summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/atomicops.h6
-rw-r--r--base/base.gyp18
-rw-r--r--base/base.gypi412
-rw-r--r--base/base_paths_linux.cc10
-rw-r--r--base/callback.h5
-rw-r--r--base/chrome_application_mac.h61
-rw-r--r--base/chrome_application_mac.mm68
-rw-r--r--base/command_line.cc18
-rw-r--r--base/command_line.h7
-rw-r--r--base/crypto/cssm_init.cc22
-rw-r--r--base/crypto/rsa_private_key.h2
-rw-r--r--base/crypto/rsa_private_key_openssl.cc13
-rw-r--r--base/crypto/signature_creator_openssl.cc3
-rw-r--r--base/crypto/signature_verifier_openssl.cc3
-rw-r--r--base/data/data_pack_unittest/sample.pakbin80 -> 0 bytes
-rw-r--r--base/data_pack.cc216
-rw-r--r--base/data_pack.h62
-rw-r--r--base/data_pack_unittest.cc73
-rw-r--r--base/debug/debugger_posix.cc18
-rw-r--r--base/debug/debugger_win.cc3
-rw-r--r--base/debug/leak_tracker.h10
-rw-r--r--base/debug/stack_trace_posix.cc4
-rw-r--r--base/debug/stack_trace_win.cc4
-rw-r--r--base/debug/trace_event.cc14
-rw-r--r--base/debug/trace_event.h8
-rw-r--r--base/debug/trace_event_win.cc6
-rw-r--r--base/debug/trace_event_win.h2
-rw-r--r--base/debug/trace_event_win_unittest.cc4
-rw-r--r--base/file_descriptor_shuffle.h6
-rw-r--r--base/file_util.cc8
-rw-r--r--base/file_util_deprecated.h2
-rw-r--r--base/file_util_posix.cc5
-rw-r--r--base/file_util_win.cc8
-rw-r--r--base/file_version_info.h51
-rw-r--r--base/file_version_info_mac.h49
-rw-r--r--base/file_version_info_mac.mm110
-rw-r--r--base/file_version_info_win.cc37
-rw-r--r--base/file_version_info_win.h34
-rw-r--r--base/global_descriptors_posix.cc8
-rw-r--r--base/global_descriptors_posix.h3
-rw-r--r--base/hash_tables.h4
-rw-r--r--base/i18n/break_iterator.cc101
-rw-r--r--base/i18n/break_iterator.h108
-rw-r--r--base/i18n/break_iterator_unittest.cc308
-rw-r--r--base/i18n/file_util_icu.cc46
-rw-r--r--base/i18n/number_formatting.cc26
-rw-r--r--base/i18n/rtl.cc52
-rw-r--r--base/i18n/rtl.h1
-rw-r--r--base/i18n/time_formatting.cc23
-rw-r--r--base/i18n/time_formatting.h14
-rw-r--r--base/i18n/word_iterator.cc70
-rw-r--r--base/i18n/word_iterator.h89
-rw-r--r--base/i18n/word_iterator_unittest.cc117
-rw-r--r--base/image_util.cc72
-rw-r--r--base/image_util.h67
-rw-r--r--base/lazy_instance.h15
-rw-r--r--base/linux_util.cc4
-rw-r--r--base/logging.cc38
-rw-r--r--base/logging_win.cc19
-rw-r--r--base/logging_win.h8
-rw-r--r--base/mac/cocoa_protocols.h (renamed from base/cocoa_protocols_mac.h)0
-rw-r--r--base/mac_util.h62
-rw-r--r--base/mac_util.mm21
-rw-r--r--base/mac_util_unittest.mm4
-rw-r--r--base/message_loop.cc25
-rw-r--r--base/message_loop_proxy_impl.h6
-rw-r--r--base/message_loop_unittest.cc4
-rw-r--r--base/message_pump_glib.cc4
-rw-r--r--base/message_pump_glib.h2
-rw-r--r--base/message_pump_glib_x.cc35
-rw-r--r--base/message_pump_glib_x.h4
-rw-r--r--base/message_pump_glib_x_dispatch.h15
-rw-r--r--base/message_pump_mac.h17
-rw-r--r--base/message_pump_mac.mm11
-rw-r--r--base/metrics/field_trial.cc24
-rw-r--r--base/metrics/field_trial.h10
-rw-r--r--base/metrics/histogram.cc63
-rw-r--r--base/metrics/histogram.h8
-rw-r--r--base/mime_util_xdg.cc27
-rw-r--r--base/nsimage_cache_mac.h33
-rw-r--r--base/nsimage_cache_mac.mm73
-rw-r--r--base/nss_util.cc4
-rw-r--r--base/nss_util.h4
-rw-r--r--base/openssl_util.cc30
-rw-r--r--base/openssl_util.h4
-rw-r--r--base/path_service.cc18
-rw-r--r--base/path_service.h5
-rw-r--r--base/pickle.cc3
-rw-r--r--base/pickle.h1
-rw-r--r--base/pickle_unittest.cc11
-rw-r--r--base/platform_thread_mac.mm20
-rw-r--r--base/platform_thread_posix.cc4
-rw-r--r--base/platform_thread_win.cc8
-rw-r--r--base/process_util.cc12
-rw-r--r--base/process_util.h45
-rw-r--r--base/process_util_linux.cc33
-rw-r--r--base/process_util_mac.mm130
-rw-r--r--base/process_util_posix.cc52
-rw-r--r--base/process_util_unittest.cc172
-rw-r--r--base/process_util_win.cc86
-rw-r--r--base/raw_scoped_refptr_mismatch_checker.h225
-rw-r--r--base/scoped_handle_win.h3
-rw-r--r--base/scoped_variant_win.h9
-rw-r--r--base/singleton.h67
-rw-r--r--base/singleton_unittest.cc186
-rw-r--r--base/string_util.cc47
-rw-r--r--base/string_util.h8
-rw-r--r--base/string_util_unittest.cc27
-rw-r--r--base/stringprintf.h1
-rw-r--r--base/task.h23
-rw-r--r--base/task_unittest.cc52
-rw-r--r--base/template_util.h47
-rw-r--r--base/test/mock_chrome_application_mac.h28
-rw-r--r--base/test/mock_chrome_application_mac.mm19
-rw-r--r--base/test/test_switches.cc1
-rw-r--r--base/test/test_switches.h1
-rw-r--r--base/test/test_timeouts.cc6
-rw-r--r--base/test/test_timeouts.h4
-rw-r--r--base/third_party/nspr/prcpucfg.h4
-rw-r--r--base/time_win.cc32
-rw-r--r--base/tuple.h6
-rw-r--r--base/unix_domain_socket_posix.cc143
-rw-r--r--base/unix_domain_socket_posix.h43
-rw-r--r--base/values.cc125
-rw-r--r--base/values.h47
-rw-r--r--base/values_unittest.cc156
-rw-r--r--base/values_util.cc4
-rw-r--r--base/values_util.h4
-rw-r--r--base/version.cc17
-rw-r--r--base/version.h7
-rw-r--r--base/waitable_event_watcher.h2
-rw-r--r--base/watchdog_unittest.cc2
-rw-r--r--base/win/registry.cc10
-rw-r--r--base/win/registry.h13
-rw-r--r--base/win/scoped_variant.cc2
-rw-r--r--base/worker_pool_linux.cc186
-rw-r--r--base/worker_pool_linux.h103
-rw-r--r--base/worker_pool_linux_unittest.cc268
-rw-r--r--base/worker_pool_mac.h33
-rw-r--r--base/worker_pool_mac.mm205
-rw-r--r--base/worker_pool_posix.cc168
-rw-r--r--base/worker_pool_posix.h89
-rw-r--r--base/worker_pool_posix_unittest.cc268
-rw-r--r--build/all.gyp14
-rwxr-xr-xbuild/build-bisect.py283
-rw-r--r--build/common.gypi97
-rw-r--r--build/features_override.gypi1
-rwxr-xr-xbuild/linux/dump_signature.py56
-rw-r--r--build/linux/system.gyp24
-rw-r--r--build/sanitize-mac-build-log.sed22
-rwxr-xr-xbuild/sanitize-mac-build-log.sh6
-rw-r--r--build/sanitize-win-build-log.sed14
-rwxr-xr-xbuild/sanitize-win-build-log.sh6
-rw-r--r--build/whitespace_file.txt2
-rw-r--r--chrome/browser/DEPS3
-rw-r--r--chrome/browser/about_flags.cc257
-rw-r--r--chrome/browser/about_flags.h40
-rw-r--r--chrome/browser/about_flags_unittest.cc91
-rw-r--r--chrome/browser/accessibility/browser_accessibility_cocoa.mm35
-rw-r--r--chrome/browser/accessibility/browser_accessibility_mac_unittest.mm2
-rw-r--r--chrome/browser/accessibility/browser_accessibility_state.cc8
-rw-r--r--chrome/browser/accessibility/browser_accessibility_state.h6
-rw-r--r--chrome/browser/accessibility/browser_views_accessibility_browsertest.cc8
-rw-r--r--chrome/browser/accessibility_events.cc2
-rw-r--r--chrome/browser/aeropeek_manager.cc2
-rw-r--r--chrome/browser/alternate_nav_url_fetcher.cc2
-rw-r--r--chrome/browser/app_controller_mac.h2
-rw-r--r--chrome/browser/app_controller_mac.mm254
-rw-r--r--chrome/browser/app_controller_mac_unittest.mm2
-rw-r--r--chrome/browser/app_modal_dialog.cc53
-rw-r--r--chrome/browser/app_modal_dialog.h82
-rw-r--r--chrome/browser/app_modal_dialog_queue.cc64
-rw-r--r--chrome/browser/app_modal_dialog_queue.h85
-rw-r--r--chrome/browser/appcache/appcache_dispatcher_host.cc101
-rw-r--r--chrome/browser/appcache/appcache_dispatcher_host.h44
-rw-r--r--chrome/browser/appcache/appcache_frontend_proxy.cc4
-rw-r--r--chrome/browser/appcache/appcache_frontend_proxy.h4
-rw-r--r--chrome/browser/appcache/appcache_ui_test.cc90
-rw-r--r--chrome/browser/appcache/chrome_appcache_service.h2
-rw-r--r--chrome/browser/appcache/view_appcache_internals_job_factory.cc5
-rw-r--r--chrome/browser/autocomplete/autocomplete.cc94
-rw-r--r--chrome/browser/autocomplete/autocomplete.h7
-rw-r--r--chrome/browser/autocomplete/autocomplete_browsertest.cc39
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit.cc36
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit.h18
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_unittest.cc3
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_browsertest.cc4
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc172
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_gtk.h21
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_mac.h3
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_mac.mm16
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_win.cc26
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_win.h7
-rw-r--r--chrome/browser/autocomplete/autocomplete_match.h2
-rw-r--r--chrome/browser/autocomplete/autocomplete_popup_model.cc15
-rw-r--r--chrome/browser/autocomplete/autocomplete_popup_view_gtk.cc6
-rw-r--r--chrome/browser/autocomplete/autocomplete_popup_view_gtk.h2
-rw-r--r--chrome/browser/autocomplete/autocomplete_popup_view_mac.h2
-rw-r--r--chrome/browser/autocomplete/autocomplete_popup_view_mac.mm12
-rw-r--r--chrome/browser/autocomplete/autocomplete_unittest.cc15
-rw-r--r--chrome/browser/autocomplete/history_contents_provider.cc6
-rw-r--r--chrome/browser/autocomplete/history_contents_provider.h9
-rw-r--r--chrome/browser/autocomplete/history_provider.cc41
-rw-r--r--chrome/browser/autocomplete/history_provider.h4
-rw-r--r--chrome/browser/autocomplete/history_quick_provider.cc12
-rw-r--r--chrome/browser/autocomplete/history_quick_provider.h5
-rw-r--r--chrome/browser/autocomplete/history_url_provider.cc36
-rw-r--r--chrome/browser/autocomplete/history_url_provider.h6
-rw-r--r--chrome/browser/autocomplete/keyword_provider.cc9
-rw-r--r--chrome/browser/autocomplete/keyword_provider.h6
-rw-r--r--chrome/browser/autocomplete/search_provider.cc4
-rw-r--r--chrome/browser/autocomplete_history_manager.cc2
-rw-r--r--chrome/browser/autofill/address_field.cc4
-rw-r--r--chrome/browser/autofill/address_field.h2
-rw-r--r--chrome/browser/autofill/autofill-inl.h36
-rw-r--r--chrome/browser/autofill/autofill_address_model_mac_unittest.mm4
-rw-r--r--chrome/browser/autofill/autofill_address_sheet_controller_mac_unittest.mm4
-rw-r--r--chrome/browser/autofill/autofill_browsertest.cc309
-rw-r--r--chrome/browser/autofill/autofill_cc_infobar_delegate.cc1
-rw-r--r--chrome/browser/autofill/autofill_common_test.cc2
-rw-r--r--chrome/browser/autofill/autofill_credit_card_model_mac_unittest.mm4
-rw-r--r--chrome/browser/autofill/autofill_credit_card_sheet_controller_mac_unittest.mm4
-rw-r--r--chrome/browser/autofill/autofill_dialog_controller_mac.h2
-rw-r--r--chrome/browser/autofill/autofill_dialog_controller_mac.mm62
-rw-r--r--chrome/browser/autofill/autofill_dialog_controller_mac_unittest.mm6
-rw-r--r--chrome/browser/autofill/autofill_dialog_gtk.cc2
-rw-r--r--chrome/browser/autofill/autofill_dialog_mac.mm2
-rw-r--r--chrome/browser/autofill/autofill_download.cc7
-rw-r--r--chrome/browser/autofill/autofill_download.h7
-rw-r--r--chrome/browser/autofill/autofill_download_unittest.cc32
-rw-r--r--chrome/browser/autofill/autofill_editor_gtk.cc2
-rw-r--r--chrome/browser/autofill/autofill_field.cc9
-rw-r--r--chrome/browser/autofill/autofill_ie_toolbar_import_win.cc3
-rw-r--r--chrome/browser/autofill/autofill_manager.cc85
-rw-r--r--chrome/browser/autofill/autofill_manager.h28
-rw-r--r--chrome/browser/autofill/autofill_manager_unittest.cc14
-rw-r--r--chrome/browser/autofill/autofill_metrics.cc19
-rw-r--r--chrome/browser/autofill/autofill_metrics.h74
-rw-r--r--chrome/browser/autofill/autofill_metrics_unittest.cc229
-rw-r--r--chrome/browser/autofill/autofill_profile.cc489
-rw-r--r--chrome/browser/autofill/autofill_profile.h43
-rw-r--r--chrome/browser/autofill/autofill_profile_unittest.cc286
-rw-r--r--chrome/browser/autofill/credit_card.cc11
-rw-r--r--chrome/browser/autofill/credit_card.h4
-rw-r--r--chrome/browser/autofill/credit_card_unittest.cc14
-rw-r--r--chrome/browser/autofill/fax_number.cc33
-rw-r--r--chrome/browser/autofill/fax_number.h30
-rw-r--r--chrome/browser/autofill/form_field.cc4
-rw-r--r--chrome/browser/autofill/form_field.h2
-rw-r--r--chrome/browser/autofill/form_structure.cc22
-rw-r--r--chrome/browser/autofill/form_structure.h5
-rw-r--r--chrome/browser/autofill/form_structure_browsertest.cc160
-rw-r--r--chrome/browser/autofill/home_address.cc41
-rw-r--r--chrome/browser/autofill/home_address.h39
-rw-r--r--chrome/browser/autofill/home_phone_number.cc29
-rw-r--r--chrome/browser/autofill/home_phone_number.h26
-rw-r--r--chrome/browser/autofill/name_field.cc13
-rw-r--r--chrome/browser/autofill/name_field.h9
-rw-r--r--chrome/browser/autofill/personal_data_manager.cc107
-rw-r--r--chrome/browser/autofill/personal_data_manager.h10
-rw-r--r--chrome/browser/autofill/personal_data_manager_mac.mm2
-rw-r--r--chrome/browser/autofill/personal_data_manager_unittest.cc10
-rw-r--r--chrome/browser/autofill/phone_number.h4
-rw-r--r--chrome/browser/autofill/phone_number_unittest.cc43
-rw-r--r--chrome/browser/automation/automation_autocomplete_edit_tracker.cc28
-rw-r--r--chrome/browser/automation/automation_autocomplete_edit_tracker.h21
-rw-r--r--chrome/browser/automation/automation_browser_tracker.cc24
-rw-r--r--chrome/browser/automation/automation_browser_tracker.h23
-rw-r--r--chrome/browser/automation/automation_extension_tracker.cc24
-rw-r--r--chrome/browser/automation/automation_provider.cc67
-rw-r--r--chrome/browser/automation/automation_provider.h17
-rw-r--r--chrome/browser/automation/automation_provider_gtk.cc1
-rw-r--r--chrome/browser/automation/automation_provider_list.cc1
-rw-r--r--chrome/browser/automation/automation_provider_mac.mm6
-rw-r--r--chrome/browser/automation/automation_provider_observers.cc117
-rw-r--r--chrome/browser/automation/automation_provider_observers.h62
-rw-r--r--chrome/browser/automation/automation_provider_win.cc15
-rw-r--r--chrome/browser/automation/automation_resource_message_filter.cc8
-rw-r--r--chrome/browser/automation/automation_resource_tracker.cc3
-rw-r--r--chrome/browser/automation/automation_resource_tracker.h25
-rw-r--r--chrome/browser/automation/chrome_frame_automation_provider.cc16
-rw-r--r--chrome/browser/automation/chrome_frame_automation_provider.h2
-rw-r--r--chrome/browser/automation/extension_port_container.cc8
-rw-r--r--chrome/browser/automation/testing_automation_provider.cc628
-rw-r--r--chrome/browser/automation/testing_automation_provider.h55
-rw-r--r--chrome/browser/automation/testing_automation_provider_mac.mm6
-rw-r--r--chrome/browser/automation/ui_controls_internal.cc22
-rw-r--r--chrome/browser/automation/ui_controls_internal.h15
-rw-r--r--chrome/browser/automation/ui_controls_win.cc48
-rw-r--r--chrome/browser/automation/url_request_automation_job.cc87
-rw-r--r--chrome/browser/automation/url_request_automation_job.h27
-rw-r--r--chrome/browser/back_forward_menu_model.cc379
-rw-r--r--chrome/browser/back_forward_menu_model.h171
-rw-r--r--chrome/browser/back_forward_menu_model_unittest.cc422
-rw-r--r--chrome/browser/background_application_list_model.cc35
-rw-r--r--chrome/browser/background_application_list_model.h8
-rw-r--r--chrome/browser/background_contents_service.cc9
-rw-r--r--chrome/browser/background_mode_manager.cc221
-rw-r--r--chrome/browser/background_mode_manager.h12
-rw-r--r--chrome/browser/background_mode_manager_chromeos.cc16
-rw-r--r--chrome/browser/background_mode_manager_linux.cc116
-rw-r--r--chrome/browser/background_mode_manager_mac.mm78
-rw-r--r--chrome/browser/background_mode_manager_win.cc85
-rw-r--r--chrome/browser/background_page_tracker.cc16
-rw-r--r--chrome/browser/background_page_tracker.h2
-rw-r--r--chrome/browser/bookmarks/base_bookmark_model_observer.cc51
-rw-r--r--chrome/browser/bookmarks/base_bookmark_model_observer.h29
-rw-r--r--chrome/browser/bookmarks/bookmark_context_menu_controller.cc108
-rw-r--r--chrome/browser/bookmarks/bookmark_context_menu_controller.h10
-rw-r--r--chrome/browser/bookmarks/bookmark_context_menu_controller_unittest.cc109
-rw-r--r--chrome/browser/bookmarks/bookmark_folder_editor_controller.cc2
-rw-r--r--chrome/browser/bookmarks/bookmark_folder_editor_controller.h2
-rw-r--r--chrome/browser/bookmarks/bookmark_html_writer.cc3
-rw-r--r--chrome/browser/bookmarks/bookmark_html_writer_unittest.cc3
-rw-r--r--chrome/browser/bookmarks/bookmark_index.cc2
-rw-r--r--chrome/browser/bookmarks/bookmark_model.cc2
-rw-r--r--chrome/browser/bookmarks/bookmark_model_unittest.cc4
-rw-r--r--chrome/browser/bookmarks/bookmark_node_data.cc12
-rw-r--r--chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.mm2
-rw-r--r--chrome/browser/bookmarks/bookmark_storage.cc2
-rw-r--r--chrome/browser/bookmarks/bookmark_storage.h5
-rw-r--r--chrome/browser/bookmarks/bookmark_utils.cc5
-rw-r--r--chrome/browser/bookmarks/bookmark_utils_unittest.cc6
-rw-r--r--chrome/browser/browser_about_handler.cc151
-rw-r--r--chrome/browser/browser_about_handler.h7
-rw-r--r--chrome/browser/browser_about_handler_unittest.cc6
-rw-r--r--chrome/browser/browser_browsertest.cc38
-rw-r--r--chrome/browser/browser_child_process_host.cc114
-rw-r--r--chrome/browser/browser_child_process_host.h67
-rw-r--r--chrome/browser/browser_focus_uitest.cc126
-rw-r--r--chrome/browser/browser_keyevents_browsertest.cc148
-rw-r--r--chrome/browser/browser_main.cc87
-rw-r--r--chrome/browser/browser_main_gtk.cc4
-rw-r--r--chrome/browser/browser_main_mac.mm3
-rw-r--r--chrome/browser/browser_main_win.cc31
-rw-r--r--chrome/browser/browser_message_filter.cc91
-rw-r--r--chrome/browser/browser_message_filter.h64
-rw-r--r--chrome/browser/browser_process.h15
-rw-r--r--chrome/browser/browser_process_impl.cc109
-rw-r--r--chrome/browser/browser_process_impl.h33
-rw-r--r--chrome/browser/browser_resources.grd6
-rw-r--r--chrome/browser/browser_shutdown.cc15
-rw-r--r--chrome/browser/browser_signin.cc4
-rw-r--r--chrome/browser/browser_url_handler.cc2
-rw-r--r--chrome/browser/browsing_data_appcache_helper.cc2
-rw-r--r--chrome/browser/browsing_data_database_helper.cc2
-rw-r--r--chrome/browser/browsing_data_indexed_db_helper.cc2
-rw-r--r--chrome/browser/browsing_data_local_storage_helper.cc2
-rw-r--r--chrome/browser/browsing_data_remover.cc29
-rw-r--r--chrome/browser/browsing_data_remover.h22
-rw-r--r--chrome/browser/browsing_instance.cc2
-rw-r--r--chrome/browser/browsing_instance.h2
-rw-r--r--chrome/browser/bug_report_data.cc37
-rw-r--r--chrome/browser/bug_report_data.h44
-rw-r--r--chrome/browser/bug_report_util.cc2
-rw-r--r--chrome/browser/cert_store.cc3
-rw-r--r--chrome/browser/cert_store.h2
-rw-r--r--chrome/browser/certificate_manager_model.cc6
-rw-r--r--chrome/browser/certificate_viewer.cc2
-rw-r--r--chrome/browser/child_process_launcher.cc37
-rw-r--r--chrome/browser/child_process_launcher.h7
-rw-r--r--chrome/browser/child_process_security_policy.cc108
-rw-r--r--chrome/browser/child_process_security_policy.h92
-rw-r--r--chrome/browser/child_process_security_policy_browsertest.cc3
-rw-r--r--chrome/browser/child_process_security_policy_unittest.cc10
-rw-r--r--chrome/browser/chrome_browser_application_mac.h5
-rw-r--r--chrome/browser/chrome_browser_application_mac.mm13
-rw-r--r--chrome/browser/chrome_plugin_browsing_context.cc2
-rw-r--r--chrome/browser/chrome_plugin_browsing_context.h2
-rw-r--r--chrome/browser/chrome_plugin_host.cc56
-rw-r--r--chrome/browser/chrome_plugin_unittest.cc31
-rw-r--r--chrome/browser/chromeos/audio_handler.cc6
-rw-r--r--chrome/browser/chromeos/audio_handler.h8
-rw-r--r--chrome/browser/chromeos/boot_times_loader.cc9
-rw-r--r--chrome/browser/chromeos/brightness_bubble.cc28
-rw-r--r--chrome/browser/chromeos/brightness_bubble.h32
-rw-r--r--chrome/browser/chromeos/brightness_observer.cc17
-rw-r--r--chrome/browser/chromeos/brightness_observer.h30
-rw-r--r--chrome/browser/chromeos/browser_main_chromeos.cc9
-rw-r--r--chrome/browser/chromeos/cros/brightness_library.cc93
-rw-r--r--chrome/browser/chromeos/cros/brightness_library.h32
-rw-r--r--chrome/browser/chromeos/cros/burn_library.h3
-rw-r--r--chrome/browser/chromeos/cros/cros_library.cc177
-rw-r--r--chrome/browser/chromeos/cros/cros_library.h75
-rw-r--r--chrome/browser/chromeos/cros/cros_library_loader.cc2
-rw-r--r--chrome/browser/chromeos/cros/cros_mock.cc94
-rw-r--r--chrome/browser/chromeos/cros/cros_mock.h2
-rw-r--r--chrome/browser/chromeos/cros/cryptohome_library.h2
-rw-r--r--chrome/browser/chromeos/cros/input_method_library.cc28
-rw-r--r--chrome/browser/chromeos/cros/input_method_library.h23
-rw-r--r--chrome/browser/chromeos/cros/keyboard_library.cc2
-rw-r--r--chrome/browser/chromeos/cros/keyboard_library.h3
-rw-r--r--chrome/browser/chromeos/cros/login_library.cc5
-rw-r--r--chrome/browser/chromeos/cros/login_library.h5
-rw-r--r--chrome/browser/chromeos/cros/mock_login_library.h1
-rw-r--r--chrome/browser/chromeos/cros/mock_mount_library.h2
-rw-r--r--chrome/browser/chromeos/cros/mock_network_library.h7
-rw-r--r--chrome/browser/chromeos/cros/mount_library.h2
-rw-r--r--chrome/browser/chromeos/cros/network_library.cc144
-rw-r--r--chrome/browser/chromeos/cros/network_library.h12
-rw-r--r--chrome/browser/chromeos/cros/power_library.h2
-rw-r--r--chrome/browser/chromeos/cros/screen_lock_library.h2
-rw-r--r--chrome/browser/chromeos/cros/speech_synthesis_library.cc14
-rw-r--r--chrome/browser/chromeos/cros/speech_synthesis_library.h15
-rw-r--r--chrome/browser/chromeos/cros/syslogs_library.h2
-rw-r--r--chrome/browser/chromeos/cros/system_library.h2
-rw-r--r--chrome/browser/chromeos/cros/touchpad_library.h2
-rw-r--r--chrome/browser/chromeos/cros/update_library.h2
-rw-r--r--chrome/browser/chromeos/cros_settings.cc13
-rw-r--r--chrome/browser/chromeos/cros_settings.h6
-rw-r--r--chrome/browser/chromeos/dom_ui/accounts_options_handler.cc10
-rw-r--r--chrome/browser/chromeos/dom_ui/core_chromeos_options_handler.cc5
-rw-r--r--chrome/browser/chromeos/dom_ui/imageburner_ui.cc16
-rw-r--r--chrome/browser/chromeos/dom_ui/imageburner_ui.h14
-rw-r--r--chrome/browser/chromeos/dom_ui/internet_options_handler.cc372
-rw-r--r--chrome/browser/chromeos/dom_ui/internet_options_handler.h69
-rw-r--r--chrome/browser/chromeos/dom_ui/keyboard_overlay_ui.cc4
-rw-r--r--chrome/browser/chromeos/dom_ui/language_customize_modifier_keys_handler.cc2
-rw-r--r--chrome/browser/chromeos/dom_ui/language_options_handler.cc2
-rw-r--r--chrome/browser/chromeos/dom_ui/language_options_handler_unittest.cc14
-rw-r--r--chrome/browser/chromeos/dom_ui/login/authenticator_facade.h63
-rw-r--r--chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros.cc35
-rw-r--r--chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros.h45
-rw-r--r--chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros_helpers.cc43
-rw-r--r--chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros_helpers.h35
-rw-r--r--chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros_unittest.cc132
-rw-r--r--chrome/browser/chromeos/dom_ui/login/authenticator_facade_stub.cc28
-rw-r--r--chrome/browser/chromeos/dom_ui/login/authenticator_facade_stub.h48
-rw-r--r--chrome/browser/chromeos/dom_ui/login/authenticator_facade_stub_unittest.cc163
-rw-r--r--chrome/browser/chromeos/dom_ui/login/login_ui.cc160
-rw-r--r--chrome/browser/chromeos/dom_ui/login/login_ui.h96
-rw-r--r--chrome/browser/chromeos/dom_ui/login/login_ui_helpers.cc94
-rw-r--r--chrome/browser/chromeos/dom_ui/login/login_ui_helpers.h78
-rw-r--r--chrome/browser/chromeos/dom_ui/login/login_ui_unittest.cc154
-rw-r--r--chrome/browser/chromeos/dom_ui/login/login_ui_unittest.h78
-rw-r--r--chrome/browser/chromeos/dom_ui/login/mock_authenticator_facade_cros.h49
-rw-r--r--chrome/browser/chromeos/dom_ui/login/mock_authenticator_facade_cros_helpers.h36
-rw-r--r--chrome/browser/chromeos/dom_ui/login/mock_authenticator_facade_stub.h44
-rw-r--r--chrome/browser/chromeos/dom_ui/login/mock_login_ui_handler.h36
-rw-r--r--chrome/browser/chromeos/dom_ui/login/mock_login_ui_helpers.h63
-rw-r--r--chrome/browser/chromeos/dom_ui/menu_ui.cc10
-rw-r--r--chrome/browser/chromeos/dom_ui/mobile_setup_ui.cc5
-rw-r--r--chrome/browser/chromeos/dom_ui/network_menu_ui.cc2
-rw-r--r--chrome/browser/chromeos/dom_ui/proxy_handler.cc3
-rw-r--r--chrome/browser/chromeos/dom_ui/register_page_ui.cc2
-rw-r--r--chrome/browser/chromeos/dom_ui/stats_options_handler.cc3
-rw-r--r--chrome/browser/chromeos/dom_ui/system_info_ui.cc2
-rw-r--r--chrome/browser/chromeos/dom_ui/system_options_handler.cc1
-rw-r--r--chrome/browser/chromeos/dom_ui/system_settings_provider.cc17
-rw-r--r--chrome/browser/chromeos/dom_ui/system_settings_provider.h9
-rw-r--r--chrome/browser/chromeos/enterprise_extension_observer.cc65
-rw-r--r--chrome/browser/chromeos/enterprise_extension_observer.h45
-rw-r--r--chrome/browser/chromeos/external_protocol_dialog.cc3
-rw-r--r--chrome/browser/chromeos/frame/browser_frame_chromeos.cc17
-rw-r--r--chrome/browser/chromeos/frame/browser_non_client_frame_view_factory_chromeos.cc21
-rw-r--r--chrome/browser/chromeos/frame/browser_view.cc2
-rw-r--r--chrome/browser/chromeos/frame/bubble_window.cc2
-rw-r--r--chrome/browser/chromeos/frame/panel_browser_view.cc2
-rw-r--r--chrome/browser/chromeos/frame/panel_controller.cc2
-rw-r--r--chrome/browser/chromeos/frame/panel_controller.h2
-rw-r--r--chrome/browser/chromeos/google_update_chromeos.cc2
-rw-r--r--chrome/browser/chromeos/gview_request_interceptor.cc22
-rw-r--r--chrome/browser/chromeos/gview_request_interceptor.h16
-rw-r--r--chrome/browser/chromeos/gview_request_interceptor_unittest.cc55
-rw-r--r--chrome/browser/chromeos/input_method/candidate_window.cc399
-rw-r--r--chrome/browser/chromeos/input_method/candidate_window_main.cc2
-rw-r--r--chrome/browser/chromeos/input_method/input_method_util.cc26
-rw-r--r--chrome/browser/chromeos/input_method/input_method_util_unittest.cc3
-rw-r--r--chrome/browser/chromeos/login/account_creation_view.cc2
-rw-r--r--chrome/browser/chromeos/login/account_screen.cc2
-rw-r--r--chrome/browser/chromeos/login/account_screen_browsertest.cc6
-rw-r--r--chrome/browser/chromeos/login/apply_services_customization.cc2
-rw-r--r--chrome/browser/chromeos/login/auth_attempt_state.cc2
-rw-r--r--chrome/browser/chromeos/login/authenticator.cc9
-rw-r--r--chrome/browser/chromeos/login/authenticator.h3
-rw-r--r--chrome/browser/chromeos/login/authenticator_unittest.cc22
-rw-r--r--chrome/browser/chromeos/login/background_view.cc12
-rw-r--r--chrome/browser/chromeos/login/captcha_view.cc119
-rw-r--r--chrome/browser/chromeos/login/captcha_view.h28
-rw-r--r--chrome/browser/chromeos/login/cookie_fetcher.cc5
-rw-r--r--chrome/browser/chromeos/login/cookie_fetcher.h3
-rw-r--r--chrome/browser/chromeos/login/cookie_fetcher_unittest.cc3
-rw-r--r--chrome/browser/chromeos/login/cryptohome_op.cc1
-rw-r--r--chrome/browser/chromeos/login/cryptohome_op.h1
-rw-r--r--chrome/browser/chromeos/login/eula_view.cc2
-rw-r--r--chrome/browser/chromeos/login/existing_user_controller.cc78
-rw-r--r--chrome/browser/chromeos/login/existing_user_controller.h5
-rw-r--r--chrome/browser/chromeos/login/existing_user_view.cc68
-rw-r--r--chrome/browser/chromeos/login/existing_user_view.h31
-rw-r--r--chrome/browser/chromeos/login/google_authenticator.cc8
-rw-r--r--chrome/browser/chromeos/login/guest_user_view.cc50
-rw-r--r--chrome/browser/chromeos/login/guest_user_view.h17
-rw-r--r--chrome/browser/chromeos/login/helper.cc53
-rw-r--r--chrome/browser/chromeos/login/helper.h51
-rw-r--r--chrome/browser/chromeos/login/html_page_screen.cc2
-rw-r--r--chrome/browser/chromeos/login/image_downloader.cc6
-rw-r--r--chrome/browser/chromeos/login/keyboard_switch_menu.cc6
-rw-r--r--chrome/browser/chromeos/login/keyboard_switch_menu.h6
-rw-r--r--chrome/browser/chromeos/login/login_browsertest.cc4
-rw-r--r--chrome/browser/chromeos/login/login_html_dialog.cc4
-rw-r--r--chrome/browser/chromeos/login/login_performer.cc379
-rw-r--r--chrome/browser/chromeos/login/login_performer.h102
-rw-r--r--chrome/browser/chromeos/login/login_screen.cc13
-rw-r--r--chrome/browser/chromeos/login/login_status_consumer.h1
-rw-r--r--chrome/browser/chromeos/login/login_utils.cc189
-rw-r--r--chrome/browser/chromeos/login/login_utils.h20
-rw-r--r--chrome/browser/chromeos/login/message_bubble.cc2
-rw-r--r--chrome/browser/chromeos/login/mock_authenticator.h18
-rw-r--r--chrome/browser/chromeos/login/mock_url_fetchers.h3
-rw-r--r--chrome/browser/chromeos/login/network_screen_browsertest.cc118
-rw-r--r--chrome/browser/chromeos/login/new_user_view.cc101
-rw-r--r--chrome/browser/chromeos/login/new_user_view.h37
-rw-r--r--chrome/browser/chromeos/login/online_attempt.cc4
-rw-r--r--chrome/browser/chromeos/login/online_attempt.h2
-rw-r--r--chrome/browser/chromeos/login/online_attempt_unittest.cc8
-rw-r--r--chrome/browser/chromeos/login/owner_key_utils.cc13
-rw-r--r--chrome/browser/chromeos/login/owner_manager.cc10
-rw-r--r--chrome/browser/chromeos/login/owner_manager_unittest.h2
-rw-r--r--chrome/browser/chromeos/login/ownership_service.cc6
-rw-r--r--chrome/browser/chromeos/login/ownership_service.h7
-rw-r--r--chrome/browser/chromeos/login/parallel_authenticator.cc21
-rw-r--r--chrome/browser/chromeos/login/password_changed_view.cc10
-rw-r--r--chrome/browser/chromeos/login/password_changed_view.h4
-rw-r--r--chrome/browser/chromeos/login/registration_screen.cc8
-rw-r--r--chrome/browser/chromeos/login/rounded_view.h131
-rw-r--r--chrome/browser/chromeos/login/screen_lock_view.cc23
-rw-r--r--chrome/browser/chromeos/login/screen_lock_view.h5
-rw-r--r--chrome/browser/chromeos/login/screen_locker.cc185
-rw-r--r--chrome/browser/chromeos/login/screen_locker.h53
-rw-r--r--chrome/browser/chromeos/login/screen_locker_browsertest.cc1
-rw-r--r--chrome/browser/chromeos/login/screen_locker_tester.cc4
-rw-r--r--chrome/browser/chromeos/login/signed_settings.cc92
-rw-r--r--chrome/browser/chromeos/login/signed_settings.h16
-rw-r--r--chrome/browser/chromeos/login/signed_settings_helper.cc91
-rw-r--r--chrome/browser/chromeos/login/signed_settings_helper.h19
-rw-r--r--chrome/browser/chromeos/login/signed_settings_helper_unittest.cc42
-rw-r--r--chrome/browser/chromeos/login/signed_settings_temp_storage.cc7
-rw-r--r--chrome/browser/chromeos/login/signed_settings_temp_storage_unittest.cc6
-rw-r--r--chrome/browser/chromeos/login/signed_settings_unittest.cc138
-rw-r--r--chrome/browser/chromeos/login/test_attempt_state.cc2
-rw-r--r--chrome/browser/chromeos/login/textfield_with_margin.cc8
-rw-r--r--chrome/browser/chromeos/login/textfield_with_margin.h7
-rw-r--r--chrome/browser/chromeos/login/user_controller.cc195
-rw-r--r--chrome/browser/chromeos/login/user_controller.h62
-rw-r--r--chrome/browser/chromeos/login/user_image_downloader.cc3
-rw-r--r--chrome/browser/chromeos/login/user_image_screen.cc7
-rw-r--r--chrome/browser/chromeos/login/user_image_view.cc2
-rw-r--r--chrome/browser/chromeos/login/user_input.h33
-rw-r--r--chrome/browser/chromeos/login/user_manager.cc2
-rw-r--r--chrome/browser/chromeos/login/user_manager.h8
-rw-r--r--chrome/browser/chromeos/login/user_view.cc40
-rw-r--r--chrome/browser/chromeos/login/user_view.h6
-rw-r--r--chrome/browser/chromeos/login/username_view.cc166
-rw-r--r--chrome/browser/chromeos/login/username_view.h17
-rw-r--r--chrome/browser/chromeos/login/wizard_accessibility_handler.cc7
-rw-r--r--chrome/browser/chromeos/login/wizard_accessibility_helper.cc83
-rw-r--r--chrome/browser/chromeos/login/wizard_accessibility_helper.h11
-rw-r--r--chrome/browser/chromeos/login/wizard_controller.cc14
-rw-r--r--chrome/browser/chromeos/login/wizard_controller_browsertest.cc1
-rw-r--r--chrome/browser/chromeos/metrics_cros_settings_provider.cc8
-rw-r--r--chrome/browser/chromeos/network_message_observer.cc6
-rw-r--r--chrome/browser/chromeos/network_state_notifier.cc4
-rw-r--r--chrome/browser/chromeos/network_state_notifier.h4
-rw-r--r--chrome/browser/chromeos/network_state_notifier_browsertest.cc8
-rw-r--r--chrome/browser/chromeos/notifications/balloon_collection_impl.cc6
-rw-r--r--chrome/browser/chromeos/notifications/balloon_view.cc2
-rw-r--r--chrome/browser/chromeos/notifications/balloon_view.h1
-rw-r--r--chrome/browser/chromeos/notifications/notification_panel.cc6
-rw-r--r--chrome/browser/chromeos/offline/offline_load_page.cc7
-rw-r--r--chrome/browser/chromeos/offline/offline_load_page.h1
-rw-r--r--chrome/browser/chromeos/offline/offline_load_service.cc12
-rw-r--r--chrome/browser/chromeos/options/cellular_config_view.cc227
-rw-r--r--chrome/browser/chromeos/options/cellular_config_view.h68
-rw-r--r--chrome/browser/chromeos/options/internet_page_view.cc20
-rw-r--r--chrome/browser/chromeos/options/ip_config_view.cc92
-rw-r--r--chrome/browser/chromeos/options/ip_config_view.h47
-rw-r--r--chrome/browser/chromeos/options/language_chewing_config_view.cc2
-rw-r--r--chrome/browser/chromeos/options/language_config_model.h6
-rw-r--r--chrome/browser/chromeos/options/language_config_view.cc2
-rw-r--r--chrome/browser/chromeos/options/language_hangul_config_view.cc2
-rw-r--r--chrome/browser/chromeos/options/language_mozc_config_view.cc2
-rw-r--r--chrome/browser/chromeos/options/language_pinyin_config_view.cc2
-rw-r--r--chrome/browser/chromeos/options/network_config_view.cc148
-rw-r--r--chrome/browser/chromeos/options/network_config_view.h48
-rw-r--r--chrome/browser/chromeos/options/options_window_view.cc15
-rw-r--r--chrome/browser/chromeos/options/system_page_view.cc2
-rw-r--r--chrome/browser/chromeos/options/wifi_config_view.cc120
-rw-r--r--chrome/browser/chromeos/options/wifi_config_view.h13
-rw-r--r--chrome/browser/chromeos/options/wifi_config_view_browsertest.cc62
-rw-r--r--chrome/browser/chromeos/panels/panel_browsertest.cc5
-rw-r--r--chrome/browser/chromeos/plugin_selection_policy.cc5
-rw-r--r--chrome/browser/chromeos/plugin_selection_policy.h5
-rw-r--r--chrome/browser/chromeos/plugin_selection_policy_unittest.cc4
-rw-r--r--chrome/browser/chromeos/preferences.cc12
-rw-r--r--chrome/browser/chromeos/proxy_config_service_impl.cc49
-rw-r--r--chrome/browser/chromeos/proxy_config_service_impl.h7
-rw-r--r--chrome/browser/chromeos/proxy_config_service_impl_unittest.cc3
-rw-r--r--chrome/browser/chromeos/proxy_cros_settings_provider.cc4
-rw-r--r--chrome/browser/chromeos/setting_level_bubble.cc152
-rw-r--r--chrome/browser/chromeos/setting_level_bubble.h72
-rw-r--r--chrome/browser/chromeos/setting_level_bubble_view.cc70
-rw-r--r--chrome/browser/chromeos/setting_level_bubble_view.h50
-rw-r--r--chrome/browser/chromeos/status/clock_menu_button.cc9
-rw-r--r--chrome/browser/chromeos/status/clock_menu_button.h3
-rw-r--r--chrome/browser/chromeos/status/clock_menu_button_browsertest.cc2
-rw-r--r--chrome/browser/chromeos/status/input_method_menu.cc41
-rw-r--r--chrome/browser/chromeos/status/input_method_menu.h30
-rw-r--r--chrome/browser/chromeos/status/input_method_menu_button.cc38
-rw-r--r--chrome/browser/chromeos/status/input_method_menu_button.h6
-rw-r--r--chrome/browser/chromeos/status/input_method_menu_unittest.cc4
-rw-r--r--chrome/browser/chromeos/status/network_dropdown_button.cc17
-rw-r--r--chrome/browser/chromeos/status/network_menu.cc148
-rw-r--r--chrome/browser/chromeos/status/network_menu.h27
-rw-r--r--chrome/browser/chromeos/status/network_menu_button.cc11
-rw-r--r--chrome/browser/chromeos/status/power_menu_button.h2
-rw-r--r--chrome/browser/chromeos/system_key_event_listener.cc34
-rw-r--r--chrome/browser/chromeos/system_key_event_listener.h2
-rw-r--r--chrome/browser/chromeos/tab_closeable_state_watcher.cc5
-rw-r--r--chrome/browser/chromeos/tab_closeable_state_watcher_browsertest.cc6
-rw-r--r--chrome/browser/chromeos/update_browsertest.cc2
-rw-r--r--chrome/browser/chromeos/usb_mount_observer.cc8
-rw-r--r--chrome/browser/chromeos/usb_mount_observer.h11
-rw-r--r--chrome/browser/chromeos/usb_mount_observer_browsertest.cc2
-rw-r--r--chrome/browser/chromeos/user_cros_settings_provider.cc523
-rw-r--r--chrome/browser/chromeos/user_cros_settings_provider.h32
-rw-r--r--chrome/browser/chromeos/view_ids.h2
-rw-r--r--chrome/browser/chromeos/views/domui_menu_widget.cc8
-rw-r--r--chrome/browser/chromeos/views/native_menu_domui.cc18
-rw-r--r--chrome/browser/chromeos/views/native_menu_domui.h3
-rw-r--r--chrome/browser/chromeos/volume_bubble.cc133
-rw-r--r--chrome/browser/chromeos/volume_bubble.h47
-rw-r--r--chrome/browser/chromeos/volume_bubble_view.cc66
-rw-r--r--chrome/browser/chromeos/volume_bubble_view.h43
-rw-r--r--chrome/browser/chromeos/wm_ipc.cc9
-rw-r--r--chrome/browser/chromeos/wm_ipc.h9
-rw-r--r--chrome/browser/chromeos/wm_message_listener.cc2
-rw-r--r--chrome/browser/chromeos/wm_message_listener.h2
-rw-r--r--chrome/browser/chromeos/wm_overview_controller.cc13
-rw-r--r--chrome/browser/chromeos/wm_overview_controller.h2
-rw-r--r--chrome/browser/chromeos/wm_overview_fav_icon.cc2
-rw-r--r--chrome/browser/chromeos/wm_overview_title.cc2
-rw-r--r--chrome/browser/cocoa/about_ipc_bridge.h33
-rw-r--r--chrome/browser/cocoa/about_ipc_bridge.mm21
-rw-r--r--chrome/browser/cocoa/about_ipc_controller.h84
-rw-r--r--chrome/browser/cocoa/about_ipc_controller.mm198
-rw-r--r--chrome/browser/cocoa/about_ipc_controller_unittest.mm50
-rw-r--r--chrome/browser/cocoa/about_ipc_dialog.h24
-rw-r--r--chrome/browser/cocoa/about_ipc_dialog.mm21
-rw-r--r--chrome/browser/cocoa/about_window_controller.h69
-rw-r--r--chrome/browser/cocoa/about_window_controller.mm761
-rw-r--r--chrome/browser/cocoa/about_window_controller_unittest.mm137
-rw-r--r--chrome/browser/cocoa/accelerators_cocoa.h41
-rw-r--r--chrome/browser/cocoa/accelerators_cocoa.mm57
-rw-r--r--chrome/browser/cocoa/accelerators_cocoa_unittest.mm28
-rw-r--r--chrome/browser/cocoa/animatable_image.h57
-rw-r--r--chrome/browser/cocoa/animatable_image.mm145
-rw-r--r--chrome/browser/cocoa/animatable_image_unittest.mm46
-rw-r--r--chrome/browser/cocoa/animatable_view.h59
-rw-r--r--chrome/browser/cocoa/animatable_view.mm109
-rw-r--r--chrome/browser/cocoa/animatable_view_unittest.mm48
-rw-r--r--chrome/browser/cocoa/applescript/bookmark_applescript_utils_unittest.h53
-rw-r--r--chrome/browser/cocoa/applescript/bookmark_applescript_utils_unittest.mm62
-rw-r--r--chrome/browser/cocoa/applescript/bookmark_folder_applescript.h70
-rw-r--r--chrome/browser/cocoa/applescript/bookmark_folder_applescript.mm204
-rw-r--r--chrome/browser/cocoa/applescript/bookmark_folder_applescript_unittest.mm200
-rw-r--r--chrome/browser/cocoa/applescript/bookmark_item_applescript.h33
-rw-r--r--chrome/browser/cocoa/applescript/bookmark_item_applescript.mm66
-rw-r--r--chrome/browser/cocoa/applescript/bookmark_item_applescript_unittest.mm45
-rw-r--r--chrome/browser/cocoa/applescript/bookmark_node_applescript.h48
-rw-r--r--chrome/browser/cocoa/applescript/bookmark_node_applescript.mm130
-rw-r--r--chrome/browser/cocoa/applescript/browsercrapplication+applescript.h59
-rw-r--r--chrome/browser/cocoa/applescript/browsercrapplication+applescript.mm136
-rw-r--r--chrome/browser/cocoa/applescript/browsercrapplication+applescript_test.mm107
-rw-r--r--chrome/browser/cocoa/applescript/constants_applescript.h31
-rw-r--r--chrome/browser/cocoa/applescript/constants_applescript.mm25
-rw-r--r--chrome/browser/cocoa/applescript/element_applescript.h37
-rw-r--r--chrome/browser/cocoa/applescript/element_applescript.mm38
-rw-r--r--chrome/browser/cocoa/applescript/error_applescript.h41
-rw-r--r--chrome/browser/cocoa/applescript/error_applescript.mm56
-rw-r--r--chrome/browser/cocoa/applescript/tab_applescript.h79
-rw-r--r--chrome/browser/cocoa/applescript/tab_applescript.mm296
-rw-r--r--chrome/browser/cocoa/applescript/window_applescript.h81
-rw-r--r--chrome/browser/cocoa/applescript/window_applescript.mm246
-rw-r--r--chrome/browser/cocoa/applescript/window_applescript_test.mm178
-rw-r--r--chrome/browser/cocoa/authorization_util.h67
-rw-r--r--chrome/browser/cocoa/authorization_util.mm184
-rw-r--r--chrome/browser/cocoa/back_forward_menu_controller.h43
-rw-r--r--chrome/browser/cocoa/back_forward_menu_controller.mm102
-rw-r--r--chrome/browser/cocoa/background_gradient_view.h29
-rw-r--r--chrome/browser/cocoa/background_gradient_view.mm81
-rw-r--r--chrome/browser/cocoa/background_gradient_view_unittest.mm47
-rw-r--r--chrome/browser/cocoa/background_tile_view.h23
-rw-r--r--chrome/browser/cocoa/background_tile_view.mm32
-rw-r--r--chrome/browser/cocoa/background_tile_view_unittest.mm37
-rw-r--r--chrome/browser/cocoa/base_bubble_controller.h67
-rw-r--r--chrome/browser/cocoa/base_bubble_controller.mm201
-rw-r--r--chrome/browser/cocoa/base_view.h45
-rw-r--r--chrome/browser/cocoa/base_view.mm147
-rw-r--r--chrome/browser/cocoa/base_view_unittest.mm48
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_all_tabs_controller.h46
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_all_tabs_controller.mm88
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_all_tabs_controller_unittest.mm82
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_bridge.h60
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_bridge.mm82
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_bridge_unittest.mm135
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_constants.h38
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_controller.h399
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_controller.mm2497
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_controller_unittest.mm2169
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_folder_button_cell.h31
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_folder_button_cell.mm22
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_folder_button_cell_unittest.mm24
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_folder_controller.h182
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_folder_controller.mm1459
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_folder_controller_unittest.mm1552
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_folder_hover_state.h78
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_folder_hover_state.mm171
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_folder_hover_state_unittest.mm77
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_folder_view.mm204
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_folder_view_unittest.mm211
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_folder_window.h34
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_folder_window.mm136
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_folder_window_unittest.mm49
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_state.h62
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_toolbar_view.h44
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_toolbar_view.mm135
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_toolbar_view_unittest.mm191
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_unittest_helper.h57
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_unittest_helper.mm81
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_view.h41
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_view.mm259
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bar_view_unittest.mm215
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bubble_controller.h81
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bubble_controller.mm428
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_bubble_controller_unittest.mm490
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_button.h243
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_button.mm238
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_button_cell.h65
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_button_cell.mm246
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_button_cell_unittest.mm183
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_button_unittest.mm174
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_drag_source.h30
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_drag_source.mm43
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_editor_base_controller.h171
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_editor_base_controller.mm604
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_editor_base_controller_unittest.mm235
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_editor_controller.h36
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_editor_controller.mm143
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_editor_controller_unittest.mm423
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_folder_target.h50
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_folder_target.mm118
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_folder_target_unittest.mm125
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_menu.mm22
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_menu_bridge.h123
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_menu_bridge.mm253
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_menu_bridge_unittest.mm317
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_menu_cocoa_controller.h46
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm98
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_menu_cocoa_controller_unittest.mm66
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_menu_unittest.mm29
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_model_observer_for_cocoa.h116
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_model_observer_for_cocoa_unittest.mm68
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_name_folder_controller.h64
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_name_folder_controller.mm123
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_name_folder_controller_unittest.mm172
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_tree_browser_cell.h35
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_tree_browser_cell.mm23
-rw-r--r--chrome/browser/cocoa/bookmarks/bookmark_tree_browser_cell_unittest.mm43
-rw-r--r--chrome/browser/cocoa/browser_frame_view.mm399
-rw-r--r--chrome/browser/cocoa/browser_frame_view_unittest.mm48
-rw-r--r--chrome/browser/cocoa/browser_test_helper.h92
-rw-r--r--chrome/browser/cocoa/browser_window_cocoa.h143
-rw-r--r--chrome/browser/cocoa/browser_window_cocoa.mm640
-rw-r--r--chrome/browser/cocoa/browser_window_cocoa_unittest.mm120
-rw-r--r--chrome/browser/cocoa/browser_window_controller.h397
-rw-r--r--chrome/browser/cocoa/browser_window_controller.mm2059
-rw-r--r--chrome/browser/cocoa/browser_window_controller_private.h119
-rw-r--r--chrome/browser/cocoa/browser_window_controller_private.mm509
-rw-r--r--chrome/browser/cocoa/browser_window_controller_unittest.mm670
-rw-r--r--chrome/browser/cocoa/browser_window_factory.mm32
-rw-r--r--chrome/browser/cocoa/bubble_view.mm120
-rw-r--r--chrome/browser/cocoa/bubble_view_unittest.mm58
-rw-r--r--chrome/browser/cocoa/bug_report_window_controller.h112
-rw-r--r--chrome/browser/cocoa/bug_report_window_controller.mm231
-rw-r--r--chrome/browser/cocoa/bug_report_window_controller_unittest.mm78
-rw-r--r--chrome/browser/cocoa/chrome_browser_window.h28
-rw-r--r--chrome/browser/cocoa/chrome_browser_window.mm52
-rw-r--r--chrome/browser/cocoa/chrome_browser_window_unittest.mm45
-rw-r--r--chrome/browser/cocoa/chrome_event_processing_window.h49
-rw-r--r--chrome/browser/cocoa/chrome_event_processing_window.mm164
-rw-r--r--chrome/browser/cocoa/chrome_event_processing_window_unittest.mm104
-rw-r--r--chrome/browser/cocoa/clear_browsing_data_controller.h87
-rw-r--r--chrome/browser/cocoa/clear_browsing_data_controller.mm264
-rw-r--r--chrome/browser/cocoa/clear_browsing_data_controller_unittest.mm149
-rw-r--r--chrome/browser/cocoa/clickhold_button_cell.h48
-rw-r--r--chrome/browser/cocoa/clickhold_button_cell.mm190
-rw-r--r--chrome/browser/cocoa/clickhold_button_cell_unittest.mm51
-rw-r--r--chrome/browser/cocoa/cocoa_test_helper.h153
-rw-r--r--chrome/browser/cocoa/cocoa_test_helper.mm205
-rw-r--r--chrome/browser/cocoa/collected_cookies_mac.h123
-rw-r--r--chrome/browser/cocoa/collected_cookies_mac.mm499
-rw-r--r--chrome/browser/cocoa/collected_cookies_mac_unittest.mm39
-rw-r--r--chrome/browser/cocoa/command_observer_bridge.h47
-rw-r--r--chrome/browser/cocoa/command_observer_bridge.mm28
-rw-r--r--chrome/browser/cocoa/command_observer_bridge_unittest.mm89
-rw-r--r--chrome/browser/cocoa/confirm_quit_panel_controller.h25
-rw-r--r--chrome/browser/cocoa/confirm_quit_panel_controller.mm85
-rw-r--r--chrome/browser/cocoa/confirm_quit_panel_controller_unittest.mm28
-rw-r--r--chrome/browser/cocoa/constrained_html_delegate_mac.mm153
-rw-r--r--chrome/browser/cocoa/constrained_window_mac.h165
-rw-r--r--chrome/browser/cocoa/constrained_window_mac.mm104
-rw-r--r--chrome/browser/cocoa/content_exceptions_window_controller.h74
-rw-r--r--chrome/browser/cocoa/content_exceptions_window_controller.mm490
-rw-r--r--chrome/browser/cocoa/content_exceptions_window_controller_unittest.mm252
-rw-r--r--chrome/browser/cocoa/content_setting_bubble_cocoa.h67
-rw-r--r--chrome/browser/cocoa/content_setting_bubble_cocoa.mm487
-rw-r--r--chrome/browser/cocoa/content_setting_bubble_cocoa_unittest.mm63
-rw-r--r--chrome/browser/cocoa/content_settings_dialog_controller.h102
-rw-r--r--chrome/browser/cocoa/content_settings_dialog_controller.mm647
-rw-r--r--chrome/browser/cocoa/content_settings_dialog_controller_unittest.mm289
-rw-r--r--chrome/browser/cocoa/cookie_details.mm299
-rw-r--r--chrome/browser/cocoa/cookie_details_unittest.mm247
-rw-r--r--chrome/browser/cocoa/cookie_details_view_controller.h56
-rw-r--r--chrome/browser/cocoa/cookie_details_view_controller.mm110
-rw-r--r--chrome/browser/cocoa/cookie_details_view_controller_unittest.mm88
-rw-r--r--chrome/browser/cocoa/cookie_tree_node.h37
-rw-r--r--chrome/browser/cocoa/cookie_tree_node.mm73
-rw-r--r--chrome/browser/cocoa/cookies_window_controller.h146
-rw-r--r--chrome/browser/cocoa/cookies_window_controller.mm448
-rw-r--r--chrome/browser/cocoa/cookies_window_controller_unittest.mm687
-rw-r--r--chrome/browser/cocoa/custom_home_pages_model.h91
-rw-r--r--chrome/browser/cocoa/custom_home_pages_model.mm140
-rw-r--r--chrome/browser/cocoa/custom_home_pages_model_unittest.mm196
-rw-r--r--chrome/browser/cocoa/delayedmenu_button.h32
-rw-r--r--chrome/browser/cocoa/delayedmenu_button.mm137
-rw-r--r--chrome/browser/cocoa/delayedmenu_button_unittest.mm62
-rw-r--r--chrome/browser/cocoa/dev_tools_controller.h51
-rw-r--r--chrome/browser/cocoa/dev_tools_controller.mm164
-rw-r--r--chrome/browser/cocoa/dock_icon.mm224
-rw-r--r--chrome/browser/cocoa/download/download_item_button.h27
-rw-r--r--chrome/browser/cocoa/download/download_item_button.mm50
-rw-r--r--chrome/browser/cocoa/download/download_item_button_unittest.mm21
-rw-r--r--chrome/browser/cocoa/download/download_item_cell.h61
-rw-r--r--chrome/browser/cocoa/download/download_item_cell.mm708
-rw-r--r--chrome/browser/cocoa/download/download_item_controller.h105
-rw-r--r--chrome/browser/cocoa/download/download_item_controller.mm398
-rw-r--r--chrome/browser/cocoa/download/download_item_mac.h63
-rw-r--r--chrome/browser/cocoa/download/download_item_mac.mm96
-rw-r--r--chrome/browser/cocoa/download/download_shelf_controller.h95
-rw-r--r--chrome/browser/cocoa/download/download_shelf_controller.mm327
-rw-r--r--chrome/browser/cocoa/download/download_shelf_mac.h43
-rw-r--r--chrome/browser/cocoa/download/download_shelf_mac.mm40
-rw-r--r--chrome/browser/cocoa/download/download_shelf_mac_unittest.mm91
-rw-r--r--chrome/browser/cocoa/download/download_shelf_view.h20
-rw-r--r--chrome/browser/cocoa/download/download_shelf_view.mm71
-rw-r--r--chrome/browser/cocoa/download/download_shelf_view_unittest.mm23
-rw-r--r--chrome/browser/cocoa/download/download_started_animation_mac.mm195
-rw-r--r--chrome/browser/cocoa/download/download_util_mac.h25
-rw-r--r--chrome/browser/cocoa/download/download_util_mac.mm83
-rw-r--r--chrome/browser/cocoa/download/download_util_mac_unittest.mm58
-rw-r--r--chrome/browser/cocoa/draggable_button.mm150
-rw-r--r--chrome/browser/cocoa/draggable_button_unittest.mm137
-rw-r--r--chrome/browser/cocoa/edit_search_engine_cocoa_controller.h53
-rw-r--r--chrome/browser/cocoa/edit_search_engine_cocoa_controller.mm187
-rw-r--r--chrome/browser/cocoa/edit_search_engine_cocoa_controller_unittest.mm233
-rw-r--r--chrome/browser/cocoa/encoding_menu_controller_delegate_mac.h24
-rw-r--r--chrome/browser/cocoa/encoding_menu_controller_delegate_mac.mm60
-rw-r--r--chrome/browser/cocoa/event_utils.h30
-rw-r--r--chrome/browser/cocoa/event_utils.mm21
-rw-r--r--chrome/browser/cocoa/event_utils_unittest.mm61
-rw-r--r--chrome/browser/cocoa/extension_installed_bubble_bridge.h28
-rw-r--r--chrome/browser/cocoa/extension_installed_bubble_bridge.mm25
-rw-r--r--chrome/browser/cocoa/extension_installed_bubble_controller.h112
-rw-r--r--chrome/browser/cocoa/extension_installed_bubble_controller.mm374
-rw-r--r--chrome/browser/cocoa/extension_installed_bubble_controller_unittest.mm202
-rw-r--r--chrome/browser/cocoa/extension_view_mac.h88
-rw-r--r--chrome/browser/cocoa/extension_view_mac.mm112
-rw-r--r--chrome/browser/cocoa/extensions/browser_action_button.h98
-rw-r--r--chrome/browser/cocoa/extensions/browser_action_button.mm333
-rw-r--r--chrome/browser/cocoa/extensions/browser_actions_container_view.h84
-rw-r--r--chrome/browser/cocoa/extensions/browser_actions_container_view.mm192
-rw-r--r--chrome/browser/cocoa/extensions/browser_actions_container_view_unittest.mm52
-rw-r--r--chrome/browser/cocoa/extensions/browser_actions_controller.h117
-rw-r--r--chrome/browser/cocoa/extensions/browser_actions_controller.mm863
-rw-r--r--chrome/browser/cocoa/extensions/chevron_menu_button.h19
-rw-r--r--chrome/browser/cocoa/extensions/chevron_menu_button.mm15
-rw-r--r--chrome/browser/cocoa/extensions/chevron_menu_button_cell.h19
-rw-r--r--chrome/browser/cocoa/extensions/chevron_menu_button_cell.mm47
-rw-r--r--chrome/browser/cocoa/extensions/chevron_menu_button_unittest.mm50
-rw-r--r--chrome/browser/cocoa/extensions/extension_action_context_menu.h62
-rw-r--r--chrome/browser/cocoa/extensions/extension_action_context_menu.mm278
-rw-r--r--chrome/browser/cocoa/extensions/extension_infobar_controller.h41
-rw-r--r--chrome/browser/cocoa/extensions/extension_infobar_controller.mm266
-rw-r--r--chrome/browser/cocoa/extensions/extension_install_prompt_controller.h62
-rw-r--r--chrome/browser/cocoa/extensions/extension_install_prompt_controller.mm217
-rw-r--r--chrome/browser/cocoa/extensions/extension_install_prompt_controller_unittest.mm286
-rw-r--r--chrome/browser/cocoa/extensions/extension_popup_controller.h99
-rw-r--r--chrome/browser/cocoa/extensions/extension_popup_controller.mm338
-rw-r--r--chrome/browser/cocoa/extensions/extension_popup_controller_unittest.mm89
-rw-r--r--chrome/browser/cocoa/external_protocol_dialog.mm152
-rw-r--r--chrome/browser/cocoa/fast_resize_view.h29
-rw-r--r--chrome/browser/cocoa/fast_resize_view.mm65
-rw-r--r--chrome/browser/cocoa/fast_resize_view_unittest.mm60
-rw-r--r--chrome/browser/cocoa/file_metadata.h29
-rw-r--r--chrome/browser/cocoa/file_metadata.mm167
-rw-r--r--chrome/browser/cocoa/find_bar_bridge.h95
-rw-r--r--chrome/browser/cocoa/find_bar_bridge.mm96
-rw-r--r--chrome/browser/cocoa/find_bar_bridge_unittest.mm30
-rw-r--r--chrome/browser/cocoa/find_bar_cocoa_controller.h78
-rw-r--r--chrome/browser/cocoa/find_bar_cocoa_controller.mm384
-rw-r--r--chrome/browser/cocoa/find_bar_cocoa_controller_unittest.mm138
-rw-r--r--chrome/browser/cocoa/find_bar_text_field.h21
-rw-r--r--chrome/browser/cocoa/find_bar_text_field.mm40
-rw-r--r--chrome/browser/cocoa/find_bar_text_field_cell.h24
-rw-r--r--chrome/browser/cocoa/find_bar_text_field_cell.mm119
-rw-r--r--chrome/browser/cocoa/find_bar_text_field_cell_unittest.mm135
-rw-r--r--chrome/browser/cocoa/find_bar_text_field_unittest.mm92
-rw-r--r--chrome/browser/cocoa/find_bar_view.h19
-rw-r--r--chrome/browser/cocoa/find_bar_view.mm131
-rw-r--r--chrome/browser/cocoa/find_bar_view_unittest.mm90
-rw-r--r--chrome/browser/cocoa/find_pasteboard.h58
-rw-r--r--chrome/browser/cocoa/find_pasteboard.mm82
-rw-r--r--chrome/browser/cocoa/find_pasteboard_unittest.mm115
-rw-r--r--chrome/browser/cocoa/first_run_bubble_controller.h24
-rw-r--r--chrome/browser/cocoa/first_run_bubble_controller.mm84
-rw-r--r--chrome/browser/cocoa/first_run_bubble_controller_unittest.mm44
-rw-r--r--chrome/browser/cocoa/first_run_dialog.mm195
-rw-r--r--chrome/browser/cocoa/floating_bar_backing_view.h15
-rw-r--r--chrome/browser/cocoa/floating_bar_backing_view.mm51
-rw-r--r--chrome/browser/cocoa/floating_bar_backing_view_unittest.mm26
-rw-r--r--chrome/browser/cocoa/focus_tracker.mm46
-rw-r--r--chrome/browser/cocoa/focus_tracker_unittest.mm90
-rw-r--r--chrome/browser/cocoa/font_language_settings_controller.h94
-rw-r--r--chrome/browser/cocoa/font_language_settings_controller.mm280
-rw-r--r--chrome/browser/cocoa/font_language_settings_controller_unittest.mm91
-rw-r--r--chrome/browser/cocoa/framed_browser_window.h65
-rw-r--r--chrome/browser/cocoa/framed_browser_window.mm350
-rw-r--r--chrome/browser/cocoa/framed_browser_window_unittest.mm184
-rw-r--r--chrome/browser/cocoa/fullscreen_controller.h122
-rw-r--r--chrome/browser/cocoa/fullscreen_controller.mm633
-rw-r--r--chrome/browser/cocoa/fullscreen_window.h19
-rw-r--r--chrome/browser/cocoa/fullscreen_window.mm100
-rw-r--r--chrome/browser/cocoa/fullscreen_window_unittest.mm47
-rw-r--r--chrome/browser/cocoa/gradient_button_cell.h120
-rw-r--r--chrome/browser/cocoa/gradient_button_cell.mm719
-rw-r--r--chrome/browser/cocoa/gradient_button_cell_unittest.mm112
-rw-r--r--chrome/browser/cocoa/history_menu_bridge.h232
-rw-r--r--chrome/browser/cocoa/history_menu_bridge.mm470
-rw-r--r--chrome/browser/cocoa/history_menu_bridge_unittest.mm386
-rw-r--r--chrome/browser/cocoa/history_menu_cocoa_controller.h32
-rw-r--r--chrome/browser/cocoa/history_menu_cocoa_controller.mm58
-rw-r--r--chrome/browser/cocoa/history_menu_cocoa_controller_unittest.mm91
-rw-r--r--chrome/browser/cocoa/hover_button.mm97
-rw-r--r--chrome/browser/cocoa/hover_close_button.h26
-rw-r--r--chrome/browser/cocoa/hover_close_button.mm108
-rw-r--r--chrome/browser/cocoa/hover_image_button.h40
-rw-r--r--chrome/browser/cocoa/hover_image_button.mm52
-rw-r--r--chrome/browser/cocoa/hover_image_button_unittest.mm67
-rw-r--r--chrome/browser/cocoa/html_dialog_window_controller.h55
-rw-r--r--chrome/browser/cocoa/html_dialog_window_controller.mm293
-rw-r--r--chrome/browser/cocoa/html_dialog_window_controller_cppsafe.h32
-rw-r--r--chrome/browser/cocoa/html_dialog_window_controller_unittest.mm94
-rw-r--r--chrome/browser/cocoa/hung_renderer_controller.h76
-rw-r--r--chrome/browser/cocoa/hung_renderer_controller.mm203
-rw-r--r--chrome/browser/cocoa/hung_renderer_controller_unittest.mm51
-rw-r--r--chrome/browser/cocoa/hyperlink_button_cell.mm116
-rw-r--r--chrome/browser/cocoa/hyperlink_button_cell_unittest.mm75
-rw-r--r--chrome/browser/cocoa/image_utils.h26
-rw-r--r--chrome/browser/cocoa/image_utils.mm37
-rw-r--r--chrome/browser/cocoa/image_utils_unittest.mm138
-rw-r--r--chrome/browser/cocoa/import_progress_dialog.mm192
-rw-r--r--chrome/browser/cocoa/import_settings_dialog.h98
-rw-r--r--chrome/browser/cocoa/import_settings_dialog.mm245
-rw-r--r--chrome/browser/cocoa/import_settings_dialog_unittest.mm130
-rw-r--r--chrome/browser/cocoa/importer_lock_dialog.h21
-rw-r--r--chrome/browser/cocoa/info_bubble_view.h50
-rw-r--r--chrome/browser/cocoa/info_bubble_view.mm103
-rw-r--r--chrome/browser/cocoa/info_bubble_view_unittest.mm26
-rw-r--r--chrome/browser/cocoa/info_bubble_window.h32
-rw-r--r--chrome/browser/cocoa/info_bubble_window.mm222
-rw-r--r--chrome/browser/cocoa/info_bubble_window_unittest.mm22
-rw-r--r--chrome/browser/cocoa/infobar.h48
-rw-r--r--chrome/browser/cocoa/infobar_container_controller.h113
-rw-r--r--chrome/browser/cocoa/infobar_container_controller.mm228
-rw-r--r--chrome/browser/cocoa/infobar_container_controller_unittest.mm95
-rw-r--r--chrome/browser/cocoa/infobar_controller.h106
-rw-r--r--chrome/browser/cocoa/infobar_controller.mm534
-rw-r--r--chrome/browser/cocoa/infobar_controller_unittest.mm284
-rw-r--r--chrome/browser/cocoa/infobar_gradient_view.h19
-rw-r--r--chrome/browser/cocoa/infobar_gradient_view.mm70
-rw-r--r--chrome/browser/cocoa/infobar_gradient_view_unittest.mm32
-rw-r--r--chrome/browser/cocoa/install_from_dmg.h15
-rw-r--r--chrome/browser/cocoa/install_from_dmg.mm438
-rw-r--r--chrome/browser/cocoa/instant_confirm_window_controller.h43
-rw-r--r--chrome/browser/cocoa/instant_confirm_window_controller.mm76
-rw-r--r--chrome/browser/cocoa/instant_confirm_window_controller_unittest.mm36
-rw-r--r--chrome/browser/cocoa/js_modal_dialog_cocoa.h48
-rw-r--r--chrome/browser/cocoa/js_modal_dialog_cocoa.mm219
-rw-r--r--chrome/browser/cocoa/keystone_glue.h209
-rw-r--r--chrome/browser/cocoa/keystone_glue.mm959
-rw-r--r--chrome/browser/cocoa/keystone_glue_unittest.mm184
-rw-r--r--chrome/browser/cocoa/keystone_infobar.h24
-rw-r--r--chrome/browser/cocoa/keystone_infobar.mm212
-rwxr-xr-xchrome/browser/cocoa/keystone_promote_postflight.sh55
-rw-r--r--chrome/browser/cocoa/keyword_editor_cocoa_controller.h117
-rw-r--r--chrome/browser/cocoa/keyword_editor_cocoa_controller.mm422
-rw-r--r--chrome/browser/cocoa/keyword_editor_cocoa_controller_unittest.mm227
-rw-r--r--chrome/browser/cocoa/l10n_util.mm78
-rw-r--r--chrome/browser/cocoa/location_bar/autocomplete_text_field.h144
-rw-r--r--chrome/browser/cocoa/location_bar/autocomplete_text_field.mm385
-rw-r--r--chrome/browser/cocoa/location_bar/autocomplete_text_field_cell.h76
-rw-r--r--chrome/browser/cocoa/location_bar/autocomplete_text_field_cell.mm402
-rw-r--r--chrome/browser/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm300
-rw-r--r--chrome/browser/cocoa/location_bar/autocomplete_text_field_editor.h56
-rw-r--r--chrome/browser/cocoa/location_bar/autocomplete_text_field_editor.mm371
-rw-r--r--chrome/browser/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm297
-rw-r--r--chrome/browser/cocoa/location_bar/autocomplete_text_field_unittest.mm792
-rw-r--r--chrome/browser/cocoa/location_bar/autocomplete_text_field_unittest_helper.h58
-rw-r--r--chrome/browser/cocoa/location_bar/autocomplete_text_field_unittest_helper.mm29
-rw-r--r--chrome/browser/cocoa/location_bar/bubble_decoration.h67
-rw-r--r--chrome/browser/cocoa/location_bar/bubble_decoration.mm158
-rw-r--r--chrome/browser/cocoa/location_bar/content_setting_decoration.h55
-rw-r--r--chrome/browser/cocoa/location_bar/content_setting_decoration.mm109
-rw-r--r--chrome/browser/cocoa/location_bar/ev_bubble_decoration.h59
-rw-r--r--chrome/browser/cocoa/location_bar/ev_bubble_decoration.mm117
-rw-r--r--chrome/browser/cocoa/location_bar/ev_bubble_decoration_unittest.mm55
-rw-r--r--chrome/browser/cocoa/location_bar/image_decoration.h36
-rw-r--r--chrome/browser/cocoa/location_bar/image_decoration.mm54
-rw-r--r--chrome/browser/cocoa/location_bar/image_decoration_unittest.mm55
-rw-r--r--chrome/browser/cocoa/location_bar/instant_opt_in_controller.h43
-rw-r--r--chrome/browser/cocoa/location_bar/instant_opt_in_controller.mm31
-rw-r--r--chrome/browser/cocoa/location_bar/instant_opt_in_controller_unittest.mm62
-rw-r--r--chrome/browser/cocoa/location_bar/instant_opt_in_view.h16
-rw-r--r--chrome/browser/cocoa/location_bar/instant_opt_in_view.mm54
-rw-r--r--chrome/browser/cocoa/location_bar/instant_opt_in_view_unittest.mm26
-rw-r--r--chrome/browser/cocoa/location_bar/keyword_hint_decoration.h47
-rw-r--r--chrome/browser/cocoa/location_bar/keyword_hint_decoration.mm160
-rw-r--r--chrome/browser/cocoa/location_bar/keyword_hint_decoration_unittest.mm57
-rw-r--r--chrome/browser/cocoa/location_bar/location_bar_decoration.h89
-rw-r--r--chrome/browser/cocoa/location_bar/location_bar_decoration.mm18
-rw-r--r--chrome/browser/cocoa/location_bar/location_bar_view_mac.h237
-rw-r--r--chrome/browser/cocoa/location_bar/location_bar_view_mac.mm692
-rw-r--r--chrome/browser/cocoa/location_bar/location_icon_decoration.h46
-rw-r--r--chrome/browser/cocoa/location_bar/location_icon_decoration.mm72
-rw-r--r--chrome/browser/cocoa/location_bar/omnibox_popup_view.h17
-rw-r--r--chrome/browser/cocoa/location_bar/omnibox_popup_view.mm43
-rw-r--r--chrome/browser/cocoa/location_bar/omnibox_popup_view_unittest.mm68
-rw-r--r--chrome/browser/cocoa/location_bar/page_action_decoration.h120
-rw-r--r--chrome/browser/cocoa/location_bar/page_action_decoration.mm251
-rw-r--r--chrome/browser/cocoa/location_bar/selected_keyword_decoration.h42
-rw-r--r--chrome/browser/cocoa/location_bar/selected_keyword_decoration.mm73
-rw-r--r--chrome/browser/cocoa/location_bar/selected_keyword_decoration_unittest.mm65
-rw-r--r--chrome/browser/cocoa/location_bar/star_decoration.h44
-rw-r--r--chrome/browser/cocoa/location_bar/star_decoration.mm53
-rw-r--r--chrome/browser/cocoa/menu_button.h32
-rw-r--r--chrome/browser/cocoa/menu_button.mm122
-rw-r--r--chrome/browser/cocoa/menu_button_unittest.mm50
-rw-r--r--chrome/browser/cocoa/menu_controller.h67
-rw-r--r--chrome/browser/cocoa/menu_controller.mm185
-rw-r--r--chrome/browser/cocoa/menu_controller_unittest.mm197
-rw-r--r--chrome/browser/cocoa/menu_tracked_button.h43
-rw-r--r--chrome/browser/cocoa/menu_tracked_button.mm118
-rw-r--r--chrome/browser/cocoa/menu_tracked_button_unittest.mm117
-rw-r--r--chrome/browser/cocoa/menu_tracked_root_view.h25
-rw-r--r--chrome/browser/cocoa/menu_tracked_root_view.mm15
-rw-r--r--chrome/browser/cocoa/menu_tracked_root_view_unittest.mm45
-rw-r--r--chrome/browser/cocoa/multi_key_equivalent_button.h36
-rw-r--r--chrome/browser/cocoa/multi_key_equivalent_button.mm33
-rw-r--r--chrome/browser/cocoa/new_tab_button.h28
-rw-r--r--chrome/browser/cocoa/new_tab_button.mm42
-rw-r--r--chrome/browser/cocoa/notifications/balloon_controller.h98
-rw-r--r--chrome/browser/cocoa/notifications/balloon_controller.mm241
-rw-r--r--chrome/browser/cocoa/notifications/balloon_controller_unittest.mm113
-rw-r--r--chrome/browser/cocoa/notifications/balloon_view.h28
-rw-r--r--chrome/browser/cocoa/notifications/balloon_view.mm84
-rw-r--r--chrome/browser/cocoa/notifications/balloon_view_bridge.h40
-rw-r--r--chrome/browser/cocoa/notifications/balloon_view_bridge.mm48
-rw-r--r--chrome/browser/cocoa/notifications/balloon_view_host_mac.h42
-rw-r--r--chrome/browser/cocoa/notifications/balloon_view_host_mac.mm39
-rw-r--r--chrome/browser/cocoa/nsimage_cache_unittest.mm75
-rw-r--r--chrome/browser/cocoa/nsmenuitem_additions.h19
-rw-r--r--chrome/browser/cocoa/nsmenuitem_additions.mm103
-rw-r--r--chrome/browser/cocoa/nsmenuitem_additions_unittest.mm351
-rw-r--r--chrome/browser/cocoa/nswindow_additions.h25
-rw-r--r--chrome/browser/cocoa/nswindow_additions.mm104
-rw-r--r--chrome/browser/cocoa/objc_method_swizzle.h28
-rw-r--r--chrome/browser/cocoa/objc_method_swizzle.mm59
-rw-r--r--chrome/browser/cocoa/objc_method_swizzle_unittest.mm76
-rw-r--r--chrome/browser/cocoa/objc_zombie.h39
-rw-r--r--chrome/browser/cocoa/objc_zombie.mm414
-rw-r--r--chrome/browser/cocoa/page_info_bubble_controller.h47
-rw-r--r--chrome/browser/cocoa/page_info_bubble_controller.mm461
-rw-r--r--chrome/browser/cocoa/page_info_bubble_controller_unittest.mm210
-rw-r--r--chrome/browser/cocoa/preferences_window_controller.h241
-rw-r--r--chrome/browser/cocoa/preferences_window_controller.mm2184
-rw-r--r--chrome/browser/cocoa/preferences_window_controller_unittest.mm240
-rw-r--r--chrome/browser/cocoa/previewable_contents_controller.h47
-rw-r--r--chrome/browser/cocoa/previewable_contents_controller.mm52
-rw-r--r--chrome/browser/cocoa/previewable_contents_controller_unittest.mm34
-rw-r--r--chrome/browser/cocoa/reload_button.h50
-rw-r--r--chrome/browser/cocoa/reload_button.mm168
-rw-r--r--chrome/browser/cocoa/reload_button_unittest.mm259
-rw-r--r--chrome/browser/cocoa/repost_form_warning_mac.h40
-rw-r--r--chrome/browser/cocoa/repost_form_warning_mac.mm82
-rw-r--r--chrome/browser/cocoa/restart_browser.h22
-rw-r--r--chrome/browser/cocoa/restart_browser.mm86
-rw-r--r--chrome/browser/cocoa/rwhvm_editcommand_helper.h72
-rw-r--r--chrome/browser/cocoa/rwhvm_editcommand_helper.mm227
-rw-r--r--chrome/browser/cocoa/rwhvm_editcommand_helper_unittest.mm172
-rw-r--r--chrome/browser/cocoa/sad_tab_controller.h33
-rw-r--r--chrome/browser/cocoa/sad_tab_controller.mm48
-rw-r--r--chrome/browser/cocoa/sad_tab_controller_unittest.mm113
-rw-r--r--chrome/browser/cocoa/sad_tab_view.h36
-rw-r--r--chrome/browser/cocoa/sad_tab_view.mm127
-rw-r--r--chrome/browser/cocoa/sad_tab_view_unittest.mm25
-rw-r--r--chrome/browser/cocoa/scoped_authorizationref.h80
-rw-r--r--chrome/browser/cocoa/search_engine_dialog_controller.mm285
-rw-r--r--chrome/browser/cocoa/search_engine_list_model.h48
-rw-r--r--chrome/browser/cocoa/search_engine_list_model.mm136
-rw-r--r--chrome/browser/cocoa/search_engine_list_model_unittest.mm152
-rw-r--r--chrome/browser/cocoa/shell_dialogs_mac.mm417
-rw-r--r--chrome/browser/cocoa/side_tab_strip_controller.h19
-rw-r--r--chrome/browser/cocoa/side_tab_strip_controller.mm33
-rw-r--r--chrome/browser/cocoa/side_tab_strip_view.h15
-rw-r--r--chrome/browser/cocoa/side_tab_strip_view.mm43
-rw-r--r--chrome/browser/cocoa/side_tab_strip_view_unittest.mm30
-rw-r--r--chrome/browser/cocoa/sidebar_controller.h51
-rw-r--r--chrome/browser/cocoa/sidebar_controller.mm179
-rw-r--r--chrome/browser/cocoa/simple_content_exceptions_window_controller.h38
-rw-r--r--chrome/browser/cocoa/simple_content_exceptions_window_controller.mm125
-rw-r--r--chrome/browser/cocoa/simple_content_exceptions_window_controller_unittest.mm94
-rw-r--r--chrome/browser/cocoa/speech_input_window_controller.h57
-rw-r--r--chrome/browser/cocoa/speech_input_window_controller.mm188
-rw-r--r--chrome/browser/cocoa/ssl_client_certificate_selector.mm195
-rw-r--r--chrome/browser/cocoa/status_bubble_mac.h172
-rw-r--r--chrome/browser/cocoa/status_bubble_mac.mm705
-rw-r--r--chrome/browser/cocoa/status_bubble_mac_unittest.mm584
-rw-r--r--chrome/browser/cocoa/status_icons/status_icon_mac.h44
-rw-r--r--chrome/browser/cocoa/status_icons/status_icon_mac.mm82
-rw-r--r--chrome/browser/cocoa/status_icons/status_icon_mac_unittest.mm30
-rw-r--r--chrome/browser/cocoa/status_icons/status_tray_mac.h24
-rw-r--r--chrome/browser/cocoa/status_icons/status_tray_mac.mm18
-rw-r--r--chrome/browser/cocoa/styled_text_field.mm61
-rw-r--r--chrome/browser/cocoa/styled_text_field_cell.h58
-rw-r--r--chrome/browser/cocoa/styled_text_field_cell.mm217
-rw-r--r--chrome/browser/cocoa/styled_text_field_cell_unittest.mm93
-rw-r--r--chrome/browser/cocoa/styled_text_field_test_helper.h16
-rw-r--r--chrome/browser/cocoa/styled_text_field_test_helper.mm18
-rw-r--r--chrome/browser/cocoa/styled_text_field_unittest.mm198
-rw-r--r--chrome/browser/cocoa/tab_contents_controller.h75
-rw-r--r--chrome/browser/cocoa/tab_contents_controller.mm212
-rw-r--r--chrome/browser/cocoa/tab_controller.h113
-rw-r--r--chrome/browser/cocoa/tab_controller.mm313
-rw-r--r--chrome/browser/cocoa/tab_controller_target.h27
-rw-r--r--chrome/browser/cocoa/tab_controller_unittest.mm268
-rw-r--r--chrome/browser/cocoa/tab_strip_controller.h259
-rw-r--r--chrome/browser/cocoa/tab_strip_controller.mm1879
-rw-r--r--chrome/browser/cocoa/tab_strip_controller_unittest.mm177
-rw-r--r--chrome/browser/cocoa/tab_strip_model_observer_bridge.h85
-rw-r--r--chrome/browser/cocoa/tab_strip_model_observer_bridge.mm118
-rw-r--r--chrome/browser/cocoa/tab_strip_view.h48
-rw-r--r--chrome/browser/cocoa/tab_strip_view.mm211
-rw-r--r--chrome/browser/cocoa/tab_strip_view_unittest.mm30
-rw-r--r--chrome/browser/cocoa/tab_view.h134
-rw-r--r--chrome/browser/cocoa/tab_view.mm1057
-rw-r--r--chrome/browser/cocoa/tab_view_picker_table.h29
-rw-r--r--chrome/browser/cocoa/tab_view_picker_table_unittest.mm138
-rw-r--r--chrome/browser/cocoa/tab_view_unittest.mm60
-rw-r--r--chrome/browser/cocoa/tab_window_controller.h177
-rw-r--r--chrome/browser/cocoa/tab_window_controller.mm351
-rw-r--r--chrome/browser/cocoa/table_model_array_controller.h54
-rw-r--r--chrome/browser/cocoa/table_model_array_controller.mm246
-rw-r--r--chrome/browser/cocoa/table_model_array_controller_unittest.mm172
-rw-r--r--chrome/browser/cocoa/table_row_nsimage_cache.h55
-rw-r--r--chrome/browser/cocoa/table_row_nsimage_cache.mm79
-rw-r--r--chrome/browser/cocoa/table_row_nsimage_cache_unittest.mm200
-rw-r--r--chrome/browser/cocoa/tabpose_window.h94
-rw-r--r--chrome/browser/cocoa/tabpose_window.mm1437
-rw-r--r--chrome/browser/cocoa/tabpose_window_unittest.mm119
-rw-r--r--chrome/browser/cocoa/task_helpers.h29
-rw-r--r--chrome/browser/cocoa/task_helpers.mm57
-rw-r--r--chrome/browser/cocoa/task_manager_mac.h118
-rw-r--r--chrome/browser/cocoa/task_manager_mac.mm582
-rw-r--r--chrome/browser/cocoa/task_manager_mac_unittest.mm115
-rw-r--r--chrome/browser/cocoa/test_event_utils.h48
-rw-r--r--chrome/browser/cocoa/test_event_utils.mm86
-rw-r--r--chrome/browser/cocoa/theme_install_bubble_view.h57
-rw-r--r--chrome/browser/cocoa/theme_install_bubble_view.mm186
-rw-r--r--chrome/browser/cocoa/themed_window.h30
-rw-r--r--chrome/browser/cocoa/themed_window.mm23
-rw-r--r--chrome/browser/cocoa/throbber_view.h42
-rw-r--r--chrome/browser/cocoa/throbber_view.mm372
-rw-r--r--chrome/browser/cocoa/throbber_view_unittest.mm32
-rw-r--r--chrome/browser/cocoa/toolbar_controller.h189
-rw-r--r--chrome/browser/cocoa/toolbar_controller.mm753
-rw-r--r--chrome/browser/cocoa/toolbar_controller_unittest.mm237
-rw-r--r--chrome/browser/cocoa/toolbar_view.h26
-rw-r--r--chrome/browser/cocoa/toolbar_view.mm47
-rw-r--r--chrome/browser/cocoa/toolbar_view_unittest.mm23
-rw-r--r--chrome/browser/cocoa/translate/after_translate_infobar_controller.h11
-rw-r--r--chrome/browser/cocoa/translate/after_translate_infobar_controller.mm60
-rw-r--r--chrome/browser/cocoa/translate/before_translate_infobar_controller.h23
-rw-r--r--chrome/browser/cocoa/translate/before_translate_infobar_controller.mm123
-rw-r--r--chrome/browser/cocoa/translate/translate_infobar_base.h163
-rw-r--r--chrome/browser/cocoa/translate/translate_infobar_base.mm642
-rw-r--r--chrome/browser/cocoa/translate/translate_infobar_unittest.mm254
-rw-r--r--chrome/browser/cocoa/translate/translate_message_infobar_controller.h10
-rw-r--r--chrome/browser/cocoa/translate/translate_message_infobar_controller.mm53
-rw-r--r--chrome/browser/cocoa/ui_localizer.h35
-rw-r--r--chrome/browser/cocoa/ui_localizer.mm98
-rw-r--r--chrome/browser/cocoa/url_drop_target.h71
-rw-r--r--chrome/browser/cocoa/url_drop_target.mm98
-rw-r--r--chrome/browser/cocoa/vertical_gradient_view.h36
-rw-r--r--chrome/browser/cocoa/vertical_gradient_view.mm39
-rw-r--r--chrome/browser/cocoa/vertical_gradient_view_unittest.mm27
-rw-r--r--chrome/browser/cocoa/view_id_util.h52
-rw-r--r--chrome/browser/cocoa/view_id_util.mm87
-rw-r--r--chrome/browser/cocoa/view_id_util_browsertest.mm118
-rw-r--r--chrome/browser/cocoa/view_resizer.h28
-rw-r--r--chrome/browser/cocoa/view_resizer_pong.h22
-rw-r--r--chrome/browser/cocoa/view_resizer_pong.mm20
-rw-r--r--chrome/browser/cocoa/web_contents_drag_source.h62
-rw-r--r--chrome/browser/cocoa/web_contents_drag_source.mm130
-rw-r--r--chrome/browser/cocoa/web_drag_source.mm412
-rw-r--r--chrome/browser/cocoa/web_drop_target.mm283
-rw-r--r--chrome/browser/cocoa/web_drop_target_unittest.mm166
-rw-r--r--chrome/browser/cocoa/window_size_autosaver.h35
-rw-r--r--chrome/browser/cocoa/window_size_autosaver.mm108
-rw-r--r--chrome/browser/cocoa/window_size_autosaver_unittest.mm201
-rw-r--r--chrome/browser/cocoa/wrench_menu_button_cell.h19
-rw-r--r--chrome/browser/cocoa/wrench_menu_button_cell.mm48
-rw-r--r--chrome/browser/cocoa/wrench_menu_button_cell_unittest.mm51
-rw-r--r--chrome/browser/cocoa/wrench_menu_controller.h72
-rw-r--r--chrome/browser/cocoa/wrench_menu_controller.mm213
-rw-r--r--chrome/browser/cocoa/wrench_menu_controller_unittest.mm84
-rw-r--r--chrome/browser/content_exceptions_table_model.cc10
-rw-r--r--chrome/browser/content_exceptions_table_model.h6
-rw-r--r--chrome/browser/content_exceptions_table_model_unittest.cc2
-rw-r--r--chrome/browser/content_setting_bubble_model.cc157
-rw-r--r--chrome/browser/content_setting_bubble_model.h28
-rw-r--r--chrome/browser/content_setting_bubble_model_unittest.cc50
-rw-r--r--chrome/browser/content_setting_image_model.cc4
-rw-r--r--chrome/browser/content_setting_image_model_unittest.cc6
-rw-r--r--chrome/browser/content_settings/content_settings_details.h56
-rw-r--r--chrome/browser/content_settings/content_settings_pattern.cc87
-rw-r--r--chrome/browser/content_settings/content_settings_pattern.h72
-rw-r--r--chrome/browser/content_settings/content_settings_pattern_unittest.cc69
-rw-r--r--chrome/browser/content_settings/content_settings_provider.h42
-rw-r--r--chrome/browser/content_settings/content_settings_provider_unittest.cc26
-rw-r--r--chrome/browser/content_settings/host_content_settings_map.cc977
-rw-r--r--chrome/browser/content_settings/host_content_settings_map.h254
-rw-r--r--chrome/browser/content_settings/host_content_settings_map_unittest.cc854
-rw-r--r--chrome/browser/content_settings/host_content_settings_map_unittest.h49
-rw-r--r--chrome/browser/content_settings/mock_content_settings_provider.cc44
-rw-r--r--chrome/browser/content_settings/mock_content_settings_provider.h40
-rw-r--r--chrome/browser/content_settings/policy_content_settings_provider.cc204
-rw-r--r--chrome/browser/content_settings/policy_content_settings_provider.h78
-rw-r--r--chrome/browser/content_settings/policy_content_settings_provider_unittest.cc88
-rw-r--r--chrome/browser/content_settings/pref_content_settings_provider.cc263
-rw-r--r--chrome/browser/content_settings/pref_content_settings_provider.h88
-rw-r--r--chrome/browser/content_settings/pref_content_settings_provider_unittest.cc124
-rw-r--r--chrome/browser/cookies_tree_model.cc118
-rw-r--r--chrome/browser/cookies_tree_model.h110
-rw-r--r--chrome/browser/cookies_tree_model_unittest.cc30
-rw-r--r--chrome/browser/crash_handler_host_linux.cc23
-rw-r--r--chrome/browser/crash_handler_host_linux.h11
-rw-r--r--chrome/browser/crash_handler_host_linux_stub.cc12
-rw-r--r--chrome/browser/crash_recovery_browsertest.cc1
-rw-r--r--chrome/browser/cross_site_request_manager.cc7
-rw-r--r--chrome/browser/cross_site_request_manager.h8
-rw-r--r--chrome/browser/custom_home_pages_table_model.cc2
-rw-r--r--chrome/browser/debugger/debugger_remote_service.cc1
-rw-r--r--chrome/browser/debugger/devtools_client_host.cc16
-rw-r--r--chrome/browser/debugger/devtools_client_host.h9
-rw-r--r--chrome/browser/debugger/devtools_http_protocol_handler.cc58
-rw-r--r--chrome/browser/debugger/devtools_http_protocol_handler.h19
-rw-r--r--chrome/browser/debugger/devtools_manager.cc4
-rw-r--r--chrome/browser/debugger/devtools_netlog_observer.cc12
-rw-r--r--chrome/browser/debugger/devtools_netlog_observer.h8
-rw-r--r--chrome/browser/debugger/devtools_protocol_handler.cc1
-rw-r--r--chrome/browser/debugger/devtools_remote_listen_socket.cc4
-rw-r--r--chrome/browser/debugger/devtools_remote_listen_socket.h2
-rw-r--r--chrome/browser/debugger/devtools_remote_service.cc6
-rw-r--r--chrome/browser/debugger/devtools_sanity_unittest.cc9
-rw-r--r--chrome/browser/debugger/devtools_window.cc18
-rw-r--r--chrome/browser/debugger/devtools_window.h5
-rw-r--r--chrome/browser/debugger/extension_ports_remote_service.cc4
-rw-r--r--chrome/browser/debugger/inspectable_tab_proxy.cc2
-rw-r--r--chrome/browser/default_encoding_combo_model.cc2
-rw-r--r--chrome/browser/device_orientation/data_fetcher.h1
-rw-r--r--chrome/browser/device_orientation/dispatcher_host.cc112
-rw-r--r--chrome/browser/device_orientation/dispatcher_host.h46
-rw-r--r--chrome/browser/device_orientation/message_filter.cc106
-rw-r--r--chrome/browser/device_orientation/message_filter.h44
-rw-r--r--chrome/browser/device_orientation/provider_impl.cc16
-rw-r--r--chrome/browser/diagnostics/diagnostics_main.cc4
-rw-r--r--chrome/browser/diagnostics/diagnostics_test.cc53
-rw-r--r--chrome/browser/diagnostics/diagnostics_test.h43
-rw-r--r--chrome/browser/diagnostics/recon_diagnostics.cc1
-rw-r--r--chrome/browser/dock_info.cc268
-rw-r--r--chrome/browser/dock_info.h190
-rw-r--r--chrome/browser/dock_info_gtk.cc219
-rw-r--r--chrome/browser/dock_info_mac.cc15
-rw-r--r--chrome/browser/dock_info_unittest.cc191
-rw-r--r--chrome/browser/dock_info_win.cc326
-rw-r--r--chrome/browser/dom_ui/app_launcher_handler.cc101
-rw-r--r--chrome/browser/dom_ui/app_launcher_handler.h16
-rw-r--r--chrome/browser/dom_ui/bookmarks_ui.cc2
-rw-r--r--chrome/browser/dom_ui/bug_report_ui.cc14
-rw-r--r--chrome/browser/dom_ui/chrome_url_data_manager.cc61
-rw-r--r--chrome/browser/dom_ui/chrome_url_data_manager.h9
-rw-r--r--chrome/browser/dom_ui/conflicts_ui.cc15
-rw-r--r--chrome/browser/dom_ui/constrained_html_ui.cc8
-rw-r--r--chrome/browser/dom_ui/constrained_html_ui.h2
-rw-r--r--chrome/browser/dom_ui/constrained_html_ui_browsertest.cc1
-rw-r--r--chrome/browser/dom_ui/dom_ui.cc2
-rw-r--r--chrome/browser/dom_ui/dom_ui_factory.cc25
-rw-r--r--chrome/browser/dom_ui/dom_ui_favicon_source.cc3
-rw-r--r--chrome/browser/dom_ui/dom_ui_screenshot_source.cc6
-rw-r--r--chrome/browser/dom_ui/dom_ui_screenshot_source.h6
-rw-r--r--chrome/browser/dom_ui/dom_ui_theme_source.cc2
-rw-r--r--chrome/browser/dom_ui/dom_ui_theme_source_unittest.cc2
-rw-r--r--chrome/browser/dom_ui/dom_ui_thumbnail_source.cc3
-rw-r--r--chrome/browser/dom_ui/downloads_dom_handler.cc8
-rw-r--r--chrome/browser/dom_ui/downloads_ui.cc8
-rw-r--r--chrome/browser/dom_ui/filebrowse_ui.cc16
-rw-r--r--chrome/browser/dom_ui/fileicon_source.cc5
-rw-r--r--chrome/browser/dom_ui/fileicon_source.h5
-rw-r--r--chrome/browser/dom_ui/flags_ui.cc8
-rw-r--r--chrome/browser/dom_ui/foreign_session_handler.cc6
-rw-r--r--chrome/browser/dom_ui/foreign_session_handler.h5
-rw-r--r--chrome/browser/dom_ui/gpu_internals_ui.cc350
-rw-r--r--chrome/browser/dom_ui/gpu_internals_ui.h20
-rw-r--r--chrome/browser/dom_ui/history2_ui.cc24
-rw-r--r--chrome/browser/dom_ui/history2_ui.h4
-rw-r--r--chrome/browser/dom_ui/history_ui.cc24
-rw-r--r--chrome/browser/dom_ui/history_ui.h4
-rw-r--r--chrome/browser/dom_ui/html_dialog_tab_contents_delegate.cc4
-rw-r--r--chrome/browser/dom_ui/html_dialog_ui.cc7
-rw-r--r--chrome/browser/dom_ui/keyboard_ui.cc3
-rw-r--r--chrome/browser/dom_ui/mediaplayer_browsertest.cc5
-rw-r--r--chrome/browser/dom_ui/mediaplayer_ui.cc33
-rw-r--r--chrome/browser/dom_ui/mediaplayer_ui.h17
-rw-r--r--chrome/browser/dom_ui/most_visited_handler.cc6
-rw-r--r--chrome/browser/dom_ui/net_internals_ui.cc140
-rw-r--r--chrome/browser/dom_ui/new_tab_page_sync_handler.cc5
-rw-r--r--chrome/browser/dom_ui/new_tab_ui.cc12
-rw-r--r--chrome/browser/dom_ui/new_tab_ui.h6
-rw-r--r--chrome/browser/dom_ui/new_tab_ui_uitest.cc1
-rw-r--r--chrome/browser/dom_ui/ntp_login_handler.cc2
-rw-r--r--chrome/browser/dom_ui/ntp_resource_cache.cc4
-rw-r--r--chrome/browser/dom_ui/options/about_page_handler.cc6
-rw-r--r--chrome/browser/dom_ui/options/add_startup_page_handler.cc2
-rw-r--r--chrome/browser/dom_ui/options/advanced_options_handler.cc141
-rw-r--r--chrome/browser/dom_ui/options/advanced_options_handler.h18
-rw-r--r--chrome/browser/dom_ui/options/autofill_options_handler.cc202
-rw-r--r--chrome/browser/dom_ui/options/autofill_options_handler.h59
-rw-r--r--chrome/browser/dom_ui/options/browser_options_handler.cc32
-rw-r--r--chrome/browser/dom_ui/options/certificate_manager_handler.cc8
-rw-r--r--chrome/browser/dom_ui/options/clear_browser_data_handler.cc2
-rw-r--r--chrome/browser/dom_ui/options/content_settings_handler.cc184
-rw-r--r--chrome/browser/dom_ui/options/content_settings_handler.h10
-rw-r--r--chrome/browser/dom_ui/options/cookies_view_handler.cc16
-rw-r--r--chrome/browser/dom_ui/options/core_options_handler.cc5
-rw-r--r--chrome/browser/dom_ui/options/dom_options_util.cc18
-rw-r--r--chrome/browser/dom_ui/options/dom_options_util.h21
-rw-r--r--chrome/browser/dom_ui/options/font_settings_handler.cc6
-rw-r--r--chrome/browser/dom_ui/options/import_data_handler.cc106
-rw-r--r--chrome/browser/dom_ui/options/import_data_handler.h11
-rw-r--r--chrome/browser/dom_ui/options/options_managed_banner_handler.cc2
-rw-r--r--chrome/browser/dom_ui/options/options_managed_banner_handler.h2
-rw-r--r--chrome/browser/dom_ui/options/options_ui.cc18
-rw-r--r--chrome/browser/dom_ui/options/options_ui.h6
-rw-r--r--chrome/browser/dom_ui/options/password_manager_handler.cc190
-rw-r--r--chrome/browser/dom_ui/options/password_manager_handler.h119
-rw-r--r--chrome/browser/dom_ui/options/passwords_exceptions_handler.cc201
-rw-r--r--chrome/browser/dom_ui/options/passwords_exceptions_handler.h117
-rw-r--r--chrome/browser/dom_ui/options/personal_options_handler.cc80
-rw-r--r--chrome/browser/dom_ui/options/search_engine_manager_handler.cc5
-rw-r--r--chrome/browser/dom_ui/options/startup_page_manager_handler.cc28
-rw-r--r--chrome/browser/dom_ui/options/startup_page_manager_handler.h23
-rw-r--r--chrome/browser/dom_ui/options/stop_syncing_handler.cc4
-rw-r--r--chrome/browser/dom_ui/options/sync_options_handler.cc4
-rw-r--r--chrome/browser/dom_ui/options/sync_options_handler.h1
-rw-r--r--chrome/browser/dom_ui/plugins_ui.cc23
-rw-r--r--chrome/browser/dom_ui/print_preview_handler.cc8
-rw-r--r--chrome/browser/dom_ui/print_preview_handler.h3
-rw-r--r--chrome/browser/dom_ui/print_preview_ui.cc54
-rw-r--r--chrome/browser/dom_ui/print_preview_ui_uitest.cc27
-rw-r--r--chrome/browser/dom_ui/remoting_ui.cc6
-rw-r--r--chrome/browser/dom_ui/shared_resources_data_source.cc6
-rw-r--r--chrome/browser/dom_ui/shown_sections_handler.cc17
-rw-r--r--chrome/browser/dom_ui/shown_sections_handler.h4
-rw-r--r--chrome/browser/dom_ui/shown_sections_handler_unittest.cc3
-rw-r--r--chrome/browser/dom_ui/slideshow_ui.cc6
-rw-r--r--chrome/browser/dom_ui/textfields_ui.cc6
-rw-r--r--chrome/browser/dom_ui/tips_handler.cc2
-rw-r--r--chrome/browser/download/base_file.cc2
-rw-r--r--chrome/browser/download/download_browsertest.cc6
-rw-r--r--chrome/browser/download/download_exe.cc241
-rw-r--r--chrome/browser/download/download_extensions.cc258
-rw-r--r--chrome/browser/download/download_extensions.h39
-rw-r--r--chrome/browser/download/download_file_manager.cc6
-rw-r--r--chrome/browser/download/download_history.cc2
-rw-r--r--chrome/browser/download/download_item.cc81
-rw-r--r--chrome/browser/download/download_item.h10
-rw-r--r--chrome/browser/download/download_manager.cc285
-rw-r--r--chrome/browser/download/download_manager.h71
-rw-r--r--chrome/browser/download/download_manager_unittest.cc2
-rw-r--r--chrome/browser/download/download_prefs.cc6
-rw-r--r--chrome/browser/download/download_request_limiter.cc2
-rw-r--r--chrome/browser/download/download_request_limiter.h6
-rw-r--r--chrome/browser/download/download_shelf.cc6
-rw-r--r--chrome/browser/download/download_shelf.h4
-rw-r--r--chrome/browser/download/download_uitest.cc31
-rw-r--r--chrome/browser/download/download_util.cc38
-rw-r--r--chrome/browser/download/download_util.h11
-rw-r--r--chrome/browser/download/drag_download_file.cc2
-rw-r--r--chrome/browser/download/save_package.cc2
-rw-r--r--chrome/browser/download/save_package.h2
-rw-r--r--chrome/browser/encoding_menu_controller.cc141
-rw-r--r--chrome/browser/encoding_menu_controller.h56
-rw-r--r--chrome/browser/encoding_menu_controller_unittest.cc93
-rw-r--r--chrome/browser/enumerate_modules_model_win.cc7
-rw-r--r--chrome/browser/enumerate_modules_model_win.h4
-rw-r--r--chrome/browser/extensions/alert_apitest.cc4
-rw-r--r--chrome/browser/extensions/all_urls_apitest.cc8
-rw-r--r--chrome/browser/extensions/app_process_apitest.cc5
-rw-r--r--chrome/browser/extensions/autoupdate_interceptor.cc10
-rw-r--r--chrome/browser/extensions/autoupdate_interceptor.h2
-rw-r--r--chrome/browser/extensions/browser_action_apitest.cc8
-rw-r--r--chrome/browser/extensions/browser_action_test_util_mac.mm12
-rw-r--r--chrome/browser/extensions/content_script_extension_process_apitest.cc3
-rw-r--r--chrome/browser/extensions/convert_user_script.cc5
-rw-r--r--chrome/browser/extensions/convert_user_script_unittest.cc15
-rw-r--r--chrome/browser/extensions/convert_web_app.cc3
-rw-r--r--chrome/browser/extensions/convert_web_app_browsertest.cc24
-rw-r--r--chrome/browser/extensions/crashed_extension_infobar.cc9
-rw-r--r--chrome/browser/extensions/crashed_extension_infobar.h10
-rw-r--r--chrome/browser/extensions/crx_installer.cc19
-rw-r--r--chrome/browser/extensions/crx_installer.h8
-rw-r--r--chrome/browser/extensions/crx_installer_browsertest.cc6
-rw-r--r--chrome/browser/extensions/default_apps.cc151
-rw-r--r--chrome/browser/extensions/default_apps.h62
-rw-r--r--chrome/browser/extensions/default_apps_unittest.cc207
-rw-r--r--chrome/browser/extensions/execute_code_in_tab_function.cc6
-rw-r--r--chrome/browser/extensions/extension_accessibility_api.cc4
-rw-r--r--chrome/browser/extensions/extension_apitest.cc8
-rw-r--r--chrome/browser/extensions/extension_apitest.h1
-rw-r--r--chrome/browser/extensions/extension_bookmark_manager_api.cc2
-rw-r--r--chrome/browser/extensions/extension_bookmarks_module.cc4
-rw-r--r--chrome/browser/extensions/extension_bookmarks_module.h15
-rw-r--r--chrome/browser/extensions/extension_browser_event_router.cc5
-rw-r--r--chrome/browser/extensions/extension_browser_event_router.h6
-rw-r--r--chrome/browser/extensions/extension_browsertest.cc26
-rw-r--r--chrome/browser/extensions/extension_browsertests_misc.cc36
-rw-r--r--chrome/browser/extensions/extension_clipboard_api.cc2
-rw-r--r--chrome/browser/extensions/extension_context_menu_api.cc14
-rw-r--r--chrome/browser/extensions/extension_context_menu_browsertest.cc9
-rw-r--r--chrome/browser/extensions/extension_context_menu_model.cc13
-rw-r--r--chrome/browser/extensions/extension_cookies_api.cc6
-rw-r--r--chrome/browser/extensions/extension_cookies_api.h4
-rw-r--r--chrome/browser/extensions/extension_cookies_helpers.cc13
-rw-r--r--chrome/browser/extensions/extension_cookies_helpers.h4
-rw-r--r--chrome/browser/extensions/extension_cookies_unittest.cc4
-rw-r--r--chrome/browser/extensions/extension_crash_recovery_browsertest.cc211
-rw-r--r--chrome/browser/extensions/extension_data_deleter.cc14
-rw-r--r--chrome/browser/extensions/extension_data_deleter.h12
-rw-r--r--chrome/browser/extensions/extension_devtools_bridge.cc4
-rw-r--r--chrome/browser/extensions/extension_devtools_browsertests.cc5
-rw-r--r--chrome/browser/extensions/extension_disabled_infobar_delegate.cc35
-rw-r--r--chrome/browser/extensions/extension_disabled_infobar_delegate.h6
-rw-r--r--chrome/browser/extensions/extension_dom_ui.cc12
-rw-r--r--chrome/browser/extensions/extension_event_router.cc10
-rw-r--r--chrome/browser/extensions/extension_fileapi_apitest.cc9
-rw-r--r--chrome/browser/extensions/extension_function.cc6
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.cc28
-rw-r--r--chrome/browser/extensions/extension_history_api.cc2
-rw-r--r--chrome/browser/extensions/extension_host.cc50
-rw-r--r--chrome/browser/extensions/extension_host.h18
-rw-r--r--chrome/browser/extensions/extension_host_mac.mm6
-rw-r--r--chrome/browser/extensions/extension_i18n_api.cc2
-rw-r--r--chrome/browser/extensions/extension_idle_api.cc4
-rw-r--r--chrome/browser/extensions/extension_idle_api.h3
-rw-r--r--chrome/browser/extensions/extension_incognito_apitest.cc8
-rw-r--r--chrome/browser/extensions/extension_infobar_apitest.cc2
-rw-r--r--chrome/browser/extensions/extension_infobar_delegate.cc10
-rw-r--r--chrome/browser/extensions/extension_infobar_delegate.h2
-rw-r--r--chrome/browser/extensions/extension_infobar_module.cc2
-rw-r--r--chrome/browser/extensions/extension_input_api.cc1
-rw-r--r--chrome/browser/extensions/extension_install_ui.cc40
-rw-r--r--chrome/browser/extensions/extension_install_ui_browsertest.cc4
-rw-r--r--chrome/browser/extensions/extension_management_api.cc17
-rw-r--r--chrome/browser/extensions/extension_management_api.h4
-rw-r--r--chrome/browser/extensions/extension_management_apitest.cc6
-rw-r--r--chrome/browser/extensions/extension_management_browsertest.cc72
-rw-r--r--chrome/browser/extensions/extension_menu_manager.cc15
-rw-r--r--chrome/browser/extensions/extension_menu_manager_unittest.cc11
-rw-r--r--chrome/browser/extensions/extension_message_service.cc4
-rw-r--r--chrome/browser/extensions/extension_message_service.h6
-rw-r--r--chrome/browser/extensions/extension_messages_apitest.cc3
-rw-r--r--chrome/browser/extensions/extension_metrics_apitest.cc2
-rw-r--r--chrome/browser/extensions/extension_module.cc6
-rw-r--r--chrome/browser/extensions/extension_omnibox_api.cc17
-rw-r--r--chrome/browser/extensions/extension_omnibox_apitest.cc4
-rw-r--r--chrome/browser/extensions/extension_override_apitest.cc8
-rw-r--r--chrome/browser/extensions/extension_page_actions_module.cc6
-rw-r--r--chrome/browser/extensions/extension_popup_api.cc7
-rw-r--r--chrome/browser/extensions/extension_pref_store.cc197
-rw-r--r--chrome/browser/extensions/extension_pref_store.h118
-rw-r--r--chrome/browser/extensions/extension_pref_store_unittest.cc369
-rw-r--r--chrome/browser/extensions/extension_prefs.cc257
-rw-r--r--chrome/browser/extensions/extension_prefs.h87
-rw-r--r--chrome/browser/extensions/extension_prefs_unittest.cc367
-rw-r--r--chrome/browser/extensions/extension_process_manager.cc33
-rw-r--r--chrome/browser/extensions/extension_processes_api.cc5
-rw-r--r--chrome/browser/extensions/extension_protocols.cc40
-rw-r--r--chrome/browser/extensions/extension_proxy_api.cc54
-rw-r--r--chrome/browser/extensions/extension_proxy_api.h8
-rw-r--r--chrome/browser/extensions/extension_proxy_apitest.cc119
-rw-r--r--chrome/browser/extensions/extension_rlz_apitest.cc1
-rw-r--r--chrome/browser/extensions/extension_service.cc2074
-rw-r--r--chrome/browser/extensions/extension_service.h601
-rw-r--r--chrome/browser/extensions/extension_service_unittest.cc3264
-rw-r--r--chrome/browser/extensions/extension_service_unittest.h53
-rw-r--r--chrome/browser/extensions/extension_sidebar_api.cc6
-rw-r--r--chrome/browser/extensions/extension_startup_browsertest.cc9
-rw-r--r--chrome/browser/extensions/extension_tabs_apitest.cc2
-rw-r--r--chrome/browser/extensions/extension_tabs_module.cc66
-rw-r--r--chrome/browser/extensions/extension_tabs_module.h1
-rw-r--r--chrome/browser/extensions/extension_tabs_module_constants.cc2
-rw-r--r--chrome/browser/extensions/extension_tabs_module_constants.h1
-rw-r--r--chrome/browser/extensions/extension_test_api.cc17
-rw-r--r--chrome/browser/extensions/extension_test_api.h5
-rw-r--r--chrome/browser/extensions/extension_toolbar_model.cc23
-rw-r--r--chrome/browser/extensions/extension_toolbar_model.h8
-rw-r--r--chrome/browser/extensions/extension_toolbar_model_browsertest.cc8
-rw-r--r--chrome/browser/extensions/extension_tts_api.cc362
-rw-r--r--chrome/browser/extensions/extension_tts_api.h141
-rw-r--r--chrome/browser/extensions/extension_tts_api_chromeos.cc51
-rw-r--r--chrome/browser/extensions/extension_tts_api_util.cc15
-rw-r--r--chrome/browser/extensions/extension_tts_api_util.h20
-rw-r--r--chrome/browser/extensions/extension_tts_apitest.cc43
-rw-r--r--chrome/browser/extensions/extension_uitest.cc28
-rw-r--r--chrome/browser/extensions/extension_updater.cc52
-rw-r--r--chrome/browser/extensions/extension_updater.h12
-rw-r--r--chrome/browser/extensions/extension_updater_unittest.cc34
-rw-r--r--chrome/browser/extensions/extension_webglbackground_apitest.cc9
-rw-r--r--chrome/browser/extensions/extension_webnavigation_api.cc51
-rw-r--r--chrome/browser/extensions/extension_webnavigation_api.h31
-rw-r--r--chrome/browser/extensions/extension_webnavigation_apitest.cc1
-rw-r--r--chrome/browser/extensions/extension_webnavigation_unittest.cc37
-rw-r--r--chrome/browser/extensions/extension_webstore_private_api.cc13
-rw-r--r--chrome/browser/extensions/extension_webstore_private_browsertest.cc2
-rw-r--r--chrome/browser/extensions/extensions_service.cc2067
-rw-r--r--chrome/browser/extensions/extensions_service.h607
-rw-r--r--chrome/browser/extensions/extensions_service_unittest.cc3178
-rw-r--r--chrome/browser/extensions/extensions_service_unittest.h53
-rw-r--r--chrome/browser/extensions/extensions_startup.cc109
-rw-r--r--chrome/browser/extensions/extensions_startup.h39
-rw-r--r--chrome/browser/extensions/extensions_ui.cc28
-rw-r--r--chrome/browser/extensions/extensions_ui.h16
-rw-r--r--chrome/browser/extensions/external_extension_provider.h6
-rw-r--r--chrome/browser/extensions/external_policy_extension_provider.cc21
-rw-r--r--chrome/browser/extensions/external_policy_extension_provider.h10
-rw-r--r--chrome/browser/extensions/external_policy_extension_provider_unittest.cc21
-rw-r--r--chrome/browser/extensions/external_pref_extension_provider.cc7
-rw-r--r--chrome/browser/extensions/external_pref_extension_provider.h2
-rw-r--r--chrome/browser/extensions/external_registry_extension_provider_win.cc15
-rw-r--r--chrome/browser/extensions/external_registry_extension_provider_win.h6
-rw-r--r--chrome/browser/extensions/fragment_navigation_apitest.cc4
-rw-r--r--chrome/browser/extensions/gtk_theme_installed_infobar_delegate.cc2
-rw-r--r--chrome/browser/extensions/image_loading_tracker.cc8
-rw-r--r--chrome/browser/extensions/image_loading_tracker_unittest.cc4
-rw-r--r--chrome/browser/extensions/notifications_apitest.cc10
-rw-r--r--chrome/browser/extensions/pack_extension_job.cc40
-rw-r--r--chrome/browser/extensions/pack_extension_job.h9
-rw-r--r--chrome/browser/extensions/page_action_apitest.cc6
-rw-r--r--chrome/browser/extensions/sandboxed_extension_unpacker.cc173
-rw-r--r--chrome/browser/extensions/sandboxed_extension_unpacker.h6
-rw-r--r--chrome/browser/extensions/stateful_external_extension_provider.cc18
-rw-r--r--chrome/browser/extensions/stateful_external_extension_provider.h14
-rw-r--r--chrome/browser/extensions/test_extension_prefs.cc43
-rw-r--r--chrome/browser/extensions/test_extension_prefs.h1
-rw-r--r--chrome/browser/extensions/theme_installed_infobar_delegate.cc6
-rw-r--r--chrome/browser/extensions/user_script_listener.cc12
-rw-r--r--chrome/browser/extensions/user_script_listener_unittest.cc31
-rw-r--r--chrome/browser/extensions/user_script_master.cc16
-rw-r--r--chrome/browser/extensions/window_open_apitest.cc4
-rw-r--r--chrome/browser/external_tab_container_win.cc64
-rw-r--r--chrome/browser/external_tab_container_win.h9
-rw-r--r--chrome/browser/fav_icon_helper.cc14
-rw-r--r--chrome/browser/fav_icon_helper.h3
-rw-r--r--chrome/browser/favicon_service.cc3
-rw-r--r--chrome/browser/file_path_watcher.cc19
-rw-r--r--chrome/browser/file_path_watcher.h64
-rw-r--r--chrome/browser/file_path_watcher/file_path_watcher.cc19
-rw-r--r--chrome/browser/file_path_watcher/file_path_watcher.h64
-rw-r--r--chrome/browser/file_path_watcher/file_path_watcher_browsertest.cc455
-rw-r--r--chrome/browser/file_path_watcher/file_path_watcher_inotify.cc412
-rw-r--r--chrome/browser/file_path_watcher/file_path_watcher_mac.cc233
-rw-r--r--chrome/browser/file_path_watcher/file_path_watcher_stub.cc19
-rw-r--r--chrome/browser/file_path_watcher/file_path_watcher_win.cc244
-rw-r--r--chrome/browser/file_path_watcher_browsertest.cc455
-rw-r--r--chrome/browser/file_path_watcher_inotify.cc410
-rw-r--r--chrome/browser/file_path_watcher_mac.cc232
-rw-r--r--chrome/browser/file_path_watcher_stub.cc19
-rw-r--r--chrome/browser/file_path_watcher_win.cc244
-rw-r--r--chrome/browser/file_select_helper.cc6
-rw-r--r--chrome/browser/file_system/browser_file_system_callback_dispatcher.cc60
-rw-r--r--chrome/browser/file_system/browser_file_system_callback_dispatcher.h35
-rw-r--r--chrome/browser/file_system/browser_file_system_context.cc34
-rw-r--r--chrome/browser/file_system/browser_file_system_context.h35
-rw-r--r--chrome/browser/file_system/browser_file_system_helper.cc23
-rw-r--r--chrome/browser/file_system/browser_file_system_helper.h17
-rw-r--r--chrome/browser/file_system/file_system_dispatcher_host.cc109
-rw-r--r--chrome/browser/file_system/file_system_dispatcher_host.h41
-rw-r--r--chrome/browser/find_backend_unittest.cc76
-rw-r--r--chrome/browser/find_bar.h95
-rw-r--r--chrome/browser/find_bar_controller.cc225
-rw-r--r--chrome/browser/find_bar_controller.h89
-rw-r--r--chrome/browser/find_bar_host_browsertest.cc1070
-rw-r--r--chrome/browser/find_bar_state.cc20
-rw-r--r--chrome/browser/find_bar_state.h41
-rw-r--r--chrome/browser/find_notification_details.h51
-rw-r--r--chrome/browser/first_run/first_run.cc56
-rw-r--r--chrome/browser/first_run/first_run.h12
-rw-r--r--chrome/browser/first_run/first_run_mac.mm6
-rw-r--r--chrome/browser/first_run/first_run_win.cc54
-rw-r--r--chrome/browser/geolocation/geolocation_browsertest.cc11
-rw-r--r--chrome/browser/geolocation/geolocation_content_settings_map.cc73
-rw-r--r--chrome/browser/geolocation/geolocation_content_settings_map.h26
-rw-r--r--chrome/browser/geolocation/geolocation_content_settings_map_unittest.cc68
-rw-r--r--chrome/browser/geolocation/geolocation_dispatcher_host.cc245
-rw-r--r--chrome/browser/geolocation/geolocation_dispatcher_host.h31
-rw-r--r--chrome/browser/geolocation/geolocation_dispatcher_host_old.cc239
-rw-r--r--chrome/browser/geolocation/geolocation_dispatcher_host_old.h39
-rw-r--r--chrome/browser/geolocation/geolocation_permission_context.cc16
-rw-r--r--chrome/browser/geolocation/geolocation_permission_context.h2
-rw-r--r--chrome/browser/geolocation/geolocation_permission_context_unittest.cc9
-rw-r--r--chrome/browser/geolocation/geolocation_provider.cc5
-rw-r--r--chrome/browser/geolocation/geolocation_settings_state.cc2
-rw-r--r--chrome/browser/geolocation/location_arbitrator.cc2
-rw-r--r--chrome/browser/geolocation/mock_location_provider.cc4
-rw-r--r--chrome/browser/geolocation/win7_location_api_unittest_win.cc22
-rw-r--r--chrome/browser/geolocation/win7_location_provider_unittest_win.cc6
-rw-r--r--chrome/browser/google/google_update.cc21
-rw-r--r--chrome/browser/google/google_url_tracker.cc2
-rw-r--r--chrome/browser/google/google_url_tracker_unittest.cc5
-rw-r--r--chrome/browser/gpu.sb18
-rw-r--r--chrome/browser/gpu_blacklist.cc7
-rw-r--r--chrome/browser/gpu_blacklist.h3
-rw-r--r--chrome/browser/gpu_process_host.cc83
-rw-r--r--chrome/browser/gpu_process_host.h34
-rw-r--r--chrome/browser/gpu_process_host_ui_shim.cc22
-rw-r--r--chrome/browser/gpu_process_host_ui_shim.h19
-rw-r--r--chrome/browser/gtk/about_chrome_dialog.cc2
-rw-r--r--chrome/browser/gtk/accelerators_gtk.cc6
-rw-r--r--chrome/browser/gtk/accelerators_gtk.h13
-rw-r--r--chrome/browser/gtk/accessibility_event_router_gtk.cc4
-rw-r--r--chrome/browser/gtk/accessible_widget_helper_gtk.cc2
-rw-r--r--chrome/browser/gtk/back_forward_button_gtk.cc4
-rw-r--r--chrome/browser/gtk/bookmark_bar_gtk.cc9
-rw-r--r--chrome/browser/gtk/bookmark_bubble_gtk.cc2
-rw-r--r--chrome/browser/gtk/bookmark_editor_gtk.cc2
-rw-r--r--chrome/browser/gtk/bookmark_editor_gtk_unittest.cc2
-rw-r--r--chrome/browser/gtk/bookmark_menu_controller_gtk.cc9
-rw-r--r--chrome/browser/gtk/bookmark_utils_gtk.cc21
-rw-r--r--chrome/browser/gtk/bookmark_utils_gtk.h7
-rw-r--r--chrome/browser/gtk/browser_actions_toolbar_gtk.cc22
-rw-r--r--chrome/browser/gtk/browser_actions_toolbar_gtk.h14
-rw-r--r--chrome/browser/gtk/browser_titlebar.cc12
-rw-r--r--chrome/browser/gtk/browser_toolbar_gtk.cc40
-rw-r--r--chrome/browser/gtk/browser_toolbar_gtk.h8
-rw-r--r--chrome/browser/gtk/browser_window_gtk.cc71
-rw-r--r--chrome/browser/gtk/browser_window_gtk.h5
-rw-r--r--chrome/browser/gtk/certificate_viewer.cc8
-rw-r--r--chrome/browser/gtk/clear_browsing_data_dialog_gtk.cc2
-rw-r--r--chrome/browser/gtk/collected_cookies_gtk.cc6
-rw-r--r--chrome/browser/gtk/collected_cookies_gtk.h6
-rw-r--r--chrome/browser/gtk/constrained_html_delegate_gtk.cc1
-rw-r--r--chrome/browser/gtk/content_setting_bubble_gtk.cc97
-rw-r--r--chrome/browser/gtk/content_setting_bubble_gtk.h8
-rw-r--r--chrome/browser/gtk/create_application_shortcuts_dialog_gtk.cc23
-rw-r--r--chrome/browser/gtk/dialogs_gtk.cc1
-rw-r--r--chrome/browser/gtk/download_in_progress_dialog_gtk.cc2
-rw-r--r--chrome/browser/gtk/download_shelf_gtk.cc7
-rw-r--r--chrome/browser/gtk/download_shelf_gtk.h2
-rw-r--r--chrome/browser/gtk/download_started_animation_gtk.cc2
-rw-r--r--chrome/browser/gtk/edit_search_engine_dialog.cc2
-rw-r--r--chrome/browser/gtk/extension_installed_bubble_gtk.cc17
-rw-r--r--chrome/browser/gtk/extension_popup_gtk.cc7
-rw-r--r--chrome/browser/gtk/external_protocol_dialog_gtk.cc7
-rw-r--r--chrome/browser/gtk/find_bar_gtk.cc22
-rw-r--r--chrome/browser/gtk/find_bar_gtk.h4
-rw-r--r--chrome/browser/gtk/first_run_bubble.cc4
-rw-r--r--chrome/browser/gtk/first_run_bubble.h5
-rw-r--r--chrome/browser/gtk/first_run_dialog.cc12
-rw-r--r--chrome/browser/gtk/gconf_titlebar_listener.cc6
-rw-r--r--chrome/browser/gtk/gconf_titlebar_listener.h6
-rw-r--r--chrome/browser/gtk/gtk_chrome_cookie_view.cc14
-rw-r--r--chrome/browser/gtk/gtk_theme_provider.cc2
-rw-r--r--chrome/browser/gtk/gtk_theme_provider_unittest.cc2
-rw-r--r--chrome/browser/gtk/gtk_util.cc17
-rw-r--r--chrome/browser/gtk/html_dialog_gtk.cc4
-rw-r--r--chrome/browser/gtk/html_dialog_gtk.h2
-rw-r--r--chrome/browser/gtk/import_dialog_gtk.cc59
-rw-r--r--chrome/browser/gtk/import_dialog_gtk.h15
-rw-r--r--chrome/browser/gtk/infobar_container_gtk.cc5
-rw-r--r--chrome/browser/gtk/instant_confirm_dialog_gtk.cc4
-rw-r--r--chrome/browser/gtk/js_modal_dialog_gtk.cc29
-rw-r--r--chrome/browser/gtk/js_modal_dialog_gtk.h13
-rw-r--r--chrome/browser/gtk/keyword_editor_view.cc2
-rw-r--r--chrome/browser/gtk/location_bar_view_gtk.cc25
-rw-r--r--chrome/browser/gtk/location_bar_view_gtk.h4
-rw-r--r--chrome/browser/gtk/menu_gtk.cc27
-rw-r--r--chrome/browser/gtk/notifications/balloon_view_gtk.cc6
-rw-r--r--chrome/browser/gtk/notifications/balloon_view_gtk.h2
-rw-r--r--chrome/browser/gtk/options/advanced_contents_gtk.cc60
-rw-r--r--chrome/browser/gtk/options/advanced_page_gtk.cc4
-rw-r--r--chrome/browser/gtk/options/advanced_page_gtk.h2
-rw-r--r--chrome/browser/gtk/options/content_exception_editor.cc12
-rw-r--r--chrome/browser/gtk/options/content_exception_editor.h8
-rw-r--r--chrome/browser/gtk/options/content_exceptions_window_gtk.cc4
-rw-r--r--chrome/browser/gtk/options/content_exceptions_window_gtk.h2
-rw-r--r--chrome/browser/gtk/options/content_exceptions_window_gtk_unittest.cc2
-rw-r--r--chrome/browser/gtk/options/content_filter_page_gtk.cc35
-rw-r--r--chrome/browser/gtk/options/content_filter_page_gtk.h8
-rw-r--r--chrome/browser/gtk/options/content_page_gtk.cc1
-rw-r--r--chrome/browser/gtk/options/content_page_gtk.h7
-rw-r--r--chrome/browser/gtk/options/content_settings_window_gtk.cc4
-rw-r--r--chrome/browser/gtk/options/cookie_filter_page_gtk.cc6
-rw-r--r--chrome/browser/gtk/options/cookie_filter_page_gtk.h4
-rw-r--r--chrome/browser/gtk/options/cookies_view.cc2
-rw-r--r--chrome/browser/gtk/options/cookies_view_unittest.cc2
-rw-r--r--chrome/browser/gtk/options/fonts_languages_window_gtk.cc2
-rw-r--r--chrome/browser/gtk/options/fonts_page_gtk.cc5
-rw-r--r--chrome/browser/gtk/options/fonts_page_gtk.h2
-rw-r--r--chrome/browser/gtk/options/general_page_gtk.cc5
-rw-r--r--chrome/browser/gtk/options/general_page_gtk.h2
-rw-r--r--chrome/browser/gtk/options/languages_page_gtk.cc2
-rw-r--r--chrome/browser/gtk/options/languages_page_gtk.h2
-rw-r--r--chrome/browser/gtk/options/languages_page_gtk_unittest.cc1
-rw-r--r--chrome/browser/gtk/options/options_window_gtk.cc12
-rw-r--r--chrome/browser/gtk/options/passwords_exceptions_page_gtk.cc1
-rw-r--r--chrome/browser/gtk/options/passwords_exceptions_page_gtk.h3
-rw-r--r--chrome/browser/gtk/options/passwords_exceptions_window_gtk.cc5
-rw-r--r--chrome/browser/gtk/options/passwords_page_gtk.cc1
-rw-r--r--chrome/browser/gtk/options/passwords_page_gtk.h10
-rw-r--r--chrome/browser/gtk/options/url_picker_dialog_gtk.cc2
-rw-r--r--chrome/browser/gtk/overflow_button.cc2
-rw-r--r--chrome/browser/gtk/overflow_button.h6
-rw-r--r--chrome/browser/gtk/reload_button_gtk.cc4
-rw-r--r--chrome/browser/gtk/slide_animator_gtk.h4
-rw-r--r--chrome/browser/gtk/ssl_client_certificate_selector.cc8
-rw-r--r--chrome/browser/gtk/status_bubble_gtk.h8
-rw-r--r--chrome/browser/gtk/tab_contents_container_gtk.cc5
-rw-r--r--chrome/browser/gtk/tabs/dragged_tab_controller_gtk.cc7
-rw-r--r--chrome/browser/gtk/tabs/dragged_tab_controller_gtk.h2
-rw-r--r--chrome/browser/gtk/tabs/dragged_tab_gtk.cc2
-rw-r--r--chrome/browser/gtk/tabs/tab_gtk.cc5
-rw-r--r--chrome/browser/gtk/tabs/tab_gtk.h7
-rw-r--r--chrome/browser/gtk/tabs/tab_renderer_gtk.cc2
-rw-r--r--chrome/browser/gtk/tabs/tab_strip_gtk.cc37
-rw-r--r--chrome/browser/gtk/tabs/tab_strip_gtk.h5
-rw-r--r--chrome/browser/gtk/task_manager_gtk.cc39
-rw-r--r--chrome/browser/gtk/task_manager_gtk.h10
-rw-r--r--chrome/browser/gtk/theme_install_bubble_view_gtk.cc12
-rw-r--r--chrome/browser/gtk/theme_install_bubble_view_gtk.h20
-rw-r--r--chrome/browser/gtk/translate/after_translate_infobar_gtk.cc4
-rw-r--r--chrome/browser/gtk/translate/after_translate_infobar_gtk.h2
-rw-r--r--chrome/browser/gtk/translate/before_translate_infobar_gtk.cc4
-rw-r--r--chrome/browser/gtk/translate/before_translate_infobar_gtk.h2
-rw-r--r--chrome/browser/gtk/translate/translate_infobar_base_gtk.cc4
-rw-r--r--chrome/browser/gtk/translate/translate_infobar_base_gtk.h2
-rw-r--r--chrome/browser/gtk/view_id_util.h2
-rw-r--r--chrome/browser/guid.cc32
-rw-r--r--chrome/browser/guid.h32
-rw-r--r--chrome/browser/guid_posix.cc28
-rw-r--r--chrome/browser/guid_unittest.cc42
-rw-r--r--chrome/browser/guid_win.cc38
-rw-r--r--chrome/browser/hang_monitor/hung_plugin_action.cc6
-rw-r--r--chrome/browser/history/download_create_info.cc7
-rw-r--r--chrome/browser/history/download_create_info.h6
-rw-r--r--chrome/browser/history/expire_history_backend_unittest.cc5
-rw-r--r--chrome/browser/history/history.cc12
-rw-r--r--chrome/browser/history/history.h5
-rw-r--r--chrome/browser/history/history_backend.cc17
-rw-r--r--chrome/browser/history/history_backend.h5
-rw-r--r--chrome/browser/history/history_backend_unittest.cc6
-rw-r--r--chrome/browser/history/history_browsertest.cc6
-rw-r--r--chrome/browser/history/history_publisher_win.cc10
-rw-r--r--chrome/browser/history/history_types.cc19
-rw-r--r--chrome/browser/history/history_types.h7
-rw-r--r--chrome/browser/history/history_unittest.cc8
-rw-r--r--chrome/browser/history/in_memory_history_backend.cc8
-rw-r--r--chrome/browser/history/in_memory_url_index.cc7
-rw-r--r--chrome/browser/history/multipart_uitest.cc9
-rw-r--r--chrome/browser/history/query_parser.cc10
-rw-r--r--chrome/browser/history/redirect_uitest.cc2
-rw-r--r--chrome/browser/history/top_sites.cc2
-rw-r--r--chrome/browser/history/top_sites.h3
-rw-r--r--chrome/browser/host_content_settings_map.cc1169
-rw-r--r--chrome/browser/host_content_settings_map.h354
-rw-r--r--chrome/browser/host_content_settings_map_unittest.cc987
-rw-r--r--chrome/browser/host_zoom_map.cc2
-rw-r--r--chrome/browser/host_zoom_map_unittest.cc3
-rw-r--r--chrome/browser/idbbindingutilities_browsertest.cc4
-rw-r--r--chrome/browser/importer/firefox_importer_unittest_messages_internal.h9
-rw-r--r--chrome/browser/importer/firefox_importer_unittest_utils_mac.cc22
-rw-r--r--chrome/browser/importer/importer.cc38
-rw-r--r--chrome/browser/importer/importer.h82
-rw-r--r--chrome/browser/importer/importer_bridge.h3
-rw-r--r--chrome/browser/importer/importer_list.cc253
-rw-r--r--chrome/browser/importer/importer_list.h70
-rw-r--r--chrome/browser/importer/importer_messages.cc7
-rw-r--r--chrome/browser/importer/importer_messages.h4
-rw-r--r--chrome/browser/importer/importer_messages_internal.h95
-rw-r--r--chrome/browser/importer/importer_unittest.cc3
-rw-r--r--chrome/browser/importer/profile_writer.cc2
-rw-r--r--chrome/browser/importer/toolbar_importer.cc2
-rw-r--r--chrome/browser/in_process_webkit/browser_webkitclient_impl.cc10
-rw-r--r--chrome/browser/in_process_webkit/dom_storage_area.cc11
-rw-r--r--chrome/browser/in_process_webkit/dom_storage_area.h11
-rw-r--r--chrome/browser/in_process_webkit/dom_storage_browsertest.cc53
-rw-r--r--chrome/browser/in_process_webkit/dom_storage_context.cc96
-rw-r--r--chrome/browser/in_process_webkit/dom_storage_context.h48
-rw-r--r--chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc341
-rw-r--r--chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h117
-rw-r--r--chrome/browser/in_process_webkit/dom_storage_dispatcher_host_unittest.cc9
-rw-r--r--chrome/browser/in_process_webkit/dom_storage_message_filter.cc232
-rw-r--r--chrome/browser/in_process_webkit/dom_storage_message_filter.h98
-rw-r--r--chrome/browser/in_process_webkit/dom_storage_message_filter_unittest.cc8
-rw-r--r--chrome/browser/in_process_webkit/dom_storage_namespace.cc2
-rw-r--r--chrome/browser/in_process_webkit/indexed_db_browsertest.cc34
-rw-r--r--chrome/browser/in_process_webkit/indexed_db_callbacks.cc8
-rw-r--r--chrome/browser/in_process_webkit/indexed_db_callbacks.h23
-rw-r--r--chrome/browser/in_process_webkit/indexed_db_context.cc55
-rw-r--r--chrome/browser/in_process_webkit/indexed_db_context.h19
-rw-r--r--chrome/browser/in_process_webkit/indexed_db_dispatcher_host.cc778
-rw-r--r--chrome/browser/in_process_webkit/indexed_db_dispatcher_host.h158
-rw-r--r--chrome/browser/in_process_webkit/indexed_db_key_utility_client.cc5
-rw-r--r--chrome/browser/in_process_webkit/indexed_db_key_utility_client.h2
-rw-r--r--chrome/browser/in_process_webkit/session_storage_namespace.cc2
-rw-r--r--chrome/browser/in_process_webkit/webkit_context.cc9
-rw-r--r--chrome/browser/in_process_webkit/webkit_context.h14
-rw-r--r--chrome/browser/in_process_webkit/webkit_context_unittest.cc6
-rw-r--r--chrome/browser/input_window_dialog.h53
-rw-r--r--chrome/browser/input_window_dialog_gtk.cc146
-rw-r--r--chrome/browser/input_window_dialog_win.cc235
-rw-r--r--chrome/browser/instant/instant_browsertest.cc201
-rw-r--r--chrome/browser/instant/instant_confirm_dialog.cc2
-rw-r--r--chrome/browser/instant/instant_controller.cc22
-rw-r--r--chrome/browser/instant/instant_controller.h5
-rw-r--r--chrome/browser/instant/instant_loader.cc9
-rw-r--r--chrome/browser/instant/instant_loader_manager.cc2
-rw-r--r--chrome/browser/instant/instant_unload_handler.cc2
-rw-r--r--chrome/browser/instant/promo_counter.cc2
-rw-r--r--chrome/browser/intranet_redirect_detector.cc2
-rw-r--r--chrome/browser/io_thread.cc136
-rw-r--r--chrome/browser/io_thread.h49
-rw-r--r--chrome/browser/js_modal_dialog.cc138
-rw-r--r--chrome/browser/js_modal_dialog.h117
-rw-r--r--chrome/browser/jumplist_win.cc15
-rw-r--r--chrome/browser/language_combobox_model.cc2
-rw-r--r--chrome/browser/location_bar.h106
-rw-r--r--chrome/browser/location_bar_util.cc42
-rw-r--r--chrome/browser/location_bar_util.h24
-rw-r--r--chrome/browser/login_model.h35
-rw-r--r--chrome/browser/login_prompt.cc452
-rw-r--r--chrome/browser/login_prompt.h213
-rw-r--r--chrome/browser/login_prompt_gtk.cc199
-rw-r--r--chrome/browser/login_prompt_mac.h34
-rw-r--r--chrome/browser/login_prompt_mac.mm191
-rw-r--r--chrome/browser/login_prompt_unittest.cc42
-rw-r--r--chrome/browser/login_prompt_win.cc147
-rw-r--r--chrome/browser/mach_broker_mac.cc2
-rw-r--r--chrome/browser/mach_broker_mac.h2
-rw-r--r--chrome/browser/media_uitest.cc10
-rw-r--r--chrome/browser/memory_details.cc12
-rw-r--r--chrome/browser/memory_details.h11
-rw-r--r--chrome/browser/memory_details_linux.cc11
-rw-r--r--chrome/browser/memory_details_mac.cc36
-rw-r--r--chrome/browser/memory_details_win.cc4
-rw-r--r--chrome/browser/memory_purger.cc2
-rw-r--r--chrome/browser/message_box_handler.cc89
-rw-r--r--chrome/browser/message_box_handler.h41
-rw-r--r--chrome/browser/metrics/metrics_log.cc18
-rw-r--r--chrome/browser/metrics/metrics_log.h15
-rw-r--r--chrome/browser/metrics/metrics_service.cc31
-rw-r--r--chrome/browser/metrics/metrics_service.h9
-rw-r--r--chrome/browser/metrics/metrics_service_uitest.cc10
-rw-r--r--chrome/browser/metrics/user_metrics.cc18
-rw-r--r--chrome/browser/metrics/user_metrics.h1
-rw-r--r--chrome/browser/mime_registry_dispatcher.cc96
-rw-r--r--chrome/browser/mime_registry_dispatcher.h37
-rw-r--r--chrome/browser/mime_registry_message_filter.cc51
-rw-r--r--chrome/browser/mime_registry_message_filter.h31
-rw-r--r--chrome/browser/mock_plugin_exceptions_table_model.cc6
-rw-r--r--chrome/browser/mock_plugin_exceptions_table_model.h7
-rw-r--r--chrome/browser/modal_html_dialog_delegate.cc14
-rw-r--r--chrome/browser/modal_html_dialog_delegate.h4
-rw-r--r--chrome/browser/nacl_host/nacl_broker_host_win.cc12
-rw-r--r--chrome/browser/nacl_host/nacl_broker_host_win.h9
-rw-r--r--chrome/browser/nacl_host/nacl_broker_service_win.cc1
-rw-r--r--chrome/browser/nacl_host/nacl_process_host.cc32
-rw-r--r--chrome/browser/nacl_host/nacl_process_host.h19
-rw-r--r--chrome/browser/native_app_modal_dialog.h39
-rw-r--r--chrome/browser/net/blob_url_request_job_factory.cc6
-rw-r--r--chrome/browser/net/chrome_cookie_policy.cc2
-rw-r--r--chrome/browser/net/chrome_dns_cert_provenance_checker.cc14
-rw-r--r--chrome/browser/net/chrome_net_log.cc114
-rw-r--r--chrome/browser/net/chrome_net_log.h109
-rw-r--r--chrome/browser/net/chrome_net_log_unittest.cc73
-rw-r--r--chrome/browser/net/chrome_url_request_context.cc100
-rw-r--r--chrome/browser/net/chrome_url_request_context.h44
-rw-r--r--chrome/browser/net/connect_interceptor.cc4
-rw-r--r--chrome/browser/net/connect_interceptor.h4
-rw-r--r--chrome/browser/net/connection_tester.cc56
-rw-r--r--chrome/browser/net/connection_tester.h8
-rw-r--r--chrome/browser/net/connection_tester_unittest.cc75
-rw-r--r--chrome/browser/net/cookie_policy_browsertest.cc4
-rw-r--r--chrome/browser/net/gaia/token_service.cc2
-rw-r--r--chrome/browser/net/gaia/token_service_unittest.h2
-rw-r--r--chrome/browser/net/load_timing_observer.cc25
-rw-r--r--chrome/browser/net/load_timing_observer.h7
-rw-r--r--chrome/browser/net/load_timing_observer_unittest.cc40
-rw-r--r--chrome/browser/net/metadata_url_request.cc19
-rw-r--r--chrome/browser/net/net_log_logger.cc4
-rw-r--r--chrome/browser/net/net_log_logger.h4
-rw-r--r--chrome/browser/net/net_pref_observer.cc1
-rw-r--r--chrome/browser/net/passive_log_collector.cc89
-rw-r--r--chrome/browser/net/passive_log_collector.h81
-rw-r--r--chrome/browser/net/passive_log_collector_unittest.cc18
-rw-r--r--chrome/browser/net/preconnect.cc2
-rw-r--r--chrome/browser/net/predictor_api.cc45
-rw-r--r--chrome/browser/net/predictor_api.h1
-rw-r--r--chrome/browser/net/pref_proxy_config_service.cc164
-rw-r--r--chrome/browser/net/pref_proxy_config_service.h14
-rw-r--r--chrome/browser/net/pref_proxy_config_service_unittest.cc53
-rw-r--r--chrome/browser/net/prerender_interceptor.cc79
-rw-r--r--chrome/browser/net/prerender_interceptor.h53
-rw-r--r--chrome/browser/net/prerender_interceptor_unittest.cc107
-rw-r--r--chrome/browser/net/resolve_proxy_msg_helper.cc2
-rw-r--r--chrome/browser/net/sdch_dictionary_fetcher.cc2
-rw-r--r--chrome/browser/net/sqlite_persistent_cookie_store.cc261
-rw-r--r--chrome/browser/net/sqlite_persistent_cookie_store.h29
-rw-r--r--chrome/browser/net/sqlite_persistent_cookie_store_unittest.cc178
-rw-r--r--chrome/browser/net/ssl_config_service_manager_pref.cc13
-rw-r--r--chrome/browser/net/url_fixer_upper.cc26
-rw-r--r--chrome/browser/net/url_fixer_upper.h9
-rw-r--r--chrome/browser/net/url_request_failed_dns_job.cc15
-rw-r--r--chrome/browser/net/url_request_failed_dns_job.h8
-rw-r--r--chrome/browser/net/url_request_mock_http_job.cc16
-rw-r--r--chrome/browser/net/url_request_mock_http_job.h12
-rw-r--r--chrome/browser/net/url_request_mock_link_doctor_job.cc8
-rw-r--r--chrome/browser/net/url_request_mock_link_doctor_job.h8
-rw-r--r--chrome/browser/net/url_request_mock_net_error_job.cc13
-rw-r--r--chrome/browser/net/url_request_mock_net_error_job.h6
-rw-r--r--chrome/browser/net/url_request_mock_util.cc4
-rw-r--r--chrome/browser/net/url_request_slow_download_job.cc24
-rw-r--r--chrome/browser/net/url_request_slow_download_job.h11
-rw-r--r--chrome/browser/net/url_request_slow_http_job.cc6
-rw-r--r--chrome/browser/net/url_request_slow_http_job.h4
-rw-r--r--chrome/browser/net/url_request_tracking.cc6
-rw-r--r--chrome/browser/net/view_blob_internals_job_factory.cc5
-rw-r--r--chrome/browser/net/view_http_cache_job_factory.cc15
-rw-r--r--chrome/browser/net/websocket_experiment/websocket_experiment_task.cc2
-rw-r--r--chrome/browser/notifications/balloon_collection.cc2
-rw-r--r--chrome/browser/notifications/balloon_collection_mac.mm2
-rw-r--r--chrome/browser/notifications/balloon_host.cc16
-rw-r--r--chrome/browser/notifications/balloon_host.h8
-rw-r--r--chrome/browser/notifications/desktop_notification_service.cc14
-rw-r--r--chrome/browser/notifications/desktop_notification_service.h1
-rw-r--r--chrome/browser/notifications/desktop_notification_service_unittest.cc2
-rw-r--r--chrome/browser/notifications/notification_object_proxy.cc1
-rw-r--r--chrome/browser/notifications/notification_options_menu_model.cc19
-rw-r--r--chrome/browser/notifications/notification_options_menu_model.h2
-rw-r--r--chrome/browser/omnibox_search_hint.cc7
-rw-r--r--chrome/browser/oom_priority_manager.cc4
-rw-r--r--chrome/browser/options_page_base.cc36
-rw-r--r--chrome/browser/options_page_base.h62
-rw-r--r--chrome/browser/options_util.cc133
-rw-r--r--chrome/browser/options_util.h26
-rw-r--r--chrome/browser/options_window.h40
-rw-r--r--chrome/browser/page_info_model.cc6
-rw-r--r--chrome/browser/parsers/metadata_parser_filebase.h2
-rw-r--r--chrome/browser/parsers/metadata_parser_manager.cc11
-rw-r--r--chrome/browser/parsers/metadata_parser_manager.h2
-rw-r--r--chrome/browser/password_manager/password_form_manager.cc2
-rw-r--r--chrome/browser/password_manager/password_form_manager_unittest.cc2
-rw-r--r--chrome/browser/password_manager/password_manager.cc3
-rw-r--r--chrome/browser/password_manager/password_manager.h2
-rw-r--r--chrome/browser/password_manager/password_manager_unittest.cc2
-rw-r--r--chrome/browser/password_manager/password_store_default.cc1
-rw-r--r--chrome/browser/password_manager/password_store_default.h34
-rw-r--r--chrome/browser/password_manager/password_store_default_unittest.cc12
-rw-r--r--chrome/browser/password_manager/password_store_mac.cc1
-rw-r--r--chrome/browser/password_manager/password_store_mac.h2
-rw-r--r--chrome/browser/password_manager/password_store_win.cc2
-rw-r--r--chrome/browser/password_manager/password_store_x_unittest.cc6
-rw-r--r--chrome/browser/platform_util_chromeos.cc2
-rw-r--r--chrome/browser/plugin_carbon_interpose_mac.cc14
-rw-r--r--chrome/browser/plugin_data_remover.cc101
-rw-r--r--chrome/browser/plugin_data_remover.h38
-rw-r--r--chrome/browser/plugin_data_remover_helper.cc90
-rw-r--r--chrome/browser/plugin_data_remover_helper.h51
-rw-r--r--chrome/browser/plugin_download_helper.cc16
-rw-r--r--chrome/browser/plugin_download_helper.h18
-rw-r--r--chrome/browser/plugin_exceptions_table_model.cc17
-rw-r--r--chrome/browser/plugin_exceptions_table_model.h24
-rw-r--r--chrome/browser/plugin_exceptions_table_model_unittest.cc39
-rw-r--r--chrome/browser/plugin_installer.cc6
-rw-r--r--chrome/browser/plugin_process_host.cc52
-rw-r--r--chrome/browser/plugin_process_host.h23
-rw-r--r--chrome/browser/plugin_service.cc65
-rw-r--r--chrome/browser/plugin_service.h9
-rw-r--r--chrome/browser/plugin_service_browsertest.cc12
-rw-r--r--chrome/browser/plugin_service_unittest.cc1
-rw-r--r--chrome/browser/plugin_updater.cc73
-rw-r--r--chrome/browser/plugin_updater.h28
-rw-r--r--chrome/browser/policy/asynchronous_policy_loader.cc158
-rw-r--r--chrome/browser/policy/asynchronous_policy_loader.h118
-rw-r--r--chrome/browser/policy/asynchronous_policy_loader_unittest.cc134
-rw-r--r--chrome/browser/policy/asynchronous_policy_provider.cc46
-rw-r--r--chrome/browser/policy/asynchronous_policy_provider.h61
-rw-r--r--chrome/browser/policy/asynchronous_policy_provider_unittest.cc57
-rw-r--r--chrome/browser/policy/asynchronous_policy_test_base.h64
-rw-r--r--chrome/browser/policy/config_dir_policy_provider.cc16
-rw-r--r--chrome/browser/policy/config_dir_policy_provider.h35
-rw-r--r--chrome/browser/policy/config_dir_policy_provider_unittest.cc13
-rw-r--r--chrome/browser/policy/configuration_policy_loader_win.cc90
-rw-r--r--chrome/browser/policy/configuration_policy_loader_win.h57
-rw-r--r--chrome/browser/policy/configuration_policy_pref_store.cc991
-rw-r--r--chrome/browser/policy/configuration_policy_pref_store.h117
-rw-r--r--chrome/browser/policy/configuration_policy_pref_store_unittest.cc785
-rw-r--r--chrome/browser/policy/configuration_policy_provider.cc45
-rw-r--r--chrome/browser/policy/configuration_policy_provider.h54
-rw-r--r--chrome/browser/policy/configuration_policy_provider_delegate_win.cc160
-rw-r--r--chrome/browser/policy/configuration_policy_provider_delegate_win.h47
-rw-r--r--chrome/browser/policy/configuration_policy_provider_mac.cc14
-rw-r--r--chrome/browser/policy/configuration_policy_provider_mac.h9
-rw-r--r--chrome/browser/policy/configuration_policy_provider_mac_unittest.cc4
-rw-r--r--chrome/browser/policy/configuration_policy_provider_win.cc279
-rw-r--r--chrome/browser/policy/configuration_policy_provider_win.h95
-rw-r--r--chrome/browser/policy/configuration_policy_provider_win_unittest.cc26
-rw-r--r--chrome/browser/policy/configuration_policy_store_interface.h26
-rw-r--r--chrome/browser/policy/device_management_policy_cache.cc2
-rw-r--r--chrome/browser/policy/device_management_policy_cache.h1
-rw-r--r--chrome/browser/policy/device_management_policy_provider.cc34
-rw-r--r--chrome/browser/policy/device_management_policy_provider.h25
-rw-r--r--chrome/browser/policy/device_management_policy_provider_unittest.cc35
-rw-r--r--chrome/browser/policy/device_management_service.cc1
-rw-r--r--chrome/browser/policy/device_management_service_browsertest.cc13
-rw-r--r--chrome/browser/policy/device_token_fetcher.cc31
-rw-r--r--chrome/browser/policy/device_token_fetcher.h25
-rw-r--r--chrome/browser/policy/device_token_fetcher_unittest.cc1
-rw-r--r--chrome/browser/policy/dummy_configuration_policy_provider.cc22
-rw-r--r--chrome/browser/policy/dummy_configuration_policy_provider.h18
-rw-r--r--chrome/browser/policy/file_based_policy_loader.cc144
-rw-r--r--chrome/browser/policy/file_based_policy_loader.h78
-rw-r--r--chrome/browser/policy/file_based_policy_provider.cc238
-rw-r--r--chrome/browser/policy/file_based_policy_provider.h165
-rw-r--r--chrome/browser/policy/file_based_policy_provider_unittest.cc170
-rw-r--r--chrome/browser/policy/managed_prefs_banner_base.cc3
-rw-r--r--chrome/browser/policy/managed_prefs_banner_base.h2
-rw-r--r--chrome/browser/policy/managed_prefs_banner_base_unittest.cc1
-rw-r--r--chrome/browser/policy/mock_configuration_policy_provider.cc22
-rw-r--r--chrome/browser/policy/mock_configuration_policy_provider.h12
-rw-r--r--chrome/browser/policy/profile_policy_context.cc2
-rw-r--r--chrome/browser/popup_blocker_browsertest.cc2
-rw-r--r--chrome/browser/possible_url_model.cc2
-rw-r--r--chrome/browser/ppapi_plugin_process_host.cc63
-rw-r--r--chrome/browser/ppapi_plugin_process_host.h21
-rw-r--r--chrome/browser/prefs/browser_prefs.cc10
-rw-r--r--chrome/browser/prefs/command_line_pref_store.cc34
-rw-r--r--chrome/browser/prefs/command_line_pref_store.h14
-rw-r--r--chrome/browser/prefs/command_line_pref_store_unittest.cc70
-rw-r--r--chrome/browser/prefs/default_pref_store.cc21
-rw-r--r--chrome/browser/prefs/default_pref_store.h21
-rw-r--r--chrome/browser/prefs/dummy_pref_store.cc22
-rw-r--r--chrome/browser/prefs/dummy_pref_store.h49
-rw-r--r--chrome/browser/prefs/pref_change_registrar.cc1
-rw-r--r--chrome/browser/prefs/pref_change_registrar_unittest.cc16
-rw-r--r--chrome/browser/prefs/pref_member_unittest.cc5
-rw-r--r--chrome/browser/prefs/pref_notifier.cc137
-rw-r--r--chrome/browser/prefs/pref_notifier.h113
-rw-r--r--chrome/browser/prefs/pref_notifier_impl.cc105
-rw-r--r--chrome/browser/prefs/pref_notifier_impl.h58
-rw-r--r--chrome/browser/prefs/pref_notifier_impl_unittest.cc200
-rw-r--r--chrome/browser/prefs/pref_notifier_unittest.cc294
-rw-r--r--chrome/browser/prefs/pref_observer_mock.h60
-rw-r--r--chrome/browser/prefs/pref_service.cc138
-rw-r--r--chrome/browser/prefs/pref_service.h72
-rw-r--r--chrome/browser/prefs/pref_service_mock_builder.cc103
-rw-r--r--chrome/browser/prefs/pref_service_mock_builder.h68
-rw-r--r--chrome/browser/prefs/pref_service_unittest.cc328
-rw-r--r--chrome/browser/prefs/pref_set_observer.cc3
-rw-r--r--chrome/browser/prefs/pref_value_map.cc107
-rw-r--r--chrome/browser/prefs/pref_value_map.h64
-rw-r--r--chrome/browser/prefs/pref_value_map_unittest.cc76
-rw-r--r--chrome/browser/prefs/pref_value_store.cc475
-rw-r--r--chrome/browser/prefs/pref_value_store.h237
-rw-r--r--chrome/browser/prefs/pref_value_store_unittest.cc527
-rw-r--r--chrome/browser/prefs/proxy_prefs.cc45
-rw-r--r--chrome/browser/prefs/proxy_prefs.h45
-rw-r--r--chrome/browser/prefs/proxy_prefs_unittest.cc52
-rw-r--r--chrome/browser/prefs/scoped_pref_update.cc6
-rw-r--r--chrome/browser/prefs/session_startup_pref.cc2
-rw-r--r--chrome/browser/prefs/testing_pref_store.cc100
-rw-r--r--chrome/browser/prefs/testing_pref_store.h80
-rw-r--r--chrome/browser/prefs/value_map_pref_store.cc41
-rw-r--r--chrome/browser/prefs/value_map_pref_store.h48
-rw-r--r--chrome/browser/prerender/prerender_contents.cc217
-rw-r--r--chrome/browser/prerender/prerender_contents.h168
-rw-r--r--chrome/browser/prerender/prerender_interceptor.cc75
-rw-r--r--chrome/browser/prerender/prerender_interceptor.h49
-rw-r--r--chrome/browser/prerender/prerender_interceptor_unittest.cc101
-rw-r--r--chrome/browser/prerender/prerender_manager.cc134
-rw-r--r--chrome/browser/prerender/prerender_manager.h81
-rw-r--r--chrome/browser/prerender/prerender_manager_unittest.cc179
-rw-r--r--chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc11
-rw-r--r--chrome/browser/printing/cloud_print/cloud_print_setup_flow.cc17
-rw-r--r--chrome/browser/printing/cloud_print/cloud_print_setup_flow.h2
-rw-r--r--chrome/browser/printing/cloud_print/cloud_print_setup_source.cc7
-rw-r--r--chrome/browser/printing/cloud_print/cloud_print_setup_source.h4
-rw-r--r--chrome/browser/printing/cloud_print/cloud_print_url.cc2
-rw-r--r--chrome/browser/printing/print_dialog_cloud.cc2
-rw-r--r--chrome/browser/printing/print_dialog_cloud_uitest.cc58
-rw-r--r--chrome/browser/printing/print_job.cc13
-rw-r--r--chrome/browser/printing/print_job.h4
-rw-r--r--chrome/browser/printing/print_job_manager.h2
-rw-r--r--chrome/browser/printing/print_job_worker.cc20
-rw-r--r--chrome/browser/printing/print_job_worker.h7
-rw-r--r--chrome/browser/printing/print_job_worker_owner.h4
-rw-r--r--chrome/browser/printing/print_preview_tab_controller.cc155
-rw-r--r--chrome/browser/printing/print_preview_tab_controller.h34
-rw-r--r--chrome/browser/printing/print_view_manager.cc3
-rw-r--r--chrome/browser/printing/printer_query.cc24
-rw-r--r--chrome/browser/printing/printer_query.h11
-rw-r--r--chrome/browser/printing/printing_layout_uitest.cc23
-rw-r--r--chrome/browser/process_info_snapshot_mac_unittest.cc25
-rw-r--r--chrome/browser/process_singleton.h16
-rw-r--r--chrome/browser/process_singleton_linux.cc103
-rw-r--r--chrome/browser/process_singleton_linux_uitest.cc1
-rw-r--r--chrome/browser/process_singleton_mac.cc12
-rw-r--r--chrome/browser/process_singleton_uitest.cc2
-rw-r--r--chrome/browser/process_singleton_win.cc16
-rw-r--r--chrome/browser/profile.cc663
-rw-r--r--chrome/browser/profile.h544
-rw-r--r--chrome/browser/profile_impl.cc1319
-rw-r--r--chrome/browser/profile_impl.h290
-rw-r--r--chrome/browser/profile_import_process_host.cc19
-rw-r--r--chrome/browser/profile_import_process_host.h12
-rw-r--r--chrome/browser/profile_manager.cc284
-rw-r--r--chrome/browser/profile_manager.h128
-rw-r--r--chrome/browser/profile_manager_unittest.cc148
-rw-r--r--chrome/browser/profiles/profile.cc680
-rw-r--r--chrome/browser/profiles/profile.h558
-rw-r--r--chrome/browser/profiles/profile_impl.cc1372
-rw-r--r--chrome/browser/profiles/profile_impl.h306
-rw-r--r--chrome/browser/profiles/profile_manager.cc285
-rw-r--r--chrome/browser/profiles/profile_manager.h128
-rw-r--r--chrome/browser/profiles/profile_manager_unittest.cc149
-rw-r--r--chrome/browser/remoting/directory_add_request.cc125
-rw-r--r--chrome/browser/remoting/directory_add_request.h75
-rw-r--r--chrome/browser/remoting/directory_add_request_unittest.cc82
-rw-r--r--chrome/browser/remoting/remoting_resources_source.cc9
-rw-r--r--chrome/browser/remoting/remoting_resources_source.h4
-rw-r--r--chrome/browser/remoting/remoting_setup_flow.cc11
-rw-r--r--chrome/browser/renderer_host/accelerated_surface_container_mac.cc4
-rw-r--r--chrome/browser/renderer_host/accelerated_surface_container_mac.h6
-rw-r--r--chrome/browser/renderer_host/accelerated_surface_container_manager_mac.cc4
-rw-r--r--chrome/browser/renderer_host/accelerated_surface_container_manager_mac.h7
-rw-r--r--chrome/browser/renderer_host/async_resource_handler.cc60
-rw-r--r--chrome/browser/renderer_host/async_resource_handler.h40
-rw-r--r--chrome/browser/renderer_host/audio_renderer_host.cc123
-rw-r--r--chrome/browser/renderer_host/audio_renderer_host.h55
-rw-r--r--chrome/browser/renderer_host/audio_renderer_host_unittest.cc16
-rw-r--r--chrome/browser/renderer_host/blob_dispatcher_host.cc88
-rw-r--r--chrome/browser/renderer_host/blob_dispatcher_host.h49
-rw-r--r--chrome/browser/renderer_host/blob_message_filter.cc85
-rw-r--r--chrome/browser/renderer_host/blob_message_filter.h51
-rw-r--r--chrome/browser/renderer_host/browser_render_process_host.cc268
-rw-r--r--chrome/browser/renderer_host/browser_render_process_host.h30
-rw-r--r--chrome/browser/renderer_host/buffered_resource_handler.cc16
-rw-r--r--chrome/browser/renderer_host/cross_site_resource_handler.cc7
-rw-r--r--chrome/browser/renderer_host/database_dispatcher_host.cc437
-rw-r--r--chrome/browser/renderer_host/database_dispatcher_host.h139
-rw-r--r--chrome/browser/renderer_host/database_message_filter.cc323
-rw-r--r--chrome/browser/renderer_host/database_message_filter.h103
-rw-r--r--chrome/browser/renderer_host/download_resource_handler.cc78
-rw-r--r--chrome/browser/renderer_host/download_resource_handler.h51
-rw-r--r--chrome/browser/renderer_host/download_throttling_resource_handler.cc2
-rw-r--r--chrome/browser/renderer_host/file_utilities_dispatcher_host.cc199
-rw-r--r--chrome/browser/renderer_host/file_utilities_dispatcher_host.h63
-rw-r--r--chrome/browser/renderer_host/file_utilities_message_filter.cc106
-rw-r--r--chrome/browser/renderer_host/file_utilities_message_filter.h48
-rw-r--r--chrome/browser/renderer_host/global_request_id.h4
-rw-r--r--chrome/browser/renderer_host/gtk_im_context_wrapper.cc48
-rw-r--r--chrome/browser/renderer_host/gtk_im_context_wrapper.h5
-rw-r--r--chrome/browser/renderer_host/gtk_key_bindings_handler_unittest.cc12
-rw-r--r--chrome/browser/renderer_host/mock_render_process_host.cc5
-rw-r--r--chrome/browser/renderer_host/mock_render_process_host.h4
-rw-r--r--chrome/browser/renderer_host/offline_resource_handler.cc2
-rw-r--r--chrome/browser/renderer_host/pepper_file_message_filter.cc121
-rw-r--r--chrome/browser/renderer_host/pepper_file_message_filter.h33
-rw-r--r--chrome/browser/renderer_host/redirect_to_file_resource_handler.h24
-rw-r--r--chrome/browser/renderer_host/render_message_filter.cc1616
-rw-r--r--chrome/browser/renderer_host/render_message_filter.h498
-rw-r--r--chrome/browser/renderer_host/render_message_filter_gtk.cc344
-rw-r--r--chrome/browser/renderer_host/render_message_filter_mac.mm43
-rw-r--r--chrome/browser/renderer_host/render_message_filter_win.cc48
-rw-r--r--chrome/browser/renderer_host/render_process_host.h13
-rw-r--r--chrome/browser/renderer_host/render_sandbox_host_linux.cc15
-rw-r--r--chrome/browser/renderer_host/render_sandbox_host_linux.h6
-rw-r--r--chrome/browser/renderer_host/render_view_host.cc140
-rw-r--r--chrome/browser/renderer_host/render_view_host.h37
-rw-r--r--chrome/browser/renderer_host/render_view_host_delegate.h48
-rw-r--r--chrome/browser/renderer_host/render_widget_host.cc85
-rw-r--r--chrome/browser/renderer_host/render_widget_host.h20
-rw-r--r--chrome/browser/renderer_host/render_widget_host_unittest.cc2
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view.cc11
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view.h19
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_gtk.cc25
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_gtk.h11
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_mac.h7
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_mac.mm35
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_mac_unittest.mm88
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_views.cc23
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_views.h7
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_win.cc32
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_win.h5
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host.cc317
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host.h114
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host_request_info.cc4
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host_request_info.h8
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc246
-rw-r--r--chrome/browser/renderer_host/resource_handler.h8
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.cc1837
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.h604
-rw-r--r--chrome/browser/renderer_host/resource_message_filter_gtk.cc388
-rw-r--r--chrome/browser/renderer_host/resource_message_filter_mac.mm43
-rw-r--r--chrome/browser/renderer_host/resource_message_filter_win.cc48
-rw-r--r--chrome/browser/renderer_host/resource_queue.cc4
-rw-r--r--chrome/browser/renderer_host/resource_queue.h10
-rw-r--r--chrome/browser/renderer_host/resource_queue_unittest.cc27
-rw-r--r--chrome/browser/renderer_host/resource_request_details.cc24
-rw-r--r--chrome/browser/renderer_host/resource_request_details.h3
-rw-r--r--chrome/browser/renderer_host/safe_browsing_resource_handler.cc22
-rw-r--r--chrome/browser/renderer_host/safe_browsing_resource_handler.h45
-rw-r--r--chrome/browser/renderer_host/site_instance.cc6
-rw-r--r--chrome/browser/renderer_host/site_instance.h6
-rw-r--r--chrome/browser/renderer_host/socket_stream_dispatcher_host.cc158
-rw-r--r--chrome/browser/renderer_host/socket_stream_dispatcher_host.h37
-rw-r--r--chrome/browser/renderer_host/socket_stream_host.cc54
-rw-r--r--chrome/browser/renderer_host/socket_stream_host.h20
-rw-r--r--chrome/browser/renderer_host/sync_resource_handler.cc21
-rw-r--r--chrome/browser/renderer_host/sync_resource_handler.h38
-rw-r--r--chrome/browser/renderer_host/test/render_process_host_browsertest.cc1
-rw-r--r--chrome/browser/renderer_host/test/render_view_host_browsertest.cc184
-rw-r--r--chrome/browser/renderer_host/test/render_view_host_manager_browsertest.cc6
-rw-r--r--chrome/browser/renderer_host/test/render_view_host_unittest.cc2
-rw-r--r--chrome/browser/renderer_host/test/test_render_view_host.cc10
-rw-r--r--chrome/browser/renderer_host/test/test_render_view_host.h8
-rw-r--r--chrome/browser/renderer_host/test/web_cache_manager_browsertest.cc3
-rw-r--r--chrome/browser/renderer_host/x509_user_cert_resource_handler.cc4
-rw-r--r--chrome/browser/renderer_host/x509_user_cert_resource_handler.h26
-rw-r--r--chrome/browser/renderer_preferences_util.cc8
-rw-r--r--chrome/browser/repost_form_warning_controller.cc2
-rw-r--r--chrome/browser/repost_form_warning_controller.h6
-rw-r--r--chrome/browser/resources/about_conflicts.html78
-rw-r--r--chrome/browser/resources/about_credits.html1625
-rw-r--r--chrome/browser/resources/about_os_credits.html40
-rw-r--r--chrome/browser/resources/about_sys.html12
-rw-r--r--chrome/browser/resources/bookmark_manager/css/bmm.css8
-rw-r--r--chrome/browser/resources/bookmark_manager/main.html18
-rw-r--r--chrome/browser/resources/bug_report.css4
-rw-r--r--chrome/browser/resources/chat_manager/128.pngbin11691 -> 0 bytes
-rw-r--r--chrome/browser/resources/chat_manager/16.pngbin909 -> 0 bytes
-rw-r--r--chrome/browser/resources/chat_manager/24.pngbin1559 -> 0 bytes
-rw-r--r--chrome/browser/resources/chat_manager/32.pngbin2407 -> 0 bytes
-rw-r--r--chrome/browser/resources/chat_manager/48.pngbin4485 -> 0 bytes
-rw-r--r--chrome/browser/resources/chat_manager/_locales/en/messages.json1
-rw-r--r--chrome/browser/resources/chat_manager/background.html19
-rw-r--r--chrome/browser/resources/chat_manager/central_roster.html39
-rw-r--r--chrome/browser/resources/chat_manager/central_roster_viewer.html32
-rw-r--r--chrome/browser/resources/chat_manager/js/background.js128
-rw-r--r--chrome/browser/resources/chat_manager/js/centralroster.js137
-rw-r--r--chrome/browser/resources/chat_manager/js/centralrosterviewer.js61
-rw-r--r--chrome/browser/resources/chat_manager/js/chatbridgeeventtypes.js23
-rw-r--r--chrome/browser/resources/chat_manager/js/chatbridgehook.js159
-rw-r--r--chrome/browser/resources/chat_manager/js/gmailbridgehook.js100
-rw-r--r--chrome/browser/resources/chat_manager/manifest.json48
-rw-r--r--chrome/browser/resources/chat_manager/options.html5
-rw-r--r--chrome/browser/resources/dom_ui.css5
-rw-r--r--chrome/browser/resources/dom_ui2.css5
-rw-r--r--chrome/browser/resources/downloads.html27
-rw-r--r--chrome/browser/resources/extensions_ui.html37
-rw-r--r--chrome/browser/resources/filebrowse.html79
-rw-r--r--chrome/browser/resources/flags.html32
-rw-r--r--chrome/browser/resources/gpu_blacklist.json68
-rw-r--r--chrome/browser/resources/gpu_internals.html91
-rw-r--r--chrome/browser/resources/gpu_internals/browser_bridge.js59
-rw-r--r--chrome/browser/resources/gpu_internals/info_view.css28
-rw-r--r--chrome/browser/resources/gpu_internals/info_view.html34
-rw-r--r--chrome/browser/resources/gpu_internals/info_view.js119
-rw-r--r--chrome/browser/resources/history.html18
-rw-r--r--chrome/browser/resources/imageburner.html4
-rw-r--r--chrome/browser/resources/keyboard_overlay.css6
-rw-r--r--chrome/browser/resources/login.html63
-rw-r--r--chrome/browser/resources/login_ui.css43
-rw-r--r--chrome/browser/resources/mediaplayer.html6
-rw-r--r--chrome/browser/resources/net_internals/detailsview.js2
-rw-r--r--chrome/browser/resources/net_internals/index.html8
-rw-r--r--chrome/browser/resources/net_internals/main.css50
-rw-r--r--chrome/browser/resources/net_internals/main.js29
-rw-r--r--chrome/browser/resources/net_internals/tabswitcherview.css61
-rw-r--r--chrome/browser/resources/net_internals/tabswitcherview.js8
-rw-r--r--chrome/browser/resources/net_internals/view.js2
-rw-r--r--chrome/browser/resources/new_new_tab.css29
-rw-r--r--chrome/browser/resources/new_new_tab.html4
-rw-r--r--chrome/browser/resources/new_new_tab.js112
-rw-r--r--chrome/browser/resources/ntp/apps.css2
-rw-r--r--chrome/browser/resources/ntp/apps.js8
-rw-r--r--chrome/browser/resources/ntp/most_visited.css4
-rw-r--r--chrome/browser/resources/options.html388
-rw-r--r--chrome/browser/resources/options/add_startup_page_overlay.js2
-rw-r--r--chrome/browser/resources/options/add_startup_page_recent_pages_list.js2
-rw-r--r--chrome/browser/resources/options/advanced_options.css2
-rw-r--r--chrome/browser/resources/options/advanced_options.html55
-rw-r--r--chrome/browser/resources/options/advanced_options.js77
-rw-r--r--chrome/browser/resources/options/alert_overlay.js29
-rw-r--r--chrome/browser/resources/options/autofill_edit_address_overlay.js2
-rw-r--r--chrome/browser/resources/options/autofill_edit_creditcard_overlay.js2
-rw-r--r--chrome/browser/resources/options/autofill_options.css12
-rw-r--r--chrome/browser/resources/options/autofill_options.html47
-rw-r--r--chrome/browser/resources/options/autofill_options.js274
-rw-r--r--chrome/browser/resources/options/autofill_options_list.js71
-rw-r--r--chrome/browser/resources/options/autofill_options_page.css15
-rw-r--r--chrome/browser/resources/options/browser_options.html23
-rw-r--r--chrome/browser/resources/options/browser_options.js87
-rw-r--r--chrome/browser/resources/options/browser_options_page.css8
-rw-r--r--chrome/browser/resources/options/browser_options_startup_page_list.js17
-rw-r--r--chrome/browser/resources/options/certificate_manager.js7
-rw-r--r--chrome/browser/resources/options/chromeos_accounts_options.html11
-rw-r--r--chrome/browser/resources/options/chromeos_accounts_options.js12
-rw-r--r--chrome/browser/resources/options/chromeos_accounts_options_page.css16
-rw-r--r--chrome/browser/resources/options/chromeos_accounts_user_name_edit.js7
-rw-r--r--chrome/browser/resources/options/chromeos_internet_detail.html14
-rw-r--r--chrome/browser/resources/options/chromeos_internet_network_element.js87
-rw-r--r--chrome/browser/resources/options/chromeos_internet_options.js103
-rw-r--r--chrome/browser/resources/options/chromeos_internet_options_page.css12
-rw-r--r--chrome/browser/resources/options/chromeos_language_list.js37
-rw-r--r--chrome/browser/resources/options/chromeos_system_options.js6
-rw-r--r--chrome/browser/resources/options/clear_browser_data_overlay.css4
-rw-r--r--chrome/browser/resources/options/content_settings.css59
-rw-r--r--chrome/browser/resources/options/content_settings.html474
-rw-r--r--chrome/browser/resources/options/content_settings.js102
-rw-r--r--chrome/browser/resources/options/content_settings_exceptions_area.css18
-rw-r--r--chrome/browser/resources/options/content_settings_exceptions_area.html64
-rw-r--r--chrome/browser/resources/options/content_settings_exceptions_area.js552
-rw-r--r--chrome/browser/resources/options/cookies_view.js33
-rw-r--r--chrome/browser/resources/options/deletable_item_list.js140
-rw-r--r--chrome/browser/resources/options/edit_search_engine_overlay.css2
-rw-r--r--chrome/browser/resources/options/edit_search_engine_overlay.js4
-rw-r--r--chrome/browser/resources/options/import_data_overlay.html22
-rw-r--r--chrome/browser/resources/options/import_data_overlay.js39
-rw-r--r--chrome/browser/resources/options/options.html221
-rw-r--r--chrome/browser/resources/options/options.js183
-rw-r--r--chrome/browser/resources/options/options_page.css194
-rw-r--r--chrome/browser/resources/options/options_page.js329
-rw-r--r--chrome/browser/resources/options/password_manager.css38
-rw-r--r--chrome/browser/resources/options/password_manager.html7
-rw-r--r--chrome/browser/resources/options/password_manager.js142
-rw-r--r--chrome/browser/resources/options/password_manager_list.css10
-rw-r--r--chrome/browser/resources/options/password_manager_list.js234
-rw-r--r--chrome/browser/resources/options/passwords_exceptions.html37
-rw-r--r--chrome/browser/resources/options/passwords_exceptions.js116
-rw-r--r--chrome/browser/resources/options/passwords_exceptions_list.css9
-rw-r--r--chrome/browser/resources/options/passwords_exceptions_list.js398
-rw-r--r--chrome/browser/resources/options/personal_options.html83
-rw-r--r--chrome/browser/resources/options/personal_options.js110
-rw-r--r--chrome/browser/resources/options/pref_ui.js120
-rw-r--r--chrome/browser/resources/options/search_engine_manager.css44
-rw-r--r--chrome/browser/resources/options/search_engine_manager.html7
-rw-r--r--chrome/browser/resources/options/search_engine_manager.js12
-rw-r--r--chrome/browser/resources/options/search_engine_manager_engine_list.js55
-rw-r--r--chrome/browser/resources/options/search_page.css7
-rw-r--r--chrome/browser/resources/options/search_page.html2
-rw-r--r--chrome/browser/resources/options/search_page.js322
-rw-r--r--chrome/browser/resources/options/show_password.pngbin0 -> 1074 bytes
-rw-r--r--chrome/browser/resources/options/startup_page_manager.html5
-rw-r--r--chrome/browser/resources/options/startup_page_manager.js80
-rw-r--r--chrome/browser/resources/options/subpages_tab_controls.css4
-rw-r--r--chrome/browser/resources/options/sync_options.html72
-rw-r--r--chrome/browser/resources/options/sync_options.js64
-rw-r--r--chrome/browser/resources/options/warning.pngbin0 -> 1045 bytes
-rw-r--r--chrome/browser/resources/options/zippy.css54
-rw-r--r--chrome/browser/resources/options/zippy.js202
-rw-r--r--chrome/browser/resources/plugins.html57
-rw-r--r--chrome/browser/resources/print_preview.css5
-rw-r--r--chrome/browser/resources/print_preview.html3
-rw-r--r--chrome/browser/resources/print_preview.js38
-rw-r--r--chrome/browser/resources/safe_browsing_malware_block.html160
-rw-r--r--chrome/browser/resources/safe_browsing_phishing_block.html53
-rw-r--r--chrome/browser/resources/shared/css/button.css2
-rw-r--r--chrome/browser/resources/shared/css/list.css5
-rw-r--r--chrome/browser/resources/shared/css/menu.css2
-rw-r--r--chrome/browser/resources/shared/css/tree.css2
-rw-r--r--chrome/browser/resources/shared/js/cr.js8
-rw-r--r--chrome/browser/resources/shared/js/cr/ui/list.js121
-rw-r--r--chrome/browser/resources/shared/js/cr/ui/list_item.js30
-rw-r--r--chrome/browser/resources/shared/js/cr/ui/list_selection_controller.js3
-rw-r--r--chrome/browser/rlz/rlz.cc4
-rw-r--r--chrome/browser/safe_browsing/client_side_detection_service.cc5
-rw-r--r--chrome/browser/safe_browsing/client_side_detection_service.h6
-rw-r--r--chrome/browser/safe_browsing/malware_details.cc98
-rw-r--r--chrome/browser/safe_browsing/malware_details.h68
-rw-r--r--chrome/browser/safe_browsing/malware_details_unittest.cc175
-rw-r--r--chrome/browser/safe_browsing/protocol_manager.cc106
-rw-r--r--chrome/browser/safe_browsing/protocol_manager.h109
-rw-r--r--chrome/browser/safe_browsing/protocol_manager_unittest.cc17
-rw-r--r--chrome/browser/safe_browsing/report.proto91
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_blocking_page.cc75
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_blocking_page.h22
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc66
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_blocking_page_unittest.cc137
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_database.cc479
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_database.h147
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_database_unittest.cc399
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_service.cc146
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_service.h50
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc393
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_store.cc43
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_store.h14
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_store_file.cc72
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_store_file.h15
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_store_file_unittest.cc35
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_store_sqlite.cc87
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_store_sqlite.h79
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_store_unittest_helper.cc15
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_test.cc13
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_util.cc45
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_util.h14
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_util_unittest.cc40
-rw-r--r--chrome/browser/search_engines/edit_search_engine_controller.cc2
-rw-r--r--chrome/browser/search_engines/keyword_editor_controller.cc2
-rw-r--r--chrome/browser/search_engines/keyword_editor_controller_unittest.cc13
-rw-r--r--chrome/browser/search_engines/search_provider_install_data_unittest.cc10
-rw-r--r--chrome/browser/search_engines/search_provider_install_state_dispatcher_host.cc123
-rw-r--r--chrome/browser/search_engines/search_provider_install_state_dispatcher_host.h71
-rw-r--r--chrome/browser/search_engines/search_provider_install_state_message_filter.cc113
-rw-r--r--chrome/browser/search_engines/search_provider_install_state_message_filter.h57
-rw-r--r--chrome/browser/search_engines/template_url_fetcher.cc2
-rw-r--r--chrome/browser/search_engines/template_url_model.cc11
-rw-r--r--chrome/browser/search_engines/template_url_model_test_util.cc8
-rw-r--r--chrome/browser/search_engines/template_url_model_test_util.h4
-rw-r--r--chrome/browser/search_engines/template_url_model_unittest.cc63
-rw-r--r--chrome/browser/search_engines/template_url_prepopulate_data_unittest.cc52
-rw-r--r--chrome/browser/search_engines/template_url_scraper_unittest.cc2
-rw-r--r--chrome/browser/search_engines/template_url_table_model.cc2
-rw-r--r--chrome/browser/search_engines/util.cc2
-rw-r--r--chrome/browser/service/service_process_control.cc58
-rw-r--r--chrome/browser/service/service_process_control.h27
-rw-r--r--chrome/browser/service/service_process_control_browsertest.cc10
-rw-r--r--chrome/browser/service/service_process_control_manager.cc4
-rw-r--r--chrome/browser/service/service_process_control_manager.h2
-rw-r--r--chrome/browser/sessions/base_session_service.cc2
-rw-r--r--chrome/browser/sessions/session_restore.cc8
-rw-r--r--chrome/browser/sessions/session_restore_browsertest.cc1
-rw-r--r--chrome/browser/sessions/session_service.cc10
-rw-r--r--chrome/browser/sessions/session_service.h2
-rw-r--r--chrome/browser/sessions/session_types.h5
-rw-r--r--chrome/browser/sessions/tab_restore_service.cc2
-rw-r--r--chrome/browser/sessions/tab_restore_service_browsertest.cc1
-rw-r--r--chrome/browser/shell_integration_linux.cc3
-rw-r--r--chrome/browser/shell_integration_unittest.cc2
-rw-r--r--chrome/browser/shell_integration_win.cc14
-rw-r--r--chrome/browser/show_options_url.cc21
-rw-r--r--chrome/browser/show_options_url.h20
-rw-r--r--chrome/browser/sidebar/sidebar_container.cc5
-rw-r--r--chrome/browser/sidebar/sidebar_container.h3
-rw-r--r--chrome/browser/sidebar/sidebar_manager.cc2
-rw-r--r--chrome/browser/sidebar/sidebar_test.cc14
-rw-r--r--chrome/browser/speech/speech_input_browsertest.cc15
-rw-r--r--chrome/browser/speech/speech_input_bubble.cc5
-rw-r--r--chrome/browser/speech/speech_input_bubble.h8
-rw-r--r--chrome/browser/speech/speech_input_bubble_controller.cc63
-rw-r--r--chrome/browser/speech/speech_input_bubble_controller.h30
-rw-r--r--chrome/browser/speech/speech_input_bubble_controller_unittest.cc33
-rw-r--r--chrome/browser/speech/speech_input_bubble_gtk.cc9
-rw-r--r--chrome/browser/speech/speech_input_bubble_mac.mm9
-rw-r--r--chrome/browser/speech/speech_input_bubble_views.cc37
-rw-r--r--chrome/browser/speech/speech_input_dispatcher_host.cc114
-rw-r--r--chrome/browser/speech/speech_input_dispatcher_host.h36
-rw-r--r--chrome/browser/speech/speech_input_manager.cc47
-rw-r--r--chrome/browser/speech/speech_input_manager.h4
-rw-r--r--chrome/browser/speech/speech_recognition_request.h12
-rw-r--r--chrome/browser/speech/speech_recognizer.cc2
-rw-r--r--chrome/browser/speech/speech_recognizer.h14
-rw-r--r--chrome/browser/spellcheck_host.cc2
-rw-r--r--chrome/browser/ssl/ssl_add_cert_handler.cc2
-rw-r--r--chrome/browser/ssl/ssl_blocking_page.cc2
-rw-r--r--chrome/browser/ssl/ssl_browser_tests.cc40
-rw-r--r--chrome/browser/ssl/ssl_cert_error_handler.cc6
-rw-r--r--chrome/browser/ssl/ssl_cert_error_handler.h2
-rw-r--r--chrome/browser/ssl/ssl_client_auth_handler.cc4
-rw-r--r--chrome/browser/ssl/ssl_client_auth_handler.h4
-rw-r--r--chrome/browser/ssl/ssl_error_handler.cc22
-rw-r--r--chrome/browser/ssl/ssl_error_handler.h18
-rw-r--r--chrome/browser/ssl/ssl_error_info.cc2
-rw-r--r--chrome/browser/ssl/ssl_manager.cc2
-rw-r--r--chrome/browser/ssl/ssl_manager.h2
-rw-r--r--chrome/browser/ssl/ssl_policy.cc3
-rw-r--r--chrome/browser/ssl/ssl_policy_backend.cc2
-rw-r--r--chrome/browser/sync/engine/change_reorder_buffer.cc5
-rw-r--r--chrome/browser/sync/engine/model_changing_syncer_command.cc5
-rw-r--r--chrome/browser/sync/engine/model_changing_syncer_command.h4
-rw-r--r--chrome/browser/sync/engine/net/server_connection_manager.cc4
-rw-r--r--chrome/browser/sync/engine/net/server_connection_manager.h4
-rw-r--r--chrome/browser/sync/engine/syncapi.cc85
-rw-r--r--chrome/browser/sync/engine/syncapi.h17
-rw-r--r--chrome/browser/sync/engine/syncer.cc1
-rw-r--r--chrome/browser/sync/engine/syncer_thread.cc20
-rw-r--r--chrome/browser/sync/engine/syncer_thread.h20
-rw-r--r--chrome/browser/sync/glue/app_data_type_controller.cc23
-rw-r--r--chrome/browser/sync/glue/app_data_type_controller.h29
-rw-r--r--chrome/browser/sync/glue/autofill_change_processor.cc55
-rw-r--r--chrome/browser/sync/glue/autofill_change_processor.h5
-rw-r--r--chrome/browser/sync/glue/autofill_change_processor2.cc3
-rw-r--r--chrome/browser/sync/glue/autofill_data_type_controller.cc41
-rw-r--r--chrome/browser/sync/glue/autofill_data_type_controller.h32
-rw-r--r--chrome/browser/sync/glue/autofill_data_type_controller_unittest.cc2
-rw-r--r--chrome/browser/sync/glue/autofill_model_associator.cc164
-rw-r--r--chrome/browser/sync/glue/autofill_model_associator.h32
-rw-r--r--chrome/browser/sync/glue/autofill_model_associator2.cc6
-rw-r--r--chrome/browser/sync/glue/autofill_model_associator2.h4
-rw-r--r--chrome/browser/sync/glue/autofill_profile_change_processor.cc338
-rw-r--r--chrome/browser/sync/glue/autofill_profile_change_processor.h120
-rw-r--r--chrome/browser/sync/glue/autofill_profile_data_type_controller.cc33
-rw-r--r--chrome/browser/sync/glue/autofill_profile_data_type_controller.h39
-rw-r--r--chrome/browser/sync/glue/autofill_profile_model_associator.cc139
-rw-r--r--chrome/browser/sync/glue/autofill_profile_model_associator.h33
-rw-r--r--chrome/browser/sync/glue/bookmark_change_processor.cc9
-rw-r--r--chrome/browser/sync/glue/bookmark_change_processor.h2
-rw-r--r--chrome/browser/sync/glue/bookmark_data_type_controller.cc23
-rw-r--r--chrome/browser/sync/glue/bookmark_data_type_controller.h29
-rw-r--r--chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc2
-rw-r--r--chrome/browser/sync/glue/bookmark_model_associator.cc21
-rw-r--r--chrome/browser/sync/glue/bookmark_model_associator.h6
-rw-r--r--chrome/browser/sync/glue/change_processor.cc6
-rw-r--r--chrome/browser/sync/glue/change_processor.h2
-rw-r--r--chrome/browser/sync/glue/change_processor_mock.h3
-rw-r--r--chrome/browser/sync/glue/data_type_manager.h2
-rw-r--r--chrome/browser/sync/glue/data_type_manager_impl.cc9
-rw-r--r--chrome/browser/sync/glue/data_type_manager_impl.h8
-rw-r--r--chrome/browser/sync/glue/database_model_worker.cc4
-rw-r--r--chrome/browser/sync/glue/database_model_worker.h4
-rw-r--r--chrome/browser/sync/glue/do_optimistic_refresh_task.cc23
-rw-r--r--chrome/browser/sync/glue/do_optimistic_refresh_task.h26
-rw-r--r--chrome/browser/sync/glue/extension_change_processor.cc33
-rw-r--r--chrome/browser/sync/glue/extension_change_processor.h2
-rw-r--r--chrome/browser/sync/glue/extension_data_type_controller.cc23
-rw-r--r--chrome/browser/sync/glue/extension_data_type_controller.h29
-rw-r--r--chrome/browser/sync/glue/extension_sync.cc73
-rw-r--r--chrome/browser/sync/glue/extension_sync.h8
-rw-r--r--chrome/browser/sync/glue/extension_sync_traits.cc64
-rw-r--r--chrome/browser/sync/glue/extension_sync_traits.h27
-rw-r--r--chrome/browser/sync/glue/extension_util.cc52
-rw-r--r--chrome/browser/sync/glue/extension_util.h35
-rw-r--r--chrome/browser/sync/glue/extension_util_unittest.cc81
-rw-r--r--chrome/browser/sync/glue/history_model_worker.cc5
-rw-r--r--chrome/browser/sync/glue/history_model_worker.h4
-rw-r--r--chrome/browser/sync/glue/http_bridge.cc1
-rw-r--r--chrome/browser/sync/glue/model_associator.h4
-rw-r--r--chrome/browser/sync/glue/password_change_processor.cc7
-rw-r--r--chrome/browser/sync/glue/password_data_type_controller.cc23
-rw-r--r--chrome/browser/sync/glue/password_data_type_controller.h22
-rw-r--r--chrome/browser/sync/glue/password_model_associator.cc14
-rw-r--r--chrome/browser/sync/glue/password_model_associator.h13
-rw-r--r--chrome/browser/sync/glue/password_model_worker.cc4
-rw-r--r--chrome/browser/sync/glue/password_model_worker.h4
-rw-r--r--chrome/browser/sync/glue/preference_change_processor.cc5
-rw-r--r--chrome/browser/sync/glue/preference_data_type_controller.cc21
-rw-r--r--chrome/browser/sync/glue/preference_data_type_controller.h29
-rw-r--r--chrome/browser/sync/glue/preference_model_associator.cc15
-rw-r--r--chrome/browser/sync/glue/preference_model_associator.h13
-rw-r--r--chrome/browser/sync/glue/session_data_type_controller.cc21
-rw-r--r--chrome/browser/sync/glue/session_data_type_controller.h23
-rw-r--r--chrome/browser/sync/glue/session_model_associator.cc10
-rw-r--r--chrome/browser/sync/glue/session_model_associator.h10
-rw-r--r--chrome/browser/sync/glue/sync_backend_host.cc66
-rw-r--r--chrome/browser/sync/glue/sync_backend_host.h15
-rw-r--r--chrome/browser/sync/glue/synchronized_preferences.h1
-rw-r--r--chrome/browser/sync/glue/theme_change_processor.cc9
-rw-r--r--chrome/browser/sync/glue/theme_data_type_controller.cc24
-rw-r--r--chrome/browser/sync/glue/theme_data_type_controller.h29
-rw-r--r--chrome/browser/sync/glue/theme_util.cc20
-rw-r--r--chrome/browser/sync/glue/theme_util_unittest.cc4
-rw-r--r--chrome/browser/sync/glue/typed_url_change_processor.cc2
-rw-r--r--chrome/browser/sync/glue/typed_url_data_type_controller.cc23
-rw-r--r--chrome/browser/sync/glue/typed_url_data_type_controller.h22
-rw-r--r--chrome/browser/sync/glue/typed_url_model_associator.cc18
-rw-r--r--chrome/browser/sync/glue/typed_url_model_associator.h17
-rw-r--r--chrome/browser/sync/glue/ui_model_worker.cc4
-rw-r--r--chrome/browser/sync/glue/ui_model_worker.h2
-rw-r--r--chrome/browser/sync/notifier/chrome_invalidation_client.cc20
-rw-r--r--chrome/browser/sync/notifier/chrome_system_resources.cc39
-rw-r--r--chrome/browser/sync/notifier/chrome_system_resources.h4
-rw-r--r--chrome/browser/sync/profile_sync_factory.h9
-rw-r--r--chrome/browser/sync/profile_sync_factory_impl.cc35
-rw-r--r--chrome/browser/sync/profile_sync_factory_impl.h6
-rw-r--r--chrome/browser/sync/profile_sync_factory_mock.h6
-rw-r--r--chrome/browser/sync/profile_sync_service.cc44
-rw-r--r--chrome/browser/sync/profile_sync_service.h4
-rw-r--r--chrome/browser/sync/profile_sync_service_harness.cc48
-rw-r--r--chrome/browser/sync/profile_sync_service_harness.h18
-rw-r--r--chrome/browser/sync/profile_sync_service_mock.h2
-rw-r--r--chrome/browser/sync/profile_sync_service_unittest.cc2
-rw-r--r--chrome/browser/sync/profile_sync_test_util.h5
-rw-r--r--chrome/browser/sync/resources/configure.html8
-rw-r--r--chrome/browser/sync/resources/gaia_login.html2
-rw-r--r--chrome/browser/sync/signin_manager.cc2
-rw-r--r--chrome/browser/sync/sync_setup_flow.cc28
-rw-r--r--chrome/browser/sync/sync_setup_flow.h20
-rw-r--r--chrome/browser/sync/sync_setup_wizard.cc4
-rw-r--r--chrome/browser/sync/sync_ui_util.cc37
-rw-r--r--chrome/browser/sync/sync_ui_util_mac.mm2
-rw-r--r--chrome/browser/sync/sync_ui_util_mac_unittest.mm2
-rw-r--r--chrome/browser/sync/syncable/autofill_migration.h49
-rw-r--r--chrome/browser/sync/syncable/directory_backing_store.cc144
-rw-r--r--chrome/browser/sync/syncable/directory_backing_store.h9
-rw-r--r--chrome/browser/sync/syncable/directory_backing_store_unittest.cc165
-rw-r--r--chrome/browser/sync/syncable/model_type.cc10
-rw-r--r--chrome/browser/sync/syncable/model_type.h5
-rw-r--r--chrome/browser/sync/syncable/syncable.cc78
-rw-r--r--chrome/browser/sync/syncable/syncable.h16
-rw-r--r--chrome/browser/sync/test_profile_sync_service.h5
-rw-r--r--chrome/browser/sync/tools/sync_listen_notifications.cc11
-rw-r--r--chrome/browser/tab_closeable_state_watcher.cc8
-rw-r--r--chrome/browser/tab_closeable_state_watcher.h8
-rw-r--r--chrome/browser/tab_contents/background_contents.cc22
-rw-r--r--chrome/browser/tab_contents/background_contents.h12
-rw-r--r--chrome/browser/tab_contents/infobar_delegate.cc96
-rw-r--r--chrome/browser/tab_contents/infobar_delegate.h79
-rw-r--r--chrome/browser/tab_contents/interstitial_page.cc26
-rw-r--r--chrome/browser/tab_contents/interstitial_page.h11
-rw-r--r--chrome/browser/tab_contents/navigation_controller.cc20
-rw-r--r--chrome/browser/tab_contents/navigation_controller_unittest.cc89
-rw-r--r--chrome/browser/tab_contents/navigation_entry.cc7
-rw-r--r--chrome/browser/tab_contents/popup_menu_helper_mac.mm4
-rw-r--r--chrome/browser/tab_contents/provisional_load_details.cc4
-rw-r--r--chrome/browser/tab_contents/provisional_load_details.h10
-rw-r--r--chrome/browser/tab_contents/render_view_context_menu.cc59
-rw-r--r--chrome/browser/tab_contents/render_view_context_menu_gtk.cc6
-rw-r--r--chrome/browser/tab_contents/render_view_context_menu_gtk.h4
-rw-r--r--chrome/browser/tab_contents/render_view_context_menu_mac.mm4
-rw-r--r--chrome/browser/tab_contents/render_view_host_delegate_helper.cc19
-rw-r--r--chrome/browser/tab_contents/render_view_host_manager.cc51
-rw-r--r--chrome/browser/tab_contents/render_view_host_manager.h8
-rw-r--r--chrome/browser/tab_contents/render_view_host_manager_unittest.cc2
-rw-r--r--chrome/browser/tab_contents/tab_contents.cc212
-rw-r--r--chrome/browser/tab_contents/tab_contents.h59
-rw-r--r--chrome/browser/tab_contents/tab_contents_delegate.cc18
-rw-r--r--chrome/browser/tab_contents/tab_contents_delegate.h11
-rw-r--r--chrome/browser/tab_contents/tab_contents_ssl_helper.cc3
-rw-r--r--chrome/browser/tab_contents/tab_contents_view_gtk.cc4
-rw-r--r--chrome/browser/tab_contents/tab_contents_view_mac.h2
-rw-r--r--chrome/browser/tab_contents/tab_contents_view_mac.mm21
-rw-r--r--chrome/browser/tab_contents/tab_specific_content_settings.cc26
-rw-r--r--chrome/browser/tab_contents/tab_specific_content_settings.h11
-rw-r--r--chrome/browser/tab_contents/tab_specific_content_settings_unittest.cc10
-rw-r--r--chrome/browser/tab_contents/test_tab_contents.cc5
-rw-r--r--chrome/browser/tab_contents/web_contents_unittest.cc26
-rw-r--r--chrome/browser/tab_contents/web_drag_source_win.cc4
-rw-r--r--chrome/browser/tab_contents_wrapper.cc63
-rw-r--r--chrome/browser/tab_contents_wrapper.h79
-rw-r--r--chrome/browser/tab_menu_model.cc54
-rw-r--r--chrome/browser/tab_menu_model.h29
-rw-r--r--chrome/browser/tab_menu_model_unittest.cc26
-rw-r--r--chrome/browser/tabs/pinned_tab_codec.cc4
-rw-r--r--chrome/browser/tabs/pinned_tab_service.cc2
-rw-r--r--chrome/browser/tabs/tab_strip_model.cc25
-rw-r--r--chrome/browser/tabs/tab_strip_model.h3
-rw-r--r--chrome/browser/tabs/tab_strip_model_order_controller.cc2
-rw-r--r--chrome/browser/tabs/tab_strip_model_unittest.cc14
-rw-r--r--chrome/browser/task_manager/task_manager.cc23
-rw-r--r--chrome/browser/task_manager/task_manager.h19
-rw-r--r--chrome/browser/task_manager/task_manager_browsertest.cc110
-rw-r--r--chrome/browser/task_manager/task_manager_resource_providers.cc133
-rw-r--r--chrome/browser/task_manager/task_manager_resource_providers.h87
-rw-r--r--chrome/browser/themes/browser_theme_pack.cc8
-rw-r--r--chrome/browser/themes/browser_theme_pack.h4
-rw-r--r--chrome/browser/themes/browser_theme_provider.cc12
-rw-r--r--chrome/browser/themes/browser_theme_provider.h2
-rw-r--r--chrome/browser/toolbar_model.cc129
-rw-r--r--chrome/browser/toolbar_model.h71
-rw-r--r--chrome/browser/translate/options_menu_model.cc3
-rw-r--r--chrome/browser/translate/translate_infobar_delegate.cc10
-rw-r--r--chrome/browser/translate/translate_manager.cc18
-rw-r--r--chrome/browser/translate/translate_manager.h9
-rw-r--r--chrome/browser/translate/translate_manager_unittest.cc8
-rw-r--r--chrome/browser/ui/app_modal_dialogs/app_modal_dialog.cc57
-rw-r--r--chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h82
-rw-r--r--chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.cc69
-rw-r--r--chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h89
-rw-r--r--chrome/browser/ui/app_modal_dialogs/js_modal_dialog.cc145
-rw-r--r--chrome/browser/ui/app_modal_dialogs/js_modal_dialog.h120
-rw-r--r--chrome/browser/ui/app_modal_dialogs/message_box_handler.cc88
-rw-r--r--chrome/browser/ui/app_modal_dialogs/message_box_handler.h41
-rw-r--r--chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h39
-rw-r--r--chrome/browser/ui/browser.cc403
-rw-r--r--chrome/browser/ui/browser.h62
-rw-r--r--chrome/browser/ui/browser_init.cc37
-rw-r--r--chrome/browser/ui/browser_init_browsertest.cc1
-rw-r--r--chrome/browser/ui/browser_list.cc71
-rw-r--r--chrome/browser/ui/browser_list.h8
-rw-r--r--chrome/browser/ui/browser_navigator.cc8
-rw-r--r--chrome/browser/ui/browser_navigator_browsertest.cc4
-rw-r--r--chrome/browser/ui/browser_window.h8
-rw-r--r--chrome/browser/ui/cocoa/DEPS (renamed from chrome/browser/cocoa/DEPS)0
-rw-r--r--chrome/browser/ui/cocoa/about_ipc_bridge.h33
-rw-r--r--chrome/browser/ui/cocoa/about_ipc_bridge.mm21
-rw-r--r--chrome/browser/ui/cocoa/about_ipc_controller.h84
-rw-r--r--chrome/browser/ui/cocoa/about_ipc_controller.mm199
-rw-r--r--chrome/browser/ui/cocoa/about_ipc_controller_unittest.mm50
-rw-r--r--chrome/browser/ui/cocoa/about_ipc_dialog.h24
-rw-r--r--chrome/browser/ui/cocoa/about_ipc_dialog.mm21
-rw-r--r--chrome/browser/ui/cocoa/about_window_controller.h69
-rw-r--r--chrome/browser/ui/cocoa/about_window_controller.mm761
-rw-r--r--chrome/browser/ui/cocoa/about_window_controller_unittest.mm137
-rw-r--r--chrome/browser/ui/cocoa/accelerators_cocoa.h48
-rw-r--r--chrome/browser/ui/cocoa/accelerators_cocoa.mm63
-rw-r--r--chrome/browser/ui/cocoa/accelerators_cocoa_unittest.mm28
-rw-r--r--chrome/browser/ui/cocoa/animatable_image.h57
-rw-r--r--chrome/browser/ui/cocoa/animatable_image.mm145
-rw-r--r--chrome/browser/ui/cocoa/animatable_image_unittest.mm46
-rw-r--r--chrome/browser/ui/cocoa/animatable_view.h59
-rw-r--r--chrome/browser/ui/cocoa/animatable_view.mm109
-rw-r--r--chrome/browser/ui/cocoa/animatable_view_unittest.mm48
-rw-r--r--chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_unittest.h53
-rw-r--r--chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_unittest.mm62
-rw-r--r--chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript.h70
-rw-r--r--chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript.mm204
-rw-r--r--chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript_unittest.mm200
-rw-r--r--chrome/browser/ui/cocoa/applescript/bookmark_item_applescript.h33
-rw-r--r--chrome/browser/ui/cocoa/applescript/bookmark_item_applescript.mm66
-rw-r--r--chrome/browser/ui/cocoa/applescript/bookmark_item_applescript_unittest.mm45
-rw-r--r--chrome/browser/ui/cocoa/applescript/bookmark_node_applescript.h48
-rw-r--r--chrome/browser/ui/cocoa/applescript/bookmark_node_applescript.mm130
-rw-r--r--chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript.h59
-rw-r--r--chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript.mm136
-rw-r--r--chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript_test.mm107
-rw-r--r--chrome/browser/ui/cocoa/applescript/constants_applescript.h31
-rw-r--r--chrome/browser/ui/cocoa/applescript/constants_applescript.mm25
-rw-r--r--chrome/browser/ui/cocoa/applescript/element_applescript.h37
-rw-r--r--chrome/browser/ui/cocoa/applescript/element_applescript.mm38
-rw-r--r--chrome/browser/ui/cocoa/applescript/error_applescript.h41
-rw-r--r--chrome/browser/ui/cocoa/applescript/error_applescript.mm56
-rw-r--r--chrome/browser/ui/cocoa/applescript/examples/advanced_tab_manipulation.applescript (renamed from chrome/browser/cocoa/applescript/examples/advanced_tab_manipulation.applescript)0
-rw-r--r--chrome/browser/ui/cocoa/applescript/examples/app_info.applescript (renamed from chrome/browser/cocoa/applescript/examples/app_info.applescript)0
-rw-r--r--chrome/browser/ui/cocoa/applescript/examples/bookmark_current_tabs.applescript (renamed from chrome/browser/cocoa/applescript/examples/bookmark_current_tabs.applescript)0
-rw-r--r--chrome/browser/ui/cocoa/applescript/examples/copy_html.applescript (renamed from chrome/browser/cocoa/applescript/examples/copy_html.applescript)0
-rw-r--r--chrome/browser/ui/cocoa/applescript/examples/delete_bookmarks.applescript (renamed from chrome/browser/cocoa/applescript/examples/delete_bookmarks.applescript)0
-rw-r--r--chrome/browser/ui/cocoa/applescript/examples/execute_javascript.applescript (renamed from chrome/browser/cocoa/applescript/examples/execute_javascript.applescript)0
-rw-r--r--chrome/browser/ui/cocoa/applescript/examples/open_tabs_from_bookmark_folder.applescript (renamed from chrome/browser/cocoa/applescript/examples/open_tabs_from_bookmark_folder.applescript)0
-rw-r--r--chrome/browser/ui/cocoa/applescript/examples/quit_app.applescript (renamed from chrome/browser/cocoa/applescript/examples/quit_app.applescript)0
-rw-r--r--chrome/browser/ui/cocoa/applescript/examples/tab_manipulation.applescript (renamed from chrome/browser/cocoa/applescript/examples/tab_manipulation.applescript)0
-rw-r--r--chrome/browser/ui/cocoa/applescript/examples/tab_navigation.applescript (renamed from chrome/browser/cocoa/applescript/examples/tab_navigation.applescript)0
-rw-r--r--chrome/browser/ui/cocoa/applescript/examples/window_creation.applescript (renamed from chrome/browser/cocoa/applescript/examples/window_creation.applescript)0
-rw-r--r--chrome/browser/ui/cocoa/applescript/examples/window_operations.applescript (renamed from chrome/browser/cocoa/applescript/examples/window_operations.applescript)0
-rw-r--r--chrome/browser/ui/cocoa/applescript/scripting.sdef (renamed from chrome/browser/cocoa/applescript/scripting.sdef)0
-rw-r--r--chrome/browser/ui/cocoa/applescript/tab_applescript.h79
-rw-r--r--chrome/browser/ui/cocoa/applescript/tab_applescript.mm296
-rw-r--r--chrome/browser/ui/cocoa/applescript/window_applescript.h81
-rw-r--r--chrome/browser/ui/cocoa/applescript/window_applescript.mm246
-rw-r--r--chrome/browser/ui/cocoa/applescript/window_applescript_test.mm178
-rw-r--r--chrome/browser/ui/cocoa/authorization_util.h67
-rw-r--r--chrome/browser/ui/cocoa/authorization_util.mm183
-rw-r--r--chrome/browser/ui/cocoa/back_forward_menu_controller.h43
-rw-r--r--chrome/browser/ui/cocoa/back_forward_menu_controller.mm102
-rw-r--r--chrome/browser/ui/cocoa/background_gradient_view.h29
-rw-r--r--chrome/browser/ui/cocoa/background_gradient_view.mm81
-rw-r--r--chrome/browser/ui/cocoa/background_gradient_view_unittest.mm47
-rw-r--r--chrome/browser/ui/cocoa/background_tile_view.h23
-rw-r--r--chrome/browser/ui/cocoa/background_tile_view.mm32
-rw-r--r--chrome/browser/ui/cocoa/background_tile_view_unittest.mm37
-rw-r--r--chrome/browser/ui/cocoa/base_bubble_controller.h67
-rw-r--r--chrome/browser/ui/cocoa/base_bubble_controller.mm200
-rw-r--r--chrome/browser/ui/cocoa/base_view.h45
-rw-r--r--chrome/browser/ui/cocoa/base_view.mm147
-rw-r--r--chrome/browser/ui/cocoa/base_view_unittest.mm48
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_all_tabs_controller.h46
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_all_tabs_controller.mm88
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_all_tabs_controller_unittest.mm82
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge.h60
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge.mm82
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge_unittest.mm135
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h38
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h399
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm2497
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller_unittest.mm2169
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell.h31
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell.mm22
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell_unittest.mm24
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h182
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.mm1459
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller_unittest.mm1552
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state.h78
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state.mm171
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state_unittest.mm77
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view.h (renamed from chrome/browser/cocoa/bookmarks/bookmark_bar_folder_view.h)0
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view.mm204
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view_unittest.mm211
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.h34
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.mm136
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window_unittest.mm49
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_state.h62
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.h44
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.mm135
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view_unittest.mm191
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_unittest_helper.h57
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_unittest_helper.mm81
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.h41
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.mm259
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_unittest.mm215
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.h81
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.mm428
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller_unittest.mm490
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_button.h243
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_button.mm238
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h65
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.mm246
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell_unittest.mm183
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_button_unittest.mm174
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_drag_source.h30
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_drag_source.mm43
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller.h171
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller.mm604
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller_unittest.mm235
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller.h36
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller.mm143
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller_unittest.mm423
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h50
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.mm118
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target_unittest.mm125
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_menu.h (renamed from chrome/browser/cocoa/bookmarks/bookmark_menu.h)0
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_menu.mm22
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h123
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.mm253
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge_unittest.mm317
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.h46
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm96
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller_unittest.mm66
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_menu_unittest.mm29
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa.h116
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa_unittest.mm68
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller.h64
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller.mm123
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller_unittest.mm172
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell.h35
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell.mm23
-rw-r--r--chrome/browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell_unittest.mm43
-rw-r--r--chrome/browser/ui/cocoa/browser_command_executor.h (renamed from chrome/browser/cocoa/browser_command_executor.h)0
-rw-r--r--chrome/browser/ui/cocoa/browser_frame_view.h (renamed from chrome/browser/cocoa/browser_frame_view.h)0
-rw-r--r--chrome/browser/ui/cocoa/browser_frame_view.mm399
-rw-r--r--chrome/browser/ui/cocoa/browser_frame_view_unittest.mm48
-rw-r--r--chrome/browser/ui/cocoa/browser_test_helper.h91
-rw-r--r--chrome/browser/ui/cocoa/browser_window_cocoa.h144
-rw-r--r--chrome/browser/ui/cocoa/browser_window_cocoa.mm644
-rw-r--r--chrome/browser/ui/cocoa/browser_window_cocoa_unittest.mm120
-rw-r--r--chrome/browser/ui/cocoa/browser_window_controller.h397
-rw-r--r--chrome/browser/ui/cocoa/browser_window_controller.mm2088
-rw-r--r--chrome/browser/ui/cocoa/browser_window_controller_private.h119
-rw-r--r--chrome/browser/ui/cocoa/browser_window_controller_private.mm509
-rw-r--r--chrome/browser/ui/cocoa/browser_window_controller_unittest.mm668
-rw-r--r--chrome/browser/ui/cocoa/browser_window_factory.mm32
-rw-r--r--chrome/browser/ui/cocoa/bubble_view.h (renamed from chrome/browser/cocoa/bubble_view.h)0
-rw-r--r--chrome/browser/ui/cocoa/bubble_view.mm120
-rw-r--r--chrome/browser/ui/cocoa/bubble_view_unittest.mm58
-rw-r--r--chrome/browser/ui/cocoa/bug_report_window_controller.h112
-rw-r--r--chrome/browser/ui/cocoa/bug_report_window_controller.mm231
-rw-r--r--chrome/browser/ui/cocoa/bug_report_window_controller_unittest.mm78
-rw-r--r--chrome/browser/ui/cocoa/certificate_viewer.mm (renamed from chrome/browser/cocoa/certificate_viewer.mm)0
-rw-r--r--chrome/browser/ui/cocoa/chrome_browser_window.h28
-rw-r--r--chrome/browser/ui/cocoa/chrome_browser_window.mm52
-rw-r--r--chrome/browser/ui/cocoa/chrome_browser_window_unittest.mm45
-rw-r--r--chrome/browser/ui/cocoa/chrome_event_processing_window.h49
-rw-r--r--chrome/browser/ui/cocoa/chrome_event_processing_window.mm164
-rw-r--r--chrome/browser/ui/cocoa/chrome_event_processing_window_unittest.mm104
-rw-r--r--chrome/browser/ui/cocoa/clear_browsing_data_controller.h87
-rw-r--r--chrome/browser/ui/cocoa/clear_browsing_data_controller.mm267
-rw-r--r--chrome/browser/ui/cocoa/clear_browsing_data_controller_unittest.mm149
-rw-r--r--chrome/browser/ui/cocoa/clickhold_button_cell.h48
-rw-r--r--chrome/browser/ui/cocoa/clickhold_button_cell.mm190
-rw-r--r--chrome/browser/ui/cocoa/clickhold_button_cell_unittest.mm51
-rw-r--r--chrome/browser/ui/cocoa/cocoa_test_helper.h153
-rw-r--r--chrome/browser/ui/cocoa/cocoa_test_helper.mm205
-rw-r--r--chrome/browser/ui/cocoa/collected_cookies_mac.h123
-rw-r--r--chrome/browser/ui/cocoa/collected_cookies_mac.mm500
-rw-r--r--chrome/browser/ui/cocoa/collected_cookies_mac_unittest.mm38
-rw-r--r--chrome/browser/ui/cocoa/command_observer_bridge.h47
-rw-r--r--chrome/browser/ui/cocoa/command_observer_bridge.mm28
-rw-r--r--chrome/browser/ui/cocoa/command_observer_bridge_unittest.mm89
-rw-r--r--chrome/browser/ui/cocoa/confirm_quit_panel_controller.h25
-rw-r--r--chrome/browser/ui/cocoa/confirm_quit_panel_controller.mm85
-rw-r--r--chrome/browser/ui/cocoa/confirm_quit_panel_controller_unittest.mm27
-rw-r--r--chrome/browser/ui/cocoa/constrained_html_delegate_mac.mm153
-rw-r--r--chrome/browser/ui/cocoa/constrained_window_mac.h165
-rw-r--r--chrome/browser/ui/cocoa/constrained_window_mac.mm104
-rw-r--r--chrome/browser/ui/cocoa/content_exceptions_window_controller.h74
-rw-r--r--chrome/browser/ui/cocoa/content_exceptions_window_controller.mm489
-rw-r--r--chrome/browser/ui/cocoa/content_exceptions_window_controller_unittest.mm252
-rw-r--r--chrome/browser/ui/cocoa/content_setting_bubble_cocoa.h67
-rw-r--r--chrome/browser/ui/cocoa/content_setting_bubble_cocoa.mm490
-rw-r--r--chrome/browser/ui/cocoa/content_setting_bubble_cocoa_unittest.mm63
-rw-r--r--chrome/browser/ui/cocoa/content_settings_dialog_controller.h102
-rw-r--r--chrome/browser/ui/cocoa/content_settings_dialog_controller.mm646
-rw-r--r--chrome/browser/ui/cocoa/content_settings_dialog_controller_unittest.mm289
-rw-r--r--chrome/browser/ui/cocoa/cookie_details.h (renamed from chrome/browser/cocoa/cookie_details.h)0
-rw-r--r--chrome/browser/ui/cocoa/cookie_details.mm299
-rw-r--r--chrome/browser/ui/cocoa/cookie_details_unittest.mm247
-rw-r--r--chrome/browser/ui/cocoa/cookie_details_view_controller.h56
-rw-r--r--chrome/browser/ui/cocoa/cookie_details_view_controller.mm110
-rw-r--r--chrome/browser/ui/cocoa/cookie_details_view_controller_unittest.mm88
-rw-r--r--chrome/browser/ui/cocoa/cookie_tree_node.h37
-rw-r--r--chrome/browser/ui/cocoa/cookie_tree_node.mm73
-rw-r--r--chrome/browser/ui/cocoa/cookies_window_controller.h146
-rw-r--r--chrome/browser/ui/cocoa/cookies_window_controller.mm448
-rw-r--r--chrome/browser/ui/cocoa/cookies_window_controller_unittest.mm687
-rw-r--r--chrome/browser/ui/cocoa/custom_home_pages_model.h91
-rw-r--r--chrome/browser/ui/cocoa/custom_home_pages_model.mm140
-rw-r--r--chrome/browser/ui/cocoa/custom_home_pages_model_unittest.mm196
-rw-r--r--chrome/browser/ui/cocoa/delayedmenu_button.h32
-rw-r--r--chrome/browser/ui/cocoa/delayedmenu_button.mm137
-rw-r--r--chrome/browser/ui/cocoa/delayedmenu_button_unittest.mm62
-rw-r--r--chrome/browser/ui/cocoa/dev_tools_controller.h51
-rw-r--r--chrome/browser/ui/cocoa/dev_tools_controller.mm164
-rw-r--r--chrome/browser/ui/cocoa/dock_icon.h (renamed from chrome/browser/cocoa/dock_icon.h)0
-rw-r--r--chrome/browser/ui/cocoa/dock_icon.mm224
-rw-r--r--chrome/browser/ui/cocoa/download/download_item_button.h27
-rw-r--r--chrome/browser/ui/cocoa/download/download_item_button.mm50
-rw-r--r--chrome/browser/ui/cocoa/download/download_item_button_unittest.mm21
-rw-r--r--chrome/browser/ui/cocoa/download/download_item_cell.h61
-rw-r--r--chrome/browser/ui/cocoa/download/download_item_cell.mm708
-rw-r--r--chrome/browser/ui/cocoa/download/download_item_controller.h108
-rw-r--r--chrome/browser/ui/cocoa/download/download_item_controller.mm401
-rw-r--r--chrome/browser/ui/cocoa/download/download_item_mac.h63
-rw-r--r--chrome/browser/ui/cocoa/download/download_item_mac.mm101
-rw-r--r--chrome/browser/ui/cocoa/download/download_shelf_controller.h103
-rw-r--r--chrome/browser/ui/cocoa/download/download_shelf_controller.mm426
-rw-r--r--chrome/browser/ui/cocoa/download/download_shelf_mac.h43
-rw-r--r--chrome/browser/ui/cocoa/download/download_shelf_mac.mm40
-rw-r--r--chrome/browser/ui/cocoa/download/download_shelf_mac_unittest.mm91
-rw-r--r--chrome/browser/ui/cocoa/download/download_shelf_view.h20
-rw-r--r--chrome/browser/ui/cocoa/download/download_shelf_view.mm71
-rw-r--r--chrome/browser/ui/cocoa/download/download_shelf_view_unittest.mm23
-rw-r--r--chrome/browser/ui/cocoa/download/download_started_animation_mac.mm196
-rw-r--r--chrome/browser/ui/cocoa/download/download_util_mac.h25
-rw-r--r--chrome/browser/ui/cocoa/download/download_util_mac.mm83
-rw-r--r--chrome/browser/ui/cocoa/download/download_util_mac_unittest.mm58
-rw-r--r--chrome/browser/ui/cocoa/draggable_button.h (renamed from chrome/browser/cocoa/draggable_button.h)0
-rw-r--r--chrome/browser/ui/cocoa/draggable_button.mm150
-rw-r--r--chrome/browser/ui/cocoa/draggable_button_unittest.mm137
-rw-r--r--chrome/browser/ui/cocoa/edit_search_engine_cocoa_controller.h53
-rw-r--r--chrome/browser/ui/cocoa/edit_search_engine_cocoa_controller.mm187
-rw-r--r--chrome/browser/ui/cocoa/edit_search_engine_cocoa_controller_unittest.mm233
-rw-r--r--chrome/browser/ui/cocoa/encoding_menu_controller_delegate_mac.h24
-rw-r--r--chrome/browser/ui/cocoa/encoding_menu_controller_delegate_mac.mm60
-rw-r--r--chrome/browser/ui/cocoa/event_utils.h30
-rw-r--r--chrome/browser/ui/cocoa/event_utils.mm21
-rw-r--r--chrome/browser/ui/cocoa/event_utils_unittest.mm61
-rw-r--r--chrome/browser/ui/cocoa/extension_install_prompt.mm (renamed from chrome/browser/cocoa/extension_install_prompt.mm)0
-rw-r--r--chrome/browser/ui/cocoa/extension_installed_bubble_bridge.h28
-rw-r--r--chrome/browser/ui/cocoa/extension_installed_bubble_bridge.mm25
-rw-r--r--chrome/browser/ui/cocoa/extension_installed_bubble_controller.h112
-rw-r--r--chrome/browser/ui/cocoa/extension_installed_bubble_controller.mm378
-rw-r--r--chrome/browser/ui/cocoa/extension_installed_bubble_controller_unittest.mm202
-rw-r--r--chrome/browser/ui/cocoa/extension_view_mac.h88
-rw-r--r--chrome/browser/ui/cocoa/extension_view_mac.mm112
-rw-r--r--chrome/browser/ui/cocoa/extensions/browser_action_button.h98
-rw-r--r--chrome/browser/ui/cocoa/extensions/browser_action_button.mm333
-rw-r--r--chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h84
-rw-r--r--chrome/browser/ui/cocoa/extensions/browser_actions_container_view.mm192
-rw-r--r--chrome/browser/ui/cocoa/extensions/browser_actions_container_view_unittest.mm52
-rw-r--r--chrome/browser/ui/cocoa/extensions/browser_actions_controller.h117
-rw-r--r--chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm866
-rw-r--r--chrome/browser/ui/cocoa/extensions/chevron_menu_button.h19
-rw-r--r--chrome/browser/ui/cocoa/extensions/chevron_menu_button.mm15
-rw-r--r--chrome/browser/ui/cocoa/extensions/chevron_menu_button_cell.h19
-rw-r--r--chrome/browser/ui/cocoa/extensions/chevron_menu_button_cell.mm47
-rw-r--r--chrome/browser/ui/cocoa/extensions/chevron_menu_button_unittest.mm50
-rw-r--r--chrome/browser/ui/cocoa/extensions/extension_action_context_menu.h62
-rw-r--r--chrome/browser/ui/cocoa/extensions/extension_action_context_menu.mm278
-rw-r--r--chrome/browser/ui/cocoa/extensions/extension_infobar_controller.h41
-rw-r--r--chrome/browser/ui/cocoa/extensions/extension_infobar_controller.mm266
-rw-r--r--chrome/browser/ui/cocoa/extensions/extension_install_prompt_controller.h62
-rw-r--r--chrome/browser/ui/cocoa/extensions/extension_install_prompt_controller.mm217
-rw-r--r--chrome/browser/ui/cocoa/extensions/extension_install_prompt_controller_unittest.mm286
-rw-r--r--chrome/browser/ui/cocoa/extensions/extension_popup_controller.h99
-rw-r--r--chrome/browser/ui/cocoa/extensions/extension_popup_controller.mm338
-rw-r--r--chrome/browser/ui/cocoa/extensions/extension_popup_controller_unittest.mm99
-rw-r--r--chrome/browser/ui/cocoa/external_protocol_dialog.h (renamed from chrome/browser/cocoa/external_protocol_dialog.h)0
-rw-r--r--chrome/browser/ui/cocoa/external_protocol_dialog.mm153
-rw-r--r--chrome/browser/ui/cocoa/fast_resize_view.h29
-rw-r--r--chrome/browser/ui/cocoa/fast_resize_view.mm65
-rw-r--r--chrome/browser/ui/cocoa/fast_resize_view_unittest.mm60
-rw-r--r--chrome/browser/ui/cocoa/file_metadata.h29
-rw-r--r--chrome/browser/ui/cocoa/file_metadata.mm167
-rw-r--r--chrome/browser/ui/cocoa/find_bar_bridge.h97
-rw-r--r--chrome/browser/ui/cocoa/find_bar_bridge.mm114
-rw-r--r--chrome/browser/ui/cocoa/find_bar_bridge_unittest.mm30
-rw-r--r--chrome/browser/ui/cocoa/find_bar_cocoa_controller.h78
-rw-r--r--chrome/browser/ui/cocoa/find_bar_cocoa_controller.mm384
-rw-r--r--chrome/browser/ui/cocoa/find_bar_cocoa_controller_unittest.mm138
-rw-r--r--chrome/browser/ui/cocoa/find_bar_text_field.h21
-rw-r--r--chrome/browser/ui/cocoa/find_bar_text_field.mm40
-rw-r--r--chrome/browser/ui/cocoa/find_bar_text_field_cell.h24
-rw-r--r--chrome/browser/ui/cocoa/find_bar_text_field_cell.mm119
-rw-r--r--chrome/browser/ui/cocoa/find_bar_text_field_cell_unittest.mm135
-rw-r--r--chrome/browser/ui/cocoa/find_bar_text_field_unittest.mm92
-rw-r--r--chrome/browser/ui/cocoa/find_bar_view.h19
-rw-r--r--chrome/browser/ui/cocoa/find_bar_view.mm131
-rw-r--r--chrome/browser/ui/cocoa/find_bar_view_unittest.mm90
-rw-r--r--chrome/browser/ui/cocoa/find_pasteboard.h58
-rw-r--r--chrome/browser/ui/cocoa/find_pasteboard.mm82
-rw-r--r--chrome/browser/ui/cocoa/find_pasteboard_unittest.mm115
-rw-r--r--chrome/browser/ui/cocoa/first_run_bubble_controller.h24
-rw-r--r--chrome/browser/ui/cocoa/first_run_bubble_controller.mm82
-rw-r--r--chrome/browser/ui/cocoa/first_run_bubble_controller_unittest.mm44
-rw-r--r--chrome/browser/ui/cocoa/first_run_dialog.h (renamed from chrome/browser/cocoa/first_run_dialog.h)0
-rw-r--r--chrome/browser/ui/cocoa/first_run_dialog.mm195
-rw-r--r--chrome/browser/ui/cocoa/floating_bar_backing_view.h15
-rw-r--r--chrome/browser/ui/cocoa/floating_bar_backing_view.mm51
-rw-r--r--chrome/browser/ui/cocoa/floating_bar_backing_view_unittest.mm26
-rw-r--r--chrome/browser/ui/cocoa/focus_tracker.h (renamed from chrome/browser/cocoa/focus_tracker.h)0
-rw-r--r--chrome/browser/ui/cocoa/focus_tracker.mm46
-rw-r--r--chrome/browser/ui/cocoa/focus_tracker_unittest.mm90
-rw-r--r--chrome/browser/ui/cocoa/font_language_settings_controller.h94
-rw-r--r--chrome/browser/ui/cocoa/font_language_settings_controller.mm280
-rw-r--r--chrome/browser/ui/cocoa/font_language_settings_controller_unittest.mm91
-rw-r--r--chrome/browser/ui/cocoa/framed_browser_window.h65
-rw-r--r--chrome/browser/ui/cocoa/framed_browser_window.mm350
-rw-r--r--chrome/browser/ui/cocoa/framed_browser_window_unittest.mm184
-rw-r--r--chrome/browser/ui/cocoa/fullscreen_controller.h122
-rw-r--r--chrome/browser/ui/cocoa/fullscreen_controller.mm633
-rw-r--r--chrome/browser/ui/cocoa/fullscreen_window.h19
-rw-r--r--chrome/browser/ui/cocoa/fullscreen_window.mm100
-rw-r--r--chrome/browser/ui/cocoa/fullscreen_window_unittest.mm47
-rw-r--r--chrome/browser/ui/cocoa/gradient_button_cell.h120
-rw-r--r--chrome/browser/ui/cocoa/gradient_button_cell.mm751
-rw-r--r--chrome/browser/ui/cocoa/gradient_button_cell_unittest.mm112
-rw-r--r--chrome/browser/ui/cocoa/history_menu_bridge.h232
-rw-r--r--chrome/browser/ui/cocoa/history_menu_bridge.mm469
-rw-r--r--chrome/browser/ui/cocoa/history_menu_bridge_unittest.mm386
-rw-r--r--chrome/browser/ui/cocoa/history_menu_cocoa_controller.h32
-rw-r--r--chrome/browser/ui/cocoa/history_menu_cocoa_controller.mm56
-rw-r--r--chrome/browser/ui/cocoa/history_menu_cocoa_controller_unittest.mm91
-rw-r--r--chrome/browser/ui/cocoa/hover_button.h (renamed from chrome/browser/cocoa/hover_button.h)0
-rw-r--r--chrome/browser/ui/cocoa/hover_button.mm97
-rw-r--r--chrome/browser/ui/cocoa/hover_close_button.h26
-rw-r--r--chrome/browser/ui/cocoa/hover_close_button.mm108
-rw-r--r--chrome/browser/ui/cocoa/hover_image_button.h40
-rw-r--r--chrome/browser/ui/cocoa/hover_image_button.mm52
-rw-r--r--chrome/browser/ui/cocoa/hover_image_button_unittest.mm67
-rw-r--r--chrome/browser/ui/cocoa/html_dialog_window_controller.h55
-rw-r--r--chrome/browser/ui/cocoa/html_dialog_window_controller.mm293
-rw-r--r--chrome/browser/ui/cocoa/html_dialog_window_controller_cppsafe.h32
-rw-r--r--chrome/browser/ui/cocoa/html_dialog_window_controller_unittest.mm94
-rw-r--r--chrome/browser/ui/cocoa/hung_renderer_controller.h76
-rw-r--r--chrome/browser/ui/cocoa/hung_renderer_controller.mm203
-rw-r--r--chrome/browser/ui/cocoa/hung_renderer_controller_unittest.mm51
-rw-r--r--chrome/browser/ui/cocoa/hyperlink_button_cell.h (renamed from chrome/browser/cocoa/hyperlink_button_cell.h)0
-rw-r--r--chrome/browser/ui/cocoa/hyperlink_button_cell.mm115
-rw-r--r--chrome/browser/ui/cocoa/hyperlink_button_cell_unittest.mm75
-rw-r--r--chrome/browser/ui/cocoa/image_utils.h26
-rw-r--r--chrome/browser/ui/cocoa/image_utils.mm37
-rw-r--r--chrome/browser/ui/cocoa/image_utils_unittest.mm138
-rw-r--r--chrome/browser/ui/cocoa/import_progress_dialog.h (renamed from chrome/browser/cocoa/import_progress_dialog.h)0
-rw-r--r--chrome/browser/ui/cocoa/import_progress_dialog.mm192
-rw-r--r--chrome/browser/ui/cocoa/import_settings_dialog.h98
-rw-r--r--chrome/browser/ui/cocoa/import_settings_dialog.mm245
-rw-r--r--chrome/browser/ui/cocoa/import_settings_dialog_unittest.mm130
-rw-r--r--chrome/browser/ui/cocoa/importer_lock_dialog.h21
-rw-r--r--chrome/browser/ui/cocoa/importer_lock_dialog.mm (renamed from chrome/browser/cocoa/importer_lock_dialog.mm)0
-rw-r--r--chrome/browser/ui/cocoa/info_bubble_view.h39
-rw-r--r--chrome/browser/ui/cocoa/info_bubble_view.mm72
-rw-r--r--chrome/browser/ui/cocoa/info_bubble_view_unittest.mm26
-rw-r--r--chrome/browser/ui/cocoa/info_bubble_window.h32
-rw-r--r--chrome/browser/ui/cocoa/info_bubble_window.mm222
-rw-r--r--chrome/browser/ui/cocoa/info_bubble_window_unittest.mm22
-rw-r--r--chrome/browser/ui/cocoa/infobar.h48
-rw-r--r--chrome/browser/ui/cocoa/infobar_container_controller.h113
-rw-r--r--chrome/browser/ui/cocoa/infobar_container_controller.mm229
-rw-r--r--chrome/browser/ui/cocoa/infobar_container_controller_unittest.mm95
-rw-r--r--chrome/browser/ui/cocoa/infobar_controller.h106
-rw-r--r--chrome/browser/ui/cocoa/infobar_controller.mm533
-rw-r--r--chrome/browser/ui/cocoa/infobar_controller_unittest.mm284
-rw-r--r--chrome/browser/ui/cocoa/infobar_gradient_view.h19
-rw-r--r--chrome/browser/ui/cocoa/infobar_gradient_view.mm70
-rw-r--r--chrome/browser/ui/cocoa/infobar_gradient_view_unittest.mm32
-rw-r--r--chrome/browser/ui/cocoa/infobar_test_helper.h (renamed from chrome/browser/cocoa/infobar_test_helper.h)0
-rwxr-xr-xchrome/browser/ui/cocoa/install.sh (renamed from chrome/browser/cocoa/install.sh)0
-rw-r--r--chrome/browser/ui/cocoa/install_from_dmg.h15
-rw-r--r--chrome/browser/ui/cocoa/install_from_dmg.mm438
-rw-r--r--chrome/browser/ui/cocoa/instant_confirm_window_controller.h43
-rw-r--r--chrome/browser/ui/cocoa/instant_confirm_window_controller.mm76
-rw-r--r--chrome/browser/ui/cocoa/instant_confirm_window_controller_unittest.mm36
-rw-r--r--chrome/browser/ui/cocoa/js_modal_dialog_cocoa.h48
-rw-r--r--chrome/browser/ui/cocoa/js_modal_dialog_cocoa.mm219
-rw-r--r--chrome/browser/ui/cocoa/keystone_glue.h209
-rw-r--r--chrome/browser/ui/cocoa/keystone_glue.mm957
-rw-r--r--chrome/browser/ui/cocoa/keystone_glue_unittest.mm184
-rw-r--r--chrome/browser/ui/cocoa/keystone_infobar.h24
-rw-r--r--chrome/browser/ui/cocoa/keystone_infobar.mm212
-rwxr-xr-xchrome/browser/ui/cocoa/keystone_promote_postflight.sh55
-rwxr-xr-xchrome/browser/ui/cocoa/keystone_promote_preflight.sh (renamed from chrome/browser/cocoa/keystone_promote_preflight.sh)0
-rw-r--r--chrome/browser/ui/cocoa/keyword_editor_cocoa_controller.h117
-rw-r--r--chrome/browser/ui/cocoa/keyword_editor_cocoa_controller.mm425
-rw-r--r--chrome/browser/ui/cocoa/keyword_editor_cocoa_controller_unittest.mm227
-rw-r--r--chrome/browser/ui/cocoa/l10n_util.h (renamed from chrome/browser/cocoa/l10n_util.h)0
-rw-r--r--chrome/browser/ui/cocoa/l10n_util.mm78
-rw-r--r--chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h147
-rw-r--r--chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm385
-rw-r--r--chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h76
-rw-r--r--chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm402
-rw-r--r--chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm300
-rw-r--r--chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h56
-rw-r--r--chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.mm380
-rw-r--r--chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm297
-rw-r--r--chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm792
-rw-r--r--chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h59
-rw-r--r--chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.mm29
-rw-r--r--chrome/browser/ui/cocoa/location_bar/bubble_decoration.h67
-rw-r--r--chrome/browser/ui/cocoa/location_bar/bubble_decoration.mm158
-rw-r--r--chrome/browser/ui/cocoa/location_bar/content_setting_decoration.h75
-rw-r--r--chrome/browser/ui/cocoa/location_bar/content_setting_decoration.mm376
-rw-r--r--chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration.h59
-rw-r--r--chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration.mm117
-rw-r--r--chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration_unittest.mm55
-rw-r--r--chrome/browser/ui/cocoa/location_bar/image_decoration.h36
-rw-r--r--chrome/browser/ui/cocoa/location_bar/image_decoration.mm54
-rw-r--r--chrome/browser/ui/cocoa/location_bar/image_decoration_unittest.mm55
-rw-r--r--chrome/browser/ui/cocoa/location_bar/instant_opt_in_controller.h43
-rw-r--r--chrome/browser/ui/cocoa/location_bar/instant_opt_in_controller.mm31
-rw-r--r--chrome/browser/ui/cocoa/location_bar/instant_opt_in_controller_unittest.mm62
-rw-r--r--chrome/browser/ui/cocoa/location_bar/instant_opt_in_view.h16
-rw-r--r--chrome/browser/ui/cocoa/location_bar/instant_opt_in_view.mm54
-rw-r--r--chrome/browser/ui/cocoa/location_bar/instant_opt_in_view_unittest.mm26
-rw-r--r--chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.h47
-rw-r--r--chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.mm160
-rw-r--r--chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration_unittest.mm57
-rw-r--r--chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h89
-rw-r--r--chrome/browser/ui/cocoa/location_bar/location_bar_decoration.mm18
-rw-r--r--chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h238
-rw-r--r--chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm695
-rw-r--r--chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h46
-rw-r--r--chrome/browser/ui/cocoa/location_bar/location_icon_decoration.mm72
-rw-r--r--chrome/browser/ui/cocoa/location_bar/omnibox_popup_view.h17
-rw-r--r--chrome/browser/ui/cocoa/location_bar/omnibox_popup_view.mm43
-rw-r--r--chrome/browser/ui/cocoa/location_bar/omnibox_popup_view_unittest.mm68
-rw-r--r--chrome/browser/ui/cocoa/location_bar/page_action_decoration.h119
-rw-r--r--chrome/browser/ui/cocoa/location_bar/page_action_decoration.mm252
-rw-r--r--chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.h42
-rw-r--r--chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.mm73
-rw-r--r--chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration_unittest.mm64
-rw-r--r--chrome/browser/ui/cocoa/location_bar/star_decoration.h44
-rw-r--r--chrome/browser/ui/cocoa/location_bar/star_decoration.mm53
-rw-r--r--chrome/browser/ui/cocoa/menu_button.h32
-rw-r--r--chrome/browser/ui/cocoa/menu_button.mm122
-rw-r--r--chrome/browser/ui/cocoa/menu_button_unittest.mm50
-rw-r--r--chrome/browser/ui/cocoa/menu_controller.h67
-rw-r--r--chrome/browser/ui/cocoa/menu_controller.mm191
-rw-r--r--chrome/browser/ui/cocoa/menu_controller_unittest.mm262
-rw-r--r--chrome/browser/ui/cocoa/menu_tracked_button.h43
-rw-r--r--chrome/browser/ui/cocoa/menu_tracked_button.mm118
-rw-r--r--chrome/browser/ui/cocoa/menu_tracked_button_unittest.mm117
-rw-r--r--chrome/browser/ui/cocoa/menu_tracked_root_view.h25
-rw-r--r--chrome/browser/ui/cocoa/menu_tracked_root_view.mm15
-rw-r--r--chrome/browser/ui/cocoa/menu_tracked_root_view_unittest.mm45
-rw-r--r--chrome/browser/ui/cocoa/multi_key_equivalent_button.h36
-rw-r--r--chrome/browser/ui/cocoa/multi_key_equivalent_button.mm33
-rw-r--r--chrome/browser/ui/cocoa/new_tab_button.h28
-rw-r--r--chrome/browser/ui/cocoa/new_tab_button.mm42
-rw-r--r--chrome/browser/ui/cocoa/notifications/balloon_controller.h98
-rw-r--r--chrome/browser/ui/cocoa/notifications/balloon_controller.mm241
-rw-r--r--chrome/browser/ui/cocoa/notifications/balloon_controller_unittest.mm113
-rw-r--r--chrome/browser/ui/cocoa/notifications/balloon_view.h28
-rw-r--r--chrome/browser/ui/cocoa/notifications/balloon_view.mm84
-rw-r--r--chrome/browser/ui/cocoa/notifications/balloon_view_bridge.h40
-rw-r--r--chrome/browser/ui/cocoa/notifications/balloon_view_bridge.mm48
-rw-r--r--chrome/browser/ui/cocoa/notifications/balloon_view_host_mac.h42
-rw-r--r--chrome/browser/ui/cocoa/notifications/balloon_view_host_mac.mm39
-rw-r--r--chrome/browser/ui/cocoa/nsimage_cache_unittest.mm77
-rw-r--r--chrome/browser/ui/cocoa/nsmenuitem_additions.h24
-rw-r--r--chrome/browser/ui/cocoa/nsmenuitem_additions.mm106
-rw-r--r--chrome/browser/ui/cocoa/nsmenuitem_additions_unittest.mm351
-rw-r--r--chrome/browser/ui/cocoa/nswindow_additions.h25
-rw-r--r--chrome/browser/ui/cocoa/nswindow_additions.mm104
-rw-r--r--chrome/browser/ui/cocoa/objc_method_swizzle.h28
-rw-r--r--chrome/browser/ui/cocoa/objc_method_swizzle.mm59
-rw-r--r--chrome/browser/ui/cocoa/objc_method_swizzle_unittest.mm76
-rw-r--r--chrome/browser/ui/cocoa/objc_zombie.h39
-rw-r--r--chrome/browser/ui/cocoa/objc_zombie.mm414
-rw-r--r--chrome/browser/ui/cocoa/page_info_bubble_controller.h47
-rw-r--r--chrome/browser/ui/cocoa/page_info_bubble_controller.mm461
-rw-r--r--chrome/browser/ui/cocoa/page_info_bubble_controller_unittest.mm210
-rw-r--r--chrome/browser/ui/cocoa/preferences_window_controller.h240
-rw-r--r--chrome/browser/ui/cocoa/preferences_window_controller.mm2171
-rw-r--r--chrome/browser/ui/cocoa/preferences_window_controller_unittest.mm240
-rw-r--r--chrome/browser/ui/cocoa/previewable_contents_controller.h47
-rw-r--r--chrome/browser/ui/cocoa/previewable_contents_controller.mm52
-rw-r--r--chrome/browser/ui/cocoa/previewable_contents_controller_unittest.mm34
-rw-r--r--chrome/browser/ui/cocoa/reload_button.h50
-rw-r--r--chrome/browser/ui/cocoa/reload_button.mm168
-rw-r--r--chrome/browser/ui/cocoa/reload_button_unittest.mm259
-rw-r--r--chrome/browser/ui/cocoa/repost_form_warning_mac.h40
-rw-r--r--chrome/browser/ui/cocoa/repost_form_warning_mac.mm82
-rw-r--r--chrome/browser/ui/cocoa/restart_browser.h22
-rw-r--r--chrome/browser/ui/cocoa/restart_browser.mm86
-rw-r--r--chrome/browser/ui/cocoa/rwhvm_editcommand_helper.h72
-rw-r--r--chrome/browser/ui/cocoa/rwhvm_editcommand_helper.mm227
-rw-r--r--chrome/browser/ui/cocoa/rwhvm_editcommand_helper_unittest.mm172
-rw-r--r--chrome/browser/ui/cocoa/sad_tab_controller.h33
-rw-r--r--chrome/browser/ui/cocoa/sad_tab_controller.mm48
-rw-r--r--chrome/browser/ui/cocoa/sad_tab_controller_unittest.mm113
-rw-r--r--chrome/browser/ui/cocoa/sad_tab_view.h36
-rw-r--r--chrome/browser/ui/cocoa/sad_tab_view.mm127
-rw-r--r--chrome/browser/ui/cocoa/sad_tab_view_unittest.mm25
-rw-r--r--chrome/browser/ui/cocoa/scoped_authorizationref.h80
-rw-r--r--chrome/browser/ui/cocoa/search_engine_dialog_controller.h (renamed from chrome/browser/cocoa/search_engine_dialog_controller.h)0
-rw-r--r--chrome/browser/ui/cocoa/search_engine_dialog_controller.mm284
-rw-r--r--chrome/browser/ui/cocoa/search_engine_list_model.h48
-rw-r--r--chrome/browser/ui/cocoa/search_engine_list_model.mm136
-rw-r--r--chrome/browser/ui/cocoa/search_engine_list_model_unittest.mm152
-rw-r--r--chrome/browser/ui/cocoa/shell_dialogs_mac.mm417
-rw-r--r--chrome/browser/ui/cocoa/side_tab_strip_controller.h19
-rw-r--r--chrome/browser/ui/cocoa/side_tab_strip_controller.mm33
-rw-r--r--chrome/browser/ui/cocoa/side_tab_strip_view.h15
-rw-r--r--chrome/browser/ui/cocoa/side_tab_strip_view.mm43
-rw-r--r--chrome/browser/ui/cocoa/side_tab_strip_view_unittest.mm30
-rw-r--r--chrome/browser/ui/cocoa/sidebar_controller.h51
-rw-r--r--chrome/browser/ui/cocoa/sidebar_controller.mm179
-rw-r--r--chrome/browser/ui/cocoa/simple_content_exceptions_window_controller.h38
-rw-r--r--chrome/browser/ui/cocoa/simple_content_exceptions_window_controller.mm125
-rw-r--r--chrome/browser/ui/cocoa/simple_content_exceptions_window_controller_unittest.mm94
-rw-r--r--chrome/browser/ui/cocoa/speech_input_window_controller.h57
-rw-r--r--chrome/browser/ui/cocoa/speech_input_window_controller.mm188
-rw-r--r--chrome/browser/ui/cocoa/ssl_client_certificate_selector.mm195
-rw-r--r--chrome/browser/ui/cocoa/status_bubble_mac.h172
-rw-r--r--chrome/browser/ui/cocoa/status_bubble_mac.mm705
-rw-r--r--chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm584
-rw-r--r--chrome/browser/ui/cocoa/status_icons/status_icon_mac.h44
-rw-r--r--chrome/browser/ui/cocoa/status_icons/status_icon_mac.mm82
-rw-r--r--chrome/browser/ui/cocoa/status_icons/status_icon_mac_unittest.mm30
-rw-r--r--chrome/browser/ui/cocoa/status_icons/status_tray_mac.h24
-rw-r--r--chrome/browser/ui/cocoa/status_icons/status_tray_mac.mm18
-rw-r--r--chrome/browser/ui/cocoa/styled_text_field.h (renamed from chrome/browser/cocoa/styled_text_field.h)0
-rw-r--r--chrome/browser/ui/cocoa/styled_text_field.mm61
-rw-r--r--chrome/browser/ui/cocoa/styled_text_field_cell.h58
-rw-r--r--chrome/browser/ui/cocoa/styled_text_field_cell.mm217
-rw-r--r--chrome/browser/ui/cocoa/styled_text_field_cell_unittest.mm93
-rw-r--r--chrome/browser/ui/cocoa/styled_text_field_test_helper.h16
-rw-r--r--chrome/browser/ui/cocoa/styled_text_field_test_helper.mm18
-rw-r--r--chrome/browser/ui/cocoa/styled_text_field_unittest.mm198
-rw-r--r--chrome/browser/ui/cocoa/tab_contents_controller.h75
-rw-r--r--chrome/browser/ui/cocoa/tab_contents_controller.mm212
-rw-r--r--chrome/browser/ui/cocoa/tab_controller.h115
-rw-r--r--chrome/browser/ui/cocoa/tab_controller.mm306
-rw-r--r--chrome/browser/ui/cocoa/tab_controller_target.h27
-rw-r--r--chrome/browser/ui/cocoa/tab_controller_unittest.mm333
-rw-r--r--chrome/browser/ui/cocoa/tab_strip_controller.h262
-rw-r--r--chrome/browser/ui/cocoa/tab_strip_controller.mm1905
-rw-r--r--chrome/browser/ui/cocoa/tab_strip_controller_unittest.mm177
-rw-r--r--chrome/browser/ui/cocoa/tab_strip_model_observer_bridge.h85
-rw-r--r--chrome/browser/ui/cocoa/tab_strip_model_observer_bridge.mm118
-rw-r--r--chrome/browser/ui/cocoa/tab_strip_view.h48
-rw-r--r--chrome/browser/ui/cocoa/tab_strip_view.mm211
-rw-r--r--chrome/browser/ui/cocoa/tab_strip_view_unittest.mm30
-rw-r--r--chrome/browser/ui/cocoa/tab_view.h134
-rw-r--r--chrome/browser/ui/cocoa/tab_view.mm1056
-rw-r--r--chrome/browser/ui/cocoa/tab_view_picker_table.h29
-rw-r--r--chrome/browser/ui/cocoa/tab_view_picker_table.mm (renamed from chrome/browser/cocoa/tab_view_picker_table.mm)0
-rw-r--r--chrome/browser/ui/cocoa/tab_view_picker_table_unittest.mm138
-rw-r--r--chrome/browser/ui/cocoa/tab_view_unittest.mm60
-rw-r--r--chrome/browser/ui/cocoa/tab_window_controller.h180
-rw-r--r--chrome/browser/ui/cocoa/tab_window_controller.mm356
-rw-r--r--chrome/browser/ui/cocoa/table_model_array_controller.h54
-rw-r--r--chrome/browser/ui/cocoa/table_model_array_controller.mm246
-rw-r--r--chrome/browser/ui/cocoa/table_model_array_controller_unittest.mm171
-rw-r--r--chrome/browser/ui/cocoa/table_row_nsimage_cache.h55
-rw-r--r--chrome/browser/ui/cocoa/table_row_nsimage_cache.mm79
-rw-r--r--chrome/browser/ui/cocoa/table_row_nsimage_cache_unittest.mm200
-rw-r--r--chrome/browser/ui/cocoa/tabpose_window.h94
-rw-r--r--chrome/browser/ui/cocoa/tabpose_window.mm1554
-rw-r--r--chrome/browser/ui/cocoa/tabpose_window_unittest.mm119
-rw-r--r--chrome/browser/ui/cocoa/task_helpers.h29
-rw-r--r--chrome/browser/ui/cocoa/task_helpers.mm57
-rw-r--r--chrome/browser/ui/cocoa/task_manager_mac.h118
-rw-r--r--chrome/browser/ui/cocoa/task_manager_mac.mm582
-rw-r--r--chrome/browser/ui/cocoa/task_manager_mac_unittest.mm115
-rw-r--r--chrome/browser/ui/cocoa/test_event_utils.h48
-rw-r--r--chrome/browser/ui/cocoa/test_event_utils.mm86
-rw-r--r--chrome/browser/ui/cocoa/theme_install_bubble_view.h62
-rw-r--r--chrome/browser/ui/cocoa/theme_install_bubble_view.mm187
-rw-r--r--chrome/browser/ui/cocoa/themed_window.h30
-rw-r--r--chrome/browser/ui/cocoa/themed_window.mm23
-rw-r--r--chrome/browser/ui/cocoa/throbber_view.h42
-rw-r--r--chrome/browser/ui/cocoa/throbber_view.mm372
-rw-r--r--chrome/browser/ui/cocoa/throbber_view_unittest.mm32
-rw-r--r--chrome/browser/ui/cocoa/toolbar_controller.h189
-rw-r--r--chrome/browser/ui/cocoa/toolbar_controller.mm806
-rw-r--r--chrome/browser/ui/cocoa/toolbar_controller_unittest.mm237
-rw-r--r--chrome/browser/ui/cocoa/toolbar_view.h26
-rw-r--r--chrome/browser/ui/cocoa/toolbar_view.mm47
-rw-r--r--chrome/browser/ui/cocoa/toolbar_view_unittest.mm23
-rw-r--r--chrome/browser/ui/cocoa/translate/after_translate_infobar_controller.h11
-rw-r--r--chrome/browser/ui/cocoa/translate/after_translate_infobar_controller.mm60
-rw-r--r--chrome/browser/ui/cocoa/translate/before_translate_infobar_controller.h23
-rw-r--r--chrome/browser/ui/cocoa/translate/before_translate_infobar_controller.mm123
-rw-r--r--chrome/browser/ui/cocoa/translate/translate_infobar_base.h163
-rw-r--r--chrome/browser/ui/cocoa/translate/translate_infobar_base.mm642
-rw-r--r--chrome/browser/ui/cocoa/translate/translate_infobar_unittest.mm254
-rw-r--r--chrome/browser/ui/cocoa/translate/translate_message_infobar_controller.h10
-rw-r--r--chrome/browser/ui/cocoa/translate/translate_message_infobar_controller.mm53
-rw-r--r--chrome/browser/ui/cocoa/ui_localizer.h35
-rw-r--r--chrome/browser/ui/cocoa/ui_localizer.mm98
-rw-r--r--chrome/browser/ui/cocoa/url_drop_target.h75
-rw-r--r--chrome/browser/ui/cocoa/url_drop_target.mm109
-rw-r--r--chrome/browser/ui/cocoa/vertical_gradient_view.h36
-rw-r--r--chrome/browser/ui/cocoa/vertical_gradient_view.mm39
-rw-r--r--chrome/browser/ui/cocoa/vertical_gradient_view_unittest.mm27
-rw-r--r--chrome/browser/ui/cocoa/view_id_util.h52
-rw-r--r--chrome/browser/ui/cocoa/view_id_util.mm89
-rw-r--r--chrome/browser/ui/cocoa/view_id_util_browsertest.mm118
-rw-r--r--chrome/browser/ui/cocoa/view_resizer.h28
-rw-r--r--chrome/browser/ui/cocoa/view_resizer_pong.h22
-rw-r--r--chrome/browser/ui/cocoa/view_resizer_pong.mm20
-rw-r--r--chrome/browser/ui/cocoa/web_contents_drag_source.h62
-rw-r--r--chrome/browser/ui/cocoa/web_contents_drag_source.mm130
-rw-r--r--chrome/browser/ui/cocoa/web_drag_source.h (renamed from chrome/browser/cocoa/web_drag_source.h)0
-rw-r--r--chrome/browser/ui/cocoa/web_drag_source.mm412
-rw-r--r--chrome/browser/ui/cocoa/web_drop_target.h (renamed from chrome/browser/cocoa/web_drop_target.h)0
-rw-r--r--chrome/browser/ui/cocoa/web_drop_target.mm283
-rw-r--r--chrome/browser/ui/cocoa/web_drop_target_unittest.mm166
-rw-r--r--chrome/browser/ui/cocoa/window_size_autosaver.h35
-rw-r--r--chrome/browser/ui/cocoa/window_size_autosaver.mm108
-rw-r--r--chrome/browser/ui/cocoa/window_size_autosaver_unittest.mm201
-rw-r--r--chrome/browser/ui/cocoa/wrench_menu_button_cell.h19
-rw-r--r--chrome/browser/ui/cocoa/wrench_menu_button_cell.mm48
-rw-r--r--chrome/browser/ui/cocoa/wrench_menu_button_cell_unittest.mm51
-rw-r--r--chrome/browser/ui/cocoa/wrench_menu_controller.h72
-rw-r--r--chrome/browser/ui/cocoa/wrench_menu_controller.mm220
-rw-r--r--chrome/browser/ui/cocoa/wrench_menu_controller_unittest.mm84
-rw-r--r--chrome/browser/ui/find_bar/find_backend_unittest.cc76
-rw-r--r--chrome/browser/ui/find_bar/find_bar.h101
-rw-r--r--chrome/browser/ui/find_bar/find_bar_controller.cc228
-rw-r--r--chrome/browser/ui/find_bar/find_bar_controller.h89
-rw-r--r--chrome/browser/ui/find_bar/find_bar_host_browsertest.cc1084
-rw-r--r--chrome/browser/ui/find_bar/find_bar_state.cc20
-rw-r--r--chrome/browser/ui/find_bar/find_bar_state.h41
-rw-r--r--chrome/browser/ui/find_bar/find_notification_details.h51
-rw-r--r--chrome/browser/ui/input_window_dialog.h53
-rw-r--r--chrome/browser/ui/input_window_dialog_gtk.cc146
-rw-r--r--chrome/browser/ui/input_window_dialog_win.cc235
-rw-r--r--chrome/browser/ui/login/login_model.h35
-rw-r--r--chrome/browser/ui/login/login_prompt.cc453
-rw-r--r--chrome/browser/ui/login/login_prompt.h214
-rw-r--r--chrome/browser/ui/login/login_prompt_gtk.cc198
-rw-r--r--chrome/browser/ui/login/login_prompt_mac.h34
-rw-r--r--chrome/browser/ui/login/login_prompt_mac.mm190
-rw-r--r--chrome/browser/ui/login/login_prompt_uitest.cc (renamed from chrome/browser/login_prompt_uitest.cc)0
-rw-r--r--chrome/browser/ui/login/login_prompt_unittest.cc42
-rw-r--r--chrome/browser/ui/login/login_prompt_win.cc146
-rw-r--r--chrome/browser/ui/omnibox/location_bar.h106
-rw-r--r--chrome/browser/ui/omnibox/location_bar_util.cc44
-rw-r--r--chrome/browser/ui/omnibox/location_bar_util.h24
-rw-r--r--chrome/browser/ui/options/options_page_base.cc38
-rw-r--r--chrome/browser/ui/options/options_page_base.h62
-rw-r--r--chrome/browser/ui/options/options_util.cc134
-rw-r--r--chrome/browser/ui/options/options_util.h28
-rw-r--r--chrome/browser/ui/options/options_window.h40
-rw-r--r--chrome/browser/ui/options/show_options_url.cc21
-rw-r--r--chrome/browser/ui/options/show_options_url.h20
-rw-r--r--chrome/browser/ui/status_bubble.h (renamed from chrome/browser/status_bubble.h)0
-rw-r--r--chrome/browser/ui/tab_contents/tab_contents_wrapper.cc66
-rw-r--r--chrome/browser/ui/tab_contents/tab_contents_wrapper.h79
-rw-r--r--chrome/browser/ui/tabs/dock_info.cc268
-rw-r--r--chrome/browser/ui/tabs/dock_info.h190
-rw-r--r--chrome/browser/ui/tabs/dock_info_gtk.cc219
-rw-r--r--chrome/browser/ui/tabs/dock_info_mac.cc15
-rw-r--r--chrome/browser/ui/tabs/dock_info_unittest.cc191
-rw-r--r--chrome/browser/ui/tabs/dock_info_win.cc325
-rw-r--r--chrome/browser/ui/tabs/tab_menu_model.cc54
-rw-r--r--chrome/browser/ui/tabs/tab_menu_model.h29
-rw-r--r--chrome/browser/ui/tabs/tab_menu_model_unittest.cc26
-rw-r--r--chrome/browser/ui/tests/browser_uitest.cc (renamed from chrome/browser/browser_uitest.cc)0
-rw-r--r--chrome/browser/ui/toolbar/back_forward_menu_model.cc379
-rw-r--r--chrome/browser/ui/toolbar/back_forward_menu_model.h171
-rw-r--r--chrome/browser/ui/toolbar/back_forward_menu_model_unittest.cc422
-rw-r--r--chrome/browser/ui/toolbar/encoding_menu_controller.cc141
-rw-r--r--chrome/browser/ui/toolbar/encoding_menu_controller.h56
-rw-r--r--chrome/browser/ui/toolbar/encoding_menu_controller_unittest.cc93
-rw-r--r--chrome/browser/ui/toolbar/toolbar_model.cc129
-rw-r--r--chrome/browser/ui/toolbar/toolbar_model.h71
-rw-r--r--chrome/browser/ui/toolbar/wrench_menu_model.cc536
-rw-r--r--chrome/browser/ui/toolbar/wrench_menu_model.h150
-rw-r--r--chrome/browser/ui/toolbar/wrench_menu_model_unittest.cc105
-rw-r--r--chrome/browser/ui/touch/frame/browser_non_client_frame_view_factory_touch.cc23
-rw-r--r--chrome/browser/ui/touch/frame/touch_browser_frame_view.cc131
-rw-r--r--chrome/browser/ui/touch/frame/touch_browser_frame_view.h49
-rw-r--r--chrome/browser/ui/view_ids.h (renamed from chrome/browser/view_ids.h)0
-rw-r--r--chrome/browser/ui/views/about_chrome_view.cc39
-rw-r--r--chrome/browser/ui/views/about_chrome_view.h4
-rw-r--r--chrome/browser/ui/views/about_ipc_dialog.cc162
-rw-r--r--chrome/browser/ui/views/accelerator_table_gtk.cc3
-rw-r--r--chrome/browser/ui/views/accessibility_event_router_views.cc4
-rw-r--r--chrome/browser/ui/views/accessible_pane_view.cc10
-rw-r--r--chrome/browser/ui/views/accessible_view_helper.cc2
-rw-r--r--chrome/browser/ui/views/autocomplete/autocomplete_popup_contents_view.cc5
-rw-r--r--chrome/browser/ui/views/autofill_profiles_view_win.cc10
-rw-r--r--chrome/browser/ui/views/bookmark_bar_view.cc13
-rw-r--r--chrome/browser/ui/views/bookmark_bar_view_test.cc5
-rw-r--r--chrome/browser/ui/views/bookmark_bubble_view.cc2
-rw-r--r--chrome/browser/ui/views/bookmark_context_menu.cc13
-rw-r--r--chrome/browser/ui/views/bookmark_context_menu.h3
-rw-r--r--chrome/browser/ui/views/bookmark_context_menu_controller_views.cc100
-rw-r--r--chrome/browser/ui/views/bookmark_context_menu_controller_views.h3
-rw-r--r--chrome/browser/ui/views/bookmark_context_menu_test.cc114
-rw-r--r--chrome/browser/ui/views/bookmark_editor_view.cc2
-rw-r--r--chrome/browser/ui/views/bookmark_editor_view_unittest.cc2
-rw-r--r--chrome/browser/ui/views/bookmark_menu_controller_views.cc2
-rw-r--r--chrome/browser/ui/views/browser_actions_container.cc26
-rw-r--r--chrome/browser/ui/views/browser_actions_container_browsertest.cc8
-rw-r--r--chrome/browser/ui/views/browser_bubble_gtk.cc18
-rw-r--r--chrome/browser/ui/views/chrome_views_delegate.cc4
-rw-r--r--chrome/browser/ui/views/clear_browsing_data.cc8
-rw-r--r--chrome/browser/ui/views/clear_browsing_data_view.cc2
-rw-r--r--chrome/browser/ui/views/clear_data_view.cc2
-rw-r--r--chrome/browser/ui/views/clear_server_data.cc2
-rw-r--r--chrome/browser/ui/views/collected_cookies_win.cc9
-rw-r--r--chrome/browser/ui/views/constrained_html_delegate_gtk.cc2
-rw-r--r--chrome/browser/ui/views/constrained_html_delegate_win.cc2
-rw-r--r--chrome/browser/ui/views/constrained_window_win.cc9
-rw-r--r--chrome/browser/ui/views/content_setting_bubble_contents.cc130
-rw-r--r--chrome/browser/ui/views/content_setting_bubble_contents.h6
-rw-r--r--chrome/browser/ui/views/cookie_info_view.cc2
-rw-r--r--chrome/browser/ui/views/create_application_shortcut_view.cc2
-rw-r--r--chrome/browser/ui/views/default_search_view.cc2
-rw-r--r--chrome/browser/ui/views/dialog_stubs_gtk.cc4
-rw-r--r--chrome/browser/ui/views/dom_view.cc16
-rw-r--r--chrome/browser/ui/views/dom_view.h5
-rw-r--r--chrome/browser/ui/views/download_item_view.cc6
-rw-r--r--chrome/browser/ui/views/download_shelf_view.cc6
-rw-r--r--chrome/browser/ui/views/download_started_animation_win.cc3
-rw-r--r--chrome/browser/ui/views/dropdown_bar_host.cc9
-rw-r--r--chrome/browser/ui/views/dropdown_bar_host.h4
-rw-r--r--chrome/browser/ui/views/dropdown_bar_host_gtk.cc21
-rw-r--r--chrome/browser/ui/views/dropdown_bar_host_win.cc2
-rw-r--r--chrome/browser/ui/views/extensions/browser_action_drag_data.cc2
-rw-r--r--chrome/browser/ui/views/extensions/browser_action_drag_data.h3
-rw-r--r--chrome/browser/ui/views/extensions/browser_action_overflow_menu_controller.cc3
-rw-r--r--chrome/browser/ui/views/extensions/extension_installed_bubble.cc13
-rw-r--r--chrome/browser/ui/views/extensions/extension_popup.cc28
-rw-r--r--chrome/browser/ui/views/external_protocol_dialog.cc8
-rw-r--r--chrome/browser/ui/views/find_bar_host.cc25
-rw-r--r--chrome/browser/ui/views/find_bar_host.h4
-rw-r--r--chrome/browser/ui/views/find_bar_host_gtk.cc2
-rw-r--r--chrome/browser/ui/views/find_bar_host_interactive_uitest.cc84
-rw-r--r--chrome/browser/ui/views/find_bar_host_win.cc2
-rw-r--r--chrome/browser/ui/views/find_bar_view.cc40
-rw-r--r--chrome/browser/ui/views/find_bar_view.h28
-rw-r--r--chrome/browser/ui/views/first_run_search_engine_view.cc4
-rw-r--r--chrome/browser/ui/views/frame/browser_frame_gtk.cc23
-rw-r--r--chrome/browser/ui/views/frame/browser_frame_win.cc14
-rw-r--r--chrome/browser/ui/views/frame/browser_non_client_frame_view.h10
-rw-r--r--chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_gtk.cc21
-rw-r--r--chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_win.cc21
-rw-r--r--chrome/browser/ui/views/frame/browser_root_view.cc10
-rw-r--r--chrome/browser/ui/views/frame/browser_view.cc101
-rw-r--r--chrome/browser/ui/views/frame/browser_view.h6
-rw-r--r--chrome/browser/ui/views/frame/browser_view_layout.cc22
-rw-r--r--chrome/browser/ui/views/frame/opaque_browser_frame_view.cc19
-rw-r--r--chrome/browser/ui/views/frame/opaque_browser_frame_view.h7
-rw-r--r--chrome/browser/ui/views/html_dialog_view_browsertest.cc11
-rw-r--r--chrome/browser/ui/views/importer_view.cc35
-rw-r--r--chrome/browser/ui/views/importer_view.h16
-rw-r--r--chrome/browser/ui/views/info_bubble.cc33
-rw-r--r--chrome/browser/ui/views/info_bubble.h18
-rw-r--r--chrome/browser/ui/views/infobars/infobar_container.cc7
-rw-r--r--chrome/browser/ui/views/instant_confirm_view.cc2
-rw-r--r--chrome/browser/ui/views/js_modal_dialog_views.cc2
-rw-r--r--chrome/browser/ui/views/js_modal_dialog_views.h4
-rw-r--r--chrome/browser/ui/views/keyboard_overlay_delegate.cc70
-rw-r--r--chrome/browser/ui/views/keyboard_overlay_delegate.h39
-rw-r--r--chrome/browser/ui/views/keyword_editor_view.cc2
-rw-r--r--chrome/browser/ui/views/location_bar/click_handler.cc4
-rw-r--r--chrome/browser/ui/views/location_bar/content_setting_image_view.cc6
-rw-r--r--chrome/browser/ui/views/location_bar/keyword_hint_view.cc2
-rw-r--r--chrome/browser/ui/views/location_bar/location_bar_view.cc94
-rw-r--r--chrome/browser/ui/views/location_bar/location_bar_view.h22
-rw-r--r--chrome/browser/ui/views/location_bar/page_action_image_view.cc8
-rw-r--r--chrome/browser/ui/views/location_bar/selected_keyword_view.cc6
-rw-r--r--chrome/browser/ui/views/location_bar/star_view.cc4
-rw-r--r--chrome/browser/ui/views/login_view.h2
-rw-r--r--chrome/browser/ui/views/modal_dialog_delegate.cc40
-rw-r--r--chrome/browser/ui/views/modal_dialog_delegate.h31
-rw-r--r--chrome/browser/ui/views/notifications/balloon_view.cc9
-rw-r--r--chrome/browser/ui/views/notifications/balloon_view.h13
-rw-r--r--chrome/browser/ui/views/notifications/balloon_view_host.cc8
-rw-r--r--chrome/browser/ui/views/notifications/balloon_view_host.h4
-rw-r--r--chrome/browser/ui/views/options/advanced_contents_view.cc38
-rw-r--r--chrome/browser/ui/views/options/advanced_page_view.cc8
-rw-r--r--chrome/browser/ui/views/options/content_filter_page_view.cc25
-rw-r--r--chrome/browser/ui/views/options/content_filter_page_view.h4
-rw-r--r--chrome/browser/ui/views/options/content_page_view.cc3
-rw-r--r--chrome/browser/ui/views/options/content_settings_window_view.cc3
-rw-r--r--chrome/browser/ui/views/options/cookie_filter_page_view.cc8
-rw-r--r--chrome/browser/ui/views/options/cookies_view.cc2
-rw-r--r--chrome/browser/ui/views/options/exception_editor_view.cc12
-rw-r--r--chrome/browser/ui/views/options/exception_editor_view.h10
-rw-r--r--chrome/browser/ui/views/options/exceptions_page_view.cc2
-rw-r--r--chrome/browser/ui/views/options/exceptions_view.cc4
-rw-r--r--chrome/browser/ui/views/options/exceptions_view.h2
-rw-r--r--chrome/browser/ui/views/options/fonts_languages_window_view.cc2
-rw-r--r--chrome/browser/ui/views/options/fonts_page_view.cc2
-rw-r--r--chrome/browser/ui/views/options/general_page_view.cc10
-rw-r--r--chrome/browser/ui/views/options/languages_page_view.cc2
-rw-r--r--chrome/browser/ui/views/options/options_page_view.cc3
-rw-r--r--chrome/browser/ui/views/options/options_page_view.h2
-rw-r--r--chrome/browser/ui/views/options/options_window_view.cc17
-rw-r--r--chrome/browser/ui/views/options/passwords_page_view.cc2
-rw-r--r--chrome/browser/ui/views/options/passwords_page_view.h2
-rw-r--r--chrome/browser/ui/views/options/plugin_filter_page_view.cc2
-rw-r--r--chrome/browser/ui/views/page_info_bubble_view.cc2
-rw-r--r--chrome/browser/ui/views/repost_form_warning_view.cc1
-rw-r--r--chrome/browser/ui/views/select_file_dialog.cc2
-rw-r--r--chrome/browser/ui/views/ssl_client_certificate_selector_win.cc1
-rw-r--r--chrome/browser/ui/views/status_bubble_views.h2
-rw-r--r--chrome/browser/ui/views/tab_contents/native_tab_contents_container_gtk.cc4
-rw-r--r--chrome/browser/ui/views/tab_contents/native_tab_contents_container_win.cc6
-rw-r--r--chrome/browser/ui/views/tab_contents/render_view_context_menu_views.cc3
-rw-r--r--chrome/browser/ui/views/tab_contents/tab_contents_container.cc12
-rw-r--r--chrome/browser/ui/views/tab_contents/tab_contents_drag_win.cc1
-rw-r--r--chrome/browser/ui/views/tab_contents/tab_contents_view_gtk.cc52
-rw-r--r--chrome/browser/ui/views/tab_contents/tab_contents_view_views.cc47
-rw-r--r--chrome/browser/ui/views/tab_contents/tab_contents_view_views.h5
-rw-r--r--chrome/browser/ui/views/tab_contents/tab_contents_view_win.cc9
-rw-r--r--chrome/browser/ui/views/tab_icon_view.cc1
-rw-r--r--chrome/browser/ui/views/tabs/base_tab.cc6
-rw-r--r--chrome/browser/ui/views/tabs/base_tab_strip.cc15
-rw-r--r--chrome/browser/ui/views/tabs/base_tab_strip.h3
-rw-r--r--chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc10
-rw-r--r--chrome/browser/ui/views/tabs/dragged_tab_controller.cc7
-rw-r--r--chrome/browser/ui/views/tabs/dragged_tab_controller.h4
-rw-r--r--chrome/browser/ui/views/tabs/side_tab_strip.cc6
-rw-r--r--chrome/browser/ui/views/tabs/tab.cc68
-rw-r--r--chrome/browser/ui/views/tabs/tab.h6
-rw-r--r--chrome/browser/ui/views/tabs/tab_dragging_test.cc2
-rw-r--r--chrome/browser/ui/views/tabs/tab_strip.cc6
-rw-r--r--chrome/browser/ui/views/task_manager_view.cc4
-rw-r--r--chrome/browser/ui/views/theme_background.cc2
-rw-r--r--chrome/browser/ui/views/theme_install_bubble_view.cc4
-rw-r--r--chrome/browser/ui/views/theme_install_bubble_view.h2
-rw-r--r--chrome/browser/ui/views/toolbar_view.cc26
-rw-r--r--chrome/browser/ui/views/toolbar_view.h8
-rw-r--r--chrome/browser/ui/views/uninstall_view.cc5
-rw-r--r--chrome/browser/ui/views/url_picker.cc3
-rw-r--r--chrome/browser/ui/views/wrench_menu.cc33
-rw-r--r--chrome/browser/ui/window_sizer.cc336
-rw-r--r--chrome/browser/ui/window_sizer.h184
-rw-r--r--chrome/browser/ui/window_sizer_linux.cc131
-rw-r--r--chrome/browser/ui/window_sizer_mac.mm144
-rw-r--r--chrome/browser/ui/window_sizer_unittest.cc1002
-rw-r--r--chrome/browser/ui/window_sizer_win.cc108
-rw-r--r--chrome/browser/unload_uitest.cc2
-rw-r--r--chrome/browser/upgrade_detector.cc28
-rw-r--r--chrome/browser/upgrade_detector.h8
-rw-r--r--chrome/browser/user_style_sheet_watcher.h2
-rw-r--r--chrome/browser/utility_process_host.cc16
-rw-r--r--chrome/browser/utility_process_host.h16
-rw-r--r--chrome/browser/visitedlink/visitedlink_event_listener.cc65
-rw-r--r--chrome/browser/visitedlink/visitedlink_event_listener.h38
-rw-r--r--chrome/browser/visitedlink/visitedlink_master.cc1001
-rw-r--r--chrome/browser/visitedlink/visitedlink_master.h388
-rw-r--r--chrome/browser/visitedlink/visitedlink_perftest.cc207
-rw-r--r--chrome/browser/visitedlink/visitedlink_unittest.cc774
-rw-r--r--chrome/browser/visitedlink_event_listener.cc65
-rw-r--r--chrome/browser/visitedlink_event_listener.h38
-rw-r--r--chrome/browser/visitedlink_master.cc1002
-rw-r--r--chrome/browser/visitedlink_master.h388
-rw-r--r--chrome/browser/visitedlink_perftest.cc207
-rw-r--r--chrome/browser/visitedlink_unittest.cc774
-rw-r--r--chrome/browser/web_applications/web_app.cc5
-rw-r--r--chrome/browser/web_resource/web_resource_service.cc8
-rw-r--r--chrome/browser/webdata/web_data_service_unittest.cc2
-rw-r--r--chrome/browser/webdata/web_database.cc2
-rw-r--r--chrome/browser/webdata/web_database_unittest.cc2
-rw-r--r--chrome/browser/window_sizer.cc336
-rw-r--r--chrome/browser/window_sizer.h184
-rw-r--r--chrome/browser/window_sizer_linux.cc131
-rw-r--r--chrome/browser/window_sizer_mac.mm144
-rw-r--r--chrome/browser/window_sizer_unittest.cc1002
-rw-r--r--chrome/browser/window_sizer_win.cc108
-rw-r--r--chrome/browser/worker_host/message_port_dispatcher.cc292
-rw-r--r--chrome/browser/worker_host/message_port_dispatcher.h93
-rw-r--r--chrome/browser/worker_host/message_port_service.cc236
-rw-r--r--chrome/browser/worker_host/message_port_service.h75
-rw-r--r--chrome/browser/worker_host/worker_document_set.cc35
-rw-r--r--chrome/browser/worker_host/worker_document_set.h41
-rw-r--r--chrome/browser/worker_host/worker_message_filter.cc116
-rw-r--r--chrome/browser/worker_host/worker_message_filter.h62
-rw-r--r--chrome/browser/worker_host/worker_process_host.cc449
-rw-r--r--chrome/browser/worker_host/worker_process_host.h134
-rw-r--r--chrome/browser/worker_host/worker_service.cc515
-rw-r--r--chrome/browser/worker_host/worker_service.h119
-rw-r--r--chrome/browser/wrench_menu_model.cc539
-rw-r--r--chrome/browser/wrench_menu_model.h149
-rw-r--r--chrome/browser/wrench_menu_model_unittest.cc105
-rw-r--r--chrome/browser/zygote_host_linux.cc55
-rw-r--r--chrome/browser/zygote_host_linux.h27
-rw-r--r--chrome/browser/zygote_main_linux.cc62
-rw-r--r--chrome/common/DEPS1
-rw-r--r--chrome/common/appcache/appcache_dispatcher.h5
-rw-r--r--chrome/common/automation_messages.cc671
-rw-r--r--chrome/common/automation_messages.h684
-rw-r--r--chrome/common/automation_messages_internal.h2813
-rw-r--r--chrome/common/child_process.cc8
-rw-r--r--chrome/common/child_process_host.cc68
-rw-r--r--chrome/common/child_process_host.h33
-rw-r--r--chrome/common/child_thread.cc34
-rw-r--r--chrome/common/child_thread.h6
-rw-r--r--chrome/common/chrome_application_mac.h71
-rw-r--r--chrome/common/chrome_application_mac.mm76
-rw-r--r--chrome/common/chrome_constants.cc29
-rw-r--r--chrome/common/chrome_constants.h11
-rw-r--r--chrome/common/chrome_paths.cc12
-rw-r--r--chrome/common/chrome_paths.h1
-rw-r--r--chrome/common/chrome_paths_win.cc9
-rw-r--r--chrome/common/chrome_plugin_lib.cc4
-rw-r--r--chrome/common/chrome_switches.cc77
-rw-r--r--chrome/common/chrome_switches.h19
-rw-r--r--chrome/common/chrome_version_info.cc6
-rw-r--r--chrome/common/common_param_traits.cc54
-rw-r--r--chrome/common/common_param_traits.h16
-rw-r--r--chrome/common/common_param_traits_unittest.cc22
-rw-r--r--chrome/common/database_messages.cc8
-rw-r--r--chrome/common/database_messages.h79
-rw-r--r--chrome/common/database_util.cc10
-rw-r--r--chrome/common/db_message_filter.cc7
-rw-r--r--chrome/common/default_plugin.cc9
-rw-r--r--chrome/common/devtools_messages.cc5
-rw-r--r--chrome/common/devtools_messages.h6
-rw-r--r--chrome/common/devtools_messages_internal.h88
-rw-r--r--chrome/common/dom_storage_common.h4
-rw-r--r--chrome/common/dom_storage_messages.cc125
-rw-r--r--chrome/common/dom_storage_messages.h125
-rw-r--r--chrome/common/extensions/api/extension_api.json115
-rw-r--r--chrome/common/extensions/docs/a11y.html2
-rw-r--r--chrome/common/extensions/docs/api_index.html2
-rw-r--r--chrome/common/extensions/docs/api_other.html2
-rw-r--r--chrome/common/extensions/docs/apps.html4
-rw-r--r--chrome/common/extensions/docs/autoupdate.html2
-rw-r--r--chrome/common/extensions/docs/background_pages.html2
-rw-r--r--chrome/common/extensions/docs/bookmarks.html2
-rw-r--r--chrome/common/extensions/docs/browserAction.html2
-rw-r--r--chrome/common/extensions/docs/content_scripts.html2
-rw-r--r--chrome/common/extensions/docs/contextMenus.html2
-rw-r--r--chrome/common/extensions/docs/cookies.html2
-rw-r--r--chrome/common/extensions/docs/crx.html2
-rw-r--r--chrome/common/extensions/docs/css/samples.css3
-rw-r--r--chrome/common/extensions/docs/devguide.html2
-rw-r--r--chrome/common/extensions/docs/docs.html2
-rw-r--r--chrome/common/extensions/docs/events.html2
-rw-r--r--chrome/common/extensions/docs/examples/api/bookmarks/basic.zipbin5687 -> 8600 bytes
-rw-r--r--chrome/common/extensions/docs/examples/api/bookmarks/basic/icon.pngbin0 -> 2809 bytes
-rw-r--r--chrome/common/extensions/docs/examples/api/omnibox/simple-example.zipbin1193 -> 1193 bytes
-rw-r--r--chrome/common/extensions/docs/examples/extensions/app_launcher.zipbin0 -> 24932 bytes
-rw-r--r--chrome/common/extensions/docs/examples/extensions/app_launcher/browser_action_icon.pngbin0 -> 5563 bytes
-rw-r--r--chrome/common/extensions/docs/examples/extensions/app_launcher/icon.pngbin0 -> 5397 bytes
-rw-r--r--chrome/common/extensions/docs/examples/extensions/app_launcher/manifest.json13
-rw-r--r--chrome/common/extensions/docs/examples/extensions/app_launcher/popup.css49
-rw-r--r--chrome/common/extensions/docs/examples/extensions/app_launcher/popup.html32
-rw-r--r--chrome/common/extensions/docs/examples/extensions/app_launcher/popup.js198
-rw-r--r--chrome/common/extensions/docs/examples/extensions/benchmark.zipbin258748 -> 258732 bytes
-rw-r--r--chrome/common/extensions/docs/examples/extensions/benchmark/options.html4
-rw-r--r--chrome/common/extensions/docs/examples/extensions/buildbot.zipbin28099 -> 28652 bytes
-rw-r--r--chrome/common/extensions/docs/examples/extensions/buildbot/bg.html11
-rw-r--r--chrome/common/extensions/docs/examples/extensions/buildbot/manifest.json2
-rw-r--r--chrome/common/extensions/docs/examples/extensions/buildbot/popup.html20
-rw-r--r--chrome/common/extensions/docs/examples/extensions/chrome_search.zipbin5610 -> 5806 bytes
-rw-r--r--chrome/common/extensions/docs/examples/extensions/chrome_search/manifest.json4
-rw-r--r--chrome/common/extensions/docs/examples/extensions/imageinfo.zipbin45565 -> 46603 bytes
-rw-r--r--chrome/common/extensions/docs/examples/tutorials/getstarted.zipbin5683 -> 10884 bytes
-rw-r--r--chrome/common/extensions/docs/examples/tutorials/getstarted/getstarted.zipbin0 -> 5075 bytes
-rw-r--r--chrome/common/extensions/docs/experimental.clipboard.html2
-rw-r--r--chrome/common/extensions/docs/experimental.contextMenus.html2
-rw-r--r--chrome/common/extensions/docs/experimental.cookies.html2
-rw-r--r--chrome/common/extensions/docs/experimental.history.html2
-rw-r--r--chrome/common/extensions/docs/experimental.html2
-rw-r--r--chrome/common/extensions/docs/experimental.idle.html2
-rw-r--r--chrome/common/extensions/docs/experimental.infobars.html2
-rw-r--r--chrome/common/extensions/docs/experimental.processes.html2
-rw-r--r--chrome/common/extensions/docs/experimental.proxy.html38
-rw-r--r--chrome/common/extensions/docs/experimental.sidebar.html2
-rw-r--r--chrome/common/extensions/docs/experimental.webNavigation.html2
-rw-r--r--chrome/common/extensions/docs/experimental.webRequest.html2
-rw-r--r--chrome/common/extensions/docs/extension.html2
-rw-r--r--chrome/common/extensions/docs/external_extensions.html2
-rw-r--r--chrome/common/extensions/docs/faq.html2
-rw-r--r--chrome/common/extensions/docs/getstarted.html3
-rw-r--r--chrome/common/extensions/docs/history.html2
-rw-r--r--chrome/common/extensions/docs/hosting.html2
-rw-r--r--chrome/common/extensions/docs/i18n-messages.html2
-rw-r--r--chrome/common/extensions/docs/i18n.html2
-rw-r--r--chrome/common/extensions/docs/idle.html2
-rw-r--r--chrome/common/extensions/docs/images/perms-hw1.pngbin20247 -> 32298 bytes
-rw-r--r--chrome/common/extensions/docs/images/perms-hw2.pngbin22511 -> 37899 bytes
-rw-r--r--chrome/common/extensions/docs/index.html2
-rw-r--r--chrome/common/extensions/docs/management.html4
-rw-r--r--chrome/common/extensions/docs/manifest.html7
-rw-r--r--chrome/common/extensions/docs/match_patterns.html2
-rw-r--r--chrome/common/extensions/docs/messaging.html2
-rw-r--r--chrome/common/extensions/docs/notifications.html2
-rw-r--r--chrome/common/extensions/docs/npapi.html2
-rw-r--r--chrome/common/extensions/docs/omnibox.html2
-rw-r--r--chrome/common/extensions/docs/options.html2
-rw-r--r--chrome/common/extensions/docs/override.html2
-rw-r--r--chrome/common/extensions/docs/overview.html2
-rw-r--r--chrome/common/extensions/docs/packaging.html2
-rw-r--r--chrome/common/extensions/docs/pageAction.html11
-rw-r--r--chrome/common/extensions/docs/permission_warnings.html64
-rw-r--r--chrome/common/extensions/docs/samples.html49
-rw-r--r--chrome/common/extensions/docs/samples.json36
-rw-r--r--chrome/common/extensions/docs/server/chromeextensionsdocs.py5
-rw-r--r--chrome/common/extensions/docs/static/apps.html2
-rw-r--r--chrome/common/extensions/docs/static/getstarted.html1
-rw-r--r--chrome/common/extensions/docs/static/manifest.html5
-rw-r--r--chrome/common/extensions/docs/static/pageAction.html9
-rw-r--r--chrome/common/extensions/docs/static/permission_warnings.html66
-rw-r--r--chrome/common/extensions/docs/static/themes.html8
-rw-r--r--chrome/common/extensions/docs/static/tut_debugging.html2
-rw-r--r--chrome/common/extensions/docs/tabs.html2
-rw-r--r--chrome/common/extensions/docs/template/api_template.html2
-rw-r--r--chrome/common/extensions/docs/themes.html10
-rw-r--r--chrome/common/extensions/docs/tut_analytics.html2
-rw-r--r--chrome/common/extensions/docs/tut_debugging.html4
-rw-r--r--chrome/common/extensions/docs/tut_oauth.html2
-rw-r--r--chrome/common/extensions/docs/tutorials.html2
-rw-r--r--chrome/common/extensions/docs/whats_new.html2
-rw-r--r--chrome/common/extensions/docs/windows.html60
-rw-r--r--chrome/common/extensions/docs/xhr.html2
-rw-r--r--chrome/common/extensions/extension.cc108
-rw-r--r--chrome/common/extensions/extension.h50
-rw-r--r--chrome/common/extensions/extension_constants.cc20
-rw-r--r--chrome/common/extensions/extension_constants.h18
-rw-r--r--chrome/common/extensions/extension_file_util.cc2
-rw-r--r--chrome/common/extensions/extension_file_util_unittest.cc2
-rw-r--r--chrome/common/extensions/extension_l10n_util.cc30
-rw-r--r--chrome/common/extensions/extension_l10n_util.h9
-rw-r--r--chrome/common/extensions/extension_l10n_util_unittest.cc11
-rw-r--r--chrome/common/extensions/extension_manifests_unittest.cc43
-rw-r--r--chrome/common/extensions/extension_message_bundle.cc20
-rw-r--r--chrome/common/extensions/extension_message_bundle.h9
-rw-r--r--chrome/common/extensions/extension_resource_unittest.cc3
-rw-r--r--chrome/common/extensions/extension_unpacker.cc4
-rw-r--r--chrome/common/extensions/update_manifest.cc5
-rw-r--r--chrome/common/extensions/url_pattern.h9
-rw-r--r--chrome/common/file_system/file_system_dispatcher.h3
-rw-r--r--chrome/common/file_utilities_messages.cc8
-rw-r--r--chrome/common/file_utilities_messages.h35
-rw-r--r--chrome/common/font_config_ipc_linux.cc110
-rw-r--r--chrome/common/font_config_ipc_linux.h40
-rw-r--r--chrome/common/gpu_messages.cc8
-rw-r--r--chrome/common/gpu_messages.h4
-rw-r--r--chrome/common/gpu_messages_internal.h546
-rw-r--r--chrome/common/gpu_plugin.cc14
-rw-r--r--chrome/common/guid.cc32
-rw-r--r--chrome/common/guid.h32
-rw-r--r--chrome/common/guid_posix.cc28
-rw-r--r--chrome/common/guid_unittest.cc42
-rw-r--r--chrome/common/guid_win.cc38
-rw-r--r--chrome/common/indexed_db_key.cc16
-rw-r--r--chrome/common/indexed_db_key.h7
-rw-r--r--chrome/common/indexed_db_messages.cc339
-rw-r--r--chrome/common/indexed_db_messages.h493
-rw-r--r--chrome/common/indexed_db_param_traits.cc13
-rw-r--r--chrome/common/json_pref_store.cc45
-rw-r--r--chrome/common/json_pref_store.h34
-rw-r--r--chrome/common/json_pref_store_unittest.cc56
-rw-r--r--chrome/common/json_schema_validator.cc1
-rw-r--r--chrome/common/json_schema_validator.h2
-rw-r--r--chrome/common/json_value_serializer.h12
-rw-r--r--chrome/common/logging_chrome.cc14
-rw-r--r--chrome/common/message_router.cc14
-rw-r--r--chrome/common/message_router.h4
-rw-r--r--chrome/common/metrics_helpers.cc8
-rw-r--r--chrome/common/metrics_helpers.h8
-rw-r--r--chrome/common/mime_registry_messages.cc8
-rw-r--r--chrome/common/mime_registry_messages.h28
-rw-r--r--chrome/common/nacl_messages.cc5
-rw-r--r--chrome/common/nacl_messages.h7
-rw-r--r--chrome/common/nacl_messages_internal.h31
-rw-r--r--chrome/common/native_web_keyboard_event.h7
-rw-r--r--chrome/common/native_web_keyboard_event_linux.cc13
-rw-r--r--chrome/common/navigation_gesture.h21
-rw-r--r--chrome/common/net/gaia/gaia_auth_fetcher.h12
-rw-r--r--chrome/common/net/gaia/gaia_authenticator.cc12
-rw-r--r--chrome/common/net/gaia/gaia_authenticator.h9
-rw-r--r--chrome/common/net/http_return.h3
-rw-r--r--chrome/common/net/url_fetcher.cc17
-rw-r--r--chrome/common/net/url_fetcher.h2
-rw-r--r--chrome/common/net/url_fetcher_unittest.cc2
-rw-r--r--chrome/common/net/url_request_intercept_job.cc23
-rw-r--r--chrome/common/net/url_request_intercept_job.h4
-rw-r--r--chrome/common/notification_type.h69
-rw-r--r--chrome/common/pepper_file_messages.cc34
-rw-r--r--chrome/common/pepper_file_messages.h68
-rw-r--r--chrome/common/pepper_plugin_registry.cc48
-rw-r--r--chrome/common/pepper_plugin_registry.h13
-rw-r--r--chrome/common/persistent_pref_store.h69
-rw-r--r--chrome/common/plugin_messages.cc7
-rw-r--r--chrome/common/plugin_messages.h4
-rw-r--r--chrome/common/plugin_messages_internal.h848
-rw-r--r--chrome/common/policy_constants.cc7
-rw-r--r--chrome/common/policy_constants.h4
-rw-r--r--chrome/common/pref_names.cc62
-rw-r--r--chrome/common/pref_names.h21
-rw-r--r--chrome/common/pref_store.cc9
-rw-r--r--chrome/common/pref_store.h84
-rw-r--r--chrome/common/pref_store_observer_mock.h26
-rw-r--r--chrome/common/remoting/chromoting_host_info.h23
-rw-r--r--chrome/common/render_messages.cc72
-rw-r--r--chrome/common/render_messages.h119
-rw-r--r--chrome/common/render_messages_internal.h5470
-rw-r--r--chrome/common/render_messages_params.cc415
-rw-r--r--chrome/common/render_messages_params.h266
-rw-r--r--chrome/common/resource_dispatcher.cc6
-rw-r--r--chrome/common/resource_dispatcher.h5
-rw-r--r--chrome/common/result_codes.h7
-rw-r--r--chrome/common/sandbox_init_wrapper.h5
-rw-r--r--chrome/common/sandbox_init_wrapper_mac.cc5
-rw-r--r--chrome/common/sandbox_mac.h7
-rw-r--r--chrome/common/sandbox_mac.mm49
-rw-r--r--chrome/common/sandbox_mac_unittest_helper.mm7
-rw-r--r--chrome/common/sandbox_policy.cc24
-rw-r--r--chrome/common/security_filter_peer.h8
-rw-r--r--chrome/common/service_messages.cc44
-rw-r--r--chrome/common/service_messages.h20
-rw-r--r--chrome/common/service_messages_internal.h89
-rw-r--r--chrome/common/service_process_util.cc21
-rw-r--r--chrome/common/service_process_util.h13
-rw-r--r--chrome/common/service_process_util_unittest.cc29
-rw-r--r--chrome/common/socket_stream_dispatcher.h9
-rw-r--r--chrome/common/sqlite_utils.cc7
-rw-r--r--chrome/common/time_format.cc12
-rw-r--r--chrome/common/unix_domain_socket_posix.cc151
-rw-r--r--chrome/common/unix_domain_socket_posix.h54
-rw-r--r--chrome/common/url_constants.cc6
-rw-r--r--chrome/common/url_constants.h6
-rw-r--r--chrome/common/utility_messages.cc10
-rw-r--r--chrome/common/utility_messages.h3
-rw-r--r--chrome/common/utility_messages_internal.h234
-rw-r--r--chrome/common/web_database_observer_impl.cc9
-rw-r--r--chrome/common/webmessageportchannel_impl.cc5
-rw-r--r--chrome/common/webmessageportchannel_impl.h2
-rw-r--r--chrome/common/worker_messages.cc7
-rw-r--r--chrome/common/worker_messages.h3
-rw-r--r--chrome/common/worker_messages_internal.h194
-rw-r--r--googleurl/src/gurl.cc4
-rw-r--r--googleurl/src/gurl.h4
-rw-r--r--net/base/bandwidth_metrics.cc36
-rw-r--r--net/base/bandwidth_metrics.h26
-rw-r--r--net/base/capturing_net_log.cc28
-rw-r--r--net/base/capturing_net_log.h23
-rw-r--r--net/base/cert_database_nss_unittest.cc19
-rw-r--r--net/base/cert_database_openssl.cc20
-rw-r--r--net/base/cert_test_util.cc156
-rw-r--r--net/base/cert_test_util.h19
-rw-r--r--net/base/cert_verifier.cc505
-rw-r--r--net/base/cert_verifier.h184
-rw-r--r--net/base/cert_verifier_unittest.cc260
-rw-r--r--net/base/cookie_monster.cc31
-rw-r--r--net/base/cookie_monster.h46
-rw-r--r--net/base/cookie_monster_store_test.h16
-rw-r--r--net/base/cookie_monster_unittest.cc154
-rw-r--r--net/base/data_url.cc4
-rw-r--r--net/base/data_url.h3
-rw-r--r--net/base/data_url_unittest.cc14
-rw-r--r--net/base/directory_lister.cc7
-rw-r--r--net/base/directory_lister.h2
-rw-r--r--net/base/dnsrr_resolver.cc49
-rw-r--r--net/base/dnsrr_resolver.h11
-rw-r--r--net/base/escape.cc16
-rw-r--r--net/base/escape_unittest.cc54
-rw-r--r--net/base/forwarding_net_log.cc96
-rw-r--r--net/base/forwarding_net_log.h54
-rw-r--r--net/base/forwarding_net_log_unittest.cc84
-rw-r--r--net/base/host_resolver.cc8
-rw-r--r--net/base/host_resolver.h6
-rw-r--r--net/base/host_resolver_impl.cc4
-rw-r--r--net/base/host_resolver_impl.h2
-rw-r--r--net/base/host_resolver_impl_unittest.cc55
-rw-r--r--net/base/keygen_handler_openssl.cc32
-rw-r--r--net/base/keygen_handler_unittest.cc13
-rw-r--r--net/base/listen_socket.h4
-rw-r--r--net/base/load_flags_list.h2
-rw-r--r--net/base/load_states.h4
-rw-r--r--net/base/mime_sniffer.cc22
-rw-r--r--net/base/mime_util.cc39
-rw-r--r--net/base/net_error_list.h5
-rw-r--r--net/base/net_log.cc23
-rw-r--r--net/base/net_log.h31
-rw-r--r--net/base/net_log_event_type_list.h18
-rw-r--r--net/base/net_log_unittest.cc34
-rw-r--r--net/base/net_util.cc38
-rw-r--r--net/base/net_util.h15
-rw-r--r--net/base/openssl_memory_private_key_store.cc68
-rw-r--r--net/base/openssl_private_key_store.h51
-rw-r--r--net/base/registry_controlled_domain.h10
-rw-r--r--net/base/ssl_cert_request_info.cc5
-rw-r--r--net/base/ssl_cert_request_info.h3
-rw-r--r--net/base/ssl_cipher_suite_names.cc2
-rw-r--r--net/base/ssl_config_service.cc8
-rw-r--r--net/base/ssl_config_service.h25
-rw-r--r--net/base/ssl_config_service_mac.cc14
-rw-r--r--net/base/ssl_config_service_mac.h1
-rw-r--r--net/base/ssl_config_service_mac_unittest.cc26
-rw-r--r--net/base/ssl_config_service_win.cc9
-rw-r--r--net/base/ssl_config_service_win.h1
-rw-r--r--net/base/ssl_config_service_win_unittest.cc24
-rw-r--r--net/base/ssl_false_start_blacklist.txt20
-rw-r--r--net/base/test_root_certs.cc59
-rw-r--r--net/base/test_root_certs.h103
-rw-r--r--net/base/test_root_certs_mac.cc135
-rw-r--r--net/base/test_root_certs_nss.cc119
-rw-r--r--net/base/test_root_certs_openssl.cc51
-rw-r--r--net/base/test_root_certs_win.cc206
-rw-r--r--net/base/transport_security_state.cc36
-rw-r--r--net/base/transport_security_state.h3
-rw-r--r--net/base/transport_security_state_unittest.cc24
-rw-r--r--net/base/winsock_init.cc7
-rw-r--r--net/base/x509_cert_types.cc48
-rw-r--r--net/base/x509_cert_types.h22
-rw-r--r--net/base/x509_certificate.h41
-rw-r--r--net/base/x509_certificate_mac.cc207
-rw-r--r--net/base/x509_certificate_nss.cc114
-rw-r--r--net/base/x509_certificate_openssl.cc69
-rw-r--r--net/base/x509_certificate_unittest.cc67
-rw-r--r--net/base/x509_certificate_win.cc120
-rw-r--r--net/base/x509_openssl_util.cc65
-rw-r--r--net/base/x509_openssl_util_unittest.cc3
-rw-r--r--net/data/ftp/dir-listing-hprc-12
-rw-r--r--net/data/ftp/dir-listing-hprc-1.expected17
-rw-r--r--net/data/ftp/dir-listing-hprc-24
-rw-r--r--net/data/ftp/dir-listing-hprc-2.expected35
-rw-r--r--net/data/ftp/dir-listing-hprc-33
-rw-r--r--net/data/ftp/dir-listing-hprc-3.expected26
-rw-r--r--net/data/ftp/dir-listing-mlsd-15
-rw-r--r--net/data/ftp/dir-listing-mlsd-1.expected44
-rw-r--r--net/data/ftp/dir-listing-mlsd-21
-rw-r--r--net/data/ftp/dir-listing-mlsd-2.expected8
-rw-r--r--net/data/ssl/certificates/README5
-rw-r--r--net/data/ssl/certificates/unittest.key.binbin0 -> 635 bytes
-rw-r--r--net/data/ssl/certificates/unittest.selfsigned.derbin0 -> 414 bytes
-rw-r--r--net/disk_cache/backend_impl.cc13
-rw-r--r--net/disk_cache/backend_unittest.cc4
-rw-r--r--net/disk_cache/entry_impl.cc8
-rw-r--r--net/disk_cache/entry_unittest.cc49
-rw-r--r--net/disk_cache/file_win.cc11
-rw-r--r--net/disk_cache/in_flight_backend_io.cc27
-rw-r--r--net/disk_cache/in_flight_backend_io.h3
-rw-r--r--net/ftp/ftp_directory_listing_buffer.cc4
-rw-r--r--net/ftp/ftp_directory_listing_buffer_unittest.cc5
-rw-r--r--net/ftp/ftp_directory_listing_parser_hprc.cc60
-rw-r--r--net/ftp/ftp_directory_listing_parser_hprc.h46
-rw-r--r--net/ftp/ftp_directory_listing_parser_hprc_unittest.cc46
-rw-r--r--net/ftp/ftp_directory_listing_parser_ls.cc4
-rw-r--r--net/ftp/ftp_directory_listing_parser_ls.h2
-rw-r--r--net/ftp/ftp_directory_listing_parser_mlsd.cc142
-rw-r--r--net/ftp/ftp_directory_listing_parser_mlsd.h37
-rw-r--r--net/ftp/ftp_directory_listing_parser_mlsd_unittest.cc68
-rw-r--r--net/ftp/ftp_directory_listing_parser_netware.cc4
-rw-r--r--net/ftp/ftp_directory_listing_parser_netware.h2
-rw-r--r--net/ftp/ftp_directory_listing_parser_vms.cc4
-rw-r--r--net/ftp/ftp_directory_listing_parser_vms.h2
-rw-r--r--net/ftp/ftp_directory_listing_parser_windows.cc29
-rw-r--r--net/ftp/ftp_directory_listing_parser_windows.h2
-rw-r--r--net/ftp/ftp_directory_listing_parser_windows_unittest.cc27
-rw-r--r--net/ftp/ftp_network_transaction.cc47
-rw-r--r--net/ftp/ftp_network_transaction.h4
-rw-r--r--net/ftp/ftp_network_transaction_unittest.cc25
-rw-r--r--net/ftp/ftp_server_type_histograms.h4
-rw-r--r--net/http/des.cc10
-rw-r--r--net/http/disk_cache_based_ssl_host_info.cc41
-rw-r--r--net/http/disk_cache_based_ssl_host_info.h70
-rw-r--r--net/http/http_alternate_protocols.h1
-rw-r--r--net/http/http_auth_cache_unittest.cc2
-rw-r--r--net/http/http_auth_controller.cc87
-rw-r--r--net/http/http_auth_controller.h8
-rw-r--r--net/http/http_auth_gssapi_posix.cc5
-rw-r--r--net/http/http_auth_handler.cc12
-rw-r--r--net/http/http_auth_handler.h27
-rw-r--r--net/http/http_auth_handler_basic.cc1
-rw-r--r--net/http/http_auth_handler_basic.h2
-rw-r--r--net/http/http_auth_handler_digest.cc1
-rw-r--r--net/http/http_auth_handler_digest.h2
-rw-r--r--net/http/http_auth_handler_digest_unittest.cc157
-rw-r--r--net/http/http_auth_handler_mock.cc1
-rw-r--r--net/http/http_auth_handler_negotiate.cc1
-rw-r--r--net/http/http_auth_handler_ntlm.cc1
-rw-r--r--net/http/http_auth_handler_unittest.cc11
-rw-r--r--net/http/http_basic_stream.cc6
-rw-r--r--net/http/http_basic_stream.h8
-rw-r--r--net/http/http_cache.cc19
-rw-r--r--net/http/http_cache.h8
-rw-r--r--net/http/http_cache_transaction.cc29
-rw-r--r--net/http/http_cache_transaction.h3
-rw-r--r--net/http/http_cache_unittest.cc118
-rw-r--r--net/http/http_net_log_params.h4
-rw-r--r--net/http/http_network_layer.cc11
-rw-r--r--net/http/http_network_layer.h16
-rw-r--r--net/http/http_network_layer_unittest.cc7
-rw-r--r--net/http/http_network_session.cc3
-rw-r--r--net/http/http_network_session.h4
-rw-r--r--net/http/http_network_transaction.cc104
-rw-r--r--net/http/http_network_transaction.h7
-rw-r--r--net/http/http_network_transaction_unittest.cc590
-rw-r--r--net/http/http_proxy_client_socket.cc24
-rw-r--r--net/http/http_proxy_client_socket.h17
-rw-r--r--net/http/http_proxy_client_socket_pool.cc22
-rw-r--r--net/http/http_proxy_client_socket_pool.h15
-rw-r--r--net/http/http_proxy_client_socket_pool_unittest.cc19
-rw-r--r--net/http/http_response_body_drainer_unittest.cc1
-rw-r--r--net/http/http_stream_factory.h6
-rw-r--r--net/http/http_stream_factory_unittest.cc7
-rw-r--r--net/http/http_stream_request.cc101
-rw-r--r--net/http/http_stream_request.h15
-rw-r--r--net/http/proxy_client_socket.h35
-rw-r--r--net/http/stream_factory.h7
-rw-r--r--net/net.gyp91
-rw-r--r--net/ocsp/nss_ocsp.cc31
-rw-r--r--net/proxy/init_proxy_resolver_unittest.cc93
-rw-r--r--net/proxy/multi_threaded_proxy_resolver.cc22
-rw-r--r--net/proxy/multi_threaded_proxy_resolver_unittest.cc44
-rw-r--r--net/proxy/proxy_bypass_rules.cc63
-rw-r--r--net/proxy/proxy_bypass_rules.h23
-rw-r--r--net/proxy/proxy_config_service_fixed.cc20
-rw-r--r--net/proxy/proxy_config_service_fixed.h8
-rw-r--r--net/proxy/proxy_config_service_linux.cc12
-rw-r--r--net/proxy/proxy_config_service_linux.h15
-rw-r--r--net/proxy/proxy_resolver.h5
-rw-r--r--net/proxy/proxy_resolver_js_bindings_unittest.cc63
-rw-r--r--net/proxy/proxy_resolver_mac.cc21
-rw-r--r--net/proxy/proxy_resolver_mac.h14
-rw-r--r--net/proxy/proxy_resolver_v8.cc4
-rw-r--r--net/proxy/proxy_resolver_v8.h1
-rw-r--r--net/proxy/proxy_resolver_v8_unittest.cc4
-rw-r--r--net/proxy/proxy_resolver_winhttp.cc25
-rw-r--r--net/proxy/proxy_resolver_winhttp.h3
-rw-r--r--net/proxy/proxy_script_fetcher.h2
-rw-r--r--net/proxy/proxy_script_fetcher_impl.cc22
-rw-r--r--net/proxy/proxy_script_fetcher_impl.h23
-rw-r--r--net/proxy/proxy_script_fetcher_impl_unittest.cc9
-rw-r--r--net/proxy/proxy_service.cc29
-rw-r--r--net/proxy/proxy_service.h2
-rw-r--r--net/proxy/proxy_service_unittest.cc50
-rw-r--r--net/proxy/sync_host_resolver_bridge_unittest.cc4
-rw-r--r--net/server/http_listen_socket.cc10
-rw-r--r--net/server/http_listen_socket.h4
-rw-r--r--net/socket/client_socket_factory.cc25
-rw-r--r--net/socket/client_socket_factory.h6
-rw-r--r--net/socket/client_socket_pool.h4
-rw-r--r--net/socket/client_socket_pool_base.cc8
-rw-r--r--net/socket/client_socket_pool_base_unittest.cc78
-rw-r--r--net/socket/client_socket_pool_manager.cc5
-rw-r--r--net/socket/client_socket_pool_manager.h11
-rw-r--r--net/socket/dns_cert_provenance_checker.cc44
-rw-r--r--net/socket/nss_ssl_util.cc240
-rw-r--r--net/socket/nss_ssl_util.h36
-rw-r--r--net/socket/socket_test_util.cc17
-rw-r--r--net/socket/socket_test_util.h8
-rw-r--r--net/socket/socks5_client_socket.cc4
-rw-r--r--net/socket/socks5_client_socket.h2
-rw-r--r--net/socket/socks5_client_socket_unittest.cc41
-rw-r--r--net/socket/socks_client_socket.cc4
-rw-r--r--net/socket/socks_client_socket.h2
-rw-r--r--net/socket/socks_client_socket_pool.cc12
-rw-r--r--net/socket/socks_client_socket_pool.h12
-rw-r--r--net/socket/socks_client_socket_unittest.cc59
-rw-r--r--net/socket/ssl_client_socket.cc62
-rw-r--r--net/socket/ssl_client_socket.h57
-rw-r--r--net/socket/ssl_client_socket_mac.cc41
-rw-r--r--net/socket/ssl_client_socket_mac.h7
-rw-r--r--net/socket/ssl_client_socket_mac_factory.cc4
-rw-r--r--net/socket/ssl_client_socket_mac_factory.h1
-rw-r--r--net/socket/ssl_client_socket_nss.cc282
-rw-r--r--net/socket/ssl_client_socket_nss.h9
-rw-r--r--net/socket/ssl_client_socket_nss_factory.cc3
-rw-r--r--net/socket/ssl_client_socket_nss_factory.h1
-rw-r--r--net/socket/ssl_client_socket_openssl.cc351
-rw-r--r--net/socket/ssl_client_socket_openssl.h31
-rw-r--r--net/socket/ssl_client_socket_pool.cc38
-rw-r--r--net/socket/ssl_client_socket_pool.h20
-rw-r--r--net/socket/ssl_client_socket_pool_unittest.cc7
-rw-r--r--net/socket/ssl_client_socket_snapstart_unittest.cc19
-rw-r--r--net/socket/ssl_client_socket_unittest.cc116
-rw-r--r--net/socket/ssl_client_socket_win.cc35
-rw-r--r--net/socket/ssl_client_socket_win.h7
-rw-r--r--net/socket/ssl_host_info.cc141
-rw-r--r--net/socket/ssl_host_info.h30
-rw-r--r--net/socket/ssl_host_info.proto34
-rw-r--r--net/socket/ssl_server_socket.h53
-rw-r--r--net/socket/ssl_server_socket_nss.cc677
-rw-r--r--net/socket/ssl_server_socket_nss.h133
-rw-r--r--net/socket/ssl_server_socket_unittest.cc369
-rw-r--r--net/socket/tcp_client_socket_libevent.cc4
-rw-r--r--net/socket/tcp_client_socket_libevent.h2
-rw-r--r--net/socket/tcp_client_socket_pool.cc31
-rw-r--r--net/socket/tcp_client_socket_pool.h26
-rw-r--r--net/socket/tcp_client_socket_pool_unittest.cc3
-rw-r--r--net/socket/tcp_client_socket_unittest.cc10
-rw-r--r--net/socket_stream/socket_stream.cc6
-rw-r--r--net/socket_stream/socket_stream.h1
-rw-r--r--net/socket_stream/socket_stream_job.cc9
-rw-r--r--net/socket_stream/socket_stream_job_manager.cc7
-rw-r--r--net/socket_stream/socket_stream_job_manager.h9
-rw-r--r--net/socket_stream/socket_stream_metrics_unittest.cc2
-rw-r--r--net/spdy/spdy_http_stream.cc43
-rw-r--r--net/spdy/spdy_http_stream.h24
-rw-r--r--net/spdy/spdy_http_utils.h4
-rw-r--r--net/spdy/spdy_network_transaction_unittest.cc31
-rw-r--r--net/spdy/spdy_proxy_client_socket.cc25
-rw-r--r--net/spdy/spdy_proxy_client_socket.h19
-rw-r--r--net/spdy/spdy_proxy_client_socket_unittest.cc8
-rw-r--r--net/spdy/spdy_session.cc95
-rw-r--r--net/spdy/spdy_session.h4
-rw-r--r--net/spdy/spdy_stream.cc2
-rw-r--r--net/spdy/spdy_test_util.h9
-rw-r--r--net/test/test_server.cc40
-rw-r--r--net/test/test_server.h15
-rw-r--r--net/test/test_server_posix.cc6
-rw-r--r--net/test/test_server_win.cc28
-rw-r--r--net/tools/dump_cache/dump_cache.cc8
-rw-r--r--net/tools/fetch/fetch_client.cc19
-rw-r--r--net/tools/flip_server/balsa_headers.h19
-rw-r--r--net/tools/flip_server/flip_config.h64
-rw-r--r--net/tools/flip_server/flip_in_mem_edsm_server.cc226
-rwxr-xr-xnet/tools/testserver/testserver.py33
-rw-r--r--net/tools/testserver/xmppserver.py65
-rw-r--r--net/tools/testserver/xmppserver_test.py34
-rw-r--r--net/url_request/https_prober.cc22
-rw-r--r--net/url_request/https_prober.h35
-rw-r--r--net/url_request/url_request.cc33
-rw-r--r--net/url_request/url_request.h2
-rw-r--r--net/url_request/url_request_about_job.cc6
-rw-r--r--net/url_request/url_request_about_job.h6
-rw-r--r--net/url_request/url_request_context.cc5
-rw-r--r--net/url_request/url_request_context.h50
-rw-r--r--net/url_request/url_request_data_job.cc9
-rw-r--r--net/url_request/url_request_data_job.h8
-rw-r--r--net/url_request/url_request_error_job.cc6
-rw-r--r--net/url_request/url_request_error_job.h10
-rw-r--r--net/url_request/url_request_file_dir_job.cc27
-rw-r--r--net/url_request/url_request_file_dir_job.h6
-rw-r--r--net/url_request/url_request_file_job.cc54
-rw-r--r--net/url_request/url_request_file_job.h17
-rw-r--r--net/url_request/url_request_filter.cc31
-rw-r--r--net/url_request/url_request_filter.h17
-rw-r--r--net/url_request/url_request_ftp_job.cc83
-rw-r--r--net/url_request/url_request_ftp_job.h34
-rw-r--r--net/url_request/url_request_http_job.cc331
-rw-r--r--net/url_request/url_request_http_job.h56
-rw-r--r--net/url_request/url_request_job.cc6
-rw-r--r--net/url_request/url_request_job.h42
-rw-r--r--net/url_request/url_request_job_manager.cc53
-rw-r--r--net/url_request/url_request_job_manager.h48
-rw-r--r--net/url_request/url_request_job_metrics.cc8
-rw-r--r--net/url_request/url_request_job_metrics.h6
-rw-r--r--net/url_request/url_request_job_tracker.cc14
-rw-r--r--net/url_request/url_request_job_tracker.h34
-rw-r--r--net/url_request/url_request_job_tracker_unittest.cc39
-rw-r--r--net/url_request/url_request_netlog_params.cc6
-rw-r--r--net/url_request/url_request_netlog_params.h10
-rw-r--r--net/url_request/url_request_redirect_job.cc17
-rw-r--r--net/url_request/url_request_redirect_job.h10
-rw-r--r--net/url_request/url_request_simple_job.cc10
-rw-r--r--net/url_request/url_request_simple_job.h12
-rw-r--r--net/url_request/url_request_test_job.cc19
-rw-r--r--net/url_request/url_request_test_job.h8
-rw-r--r--net/url_request/url_request_throttler_entry.h4
-rw-r--r--net/url_request/url_request_throttler_entry_interface.h4
-rw-r--r--net/url_request/url_request_throttler_header_adapter.cc2
-rw-r--r--net/url_request/url_request_throttler_header_adapter.h2
-rw-r--r--net/url_request/url_request_throttler_manager.cc3
-rw-r--r--net/url_request/url_request_throttler_manager.h10
-rw-r--r--net/url_request/url_request_unittest.cc98
-rw-r--r--net/url_request/url_request_unittest.h27
-rw-r--r--net/websockets/websocket_job.cc22
-rw-r--r--net/websockets/websocket_job_unittest.cc4
-rw-r--r--net/websockets/websocket_net_log_params.cc51
-rw-r--r--net/websockets/websocket_net_log_params.h41
-rw-r--r--net/websockets/websocket_throttle.cc5
-rw-r--r--net/websockets/websocket_throttle.h6
-rw-r--r--testing/gmock.gyp4
-rw-r--r--testing/gtest.gyp20
-rw-r--r--webkit/glue/bookmarklet_unittest.cc18
-rw-r--r--webkit/glue/context_menu.cc2
-rw-r--r--webkit/glue/context_menu.h4
-rw-r--r--webkit/glue/cpp_bound_class.cc4
-rw-r--r--webkit/glue/cpp_bound_class.h3
-rw-r--r--webkit/glue/cpp_bound_class_unittest.cc11
-rw-r--r--webkit/glue/cpp_variant.cc9
-rw-r--r--webkit/glue/cpp_variant.h2
-rw-r--r--webkit/glue/glue_serialize.cc38
-rw-r--r--webkit/glue/media/audio_decoder.cc76
-rw-r--r--webkit/glue/media/audio_decoder.h20
-rw-r--r--webkit/glue/media/buffered_data_source.cc590
-rw-r--r--webkit/glue/media/buffered_data_source.h219
-rw-r--r--webkit/glue/media/buffered_data_source_unittest.cc548
-rw-r--r--webkit/glue/media/buffered_resource_loader.cc578
-rw-r--r--webkit/glue/media/buffered_resource_loader.h246
-rw-r--r--webkit/glue/media/buffered_resource_loader_unittest.cc486
-rw-r--r--webkit/glue/media/media_resource_loader_bridge_factory.cc82
-rw-r--r--webkit/glue/media/media_resource_loader_bridge_factory.h76
-rw-r--r--webkit/glue/media/media_resource_loader_bridge_factory_unittest.cc44
-rw-r--r--webkit/glue/media/mock_media_resource_loader_bridge_factory.h36
-rw-r--r--webkit/glue/media/simple_data_source.cc142
-rw-r--r--webkit/glue/media/simple_data_source.h76
-rw-r--r--webkit/glue/media/simple_data_source_unittest.cc95
-rw-r--r--webkit/glue/mimetype_unittest.cc12
-rw-r--r--webkit/glue/mock_resource_loader_bridge.h44
-rw-r--r--webkit/glue/multipart_response_delegate.cc44
-rw-r--r--webkit/glue/multipart_response_delegate.h3
-rw-r--r--webkit/glue/multipart_response_delegate_unittest.cc16
-rw-r--r--webkit/glue/plugins/DEPS4
-rw-r--r--webkit/glue/plugins/carbon_plugin_window_tracker_mac.cc55
-rw-r--r--webkit/glue/plugins/carbon_plugin_window_tracker_mac.h53
-rw-r--r--webkit/glue/plugins/coregraphics_private_symbols_mac.h27
-rw-r--r--webkit/glue/plugins/default_plugin_shared.h31
-rw-r--r--webkit/glue/plugins/gtk_plugin_container.cc85
-rw-r--r--webkit/glue/plugins/gtk_plugin_container.h26
-rw-r--r--webkit/glue/plugins/gtk_plugin_container_manager.cc155
-rw-r--r--webkit/glue/plugins/gtk_plugin_container_manager.h57
-rw-r--r--webkit/glue/plugins/npapi_extension_thunk.cc551
-rw-r--r--webkit/glue/plugins/npapi_extension_thunk.h23
-rw-r--r--webkit/glue/plugins/pepper_audio.cc389
-rw-r--r--webkit/glue/plugins/pepper_audio.h136
-rw-r--r--webkit/glue/plugins/pepper_buffer.cc117
-rw-r--r--webkit/glue/plugins/pepper_buffer.h56
-rw-r--r--webkit/glue/plugins/pepper_char_set.cc166
-rw-r--r--webkit/glue/plugins/pepper_char_set.h21
-rw-r--r--webkit/glue/plugins/pepper_class.h66
-rw-r--r--webkit/glue/plugins/pepper_common.h24
-rw-r--r--webkit/glue/plugins/pepper_cursor_control.cc92
-rw-r--r--webkit/glue/plugins/pepper_cursor_control.h19
-rw-r--r--webkit/glue/plugins/pepper_dir_contents.h18
-rw-r--r--webkit/glue/plugins/pepper_directory_reader.cc156
-rw-r--r--webkit/glue/plugins/pepper_directory_reader.h51
-rw-r--r--webkit/glue/plugins/pepper_error_util.cc33
-rw-r--r--webkit/glue/plugins/pepper_error_util.h16
-rw-r--r--webkit/glue/plugins/pepper_event_conversion.cc301
-rw-r--r--webkit/glue/plugins/pepper_event_conversion.h30
-rw-r--r--webkit/glue/plugins/pepper_file_callbacks.cc99
-rw-r--r--webkit/glue/plugins/pepper_file_callbacks.h57
-rw-r--r--webkit/glue/plugins/pepper_file_chooser.cc161
-rw-r--r--webkit/glue/plugins/pepper_file_chooser.h52
-rw-r--r--webkit/glue/plugins/pepper_file_io.cc433
-rw-r--r--webkit/glue/plugins/pepper_file_io.h94
-rw-r--r--webkit/glue/plugins/pepper_file_ref.cc343
-rw-r--r--webkit/glue/plugins/pepper_file_ref.h62
-rw-r--r--webkit/glue/plugins/pepper_file_system.cc85
-rw-r--r--webkit/glue/plugins/pepper_file_system.h44
-rw-r--r--webkit/glue/plugins/pepper_font.cc294
-rw-r--r--webkit/glue/plugins/pepper_font.h53
-rw-r--r--webkit/glue/plugins/pepper_fullscreen_container.h36
-rw-r--r--webkit/glue/plugins/pepper_graphics_2d.cc638
-rw-r--r--webkit/glue/plugins/pepper_graphics_2d.h180
-rw-r--r--webkit/glue/plugins/pepper_graphics_3d.cc256
-rw-r--r--webkit/glue/plugins/pepper_graphics_3d.h90
-rw-r--r--webkit/glue/plugins/pepper_graphics_3d_gl.cc671
-rw-r--r--webkit/glue/plugins/pepper_image_data.cc210
-rw-r--r--webkit/glue/plugins/pepper_image_data.h131
-rw-r--r--webkit/glue/plugins/pepper_plugin_delegate.h281
-rw-r--r--webkit/glue/plugins/pepper_plugin_instance.cc1179
-rw-r--r--webkit/glue/plugins/pepper_plugin_instance.h318
-rw-r--r--webkit/glue/plugins/pepper_plugin_module.cc553
-rw-r--r--webkit/glue/plugins/pepper_plugin_module.h169
-rw-r--r--webkit/glue/plugins/pepper_plugin_object.cc887
-rw-r--r--webkit/glue/plugins/pepper_plugin_object.h89
-rw-r--r--webkit/glue/plugins/pepper_private.cc302
-rw-r--r--webkit/glue/plugins/pepper_private.h23
-rw-r--r--webkit/glue/plugins/pepper_private2.cc243
-rw-r--r--webkit/glue/plugins/pepper_private2.h42
-rw-r--r--webkit/glue/plugins/pepper_private2_linux.cc110
-rw-r--r--webkit/glue/plugins/pepper_resource.cc37
-rw-r--r--webkit/glue/plugins/pepper_resource.h140
-rw-r--r--webkit/glue/plugins/pepper_resource_tracker.cc167
-rw-r--r--webkit/glue/plugins/pepper_resource_tracker.h134
-rw-r--r--webkit/glue/plugins/pepper_scrollbar.cc242
-rw-r--r--webkit/glue/plugins/pepper_scrollbar.h62
-rw-r--r--webkit/glue/plugins/pepper_string.cc13
-rw-r--r--webkit/glue/plugins/pepper_string.h30
-rw-r--r--webkit/glue/plugins/pepper_transport.cc140
-rw-r--r--webkit/glue/plugins/pepper_transport.h35
-rw-r--r--webkit/glue/plugins/pepper_url_loader.cc532
-rw-r--r--webkit/glue/plugins/pepper_url_loader.h140
-rw-r--r--webkit/glue/plugins/pepper_url_request_info.cc278
-rw-r--r--webkit/glue/plugins/pepper_url_request_info.h69
-rw-r--r--webkit/glue/plugins/pepper_url_response_info.cc137
-rw-r--r--webkit/glue/plugins/pepper_url_response_info.h51
-rw-r--r--webkit/glue/plugins/pepper_url_util.cc177
-rw-r--r--webkit/glue/plugins/pepper_url_util.h19
-rw-r--r--webkit/glue/plugins/pepper_var.cc853
-rw-r--r--webkit/glue/plugins/pepper_var.h251
-rw-r--r--webkit/glue/plugins/pepper_video_decoder.cc141
-rw-r--r--webkit/glue/plugins/pepper_video_decoder.h50
-rw-r--r--webkit/glue/plugins/pepper_webplugin_impl.cc226
-rw-r--r--webkit/glue/plugins/pepper_webplugin_impl.h95
-rw-r--r--webkit/glue/plugins/pepper_widget.cc95
-rw-r--r--webkit/glue/plugins/pepper_widget.h53
-rw-r--r--webkit/glue/plugins/plugin_constants_win.h41
-rw-r--r--webkit/glue/plugins/plugin_group.cc419
-rw-r--r--webkit/glue/plugins/plugin_group.h184
-rw-r--r--webkit/glue/plugins/plugin_group_unittest.cc181
-rw-r--r--webkit/glue/plugins/plugin_host.cc1104
-rw-r--r--webkit/glue/plugins/plugin_host.h63
-rw-r--r--webkit/glue/plugins/plugin_instance.cc680
-rw-r--r--webkit/glue/plugins/plugin_instance.h375
-rw-r--r--webkit/glue/plugins/plugin_instance_mac.mm133
-rw-r--r--webkit/glue/plugins/plugin_lib.cc349
-rw-r--r--webkit/glue/plugins/plugin_lib.h120
-rw-r--r--webkit/glue/plugins/plugin_lib_mac.mm348
-rw-r--r--webkit/glue/plugins/plugin_lib_posix.cc256
-rw-r--r--webkit/glue/plugins/plugin_lib_unittest.cc152
-rw-r--r--webkit/glue/plugins/plugin_lib_win.cc46
-rw-r--r--webkit/glue/plugins/plugin_list.cc613
-rw-r--r--webkit/glue/plugins/plugin_list.h304
-rw-r--r--webkit/glue/plugins/plugin_list_mac.mm103
-rw-r--r--webkit/glue/plugins/plugin_list_posix.cc270
-rw-r--r--webkit/glue/plugins/plugin_list_win.cc410
-rw-r--r--webkit/glue/plugins/plugin_stream.cc254
-rw-r--r--webkit/glue/plugins/plugin_stream.h158
-rw-r--r--webkit/glue/plugins/plugin_stream_posix.cc74
-rw-r--r--webkit/glue/plugins/plugin_stream_url.cc118
-rw-r--r--webkit/glue/plugins/plugin_stream_url.h71
-rw-r--r--webkit/glue/plugins/plugin_stream_win.cc97
-rw-r--r--webkit/glue/plugins/plugin_string_stream.cc37
-rw-r--r--webkit/glue/plugins/plugin_string_stream.h39
-rw-r--r--webkit/glue/plugins/plugin_stubs.cc30
-rw-r--r--webkit/glue/plugins/plugin_switches.cc15
-rw-r--r--webkit/glue/plugins/plugin_switches.h15
-rw-r--r--webkit/glue/plugins/plugin_web_event_converter_mac.h60
-rw-r--r--webkit/glue/plugins/plugin_web_event_converter_mac.mm359
-rw-r--r--webkit/glue/plugins/ppb_private.h135
-rw-r--r--webkit/glue/plugins/ppb_private2.h117
-rw-r--r--webkit/glue/plugins/ppp_private.h20
-rw-r--r--webkit/glue/plugins/quickdraw_drawing_manager_mac.cc154
-rw-r--r--webkit/glue/plugins/quickdraw_drawing_manager_mac.h83
-rw-r--r--webkit/glue/plugins/test/Info.plist46
-rw-r--r--webkit/glue/plugins/test/npapi_constants.cc10
-rw-r--r--webkit/glue/plugins/test/npapi_constants.h19
-rw-r--r--webkit/glue/plugins/test/npapi_test.cc122
-rw-r--r--webkit/glue/plugins/test/npapi_test.def6
-rw-r--r--webkit/glue/plugins/test/npapi_test.rc102
-rw-r--r--webkit/glue/plugins/test/plugin_arguments_test.cc69
-rw-r--r--webkit/glue/plugins/test/plugin_arguments_test.h43
-rw-r--r--webkit/glue/plugins/test/plugin_client.cc240
-rw-r--r--webkit/glue/plugins/test/plugin_client.h45
-rw-r--r--webkit/glue/plugins/test/plugin_create_instance_in_paint.cc78
-rw-r--r--webkit/glue/plugins/test/plugin_create_instance_in_paint.h33
-rw-r--r--webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.cc45
-rw-r--r--webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.h30
-rw-r--r--webkit/glue/plugins/test/plugin_get_javascript_url2_test.cc134
-rw-r--r--webkit/glue/plugins/test/plugin_get_javascript_url2_test.h38
-rw-r--r--webkit/glue/plugins/test/plugin_get_javascript_url_test.cc218
-rw-r--r--webkit/glue/plugins/test/plugin_get_javascript_url_test.h47
-rw-r--r--webkit/glue/plugins/test/plugin_geturl_test.cc414
-rw-r--r--webkit/glue/plugins/test/plugin_geturl_test.h61
-rw-r--r--webkit/glue/plugins/test/plugin_javascript_open_popup.cc103
-rw-r--r--webkit/glue/plugins/test/plugin_javascript_open_popup.h47
-rw-r--r--webkit/glue/plugins/test/plugin_new_fails_test.cc18
-rw-r--r--webkit/glue/plugins/test/plugin_new_fails_test.h21
-rw-r--r--webkit/glue/plugins/test/plugin_npobject_lifetime_test.cc174
-rw-r--r--webkit/glue/plugins/test/plugin_npobject_lifetime_test.h82
-rw-r--r--webkit/glue/plugins/test/plugin_npobject_proxy_test.cc51
-rw-r--r--webkit/glue/plugins/test/plugin_npobject_proxy_test.h27
-rw-r--r--webkit/glue/plugins/test/plugin_private_test.cc57
-rw-r--r--webkit/glue/plugins/test/plugin_private_test.h25
-rw-r--r--webkit/glue/plugins/test/plugin_schedule_timer_test.cc116
-rw-r--r--webkit/glue/plugins/test/plugin_schedule_timer_test.h68
-rw-r--r--webkit/glue/plugins/test/plugin_setup_test.cc22
-rw-r--r--webkit/glue/plugins/test/plugin_setup_test.h24
-rw-r--r--webkit/glue/plugins/test/plugin_test.cc155
-rw-r--r--webkit/glue/plugins/test/plugin_test.h134
-rw-r--r--webkit/glue/plugins/test/plugin_test_factory.cc104
-rw-r--r--webkit/glue/plugins/test/plugin_test_factory.h22
-rw-r--r--webkit/glue/plugins/test/plugin_thread_async_call_test.cc117
-rw-r--r--webkit/glue/plugins/test/plugin_thread_async_call_test.h39
-rw-r--r--webkit/glue/plugins/test/plugin_window_size_test.cc55
-rw-r--r--webkit/glue/plugins/test/plugin_window_size_test.h24
-rw-r--r--webkit/glue/plugins/test/plugin_windowed_test.cc150
-rw-r--r--webkit/glue/plugins/test/plugin_windowed_test.h33
-rw-r--r--webkit/glue/plugins/test/plugin_windowless_test.cc261
-rw-r--r--webkit/glue/plugins/test/plugin_windowless_test.h35
-rw-r--r--webkit/glue/plugins/test/resource.h15
-rw-r--r--webkit/glue/plugins/webplugin.cc26
-rw-r--r--webkit/glue/plugins/webplugin.h200
-rw-r--r--webkit/glue/plugins/webplugin_2d_device_delegate.h57
-rw-r--r--webkit/glue/plugins/webplugin_3d_device_delegate.h101
-rw-r--r--webkit/glue/plugins/webplugin_accelerated_surface_mac.h44
-rw-r--r--webkit/glue/plugins/webplugin_audio_device_delegate.h56
-rw-r--r--webkit/glue/plugins/webplugin_delegate.h166
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl.cc304
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl.h511
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl_gtk.cc767
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl_mac.mm1145
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl_win.cc1410
-rw-r--r--webkit/glue/plugins/webplugin_file_delegate.h35
-rw-r--r--webkit/glue/plugins/webplugin_impl.cc1379
-rw-r--r--webkit/glue/plugins/webplugin_impl.h332
-rw-r--r--webkit/glue/plugins/webplugin_impl_unittest.cc232
-rw-r--r--webkit/glue/plugins/webplugin_page_delegate.h69
-rw-r--r--webkit/glue/plugins/webplugin_print_delegate.h49
-rw-r--r--webkit/glue/plugins/webplugininfo.cc44
-rw-r--r--webkit/glue/plugins/webplugininfo.h60
-rw-r--r--webkit/glue/plugins/webview_plugin.cc217
-rw-r--r--webkit/glue/plugins/webview_plugin.h138
-rw-r--r--webkit/glue/resource_loader_bridge.cc5
-rw-r--r--webkit/glue/resource_loader_bridge.h11
-rw-r--r--webkit/glue/resources/webkit_strings_am.xtb2
-rw-r--r--webkit/glue/resources/webkit_strings_ar.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_bg.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_bn.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_ca.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_cs.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_da.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_de.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_el.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_en-GB.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_es-419.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_es.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_et.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_fa.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_fi.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_fil.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_fr.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_gu.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_hi.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_hr.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_hu.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_id.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_it.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_iw.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_ja.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_kn.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_ko.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_lt.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_lv.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_ml.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_mr.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_nl.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_no.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_pl.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_pt-BR.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_pt-PT.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_ro.xtb52
-rw-r--r--webkit/glue/resources/webkit_strings_ru.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_sk.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_sl.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_sr.xtb6
-rw-r--r--webkit/glue/resources/webkit_strings_sv.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_sw.xtb2
-rw-r--r--webkit/glue/resources/webkit_strings_ta.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_te.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_th.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_tr.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_uk.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_vi.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_zh-CN.xtb4
-rw-r--r--webkit/glue/resources/webkit_strings_zh-TW.xtb4
-rw-r--r--webkit/glue/webaccessibility.cc2
-rw-r--r--webkit/glue/webaccessibility.h2
-rw-r--r--webkit/glue/webcursor.cc36
-rw-r--r--webkit/glue/webcursor_mac.mm12
-rw-r--r--webkit/glue/webcursor_unittest.cc19
-rw-r--r--webkit/glue/webkit_glue.cc96
-rw-r--r--webkit/glue/webkit_glue.gypi309
-rw-r--r--webkit/glue/webkit_glue.h35
-rw-r--r--webkit/glue/webkitclient_impl.cc25
-rw-r--r--webkit/glue/webkitclient_impl.h3
-rw-r--r--webkit/glue/webmediaplayer_impl.cc30
-rw-r--r--webkit/glue/webmediaplayer_impl.h24
-rw-r--r--webkit/glue/webpreferences.cc24
-rw-r--r--webkit/glue/webpreferences.h14
-rw-r--r--webkit/glue/weburlloader_impl.cc29
4497 files changed, 192803 insertions, 206530 deletions
diff --git a/base/atomicops.h b/base/atomicops.h
index cf2f2bb..445696b 100644
--- a/base/atomicops.h
+++ b/base/atomicops.h
@@ -43,8 +43,14 @@ typedef __w64 int32 Atomic32;
#ifdef ARCH_CPU_64_BITS
// We need to be able to go between Atomic64 and AtomicWord implicitly. This
// means Atomic64 and AtomicWord should be the same type on 64-bit.
+#if defined(OS_NACL)
+// NaCl's intptr_t is not actually 64-bits on 64-bit!
+// http://code.google.com/p/nativeclient/issues/detail?id=1162
+typedef int64_t Atomic64;
+#else
typedef intptr_t Atomic64;
#endif
+#endif
// Use AtomicWord for a machine-sized pointer. It will use the Atomic32 or
// Atomic64 routines below, depending on your architecture.
diff --git a/base/base.gyp b/base/base.gyp
index f68359a..075561b 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -31,6 +31,8 @@
'base',
],
'sources': [
+ 'i18n/break_iterator.cc',
+ 'i18n/break_iterator.h',
'i18n/char_iterator.cc',
'i18n/char_iterator.h',
'i18n/file_util_icu.cc',
@@ -47,8 +49,6 @@
'i18n/rtl.h',
'i18n/time_formatting.cc',
'i18n/time_formatting.h',
- 'i18n/word_iterator.cc',
- 'i18n/word_iterator.h',
],
},
{
@@ -74,7 +74,6 @@
'crypto/signature_creator_unittest.cc',
'crypto/signature_verifier_unittest.cc',
'crypto/symmetric_key_unittest.cc',
- 'data_pack_unittest.cc',
'debug/leak_tracker_unittest.cc',
'debug/stack_trace_unittest.cc',
'debug/trace_event_win_unittest.cc',
@@ -87,11 +86,11 @@
'gmock_unittest.cc',
'hmac_unittest.cc',
'id_map_unittest.cc',
+ 'i18n/break_iterator_unittest.cc',
'i18n/char_iterator_unittest.cc',
'i18n/file_util_icu_unittest.cc',
'i18n/icu_string_conversions_unittest.cc',
'i18n/rtl_unittest.cc',
- 'i18n/word_iterator_unittest.cc',
'json/json_reader_unittest.cc',
'json/json_writer_unittest.cc',
'json/string_escape_unittest.cc',
@@ -141,6 +140,7 @@
'sys_string_conversions_mac_unittest.mm',
'sys_string_conversions_unittest.cc',
'task_queue_unittest.cc',
+ 'task_unittest.cc',
'thread_checker_unittest.cc',
'thread_collision_warner_unittest.cc',
'thread_local_storage_unittest.cc',
@@ -171,13 +171,9 @@
'win/scoped_bstr_unittest.cc',
'win/scoped_comptr_unittest.cc',
'win/scoped_variant_unittest.cc',
+ 'worker_pool_posix_unittest.cc',
'worker_pool_unittest.cc',
],
- 'include_dirs': [
- # word_iterator.h (used by word_iterator_unittest.cc) leaks an ICU
- # #include for unicode/uchar.h. This should probably be cleaned up.
- '../third_party/icu/public/common',
- ],
'dependencies': [
'base',
'base_i18n',
@@ -189,7 +185,6 @@
['OS == "linux" or OS == "freebsd" or OS == "openbsd" or OS == "solaris"', {
'sources!': [
'file_version_info_unittest.cc',
- 'worker_pool_linux_unittest.cc',
],
'sources': [
'nix/xdg_util_unittest.cc',
@@ -222,6 +217,7 @@
'sources!': [
'dir_reader_posix_unittest.cc',
'file_descriptor_shuffle_unittest.cc',
+ 'worker_pool_posix_unittest.cc',
],
}, { # OS != "win"
'sources/': [
@@ -261,6 +257,8 @@
],
'sources': [
'perftimer.cc',
+ 'test/mock_chrome_application_mac.h',
+ 'test/mock_chrome_application_mac.mm',
'test/multiprocess_test.cc',
'test/multiprocess_test.h',
'test/perf_test_suite.cc',
diff --git a/base/base.gypi b/base/base.gypi
index a71ccf4..3eaedfa 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -6,7 +6,6 @@
'target_defaults': {
'variables': {
'base_target': 0,
- 'base_extra_target': 0,
},
'target_conditions': [
# This part is shared between the targets defined below.
@@ -42,9 +41,6 @@
'callback.h',
'cancellation_flag.cc',
'cancellation_flag.h',
- 'chrome_application_mac.h',
- 'chrome_application_mac.mm',
- 'cocoa_protocols_mac.h',
'command_line.cc',
'command_line.h',
'compiler_specific.h',
@@ -120,6 +116,7 @@
'logging_win.cc',
'mac_util.h',
'mac_util.mm',
+ 'mac/cocoa_protocols.h',
'mac/scoped_aedesc.h',
'mac/scoped_cftyperef.h',
'mac/scoped_nsautorelease_pool.h',
@@ -272,7 +269,6 @@
'tracked_objects.cc',
'tracked_objects.h',
'tuple.h',
- 'unix_domain_socket_posix.cc',
'utf_offset_string_conversions.cc',
'utf_offset_string_conversions.h',
'utf_string_conversion_utils.cc',
@@ -323,10 +319,8 @@
'win_util.cc',
'win_util.h',
'worker_pool.h',
- 'worker_pool_linux.cc',
- 'worker_pool_linux.h',
- 'worker_pool_mac.h',
- 'worker_pool_mac.mm',
+ 'worker_pool_posix.cc',
+ 'worker_pool_posix.h',
'worker_pool_win.cc',
'nix/xdg_util.h',
'nix/xdg_util.cc',
@@ -363,13 +357,6 @@
],
},
],
- # Temporarily include linux implementation while debugging a
- # workerpool issue. See http://crbug.com/20471 and
- # http://crbug.com/60426
- [ 'OS == "mac"', {
- 'sources/': [ ['include', '(^|/)worker_pool_linux\.cc$'] ],
- },
- ],
[ 'OS != "mac"', {
'sources!': [
'scoped_aedesc.h'
@@ -406,180 +393,6 @@
},],
],
}],
- ['base_extra_target==1', {
- 'sources': [
- 'crypto/capi_util.cc',
- 'crypto/capi_util.h',
- 'crypto/cssm_init.cc',
- 'crypto/cssm_init.h',
- 'crypto/encryptor.h',
- 'crypto/encryptor_mac.cc',
- 'crypto/encryptor_nss.cc',
- 'crypto/encryptor_openssl.cc',
- 'crypto/encryptor_win.cc',
- 'crypto/rsa_private_key.h',
- 'crypto/rsa_private_key.cc',
- 'crypto/rsa_private_key_mac.cc',
- 'crypto/rsa_private_key_nss.cc',
- 'crypto/rsa_private_key_openssl.cc',
- 'crypto/rsa_private_key_win.cc',
- 'crypto/signature_creator.h',
- 'crypto/signature_creator_mac.cc',
- 'crypto/signature_creator_nss.cc',
- 'crypto/signature_creator_openssl.cc',
- 'crypto/signature_creator_win.cc',
- 'crypto/signature_verifier.h',
- 'crypto/signature_verifier_mac.cc',
- 'crypto/signature_verifier_nss.cc',
- 'crypto/signature_verifier_openssl.cc',
- 'crypto/signature_verifier_win.cc',
- 'crypto/symmetric_key.h',
- 'crypto/symmetric_key_mac.cc',
- 'crypto/symmetric_key_nss.cc',
- 'crypto/symmetric_key_openssl.cc',
- 'crypto/symmetric_key_win.cc',
- 'third_party/nspr/prcpucfg.h',
- 'third_party/nspr/prcpucfg_win.h',
- 'third_party/nspr/prtypes.h',
- 'third_party/nss/blapi.h',
- 'third_party/nss/blapit.h',
- 'third_party/nss/sha256.h',
- 'third_party/nss/sha512.cc',
- 'third_party/purify/pure.h',
- 'third_party/purify/pure_api.c',
- 'third_party/xdg_user_dirs/xdg_user_dir_lookup.cc',
- 'third_party/xdg_user_dirs/xdg_user_dir_lookup.h',
- 'auto_reset.h',
- 'base64.cc',
- 'base64.h',
- 'data_pack.cc',
- 'event_recorder.cc',
- 'event_recorder.h',
- 'event_recorder_stubs.cc',
- 'file_descriptor_shuffle.cc',
- 'file_descriptor_shuffle.h',
- 'hmac.h',
- 'hmac_mac.cc',
- 'hmac_nss.cc',
- 'hmac_openssl.cc',
- 'hmac_win.cc',
- 'image_util.cc',
- 'image_util.h',
- 'linux_util.cc',
- 'linux_util.h',
- 'md5.cc',
- 'md5.h',
- 'message_pump_glib.cc',
- 'message_pump_glib.h',
- 'message_pump_glib_x.cc',
- 'message_pump_glib_x.h',
- 'message_pump_glib_x_dispatch.h',
- 'message_pump_libevent.cc',
- 'message_pump_libevent.h',
- 'message_pump_mac.h',
- 'message_pump_mac.mm',
- 'metrics/field_trial.cc',
- 'metrics/field_trial.h',
- 'nsimage_cache_mac.h',
- 'nsimage_cache_mac.mm',
- 'nss_util.cc',
- 'nss_util.h',
- 'openssl_util.cc',
- 'openssl_util.h',
- 'setproctitle_linux.c',
- 'setproctitle_linux.h',
- 'sha2.cc',
- 'sha2.h',
- 'sha2_openssl.cc',
- 'string16.cc',
- 'string16.h',
- 'sync_socket.h',
- 'sync_socket_win.cc',
- 'sync_socket_posix.cc',
- 'time_mac.cc',
- 'time_posix.cc',
- ],
- 'conditions': [
- [ 'OS == "linux" or OS == "freebsd" or OS == "openbsd" or OS == "solaris"', {
- 'conditions': [
- [ 'chromeos==1', {
- 'sources/': [ ['include', '_chromeos\\.cc$'] ]
- },
- ],
- ],
- 'defines': [
- 'USE_SYMBOLIZE',
- ],
- 'cflags': [
- '-Wno-write-strings',
- ],
- }, { # OS != "linux" and OS != "freebsd" and OS != "openbsd" and OS != "solaris"
- 'sources/': [
- ['exclude', '/xdg_user_dirs/'],
- ['exclude', '_nss\.cc$'],
- ],
- }],
- [ 'OS != "mac"', {
- 'sources!': [
- 'crypto/cssm_init.cc',
- 'crypto/cssm_init.h',
- ],
- },],
- [ 'OS != "win"', {
- 'sources!': [
- 'third_party/purify/pure_api.c',
- 'base_drag_source.cc',
- 'base_drop_target.cc',
- 'cpu.cc',
- 'crypto/capi_util.h',
- 'crypto/capi_util.cc',
- 'debug_on_start.cc',
- 'event_recorder.cc',
- 'file_version_info.cc',
- 'image_util.cc',
- 'object_watcher.cc',
- 'pe_image.cc',
- 'registry.cc',
- 'resource_util.cc',
- 'win_util.cc',
- ],
- },],
- [ 'use_openssl==1', {
- # TODO(joth): Use a glob to match exclude patterns once the
- # OpenSSL file set is complete.
- 'sources!': [
- 'crypto/encryptor_nss.cc',
- 'crypto/rsa_private_key_nss.cc',
- 'crypto/signature_creator_nss.cc',
- 'crypto/signature_verifier_nss.cc',
- 'crypto/symmetric_key_nss.cc',
- 'hmac_nss.cc',
- 'nss_util.cc',
- 'nss_util.h',
- # Note that sha2.cc depends on the NSS files bundled into
- # chromium; it does not have the _nss postfix as it is required
- # on platforms besides linux and *bsd.
- 'sha2.cc',
- 'third_party/nss/blapi.h',
- 'third_party/nss/blapit.h',
- 'third_party/nss/sha256.h',
- 'third_party/nss/sha512.cc',
- ],
- }, {
- 'sources!': [
- 'crypto/encryptor_openssl.cc',
- 'crypto/rsa_private_key_openssl.cc',
- 'crypto/signature_creator_openssl.cc',
- 'crypto/signature_verifier_openssl.cc',
- 'crypto/symmetric_key_openssl.cc',
- 'hmac_openssl.cc',
- 'openssl_util.cc',
- 'openssl_util.h',
- 'sha2_openssl.cc',
- ],
- },],
- ],
- }],
],
},
'targets': [
@@ -589,7 +402,6 @@
'msvs_guid': '1832A374-8A74-4F9E-B536-69A699B3E165',
'variables': {
'base_target': 1,
- 'base_extra_target': 1,
},
'dependencies': [
'../third_party/modp_b64/modp_b64.gyp:modp_b64',
@@ -603,8 +415,12 @@
],
},
'conditions': [
- [ 'OS == "linux" or OS == "freebsd" or OS == "openbsd"', {
+ [ 'OS == "linux" or OS == "freebsd" or OS == "openbsd" or OS == "solaris"', {
'conditions': [
+ [ 'chromeos==1', {
+ 'sources/': [ ['include', '_chromeos\\.cc$'] ]
+ },
+ ],
[ 'linux_use_tcmalloc==0', {
'defines': [
'NO_TCMALLOC',
@@ -618,7 +434,7 @@
],
[ 'use_openssl==1', {
'dependencies': [
- '../build/linux/system.gyp:openssl',
+ '../third_party/openssl/openssl.gyp:openssl',
],
}, { # use_openssl==0
'dependencies': [
@@ -634,11 +450,22 @@
'../build/linux/system.gyp:x11',
'xdg_mime',
],
+ 'defines': [
+ 'USE_SYMBOLIZE',
+ ],
+ 'cflags': [
+ '-Wno-write-strings',
+ ],
'export_dependent_settings': [
'../build/linux/system.gyp:gtk',
'../build/linux/system.gyp:x11',
],
- },],
+ }, { # OS != "linux" and OS != "freebsd" and OS != "openbsd" and OS != "solaris"
+ 'sources/': [
+ ['exclude', '/xdg_user_dirs/'],
+ ['exclude', '_nss\.cc$'],
+ ],
+ }],
[ 'OS == "freebsd" or OS == "openbsd"', {
'link_settings': {
'libraries': [
@@ -668,7 +495,12 @@
'$(SDKROOT)/System/Library/Frameworks/Security.framework',
],
},
- },],
+ }, { # OS != "mac"
+ 'sources!': [
+ 'crypto/cssm_init.cc',
+ 'crypto/cssm_init.h',
+ ],
+ }],
[ 'OS == "mac" or OS == "win"', {
'dependencies': [
'../third_party/nss/nss.gyp:nss',
@@ -676,8 +508,145 @@
},],
[ 'OS != "win"', {
'dependencies': ['../third_party/libevent/libevent.gyp:libevent'],
+ 'sources!': [
+ 'third_party/purify/pure_api.c',
+ 'base_drag_source.cc',
+ 'base_drop_target.cc',
+ 'cpu.cc',
+ 'crypto/capi_util.h',
+ 'crypto/capi_util.cc',
+ 'debug_on_start.cc',
+ 'event_recorder.cc',
+ 'file_version_info.cc',
+ 'object_watcher.cc',
+ 'pe_image.cc',
+ 'registry.cc',
+ 'resource_util.cc',
+ 'win_util.cc',
+ ],
+ },],
+ [ 'use_openssl==1', {
+ # TODO(joth): Use a glob to match exclude patterns once the
+ # OpenSSL file set is complete.
+ 'sources!': [
+ 'crypto/encryptor_nss.cc',
+ 'crypto/rsa_private_key_nss.cc',
+ 'crypto/signature_creator_nss.cc',
+ 'crypto/signature_verifier_nss.cc',
+ 'crypto/symmetric_key_nss.cc',
+ 'hmac_nss.cc',
+ 'nss_util.cc',
+ 'nss_util.h',
+ # Note that sha2.cc depends on the NSS files bundled into
+ # chromium; it does not have the _nss postfix as it is required
+ # on platforms besides linux and *bsd.
+ 'sha2.cc',
+ 'third_party/nss/blapi.h',
+ 'third_party/nss/blapit.h',
+ 'third_party/nss/sha256.h',
+ 'third_party/nss/sha512.cc',
+ ],
+ }, {
+ 'sources!': [
+ 'crypto/encryptor_openssl.cc',
+ 'crypto/rsa_private_key_openssl.cc',
+ 'crypto/signature_creator_openssl.cc',
+ 'crypto/signature_verifier_openssl.cc',
+ 'crypto/symmetric_key_openssl.cc',
+ 'hmac_openssl.cc',
+ 'openssl_util.cc',
+ 'openssl_util.h',
+ 'sha2_openssl.cc',
+ ],
},],
],
+ 'sources': [
+ 'crypto/capi_util.cc',
+ 'crypto/capi_util.h',
+ 'crypto/cssm_init.cc',
+ 'crypto/cssm_init.h',
+ 'crypto/encryptor.h',
+ 'crypto/encryptor_mac.cc',
+ 'crypto/encryptor_nss.cc',
+ 'crypto/encryptor_openssl.cc',
+ 'crypto/encryptor_win.cc',
+ 'crypto/rsa_private_key.h',
+ 'crypto/rsa_private_key.cc',
+ 'crypto/rsa_private_key_mac.cc',
+ 'crypto/rsa_private_key_nss.cc',
+ 'crypto/rsa_private_key_openssl.cc',
+ 'crypto/rsa_private_key_win.cc',
+ 'crypto/signature_creator.h',
+ 'crypto/signature_creator_mac.cc',
+ 'crypto/signature_creator_nss.cc',
+ 'crypto/signature_creator_openssl.cc',
+ 'crypto/signature_creator_win.cc',
+ 'crypto/signature_verifier.h',
+ 'crypto/signature_verifier_mac.cc',
+ 'crypto/signature_verifier_nss.cc',
+ 'crypto/signature_verifier_openssl.cc',
+ 'crypto/signature_verifier_win.cc',
+ 'crypto/symmetric_key.h',
+ 'crypto/symmetric_key_mac.cc',
+ 'crypto/symmetric_key_nss.cc',
+ 'crypto/symmetric_key_openssl.cc',
+ 'crypto/symmetric_key_win.cc',
+ 'third_party/nspr/prcpucfg.h',
+ 'third_party/nspr/prcpucfg_win.h',
+ 'third_party/nspr/prtypes.h',
+ 'third_party/nss/blapi.h',
+ 'third_party/nss/blapit.h',
+ 'third_party/nss/sha256.h',
+ 'third_party/nss/sha512.cc',
+ 'third_party/purify/pure.h',
+ 'third_party/purify/pure_api.c',
+ 'third_party/xdg_user_dirs/xdg_user_dir_lookup.cc',
+ 'third_party/xdg_user_dirs/xdg_user_dir_lookup.h',
+ 'auto_reset.h',
+ 'base64.cc',
+ 'base64.h',
+ 'event_recorder.cc',
+ 'event_recorder.h',
+ 'event_recorder_stubs.cc',
+ 'file_descriptor_shuffle.cc',
+ 'file_descriptor_shuffle.h',
+ 'hmac.h',
+ 'hmac_mac.cc',
+ 'hmac_nss.cc',
+ 'hmac_openssl.cc',
+ 'hmac_win.cc',
+ 'linux_util.cc',
+ 'linux_util.h',
+ 'md5.cc',
+ 'md5.h',
+ 'message_pump_glib.cc',
+ 'message_pump_glib.h',
+ 'message_pump_glib_x.cc',
+ 'message_pump_glib_x.h',
+ 'message_pump_glib_x_dispatch.h',
+ 'message_pump_libevent.cc',
+ 'message_pump_libevent.h',
+ 'message_pump_mac.h',
+ 'message_pump_mac.mm',
+ 'metrics/field_trial.cc',
+ 'metrics/field_trial.h',
+ 'nss_util.cc',
+ 'nss_util.h',
+ 'openssl_util.cc',
+ 'openssl_util.h',
+ 'setproctitle_linux.c',
+ 'setproctitle_linux.h',
+ 'sha2.cc',
+ 'sha2.h',
+ 'sha2_openssl.cc',
+ 'string16.cc',
+ 'string16.h',
+ 'sync_socket.h',
+ 'sync_socket_win.cc',
+ 'sync_socket_posix.cc',
+ 'time_mac.cc',
+ 'time_posix.cc',
+ ],
},
],
'conditions': [
@@ -714,59 +683,6 @@
},
],
}],
- [ 'OS == "linux" and internal_pdf', {
- 'targets': [
- {
- 'target_name': 'base_fpic',
- 'type': '<(library)',
- 'variables': {
- 'base_target': 1,
- 'base_extra_target': 1,
- },
- 'cflags': [
- '-fPIC',
- ],
- 'direct_dependent_settings': {
- 'include_dirs': [
- '..',
- ],
- },
- 'conditions': [
- [ 'OS == "linux" or OS == "freebsd" or OS == "openbsd"', {
- 'dependencies': [
- '../build/util/build_util.gyp:lastchange',
- '../build/linux/system.gyp:gtk',
- '../build/linux/system.gyp:nss',
- '../build/linux/system.gyp:x11',
- 'xdg_mime',
- ],
- 'export_dependent_settings': [
- '../build/linux/system.gyp:gtk',
- '../build/linux/system.gyp:x11',
- ],
- },],
- ['OS == "linux"', {
- 'link_settings': {
- 'libraries': [
- # We need rt for clock_gettime().
- '-lrt',
- # For 'native_library_linux.cc'
- '-ldl',
- ],
- },
- }],
- [ 'OS == "mac" or OS == "win"', {
- 'dependencies': [
- '../third_party/nss/nss.gyp:nss',
- ],
- },],
- [ 'OS != "win"', {
- 'dependencies': ['../third_party/libevent/libevent.gyp:libevent'],
- },],
- ],
- },
- ],
- }],
[ 'OS == "linux" or OS == "freebsd" or OS == "openbsd" or OS == "solaris"', {
'targets': [
{
diff --git a/base/base_paths_linux.cc b/base/base_paths_linux.cc
index b2f2b57..48db3f8 100644
--- a/base/base_paths_linux.cc
+++ b/base/base_paths_linux.cc
@@ -37,14 +37,12 @@ bool PathProviderPosix(int key, FilePath* result) {
case base::FILE_EXE:
case base::FILE_MODULE: { // TODO(evanm): is this correct?
#if defined(OS_LINUX)
- char bin_dir[PATH_MAX + 1];
- int bin_dir_size = readlink(kSelfExe, bin_dir, PATH_MAX);
- if (bin_dir_size < 0 || bin_dir_size > PATH_MAX) {
+ FilePath bin_dir;
+ if (!file_util::ReadSymbolicLink(FilePath(kSelfExe), &bin_dir)) {
NOTREACHED() << "Unable to resolve " << kSelfExe << ".";
return false;
}
- bin_dir[bin_dir_size] = 0;
- *result = FilePath(bin_dir);
+ *result = bin_dir;
return true;
#elif defined(OS_FREEBSD)
int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
@@ -76,7 +74,7 @@ bool PathProviderPosix(int key, FilePath* result) {
}
}
// On POSIX, unit tests execute two levels deep from the source root.
- // For example: sconsbuild/{Debug|Release}/net_unittest
+ // For example: out/{Debug|Release}/net_unittest
if (PathService::Get(base::DIR_EXE, &path)) {
path = path.DirName().DirName();
if (file_util::PathExists(path.Append(kThisSourceFile))) {
diff --git a/base/callback.h b/base/callback.h
index 7f2eb70..e5ea771 100644
--- a/base/callback.h
+++ b/base/callback.h
@@ -206,8 +206,9 @@ template <class T, class Method, class Params>
class UnboundMethod {
public:
UnboundMethod(Method m, const Params& p) : m_(m), p_(p) {
- COMPILE_ASSERT((MethodUsesScopedRefptrCorrectly<Method, Params>::value),
- badunboundmethodparams);
+ COMPILE_ASSERT(
+ (base::internal::ParamsUseScopedRefptrCorrectly<Params>::value),
+ badunboundmethodparams);
}
void Run(T* obj) const {
DispatchToMethod(obj, m_, p_);
diff --git a/base/chrome_application_mac.h b/base/chrome_application_mac.h
deleted file mode 100644
index 676959e..0000000
--- a/base/chrome_application_mac.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) 2009 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 BASE_CHROME_APPLICATION_MAC_H_
-#define BASE_CHROME_APPLICATION_MAC_H_
-#pragma once
-
-#import <AppKit/AppKit.h>
-
-#include "base/basictypes.h"
-#include "base/scoped_nsobject.h"
-
-// Event hooks must implement this protocol.
-@protocol CrApplicationEventHookProtocol
-- (void)hookForEvent:(NSEvent*)theEvent;
-@end
-
-
-@interface CrApplication : NSApplication {
- @private
- BOOL handlingSendEvent_;
- // Array of objects implementing the CrApplicationEventHookProtocol
- scoped_nsobject<NSMutableArray> eventHooks_;
-}
-@property(readonly,
- getter=isHandlingSendEvent,
- nonatomic) BOOL handlingSendEvent;
-
-// Add or remove an event hook to be called for every sendEvent:
-// that the application receives. These handlers are called before
-// the normal [NSApplication sendEvent:] call is made.
-
-// This is not a good alternative to a nested event loop. It should
-// be used only when normal event logic and notification breaks down
-// (e.g. when clicking outside a canBecomeKey:NO window to "switch
-// context" out of it).
-- (void)addEventHook:(id<CrApplicationEventHookProtocol>)hook;
-- (void)removeEventHook:(id<CrApplicationEventHookProtocol>)hook;
-
-+ (NSApplication*)sharedApplication;
-@end
-
-namespace chrome_application_mac {
-
-// Controls the state of |handlingSendEvent_| in the event loop so that it is
-// reset properly.
-class ScopedSendingEvent {
- public:
- ScopedSendingEvent();
- ~ScopedSendingEvent();
-
- private:
- CrApplication* app_;
- BOOL handling_;
- DISALLOW_COPY_AND_ASSIGN(ScopedSendingEvent);
-};
-
-} // chrome_application_mac
-
-#endif // BASE_CHROME_APPLICATION_MAC_H_
diff --git a/base/chrome_application_mac.mm b/base/chrome_application_mac.mm
deleted file mode 100644
index a163534..0000000
--- a/base/chrome_application_mac.mm
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright (c) 2009 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 "chrome_application_mac.h"
-
-#include "base/logging.h"
-
-@interface CrApplication ()
-@property(readwrite,
- getter=isHandlingSendEvent,
- nonatomic) BOOL handlingSendEvent;
-@end
-
-@implementation CrApplication
-@synthesize handlingSendEvent = handlingSendEvent_;
-
-// Initialize NSApplication using the custom subclass. Check whether NSApp
-// was already initialized using another class, because that would break
-// some things.
-+ (NSApplication*)sharedApplication {
- NSApplication* app = [super sharedApplication];
- if (![NSApp isKindOfClass:self]) {
- LOG(ERROR) << "NSApp should be of type " << [[self className] UTF8String]
- << ", not " << [[NSApp className] UTF8String];
- DCHECK(false) << "NSApp is of wrong type";
- }
- return app;
-}
-
-- (id)init {
- if ((self = [super init])) {
- eventHooks_.reset([[NSMutableArray alloc] init]);
- }
- return self;
-}
-
-- (void)sendEvent:(NSEvent*)event {
- chrome_application_mac::ScopedSendingEvent sendingEventScoper;
- for (id<CrApplicationEventHookProtocol> handler in eventHooks_.get()) {
- [handler hookForEvent:event];
- }
- [super sendEvent:event];
-}
-
-- (void)addEventHook:(id<CrApplicationEventHookProtocol>)handler {
- [eventHooks_ addObject:handler];
-}
-
-- (void)removeEventHook:(id<CrApplicationEventHookProtocol>)handler {
- [eventHooks_ removeObject:handler];
-}
-
-@end
-
-namespace chrome_application_mac {
-
-ScopedSendingEvent::ScopedSendingEvent()
- : app_(static_cast<CrApplication*>([CrApplication sharedApplication])),
- handling_([app_ isHandlingSendEvent]) {
- [app_ setHandlingSendEvent:YES];
-}
-
-ScopedSendingEvent::~ScopedSendingEvent() {
- [app_ setHandlingSendEvent:handling_];
-}
-
-} // namespace chrome_application_mac
diff --git a/base/command_line.cc b/base/command_line.cc
index b335e7c..70d6872 100644
--- a/base/command_line.cc
+++ b/base/command_line.cc
@@ -19,6 +19,7 @@
#include <algorithm>
#include "base/file_path.h"
+#include "base/file_util.h"
#include "base/logging.h"
#include "base/singleton.h"
#include "base/string_split.h"
@@ -237,13 +238,11 @@ void CommandLine::SetProcTitle() {
// show up as "exe" in process listings. Read the symlink /proc/self/exe and
// use the path it points at for our process title. Note that this is only for
// display purposes and has no TOCTTOU security implications.
- char buffer[PATH_MAX];
- // Note: readlink() does not append a null byte to terminate the string.
- ssize_t length = readlink("/proc/self/exe", buffer, sizeof(buffer));
- DCHECK(length <= static_cast<ssize_t>(sizeof(buffer)));
- if (length > 0) {
+ FilePath target;
+ FilePath self_exe("/proc/self/exe");
+ if (file_util::ReadSymbolicLink(self_exe, &target)) {
have_argv0 = true;
- title.assign(buffer, length);
+ title = target.value();
// If the binary has since been deleted, Linux appends " (deleted)" to the
// symlink target. Remove it, since this is not really part of our name.
const std::string kDeletedSuffix = " (deleted)";
@@ -288,13 +287,6 @@ bool CommandLine::HasSwitch(const std::string& switch_string) const {
return switches_.find(lowercased_switch) != switches_.end();
}
-#if defined(OS_WIN)
-// Deprecated; still temporarily available on Windows.
-bool CommandLine::HasSwitch(const std::wstring& switch_string) const {
- return HasSwitch(WideToASCII(switch_string));
-}
-#endif
-
std::string CommandLine::GetSwitchValueASCII(
const std::string& switch_string) const {
CommandLine::StringType value = GetSwitchValueNative(switch_string);
diff --git a/base/command_line.h b/base/command_line.h
index a5bdd1a..df0293c 100644
--- a/base/command_line.h
+++ b/base/command_line.h
@@ -161,13 +161,6 @@ class CommandLine {
void CopySwitchesFrom(const CommandLine& source, const char* const switches[],
size_t count);
- // APIs that work with wstrings are deprecated.
- // TODO(evanm): remove all of these.
-#if defined(OS_WIN)
- // Deprecated on non-Windows.
- bool HasSwitch(const std::wstring& switch_string) const;
-#endif
-
private:
friend class InProcessBrowserTest;
diff --git a/base/crypto/cssm_init.cc b/base/crypto/cssm_init.cc
index b04cbe7..46a6ffe 100644
--- a/base/crypto/cssm_init.cc
+++ b/base/crypto/cssm_init.cc
@@ -22,6 +22,13 @@ namespace {
class CSSMInitSingleton {
public:
+ static CSSMInitSingleton* GetInstance() {
+ return Singleton<CSSMInitSingleton>::get();
+ }
+
+ CSSM_CSP_HANDLE csp_handle() const {return csp_handle_;}
+
+ private:
CSSMInitSingleton() : inited_(false), loaded_(false), csp_handle_(NULL) {
static CSSM_VERSION version = {2, 0};
// TODO(wtc): what should our caller GUID be?
@@ -68,18 +75,21 @@ class CSSMInitSingleton {
}
}
- CSSM_CSP_HANDLE csp_handle() const {return csp_handle_;}
-
- private:
bool inited_; // True if CSSM_Init has been called successfully.
bool loaded_; // True if CSSM_ModuleLoad has been called successfully.
CSSM_CSP_HANDLE csp_handle_;
+
+ friend struct DefaultSingletonTraits<CSSMInitSingleton>;
};
// This singleton is separate as it pertains to Apple's wrappers over
// their own CSSM handles, as opposed to our own CSSM_CSP_HANDLE.
class SecurityServicesSingleton {
public:
+ static SecurityServicesSingleton* GetInstance() {
+ return Singleton<SecurityServicesSingleton>::get();
+ }
+
~SecurityServicesSingleton() {}
Lock& lock() { return lock_; }
@@ -100,11 +110,11 @@ class SecurityServicesSingleton {
namespace base {
void EnsureCSSMInit() {
- Singleton<CSSMInitSingleton>::get();
+ CSSMInitSingleton::GetInstance();
}
CSSM_CSP_HANDLE GetSharedCSPHandle() {
- return Singleton<CSSMInitSingleton>::get()->csp_handle();
+ return CSSMInitSingleton::GetInstance()->csp_handle();
}
void* CSSMMalloc(CSSM_SIZE size, void *alloc_ref) {
@@ -145,7 +155,7 @@ void LogCSSMError(const char *fn_name, CSSM_RETURN err) {
}
Lock& GetMacSecurityServicesLock() {
- return Singleton<SecurityServicesSingleton>::get()->lock();
+ return SecurityServicesSingleton::GetInstance()->lock();
}
} // namespace base
diff --git a/base/crypto/rsa_private_key.h b/base/crypto/rsa_private_key.h
index ecec015..bac4250 100644
--- a/base/crypto/rsa_private_key.h
+++ b/base/crypto/rsa_private_key.h
@@ -165,6 +165,7 @@ class PrivateKeyInfoCodec {
// Encapsulates an RSA private key. Can be used to generate new keys, export
// keys to other formats, or to extract a public key.
+// TODO(hclam): This class should be ref-counted so it can be reused easily.
class RSAPrivateKey {
public:
// Create a new random instance. Can return NULL if initialization fails.
@@ -208,6 +209,7 @@ class RSAPrivateKey {
EVP_PKEY* key() { return key_; }
#elif defined(USE_NSS)
SECKEYPrivateKeyStr* key() { return key_; }
+ SECKEYPublicKeyStr* public_key() { return public_key_; }
#elif defined(OS_WIN)
HCRYPTPROV provider() { return provider_; }
HCRYPTKEY key() { return key_; }
diff --git a/base/crypto/rsa_private_key_openssl.cc b/base/crypto/rsa_private_key_openssl.cc
index 0776b63..891ea52 100644
--- a/base/crypto/rsa_private_key_openssl.cc
+++ b/base/crypto/rsa_private_key_openssl.cc
@@ -50,9 +50,13 @@ bool ExportKey(EVP_PKEY* key,
// static
RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) {
OpenSSLErrStackTracer err_tracer(FROM_HERE);
- ScopedOpenSSL<RSA, RSA_free> rsa_key(RSA_generate_key(num_bits, 65537L,
- NULL, NULL));
- if (!rsa_key.get())
+
+ ScopedOpenSSL<RSA, RSA_free> rsa_key(RSA_new());
+ ScopedOpenSSL<BIGNUM, BN_free> bn(BN_new());
+ if (!rsa_key.get() || !bn.get() || !BN_set_word(bn.get(), 65537L))
+ return NULL;
+
+ if (!RSA_generate_key_ex(rsa_key.get(), num_bits, bn.get(), NULL))
return NULL;
scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
@@ -75,7 +79,8 @@ RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
OpenSSLErrStackTracer err_tracer(FROM_HERE);
// BIO_new_mem_buf is not const aware, but it does not modify the buffer.
- char* data = reinterpret_cast<char*>(const_cast<uint8*>(input.data()));
+ char* data = reinterpret_cast<char*>(const_cast<uint8*>(
+ vector_as_array(&input)));
ScopedOpenSSL<BIO, BIO_free_all> bio(BIO_new_mem_buf(data, input.size()));
if (!bio.get())
return NULL;
diff --git a/base/crypto/signature_creator_openssl.cc b/base/crypto/signature_creator_openssl.cc
index 7eed379..5bdb783 100644
--- a/base/crypto/signature_creator_openssl.cc
+++ b/base/crypto/signature_creator_openssl.cc
@@ -9,6 +9,7 @@
#include "base/logging.h"
#include "base/openssl_util.h"
#include "base/scoped_ptr.h"
+#include "base/stl_util-inl.h"
namespace base {
@@ -41,7 +42,7 @@ bool SignatureCreator::Final(std::vector<uint8>* signature) {
signature->resize(EVP_PKEY_size(key));
unsigned int len = 0;
- int rv = EVP_SignFinal(sign_context_, signature->data(), &len, key);
+ int rv = EVP_SignFinal(sign_context_, vector_as_array(signature), &len, key);
if (!rv) {
signature->clear();
return false;
diff --git a/base/crypto/signature_verifier_openssl.cc b/base/crypto/signature_verifier_openssl.cc
index b4fff78..4850efa 100644
--- a/base/crypto/signature_verifier_openssl.cc
+++ b/base/crypto/signature_verifier_openssl.cc
@@ -12,6 +12,7 @@
#include "base/logging.h"
#include "base/openssl_util.h"
#include "base/scoped_ptr.h"
+#include "base/stl_util-inl.h"
namespace base {
@@ -77,7 +78,7 @@ bool SignatureVerifier::VerifyFinal() {
DCHECK(verify_context_);
OpenSSLErrStackTracer err_tracer(FROM_HERE);
int rv = EVP_VerifyFinal(verify_context_->ctx.get(),
- signature_.data(), signature_.size(),
+ vector_as_array(&signature_), signature_.size(),
verify_context_->public_key.get());
DCHECK_GE(rv, 0);
Reset();
diff --git a/base/data/data_pack_unittest/sample.pak b/base/data/data_pack_unittest/sample.pak
deleted file mode 100644
index fdbe2b5..0000000
--- a/base/data/data_pack_unittest/sample.pak
+++ /dev/null
Binary files differ
diff --git a/base/data_pack.cc b/base/data_pack.cc
deleted file mode 100644
index e01318f..0000000
--- a/base/data_pack.cc
+++ /dev/null
@@ -1,216 +0,0 @@
-// 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.
-
-#include "base/data_pack.h"
-
-#include <errno.h>
-
-#include "base/file_util.h"
-#include "base/logging.h"
-#include "base/metrics/histogram.h"
-#include "base/ref_counted_memory.h"
-#include "base/string_piece.h"
-
-// For details of the file layout, see
-// http://dev.chromium.org/developers/design-documents/linuxresourcesandlocalizedstrings
-
-namespace {
-
-// A word is four bytes.
-static const size_t kWord = 4;
-
-static const uint32 kFileFormatVersion = 1;
-// Length of file header: version and entry count.
-static const size_t kHeaderLength = 2 * sizeof(uint32);
-
-struct DataPackEntry {
- uint32 resource_id;
- uint32 file_offset;
- uint32 length;
-
- static int CompareById(const void* void_key, const void* void_entry) {
- uint32 key = *reinterpret_cast<const uint32*>(void_key);
- const DataPackEntry* entry =
- reinterpret_cast<const DataPackEntry*>(void_entry);
- if (key < entry->resource_id) {
- return -1;
- } else if (key > entry->resource_id) {
- return 1;
- } else {
- return 0;
- }
- }
-};
-
-COMPILE_ASSERT(sizeof(DataPackEntry) == 12, size_of_header_must_be_twelve);
-
-// We're crashing when trying to load a pak file on Windows. Add some error
-// codes for logging.
-// http://crbug.com/58056
-enum LoadErrors {
- INIT_FAILED = 1,
- BAD_VERSION,
- INDEX_TRUNCATED,
- ENTRY_NOT_FOUND,
-
- LOAD_ERRORS_COUNT,
-};
-
-} // anonymous namespace
-
-namespace base {
-
-// In .cc for MemoryMappedFile dtor.
-DataPack::DataPack() : resource_count_(0) {
-}
-DataPack::~DataPack() {
-}
-
-bool DataPack::Load(const FilePath& path) {
- mmap_.reset(new file_util::MemoryMappedFile);
- if (!mmap_->Initialize(path)) {
- DLOG(ERROR) << "Failed to mmap datapack";
- UMA_HISTOGRAM_ENUMERATION("DataPack.Load", INIT_FAILED,
- LOAD_ERRORS_COUNT);
- return false;
- }
-
- // Parse the header of the file.
- // First uint32: version; second: resource count.
- const uint32* ptr = reinterpret_cast<const uint32*>(mmap_->data());
- uint32 version = ptr[0];
- if (version != kFileFormatVersion) {
- LOG(ERROR) << "Bad data pack version: got " << version << ", expected "
- << kFileFormatVersion;
- UMA_HISTOGRAM_ENUMERATION("DataPack.Load", BAD_VERSION,
- LOAD_ERRORS_COUNT);
- mmap_.reset();
- return false;
- }
- resource_count_ = ptr[1];
-
- // Sanity check the file.
- // 1) Check we have enough entries.
- if (kHeaderLength + resource_count_ * sizeof(DataPackEntry) >
- mmap_->length()) {
- LOG(ERROR) << "Data pack file corruption: too short for number of "
- "entries specified.";
- UMA_HISTOGRAM_ENUMERATION("DataPack.Load", INDEX_TRUNCATED,
- LOAD_ERRORS_COUNT);
- mmap_.reset();
- return false;
- }
- // 2) Verify the entries are within the appropriate bounds.
- for (size_t i = 0; i < resource_count_; ++i) {
- const DataPackEntry* entry = reinterpret_cast<const DataPackEntry*>(
- mmap_->data() + kHeaderLength + (i * sizeof(DataPackEntry)));
- if (entry->file_offset + entry->length > mmap_->length()) {
- LOG(ERROR) << "Entry #" << i << " in data pack points off end of file. "
- << "Was the file corrupted?";
- UMA_HISTOGRAM_ENUMERATION("DataPack.Load", ENTRY_NOT_FOUND,
- LOAD_ERRORS_COUNT);
- mmap_.reset();
- return false;
- }
- }
-
- return true;
-}
-
-bool DataPack::GetStringPiece(uint32 resource_id, StringPiece* data) const {
- // It won't be hard to make this endian-agnostic, but it's not worth
- // bothering to do right now.
-#if defined(__BYTE_ORDER)
- // Linux check
- COMPILE_ASSERT(__BYTE_ORDER == __LITTLE_ENDIAN,
- datapack_assumes_little_endian);
-#elif defined(__BIG_ENDIAN__)
- // Mac check
- #error DataPack assumes little endian
-#endif
-
- DataPackEntry* target = reinterpret_cast<DataPackEntry*>(
- bsearch(&resource_id, mmap_->data() + kHeaderLength, resource_count_,
- sizeof(DataPackEntry), DataPackEntry::CompareById));
- if (!target) {
- return false;
- }
-
- data->set(mmap_->data() + target->file_offset, target->length);
- return true;
-}
-
-RefCountedStaticMemory* DataPack::GetStaticMemory(uint32 resource_id) const {
- base::StringPiece piece;
- if (!GetStringPiece(resource_id, &piece))
- return NULL;
-
- return new RefCountedStaticMemory(
- reinterpret_cast<const unsigned char*>(piece.data()), piece.length());
-}
-
-// static
-bool DataPack::WritePack(const FilePath& path,
- const std::map<uint32, StringPiece>& resources) {
- FILE* file = file_util::OpenFile(path, "wb");
- if (!file)
- return false;
-
- if (fwrite(&kFileFormatVersion, 1, kWord, file) != kWord) {
- LOG(ERROR) << "Failed to write file version";
- file_util::CloseFile(file);
- return false;
- }
-
- // Note: the python version of this function explicitly sorted keys, but
- // std::map is a sorted associative container, we shouldn't have to do that.
- uint32 entry_count = resources.size();
- if (fwrite(&entry_count, 1, kWord, file) != kWord) {
- LOG(ERROR) << "Failed to write entry count";
- file_util::CloseFile(file);
- return false;
- }
-
- // Each entry is 3 uint32s.
- uint32 index_length = entry_count * 3 * kWord;
- uint32 data_offset = kHeaderLength + index_length;
- for (std::map<uint32, StringPiece>::const_iterator it = resources.begin();
- it != resources.end(); ++it) {
- if (fwrite(&it->first, 1, kWord, file) != kWord) {
- LOG(ERROR) << "Failed to write id for " << it->first;
- file_util::CloseFile(file);
- return false;
- }
-
- if (fwrite(&data_offset, 1, kWord, file) != kWord) {
- LOG(ERROR) << "Failed to write offset for " << it->first;
- file_util::CloseFile(file);
- return false;
- }
-
- uint32 len = it->second.length();
- if (fwrite(&len, 1, kWord, file) != kWord) {
- LOG(ERROR) << "Failed to write length for " << it->first;
- file_util::CloseFile(file);
- return false;
- }
-
- data_offset += len;
- }
-
- for (std::map<uint32, StringPiece>::const_iterator it = resources.begin();
- it != resources.end(); ++it) {
- if (fwrite(it->second.data(), it->second.length(), 1, file) != 1) {
- LOG(ERROR) << "Failed to write data for " << it->first;
- file_util::CloseFile(file);
- return false;
- }
- }
-
- file_util::CloseFile(file);
-
- return true;
-}
-
-} // namespace base
diff --git a/base/data_pack.h b/base/data_pack.h
deleted file mode 100644
index 2836715..0000000
--- a/base/data_pack.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (c) 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.
-
-// DataPack represents a read-only view onto an on-disk file that contains
-// (key, value) pairs of data. It's used to store static resources like
-// translation strings and images.
-
-#ifndef BASE_DATA_PACK_H_
-#define BASE_DATA_PACK_H_
-#pragma once
-
-#include <map>
-
-#include "base/basictypes.h"
-#include "base/scoped_ptr.h"
-
-namespace file_util {
- class MemoryMappedFile;
-}
-class FilePath;
-class RefCountedStaticMemory;
-
-namespace base {
-
-class StringPiece;
-
-class DataPack {
- public:
- DataPack();
- ~DataPack();
-
- // Load a pack file from |path|, returning false on error.
- bool Load(const FilePath& path);
-
- // Get resource by id |resource_id|, filling in |data|.
- // The data is owned by the DataPack object and should not be modified.
- // Returns false if the resource id isn't found.
- bool GetStringPiece(uint32 resource_id, StringPiece* data) const;
-
- // Like GetStringPiece(), but returns a reference to memory. This interface
- // is used for image data, while the StringPiece interface is usually used
- // for localization strings.
- RefCountedStaticMemory* GetStaticMemory(uint32 resource_id) const;
-
- // Writes a pack file containing |resources| to |path|.
- static bool WritePack(const FilePath& path,
- const std::map<uint32, StringPiece>& resources);
-
- private:
- // The memory-mapped data.
- scoped_ptr<file_util::MemoryMappedFile> mmap_;
-
- // Number of resources in the data.
- size_t resource_count_;
-
- DISALLOW_COPY_AND_ASSIGN(DataPack);
-};
-
-} // namespace base
-
-#endif // BASE_DATA_PACK_H_
diff --git a/base/data_pack_unittest.cc b/base/data_pack_unittest.cc
deleted file mode 100644
index d089b28..0000000
--- a/base/data_pack_unittest.cc
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright (c) 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.
-
-#include "base/data_pack.h"
-
-#include "base/file_path.h"
-#include "base/file_util.h"
-#include "base/path_service.h"
-#include "base/scoped_temp_dir.h"
-#include "base/string_piece.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-TEST(DataPackTest, Load) {
- FilePath data_path;
- PathService::Get(base::DIR_SOURCE_ROOT, &data_path);
- data_path = data_path.Append(
- FILE_PATH_LITERAL("base/data/data_pack_unittest/sample.pak"));
-
- base::DataPack pack;
- ASSERT_TRUE(pack.Load(data_path));
-
- base::StringPiece data;
- ASSERT_TRUE(pack.GetStringPiece(4, &data));
- EXPECT_EQ("this is id 4", data);
- ASSERT_TRUE(pack.GetStringPiece(6, &data));
- EXPECT_EQ("this is id 6", data);
-
- // Try reading zero-length data blobs, just in case.
- ASSERT_TRUE(pack.GetStringPiece(1, &data));
- EXPECT_EQ(0U, data.length());
- ASSERT_TRUE(pack.GetStringPiece(10, &data));
- EXPECT_EQ(0U, data.length());
-
- // Try looking up an invalid key.
- ASSERT_FALSE(pack.GetStringPiece(140, &data));
-}
-
-TEST(DataPackTest, Write) {
- ScopedTempDir dir;
- ASSERT_TRUE(dir.CreateUniqueTempDir());
- FilePath file = dir.path().Append(FILE_PATH_LITERAL("data.pak"));
-
- std::string one("one");
- std::string two("two");
- std::string three("three");
- std::string four("four");
- std::string fifteen("fifteen");
-
- std::map<uint32, base::StringPiece> resources;
- resources.insert(std::make_pair(1, base::StringPiece(one)));
- resources.insert(std::make_pair(2, base::StringPiece(two)));
- resources.insert(std::make_pair(15, base::StringPiece(fifteen)));
- resources.insert(std::make_pair(3, base::StringPiece(three)));
- resources.insert(std::make_pair(4, base::StringPiece(four)));
- ASSERT_TRUE(base::DataPack::WritePack(file, resources));
-
- // Now try to read the data back in.
- base::DataPack pack;
- ASSERT_TRUE(pack.Load(file));
-
- base::StringPiece data;
- ASSERT_TRUE(pack.GetStringPiece(1, &data));
- EXPECT_EQ(one, data);
- ASSERT_TRUE(pack.GetStringPiece(2, &data));
- EXPECT_EQ(two, data);
- ASSERT_TRUE(pack.GetStringPiece(3, &data));
- EXPECT_EQ(three, data);
- ASSERT_TRUE(pack.GetStringPiece(4, &data));
- EXPECT_EQ(four, data);
- ASSERT_TRUE(pack.GetStringPiece(15, &data));
- EXPECT_EQ(fifteen, data);
-}
diff --git a/base/debug/debugger_posix.cc b/base/debug/debugger_posix.cc
index 2df3c4c..1e0c2ba 100644
--- a/base/debug/debugger_posix.cc
+++ b/base/debug/debugger_posix.cc
@@ -3,13 +3,16 @@
// found in the LICENSE file.
#include "base/debug/debugger.h"
+#include "build/build_config.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
+#if !defined(OS_NACL)
#include <sys/sysctl.h>
+#endif
#include <sys/types.h>
#include <unistd.h>
@@ -125,6 +128,13 @@ bool BeingDebugged() {
return pid_index < status.size() && status[pid_index] != '0';
}
+#elif defined(OS_NACL)
+
+bool BeingDebugged() {
+ NOTIMPLEMENTED();
+ return false;
+}
+
#elif defined(OS_FREEBSD)
bool DebugUtil::BeingDebugged() {
@@ -151,6 +161,11 @@ bool DebugUtil::BeingDebugged() {
#if defined(NDEBUG) && !defined(OS_MACOSX)
#define DEBUG_BREAK() abort()
+#elif defined(OS_NACL)
+// The NaCl verifier doesn't let use use int3. For now, we call abort(). We
+// should ask for advice from some NaCl experts about the optimum thing here.
+// http://code.google.com/p/nativeclient/issues/detail?id=645
+#define DEBUG_BREAK() abort()
#elif defined(ARCH_CPU_ARM_FAMILY)
#define DEBUG_BREAK() asm("bkpt 0")
#else
@@ -159,9 +174,6 @@ bool DebugUtil::BeingDebugged() {
void BreakDebugger() {
DEBUG_BREAK();
-#if defined(NDEBUG)
- _exit(1);
-#endif
}
} // namespace debug
diff --git a/base/debug/debugger_win.cc b/base/debug/debugger_win.cc
index 51a067e..d1d47cd 100644
--- a/base/debug/debugger_win.cc
+++ b/base/debug/debugger_win.cc
@@ -106,9 +106,6 @@ void BreakDebugger() {
if (DebugUtil::AreDialogsSuppressed())
_exit(1);
__debugbreak();
-#if defined(NDEBUG)
- _exit(1);
-#endif
}
} // namespace debug
diff --git a/base/debug/leak_tracker.h b/base/debug/leak_tracker.h
index 9709aa1..a8ea5f4 100644
--- a/base/debug/leak_tracker.h
+++ b/base/debug/leak_tracker.h
@@ -24,8 +24,8 @@
// before destroying that thread, one can check that there are no remaining
// instances of that class.
//
-// For example, to enable leak tracking for class URLRequest, start by
-// adding a member variable of type LeakTracker<URLRequest>.
+// For example, to enable leak tracking for class net::URLRequest, start by
+// adding a member variable of type LeakTracker<net::URLRequest>.
//
// class URLRequest {
// ...
@@ -34,11 +34,11 @@
// };
//
//
-// Next, when we believe all instances of URLRequest have been deleted:
+// Next, when we believe all instances of net::URLRequest have been deleted:
//
-// LeakTracker<URLRequest>::CheckForLeaks();
+// LeakTracker<net::URLRequest>::CheckForLeaks();
//
-// Should the check fail (because there are live instances of URLRequest),
+// Should the check fail (because there are live instances of net::URLRequest),
// then the allocation callstack for each leaked instances is dumped to
// the error log.
//
diff --git a/base/debug/stack_trace_posix.cc b/base/debug/stack_trace_posix.cc
index 5d5d88d..90e302e 100644
--- a/base/debug/stack_trace_posix.cc
+++ b/base/debug/stack_trace_posix.cc
@@ -56,9 +56,9 @@ const char kSymbolCharacters[] =
#if !defined(USE_SYMBOLIZE)
// Demangles C++ symbols in the given text. Example:
//
-// "sconsbuild/Debug/base_unittests(_ZN10StackTraceC1Ev+0x20) [0x817778c]"
+// "out/Debug/base_unittests(_ZN10StackTraceC1Ev+0x20) [0x817778c]"
// =>
-// "sconsbuild/Debug/base_unittests(StackTrace::StackTrace()+0x20) [0x817778c]"
+// "out/Debug/base_unittests(StackTrace::StackTrace()+0x20) [0x817778c]"
void DemangleSymbols(std::string* text) {
#if defined(__GLIBCXX__)
diff --git a/base/debug/stack_trace_win.cc b/base/debug/stack_trace_win.cc
index 653d234..6f4ad02 100644
--- a/base/debug/stack_trace_win.cc
+++ b/base/debug/stack_trace_win.cc
@@ -36,7 +36,7 @@ namespace {
// just ignore it.
class SymbolContext {
public:
- static SymbolContext* Get() {
+ static SymbolContext* GetInstance() {
// We use a leaky singleton because code may call this during process
// termination.
return
@@ -179,7 +179,7 @@ void StackTrace::PrintBacktrace() {
}
void StackTrace::OutputToStream(std::ostream* os) {
- SymbolContext* context = SymbolContext::Get();
+ SymbolContext* context = SymbolContext::GetInstance();
DWORD error = context->init_error();
if (error != ERROR_SUCCESS) {
(*os) << "Error initializing symbols (" << error
diff --git a/base/debug/trace_event.cc b/base/debug/trace_event.cc
index 616d7ca..9b9ed1f 100644
--- a/base/debug/trace_event.cc
+++ b/base/debug/trace_event.cc
@@ -49,15 +49,18 @@ TraceLog::~TraceLog() {
}
// static
+TraceLog* TraceLog::GetInstance() {
+ return Singleton<TraceLog, DefaultSingletonTraits<TraceLog> >::get();
+}
+
+// static
bool TraceLog::IsTracing() {
- TraceLog* trace = Singleton<TraceLog>::get();
- return trace->enabled_;
+ return TraceLog::GetInstance()->enabled_;
}
// static
bool TraceLog::StartTracing() {
- TraceLog* trace = Singleton<TraceLog>::get();
- return trace->Start();
+ return TraceLog::GetInstance()->Start();
}
bool TraceLog::Start() {
@@ -78,8 +81,7 @@ bool TraceLog::Start() {
// static
void TraceLog::StopTracing() {
- TraceLog* trace = Singleton<TraceLog>::get();
- return trace->Stop();
+ return TraceLog::GetInstance()->Stop();
}
void TraceLog::Stop() {
diff --git a/base/debug/trace_event.h b/base/debug/trace_event.h
index 38b4d05..476f065 100644
--- a/base/debug/trace_event.h
+++ b/base/debug/trace_event.h
@@ -52,7 +52,7 @@
// Record that an event (of name, id) has begun. All BEGIN events should have
// corresponding END events with a matching (name, id).
#define TRACE_EVENT_BEGIN(name, id, extra) \
- Singleton<base::debug::TraceLog>::get()->Trace( \
+ base::debug::TraceLog::GetInstance()->Trace( \
name, \
base::debug::TraceLog::EVENT_BEGIN, \
reinterpret_cast<const void*>(id), \
@@ -63,7 +63,7 @@
// Record that an event (of name, id) has ended. All END events should have
// corresponding BEGIN events with a matching (name, id).
#define TRACE_EVENT_END(name, id, extra) \
- Singleton<base::debug::TraceLog>::get()->Trace( \
+ base::debug::TraceLog::GetInstance()->Trace( \
name, \
base::debug::TraceLog::EVENT_END, \
reinterpret_cast<const void*>(id), \
@@ -73,7 +73,7 @@
// Record that an event (of name, id) with no duration has happened.
#define TRACE_EVENT_INSTANT(name, id, extra) \
- Singleton<base::debug::TraceLog>::get()->Trace( \
+ base::debug::TraceLog::GetInstance()->Trace( \
name, \
base::debug::TraceLog::EVENT_INSTANT, \
reinterpret_cast<const void*>(id), \
@@ -96,6 +96,8 @@ class TraceLog {
EVENT_INSTANT
};
+ static TraceLog* GetInstance();
+
// Is tracing currently enabled.
static bool IsTracing();
// Start logging trace events.
diff --git a/base/debug/trace_event_win.cc b/base/debug/trace_event_win.cc
index 8405699..005ff62 100644
--- a/base/debug/trace_event_win.cc
+++ b/base/debug/trace_event_win.cc
@@ -31,8 +31,8 @@ TraceLog::TraceLog() : EtwTraceProvider(kChromeTraceProviderName) {
Register();
}
-TraceLog* TraceLog::Get() {
- return Singleton<TraceLog, StaticMemorySingletonTraits<TraceLog>>::get();
+TraceLog* TraceLog::GetInstance() {
+ return Singleton<TraceLog, StaticMemorySingletonTraits<TraceLog> >::get();
}
bool TraceLog::StartTracing() {
@@ -99,7 +99,7 @@ void TraceLog::Trace(const char* name,
const void* id,
const char* extra,
size_t extra_len) {
- TraceLog* provider = TraceLog::Get();
+ TraceLog* provider = TraceLog::GetInstance();
if (provider && provider->IsTracing()) {
// Compute the name & extra lengths if not supplied already.
if (name_len == -1)
diff --git a/base/debug/trace_event_win.h b/base/debug/trace_event_win.h
index dd3f512..a1c79ba 100644
--- a/base/debug/trace_event_win.h
+++ b/base/debug/trace_event_win.h
@@ -85,7 +85,7 @@ class TraceLog : public base::win::EtwTraceProvider {
// Retrieves the singleton.
// Note that this may return NULL post-AtExit processing.
- static TraceLog* Get();
+ static TraceLog* GetInstance();
// Returns true iff tracing is turned on.
bool IsTracing() {
diff --git a/base/debug/trace_event_win_unittest.cc b/base/debug/trace_event_win_unittest.cc
index 8544bc7..4c5ed45 100644
--- a/base/debug/trace_event_win_unittest.cc
+++ b/base/debug/trace_event_win_unittest.cc
@@ -106,7 +106,7 @@ class TraceEventTest: public testing::Test {
TraceLog* tracelog = NULL;
if (!is_xp) {
TraceLog::Resurrect();
- tracelog = TraceLog::Get();
+ tracelog = TraceLog::GetInstance();
ASSERT_TRUE(tracelog != NULL);
ASSERT_FALSE(tracelog->IsTracing());
}
@@ -142,7 +142,7 @@ class TraceEventTest: public testing::Test {
if (is_xp) {
TraceLog::Resurrect();
- tracelog = TraceLog::Get();
+ tracelog = TraceLog::GetInstance();
}
ASSERT_TRUE(tracelog != NULL);
EXPECT_TRUE(tracelog->IsTracing());
diff --git a/base/file_descriptor_shuffle.h b/base/file_descriptor_shuffle.h
index a5c08e4..e193035 100644
--- a/base/file_descriptor_shuffle.h
+++ b/base/file_descriptor_shuffle.h
@@ -46,9 +46,9 @@ class InjectionDelegate {
// An implementation of the InjectionDelegate interface using the file
// descriptor table of the current process as the domain.
class FileDescriptorTableInjection : public InjectionDelegate {
- bool Duplicate(int* result, int fd);
- bool Move(int src, int dest);
- void Close(int fd);
+ virtual bool Duplicate(int* result, int fd);
+ virtual bool Move(int src, int dest);
+ virtual void Close(int fd);
};
// A single arc of the directed graph which describes an injective multimapping.
diff --git a/base/file_util.cc b/base/file_util.cc
index 254e649..2b5dc84 100644
--- a/base/file_util.cc
+++ b/base/file_util.cc
@@ -361,14 +361,6 @@ bool MemoryMappedFile::IsValid() {
// Deprecated functions ----------------------------------------------------
#if defined(OS_WIN)
-bool AbsolutePath(std::wstring* path_str) {
- FilePath path(FilePath::FromWStringHack(*path_str));
- if (!AbsolutePath(&path))
- return false;
- *path_str = path.ToWStringHack();
- return true;
-}
-
void AppendToPath(std::wstring* path, const std::wstring& new_ending) {
if (!path) {
NOTREACHED();
diff --git a/base/file_util_deprecated.h b/base/file_util_deprecated.h
index 45e60b7..9bafb31 100644
--- a/base/file_util_deprecated.h
+++ b/base/file_util_deprecated.h
@@ -49,8 +49,6 @@ void AppendToPath(std::wstring* path, const std::wstring& new_ending);
FilePath::StringType GetFileExtensionFromPath(const FilePath& path);
std::wstring GetFileExtensionFromPath(const std::wstring& path);
-bool AbsolutePath(std::wstring* path);
-
// Use version that takes a FilePath.
bool Delete(const std::wstring& path, bool recursive);
bool CopyDirectory(const std::wstring& from_path, const std::wstring& to_path,
diff --git a/base/file_util_posix.cc b/base/file_util_posix.cc
index 56b1ce0..ac6dabb 100644
--- a/base/file_util_posix.cc
+++ b/base/file_util_posix.cc
@@ -388,11 +388,12 @@ bool ReadSymbolicLink(const FilePath& symlink_path,
char buf[PATH_MAX];
ssize_t count = ::readlink(symlink_path.value().c_str(), buf, arraysize(buf));
- if (count <= 0)
+ if (count <= 0) {
+ target_path->clear();
return false;
+ }
*target_path = FilePath(FilePath::StringType(buf, count));
-
return true;
}
diff --git a/base/file_util_win.cc b/base/file_util_win.cc
index 4645acc..3ca52ae 100644
--- a/base/file_util_win.cc
+++ b/base/file_util_win.cc
@@ -163,6 +163,14 @@ bool Delete(const FilePath& path, bool recursive) {
if (!recursive)
file_operation.fFlags |= FOF_NORECURSION | FOF_FILESONLY;
int err = SHFileOperation(&file_operation);
+
+ // Since we're passing flags to the operation telling it to be silent,
+ // it's possible for the operation to be aborted/cancelled without err
+ // being set (although MSDN doesn't give any scenarios for how this can
+ // happen). See MSDN for SHFileOperation and SHFILEOPTSTRUCT.
+ if (file_operation.fAnyOperationsAborted)
+ return false;
+
// Some versions of Windows return ERROR_FILE_NOT_FOUND (0x2) when deleting
// an empty directory and some return 0x402 when they should be returning
// ERROR_FILE_NOT_FOUND. MSDN says Vista and up won't return 0x402.
diff --git a/base/file_version_info.h b/base/file_version_info.h
index 19407d2..481e88d 100644
--- a/base/file_version_info.h
+++ b/base/file_version_info.h
@@ -6,15 +6,23 @@
#define BASE_FILE_VERSION_INFO_H__
#pragma once
+#include "build/build_config.h"
+
#include <string>
-#include "build/build_config.h"
+#include "base/string16.h"
class FilePath;
-// Provides an interface for accessing the version information for a file.
-// This is the information you access when you select a file in the Windows
-// explorer, right-click select Properties, then click the Version tab.
+// Provides an interface for accessing the version information for a file. This
+// is the information you access when you select a file in the Windows Explorer,
+// right-click select Properties, then click the Version tab, and on the Mac
+// when you select a file in the Finder and do a Get Info.
+//
+// This list of properties is straight out of Win32's VerQueryValue
+// <http://msdn.microsoft.com/en-us/library/ms647464.aspx> and the Mac
+// version returns values from the Info.plist as appropriate. TODO(avi): make
+// this a less-obvious Windows-ism.
class FileVersionInfo {
public:
@@ -24,10 +32,7 @@ class FileVersionInfo {
// goes wrong (typically the file does not exit or cannot be opened). The
// returned object should be deleted when you are done with it.
static FileVersionInfo* CreateFileVersionInfo(const FilePath& file_path);
- // This version, taking a wstring, is deprecated and only kept around
- // until we can fix all callers.
- static FileVersionInfo* CreateFileVersionInfo(const std::wstring& file_path);
-#endif
+#endif // OS_WIN || OS_MACOSX
// Creates a FileVersionInfo for the current module. Returns NULL in case
// of error. The returned object should be deleted when you are done with it.
@@ -35,21 +40,21 @@ class FileVersionInfo {
// Accessors to the different version properties.
// Returns an empty string if the property is not found.
- virtual std::wstring company_name() = 0;
- virtual std::wstring company_short_name() = 0;
- virtual std::wstring product_name() = 0;
- virtual std::wstring product_short_name() = 0;
- virtual std::wstring internal_name() = 0;
- virtual std::wstring product_version() = 0;
- virtual std::wstring private_build() = 0;
- virtual std::wstring special_build() = 0;
- virtual std::wstring comments() = 0;
- virtual std::wstring original_filename() = 0;
- virtual std::wstring file_description() = 0;
- virtual std::wstring file_version() = 0;
- virtual std::wstring legal_copyright() = 0;
- virtual std::wstring legal_trademarks() = 0;
- virtual std::wstring last_change() = 0;
+ virtual string16 company_name() = 0;
+ virtual string16 company_short_name() = 0;
+ virtual string16 product_name() = 0;
+ virtual string16 product_short_name() = 0;
+ virtual string16 internal_name() = 0;
+ virtual string16 product_version() = 0;
+ virtual string16 private_build() = 0;
+ virtual string16 special_build() = 0;
+ virtual string16 comments() = 0;
+ virtual string16 original_filename() = 0;
+ virtual string16 file_description() = 0;
+ virtual string16 file_version() = 0;
+ virtual string16 legal_copyright() = 0;
+ virtual string16 legal_trademarks() = 0;
+ virtual string16 last_change() = 0;
virtual bool is_official_build() = 0;
};
diff --git a/base/file_version_info_mac.h b/base/file_version_info_mac.h
index d66c4e6..879edb3 100644
--- a/base/file_version_info_mac.h
+++ b/base/file_version_info_mac.h
@@ -8,9 +8,8 @@
#include <string>
-#include "base/basictypes.h"
#include "base/file_version_info.h"
-#include "base/scoped_ptr.h"
+#include "base/scoped_nsobject.h"
#ifdef __OBJC__
@class NSBundle;
@@ -18,43 +17,37 @@
class NSBundle;
#endif
-// Provides a way to access the version information for a file.
-// This is the information you access when you select a file in the Windows
-// explorer, right-click select Properties, then click the Version tab.
-
class FileVersionInfoMac : public FileVersionInfo {
public:
explicit FileVersionInfoMac(NSBundle *bundle);
- ~FileVersionInfoMac();
// Accessors to the different version properties.
// Returns an empty string if the property is not found.
- virtual std::wstring company_name();
- virtual std::wstring company_short_name();
- virtual std::wstring product_name();
- virtual std::wstring product_short_name();
- virtual std::wstring internal_name();
- virtual std::wstring product_version();
- virtual std::wstring private_build();
- virtual std::wstring special_build();
- virtual std::wstring comments();
- virtual std::wstring original_filename();
- virtual std::wstring file_description();
- virtual std::wstring file_version();
- virtual std::wstring legal_copyright();
- virtual std::wstring legal_trademarks();
- virtual std::wstring last_change();
+ virtual string16 company_name();
+ virtual string16 company_short_name();
+ virtual string16 product_name();
+ virtual string16 product_short_name();
+ virtual string16 internal_name();
+ virtual string16 product_version();
+ virtual string16 private_build();
+ virtual string16 special_build();
+ virtual string16 comments();
+ virtual string16 original_filename();
+ virtual string16 file_description();
+ virtual string16 file_version();
+ virtual string16 legal_copyright();
+ virtual string16 legal_trademarks();
+ virtual string16 last_change();
virtual bool is_official_build();
private:
- // Lets you access other properties not covered above.
- bool GetValue(const wchar_t* name, std::wstring* value);
- // Similar to GetValue but returns a wstring (empty string if the property
- // does not exist).
- std::wstring GetStringValue(const wchar_t* name);
- NSBundle *bundle_;
+ // Returns a string16 value for a property name.
+ // Returns the empty string if the property does not exist.
+ string16 GetString16Value(CFStringRef name);
+
+ scoped_nsobject<NSBundle> bundle_;
DISALLOW_COPY_AND_ASSIGN(FileVersionInfoMac);
};
diff --git a/base/file_version_info_mac.mm b/base/file_version_info_mac.mm
index 57be79a..fa97df8 100644
--- a/base/file_version_info_mac.mm
+++ b/base/file_version_info_mac.mm
@@ -4,103 +4,87 @@
#include "base/file_version_info_mac.h"
-#import <Cocoa/Cocoa.h>
+#import <Foundation/Foundation.h>
-#include "base/basictypes.h"
#include "base/file_path.h"
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
+#include "base/logging.h"
+#include "base/sys_string_conversions.h"
+#include "base/mac_util.h"
FileVersionInfoMac::FileVersionInfoMac(NSBundle *bundle) : bundle_(bundle) {
- [bundle_ retain];
-}
-
-FileVersionInfoMac::~FileVersionInfoMac() {
- [bundle_ release];
}
// static
FileVersionInfo* FileVersionInfo::CreateFileVersionInfoForCurrentModule() {
- // TODO(erikkay): this should really use bundleForClass, but we don't have
- // a class to hang onto yet.
- NSBundle* bundle = [NSBundle mainBundle];
- return new FileVersionInfoMac(bundle);
-}
-
-// static
-FileVersionInfo* FileVersionInfo::CreateFileVersionInfo(
- const std::wstring& file_path) {
- NSString* path = [NSString stringWithCString:
- reinterpret_cast<const char*>(file_path.c_str())
- encoding:NSUTF32StringEncoding];
- return new FileVersionInfoMac([NSBundle bundleWithPath:path]);
+ return CreateFileVersionInfo(mac_util::MainAppBundlePath());
}
// static
FileVersionInfo* FileVersionInfo::CreateFileVersionInfo(
const FilePath& file_path) {
- NSString* path = [NSString stringWithUTF8String:file_path.value().c_str()];
- return new FileVersionInfoMac([NSBundle bundleWithPath:path]);
+ NSString* path = base::SysUTF8ToNSString(file_path.value());
+ NSBundle* bundle = [NSBundle bundleWithPath:path];
+ return new FileVersionInfoMac(bundle);
}
-std::wstring FileVersionInfoMac::company_name() {
- return std::wstring();
+string16 FileVersionInfoMac::company_name() {
+ return string16();
}
-std::wstring FileVersionInfoMac::company_short_name() {
- return std::wstring();
+string16 FileVersionInfoMac::company_short_name() {
+ return string16();
}
-std::wstring FileVersionInfoMac::internal_name() {
- return std::wstring();
+string16 FileVersionInfoMac::internal_name() {
+ return string16();
}
-std::wstring FileVersionInfoMac::product_name() {
- return GetStringValue(L"CFBundleName");
+string16 FileVersionInfoMac::product_name() {
+ return GetString16Value(kCFBundleNameKey);
}
-std::wstring FileVersionInfoMac::product_short_name() {
- return GetStringValue(L"CFBundleName");
+string16 FileVersionInfoMac::product_short_name() {
+ return GetString16Value(kCFBundleNameKey);
}
-std::wstring FileVersionInfoMac::comments() {
- return std::wstring();
+string16 FileVersionInfoMac::comments() {
+ return string16();
}
-std::wstring FileVersionInfoMac::legal_copyright() {
- return GetStringValue(L"CFBundleGetInfoString");
+string16 FileVersionInfoMac::legal_copyright() {
+ return GetString16Value(CFSTR("CFBundleGetInfoString"));
}
-std::wstring FileVersionInfoMac::product_version() {
- return GetStringValue(L"CFBundleShortVersionString");
+string16 FileVersionInfoMac::product_version() {
+ return GetString16Value(CFSTR("CFBundleShortVersionString"));
}
-std::wstring FileVersionInfoMac::file_description() {
- return std::wstring();
+string16 FileVersionInfoMac::file_description() {
+ return string16();
}
-std::wstring FileVersionInfoMac::legal_trademarks() {
- return std::wstring();
+string16 FileVersionInfoMac::legal_trademarks() {
+ return string16();
}
-std::wstring FileVersionInfoMac::private_build() {
- return std::wstring();
+string16 FileVersionInfoMac::private_build() {
+ return string16();
}
-std::wstring FileVersionInfoMac::file_version() {
+string16 FileVersionInfoMac::file_version() {
return product_version();
}
-std::wstring FileVersionInfoMac::original_filename() {
- return GetStringValue(L"CFBundleName");
+string16 FileVersionInfoMac::original_filename() {
+ return GetString16Value(kCFBundleNameKey);
}
-std::wstring FileVersionInfoMac::special_build() {
- return std::wstring();
+string16 FileVersionInfoMac::special_build() {
+ return string16();
}
-std::wstring FileVersionInfoMac::last_change() {
- return GetStringValue(L"SVNRevision");
+string16 FileVersionInfoMac::last_change() {
+ return GetString16Value(CFSTR("SVNRevision"));
}
bool FileVersionInfoMac::is_official_build() {
@@ -111,23 +95,13 @@ bool FileVersionInfoMac::is_official_build() {
#endif
}
-bool FileVersionInfoMac::GetValue(const wchar_t* name,
- std::wstring* value_str) {
+string16 FileVersionInfoMac::GetString16Value(CFStringRef name) {
if (bundle_) {
- NSString* value = [bundle_ objectForInfoDictionaryKey:
- [NSString stringWithUTF8String:WideToUTF8(name).c_str()]];
+ NSString *ns_name = mac_util::CFToNSCast(name);
+ NSString* value = [bundle_ objectForInfoDictionaryKey:ns_name];
if (value) {
- *value_str = reinterpret_cast<const wchar_t*>(
- [value cStringUsingEncoding:NSUTF32StringEncoding]);
- return true;
+ return base::SysNSStringToUTF16(value);
}
}
- return false;
-}
-
-std::wstring FileVersionInfoMac::GetStringValue(const wchar_t* name) {
- std::wstring str;
- if (GetValue(name, &str))
- return str;
- return std::wstring();
+ return string16();
}
diff --git a/base/file_version_info_win.cc b/base/file_version_info_win.cc
index 6c69708..e2bc84b 100644
--- a/base/file_version_info_win.cc
+++ b/base/file_version_info_win.cc
@@ -77,70 +77,63 @@ FileVersionInfo* FileVersionInfo::CreateFileVersionInfo(
}
}
-// static
-FileVersionInfo* FileVersionInfo::CreateFileVersionInfo(
- const std::wstring& file_path) {
- FilePath file_path_fp = FilePath::FromWStringHack(file_path);
- return CreateFileVersionInfo(file_path_fp);
-}
-
-std::wstring FileVersionInfoWin::company_name() {
+string16 FileVersionInfoWin::company_name() {
return GetStringValue(L"CompanyName");
}
-std::wstring FileVersionInfoWin::company_short_name() {
+string16 FileVersionInfoWin::company_short_name() {
return GetStringValue(L"CompanyShortName");
}
-std::wstring FileVersionInfoWin::internal_name() {
+string16 FileVersionInfoWin::internal_name() {
return GetStringValue(L"InternalName");
}
-std::wstring FileVersionInfoWin::product_name() {
+string16 FileVersionInfoWin::product_name() {
return GetStringValue(L"ProductName");
}
-std::wstring FileVersionInfoWin::product_short_name() {
+string16 FileVersionInfoWin::product_short_name() {
return GetStringValue(L"ProductShortName");
}
-std::wstring FileVersionInfoWin::comments() {
+string16 FileVersionInfoWin::comments() {
return GetStringValue(L"Comments");
}
-std::wstring FileVersionInfoWin::legal_copyright() {
+string16 FileVersionInfoWin::legal_copyright() {
return GetStringValue(L"LegalCopyright");
}
-std::wstring FileVersionInfoWin::product_version() {
+string16 FileVersionInfoWin::product_version() {
return GetStringValue(L"ProductVersion");
}
-std::wstring FileVersionInfoWin::file_description() {
+string16 FileVersionInfoWin::file_description() {
return GetStringValue(L"FileDescription");
}
-std::wstring FileVersionInfoWin::legal_trademarks() {
+string16 FileVersionInfoWin::legal_trademarks() {
return GetStringValue(L"LegalTrademarks");
}
-std::wstring FileVersionInfoWin::private_build() {
+string16 FileVersionInfoWin::private_build() {
return GetStringValue(L"PrivateBuild");
}
-std::wstring FileVersionInfoWin::file_version() {
+string16 FileVersionInfoWin::file_version() {
return GetStringValue(L"FileVersion");
}
-std::wstring FileVersionInfoWin::original_filename() {
+string16 FileVersionInfoWin::original_filename() {
return GetStringValue(L"OriginalFilename");
}
-std::wstring FileVersionInfoWin::special_build() {
+string16 FileVersionInfoWin::special_build() {
return GetStringValue(L"SpecialBuild");
}
-std::wstring FileVersionInfoWin::last_change() {
+string16 FileVersionInfoWin::last_change() {
return GetStringValue(L"LastChange");
}
diff --git a/base/file_version_info_win.h b/base/file_version_info_win.h
index 3d60d69..4a49314 100644
--- a/base/file_version_info_win.h
+++ b/base/file_version_info_win.h
@@ -15,10 +15,6 @@
struct tagVS_FIXEDFILEINFO;
typedef tagVS_FIXEDFILEINFO VS_FIXEDFILEINFO;
-// Provides a way to access the version information for a file.
-// This is the information you access when you select a file in the Windows
-// explorer, right-click select Properties, then click the Version tab.
-
class FileVersionInfoWin : public FileVersionInfo {
public:
FileVersionInfoWin(void* data, int language, int code_page);
@@ -26,21 +22,21 @@ class FileVersionInfoWin : public FileVersionInfo {
// Accessors to the different version properties.
// Returns an empty string if the property is not found.
- virtual std::wstring company_name();
- virtual std::wstring company_short_name();
- virtual std::wstring product_name();
- virtual std::wstring product_short_name();
- virtual std::wstring internal_name();
- virtual std::wstring product_version();
- virtual std::wstring private_build();
- virtual std::wstring special_build();
- virtual std::wstring comments();
- virtual std::wstring original_filename();
- virtual std::wstring file_description();
- virtual std::wstring file_version();
- virtual std::wstring legal_copyright();
- virtual std::wstring legal_trademarks();
- virtual std::wstring last_change();
+ virtual string16 company_name();
+ virtual string16 company_short_name();
+ virtual string16 product_name();
+ virtual string16 product_short_name();
+ virtual string16 internal_name();
+ virtual string16 product_version();
+ virtual string16 private_build();
+ virtual string16 special_build();
+ virtual string16 comments();
+ virtual string16 original_filename();
+ virtual string16 file_description();
+ virtual string16 file_version();
+ virtual string16 legal_copyright();
+ virtual string16 legal_trademarks();
+ virtual string16 last_change();
virtual bool is_official_build();
// Lets you access other properties not covered above.
diff --git a/base/global_descriptors_posix.cc b/base/global_descriptors_posix.cc
index 8c853a0..2fe953c 100644
--- a/base/global_descriptors_posix.cc
+++ b/base/global_descriptors_posix.cc
@@ -15,6 +15,14 @@ GlobalDescriptors::GlobalDescriptors() {}
GlobalDescriptors::~GlobalDescriptors() {}
+// static
+GlobalDescriptors* GlobalDescriptors::GetInstance() {
+ typedef Singleton<base::GlobalDescriptors,
+ LeakySingletonTraits<base::GlobalDescriptors> >
+ GlobalDescriptorsSingleton;
+ return GlobalDescriptorsSingleton::get();
+}
+
int GlobalDescriptors::MaybeGet(Key key) const {
for (Mapping::const_iterator
i = descriptors_.begin(); i != descriptors_.end(); ++i) {
diff --git a/base/global_descriptors_posix.h b/base/global_descriptors_posix.h
index 8ea743e..ab2b86b 100644
--- a/base/global_descriptors_posix.h
+++ b/base/global_descriptors_posix.h
@@ -41,6 +41,9 @@ class GlobalDescriptors {
// the following constant to the key value:
static const int kBaseDescriptor = 3; // 0, 1, 2 are already taken.
+ // Return the singleton instance of GlobalDescriptors.
+ static GlobalDescriptors* GetInstance();
+
// Get a descriptor given a key. It is a fatal error if the key is not known.
int Get(Key key) const;
// Get a descriptor give a key. Returns -1 on error.
diff --git a/base/hash_tables.h b/base/hash_tables.h
index 5fbe466..d11e19f 100644
--- a/base/hash_tables.h
+++ b/base/hash_tables.h
@@ -58,10 +58,14 @@ using __gnu_cxx::hash_set;
namespace __gnu_cxx {
+<<<<<<< HEAD
#ifndef ANDROID
// Already defined for android
// The GNU C++ library provides identiy hash functions for many integral types,
+=======
+// The GNU C++ library provides identity hash functions for many integral types,
+>>>>>>> chromium.org at r10.0.621.0
// but not for |long long|. This hash function will truncate if |size_t| is
// narrower than |long long|. This is probably good enough for what we will
// use it for.
diff --git a/base/i18n/break_iterator.cc b/base/i18n/break_iterator.cc
new file mode 100644
index 0000000..e1b5e29
--- /dev/null
+++ b/base/i18n/break_iterator.cc
@@ -0,0 +1,101 @@
+// Copyright (c) 2009 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/i18n/break_iterator.h"
+
+#include "base/logging.h"
+#include "unicode/ubrk.h"
+#include "unicode/uchar.h"
+#include "unicode/ustring.h"
+
+namespace base {
+
+const size_t npos = -1;
+
+BreakIterator::BreakIterator(const string16* str, BreakType break_type)
+ : iter_(NULL),
+ string_(str),
+ break_type_(break_type),
+ prev_(npos),
+ pos_(0) {
+}
+
+BreakIterator::~BreakIterator() {
+ if (iter_)
+ ubrk_close(static_cast<UBreakIterator*>(iter_));
+}
+
+bool BreakIterator::Init() {
+ UErrorCode status = U_ZERO_ERROR;
+ UBreakIteratorType break_type;
+ switch (break_type_) {
+ case BREAK_WORD:
+ break_type = UBRK_WORD;
+ break;
+ case BREAK_SPACE:
+ case BREAK_NEWLINE:
+ break_type = UBRK_LINE;
+ break;
+ default:
+ NOTREACHED() << "invalid break_type_";
+ return false;
+ }
+ iter_ = ubrk_open(break_type, NULL,
+ string_->data(), static_cast<int32_t>(string_->size()),
+ &status);
+ if (U_FAILURE(status)) {
+ NOTREACHED() << "ubrk_open failed";
+ return false;
+ }
+ // Move the iterator to the beginning of the string.
+ ubrk_first(static_cast<UBreakIterator*>(iter_));
+ return true;
+}
+
+bool BreakIterator::Advance() {
+ int32_t pos;
+ int32_t status;
+ prev_ = pos_;
+ switch (break_type_) {
+ case BREAK_WORD:
+ case BREAK_SPACE:
+ pos = ubrk_next(static_cast<UBreakIterator*>(iter_));
+ if (pos == UBRK_DONE) {
+ pos_ = npos;
+ return false;
+ }
+ pos_ = static_cast<size_t>(pos);
+ return true;
+ case BREAK_NEWLINE:
+ do {
+ pos = ubrk_next(static_cast<UBreakIterator*>(iter_));
+ if (pos == UBRK_DONE) {
+ break;
+ }
+ pos_ = static_cast<size_t>(pos);
+ status = ubrk_getRuleStatus(static_cast<UBreakIterator*>(iter_));
+ } while (status >= UBRK_LINE_SOFT && status < UBRK_LINE_SOFT_LIMIT);
+ if (pos == UBRK_DONE && prev_ == pos_) {
+ pos_ = npos;
+ return false;
+ }
+ return true;
+ default:
+ NOTREACHED() << "invalid break_type_";
+ return false;
+ }
+}
+
+bool BreakIterator::IsWord() const {
+ return (break_type_ == BREAK_WORD &&
+ ubrk_getRuleStatus(static_cast<UBreakIterator*>(iter_)) !=
+ UBRK_WORD_NONE);
+}
+
+string16 BreakIterator::GetString() const {
+ DCHECK(prev_ != npos && pos_ != npos);
+ return string_->substr(prev_, pos_ - prev_);
+}
+
+} // namespace base
diff --git a/base/i18n/break_iterator.h b/base/i18n/break_iterator.h
new file mode 100644
index 0000000..9de7ac7
--- /dev/null
+++ b/base/i18n/break_iterator.h
@@ -0,0 +1,108 @@
+// 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.
+
+#ifndef BASE_I18N_BREAK_ITERATOR_H_
+#define BASE_I18N_BREAK_ITERATOR_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/string16.h"
+
+// The BreakIterator class iterates through the words, word breaks, and
+// line breaks in a UTF-16 string.
+//
+// It provides several modes, BREAK_WORD, BREAK_SPACE, and BREAK_NEWLINE,
+// which modify how characters are aggregated into the returned string.
+//
+// Under BREAK_WORD mode, once a word is encountered any non-word
+// characters are not included in the returned string (e.g. in the
+// UTF-16 equivalent of the string " foo bar! ", the word breaks are at
+// the periods in ". .foo. .bar.!. .").
+//
+// Under BREAK_SPACE mode, once a word is encountered, any non-word
+// characters are included in the returned string, breaking only when a
+// space-equivalent character is encountered (e.g. in the
+// UTF16-equivalent of the string " foo bar! ", the word breaks are at
+// the periods in ". .foo .bar! .").
+//
+// Under BREAK_NEWLINE mode, all characters are included in the returned
+// string, breking only when a newline-equivalent character is encountered
+// (eg. in the UTF-16 equivalent of the string "foo\nbar!\n\n", the line
+// breaks are at the periods in ".foo\n.bar\n.\n.").
+//
+// To extract the words from a string, move a BREAK_WORD BreakIterator
+// through the string and test whether IsWord() is true. E.g.,
+// BreakIterator iter(&str, BreakIterator::BREAK_WORD);
+// if (!iter.Init()) return false;
+// while (iter.Advance()) {
+// if (iter.IsWord()) {
+// // region [iter.prev(),iter.pos()) contains a word.
+// VLOG(1) << "word: " << iter.GetString();
+// }
+// }
+
+namespace base {
+
+class BreakIterator {
+ public:
+ enum BreakType {
+ BREAK_WORD,
+ BREAK_SPACE,
+ BREAK_NEWLINE,
+ };
+
+ // Requires |str| to live as long as the BreakIterator does.
+ BreakIterator(const string16* str, BreakType break_type);
+ ~BreakIterator();
+
+ // Init() must be called before any of the iterators are valid.
+ // Returns false if ICU failed to initialize.
+ bool Init();
+
+ // Return the current break position within the string,
+ // or BreakIterator::npos when done.
+ size_t pos() const { return pos_; }
+
+ // Return the value of pos() returned before Advance() was last called.
+ size_t prev() const { return prev_; }
+
+ // Advance to the next break. Returns false if we've run past the end of
+ // the string. (Note that the very last "break" is after the final
+ // character in the string, and when we advance to that position it's the
+ // last time Advance() returns true.)
+ bool Advance();
+
+ // Under BREAK_WORD mode, returns true if the break we just hit is the
+ // end of a word. (Otherwise, the break iterator just skipped over e.g.
+ // whitespace or punctuation.) Under BREAK_SPACE and BREAK_NEWLINE modes,
+ // this distinction doesn't apply and it always retuns false.
+ bool IsWord() const;
+
+ // Return the string between prev() and pos().
+ // Advance() must have been called successfully at least once
+ // for pos() to have advanced to somewhere useful.
+ string16 GetString() const;
+
+ private:
+ // ICU iterator, avoiding ICU ubrk.h dependence.
+ // This is actually an ICU UBreakiterator* type, which turns out to be
+ // a typedef for a void* in the ICU headers. Using void* directly prevents
+ // callers from needing access to the ICU public headers directory.
+ void* iter_;
+
+ // The string we're iterating over.
+ const string16* string_;
+
+ // The breaking style (word/space/newline).
+ BreakType break_type_;
+
+ // Previous and current iterator positions.
+ size_t prev_, pos_;
+
+ DISALLOW_COPY_AND_ASSIGN(BreakIterator);
+};
+
+} // namespace base
+
+#endif // BASE_I18N_BREAK_ITERATOR_H__
diff --git a/base/i18n/break_iterator_unittest.cc b/base/i18n/break_iterator_unittest.cc
new file mode 100644
index 0000000..bf4fdc1
--- /dev/null
+++ b/base/i18n/break_iterator_unittest.cc
@@ -0,0 +1,308 @@
+// 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.
+
+#include "base/i18n/break_iterator.h"
+
+#include "base/string_piece.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(BreakIteratorTest, BreakWordEmpty) {
+ string16 empty;
+ base::BreakIterator iter(&empty, base::BreakIterator::BREAK_WORD);
+ ASSERT_TRUE(iter.Init());
+ EXPECT_FALSE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end.
+ EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakWord) {
+ string16 space(UTF8ToUTF16(" "));
+ string16 str(UTF8ToUTF16(" foo bar! \npouet boom"));
+ base::BreakIterator iter(&str, base::BreakIterator::BREAK_WORD);
+ ASSERT_TRUE(iter.Init());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(space, iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_TRUE(iter.IsWord());
+ EXPECT_EQ(UTF8ToUTF16("foo"), iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(space, iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_TRUE(iter.IsWord());
+ EXPECT_EQ(UTF8ToUTF16("bar"), iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(UTF8ToUTF16("!"), iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(space, iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(UTF8ToUTF16("\n"), iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_TRUE(iter.IsWord());
+ EXPECT_EQ(UTF8ToUTF16("pouet"), iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(space, iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_TRUE(iter.IsWord());
+ EXPECT_EQ(UTF8ToUTF16("boom"), iter.GetString());
+ EXPECT_FALSE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end.
+ EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakWide16) {
+ // Two greek words separated by space.
+ const string16 str(WideToUTF16(
+ L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9"
+ L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2"));
+ const string16 word1(str.substr(0, 10));
+ const string16 word2(str.substr(11, 5));
+ base::BreakIterator iter(&str, base::BreakIterator::BREAK_WORD);
+ ASSERT_TRUE(iter.Init());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_TRUE(iter.IsWord());
+ EXPECT_EQ(word1, iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_TRUE(iter.IsWord());
+ EXPECT_EQ(word2, iter.GetString());
+ EXPECT_FALSE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end.
+ EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakWide32) {
+ // U+1D49C MATHEMATICAL SCRIPT CAPITAL A
+ const char* very_wide_char = "\xF0\x9D\x92\x9C";
+ const string16 str(
+ UTF8ToUTF16(StringPrintf("%s a", very_wide_char)));
+ const string16 very_wide_word(str.substr(0, 2));
+
+ base::BreakIterator iter(&str, base::BreakIterator::BREAK_WORD);
+ ASSERT_TRUE(iter.Init());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_TRUE(iter.IsWord());
+ EXPECT_EQ(very_wide_word, iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_TRUE(iter.IsWord());
+ EXPECT_EQ(UTF8ToUTF16("a"), iter.GetString());
+ EXPECT_FALSE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end.
+ EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakSpaceEmpty) {
+ string16 empty;
+ base::BreakIterator iter(&empty, base::BreakIterator::BREAK_SPACE);
+ ASSERT_TRUE(iter.Init());
+ EXPECT_FALSE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end.
+ EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakSpace) {
+ string16 str(UTF8ToUTF16(" foo bar! \npouet boom"));
+ base::BreakIterator iter(&str, base::BreakIterator::BREAK_SPACE);
+ ASSERT_TRUE(iter.Init());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(UTF8ToUTF16("foo "), iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(UTF8ToUTF16("bar! \n"), iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(UTF8ToUTF16("pouet "), iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(UTF8ToUTF16("boom"), iter.GetString());
+ EXPECT_FALSE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end.
+ EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakSpaceSP) {
+ string16 str(UTF8ToUTF16(" foo bar! \npouet boom "));
+ base::BreakIterator iter(&str, base::BreakIterator::BREAK_SPACE);
+ ASSERT_TRUE(iter.Init());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(UTF8ToUTF16("foo "), iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(UTF8ToUTF16("bar! \n"), iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(UTF8ToUTF16("pouet "), iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(UTF8ToUTF16("boom "), iter.GetString());
+ EXPECT_FALSE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end.
+ EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakSpacekWide16) {
+ // Two Greek words.
+ const string16 str(WideToUTF16(
+ L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9"
+ L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2"));
+ const string16 word1(str.substr(0, 11));
+ const string16 word2(str.substr(11, 5));
+ base::BreakIterator iter(&str, base::BreakIterator::BREAK_SPACE);
+ ASSERT_TRUE(iter.Init());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(word1, iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(word2, iter.GetString());
+ EXPECT_FALSE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end.
+ EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakSpaceWide32) {
+ // U+1D49C MATHEMATICAL SCRIPT CAPITAL A
+ const char* very_wide_char = "\xF0\x9D\x92\x9C";
+ const string16 str(
+ UTF8ToUTF16(StringPrintf("%s a", very_wide_char)));
+ const string16 very_wide_word(str.substr(0, 3));
+
+ base::BreakIterator iter(&str, base::BreakIterator::BREAK_SPACE);
+ ASSERT_TRUE(iter.Init());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(very_wide_word, iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(UTF8ToUTF16("a"), iter.GetString());
+ EXPECT_FALSE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end.
+ EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakLineEmpty) {
+ string16 empty;
+ base::BreakIterator iter(&empty, base::BreakIterator::BREAK_NEWLINE);
+ ASSERT_TRUE(iter.Init());
+ EXPECT_FALSE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end.
+ EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakLine) {
+ string16 nl(UTF8ToUTF16("\n"));
+ string16 str(UTF8ToUTF16("\nfoo bar!\n\npouet boom"));
+ base::BreakIterator iter(&str, base::BreakIterator::BREAK_NEWLINE);
+ ASSERT_TRUE(iter.Init());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(nl, iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(UTF8ToUTF16("foo bar!\n"), iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(nl, iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(UTF8ToUTF16("pouet boom"), iter.GetString());
+ EXPECT_FALSE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end.
+ EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakLineNL) {
+ string16 nl(UTF8ToUTF16("\n"));
+ string16 str(UTF8ToUTF16("\nfoo bar!\n\npouet boom\n"));
+ base::BreakIterator iter(&str, base::BreakIterator::BREAK_NEWLINE);
+ ASSERT_TRUE(iter.Init());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(nl, iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(UTF8ToUTF16("foo bar!\n"), iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(nl, iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(UTF8ToUTF16("pouet boom\n"), iter.GetString());
+ EXPECT_FALSE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end.
+ EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakLineWide16) {
+ // Two Greek words separated by newline.
+ const string16 str(WideToUTF16(
+ L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9"
+ L"\x03bf\x03c2\x000a\x0399\x03c3\x03c4\x03cc\x03c2"));
+ const string16 line1(str.substr(0, 11));
+ const string16 line2(str.substr(11, 5));
+ base::BreakIterator iter(&str, base::BreakIterator::BREAK_NEWLINE);
+ ASSERT_TRUE(iter.Init());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(line1, iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(line2, iter.GetString());
+ EXPECT_FALSE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end.
+ EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakLineWide32) {
+ // U+1D49C MATHEMATICAL SCRIPT CAPITAL A
+ const char* very_wide_char = "\xF0\x9D\x92\x9C";
+ const string16 str(
+ UTF8ToUTF16(StringPrintf("%s\na", very_wide_char)));
+ const string16 very_wide_line(str.substr(0, 3));
+ base::BreakIterator iter(&str, base::BreakIterator::BREAK_NEWLINE);
+ ASSERT_TRUE(iter.Init());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(very_wide_line, iter.GetString());
+ EXPECT_TRUE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_EQ(UTF8ToUTF16("a"), iter.GetString());
+ EXPECT_FALSE(iter.Advance());
+ EXPECT_FALSE(iter.IsWord());
+ EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end.
+ EXPECT_FALSE(iter.IsWord());
+}
diff --git a/base/i18n/file_util_icu.cc b/base/i18n/file_util_icu.cc
index 0e9c2cd..34eefac 100644
--- a/base/i18n/file_util_icu.cc
+++ b/base/i18n/file_util_icu.cc
@@ -21,6 +21,10 @@ namespace {
class IllegalCharacters {
public:
+ static IllegalCharacters* GetInstance() {
+ return Singleton<IllegalCharacters>::get();
+ }
+
bool contains(UChar32 ucs4) {
return !!set->contains(ucs4);
}
@@ -76,19 +80,8 @@ IllegalCharacters::IllegalCharacters() {
class LocaleAwareComparator {
public:
- LocaleAwareComparator() {
- UErrorCode error_code = U_ZERO_ERROR;
- // Use the default collator. The default locale should have been properly
- // set by the time this constructor is called.
- collator_.reset(icu::Collator::createInstance(error_code));
- DCHECK(U_SUCCESS(error_code));
- // Make it case-sensitive.
- collator_->setStrength(icu::Collator::TERTIARY);
- // Note: We do not set UCOL_NORMALIZATION_MODE attribute. In other words, we
- // do not pay performance penalty to guarantee sort order correctness for
- // non-FCD (http://unicode.org/notes/tn5/#FCD) file names. This should be a
- // reasonable tradeoff because such file names should be rare and the sort
- // order doesn't change much anyway.
+ static LocaleAwareComparator* GetInstance() {
+ return Singleton<LocaleAwareComparator>::get();
}
// Note: A similar function is available in l10n_util.
@@ -111,6 +104,21 @@ class LocaleAwareComparator {
}
private:
+ LocaleAwareComparator() {
+ UErrorCode error_code = U_ZERO_ERROR;
+ // Use the default collator. The default locale should have been properly
+ // set by the time this constructor is called.
+ collator_.reset(icu::Collator::createInstance(error_code));
+ DCHECK(U_SUCCESS(error_code));
+ // Make it case-sensitive.
+ collator_->setStrength(icu::Collator::TERTIARY);
+ // Note: We do not set UCOL_NORMALIZATION_MODE attribute. In other words, we
+ // do not pay performance penalty to guarantee sort order correctness for
+ // non-FCD (http://unicode.org/notes/tn5/#FCD) file names. This should be a
+ // reasonable tradeoff because such file names should be rare and the sort
+ // order doesn't change much anyway.
+ }
+
scoped_ptr<icu::Collator> collator_;
Lock lock_;
friend struct DefaultSingletonTraits<LocaleAwareComparator>;
@@ -123,19 +131,19 @@ class LocaleAwareComparator {
namespace file_util {
bool IsFilenameLegal(const string16& file_name) {
- return Singleton<IllegalCharacters>()->containsNone(file_name);
+ return IllegalCharacters::GetInstance()->containsNone(file_name);
}
void ReplaceIllegalCharactersInPath(FilePath::StringType* file_name,
char replace_char) {
DCHECK(file_name);
- DCHECK(!(Singleton<IllegalCharacters>()->contains(replace_char)));
+ DCHECK(!(IllegalCharacters::GetInstance()->contains(replace_char)));
// Remove leading and trailing whitespace.
TrimWhitespace(*file_name, TRIM_ALL, file_name);
- IllegalCharacters* illegal = Singleton<IllegalCharacters>::get();
+ IllegalCharacters* illegal = IllegalCharacters::GetInstance();
int cursor = 0; // The ICU macros expect an int.
while (cursor < static_cast<int>(file_name->size())) {
int char_begin = cursor;
@@ -171,8 +179,8 @@ void ReplaceIllegalCharactersInPath(FilePath::StringType* file_name,
bool LocaleAwareCompareFilenames(const FilePath& a, const FilePath& b) {
#if defined(OS_WIN)
- return Singleton<LocaleAwareComparator>()->Compare(a.value().c_str(),
- b.value().c_str()) < 0;
+ return LocaleAwareComparator::GetInstance()->Compare(a.value().c_str(),
+ b.value().c_str()) < 0;
#elif defined(OS_POSIX)
// On linux, the file system encoding is not defined. We assume
@@ -181,7 +189,7 @@ bool LocaleAwareCompareFilenames(const FilePath& a, const FilePath& b) {
// ICU's collator can take strings in OS native encoding. But we convert the
// strings to UTF-16 ourselves to ensure conversion consistency.
// TODO(yuzo): Perhaps we should define SysNativeMBToUTF16?
- return Singleton<LocaleAwareComparator>()->Compare(
+ return LocaleAwareComparator::GetInstance()->Compare(
WideToUTF16(base::SysNativeMBToWide(a.value().c_str())),
WideToUTF16(base::SysNativeMBToWide(b.value().c_str()))) < 0;
#else
diff --git a/base/i18n/number_formatting.cc b/base/i18n/number_formatting.cc
index 7a69294..df6af14 100644
--- a/base/i18n/number_formatting.cc
+++ b/base/i18n/number_formatting.cc
@@ -6,7 +6,8 @@
#include "base/format_macros.h"
#include "base/logging.h"
-#include "base/singleton.h"
+#include "base/lazy_instance.h"
+#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "unicode/numfmt.h"
@@ -16,25 +17,26 @@ namespace base {
namespace {
-struct NumberFormatSingletonTraits
- : public DefaultSingletonTraits<icu::NumberFormat> {
- static icu::NumberFormat* New() {
+struct NumberFormatWrapper {
+ NumberFormatWrapper() {
+ // There's no ICU call to destroy a NumberFormat object other than
+ // operator delete, so use the default Delete, which calls operator delete.
+ // This can cause problems if a different allocator is used by this file
+ // than by ICU.
UErrorCode status = U_ZERO_ERROR;
- icu::NumberFormat* formatter = icu::NumberFormat::createInstance(status);
+ number_format.reset(icu::NumberFormat::createInstance(status));
DCHECK(U_SUCCESS(status));
- return formatter;
}
- // There's no ICU call to destroy a NumberFormat object other than
- // operator delete, so use the default Delete, which calls operator delete.
- // This can cause problems if a different allocator is used by this file than
- // by ICU.
+
+ scoped_ptr<icu::NumberFormat> number_format;
};
} // namespace
+static LazyInstance<NumberFormatWrapper> g_number_format(LINKER_INITIALIZED);
+
string16 FormatNumber(int64 number) {
- icu::NumberFormat* number_format =
- Singleton<icu::NumberFormat, NumberFormatSingletonTraits>::get();
+ icu::NumberFormat* number_format = g_number_format.Get().number_format.get();
if (!number_format) {
// As a fallback, just return the raw number in a string.
diff --git a/base/i18n/rtl.cc b/base/i18n/rtl.cc
index 6a5d293..12b376d 100644
--- a/base/i18n/rtl.cc
+++ b/base/i18n/rtl.cc
@@ -163,6 +163,7 @@ TextDirection GetFirstStrongCharacterDirection(const std::wstring& text) {
}
#endif
+#if defined(OS_WIN)
bool AdjustStringForLocaleDirection(string16* text) {
if (!IsRTL() || text->empty())
return false;
@@ -177,6 +178,57 @@ bool AdjustStringForLocaleDirection(string16* text) {
return true;
}
+#else
+bool AdjustStringForLocaleDirection(string16* text) {
+ // On OS X & GTK the directionality of a label is determined by the first
+ // strongly directional character.
+ // However, we want to make sure that in an LTR-language-UI all strings are
+ // left aligned and vice versa.
+ // A problem can arise if we display a string which starts with user input.
+ // User input may be of the opposite directionality to the UI. So the whole
+ // string will be displayed in the opposite directionality, e.g. if we want to
+ // display in an LTR UI [such as US English]:
+ //
+ // EMAN_NOISNETXE is now installed.
+ //
+ // Since EXTENSION_NAME begins with a strong RTL char, the label's
+ // directionality will be set to RTL and the string will be displayed visually
+ // as:
+ //
+ // .is now installed EMAN_NOISNETXE
+ //
+ // In order to solve this issue, we prepend an LRM to the string. An LRM is a
+ // strongly directional LTR char.
+ // We also append an LRM at the end, which ensures that we're in an LTR
+ // context.
+
+ // Unlike Windows, Linux and OS X can correctly display RTL glyphs out of the
+ // box so there is no issue with displaying zero-width bidi control characters
+ // on any system. Thus no need for the !IsRTL() check here.
+ if (text->empty())
+ return false;
+
+ bool ui_direction_is_rtl = IsRTL();
+
+ bool has_rtl_chars = StringContainsStrongRTLChars(*text);
+ if (!ui_direction_is_rtl && has_rtl_chars) {
+ WrapStringWithRTLFormatting(text);
+ text->insert(0, 1, kLeftToRightMark);
+ text->push_back(kLeftToRightMark);
+ } else if (ui_direction_is_rtl && has_rtl_chars) {
+ WrapStringWithRTLFormatting(text);
+ text->insert(0, 1, kRightToLeftMark);
+ text->push_back(kRightToLeftMark);
+ } else if (ui_direction_is_rtl) {
+ WrapStringWithLTRFormatting(text);
+ text->insert(0, 1, kRightToLeftMark);
+ text->push_back(kRightToLeftMark);
+ }
+
+ return true;
+}
+
+#endif // !OS_WIN
#if defined(WCHAR_T_IS_UTF32)
bool AdjustStringForLocaleDirection(std::wstring* text) {
diff --git a/base/i18n/rtl.h b/base/i18n/rtl.h
index 82ac576..a75ed4f 100644
--- a/base/i18n/rtl.h
+++ b/base/i18n/rtl.h
@@ -84,6 +84,7 @@ TextDirection GetFirstStrongCharacterDirection(const std::wstring& text);
// string is always treated as a right-to-left string. This is done by
// inserting certain Unicode formatting marks into the returned string.
//
+// ** Notes about the Windows version of this function:
// TODO(idana) bug 6806: this function adjusts the string in question only
// if the current locale is right-to-left. The function does not take care of
// the opposite case (an RTL string displayed in an LTR context) since
diff --git a/base/i18n/time_formatting.cc b/base/i18n/time_formatting.cc
index 406145d..3fa984a 100644
--- a/base/i18n/time_formatting.cc
+++ b/base/i18n/time_formatting.cc
@@ -14,24 +14,21 @@ using base::Time;
namespace {
-std::wstring TimeFormat(const icu::DateFormat* formatter,
- const Time& time) {
+string16 TimeFormat(const icu::DateFormat* formatter,
+ const Time& time) {
DCHECK(formatter);
icu::UnicodeString date_string;
formatter->format(static_cast<UDate>(time.ToDoubleT() * 1000), date_string);
- std::wstring output;
- bool success = UTF16ToWide(date_string.getBuffer(), date_string.length(),
- &output);
- DCHECK(success);
- return output;
+ return string16(date_string.getBuffer(),
+ static_cast<size_t>(date_string.length()));
}
} // namespace
namespace base {
-std::wstring TimeFormatTimeOfDay(const Time& time) {
+string16 TimeFormatTimeOfDay(const Time& time) {
// We can omit the locale parameter because the default should match
// Chrome's application locale.
scoped_ptr<icu::DateFormat> formatter(
@@ -39,31 +36,31 @@ std::wstring TimeFormatTimeOfDay(const Time& time) {
return TimeFormat(formatter.get(), time);
}
-std::wstring TimeFormatShortDate(const Time& time) {
+string16 TimeFormatShortDate(const Time& time) {
scoped_ptr<icu::DateFormat> formatter(
icu::DateFormat::createDateInstance(icu::DateFormat::kMedium));
return TimeFormat(formatter.get(), time);
}
-std::wstring TimeFormatShortDateNumeric(const Time& time) {
+string16 TimeFormatShortDateNumeric(const Time& time) {
scoped_ptr<icu::DateFormat> formatter(
icu::DateFormat::createDateInstance(icu::DateFormat::kShort));
return TimeFormat(formatter.get(), time);
}
-std::wstring TimeFormatShortDateAndTime(const Time& time) {
+string16 TimeFormatShortDateAndTime(const Time& time) {
scoped_ptr<icu::DateFormat> formatter(
icu::DateFormat::createDateTimeInstance(icu::DateFormat::kShort));
return TimeFormat(formatter.get(), time);
}
-std::wstring TimeFormatFriendlyDateAndTime(const Time& time) {
+string16 TimeFormatFriendlyDateAndTime(const Time& time) {
scoped_ptr<icu::DateFormat> formatter(
icu::DateFormat::createDateTimeInstance(icu::DateFormat::kFull));
return TimeFormat(formatter.get(), time);
}
-std::wstring TimeFormatFriendlyDate(const Time& time) {
+string16 TimeFormatFriendlyDate(const Time& time) {
scoped_ptr<icu::DateFormat> formatter(icu::DateFormat::createDateInstance(
icu::DateFormat::kFull));
return TimeFormat(formatter.get(), time);
diff --git a/base/i18n/time_formatting.h b/base/i18n/time_formatting.h
index d78ae9b..e70ad3d 100644
--- a/base/i18n/time_formatting.h
+++ b/base/i18n/time_formatting.h
@@ -9,32 +9,32 @@
#define BASE_I18N_TIME_FORMATTING_H_
#pragma once
-#include <string>
+#include "base/string16.h"
namespace base {
class Time;
// Returns the time of day, e.g., "3:07 PM".
-std::wstring TimeFormatTimeOfDay(const Time& time);
+string16 TimeFormatTimeOfDay(const Time& time);
// Returns a shortened date, e.g. "Nov 7, 2007"
-std::wstring TimeFormatShortDate(const Time& time);
+string16 TimeFormatShortDate(const Time& time);
// Returns a numeric date such as 12/13/52.
-std::wstring TimeFormatShortDateNumeric(const Time& time);
+string16 TimeFormatShortDateNumeric(const Time& time);
// Formats a time in a friendly sentence format, e.g.
// "Monday, March 6, 2008 2:44:30 PM".
-std::wstring TimeFormatShortDateAndTime(const Time& time);
+string16 TimeFormatShortDateAndTime(const Time& time);
// Formats a time in a friendly sentence format, e.g.
// "Monday, March 6, 2008 2:44:30 PM".
-std::wstring TimeFormatFriendlyDateAndTime(const Time& time);
+string16 TimeFormatFriendlyDateAndTime(const Time& time);
// Formats a time in a friendly sentence format, e.g.
// "Monday, March 6, 2008".
-std::wstring TimeFormatFriendlyDate(const Time& time);
+string16 TimeFormatFriendlyDate(const Time& time);
} // namespace base
diff --git a/base/i18n/word_iterator.cc b/base/i18n/word_iterator.cc
deleted file mode 100644
index a9fa4af..0000000
--- a/base/i18n/word_iterator.cc
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) 2009 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/i18n/word_iterator.h"
-
-#include "base/logging.h"
-#include "unicode/ubrk.h"
-#include "unicode/ustring.h"
-
-const size_t npos = -1;
-
-WordIterator::WordIterator(const string16* str, BreakType break_type)
- : iter_(NULL),
- string_(str),
- break_type_(break_type),
- prev_(npos),
- pos_(0) {
-}
-
-WordIterator::~WordIterator() {
- if (iter_)
- ubrk_close(iter_);
-}
-
-bool WordIterator::Init() {
- UErrorCode status = U_ZERO_ERROR;
- UBreakIteratorType break_type;
- switch (break_type_) {
- case BREAK_WORD:
- break_type = UBRK_WORD;
- break;
- case BREAK_LINE:
- break_type = UBRK_LINE;
- break;
- default:
- NOTREACHED();
- break_type = UBRK_LINE;
- }
- iter_ = ubrk_open(break_type, NULL,
- string_->data(), static_cast<int32_t>(string_->size()),
- &status);
- if (U_FAILURE(status)) {
- NOTREACHED() << "ubrk_open failed";
- return false;
- }
- ubrk_first(iter_); // Move the iterator to the beginning of the string.
- return true;
-}
-
-bool WordIterator::Advance() {
- prev_ = pos_;
- const int32_t pos = ubrk_next(iter_);
- if (pos == UBRK_DONE) {
- pos_ = npos;
- return false;
- } else {
- pos_ = static_cast<size_t>(pos);
- return true;
- }
-}
-
-bool WordIterator::IsWord() const {
- return (ubrk_getRuleStatus(iter_) != UBRK_WORD_NONE);
-}
-
-string16 WordIterator::GetWord() const {
- DCHECK(prev_ != npos && pos_ != npos);
- return string_->substr(prev_, pos_ - prev_);
-}
diff --git a/base/i18n/word_iterator.h b/base/i18n/word_iterator.h
deleted file mode 100644
index b097bc2..0000000
--- a/base/i18n/word_iterator.h
+++ /dev/null
@@ -1,89 +0,0 @@
-// 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.
-
-#ifndef BASE_I18N_WORD_ITERATOR_H_
-#define BASE_I18N_WORD_ITERATOR_H_
-#pragma once
-
-#include <vector>
-
-#include "unicode/ubrk.h"
-#include "unicode/uchar.h"
-
-#include "base/basictypes.h"
-#include "base/string16.h"
-
-// The WordIterator class iterates through the words and word breaks
-// in a string. (In the string " foo bar! ", the word breaks are at the
-// periods in ". .foo. .bar.!. .".)
-//
-// To extract the words from a string, move a WordIterator through the
-// string and test whether IsWord() is true. E.g.,
-// WordIterator iter(&str, WordIterator::BREAK_WORD);
-// if (!iter.Init()) return false;
-// while (iter.Advance()) {
-// if (iter.IsWord()) {
-// // region [iter.prev(),iter.pos()) contains a word.
-// VLOG(1) << "word: " << iter.GetWord();
-// }
-// }
-
-
-class WordIterator {
- public:
- enum BreakType {
- BREAK_WORD,
- BREAK_LINE
- };
-
- // Requires |str| to live as long as the WordIterator does.
- WordIterator(const string16* str, BreakType break_type);
- ~WordIterator();
-
- // Init() must be called before any of the iterators are valid.
- // Returns false if ICU failed to initialize.
- bool Init();
-
- // Return the current break position within the string,
- // or WordIterator::npos when done.
- size_t pos() const { return pos_; }
- // Return the value of pos() returned before Advance() was last called.
- size_t prev() const { return prev_; }
-
- // Advance to the next break. Returns false if we've run past the end of
- // the string. (Note that the very last "word break" is after the final
- // character in the string, and when we advance to that position it's the
- // last time Advance() returns true.)
- bool Advance();
-
- // Returns true if the break we just hit is the end of a word.
- // (Otherwise, the break iterator just skipped over e.g. whitespace
- // or punctuation.)
- bool IsWord() const;
-
- // Return the word between prev() and pos().
- // Advance() must have been called successfully at least once
- // for pos() to have advanced to somewhere useful.
- string16 GetWord() const;
-
- private:
- // ICU iterator.
- UBreakIterator* iter_;
-#if !defined(WCHAR_T_IS_UTF16)
- std::vector<UChar> chars_;
-#endif
-
- // The string we're iterating over.
- const string16* string_;
-
- // The breaking style (word/line).
- BreakType break_type_;
-
- // Previous and current iterator positions.
- size_t prev_, pos_;
-
- DISALLOW_COPY_AND_ASSIGN(WordIterator);
-};
-
-#endif // BASE_I18N_WORD_ITERATOR_H__
diff --git a/base/i18n/word_iterator_unittest.cc b/base/i18n/word_iterator_unittest.cc
deleted file mode 100644
index 92aff76..0000000
--- a/base/i18n/word_iterator_unittest.cc
+++ /dev/null
@@ -1,117 +0,0 @@
-// 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.
-
-#include "base/i18n/word_iterator.h"
-
-#include "base/string_piece.h"
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-TEST(WordIteratorTest, BreakWord) {
- string16 space(UTF8ToUTF16(" "));
-
- string16 str(UTF8ToUTF16(" foo bar! \npouet boom"));
- WordIterator iter(&str, WordIterator::BREAK_WORD);
- ASSERT_TRUE(iter.Init());
- EXPECT_TRUE(iter.Advance());
- EXPECT_FALSE(iter.IsWord());
- EXPECT_EQ(space, iter.GetWord());
- EXPECT_TRUE(iter.Advance());
- EXPECT_TRUE(iter.IsWord());
- EXPECT_EQ(UTF8ToUTF16("foo"), iter.GetWord());
- EXPECT_TRUE(iter.Advance());
- EXPECT_FALSE(iter.IsWord());
- EXPECT_EQ(space, iter.GetWord());
- EXPECT_TRUE(iter.Advance());
- EXPECT_TRUE(iter.IsWord());
- EXPECT_EQ(UTF8ToUTF16("bar"), iter.GetWord());
- EXPECT_TRUE(iter.Advance());
- EXPECT_FALSE(iter.IsWord());
- EXPECT_EQ(UTF8ToUTF16("!"), iter.GetWord());
- EXPECT_TRUE(iter.Advance());
- EXPECT_FALSE(iter.IsWord());
- EXPECT_EQ(space, iter.GetWord());
- EXPECT_TRUE(iter.Advance());
- EXPECT_FALSE(iter.IsWord());
- EXPECT_EQ(UTF8ToUTF16("\n"), iter.GetWord());
- EXPECT_TRUE(iter.Advance());
- EXPECT_TRUE(iter.IsWord());
- EXPECT_EQ(UTF8ToUTF16("pouet"), iter.GetWord());
- EXPECT_TRUE(iter.Advance());
- EXPECT_FALSE(iter.IsWord());
- EXPECT_EQ(space, iter.GetWord());
- EXPECT_TRUE(iter.Advance());
- EXPECT_TRUE(iter.IsWord());
- EXPECT_EQ(UTF8ToUTF16("boom"), iter.GetWord());
- EXPECT_FALSE(iter.Advance());
- EXPECT_FALSE(iter.IsWord());
-}
-
-TEST(WordIteratorTest, BreakLine) {
- string16 str(UTF8ToUTF16(" foo bar! \npouet boom"));
- WordIterator iter(&str, WordIterator::BREAK_LINE);
- ASSERT_TRUE(iter.Init());
- EXPECT_TRUE(iter.Advance());
- EXPECT_FALSE(iter.IsWord());
- EXPECT_EQ(UTF8ToUTF16(" "), iter.GetWord());
- EXPECT_TRUE(iter.Advance());
- EXPECT_FALSE(iter.IsWord());
- EXPECT_EQ(UTF8ToUTF16("foo "), iter.GetWord());
- EXPECT_TRUE(iter.Advance());
- EXPECT_TRUE(iter.IsWord());
- EXPECT_EQ(UTF8ToUTF16("bar! \n"), iter.GetWord());
- EXPECT_TRUE(iter.Advance());
- EXPECT_FALSE(iter.IsWord());
- EXPECT_EQ(UTF8ToUTF16("pouet "), iter.GetWord());
- EXPECT_TRUE(iter.Advance());
- EXPECT_FALSE(iter.IsWord());
- EXPECT_EQ(UTF8ToUTF16("boom"), iter.GetWord());
- EXPECT_FALSE(iter.Advance());
- EXPECT_FALSE(iter.IsWord());
-}
-
-TEST(WordIteratorTest, BreakWide16) {
- // "Παγκόσμιος Ιστός"
- const string16 str(WideToUTF16(
- L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9"
- L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2"));
- const string16 word1(str.substr(0, 10));
- const string16 word2(str.substr(11, 5));
- WordIterator iter(&str, WordIterator::BREAK_WORD);
- ASSERT_TRUE(iter.Init());
- EXPECT_TRUE(iter.Advance());
- EXPECT_TRUE(iter.IsWord());
- EXPECT_EQ(word1, iter.GetWord());
- EXPECT_TRUE(iter.Advance());
- EXPECT_FALSE(iter.IsWord());
- EXPECT_EQ(UTF8ToUTF16(" "), iter.GetWord());
- EXPECT_TRUE(iter.Advance());
- EXPECT_TRUE(iter.IsWord());
- EXPECT_EQ(word2, iter.GetWord());
- EXPECT_FALSE(iter.Advance());
- EXPECT_FALSE(iter.IsWord());
-}
-
-TEST(WordIteratorTest, BreakWide32) {
- // U+1D49C MATHEMATICAL SCRIPT CAPITAL A
- const char* very_wide_char = "\xF0\x9D\x92\x9C";
- const string16 str(
- UTF8ToUTF16(StringPrintf("%s a", very_wide_char)));
- const string16 very_wide_word(str.substr(0, 2));
-
- WordIterator iter(&str, WordIterator::BREAK_WORD);
- ASSERT_TRUE(iter.Init());
- EXPECT_TRUE(iter.Advance());
- EXPECT_TRUE(iter.IsWord());
- EXPECT_EQ(very_wide_word, iter.GetWord());
- EXPECT_TRUE(iter.Advance());
- EXPECT_FALSE(iter.IsWord());
- EXPECT_EQ(UTF8ToUTF16(" "), iter.GetWord());
- EXPECT_TRUE(iter.Advance());
- EXPECT_TRUE(iter.IsWord());
- EXPECT_EQ(UTF8ToUTF16("a"), iter.GetWord());
- EXPECT_FALSE(iter.Advance());
- EXPECT_FALSE(iter.IsWord());
-}
diff --git a/base/image_util.cc b/base/image_util.cc
deleted file mode 100644
index d17158f..0000000
--- a/base/image_util.cc
+++ /dev/null
@@ -1,72 +0,0 @@
-// 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.
-#include <windows.h>
-#include <ImageHlp.h>
-#include <psapi.h>
-
-#include "base/image_util.h"
-#include "base/process_util.h"
-
-// imagehlp.dll appears to ship in all win versions after Win95.
-// nsylvain verified it is present in win2k.
-// Using #pragma comment for dependency, instead of LoadLibrary/GetProcAddress.
-#pragma comment(lib, "imagehlp.lib")
-
-namespace image_util {
-
-// ImageMetrics
-ImageMetrics::ImageMetrics(HANDLE process) : process_(process) {
-}
-
-ImageMetrics::~ImageMetrics() {
-}
-
-bool ImageMetrics::GetDllImageSectionData(const std::string& loaded_dll_name,
- ImageSectionsData* section_sizes) {
- // Get a handle to the loaded DLL
- HMODULE the_dll = GetModuleHandleA(loaded_dll_name.c_str());
- char full_filename[MAX_PATH];
- // Get image path
- if (GetModuleFileNameExA(process_, the_dll, full_filename, MAX_PATH)) {
- return GetImageSectionSizes(full_filename, section_sizes);
- }
- return false;
-}
-
-bool ImageMetrics::GetProcessImageSectionData(ImageSectionsData*
- section_sizes) {
- char exe_path[MAX_PATH];
- // Get image path
- if (GetModuleFileNameExA(process_, NULL, exe_path, MAX_PATH)) {
- return GetImageSectionSizes(exe_path, section_sizes);
- }
- return false;
-}
-
-// private
-bool ImageMetrics::GetImageSectionSizes(char* qualified_path,
- ImageSectionsData* result) {
- LOADED_IMAGE li;
- // TODO (timsteele): There is no unicode version for MapAndLoad, hence
- // why ansi functions are used in this class. Should we try and rewrite
- // this call ourselves to be safe?
- if (MapAndLoad(qualified_path, 0, &li, FALSE, TRUE)) {
- IMAGE_SECTION_HEADER* section_header = li.Sections;
- for (unsigned i = 0; i < li.NumberOfSections; i++, section_header++) {
- std::string name(reinterpret_cast<char*>(section_header->Name));
- ImageSectionData data(name, section_header->Misc.VirtualSize ?
- section_header->Misc.VirtualSize :
- section_header->SizeOfRawData);
- // copy into result
- result->push_back(data);
- }
- } else {
- // map and load failed
- return false;
- }
- UnMapAndLoad(&li);
- return true;
-}
-
-} // namespace image_util
diff --git a/base/image_util.h b/base/image_util.h
deleted file mode 100644
index ccdffc3..0000000
--- a/base/image_util.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// 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.
-
-// This file/namespace contains utility functions for gathering
-// information about PE (Portable Executable) headers within
-// images (dll's / exe's )
-
-#ifndef BASE_IMAGE_UTIL_H_
-#define BASE_IMAGE_UTIL_H_
-#pragma once
-
-#include <windows.h>
-#include <vector>
-
-#include "base/basictypes.h"
-
-namespace image_util {
-
-// Contains both the PE section name (.text, .reloc etc) and its size.
-struct ImageSectionData {
- ImageSectionData(const std::string& section_name, size_t section_size)
- : name(section_name),
- size_in_bytes(section_size) {
- }
-
- std::string name;
- size_t size_in_bytes;
-};
-
-typedef std::vector<ImageSectionData> ImageSectionsData;
-
-// Provides image statistics for modules of a specified process, or for the
-// specified process' own executable file. To use, invoke CreateImageMetrics()
-// to get an instance for a specified process, then access the information via
-// methods.
-class ImageMetrics {
- public:
- // Creates an ImageMetrics instance for given process owned by
- // the caller.
- explicit ImageMetrics(HANDLE process);
- ~ImageMetrics();
-
- // Fills a vector of ImageSectionsData containing name/size info
- // for every section found in the specified dll's PE section table.
- // The DLL must be loaded by the process associated with this ImageMetrics
- // instance.
- bool GetDllImageSectionData(const std::string& loaded_dll_name,
- ImageSectionsData* section_sizes);
-
- // Fills a vector if ImageSectionsData containing name/size info
- // for every section found in the executable file of the process
- // associated with this ImageMetrics instance.
- bool GetProcessImageSectionData(ImageSectionsData* section_sizes);
-
- private:
- // Helper for GetDllImageSectionData and GetProcessImageSectionData
- bool GetImageSectionSizes(char* qualified_path, ImageSectionsData* result);
-
- HANDLE process_;
-
- DISALLOW_COPY_AND_ASSIGN(ImageMetrics);
-};
-
-} // namespace image_util
-
-#endif // BASE_IMAGE_UTIL_H_
diff --git a/base/lazy_instance.h b/base/lazy_instance.h
index f8d5987..bdf5ce3 100644
--- a/base/lazy_instance.h
+++ b/base/lazy_instance.h
@@ -127,7 +127,9 @@ class LazyInstance : public LazyInstanceHelper {
NeedsInstance()) {
// Create the instance in the space provided by |buf_|.
instance_ = Traits::New(buf_);
- CompleteInstance(instance_, Traits::Delete);
+ // Traits::Delete will be null for LeakyLazyInstannceTraits
+ void (*dtor)(void*) = Traits::Delete;
+ CompleteInstance(this, (dtor == NULL) ? NULL : OnExit);
}
// This annotation helps race detectors recognize correct lock-less
@@ -140,6 +142,17 @@ class LazyInstance : public LazyInstanceHelper {
}
private:
+ // Adapter function for use with AtExit. This should be called single
+ // threaded, so don't use atomic operations.
+ // Calling OnExit while the instance is in use by other threads is a mistake.
+ static void OnExit(void* lazy_instance) {
+ LazyInstance<Type, Traits>* me =
+ reinterpret_cast<LazyInstance<Type, Traits>*>(lazy_instance);
+ Traits::Delete(me->instance_);
+ me->instance_ = NULL;
+ base::subtle::Release_Store(&me->state_, STATE_EMPTY);
+ }
+
int8 buf_[sizeof(Type)]; // Preallocate the space for the Type instance.
Type *instance_;
diff --git a/base/linux_util.cc b/base/linux_util.cc
index 62931ce..e1f7275 100644
--- a/base/linux_util.cc
+++ b/base/linux_util.cc
@@ -38,7 +38,7 @@ enum LinuxDistroState {
class LinuxDistroHelper {
public:
// Retrieves the Singleton.
- static LinuxDistroHelper* Get() {
+ static LinuxDistroHelper* GetInstance() {
return Singleton<LinuxDistroHelper>::get();
}
@@ -141,7 +141,7 @@ std::string GetLinuxDistro() {
#if defined(OS_CHROMEOS)
return g_linux_distro;
#elif defined(OS_LINUX)
- LinuxDistroHelper* distro_state_singleton = LinuxDistroHelper::Get();
+ LinuxDistroHelper* distro_state_singleton = LinuxDistroHelper::GetInstance();
LinuxDistroState state = distro_state_singleton->State();
if (STATE_DID_NOT_CHECK == state) {
// We do this check only once per process. If it fails, there's
diff --git a/base/logging.cc b/base/logging.cc
index a202e05..17db628 100644
--- a/base/logging.cc
+++ b/base/logging.cc
@@ -51,14 +51,19 @@ typedef pthread_mutex_t* MutexHandle;
#include "base/debug/stack_trace.h"
#include "base/eintr_wrapper.h"
#include "base/lock_impl.h"
-#if defined(OS_POSIX)
-#include "base/safe_strerror_posix.h"
-#endif
-#include "base/process_util.h"
#include "base/string_piece.h"
#include "base/utf_string_conversions.h"
#ifndef ANDROID
#include "base/vlog.h"
+<<<<<<< HEAD
+=======
+#if defined(OS_POSIX)
+#include "base/safe_strerror_posix.h"
+#endif
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_cftyperef.h"
+#include "base/sys_string_conversions.h"
+>>>>>>> chromium.org at r10.0.621.0
#endif
namespace logging {
@@ -469,6 +474,9 @@ template std::string* MakeCheckOpString<std::string, std::string>(
// Displays a message box to the user with the error message in it.
// Used for fatal messages, where we close the app simultaneously.
+// This is for developers only; we don't use this in circumstances
+// (like release builds) where users could see it, since users don't
+// understand these messages anyway.
void DisplayDebugMessageInDialog(const std::string& str) {
if (str.empty())
return;
@@ -509,19 +517,15 @@ void DisplayDebugMessageInDialog(const std::string& str) {
MessageBoxW(NULL, &cmdline[0], L"Fatal error",
MB_OK | MB_ICONHAND | MB_TOPMOST);
}
-#elif defined(USE_X11) && !defined(OS_CHROMEOS)
- // Shell out to xmessage, which behaves like debug_message.exe, but is
- // way more retro. We could use zenity/kdialog but then we're starting
- // to get into needing to check the desktop env and this dialog should
- // only be coming up in Very Bad situations.
- std::vector<std::string> argv;
- argv.push_back("xmessage");
- argv.push_back(str);
- base::LaunchApp(argv, base::file_handle_mapping_vector(), true /* wait */,
- NULL);
+#elif defined(OS_MACOSX)
+ base::mac::ScopedCFTypeRef<CFStringRef> message(
+ base::SysUTF8ToCFStringRef(str));
+ CFUserNotificationDisplayNotice(0, kCFUserNotificationStopAlertLevel,
+ NULL, NULL, NULL, CFSTR("Fatal Error"),
+ message, NULL);
#else
- // http://code.google.com/p/chromium/issues/detail?id=37026
- NOTIMPLEMENTED();
+ // We intentionally don't implement a dialog on other platforms.
+ // You can just look at stderr.
#endif
}
@@ -602,7 +606,7 @@ void LogMessage::Init(const char* file, int line) {
else
stream_ << "VERBOSE" << -severity_;
- stream_ << ":" << file << "(" << line << ")] ";
+ stream_ << ":" << filename << "(" << line << ")] ";
message_start_ = stream_.tellp();
}
diff --git a/base/logging_win.cc b/base/logging_win.cc
index 42610b5..f780b5e 100644
--- a/base/logging_win.cc
+++ b/base/logging_win.cc
@@ -6,14 +6,6 @@
#include "base/singleton.h"
#include <initguid.h> // NOLINT
-namespace {
-
-typedef StaticMemorySingletonTraits<logging::LogEventProvider>
- LogEventSingletonTraits;
-Singleton<logging::LogEventProvider, LogEventSingletonTraits> log_provider;
-
-} // namespace
-
namespace logging {
using base::win::EtwEventLevel;
@@ -25,6 +17,11 @@ DEFINE_GUID(kLogEventId,
LogEventProvider::LogEventProvider() : old_log_level_(LOG_NONE) {
}
+LogEventProvider* LogEventProvider::GetInstance() {
+ return Singleton<LogEventProvider,
+ StaticMemorySingletonTraits<LogEventProvider> >::get();
+}
+
bool LogEventProvider::LogMessage(logging::LogSeverity severity,
const char* file, int line, size_t message_start,
const std::string& message) {
@@ -53,7 +50,7 @@ bool LogEventProvider::LogMessage(logging::LogSeverity severity,
// Bail if we're not logging, not at that level,
// or if we're post-atexit handling.
- LogEventProvider* provider = log_provider.get();
+ LogEventProvider* provider = LogEventProvider::GetInstance();
if (provider == NULL || level > provider->enable_level())
return false;
@@ -100,7 +97,7 @@ bool LogEventProvider::LogMessage(logging::LogSeverity severity,
}
void LogEventProvider::Initialize(const GUID& provider_name) {
- LogEventProvider* provider = log_provider.get();
+ LogEventProvider* provider = LogEventProvider::GetInstance();
provider->set_provider_name(provider_name);
provider->Register();
@@ -110,7 +107,7 @@ void LogEventProvider::Initialize(const GUID& provider_name) {
}
void LogEventProvider::Uninitialize() {
- log_provider.get()->Unregister();
+ LogEventProvider::GetInstance()->Unregister();
}
void LogEventProvider::OnEventsEnabled() {
diff --git a/base/logging_win.h b/base/logging_win.h
index 695c7f2..9058c84 100644
--- a/base/logging_win.h
+++ b/base/logging_win.h
@@ -11,6 +11,9 @@
#include "base/win/event_trace_provider.h"
#include "base/logging.h"
+template <typename Type>
+struct StaticMemorySingletonTraits;
+
namespace logging {
// Event ID for the log messages we generate.
@@ -47,7 +50,7 @@ enum LogMessageTypes {
// with Event Tracing for Windows.
class LogEventProvider : public base::win::EtwTraceProvider {
public:
- LogEventProvider();
+ static LogEventProvider* GetInstance();
static bool LogMessage(logging::LogSeverity severity, const char* file,
int line, size_t message_start, const std::string& str);
@@ -61,10 +64,13 @@ class LogEventProvider : public base::win::EtwTraceProvider {
virtual void OnEventsDisabled();
private:
+ LogEventProvider();
+
// The log severity prior to OnEventsEnabled,
// restored in OnEventsDisabled.
logging::LogSeverity old_log_level_;
+ friend struct StaticMemorySingletonTraits<LogEventProvider>;
DISALLOW_COPY_AND_ASSIGN(LogEventProvider);
};
diff --git a/base/cocoa_protocols_mac.h b/base/mac/cocoa_protocols.h
index 9482d51..9482d51 100644
--- a/base/cocoa_protocols_mac.h
+++ b/base/mac/cocoa_protocols.h
diff --git a/base/mac_util.h b/base/mac_util.h
index d31bf82..076865d 100644
--- a/base/mac_util.h
+++ b/base/mac_util.h
@@ -10,16 +10,20 @@
#include <string>
#include <vector>
-class FilePath;
+#include "base/logging.h"
+
+#if defined(__OBJC__)
+#import <Foundation/Foundation.h>
-#ifdef __OBJC__
@class NSBundle;
@class NSWindow;
-#else
+#else // __OBJC__
class NSBundle;
class NSImage;
class NSWindow;
-#endif
+#endif // __OBJC__
+
+class FilePath;
// Adapted from NSPathUtilities.h and NSObjCRuntime.h.
#if __LP64__ || NS_BUILD_32_LIKE_64
@@ -188,6 +192,56 @@ bool WasLaunchedAsHiddenLoginItem();
void NSObjectRetain(void* obj);
void NSObjectRelease(void* obj);
+#if defined(__OBJC__)
+
+// Convert toll-free bridged CFTypes to NSTypes. This does not autorelease
+// |cf_val|. This is useful for the case where there is a CFType in a call that
+// expects an NSType and the compiler is complaining about const casting
+// problems.
+// The call is used like this:
+// NSString *foo = CFToNSCast(CFSTR("Hello"));
+// The macro magic below is to enforce safe casting. It could possibly have
+// been done using template function specialization, but template function
+// specialization doesn't always work intuitively,
+// (http://www.gotw.ca/publications/mill17.htm) so the trusty combination
+// of macros and function overloading is used instead.
+
+#define CF_TO_NS_CAST(TypeCF, TypeNS) \
+inline TypeNS* CFToNSCast(TypeCF cf_val) { \
+ TypeNS* ns_val = \
+ const_cast<TypeNS*>(reinterpret_cast<const TypeNS*>(cf_val)); \
+ DCHECK(!ns_val || [ns_val isKindOfClass:[TypeNS class]]); \
+ return ns_val; \
+}
+
+// List of toll-free bridged types taken from:
+// http://www.cocoadev.com/index.pl?TollFreeBridged
+
+CF_TO_NS_CAST(CFArrayRef, NSArray);
+CF_TO_NS_CAST(CFMutableArrayRef, NSMutableArray);
+CF_TO_NS_CAST(CFAttributedStringRef, NSAttributedString);
+CF_TO_NS_CAST(CFMutableAttributedStringRef, NSMutableAttributedString);
+CF_TO_NS_CAST(CFCalendarRef, NSCalendar);
+CF_TO_NS_CAST(CFCharacterSetRef, NSCharacterSet);
+CF_TO_NS_CAST(CFMutableCharacterSetRef, NSMutableCharacterSet);
+CF_TO_NS_CAST(CFDataRef, NSData);
+CF_TO_NS_CAST(CFMutableDataRef, NSMutableData);
+CF_TO_NS_CAST(CFDateRef, NSDate);
+CF_TO_NS_CAST(CFDictionaryRef, NSDictionary);
+CF_TO_NS_CAST(CFMutableDictionaryRef, NSMutableDictionary);
+CF_TO_NS_CAST(CFNumberRef, NSNumber);
+CF_TO_NS_CAST(CFRunLoopTimerRef, NSTimer);
+CF_TO_NS_CAST(CFSetRef, NSSet);
+CF_TO_NS_CAST(CFMutableSetRef, NSMutableSet);
+CF_TO_NS_CAST(CFStringRef, NSString);
+CF_TO_NS_CAST(CFMutableStringRef, NSMutableString);
+CF_TO_NS_CAST(CFURLRef, NSURL);
+CF_TO_NS_CAST(CFTimeZoneRef, NSTimeZone);
+CF_TO_NS_CAST(CFReadStreamRef, NSInputStream);
+CF_TO_NS_CAST(CFWriteStreamRef, NSOutputStream);
+
+#endif // __OBJC__
+
} // namespace mac_util
#endif // BASE_MAC_UTIL_H_
diff --git a/base/mac_util.mm b/base/mac_util.mm
index 9610d37..598f69b 100644
--- a/base/mac_util.mm
+++ b/base/mac_util.mm
@@ -55,19 +55,17 @@ void SetUIMode() {
bool WasLaunchedAsLoginItem() {
ProcessSerialNumber psn = { 0, kCurrentProcess };
- scoped_nsobject<const NSDictionary> process_info(
- reinterpret_cast<const NSDictionary*>(
- ProcessInformationCopyDictionary(&psn,
- kProcessDictionaryIncludeAllInformationMask)));
+ scoped_nsobject<NSDictionary> process_info(
+ mac_util::CFToNSCast(ProcessInformationCopyDictionary(&psn,
+ kProcessDictionaryIncludeAllInformationMask)));
long long temp = [[process_info objectForKey:@"ParentPSN"] longLongValue];
ProcessSerialNumber parent_psn =
{ (temp >> 32) & 0x00000000FFFFFFFFLL, temp & 0x00000000FFFFFFFFLL };
- scoped_nsobject<const NSDictionary> parent_info(
- reinterpret_cast<const NSDictionary*>(
- ProcessInformationCopyDictionary(&parent_psn,
- kProcessDictionaryIncludeAllInformationMask)));
+ scoped_nsobject<NSDictionary> parent_info(
+ mac_util::CFToNSCast(ProcessInformationCopyDictionary(&parent_psn,
+ kProcessDictionaryIncludeAllInformationMask)));
// Check that creator process code is that of loginwindow.
BOOL result =
@@ -88,9 +86,8 @@ LSSharedFileListItemRef GetLoginItemForApp() {
return NULL;
}
- scoped_nsobject<const NSArray> login_items_array(
- reinterpret_cast<const NSArray*>(
- LSSharedFileListCopySnapshot(login_items, NULL)));
+ scoped_nsobject<NSArray> login_items_array(
+ mac_util::CFToNSCast(LSSharedFileListCopySnapshot(login_items, NULL)));
NSURL* url = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
@@ -563,7 +560,7 @@ void SetProcessName(CFStringRef process_name) {
if (!ls_set_application_information_item_func)
LOG(ERROR) << "Could not find _LSSetApplicationInformationItem";
- const CFStringRef* key_pointer = reinterpret_cast<const CFStringRef*>(
+ CFStringRef* key_pointer = reinterpret_cast<CFStringRef*>(
CFBundleGetDataPointerForName(launch_services_bundle,
CFSTR("_kLSDisplayNameKey")));
ls_display_name_key = key_pointer ? *key_pointer : NULL;
diff --git a/base/mac_util_unittest.mm b/base/mac_util_unittest.mm
index 7999878..63ea9b2 100644
--- a/base/mac_util_unittest.mm
+++ b/base/mac_util_unittest.mm
@@ -7,10 +7,10 @@
#include "base/mac_util.h"
-#import "base/chrome_application_mac.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/mac/scoped_cftyperef.h"
+#include "base/test/mock_chrome_application_mac.h"
#include "base/scoped_nsobject.h"
#include "base/scoped_ptr.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -54,7 +54,7 @@ TEST_F(MacUtilTest, TestLibraryPath) {
TEST_F(MacUtilTest, TestGrabWindowSnapshot) {
// Launch a test window so we can take a snapshot.
- [CrApplication sharedApplication];
+ [MockCrApp sharedApplication];
NSRect frame = NSMakeRect(0, 0, 400, 400);
scoped_nsobject<NSWindow> window(
[[NSWindow alloc] initWithContentRect:frame
diff --git a/base/message_loop.cc b/base/message_loop.cc
index 11c7198..98c7ceb 100644
--- a/base/message_loop.cc
+++ b/base/message_loop.cc
@@ -26,7 +26,6 @@
#include "base/message_pump_glib_x.h"
#endif
-using base::Time;
using base::TimeDelta;
using base::TimeTicks;
@@ -141,9 +140,13 @@ MessageLoop::MessageLoop(Type type)
#define MESSAGE_PUMP_UI new base::MessagePumpDefault()
#define MESSAGE_PUMP_IO new base::MessagePumpLibevent()
#elif defined(TOUCH_UI)
-// TODO(sadrul): enable the new message pump when ready
-#define MESSAGE_PUMP_UI new base::MessagePumpForUI()
+#define MESSAGE_PUMP_UI new base::MessagePumpGlibX()
#define MESSAGE_PUMP_IO new base::MessagePumpLibevent()
+#elif defined(OS_NACL)
+// Currently NaCl doesn't have a UI or an IO MessageLoop.
+// TODO(abarth): Figure out if we need these.
+#define MESSAGE_PUMP_UI NULL
+#define MESSAGE_PUMP_IO NULL
#elif defined(OS_POSIX) // POSIX but not MACOSX.
#define MESSAGE_PUMP_UI new base::MessagePumpForUI()
#define MESSAGE_PUMP_IO new base::MessagePumpLibevent()
@@ -347,9 +350,9 @@ void MessageLoop::PostTask_Helper(
// res timers for any timer which is within 2x of the granularity.
// This is a tradeoff between accuracy and power management.
bool needs_high_res_timers =
- delay_ms < (2 * Time::kMinLowResolutionThresholdMs);
+ delay_ms < (2 * base::Time::kMinLowResolutionThresholdMs);
if (needs_high_res_timers) {
- Time::ActivateHighResolutionTimer(true);
+ base::Time::ActivateHighResolutionTimer(true);
high_resolution_timer_expiration_ = TimeTicks::Now() +
TimeDelta::FromMilliseconds(kHighResolutionTimerModeLeaseTimeMs);
}
@@ -362,7 +365,7 @@ void MessageLoop::PostTask_Helper(
#if defined(OS_WIN)
if (!high_resolution_timer_expiration_.is_null()) {
if (TimeTicks::Now() > high_resolution_timer_expiration_) {
- Time::ActivateHighResolutionTimer(false);
+ base::Time::ActivateHighResolutionTimer(false);
high_resolution_timer_expiration_ = TimeTicks();
}
}
@@ -640,7 +643,7 @@ void MessageLoop::EnableHistogrammer(bool enable) {
void MessageLoop::StartHistogrammer() {
if (enable_histogrammer_ && !message_histogram_.get()
- && base::StatisticsRecorder::WasStarted()) {
+ && base::StatisticsRecorder::IsActive()) {
DCHECK(!thread_name_.empty());
message_histogram_ = base::LinearHistogram::FactoryGet(
"MsgLoop:" + thread_name_,
@@ -665,7 +668,11 @@ void MessageLoopForUI::DidProcessMessage(const MSG& message) {
}
#endif // defined(OS_WIN)
+<<<<<<< HEAD
#if !defined(OS_MACOSX) && !defined(ANDROID)
+=======
+#if !defined(OS_MACOSX) && !defined(OS_NACL)
+>>>>>>> chromium.org at r10.0.621.0
void MessageLoopForUI::AddObserver(Observer* observer) {
pump_ui()->AddObserver(observer);
}
@@ -679,7 +686,7 @@ void MessageLoopForUI::Run(Dispatcher* dispatcher) {
state_->dispatcher = dispatcher;
RunHandler();
}
-#endif // !defined(OS_MACOSX)
+#endif // !defined(OS_MACOSX) && !defined(OS_NACL)
//------------------------------------------------------------------------------
// MessageLoopForIO
@@ -694,7 +701,7 @@ bool MessageLoopForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) {
return pump_io()->WaitForIOCompletion(timeout, filter);
}
-#elif defined(OS_POSIX)
+#elif defined(OS_POSIX) && !defined(OS_NACL)
bool MessageLoopForIO::WatchFileDescriptor(int fd,
bool persistent,
diff --git a/base/message_loop_proxy_impl.h b/base/message_loop_proxy_impl.h
index 87ae70a..44ab2ea 100644
--- a/base/message_loop_proxy_impl.h
+++ b/base/message_loop_proxy_impl.h
@@ -18,7 +18,7 @@ namespace base {
class MessageLoopProxyImpl : public MessageLoopProxy,
public MessageLoop::DestructionObserver {
public:
- ~MessageLoopProxyImpl();
+ virtual ~MessageLoopProxyImpl();
// MessageLoopProxy implementation
virtual bool PostTask(const tracked_objects::Location& from_here,
@@ -33,8 +33,8 @@ class MessageLoopProxyImpl : public MessageLoopProxy,
int64 delay_ms);
virtual bool BelongsToCurrentThread();
-// MessageLoop::DestructionObserver implementation
- void WillDestroyCurrentMessageLoop();
+ // MessageLoop::DestructionObserver implementation
+ virtual void WillDestroyCurrentMessageLoop();
protected:
// Override OnDestruct so that we can delete the object on the target message
diff --git a/base/message_loop_unittest.cc b/base/message_loop_unittest.cc
index 537c606..a196519 100644
--- a/base/message_loop_unittest.cc
+++ b/base/message_loop_unittest.cc
@@ -1576,7 +1576,7 @@ TEST(MessageLoopTest, HighResolutionTimer) {
#endif // defined(OS_WIN)
-#if defined(OS_POSIX)
+#if defined(OS_POSIX) && !defined(OS_NACL)
namespace {
@@ -1646,7 +1646,7 @@ TEST(MessageLoopTest, FileDescriptorWatcherDoubleStop) {
} // namespace
-#endif // defined(OS_POSIX)
+#endif // defined(OS_POSIX) && !defined(OS_NACL)
namespace {
class RunAtDestructionTask : public Task {
diff --git a/base/message_pump_glib.cc b/base/message_pump_glib.cc
index fa5b726..fd24285 100644
--- a/base/message_pump_glib.cc
+++ b/base/message_pump_glib.cc
@@ -315,6 +315,10 @@ void MessagePumpForUI::DidProcessEvent(GdkEvent* event) {
FOR_EACH_OBSERVER(Observer, observers_, DidProcessEvent(event));
}
+void MessagePumpForUI::Run(Delegate* delegate) {
+ RunWithDispatcher(delegate, NULL);
+}
+
void MessagePumpForUI::Quit() {
if (state_) {
state_->should_quit = true;
diff --git a/base/message_pump_glib.h b/base/message_pump_glib.h
index 06635de..c118155 100644
--- a/base/message_pump_glib.h
+++ b/base/message_pump_glib.h
@@ -62,7 +62,7 @@ class MessagePumpForUI : public MessagePump {
// is ready for processing.
virtual bool RunOnce(GMainContext* context, bool block);
- virtual void Run(Delegate* delegate) { RunWithDispatcher(delegate, NULL); }
+ virtual void Run(Delegate* delegate);
virtual void Quit();
virtual void ScheduleWork();
virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time);
diff --git a/base/message_pump_glib_x.cc b/base/message_pump_glib_x.cc
index 78c1799..26c4b87 100644
--- a/base/message_pump_glib_x.cc
+++ b/base/message_pump_glib_x.cc
@@ -85,6 +85,8 @@ MessagePumpGlibX::~MessagePumpGlibX() {
bool MessagePumpGlibX::RunOnce(GMainContext* context, bool block) {
GdkDisplay* gdisp = gdk_display_get_default();
Display* display = GDK_DISPLAY_XDISPLAY(gdisp);
+ bool should_quit = false;
+
if (XPending(display)) {
XEvent xev;
XPeekEvent(display, &xev);
@@ -95,10 +97,22 @@ bool MessagePumpGlibX::RunOnce(GMainContext* context, bool block) {
) {
XNextEvent(display, &xev);
- bool processed = static_cast<MessagePumpGlibXDispatcher*>
+#if defined(HAVE_XINPUT2)
+ bool have_cookie = false;
+ if (xev.type == GenericEvent &&
+ XGetEventData(xev.xgeneric.display, &xev.xcookie)) {
+ have_cookie = true;
+ }
+#endif
+
+ MessagePumpGlibXDispatcher::DispatchStatus status =
+ static_cast<MessagePumpGlibXDispatcher*>
(GetDispatcher())->Dispatch(&xev);
- if (!processed) {
+ if (status == MessagePumpGlibXDispatcher::EVENT_QUIT) {
+ should_quit = true;
+ Quit();
+ } else if (status == MessagePumpGlibXDispatcher::EVENT_IGNORED) {
DLOG(WARNING) << "Event (" << xev.type << ") not handled.";
// TODO(sad): It is necessary to put back the event so that the default
@@ -106,16 +120,29 @@ bool MessagePumpGlibX::RunOnce(GMainContext* context, bool block) {
// impossible to use the omnibox at the moment. However, this will
// eventually be removed once the omnibox code is updated for touchui.
XPutBackEvent(display, &xev);
+ if (gdksource_)
+ gdksource_->source_funcs->dispatch = gdkdispatcher_;
g_main_context_iteration(context, FALSE);
}
+
+#if defined(HAVE_XINPUT2)
+ if (have_cookie) {
+ XFreeEventData(xev.xgeneric.display, &xev.xcookie);
+ }
+#endif
} else {
// TODO(sad): A couple of extra events can still sneak in during this.
// Those should be sent back to the X queue from the dispatcher
// EventDispatcherX.
+ if (gdksource_)
+ gdksource_->source_funcs->dispatch = gdkdispatcher_;
g_main_context_iteration(context, FALSE);
}
}
+ if (should_quit)
+ return true;
+
bool retvalue;
if (gdksource_) {
// Replace the dispatch callback of the GDK event source temporarily so that
@@ -178,6 +205,9 @@ void MessagePumpGlibX::InitializeXInput2(void) {
return;
}
+ // TODO(sad): Here, we only setup so that the X windows created by GTK+ are
+ // setup for XInput2 events. We need a way to listen for XInput2 events for X
+ // windows created by other means (e.g. for context menus).
SetupGtkWidgetRealizeNotifier(this);
// Instead of asking X for the list of devices all the time, let's maintain a
@@ -242,6 +272,7 @@ void MessagePumpGlibX::EventDispatcherX(GdkEvent* event, gpointer data) {
if (!pump_x->gdksource_) {
pump_x->gdksource_ = g_main_current_source();
+ pump_x->gdkdispatcher_ = pump_x->gdksource_->source_funcs->dispatch;
} else if (!pump_x->IsDispatchingEvent()) {
if (event->type != GDK_NOTHING &&
pump_x->capture_gdk_events_[event->type]) {
diff --git a/base/message_pump_glib_x.h b/base/message_pump_glib_x.h
index c6d98e3..fc3f3b1 100644
--- a/base/message_pump_glib_x.h
+++ b/base/message_pump_glib_x.h
@@ -60,6 +60,10 @@ class MessagePumpGlibX : public MessagePumpForUI {
// The event source for GDK events.
GSource* gdksource_;
+ // The default GDK event dispatcher. This is stored so that it can be restored
+ // when necessary during nested event dispatching.
+ gboolean (*gdkdispatcher_)(GSource*, GSourceFunc, void*);
+
// Indicates whether a GDK event was injected by chrome (when |true|) or if it
// was captured and being processed by GDK (when |false|).
bool dispatching_event_;
diff --git a/base/message_pump_glib_x_dispatch.h b/base/message_pump_glib_x_dispatch.h
index 95364a2..faee5b5 100644
--- a/base/message_pump_glib_x_dispatch.h
+++ b/base/message_pump_glib_x_dispatch.h
@@ -18,9 +18,18 @@ namespace base {
// GdkEvents. This class provides additional mechanism for dispatching XEvents.
class MessagePumpGlibXDispatcher : public MessagePumpForUI::Dispatcher {
public:
- // Dispatches the event. If true is returned processing continues as
- // normal. If false is returned, the nested loop exits immediately.
- virtual bool Dispatch(XEvent* xevent) = 0;
+
+ typedef enum {
+ EVENT_IGNORED, // The event was not processed.
+ EVENT_PROCESSED, // The event has been processed.
+ EVENT_QUIT // The event was processed and the message-loop should
+ // terminate.
+ } DispatchStatus;
+
+ // Dispatches the event. EVENT_IGNORED is returned if the event was ignored
+ // (i.e. not processed). EVENT_PROCESSED is returned if the event was
+ // processed. The nested loop exits immediately if EVENT_QUIT is returned.
+ virtual DispatchStatus Dispatch(XEvent* xevent) = 0;
};
} // namespace base
diff --git a/base/message_pump_mac.h b/base/message_pump_mac.h
index e016d54..c30a8ea 100644
--- a/base/message_pump_mac.h
+++ b/base/message_pump_mac.h
@@ -36,11 +36,20 @@
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
-#if defined(__OBJC__)
-@class NSAutoreleasePool;
-#else // defined(__OBJC__)
+#if !defined(__OBJC__)
class NSAutoreleasePool;
-#endif // defined(__OBJC__)
+#else // !defined(__OBJC__)
+#import <AppKit/AppKit.h>
+
+// Clients must subclass NSApplication and implement this protocol if they use
+// MessagePumpMac.
+@protocol CrAppProtocol
+// Must return true if -[NSApplication sendEvent:] is currently on the stack.
+// See the comment for |CreateAutoreleasePool()| in the cc file for why this is
+// necessary.
+- (BOOL)isHandlingSendEvent;
+@end
+#endif // !defined(__OBJC__)
namespace base {
diff --git a/base/message_pump_mac.mm b/base/message_pump_mac.mm
index 9091006..8c5461c 100644
--- a/base/message_pump_mac.mm
+++ b/base/message_pump_mac.mm
@@ -11,7 +11,6 @@
#include <limits>
-#import "base/chrome_application_mac.h"
#include "base/logging.h"
#include "base/time.h"
@@ -673,10 +672,6 @@ MessagePumpNSApplication::MessagePumpNSApplication()
void MessagePumpNSApplication::DoRun(Delegate* delegate) {
bool last_running_own_loop_ = running_own_loop_;
- // TODO(dmaclach): Get rid of this gratuitous sharedApplication.
- // Tests should be setting up their applications on their own.
- [CrApplication sharedApplication];
-
if (![NSApp isRunning]) {
running_own_loop_ = false;
// NSApplication manages autorelease pools itself when run this way.
@@ -749,12 +744,12 @@ void MessagePumpNSApplication::Quit() {
// autorelease pool stack.
//
// CrApplication is responsible for setting handlingSendEvent to true just
-// before it sends the event throught the event handling mechanism, and
+// before it sends the event through the event handling mechanism, and
// returning it to its previous value once the event has been sent.
NSAutoreleasePool* MessagePumpNSApplication::CreateAutoreleasePool() {
NSAutoreleasePool* pool = nil;
- DCHECK([NSApp isKindOfClass:[CrApplication class]]);
- if (![static_cast<CrApplication*>(NSApp) isHandlingSendEvent]) {
+ DCHECK([NSApp conformsToProtocol:@protocol(CrAppProtocol)]);
+ if (![NSApp isHandlingSendEvent]) {
pool = MessagePumpCFRunLoopBase::CreateAutoreleasePool();
}
return pool;
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc
index 63d9ed5..d29ed2d 100644
--- a/base/metrics/field_trial.cc
+++ b/base/metrics/field_trial.cc
@@ -17,6 +17,9 @@ const int FieldTrial::kNotParticipating = -1;
const int FieldTrial::kAllRemainingProbability = -2;
// static
+bool FieldTrial::enable_benchmarking_ = false;
+
+// static
const char FieldTrialList::kPersistentStringSeparator('/');
static const char kHistogramFieldTrialSeparator('_');
@@ -40,10 +43,13 @@ int FieldTrial::AppendGroup(const std::string& name,
DCHECK(group_probability <= divisor_);
DCHECK(group_probability >=0 ||
group_probability == kAllRemainingProbability);
- if (group_probability == kAllRemainingProbability)
+ if (group_probability == kAllRemainingProbability) {
accumulated_group_probability_ = divisor_;
- else
+ } else {
+ if (enable_benchmarking_)
+ group_probability = 0;
accumulated_group_probability_ += group_probability;
+ }
DCHECK(accumulated_group_probability_ <= divisor_);
if (group_ == kNotParticipating && accumulated_group_probability_ > random_) {
// This is the group that crossed the random line, so we do the assignment.
@@ -64,6 +70,12 @@ std::string FieldTrial::MakeName(const std::string& name_prefix,
return big_string.append(FieldTrialList::FindFullName(trial_name));
}
+// static
+void FieldTrial::EnableBenchmarking() {
+ DCHECK_EQ(0u, FieldTrialList::GetFieldTrialCount());
+ enable_benchmarking_ = true;
+}
+
FieldTrial::~FieldTrial() {}
//------------------------------------------------------------------------------
@@ -190,4 +202,12 @@ bool FieldTrialList::StringAugmentsState(const std::string& prior_state) {
return true;
}
+// static
+size_t FieldTrialList::GetFieldTrialCount() {
+ if (!global_)
+ return 0;
+ AutoLock auto_lock(global_->lock_);
+ return global_->registered_.size();
+}
+
} // namespace base
diff --git a/base/metrics/field_trial.h b/base/metrics/field_trial.h
index 348a1a7..1f0af9e 100644
--- a/base/metrics/field_trial.h
+++ b/base/metrics/field_trial.h
@@ -117,6 +117,9 @@ class FieldTrial : public RefCounted<FieldTrial> {
static std::string MakeName(const std::string& name_prefix,
const std::string& trial_name);
+ // Enable benchmarking sets field trials to a common setting.
+ static void EnableBenchmarking();
+
private:
friend class RefCounted<FieldTrial>;
@@ -148,6 +151,10 @@ class FieldTrial : public RefCounted<FieldTrial> {
// If this Trial is not a member of an group, this string is empty.
std::string group_name_;
+ // When benchmarking is enabled, field trials all revert to the 'default'
+ // bucket.
+ static bool enable_benchmarking_;
+
DISALLOW_COPY_AND_ASSIGN(FieldTrial);
};
@@ -206,6 +213,9 @@ class FieldTrialList {
return TimeTicks::Now();
}
+ // Return the number of active field trials.
+ static size_t GetFieldTrialCount();
+
private:
// Helper function should be called only while holding lock_.
FieldTrial* PreLockedFind(const std::string& name);
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
index 729e3b9..75df12e 100644
--- a/base/metrics/histogram.cc
+++ b/base/metrics/histogram.cc
@@ -571,6 +571,18 @@ Histogram::Inconsistencies Histogram::FindCorruption(
return static_cast<Inconsistencies>(inconsistencies);
}
+Histogram::ClassType Histogram::histogram_type() const {
+ return HISTOGRAM;
+}
+
+Histogram::Sample Histogram::ranges(size_t i) const {
+ return ranges_[i];
+}
+
+size_t Histogram::bucket_count() const {
+ return bucket_count_;
+}
+
//------------------------------------------------------------------------------
// Methods for the Histogram::SampleSet class
//------------------------------------------------------------------------------
@@ -892,12 +904,21 @@ double CustomHistogram::GetBucketSize(Count current, size_t i) const {
// provide support for all future calls.
StatisticsRecorder::StatisticsRecorder() {
DCHECK(!histograms_);
- lock_ = new Lock;
+ if (lock_ == NULL) {
+ // This will leak on purpose. It's the only way to make sure we won't race
+ // against the static uninitialization of the module while one of our
+ // static methods relying on the lock get called at an inappropriate time
+ // during the termination phase. Since it's a static data member, we will
+ // leak one per process, which would be similar to the instance allocated
+ // during static initialization and released only on process termination.
+ lock_ = new Lock;
+ }
+ AutoLock auto_lock(*lock_);
histograms_ = new HistogramMap;
}
StatisticsRecorder::~StatisticsRecorder() {
- DCHECK(histograms_);
+ DCHECK(histograms_ && lock_);
if (dump_on_exit_) {
std::string output;
@@ -905,14 +926,22 @@ StatisticsRecorder::~StatisticsRecorder() {
LOG(INFO) << output;
}
// Clean up.
- delete histograms_;
- histograms_ = NULL;
- delete lock_;
- lock_ = NULL;
+ HistogramMap* histograms = NULL;
+ {
+ AutoLock auto_lock(*lock_);
+ histograms = histograms_;
+ histograms_ = NULL;
+ }
+ delete histograms;
+ // We don't delete lock_ on purpose to avoid having to properly protect
+ // against it going away after we checked for NULL in the static methods.
}
// static
-bool StatisticsRecorder::WasStarted() {
+bool StatisticsRecorder::IsActive() {
+ if (lock_ == NULL)
+ return false;
+ AutoLock auto_lock(*lock_);
return NULL != histograms_;
}
@@ -923,10 +952,12 @@ bool StatisticsRecorder::WasStarted() {
// destroyed before assignment (when value was returned by new).
// static
void StatisticsRecorder::Register(Histogram* histogram) {
+ if (lock_ == NULL)
+ return;
+ AutoLock auto_lock(*lock_);
if (!histograms_)
return;
const std::string name = histogram->histogram_name();
- AutoLock auto_lock(*lock_);
// Avoid overwriting a previous registration.
if (histograms_->end() == histograms_->find(name))
(*histograms_)[name] = histogram;
@@ -935,7 +966,7 @@ void StatisticsRecorder::Register(Histogram* histogram) {
// static
void StatisticsRecorder::WriteHTMLGraph(const std::string& query,
std::string* output) {
- if (!histograms_)
+ if (!IsActive())
return;
output->append("<html><head><title>About Histograms");
if (!query.empty())
@@ -959,7 +990,7 @@ void StatisticsRecorder::WriteHTMLGraph(const std::string& query,
// static
void StatisticsRecorder::WriteGraph(const std::string& query,
std::string* output) {
- if (!histograms_)
+ if (!IsActive())
return;
if (query.length())
StringAppendF(output, "Collections of histograms for %s\n", query.c_str());
@@ -978,9 +1009,11 @@ void StatisticsRecorder::WriteGraph(const std::string& query,
// static
void StatisticsRecorder::GetHistograms(Histograms* output) {
- if (!histograms_)
+ if (lock_ == NULL)
return;
AutoLock auto_lock(*lock_);
+ if (!histograms_)
+ return;
for (HistogramMap::iterator it = histograms_->begin();
histograms_->end() != it;
++it) {
@@ -991,9 +1024,11 @@ void StatisticsRecorder::GetHistograms(Histograms* output) {
bool StatisticsRecorder::FindHistogram(const std::string& name,
scoped_refptr<Histogram>* histogram) {
- if (!histograms_)
+ if (lock_ == NULL)
return false;
AutoLock auto_lock(*lock_);
+ if (!histograms_)
+ return false;
HistogramMap::iterator it = histograms_->find(name);
if (histograms_->end() == it)
return false;
@@ -1004,7 +1039,11 @@ bool StatisticsRecorder::FindHistogram(const std::string& name,
// private static
void StatisticsRecorder::GetSnapshot(const std::string& query,
Histograms* snapshot) {
+ if (lock_ == NULL)
+ return;
AutoLock auto_lock(*lock_);
+ if (!histograms_)
+ return;
for (HistogramMap::iterator it = histograms_->begin();
histograms_->end() != it;
++it) {
diff --git a/base/metrics/histogram.h b/base/metrics/histogram.h
index b87c891..6b09aa3 100644
--- a/base/metrics/histogram.h
+++ b/base/metrics/histogram.h
@@ -403,13 +403,13 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
//----------------------------------------------------------------------------
// Accessors for factory constuction, serialization and testing.
//----------------------------------------------------------------------------
- virtual ClassType histogram_type() const { return HISTOGRAM; }
+ virtual ClassType histogram_type() const;
const std::string& histogram_name() const { return histogram_name_; }
Sample declared_min() const { return declared_min_; }
Sample declared_max() const { return declared_max_; }
- virtual Sample ranges(size_t i) const { return ranges_[i];}
+ virtual Sample ranges(size_t i) const;
Sample range_checksum() const { return range_checksum_; }
- virtual size_t bucket_count() const { return bucket_count_; }
+ virtual size_t bucket_count() const;
// Snapshot the current complete set of sample data.
// Override with atomic/locked snapshot if needed.
virtual void SnapshotSample(SampleSet* sample) const;
@@ -643,7 +643,7 @@ class StatisticsRecorder {
~StatisticsRecorder();
// Find out if histograms can now be registered into our list.
- static bool WasStarted();
+ static bool IsActive();
// Register, or add a new histogram to the collection of statistics.
static void Register(Histogram* histogram);
diff --git a/base/mime_util_xdg.cc b/base/mime_util_xdg.cc
index 5dc4960..8be1d0d 100644
--- a/base/mime_util_xdg.cc
+++ b/base/mime_util_xdg.cc
@@ -28,6 +28,9 @@ class IconTheme;
class MimeUtilConstants {
public:
+ static MimeUtilConstants* GetInstance() {
+ return Singleton<MimeUtilConstants>::get();
+ }
// In seconds, specified by icon theme specs.
const int kUpdateInterval;
@@ -157,7 +160,7 @@ IconTheme::IconTheme(const std::string& name)
std::map<FilePath, int>::iterator iter;
FilePath theme_path;
std::map<FilePath, int>* icon_dirs =
- Singleton<MimeUtilConstants>::get()->icon_dirs_;
+ MimeUtilConstants::GetInstance()->icon_dirs_;
for (iter = icon_dirs->begin(); iter != icon_dirs->end(); ++iter) {
theme_path = iter->first.Append(name);
if (!file_util::DirectoryExists(theme_path))
@@ -218,7 +221,7 @@ FilePath IconTheme::GetIconPath(const std::string& icon_name, int size,
IconTheme* IconTheme::LoadTheme(const std::string& theme_name) {
scoped_ptr<IconTheme> theme;
std::map<std::string, IconTheme*>* icon_themes =
- Singleton<MimeUtilConstants>::get()->icon_themes_;
+ MimeUtilConstants::GetInstance()->icon_themes_;
if (icon_themes->find(theme_name) != icon_themes->end()) {
theme.reset((*icon_themes)[theme_name]);
} else {
@@ -235,7 +238,7 @@ FilePath IconTheme::GetIconPathUnderSubdir(const std::string& icon_name,
FilePath icon_path;
std::list<FilePath>::iterator dir_iter;
std::vector<std::string>* icon_formats =
- &Singleton<MimeUtilConstants>::get()->icon_formats_;
+ &MimeUtilConstants::GetInstance()->icon_formats_;
for (dir_iter = dirs_.begin(); dir_iter != dirs_.end(); ++dir_iter) {
for (size_t i = 0; i < icon_formats->size(); ++i) {
icon_path = dir_iter->Append(subdir);
@@ -383,7 +386,7 @@ bool IconTheme::SetDirectories(const std::string& dirs) {
void TryAddIconDir(const FilePath& dir) {
if (!file_util::DirectoryExists(dir))
return;
- (*Singleton<MimeUtilConstants>::get()->icon_dirs_)[dir] = 0;
+ (*MimeUtilConstants::GetInstance()->icon_dirs_)[dir] = 0;
}
// For a xdg directory |dir|, add the appropriate icon sub-directories.
@@ -396,7 +399,7 @@ void AddXDGDataDir(const FilePath& dir) {
// Add all the xdg icon directories.
void InitIconDir() {
- Singleton<MimeUtilConstants>::get()->icon_dirs_->clear();
+ MimeUtilConstants::GetInstance()->icon_dirs_->clear();
FilePath home = file_util::GetHomeDir();
if (!home.empty()) {
FilePath legacy_data_dir(home);
@@ -435,7 +438,7 @@ void EnsureUpdated() {
struct timeval t;
gettimeofday(&t, NULL);
time_t now = t.tv_sec;
- MimeUtilConstants* constants = Singleton<MimeUtilConstants>::get();
+ MimeUtilConstants* constants = MimeUtilConstants::GetInstance();
if (constants->last_check_time_ == 0) {
constants->icon_dirs_ = new std::map<FilePath, int>;
@@ -453,7 +456,7 @@ void EnsureUpdated() {
// Find a fallback icon if we cannot find it in the default theme.
FilePath LookupFallbackIcon(const std::string& icon_name) {
FilePath icon;
- MimeUtilConstants* constants = Singleton<MimeUtilConstants>::get();
+ MimeUtilConstants* constants = MimeUtilConstants::GetInstance();
std::map<FilePath, int>::iterator iter;
std::map<FilePath, int>* icon_dirs = constants->icon_dirs_;
std::vector<std::string>* icon_formats = &constants->icon_formats_;
@@ -470,7 +473,7 @@ FilePath LookupFallbackIcon(const std::string& icon_name) {
// Initialize the list of default themes.
void InitDefaultThemes() {
IconTheme** default_themes =
- Singleton<MimeUtilConstants>::get()->default_themes_;
+ MimeUtilConstants::GetInstance()->default_themes_;
char* env = getenv("KDE_FULL_SESSION");
if (env) {
@@ -498,7 +501,7 @@ void InitDefaultThemes() {
} else {
// Assume it's Gnome and use GTK to figure out the theme.
default_themes[1] = IconTheme::LoadTheme(
- Singleton<MimeUtilConstants>::get()->gtk_theme_name_);
+ MimeUtilConstants::GetInstance()->gtk_theme_name_);
default_themes[2] = IconTheme::LoadTheme("gnome");
}
// hicolor needs to be last per icon theme spec.
@@ -518,7 +521,7 @@ void InitDefaultThemes() {
// Try to find an icon with the name |icon_name| that's |size| pixels.
FilePath LookupIconInDefaultTheme(const std::string& icon_name, int size) {
EnsureUpdated();
- MimeUtilConstants* constants = Singleton<MimeUtilConstants>::get();
+ MimeUtilConstants* constants = MimeUtilConstants::GetInstance();
std::map<std::string, IconTheme*>* icon_themes = constants->icon_themes_;
if (icon_themes->size() == 0)
InitDefaultThemes();
@@ -558,7 +561,7 @@ void DetectGtkTheme() {
// If the theme name is already loaded, do nothing. Chrome doesn't respond
// to changes in the system theme, so we never need to set this more than
// once.
- if (!Singleton<MimeUtilConstants>::get()->gtk_theme_name_.empty())
+ if (!MimeUtilConstants::GetInstance()->gtk_theme_name_.empty())
return;
// We should only be called on the UI thread.
@@ -568,7 +571,7 @@ void DetectGtkTheme() {
g_object_get(gtk_settings_get_default(),
"gtk-icon-theme-name",
&gtk_theme_name, NULL);
- Singleton<MimeUtilConstants>::get()->gtk_theme_name_.assign(gtk_theme_name);
+ MimeUtilConstants::GetInstance()->gtk_theme_name_.assign(gtk_theme_name);
g_free(gtk_theme_name);
}
diff --git a/base/nsimage_cache_mac.h b/base/nsimage_cache_mac.h
deleted file mode 100644
index b13eac9..0000000
--- a/base/nsimage_cache_mac.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) 2009 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 BASE_NSIMAGE_CACHE_MAC_H_
-#define BASE_NSIMAGE_CACHE_MAC_H_
-#pragma once
-
-#ifdef __OBJC__
-@class NSImage;
-@class NSString;
-#else
-class NSImage;
-class NSString;
-#endif
-
-namespace nsimage_cache {
-
-// Returns an autoreleased image from the main app bundle
-// (mac_util::MainAppBundle()) with the given name, and keeps it in memory so
-// future fetches are fast.
-// NOTE:
-// - This should only be called on the main thread.
-// - The caller should retain the image if they want to keep it around, as
-// the cache could have limit on size/lifetime, etc.
-NSImage* ImageNamed(NSString* name);
-
-// Clears the cache.
-void Clear(void);
-
-} // namespace nsimage_cache
-
-#endif // BASE_NSIMAGE_CACHE_MAC_H_
diff --git a/base/nsimage_cache_mac.mm b/base/nsimage_cache_mac.mm
deleted file mode 100644
index e693ed4..0000000
--- a/base/nsimage_cache_mac.mm
+++ /dev/null
@@ -1,73 +0,0 @@
-// 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.
-
-#include "base/nsimage_cache_mac.h"
-
-#import <AppKit/AppKit.h>
-
-#include "base/logging.h"
-#include "base/mac_util.h"
-
-// When C++ exceptions are disabled, the C++ library defines |try| and
-// |catch| so as to allow exception-expecting C++ code to build properly when
-// language support for exceptions is not present. These macros interfere
-// with the use of |@try| and |@catch| in Objective-C files such as this one.
-// Undefine these macros here, after everything has been #included, since
-// there will be no C++ uses and only Objective-C uses from this point on.
-#undef try
-#undef catch
-
-namespace nsimage_cache {
-
-static NSMutableDictionary* image_cache = nil;
-
-NSImage* ImageNamed(NSString* name) {
- DCHECK(name);
-
- // NOTE: to make this thread safe, we'd have to sync on the cache and
- // also force all the bundle calls on the main thread.
-
- if (!image_cache) {
- image_cache = [[NSMutableDictionary alloc] init];
- DCHECK(image_cache);
- }
-
- NSImage* result = [image_cache objectForKey:name];
- if (!result) {
- DVLOG_IF(1, [[name pathExtension] length] == 0) << "Suggest including the "
- "extension in the image name";
-
- NSString* path = [mac_util::MainAppBundle() pathForImageResource:name];
- if (path) {
- @try {
- result = [[[NSImage alloc] initWithContentsOfFile:path] autorelease];
- if (result) {
- // Auto-template images with names ending in "Template".
- NSString* extensionlessName = [name stringByDeletingPathExtension];
- if ([extensionlessName hasSuffix:@"Template"])
- [result setTemplate:YES];
-
- [image_cache setObject:result forKey:name];
- }
- }
- @catch (id err) {
- DLOG(ERROR) << "Failed to load the image for name '"
- << [name UTF8String] << "' from path '" << [path UTF8String]
- << "', error: " << [[err description] UTF8String];
- result = nil;
- }
- }
- }
-
- // TODO: if we ever limit the cache size, this should retain & autorelease
- // the image.
- return result;
-}
-
-void Clear(void) {
- // NOTE: to make this thread safe, we'd have to sync on the cache.
- [image_cache removeAllObjects];
-}
-
-} // namespace nsimage_cache
diff --git a/base/nss_util.cc b/base/nss_util.cc
index 580fb60..36394da 100644
--- a/base/nss_util.cc
+++ b/base/nss_util.cc
@@ -333,6 +333,10 @@ void EnsureNSSInit() {
g_nss_singleton.Get();
}
+bool CheckNSSVersion(const char* version) {
+ return !!NSS_VersionCheck(version);
+}
+
#if defined(USE_NSS)
bool OpenTestNSSDB(const FilePath& path, const char* description) {
return g_nss_singleton.Get().OpenTestNSSDB(path, description);
diff --git a/base/nss_util.h b/base/nss_util.h
index 15b624c..d1e36ac 100644
--- a/base/nss_util.h
+++ b/base/nss_util.h
@@ -30,6 +30,10 @@ void EnsureNSPRInit();
// ever be initialized once. NSS will be properly shut down on program exit.
void EnsureNSSInit();
+// Check if the current NSS version is greater than or equals to |version|.
+// A sample version string is "3.12.3".
+bool CheckNSSVersion(const char* version);
+
#if defined(OS_CHROMEOS)
// Open the r/w nssdb that's stored inside the user's encrypted home directory.
void OpenPersistentNSSDB();
diff --git a/base/openssl_util.cc b/base/openssl_util.cc
index 5cfc34a..bc174fa 100644
--- a/base/openssl_util.cc
+++ b/base/openssl_util.cc
@@ -11,6 +11,7 @@
#include "base/logging.h"
#include "base/scoped_vector.h"
#include "base/singleton.h"
+#include "base/string_piece.h"
namespace base {
@@ -23,7 +24,7 @@ unsigned long CurrentThreadId() {
// Singleton for initializing and cleaning up the OpenSSL library.
class OpenSSLInitSingleton {
public:
- static OpenSSLInitSingleton* Get() {
+ static OpenSSLInitSingleton* GetInstance() {
// We allow the SSL environment to leak for multiple reasons:
// - it is used from a non-joinable worker thread that is not stopped on
// shutdown, hence may still be using OpenSSL library after the AtExit
@@ -57,7 +58,7 @@ class OpenSSLInitSingleton {
}
static void LockingCallback(int mode, int n, const char* file, int line) {
- OpenSSLInitSingleton::Get()->OnLockingCallback(mode, n, file, line);
+ OpenSSLInitSingleton::GetInstance()->OnLockingCallback(mode, n, file, line);
}
void OnLockingCallback(int mode, int n, const char* file, int line) {
@@ -74,27 +75,36 @@ class OpenSSLInitSingleton {
DISALLOW_COPY_AND_ASSIGN(OpenSSLInitSingleton);
};
+// Callback routine for OpenSSL to print error messages. |str| is a
+// NULL-terminated string of length |len| containing diagnostic information
+// such as the library, function and reason for the error, the file and line
+// where the error originated, plus potentially any context-specific
+// information about the error. |context| contains a pointer to user-supplied
+// data, which is currently unused.
+// If this callback returns a value <= 0, OpenSSL will stop processing the
+// error queue and return, otherwise it will continue calling this function
+// until all errors have been removed from the queue.
+int OpenSSLErrorCallback(const char* str, size_t len, void* context) {
+ DVLOG(1) << "\t" << StringPiece(str, len);
+ return 1;
+}
+
} // namespace
void EnsureOpenSSLInit() {
- (void)OpenSSLInitSingleton::Get();
+ (void)OpenSSLInitSingleton::GetInstance();
}
void ClearOpenSSLERRStack(const tracked_objects::Location& location) {
if (logging::DEBUG_MODE && VLOG_IS_ON(1)) {
- int error_num = ERR_get_error();
+ int error_num = ERR_peek_error();
if (error_num == 0)
return;
std::string message;
location.Write(true, true, &message);
DVLOG(1) << "OpenSSL ERR_get_error stack from " << message;
- char buf[140];
- do {
- ERR_error_string_n(error_num, buf, arraysize(buf));
- DVLOG(1) << "\t" << error_num << ": " << buf;
- error_num = ERR_get_error();
- } while (error_num != 0);
+ ERR_print_errors_cb(&OpenSSLErrorCallback, NULL);
} else {
ERR_clear_error();
}
diff --git a/base/openssl_util.h b/base/openssl_util.h
index 60cb0b7..9ce7f81 100644
--- a/base/openssl_util.h
+++ b/base/openssl_util.h
@@ -18,7 +18,9 @@ class ScopedOpenSSL {
public:
ScopedOpenSSL() : ptr_(NULL) { }
explicit ScopedOpenSSL(T* ptr) : ptr_(ptr) { }
- ~ScopedOpenSSL() { if (ptr_) (*destructor)(ptr_); }
+ ~ScopedOpenSSL() {
+ reset(NULL);
+ }
T* get() const { return ptr_; }
void reset(T* ptr) {
diff --git a/base/path_service.cc b/base/path_service.cc
index 8660c42..56ce5fa 100644
--- a/base/path_service.cc
+++ b/base/path_service.cc
@@ -13,9 +13,9 @@
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/hash_tables.h"
+#include "base/lazy_instance.h"
#include "base/lock.h"
#include "base/logging.h"
-#include "base/singleton.h"
namespace base {
bool PathProvider(int key, FilePath* result);
@@ -118,8 +118,10 @@ struct PathData {
}
};
+static base::LazyInstance<PathData> g_path_data(base::LINKER_INITIALIZED);
+
static PathData* GetPathData() {
- return Singleton<PathData>::get();
+ return g_path_data.Pointer();
}
} // namespace
@@ -203,18 +205,6 @@ bool PathService::Get(int key, FilePath* result) {
return true;
}
-#if defined(OS_WIN)
-// static
-bool PathService::Get(int key, std::wstring* result) {
- // Deprecated compatibility function.
- FilePath path;
- if (!Get(key, &path))
- return false;
- *result = path.ToWStringHack();
- return true;
-}
-#endif
-
bool PathService::Override(int key, const FilePath& path) {
PathData* path_data = GetPathData();
DCHECK(path_data);
diff --git a/base/path_service.h b/base/path_service.h
index 4d99cdc..edaa5e3 100644
--- a/base/path_service.h
+++ b/base/path_service.h
@@ -27,11 +27,6 @@ class PathService {
// Returns true if the directory or file was successfully retrieved. On
// failure, 'path' will not be changed.
static bool Get(int key, FilePath* path);
-#if defined(OS_WIN)
- // This version, producing a wstring, is deprecated and only kept around
- // until we can fix all callers.
- static bool Get(int key, std::wstring* path);
-#endif
// Overrides the path to a special directory or file. This cannot be used to
// change the value of DIR_CURRENT, but that should be obvious. Also, if the
diff --git a/base/pickle.cc b/base/pickle.cc
index 7745527..3f376e3 100644
--- a/base/pickle.cc
+++ b/base/pickle.cc
@@ -406,9 +406,6 @@ const char* Pickle::FindNext(size_t header_size,
DCHECK(header_size == AlignInt(header_size, sizeof(uint32)));
DCHECK(header_size <= static_cast<size_t>(kPayloadUnit));
- if (static_cast<size_t>(end - start) < sizeof(Header))
- return NULL;
-
const Header* hdr = reinterpret_cast<const Header*>(start);
const char* payload_base = start + header_size;
const char* payload_end = payload_base + hdr->payload_size;
diff --git a/base/pickle.h b/base/pickle.h
index 03f0af1..6006e62 100644
--- a/base/pickle.h
+++ b/base/pickle.h
@@ -236,7 +236,6 @@ class Pickle {
FRIEND_TEST_ALL_PREFIXES(PickleTest, Resize);
FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNext);
- FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNextWithIncompleteHeader);
FRIEND_TEST_ALL_PREFIXES(PickleTest, IteratorHasRoom);
};
diff --git a/base/pickle_unittest.cc b/base/pickle_unittest.cc
index 39eaa1b..fdc0664 100644
--- a/base/pickle_unittest.cc
+++ b/base/pickle_unittest.cc
@@ -171,17 +171,6 @@ TEST(PickleTest, FindNext) {
EXPECT_TRUE(end == Pickle::FindNext(pickle.header_size_, start, end + 1));
}
-TEST(PickleTest, FindNextWithIncompleteHeader) {
- size_t header_size = sizeof(Pickle::Header);
- scoped_array<char> buffer(new char[header_size - 1]);
- memset(buffer.get(), 0x1, header_size - 1);
-
- const char* start = buffer.get();
- const char* end = start + header_size - 1;
-
- EXPECT_TRUE(NULL == Pickle::FindNext(header_size, start, end));
-}
-
TEST(PickleTest, IteratorHasRoom) {
Pickle pickle;
EXPECT_TRUE(pickle.WriteInt(1));
diff --git a/base/platform_thread_mac.mm b/base/platform_thread_mac.mm
index 34afea7..36e08be 100644
--- a/base/platform_thread_mac.mm
+++ b/base/platform_thread_mac.mm
@@ -9,21 +9,6 @@
#include "base/logging.h"
-// A simple class that demonstrates our impressive ability to do nothing.
-@interface NoOp : NSObject
-
-// Does the deed. Or does it?
-+ (void)noOp;
-
-@end
-
-@implementation NoOp
-
-+ (void)noOp {
-}
-
-@end
-
namespace base {
// If Cocoa is to be used on more than one thread, it must know that the
@@ -37,8 +22,9 @@ namespace base {
void InitThreading() {
static BOOL multithreaded = [NSThread isMultiThreaded];
if (!multithreaded) {
- [NSThread detachNewThreadSelector:@selector(noOp)
- toTarget:[NoOp class]
+ // +[NSObject class] is idempotent.
+ [NSThread detachNewThreadSelector:@selector(class)
+ toTarget:[NSObject class]
withObject:nil];
multithreaded = YES;
diff --git a/base/platform_thread_posix.cc b/base/platform_thread_posix.cc
index e442e9c..9807ac6 100644
--- a/base/platform_thread_posix.cc
+++ b/base/platform_thread_posix.cc
@@ -219,5 +219,9 @@ bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
// static
void PlatformThread::Join(PlatformThreadHandle thread_handle) {
+ // Joining another thread may block the current thread for a long time, since
+ // the thread referred to by |thread_handle| may still be running long-lived /
+ // blocking tasks.
+ base::ThreadRestrictions::AssertIOAllowed();
pthread_join(thread_handle, NULL);
}
diff --git a/base/platform_thread_win.cc b/base/platform_thread_win.cc
index e5afc52..ac8a5db 100644
--- a/base/platform_thread_win.cc
+++ b/base/platform_thread_win.cc
@@ -125,6 +125,14 @@ bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
// static
void PlatformThread::Join(PlatformThreadHandle thread_handle) {
DCHECK(thread_handle);
+ // TODO(willchan): Enable this check once I can get it to work for Windows
+ // shutdown.
+ // Joining another thread may block the current thread for a long time, since
+ // the thread referred to by |thread_handle| may still be running long-lived /
+ // blocking tasks.
+#if 0
+ base::ThreadRestrictions::AssertIOAllowed();
+#endif
// Wait for the thread to exit. It should already have terminated but make
// sure this assumption is valid.
diff --git a/base/process_util.cc b/base/process_util.cc
index 6293740..7b2935d 100644
--- a/base/process_util.cc
+++ b/base/process_util.cc
@@ -11,7 +11,7 @@ ProcessEntry::ProcessEntry() {}
ProcessEntry::~ProcessEntry() {}
#endif
-int GetProcessCount(const std::wstring& executable_name,
+int GetProcessCount(const FilePath::StringType& executable_name,
const ProcessFilter* filter) {
int count = 0;
NamedProcessIterator iter(executable_name, filter);
@@ -20,7 +20,7 @@ int GetProcessCount(const std::wstring& executable_name,
return count;
}
-bool KillProcesses(const std::wstring& executable_name, int exit_code,
+bool KillProcesses(const FilePath::StringType& executable_name, int exit_code,
const ProcessFilter* filter) {
bool result = true;
NamedProcessIterator iter(executable_name, filter);
@@ -56,10 +56,10 @@ ProcessIterator::ProcessEntries ProcessIterator::Snapshot() {
return found;
}
-NamedProcessIterator::NamedProcessIterator(const std::wstring& executable_name,
- const ProcessFilter* filter)
- : ProcessIterator(filter),
- executable_name_(executable_name) {
+NamedProcessIterator::NamedProcessIterator(
+ const FilePath::StringType& executable_name,
+ const ProcessFilter* filter) : ProcessIterator(filter),
+ executable_name_(executable_name) {
}
NamedProcessIterator::~NamedProcessIterator() {
diff --git a/base/process_util.h b/base/process_util.h
index ca43289..ce4b0bb 100644
--- a/base/process_util.h
+++ b/base/process_util.h
@@ -34,10 +34,10 @@ typedef struct _malloc_zone_t malloc_zone_t;
#include <vector>
#include "base/file_descriptor_shuffle.h"
+#include "base/file_path.h"
#include "base/process.h"
class CommandLine;
-class FilePath;
namespace base {
@@ -118,13 +118,15 @@ const uint32 kProcessAccessQueryLimitedInfomation = 0;
const uint32 kProcessAccessWaitForTermination = 0;
#endif // defined(OS_POSIX)
-// A minimalistic but hopefully cross-platform set of exit codes.
-// Do not change the enumeration values or you will break third-party
-// installers.
-enum {
- PROCESS_END_NORMAL_TERMINATION = 0,
- PROCESS_END_KILLED_BY_USER = 1,
- PROCESS_END_PROCESS_WAS_HUNG = 2
+// Return status values from GetTerminationStatus. Don't use these as
+// exit code arguments to KillProcess*(), use platform/application
+// specific values instead.
+enum TerminationStatus {
+ TERMINATION_STATUS_NORMAL_TERMINATION, // zero exit status
+ TERMINATION_STATUS_ABNORMAL_TERMINATION, // non-zero exit status
+ TERMINATION_STATUS_PROCESS_WAS_KILLED, // e.g. SIGKILL or task manager kill
+ TERMINATION_STATUS_PROCESS_CRASHED, // e.g. Segmentation fault
+ TERMINATION_STATUS_STILL_RUNNING // child hasn't exited yet
};
// Returns the id of the current process.
@@ -180,7 +182,7 @@ bool AdjustOOMScore(ProcessId process, int score);
#endif
#if defined(OS_POSIX)
-// Close all file descriptors, expect those which are a destination in the
+// Close all file descriptors, except those which are a destination in the
// given multimap. Only call this function in a child process where you know
// that there aren't any other threads.
void CloseSuperfluousFds(const InjectiveMultimap& saved_map);
@@ -320,7 +322,7 @@ class ProcessFilter {
// Returns the number of processes on the machine that are running from the
// given executable name. If filter is non-null, then only processes selected
// by the filter will be counted.
-int GetProcessCount(const std::wstring& executable_name,
+int GetProcessCount(const FilePath::StringType& executable_name,
const ProcessFilter* filter);
// Attempts to kill all the processes on the current machine that were launched
@@ -328,7 +330,7 @@ int GetProcessCount(const std::wstring& executable_name,
// filter is non-null, then only processes selected by the filter are killed.
// Returns true if all processes were able to be killed off, false if at least
// one couldn't be killed.
-bool KillProcesses(const std::wstring& executable_name, int exit_code,
+bool KillProcesses(const FilePath::StringType& executable_name, int exit_code,
const ProcessFilter* filter);
// Attempts to kill the process identified by the given process
@@ -347,10 +349,15 @@ bool KillProcessGroup(ProcessHandle process_group_id);
bool KillProcessById(ProcessId process_id, int exit_code, bool wait);
#endif
-// Get the termination status (exit code) of the process and return true if the
-// status indicates the process crashed. |child_exited| is set to true iff the
-// child process has terminated. (|child_exited| may be NULL.)
-bool DidProcessCrash(bool* child_exited, ProcessHandle handle);
+// Get the termination status of the process by interpreting the
+// circumstances of the child process' death. |exit_code| is set to
+// the status returned by waitpid() on POSIX, and from
+// GetExitCodeProcess() on Windows. |exit_code| may be NULL if the
+// caller is not interested in it. Note that on Linux, this function
+// will only return a useful result the first time it is called after
+// the child exits (because it will reap the child and the information
+// will no longer be available).
+TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code);
// Waits for process to exit. In POSIX systems, if the process hasn't been
// signaled then puts the exit code in |exit_code|; otherwise it's considered
@@ -370,7 +377,7 @@ bool WaitForExitCodeWithTimeout(ProcessHandle handle, int* exit_code,
// is non-null, then only processes selected by the filter are waited on.
// Returns after all processes have exited or wait_milliseconds have expired.
// Returns true if all the processes exited, false otherwise.
-bool WaitForProcessesToExit(const std::wstring& executable_name,
+bool WaitForProcessesToExit(const FilePath::StringType& executable_name,
int64 wait_milliseconds,
const ProcessFilter* filter);
@@ -389,7 +396,7 @@ bool CrashAwareSleep(ProcessHandle handle, int64 wait_milliseconds);
// on. Killed processes are ended with the given exit code. Returns false if
// any processes needed to be killed, true if they all exited cleanly within
// the wait_milliseconds delay.
-bool CleanupProcesses(const std::wstring& executable_name,
+bool CleanupProcesses(const FilePath::StringType& executable_name,
int64 wait_milliseconds,
int exit_code,
const ProcessFilter* filter);
@@ -450,7 +457,7 @@ class ProcessIterator {
// until it returns false.
class NamedProcessIterator : public ProcessIterator {
public:
- NamedProcessIterator(const std::wstring& executable_name,
+ NamedProcessIterator(const FilePath::StringType& executable_name,
const ProcessFilter* filter);
virtual ~NamedProcessIterator();
@@ -458,7 +465,7 @@ class NamedProcessIterator : public ProcessIterator {
virtual bool IncludeEntry();
private:
- std::wstring executable_name_;
+ FilePath::StringType executable_name_;
DISALLOW_COPY_AND_ASSIGN(NamedProcessIterator);
};
diff --git a/base/process_util_linux.cc b/base/process_util_linux.cc
index 6138c07..670de6a 100644
--- a/base/process_util_linux.cc
+++ b/base/process_util_linux.cc
@@ -111,13 +111,12 @@ FilePath GetProcessExecutablePath(ProcessHandle process) {
FilePath stat_file("/proc");
stat_file = stat_file.Append(base::IntToString(process));
stat_file = stat_file.Append("exe");
- char exename[2048];
- ssize_t len = readlink(stat_file.value().c_str(), exename, sizeof(exename));
- if (len < 1) {
+ FilePath exe_name;
+ if (!file_util::ReadSymbolicLink(stat_file, &exe_name)) {
// No such process. Happens frequently in e.g. TerminateAllChromeProcesses
return FilePath();
}
- return FilePath(std::string(exename, len));
+ return exe_name;
}
ProcessIterator::ProcessIterator(const ProcessFilter* filter)
@@ -221,8 +220,7 @@ bool ProcessIterator::CheckForNextProcess() {
}
bool NamedProcessIterator::IncludeEntry() {
- // TODO(port): make this also work for non-ASCII filenames
- if (WideToASCII(executable_name_) != entry().exe_file())
+ if (executable_name_ != entry().exe_file())
return false;
return ProcessIterator::IncludeEntry();
}
@@ -320,13 +318,20 @@ bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
// Synchronously reading files in /proc is safe.
base::ThreadRestrictions::ScopedAllowIO allow_io;
- FilePath stat_file =
- FilePath("/proc").Append(base::IntToString(process_)).Append("smaps");
+ FilePath proc_dir = FilePath("/proc").Append(base::IntToString(process_));
std::string smaps;
int private_kb = 0;
int pss_kb = 0;
bool have_pss = false;
- if (file_util::ReadFileToString(stat_file, &smaps) && smaps.length() > 0) {
+ bool ret;
+
+ {
+ FilePath smaps_file = proc_dir.Append("smaps");
+ // Synchronously reading files in /proc is safe.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+ ret = file_util::ReadFileToString(smaps_file, &smaps);
+ }
+ if (ret && smaps.length() > 0) {
const std::string private_prefix = "Private_";
const std::string pss_prefix = "Pss";
StringTokenizer tokenizer(smaps, ":\n");
@@ -364,10 +369,14 @@ bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
if (page_size_kb <= 0)
return false;
- stat_file =
- FilePath("/proc").Append(base::IntToString(process_)).Append("statm");
std::string statm;
- if (!file_util::ReadFileToString(stat_file, &statm) || statm.length() == 0)
+ {
+ FilePath statm_file = proc_dir.Append("statm");
+ // Synchronously reading files in /proc is safe.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+ ret = file_util::ReadFileToString(statm_file, &statm);
+ }
+ if (!ret || statm.length() == 0)
return false;
std::vector<std::string> statm_vec;
diff --git a/base/process_util_mac.mm b/base/process_util_mac.mm
index b167aa2..aa0f14d 100644
--- a/base/process_util_mac.mm
+++ b/base/process_util_mac.mm
@@ -10,6 +10,8 @@
#include <dlfcn.h>
#include <mach/mach.h>
#include <mach/mach_init.h>
+#include <mach/mach_vm.h>
+#include <mach/shared_region.h>
#include <mach/task.h>
#include <malloc/malloc.h>
#import <objc/runtime.h>
@@ -25,6 +27,7 @@
#include "base/debug/debugger.h"
#include "base/eintr_wrapper.h"
+#include "base/hash_tables.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "base/sys_info.h"
@@ -166,7 +169,7 @@ bool ProcessIterator::CheckForNextProcess() {
}
bool NamedProcessIterator::IncludeEntry() {
- return (SysWideToUTF8(executable_name_) == entry().exe_file() &&
+ return (executable_name_ == entry().exe_file() &&
ProcessIterator::IncludeEntry());
}
@@ -235,13 +238,130 @@ size_t ProcessMetrics::GetPeakWorkingSetSize() const {
return 0;
}
-// OSX appears to use a different system to get its memory.
+static bool GetCPUTypeForProcess(pid_t pid, cpu_type_t* cpu_type) {
+ size_t len = sizeof(*cpu_type);
+ int result = sysctlbyname("sysctl.proc_cputype",
+ cpu_type,
+ &len,
+ NULL,
+ 0);
+ if (result != 0) {
+ PLOG(ERROR) << "sysctlbyname(""sysctl.proc_cputype"")";
+ return false;
+ }
+
+ return true;
+}
+
+static bool IsAddressInSharedRegion(mach_vm_address_t addr, cpu_type_t type) {
+ if (type == CPU_TYPE_I386)
+ return addr >= SHARED_REGION_BASE_I386 &&
+ addr < (SHARED_REGION_BASE_I386 + SHARED_REGION_SIZE_I386);
+ else if (type == CPU_TYPE_X86_64)
+ return addr >= SHARED_REGION_BASE_X86_64 &&
+ addr < (SHARED_REGION_BASE_X86_64 + SHARED_REGION_SIZE_X86_64);
+ else
+ return false;
+}
+
+// This is a rough approximation of the algorithm that libtop uses.
+// private_bytes is the size of private resident memory.
+// shared_bytes is the size of shared resident memory.
bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes,
size_t* shared_bytes) {
+ kern_return_t kr;
+ size_t private_pages_count = 0;
+ size_t shared_pages_count = 0;
+
+ if (!private_bytes && !shared_bytes)
+ return true;
+
+ mach_port_t task = TaskForPid(process_);
+ if (task == MACH_PORT_NULL) {
+ LOG(ERROR) << "Invalid process";
+ return false;
+ }
+
+ cpu_type_t cpu_type;
+ if (!GetCPUTypeForProcess(process_, &cpu_type))
+ return false;
+
+ // The same region can be referenced multiple times. To avoid double counting
+ // we need to keep track of which regions we've already counted.
+ base::hash_set<int> seen_objects;
+
+ // We iterate through each VM region in the task's address map. For shared
+ // memory we add up all the pages that are marked as shared. Like libtop we
+ // try to avoid counting pages that are also referenced by other tasks. Since
+ // we don't have access to the VM regions of other tasks the only hint we have
+ // is if the address is in the shared region area.
+ //
+ // Private memory is much simpler. We simply count the pages that are marked
+ // as private or copy on write (COW).
+ //
+ // See libtop_update_vm_regions in
+ // http://www.opensource.apple.com/source/top/top-67/libtop.c
+ mach_vm_size_t size = 0;
+ for (mach_vm_address_t address = MACH_VM_MIN_ADDRESS;; address += size) {
+ vm_region_top_info_data_t info;
+ mach_msg_type_number_t info_count = VM_REGION_TOP_INFO_COUNT;
+ mach_port_t object_name;
+ kr = mach_vm_region(task,
+ &address,
+ &size,
+ VM_REGION_TOP_INFO,
+ (vm_region_info_t)&info,
+ &info_count,
+ &object_name);
+ if (kr == KERN_INVALID_ADDRESS) {
+ // We're at the end of the address space.
+ break;
+ } else if (kr != KERN_SUCCESS) {
+ LOG(ERROR) << "Calling mach_vm_region failed with error: "
+ << mach_error_string(kr);
+ return false;
+ }
+
+ if (IsAddressInSharedRegion(address, cpu_type) &&
+ info.share_mode != SM_PRIVATE)
+ continue;
+
+ if (info.share_mode == SM_COW && info.ref_count == 1)
+ info.share_mode = SM_PRIVATE;
+
+ switch (info.share_mode) {
+ case SM_PRIVATE:
+ private_pages_count += info.private_pages_resident;
+ private_pages_count += info.shared_pages_resident;
+ break;
+ case SM_COW:
+ private_pages_count += info.private_pages_resident;
+ // Fall through
+ case SM_SHARED:
+ if (seen_objects.count(info.obj_id) == 0) {
+ // Only count the first reference to this region.
+ seen_objects.insert(info.obj_id);
+ shared_pages_count += info.shared_pages_resident;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ vm_size_t page_size;
+ kr = host_page_size(task, &page_size);
+ if (kr != KERN_SUCCESS) {
+ LOG(ERROR) << "Failed to fetch host page size, error: "
+ << mach_error_string(kr);
+ return false;
+ }
+
if (private_bytes)
- *private_bytes = 0;
+ *private_bytes = private_pages_count * page_size;
if (shared_bytes)
- *shared_bytes = 0;
+ *shared_bytes = shared_pages_count * page_size;
+
return true;
}
@@ -596,7 +716,7 @@ void EnableTerminationOnOutOfMemory() {
!g_old_valloc_purgeable && !g_old_realloc_purgeable &&
!g_old_memalign_purgeable) << "Old allocators unexpectedly non-null";
- // See http://trac.webkit.org/changeset/53362/trunk/WebKitTools/DumpRenderTree/mac
+ // See http://trac.webkit.org/changeset/53362/trunk/Tools/DumpRenderTree/mac
bool zone_allocators_protected = darwin_version > 10;
ChromeMallocZone* default_zone =
diff --git a/base/process_util_posix.cc b/base/process_util_posix.cc
index 43096c0..f31ffdd 100644
--- a/base/process_util_posix.cc
+++ b/base/process_util_posix.cc
@@ -26,6 +26,7 @@
#include "base/process_util.h"
#include "base/scoped_ptr.h"
#include "base/stringprintf.h"
+#include "base/thread_restrictions.h"
#include "base/time.h"
#include "base/waitable_event.h"
@@ -241,6 +242,8 @@ bool KillProcess(ProcessHandle process_id, int exit_code, bool wait) {
sleep_ms *= 2;
}
+ // If we're waiting and the child hasn't died by now, force it
+ // with a SIGKILL.
if (!exited)
result = kill(process_id, SIGKILL) == 0;
}
@@ -558,6 +561,9 @@ bool LaunchAppImpl(
} else {
// Parent process
if (wait) {
+ // While this isn't strictly disk IO, waiting for another process to
+ // finish is the sort of thing ThreadRestrictions is trying to prevent.
+ base::ThreadRestrictions::AssertIOAllowed();
pid_t ret = HANDLE_EINTR(waitpid(pid, 0, 0));
DPCHECK(ret > 0);
}
@@ -635,40 +641,45 @@ void RaiseProcessToHighPriority() {
// setpriority() or sched_getscheduler, but these all require extra rights.
}
-bool DidProcessCrash(bool* child_exited, ProcessHandle handle) {
- int status;
+TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) {
+ int status = 0;
const pid_t result = HANDLE_EINTR(waitpid(handle, &status, WNOHANG));
if (result == -1) {
PLOG(ERROR) << "waitpid(" << handle << ")";
- if (child_exited)
- *child_exited = false;
- return false;
+ if (exit_code)
+ *exit_code = 0;
+ return TERMINATION_STATUS_NORMAL_TERMINATION;
} else if (result == 0) {
// the child hasn't exited yet.
- if (child_exited)
- *child_exited = false;
- return false;
+ if (exit_code)
+ *exit_code = 0;
+ return TERMINATION_STATUS_STILL_RUNNING;
}
- if (child_exited)
- *child_exited = true;
+ if (exit_code)
+ *exit_code = status;
if (WIFSIGNALED(status)) {
switch (WTERMSIG(status)) {
- case SIGSEGV:
- case SIGILL:
case SIGABRT:
+ case SIGBUS:
case SIGFPE:
- return true;
+ case SIGILL:
+ case SIGSEGV:
+ return TERMINATION_STATUS_PROCESS_CRASHED;
+ case SIGINT:
+ case SIGKILL:
+ case SIGTERM:
+ return TERMINATION_STATUS_PROCESS_WAS_KILLED;
default:
- return false;
+ break;
}
}
- if (WIFEXITED(status))
- return WEXITSTATUS(status) != 0;
+ if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
+ return TERMINATION_STATUS_ABNORMAL_TERMINATION;
- return false;
+ return TERMINATION_STATUS_NORMAL_TERMINATION;
}
bool WaitForExitCode(ProcessHandle handle, int* exit_code) {
@@ -753,6 +764,9 @@ int64 TimeValToMicroseconds(const struct timeval& tv) {
static bool GetAppOutputInternal(const CommandLine& cl, char* const envp[],
std::string* output, size_t max_output,
bool do_search_path) {
+ // Doing a blocking wait for another command to finish counts as IO.
+ base::ThreadRestrictions::AssertIOAllowed();
+
int pipe_fd[2];
pid_t pid;
InjectiveMultimap fd_shuffle1, fd_shuffle2;
@@ -868,7 +882,7 @@ bool GetAppOutputRestricted(const CommandLine& cl,
return GetAppOutputInternal(cl, &empty_environ, output, max_output, false);
}
-bool WaitForProcessesToExit(const std::wstring& executable_name,
+bool WaitForProcessesToExit(const FilePath::StringType& executable_name,
int64 wait_milliseconds,
const ProcessFilter* filter) {
bool result = false;
@@ -890,7 +904,7 @@ bool WaitForProcessesToExit(const std::wstring& executable_name,
return result;
}
-bool CleanupProcesses(const std::wstring& executable_name,
+bool CleanupProcesses(const FilePath::StringType& executable_name,
int64 wait_milliseconds,
int exit_code,
const ProcessFilter* filter) {
diff --git a/base/process_util_unittest.cc b/base/process_util_unittest.cc
index 34c444c..0eaf5d4 100644
--- a/base/process_util_unittest.cc
+++ b/base/process_util_unittest.cc
@@ -7,6 +7,7 @@
#include <limits>
#include "base/command_line.h"
+#include "base/debug_util.h"
#include "base/eintr_wrapper.h"
#include "base/file_path.h"
#include "base/logging.h"
@@ -15,6 +16,7 @@
#include "base/process_util.h"
#include "base/scoped_ptr.h"
#include "base/test/multiprocess_test.h"
+#include "base/test/test_timeouts.h"
#include "base/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/multiprocess_func_list.h"
@@ -27,6 +29,7 @@
#if defined(OS_POSIX)
#include <dlfcn.h>
#include <fcntl.h>
+#include <signal.h>
#include <sys/resource.h>
#include <sys/socket.h>
#endif
@@ -41,11 +44,25 @@
namespace {
#if defined(OS_WIN)
-const wchar_t* const kProcessName = L"base_unittests.exe";
+const wchar_t kProcessName[] = L"base_unittests.exe";
#else
-const wchar_t* const kProcessName = L"base_unittests";
+const wchar_t kProcessName[] = L"base_unittests";
#endif // defined(OS_WIN)
+const char kSignalFileSlow[] = "SlowChildProcess.die";
+const char kSignalFileCrash[] = "CrashingChildProcess.die";
+const char kSignalFileKill[] = "KilledChildProcess.die";
+
+#if defined(OS_WIN)
+const int kExpectedStillRunningExitCode = 0x102;
+const int kExpectedKilledExitCode = 1;
+#else
+const int kExpectedStillRunningExitCode = 0;
+#endif
+
+// The longest we'll wait for a process, in milliseconds.
+const int kMaxWaitTimeMs = TestTimeouts::action_max_timeout_ms();
+
// Sleeps until file filename is created.
void WaitToDie(const char* filename) {
FILE *fp;
@@ -62,6 +79,27 @@ void SignalChildren(const char* filename) {
fclose(fp);
}
+// Using a pipe to the child to wait for an event was considered, but
+// there were cases in the past where pipes caused problems (other
+// libraries closing the fds, child deadlocking). This is a simple
+// case, so it's not worth the risk. Using wait loops is discouraged
+// in most instances.
+base::TerminationStatus WaitForChildTermination(base::ProcessHandle handle,
+ int* exit_code) {
+ // Now we wait until the result is something other than STILL_RUNNING.
+ base::TerminationStatus status = base::TERMINATION_STATUS_STILL_RUNNING;
+ const int kIntervalMs = 20;
+ int waited = 0;
+ do {
+ status = base::GetTerminationStatus(handle, exit_code);
+ PlatformThread::Sleep(kIntervalMs);
+ waited += kIntervalMs;
+ } while (status == base::TERMINATION_STATUS_STILL_RUNNING &&
+ waited < kMaxWaitTimeMs);
+
+ return status;
+}
+
} // namespace
class ProcessUtilTest : public base::MultiProcessTest {
@@ -79,40 +117,140 @@ MULTIPROCESS_TEST_MAIN(SimpleChildProcess) {
TEST_F(ProcessUtilTest, SpawnChild) {
base::ProcessHandle handle = this->SpawnChild("SimpleChildProcess", false);
ASSERT_NE(base::kNullProcessHandle, handle);
- EXPECT_TRUE(base::WaitForSingleProcess(handle, 5000));
+ EXPECT_TRUE(base::WaitForSingleProcess(handle, kMaxWaitTimeMs));
base::CloseProcessHandle(handle);
}
MULTIPROCESS_TEST_MAIN(SlowChildProcess) {
- WaitToDie("SlowChildProcess.die");
+ WaitToDie(kSignalFileSlow);
return 0;
}
TEST_F(ProcessUtilTest, KillSlowChild) {
- remove("SlowChildProcess.die");
+ remove(kSignalFileSlow);
base::ProcessHandle handle = this->SpawnChild("SlowChildProcess", false);
ASSERT_NE(base::kNullProcessHandle, handle);
- SignalChildren("SlowChildProcess.die");
- EXPECT_TRUE(base::WaitForSingleProcess(handle, 5000));
+ SignalChildren(kSignalFileSlow);
+ EXPECT_TRUE(base::WaitForSingleProcess(handle, kMaxWaitTimeMs));
base::CloseProcessHandle(handle);
- remove("SlowChildProcess.die");
+ remove(kSignalFileSlow);
}
-TEST_F(ProcessUtilTest, DidProcessCrash) {
- remove("SlowChildProcess.die");
+TEST_F(ProcessUtilTest, GetTerminationStatusExit) {
+ remove(kSignalFileSlow);
base::ProcessHandle handle = this->SpawnChild("SlowChildProcess", false);
ASSERT_NE(base::kNullProcessHandle, handle);
- bool child_exited = true;
- EXPECT_FALSE(base::DidProcessCrash(&child_exited, handle));
- EXPECT_FALSE(child_exited);
+ int exit_code = 42;
+ EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
+ base::GetTerminationStatus(handle, &exit_code));
+ EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
+
+ SignalChildren(kSignalFileSlow);
+ exit_code = 42;
+ base::TerminationStatus status =
+ WaitForChildTermination(handle, &exit_code);
+ EXPECT_EQ(base::TERMINATION_STATUS_NORMAL_TERMINATION, status);
+ EXPECT_EQ(0, exit_code);
+ base::CloseProcessHandle(handle);
+ remove(kSignalFileSlow);
+}
- SignalChildren("SlowChildProcess.die");
- EXPECT_TRUE(base::WaitForSingleProcess(handle, 5000));
+#if !defined(OS_MACOSX)
+// This test is disabled on Mac, since it's flaky due to ReportCrash
+// taking a variable amount of time to parse and load the debug and
+// symbol data for this unit test's executable before firing the
+// signal handler.
+//
+// TODO(gspencer): turn this test process into a very small program
+// with no symbols (instead of using the multiprocess testing
+// framework) to reduce the ReportCrash overhead.
+
+MULTIPROCESS_TEST_MAIN(CrashingChildProcess) {
+ WaitToDie(kSignalFileCrash);
+#if defined(OS_POSIX)
+ // Have to disable to signal handler for segv so we can get a crash
+ // instead of an abnormal termination through the crash dump handler.
+ ::signal(SIGSEGV, SIG_DFL);
+#endif
+ // Make this process have a segmentation fault.
+ int* oops = NULL;
+ *oops = 0xDEAD;
+ return 1;
+}
+
+TEST_F(ProcessUtilTest, GetTerminationStatusCrash) {
+ remove(kSignalFileCrash);
+ base::ProcessHandle handle = this->SpawnChild("CrashingChildProcess",
+ false);
+ ASSERT_NE(base::kNullProcessHandle, handle);
- EXPECT_FALSE(base::DidProcessCrash(&child_exited, handle));
+ int exit_code = 42;
+ EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
+ base::GetTerminationStatus(handle, &exit_code));
+ EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
+
+ SignalChildren(kSignalFileCrash);
+ exit_code = 42;
+ base::TerminationStatus status =
+ WaitForChildTermination(handle, &exit_code);
+ EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_CRASHED, status);
+
+#if defined(OS_WIN)
+ EXPECT_EQ(0xc0000005, exit_code);
+#elif defined(OS_POSIX)
+ int signaled = WIFSIGNALED(exit_code);
+ EXPECT_NE(0, signaled);
+ int signal = WTERMSIG(exit_code);
+ EXPECT_EQ(SIGSEGV, signal);
+#endif
+ base::CloseProcessHandle(handle);
+
+ // Reset signal handlers back to "normal".
+ base::EnableInProcessStackDumping();
+ remove(kSignalFileCrash);
+}
+#endif // !defined(OS_MACOSX)
+
+MULTIPROCESS_TEST_MAIN(KilledChildProcess) {
+ WaitToDie(kSignalFileKill);
+#if defined(OS_WIN)
+ // Kill ourselves.
+ HANDLE handle = ::OpenProcess(PROCESS_ALL_ACCESS, 0, ::GetCurrentProcessId());
+ ::TerminateProcess(handle, kExpectedKilledExitCode);
+#elif defined(OS_POSIX)
+ // Send a SIGKILL to this process, just like the OOM killer would.
+ ::kill(getpid(), SIGKILL);
+#endif
+ return 1;
+}
+
+TEST_F(ProcessUtilTest, GetTerminationStatusKill) {
+ remove(kSignalFileKill);
+ base::ProcessHandle handle = this->SpawnChild("KilledChildProcess",
+ false);
+ ASSERT_NE(base::kNullProcessHandle, handle);
+
+ int exit_code = 42;
+ EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
+ base::GetTerminationStatus(handle, &exit_code));
+ EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
+
+ SignalChildren(kSignalFileKill);
+ exit_code = 42;
+ base::TerminationStatus status =
+ WaitForChildTermination(handle, &exit_code);
+ EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED, status);
+#if defined(OS_WIN)
+ EXPECT_EQ(kExpectedKilledExitCode, exit_code);
+#elif defined(OS_POSIX)
+ int signaled = WIFSIGNALED(exit_code);
+ EXPECT_NE(0, signaled);
+ int signal = WTERMSIG(exit_code);
+ EXPECT_EQ(SIGKILL, signal);
+#endif
base::CloseProcessHandle(handle);
- remove("SlowChildProcess.die");
+ remove(kSignalFileKill);
}
// Ensure that the priority of a process is restored correctly after
diff --git a/base/process_util_win.cc b/base/process_util_win.cc
index 097888e..71f0a1a 100644
--- a/base/process_util_win.cc
+++ b/base/process_util_win.cc
@@ -30,6 +30,20 @@ namespace {
// System pagesize. This value remains constant on x86/64 architectures.
const int PAGESIZE_KB = 4;
+// Exit codes with special meanings on Windows.
+const DWORD kNormalTerminationExitCode = 0;
+const DWORD kDebuggerInactiveExitCode = 0xC0000354;
+const DWORD kKeyboardInterruptExitCode = 0xC000013A;
+const DWORD kDebuggerTerminatedExitCode = 0x40010004;
+
+// This exit code is used by the Windows task manager when it kills a
+// process. It's value is obviously not that unique, and it's
+// surprising to me that the task manager uses this value, but it
+// seems to be common practice on Windows to test for it as an
+// indication that the task manager has killed something if the
+// process goes away.
+const DWORD kProcessKilledExitCode = 1;
+
// HeapSetInformation function pointer.
typedef BOOL (WINAPI* HeapSetFn)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T);
@@ -105,10 +119,10 @@ bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) {
bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) {
ProcessHandle result = OpenProcess(PROCESS_DUP_HANDLE |
- PROCESS_TERMINATE |
- PROCESS_QUERY_INFORMATION |
- PROCESS_VM_READ |
- SYNCHRONIZE,
+ PROCESS_TERMINATE |
+ PROCESS_QUERY_INFORMATION |
+ PROCESS_VM_READ |
+ SYNCHRONIZE,
FALSE, pid);
if (result == INVALID_HANDLE_VALUE)
@@ -394,22 +408,33 @@ bool KillProcess(ProcessHandle process, int exit_code, bool wait) {
return result;
}
-bool DidProcessCrash(bool* child_exited, ProcessHandle handle) {
- DWORD exitcode = 0;
+TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) {
+ DWORD tmp_exit_code = 0;
- if (!::GetExitCodeProcess(handle, &exitcode)) {
+ if (!::GetExitCodeProcess(handle, &tmp_exit_code)) {
NOTREACHED();
- // Assume the child has exited.
- if (child_exited)
- *child_exited = true;
- return false;
+ if (exit_code) {
+ // This really is a random number. We haven't received any
+ // information about the exit code, presumably because this
+ // process doesn't have permission to get the exit code, or
+ // because of some other cause for GetExitCodeProcess to fail
+ // (MSDN docs don't give the possible failure error codes for
+ // this function, so it could be anything). But we don't want
+ // to leave exit_code uninitialized, since that could cause
+ // random interpretations of the exit code. So we assume it
+ // terminated "normally" in this case.
+ *exit_code = kNormalTerminationExitCode;
+ }
+ // Assume the child has exited normally if we can't get the exit
+ // code.
+ return TERMINATION_STATUS_NORMAL_TERMINATION;
}
- if (exitcode == STILL_ACTIVE) {
+ if (tmp_exit_code == STILL_ACTIVE) {
DWORD wait_result = WaitForSingleObject(handle, 0);
if (wait_result == WAIT_TIMEOUT) {
- if (child_exited)
- *child_exited = false;
- return false;
+ if (exit_code)
+ *exit_code = wait_result;
+ return TERMINATION_STATUS_STILL_RUNNING;
}
DCHECK_EQ(WAIT_OBJECT_0, wait_result);
@@ -417,27 +442,24 @@ bool DidProcessCrash(bool* child_exited, ProcessHandle handle) {
// Strange, the process used 0x103 (STILL_ACTIVE) as exit code.
NOTREACHED();
- return false;
+ return TERMINATION_STATUS_ABNORMAL_TERMINATION;
}
- // We're sure the child has exited.
- if (child_exited)
- *child_exited = true;
+ if (exit_code)
+ *exit_code = tmp_exit_code;
- // Warning, this is not generic code; it heavily depends on the way
- // the rest of the code kills a process.
-
- if (exitcode == PROCESS_END_NORMAL_TERMINATION ||
- exitcode == PROCESS_END_KILLED_BY_USER ||
- exitcode == PROCESS_END_PROCESS_WAS_HUNG ||
- exitcode == 0xC0000354 || // STATUS_DEBUGGER_INACTIVE.
- exitcode == 0xC000013A || // Control-C/end session.
- exitcode == 0x40010004) { // Debugger terminated process/end session.
- return false;
+ switch (tmp_exit_code) {
+ case kNormalTerminationExitCode:
+ return TERMINATION_STATUS_NORMAL_TERMINATION;
+ case kDebuggerInactiveExitCode: // STATUS_DEBUGGER_INACTIVE.
+ case kKeyboardInterruptExitCode: // Control-C/end session.
+ case kDebuggerTerminatedExitCode: // Debugger terminated process.
+ case kProcessKilledExitCode: // Task manager kill.
+ return TERMINATION_STATUS_PROCESS_WAS_KILLED;
+ default:
+ // All other exit codes indicate crashes.
+ return TERMINATION_STATUS_PROCESS_CRASHED;
}
-
- // All other exit codes indicate crashes.
- return true;
}
bool WaitForExitCode(ProcessHandle handle, int* exit_code) {
diff --git a/base/raw_scoped_refptr_mismatch_checker.h b/base/raw_scoped_refptr_mismatch_checker.h
index d2913e7..b79cfb5 100644
--- a/base/raw_scoped_refptr_mismatch_checker.h
+++ b/base/raw_scoped_refptr_mismatch_checker.h
@@ -7,165 +7,124 @@
#pragma once
#include "base/ref_counted.h"
+#include "base/template_util.h"
#include "base/tuple.h"
+#include "build/build_config.h"
-// It is dangerous to post a task with a raw pointer argument to a function
-// that expects a scoped_refptr<>. The compiler will happily accept the
-// situation, but it will not attempt to increase the refcount until the task
-// runs. Callers expecting the argument to be refcounted up at post time are
-// in for a nasty surprise! Example: http://crbug.com/27191
+// 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.
-template <class A, class B>
-struct ExpectsScopedRefptrButGetsRawPtr {
+
+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 internal {
+
+template <typename T>
+struct NeedsScopedRefptrButGetsRawPtr {
+#if defined(OS_WIN)
+ enum {
+ value = base::false_type::value
+ };
+#else
+ enum {
+ // 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.
+ value = (is_pointer<T>::value &&
+ (is_convertible<T, subtle::RefCountedBase*>::value ||
+ is_convertible<T, subtle::RefCountedThreadSafeBase*>::value))
+ };
+#endif
+};
+
+template <typename Params>
+struct ParamsUseScopedRefptrCorrectly {
enum { value = 0 };
};
-template <class A, class B>
-struct ExpectsScopedRefptrButGetsRawPtr<scoped_refptr<A>, B*> {
+template <>
+struct ParamsUseScopedRefptrCorrectly<Tuple0> {
enum { value = 1 };
};
-template <class Function, class Params>
-struct FunctionUsesScopedRefptrCorrectly {
- enum { value = 1 };
+template <typename A>
+struct ParamsUseScopedRefptrCorrectly<Tuple1<A> > {
+ enum { value = !NeedsScopedRefptrButGetsRawPtr<A>::value };
};
-template <class A1, class A2>
-struct FunctionUsesScopedRefptrCorrectly<void (*)(A1), Tuple1<A2> > {
- enum { value = !ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value };
+template <typename A, typename B>
+struct ParamsUseScopedRefptrCorrectly<Tuple2<A, B> > {
+ enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+ NeedsScopedRefptrButGetsRawPtr<B>::value) };
};
-template <class A1, class B1, class A2, class B2>
-struct FunctionUsesScopedRefptrCorrectly<void (*)(A1, B1), Tuple2<A2, B2> > {
- enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value) };
+template <typename A, typename B, typename C>
+struct ParamsUseScopedRefptrCorrectly<Tuple3<A, B, C> > {
+ enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+ NeedsScopedRefptrButGetsRawPtr<B>::value ||
+ NeedsScopedRefptrButGetsRawPtr<C>::value) };
};
-template <class A1, class B1, class C1, class A2, class B2, class C2>
-struct FunctionUsesScopedRefptrCorrectly<void (*)(A1, B1, C1),
- Tuple3<A2, B2, C2> > {
- enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value) };
+template <typename A, typename B, typename C, typename D>
+struct ParamsUseScopedRefptrCorrectly<Tuple4<A, B, C, D> > {
+ enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+ NeedsScopedRefptrButGetsRawPtr<B>::value ||
+ NeedsScopedRefptrButGetsRawPtr<C>::value ||
+ NeedsScopedRefptrButGetsRawPtr<D>::value) };
};
-template <class A1, class B1, class C1, class D1,
- class A2, class B2, class C2, class D2>
-struct FunctionUsesScopedRefptrCorrectly<void (*)(A1, B1, C1, D1),
- Tuple4<A2, B2, C2, D2> > {
- enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<D1, D2>::value) };
+template <typename A, typename B, typename C, typename D, typename E>
+struct ParamsUseScopedRefptrCorrectly<Tuple5<A, B, C, D, E> > {
+ enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+ NeedsScopedRefptrButGetsRawPtr<B>::value ||
+ NeedsScopedRefptrButGetsRawPtr<C>::value ||
+ NeedsScopedRefptrButGetsRawPtr<D>::value ||
+ NeedsScopedRefptrButGetsRawPtr<E>::value) };
};
-template <class A1, class B1, class C1, class D1, class E1,
- class A2, class B2, class C2, class D2, class E2>
-struct FunctionUsesScopedRefptrCorrectly<void (*)(A1, B1, C1, D1, E1),
- Tuple5<A2, B2, C2, D2, E2> > {
- enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<D1, D2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<E1, E2>::value) };
+template <typename A, typename B, typename C, typename D, typename E,
+ typename F>
+struct ParamsUseScopedRefptrCorrectly<Tuple6<A, B, C, D, E, F> > {
+ enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+ NeedsScopedRefptrButGetsRawPtr<B>::value ||
+ NeedsScopedRefptrButGetsRawPtr<C>::value ||
+ NeedsScopedRefptrButGetsRawPtr<D>::value ||
+ NeedsScopedRefptrButGetsRawPtr<E>::value ||
+ NeedsScopedRefptrButGetsRawPtr<F>::value) };
};
-template <class A1, class B1, class C1, class D1, class E1, class F1,
- class A2, class B2, class C2, class D2, class E2, class F2>
-struct FunctionUsesScopedRefptrCorrectly<void (*)(A1, B1, C1, D1, E1, F1),
- Tuple6<A2, B2, C2, D2, E2, F2> > {
- enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<D1, D2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<E1, E2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<F1, F2>::value) };
+template <typename A, typename B, typename C, typename D, typename E,
+ typename F, typename G>
+struct ParamsUseScopedRefptrCorrectly<Tuple7<A, B, C, D, E, F, G> > {
+ enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+ NeedsScopedRefptrButGetsRawPtr<B>::value ||
+ NeedsScopedRefptrButGetsRawPtr<C>::value ||
+ NeedsScopedRefptrButGetsRawPtr<D>::value ||
+ NeedsScopedRefptrButGetsRawPtr<E>::value ||
+ NeedsScopedRefptrButGetsRawPtr<F>::value ||
+ NeedsScopedRefptrButGetsRawPtr<G>::value) };
};
-template <class A1, class B1, class C1, class D1, class E1, class F1, class G1,
- class A2, class B2, class C2, class D2, class E2, class F2, class G2>
-struct FunctionUsesScopedRefptrCorrectly<void (*)(A1, B1, C1, D1, E1, F1, G1),
- Tuple7<A2, B2, C2, D2, E2, F2, G2> > {
- enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<D1, D2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<E1, E2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<F1, F2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<G1, G2>::value) };
+template <typename A, typename B, typename C, typename D, typename E,
+ typename F, typename G, typename H>
+struct ParamsUseScopedRefptrCorrectly<Tuple8<A, B, C, D, E, F, G, H> > {
+ enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+ NeedsScopedRefptrButGetsRawPtr<B>::value ||
+ NeedsScopedRefptrButGetsRawPtr<C>::value ||
+ NeedsScopedRefptrButGetsRawPtr<D>::value ||
+ NeedsScopedRefptrButGetsRawPtr<E>::value ||
+ NeedsScopedRefptrButGetsRawPtr<F>::value ||
+ NeedsScopedRefptrButGetsRawPtr<G>::value ||
+ NeedsScopedRefptrButGetsRawPtr<H>::value) };
};
-template <class Method, class Params>
-struct MethodUsesScopedRefptrCorrectly {
- enum { value = 1 };
-};
+} // namespace internal
-template <class T, class A1, class A2>
-struct MethodUsesScopedRefptrCorrectly<void (T::*)(A1), Tuple1<A2> > {
- enum { value = !ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value };
-};
-
-template <class T, class A1, class B1, class A2, class B2>
-struct MethodUsesScopedRefptrCorrectly<void (T::*)(A1, B1), Tuple2<A2, B2> > {
- enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value) };
-};
-
-template <class T, class A1, class B1, class C1,
- class A2, class B2, class C2>
-struct MethodUsesScopedRefptrCorrectly<void (T::*)(A1, B1, C1),
- Tuple3<A2, B2, C2> > {
- enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value) };
-};
-
-template <class T, class A1, class B1, class C1, class D1,
- class A2, class B2, class C2, class D2>
-struct MethodUsesScopedRefptrCorrectly<void (T::*)(A1, B1, C1, D1),
- Tuple4<A2, B2, C2, D2> > {
- enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<D1, D2>::value) };
-};
-
-template <class T, class A1, class B1, class C1, class D1, class E1,
- class A2, class B2, class C2, class D2, class E2>
-struct MethodUsesScopedRefptrCorrectly<void (T::*)(A1, B1, C1, D1, E1),
- Tuple5<A2, B2, C2, D2, E2> > {
- enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<D1, D2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<E1, E2>::value) };
-};
-
-template <class T, class A1, class B1, class C1, class D1, class E1, class F1,
- class A2, class B2, class C2, class D2, class E2, class F2>
-struct MethodUsesScopedRefptrCorrectly<void (T::*)(A1, B1, C1, D1, E1, F1),
- Tuple6<A2, B2, C2, D2, E2, F2> > {
- enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<D1, D2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<E1, E2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<F1, F2>::value) };
-};
-
-template <class T,
- class A1, class B1, class C1, class D1, class E1, class F1, class G1,
- class A2, class B2, class C2, class D2, class E2, class F2, class G2>
-struct MethodUsesScopedRefptrCorrectly<void (T::*)(A1, B1, C1, D1, E1, F1, G1),
- Tuple7<A2, B2, C2, D2, E2, F2, G2> > {
- enum { value = !(ExpectsScopedRefptrButGetsRawPtr<A1, A2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<B1, B2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<C1, C2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<D1, D2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<E1, E2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<F1, F2>::value ||
- ExpectsScopedRefptrButGetsRawPtr<G1, G2>::value) };
-};
+} // namespace base
#endif // BASE_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
diff --git a/base/scoped_handle_win.h b/base/scoped_handle_win.h
index a98114b..09bb2cb 100644
--- a/base/scoped_handle_win.h
+++ b/base/scoped_handle_win.h
@@ -4,14 +4,13 @@
// TODO(brettw) remove this file when all callers are converted to using the
// new location/namespace
-#include "base/win/scoped_handle.h"
#include "base/win/scoped_gdi_object.h"
#include "base/win/scoped_handle.h"
+#include "base/win/scoped_handle.h"
#include "base/win/scoped_hdc.h"
#include "base/win/scoped_hglobal.h"
using base::win::ScopedBitmap;
-using base::win::ScopedGDIObject;
using base::win::ScopedHandle;
using base::win::ScopedHDC;
using base::win::ScopedHFONT;
diff --git a/base/scoped_variant_win.h b/base/scoped_variant_win.h
deleted file mode 100644
index 3d6b650..0000000
--- a/base/scoped_variant_win.h
+++ /dev/null
@@ -1,9 +0,0 @@
-// 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.
-
-// TODO(brettw) remove this file when all callers are converted to using the
-// new location/namespace
-#include "base/win/scoped_variant.h"
-
-using base::win::ScopedVariant;
diff --git a/base/singleton.h b/base/singleton.h
index 8435c43..e5713c4 100644
--- a/base/singleton.h
+++ b/base/singleton.h
@@ -114,7 +114,6 @@ template <typename Type> intptr_t
template <typename Type> base::subtle::Atomic32
StaticMemorySingletonTraits<Type>::dead_ = 0;
-
// The Singleton<Type, Traits, DifferentiatingType> class manages a single
// instance of Type which will be created on first use and will be destroyed at
// normal process exit). The Trait::Delete function will not be called on
@@ -124,15 +123,37 @@ template <typename Type> base::subtle::Atomic32
// singletons having the same memory allocation functions but serving a
// different purpose. This is mainly used for Locks serving different purposes.
//
-// Example usages: (none are preferred, they all result in the same code)
-// 1. FooClass* ptr = Singleton<FooClass>::get();
-// ptr->Bar();
-// 2. Singleton<FooClass>()->Bar();
-// 3. Singleton<FooClass>::get()->Bar();
+// Example usage:
+//
+// In your header:
+// #include "base/singleton.h"
+// class FooClass {
+// public:
+// static FooClass* GetInstance(); <-- See comment below on this.
+// void Bar() { ... }
+// private:
+// FooClass() { ... }
+// friend struct DefaultSingletonTraits<FooClass>;
+//
+// DISALLOW_COPY_AND_ASSIGN(FooClass);
+// };
+//
+// In your source file:
+// FooClass* FooClass::GetInstance() {
+// return Singleton<FooClass>::get();
+// }
+//
+// And to call methods on FooClass:
+// FooClass::GetInstance()->Bar();
+//
+// NOTE: The method accessing Singleton<T>::get() has to be named as GetInstance
+// and it is important that FooClass::GetInstance() is not inlined in the
+// header. This makes sure that when source files from multiple targets include
+// this header they don't end up with different copies of the inlined code
+// creating multiple copies of the singleton.
//
// Singleton<> has no non-static members and doesn't need to actually be
-// instantiated. It does no harm to instantiate it and use it as a class member
-// or at global level since it is acting as a POD type.
+// instantiated.
//
// This class is itself thread-safe. The underlying Type must of course be
// thread-safe if you want to use it concurrently. Two parameters may be tuned
@@ -152,20 +173,6 @@ template <typename Type> base::subtle::Atomic32
// shouldn't be false unless absolutely necessary. Remember that the heap where
// the object is allocated may be destroyed by the CRT anyway.
//
-// If you want to ensure that your class can only exist as a singleton, make
-// its constructors private, and make DefaultSingletonTraits<> a friend:
-//
-// #include "base/singleton.h"
-// class FooClass {
-// public:
-// void Bar() { ... }
-// private:
-// FooClass() { ... }
-// friend struct DefaultSingletonTraits<FooClass>;
-//
-// DISALLOW_COPY_AND_ASSIGN(FooClass);
-// };
-//
// Caveats:
// (a) Every call to get(), operator->() and operator*() incurs some overhead
// (16ns on my P4/2.8GHz) to check whether the object has already been
@@ -179,7 +186,11 @@ template <typename Type,
typename Traits = DefaultSingletonTraits<Type>,
typename DifferentiatingType = Type>
class Singleton {
- public:
+ private:
+ // Classes using the Singleton<T> pattern should declare a GetInstance()
+ // method and call Singleton::get() from within that.
+ friend Type* Type::GetInstance();
+
// This class is safe to be constructed and copy-constructed since it has no
// member.
@@ -240,16 +251,6 @@ class Singleton {
return reinterpret_cast<Type*>(value);
}
- // Shortcuts.
- Type& operator*() {
- return *get();
- }
-
- Type* operator->() {
- return get();
- }
-
- private:
// Adapter function for use with AtExit(). This should be called single
// threaded, so don't use atomic operations.
// Calling OnExit while singleton is in use by other threads is a mistake.
diff --git a/base/singleton_unittest.cc b/base/singleton_unittest.cc
index acb1247..3d7e7e6 100644
--- a/base/singleton_unittest.cc
+++ b/base/singleton_unittest.cc
@@ -12,87 +12,131 @@ namespace {
COMPILE_ASSERT(DefaultSingletonTraits<int>::kRegisterAtExit == true, a);
-template<typename Type>
-struct LockTrait : public DefaultSingletonTraits<Type> {
-};
+typedef void (*CallbackFunc)();
-struct Init5Trait : public DefaultSingletonTraits<int> {
- static int* New() {
- return new int(5);
+class IntSingleton {
+ public:
+ static IntSingleton* GetInstance() {
+ return Singleton<IntSingleton>::get();
}
+
+ int value_;
};
-typedef void (*CallbackFunc)();
+class Init5Singleton {
+ public:
+ struct Trait;
-struct CallbackTrait : public DefaultSingletonTraits<CallbackFunc> {
- static void Delete(CallbackFunc* p) {
- if (*p)
- (*p)();
- DefaultSingletonTraits<CallbackFunc>::Delete(p);
+ static Init5Singleton* GetInstance() {
+ return Singleton<Init5Singleton, Trait>::get();
}
+
+ int value_;
};
-struct StaticCallbackTrait : public StaticMemorySingletonTraits<CallbackFunc> {
- static void Delete(CallbackFunc* p) {
- if (*p)
- (*p)();
- StaticMemorySingletonTraits<CallbackFunc>::Delete(p);
+struct Init5Singleton::Trait : public DefaultSingletonTraits<Init5Singleton> {
+ static Init5Singleton* New() {
+ Init5Singleton* instance = new Init5Singleton();
+ instance->value_ = 5;
+ return instance;
}
};
+int* SingletonInt() {
+ return &IntSingleton::GetInstance()->value_;
+}
+
+int* SingletonInt5() {
+ return &Init5Singleton::GetInstance()->value_;
+}
-struct NoLeakTrait : public CallbackTrait {
+template <typename Type>
+struct CallbackTrait : public DefaultSingletonTraits<Type> {
+ static void Delete(Type* instance) {
+ if (instance->callback_)
+ (instance->callback_)();
+ DefaultSingletonTraits<Type>::Delete(instance);
+ }
};
-struct LeakTrait : public CallbackTrait {
- static const bool kRegisterAtExit = false;
+class CallbackSingleton {
+ public:
+ CallbackSingleton() : callback_(NULL) { }
+ CallbackFunc callback_;
};
-int* SingletonInt1() {
- return Singleton<int>::get();
-}
+class CallbackSingletonWithNoLeakTrait : public CallbackSingleton {
+ public:
+ struct Trait : public CallbackTrait<CallbackSingletonWithNoLeakTrait> { };
-int* SingletonInt2() {
- // Force to use a different singleton than SingletonInt1.
- return Singleton<int, DefaultSingletonTraits<int> >::get();
-}
+ CallbackSingletonWithNoLeakTrait() : CallbackSingleton() { }
-class DummyDifferentiatingClass {
+ static CallbackSingletonWithNoLeakTrait* GetInstance() {
+ return Singleton<CallbackSingletonWithNoLeakTrait, Trait>::get();
+ }
};
-int* SingletonInt3() {
- // Force to use a different singleton than SingletonInt1 and SingletonInt2.
- // Note that any type can be used; int, float, std::wstring...
- return Singleton<int, DefaultSingletonTraits<int>,
- DummyDifferentiatingClass>::get();
-}
+class CallbackSingletonWithLeakTrait : public CallbackSingleton {
+ public:
+ struct Trait : public CallbackTrait<CallbackSingletonWithLeakTrait> {
+ static const bool kRegisterAtExit = false;
+ };
-int* SingletonInt4() {
- return Singleton<int, LockTrait<int> >::get();
-}
+ CallbackSingletonWithLeakTrait() : CallbackSingleton() { }
+
+ static CallbackSingletonWithLeakTrait* GetInstance() {
+ return Singleton<CallbackSingletonWithLeakTrait, Trait>::get();
+ }
+};
+
+class CallbackSingletonWithStaticTrait : public CallbackSingleton {
+ public:
+ struct Trait;
+
+ CallbackSingletonWithStaticTrait() : CallbackSingleton() { }
+
+ static CallbackSingletonWithStaticTrait* GetInstance() {
+ return Singleton<CallbackSingletonWithStaticTrait, Trait>::get();
+ }
+};
+
+struct CallbackSingletonWithStaticTrait::Trait
+ : public StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait> {
+ static void Delete(CallbackSingletonWithStaticTrait* instance) {
+ if (instance->callback_)
+ (instance->callback_)();
+ StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait>::Delete(
+ instance);
+ }
+};
-int* SingletonInt5() {
- return Singleton<int, Init5Trait>::get();
-}
void SingletonNoLeak(CallbackFunc CallOnQuit) {
- *Singleton<CallbackFunc, NoLeakTrait>::get() = CallOnQuit;
+ CallbackSingletonWithNoLeakTrait::GetInstance()->callback_ = CallOnQuit;
}
void SingletonLeak(CallbackFunc CallOnQuit) {
- *Singleton<CallbackFunc, LeakTrait>::get() = CallOnQuit;
+ CallbackSingletonWithLeakTrait::GetInstance()->callback_ = CallOnQuit;
}
CallbackFunc* GetLeakySingleton() {
- return Singleton<CallbackFunc, LeakTrait>::get();
+ return &CallbackSingletonWithLeakTrait::GetInstance()->callback_;
+}
+
+void DeleteLeakySingleton() {
+ DefaultSingletonTraits<CallbackSingletonWithLeakTrait>::Delete(
+ CallbackSingletonWithLeakTrait::GetInstance());
}
void SingletonStatic(CallbackFunc CallOnQuit) {
- *Singleton<CallbackFunc, StaticCallbackTrait>::get() = CallOnQuit;
+ CallbackSingletonWithStaticTrait::GetInstance()->callback_ = CallOnQuit;
}
CallbackFunc* GetStaticSingleton() {
- return Singleton<CallbackFunc, StaticCallbackTrait>::get();
+ return &CallbackSingletonWithStaticTrait::GetInstance()->callback_;
+}
+
+void ResurrectStaticSingleton() {
}
} // namespace
@@ -149,10 +193,7 @@ bool SingletonTest::leaky_called_ = false;
bool SingletonTest::static_called_ = false;
TEST_F(SingletonTest, Basic) {
- int* singleton_int_1;
- int* singleton_int_2;
- int* singleton_int_3;
- int* singleton_int_4;
+ int* singleton_int;
int* singleton_int_5;
CallbackFunc* leaky_singleton;
CallbackFunc* static_singleton;
@@ -160,49 +201,20 @@ TEST_F(SingletonTest, Basic) {
{
base::ShadowingAtExitManager sem;
{
- singleton_int_1 = SingletonInt1();
+ singleton_int = SingletonInt();
}
// Ensure POD type initialization.
- EXPECT_EQ(*singleton_int_1, 0);
- *singleton_int_1 = 1;
-
- EXPECT_EQ(singleton_int_1, SingletonInt1());
- EXPECT_EQ(*singleton_int_1, 1);
-
- {
- singleton_int_2 = SingletonInt2();
- }
- // Same instance that 1.
- EXPECT_EQ(*singleton_int_2, 1);
- EXPECT_EQ(singleton_int_1, singleton_int_2);
+ EXPECT_EQ(*singleton_int, 0);
+ *singleton_int = 1;
- {
- singleton_int_3 = SingletonInt3();
- }
- // Different instance than 1 and 2.
- EXPECT_EQ(*singleton_int_3, 0);
- EXPECT_NE(singleton_int_1, singleton_int_3);
- *singleton_int_3 = 3;
- EXPECT_EQ(*singleton_int_1, 1);
- EXPECT_EQ(*singleton_int_2, 1);
-
- {
- singleton_int_4 = SingletonInt4();
- }
- // Use a lock for creation. Not really tested at length.
- EXPECT_EQ(*singleton_int_4, 0);
- *singleton_int_4 = 4;
- EXPECT_NE(singleton_int_1, singleton_int_4);
- EXPECT_NE(singleton_int_3, singleton_int_4);
+ EXPECT_EQ(singleton_int, SingletonInt());
+ EXPECT_EQ(*singleton_int, 1);
{
singleton_int_5 = SingletonInt5();
}
// Is default initialized to 5.
EXPECT_EQ(*singleton_int_5, 5);
- EXPECT_NE(singleton_int_1, singleton_int_5);
- EXPECT_NE(singleton_int_3, singleton_int_5);
- EXPECT_NE(singleton_int_4, singleton_int_5);
SingletonNoLeak(&CallbackNoLeak);
SingletonLeak(&CallbackLeak);
@@ -216,7 +228,7 @@ TEST_F(SingletonTest, Basic) {
VerifiesCallbacks();
// Delete the leaky singleton. It is interesting to note that Purify does
// *not* detect the leak when this call is commented out. :(
- DefaultSingletonTraits<CallbackFunc>::Delete(leaky_singleton);
+ DeleteLeakySingleton();
// The static singleton can't be acquired post-atexit.
EXPECT_EQ(NULL, GetStaticSingleton());
@@ -225,8 +237,8 @@ TEST_F(SingletonTest, Basic) {
base::ShadowingAtExitManager sem;
// Verifiy that the variables were reset.
{
- singleton_int_1 = SingletonInt1();
- EXPECT_EQ(*singleton_int_1, 0);
+ singleton_int = SingletonInt();
+ EXPECT_EQ(*singleton_int, 0);
}
{
singleton_int_5 = SingletonInt5();
@@ -235,7 +247,7 @@ TEST_F(SingletonTest, Basic) {
{
// Resurrect the static singleton, and assert that it
// still points to the same (static) memory.
- StaticMemorySingletonTraits<CallbackFunc>::Resurrect();
+ CallbackSingletonWithStaticTrait::Trait::Resurrect();
EXPECT_EQ(GetStaticSingleton(), static_singleton);
}
}
diff --git a/base/string_util.cc b/base/string_util.cc
index 1c97487..0e0f17b 100644
--- a/base/string_util.cc
+++ b/base/string_util.cc
@@ -38,6 +38,10 @@ struct EmptyStrings {
const std::string s;
const std::wstring ws;
const string16 s16;
+
+ static EmptyStrings* GetInstance() {
+ return Singleton<EmptyStrings>::get();
+ }
};
// Used by ReplaceStringPlaceholders to track the position in the string of
@@ -102,15 +106,15 @@ bool IsWprintfFormatPortable(const wchar_t* format) {
const std::string& EmptyString() {
- return Singleton<EmptyStrings>::get()->s;
+ return EmptyStrings::GetInstance()->s;
}
const std::wstring& EmptyWString() {
- return Singleton<EmptyStrings>::get()->ws;
+ return EmptyStrings::GetInstance()->ws;
}
const string16& EmptyString16() {
- return Singleton<EmptyStrings>::get()->s16;
+ return EmptyStrings::GetInstance()->s16;
}
#define WHITESPACE_UNICODE \
@@ -1094,40 +1098,3 @@ size_t base::strlcpy(char* dst, const char* src, size_t dst_size) {
size_t base::wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size) {
return lcpyT<wchar_t>(dst, src, dst_size);
}
-
-bool ElideString(const std::wstring& input, int max_len, std::wstring* output) {
- DCHECK(max_len >= 0);
- if (static_cast<int>(input.length()) <= max_len) {
- output->assign(input);
- return false;
- }
-
- switch (max_len) {
- case 0:
- output->clear();
- break;
- case 1:
- output->assign(input.substr(0, 1));
- break;
- case 2:
- output->assign(input.substr(0, 2));
- break;
- case 3:
- output->assign(input.substr(0, 1) + L"." +
- input.substr(input.length() - 1));
- break;
- case 4:
- output->assign(input.substr(0, 1) + L".." +
- input.substr(input.length() - 1));
- break;
- default: {
- int rstr_len = (max_len - 3) / 2;
- int lstr_len = rstr_len + ((max_len - 3) % 2);
- output->assign(input.substr(0, lstr_len) + L"..." +
- input.substr(input.length() - rstr_len));
- break;
- }
- }
-
- return true;
-}
diff --git a/base/string_util.h b/base/string_util.h
index 498ccc5..f65652c 100644
--- a/base/string_util.h
+++ b/base/string_util.h
@@ -523,14 +523,6 @@ string16 ReplaceStringPlaceholders(const string16& format_string,
const string16& a,
size_t* offset);
-// If the size of |input| is more than |max_len|, this function returns true and
-// |input| is shortened into |output| by removing chars in the middle (they are
-// replaced with up to 3 dots, as size permits).
-// Ex: ElideString(L"Hello", 10, &str) puts Hello in str and returns false.
-// ElideString(L"Hello my name is Tom", 10, &str) puts "Hell...Tom" in str and
-// returns true.
-bool ElideString(const std::wstring& input, int max_len, std::wstring* output);
-
// Returns true if the string passed in matches the pattern. The pattern
// string can contain wildcards like * and ?
// The backslash character (\) is an escape character for * and ?
diff --git a/base/string_util_unittest.cc b/base/string_util_unittest.cc
index b7639bb..cd45642 100644
--- a/base/string_util_unittest.cc
+++ b/base/string_util_unittest.cc
@@ -1056,33 +1056,6 @@ TEST(StringUtilTest, WprintfFormatPortabilityTest) {
}
}
-TEST(StringUtilTest, ElideString) {
- struct TestData {
- const wchar_t* input;
- int max_len;
- bool result;
- const wchar_t* output;
- } cases[] = {
- { L"Hello", 0, true, L"" },
- { L"", 0, false, L"" },
- { L"Hello, my name is Tom", 1, true, L"H" },
- { L"Hello, my name is Tom", 2, true, L"He" },
- { L"Hello, my name is Tom", 3, true, L"H.m" },
- { L"Hello, my name is Tom", 4, true, L"H..m" },
- { L"Hello, my name is Tom", 5, true, L"H...m" },
- { L"Hello, my name is Tom", 6, true, L"He...m" },
- { L"Hello, my name is Tom", 7, true, L"He...om" },
- { L"Hello, my name is Tom", 10, true, L"Hell...Tom" },
- { L"Hello, my name is Tom", 100, false, L"Hello, my name is Tom" }
- };
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- std::wstring output;
- EXPECT_EQ(cases[i].result,
- ElideString(cases[i].input, cases[i].max_len, &output));
- EXPECT_TRUE(output == cases[i].output);
- }
-}
-
TEST(StringUtilTest, RemoveChars) {
const char* kRemoveChars = "-/+*";
std::string input = "A-+bc/d!*";
diff --git a/base/stringprintf.h b/base/stringprintf.h
index f3ca6e7..9170ddd 100644
--- a/base/stringprintf.h
+++ b/base/stringprintf.h
@@ -49,6 +49,5 @@ void StringAppendV(std::wstring* dst, const wchar_t* format, va_list ap)
//
// TODO(brettw) remove these when calling code is converted.
using base::StringPrintf;
-using base::StringAppendV;
#endif // BASE_STRINGPRINTF_H_
diff --git a/base/task.h b/base/task.h
index b21ccd8..e6e0d2d 100644
--- a/base/task.h
+++ b/base/task.h
@@ -149,8 +149,9 @@ class ScopedRunnableMethodFactory {
: obj_(obj),
meth_(meth),
params_(params) {
- COMPILE_ASSERT((MethodUsesScopedRefptrCorrectly<Method, Params>::value),
- badscopedrunnablemethodparams);
+ COMPILE_ASSERT(
+ (base::internal::ParamsUseScopedRefptrCorrectly<Params>::value),
+ badscopedrunnablemethodparams);
}
virtual void Run() {
@@ -317,8 +318,9 @@ class RunnableMethod : public CancelableTask {
RunnableMethod(T* obj, Method meth, const Params& params)
: obj_(obj), meth_(meth), params_(params) {
traits_.RetainCallee(obj_);
- COMPILE_ASSERT((MethodUsesScopedRefptrCorrectly<Method, Params>::value),
- badrunnablemethodparams);
+ COMPILE_ASSERT(
+ (base::internal::ParamsUseScopedRefptrCorrectly<Params>::value),
+ badrunnablemethodparams);
}
~RunnableMethod() {
@@ -336,10 +338,10 @@ class RunnableMethod : public CancelableTask {
private:
void ReleaseCallee() {
- if (obj_) {
- traits_.ReleaseCallee(obj_);
- obj_ = NULL;
- }
+ T* obj = obj_;
+ obj_ = NULL;
+ if (obj)
+ traits_.ReleaseCallee(obj);
}
T* obj_;
@@ -429,8 +431,9 @@ class RunnableFunction : public CancelableTask {
public:
RunnableFunction(Function function, const Params& params)
: function_(function), params_(params) {
- COMPILE_ASSERT((FunctionUsesScopedRefptrCorrectly<Function, Params>::value),
- badrunnablefunctionparams);
+ COMPILE_ASSERT(
+ (base::internal::ParamsUseScopedRefptrCorrectly<Params>::value),
+ badrunnablefunctionparams);
}
~RunnableFunction() {
diff --git a/base/task_unittest.cc b/base/task_unittest.cc
new file mode 100644
index 0000000..cc975e0
--- /dev/null
+++ b/base/task_unittest.cc
@@ -0,0 +1,52 @@
+// 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.
+
+#include "base/ref_counted.h"
+#include "base/task.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class CancelInDestructor : public base::RefCounted<CancelInDestructor> {
+ public:
+ CancelInDestructor() : cancelable_task_(NULL) {}
+
+ void Start() {
+ if (cancelable_task_) {
+ ADD_FAILURE();
+ return;
+ }
+ AddRef();
+ cancelable_task_ = NewRunnableMethod(
+ this, &CancelInDestructor::NeverIssuedCallback);
+ Release();
+ }
+
+ CancelableTask* cancelable_task() {
+ return cancelable_task_;
+ }
+
+ private:
+ friend class base::RefCounted<CancelInDestructor>;
+
+ ~CancelInDestructor() {
+ if (cancelable_task_)
+ cancelable_task_->Cancel();
+ }
+
+ void NeverIssuedCallback() { NOTREACHED(); }
+
+ CancelableTask* cancelable_task_;
+};
+
+TEST(TaskTest, TestCancelInDestructor) {
+ // Intentionally not using a scoped_refptr for cancel_in_destructor.
+ CancelInDestructor* cancel_in_destructor = new CancelInDestructor();
+ cancel_in_destructor->Start();
+ CancelableTask* cancelable_task = cancel_in_destructor->cancelable_task();
+ ASSERT_TRUE(cancelable_task);
+ delete cancelable_task;
+}
+
+} // namespace
diff --git a/base/template_util.h b/base/template_util.h
index 2cfe04c..27bdb73 100644
--- a/base/template_util.h
+++ b/base/template_util.h
@@ -6,6 +6,8 @@
#define BASE_TEMPLATE_UTIL_H_
#pragma once
+#include "build/build_config.h"
+
namespace base {
// template definitions from tr1
@@ -25,6 +27,51 @@ typedef integral_constant<bool, false> false_type;
template <class T> struct is_pointer : false_type {};
template <class T> struct is_pointer<T*> : true_type {};
+namespace internal {
+
+// Types small_ and big_ are guaranteed such that sizeof(small_) <
+// sizeof(big_)
+typedef char small_;
+
+struct big_ {
+ small_ dummy[2];
+};
+
+#if !defined(OS_WIN)
+
+// This class is an implementation detail for is_convertible, and you
+// don't need to know how it works to use is_convertible. For those
+// who care: we declare two different functions, one whose argument is
+// of type To and one with a variadic argument list. We give them
+// return types of different size, so we can use sizeof to trick the
+// compiler into telling us which function it would have chosen if we
+// had called it with an argument of type From. See Alexandrescu's
+// _Modern C++ Design_ for more details on this sort of trick.
+
+template <typename From, typename To>
+struct ConvertHelper {
+ static small_ Test(To);
+ static big_ Test(...);
+ static From Create();
+};
+
+#endif // !defined(OS_WIN)
+
+} // namespace internal
+
+#if !defined(OS_WIN)
+
+// Inherits from true_type if From is convertible to To, false_type otherwise.
+template <typename From, typename To>
+struct is_convertible
+ : integral_constant<bool,
+ sizeof(internal::ConvertHelper<From, To>::Test(
+ internal::ConvertHelper<From, To>::Create()))
+ == sizeof(internal::small_)> {
+};
+
+#endif // !defined(OS_WIN)
+
} // namespace base
#endif // BASE_TEMPLATE_UTIL_H_
diff --git a/base/test/mock_chrome_application_mac.h b/base/test/mock_chrome_application_mac.h
new file mode 100644
index 0000000..e7e2c67
--- /dev/null
+++ b/base/test/mock_chrome_application_mac.h
@@ -0,0 +1,28 @@
+// 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.
+
+#ifndef BASE_TEST_MOCK_CHROME_APPLICATION_MAC_H_
+#define BASE_TEST_MOCK_CHROME_APPLICATION_MAC_H_
+#pragma once
+
+#if defined(__OBJC__)
+
+#import <AppKit/AppKit.h>
+
+#include "base/message_pump_mac.h"
+
+// A mock implementation of CrAppProtocol that claims that -sendEvent: is never
+// on the stack. This can be used in tests that need an NSApplication and use a
+// runloop, but don't run nested message loops.
+@interface MockCrApp : NSApplication<CrAppProtocol>
+@end
+
+#endif
+
+// To be used to instantiate MockCrApp from C++ code.
+namespace mock_cr_app {
+void RegisterMockCrApp();
+} // namespace mock_cr_app
+
+#endif // BASE_TEST_MOCK_CHROME_APPLICATION_MAC_H_
diff --git a/base/test/mock_chrome_application_mac.mm b/base/test/mock_chrome_application_mac.mm
new file mode 100644
index 0000000..f7010c4
--- /dev/null
+++ b/base/test/mock_chrome_application_mac.mm
@@ -0,0 +1,19 @@
+// 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.
+
+#include "base/test/mock_chrome_application_mac.h"
+
+@implementation MockCrApp
+- (BOOL)isHandlingSendEvent {
+ return NO;
+}
+@end
+
+namespace mock_cr_app {
+
+void RegisterMockCrApp() {
+ [MockCrApp sharedApplication];
+}
+
+} // namespace mock_cr_app
diff --git a/base/test/test_switches.cc b/base/test/test_switches.cc
index 1dfd63f..991f4f3 100644
--- a/base/test/test_switches.cc
+++ b/base/test/test_switches.cc
@@ -10,6 +10,7 @@ const char switches::kLiveOperationTimeout[] = "live-operation-timeout";
// Time (in milliseconds) that the tests should wait before timing out.
// TODO(phajdan.jr): Clean up the switch names.
const char switches::kTestLargeTimeout[] = "test-large-timeout";
+const char switches::kTestTinyTimeout[] = "test-tiny-timeout";
const char switches::kUiTestActionTimeout[] = "ui-test-action-timeout";
const char switches::kUiTestActionMaxTimeout[] = "ui-test-action-max-timeout";
const char switches::kUiTestCommandExecutionTimeout[] = "ui-test-timeout";
diff --git a/base/test/test_switches.h b/base/test/test_switches.h
index 2194596..44ebd23 100644
--- a/base/test/test_switches.h
+++ b/base/test/test_switches.h
@@ -11,6 +11,7 @@ namespace switches {
// alongside the definition of their values in the .cc file.
extern const char kLiveOperationTimeout[];
extern const char kTestLargeTimeout[];
+extern const char kTestTinyTimeout[];
extern const char kUiTestActionTimeout[];
extern const char kUiTestActionMaxTimeout[];
extern const char kUiTestCommandExecutionTimeout[];
diff --git a/base/test/test_timeouts.cc b/base/test/test_timeouts.cc
index 7ee1b70..046f320 100644
--- a/base/test/test_timeouts.cc
+++ b/base/test/test_timeouts.cc
@@ -42,6 +42,7 @@ bool TestTimeouts::initialized_ = false;
// The timeout values should increase in the order they appear in this block.
// static
+int TestTimeouts::tiny_timeout_ms_ = 100;
int TestTimeouts::action_timeout_ms_ = 2000;
int TestTimeouts::action_max_timeout_ms_ = 15000;
int TestTimeouts::large_test_timeout_ms_ = 3 * 60 * 1000;
@@ -66,7 +67,9 @@ void TestTimeouts::Initialize() {
// Note that these timeouts MUST be initialized in the correct order as
// per the CHECKS below.
- InitializeTimeout(switches::kUiTestActionTimeout, &action_timeout_ms_);
+ InitializeTimeout(switches::kTestTinyTimeout, &tiny_timeout_ms_);
+ InitializeTimeout(switches::kUiTestActionTimeout, tiny_timeout_ms_,
+ &action_timeout_ms_);
InitializeTimeout(switches::kUiTestActionMaxTimeout, action_timeout_ms_,
&action_max_timeout_ms_);
InitializeTimeout(switches::kTestLargeTimeout, action_max_timeout_ms_,
@@ -75,6 +78,7 @@ void TestTimeouts::Initialize() {
&huge_test_timeout_ms_);
// The timeout values should be increasing in the right order.
+ CHECK(tiny_timeout_ms_ <= action_timeout_ms_);
CHECK(action_timeout_ms_ <= action_max_timeout_ms_);
CHECK(action_max_timeout_ms_ <= large_test_timeout_ms_);
CHECK(large_test_timeout_ms_ <= huge_test_timeout_ms_);
diff --git a/base/test/test_timeouts.h b/base/test/test_timeouts.h
index d49ca2c..f4cb1ff 100644
--- a/base/test/test_timeouts.h
+++ b/base/test/test_timeouts.h
@@ -15,6 +15,9 @@ class TestTimeouts {
// by the test suite.
static void Initialize();
+ // Timeout for actions that are expected to finish "almost instantly".
+ static int tiny_timeout_ms() { return tiny_timeout_ms_; }
+
// Timeout to wait for something to happen. If you are not sure
// which timeout to use, this is the one you want.
static int action_timeout_ms() { return action_timeout_ms_; }
@@ -52,6 +55,7 @@ class TestTimeouts {
private:
static bool initialized_;
+ static int tiny_timeout_ms_;
static int action_timeout_ms_;
static int action_max_timeout_ms_;
static int large_test_timeout_ms_;
diff --git a/base/third_party/nspr/prcpucfg.h b/base/third_party/nspr/prcpucfg.h
index 8651edd..95c2c0a 100644
--- a/base/third_party/nspr/prcpucfg.h
+++ b/base/third_party/nspr/prcpucfg.h
@@ -34,7 +34,11 @@
#include "base/third_party/nspr/prcpucfg_win.h"
#elif defined(__APPLE__)
#include "base/third_party/nspr/prcpucfg_mac.h"
+<<<<<<< HEAD
#elif defined(__linux__) || defined(ANDROID)
+=======
+#elif defined(__linux__) || defined(__native_client__)
+>>>>>>> chromium.org at r10.0.621.0
#include "base/third_party/nspr/prcpucfg_linux.h"
#elif defined(__FreeBSD__)
#include "base/third_party/nspr/prcpucfg_freebsd.h"
diff --git a/base/time_win.cc b/base/time_win.cc
index 5d3ecd6..ca3aef1 100644
--- a/base/time_win.cc
+++ b/base/time_win.cc
@@ -310,16 +310,8 @@ TimeDelta RolloverProtectedNow() {
// retrieve and more reliable.
class HighResNowSingleton {
public:
- HighResNowSingleton()
- : ticks_per_microsecond_(0.0),
- skew_(0) {
- InitializeClock();
-
- // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is
- // unreliable. Fallback to low-res clock.
- base::CPU cpu;
- if (cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15)
- DisableHighResClock();
+ static HighResNowSingleton* GetInstance() {
+ return Singleton<HighResNowSingleton>::get();
}
bool IsUsingHighResClock() {
@@ -346,6 +338,18 @@ class HighResNowSingleton {
}
private:
+ HighResNowSingleton()
+ : ticks_per_microsecond_(0.0),
+ skew_(0) {
+ InitializeClock();
+
+ // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is
+ // unreliable. Fallback to low-res clock.
+ base::CPU cpu;
+ if (cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15)
+ DisableHighResClock();
+ }
+
// Synchronize the QPC clock with GetSystemTimeAsFileTime.
void InitializeClock() {
LARGE_INTEGER ticks_per_sec = {0};
@@ -374,7 +378,7 @@ class HighResNowSingleton {
float ticks_per_microsecond_; // 0 indicates QPF failed and we're broken.
int64 skew_; // Skew between lo-res and hi-res clocks (for debugging).
- DISALLOW_COPY_AND_ASSIGN(HighResNowSingleton);
+ friend struct DefaultSingletonTraits<HighResNowSingleton>;
};
} // namespace
@@ -394,15 +398,15 @@ TimeTicks TimeTicks::Now() {
// static
TimeTicks TimeTicks::HighResNow() {
- return TimeTicks() + Singleton<HighResNowSingleton>::get()->Now();
+ return TimeTicks() + HighResNowSingleton::GetInstance()->Now();
}
// static
int64 TimeTicks::GetQPCDriftMicroseconds() {
- return Singleton<HighResNowSingleton>::get()->GetQPCDriftMicroseconds();
+ return HighResNowSingleton::GetInstance()->GetQPCDriftMicroseconds();
}
// static
bool TimeTicks::IsHighResClockWorking() {
- return Singleton<HighResNowSingleton>::get()->IsUsingHighResClock();
+ return HighResNowSingleton::GetInstance()->IsUsingHighResClock();
} \ No newline at end of file
diff --git a/base/tuple.h b/base/tuple.h
index bfe6562..6b0d336 100644
--- a/base/tuple.h
+++ b/base/tuple.h
@@ -30,6 +30,10 @@
#define BASE_TUPLE_H__
#pragma once
+#if defined(OS_CHROMEOS)
+// To troubleshoot crosbug.com/7327.
+#include "base/logging.h"
+#endif
// Traits ----------------------------------------------------------------------
//
// A simple traits class for tuple arguments.
@@ -545,7 +549,7 @@ inline void DispatchToMethod(ObjT* obj, Method method, const A& arg) {
template <class ObjT, class Method, class A>
inline void DispatchToMethod(ObjT* obj, Method method, const Tuple1<A>& arg) {
-#if defined(OS_CHROMEOS) && defined(CHECK)
+#if defined(OS_CHROMEOS)
// To troubleshoot crosbug.com/7327.
CHECK(obj);
CHECK(&arg);
diff --git a/base/unix_domain_socket_posix.cc b/base/unix_domain_socket_posix.cc
deleted file mode 100644
index 73fa260..0000000
--- a/base/unix_domain_socket_posix.cc
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright (c) 2009 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/unix_domain_socket_posix.h"
-
-#include <errno.h>
-#include <unistd.h>
-#include <sys/uio.h>
-#include <sys/socket.h>
-
-#include "base/eintr_wrapper.h"
-#include "base/logging.h"
-#include "base/pickle.h"
-
-namespace base {
-
-bool SendMsg(int fd, const void* buf, size_t length,
- const std::vector<int>& fds) {
- struct msghdr msg;
- memset(&msg, 0, sizeof(msg));
- struct iovec iov = {const_cast<void*>(buf), length};
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
-
- char* control_buffer = NULL;
- if (fds.size()) {
- const unsigned control_len = CMSG_SPACE(sizeof(int) * fds.size());
- control_buffer = new char[control_len];
-
- struct cmsghdr *cmsg;
- msg.msg_control = control_buffer;
- msg.msg_controllen = control_len;
- cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(int) * fds.size());
- memcpy(CMSG_DATA(cmsg), &fds[0], sizeof(int) * fds.size());
- msg.msg_controllen = cmsg->cmsg_len;
- }
-
- const ssize_t r = HANDLE_EINTR(sendmsg(fd, &msg, 0));
- const bool ret = static_cast<ssize_t>(length) == r;
- delete[] control_buffer;
- return ret;
-}
-
-ssize_t RecvMsg(int fd, void* buf, size_t length, std::vector<int>* fds) {
- static const unsigned kMaxDescriptors = 16;
-
- fds->clear();
-
- struct msghdr msg;
- memset(&msg, 0, sizeof(msg));
- struct iovec iov = {buf, length};
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
-
- char control_buffer[CMSG_SPACE(sizeof(int) * kMaxDescriptors)];
- msg.msg_control = control_buffer;
- msg.msg_controllen = sizeof(control_buffer);
-
- const ssize_t r = HANDLE_EINTR(recvmsg(fd, &msg, 0));
- if (r == -1)
- return -1;
-
- int* wire_fds = NULL;
- unsigned wire_fds_len = 0;
-
- if (msg.msg_controllen > 0) {
- struct cmsghdr* cmsg;
- for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
- if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_RIGHTS) {
- const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0);
- DCHECK(payload_len % sizeof(int) == 0);
- wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
- wire_fds_len = payload_len / sizeof(int);
- break;
- }
- }
- }
-
- if (msg.msg_flags & MSG_TRUNC || msg.msg_flags & MSG_CTRUNC) {
- for (unsigned i = 0; i < wire_fds_len; ++i)
- close(wire_fds[i]);
- errno = EMSGSIZE;
- return -1;
- }
-
- fds->resize(wire_fds_len);
- memcpy(&(*fds)[0], wire_fds, sizeof(int) * wire_fds_len);
-
- return r;
-}
-
-ssize_t SendRecvMsg(int fd, uint8_t* reply, unsigned max_reply_len, int* result_fd,
- const Pickle& request) {
- int fds[2];
-
- // This socketpair is only used for the IPC and is cleaned up before
- // returning.
- if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fds) == -1)
- return false;
-
- std::vector<int> fd_vector;
- fd_vector.push_back(fds[1]);
- if (!SendMsg(fd, request.data(), request.size(), fd_vector)) {
- close(fds[0]);
- close(fds[1]);
- return -1;
- }
- close(fds[1]);
-
- fd_vector.clear();
- const ssize_t reply_len = RecvMsg(fds[0], reply, max_reply_len, &fd_vector);
- close(fds[0]);
- if (reply_len == -1)
- return -1;
-
- if ((fd_vector.size() > 0 && result_fd == NULL) || fd_vector.size() > 1) {
- for (std::vector<int>::const_iterator
- i = fd_vector.begin(); i != fd_vector.end(); ++i) {
- close(*i);
- }
-
- NOTREACHED();
-
- return -1;
- }
-
- if (result_fd) {
- if (fd_vector.size() == 0) {
- *result_fd = -1;
- } else {
- *result_fd = fd_vector[0];
- }
- }
-
- return reply_len;
-}
-
-} // namespace base
diff --git a/base/unix_domain_socket_posix.h b/base/unix_domain_socket_posix.h
deleted file mode 100644
index 51c821b..0000000
--- a/base/unix_domain_socket_posix.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) 2009 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 BASE_UNIX_DOMAIN_SOCKET_POSIX_H_
-#define BASE_UNIX_DOMAIN_SOCKET_POSIX_H_
-#pragma once
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <vector>
-
-class Pickle;
-
-namespace base {
-
-// Use sendmsg to write the given msg and include a vector
-// of file descriptors. Returns true iff successful.
-bool SendMsg(int fd, const void* msg, size_t length,
- const std::vector<int>& fds);
-// Use recvmsg to read a message and an array of file descriptors. Returns
-// -1 on failure. Note: will read, at most, 16 descriptors.
-ssize_t RecvMsg(int fd, void* msg, size_t length, std::vector<int>* fds);
-// Perform a sendmsg/recvmsg pair.
-// 1. This process creates a UNIX DGRAM socketpair.
-// 2. This proces writes a request to |fd| with an SCM_RIGHTS control message
-// containing on end of the fresh socket pair.
-// 3. This process blocks reading from the other end of the fresh socketpair.
-// 4. The target process receives the request, processes it and writes the
-// reply to the end of the socketpair contained in the request.
-// 5. This process wakes up and continues.
-//
-// fd: descriptor to send the request on
-// reply: buffer for the reply
-// reply_len: size of |reply|
-// result_fd: (may be NULL) the file descriptor returned in the reply (if any)
-// request: the bytes to send in the request
-ssize_t SendRecvMsg(int fd, uint8_t* reply, unsigned reply_len, int* result_fd,
- const Pickle& request);
-
-} // namespace base
-
-#endif // BASE_UNIX_DOMAIN_SOCKET_POSIX_H_
diff --git a/base/values.cc b/base/values.cc
index cd0f6a8..4553e68 100644
--- a/base/values.cc
+++ b/base/values.cc
@@ -119,6 +119,10 @@ bool Value::GetAsString(string16* out_value) const {
return false;
}
+bool Value::GetAsList(ListValue** out_value) {
+ return false;
+}
+
Value* Value::DeepCopy() const {
// This method should only be getting called for null Values--all subclasses
// need to provide their own implementation;.
@@ -133,6 +137,13 @@ bool Value::Equals(const Value* other) const {
return other->IsType(TYPE_NULL);
}
+// static
+bool Value::Equals(const Value* a, const Value* b) {
+ if ((a == NULL) && (b == NULL)) return true;
+ if ((a == NULL) ^ (b == NULL)) return false;
+ return a->Equals(b);
+}
+
Value::Value(ValueType type) : type_(type) {
}
@@ -674,114 +685,6 @@ void DictionaryValue::MergeDictionary(const DictionaryValue* dictionary) {
}
}
-bool DictionaryValue::GetDifferingPathsHelper(
- const std::string& path_prefix,
- const DictionaryValue* other,
- std::vector<std::string>* different_paths) const {
- bool added_path = false;
- std::map<std::string, Value*>::const_iterator current_this;
- std::map<std::string, Value*>::const_iterator end_this;
- current_this = dictionary_.begin();
- end_this = dictionary_.end();
- if (!other) {
- // Recursively add all paths from the |this| dictionary, since they are
- // not in |other|.
- for (; current_this != end_this; ++current_this) {
- std::string full_path_for_key(path_prefix.empty() ? current_this->first :
- path_prefix + "." + current_this->first);
- different_paths->push_back(full_path_for_key);
- added_path = true;
- if (current_this->second->IsType(Value::TYPE_DICTIONARY)) {
- const DictionaryValue* dictionary_this =
- static_cast<const DictionaryValue*>(current_this->second);
- dictionary_this->GetDifferingPathsHelper(full_path_for_key,
- NULL,
- different_paths);
- }
- }
- } else {
- // Both the |this| and |other| dictionaries have entries. Iterate over
- // both simultaneously. Paths that are in one but not the other are
- // added to |different_paths| and DictionaryValues are processed
- // recursively.
- std::map<std::string, Value*>::const_iterator current_other =
- other->dictionary_.begin();
- std::map<std::string, Value*>::const_iterator end_other =
- other->dictionary_.end();
- while (current_this != end_this || current_other != end_other) {
- const Value* recursion_this = NULL;
- const Value* recursion_other = NULL;
- const std::string* key_name = NULL;
- bool current_value_known_equal = false;
- if (current_this == end_this ||
- (current_other != end_other &&
- (current_other->first < current_this->first))) {
- key_name = &current_other->first;
- if (current_other->second->IsType(Value::TYPE_DICTIONARY))
- recursion_this = current_other->second;
- ++current_other;
- } else {
- key_name = &current_this->first;
- if (current_other == end_other ||
- current_this->first < current_other->first) {
- if (current_this->second->IsType(Value::TYPE_DICTIONARY))
- recursion_this = current_this->second;
- ++current_this;
- } else {
- DCHECK(current_this->first == current_other->first);
- if (current_this->second->IsType(Value::TYPE_DICTIONARY)) {
- recursion_this = current_this->second;
- if (current_other->second->IsType(Value::TYPE_DICTIONARY)) {
- recursion_other = current_other->second;
- }
- } else {
- if (current_other->second->IsType(Value::TYPE_DICTIONARY)) {
- recursion_this = current_other->second;
- } else {
- current_value_known_equal =
- current_this->second->Equals(current_other->second);
- }
- }
- ++current_this;
- ++current_other;
- }
- }
- const std::string& full_path_for_key(path_prefix.empty() ?
- *key_name : path_prefix + "." + *key_name);
- if (!current_value_known_equal)
- different_paths->push_back(full_path_for_key);
- if (recursion_this) {
- const DictionaryValue* dictionary_this =
- static_cast<const DictionaryValue*>(recursion_this);
- bool subtree_changed = dictionary_this->GetDifferingPathsHelper(
- full_path_for_key,
- static_cast<const DictionaryValue*>(recursion_other),
- different_paths);
- if (subtree_changed) {
- added_path = true;
- } else {
- // In order to maintain lexicographical sorting order, directory
- // paths are pushed "optimistically" assuming that their subtree will
- // contain differences. If in retrospect there were no differences
- // in the subtree, the assumption was false and the dictionary path
- // must be removed.
- different_paths->pop_back();
- }
- } else {
- added_path |= !current_value_known_equal;
- }
- }
- }
- return added_path;
-}
-
-void DictionaryValue::GetDifferingPaths(
- const DictionaryValue* other,
- std::vector<std::string>* different_paths) const {
- different_paths->clear();
- GetDifferingPathsHelper("", other, different_paths);
-}
-
///////////////////// ListValue ////////////////////
ListValue::ListValue() : Value(TYPE_LIST) {
@@ -954,6 +857,12 @@ bool ListValue::Insert(size_t index, Value* in_value) {
return true;
}
+bool ListValue::GetAsList(ListValue** out_value) {
+ if (out_value)
+ *out_value = this;
+ return true;
+}
+
Value* ListValue::DeepCopy() const {
ListValue* result = new ListValue;
diff --git a/base/values.h b/base/values.h
index 07d4985..2719d27 100644
--- a/base/values.h
+++ b/base/values.h
@@ -92,6 +92,7 @@ class Value {
virtual bool GetAsReal(double* out_value) const;
virtual bool GetAsString(std::string* out_value) const;
virtual bool GetAsString(string16* out_value) const;
+ virtual bool GetAsList(ListValue** out_value);
// This creates a deep copy of the entire Value tree, and returns a pointer
// to the copy. The caller gets ownership of the copy, of course.
@@ -100,6 +101,10 @@ class Value {
// Compares if two Value objects have equal contents.
virtual bool Equals(const Value* other) const;
+ // Compares if two Value objects have equal contents. Can handle NULLs.
+ // NULLs are considered equal but different from Value::CreateNullValue().
+ static bool Equals(const Value* a, const Value* b);
+
protected:
// This isn't safe for end-users (they should use the Create*Value()
// static methods above), but it's useful for subclasses.
@@ -119,7 +124,7 @@ class FundamentalValue : public Value {
explicit FundamentalValue(bool in_value);
explicit FundamentalValue(int in_value);
explicit FundamentalValue(double in_value);
- ~FundamentalValue();
+ virtual ~FundamentalValue();
// Subclassed methods
virtual bool GetAsBoolean(bool* out_value) const;
@@ -146,12 +151,12 @@ class StringValue : public Value {
// Initializes a StringValue with a string16.
explicit StringValue(const string16& in_value);
- ~StringValue();
+ virtual ~StringValue();
// Subclassed methods
- bool GetAsString(std::string* out_value) const;
- bool GetAsString(string16* out_value) const;
- Value* DeepCopy() const;
+ virtual bool GetAsString(std::string* out_value) const;
+ virtual bool GetAsString(string16* out_value) const;
+ virtual Value* DeepCopy() const;
virtual bool Equals(const Value* other) const;
private:
@@ -173,10 +178,10 @@ class BinaryValue: public Value {
// Returns NULL if buffer is NULL.
static BinaryValue* CreateWithCopiedBuffer(const char* buffer, size_t size);
- ~BinaryValue();
+ virtual ~BinaryValue();
// Subclassed methods
- Value* DeepCopy() const;
+ virtual Value* DeepCopy() const;
virtual bool Equals(const Value* other) const;
size_t GetSize() const { return size_; }
@@ -200,10 +205,10 @@ class BinaryValue: public Value {
class DictionaryValue : public Value {
public:
DictionaryValue();
- ~DictionaryValue();
+ virtual ~DictionaryValue();
// Subclassed methods
- Value* DeepCopy() const;
+ virtual Value* DeepCopy() const;
virtual bool Equals(const Value* other) const;
// Returns true if the current dictionary has a value for the given key.
@@ -303,16 +308,6 @@ class DictionaryValue : public Value {
// replaced.
void MergeDictionary(const DictionaryValue* dictionary);
- // Builds a vector containing all of the paths that are different between
- // the dictionary and a second specified dictionary. These are paths of
- // values that are either in one dictionary or the other but not both, OR
- // paths that are present in both dictionaries but differ in value.
- // Path strings are in ascending lexicographical order in the generated
- // vector. |different_paths| is cleared before added any paths.
- void GetDifferingPaths(
- const DictionaryValue* other,
- std::vector<std::string>* different_paths) const;
-
// This class provides an iterator for the keys in the dictionary.
// It can't be used to modify the dictionary.
//
@@ -339,17 +334,6 @@ class DictionaryValue : public Value {
key_iterator end_keys() const { return key_iterator(dictionary_.end()); }
private:
- // Does the actual heavy lifting for GetDifferingPaths.
- // Returns true if a path is added to different_paths, otherwise false.
- // The difference compuation is calculated recursively. The keys for
- // dictionaries that are handled by recursive calls more shallow than
- // the current one are concatenated and passed through to deeper calls in
- // |path_prefix|.
- bool GetDifferingPathsHelper(
- const std::string& path_prefix,
- const DictionaryValue* other,
- std::vector<std::string>* different_paths) const;
-
ValueMap dictionary_;
DISALLOW_COPY_AND_ASSIGN(DictionaryValue);
@@ -362,7 +346,8 @@ class ListValue : public Value {
~ListValue();
// Subclassed methods
- Value* DeepCopy() const;
+ virtual bool GetAsList(ListValue** out_value);
+ virtual Value* DeepCopy() const;
virtual bool Equals(const Value* other) const;
// Clears the contents of this ListValue
diff --git a/base/values_unittest.cc b/base/values_unittest.cc
index 9f34c62..adcd07e 100644
--- a/base/values_unittest.cc
+++ b/base/values_unittest.cc
@@ -10,27 +10,7 @@
#include "base/values.h"
#include "testing/gtest/include/gtest/gtest.h"
-class ValuesTest: public testing::Test {
- protected:
- void CompareDictionariesAndCheckResult(
- const DictionaryValue* dict1,
- const DictionaryValue* dict2,
- const char* expected_paths[],
- size_t expected_paths_count) {
- std::vector<std::string> differing_paths;
- std::vector<std::string> expected_paths_vector(expected_paths,
- expected_paths+expected_paths_count);
- // All comparisons should be commutative, check dict1 against dict2
- // and vice-versa.
- dict1->GetDifferingPaths(dict2, &differing_paths);
- ASSERT_EQ(expected_paths_count, differing_paths.size());
- EXPECT_TRUE(equal(differing_paths.begin(), differing_paths.end(),
- expected_paths_vector.begin()));
- dict2->GetDifferingPaths(dict1, &differing_paths);
- ASSERT_EQ(expected_paths_count, differing_paths.size());
- EXPECT_TRUE(equal(differing_paths.begin(), differing_paths.end(),
- expected_paths_vector.begin()));
- }
+class ValuesTest : public testing::Test {
};
TEST_F(ValuesTest, Basic) {
@@ -508,6 +488,29 @@ TEST_F(ValuesTest, Equals) {
EXPECT_FALSE(dv.Equals(copy.get()));
}
+TEST_F(ValuesTest, StaticEquals) {
+ scoped_ptr<Value> null1(Value::CreateNullValue());
+ scoped_ptr<Value> null2(Value::CreateNullValue());
+ EXPECT_TRUE(Value::Equals(null1.get(), null2.get()));
+ EXPECT_TRUE(Value::Equals(NULL, NULL));
+
+ scoped_ptr<Value> i42(Value::CreateIntegerValue(42));
+ scoped_ptr<Value> j42(Value::CreateIntegerValue(42));
+ scoped_ptr<Value> i17(Value::CreateIntegerValue(17));
+ EXPECT_TRUE(Value::Equals(i42.get(), i42.get()));
+ EXPECT_TRUE(Value::Equals(j42.get(), i42.get()));
+ EXPECT_TRUE(Value::Equals(i42.get(), j42.get()));
+ EXPECT_FALSE(Value::Equals(i42.get(), i17.get()));
+ EXPECT_FALSE(Value::Equals(i42.get(), NULL));
+ EXPECT_FALSE(Value::Equals(NULL, i42.get()));
+
+ // NULL and Value::CreateNullValue() are intentionally different: We need
+ // support for NULL as a return value for "undefined" without caring for
+ // ownership of the pointer.
+ EXPECT_FALSE(Value::Equals(null1.get(), NULL));
+ EXPECT_FALSE(Value::Equals(NULL, null1.get()));
+}
+
TEST_F(ValuesTest, RemoveEmptyChildren) {
scoped_ptr<DictionaryValue> root(new DictionaryValue);
// Remove empty lists and dictionaries.
@@ -627,114 +630,3 @@ TEST_F(ValuesTest, MergeDictionary) {
EXPECT_TRUE(res_sub_dict->GetString("sub_merge_key", &sub_merge_key_value));
EXPECT_EQ("sub_merge_key_value_merge", sub_merge_key_value); // Merged in.
}
-
-TEST_F(ValuesTest, GetDifferingPaths) {
- scoped_ptr<DictionaryValue> dict1(new DictionaryValue());
- scoped_ptr<DictionaryValue> dict2(new DictionaryValue());
- std::vector<std::string> differing_paths;
-
- // Test comparing empty dictionaries.
- dict1->GetDifferingPaths(dict2.get(), &differing_paths);
- EXPECT_EQ(differing_paths.size(), 0UL);
-
- // Compare an empty dictionary with various non-empty dictionaries.
- static const char* expected_paths1[] = {
- "segment1"
- };
- dict1->SetString("segment1", "value1");
- CompareDictionariesAndCheckResult(dict1.get(), dict2.get(), expected_paths1,
- arraysize(expected_paths1));
-
- static const char* expected_paths2[] = {
- "segment1",
- "segment2",
- "segment2.segment3"
- };
- dict1->SetString("segment2.segment3", "value2");
- CompareDictionariesAndCheckResult(dict1.get(), dict2.get(), expected_paths2,
- arraysize(expected_paths2));
-
- static const char* expected_paths3[] = {
- "segment1",
- "segment2",
- "segment2.segment3",
- "segment4",
- "segment4.segment5"
- };
- dict1->SetString("segment4.segment5", "value3");
- CompareDictionariesAndCheckResult(dict1.get(), dict2.get(), expected_paths3,
- arraysize(expected_paths3));
-
- // Now various tests with two populated dictionaries.
- static const char* expected_paths4[] = {
- "segment1",
- "segment2",
- "segment2.segment3",
- "segment4",
- "segment4.segment5"
- };
- dict2->Set("segment2", new DictionaryValue());
- CompareDictionariesAndCheckResult(dict1.get(), dict2.get(), expected_paths4,
- arraysize(expected_paths4));
-
- static const char* expected_paths5[] = {
- "segment1",
- "segment4",
- "segment4.segment5"
- };
- dict2->SetString("segment2.segment3", "value2");
- CompareDictionariesAndCheckResult(dict1.get(), dict2.get(), expected_paths5,
- arraysize(expected_paths5));
-
- dict2->SetBoolean("segment2.segment3", true);
- CompareDictionariesAndCheckResult(dict1.get(), dict2.get(), expected_paths4,
- arraysize(expected_paths4));
-
- // Test two identical dictionaries.
- dict2.reset(static_cast<DictionaryValue*>(dict1->DeepCopy()));
- dict2->GetDifferingPaths(dict1.get(), &differing_paths);
- EXPECT_EQ(differing_paths.size(), 0UL);
-
- // Test a deep dictionary structure.
- static const char* expected_paths6[] = {
- "s1",
- "s1.s2",
- "s1.s2.s3",
- "s1.s2.s3.s4",
- "s1.s2.s3.s4.s5"
- };
- dict1.reset(new DictionaryValue());
- dict2.reset(new DictionaryValue());
- dict1->Set("s1.s2.s3.s4.s5", new DictionaryValue());
- CompareDictionariesAndCheckResult(dict1.get(), dict2.get(), expected_paths6,
- arraysize(expected_paths6));
-
- // Make sure disjoint dictionaries generate the right differing path list.
- static const char* expected_paths7[] = {
- "a",
- "b",
- "c",
- "d"
- };
- dict1.reset(new DictionaryValue());
- dict1->SetBoolean("a", true);
- dict1->SetBoolean("c", true);
- dict2.reset(new DictionaryValue());
- dict1->SetBoolean("b", true);
- dict1->SetBoolean("d", true);
- CompareDictionariesAndCheckResult(dict1.get(), dict2.get(), expected_paths7,
- arraysize(expected_paths7));
-
- // For code coverage completeness. Make sure that all branches
- // that were not covered are executed.
- static const char* expected_paths8[] = {
- "s1",
- "s1.s2"
- };
- dict1.reset(new DictionaryValue());
- dict1->Set("s1.s2", new DictionaryValue());
- dict2.reset(new DictionaryValue());
- dict2->SetInteger("s1", 1);
- CompareDictionariesAndCheckResult(dict1.get(), dict2.get(), expected_paths8,
- arraysize(expected_paths8));
-}
diff --git a/base/values_util.cc b/base/values_util.cc
index 31d8e8c..fbc616b 100644
--- a/base/values_util.cc
+++ b/base/values_util.cc
@@ -12,3 +12,7 @@ RefCountedList::~RefCountedList() {
if (list_)
delete list_;
}
+
+ListValue* RefCountedList::Get() {
+ return list_;
+}
diff --git a/base/values_util.h b/base/values_util.h
index 57b35c1..1626bb5 100644
--- a/base/values_util.h
+++ b/base/values_util.h
@@ -15,9 +15,7 @@ class RefCountedList : public base::RefCountedThreadSafe<RefCountedList> {
explicit RefCountedList(ListValue* list);
virtual ~RefCountedList();
- virtual ListValue* Get() {
- return list_;
- }
+ virtual ListValue* Get();
private:
ListValue* list_;
diff --git a/base/version.cc b/base/version.cc
index fe224eb..384be0a 100644
--- a/base/version.cc
+++ b/base/version.cc
@@ -4,6 +4,8 @@
#include "base/version.h"
+#include <algorithm>
+
#include "base/logging.h"
#include "base/string_number_conversions.h"
#include "base/string_split.h"
@@ -11,13 +13,6 @@
#include "base/utf_string_conversions.h"
// static
-Version* Version::GetVersionFromString(const std::wstring& version_str) {
- if (!IsStringASCII(version_str))
- return NULL;
- return GetVersionFromString(WideToUTF8(version_str));
-}
-
-// static
Version* Version::GetVersionFromString(const std::string& version_str) {
Version* vers = new Version();
if (vers->InitFromString(version_str)) {
@@ -32,6 +27,14 @@ Version::Version() : is_valid_(false) {}
Version::~Version() {}
+Version* Version::Clone() const {
+ DCHECK(is_valid_);
+ Version* copy = new Version();
+ copy->components_ = components_;
+ copy->is_valid_ = true;
+ return copy;
+}
+
bool Version::Equals(const Version& that) const {
DCHECK(is_valid_);
DCHECK(that.is_valid_);
diff --git a/base/version.h b/base/version.h
index 2b182bb..2fda4ad 100644
--- a/base/version.h
+++ b/base/version.h
@@ -12,12 +12,14 @@
#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
+// Version represents a dotted version number, like "1.2.3.4", supporting
+// parsing and comparison.
+// Each component is limited to a uint16.
class Version {
public:
// The version string must be made up of 1 or more uint16's separated
// by '.'. Returns NULL if string is not in this format.
// Caller is responsible for freeing the Version object once done.
- static Version* GetVersionFromString(const std::wstring& version_str);
static Version* GetVersionFromString(const std::string& version_str);
// Exposed only so that a Version can be stored in STL containers;
@@ -27,6 +29,9 @@ class Version {
~Version();
+ // Creates a copy of this version. Caller takes ownership.
+ Version* Clone() const;
+
bool Equals(const Version& other) const;
// Returns -1, 0, 1 for <, ==, >.
diff --git a/base/waitable_event_watcher.h b/base/waitable_event_watcher.h
index b6f5e9e..04aa8cf 100644
--- a/base/waitable_event_watcher.h
+++ b/base/waitable_event_watcher.h
@@ -145,7 +145,7 @@ class WaitableEventWatcher
// ---------------------------------------------------------------------------
// Implementation of MessageLoop::DestructionObserver
// ---------------------------------------------------------------------------
- void WillDestroyCurrentMessageLoop();
+ virtual void WillDestroyCurrentMessageLoop();
MessageLoop* message_loop_;
scoped_refptr<Flag> cancel_flag_;
diff --git a/base/watchdog_unittest.cc b/base/watchdog_unittest.cc
index 19dfe28..658a31a 100644
--- a/base/watchdog_unittest.cc
+++ b/base/watchdog_unittest.cc
@@ -86,7 +86,7 @@ TEST_F(WatchdogTest, AlarmTest) {
// Make sure a basic alarm fires when the time has expired.
TEST_F(WatchdogTest, AlarmPriorTimeTest) {
- WatchdogCounter watchdog(TimeDelta::TimeDelta(), "Enabled2", true);
+ WatchdogCounter watchdog(TimeDelta(), "Enabled2", true);
// Set a time in the past.
watchdog.ArmSomeTimeDeltaAgo(TimeDelta::FromSeconds(2));
// It should instantly go off, but certainly in less than 5 minutes.
diff --git a/base/win/registry.cc b/base/win/registry.cc
index 3372cf4..f8e05a7 100644
--- a/base/win/registry.cc
+++ b/base/win/registry.cc
@@ -244,7 +244,7 @@ bool RegKey::OpenKey(const wchar_t* name, REGSAM access) {
return (result == ERROR_SUCCESS);
}
-DWORD RegKey::ValueCount() {
+DWORD RegKey::ValueCount() const {
base::ThreadRestrictions::AssertIOAllowed();
DWORD count = 0;
HRESULT result = RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL,
@@ -252,7 +252,7 @@ DWORD RegKey::ValueCount() {
return (result != ERROR_SUCCESS) ? 0 : count;
}
-bool RegKey::ReadName(int index, std::wstring* name) {
+bool RegKey::ReadName(int index, std::wstring* name) const {
base::ThreadRestrictions::AssertIOAllowed();
wchar_t buf[256];
DWORD bufsize = arraysize(buf);
@@ -274,7 +274,7 @@ bool RegKey::ValueExists(const wchar_t* name) {
}
bool RegKey::ReadValue(const wchar_t* name, void* data,
- DWORD* dsize, DWORD* dtype) {
+ DWORD* dsize, DWORD* dtype) const {
base::ThreadRestrictions::AssertIOAllowed();
if (!key_)
return false;
@@ -283,7 +283,7 @@ bool RegKey::ReadValue(const wchar_t* name, void* data,
return (result == ERROR_SUCCESS);
}
-bool RegKey::ReadValue(const wchar_t* name, std::wstring* value) {
+bool RegKey::ReadValue(const wchar_t* name, std::wstring* value) const {
base::ThreadRestrictions::AssertIOAllowed();
DCHECK(value);
const size_t kMaxStringLength = 1024; // This is after expansion.
@@ -312,7 +312,7 @@ bool RegKey::ReadValue(const wchar_t* name, std::wstring* value) {
return false;
}
-bool RegKey::ReadValueDW(const wchar_t* name, DWORD* value) {
+bool RegKey::ReadValueDW(const wchar_t* name, DWORD* value) const {
DCHECK(value);
DWORD type = REG_DWORD;
DWORD size = sizeof(DWORD);
diff --git a/base/win/registry.h b/base/win/registry.h
index d1ef25b..96a2bb3 100644
--- a/base/win/registry.h
+++ b/base/win/registry.h
@@ -38,10 +38,10 @@ class RegKey {
void Close();
- DWORD ValueCount();
+ DWORD ValueCount() const;
// Determine the nth value's name.
- bool ReadName(int index, std::wstring* name);
+ bool ReadName(int index, std::wstring* name) const;
// True while the key is valid.
bool Valid() const { return key_ != NULL; }
@@ -55,9 +55,10 @@ class RegKey {
bool ValueExists(const wchar_t* name);
- bool ReadValue(const wchar_t* name, void* data, DWORD* dsize, DWORD* dtype);
- bool ReadValue(const wchar_t* name, std::wstring* value);
- bool ReadValueDW(const wchar_t* name, DWORD* value);
+ bool ReadValue(const wchar_t* name, void* data, DWORD* dsize,
+ DWORD* dtype) const;
+ bool ReadValue(const wchar_t* name, std::wstring* value) const;
+ bool ReadValueDW(const wchar_t* name, DWORD* value) const;
bool WriteValue(const wchar_t* name, const void* data, DWORD dsize,
DWORD dtype);
@@ -65,7 +66,7 @@ class RegKey {
bool WriteValue(const wchar_t* name, DWORD value);
// Starts watching the key to see if any of its values have changed.
- // The key must have been opened with the KEY_NOTIFY access privelege.
+ // The key must have been opened with the KEY_NOTIFY access privilege.
bool StartWatching();
// If StartWatching hasn't been called, always returns false.
diff --git a/base/win/scoped_variant.cc b/base/win/scoped_variant.cc
index 278e976..40ccdf2 100644
--- a/base/win/scoped_variant.cc
+++ b/base/win/scoped_variant.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/scoped_variant_win.h"
+#include "base/win/scoped_variant.h"
#include "base/logging.h"
namespace base {
diff --git a/base/worker_pool_linux.cc b/base/worker_pool_linux.cc
deleted file mode 100644
index 8c96ca0..0000000
--- a/base/worker_pool_linux.cc
+++ /dev/null
@@ -1,186 +0,0 @@
-// 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.
-
-#include "base/worker_pool.h"
-#include "base/worker_pool_linux.h"
-
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/platform_thread.h"
-#include "base/ref_counted.h"
-#include "base/stringprintf.h"
-#include "base/task.h"
-
-namespace {
-
-const int kIdleSecondsBeforeExit = 10 * 60;
-// A stack size of 64 KB is too small for the CERT_PKIXVerifyCert
-// function of NSS because of NSS bug 439169.
-const int kWorkerThreadStackSize = 128 * 1024;
-
-class WorkerPoolImpl {
- public:
- WorkerPoolImpl();
- ~WorkerPoolImpl();
-
- void PostTask(const tracked_objects::Location& from_here, Task* task,
- bool task_is_slow);
-
- private:
- scoped_refptr<base::LinuxDynamicThreadPool> pool_;
-};
-
-WorkerPoolImpl::WorkerPoolImpl()
- : pool_(new base::LinuxDynamicThreadPool(
- "WorkerPool", kIdleSecondsBeforeExit)) {}
-
-WorkerPoolImpl::~WorkerPoolImpl() {
- pool_->Terminate();
-}
-
-void WorkerPoolImpl::PostTask(const tracked_objects::Location& from_here,
- Task* task, bool task_is_slow) {
- task->SetBirthPlace(from_here);
- pool_->PostTask(task);
-}
-
-base::LazyInstance<WorkerPoolImpl> g_lazy_worker_pool(base::LINKER_INITIALIZED);
-
-class WorkerThread : public PlatformThread::Delegate {
- public:
- WorkerThread(const std::string& name_prefix, int idle_seconds_before_exit,
- base::LinuxDynamicThreadPool* pool)
- : name_prefix_(name_prefix),
- idle_seconds_before_exit_(idle_seconds_before_exit),
- pool_(pool) {}
-
- virtual void ThreadMain();
-
- private:
- const std::string name_prefix_;
- const int idle_seconds_before_exit_;
- scoped_refptr<base::LinuxDynamicThreadPool> pool_;
-
- DISALLOW_COPY_AND_ASSIGN(WorkerThread);
-};
-
-void WorkerThread::ThreadMain() {
- const std::string name = base::StringPrintf(
- "%s/%d", name_prefix_.c_str(), PlatformThread::CurrentId());
- PlatformThread::SetName(name.c_str());
-
- for (;;) {
- Task* task = pool_->WaitForTask();
- if (!task)
- break;
- task->Run();
- delete task;
- }
-
- // The WorkerThread is non-joinable, so it deletes itself.
- delete this;
-}
-
-} // namespace
-
-// NOTE(shess): Temporarily allow the Mac WorkerPool implementation to
-// call into the linux so that it can provide a command-line flag for
-// switching back and forth. After evaluating, either remove the
-// ifdef, or shift this to a shared POSIX implementation.
-// http://crbug.com/44392
-#if defined(OS_MACOSX)
-namespace worker_pool_mac {
-
-bool MacPostTaskHelper(const tracked_objects::Location& from_here,
- Task* task, bool task_is_slow) {
- g_lazy_worker_pool.Pointer()->PostTask(from_here, task, task_is_slow);
- return true;
-}
-
-} // namespace worker_pool_mac
-
-#else
-bool WorkerPool::PostTask(const tracked_objects::Location& from_here,
- Task* task, bool task_is_slow) {
- g_lazy_worker_pool.Pointer()->PostTask(from_here, task, task_is_slow);
- return true;
-}
-#endif
-
-namespace base {
-
-LinuxDynamicThreadPool::LinuxDynamicThreadPool(
- const std::string& name_prefix,
- int idle_seconds_before_exit)
- : name_prefix_(name_prefix),
- idle_seconds_before_exit_(idle_seconds_before_exit),
- tasks_available_cv_(&lock_),
- num_idle_threads_(0),
- terminated_(false),
- num_idle_threads_cv_(NULL) {}
-
-LinuxDynamicThreadPool::~LinuxDynamicThreadPool() {
- while (!tasks_.empty()) {
- Task* task = tasks_.front();
- tasks_.pop();
- delete task;
- }
-}
-
-void LinuxDynamicThreadPool::Terminate() {
- {
- AutoLock locked(lock_);
- DCHECK(!terminated_) << "Thread pool is already terminated.";
- terminated_ = true;
- }
- tasks_available_cv_.Broadcast();
-}
-
-void LinuxDynamicThreadPool::PostTask(Task* task) {
- AutoLock locked(lock_);
- DCHECK(!terminated_) <<
- "This thread pool is already terminated. Do not post new tasks.";
-
- tasks_.push(task);
-
- // We have enough worker threads.
- if (static_cast<size_t>(num_idle_threads_) >= tasks_.size()) {
- tasks_available_cv_.Signal();
- } else {
- // The new PlatformThread will take ownership of the WorkerThread object,
- // which will delete itself on exit.
- WorkerThread* worker =
- new WorkerThread(name_prefix_, idle_seconds_before_exit_, this);
- PlatformThread::CreateNonJoinable(kWorkerThreadStackSize, worker);
- }
-}
-
-Task* LinuxDynamicThreadPool::WaitForTask() {
- AutoLock locked(lock_);
-
- if (terminated_)
- return NULL;
-
- if (tasks_.empty()) { // No work available, wait for work.
- num_idle_threads_++;
- if (num_idle_threads_cv_.get())
- num_idle_threads_cv_->Signal();
- tasks_available_cv_.TimedWait(
- TimeDelta::FromSeconds(kIdleSecondsBeforeExit));
- num_idle_threads_--;
- if (num_idle_threads_cv_.get())
- num_idle_threads_cv_->Signal();
- if (tasks_.empty()) {
- // We waited for work, but there's still no work. Return NULL to signal
- // the thread to terminate.
- return NULL;
- }
- }
-
- Task* task = tasks_.front();
- tasks_.pop();
- return task;
-}
-
-} // namespace base
diff --git a/base/worker_pool_linux.h b/base/worker_pool_linux.h
deleted file mode 100644
index ea6bab7..0000000
--- a/base/worker_pool_linux.h
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright (c) 2009 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.
-//
-// The thread pool used in the Linux implementation of WorkerPool dynamically
-// adds threads as necessary to handle all tasks. It keeps old threads around
-// for a period of time to allow them to be reused. After this waiting period,
-// the threads exit. This thread pool uses non-joinable threads, therefore
-// worker threads are not joined during process shutdown. This means that
-// potentially long running tasks (such as DNS lookup) do not block process
-// shutdown, but also means that process shutdown may "leak" objects. Note that
-// although LinuxDynamicThreadPool spawns the worker threads and manages the
-// task queue, it does not own the worker threads. The worker threads ask the
-// LinuxDynamicThreadPool for work and eventually clean themselves up. The
-// worker threads all maintain scoped_refptrs to the LinuxDynamicThreadPool
-// instance, which prevents LinuxDynamicThreadPool from disappearing before all
-// worker threads exit. The owner of LinuxDynamicThreadPool should likewise
-// maintain a scoped_refptr to the LinuxDynamicThreadPool instance.
-//
-// NOTE: The classes defined in this file are only meant for use by the Linux
-// implementation of WorkerPool. No one else should be using these classes.
-// These symbols are exported in a header purely for testing purposes.
-
-#ifndef BASE_WORKER_POOL_LINUX_H_
-#define BASE_WORKER_POOL_LINUX_H_
-#pragma once
-
-#include <queue>
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/condition_variable.h"
-#include "base/lock.h"
-#include "base/platform_thread.h"
-#include "base/ref_counted.h"
-#include "base/scoped_ptr.h"
-
-class Task;
-
-namespace base {
-
-class LinuxDynamicThreadPool
- : public RefCountedThreadSafe<LinuxDynamicThreadPool> {
- public:
- class LinuxDynamicThreadPoolPeer;
-
- // All worker threads will share the same |name_prefix|. They will exit after
- // |idle_seconds_before_exit|.
- LinuxDynamicThreadPool(const std::string& name_prefix,
- int idle_seconds_before_exit);
- ~LinuxDynamicThreadPool();
-
- // Indicates that the thread pool is going away. Stops handing out tasks to
- // worker threads. Wakes up all the idle threads to let them exit.
- void Terminate();
-
- // Adds |task| to the thread pool. LinuxDynamicThreadPool assumes ownership
- // of |task|.
- void PostTask(Task* task);
-
- // Worker thread method to wait for up to |idle_seconds_before_exit| for more
- // work from the thread pool. Returns NULL if no work is available.
- Task* WaitForTask();
-
- private:
- friend class LinuxDynamicThreadPoolPeer;
-
- const std::string name_prefix_;
- const int idle_seconds_before_exit_;
-
- Lock lock_; // Protects all the variables below.
-
- // Signal()s worker threads to let them know more tasks are available.
- // Also used for Broadcast()'ing to worker threads to let them know the pool
- // is being deleted and they can exit.
- ConditionVariable tasks_available_cv_;
- int num_idle_threads_;
- std::queue<Task*> tasks_;
- bool terminated_;
- // Only used for tests to ensure correct thread ordering. It will always be
- // NULL in non-test code.
- scoped_ptr<ConditionVariable> num_idle_threads_cv_;
-
- DISALLOW_COPY_AND_ASSIGN(LinuxDynamicThreadPool);
-};
-
-} // namespace base
-
-#if defined(OS_MACOSX)
-namespace worker_pool_mac {
-
-// NOTE(shess): Helper so that Mac WorkerPool implementation can call
-// into Linux implementation while determining if the implementations
-// should be merged. After evaluating, either remove the ifdef, or
-// shift this to a shared POSIX implementation.
-// http://crbug.com/44392
-bool MacPostTaskHelper(const tracked_objects::Location& from_here,
- Task* task, bool task_is_slow);
-
-} // namespace worker_pool_mac
-#endif
-
-#endif // BASE_WORKER_POOL_LINUX_H_
diff --git a/base/worker_pool_linux_unittest.cc b/base/worker_pool_linux_unittest.cc
deleted file mode 100644
index f98f37a..0000000
--- a/base/worker_pool_linux_unittest.cc
+++ /dev/null
@@ -1,268 +0,0 @@
-// Copyright (c) 2009 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/worker_pool_linux.h"
-
-#include <set>
-
-#include "base/condition_variable.h"
-#include "base/lock.h"
-#include "base/platform_thread.h"
-#include "base/task.h"
-#include "base/waitable_event.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-
-// Peer class to provide passthrough access to LinuxDynamicThreadPool internals.
-class LinuxDynamicThreadPool::LinuxDynamicThreadPoolPeer {
- public:
- explicit LinuxDynamicThreadPoolPeer(LinuxDynamicThreadPool* pool)
- : pool_(pool) {}
-
- Lock* lock() { return &pool_->lock_; }
- ConditionVariable* tasks_available_cv() {
- return &pool_->tasks_available_cv_;
- }
- const std::queue<Task*>& tasks() const { return pool_->tasks_; }
- int num_idle_threads() const { return pool_->num_idle_threads_; }
- ConditionVariable* num_idle_threads_cv() {
- return pool_->num_idle_threads_cv_.get();
- }
- void set_num_idle_threads_cv(ConditionVariable* cv) {
- pool_->num_idle_threads_cv_.reset(cv);
- }
-
- private:
- LinuxDynamicThreadPool* pool_;
-
- DISALLOW_COPY_AND_ASSIGN(LinuxDynamicThreadPoolPeer);
-};
-
-} // namespace base
-
-namespace {
-
-// IncrementingTask's main purpose is to increment a counter. It also updates a
-// set of unique thread ids, and signals a ConditionVariable on completion.
-// Note that since it does not block, there is no way to control the number of
-// threads used if more than one IncrementingTask is consecutively posted to the
-// thread pool, since the first one might finish executing before the subsequent
-// PostTask() calls get invoked.
-class IncrementingTask : public Task {
- public:
- IncrementingTask(Lock* counter_lock,
- int* counter,
- Lock* unique_threads_lock,
- std::set<PlatformThreadId>* unique_threads)
- : counter_lock_(counter_lock),
- unique_threads_lock_(unique_threads_lock),
- unique_threads_(unique_threads),
- counter_(counter) {}
-
- virtual void Run() {
- AddSelfToUniqueThreadSet();
- AutoLock locked(*counter_lock_);
- (*counter_)++;
- }
-
- void AddSelfToUniqueThreadSet() {
- AutoLock locked(*unique_threads_lock_);
- unique_threads_->insert(PlatformThread::CurrentId());
- }
-
- private:
- Lock* counter_lock_;
- Lock* unique_threads_lock_;
- std::set<PlatformThreadId>* unique_threads_;
- int* counter_;
-
- DISALLOW_COPY_AND_ASSIGN(IncrementingTask);
-};
-
-// BlockingIncrementingTask is a simple wrapper around IncrementingTask that
-// allows for waiting at the start of Run() for a WaitableEvent to be signalled.
-class BlockingIncrementingTask : public Task {
- public:
- BlockingIncrementingTask(Lock* counter_lock,
- int* counter,
- Lock* unique_threads_lock,
- std::set<PlatformThreadId>* unique_threads,
- Lock* num_waiting_to_start_lock,
- int* num_waiting_to_start,
- ConditionVariable* num_waiting_to_start_cv,
- base::WaitableEvent* start)
- : incrementer_(
- counter_lock, counter, unique_threads_lock, unique_threads),
- num_waiting_to_start_lock_(num_waiting_to_start_lock),
- num_waiting_to_start_(num_waiting_to_start),
- num_waiting_to_start_cv_(num_waiting_to_start_cv),
- start_(start) {}
-
- virtual void Run() {
- {
- AutoLock num_waiting_to_start_locked(*num_waiting_to_start_lock_);
- (*num_waiting_to_start_)++;
- }
- num_waiting_to_start_cv_->Signal();
- CHECK(start_->Wait());
- incrementer_.Run();
- }
-
- private:
- IncrementingTask incrementer_;
- Lock* num_waiting_to_start_lock_;
- int* num_waiting_to_start_;
- ConditionVariable* num_waiting_to_start_cv_;
- base::WaitableEvent* start_;
-
- DISALLOW_COPY_AND_ASSIGN(BlockingIncrementingTask);
-};
-
-class LinuxDynamicThreadPoolTest : public testing::Test {
- protected:
- LinuxDynamicThreadPoolTest()
- : pool_(new base::LinuxDynamicThreadPool("dynamic_pool", 60*60)),
- peer_(pool_.get()),
- counter_(0),
- num_waiting_to_start_(0),
- num_waiting_to_start_cv_(&num_waiting_to_start_lock_),
- start_(true, false) {}
-
- virtual void SetUp() {
- peer_.set_num_idle_threads_cv(new ConditionVariable(peer_.lock()));
- }
-
- virtual void TearDown() {
- // Wake up the idle threads so they can terminate.
- if (pool_.get()) pool_->Terminate();
- }
-
- void WaitForTasksToStart(int num_tasks) {
- AutoLock num_waiting_to_start_locked(num_waiting_to_start_lock_);
- while (num_waiting_to_start_ < num_tasks) {
- num_waiting_to_start_cv_.Wait();
- }
- }
-
- void WaitForIdleThreads(int num_idle_threads) {
- AutoLock pool_locked(*peer_.lock());
- while (peer_.num_idle_threads() < num_idle_threads) {
- peer_.num_idle_threads_cv()->Wait();
- }
- }
-
- Task* CreateNewIncrementingTask() {
- return new IncrementingTask(&counter_lock_, &counter_,
- &unique_threads_lock_, &unique_threads_);
- }
-
- Task* CreateNewBlockingIncrementingTask() {
- return new BlockingIncrementingTask(
- &counter_lock_, &counter_, &unique_threads_lock_, &unique_threads_,
- &num_waiting_to_start_lock_, &num_waiting_to_start_,
- &num_waiting_to_start_cv_, &start_);
- }
-
- scoped_refptr<base::LinuxDynamicThreadPool> pool_;
- base::LinuxDynamicThreadPool::LinuxDynamicThreadPoolPeer peer_;
- Lock counter_lock_;
- int counter_;
- Lock unique_threads_lock_;
- std::set<PlatformThreadId> unique_threads_;
- Lock num_waiting_to_start_lock_;
- int num_waiting_to_start_;
- ConditionVariable num_waiting_to_start_cv_;
- base::WaitableEvent start_;
-};
-
-TEST_F(LinuxDynamicThreadPoolTest, Basic) {
- EXPECT_EQ(0, peer_.num_idle_threads());
- EXPECT_EQ(0U, unique_threads_.size());
- EXPECT_EQ(0U, peer_.tasks().size());
-
- // Add one task and wait for it to be completed.
- pool_->PostTask(CreateNewIncrementingTask());
-
- WaitForIdleThreads(1);
-
- EXPECT_EQ(1U, unique_threads_.size()) <<
- "There should be only one thread allocated for one task.";
- EXPECT_EQ(1, peer_.num_idle_threads());
- EXPECT_EQ(1, counter_);
-}
-
-TEST_F(LinuxDynamicThreadPoolTest, ReuseIdle) {
- // Add one task and wait for it to be completed.
- pool_->PostTask(CreateNewIncrementingTask());
-
- WaitForIdleThreads(1);
-
- // Add another 2 tasks. One should reuse the existing worker thread.
- pool_->PostTask(CreateNewBlockingIncrementingTask());
- pool_->PostTask(CreateNewBlockingIncrementingTask());
-
- WaitForTasksToStart(2);
- start_.Signal();
- WaitForIdleThreads(2);
-
- EXPECT_EQ(2U, unique_threads_.size());
- EXPECT_EQ(2, peer_.num_idle_threads());
- EXPECT_EQ(3, counter_);
-}
-
-TEST_F(LinuxDynamicThreadPoolTest, TwoActiveTasks) {
- // Add two blocking tasks.
- pool_->PostTask(CreateNewBlockingIncrementingTask());
- pool_->PostTask(CreateNewBlockingIncrementingTask());
-
- EXPECT_EQ(0, counter_) << "Blocking tasks should not have started yet.";
-
- WaitForTasksToStart(2);
- start_.Signal();
- WaitForIdleThreads(2);
-
- EXPECT_EQ(2U, unique_threads_.size());
- EXPECT_EQ(2, peer_.num_idle_threads()) << "Existing threads are now idle.";
- EXPECT_EQ(2, counter_);
-}
-
-TEST_F(LinuxDynamicThreadPoolTest, Complex) {
- // Add two non blocking tasks and wait for them to finish.
- pool_->PostTask(CreateNewIncrementingTask());
-
- WaitForIdleThreads(1);
-
- // Add two blocking tasks, start them simultaneously, and wait for them to
- // finish.
- pool_->PostTask(CreateNewBlockingIncrementingTask());
- pool_->PostTask(CreateNewBlockingIncrementingTask());
-
- WaitForTasksToStart(2);
- start_.Signal();
- WaitForIdleThreads(2);
-
- EXPECT_EQ(3, counter_);
- EXPECT_EQ(2, peer_.num_idle_threads());
- EXPECT_EQ(2U, unique_threads_.size());
-
- // Wake up all idle threads so they can exit.
- {
- AutoLock locked(*peer_.lock());
- while (peer_.num_idle_threads() > 0) {
- peer_.tasks_available_cv()->Signal();
- peer_.num_idle_threads_cv()->Wait();
- }
- }
-
- // Add another non blocking task. There are no threads to reuse.
- pool_->PostTask(CreateNewIncrementingTask());
- WaitForIdleThreads(1);
-
- EXPECT_EQ(3U, unique_threads_.size());
- EXPECT_EQ(1, peer_.num_idle_threads());
- EXPECT_EQ(4, counter_);
-}
-
-} // namespace
diff --git a/base/worker_pool_mac.h b/base/worker_pool_mac.h
deleted file mode 100644
index 1e86891..0000000
--- a/base/worker_pool_mac.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) 2009 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 BASE_WORKER_POOL_MAC_H_
-#define BASE_WORKER_POOL_MAC_H_
-#pragma once
-
-#include "base/worker_pool.h"
-
-#import <Foundation/Foundation.h>
-
-// WorkerPoolObjC provides an Objective-C interface to the same WorkerPool
-// used by the rest of the application.
-@interface WorkerPoolObjC : NSObject
-
-// Returns the underlying NSOperationQueue back end that WorkerPool::PostTask
-// would post tasks to. This can be used to add NSOperation subclasses
-// directly to the same NSOperationQueue, by calling -[NSOperationQueue
-// addOperation:]. Most Objective-C code wishing to dispatch tasks to the
-// WorkerPool will find it handy to add an operation of type
-// NSInvocationOperation.
-+ (NSOperationQueue*)sharedOperationQueue;
-
-@end // @interface WorkerPoolObjC
-
-namespace worker_pool_mac {
-
-void SetUseLinuxWorkerPool(bool flag);
-
-} // namespace worker_pool_mac
-
-#endif // BASE_WORKER_POOL_MAC_H_
diff --git a/base/worker_pool_mac.mm b/base/worker_pool_mac.mm
deleted file mode 100644
index bbc7892..0000000
--- a/base/worker_pool_mac.mm
+++ /dev/null
@@ -1,205 +0,0 @@
-// 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.
-
-#include "base/worker_pool_mac.h"
-
-#include "base/logging.h"
-#include "base/mac/scoped_nsautorelease_pool.h"
-#include "base/metrics/histogram.h"
-#include "base/scoped_ptr.h"
-#import "base/singleton_objc.h"
-#include "base/task.h"
-#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
-#include "base/worker_pool_linux.h"
-
-// When C++ exceptions are disabled, the C++ library defines |try| and
-// |catch| so as to allow exception-expecting C++ code to build properly when
-// language support for exceptions is not present. These macros interfere
-// with the use of |@try| and |@catch| in Objective-C files such as this one.
-// Undefine these macros here, after everything has been #included, since
-// there will be no C++ uses and only Objective-C uses from this point on.
-#undef try
-#undef catch
-
-namespace {
-
-// |true| to use the Linux WorkerPool implementation for
-// |WorkerPool::PostTask()|.
-bool use_linux_workerpool_ = true;
-
-Lock lock_;
-base::Time last_check_; // Last hung-test check.
-std::vector<id> outstanding_ops_; // Outstanding operations at last check.
-size_t running_ = 0; // Operations in |Run()|.
-size_t outstanding_ = 0; // Operations posted but not completed.
-
-} // namespace
-
-namespace worker_pool_mac {
-
-void SetUseLinuxWorkerPool(bool flag) {
- use_linux_workerpool_ = flag;
-}
-
-} // namespace worker_pool_mac
-
-@implementation WorkerPoolObjC
-
-+ (NSOperationQueue*)sharedOperationQueue {
- return SingletonObjC<NSOperationQueue>::get();
-}
-
-@end // @implementation WorkerPoolObjC
-
-// TaskOperation adapts Task->Run() for use in an NSOperationQueue.
-@interface TaskOperation : NSOperation {
- @private
- scoped_ptr<Task> task_;
-}
-
-// Returns an autoreleased instance of TaskOperation. See -initWithTask: for
-// details.
-+ (id)taskOperationWithTask:(Task*)task;
-
-// Designated initializer. |task| is adopted as the Task* whose Run method
-// this operation will call when executed.
-- (id)initWithTask:(Task*)task;
-
-@end // @interface TaskOperation
-
-@implementation TaskOperation
-
-+ (id)taskOperationWithTask:(Task*)task {
- return [[[TaskOperation alloc] initWithTask:task] autorelease];
-}
-
-- (id)init {
- return [self initWithTask:NULL];
-}
-
-- (id)initWithTask:(Task*)task {
- if ((self = [super init])) {
- task_.reset(task);
- }
- return self;
-}
-
-- (void)main {
- DCHECK(task_.get()) << "-[TaskOperation main] called with no task";
- if (!task_.get()) {
- return;
- }
-
- {
- AutoLock locked(lock_);
- ++running_;
- }
-
- base::mac::ScopedNSAutoreleasePool autoreleasePool;
-
- @try {
- task_->Run();
- } @catch(NSException* exception) {
- LOG(ERROR) << "-[TaskOperation main] caught an NSException: "
- << [[exception description] UTF8String];
- } @catch(id exception) {
- LOG(ERROR) << "-[TaskOperation main] caught an unknown exception";
- }
-
- task_.reset(NULL);
-
- {
- AutoLock locked(lock_);
- --running_;
- --outstanding_;
- }
-}
-
-- (void)dealloc {
- // Getting the task_ contents without a lock can lead to a benign data race.
- // We annotate it to stay silent under ThreadSanitizer.
- ANNOTATE_IGNORE_READS_BEGIN();
- DCHECK(!task_.get())
- << "-[TaskOperation dealloc] called without running task";
- ANNOTATE_IGNORE_READS_END();
- [super dealloc];
-}
-
-@end // @implementation TaskOperation
-
-bool WorkerPool::PostTask(const tracked_objects::Location& from_here,
- Task* task, bool task_is_slow) {
- if (use_linux_workerpool_) {
- return worker_pool_mac::MacPostTaskHelper(from_here, task, task_is_slow);
- }
-
- base::mac::ScopedNSAutoreleasePool autorelease_pool;
-
- // Ignore |task_is_slow|, it doesn't map directly to any tunable aspect of
- // an NSOperation.
-
- DCHECK(task) << "WorkerPool::PostTask called with no task";
- if (!task) {
- return false;
- }
-
- task->SetBirthPlace(from_here);
-
- NSOperationQueue* operation_queue = [WorkerPoolObjC sharedOperationQueue];
- [operation_queue addOperation:[TaskOperation taskOperationWithTask:task]];
-
- if ([operation_queue isSuspended]) {
- LOG(WARNING) << "WorkerPool::PostTask freeing stuck NSOperationQueue";
-
- // Nothing should ever be suspending this queue, but in case it winds up
- // happening, free things up. This is a purely speculative shot in the
- // dark for http://crbug.com/20471.
- [operation_queue setSuspended:NO];
- }
-
- // Periodically calculate the set of operations which have not made
- // progress and report how many there are. This should provide a
- // sense of how many clients are seeing hung operations of any sort,
- // and a sense of how many clients are seeing "too many" hung
- // operations.
- std::vector<id> hung_ops;
- size_t outstanding_delta = 0;
- size_t running_ops = 0;
- {
- const base::TimeDelta kCheckPeriod(base::TimeDelta::FromMinutes(10));
- base::Time now = base::Time::Now();
-
- AutoLock locked(lock_);
- ++outstanding_;
- running_ops = running_;
- if (last_check_.is_null() || now - last_check_ > kCheckPeriod) {
- base::mac::ScopedNSAutoreleasePool autoreleasePool;
- std::vector<id> ops;
- for (id op in [operation_queue operations]) {
- // DO NOT RETAIN.
- ops.push_back(op);
- }
- std::sort(ops.begin(), ops.end());
-
- outstanding_delta = outstanding_ - ops.size();
-
- std::set_intersection(outstanding_ops_.begin(), outstanding_ops_.end(),
- ops.begin(), ops.end(),
- std::back_inserter(hung_ops));
-
- outstanding_ops_.swap(ops);
- last_check_ = now;
- }
- }
-
- // Don't report "nothing to report".
- const size_t kUnaccountedOpsDelta = 10;
- if (hung_ops.size() > 0 || outstanding_delta > kUnaccountedOpsDelta) {
- UMA_HISTOGRAM_COUNTS_100("OSX.HungWorkers", hung_ops.size());
- UMA_HISTOGRAM_COUNTS_100("OSX.OutstandingDelta", outstanding_delta);
- UMA_HISTOGRAM_COUNTS_100("OSX.RunningOps", running_ops);
- }
-
- return true;
-}
diff --git a/base/worker_pool_posix.cc b/base/worker_pool_posix.cc
new file mode 100644
index 0000000..85e1d8e
--- /dev/null
+++ b/base/worker_pool_posix.cc
@@ -0,0 +1,168 @@
+// 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.
+
+#include "base/worker_pool.h"
+#include "base/worker_pool_posix.h"
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/platform_thread.h"
+#include "base/ref_counted.h"
+#include "base/stringprintf.h"
+#include "base/task.h"
+
+namespace {
+
+const int kIdleSecondsBeforeExit = 10 * 60;
+// A stack size of 64 KB is too small for the CERT_PKIXVerifyCert
+// function of NSS because of NSS bug 439169.
+const int kWorkerThreadStackSize = 128 * 1024;
+
+class WorkerPoolImpl {
+ public:
+ WorkerPoolImpl();
+ ~WorkerPoolImpl();
+
+ void PostTask(const tracked_objects::Location& from_here, Task* task,
+ bool task_is_slow);
+
+ private:
+ scoped_refptr<base::PosixDynamicThreadPool> pool_;
+};
+
+WorkerPoolImpl::WorkerPoolImpl()
+ : pool_(new base::PosixDynamicThreadPool(
+ "WorkerPool", kIdleSecondsBeforeExit)) {}
+
+WorkerPoolImpl::~WorkerPoolImpl() {
+ pool_->Terminate();
+}
+
+void WorkerPoolImpl::PostTask(const tracked_objects::Location& from_here,
+ Task* task, bool task_is_slow) {
+ task->SetBirthPlace(from_here);
+ pool_->PostTask(task);
+}
+
+base::LazyInstance<WorkerPoolImpl> g_lazy_worker_pool(base::LINKER_INITIALIZED);
+
+class WorkerThread : public PlatformThread::Delegate {
+ public:
+ WorkerThread(const std::string& name_prefix, int idle_seconds_before_exit,
+ base::PosixDynamicThreadPool* pool)
+ : name_prefix_(name_prefix),
+ idle_seconds_before_exit_(idle_seconds_before_exit),
+ pool_(pool) {}
+
+ virtual void ThreadMain();
+
+ private:
+ const std::string name_prefix_;
+ const int idle_seconds_before_exit_;
+ scoped_refptr<base::PosixDynamicThreadPool> pool_;
+
+ DISALLOW_COPY_AND_ASSIGN(WorkerThread);
+};
+
+void WorkerThread::ThreadMain() {
+ const std::string name = base::StringPrintf(
+ "%s/%d", name_prefix_.c_str(), PlatformThread::CurrentId());
+ PlatformThread::SetName(name.c_str());
+
+ for (;;) {
+ Task* task = pool_->WaitForTask();
+ if (!task)
+ break;
+ task->Run();
+ delete task;
+ }
+
+ // The WorkerThread is non-joinable, so it deletes itself.
+ delete this;
+}
+
+} // namespace
+
+bool WorkerPool::PostTask(const tracked_objects::Location& from_here,
+ Task* task, bool task_is_slow) {
+ g_lazy_worker_pool.Pointer()->PostTask(from_here, task, task_is_slow);
+ return true;
+}
+
+namespace base {
+
+PosixDynamicThreadPool::PosixDynamicThreadPool(
+ const std::string& name_prefix,
+ int idle_seconds_before_exit)
+ : name_prefix_(name_prefix),
+ idle_seconds_before_exit_(idle_seconds_before_exit),
+ tasks_available_cv_(&lock_),
+ num_idle_threads_(0),
+ terminated_(false),
+ num_idle_threads_cv_(NULL) {}
+
+PosixDynamicThreadPool::~PosixDynamicThreadPool() {
+ while (!tasks_.empty()) {
+ Task* task = tasks_.front();
+ tasks_.pop();
+ delete task;
+ }
+}
+
+void PosixDynamicThreadPool::Terminate() {
+ {
+ AutoLock locked(lock_);
+ DCHECK(!terminated_) << "Thread pool is already terminated.";
+ terminated_ = true;
+ }
+ tasks_available_cv_.Broadcast();
+}
+
+void PosixDynamicThreadPool::PostTask(Task* task) {
+ AutoLock locked(lock_);
+ DCHECK(!terminated_) <<
+ "This thread pool is already terminated. Do not post new tasks.";
+
+ tasks_.push(task);
+
+ // We have enough worker threads.
+ if (static_cast<size_t>(num_idle_threads_) >= tasks_.size()) {
+ tasks_available_cv_.Signal();
+ } else {
+ // The new PlatformThread will take ownership of the WorkerThread object,
+ // which will delete itself on exit.
+ WorkerThread* worker =
+ new WorkerThread(name_prefix_, idle_seconds_before_exit_, this);
+ PlatformThread::CreateNonJoinable(kWorkerThreadStackSize, worker);
+ }
+}
+
+Task* PosixDynamicThreadPool::WaitForTask() {
+ AutoLock locked(lock_);
+
+ if (terminated_)
+ return NULL;
+
+ if (tasks_.empty()) { // No work available, wait for work.
+ num_idle_threads_++;
+ if (num_idle_threads_cv_.get())
+ num_idle_threads_cv_->Signal();
+ tasks_available_cv_.TimedWait(
+ TimeDelta::FromSeconds(kIdleSecondsBeforeExit));
+ num_idle_threads_--;
+ if (num_idle_threads_cv_.get())
+ num_idle_threads_cv_->Signal();
+ if (tasks_.empty()) {
+ // We waited for work, but there's still no work. Return NULL to signal
+ // the thread to terminate.
+ return NULL;
+ }
+ }
+
+ Task* task = tasks_.front();
+ tasks_.pop();
+ return task;
+}
+
+} // namespace base
diff --git a/base/worker_pool_posix.h b/base/worker_pool_posix.h
new file mode 100644
index 0000000..73d8287
--- /dev/null
+++ b/base/worker_pool_posix.h
@@ -0,0 +1,89 @@
+// Copyright (c) 2009 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.
+//
+// The thread pool used in the POSIX implementation of WorkerPool dynamically
+// adds threads as necessary to handle all tasks. It keeps old threads around
+// for a period of time to allow them to be reused. After this waiting period,
+// the threads exit. This thread pool uses non-joinable threads, therefore
+// worker threads are not joined during process shutdown. This means that
+// potentially long running tasks (such as DNS lookup) do not block process
+// shutdown, but also means that process shutdown may "leak" objects. Note that
+// although PosixDynamicThreadPool spawns the worker threads and manages the
+// task queue, it does not own the worker threads. The worker threads ask the
+// PosixDynamicThreadPool for work and eventually clean themselves up. The
+// worker threads all maintain scoped_refptrs to the PosixDynamicThreadPool
+// instance, which prevents PosixDynamicThreadPool from disappearing before all
+// worker threads exit. The owner of PosixDynamicThreadPool should likewise
+// maintain a scoped_refptr to the PosixDynamicThreadPool instance.
+//
+// NOTE: The classes defined in this file are only meant for use by the POSIX
+// implementation of WorkerPool. No one else should be using these classes.
+// These symbols are exported in a header purely for testing purposes.
+
+#ifndef BASE_WORKER_POOL_POSIX_H_
+#define BASE_WORKER_POOL_POSIX_H_
+#pragma once
+
+#include <queue>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/condition_variable.h"
+#include "base/lock.h"
+#include "base/platform_thread.h"
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+
+class Task;
+
+namespace base {
+
+class PosixDynamicThreadPool
+ : public RefCountedThreadSafe<PosixDynamicThreadPool> {
+ public:
+ class PosixDynamicThreadPoolPeer;
+
+ // All worker threads will share the same |name_prefix|. They will exit after
+ // |idle_seconds_before_exit|.
+ PosixDynamicThreadPool(const std::string& name_prefix,
+ int idle_seconds_before_exit);
+ ~PosixDynamicThreadPool();
+
+ // Indicates that the thread pool is going away. Stops handing out tasks to
+ // worker threads. Wakes up all the idle threads to let them exit.
+ void Terminate();
+
+ // Adds |task| to the thread pool. PosixDynamicThreadPool assumes ownership
+ // of |task|.
+ void PostTask(Task* task);
+
+ // Worker thread method to wait for up to |idle_seconds_before_exit| for more
+ // work from the thread pool. Returns NULL if no work is available.
+ Task* WaitForTask();
+
+ private:
+ friend class PosixDynamicThreadPoolPeer;
+
+ const std::string name_prefix_;
+ const int idle_seconds_before_exit_;
+
+ Lock lock_; // Protects all the variables below.
+
+ // Signal()s worker threads to let them know more tasks are available.
+ // Also used for Broadcast()'ing to worker threads to let them know the pool
+ // is being deleted and they can exit.
+ ConditionVariable tasks_available_cv_;
+ int num_idle_threads_;
+ std::queue<Task*> tasks_;
+ bool terminated_;
+ // Only used for tests to ensure correct thread ordering. It will always be
+ // NULL in non-test code.
+ scoped_ptr<ConditionVariable> num_idle_threads_cv_;
+
+ DISALLOW_COPY_AND_ASSIGN(PosixDynamicThreadPool);
+};
+
+} // namespace base
+
+#endif // BASE_WORKER_POOL_POSIX_H_
diff --git a/base/worker_pool_posix_unittest.cc b/base/worker_pool_posix_unittest.cc
new file mode 100644
index 0000000..55453c8
--- /dev/null
+++ b/base/worker_pool_posix_unittest.cc
@@ -0,0 +1,268 @@
+// Copyright (c) 2009 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/worker_pool_posix.h"
+
+#include <set>
+
+#include "base/condition_variable.h"
+#include "base/lock.h"
+#include "base/platform_thread.h"
+#include "base/task.h"
+#include "base/waitable_event.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+// Peer class to provide passthrough access to PosixDynamicThreadPool internals.
+class PosixDynamicThreadPool::PosixDynamicThreadPoolPeer {
+ public:
+ explicit PosixDynamicThreadPoolPeer(PosixDynamicThreadPool* pool)
+ : pool_(pool) {}
+
+ Lock* lock() { return &pool_->lock_; }
+ ConditionVariable* tasks_available_cv() {
+ return &pool_->tasks_available_cv_;
+ }
+ const std::queue<Task*>& tasks() const { return pool_->tasks_; }
+ int num_idle_threads() const { return pool_->num_idle_threads_; }
+ ConditionVariable* num_idle_threads_cv() {
+ return pool_->num_idle_threads_cv_.get();
+ }
+ void set_num_idle_threads_cv(ConditionVariable* cv) {
+ pool_->num_idle_threads_cv_.reset(cv);
+ }
+
+ private:
+ PosixDynamicThreadPool* pool_;
+
+ DISALLOW_COPY_AND_ASSIGN(PosixDynamicThreadPoolPeer);
+};
+
+} // namespace base
+
+namespace {
+
+// IncrementingTask's main purpose is to increment a counter. It also updates a
+// set of unique thread ids, and signals a ConditionVariable on completion.
+// Note that since it does not block, there is no way to control the number of
+// threads used if more than one IncrementingTask is consecutively posted to the
+// thread pool, since the first one might finish executing before the subsequent
+// PostTask() calls get invoked.
+class IncrementingTask : public Task {
+ public:
+ IncrementingTask(Lock* counter_lock,
+ int* counter,
+ Lock* unique_threads_lock,
+ std::set<PlatformThreadId>* unique_threads)
+ : counter_lock_(counter_lock),
+ unique_threads_lock_(unique_threads_lock),
+ unique_threads_(unique_threads),
+ counter_(counter) {}
+
+ virtual void Run() {
+ AddSelfToUniqueThreadSet();
+ AutoLock locked(*counter_lock_);
+ (*counter_)++;
+ }
+
+ void AddSelfToUniqueThreadSet() {
+ AutoLock locked(*unique_threads_lock_);
+ unique_threads_->insert(PlatformThread::CurrentId());
+ }
+
+ private:
+ Lock* counter_lock_;
+ Lock* unique_threads_lock_;
+ std::set<PlatformThreadId>* unique_threads_;
+ int* counter_;
+
+ DISALLOW_COPY_AND_ASSIGN(IncrementingTask);
+};
+
+// BlockingIncrementingTask is a simple wrapper around IncrementingTask that
+// allows for waiting at the start of Run() for a WaitableEvent to be signalled.
+class BlockingIncrementingTask : public Task {
+ public:
+ BlockingIncrementingTask(Lock* counter_lock,
+ int* counter,
+ Lock* unique_threads_lock,
+ std::set<PlatformThreadId>* unique_threads,
+ Lock* num_waiting_to_start_lock,
+ int* num_waiting_to_start,
+ ConditionVariable* num_waiting_to_start_cv,
+ base::WaitableEvent* start)
+ : incrementer_(
+ counter_lock, counter, unique_threads_lock, unique_threads),
+ num_waiting_to_start_lock_(num_waiting_to_start_lock),
+ num_waiting_to_start_(num_waiting_to_start),
+ num_waiting_to_start_cv_(num_waiting_to_start_cv),
+ start_(start) {}
+
+ virtual void Run() {
+ {
+ AutoLock num_waiting_to_start_locked(*num_waiting_to_start_lock_);
+ (*num_waiting_to_start_)++;
+ }
+ num_waiting_to_start_cv_->Signal();
+ CHECK(start_->Wait());
+ incrementer_.Run();
+ }
+
+ private:
+ IncrementingTask incrementer_;
+ Lock* num_waiting_to_start_lock_;
+ int* num_waiting_to_start_;
+ ConditionVariable* num_waiting_to_start_cv_;
+ base::WaitableEvent* start_;
+
+ DISALLOW_COPY_AND_ASSIGN(BlockingIncrementingTask);
+};
+
+class PosixDynamicThreadPoolTest : public testing::Test {
+ protected:
+ PosixDynamicThreadPoolTest()
+ : pool_(new base::PosixDynamicThreadPool("dynamic_pool", 60*60)),
+ peer_(pool_.get()),
+ counter_(0),
+ num_waiting_to_start_(0),
+ num_waiting_to_start_cv_(&num_waiting_to_start_lock_),
+ start_(true, false) {}
+
+ virtual void SetUp() {
+ peer_.set_num_idle_threads_cv(new ConditionVariable(peer_.lock()));
+ }
+
+ virtual void TearDown() {
+ // Wake up the idle threads so they can terminate.
+ if (pool_.get()) pool_->Terminate();
+ }
+
+ void WaitForTasksToStart(int num_tasks) {
+ AutoLock num_waiting_to_start_locked(num_waiting_to_start_lock_);
+ while (num_waiting_to_start_ < num_tasks) {
+ num_waiting_to_start_cv_.Wait();
+ }
+ }
+
+ void WaitForIdleThreads(int num_idle_threads) {
+ AutoLock pool_locked(*peer_.lock());
+ while (peer_.num_idle_threads() < num_idle_threads) {
+ peer_.num_idle_threads_cv()->Wait();
+ }
+ }
+
+ Task* CreateNewIncrementingTask() {
+ return new IncrementingTask(&counter_lock_, &counter_,
+ &unique_threads_lock_, &unique_threads_);
+ }
+
+ Task* CreateNewBlockingIncrementingTask() {
+ return new BlockingIncrementingTask(
+ &counter_lock_, &counter_, &unique_threads_lock_, &unique_threads_,
+ &num_waiting_to_start_lock_, &num_waiting_to_start_,
+ &num_waiting_to_start_cv_, &start_);
+ }
+
+ scoped_refptr<base::PosixDynamicThreadPool> pool_;
+ base::PosixDynamicThreadPool::PosixDynamicThreadPoolPeer peer_;
+ Lock counter_lock_;
+ int counter_;
+ Lock unique_threads_lock_;
+ std::set<PlatformThreadId> unique_threads_;
+ Lock num_waiting_to_start_lock_;
+ int num_waiting_to_start_;
+ ConditionVariable num_waiting_to_start_cv_;
+ base::WaitableEvent start_;
+};
+
+TEST_F(PosixDynamicThreadPoolTest, Basic) {
+ EXPECT_EQ(0, peer_.num_idle_threads());
+ EXPECT_EQ(0U, unique_threads_.size());
+ EXPECT_EQ(0U, peer_.tasks().size());
+
+ // Add one task and wait for it to be completed.
+ pool_->PostTask(CreateNewIncrementingTask());
+
+ WaitForIdleThreads(1);
+
+ EXPECT_EQ(1U, unique_threads_.size()) <<
+ "There should be only one thread allocated for one task.";
+ EXPECT_EQ(1, peer_.num_idle_threads());
+ EXPECT_EQ(1, counter_);
+}
+
+TEST_F(PosixDynamicThreadPoolTest, ReuseIdle) {
+ // Add one task and wait for it to be completed.
+ pool_->PostTask(CreateNewIncrementingTask());
+
+ WaitForIdleThreads(1);
+
+ // Add another 2 tasks. One should reuse the existing worker thread.
+ pool_->PostTask(CreateNewBlockingIncrementingTask());
+ pool_->PostTask(CreateNewBlockingIncrementingTask());
+
+ WaitForTasksToStart(2);
+ start_.Signal();
+ WaitForIdleThreads(2);
+
+ EXPECT_EQ(2U, unique_threads_.size());
+ EXPECT_EQ(2, peer_.num_idle_threads());
+ EXPECT_EQ(3, counter_);
+}
+
+TEST_F(PosixDynamicThreadPoolTest, TwoActiveTasks) {
+ // Add two blocking tasks.
+ pool_->PostTask(CreateNewBlockingIncrementingTask());
+ pool_->PostTask(CreateNewBlockingIncrementingTask());
+
+ EXPECT_EQ(0, counter_) << "Blocking tasks should not have started yet.";
+
+ WaitForTasksToStart(2);
+ start_.Signal();
+ WaitForIdleThreads(2);
+
+ EXPECT_EQ(2U, unique_threads_.size());
+ EXPECT_EQ(2, peer_.num_idle_threads()) << "Existing threads are now idle.";
+ EXPECT_EQ(2, counter_);
+}
+
+TEST_F(PosixDynamicThreadPoolTest, Complex) {
+ // Add two non blocking tasks and wait for them to finish.
+ pool_->PostTask(CreateNewIncrementingTask());
+
+ WaitForIdleThreads(1);
+
+ // Add two blocking tasks, start them simultaneously, and wait for them to
+ // finish.
+ pool_->PostTask(CreateNewBlockingIncrementingTask());
+ pool_->PostTask(CreateNewBlockingIncrementingTask());
+
+ WaitForTasksToStart(2);
+ start_.Signal();
+ WaitForIdleThreads(2);
+
+ EXPECT_EQ(3, counter_);
+ EXPECT_EQ(2, peer_.num_idle_threads());
+ EXPECT_EQ(2U, unique_threads_.size());
+
+ // Wake up all idle threads so they can exit.
+ {
+ AutoLock locked(*peer_.lock());
+ while (peer_.num_idle_threads() > 0) {
+ peer_.tasks_available_cv()->Signal();
+ peer_.num_idle_threads_cv()->Wait();
+ }
+ }
+
+ // Add another non blocking task. There are no threads to reuse.
+ pool_->PostTask(CreateNewIncrementingTask());
+ WaitForIdleThreads(1);
+
+ EXPECT_EQ(3U, unique_threads_.size());
+ EXPECT_EQ(1, peer_.num_idle_threads());
+ EXPECT_EQ(4, counter_);
+}
+
+} // namespace
diff --git a/build/all.gyp b/build/all.gyp
index 79453dd..46d550d 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -33,7 +33,6 @@
'../third_party/ffmpeg/ffmpeg.gyp:*',
'../third_party/iccjpeg/iccjpeg.gyp:*',
'../third_party/icu/icu.gyp:*',
- '../third_party/libjpeg/libjpeg.gyp:*',
'../third_party/libpng/libpng.gyp:*',
'../third_party/libwebp/libwebp.gyp:*',
'../third_party/libxml/libxml.gyp:*',
@@ -51,6 +50,7 @@
'../webkit/webkit.gyp:*',
'util/build_util.gyp:*',
'temp_gyp/googleurl.gyp:*',
+ '<(libjpeg_gyp_path):*',
],
'conditions': [
['javascript_engine=="v8"', {
@@ -197,7 +197,15 @@
],
}],
],
- }
+ },
+ {
+ 'target_name': 'chromium_gpu_builder',
+ 'type': 'none',
+ 'dependencies': [
+ '../chrome/chrome.gyp:gpu_tests',
+ '../third_party/WebKit/WebKit/chromium/WebKit.gyp:DumpRenderTree',
+ ],
+ }
],
'conditions': [
['OS=="mac"', {
@@ -296,6 +304,7 @@
'../net/net.gyp:net_unittests',
'../printing/printing.gyp:printing_unittests',
'../remoting/remoting.gyp:remoting_unittests',
+ '../chrome/chrome.gyp:safe_browsing_tests',
'../chrome/chrome.gyp:sync_unit_tests',
'../chrome/chrome.gyp:unit_tests',
'../chrome/chrome.gyp:ui_tests',
@@ -391,7 +400,6 @@
'../chrome/app/locales/locales.gyp:*',
'../chrome/chrome.gyp:crash_service',
'../chrome/chrome.gyp:page_cycler_tests',
- '../chrome/chrome.gyp:policy_templates',
'../chrome/chrome.gyp:pyautolib',
'../chrome/chrome.gyp:reliability_tests',
'../chrome/chrome.gyp:startup_tests',
diff --git a/build/build-bisect.py b/build/build-bisect.py
index 84807bc..33fcb89 100755
--- a/build/build-bisect.py
+++ b/build/build-bisect.py
@@ -3,286 +3,9 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Snapshot Build Bisect Tool
-
-This script bisects a snapshot archive using binary search. It starts at
-a bad revision (it will try to guess HEAD) and asks for a last known-good
-revision. It will then binary search across this revision range by downloading,
-unzipping, and opening Chromium for you. After testing the specific revision,
-it will ask you whether it is good or bad before continuing the search.
-"""
-
-# Base URL to download snapshots from.
-BUILD_BASE_URL = 'http://build.chromium.org/buildbot/snapshots/'
-
-# The type (platform) of the build archive. This is what's passed in to the
-# '-a/--archive' option.
-BUILD_ARCHIVE_TYPE = ''
-
-# The selected archive to bisect.
-BUILD_ARCHIVE_DIR = ''
-
-# The location of the builds.
-BUILD_ARCHIVE_URL = '/%d/'
-
-# Name of the build archive.
-BUILD_ZIP_NAME = ''
-
-# Directory name inside the archive.
-BUILD_DIR_NAME = ''
-
-# Name of the executable.
-BUILD_EXE_NAME = ''
-
-# URL to the ViewVC commit page.
-BUILD_VIEWVC_URL = 'http://src.chromium.org/viewvc/chrome?view=rev&revision=%d'
-
-# Changelogs URL
-CHANGELOG_URL = 'http://build.chromium.org/buildbot/' \
- 'perf/dashboard/ui/changelog.html?url=/trunk/src&range=%d:%d'
-
-###############################################################################
-
-import math
-import optparse
-import os
-import pipes
-import re
-import shutil
import sys
-import tempfile
-import urllib
-import zipfile
-
-
-def UnzipFilenameToDir(filename, dir):
- """Unzip |filename| to directory |dir|."""
- zf = zipfile.ZipFile(filename)
- # Make base.
- pushd = os.getcwd()
- try:
- if not os.path.isdir(dir):
- os.mkdir(dir)
- os.chdir(dir)
- # Extract files.
- for info in zf.infolist():
- name = info.filename
- if name.endswith('/'): # dir
- if not os.path.isdir(name):
- os.makedirs(name)
- else: # file
- dir = os.path.dirname(name)
- if not os.path.isdir(dir):
- os.makedirs(dir)
- out = open(name, 'wb')
- out.write(zf.read(name))
- out.close()
- # Set permissions. Permission info in external_attr is shifted 16 bits.
- os.chmod(name, info.external_attr >> 16L)
- os.chdir(pushd)
- except Exception, e:
- print >>sys.stderr, e
- sys.exit(1)
-
-
-def SetArchiveVars(archive):
- """Set a bunch of global variables appropriate for the specified archive."""
- global BUILD_ARCHIVE_TYPE
- global BUILD_ARCHIVE_DIR
- global BUILD_ZIP_NAME
- global BUILD_DIR_NAME
- global BUILD_EXE_NAME
- global BUILD_BASE_URL
-
- BUILD_ARCHIVE_TYPE = archive
- BUILD_ARCHIVE_DIR = 'chromium-rel-' + BUILD_ARCHIVE_TYPE
-
- if BUILD_ARCHIVE_TYPE in ('linux', 'linux-64', 'linux-chromiumos'):
- BUILD_ZIP_NAME = 'chrome-linux.zip'
- BUILD_DIR_NAME = 'chrome-linux'
- BUILD_EXE_NAME = 'chrome'
- elif BUILD_ARCHIVE_TYPE in ('mac'):
- BUILD_ZIP_NAME = 'chrome-mac.zip'
- BUILD_DIR_NAME = 'chrome-mac'
- BUILD_EXE_NAME = 'Chromium.app/Contents/MacOS/Chromium'
- elif BUILD_ARCHIVE_TYPE in ('xp'):
- BUILD_ZIP_NAME = 'chrome-win32.zip'
- BUILD_DIR_NAME = 'chrome-win32'
- BUILD_EXE_NAME = 'chrome.exe'
-
- BUILD_BASE_URL += BUILD_ARCHIVE_DIR
-
-def ParseDirectoryIndex(url):
- """Parses the HTML directory listing into a list of revision numbers."""
- handle = urllib.urlopen(url)
- dirindex = handle.read()
- handle.close()
- return re.findall(r'<a href="([0-9]*)/">\1/</a>', dirindex)
-
-def GetRevList(good, bad):
- """Gets the list of revision numbers between |good| and |bad|."""
- # Download the main revlist.
- revlist = ParseDirectoryIndex(BUILD_BASE_URL)
- revlist = map(int, revlist)
- revlist = filter(lambda r: range(good, bad).__contains__(int(r)), revlist)
- revlist.sort()
- return revlist
-
-def TryRevision(rev, profile, args):
- """Downloads revision |rev|, unzips it, and opens it for the user to test.
- |profile| is the profile to use."""
- # Do this in a temp dir so we don't collide with user files.
- cwd = os.getcwd()
- tempdir = tempfile.mkdtemp(prefix='bisect_tmp')
- os.chdir(tempdir)
-
- # Download the file.
- download_url = BUILD_BASE_URL + (BUILD_ARCHIVE_URL % rev) + BUILD_ZIP_NAME
- try:
- print 'Fetching ' + download_url
- urllib.urlretrieve(download_url, BUILD_ZIP_NAME)
- except Exception, e:
- print('Could not retrieve the download. Sorry.')
- sys.exit(-1)
-
- # Unzip the file.
- print 'Unziping ...'
- UnzipFilenameToDir(BUILD_ZIP_NAME, os.curdir)
-
- # Tell the system to open the app.
- args = ['--user-data-dir=%s' % profile] + args
- flags = ' '.join(map(pipes.quote, args))
- exe = os.path.join(os.getcwd(), BUILD_DIR_NAME, BUILD_EXE_NAME)
- cmd = '%s %s' % (exe, flags)
- print 'Running %s' % cmd
- os.system(cmd)
-
- os.chdir(cwd)
- print 'Cleaning temp dir ...'
- try:
- shutil.rmtree(tempdir, True)
- except Exception, e:
- pass
-
-
-def AskIsGoodBuild(rev):
- """Ask the user whether build |rev| is good or bad."""
- # Loop until we get a response that we can parse.
- while True:
- response = raw_input('\nBuild %d is [(g)ood/(b)ad]: ' % int(rev))
- if response and response in ('g', 'b'):
- return response == 'g'
-
-def main():
- usage = ('%prog [options] [-- chromium-options]\n'
- 'Perform binary search on the snapshot builds.\n'
- '\n'
- 'Tip: add "-- --no-first-run" to bypass the first run prompts.')
- parser = optparse.OptionParser(usage=usage)
- # Strangely, the default help output doesn't include the choice list.
- choices = ['mac', 'xp', 'linux', 'linux-64', 'linux-chromiumos']
- parser.add_option('-a', '--archive',
- choices = choices,
- help = 'The buildbot archive to bisect [%s].' %
- '|'.join(choices))
- parser.add_option('-b', '--bad', type = 'int',
- help = 'The bad revision to bisect to.')
- parser.add_option('-g', '--good', type = 'int',
- help = 'The last known good revision to bisect from.')
- parser.add_option('-p', '--profile', '--user-data-dir', type = 'str',
- help = 'Profile to use; this will not reset every run. ' +
- 'Defaults to a clean profile.')
- (opts, args) = parser.parse_args()
-
- if opts.archive is None:
- print 'Error: missing required parameter: --archive'
- print
- parser.print_help()
- return 1
-
- if opts.bad and opts.good and (opts.good > opts.bad):
- print ('The good revision (%d) must precede the bad revision (%d).\n' %
- (opts.good, opts.bad))
- parser.print_help()
- return 1
-
- SetArchiveVars(opts.archive)
-
- # Pick a starting point, try to get HEAD for this.
- if opts.bad:
- bad_rev = opts.bad
- else:
- bad_rev = 0
- try:
- # Location of the latest build revision number
- BUILD_LATEST_URL = '%s/LATEST' % (BUILD_BASE_URL)
- nh = urllib.urlopen(BUILD_LATEST_URL)
- latest = int(nh.read())
- nh.close()
- bad_rev = raw_input('Bad revision [HEAD:%d]: ' % latest)
- if (bad_rev == ''):
- bad_rev = latest
- bad_rev = int(bad_rev)
- except Exception, e:
- print('Could not determine latest revision. This could be bad...')
- bad_rev = int(raw_input('Bad revision: '))
-
- # Find out when we were good.
- if opts.good:
- good_rev = opts.good
- else:
- good_rev = 0
- try:
- good_rev = int(raw_input('Last known good [0]: '))
- except Exception, e:
- pass
-
- # Get a list of revisions to bisect across.
- revlist = GetRevList(good_rev, bad_rev)
- if len(revlist) < 2: # Don't have enough builds to bisect
- print 'We don\'t have enough builds to bisect. revlist: %s' % revlist
- sys.exit(1)
-
- # If we don't have a |good_rev|, set it to be the first revision possible.
- if good_rev == 0:
- good_rev = revlist[0]
-
- # These are indexes of |revlist|.
- good = 0
- bad = len(revlist) - 1
- last_known_good_rev = revlist[good]
-
- # Binary search time!
- while good < bad:
- candidates = revlist[good:bad]
- num_poss = len(candidates)
- if num_poss > 10:
- print('%d candidates. %d tries left.' %
- (num_poss, round(math.log(num_poss, 2))))
- else:
- print('Candidates: %s' % revlist[good:bad])
-
- # Cut the problem in half...
- test = int((bad - good) / 2) + good
- test_rev = revlist[test]
-
- # Let the user give this rev a spin (in her own profile, if she wants).
- profile = opts.profile
- if not profile:
- profile = 'profile' # In a temp dir.
- TryRevision(test_rev, profile, args)
- if AskIsGoodBuild(test_rev):
- last_known_good_rev = revlist[good]
- good = test + 1
- else:
- bad = test
- # We're done. Let the user know the results in an official manner.
- print('You are probably looking for build %d.' % revlist[bad])
- print('CHANGELOG URL:')
- print(CHANGELOG_URL % (last_known_good_rev, revlist[bad]))
- print('Built at revision:')
- print(BUILD_VIEWVC_URL % revlist[bad])
+print "This script has been moved to tools/bisect-builds.py."
+print "Please update any docs you're working from!"
-if __name__ == '__main__':
- sys.exit(main())
+sys.exit(1)
diff --git a/build/common.gypi b/build/common.gypi
index 1b260cd..e741a29 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -140,6 +140,9 @@
# Remoting compilation is enabled by default. Set to 0 to disable.
'remoting%': 1,
+ # Use libjpeg-turbo as the JPEG codec used by Chromium.
+ 'use_libjpeg_turbo%': 0,
+
'library%': '<(library)',
# Variable 'component' is for cases where we would like to build some
@@ -317,7 +320,7 @@
# Use GConf, the GNOME configuration system.
'use_gconf%': 1,
- # Use OpenSSL instead of NSS. Currently in development.
+ # Use OpenSSL instead of NSS. Under development: see http://crbug.com/62803
'use_openssl%': 0,
'conditions': [
@@ -400,6 +403,13 @@
}, {
'use_cups%': 0,
}],
+ # Set the relative path from this file to the GYP file of the JPEG
+ # library used by Chromium.
+ ['use_libjpeg_turbo==1', {
+ 'libjpeg_gyp_path': '../third_party/libjpeg_turbo/libjpeg.gyp',
+ }, {
+ 'libjpeg_gyp_path': '../third_party/libjpeg/libjpeg.gyp',
+ }], # use_libjpeg_turbo==1
],
# NOTE: When these end up in the Mac bundle, we need to replace '-' for '_'
@@ -541,9 +551,6 @@
}],
],
}],
- # Linux gyp (into scons) doesn't like target_conditions?
- # TODO(???): track down why 'target_conditions' doesn't work
- # on Linux gyp into scons like it does on Mac gyp into xcodeproj.
['OS=="linux"', {
'cflags': [ '-ftest-coverage',
'-fprofile-arcs' ],
@@ -894,73 +901,6 @@
'ldflags': [
'-pthread', '-Wl,-z,noexecstack',
],
- 'scons_variable_settings': {
- 'LIBPATH': ['$LIB_DIR'],
- # Linking of large files uses lots of RAM, so serialize links
- # using the handy flock command from util-linux.
- 'FLOCK_LINK': ['flock', '$TOP_BUILDDIR/linker.lock', '$LINK'],
- 'FLOCK_SHLINK': ['flock', '$TOP_BUILDDIR/linker.lock', '$SHLINK'],
- 'FLOCK_LDMODULE': ['flock', '$TOP_BUILDDIR/linker.lock', '$LDMODULE'],
-
- # We have several cases where archives depend on each other in
- # a cyclic fashion. Since the GNU linker does only a single
- # pass over the archives we surround the libraries with
- # --start-group and --end-group (aka -( and -) ). That causes
- # ld to loop over the group until no more undefined symbols
- # are found. In an ideal world we would only make groups from
- # those libraries which we knew to be in cycles. However,
- # that's tough with SCons, so we bodge it by making all the
- # archives a group by redefining the linking command here.
- #
- # TODO: investigate whether we still have cycles that
- # require --{start,end}-group. There has been a lot of
- # refactoring since this was first coded, which might have
- # eliminated the circular dependencies.
- #
- # Note: $_LIBDIRFLAGS comes before ${LINK,SHLINK,LDMODULE}FLAGS
- # so that we prefer our own built libraries (e.g. -lpng) to
- # system versions of libraries that pkg-config might turn up.
- # TODO(sgk): investigate handling this not by re-ordering the
- # flags this way, but by adding a hook to use the SCons
- # ParseFlags() option on the output from pkg-config.
- 'LINKCOM': [['$FLOCK_LINK', '-o', '$TARGET',
- '$_LIBDIRFLAGS', '$LINKFLAGS', '$SOURCES',
- '-Wl,--start-group', '$_LIBFLAGS', '-Wl,--end-group']],
- 'SHLINKCOM': [['$FLOCK_SHLINK', '-o', '$TARGET',
- '$_LIBDIRFLAGS', '$SHLINKFLAGS', '$SOURCES',
- '-Wl,--start-group', '$_LIBFLAGS', '-Wl,--end-group']],
- 'LDMODULECOM': [['$FLOCK_LDMODULE', '-o', '$TARGET',
- '$_LIBDIRFLAGS', '$LDMODULEFLAGS', '$SOURCES',
- '-Wl,--start-group', '$_LIBFLAGS', '-Wl,--end-group']],
- 'IMPLICIT_COMMAND_DEPENDENCIES': 0,
- # -rpath is only used when building with shared libraries.
- 'conditions': [
- [ 'library=="shared_library"', {
- 'RPATH': '$LIB_DIR',
- }],
- ],
- },
- 'scons_import_variables': [
- 'AS',
- 'CC',
- 'CXX',
- 'LINK',
- ],
- 'scons_propagate_variables': [
- 'AS',
- 'CC',
- 'CCACHE_DIR',
- 'CXX',
- 'DISTCC_DIR',
- 'DISTCC_HOSTS',
- 'HOME',
- 'INCLUDE_SERVER_ARGS',
- 'INCLUDE_SERVER_PORT',
- 'LINK',
- 'CHROME_BUILD_TYPE',
- 'CHROMIUM_BUILD',
- 'OFFICIAL_BUILD',
- ],
'configurations': {
'Debug_Base': {
'variables': {
@@ -1168,9 +1108,6 @@
# http://code.google.com/p/googletest/source/detail?r=446 .
# TODO(thakis): Use -isystem instead (http://crbug.com/58751 ).
'-Wno-unnamed-type-template-args',
- # The integrated assembler chokes on one ffmpeg file.
- # http://crbug.com/61931
- '-no-integrated-as',
],
'cflags!': [
# Clang doesn't seem to know know this flag.
@@ -1186,9 +1123,6 @@
'cflags': [ '-g' ],
'defines': ['USE_LINUX_BREAKPAD'],
}],
- ['linux_use_seccomp_sandbox==1 and buildtype!="Official"', {
- 'defines': ['USE_SECCOMP_SANDBOX'],
- }],
['library=="shared_library"', {
# When building with shared libraries, remove the visiblity-hiding
# flag.
@@ -1199,6 +1133,11 @@
'cflags': ['-fPIC']
}]
],
+ 'ldflags!': [
+ # --as-needed confuses library interdependencies.
+ # See http://code.google.com/p/chromium/issues/detail?id=61430
+ '-Wl,--as-needed',
+ ],
}],
['linux_use_heapchecker==1', {
'variables': {'linux_use_tcmalloc%': 1},
@@ -1503,10 +1442,6 @@
},
}],
],
- 'scons_settings': {
- 'sconsbuild_dir': '<(DEPTH)/sconsbuild',
- 'tools': ['ar', 'as', 'gcc', 'g++', 'gnulink', 'chromium_builders'],
- },
'xcode_settings': {
# DON'T ADD ANYTHING NEW TO THIS BLOCK UNLESS YOU REALLY REALLY NEED IT!
# This block adds *project-wide* configuration settings to each project
diff --git a/build/features_override.gypi b/build/features_override.gypi
index 5c069ea..dc59950 100644
--- a/build/features_override.gypi
+++ b/build/features_override.gypi
@@ -15,6 +15,7 @@
'ENABLE_BLOB=1',
'ENABLE_BLOB_SLICE=1',
'ENABLE_CHANNEL_MESSAGING=1',
+ 'ENABLE_CLIENT_BASED_GEOLOCATION=0',
'ENABLE_DASHBOARD_SUPPORT=0',
'ENABLE_DATABASE=1',
'ENABLE_DATAGRID=0',
diff --git a/build/linux/dump_signature.py b/build/linux/dump_signature.py
deleted file mode 100755
index 37e50f4..0000000
--- a/build/linux/dump_signature.py
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/usr/bin/python
-#
-# 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.
-#
-# This generates symbol signatures with the same algorithm as
-# src/breakpad/src/common/linux/file_id.cc@461
-
-import struct
-import sys
-import subprocess
-
-if len(sys.argv) != 2:
- sys.stderr.write("Error, no filename specified.\n")
- sys.exit(1)
-
-# Shell out to objdump to get the offset of the .text section
-objdump = subprocess.Popen(['objdump', '-h', sys.argv[1]], stdout = subprocess.PIPE)
-(sections, _) = objdump.communicate()
-if objdump.returncode != 0:
- sys.stderr.write('Failed to run objdump to find .text section.\n')
- sys.exit(1)
-
-text_section = [x for x in sections.splitlines() if '.text' in x]
-if len(text_section) == 0:
- sys.stderr.write('objdump failed to find a .text section.\n')
- sys.exit(1)
-text_section = text_section[0]
-try:
- file_offset = int(text_section.split()[5], 16)
-except ValueError:
- sys.stderr.write("Failed to parse objdump output. Here is the failing line:\n");
- sys.stderr.write(text_section)
- sys.exit(1)
-
-bin = open(sys.argv[1])
-bin.seek(file_offset)
-if bin.tell() != file_offset:
- sys.stderr.write("Failed to seek to the .text segment. Truncated file?\n");
- sys.exit(1)
-
-data = bin.read(4096)
-if len(data) != 4096:
- sys.stderr.write("Error, did not read first page of data.\n");
- sys.exit(1)
-bin.close()
-
-signature = [0] * 16
-for i in range(0, 4096):
- signature[i % 16] ^= ord(data[i])
-
-# Append a 0 at the end for the generation number (always 0 on Linux)
-out = ('%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X0' %
- struct.unpack('I2H8B', struct.pack('16B', *signature)))
-sys.stdout.write(out)
diff --git a/build/linux/system.gyp b/build/linux/system.gyp
index 85f8063..39b3a11 100644
--- a/build/linux/system.gyp
+++ b/build/linux/system.gyp
@@ -93,7 +93,6 @@
# out of $(pkg-config --cflags nss) and GYP include paths
# come after cflags on the command line. So we have these
# bodges:
- '-I../net/third_party/nss/ssl', # for scons
'-Inet/third_party/nss/ssl', # for make
'-IWebKit/chromium/net/third_party/nss/ssl', # for make in webkit
'<!@(<(pkg-config) --cflags nss)',
@@ -347,29 +346,6 @@
],
},
},
- {
- 'target_name': 'openssl',
- 'type': 'settings',
- 'conditions': [
- ['use_openssl==1', {
- 'direct_dependent_settings': {
- 'defines': [
- # OpenSSL support is incomplete: http://crbug.com/62803.
- # Defining USE_OPENSSL disables USE_NSS.
- 'USE_OPENSSL',
- ],
- 'include_dirs': [
- '<!@(<(pkg-config) --cflags openssl)',
- ],
- },
- 'link_settings': {
- 'libraries': [
- '<!@(<(pkg-config) --libs-only-l openssl)',
- ],
- },
- },],
- ],
- },
],
}
diff --git a/build/sanitize-mac-build-log.sed b/build/sanitize-mac-build-log.sed
new file mode 100644
index 0000000..d6cef78
--- /dev/null
+++ b/build/sanitize-mac-build-log.sed
@@ -0,0 +1,22 @@
+#!/bin/echo Use sanitize-mac-build-log.sh or sed -f
+
+# 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.
+
+# Use this sed script to reduce a Mac build log into something readable.
+
+# Drop uninformative lines.
+/^distcc/d
+/^Check dependencies/d
+/^ setenv /d
+/^ cd /d
+/^make: Nothing to be done/d
+
+# Xcode prints a short "compiling foobar.o" line followed by the lengthy
+# full command line. These deletions drop the command line.
+\|^ /Developer/usr/bin/|d
+
+# Shorten the "compiling foobar.o" line.
+s|^Distributed-CompileC \(.*\) normal i386 c++ com.apple.compilers.gcc.4_2| CC \1|
+s|^CompileC \(.*\) normal i386 c++ com.apple.compilers.gcc.4_2| CC \1|
diff --git a/build/sanitize-mac-build-log.sh b/build/sanitize-mac-build-log.sh
new file mode 100755
index 0000000..dc743fa
--- /dev/null
+++ b/build/sanitize-mac-build-log.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+# 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.
+sed -f `dirname "${0}"`/`basename "${0}" sh`sed
+
diff --git a/build/sanitize-win-build-log.sed b/build/sanitize-win-build-log.sed
new file mode 100644
index 0000000..d6d049c
--- /dev/null
+++ b/build/sanitize-win-build-log.sed
@@ -0,0 +1,14 @@
+#!/bin/echo Use sanitize-win-build-log.sh or sed -f
+
+# 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.
+
+# Use this sed script to reduce a Windows build log into something
+# machine-parsable.
+
+# Drop uninformative lines.
+/The operation completed successfully./d
+
+# Drop parallelization indicators on lines.
+s/^[0-9]\+>//
diff --git a/build/sanitize-win-build-log.sh b/build/sanitize-win-build-log.sh
new file mode 100755
index 0000000..dc743fa
--- /dev/null
+++ b/build/sanitize-win-build-log.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+# 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.
+sed -f `dirname "${0}"`/`basename "${0}" sh`sed
+
diff --git a/build/whitespace_file.txt b/build/whitespace_file.txt
index 7bd040c..ccedfae 100644
--- a/build/whitespace_file.txt
+++ b/build/whitespace_file.txt
@@ -6,4 +6,4 @@ This file is used for making non-code changes to trigger buildbot cycles. Make
any modification below this line.
================================================================================
-I AM SOMEWHAT SPARTA
+i am somewhat YELLY!
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index b92e996..a052a2d 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -7,7 +7,6 @@ include_rules = [
"+chrome/profile_import",
"+chrome/tools/profiles", # For history unit tests.
"+chrome/views",
- "+cros",
"+grit", # For generated headers
"+ppapi/proxy",
"+rlz",
@@ -15,8 +14,10 @@ include_rules = [
"+sandbox/src", # The path doesn't say it, but this is the Windows sandbox.
"+skia/ext",
"+skia/include",
+ "+third_party/cros",
"+webkit/database",
"+webkit/glue", # Defines some types that are marshalled over IPC.
+ "+webkit/plugins", # Defines some types that are marshalled over IPC.
"+xib_localizers", # For generated mac localization helpers
# Other libraries.
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index a404dc1..5085859 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -12,6 +12,7 @@
#include "app/l10n_util.h"
#include "base/command_line.h"
#include "base/singleton.h"
+#include "base/string_number_conversions.h"
#include "base/values.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/prefs/pref_service.h"
@@ -21,6 +22,12 @@
namespace about_flags {
+// Macros to simplify specifying the type.
+#define SINGLE_VALUE_TYPE(command_line) Experiment::SINGLE_VALUE, \
+ command_line, NULL, 0
+#define MULTI_VALUE_TYPE(choices) Experiment::MULTI_VALUE, "", choices, \
+ arraysize(choices)
+
namespace {
const unsigned kOsAll = kOsMac | kOsWin | kOsLinux | kOsCrOS;
@@ -31,6 +38,15 @@ const char kMediaPlayerExperimentName[] = "media-player";
const char kAdvancedFileSystemExperimentName[] = "advanced-file-system";
const char kVerticalTabsExperimentName[] = "vertical-tabs";
+// If adding a new choice, add it to the end of the list.
+const Experiment::Choice kInstantChoices[] = {
+ { IDS_FLAGS_INSTANT_TYPE_VERBATIM, switches::kEnableVerbatimInstant },
+ { IDS_FLAGS_INSTANT_TYPE_PREDICTIVE, switches::kEnablePredictiveInstant },
+ { IDS_FLAGS_INSTANT_TYPE_PREDICTIVE_NO_AUTO_COMPLETE,
+ switches::kEnablePredictiveNoAutoCompleteInstant
+ },
+};
+
// RECORDING USER METRICS FOR FLAGS:
// -----------------------------------------------------------------------------
// The first line of the experiment is the internal name. If you'd like to
@@ -51,6 +67,16 @@ const char kVerticalTabsExperimentName[] = "vertical-tabs";
// TODO(rsesek): See if there's a way to count per-user, rather than
// per-startup.
+// To add a new experiment add to the end of kExperiments. There are two
+// distinct types of experiments:
+// . SINGLE_VALUE: experiment is either on or off. Use the SINGLE_VALUE_TYPE
+// macro for this type supplying the command line to the macro.
+// . MULTI_VALUE: if enabled the command line of the selected choice is enabled.
+// To specify this type of experiment use the macro MULTI_VALUE_TYPE supplying
+// it the array of choices.
+// See the documentation of Experiment for details on the fields.
+//
+// When adding a new choice, add it to the end of the list.
const Experiment kExperiments[] = {
{
"expose-for-tabs", // FLAGS:RECORD_UMA
@@ -59,9 +85,9 @@ const Experiment kExperiments[] = {
kOsMac,
#if defined(OS_MACOSX)
// The switch exists only on OS X.
- switches::kEnableExposeForTabs
+ SINGLE_VALUE_TYPE(switches::kEnableExposeForTabs)
#else
- ""
+ SINGLE_VALUE_TYPE("")
#endif
},
{
@@ -71,9 +97,9 @@ const Experiment kExperiments[] = {
kOsCrOS,
#if defined(OS_CHROMEOS)
// The switch exists only on Chrome OS.
- switches::kEnableMediaPlayer
+ SINGLE_VALUE_TYPE(switches::kEnableMediaPlayer)
#else
- ""
+ SINGLE_VALUE_TYPE("")
#endif
},
{
@@ -83,9 +109,9 @@ const Experiment kExperiments[] = {
kOsCrOS,
#if defined(OS_CHROMEOS)
// The switch exists only on Chrome OS.
- switches::kEnableAdvancedFileSystem
+ SINGLE_VALUE_TYPE(switches::kEnableAdvancedFileSystem)
#else
- ""
+ SINGLE_VALUE_TYPE("")
#endif
},
{
@@ -93,14 +119,14 @@ const Experiment kExperiments[] = {
IDS_FLAGS_SIDE_TABS_NAME,
IDS_FLAGS_SIDE_TABS_DESCRIPTION,
kOsWin | kOsCrOS,
- switches::kEnableVerticalTabs
+ SINGLE_VALUE_TYPE(switches::kEnableVerticalTabs)
},
{
"tabbed-options", // FLAGS:RECORD_UMA
IDS_FLAGS_TABBED_OPTIONS_NAME,
IDS_FLAGS_TABBED_OPTIONS_DESCRIPTION,
kOsWin | kOsLinux | kOsMac, // Enabled by default on CrOS.
- switches::kEnableTabbedOptions
+ SINGLE_VALUE_TYPE(switches::kEnableTabbedOptions)
},
{
"remoting", // FLAGS:RECORD_UMA
@@ -116,35 +142,28 @@ const Experiment kExperiments[] = {
0,
#endif
kOsWin | kOsLinux | kOsCrOS,
- switches::kEnableRemoting
- },
- {
- "disable-outdated-plugins", // FLAGS:RECORD_UMA
- IDS_FLAGS_DISABLE_OUTDATED_PLUGINS_NAME,
- IDS_FLAGS_DISABLE_OUTDATED_PLUGINS_DESCRIPTION,
- kOsAll,
- switches::kDisableOutdatedPlugins
+ SINGLE_VALUE_TYPE(switches::kEnableRemoting)
},
{
"xss-auditor", // FLAGS:RECORD_UMA
IDS_FLAGS_XSS_AUDITOR_NAME,
IDS_FLAGS_XSS_AUDITOR_DESCRIPTION,
kOsAll,
- switches::kEnableXSSAuditor
+ SINGLE_VALUE_TYPE(switches::kEnableXSSAuditor)
},
{
"background-webapps", // FLAGS:RECORD_UMA
IDS_FLAGS_BACKGROUND_WEBAPPS_NAME,
IDS_FLAGS_BACKGROUND_WEBAPPS_DESCRIPTION,
- kOsAll,
- switches::kEnableBackgroundMode
+ kOsLinux, // Enabled by default on windows and mac, not available on CrOS.
+ SINGLE_VALUE_TYPE(switches::kEnableBackgroundMode)
},
{
"conflicting-modules-check", // FLAGS:RECORD_UMA
IDS_FLAGS_CONFLICTS_CHECK_NAME,
IDS_FLAGS_CONFLICTS_CHECK_DESCRIPTION,
kOsWin,
- switches::kConflictingModulesCheck
+ SINGLE_VALUE_TYPE(switches::kConflictingModulesCheck)
},
{
"cloud-print-proxy", // FLAGS:RECORD_UMA
@@ -159,28 +178,28 @@ const Experiment kExperiments[] = {
// plug-in could be supplied, we'll keep the lab enabled.
kOsWin,
#endif
- switches::kEnableCloudPrintProxy
+ SINGLE_VALUE_TYPE(switches::kEnableCloudPrintProxy)
},
{
"crxless-web-apps",
IDS_FLAGS_CRXLESS_WEB_APPS_NAME,
IDS_FLAGS_CRXLESS_WEB_APPS_DESCRIPTION,
kOsAll,
- switches::kEnableCrxlessWebApps
+ SINGLE_VALUE_TYPE(switches::kEnableCrxlessWebApps)
},
{
"gpu-compositing",
IDS_FLAGS_ACCELERATED_COMPOSITING_NAME,
IDS_FLAGS_ACCELERATED_COMPOSITING_DESCRIPTION,
kOsAll,
- switches::kEnableAcceleratedLayers
+ SINGLE_VALUE_TYPE(switches::kEnableAcceleratedLayers)
},
{
"gpu-canvas-2d", // FLAGS:RECORD_UMA
IDS_FLAGS_ACCELERATED_CANVAS_2D_NAME,
IDS_FLAGS_ACCELERATED_CANVAS_2D_DESCRIPTION,
kOsWin | kOsLinux | kOsCrOS,
- switches::kEnableAccelerated2dCanvas
+ SINGLE_VALUE_TYPE(switches::kEnableAccelerated2dCanvas)
},
// FIXME(scheib): Add Flags entry for WebGL,
// or pull it and the strings in generated_resources.grd by Dec 2010
@@ -189,64 +208,78 @@ const Experiment kExperiments[] = {
// IDS_FLAGS_WEBGL_NAME,
// IDS_FLAGS_WEBGL_DESCRIPTION,
// kOsAll,
- // switches::kDisableExperimentalWebGL
+ // SINGLE_VALUE_TYPE(switches::kDisableExperimentalWebGL)
// }
{
"print-preview", // FLAGS:RECORD_UMA
IDS_FLAGS_PRINT_PREVIEW_NAME,
IDS_FLAGS_PRINT_PREVIEW_DESCRIPTION,
kOsAll,
- switches::kEnablePrintPreview
+ SINGLE_VALUE_TYPE(switches::kEnablePrintPreview)
},
{
"enable-nacl", // FLAGS:RECORD_UMA
IDS_FLAGS_ENABLE_NACL_NAME,
IDS_FLAGS_ENABLE_NACL_DESCRIPTION,
kOsAll,
- switches::kEnableNaCl
+ SINGLE_VALUE_TYPE(switches::kEnableNaCl)
},
{
"dns-server", // FLAGS:RECORD_UMA
IDS_FLAGS_DNS_SERVER_NAME,
IDS_FLAGS_DNS_SERVER_DESCRIPTION,
kOsLinux,
- switches::kDnsServer
+ SINGLE_VALUE_TYPE(switches::kDnsServer)
},
{
"page-prerender", // FLAGS:RECORD_UMA
IDS_FLAGS_PAGE_PRERENDER_NAME,
IDS_FLAGS_PAGE_PRERENDER_DESCRIPTION,
kOsAll,
- switches::kEnablePagePrerender
+ SINGLE_VALUE_TYPE(switches::kEnablePagePrerender)
},
{
"confirm-to-quit", // FLAGS:RECORD_UMA
IDS_FLAGS_CONFIRM_TO_QUIT_NAME,
IDS_FLAGS_CONFIRM_TO_QUIT_DESCRIPTION,
kOsMac,
- switches::kEnableConfirmToQuit
+ SINGLE_VALUE_TYPE(switches::kEnableConfirmToQuit)
},
{
"extension-apis", // FLAGS:RECORD_UMA
IDS_FLAGS_EXPERIMENTAL_EXTENSION_APIS_NAME,
IDS_FLAGS_EXPERIMENTAL_EXTENSION_APIS_DESCRIPTION,
kOsAll,
- switches::kEnableExperimentalExtensionApis
+ SINGLE_VALUE_TYPE(switches::kEnableExperimentalExtensionApis)
},
{
"click-to-play", // FLAGS:RECORD_UMA
IDS_FLAGS_CLICK_TO_PLAY_NAME,
IDS_FLAGS_CLICK_TO_PLAY_DESCRIPTION,
kOsAll,
- switches::kEnableClickToPlay
+ SINGLE_VALUE_TYPE(switches::kEnableClickToPlay)
},
{
"disable-hyperlink-auditing",
IDS_FLAGS_DISABLE_HYPERLINK_AUDITING_NAME,
IDS_FLAGS_DISABLE_HYPERLINK_AUDITING_DESCRIPTION,
kOsAll,
- switches::kNoPings
- }
+ SINGLE_VALUE_TYPE(switches::kNoPings)
+ },
+ {
+ "experimental-location-features", // FLAGS:RECORD_UMA
+ IDS_FLAGS_EXPERIMENTAL_LOCATION_FEATURES_NAME,
+ IDS_FLAGS_EXPERIMENTAL_LOCATION_FEATURES_DESCRIPTION,
+ kOsMac | kOsWin | kOsLinux, // Currently does nothing on CrOS.
+ SINGLE_VALUE_TYPE(switches::kExperimentalLocationFeatures)
+ },
+ {
+ "instant-type", // FLAGS:RECORD_UMA
+ IDS_FLAGS_INSTANT_TYPE_NAME,
+ IDS_FLAGS_INSTANT_TYPE_DESCRIPTION,
+ kOsWin,
+ MULTI_VALUE_TYPE(kInstantChoices)
+ },
};
const Experiment* experiments = kExperiments;
@@ -265,7 +298,7 @@ class FlagsState {
void reset();
// Returns the singleton instance of this class
- static FlagsState* instance() {
+ static FlagsState* GetInstance() {
return Singleton<FlagsState>::get();
}
@@ -331,13 +364,32 @@ void SetEnabledFlags(
}
}
+// Returns the name used in prefs for the choice at the specified index.
+std::string NameForChoice(const Experiment& e, int index) {
+ DCHECK(e.type == Experiment::MULTI_VALUE);
+ DCHECK(index < e.num_choices);
+ return std::string(e.internal_name) + about_flags::testing::kMultiSeparator +
+ base::IntToString(index);
+}
+
+// Adds the internal names for the specified experiment to |names|.
+void AddInternalName(const Experiment& e, std::set<std::string>* names) {
+ if (e.type == Experiment::SINGLE_VALUE) {
+ names->insert(e.internal_name);
+ } else {
+ DCHECK(e.type == Experiment::MULTI_VALUE);
+ for (int i = 0; i < e.num_choices; ++i)
+ names->insert(NameForChoice(e, i));
+ }
+}
+
// Removes all experiments from prefs::kEnabledLabsExperiments that are
// unknown, to prevent this list to become very long as experiments are added
// and removed.
void SanitizeList(PrefService* prefs) {
std::set<std::string> known_experiments;
for (size_t i = 0; i < num_experiments; ++i)
- known_experiments.insert(experiments[i].internal_name);
+ AddInternalName(experiments[i], &known_experiments);
std::set<std::string> enabled_experiments;
GetEnabledFlags(prefs, &enabled_experiments);
@@ -370,7 +422,7 @@ void GetSanitizedEnabledFlagsForCurrentPlatform(
int current_platform = GetCurrentPlatform();
for (size_t i = 0; i < num_experiments; ++i) {
if (experiments[i].supported_platforms & current_platform)
- platform_experiments.insert(experiments[i].internal_name);
+ AddInternalName(experiments[i], &platform_experiments);
}
std::set<std::string> new_enabled_experiments;
@@ -382,10 +434,33 @@ void GetSanitizedEnabledFlagsForCurrentPlatform(
result->swap(new_enabled_experiments);
}
+// Returns the Value representing the choice data in the specified experiment.
+// If one of the choices is enabled |is_one_selected| is set to true.
+Value* CreateChoiceData(const Experiment& experiment,
+ const std::set<std::string>& enabled_experiments,
+ bool* is_one_selected) {
+ DCHECK(experiment.type == Experiment::MULTI_VALUE);
+ ListValue* result = new ListValue;
+ for (int i = 0; i < experiment.num_choices; ++i) {
+ const Experiment::Choice& choice = experiment.choices[i];
+ DictionaryValue* value = new DictionaryValue;
+ std::string name = NameForChoice(experiment, i);
+ value->SetString("description",
+ l10n_util::GetStringUTF16(choice.description_id));
+ value->SetString("internal_name", name);
+ bool is_selected = enabled_experiments.count(name) > 0;
+ if (is_selected)
+ *is_one_selected = true;
+ value->SetBoolean("selected", is_selected);
+ result->Append(value);
+ }
+ return result;
+}
+
} // namespace
void ConvertFlagsToSwitches(PrefService* prefs, CommandLine* command_line) {
- FlagsState::instance()->ConvertFlagsToSwitches(prefs, command_line);
+ FlagsState::GetInstance()->ConvertFlagsToSwitches(prefs, command_line);
}
ListValue* GetFlagsExperimentsData(PrefService* prefs) {
@@ -407,26 +482,32 @@ ListValue* GetFlagsExperimentsData(PrefService* prefs) {
data->SetString("description",
l10n_util::GetStringUTF16(
experiment.visible_description_id));
- data->SetBoolean("enabled",
- enabled_experiments.count(experiment.internal_name) > 0);
+ bool enabled = enabled_experiments.count(experiment.internal_name) > 0;
+
+ if (experiment.type == Experiment::MULTI_VALUE) {
+ data->Set("choices", CreateChoiceData(experiment, enabled_experiments,
+ &enabled));
+ }
+
+ data->SetBoolean("enabled", enabled);
experiments_data->Append(data);
}
return experiments_data;
}
bool IsRestartNeededToCommitChanges() {
- return FlagsState::instance()->IsRestartNeededToCommitChanges();
+ return FlagsState::GetInstance()->IsRestartNeededToCommitChanges();
}
void SetExperimentEnabled(
PrefService* prefs, const std::string& internal_name, bool enable) {
- FlagsState::instance()->SetExperimentEnabled(prefs, internal_name, enable);
+ FlagsState::GetInstance()->SetExperimentEnabled(prefs, internal_name, enable);
}
void RemoveFlagsSwitches(
std::map<std::string, CommandLine::StringType>* switch_list) {
- FlagsState::instance()->RemoveFlagsSwitches(switch_list);
+ FlagsState::GetInstance()->RemoveFlagsSwitches(switch_list);
}
int GetCurrentPlatform() {
@@ -478,9 +559,17 @@ void FlagsState::ConvertFlagsToSwitches(
GetSanitizedEnabledFlagsForCurrentPlatform(prefs, &enabled_experiments);
- std::map<std::string, const Experiment*> experiment_map;
- for (size_t i = 0; i < num_experiments; ++i)
- experiment_map[experiments[i].internal_name] = &experiments[i];
+ typedef std::map<std::string, std::string> NameToSwitchMap;
+ NameToSwitchMap name_to_switch_map;
+ for (size_t i = 0; i < num_experiments; ++i) {
+ const Experiment& e = experiments[i];
+ if (e.type == Experiment::SINGLE_VALUE) {
+ name_to_switch_map[e.internal_name] = e.command_line;
+ } else {
+ for (int j = 0; j < e.num_choices; ++j)
+ name_to_switch_map[NameForChoice(e, j)] = e.choices[j].command_line;
+ }
+ }
command_line->AppendSwitch(switches::kFlagSwitchesBegin);
flags_switches_.insert(switches::kFlagSwitchesBegin);
@@ -488,14 +577,15 @@ void FlagsState::ConvertFlagsToSwitches(
it != enabled_experiments.end();
++it) {
const std::string& experiment_name = *it;
- std::map<std::string, const Experiment*>::iterator experiment =
- experiment_map.find(experiment_name);
- DCHECK(experiment != experiment_map.end());
- if (experiment == experiment_map.end())
+ NameToSwitchMap::const_iterator name_to_switch_it =
+ name_to_switch_map.find(experiment_name);
+ if (name_to_switch_it == name_to_switch_map.end()) {
+ NOTREACHED();
continue;
+ }
- command_line->AppendSwitch(experiment->second->command_line);
- flags_switches_.insert(experiment->second->command_line);
+ command_line->AppendSwitch(name_to_switch_it->second);
+ flags_switches_.insert(name_to_switch_it->second);
}
command_line->AppendSwitch(switches::kFlagSwitchesEnd);
flags_switches_.insert(switches::kFlagSwitchesEnd);
@@ -509,13 +599,56 @@ void FlagsState::SetExperimentEnabled(
PrefService* prefs, const std::string& internal_name, bool enable) {
needs_restart_ = true;
+ size_t at_index = internal_name.find(about_flags::testing::kMultiSeparator);
+ if (at_index != std::string::npos) {
+ DCHECK(enable);
+ // We're being asked to enable a multi-choice experiment. Disable the
+ // currently selected choice.
+ DCHECK_NE(at_index, 0u);
+ SetExperimentEnabled(prefs, internal_name.substr(0, at_index), false);
+
+ // And enable the new choice.
+ std::set<std::string> enabled_experiments;
+ GetSanitizedEnabledFlags(prefs, &enabled_experiments);
+ enabled_experiments.insert(internal_name);
+ SetEnabledFlags(prefs, enabled_experiments);
+ return;
+ }
+
std::set<std::string> enabled_experiments;
GetSanitizedEnabledFlags(prefs, &enabled_experiments);
- if (enable)
- enabled_experiments.insert(internal_name);
- else
- enabled_experiments.erase(internal_name);
+ const Experiment* e = NULL;
+ for (size_t i = 0; i < num_experiments; ++i) {
+ if (experiments[i].internal_name == internal_name) {
+ e = experiments + i;
+ break;
+ }
+ }
+ DCHECK(e);
+
+ if (e->type == Experiment::SINGLE_VALUE) {
+ if (enable)
+ enabled_experiments.insert(internal_name);
+ else
+ enabled_experiments.erase(internal_name);
+ } else {
+ if (enable) {
+ // Enable the first choice.
+ enabled_experiments.insert(NameForChoice(*e, 0));
+ } else {
+ // Find the currently enabled choice and disable it.
+ for (int i = 0; i < e->num_choices; ++i) {
+ std::string choice_name = NameForChoice(*e, i);
+ if (enabled_experiments.find(choice_name) !=
+ enabled_experiments.end()) {
+ enabled_experiments.erase(choice_name);
+ // Continue on just in case there's a bug and more than one
+ // experiment for this choice was enabled.
+ }
+ }
+ }
+ }
SetEnabledFlags(prefs, enabled_experiments);
}
@@ -537,8 +670,13 @@ void FlagsState::reset() {
} // namespace
namespace testing {
+
+// WARNING: '@' is also used in the html file. If you update this constant you
+// also need to update the html file.
+const char kMultiSeparator[] = "@";
+
void ClearState() {
- FlagsState::instance()->reset();
+ FlagsState::GetInstance()->reset();
}
void SetExperiments(const Experiment* e, size_t count) {
@@ -551,6 +689,11 @@ void SetExperiments(const Experiment* e, size_t count) {
}
}
+const Experiment* GetExperiments(size_t* count) {
+ *count = num_experiments;
+ return experiments;
+}
+
} // namespace testing
} // namespace about_flags
diff --git a/chrome/browser/about_flags.h b/chrome/browser/about_flags.h
index fa8c868..daa76df 100644
--- a/chrome/browser/about_flags.h
+++ b/chrome/browser/about_flags.h
@@ -24,6 +24,27 @@ enum { kOsMac = 1 << 0, kOsWin = 1 << 1, kOsLinux = 1 << 2 , kOsCrOS = 1 << 3 };
// for testing).
// This is exposed only for testing.
struct Experiment {
+ enum Type {
+ // An experiment with a single value. This is typically what you want.
+ SINGLE_VALUE,
+
+ // The experiment has multiple values only one of which is ever enabled.
+ // For MULTI_VALUE experiments the command_line of the Experiment is not
+ // used. If the experiment is enabled the command line of the selected
+ // Choice is enabled.
+ MULTI_VALUE,
+ };
+
+ // Used for MULTI_VALUE types to describe one of the possible values the user
+ // can select.
+ struct Choice {
+ // ID of the message containing the choice name.
+ int description_id;
+
+ // Command line to enabled for this choice.
+ const char* command_line;
+ };
+
// The internal name of the experiment. This is never shown to the user.
// It _is_ however stored in the prefs file, so you shouldn't change the
// name of existing flags.
@@ -39,10 +60,21 @@ struct Experiment {
// Needs to be more than a compile-time #ifdef because of profile sync.
unsigned supported_platforms; // bitmask
+ // Type of experiment.
+ Type type;
+
// The commandline parameter that's added when this lab is active. This is
// different from |internal_name| so that the commandline flag can be
// renamed without breaking the prefs file.
+ // This is used if type is SINGLE_VALUE.
const char* command_line;
+
+ // This is used if type is MULTI_VALUE.
+ const Choice* choices;
+
+ // Number of |choices|.
+ // This is used if type is MULTI_VALUE.
+ int num_choices;
};
// Reads the Labs |prefs| (called "Labs" for historical reasons) and adds the
@@ -80,6 +112,14 @@ void ClearState();
// Sets the list of experiments. Pass in NULL to use the default set. This does
// NOT take ownership of the supplied Experiments.
void SetExperiments(const Experiment* e, size_t count);
+
+// Returns the current set of experiments.
+const Experiment* GetExperiments(size_t* count);
+
+// Separator used for multi values. Multi values are represented in prefs as
+// name-of-experiment + kMultiSeparator + selected_index.
+extern const char kMultiSeparator[];
+
} // namespace testing
} // namespace about_flags
diff --git a/chrome/browser/about_flags_unittest.cc b/chrome/browser/about_flags_unittest.cc
index f6b5193..c3bbe95 100644
--- a/chrome/browser/about_flags_unittest.cc
+++ b/chrome/browser/about_flags_unittest.cc
@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/about_flags.h"
-
+#include "base/string_number_conversions.h"
#include "base/values.h"
+#include "chrome/browser/about_flags.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_pref_service.h"
@@ -14,37 +14,64 @@
const char kFlags1[] = "flag1";
const char kFlags2[] = "flag2";
const char kFlags3[] = "flag3";
+const char kFlags4[] = "flag4";
const char kSwitch1[] = "switch";
const char kSwitch2[] = "switch2";
const char kSwitch3[] = "switch3";
+const char kMultiSwitch1[] = "multi_switch1";
+const char kMultiSwitch2[] = "multi_switch2";
+
namespace about_flags {
-// The experiments that are set for these tests. The first two experiments are
-// supported on the current platform, but the last is only supported on a
-// platform other than the current.
+const Experiment::Choice kMultiChoices[] = {
+ { IDS_PRODUCT_NAME, kMultiSwitch1 },
+ { IDS_PRODUCT_NAME, kMultiSwitch2 },
+};
+
+// The experiments that are set for these tests. The 3rd experiment is not
+// supported on the current platform, all others are.
static Experiment kExperiments[] = {
{
kFlags1,
IDS_PRODUCT_NAME,
IDS_PRODUCT_NAME,
0, // Ends up being mapped to the current platform.
- kSwitch1
+ Experiment::SINGLE_VALUE,
+ kSwitch1,
+ NULL,
+ 0
},
{
kFlags2,
IDS_PRODUCT_NAME,
IDS_PRODUCT_NAME,
0, // Ends up being mapped to the current platform.
- kSwitch2
+ Experiment::SINGLE_VALUE,
+ kSwitch2,
+ NULL,
+ 0
},
{
kFlags3,
IDS_PRODUCT_NAME,
IDS_PRODUCT_NAME,
0, // This ends up enabling for an OS other than the current.
- kSwitch3
+ Experiment::SINGLE_VALUE,
+ kSwitch3,
+ NULL,
+ 0
+ },
+ {
+ kFlags4,
+ IDS_PRODUCT_NAME,
+ IDS_PRODUCT_NAME,
+ 0, // Ends up being mapped to the current platform.
+ Experiment::MULTI_VALUE,
+ "",
+ kMultiChoices,
+ arraysize(kMultiChoices)
},
};
@@ -176,7 +203,7 @@ TEST_F(AboutFlagsTest, RemoveFlagSwitches) {
// Tests enabling experiments that aren't supported on the current platform.
TEST_F(AboutFlagsTest, PersistAndPrune) {
- // Enable exerpiement 1 and experiment 3.
+ // Enable experiments 1 and 3.
SetExperimentEnabled(&prefs_, kFlags1, true);
SetExperimentEnabled(&prefs_, kFlags3, true);
CommandLine command_line(CommandLine::NO_PROGRAM);
@@ -192,7 +219,51 @@ TEST_F(AboutFlagsTest, PersistAndPrune) {
// Experiment 3 should show still be persisted in preferences though.
scoped_ptr<ListValue> switch_prefs(GetFlagsExperimentsData(&prefs_));
ASSERT_TRUE(switch_prefs.get());
- EXPECT_EQ(2u, switch_prefs->GetSize());
+ EXPECT_EQ(arraysize(kExperiments) - 1, switch_prefs->GetSize());
+}
+
+// Tests enabling multi-value type experiments.
+TEST_F(AboutFlagsTest, MultiValues) {
+ // Enable the multi value experiment, which should enable the first choice.
+ SetExperimentEnabled(&prefs_, kFlags4, true);
+ {
+ CommandLine command_line(CommandLine::NO_PROGRAM);
+ ConvertFlagsToSwitches(&prefs_, &command_line);
+ EXPECT_TRUE(command_line.HasSwitch(kMultiSwitch1));
+ EXPECT_FALSE(command_line.HasSwitch(kMultiSwitch2));
+ }
+
+ // Enable the 2nd choice of the multi-value, which should disable the first
+ // choice.
+ SetExperimentEnabled(&prefs_, std::string(kFlags4) +
+ std::string(testing::kMultiSeparator) +
+ base::IntToString(1), true);
+ {
+ CommandLine command_line(CommandLine::NO_PROGRAM);
+ ConvertFlagsToSwitches(&prefs_, &command_line);
+ EXPECT_FALSE(command_line.HasSwitch(kMultiSwitch1));
+ EXPECT_TRUE(command_line.HasSwitch(kMultiSwitch2));
+ }
+
+ // Disable the multi-value experiment.
+ SetExperimentEnabled(&prefs_, kFlags4, false);
+ {
+ CommandLine command_line(CommandLine::NO_PROGRAM);
+ ConvertFlagsToSwitches(&prefs_, &command_line);
+ EXPECT_FALSE(command_line.HasSwitch(kMultiSwitch1));
+ EXPECT_FALSE(command_line.HasSwitch(kMultiSwitch2));
+ }
+}
+
+// Makes sure there are no separators in any of the experiment names.
+TEST_F(AboutFlagsTest, NoSeparators) {
+ testing::SetExperiments(NULL, 0);
+ size_t count;
+ const Experiment* experiments = testing::GetExperiments(&count);
+ for (size_t i = 0; i < count; ++i) {
+ std::string name = experiments->internal_name;
+ EXPECT_EQ(std::string::npos, name.find(testing::kMultiSeparator)) << i;
+ }
}
} // namespace about_flags
diff --git a/chrome/browser/accessibility/browser_accessibility_cocoa.mm b/chrome/browser/accessibility/browser_accessibility_cocoa.mm
index e03d1ed..a86a0bb 100644
--- a/chrome/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/chrome/browser/accessibility/browser_accessibility_cocoa.mm
@@ -210,6 +210,9 @@ bool GetState(BrowserAccessibility* accessibility, int state) {
WebAccessibility::ATTR_HELP);
}
if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
+ // WebCore uses an attachmentView to get the below behavior.
+ // We do not have any native views backing this object, so need
+ // to approximate Cocoa ax behavior best as we can.
if ([self role] == @"AXHeading") {
NSString* headingLevel =
NSStringForWebAccessibilityAttribute(
@@ -219,6 +222,9 @@ bool GetState(BrowserAccessibility* accessibility, int state) {
return [NSNumber numberWithInt:
[[headingLevel substringFromIndex:1] intValue]];
}
+ } else if ([self role] == NSAccessibilityButtonRole) {
+ // AXValue does not make sense for pure buttons.
+ return @"";
} else if ([self role] == NSAccessibilityCheckBoxRole) {
return [NSNumber numberWithInt:GetState(
browserAccessibility_, WebAccessibility::STATE_CHECKED) ? 1 : 0];
@@ -238,20 +244,24 @@ bool GetState(BrowserAccessibility* accessibility, int state) {
return [NSNumber numberWithBool:
!GetState(browserAccessibility_, WebAccessibility::STATE_UNAVAILABLE)];
}
+ if ([attribute isEqualToString:@"AXVisited"]) {
+ return [NSNumber numberWithBool:
+ GetState(browserAccessibility_, WebAccessibility::STATE_TRAVERSED)];
+ }
// AXWebArea attributes.
if ([attribute isEqualToString:@"AXLoaded"])
return [NSNumber numberWithBool:YES];
if ([attribute isEqualToString:@"AXURL"]) {
+ WebAccessibility::Attribute urlAttribute =
+ [[self role] isEqualToString:@"AXWebArea"] ?
+ WebAccessibility::ATTR_DOC_URL :
+ WebAccessibility::ATTR_URL;
return NSStringForWebAccessibilityAttribute(
browserAccessibility_->attributes(),
- WebAccessibility::ATTR_DOC_URL);
+ urlAttribute);
}
- // TODO(dtseng): provide complete implementations for the following.
- if ([attribute isEqualToString:@"AXVisited"])
- return [NSNumber numberWithBool:NO];
-
// Text related attributes.
if ([attribute isEqualToString:
NSAccessibilityNumberOfCharactersAttribute]) {
@@ -294,8 +304,11 @@ bool GetState(BrowserAccessibility* accessibility, int state) {
[ret addObject:NSAccessibilityShowMenuAction];
// TODO(dtseng): this should only get set when there's a default action.
- if ([self role] != NSAccessibilityStaticTextRole)
+ if ([self role] != NSAccessibilityStaticTextRole &&
+ [self role] != NSAccessibilityTextAreaRole &&
+ [self role] != NSAccessibilityTextFieldRole) {
[ret addObject:NSAccessibilityPressAction];
+ }
return ret;
}
@@ -350,14 +363,14 @@ bool GetState(BrowserAccessibility* accessibility, int state) {
NSAccessibilityTopLevelUIElementAttribute,
NSAccessibilityValueAttribute,
NSAccessibilityWindowAttribute,
+ @"AXURL",
+ @"AXVisited",
nil]];
// Specific role attributes.
if ([self role] == @"AXWebArea") {
[ret addObjectsFromArray:[NSArray arrayWithObjects:
@"AXLoaded",
- @"AXURL",
- @"AXVisited",
nil]];
}
@@ -404,7 +417,11 @@ bool GetState(BrowserAccessibility* accessibility, int state) {
// that backs this object.
- (void)accessibilityPerformAction:(NSString*)action {
// TODO(feldstein): Support more actions.
- [delegate_ doDefaultAction:browserAccessibility_->renderer_id()];
+ if ([action isEqualToString:NSAccessibilityPressAction]) {
+ [delegate_ doDefaultAction:browserAccessibility_->renderer_id()];
+ } else if ([action isEqualToString:NSAccessibilityShowMenuAction]) {
+ // TODO(dtseng): implement.
+ }
}
// Returns the description of the given action.
diff --git a/chrome/browser/accessibility/browser_accessibility_mac_unittest.mm b/chrome/browser/accessibility/browser_accessibility_mac_unittest.mm
index a9a0a5d..aea75d7 100644
--- a/chrome/browser/accessibility/browser_accessibility_mac_unittest.mm
+++ b/chrome/browser/accessibility/browser_accessibility_mac_unittest.mm
@@ -9,7 +9,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/accessibility/browser_accessibility_cocoa.h"
#include "chrome/browser/accessibility/browser_accessibility_manager.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
#import "testing/gtest_mac.h"
diff --git a/chrome/browser/accessibility/browser_accessibility_state.cc b/chrome/browser/accessibility/browser_accessibility_state.cc
index 4896f91..1f251d9 100644
--- a/chrome/browser/accessibility/browser_accessibility_state.cc
+++ b/chrome/browser/accessibility/browser_accessibility_state.cc
@@ -3,7 +3,8 @@
// found in the LICENSE file.
#include "chrome/browser/accessibility/browser_accessibility_state.h"
-#include "chrome/browser/profile.h"
+
+#include "base/singleton.h"
BrowserAccessibilityState::BrowserAccessibilityState()
: screen_reader_active_(false) {
@@ -12,6 +13,11 @@ BrowserAccessibilityState::BrowserAccessibilityState()
BrowserAccessibilityState::~BrowserAccessibilityState() {
}
+// static
+BrowserAccessibilityState* BrowserAccessibilityState::GetInstance() {
+ return Singleton<BrowserAccessibilityState>::get();
+}
+
void BrowserAccessibilityState::OnScreenReaderDetected() {
screen_reader_active_ = true;
}
diff --git a/chrome/browser/accessibility/browser_accessibility_state.h b/chrome/browser/accessibility/browser_accessibility_state.h
index efcd2dd..bdd7bcc 100644
--- a/chrome/browser/accessibility/browser_accessibility_state.h
+++ b/chrome/browser/accessibility/browser_accessibility_state.h
@@ -7,7 +7,8 @@
#pragma once
#include "base/basictypes.h"
-#include "base/singleton.h"
+
+template <typename T> struct DefaultSingletonTraits;
// The BrowserAccessibilityState class is used to determine if Chrome should be
// customized for users with assistive technology, such as screen readers. We
@@ -25,6 +26,9 @@
// file for Universal Access with the key "voiceOverOnOffKey".
class BrowserAccessibilityState {
public:
+ // Returns the singleton instance.
+ static BrowserAccessibilityState* GetInstance();
+
~BrowserAccessibilityState();
// Called when screen reader client is detected.
diff --git a/chrome/browser/accessibility/browser_views_accessibility_browsertest.cc b/chrome/browser/accessibility/browser_views_accessibility_browsertest.cc
index d0c08c1..6844409 100644
--- a/chrome/browser/accessibility/browser_views_accessibility_browsertest.cc
+++ b/chrome/browser/accessibility/browser_views_accessibility_browsertest.cc
@@ -9,10 +9,10 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/view_ids.h"
-#include "chrome/browser/views/bookmark_bar_view.h"
-#include "chrome/browser/views/frame/browser_view.h"
-#include "chrome/browser/views/toolbar_view.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/bookmark_bar_view.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/toolbar_view.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
diff --git a/chrome/browser/accessibility_events.cc b/chrome/browser/accessibility_events.cc
index a48ca11..ce9f637 100644
--- a/chrome/browser/accessibility_events.cc
+++ b/chrome/browser/accessibility_events.cc
@@ -7,7 +7,7 @@
#include "base/values.h"
#include "chrome/browser/extensions/extension_accessibility_api_constants.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
diff --git a/chrome/browser/aeropeek_manager.cc b/chrome/browser/aeropeek_manager.cc
index 54fd46d..9273cd2 100644
--- a/chrome/browser/aeropeek_manager.cc
+++ b/chrome/browser/aeropeek_manager.cc
@@ -24,8 +24,8 @@
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/tab_contents/thumbnail_generator.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/installer/util/browser_distribution.h"
diff --git a/chrome/browser/alternate_nav_url_fetcher.cc b/chrome/browser/alternate_nav_url_fetcher.cc
index cdd4f7e..199afbc 100644
--- a/chrome/browser/alternate_nav_url_fetcher.cc
+++ b/chrome/browser/alternate_nav_url_fetcher.cc
@@ -8,7 +8,7 @@
#include "app/resource_bundle.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/intranet_redirect_detector.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
diff --git a/chrome/browser/app_controller_mac.h b/chrome/browser/app_controller_mac.h
index 721aefc..02a55b0 100644
--- a/chrome/browser/app_controller_mac.h
+++ b/chrome/browser/app_controller_mac.h
@@ -9,7 +9,7 @@
#import <Cocoa/Cocoa.h>
#include <vector>
-#include "base/cocoa_protocols_mac.h"
+#import "base/mac/cocoa_protocols.h"
#include "base/scoped_nsobject.h"
#include "base/scoped_ptr.h"
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm
index f0c715b..428f375 100644
--- a/chrome/browser/app_controller_mac.mm
+++ b/chrome/browser/app_controller_mac.mm
@@ -13,32 +13,17 @@
#include "base/message_loop.h"
#include "base/string_number_conversions.h"
#include "base/sys_string_conversions.h"
-#import "base/worker_pool_mac.h"
#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/background_application_list_model.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_shutdown.h"
#include "chrome/browser/browser_thread.h"
-#import "chrome/browser/cocoa/about_window_controller.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_menu_bridge.h"
-#import "chrome/browser/cocoa/browser_window_cocoa.h"
-#import "chrome/browser/cocoa/browser_window_controller.h"
-#import "chrome/browser/cocoa/bug_report_window_controller.h"
-#import "chrome/browser/cocoa/clear_browsing_data_controller.h"
-#import "chrome/browser/cocoa/confirm_quit_panel_controller.h"
-#import "chrome/browser/cocoa/encoding_menu_controller_delegate_mac.h"
-#import "chrome/browser/cocoa/history_menu_bridge.h"
-#import "chrome/browser/cocoa/import_settings_dialog.h"
-#import "chrome/browser/cocoa/preferences_window_controller.h"
-#import "chrome/browser/cocoa/tab_strip_controller.h"
-#import "chrome/browser/cocoa/tab_window_controller.h"
-#include "chrome/browser/cocoa/task_manager_mac.h"
#include "chrome/browser/command_updater.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/options_window.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/printing/print_job_manager.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/sessions/tab_restore_service.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/sync_ui_util.h"
@@ -48,6 +33,21 @@
#include "chrome/browser/ui/browser_init.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
+#import "chrome/browser/ui/cocoa/about_window_controller.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h"
+#import "chrome/browser/ui/cocoa/browser_window_cocoa.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "chrome/browser/ui/cocoa/bug_report_window_controller.h"
+#import "chrome/browser/ui/cocoa/clear_browsing_data_controller.h"
+#import "chrome/browser/ui/cocoa/confirm_quit_panel_controller.h"
+#import "chrome/browser/ui/cocoa/encoding_menu_controller_delegate_mac.h"
+#import "chrome/browser/ui/cocoa/history_menu_bridge.h"
+#import "chrome/browser/ui/cocoa/import_settings_dialog.h"
+#import "chrome/browser/ui/cocoa/preferences_window_controller.h"
+#import "chrome/browser/ui/cocoa/tab_strip_controller.h"
+#import "chrome/browser/ui/cocoa/tab_window_controller.h"
+#include "chrome/browser/ui/cocoa/task_manager_mac.h"
+#include "chrome/browser/ui/options/options_window.h"
#include "chrome/common/app_mode_common_mac.h"
#include "chrome/common/chrome_paths_internal.h"
#include "chrome/common/chrome_switches.h"
@@ -155,6 +155,7 @@ void RecordLastRunAppBundlePath() {
- (void)showPreferencesWindow:(id)sender
page:(OptionsPage)page
profile:(Profile*)profile;
+- (void)executeApplication:(id)sender;
@end
@implementation AppController
@@ -223,15 +224,6 @@ void RecordLastRunAppBundlePath() {
if (parsed_command_line.HasSwitch(switches::kActivateOnLaunch)) {
[NSApp activateIgnoringOtherApps:YES];
}
-
- // Temporary flag to revert to the old WorkerPool implementation.
- // This will be removed once we either fix the Mac WorkerPool
- // implementation, or completely switch to the shared (with Linux)
- // implementation.
- // http://crbug.com/44392
- if (parsed_command_line.HasSwitch(switches::kDisableLinuxWorkerPool)) {
- worker_pool_mac::SetUseLinuxWorkerPool(false);
- }
}
// (NSApplicationDelegate protocol) This is the Apple-approved place to override
@@ -293,76 +285,92 @@ void RecordLastRunAppBundlePath() {
// If the application is going to terminate as the result of a Cmd+Q
// invocation, use the special sauce to prevent accidental quitting.
// http://dev.chromium.org/developers/design-documents/confirm-to-quit-experiment
- NSEvent* currentEvent = [app currentEvent];
- if ([currentEvent type] == NSKeyDown) {
- // Show the info panel that explains what the user must to do confirm quit.
- [[ConfirmQuitPanelController sharedController] showWindow:self];
-
- // How long the user must hold down Cmd+Q to confirm the quit.
- const NSTimeInterval kTimeToConfirmQuit = 1.5;
- // Leeway between the |targetDate| and the current time that will confirm a
- // quit.
- const NSTimeInterval kTimeDeltaFuzzFactor = 1.0;
- // Duration of the window fade out animation.
- const NSTimeInterval kWindowFadeAnimationDuration = 0.2;
-
- // Spin a nested run loop until the |targetDate| is reached or a KeyUp event
- // is sent.
- NSDate* targetDate =
- [NSDate dateWithTimeIntervalSinceNow:kTimeToConfirmQuit];
- BOOL willQuit = NO;
- NSEvent* nextEvent = nil;
- do {
- // Dequeue events until a key up is received.
- nextEvent = [app nextEventMatchingMask:NSKeyUpMask
- untilDate:nil
- inMode:NSEventTrackingRunLoopMode
- dequeue:YES];
-
- // Wait for the time expiry to happen. Once past the hold threshold,
- // commit to quitting and hide all the open windows.
- if (!willQuit) {
- NSDate* now = [NSDate date];
- NSTimeInterval difference = [targetDate timeIntervalSinceDate:now];
- if (difference < kTimeDeltaFuzzFactor) {
- willQuit = YES;
-
- // At this point, the quit has been confirmed and windows should all
- // fade out to convince the user to release the key combo to finalize
- // the quit.
- [NSAnimationContext beginGrouping];
- [[NSAnimationContext currentContext] setDuration:
- kWindowFadeAnimationDuration];
- for (NSWindow* aWindow in [app windows]) {
- // Windows that are set to animate and have a delegate do not
- // expect to be animated by other things and could result in an
- // invalid state. If a window is set up like so, just force the
- // alpha value to 0. Otherwise, animate all pretty and stuff.
- if (![[aWindow animationForKey:@"alphaValue"] delegate]) {
- [[aWindow animator] setAlphaValue:0.0];
- } else {
- [aWindow setAlphaValue:0.0];
- }
+
+ // How long the user must hold down Cmd+Q to confirm the quit.
+ const NSTimeInterval kTimeToConfirmQuit = 1.5;
+ // Leeway between the |targetDate| and the current time that will confirm a
+ // quit.
+ const NSTimeInterval kTimeDeltaFuzzFactor = 1.0;
+ // Duration of the window fade out animation.
+ const NSTimeInterval kWindowFadeAnimationDuration = 0.2;
+
+ // This logic is only for keyboard-initiated quits.
+ if ([[app currentEvent] type] != NSKeyDown)
+ return NSTerminateNow;
+
+ // If this is the second of two such attempts to quit within a certain time
+ // interval, then just quit.
+ // Time of last quit attempt, if any.
+ static NSDate* lastQuitAttempt; // Initially nil, as it's static.
+ NSDate* timeNow = [NSDate date];
+ if (lastQuitAttempt &&
+ [timeNow timeIntervalSinceDate:lastQuitAttempt] < kTimeDeltaFuzzFactor) {
+ return NSTerminateNow;
+ } else {
+ [lastQuitAttempt release]; // Harmless if already nil.
+ lastQuitAttempt = [timeNow retain]; // Record this attempt for next time.
+ }
+
+ // Show the info panel that explains what the user must to do confirm quit.
+ [[ConfirmQuitPanelController sharedController] showWindow:self];
+
+ // Spin a nested run loop until the |targetDate| is reached or a KeyUp event
+ // is sent.
+ NSDate* targetDate =
+ [NSDate dateWithTimeIntervalSinceNow:kTimeToConfirmQuit];
+ BOOL willQuit = NO;
+ NSEvent* nextEvent = nil;
+ do {
+ // Dequeue events until a key up is received.
+ nextEvent = [app nextEventMatchingMask:NSKeyUpMask
+ untilDate:nil
+ inMode:NSEventTrackingRunLoopMode
+ dequeue:YES];
+
+ // Wait for the time expiry to happen. Once past the hold threshold,
+ // commit to quitting and hide all the open windows.
+ if (!willQuit) {
+ NSDate* now = [NSDate date];
+ NSTimeInterval difference = [targetDate timeIntervalSinceDate:now];
+ if (difference < kTimeDeltaFuzzFactor) {
+ willQuit = YES;
+
+ // At this point, the quit has been confirmed and windows should all
+ // fade out to convince the user to release the key combo to finalize
+ // the quit.
+ [NSAnimationContext beginGrouping];
+ [[NSAnimationContext currentContext] setDuration:
+ kWindowFadeAnimationDuration];
+ for (NSWindow* aWindow in [app windows]) {
+ // Windows that are set to animate and have a delegate do not
+ // expect to be animated by other things and could result in an
+ // invalid state. If a window is set up like so, just force the
+ // alpha value to 0. Otherwise, animate all pretty and stuff.
+ if (![[aWindow animationForKey:@"alphaValue"] delegate]) {
+ [[aWindow animator] setAlphaValue:0.0];
+ } else {
+ [aWindow setAlphaValue:0.0];
}
- [NSAnimationContext endGrouping];
}
+ [NSAnimationContext endGrouping];
}
- } while (!nextEvent);
-
- // The user has released the key combo. Discard any events (i.e. the
- // repeated KeyDown Cmd+Q).
- [app discardEventsMatchingMask:NSAnyEventMask beforeEvent:nextEvent];
- if (willQuit) {
- // The user held down the combination long enough that quitting should
- // happen.
- return NSTerminateNow;
- } else {
- // Slowly fade the confirm window out in case the user doesn't
- // understand what they have to do to quit.
- [[ConfirmQuitPanelController sharedController] dismissPanel];
- return NSTerminateCancel;
}
- } // if event type is KeyDown
+ } while (!nextEvent);
+
+ // The user has released the key combo. Discard any events (i.e. the
+ // repeated KeyDown Cmd+Q).
+ [app discardEventsMatchingMask:NSAnyEventMask beforeEvent:nextEvent];
+
+ if (willQuit) {
+ // The user held down the combination long enough that quitting should
+ // happen.
+ return NSTerminateNow;
+ } else {
+ // Slowly fade the confirm window out in case the user doesn't
+ // understand what they have to do to quit.
+ [[ConfirmQuitPanelController sharedController] dismissPanel];
+ return NSTerminateCancel;
+ }
// Default case: terminate.
return NSTerminateNow;
@@ -786,7 +794,7 @@ void RecordLastRunAppBundlePath() {
enable = YES;
} else if (action == @selector(orderFrontStandardAboutPanel:)) {
enable = YES;
- } else if (action == @selector(newWindowFromDock:)) {
+ } else if (action == @selector(commandFromDock:)) {
enable = YES;
}
return enable;
@@ -922,7 +930,30 @@ void RecordLastRunAppBundlePath() {
case IDC_OPTIONS:
[self showPreferences:sender];
break;
+ default:
+ // Background Applications use dynamic values that must be less than the
+ // smallest value among the predefined IDC_* labels.
+ if ([sender tag] < IDC_MinimumLabelValue)
+ [self executeApplication:sender];
+ break;
+ }
+}
+
+// Run a (background) application in a new tab.
+- (void)executeApplication:(id)sender {
+ NSInteger tag = [sender tag];
+ Profile* profile = [self defaultProfile];
+ DCHECK(profile);
+ BackgroundApplicationListModel applications(profile);
+ DCHECK(tag >= 0 &&
+ tag < static_cast<int>(applications.size()));
+ Browser* browser = BrowserList::GetLastActive();
+ if (!browser) {
+ Browser::OpenEmptyWindow(profile);
+ browser = BrowserList::GetLastActive();
}
+ const Extension* extension = applications.GetExtension(tag);
+ browser->OpenApplicationTab(profile, extension, NULL);
}
// Same as |-commandDispatch:|, but executes commands using a disposition
@@ -1156,25 +1187,52 @@ void RecordLastRunAppBundlePath() {
}
// Explicitly bring to the foreground when creating new windows from the dock.
-- (void)newWindowFromDock:(id)sender {
+- (void)commandFromDock:(id)sender {
[NSApp activateIgnoringOtherApps:YES];
[self commandDispatch:sender];
}
- (NSMenu*)applicationDockMenu:(NSApplication*)sender {
NSMenu* dockMenu = [[[NSMenu alloc] initWithTitle: @""] autorelease];
+ Profile* profile = [self defaultProfile];
+
+ // TODO(rickcam): Mock out BackgroundApplicationListModel, then add unit
+ // tests which use the mock in place of the profile-initialized model.
+
+ // Avoid breaking unit tests which have no profile.
+ if (profile) {
+ int position = 0;
+ BackgroundApplicationListModel applications(profile);
+ for (ExtensionList::const_iterator cursor = applications.begin();
+ cursor != applications.end();
+ ++cursor, ++position) {
+ DCHECK(position == applications.GetPosition(*cursor));
+ scoped_nsobject<NSMenuItem> appItem([[NSMenuItem alloc]
+ initWithTitle:base::SysUTF16ToNSString(UTF8ToUTF16((*cursor)->name()))
+ action:@selector(commandFromDock:)
+ keyEquivalent:@""]);
+ [appItem setTarget:self];
+ [appItem setTag:position];
+ [dockMenu addItem:appItem];
+ }
+ if (applications.begin() != applications.end()) {
+ NSMenuItem* sepItem = [[NSMenuItem separatorItem] init];
+ [dockMenu addItem:sepItem];
+ }
+ }
+
NSString* titleStr = l10n_util::GetNSStringWithFixup(IDS_NEW_WINDOW_MAC);
scoped_nsobject<NSMenuItem> item([[NSMenuItem alloc]
- initWithTitle:titleStr
- action:@selector(newWindowFromDock:)
- keyEquivalent:@""]);
+ initWithTitle:titleStr
+ action:@selector(commandFromDock:)
+ keyEquivalent:@""]);
[item setTarget:self];
[item setTag:IDC_NEW_WINDOW];
[dockMenu addItem:item];
titleStr = l10n_util::GetNSStringWithFixup(IDS_NEW_INCOGNITO_WINDOW_MAC);
item.reset([[NSMenuItem alloc] initWithTitle:titleStr
- action:@selector(newWindowFromDock:)
+ action:@selector(commandFromDock:)
keyEquivalent:@""]);
[item setTarget:self];
[item setTag:IDC_NEW_INCOGNITO_WINDOW];
diff --git a/chrome/browser/app_controller_mac_unittest.mm b/chrome/browser/app_controller_mac_unittest.mm
index 6af8e13..88e8de3 100644
--- a/chrome/browser/app_controller_mac_unittest.mm
+++ b/chrome/browser/app_controller_mac_unittest.mm
@@ -22,6 +22,6 @@ TEST_F(AppControllerTest, DockMenu) {
EXPECT_NE(-1, [menu indexOfItemWithTag:IDC_NEW_INCOGNITO_WINDOW]);
for (item in [menu itemArray]) {
EXPECT_EQ(ac.get(), [item target]);
- EXPECT_EQ(@selector(newWindowFromDock:), [item action]);
+ EXPECT_EQ(@selector(commandFromDock:), [item action]);
}
}
diff --git a/chrome/browser/app_modal_dialog.cc b/chrome/browser/app_modal_dialog.cc
deleted file mode 100644
index 506d76f..0000000
--- a/chrome/browser/app_modal_dialog.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/app_modal_dialog.h"
-
-#include "chrome/browser/app_modal_dialog_queue.h"
-#include "chrome/browser/native_app_modal_dialog.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/notification_type.h"
-
-AppModalDialog::AppModalDialog(TabContents* tab_contents,
- const std::wstring& title)
- : skip_this_dialog_(false),
- tab_contents_(tab_contents),
- native_dialog_(NULL),
- title_(title) {
-}
-
-AppModalDialog::~AppModalDialog() {
-}
-
-void AppModalDialog::ShowModalDialog() {
- if (tab_contents_)
- tab_contents_->Activate();
-
- CreateAndShowDialog();
-
- NotificationService::current()->Notify(
- NotificationType::APP_MODAL_DIALOG_SHOWN,
- Source<AppModalDialog>(this),
- NotificationService::NoDetails());
-}
-
-void AppModalDialog::CreateAndShowDialog() {
- native_dialog_ = CreateNativeDialog();
- native_dialog_->ShowAppModalDialog();
-}
-
-void AppModalDialog::ActivateModalDialog() {
- DCHECK(native_dialog_);
- native_dialog_->ActivateAppModalDialog();
-}
-
-void AppModalDialog::CloseModalDialog() {
- DCHECK(native_dialog_);
- native_dialog_->CloseAppModalDialog();
-}
-
-void AppModalDialog::CompleteDialog() {
- Singleton<AppModalDialogQueue>()->ShowNextDialog();
-}
diff --git a/chrome/browser/app_modal_dialog.h b/chrome/browser/app_modal_dialog.h
deleted file mode 100644
index 0803972..0000000
--- a/chrome/browser/app_modal_dialog.h
+++ /dev/null
@@ -1,82 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_APP_MODAL_DIALOG_H_
-#define CHROME_BROWSER_APP_MODAL_DIALOG_H_
-#pragma once
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "build/build_config.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
-
-class NativeAppModalDialog;
-class TabContents;
-
-// A controller+model base class for modal dialogs.
-class AppModalDialog {
- public:
- // A union of data necessary to determine the type of message box to
- // show. |tab_contents| parameter is optional, if provided that tab will be
- // activated before the modal dialog is displayed.
- AppModalDialog(TabContents* tab_contents, const std::wstring& title);
- virtual ~AppModalDialog();
-
- // Called by the AppModalDialogQueue to show this dialog.
- void ShowModalDialog();
-
- // Called by the AppModalDialogQueue to activate the dialog.
- void ActivateModalDialog();
-
- // Closes the dialog if it is showing.
- void CloseModalDialog();
-
- // Completes dialog handling, shows next modal dialog from the queue.
- // TODO(beng): Get rid of this method.
- void CompleteDialog();
-
- // Dialog window title.
- std::wstring title() const { return title_; }
-
- NativeAppModalDialog* native_dialog() const { return native_dialog_; }
-
- // Methods overridable by AppModalDialog subclasses:
-
- // Creates an implementation of NativeAppModalDialog and shows it.
- // When the native dialog is closed, the implementation of
- // NativeAppModalDialog should call OnAccept or OnCancel to notify the
- // renderer of the user's action. The NativeAppModalDialog is also
- // expected to delete the AppModalDialog associated with it.
- virtual void CreateAndShowDialog();
-
- // Returns true if the dialog is still valid. As dialogs are created they are
- // added to the AppModalDialogQueue. When the current modal dialog finishes
- // and it's time to show the next dialog in the queue IsValid is invoked.
- // If IsValid returns false the dialog is deleted and not shown.
- virtual bool IsValid() { return !skip_this_dialog_; }
-
- protected:
- // Overridden by subclasses to create the feature-specific native dialog box.
- virtual NativeAppModalDialog* CreateNativeDialog() = 0;
-
- // True if the dialog should no longer be shown, e.g. because the underlying
- // tab navigated away while the dialog was queued.
- bool skip_this_dialog_;
-
- // Parent tab contents.
- TabContents* tab_contents_;
-
- // The toolkit-specific implementation of the app modal dialog box.
- NativeAppModalDialog* native_dialog_;
-
- private:
- // Information about the message box is held in the following variables.
- std::wstring title_;
-
- DISALLOW_COPY_AND_ASSIGN(AppModalDialog);
-};
-
-#endif // CHROME_BROWSER_APP_MODAL_DIALOG_H_
diff --git a/chrome/browser/app_modal_dialog_queue.cc b/chrome/browser/app_modal_dialog_queue.cc
deleted file mode 100644
index d3f48d7..0000000
--- a/chrome/browser/app_modal_dialog_queue.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-// 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.
-
-#include "chrome/browser/app_modal_dialog_queue.h"
-
-#include "chrome/browser/browser_list.h"
-
-void AppModalDialogQueue::AddDialog(AppModalDialog* dialog) {
- if (!active_dialog_) {
- ShowModalDialog(dialog);
- return;
- }
- app_modal_dialog_queue_.push(dialog);
-}
-
-void AppModalDialogQueue::ShowNextDialog() {
- AppModalDialog* dialog = GetNextDialog();
- if (dialog)
- ShowModalDialog(dialog);
- else
- active_dialog_ = NULL;
-}
-
-void AppModalDialogQueue::ActivateModalDialog() {
- if (showing_modal_dialog_) {
- // As part of showing a modal dialog we may end up back in this method
- // (showing a dialog activates the TabContents, which can trigger a call
- // to ActivateModalDialog). We ignore such a request as after the call to
- // activate the tab contents the dialog is shown.
- return;
- }
- if (active_dialog_)
- active_dialog_->ActivateModalDialog();
-}
-
-AppModalDialogQueue::AppModalDialogQueue()
- : active_dialog_(NULL), showing_modal_dialog_(false) {
-}
-
-AppModalDialogQueue::~AppModalDialogQueue() {}
-
-void AppModalDialogQueue::ShowModalDialog(AppModalDialog* dialog) {
- // Be sure and set the active_dialog_ field first, otherwise if
- // ShowModalDialog triggers a call back to the queue they'll get the old
- // dialog. Also, if the dialog calls |ShowNextDialog()| before returning, that
- // would write NULL into |active_dialog_| and this function would then undo
- // that.
- active_dialog_ = dialog;
- showing_modal_dialog_ = true;
- dialog->ShowModalDialog();
- showing_modal_dialog_ = false;
-}
-
-AppModalDialog* AppModalDialogQueue::GetNextDialog() {
- while (!app_modal_dialog_queue_.empty()) {
- AppModalDialog* dialog = app_modal_dialog_queue_.front();
- app_modal_dialog_queue_.pop();
- if (dialog->IsValid())
- return dialog;
- delete dialog;
- }
- return NULL;
-}
diff --git a/chrome/browser/app_modal_dialog_queue.h b/chrome/browser/app_modal_dialog_queue.h
deleted file mode 100644
index 90298e3..0000000
--- a/chrome/browser/app_modal_dialog_queue.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_APP_MODAL_DIALOG_QUEUE_H_
-#define CHROME_BROWSER_APP_MODAL_DIALOG_QUEUE_H_
-#pragma once
-
-#include <queue>
-
-#include "base/singleton.h"
-#include "chrome/browser/app_modal_dialog.h"
-
-// Keeps a queue of AppModalDialogs, making sure only one app modal
-// dialog is shown at a time.
-// This class is a singleton.
-class AppModalDialogQueue {
- public:
- // Adds a modal dialog to the queue, if there are no other dialogs in the
- // queue, the dialog will be shown immediately. Once it is shown, the
- // most recently active browser window (or whichever is currently active)
- // will be app modal, meaning it will be activated if the user tries to
- // activate any other browser windows. So the dialog being shown should
- // assure it is the child of BrowserList::GetLastActive() so that it is
- // activated as well. See browser_list.h for more notes about our somewhat
- // sloppy app modality.
- // Note: The AppModalDialog |dialog| must be window modal before it
- // can be added as app modal.
- void AddDialog(AppModalDialog* dialog);
-
- // Removes the current dialog in the queue (the one that is being shown).
- // Shows the next dialog in the queue, if any is present. This does not
- // ensure that the currently showing dialog is closed, it just makes it no
- // longer app modal.
- void ShowNextDialog();
-
- // Activates and shows the current dialog, if the user clicks on one of the
- // windows disabled by the presence of an app modal dialog. This forces
- // the window to be visible on the display even if desktop manager software
- // opened the dialog on another virtual desktop. Assumes there is currently a
- // dialog being shown. (Call BrowserList::IsShowingAppModalDialog to test
- // this condition).
- void ActivateModalDialog();
-
- // Returns true if there is currently an active app modal dialog box.
- bool HasActiveDialog() {
- return active_dialog_ != NULL;
- }
-
- // Accessor for |active_dialog_|.
- AppModalDialog* active_dialog() {
- return active_dialog_;
- }
-
- private:
- friend struct DefaultSingletonTraits<AppModalDialogQueue>;
-
- AppModalDialogQueue();
- ~AppModalDialogQueue();
-
- // Shows |dialog| and notifies the BrowserList that a modal dialog is showing.
- void ShowModalDialog(AppModalDialog* dialog);
-
- // Returns the next dialog to show. This removes entries from
- // app_modal_dialog_queue_ until one is valid or the queue is empty. This
- // returns NULL if there are no more dialogs, or all the dialogs in the queue
- // are not valid.
- AppModalDialog* GetNextDialog();
-
- // Contains all app modal dialogs which are waiting to be shown, with the
- // currently modal dialog at the front of the queue.
- std::queue<AppModalDialog*> app_modal_dialog_queue_;
-
- // The currently active app-modal dialog box's delegate. NULL if there is no
- // active app-modal dialog box.
- AppModalDialog* active_dialog_;
-
- // Stores if |ShowModalDialog()| is currently being called on an app-modal
- // dialog.
- bool showing_modal_dialog_;
-
- DISALLOW_COPY_AND_ASSIGN(AppModalDialogQueue);
-};
-
-#endif // CHROME_BROWSER_APP_MODAL_DIALOG_QUEUE_H_
diff --git a/chrome/browser/appcache/appcache_dispatcher_host.cc b/chrome/browser/appcache/appcache_dispatcher_host.cc
index e7525e2..8bcf53e 100644
--- a/chrome/browser/appcache/appcache_dispatcher_host.cc
+++ b/chrome/browser/appcache/appcache_dispatcher_host.cc
@@ -6,32 +6,35 @@
#include "base/callback.h"
#include "chrome/browser/appcache/chrome_appcache_service.h"
-#include "chrome/browser/renderer_host/browser_render_process_host.h"
+#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/net/chrome_url_request_context.h"
+#include "chrome/browser/renderer_host/browser_render_process_host.h"
#include "chrome/common/render_messages.h"
AppCacheDispatcherHost::AppCacheDispatcherHost(
- URLRequestContext* request_context)
- : request_context_(request_context),
- receiver_(NULL) {
+ URLRequestContext* request_context,
+ int process_id)
+ : ALLOW_THIS_IN_INITIALIZER_LIST(frontend_proxy_(this)),
+ request_context_(request_context),
+ process_id_(process_id) {
DCHECK(request_context_.get());
}
AppCacheDispatcherHost::AppCacheDispatcherHost(
- URLRequestContextGetter* request_context_getter)
- : request_context_getter_(request_context_getter),
- receiver_(NULL) {
+ URLRequestContextGetter* request_context_getter,
+ int process_id)
+ : ALLOW_THIS_IN_INITIALIZER_LIST(frontend_proxy_(this)),
+ request_context_getter_(request_context_getter),
+ process_id_(process_id) {
DCHECK(request_context_getter_.get());
}
AppCacheDispatcherHost::~AppCacheDispatcherHost() {}
-void AppCacheDispatcherHost::Initialize(
- ResourceDispatcherHost::Receiver* receiver) {
- DCHECK(receiver && !receiver_);
- DCHECK(request_context_.get() || request_context_getter_.get());
+void AppCacheDispatcherHost::OnChannelConnected(int32 peer_pid) {
+ BrowserMessageFilter::OnChannelConnected(peer_pid);
- receiver_ = receiver;
+ DCHECK(request_context_.get() || request_context_getter_.get());
// Get the AppCacheService (it can only be accessed from IO thread).
URLRequestContext* context = request_context_.get();
@@ -42,10 +45,9 @@ void AppCacheDispatcherHost::Initialize(
request_context_ = NULL;
request_context_getter_ = NULL;
- frontend_proxy_.set_sender(receiver);
if (appcache_service_.get()) {
backend_impl_.Initialize(
- appcache_service_.get(), &frontend_proxy_, receiver->id());
+ appcache_service_.get(), &frontend_proxy_, process_id_);
get_status_callback_.reset(
NewCallback(this, &AppCacheDispatcherHost::GetStatusCallback));
start_update_callback_.reset(
@@ -55,33 +57,37 @@ void AppCacheDispatcherHost::Initialize(
}
}
-bool AppCacheDispatcherHost::OnMessageReceived(const IPC::Message& msg,
- bool *msg_ok) {
- DCHECK(receiver_);
- *msg_ok = true;
+bool AppCacheDispatcherHost::OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok) {
bool handled = true;
- IPC_BEGIN_MESSAGE_MAP_EX(AppCacheDispatcherHost, msg, *msg_ok)
- IPC_MESSAGE_HANDLER(AppCacheMsg_RegisterHost, OnRegisterHost);
- IPC_MESSAGE_HANDLER(AppCacheMsg_UnregisterHost, OnUnregisterHost);
- IPC_MESSAGE_HANDLER(AppCacheMsg_GetResourceList, OnGetResourceList);
- IPC_MESSAGE_HANDLER(AppCacheMsg_SelectCache, OnSelectCache);
+ IPC_BEGIN_MESSAGE_MAP_EX(AppCacheDispatcherHost, message, *message_was_ok)
+ IPC_MESSAGE_HANDLER(AppCacheMsg_RegisterHost, OnRegisterHost)
+ IPC_MESSAGE_HANDLER(AppCacheMsg_UnregisterHost, OnUnregisterHost)
+ IPC_MESSAGE_HANDLER(AppCacheMsg_GetResourceList, OnGetResourceList)
+ IPC_MESSAGE_HANDLER(AppCacheMsg_SelectCache, OnSelectCache)
IPC_MESSAGE_HANDLER(AppCacheMsg_SelectCacheForWorker,
- OnSelectCacheForWorker);
+ OnSelectCacheForWorker)
IPC_MESSAGE_HANDLER(AppCacheMsg_SelectCacheForSharedWorker,
- OnSelectCacheForSharedWorker);
- IPC_MESSAGE_HANDLER(AppCacheMsg_MarkAsForeignEntry, OnMarkAsForeignEntry);
- IPC_MESSAGE_HANDLER_DELAY_REPLY(AppCacheMsg_GetStatus, OnGetStatus);
- IPC_MESSAGE_HANDLER_DELAY_REPLY(AppCacheMsg_StartUpdate, OnStartUpdate);
- IPC_MESSAGE_HANDLER_DELAY_REPLY(AppCacheMsg_SwapCache, OnSwapCache);
+ OnSelectCacheForSharedWorker)
+ IPC_MESSAGE_HANDLER(AppCacheMsg_MarkAsForeignEntry, OnMarkAsForeignEntry)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(AppCacheMsg_GetStatus, OnGetStatus)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(AppCacheMsg_StartUpdate, OnStartUpdate)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(AppCacheMsg_SwapCache, OnSwapCache)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP_EX()
+
return handled;
}
+void AppCacheDispatcherHost::BadMessageReceived() {
+ UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_ACDH"));
+ BrowserMessageFilter::BadMessageReceived();
+}
+
void AppCacheDispatcherHost::OnRegisterHost(int host_id) {
if (appcache_service_.get()) {
if (!backend_impl_.RegisterHost(host_id)) {
- ReceivedBadMessage(AppCacheMsg_RegisterHost::ID);
+ BadMessageReceived();
}
}
}
@@ -89,7 +95,7 @@ void AppCacheDispatcherHost::OnRegisterHost(int host_id) {
void AppCacheDispatcherHost::OnUnregisterHost(int host_id) {
if (appcache_service_.get()) {
if (!backend_impl_.UnregisterHost(host_id)) {
- ReceivedBadMessage(AppCacheMsg_UnregisterHost::ID);
+ BadMessageReceived();
}
}
}
@@ -102,7 +108,7 @@ void AppCacheDispatcherHost::OnSelectCache(
if (!backend_impl_.SelectCache(host_id, document_url,
cache_document_was_loaded_from,
opt_manifest_url)) {
- ReceivedBadMessage(AppCacheMsg_SelectCache::ID);
+ BadMessageReceived();
}
} else {
frontend_proxy_.OnCacheSelected(host_id, appcache::AppCacheInfo());
@@ -114,7 +120,7 @@ void AppCacheDispatcherHost::OnSelectCacheForWorker(
if (appcache_service_.get()) {
if (!backend_impl_.SelectCacheForWorker(
host_id, parent_process_id, parent_host_id)) {
- ReceivedBadMessage(AppCacheMsg_SelectCacheForWorker::ID);
+ BadMessageReceived();
}
} else {
frontend_proxy_.OnCacheSelected(host_id, appcache::AppCacheInfo());
@@ -125,7 +131,7 @@ void AppCacheDispatcherHost::OnSelectCacheForSharedWorker(
int host_id, int64 appcache_id) {
if (appcache_service_.get()) {
if (!backend_impl_.SelectCacheForSharedWorker(host_id, appcache_id))
- ReceivedBadMessage(AppCacheMsg_SelectCacheForSharedWorker::ID);
+ BadMessageReceived();
} else {
frontend_proxy_.OnCacheSelected(host_id, appcache::AppCacheInfo());
}
@@ -137,7 +143,7 @@ void AppCacheDispatcherHost::OnMarkAsForeignEntry(
if (appcache_service_.get()) {
if (!backend_impl_.MarkAsForeignEntry(host_id, document_url,
cache_document_was_loaded_from)) {
- ReceivedBadMessage(AppCacheMsg_MarkAsForeignEntry::ID);
+ BadMessageReceived();
}
}
}
@@ -151,7 +157,7 @@ void AppCacheDispatcherHost::OnGetResourceList(
void AppCacheDispatcherHost::OnGetStatus(int host_id,
IPC::Message* reply_msg) {
if (pending_reply_msg_.get()) {
- ReceivedBadMessage(AppCacheMsg_GetStatus::ID);
+ BadMessageReceived();
delete reply_msg;
return;
}
@@ -160,7 +166,7 @@ void AppCacheDispatcherHost::OnGetStatus(int host_id,
if (appcache_service_.get()) {
if (!backend_impl_.GetStatusWithCallback(
host_id, get_status_callback_.get(), reply_msg)) {
- ReceivedBadMessage(AppCacheMsg_GetStatus::ID);
+ BadMessageReceived();
}
return;
}
@@ -171,7 +177,7 @@ void AppCacheDispatcherHost::OnGetStatus(int host_id,
void AppCacheDispatcherHost::OnStartUpdate(int host_id,
IPC::Message* reply_msg) {
if (pending_reply_msg_.get()) {
- ReceivedBadMessage(AppCacheMsg_StartUpdate::ID);
+ BadMessageReceived();
delete reply_msg;
return;
}
@@ -180,7 +186,7 @@ void AppCacheDispatcherHost::OnStartUpdate(int host_id,
if (appcache_service_.get()) {
if (!backend_impl_.StartUpdateWithCallback(
host_id, start_update_callback_.get(), reply_msg)) {
- ReceivedBadMessage(AppCacheMsg_StartUpdate::ID);
+ BadMessageReceived();
}
return;
}
@@ -191,7 +197,7 @@ void AppCacheDispatcherHost::OnStartUpdate(int host_id,
void AppCacheDispatcherHost::OnSwapCache(int host_id,
IPC::Message* reply_msg) {
if (pending_reply_msg_.get()) {
- ReceivedBadMessage(AppCacheMsg_SwapCache::ID);
+ BadMessageReceived();
delete reply_msg;
return;
}
@@ -200,7 +206,7 @@ void AppCacheDispatcherHost::OnSwapCache(int host_id,
if (appcache_service_.get()) {
if (!backend_impl_.SwapCacheWithCallback(
host_id, swap_cache_callback_.get(), reply_msg)) {
- ReceivedBadMessage(AppCacheMsg_SwapCache::ID);
+ BadMessageReceived();
}
return;
}
@@ -213,26 +219,19 @@ void AppCacheDispatcherHost::GetStatusCallback(
IPC::Message* reply_msg = reinterpret_cast<IPC::Message*>(param);
DCHECK(reply_msg == pending_reply_msg_.get());
AppCacheMsg_GetStatus::WriteReplyParams(reply_msg, status);
- frontend_proxy_.sender()->Send(pending_reply_msg_.release());
+ Send(pending_reply_msg_.release());
}
void AppCacheDispatcherHost::StartUpdateCallback(bool result, void* param) {
IPC::Message* reply_msg = reinterpret_cast<IPC::Message*>(param);
DCHECK(reply_msg == pending_reply_msg_.get());
AppCacheMsg_StartUpdate::WriteReplyParams(reply_msg, result);
- frontend_proxy_.sender()->Send(pending_reply_msg_.release());
+ Send(pending_reply_msg_.release());
}
void AppCacheDispatcherHost::SwapCacheCallback(bool result, void* param) {
IPC::Message* reply_msg = reinterpret_cast<IPC::Message*>(param);
DCHECK(reply_msg == pending_reply_msg_.get());
AppCacheMsg_SwapCache::WriteReplyParams(reply_msg, result);
- frontend_proxy_.sender()->Send(pending_reply_msg_.release());
-}
-
-void AppCacheDispatcherHost::ReceivedBadMessage(uint32 msg_type) {
- // TODO(michaeln): Consider gathering UMA stats
- // http://code.google.com/p/chromium/issues/detail?id=24634
- BrowserRenderProcessHost::BadMessageTerminateProcess(
- msg_type, receiver_->handle());
+ Send(pending_reply_msg_.release());
}
diff --git a/chrome/browser/appcache/appcache_dispatcher_host.h b/chrome/browser/appcache/appcache_dispatcher_host.h
index 23c7c77..3e2dbe9 100644
--- a/chrome/browser/appcache/appcache_dispatcher_host.h
+++ b/chrome/browser/appcache/appcache_dispatcher_host.h
@@ -12,6 +12,7 @@
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/appcache/appcache_frontend_proxy.h"
+#include "chrome/browser/browser_message_filter.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "ipc/ipc_message.h"
#include "webkit/appcache/appcache_backend_impl.h"
@@ -22,32 +23,30 @@ class URLRequestContextGetter;
// Handles appcache related messages sent to the main browser process from
// its child processes. There is a distinct host for each child process.
-// Messages are handled on the IO thread. The ResourceMessageFilter and
+// Messages are handled on the IO thread. The BrowserRenderProcessHost and
// WorkerProcessHost create an instance and delegates calls to it.
-class AppCacheDispatcherHost {
+class AppCacheDispatcherHost : public BrowserMessageFilter {
public:
// Constructor for use on the IO thread.
- explicit AppCacheDispatcherHost(
- URLRequestContext* request_context);
+ AppCacheDispatcherHost(URLRequestContext* request_context,
+ int process_id);
// Constructor for use on the UI thread.
- explicit AppCacheDispatcherHost(
- URLRequestContextGetter* request_context_getter);
+ AppCacheDispatcherHost(URLRequestContextGetter* request_context_getter,
+ int process_id);
~AppCacheDispatcherHost();
- void Initialize(ResourceDispatcherHost::Receiver* receiver);
- bool OnMessageReceived(const IPC::Message& msg, bool* msg_is_ok);
-
- int process_id() const { return backend_impl_.process_id(); }
-
- // Note: needed to satisfy ipc message dispatching macros.
- bool Send(IPC::Message* msg) {
- return frontend_proxy_.sender()->Send(msg);
- }
+ // BrowserIOMessageFilter implementation
+ virtual void OnChannelConnected(int32 peer_pid);
+ virtual bool OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok);
private:
- // Ipc message handlers
+ // BrowserMessageFilter override.
+ virtual void BadMessageReceived();
+
+ // IPC message handlers
void OnRegisterHost(int host_id);
void OnUnregisterHost(int host_id);
void OnSelectCache(int host_id, const GURL& document_url,
@@ -68,25 +67,26 @@ class AppCacheDispatcherHost {
void StartUpdateCallback(bool result, void* param);
void SwapCacheCallback(bool result, void* param);
- void ReceivedBadMessage(uint32 msg_type);
+ // This is only valid once Initialize() has been called. This MUST be defined
+ // before backend_impl_ since the latter maintains a (non-refcounted) pointer
+ // to it.
+ scoped_refptr<ChromeAppCacheService> appcache_service_;
AppCacheFrontendProxy frontend_proxy_;
appcache::AppCacheBackendImpl backend_impl_;
- // Temporary until Initialize() can be called from the IO thread,
+ // Temporary until OnChannelConnected() can be called from the IO thread,
// which will extract the AppCacheService from the URLRequestContext.
scoped_refptr<URLRequestContext> request_context_;
scoped_refptr<URLRequestContextGetter> request_context_getter_;
- // This is only valid once Initialize() has been called.
- scoped_refptr<ChromeAppCacheService> appcache_service_;
-
scoped_ptr<appcache::GetStatusCallback> get_status_callback_;
scoped_ptr<appcache::StartUpdateCallback> start_update_callback_;
scoped_ptr<appcache::SwapCacheCallback> swap_cache_callback_;
scoped_ptr<IPC::Message> pending_reply_msg_;
- ResourceDispatcherHost::Receiver* receiver_;
+ // The corresponding ChildProcessHost object's id().
+ int process_id_;
DISALLOW_COPY_AND_ASSIGN(AppCacheDispatcherHost);
};
diff --git a/chrome/browser/appcache/appcache_frontend_proxy.cc b/chrome/browser/appcache/appcache_frontend_proxy.cc
index 0a80424..c82cb57 100644
--- a/chrome/browser/appcache/appcache_frontend_proxy.cc
+++ b/chrome/browser/appcache/appcache_frontend_proxy.cc
@@ -6,6 +6,10 @@
#include "chrome/common/render_messages.h"
+AppCacheFrontendProxy::AppCacheFrontendProxy(IPC::Message::Sender* sender)
+ : sender_(sender) {
+}
+
void AppCacheFrontendProxy::OnCacheSelected(
int host_id, const appcache::AppCacheInfo& info) {
sender_->Send(new AppCacheMsg_CacheSelected(host_id, info));
diff --git a/chrome/browser/appcache/appcache_frontend_proxy.h b/chrome/browser/appcache/appcache_frontend_proxy.h
index 2d3775c..51e1f95 100644
--- a/chrome/browser/appcache/appcache_frontend_proxy.h
+++ b/chrome/browser/appcache/appcache_frontend_proxy.h
@@ -15,9 +15,7 @@
// Sends appcache related messages to a child process.
class AppCacheFrontendProxy : public appcache::AppCacheFrontend {
public:
- AppCacheFrontendProxy() : sender_(NULL) {}
- void set_sender(IPC::Message::Sender* sender) { sender_ = sender; }
- IPC::Message::Sender* sender() const { return sender_; }
+ explicit AppCacheFrontendProxy(IPC::Message::Sender* sender);
// AppCacheFrontend methods
virtual void OnCacheSelected(int host_id, const appcache::AppCacheInfo& info);
diff --git a/chrome/browser/appcache/appcache_ui_test.cc b/chrome/browser/appcache/appcache_ui_test.cc
index a4814cf..521cfd6 100644
--- a/chrome/browser/appcache/appcache_ui_test.cc
+++ b/chrome/browser/appcache/appcache_ui_test.cc
@@ -6,16 +6,32 @@
#include "chrome/test/ui/ui_layout_test.h"
class AppCacheUITest : public UILayoutTest {
+ public:
+ void RunAppCacheTests(const char* tests[], int num_tests) {
+ FilePath http_test_dir;
+ http_test_dir = http_test_dir.AppendASCII("http");
+ http_test_dir = http_test_dir.AppendASCII("tests");
+
+ FilePath appcache_test_dir;
+ appcache_test_dir = appcache_test_dir.AppendASCII("appcache");
+ InitializeForLayoutTest(http_test_dir, appcache_test_dir, kHttpPort);
+
+ StartHttpServer(new_http_root_dir_);
+ for (int i = 0; i < num_tests; ++i)
+ RunLayoutTest(tests[i], kHttpPort);
+ StopHttpServer();
+ }
+
protected:
virtual ~AppCacheUITest() {}
};
// Flaky: http://crbug.com/54717
-TEST_F(AppCacheUITest, FLAKY_AppCacheLayoutTests) {
- static const char* kLayoutTestFiles[] = {
+// The tests that don't depend on PHP should be less flaky.
+TEST_F(AppCacheUITest, FLAKY_AppCacheLayoutTests_NoPHP) {
+ static const char* kNoPHPTests[] = {
"404-manifest.html",
"404-resource.html",
- "auth.html",
"cyrillic-uri.html",
"deferred-events-delete-while-raising.html",
"deferred-events.html",
@@ -24,22 +40,14 @@ TEST_F(AppCacheUITest, FLAKY_AppCacheLayoutTests) {
"different-origin-manifest.html",
"different-scheme.html",
"empty-manifest.html",
- "fallback.html",
"foreign-iframe-main.html",
- "main-resource-hash.html",
+ "insert-html-element-with-manifest.html",
+ "insert-html-element-with-manifest-2.html",
"manifest-containing-itself.html",
"manifest-parsing.html",
- "manifest-redirect-2.html",
- "manifest-redirect.html",
"manifest-with-empty-file.html",
- "navigating-away-while-cache-attempt-in-progress.html",
- "offline-access.html",
- "online-whitelist.html",
"progress-counter.html",
"reload.html",
- "remove-cache.html",
- "resource-redirect-2.html",
- "resource-redirect.html",
"simple.html",
"top-frame-1.html",
"top-frame-2.html",
@@ -50,28 +58,46 @@ TEST_F(AppCacheUITest, FLAKY_AppCacheLayoutTests) {
"wrong-signature-2.html",
"wrong-signature.html",
"xhr-foreign-resource.html",
+ };
- // TODO(michaeln): investigate these more closely
- // "crash-when-navigating-away-then-back.html",
- // "credential-url.html",
- // "different-https-origin-resource-main.html",
- // "fail-on-update.html",
- // "idempotent-update.html", not sure this is a valid test
- // "local-content.html",
- // "max-size.html", we use a different quota scheme
- // "update-cache.html", bug 38006
+ // This test is racey.
+ // https://bugs.webkit.org/show_bug.cgi?id=49104
+ // "foreign-fallback.html"
+
+ RunAppCacheTests(kNoPHPTests, arraysize(kNoPHPTests));
+}
+
+// Flaky: http://crbug.com/54717
+// Lighty/PHP is not reliable enough on windows.
+TEST_F(AppCacheUITest, FLAKY_AppCacheLayoutTests_PHP) {
+ static const char* kPHPTests[] = {
+ "auth.html",
+ "fallback.html",
+ "main-resource-hash.html",
+ "manifest-redirect.html",
+ "manifest-redirect-2.html",
+ "navigating-away-while-cache-attempt-in-progress.html",
+ "non-html.xhtml",
+ "offline-access.html",
+ "online-whitelist.html",
+ "resource-redirect.html",
+ "resource-redirect-2.html",
+ "update-cache.html",
};
- FilePath http_test_dir;
- http_test_dir = http_test_dir.AppendASCII("http");
- http_test_dir = http_test_dir.AppendASCII("tests");
+ // These tests are racey due to status polling on timers.
+ // https://bugs.webkit.org/show_bug.cgi?id=49104
+ // "fail-on-update.html",
+ // "fail-on-update2.html",
+ // "remove-cache.html",
- FilePath appcache_test_dir;
- appcache_test_dir = appcache_test_dir.AppendASCII("appcache");
- InitializeForLayoutTest(http_test_dir, appcache_test_dir, kHttpPort);
+ // TODO(michaeln): investigate these more closely
+ // "crash-when-navigating-away-then-back.html",
+ // "credential-url.html",
+ // "different-https-origin-resource-main.html",
+ // "idempotent-update.html", not sure this is a valid test
+ // "local-content.html",
+ // "max-size.html", we use a different quota scheme
- StartHttpServer(new_http_root_dir_);
- for (size_t i = 0; i < arraysize(kLayoutTestFiles); ++i)
- RunLayoutTest(kLayoutTestFiles[i], kHttpPort);
- StopHttpServer();
+ RunAppCacheTests(kPHPTests, arraysize(kPHPTests));
}
diff --git a/chrome/browser/appcache/chrome_appcache_service.h b/chrome/browser/appcache/chrome_appcache_service.h
index aade722..dbc0616 100644
--- a/chrome/browser/appcache/chrome_appcache_service.h
+++ b/chrome/browser/appcache/chrome_appcache_service.h
@@ -8,7 +8,7 @@
#include "base/ref_counted.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/host_content_settings_map.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/common/notification_registrar.h"
#include "webkit/appcache/appcache_policy.h"
#include "webkit/appcache/appcache_service.h"
diff --git a/chrome/browser/appcache/view_appcache_internals_job_factory.cc b/chrome/browser/appcache/view_appcache_internals_job_factory.cc
index 6bd384d..99ef75f 100644
--- a/chrome/browser/appcache/view_appcache_internals_job_factory.cc
+++ b/chrome/browser/appcache/view_appcache_internals_job_factory.cc
@@ -18,12 +18,11 @@ bool ViewAppCacheInternalsJobFactory::IsSupportedURL(const GURL& url) {
}
// static.
-URLRequestJob* ViewAppCacheInternalsJobFactory::CreateJobForRequest(
- URLRequest* request) {
+net::URLRequestJob* ViewAppCacheInternalsJobFactory::CreateJobForRequest(
+ net::URLRequest* request) {
URLRequestContext* context = request->context();
ChromeURLRequestContext* chrome_request_context =
reinterpret_cast<ChromeURLRequestContext*>(context);
return new appcache::ViewAppCacheInternalsJob(
request, chrome_request_context->appcache_service());
}
-
diff --git a/chrome/browser/autocomplete/autocomplete.cc b/chrome/browser/autocomplete/autocomplete.cc
index c6e700d..6bb8ad2 100644
--- a/chrome/browser/autocomplete/autocomplete.cc
+++ b/chrome/browser/autocomplete/autocomplete.cc
@@ -24,7 +24,7 @@
#include "chrome/browser/external_protocol_handler.h"
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
@@ -68,19 +68,17 @@ AutocompleteInput::AutocompleteInput(const std::wstring& text,
if (TrimWhitespace(text, TRIM_ALL, &text_) & TRIM_TRAILING)
prevent_inline_autocomplete_ = true;
- type_ = Parse(text_, desired_tld, &parts_, &scheme_);
+ GURL canonicalized_url;
+ type_ = Parse(text_, desired_tld, &parts_, &scheme_, &canonicalized_url);
if (type_ == INVALID)
return;
- if ((type_ == UNKNOWN) || (type_ == REQUESTED_URL) || (type_ == URL)) {
- GURL canonicalized_url(URLFixerUpper::FixupURL(WideToUTF8(text_),
- WideToUTF8(desired_tld_)));
- if (canonicalized_url.is_valid() &&
- (!canonicalized_url.IsStandard() || canonicalized_url.SchemeIsFile() ||
- !canonicalized_url.host().empty()))
- canonicalized_url_ = canonicalized_url;
- }
+ if (((type_ == UNKNOWN) || (type_ == REQUESTED_URL) || (type_ == URL)) &&
+ canonicalized_url.is_valid() &&
+ (!canonicalized_url.IsStandard() || canonicalized_url.SchemeIsFile() ||
+ !canonicalized_url.host().empty()))
+ canonicalized_url_ = canonicalized_url;
RemoveForcedQueryStringIfNecessary(type_, &text_);
}
@@ -116,7 +114,8 @@ AutocompleteInput::Type AutocompleteInput::Parse(
const std::wstring& text,
const std::wstring& desired_tld,
url_parse::Parsed* parts,
- std::wstring* scheme) {
+ std::wstring* scheme,
+ GURL* canonicalized_url) {
const size_t first_non_white = text.find_first_not_of(kWhitespaceWide, 0);
if (first_non_white == std::wstring::npos)
return INVALID; // All whitespace.
@@ -137,6 +136,10 @@ AutocompleteInput::Type AutocompleteInput::Parse(
const std::wstring parsed_scheme(URLFixerUpper::SegmentURL(text, parts));
if (scheme)
*scheme = parsed_scheme;
+ if (canonicalized_url) {
+ *canonicalized_url = URLFixerUpper::FixupURL(WideToUTF8(text),
+ WideToUTF8(desired_tld));
+ }
if (parsed_scheme == L"file") {
// A user might or might not type a scheme when entering a file URL. In
@@ -154,22 +157,23 @@ AutocompleteInput::Type AutocompleteInput::Parse(
if (parts->scheme.is_nonempty() &&
(parsed_scheme != L"http") && (parsed_scheme != L"https")) {
// See if we know how to handle the URL internally.
- if (URLRequest::IsHandledProtocol(WideToASCII(parsed_scheme)))
+ if (net::URLRequest::IsHandledProtocol(WideToASCII(parsed_scheme)))
return URL;
// There are also some schemes that we convert to other things before they
// reach the renderer or else the renderer handles internally without
- // reaching the URLRequest logic. We thus won't catch these above, but we
- // should still claim to handle them.
+ // reaching the net::URLRequest logic. We thus won't catch these above, but
+ // we should still claim to handle them.
if (LowerCaseEqualsASCII(parsed_scheme, chrome::kViewSourceScheme) ||
LowerCaseEqualsASCII(parsed_scheme, chrome::kJavaScriptScheme) ||
LowerCaseEqualsASCII(parsed_scheme, chrome::kDataScheme))
return URL;
// Finally, check and see if the user has explicitly opened this scheme as
- // a URL before. We need to do this last because some schemes may be in
- // here as "blocked" (e.g. "javascript") because we don't want pages to open
- // them, but users still can.
+ // a URL before, or if the "scheme" is actually a username. We need to do
+ // this last because some schemes (e.g. "javascript") may be treated as
+ // "blocked" by the external protocol handler because we don't want pages to
+ // open them, but users still can.
// TODO(viettrungluu): get rid of conversion.
switch (ExternalProtocolHandler::GetBlockState(WideToUTF8(parsed_scheme))) {
case ExternalProtocolHandler::DONT_BLOCK:
@@ -180,13 +184,55 @@ AutocompleteInput::Type AutocompleteInput::Parse(
// to at all.
return QUERY;
- default:
- // We don't know about this scheme. It's likely to be a search operator
+ default: {
+ // We don't know about this scheme. It might be that the user typed a
+ // URL of the form "username:password@foo.com".
+ const std::wstring http_scheme_prefix = L"http://";
+ url_parse::Parsed http_parts;
+ std::wstring http_scheme;
+ GURL http_canonicalized_url;
+ Type http_type = Parse(http_scheme_prefix + text, desired_tld,
+ &http_parts, &http_scheme,
+ &http_canonicalized_url);
+ DCHECK_EQ("http", WideToUTF8(http_scheme));
+
+ if ((http_type == URL || http_type == REQUESTED_URL) &&
+ http_parts.username.is_nonempty() &&
+ http_parts.password.is_nonempty()) {
+ // Manually re-jigger the parsed parts to match |text| (without the
+ // http scheme added).
+ http_parts.scheme.reset();
+ url_parse::Component* components[] = {
+ &http_parts.username,
+ &http_parts.password,
+ &http_parts.host,
+ &http_parts.port,
+ &http_parts.path,
+ &http_parts.query,
+ &http_parts.ref,
+ };
+ for (size_t i = 0; i < arraysize(components); ++i) {
+ URLFixerUpper::OffsetComponent(
+ -static_cast<int>(http_scheme_prefix.size()), components[i]);
+ }
+
+ *parts = http_parts;
+ if (scheme)
+ scheme->clear();
+ if (canonicalized_url)
+ *canonicalized_url = http_canonicalized_url;
+
+ return http_type;
+ }
+
+ // We don't know about this scheme and it doesn't look like the user
+ // typed a username and password. It's likely to be a search operator
// like "site:" or "link:". We classify it as UNKNOWN so the user has
// the option of treating it as a URL if we're wrong.
// Note that SegmentURL() is smart so we aren't tricked by "c:\foo" or
// "www.example.com:81" in this case.
return UNKNOWN;
+ }
}
}
@@ -352,7 +398,7 @@ void AutocompleteInput::ParseForEmphasizeComponents(
url_parse::Component* host) {
url_parse::Parsed parts;
std::wstring scheme_str;
- Parse(text, desired_tld, &parts, &scheme_str);
+ Parse(text, desired_tld, &parts, &scheme_str, NULL);
*scheme = parts.scheme;
*host = parts.host;
@@ -365,7 +411,7 @@ void AutocompleteInput::ParseForEmphasizeComponents(
// Obtain the URL prefixed by view-source and parse it.
std::wstring real_url(text.substr(after_scheme_and_colon));
url_parse::Parsed real_parts;
- AutocompleteInput::Parse(real_url, desired_tld, &real_parts, NULL);
+ AutocompleteInput::Parse(real_url, desired_tld, &real_parts, NULL, NULL);
if (real_parts.scheme.is_nonempty() || real_parts.host.is_nonempty()) {
if (real_parts.scheme.is_nonempty()) {
*scheme = url_parse::Component(
@@ -392,8 +438,10 @@ std::wstring AutocompleteInput::FormattedStringWithEquivalentMeaning(
if (!net::CanStripTrailingSlash(url))
return formatted_url;
const std::wstring url_with_path(formatted_url + L"/");
- return (AutocompleteInput::Parse(formatted_url, std::wstring(), NULL, NULL) ==
- AutocompleteInput::Parse(url_with_path, std::wstring(), NULL, NULL)) ?
+ return (AutocompleteInput::Parse(formatted_url, std::wstring(), NULL, NULL,
+ NULL) ==
+ AutocompleteInput::Parse(url_with_path, std::wstring(), NULL, NULL,
+ NULL)) ?
formatted_url : url_with_path;
}
diff --git a/chrome/browser/autocomplete/autocomplete.h b/chrome/browser/autocomplete/autocomplete.h
index 8388265..f91dbab 100644
--- a/chrome/browser/autocomplete/autocomplete.h
+++ b/chrome/browser/autocomplete/autocomplete.h
@@ -196,11 +196,14 @@ class AutocompleteInput {
// Parses |text| and returns the type of input this will be interpreted as.
// The components of the input are stored in the output parameter |parts|, if
- // it is non-NULL.
+ // it is non-NULL. The scheme is stored in |scheme| if it is non-NULL. The
+ // canonicalized URL is stored in |canonicalized_url|; however, this URL is
+ // not guaranteed to be valid, especially if the parsed type is, e.g., QUERY.
static Type Parse(const std::wstring& text,
const std::wstring& desired_tld,
url_parse::Parsed* parts,
- std::wstring* scheme);
+ std::wstring* scheme,
+ GURL* canonicalized_url);
// Parses |text| and fill |scheme| and |host| by the positions of them.
// The results are almost as same as the result of Parse(), but if the scheme
diff --git a/chrome/browser/autocomplete/autocomplete_browsertest.cc b/chrome/browser/autocomplete/autocomplete_browsertest.cc
index 2828353..1d695d2 100644
--- a/chrome/browser/autocomplete/autocomplete_browsertest.cc
+++ b/chrome/browser/autocomplete/autocomplete_browsertest.cc
@@ -11,11 +11,10 @@
#include "chrome/browser/autocomplete/autocomplete_popup_model.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/history/history.h"
-#include "chrome/browser/location_bar.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/omnibox/location_bar.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/in_process_browser_test.h"
@@ -62,7 +61,7 @@ class AutocompleteBrowserTest : public InProcessBrowserTest {
IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, Basic) {
LocationBar* location_bar = GetLocationBar();
- EXPECT_EQ(std::wstring(), location_bar->GetInputString());
+ EXPECT_TRUE(location_bar->GetInputString().empty());
EXPECT_EQ(UTF8ToWide(chrome::kAboutBlankURL),
location_bar->location_entry()->GetText());
// TODO(phajdan.jr): check state of IsSelectAll when it's consistent across
@@ -70,20 +69,20 @@ IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, Basic) {
location_bar->FocusLocation(true);
- EXPECT_EQ(std::wstring(), location_bar->GetInputString());
+ EXPECT_TRUE(location_bar->GetInputString().empty());
EXPECT_EQ(UTF8ToWide(chrome::kAboutBlankURL),
location_bar->location_entry()->GetText());
EXPECT_TRUE(location_bar->location_entry()->IsSelectAll());
location_bar->location_entry()->SetUserText(L"chrome");
- EXPECT_EQ(std::wstring(), location_bar->GetInputString());
+ EXPECT_TRUE(location_bar->GetInputString().empty());
EXPECT_EQ(L"chrome", location_bar->location_entry()->GetText());
EXPECT_FALSE(location_bar->location_entry()->IsSelectAll());
location_bar->location_entry()->RevertAll();
- EXPECT_EQ(std::wstring(), location_bar->GetInputString());
+ EXPECT_TRUE(location_bar->GetInputString().empty());
EXPECT_EQ(UTF8ToWide(chrome::kAboutBlankURL),
location_bar->location_entry()->GetText());
EXPECT_FALSE(location_bar->location_entry()->IsSelectAll());
@@ -91,7 +90,7 @@ IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, Basic) {
location_bar->location_entry()->SetUserText(L"chrome");
location_bar->Revert();
- EXPECT_EQ(std::wstring(), location_bar->GetInputString());
+ EXPECT_TRUE(location_bar->GetInputString().empty());
EXPECT_EQ(UTF8ToWide(chrome::kAboutBlankURL),
location_bar->location_entry()->GetText());
EXPECT_FALSE(location_bar->location_entry()->IsSelectAll());
@@ -110,8 +109,8 @@ IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, MAYBE_Autocomplete) {
true, false, true, true);
EXPECT_TRUE(autocomplete_controller->done());
- EXPECT_EQ(std::wstring(), location_bar->GetInputString());
- EXPECT_EQ(std::wstring(), location_bar->location_entry()->GetText());
+ EXPECT_TRUE(location_bar->GetInputString().empty());
+ EXPECT_TRUE(location_bar->location_entry()->GetText().empty());
EXPECT_TRUE(location_bar->location_entry()->IsSelectAll());
const AutocompleteResult& result = autocomplete_controller->result();
ASSERT_EQ(1U, result.size()) << AutocompleteResultAsString(result);
@@ -123,7 +122,7 @@ IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, MAYBE_Autocomplete) {
{
location_bar->Revert();
- EXPECT_EQ(std::wstring(), location_bar->GetInputString());
+ EXPECT_TRUE(location_bar->GetInputString().empty());
EXPECT_EQ(UTF8ToWide(chrome::kAboutBlankURL),
location_bar->location_entry()->GetText());
EXPECT_FALSE(location_bar->location_entry()->IsSelectAll());
@@ -157,12 +156,12 @@ IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, FocusSearch) {
// Focus search when omnibox is blank
{
- EXPECT_EQ(std::wstring(), location_bar->GetInputString());
+ EXPECT_TRUE(location_bar->GetInputString().empty());
EXPECT_EQ(UTF8ToWide(chrome::kAboutBlankURL),
location_bar->location_entry()->GetText());
location_bar->FocusSearch();
- EXPECT_EQ(std::wstring(), location_bar->GetInputString());
+ EXPECT_TRUE(location_bar->GetInputString().empty());
EXPECT_EQ(L"?", location_bar->location_entry()->GetText());
size_t selection_start, selection_end;
@@ -175,11 +174,11 @@ IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, FocusSearch) {
// Focus search when omnibox is _not_ alread in forced query mode.
{
location_bar->location_entry()->SetUserText(L"foo");
- EXPECT_EQ(std::wstring(), location_bar->GetInputString());
+ EXPECT_TRUE(location_bar->GetInputString().empty());
EXPECT_EQ(L"foo", location_bar->location_entry()->GetText());
location_bar->FocusSearch();
- EXPECT_EQ(std::wstring(), location_bar->GetInputString());
+ EXPECT_TRUE(location_bar->GetInputString().empty());
EXPECT_EQ(L"?", location_bar->location_entry()->GetText());
size_t selection_start, selection_end;
@@ -193,11 +192,11 @@ IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, FocusSearch) {
// has been typed.
{
location_bar->location_entry()->SetUserText(L"?");
- EXPECT_EQ(std::wstring(), location_bar->GetInputString());
+ EXPECT_TRUE(location_bar->GetInputString().empty());
EXPECT_EQ(L"?", location_bar->location_entry()->GetText());
location_bar->FocusSearch();
- EXPECT_EQ(std::wstring(), location_bar->GetInputString());
+ EXPECT_TRUE(location_bar->GetInputString().empty());
EXPECT_EQ(L"?", location_bar->location_entry()->GetText());
size_t selection_start, selection_end;
@@ -211,11 +210,11 @@ IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, FocusSearch) {
// has been typed.
{
location_bar->location_entry()->SetUserText(L"?foo");
- EXPECT_EQ(std::wstring(), location_bar->GetInputString());
+ EXPECT_TRUE(location_bar->GetInputString().empty());
EXPECT_EQ(L"?foo", location_bar->location_entry()->GetText());
location_bar->FocusSearch();
- EXPECT_EQ(std::wstring(), location_bar->GetInputString());
+ EXPECT_TRUE(location_bar->GetInputString().empty());
EXPECT_EQ(L"?foo", location_bar->location_entry()->GetText());
size_t selection_start, selection_end;
@@ -228,11 +227,11 @@ IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, FocusSearch) {
// Focus search when omnibox is in forced query mode with leading whitespace.
{
location_bar->location_entry()->SetUserText(L" ?foo");
- EXPECT_EQ(std::wstring(), location_bar->GetInputString());
+ EXPECT_TRUE(location_bar->GetInputString().empty());
EXPECT_EQ(L" ?foo", location_bar->location_entry()->GetText());
location_bar->FocusSearch();
- EXPECT_EQ(std::wstring(), location_bar->GetInputString());
+ EXPECT_TRUE(location_bar->GetInputString().empty());
EXPECT_EQ(L" ?foo", location_bar->location_entry()->GetText());
size_t selection_start, selection_end;
diff --git a/chrome/browser/autocomplete/autocomplete_edit.cc b/chrome/browser/autocomplete/autocomplete_edit.cc
index af364d3..68cdc82 100644
--- a/chrome/browser/autocomplete/autocomplete_edit.cc
+++ b/chrome/browser/autocomplete/autocomplete_edit.cc
@@ -24,7 +24,7 @@
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/net/predictor_api.h"
#include "chrome/browser/net/url_fixer_upper.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/common/notification_service.h"
@@ -178,9 +178,16 @@ void AutocompleteEditModel::GetDataForURLExport(GURL* url,
}
bool AutocompleteEditModel::UseVerbatimInstant() {
+#if defined(OS_MACOSX)
+ // TODO(suzhe): Fix Mac port to display Instant suggest in a separated NSView,
+ // so that we can display instant suggest along with composition text.
const AutocompleteInput& input = popup_->autocomplete_controller()->input();
- if (input.initial_prevent_inline_autocomplete() ||
- view_->DeleteAtEndPressed() || (popup_->selected_line() != 0))
+ if (input.initial_prevent_inline_autocomplete())
+ return true;
+#endif
+
+ if (view_->DeleteAtEndPressed() || (popup_->selected_line() != 0) ||
+ just_deleted_text_)
return true;
std::wstring::size_type start, end;
@@ -225,17 +232,6 @@ AutocompleteMatch::Type AutocompleteEditModel::CurrentTextType() const {
return match.type;
}
-bool AutocompleteEditModel::GetURLForText(const std::wstring& text,
- GURL* url) const {
- const AutocompleteInput::Type type = AutocompleteInput::Parse(
- UserTextFromDisplayText(text), std::wstring(), NULL, NULL);
- if (type != AutocompleteInput::URL)
- return false;
-
- *url = URLFixerUpper::FixupURL(WideToUTF8(text), std::string());
- return true;
-}
-
void AutocompleteEditModel::AdjustTextForCopy(int sel_min,
bool is_all_selected,
std::wstring* text,
@@ -794,6 +790,18 @@ void AutocompleteEditModel::GetInfoForCurrentText(
}
}
+bool AutocompleteEditModel::GetURLForText(const std::wstring& text,
+ GURL* url) const {
+ GURL parsed_url;
+ const AutocompleteInput::Type type = AutocompleteInput::Parse(
+ UserTextFromDisplayText(text), std::wstring(), NULL, NULL, &parsed_url);
+ if (type != AutocompleteInput::URL)
+ return false;
+
+ *url = parsed_url;
+ return true;
+}
+
// Returns true if suggested search text should be shown for the specified match
// type.
static bool ShouldShowSuggestSearchTextFor(AutocompleteMatch::Type type) {
diff --git a/chrome/browser/autocomplete/autocomplete_edit.h b/chrome/browser/autocomplete/autocomplete_edit.h
index 983a5f5..da0625e 100644
--- a/chrome/browser/autocomplete/autocomplete_edit.h
+++ b/chrome/browser/autocomplete/autocomplete_edit.h
@@ -52,7 +52,7 @@ class AutocompleteEditController {
// Accepts the currently showing instant preview, if any, and returns true.
// Returns false if there is no instant preview showing.
- virtual bool AcceptCurrentInstantPreview() { return false; }
+ virtual bool AcceptCurrentInstantPreview() = 0;
// Sets the suggested search text to |suggested_text|.
virtual void OnSetSuggestedSearchText(const string16& suggested_text) = 0;
@@ -179,14 +179,6 @@ class AutocompleteEditModel : public NotificationObserver {
// Returns the match type for the current edit contents.
AutocompleteMatch::Type CurrentTextType() const;
- // Returns true if |text| (which is display text in the current context)
- // parses as a URL, and in that case sets |url| to the calculated URL.
- // Subtle note: This ignores the desired_tld_ (unlike GetDataForURLExport()
- // and CurrentTextIsURL()). The view needs this because it calls this
- // function during copy handling, when the control key is down to trigger the
- // copy.
- bool GetURLForText(const std::wstring& text, GURL* url) const;
-
// Invoked to adjust the text before writting to the clipboard for a copy
// (e.g. by adding 'http' to the front). |sel_min| gives the minimum position
// of the selection e.g. min(selection_start, selection_end). |text| is the
@@ -391,6 +383,14 @@ class AutocompleteEditModel : public NotificationObserver {
void GetInfoForCurrentText(AutocompleteMatch* match,
GURL* alternate_nav_url) const;
+ // Returns true if |text| (which is display text in the current context)
+ // parses as a URL, and in that case sets |url| to the calculated URL.
+ // Subtle note: This ignores the desired_tld_ (unlike GetDataForURLExport()
+ // and CurrentTextIsURL()). The view needs this because it calls this
+ // function during copy handling, when the control key is down to trigger the
+ // copy.
+ bool GetURLForText(const std::wstring& text, GURL* url) const;
+
// Determines the suggested search text and invokes OnSetSuggestedSearchText
// on the controller.
void UpdateSuggestedSearchText();
diff --git a/chrome/browser/autocomplete/autocomplete_edit_unittest.cc b/chrome/browser/autocomplete/autocomplete_edit_unittest.cc
index d70d07f..7dedb98 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_unittest.cc
+++ b/chrome/browser/autocomplete/autocomplete_edit_unittest.cc
@@ -68,6 +68,9 @@ class TestingAutocompleteEditController : public AutocompleteEditController {
virtual bool OnCommitSuggestedText(const std::wstring& typed_text) {
return false;
}
+ virtual bool AcceptCurrentInstantPreview() {
+ return false;
+ }
virtual void OnSetSuggestedSearchText(const string16& suggested_text) {}
virtual void OnPopupBoundsChanged(const gfx::Rect& bounds) {}
virtual void OnAutocompleteAccept(const GURL& url,
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_browsertest.cc b/chrome/browser/autocomplete/autocomplete_edit_view_browsertest.cc
index 584b3a5..3a5b68b 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_view_browsertest.cc
+++ b/chrome/browser/autocomplete/autocomplete_edit_view_browsertest.cc
@@ -19,12 +19,12 @@
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/history/history.h"
-#include "chrome/browser/location_bar.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/omnibox/location_bar.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc
index ffc8f1c..e450e70 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc
+++ b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc
@@ -19,7 +19,6 @@
#include "chrome/browser/autocomplete/autocomplete_match.h"
#include "chrome/browser/autocomplete/autocomplete_popup_model.h"
#include "chrome/browser/bookmarks/bookmark_node_data.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/command_updater.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/gtk/gtk_util.h"
@@ -27,7 +26,7 @@
#include "chrome/browser/instant/instant_controller.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/toolbar_model.h"
+#include "chrome/browser/ui/toolbar/toolbar_model.h"
#include "chrome/common/notification_service.h"
#include "gfx/color_utils.h"
#include "gfx/font.h"
@@ -187,6 +186,11 @@ AutocompleteEditViewGtk::AutocompleteEditViewGtk(
selection_suggested_(false),
delete_was_pressed_(false),
delete_at_end_pressed_(false),
+ handling_key_press_(false),
+ content_maybe_changed_by_key_press_(false),
+#if GTK_CHECK_VERSION(2, 20, 0)
+ preedit_size_before_change_(0),
+#endif
going_to_focus_(NULL) {
model_->SetPopupModel(popup_view_->GetModel());
}
@@ -434,10 +438,22 @@ int AutocompleteEditViewGtk::TextWidth() {
&start, &first_char_bounds);
gtk_text_view_get_iter_location(GTK_TEXT_VIEW(text_view_),
&end, &last_char_bounds);
- return ((last_char_bounds.x > first_char_bounds.x) ?
- (last_char_bounds.x + last_char_bounds.width - first_char_bounds.x) :
- (first_char_bounds.x - last_char_bounds.x + last_char_bounds.width)) +
- horizontal_border_size;
+
+ gint first_char_start = first_char_bounds.x;
+ gint first_char_end = first_char_start + first_char_bounds.width;
+ gint last_char_start = last_char_bounds.x;
+ gint last_char_end = last_char_start + last_char_bounds.width;
+
+ // bounds width could be negative for RTL text.
+ if (first_char_start > first_char_end)
+ std::swap(first_char_start, first_char_end);
+ if (last_char_start > last_char_end)
+ std::swap(last_char_start, last_char_end);
+
+ gint text_width = first_char_start < last_char_start ?
+ last_char_end - first_char_start : first_char_end - last_char_start;
+
+ return text_width + horizontal_border_size;
}
int AutocompleteEditViewGtk::WidthOfTextAfterCursor() {
@@ -451,6 +467,14 @@ gfx::Font AutocompleteEditViewGtk::GetFont() {
rc_style->font_desc : text_view_->style->font_desc);
}
+AutocompleteEditModel* AutocompleteEditViewGtk::model() {
+ return model_.get();
+}
+
+const AutocompleteEditModel* AutocompleteEditViewGtk::model() const {
+ return model_.get();
+}
+
void AutocompleteEditViewGtk::SaveStateToTab(TabContents* tab) {
DCHECK(tab);
// If any text has been selected, register it as the PRIMARY selection so it
@@ -665,6 +689,12 @@ void AutocompleteEditViewGtk::OnRevertTemporaryText() {
}
void AutocompleteEditViewGtk::OnBeforePossibleChange() {
+ // This method will be called in HandleKeyPress() method just before
+ // handling a key press event. So we should prevent it from being called
+ // when handling the key press event.
+ if (handling_key_press_)
+ return;
+
// If this change is caused by a paste clipboard action and all text is
// selected, then call model_->on_paste_replacing_all() to prevent inline
// autocomplete.
@@ -677,10 +707,21 @@ void AutocompleteEditViewGtk::OnBeforePossibleChange() {
// Record our state.
text_before_change_ = GetText();
sel_before_change_ = GetSelection();
+#if GTK_CHECK_VERSION(2, 20, 0)
+ preedit_size_before_change_ = preedit_.size();
+#endif
}
// TODO(deanm): This is mostly stolen from Windows, and will need some work.
bool AutocompleteEditViewGtk::OnAfterPossibleChange() {
+ // This method will be called in HandleKeyPress() method just after
+ // handling a key press event. So we should prevent it from being called
+ // when handling the key press event.
+ if (handling_key_press_) {
+ content_maybe_changed_by_key_press_ = true;
+ return false;
+ }
+
// If the change is caused by an Enter key press event, and the event was not
// handled by IME, then it's an unexpected change and shall be reverted here.
// {Start|Finish}UpdatingHighlightedText() are called here to prevent the
@@ -701,6 +742,10 @@ bool AutocompleteEditViewGtk::OnAfterPossibleChange() {
// See if the text or selection have changed since OnBeforePossibleChange().
std::wstring new_text(GetText());
text_changed_ = (new_text != text_before_change_);
+#if GTK_CHECK_VERSION(2, 20, 0)
+ text_changed_ =
+ text_changed_ || (preedit_.size() != preedit_size_before_change_);
+#endif
if (text_changed_)
AdjustTextJustification();
@@ -849,12 +894,17 @@ void AutocompleteEditViewGtk::SetBaseColor() {
}
void AutocompleteEditViewGtk::UpdateInstantViewColors() {
-#if !defined(TOOLKIT_VIEWS)
SkColor selection_text, selection_bg;
GdkColor faded_text, normal_bg;
- if (theme_provider_->UseGtkTheme()) {
- GtkStyle* style = gtk_rc_get_style(text_view_);
+#if defined(TOOLKIT_VIEWS)
+ bool use_gtk = false;
+#else
+ bool use_gtk = theme_provider_->UseGtkTheme();
+#endif
+
+ if (use_gtk) {
+ GtkStyle* style = gtk_rc_get_style(instant_view_);
faded_text = gtk_util::AverageColors(
style->text[GTK_STATE_NORMAL], style->base[GTK_STATE_NORMAL]);
@@ -864,12 +914,23 @@ void AutocompleteEditViewGtk::UpdateInstantViewColors() {
selection_bg = gfx::GdkColorToSkColor(style->base[GTK_STATE_SELECTED]);
} else {
gdk_color_parse(kTextBaseColor, &faded_text);
- normal_bg = LocationBarViewGtk::kBackgroundColor;
+#if defined(TOOLKIT_VIEWS)
+ normal_bg = gfx::SkColorToGdkColor(
+ LocationBarView::GetColor(ToolbarModel::NONE,
+ LocationBarView::BACKGROUND));
+ selection_text = LocationBarView::GetColor(
+ ToolbarModel::NONE, LocationBarView::SELECTED_TEXT);
+
+ GtkStyle* style = gtk_rc_get_style(instant_view_);
+ selection_bg = gfx::GdkColorToSkColor(style->base[GTK_STATE_SELECTED]);
+#else
+ normal_bg = LocationBarViewGtk::kBackgroundColor;
selection_text =
theme_provider_->get_active_selection_fg_color();
selection_bg =
theme_provider_->get_active_selection_bg_color();
+#endif
}
double alpha = instant_animation_->is_animating() ?
@@ -893,9 +954,6 @@ void AutocompleteEditViewGtk::UpdateInstantViewColors() {
// is NORMAL, and the background is transparent.
gtk_widget_modify_fg(instant_view_, GTK_STATE_NORMAL, &text);
}
-#else // defined(TOOLKIT_VIEWS)
- // We don't worry about views because it doesn't use the instant view.
-#endif
}
void AutocompleteEditViewGtk::HandleBeginUserAction(GtkTextBuffer* sender) {
@@ -988,11 +1046,19 @@ gboolean AutocompleteEditViewGtk::HandleKeyPress(GtkWidget* widget,
// Reset |text_changed_| before passing the key event on to the text view.
text_changed_ = false;
+ OnBeforePossibleChange();
+ handling_key_press_ = true;
+ content_maybe_changed_by_key_press_ = false;
+
// Call the default handler, so that IME can work as normal.
// New line characters will be filtered out by our "insert-text"
// signal handler attached to |text_buffer_| object.
gboolean result = klass->key_press_event(widget, event);
+ handling_key_press_ = false;
+ if (content_maybe_changed_by_key_press_)
+ OnAfterPossibleChange();
+
// Set |tab_was_pressed_| to false, to make sure Tab to search behavior can
// only be triggered by pressing Tab key.
tab_was_pressed_ = false;
@@ -1173,39 +1239,45 @@ void AutocompleteEditViewGtk::HandleViewMoveCursor(
GtkTextIter sel_start, sel_end;
gboolean has_selection =
gtk_text_buffer_get_selection_bounds(text_buffer_, &sel_start, &sel_end);
+ bool handled = false;
- bool handled = true;
-
- // We want the GtkEntry behavior when you move the cursor while you have a
- // selection. GtkTextView just drops the selection and moves the cursor, but
- // instead we want to move the cursor to the appropiate end of the selection.
- if (step == GTK_MOVEMENT_VISUAL_POSITIONS && !extend_selection) {
- if ((count == 1 || count == -1) && has_selection) {
+ if (step == GTK_MOVEMENT_VISUAL_POSITIONS && !extend_selection &&
+ (count == 1 || count == -1)) {
+ gint cursor_pos;
+ g_object_get(G_OBJECT(text_buffer_), "cursor-position", &cursor_pos, NULL);
+
+ // We need to take the content direction into account when handling cursor
+ // movement, because the behavior of Left and Right key will be inverted if
+ // the direction is RTL. Although we should check the direction around the
+ // input caret, it's much simpler and good enough to check whole content's
+ // direction.
+ PangoDirection content_dir = GetContentDirection();
+ gint count_towards_end = content_dir == PANGO_DIRECTION_RTL ? -1 : 1;
+
+ // We want the GtkEntry behavior when you move the cursor while you have a
+ // selection. GtkTextView just drops the selection and moves the cursor,
+ // but instead we want to move the cursor to the appropiate end of the
+ // selection.
+ if (has_selection) {
// We have a selection and start / end are in ascending order.
- // Cursor placement will remove the selection, so we need inform |model_|
- // about this change by calling On{Before|After}PossibleChange() methods.
+ // Cursor placement will remove the selection, so we need inform
+ // |model_| about this change by
+ // calling On{Before|After}PossibleChange() methods.
OnBeforePossibleChange();
- gtk_text_buffer_place_cursor(text_buffer_,
- count == 1 ? &sel_end : &sel_start);
+ gtk_text_buffer_place_cursor(
+ text_buffer_, count == count_towards_end ? &sel_end : &sel_start);
OnAfterPossibleChange();
- } else if (count == 1 && !has_selection) {
- gint cursor_pos;
- g_object_get(G_OBJECT(text_buffer_), "cursor-position", &cursor_pos,
- NULL);
- if (cursor_pos == GetTextLength())
- controller_->OnCommitSuggestedText(GetText());
- else
- handled = false;
- } else {
- handled = false;
+ handled = true;
+ } else if (count == count_towards_end && cursor_pos == GetTextLength()) {
+ handled = controller_->OnCommitSuggestedText(GetText());
}
} else if (step == GTK_MOVEMENT_PAGES) { // Page up and down.
// Multiply by count for the direction (if we move too much that's ok).
model_->OnUpOrDownKeyPressed(model_->result().size() * count);
+ handled = true;
} else if (step == GTK_MOVEMENT_DISPLAY_LINES) { // Arrow up and down.
model_->OnUpOrDownKeyPressed(count);
- } else {
- handled = false;
+ handled = true;
}
if (!handled) {
@@ -1471,9 +1543,6 @@ void AutocompleteEditViewGtk::HandleViewMoveFocus(GtkWidget* widget,
handled = true;
}
} else {
- // TODO(estade): this only works for linux/gtk; linux/views doesn't use
- // |instant_view_| so its visibility is not an indicator of whether we
- // have a suggestion.
if (GTK_WIDGET_VISIBLE(instant_view_)) {
controller_->OnCommitSuggestedText(GetText());
handled = true;
@@ -1672,18 +1741,27 @@ AutocompleteEditViewGtk::CharRange AutocompleteEditViewGtk::GetSelection() {
mark = gtk_text_buffer_get_insert(text_buffer_);
gtk_text_buffer_get_iter_at_mark(text_buffer_, &insert, mark);
+ gint start_offset = gtk_text_iter_get_offset(&start);
+ gint end_offset = gtk_text_iter_get_offset(&insert);
+
#if GTK_CHECK_VERSION(2, 20, 0)
// Nothing should be selected when we are in the middle of composition.
- DCHECK(preedit_.empty() || gtk_text_iter_equal(&start, &insert));
+ DCHECK(preedit_.empty() || start_offset == end_offset);
+ if (!preedit_.empty()) {
+ start_offset += preedit_.size();
+ end_offset += preedit_.size();
+ }
#endif
- return CharRange(gtk_text_iter_get_offset(&start),
- gtk_text_iter_get_offset(&insert));
+ return CharRange(start_offset, end_offset);
}
void AutocompleteEditViewGtk::ItersFromCharRange(const CharRange& range,
GtkTextIter* iter_min,
GtkTextIter* iter_max) {
+#if GTK_CHECK_VERSION(2, 20, 0)
+ DCHECK(preedit_.empty());
+#endif
gtk_text_buffer_get_iter_at_offset(text_buffer_, iter_min, range.cp_min);
gtk_text_buffer_get_iter_at_offset(text_buffer_, iter_max, range.cp_max);
}
@@ -1707,8 +1785,10 @@ void AutocompleteEditViewGtk::EmphasizeURLComponents() {
// a part of the text content inside GtkTextView. And it's ok to simply return
// in this case, as this method will be called again when the preedit string
// gets committed.
- if (preedit_.size())
+ if (preedit_.size()) {
+ strikethrough_ = CharRange();
return;
+ }
#endif
// See whether the contents are a URL with a non-empty host portion, which we
// should emphasize. To check for a URL, rather than using the type returned
@@ -1776,7 +1856,11 @@ void AutocompleteEditViewGtk::SetInstantSuggestion(
gtk_widget_hide(instant_view_);
} else {
if (InstantController::IsEnabled(model_->profile(),
- InstantController::PREDICTIVE_TYPE)) {
+ InstantController::PREDICTIVE_TYPE)
+#if GTK_CHECK_VERSION(2, 20, 0)
+ && preedit_.empty()
+#endif
+ ) {
instant_animation_->set_delegate(this);
instant_animation_->Start();
}
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h
index 25d953f..dc09d91 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h
+++ b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h
@@ -19,7 +19,7 @@
#include "base/string_util.h"
#include "chrome/browser/autocomplete/autocomplete_edit_view.h"
#include "chrome/browser/gtk/owned_widget_gtk.h"
-#include "chrome/browser/toolbar_model.h"
+#include "chrome/browser/ui/toolbar/toolbar_model.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/page_transition_types.h"
@@ -93,8 +93,8 @@ class AutocompleteEditViewGtk : public AutocompleteEditView,
gfx::Font GetFont();
// Implement the AutocompleteEditView interface.
- virtual AutocompleteEditModel* model() { return model_.get(); }
- virtual const AutocompleteEditModel* model() const { return model_.get(); }
+ virtual AutocompleteEditModel* model();
+ virtual const AutocompleteEditModel* model() const;
virtual void SaveStateToTab(TabContents* tab);
@@ -488,9 +488,24 @@ class AutocompleteEditViewGtk : public AutocompleteEditView,
// Was the delete key pressed with an empty selection at the end of the edit?
bool delete_at_end_pressed_;
+ // Indicates if we are handling a key press event.
+ bool handling_key_press_;
+
+ // Indicates if omnibox's content maybe changed by a key press event, so that
+ // we need to call OnAfterPossibleChange() after handling the event.
+ // This flag should be set for changes directly caused by a key press event,
+ // including changes to content text, selection range and preedit string.
+ // Changes caused by function calls like SetUserText() should not affect this
+ // flag.
+ bool content_maybe_changed_by_key_press_;
+
#if GTK_CHECK_VERSION(2, 20, 0)
// Stores the text being composed by the input method.
std::wstring preedit_;
+
+ // Tracking preedit state before and after a possible change. We don't need to
+ // track preedit_'s content, as it'll be treated as part of text content.
+ size_t preedit_size_before_change_;
#endif
// The view that is going to be focused next. Only valid while handling
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_mac.h b/chrome/browser/autocomplete/autocomplete_edit_view_mac.h
index 094712c..d486cc5 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_view_mac.h
+++ b/chrome/browser/autocomplete/autocomplete_edit_view_mac.h
@@ -11,7 +11,7 @@
#include "base/scoped_ptr.h"
#include "base/string16.h"
#include "chrome/browser/autocomplete/autocomplete_edit_view.h"
-#include "chrome/browser/cocoa/location_bar/autocomplete_text_field.h"
+#include "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
class AutocompleteEditController;
class AutocompletePopupViewMac;
@@ -74,6 +74,7 @@ class AutocompleteEditViewMac : public AutocompleteEditView,
bool save_original_selection);
virtual bool OnInlineAutocompleteTextMaybeChanged(
const std::wstring& display_text, size_t user_text_length);
+ virtual void OnStartingIME();
virtual void OnRevertTemporaryText();
virtual void OnBeforePossibleChange();
virtual bool OnAfterPossibleChange();
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm b/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm
index 5157b9a..ce2c0f1 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm
+++ b/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm
@@ -8,8 +8,8 @@
#include "app/clipboard/clipboard.h"
#include "app/clipboard/scoped_clipboard_writer.h"
+#include "app/mac/nsimage_cache.h"
#include "app/resource_bundle.h"
-#include "base/nsimage_cache_mac.h"
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
#include "base/utf_string_conversions.h"
@@ -18,9 +18,9 @@
#include "chrome/browser/autocomplete/autocomplete_popup_model.h"
#include "chrome/browser/autocomplete/autocomplete_popup_view_mac.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/cocoa/event_utils.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/toolbar_model.h"
+#include "chrome/browser/ui/cocoa/event_utils.h"
+#include "chrome/browser/ui/toolbar/toolbar_model.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "net/base/escape.h"
@@ -149,7 +149,7 @@ NSImage* AutocompleteEditViewMac::ImageForResource(int resource_id) {
}
if (image_name) {
- if (NSImage* image = nsimage_cache::ImageNamed(image_name)) {
+ if (NSImage* image = app::mac::GetCachedImageWithName(image_name)) {
return image;
} else {
NOTREACHED()
@@ -627,6 +627,11 @@ void AutocompleteEditViewMac::OnTemporaryTextMaybeChanged(
[field_ clearUndoChain];
}
+void AutocompleteEditViewMac::OnStartingIME() {
+ if (model_->is_keyword_hint() && !model_->keyword().empty())
+ model_->AcceptKeyword();
+}
+
bool AutocompleteEditViewMac::OnInlineAutocompleteTextMaybeChanged(
const std::wstring& display_text, size_t user_text_length) {
// TODO(shess): Make sure that this actually works. The round trip
@@ -805,6 +810,9 @@ bool AutocompleteEditViewMac::OnDoCommandBySelector(SEL cmd) {
controller_->OnCommitSuggestedText(GetText());
return true;
}
+
+ if (controller_->AcceptCurrentInstantPreview())
+ return true;
}
// |-noop:| is sent when the user presses Cmd+Return. Override the no-op
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_win.cc b/chrome/browser/autocomplete/autocomplete_edit_view_win.cc
index f16a15e..284f30c 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_view_win.cc
+++ b/chrome/browser/autocomplete/autocomplete_edit_view_win.cc
@@ -38,7 +38,7 @@
#include "chrome/browser/command_updater.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/net/url_fixer_upper.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/tab_contents/tab_contents.h"
@@ -711,14 +711,6 @@ void AutocompleteEditViewWin::UpdatePopup() {
return;
}
- // Figure out whether the user is trying to compose something in an IME.
- bool ime_composing = false;
- HIMC context = ImmGetContext(m_hWnd);
- if (context) {
- ime_composing = !!ImmGetCompositionString(context, GCS_COMPSTR, NULL, 0);
- ImmReleaseContext(m_hWnd, context);
- }
-
// Don't inline autocomplete when:
// * The user is deleting text
// * The caret/selection isn't at the end of the text
@@ -727,7 +719,7 @@ void AutocompleteEditViewWin::UpdatePopup() {
CHARRANGE sel;
GetSel(sel);
model_->StartAutocomplete(sel.cpMax != sel.cpMin,
- (sel.cpMax < GetTextLength()) || ime_composing);
+ (sel.cpMax < GetTextLength()) || IsImeComposing());
}
void AutocompleteEditViewWin::ClosePopup() {
@@ -1011,7 +1003,7 @@ bool AutocompleteEditViewWin::GetAcceleratorForCommandId(
return parent_view_->GetWidget()->GetAccelerator(command_id, accelerator);
}
-bool AutocompleteEditViewWin::IsLabelForCommandIdDynamic(int command_id) const {
+bool AutocompleteEditViewWin::IsItemForCommandIdDynamic(int command_id) const {
// No need to change the default IDS_PASTE_AND_GO label unless this is a
// search.
return command_id == IDS_PASTE_AND_GO;
@@ -2130,7 +2122,7 @@ LONG AutocompleteEditViewWin::ClipXCoordToVisibleText(
if (end_position_x >= first_position_x) {
right_bound = std::min(right_bound, end_position_x); // LTR case.
}
- // For trailing characters that are 2 pixels wide of less (like "l" in some
+ // For trailing characters that are 2 pixels wide or less (like "l" in some
// fonts), we have a problem:
// * Clicks on any pixel within the character will place the cursor before
// the character.
@@ -2593,3 +2585,13 @@ int AutocompleteEditViewWin::WidthNeededToDisplay(const std::wstring& text) {
// PosFromChar(i) might return 0 when i is greater than 1.
return font_.GetStringWidth(text) + GetHorizontalMargin();
}
+
+bool AutocompleteEditViewWin::IsImeComposing() const {
+ bool ime_composing = false;
+ HIMC context = ImmGetContext(m_hWnd);
+ if (context) {
+ ime_composing = !!ImmGetCompositionString(context, GCS_COMPSTR, NULL, 0);
+ ImmReleaseContext(m_hWnd, context);
+ }
+ return ime_composing;
+}
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_win.h b/chrome/browser/autocomplete/autocomplete_edit_view_win.h
index 3a9c0b2..0773843 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_view_win.h
+++ b/chrome/browser/autocomplete/autocomplete_edit_view_win.h
@@ -18,7 +18,7 @@
#include "base/scoped_ptr.h"
#include "chrome/browser/autocomplete/autocomplete.h"
#include "chrome/browser/autocomplete/autocomplete_edit_view.h"
-#include "chrome/browser/toolbar_model.h"
+#include "chrome/browser/ui/toolbar/toolbar_model.h"
#include "chrome/browser/views/autocomplete/autocomplete_popup_contents_view.h"
#include "chrome/common/page_transition_types.h"
#include "gfx/font.h"
@@ -209,10 +209,13 @@ class AutocompleteEditViewWin
virtual bool IsCommandIdEnabled(int command_id) const;
virtual bool GetAcceleratorForCommandId(int command_id,
menus::Accelerator* accelerator);
- virtual bool IsLabelForCommandIdDynamic(int command_id) const;
+ virtual bool IsItemForCommandIdDynamic(int command_id) const;
virtual std::wstring GetLabelForCommandId(int command_id) const;
virtual void ExecuteCommand(int command_id);
+ // Returns true if the user is composing something in an IME.
+ bool IsImeComposing() const;
+
private:
enum MouseButton {
kLeft = 0,
diff --git a/chrome/browser/autocomplete/autocomplete_match.h b/chrome/browser/autocomplete/autocomplete_match.h
index 4ad4a6e..d65ff5f 100644
--- a/chrome/browser/autocomplete/autocomplete_match.h
+++ b/chrome/browser/autocomplete/autocomplete_match.h
@@ -125,7 +125,7 @@ struct AutocompleteMatch {
int style,
ACMatchClassifications* classifications);
- // The provider of this match, used to remember which provider the user had
+ // The provider of this match, used to remember which provider the user had
// selected when the input changes. This may be NULL, in which case there is
// no provider (or memory of the user's selection).
AutocompleteProvider* provider;
diff --git a/chrome/browser/autocomplete/autocomplete_popup_model.cc b/chrome/browser/autocomplete/autocomplete_popup_model.cc
index 6bf065d..2ea4068 100644
--- a/chrome/browser/autocomplete/autocomplete_popup_model.cc
+++ b/chrome/browser/autocomplete/autocomplete_popup_model.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/autocomplete/autocomplete_popup_model.h"
+#include <algorithm>
+
#include "unicode/ubidi.h"
#include "base/string_util.h"
@@ -11,11 +13,12 @@
#include "chrome/browser/autocomplete/autocomplete_match.h"
#include "chrome/browser/autocomplete/autocomplete_popup_view.h"
#include "chrome/browser/autocomplete/search_provider.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
#include "gfx/rect.h"
///////////////////////////////////////////////////////////////////////////////
@@ -224,11 +227,11 @@ bool AutocompletePopupModel::GetKeywordForMatch(const AutocompleteMatch& match,
// Don't provide a hint for inactive/disabled extension keywords.
if (template_url->IsExtensionKeyword()) {
- const Extension* extension = profile_->GetExtensionsService()->
+ const Extension* extension = profile_->GetExtensionService()->
GetExtensionById(template_url->GetExtensionId(), false);
if (!extension ||
(profile_->IsOffTheRecord() &&
- !profile_->GetExtensionsService()->IsIncognitoEnabled(extension)))
+ !profile_->GetExtensionService()->IsIncognitoEnabled(extension)))
return false;
}
@@ -322,6 +325,6 @@ const SkBitmap* AutocompletePopupModel::GetSpecialIconForMatch(
if (!match.template_url || !match.template_url->IsExtensionKeyword())
return NULL;
- return &profile_->GetExtensionsService()->GetOmniboxPopupIcon(
+ return &profile_->GetExtensionService()->GetOmniboxPopupIcon(
match.template_url->GetExtensionId());
}
diff --git a/chrome/browser/autocomplete/autocomplete_popup_view_gtk.cc b/chrome/browser/autocomplete/autocomplete_popup_view_gtk.cc
index 088c9ad..e7da263 100644
--- a/chrome/browser/autocomplete/autocomplete_popup_view_gtk.cc
+++ b/chrome/browser/autocomplete/autocomplete_popup_view_gtk.cc
@@ -22,7 +22,7 @@
#include "chrome/browser/defaults.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/gtk/gtk_util.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/common/notification_service.h"
@@ -337,6 +337,10 @@ AutocompletePopupViewGtk::~AutocompletePopupViewGtk() {
g_object_unref(it->second);
}
+bool AutocompletePopupViewGtk::IsOpen() const {
+ return opened_;
+}
+
void AutocompletePopupViewGtk::InvalidateLine(size_t line) {
// TODO(deanm): Is it possible to use some constant for the width, instead
// of having to query the width of the window?
diff --git a/chrome/browser/autocomplete/autocomplete_popup_view_gtk.h b/chrome/browser/autocomplete/autocomplete_popup_view_gtk.h
index 590cc41..0632635 100644
--- a/chrome/browser/autocomplete/autocomplete_popup_view_gtk.h
+++ b/chrome/browser/autocomplete/autocomplete_popup_view_gtk.h
@@ -35,7 +35,7 @@ class AutocompletePopupViewGtk : public AutocompletePopupView,
~AutocompletePopupViewGtk();
// Overridden from AutocompletePopupView:
- virtual bool IsOpen() const { return opened_; }
+ virtual bool IsOpen() const;
virtual void InvalidateLine(size_t line);
virtual void UpdatePopupAppearance();
virtual gfx::Rect GetTargetBounds();
diff --git a/chrome/browser/autocomplete/autocomplete_popup_view_mac.h b/chrome/browser/autocomplete/autocomplete_popup_view_mac.h
index 32e080c..2fdfaa9 100644
--- a/chrome/browser/autocomplete/autocomplete_popup_view_mac.h
+++ b/chrome/browser/autocomplete/autocomplete_popup_view_mac.h
@@ -16,7 +16,7 @@
#include "chrome/browser/autocomplete/autocomplete.h"
#include "chrome/browser/autocomplete/autocomplete_match.h"
#include "chrome/browser/autocomplete/autocomplete_popup_view.h"
-#import "chrome/browser/cocoa/location_bar/instant_opt_in_controller.h"
+#import "chrome/browser/ui/cocoa/location_bar/instant_opt_in_controller.h"
#include "gfx/font.h"
#include "webkit/glue/window_open_disposition.h"
diff --git a/chrome/browser/autocomplete/autocomplete_popup_view_mac.mm b/chrome/browser/autocomplete/autocomplete_popup_view_mac.mm
index 0a84fb2..950cf08 100644
--- a/chrome/browser/autocomplete/autocomplete_popup_view_mac.mm
+++ b/chrome/browser/autocomplete/autocomplete_popup_view_mac.mm
@@ -16,14 +16,14 @@
#include "chrome/browser/autocomplete/autocomplete_edit_view_mac.h"
#include "chrome/browser/autocomplete/autocomplete_match.h"
#include "chrome/browser/autocomplete/autocomplete_popup_model.h"
-#include "chrome/browser/cocoa/event_utils.h"
-#include "chrome/browser/cocoa/image_utils.h"
-#import "chrome/browser/cocoa/location_bar/instant_opt_in_controller.h"
-#import "chrome/browser/cocoa/location_bar/instant_opt_in_view.h"
-#import "chrome/browser/cocoa/location_bar/omnibox_popup_view.h"
#include "chrome/browser/instant/instant_confirm_dialog.h"
#include "chrome/browser/instant/promo_counter.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/cocoa/event_utils.h"
+#include "chrome/browser/ui/cocoa/image_utils.h"
+#import "chrome/browser/ui/cocoa/location_bar/instant_opt_in_controller.h"
+#import "chrome/browser/ui/cocoa/location_bar/instant_opt_in_view.h"
+#import "chrome/browser/ui/cocoa/location_bar/omnibox_popup_view.h"
#include "gfx/rect.h"
#include "grit/theme_resources.h"
#include "skia/ext/skia_utils_mac.h"
diff --git a/chrome/browser/autocomplete/autocomplete_unittest.cc b/chrome/browser/autocomplete/autocomplete_unittest.cc
index f6b165e..fc6c402 100644
--- a/chrome/browser/autocomplete/autocomplete_unittest.cc
+++ b/chrome/browser/autocomplete/autocomplete_unittest.cc
@@ -288,18 +288,25 @@ TEST(AutocompleteTest, InputType) {
{ L"foo+bar.com", AutocompleteInput::UNKNOWN },
{ L"\"foo:bar\"", AutocompleteInput::QUERY },
{ L"link:foo.com", AutocompleteInput::UNKNOWN },
+ { L"foo:81", AutocompleteInput::URL },
{ L"www.foo.com:81", AutocompleteInput::URL },
{ L"localhost:8080", AutocompleteInput::URL },
{ L"foo.com:123456", AutocompleteInput::QUERY },
{ L"foo.com:abc", AutocompleteInput::QUERY },
{ L"1.2.3.4:abc", AutocompleteInput::QUERY },
{ L"user@foo.com", AutocompleteInput::UNKNOWN },
- { L"user:pass@foo.com", AutocompleteInput::UNKNOWN },
+ { L"user:pass@", AutocompleteInput::UNKNOWN },
+ { L"user:pass@!foo.com", AutocompleteInput::UNKNOWN },
+ { L"user:pass@foo", AutocompleteInput::URL },
+ { L"user:pass@foo.c", AutocompleteInput::URL },
+ { L"user:pass@foo.com", AutocompleteInput::URL },
+ { L"user:pass@foo.com:81", AutocompleteInput::URL },
+ { L"user:pass@foo:81", AutocompleteInput::URL },
{ L"1.2", AutocompleteInput::UNKNOWN },
{ L"1.2/45", AutocompleteInput::UNKNOWN },
{ L"1.2:45", AutocompleteInput::UNKNOWN },
{ L"user@1.2:45", AutocompleteInput::UNKNOWN },
- { L"user:foo@1.2:45", AutocompleteInput::UNKNOWN },
+ { L"user:pass@1.2:45", AutocompleteInput::URL },
{ L"ps/2 games", AutocompleteInput::UNKNOWN },
{ L"en.wikipedia.org/wiki/James Bond", AutocompleteInput::URL },
// In Chrome itself, mailto: will get handled by ShellExecute, but in
@@ -344,10 +351,10 @@ TEST(AutocompleteTest, InputType) {
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(input_cases); ++i) {
+ SCOPED_TRACE(input_cases[i].input);
AutocompleteInput input(input_cases[i].input, std::wstring(), true, false,
true, false);
- EXPECT_EQ(input_cases[i].type, input.type()) << "Input: " <<
- input_cases[i].input;
+ EXPECT_EQ(input_cases[i].type, input.type());
}
}
diff --git a/chrome/browser/autocomplete/history_contents_provider.cc b/chrome/browser/autocomplete/history_contents_provider.cc
index 1d0c828..37f3144 100644
--- a/chrome/browser/autocomplete/history_contents_provider.cc
+++ b/chrome/browser/autocomplete/history_contents_provider.cc
@@ -12,7 +12,7 @@
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/history/query_parser.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/url_constants.h"
#include "googleurl/src/url_util.h"
#include "net/base/net_util.h"
@@ -53,7 +53,7 @@ using history::HistoryDatabase;
HistoryContentsProvider::HistoryContentsProvider(ACProviderListener* listener,
Profile* profile)
- : AutocompleteProvider(listener, profile, "HistoryContents"),
+ : HistoryProvider(listener, profile, "HistoryContents"),
star_title_count_(0),
star_contents_count_(0),
title_count_(0),
@@ -222,7 +222,7 @@ AutocompleteMatch HistoryContentsProvider::ResultToMatch(
int score) {
// TODO(sky): if matched title highlight matching words in title.
// Also show star in popup.
- AutocompleteMatch match(this, score, false, MatchInTitle(result) ?
+ AutocompleteMatch match(this, score, true, MatchInTitle(result) ?
AutocompleteMatch::HISTORY_TITLE : AutocompleteMatch::HISTORY_BODY);
match.contents = StringForURLDisplay(result.url(), true, trim_http_);
match.fill_into_edit =
diff --git a/chrome/browser/autocomplete/history_contents_provider.h b/chrome/browser/autocomplete/history_contents_provider.h
index 31b75ec..657403f 100644
--- a/chrome/browser/autocomplete/history_contents_provider.h
+++ b/chrome/browser/autocomplete/history_contents_provider.h
@@ -6,7 +6,7 @@
#define CHROME_BROWSER_AUTOCOMPLETE_HISTORY_CONTENTS_PROVIDER_H_
#pragma once
-#include "chrome/browser/autocomplete/autocomplete.h"
+#include "chrome/browser/autocomplete/history_provider.h"
#include "chrome/browser/history/history.h"
namespace bookmark_utils {
@@ -20,16 +20,15 @@ struct TitleMatch;
// previously viewed pages. This is asynchronous.
// . BookmarkModel: provides results for matches in the titles of bookmarks.
// This is synchronous.
-class HistoryContentsProvider : public AutocompleteProvider {
+class HistoryContentsProvider : public HistoryProvider {
public:
HistoryContentsProvider(ACProviderListener* listener, Profile* profile);
// As necessary asks the history service for the relevant results. When
// done SetResults is invoked.
virtual void Start(const AutocompleteInput& input,
- bool minimal_changes);
-
- virtual void Stop();
+ bool minimal_changes) OVERRIDE;
+ virtual void Stop() OVERRIDE;
// Returns the total number of matches available in the database, up to
// kMaxMatchCount, whichever is smaller.
diff --git a/chrome/browser/autocomplete/history_provider.cc b/chrome/browser/autocomplete/history_provider.cc
index bbc2fe5..100db04 100644
--- a/chrome/browser/autocomplete/history_provider.cc
+++ b/chrome/browser/autocomplete/history_provider.cc
@@ -8,7 +8,11 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
+#include "chrome/browser/autocomplete/autocomplete.h"
+#include "chrome/browser/autocomplete/autocomplete_match.h"
+#include "chrome/browser/history/history.h"
#include "chrome/browser/net/url_fixer_upper.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/url_constants.h"
#include "googleurl/src/url_util.h"
@@ -18,6 +22,43 @@ HistoryProvider::HistoryProvider(ACProviderListener* listener,
: AutocompleteProvider(listener, profile, name) {
}
+void HistoryProvider::DeleteMatch(const AutocompleteMatch& match) {
+ DCHECK(done_);
+ DCHECK(profile_);
+ DCHECK(match.deletable);
+
+ HistoryService* const history_service =
+ profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
+
+ // Delete the match from the history DB.
+ GURL selected_url(match.destination_url);
+ if (!history_service || !selected_url.is_valid()) {
+ NOTREACHED() << "Can't delete requested URL";
+ return;
+ }
+ history_service->DeleteURL(selected_url);
+
+ // Delete the match from the current set of matches.
+ bool found = false;
+ for (ACMatches::iterator i(matches_.begin()); i != matches_.end(); ++i) {
+ if (i->destination_url == selected_url && i->type == match.type) {
+ found = true;
+ if (i->is_history_what_you_typed_match) {
+ // We can't get rid of the What You Typed match, but we can make it
+ // look like it has no backing data.
+ i->deletable = false;
+ i->description.clear();
+ i->description_class.clear();
+ } else {
+ matches_.erase(i);
+ }
+ break;
+ }
+ }
+ DCHECK(found) << "Asked to delete a URL that isn't in our set of matches";
+ listener_->OnProviderUpdate(true);
+}
+
// static
std::wstring HistoryProvider::FixupUserInput(const AutocompleteInput& input) {
const std::wstring& input_text = input.text();
diff --git a/chrome/browser/autocomplete/history_provider.h b/chrome/browser/autocomplete/history_provider.h
index bdefabd..a1119a4 100644
--- a/chrome/browser/autocomplete/history_provider.h
+++ b/chrome/browser/autocomplete/history_provider.h
@@ -6,8 +6,8 @@
#define CHROME_BROWSER_AUTOCOMPLETE_HISTORY_PROVIDER_H_
#pragma once
+#include "base/compiler_specific.h"
#include "chrome/browser/autocomplete/autocomplete.h"
-#include "chrome/browser/autocomplete/history_provider_util.h"
namespace history {
@@ -31,6 +31,8 @@ class HistoryProvider : public AutocompleteProvider {
Profile* profile,
const char* name);
+ virtual void DeleteMatch(const AutocompleteMatch& match) OVERRIDE;
+
// Fixes up user URL input to make it more possible to match against. Among
// many other things, this takes care of the following:
// * Prepending file:// to file URLs
diff --git a/chrome/browser/autocomplete/history_quick_provider.cc b/chrome/browser/autocomplete/history_quick_provider.cc
index 236c1c4..0392f1e 100644
--- a/chrome/browser/autocomplete/history_quick_provider.cc
+++ b/chrome/browser/autocomplete/history_quick_provider.cc
@@ -5,14 +5,14 @@
#include "chrome/browser/autocomplete/history_quick_provider.h"
#include "base/basictypes.h"
-#include "base/i18n/word_iterator.h"
+#include "base/i18n/break_iterator.h"
#include "base/string_util.h"
#include "base/logging.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autocomplete/autocomplete_match.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/history/in_memory_url_index.h"
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/plugin_service.h"
@@ -70,6 +70,10 @@ void HistoryQuickProvider::Start(const AutocompleteInput& input,
}
}
+// HistoryQuickProvider matches are currently not deletable.
+// TODO(mrossetti): Determine when a match should be deletable.
+void HistoryQuickProvider::DeleteMatch(const AutocompleteMatch& match) {}
+
void HistoryQuickProvider::DoAutocomplete() {
// Get the matching URLs from the DB.
string16 term_string(WideToUTF16(autocomplete_input_.text()));
@@ -167,11 +171,11 @@ void HistoryQuickProvider::SetIndexForTesting(
history::InMemoryURLIndex::String16Vector
HistoryQuickProvider::WordVectorFromString16(const string16& uni_string) {
history::InMemoryURLIndex::String16Vector words;
- WordIterator iter(&uni_string, WordIterator::BREAK_WORD);
+ base::BreakIterator iter(&uni_string, base::BreakIterator::BREAK_WORD);
if (iter.Init()) {
while (iter.Advance()) {
if (iter.IsWord())
- words.push_back(iter.GetWord());
+ words.push_back(iter.GetString());
}
}
return words;
diff --git a/chrome/browser/autocomplete/history_quick_provider.h b/chrome/browser/autocomplete/history_quick_provider.h
index b86ca8c..561336b 100644
--- a/chrome/browser/autocomplete/history_quick_provider.h
+++ b/chrome/browser/autocomplete/history_quick_provider.h
@@ -33,7 +33,10 @@ class HistoryQuickProvider : public HistoryProvider {
// AutocompleteProvider. |minimal_changes| is ignored since there
// is no asynch completion performed.
- void Start(const AutocompleteInput& input, bool minimal_changes);
+ virtual void Start(const AutocompleteInput& input,
+ bool minimal_changes) OVERRIDE;
+
+ virtual void DeleteMatch(const AutocompleteMatch& match) OVERRIDE;
// Performs the autocomplete matching and scoring.
void DoAutocomplete();
diff --git a/chrome/browser/autocomplete/history_url_provider.cc b/chrome/browser/autocomplete/history_url_provider.cc
index fd5b8fb..41fb155 100644
--- a/chrome/browser/autocomplete/history_url_provider.cc
+++ b/chrome/browser/autocomplete/history_url_provider.cc
@@ -17,7 +17,7 @@
#include "chrome/browser/history/history_database.h"
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "googleurl/src/gurl.h"
@@ -147,40 +147,6 @@ void HistoryURLProvider::Stop() {
params_->cancel = true;
}
-void HistoryURLProvider::DeleteMatch(const AutocompleteMatch& match) {
- DCHECK(done_);
-
- // Delete the match from the history DB.
- HistoryService* const history_service =
- profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
- GURL selected_url(match.destination_url);
- if (!history_service || !selected_url.is_valid()) {
- NOTREACHED() << "Can't delete requested URL";
- return;
- }
- history_service->DeleteURL(selected_url);
-
- // Delete the match from the current set of matches.
- bool found = false;
- for (ACMatches::iterator i(matches_.begin()); i != matches_.end(); ++i) {
- if (i->destination_url == match.destination_url) {
- found = true;
- if (i->is_history_what_you_typed_match) {
- // We can't get rid of the What You Typed match, but we can make it
- // look like it has no backing data.
- i->deletable = false;
- i->description.clear();
- i->description_class.clear();
- } else {
- matches_.erase(i);
- }
- break;
- }
- }
- DCHECK(found) << "Asked to delete a URL that isn't in our set of matches";
- listener_->OnProviderUpdate(true);
-}
-
// Called on the history thread.
void HistoryURLProvider::ExecuteWithDB(history::HistoryBackend* backend,
history::URLDatabase* db,
diff --git a/chrome/browser/autocomplete/history_url_provider.h b/chrome/browser/autocomplete/history_url_provider.h
index 58c4c25..0e4e5ff 100644
--- a/chrome/browser/autocomplete/history_url_provider.h
+++ b/chrome/browser/autocomplete/history_url_provider.h
@@ -8,6 +8,7 @@
#include <string>
+#include "base/compiler_specific.h"
#include "chrome/browser/autocomplete/history_provider.h"
#include "chrome/browser/autocomplete/history_provider_util.h"
@@ -151,9 +152,8 @@ class HistoryURLProvider : public HistoryProvider {
// AutocompleteProvider
virtual void Start(const AutocompleteInput& input,
- bool minimal_changes);
- virtual void Stop();
- virtual void DeleteMatch(const AutocompleteMatch& match);
+ bool minimal_changes) OVERRIDE;
+ virtual void Stop() OVERRIDE;
// Runs the history query on the history thread, called by the history
// system. The history database MAY BE NULL in which case it is not
diff --git a/chrome/browser/autocomplete/keyword_provider.cc b/chrome/browser/autocomplete/keyword_provider.cc
index a82f340..5f2d430 100644
--- a/chrome/browser/autocomplete/keyword_provider.cc
+++ b/chrome/browser/autocomplete/keyword_provider.cc
@@ -12,11 +12,12 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/autocomplete/autocomplete_match.h"
#include "chrome/browser/extensions/extension_omnibox_api.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
#include "grit/generated_resources.h"
#include "net/base/escape.h"
#include "net/base/net_util.h"
@@ -182,7 +183,7 @@ void KeywordProvider::Start(const AutocompleteInput& input,
const TemplateURL* template_url(model->GetTemplateURLForKeyword(*i));
if (profile_ &&
!input.synchronous_only() && template_url->IsExtensionKeyword()) {
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
const Extension* extension = service->GetExtensionById(
template_url->GetExtensionId(), false);
bool enabled = extension && (!profile_->IsOffTheRecord() ||
diff --git a/chrome/browser/autocomplete/keyword_provider.h b/chrome/browser/autocomplete/keyword_provider.h
index e39b5b6..4a6ad90 100644
--- a/chrome/browser/autocomplete/keyword_provider.h
+++ b/chrome/browser/autocomplete/keyword_provider.h
@@ -126,9 +126,9 @@ class KeywordProvider : public AutocompleteProvider,
void MaybeEndExtensionKeywordMode();
// NotificationObserver interface.
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
// Model for the keywords. This is only non-null when testing, otherwise the
// TemplateURLModel from the Profile is used.
diff --git a/chrome/browser/autocomplete/search_provider.cc b/chrome/browser/autocomplete/search_provider.cc
index f1da091..bd5a949 100644
--- a/chrome/browser/autocomplete/search_provider.cc
+++ b/chrome/browser/autocomplete/search_provider.cc
@@ -15,13 +15,12 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/autocomplete/keyword_provider.h"
#include "chrome/browser/autocomplete/autocomplete_match.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/instant/instant_controller.h"
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/history/in_memory_database.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/common/json_value_serializer.h"
@@ -60,6 +59,7 @@ void SearchProvider::Providers::Set(const TemplateURL* default_provider,
SearchProvider::SearchProvider(ACProviderListener* listener, Profile* profile)
: AutocompleteProvider(listener, profile, "Search"),
suggest_results_pending_(0),
+ have_suggest_results_(false),
instant_finalized_(false) {
}
diff --git a/chrome/browser/autocomplete_history_manager.cc b/chrome/browser/autocomplete_history_manager.cc
index 763445b..4e93aa6 100644
--- a/chrome/browser/autocomplete_history_manager.cc
+++ b/chrome/browser/autocomplete_history_manager.cc
@@ -11,7 +11,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/credit_card.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/pref_names.h"
diff --git a/chrome/browser/autofill/address_field.cc b/chrome/browser/autofill/address_field.cc
index 42a8531..009e25e 100644
--- a/chrome/browser/autofill/address_field.cc
+++ b/chrome/browser/autofill/address_field.cc
@@ -74,6 +74,10 @@ bool AddressField::GetFieldInfo(FieldTypeMap* field_type_map) const {
return ok;
}
+FormFieldType AddressField::GetFormFieldType() const {
+ return kAddressType;
+}
+
AddressField* AddressField::Parse(
std::vector<AutoFillField*>::const_iterator* iter,
bool is_ecml) {
diff --git a/chrome/browser/autofill/address_field.h b/chrome/browser/autofill/address_field.h
index 51dd105..116ae35 100644
--- a/chrome/browser/autofill/address_field.h
+++ b/chrome/browser/autofill/address_field.h
@@ -16,7 +16,7 @@ class AutoFillField;
class AddressField : public FormField {
public:
virtual bool GetFieldInfo(FieldTypeMap* field_type_map) const;
- virtual FormFieldType GetFormFieldType() const { return kAddressType; }
+ virtual FormFieldType GetFormFieldType() const;
static AddressField* Parse(std::vector<AutoFillField*>::const_iterator* iter,
bool is_ecml);
diff --git a/chrome/browser/autofill/autofill-inl.h b/chrome/browser/autofill/autofill-inl.h
new file mode 100644
index 0000000..66e0df2
--- /dev/null
+++ b/chrome/browser/autofill/autofill-inl.h
@@ -0,0 +1,36 @@
+// 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.
+
+#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_INL_H_
+#define CHROME_BROWSER_AUTOFILL_AUTOFILL_INL_H_
+#pragma once
+
+template<typename T>
+class FormGroupMatchesByCompareFunctor {
+ public:
+ explicit FormGroupMatchesByCompareFunctor(const T& form_group)
+ : form_group_(form_group) {
+ }
+
+ bool operator()(const T* form_group) {
+ return form_group->Compare(form_group_) == 0;
+ }
+
+ bool operator()(const T& form_group) {
+ return form_group.Compare(form_group_) == 0;
+ }
+
+ private:
+ const T& form_group_;
+};
+
+template<typename C, typename T>
+bool FindByContents(const C& container, const T& form_group) {
+ return std::find_if(
+ container.begin(),
+ container.end(),
+ FormGroupMatchesByCompareFunctor<T>(form_group)) != container.end();
+}
+
+#endif // CHROME_BROWSER_AUTOFILL_AUTOFILL_INL_H_
diff --git a/chrome/browser/autofill/autofill_address_model_mac_unittest.mm b/chrome/browser/autofill/autofill_address_model_mac_unittest.mm
index 21ee8b5..5d7ab4e 100644
--- a/chrome/browser/autofill/autofill_address_model_mac_unittest.mm
+++ b/chrome/browser/autofill/autofill_address_model_mac_unittest.mm
@@ -7,8 +7,8 @@
#import "chrome/browser/autofill/autofill_address_model_mac.h"
#include "chrome/browser/autofill/autofill_common_test.h"
#include "chrome/browser/autofill/autofill_profile.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
diff --git a/chrome/browser/autofill/autofill_address_sheet_controller_mac_unittest.mm b/chrome/browser/autofill/autofill_address_sheet_controller_mac_unittest.mm
index 2d6d34a..46379ac 100644
--- a/chrome/browser/autofill/autofill_address_sheet_controller_mac_unittest.mm
+++ b/chrome/browser/autofill/autofill_address_sheet_controller_mac_unittest.mm
@@ -6,8 +6,8 @@
#include "base/utf_string_conversions.h"
#import "chrome/browser/autofill/autofill_address_sheet_controller_mac.h"
#include "chrome/browser/autofill/autofill_profile.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
diff --git a/chrome/browser/autofill/autofill_browsertest.cc b/chrome/browser/autofill/autofill_browsertest.cc
index d4901bd..0aad9de 100644
--- a/chrome/browser/autofill/autofill_browsertest.cc
+++ b/chrome/browser/autofill/autofill_browsertest.cc
@@ -4,6 +4,7 @@
#include <string>
+#include "base/utf_string_conversions.h"
#include "app/keyboard_code_conversion.h"
#include "base/basictypes.h"
#include "base/ref_counted.h"
@@ -13,15 +14,54 @@
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/personal_data_manager.h"
#include "chrome/browser/net/predictor_api.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/mock_render_process_host.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/translate/translate_infobar_delegate.h"
+#include "chrome/browser/translate/translate_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
+#include "chrome/common/net/test_url_fetcher_factory.h"
#include "chrome/common/pref_names.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/renderer/translate_helper.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
+static const char* kTestFormString =
+ "<form action=\"http://www.google.com/\" method=\"POST\">"
+ "<label for=\"firstname\">First name:</label>"
+ " <input type=\"text\" id=\"firstname\""
+ " onFocus=\"domAutomationController.send(true)\""
+ " /><br />"
+ "<label for=\"lastname\">Last name:</label>"
+ " <input type=\"text\" id=\"lastname\" /><br />"
+ "<label for=\"address1\">Address line 1:</label>"
+ " <input type=\"text\" id=\"address1\" /><br />"
+ "<label for=\"address2\">Address line 2:</label>"
+ " <input type=\"text\" id=\"address2\" /><br />"
+ "<label for=\"city\">City:</label>"
+ " <input type=\"text\" id=\"city\" /><br />"
+ "<label for=\"state\">State:</label>"
+ " <select id=\"state\">"
+ " <option value=\"\" selected=\"yes\">--</option>"
+ " <option value=\"CA\">California</option>"
+ " <option value=\"TX\">Texas</option>"
+ " </select><br />"
+ "<label for=\"zip\">ZIP code:</label>"
+ " <input type=\"text\" id=\"zip\" /><br />"
+ "<label for=\"country\">Country:</label>"
+ " <select id=\"country\">"
+ " <option value=\"\" selected=\"yes\">--</option>"
+ " <option value=\"CA\">Canada</option>"
+ " <option value=\"US\">United States</option>"
+ " </select><br />"
+ "<label for=\"phone\">Phone number:</label>"
+ " <input type=\"text\" id=\"phone\" /><br />"
+ "</form>";
+
class AutoFillTest : public InProcessBrowserTest {
protected:
AutoFillTest() {
@@ -56,6 +96,113 @@ class AutoFillTest : public InProcessBrowserTest {
L"document.getElementById('" + field_name + L"').value);", &value));
EXPECT_EQ(expected_value, value);
}
+
+ RenderViewHost* rvh() {
+ return browser()->GetSelectedTabContents()->render_view_host();
+ }
+
+ virtual void SetUp() {
+ URLFetcher::set_factory(&url_fetcher_factory_);
+ InProcessBrowserTest::SetUp();
+ }
+
+ void SimulateURLFetch(bool success) {
+ TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0);
+ ASSERT_TRUE(fetcher);
+ URLRequestStatus status;
+ status.set_status(success ? URLRequestStatus::SUCCESS :
+ URLRequestStatus::FAILED);
+
+ std::string script = " var google = {};"
+ "google.translate = (function() {"
+ " return {"
+ " TranslateService: function() {"
+ " return {"
+ " isAvailable : function() {"
+ " return true;"
+ " },"
+ " restore : function() {"
+ " return;"
+ " },"
+ " getDetectedLanguage : function() {"
+ " return \"ja\";"
+ " },"
+ " translatePage : function(originalLang, targetLang,"
+ " onTranslateProgress) {"
+ " document.getElementsByTagName(\"body\")[0].innerHTML = '" +
+ std::string(kTestFormString) +
+ " ';"
+ " onTranslateProgress(100, true, false);"
+ " }"
+ " };"
+ " }"
+ " };"
+ "})();";
+
+ fetcher->delegate()->OnURLFetchComplete(fetcher, fetcher->original_url(),
+ status, success ? 200 : 500,
+ ResponseCookies(),
+ script);
+ }
+
+ void TryBasicFormFillWithMKey() {
+ ASSERT_NO_FATAL_FAILURE(ui_test_utils::ClickOnView(browser(),
+ VIEW_ID_TAB_CONTAINER));
+ ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(),
+ VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
+
+ bool result = false;
+ ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
+ rvh(), L"", L"document.getElementById('firstname').focus();", &result));
+ ASSERT_TRUE(result);
+ // Start filling the first name field with "M" and wait for the popup to be
+ // shown.
+ ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait(
+ browser(), app::VKEY_M, false, true, false, false,
+ NotificationType::AUTOFILL_DID_SHOW_SUGGESTIONS,
+ Source<RenderViewHost>(rvh())));
+
+ // Press the down arrow to select the suggestion and preview the autofilled
+ // form.
+ ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait(
+ browser(), app::VKEY_DOWN, false, false, false, false,
+ NotificationType::AUTOFILL_DID_FILL_FORM_DATA,
+ Source<RenderViewHost>(rvh())));
+
+ // The previewed values should not be accessible to JavaScript.
+ ExpectFieldValue(L"firstname", "M");
+ ExpectFieldValue(L"lastname", "");
+ ExpectFieldValue(L"address1", "");
+ ExpectFieldValue(L"address2", "");
+ ExpectFieldValue(L"city", "");
+ ExpectFieldValue(L"state", "");
+ ExpectFieldValue(L"zip", "");
+ ExpectFieldValue(L"country", "");
+ ExpectFieldValue(L"phone", "");
+ // TODO(isherman): It would be nice to test that the previewed values are
+ // displayed: http://crbug.com/57220
+
+ // Press Enter to accept the autofill suggestions.
+ ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait(
+ browser(), app::VKEY_RETURN, false, false, false, false,
+ NotificationType::AUTOFILL_DID_FILL_FORM_DATA,
+ Source<RenderViewHost>(rvh())));
+
+ // The form should be filled.
+ ExpectFieldValue(L"firstname", "Milton");
+ ExpectFieldValue(L"lastname", "Waddams");
+ ExpectFieldValue(L"address1", "4120 Freidrich Lane");
+ ExpectFieldValue(L"address2", "Basement");
+ ExpectFieldValue(L"city", "Austin");
+ ExpectFieldValue(L"state", "TX");
+ ExpectFieldValue(L"zip", "78744");
+ ExpectFieldValue(L"country", "US");
+ ExpectFieldValue(L"phone", "5125551234");
+
+ }
+
+ private:
+ TestURLFetcherFactory url_fetcher_factory_;
};
// Test that basic form fill is working.
@@ -63,93 +210,77 @@ IN_PROC_BROWSER_TEST_F(AutoFillTest, BasicFormFill) {
SetUpProfile();
ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+ ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(),
+ GURL("data:text/html;charset=utf-8," + std::string(kTestFormString))));
+
+ TryBasicFormFillWithMKey();
+}
+
+// Test that basic form fill is working.
+IN_PROC_BROWSER_TEST_F(AutoFillTest, TranslateAndFormFill) {
+ SetUpProfile();
+
+ GURL url("data:text/html;charset=utf-8,"
+ "<form action=\"http://www.google.com/\" method=\"POST\">"
+ "<label for=\"firstname\">なまえ</label>"
+ " <input type=\"text\" id=\"firstname\""
+ " onFocus=\"domAutomationController.send(true)\""
+ " /><br />"
+ "<label for=\"lastname\">みょうじ</label>"
+ " <input type=\"text\" id=\"lastname\" /><br />"
+ "<label for=\"address1\">Address line 1:</label>"
+ " <input type=\"text\" id=\"address1\" /><br />"
+ "<label for=\"address2\">Address line 2:</label>"
+ " <input type=\"text\" id=\"address2\" /><br />"
+ "<label for=\"city\">City:</label>"
+ " <input type=\"text\" id=\"city\" /><br />"
+ "<label for=\"state\">State:</label>"
+ " <select id=\"state\">"
+ " <option value=\"\" selected=\"yes\">--</option>"
+ " <option value=\"CA\">California</option>"
+ " <option value=\"TX\">Texas</option>"
+ " </select><br />"
+ "<label for=\"zip\">ZIP code:</label>"
+ " <input type=\"text\" id=\"zip\" /><br />"
+ "<label for=\"country\">Country:</label>"
+ " <select id=\"country\">"
+ " <option value=\"\" selected=\"yes\">--</option>"
+ " <option value=\"CA\">Canada</option>"
+ " <option value=\"US\">United States</option>"
+ " </select><br />"
+ "<label for=\"phone\">Phone number:</label>"
+ " <input type=\"text\" id=\"phone\" /><br />"
+ "</form>");
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
- browser(), GURL("data:text/html;charset=utf-8,"
- "<form action=\"http://www.google.com/\" method=\"POST\">"
- "<label for=\"firstname\">First name:</label>"
- " <input type=\"text\" id=\"firstname\""
- " onFocus=\"domAutomationController.send(true)\""
- " /><br />"
- "<label for=\"lastname\">Last name:</label>"
- " <input type=\"text\" id=\"lastname\" /><br />"
- "<label for=\"address1\">Address line 1:</label>"
- " <input type=\"text\" id=\"address1\" /><br />"
- "<label for=\"address2\">Address line 2:</label>"
- " <input type=\"text\" id=\"address2\" /><br />"
- "<label for=\"city\">City:</label>"
- " <input type=\"text\" id=\"city\" /><br />"
- "<label for=\"state\">State:</label>"
- " <select id=\"state\">"
- " <option value=\"\" selected=\"yes\">--</option>"
- " <option value=\"CA\">California</option>"
- " <option value=\"TX\">Texas</option>"
- " </select><br />"
- "<label for=\"zip\">ZIP code:</label>"
- " <input type=\"text\" id=\"zip\" /><br />"
- "<label for=\"country\">Country:</label>"
- " <select id=\"country\">"
- " <option value=\"\" selected=\"yes\">--</option>"
- " <option value=\"CA\">Canada</option>"
- " <option value=\"US\">United States</option>"
- " </select><br />"
- "<label for=\"phone\">Phone number:</label>"
- " <input type=\"text\" id=\"phone\" /><br />"
- "</form>")));
-
- ASSERT_NO_FATAL_FAILURE(ui_test_utils::ClickOnView(browser(),
- VIEW_ID_TAB_CONTAINER));
- ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(),
- VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
-
- RenderViewHost* render_view_host =
- browser()->GetSelectedTabContents()->render_view_host();
- bool result;
- ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
- render_view_host, L"", L"document.getElementById('firstname').focus();",
- &result));
- ASSERT_TRUE(result);
-
- // Start filling the first name field with "M" and wait for the popup to be
- // shown.
- ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait(
- browser(), app::VKEY_M, false, true, false, false,
- NotificationType::AUTOFILL_DID_SHOW_SUGGESTIONS,
- Source<RenderViewHost>(render_view_host)));
-
- // Press the down arrow to select the suggestion and preview the autofilled
- // form.
- ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait(
- browser(), app::VKEY_DOWN, false, false, false, false,
- NotificationType::AUTOFILL_DID_FILL_FORM_DATA,
- Source<RenderViewHost>(render_view_host)));
-
- // The previewed values should not be accessible to JavaScript.
- ExpectFieldValue(L"firstname", "M");
- ExpectFieldValue(L"lastname", "");
- ExpectFieldValue(L"address1", "");
- ExpectFieldValue(L"address2", "");
- ExpectFieldValue(L"city", "");
- ExpectFieldValue(L"state", "");
- ExpectFieldValue(L"zip", "");
- ExpectFieldValue(L"country", "");
- ExpectFieldValue(L"phone", "");
- // TODO(isherman): It would be nice to test that the previewed values are
- // displayed: http://crbug.com/57220
-
- // Press Enter to accept the autofill suggestions.
- ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait(
- browser(), app::VKEY_RETURN, false, false, false, false,
- NotificationType::AUTOFILL_DID_FILL_FORM_DATA,
- Source<RenderViewHost>(render_view_host)));
-
- // The form should be filled.
- ExpectFieldValue(L"firstname", "Milton");
- ExpectFieldValue(L"lastname", "Waddams");
- ExpectFieldValue(L"address1", "4120 Freidrich Lane");
- ExpectFieldValue(L"address2", "Basement");
- ExpectFieldValue(L"city", "Austin");
- ExpectFieldValue(L"state", "TX");
- ExpectFieldValue(L"zip", "78744");
- ExpectFieldValue(L"country", "US");
- ExpectFieldValue(L"phone", "5125551234");
+ browser(), url));
+
+ // Get translation bar.
+ int page_id = browser()->GetSelectedTabContents()->controller().
+ GetLastCommittedEntry()->page_id();
+ rvh()->OnMessageReceived(ViewHostMsg_PageContents(0, url, page_id,
+ UTF8ToUTF16("test"), "ja", true));
+ TranslateInfoBarDelegate* infobar = browser()->GetSelectedTabContents()->
+ GetInfoBarDelegateAt(0)->AsTranslateInfoBarDelegate();
+
+ ASSERT_TRUE(infobar != NULL);
+ EXPECT_EQ(TranslateInfoBarDelegate::BEFORE_TRANSLATE, infobar->type());
+
+ // Simulate press translation button.
+ infobar->Translate();
+
+ // Simulate the translate script being retrieved.
+ // Pass fake google.translate lib as the translate script.
+ SimulateURLFetch(true);
+
+ // Simulate translation to kick onTranslateElementLoad.
+ // But right now, the call stucks here.
+ // Once click the text field, it starts again.
+ ASSERT_TRUE(ui_test_utils::ExecuteJavaScript(
+ rvh(), L"", L"cr.googleTranslate.onTranslateElementLoad();"));
+
+ // Simulate the render notifying the translation has been done.
+ ui_test_utils::WaitForNotification(NotificationType::PAGE_TRANSLATED);
+
+ TryBasicFormFillWithMKey();
}
diff --git a/chrome/browser/autofill/autofill_cc_infobar_delegate.cc b/chrome/browser/autofill/autofill_cc_infobar_delegate.cc
index 01b49eb..a57c6e3 100644
--- a/chrome/browser/autofill/autofill_cc_infobar_delegate.cc
+++ b/chrome/browser/autofill/autofill_cc_infobar_delegate.cc
@@ -11,7 +11,6 @@
#include "chrome/browser/autofill/autofill_manager.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
#include "chrome/common/pref_names.h"
diff --git a/chrome/browser/autofill/autofill_common_test.cc b/chrome/browser/autofill/autofill_common_test.cc
index 32041cc..050703c 100644
--- a/chrome/browser/autofill/autofill_common_test.cc
+++ b/chrome/browser/autofill/autofill_common_test.cc
@@ -9,7 +9,7 @@
#include "chrome/browser/autofill/credit_card.h"
#include "chrome/browser/password_manager/encryptor.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "webkit/glue/form_field.h"
diff --git a/chrome/browser/autofill/autofill_credit_card_model_mac_unittest.mm b/chrome/browser/autofill/autofill_credit_card_model_mac_unittest.mm
index e95c2dd..5be95d1 100644
--- a/chrome/browser/autofill/autofill_credit_card_model_mac_unittest.mm
+++ b/chrome/browser/autofill/autofill_credit_card_model_mac_unittest.mm
@@ -7,8 +7,8 @@
#include "chrome/browser/autofill/autofill_common_test.h"
#import "chrome/browser/autofill/autofill_credit_card_model_mac.h"
#include "chrome/browser/autofill/credit_card.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
diff --git a/chrome/browser/autofill/autofill_credit_card_sheet_controller_mac_unittest.mm b/chrome/browser/autofill/autofill_credit_card_sheet_controller_mac_unittest.mm
index 6f943ea..eb2bce5 100644
--- a/chrome/browser/autofill/autofill_credit_card_sheet_controller_mac_unittest.mm
+++ b/chrome/browser/autofill/autofill_credit_card_sheet_controller_mac_unittest.mm
@@ -6,8 +6,8 @@
#include "base/utf_string_conversions.h"
#import "chrome/browser/autofill/autofill_credit_card_sheet_controller_mac.h"
#include "chrome/browser/autofill/credit_card.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
diff --git a/chrome/browser/autofill/autofill_dialog_controller_mac.h b/chrome/browser/autofill/autofill_dialog_controller_mac.h
index 4ebf2d6..642e811 100644
--- a/chrome/browser/autofill/autofill_dialog_controller_mac.h
+++ b/chrome/browser/autofill/autofill_dialog_controller_mac.h
@@ -9,7 +9,7 @@
#import <Cocoa/Cocoa.h>
#include <vector>
-#import "base/cocoa_protocols_mac.h"
+#import "base/mac/cocoa_protocols.h"
#include "base/scoped_nsobject.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/autofill/autofill_dialog.h"
diff --git a/chrome/browser/autofill/autofill_dialog_controller_mac.mm b/chrome/browser/autofill/autofill_dialog_controller_mac.mm
index d2df304..713c172 100644
--- a/chrome/browser/autofill/autofill_dialog_controller_mac.mm
+++ b/chrome/browser/autofill/autofill_dialog_controller_mac.mm
@@ -5,18 +5,19 @@
#import "chrome/browser/autofill/autofill_dialog_controller_mac.h"
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
+#include "base/lazy_instance.h"
#include "base/mac_util.h"
-#include "base/singleton.h"
#include "base/sys_string_conversions.h"
#import "chrome/browser/autofill/autofill_address_model_mac.h"
#import "chrome/browser/autofill/autofill_address_sheet_controller_mac.h"
#import "chrome/browser/autofill/autofill_credit_card_model_mac.h"
#import "chrome/browser/autofill/autofill_credit_card_sheet_controller_mac.h"
+#import "chrome/browser/autofill/autofill-inl.h"
#import "chrome/browser/autofill/personal_data_manager.h"
#include "chrome/browser/browser_process.h"
-#import "chrome/browser/cocoa/window_size_autosaver.h"
+#import "chrome/browser/ui/cocoa/window_size_autosaver.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/common/notification_details.h"
@@ -32,6 +33,9 @@ namespace {
// dialog.
typedef std::map<Profile*, AutoFillDialogController*> ProfileControllerMap;
+static base::LazyInstance<ProfileControllerMap> g_profile_controller_map(
+ base::LINKER_INITIALIZED);
+
} // namespace
// Delegate protocol that needs to be in place for the AutoFillTableView's
@@ -91,6 +95,14 @@ typedef std::map<Profile*, AutoFillDialogController*> ProfileControllerMap;
// UI.
- (void)preferenceDidChange:(const std::string&)preferenceName;
+// Adjust the selected index when underlying data changes.
+// Selects the previous row if possible, else current row, else deselect all.
+- (void) adjustSelectionOnDelete:(NSInteger)selectedRow;
+
+// Adjust the selected index when underlying data changes.
+// Selects the current row if possible, else previous row, else deselect all.
+- (void) adjustSelectionOnReload:(NSInteger)selectedRow;
+
// Returns true if |row| is an index to a valid profile in |tableView_|, and
// false otherwise.
- (BOOL)isProfileRow:(NSInteger)row;
@@ -268,7 +280,7 @@ class PreferenceObserver : public NotificationObserver {
[self autorelease];
// Remove ourself from the map.
- ProfileControllerMap* map = Singleton<ProfileControllerMap>::get();
+ ProfileControllerMap* map = g_profile_controller_map.Pointer();
ProfileControllerMap::iterator it = map->find(profile_);
if (it != map->end()) {
map->erase(it);
@@ -329,7 +341,7 @@ class PreferenceObserver : public NotificationObserver {
// Create a new address and save it to the |profiles_| list.
AutoFillProfile newAddress;
[addressSheetController copyModelToProfile:&newAddress];
- if (!newAddress.IsEmpty()) {
+ if (!newAddress.IsEmpty() && !FindByContents(profiles_, newAddress)) {
profiles_.push_back(newAddress);
// Saving will save to the PDM and the table will refresh when PDM sends
@@ -356,7 +368,8 @@ class PreferenceObserver : public NotificationObserver {
// Create a new credit card and save it to the |creditCards_| list.
CreditCard newCreditCard;
[creditCardSheetController copyModelToCreditCard:&newCreditCard];
- if (!newCreditCard.IsEmpty()) {
+ if (!newCreditCard.IsEmpty() &&
+ !FindByContents(creditCards_, newCreditCard)) {
creditCards_.push_back(newCreditCard);
// Saving will save to the PDM and the table will refresh when PDM sends
@@ -397,15 +410,7 @@ class PreferenceObserver : public NotificationObserver {
}
// Select the previous row if possible, else current row, else deselect all.
- if ([self tableView:tableView_ shouldSelectRow:selectedRow-1]) {
- [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:selectedRow-1]
- byExtendingSelection:NO];
- } else if ([self tableView:tableView_ shouldSelectRow:selectedRow]) {
- [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:selectedRow]
- byExtendingSelection:NO];
- } else {
- [tableView_ deselectAll:self];
- }
+ [self adjustSelectionOnDelete:selectedRow];
// Saving will save to the PDM and the table will refresh when PDM sends
// notification that the underlying model has changed.
@@ -633,7 +638,7 @@ class PreferenceObserver : public NotificationObserver {
profile:(Profile*)profile {
profile = profile->GetOriginalProfile();
- ProfileControllerMap* map = Singleton<ProfileControllerMap>::get();
+ ProfileControllerMap* map = g_profile_controller_map.Pointer();
DCHECK(map != NULL);
ProfileControllerMap::iterator it = map->find(profile);
if (it == map->end()) {
@@ -796,6 +801,7 @@ class PreferenceObserver : public NotificationObserver {
iter != creditCards.end(); ++iter)
creditCards_.push_back(**iter);
+ [self adjustSelectionOnReload:[tableView_ selectedRow]];
[tableView_ reloadData];
}
@@ -812,6 +818,30 @@ class PreferenceObserver : public NotificationObserver {
}
}
+- (void) adjustSelectionOnDelete:(NSInteger)selectedRow {
+ if ([self tableView:tableView_ shouldSelectRow:selectedRow-1]) {
+ [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:selectedRow-1]
+ byExtendingSelection:NO];
+ } else if ([self tableView:tableView_ shouldSelectRow:selectedRow]) {
+ [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:selectedRow]
+ byExtendingSelection:NO];
+ } else {
+ [tableView_ deselectAll:self];
+ }
+}
+
+- (void) adjustSelectionOnReload:(NSInteger)selectedRow {
+ if ([self tableView:tableView_ shouldSelectRow:selectedRow]) {
+ [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:selectedRow]
+ byExtendingSelection:NO];
+ } else if ([self tableView:tableView_ shouldSelectRow:selectedRow-1]) {
+ [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:selectedRow-1]
+ byExtendingSelection:NO];
+ } else {
+ [tableView_ deselectAll:self];
+ }
+}
+
- (BOOL)isProfileRow:(NSInteger)row {
if (row > 0 && static_cast<size_t>(row) <= profiles_.size())
return YES;
diff --git a/chrome/browser/autofill/autofill_dialog_controller_mac_unittest.mm b/chrome/browser/autofill/autofill_dialog_controller_mac_unittest.mm
index 71c9ae8..bc2bb40 100644
--- a/chrome/browser/autofill/autofill_dialog_controller_mac_unittest.mm
+++ b/chrome/browser/autofill/autofill_dialog_controller_mac_unittest.mm
@@ -12,10 +12,10 @@
#import "chrome/browser/autofill/autofill_dialog_controller_mac.h"
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/personal_data_manager.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_pref_service.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/autofill/autofill_dialog_gtk.cc b/chrome/browser/autofill/autofill_dialog_gtk.cc
index 46708e9..b35ad90 100644
--- a/chrome/browser/autofill/autofill_dialog_gtk.cc
+++ b/chrome/browser/autofill/autofill_dialog_gtk.cc
@@ -27,7 +27,7 @@
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/common/notification_details.h"
diff --git a/chrome/browser/autofill/autofill_dialog_mac.mm b/chrome/browser/autofill/autofill_dialog_mac.mm
index f97bad9..ca611c4 100644
--- a/chrome/browser/autofill/autofill_dialog_mac.mm
+++ b/chrome/browser/autofill/autofill_dialog_mac.mm
@@ -5,7 +5,7 @@
#import "chrome/browser/autofill/autofill_dialog_controller_mac.h"
#include "chrome/browser/autofill/autofill_dialog.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
// Mac implementation of |ShowAutoFillDialog| interface defined in
diff --git a/chrome/browser/autofill/autofill_download.cc b/chrome/browser/autofill/autofill_download.cc
index 1354a96..9e8504f 100644
--- a/chrome/browser/autofill/autofill_download.cc
+++ b/chrome/browser/autofill/autofill_download.cc
@@ -13,7 +13,7 @@
#include "chrome/browser/autofill/autofill_metrics.h"
#include "chrome/browser/autofill/autofill_xml_parser.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "net/http/http_response_headers.h"
@@ -67,7 +67,8 @@ void AutoFillDownloadManager::SetObserver(
}
bool AutoFillDownloadManager::StartQueryRequest(
- const ScopedVector<FormStructure>& forms) {
+ const ScopedVector<FormStructure>& forms,
+ const AutoFillMetrics& metric_logger) {
if (next_query_request_ > base::Time::Now()) {
// We are in back-off mode: do not do the request.
return false;
@@ -79,7 +80,7 @@ bool AutoFillDownloadManager::StartQueryRequest(
return false;
request_data.request_type = AutoFillDownloadManager::REQUEST_QUERY;
- autofill_metrics::LogServerQueryMetric(autofill_metrics::QUERY_SENT);
+ metric_logger.Log(AutoFillMetrics::QUERY_SENT);
return StartRequest(form_xml, request_data);
}
diff --git a/chrome/browser/autofill/autofill_download.h b/chrome/browser/autofill/autofill_download.h
index a3a66fd..9220ad1 100644
--- a/chrome/browser/autofill/autofill_download.h
+++ b/chrome/browser/autofill/autofill_download.h
@@ -16,10 +16,14 @@
#include "chrome/browser/autofill/form_structure.h"
#include "chrome/common/net/url_fetcher.h"
+<<<<<<< HEAD
#ifdef ANDROID
#include "android/autofill/url_fetcher_proxy.h"
#endif
+=======
+class AutoFillMetrics;
+>>>>>>> chromium.org at r10.0.621.0
class Profile;
// Handles getting and updating AutoFill heuristics.
@@ -64,7 +68,8 @@ class AutoFillDownloadManager : public URLFetcher::Delegate {
// Starts a query request to AutoFill servers. The observer is called with the
// list of the fields of all requested forms.
// |forms| - array of forms aggregated in this request.
- bool StartQueryRequest(const ScopedVector<FormStructure>& forms);
+ bool StartQueryRequest(const ScopedVector<FormStructure>& forms,
+ const AutoFillMetrics& metric_logger);
// Start upload request if necessary. The probability of request going
// over the wire are GetPositiveUploadRate() if it was matched by
diff --git a/chrome/browser/autofill/autofill_download_unittest.cc b/chrome/browser/autofill/autofill_download_unittest.cc
index 68173c6..a2f9d78 100644
--- a/chrome/browser/autofill/autofill_download_unittest.cc
+++ b/chrome/browser/autofill/autofill_download_unittest.cc
@@ -8,9 +8,11 @@
#include "base/test/test_timeouts.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_download.h"
+#include "chrome/browser/autofill/autofill_metrics.h"
#include "chrome/common/net/test_url_fetcher_factory.h"
#include "chrome/test/testing_profile.h"
#include "net/url_request/url_request_status.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/WebKit/chromium/public/WebInputElement.h"
#include "webkit/glue/form_data.h"
@@ -18,6 +20,19 @@
using webkit_glue::FormData;
using WebKit::WebInputElement;
+namespace {
+
+class MockAutoFillMetrics : public AutoFillMetrics {
+ public:
+ MockAutoFillMetrics() {}
+ MOCK_CONST_METHOD1(Log, void(ServerQueryMetric metric));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockAutoFillMetrics);
+};
+
+} // namespace
+
// This tests AutoFillDownloadManager. AutoFillDownloadTestHelper implements
// AutoFillDownloadManager::Observer and creates an instance of
// AutoFillDownloadManager. Then it records responses to different initiated
@@ -86,8 +101,6 @@ class AutoFillDownloadTestHelper : public AutoFillDownloadManager::Observer {
AutoFillDownloadManager download_manager;
};
-namespace {
-
TEST(AutoFillDownloadTest, QueryAndUploadTest) {
MessageLoopForUI message_loop;
// Create and register factory.
@@ -173,7 +186,10 @@ TEST(AutoFillDownloadTest, QueryAndUploadTest) {
form_structures.push_back(form_structure);
// Request with id 0.
- EXPECT_TRUE(helper.download_manager.StartQueryRequest(form_structures));
+ MockAutoFillMetrics mock_metric_logger;
+ EXPECT_CALL(mock_metric_logger, Log(AutoFillMetrics::QUERY_SENT)).Times(1);
+ EXPECT_TRUE(helper.download_manager.StartQueryRequest(form_structures,
+ mock_metric_logger));
// Set upload to 100% so requests happen.
helper.download_manager.SetPositiveUploadRate(1.0);
helper.download_manager.SetNegativeUploadRate(1.0);
@@ -258,7 +274,9 @@ TEST(AutoFillDownloadTest, QueryAndUploadTest) {
EXPECT_EQ(NULL, fetcher);
// Request with id 3.
- EXPECT_TRUE(helper.download_manager.StartQueryRequest(form_structures));
+ EXPECT_CALL(mock_metric_logger, Log(AutoFillMetrics::QUERY_SENT)).Times(1);
+ EXPECT_TRUE(helper.download_manager.StartQueryRequest(form_structures,
+ mock_metric_logger));
fetcher = factory.GetFetcherByID(3);
ASSERT_TRUE(fetcher);
fetcher->set_backoff_delay(
@@ -274,7 +292,9 @@ TEST(AutoFillDownloadTest, QueryAndUploadTest) {
helper.responses_.pop_front();
// Query requests should be ignored for the next 10 seconds.
- EXPECT_FALSE(helper.download_manager.StartQueryRequest(form_structures));
+ EXPECT_CALL(mock_metric_logger, Log(AutoFillMetrics::QUERY_SENT)).Times(0);
+ EXPECT_FALSE(helper.download_manager.StartQueryRequest(form_structures,
+ mock_metric_logger));
fetcher = factory.GetFetcherByID(4);
EXPECT_EQ(NULL, fetcher);
@@ -304,5 +324,3 @@ TEST(AutoFillDownloadTest, QueryAndUploadTest) {
// Make sure consumer of URLFetcher does the right thing.
URLFetcher::set_factory(NULL);
}
-
-} // namespace
diff --git a/chrome/browser/autofill/autofill_editor_gtk.cc b/chrome/browser/autofill/autofill_editor_gtk.cc
index 21f7ef3..3cdec02 100644
--- a/chrome/browser/autofill/autofill_editor_gtk.cc
+++ b/chrome/browser/autofill/autofill_editor_gtk.cc
@@ -18,7 +18,7 @@
#include "chrome/browser/autofill/personal_data_manager.h"
#include "chrome/browser/autofill/phone_number.h"
#include "chrome/browser/gtk/gtk_util.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "grit/app_resources.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
diff --git a/chrome/browser/autofill/autofill_field.cc b/chrome/browser/autofill/autofill_field.cc
index cd41b65..74a6368 100644
--- a/chrome/browser/autofill/autofill_field.cc
+++ b/chrome/browser/autofill/autofill_field.cc
@@ -41,11 +41,14 @@ AutoFillField::AutoFillField(const webkit_glue::FormField& field,
AutoFillField::~AutoFillField() {}
void AutoFillField::set_heuristic_type(const AutoFillFieldType& type) {
- DCHECK(type >= 0 && type < MAX_VALID_FIELD_TYPE);
- if (type >= 0 && type < MAX_VALID_FIELD_TYPE)
+ if (type >= 0 && type < MAX_VALID_FIELD_TYPE) {
heuristic_type_ = type;
- else
+ } else {
+ NOTREACHED();
+ // This case should not be reachable; but since this has potential
+ // implications on data uploaded to the server, better safe than sorry.
heuristic_type_ = UNKNOWN_TYPE;
+ }
}
AutoFillFieldType AutoFillField::type() const {
diff --git a/chrome/browser/autofill/autofill_ie_toolbar_import_win.cc b/chrome/browser/autofill/autofill_ie_toolbar_import_win.cc
index 05b7ade..2350607 100644
--- a/chrome/browser/autofill/autofill_ie_toolbar_import_win.cc
+++ b/chrome/browser/autofill/autofill_ie_toolbar_import_win.cc
@@ -249,9 +249,6 @@ bool ImportCurrentUserProfiles(std::vector<AutoFillProfile>* profiles,
}
bool ImportAutofillDataWin(PersonalDataManager* pdm) {
- // In incognito mode we do not have PDM - and we should not import anything.
- if (!pdm)
- return false;
AutoFillImporter *importer = new AutoFillImporter(pdm);
// importer will self delete.
return importer->ImportProfiles();
diff --git a/chrome/browser/autofill/autofill_manager.cc b/chrome/browser/autofill/autofill_manager.cc
index 1e4d201..1d813c8 100644
--- a/chrome/browser/autofill/autofill_manager.cc
+++ b/chrome/browser/autofill/autofill_manager.cc
@@ -15,17 +15,22 @@
#include "chrome/browser/autofill/autofill_cc_infobar_delegate.h"
#endif
#include "chrome/browser/autofill/autofill_dialog.h"
+#include "chrome/browser/autofill/autofill_metrics.h"
#include "chrome/browser/autofill/form_structure.h"
#include "chrome/browser/autofill/phone_number.h"
#include "chrome/browser/autofill/select_control_handler.h"
-#include "chrome/browser/guid.h"
#include "chrome/browser/prefs/pref_service.h"
+<<<<<<< HEAD
#include "chrome/browser/profile.h"
#ifndef ANDROID
+=======
+#include "chrome/browser/profiles/profile.h"
+>>>>>>> chromium.org at r10.0.621.0
#include "chrome/browser/renderer_host/render_view_host.h"
#endif
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/guid.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#ifndef ANDROID
@@ -138,6 +143,7 @@ AutoFillManager::AutoFillManager(TabContents* tab_contents)
personal_data_(NULL),
download_manager_(tab_contents_->profile()),
disable_download_manager_requests_(false),
+ metric_logger_(new AutoFillMetrics),
cc_infobar_(NULL) {
DCHECK(tab_contents);
@@ -184,12 +190,17 @@ void AutoFillManager::FormSubmitted(const FormData& form) {
// Grab a copy of the form data.
upload_form_structure_.reset(new FormStructure(form));
+ // Disregard forms that we wouldn't ever autofill in the first place.
+ if (!upload_form_structure_->ShouldBeParsed(true))
+ return;
+
+ DeterminePossibleFieldTypesForUpload();
+ // TODO(isherman): Consider uploading to server here rather than in
+ // HandleSubmit().
+
if (!upload_form_structure_->IsAutoFillable(true))
return;
- // Determine the possible field types and upload the form structure to the
- // PersonalDataManager.
- DeterminePossibleFieldTypes(upload_form_structure_.get());
HandleSubmit();
}
@@ -266,8 +277,9 @@ bool AutoFillManager::GetAutoFillSuggestions(const FormData& form,
#endif
// If the form is auto-filled and the renderer is querying for suggestions,
- // then the user is editing the value of a field. In this case, mimick
- // autocomplete: don't display or icons, as that information is redundant.
+ // then the user is editing the value of a field. In this case, mimic
+ // autocomplete: don't display labels or icons, as that information is
+ // redundant.
if (FormIsAutoFilled(form_structure, form, is_filling_credit_card)) {
labels.assign(labels.size(), string16());
icons.assign(icons.size(), string16());
@@ -419,7 +431,8 @@ void AutoFillManager::OnLoadedAutoFillHeuristics(
UploadRequired upload_required;
FormStructure::ParseQueryResponse(heuristic_xml,
form_structures_.get(),
- &upload_required);
+ &upload_required,
+ *metric_logger_);
}
void AutoFillManager::OnUploadedAutoFillHeuristics(
@@ -450,13 +463,38 @@ bool AutoFillManager::IsAutoFillEnabled() const {
return prefs->GetBoolean(prefs::kAutoFillEnabled);
}
-void AutoFillManager::DeterminePossibleFieldTypes(
- FormStructure* form_structure) {
- for (size_t i = 0; i < form_structure->field_count(); i++) {
- const AutoFillField* field = form_structure->field(i);
+void AutoFillManager::DeterminePossibleFieldTypesForUpload() {
+ for (size_t i = 0; i < upload_form_structure_->field_count(); i++) {
+ const AutoFillField* field = upload_form_structure_->field(i);
FieldTypeSet field_types;
personal_data_->GetPossibleFieldTypes(field->value(), &field_types);
- form_structure->set_possible_types(i, field_types);
+ DCHECK(!field_types.empty());
+ upload_form_structure_->set_possible_types(i, field_types);
+
+ if (field->form_control_type() == ASCIIToUTF16("select-one")) {
+ // TODO(isherman): <select> fields don't support |is_autofilled()|. Since
+ // this is heavily relied upon by our metrics, we just don't log anything
+ // for all <select> fields. Better to have less data than misleading data.
+ continue;
+ }
+
+ // Log various quality metrics.
+ metric_logger_->Log(AutoFillMetrics::FIELD_SUBMITTED);
+ if (field_types.find(EMPTY_TYPE) == field_types.end() &&
+ field_types.find(UNKNOWN_TYPE) == field_types.end()) {
+ if (field->is_autofilled())
+ metric_logger_->Log(AutoFillMetrics::FIELD_AUTOFILLED);
+ else
+ metric_logger_->Log(AutoFillMetrics::FIELD_AUTOFILL_FAILED);
+
+ // TODO(isherman): Other things we might want to log here:
+ // * Did the field's heuristic type match the PDM type?
+ // * Per Vadim's email, a combination of (1) whether heuristics fired,
+ // (2) whether the server returned something interesting, (3) whether
+ // the user filled the field
+ // * Whether the server type matches the heursitic type
+ // - Perhaps only if at least one of the types is not unknown/no data.
+ }
}
}
@@ -522,7 +560,8 @@ AutoFillManager::AutoFillManager()
: tab_contents_(NULL),
personal_data_(NULL),
download_manager_(NULL),
- disable_download_manager_requests_(false),
+ disable_download_manager_requests_(true),
+ metric_logger_(new AutoFillMetrics),
cc_infobar_(NULL) {
}
@@ -531,11 +570,17 @@ AutoFillManager::AutoFillManager(TabContents* tab_contents,
: tab_contents_(tab_contents),
personal_data_(personal_data),
download_manager_(NULL),
- disable_download_manager_requests_(false),
+ disable_download_manager_requests_(true),
+ metric_logger_(new AutoFillMetrics),
cc_infobar_(NULL) {
DCHECK(tab_contents);
}
+void AutoFillManager::set_metric_logger(
+ const AutoFillMetrics* metric_logger) {
+ metric_logger_.reset(metric_logger);
+}
+
bool AutoFillManager::GetHost(const std::vector<AutoFillProfile*>& profiles,
const std::vector<CreditCard*>& credit_cards,
#ifdef ANDROID
@@ -640,8 +685,8 @@ void AutoFillManager::GetProfileSuggestions(FormStructure* form,
form_fields.push_back((*iter)->type());
}
- AutoFillProfile::CreateInferredLabels(&matched_profiles, labels, 1,
- type.field_type(), &form_fields);
+ AutoFillProfile::CreateInferredLabels(&matched_profiles, &form_fields,
+ type.field_type(), 1, labels);
// No icons for profile suggestions.
icons->resize(values->size());
@@ -735,8 +780,6 @@ void AutoFillManager::ParseForms(const std::vector<FormData>& forms) {
if (!form_structure->ShouldBeParsed(false))
continue;
- DeterminePossibleFieldTypes(form_structure.get());
-
// Set aside forms with method GET so that they are not included in the
// query to the server.
if (form_structure->ShouldBeParsed(true))
@@ -746,8 +789,10 @@ void AutoFillManager::ParseForms(const std::vector<FormData>& forms) {
}
// If none of the forms were parsed, no use querying the server.
- if (!form_structures_.empty() && !disable_download_manager_requests_)
- download_manager_.StartQueryRequest(form_structures_);
+ if (!form_structures_.empty() && !disable_download_manager_requests_) {
+ download_manager_.StartQueryRequest(form_structures_,
+ *metric_logger_);
+ }
for (std::vector<FormStructure *>::const_iterator iter =
non_queryable_forms.begin();
diff --git a/chrome/browser/autofill/autofill_manager.h b/chrome/browser/autofill/autofill_manager.h
index e516472..bb0d67e 100644
--- a/chrome/browser/autofill/autofill_manager.h
+++ b/chrome/browser/autofill/autofill_manager.h
@@ -24,6 +24,7 @@
class AutoFillCCInfoBarDelegate;
#endif
class AutoFillProfile;
+class AutoFillMetrics;
class CreditCard;
class FormStructure;
class PrefService;
@@ -68,14 +69,12 @@ class AutoFillManager :
const webkit_glue::FormField& field,
int unique_id);
virtual void ShowAutoFillDialog();
+ virtual void Reset();
// Called by the AutoFillCCInfoBarDelegate when the user interacts with the
// infobar.
virtual void OnInfoBarClosed(bool should_save);
- // Resets the stored form data.
- virtual void Reset();
-
// AutoFillDownloadManager::Observer implementation:
virtual void OnLoadedAutoFillHeuristics(const std::string& heuristic_xml);
virtual void OnUploadedAutoFillHeuristics(const std::string& form_signature);
@@ -87,10 +86,6 @@ class AutoFillManager :
// Returns the value of the AutoFillEnabled pref.
virtual bool IsAutoFillEnabled() const;
- // Uses heuristics and existing personal data to determine the possible field
- // types.
- void DeterminePossibleFieldTypes(FormStructure* form_structure);
-
// Handles the form data submitted by the user.
void HandleSubmit();
@@ -107,6 +102,11 @@ class AutoFillManager :
personal_data_ = personal_data;
}
+ const AutoFillMetrics* metric_logger() const {
+ return metric_logger_.get();
+ }
+ void set_metric_logger(const AutoFillMetrics* metric_logger);
+
// Maps GUIDs to and from IDs that are used to identify profiles and credit
// cards sent to and from the renderer process.
virtual int GUIDToID(const std::string& guid);
@@ -177,10 +177,9 @@ class AutoFillManager :
// Parses the forms using heuristic matching and querying the AutoFill server.
void ParseForms(const std::vector<webkit_glue::FormData>& forms);
- // The following function is meant to be called from unit-test only.
- void set_disable_download_manager_requests(bool value) {
- disable_download_manager_requests_ = value;
- }
+ // Uses existing personal data to determine possible field types for the
+ // |upload_form_structure_|.
+ void DeterminePossibleFieldTypesForUpload();
// The TabContents hosting this AutoFillManager.
// Weak reference.
@@ -199,9 +198,13 @@ class AutoFillManager :
// Should be set to true in AutoFillManagerTest and other tests, false in
// AutoFillDownloadManagerTest and in non-test environment. Is false by
- // default.
+ // default for the public constructor, and true by default for the test-only
+ // constructors.
bool disable_download_manager_requests_;
+ // For logging UMA metrics. Overridden by metrics tests.
+ scoped_ptr<const AutoFillMetrics> metric_logger_;
+
// Our copy of the form data.
ScopedVector<FormStructure> form_structures_;
@@ -222,7 +225,6 @@ class AutoFillManager :
std::map<int, std::string> id_guid_map_;
friend class FormStructureBrowserTest;
- friend class TestAutoFillManager;
FRIEND_TEST_ALL_PREFIXES(AutoFillManagerTest, FillCreditCardForm);
FRIEND_TEST_ALL_PREFIXES(AutoFillManagerTest, FillAddressForm);
FRIEND_TEST_ALL_PREFIXES(AutoFillManagerTest, FillAddressAndCreditCardForm);
diff --git a/chrome/browser/autofill/autofill_manager_unittest.cc b/chrome/browser/autofill/autofill_manager_unittest.cc
index 06af660..b454143 100644
--- a/chrome/browser/autofill/autofill_manager_unittest.cc
+++ b/chrome/browser/autofill/autofill_manager_unittest.cc
@@ -19,7 +19,7 @@
#include "chrome/browser/autofill/credit_card.h"
#include "chrome/browser/autofill/personal_data_manager.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/test/test_render_view_host.h"
#include "chrome/browser/tab_contents/test_tab_contents.h"
#include "chrome/common/ipc_test_sink.h"
@@ -183,7 +183,7 @@ void CreateTestAddressFormData(FormData* form) {
form->fields.push_back(field);
}
-// Populates |form| with data corresponding to a simple credit card form, with.
+// Populates |form| with data corresponding to a simple credit card form.
// Note that this actually appends fields to the form data, which can be useful
// for building up more complex test forms.
void CreateTestCreditCardFormData(FormData* form, bool is_https) {
@@ -364,19 +364,13 @@ void ExpectFilledCreditCardFormElvis(int page_id,
has_address_fields, true);
}
-} // namespace
-
class TestAutoFillManager : public AutoFillManager {
public:
TestAutoFillManager(TabContents* tab_contents,
TestPersonalDataManager* personal_manager)
- : AutoFillManager(tab_contents, NULL),
+ : AutoFillManager(tab_contents, personal_manager),
autofill_enabled_(true) {
test_personal_data_ = personal_manager;
- set_personal_data_manager(personal_manager);
- // Download manager requests are disabled for purposes of this unit test.
- // These requests are tested in autofill_download_unittest.cc.
- set_disable_download_manager_requests(true);
}
virtual bool IsAutoFillEnabled() const { return autofill_enabled_; }
@@ -425,6 +419,8 @@ class TestAutoFillManager : public AutoFillManager {
DISALLOW_COPY_AND_ASSIGN(TestAutoFillManager);
};
+} // namespace
+
class AutoFillManagerTest : public RenderViewHostTestHarness {
public:
AutoFillManagerTest() {}
diff --git a/chrome/browser/autofill/autofill_metrics.cc b/chrome/browser/autofill/autofill_metrics.cc
index 85b5517..bae11d7 100644
--- a/chrome/browser/autofill/autofill_metrics.cc
+++ b/chrome/browser/autofill/autofill_metrics.cc
@@ -6,13 +6,22 @@
#include "base/metrics/histogram.h"
-namespace autofill_metrics {
+AutoFillMetrics::AutoFillMetrics() {
+}
+
+AutoFillMetrics::~AutoFillMetrics() {
+}
-void LogServerQueryMetric(ServerQueryMetricType type) {
- DCHECK(type < NUM_SERVER_QUERY_METRICS);
+void AutoFillMetrics::Log(ServerQueryMetric metric) const {
+ DCHECK(metric < NUM_SERVER_QUERY_METRICS);
- UMA_HISTOGRAM_ENUMERATION("AutoFill.ServerQueryResponse", type,
+ UMA_HISTOGRAM_ENUMERATION("AutoFill.ServerQueryResponse", metric,
NUM_SERVER_QUERY_METRICS);
}
-} // namespace autofill_metrics
+void AutoFillMetrics::Log(QualityMetric metric) const {
+ DCHECK(metric < NUM_QUALITY_METRICS);
+
+ UMA_HISTOGRAM_ENUMERATION("AutoFill.Quality", metric,
+ NUM_QUALITY_METRICS);
+}
diff --git a/chrome/browser/autofill/autofill_metrics.h b/chrome/browser/autofill/autofill_metrics.h
index d461668..6318274 100644
--- a/chrome/browser/autofill/autofill_metrics.h
+++ b/chrome/browser/autofill/autofill_metrics.h
@@ -6,32 +6,56 @@
#define CHROME_BROWSER_AUTOFILL_AUTOFILL_METRICS_H_
#pragma once
-namespace autofill_metrics {
-
-// Each of these should be logged at most once per query to the server, which in
-// turn should occur at most once per page load.
-enum ServerQueryMetricType {
- // Logged for each query sent to the server
- QUERY_SENT = 0,
- // Logged for each query response received from the server
- QUERY_RESPONSE_RECEIVED,
- // Logged for each parsable response received from the server
- QUERY_RESPONSE_PARSED,
- // Logged for each parsable response that provided no improvements relative to
- // our heuristics.
- QUERY_RESPONSE_MATCHED_LOCAL_HEURISTICS,
- // Logged for each page for which our heuristics detected at least one
- // auto-fillable field, but the server response overrode the type of at least
- // one field
- QUERY_RESPONSE_OVERRODE_LOCAL_HEURISTICS,
- // Logged for each page for which our heuristics did not detect any
- // auto-fillable fields, but the server response did detect some.
- QUERY_RESPONSE_WITH_NO_LOCAL_HEURISTICS,
- NUM_SERVER_QUERY_METRICS
-};
+#include "base/basictypes.h"
+
+class AutoFillMetrics {
+ public:
+ // Each of these is logged at most once per query to the server, which in turn
+ // occurs at most once per page load.
+ enum ServerQueryMetric {
+ // Logged for each query sent to the server.
+ QUERY_SENT = 0,
+ // Logged for each query response received from the server.
+ QUERY_RESPONSE_RECEIVED,
+ // Logged for each parsable response received from the server.
+ QUERY_RESPONSE_PARSED,
+ // Logged for each parsable response that provided no improvements relative
+ // to our heuristics.
+ QUERY_RESPONSE_MATCHED_LOCAL_HEURISTICS,
+ // Logged for each page for which our heuristics detected at least one
+ // auto-fillable field, but the server response overrode the type of at
+ // least one field.
+ QUERY_RESPONSE_OVERRODE_LOCAL_HEURISTICS,
+ // Logged for each page for which our heuristics did not detect any
+ // auto-fillable fields, but the server response did detect some.
+ QUERY_RESPONSE_WITH_NO_LOCAL_HEURISTICS,
+ NUM_SERVER_QUERY_METRICS
+ };
+
+ // Each of these is logged at most once per form submission.
+ enum QualityMetric {
+ // Logged for each field in a submitted form.
+ FIELD_SUBMITTED = 0,
+ // A simple successs metric, logged for each field that returns true for
+ // |is_autofilled()| and has a value that is present in the personal data
+ // manager. There is a small chance of false positives from filling via
+ // autocomplete rather than autofill.
+ FIELD_AUTOFILLED,
+ // A simple failure metric, logged for each field that returns false for
+ // |is_autofilled()| but as a value that is present in the personal data
+ // manager.
+ FIELD_AUTOFILL_FAILED,
+ NUM_QUALITY_METRICS
+ };
-void LogServerQueryMetric(ServerQueryMetricType type);
+ AutoFillMetrics();
+ virtual ~AutoFillMetrics();
-} // namespace autofill_metrics
+ virtual void Log(ServerQueryMetric metric) const;
+ virtual void Log(QualityMetric metric) const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AutoFillMetrics);
+};
#endif // CHROME_BROWSER_AUTOFILL_AUTOFILL_METRICS_H_
diff --git a/chrome/browser/autofill/autofill_metrics_unittest.cc b/chrome/browser/autofill/autofill_metrics_unittest.cc
new file mode 100644
index 0000000..4521296
--- /dev/null
+++ b/chrome/browser/autofill/autofill_metrics_unittest.cc
@@ -0,0 +1,229 @@
+// 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.
+
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+#include "base/string16.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/autofill/autofill_common_test.h"
+#include "chrome/browser/autofill/autofill_manager.h"
+#include "chrome/browser/autofill/autofill_metrics.h"
+#include "chrome/browser/autofill/personal_data_manager.h"
+#include "chrome/browser/renderer_host/test/test_render_view_host.h"
+#include "chrome/browser/tab_contents/test_tab_contents.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/glue/form_data.h"
+#include "webkit/glue/form_field.h"
+
+using webkit_glue::FormData;
+using webkit_glue::FormField;
+
+namespace {
+
+// TODO(isherman): Move this into autofill_common_test.h?
+class TestPersonalDataManager : public PersonalDataManager {
+ public:
+ TestPersonalDataManager() {
+ CreateTestAutoFillProfiles(&web_profiles_);
+ CreateTestCreditCards(&credit_cards_);
+ }
+
+ virtual void InitializeIfNeeded() {}
+ virtual void SaveImportedFormData() {}
+ virtual bool IsDataLoaded() const { return true; }
+
+ private:
+ void CreateTestAutoFillProfiles(ScopedVector<AutoFillProfile>* profiles) {
+ AutoFillProfile* profile = new AutoFillProfile;
+ autofill_test::SetProfileInfo(profile, "Home", "Elvis", "Aaron",
+ "Presley", "theking@gmail.com", "RCA",
+ "3734 Elvis Presley Blvd.", "Apt. 10",
+ "Memphis", "Tennessee", "38116", "USA",
+ "12345678901", "");
+ profile->set_guid("00000000-0000-0000-0000-000000000001");
+ profiles->push_back(profile);
+ profile = new AutoFillProfile;
+ autofill_test::SetProfileInfo(profile, "Work", "Charles", "Hardin",
+ "Holley", "buddy@gmail.com", "Decca",
+ "123 Apple St.", "unit 6", "Lubbock",
+ "Texas", "79401", "USA", "23456789012",
+ "");
+ profile->set_guid("00000000-0000-0000-0000-000000000002");
+ profiles->push_back(profile);
+ profile = new AutoFillProfile;
+ autofill_test::SetProfileInfo(profile, "Empty", "", "", "", "", "", "", "",
+ "", "", "", "", "", "");
+ profile->set_guid("00000000-0000-0000-0000-000000000003");
+ profiles->push_back(profile);
+ }
+
+ void CreateTestCreditCards(ScopedVector<CreditCard>* credit_cards) {
+ CreditCard* credit_card = new CreditCard;
+ autofill_test::SetCreditCardInfo(credit_card, "First", "Elvis Presley",
+ "4234567890123456", // Visa
+ "04", "2012");
+ credit_card->set_guid("00000000-0000-0000-0000-000000000004");
+ credit_cards->push_back(credit_card);
+ credit_card = new CreditCard;
+ autofill_test::SetCreditCardInfo(credit_card, "Second", "Buddy Holly",
+ "5187654321098765", // Mastercard
+ "10", "2014");
+ credit_card->set_guid("00000000-0000-0000-0000-000000000005");
+ credit_cards->push_back(credit_card);
+ credit_card = new CreditCard;
+ autofill_test::SetCreditCardInfo(credit_card, "Empty", "", "", "", "");
+ credit_card->set_guid("00000000-0000-0000-0000-000000000006");
+ credit_cards->push_back(credit_card);
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(TestPersonalDataManager);
+};
+
+class MockAutoFillMetrics : public AutoFillMetrics {
+ public:
+ MockAutoFillMetrics() {}
+ MOCK_CONST_METHOD1(Log, void(ServerQueryMetric metric));
+ MOCK_CONST_METHOD1(Log, void(QualityMetric metric));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockAutoFillMetrics);
+};
+
+class TestAutoFillManager : public AutoFillManager {
+ public:
+ TestAutoFillManager(TabContents* tab_contents,
+ TestPersonalDataManager* personal_manager)
+ : AutoFillManager(tab_contents, personal_manager),
+ autofill_enabled_(true) {
+ set_metric_logger(new MockAutoFillMetrics);
+ }
+ virtual ~TestAutoFillManager() {}
+
+ virtual bool IsAutoFillEnabled() const { return autofill_enabled_; }
+
+ void set_autofill_enabled(bool autofill_enabled) {
+ autofill_enabled_ = autofill_enabled;
+ }
+
+ const MockAutoFillMetrics* metric_logger() const {
+ return static_cast<const MockAutoFillMetrics*>(
+ AutoFillManager::metric_logger());
+ }
+
+ private:
+ bool autofill_enabled_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestAutoFillManager);
+};
+
+} // namespace
+
+class AutoFillMetricsTest : public RenderViewHostTestHarness {
+ public:
+ AutoFillMetricsTest() {}
+ virtual ~AutoFillMetricsTest() {
+ // Order of destruction is important as AutoFillManager relies on
+ // PersonalDataManager to be around when it gets destroyed.
+ autofill_manager_.reset(NULL);
+ test_personal_data_ = NULL;
+ }
+
+ virtual void SetUp() {
+ RenderViewHostTestHarness::SetUp();
+ test_personal_data_ = new TestPersonalDataManager();
+ autofill_manager_.reset(new TestAutoFillManager(contents(),
+ test_personal_data_.get()));
+ }
+
+ protected:
+ scoped_ptr<TestAutoFillManager> autofill_manager_;
+ scoped_refptr<TestPersonalDataManager> test_personal_data_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AutoFillMetricsTest);
+};
+
+// Test that we log quality metrics appropriately.
+TEST_F(AutoFillMetricsTest, QualityMetrics) {
+ // Set up our form data.
+ FormData form;
+ form.name = ASCIIToUTF16("TestForm");
+ form.method = ASCIIToUTF16("POST");
+ form.origin = GURL("http://example.com/form.html");
+ form.action = GURL("http://example.com/submit.html");
+ form.user_submitted = true;
+
+ FormField field;
+ autofill_test::CreateTestFormField(
+ "Autofilled", "autofilled", "Elvis Presley", "text", &field);
+ field.set_autofilled(true);
+ form.fields.push_back(field);
+ autofill_test::CreateTestFormField(
+ "Autofill Failed", "autofillfailed", "buddy@gmail.com", "text", &field);
+ form.fields.push_back(field);
+ autofill_test::CreateTestFormField(
+ "Empty", "empty", "", "text", &field);
+ form.fields.push_back(field);
+ autofill_test::CreateTestFormField(
+ "Unknown", "unknown", "garbage", "text", &field);
+ form.fields.push_back(field);
+ autofill_test::CreateTestFormField(
+ "Select", "select", "USA", "select-one", &field);
+ form.fields.push_back(field);
+
+ // Establish our expectations.
+ ::testing::InSequence dummy;
+ EXPECT_CALL(*autofill_manager_->metric_logger(),
+ Log(AutoFillMetrics::FIELD_SUBMITTED));
+ EXPECT_CALL(*autofill_manager_->metric_logger(),
+ Log(AutoFillMetrics::FIELD_AUTOFILLED));
+ EXPECT_CALL(*autofill_manager_->metric_logger(),
+ Log(AutoFillMetrics::FIELD_SUBMITTED));
+ EXPECT_CALL(*autofill_manager_->metric_logger(),
+ Log(AutoFillMetrics::FIELD_AUTOFILL_FAILED ));
+ EXPECT_CALL(*autofill_manager_->metric_logger(),
+ Log(AutoFillMetrics::FIELD_SUBMITTED));
+ EXPECT_CALL(*autofill_manager_->metric_logger(),
+ Log(AutoFillMetrics::FIELD_SUBMITTED));
+
+ // Simulate form submission.
+ EXPECT_NO_FATAL_FAILURE(autofill_manager_->FormSubmitted(form));
+}
+
+// Test that we don't log quality metrics for non-autofillable forms.
+TEST_F(AutoFillMetricsTest, NoQualityMetricsForNonAutoFillableForms) {
+ // Forms must include at least three fields to be auto-fillable.
+ FormData form;
+ form.name = ASCIIToUTF16("TestForm");
+ form.method = ASCIIToUTF16("POST");
+ form.origin = GURL("http://example.com/form.html");
+ form.action = GURL("http://example.com/submit.html");
+ form.user_submitted = true;
+
+ FormField field;
+ autofill_test::CreateTestFormField(
+ "Autofilled", "autofilled", "Elvis Presley", "text", &field);
+ field.set_autofilled(true);
+ form.fields.push_back(field);
+ autofill_test::CreateTestFormField(
+ "Autofill Failed", "autofillfailed", "buddy@gmail.com", "text", &field);
+ form.fields.push_back(field);
+
+ // Simulate form submission.
+ EXPECT_CALL(*autofill_manager_->metric_logger(),
+ Log(AutoFillMetrics::FIELD_SUBMITTED)).Times(0);
+ EXPECT_NO_FATAL_FAILURE(autofill_manager_->FormSubmitted(form));
+
+ // Search forms are not auto-fillable.
+ form.action = GURL("http://example.com/search?q=Elvis%20Presley");
+ autofill_test::CreateTestFormField(
+ "Empty", "empty", "", "text", &field);
+ form.fields.push_back(field);
+
+ // Simulate form submission.
+ EXPECT_CALL(*autofill_manager_->metric_logger(),
+ Log(AutoFillMetrics::FIELD_SUBMITTED)).Times(0);
+ EXPECT_NO_FATAL_FAILURE(autofill_manager_->FormSubmitted(form));
+}
diff --git a/chrome/browser/autofill/autofill_profile.cc b/chrome/browser/autofill/autofill_profile.cc
index 263df46..a1ea628 100644
--- a/chrome/browser/autofill/autofill_profile.cc
+++ b/chrome/browser/autofill/autofill_profile.cc
@@ -5,10 +5,7 @@
#include "chrome/browser/autofill/autofill_profile.h"
#include <algorithm>
-#include <list>
-#include <map>
#include <set>
-#include <vector>
#include "app/l10n_util.h"
#include "base/stl_util-inl.h"
@@ -19,8 +16,12 @@
#include "chrome/browser/autofill/fax_number.h"
#include "chrome/browser/autofill/home_address.h"
#include "chrome/browser/autofill/home_phone_number.h"
+<<<<<<< HEAD
#include "chrome/browser/guid.h"
#ifndef ANDROID
+=======
+#include "chrome/common/guid.h"
+>>>>>>> chromium.org at r10.0.621.0
#include "grit/generated_resources.h"
#endif
@@ -33,6 +34,116 @@ void InitPersonalInfo(FormGroupMap* personal_info) {
(*personal_info)[AutoFillType::ADDRESS_HOME] = new HomeAddress();
}
+// Maps |field_type| to a field type that can be directly stored in a profile
+// (in the sense that it makes sense to call |AutoFillProfile::SetInfo()| with
+// the returned field type as the first parameter.
+AutoFillFieldType GetEquivalentFieldType(AutoFillFieldType field_type) {
+ // When billing information is requested from the profile we map to the
+ // home address equivalents.
+ switch (field_type) {
+ case ADDRESS_BILLING_LINE1:
+ return ADDRESS_HOME_LINE1;
+
+ case ADDRESS_BILLING_LINE2:
+ return ADDRESS_HOME_LINE2;
+
+ case ADDRESS_BILLING_APT_NUM:
+ return ADDRESS_HOME_APT_NUM;
+
+ case ADDRESS_BILLING_CITY:
+ return ADDRESS_HOME_CITY;
+
+ case ADDRESS_BILLING_STATE:
+ return ADDRESS_HOME_STATE;
+
+ case ADDRESS_BILLING_ZIP:
+ return ADDRESS_HOME_ZIP;
+
+ case ADDRESS_BILLING_COUNTRY:
+ return ADDRESS_HOME_COUNTRY;
+
+ default:
+ return field_type;
+ }
+}
+
+// Like |GetEquivalentFieldType()| above, but also returns |NAME_FULL| for
+// first, middle, and last name field types.
+AutoFillFieldType GetEquivalentFieldTypeCollapsingNames(
+ AutoFillFieldType field_type) {
+ if (field_type == NAME_FIRST || field_type == NAME_MIDDLE ||
+ field_type == NAME_LAST)
+ return NAME_FULL;
+
+ return GetEquivalentFieldType(field_type);
+}
+
+// Fills |distinguishing_fields| with a list of fields to use when creating
+// labels that can help to distinguish between two profiles. Draws fields from
+// |suggested_fields| if it is non-NULL; otherwise returns a default list.
+// If |suggested_fields| is non-NULL, does not include |excluded_field| in the
+// list. Otherwise, |excluded_field| is ignored, and should be set to
+// |UNKNOWN_TYPE| by convention. The resulting list of fields is sorted in
+// decreasing order of importance.
+void GetFieldsForDistinguishingProfiles(
+ const std::vector<AutoFillFieldType>* suggested_fields,
+ AutoFillFieldType excluded_field,
+ std::vector<AutoFillFieldType>* distinguishing_fields) {
+ static const AutoFillFieldType kDefaultDistinguishingFields[] = {
+ NAME_FULL,
+ ADDRESS_HOME_LINE1,
+ ADDRESS_HOME_CITY,
+ ADDRESS_HOME_STATE,
+ ADDRESS_HOME_ZIP,
+ ADDRESS_HOME_COUNTRY,
+ EMAIL_ADDRESS,
+ PHONE_HOME_WHOLE_NUMBER,
+ PHONE_FAX_WHOLE_NUMBER,
+ COMPANY_NAME,
+ };
+
+ if (!suggested_fields) {
+ DCHECK_EQ(excluded_field, UNKNOWN_TYPE);
+ distinguishing_fields->assign(
+ kDefaultDistinguishingFields,
+ kDefaultDistinguishingFields + arraysize(kDefaultDistinguishingFields));
+ return;
+ }
+
+ // Keep track of which fields we've seen so that we avoid duplicate entries.
+ // Always ignore fields of unknown type and the excluded field.
+ std::set<AutoFillFieldType> seen_fields;
+ seen_fields.insert(UNKNOWN_TYPE);
+ seen_fields.insert(GetEquivalentFieldTypeCollapsingNames(excluded_field));
+
+ distinguishing_fields->clear();
+ for (std::vector<AutoFillFieldType>::const_iterator it =
+ suggested_fields->begin();
+ it != suggested_fields->end(); ++it) {
+ AutoFillFieldType suggested_type =
+ GetEquivalentFieldTypeCollapsingNames(*it);
+ if (seen_fields.insert(suggested_type).second)
+ distinguishing_fields->push_back(suggested_type);
+ }
+
+ // Special case: If the excluded field is a partial name (e.g. first name) and
+ // the suggested fields include other name fields, include |NAME_FULL| in the
+ // list of distinguishing fields as a last-ditch fallback. This allows us to
+ // distinguish between profiles that are identical except for the name.
+ if (excluded_field != NAME_FULL &&
+ GetEquivalentFieldTypeCollapsingNames(excluded_field) == NAME_FULL) {
+ for (std::vector<AutoFillFieldType>::const_iterator it =
+ suggested_fields->begin();
+ it != suggested_fields->end(); ++it) {
+ if (*it != excluded_field &&
+ GetEquivalentFieldTypeCollapsingNames(*it) == NAME_FULL) {
+ distinguishing_fields->push_back(NAME_FULL);
+ break;
+ }
+ }
+ }
+}
+
} // namespace
AutoFillProfile::AutoFillProfile(const std::string& guid)
@@ -77,37 +188,7 @@ void AutoFillProfile::GetAvailableFieldTypes(
}
string16 AutoFillProfile::GetFieldText(const AutoFillType& type) const {
- AutoFillType return_type = type;
-
- // When billing information is requested from the profile we map to the
- // home address equivalents. This indicates the address information within
- // this profile is being used to fill billing fields in the form.
- switch (type.field_type()) {
- case ADDRESS_BILLING_LINE1:
- return_type = AutoFillType(ADDRESS_HOME_LINE1);
- break;
- case ADDRESS_BILLING_LINE2:
- return_type = AutoFillType(ADDRESS_HOME_LINE2);
- break;
- case ADDRESS_BILLING_APT_NUM:
- return_type = AutoFillType(ADDRESS_HOME_APT_NUM);
- break;
- case ADDRESS_BILLING_CITY:
- return_type = AutoFillType(ADDRESS_HOME_CITY);
- break;
- case ADDRESS_BILLING_STATE:
- return_type = AutoFillType(ADDRESS_HOME_STATE);
- break;
- case ADDRESS_BILLING_ZIP:
- return_type = AutoFillType(ADDRESS_HOME_ZIP);
- break;
- case ADDRESS_BILLING_COUNTRY:
- return_type = AutoFillType(ADDRESS_HOME_COUNTRY);
- break;
- default:
- break;
- }
-
+ AutoFillType return_type(GetEquivalentFieldType(type.field_type()));
FormGroupMap::const_iterator iter = personal_info_.find(return_type.group());
if (iter == personal_info_.end() || iter->second == NULL)
return string16();
@@ -149,18 +230,7 @@ void AutoFillProfile::SetInfo(const AutoFillType& type, const string16& value) {
}
FormGroup* AutoFillProfile::Clone() const {
- AutoFillProfile* profile = new AutoFillProfile();
- profile->label_ = label_;
- profile->guid_ = guid();
-
- FormGroupMap::const_iterator iter;
- for (iter = personal_info_.begin(); iter != personal_info_.end(); ++iter) {
- if (profile->personal_info_.count(iter->first))
- delete profile->personal_info_[iter->first];
- profile->personal_info_[iter->first] = iter->second->Clone();
- }
-
- return profile;
+ return new AutoFillProfile(*this);
}
const string16 AutoFillProfile::Label() const {
@@ -170,16 +240,18 @@ const string16 AutoFillProfile::Label() const {
// static
bool AutoFillProfile::AdjustInferredLabels(
std::vector<AutoFillProfile*>* profiles) {
- std::vector<string16> created_labels;
const size_t kMinimalFieldsShown = 2;
- CreateInferredLabels(profiles, &created_labels, kMinimalFieldsShown,
- UNKNOWN_TYPE, NULL);
- DCHECK(profiles->size() == created_labels.size());
+
+ std::vector<string16> created_labels;
+ CreateInferredLabels(profiles, NULL, UNKNOWN_TYPE, kMinimalFieldsShown,
+ &created_labels);
+ DCHECK_EQ(profiles->size(), created_labels.size());
+
bool updated_labels = false;
for (size_t i = 0; i < profiles->size(); ++i) {
- if (profiles->at(i)->Label() != created_labels[i]) {
+ if ((*profiles)[i]->Label() != created_labels[i]) {
updated_labels = true;
- profiles->at(i)->set_label(created_labels[i]);
+ (*profiles)[i]->set_label(created_labels[i]);
}
}
return updated_labels;
@@ -188,188 +260,42 @@ bool AutoFillProfile::AdjustInferredLabels(
// static
void AutoFillProfile::CreateInferredLabels(
const std::vector<AutoFillProfile*>* profiles,
- std::vector<string16>* created_labels,
+ const std::vector<AutoFillFieldType>* suggested_fields,
+ AutoFillFieldType excluded_field,
size_t minimal_fields_shown,
- AutoFillFieldType exclude_field,
- const std::vector<AutoFillFieldType>* suggested_fields) {
- // |suggested_fields| may be NULL.
- // The following fields are use to distinguish between two profiles in the
- // order of importance, e. g. if both EMAIL_ADDRESS and COMPANY_NAME are
- // different, EMAIL_ADDRESS will be used to distinguish them.
- const AutoFillFieldType distinguishing_fields[] = {
- // First non empty data are always present in the label, even if it matches.
- NAME_FULL,
- ADDRESS_HOME_LINE1,
- ADDRESS_HOME_CITY,
- ADDRESS_HOME_STATE,
- ADDRESS_HOME_ZIP,
- ADDRESS_HOME_COUNTRY,
- EMAIL_ADDRESS,
- PHONE_HOME_WHOLE_NUMBER,
- PHONE_FAX_WHOLE_NUMBER,
- COMPANY_NAME,
- };
-
+ std::vector<string16>* created_labels) {
DCHECK(profiles);
DCHECK(created_labels);
std::vector<AutoFillFieldType> fields_to_use;
- if (suggested_fields) {
- // Limiting the number of possible fields simplifies the following code,
- // and 10 fields more than enough to create clear label.
- fields_to_use.reserve(std::min(suggested_fields->size(),
- arraysize(distinguishing_fields)));
- bool name_selected = false;
- for (size_t i = 0; i < suggested_fields->size() &&
- fields_to_use.size() < arraysize(distinguishing_fields); ++i) {
- if (suggested_fields->at(i) == NAME_FIRST ||
- suggested_fields->at(i) == NAME_LAST ||
- suggested_fields->at(i) == NAME_MIDDLE ||
- suggested_fields->at(i) == NAME_FULL) {
- if (name_selected)
- continue;
- name_selected = true;
- fields_to_use.push_back(NAME_FULL);
- } else {
- fields_to_use.push_back(suggested_fields->at(i));
- }
- }
- } else {
- fields_to_use.resize(arraysize(distinguishing_fields));
- for (size_t i = 0; i < arraysize(distinguishing_fields); ++i) {
- fields_to_use[i] = distinguishing_fields[i];
- }
- }
+ GetFieldsForDistinguishingProfiles(suggested_fields, excluded_field,
+ &fields_to_use);
- if (exclude_field == NAME_FIRST || exclude_field == NAME_LAST ||
- exclude_field == NAME_MIDDLE)
- exclude_field = NAME_FULL;
- created_labels->resize(profiles->size());
+ // Construct the default label for each profile. Also construct a map that
+ // associates each label with the profiles that have this label. This map is
+ // then used to detect which labels need further differentiating fields.
std::map<string16, std::list<size_t> > labels;
- for (size_t it = 0; it < profiles->size(); ++it) {
- labels[profiles->at(it)->GetFieldText(
- AutoFillType(fields_to_use.size() ? fields_to_use[0] :
- NAME_FULL))].push_back(it);
+ for (size_t i = 0; i < profiles->size(); ++i) {
+ string16 label =
+ (*profiles)[i]->ConstructInferredLabel(fields_to_use,
+ minimal_fields_shown);
+ labels[label].push_back(i);
}
- std::map<string16, std::list<size_t> >::iterator label_iterator;
- for (label_iterator = labels.begin(); label_iterator != labels.end();
- ++label_iterator) {
- if (label_iterator->second.size() > 1) {
- // We have more than one item with the same preview, add differentiating
- // data.
- std::list<size_t>::iterator similar_profiles;
- DCHECK(fields_to_use.size() <= arraysize(distinguishing_fields));
- std::map<string16, int> tested_fields[arraysize(distinguishing_fields)];
- for (similar_profiles = label_iterator->second.begin();
- similar_profiles != label_iterator->second.end();
- ++similar_profiles) {
- for (size_t i = 0; i < fields_to_use.size(); ++i) {
- string16 key = profiles->at(*similar_profiles)->GetFieldText(
- AutoFillType(fields_to_use[i]));
- std::map<string16, int>::iterator tested_field =
- tested_fields[i].find(key);
- if (tested_field == tested_fields[i].end())
- (tested_fields[i])[key] = 1;
- else
- ++(tested_field->second);
- }
- }
- std::vector<AutoFillFieldType> fields;
- std::vector<AutoFillFieldType> first_non_empty_fields;
- size_t added_fields = 0;
- bool matched_necessary = false;
- // Leave it as a candidate if it is not the same for everybody.
- for (size_t i = 0; i < fields_to_use.size(); ++i) {
- if (tested_fields[i].size() == label_iterator->second.size()) {
- // This field is different for everybody.
- if (!matched_necessary) {
- matched_necessary = true;
- fields.clear();
- added_fields = 1;
- if (first_non_empty_fields.size()) {
- added_fields += first_non_empty_fields.size();
- fields.resize(added_fields - 1);
- std::copy(first_non_empty_fields.begin(),
- first_non_empty_fields.end(),
- fields.begin());
- }
- } else {
- ++added_fields;
- }
- fields.push_back(fields_to_use[i]);
- if (added_fields >= minimal_fields_shown)
- break;
- } else if (tested_fields[i].size() != 1) {
- // this field is different for some.
- if (added_fields < minimal_fields_shown) {
- first_non_empty_fields.push_back(fields_to_use[i]);
- ++added_fields;
- if (added_fields == minimal_fields_shown && matched_necessary)
- break;
- }
- fields.push_back(fields_to_use[i]);
- } else if (added_fields < minimal_fields_shown &&
- exclude_field != fields_to_use[i] &&
- !label_iterator->first.empty()) {
- fields.push_back(fields_to_use[i]);
- first_non_empty_fields.push_back(fields_to_use[i]);
- ++added_fields;
- if (added_fields == minimal_fields_shown && matched_necessary)
- break;
- }
- }
- // Update labels if needed.
- for (similar_profiles = label_iterator->second.begin();
- similar_profiles != label_iterator->second.end();
- ++similar_profiles) {
- size_t field_it = 0;
- for (size_t field_id = 0;
- field_id < fields_to_use.size() &&
- field_it < fields.size(); ++field_id) {
- if (fields[field_it] == fields_to_use[field_id]) {
- if ((tested_fields[field_id])[
- profiles->at(*similar_profiles)->GetFieldText(
- AutoFillType(fields_to_use[field_id]))] == 1) {
- // this field is unique among the subset.
- break;
- }
- ++field_it;
- }
- }
-
- string16 new_label;
- if (field_it < fields.size() && fields.size() > minimal_fields_shown) {
- std::vector<AutoFillFieldType> unique_fields;
- unique_fields.resize(fields.size());
- std::copy(fields.begin(), fields.end(), unique_fields.begin());
- unique_fields.resize(std::max(field_it + 1, minimal_fields_shown));
- new_label =
- profiles->at(*similar_profiles)->ConstructInferredLabel(
- &unique_fields);
- } else {
- new_label =
- profiles->at(*similar_profiles)->ConstructInferredLabel(&fields);
- }
- (*created_labels)[*similar_profiles] = new_label;
- }
- } else {
- std::vector<AutoFillFieldType> non_empty_fields;
- size_t include_fields = minimal_fields_shown ? minimal_fields_shown : 1;
- non_empty_fields.reserve(include_fields);
- for (size_t i = 0; i < fields_to_use.size(); ++i) {
- if (exclude_field == fields_to_use[i])
- continue;
- if (!profiles->at(label_iterator->second.front())->GetFieldText(
- AutoFillType(fields_to_use[i])).empty()) {
- non_empty_fields.push_back(fields_to_use[i]);
- if (non_empty_fields.size() >= include_fields)
- break;
- }
- }
- (*created_labels)[label_iterator->second.front()] =
- profiles->at(label_iterator->second.front())->ConstructInferredLabel(
- &non_empty_fields);
+ created_labels->resize(profiles->size());
+ for (std::map<string16, std::list<size_t> >::const_iterator it =
+ labels.begin();
+ it != labels.end(); ++it) {
+ if (it->second.size() == 1) {
+ // This label is unique, so use it without any further ado.
+ string16 label = it->first;
+ size_t profile_index = it->second.front();
+ (*created_labels)[profile_index] = label;
+ } else {
+ // We have more than one profile with the same label, so add
+ // differentiating fields.
+ CreateDifferentiatingLabels(*profiles, it->second, fields_to_use,
+ minimal_fields_shown, created_labels);
}
}
}
@@ -381,6 +307,9 @@ bool AutoFillProfile::IsEmpty() const {
}
void AutoFillProfile::operator=(const AutoFillProfile& source) {
+ if (this == &source)
+ return;
+
label_ = source.label_;
guid_ = source.guid_;
@@ -441,19 +370,20 @@ const string16 AutoFillProfile::PrimaryValue() const {
GetFieldText(AutoFillType(EMAIL_ADDRESS));
}
-Address* AutoFillProfile::GetHomeAddress() {
- return static_cast<Address*>(personal_info_[AutoFillType::ADDRESS_HOME]);
-}
-
string16 AutoFillProfile::ConstructInferredLabel(
- const std::vector<AutoFillFieldType>* included_fields) const {
- DCHECK(included_fields);
+ const std::vector<AutoFillFieldType>& included_fields,
+ size_t num_fields_to_use) const {
+ const string16 separator =
+ l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADDRESS_SUMMARY_SEPARATOR);
+
string16 label;
- string16 separator = l10n_util::GetStringUTF16(
- IDS_AUTOFILL_DIALOG_ADDRESS_SUMMARY_SEPARATOR);
+ size_t num_fields_used = 0;
for (std::vector<AutoFillFieldType>::const_iterator it =
- included_fields->begin(); it != included_fields->end(); ++it) {
+ included_fields.begin();
+ it != included_fields.end() && num_fields_used < num_fields_to_use;
+ ++it) {
string16 field = GetFieldText(AutoFillType(*it));
+<<<<<<< HEAD
if (!field.empty()) {
if (!label.empty()) {
label.append(separator);
@@ -467,11 +397,102 @@ string16 AutoFillProfile::ConstructInferredLabel(
}
#endif
label.append(field);
+=======
+ if (field.empty())
+ continue;
+
+ if (!label.empty())
+ label.append(separator);
+
+ // Fax number has special format, to indicate that this is a fax number.
+ if (*it == PHONE_FAX_WHOLE_NUMBER) {
+ field = l10n_util::GetStringFUTF16(
+ IDS_AUTOFILL_DIALOG_ADDRESS_SUMMARY_FAX_FORMAT, field);
+>>>>>>> chromium.org at r10.0.621.0
}
+ label.append(field);
+ ++num_fields_used;
}
return label;
}
+// static
+void AutoFillProfile::CreateDifferentiatingLabels(
+ const std::vector<AutoFillProfile*>& profiles,
+ const std::list<size_t>& indices,
+ const std::vector<AutoFillFieldType>& fields,
+ size_t num_fields_to_include,
+ std::vector<string16>* created_labels) {
+ // For efficiency, we first construct a map of fields to their text values and
+ // each value's frequency.
+ std::map<AutoFillFieldType,
+ std::map<string16, size_t> > field_text_frequencies_by_field;
+ for (std::vector<AutoFillFieldType>::const_iterator field = fields.begin();
+ field != fields.end(); ++field) {
+ std::map<string16, size_t>& field_text_frequencies =
+ field_text_frequencies_by_field[*field];
+
+ for (std::list<size_t>::const_iterator it = indices.begin();
+ it != indices.end(); ++it) {
+ const AutoFillProfile* profile = profiles[*it];
+ string16 field_text = profile->GetFieldText(AutoFillType(*field));
+
+ // If this label is not already in the map, add it with frequency 0.
+ if (!field_text_frequencies.count(field_text))
+ field_text_frequencies[field_text] = 0;
+
+ // Now, increment the frequency for this label.
+ ++field_text_frequencies[field_text];
+ }
+ }
+
+ // Now comes the meat of the algorithm. For each profile, we scan the list of
+ // fields to use, looking for two things:
+ // 1. A (non-empty) field that differentiates the profile from all others
+ // 2. At least |num_fields_to_include| non-empty fields
+ // Before we've satisfied condition (2), we include all fields, even ones that
+ // are identical across all the profiles. Once we've satisfied condition (2),
+ // we only include fields that that have at last two distinct values.
+ for (std::list<size_t>::const_iterator it = indices.begin();
+ it != indices.end(); ++it) {
+ const AutoFillProfile* profile = profiles[*it];
+
+ std::vector<AutoFillFieldType> label_fields;
+ bool found_differentiating_field = false;
+ for (std::vector<AutoFillFieldType>::const_iterator field = fields.begin();
+ field != fields.end(); ++field) {
+ // Skip over empty fields.
+ string16 field_text = profile->GetFieldText(AutoFillType(*field));
+ if (field_text.empty())
+ continue;
+
+ std::map<string16, size_t>& field_text_frequencies =
+ field_text_frequencies_by_field[*field];
+ found_differentiating_field |=
+ !field_text_frequencies.count(string16()) &&
+ (field_text_frequencies[field_text] == 1);
+
+ // Once we've found enough non-empty fields, skip over any remaining
+ // fields that are identical across all the profiles.
+ if (label_fields.size() >= num_fields_to_include &&
+ (field_text_frequencies.size() == 1))
+ continue;
+
+ label_fields.push_back(*field);
+
+ // If we've (1) found a differentiating field and (2) found at least
+ // |num_fields_to_include| non-empty fields, we're done!
+ if (found_differentiating_field &&
+ label_fields.size() >= num_fields_to_include)
+ break;
+ }
+
+ (*created_labels)[*it] =
+ profile->ConstructInferredLabel(label_fields,
+ label_fields.size());
+ }
+}
+
// So we can compare AutoFillProfiles with EXPECT_EQ().
std::ostream& operator<<(std::ostream& os, const AutoFillProfile& profile) {
return os
diff --git a/chrome/browser/autofill/autofill_profile.h b/chrome/browser/autofill/autofill_profile.h
index d201294..964568a 100644
--- a/chrome/browser/autofill/autofill_profile.h
+++ b/chrome/browser/autofill/autofill_profile.h
@@ -6,6 +6,7 @@
#define CHROME_BROWSER_AUTOFILL_AUTOFILL_PROFILE_H_
#pragma once
+#include <list>
#include <map>
#include <vector>
@@ -67,17 +68,19 @@ class AutoFillProfile : public FormGroup {
// started typing in the field, for example) use CreateInferredLabels().
static bool AdjustInferredLabels(std::vector<AutoFillProfile*>* profiles);
- // Created inferred labels for |profiles|, according to the rules above and
- // stores them in |created_labels|. |minimal_fields_shown| minimal number of
- // fields that need to be shown for the label. |exclude_field| is excluded
- // from the label. If |suggested_fields| is not NULL it is used to generate
- // labels appropriate to the actual fields in a given form.
+ // Creates inferred labels for |profiles|, according to the rules above and
+ // stores them in |created_labels|. If |suggested_fields| is not NULL, the
+ // resulting label fields are drawn from |suggested_fields|, except excluding
+ // |excluded_field|. Otherwise, the label fields are drawn from a default set,
+ // and |excluded_field| is ignored; by convention, it should be of
+ // |UNKNOWN_TYPE| when |suggested_fields| is NULL. Each label includes at
+ // least |minimal_fields_shown| fields, if possible.
static void CreateInferredLabels(
const std::vector<AutoFillProfile*>* profiles,
- std::vector<string16>* created_labels,
+ const std::vector<AutoFillFieldType>* suggested_fields,
+ AutoFillFieldType excluded_field,
size_t minimal_fields_shown,
- AutoFillFieldType exclude_field,
- const std::vector<AutoFillFieldType>* suggested_fields);
+ std::vector<string16>* created_labels);
// Returns true if there are no values (field types) set.
bool IsEmpty() const;
@@ -107,14 +110,24 @@ class AutoFillProfile : public FormGroup {
const string16 PrimaryValue() const;
private:
- Address* GetHomeAddress();
-
- // Builds inferred label, includes first non-empty field at the beginning,
- // even if it matches for all.
- // |included_fields| - array of the fields, that needs to be included in this
- // label.
+ // Builds inferred label from the first |num_fields_to_include| non-empty
+ // fields in |label_fields|. Uses as many fields as possible if there are not
+ // enough non-empty fields.
string16 ConstructInferredLabel(
- const std::vector<AutoFillFieldType>* included_fields) const;
+ const std::vector<AutoFillFieldType>& label_fields,
+ size_t num_fields_to_include) const;
+
+ // Creates inferred labels for |profiles| at indices corresponding to
+ // |indices|, and stores the results to the corresponding elements of
+ // |created_labels|. These labels include enough fields to differentiate among
+ // the profiles, if possible; and also at least |num_fields_to_include|
+ // fields, if possible. The label fields are drawn from |fields|.
+ static void CreateDifferentiatingLabels(
+ const std::vector<AutoFillProfile*>& profiles,
+ const std::list<size_t>& indices,
+ const std::vector<AutoFillFieldType>& fields,
+ size_t num_fields_to_include,
+ std::vector<string16>* created_labels);
// The label presented to the user when selecting a profile.
string16 label_;
diff --git a/chrome/browser/autofill/autofill_profile_unittest.cc b/chrome/browser/autofill/autofill_profile_unittest.cc
index 3c500a3..93e9602 100644
--- a/chrome/browser/autofill/autofill_profile_unittest.cc
+++ b/chrome/browser/autofill/autofill_profile_unittest.cc
@@ -4,12 +4,13 @@
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
+#include "base/scoped_vector.h"
#include "base/stl_util-inl.h"
#include "base/string16.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_common_test.h"
#include "chrome/browser/autofill/autofill_profile.h"
-#include "chrome/browser/guid.h"
+#include "chrome/common/guid.h"
#include "grit/generated_resources.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -39,7 +40,7 @@ TEST(AutoFillProfileTest, PreviewSummaryString) {
"12345678910", "01987654321");
EXPECT_TRUE(UpdateProfileLabel(&profile00));
string16 summary00 = profile00.Label();
- EXPECT_EQ(string16(ASCIIToUTF16("Hollywood, CA")), summary00);
+ EXPECT_EQ(ASCIIToUTF16("Hollywood, CA"), summary00);
// Case 1: "<address>"
AutoFillProfile profile1;
@@ -48,7 +49,7 @@ TEST(AutoFillProfileTest, PreviewSummaryString) {
"91601", "US", "12345678910", "01987654321");
EXPECT_TRUE(UpdateProfileLabel(&profile1));
string16 summary1 = profile1.Label();
- EXPECT_EQ(string16(ASCIIToUTF16("123 Zoo St., Hollywood")), summary1);
+ EXPECT_EQ(ASCIIToUTF16("123 Zoo St., Hollywood"), summary1);
// Case 2: "<lastname>"
AutoFillProfile profile2;
@@ -58,7 +59,7 @@ TEST(AutoFillProfileTest, PreviewSummaryString) {
EXPECT_TRUE(UpdateProfileLabel(&profile2));
string16 summary2 = profile2.Label();
// Summary does include full name which is empty if the first name is empty.
- EXPECT_EQ(string16(ASCIIToUTF16("Hollywood, CA")), summary2);
+ EXPECT_EQ(ASCIIToUTF16("Hollywood, CA"), summary2);
// Case 3: "<lastname>, <address>"
AutoFillProfile profile3;
@@ -67,7 +68,7 @@ TEST(AutoFillProfileTest, PreviewSummaryString) {
"Hollywood", "CA", "91601", "US", "12345678910", "01987654321");
EXPECT_TRUE(UpdateProfileLabel(&profile3));
string16 summary3 = profile3.Label();
- EXPECT_EQ(string16(ASCIIToUTF16("123 Zoo St., Hollywood")), summary3);
+ EXPECT_EQ(ASCIIToUTF16("123 Zoo St., Hollywood"), summary3);
// Case 4: "<firstname>"
AutoFillProfile profile4;
@@ -76,7 +77,7 @@ TEST(AutoFillProfileTest, PreviewSummaryString) {
"12345678910", "01987654321");
EXPECT_TRUE(UpdateProfileLabel(&profile4));
string16 summary4 = profile4.Label();
- EXPECT_EQ(string16(ASCIIToUTF16("Marion Mitchell, Hollywood")), summary4);
+ EXPECT_EQ(ASCIIToUTF16("Marion Mitchell, Hollywood"), summary4);
// Case 5: "<firstname>, <address>"
AutoFillProfile profile5;
@@ -85,7 +86,7 @@ TEST(AutoFillProfileTest, PreviewSummaryString) {
"91601", "US", "12345678910", "01987654321");
EXPECT_TRUE(UpdateProfileLabel(&profile5));
string16 summary5 = profile5.Label();
- EXPECT_EQ(string16(ASCIIToUTF16("Marion Mitchell, 123 Zoo St.")), summary5);
+ EXPECT_EQ(ASCIIToUTF16("Marion Mitchell, 123 Zoo St."), summary5);
// Case 6: "<firstname> <lastname>"
AutoFillProfile profile6;
@@ -94,7 +95,7 @@ TEST(AutoFillProfileTest, PreviewSummaryString) {
"91601", "US", "12345678910", "01987654321");
EXPECT_TRUE(UpdateProfileLabel(&profile6));
string16 summary6 = profile6.Label();
- EXPECT_EQ(string16(ASCIIToUTF16("Marion Mitchell Morrison, Hollywood")),
+ EXPECT_EQ(ASCIIToUTF16("Marion Mitchell Morrison, Hollywood"),
summary6);
// Case 7: "<firstname> <lastname>, <address>"
@@ -104,7 +105,7 @@ TEST(AutoFillProfileTest, PreviewSummaryString) {
"Hollywood", "CA", "91601", "US", "12345678910", "01987654321");
EXPECT_TRUE(UpdateProfileLabel(&profile7));
string16 summary7 = profile7.Label();
- EXPECT_EQ(string16(ASCIIToUTF16("Marion Mitchell Morrison, 123 Zoo St.")),
+ EXPECT_EQ(ASCIIToUTF16("Marion Mitchell Morrison, 123 Zoo St."),
summary7);
// Case 7a: "<firstname> <lastname>, <address>" - same as #7, except for
@@ -119,10 +120,10 @@ TEST(AutoFillProfileTest, PreviewSummaryString) {
EXPECT_TRUE(AutoFillProfile::AdjustInferredLabels(&profiles));
summary7 = profile7.Label();
string16 summary7a = profile7a.Label();
- EXPECT_EQ(string16(ASCIIToUTF16(
- "Marion Mitchell Morrison, 123 Zoo St., johnwayne@me.xyz")), summary7);
- EXPECT_EQ(string16(ASCIIToUTF16(
- "Marion Mitchell Morrison, 123 Zoo St., marion@me.xyz")), summary7a);
+ EXPECT_EQ(ASCIIToUTF16(
+ "Marion Mitchell Morrison, 123 Zoo St., johnwayne@me.xyz"), summary7);
+ EXPECT_EQ(ASCIIToUTF16(
+ "Marion Mitchell Morrison, 123 Zoo St., marion@me.xyz"), summary7a);
}
TEST(AutoFillProfileTest, AdjustInferredLabels) {
@@ -163,9 +164,9 @@ TEST(AutoFillProfileTest, AdjustInferredLabels) {
EXPECT_TRUE(AutoFillProfile::AdjustInferredLabels(&profiles));
// No need to adjust them anymore.
EXPECT_FALSE(AutoFillProfile::AdjustInferredLabels(&profiles));
- EXPECT_EQ(string16(ASCIIToUTF16("John Doe, 666 Erebus St.")),
+ EXPECT_EQ(ASCIIToUTF16("John Doe, 666 Erebus St."),
profiles[0]->Label());
- EXPECT_EQ(string16(ASCIIToUTF16("Jane Doe, 123 Letha Shore.")),
+ EXPECT_EQ(ASCIIToUTF16("Jane Doe, 123 Letha Shore."),
profiles[1]->Label());
profiles.push_back(new AutoFillProfile);
@@ -187,13 +188,11 @@ TEST(AutoFillProfileTest, AdjustInferredLabels) {
EXPECT_TRUE(AutoFillProfile::AdjustInferredLabels(&profiles));
// Profile 0 and 2 inferred label now includes an e-mail.
- EXPECT_EQ(string16(
- ASCIIToUTF16("John Doe, 666 Erebus St., johndoe@hades.com")),
+ EXPECT_EQ(ASCIIToUTF16("John Doe, 666 Erebus St., johndoe@hades.com"),
profiles[0]->Label());
- EXPECT_EQ(string16(ASCIIToUTF16("Jane Doe, 123 Letha Shore.")),
+ EXPECT_EQ(ASCIIToUTF16("Jane Doe, 123 Letha Shore."),
profiles[1]->Label());
- EXPECT_EQ(string16(
- ASCIIToUTF16("John Doe, 666 Erebus St., johndoe@tertium.com")),
+ EXPECT_EQ(ASCIIToUTF16("John Doe, 666 Erebus St., johndoe@tertium.com"),
profiles[2]->Label());
delete profiles[2];
@@ -219,13 +218,11 @@ TEST(AutoFillProfileTest, AdjustInferredLabels) {
EXPECT_TRUE(AutoFillProfile::AdjustInferredLabels(&profiles));
// Profile 0 and 2 inferred label now includes a fax number.
- EXPECT_EQ(string16(ASCIIToUTF16(
- "John Doe, 666 Erebus St., fax:#22222222222")),
+ EXPECT_EQ(ASCIIToUTF16("John Doe, 666 Erebus St., fax:#22222222222"),
profiles[0]->Label());
- EXPECT_EQ(string16(ASCIIToUTF16("Jane Doe, 123 Letha Shore.")),
+ EXPECT_EQ(ASCIIToUTF16("Jane Doe, 123 Letha Shore."),
profiles[1]->Label());
- EXPECT_EQ(string16(ASCIIToUTF16(
- "John Doe, 666 Erebus St., fax:#33333333333")),
+ EXPECT_EQ(ASCIIToUTF16("John Doe, 666 Erebus St., fax:#33333333333"),
profiles[2]->Label());
profiles.push_back(new AutoFillProfile);
@@ -247,17 +244,17 @@ TEST(AutoFillProfileTest, AdjustInferredLabels) {
EXPECT_TRUE(AutoFillProfile::AdjustInferredLabels(&profiles));
- EXPECT_EQ(string16(ASCIIToUTF16("John Doe, 666 Erebus St., 11111111111,"
- " fax:#22222222222")),
+ EXPECT_EQ(ASCIIToUTF16("John Doe, 666 Erebus St., 11111111111,"
+ " fax:#22222222222"),
profiles[0]->Label());
- EXPECT_EQ(string16(ASCIIToUTF16("Jane Doe, 123 Letha Shore.")),
+ EXPECT_EQ(ASCIIToUTF16("Jane Doe, 123 Letha Shore."),
profiles[1]->Label());
- EXPECT_EQ(string16(ASCIIToUTF16("John Doe, 666 Erebus St., 11111111111,"
- " fax:#33333333333")),
+ EXPECT_EQ(ASCIIToUTF16("John Doe, 666 Erebus St., 11111111111,"
+ " fax:#33333333333"),
profiles[2]->Label());
// This one differs from other ones by unique phone, so no need for extra
// information.
- EXPECT_EQ(string16(ASCIIToUTF16("John Doe, 666 Erebus St., 44444444444")),
+ EXPECT_EQ(ASCIIToUTF16("John Doe, 666 Erebus St., 44444444444"),
profiles[3]->Label());
profiles.push_back(new AutoFillProfile);
@@ -279,25 +276,21 @@ TEST(AutoFillProfileTest, AdjustInferredLabels) {
EXPECT_TRUE(AutoFillProfile::AdjustInferredLabels(&profiles));
- EXPECT_EQ(string16(ASCIIToUTF16(
- "John Doe, 666 Erebus St., johndoe@hades.com,"
- " 11111111111, fax:#22222222222")),
- profiles[0]->Label());
- EXPECT_EQ(string16(ASCIIToUTF16("Jane Doe, 123 Letha Shore.")),
+ EXPECT_EQ(ASCIIToUTF16("John Doe, 666 Erebus St., johndoe@hades.com,"
+ " 11111111111, fax:#22222222222"),
+ profiles[0]->Label());
+ EXPECT_EQ(ASCIIToUTF16("Jane Doe, 123 Letha Shore."),
profiles[1]->Label());
- EXPECT_EQ(string16(ASCIIToUTF16(
- "John Doe, 666 Erebus St., johndoe@hades.com,"
- " 11111111111, fax:#33333333333")),
- profiles[2]->Label());
- EXPECT_EQ(string16(ASCIIToUTF16(
- "John Doe, 666 Erebus St., johndoe@hades.com,"
- " 44444444444, fax:#33333333333")),
- profiles[3]->Label());
+ EXPECT_EQ(ASCIIToUTF16("John Doe, 666 Erebus St., johndoe@hades.com,"
+ " 11111111111, fax:#33333333333"),
+ profiles[2]->Label());
+ EXPECT_EQ(ASCIIToUTF16("John Doe, 666 Erebus St., johndoe@hades.com,"
+ " 44444444444, fax:#33333333333"),
+ profiles[3]->Label());
// This one differs from other ones by unique e-mail, so no need for extra
// information.
- EXPECT_EQ(string16(ASCIIToUTF16(
- "John Doe, 666 Erebus St., johndoe@styx.com")),
- profiles[4]->Label());
+ EXPECT_EQ(ASCIIToUTF16("John Doe, 666 Erebus St., johndoe@styx.com"),
+ profiles[4]->Label());
EXPECT_FALSE(AutoFillProfile::AdjustInferredLabels(&profiles));
@@ -339,67 +332,172 @@ TEST(AutoFillProfileTest, CreateInferredLabels) {
"01987654321");
std::vector<string16> labels;
// Two fields at least - no filter.
- AutoFillProfile::CreateInferredLabels(&profiles, &labels, 2, UNKNOWN_TYPE,
- NULL);
- EXPECT_EQ(string16(ASCIIToUTF16("John Doe, 666 Erebus St.")), labels[0]);
- EXPECT_EQ(string16(ASCIIToUTF16("Jane Doe, 123 Letha Shore.")), labels[1]);
+ AutoFillProfile::CreateInferredLabels(&profiles, NULL, UNKNOWN_TYPE, 2,
+ &labels);
+ EXPECT_EQ(ASCIIToUTF16("John Doe, 666 Erebus St."), labels[0]);
+ EXPECT_EQ(ASCIIToUTF16("Jane Doe, 123 Letha Shore."), labels[1]);
// Three fields at least - no filter.
- AutoFillProfile::CreateInferredLabels(&profiles, &labels, 3, UNKNOWN_TYPE,
- NULL);
- EXPECT_EQ(string16(ASCIIToUTF16("John Doe, 666 Erebus St., Elysium")),
+ AutoFillProfile::CreateInferredLabels(&profiles, NULL, UNKNOWN_TYPE, 3,
+ &labels);
+ EXPECT_EQ(ASCIIToUTF16("John Doe, 666 Erebus St., Elysium"),
labels[0]);
- EXPECT_EQ(string16(ASCIIToUTF16("Jane Doe, 123 Letha Shore., Dis")),
+ EXPECT_EQ(ASCIIToUTF16("Jane Doe, 123 Letha Shore., Dis"),
labels[1]);
- // Two fields at least - filter out the name.
- AutoFillProfile::CreateInferredLabels(&profiles, &labels, 2, NAME_FULL, NULL);
- EXPECT_EQ(string16(ASCIIToUTF16("666 Erebus St., Elysium")), labels[0]);
- EXPECT_EQ(string16(ASCIIToUTF16("123 Letha Shore., Dis")), labels[1]);
-
std::vector<AutoFillFieldType> suggested_fields;
suggested_fields.push_back(ADDRESS_HOME_CITY);
suggested_fields.push_back(ADDRESS_HOME_STATE);
suggested_fields.push_back(ADDRESS_HOME_ZIP);
// Two fields at least, from suggested fields - no filter.
- AutoFillProfile::CreateInferredLabels(&profiles, &labels, 2, UNKNOWN_TYPE,
- &suggested_fields);
- EXPECT_EQ(string16(ASCIIToUTF16("Elysium, CA")), labels[0]);
- EXPECT_EQ(string16(ASCIIToUTF16("Dis, CA")), labels[1]);
+ AutoFillProfile::CreateInferredLabels(&profiles, &suggested_fields,
+ UNKNOWN_TYPE, 2, &labels);
+ EXPECT_EQ(ASCIIToUTF16("Elysium, CA"), labels[0]);
+ EXPECT_EQ(ASCIIToUTF16("Dis, CA"), labels[1]);
// Three fields at least, from suggested fields - no filter.
- AutoFillProfile::CreateInferredLabels(&profiles, &labels, 3, UNKNOWN_TYPE,
- &suggested_fields);
- EXPECT_EQ(string16(ASCIIToUTF16("Elysium, CA, 91111")), labels[0]);
- EXPECT_EQ(string16(ASCIIToUTF16("Dis, CA, 91222")), labels[1]);
+ AutoFillProfile::CreateInferredLabels(&profiles, &suggested_fields,
+ UNKNOWN_TYPE, 3, &labels);
+ EXPECT_EQ(ASCIIToUTF16("Elysium, CA, 91111"), labels[0]);
+ EXPECT_EQ(ASCIIToUTF16("Dis, CA, 91222"), labels[1]);
// Three fields at least, from suggested fields - but filter reduces available
// fields to two.
- AutoFillProfile::CreateInferredLabels(&profiles, &labels, 3,
- ADDRESS_HOME_STATE, &suggested_fields);
- EXPECT_EQ(string16(ASCIIToUTF16("Elysium, 91111")), labels[0]);
- EXPECT_EQ(string16(ASCIIToUTF16("Dis, 91222")), labels[1]);
+ AutoFillProfile::CreateInferredLabels(&profiles, &suggested_fields,
+ ADDRESS_HOME_STATE, 3, &labels);
+ EXPECT_EQ(ASCIIToUTF16("Elysium, 91111"), labels[0]);
+ EXPECT_EQ(ASCIIToUTF16("Dis, 91222"), labels[1]);
suggested_fields.clear();
// In our implementation we always display NAME_FULL for all NAME* fields...
suggested_fields.push_back(NAME_MIDDLE);
// One field at least, from suggested fields - no filter.
- AutoFillProfile::CreateInferredLabels(&profiles, &labels, 1, UNKNOWN_TYPE,
- &suggested_fields);
- EXPECT_EQ(string16(ASCIIToUTF16("John Doe")), labels[0]);
- EXPECT_EQ(string16(ASCIIToUTF16("Jane Doe")), labels[1]);
+ AutoFillProfile::CreateInferredLabels(&profiles, &suggested_fields,
+ UNKNOWN_TYPE, 1, &labels);
+ EXPECT_EQ(ASCIIToUTF16("John Doe"), labels[0]);
+ EXPECT_EQ(ASCIIToUTF16("Jane Doe"), labels[1]);
// One field at least, from suggested fields - filter the same as suggested
// field.
- AutoFillProfile::CreateInferredLabels(&profiles, &labels, 1, NAME_MIDDLE,
- &suggested_fields);
- EXPECT_EQ(string16(ASCIIToUTF16("")), labels[0]);
- EXPECT_EQ(string16(ASCIIToUTF16("")), labels[1]);
+ AutoFillProfile::CreateInferredLabels(&profiles, &suggested_fields,
+ NAME_MIDDLE, 1, &labels);
+ EXPECT_EQ(string16(), labels[0]);
+ EXPECT_EQ(string16(), labels[1]);
+
+ // One field at least, from suggested fields - filter same as the first non-
+ // unknown suggested field.
+ suggested_fields.clear();
+ suggested_fields.push_back(UNKNOWN_TYPE);
+ suggested_fields.push_back(NAME_FULL);
+ suggested_fields.push_back(ADDRESS_HOME_LINE1);
+ AutoFillProfile::CreateInferredLabels(&profiles, &suggested_fields, NAME_FULL,
+ 1, &labels);
+ EXPECT_EQ(string16(ASCIIToUTF16("666 Erebus St.")), labels[0]);
+ EXPECT_EQ(string16(ASCIIToUTF16("123 Letha Shore.")), labels[1]);
+
// Clean up.
STLDeleteContainerPointers(profiles.begin(), profiles.end());
}
+// Test that we fall back to using the full name if there are no other
+// distinguishing fields, but only if it makes sense given the suggested fields.
+TEST(AutoFillProfileTest, CreateInferredLabelsFallsBackToFullName) {
+ ScopedVector<AutoFillProfile> profiles;
+ profiles.push_back(new AutoFillProfile);
+ autofill_test::SetProfileInfo(profiles[0],
+ "", "John", "", "Doe", "doe@example.com", "",
+ "88 Nowhere Ave.", "", "", "", "", "", "", "");
+ profiles.push_back(new AutoFillProfile);
+ autofill_test::SetProfileInfo(profiles[1],
+ "", "Johnny", "K", "Doe", "doe@example.com", "",
+ "88 Nowhere Ave.", "", "", "", "", "", "", "");
+
+ // If the only name field in the suggested fields is the excluded field, we
+ // should not fall back to the full name as a distinguishing field.
+ std::vector<AutoFillFieldType> suggested_fields;
+ suggested_fields.push_back(NAME_LAST);
+ suggested_fields.push_back(ADDRESS_HOME_LINE1);
+ suggested_fields.push_back(EMAIL_ADDRESS);
+ std::vector<string16> labels;
+ AutoFillProfile::CreateInferredLabels(&profiles.get(), &suggested_fields,
+ NAME_LAST, 1, &labels);
+ ASSERT_EQ(2U, labels.size());
+ EXPECT_EQ(ASCIIToUTF16("88 Nowhere Ave."), labels[0]);
+ EXPECT_EQ(ASCIIToUTF16("88 Nowhere Ave."), labels[1]);
+
+ // Otherwise, we should.
+ suggested_fields.push_back(NAME_FIRST);
+ AutoFillProfile::CreateInferredLabels(&profiles.get(), &suggested_fields,
+ NAME_LAST, 1, &labels);
+ ASSERT_EQ(2U, labels.size());
+ EXPECT_EQ(ASCIIToUTF16("88 Nowhere Ave., John Doe"), labels[0]);
+ EXPECT_EQ(ASCIIToUTF16("88 Nowhere Ave., Johnny K Doe"), labels[1]);
+}
+
+// Test that we do not show duplicate fields in the labels.
+TEST(AutoFillProfileTest, CreateInferredLabelsNoDuplicatedFields) {
+ ScopedVector<AutoFillProfile> profiles;
+ profiles.push_back(new AutoFillProfile);
+ autofill_test::SetProfileInfo(profiles[0],
+ "", "John", "", "Doe", "doe@example.com", "",
+ "88 Nowhere Ave.", "", "", "", "", "", "", "");
+ profiles.push_back(new AutoFillProfile);
+ autofill_test::SetProfileInfo(profiles[1],
+ "", "John", "", "Doe", "dojo@example.com", "",
+ "88 Nowhere Ave.", "", "", "", "", "", "", "");
+
+ // If the only name field in the suggested fields is the excluded field, we
+ // should not fall back to the full name as a distinguishing field.
+ std::vector<AutoFillFieldType> suggested_fields;
+ suggested_fields.push_back(ADDRESS_HOME_LINE1);
+ suggested_fields.push_back(ADDRESS_BILLING_LINE1);
+ suggested_fields.push_back(EMAIL_ADDRESS);
+ std::vector<string16> labels;
+ AutoFillProfile::CreateInferredLabels(&profiles.get(), &suggested_fields,
+ UNKNOWN_TYPE, 2, &labels);
+ ASSERT_EQ(2U, labels.size());
+ EXPECT_EQ(ASCIIToUTF16("88 Nowhere Ave., doe@example.com"), labels[0]);
+ EXPECT_EQ(ASCIIToUTF16("88 Nowhere Ave., dojo@example.com"), labels[1]);
+}
+
+// Make sure that empty fields are not treated as distinguishing fields.
+TEST(AutoFillProfileTest, CreateInferredLabelsSkipsEmptyFields) {
+ ScopedVector<AutoFillProfile> profiles;
+ profiles.push_back(new AutoFillProfile);
+ autofill_test::SetProfileInfo(profiles[0],
+ "", "John", "", "Doe", "doe@example.com",
+ "Gogole", "", "", "", "", "", "", "", "");
+ profiles.push_back(new AutoFillProfile);
+ autofill_test::SetProfileInfo(profiles[1],
+ "", "John", "", "Doe", "doe@example.com",
+ "Ggoole", "", "", "", "", "", "", "", "");
+ profiles.push_back(new AutoFillProfile);
+ autofill_test::SetProfileInfo(profiles[2],
+ "", "John", "", "Doe", "john.doe@example.com",
+ "Goolge", "", "", "", "", "", "", "", "");
+
+ std::vector<string16> labels;
+ AutoFillProfile::CreateInferredLabels(&profiles.get(), NULL, UNKNOWN_TYPE, 3,
+ &labels);
+ ASSERT_EQ(3U, labels.size());
+ EXPECT_EQ(ASCIIToUTF16("John Doe, doe@example.com, Gogole"), labels[0]);
+ EXPECT_EQ(ASCIIToUTF16("John Doe, doe@example.com, Ggoole"), labels[1]);
+ EXPECT_EQ(ASCIIToUTF16("John Doe, john.doe@example.com, Goolge"), labels[2]);
+
+ // A field must have a non-empty value for each profile to be considered a
+ // distinguishing field.
+ profiles[1]->SetInfo(AutoFillType(ADDRESS_HOME_LINE1),
+ ASCIIToUTF16("88 Nowhere Ave."));
+ AutoFillProfile::CreateInferredLabels(&profiles.get(), NULL, UNKNOWN_TYPE, 1,
+ &labels);
+ ASSERT_EQ(3U, labels.size());
+ EXPECT_EQ(ASCIIToUTF16("John Doe, doe@example.com, Gogole"), labels[0]);
+ EXPECT_EQ(ASCIIToUTF16("John Doe, 88 Nowhere Ave., doe@example.com, Ggoole"),
+ labels[1]) << labels[1];
+ EXPECT_EQ(ASCIIToUTF16("John Doe, john.doe@example.com"), labels[2]);
+}
+
TEST(AutoFillProfileTest, IsSubsetOf) {
scoped_ptr<AutoFillProfile> a, b;
@@ -495,6 +593,34 @@ TEST(AutoFillProfileTest, MergeWith) {
EXPECT_EQ(0, expected_b.Compare(*b));
}
+TEST(AutoFillProfileTest, AssignmentOperator){
+ AutoFillProfile a, b;
+
+ // Result of assignment should be logically equal to the original profile.
+ autofill_test::SetProfileInfo(&a, "Billing", "Marion", "Mitchell", "Morrison",
+ "marion@me.xyz", "Fox", "123 Zoo St.", "unit 5",
+ "Hollywood", "CA", "91601", "US", "12345678910",
+ "01987654321");
+ b = a;
+ EXPECT_TRUE(a == b);
+
+ // Assignment to self should not change the profile value.
+ a = a;
+ EXPECT_TRUE(a == b);
+}
+
+TEST(AutoFillProfileTest, Clone) {
+ AutoFillProfile a;
+
+ // Clone should be logically equal to the original.
+ autofill_test::SetProfileInfo(&a, "Billing", "Marion", "Mitchell", "Morrison",
+ "marion@me.xyz", "Fox", "123 Zoo St.", "unit 5",
+ "Hollywood", "CA", "91601", "US", "12345678910",
+ "01987654321");
+ scoped_ptr<AutoFillProfile> b(static_cast<AutoFillProfile*>(a.Clone()));
+ EXPECT_TRUE(a == *b);
+}
+
TEST(AutoFillProfileTest, Compare) {
AutoFillProfile a, b;
diff --git a/chrome/browser/autofill/credit_card.cc b/chrome/browser/autofill/credit_card.cc
index 0ca5e45..2175804 100644
--- a/chrome/browser/autofill/credit_card.cc
+++ b/chrome/browser/autofill/credit_card.cc
@@ -18,8 +18,12 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_type.h"
#include "chrome/browser/autofill/field_types.h"
+<<<<<<< HEAD
#include "chrome/browser/guid.h"
#ifndef ANDROID
+=======
+#include "chrome/common/guid.h"
+>>>>>>> chromium.org at r10.0.621.0
#include "grit/generated_resources.h"
#endif
@@ -343,6 +347,10 @@ void CreditCard::SetInfo(const AutoFillType& type, const string16& value) {
}
}
+const string16 CreditCard::Label() const {
+ return label_;
+}
+
string16 CreditCard::ObfuscatedNumber() const {
if (number().empty())
return string16(); // No CC number, means empty preview.
@@ -389,6 +397,9 @@ string16 CreditCard::LastFourDigits() const {
}
void CreditCard::operator=(const CreditCard& credit_card) {
+ if (this == &credit_card)
+ return;
+
number_ = credit_card.number_;
name_on_card_ = credit_card.name_on_card_;
type_ = credit_card.type_;
diff --git a/chrome/browser/autofill/credit_card.h b/chrome/browser/autofill/credit_card.h
index b6fdfde..ebb3161 100644
--- a/chrome/browser/autofill/credit_card.h
+++ b/chrome/browser/autofill/credit_card.h
@@ -22,7 +22,7 @@ class CreditCard : public FormGroup {
virtual ~CreditCard();
// FormGroup implementation:
- FormGroup* Clone() const;
+ virtual FormGroup* Clone() const;
virtual void GetPossibleFieldTypes(const string16& text,
FieldTypeSet* possible_types) const;
virtual void GetAvailableFieldTypes(FieldTypeSet* available_types) const;
@@ -32,7 +32,7 @@ class CreditCard : public FormGroup {
virtual string16 GetFieldText(const AutoFillType& type) const;
virtual string16 GetPreviewText(const AutoFillType& type) const;
virtual void SetInfo(const AutoFillType& type, const string16& value);
- virtual const string16 Label() const { return label_; }
+ virtual const string16 Label() const;
// The number altered for display, for example: ******1234
string16 ObfuscatedNumber() const;
diff --git a/chrome/browser/autofill/credit_card_unittest.cc b/chrome/browser/autofill/credit_card_unittest.cc
index 507379b..89e73d7 100644
--- a/chrome/browser/autofill/credit_card_unittest.cc
+++ b/chrome/browser/autofill/credit_card_unittest.cc
@@ -67,5 +67,19 @@ TEST(CreditCardTest, PreviewSummaryAndObfuscatedNumberStrings) {
EXPECT_EQ(string16(ASCIIToUTF16("************9012")), obfuscated4);
}
+TEST(CreditCardTest, AssignmentOperator){
+ CreditCard a, b;
+
+ // Result of assignment should be logically equal to the original profile.
+ autofill_test::SetCreditCardInfo(&a, "Corporate", "John Dillinger",
+ "123456789012", "01", "2010");
+ b = a;
+ EXPECT_TRUE(a == b);
+
+ // Assignment to self should not change the profile value.
+ a = a;
+ EXPECT_TRUE(a == b);
+}
+
} // namespace
diff --git a/chrome/browser/autofill/fax_number.cc b/chrome/browser/autofill/fax_number.cc
new file mode 100644
index 0000000..06dd781
--- /dev/null
+++ b/chrome/browser/autofill/fax_number.cc
@@ -0,0 +1,33 @@
+// 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.
+
+#include "chrome/browser/autofill/fax_number.h"
+
+FaxNumber::FaxNumber() {}
+
+FaxNumber::~FaxNumber() {}
+
+FormGroup* FaxNumber::Clone() const {
+ return new FaxNumber(*this);
+}
+
+AutoFillFieldType FaxNumber::GetNumberType() const {
+ return PHONE_FAX_NUMBER;
+}
+
+AutoFillFieldType FaxNumber::GetCityCodeType() const {
+ return PHONE_FAX_CITY_CODE;
+}
+
+AutoFillFieldType FaxNumber::GetCountryCodeType() const {
+ return PHONE_FAX_COUNTRY_CODE;
+}
+
+AutoFillFieldType FaxNumber::GetCityAndNumberType() const {
+ return PHONE_FAX_CITY_AND_NUMBER;
+}
+
+AutoFillFieldType FaxNumber::GetWholeNumberType() const {
+ return PHONE_FAX_WHOLE_NUMBER;
+}
diff --git a/chrome/browser/autofill/fax_number.h b/chrome/browser/autofill/fax_number.h
index 864746f..7fe9a1c 100644
--- a/chrome/browser/autofill/fax_number.h
+++ b/chrome/browser/autofill/fax_number.h
@@ -12,29 +12,17 @@ class FormGroup;
class FaxNumber : public PhoneNumber {
public:
- FaxNumber() {}
- virtual FormGroup* Clone() const { return new FaxNumber(*this); }
+ FaxNumber();
+ virtual ~FaxNumber();
- protected:
- virtual AutoFillFieldType GetNumberType() const {
- return PHONE_FAX_NUMBER;
- }
-
- virtual AutoFillFieldType GetCityCodeType() const {
- return PHONE_FAX_CITY_CODE;
- }
-
- virtual AutoFillFieldType GetCountryCodeType() const {
- return PHONE_FAX_COUNTRY_CODE;
- }
+ virtual FormGroup* Clone() const;
- virtual AutoFillFieldType GetCityAndNumberType() const {
- return PHONE_FAX_CITY_AND_NUMBER;
- }
-
- virtual AutoFillFieldType GetWholeNumberType() const {
- return PHONE_FAX_WHOLE_NUMBER;
- }
+ protected:
+ virtual AutoFillFieldType GetNumberType() const;
+ virtual AutoFillFieldType GetCityCodeType() const;
+ virtual AutoFillFieldType GetCountryCodeType() const;
+ virtual AutoFillFieldType GetCityAndNumberType() const;
+ virtual AutoFillFieldType GetWholeNumberType() const;
private:
explicit FaxNumber(const FaxNumber& phone) : PhoneNumber(phone) {}
diff --git a/chrome/browser/autofill/form_field.cc b/chrome/browser/autofill/form_field.cc
index 2037cf7..ed20213 100644
--- a/chrome/browser/autofill/form_field.cc
+++ b/chrome/browser/autofill/form_field.cc
@@ -109,6 +109,10 @@ class EmailField : public FormField {
AutoFillField* field_;
};
+FormFieldType FormField::GetFormFieldType() const {
+ return kOtherFieldType;
+}
+
// static
bool FormField::Match(AutoFillField* field,
const string16& pattern,
diff --git a/chrome/browser/autofill/form_field.h b/chrome/browser/autofill/form_field.h
index 38b2ec2..4c5e02b 100644
--- a/chrome/browser/autofill/form_field.h
+++ b/chrome/browser/autofill/form_field.h
@@ -75,7 +75,7 @@ class FormField {
virtual bool GetFieldInfo(FieldTypeMap* field_type_map) const = 0;
// Returns the type of form field of the class implementing this interface.
- virtual FormFieldType GetFormFieldType() const { return kOtherFieldType; }
+ virtual FormFieldType GetFormFieldType() const;
// Returns true if |field| contains the regexp |pattern| in the name or label.
// If |match_label_only| is true, then only the field's label is considered.
diff --git a/chrome/browser/autofill/form_structure.cc b/chrome/browser/autofill/form_structure.cc
index f8a103f..7f4dcbf 100644
--- a/chrome/browser/autofill/form_structure.cc
+++ b/chrome/browser/autofill/form_structure.cc
@@ -204,9 +204,9 @@ bool FormStructure::EncodeQueryRequest(const ScopedVector<FormStructure>& forms,
// static
void FormStructure::ParseQueryResponse(const std::string& response_xml,
const std::vector<FormStructure*>& forms,
- UploadRequired* upload_required) {
- autofill_metrics::LogServerQueryMetric(
- autofill_metrics::QUERY_RESPONSE_RECEIVED);
+ UploadRequired* upload_required,
+ const AutoFillMetrics& metric_logger) {
+ metric_logger.Log(AutoFillMetrics::QUERY_RESPONSE_RECEIVED);
// Parse the field types from the server response to the query.
std::vector<AutoFillFieldType> field_types;
@@ -216,8 +216,7 @@ void FormStructure::ParseQueryResponse(const std::string& response_xml,
if (!parse_handler.succeeded())
return;
- autofill_metrics::LogServerQueryMetric(
- autofill_metrics::QUERY_RESPONSE_PARSED);
+ metric_logger.Log(AutoFillMetrics::QUERY_RESPONSE_PARSED);
bool heuristics_detected_fillable_field = false;
bool query_response_overrode_heuristics = false;
@@ -245,6 +244,9 @@ void FormStructure::ParseQueryResponse(const std::string& response_xml,
if (current_type == field_types.end())
break;
+ // UNKNOWN_TYPE is reserved for use by the client.
+ DCHECK_NE(*current_type, UNKNOWN_TYPE);
+
AutoFillFieldType heuristic_type = (*field)->type();
(*field)->set_server_type(*current_type);
if (heuristic_type != (*field)->type())
@@ -260,17 +262,17 @@ void FormStructure::ParseQueryResponse(const std::string& response_xml,
form->UpdateAutoFillCount();
}
- autofill_metrics::ServerQueryMetricType metric_type;
+ AutoFillMetrics::ServerQueryMetric metric;
if (query_response_overrode_heuristics) {
if (heuristics_detected_fillable_field) {
- metric_type = autofill_metrics::QUERY_RESPONSE_OVERRODE_LOCAL_HEURISTICS;
+ metric = AutoFillMetrics::QUERY_RESPONSE_OVERRODE_LOCAL_HEURISTICS;
} else {
- metric_type = autofill_metrics::QUERY_RESPONSE_WITH_NO_LOCAL_HEURISTICS;
+ metric = AutoFillMetrics::QUERY_RESPONSE_WITH_NO_LOCAL_HEURISTICS;
}
} else {
- metric_type = autofill_metrics::QUERY_RESPONSE_MATCHED_LOCAL_HEURISTICS;
+ metric = AutoFillMetrics::QUERY_RESPONSE_MATCHED_LOCAL_HEURISTICS;
}
- autofill_metrics::LogServerQueryMetric(metric_type);
+ metric_logger.Log(metric);
}
std::string FormStructure::FormSignature() const {
diff --git a/chrome/browser/autofill/form_structure.h b/chrome/browser/autofill/form_structure.h
index fe4c5da..ad0c411 100644
--- a/chrome/browser/autofill/form_structure.h
+++ b/chrome/browser/autofill/form_structure.h
@@ -31,6 +31,8 @@ enum UploadRequired {
USE_UPLOAD_RATES
};
+class AutoFillMetrics;
+
// FormStructure stores a single HTML form together with the values entered
// in the fields along with additional information needed by AutoFill.
class FormStructure {
@@ -55,7 +57,8 @@ class FormStructure {
// same as the one passed to EncodeQueryRequest when constructing the query.
static void ParseQueryResponse(const std::string& response_xml,
const std::vector<FormStructure*>& forms,
- UploadRequired* upload_required);
+ UploadRequired* upload_required,
+ const AutoFillMetrics& metric_logger);
// The unique signature for this form, composed of the target url domain,
// the form name, and the form field names in a 64-bit hash.
diff --git a/chrome/browser/autofill/form_structure_browsertest.cc b/chrome/browser/autofill/form_structure_browsertest.cc
index dc64052..ae38f7d 100644
--- a/chrome/browser/autofill/form_structure_browsertest.cc
+++ b/chrome/browser/autofill/form_structure_browsertest.cc
@@ -4,20 +4,74 @@
#include <vector>
+#include "base/file_path.h"
+#include "base/path_service.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_manager.h"
#include "chrome/browser/autofill/form_structure.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/common/chrome_paths.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "googleurl/src/gurl.h"
+namespace {
+
+FilePath GetInputFileDirectory() {
+ FilePath test_data_dir_;
+ PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_);
+ test_data_dir_ = test_data_dir_.AppendASCII("autofill_heuristics")
+ .AppendASCII("input");
+ return test_data_dir_;
+}
+
+FilePath GetOutputFileDirectory() {
+ FilePath test_data_dir_;
+ PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_);
+ test_data_dir_ = test_data_dir_.AppendASCII("autofill_heuristics")
+ .AppendASCII("output");
+ return test_data_dir_;
+}
+
+// Write |content| to |file|. Returns true on success.
+bool WriteFile(const FilePath& file, const std::string& content) {
+ int write_size = file_util::WriteFile(file, content.c_str(),
+ content.length());
+ return write_size == static_cast<int>(content.length());
+}
+
+// Convert |html| to URL format, and return the converted string.
+const std::string ConvertToURLFormat(const std::string& html) {
+ return std::string("data:text/html;charset=utf-8,") + html;
+}
+
+// Compare |output_file_source| with |form_string|. Returns true when they are
+// identical.
+bool CompareText(const std::string& output_file_source,
+ const std::string& form_string) {
+ std::string output_file = output_file_source;
+ std::string form = form_string;
+
+ ReplaceSubstringsAfterOffset(&output_file, 0, "\r\n", " ");
+ ReplaceSubstringsAfterOffset(&output_file, 0, "\r", " ");
+ ReplaceSubstringsAfterOffset(&output_file, 0, "\n", " ");
+ ReplaceSubstringsAfterOffset(&form, 0, "\n", " ");
+
+ return (output_file == form);
+}
+
+} // namespace
+
// Test class for verifying proper form structure as determined by AutoFill
-// heuristics. After a test loads HTML content with a call to |NavigateToURL|
-// the |AutoFillManager| associated with the tab contents is queried for the
-// form structures that were loaded and parsed.
-// These form structures are serialized to string form and compared with
-// expected results.
+// heuristics. A test inputs each form file(e.g. form_[language_code].html),
+// loads its HTML content with a call to |NavigateToURL|, the |AutoFillManager|
+// associated with the tab contents is queried for the form structures that
+// were loaded and parsed. These form structures are serialized to string form.
+// If this is the first time test is run, a gold test result file is generated
+// in output directory, else the form structures are compared against the
+// existing result file.
class FormStructureBrowserTest : public InProcessBrowserTest {
public:
FormStructureBrowserTest() {}
@@ -51,8 +105,6 @@ const std::string FormStructureBrowserTest::FormStructuresToString(
for (std::vector<FormStructure*>::const_iterator iter = forms.begin();
iter != forms.end();
++iter) {
- forms_string += (*iter)->source_url().spec();
- forms_string += "\n";
for (std::vector<AutoFillField*>::const_iterator field_iter =
(*iter)->begin();
@@ -162,55 +214,53 @@ const std::string FormStructureBrowserTest::AutoFillFieldTypeToString(
default:
NOTREACHED() << "Invalid AutoFillFieldType value.";
}
-
return std::string();
}
-IN_PROC_BROWSER_TEST_F(FormStructureBrowserTest, BasicFormStructure) {
- ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
- ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
- browser(), GURL("data:text/html;charset=utf-8,"
- "<form action=\"http://www.google.com/\" method=\"POST\">"
- "<label for=\"firstname\">First name:</label>"
- " <input type=\"text\" id=\"firstname\"/><br />"
- "<label for=\"lastname\">Last name:</label>"
- " <input type=\"text\" id=\"lastname\" /><br />"
- "<label for=\"address1\">Address line 1:</label>"
- " <input type=\"text\" id=\"address1\" /><br />"
- "<label for=\"address2\">Address line 2:</label>"
- " <input type=\"text\" id=\"address2\" /><br />"
- "<label for=\"city\">City:</label>"
- " <input type=\"text\" id=\"city\" /><br />"
- "</form>")));
-
- ASSERT_NO_FATAL_FAILURE(ui_test_utils::ClickOnView(browser(),
- VIEW_ID_TAB_CONTAINER));
- ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(),
- VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
-
- AutoFillManager* autofill_manager =
- browser()->GetSelectedTabContents()->GetAutoFillManager();
- ASSERT_NE(static_cast<AutoFillManager*>(NULL), autofill_manager);
- std::vector<FormStructure*> forms = GetFormStructures(*autofill_manager);
- std::string expected("data:text/html;charset=utf-8,"
- "<form action=\"http://www.google.com/\""
- " method=\"POST\">"
- "<label for=\"firstname\">First name:</label>"
- " <input type=\"text\" id=\"firstname\"/><br />"
- "<label for=\"lastname\">Last name:</label>"
- " <input type=\"text\" id=\"lastname\" /><br />"
- "<label for=\"address1\">Address line 1:</label>"
- " <input type=\"text\" id=\"address1\" /><br />"
- "<label for=\"address2\">Address line 2:</label>"
- " <input type=\"text\" id=\"address2\" /><br />"
- "<label for=\"city\">City:</label>"
- " <input type=\"text\" id=\"city\" /><br />"
- "</form>\n"
- "NAME_FIRST\n"
- "NAME_LAST\n"
- "ADDRESS_HOME_LINE1\n"
- "ADDRESS_HOME_LINE2\n"
- "ADDRESS_HOME_CITY\n");
-
- EXPECT_EQ(expected, FormStructureBrowserTest::FormStructuresToString(forms));
+IN_PROC_BROWSER_TEST_F(FormStructureBrowserTest, HTMLFiles) {
+ FilePath input_file_path = GetInputFileDirectory();
+ file_util::FileEnumerator input_file_enumerator(input_file_path,
+ false, file_util::FileEnumerator::FILES, FILE_PATH_LITERAL("*.html"));
+
+ for (input_file_path = input_file_enumerator.Next();
+ !input_file_path.empty();
+ input_file_path = input_file_enumerator.Next()) {
+ std::string input_file_source;
+
+ ASSERT_TRUE(file_util::ReadFileToString(input_file_path,
+ &input_file_source));
+ input_file_source = ConvertToURLFormat(input_file_source);
+
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+ ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+ browser(), GURL(input_file_source)));
+
+ ASSERT_NO_FATAL_FAILURE(ui_test_utils::ClickOnView(browser(),
+ VIEW_ID_TAB_CONTAINER));
+ ASSERT_TRUE(ui_test_utils::IsViewFocused(
+ browser(),
+ VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
+
+ AutoFillManager* autofill_manager =
+ browser()->GetSelectedTabContents()->GetAutoFillManager();
+ ASSERT_NE(static_cast<AutoFillManager*>(NULL), autofill_manager);
+ std::vector<FormStructure*> forms = GetFormStructures(*autofill_manager);
+
+ FilePath output_file_directory = GetOutputFileDirectory();
+ FilePath output_file_path = output_file_directory.Append(
+ input_file_path.BaseName().StripTrailingSeparators().ReplaceExtension(
+ FILE_PATH_LITERAL(".out")));
+
+ std::string output_file_source;
+ if (file_util::ReadFileToString(output_file_path, &output_file_source)) {
+ ASSERT_TRUE(CompareText(
+ output_file_source,
+ FormStructureBrowserTest::FormStructuresToString(forms)));
+
+ } else {
+ ASSERT_TRUE(WriteFile(
+ output_file_path,
+ FormStructureBrowserTest::FormStructuresToString(forms)));
+ }
+ }
}
diff --git a/chrome/browser/autofill/home_address.cc b/chrome/browser/autofill/home_address.cc
new file mode 100644
index 0000000..5c036a1
--- /dev/null
+++ b/chrome/browser/autofill/home_address.cc
@@ -0,0 +1,41 @@
+// 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.
+
+#include "chrome/browser/autofill/home_address.h"
+
+HomeAddress::HomeAddress() {}
+
+HomeAddress::~HomeAddress() {}
+
+FormGroup* HomeAddress::Clone() const {
+ return new HomeAddress(*this);
+}
+
+AutoFillFieldType HomeAddress::GetLine1Type() const {
+ return ADDRESS_HOME_LINE1;
+}
+
+AutoFillFieldType HomeAddress::GetLine2Type() const {
+ return ADDRESS_HOME_LINE2;
+}
+
+AutoFillFieldType HomeAddress::GetAptNumType() const {
+ return ADDRESS_HOME_APT_NUM;
+}
+
+AutoFillFieldType HomeAddress::GetCityType() const {
+ return ADDRESS_HOME_CITY;
+}
+
+AutoFillFieldType HomeAddress::GetStateType() const {
+ return ADDRESS_HOME_STATE;
+}
+
+AutoFillFieldType HomeAddress::GetZipCodeType() const {
+ return ADDRESS_HOME_ZIP;
+}
+
+AutoFillFieldType HomeAddress::GetCountryType() const {
+ return ADDRESS_HOME_COUNTRY;
+}
diff --git a/chrome/browser/autofill/home_address.h b/chrome/browser/autofill/home_address.h
index ced2922..9f441f5 100644
--- a/chrome/browser/autofill/home_address.h
+++ b/chrome/browser/autofill/home_address.h
@@ -14,37 +14,18 @@ class FormGroup;
// A specialization of Address that identifies itself as a home address.
class HomeAddress : public Address {
public:
- HomeAddress() {}
- FormGroup* Clone() const { return new HomeAddress(*this); }
+ HomeAddress();
+ virtual ~HomeAddress();
+ virtual FormGroup* Clone() const;
protected:
- virtual AutoFillFieldType GetLine1Type() const {
- return ADDRESS_HOME_LINE1;
- }
-
- virtual AutoFillFieldType GetLine2Type() const {
- return ADDRESS_HOME_LINE2;
- }
-
- virtual AutoFillFieldType GetAptNumType() const {
- return ADDRESS_HOME_APT_NUM;
- }
-
- virtual AutoFillFieldType GetCityType() const {
- return ADDRESS_HOME_CITY;
- }
-
- virtual AutoFillFieldType GetStateType() const {
- return ADDRESS_HOME_STATE;
- }
-
- virtual AutoFillFieldType GetZipCodeType() const {
- return ADDRESS_HOME_ZIP;
- }
-
- virtual AutoFillFieldType GetCountryType() const {
- return ADDRESS_HOME_COUNTRY;
- }
+ virtual AutoFillFieldType GetLine1Type() const;
+ virtual AutoFillFieldType GetLine2Type() const;
+ virtual AutoFillFieldType GetAptNumType() const;
+ virtual AutoFillFieldType GetCityType() const;
+ virtual AutoFillFieldType GetStateType() const;
+ virtual AutoFillFieldType GetZipCodeType() const;
+ virtual AutoFillFieldType GetCountryType() const;
private:
explicit HomeAddress(const HomeAddress& address) : Address(address) {}
diff --git a/chrome/browser/autofill/home_phone_number.cc b/chrome/browser/autofill/home_phone_number.cc
new file mode 100644
index 0000000..f48efa8
--- /dev/null
+++ b/chrome/browser/autofill/home_phone_number.cc
@@ -0,0 +1,29 @@
+// 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.
+
+#include "chrome/browser/autofill/home_phone_number.h"
+
+FormGroup* HomePhoneNumber::Clone() const {
+ return new HomePhoneNumber(*this);
+}
+
+AutoFillFieldType HomePhoneNumber::GetNumberType() const {
+ return PHONE_HOME_NUMBER;
+}
+
+AutoFillFieldType HomePhoneNumber::GetCityCodeType() const {
+ return PHONE_HOME_CITY_CODE;
+}
+
+AutoFillFieldType HomePhoneNumber::GetCountryCodeType() const {
+ return PHONE_HOME_COUNTRY_CODE;
+}
+
+AutoFillFieldType HomePhoneNumber::GetCityAndNumberType() const {
+ return PHONE_HOME_CITY_AND_NUMBER;
+}
+
+AutoFillFieldType HomePhoneNumber::GetWholeNumberType() const {
+ return PHONE_HOME_WHOLE_NUMBER;
+}
diff --git a/chrome/browser/autofill/home_phone_number.h b/chrome/browser/autofill/home_phone_number.h
index e2aba0a..3e311e6 100644
--- a/chrome/browser/autofill/home_phone_number.h
+++ b/chrome/browser/autofill/home_phone_number.h
@@ -13,28 +13,14 @@ class FormGroup;
class HomePhoneNumber : public PhoneNumber {
public:
HomePhoneNumber() {}
- virtual FormGroup* Clone() const { return new HomePhoneNumber(*this); }
+ virtual FormGroup* Clone() const;
protected:
- virtual AutoFillFieldType GetNumberType() const {
- return PHONE_HOME_NUMBER;
- }
-
- virtual AutoFillFieldType GetCityCodeType() const {
- return PHONE_HOME_CITY_CODE;
- }
-
- virtual AutoFillFieldType GetCountryCodeType() const {
- return PHONE_HOME_COUNTRY_CODE;
- }
-
- virtual AutoFillFieldType GetCityAndNumberType() const {
- return PHONE_HOME_CITY_AND_NUMBER;
- }
-
- virtual AutoFillFieldType GetWholeNumberType() const {
- return PHONE_HOME_WHOLE_NUMBER;
- }
+ virtual AutoFillFieldType GetNumberType() const;
+ virtual AutoFillFieldType GetCityCodeType() const;
+ virtual AutoFillFieldType GetCountryCodeType() const;
+ virtual AutoFillFieldType GetCityAndNumberType() const;
+ virtual AutoFillFieldType GetWholeNumberType() const;
private:
explicit HomePhoneNumber(const HomePhoneNumber& phone) : PhoneNumber(phone) {}
diff --git a/chrome/browser/autofill/name_field.cc b/chrome/browser/autofill/name_field.cc
index a2753be..1c02099 100644
--- a/chrome/browser/autofill/name_field.cc
+++ b/chrome/browser/autofill/name_field.cc
@@ -4,7 +4,10 @@
#include "chrome/browser/autofill/name_field.h"
+<<<<<<< HEAD
#include "app/l10n_util.h"
+=======
+>>>>>>> chromium.org at r10.0.621.0
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
@@ -23,6 +26,12 @@ NameField* NameField::Parse(std::vector<AutoFillField*>::const_iterator* iter,
return field;
}
+bool FullNameField::GetFieldInfo(FieldTypeMap* field_type_map) const {
+ bool ok = Add(field_type_map, field_, AutoFillType(NAME_FULL));
+ DCHECK(ok);
+ return true;
+}
+
FullNameField* FullNameField::Parse(
std::vector<AutoFillField*>::const_iterator* iter) {
// Exclude labels containing the string "username", which typically
@@ -41,6 +50,10 @@ FullNameField* FullNameField::Parse(
return NULL;
}
+FullNameField::FullNameField(AutoFillField* field)
+ : field_(field) {
+}
+
FirstLastNameField* FirstLastNameField::Parse1(
std::vector<AutoFillField*>::const_iterator* iter) {
// Some pages (e.g. Overstock_comBilling.html, SmithsonianCheckout.html)
diff --git a/chrome/browser/autofill/name_field.h b/chrome/browser/autofill/name_field.h
index 7b16e77..0c6bd09 100644
--- a/chrome/browser/autofill/name_field.h
+++ b/chrome/browser/autofill/name_field.h
@@ -8,7 +8,6 @@
#include <vector>
-#include "base/logging.h"
#include "chrome/browser/autofill/autofill_field.h"
#include "chrome/browser/autofill/form_field.h"
@@ -28,17 +27,13 @@ class NameField : public FormField {
// A form field that can parse a full name field.
class FullNameField : public NameField {
public:
- virtual bool GetFieldInfo(FieldTypeMap* field_type_map) const {
- bool ok = Add(field_type_map, field_, AutoFillType(NAME_FULL));
- DCHECK(ok);
- return true;
- }
+ virtual bool GetFieldInfo(FieldTypeMap* field_type_map) const;
static FullNameField* Parse(
std::vector<AutoFillField*>::const_iterator* iter);
private:
- explicit FullNameField(AutoFillField* field) : field_(field) {}
+ explicit FullNameField(AutoFillField* field);
AutoFillField* field_;
DISALLOW_COPY_AND_ASSIGN(FullNameField);
diff --git a/chrome/browser/autofill/personal_data_manager.cc b/chrome/browser/autofill/personal_data_manager.cc
index 13b1661..085ee53 100644
--- a/chrome/browser/autofill/personal_data_manager.cc
+++ b/chrome/browser/autofill/personal_data_manager.cc
@@ -11,10 +11,11 @@
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_field.h"
+#include "chrome/browser/autofill/autofill-inl.h"
#include "chrome/browser/autofill/form_structure.h"
#include "chrome/browser/autofill/phone_number.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/webdata/web_data_service.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/pref_names.h"
@@ -28,18 +29,32 @@ const int kMinProfileImportSize = 3;
const int kMinCreditCardImportSize = 2;
template<typename T>
-class FormGroupGUIDMatchesFunctor {
+class FormGroupMatchesByGUIDFunctor {
public:
- explicit FormGroupGUIDMatchesFunctor(const std::string& guid) : guid_(guid) {}
+ explicit FormGroupMatchesByGUIDFunctor(const std::string& guid)
+ : guid_(guid) {
+ }
bool operator()(const T& form_group) {
return form_group.guid() == guid_;
}
+ bool operator()(const T* form_group) {
+ return form_group->guid() == guid_;
+ }
+
private:
std::string guid_;
};
+template<typename T, typename C>
+bool FindByGUID(const C& container, const std::string& guid) {
+ return std::find_if(
+ container.begin(),
+ container.end(),
+ FormGroupMatchesByGUIDFunctor<T>(guid)) != container.end();
+}
+
template<typename T>
class DereferenceFunctor {
public:
@@ -54,51 +69,6 @@ T* address_of(T& v) {
return &v;
}
-bool FindInProfilesByGUID(const std::vector<AutoFillProfile>& profiles,
- const std::string& guid) {
- for (std::vector<AutoFillProfile>::const_iterator iter = profiles.begin();
- iter != profiles.end();
- ++iter) {
- if (iter->guid() == guid)
- return true;
- }
- return false;
-}
-
-bool FindInScopedProfilesByGUID(const ScopedVector<AutoFillProfile>& profiles,
- const std::string& guid) {
- for (std::vector<AutoFillProfile*>::const_iterator iter = profiles.begin();
- iter != profiles.end();
- ++iter) {
- if ((*iter)->guid() == guid)
- return true;
- }
- return false;
-}
-
-bool FindInCreditCardsByGUID(const std::vector<CreditCard>& credit_cards,
- const std::string& guid) {
- for (std::vector<CreditCard>::const_iterator iter = credit_cards.begin();
- iter != credit_cards.end();
- ++iter) {
- if (iter->guid() == guid)
- return true;
- }
- return false;
-}
-
-bool FindInScopedCreditCardsByGUID(
- const ScopedVector<CreditCard>& credit_cards, const std::string& guid) {
- for (std::vector<CreditCard*>::const_iterator iter =
- credit_cards.begin();
- iter != credit_cards.end();
- ++iter) {
- if ((*iter)->guid() == guid)
- return true;
- }
- return false;
-}
-
} // namespace
PersonalDataManager::~PersonalDataManager() {
@@ -335,21 +305,22 @@ void PersonalDataManager::SetProfiles(std::vector<AutoFillProfile>* profiles) {
for (std::vector<AutoFillProfile*>::const_iterator iter =
web_profiles_.begin();
iter != web_profiles_.end(); ++iter) {
- if (!FindInProfilesByGUID(*profiles, (*iter)->guid()))
+ if (!FindByGUID<AutoFillProfile>(*profiles, (*iter)->guid()))
wds->RemoveAutoFillProfileGUID((*iter)->guid());
}
// Update the web database with the existing profiles.
for (std::vector<AutoFillProfile>::iterator iter = profiles->begin();
iter != profiles->end(); ++iter) {
- if (FindInScopedProfilesByGUID(web_profiles_, iter->guid()))
+ if (FindByGUID<AutoFillProfile>(web_profiles_, iter->guid()))
wds->UpdateAutoFillProfileGUID(*iter);
}
- // Add the new profiles to the web database.
+ // Add the new profiles to the web database. Don't add a duplicate.
for (std::vector<AutoFillProfile>::iterator iter = profiles->begin();
iter != profiles->end(); ++iter) {
- if (!FindInScopedProfilesByGUID(web_profiles_, iter->guid()))
+ if (!FindByGUID<AutoFillProfile>(web_profiles_, iter->guid()) &&
+ !FindByContents(web_profiles_, *iter))
wds->AddAutoFillProfileGUID(*iter);
}
#endif
@@ -391,21 +362,22 @@ void PersonalDataManager::SetCreditCards(
// removed.
for (std::vector<CreditCard*>::const_iterator iter = credit_cards_.begin();
iter != credit_cards_.end(); ++iter) {
- if (!FindInCreditCardsByGUID(*credit_cards, (*iter)->guid()))
+ if (!FindByGUID<CreditCard>(*credit_cards, (*iter)->guid()))
wds->RemoveCreditCardGUID((*iter)->guid());
}
// Update the web database with the existing credit cards.
for (std::vector<CreditCard>::iterator iter = credit_cards->begin();
iter != credit_cards->end(); ++iter) {
- if (FindInScopedCreditCardsByGUID(credit_cards_, iter->guid()))
+ if (FindByGUID<CreditCard>(credit_cards_, iter->guid()))
wds->UpdateCreditCardGUID(*iter);
}
- // Add the new credit cards to the web database.
+ // Add the new credit cards to the web database. Don't add a duplicate.
for (std::vector<CreditCard>::iterator iter = credit_cards->begin();
iter != credit_cards->end(); ++iter) {
- if (!FindInScopedCreditCardsByGUID(credit_cards_, iter->guid()))
+ if (!FindByGUID<CreditCard>(credit_cards_, iter->guid()) &&
+ !FindByContents(credit_cards_, *iter))
wds->AddCreditCardGUID(*iter);
}
@@ -518,7 +490,7 @@ void PersonalDataManager::RemoveProfile(const std::string& guid) {
// Remove the profile that matches |guid|.
profiles.erase(
std::remove_if(profiles.begin(), profiles.end(),
- FormGroupGUIDMatchesFunctor<AutoFillProfile>(guid)),
+ FormGroupMatchesByGUIDFunctor<AutoFillProfile>(guid)),
profiles.end());
SetProfiles(&profiles);
@@ -576,7 +548,7 @@ void PersonalDataManager::RemoveCreditCard(const std::string& guid) {
// Remove the credit card that matches |guid|.
credit_cards.erase(
std::remove_if(credit_cards.begin(), credit_cards.end(),
- FormGroupGUIDMatchesFunctor<CreditCard>(guid)),
+ FormGroupMatchesByGUIDFunctor<CreditCard>(guid)),
credit_cards.end());
SetCreditCards(&credit_cards);
@@ -599,8 +571,9 @@ void PersonalDataManager::GetPossibleFieldTypes(const string16& text,
return;
}
- for (ScopedVector<AutoFillProfile>::iterator iter = web_profiles_.begin();
- iter != web_profiles_.end(); ++iter) {
+ const std::vector<AutoFillProfile*>& profiles = this->profiles();
+ for (std::vector<AutoFillProfile*>::const_iterator iter = profiles.begin();
+ iter != profiles.end(); ++iter) {
const FormGroup* profile = *iter;
if (!profile) {
DLOG(ERROR) << "NULL information in profiles list";
@@ -621,7 +594,7 @@ void PersonalDataManager::GetPossibleFieldTypes(const string16& text,
credit_card->GetPossibleFieldTypes(clean_info, possible_types);
}
- if (possible_types->size() == 0)
+ if (possible_types->empty())
possible_types->insert(UNKNOWN_TYPE);
}
@@ -629,6 +602,10 @@ bool PersonalDataManager::HasPassword() {
return !password_hash_.empty();
}
+bool PersonalDataManager::IsDataLoaded() const {
+ return is_data_loaded_;
+}
+
const std::vector<AutoFillProfile*>& PersonalDataManager::profiles() {
// |profile_| is NULL in AutoFillManagerTest.
bool auxiliary_profiles_enabled = profile_ ? profile_->GetPrefs()->GetBoolean(
@@ -651,6 +628,14 @@ const std::vector<AutoFillProfile*>& PersonalDataManager::profiles() {
return profiles_;
}
+const std::vector<AutoFillProfile*>& PersonalDataManager::web_profiles() {
+ return web_profiles_.get();
+}
+
+const std::vector<CreditCard*>& PersonalDataManager::credit_cards() {
+ return credit_cards_.get();
+}
+
AutoFillProfile* PersonalDataManager::CreateNewEmptyAutoFillProfileForDBThread(
const string16& label) {
#ifdef ANDROID
diff --git a/chrome/browser/autofill/personal_data_manager.h b/chrome/browser/autofill/personal_data_manager.h
index 8d79315..6d25013 100644
--- a/chrome/browser/autofill/personal_data_manager.h
+++ b/chrome/browser/autofill/personal_data_manager.h
@@ -132,19 +132,15 @@ class PersonalDataManager
bool HasPassword();
// Returns whether the personal data has been loaded from the web database.
- virtual bool IsDataLoaded() const { return is_data_loaded_; }
+ virtual bool IsDataLoaded() const;
// This PersonalDataManager owns these profiles and credit cards. Their
// lifetime is until the web database is updated with new profile and credit
// card information, respectively. |profiles()| returns both web and
// auxiliary profiles. |web_profiles()| returns only web profiles.
const std::vector<AutoFillProfile*>& profiles();
- virtual const std::vector<AutoFillProfile*>& web_profiles() {
- return web_profiles_.get();
- }
- virtual const std::vector<CreditCard*>& credit_cards() {
- return credit_cards_.get();
- }
+ virtual const std::vector<AutoFillProfile*>& web_profiles();
+ virtual const std::vector<CreditCard*>& credit_cards();
// Creates a profile labeled |label|.
// This must be called on the DB thread with the expectation that the
diff --git a/chrome/browser/autofill/personal_data_manager_mac.mm b/chrome/browser/autofill/personal_data_manager_mac.mm
index 4a9fb25..d6ddf1b 100644
--- a/chrome/browser/autofill/personal_data_manager_mac.mm
+++ b/chrome/browser/autofill/personal_data_manager_mac.mm
@@ -13,7 +13,7 @@
#include "base/sys_string_conversions.h"
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/phone_number.h"
-#include "chrome/browser/guid.h"
+#include "chrome/common/guid.h"
#include "grit/generated_resources.h"
namespace {
diff --git a/chrome/browser/autofill/personal_data_manager_unittest.cc b/chrome/browser/autofill/personal_data_manager_unittest.cc
index a4b3099..79f3d58 100644
--- a/chrome/browser/autofill/personal_data_manager_unittest.cc
+++ b/chrome/browser/autofill/personal_data_manager_unittest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <string>
+
#include "base/basictypes.h"
#include "base/message_loop.h"
#include "base/ref_counted.h"
@@ -12,13 +14,13 @@
#include "chrome/browser/autofill/form_structure.h"
#include "chrome/browser/autofill/personal_data_manager.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/guid.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/password_manager/encryptor.h"
+#include "chrome/common/guid.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_observer_mock.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_profile.h"
@@ -543,7 +545,8 @@ TEST_F(PersonalDataManagerTest, ImportFormData) {
EXPECT_EQ(0, expected.Compare(*results[0]));
}
-TEST_F(PersonalDataManagerTest, ImportFormDataNotEnoughFilledFields) {
+// Crashy, http://crbug.com/67423.
+TEST_F(PersonalDataManagerTest, DISABLED_ImportFormDataNotEnoughFilledFields) {
FormData form;
webkit_glue::FormField field;
autofill_test::CreateTestFormField(
@@ -1385,4 +1388,3 @@ TEST_F(PersonalDataManagerTest, AggregateCreditCardWithMissingInfoInOld) {
ASSERT_EQ(1U, results2.size());
EXPECT_EQ(0, expected2.Compare(*results2[0]));
}
-
diff --git a/chrome/browser/autofill/phone_number.h b/chrome/browser/autofill/phone_number.h
index 277e1b1..25648bc 100644
--- a/chrome/browser/autofill/phone_number.h
+++ b/chrome/browser/autofill/phone_number.h
@@ -9,6 +9,7 @@
#include <vector>
#include "base/string16.h"
+#include "base/gtest_prod_util.h"
#include "chrome/browser/autofill/form_group.h"
// A form group that stores phone number information.
@@ -48,8 +49,7 @@ class PhoneNumber : public FormGroup {
explicit PhoneNumber(const PhoneNumber& phone_number);
private:
- // For test.
- friend class PhoneNumberTest;
+ FRIEND_TEST_ALL_PREFIXES(PhoneNumberTest, Matcher);
void operator=(const PhoneNumber& phone_number);
diff --git a/chrome/browser/autofill/phone_number_unittest.cc b/chrome/browser/autofill/phone_number_unittest.cc
index bcb37f2..c5dc712 100644
--- a/chrome/browser/autofill/phone_number_unittest.cc
+++ b/chrome/browser/autofill/phone_number_unittest.cc
@@ -7,33 +7,8 @@
#include "chrome/browser/autofill/phone_number.h"
#include "testing/gtest/include/gtest/gtest.h"
-class PhoneNumberTest : public testing::Test {
- public:
- PhoneNumberTest() {}
-
- void set_whole_number(PhoneNumber* phone_number,
- const string16& whole_number) {
- phone_number->set_whole_number(whole_number);
- }
-
- bool IsNumber(PhoneNumber* phone_number, const string16& text) const {
- return phone_number->IsNumber(text);
- }
-
- bool IsCityCode(PhoneNumber* phone_number, const string16& text) const {
- return phone_number->IsCityCode(text);
- }
-
- bool IsCountryCode(PhoneNumber* phone_number, const string16& text) const {
- return phone_number->IsCountryCode(text);
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(PhoneNumberTest);
-};
-
// Tests the phone number parser.
-TEST_F(PhoneNumberTest, Parser) {
+TEST(PhoneNumberTest, Parser) {
string16 number;
string16 city_code;
string16 country_code;
@@ -119,28 +94,28 @@ TEST_F(PhoneNumberTest, Parser) {
EXPECT_EQ(ASCIIToUTF16("01"), country_code);
}
-TEST_F(PhoneNumberTest, Matcher) {
+TEST(PhoneNumberTest, Matcher) {
string16 phone(ASCIIToUTF16("121231234567"));
HomePhoneNumber phone_number;
- set_whole_number(&phone_number, phone);
+ phone_number.set_whole_number(phone);
// Phone number is now country_code == 12, city_code = 123, number = 1234567.
char test_number[] = "1234567890";
for (int i = arraysize(test_number) - 1; i >= 0; --i) {
test_number[i] = 0; // Cut the string.
if (i > 7) {
- EXPECT_FALSE(IsNumber(&phone_number, ASCIIToUTF16(test_number)));
+ EXPECT_FALSE(phone_number.IsNumber(ASCIIToUTF16(test_number)));
} else {
- EXPECT_TRUE(IsNumber(&phone_number, ASCIIToUTF16(test_number)));
+ EXPECT_TRUE(phone_number.IsNumber(ASCIIToUTF16(test_number)));
}
if (i > 3) {
- EXPECT_FALSE(IsCityCode(&phone_number, ASCIIToUTF16(test_number)));
+ EXPECT_FALSE(phone_number.IsCityCode(ASCIIToUTF16(test_number)));
} else {
- EXPECT_TRUE(IsCityCode(&phone_number, ASCIIToUTF16(test_number)));
+ EXPECT_TRUE(phone_number.IsCityCode(ASCIIToUTF16(test_number)));
}
if (i > 2) {
- EXPECT_FALSE(IsCountryCode(&phone_number, ASCIIToUTF16(test_number)));
+ EXPECT_FALSE(phone_number.IsCountryCode(ASCIIToUTF16(test_number)));
} else {
- EXPECT_TRUE(IsCountryCode(&phone_number, ASCIIToUTF16(test_number)));
+ EXPECT_TRUE(phone_number.IsCountryCode(ASCIIToUTF16(test_number)));
}
}
}
diff --git a/chrome/browser/automation/automation_autocomplete_edit_tracker.cc b/chrome/browser/automation/automation_autocomplete_edit_tracker.cc
new file mode 100644
index 0000000..e34e26f
--- /dev/null
+++ b/chrome/browser/automation/automation_autocomplete_edit_tracker.cc
@@ -0,0 +1,28 @@
+// 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.
+
+#include "chrome/browser/automation/automation_autocomplete_edit_tracker.h"
+
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
+
+AutomationAutocompleteEditTracker::AutomationAutocompleteEditTracker(
+ IPC::Message::Sender* automation)
+ : AutomationResourceTracker<AutocompleteEditView*>(automation) {
+}
+
+AutomationAutocompleteEditTracker::~AutomationAutocompleteEditTracker() {
+}
+
+void AutomationAutocompleteEditTracker::AddObserver(
+ AutocompleteEditView* resource) {
+ registrar_.Add(this, NotificationType::AUTOCOMPLETE_EDIT_DESTROYED,
+ Source<AutocompleteEditView>(resource));
+}
+
+void AutomationAutocompleteEditTracker::RemoveObserver(
+ AutocompleteEditView* resource) {
+ registrar_.Remove(this, NotificationType::AUTOCOMPLETE_EDIT_DESTROYED,
+ Source<AutocompleteEditView>(resource));
+}
diff --git a/chrome/browser/automation/automation_autocomplete_edit_tracker.h b/chrome/browser/automation/automation_autocomplete_edit_tracker.h
index 2394b89..0e0a4ed 100644
--- a/chrome/browser/automation/automation_autocomplete_edit_tracker.h
+++ b/chrome/browser/automation/automation_autocomplete_edit_tracker.h
@@ -8,27 +8,14 @@
#include "chrome/browser/autocomplete/autocomplete_edit_view.h"
#include "chrome/browser/automation/automation_resource_tracker.h"
-#include "chrome/common/notification_source.h"
-#include "chrome/common/notification_type.h"
class AutomationAutocompleteEditTracker
: public AutomationResourceTracker<AutocompleteEditView*> {
public:
- explicit AutomationAutocompleteEditTracker(IPC::Message::Sender* automation)
- : AutomationResourceTracker<AutocompleteEditView*>(automation) { }
-
- virtual ~AutomationAutocompleteEditTracker() {
- }
-
- virtual void AddObserver(AutocompleteEditView* resource) {
- registrar_.Add(this, NotificationType::AUTOCOMPLETE_EDIT_DESTROYED,
- Source<AutocompleteEditView>(resource));
- }
-
- virtual void RemoveObserver(AutocompleteEditView* resource) {
- registrar_.Remove(this, NotificationType::AUTOCOMPLETE_EDIT_DESTROYED,
- Source<AutocompleteEditView>(resource));
- }
+ explicit AutomationAutocompleteEditTracker(IPC::Message::Sender* automation);
+ virtual ~AutomationAutocompleteEditTracker();
+ virtual void AddObserver(AutocompleteEditView* resource);
+ virtual void RemoveObserver(AutocompleteEditView* resource);
};
#endif // CHROME_BROWSER_AUTOMATION_AUTOMATION_AUTOCOMPLETE_EDIT_TRACKER_H_
diff --git a/chrome/browser/automation/automation_browser_tracker.cc b/chrome/browser/automation/automation_browser_tracker.cc
new file mode 100644
index 0000000..3000e44
--- /dev/null
+++ b/chrome/browser/automation/automation_browser_tracker.cc
@@ -0,0 +1,24 @@
+// 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.
+
+#include "chrome/browser/automation/automation_browser_tracker.h"
+
+#include "chrome/common/notification_source.h"
+
+AutomationBrowserTracker::AutomationBrowserTracker(
+ IPC::Message::Sender* automation)
+ : AutomationResourceTracker<Browser*>(automation) {
+}
+
+AutomationBrowserTracker::~AutomationBrowserTracker() {}
+
+void AutomationBrowserTracker::AddObserver(Browser* resource) {
+ registrar_.Add(this, NotificationType::BROWSER_CLOSED,
+ Source<Browser>(resource));
+}
+
+void AutomationBrowserTracker::RemoveObserver(Browser* resource) {
+ registrar_.Remove(this, NotificationType::BROWSER_CLOSED,
+ Source<Browser>(resource));
+}
diff --git a/chrome/browser/automation/automation_browser_tracker.h b/chrome/browser/automation/automation_browser_tracker.h
index 147b820..f3c8d3b 100644
--- a/chrome/browser/automation/automation_browser_tracker.h
+++ b/chrome/browser/automation/automation_browser_tracker.h
@@ -7,27 +7,16 @@
#pragma once
#include "chrome/browser/automation/automation_resource_tracker.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/common/notification_source.h"
+
+class Browser;
// Tracks Browser objects.
class AutomationBrowserTracker : public AutomationResourceTracker<Browser*> {
public:
- explicit AutomationBrowserTracker(IPC::Message::Sender* automation)
- : AutomationResourceTracker<Browser*>(automation) { }
-
- virtual ~AutomationBrowserTracker() {
- }
-
- virtual void AddObserver(Browser* resource) {
- registrar_.Add(this, NotificationType::BROWSER_CLOSED,
- Source<Browser>(resource));
- }
-
- virtual void RemoveObserver(Browser* resource) {
- registrar_.Remove(this, NotificationType::BROWSER_CLOSED,
- Source<Browser>(resource));
- }
+ explicit AutomationBrowserTracker(IPC::Message::Sender* automation);
+ virtual ~AutomationBrowserTracker();
+ virtual void AddObserver(Browser* resource);
+ virtual void RemoveObserver(Browser* resource);
};
#endif // CHROME_BROWSER_AUTOMATION_AUTOMATION_BROWSER_TRACKER_H__
diff --git a/chrome/browser/automation/automation_extension_tracker.cc b/chrome/browser/automation/automation_extension_tracker.cc
index 8ab734d..88ed0e9 100644
--- a/chrome/browser/automation/automation_extension_tracker.cc
+++ b/chrome/browser/automation/automation_extension_tracker.cc
@@ -3,8 +3,8 @@
// found in the LICENSE file.
#include "chrome/browser/automation/automation_extension_tracker.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_service.h"
@@ -13,8 +13,6 @@ AutomationExtensionTracker::AutomationExtensionTracker(
: AutomationResourceTracker<const Extension*>(automation) {
registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
NotificationService::AllSources());
- registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED,
- NotificationService::AllSources());
}
AutomationExtensionTracker::~AutomationExtensionTracker() {
@@ -27,20 +25,18 @@ void AutomationExtensionTracker::RemoveObserver(const Extension* resource) {}
void AutomationExtensionTracker::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
- if (type != NotificationType::EXTENSION_UNLOADED &&
- type != NotificationType::EXTENSION_UNLOADED_DISABLED)
+ if (type != NotificationType::EXTENSION_UNLOADED) {
+ NOTREACHED();
return;
-
- const Extension* extension = Details<const Extension>(details).ptr();
+ }
+ UnloadedExtensionInfo* info = Details<UnloadedExtensionInfo>(details).ptr();
+ const Extension* extension = info->extension;
Profile* profile = Source<Profile>(source).ptr();
if (profile) {
- ExtensionsService* service = profile->GetExtensionsService();
- if (service) {
+ ExtensionService* service = profile->GetExtensionService();
+ if (service && info->reason == UnloadedExtensionInfo::UNINSTALL) {
// Remove this extension only if it is uninstalled, not just disabled.
- // If it is being uninstalled, the extension will not be in the regular
- // or disabled list.
- if (!service->GetExtensionById(extension->id(), true))
- CloseResource(extension);
+ CloseResource(extension);
}
}
}
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc
index d903cd9..b782c2c 100644
--- a/chrome/browser/automation/automation_provider.cc
+++ b/chrome/browser/automation/automation_provider.cc
@@ -25,8 +25,6 @@
#include "base/values.h"
#include "base/waitable_event.h"
#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/app_modal_dialog.h"
-#include "chrome/browser/app_modal_dialog_queue.h"
#include "chrome/browser/autofill/autofill_manager.h"
#include "chrome/browser/automation/automation_autocomplete_edit_tracker.h"
#include "chrome/browser/automation/automation_browser_tracker.h"
@@ -47,6 +45,7 @@
#include "chrome/browser/browser_window.h"
#include "chrome/browser/browsing_data_remover.h"
#include "chrome/browser/character_encoding.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/dom_operation_notification_details.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/download/download_item.h"
@@ -59,22 +58,16 @@
#include "chrome/browser/extensions/extension_message_service.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
#include "chrome/browser/extensions/extension_toolbar_model.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/user_script_master.h"
-#include "chrome/browser/find_bar.h"
-#include "chrome/browser/find_bar_controller.h"
-#include "chrome/browser/find_notification_details.h"
-#include "chrome/browser/host_content_settings_map.h"
#include "chrome/browser/importer/importer.h"
#include "chrome/browser/importer/importer_data_types.h"
#include "chrome/browser/io_thread.h"
-#include "chrome/browser/location_bar.h"
-#include "chrome/browser/login_prompt.h"
#include "chrome/browser/net/url_request_mock_util.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/printing/print_job.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/ssl/ssl_manager.h"
@@ -84,6 +77,13 @@
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/translate/translate_infobar_delegate.h"
+#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
+#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h"
+#include "chrome/browser/ui/find_bar/find_bar.h"
+#include "chrome/browser/ui/find_bar/find_bar_controller.h"
+#include "chrome/browser/ui/find_bar/find_notification_details.h"
+#include "chrome/browser/ui/login/login_prompt.h"
+#include "chrome/browser/ui/omnibox/location_bar.h"
#include "chrome/common/automation_constants.h"
#include "chrome/common/automation_messages.h"
#include "chrome/common/chrome_constants.h"
@@ -93,7 +93,6 @@
#include "chrome/common/extensions/extension.h"
#include "chrome/common/json_value_serializer.h"
#include "chrome/common/net/url_request_context_getter.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/automation/tab_proxy.h"
@@ -103,7 +102,6 @@
#include "chrome/browser/automation/ui_controls.h"
#include "views/event.h"
#include "webkit/glue/password_form.h"
-#include "webkit/glue/plugins/plugin_list.h"
#if defined(OS_WIN)
#include "chrome/browser/external_tab_container_win.h"
@@ -176,9 +174,9 @@ bool AutomationProvider::InitializeChannel(const std::string& channel_id) {
use_named_interface ? IPC::Channel::MODE_NAMED_SERVER
: IPC::Channel::MODE_CLIENT,
this,
- automation_resource_message_filter_,
g_browser_process->io_thread()->message_loop(),
true, g_browser_process->shutdown_event()));
+ channel_->AddFilter(automation_resource_message_filter_);
TRACE_EVENT_END("AutomationProvider::InitializeChannel", 0, "");
@@ -200,7 +198,7 @@ void AutomationProvider::SetExpectedTabCount(size_t expected_tabs) {
void AutomationProvider::OnInitialLoadsComplete() {
initial_loads_complete_ = true;
if (is_connected_)
- Send(new AutomationMsg_InitialLoadsComplete(0));
+ Send(new AutomationMsg_InitialLoadsComplete());
}
NotificationObserver* AutomationProvider::AddNavigationStatusListener(
@@ -330,7 +328,7 @@ const Extension* AutomationProvider::GetExtension(int extension_handle) {
const Extension* AutomationProvider::GetEnabledExtension(int extension_handle) {
const Extension* extension =
extension_tracker_->GetResource(extension_handle);
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
if (extension && service &&
service->GetExtensionById(extension->id(), false))
return extension;
@@ -341,7 +339,7 @@ const Extension* AutomationProvider::GetDisabledExtension(
int extension_handle) {
const Extension* extension =
extension_tracker_->GetResource(extension_handle);
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
if (extension && service &&
service->GetExtensionById(extension->id(), true) &&
!service->GetExtensionById(extension->id(), false))
@@ -355,22 +353,20 @@ void AutomationProvider::OnChannelConnected(int pid) {
// Send a hello message with our current automation protocol version.
chrome::VersionInfo version_info;
- channel_->Send(new AutomationMsg_Hello(0, version_info.Version()));
+ channel_->Send(new AutomationMsg_Hello(version_info.Version()));
if (initial_loads_complete_)
- Send(new AutomationMsg_InitialLoadsComplete(0));
+ Send(new AutomationMsg_InitialLoadsComplete());
}
-void AutomationProvider::OnMessageReceived(const IPC::Message& message) {
+bool AutomationProvider::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
IPC_BEGIN_MESSAGE_MAP(AutomationProvider, message)
#if !defined(OS_MACOSX)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WindowDrag,
WindowSimulateDrag)
#endif // !defined(OS_MACOSX)
-#if defined(OS_WIN)
- IPC_MESSAGE_HANDLER(AutomationMsg_TabHWND, GetTabHWND)
-#endif // defined(OS_WIN)
IPC_MESSAGE_HANDLER(AutomationMsg_HandleUnused, HandleUnused)
- IPC_MESSAGE_HANDLER(AutomationMsg_SetProxyConfig, SetProxyConfig);
+ IPC_MESSAGE_HANDLER(AutomationMsg_SetProxyConfig, SetProxyConfig)
IPC_MESSAGE_HANDLER(AutomationMsg_PrintAsync, PrintAsync)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_Find, HandleFindRequest)
IPC_MESSAGE_HANDLER(AutomationMsg_OverrideEncoding, OverrideEncoding)
@@ -434,8 +430,9 @@ void AutomationProvider::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_LoginWithUserAndPass,
LoginWithUserAndPass)
#endif // defined(OS_CHROMEOS)
- IPC_MESSAGE_UNHANDLED(OnUnhandledMessage())
+ IPC_MESSAGE_UNHANDLED(handled = false;OnUnhandledMessage())
IPC_END_MESSAGE_MAP()
+ return handled;
}
void AutomationProvider::OnUnhandledMessage() {
@@ -790,7 +787,7 @@ RenderViewHost* AutomationProvider::GetViewForTab(int tab_handle) {
void AutomationProvider::InstallExtension(const FilePath& crx_path,
IPC::Message* reply_message) {
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
if (service) {
// The observer will delete itself when done.
new ExtensionInstallNotificationObserver(this,
@@ -810,14 +807,14 @@ void AutomationProvider::InstallExtension(const FilePath& crx_path,
void AutomationProvider::LoadExpandedExtension(
const FilePath& extension_dir,
IPC::Message* reply_message) {
- if (profile_->GetExtensionsService()) {
+ if (profile_->GetExtensionService()) {
// The observer will delete itself when done.
new ExtensionInstallNotificationObserver(
this,
AutomationMsg_LoadExpandedExtension::ID,
reply_message);
- profile_->GetExtensionsService()->LoadExtension(extension_dir);
+ profile_->GetExtensionService()->LoadExtension(extension_dir);
} else {
AutomationMsg_LoadExpandedExtension::WriteReplyParams(
reply_message, AUTOMATION_MSG_EXTENSION_INSTALL_FAILED);
@@ -827,7 +824,7 @@ void AutomationProvider::LoadExpandedExtension(
void AutomationProvider::GetEnabledExtensions(
std::vector<FilePath>* result) {
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
DCHECK(service);
if (service->extensions_enabled()) {
const ExtensionList* extensions = service->extensions();
@@ -856,7 +853,7 @@ void AutomationProvider::WaitForExtensionTestResult(
void AutomationProvider::InstallExtensionAndGetHandle(
const FilePath& crx_path, bool with_ui, IPC::Message* reply_message) {
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
ExtensionProcessManager* manager = profile_->GetExtensionProcessManager();
if (service && manager) {
// The observer will delete itself when done.
@@ -881,7 +878,7 @@ void AutomationProvider::UninstallExtension(int extension_handle,
bool* success) {
*success = false;
const Extension* extension = GetExtension(extension_handle);
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
if (extension && service) {
ExtensionUnloadNotificationObserver observer;
service->UninstallExtension(extension->id(), false);
@@ -894,7 +891,7 @@ void AutomationProvider::UninstallExtension(int extension_handle,
void AutomationProvider::EnableExtension(int extension_handle,
IPC::Message* reply_message) {
const Extension* extension = GetDisabledExtension(extension_handle);
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
ExtensionProcessManager* manager = profile_->GetExtensionProcessManager();
// Only enable if this extension is disabled.
if (extension && service && manager) {
@@ -915,7 +912,7 @@ void AutomationProvider::DisableExtension(int extension_handle,
bool* success) {
*success = false;
const Extension* extension = GetEnabledExtension(extension_handle);
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
if (extension && service) {
ExtensionUnloadNotificationObserver observer;
service->DisableExtension(extension->id());
@@ -930,7 +927,7 @@ void AutomationProvider::ExecuteExtensionActionInActiveTabAsync(
IPC::Message* reply_message) {
bool success = false;
const Extension* extension = GetEnabledExtension(extension_handle);
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
ExtensionMessageService* message_service =
profile_->GetExtensionMessageService();
Browser* browser = browser_tracker_->GetResource(browser_handle);
@@ -955,7 +952,7 @@ void AutomationProvider::MoveExtensionBrowserAction(
int extension_handle, int index, bool* success) {
*success = false;
const Extension* extension = GetEnabledExtension(extension_handle);
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
if (extension && service) {
ExtensionToolbarModel* toolbar = service->toolbar_model();
if (toolbar) {
@@ -976,7 +973,7 @@ void AutomationProvider::GetExtensionProperty(
std::string* value) {
*success = false;
const Extension* extension = GetExtension(extension_handle);
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
if (extension && service) {
ExtensionToolbarModel* toolbar = service->toolbar_model();
int found_index = -1;
diff --git a/chrome/browser/automation/automation_provider.h b/chrome/browser/automation/automation_provider.h
index c30fb97..4eb6f96 100644
--- a/chrome/browser/automation/automation_provider.h
+++ b/chrome/browser/automation/automation_provider.h
@@ -34,13 +34,13 @@
#include "views/event.h"
#endif // defined(OS_WIN)
-struct AutomationMsg_Find_Params;
class PopupMenuWaiter;
class TabContents;
-
-namespace IPC {
+struct AutomationMsg_Find_Params;
struct Reposition_Params;
struct ExternalTabSettings;
+
+namespace IPC {
class ChannelProxy;
}
@@ -148,7 +148,7 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>,
// IPC implementations
virtual bool Send(IPC::Message* msg);
virtual void OnChannelConnected(int pid);
- virtual void OnMessageReceived(const IPC::Message& msg);
+ virtual bool OnMessageReceived(const IPC::Message& msg);
virtual void OnChannelError();
IPC::Message* reply_message_release() {
@@ -238,11 +238,6 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>,
int flags,
bool press_escape_en_route,
IPC::Message* reply_message);
-
-#if defined(OS_WIN)
- // TODO(port): Replace HWND.
- void GetTabHWND(int handle, HWND* tab_hwnd);
-#endif // defined(OS_WIN)
void HandleUnused(const IPC::Message& message, int handle);
void SetFilteredInet(const IPC::Message& message, bool enabled);
void GetFilteredInetHitCount(int* hit_count);
@@ -360,11 +355,11 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>,
bool restore_focus_to_view);
void OnTabReposition(int tab_handle,
- const IPC::Reposition_Params& params);
+ const Reposition_Params& params);
void OnForwardContextMenuCommandToChrome(int tab_handle, int command);
- void CreateExternalTab(const IPC::ExternalTabSettings& settings,
+ void CreateExternalTab(const ExternalTabSettings& settings,
gfx::NativeWindow* tab_container_window,
gfx::NativeWindow* tab_window,
int* tab_handle,
diff --git a/chrome/browser/automation/automation_provider_gtk.cc b/chrome/browser/automation/automation_provider_gtk.cc
index bf6a15c..ca021cd 100644
--- a/chrome/browser/automation/automation_provider_gtk.cc
+++ b/chrome/browser/automation/automation_provider_gtk.cc
@@ -13,6 +13,7 @@
#include "chrome/browser/gtk/browser_window_gtk.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/gtk/view_id_util.h"
+#include "chrome/browser/ui/browser.h"
#include "chrome/common/automation_messages.h"
#include "gfx/point.h"
#include "gfx/rect.h"
diff --git a/chrome/browser/automation/automation_provider_list.cc b/chrome/browser/automation/automation_provider_list.cc
index 6676626..5e3afec 100644
--- a/chrome/browser/automation/automation_provider_list.cc
+++ b/chrome/browser/automation/automation_provider_list.cc
@@ -8,7 +8,6 @@
#include "base/logging.h"
#include "chrome/browser/automation/automation_provider.h"
-#include "chrome/browser/browser_process.h"
AutomationProviderList* AutomationProviderList::instance_ = NULL;
diff --git a/chrome/browser/automation/automation_provider_mac.mm b/chrome/browser/automation/automation_provider_mac.mm
index 451e7f1..f19bec2 100644
--- a/chrome/browser/automation/automation_provider_mac.mm
+++ b/chrome/browser/automation/automation_provider_mac.mm
@@ -11,9 +11,9 @@
#include "base/sys_string_conversions.h"
#include "chrome/browser/automation/automation_browser_tracker.h"
#include "chrome/browser/automation/automation_window_tracker.h"
-#include "chrome/browser/cocoa/tab_window_controller.h"
-#include "chrome/browser/view_ids.h"
-#import "chrome/browser/cocoa/browser_window_controller.h"
+#include "chrome/browser/ui/cocoa/tab_window_controller.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#include "chrome/browser/ui/view_ids.h"
#include "chrome/common/automation_messages.h"
#include "gfx/point.h"
#include "gfx/rect.h"
diff --git a/chrome/browser/automation/automation_provider_observers.cc b/chrome/browser/automation/automation_provider_observers.cc
index 779b6eb..1b6973d 100644
--- a/chrome/browser/automation/automation_provider_observers.cc
+++ b/chrome/browser/automation/automation_provider_observers.cc
@@ -5,6 +5,8 @@
#include "chrome/browser/automation/automation_provider_observers.h"
#include <deque>
+#include <string>
+#include <vector>
#include "base/basictypes.h"
#include "base/callback.h"
@@ -30,22 +32,26 @@
#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extension_updater.h"
#include "chrome/browser/history/top_sites.h"
-#include "chrome/browser/login_prompt.h"
#include "chrome/browser/metrics/metric_event_duration_details.h"
#include "chrome/browser/notifications/balloon.h"
+#include "chrome/browser/notifications/balloon_host.h"
#include "chrome/browser/notifications/balloon_collection.h"
+#include "chrome/browser/notifications/notification.h"
+#include "chrome/browser/notifications/notification_ui_manager.h"
#include "chrome/browser/printing/print_job.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/sessions/tab_restore_service.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/thumbnail_generator.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/translate/page_translated_details.h"
#include "chrome/browser/translate/translate_infobar_delegate.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/login/login_prompt.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/automation_constants.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_service.h"
@@ -158,7 +164,7 @@ void NewTabUILoadObserver::Observe(NotificationType type,
if (type == NotificationType::INITIAL_NEW_TAB_UI_LOAD) {
Details<int> load_time(details);
automation_->Send(
- new AutomationMsg_InitialNewTabUILoadComplete(0, *load_time.ptr()));
+ new AutomationMsg_InitialNewTabUILoadComplete(*load_time.ptr()));
} else {
NOTREACHED();
}
@@ -544,8 +550,6 @@ ExtensionUnloadNotificationObserver::ExtensionUnloadNotificationObserver()
: did_receive_unload_notification_(false) {
registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
NotificationService::AllSources());
- registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED,
- NotificationService::AllSources());
}
ExtensionUnloadNotificationObserver::~ExtensionUnloadNotificationObserver() {
@@ -554,8 +558,7 @@ ExtensionUnloadNotificationObserver::~ExtensionUnloadNotificationObserver() {
void ExtensionUnloadNotificationObserver::Observe(
NotificationType type, const NotificationSource& source,
const NotificationDetails& details) {
- if (type.value == NotificationType::EXTENSION_UNLOADED ||
- type.value == NotificationType::EXTENSION_UNLOADED_DISABLED) {
+ if (type.value == NotificationType::EXTENSION_UNLOADED) {
did_receive_unload_notification_ = true;
} else {
NOTREACHED();
@@ -756,6 +759,7 @@ const struct CommandNotification command_notifications[] = {
// load to finish, and title to change.
{IDC_MANAGE_EXTENSIONS, NotificationType::TAB_CONTENTS_TITLE_UPDATED},
{IDC_OPTIONS, NotificationType::TAB_CONTENTS_TITLE_UPDATED},
+ {IDC_PRINT, NotificationType::TAB_CONTENTS_TITLE_UPDATED},
{IDC_SHOW_DOWNLOADS, NotificationType::TAB_CONTENTS_TITLE_UPDATED},
{IDC_SHOW_HISTORY, NotificationType::TAB_CONTENTS_TITLE_UPDATED},
};
@@ -1166,6 +1170,15 @@ AutomationProviderBookmarkModelObserver::
model_->RemoveObserver(this);
}
+void AutomationProviderBookmarkModelObserver::Loaded(BookmarkModel* model) {
+ ReplyAndDelete(true);
+}
+
+void AutomationProviderBookmarkModelObserver::BookmarkModelBeingDeleted(
+ BookmarkModel* model) {
+ ReplyAndDelete(false);
+}
+
void AutomationProviderBookmarkModelObserver::ReplyAndDelete(bool success) {
AutomationMsg_WaitForBookmarkModelToLoad::WriteReplyParams(
reply_message_, success);
@@ -1457,6 +1470,8 @@ NTPInfoObserver::NTPInfoObserver(
}
}
+NTPInfoObserver::~NTPInfoObserver() {}
+
void NTPInfoObserver::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
@@ -1516,6 +1531,75 @@ void AutocompleteEditFocusedObserver::Observe(
delete this;
}
+namespace {
+
+// Returns whether the notification's host has a non-null process handle.
+bool IsNotificationProcessReady(Balloon* balloon) {
+ return balloon->view() &&
+ balloon->view()->GetHost() &&
+ balloon->view()->GetHost()->render_view_host() &&
+ balloon->view()->GetHost()->render_view_host()->process()->GetHandle();
+}
+
+// Returns whether all active notifications have an associated process ID.
+bool AreActiveNotificationProcessesReady() {
+ NotificationUIManager* manager = g_browser_process->notification_ui_manager();
+ const BalloonCollection::Balloons& balloons =
+ manager->balloon_collection()->GetActiveBalloons();
+ BalloonCollection::Balloons::const_iterator iter;
+ for (iter = balloons.begin(); iter != balloons.end(); ++iter) {
+ if (!IsNotificationProcessReady(*iter))
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+GetActiveNotificationsObserver::GetActiveNotificationsObserver(
+ AutomationProvider* automation,
+ IPC::Message* reply_message)
+ : reply_(automation, reply_message) {
+ if (AreActiveNotificationProcessesReady()) {
+ SendMessage();
+ } else {
+ registrar_.Add(this, NotificationType::RENDERER_PROCESS_CREATED,
+ NotificationService::AllSources());
+ }
+}
+
+void GetActiveNotificationsObserver::Observe(
+ NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (AreActiveNotificationProcessesReady())
+ SendMessage();
+}
+
+void GetActiveNotificationsObserver::SendMessage() {
+ NotificationUIManager* manager =
+ g_browser_process->notification_ui_manager();
+ const BalloonCollection::Balloons& balloons =
+ manager->balloon_collection()->GetActiveBalloons();
+ scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
+ ListValue* list = new ListValue;
+ return_value->Set("notifications", list);
+ BalloonCollection::Balloons::const_iterator iter;
+ for (iter = balloons.begin(); iter != balloons.end(); ++iter) {
+ const Notification& notification = (*iter)->notification();
+ DictionaryValue* balloon = new DictionaryValue;
+ balloon->SetString("content_url", notification.content_url().spec());
+ balloon->SetString("origin_url", notification.origin_url().spec());
+ balloon->SetString("display_source", notification.display_source());
+ BalloonView* view = (*iter)->view();
+ balloon->SetInteger("pid", base::GetProcId(
+ view->GetHost()->render_view_host()->process()->GetHandle()));
+ list->Append(balloon);
+ }
+ reply_.SendSuccess(return_value.get());
+ delete this;
+}
+
OnNotificationBalloonCountObserver::OnNotificationBalloonCountObserver(
AutomationProvider* provider,
IPC::Message* reply_message,
@@ -1535,3 +1619,20 @@ void OnNotificationBalloonCountObserver::OnBalloonCollectionChanged() {
delete this;
}
}
+
+RendererProcessClosedObserver::RendererProcessClosedObserver(
+ AutomationProvider* automation,
+ IPC::Message* reply_message)
+ : automation_(automation),
+ reply_message_(reply_message) {
+ registrar_.Add(this, NotificationType::RENDERER_PROCESS_CLOSED,
+ NotificationService::AllSources());
+}
+
+void RendererProcessClosedObserver::Observe(
+ NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ AutomationJSONReply(automation_, reply_message_).SendSuccess(NULL);
+ delete this;
+}
diff --git a/chrome/browser/automation/automation_provider_observers.h b/chrome/browser/automation/automation_provider_observers.h
index 7287d05..8868863 100644
--- a/chrome/browser/automation/automation_provider_observers.h
+++ b/chrome/browser/automation/automation_provider_observers.h
@@ -648,12 +648,8 @@ class AutomationProviderBookmarkModelObserver : BookmarkModelObserver {
BookmarkModel* model);
virtual ~AutomationProviderBookmarkModelObserver();
- virtual void Loaded(BookmarkModel* model) {
- ReplyAndDelete(true);
- }
- virtual void BookmarkModelBeingDeleted(BookmarkModel* model) {
- ReplyAndDelete(false);
- }
+ virtual void Loaded(BookmarkModel* model);
+ virtual void BookmarkModelBeingDeleted(BookmarkModel* model);
virtual void BookmarkNodeMoved(BookmarkModel* model,
const BookmarkNode* old_parent,
int old_index,
@@ -770,7 +766,7 @@ class AutomationProviderSearchEngineObserver
: provider_(provider),
reply_message_(reply_message) {}
- void OnTemplateURLModelChanged();
+ virtual void OnTemplateURLModelChanged();
private:
AutomationProvider* provider_;
@@ -806,10 +802,10 @@ class AutomationProviderImportSettingsObserver
IPC::Message* reply_message)
: provider_(provider),
reply_message_(reply_message) {}
- void ImportStarted() {}
- void ImportItemStarted(importer::ImportItem item) {}
- void ImportItemEnded(importer::ImportItem item) {}
- void ImportEnded();
+ virtual void ImportStarted() {}
+ virtual void ImportItemStarted(importer::ImportItem item) {}
+ virtual void ImportItemEnded(importer::ImportItem item) {}
+ virtual void ImportEnded();
private:
AutomationProvider* provider_;
IPC::Message* reply_message_;
@@ -825,7 +821,7 @@ class AutomationProviderGetPasswordsObserver
: provider_(provider),
reply_message_(reply_message) {}
- void OnPasswordStoreRequestDone(
+ virtual void OnPasswordStoreRequestDone(
int handle, const std::vector<webkit_glue::PasswordForm*>& result);
private:
@@ -842,7 +838,7 @@ class AutomationProviderBrowsingDataObserver
IPC::Message* reply_message)
: provider_(provider),
reply_message_(reply_message) {}
- void OnBrowsingDataRemoverDone();
+ virtual void OnBrowsingDataRemoverDone();
private:
AutomationProvider* provider_;
@@ -932,6 +928,7 @@ class NTPInfoObserver : public NotificationObserver {
NTPInfoObserver(AutomationProvider* automation,
IPC::Message* reply_message,
CancelableRequestConsumer* consumer);
+ virtual ~NTPInfoObserver();
virtual void Observe(NotificationType type,
const NotificationSource& source,
@@ -973,6 +970,26 @@ class AutocompleteEditFocusedObserver : public NotificationObserver {
DISALLOW_COPY_AND_ASSIGN(AutocompleteEditFocusedObserver);
};
+// Allows the automation provider to wait until all the notification
+// processes are ready.
+class GetActiveNotificationsObserver : public NotificationObserver {
+ public:
+ GetActiveNotificationsObserver(AutomationProvider* automation,
+ IPC::Message* reply_message);
+
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ private:
+ void SendMessage();
+
+ AutomationJSONReply reply_;
+ NotificationRegistrar registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(GetActiveNotificationsObserver);
+};
+
// Allows the automation provider to wait for a given number of
// notification balloons.
class OnNotificationBalloonCountObserver {
@@ -992,5 +1009,24 @@ class OnNotificationBalloonCountObserver {
DISALLOW_COPY_AND_ASSIGN(OnNotificationBalloonCountObserver);
};
+// Allows the automation provider to wait for a RENDERER_PROCESS_CLOSED
+// notification.
+class RendererProcessClosedObserver : public NotificationObserver {
+ public:
+ RendererProcessClosedObserver(AutomationProvider* automation,
+ IPC::Message* reply_message);
+
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ private:
+ NotificationRegistrar registrar_;
+ AutomationProvider* automation_;
+ IPC::Message* reply_message_;
+
+ DISALLOW_COPY_AND_ASSIGN(RendererProcessClosedObserver);
+};
+
#endif // CHROME_BROWSER_AUTOMATION_AUTOMATION_PROVIDER_OBSERVERS_H_
diff --git a/chrome/browser/automation/automation_provider_win.cc b/chrome/browser/automation/automation_provider_win.cc
index 56fe617..0ad5400 100644
--- a/chrome/browser/automation/automation_provider_win.cc
+++ b/chrome/browser/automation/automation_provider_win.cc
@@ -18,7 +18,7 @@
#include "chrome/browser/browser_window.h"
#include "chrome/browser/extensions/extension_event_router.h"
#include "chrome/browser/external_tab_container_win.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/views/bookmark_bar_view.h"
@@ -229,17 +229,8 @@ void AutomationProvider::WindowSimulateDrag(int handle,
}
}
-void AutomationProvider::GetTabHWND(int handle, HWND* tab_hwnd) {
- *tab_hwnd = NULL;
-
- if (tab_tracker_->ContainsHandle(handle)) {
- NavigationController* tab = tab_tracker_->GetResource(handle);
- *tab_hwnd = tab->tab_contents()->GetNativeView();
- }
-}
-
void AutomationProvider::CreateExternalTab(
- const IPC::ExternalTabSettings& settings,
+ const ExternalTabSettings& settings,
gfx::NativeWindow* tab_container_window, gfx::NativeWindow* tab_window,
int* tab_handle, int* session_id) {
TRACE_EVENT_BEGIN("AutomationProvider::CreateExternalTab", 0, "");
@@ -327,7 +318,7 @@ ExternalTabContainer* AutomationProvider::GetExternalTabForHandle(int handle) {
}
void AutomationProvider::OnTabReposition(
- int tab_handle, const IPC::Reposition_Params& params) {
+ int tab_handle, const Reposition_Params& params) {
if (!tab_tracker_->ContainsHandle(tab_handle))
return;
diff --git a/chrome/browser/automation/automation_resource_message_filter.cc b/chrome/browser/automation/automation_resource_message_filter.cc
index 98461d7..5d3ac14 100644
--- a/chrome/browser/automation/automation_resource_message_filter.cc
+++ b/chrome/browser/automation/automation_resource_message_filter.cc
@@ -14,7 +14,7 @@
#include "chrome/browser/net/url_request_mock_util.h"
#include "chrome/browser/net/url_request_slow_download_job.h"
#include "chrome/browser/net/url_request_slow_http_job.h"
-#include "chrome/browser/renderer_host/resource_message_filter.h"
+#include "chrome/browser/renderer_host/render_message_filter.h"
#include "chrome/common/automation_messages.h"
#include "chrome/common/chrome_paths.h"
#include "googleurl/src/gurl.h"
@@ -407,7 +407,7 @@ bool AutomationResourceMessageFilter::SendDownloadRequestToHost(
return false;
}
- return Send(new AutomationMsg_DownloadRequestInHost(0, tab_handle,
+ return Send(new AutomationMsg_DownloadRequestInHost(tab_handle,
automation_request_id));
}
@@ -459,7 +459,7 @@ bool AutomationResourceMessageFilter::GetCookiesForUrl(
if (automation_details_iter->second.filter) {
automation_details_iter->second.filter->Send(
new AutomationMsg_GetCookiesFromHost(
- 0, automation_details_iter->second.tab_handle, url,
+ automation_details_iter->second.tab_handle, url,
completion_callback_id));
}
return true;
@@ -530,7 +530,7 @@ bool AutomationResourceMessageFilter::SetCookiesForUrl(
if (automation_details_iter->second.filter) {
automation_details_iter->second.filter->Send(
new AutomationMsg_SetCookieAsync(
- 0, automation_details_iter->second.tab_handle, url, cookie_line));
+ automation_details_iter->second.tab_handle, url, cookie_line));
}
return true;
diff --git a/chrome/browser/automation/automation_resource_tracker.cc b/chrome/browser/automation/automation_resource_tracker.cc
index 49797c6..82c384a 100644
--- a/chrome/browser/automation/automation_resource_tracker.cc
+++ b/chrome/browser/automation/automation_resource_tracker.cc
@@ -5,7 +5,6 @@
#include "chrome/browser/automation/automation_resource_tracker.h"
#include "chrome/common/automation_messages.h"
-#include "chrome/common/notification_service.h"
AutomationResourceTrackerImpl::AutomationResourceTrackerImpl(
IPC::Message::Sender* sender)
@@ -79,7 +78,7 @@ void AutomationResourceTrackerImpl::HandleCloseNotification(
return;
sender_->Send(
- new AutomationMsg_InvalidateHandle(0, resource_to_handle_[resource]));
+ new AutomationMsg_InvalidateHandle(resource_to_handle_[resource]));
RemoveImpl(resource);
}
diff --git a/chrome/browser/automation/automation_resource_tracker.h b/chrome/browser/automation/automation_resource_tracker.h
index 2d6b0cd..871af66 100644
--- a/chrome/browser/automation/automation_resource_tracker.h
+++ b/chrome/browser/automation/automation_resource_tracker.h
@@ -11,11 +11,10 @@
#include "base/basictypes.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"
#include "ipc/ipc_message.h"
-template <class T> class Source;
-
// Template trick so that AutomationResourceTracker can be used with non-pointer
// types.
template <class T>
@@ -35,6 +34,7 @@ class AutomationResourceTrackerImpl {
explicit AutomationResourceTrackerImpl(IPC::Message::Sender* sender);
virtual ~AutomationResourceTrackerImpl();
+ protected:
// These need to be implemented in AutomationResourceTracker,
// since it needs to call the subclass's type-specific notification
// registration functions.
@@ -50,16 +50,16 @@ class AutomationResourceTrackerImpl {
int GetHandleImpl(const void* resource);
void HandleCloseNotification(const void* resource);
- protected:
+ private:
typedef std::map<const void*, int> ResourceToHandleMap;
typedef std::map<int, const void*> HandleToResourceMap;
+
ResourceToHandleMap resource_to_handle_;
HandleToResourceMap handle_to_resource_;
- private:
- DISALLOW_COPY_AND_ASSIGN(AutomationResourceTrackerImpl);
-
IPC::Message::Sender* sender_;
+
+ DISALLOW_COPY_AND_ASSIGN(AutomationResourceTrackerImpl);
};
// This template defines a superclass for an object that wants to track
@@ -68,15 +68,12 @@ class AutomationResourceTrackerImpl {
// define are AddObserver and RemoveObserver for the given resource's
// close notifications.
template <class T>
-class AutomationResourceTracker : public NotificationObserver,
- private AutomationResourceTrackerImpl {
+class AutomationResourceTracker : public AutomationResourceTrackerImpl,
+ public NotificationObserver {
public:
explicit AutomationResourceTracker(IPC::Message::Sender* automation)
: AutomationResourceTrackerImpl(automation) {}
- virtual ~AutomationResourceTracker() {
- }
-
// The implementations for these should call the NotificationService
// to add and remove this object as an observer for the appropriate
// resource closing notification.
@@ -141,9 +138,6 @@ class AutomationResourceTracker : public NotificationObserver,
HandleCloseNotification(resource);
}
- NotificationRegistrar registrar_;
-
- private:
// These proxy calls from the base Impl class to the template's subclss.
// The casts here allow this to compile with both T = Foo and T = const Foo.
virtual void AddObserverTypeProxy(const void* resource) {
@@ -153,6 +147,9 @@ class AutomationResourceTracker : public NotificationObserver,
RemoveObserver(static_cast<T>(const_cast<void*>(resource)));
}
+ NotificationRegistrar registrar_;
+
+ private:
DISALLOW_COPY_AND_ASSIGN(AutomationResourceTracker);
};
diff --git a/chrome/browser/automation/chrome_frame_automation_provider.cc b/chrome/browser/automation/chrome_frame_automation_provider.cc
index 4de788a..7b699f1 100644
--- a/chrome/browser/automation/chrome_frame_automation_provider.cc
+++ b/chrome/browser/automation/chrome_frame_automation_provider.cc
@@ -3,8 +3,8 @@
// found in the LICENSE file.
#include "chrome/browser/automation/chrome_frame_automation_provider.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/common/automation_messages.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_channel.h"
@@ -12,13 +12,13 @@
ChromeFrameAutomationProvider::ChromeFrameAutomationProvider(Profile* profile)
: AutomationProvider(profile) {}
-void ChromeFrameAutomationProvider::OnMessageReceived(
+bool ChromeFrameAutomationProvider::OnMessageReceived(
const IPC::Message& message) {
- if (IsValidMessage(message.type())) {
- AutomationProvider::OnMessageReceived(message);
- } else {
- OnUnhandledMessage(message);
- }
+ if (IsValidMessage(message.type()))
+ return AutomationProvider::OnMessageReceived(message);
+
+ OnUnhandledMessage(message);
+ return false;
}
void ChromeFrameAutomationProvider::OnUnhandledMessage(
diff --git a/chrome/browser/automation/chrome_frame_automation_provider.h b/chrome/browser/automation/chrome_frame_automation_provider.h
index fad6bd8..f2a67e0 100644
--- a/chrome/browser/automation/chrome_frame_automation_provider.h
+++ b/chrome/browser/automation/chrome_frame_automation_provider.h
@@ -24,7 +24,7 @@ class ChromeFrameAutomationProvider : public AutomationProvider {
explicit ChromeFrameAutomationProvider(Profile* profile);
// IPC::Channel::Listener overrides.
- virtual void OnMessageReceived(const IPC::Message& message);
+ virtual bool OnMessageReceived(const IPC::Message& message);
protected:
// This function is called when we receive an invalid message type.
diff --git a/chrome/browser/automation/extension_port_container.cc b/chrome/browser/automation/extension_port_container.cc
index baf6517..d1fb46f 100644
--- a/chrome/browser/automation/extension_port_container.cc
+++ b/chrome/browser/automation/extension_port_container.cc
@@ -10,13 +10,11 @@
#include "base/values.h"
#include "chrome/browser/automation/automation_provider.h"
#include "chrome/browser/automation/extension_automation_constants.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/extensions/extension_message_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/common/automation_messages.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/render_messages.h"
// TODO(siggi): Find a more structured way to read and write JSON messages.
@@ -42,7 +40,7 @@ bool ExtensionPortContainer::PostResponseToExternalPort(
const std::string& message) {
return automation_->Send(
new AutomationMsg_ForwardMessageToExternalHost(
- 0, tab_handle_, message, ext::kAutomationOrigin,
+ tab_handle_, message, ext::kAutomationOrigin,
ext::kAutomationPortResponseTarget));
}
@@ -50,7 +48,7 @@ bool ExtensionPortContainer::PostMessageToExternalPort(
const std::string& message) {
return automation_->Send(
new AutomationMsg_ForwardMessageToExternalHost(
- 0, tab_handle_, message,
+ tab_handle_, message,
ext::kAutomationOrigin,
ext::kAutomationPortRequestTarget));
}
diff --git a/chrome/browser/automation/testing_automation_provider.cc b/chrome/browser/automation/testing_automation_provider.cc
index ac2622e..103225b 100644
--- a/chrome/browser/automation/testing_automation_provider.cc
+++ b/chrome/browser/automation/testing_automation_provider.cc
@@ -10,13 +10,13 @@
#include "base/json/json_writer.h"
#include "base/json/string_escape.h"
#include "base/path_service.h"
+#include "base/process.h"
+#include "base/process_util.h"
#include "base/stringprintf.h"
#include "base/thread_restrictions.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/app_modal_dialog.h"
-#include "chrome/browser/app_modal_dialog_queue.h"
#include "chrome/browser/autocomplete/autocomplete.h"
#include "chrome/browser/autocomplete/autocomplete_edit.h"
#include "chrome/browser/autocomplete/autocomplete_match.h"
@@ -39,21 +39,18 @@
#include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/download/download_shelf.h"
#include "chrome/browser/extensions/extension_host.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/find_bar.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/instant/instant_controller.h"
#include "chrome/browser/history/top_sites.h"
-#include "chrome/browser/location_bar.h"
-#include "chrome/browser/login_prompt.h"
-#include "chrome/browser/native_app_modal_dialog.h"
+#include "chrome/browser/importer/importer.h"
#include "chrome/browser/notifications/balloon.h"
#include "chrome/browser/notifications/balloon_collection.h"
-#include "chrome/browser/notifications/balloon_host.h"
#include "chrome/browser/notifications/notification.h"
#include "chrome/browser/notifications/notification_ui_manager.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/search_engines/keyword_editor_controller.h"
@@ -61,8 +58,14 @@
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/browser/tab_contents/interstitial_page.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/translate/translate_infobar_delegate.h"
+#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
+#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h"
+#include "chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h"
+#include "chrome/browser/ui/find_bar/find_bar.h"
+#include "chrome/browser/ui/login/login_prompt.h"
+#include "chrome/browser/ui/omnibox/location_bar.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
@@ -73,140 +76,55 @@
#include "net/base/cookie_store.h"
#include "net/url_request/url_request_context.h"
#include "views/event.h"
-#include "webkit/glue/plugins/plugin_list.h"
+#include "webkit/plugins/npapi/plugin_list.h"
namespace {
-class GetCookiesTask : public Task {
- public:
- GetCookiesTask(const GURL& url,
- URLRequestContextGetter* context_getter,
- base::WaitableEvent* event,
- std::string* cookies)
- : url_(url),
- context_getter_(context_getter),
- event_(event),
- cookies_(cookies) {}
-
- virtual void Run() {
- *cookies_ = context_getter_->GetCookieStore()->GetCookies(url_);
- event_->Signal();
- }
-
- private:
- const GURL& url_;
- URLRequestContextGetter* const context_getter_;
- base::WaitableEvent* const event_;
- std::string* const cookies_;
-
- DISALLOW_COPY_AND_ASSIGN(GetCookiesTask);
-};
-
-std::string GetCookiesForURL(
+void GetCookiesOnIOThread(
const GURL& url,
- URLRequestContextGetter* context_getter) {
- std::string cookies;
- base::WaitableEvent event(true /* manual reset */,
- false /* not initially signaled */);
- CHECK(BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- new GetCookiesTask(url, context_getter, &event, &cookies)));
- event.Wait();
- return cookies;
+ const scoped_refptr<URLRequestContextGetter>& context_getter,
+ base::WaitableEvent* event,
+ std::string* cookies) {
+ *cookies = context_getter->GetCookieStore()->GetCookies(url);
+ event->Signal();
}
-class SetCookieTask : public Task {
- public:
- SetCookieTask(const GURL& url,
- const std::string& value,
- URLRequestContextGetter* context_getter,
- base::WaitableEvent* event,
- bool* rv)
- : url_(url),
- value_(value),
- context_getter_(context_getter),
- event_(event),
- rv_(rv) {}
-
- virtual void Run() {
- *rv_ = context_getter_->GetCookieStore()->SetCookie(url_, value_);
- event_->Signal();
- }
-
- private:
- const GURL& url_;
- const std::string& value_;
- URLRequestContextGetter* const context_getter_;
- base::WaitableEvent* const event_;
- bool* const rv_;
-
- DISALLOW_COPY_AND_ASSIGN(SetCookieTask);
-};
-
-bool SetCookieForURL(
+void SetCookieOnIOThread(
const GURL& url,
const std::string& value,
- URLRequestContextGetter* context_getter) {
- base::WaitableEvent event(true /* manual reset */,
- false /* not initially signaled */);
- bool rv = false;
- CHECK(BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- new SetCookieTask(url, value, context_getter, &event, &rv)));
- event.Wait();
- return rv;
+ const scoped_refptr<URLRequestContextGetter>& context_getter,
+ base::WaitableEvent* event,
+ bool* success) {
+ *success = context_getter->GetCookieStore()->SetCookie(url, value);
+ event->Signal();
}
-class DeleteCookieTask : public Task {
- public:
- DeleteCookieTask(const GURL& url,
- const std::string& name,
- const scoped_refptr<URLRequestContextGetter>& context_getter)
- : url_(url),
- name_(name),
- context_getter_(context_getter) {}
-
- virtual void Run() {
- net::CookieStore* cookie_store = context_getter_->GetCookieStore();
- cookie_store->DeleteCookie(url_, name_);
- }
-
- private:
- const GURL url_;
- const std::string name_;
- const scoped_refptr<URLRequestContextGetter> context_getter_;
-
- DISALLOW_COPY_AND_ASSIGN(DeleteCookieTask);
-};
-
-class ClickTask : public Task {
- public:
- explicit ClickTask(int flags) : flags_(flags) {}
- virtual ~ClickTask() {}
-
- virtual void Run() {
- ui_controls::MouseButton button = ui_controls::LEFT;
- if ((flags_ & views::Event::EF_LEFT_BUTTON_DOWN) ==
- views::Event::EF_LEFT_BUTTON_DOWN) {
- button = ui_controls::LEFT;
- } else if ((flags_ & views::Event::EF_RIGHT_BUTTON_DOWN) ==
- views::Event::EF_RIGHT_BUTTON_DOWN) {
- button = ui_controls::RIGHT;
- } else if ((flags_ & views::Event::EF_MIDDLE_BUTTON_DOWN) ==
- views::Event::EF_MIDDLE_BUTTON_DOWN) {
- button = ui_controls::MIDDLE;
- } else {
- NOTREACHED();
- }
-
- ui_controls::SendMouseClick(button);
+void DeleteCookieOnIOThread(
+ const GURL& url,
+ const std::string& name,
+ const scoped_refptr<URLRequestContextGetter>& context_getter,
+ base::WaitableEvent* event) {
+ context_getter->GetCookieStore()->DeleteCookie(url, name);
+ event->Signal();
+}
+
+void SendMouseClick(int flags) {
+ ui_controls::MouseButton button = ui_controls::LEFT;
+ if ((flags & views::Event::EF_LEFT_BUTTON_DOWN) ==
+ views::Event::EF_LEFT_BUTTON_DOWN) {
+ button = ui_controls::LEFT;
+ } else if ((flags & views::Event::EF_RIGHT_BUTTON_DOWN) ==
+ views::Event::EF_RIGHT_BUTTON_DOWN) {
+ button = ui_controls::RIGHT;
+ } else if ((flags & views::Event::EF_MIDDLE_BUTTON_DOWN) ==
+ views::Event::EF_MIDDLE_BUTTON_DOWN) {
+ button = ui_controls::MIDDLE;
+ } else {
+ NOTREACHED();
}
- private:
- int flags_;
-
- DISALLOW_COPY_AND_ASSIGN(ClickTask);
-};
+ ui_controls::SendMouseClick(button);
+}
class AutomationInterstitialPage : public InterstitialPage {
public:
@@ -220,7 +138,7 @@ class AutomationInterstitialPage : public InterstitialPage {
virtual std::string GetHTMLContents() { return contents_; }
private:
- std::string contents_;
+ const std::string contents_;
DISALLOW_COPY_AND_ASSIGN(AutomationInterstitialPage);
};
@@ -242,8 +160,52 @@ TestingAutomationProvider::~TestingAutomationProvider() {
BrowserList::RemoveObserver(this);
}
-void TestingAutomationProvider::OnMessageReceived(
+void TestingAutomationProvider::SourceProfilesLoaded() {
+ DCHECK_NE(static_cast<ImporterHost*>(NULL), importer_host_.get());
+
+ // Get the correct ProfileInfo based on the browser the user provided.
+ importer::ProfileInfo profile_info;
+ int num_browsers = importer_host_->GetAvailableProfileCount();
+ int i = 0;
+ for ( ; i < num_browsers; i++) {
+ string16 name = WideToUTF16Hack(importer_host_->GetSourceProfileNameAt(i));
+ if (name == import_settings_data_.browser_name) {
+ profile_info = importer_host_->GetSourceProfileInfoAt(i);
+ break;
+ }
+ }
+ // If we made it to the end of the loop, then the input was bad.
+ if (i == num_browsers) {
+ AutomationJSONReply(this, import_settings_data_.reply_message).SendError(
+ "Invalid browser name string found.");
+ return;
+ }
+
+ importer_host_->SetObserver(
+ new AutomationProviderImportSettingsObserver(
+ this, import_settings_data_.reply_message));
+
+ Profile* profile = import_settings_data_.browser->profile();
+ importer_host_->StartImportSettings(profile_info,
+ profile,
+ import_settings_data_.import_items,
+ new ProfileWriter(profile),
+ import_settings_data_.first_run);
+}
+
+void TestingAutomationProvider::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK(type == NotificationType::SESSION_END);
+ // OnBrowserRemoved does a ReleaseLater. When session end is received we exit
+ // before the task runs resulting in this object not being deleted. This
+ // Release balance out the Release scheduled by OnBrowserRemoved.
+ Release();
+}
+
+bool TestingAutomationProvider::OnMessageReceived(
const IPC::Message& message) {
+ bool handled = true;
IPC_BEGIN_MESSAGE_MAP(TestingAutomationProvider, message)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_CloseBrowser, CloseBrowser)
IPC_MESSAGE_HANDLER(AutomationMsg_CloseBrowserRequestAsync,
@@ -257,15 +219,12 @@ void TestingAutomationProvider::OnMessageReceived(
IPC_MESSAGE_HANDLER(AutomationMsg_DeleteCookie, DeleteCookie)
IPC_MESSAGE_HANDLER(AutomationMsg_ShowCollectedCookiesDialog,
ShowCollectedCookiesDialog)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_NavigateToURL, NavigateToURL)
IPC_MESSAGE_HANDLER_DELAY_REPLY(
AutomationMsg_NavigateToURLBlockUntilNavigationsComplete,
NavigateToURLBlockUntilNavigationsComplete)
IPC_MESSAGE_HANDLER(AutomationMsg_NavigationAsync, NavigationAsync)
IPC_MESSAGE_HANDLER(AutomationMsg_NavigationAsyncWithDisposition,
NavigationAsyncWithDisposition)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_GoBack, GoBack)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_GoForward, GoForward)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_Reload, Reload)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_SetAuth, SetAuth)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_CancelAuth, CancelAuth)
@@ -320,7 +279,6 @@ void TestingAutomationProvider::OnMessageReceived(
AutocompleteEditGetMatches)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForAutocompleteEditFocus,
WaitForAutocompleteEditFocus)
- IPC_MESSAGE_HANDLER(AutomationMsg_ApplyAccelerator, ApplyAccelerator)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_DomOperation,
ExecuteJavascript)
IPC_MESSAGE_HANDLER(AutomationMsg_ConstrainedWindowCount,
@@ -337,8 +295,6 @@ void TestingAutomationProvider::OnMessageReceived(
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_InspectElement,
HandleInspectElementRequest)
IPC_MESSAGE_HANDLER(AutomationMsg_DownloadDirectory, GetDownloadDirectory)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_OpenNewBrowserWindow,
- OpenNewBrowserWindow)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_OpenNewBrowserWindowOfType,
OpenNewBrowserWindowOfType)
IPC_MESSAGE_HANDLER(AutomationMsg_WindowForBrowser, GetWindowForBrowser)
@@ -434,8 +390,10 @@ void TestingAutomationProvider::OnMessageReceived(
IPC_MESSAGE_HANDLER(AutomationMsg_LoadBlockedPlugins, LoadBlockedPlugins)
IPC_MESSAGE_HANDLER(AutomationMsg_ResetToDefaultTheme, ResetToDefaultTheme)
- IPC_MESSAGE_UNHANDLED(AutomationProvider::OnMessageReceived(message));
+ IPC_MESSAGE_UNHANDLED(
+ handled = AutomationProvider::OnMessageReceived(message))
IPC_END_MESSAGE_MAP()
+ return handled;
}
void TestingAutomationProvider::OnChannelError() {
@@ -446,23 +404,20 @@ void TestingAutomationProvider::OnChannelError() {
void TestingAutomationProvider::CloseBrowser(int browser_handle,
IPC::Message* reply_message) {
- if (browser_tracker_->ContainsHandle(browser_handle)) {
- Browser* browser = browser_tracker_->GetResource(browser_handle);
- new BrowserClosedNotificationObserver(browser, this,
- reply_message);
- browser->window()->Close();
- } else {
- NOTREACHED();
- }
+ if (!browser_tracker_->ContainsHandle(browser_handle))
+ return;
+
+ Browser* browser = browser_tracker_->GetResource(browser_handle);
+ new BrowserClosedNotificationObserver(browser, this, reply_message);
+ browser->window()->Close();
}
void TestingAutomationProvider::CloseBrowserAsync(int browser_handle) {
- if (browser_tracker_->ContainsHandle(browser_handle)) {
- Browser* browser = browser_tracker_->GetResource(browser_handle);
- browser->window()->Close();
- } else {
- NOTREACHED();
- }
+ if (!browser_tracker_->ContainsHandle(browser_handle))
+ return;
+
+ Browser* browser = browser_tracker_->GetResource(browser_handle);
+ browser->window()->Close();
}
void TestingAutomationProvider::ActivateTab(int handle,
@@ -478,7 +433,8 @@ void TestingAutomationProvider::ActivateTab(int handle,
}
}
-void TestingAutomationProvider::AppendTab(int handle, const GURL& url,
+void TestingAutomationProvider::AppendTab(int handle,
+ const GURL& url,
IPC::Message* reply_message) {
int append_tab_response = -1; // -1 is the error code
NotificationObserver* observer = NULL;
@@ -538,10 +494,18 @@ void TestingAutomationProvider::GetCookies(const GURL& url, int handle,
std::string* value) {
*value_size = -1;
if (url.is_valid() && tab_tracker_->ContainsHandle(handle)) {
- NavigationController* tab = tab_tracker_->GetResource(handle);
-
// Since we are running on the UI thread don't call GetURLRequestContext().
- *value = GetCookiesForURL(url, tab->profile()->GetRequestContext());
+ scoped_refptr<URLRequestContextGetter> context_getter =
+ tab_tracker_->GetResource(handle)->profile()->GetRequestContext();
+
+ base::WaitableEvent event(true /* manual reset */,
+ false /* not initially signaled */);
+ CHECK(BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableFunction(&GetCookiesOnIOThread,
+ url, context_getter, &event, value)));
+ event.Wait();
+
*value_size = static_cast<int>(value->size());
}
}
@@ -553,9 +517,20 @@ void TestingAutomationProvider::SetCookie(const GURL& url,
*response_value = -1;
if (url.is_valid() && tab_tracker_->ContainsHandle(handle)) {
- NavigationController* tab = tab_tracker_->GetResource(handle);
-
- if (SetCookieForURL(url, value, tab->profile()->GetRequestContext()))
+ // Since we are running on the UI thread don't call GetURLRequestContext().
+ scoped_refptr<URLRequestContextGetter> context_getter =
+ tab_tracker_->GetResource(handle)->profile()->GetRequestContext();
+
+ base::WaitableEvent event(true /* manual reset */,
+ false /* not initially signaled */);
+ bool success = false;
+ CHECK(BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableFunction(&SetCookieOnIOThread,
+ url, value, context_getter, &event,
+ &success)));
+ event.Wait();
+ if (success)
*response_value = 1;
}
}
@@ -565,12 +540,17 @@ void TestingAutomationProvider::DeleteCookie(const GURL& url,
int handle, bool* success) {
*success = false;
if (url.is_valid() && tab_tracker_->ContainsHandle(handle)) {
- NavigationController* tab = tab_tracker_->GetResource(handle);
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- new DeleteCookieTask(
- url, cookie_name,
- make_scoped_refptr(tab->profile()->GetRequestContext())));
+ // Since we are running on the UI thread don't call GetURLRequestContext().
+ scoped_refptr<URLRequestContextGetter> context_getter =
+ tab_tracker_->GetResource(handle)->profile()->GetRequestContext();
+
+ base::WaitableEvent event(true /* manual reset */,
+ false /* not initially signaled */);
+ CHECK(BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableFunction(&DeleteCookieOnIOThread,
+ url, cookie_name, context_getter, &event)));
+ event.Wait();
*success = true;
}
}
@@ -586,12 +566,6 @@ void TestingAutomationProvider::ShowCollectedCookiesDialog(
}
}
-void TestingAutomationProvider::NavigateToURL(int handle,
- const GURL& url,
- IPC::Message* reply_message) {
- NavigateToURLBlockUntilNavigationsComplete(handle, url, 1, reply_message);
-}
-
void TestingAutomationProvider::NavigateToURLBlockUntilNavigationsComplete(
int handle, const GURL& url, int number_of_navigations,
IPC::Message* reply_message) {
@@ -606,13 +580,13 @@ void TestingAutomationProvider::NavigateToURLBlockUntilNavigationsComplete(
AddNavigationStatusListener(tab, reply_message, number_of_navigations,
false);
- // TODO(darin): avoid conversion to GURL
+ // TODO(darin): avoid conversion to GURL.
browser->OpenURL(url, GURL(), CURRENT_TAB, PageTransition::TYPED);
return;
}
}
- AutomationMsg_NavigateToURL::WriteReplyParams(
+ AutomationMsg_NavigateToURLBlockUntilNavigationsComplete::WriteReplyParams(
reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
Send(reply_message);
}
@@ -646,40 +620,6 @@ void TestingAutomationProvider::NavigationAsyncWithDisposition(
}
}
-void TestingAutomationProvider::GoBack(int handle,
- IPC::Message* reply_message) {
- if (tab_tracker_->ContainsHandle(handle)) {
- NavigationController* tab = tab_tracker_->GetResource(handle);
- Browser* browser = FindAndActivateTab(tab);
- if (browser && browser->command_updater()->IsCommandEnabled(IDC_BACK)) {
- AddNavigationStatusListener(tab, reply_message, 1, false);
- browser->GoBack(CURRENT_TAB);
- return;
- }
- }
-
- AutomationMsg_GoBack::WriteReplyParams(
- reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
- Send(reply_message);
-}
-
-void TestingAutomationProvider::GoForward(int handle,
- IPC::Message* reply_message) {
- if (tab_tracker_->ContainsHandle(handle)) {
- NavigationController* tab = tab_tracker_->GetResource(handle);
- Browser* browser = FindAndActivateTab(tab);
- if (browser && browser->command_updater()->IsCommandEnabled(IDC_FORWARD)) {
- AddNavigationStatusListener(tab, reply_message, 1, false);
- browser->GoForward(CURRENT_TAB);
- return;
- }
- }
-
- AutomationMsg_GoForward::WriteReplyParams(
- reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
- Send(reply_message);
-}
-
void TestingAutomationProvider::Reload(int handle,
IPC::Message* reply_message) {
if (tab_tracker_->ContainsHandle(handle)) {
@@ -758,8 +698,9 @@ void TestingAutomationProvider::NeedsAuth(int tab_handle, bool* needs_auth) {
void TestingAutomationProvider::GetRedirectsFrom(int tab_handle,
const GURL& source_url,
IPC::Message* reply_message) {
- DCHECK(!redirect_query_) << "Can only handle one redirect query at once.";
- if (tab_tracker_->ContainsHandle(tab_handle)) {
+ if (redirect_query_) {
+ LOG(ERROR) << "Can only handle one redirect query at once.";
+ } else if (tab_tracker_->ContainsHandle(tab_handle)) {
NavigationController* tab = tab_tracker_->GetResource(tab_handle);
HistoryService* history_service =
tab->profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
@@ -883,7 +824,6 @@ void TestingAutomationProvider::ExecuteBrowserCommand(
}
void TestingAutomationProvider::GetBrowserLocale(string16* locale) {
- DCHECK(g_browser_process);
*locale = ASCIIToUTF16(g_browser_process->GetApplicationLocale());
}
@@ -905,8 +845,9 @@ void TestingAutomationProvider::WindowSimulateClick(const IPC::Message& message,
const gfx::Point& click,
int flags) {
if (window_tracker_->ContainsHandle(handle)) {
- ui_controls::SendMouseMoveNotifyWhenDone(click.x(), click.y(),
- new ClickTask(flags));
+ // TODO(phajdan.jr): This is flaky. We should wait for the final click.
+ ui_controls::SendMouseMoveNotifyWhenDone(
+ click.x(), click.y(), NewRunnableFunction(&SendMouseClick, flags));
}
}
@@ -929,14 +870,14 @@ void TestingAutomationProvider::WindowSimulateKeyPress(
gfx::NativeWindow window = window_tracker_->GetResource(handle);
// The key event is sent to whatever window is active.
ui_controls::SendKeyPress(window, static_cast<app::KeyboardCode>(key),
- ((flags & views::Event::EF_CONTROL_DOWN) ==
- views::Event::EF_CONTROL_DOWN),
+ ((flags & views::Event::EF_CONTROL_DOWN) ==
+ views::Event::EF_CONTROL_DOWN),
((flags & views::Event::EF_SHIFT_DOWN) ==
- views::Event::EF_SHIFT_DOWN),
+ views::Event::EF_SHIFT_DOWN),
((flags & views::Event::EF_ALT_DOWN) ==
- views::Event::EF_ALT_DOWN),
+ views::Event::EF_ALT_DOWN),
((flags & views::Event::EF_COMMAND_DOWN) ==
- views::Event::EF_COMMAND_DOWN));
+ views::Event::EF_COMMAND_DOWN));
}
void TestingAutomationProvider::GetTabCount(int handle, int* tab_count) {
@@ -1164,53 +1105,44 @@ void TestingAutomationProvider::AutocompleteEditIsQueryInProgress(
}
}
-void TestingAutomationProvider::ApplyAccelerator(int handle, int id) {
- LOG(ERROR) << "ApplyAccelerator has been deprecated. "
- << "Please use ExecuteBrowserCommandAsync instead.";
-}
-
void TestingAutomationProvider::ExecuteJavascript(
int handle,
const std::wstring& frame_xpath,
const std::wstring& script,
IPC::Message* reply_message) {
- bool succeeded = false;
TabContents* tab_contents = GetTabContentsForHandle(handle, NULL);
- if (tab_contents) {
- // Set the routing id of this message with the controller.
- // This routing id needs to be remembered for the reverse
- // communication while sending back the response of
- // this javascript execution.
- std::wstring set_automation_id;
- base::SStringPrintf(&set_automation_id,
- L"window.domAutomationController.setAutomationId(%d);",
- reply_message->routing_id());
-
- DCHECK(reply_message_ == NULL);
- reply_message_ = reply_message;
-
- tab_contents->render_view_host()->ExecuteJavascriptInWebFrame(
- frame_xpath, set_automation_id);
- tab_contents->render_view_host()->ExecuteJavascriptInWebFrame(
- frame_xpath, script);
- succeeded = true;
- }
-
- if (!succeeded) {
+ if (!tab_contents) {
AutomationMsg_DomOperation::WriteReplyParams(reply_message, std::string());
Send(reply_message);
+ return;
}
+
+ // Set the routing id of this message with the controller.
+ // This routing id needs to be remembered for the reverse
+ // communication while sending back the response of
+ // this javascript execution.
+ std::wstring set_automation_id;
+ base::SStringPrintf(&set_automation_id,
+ L"window.domAutomationController.setAutomationId(%d);",
+ reply_message->routing_id());
+
+ DCHECK(reply_message_ == NULL);
+ reply_message_ = reply_message;
+
+ tab_contents->render_view_host()->ExecuteJavascriptInWebFrame(
+ frame_xpath, set_automation_id);
+ tab_contents->render_view_host()->ExecuteJavascriptInWebFrame(
+ frame_xpath, script);
}
void TestingAutomationProvider::GetConstrainedWindowCount(int handle,
int* count) {
*count = -1; // -1 is the error code
if (tab_tracker_->ContainsHandle(handle)) {
- NavigationController* nav_controller = tab_tracker_->GetResource(handle);
- TabContents* tab_contents = nav_controller->tab_contents();
- if (tab_contents) {
- *count = static_cast<int>(tab_contents->child_windows_.size());
- }
+ NavigationController* nav_controller = tab_tracker_->GetResource(handle);
+ TabContents* tab_contents = nav_controller->tab_contents();
+ if (tab_contents)
+ *count = static_cast<int>(tab_contents->child_windows_.size());
}
}
@@ -1238,12 +1170,6 @@ void TestingAutomationProvider::GetDownloadDirectory(
}
}
-void TestingAutomationProvider::OpenNewBrowserWindow(
- bool show, IPC::Message* reply_message) {
- OpenNewBrowserWindowOfType(static_cast<int>(Browser::TYPE_NORMAL), show,
- reply_message);
-}
-
void TestingAutomationProvider::OpenNewBrowserWindowOfType(
int type, bool show, IPC::Message* reply_message) {
new BrowserOpenedNotificationObserver(this, reply_message);
@@ -1415,24 +1341,22 @@ void TestingAutomationProvider::ActionOnSSLBlockingPage(
void TestingAutomationProvider::BringBrowserToFront(int browser_handle,
bool* success) {
+ *success = false;
if (browser_tracker_->ContainsHandle(browser_handle)) {
Browser* browser = browser_tracker_->GetResource(browser_handle);
browser->window()->Activate();
*success = true;
- } else {
- *success = false;
}
}
void TestingAutomationProvider::IsMenuCommandEnabled(int browser_handle,
int message_num,
bool* menu_item_enabled) {
+ *menu_item_enabled = false;
if (browser_tracker_->ContainsHandle(browser_handle)) {
Browser* browser = browser_tracker_->GetResource(browser_handle);
*menu_item_enabled =
browser->command_updater()->IsCommandEnabled(message_num);
- } else {
- *menu_item_enabled = false;
}
}
@@ -1456,6 +1380,14 @@ void TestingAutomationProvider::SavePage(int tab_handle,
const FilePath& dir_path,
int type,
bool* success) {
+ SavePackage::SavePackageType save_type =
+ static_cast<SavePackage::SavePackageType>(type);
+ if (save_type < SavePackage::SAVE_AS_ONLY_HTML ||
+ save_type > SavePackage::SAVE_AS_COMPLETE_HTML) {
+ *success = false;
+ return;
+ }
+
if (!tab_tracker_->ContainsHandle(tab_handle)) {
*success = false;
return;
@@ -1463,18 +1395,12 @@ void TestingAutomationProvider::SavePage(int tab_handle,
NavigationController* nav = tab_tracker_->GetResource(tab_handle);
Browser* browser = FindAndActivateTab(nav);
- DCHECK(browser);
if (!browser->command_updater()->IsCommandEnabled(IDC_SAVE_PAGE)) {
*success = false;
return;
}
- SavePackage::SavePackageType save_type =
- static_cast<SavePackage::SavePackageType>(type);
- DCHECK(save_type >= SavePackage::SAVE_AS_ONLY_HTML &&
- save_type <= SavePackage::SAVE_AS_COMPLETE_HTML);
nav->tab_contents()->SavePage(file_name, dir_path, save_type);
-
*success = true;
}
@@ -1851,7 +1777,7 @@ void TestingAutomationProvider::SetBooleanPreference(int handle,
void TestingAutomationProvider::GetShowingAppModalDialog(bool* showing_dialog,
int* dialog_button) {
AppModalDialog* active_dialog =
- Singleton<AppModalDialogQueue>()->active_dialog();
+ AppModalDialogQueue::GetInstance()->active_dialog();
if (!active_dialog) {
*showing_dialog = false;
*dialog_button = MessageBoxFlags::DIALOGBUTTON_NONE;
@@ -1870,7 +1796,7 @@ void TestingAutomationProvider::ClickAppModalDialogButton(int button,
*success = false;
NativeAppModalDialog* native_dialog =
- Singleton<AppModalDialogQueue>()->active_dialog()->native_dialog();
+ AppModalDialogQueue::GetInstance()->active_dialog()->native_dialog();
if (native_dialog &&
(native_dialog->GetAppModalDialogButtons() & button) == button) {
if ((button & MessageBoxFlags::DIALOGBUTTON_OK) ==
@@ -1902,7 +1828,7 @@ void TestingAutomationProvider::WaitForBrowserWindowCountToBecome(
void TestingAutomationProvider::WaitForAppModalDialogToBeShown(
IPC::Message* reply_message) {
- if (Singleton<AppModalDialogQueue>()->HasActiveDialog()) {
+ if (AppModalDialogQueue::GetInstance()->HasActiveDialog()) {
AutomationMsg_WaitForAppModalDialogToBeShown::WriteReplyParams(
reply_message, true);
Send(reply_message);
@@ -2062,6 +1988,8 @@ void TestingAutomationProvider::SendJSONRequest(int handle,
handler_map["OmniboxMovePopupSelection"] =
&TestingAutomationProvider::OmniboxMovePopupSelection;
+ handler_map["GetInstantInfo"] = &TestingAutomationProvider::GetInstantInfo;
+
handler_map["LoadSearchEngineInfo"] =
&TestingAutomationProvider::LoadSearchEngineInfo;
handler_map["GetSearchEngineInfo"] =
@@ -2154,6 +2082,9 @@ void TestingAutomationProvider::SendJSONRequest(int handle,
handler_map["RestoreAllNTPMostVisitedThumbnails"] =
&TestingAutomationProvider::RestoreAllNTPMostVisitedThumbnails;
+ handler_map["KillRendererProcess"] =
+ &TestingAutomationProvider::KillRendererProcess;
+
if (handler_map.find(std::string(command)) != handler_map.end()) {
(this->*handler_map[command])(browser, dict_value, reply_message);
} else {
@@ -2354,11 +2285,11 @@ void TestingAutomationProvider::GetBrowserInfo(
DictionaryValue* properties = new DictionaryValue;
properties->SetString("ChromeVersion", chrome::kChromeVersion);
properties->SetString("BrowserProcessExecutableName",
- WideToUTF16Hack(chrome::kBrowserProcessExecutableName));
+ chrome::kBrowserProcessExecutableName);
properties->SetString("HelperProcessExecutableName",
- WideToUTF16Hack(chrome::kHelperProcessExecutableName));
+ chrome::kHelperProcessExecutableName);
properties->SetString("BrowserProcessExecutablePath",
- WideToUTF16Hack(chrome::kBrowserProcessExecutablePath));
+ chrome::kBrowserProcessExecutablePath);
properties->SetString("HelperProcessExecutablePath",
chrome::kHelperProcessExecutablePath);
properties->SetString("command_line_string",
@@ -2615,17 +2546,17 @@ void TestingAutomationProvider::WaitForDownloadsToComplete(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
- AutomationJSONReply reply(this, reply_message);
// Look for a quick return.
if (!profile_->HasCreatedDownloadManager()) {
- reply.SendSuccess(NULL); // No download manager.
+ // No download manager.
+ AutomationJSONReply(this, reply_message).SendSuccess(NULL);
return;
}
std::vector<DownloadItem*> downloads;
profile_->GetDownloadManager()->GetCurrentDownloads(FilePath(), &downloads);
if (downloads.empty()) {
- reply.SendSuccess(NULL);
+ AutomationJSONReply(this, reply_message).SendSuccess(NULL);
return;
}
@@ -2989,6 +2920,32 @@ void TestingAutomationProvider::OmniboxAcceptInput(
browser->window()->GetLocationBar()->AcceptInput();
}
+// Sample json input: { "command": "GetInstantInfo" }
+void TestingAutomationProvider::GetInstantInfo(Browser* browser,
+ DictionaryValue* args,
+ IPC::Message* reply_message) {
+ DictionaryValue* info = new DictionaryValue;
+ if (browser->instant()) {
+ InstantController* instant = browser->instant();
+ info->SetBoolean("enabled", true);
+ info->SetBoolean("showing", instant->IsShowingInstant());
+ info->SetBoolean("active", instant->is_active());
+ info->SetBoolean("current", instant->IsCurrent());
+ if (instant->GetPreviewContents() &&
+ instant->GetPreviewContents()->tab_contents()) {
+ TabContents* contents = instant->GetPreviewContents()->tab_contents();
+ info->SetBoolean("loading", contents->is_loading());
+ info->SetString("location", contents->GetURL().spec());
+ info->SetString("title", contents->GetTitle());
+ }
+ } else {
+ info->SetBoolean("enabled", false);
+ }
+ scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
+ return_value->Set("instant", info);
+ AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
+}
+
// Sample json input: { "command": "GetInitialLoadTimes" }
// Refer to InitialLoadObserver::GetTimingInformation() for sample output.
void TestingAutomationProvider::GetInitialLoadTimes(
@@ -3011,10 +2968,11 @@ void TestingAutomationProvider::GetPluginsInfo(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
- std::vector<WebPluginInfo> plugins;
- NPAPI::PluginList::Singleton()->GetPlugins(false, &plugins);
+ std::vector<webkit::npapi::WebPluginInfo> plugins;
+ webkit::npapi::PluginList::Singleton()->GetPlugins(false, &plugins);
ListValue* items = new ListValue;
- for (std::vector<WebPluginInfo>::const_iterator it = plugins.begin();
+ for (std::vector<webkit::npapi::WebPluginInfo>::const_iterator it =
+ plugins.begin();
it != plugins.end();
++it) {
DictionaryValue* item = new DictionaryValue;
@@ -3025,7 +2983,7 @@ void TestingAutomationProvider::GetPluginsInfo(
item->SetBoolean("enabled", it->enabled);
// Add info about mime types.
ListValue* mime_types = new ListValue();
- for (std::vector<WebPluginMimeType>::const_iterator type_it =
+ for (std::vector<webkit::npapi::WebPluginMimeType>::const_iterator type_it =
it->mime_types.begin();
type_it != it->mime_types.end();
++type_it) {
@@ -3064,7 +3022,8 @@ void TestingAutomationProvider::EnablePlugin(Browser* browser,
if (!args->GetString("path", &path)) {
reply.SendError("path not specified.");
return;
- } else if (!NPAPI::PluginList::Singleton()->EnablePlugin(FilePath(path))) {
+ } else if (!webkit::npapi::PluginList::Singleton()->EnablePlugin(
+ FilePath(path))) {
reply.SendError(StringPrintf("Could not enable plugin for path %s.",
path.c_str()));
return;
@@ -3083,7 +3042,8 @@ void TestingAutomationProvider::DisablePlugin(Browser* browser,
if (!args->GetString("path", &path)) {
reply.SendError("path not specified.");
return;
- } else if (!NPAPI::PluginList::Singleton()->DisablePlugin(FilePath(path))) {
+ } else if (!webkit::npapi::PluginList::Singleton()->DisablePlugin(
+ FilePath(path))) {
reply.SendError(StringPrintf("Could not disable plugin for path %s.",
path.c_str()));
return;
@@ -3149,19 +3109,16 @@ void TestingAutomationProvider::ImportSettings(Browser* browser,
string_to_import_item["HOME_PAGE"] = importer::HOME_PAGE;
string_to_import_item["ALL"] = importer::ALL;
- string16 browser_name;
- int import_items = 0;
ListValue* import_items_list = NULL;
- bool first_run;
-
- if (!args->GetString("import_from", &browser_name) ||
- !args->GetBoolean("first_run", &first_run) ||
+ if (!args->GetString("import_from", &import_settings_data_.browser_name) ||
+ !args->GetBoolean("first_run", &import_settings_data_.first_run) ||
!args->GetList("import_items", &import_items_list)) {
AutomationJSONReply(this, reply_message).SendError(
"Incorrect type for one or more of the arguments.");
return;
}
+ import_settings_data_.import_items = 0;
int num_items = import_items_list->GetSize();
for (int i = 0; i < num_items; i++) {
std::string item;
@@ -3172,34 +3129,16 @@ void TestingAutomationProvider::ImportSettings(Browser* browser,
"Invalid item string found in import_items.");
return;
}
- import_items |= string_to_import_item[item];
+ import_settings_data_.import_items |= string_to_import_item[item];
}
- ImporterHost* importer_host = new ImporterHost();
- // Get the correct ProfileInfo based on the browser they user provided.
- importer::ProfileInfo profile_info;
- int num_browsers = importer_host->GetAvailableProfileCount();
- int i = 0;
- for ( ; i < num_browsers; i++) {
- string16 name = WideToUTF16Hack(importer_host->GetSourceProfileNameAt(i));
- if (name == browser_name) {
- profile_info = importer_host->GetSourceProfileInfoAt(i);
- break;
- }
- }
- // If we made it to the end of the loop, then the input was bad.
- if (i == num_browsers) {
- AutomationJSONReply(this, reply_message).SendError(
- "Invalid browser name string found.");
- return;
- }
+ import_settings_data_.browser = browser;
+ import_settings_data_.reply_message = reply_message;
- Profile* profile = browser->profile();
-
- importer_host->SetObserver(
- new AutomationProviderImportSettingsObserver(this, reply_message));
- importer_host->StartImportSettings(profile_info, profile, import_items,
- new ProfileWriter(profile), first_run);
+ // The remaining functionality of importing settings is in
+ // SourceProfilesLoaded(), which is called by |importer_host_| once the source
+ // profiles are loaded.
+ importer_host_ = new ImporterHost(this);
}
namespace {
@@ -3733,7 +3672,7 @@ void TestingAutomationProvider::GetExtensionsInfo(
DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
- ExtensionsService* service = profile()->GetExtensionsService();
+ ExtensionService* service = profile()->GetExtensionService();
if (!service) {
reply.SendError("No extensions service.");
}
@@ -3772,7 +3711,7 @@ void TestingAutomationProvider::UninstallExtensionById(
reply.SendError("Must include string id.");
return;
}
- ExtensionsService* service = profile()->GetExtensionsService();
+ ExtensionService* service = profile()->GetExtensionService();
if (!service) {
reply.SendError("No extensions service.");
return;
@@ -4248,27 +4187,7 @@ void TestingAutomationProvider::GetActiveNotifications(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
- NotificationUIManager* manager = g_browser_process->notification_ui_manager();
- const BalloonCollection::Balloons& balloons =
- manager->balloon_collection()->GetActiveBalloons();
- scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
- ListValue* list = new ListValue;
- return_value->Set("notifications", list);
- BalloonCollection::Balloons::const_iterator iter;
- for (iter = balloons.begin(); iter != balloons.end(); ++iter) {
- const Notification& notification = (*iter)->notification();
- DictionaryValue* balloon = new DictionaryValue;
- balloon->SetString("content_url", notification.content_url().spec());
- balloon->SetString("origin_url", notification.origin_url().spec());
- balloon->SetString("display_source", notification.display_source());
- BalloonView* view = (*iter)->view();
- if (view && view->GetHost() && view->GetHost()->render_view_host()) {
- balloon->SetInteger("pid", base::GetProcId(
- view->GetHost()->render_view_host()->process()->GetHandle()));
- }
- list->Append(balloon);
- }
- AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
+ new GetActiveNotificationsObserver(this, reply_message);
}
// Refer to CloseNotification() in chrome/test/pyautolib/pyauto.py for
@@ -4420,6 +4339,27 @@ void TestingAutomationProvider::RestoreAllNTPMostVisitedThumbnails(
reply.SendSuccess(NULL);
}
+void TestingAutomationProvider::KillRendererProcess(
+ Browser* browser,
+ DictionaryValue* args,
+ IPC::Message* reply_message) {
+ int pid;
+ if (!args->GetInteger("pid", &pid)) {
+ AutomationJSONReply(this, reply_message).
+ SendError("'pid' key missing or invalid.");
+ return;
+ }
+ base::ProcessHandle process;
+ if (!base::OpenProcessHandle(static_cast<base::ProcessId>(pid), &process)) {
+ AutomationJSONReply(this, reply_message).SendError(base::StringPrintf(
+ "Failed to open process handle for pid %d", pid));
+ return;
+ }
+ new RendererProcessClosedObserver(this, reply_message);
+ base::KillProcess(process, 0, false);
+ base::CloseProcessHandle(process);
+}
+
void TestingAutomationProvider::WaitForTabCountToBecome(
int browser_handle,
int target_tab_count,
@@ -4497,7 +4437,7 @@ void TestingAutomationProvider::SetContentSetting(
if (host.empty()) {
map->SetDefaultContentSetting(content_type, setting);
} else {
- map->SetContentSetting(HostContentSettingsMap::Pattern(host),
+ map->SetContentSetting(ContentSettingsPattern(host),
content_type, "", setting);
}
*success = true;
@@ -4562,16 +4502,6 @@ void TestingAutomationProvider::OnBrowserRemoved(const Browser* browser) {
}
}
-void TestingAutomationProvider::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- DCHECK(type == NotificationType::SESSION_END);
- // OnBrowserRemoved does a ReleaseLater. When session end is received we exit
- // before the task runs resulting in this object not being deleted. This
- // Release balance out the Release scheduled by OnBrowserRemoved.
- Release();
-}
-
void TestingAutomationProvider::OnRemoveProvider() {
AutomationProviderList::GetInstance()->RemoveProvider(this);
}
diff --git a/chrome/browser/automation/testing_automation_provider.h b/chrome/browser/automation/testing_automation_provider.h
index ac3ad58..6bda672 100644
--- a/chrome/browser/automation/testing_automation_provider.h
+++ b/chrome/browser/automation/testing_automation_provider.h
@@ -11,33 +11,53 @@
#include "chrome/browser/automation/automation_provider.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/history/history.h"
+#include "chrome/browser/importer/importer_list.h"
#include "chrome/browser/sync/profile_sync_service_harness.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/page_type.h"
class DictionaryValue;
+class ImporterHost;
class TemplateURLModel;
// This is an automation provider containing testing calls.
class TestingAutomationProvider : public AutomationProvider,
public BrowserList::Observer,
+ public ImporterList::Observer,
public NotificationObserver {
public:
explicit TestingAutomationProvider(Profile* profile);
- // BrowserList::Observer implementation
+ // BrowserList::Observer implementation.
virtual void OnBrowserAdded(const Browser* browser);
virtual void OnBrowserRemoved(const Browser* browser);
- // IPC implementations
- virtual void OnMessageReceived(const IPC::Message& msg);
+ // IPC::Channel::Listener implementation.
+ virtual bool OnMessageReceived(const IPC::Message& msg);
virtual void OnChannelError();
private:
class PopupMenuWaiter;
+ // Storage for ImportSettings() to resume operations after a callback.
+ struct ImportSettingsData {
+ string16 browser_name;
+ int import_items;
+ bool first_run;
+ Browser* browser;
+ IPC::Message* reply_message;
+ };
+
virtual ~TestingAutomationProvider();
+ // ImporterList::Observer implementation.
+ virtual void SourceProfilesLoaded();
+
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
// IPC Message callbacks.
void CloseBrowser(int handle, IPC::Message* reply_message);
void CloseBrowserAsync(int browser_handle);
@@ -55,7 +75,6 @@ class TestingAutomationProvider : public AutomationProvider,
void DeleteCookie(const GURL& url, const std::string& cookie_name,
int handle, bool* success);
void ShowCollectedCookiesDialog(int handle, bool* success);
- void NavigateToURL(int handle, const GURL& url, IPC::Message* reply_message);
void NavigateToURLBlockUntilNavigationsComplete(int handle, const GURL& url,
int number_of_navigations,
IPC::Message* reply_message);
@@ -64,8 +83,6 @@ class TestingAutomationProvider : public AutomationProvider,
const GURL& url,
WindowOpenDisposition disposition,
bool* status);
- void GoBack(int handle, IPC::Message* reply_message);
- void GoForward(int handle, IPC::Message* reply_message);
void Reload(int handle, IPC::Message* reply_message);
void SetAuth(int tab_handle, const std::wstring& username,
const std::wstring& password, IPC::Message* reply_message);
@@ -142,9 +159,6 @@ class TestingAutomationProvider : public AutomationProvider,
void WaitForAutocompleteEditFocus(int autocomplete_edit_handle,
IPC::Message* reply_message);
- // Deprecated.
- void ApplyAccelerator(int handle, int id);
-
void ExecuteJavascript(int handle,
const std::wstring& frame_xpath,
const std::wstring& script,
@@ -177,7 +191,6 @@ class TestingAutomationProvider : public AutomationProvider,
void GetDownloadDirectory(int handle, FilePath* download_directory);
// If |show| is true, call Show() on the new window after creating it.
- void OpenNewBrowserWindow(bool show, IPC::Message* reply_message);
void OpenNewBrowserWindowOfType(int type,
bool show,
IPC::Message* reply_message);
@@ -520,6 +533,12 @@ class TestingAutomationProvider : public AutomationProvider,
DictionaryValue* args,
IPC::Message* reply_message);
+ // Generate dictionary info about instant tab.
+ // Uses the JSON interface for input/output.
+ void GetInstantInfo(Browser* browser,
+ DictionaryValue* args,
+ IPC::Message* reply_message);
+
// Save the contents of a tab into a file.
// Uses the JSON interface for input/output.
void SaveTabContents(Browser* browser,
@@ -724,6 +743,12 @@ class TestingAutomationProvider : public AutomationProvider,
DictionaryValue* args,
IPC::Message* reply_message);
+ // Kills the given renderer process and returns after the associated
+ // RenderProcessHost receives notification of its closing.
+ void KillRendererProcess(Browser* browser,
+ DictionaryValue* args,
+ IPC::Message* reply_message);
+
void WaitForTabCountToBecome(int browser_handle,
int target_tab_count,
IPC::Message* reply_message);
@@ -756,10 +781,6 @@ class TestingAutomationProvider : public AutomationProvider,
bool success,
history::RedirectList* redirects);
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
void OnRemoveProvider(); // Called via PostTask
#if defined(TOOLKIT_VIEWS)
@@ -782,6 +803,12 @@ class TestingAutomationProvider : public AutomationProvider,
NotificationRegistrar registrar_;
+ // Used to import settings from browser profiles.
+ scoped_refptr<ImporterHost> importer_host_;
+
+ // The stored data for the ImportSettings operation.
+ ImportSettingsData import_settings_data_;
+
DISALLOW_COPY_AND_ASSIGN(TestingAutomationProvider);
};
diff --git a/chrome/browser/automation/testing_automation_provider_mac.mm b/chrome/browser/automation/testing_automation_provider_mac.mm
index bd50ad4..094dfff 100644
--- a/chrome/browser/automation/testing_automation_provider_mac.mm
+++ b/chrome/browser/automation/testing_automation_provider_mac.mm
@@ -12,9 +12,9 @@
#include "base/sys_string_conversions.h"
#include "chrome/browser/automation/automation_browser_tracker.h"
#include "chrome/browser/automation/automation_window_tracker.h"
-#import "chrome/browser/cocoa/browser_window_controller.h"
-#include "chrome/browser/cocoa/tab_window_controller.h"
-#include "chrome/browser/view_ids.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#include "chrome/browser/ui/cocoa/tab_window_controller.h"
+#include "chrome/browser/ui/view_ids.h"
#include "grit/generated_resources.h"
void TestingAutomationProvider::ActivateWindow(int handle) {
diff --git a/chrome/browser/automation/ui_controls_internal.cc b/chrome/browser/automation/ui_controls_internal.cc
new file mode 100644
index 0000000..25598e8
--- /dev/null
+++ b/chrome/browser/automation/ui_controls_internal.cc
@@ -0,0 +1,22 @@
+// 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.
+
+#include "chrome/browser/automation/ui_controls_internal.h"
+
+namespace ui_controls {
+
+ClickTask::ClickTask(MouseButton button, int state, Task* followup)
+ : button_(button), state_(state), followup_(followup) {
+}
+
+ClickTask::~ClickTask() {}
+
+void ClickTask::Run() {
+ if (followup_)
+ SendMouseEventsNotifyWhenDone(button_, state_, followup_);
+ else
+ SendMouseEvents(button_, state_);
+}
+
+} // ui_controls
diff --git a/chrome/browser/automation/ui_controls_internal.h b/chrome/browser/automation/ui_controls_internal.h
index 88631c9..7299b9b 100644
--- a/chrome/browser/automation/ui_controls_internal.h
+++ b/chrome/browser/automation/ui_controls_internal.h
@@ -16,18 +16,9 @@ class ClickTask : public Task {
public:
// A |followup| Task can be specified to notify the caller when the mouse
// click event is sent. If can be NULL if the caller does not care about it.
- ClickTask(MouseButton button, int state, Task* followup)
- : button_(button), state_(state), followup_(followup) {
- }
-
- virtual ~ClickTask() {}
-
- virtual void Run() {
- if (followup_)
- SendMouseEventsNotifyWhenDone(button_, state_, followup_);
- else
- SendMouseEvents(button_, state_);
- }
+ ClickTask(MouseButton button, int state, Task* followup);
+ virtual ~ClickTask();
+ virtual void Run();
private:
MouseButton button_;
diff --git a/chrome/browser/automation/ui_controls_win.cc b/chrome/browser/automation/ui_controls_win.cc
index dfa2af6..25469ad 100644
--- a/chrome/browser/automation/ui_controls_win.cc
+++ b/chrome/browser/automation/ui_controls_win.cc
@@ -8,7 +8,6 @@
#include "app/keyboard_codes.h"
#include "base/logging.h"
#include "base/message_loop.h"
-#include "base/string_util.h"
#include "base/win_util.h"
#include "base/ref_counted.h"
#include "base/task.h"
@@ -18,12 +17,6 @@ namespace ui_controls {
namespace {
-void Checkpoint(const char* message, const base::TimeTicks& start_time) {
- LOG(INFO) << message << " : "
- << (base::TimeTicks::Now() - start_time).InMilliseconds()
- << " ms" << std::flush;
-}
-
// InputDispatcher ------------------------------------------------------------
// InputDispatcher is used to listen for a mouse/keyboard event. When the
@@ -45,7 +38,7 @@ class InputDispatcher : public base::RefCounted<InputDispatcher> {
~InputDispatcher();
- // Notifies the task and release this (which should delete it).
+ // Notifies the task and release this (which should delete it).
void NotifyTask();
// The task we notify.
@@ -78,25 +71,14 @@ LRESULT CALLBACK MouseHook(int n_code, WPARAM w_param, LPARAM l_param) {
// Callback from hook when a key message is received.
LRESULT CALLBACK KeyHook(int n_code, WPARAM w_param, LPARAM l_param) {
- base::TimeTicks start_time = base::TimeTicks::Now();
- char msg[512];
- base::snprintf(msg, 512, "KeyHook starts: %d", n_code);
- Checkpoint(msg, start_time);
-
HHOOK next_hook = next_hook_;
- base::snprintf(msg, 512, "n_code == HC_ACTION: %d, %d",
- l_param, !!(l_param & (1 << 30)));
- Checkpoint(msg, start_time);
if (n_code == HC_ACTION) {
DCHECK(current_dispatcher_);
- if (l_param & (1 << 30)) { // Only send on key up.
- Checkpoint("MatchingMessageFound", start_time);
+ if (l_param & (1 << 30)) {
+ // Only send on key up.
current_dispatcher_->MatchingMessageFound();
- } else {
- Checkpoint("Not key up", start_time);
}
}
- Checkpoint("KeyHook ends, calling next hook.", start_time);
return CallNextHookEx(next_hook, n_code, w_param, l_param);
}
@@ -184,99 +166,77 @@ bool SendKeyEvent(app::KeyboardCode key, bool up) {
bool SendKeyPressImpl(app::KeyboardCode key,
bool control, bool shift, bool alt,
Task* task) {
- base::TimeTicks start_time = base::TimeTicks::Now();
- Checkpoint("SendKeyPressImpl starts", start_time);
-
scoped_refptr<InputDispatcher> dispatcher(
task ? new InputDispatcher(task, WM_KEYUP) : NULL);
// If a pop-up menu is open, it won't receive events sent using SendInput.
// Check for a pop-up menu using its window class (#32768) and if one
// exists, send the key event directly there.
- Checkpoint("FindWindow", start_time);
HWND popup_menu = ::FindWindow(L"#32768", 0);
if (popup_menu != NULL && popup_menu == ::GetTopWindow(NULL)) {
- Checkpoint("Found popup window", start_time);
WPARAM w_param = app::WindowsKeyCodeForKeyboardCode(key);
LPARAM l_param = 0;
- Checkpoint("Send WM_KEYDOWN", start_time);
::SendMessage(popup_menu, WM_KEYDOWN, w_param, l_param);
- Checkpoint("Send WM_KEYUP", start_time);
::SendMessage(popup_menu, WM_KEYUP, w_param, l_param);
- Checkpoint("Send Done", start_time);
if (dispatcher.get())
dispatcher->AddRef();
return true;
}
- Checkpoint("Found no popup window", start_time);
-
- INPUT input[8] = { 0 }; // 8, assuming all the modifiers are activated
+ INPUT input[8] = { 0 }; // 8, assuming all the modifiers are activated.
UINT i = 0;
if (control) {
- Checkpoint("FillKeyboardInput Control", start_time);
if (!FillKeyboardInput(app::VKEY_CONTROL, &input[i], false))
return false;
i++;
}
if (shift) {
- Checkpoint("FillKeyboardInput Shift", start_time);
if (!FillKeyboardInput(app::VKEY_SHIFT, &input[i], false))
return false;
i++;
}
if (alt) {
- Checkpoint("FillKeyboardInput Alt", start_time);
if (!FillKeyboardInput(app::VKEY_MENU, &input[i], false))
return false;
i++;
}
- Checkpoint("FillKeyboardInput 1", start_time);
if (!FillKeyboardInput(key, &input[i], false))
return false;
i++;
- Checkpoint("FillKeyboardInput 2", start_time);
if (!FillKeyboardInput(key, &input[i], true))
return false;
i++;
if (alt) {
- Checkpoint("FillKeyboardInput Alt2", start_time);
if (!FillKeyboardInput(app::VKEY_MENU, &input[i], true))
return false;
i++;
}
if (shift) {
- Checkpoint("FillKeyboardInput Shift2", start_time);
if (!FillKeyboardInput(app::VKEY_SHIFT, &input[i], true))
return false;
i++;
}
if (control) {
- Checkpoint("FillKeyboardInput Ctrl2", start_time);
if (!FillKeyboardInput(app::VKEY_CONTROL, &input[i], true))
return false;
i++;
}
- Checkpoint("SendInput called", start_time);
if (::SendInput(i, input, sizeof(INPUT)) != i)
return false;
- Checkpoint("SendInput done", start_time);
-
if (dispatcher.get())
dispatcher->AddRef();
- Checkpoint("Test done", start_time);
return true;
}
diff --git a/chrome/browser/automation/url_request_automation_job.cc b/chrome/browser/automation/url_request_automation_job.cc
index 1b73b68..7e2bc57 100644
--- a/chrome/browser/automation/url_request_automation_job.cc
+++ b/chrome/browser/automation/url_request_automation_job.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/automation/url_request_automation_job.h"
+#include "base/compiler_specific.h"
#include "base/message_loop.h"
#include "base/time.h"
#include "chrome/browser/automation/automation_resource_message_filter.h"
@@ -39,21 +40,26 @@ static const char* const kFilteredHeaderStrings[] = {
int URLRequestAutomationJob::instance_count_ = 0;
bool URLRequestAutomationJob::is_protocol_factory_registered_ = false;
-URLRequest::ProtocolFactory* URLRequestAutomationJob::old_http_factory_
+net::URLRequest::ProtocolFactory* URLRequestAutomationJob::old_http_factory_
= NULL;
-URLRequest::ProtocolFactory* URLRequestAutomationJob::old_https_factory_
+net::URLRequest::ProtocolFactory* URLRequestAutomationJob::old_https_factory_
= NULL;
-URLRequestAutomationJob::URLRequestAutomationJob(URLRequest* request, int tab,
- int request_id, AutomationResourceMessageFilter* filter, bool is_pending)
- : URLRequestJob(request),
+URLRequestAutomationJob::URLRequestAutomationJob(
+ net::URLRequest* request,
+ int tab,
+ int request_id,
+ AutomationResourceMessageFilter* filter,
+ bool is_pending)
+ : net::URLRequestJob(request),
id_(0),
tab_(tab),
message_filter_(filter),
pending_buf_size_(0),
redirect_status_(0),
request_id_(request_id),
- is_pending_(is_pending) {
+ is_pending_(is_pending),
+ ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
DVLOG(1) << "URLRequestAutomationJob create. Count: " << ++instance_count_;
DCHECK(message_filter_ != NULL);
@@ -73,19 +79,20 @@ bool URLRequestAutomationJob::EnsureProtocolFactoryRegistered() {
if (!is_protocol_factory_registered_) {
old_http_factory_ =
- URLRequest::RegisterProtocolFactory("http",
- &URLRequestAutomationJob::Factory);
+ net::URLRequest::RegisterProtocolFactory(
+ "http", &URLRequestAutomationJob::Factory);
old_https_factory_ =
- URLRequest::RegisterProtocolFactory("https",
- &URLRequestAutomationJob::Factory);
+ net::URLRequest::RegisterProtocolFactory(
+ "https", &URLRequestAutomationJob::Factory);
is_protocol_factory_registered_ = true;
}
return true;
}
-URLRequestJob* URLRequestAutomationJob::Factory(URLRequest* request,
- const std::string& scheme) {
+net::URLRequestJob* URLRequestAutomationJob::Factory(
+ net::URLRequest* request,
+ const std::string& scheme) {
bool scheme_is_http = request->url().SchemeIs("http");
bool scheme_is_https = request->url().SchemeIs("https");
@@ -121,13 +128,15 @@ URLRequestJob* URLRequestAutomationJob::Factory(URLRequest* request,
return NULL;
}
-// URLRequestJob Implementation.
+// net::URLRequestJob Implementation.
void URLRequestAutomationJob::Start() {
if (!is_pending()) {
// Start reading asynchronously so that all error reporting and data
// callbacks happen as they would for network requests.
- MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
- this, &URLRequestAutomationJob::StartAsync));
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &URLRequestAutomationJob::StartAsync));
} else {
// If this is a pending job, then register it immediately with the message
// filter so it can be serviced later when we receive a request from the
@@ -139,12 +148,12 @@ void URLRequestAutomationJob::Start() {
void URLRequestAutomationJob::Kill() {
if (message_filter_.get()) {
if (!is_pending()) {
- message_filter_->Send(new AutomationMsg_RequestEnd(0, tab_, id_,
+ message_filter_->Send(new AutomationMsg_RequestEnd(tab_, id_,
URLRequestStatus(URLRequestStatus::CANCELED, net::ERR_ABORTED)));
}
}
DisconnectFromMessageFilter();
- URLRequestJob::Kill();
+ net::URLRequestJob::Kill();
}
bool URLRequestAutomationJob::ReadRawData(
@@ -159,13 +168,13 @@ bool URLRequestAutomationJob::ReadRawData(
pending_buf_size_ = buf_size;
if (message_filter_) {
- message_filter_->Send(new AutomationMsg_RequestRead(0, tab_, id_,
- buf_size));
+ message_filter_->Send(new AutomationMsg_RequestRead(tab_, id_, buf_size));
SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
} else {
- BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(this,
- &URLRequestAutomationJob::NotifyJobCompletionTask));
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &URLRequestAutomationJob::NotifyJobCompletionTask));
}
return false;
}
@@ -231,11 +240,8 @@ bool URLRequestAutomationJob::MayFilterMessage(const IPC::Message& message,
case AutomationMsg_RequestData::ID:
case AutomationMsg_RequestEnd::ID: {
void* iter = NULL;
- int tab = 0;
- if (message.ReadInt(&iter, &tab) &&
- message.ReadInt(&iter, request_id)) {
+ if (message.ReadInt(&iter, request_id))
return true;
- }
break;
}
}
@@ -258,8 +264,8 @@ void URLRequestAutomationJob::OnMessage(const IPC::Message& message) {
IPC_END_MESSAGE_MAP()
}
-void URLRequestAutomationJob::OnRequestStarted(int tab, int id,
- const IPC::AutomationURLResponse& response) {
+void URLRequestAutomationJob::OnRequestStarted(
+ int id, const AutomationURLResponse& response) {
DVLOG(1) << "URLRequestAutomationJob: " << request_->url().spec()
<< " - response started.";
set_expected_content_size(response.content_length);
@@ -279,7 +285,7 @@ void URLRequestAutomationJob::OnRequestStarted(int tab, int id,
}
void URLRequestAutomationJob::OnDataAvailable(
- int tab, int id, const std::string& bytes) {
+ int id, const std::string& bytes) {
DVLOG(1) << "URLRequestAutomationJob: " << request_->url().spec()
<< " - data available, Size: " << bytes.size();
DCHECK(!bytes.empty());
@@ -303,7 +309,7 @@ void URLRequestAutomationJob::OnDataAvailable(
}
void URLRequestAutomationJob::OnRequestEnd(
- int tab, int id, const URLRequestStatus& status) {
+ int id, const URLRequestStatus& status) {
#ifndef NDEBUG
std::string url;
if (request_)
@@ -426,19 +432,18 @@ void URLRequestAutomationJob::StartAsync() {
}
// Ask automation to start this request.
- IPC::AutomationURLRequest automation_request = {
- request_->url().spec(),
- request_->method(),
- referrer.spec(),
- new_request_headers.ToString(),
- request_->get_upload(),
- resource_type,
- request_->load_flags()
- };
+ AutomationURLRequest automation_request(
+ request_->url().spec(),
+ request_->method(),
+ referrer.spec(),
+ new_request_headers.ToString(),
+ request_->get_upload(),
+ resource_type,
+ request_->load_flags());
DCHECK(message_filter_);
- message_filter_->Send(new AutomationMsg_RequestStart(0, tab_, id_,
- automation_request));
+ message_filter_->Send(new AutomationMsg_RequestStart(
+ tab_, id_, automation_request));
}
void URLRequestAutomationJob::DisconnectFromMessageFilter() {
diff --git a/chrome/browser/automation/url_request_automation_job.h b/chrome/browser/automation/url_request_automation_job.h
index 06401d7..9256a77 100644
--- a/chrome/browser/automation/url_request_automation_job.h
+++ b/chrome/browser/automation/url_request_automation_job.h
@@ -7,11 +7,13 @@
#define CHROME_BROWSER_AUTOMATION_URL_REQUEST_AUTOMATION_JOB_H_
#pragma once
+#include "base/task.h"
#include "chrome/common/ref_counted_util.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_job.h"
class AutomationResourceMessageFilter;
+struct AutomationURLResponse;
namespace net {
class HttpResponseHeaders;
@@ -20,23 +22,22 @@ class HttpResponseInfo;
namespace IPC {
class Message;
-struct AutomationURLResponse;
}
-// URLRequestJob implementation that loads the resources using
+// net::URLRequestJob implementation that loads the resources using
// automation.
class URLRequestAutomationJob : public net::URLRequestJob {
public:
- URLRequestAutomationJob(URLRequest* request, int tab, int request_id,
+ URLRequestAutomationJob(net::URLRequest* request, int tab, int request_id,
AutomationResourceMessageFilter* filter,
bool is_pending);
// Register our factory for HTTP/HTTPs requests.
static bool EnsureProtocolFactoryRegistered();
- static URLRequest::ProtocolFactory Factory;
+ static net::URLRequest::ProtocolFactory Factory;
- // URLRequestJob methods.
+ // net::URLRequestJob methods.
virtual void Start();
virtual void Kill();
virtual bool GetMimeType(std::string* mime_type) const;
@@ -72,7 +73,7 @@ class URLRequestAutomationJob : public net::URLRequestJob {
AutomationResourceMessageFilter* new_filter);
protected:
- // Protected URLRequestJob override.
+ // Protected net::URLRequestJob override.
virtual bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read);
void StartAsync();
@@ -80,10 +81,9 @@ class URLRequestAutomationJob : public net::URLRequestJob {
void DisconnectFromMessageFilter();
// IPC message handlers.
- void OnRequestStarted(int tab, int id,
- const IPC::AutomationURLResponse& response);
- void OnDataAvailable(int tab, int id, const std::string& bytes);
- void OnRequestEnd(int tab, int id, const URLRequestStatus& status);
+ void OnRequestStarted(int id, const AutomationURLResponse& response);
+ void OnDataAvailable(int id, const std::string& bytes);
+ void OnRequestEnd(int id, const URLRequestStatus& status);
private:
virtual ~URLRequestAutomationJob();
@@ -110,8 +110,8 @@ class URLRequestAutomationJob : public net::URLRequestJob {
static bool is_protocol_factory_registered_;
// The previous HTTP/HTTPs protocol factories. We pass unhandled
// requests off to these factories
- static URLRequest::ProtocolFactory* old_http_factory_;
- static URLRequest::ProtocolFactory* old_https_factory_;
+ static net::URLRequest::ProtocolFactory* old_http_factory_;
+ static net::URLRequest::ProtocolFactory* old_https_factory_;
// Set to true if the job is waiting for the external host to connect to the
// automation channel, which will be used for routing the network requests to
@@ -122,8 +122,9 @@ class URLRequestAutomationJob : public net::URLRequestJob {
// stack when we receive a Read request for a completed job.
URLRequestStatus request_status_;
+ ScopedRunnableMethodFactory<URLRequestAutomationJob> method_factory_;
+
DISALLOW_COPY_AND_ASSIGN(URLRequestAutomationJob);
};
#endif // CHROME_BROWSER_AUTOMATION_URL_REQUEST_AUTOMATION_JOB_H_
-
diff --git a/chrome/browser/back_forward_menu_model.cc b/chrome/browser/back_forward_menu_model.cc
deleted file mode 100644
index 31595d5..0000000
--- a/chrome/browser/back_forward_menu_model.cc
+++ /dev/null
@@ -1,379 +0,0 @@
-// 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.
-
-#include "build/build_config.h"
-
-#include "chrome/browser/back_forward_menu_model.h"
-
-#include "app/l10n_util.h"
-#include "app/text_elider.h"
-#include "app/resource_bundle.h"
-#include "base/string_number_conversions.h"
-#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/tab_contents/navigation_controller.h"
-#include "chrome/browser/tab_contents/navigation_entry.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/common/url_constants.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#include "net/base/registry_controlled_domain.h"
-
-const int BackForwardMenuModel::kMaxHistoryItems = 12;
-const int BackForwardMenuModel::kMaxChapterStops = 5;
-static const int kMaxWidth = 700;
-
-BackForwardMenuModel::BackForwardMenuModel(Browser* browser,
- ModelType model_type)
- : browser_(browser),
- test_tab_contents_(NULL),
- model_type_(model_type) {
-}
-
-bool BackForwardMenuModel::HasIcons() const {
- return true;
-}
-
-int BackForwardMenuModel::GetItemCount() const {
- int items = GetHistoryItemCount();
-
- if (items > 0) {
- int chapter_stops = 0;
-
- // Next, we count ChapterStops, if any.
- if (items == kMaxHistoryItems)
- chapter_stops = GetChapterStopCount(items);
-
- if (chapter_stops)
- items += chapter_stops + 1; // Chapter stops also need a separator.
-
- // If the menu is not empty, add two positions in the end
- // for a separator and a "Show Full History" item.
- items += 2;
- }
-
- return items;
-}
-
-menus::MenuModel::ItemType BackForwardMenuModel::GetTypeAt(int index) const {
- return IsSeparator(index) ? TYPE_SEPARATOR : TYPE_COMMAND;
-}
-
-int BackForwardMenuModel::GetCommandIdAt(int index) const {
- return index;
-}
-
-string16 BackForwardMenuModel::GetLabelAt(int index) const {
- // Return label "Show Full History" for the last item of the menu.
- if (index == GetItemCount() - 1)
- return l10n_util::GetStringUTF16(IDS_SHOWFULLHISTORY_LINK);
-
- // Return an empty string for a separator.
- if (IsSeparator(index))
- return string16();
-
- // Return the entry title, escaping any '&' characters and eliding it if it's
- // super long.
- NavigationEntry* entry = GetNavigationEntry(index);
- string16 menu_text(entry->GetTitleForDisplay(
- &GetTabContents()->controller()));
- menu_text = gfx::ElideText(menu_text, gfx::Font(), kMaxWidth, false);
-
- for (size_t i = menu_text.find('&'); i != string16::npos;
- i = menu_text.find('&', i + 2)) {
- menu_text.insert(i, 1, '&');
- }
- return menu_text;
-}
-
-bool BackForwardMenuModel::IsLabelDynamicAt(int index) const {
- // This object is only used for a single showing of a menu.
- return false;
-}
-
-bool BackForwardMenuModel::GetAcceleratorAt(
- int index,
- menus::Accelerator* accelerator) const {
- return false;
-}
-
-bool BackForwardMenuModel::IsItemCheckedAt(int index) const {
- return false;
-}
-
-int BackForwardMenuModel::GetGroupIdAt(int index) const {
- return false;
-}
-
-bool BackForwardMenuModel::GetIconAt(int index, SkBitmap* icon) const {
- if (!ItemHasIcon(index))
- return false;
-
- if (index == GetItemCount() - 1) {
- *icon = *ResourceBundle::GetSharedInstance().GetBitmapNamed(
- IDR_HISTORY_FAVICON);
- } else {
- NavigationEntry* entry = GetNavigationEntry(index);
- *icon = entry->favicon().bitmap();
- }
-
- return true;
-}
-
-menus::ButtonMenuItemModel* BackForwardMenuModel::GetButtonMenuItemAt(
- int index) const {
- return NULL;
-}
-
-bool BackForwardMenuModel::IsEnabledAt(int index) const {
- return index < GetItemCount() && !IsSeparator(index);
-}
-
-menus::MenuModel* BackForwardMenuModel::GetSubmenuModelAt(int index) const {
- return NULL;
-}
-
-void BackForwardMenuModel::HighlightChangedTo(int index) {
-}
-
-void BackForwardMenuModel::ActivatedAt(int index) {
- ActivatedAtWithDisposition(index, CURRENT_TAB);
-}
-
-void BackForwardMenuModel::ActivatedAtWithDisposition(
- int index, int disposition) {
- Profile* profile = browser_->profile();
-
- DCHECK(!IsSeparator(index));
-
- // Execute the command for the last item: "Show Full History".
- if (index == GetItemCount() - 1) {
- UserMetrics::RecordComputedAction(BuildActionName("ShowFullHistory", -1),
- profile);
- browser_->ShowSingletonTab(GURL(chrome::kChromeUIHistoryURL), false);
- return;
- }
-
- // Log whether it was a history or chapter click.
- if (index < GetHistoryItemCount()) {
- UserMetrics::RecordComputedAction(
- BuildActionName("HistoryClick", index), profile);
- } else {
- UserMetrics::RecordComputedAction(
- BuildActionName("ChapterClick", index - GetHistoryItemCount() - 1),
- profile);
- }
-
- int controller_index = MenuIndexToNavEntryIndex(index);
- if (!browser_->NavigateToIndexWithDisposition(
- controller_index, static_cast<WindowOpenDisposition>(disposition))) {
- NOTREACHED();
- }
-}
-
-void BackForwardMenuModel::MenuWillShow() {
- UserMetrics::RecordComputedAction(BuildActionName("Popup", -1),
- browser_->profile());
-}
-
-bool BackForwardMenuModel::IsSeparator(int index) const {
- int history_items = GetHistoryItemCount();
- // If the index is past the number of history items + separator,
- // we then consider if it is a chapter-stop entry.
- if (index > history_items) {
- // We either are in ChapterStop area, or at the end of the list (the "Show
- // Full History" link).
- int chapter_stops = GetChapterStopCount(history_items);
- if (chapter_stops == 0)
- return false; // We must have reached the "Show Full History" link.
- // Otherwise, look to see if we have reached the separator for the
- // chapter-stops. If not, this is a chapter stop.
- return (index == history_items + 1 + chapter_stops);
- }
-
- // Look to see if we have reached the separator for the history items.
- return index == history_items;
-}
-
-int BackForwardMenuModel::GetHistoryItemCount() const {
- TabContents* contents = GetTabContents();
- int items = 0;
-
- if (model_type_ == FORWARD_MENU) {
- // Only count items from n+1 to end (if n is current entry)
- items = contents->controller().entry_count() -
- contents->controller().GetCurrentEntryIndex() - 1;
- } else {
- items = contents->controller().GetCurrentEntryIndex();
- }
-
- if (items > kMaxHistoryItems)
- items = kMaxHistoryItems;
- else if (items < 0)
- items = 0;
-
- return items;
-}
-
-int BackForwardMenuModel::GetChapterStopCount(int history_items) const {
- TabContents* contents = GetTabContents();
-
- int chapter_stops = 0;
- int current_entry = contents->controller().GetCurrentEntryIndex();
-
- if (history_items == kMaxHistoryItems) {
- int chapter_id = current_entry;
- if (model_type_ == FORWARD_MENU) {
- chapter_id += history_items;
- } else {
- chapter_id -= history_items;
- }
-
- do {
- chapter_id = GetIndexOfNextChapterStop(chapter_id,
- model_type_ == FORWARD_MENU);
- if (chapter_id != -1)
- ++chapter_stops;
- } while (chapter_id != -1 && chapter_stops < kMaxChapterStops);
- }
-
- return chapter_stops;
-}
-
-int BackForwardMenuModel::GetIndexOfNextChapterStop(int start_from,
- bool forward) const {
- TabContents* contents = GetTabContents();
- NavigationController& controller = contents->controller();
-
- int max_count = controller.entry_count();
- if (start_from < 0 || start_from >= max_count)
- return -1; // Out of bounds.
-
- if (forward) {
- if (start_from < max_count - 1) {
- // We want to advance over the current chapter stop, so we add one.
- // We don't need to do this when direction is backwards.
- start_from++;
- } else {
- return -1;
- }
- }
-
- NavigationEntry* start_entry = controller.GetEntryAtIndex(start_from);
- const GURL& url = start_entry->url();
-
- if (!forward) {
- // When going backwards we return the first entry we find that has a
- // different domain.
- for (int i = start_from - 1; i >= 0; --i) {
- if (!net::RegistryControlledDomainService::SameDomainOrHost(url,
- controller.GetEntryAtIndex(i)->url()))
- return i;
- }
- // We have reached the beginning without finding a chapter stop.
- return -1;
- } else {
- // When going forwards we return the entry before the entry that has a
- // different domain.
- for (int i = start_from + 1; i < max_count; ++i) {
- if (!net::RegistryControlledDomainService::SameDomainOrHost(url,
- controller.GetEntryAtIndex(i)->url()))
- return i - 1;
- }
- // Last entry is always considered a chapter stop.
- return max_count - 1;
- }
-}
-
-int BackForwardMenuModel::FindChapterStop(int offset,
- bool forward,
- int skip) const {
- if (offset < 0 || skip < 0)
- return -1;
-
- if (!forward)
- offset *= -1;
-
- TabContents* contents = GetTabContents();
- int entry = contents->controller().GetCurrentEntryIndex() + offset;
- for (int i = 0; i < skip + 1; i++)
- entry = GetIndexOfNextChapterStop(entry, forward);
-
- return entry;
-}
-
-bool BackForwardMenuModel::ItemHasCommand(int index) const {
- return index < GetItemCount() && !IsSeparator(index);
-}
-
-bool BackForwardMenuModel::ItemHasIcon(int index) const {
- return index < GetItemCount() && !IsSeparator(index);
-}
-
-string16 BackForwardMenuModel::GetShowFullHistoryLabel() const {
- return l10n_util::GetStringUTF16(IDS_SHOWFULLHISTORY_LINK);
-}
-
-TabContents* BackForwardMenuModel::GetTabContents() const {
- // We use the test tab contents if the unit test has specified it.
- return test_tab_contents_ ? test_tab_contents_ :
- browser_->GetSelectedTabContents();
-}
-
-int BackForwardMenuModel::MenuIndexToNavEntryIndex(int index) const {
- TabContents* contents = GetTabContents();
- int history_items = GetHistoryItemCount();
-
- DCHECK_GE(index, 0);
-
- // Convert anything above the History items separator.
- if (index < history_items) {
- if (model_type_ == FORWARD_MENU) {
- index += contents->controller().GetCurrentEntryIndex() + 1;
- } else {
- // Back menu is reverse.
- index = contents->controller().GetCurrentEntryIndex() - (index + 1);
- }
- return index;
- }
- if (index == history_items)
- return -1; // Don't translate the separator for history items.
-
- if (index >= history_items + 1 + GetChapterStopCount(history_items))
- return -1; // This is beyond the last chapter stop so we abort.
-
- // This menu item is a chapter stop located between the two separators.
- index = FindChapterStop(history_items,
- model_type_ == FORWARD_MENU,
- index - history_items - 1);
-
- return index;
-}
-
-NavigationEntry* BackForwardMenuModel::GetNavigationEntry(int index) const {
- int controller_index = MenuIndexToNavEntryIndex(index);
- NavigationController& controller = GetTabContents()->controller();
- if (controller_index >= 0 && controller_index < controller.entry_count())
- return controller.GetEntryAtIndex(controller_index);
-
- NOTREACHED();
- return NULL;
-}
-
-std::string BackForwardMenuModel::BuildActionName(
- const std::string& action, int index) const {
- DCHECK(!action.empty());
- DCHECK(index >= -1);
- std::string metric_string;
- if (model_type_ == FORWARD_MENU)
- metric_string += "ForwardMenu_";
- else
- metric_string += "BackMenu_";
- metric_string += action;
- if (index != -1) {
- // +1 is for historical reasons (indices used to start at 1).
- metric_string += base::IntToString(index + 1);
- }
- return metric_string;
-}
diff --git a/chrome/browser/back_forward_menu_model.h b/chrome/browser/back_forward_menu_model.h
deleted file mode 100644
index b97698d..0000000
--- a/chrome/browser/back_forward_menu_model.h
+++ /dev/null
@@ -1,171 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_BACK_FORWARD_MENU_MODEL_H_
-#define CHROME_BROWSER_BACK_FORWARD_MENU_MODEL_H_
-#pragma once
-
-#include <string>
-
-#include "app/menus/menu_model.h"
-#include "base/basictypes.h"
-#include "base/gtest_prod_util.h"
-#include "base/string16.h"
-#include "webkit/glue/window_open_disposition.h"
-
-class Browser;
-class SkBitmap;
-class TabContents;
-class NavigationEntry;
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// BackForwardMenuModel
-//
-// Interface for the showing of the dropdown menu for the Back/Forward buttons.
-// Actual implementations are platform-specific.
-///////////////////////////////////////////////////////////////////////////////
-class BackForwardMenuModel : public menus::MenuModel {
- public:
- // These are IDs used to identify individual UI elements within the
- // browser window using View::GetViewByID.
- enum ModelType {
- FORWARD_MENU = 1,
- BACKWARD_MENU = 2
- };
-
- BackForwardMenuModel(Browser* browser, ModelType model_type);
- virtual ~BackForwardMenuModel() { }
-
- // MenuModel implementation.
- virtual bool HasIcons() const;
- // Returns how many items the menu should show, including history items,
- // chapter-stops, separators and the Show Full History link. This function
- // uses GetHistoryItemCount() and GetChapterStopCount() internally to figure
- // out the total number of items to show.
- virtual int GetItemCount() const;
- virtual ItemType GetTypeAt(int index) const;
- virtual int GetCommandIdAt(int index) const;
- virtual string16 GetLabelAt(int index) const;
- virtual bool IsLabelDynamicAt(int index) const;
- virtual bool GetAcceleratorAt(int index,
- menus::Accelerator* accelerator) const;
- virtual bool IsItemCheckedAt(int index) const;
- virtual int GetGroupIdAt(int index) const;
- virtual bool GetIconAt(int index, SkBitmap* icon) const;
- virtual menus::ButtonMenuItemModel* GetButtonMenuItemAt(int index) const;
- virtual bool IsEnabledAt(int index) const;
- virtual MenuModel* GetSubmenuModelAt(int index) const;
- virtual void HighlightChangedTo(int index);
- virtual void ActivatedAt(int index);
- virtual void ActivatedAtWithDisposition(int index, int disposition);
- virtual void MenuWillShow();
-
- // Is the item at |index| a separator?
- bool IsSeparator(int index) const;
-
- private:
- // Allows the unit test to use its own dummy tab contents.
- void set_test_tab_contents(TabContents* test_tab_contents) {
- test_tab_contents_ = test_tab_contents;
- }
-
- // Returns how many history items the menu should show. For example, if the
- // navigation controller of the current tab has a current entry index of 5 and
- // forward_direction_ is false (we are the back button delegate) then this
- // function will return 5 (representing 0-4). If forward_direction_ is
- // true (we are the forward button delegate), then this function will return
- // the number of entries after 5. Note, though, that in either case it will
- // not report more than kMaxHistoryItems. The number returned also does not
- // include the separator line after the history items (nor the separator for
- // the "Show Full History" link).
- int GetHistoryItemCount() const;
-
- // Returns how many chapter-stop items the menu should show. For the
- // definition of a chapter-stop, see GetIndexOfNextChapterStop(). The number
- // returned does not include the separator lines before and after the
- // chapter-stops.
- int GetChapterStopCount(int history_items) const;
-
- // Finds the next chapter-stop in the NavigationEntryList starting from
- // the index specified in |start_from| and continuing in the direction
- // specified (|forward|) until either a chapter-stop is found or we reach the
- // end, in which case -1 is returned. If |start_from| is out of bounds, -1
- // will also be returned. A chapter-stop is defined as the last page the user
- // browsed to within the same domain. For example, if the user's homepage is
- // Google and she navigates to Google pages G1, G2 and G3 before heading over
- // to WikiPedia for pages W1 and W2 and then back to Google for pages G4 and
- // G5 then G3, W2 and G5 are considered chapter-stops. The return value from
- // this function is an index into the NavigationEntryList vector.
- int GetIndexOfNextChapterStop(int start_from, bool forward) const;
-
- // Finds a given chapter-stop starting at the currently active entry in the
- // NavigationEntryList vector advancing first forward or backward by |offset|
- // (depending on the direction specified in parameter |forward|). It also
- // allows you to skip chapter-stops by specifying a positive value for |skip|.
- // Example: FindChapterStop(5, false, 3) starts with the currently active
- // index, subtracts 5 from it and then finds the fourth chapter-stop before
- // that index (skipping the first 3 it finds).
- // Example: FindChapterStop(0, true, 0) is functionally equivalent to
- // calling GetIndexOfNextChapterStop(GetCurrentEntryIndex(), true).
- //
- // NOTE: Both |offset| and |skip| must be non-negative. The return value from
- // this function is an index into the NavigationEntryList vector. If |offset|
- // is out of bounds or if we skip too far (run out of chapter-stops) this
- // function returns -1.
- int FindChapterStop(int offset, bool forward, int skip) const;
-
- // How many items (max) to show in the back/forward history menu dropdown.
- static const int kMaxHistoryItems;
-
- // How many chapter-stops (max) to show in the back/forward dropdown list.
- static const int kMaxChapterStops;
-
- // Takes a menu item index as passed in through one of the menu delegate
- // functions and converts it into an index into the NavigationEntryList
- // vector. |index| can point to a separator, or the
- // "Show Full History" link in which case this function returns -1.
- int MenuIndexToNavEntryIndex(int index) const;
-
- // Does the item have a command associated with it?
- bool ItemHasCommand(int index) const;
-
- // Returns true if there is an icon for this menu item.
- bool ItemHasIcon(int index) const;
-
- // Allow the unit test to use the "Show Full History" label.
- string16 GetShowFullHistoryLabel() const;
-
- // Looks up a NavigationEntry by menu id.
- NavigationEntry* GetNavigationEntry(int index) const;
-
- // Retrieves the TabContents pointer to use, which is either the one that
- // the unit test sets (using SetTabContentsForUnitTest) or the one from
- // the browser window.
- TabContents* GetTabContents() const;
-
- // Build a string version of a user action on this menu, used as an
- // identifier for logging user behavior.
- // E.g. BuildActionName("Click", 2) returns "BackMenu_Click2".
- // An index of -1 means no index.
- std::string BuildActionName(const std::string& name, int index) const;
-
- Browser* browser_;
-
- // The unit tests will provide their own TabContents to use.
- TabContents* test_tab_contents_;
-
- // Represents whether this is the delegate for the forward button or the
- // back button.
- ModelType model_type_;
-
- friend class BackFwdMenuModelTest;
- FRIEND_TEST_ALL_PREFIXES(BackFwdMenuModelTest, BasicCase);
- FRIEND_TEST_ALL_PREFIXES(BackFwdMenuModelTest, MaxItemsTest);
- FRIEND_TEST_ALL_PREFIXES(BackFwdMenuModelTest, ChapterStops);
-
- DISALLOW_COPY_AND_ASSIGN(BackForwardMenuModel);
-};
-
-#endif // CHROME_BROWSER_BACK_FORWARD_MENU_MODEL_H_
diff --git a/chrome/browser/back_forward_menu_model_unittest.cc b/chrome/browser/back_forward_menu_model_unittest.cc
deleted file mode 100644
index f6d2ea7..0000000
--- a/chrome/browser/back_forward_menu_model_unittest.cc
+++ /dev/null
@@ -1,422 +0,0 @@
-// 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.
-
-#include "chrome/browser/back_forward_menu_model.h"
-
-#include "base/path_service.h"
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/profile_manager.h"
-#include "chrome/browser/renderer_host/test/test_render_view_host.h"
-#include "chrome/browser/tab_contents/navigation_controller.h"
-#include "chrome/browser/tab_contents/navigation_entry.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents/test_tab_contents.h"
-#include "chrome/common/url_constants.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-class BackFwdMenuModelTest : public RenderViewHostTestHarness {
- public:
- void ValidateModel(BackForwardMenuModel* model, int history_items,
- int chapter_stops) {
- int h = std::min(BackForwardMenuModel::kMaxHistoryItems, history_items);
- int c = std::min(BackForwardMenuModel::kMaxChapterStops, chapter_stops);
- EXPECT_EQ(h, model->GetHistoryItemCount());
- EXPECT_EQ(c, model->GetChapterStopCount(h));
- if (h > 0)
- h += 2; // Separator and View History link.
- if (c > 0)
- ++c;
- EXPECT_EQ(h + c, model->GetItemCount());
- }
-
- void LoadURLAndUpdateState(const char* url, const char* title) {
- NavigateAndCommit(GURL(url));
- controller().GetLastCommittedEntry()->set_title(UTF8ToUTF16(title));
- }
-
- // Navigate back or forward the given amount and commits the entry (which
- // will be pending after we ask to navigate there).
- void NavigateToOffset(int offset) {
- controller().GoToOffset(offset);
- contents()->CommitPendingNavigation();
- }
-
- // Same as NavigateToOffset but goes to an absolute index.
- void NavigateToIndex(int index) {
- controller().GoToIndex(index);
- contents()->CommitPendingNavigation();
- }
-
- // Goes back/forward and commits the load.
- void GoBack() {
- controller().GoBack();
- contents()->CommitPendingNavigation();
- }
- void GoForward() {
- controller().GoForward();
- contents()->CommitPendingNavigation();
- }
-};
-
-TEST_F(BackFwdMenuModelTest, BasicCase) {
- scoped_ptr<BackForwardMenuModel> back_model(new BackForwardMenuModel(
- NULL, BackForwardMenuModel::BACKWARD_MENU));
- back_model->set_test_tab_contents(contents());
-
- scoped_ptr<BackForwardMenuModel> forward_model(new BackForwardMenuModel(
- NULL, BackForwardMenuModel::FORWARD_MENU));
- forward_model->set_test_tab_contents(contents());
-
- EXPECT_EQ(0, back_model->GetItemCount());
- EXPECT_EQ(0, forward_model->GetItemCount());
- EXPECT_FALSE(back_model->ItemHasCommand(1));
-
- // Seed the controller with a few URLs
- LoadURLAndUpdateState("http://www.a.com/1", "A1");
- LoadURLAndUpdateState("http://www.a.com/2", "A2");
- LoadURLAndUpdateState("http://www.a.com/3", "A3");
- LoadURLAndUpdateState("http://www.b.com/1", "B1");
- LoadURLAndUpdateState("http://www.b.com/2", "B2");
- LoadURLAndUpdateState("http://www.c.com/1", "C1");
- LoadURLAndUpdateState("http://www.c.com/2", "C2");
- LoadURLAndUpdateState("http://www.c.com/3", "C3");
-
- // There're two more items here: a separator and a "Show Full History".
- EXPECT_EQ(9, back_model->GetItemCount());
- EXPECT_EQ(0, forward_model->GetItemCount());
- EXPECT_EQ(ASCIIToUTF16("C2"), back_model->GetLabelAt(0));
- EXPECT_EQ(ASCIIToUTF16("A1"), back_model->GetLabelAt(6));
- EXPECT_EQ(back_model->GetShowFullHistoryLabel(),
- back_model->GetLabelAt(8));
-
- EXPECT_TRUE(back_model->ItemHasCommand(0));
- EXPECT_TRUE(back_model->ItemHasCommand(6));
- EXPECT_TRUE(back_model->IsSeparator(7));
- EXPECT_TRUE(back_model->ItemHasCommand(8));
- EXPECT_FALSE(back_model->ItemHasCommand(9));
- EXPECT_FALSE(back_model->ItemHasCommand(9));
-
- NavigateToOffset(-7);
-
- EXPECT_EQ(0, back_model->GetItemCount());
- EXPECT_EQ(9, forward_model->GetItemCount());
- EXPECT_EQ(ASCIIToUTF16("A2"), forward_model->GetLabelAt(0));
- EXPECT_EQ(ASCIIToUTF16("C3"), forward_model->GetLabelAt(6));
- EXPECT_EQ(forward_model->GetShowFullHistoryLabel(),
- forward_model->GetLabelAt(8));
-
- EXPECT_TRUE(forward_model->ItemHasCommand(0));
- EXPECT_TRUE(forward_model->ItemHasCommand(6));
- EXPECT_TRUE(forward_model->IsSeparator(7));
- EXPECT_TRUE(forward_model->ItemHasCommand(8));
- EXPECT_FALSE(forward_model->ItemHasCommand(7));
- EXPECT_FALSE(forward_model->ItemHasCommand(9));
-
- NavigateToOffset(4);
-
- EXPECT_EQ(6, back_model->GetItemCount());
- EXPECT_EQ(5, forward_model->GetItemCount());
- EXPECT_EQ(ASCIIToUTF16("B1"), back_model->GetLabelAt(0));
- EXPECT_EQ(ASCIIToUTF16("A1"), back_model->GetLabelAt(3));
- EXPECT_EQ(back_model->GetShowFullHistoryLabel(),
- back_model->GetLabelAt(5));
- EXPECT_EQ(ASCIIToUTF16("C1"), forward_model->GetLabelAt(0));
- EXPECT_EQ(ASCIIToUTF16("C3"), forward_model->GetLabelAt(2));
- EXPECT_EQ(forward_model->GetShowFullHistoryLabel(),
- forward_model->GetLabelAt(4));
-}
-
-TEST_F(BackFwdMenuModelTest, MaxItemsTest) {
- scoped_ptr<BackForwardMenuModel> back_model(new BackForwardMenuModel(
- NULL, BackForwardMenuModel::BACKWARD_MENU));
- back_model->set_test_tab_contents(contents());
-
- scoped_ptr<BackForwardMenuModel> forward_model(new BackForwardMenuModel(
- NULL, BackForwardMenuModel::FORWARD_MENU));
- forward_model->set_test_tab_contents(contents());
-
- // Seed the controller with 32 URLs
- LoadURLAndUpdateState("http://www.a.com/1", "A1");
- LoadURLAndUpdateState("http://www.a.com/2", "A2");
- LoadURLAndUpdateState("http://www.a.com/3", "A3");
- LoadURLAndUpdateState("http://www.b.com/1", "B1");
- LoadURLAndUpdateState("http://www.b.com/2", "B2");
- LoadURLAndUpdateState("http://www.b.com/3", "B3");
- LoadURLAndUpdateState("http://www.c.com/1", "C1");
- LoadURLAndUpdateState("http://www.c.com/2", "C2");
- LoadURLAndUpdateState("http://www.c.com/3", "C3");
- LoadURLAndUpdateState("http://www.d.com/1", "D1");
- LoadURLAndUpdateState("http://www.d.com/2", "D2");
- LoadURLAndUpdateState("http://www.d.com/3", "D3");
- LoadURLAndUpdateState("http://www.e.com/1", "E1");
- LoadURLAndUpdateState("http://www.e.com/2", "E2");
- LoadURLAndUpdateState("http://www.e.com/3", "E3");
- LoadURLAndUpdateState("http://www.f.com/1", "F1");
- LoadURLAndUpdateState("http://www.f.com/2", "F2");
- LoadURLAndUpdateState("http://www.f.com/3", "F3");
- LoadURLAndUpdateState("http://www.g.com/1", "G1");
- LoadURLAndUpdateState("http://www.g.com/2", "G2");
- LoadURLAndUpdateState("http://www.g.com/3", "G3");
- LoadURLAndUpdateState("http://www.h.com/1", "H1");
- LoadURLAndUpdateState("http://www.h.com/2", "H2");
- LoadURLAndUpdateState("http://www.h.com/3", "H3");
- LoadURLAndUpdateState("http://www.i.com/1", "I1");
- LoadURLAndUpdateState("http://www.i.com/2", "I2");
- LoadURLAndUpdateState("http://www.i.com/3", "I3");
- LoadURLAndUpdateState("http://www.j.com/1", "J1");
- LoadURLAndUpdateState("http://www.j.com/2", "J2");
- LoadURLAndUpdateState("http://www.j.com/3", "J3");
- LoadURLAndUpdateState("http://www.k.com/1", "K1");
- LoadURLAndUpdateState("http://www.k.com/2", "K2");
-
- // Also there're two more for a separator and a "Show Full History".
- int chapter_stop_offset = 6;
- EXPECT_EQ(BackForwardMenuModel::kMaxHistoryItems + 2 + chapter_stop_offset,
- back_model->GetItemCount());
- EXPECT_EQ(0, forward_model->GetItemCount());
- EXPECT_EQ(ASCIIToUTF16("K1"), back_model->GetLabelAt(0));
- EXPECT_EQ(back_model->GetShowFullHistoryLabel(),
- back_model->GetLabelAt(BackForwardMenuModel::kMaxHistoryItems + 1 +
- chapter_stop_offset));
-
- // Test for out of bounds (beyond Show Full History).
- EXPECT_FALSE(back_model->ItemHasCommand(
- BackForwardMenuModel::kMaxHistoryItems + chapter_stop_offset + 2));
-
- EXPECT_TRUE(back_model->ItemHasCommand(
- BackForwardMenuModel::kMaxHistoryItems - 1));
- EXPECT_TRUE(back_model->IsSeparator(
- BackForwardMenuModel::kMaxHistoryItems));
-
- NavigateToIndex(0);
-
- EXPECT_EQ(BackForwardMenuModel::kMaxHistoryItems + 2 + chapter_stop_offset,
- forward_model->GetItemCount());
- EXPECT_EQ(0, back_model->GetItemCount());
- EXPECT_EQ(ASCIIToUTF16("A2"), forward_model->GetLabelAt(0));
- EXPECT_EQ(forward_model->GetShowFullHistoryLabel(),
- forward_model->GetLabelAt(BackForwardMenuModel::kMaxHistoryItems + 1 +
- chapter_stop_offset));
-
- // Out of bounds
- EXPECT_FALSE(forward_model->ItemHasCommand(
- BackForwardMenuModel::kMaxHistoryItems + 2 + chapter_stop_offset));
-
- EXPECT_TRUE(forward_model->ItemHasCommand(
- BackForwardMenuModel::kMaxHistoryItems - 1));
- EXPECT_TRUE(forward_model->IsSeparator(
- BackForwardMenuModel::kMaxHistoryItems));
-}
-
-TEST_F(BackFwdMenuModelTest, ChapterStops) {
- scoped_ptr<BackForwardMenuModel> back_model(new BackForwardMenuModel(
- NULL, BackForwardMenuModel::BACKWARD_MENU));
- back_model->set_test_tab_contents(contents());
-
- scoped_ptr<BackForwardMenuModel> forward_model(new BackForwardMenuModel(
- NULL, BackForwardMenuModel::FORWARD_MENU));
- forward_model->set_test_tab_contents(contents());
-
- // Seed the controller with 32 URLs.
- int i = 0;
- LoadURLAndUpdateState("http://www.a.com/1", "A1");
- ValidateModel(back_model.get(), i++, 0);
- LoadURLAndUpdateState("http://www.a.com/2", "A2");
- ValidateModel(back_model.get(), i++, 0);
- LoadURLAndUpdateState("http://www.a.com/3", "A3");
- ValidateModel(back_model.get(), i++, 0);
- LoadURLAndUpdateState("http://www.b.com/1", "B1");
- ValidateModel(back_model.get(), i++, 0);
- LoadURLAndUpdateState("http://www.b.com/2", "B2");
- ValidateModel(back_model.get(), i++, 0);
- // i = 5
- LoadURLAndUpdateState("http://www.b.com/3", "B3");
- ValidateModel(back_model.get(), i++, 0);
- LoadURLAndUpdateState("http://www.c.com/1", "C1");
- ValidateModel(back_model.get(), i++, 0);
- LoadURLAndUpdateState("http://www.c.com/2", "C2");
- ValidateModel(back_model.get(), i++, 0);
- LoadURLAndUpdateState("http://www.c.com/3", "C3");
- ValidateModel(back_model.get(), i++, 0);
- LoadURLAndUpdateState("http://www.d.com/1", "D1");
- ValidateModel(back_model.get(), i++, 0);
- // i = 10
- LoadURLAndUpdateState("http://www.d.com/2", "D2");
- ValidateModel(back_model.get(), i++, 0);
- LoadURLAndUpdateState("http://www.d.com/3", "D3");
- ValidateModel(back_model.get(), i++, 0);
- LoadURLAndUpdateState("http://www.e.com/1", "E1");
- ValidateModel(back_model.get(), i++, 0);
- LoadURLAndUpdateState("http://www.e.com/2", "E2");
- ValidateModel(back_model.get(), i++, 0);
- LoadURLAndUpdateState("http://www.e.com/3", "E3");
- ValidateModel(back_model.get(), i++, 0);
- // i = 15
- LoadURLAndUpdateState("http://www.f.com/1", "F1");
- ValidateModel(back_model.get(), i++, 1);
- LoadURLAndUpdateState("http://www.f.com/2", "F2");
- ValidateModel(back_model.get(), i++, 1);
- LoadURLAndUpdateState("http://www.f.com/3", "F3");
- ValidateModel(back_model.get(), i++, 1);
- LoadURLAndUpdateState("http://www.g.com/1", "G1");
- ValidateModel(back_model.get(), i++, 2);
- LoadURLAndUpdateState("http://www.g.com/2", "G2");
- ValidateModel(back_model.get(), i++, 2);
- // i = 20
- LoadURLAndUpdateState("http://www.g.com/3", "G3");
- ValidateModel(back_model.get(), i++, 2);
- LoadURLAndUpdateState("http://www.h.com/1", "H1");
- ValidateModel(back_model.get(), i++, 3);
- LoadURLAndUpdateState("http://www.h.com/2", "H2");
- ValidateModel(back_model.get(), i++, 3);
- LoadURLAndUpdateState("http://www.h.com/3", "H3");
- ValidateModel(back_model.get(), i++, 3);
- LoadURLAndUpdateState("http://www.i.com/1", "I1");
- ValidateModel(back_model.get(), i++, 4);
- // i = 25
- LoadURLAndUpdateState("http://www.i.com/2", "I2");
- ValidateModel(back_model.get(), i++, 4);
- LoadURLAndUpdateState("http://www.i.com/3", "I3");
- ValidateModel(back_model.get(), i++, 4);
- LoadURLAndUpdateState("http://www.j.com/1", "J1");
- ValidateModel(back_model.get(), i++, 5);
- LoadURLAndUpdateState("http://www.j.com/2", "J2");
- ValidateModel(back_model.get(), i++, 5);
- LoadURLAndUpdateState("http://www.j.com/3", "J3");
- ValidateModel(back_model.get(), i++, 5);
- // i = 30
- LoadURLAndUpdateState("http://www.k.com/1", "K1");
- ValidateModel(back_model.get(), i++, 6);
- LoadURLAndUpdateState("http://www.k.com/2", "K2");
- ValidateModel(back_model.get(), i++, 6);
- // i = 32
- LoadURLAndUpdateState("http://www.k.com/3", "K3");
- ValidateModel(back_model.get(), i++, 6);
-
- // A chapter stop is defined as the last page the user
- // browsed to within the same domain.
-
- // Check to see if the chapter stops have the right labels.
- int index = BackForwardMenuModel::kMaxHistoryItems;
- // Empty string indicates item is a separator.
- EXPECT_EQ(ASCIIToUTF16(""), back_model->GetLabelAt(index++));
- EXPECT_EQ(ASCIIToUTF16("F3"), back_model->GetLabelAt(index++));
- EXPECT_EQ(ASCIIToUTF16("E3"), back_model->GetLabelAt(index++));
- EXPECT_EQ(ASCIIToUTF16("D3"), back_model->GetLabelAt(index++));
- EXPECT_EQ(ASCIIToUTF16("C3"), back_model->GetLabelAt(index++));
- // The menu should only show a maximum of 5 chapter stops.
- EXPECT_EQ(ASCIIToUTF16("B3"), back_model->GetLabelAt(index));
- // Empty string indicates item is a separator.
- EXPECT_EQ(ASCIIToUTF16(""), back_model->GetLabelAt(index + 1));
- EXPECT_EQ(back_model->GetShowFullHistoryLabel(),
- back_model->GetLabelAt(index + 2));
-
- // If we go back two we should still see the same chapter stop at the end.
- GoBack();
- EXPECT_EQ(ASCIIToUTF16("B3"), back_model->GetLabelAt(index));
- GoBack();
- EXPECT_EQ(ASCIIToUTF16("B3"), back_model->GetLabelAt(index));
- // But if we go back again, it should change.
- GoBack();
- EXPECT_EQ(ASCIIToUTF16("A3"), back_model->GetLabelAt(index));
- GoBack();
- EXPECT_EQ(ASCIIToUTF16("A3"), back_model->GetLabelAt(index));
- GoBack();
- EXPECT_EQ(ASCIIToUTF16("A3"), back_model->GetLabelAt(index));
- GoBack();
- // It is now a separator.
- EXPECT_EQ(ASCIIToUTF16(""), back_model->GetLabelAt(index));
- // Undo our position change.
- NavigateToOffset(6);
-
- // Go back enough to make sure no chapter stops should appear.
- NavigateToOffset(-BackForwardMenuModel::kMaxHistoryItems);
- ValidateModel(forward_model.get(), BackForwardMenuModel::kMaxHistoryItems, 0);
- // Go forward (still no chapter stop)
- GoForward();
- ValidateModel(forward_model.get(),
- BackForwardMenuModel::kMaxHistoryItems - 1, 0);
- // Go back two (one chapter stop should show up)
- GoBack();
- GoBack();
- ValidateModel(forward_model.get(),
- BackForwardMenuModel::kMaxHistoryItems, 1);
-
- // Go to beginning.
- NavigateToIndex(0);
-
- // Check to see if the chapter stops have the right labels.
- index = BackForwardMenuModel::kMaxHistoryItems;
- // Empty string indicates item is a separator.
- EXPECT_EQ(ASCIIToUTF16(""), forward_model->GetLabelAt(index++));
- EXPECT_EQ(ASCIIToUTF16("E3"), forward_model->GetLabelAt(index++));
- EXPECT_EQ(ASCIIToUTF16("F3"), forward_model->GetLabelAt(index++));
- EXPECT_EQ(ASCIIToUTF16("G3"), forward_model->GetLabelAt(index++));
- EXPECT_EQ(ASCIIToUTF16("H3"), forward_model->GetLabelAt(index++));
- // The menu should only show a maximum of 5 chapter stops.
- EXPECT_EQ(ASCIIToUTF16("I3"), forward_model->GetLabelAt(index));
- // Empty string indicates item is a separator.
- EXPECT_EQ(ASCIIToUTF16(""), forward_model->GetLabelAt(index + 1));
- EXPECT_EQ(forward_model->GetShowFullHistoryLabel(),
- forward_model->GetLabelAt(index + 2));
-
- // If we advance one we should still see the same chapter stop at the end.
- GoForward();
- EXPECT_EQ(ASCIIToUTF16("I3"), forward_model->GetLabelAt(index));
- // But if we advance one again, it should change.
- GoForward();
- EXPECT_EQ(ASCIIToUTF16("J3"), forward_model->GetLabelAt(index));
- GoForward();
- EXPECT_EQ(ASCIIToUTF16("J3"), forward_model->GetLabelAt(index));
- GoForward();
- EXPECT_EQ(ASCIIToUTF16("J3"), forward_model->GetLabelAt(index));
- GoForward();
- EXPECT_EQ(ASCIIToUTF16("K3"), forward_model->GetLabelAt(index));
-
- // Now test the boundary cases by using the chapter stop function directly.
- // Out of bounds, first too far right (incrementing), then too far left.
- EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(33, false));
- EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(-1, true));
- // Test being at end and going right, then at beginning going left.
- EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(32, true));
- EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(0, false));
- // Test success: beginning going right and end going left.
- EXPECT_EQ(2, back_model->GetIndexOfNextChapterStop(0, true));
- EXPECT_EQ(29, back_model->GetIndexOfNextChapterStop(32, false));
- // Now see when the chapter stops begin to show up.
- EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(1, false));
- EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(2, false));
- EXPECT_EQ(2, back_model->GetIndexOfNextChapterStop(3, false));
- // Now see when the chapter stops end.
- EXPECT_EQ(32, back_model->GetIndexOfNextChapterStop(30, true));
- EXPECT_EQ(32, back_model->GetIndexOfNextChapterStop(31, true));
- EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(32, true));
-
- // Bug found during review (two different sites, but first wasn't considered
- // a chapter-stop).
- // Go to A1;
- NavigateToIndex(0);
- LoadURLAndUpdateState("http://www.b.com/1", "B1");
- EXPECT_EQ(0, back_model->GetIndexOfNextChapterStop(1, false));
- EXPECT_EQ(1, back_model->GetIndexOfNextChapterStop(0, true));
-
- // Now see if it counts 'www.x.com' and 'mail.x.com' as same domain, which
- // it should.
- // Go to A1.
- NavigateToIndex(0);
- LoadURLAndUpdateState("http://mail.a.com/2", "A2-mai");
- LoadURLAndUpdateState("http://www.b.com/1", "B1");
- LoadURLAndUpdateState("http://mail.b.com/2", "B2-mai");
- LoadURLAndUpdateState("http://new.site.com", "new");
- EXPECT_EQ(1, back_model->GetIndexOfNextChapterStop(0, true));
- EXPECT_EQ(3, back_model->GetIndexOfNextChapterStop(1, true));
- EXPECT_EQ(3, back_model->GetIndexOfNextChapterStop(2, true));
- EXPECT_EQ(4, back_model->GetIndexOfNextChapterStop(3, true));
- // And try backwards as well.
- EXPECT_EQ(3, back_model->GetIndexOfNextChapterStop(4, false));
- EXPECT_EQ(1, back_model->GetIndexOfNextChapterStop(3, false));
- EXPECT_EQ(1, back_model->GetIndexOfNextChapterStop(2, false));
- EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(1, false));
-}
diff --git a/chrome/browser/background_application_list_model.cc b/chrome/browser/background_application_list_model.cc
index 64ccf2e..0392d09 100644
--- a/chrome/browser/background_application_list_model.cc
+++ b/chrome/browser/background_application_list_model.cc
@@ -5,20 +5,23 @@
#include "chrome/browser/background_application_list_model.h"
#include <algorithm>
+#include <set>
#include "app/l10n_util_collator.h"
#include "base/stl_util-inl.h"
#include "base/utf_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/background_mode_manager.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extension_prefs.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/image_loading_tracker.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_resource.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/pref_names.h"
class ExtensionNameComparator {
@@ -67,7 +70,7 @@ class BackgroundApplicationListModel::Application
};
namespace {
-void GetServiceApplications(ExtensionsService* service,
+void GetServiceApplications(ExtensionService* service,
ExtensionList* applications_result) {
const ExtensionList* extensions = service->extensions();
@@ -150,11 +153,11 @@ BackgroundApplicationListModel::BackgroundApplicationListModel(Profile* profile)
NotificationType::EXTENSION_UNLOADED,
Source<Profile>(profile));
registrar_.Add(this,
- NotificationType::EXTENSION_UNLOADED_DISABLED,
- Source<Profile>(profile));
- registrar_.Add(this,
NotificationType::EXTENSIONS_READY,
Source<Profile>(profile));
+ ExtensionService* service = profile->GetExtensionService();
+ if (service && service->is_ready())
+ Update();
}
void BackgroundApplicationListModel::AddObserver(Observer* observer) {
@@ -166,6 +169,13 @@ void BackgroundApplicationListModel::AssociateApplicationData(
DCHECK(IsBackgroundApp(*extension));
Application* application = FindApplication(extension);
if (!application) {
+ // App position is used as a dynamic command and so must be less than any
+ // predefined command id.
+ if (applications_.size() >= IDC_MinimumLabelValue) {
+ LOG(ERROR) << "Background application limit of " << IDC_MinimumLabelValue
+ << " exceeded. Ignoring.";
+ return;
+ }
application = new Application(this, extension);
applications_[extension->id()] = application;
application->RequestIcon(Extension::EXTENSION_ICON_BITTY);
@@ -239,7 +249,7 @@ void BackgroundApplicationListModel::Observe(
Update();
return;
}
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
if (!service || !service->is_ready())
return;
@@ -248,9 +258,7 @@ void BackgroundApplicationListModel::Observe(
OnExtensionLoaded(Details<Extension>(details).ptr());
break;
case NotificationType::EXTENSION_UNLOADED:
- // Handle extension unload uniformly, falling through to next case.
- case NotificationType::EXTENSION_UNLOADED_DISABLED:
- OnExtensionUnloaded(Details<Extension>(details).ptr());
+ OnExtensionUnloaded(Details<UnloadedExtensionInfo>(details)->extension);
break;
default:
NOTREACHED() << "Received unexpected notification";
@@ -270,7 +278,8 @@ void BackgroundApplicationListModel::OnExtensionLoaded(Extension* extension) {
Update();
}
-void BackgroundApplicationListModel::OnExtensionUnloaded(Extension* extension) {
+void BackgroundApplicationListModel::OnExtensionUnloaded(
+ const Extension* extension) {
if (!IsBackgroundApp(*extension))
return;
Update();
@@ -286,7 +295,7 @@ void BackgroundApplicationListModel::RemoveObserver(Observer* observer) {
// differs from the old list, it generates OnApplicationListChanged events for
// each observer.
void BackgroundApplicationListModel::Update() {
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
// Discover current background applications, compare with previous list, which
// is consistently sorted, and notify observers if they differ.
diff --git a/chrome/browser/background_application_list_model.h b/chrome/browser/background_application_list_model.h
index 63c356e..29bfe65 100644
--- a/chrome/browser/background_application_list_model.h
+++ b/chrome/browser/background_application_list_model.h
@@ -11,13 +11,13 @@
#include "base/basictypes.h"
#include "base/observer_list.h"
-#include "chrome/browser/profile.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-class ExtensionsService;
+class ExtensionService;
class PrefService;
+class Profile;
// Model for list of Background Applications, that is, Extensions with
// kBackgroundPermission set, associated with a Profile.
@@ -119,8 +119,8 @@ class BackgroundApplicationListModel : public NotificationObserver {
// Invoked by Observe for EXTENSION_LOADED notifications.
void OnExtensionLoaded(Extension* extension);
- // Invoked by Observe for EXTENSION_UNLOADED* notifications.
- void OnExtensionUnloaded(Extension* extension);
+ // Invoked by Observe for EXTENSION_UNLOADED notifications.
+ void OnExtensionUnloaded(const Extension* extension);
// Refresh the list of background applications and generates ApplicationAdded
// and ApplicationRemoved events.
diff --git a/chrome/browser/background_contents_service.cc b/chrome/browser/background_contents_service.cc
index 8b5a42d..df6db03 100644
--- a/chrome/browser/background_contents_service.cc
+++ b/chrome/browser/background_contents_service.cc
@@ -9,9 +9,9 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/tab_contents/tab_contents.h"
@@ -115,7 +115,8 @@ void BackgroundContentsService::Observe(NotificationType type,
break;
case NotificationType::EXTENSION_UNLOADED:
ShutdownAssociatedBackgroundContents(
- ASCIIToUTF16(Details<const Extension>(details)->id()));
+ ASCIIToUTF16(
+ Details<UnloadedExtensionInfo>(details)->extension->id()));
break;
default:
NOTREACHED();
@@ -132,7 +133,7 @@ void BackgroundContentsService::LoadBackgroundContentsFromPrefs(
prefs_->GetDictionary(prefs::kRegisteredBackgroundContents);
if (!contents)
return;
- ExtensionsService* extensions_service = profile->GetExtensionsService();
+ ExtensionService* extensions_service = profile->GetExtensionService();
DCHECK(extensions_service);
for (DictionaryValue::key_iterator it = contents->begin_keys();
it != contents->end_keys(); ++it) {
diff --git a/chrome/browser/background_mode_manager.cc b/chrome/browser/background_mode_manager.cc
index 0676628..74c0df6 100644
--- a/chrome/browser/background_mode_manager.cc
+++ b/chrome/browser/background_mode_manager.cc
@@ -6,19 +6,16 @@
#include "app/resource_bundle.h"
#include "base/base_paths.h"
#include "base/command_line.h"
-#include "base/file_path.h"
#include "base/logging.h"
-#include "base/path_service.h"
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/background_application_list_model.h"
#include "chrome/browser/background_mode_manager.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/shell_integration.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/status_icons/status_icon.h"
#include "chrome/browser/status_icons/status_tray.h"
#include "chrome/common/chrome_switches.h"
@@ -26,110 +23,10 @@
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
-#include "grit/browser_resources.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
-#if defined(OS_LINUX)
-#include <unistd.h>
-#include "base/environment.h"
-#include "base/file_util.h"
-#include "base/nix/xdg_util.h"
-#include "base/task.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/common/chrome_version_info.h"
-#endif
-
-#if defined(OS_MACOSX)
-#include "base/mac_util.h"
-#endif
-
-#if defined(TOOLKIT_GTK)
-#include "chrome/browser/gtk/gtk_util.h"
-#endif
-
-#if defined(OS_LINUX)
-static const FilePath::CharType kAutostart[] = "autostart";
-static const FilePath::CharType kConfig[] = ".config";
-static const char kXdgConfigHome[] = "XDG_CONFIG_HOME";
-#endif
-
-#if defined(OS_WIN)
-#include "base/win/registry.h"
-const HKEY kBackgroundModeRegistryRootKey = HKEY_CURRENT_USER;
-const wchar_t* kBackgroundModeRegistrySubkey =
- L"Software\\Microsoft\\Windows\\CurrentVersion\\Run";
-const wchar_t* kBackgroundModeRegistryKeyName = L"chromium";
-#endif
-
-#if defined(OS_LINUX)
-namespace {
-
-FilePath GetAutostartDirectory(base::Environment* environment) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- FilePath result =
- base::nix::GetXDGDirectory(environment, kXdgConfigHome, kConfig);
- result = result.Append(kAutostart);
- return result;
-}
-
-FilePath GetAutostartFilename(base::Environment* environment) {
- FilePath directory = GetAutostartDirectory(environment);
- return directory.Append(ShellIntegration::GetDesktopName(environment));
-}
-
-} // namespace
-
-class DisableLaunchOnStartupTask : public Task {
- public:
- virtual void Run() {
- scoped_ptr<base::Environment> environment(base::Environment::Create());
- if (!file_util::Delete(GetAutostartFilename(environment.get()), false)) {
- LOG(WARNING) << "Failed to deregister launch on login.";
- }
- }
-};
-
-// TODO(rickcam): Bug 56280: Share implementation with ShellIntegration
-class EnableLaunchOnStartupTask : public Task {
- public:
- virtual void Run() {
- scoped_ptr<base::Environment> environment(base::Environment::Create());
- scoped_ptr<chrome::VersionInfo> version_info(new chrome::VersionInfo());
- FilePath autostart_directory = GetAutostartDirectory(environment.get());
- FilePath autostart_file = GetAutostartFilename(environment.get());
- if (!file_util::DirectoryExists(autostart_directory) &&
- !file_util::CreateDirectory(autostart_directory)) {
- LOG(WARNING)
- << "Failed to register launch on login. No autostart directory.";
- return;
- }
- std::string wrapper_script;
- if (!environment->GetVar("CHROME_WRAPPER", &wrapper_script)) {
- LOG(WARNING)
- << "Failed to register launch on login. CHROME_WRAPPER not set.";
- return;
- }
- std::string autostart_file_contents =
- "[Desktop Entry]\n"
- "Type=Application\n"
- "Terminal=false\n"
- "Exec=" + wrapper_script +
- " --enable-background-mode --no-startup-window\n"
- "Name=" + version_info->Name() + "\n";
- std::string::size_type content_length = autostart_file_contents.length();
- if (file_util::WriteFile(autostart_file, autostart_file_contents.c_str(),
- content_length) !=
- static_cast<int>(content_length)) {
- LOG(WARNING) << "Failed to register launch on login. Failed to write "
- << autostart_file.value();
- file_util::Delete(GetAutostartFilename(environment.get()), false);
- }
- }
-};
-#endif // defined(OS_LINUX)
-
void BackgroundModeManager::OnApplicationDataChanged(
const Extension* extension) {
UpdateContextMenuEntryIcon(extension);
@@ -208,15 +105,6 @@ BackgroundModeManager::~BackgroundModeManager() {
EndBackgroundMode();
}
-bool BackgroundModeManager::IsLaunchOnStartupResetAllowed() {
- return profile_->GetPrefs()->GetBoolean(prefs::kLaunchOnStartupResetAllowed);
-}
-
-void BackgroundModeManager::SetLaunchOnStartupResetAllowed(bool allowed) {
- profile_->GetPrefs()->SetBoolean(prefs::kLaunchOnStartupResetAllowed,
- allowed);
-}
-
void BackgroundModeManager::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
@@ -241,7 +129,7 @@ void BackgroundModeManager::Observe(NotificationType type,
break;
case NotificationType::EXTENSION_UNLOADED:
if (BackgroundApplicationListModel::IsBackgroundApp(
- *Details<Extension>(details).ptr())) {
+ *Details<UnloadedExtensionInfo>(details)->extension)) {
OnBackgroundAppUnloaded();
}
break;
@@ -343,70 +231,6 @@ void BackgroundModeManager::OnBackgroundAppUninstalled() {
EnableLaunchOnStartup(false);
}
-void BackgroundModeManager::EnableLaunchOnStartup(bool should_launch) {
- // This functionality is only defined for default profile, currently.
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUserDataDir))
- return;
-#if defined(OS_LINUX)
- if (should_launch)
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- new EnableLaunchOnStartupTask());
- else
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- new DisableLaunchOnStartupTask());
-#elif defined(OS_MACOSX)
- if (should_launch) {
- // Return if Chrome is already a Login Item (avoid overriding user choice).
- if (mac_util::CheckLoginItemStatus(NULL))
- return;
-
- mac_util::AddToLoginItems(true); // Hide on startup.
-
- // Remember we set Login Item, not the user - so we can reset it later.
- SetLaunchOnStartupResetAllowed(true);
- } else {
- // If we didn't set Login Item, don't mess with it.
- if (!IsLaunchOnStartupResetAllowed())
- return;
- SetLaunchOnStartupResetAllowed(false);
-
- // Check if Chrome is not a login Item, or is a Login Item but w/o 'hidden'
- // flag - most likely user has modified the setting, don't override it.
- bool is_hidden = false;
- if (!mac_util::CheckLoginItemStatus(&is_hidden) || !is_hidden)
- return;
-
- mac_util::RemoveFromLoginItems();
- }
-#elif defined(OS_WIN)
- // TODO(rickcam): Bug 53597: Make RegKey mockable.
- // TODO(rickcam): Bug 53600: Use distinct registry keys per flavor+profile.
- const wchar_t* key_name = kBackgroundModeRegistryKeyName;
- base::win::RegKey read_key(kBackgroundModeRegistryRootKey,
- kBackgroundModeRegistrySubkey, KEY_READ);
- base::win::RegKey write_key(kBackgroundModeRegistryRootKey,
- kBackgroundModeRegistrySubkey, KEY_WRITE);
- if (should_launch) {
- FilePath executable;
- if (!PathService::Get(base::FILE_EXE, &executable))
- return;
- std::wstring new_value = executable.value() +
- L" --enable-background-mode --no-startup-window";
- if (read_key.ValueExists(key_name)) {
- std::wstring current_value;
- if (read_key.ReadValue(key_name, &current_value) &&
- (current_value == new_value))
- return;
- }
- if (!write_key.WriteValue(key_name, new_value.c_str()))
- LOG(WARNING) << "Failed to register launch on login.";
- } else {
- if (read_key.ValueExists(key_name) && !write_key.DeleteValue(key_name))
- LOG(WARNING) << "Failed to deregister launch on login.";
- }
-#endif
-}
-
void BackgroundModeManager::CreateStatusTrayIcon() {
// Only need status icons on windows/linux. ChromeOS doesn't allow exiting
// Chrome and Mac can use the dock icon instead.
@@ -450,35 +274,23 @@ void BackgroundModeManager::UpdateStatusTrayIconContextMenu() {
// Add About item
menu->AddItem(IDC_ABOUT, l10n_util::GetStringFUTF16(IDS_ABOUT,
l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
-
- // Add Preferences item
-#if defined(OS_CHROMEOS)
- menu->AddItemWithStringId(IDC_OPTIONS, IDS_SETTINGS);
-#elif defined(TOOLKIT_GTK)
- string16 preferences = gtk_util::GetStockPreferencesMenuLabel();
- if (!preferences.empty())
- menu->AddItem(IDC_OPTIONS, preferences);
- else
- menu->AddItemWithStringId(IDC_OPTIONS, IDS_PREFERENCES);
-#else
- menu->AddItemWithStringId(IDC_OPTIONS, IDS_OPTIONS);
-#endif
+ menu->AddItem(IDC_OPTIONS, GetPreferencesMenuLabel());
menu->AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER);
menu->AddSeparator();
- int application_position = 0;
+ int position = 0;
context_menu_application_offset_ = menu->GetItemCount();
for (ExtensionList::const_iterator cursor = applications_.begin();
cursor != applications_.end();
- ++cursor, ++application_position) {
+ ++cursor, ++position) {
const SkBitmap* icon = applications_.GetIcon(*cursor);
- int sort_position = applications_.GetPosition(*cursor);
- DCHECK(sort_position == application_position);
+ DCHECK(position == applications_.GetPosition(*cursor));
const std::string& name = (*cursor)->name();
- menu->AddItem(sort_position, ASCIIToUTF16(name));
+ menu->AddItem(position, UTF8ToUTF16(name));
if (icon)
menu->SetIcon(menu->GetItemCount() - 1, *icon);
}
- menu->AddSeparator();
+ if (applications_.size() > 0)
+ menu->AddSeparator();
menu->AddItemWithStringId(IDC_EXIT, IDS_EXIT);
context_menu_ = menu;
status_icon_->SetContextMenu(menu);
@@ -548,11 +360,6 @@ Browser* BackgroundModeManager::GetBrowserWindow() {
}
// static
-void BackgroundModeManager::RegisterUserPrefs(PrefService* prefs) {
- prefs->RegisterBooleanPref(prefs::kLaunchOnStartupResetAllowed, false);
-}
-
-// static
bool BackgroundModeManager::IsBackgroundModeEnabled(
const CommandLine* command_line) {
@@ -561,10 +368,12 @@ bool BackgroundModeManager::IsBackgroundModeEnabled(
bool background_mode_enabled =
!command_line->HasSwitch(switches::kDisableBackgroundMode) &&
!command_line->HasSwitch(switches::kDisableExtensions);
-
- // Only enable BackgroundMode if the associated flag is enabled.
+#if !(defined(OS_WIN) || defined(OS_MACOSX))
+ // BackgroundMode is enabled by default on windows and mac. On other
+ // platforms, it is enabled via about:flags.
background_mode_enabled = background_mode_enabled &&
command_line->HasSwitch(switches::kEnableBackgroundMode);
+#endif
+
return background_mode_enabled;
}
-
diff --git a/chrome/browser/background_mode_manager.h b/chrome/browser/background_mode_manager.h
index 6da40ec..9407d4a 100644
--- a/chrome/browser/background_mode_manager.h
+++ b/chrome/browser/background_mode_manager.h
@@ -44,8 +44,6 @@ class BackgroundModeManager
BackgroundModeManager(Profile* profile, CommandLine* command_line);
virtual ~BackgroundModeManager();
- static void RegisterUserPrefs(PrefService* prefs);
-
static bool IsBackgroundModeEnabled(const CommandLine* command_line);
private:
@@ -95,12 +93,6 @@ class BackgroundModeManager
// launch-on-startup is disabled if appropriate.
void OnBackgroundAppUninstalled();
- // Returns true if chrome has set "launch on startup" property for itself
- // earlier and is allowed to reset it later, reducing likelihood of
- // overriding user choices.
- bool IsLaunchOnStartupResetAllowed();
- void SetLaunchOnStartupResetAllowed(bool allowed);
-
// Called to make sure that our launch-on-startup mode is properly set.
// (virtual so we can override for tests).
virtual void EnableLaunchOnStartup(bool should_launch);
@@ -119,6 +111,10 @@ class BackgroundModeManager
// manually, or all apps have been loaded).
void EndKeepAliveForStartup();
+ // Return an appropriate name for a Preferences menu entry. Preferences is
+ // sometimes called Options or Settings.
+ string16 GetPreferencesMenuLabel();
+
// Create a status tray icon to allow the user to shutdown Chrome when running
// in background mode. Virtual to enable testing.
virtual void CreateStatusTrayIcon();
diff --git a/chrome/browser/background_mode_manager_chromeos.cc b/chrome/browser/background_mode_manager_chromeos.cc
new file mode 100644
index 0000000..8439f18
--- /dev/null
+++ b/chrome/browser/background_mode_manager_chromeos.cc
@@ -0,0 +1,16 @@
+// 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.
+
+#include "chrome/browser/background_mode_manager.h"
+
+#include "app/l10n_util.h"
+#include "grit/generated_resources.h"
+
+void BackgroundModeManager::EnableLaunchOnStartup(bool should_launch) {
+ NOTREACHED();
+}
+
+string16 BackgroundModeManager::GetPreferencesMenuLabel() {
+ return l10n_util::GetStringUTF16(IDS_SETTINGS);
+}
diff --git a/chrome/browser/background_mode_manager_linux.cc b/chrome/browser/background_mode_manager_linux.cc
new file mode 100644
index 0000000..3d998a6
--- /dev/null
+++ b/chrome/browser/background_mode_manager_linux.cc
@@ -0,0 +1,116 @@
+// 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.
+
+#include <unistd.h>
+
+#include "app/l10n_util.h"
+#include "base/command_line.h"
+#include "base/environment.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/nix/xdg_util.h"
+#include "base/task.h"
+#include "chrome/browser/background_mode_manager.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/gtk/gtk_util.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/shell_integration.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/chrome_version_info.h"
+#include "chrome/common/pref_names.h"
+#include "grit/generated_resources.h"
+
+namespace {
+
+class DisableLaunchOnStartupTask : public Task {
+ public:
+ virtual void Run();
+};
+
+class EnableLaunchOnStartupTask : public Task {
+ public:
+ virtual void Run();
+};
+
+static const FilePath::CharType kAutostart[] = "autostart";
+static const FilePath::CharType kConfig[] = ".config";
+static const char kXdgConfigHome[] = "XDG_CONFIG_HOME";
+
+FilePath GetAutostartDirectory(base::Environment* environment) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ FilePath result =
+ base::nix::GetXDGDirectory(environment, kXdgConfigHome, kConfig);
+ result = result.Append(kAutostart);
+ return result;
+}
+
+FilePath GetAutostartFilename(base::Environment* environment) {
+ FilePath directory = GetAutostartDirectory(environment);
+ return directory.Append(ShellIntegration::GetDesktopName(environment));
+}
+
+} // namespace
+
+void BackgroundModeManager::EnableLaunchOnStartup(bool should_launch) {
+ // This functionality is only defined for default profile, currently.
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUserDataDir))
+ return;
+ if (should_launch) {
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ new EnableLaunchOnStartupTask());
+ } else {
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ new DisableLaunchOnStartupTask());
+ }
+}
+
+void DisableLaunchOnStartupTask::Run() {
+ scoped_ptr<base::Environment> environment(base::Environment::Create());
+ if (!file_util::Delete(GetAutostartFilename(environment.get()), false)) {
+ NOTREACHED() << "Failed to deregister launch on login.";
+ }
+}
+
+// TODO(rickcam): Bug 56280: Share implementation with ShellIntegration
+void EnableLaunchOnStartupTask::Run() {
+ scoped_ptr<base::Environment> environment(base::Environment::Create());
+ scoped_ptr<chrome::VersionInfo> version_info(new chrome::VersionInfo());
+ FilePath autostart_directory = GetAutostartDirectory(environment.get());
+ FilePath autostart_file = GetAutostartFilename(environment.get());
+ if (!file_util::DirectoryExists(autostart_directory) &&
+ !file_util::CreateDirectory(autostart_directory)) {
+ NOTREACHED()
+ << "Failed to register launch on login. No autostart directory.";
+ return;
+ }
+ std::string wrapper_script;
+ if (!environment->GetVar("CHROME_WRAPPER", &wrapper_script)) {
+ LOG(WARNING)
+ << "Failed to register launch on login. CHROME_WRAPPER not set.";
+ return;
+ }
+ std::string autostart_file_contents =
+ "[Desktop Entry]\n"
+ "Type=Application\n"
+ "Terminal=false\n"
+ "Exec=" + wrapper_script +
+ " --enable-background-mode --no-startup-window\n"
+ "Name=" + version_info->Name() + "\n";
+ std::string::size_type content_length = autostart_file_contents.length();
+ if (file_util::WriteFile(autostart_file, autostart_file_contents.c_str(),
+ content_length) !=
+ static_cast<int>(content_length)) {
+ NOTREACHED() << "Failed to register launch on login. Failed to write "
+ << autostart_file.value();
+ file_util::Delete(GetAutostartFilename(environment.get()), false);
+ }
+}
+
+string16 BackgroundModeManager::GetPreferencesMenuLabel() {
+ string16 result = gtk_util::GetStockPreferencesMenuLabel();
+ if (!result.empty())
+ return result;
+ return l10n_util::GetStringUTF16(IDS_PREFERENCES);
+}
diff --git a/chrome/browser/background_mode_manager_mac.mm b/chrome/browser/background_mode_manager_mac.mm
new file mode 100644
index 0000000..cc6ab4b
--- /dev/null
+++ b/chrome/browser/background_mode_manager_mac.mm
@@ -0,0 +1,78 @@
+// 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.
+
+#include "app/l10n_util.h"
+#include "base/command_line.h"
+#include "base/mac_util.h"
+#include "chrome/browser/background_mode_manager.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/common/app_mode_common_mac.h"
+#include "chrome/common/chrome_switches.h"
+#include "grit/generated_resources.h"
+
+namespace {
+
+class DisableLaunchOnStartupTask : public Task {
+ public:
+ virtual void Run();
+};
+
+class EnableLaunchOnStartupTask : public Task {
+ public:
+ virtual void Run();
+};
+
+const CFStringRef kLaunchOnStartupResetAllowedPrefsKey =
+ CFSTR("LaunchOnStartupResetAllowed");
+
+void DisableLaunchOnStartupTask::Run() {
+ Boolean key_exists_and_has_valid_format; // ignored
+ if (!CFPreferencesGetAppBooleanValue(kLaunchOnStartupResetAllowedPrefsKey,
+ app_mode::kAppPrefsID,
+ &key_exists_and_has_valid_format))
+ return;
+
+ CFPreferencesSetAppValue(kLaunchOnStartupResetAllowedPrefsKey,
+ kCFBooleanFalse,
+ app_mode::kAppPrefsID);
+
+ // Check if Chrome is not a login Item, or is a Login Item but w/o 'hidden'
+ // flag - most likely user has modified the setting, don't override it.
+ bool is_hidden = false;
+ if (!mac_util::CheckLoginItemStatus(&is_hidden) || !is_hidden)
+ return;
+
+ mac_util::RemoveFromLoginItems();
+}
+
+void EnableLaunchOnStartupTask::Run() {
+ // Return if Chrome is already a Login Item (avoid overriding user choice).
+ if (mac_util::CheckLoginItemStatus(NULL))
+ return;
+
+ mac_util::AddToLoginItems(true); // Hide on startup.
+ CFPreferencesSetAppValue(kLaunchOnStartupResetAllowedPrefsKey,
+ kCFBooleanTrue,
+ app_mode::kAppPrefsID);
+}
+
+} // namespace
+
+void BackgroundModeManager::EnableLaunchOnStartup(bool should_launch) {
+ // This functionality is only defined for default profile, currently.
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUserDataDir))
+ return;
+
+ if (should_launch) {
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ new EnableLaunchOnStartupTask());
+ } else {
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ new DisableLaunchOnStartupTask());
+ }
+}
+
+string16 BackgroundModeManager::GetPreferencesMenuLabel() {
+ return l10n_util::GetStringUTF16(IDS_OPTIONS);
+}
diff --git a/chrome/browser/background_mode_manager_win.cc b/chrome/browser/background_mode_manager_win.cc
new file mode 100644
index 0000000..2f10843
--- /dev/null
+++ b/chrome/browser/background_mode_manager_win.cc
@@ -0,0 +1,85 @@
+// 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.
+
+#include "app/l10n_util.h"
+#include "base/base_paths.h"
+#include "base/command_line.h"
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/task.h"
+#include "base/win/registry.h"
+#include "chrome/browser/background_mode_manager.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/common/chrome_switches.h"
+#include "grit/generated_resources.h"
+
+namespace {
+
+class DisableLaunchOnStartupTask : public Task {
+ public:
+ virtual void Run();
+};
+
+class EnableLaunchOnStartupTask : public Task {
+ public:
+ virtual void Run();
+};
+
+const HKEY kBackgroundModeRegistryRootKey = HKEY_CURRENT_USER;
+const wchar_t* kBackgroundModeRegistrySubkey =
+ L"Software\\Microsoft\\Windows\\CurrentVersion\\Run";
+const wchar_t* kBackgroundModeRegistryKeyName = L"chromium";
+
+void DisableLaunchOnStartupTask::Run() {
+ const wchar_t* key_name = kBackgroundModeRegistryKeyName;
+ base::win::RegKey read_key(kBackgroundModeRegistryRootKey,
+ kBackgroundModeRegistrySubkey, KEY_READ);
+ base::win::RegKey write_key(kBackgroundModeRegistryRootKey,
+ kBackgroundModeRegistrySubkey, KEY_WRITE);
+ if (read_key.ValueExists(key_name) && !write_key.DeleteValue(key_name))
+ NOTREACHED() << "Failed to deregister launch on login.";
+}
+
+void EnableLaunchOnStartupTask::Run() {
+ // TODO(rickcam): Bug 53597: Make RegKey mockable.
+ // TODO(rickcam): Bug 53600: Use distinct registry keys per flavor+profile.
+ const wchar_t* key_name = kBackgroundModeRegistryKeyName;
+ base::win::RegKey read_key(kBackgroundModeRegistryRootKey,
+ kBackgroundModeRegistrySubkey, KEY_READ);
+ base::win::RegKey write_key(kBackgroundModeRegistryRootKey,
+ kBackgroundModeRegistrySubkey, KEY_WRITE);
+ FilePath executable;
+ if (!PathService::Get(base::FILE_EXE, &executable))
+ return;
+ std::wstring new_value = executable.value() + L" --no-startup-window";
+ if (read_key.ValueExists(key_name)) {
+ std::wstring current_value;
+ if (read_key.ReadValue(key_name, &current_value) &&
+ (current_value == new_value)) {
+ return;
+ }
+ }
+ if (!write_key.WriteValue(key_name, new_value.c_str()))
+ NOTREACHED() << "Failed to register launch on login.";
+}
+
+} // namespace
+
+void BackgroundModeManager::EnableLaunchOnStartup(bool should_launch) {
+ // This functionality is only defined for default profile, currently.
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUserDataDir))
+ return;
+ if (should_launch) {
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ new EnableLaunchOnStartupTask());
+ } else {
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ new DisableLaunchOnStartupTask());
+ }
+}
+
+string16 BackgroundModeManager::GetPreferencesMenuLabel() {
+ return l10n_util::GetStringUTF16(IDS_OPTIONS);
+}
diff --git a/chrome/browser/background_page_tracker.cc b/chrome/browser/background_page_tracker.cc
index 515ca75..7bc4c4f 100644
--- a/chrome/browser/background_page_tracker.cc
+++ b/chrome/browser/background_page_tracker.cc
@@ -13,10 +13,10 @@
#include "chrome/browser/background_contents_service.h"
#include "chrome/browser/background_mode_manager.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_service.h"
@@ -42,7 +42,7 @@ void BackgroundPageTracker::RegisterPrefs(PrefService* prefs) {
}
// static
-BackgroundPageTracker* BackgroundPageTracker::GetSingleton() {
+BackgroundPageTracker* BackgroundPageTracker::GetInstance() {
return Singleton<BackgroundPageTracker>::get();
}
@@ -109,8 +109,8 @@ BackgroundPageTracker::BackgroundPageTracker() {
// Check to make sure all of the extensions are loaded - once they are loaded
// we can update the list.
Profile* profile = g_browser_process->profile_manager()->GetDefaultProfile();
- if (profile->GetExtensionsService() &&
- profile->GetExtensionsService()->is_ready()) {
+ if (profile->GetExtensionService() &&
+ profile->GetExtensionService()->is_ready()) {
UpdateExtensionList();
// We do not send any change notifications here, because the object was
// just created (it doesn't seem appropriate to send a change notification
@@ -165,7 +165,7 @@ void BackgroundPageTracker::Observe(NotificationType type,
break;
}
case NotificationType::EXTENSION_UNLOADED: {
- std::string id = Details<const Extension>(details)->id();
+ std::string id = Details<UnloadedExtensionInfo>(details)->extension->id();
OnExtensionUnloaded(id);
break;
}
@@ -177,7 +177,7 @@ void BackgroundPageTracker::Observe(NotificationType type,
bool BackgroundPageTracker::UpdateExtensionList() {
// Extensions are loaded - update our list.
Profile* profile = g_browser_process->profile_manager()->GetDefaultProfile();
- ExtensionsService* extensions_service = profile->GetExtensionsService();
+ ExtensionService* extensions_service = profile->GetExtensionService();
DCHECK(extensions_service);
// We will make two passes to update the list:
diff --git a/chrome/browser/background_page_tracker.h b/chrome/browser/background_page_tracker.h
index 2b3b90c..e66c961 100644
--- a/chrome/browser/background_page_tracker.h
+++ b/chrome/browser/background_page_tracker.h
@@ -27,7 +27,7 @@ class BackgroundPageTracker : public NotificationObserver {
static void RegisterPrefs(PrefService* prefs);
// Convenience routine which gets the singleton object.
- static BackgroundPageTracker* GetSingleton();
+ static BackgroundPageTracker* GetInstance();
// Returns the number of background apps/extensions currently loaded.
int GetBackgroundPageCount();
diff --git a/chrome/browser/bookmarks/base_bookmark_model_observer.cc b/chrome/browser/bookmarks/base_bookmark_model_observer.cc
new file mode 100644
index 0000000..dfa4ba6
--- /dev/null
+++ b/chrome/browser/bookmarks/base_bookmark_model_observer.cc
@@ -0,0 +1,51 @@
+// 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.
+
+#include "chrome/browser/bookmarks/base_bookmark_model_observer.h"
+
+void BaseBookmarkModelObserver::Loaded(BookmarkModel* model) {
+}
+
+void BaseBookmarkModelObserver::BookmarkModelBeingDeleted(
+ BookmarkModel* model) {
+ BookmarkModelChanged();
+}
+
+void BaseBookmarkModelObserver::BookmarkNodeMoved(
+ BookmarkModel* model,
+ const BookmarkNode* old_parent,
+ int old_index,
+ const BookmarkNode* new_parent,
+ int new_index) {
+ BookmarkModelChanged();
+}
+
+void BaseBookmarkModelObserver::BookmarkNodeAdded(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int index) {
+ BookmarkModelChanged();
+}
+
+void BaseBookmarkModelObserver::BookmarkNodeRemoved(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int old_index,
+ const BookmarkNode* node) {
+ BookmarkModelChanged();
+}
+
+void BaseBookmarkModelObserver::BookmarkNodeChanged(BookmarkModel* model,
+ const BookmarkNode* node) {
+ BookmarkModelChanged();
+}
+
+void BaseBookmarkModelObserver::BookmarkNodeFavIconLoaded(
+ BookmarkModel* model,
+ const BookmarkNode* node) {
+}
+
+void BaseBookmarkModelObserver::BookmarkNodeChildrenReordered(
+ BookmarkModel* model,
+ const BookmarkNode* node) {
+ BookmarkModelChanged();
+}
diff --git a/chrome/browser/bookmarks/base_bookmark_model_observer.h b/chrome/browser/bookmarks/base_bookmark_model_observer.h
index 5a306aa..ff561af 100644
--- a/chrome/browser/bookmarks/base_bookmark_model_observer.h
+++ b/chrome/browser/bookmarks/base_bookmark_model_observer.h
@@ -18,40 +18,27 @@ class BaseBookmarkModelObserver : public BookmarkModelObserver {
virtual void BookmarkModelChanged() = 0;
- virtual void Loaded(BookmarkModel* model) {}
+ virtual void Loaded(BookmarkModel* model);
- virtual void BookmarkModelBeingDeleted(BookmarkModel* model) {
- BookmarkModelChanged();
- }
+ virtual void BookmarkModelBeingDeleted(BookmarkModel* model);
virtual void BookmarkNodeMoved(BookmarkModel* model,
const BookmarkNode* old_parent,
int old_index,
const BookmarkNode* new_parent,
- int new_index) {
- BookmarkModelChanged();
- }
+ int new_index);
virtual void BookmarkNodeAdded(BookmarkModel* model,
const BookmarkNode* parent,
- int index) {
- BookmarkModelChanged();
- }
+ int index);
virtual void BookmarkNodeRemoved(BookmarkModel* model,
const BookmarkNode* parent,
int old_index,
- const BookmarkNode* node) {
- BookmarkModelChanged();
- }
+ const BookmarkNode* node);
virtual void BookmarkNodeChanged(BookmarkModel* model,
- const BookmarkNode* node) {
- BookmarkModelChanged();
- }
+ const BookmarkNode* node);
virtual void BookmarkNodeFavIconLoaded(BookmarkModel* model,
- const BookmarkNode* node) {
- }
+ const BookmarkNode* node);
virtual void BookmarkNodeChildrenReordered(BookmarkModel* model,
- const BookmarkNode* node) {
- BookmarkModelChanged();
- }
+ const BookmarkNode* node);
private:
DISALLOW_COPY_AND_ASSIGN(BaseBookmarkModelObserver);
diff --git a/chrome/browser/bookmarks/bookmark_context_menu_controller.cc b/chrome/browser/bookmarks/bookmark_context_menu_controller.cc
index e177ed2..32b9d07 100644
--- a/chrome/browser/bookmarks/bookmark_context_menu_controller.cc
+++ b/chrome/browser/bookmarks/bookmark_context_menu_controller.cc
@@ -6,6 +6,7 @@
#include "app/l10n_util.h"
#include "base/compiler_specific.h"
+#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/bookmarks/bookmark_editor.h"
#include "chrome/browser/bookmarks/bookmark_folder_editor_controller.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
@@ -13,7 +14,7 @@
#include "chrome/browser/browser_list.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/page_navigator.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/pref_names.h"
@@ -48,44 +49,42 @@ BookmarkContextMenuController::~BookmarkContextMenuController() {
void BookmarkContextMenuController::BuildMenu() {
if (selection_.size() == 1 && selection_[0]->is_url()) {
- AddItem(IDS_BOOMARK_BAR_OPEN_ALL,
+ AddItem(IDC_BOOKMARK_BAR_OPEN_ALL,
IDS_BOOMARK_BAR_OPEN_IN_NEW_TAB);
- AddItem(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW,
+ AddItem(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW,
IDS_BOOMARK_BAR_OPEN_IN_NEW_WINDOW);
- AddItem(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO,
+ AddItem(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO,
IDS_BOOMARK_BAR_OPEN_INCOGNITO);
} else {
- AddItem(IDS_BOOMARK_BAR_OPEN_ALL);
- AddItem(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW);
- AddItem(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO);
+ AddItem(IDC_BOOKMARK_BAR_OPEN_ALL, IDS_BOOMARK_BAR_OPEN_ALL);
+ AddItem(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW,
+ IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW);
+ AddItem(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO,
+ IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO);
}
AddSeparator();
if (selection_.size() == 1 && selection_[0]->is_folder()) {
- AddItem(IDS_BOOKMARK_BAR_RENAME_FOLDER);
+ AddItem(IDC_BOOKMARK_BAR_RENAME_FOLDER, IDS_BOOKMARK_BAR_RENAME_FOLDER);
} else {
- AddItem(IDS_BOOKMARK_BAR_EDIT);
+ AddItem(IDC_BOOKMARK_BAR_EDIT, IDS_BOOKMARK_BAR_EDIT);
}
AddSeparator();
- AddItem(IDS_CUT);
- AddItem(IDS_COPY);
- AddItem(IDS_PASTE);
+ AddItem(IDC_CUT, IDS_CUT);
+ AddItem(IDC_COPY, IDS_COPY);
+ AddItem(IDC_PASTE, IDS_PASTE);
AddSeparator();
- AddItem(IDS_BOOKMARK_BAR_REMOVE);
+ AddItem(IDC_BOOKMARK_BAR_REMOVE, IDS_BOOKMARK_BAR_REMOVE);
AddSeparator();
- AddItem(IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK);
- AddItem(IDS_BOOMARK_BAR_NEW_FOLDER);
+ AddItem(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK, IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK);
+ AddItem(IDC_BOOKMARK_BAR_NEW_FOLDER, IDS_BOOMARK_BAR_NEW_FOLDER);
AddSeparator();
- AddItem(IDS_BOOKMARK_MANAGER);
- AddCheckboxItem(IDS_BOOMARK_BAR_ALWAYS_SHOW);
-}
-
-void BookmarkContextMenuController::AddItem(int id) {
- menu_model_->AddItem(id, l10n_util::GetStringUTF16(id));
+ AddItem(IDC_BOOKMARK_MANAGER, IDS_BOOKMARK_MANAGER);
+ AddCheckboxItem(IDC_BOOKMARK_BAR_ALWAYS_SHOW, IDS_BOOMARK_BAR_ALWAYS_SHOW);
}
void BookmarkContextMenuController::AddItem(int id, int localization_id) {
@@ -96,8 +95,9 @@ void BookmarkContextMenuController::AddSeparator() {
menu_model_->AddSeparator();
}
-void BookmarkContextMenuController::AddCheckboxItem(int id) {
- menu_model_->AddCheckItemWithStringId(id, id);
+void BookmarkContextMenuController::AddCheckboxItem(int id,
+ int localization_id) {
+ menu_model_->AddCheckItemWithStringId(id, localization_id);
}
void BookmarkContextMenuController::ExecuteCommand(int id) {
@@ -105,16 +105,16 @@ void BookmarkContextMenuController::ExecuteCommand(int id) {
delegate_->WillExecuteCommand();
switch (id) {
- case IDS_BOOMARK_BAR_OPEN_ALL:
- case IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO:
- case IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW: {
+ case IDC_BOOKMARK_BAR_OPEN_ALL:
+ case IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO:
+ case IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW: {
WindowOpenDisposition initial_disposition;
- if (id == IDS_BOOMARK_BAR_OPEN_ALL) {
+ if (id == IDC_BOOKMARK_BAR_OPEN_ALL) {
initial_disposition = NEW_FOREGROUND_TAB;
UserMetrics::RecordAction(
UserMetricsAction("BookmarkBar_ContextMenu_OpenAll"),
profile_);
- } else if (id == IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW) {
+ } else if (id == IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW) {
initial_disposition = NEW_WINDOW;
UserMetrics::RecordAction(
UserMetricsAction("BookmarkBar_ContextMenu_OpenAllInNewWindow"),
@@ -130,8 +130,8 @@ void BookmarkContextMenuController::ExecuteCommand(int id) {
break;
}
- case IDS_BOOKMARK_BAR_RENAME_FOLDER:
- case IDS_BOOKMARK_BAR_EDIT:
+ case IDC_BOOKMARK_BAR_RENAME_FOLDER:
+ case IDC_BOOKMARK_BAR_EDIT:
UserMetrics::RecordAction(
UserMetricsAction("BookmarkBar_ContextMenu_Edit"),
profile_);
@@ -152,7 +152,7 @@ void BookmarkContextMenuController::ExecuteCommand(int id) {
}
break;
- case IDS_BOOKMARK_BAR_REMOVE: {
+ case IDC_BOOKMARK_BAR_REMOVE: {
UserMetrics::RecordAction(
UserMetricsAction("BookmarkBar_ContextMenu_Remove"),
profile_);
@@ -165,7 +165,7 @@ void BookmarkContextMenuController::ExecuteCommand(int id) {
break;
}
- case IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK: {
+ case IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK: {
UserMetrics::RecordAction(
UserMetricsAction("BookmarkBar_ContextMenu_Add"),
profile_);
@@ -178,7 +178,7 @@ void BookmarkContextMenuController::ExecuteCommand(int id) {
break;
}
- case IDS_BOOMARK_BAR_NEW_FOLDER: {
+ case IDC_BOOKMARK_BAR_NEW_FOLDER: {
UserMetrics::RecordAction(
UserMetricsAction("BookmarkBar_ContextMenu_NewFolder"),
profile_);
@@ -190,11 +190,11 @@ void BookmarkContextMenuController::ExecuteCommand(int id) {
break;
}
- case IDS_BOOMARK_BAR_ALWAYS_SHOW:
+ case IDC_BOOKMARK_BAR_ALWAYS_SHOW:
bookmark_utils::ToggleWhenVisible(profile_);
break;
- case IDS_BOOKMARK_MANAGER:
+ case IDC_BOOKMARK_MANAGER:
UserMetrics::RecordAction(UserMetricsAction("ShowBookmarkManager"),
profile_);
{
@@ -206,15 +206,15 @@ void BookmarkContextMenuController::ExecuteCommand(int id) {
}
break;
- case IDS_CUT:
+ case IDC_CUT:
bookmark_utils::CopyToClipboard(model_, selection_, true);
break;
- case IDS_COPY:
+ case IDC_COPY:
bookmark_utils::CopyToClipboard(model_, selection_, false);
break;
- case IDS_PASTE: {
+ case IDC_PASTE: {
int index;
const BookmarkNode* paste_target =
bookmark_utils::GetParentForNewNodes(parent_, selection_, &index);
@@ -234,7 +234,7 @@ void BookmarkContextMenuController::ExecuteCommand(int id) {
}
bool BookmarkContextMenuController::IsCommandIdChecked(int command_id) const {
- DCHECK(command_id == IDS_BOOMARK_BAR_ALWAYS_SHOW);
+ DCHECK(command_id == IDC_BOOKMARK_BAR_ALWAYS_SHOW);
return profile_->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar);
}
@@ -243,33 +243,33 @@ bool BookmarkContextMenuController::IsCommandIdEnabled(int command_id) const {
(selection_.size() == 1 &&
selection_[0]->GetParent() == model_->root_node());
switch (command_id) {
- case IDS_BOOMARK_BAR_OPEN_INCOGNITO:
+ case IDC_BOOKMARK_BAR_OPEN_INCOGNITO:
return !profile_->IsOffTheRecord();
- case IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO:
+ case IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO:
return HasURLs() && !profile_->IsOffTheRecord();
- case IDS_BOOMARK_BAR_OPEN_ALL:
- case IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW:
+ case IDC_BOOKMARK_BAR_OPEN_ALL:
+ case IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW:
return HasURLs();
- case IDS_BOOKMARK_BAR_RENAME_FOLDER:
- case IDS_BOOKMARK_BAR_EDIT:
+ case IDC_BOOKMARK_BAR_RENAME_FOLDER:
+ case IDC_BOOKMARK_BAR_EDIT:
return selection_.size() == 1 && !is_root_node;
- case IDS_BOOKMARK_BAR_REMOVE:
+ case IDC_BOOKMARK_BAR_REMOVE:
return !selection_.empty() && !is_root_node;
- case IDS_BOOMARK_BAR_NEW_FOLDER:
- case IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK:
+ case IDC_BOOKMARK_BAR_NEW_FOLDER:
+ case IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK:
return bookmark_utils::GetParentForNewNodes(
parent_, selection_, NULL) != NULL;
- case IDS_COPY:
- case IDS_CUT:
+ case IDC_COPY:
+ case IDC_CUT:
return selection_.size() > 0 && !is_root_node;
- case IDS_PASTE:
+ case IDC_PASTE:
// Paste to selection from the Bookmark Bar, to parent_ everywhere else
return (!selection_.empty() &&
bookmark_utils::CanPasteFromClipboard(selection_[0])) ||
@@ -278,6 +278,12 @@ bool BookmarkContextMenuController::IsCommandIdEnabled(int command_id) const {
return true;
}
+bool BookmarkContextMenuController::GetAcceleratorForCommandId(
+ int command_id,
+ menus::Accelerator* accelerator) {
+ return false;
+}
+
void BookmarkContextMenuController::BookmarkModelChanged() {
if (delegate_)
delegate_->CloseMenu();
diff --git a/chrome/browser/bookmarks/bookmark_context_menu_controller.h b/chrome/browser/bookmarks/bookmark_context_menu_controller.h
index 76ffaa4..f5f04af 100644
--- a/chrome/browser/bookmarks/bookmark_context_menu_controller.h
+++ b/chrome/browser/bookmarks/bookmark_context_menu_controller.h
@@ -60,9 +60,7 @@ class BookmarkContextMenuController : public BaseBookmarkModelObserver,
virtual bool IsCommandIdChecked(int command_id) const;
virtual bool IsCommandIdEnabled(int command_id) const;
virtual bool GetAcceleratorForCommandId(int command_id,
- menus::Accelerator* accelerator) {
- return false;
- }
+ menus::Accelerator* accelerator);
virtual void ExecuteCommand(int command_id);
// Accessors:
@@ -70,14 +68,12 @@ class BookmarkContextMenuController : public BaseBookmarkModelObserver,
PageNavigator* navigator() const { return navigator_; }
private:
- // Adds a IDS_* style command to the menu.
- void AddItem(int id);
- // Adds a IDS_* style command to the menu with a different localized string.
+ // Adds a IDC_* style command to the menu with a localized string.
void AddItem(int id, int localization_id);
// Adds a separator to the menu.
void AddSeparator();
// Adds a checkable item to the menu.
- void AddCheckboxItem(int id);
+ void AddCheckboxItem(int id, int localization_id);
// Overridden from BaseBookmarkModelObserver:
// Any change to the model results in closing the menu.
diff --git a/chrome/browser/bookmarks/bookmark_context_menu_controller_unittest.cc b/chrome/browser/bookmarks/bookmark_context_menu_controller_unittest.cc
index e7293f1..311237f 100644
--- a/chrome/browser/bookmarks/bookmark_context_menu_controller_unittest.cc
+++ b/chrome/browser/bookmarks/bookmark_context_menu_controller_unittest.cc
@@ -4,12 +4,13 @@
#include "base/scoped_ptr.h"
#include "base/utf_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/bookmarks/bookmark_context_menu_controller.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/page_navigator.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_profile.h"
@@ -109,9 +110,9 @@ TEST_F(BookmarkContextMenuControllerTest, DeleteURL) {
BookmarkContextMenuController controller(
NULL, NULL, profile_.get(), NULL, nodes[0]->GetParent(), nodes);
GURL url = model_->GetBookmarkBarNode()->GetChild(0)->GetURL();
- ASSERT_TRUE(controller.IsCommandIdEnabled(IDS_BOOKMARK_BAR_REMOVE));
+ ASSERT_TRUE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_REMOVE));
// Delete the URL.
- controller.ExecuteCommand(IDS_BOOKMARK_BAR_REMOVE);
+ controller.ExecuteCommand(IDC_BOOKMARK_BAR_REMOVE);
// Model shouldn't have URL anymore.
ASSERT_FALSE(model_->IsBookmarked(url));
}
@@ -134,16 +135,16 @@ TEST_F(BookmarkContextMenuControllerTest, EmptyNodes) {
BookmarkContextMenuController controller(
NULL, NULL, profile_.get(), NULL, model_->other_node(),
std::vector<const BookmarkNode*>());
- EXPECT_FALSE(controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_OPEN_ALL));
+ EXPECT_FALSE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
EXPECT_FALSE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
EXPECT_FALSE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO));
- EXPECT_FALSE(controller.IsCommandIdEnabled(IDS_BOOKMARK_BAR_REMOVE));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
+ EXPECT_FALSE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_REMOVE));
EXPECT_TRUE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
EXPECT_TRUE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_NEW_FOLDER));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
}
// Tests the enabled state of the menus when supplied a vector with a single
@@ -153,16 +154,16 @@ TEST_F(BookmarkContextMenuControllerTest, SingleURL) {
nodes.push_back(model_->GetBookmarkBarNode()->GetChild(0));
BookmarkContextMenuController controller(
NULL, NULL, profile_.get(), NULL, nodes[0]->GetParent(), nodes);
- EXPECT_TRUE(controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_OPEN_ALL));
+ EXPECT_TRUE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
EXPECT_TRUE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
EXPECT_TRUE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO));
- EXPECT_TRUE(controller.IsCommandIdEnabled(IDS_BOOKMARK_BAR_REMOVE));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
+ EXPECT_TRUE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_REMOVE));
EXPECT_TRUE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
EXPECT_TRUE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_NEW_FOLDER));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
}
// Tests the enabled state of the menus when supplied a vector with multiple
@@ -173,16 +174,16 @@ TEST_F(BookmarkContextMenuControllerTest, MultipleURLs) {
nodes.push_back(model_->GetBookmarkBarNode()->GetChild(1)->GetChild(0));
BookmarkContextMenuController controller(
NULL, NULL, profile_.get(), NULL, nodes[0]->GetParent(), nodes);
- EXPECT_TRUE(controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_OPEN_ALL));
+ EXPECT_TRUE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
EXPECT_TRUE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
EXPECT_TRUE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO));
- EXPECT_TRUE(controller.IsCommandIdEnabled(IDS_BOOKMARK_BAR_REMOVE));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
+ EXPECT_TRUE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_REMOVE));
EXPECT_TRUE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
EXPECT_TRUE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_NEW_FOLDER));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
}
// Tests the enabled state of the menus when supplied an vector with a single
@@ -192,16 +193,16 @@ TEST_F(BookmarkContextMenuControllerTest, SingleFolder) {
nodes.push_back(model_->GetBookmarkBarNode()->GetChild(2));
BookmarkContextMenuController controller(
NULL, NULL, profile_.get(), NULL, nodes[0]->GetParent(), nodes);
- EXPECT_FALSE(controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_OPEN_ALL));
+ EXPECT_FALSE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
EXPECT_FALSE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
EXPECT_FALSE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO));
- EXPECT_TRUE(controller.IsCommandIdEnabled(IDS_BOOKMARK_BAR_REMOVE));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
+ EXPECT_TRUE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_REMOVE));
EXPECT_TRUE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
EXPECT_TRUE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_NEW_FOLDER));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
}
// Tests the enabled state of the menus when supplied a vector with multiple
@@ -212,16 +213,16 @@ TEST_F(BookmarkContextMenuControllerTest, MultipleEmptyFolders) {
nodes.push_back(model_->GetBookmarkBarNode()->GetChild(3));
BookmarkContextMenuController controller(
NULL, NULL, profile_.get(), NULL, nodes[0]->GetParent(), nodes);
- EXPECT_FALSE(controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_OPEN_ALL));
+ EXPECT_FALSE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
EXPECT_FALSE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
EXPECT_FALSE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO));
- EXPECT_TRUE(controller.IsCommandIdEnabled(IDS_BOOKMARK_BAR_REMOVE));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
+ EXPECT_TRUE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_REMOVE));
EXPECT_TRUE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
EXPECT_TRUE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_NEW_FOLDER));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
}
// Tests the enabled state of the menus when supplied a vector with multiple
@@ -232,16 +233,16 @@ TEST_F(BookmarkContextMenuControllerTest, MultipleFoldersWithURLs) {
nodes.push_back(model_->GetBookmarkBarNode()->GetChild(4));
BookmarkContextMenuController controller(
NULL, NULL, profile_.get(), NULL, nodes[0]->GetParent(), nodes);
- EXPECT_TRUE(controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_OPEN_ALL));
+ EXPECT_TRUE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
EXPECT_TRUE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
EXPECT_TRUE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO));
- EXPECT_TRUE(controller.IsCommandIdEnabled(IDS_BOOKMARK_BAR_REMOVE));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
+ EXPECT_TRUE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_REMOVE));
EXPECT_TRUE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
EXPECT_TRUE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_NEW_FOLDER));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
}
// Tests the enabled state of open incognito.
@@ -251,9 +252,9 @@ TEST_F(BookmarkContextMenuControllerTest, DisableIncognito) {
BookmarkContextMenuController controller(
NULL, NULL, profile_.get(), NULL, nodes[0]->GetParent(), nodes);
profile_->set_off_the_record(true);
- EXPECT_FALSE(controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_OPEN_INCOGNITO));
+ EXPECT_FALSE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_INCOGNITO));
EXPECT_FALSE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
}
// Tests that you can't remove/edit when showing the other node.
@@ -262,8 +263,8 @@ TEST_F(BookmarkContextMenuControllerTest, DisabledItemsWithOtherNode) {
nodes.push_back(model_->other_node());
BookmarkContextMenuController controller(
NULL, NULL, profile_.get(), NULL, nodes[0], nodes);
- EXPECT_FALSE(controller.IsCommandIdEnabled(IDS_BOOKMARK_BAR_EDIT));
- EXPECT_FALSE(controller.IsCommandIdEnabled(IDS_BOOKMARK_BAR_REMOVE));
+ EXPECT_FALSE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_EDIT));
+ EXPECT_FALSE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_REMOVE));
}
// Tests the enabled state of the menus when supplied an empty vector and null
@@ -272,16 +273,16 @@ TEST_F(BookmarkContextMenuControllerTest, EmptyNodesNullParent) {
BookmarkContextMenuController controller(
NULL, NULL, profile_.get(), NULL, NULL,
std::vector<const BookmarkNode*>());
- EXPECT_FALSE(controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_OPEN_ALL));
+ EXPECT_FALSE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
EXPECT_FALSE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
EXPECT_FALSE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO));
- EXPECT_FALSE(controller.IsCommandIdEnabled(IDS_BOOKMARK_BAR_REMOVE));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
+ EXPECT_FALSE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_REMOVE));
EXPECT_FALSE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
EXPECT_FALSE(
- controller.IsCommandIdEnabled(IDS_BOOMARK_BAR_NEW_FOLDER));
+ controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
}
TEST_F(BookmarkContextMenuControllerTest, CutCopyPasteNode) {
@@ -290,16 +291,16 @@ TEST_F(BookmarkContextMenuControllerTest, CutCopyPasteNode) {
scoped_ptr<BookmarkContextMenuController> controller(
new BookmarkContextMenuController(
NULL, NULL, profile_.get(), NULL, nodes[0]->GetParent(), nodes));
- EXPECT_TRUE(controller->IsCommandIdEnabled(IDS_COPY));
- EXPECT_TRUE(controller->IsCommandIdEnabled(IDS_CUT));
+ EXPECT_TRUE(controller->IsCommandIdEnabled(IDC_COPY));
+ EXPECT_TRUE(controller->IsCommandIdEnabled(IDC_CUT));
// Copy the URL.
- controller->ExecuteCommand(IDS_COPY);
+ controller->ExecuteCommand(IDC_COPY);
controller.reset(new BookmarkContextMenuController(
NULL, NULL, profile_.get(), NULL, nodes[0]->GetParent(), nodes));
int old_count = model_->GetBookmarkBarNode()->GetChildCount();
- controller->ExecuteCommand(IDS_PASTE);
+ controller->ExecuteCommand(IDC_PASTE);
ASSERT_TRUE(model_->GetBookmarkBarNode()->GetChild(1)->is_url());
ASSERT_EQ(old_count + 1, model_->GetBookmarkBarNode()->GetChildCount());
@@ -309,7 +310,7 @@ TEST_F(BookmarkContextMenuControllerTest, CutCopyPasteNode) {
controller.reset(new BookmarkContextMenuController(
NULL, NULL, profile_.get(), NULL, nodes[0]->GetParent(), nodes));
// Cut the URL.
- controller->ExecuteCommand(IDS_CUT);
+ controller->ExecuteCommand(IDC_CUT);
ASSERT_TRUE(model_->GetBookmarkBarNode()->GetChild(0)->is_url());
ASSERT_TRUE(model_->GetBookmarkBarNode()->GetChild(1)->is_folder());
ASSERT_EQ(old_count, model_->GetBookmarkBarNode()->GetChildCount());
diff --git a/chrome/browser/bookmarks/bookmark_folder_editor_controller.cc b/chrome/browser/bookmarks/bookmark_folder_editor_controller.cc
index ab545b4..a995c63 100644
--- a/chrome/browser/bookmarks/bookmark_folder_editor_controller.cc
+++ b/chrome/browser/bookmarks/bookmark_folder_editor_controller.cc
@@ -8,7 +8,7 @@
#include "base/string16.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "grit/generated_resources.h"
BookmarkFolderEditorController::~BookmarkFolderEditorController() {
diff --git a/chrome/browser/bookmarks/bookmark_folder_editor_controller.h b/chrome/browser/bookmarks/bookmark_folder_editor_controller.h
index 9ab3c6d..fde7c68 100644
--- a/chrome/browser/bookmarks/bookmark_folder_editor_controller.h
+++ b/chrome/browser/bookmarks/bookmark_folder_editor_controller.h
@@ -8,7 +8,7 @@
#include "base/basictypes.h"
#include "chrome/browser/bookmarks/base_bookmark_model_observer.h"
-#include "chrome/browser/input_window_dialog.h"
+#include "chrome/browser/ui/input_window_dialog.h"
#include "gfx/native_widget_types.h"
class Profile;
diff --git a/chrome/browser/bookmarks/bookmark_html_writer.cc b/chrome/browser/bookmarks/bookmark_html_writer.cc
index 38899bf..5095158 100644
--- a/chrome/browser/bookmarks/bookmark_html_writer.cc
+++ b/chrome/browser/bookmarks/bookmark_html_writer.cc
@@ -18,8 +18,7 @@
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/history/history_types.h"
-#include "chrome/browser/profile.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/notification_source.h"
#include "grit/generated_resources.h"
#include "net/base/escape.h"
diff --git a/chrome/browser/bookmarks/bookmark_html_writer_unittest.cc b/chrome/browser/bookmarks/bookmark_html_writer_unittest.cc
index 2394f76..3a0bcbf 100644
--- a/chrome/browser/bookmarks/bookmark_html_writer_unittest.cc
+++ b/chrome/browser/bookmarks/bookmark_html_writer_unittest.cc
@@ -75,8 +75,7 @@ class BookmarkHTMLWriterTest : public testing::Test {
result.append(WideToUTF16Hack(entry.title));
result.append(ASCIIToUTF16(" time="));
- result.append(WideToUTF16Hack(
- base::TimeFormatFriendlyDateAndTime(entry.creation_time)));
+ result.append(base::TimeFormatFriendlyDateAndTime(entry.creation_time));
return result;
}
diff --git a/chrome/browser/bookmarks/bookmark_index.cc b/chrome/browser/bookmarks/bookmark_index.cc
index b1c1ab3..c75c5fe 100644
--- a/chrome/browser/bookmarks/bookmark_index.cc
+++ b/chrome/browser/bookmarks/bookmark_index.cc
@@ -14,7 +14,7 @@
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/history/history_database.h"
#include "chrome/browser/history/query_parser.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
// Used when finding the set of bookmarks that match a query. Each match
// represents a set of terms (as an interator into the Index) matching the
diff --git a/chrome/browser/bookmarks/bookmark_model.cc b/chrome/browser/bookmarks/bookmark_model.cc
index c9b3da7..848527a 100644
--- a/chrome/browser/bookmarks/bookmark_model.cc
+++ b/chrome/browser/bookmarks/bookmark_model.cc
@@ -15,7 +15,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/history/history_notifications.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/notification_service.h"
#include "gfx/codec/png_codec.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/bookmarks/bookmark_model_unittest.cc b/chrome/browser/bookmarks/bookmark_model_unittest.cc
index 6d6017a..ef486fb 100644
--- a/chrome/browser/bookmarks/bookmark_model_unittest.cc
+++ b/chrome/browser/bookmarks/bookmark_model_unittest.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 <string>
#include <set>
#include "app/tree_node_iterator.h"
@@ -22,8 +23,9 @@
#include "chrome/browser/history/history_notifications.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
+#include "chrome/common/notification_details.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
#include "chrome/test/model_test_utils.h"
#include "chrome/test/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/bookmarks/bookmark_node_data.cc b/chrome/browser/bookmarks/bookmark_node_data.cc
index a31f7aa..27e8683 100644
--- a/chrome/browser/bookmarks/bookmark_node_data.cc
+++ b/chrome/browser/bookmarks/bookmark_node_data.cc
@@ -4,19 +4,23 @@
#include "chrome/browser/bookmarks/bookmark_node_data.h"
+#include <string>
+
#include "app/clipboard/scoped_clipboard_writer.h"
#include "base/basictypes.h"
#include "base/pickle.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/url_constants.h"
+#include "net/base/escape.h"
+
#if defined(OS_MACOSX)
#include "chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.h"
-#endif
-#include "chrome/browser/profile.h"
-#include "chrome/common/url_constants.h"
+#else
#include "chrome/browser/browser_process.h"
-#include "net/base/escape.h"
+#endif
const char* BookmarkNodeData::kClipboardFormatString =
"chromium/x-bookmark-entries";
diff --git a/chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.mm b/chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.mm
index 9248964..25b8fca 100644
--- a/chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.mm
+++ b/chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.mm
@@ -8,7 +8,7 @@
#include "base/sys_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
-#include "chrome/browser/cocoa/bookmarks/bookmark_drag_source.h"
+#include "chrome/browser/ui/cocoa/bookmarks/bookmark_drag_source.h"
#include "chrome/browser/tab_contents/tab_contents_view_mac.h"
NSString* const kBookmarkDictionaryListPboardType =
diff --git a/chrome/browser/bookmarks/bookmark_storage.cc b/chrome/browser/bookmarks/bookmark_storage.cc
index ee50a71..a501baa 100644
--- a/chrome/browser/bookmarks/bookmark_storage.cc
+++ b/chrome/browser/bookmarks/bookmark_storage.cc
@@ -12,7 +12,7 @@
#include "chrome/browser/bookmarks/bookmark_codec.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/json_value_serializer.h"
#include "chrome/common/notification_source.h"
diff --git a/chrome/browser/bookmarks/bookmark_storage.h b/chrome/browser/bookmarks/bookmark_storage.h
index 541b063..0bcb137 100644
--- a/chrome/browser/bookmarks/bookmark_storage.h
+++ b/chrome/browser/bookmarks/bookmark_storage.h
@@ -129,8 +129,9 @@ class BookmarkStorage : public NotificationObserver,
void FinishHistoryMigration();
// NotificationObserver
- void Observe(NotificationType type, const NotificationSource& source,
- const NotificationDetails& details);
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
// Serializes the data and schedules save using ImportantFileWriter.
// Returns true on successful serialization.
diff --git a/chrome/browser/bookmarks/bookmark_utils.cc b/chrome/browser/bookmarks/bookmark_utils.cc
index fccbbb9..55acbbe 100644
--- a/chrome/browser/bookmarks/bookmark_utils.cc
+++ b/chrome/browser/bookmarks/bookmark_utils.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/bookmarks/bookmark_utils.h"
+#include <utility>
+
#include "app/drag_drop_types.h"
#include "app/l10n_util.h"
#include "app/tree_node_iterator.h"
@@ -19,12 +21,11 @@
#include "chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.h"
#endif
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/history/query_parser.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/page_navigator.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
diff --git a/chrome/browser/bookmarks/bookmark_utils_unittest.cc b/chrome/browser/bookmarks/bookmark_utils_unittest.cc
index f27ef8b..9de3b66 100644
--- a/chrome/browser/bookmarks/bookmark_utils_unittest.cc
+++ b/chrome/browser/bookmarks/bookmark_utils_unittest.cc
@@ -8,10 +8,13 @@
#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
+#if !defined(OS_MACOSX)
+#include "chrome/browser/browser_process.h"
+#endif
+
typedef testing::Test BookmarkUtilsTest;
TEST_F(BookmarkUtilsTest, GetBookmarksContainingText) {
@@ -127,4 +130,3 @@ TEST_F(BookmarkUtilsTest, CopyPaste) {
bookmark_utils::CanPasteFromClipboard(model.GetBookmarkBarNode()));
}
#endif
-
diff --git a/chrome/browser/browser_about_handler.cc b/chrome/browser/browser_about_handler.cc
index ba97478..715f460 100644
--- a/chrome/browser/browser_about_handler.cc
+++ b/chrome/browser/browser_about_handler.cc
@@ -17,6 +17,7 @@
#include "base/metrics/stats_table.h"
#include "base/path_service.h"
#include "base/platform_thread.h"
+#include "base/singleton.h"
#include "base/stringprintf.h"
#include "base/string_number_conversions.h"
#include "base/string_piece.h"
@@ -36,8 +37,8 @@
#include "chrome/browser/net/predictor_api.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/sync/profile_sync_service.h"
@@ -73,7 +74,7 @@
#include "chrome/browser/chromeos/version_loader.h"
#include "chrome/browser/zygote_host_linux.h"
#elif defined(OS_MACOSX)
-#include "chrome/browser/cocoa/about_ipc_dialog.h"
+#include "chrome/browser/ui/cocoa/about_ipc_dialog.h"
#elif defined(OS_LINUX)
#include "chrome/browser/zygote_host_linux.h"
#endif
@@ -88,9 +89,14 @@ using base::Time;
using base::TimeDelta;
#if defined(USE_TCMALLOC)
+// static
+AboutTcmallocOutputs* AboutTcmallocOutputs::GetInstance() {
+ return Singleton<AboutTcmallocOutputs>::get();
+}
+
// Glue between the callback task and the method in the singleton.
void AboutTcmallocRendererCallback(base::ProcessId pid, std::string output) {
- Singleton<AboutTcmallocOutputs>::get()->RendererCallback(pid, output);
+ AboutTcmallocOutputs::GetInstance()->RendererCallback(pid, output);
}
#endif
@@ -155,7 +161,6 @@ const char *kAllAboutPaths[] = {
kTermsPath,
kVersionPath,
#if defined(OS_LINUX)
- kLinuxProxyConfigPath,
kSandboxPath,
#endif
#if defined(OS_CHROMEOS)
@@ -274,6 +279,7 @@ std::string AboutAbout() {
kAllAboutPaths[i] == kConflictsPath ||
#endif
kAllAboutPaths[i] == kFlagsPath ||
+ kAllAboutPaths[i] == kGpuPath ||
kAllAboutPaths[i] == kNetInternalsPath ||
kAllAboutPaths[i] == kPluginsPath) {
html.append("<li><a href='chrome://");
@@ -364,7 +370,7 @@ class AboutDnsHandler : public base::RefCountedThreadSafe<AboutDnsHandler> {
std::string AboutTcmalloc(const std::string& query) {
std::string data;
AboutTcmallocOutputsType* outputs =
- Singleton<AboutTcmallocOutputs>::get()->outputs();
+ AboutTcmallocOutputs::GetInstance()->outputs();
// Display any stats for which we sent off requests the last time.
data.append("<html><head><title>About tcmalloc</title></head><body>\n");
@@ -392,7 +398,7 @@ std::string AboutTcmalloc(const std::string& query) {
char buffer[1024 * 32];
MallocExtension::instance()->GetStats(buffer, sizeof(buffer));
std::string browser("Browser");
- Singleton<AboutTcmallocOutputs>::get()->SetOutput(browser, buffer);
+ AboutTcmallocOutputs::GetInstance()->SetOutput(browser, buffer);
RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
while (!it.IsAtEnd()) {
it.GetCurrentValue()->Send(new ViewMsg_GetRendererTcmalloc);
@@ -590,7 +596,7 @@ std::string AboutSandbox() {
data.append(l10n_util::GetStringUTF8(IDS_ABOUT_SANDBOX_TITLE));
data.append("</h1>");
- const int status = Singleton<ZygoteHost>()->sandbox_status();
+ const int status = ZygoteHost::GetInstance()->sandbox_status();
data.append("<table>");
@@ -715,110 +721,6 @@ std::string VersionNumberToString(uint32 value) {
return base::IntToString(hi) + "." + base::IntToString(low);
}
-namespace {
-
-#if defined(OS_WIN)
-
-// Output DxDiagNode tree as HTML tables and nested HTML unordered list
-// elements.
-void DxDiagNodeToHTML(std::string* output, const DxDiagNode& node) {
- output->append("<table>\n");
-
- for (std::map<std::string, std::string>::const_iterator it =
- node.values.begin();
- it != node.values.end();
- ++it) {
- output->append("<tr><td><strong>");
- output->append(EscapeForHTML(it->first));
- output->append("</strong></td><td>");
- output->append(EscapeForHTML(it->second));
- output->append("</td></tr>\n");
- }
-
- output->append("</table>\n<ul>\n");
-
- for (std::map<std::string, DxDiagNode>::const_iterator it =
- node.children.begin();
- it != node.children.end();
- ++it) {
- output->append("<li><strong>");
- output->append(EscapeForHTML(it->first));
- output->append("</strong>");
-
- DxDiagNodeToHTML(output, it->second);
-
- output->append("</li>\n");
- }
-
- output->append("</ul>\n");
-}
-
-#endif // OS_WIN
-
-}
-
-std::string AboutGpu() {
- const GPUInfo& gpu_info = GpuProcessHostUIShim::Get()->gpu_info();
-
- std::string html;
-
- html.append("<html><head><title>About GPU</title></head>\n");
-
- if (gpu_info.progress() != GPUInfo::kComplete) {
- GpuProcessHostUIShim::Get()->CollectGraphicsInfoAsynchronously();
-
- // If it's not fully initialized yet, set a timeout to reload the page.
- html.append("<body onload=\"setTimeout('window.location.reload(true)',");
- html.append("2000)\">\n");
- } else {
- html.append("<body>\n");
- }
-
- html.append("<h2>GPU Information</h2>\n");
-
- if (gpu_info.progress() == GPUInfo::kUninitialized) {
- html.append("<p>Retrieving GPU information . . .</p>\n");
- } else {
- html.append("<table><tr>");
- html.append("<td><strong>Initialization time</strong></td><td>");
- html.append(base::Int64ToString(
- gpu_info.initialization_time().InMilliseconds()));
- html.append("</td></tr><tr><td>");
- html.append("<strong>Vendor ID</strong></td><td>");
- html.append(base::StringPrintf("0x%04x", gpu_info.vendor_id()));
- html.append("</td></tr><tr><td>");
- html.append("<strong>Device ID</strong></td><td>");
- html.append(base::StringPrintf("0x%04x", gpu_info.device_id()));
- html.append("</td></tr><tr><td>");
- html.append("<strong>Driver Version</strong></td><td>");
- html.append(WideToASCII(gpu_info.driver_version()).c_str());
- html.append("</td></tr><tr><td>");
- html.append("<strong>Pixel Shader Version</strong></td><td>");
- html.append(VersionNumberToString(gpu_info.pixel_shader_version()).c_str());
- html.append("</td></tr><tr><td>");
- html.append("<strong>Vertex Shader Version</strong></td><td>");
- html.append(VersionNumberToString(
- gpu_info.vertex_shader_version()).c_str());
- html.append("</td></tr><tr><td>");
- html.append("<strong>GL Version</strong></td><td>");
- html.append(VersionNumberToString(gpu_info.gl_version()).c_str());
- html.append("</td></tr></table>");
-
-#if defined(OS_WIN)
- if (gpu_info.progress() != GPUInfo::kComplete) {
- html.append("<p>Retrieving DirectX Diagnostics . . .</p>\n");
- } else {
- html.append("<h2>DirectX Diagnostics</h2>");
- DxDiagNodeToHTML(&html, gpu_info.dx_diagnostics());
- }
-#endif
- }
-
- html.append("</body></html>");
-
- return html;
-}
-
// AboutSource -----------------------------------------------------------------
AboutSource::AboutSource()
@@ -831,7 +733,7 @@ AboutSource::AboutSource()
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(this)));
}
@@ -903,8 +805,6 @@ void AboutSource::StartDataRequest(const std::string& path_raw,
#endif
} else if (path == kSyncPath) {
response = AboutSync();
- } else if (path == kGpuPath) {
- response = AboutGpu();
}
FinishDataRequest(response, request_id);
@@ -936,7 +836,7 @@ void AboutMemoryHandler::BindProcessMetrics(DictionaryValue* data,
data->SetInteger("comm_map", static_cast<int>(info->committed.mapped));
data->SetInteger("comm_image", static_cast<int>(info->committed.image));
data->SetInteger("pid", info->pid);
- data->SetString("version", WideToUTF16Hack(info->version));
+ data->SetString("version", info->version);
data->SetInteger("processes", info->num_processes);
}
@@ -958,7 +858,7 @@ void AboutMemoryHandler::AppendProcess(ListValue* child_data,
ListValue* titles = new ListValue();
child->Set("titles", titles);
for (size_t i = 0; i < info->titles.size(); ++i)
- titles->Append(new StringValue(WideToUTF16Hack(info->titles[i])));
+ titles->Append(new StringValue(info->titles[i]));
}
@@ -997,15 +897,14 @@ void AboutMemoryHandler::OnDetailsAvailable() {
}
DictionaryValue* browser_data = new DictionaryValue();
browsers->Append(browser_data);
- browser_data->SetString("name",
- WideToUTF16Hack(browser_processes[index].name));
+ browser_data->SetString("name", browser_processes[index].name);
BindProcessMetrics(browser_data, &aggregate);
// We log memory info as we record it.
if (log_string.length() > 0)
log_string.append(L", ");
- log_string.append(browser_processes[index].name);
+ log_string.append(UTF16ToWide(browser_processes[index].name));
log_string.append(L", ");
log_string.append(UTF8ToWide(
base::Int64ToString(aggregate.working_set.priv)));
@@ -1026,7 +925,7 @@ void AboutMemoryHandler::OnDetailsAvailable() {
root.Set("child_data", child_data);
ProcessData process = browser_processes[0]; // Chrome is the first browser.
- root.SetString("current_browser_name", WideToUTF16Hack(process.name));
+ root.SetString("current_browser_name", process.name);
for (size_t index = 0; index < process.processes.size(); index++) {
if (process.processes[index].type == ChildProcessInfo::BROWSER_PROCESS)
@@ -1138,6 +1037,12 @@ bool WillHandleBrowserAboutURL(GURL* url, Profile* profile) {
return true;
}
+ // Rewrite about:gpu/* URLs to chrome://gpu-internals/*
+ if (StartsWithAboutSpecifier(*url, chrome::kAboutGpuURL)) {
+ *url = RemapAboutURL(chrome::kGpuInternalsURL, *url);
+ return true;
+ }
+
// Rewrite about:appcache-internals/* URLs to chrome://appcache/*
if (StartsWithAboutSpecifier(*url, chrome::kAboutAppCacheInternalsURL)) {
*url = RemapAboutURL(chrome::kAppCacheViewInternalsURL, *url);
@@ -1160,11 +1065,11 @@ bool WillHandleBrowserAboutURL(GURL* url, Profile* profile) {
// Handle URLs to wreck the gpu process.
if (LowerCaseEqualsASCII(url->spec(), chrome::kAboutGpuCrashURL)) {
- GpuProcessHostUIShim::Get()->SendAboutGpuCrash();
+ GpuProcessHostUIShim::GetInstance()->SendAboutGpuCrash();
return true;
}
if (LowerCaseEqualsASCII(url->spec(), chrome::kAboutGpuHangURL)) {
- GpuProcessHostUIShim::Get()->SendAboutGpuHang();
+ GpuProcessHostUIShim::GetInstance()->SendAboutGpuHang();
return true;
}
diff --git a/chrome/browser/browser_about_handler.h b/chrome/browser/browser_about_handler.h
index de8f1bf..e0a0dbf 100644
--- a/chrome/browser/browser_about_handler.h
+++ b/chrome/browser/browser_about_handler.h
@@ -12,9 +12,9 @@
#include <string>
#include "base/process.h"
-#include "base/singleton.h"
#include "base/string_util.h"
+template <typename T> struct DefaultSingletonTraits;
class GURL;
class Profile;
@@ -38,7 +38,8 @@ typedef std::map<std::string, std::string> AboutTcmallocOutputsType;
class AboutTcmallocOutputs {
public:
- AboutTcmallocOutputs() {}
+ // Returns the singleton instance.
+ static AboutTcmallocOutputs* GetInstance();
AboutTcmallocOutputsType* outputs() { return &outputs_; }
@@ -55,6 +56,8 @@ class AboutTcmallocOutputs {
}
private:
+ AboutTcmallocOutputs() {}
+
AboutTcmallocOutputsType outputs_;
friend struct DefaultSingletonTraits<AboutTcmallocOutputs>;
diff --git a/chrome/browser/browser_about_handler_unittest.cc b/chrome/browser/browser_about_handler_unittest.cc
index be08e56..9b234a2 100644
--- a/chrome/browser/browser_about_handler_unittest.cc
+++ b/chrome/browser/browser_about_handler_unittest.cc
@@ -42,6 +42,12 @@ TEST(BrowserAboutHandlerTest, WillHandleBrowserAboutURL) {
true
},
{
+ GURL(std::string(chrome::kAboutGpuURL) + "/jupiter"),
+ GURL(std::string(chrome::kGpuInternalsURL) + "jupiter"),
+ false,
+ true
+ },
+ {
GURL(std::string(chrome::kAboutAppCacheInternalsURL) + "/earth"),
GURL(std::string(chrome::kAppCacheViewInternalsURL) + "earth"),
false,
diff --git a/chrome/browser/browser_browsertest.cc b/chrome/browser/browser_browsertest.cc
index b0da49c..ae52bac 100644
--- a/chrome/browser/browser_browsertest.cc
+++ b/chrome/browser/browser_browsertest.cc
@@ -10,29 +10,29 @@
#include "base/sys_info.h"
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/app_modal_dialog.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/extensions/extension_browsertest.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/js_modal_dialog.h"
-#include "chrome/browser/native_app_modal_dialog.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/tabs/pinned_tab_codec.h"
#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
+#include "chrome/browser/ui/app_modal_dialogs/js_modal_dialog.h"
+#include "chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_init.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
-#include "chrome/common/url_constants.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/page_transition_types.h"
+#include "chrome/common/url_constants.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "grit/chromium_strings.h"
@@ -42,6 +42,7 @@
#if defined(OS_WIN)
#include "base/i18n/rtl.h"
+#include "chrome/browser/browser_process.h"
#endif
namespace {
@@ -160,7 +161,7 @@ class BrowserTest : public ExtensionBrowserTest {
// Returns the app extension aptly named "App Test".
const Extension* GetExtension() {
const ExtensionList* extensions =
- browser()->profile()->GetExtensionsService()->extensions();
+ browser()->profile()->GetExtensionService()->extensions();
for (size_t i = 0; i < extensions->size(); ++i) {
if ((*extensions)[i]->name() == "App Test")
return (*extensions)[i];
@@ -480,7 +481,7 @@ IN_PROC_BROWSER_TEST_F(BrowserTest, TabClosingWhenRemovingExtension) {
model->AddObserver(&observer);
// Uninstall the extension and make sure TabClosing is sent.
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
service->UninstallExtension(GetExtension()->id(), false);
EXPECT_EQ(1, observer.closing_count());
@@ -501,32 +502,33 @@ IN_PROC_BROWSER_TEST_F(BrowserTest, MAYBE_PageLanguageDetection) {
ASSERT_TRUE(test_server()->Start());
TabContents* current_tab = browser()->GetSelectedTabContents();
+ Source<TabContents> source(current_tab);
// Navigate to a page in English.
- ui_test_utils::WindowedNotificationObserverWithDetails<TabContents,
- std::string>
+ ui_test_utils::WindowedNotificationObserverWithDetails<std::string>
en_language_detected_signal(NotificationType::TAB_LANGUAGE_DETERMINED,
- current_tab);
+ source);
ui_test_utils::NavigateToURL(
browser(), GURL(test_server()->GetURL("files/english_page.html")));
EXPECT_TRUE(current_tab->language_state().original_language().empty());
en_language_detected_signal.Wait();
std::string lang;
- EXPECT_TRUE(en_language_detected_signal.GetDetailsFor(current_tab, &lang));
+ EXPECT_TRUE(en_language_detected_signal.GetDetailsFor(
+ source.map_key(), &lang));
EXPECT_EQ("en", lang);
EXPECT_EQ("en", current_tab->language_state().original_language());
// Now navigate to a page in French.
- ui_test_utils::WindowedNotificationObserverWithDetails<TabContents,
- std::string>
+ ui_test_utils::WindowedNotificationObserverWithDetails<std::string>
fr_language_detected_signal(NotificationType::TAB_LANGUAGE_DETERMINED,
- current_tab);
+ source);
ui_test_utils::NavigateToURL(
browser(), GURL(test_server()->GetURL("files/french_page.html")));
EXPECT_TRUE(current_tab->language_state().original_language().empty());
fr_language_detected_signal.Wait();
lang.clear();
- EXPECT_TRUE(fr_language_detected_signal.GetDetailsFor(current_tab, &lang));
+ EXPECT_TRUE(fr_language_detected_signal.GetDetailsFor(
+ source.map_key(), &lang));
EXPECT_EQ("fr", lang);
EXPECT_EQ("fr", current_tab->language_state().original_language());
}
diff --git a/chrome/browser/browser_child_process_host.cc b/chrome/browser/browser_child_process_host.cc
index a317f26..13bc04e 100644
--- a/chrome/browser/browser_child_process_host.cc
+++ b/chrome/browser/browser_child_process_host.cc
@@ -6,11 +6,11 @@
#include "base/command_line.h"
#include "base/file_path.h"
+#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/path_service.h"
#include "base/process_util.h"
-#include "base/singleton.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "chrome/app/breakpad_mac.h"
@@ -34,6 +34,8 @@
namespace {
typedef std::list<BrowserChildProcessHost*> ChildProcessList;
+static base::LazyInstance<ChildProcessList> g_child_process_list(
+ base::LINKER_INITIALIZED);
// The NotificationTask is used to notify about plugin process connection/
// disconnection. It is needed because the notifications in the
@@ -59,19 +61,43 @@ class ChildNotificationTask : public Task {
BrowserChildProcessHost::BrowserChildProcessHost(
- ProcessType type, ResourceDispatcherHost* resource_dispatcher_host)
- : Receiver(type, -1),
+ ChildProcessInfo::ProcessType type,
+ ResourceDispatcherHost* resource_dispatcher_host,
+ ResourceMessageFilter::URLRequestContextOverride*
+ url_request_context_override)
+ : ChildProcessInfo(type, -1),
ALLOW_THIS_IN_INITIALIZER_LIST(client_(this)),
resource_dispatcher_host_(resource_dispatcher_host) {
- Singleton<ChildProcessList>::get()->push_back(this);
+ Initialize(url_request_context_override);
}
+BrowserChildProcessHost::BrowserChildProcessHost(
+ ChildProcessInfo::ProcessType type,
+ ResourceDispatcherHost* resource_dispatcher_host)
+ : ChildProcessInfo(type, -1),
+ ALLOW_THIS_IN_INITIALIZER_LIST(client_(this)),
+ resource_dispatcher_host_(resource_dispatcher_host) {
+ Initialize(NULL);
+}
-BrowserChildProcessHost::~BrowserChildProcessHost() {
- Singleton<ChildProcessList>::get()->remove(this);
+void BrowserChildProcessHost::Initialize(
+ ResourceMessageFilter::URLRequestContextOverride*
+ url_request_context_override) {
+ if (resource_dispatcher_host_) {
+ ResourceMessageFilter* resource_message_filter = new ResourceMessageFilter(
+ id(), type(), resource_dispatcher_host_);
+ if (url_request_context_override) {
+ resource_message_filter->set_url_request_context_override(
+ url_request_context_override);
+ }
+ AddFilter(resource_message_filter);
+ }
+
+ g_child_process_list.Get().push_back(this);
+}
- if (resource_dispatcher_host_)
- resource_dispatcher_host_->CancelRequestsForProcess(id());
+BrowserChildProcessHost::~BrowserChildProcessHost() {
+ g_child_process_list.Get().remove(this);
}
// static
@@ -93,7 +119,7 @@ void BrowserChildProcessHost::SetCrashReporterCommandLine(
// static
void BrowserChildProcessHost::TerminateAll() {
// Make a copy since the ChildProcessHost dtor mutates the original list.
- ChildProcessList copy = *(Singleton<ChildProcessList>::get());
+ ChildProcessList copy = g_child_process_list.Get();
STLDeleteElements(&copy);
}
@@ -117,12 +143,16 @@ void BrowserChildProcessHost::Launch(
&client_));
}
-bool BrowserChildProcessHost::Send(IPC::Message* msg) {
- return SendOnChannel(msg);
+base::ProcessHandle BrowserChildProcessHost::GetChildProcessHandle() const {
+ DCHECK(child_process_.get())
+ << "Requesting a child process handle before launching.";
+ DCHECK(child_process_->GetHandle())
+ << "Requesting a child process handle before launch has completed OK.";
+ return child_process_->GetHandle();
}
void BrowserChildProcessHost::ForceShutdown() {
- Singleton<ChildProcessList>::get()->remove(this);
+ g_child_process_list.Get().remove(this);
ChildProcessHost::ForceShutdown();
}
@@ -131,18 +161,34 @@ void BrowserChildProcessHost::Notify(NotificationType type) {
BrowserThread::UI, FROM_HERE, new ChildNotificationTask(type, this));
}
-bool BrowserChildProcessHost::DidChildCrash() {
- return child_process_->DidProcessCrash();
+base::TerminationStatus BrowserChildProcessHost::GetChildTerminationStatus(
+ int* exit_code) {
+ return child_process_->GetChildTerminationStatus(exit_code);
}
void BrowserChildProcessHost::OnChildDied() {
if (handle() != base::kNullProcessHandle) {
- bool did_crash = DidChildCrash();
- if (did_crash) {
- OnProcessCrashed();
- // Report that this child process crashed.
- Notify(NotificationType::CHILD_PROCESS_CRASHED);
- UMA_HISTOGRAM_COUNTS("ChildProcess.Crashes", this->type());
+ int exit_code;
+ base::TerminationStatus status = GetChildTerminationStatus(&exit_code);
+ switch (status) {
+ case base::TERMINATION_STATUS_PROCESS_CRASHED: {
+ OnProcessCrashed(exit_code);
+
+ // Report that this child process crashed.
+ Notify(NotificationType::CHILD_PROCESS_CRASHED);
+ UMA_HISTOGRAM_COUNTS("ChildProcess.Crashes", this->type());
+ break;
+ }
+ case base::TERMINATION_STATUS_PROCESS_WAS_KILLED: {
+ OnProcessWasKilled(exit_code);
+
+ // Report that this child process was killed.
+ Notify(NotificationType::CHILD_PROCESS_WAS_KILLED);
+ UMA_HISTOGRAM_COUNTS("ChildProcess.Kills", this->type());
+ break;
+ }
+ default:
+ break;
}
// Notify in the main loop of the disconnection.
Notify(NotificationType::CHILD_PROCESS_HOST_DISCONNECTED);
@@ -150,22 +196,10 @@ void BrowserChildProcessHost::OnChildDied() {
ChildProcessHost::OnChildDied();
}
-bool BrowserChildProcessHost::InterceptMessageFromChild(
- const IPC::Message& msg) {
- bool msg_is_ok = true;
- bool handled = false;
- if (resource_dispatcher_host_) {
- handled = resource_dispatcher_host_->OnMessageReceived(
- msg, this, &msg_is_ok);
- }
- if (!handled && (msg.type() == PluginProcessHostMsg_ShutdownRequest::ID)) {
- // Must remove the process from the list now, in case it gets used for a
- // new instance before our watcher tells us that the process terminated.
- Singleton<ChildProcessList>::get()->remove(this);
- }
- if (!msg_is_ok)
- base::KillProcess(handle(), ResultCodes::KILLED_BAD_MESSAGE, false);
- return handled;
+void BrowserChildProcessHost::ShutdownStarted() {
+ // Must remove the process from the list now, in case it gets used for a
+ // new instance before our watcher tells us that the process terminated.
+ g_child_process_list.Get().remove(this);
}
BrowserChildProcessHost::ClientHook::ClientHook(BrowserChildProcessHost* host)
@@ -185,14 +219,14 @@ BrowserChildProcessHost::Iterator::Iterator()
: all_(true), type_(UNKNOWN_PROCESS) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)) <<
"ChildProcessInfo::Iterator must be used on the IO thread.";
- iterator_ = Singleton<ChildProcessList>::get()->begin();
+ iterator_ = g_child_process_list.Get().begin();
}
-BrowserChildProcessHost::Iterator::Iterator(ProcessType type)
+BrowserChildProcessHost::Iterator::Iterator(ChildProcessInfo::ProcessType type)
: all_(false), type_(type) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)) <<
"ChildProcessInfo::Iterator must be used on the IO thread.";
- iterator_ = Singleton<ChildProcessList>::get()->begin();
+ iterator_ = g_child_process_list.Get().begin();
if (!Done() && (*iterator_)->type() != type_)
++(*this);
}
@@ -213,5 +247,5 @@ BrowserChildProcessHost* BrowserChildProcessHost::Iterator::operator++() {
}
bool BrowserChildProcessHost::Iterator::Done() {
- return iterator_ == Singleton<ChildProcessList>::get()->end();
+ return iterator_ == g_child_process_list.Get().end();
}
diff --git a/chrome/browser/browser_child_process_host.h b/chrome/browser/browser_child_process_host.h
index cf30973..f917a4d 100644
--- a/chrome/browser/browser_child_process_host.h
+++ b/chrome/browser/browser_child_process_host.h
@@ -9,17 +9,19 @@
#include <list>
#include "chrome/browser/child_process_launcher.h"
-#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+#include "chrome/browser/renderer_host/resource_message_filter.h"
#include "chrome/common/child_process_host.h"
+#include "chrome/common/child_process_info.h"
+class ResourceDispatcherHost;
// Plugins/workers and other child processes that live on the IO thread should
// derive from this class.
//
// [Browser]RenderProcessHost is the main exception that doesn't derive from
// this class. That project lives on the UI thread.
-class BrowserChildProcessHost : public ResourceDispatcherHost::Receiver,
- public ChildProcessHost,
+class BrowserChildProcessHost : public ChildProcessHost,
+ public ChildProcessInfo,
public ChildProcessLauncher::Client {
public:
virtual ~BrowserChildProcessHost();
@@ -34,9 +36,6 @@ class BrowserChildProcessHost : public ResourceDispatcherHost::Receiver,
// Terminates all child processes and deletes each ChildProcessHost instance.
static void TerminateAll();
- // ResourceDispatcherHost::Receiver implementation:
- virtual bool Send(IPC::Message* msg);
-
// The Iterator class allows iteration through either all child processes, or
// ones of a specific type, depending on which constructor is used. Note that
// this should be done from the IO thread and that the iterator should not be
@@ -45,7 +44,7 @@ class BrowserChildProcessHost : public ResourceDispatcherHost::Receiver,
class Iterator {
public:
Iterator();
- explicit Iterator(ProcessType type);
+ explicit Iterator(ChildProcessInfo::ProcessType type);
BrowserChildProcessHost* operator->() { return *iterator_; }
BrowserChildProcessHost* operator*() { return *iterator_; }
BrowserChildProcessHost* operator++();
@@ -53,15 +52,26 @@ class BrowserChildProcessHost : public ResourceDispatcherHost::Receiver,
private:
bool all_;
- ProcessType type_;
+ ChildProcessInfo::ProcessType type_;
std::list<BrowserChildProcessHost*>::iterator iterator_;
};
protected:
- // The resource_dispatcher_host may be NULL to indicate none is needed for
+ // |resource_dispatcher_host| may be NULL to indicate none is needed for
// this process type.
- BrowserChildProcessHost(ProcessType type,
- ResourceDispatcherHost* resource_dispatcher_host);
+ // |url_request_context_getter| allows derived classes to override the
+ // URLRequestContext.
+ BrowserChildProcessHost(
+ ChildProcessInfo::ProcessType type,
+ ResourceDispatcherHost* resource_dispatcher_host,
+ ResourceMessageFilter::URLRequestContextOverride*
+ url_request_context_override);
+
+ // A convenient constructor for those classes that want to use the default
+ // URLRequestContext.
+ BrowserChildProcessHost(
+ ChildProcessInfo::ProcessType type,
+ ResourceDispatcherHost* resource_dispatcher_host);
// Derived classes call this to launch the child process asynchronously.
void Launch(
@@ -73,23 +83,47 @@ class BrowserChildProcessHost : public ResourceDispatcherHost::Receiver,
#endif
CommandLine* cmd_line);
+ // Returns the handle of the child process. This can be called only after
+ // OnProcessLaunched is called or it will be invalid and may crash.
+ base::ProcessHandle GetChildProcessHandle() const;
+
// ChildProcessLauncher::Client implementation.
- virtual void OnProcessLaunched() { }
+ virtual void OnProcessLaunched() {}
// Derived classes can override this to know if the process crashed.
- virtual void OnProcessCrashed() {}
-
- virtual bool DidChildCrash();
+ // |exit_code| is the status returned when the process crashed (for
+ // posix, as returned from waitpid(), for Windows, as returned from
+ // GetExitCodeProcess()).
+ virtual void OnProcessCrashed(int exit_code) {}
+
+ // Derived classes can override this to know if the process was
+ // killed. |exit_code| is the status returned when the process
+ // was killed (for posix, as returned from waitpid(), for Windows,
+ // as returned from GetExitCodeProcess()).
+ virtual void OnProcessWasKilled(int exit_code) {}
+
+ // Returns the termination status of a child. |exit_code| is the
+ // status returned when the process exited (for posix, as returned
+ // from waitpid(), for Windows, as returned from
+ // GetExitCodeProcess()). |exit_code| may be NULL.
+ virtual base::TerminationStatus GetChildTerminationStatus(int* exit_code);
// Overrides from ChildProcessHost
virtual void OnChildDied();
- virtual bool InterceptMessageFromChild(const IPC::Message& msg);
+ virtual void ShutdownStarted();
virtual void Notify(NotificationType type);
// Extends the base class implementation and removes this host from
// the host list. Calls ChildProcessHost::ForceShutdown
virtual void ForceShutdown();
+ ResourceDispatcherHost* resource_dispatcher_host() {
+ return resource_dispatcher_host_;
+ }
+
private:
+ void Initialize(ResourceMessageFilter::URLRequestContextOverride*
+ url_request_context_override);
+
// By using an internal class as the ChildProcessLauncher::Client, we can
// intercept OnProcessLaunched and do our own processing before
// calling the subclass' implementation.
@@ -107,4 +141,3 @@ class BrowserChildProcessHost : public ResourceDispatcherHost::Receiver,
};
#endif // CHROME_BROWSER_BROWSER_CHILD_PROCESS_HOST_H_
-
diff --git a/chrome/browser/browser_focus_uitest.cc b/chrome/browser/browser_focus_uitest.cc
index 13c6b94..0be8a42 100644
--- a/chrome/browser/browser_focus_uitest.cc
+++ b/chrome/browser/browser_focus_uitest.cc
@@ -8,6 +8,7 @@
#include "base/format_macros.h"
#include "base/message_loop.h"
#include "base/path_service.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_window.h"
@@ -18,7 +19,7 @@
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/view_ids.h"
+#include "chrome/browser/ui/view_ids.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/in_process_browser_test.h"
@@ -41,6 +42,11 @@
#include "chrome/browser/gtk/view_id_util.h"
#endif
+#if defined(OS_WIN)
+#include <windows.h>
+#include <Psapi.h>
+#endif
+
#if defined(OS_LINUX)
#define MAYBE_FocusTraversal FocusTraversal
#define MAYBE_FocusTraversalOnInterstitial FocusTraversalOnInterstitial
@@ -72,6 +78,49 @@ const char kStealFocusPage[] = "files/focus/page_steals_focus.html";
const char kTypicalPage[] = "files/focus/typical_page.html";
const char kTypicalPageName[] = "typical_page.html";
+// Test to make sure Chrome is in the foreground as we start testing. This is
+// required for tests that synthesize input to the Chrome window.
+bool ChromeInForeground() {
+#if defined(OS_WIN)
+ HWND window = ::GetForegroundWindow();
+ std::wstring caption;
+ std::wstring filename;
+ int len = ::GetWindowTextLength(window) + 1;
+ ::GetWindowText(window, WriteInto(&caption, len), len);
+ bool chrome_window_in_foreground =
+ EndsWith(caption, L" - Google Chrome", true) ||
+ EndsWith(caption, L" - Chromium", true);
+ if (!chrome_window_in_foreground) {
+ DWORD process_id;
+ int thread_id = ::GetWindowThreadProcessId(window, &process_id);
+
+ base::ProcessHandle process;
+ if (base::OpenProcessHandleWithAccess(process_id,
+ PROCESS_QUERY_LIMITED_INFORMATION,
+ &process)) {
+ len = MAX_PATH;
+ if (!GetProcessImageFileName(process, WriteInto(&filename, len), len)) {
+ int error = GetLastError();
+ filename = std::wstring(L"Unable to read filename for process id '" +
+ base::IntToString16(process_id) +
+ L"' (error ") +
+ base::IntToString16(error) + L")";
+ }
+ base::CloseProcessHandle(process);
+ }
+ }
+ EXPECT_TRUE(chrome_window_in_foreground)
+ << "Chrome must be in the foreground when running interactive tests\n"
+ << "Process in foreground: " << filename.c_str() << "\n"
+ << "Window: " << window << "\n"
+ << "Caption: " << caption.c_str();
+ return chrome_window_in_foreground;
+#else
+ // Windows only at the moment.
+ return true;
+#endif
+}
+
class BrowserFocusTest : public InProcessBrowserTest {
public:
BrowserFocusTest() {
@@ -116,11 +165,11 @@ class TestInterstitialPage : public InterstitialPage {
}
protected:
- virtual void FocusedNodeChanged() {
+ virtual void FocusedNodeChanged(bool is_editable_node) {
NotificationService::current()->Notify(
NotificationType::FOCUS_CHANGED_IN_PAGE,
Source<RenderViewHost>(render_view_host()),
- NotificationService::NoDetails());
+ Details<const bool>(&is_editable_node));
}
private:
@@ -129,14 +178,14 @@ class TestInterstitialPage : public InterstitialPage {
IN_PROC_BROWSER_TEST_F(BrowserFocusTest, ClickingMovesFocus) {
ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-#if defined(USE_X11) || defined(OS_MACOSX)
+#if defined(OS_POSIX)
// It seems we have to wait a little bit for the widgets to spin up before
// we can start clicking on them.
MessageLoop::current()->PostDelayedTask(FROM_HERE,
new MessageLoop::QuitTask(),
kActionDelayMs);
ui_test_utils::RunMessageLoop();
-#endif
+#endif // defined(OS_POSIX)
ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR));
@@ -401,10 +450,11 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversal) {
browser()->FocusLocationBar();
+ const char* kTextElementID = "textEdit";
const char* kExpElementIDs[] = {
"", // Initially no element in the page should be focused
// (the location bar is focused).
- "textEdit", "searchButton", "luckyButton", "googleLink", "gmailLink",
+ kTextElementID, "searchButton", "luckyButton", "googleLink", "gmailLink",
"gmapLink"
};
@@ -426,22 +476,26 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversal) {
&actual));
ASSERT_STREQ(kExpElementIDs[j], actual.c_str());
- NotificationType::Type notification_type;
- NotificationSource notification_source =
- NotificationService::AllSources();
if (j < arraysize(kExpElementIDs) - 1) {
- notification_type = NotificationType::FOCUS_CHANGED_IN_PAGE;
- notification_source = Source<RenderViewHost>(
- browser()->GetSelectedTabContents()->render_view_host());
+ // If the next element is the kTextElementID, we expect to be
+ // notified we have switched to an editable node.
+ bool is_editable_node =
+ (strcmp(kTextElementID, kExpElementIDs[j + 1]) == 0);
+ Details<bool> details(&is_editable_node);
+
+ ASSERT_TRUE(ui_test_utils::SendKeyPressAndWaitWithDetails(
+ browser(), app::VKEY_TAB, false, false, false, false,
+ NotificationType::FOCUS_CHANGED_IN_PAGE,
+ NotificationSource(Source<RenderViewHost>(
+ browser()->GetSelectedTabContents()->render_view_host())),
+ details));
} else {
// On the last tab key press, the focus returns to the browser.
- notification_type = NotificationType::FOCUS_RETURNED_TO_BROWSER;
- notification_source = Source<Browser>(browser());
+ ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait(
+ browser(), app::VKEY_TAB, false, false, false, false,
+ NotificationType::FOCUS_RETURNED_TO_BROWSER,
+ NotificationSource(Source<Browser>(browser()))));
}
-
- ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait(
- browser(), app::VKEY_TAB, false, false, false, false,
- notification_type, notification_source));
}
// At this point the renderer has sent us a message asking to advance the
@@ -459,24 +513,29 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversal) {
// Now let's press shift-tab to move the focus in reverse.
for (size_t j = 0; j < arraysize(kExpElementIDs); ++j) {
SCOPED_TRACE(StringPrintf("inner loop: %" PRIuS, j));
+ const char* next_element =
+ kExpElementIDs[arraysize(kExpElementIDs) - 1 - j];
- NotificationType::Type notification_type;
- NotificationSource notification_source =
- NotificationService::AllSources();
if (j < arraysize(kExpElementIDs) - 1) {
- notification_type = NotificationType::FOCUS_CHANGED_IN_PAGE;
- notification_source = Source<RenderViewHost>(
- browser()->GetSelectedTabContents()->render_view_host());
+ // If the next element is the kTextElementID, we expect to be
+ // notified we have switched to an editable node.
+ bool is_editable_node = (strcmp(kTextElementID, next_element) == 0);
+ Details<bool> details(&is_editable_node);
+
+ ASSERT_TRUE(ui_test_utils::SendKeyPressAndWaitWithDetails(
+ browser(), app::VKEY_TAB, false, true, false, false,
+ NotificationType::FOCUS_CHANGED_IN_PAGE,
+ NotificationSource(Source<RenderViewHost>(
+ browser()->GetSelectedTabContents()->render_view_host())),
+ details));
} else {
// On the last tab key press, the focus returns to the browser.
- notification_type = NotificationType::FOCUS_RETURNED_TO_BROWSER;
- notification_source = Source<Browser>(browser());
+ ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait(
+ browser(), app::VKEY_TAB, false, true, false, false,
+ NotificationType::FOCUS_RETURNED_TO_BROWSER,
+ NotificationSource(Source<Browser>(browser()))));
}
- ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait(
- browser(), app::VKEY_TAB, false, true, false, false,
- notification_type, notification_source));
-
// Let's make sure the focus is on the expected element in the page.
std::string actual;
ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString(
@@ -484,7 +543,7 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversal) {
L"",
L"window.domAutomationController.send(getFocusedElement());",
&actual));
- ASSERT_STREQ(kExpElementIDs[6 - j], actual.c_str());
+ ASSERT_STREQ(next_element, actual.c_str());
}
// At this point the renderer has sent us a message asking to advance the
@@ -642,8 +701,7 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, InterstitialFocus) {
}
// Make sure Find box can request focus, even when it is already open.
-// Disabled, http://crbug.com/62936.
-IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_FindFocusTest) {
+IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FindFocusTest) {
ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
ASSERT_TRUE(test_server()->Start());
@@ -651,6 +709,8 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_FindFocusTest) {
GURL url = test_server()->GetURL(kTypicalPage);
ui_test_utils::NavigateToURL(browser(), url);
+ EXPECT_TRUE(ChromeInForeground());
+
#if defined(OS_MACOSX)
// Press Cmd+F, which will make the Find box open and request focus.
ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
diff --git a/chrome/browser/browser_keyevents_browsertest.cc b/chrome/browser/browser_keyevents_browsertest.cc
index 021104b..3de74f7 100644
--- a/chrome/browser/browser_keyevents_browsertest.cc
+++ b/chrome/browser/browser_keyevents_browsertest.cc
@@ -636,14 +636,8 @@ IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, AccessKeys) {
#endif
}
-#if defined(OS_MACOSX)
-// See http://crbug.com/50447 for details.
-#define MAYBE_ReservedAccelerators FLAKY_ReservedAccelerators
-#else
-#define MAYBE_ReservedAccelerators ReservedAccelerators
-#endif
-
-IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, MAYBE_ReservedAccelerators) {
+// Flaky, http://crbug.com/65847.
+IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, FLAKY_ReservedAccelerators) {
ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
@@ -653,126 +647,66 @@ IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, MAYBE_ReservedAccelerators) {
ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
-#if defined(OS_WIN) || defined(TOOLKIT_VIEWS)
- static const KeyEventTestData kTestCtrlT = {
- app::VKEY_T, true, false, false, false,
- true, false, false, false, 1,
- { "D 17 0 true false false false" }
- };
-
ASSERT_EQ(1, browser()->tab_count());
- // Press Ctrl+T, which will open a new tab.
- EXPECT_NO_FATAL_FAILURE(TestKeyEvent(0, kTestCtrlT));
- EXPECT_EQ(2, browser()->tab_count());
- browser()->SelectNumberedTab(0);
- ASSERT_EQ(0, browser()->selected_index());
-
- int result_length;
- ASSERT_NO_FATAL_FAILURE(GetResultLength(0, &result_length));
- EXPECT_EQ(1, result_length);
- // Reserved accelerators can't be suppressed.
- ASSERT_NO_FATAL_FAILURE(SuppressAllEvents(0, true));
- // Press Ctrl+W, which will close the tab.
- ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
- browser(), app::VKEY_W, true, false, false, false));
- EXPECT_EQ(1, browser()->tab_count());
-#elif defined(OS_MACOSX)
- static const KeyEventTestData kTestCmdT = {
+ static const KeyEventTestData kTestCtrlOrCmdT = {
+#if defined(OS_MACOSX)
app::VKEY_T, false, false, false, true,
true, false, false, false, 1,
{ "D 91 0 false false false true" }
- };
-
- ASSERT_EQ(1, browser()->tab_count());
- // Press Cmd+T, which will open a new tab.
- EXPECT_NO_FATAL_FAILURE(TestKeyEvent(0, kTestCmdT));
- EXPECT_EQ(2, browser()->tab_count());
- browser()->SelectNumberedTab(0);
- ASSERT_EQ(0, browser()->selected_index());
-
- int result_length;
- ASSERT_NO_FATAL_FAILURE(GetResultLength(0, &result_length));
- EXPECT_EQ(1, result_length);
-
- // Reserved accelerators can't be suppressed.
- ASSERT_NO_FATAL_FAILURE(SuppressAllEvents(0, true));
- // Press Cmd+W, which will close the tab.
- ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
- browser(), app::VKEY_W, false, false, false, true));
- EXPECT_EQ(1, browser()->tab_count());
-#elif defined(TOOLKIT_GTK)
- // Ctrl-[a-z] are not treated as reserved accelerators on GTK.
- static const KeyEventTestData kTestCtrlT = {
+#else
app::VKEY_T, true, false, false, false,
- false, false, false, false, 2,
- { "D 17 0 true false false false",
- "D 84 0 true false false false" }
- };
-
- static const KeyEventTestData kTestCtrlPageDown = {
- app::VKEY_NEXT, true, false, false, false,
true, false, false, false, 1,
{ "D 17 0 true false false false" }
+#endif
};
- static const KeyEventTestData kTestCtrlTab = {
- app::VKEY_TAB, true, false, false, false,
- true, false, false, false, 1,
- { "D 17 0 true false false false" }
- };
+ ui_test_utils::WindowedNotificationObserver wait_for_new_tab(
+ NotificationType::TAB_PARENTED,
+ NotificationService::AllSources());
- static const KeyEventTestData kTestCtrlTBlocked = {
- app::VKEY_T, true, false, false, false,
- true, false, false, false, 4,
- { "D 17 0 true false false false",
- "D 84 0 true false false false",
- "U 84 0 true false false false",
- "U 17 0 true false false false" }
- };
+ // Press Ctrl/Cmd+T, which will open a new tab. It cannot be suppressed.
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(0, kTestCtrlOrCmdT));
- static const KeyEventTestData kTestCtrlWBlocked = {
- app::VKEY_W, true, false, false, false,
- true, false, false, false, 4,
- { "D 17 0 true false false false",
- "D 87 0 true false false false",
- "U 87 0 true false false false",
- "U 17 0 true false false false" }
- };
+ ASSERT_NO_FATAL_FAILURE(
+ wait_for_new_tab.WaitFor(Source<NavigationController>(
+ &browser()->GetTabContentsAt(1)->controller())));
- ASSERT_EQ(1, browser()->tab_count());
-
- // Ctrl+T should be blockable.
- EXPECT_NO_FATAL_FAILURE(TestKeyEvent(0, kTestCtrlTBlocked));
- ASSERT_EQ(1, browser()->tab_count());
+ int result_length;
+ ASSERT_NO_FATAL_FAILURE(GetResultLength(0, &result_length));
+ EXPECT_EQ(1, result_length);
- EXPECT_NO_FATAL_FAILURE(TestKeyEvent(0, kTestCtrlT));
- ASSERT_EQ(2, browser()->tab_count());
+ EXPECT_EQ(2, browser()->tab_count());
ASSERT_EQ(1, browser()->selected_index());
- browser()->SelectNumberedTab(0);
- ASSERT_EQ(0, browser()->selected_index());
- // Ctrl+PageDown and Ctrl+Tab switches to the next tab.
- EXPECT_NO_FATAL_FAILURE(TestKeyEvent(0, kTestCtrlPageDown));
- ASSERT_EQ(1, browser()->selected_index());
+ // Because of issue http://crbug.com/65375, switching back to the first tab
+ // may cause the focus to be grabbed by omnibox. So instead, we load our
+ // testing page in the newly created tab and try Cmd-W here.
+ ui_test_utils::NavigateToURL(browser(), url);
- browser()->SelectNumberedTab(0);
- ASSERT_EQ(0, browser()->selected_index());
- EXPECT_NO_FATAL_FAILURE(TestKeyEvent(0, kTestCtrlTab));
- ASSERT_EQ(1, browser()->selected_index());
+ // Make sure the focus is in the testing page.
+ ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
+ ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
+
+ // Reserved accelerators can't be suppressed.
+ ASSERT_NO_FATAL_FAILURE(SuppressAllEvents(1, true));
- // Ctrl+W should be blockable.
- browser()->SelectNumberedTab(0);
- ASSERT_EQ(0, browser()->selected_index());
- EXPECT_NO_FATAL_FAILURE(TestKeyEvent(0, kTestCtrlWBlocked));
- ASSERT_EQ(2, browser()->tab_count());
+ ui_test_utils::WindowedNotificationObserver wait_for_tab_closed(
+ NotificationType::TAB_CLOSED, Source<NavigationController>(
+ &browser()->GetTabContentsAt(1)->controller()));
- // Ctrl+F4 to close the tab.
- ASSERT_NO_FATAL_FAILURE(SuppressAllEvents(0, true));
+ // Press Ctrl/Cmd+W, which will close the tab.
+#if defined(OS_MACOSX)
ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
- browser(), app::VKEY_F4, true, false, false, false));
- ASSERT_EQ(1, browser()->tab_count());
+ browser(), app::VKEY_W, false, false, false, true));
+#else
+ ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
+ browser(), app::VKEY_W, true, false, false, false));
#endif
+
+ ASSERT_NO_FATAL_FAILURE(wait_for_tab_closed.Wait());
+
+ EXPECT_EQ(1, browser()->tab_count());
}
#if defined(OS_MACOSX)
diff --git a/chrome/browser/browser_main.cc b/chrome/browser/browser_main.cc
index 0e5d339..030e1ee 100644
--- a/chrome/browser/browser_main.cc
+++ b/chrome/browser/browser_main.cc
@@ -42,7 +42,7 @@
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
#include "chrome/browser/extensions/extension_protocols.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extensions_startup.h"
#include "chrome/browser/first_run/first_run.h"
#include "chrome/browser/jankometer.h"
@@ -61,8 +61,8 @@
#include "chrome/browser/prefs/pref_value_store.h"
#include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h"
#include "chrome/browser/process_singleton.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/search_engines/search_engine_type.h"
#include "chrome/browser/search_engines/template_url.h"
@@ -86,7 +86,6 @@
#include "chrome/common/pref_names.h"
#include "chrome/common/result_codes.h"
#include "chrome/installer/util/google_update_settings.h"
-#include "chrome/installer/util/master_preferences.h"
#include "grit/app_locale_settings.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
@@ -101,6 +100,7 @@
#include "net/spdy/spdy_session.h"
#include "net/spdy/spdy_session_pool.h"
#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_throttler_manager.h"
#if defined(USE_LINUX_BREAKPAD)
#include "base/linux_util.h"
@@ -139,7 +139,6 @@
#include "chrome/installer/util/helper.h"
#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/shell_util.h"
-#include "chrome/installer/util/version.h"
#include "gfx/platform_font_win.h"
#include "net/base/net_util.h"
#include "net/base/sdch_manager.h"
@@ -149,7 +148,7 @@
#if defined(OS_MACOSX)
#include <Security/Security.h>
-#include "chrome/browser/cocoa/install_from_dmg.h"
+#include "chrome/browser/ui/cocoa/install_from_dmg.h"
#endif
#if defined(TOOLKIT_VIEWS)
@@ -189,6 +188,9 @@ BrowserMainParts::~BrowserMainParts() {
void BrowserMainParts::EarlyInitialization() {
PreEarlyInitialization();
+ if (parsed_command_line().HasSwitch(switches::kEnableBenchmarking))
+ base::FieldTrial::EnableBenchmarking();
+
// Note: make sure to call ConnectionFieldTrial() before
// ProxyConnectionsFieldTrial().
ConnectionFieldTrial();
@@ -379,6 +381,22 @@ void BrowserMainParts::SpdyFieldTrial() {
CHECK(!is_spdy_trial);
}
}
+
+ // Setup SPDY CWND Field trial.
+ const base::FieldTrial::Probability kSpdyCwndDivisor = 100;
+ const base::FieldTrial::Probability kSpdyCwnd32 = 20; // fixed at 32
+ const base::FieldTrial::Probability kSpdyCwnd16 = 20; // fixed at 16
+ const base::FieldTrial::Probability kSpdyCwndMin16 = 20; // no less than 16
+ const base::FieldTrial::Probability kSpdyCwndMin10 = 20; // no less than 10
+ scoped_refptr<base::FieldTrial> trial(
+ new base::FieldTrial("SpdyCwnd", kSpdyCwndDivisor));
+ trial->AppendGroup("cwnd32", kSpdyCwnd32);
+ trial->AppendGroup("cwnd16", kSpdyCwnd16);
+ trial->AppendGroup("cwndMin16", kSpdyCwndMin16);
+ trial->AppendGroup("cwndMin10", kSpdyCwndMin10);
+ trial->AppendGroup("cwndDynamic",
+ base::FieldTrial::kAllRemainingProbability);
+
if (parsed_command_line().HasSwitch(switches::kMaxSpdyConcurrentStreams)) {
int value = 0;
base::StringToInt(parsed_command_line().GetSwitchValueASCII(
@@ -389,16 +407,19 @@ void BrowserMainParts::SpdyFieldTrial() {
}
}
-// If neither --enable-content-prefetch or --disable-content-prefetch
-// is set, users will not be in an A/B test for prefetching.
+// If any of --enable-prerender, --enable-content-prefetch or
+// --disable-content-prefetch are set, use those to determine if
+// prefetch is enabled. Otherwise, randomly assign users to an A/B test for
+// prefetching.
void BrowserMainParts::PrefetchFieldTrial() {
- if (parsed_command_line().HasSwitch(switches::kEnableContentPrefetch))
+ if (parsed_command_line().HasSwitch(switches::kEnableContentPrefetch) ||
+ parsed_command_line().HasSwitch(switches::kEnablePagePrerender))
ResourceDispatcherHost::set_is_prefetch_enabled(true);
else if (parsed_command_line().HasSwitch(switches::kDisableContentPrefetch)) {
ResourceDispatcherHost::set_is_prefetch_enabled(false);
} else {
const base::FieldTrial::Probability kPrefetchDivisor = 1000;
- const base::FieldTrial::Probability no_prefetch_probability = 970;
+ const base::FieldTrial::Probability no_prefetch_probability = 500;
scoped_refptr<base::FieldTrial> trial(
new base::FieldTrial("Prefetch", kPrefetchDivisor));
trial->AppendGroup("ContentPrefetchDisabled", no_prefetch_probability);
@@ -566,6 +587,11 @@ void InitializeNetworkOptions(const CommandLine& parsed_command_line) {
net::SpdySessionPool::set_max_sessions_per_domain(value);
}
+ if (parsed_command_line.HasSwitch(switches::kDisableEnforcedThrottling)) {
+ net::URLRequestThrottlerManager::GetInstance()->
+ set_enforce_throttling(false);
+ }
+
SetDnsCertProvenanceCheckerFactory(CreateChromeDnsCertProvenanceChecker);
}
@@ -629,7 +655,7 @@ PrefService* InitializeLocalState(const CommandLine& parsed_command_line,
FilePath parent_profile =
parsed_command_line.GetSwitchValuePath(switches::kParentProfile);
scoped_ptr<PrefService> parent_local_state(
- PrefService::CreatePrefService(parent_profile, NULL));
+ PrefService::CreatePrefService(parent_profile, NULL, NULL));
parent_local_state->RegisterStringPref(prefs::kApplicationLocale,
std::string());
// Right now, we only inherit the locale setting from the parent profile.
@@ -668,7 +694,7 @@ void InitializeBrokerServices(const MainFunctionParams& parameters,
MetricsService* InitializeMetrics(const CommandLine& parsed_command_line,
const PrefService* local_state) {
#if defined(OS_WIN)
- if (InstallUtil::IsChromeFrameProcess())
+ if (parsed_command_line.HasSwitch(switches::kChromeFrame))
MetricsLog::set_version_extension("-F");
#elif defined(ARCH_CPU_64_BITS)
MetricsLog::set_version_extension("-64");
@@ -676,7 +702,8 @@ MetricsService* InitializeMetrics(const CommandLine& parsed_command_line,
MetricsService* metrics = g_browser_process->metrics_service();
- if (parsed_command_line.HasSwitch(switches::kMetricsRecordingOnly)) {
+ if (parsed_command_line.HasSwitch(switches::kMetricsRecordingOnly) ||
+ parsed_command_line.HasSwitch(switches::kEnableBenchmarking)) {
// If we're testing then we don't care what the user preference is, we turn
// on recording, but not reporting, otherwise tests fail.
metrics->StartRecordingOnly();
@@ -913,7 +940,10 @@ class StubLogin : public chromeos::LoginStatusConsumer {
const std::string& password,
const GaiaAuthConsumer::ClientLoginResult& credentials,
bool pending_requests) {
- chromeos::LoginUtils::Get()->CompleteLogin(username, password, credentials);
+ chromeos::LoginUtils::Get()->CompleteLogin(username,
+ password,
+ credentials,
+ pending_requests);
delete this;
}
@@ -1077,8 +1107,8 @@ int BrowserMain(const MainFunctionParams& parameters) {
if (parsed_command_line.HasSwitch(switches::kImport) ||
parsed_command_line.HasSwitch(switches::kImportFromFile)) {
// We use different BrowserProcess when importing so no GoogleURLTracker is
- // instantiated (as it makes a URLRequest and we don't have an IO thread,
- // see bug #1292702).
+ // instantiated (as it makes a net::URLRequest and we don't have an IO
+ // thread, see bug #1292702).
browser_process.reset(new FirstRunBrowserProcess(parsed_command_line));
is_first_run = false;
} else {
@@ -1258,8 +1288,12 @@ int BrowserMain(const MainFunctionParams& parameters) {
// If the command line specifies --pack-extension, attempt the pack extension
// startup action and exit.
if (parsed_command_line.HasSwitch(switches::kPackExtension)) {
- extensions_startup::HandlePackExtension(parsed_command_line);
- return ResultCodes::NORMAL_EXIT;
+ ExtensionsStartupUtil extension_startup_util;
+ if (extension_startup_util.PackExtension(parsed_command_line)) {
+ return ResultCodes::NORMAL_EXIT;
+ } else {
+ return ResultCodes::PACK_EXTENSION_ERROR;
+ }
}
#if !defined(OS_MACOSX)
@@ -1325,7 +1359,7 @@ int BrowserMain(const MainFunctionParams& parameters) {
// Allow access to file:// on ChromeOS for tests.
if (parsed_command_line.HasSwitch(switches::kAllowFileAccess)) {
- URLRequest::AllowFileAccess();
+ net::URLRequest::AllowFileAccess();
}
// There are two use cases for kLoginUser:
@@ -1390,7 +1424,7 @@ int BrowserMain(const MainFunctionParams& parameters) {
return ResultCodes::MACHINE_LEVEL_INSTALL_EXISTS;
// Create the TranslateManager singleton.
- Singleton<TranslateManager>::get();
+ TranslateManager::GetInstance();
#if defined(OS_MACOSX)
if (!parsed_command_line.HasSwitch(switches::kNoFirstRun)) {
@@ -1544,18 +1578,18 @@ int BrowserMain(const MainFunctionParams& parameters) {
// Initialize extension event routers. Note that on Chrome OS, this will
// not succeed if the user has not logged in yet, in which case the
// event routers are initialized in LoginUtilsImpl::CompleteLogin instead.
- if (profile->GetExtensionsService()) {
+ if (profile->GetExtensionService()) {
// This will initialize bookmarks. Call it after bookmark import is done.
// See issue 40144.
- profile->GetExtensionsService()->InitEventRouters();
+ profile->GetExtensionService()->InitEventRouters();
}
// The extension service may be available at this point. If the command line
// specifies --uninstall-extension, attempt the uninstall extension startup
// action.
if (parsed_command_line.HasSwitch(switches::kUninstallExtension)) {
- if (extensions_startup::HandleUninstallExtension(parsed_command_line,
- profile)) {
+ ExtensionsStartupUtil ext_startup_util;
+ if (ext_startup_util.UninstallExtension(parsed_command_line, profile)) {
return ResultCodes::NORMAL_EXIT;
} else {
return ResultCodes::UNINSTALL_EXTENSION_ERROR;
@@ -1582,8 +1616,9 @@ int BrowserMain(const MainFunctionParams& parameters) {
// TODO(hclam): Need to check for cloud print proxy too.
if (parsed_command_line.HasSwitch(switches::kEnableRemoting)) {
if (user_prefs->GetBoolean(prefs::kRemotingHasSetupCompleted)) {
- ServiceProcessControl* control = ServiceProcessControlManager::instance()
- ->GetProcessControl(profile);
+ ServiceProcessControl* control =
+ ServiceProcessControlManager::GetInstance()->GetProcessControl(
+ profile);
control->Launch(NULL, NULL);
}
}
diff --git a/chrome/browser/browser_main_gtk.cc b/chrome/browser/browser_main_gtk.cc
index 924bffd..ec73aaf 100644
--- a/chrome/browser/browser_main_gtk.cc
+++ b/chrome/browser/browser_main_gtk.cc
@@ -86,9 +86,9 @@ void BrowserMainPartsGtk::SetupSandbox() {
sandbox_cmd = sandbox_binary;
// Tickle the sandbox host and zygote host so they fork now.
- RenderSandboxHostLinux* shost = Singleton<RenderSandboxHostLinux>::get();
+ RenderSandboxHostLinux* shost = RenderSandboxHostLinux::GetInstance();
shost->Init(sandbox_cmd);
- ZygoteHost* zhost = Singleton<ZygoteHost>::get();
+ ZygoteHost* zhost = ZygoteHost::GetInstance();
zhost->Init(sandbox_cmd);
}
diff --git a/chrome/browser/browser_main_mac.mm b/chrome/browser/browser_main_mac.mm
index 21529c4..619be2d 100644
--- a/chrome/browser/browser_main_mac.mm
+++ b/chrome/browser/browser_main_mac.mm
@@ -20,12 +20,11 @@
#import "chrome/browser/app_controller_mac.h"
#include "chrome/browser/browser_main_win.h"
#import "chrome/browser/chrome_browser_application_mac.h"
-#import "chrome/browser/cocoa/keystone_glue.h"
+#import "chrome/browser/ui/cocoa/keystone_glue.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/main_function_params.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/result_codes.h"
#include "net/socket/ssl_client_socket_mac_factory.h"
diff --git a/chrome/browser/browser_main_win.cc b/chrome/browser/browser_main_win.cc
index f4f9a59..bd5573a 100644
--- a/chrome/browser/browser_main_win.cc
+++ b/chrome/browser/browser_main_win.cc
@@ -29,6 +29,7 @@
#include "chrome/common/env_vars.h"
#include "chrome/common/main_function_params.h"
#include "chrome/common/result_codes.h"
+#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/helper.h"
#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/shell_util.h"
@@ -99,9 +100,12 @@ int DoUninstallTasks(bool chrome_still_running) {
VLOG(1) << "Failed to delete sentinel file.";
// We want to remove user level shortcuts and we only care about the ones
// created by us and not by the installer so |alternate| is false.
- if (!ShellUtil::RemoveChromeDesktopShortcut(ShellUtil::CURRENT_USER, false))
+ BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+ if (!ShellUtil::RemoveChromeDesktopShortcut(dist, ShellUtil::CURRENT_USER,
+ false))
VLOG(1) << "Failed to delete desktop shortcut.";
- if (!ShellUtil::RemoveChromeQuickLaunchShortcut(ShellUtil::CURRENT_USER))
+ if (!ShellUtil::RemoveChromeQuickLaunchShortcut(dist,
+ ShellUtil::CURRENT_USER))
VLOG(1) << "Failed to delete quick launch shortcut.";
}
return ret;
@@ -176,26 +180,27 @@ int HandleIconsCommands(const CommandLine &parsed_command_line) {
// allow the user level Chrome to run. So we notify the user and uninstall
// user level Chrome.
bool CheckMachineLevelInstall() {
- scoped_ptr<installer::Version> version(InstallUtil::GetChromeVersion(true));
+ // TODO(tommi): Check if using the default distribution is always the right
+ // thing to do.
+ BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+ scoped_ptr<Version> version(InstallUtil::GetChromeVersion(dist, true));
if (version.get()) {
- std::wstring exe;
- PathService::Get(base::DIR_EXE, &exe);
- std::transform(exe.begin(), exe.end(), exe.begin(), tolower);
- std::wstring user_exe_path = installer::GetChromeInstallPath(false);
- std::transform(user_exe_path.begin(), user_exe_path.end(),
- user_exe_path.begin(), tolower);
- if (exe == user_exe_path) {
+ FilePath exe_path;
+ PathService::Get(base::DIR_EXE, &exe_path);
+ std::wstring exe = exe_path.value();
+ FilePath user_exe_path(installer::GetChromeInstallPath(false, dist));
+ if (FilePath::CompareEqualIgnoreCase(exe, user_exe_path.value())) {
const std::wstring text =
l10n_util::GetString(IDS_MACHINE_LEVEL_INSTALL_CONFLICT);
const std::wstring caption = l10n_util::GetString(IDS_PRODUCT_NAME);
const UINT flags = MB_OK | MB_ICONERROR | MB_TOPMOST;
win_util::MessageBox(NULL, text, caption, flags);
- FilePath uninstall_path(InstallUtil::GetChromeUninstallCmd(false));
+ FilePath uninstall_path(InstallUtil::GetChromeUninstallCmd(false, dist));
CommandLine uninstall_cmd(uninstall_path);
if (!uninstall_cmd.GetProgram().value().empty()) {
- uninstall_cmd.AppendSwitch(installer_util::switches::kForceUninstall);
+ uninstall_cmd.AppendSwitch(installer::switches::kForceUninstall);
uninstall_cmd.AppendSwitch(
- installer_util::switches::kDoNotRemoveSharedItems);
+ installer::switches::kDoNotRemoveSharedItems);
base::LaunchApp(uninstall_cmd, false, false, NULL);
}
return true;
diff --git a/chrome/browser/browser_message_filter.cc b/chrome/browser/browser_message_filter.cc
new file mode 100644
index 0000000..d226af4
--- /dev/null
+++ b/chrome/browser/browser_message_filter.cc
@@ -0,0 +1,91 @@
+// 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.
+
+#include "chrome/browser/browser_message_filter.h"
+
+#include "base/logging.h"
+#include "base/process.h"
+#include "base/process_util.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/common/result_codes.h"
+
+BrowserMessageFilter::BrowserMessageFilter()
+ : channel_(NULL), peer_handle_(base::kNullProcessHandle) {
+}
+
+BrowserMessageFilter::~BrowserMessageFilter() {
+}
+
+void BrowserMessageFilter::OnFilterAdded(IPC::Channel* channel) {
+ channel_ = channel;
+}
+
+void BrowserMessageFilter::OnChannelClosing() {
+ channel_ = NULL;
+}
+
+void BrowserMessageFilter::OnChannelConnected(int32 peer_pid) {
+ if (!base::OpenProcessHandle(peer_pid, &peer_handle_)) {
+ NOTREACHED();
+ }
+}
+
+bool BrowserMessageFilter::Send(IPC::Message* message) {
+ if (message->is_sync()) {
+ // We don't support sending synchronous messages from the browser. If we
+ // really needed it, we can make this class derive from SyncMessageFilter
+ // but it seems better to not allow sending synchronous messages from the
+ // browser, since it might allow a corrupt/malicious renderer to hang us.
+ NOTREACHED() << "Can't send sync message through BrowserMessageFilter!";
+ return false;
+ }
+
+ if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ NewRunnableMethod(this, &BrowserMessageFilter::Send, message));
+ return true;
+ }
+
+ if (channel_)
+ return channel_->Send(message);
+
+ delete message;
+ return false;
+}
+
+void BrowserMessageFilter::OverrideThreadForMessage(const IPC::Message& message,
+ BrowserThread::ID* thread) {
+}
+
+bool BrowserMessageFilter::OnMessageReceived(const IPC::Message& message) {
+ BrowserThread::ID thread = BrowserThread::IO;
+ OverrideThreadForMessage(message, &thread);
+ if (thread == BrowserThread::IO)
+ return DispatchMessage(message);
+
+ BrowserThread::PostTask(
+ thread, FROM_HERE,
+ NewRunnableMethod(
+ this, &BrowserMessageFilter::DispatchMessage, message));
+ return true;
+}
+
+bool BrowserMessageFilter::DispatchMessage(const IPC::Message& message) {
+ bool message_was_ok = true;
+ bool rv = OnMessageReceived(message, &message_was_ok);
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO) || rv) <<
+ "Must handle messages that were dispatched to another thread!";
+ if (!message_was_ok) {
+ UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_BMF"));
+ BadMessageReceived();
+ }
+
+ return rv;
+}
+
+void BrowserMessageFilter::BadMessageReceived() {
+ base::KillProcess(peer_handle(), ResultCodes::KILLED_BAD_MESSAGE, false);
+}
diff --git a/chrome/browser/browser_message_filter.h b/chrome/browser/browser_message_filter.h
new file mode 100644
index 0000000..19f5c7d
--- /dev/null
+++ b/chrome/browser/browser_message_filter.h
@@ -0,0 +1,64 @@
+// 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.
+
+#ifndef CHROME_BROWSER_BROWSER_MESSAGE_FILTER_H_
+#define CHROME_BROWSER_BROWSER_MESSAGE_FILTER_H_
+#pragma once
+
+#include "base/process.h"
+#include "chrome/browser/browser_thread.h"
+#include "ipc/ipc_channel_proxy.h"
+
+// Base class for message filters in the browser process. You can receive and
+// send messages on any thread.
+class BrowserMessageFilter : public IPC::ChannelProxy::MessageFilter,
+ public IPC::Message::Sender {
+ public:
+ BrowserMessageFilter();
+ virtual ~BrowserMessageFilter();
+
+ // IPC::ChannelProxy::MessageFilter methods. If you override them, make sure
+ // to call them as well. These are always called on the IO thread.
+ virtual void OnFilterAdded(IPC::Channel* channel);
+ virtual void OnChannelClosing();
+ virtual void OnChannelConnected(int32 peer_pid);
+ // DON'T OVERRIDE THIS! Override the other version below.
+ virtual bool OnMessageReceived(const IPC::Message& message);
+
+ // IPC::Message::Sender implementation. Can be called on any thread. Can't
+ // send sync messages (since we don't want to block the browser on any other
+ // process).
+ virtual bool Send(IPC::Message* message);
+
+ // If you want the given message to be dispatched to your OnMessageReceived on
+ // a different thread, change |thread| to the id of the target thread.
+ // If you don't handle this message, or want to keep it on the IO thread, do
+ // nothing.
+ virtual void OverrideThreadForMessage(const IPC::Message& message,
+ BrowserThread::ID* thread);
+
+ // Override this to receive messages.
+ // Your function will normally be called on the IO thread. However, if your
+ // OverrideThreadForMessage modifies the thread used to dispatch the message,
+ // your function will be called on the requested thread.
+ virtual bool OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok) = 0;
+
+ // Can be called on any thread, after OnChannelConnected is called.
+ base::ProcessHandle peer_handle() { return peer_handle_; }
+
+ protected:
+ // Call this if a message couldn't be deserialized. This kills the renderer.
+ // Can be called on any thread.
+ virtual void BadMessageReceived();
+
+ private:
+ // Dispatches a message to the derived class.
+ bool DispatchMessage(const IPC::Message& message);
+
+ IPC::Channel* channel_;
+ base::ProcessHandle peer_handle_;
+};
+
+#endif // CHROME_BROWSER_BROWSER_MESSAGE_FILTER_H_
diff --git a/chrome/browser/browser_process.h b/chrome/browser/browser_process.h
index 7c2e307..b9510a8 100644
--- a/chrome/browser/browser_process.h
+++ b/chrome/browser/browser_process.h
@@ -18,13 +18,19 @@
#include "ipc/ipc_message.h"
class AutomationProviderList;
+
+namespace safe_browsing {
+class ClientSideDetectionService;
+}
+
class Clipboard;
class DevToolsManager;
class DownloadRequestLimiter;
class DownloadStatusUpdater;
class GoogleURLTracker;
-class IntranetRedirectDetector;
class IconManager;
+class IntranetRedirectDetector;
+class IOThread;
class MetricsService;
class NotificationUIManager;
class PrefService;
@@ -44,8 +50,6 @@ class PrintJobManager;
class PrintPreviewTabController;
}
-class IOThread;
-
// NOT THREAD SAFE, call only from the main thread.
// These functions shouldn't return NULL unless otherwise noted.
class BrowserProcess {
@@ -141,6 +145,11 @@ class BrowserProcess {
// Returns the object that watches for changes in the closeable state of tab.
virtual TabCloseableStateWatcher* tab_closeable_state_watcher() = 0;
+ // Returns an object which handles communication with the SafeBrowsing
+ // client-side detection servers.
+ virtual safe_browsing::ClientSideDetectionService*
+ safe_browsing_detection_service() = 0;
+
// Trigger an asynchronous check to see if we have the inspector's files on
// disk.
virtual void CheckForInspectorFiles() = 0;
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 33659d0..d60b672 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -13,6 +13,7 @@
#include "base/path_service.h"
#include "base/task.h"
#include "base/thread.h"
+#include "base/thread_restrictions.h"
#include "base/waitable_event.h"
#include "chrome/browser/appcache/chrome_appcache_service.h"
#include "chrome/browser/automation/automation_provider_list.h"
@@ -29,23 +30,23 @@
#include "chrome/browser/first_run/first_run.h"
#include "chrome/browser/google/google_url_tracker.h"
#include "chrome/browser/icon_manager.h"
-#include "chrome/browser/in_process_webkit/dom_storage_context.h"
-#include "chrome/browser/in_process_webkit/indexed_db_context.h"
#include "chrome/browser/intranet_redirect_detector.h"
#include "chrome/browser/io_thread.h"
#include "chrome/browser/metrics/metrics_service.h"
+#include "chrome/browser/net/chrome_net_log.h"
#include "chrome/browser/net/predictor_api.h"
#include "chrome/browser/net/sdch_dictionary_fetcher.h"
-#include "chrome/browser/net/sqlite_persistent_cookie_store.h"
#include "chrome/browser/notifications/notification_ui_manager.h"
+#include "chrome/browser/plugin_data_remover.h"
#include "chrome/browser/plugin_service.h"
#include "chrome/browser/plugin_updater.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/printing/print_job_manager.h"
#include "chrome/browser/printing/print_preview_tab_controller.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+#include "chrome/browser/safe_browsing/client_side_detection_service.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/browser/sidebar/sidebar_manager.h"
#include "chrome/browser/tab_closeable_state_watcher.h"
@@ -100,6 +101,7 @@ BrowserProcessImpl::BrowserProcessImpl(const CommandLine& command_line)
created_devtools_manager_(false),
created_sidebar_manager_(false),
created_notification_ui_manager_(false),
+ created_safe_browsing_detection_service_(false),
module_ref_count_(0),
did_start_(false),
checked_for_new_frames_(false),
@@ -109,10 +111,16 @@ BrowserProcessImpl::BrowserProcessImpl(const CommandLine& command_line)
clipboard_.reset(new Clipboard);
main_notification_service_.reset(new NotificationService);
+ notification_registrar_.Add(this,
+ NotificationType::APP_TERMINATING,
+ NotificationService::AllSources());
+
// Must be created after the NotificationService.
print_job_manager_.reset(new printing::PrintJobManager);
shutdown_event_.reset(new base::WaitableEvent(true, false));
+
+ net_log_.reset(new ChromeNetLog);
}
BrowserProcessImpl::~BrowserProcessImpl() {
@@ -172,6 +180,9 @@ BrowserProcessImpl::~BrowserProcessImpl() {
background_x11_thread_.reset();
#endif
+ // Wait for removing plugin data to finish before shutting down the IO thread.
+ WaitForPluginDataRemoverToFinish();
+
// Need to stop io_thread_ before resource_dispatcher_host_, since
// io_thread_ may still deref ResourceDispatcherHost and handle resource
// request before going away.
@@ -250,6 +261,12 @@ unsigned int BrowserProcessImpl::ReleaseModule() {
DCHECK_NE(0u, module_ref_count_);
module_ref_count_--;
if (0 == module_ref_count_) {
+ // Allow UI and IO threads to do blocking IO on shutdown, since we do a lot
+ // of it on shutdown for valid reasons.
+ base::ThreadRestrictions::SetIOAllowed(true);
+ io_thread()->message_loop()->PostTask(
+ FROM_HERE,
+ NewRunnableFunction(&base::ThreadRestrictions::SetIOAllowed, true));
MessageLoop::current()->PostTask(
FROM_HERE, NewRunnableFunction(DidEndMainMessageLoop));
MessageLoop::current()->Quit();
@@ -483,12 +500,49 @@ TabCloseableStateWatcher* BrowserProcessImpl::tab_closeable_state_watcher() {
return tab_closeable_state_watcher_.get();
}
+safe_browsing::ClientSideDetectionService*
+ BrowserProcessImpl::safe_browsing_detection_service() {
+ DCHECK(CalledOnValidThread());
+ if (!created_safe_browsing_detection_service_) {
+ CreateSafeBrowsingDetectionService();
+ }
+ return safe_browsing_detection_service_.get();
+}
+
void BrowserProcessImpl::CheckForInspectorFiles() {
file_thread()->message_loop()->PostTask
(FROM_HERE,
NewRunnableMethod(this, &BrowserProcessImpl::DoInspectorFilesCheck));
}
+void BrowserProcessImpl::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NotificationType::APP_TERMINATING) {
+ Profile* profile = ProfileManager::GetDefaultProfile();
+ if (profile) {
+ PrefService* prefs = profile->GetPrefs();
+ if (prefs->GetBoolean(prefs::kClearPluginLSODataOnExit) &&
+ local_state()->GetBoolean(prefs::kClearPluginLSODataEnabled)) {
+ plugin_data_remover_ = new PluginDataRemover();
+ plugin_data_remover_->StartRemoving(base::Time(), NULL);
+ }
+ }
+ } else {
+ NOTREACHED();
+ }
+}
+
+void BrowserProcessImpl::WaitForPluginDataRemoverToFinish() {
+ if (!plugin_data_remover_.get() || !plugin_data_remover_->is_removing())
+ return;
+ plugin_data_remover_->set_done_task(new MessageLoop::QuitTask());
+ base::Time start_time(base::Time::Now());
+ MessageLoop::current()->Run();
+ UMA_HISTOGRAM_TIMES("ClearPluginData.wait_at_shutdown",
+ base::Time::Now() - start_time);
+}
+
#if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
void BrowserProcessImpl::StartAutoupdateTimer() {
autoupdate_timer_.Start(
@@ -503,10 +557,6 @@ bool BrowserProcessImpl::have_inspector_files() const {
}
void BrowserProcessImpl::ClearLocalState(const FilePath& profile_path) {
- SQLitePersistentCookieStore::ClearLocalState(profile_path.Append(
- chrome::kCookieFilename));
- DOMStorageContext::ClearLocalState(profile_path, chrome::kExtensionScheme);
- IndexedDBContext::ClearLocalState(profile_path, chrome::kExtensionScheme);
webkit_database::DatabaseTracker::ClearLocalState(profile_path);
ChromeAppCacheService::ClearLocalState(profile_path);
}
@@ -566,7 +616,7 @@ void BrowserProcessImpl::CreateIOThread() {
background_x11_thread_.swap(background_x11_thread);
#endif
- scoped_ptr<IOThread> thread(new IOThread(local_state()));
+ scoped_ptr<IOThread> thread(new IOThread(local_state(), net_log_.get()));
base::Thread::Options options;
options.message_loop_type = MessageLoop::TYPE_IO;
if (!thread->StartWithOptions(options))
@@ -641,7 +691,8 @@ void BrowserProcessImpl::CreateLocalState() {
FilePath local_state_path;
PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path);
- local_state_.reset(PrefService::CreatePrefService(local_state_path, NULL));
+ local_state_.reset(
+ PrefService::CreatePrefService(local_state_path, NULL, NULL));
pref_change_registrar_.Init(local_state_.get());
@@ -649,7 +700,7 @@ void BrowserProcessImpl::CreateLocalState() {
// in the plugin blacklist.
local_state_->RegisterListPref(prefs::kPluginsPluginsBlacklist);
pref_change_registrar_.Add(prefs::kPluginsPluginsBlacklist,
- PluginUpdater::GetPluginUpdater());
+ PluginUpdater::GetInstance());
// Initialize and set up notifications for the printing enabled
// preference.
@@ -715,6 +766,38 @@ void BrowserProcessImpl::CreatePrintPreviewTabController() {
print_preview_tab_controller_ = new printing::PrintPreviewTabController();
}
+void BrowserProcessImpl::CreateSafeBrowsingDetectionService() {
+ DCHECK(safe_browsing_detection_service_.get() == NULL);
+ // Set this flag to true so that we don't retry indefinitely to
+ // create the service class if there was an error.
+ created_safe_browsing_detection_service_ = true;
+
+ FilePath model_file_path;
+ Profile* profile = profile_manager() ?
+ profile_manager()->GetDefaultProfile() : NULL;
+ if (IsSafeBrowsingDetectionServiceEnabled() &&
+ PathService::Get(chrome::DIR_USER_DATA, &model_file_path) &&
+ profile && profile->GetRequestContext()) {
+ safe_browsing_detection_service_.reset(
+ safe_browsing::ClientSideDetectionService::Create(
+ model_file_path.Append(chrome::kSafeBrowsingPhishingModelFilename),
+ profile->GetRequestContext()));
+ }
+}
+
+bool BrowserProcessImpl::IsSafeBrowsingDetectionServiceEnabled() {
+ // The safe browsing client-side detection is enabled only if the switch is
+ // enabled, the user has opted in to UMA usage stats and SafeBrowsing
+ // is enabled.
+ Profile* profile = profile_manager() ?
+ profile_manager()->GetDefaultProfile() : NULL;
+ return (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableClientSidePhishingDetection) &&
+ metrics_service() && metrics_service()->reporting_active() &&
+ profile && profile->GetPrefs() &&
+ profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled));
+}
+
// The BrowserProcess object must outlive the file thread so we use traits
// which don't do any management.
DISABLE_RUNNABLE_METHOD_REFCOUNT(BrowserProcessImpl);
@@ -724,9 +807,9 @@ DISABLE_RUNNABLE_METHOD_REFCOUNT(BrowserProcessImpl);
void BrowserProcessImpl::SetIPCLoggingEnabled(bool enable) {
// First enable myself.
if (enable)
- IPC::Logging::current()->Enable();
+ IPC::Logging::GetInstance()->Enable();
else
- IPC::Logging::current()->Disable();
+ IPC::Logging::GetInstance()->Disable();
// Now tell subprocesses. Messages to ChildProcess-derived
// processes must be done on the IO thread.
diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h
index 0aeb976..c763d31 100644
--- a/chrome/browser/browser_process_impl.h
+++ b/chrome/browser/browser_process_impl.h
@@ -22,22 +22,29 @@
#include "chrome/browser/download/download_status_updater.h"
#include "chrome/browser/prefs/pref_change_registrar.h"
#include "chrome/browser/tab_contents/thumbnail_generator.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
#include "ipc/ipc_message.h"
+class ChromeNetLog;
class CommandLine;
class DebuggerWrapper;
class FilePath;
class NotificationService;
+class PluginDataRemover;
class TabCloseableStateWatcher;
// Real implementation of BrowserProcess that creates and returns the services.
-class BrowserProcessImpl : public BrowserProcess, public NonThreadSafe {
+class BrowserProcessImpl : public BrowserProcess,
+ public NonThreadSafe,
+ public NotificationObserver {
public:
explicit BrowserProcessImpl(const CommandLine& command_line);
virtual ~BrowserProcessImpl();
virtual void EndSession();
+ // BrowserProcess methods
virtual ResourceDispatcherHost* resource_dispatcher_host();
virtual MetricsService* metrics_service();
virtual IOThread* io_thread();
@@ -70,10 +77,17 @@ class BrowserProcessImpl : public BrowserProcess, public NonThreadSafe {
virtual DownloadStatusUpdater* download_status_updater();
virtual base::WaitableEvent* shutdown_event();
virtual TabCloseableStateWatcher* tab_closeable_state_watcher();
+ virtual safe_browsing::ClientSideDetectionService*
+ safe_browsing_detection_service();
virtual void CheckForInspectorFiles();
+ // NotificationObserver methods
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
#if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
- void StartAutoupdateTimer();
+ virtual void StartAutoupdateTimer();
#endif
virtual bool have_inspector_files() const;
@@ -93,6 +107,8 @@ class BrowserProcessImpl : public BrowserProcess, public NonThreadSafe {
void CreateIOThread();
static void CleanupOnIOThread();
+ void WaitForPluginDataRemoverToFinish();
+
void CreateFileThread();
void CreateDBThread();
void CreateProcessLauncherThread();
@@ -112,6 +128,9 @@ class BrowserProcessImpl : public BrowserProcess, public NonThreadSafe {
void CreateStatusTrayManager();
void CreateTabCloseableStateWatcher();
void CreatePrintPreviewTabController();
+ void CreateSafeBrowsingDetectionService();
+
+ bool IsSafeBrowsingDetectionServiceEnabled();
#if defined(IPC_MESSAGE_LOG_ENABLED)
void SetIPCLoggingEnabledForChildProcesses(bool enabled);
@@ -178,6 +197,10 @@ class BrowserProcessImpl : public BrowserProcess, public NonThreadSafe {
scoped_ptr<TabCloseableStateWatcher> tab_closeable_state_watcher_;
+ bool created_safe_browsing_detection_service_;
+ scoped_ptr<safe_browsing::ClientSideDetectionService>
+ safe_browsing_detection_service_;
+
unsigned int module_ref_count_;
bool did_start_;
@@ -211,6 +234,12 @@ class BrowserProcessImpl : public BrowserProcess, public NonThreadSafe {
// notifications are properly added and removed.
PrefChangeRegistrar pref_change_registrar_;
+ // Lives here so can safely log events on shutdown.
+ scoped_ptr<ChromeNetLog> net_log_;
+
+ NotificationRegistrar notification_registrar_;
+ scoped_refptr<PluginDataRemover> plugin_data_remover_;
+
#if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
base::RepeatingTimer<BrowserProcessImpl> autoupdate_timer_;
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index b4b335d..af317b1 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -36,12 +36,14 @@ without changes to the corresponding grd file. etaa -->
<include name="IDR_EXTENSIONS_INFOBAR_CSS" file="resources\extensions_infobar.css" flattenhtml="true" type="BINDATA" />
</if>
<include name="IDR_EXTENSIONS_UI_HTML" file="resources\extensions_ui.html" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_FLAGS_HTML" file="resources\flags.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_GAIA_LOGIN_HTML" file="sync\resources\gaia_login.html" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_GPU_INTERNALS_HTML" file="resources\gpu_internals.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_HISTORY_HTML" file="resources\history.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_HISTORY2_HTML" file="resources\history2.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_INCOGNITO_TAB_HTML" file="resources\incognito_tab.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_KEYBOARD_MANIFEST" file="resources\keyboard\manifest.json" type="BINDATA" />
- <include name="IDR_FLAGS_HTML" file="resources\flags.html" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_LOGIN_HTML" file="resources\login.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_GPU_BLACKLIST" file="resources\gpu_blacklist.json" type="BINDATA" />
<include name="IDR_NEW_INCOGNITO_TAB_THEME_CSS" file="resources\new_incognito_tab_theme.css" flattenhtml="true" type="BINDATA" />
<include name="IDR_NEW_NEW_TAB_HTML" file="resources\new_new_tab.html" flattenhtml="true" type="BINDATA" />
@@ -49,7 +51,7 @@ without changes to the corresponding grd file. etaa -->
<include name="IDR_NOTIFICATION_1LINE_HTML" file="resources\notification_1line.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_NOTIFICATION_2LINE_HTML" file="resources\notification_2line.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_NOTIFICATION_ICON_HTML" file="resources\notification_icon.html" type="BINDATA" />
- <include name="IDR_OPTIONS_HTML" file="resources\options.html" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_OPTIONS_HTML" file="resources\options\options.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_PLUGINS_HTML" file="resources\plugins.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_PRINT_PREVIEW_HTML" file="resources\print_preview.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_SAFE_BROWSING_MALWARE_BLOCK" file="resources\safe_browsing_malware_block.html" flattenhtml="true" type="BINDATA" />
diff --git a/chrome/browser/browser_shutdown.cc b/chrome/browser/browser_shutdown.cc
index e136ef8..a312523 100644
--- a/chrome/browser/browser_shutdown.cc
+++ b/chrome/browser/browser_shutdown.cc
@@ -28,6 +28,7 @@
#include "chrome/browser/metrics/metrics_service.h"
#include "chrome/browser/plugin_process_host.h"
#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
@@ -45,6 +46,8 @@
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/boot_times_loader.h"
+#include "chrome/browser/chromeos/cros/cros_library.h"
+#include "chrome/browser/chromeos/cros/login_library.h"
#endif
using base::Time;
@@ -121,7 +124,7 @@ void Shutdown() {
NewRunnableFunction(&ChromePluginLib::UnloadAllPlugins));
// Shutdown all IPC channels to service processes.
- ServiceProcessControlManager::instance()->Shutdown();
+ ServiceProcessControlManager::GetInstance()->Shutdown();
// WARNING: During logoff/shutdown (WM_ENDSESSION) we may not have enough
// time to get here. If you have something that *must* happen on end session,
@@ -132,8 +135,10 @@ void Shutdown() {
g_browser_process->shutdown_event()->Signal();
PrefService* prefs = g_browser_process->local_state();
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ PrefService* user_prefs = profile_manager->GetDefaultProfile()->GetPrefs();
- chrome_browser_net::SavePredictorStateForNextStartupAndTrim(prefs);
+ chrome_browser_net::SavePredictorStateForNextStartupAndTrim(user_prefs);
MetricsService* metrics = g_browser_process->metrics_service();
if (metrics) {
@@ -244,6 +249,12 @@ void Shutdown() {
}
UnregisterURLRequestChromeJob();
+
+#if defined(OS_CHROMEOS)
+ if (chromeos::CrosLibrary::Get()->EnsureLoaded()) {
+ chromeos::CrosLibrary::Get()->GetLoginLibrary()->StopSession("");
+ }
+#endif
}
void ReadLastShutdownFile(
diff --git a/chrome/browser/browser_signin.cc b/chrome/browser/browser_signin.cc
index 5e63c87..535dcd5 100644
--- a/chrome/browser/browser_signin.cc
+++ b/chrome/browser/browser_signin.cc
@@ -20,7 +20,7 @@
#include "chrome/browser/dom_ui/dom_ui_util.h"
#include "chrome/browser/dom_ui/html_dialog_ui.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/sync_setup_flow.h"
@@ -218,7 +218,7 @@ BrowserSignin::BrowserSignin(Profile* profile)
BrowserSigninResourcesSource* source = new BrowserSigninResourcesSource();
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(Singleton<ChromeURLDataManager>::get(),
+ NewRunnableMethod(ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(source)));
}
diff --git a/chrome/browser/browser_url_handler.cc b/chrome/browser/browser_url_handler.cc
index f4f9fd7..6d55e3e 100644
--- a/chrome/browser/browser_url_handler.cc
+++ b/chrome/browser/browser_url_handler.cc
@@ -8,7 +8,7 @@
#include "chrome/browser/browser_about_handler.h"
#include "chrome/browser/dom_ui/dom_ui_factory.h"
#include "chrome/browser/extensions/extension_dom_ui.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/url_constants.h"
#include "googleurl/src/gurl.h"
diff --git a/chrome/browser/browsing_data_appcache_helper.cc b/chrome/browser/browsing_data_appcache_helper.cc
index 18331b1..388b98b 100644
--- a/chrome/browser/browsing_data_appcache_helper.cc
+++ b/chrome/browser/browsing_data_appcache_helper.cc
@@ -6,7 +6,7 @@
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/net/chrome_url_request_context.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/url_constants.h"
#include "webkit/appcache/appcache_database.h"
#include "webkit/appcache/appcache_storage.h"
diff --git a/chrome/browser/browsing_data_database_helper.cc b/chrome/browser/browsing_data_database_helper.cc
index a86affd..ad822bc 100644
--- a/chrome/browser/browsing_data_database_helper.cc
+++ b/chrome/browser/browsing_data_database_helper.cc
@@ -9,7 +9,7 @@
#include "base/message_loop.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "net/base/net_errors.h"
#include "third_party/WebKit/WebKit/chromium/public/WebCString.h"
#include "third_party/WebKit/WebKit/chromium/public/WebSecurityOrigin.h"
diff --git a/chrome/browser/browsing_data_indexed_db_helper.cc b/chrome/browser/browsing_data_indexed_db_helper.cc
index 4979471..8b07235 100644
--- a/chrome/browser/browsing_data_indexed_db_helper.cc
+++ b/chrome/browser/browsing_data_indexed_db_helper.cc
@@ -11,7 +11,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/in_process_webkit/webkit_context.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "third_party/WebKit/WebKit/chromium/public/WebCString.h"
#include "third_party/WebKit/WebKit/chromium/public/WebSecurityOrigin.h"
#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
diff --git a/chrome/browser/browsing_data_local_storage_helper.cc b/chrome/browser/browsing_data_local_storage_helper.cc
index bfbe774..0894707 100644
--- a/chrome/browser/browsing_data_local_storage_helper.cc
+++ b/chrome/browser/browsing_data_local_storage_helper.cc
@@ -10,7 +10,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/in_process_webkit/webkit_context.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "third_party/WebKit/WebKit/chromium/public/WebCString.h"
#include "third_party/WebKit/WebKit/chromium/public/WebSecurityOrigin.h"
#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
diff --git a/chrome/browser/browsing_data_remover.cc b/chrome/browser/browsing_data_remover.cc
index b532f30..3b138ad 100644
--- a/chrome/browser/browsing_data_remover.cc
+++ b/chrome/browser/browsing_data_remover.cc
@@ -11,10 +11,11 @@
#include "chrome/browser/autofill/personal_data_manager.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/download/download_manager.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/in_process_webkit/webkit_context.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/plugin_data_remover.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/browser/password_manager/password_store.h"
@@ -24,7 +25,7 @@
#include "chrome/browser/sessions/tab_restore_service.h"
#include "chrome/browser/webdata/web_data_service.h"
#include "chrome/common/net/url_request_context_getter.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/url_constants.h"
#include "net/base/cookie_monster.h"
#include "net/base/net_errors.h"
@@ -87,7 +88,8 @@ BrowsingDataRemover::BrowsingDataRemover(Profile* profile,
waiting_for_clear_databases_(false),
waiting_for_clear_history_(false),
waiting_for_clear_cache_(false),
- waiting_for_clear_appcache_(false) {
+ waiting_for_clear_appcache_(false),
+ waiting_for_clear_lso_data_(false) {
DCHECK(profile);
}
@@ -100,7 +102,7 @@ void BrowsingDataRemover::Remove(int remove_mask) {
removing_ = true;
std::vector<GURL> origin_whitelist;
- ExtensionsService* extensions_service = profile_->GetExtensionsService();
+ ExtensionService* extensions_service = profile_->GetExtensionService();
if (extensions_service && extensions_service->HasInstalledExtensions()) {
std::map<GURL, int> whitelist_map =
extensions_service->protected_storage_map();
@@ -252,6 +254,17 @@ void BrowsingDataRemover::Remove(int remove_mask) {
NewRunnableMethod(this, &BrowsingDataRemover::ClearCacheOnIOThread));
}
+ if (remove_mask & REMOVE_LSO_DATA) {
+ UserMetrics::RecordAction(UserMetricsAction("ClearBrowsingData_LSOData"));
+
+ waiting_for_clear_lso_data_ = true;
+ if (!plugin_data_remover_.get())
+ plugin_data_remover_ = new PluginDataRemover();
+ plugin_data_remover_->StartRemoving(
+ delete_begin_,
+ NewRunnableMethod(this, &BrowsingDataRemover::OnClearedPluginData));
+ }
+
NotifyAndDeleteIfDone();
}
@@ -458,7 +471,6 @@ void BrowsingDataRemover::OnGotAppCacheInfo(int rv) {
for (InfoByOrigin::const_iterator origin =
appcache_info_->infos_by_origin.begin();
origin != appcache_info_->infos_by_origin.end(); ++origin) {
-
bool found_in_whitelist = false;
for (size_t i = 0; i < appcache_whitelist_.size(); ++i) {
if (appcache_whitelist_[i] == origin->first)
@@ -496,3 +508,8 @@ ChromeAppCacheService* BrowsingDataRemover::GetAppCacheService() {
return request_context ? request_context->appcache_service()
: NULL;
}
+
+void BrowsingDataRemover::OnClearedPluginData() {
+ waiting_for_clear_lso_data_ = false;
+ NotifyAndDeleteIfDone();
+}
diff --git a/chrome/browser/browsing_data_remover.h b/chrome/browser/browsing_data_remover.h
index a160198..9a8addb 100644
--- a/chrome/browser/browsing_data_remover.h
+++ b/chrome/browser/browsing_data_remover.h
@@ -14,8 +14,8 @@
#include "chrome/browser/appcache/chrome_appcache_service.h"
#include "chrome/browser/cancelable_request.h"
#include "chrome/common/notification_registrar.h"
-#include "webkit/database/database_tracker.h"
+class PluginDataRemover;
class Profile;
class URLRequestContextGetter;
@@ -23,6 +23,10 @@ namespace disk_cache {
class Backend;
}
+namespace webkit_database {
+class DatabaseTracker;
+}
+
// BrowsingDataRemover is responsible for removing data related to browsing:
// visits in url database, downloads, cookies ...
@@ -46,6 +50,7 @@ class BrowsingDataRemover : public NotificationObserver {
static const int REMOVE_PASSWORDS = 1 << 3;
static const int REMOVE_FORM_DATA = 1 << 4;
static const int REMOVE_CACHE = 1 << 5;
+ static const int REMOVE_LSO_DATA = 1 << 6;
// Observer is notified when the removal is done. Done means keywords have
// been deleted, cache cleared and all other tasks scheduled.
@@ -97,9 +102,9 @@ class BrowsingDataRemover : public NotificationObserver {
// NotificationObserver method. Callback when TemplateURLModel has finished
// loading. Deletes the entries from the model, and if we're not waiting on
// anything else notifies observers and deletes this BrowsingDataRemover.
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
// If we're not waiting on anything, notifies observers and deletes this
// object.
@@ -137,6 +142,9 @@ class BrowsingDataRemover : public NotificationObserver {
void OnAppCacheDeleted(int rv);
ChromeAppCacheService* GetAppCacheService();
+ // Callback when plug-in data has been cleared. Invokes NotifyAndDeleteIfDone.
+ void OnClearedPluginData();
+
// Calculate the begin time for the deletion range specified by |time_period|.
base::Time CalculateBeginDeleteTime(TimePeriod time_period);
@@ -144,7 +152,7 @@ class BrowsingDataRemover : public NotificationObserver {
bool all_done() {
return registrar_.IsEmpty() && !waiting_for_clear_cache_ &&
!waiting_for_clear_history_ && !waiting_for_clear_databases_ &&
- !waiting_for_clear_appcache_;
+ !waiting_for_clear_appcache_ && !waiting_for_clear_lso_data_;
}
NotificationRegistrar registrar_;
@@ -181,11 +189,15 @@ class BrowsingDataRemover : public NotificationObserver {
scoped_refptr<URLRequestContextGetter> main_context_getter_;
scoped_refptr<URLRequestContextGetter> media_context_getter_;
+ // Used to delete plugin data.
+ scoped_refptr<PluginDataRemover> plugin_data_remover_;
+
// True if we're waiting for various data to be deleted.
bool waiting_for_clear_databases_;
bool waiting_for_clear_history_;
bool waiting_for_clear_cache_;
bool waiting_for_clear_appcache_;
+ bool waiting_for_clear_lso_data_;
ObserverList<Observer> observer_list_;
diff --git a/chrome/browser/browsing_instance.cc b/chrome/browser/browsing_instance.cc
index e3d436b..de6a677 100644
--- a/chrome/browser/browsing_instance.cc
+++ b/chrome/browser/browsing_instance.cc
@@ -6,7 +6,7 @@
#include "base/command_line.h"
#include "base/logging.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/url_constants.h"
diff --git a/chrome/browser/browsing_instance.h b/chrome/browser/browsing_instance.h
index 58b7846..3082b61 100644
--- a/chrome/browser/browsing_instance.h
+++ b/chrome/browser/browsing_instance.h
@@ -8,7 +8,7 @@
#include "base/hash_tables.h"
#include "base/ref_counted.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
class GURL;
class SiteInstance;
diff --git a/chrome/browser/bug_report_data.cc b/chrome/browser/bug_report_data.cc
index c277d88..a0d9772 100644
--- a/chrome/browser/bug_report_data.cc
+++ b/chrome/browser/bug_report_data.cc
@@ -10,6 +10,43 @@
#include "chrome/browser/chromeos/notifications/system_notification.h"
#endif
+BugReportData::BugReportData()
+ : profile_(NULL),
+ problem_type_(0)
+#if defined(OS_CHROMEOS)
+ , sent_report_(false), send_sys_info_(false)
+#endif
+{
+}
+
+BugReportData::~BugReportData() {}
+
+void BugReportData::UpdateData(Profile* profile,
+ const std::string& target_tab_url,
+ const string16& target_tab_title,
+ const int problem_type,
+ const std::string& page_url,
+ const std::string& description,
+ const std::vector<unsigned char>& image
+#if defined(OS_CHROMEOS)
+ , const std::string& user_email
+ , const bool send_sys_info
+ , const bool sent_report
+#endif
+ ) {
+ profile_ = profile;
+ target_tab_url_ = target_tab_url;
+ target_tab_title_ = target_tab_title;
+ problem_type_ = problem_type;
+ page_url_ = page_url;
+ description_ = description;
+ image_ = image;
+#if defined(OS_CHROMEOS)
+ user_email_ = user_email;
+ send_sys_info_ = send_sys_info;
+ sent_report_ = sent_report;
+#endif
+}
#if defined(OS_CHROMEOS)
diff --git a/chrome/browser/bug_report_data.h b/chrome/browser/bug_report_data.h
index 7752350..2c3a6dd 100644
--- a/chrome/browser/bug_report_data.h
+++ b/chrome/browser/bug_report_data.h
@@ -1,10 +1,10 @@
-// Copyright 2010 Google Inc. All Rights Reserved.
-// Author: rkc@google.com (Rahul Chaturvedi)
+// 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.
#ifndef CHROME_BROWSER_BUG_REPORT_DATA_H_
#define CHROME_BROWSER_BUG_REPORT_DATA_H_
-
#include <string>
#include <vector>
@@ -23,43 +23,25 @@ class BugReportData {
// don't want it to send the report either - this will make sure that if
// SyslogsComplete gets called before UpdateData, we'll simply populate the
// sys_info and zip_content fields and exit without disturbing anything else
- BugReportData() : profile_(NULL),
- problem_type_(0)
-#if defined(OS_CHROMEOS)
- , sent_report_(false), send_sys_info_(false)
-#endif
- {
- }
+ BugReportData();
+ ~BugReportData();
// Defined in bug_report_ui.cc
void SendReport();
- void UpdateData(Profile* profile
- , const std::string& target_tab_url
- , const string16& target_tab_title
- , const int problem_type
- , const std::string& page_url
- , const std::string& description
- , const std::vector<unsigned char>& image
+ void UpdateData(Profile* profile,
+ const std::string& target_tab_url,
+ const string16& target_tab_title,
+ const int problem_type,
+ const std::string& page_url,
+ const std::string& description,
+ const std::vector<unsigned char>& image
#if defined(OS_CHROMEOS)
, const std::string& user_email
, const bool send_sys_info
, const bool sent_report
#endif
- ) {
- profile_ = profile;
- target_tab_url_ = target_tab_url;
- target_tab_title_ = target_tab_title;
- problem_type_ = problem_type;
- page_url_ = page_url;
- description_ = description;
- image_ = image;
-#if defined(OS_CHROMEOS)
- user_email_ = user_email;
- send_sys_info_ = send_sys_info;
- sent_report_ = sent_report;
-#endif
- }
+ );
#if defined(OS_CHROMEOS)
void SyslogsComplete(chromeos::LogDictionaryType* logs,
diff --git a/chrome/browser/bug_report_util.cc b/chrome/browser/bug_report_util.cc
index a726c74..28cc685 100644
--- a/chrome/browser/bug_report_util.cc
+++ b/chrome/browser/bug_report_util.cc
@@ -16,7 +16,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process_impl.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/safe_browsing/safe_browsing_util.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_version_info.h"
diff --git a/chrome/browser/cert_store.cc b/chrome/browser/cert_store.cc
index e2f9c2c..30ef867 100644
--- a/chrome/browser/cert_store.cc
+++ b/chrome/browser/cert_store.cc
@@ -10,7 +10,6 @@
#include "base/stl_util-inl.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/notification_service.h"
template <typename T>
@@ -25,7 +24,7 @@ struct MatchSecond {
};
// static
-CertStore* CertStore::GetSharedInstance() {
+CertStore* CertStore::GetInstance() {
return Singleton<CertStore>::get();
}
diff --git a/chrome/browser/cert_store.h b/chrome/browser/cert_store.h
index fc17501..0af7ef4 100644
--- a/chrome/browser/cert_store.h
+++ b/chrome/browser/cert_store.h
@@ -27,7 +27,7 @@
class CertStore : public NotificationObserver {
public:
// Returns the singleton instance of the CertStore.
- static CertStore* GetSharedInstance();
+ static CertStore* GetInstance();
// Stores the specified cert and returns the id associated with it. The cert
// is associated to the specified RenderProcessHost.
diff --git a/chrome/browser/certificate_manager_model.cc b/chrome/browser/certificate_manager_model.cc
index 1c7cd4e..619260e 100644
--- a/chrome/browser/certificate_manager_model.cc
+++ b/chrome/browser/certificate_manager_model.cc
@@ -65,10 +65,8 @@ string16 CertificateManagerModel::GetColumnText(
cert.os_cert_handle(), ""));
break;
case COL_EXPIRES_ON:
- if (!cert.valid_expiry().is_null()) {
- rv = WideToUTF16Hack(
- base::TimeFormatShortDateNumeric(cert.valid_expiry()));
- }
+ if (!cert.valid_expiry().is_null())
+ rv = base::TimeFormatShortDateNumeric(cert.valid_expiry());
break;
default:
NOTREACHED();
diff --git a/chrome/browser/certificate_viewer.cc b/chrome/browser/certificate_viewer.cc
index 677c81f..73cc4d5 100644
--- a/chrome/browser/certificate_viewer.cc
+++ b/chrome/browser/certificate_viewer.cc
@@ -8,7 +8,7 @@
void ShowCertificateViewerByID(gfx::NativeWindow parent, int cert_id) {
scoped_refptr<net::X509Certificate> cert;
- CertStore::GetSharedInstance()->RetrieveCert(cert_id, &cert);
+ CertStore::GetInstance()->RetrieveCert(cert_id, &cert);
if (!cert.get()) {
// The certificate was not found. Could be that the renderer crashed before
// we displayed the page info.
diff --git a/chrome/browser/child_process_launcher.cc b/chrome/browser/child_process_launcher.cc
index f215084..8ba6941 100644
--- a/chrome/browser/child_process_launcher.cc
+++ b/chrome/browser/child_process_launcher.cc
@@ -115,12 +115,13 @@ class ChildProcessLauncher::Context
base::GlobalDescriptors::Mapping mapping;
mapping.push_back(std::pair<uint32_t, int>(kPrimaryIPCChannel, ipcfd));
const int crash_signal_fd =
- Singleton<RendererCrashHandlerHostLinux>()->GetDeathSignalSocket();
+ RendererCrashHandlerHostLinux::GetInstance()->GetDeathSignalSocket();
if (crash_signal_fd >= 0) {
mapping.push_back(std::pair<uint32_t, int>(kCrashDumpSignal,
crash_signal_fd));
}
- handle = Singleton<ZygoteHost>()->ForkRenderer(cmd_line->argv(), mapping);
+ handle = ZygoteHost::GetInstance()->ForkRenderer(cmd_line->argv(),
+ mapping);
} else
// Fall through to the normal posix case below when we're not zygoting.
#endif
@@ -143,10 +144,10 @@ class ChildProcessLauncher::Context
if (is_renderer || is_plugin) {
int crash_signal_fd;
if (is_renderer) {
- crash_signal_fd = Singleton<RendererCrashHandlerHostLinux>()->
+ crash_signal_fd = RendererCrashHandlerHostLinux::GetInstance()->
GetDeathSignalSocket();
} else {
- crash_signal_fd = Singleton<PluginCrashHandlerHostLinux>()->
+ crash_signal_fd = PluginCrashHandlerHostLinux::GetInstance()->
GetDeathSignalSocket();
}
if (crash_signal_fd >= 0) {
@@ -157,7 +158,7 @@ class ChildProcessLauncher::Context
}
if (is_renderer) {
const int sandbox_fd =
- Singleton<RenderSandboxHostLinux>()->GetRendererSocket();
+ RenderSandboxHostLinux::GetInstance()->GetRendererSocket();
fds_to_map.push_back(std::make_pair(
sandbox_fd,
kSandboxIPCChannel + base::GlobalDescriptors::kBaseDescriptor));
@@ -172,7 +173,7 @@ class ChildProcessLauncher::Context
// notification will be processed by the MachBroker after the call to
// AddPlaceholderForPid(), enabling proper cleanup.
{ // begin scope for AutoLock
- MachBroker* broker = MachBroker::instance();
+ MachBroker* broker = MachBroker::GetInstance();
AutoLock lock(broker->GetLock());
// This call to |PrepareForFork()| will start the MachBroker listener
@@ -253,7 +254,7 @@ class ChildProcessLauncher::Context
if (zygote) {
// If the renderer was created via a zygote, we have to proxy the reaping
// through the zygote process.
- Singleton<ZygoteHost>()->EnsureProcessTerminated(handle);
+ ZygoteHost::GetInstance()->EnsureProcessTerminated(handle);
} else
#endif // OS_LINUX
{
@@ -310,27 +311,29 @@ base::ProcessHandle ChildProcessLauncher::GetHandle() {
return context_->process_.handle();
}
-bool ChildProcessLauncher::DidProcessCrash() {
- bool did_crash, child_exited;
+base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus(
+ int* exit_code) {
+ base::TerminationStatus status;
base::ProcessHandle handle = context_->process_.handle();
#if defined(OS_LINUX)
if (context_->zygote_) {
- did_crash = Singleton<ZygoteHost>()->DidProcessCrash(handle, &child_exited);
+ status = ZygoteHost::GetInstance()->GetTerminationStatus(handle, exit_code);
} else
#endif
{
- did_crash = base::DidProcessCrash(&child_exited, handle);
+ status = base::GetTerminationStatus(handle, exit_code);
}
- // POSIX: If the process crashed, then the kernel closed the socket for it
- // and so the child has already died by the time we get here. Since
- // DidProcessCrash called waitpid with WNOHANG, it'll reap the process.
- // However, if DidProcessCrash didn't reap the child, we'll need to in
+ // POSIX: If the process crashed, then the kernel closed the socket
+ // for it and so the child has already died by the time we get
+ // here. Since GetTerminationStatus called waitpid with WNOHANG,
+ // it'll reap the process. However, if GetTerminationStatus didn't
+ // reap the child (because it was still running), we'll need to
// Terminate via ProcessWatcher. So we can't close the handle here.
- if (child_exited)
+ if (status != base::TERMINATION_STATUS_STILL_RUNNING)
context_->process_.Close();
- return did_crash;
+ return status;
}
void ChildProcessLauncher::SetProcessBackgrounded(bool background) {
diff --git a/chrome/browser/child_process_launcher.h b/chrome/browser/child_process_launcher.h
index 95fb6ea..a3add53 100644
--- a/chrome/browser/child_process_launcher.h
+++ b/chrome/browser/child_process_launcher.h
@@ -50,8 +50,11 @@ class ChildProcessLauncher {
// Getter for the process handle. Only call after the process has started.
base::ProcessHandle GetHandle();
- // Call this when the process exits to know if a process crashed or not.
- bool DidProcessCrash();
+ // Call this when the child process exits to know what happened to
+ // it. |exit_code| is the exit code of the process if it exited
+ // (e.g. status from waitpid if on posix, from GetExitCodeProcess on
+ // Windows). |exit_code| may be NULL.
+ base::TerminationStatus GetChildTerminationStatus(int* exit_code);
// Changes whether the process runs in the background or not. Only call
// this after the process has started.
diff --git a/chrome/browser/child_process_security_policy.cc b/chrome/browser/child_process_security_policy.cc
index 0aed464..ea1f725 100644
--- a/chrome/browser/child_process_security_policy.cc
+++ b/chrome/browser/child_process_security_policy.cc
@@ -20,7 +20,7 @@ static const int kReadFilePermissions =
base::PLATFORM_FILE_EXCLUSIVE_READ |
base::PLATFORM_FILE_ASYNC;
-// The SecurityState class is used to maintain per-renderer security state
+// The SecurityState class is used to maintain per-child process security state
// information.
class ChildProcessSecurityPolicy::SecurityState {
public:
@@ -111,7 +111,7 @@ class ChildProcessSecurityPolicy::SecurityState {
// or revoked.
SchemeMap scheme_policy_;
- // The set of files the renderer is permited to upload to the web.
+ // The set of files the child process is permited to upload to the web.
FileMap file_permissions_;
int enabled_bindings_;
@@ -150,23 +150,23 @@ ChildProcessSecurityPolicy* ChildProcessSecurityPolicy::GetInstance() {
return Singleton<ChildProcessSecurityPolicy>::get();
}
-void ChildProcessSecurityPolicy::Add(int renderer_id) {
+void ChildProcessSecurityPolicy::Add(int child_id) {
AutoLock lock(lock_);
- if (security_state_.count(renderer_id) != 0) {
- NOTREACHED() << "Add renderers at most once.";
+ if (security_state_.count(child_id) != 0) {
+ NOTREACHED() << "Add child process at most once.";
return;
}
- security_state_[renderer_id] = new SecurityState();
+ security_state_[child_id] = new SecurityState();
}
-void ChildProcessSecurityPolicy::Remove(int renderer_id) {
+void ChildProcessSecurityPolicy::Remove(int child_id) {
AutoLock lock(lock_);
- if (!security_state_.count(renderer_id))
+ if (!security_state_.count(child_id))
return; // May be called multiple times.
- delete security_state_[renderer_id];
- security_state_.erase(renderer_id);
+ delete security_state_[child_id];
+ security_state_.erase(child_id);
}
void ChildProcessSecurityPolicy::RegisterWebSafeScheme(
@@ -201,13 +201,13 @@ bool ChildProcessSecurityPolicy::IsPseudoScheme(const std::string& scheme) {
}
void ChildProcessSecurityPolicy::GrantRequestURL(
- int renderer_id, const GURL& url) {
+ int child_id, const GURL& url) {
if (!url.is_valid())
return; // Can't grant the capability to request invalid URLs.
if (IsWebSafeScheme(url.scheme()))
- return; // The scheme has already been white-listed for every renderer.
+ return; // The scheme has already been whitelisted for every child process.
if (IsPseudoScheme(url.scheme())) {
// The view-source scheme is a special case of a pseudo-URL that eventually
@@ -215,9 +215,9 @@ void ChildProcessSecurityPolicy::GrantRequestURL(
if (url.SchemeIs(chrome::kViewSourceScheme)) {
// URLs with the view-source scheme typically look like:
// view-source:http://www.google.com/a
- // In order to request these URLs, the renderer needs to be able to
+ // In order to request these URLs, the child_id needs to be able to
// request the embedded URL.
- GrantRequestURL(renderer_id, GURL(url.path()));
+ GrantRequestURL(child_id, GURL(url.path()));
}
return; // Can't grant the capability to request pseudo schemes.
@@ -225,26 +225,26 @@ void ChildProcessSecurityPolicy::GrantRequestURL(
{
AutoLock lock(lock_);
- SecurityStateMap::iterator state = security_state_.find(renderer_id);
+ SecurityStateMap::iterator state = security_state_.find(child_id);
if (state == security_state_.end())
return;
- // If the renderer has been commanded to request a scheme, then we grant
- // it the capability to request URLs of that scheme.
+ // If the child process has been commanded to request a scheme, then we
+ // grant it the capability to request URLs of that scheme.
state->second->GrantScheme(url.scheme());
}
}
-void ChildProcessSecurityPolicy::GrantReadFile(int renderer_id,
+void ChildProcessSecurityPolicy::GrantReadFile(int child_id,
const FilePath& file) {
- GrantPermissionsForFile(renderer_id, file, kReadFilePermissions);
+ GrantPermissionsForFile(child_id, file, kReadFilePermissions);
}
void ChildProcessSecurityPolicy::GrantPermissionsForFile(
- int renderer_id, const FilePath& file, int permissions) {
+ int child_id, const FilePath& file, int permissions) {
AutoLock lock(lock_);
- SecurityStateMap::iterator state = security_state_.find(renderer_id);
+ SecurityStateMap::iterator state = security_state_.find(child_id);
if (state == security_state_.end())
return;
@@ -252,31 +252,31 @@ void ChildProcessSecurityPolicy::GrantPermissionsForFile(
}
void ChildProcessSecurityPolicy::RevokeAllPermissionsForFile(
- int renderer_id, const FilePath& file) {
+ int child_id, const FilePath& file) {
AutoLock lock(lock_);
- SecurityStateMap::iterator state = security_state_.find(renderer_id);
+ SecurityStateMap::iterator state = security_state_.find(child_id);
if (state == security_state_.end())
return;
state->second->RevokeAllPermissionsForFile(file);
}
-void ChildProcessSecurityPolicy::GrantScheme(int renderer_id,
+void ChildProcessSecurityPolicy::GrantScheme(int child_id,
const std::string& scheme) {
AutoLock lock(lock_);
- SecurityStateMap::iterator state = security_state_.find(renderer_id);
+ SecurityStateMap::iterator state = security_state_.find(child_id);
if (state == security_state_.end())
return;
state->second->GrantScheme(scheme);
}
-void ChildProcessSecurityPolicy::GrantDOMUIBindings(int renderer_id) {
+void ChildProcessSecurityPolicy::GrantDOMUIBindings(int child_id) {
AutoLock lock(lock_);
- SecurityStateMap::iterator state = security_state_.find(renderer_id);
+ SecurityStateMap::iterator state = security_state_.find(child_id);
if (state == security_state_.end())
return;
@@ -289,30 +289,30 @@ void ChildProcessSecurityPolicy::GrantDOMUIBindings(int renderer_id) {
state->second->GrantScheme(chrome::kFileScheme);
}
-void ChildProcessSecurityPolicy::GrantExtensionBindings(int renderer_id) {
+void ChildProcessSecurityPolicy::GrantExtensionBindings(int child_id) {
AutoLock lock(lock_);
- SecurityStateMap::iterator state = security_state_.find(renderer_id);
+ SecurityStateMap::iterator state = security_state_.find(child_id);
if (state == security_state_.end())
return;
state->second->GrantBindings(BindingsPolicy::EXTENSION);
}
-void ChildProcessSecurityPolicy::GrantReadRawCookies(int renderer_id) {
+void ChildProcessSecurityPolicy::GrantReadRawCookies(int child_id) {
AutoLock lock(lock_);
- SecurityStateMap::iterator state = security_state_.find(renderer_id);
+ SecurityStateMap::iterator state = security_state_.find(child_id);
if (state == security_state_.end())
return;
state->second->GrantReadRawCookies();
}
-void ChildProcessSecurityPolicy::RevokeReadRawCookies(int renderer_id) {
+void ChildProcessSecurityPolicy::RevokeReadRawCookies(int child_id) {
AutoLock lock(lock_);
- SecurityStateMap::iterator state = security_state_.find(renderer_id);
+ SecurityStateMap::iterator state = security_state_.find(child_id);
if (state == security_state_.end())
return;
@@ -320,92 +320,92 @@ void ChildProcessSecurityPolicy::RevokeReadRawCookies(int renderer_id) {
}
bool ChildProcessSecurityPolicy::CanRequestURL(
- int renderer_id, const GURL& url) {
+ int child_id, const GURL& url) {
if (!url.is_valid())
return false; // Can't request invalid URLs.
if (IsWebSafeScheme(url.scheme()))
- return true; // The scheme has been white-listed for every renderer.
+ return true; // The scheme has been white-listed for every child process.
if (IsPseudoScheme(url.scheme())) {
// There are a number of special cases for pseudo schemes.
if (url.SchemeIs(chrome::kViewSourceScheme)) {
- // A view-source URL is allowed if the renderer is permitted to request
- // the embedded URL. Careful to avoid pointless recursion.
+ // A view-source URL is allowed if the child process is permitted to
+ // request the embedded URL. Careful to avoid pointless recursion.
GURL child_url(url.path());
if (child_url.SchemeIs(chrome::kViewSourceScheme) &&
url.SchemeIs(chrome::kViewSourceScheme))
return false;
- return CanRequestURL(renderer_id, child_url);
+ return CanRequestURL(child_id, child_url);
}
if (LowerCaseEqualsASCII(url.spec(), chrome::kAboutBlankURL))
- return true; // Every renderer can request <about:blank>.
+ return true; // Every child process can request <about:blank>.
// URLs like <about:memory> and <about:crash> shouldn't be requestable by
- // any renderer. Also, this case covers <javascript:...>, which should be
- // handled internally by the renderer and not kicked up to the browser.
+ // any child process. Also, this case covers <javascript:...>, which should
+ // be handled internally by the process and not kicked up to the browser.
return false;
}
- if (!URLRequest::IsHandledURL(url))
+ if (!net::URLRequest::IsHandledURL(url))
return true; // This URL request is destined for ShellExecute.
{
AutoLock lock(lock_);
- SecurityStateMap::iterator state = security_state_.find(renderer_id);
+ SecurityStateMap::iterator state = security_state_.find(child_id);
if (state == security_state_.end())
return false;
- // Otherwise, we consult the renderer's security state to see if it is
+ // Otherwise, we consult the child process's security state to see if it is
// allowed to request the URL.
return state->second->CanRequestURL(url);
}
}
-bool ChildProcessSecurityPolicy::CanReadFile(int renderer_id,
+bool ChildProcessSecurityPolicy::CanReadFile(int child_id,
const FilePath& file) {
- return HasPermissionsForFile(renderer_id, file, kReadFilePermissions);
+ return HasPermissionsForFile(child_id, file, kReadFilePermissions);
}
bool ChildProcessSecurityPolicy::HasPermissionsForFile(
- int renderer_id, const FilePath& file, int permissions) {
+ int child_id, const FilePath& file, int permissions) {
AutoLock lock(lock_);
- SecurityStateMap::iterator state = security_state_.find(renderer_id);
+ SecurityStateMap::iterator state = security_state_.find(child_id);
if (state == security_state_.end())
return false;
return state->second->HasPermissionsForFile(file, permissions);
}
-bool ChildProcessSecurityPolicy::HasDOMUIBindings(int renderer_id) {
+bool ChildProcessSecurityPolicy::HasDOMUIBindings(int child_id) {
AutoLock lock(lock_);
- SecurityStateMap::iterator state = security_state_.find(renderer_id);
+ SecurityStateMap::iterator state = security_state_.find(child_id);
if (state == security_state_.end())
return false;
return state->second->has_dom_ui_bindings();
}
-bool ChildProcessSecurityPolicy::HasExtensionBindings(int renderer_id) {
+bool ChildProcessSecurityPolicy::HasExtensionBindings(int child_id) {
AutoLock lock(lock_);
- SecurityStateMap::iterator state = security_state_.find(renderer_id);
+ SecurityStateMap::iterator state = security_state_.find(child_id);
if (state == security_state_.end())
return false;
return state->second->has_extension_bindings();
}
-bool ChildProcessSecurityPolicy::CanReadRawCookies(int renderer_id) {
+bool ChildProcessSecurityPolicy::CanReadRawCookies(int child_id) {
AutoLock lock(lock_);
- SecurityStateMap::iterator state = security_state_.find(renderer_id);
+ SecurityStateMap::iterator state = security_state_.find(child_id);
if (state == security_state_.end())
return false;
diff --git a/chrome/browser/child_process_security_policy.h b/chrome/browser/child_process_security_policy.h
index b70dc25..9280400 100644
--- a/chrome/browser/child_process_security_policy.h
+++ b/chrome/browser/child_process_security_policy.h
@@ -20,9 +20,9 @@ class FilePath;
class GURL;
// The ChildProcessSecurityPolicy class is used to grant and revoke security
-// capabilities for renderers. For example, it restricts whether a renderer
-// is permmitted to loaded file:// URLs based on whether the renderer has ever
-// been commanded to load file:// URLs by the browser.
+// capabilities for child porcesses. For example, it restricts whether a child
+// process is permmitted to loaded file:// URLs based on whether the process
+// has ever been commanded to load file:// URLs by the browser.
//
// ChildProcessSecurityPolicy is a singleton that may be used on any thread.
//
@@ -37,9 +37,9 @@ class ChildProcessSecurityPolicy {
// any thread.
static ChildProcessSecurityPolicy* GetInstance();
- // Web-safe schemes can be requested by any renderer. Once a web-safe scheme
- // has been registered, any renderer processes can request URLs with that
- // scheme. There is no mechanism for revoking web-safe schemes.
+ // Web-safe schemes can be requested by any child process. Once a web-safe
+ // scheme has been registered, any child process can request URLs with
+ // that scheme. There is no mechanism for revoking web-safe schemes.
void RegisterWebSafeScheme(const std::string& scheme);
// Returns true iff |scheme| has been registered as a web-safe scheme.
@@ -53,77 +53,77 @@ class ChildProcessSecurityPolicy {
// Returns true iff |scheme| has been registered as pseudo scheme.
bool IsPseudoScheme(const std::string& scheme);
- // Upon creation, render processes should register themselves by calling this
+ // Upon creation, child processes should register themselves by calling this
// this method exactly once.
- void Add(int renderer_id);
+ void Add(int child_id);
- // Upon destruction, render processess should unregister themselves by caling
+ // Upon destruction, child processess should unregister themselves by caling
// this method exactly once.
- void Remove(int renderer_id);
+ void Remove(int child_id);
- // Whenever the browser processes commands the renderer to request a URL, it
- // should call this method to grant the renderer process the capability to
+ // Whenever the browser processes commands the child process to request a URL,
+ // it should call this method to grant the child process the capability to
// request the URL.
- void GrantRequestURL(int renderer_id, const GURL& url);
+ void GrantRequestURL(int child_id, const GURL& url);
// Whenever the user picks a file from a <input type="file"> element, the
- // browser should call this function to grant the renderer the capability to
- // upload the file to the web.
- void GrantReadFile(int renderer_id, const FilePath& file);
+ // browser should call this function to grant the child process the capability
+ // to upload the file to the web.
+ void GrantReadFile(int child_id, const FilePath& file);
// Grants certain permissions to a file. |permissions| must be a bit-set of
// base::PlatformFileFlags.
- void GrantPermissionsForFile(int renderer_id,
+ void GrantPermissionsForFile(int child_id,
const FilePath& file,
int permissions);
// Revokes all permissions granted to the given file.
- void RevokeAllPermissionsForFile(int renderer_id, const FilePath& file);
+ void RevokeAllPermissionsForFile(int child_id, const FilePath& file);
- // Grants the renderer process the capability to access URLs of the provided
+ // Grants the child process the capability to access URLs of the provided
// scheme.
- void GrantScheme(int renderer_id, const std::string& scheme);
+ void GrantScheme(int child_id, const std::string& scheme);
- // Grant this renderer the ability to use DOM UI Bindings.
- void GrantDOMUIBindings(int renderer_id);
+ // Grant the child process the ability to use DOM UI Bindings.
+ void GrantDOMUIBindings(int child_id);
- // Grant this renderer the ability to use extension Bindings.
- void GrantExtensionBindings(int renderer_id);
+ // Grant the child process the ability to use extension Bindings.
+ void GrantExtensionBindings(int child_id);
- // Grant this renderer the ability to read raw cookies.
- void GrantReadRawCookies(int renderer_id);
+ // Grant the child process the ability to read raw cookies.
+ void GrantReadRawCookies(int child_id);
// Revoke read raw cookies permission.
- void RevokeReadRawCookies(int renderer_id);
+ void RevokeReadRawCookies(int child_id);
- // Before servicing a renderer's request for a URL, the browser should call
- // this method to determine whether the renderer has the capability to
+ // Before servicing a child process's request for a URL, the browser should
+ // call this method to determine whether the process has the capability to
// request the URL.
- bool CanRequestURL(int renderer_id, const GURL& url);
+ bool CanRequestURL(int child_id, const GURL& url);
- // Before servicing a renderer's request to upload a file to the web, the
- // browser should call this method to determine whether the renderer has the
+ // Before servicing a child process's request to upload a file to the web, the
+ // browser should call this method to determine whether the process has the
// capability to upload the requested file.
- bool CanReadFile(int renderer_id, const FilePath& file);
+ bool CanReadFile(int child_id, const FilePath& file);
// Determines if certain permissions were granted for a file. |permissions|
// must be a bit-set of base::PlatformFileFlags.
- bool HasPermissionsForFile(int renderer_id,
+ bool HasPermissionsForFile(int child_id,
const FilePath& file,
int permissions);
- // Returns true if the specified renderer_id has been granted DOMUIBindings.
- // The browser should check this property before assuming the renderer is
+ // Returns true if the specified child_id has been granted DOMUIBindings.
+ // The browser should check this property before assuming the child process is
// allowed to use DOMUIBindings.
- bool HasDOMUIBindings(int renderer_id);
+ bool HasDOMUIBindings(int child_id);
- // Returns true if the specified renderer_id has been granted DOMUIBindings.
- // The browser should check this property before assuming the renderer is
+ // Returns true if the specified child_id has been granted DOMUIBindings.
+ // The browser should check this property before assuming the child process is
// allowed to use extension bindings.
- bool HasExtensionBindings(int renderer_id);
+ bool HasExtensionBindings(int child_id);
- // Returns true if the specified renderer_id has been granted ReadRawCookies.
- bool CanReadRawCookies(int renderer_id);
+ // Returns true if the specified child_id has been granted ReadRawCookies.
+ bool CanReadRawCookies(int child_id);
private:
friend class ChildProcessSecurityPolicyInProcessBrowserTest;
@@ -143,8 +143,8 @@ class ChildProcessSecurityPolicy {
// class. You must not block while holding this lock.
Lock lock_;
- // These schemes are white-listed for all renderers. This set is protected
- // by |lock_|.
+ // These schemes are white-listed for all child processes. This set is
+ // protected by |lock_|.
SchemeSet web_safe_schemes_;
// These schemes do not actually represent retrievable URLs. For example,
@@ -152,8 +152,8 @@ class ChildProcessSecurityPolicy {
// protected by |lock_|.
SchemeSet pseudo_schemes_;
- // This map holds a SecurityState for each renderer process. The key for the
- // map is the ID of the RenderProcessHost. The SecurityState objects are
+ // This map holds a SecurityState for each child process. The key for the
+ // map is the ID of the ChildProcessHost. The SecurityState objects are
// owned by this object and are protected by |lock_|. References to them must
// not escape this class.
SecurityStateMap security_state_;
diff --git a/chrome/browser/child_process_security_policy_browsertest.cc b/chrome/browser/child_process_security_policy_browsertest.cc
index bedac81..4bcd3dc 100644
--- a/chrome/browser/child_process_security_policy_browsertest.cc
+++ b/chrome/browser/child_process_security_policy_browsertest.cc
@@ -11,6 +11,7 @@
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/common/result_codes.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -43,7 +44,7 @@ IN_PROC_BROWSER_TEST_F(ChildProcessSecurityPolicyInProcessBrowserTest, NoLeak) {
TabContents* tab = browser()->GetTabContentsAt(0);
ASSERT_TRUE(tab != NULL);
base::KillProcess(tab->GetRenderProcessHost()->GetHandle(),
- base::PROCESS_END_KILLED_BY_USER, true);
+ ResultCodes::KILLED, true);
tab->controller().Reload(true);
EXPECT_EQ(
diff --git a/chrome/browser/child_process_security_policy_unittest.cc b/chrome/browser/child_process_security_policy_unittest.cc
index 26f794f..cc31188 100644
--- a/chrome/browser/child_process_security_policy_unittest.cc
+++ b/chrome/browser/child_process_security_policy_unittest.cc
@@ -18,11 +18,11 @@ class ChildProcessSecurityPolicyTest : public testing::Test {
// testing::Test
virtual void SetUp() {
// In the real world, "chrome:" is a handled scheme.
- URLRequest::RegisterProtocolFactory(chrome::kChromeUIScheme,
- &URLRequestTestJob::Factory);
+ net::URLRequest::RegisterProtocolFactory(chrome::kChromeUIScheme,
+ &URLRequestTestJob::Factory);
}
virtual void TearDown() {
- URLRequest::RegisterProtocolFactory(chrome::kChromeUIScheme, NULL);
+ net::URLRequest::RegisterProtocolFactory(chrome::kChromeUIScheme, NULL);
}
};
@@ -133,7 +133,7 @@ TEST_F(ChildProcessSecurityPolicyTest, RegisterWebSafeSchemeTest) {
EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("asdf:rockers")));
// Once we register a ProtocolFactory for "asdf", we default to deny.
- URLRequest::RegisterProtocolFactory("asdf", &URLRequestTestJob::Factory);
+ net::URLRequest::RegisterProtocolFactory("asdf", &URLRequestTestJob::Factory);
EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("asdf:rockers")));
// We can allow new schemes by adding them to the whitelist.
@@ -141,7 +141,7 @@ TEST_F(ChildProcessSecurityPolicyTest, RegisterWebSafeSchemeTest) {
EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("asdf:rockers")));
// Cleanup.
- URLRequest::RegisterProtocolFactory("asdf", NULL);
+ net::URLRequest::RegisterProtocolFactory("asdf", NULL);
EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("asdf:rockers")));
p->Remove(kRendererID);
diff --git a/chrome/browser/chrome_browser_application_mac.h b/chrome/browser/chrome_browser_application_mac.h
index e599c63..a1ebb04 100644
--- a/chrome/browser/chrome_browser_application_mac.h
+++ b/chrome/browser/chrome_browser_application_mac.h
@@ -8,7 +8,7 @@
#ifdef __OBJC__
-#import "base/chrome_application_mac.h"
+#import "chrome/common/chrome_application_mac.h"
@interface BrowserCrApplication : CrApplication
// Our implementation of |-terminate:| only attempts to terminate the
@@ -36,6 +36,9 @@ void RecordExceptionWithUma(NSException* exception);
namespace chrome_browser_application_mac {
+// To be used to instantiate BrowserCrApplication from C++ code.
+void RegisterBrowserCrApp();
+
// Calls -[NSApp terminate:].
void Terminate();
diff --git a/chrome/browser/chrome_browser_application_mac.mm b/chrome/browser/chrome_browser_application_mac.mm
index 997221d..aea31b0 100644
--- a/chrome/browser/chrome_browser_application_mac.mm
+++ b/chrome/browser/chrome_browser_application_mac.mm
@@ -10,8 +10,8 @@
#import "base/sys_string_conversions.h"
#import "chrome/app/breakpad_mac.h"
#import "chrome/browser/app_controller_mac.h"
-#import "chrome/browser/cocoa/objc_method_swizzle.h"
-#import "chrome/browser/cocoa/objc_zombie.h"
+#import "chrome/browser/ui/cocoa/objc_method_swizzle.h"
+#import "chrome/browser/ui/cocoa/objc_zombie.h"
// The implementation of NSExceptions break various assumptions in the
// Chrome code. This category defines a replacement for
@@ -64,7 +64,8 @@ static IMP gOriginalInitIMP = NULL;
BOOL fatal = NO;
if (aName == NSInternalInconsistencyException) {
NSString* const kNSMenuItemArrayBoundsCheck =
- @"Invalid parameter not satisfying: (index >= 0) && (index < [_itemArray count])";
+ @"Invalid parameter not satisfying: (index >= 0) && "
+ @"(index < [_itemArray count])";
if ([aReason isEqualToString:kNSMenuItemArrayBoundsCheck]) {
fatal = YES;
}
@@ -141,6 +142,10 @@ void RecordExceptionWithUma(NSException* exception) {
BinForException(exception), kUnknownNSException);
}
+void RegisterBrowserCrApp() {
+ [BrowserCrApplication sharedApplication];
+};
+
void Terminate() {
[NSApp terminate:nil];
}
@@ -188,8 +193,6 @@ BOOL SwizzleNSExceptionInit() {
+ (void)initialize {
// Turn all deallocated Objective-C objects into zombies, keeping
// the most recent 10,000 of them on the treadmill.
- // TODO(shess): Convert to a DCHECK() before the next beta channel.
- // http://crbug.com/45676
ObjcEvilDoers::ZombieEnable(YES, 10000);
}
diff --git a/chrome/browser/chrome_plugin_browsing_context.cc b/chrome/browser/chrome_plugin_browsing_context.cc
index 34fe815..3ff4729 100644
--- a/chrome/browser/chrome_plugin_browsing_context.cc
+++ b/chrome/browser/chrome_plugin_browsing_context.cc
@@ -9,7 +9,7 @@
#include "chrome/browser/browser_thread.h"
#include "chrome/common/notification_service.h"
-CPBrowsingContextManager* CPBrowsingContextManager::Instance() {
+CPBrowsingContextManager* CPBrowsingContextManager::GetInstance() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
return Singleton<CPBrowsingContextManager>::get();
}
diff --git a/chrome/browser/chrome_plugin_browsing_context.h b/chrome/browser/chrome_plugin_browsing_context.h
index ef31262..45d24f3 100644
--- a/chrome/browser/chrome_plugin_browsing_context.h
+++ b/chrome/browser/chrome_plugin_browsing_context.h
@@ -23,7 +23,7 @@ class URLRequestContext;
// Note: This class should be used on the IO thread only.
class CPBrowsingContextManager : public NotificationObserver {
public:
- static CPBrowsingContextManager* Instance();
+ static CPBrowsingContextManager* GetInstance();
// Note: don't call these directly - use Instance() above. They are public
// so Singleton can access them.
diff --git a/chrome/browser/chrome_plugin_host.cc b/chrome/browser/chrome_plugin_host.cc
index a044306..09abdea 100644
--- a/chrome/browser/chrome_plugin_host.cc
+++ b/chrome/browser/chrome_plugin_host.cc
@@ -24,7 +24,7 @@
#include "chrome/browser/gears_integration.h"
#include "chrome/browser/plugin_process_host.h"
#include "chrome/browser/plugin_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_counters.h"
@@ -42,6 +42,7 @@
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/http/http_request_headers.h"
+#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_error_job.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -54,29 +55,29 @@ using base::TimeDelta;
// intercept the request.
// NOTE: All methods must be called on the IO thread.
class PluginRequestInterceptor
- : public PluginHelper, public URLRequest::Interceptor {
+ : public PluginHelper, public net::URLRequest::Interceptor {
public:
- static URLRequestJob* UninterceptedProtocolHandler(
- URLRequest* request, const std::string& scheme) {
+ static net::URLRequestJob* UninterceptedProtocolHandler(
+ net::URLRequest* request, const std::string& scheme) {
// This will get called if a plugin failed to intercept a request for a
// protocol it has registered. In that case, we return NULL and the request
// will result in an error.
- return new URLRequestErrorJob(request, net::ERR_FILE_NOT_FOUND);
+ return new net::URLRequestErrorJob(request, net::ERR_FILE_NOT_FOUND);
}
explicit PluginRequestInterceptor(ChromePluginLib* plugin)
: PluginHelper(plugin) {
- URLRequest::RegisterRequestInterceptor(this);
+ net::URLRequest::RegisterRequestInterceptor(this);
}
virtual ~PluginRequestInterceptor() {
- URLRequest::UnregisterRequestInterceptor(this);
+ net::URLRequest::UnregisterRequestInterceptor(this);
// Unregister our protocols.
for (HandledProtocolList::iterator it = registered_protocols_.begin();
it != registered_protocols_.end(); ++it) {
- URLRequest::ProtocolFactory* factory =
- URLRequest::RegisterProtocolFactory(*it, NULL);
+ net::URLRequest::ProtocolFactory* factory =
+ net::URLRequest::RegisterProtocolFactory(*it, NULL);
DCHECK(factory == UninterceptedProtocolHandler);
}
}
@@ -87,17 +88,17 @@ class PluginRequestInterceptor
std::string lower_scheme = StringToLowerASCII(scheme);
handled_protocols_.insert(lower_scheme);
- // Only add a protocol factory if the URLRequest doesn't already handle
+ // Only add a protocol factory if the net::URLRequest doesn't already handle
// it. If we fail to intercept, the request will be treated as an error.
- if (!URLRequest::IsHandledProtocol(lower_scheme)) {
+ if (!net::URLRequest::IsHandledProtocol(lower_scheme)) {
registered_protocols_.insert(lower_scheme);
- URLRequest::RegisterProtocolFactory(lower_scheme,
+ net::URLRequest::RegisterProtocolFactory(lower_scheme,
&UninterceptedProtocolHandler);
}
}
- // URLRequest::Interceptor
- virtual URLRequestJob* MaybeIntercept(URLRequest* request) {
+ // net::URLRequest::Interceptor
+ virtual net::URLRequestJob* MaybeIntercept(net::URLRequest* request) {
// TODO(darin): This DCHECK fails in the unit tests because our interceptor
// is being persisted across unit tests. As a result, each time we get
// poked on a different thread, but never from more than one thread at a
@@ -109,7 +110,7 @@ class PluginRequestInterceptor
return NULL;
CPBrowsingContext context =
- CPBrowsingContextManager::Instance()->Lookup(request->context());
+ CPBrowsingContextManager::GetInstance()->Lookup(request->context());
scoped_ptr<ScopableCPRequest> cprequest(
new ScopableCPRequest(request->url().spec().c_str(),
request->method().c_str(),
@@ -143,9 +144,10 @@ class PluginRequestInterceptor
};
// This class manages a network request made by the plugin, also acting as
-// the URLRequest delegate.
+// the net::URLRequest delegate.
// NOTE: All methods must be called on the IO thread.
-class PluginRequestHandler : public PluginHelper, public URLRequest::Delegate {
+class PluginRequestHandler : public PluginHelper,
+ public net::URLRequest::Delegate {
public:
static PluginRequestHandler* FromCPRequest(CPRequest* request) {
return ScopableCPRequest::GetData<PluginRequestHandler*>(request);
@@ -155,22 +157,22 @@ class PluginRequestHandler : public PluginHelper, public URLRequest::Delegate {
: PluginHelper(plugin), cprequest_(cprequest), user_buffer_(NULL) {
cprequest_->data = this; // see FromCPRequest().
- URLRequestContext* context = CPBrowsingContextManager::Instance()->
+ URLRequestContext* context = CPBrowsingContextManager::GetInstance()->
ToURLRequestContext(cprequest_->context);
// TODO(mpcomplete): remove fallback case when Gears support is prevalent.
if (!context)
context = Profile::GetDefaultRequestContext()->GetURLRequestContext();
GURL gurl(cprequest_->url);
- request_.reset(new URLRequest(gurl, this));
+ request_.reset(new net::URLRequest(gurl, this));
request_->set_context(context);
request_->set_method(cprequest_->method);
request_->set_load_flags(PluginResponseUtils::CPLoadFlagsToNetFlags(0));
}
- URLRequest* request() { return request_.get(); }
+ net::URLRequest* request() { return request_.get(); }
- // Wraper of URLRequest::Read()
+ // Wraper of net::URLRequest::Read()
bool Read(char* dest, int dest_size, int *bytes_read) {
CHECK(!my_buffer_.get());
// We'll use our own buffer until the read actually completes.
@@ -189,14 +191,14 @@ class PluginRequestHandler : public PluginHelper, public URLRequest::Delegate {
return false;
}
- // URLRequest::Delegate
- virtual void OnReceivedRedirect(URLRequest* request, const GURL& new_url,
+ // net::URLRequest::Delegate
+ virtual void OnReceivedRedirect(net::URLRequest* request, const GURL& new_url,
bool* defer_redirect) {
plugin_->functions().response_funcs->received_redirect(
cprequest_.get(), new_url.spec().c_str());
}
- virtual void OnResponseStarted(URLRequest* request) {
+ virtual void OnResponseStarted(net::URLRequest* request) {
// TODO(mpcomplete): better error codes
CPError result =
request_->status().is_success() ? CPERR_SUCCESS : CPERR_FAILURE;
@@ -204,7 +206,7 @@ class PluginRequestHandler : public PluginHelper, public URLRequest::Delegate {
cprequest_.get(), result);
}
- virtual void OnReadCompleted(URLRequest* request, int bytes_read) {
+ virtual void OnReadCompleted(net::URLRequest* request, int bytes_read) {
CHECK(my_buffer_.get());
CHECK(user_buffer_);
if (bytes_read > 0) {
@@ -220,7 +222,7 @@ class PluginRequestHandler : public PluginHelper, public URLRequest::Delegate {
private:
scoped_ptr<ScopableCPRequest> cprequest_;
- scoped_ptr<URLRequest> request_;
+ scoped_ptr<net::URLRequest> request_;
scoped_refptr<net::IOBuffer> my_buffer_;
char* user_buffer_;
};
@@ -385,7 +387,7 @@ void STDCALL CPB_SetKeepProcessAlive(CPID id, CPBool keep_alive) {
CPError STDCALL CPB_GetCookies(CPID id, CPBrowsingContext bcontext,
const char* url, char** cookies) {
CHECK(ChromePluginLib::IsPluginThread());
- URLRequestContext* context = CPBrowsingContextManager::Instance()->
+ URLRequestContext* context = CPBrowsingContextManager::GetInstance()->
ToURLRequestContext(bcontext);
// TODO(mpcomplete): remove fallback case when Gears support is prevalent.
if (!context) {
diff --git a/chrome/browser/chrome_plugin_unittest.cc b/chrome/browser/chrome_plugin_unittest.cc
index a7eee5b..9322678 100644
--- a/chrome/browser/chrome_plugin_unittest.cc
+++ b/chrome/browser/chrome_plugin_unittest.cc
@@ -9,7 +9,7 @@
#include "base/string_util.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/chrome_plugin_host.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_plugin_lib.h"
#include "chrome/common/net/url_request_context_getter.h"
#include "chrome/test/chrome_plugin/test_chrome_plugin.h"
@@ -42,7 +42,8 @@ class TestURLRequestContextGetter : public URLRequestContextGetter {
scoped_refptr<URLRequestContext> context_;
};
-class ChromePluginTest : public testing::Test, public URLRequest::Delegate {
+class ChromePluginTest : public testing::Test,
+ public net::URLRequest::Delegate {
public:
ChromePluginTest()
: io_thread_(BrowserThread::IO, &message_loop_),
@@ -62,17 +63,18 @@ class ChromePluginTest : public testing::Test, public URLRequest::Delegate {
// is NULL, the request is expected to fail.
void RunTest(const GURL& url, const TestResponsePayload* expected_payload);
- // URLRequest::Delegate implementations
- virtual void OnResponseStarted(URLRequest* request);
- virtual void OnReadCompleted(URLRequest* request, int bytes_read);
+ // net::URLRequest::Delegate implementations
+ virtual void OnResponseStarted(net::URLRequest* request);
+ virtual void OnReadCompleted(net::URLRequest* request, int bytes_read);
- // Helper called when the URLRequest is done.
+ // Helper called when the net::URLRequest is done.
void OnURLRequestComplete();
// testing::Test
virtual void SetUp() {
LoadPlugin();
- URLRequest::RegisterProtocolFactory("test", &URLRequestTestJob::Factory);
+ net::URLRequest::RegisterProtocolFactory("test",
+ &URLRequestTestJob::Factory);
// We need to setup a default request context in order to issue HTTP
// requests.
@@ -81,7 +83,7 @@ class ChromePluginTest : public testing::Test, public URLRequest::Delegate {
}
virtual void TearDown() {
UnloadPlugin();
- URLRequest::RegisterProtocolFactory("test", NULL);
+ net::URLRequest::RegisterProtocolFactory("test", NULL);
Profile::set_default_request_context(NULL);
@@ -96,9 +98,9 @@ class ChromePluginTest : public testing::Test, public URLRequest::Delegate {
MessageLoopForIO message_loop_;
BrowserThread io_thread_;
- // Note: we use URLRequest (instead of URLFetcher) because this allows the
- // request to be intercepted.
- scoped_ptr<URLRequest> request_;
+ // Note: we use net::URLRequest (instead of URLFetcher) because this allows
+ // the request to be intercepted.
+ scoped_ptr<net::URLRequest> request_;
scoped_refptr<net::IOBuffer> response_buffer_;
std::string response_data_;
@@ -166,14 +168,14 @@ void ChromePluginTest::RunTest(const GURL& url,
expected_payload_ = expected_payload;
response_data_.clear();
- request_.reset(new URLRequest(url, this));
+ request_.reset(new net::URLRequest(url, this));
request_->set_context(new TestURLRequestContext());
request_->Start();
MessageLoop::current()->Run();
}
-void ChromePluginTest::OnResponseStarted(URLRequest* request) {
+void ChromePluginTest::OnResponseStarted(net::URLRequest* request) {
DCHECK(request == request_);
int bytes_read = 0;
@@ -182,7 +184,8 @@ void ChromePluginTest::OnResponseStarted(URLRequest* request) {
OnReadCompleted(request_.get(), bytes_read);
}
-void ChromePluginTest::OnReadCompleted(URLRequest* request, int bytes_read) {
+void ChromePluginTest::OnReadCompleted(net::URLRequest* request,
+ int bytes_read) {
DCHECK(request == request_);
do {
diff --git a/chrome/browser/chromeos/audio_handler.cc b/chrome/browser/chromeos/audio_handler.cc
index a463e29..f8ad726 100644
--- a/chrome/browser/chromeos/audio_handler.cc
+++ b/chrome/browser/chromeos/audio_handler.cc
@@ -7,6 +7,7 @@
#include <math.h>
#include "base/logging.h"
+#include "base/singleton.h"
#include "chrome/browser/chromeos/pulse_audio_mixer.h"
namespace chromeos {
@@ -168,4 +169,9 @@ double AudioHandler::PercentToVolumeDb(double volume_percent) {
(kMaxVolumeDb - kMinVolumeDb) + kMinVolumeDb;
}
+// static
+AudioHandler* AudioHandler::GetInstance() {
+ return Singleton<AudioHandler>::get();
+}
+
} // namespace chromeos
diff --git a/chrome/browser/chromeos/audio_handler.h b/chrome/browser/chromeos/audio_handler.h
index 67addcb..59e9d70 100644
--- a/chrome/browser/chromeos/audio_handler.h
+++ b/chrome/browser/chromeos/audio_handler.h
@@ -6,8 +6,10 @@
#define CHROME_BROWSER_CHROMEOS_AUDIO_HANDLER_H_
#pragma once
+#include "base/basictypes.h"
#include "base/scoped_ptr.h"
-#include "base/singleton.h"
+
+template <typename T> struct DefaultSingletonTraits;
namespace chromeos {
@@ -15,9 +17,7 @@ class PulseAudioMixer;
class AudioHandler {
public:
- static AudioHandler* instance() {
- return Singleton<AudioHandler>::get();
- }
+ static AudioHandler* GetInstance();
// Get volume level in our internal 0-100% range, 0 being pure silence.
// Volume may go above 100% if another process changes PulseAudio's volume.
diff --git a/chrome/browser/chromeos/boot_times_loader.cc b/chrome/browser/chromeos/boot_times_loader.cc
index 4f7b45f..b405057 100644
--- a/chrome/browser/chromeos/boot_times_loader.cc
+++ b/chrome/browser/chromeos/boot_times_loader.cc
@@ -9,10 +9,10 @@
#include "base/command_line.h"
#include "base/file_path.h"
#include "base/file_util.h"
+#include "base/lazy_instance.h"
#include "base/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/process_util.h"
-#include "base/singleton.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
@@ -62,6 +62,9 @@ static const FilePath::CharType kLoginTimes[] = FPL("login-times-sent");
// Name of file collecting logout times.
static const char kLogoutTimes[] = "logout-times-sent";
+static base::LazyInstance<BootTimesLoader> g_boot_times_loader(
+ base::LINKER_INITIALIZED);
+
BootTimesLoader::BootTimesLoader()
: backend_(new Backend()),
have_registered_(false) {
@@ -71,7 +74,7 @@ BootTimesLoader::BootTimesLoader()
// static
BootTimesLoader* BootTimesLoader::Get() {
- return Singleton<BootTimesLoader>::get();
+ return g_boot_times_loader.Pointer();
}
BootTimesLoader::Handle BootTimesLoader::GetBootTimes(
@@ -373,7 +376,7 @@ void BootTimesLoader::Observe(
// Only log for first tab to render. Make sure this is only done once.
// If the network isn't connected we'll get a second LOAD_START once it is
// and the page is reloaded.
- if (NetworkStateNotifier::Get()->is_connected()) {
+ if (NetworkStateNotifier::GetInstance()->is_connected()) {
// Post difference between first tab and login success time.
AddLoginTimeMarker("LoginDone", true);
RecordCurrentStats(kChromeFirstRender);
diff --git a/chrome/browser/chromeos/brightness_bubble.cc b/chrome/browser/chromeos/brightness_bubble.cc
new file mode 100644
index 0000000..5299e4b
--- /dev/null
+++ b/chrome/browser/chromeos/brightness_bubble.cc
@@ -0,0 +1,28 @@
+// 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.
+
+#include "chrome/browser/chromeos/brightness_bubble.h"
+
+#include "app/resource_bundle.h"
+#include "base/singleton.h"
+#include "grit/theme_resources.h"
+
+namespace chromeos {
+
+BrightnessBubble::BrightnessBubble()
+ : SettingLevelBubble(
+ ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_BRIGHTNESS_BUBBLE_ICON),
+ ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_BRIGHTNESS_BUBBLE_ICON),
+ ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_BRIGHTNESS_BUBBLE_ICON)) {
+}
+
+// static
+BrightnessBubble* BrightnessBubble::GetInstance() {
+ return Singleton<BrightnessBubble>::get();
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/brightness_bubble.h b/chrome/browser/chromeos/brightness_bubble.h
new file mode 100644
index 0000000..7b5ed8c
--- /dev/null
+++ b/chrome/browser/chromeos/brightness_bubble.h
@@ -0,0 +1,32 @@
+// 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_BRIGHTNESS_BUBBLE_H_
+#define CHROME_BROWSER_CHROMEOS_BRIGHTNESS_BUBBLE_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "chrome/browser/chromeos/setting_level_bubble.h"
+
+template <typename T> struct DefaultSingletonTraits;
+
+namespace chromeos {
+
+// Singleton class controlling brightness bubble.
+class BrightnessBubble : public SettingLevelBubble {
+ public:
+ static BrightnessBubble* GetInstance();
+
+ private:
+ friend struct DefaultSingletonTraits<BrightnessBubble>;
+
+ BrightnessBubble();
+ virtual ~BrightnessBubble() {}
+
+ DISALLOW_COPY_AND_ASSIGN(BrightnessBubble);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_BRIGHTNESS_BUBBLE_H_
diff --git a/chrome/browser/chromeos/brightness_observer.cc b/chrome/browser/chromeos/brightness_observer.cc
new file mode 100644
index 0000000..5a878dd
--- /dev/null
+++ b/chrome/browser/chromeos/brightness_observer.cc
@@ -0,0 +1,17 @@
+// 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.
+
+#include "chrome/browser/chromeos/brightness_observer.h"
+
+#include "chrome/browser/chromeos/brightness_bubble.h"
+#include "chrome/browser/chromeos/volume_bubble.h"
+
+namespace chromeos {
+
+void BrightnessObserver::BrightnessChanged(int level) {
+ BrightnessBubble::GetInstance()->ShowBubble(level);
+ VolumeBubble::GetInstance()->HideBubble();
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/brightness_observer.h b/chrome/browser/chromeos/brightness_observer.h
new file mode 100644
index 0000000..ce7bc95
--- /dev/null
+++ b/chrome/browser/chromeos/brightness_observer.h
@@ -0,0 +1,30 @@
+// 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_BRIGHTNESS_OBSERVER_H_
+#define CHROME_BROWSER_CHROMEOS_BRIGHTNESS_OBSERVER_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "chrome/browser/chromeos/cros/brightness_library.h"
+
+namespace chromeos {
+
+// This observer displays a bubble at the bottom of the screen showing the
+// current brightness level whenever the user changes it.
+class BrightnessObserver : public BrightnessLibrary::Observer {
+ public:
+ BrightnessObserver() {}
+ virtual ~BrightnessObserver() {}
+
+ private:
+ // BrightnessLibrary::Observer implementation.
+ virtual void BrightnessChanged(int level);
+
+ DISALLOW_COPY_AND_ASSIGN(BrightnessObserver);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_BRIGHTNESS_OBSERVER_H_
diff --git a/chrome/browser/chromeos/browser_main_chromeos.cc b/chrome/browser/chromeos/browser_main_chromeos.cc
index df4653a..776a82b 100644
--- a/chrome/browser/chromeos/browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/browser_main_chromeos.cc
@@ -4,8 +4,8 @@
#include "chrome/browser/chromeos/browser_main_chromeos.h"
+#include "base/lazy_instance.h"
#include "base/message_loop.h"
-#include "base/singleton.h"
#include <gtk/gtk.h>
@@ -38,12 +38,13 @@ class MessageLoopObserver : public MessageLoopForUI::Observer {
}
};
-void BrowserMainPartsChromeos::PostMainMessageLoopStart() {
- static Singleton<MessageLoopObserver> observer;
+static base::LazyInstance<MessageLoopObserver> g_message_loop_observer(
+ base::LINKER_INITIALIZED);
+void BrowserMainPartsChromeos::PostMainMessageLoopStart() {
BrowserMainPartsPosix::PostMainMessageLoopStart();
MessageLoopForUI* message_loop = MessageLoopForUI::current();
- message_loop->AddObserver(observer.get());
+ message_loop->AddObserver(g_message_loop_observer.Pointer());
}
// static
diff --git a/chrome/browser/chromeos/cros/brightness_library.cc b/chrome/browser/chromeos/cros/brightness_library.cc
new file mode 100644
index 0000000..64bd1bf
--- /dev/null
+++ b/chrome/browser/chromeos/cros/brightness_library.cc
@@ -0,0 +1,93 @@
+// 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.
+
+#include "chrome/browser/chromeos/cros/brightness_library.h"
+
+#include "base/message_loop.h"
+#include "base/observer_list.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/chromeos/brightness_bubble.h"
+#include "chrome/browser/chromeos/volume_bubble.h"
+#include "chrome/browser/chromeos/cros/cros_library.h"
+
+namespace chromeos {
+
+class BrightnessLibraryImpl : public BrightnessLibrary {
+ public:
+ BrightnessLibraryImpl() : brightness_connection_(NULL) {
+ if (CrosLibrary::Get()->EnsureLoaded())
+ Init();
+ }
+
+ ~BrightnessLibraryImpl() {
+ if (brightness_connection_) {
+ chromeos::DisconnectBrightness(brightness_connection_);
+ brightness_connection_ = NULL;
+ }
+ }
+
+ void AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+ }
+
+ void RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+ }
+
+ private:
+ static void BrightnessChangedHandler(void* object,
+ int brightness_level) {
+ BrightnessLibraryImpl* self = static_cast<BrightnessLibraryImpl*>(object);
+ self->OnBrightnessChanged(brightness_level);
+ }
+
+ void Init() {
+ DCHECK(!brightness_connection_) << "Already intialized";
+ brightness_connection_ =
+ chromeos::MonitorBrightness(&BrightnessChangedHandler, this);
+ }
+
+ void OnBrightnessChanged(int brightness_level) {
+ // Make sure we run on the UI thread.
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(this,
+ &BrightnessLibraryImpl::OnBrightnessChanged,
+ brightness_level));
+ return;
+ }
+
+ FOR_EACH_OBSERVER(Observer,
+ observers_,
+ BrightnessChanged(brightness_level));
+ }
+
+ chromeos::BrightnessConnection brightness_connection_;
+
+ ObserverList<Observer> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrightnessLibraryImpl);
+};
+
+class BrightnessLibraryStubImpl : public BrightnessLibrary {
+ public:
+ BrightnessLibraryStubImpl() {}
+ ~BrightnessLibraryStubImpl() {}
+ void AddObserver(Observer* observer) {}
+ void RemoveObserver(Observer* observer) {}
+};
+
+// static
+BrightnessLibrary* BrightnessLibrary::GetImpl(bool stub) {
+ if (stub)
+ return new BrightnessLibraryStubImpl();
+ else
+ return new BrightnessLibraryImpl();
+}
+
+} // namespace chromeos
+
+// Needed for NewRunnableMethod() call above.
+DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::BrightnessLibraryImpl);
diff --git a/chrome/browser/chromeos/cros/brightness_library.h b/chrome/browser/chromeos/cros/brightness_library.h
new file mode 100644
index 0000000..3ebebec
--- /dev/null
+++ b/chrome/browser/chromeos/cros/brightness_library.h
@@ -0,0 +1,32 @@
+// 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_CROS_BRIGHTNESS_LIBRARY_H_
+#define CHROME_BROWSER_CHROMEOS_CROS_BRIGHTNESS_LIBRARY_H_
+#pragma once
+
+#include "third_party/cros/chromeos_brightness.h"
+
+namespace chromeos {
+
+class BrightnessLibrary {
+ public:
+ class Observer {
+ public:
+ virtual void BrightnessChanged(int level) = 0;
+ };
+
+ virtual ~BrightnessLibrary() {}
+
+ virtual void AddObserver(Observer* observer) = 0;
+ virtual void RemoveObserver(Observer* observer) = 0;
+
+ // Factory function, creates a new instance and returns ownership.
+ // For normal usage, access the singleton via CrosLibrary::Get().
+ static BrightnessLibrary* GetImpl(bool stub);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_CROS_BRIGHTNESS_LIBRARY_H_
diff --git a/chrome/browser/chromeos/cros/burn_library.h b/chrome/browser/chromeos/cros/burn_library.h
index 28ebdb1..bc4a657 100644
--- a/chrome/browser/chromeos/cros/burn_library.h
+++ b/chrome/browser/chromeos/cros/burn_library.h
@@ -12,8 +12,7 @@
#include "base/file_path.h"
#include "base/observer_list.h"
#include "base/weak_ptr.h"
-
-#include "cros/chromeos_imageburn.h"
+#include "third_party/cros/chromeos_imageburn.h"
struct ImageBurnStatus {
explicit ImageBurnStatus(const chromeos::BurnStatus& status)
diff --git a/chrome/browser/chromeos/cros/cros_library.cc b/chrome/browser/chromeos/cros/cros_library.cc
index 9065304..af6e426 100644
--- a/chrome/browser/chromeos/cros/cros_library.cc
+++ b/chrome/browser/chromeos/cros/cros_library.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/chromeos/cros/cros_library.h"
+#include "base/lazy_instance.h"
+#include "chrome/browser/chromeos/cros/brightness_library.h"
#include "chrome/browser/chromeos/cros/burn_library.h"
#include "chrome/browser/chromeos/cros/cros_library_loader.h"
#include "chrome/browser/chromeos/cros/cryptohome_library.h"
@@ -20,8 +22,23 @@
#include "chrome/browser/chromeos/cros/touchpad_library.h"
#include "chrome/browser/chromeos/cros/update_library.h"
+#define DEFINE_GET_LIBRARY_METHOD(class_prefix, var_prefix) \
+class_prefix##Library* CrosLibrary::Get##class_prefix##Library() { \
+ return var_prefix##_lib_.GetDefaultImpl(use_stub_impl_); \
+}
+
+#define DEFINE_SET_LIBRARY_METHOD(class_prefix, var_prefix) \
+void CrosLibrary::TestApi::Set##class_prefix##Library( \
+ class_prefix##Library* library, bool own) { \
+ library_->var_prefix##_lib_.SetImpl(library, own); \
+}
+
+
namespace chromeos {
+static base::LazyInstance<CrosLibrary> g_cros_library(
+ base::LINKER_INITIALIZED);
+
CrosLibrary::CrosLibrary() : library_loader_(NULL),
own_library_loader_(false),
use_stub_impl_(false),
@@ -37,64 +54,24 @@ CrosLibrary::~CrosLibrary() {
// static
CrosLibrary* CrosLibrary::Get() {
- return Singleton<CrosLibrary>::get();
-}
-
-BurnLibrary* CrosLibrary::GetBurnLibrary() {
- return burn_lib_.GetDefaultImpl(use_stub_impl_);
-}
-
-CryptohomeLibrary* CrosLibrary::GetCryptohomeLibrary() {
- return crypto_lib_.GetDefaultImpl(use_stub_impl_);
-}
-
-KeyboardLibrary* CrosLibrary::GetKeyboardLibrary() {
- return keyboard_lib_.GetDefaultImpl(use_stub_impl_);
-}
-
-InputMethodLibrary* CrosLibrary::GetInputMethodLibrary() {
- return input_method_lib_.GetDefaultImpl(use_stub_impl_);
-}
-
-LoginLibrary* CrosLibrary::GetLoginLibrary() {
- return login_lib_.GetDefaultImpl(use_stub_impl_);
-}
-
-MountLibrary* CrosLibrary::GetMountLibrary() {
- return mount_lib_.GetDefaultImpl(use_stub_impl_);
-}
-
-NetworkLibrary* CrosLibrary::GetNetworkLibrary() {
- return network_lib_.GetDefaultImpl(use_stub_impl_);
-}
-
-PowerLibrary* CrosLibrary::GetPowerLibrary() {
- return power_lib_.GetDefaultImpl(use_stub_impl_);
-}
-
-ScreenLockLibrary* CrosLibrary::GetScreenLockLibrary() {
- return screen_lock_lib_.GetDefaultImpl(use_stub_impl_);
-}
-
-SpeechSynthesisLibrary* CrosLibrary::GetSpeechSynthesisLibrary() {
- return speech_synthesis_lib_.GetDefaultImpl(use_stub_impl_);
-}
-
-SyslogsLibrary* CrosLibrary::GetSyslogsLibrary() {
- return syslogs_lib_.GetDefaultImpl(use_stub_impl_);
-}
-
-SystemLibrary* CrosLibrary::GetSystemLibrary() {
- return system_lib_.GetDefaultImpl(use_stub_impl_);
-}
-
-TouchpadLibrary* CrosLibrary::GetTouchpadLibrary() {
- return touchpad_lib_.GetDefaultImpl(use_stub_impl_);
-}
-
-UpdateLibrary* CrosLibrary::GetUpdateLibrary() {
- return update_lib_.GetDefaultImpl(use_stub_impl_);
-}
+ return g_cros_library.Pointer();
+}
+
+DEFINE_GET_LIBRARY_METHOD(Brightness, brightness);
+DEFINE_GET_LIBRARY_METHOD(Burn, burn);
+DEFINE_GET_LIBRARY_METHOD(Cryptohome, crypto);
+DEFINE_GET_LIBRARY_METHOD(Keyboard, keyboard);
+DEFINE_GET_LIBRARY_METHOD(InputMethod, input_method);
+DEFINE_GET_LIBRARY_METHOD(Login, login);
+DEFINE_GET_LIBRARY_METHOD(Mount, mount);
+DEFINE_GET_LIBRARY_METHOD(Network, network);
+DEFINE_GET_LIBRARY_METHOD(Power, power);
+DEFINE_GET_LIBRARY_METHOD(ScreenLock, screen_lock);
+DEFINE_GET_LIBRARY_METHOD(SpeechSynthesis, speech_synthesis);
+DEFINE_GET_LIBRARY_METHOD(Syslogs, syslogs);
+DEFINE_GET_LIBRARY_METHOD(System, system);
+DEFINE_GET_LIBRARY_METHOD(Touchpad, touchpad);
+DEFINE_GET_LIBRARY_METHOD(Update, update);
bool CrosLibrary::EnsureLoaded() {
if (use_stub_impl_)
@@ -138,74 +115,20 @@ void CrosLibrary::TestApi::SetLibraryLoader(LibraryLoader* loader, bool own) {
library_->load_error_ = false;
}
-void CrosLibrary::TestApi::SetBurnLibrary(
- BurnLibrary* library, bool own) {
- library_->burn_lib_.SetImpl(library, own);
-}
-
-void CrosLibrary::TestApi::SetCryptohomeLibrary(
- CryptohomeLibrary* library, bool own) {
- library_->crypto_lib_.SetImpl(library, own);
-}
-
-void CrosLibrary::TestApi::SetKeyboardLibrary(
- KeyboardLibrary* library, bool own) {
- library_->keyboard_lib_.SetImpl(library, own);
-}
-
-void CrosLibrary::TestApi::SetInputMethodLibrary(
- InputMethodLibrary* library, bool own) {
- library_->input_method_lib_.SetImpl(library, own);
-}
-
-void CrosLibrary::TestApi::SetLoginLibrary(
- LoginLibrary* library, bool own) {
- library_->login_lib_.SetImpl(library, own);
-}
-
-void CrosLibrary::TestApi::SetMountLibrary(
- MountLibrary* library, bool own) {
- library_->mount_lib_.SetImpl(library, own);
-}
-
-void CrosLibrary::TestApi::SetNetworkLibrary(
- NetworkLibrary* library, bool own) {
- library_->network_lib_.SetImpl(library, own);
-}
-
-void CrosLibrary::TestApi::SetPowerLibrary(
- PowerLibrary* library, bool own) {
- library_->power_lib_.SetImpl(library, own);
-}
-
-void CrosLibrary::TestApi::SetScreenLockLibrary(
- ScreenLockLibrary* library, bool own) {
- library_->screen_lock_lib_.SetImpl(library, own);
-}
-
-void CrosLibrary::TestApi::SetSpeechSynthesisLibrary(
- SpeechSynthesisLibrary* library, bool own) {
- library_->speech_synthesis_lib_.SetImpl(library, own);
-}
-
-void CrosLibrary::TestApi::SetTouchpadLibrary(
- TouchpadLibrary* library, bool own) {
- library_->touchpad_lib_.SetImpl(library, own);
-}
-
-void CrosLibrary::TestApi::SetSyslogsLibrary(
- SyslogsLibrary* library, bool own) {
- library_->syslogs_lib_.SetImpl(library, own);
-}
-
-void CrosLibrary::TestApi::SetSystemLibrary(
- SystemLibrary* library, bool own) {
- library_->system_lib_.SetImpl(library, own);
-}
-
-void CrosLibrary::TestApi::SetUpdateLibrary(
- UpdateLibrary* library, bool own) {
- library_->update_lib_.SetImpl(library, own);
-}
+DEFINE_SET_LIBRARY_METHOD(Brightness, brightness);
+DEFINE_SET_LIBRARY_METHOD(Burn, burn);
+DEFINE_SET_LIBRARY_METHOD(Cryptohome, crypto);
+DEFINE_SET_LIBRARY_METHOD(Keyboard, keyboard);
+DEFINE_SET_LIBRARY_METHOD(InputMethod, input_method);
+DEFINE_SET_LIBRARY_METHOD(Login, login);
+DEFINE_SET_LIBRARY_METHOD(Mount, mount);
+DEFINE_SET_LIBRARY_METHOD(Network, network);
+DEFINE_SET_LIBRARY_METHOD(Power, power);
+DEFINE_SET_LIBRARY_METHOD(ScreenLock, screen_lock);
+DEFINE_SET_LIBRARY_METHOD(SpeechSynthesis, speech_synthesis);
+DEFINE_SET_LIBRARY_METHOD(Syslogs, syslogs);
+DEFINE_SET_LIBRARY_METHOD(System, system);
+DEFINE_SET_LIBRARY_METHOD(Touchpad, touchpad);
+DEFINE_SET_LIBRARY_METHOD(Update, update);
} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros/cros_library.h b/chrome/browser/chromeos/cros/cros_library.h
index 467a9b8..9c5810c 100644
--- a/chrome/browser/chromeos/cros/cros_library.h
+++ b/chrome/browser/chromeos/cros/cros_library.h
@@ -10,14 +10,19 @@
#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/scoped_ptr.h"
-#include "base/singleton.h"
#include "chrome/common/chrome_switches.h"
+
+namespace base {
+template <typename T> struct DefaultLazyInstanceTraits;
+}
+
namespace chromeos {
+class BrightnessLibrary;
class BurnLibrary;
class CryptohomeLibrary;
-class KeyboardLibrary;
class InputMethodLibrary;
+class KeyboardLibrary;
class LibraryLoader;
class LoginLibrary;
class MountLibrary;
@@ -43,40 +48,29 @@ class CrosLibrary {
// Use the stub implementations of the library. This is mainly for
// running the chromeos build of chrome on the desktop.
void SetUseStubImpl();
+
// Reset the stub implementations of the library, called after
// SetUseStubImp is called.
void ResetUseStubImpl();
+
// Passing true for own for these setters will cause them to be deleted
// when the CrosLibrary is deleted (or other mocks are set).
// Setter for LibraryLoader.
void SetLibraryLoader(LibraryLoader* loader, bool own);
- // Setter for BurnLibrary.
+ void SetBrightnessLibrary(BrightnessLibrary* library, bool own);
void SetBurnLibrary(BurnLibrary* library, bool own);
- // Setter for CryptohomeLibrary.
void SetCryptohomeLibrary(CryptohomeLibrary* library, bool own);
- // Setter for KeyboardLibrary
void SetKeyboardLibrary(KeyboardLibrary* library, bool own);
- // Setter for InputMethodLibrary
void SetInputMethodLibrary(InputMethodLibrary* library, bool own);
- // Setter for LoginLibrary.
void SetLoginLibrary(LoginLibrary* library, bool own);
- // Setter for MountLibrary.
void SetMountLibrary(MountLibrary* library, bool own);
- // Setter for NetworkLibrary.
void SetNetworkLibrary(NetworkLibrary* library, bool own);
- // Setter for PowerLibrary.
void SetPowerLibrary(PowerLibrary* library, bool own);
- // Setter for ScreenLockLibrary.
void SetScreenLockLibrary(ScreenLockLibrary* library, bool own);
- // Setter for SpeechSynthesisLibrary.
void SetSpeechSynthesisLibrary(SpeechSynthesisLibrary* library, bool own);
- // Setter for SyslogsLibrary.
void SetSyslogsLibrary(SyslogsLibrary* library, bool own);
- // Setter for SystemLibrary.
void SetSystemLibrary(SystemLibrary* library, bool own);
- // Setter for TouchpadLibrary.
void SetTouchpadLibrary(TouchpadLibrary* library, bool own);
- // Setter for UpdateLibrary.
void SetUpdateLibrary(UpdateLibrary* library, bool own);
private:
@@ -88,46 +82,20 @@ class CrosLibrary {
// This gets the CrosLibrary.
static CrosLibrary* Get();
- // Getter for BurnLibrary.
+ BrightnessLibrary* GetBrightnessLibrary();
BurnLibrary* GetBurnLibrary();
-
- // Getter for CryptohomeLibrary.
CryptohomeLibrary* GetCryptohomeLibrary();
-
- // Getter for KeyboardLibrary
- KeyboardLibrary* GetKeyboardLibrary();
-
- // Getter for InputMethodLibrary
InputMethodLibrary* GetInputMethodLibrary();
-
- // Getter for LoginLibrary.
+ KeyboardLibrary* GetKeyboardLibrary();
LoginLibrary* GetLoginLibrary();
-
- // Getter for MountLibrary
MountLibrary* GetMountLibrary();
-
- // Getter for NetworkLibrary
NetworkLibrary* GetNetworkLibrary();
-
- // Getter for PowerLibrary
PowerLibrary* GetPowerLibrary();
-
- // Getter for ScreenLockLibrary
ScreenLockLibrary* GetScreenLockLibrary();
-
- // This gets the singleton SpeechSynthesisLibrary.
SpeechSynthesisLibrary* GetSpeechSynthesisLibrary();
-
- // This gets the singleton SyslogsLibrary.
SyslogsLibrary* GetSyslogsLibrary();
-
- // This gets the singleton SystemLibrary.
SystemLibrary* GetSystemLibrary();
-
- // This gets the singleton TouchpadLibrary.
TouchpadLibrary* GetTouchpadLibrary();
-
- // This gets the singleton UpdateLibrary.
UpdateLibrary* GetUpdateLibrary();
// Getter for Test API that gives access to internal members of this class.
@@ -143,7 +111,7 @@ class CrosLibrary {
}
private:
- friend struct DefaultSingletonTraits<chromeos::CrosLibrary>;
+ friend struct base::DefaultLazyInstanceTraits<chromeos::CrosLibrary>;
friend class CrosLibrary::TestApi;
CrosLibrary();
@@ -190,6 +158,7 @@ class CrosLibrary {
bool own_;
};
+ Library<BrightnessLibrary> brightness_lib_;
Library<BurnLibrary> burn_lib_;
Library<CryptohomeLibrary> crypto_lib_;
Library<KeyboardLibrary> keyboard_lib_;
@@ -218,6 +187,22 @@ class CrosLibrary {
DISALLOW_COPY_AND_ASSIGN(CrosLibrary);
};
+// The class is used for enabling the stub libcros, and cleaning it up at
+// the end of the object lifetime. Useful for testing.
+class ScopedStubCrosEnabler {
+ public:
+ ScopedStubCrosEnabler() {
+ chromeos::CrosLibrary::Get()->GetTestApi()->SetUseStubImpl();
+ }
+
+ ~ScopedStubCrosEnabler() {
+ chromeos::CrosLibrary::Get()->GetTestApi()->ResetUseStubImpl();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScopedStubCrosEnabler);
+};
+
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_CROS_CROS_LIBRARY_H_
diff --git a/chrome/browser/chromeos/cros/cros_library_loader.cc b/chrome/browser/chromeos/cros/cros_library_loader.cc
index a542802..d53d187 100644
--- a/chrome/browser/chromeos/cros/cros_library_loader.cc
+++ b/chrome/browser/chromeos/cros/cros_library_loader.cc
@@ -10,7 +10,7 @@
#include "base/logging.h"
#include "base/path_service.h"
#include "chrome/common/chrome_paths.h"
-#include "cros/chromeos_cros_api.h"
+#include "third_party/cros/chromeos_cros_api.h"
namespace chromeos {
diff --git a/chrome/browser/chromeos/cros/cros_mock.cc b/chrome/browser/chromeos/cros/cros_mock.cc
index 0d9b57b..efdfbcc 100644
--- a/chrome/browser/chromeos/cros/cros_mock.cc
+++ b/chrome/browser/chromeos/cros/cros_mock.cc
@@ -7,7 +7,6 @@
#include "base/message_loop.h"
#include "base/ref_counted.h"
#include "base/time.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/cros/mock_cryptohome_library.h"
#include "chrome/browser/chromeos/cros/mock_input_method_library.h"
#include "chrome/browser/chromeos/cros/mock_keyboard_library.h"
@@ -270,26 +269,54 @@ void CrosMock::SetInputMethodLibraryStatusAreaExpectations() {
}
void CrosMock::SetNetworkLibraryStatusAreaExpectations() {
+ // We don't care how often these are called, just set their return values:
EXPECT_CALL(*mock_network_library_, AddNetworkManagerObserver(_))
- .Times(1)
- .RetiresOnSaturation();
+ .Times(AnyNumber());
EXPECT_CALL(*mock_network_library_, AddCellularDataPlanObserver(_))
- .Times(1)
- .RetiresOnSaturation();
-
- // NetworkMenuButton::OnNetworkManagerChanged() calls:
+ .Times(AnyNumber());
+ EXPECT_CALL(*mock_network_library_, RemoveNetworkManagerObserver(_))
+ .Times(AnyNumber());
+ EXPECT_CALL(*mock_network_library_, RemoveObserverForAllNetworks(_))
+ .Times(AnyNumber());
+ EXPECT_CALL(*mock_network_library_, RemoveCellularDataPlanObserver(_))
+ .Times(AnyNumber());
+ EXPECT_CALL(*mock_network_library_, ethernet_available())
+ .Times(AnyNumber())
+ .WillRepeatedly((Return(true)));
+ EXPECT_CALL(*mock_network_library_, wifi_available())
+ .Times(AnyNumber())
+ .WillRepeatedly((Return(false)));
+ EXPECT_CALL(*mock_network_library_, cellular_available())
+ .Times(AnyNumber())
+ .WillRepeatedly((Return(false)));
+ EXPECT_CALL(*mock_network_library_, ethernet_enabled())
+ .Times(AnyNumber())
+ .WillRepeatedly((Return(true)));
+ EXPECT_CALL(*mock_network_library_, wifi_enabled())
+ .Times(AnyNumber())
+ .WillRepeatedly((Return(false)));
+ EXPECT_CALL(*mock_network_library_, cellular_enabled())
+ .Times(AnyNumber())
+ .WillRepeatedly((Return(false)));
EXPECT_CALL(*mock_network_library_, active_network())
.Times(AnyNumber())
- .WillRepeatedly((Return((const Network*)(NULL))))
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_network_library_, wifi_connecting())
+ .WillRepeatedly((Return((const Network*)(NULL))));
+ EXPECT_CALL(*mock_network_library_, wifi_network())
.Times(AnyNumber())
- .WillRepeatedly((Return(false)))
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_network_library_, cellular_connecting())
+ .WillRepeatedly((Return((const WifiNetwork*)(NULL))));
+ EXPECT_CALL(*mock_network_library_, cellular_network())
.Times(AnyNumber())
- .WillRepeatedly((Return(false)))
- .RetiresOnSaturation();
+ .WillRepeatedly((Return((const CellularNetwork*)(NULL))));
+ EXPECT_CALL(*mock_network_library_, wifi_networks())
+ .Times(AnyNumber())
+ .WillRepeatedly((ReturnRef(wifi_networks_)));
+ EXPECT_CALL(*mock_network_library_, cellular_networks())
+ .Times(AnyNumber())
+ .WillRepeatedly((ReturnRef(cellular_networks_)));
+
+ // Set specific expectations for interesting functions:
+
+ // NetworkMenuButton::OnNetworkChanged() calls:
EXPECT_CALL(*mock_network_library_, Connected())
.Times(AnyNumber())
.WillRepeatedly((Return(false)))
@@ -300,14 +327,6 @@ void CrosMock::SetNetworkLibraryStatusAreaExpectations() {
.RetiresOnSaturation();
// NetworkMenu::InitMenuItems() calls:
- EXPECT_CALL(*mock_network_library_, ethernet_available())
- .Times(1)
- .WillRepeatedly((Return(true)))
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_network_library_, ethernet_enabled())
- .Times(1)
- .WillRepeatedly((Return(true)))
- .RetiresOnSaturation();
EXPECT_CALL(*mock_network_library_, ethernet_connected())
.Times(1)
.WillRepeatedly((Return(false)))
@@ -316,32 +335,6 @@ void CrosMock::SetNetworkLibraryStatusAreaExpectations() {
.Times(1)
.WillRepeatedly((Return(false)))
.RetiresOnSaturation();
- EXPECT_CALL(*mock_network_library_, wifi_available())
- .Times(1)
- .WillRepeatedly((Return(false)))
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_network_library_, wifi_enabled())
- .Times(1)
- .WillRepeatedly((Return(false)))
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_network_library_, cellular_available())
- .Times(1)
- .WillRepeatedly((Return(false)))
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_network_library_, cellular_enabled())
- .Times(1)
- .WillRepeatedly((Return(false)))
- .RetiresOnSaturation();
-
- EXPECT_CALL(*mock_network_library_, RemoveNetworkManagerObserver(_))
- .Times(1)
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_network_library_, RemoveObserverForAllNetworks(_))
- .Times(1)
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_network_library_, RemoveCellularDataPlanObserver(_))
- .Times(1)
- .RetiresOnSaturation();
}
void CrosMock::SetPowerLibraryStatusAreaExpectations() {
@@ -392,6 +385,9 @@ void CrosMock::SetSpeechSynthesisLibraryExpectations() {
EXPECT_CALL(*mock_speech_synthesis_library_, Speak(_))
.WillOnce(Return(true))
.RetiresOnSaturation();
+ EXPECT_CALL(*mock_speech_synthesis_library_, IsSpeaking())
+ .Times(AnyNumber())
+ .WillRepeatedly(Return(true));
EXPECT_CALL(*mock_speech_synthesis_library_, StopSpeaking())
.WillOnce(Return(true))
.RetiresOnSaturation();
diff --git a/chrome/browser/chromeos/cros/cros_mock.h b/chrome/browser/chromeos/cros/cros_mock.h
index c39843e..990b43f 100644
--- a/chrome/browser/chromeos/cros/cros_mock.h
+++ b/chrome/browser/chromeos/cros/cros_mock.h
@@ -8,7 +8,7 @@
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/network_library.h"
#include "chrome/test/in_process_browser_test.h"
-#include "cros/chromeos_input_method.h"
+#include "third_party/cros/chromeos_input_method.h"
namespace chromeos {
diff --git a/chrome/browser/chromeos/cros/cryptohome_library.h b/chrome/browser/chromeos/cros/cryptohome_library.h
index 0daa2b5..2a1d066 100644
--- a/chrome/browser/chromeos/cros/cryptohome_library.h
+++ b/chrome/browser/chromeos/cros/cryptohome_library.h
@@ -10,7 +10,7 @@
#include "base/singleton.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
-#include "cros/chromeos_cryptohome.h"
+#include "third_party/cros/chromeos_cryptohome.h"
namespace chromeos {
diff --git a/chrome/browser/chromeos/cros/input_method_library.cc b/chrome/browser/chromeos/cros/input_method_library.cc
index 1e6f15a..9b5316f 100644
--- a/chrome/browser/chromeos/cros/input_method_library.cc
+++ b/chrome/browser/chromeos/cros/input_method_library.cc
@@ -23,6 +23,7 @@
#include "chrome/common/notification_service.h"
namespace {
+
const char kIBusDaemonPath[] = "/usr/bin/ibus-daemon";
const char kCandidateWindowPath[] = "/opt/google/chrome/candidate_window";
@@ -290,7 +291,11 @@ class InputMethodLibraryImpl : public InputMethodLibrary,
}
if (active_input_methods_are_changed) {
- FOR_EACH_OBSERVER(Observer, observers_, ActiveInputMethodsChanged(this));
+ const size_t num_active_input_methods = GetNumActiveInputMethods();
+ FOR_EACH_OBSERVER(Observer, observers_,
+ ActiveInputMethodsChanged(this,
+ current_input_method_,
+ num_active_input_methods));
}
}
@@ -386,13 +391,29 @@ class InputMethodLibraryImpl : public InputMethodLibrary,
previous_input_method_ = current_input_method_;
current_input_method_ = new_input_method;
}
- FOR_EACH_OBSERVER(Observer, observers_, InputMethodChanged(this));
+ const size_t num_active_input_methods = GetNumActiveInputMethods();
+ FOR_EACH_OBSERVER(Observer, observers_,
+ InputMethodChanged(this,
+ previous_input_method_,
+ current_input_method_,
+ num_active_input_methods));
+
+ // Ask the first observer to update preferences. We should not ask every
+ // observer to do so. Otherwise, we'll end up updating preferences many
+ // times when many observers are attached (ex. many windows are opened),
+ // which is unnecessary and expensive.
+ ObserverListBase<Observer>::Iterator it(observers_);
+ Observer* first_observer = it.GetNext();
+ if (first_observer) {
+ first_observer->PreferenceUpdateNeeded(this,
+ previous_input_method_,
+ current_input_method_);
+ }
}
void RegisterProperties(const ImePropertyList& prop_list) {
// |prop_list| might be empty. This means "clear all properties."
current_ime_properties_ = prop_list;
- FOR_EACH_OBSERVER(Observer, observers_, ImePropertiesChanged(this));
}
void StartInputMethodProcesses() {
@@ -404,7 +425,6 @@ class InputMethodLibraryImpl : public InputMethodLibrary,
for (size_t i = 0; i < prop_list.size(); ++i) {
FindAndUpdateProperty(prop_list[i], &current_ime_properties_);
}
- FOR_EACH_OBSERVER(Observer, observers_, ImePropertiesChanged(this));
}
// Launches an input method procsess specified by the given command
diff --git a/chrome/browser/chromeos/cros/input_method_library.h b/chrome/browser/chromeos/cros/input_method_library.h
index f3bbe3c..c30db2f 100644
--- a/chrome/browser/chromeos/cros/input_method_library.h
+++ b/chrome/browser/chromeos/cros/input_method_library.h
@@ -12,7 +12,7 @@
#include "base/observer_list.h"
#include "base/time.h"
#include "base/timer.h"
-#include "cros/chromeos_input_method.h"
+#include "third_party/cros/chromeos_input_method.h"
namespace chromeos {
@@ -26,14 +26,23 @@ class InputMethodLibrary {
public:
virtual ~Observer() = 0;
// Called when the current input method is changed.
- virtual void InputMethodChanged(InputMethodLibrary* obj) = 0;
-
- // Called when input method properties (see chromeos_input_method.h
- // for details) are changed.
- virtual void ImePropertiesChanged(InputMethodLibrary* obj) = 0;
+ virtual void InputMethodChanged(
+ InputMethodLibrary* obj,
+ const InputMethodDescriptor& previous_input_method,
+ const InputMethodDescriptor& current_input_method,
+ size_t num_active_input_methods) = 0;
// Called when the active input methods are changed.
- virtual void ActiveInputMethodsChanged(InputMethodLibrary* obj) = 0;
+ virtual void ActiveInputMethodsChanged(
+ InputMethodLibrary* obj,
+ const InputMethodDescriptor& current_input_method,
+ size_t num_active_input_methods) = 0;
+
+ // Called when the preferences have to be updated.
+ virtual void PreferenceUpdateNeeded(
+ InputMethodLibrary* obj,
+ const InputMethodDescriptor& previous_input_method,
+ const InputMethodDescriptor& current_input_method) = 0;
};
virtual ~InputMethodLibrary() {}
diff --git a/chrome/browser/chromeos/cros/keyboard_library.cc b/chrome/browser/chromeos/cros/keyboard_library.cc
index c7728c1..c762390 100644
--- a/chrome/browser/chromeos/cros/keyboard_library.cc
+++ b/chrome/browser/chromeos/cros/keyboard_library.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/chromeos/cros/keyboard_library.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
-#include "cros/chromeos_keyboard.h"
+#include "third_party/cros/chromeos_keyboard.h"
namespace chromeos {
diff --git a/chrome/browser/chromeos/cros/keyboard_library.h b/chrome/browser/chromeos/cros/keyboard_library.h
index b5f0deb..d29f0e6 100644
--- a/chrome/browser/chromeos/cros/keyboard_library.h
+++ b/chrome/browser/chromeos/cros/keyboard_library.h
@@ -6,11 +6,10 @@
#define CHROME_BROWSER_CHROMEOS_CROS_KEYBOARD_LIBRARY_H_
#pragma once
-#include "cros/chromeos_keyboard.h"
-
#include <string>
#include "base/basictypes.h"
+#include "third_party/cros/chromeos_keyboard.h"
namespace chromeos {
diff --git a/chrome/browser/chromeos/cros/login_library.cc b/chrome/browser/chromeos/cros/login_library.cc
index 5af80e9..2f69b02 100644
--- a/chrome/browser/chromeos/cros/login_library.cc
+++ b/chrome/browser/chromeos/cros/login_library.cc
@@ -134,6 +134,10 @@ class LoginLibraryImpl : public LoginLibrary {
return chromeos::StopSession("");
}
+ bool RestartEntd() {
+ return chromeos::RestartEntd();
+ }
+
bool RestartJob(int pid, const std::string& command_line) {
return chromeos::RestartJob(pid, command_line.c_str());
}
@@ -257,6 +261,7 @@ class LoginLibraryStubImpl : public LoginLibrary {
const std::string& unique_id /* unused */) { return true; }
bool StopSession(const std::string& unique_id /* unused */) { return true; }
bool RestartJob(int pid, const std::string& command_line) { return true; }
+ bool RestartEntd() { return true; }
private:
static void DoStubCallback(Delegate* callback) {
diff --git a/chrome/browser/chromeos/cros/login_library.h b/chrome/browser/chromeos/cros/login_library.h
index fc9b11a..9cb687c 100644
--- a/chrome/browser/chromeos/cros/login_library.h
+++ b/chrome/browser/chromeos/cros/login_library.h
@@ -9,7 +9,7 @@
#include <string>
#include "base/singleton.h"
-#include "cros/chromeos_login.h"
+#include "third_party/cros/chromeos_login.h"
namespace chromeos {
@@ -95,6 +95,9 @@ class LoginLibrary {
// indicated by |unique_id|.
virtual bool StopSession(const std::string& unique_id /* unused */) = 0;
+ // Restarts the Enterprise Daemon.
+ virtual bool RestartEntd() = 0;
+
// Restarts the job with specified command line string.
virtual bool RestartJob(int pid, const std::string& command_line) = 0;
diff --git a/chrome/browser/chromeos/cros/mock_login_library.h b/chrome/browser/chromeos/cros/mock_login_library.h
index 43a77b4..48d62c8 100644
--- a/chrome/browser/chromeos/cros/mock_login_library.h
+++ b/chrome/browser/chromeos/cros/mock_login_library.h
@@ -36,6 +36,7 @@ class MockLoginLibrary : public LoginLibrary {
Delegate*));
MOCK_METHOD2(StartSession, bool(const std::string&, const std::string&));
MOCK_METHOD1(StopSession, bool(const std::string&));
+ MOCK_METHOD0(RestartEntd, bool(void));
MOCK_METHOD2(RestartJob, bool(int, const std::string&));
};
diff --git a/chrome/browser/chromeos/cros/mock_mount_library.h b/chrome/browser/chromeos/cros/mock_mount_library.h
index 32a52c2..bc0f79a 100644
--- a/chrome/browser/chromeos/cros/mock_mount_library.h
+++ b/chrome/browser/chromeos/cros/mock_mount_library.h
@@ -11,9 +11,9 @@
#include "base/observer_list.h"
#include "base/time.h"
#include "chrome/browser/chromeos/cros/mount_library.h"
-#include "cros/chromeos_mount.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/cros/chromeos_mount.h"
namespace chromeos {
diff --git a/chrome/browser/chromeos/cros/mock_network_library.h b/chrome/browser/chromeos/cros/mock_network_library.h
index cfa161f..3b541aa 100644
--- a/chrome/browser/chromeos/cros/mock_network_library.h
+++ b/chrome/browser/chromeos/cros/mock_network_library.h
@@ -25,14 +25,15 @@ class MockNetworkLibrary : public NetworkLibrary {
MOCK_METHOD1(RemoveObserverForAllNetworks, void(NetworkObserver*));
MOCK_METHOD1(AddCellularDataPlanObserver, void(CellularDataPlanObserver*));
MOCK_METHOD1(RemoveCellularDataPlanObserver, void(CellularDataPlanObserver*));
- MOCK_METHOD0(ethernet_network, EthernetNetwork*(void));
+ MOCK_CONST_METHOD0(ethernet_network, const EthernetNetwork*(void));
MOCK_CONST_METHOD0(ethernet_connecting, bool(void));
MOCK_CONST_METHOD0(ethernet_connected, bool(void));
- MOCK_METHOD0(wifi_network, WifiNetwork*(void));
+
+ MOCK_CONST_METHOD0(wifi_network, const WifiNetwork*(void));
MOCK_CONST_METHOD0(wifi_connecting, bool(void));
MOCK_CONST_METHOD0(wifi_connected, bool(void));
- MOCK_METHOD0(cellular_network, CellularNetwork*(void));
+ MOCK_CONST_METHOD0(cellular_network, const CellularNetwork*(void));
MOCK_CONST_METHOD0(cellular_connecting, bool(void));
MOCK_CONST_METHOD0(cellular_connected, bool(void));
diff --git a/chrome/browser/chromeos/cros/mount_library.h b/chrome/browser/chromeos/cros/mount_library.h
index f54ba53..21b1dac 100644
--- a/chrome/browser/chromeos/cros/mount_library.h
+++ b/chrome/browser/chromeos/cros/mount_library.h
@@ -12,7 +12,7 @@
#include "base/observer_list.h"
#include "base/singleton.h"
#include "base/time.h"
-#include "cros/chromeos_mount.h"
+#include "third_party/cros/chromeos_mount.h"
namespace chromeos {
diff --git a/chrome/browser/chromeos/cros/network_library.cc b/chrome/browser/chromeos/cros/network_library.cc
index f4a9861..b99cb95 100644
--- a/chrome/browser/chromeos/cros/network_library.cc
+++ b/chrome/browser/chromeos/cros/network_library.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+ // 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.
@@ -16,6 +16,7 @@
#include "base/values.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
+#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/common/time_format.h"
#include "grit/generated_resources.h"
@@ -236,14 +237,14 @@ static bool EnsureCrosLoaded() {
// Network
Network::Network(const Network& network) {
- service_path_ = network.service_path();
- device_path_ = network.device_path();
- ip_address_ = network.ip_address();
- type_ = network.type();
- state_ = network.state();
- error_ = network.error();
- connectable_ = network.connectable();
- is_active_ = network.is_active();
+ service_path_ = network.service_path_;
+ device_path_ = network.device_path_;
+ ip_address_ = network.ip_address_;
+ type_ = network.type_;
+ state_ = network.state_;
+ error_ = network.error_;
+ connectable_ = network.connectable_;
+ is_active_ = network.is_active_;
}
void Network::Clear() {
@@ -356,10 +357,10 @@ void Network::InitIPAddress() {
// WirelessNetwork
WirelessNetwork::WirelessNetwork(const WirelessNetwork& network)
: Network(network) {
- name_ = network.name();
- strength_ = network.strength();
- auto_connect_ = network.auto_connect();
- favorite_ = network.favorite();
+ name_ = network.name_;
+ strength_ = network.strength_;
+ auto_connect_ = network.auto_connect_;
+ favorite_ = network.favorite_;
}
WirelessNetwork::WirelessNetwork(const ServiceInfo* service)
@@ -386,7 +387,7 @@ string16 CellularDataPlan::GetPlanDesciption() const {
case chromeos::CELLULAR_DATA_PLAN_UNLIMITED: {
return l10n_util::GetStringFUTF16(
IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PURCHASE_UNLIMITED_DATA,
- WideToUTF16(base::TimeFormatFriendlyDate(plan_start_time)));
+ base::TimeFormatFriendlyDate(plan_start_time));
break;
}
case chromeos::CELLULAR_DATA_PLAN_METERED_PAID: {
@@ -395,8 +396,7 @@ string16 CellularDataPlan::GetPlanDesciption() const {
FormatBytes(plan_data_bytes,
GetByteDisplayUnits(plan_data_bytes),
true),
- WideToUTF16(base::TimeFormatFriendlyDate(
- plan_start_time)));
+ base::TimeFormatFriendlyDate(plan_start_time));
}
case chromeos::CELLULAR_DATA_PLAN_METERED_BASE: {
return l10n_util::GetStringFUTF16(
@@ -404,8 +404,7 @@ string16 CellularDataPlan::GetPlanDesciption() const {
FormatBytes(plan_data_bytes,
GetByteDisplayUnits(plan_data_bytes),
true),
- WideToUTF16(base::TimeFormatFriendlyDate(
- plan_start_time)));
+ base::TimeFormatFriendlyDate(plan_start_time));
default:
break;
}
@@ -505,26 +504,26 @@ CellularNetwork::CellularNetwork()
CellularNetwork::CellularNetwork(const CellularNetwork& network)
: WirelessNetwork(network) {
- activation_state_ = network.activation_state();
- network_technology_ = network.network_technology();
- roaming_state_ = network.roaming_state();
- connectivity_state_ = network.connectivity_state();
- service_name_ = network.service_name();
- operator_name_ = network.operator_name();
- operator_code_ = network.operator_code();
- payment_url_ = network.payment_url();
- meid_ = network.meid();
- imei_ = network.imei();
- imsi_ = network.imsi();
- esn_ = network.esn();
- mdn_ = network.mdn();
- min_ = network.min();
- model_id_ = network.model_id();
- manufacturer_ = network.manufacturer();
- firmware_revision_ = network.firmware_revision();
- hardware_revision_ = network.hardware_revision();
- last_update_ = network.last_update();
- prl_version_ = network.prl_version();
+ activation_state_ = network.activation_state_;
+ network_technology_ = network.network_technology_;
+ roaming_state_ = network.roaming_state_;
+ connectivity_state_ = network.connectivity_state_;
+ service_name_ = network.service_name_;
+ operator_name_ = network.operator_name_;
+ operator_code_ = network.operator_code_;
+ payment_url_ = network.payment_url_;
+ meid_ = network.meid_;
+ imei_ = network.imei_;
+ imsi_ = network.imsi_;
+ esn_ = network.esn_;
+ mdn_ = network.mdn_;
+ min_ = network.min_;
+ model_id_ = network.model_id_;
+ manufacturer_ = network.manufacturer_;
+ firmware_revision_ = network.firmware_revision_;
+ hardware_revision_ = network.hardware_revision_;
+ last_update_ = network.last_update_;
+ prl_version_ = network.prl_version_;
type_ = TYPE_CELLULAR;
}
@@ -750,24 +749,22 @@ WifiNetwork::WifiNetwork()
WifiNetwork::WifiNetwork(const WifiNetwork& network)
: WirelessNetwork(network) {
- encryption_ = network.encryption();
- passphrase_ = network.passphrase();
- passphrase_required_ = network.passphrase_required();
- identity_ = network.identity();
- cert_path_ = network.cert_path();
+ encryption_ = network.encryption_;
+ passphrase_ = network.passphrase_;
+ passphrase_required_ = network.passphrase_required_;
+ identity_ = network.identity_;
+ cert_path_ = network.cert_path_;
}
WifiNetwork::WifiNetwork(const ServiceInfo* service)
: WirelessNetwork(service) {
encryption_ = service->security;
- passphrase_ = SafeString(service->passphrase);
- // TODO(stevenjb): Remove this once flimflam is setting passphrase_required
- // correctly: http://crosbug.com/8830.
- if (service->state == chromeos::STATE_FAILURE &&
- service->security != chromeos::SECURITY_NONE)
- passphrase_required_ = true;
+ // TODO(stevenjb): Remove this if/when flimflam handles multiple profiles.
+ if (UserManager::Get()->current_user_is_owner())
+ passphrase_ = SafeString(service->passphrase);
else
- passphrase_required_ = service->passphrase_required;
+ passphrase_.clear();
+ passphrase_required_ = service->passphrase_required;
identity_ = SafeString(service->identity);
cert_path_ = SafeString(service->cert_path);
type_ = TYPE_WIFI;
@@ -799,6 +796,14 @@ std::string WifiNetwork::GetEncryptionString() {
return "Unknown";
}
+bool WifiNetwork::IsPassphraseRequired() const {
+ // TODO(stevenjb): Remove error_ tests when fixed in flimflam
+ // (http://crosbug.com/10135).
+ if (error_ == ERROR_BAD_PASSPHRASE || error_ == ERROR_BAD_WEPKEY)
+ return true;
+ return passphrase_required_;
+}
+
// Parse 'path' to determine if the certificate is stored in a pkcs#11 device.
// flimflam recognizes the string "SETTINGS:" to specify authentication
// parameters. 'key_id=' indicates that the certificate is stored in a pkcs#11
@@ -940,7 +945,7 @@ class NetworkLibraryImpl : public NetworkLibrary {
data_plan_observers_.RemoveObserver(observer);
}
- virtual EthernetNetwork* ethernet_network() { return ethernet_; }
+ virtual const EthernetNetwork* ethernet_network() const { return ethernet_; }
virtual bool ethernet_connecting() const {
return ethernet_ ? ethernet_->connecting() : false;
}
@@ -948,7 +953,7 @@ class NetworkLibraryImpl : public NetworkLibrary {
return ethernet_ ? ethernet_->connected() : false;
}
- virtual WifiNetwork* wifi_network() { return wifi_; }
+ virtual const WifiNetwork* wifi_network() const { return wifi_; }
virtual bool wifi_connecting() const {
return wifi_ ? wifi_->connecting() : false;
}
@@ -956,7 +961,7 @@ class NetworkLibraryImpl : public NetworkLibrary {
return wifi_ ? wifi_->connected() : false;
}
- virtual CellularNetwork* cellular_network() { return cellular_; }
+ virtual const CellularNetwork* cellular_network() const { return cellular_; }
virtual bool cellular_connecting() const {
return cellular_ ? cellular_->connecting() : false;
}
@@ -1055,7 +1060,7 @@ class NetworkLibraryImpl : public NetworkLibrary {
WifiNetwork* wifi = GetWirelessNetworkByPath(
wifi_networks_, network->service_path());
if (wifi) {
- // Note: don't save the passphrase here, it might be incorrect.
+ wifi->set_passphrase(password);
wifi->set_identity(identity);
wifi->set_cert_path(certpath);
wifi->set_connecting(true);
@@ -1282,7 +1287,6 @@ class NetworkLibraryImpl : public NetworkLibrary {
}
virtual void EnableWifiNetworkDevice(bool enable) {
- wifi_scanning_ = enable; // Cleared in UpdateNetworkManagerStatus.
EnableNetworkDeviceType(TYPE_WIFI, enable);
}
@@ -1484,8 +1488,17 @@ class NetworkLibraryImpl : public NetworkLibrary {
// Once a connected ethernet service is found, disregard other ethernet
// services that are also found
if (service->type == TYPE_ETHERNET) {
- if (ethernet_enabled())
+ // There could be multiple ethernet services (eth0, dummy0, etc)
+ // In this case, once you find a connected service, ignore the
+ // other ones. Otherwise, you may choose an ethernet service
+ // that is not connected.
+ if (ethernet_enabled() &&
+ (ethernet_ == NULL || !(ethernet_->connected()))) {
+ // If previous ethernet was previously created, free it first
+ if (ethernet_ != NULL)
+ delete ethernet_;
ethernet_ = new EthernetNetwork(service);
+ }
} else if (service->type == TYPE_WIFI) {
// Sometimes flimflam still returns wifi networks when disabled.
// We don't want to show these in the UI.
@@ -1552,14 +1565,11 @@ class NetworkLibraryImpl : public NetworkLibrary {
}
wifi_scanning_ = false;
- // TODO(stevenjb): Enable this code once crosbug.com/9326 is fixed.
- // for (int i = 0; i < system->device_size; i++) {
- // const DeviceInfo* device = system->GetDeviceInfo(i);
- // if (device->type == TYPE_WIFI) {
- // if (device->scanning)
- // wifi_scanning_ = true;
- // }
- // }
+ for (int i = 0; i < system->device_size; i++) {
+ const DeviceInfo* device = system->GetDeviceInfo(i);
+ if (device->type == TYPE_WIFI && device->scanning)
+ wifi_scanning_ = true;
+ }
}
void Init() {
@@ -1909,17 +1919,17 @@ class NetworkLibraryStubImpl : public NetworkLibrary {
CellularDataPlanObserver* observer) {}
virtual void RemoveCellularDataPlanObserver(
CellularDataPlanObserver* observer) {}
- virtual EthernetNetwork* ethernet_network() {
+ virtual const EthernetNetwork* ethernet_network() const {
return ethernet_;
}
virtual bool ethernet_connecting() const { return false; }
virtual bool ethernet_connected() const { return true; }
- virtual WifiNetwork* wifi_network() {
+ virtual const WifiNetwork* wifi_network() const {
return wifi_;
}
virtual bool wifi_connecting() const { return false; }
virtual bool wifi_connected() const { return false; }
- virtual CellularNetwork* cellular_network() {
+ virtual const CellularNetwork* cellular_network() const {
return cellular_;
}
virtual bool cellular_connecting() const { return false; }
diff --git a/chrome/browser/chromeos/cros/network_library.h b/chrome/browser/chromeos/cros/network_library.h
index 41868f2..99780e2 100644
--- a/chrome/browser/chromeos/cros/network_library.h
+++ b/chrome/browser/chromeos/cros/network_library.h
@@ -16,7 +16,7 @@
#include "base/singleton.h"
#include "base/string16.h"
#include "base/timer.h"
-#include "cros/chromeos_network.h"
+#include "third_party/cros/chromeos_network.h"
class Value;
@@ -361,7 +361,6 @@ class WifiNetwork : public WirelessNetwork {
bool encrypted() const { return encryption_ != SECURITY_NONE; }
ConnectionSecurity encryption() const { return encryption_; }
const std::string& passphrase() const { return passphrase_; }
- bool passphrase_required() const { return passphrase_required_; }
const std::string& identity() const { return identity_; }
const std::string& cert_path() const { return cert_path_; }
@@ -385,6 +384,9 @@ class WifiNetwork : public WirelessNetwork {
// This not translated and should be only used for debugging purposes.
std::string GetEncryptionString();
+ // Return true if a passphrase or other input is required to connect.
+ bool IsPassphraseRequired() const;
+
// Return true if cert_path_ indicates that we have loaded the certificate.
bool IsCertificateLoaded() const;
@@ -500,17 +502,17 @@ class NetworkLibrary {
CellularDataPlanObserver* observer) = 0;
// Return the active Ethernet network (or a default structure if inactive).
- virtual EthernetNetwork* ethernet_network() = 0;
+ virtual const EthernetNetwork* ethernet_network() const = 0;
virtual bool ethernet_connecting() const = 0;
virtual bool ethernet_connected() const = 0;
// Return the active Wifi network (or a default structure if none active).
- virtual WifiNetwork* wifi_network() = 0;
+ virtual const WifiNetwork* wifi_network() const = 0;
virtual bool wifi_connecting() const = 0;
virtual bool wifi_connected() const = 0;
// Return the active Cellular network (or a default structure if none active).
- virtual CellularNetwork* cellular_network() = 0;
+ virtual const CellularNetwork* cellular_network() const = 0;
virtual bool cellular_connecting() const = 0;
virtual bool cellular_connected() const = 0;
diff --git a/chrome/browser/chromeos/cros/power_library.h b/chrome/browser/chromeos/cros/power_library.h
index 83a5fc4..ed61e1d 100644
--- a/chrome/browser/chromeos/cros/power_library.h
+++ b/chrome/browser/chromeos/cros/power_library.h
@@ -9,7 +9,7 @@
#include "base/observer_list.h"
#include "base/singleton.h"
#include "base/time.h"
-#include "cros/chromeos_power.h"
+#include "third_party/cros/chromeos_power.h"
namespace chromeos {
diff --git a/chrome/browser/chromeos/cros/screen_lock_library.h b/chrome/browser/chromeos/cros/screen_lock_library.h
index 251c6f4..5bc70c7 100644
--- a/chrome/browser/chromeos/cros/screen_lock_library.h
+++ b/chrome/browser/chromeos/cros/screen_lock_library.h
@@ -7,7 +7,7 @@
#pragma once
#include "base/observer_list.h"
-#include "cros/chromeos_screen_lock.h"
+#include "third_party/cros/chromeos_screen_lock.h"
namespace chromeos {
diff --git a/chrome/browser/chromeos/cros/speech_synthesis_library.cc b/chrome/browser/chromeos/cros/speech_synthesis_library.cc
index b3b19ea..9dc797e 100644
--- a/chrome/browser/chromeos/cros/speech_synthesis_library.cc
+++ b/chrome/browser/chromeos/cros/speech_synthesis_library.cc
@@ -5,12 +5,22 @@
#include "chrome/browser/chromeos/cros/speech_synthesis_library.h"
#include "base/message_loop.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
-#include "cros/chromeos_speech_synthesis.h"
+#include "third_party/cros/chromeos_speech_synthesis.h"
namespace chromeos {
+// TODO(chaitanyag): rename to "locale" after making equivalent change in
+// Chrome OS code.
+const char SpeechSynthesisLibrary::kSpeechPropertyLocale[] = "name";
+
+const char SpeechSynthesisLibrary::kSpeechPropertyGender[] = "gender";
+const char SpeechSynthesisLibrary::kSpeechPropertyRate[] = "rate";
+const char SpeechSynthesisLibrary::kSpeechPropertyPitch[] = "pitch";
+const char SpeechSynthesisLibrary::kSpeechPropertyVolume[] = "volume";
+const char SpeechSynthesisLibrary::kSpeechPropertyEquals[] = "=";
+const char SpeechSynthesisLibrary::kSpeechPropertyDelimiter[] = ";";
+
class SpeechSynthesisLibraryImpl : public SpeechSynthesisLibrary {
public:
SpeechSynthesisLibraryImpl() {}
diff --git a/chrome/browser/chromeos/cros/speech_synthesis_library.h b/chrome/browser/chromeos/cros/speech_synthesis_library.h
index 5ba97d1..fff4409 100644
--- a/chrome/browser/chromeos/cros/speech_synthesis_library.h
+++ b/chrome/browser/chromeos/cros/speech_synthesis_library.h
@@ -16,14 +16,20 @@ class SpeechSynthesisLibrary {
typedef void(*InitStatusCallback)(bool success);
virtual ~SpeechSynthesisLibrary() {}
+
// Speaks the specified text.
virtual bool Speak(const char* text) = 0;
+
// Sets options for the subsequent speech synthesis requests.
+ // Use the constants below.
virtual bool SetSpeakProperties(const char* props) = 0;
+
// Stops speaking the current utterance.
virtual bool StopSpeaking() = 0;
+
// Checks if the engine is currently speaking.
virtual bool IsSpeaking() = 0;
+
// Starts the speech synthesis service and indicates through a callback if
// it started successfully.
virtual void InitTts(InitStatusCallback) = 0;
@@ -31,6 +37,15 @@ class SpeechSynthesisLibrary {
// Factory function, creates a new instance and returns ownership.
// For normal usage, access the singleton via CrosLibrary::Get().
static SpeechSynthesisLibrary* GetImpl(bool stub);
+
+ // Constants to be used with SetSpeakProperties.
+ static const char kSpeechPropertyLocale[];
+ static const char kSpeechPropertyGender[];
+ static const char kSpeechPropertyRate[];
+ static const char kSpeechPropertyPitch[];
+ static const char kSpeechPropertyVolume[];
+ static const char kSpeechPropertyEquals[];
+ static const char kSpeechPropertyDelimiter[];
};
} // namespace chromeos
diff --git a/chrome/browser/chromeos/cros/syslogs_library.h b/chrome/browser/chromeos/cros/syslogs_library.h
index 6b8c441..de53694 100644
--- a/chrome/browser/chromeos/cros/syslogs_library.h
+++ b/chrome/browser/chromeos/cros/syslogs_library.h
@@ -8,7 +8,7 @@
#include "base/singleton.h"
#include "chrome/browser/cancelable_request.h"
-#include "cros/chromeos_syslogs.h"
+#include "third_party/cros/chromeos_syslogs.h"
class CancelableRequestConsumerBase;
diff --git a/chrome/browser/chromeos/cros/system_library.h b/chrome/browser/chromeos/cros/system_library.h
index 9cf6640..414e9c1 100644
--- a/chrome/browser/chromeos/cros/system_library.h
+++ b/chrome/browser/chromeos/cros/system_library.h
@@ -8,7 +8,7 @@
#include "base/observer_list.h"
#include "base/singleton.h"
-#include "cros/chromeos_system.h"
+#include "third_party/cros/chromeos_system.h"
#include "unicode/timezone.h"
namespace chromeos {
diff --git a/chrome/browser/chromeos/cros/touchpad_library.h b/chrome/browser/chromeos/cros/touchpad_library.h
index ab5ea39..09c23ef 100644
--- a/chrome/browser/chromeos/cros/touchpad_library.h
+++ b/chrome/browser/chromeos/cros/touchpad_library.h
@@ -6,7 +6,7 @@
#define CHROME_BROWSER_CHROMEOS_CROS_TOUCHPAD_LIBRARY_H_
#pragma once
-#include "cros/chromeos_touchpad.h"
+#include "third_party/cros/chromeos_touchpad.h"
namespace chromeos {
diff --git a/chrome/browser/chromeos/cros/update_library.h b/chrome/browser/chromeos/cros/update_library.h
index e8a9daa..0ad23c0 100644
--- a/chrome/browser/chromeos/cros/update_library.h
+++ b/chrome/browser/chromeos/cros/update_library.h
@@ -11,7 +11,7 @@
#include "base/observer_list.h"
#include "base/singleton.h"
#include "base/time.h"
-#include "cros/chromeos_update_engine.h"
+#include "third_party/cros/chromeos_update_engine.h"
namespace chromeos {
diff --git a/chrome/browser/chromeos/cros_settings.cc b/chrome/browser/chromeos/cros_settings.cc
index 0c86226..59cdb4d 100644
--- a/chrome/browser/chromeos/cros_settings.cc
+++ b/chrome/browser/chromeos/cros_settings.cc
@@ -4,18 +4,23 @@
#include "chrome/browser/chromeos/cros_settings.h"
-#include "base/singleton.h"
+#include "base/lazy_instance.h"
#include "base/string_util.h"
#include "base/values.h"
#include "chrome/browser/chromeos/cros_settings_provider.h"
#include "chrome/browser/chromeos/user_cros_settings_provider.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
namespace chromeos {
+static base::LazyInstance<CrosSettings> g_cros_settings(
+ base::LINKER_INITIALIZED);
+
CrosSettings* CrosSettings::Get() {
// TODO(xiyaun): Use real stuff when underlying libcros is ready.
- return Singleton<CrosSettings>::get();
+ return g_cros_settings.Pointer();
}
bool CrosSettings::IsCrosSettings(const std::string& path) {
@@ -139,7 +144,7 @@ void CrosSettings::RemoveSettingsObserver(const char* path,
CrosSettingsProvider* CrosSettings::GetProvider(
const std::string& path) const {
for (size_t i = 0; i < providers_.size(); ++i) {
- if (providers_[i]->HandlesSetting(path)){
+ if (providers_[i]->HandlesSetting(path)) {
return providers_[i];
}
}
diff --git a/chrome/browser/chromeos/cros_settings.h b/chrome/browser/chromeos/cros_settings.h
index 226ec08..79428d2 100644
--- a/chrome/browser/chromeos/cros_settings.h
+++ b/chrome/browser/chromeos/cros_settings.h
@@ -16,6 +16,10 @@
#include "chrome/browser/chromeos/cros_settings_names.h"
#include "chrome/common/notification_observer.h"
+namespace base {
+template <typename T> struct DefaultLazyInstanceTraits;
+}
+
class Value;
namespace chromeos {
@@ -80,7 +84,7 @@ class CrosSettings : public NonThreadSafe {
CrosSettings();
~CrosSettings();
CrosSettingsProvider* GetProvider(const std::string& path) const;
- friend struct DefaultSingletonTraits<CrosSettings>;
+ friend struct base::DefaultLazyInstanceTraits<CrosSettings>;
DISALLOW_COPY_AND_ASSIGN(CrosSettings);
};
diff --git a/chrome/browser/chromeos/dom_ui/accounts_options_handler.cc b/chrome/browser/chromeos/dom_ui/accounts_options_handler.cc
index e461989..9d9be53 100644
--- a/chrome/browser/chromeos/dom_ui/accounts_options_handler.cc
+++ b/chrome/browser/chromeos/dom_ui/accounts_options_handler.cc
@@ -17,7 +17,7 @@
namespace chromeos {
AccountsOptionsHandler::AccountsOptionsHandler()
- : CrosOptionsPageUIHandler(new UserCrosSettingsProvider()) {
+ : CrosOptionsPageUIHandler(new UserCrosSettingsProvider) {
}
AccountsOptionsHandler::~AccountsOptionsHandler() {
@@ -43,8 +43,8 @@ void AccountsOptionsHandler::GetLocalizedValues(
localized_strings->SetString("allow_BWSI", l10n_util::GetStringUTF16(
IDS_OPTIONS_ACCOUNTS_ALLOW_BWSI_DESCRIPTION));
- localized_strings->SetString("allow_guest",l10n_util::GetStringUTF16(
- IDS_OPTIONS_ACCOUNTS_ALLOW_GUEST_DESCRIPTION));
+ localized_strings->SetString("use_whitelist",l10n_util::GetStringUTF16(
+ IDS_OPTIONS_ACCOUNTS_USE_WHITELIST_DESCRIPTION));
localized_strings->SetString("show_user_on_signin",l10n_util::GetStringUTF16(
IDS_OPTIONS_ACCOUNTS_SHOW_USER_NAMES_ON_SINGIN_DESCRIPTION));
localized_strings->SetString("username_edit_hint",l10n_util::GetStringUTF16(
@@ -53,6 +53,10 @@ void AccountsOptionsHandler::GetLocalizedValues(
IDS_OPTIONS_ACCOUNTS_USERNAME_FORMAT));
localized_strings->SetString("add_users",l10n_util::GetStringUTF16(
IDS_OPTIONS_ACCOUNTS_ADD_USERS));
+ localized_strings->SetString("owner_only", l10n_util::GetStringUTF16(
+ IDS_OPTIONS_ACCOUNTS_OWNER_ONLY));
+ localized_strings->SetString("owner_user_id", UTF8ToUTF16(
+ UserCrosSettingsProvider::cached_owner()));
localized_strings->SetString("current_user_is_owner",
UserManager::Get()->current_user_is_owner() ?
diff --git a/chrome/browser/chromeos/dom_ui/core_chromeos_options_handler.cc b/chrome/browser/chromeos/dom_ui/core_chromeos_options_handler.cc
index d76e33d..43d1148 100644
--- a/chrome/browser/chromeos/dom_ui/core_chromeos_options_handler.cc
+++ b/chrome/browser/chromeos/dom_ui/core_chromeos_options_handler.cc
@@ -4,11 +4,14 @@
#include "chrome/browser/chromeos/dom_ui/core_chromeos_options_handler.h"
+#include <string>
+
#include "base/json/json_reader.h"
#include "base/string_number_conversions.h"
#include "chrome/browser/chromeos/cros_settings.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
namespace chromeos {
diff --git a/chrome/browser/chromeos/dom_ui/imageburner_ui.cc b/chrome/browser/chromeos/dom_ui/imageburner_ui.cc
index b827c93..24fc64a 100644
--- a/chrome/browser/chromeos/dom_ui/imageburner_ui.cc
+++ b/chrome/browser/chromeos/dom_ui/imageburner_ui.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/chromeos/dom_ui/imageburner_ui.h"
+#include <algorithm>
+
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/i18n/rtl.h"
@@ -17,7 +19,8 @@
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/download/download_types.h"
#include "chrome/browser/download/download_util.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/jstemplate_builder.h"
#include "chrome/common/url_constants.h"
@@ -105,7 +108,7 @@ ImageBurnHandler::ImageBurnHandler(TabContents* contents)
chromeos::CrosLibrary::Get()->GetBurnLibrary();
burn_lib->AddObserver(this);
local_image_file_path_.clear();
- burn_resource_manager_ = Singleton<ImageBurnResourceManager>::get();
+ burn_resource_manager_ = ImageBurnResourceManager::GetInstance();
}
ImageBurnHandler::~ImageBurnHandler() {
@@ -398,7 +401,7 @@ void ImageBurnHandler::CreateLocalImagePath() {
ImageBurnTaskProxy::ImageBurnTaskProxy(
const base::WeakPtr<ImageBurnHandler>& handler)
: handler_(handler) {
- resource_manager_ = Singleton<ImageBurnResourceManager>::get();
+ resource_manager_ = ImageBurnResourceManager::GetInstance();
}
bool ImageBurnTaskProxy::ReportDownloadInitialized() {
@@ -464,6 +467,11 @@ ImageBurnResourceManager::~ImageBurnResourceManager() {
download_manager_->RemoveObserver(this);
}
+// static
+ImageBurnResourceManager* ImageBurnResourceManager::GetInstance() {
+ return Singleton<ImageBurnResourceManager>::get();
+}
+
void ImageBurnResourceManager::OnDownloadUpdated(DownloadItem* download) {
if (download->state() == DownloadItem::CANCELLED) {
image_url_.reset();
@@ -610,7 +618,7 @@ ImageBurnUI::ImageBurnUI(TabContents* contents) : DOMUI(contents) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(html_source)));
}
diff --git a/chrome/browser/chromeos/dom_ui/imageburner_ui.h b/chrome/browser/chromeos/dom_ui/imageburner_ui.h
index 0f2560a..44041e5 100644
--- a/chrome/browser/chromeos/dom_ui/imageburner_ui.h
+++ b/chrome/browser/chromeos/dom_ui/imageburner_ui.h
@@ -22,10 +22,11 @@
#include "chrome/browser/download/download_item.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/download/download_util.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
#include "googleurl/src/gurl.h"
#include "net/base/file_stream.h"
+template <typename T> struct DefaultSingletonTraits;
+
static const std::string kPropertyPath = "path";
static const std::string kPropertyTitle = "title";
static const std::string kPropertyDirectory = "isDirectory";
@@ -36,6 +37,7 @@ static const std::string kImageFileName = "chromeos_image.bin.gz";
static const std::string kTempImageFolderName = "chromeos_image";
class ImageBurnResourceManager;
+class TabContents;
class ImageBurnUIHTMLSource : public ChromeURLDataManager::DataSource {
public:
@@ -158,8 +160,8 @@ class ImageBurnTaskProxy
class ImageBurnResourceManager : public DownloadManager::Observer,
public DownloadItem::Observer {
public:
- ImageBurnResourceManager();
- ~ImageBurnResourceManager();
+ // Returns the singleton instance.
+ static ImageBurnResourceManager* GetInstance();
// DownloadItem::Observer interface
virtual void OnDownloadUpdated(DownloadItem* download);
@@ -190,6 +192,11 @@ class ImageBurnResourceManager : public DownloadManager::Observer,
net::FileStream* CreateFileStream(FilePath* file_path);
private:
+ friend struct DefaultSingletonTraits<ImageBurnResourceManager>;
+
+ ImageBurnResourceManager();
+ ~ImageBurnResourceManager();
+
FilePath local_image_dir_file_path_;
FilePath image_fecher_local_path_;
bool image_download_started_;
@@ -216,4 +223,3 @@ class ImageBurnUI : public DOMUI {
DISALLOW_COPY_AND_ASSIGN(ImageBurnUI);
};
#endif // CHROME_BROWSER_CHROMEOS_DOM_UI_IMAGEBURNER_UI_H_
-
diff --git a/chrome/browser/chromeos/dom_ui/internet_options_handler.cc b/chrome/browser/chromeos/dom_ui/internet_options_handler.cc
index 5f1e772..1b37cea 100644
--- a/chrome/browser/chromeos/dom_ui/internet_options_handler.cc
+++ b/chrome/browser/chromeos/dom_ui/internet_options_handler.cc
@@ -26,11 +26,8 @@
#include "chrome/browser/chromeos/login/ownership_service.h"
#include "chrome/browser/chromeos/status/network_menu.h"
#include "chrome/browser/dom_ui/dom_ui_util.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/views/window.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/time_format.h"
#include "grit/browser_resources.h"
#include "grit/chromium_strings.h"
@@ -296,23 +293,12 @@ void InternetOptionsHandler::GetLocalizedValues(
localized_strings->SetString("generalNetworkingTitle",
l10n_util::GetStringUTF16(
IDS_OPTIONS_SETTINGS_INTERNET_CONTROL_TITLE));
-
- localized_strings->SetString("detailsInternetOk",
- l10n_util::GetStringUTF16(IDS_OK));
localized_strings->SetString("detailsInternetDismiss",
- l10n_util::GetStringUTF16(IDS_CANCEL));
-
- localized_strings->Set("wiredList", GetWiredList());
- localized_strings->Set("wirelessList", GetWirelessList());
- localized_strings->Set("rememberedList", GetRememberedList());
+ l10n_util::GetStringUTF16(IDS_CLOSE));
chromeos::NetworkLibrary* cros =
chromeos::CrosLibrary::Get()->GetNetworkLibrary();
- localized_strings->SetBoolean("wifiAvailable", cros->wifi_available());
- localized_strings->SetBoolean("wifiEnabled", cros->wifi_enabled());
- localized_strings->SetBoolean("cellularAvailable",
- cros->cellular_available());
- localized_strings->SetBoolean("cellularEnabled", cros->cellular_enabled());
+ FillNetworkInfo(localized_strings, cros);
localized_strings->SetBoolean("networkUseSettingsUI", use_settings_ui_);
}
@@ -328,10 +314,10 @@ void InternetOptionsHandler::RegisterMessages() {
NewCallback(this, &InternetOptionsHandler::LoginCallback));
dom_ui_->RegisterMessageCallback("loginToCertNetwork",
NewCallback(this, &InternetOptionsHandler::LoginCertCallback));
- dom_ui_->RegisterMessageCallback("setDetails",
- NewCallback(this, &InternetOptionsHandler::SetDetailsCallback));
dom_ui_->RegisterMessageCallback("loginToOtherNetwork",
NewCallback(this, &InternetOptionsHandler::LoginToOtherCallback));
+ dom_ui_->RegisterMessageCallback("setDetails",
+ NewCallback(this, &InternetOptionsHandler::SetDetailsCallback));
dom_ui_->RegisterMessageCallback("enableWifi",
NewCallback(this, &InternetOptionsHandler::EnableWifiCallback));
dom_ui_->RegisterMessageCallback("disableWifi",
@@ -382,13 +368,7 @@ void InternetOptionsHandler::BuyDataPlanCallback(const ListValue* args) {
void InternetOptionsHandler::RefreshNetworkData(
chromeos::NetworkLibrary* cros) {
DictionaryValue dictionary;
- dictionary.Set("wiredList", GetWiredList());
- dictionary.Set("wirelessList", GetWirelessList());
- dictionary.Set("rememberedList", GetRememberedList());
- dictionary.SetBoolean("wifiAvailable", cros->wifi_available());
- dictionary.SetBoolean("wifiEnabled", cros->wifi_enabled());
- dictionary.SetBoolean("cellularAvailable", cros->cellular_available());
- dictionary.SetBoolean("cellularEnabled", cros->cellular_enabled());
+ FillNetworkInfo(&dictionary, cros);
dom_ui_->CallJavascriptFunction(
L"options.InternetOptions.refreshNetworkData", dictionary);
}
@@ -408,9 +388,6 @@ void InternetOptionsHandler::OnNetworkChanged(
RefreshNetworkData(cros);
}
-// Add an observer for the active network, if any, so
-// that we can dynamically display the correct icon for
-// that network's signal strength.
// TODO(ers) Ideally, on this page we'd monitor all networks for
// signal strength changes, not just the active network.
void InternetOptionsHandler::MonitorActiveNetwork(
@@ -435,7 +412,7 @@ void InternetOptionsHandler::OnCellularDataPlanChanged(
chromeos::NetworkLibrary* obj) {
if (!dom_ui_)
return;
- chromeos::CellularNetwork* cellular = obj->cellular_network();
+ const chromeos::CellularNetwork* cellular = obj->cellular_network();
if (!cellular)
return;
const chromeos::CellularDataPlanVector& plans = cellular->GetDataPlans();
@@ -448,6 +425,8 @@ void InternetOptionsHandler::OnCellularDataPlanChanged(
}
connection_plans.SetString("servicePath", cellular->service_path());
connection_plans.SetBoolean("needsPlan", cellular->needs_new_plan());
+ connection_plans.SetBoolean("activated",
+ cellular->activation_state() == chromeos::ACTIVATION_STATE_ACTIVATED);
connection_plans.Set("plans", plan_list);
dom_ui_->CallJavascriptFunction(
L"options.InternetOptions.updateCellularPlans", connection_plans);
@@ -499,7 +478,7 @@ void InternetOptionsHandler::SetDetailsCallback(const ListValue* args) {
network->set_identity(ident);
changed = true;
}
- if (!is_certificate_in_pkcs11(network->cert_path())) {
+ if (!IsCertificateInPkcs11(network->cert_path())) {
std::string certpath;
if (!args->GetString(3, &certpath)) {
NOTREACHED();
@@ -523,11 +502,7 @@ void InternetOptionsHandler::SetDetailsCallback(const ListValue* args) {
cros->SaveWifiNetwork(network);
}
-// Parse 'path' to determine if the certificate is stored in a pkcs#11 device.
-// flimflam recognizes the string "SETTINGS:" to specify authentication
-// parameters. 'key_id=' indicates that the certificate is stored in a pkcs#11
-// device. See src/third_party/flimflam/files/doc/service-api.txt.
-bool InternetOptionsHandler::is_certificate_in_pkcs11(const std::string& path) {
+bool InternetOptionsHandler::IsCertificateInPkcs11(const std::string& path) {
static const std::string settings_string("SETTINGS:");
static const std::string pkcs11_key("key_id");
if (path.find(settings_string) == 0) {
@@ -544,10 +519,13 @@ void InternetOptionsHandler::PopulateDictionaryDetails(
const chromeos::Network* net, chromeos::NetworkLibrary* cros) {
DCHECK(net);
DictionaryValue dictionary;
- chromeos::ConnectionType type = net->type();
std::string hardware_address;
chromeos::NetworkIPConfigVector ipconfigs =
cros->GetIPConfigs(net->device_path(), &hardware_address);
+ if (!hardware_address.empty()) {
+ dictionary.SetString("hardwareAddress",
+ FormatHardwareAddress(hardware_address));
+ }
scoped_ptr<ListValue> ipconfig_list(new ListValue());
for (chromeos::NetworkIPConfigVector::const_iterator it = ipconfigs.begin();
it != ipconfigs.end(); ++it) {
@@ -560,39 +538,21 @@ void InternetOptionsHandler::PopulateDictionaryDetails(
ipconfig_list->Append(ipconfig_dict.release());
}
dictionary.Set("ipconfigs", ipconfig_list.release());
+
+ chromeos::ConnectionType type = net->type();
dictionary.SetInteger("type", type);
dictionary.SetString("servicePath", net->service_path());
dictionary.SetBoolean("connecting", net->connecting());
dictionary.SetBoolean("connected", net->connected());
dictionary.SetString("connectionState", net->GetStateString());
+
if (type == chromeos::TYPE_WIFI) {
- chromeos::WifiNetwork* wireless =
+ chromeos::WifiNetwork* wifi =
cros->FindWifiNetworkByPath(net->service_path());
- if (!wireless) {
+ if (!wifi) {
LOG(WARNING) << "Cannot find network " << net->service_path();
} else {
- dictionary.SetString("ssid", wireless->name());
- dictionary.SetBoolean("autoConnect", wireless->auto_connect());
- if (wireless->encrypted()) {
- dictionary.SetBoolean("encrypted", true);
- if (wireless->encryption() == chromeos::SECURITY_8021X) {
- bool certificate_in_pkcs11 =
- is_certificate_in_pkcs11(wireless->cert_path());
- if (certificate_in_pkcs11) {
- dictionary.SetBoolean("certInPkcs", true);
- } else {
- dictionary.SetBoolean("certInPkcs", false);
- }
- dictionary.SetString("certPath", wireless->cert_path());
- dictionary.SetString("ident", wireless->identity());
- dictionary.SetBoolean("certNeeded", true);
- dictionary.SetString("certPass", wireless->passphrase());
- } else {
- dictionary.SetBoolean("certNeeded", false);
- }
- } else {
- dictionary.SetBoolean("encrypted", false);
- }
+ PopulateWifiDetails(&dictionary, wifi);
}
} else if (type == chromeos::TYPE_CELLULAR) {
chromeos::CellularNetwork* cellular =
@@ -600,50 +560,81 @@ void InternetOptionsHandler::PopulateDictionaryDetails(
if (!cellular) {
LOG(WARNING) << "Cannot find network " << net->service_path();
} else {
- // Cellular network / connection settings.
- dictionary.SetString("serviceName", cellular->service_name());
- dictionary.SetString("networkTechnology",
- cellular->GetNetworkTechnologyString());
- dictionary.SetString("operatorName", cellular->operator_name());
- dictionary.SetString("operatorCode", cellular->operator_code());
- dictionary.SetString("activationState",
- cellular->GetActivationStateString());
- dictionary.SetString("roamingState",
- cellular->GetRoamingStateString());
- dictionary.SetString("restrictedPool",
- cellular->restricted_pool() ?
- l10n_util::GetStringUTF8(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL) :
- l10n_util::GetStringUTF8(IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL));
- dictionary.SetString("errorState", cellular->GetErrorString());
- dictionary.SetString("supportUrl",
- cellular->payment_url());
- // Device settings.
- dictionary.SetString("manufacturer", cellular->manufacturer());
- dictionary.SetString("modelId", cellular->model_id());
- dictionary.SetString("firmwareRevision", cellular->firmware_revision());
- dictionary.SetString("hardwareRevision", cellular->hardware_revision());
- dictionary.SetString("lastUpdate", cellular->last_update());
- dictionary.SetString("prlVersion", StringPrintf("%u",
- cellular->prl_version()));
- dictionary.SetString("meid", cellular->meid());
- dictionary.SetString("imei", cellular->imei());
- dictionary.SetString("mdn", cellular->mdn());
- dictionary.SetString("imsi", cellular->imsi());
- dictionary.SetString("esn", cellular->esn());
- dictionary.SetString("min", cellular->min());
-
- dictionary.SetBoolean("gsm", cellular->is_gsm());
+ PopulateCellularDetails(&dictionary, cellular);
}
}
- if (!hardware_address.empty()) {
- dictionary.SetString("hardwareAddress",
- FormatHardwareAddress(hardware_address));
- }
dom_ui_->CallJavascriptFunction(
L"options.InternetOptions.showDetailedInfo", dictionary);
}
+void InternetOptionsHandler::PopulateWifiDetails(
+ DictionaryValue* dictionary,
+ const chromeos::WifiNetwork* wifi) {
+ dictionary->SetString("ssid", wifi->name());
+ dictionary->SetBoolean("autoConnect", wifi->auto_connect());
+ if (wifi->encrypted()) {
+ dictionary->SetBoolean("encrypted", true);
+ if (wifi->encryption() == chromeos::SECURITY_8021X) {
+ bool certificate_in_pkcs11 =
+ IsCertificateInPkcs11(wifi->cert_path());
+ if (certificate_in_pkcs11) {
+ dictionary->SetBoolean("certInPkcs", true);
+ } else {
+ dictionary->SetBoolean("certInPkcs", false);
+ }
+ dictionary->SetString("certPath", wifi->cert_path());
+ dictionary->SetString("ident", wifi->identity());
+ dictionary->SetBoolean("certNeeded", true);
+ dictionary->SetString("certPass", wifi->passphrase());
+ } else {
+ dictionary->SetBoolean("certNeeded", false);
+ }
+ } else {
+ dictionary->SetBoolean("encrypted", false);
+ }
+}
+
+void InternetOptionsHandler::PopulateCellularDetails(
+ DictionaryValue* dictionary,
+ const chromeos::CellularNetwork* cellular) {
+ // Cellular network / connection settings.
+ dictionary->SetString("serviceName", cellular->service_name());
+ dictionary->SetString("networkTechnology",
+ cellular->GetNetworkTechnologyString());
+ dictionary->SetString("operatorName", cellular->operator_name());
+ dictionary->SetString("operatorCode", cellular->operator_code());
+ dictionary->SetString("activationState",
+ cellular->GetActivationStateString());
+ dictionary->SetString("roamingState",
+ cellular->GetRoamingStateString());
+ dictionary->SetString("restrictedPool",
+ cellular->restricted_pool() ?
+ l10n_util::GetStringUTF8(
+ IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL) :
+ l10n_util::GetStringUTF8(
+ IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL));
+ dictionary->SetString("errorState", cellular->GetErrorString());
+ dictionary->SetString("supportUrl", cellular->payment_url());
+
+ // Device settings.
+ dictionary->SetString("manufacturer", cellular->manufacturer());
+ dictionary->SetString("modelId", cellular->model_id());
+ dictionary->SetString("firmwareRevision", cellular->firmware_revision());
+ dictionary->SetString("hardwareRevision", cellular->hardware_revision());
+ dictionary->SetString("lastUpdate", cellular->last_update());
+ dictionary->SetString("prlVersion", StringPrintf("%u",
+ cellular->prl_version()));
+ dictionary->SetString("meid", cellular->meid());
+ dictionary->SetString("imei", cellular->imei());
+ dictionary->SetString("mdn", cellular->mdn());
+ dictionary->SetString("imsi", cellular->imsi());
+ dictionary->SetString("esn", cellular->esn());
+ dictionary->SetString("min", cellular->min());
+
+ dictionary->SetBoolean("gsm", cellular->is_gsm());
+}
+
void InternetOptionsHandler::LoginCallback(const ListValue* args) {
std::string service_path;
std::string password;
@@ -749,78 +740,84 @@ void InternetOptionsHandler::ButtonClickCallback(const ListValue* args) {
return;
}
- bool is_owner =
- chromeos::OwnershipService::GetSharedInstance()->CurrentUserIsOwner();
-
int type = atoi(str_type.c_str());
- chromeos::NetworkLibrary* cros =
- chromeos::CrosLibrary::Get()->GetNetworkLibrary();
-
if (type == chromeos::TYPE_ETHERNET) {
- chromeos::EthernetNetwork* ether = cros->ethernet_network();
+ chromeos::NetworkLibrary* cros =
+ chromeos::CrosLibrary::Get()->GetNetworkLibrary();
+ const chromeos::EthernetNetwork* ether = cros->ethernet_network();
PopulateDictionaryDetails(ether, cros);
} else if (type == chromeos::TYPE_WIFI) {
- chromeos::WifiNetwork* network;
- if (command == "forget") {
- if (!is_owner) {
- LOG(WARNING) << "Non-owner tried to forget a network.";
- return;
- }
- cros->ForgetWifiNetwork(service_path);
- } else if (!use_settings_ui_ &&
- service_path == kOtherNetworksFakePath) {
- // Other wifi networks.
- chromeos::NetworkConfigView* view =
- new chromeos::NetworkConfigView();
- CreateModalPopup(view);
- view->SetLoginTextfieldFocus();
- } else if ((network = cros->FindWifiNetworkByPath(service_path))) {
- if (command == "connect") {
- // Connect to wifi here. Open password page if appropriate.
- if (network->encrypted() && !network->auto_connect()) {
- if (use_settings_ui_) {
- if (network->encryption() == chromeos::SECURITY_8021X) {
- PopulateDictionaryDetails(network, cros);
- } else {
- DictionaryValue dictionary;
- dictionary.SetString("servicePath", network->service_path());
- dom_ui_->CallJavascriptFunction(
- L"options.InternetOptions.showPasswordEntry", dictionary);
- }
+ HandleWifiButtonClick(service_path, command);
+ } else if (type == chromeos::TYPE_CELLULAR) {
+ HandleCellularButtonClick(service_path, command);
+ } else {
+ NOTREACHED();
+ }
+}
+
+void InternetOptionsHandler::HandleWifiButtonClick(
+ const std::string& service_path,
+ const std::string& command) {
+ chromeos::NetworkLibrary* cros =
+ chromeos::CrosLibrary::Get()->GetNetworkLibrary();
+ chromeos::WifiNetwork* network;
+ if (command == "forget") {
+ if (!chromeos::OwnershipService::GetSharedInstance()->
+ CurrentUserIsOwner()) {
+ LOG(WARNING) << "Non-owner tried to forget a network.";
+ return;
+ }
+ cros->ForgetWifiNetwork(service_path);
+ } else if (!use_settings_ui_ && service_path == kOtherNetworksFakePath) {
+ // Other wifi networks.
+ CreateModalPopup(new chromeos::NetworkConfigView());
+ } else if ((network = cros->FindWifiNetworkByPath(service_path))) {
+ if (command == "connect") {
+ // Connect to wifi here. Open password page if appropriate.
+ if (network->IsPassphraseRequired()) {
+ if (use_settings_ui_) {
+ if (network->encryption() == chromeos::SECURITY_8021X) {
+ PopulateDictionaryDetails(network, cros);
} else {
- chromeos::NetworkConfigView* view =
- new chromeos::NetworkConfigView(network, true);
- CreateModalPopup(view);
- view->SetLoginTextfieldFocus();
+ DictionaryValue dictionary;
+ dictionary.SetString("servicePath", network->service_path());
+ dom_ui_->CallJavascriptFunction(
+ L"options.InternetOptions.showPasswordEntry", dictionary);
}
} else {
- cros->ConnectToWifiNetwork(
- network, std::string(), std::string(), std::string());
+ CreateModalPopup(new chromeos::NetworkConfigView(network));
}
- } else if (command == "disconnect") {
- cros->DisconnectFromWirelessNetwork(network);
- } else if (command == "options") {
- PopulateDictionaryDetails(network, cros);
+ } else {
+ cros->ConnectToWifiNetwork(
+ network, std::string(), std::string(), std::string());
}
+ } else if (command == "disconnect") {
+ cros->DisconnectFromWirelessNetwork(network);
+ } else if (command == "options") {
+ PopulateDictionaryDetails(network, cros);
}
- } else if (type == chromeos::TYPE_CELLULAR) {
- chromeos::CellularNetwork* cellular =
- cros->FindCellularNetworkByPath(service_path);
- if (cellular) {
- if (command == "connect") {
- cros->ConnectToCellularNetwork(cellular);
- } else if (command == "disconnect") {
- cros->DisconnectFromWirelessNetwork(cellular);
- } else if (command == "activate") {
- Browser* browser = BrowserList::GetLastActive();
- if (browser)
- browser->OpenMobilePlanTabAndActivate();
- } else if (command == "options") {
- PopulateDictionaryDetails(cellular, cros);
- }
+ }
+}
+
+void InternetOptionsHandler::HandleCellularButtonClick(
+ const std::string& service_path,
+ const std::string& command) {
+ chromeos::NetworkLibrary* cros =
+ chromeos::CrosLibrary::Get()->GetNetworkLibrary();
+ chromeos::CellularNetwork* cellular =
+ cros->FindCellularNetworkByPath(service_path);
+ if (cellular) {
+ if (command == "connect") {
+ cros->ConnectToCellularNetwork(cellular);
+ } else if (command == "disconnect") {
+ cros->DisconnectFromWirelessNetwork(cellular);
+ } else if (command == "activate") {
+ Browser* browser = BrowserList::GetLastActive();
+ if (browser)
+ browser->OpenMobilePlanTabAndActivate();
+ } else if (command == "options") {
+ PopulateDictionaryDetails(cellular, cros);
}
- } else {
- NOTREACHED();
}
}
@@ -840,10 +837,16 @@ void InternetOptionsHandler::RefreshCellularPlanCallback(
cros->RefreshCellularDataPlans(cellular);
}
-ListValue* InternetOptionsHandler::GetNetwork(const std::string& service_path,
- const SkBitmap& icon, const std::string& name, bool connecting,
- bool connected, bool connectable, chromeos::ConnectionType connection_type,
- bool remembered, chromeos::ActivationState activation_state,
+ListValue* InternetOptionsHandler::GetNetwork(
+ const std::string& service_path,
+ const SkBitmap& icon,
+ const std::string& name,
+ bool connecting,
+ bool connected,
+ bool connectable,
+ chromeos::ConnectionType connection_type,
+ bool remembered,
+ chromeos::ActivationState activation_state,
bool needs_new_plan) {
ListValue* network = new ListValue();
@@ -864,29 +867,33 @@ ListValue* InternetOptionsHandler::GetNetwork(const std::string& service_path,
chromeos::CellularNetwork::ActivationStateToString(activation_state));
}
}
- // service path
+
+ // To keep the consistency with JS implementation, do not change the order
+ // locally.
+ // TODO(kochi): Use dictionaly for future maintainability.
+ // 0) service path
network->Append(Value::CreateStringValue(service_path));
- // name
+ // 1) name
network->Append(Value::CreateStringValue(name));
- // status
+ // 2) status
network->Append(Value::CreateStringValue(status));
- // type
+ // 3) type
network->Append(Value::CreateIntegerValue(static_cast<int>(connection_type)));
- // connected
+ // 4) connected
network->Append(Value::CreateBooleanValue(connected));
- // connecting
+ // 5) connecting
network->Append(Value::CreateBooleanValue(connecting));
- // icon data url
+ // 6) icon data url
network->Append(Value::CreateStringValue(icon.isNull() ? "" :
dom_ui_util::GetImageDataUrl(icon)));
- // remembered
+ // 7) remembered
network->Append(Value::CreateBooleanValue(remembered));
- // activation_state
+ // 8) activation state
network->Append(Value::CreateIntegerValue(
static_cast<int>(activation_state)));
- // needs_new_plan
+ // 9) needs new plan
network->Append(Value::CreateBooleanValue(needs_new_plan));
- // connectable
+ // 10) connectable
network->Append(Value::CreateBooleanValue(connectable));
return network;
}
@@ -899,7 +906,7 @@ ListValue* InternetOptionsHandler::GetWiredList() {
// If ethernet is not enabled, then don't add anything.
if (cros->ethernet_enabled()) {
- chromeos::EthernetNetwork* ethernet_network =
+ const chromeos::EthernetNetwork* ethernet_network =
cros->ethernet_network();
SkBitmap icon = *rb.GetBitmapNamed(IDR_STATUSBAR_WIRED_BLACK);
if (!ethernet_network || (!ethernet_network->connecting() &&
@@ -933,8 +940,7 @@ ListValue* InternetOptionsHandler::GetWirelessList() {
const chromeos::WifiNetworkVector& wifi_networks = cros->wifi_networks();
for (chromeos::WifiNetworkVector::const_iterator it =
wifi_networks.begin(); it != wifi_networks.end(); ++it) {
- SkBitmap icon = chromeos::NetworkMenu::IconForNetworkStrength(
- (*it)->strength(), true);
+ SkBitmap icon = chromeos::NetworkMenu::IconForNetworkStrength(*it, true);
if ((*it)->encrypted()) {
icon = chromeos::NetworkMenu::IconForDisplay(icon,
*rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_SECURE));
@@ -956,8 +962,7 @@ ListValue* InternetOptionsHandler::GetWirelessList() {
cros->cellular_networks();
for (chromeos::CellularNetworkVector::const_iterator it =
cellular_networks.begin(); it != cellular_networks.end(); ++it) {
- SkBitmap icon = chromeos::NetworkMenu::IconForNetworkStrength(
- (*it)->strength(), true);
+ SkBitmap icon = chromeos::NetworkMenu::IconForNetworkStrength(*it, true);
SkBitmap badge = chromeos::NetworkMenu::BadgeForNetworkTechnology(*it);
icon = chromeos::NetworkMenu::IconForDisplay(icon, badge);
list->Append(GetNetwork(
@@ -1020,3 +1025,14 @@ ListValue* InternetOptionsHandler::GetRememberedList() {
}
return list;
}
+
+void InternetOptionsHandler::FillNetworkInfo(
+ DictionaryValue* dictionary, chromeos::NetworkLibrary* cros) {
+ dictionary->Set("wiredList", GetWiredList());
+ dictionary->Set("wirelessList", GetWirelessList());
+ dictionary->Set("rememberedList", GetRememberedList());
+ dictionary->SetBoolean("wifiAvailable", cros->wifi_available());
+ dictionary->SetBoolean("wifiEnabled", cros->wifi_enabled());
+ dictionary->SetBoolean("cellularAvailable", cros->cellular_available());
+ dictionary->SetBoolean("cellularEnabled", cros->cellular_enabled());
+}
diff --git a/chrome/browser/chromeos/dom_ui/internet_options_handler.h b/chrome/browser/chromeos/dom_ui/internet_options_handler.h
index b44263c..7b857ff 100644
--- a/chrome/browser/chromeos/dom_ui/internet_options_handler.h
+++ b/chrome/browser/chromeos/dom_ui/internet_options_handler.h
@@ -40,15 +40,23 @@ class InternetOptionsHandler
virtual void OnCellularDataPlanChanged(chromeos::NetworkLibrary* network_lib);
private:
- // Open a modal popup dialog.
+ // Opens a modal popup dialog.
void CreateModalPopup(views::WindowDelegate* view);
// Passes data needed to show details overlay for network.
// |args| will be [ network_type, service_path, command ]
- // And command is one of 'options', 'connect', disconnect', or 'forget'
+ // And command is one of 'options', 'connect', disconnect', 'activate' or
+ // 'forget'
+ // Handle{Wifi,Cellular}ButtonClick handles button click on a wireless
+ // network item and a cellular network item respectively.
void ButtonClickCallback(const ListValue* args);
- // Initiates cellular plan data refresh. The results from libcros will
- // be passed through CellularDataPlanChanged() callback method.
+ void HandleWifiButtonClick(const std::string& service_path,
+ const std::string& command);
+ void HandleCellularButtonClick(const std::string& service_path,
+ const std::string& command);
+
+ // Initiates cellular plan data refresh. The results from libcros will be
+ // passed through CellularDataPlanChanged() callback method.
// |args| will be [ service_path ]
void RefreshCellularPlanCallback(const ListValue* args);
@@ -62,36 +70,55 @@ class InternetOptionsHandler
void DisableCellularCallback(const ListValue* args);
void BuyDataPlanCallback(const ListValue* args);
- bool is_certificate_in_pkcs11(const std::string& path);
+ // Parses 'path' to determine if the certificate is stored in a pkcs#11
+ // device. flimflam recognizes the string "SETTINGS:" to specify
+ // authentication parameters. 'key_id=' indicates that the certificate is
+ // stored in a pkcs#11 device.
+ // See src/third_party/flimflam/files/doc/service-api.txt.
+ bool IsCertificateInPkcs11(const std::string& path);
// Populates the ui with the details of the given device path. This forces
// an overlay to be displayed in the UI.
void PopulateDictionaryDetails(const chromeos::Network* net,
chromeos::NetworkLibrary* cros);
-
- // Converts CellularDataPlan structure into dictionary for JS. Formats
- // plan settings into human readable texts.
+ void PopulateWifiDetails(DictionaryValue* dictionary,
+ const chromeos::WifiNetwork* wifi);
+ void PopulateCellularDetails(DictionaryValue* dictionary,
+ const chromeos::CellularNetwork*
+ cellular);
+
+ // Converts CellularDataPlan structure into dictionary for JS. Formats plan
+ // settings into human readable texts.
DictionaryValue* CellularDataPlanToDictionary(
const chromeos::CellularDataPlan* plan);
- // Creates the map of a network
- ListValue* GetNetwork(const std::string& service_path, const SkBitmap& icon,
- const std::string& name, bool connecting, bool connected,
- bool connectable, chromeos::ConnectionType connection_type,
- bool remembered, chromeos::ActivationState activation_state,
- bool restricted_ip);
-
- // Creates the map of wired networks
+ // Creates the map of a network.
+ ListValue* GetNetwork(const std::string& service_path,
+ const SkBitmap& icon,
+ const std::string& name,
+ bool connecting,
+ bool connected,
+ bool connectable,
+ chromeos::ConnectionType connection_type,
+ bool remembered,
+ chromeos::ActivationState activation_state,
+ bool restricted_ip);
+
+ // Creates the map of wired networks.
ListValue* GetWiredList();
- // Creates the map of wireless networks
+ // Creates the map of wireless networks.
ListValue* GetWirelessList();
- // Creates the map of remembered networks
+ // Creates the map of remembered networks.
ListValue* GetRememberedList();
- // Refresh the display of network information
+ // Fills network information into JS dictionary for displaying network lists.
+ void FillNetworkInfo(DictionaryValue* dictionary,
+ chromeos::NetworkLibrary* cros);
+ // Refreshes the display of network information.
void RefreshNetworkData(chromeos::NetworkLibrary* cros);
- // Monitor the active network, if any
+ // Adds an observer for the active network, if any, so that we can dynamically
+ // display the correct icon for that network's signal strength.
void MonitorActiveNetwork(chromeos::NetworkLibrary* cros);
- // If any network is currently active, this is its service path
+ // If any network is currently active, this is its service path.
std::string active_network_;
// A boolean flag of whether to use DOMUI for connect UI. True to use DOMUI
diff --git a/chrome/browser/chromeos/dom_ui/keyboard_overlay_ui.cc b/chrome/browser/chromeos/dom_ui/keyboard_overlay_ui.cc
index e2477aa..9a2c0ce 100644
--- a/chrome/browser/chromeos/dom_ui/keyboard_overlay_ui.cc
+++ b/chrome/browser/chromeos/dom_ui/keyboard_overlay_ui.cc
@@ -16,9 +16,9 @@
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
#include "chrome/common/jstemplate_builder.h"
#include "chrome/common/url_constants.h"
-#include "cros/chromeos_input_method.h"
#include "grit/browser_resources.h"
#include "grit/generated_resources.h"
+#include "third_party/cros/chromeos_input_method.h"
class KeyboardOverlayUIHTMLSource : public ChromeURLDataManager::DataSource {
@@ -295,7 +295,7 @@ KeyboardOverlayUI::KeyboardOverlayUI(TabContents* contents)
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(html_source)));
}
diff --git a/chrome/browser/chromeos/dom_ui/language_customize_modifier_keys_handler.cc b/chrome/browser/chromeos/dom_ui/language_customize_modifier_keys_handler.cc
index 954b971..56e4448 100644
--- a/chrome/browser/chromeos/dom_ui/language_customize_modifier_keys_handler.cc
+++ b/chrome/browser/chromeos/dom_ui/language_customize_modifier_keys_handler.cc
@@ -6,8 +6,8 @@
#include "app/l10n_util.h"
#include "base/values.h"
-#include "cros/chromeos_keyboard.h"
#include "grit/generated_resources.h"
+#include "third_party/cros/chromeos_keyboard.h"
namespace {
const struct ModifierKeysSelectItem {
diff --git a/chrome/browser/chromeos/dom_ui/language_options_handler.cc b/chrome/browser/chromeos/dom_ui/language_options_handler.cc
index 413eecc..cd81ada 100644
--- a/chrome/browser/chromeos/dom_ui/language_options_handler.cc
+++ b/chrome/browser/chromeos/dom_ui/language_options_handler.cc
@@ -20,7 +20,7 @@
#include "chrome/browser/chromeos/input_method/input_method_util.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/pref_names.h"
diff --git a/chrome/browser/chromeos/dom_ui/language_options_handler_unittest.cc b/chrome/browser/chromeos/dom_ui/language_options_handler_unittest.cc
index 4c940ef..ddf58b7 100644
--- a/chrome/browser/chromeos/dom_ui/language_options_handler_unittest.cc
+++ b/chrome/browser/chromeos/dom_ui/language_options_handler_unittest.cc
@@ -27,12 +27,14 @@ static InputMethodDescriptors CreateInputMethodDescriptors() {
return descriptors;
}
-// TODO: Fix this test. See http://crosbug.com/6269
-TEST(LanguageOptionsHandlerTest, DISABLED_GetInputMethodList) {
- // Use the stub libcros. The change is global (i.e. affects other unti
- // tests), but it should be ok. Unit tests should not require the real
- // libcros.
- CrosLibrary::Get()->GetTestApi()->SetUseStubImpl();
+TEST(LanguageOptionsHandlerTest, GetInputMethodList) {
+ // Use the stub libcros. The object will take care of the cleanup.
+ ScopedStubCrosEnabler stub_cros_enabler;
+
+ // Reset the library implementation so it will be initialized
+ // again. Otherwise, non-stub implementation can be reused, if it's
+ // already initialized elsewhere, which results in a crash.
+ CrosLibrary::Get()->GetTestApi()->SetInputMethodLibrary(NULL, false);
InputMethodDescriptors descriptors = CreateInputMethodDescriptors();
scoped_ptr<ListValue> list(
diff --git a/chrome/browser/chromeos/dom_ui/login/authenticator_facade.h b/chrome/browser/chromeos/dom_ui/login/authenticator_facade.h
new file mode 100644
index 0000000..0c6af1c
--- /dev/null
+++ b/chrome/browser/chromeos/dom_ui/login/authenticator_facade.h
@@ -0,0 +1,63 @@
+// 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_AUTHENTICATOR_FACADE_H_
+#define CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_AUTHENTICATOR_FACADE_H_
+#pragma once
+
+#include <string>
+
+#include "chrome/browser/chromeos/login/authenticator.h"
+#include "chrome/browser/chromeos/login/login_utils.h"
+#include "chrome/common/net/gaia/google_service_auth_error.h"
+
+class Profile;
+
+namespace chromeos {
+
+class LoginStatusConsumer;
+
+// AuthenticatorFacade operates as an interface between the DOMui login handling
+// layer and the authentication layer. This allows for using a stubbed version
+// of authentication during testing if needed. Also this allows for a clear
+// seperation between the DOMui login handling code and the code that deals with
+// authentication.
+// What code will be compiled with what DEPS flags:
+// touchui == 0
+// AuthenticatorFacade is not compiled
+// touchui == 1 && chromeos == 0
+// AuthenticatorFacade is compiled in using the stubbed authentication code
+// touchui == 1 && chromes == 1
+// AuthenticatorFacade is compiled in using the functional authentication code
+// TODO(rharrison): Implement the real authentication code.
+class AuthenticatorFacade {
+ public:
+ explicit AuthenticatorFacade(LoginStatusConsumer* consumer) :
+ consumer_(consumer) {}
+ virtual ~AuthenticatorFacade() {}
+ virtual void Setup() {}
+ virtual void AuthenticateToLogin(Profile* profile,
+ const std::string& username,
+ const std::string& password,
+ const std::string& login_token,
+ const std::string& login_captcha) = 0;
+ void AuthenticateToUnlock(const std::string& username,
+ const std::string& password) {
+ AuthenticateToLogin(NULL /* not used */,
+ username,
+ password,
+ std::string(),
+ std::string());
+ }
+
+ protected:
+ LoginStatusConsumer* consumer_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AuthenticatorFacade);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_AUTHENTICATOR_FACADE_H_
diff --git a/chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros.cc b/chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros.cc
new file mode 100644
index 0000000..051c875
--- /dev/null
+++ b/chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros.cc
@@ -0,0 +1,35 @@
+// 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.
+
+#include "chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros.h"
+#include "chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros_helpers.h"
+
+#include <string>
+
+namespace chromeos {
+
+AuthenticatorFacadeCros::AuthenticatorFacadeCros(
+ LoginStatusConsumer* consumer)
+ : AuthenticatorFacade(consumer),
+ authenticator_(NULL),
+ helpers_(new AuthenticatorFacadeCrosHelpers()) {
+}
+
+void AuthenticatorFacadeCros::Setup() {
+ authenticator_ = helpers_->CreateAuthenticator(consumer_);
+}
+
+void AuthenticatorFacadeCros::AuthenticateToLogin(
+ Profile* profile,
+ const std::string& username,
+ const std::string& password,
+ const std::string& login_token,
+ const std::string& login_captcha) {
+ helpers_->PostAuthenticateToLogin(authenticator_.get(),
+ profile,
+ username,
+ password);
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros.h b/chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros.h
new file mode 100644
index 0000000..4135f07
--- /dev/null
+++ b/chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros.h
@@ -0,0 +1,45 @@
+// 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_AUTHENTICATOR_FACADE_CROS_H_
+#define CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_AUTHENTICATOR_FACADE_CROS_H_
+#pragma once
+
+#include <string>
+
+#include "base/scoped_ptr.h"
+#include "chrome/browser/chromeos/login/authenticator.h"
+#include "chrome/browser/chromeos/dom_ui/login/authenticator_facade.h"
+#include "chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros_helpers.h"
+
+namespace chromeos {
+
+class AuthenticatorFacadeCrosHelpers;
+
+// This class provides authentication services to the DOM login screen through
+// libcros. It is only compiled and used when TOUCH_UI and OS_CHROMEOS are
+// defined.
+class AuthenticatorFacadeCros : public AuthenticatorFacade {
+ public:
+ explicit AuthenticatorFacadeCros(LoginStatusConsumer* consumer);
+ virtual ~AuthenticatorFacadeCros() {}
+
+ void Setup();
+ virtual void AuthenticateToLogin(Profile* profile,
+ const std::string& username,
+ const std::string& password,
+ const std::string& login_token,
+ const std::string& login_captcha);
+
+ protected:
+ scoped_refptr<Authenticator> authenticator_;
+ scoped_ptr<AuthenticatorFacadeCrosHelpers> helpers_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AuthenticatorFacadeCros);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_AUTHENTICATOR_FACADE_CROS_H_
diff --git a/chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros_helpers.cc b/chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros_helpers.cc
new file mode 100644
index 0000000..3337c2e
--- /dev/null
+++ b/chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros_helpers.cc
@@ -0,0 +1,43 @@
+// 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.
+
+#include <string>
+
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/chromeos/cros/cros_library.h"
+#include "chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros_helpers.h"
+#include "chrome/browser/chromeos/login/authenticator.h"
+#include "chrome/browser/chromeos/login/login_utils.h"
+
+namespace chromeos {
+
+AuthenticatorFacadeCrosHelpers::AuthenticatorFacadeCrosHelpers() {
+}
+
+Authenticator* AuthenticatorFacadeCrosHelpers::CreateAuthenticator(
+ LoginStatusConsumer* consumer) {
+
+ return CrosLibrary::Get()->EnsureLoaded() ?
+ LoginUtils::Get()->CreateAuthenticator(consumer) :
+ NULL;
+}
+
+void AuthenticatorFacadeCrosHelpers::PostAuthenticateToLogin(
+ Authenticator* authenticator,
+ Profile* profile,
+ const std::string& username,
+ const std::string& password) {
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(authenticator,
+ &Authenticator::AuthenticateToLogin,
+ profile,
+ username,
+ password,
+ std::string(),
+ std::string()));
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros_helpers.h b/chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros_helpers.h
new file mode 100644
index 0000000..ddac0c5
--- /dev/null
+++ b/chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros_helpers.h
@@ -0,0 +1,35 @@
+// 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_AUTHENTICATOR_FACADE_CROS_HELPERS_H_
+#define CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_AUTHENTICATOR_FACADE_CROS_HELPERS_H_
+#pragma once
+
+#include <string>
+
+class Profile;
+
+namespace chromeos {
+
+class Authenticator;
+class LoginStatusConsumer;
+
+class AuthenticatorFacadeCrosHelpers {
+ public:
+ AuthenticatorFacadeCrosHelpers();
+ virtual ~AuthenticatorFacadeCrosHelpers() {}
+
+ virtual Authenticator* CreateAuthenticator(LoginStatusConsumer* consumer);
+ virtual void PostAuthenticateToLogin(Authenticator* authenticator,
+ Profile* profile,
+ const std::string& username,
+ const std::string& password);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AuthenticatorFacadeCrosHelpers);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_AUTHENTICATOR_FACADE_CROS_HELPERS_H_
diff --git a/chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros_unittest.cc b/chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros_unittest.cc
new file mode 100644
index 0000000..a3df5a7
--- /dev/null
+++ b/chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros_unittest.cc
@@ -0,0 +1,132 @@
+// 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.
+
+#include <string>
+
+#include "base/scoped_ptr.h"
+#include "chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros.h"
+#include "chrome/browser/chromeos/dom_ui/login/mock_authenticator_facade_cros_helpers.h"
+#include "chrome/browser/chromeos/dom_ui/login/mock_login_ui_handler.h"
+#include "chrome/browser/chromeos/login/mock_authenticator.h"
+#include "chrome/test/testing_profile.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+using ::testing::Return;
+
+namespace {
+
+class AuthenticatorFacadeCrosHarness
+ : public chromeos::AuthenticatorFacadeCros {
+ public:
+ AuthenticatorFacadeCrosHarness(
+ chromeos::LoginStatusConsumer* consumer)
+ : chromeos::AuthenticatorFacadeCros(consumer) {
+ }
+
+ chromeos::LoginStatusConsumer* GetConsumer() const {
+ return consumer_;
+ }
+ chromeos::MockAuthenticatorFacadeCrosHelpers* GetHelpers() const {
+ return static_cast<chromeos::MockAuthenticatorFacadeCrosHelpers*>(
+ helpers_.get());
+ }
+ void SetHelpers(chromeos::MockAuthenticatorFacadeCrosHelpers* helpers) {
+ helpers_.reset(helpers);
+ }
+ chromeos::MockAuthenticator* GetAuthenticator() const {
+ return static_cast<chromeos::MockAuthenticator*>(
+ authenticator_.get());
+ }
+ void SetAuthenticator(chromeos::MockAuthenticator* authenticator) {
+ authenticator_ = authenticator;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AuthenticatorFacadeCrosHarness);
+};
+
+} // namespace
+
+namespace chromeos {
+
+// Setup Tests
+TEST(AuthenticatorFacadeCrosTest, Setup) {
+ MockLoginUIHandler consumer;
+ MockAuthenticatorFacadeCrosHelpers* helpers =
+ new chromeos::MockAuthenticatorFacadeCrosHelpers();
+ scoped_refptr<chromeos::MockAuthenticator> authenticator =
+ new chromeos::MockAuthenticator(&consumer,
+ std::string(),
+ std::string());
+ TestingProfile mock_profile;
+ AuthenticatorFacadeCrosHarness facade(&consumer);
+
+ facade.SetHelpers(helpers);
+ EXPECT_CALL(*helpers, CreateAuthenticator(&consumer))
+ .Times(1)
+ .WillRepeatedly(Return(authenticator.get()));
+
+ facade.Setup();
+
+ ASSERT_EQ(&consumer, facade.GetConsumer());
+ ASSERT_EQ(authenticator.get(), facade.GetAuthenticator());
+}
+
+// AuthenticateToLogin Tests
+TEST(AuthenticatorFacadeCrosTest, AuthenticateToLogin) {
+ MockLoginUIHandler consumer;
+ MockAuthenticatorFacadeCrosHelpers* helpers =
+ new chromeos::MockAuthenticatorFacadeCrosHelpers();
+ scoped_refptr<chromeos::MockAuthenticator> authenticator =
+ new chromeos::MockAuthenticator(&consumer,
+ std::string(),
+ std::string());
+ TestingProfile mock_profile;
+ std::string test_username("Test_User");
+ std::string test_password("Test_Password");
+ std::string test_token("Test_Token");
+ std::string test_captcha("Test_Captcha");
+ AuthenticatorFacadeCrosHarness facade(&consumer);
+
+ facade.SetHelpers(helpers);
+ facade.SetAuthenticator(authenticator.get());
+ EXPECT_CALL(*helpers, PostAuthenticateToLogin(authenticator.get(),
+ &mock_profile,
+ test_username,
+ test_password))
+ .Times(1);
+
+ facade.AuthenticateToLogin(&mock_profile,
+ test_username,
+ test_password,
+ test_token,
+ test_captcha);
+}
+
+// AuthenticateToUnlock
+TEST(AuthenticatorFacadeCrosTest, AuthenticateToUnlock) {
+ MockLoginUIHandler consumer;
+ MockAuthenticatorFacadeCrosHelpers* helpers =
+ new chromeos::MockAuthenticatorFacadeCrosHelpers();
+ scoped_refptr<chromeos::MockAuthenticator> authenticator =
+ new chromeos::MockAuthenticator(&consumer,
+ std::string(),
+ std::string());
+ std::string test_username("Test_User");
+ std::string test_password("Test_Password");
+ AuthenticatorFacadeCrosHarness facade(&consumer);
+
+ facade.SetHelpers(helpers);
+ facade.SetAuthenticator(authenticator.get());
+ EXPECT_CALL(*helpers, PostAuthenticateToLogin(authenticator.get(),
+ NULL,
+ test_username,
+ test_password))
+ .Times(1);
+
+ facade.AuthenticateToUnlock(test_username, test_password);
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/dom_ui/login/authenticator_facade_stub.cc b/chrome/browser/chromeos/dom_ui/login/authenticator_facade_stub.cc
new file mode 100644
index 0000000..93b138b
--- /dev/null
+++ b/chrome/browser/chromeos/dom_ui/login/authenticator_facade_stub.cc
@@ -0,0 +1,28 @@
+// 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.
+
+#include "chrome/browser/chromeos/dom_ui/login/authenticator_facade_stub.h"
+
+namespace chromeos {
+
+void AuthenticatorFacadeStub::AuthenticateToLogin(
+ Profile* profile,
+ const std::string& username,
+ const std::string& password,
+ const std::string& login_token,
+ const std::string& login_captcha) {
+ if (!expected_username_.compare(username) &&
+ !expected_password_.compare(password)) {
+ consumer_->OnLoginSuccess(username,
+ password,
+ credentials_,
+ false);
+ } else {
+ GoogleServiceAuthError error(
+ GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
+ consumer_->OnLoginFailure(LoginFailure::FromNetworkAuthFailure(error));
+ }
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/dom_ui/login/authenticator_facade_stub.h b/chrome/browser/chromeos/dom_ui/login/authenticator_facade_stub.h
new file mode 100644
index 0000000..b773dbb
--- /dev/null
+++ b/chrome/browser/chromeos/dom_ui/login/authenticator_facade_stub.h
@@ -0,0 +1,48 @@
+// 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_AUTHENTICATOR_FACADE_STUB_H_
+#define CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_AUTHENTICATOR_FACADE_STUB_H_
+#pragma once
+
+#include <string>
+
+#include "chrome/browser/chromeos/dom_ui/login/authenticator_facade.h"
+
+namespace chromeos {
+
+// This class is a stubbed out version of the authentication that is used for
+// functional testing of the LoginUI code. It takes in an expected user/pass
+// pair during construction, which is used for authentication. Any pair that
+// isn't the expected pair will fail authentication and the pair will pass.
+// TODO(rharrison): Once the functional authentication code is completed make
+// sure that this code isn't used in chromeos builds.
+class AuthenticatorFacadeStub : public AuthenticatorFacade {
+ public:
+ AuthenticatorFacadeStub(LoginStatusConsumer* consumer,
+ const std::string& expected_username,
+ const std::string& expected_password) :
+ AuthenticatorFacade(consumer),
+ expected_username_(expected_username),
+ expected_password_(expected_password) {}
+ virtual ~AuthenticatorFacadeStub() {}
+
+ virtual void AuthenticateToLogin(Profile* profile,
+ const std::string& username,
+ const std::string& password,
+ const std::string& login_token,
+ const std::string& login_captcha);
+
+ protected:
+ const std::string expected_username_;
+ const std::string expected_password_;
+ GaiaAuthConsumer::ClientLoginResult credentials_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AuthenticatorFacadeStub);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_AUTHENTICATOR_FACADE_STUB_H_
diff --git a/chrome/browser/chromeos/dom_ui/login/authenticator_facade_stub_unittest.cc b/chrome/browser/chromeos/dom_ui/login/authenticator_facade_stub_unittest.cc
new file mode 100644
index 0000000..4c8252a
--- /dev/null
+++ b/chrome/browser/chromeos/dom_ui/login/authenticator_facade_stub_unittest.cc
@@ -0,0 +1,163 @@
+// 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.
+#include <string>
+
+#include "base/scoped_ptr.h"
+#include "chrome/browser/chromeos/dom_ui/login/authenticator_facade_stub.h"
+#include "chrome/browser/chromeos/dom_ui/login/mock_login_ui_handler.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+
+class LoginStatusConsumer;
+
+namespace {
+
+class AuthenticatorFacadeStubHarness
+ : public chromeos::AuthenticatorFacadeStub {
+ public:
+ AuthenticatorFacadeStubHarness(chromeos::LoginStatusConsumer* consumer,
+ const std::string& username,
+ const std::string& password) :
+ chromeos::AuthenticatorFacadeStub(consumer,
+ username,
+ password) {}
+ const std::string GetUsername() const { return expected_username_; }
+ const std::string GetPassword() const { return expected_password_; }
+ chromeos::LoginStatusConsumer* GetConsumer() const { return consumer_; }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AuthenticatorFacadeStubHarness);
+};
+
+} // namespace
+
+namespace chromeos {
+
+// Setup Tests
+TEST(AuthenticatorFacadeStubTest, SetupSuccess) {
+ MockLoginUIHandler consumer;
+ std::string test_username("Test_User");
+ std::string test_password("Test_Password");
+ scoped_ptr<AuthenticatorFacadeStubHarness>
+ facade(new AuthenticatorFacadeStubHarness(&consumer,
+ test_username,
+ test_password));
+ ASSERT_EQ(&consumer, facade->GetConsumer());
+ ASSERT_EQ(test_username, facade->GetUsername());
+ ASSERT_EQ(test_password, facade->GetPassword());
+}
+
+// AuthenticateToLogin Tests
+TEST(AuthenticatorFacadeStubTest, AuthenticateToLoginSuccess) {
+ MockLoginUIHandler consumer;
+ std::string test_username("Test_User");
+ std::string test_password("Test_Password");
+ std::string test_token("Test_Token");
+ std::string test_captcha("Test_Captcha");
+ scoped_ptr<AuthenticatorFacadeStubHarness>
+ facade(new AuthenticatorFacadeStubHarness(&consumer,
+ test_username,
+ test_password));
+
+ EXPECT_CALL(consumer, OnLoginSuccess(test_username,
+ _,
+ _,
+ false))
+ .Times(1);
+
+ facade->AuthenticateToLogin(NULL,
+ test_username,
+ test_password,
+ test_token,
+ test_captcha);
+}
+
+TEST(AuthenticatorFacadeStubTest, AuthenticateToLoginFailure) {
+ MockLoginUIHandler consumer;
+ std::string test_username("Test_User");
+ std::string test_password("Test_Password");
+ std::string bad_username("Bad_User");
+ std::string bad_password("Bad_Password");
+ std::string test_token("Test_Token");
+ std::string test_captcha("Test_Captcha");
+ scoped_ptr<AuthenticatorFacadeStubHarness>
+ facade(new AuthenticatorFacadeStubHarness(&consumer,
+ test_username,
+ test_password));
+ EXPECT_CALL(consumer, OnLoginFailure(_))
+ .Times(1);
+
+ facade->AuthenticateToLogin(NULL,
+ bad_username,
+ test_password,
+ test_token,
+ test_captcha);
+
+ EXPECT_CALL(consumer, OnLoginFailure(_))
+ .Times(1);
+
+ facade->AuthenticateToLogin(NULL,
+ test_username,
+ bad_password,
+ test_token,
+ test_captcha);
+
+ EXPECT_CALL(consumer, OnLoginFailure(_))
+ .Times(1);
+
+ facade->AuthenticateToLogin(NULL,
+ bad_username,
+ bad_password,
+ test_token,
+ test_captcha);
+}
+
+// AuthenticateToUnlock
+TEST(AuthenticatorFacadeStubTest, AuthenticateToUnlockSuccess) {
+ MockLoginUIHandler consumer;
+ std::string test_username("Test_User");
+ std::string test_password("Test_Password");
+ scoped_ptr<AuthenticatorFacadeStubHarness>
+ facade(new AuthenticatorFacadeStubHarness(&consumer,
+ test_username,
+ test_password));
+
+ EXPECT_CALL(consumer, OnLoginSuccess(test_username,
+ _,
+ _,
+ false))
+ .Times(1);
+
+ facade->AuthenticateToUnlock(test_username, test_password);
+}
+
+TEST(AuthenticatorFacadeStubTest, AuthenticateToUnlockFailure) {
+ MockLoginUIHandler consumer;
+ std::string test_username("Test_User");
+ std::string test_password("Test_Password");
+ std::string bad_username("Bad_User");
+ std::string bad_password("Bad_Password");
+ scoped_ptr<AuthenticatorFacadeStubHarness>
+ facade(new AuthenticatorFacadeStubHarness(&consumer,
+ test_username,
+ test_password));
+ EXPECT_CALL(consumer, OnLoginFailure(_))
+ .Times(1);
+
+ facade->AuthenticateToUnlock(bad_username, test_password);
+
+ EXPECT_CALL(consumer, OnLoginFailure(_))
+ .Times(1);
+
+ facade->AuthenticateToUnlock(test_username, bad_password);
+
+ EXPECT_CALL(consumer, OnLoginFailure(_))
+ .Times(1);
+
+ facade->AuthenticateToUnlock(bad_username, bad_password);
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/dom_ui/login/login_ui.cc b/chrome/browser/chromeos/dom_ui/login/login_ui.cc
new file mode 100644
index 0000000..cf9d3f5
--- /dev/null
+++ b/chrome/browser/chromeos/dom_ui/login/login_ui.cc
@@ -0,0 +1,160 @@
+// 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.
+
+#include "base/ref_counted_memory.h"
+#include "base/singleton.h"
+#include "base/string_piece.h"
+#include "base/values.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/chromeos/dom_ui/login/authenticator_facade.h"
+#include "chrome/browser/chromeos/dom_ui/login/login_ui.h"
+#include "chrome/browser/chromeos/dom_ui/login/login_ui_helpers.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/common/url_constants.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros.h"
+#else
+#include "chrome/browser/chromeos/dom_ui/login/authenticator_facade_stub.h"
+#endif
+
+namespace chromeos {
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// LoginUIHTMLSource
+//
+////////////////////////////////////////////////////////////////////////////////
+
+LoginUIHTMLSource::LoginUIHTMLSource(MessageLoop* message_loop)
+ : DataSource(chrome::kChromeUILoginHost, message_loop),
+ html_operations_(new HTMLOperationsInterface()) {
+}
+
+void LoginUIHTMLSource::StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id) {
+ DictionaryValue localized_strings;
+ SetFontAndTextDirection(&localized_strings);
+
+ base::StringPiece login_html = html_operations_->GetLoginHTML();
+ std::string full_html = html_operations_->GetFullHTML(login_html,
+ &localized_strings);
+ scoped_refptr<RefCountedBytes> html_bytes(
+ html_operations_->CreateHTMLBytes(full_html));
+ SendResponse(request_id,
+ (html_bytes.get()));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// LoginUIHandler
+//
+////////////////////////////////////////////////////////////////////////////////
+
+LoginUIHandler::LoginUIHandler()
+ : facade_(NULL),
+ profile_operations_(NULL),
+ browser_operations_(NULL) {
+#if defined(OS_CHROMEOS)
+ facade_.reset(new chromeos::AuthenticatorFacadeCros(this));
+#else
+ facade_.reset(new chromeos::AuthenticatorFacadeStub(this,
+ "chronos",
+ "chronos"));
+#endif
+ facade_->Setup();
+ profile_operations_.reset(new ProfileOperationsInterface());
+ browser_operations_.reset(new BrowserOperationsInterface());
+}
+
+DOMMessageHandler* LoginUIHandler::Attach(DOMUI* dom_ui) {
+ return DOMMessageHandler::Attach(dom_ui);
+}
+
+void LoginUIHandler::RegisterMessages() {
+ dom_ui_->RegisterMessageCallback(
+ "LaunchIncognito",
+ NewCallback(this,
+ &LoginUIHandler::HandleLaunchIncognito));
+ dom_ui_->RegisterMessageCallback(
+ "AuthenticateUser",
+ NewCallback(this,
+ &LoginUIHandler::HandleAuthenticateUser));
+}
+
+void LoginUIHandler::HandleAuthenticateUser(const ListValue* args) {
+ std::string username;
+ std::string password;
+ size_t expected_size = 2;
+ CHECK_EQ(args->GetSize(), expected_size);
+ args->GetString(0, &username);
+ args->GetString(1, &password);
+
+ Profile* profile = profile_operations_->GetDefaultProfile();
+ // For AuthenticateToLogin we are currently not using/supporting tokens and
+ // captchas, but the function signature that we inherit from
+ // LoginStatusConsumer has two fields for them. We are currently passing in an
+ // empty string for these fields by calling the default constructor for the
+ // string class.
+ facade_->AuthenticateToLogin(profile,
+ username,
+ password,
+ std::string(),
+ std::string());
+}
+
+void LoginUIHandler::HandleLaunchIncognito(const ListValue* args) {
+ Profile* profile = profile_operations_->GetDefaultProfileByPath();
+ Browser* login_browser = browser_operations_->GetLoginBrowser(profile);
+ Browser* logged_in = browser_operations_->CreateBrowser(profile);
+ logged_in->NewTab();
+ logged_in->window()->Show();
+ login_browser->CloseWindow();
+}
+
+void LoginUIHandler::OnLoginFailure(const LoginFailure& failure) {
+ Profile* profile = profile_operations_->GetDefaultProfileByPath();
+ Browser* login_browser = browser_operations_->GetLoginBrowser(profile);
+ login_browser->OpenCurrentURL();
+}
+
+void LoginUIHandler::OnLoginSuccess(
+ const std::string& username,
+ const std::string& password,
+ const GaiaAuthConsumer::ClientLoginResult& credentials,
+ bool pending_requests) {
+ Profile* profile = profile_operations_->GetDefaultProfileByPath();
+ Browser* login_browser = browser_operations_->GetLoginBrowser(profile);
+ Browser* logged_in = browser_operations_->CreateBrowser(profile);
+ logged_in->NewTab();
+ logged_in->window()->Show();
+ login_browser->CloseWindow();
+}
+
+void LoginUIHandler::OnOffTheRecordLoginSuccess() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// LoginUI
+//
+////////////////////////////////////////////////////////////////////////////////
+LoginUI::LoginUI(TabContents* contents)
+ : DOMUI(contents) {
+ LoginUIHandler* handler = new LoginUIHandler();
+ AddMessageHandler(handler->Attach(this));
+ LoginUIHTMLSource* html_source =
+ new LoginUIHTMLSource(MessageLoop::current());
+
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(
+ ChromeURLDataManager::GetInstance(),
+ &ChromeURLDataManager::AddDataSource,
+ make_scoped_refptr(html_source)));
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/dom_ui/login/login_ui.h b/chrome/browser/chromeos/dom_ui/login/login_ui.h
new file mode 100644
index 0000000..b19699e
--- /dev/null
+++ b/chrome/browser/chromeos/dom_ui/login/login_ui.h
@@ -0,0 +1,96 @@
+// 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_LOGIN_UI_H_
+#define CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_LOGIN_UI_H_
+#pragma once
+
+#include <string>
+
+#include "base/scoped_ptr.h"
+#include "chrome/browser/chromeos/login/login_status_consumer.h"
+#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
+#include "chrome/browser/dom_ui/dom_ui.h"
+
+class Profile;
+
+namespace chromeos {
+
+class AuthenticatorFacade;
+class BrowserOperationsInterface;
+class HTMLOperationsInterface;
+class ProfileOperationsInterface;
+
+// Boilerplate class that is used to associate the LoginUI code with the URL
+// "chrome://login"
+class LoginUIHTMLSource : public ChromeURLDataManager::DataSource {
+ public:
+ explicit LoginUIHTMLSource(MessageLoop* message_loop);
+
+ virtual void StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id);
+ virtual std::string GetMimeType(const std::string&) const {
+ return "text/html";
+ }
+
+ private:
+ scoped_ptr<HTMLOperationsInterface> html_operations_;
+
+ DISALLOW_COPY_AND_ASSIGN(LoginUIHTMLSource);
+};
+
+// Main LoginUI handling function. It handles the DOMui hooks that are supplied
+// for the login page to use for authentication. It passes the key pair form the
+// login page to the AuthenticatorFacade. The facade then will call back into
+// this class with the result, which will then be used to determine the browser
+// behaviour.
+class LoginUIHandler : public DOMMessageHandler,
+ public chromeos::LoginStatusConsumer {
+ public:
+ LoginUIHandler();
+
+ // DOMMessageHandler implementation.
+ virtual DOMMessageHandler* Attach(DOMUI* dom_ui);
+ virtual void RegisterMessages();
+
+ void HandleAuthenticateUser(const ListValue* args);
+ void HandleLaunchIncognito(const ListValue* args);
+
+ // Overridden from LoginStatusConsumer.
+ virtual void OnLoginFailure(const chromeos::LoginFailure& failure);
+ virtual void OnLoginSuccess(
+ const std::string& username,
+ const std::string& password,
+ const GaiaAuthConsumer::ClientLoginResult& credentials,
+ bool pending_requests);
+ virtual void OnOffTheRecordLoginSuccess();
+
+ protected:
+ scoped_ptr<AuthenticatorFacade> facade_;
+ scoped_ptr<ProfileOperationsInterface> profile_operations_;
+ scoped_ptr<BrowserOperationsInterface> browser_operations_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(LoginUIHandler);
+};
+
+// Boilerplate class that is used to associate the LoginUI code with the DOMui
+// code.
+class LoginUI : public DOMUI {
+ public:
+ explicit LoginUI(TabContents* contents);
+
+ // Return the URL for a given search term.
+ static const GURL GetLoginURLWithSearchText(const string16& text);
+
+ static RefCountedMemory* GetFaviconResourceBytes();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(LoginUI);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_LOGIN_UI_H_
diff --git a/chrome/browser/chromeos/dom_ui/login/login_ui_helpers.cc b/chrome/browser/chromeos/dom_ui/login/login_ui_helpers.cc
new file mode 100644
index 0000000..c0d05d0
--- /dev/null
+++ b/chrome/browser/chromeos/dom_ui/login/login_ui_helpers.cc
@@ -0,0 +1,94 @@
+// 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.
+// #include <algorithm>
+
+#include <algorithm>
+
+#include "app/resource_bundle.h"
+#include "base/file_path.h"
+#include "base/path_service.h"
+#include "base/values.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/dom_ui/login/login_ui_helpers.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/jstemplate_builder.h"
+#include "grit/browser_resources.h"
+
+namespace chromeos {
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// ProfileOperationsInterface
+//
+////////////////////////////////////////////////////////////////////////////////
+Profile* ProfileOperationsInterface::GetDefaultProfile() {
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ return profile_manager->GetDefaultProfile();
+}
+
+Profile* ProfileOperationsInterface::GetDefaultProfileByPath() {
+ return GetDefaultProfile(GetUserDataPath());
+}
+
+Profile* ProfileOperationsInterface::GetDefaultProfile(FilePath user_data_dir) {
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ return profile_manager->GetDefaultProfile(user_data_dir);
+}
+
+FilePath ProfileOperationsInterface::GetUserDataPath() {
+ FilePath user_data_dir;
+ PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
+ return user_data_dir;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// BrowserOperationsInterface
+//
+////////////////////////////////////////////////////////////////////////////////
+Browser* BrowserOperationsInterface::CreateBrowser(Profile* profile) {
+ return Browser::Create(profile);
+}
+
+Browser* BrowserOperationsInterface::GetLoginBrowser(Profile* profile) {
+ return BrowserList::FindBrowserWithType(profile,
+ Browser::TYPE_ANY,
+ true);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// HTMLOperationsInterface
+//
+////////////////////////////////////////////////////////////////////////////////
+base::StringPiece HTMLOperationsInterface::GetLoginHTML() {
+ base::StringPiece login_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_LOGIN_HTML));
+ return login_html;
+}
+
+std::string HTMLOperationsInterface::GetFullHTML(
+ base::StringPiece login_html,
+ DictionaryValue* localized_strings) {
+ return jstemplate_builder::GetI18nTemplateHtml(
+ login_html,
+ localized_strings);
+}
+
+RefCountedBytes* HTMLOperationsInterface::CreateHTMLBytes(
+ std::string full_html) {
+ RefCountedBytes* html_bytes = new RefCountedBytes();
+ html_bytes->data.resize(full_html.size());
+ std::copy(full_html.begin(),
+ full_html.end(),
+ html_bytes->data.begin());
+ return html_bytes;
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/dom_ui/login/login_ui_helpers.h b/chrome/browser/chromeos/dom_ui/login/login_ui_helpers.h
new file mode 100644
index 0000000..93e73c5
--- /dev/null
+++ b/chrome/browser/chromeos/dom_ui/login/login_ui_helpers.h
@@ -0,0 +1,78 @@
+// 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_LOGIN_UI_HELPERS_H_
+#define CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_LOGIN_UI_HELPERS_H_
+#pragma once
+
+#include <string>
+
+class Browser;
+class DictionaryValue;
+class FilePath;
+class Profile;
+class RefCountedBytes;
+
+namespace base {
+class StringPiece;
+}; // namespace base
+
+namespace chromeos {
+
+// This class is used for encapsulating the statics and other other messy
+// external calls that are required for getting the needed profile objects. This
+// allows for easier mocking of this code and allows for modularity.
+class ProfileOperationsInterface {
+ public:
+ ProfileOperationsInterface() {}
+ virtual ~ProfileOperationsInterface() {}
+
+ virtual Profile* GetDefaultProfile();
+ virtual Profile* GetDefaultProfileByPath();
+
+ private:
+ Profile* GetDefaultProfile(FilePath user_data_dir);
+ FilePath GetUserDataPath();
+
+ DISALLOW_COPY_AND_ASSIGN(ProfileOperationsInterface);
+};
+
+// This class is used for encapsulating the statics and other other messy
+// external calls that are required for creating and getting the needed browser
+// objects. This allows for easier mocking of this code and allows for
+// modularity.
+class BrowserOperationsInterface {
+ public:
+ BrowserOperationsInterface() {}
+ virtual ~BrowserOperationsInterface() {}
+
+ virtual Browser* CreateBrowser(Profile* profile);
+ virtual Browser* GetLoginBrowser(Profile* profile);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BrowserOperationsInterface);
+};
+
+// This class is used for encapsulating the statics and other other messy
+// external calls that are required for creating and getting the needed HTML
+// objects. This allows for easier mocking of this code and allows for
+// modularity. Since we don't currently unit the class that this code is related
+// to, there is a case for refactoring it back into LoginUIHTMLSource.
+class HTMLOperationsInterface {
+ public:
+ HTMLOperationsInterface() {}
+ virtual ~HTMLOperationsInterface() {}
+
+ virtual base::StringPiece GetLoginHTML();
+ virtual std::string GetFullHTML(base::StringPiece login_html,
+ DictionaryValue* localized_strings);
+ virtual RefCountedBytes* CreateHTMLBytes(std::string full_html);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HTMLOperationsInterface);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_LOGIN_UI_HELPERS_H_
diff --git a/chrome/browser/chromeos/dom_ui/login/login_ui_unittest.cc b/chrome/browser/chromeos/dom_ui/login/login_ui_unittest.cc
new file mode 100644
index 0000000..e3e60b3
--- /dev/null
+++ b/chrome/browser/chromeos/dom_ui/login/login_ui_unittest.cc
@@ -0,0 +1,154 @@
+// 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.
+
+#include <string>
+
+#include "base/scoped_ptr.h"
+#include "base/string_piece.h"
+#include "base/values.h"
+#include "chrome/browser/chromeos/dom_ui/login/login_ui.h"
+#include "chrome/browser/chromeos/dom_ui/login/login_ui_unittest.h"
+#include "chrome/test/testing_profile.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+using ::testing::Return;
+using ::testing::StrEq;
+
+// Listing of untested functions:
+//
+// LoginUI::*
+// LoginUIHTML::*
+//
+// The objects LoginUI and LoginUIHTMLSource do not have any testing,
+// since there are rather trivial/boilerplatey. They are used for hooking the
+// LoginUI code into the greater system and depend extensively on calling
+// external functions. The external functions should be unit tested, but the
+// these objects are better tested in a functional manner.
+//
+//
+// LoginUIHandler::RegisterMessage
+//
+// There is currently no test for LoginUIHandler::RegisterMessage, b/c the
+// function DOMUI::RegisterMesssageCallback is not declared virtual. This means
+// that it cannot be mocked easily and it is non-trivial to resolve, since just
+// making the function virtual causes other problems. Either this class or that
+// class needs to be refactored to deal with this before one can write this
+// test. Realistically there isn't much to fail in this function, so testing
+// should not be needed in this class.
+//
+//
+// LoginUIHandler::HandleLaunchIncognito
+// LoginUIHandler::OnLoginFailure
+// LoginUIHandler::OnLoginSuccess
+// LoginUIHandler::OnOffTheRecordLoginSuccess
+//
+// There no tests for these functions since all of them are pretty straight
+// forward assuming that the called functions perform as expected and it is
+// non-trivial to mock the Browser class.
+namespace chromeos {
+
+// LoginUIHandler::Attach
+TEST(LoginUIHandlerTest, Attach) {
+ // Don't care about the expected in this test
+ LoginUIHandlerHarness handler_harness("", "");
+ MockDOMUI dom_ui;
+
+ EXPECT_EQ(&handler_harness, handler_harness.Attach(&dom_ui));
+ EXPECT_EQ(&dom_ui, handler_harness.GetDOMUI());
+}
+
+// Helper for LoginUIHandler::HandleAuthenticateUser
+void RunHandleAuthenticateUserTest(const std::string& expected_username,
+ const std::string& expected_password,
+ const std::string& supplied_username,
+ const std::string& supplied_password) {
+ ListValue arg_list;
+ StringValue* username_value = new StringValue(supplied_username);
+ StringValue* password_value = new StringValue(supplied_password);
+ TestingProfile mock_profile;
+ LoginUIHandlerHarness handler(expected_username,
+ expected_password);
+
+ EXPECT_EQ(expected_username, handler.GetMockFacade()->GetUsername());
+ EXPECT_EQ(expected_password, handler.GetMockFacade()->GetPassword());
+
+ arg_list.Append(username_value);
+ arg_list.Append(password_value);
+ EXPECT_CALL(*(handler.GetMockProfileOperations()),
+ GetDefaultProfile())
+ .Times(1)
+ .WillRepeatedly(Return(&mock_profile));
+
+ EXPECT_CALL(*(handler.GetMockFacade()),
+ AuthenticateToLogin(&mock_profile,
+ StrEq(supplied_username),
+ StrEq(supplied_password),
+ StrEq(std::string()),
+ StrEq(std::string())))
+ .Times(1);
+
+ handler.HandleAuthenticateUser(&arg_list);
+ // This code does not simulate the callback that occurs in the
+ // AuthenticatorFacade, since that would be a) a functional test and b)
+ // require a working mock of Browser.
+}
+
+// LoginUIHandler::HandleAuthenticateUser on success
+TEST(LoginUIHandlerTest, HandleAuthenticateUserSuccess) {
+ RunHandleAuthenticateUserTest("chronos",
+ "chronos",
+ "chronos",
+ "chronos");
+
+ RunHandleAuthenticateUserTest("bob",
+ "mumistheword",
+ "bob",
+ "mumistheword");
+}
+
+// LoginUIHandler::HandleAuthenticateUser on failure
+TEST(LoginUIHandlerTest, HandleAuthenticateUserFailure) {
+ RunHandleAuthenticateUserTest("chronos",
+ "chronos",
+ std::string(),
+ "chronos");
+
+ RunHandleAuthenticateUserTest("chronos",
+ "chronos",
+ std::string(),
+ std::string());
+
+ RunHandleAuthenticateUserTest("chronos",
+ "chronos",
+ "chronos",
+ std::string());
+
+ RunHandleAuthenticateUserTest("chronos",
+ "chronos",
+ "bob",
+ "mumistheword");
+
+ RunHandleAuthenticateUserTest("bob",
+ "mumistheword",
+ "bob",
+ std::string());
+
+ RunHandleAuthenticateUserTest("bob",
+ "mumistheword",
+ std::string(),
+ std::string());
+
+ RunHandleAuthenticateUserTest("bob",
+ "mumistheword",
+ std::string(),
+ "mumistheword");
+
+ RunHandleAuthenticateUserTest("bob",
+ "mumistheword",
+ "chronos",
+ "chronos");
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/dom_ui/login/login_ui_unittest.h b/chrome/browser/chromeos/dom_ui/login/login_ui_unittest.h
new file mode 100644
index 0000000..cb143cc
--- /dev/null
+++ b/chrome/browser/chromeos/dom_ui/login/login_ui_unittest.h
@@ -0,0 +1,78 @@
+// 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_LOGIN_UI_UNITTEST_H_
+#define CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_LOGIN_UI_UNITTEST_H_
+#pragma once
+
+#include <string>
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/dom_ui/login/mock_authenticator_facade_cros.h"
+#else
+#include "chrome/browser/chromeos/dom_ui/login/mock_authenticator_facade_stub.h"
+#endif
+#include "chrome/browser/chromeos/dom_ui/login/mock_login_ui_helpers.h"
+#include "chrome/test/testing_profile.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace chromeos {
+
+class MockDOMUI : public DOMUI {
+ public:
+ MockDOMUI() : DOMUI(NULL) {}
+ MOCK_METHOD2(RegisterMessageCallback,
+ void(const std::string& message,
+ MessageCallback* callback));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockDOMUI);
+};
+
+class LoginUIHandlerHarness : public LoginUIHandler {
+ public:
+ explicit LoginUIHandlerHarness(const std::string& expected_username,
+ const std::string& expected_password)
+ : LoginUIHandler() {
+#if defined(OS_CHROMEOS)
+ facade_.reset(new MockAuthenticatorFacadeCros(this,
+ expected_username,
+ expected_password));
+#else
+ facade_.reset(new MockAuthenticatorFacadeStub(this,
+ expected_username,
+ expected_password));
+#endif
+ profile_operations_.reset(new MockProfileOperationsInterface());
+ browser_operations_.reset(new MockBrowserOperationsInterface());
+ }
+
+ DOMUI* GetDOMUI() const { return dom_ui_;}
+#if defined(OS_CHROMEOS)
+ MockAuthenticatorFacadeCros* GetMockFacade() const {
+ return static_cast<MockAuthenticatorFacadeCros*>
+ (facade_.get());
+ }
+#else
+ MockAuthenticatorFacadeStub* GetMockFacade() const {
+ return static_cast<MockAuthenticatorFacadeStub*>
+ (facade_.get());
+ }
+#endif
+ MockProfileOperationsInterface* GetMockProfileOperations() const {
+ return static_cast<MockProfileOperationsInterface*>
+ (profile_operations_.get());
+ }
+ MockBrowserOperationsInterface* GetMockBrowserOperations() const {
+ return static_cast<MockBrowserOperationsInterface*>
+ (browser_operations_.get());
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(LoginUIHandlerHarness);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_LOGIN_UI_UNITTEST_H_
diff --git a/chrome/browser/chromeos/dom_ui/login/mock_authenticator_facade_cros.h b/chrome/browser/chromeos/dom_ui/login/mock_authenticator_facade_cros.h
new file mode 100644
index 0000000..a7dc25f
--- /dev/null
+++ b/chrome/browser/chromeos/dom_ui/login/mock_authenticator_facade_cros.h
@@ -0,0 +1,49 @@
+// 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_MOCK_AUTHENTICATOR_FACADE_CROS_H_
+#define CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_MOCK_AUTHENTICATOR_FACADE_CROS_H_
+#pragma once
+
+#include <string>
+
+#include "chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace chromeos {
+
+class MockAuthenticatorFacadeCros : public AuthenticatorFacadeCros {
+ public:
+ explicit MockAuthenticatorFacadeCros(LoginStatusConsumer* consumer,
+ const std::string& expected_username,
+ const std::string& expected_password)
+ : chromeos::AuthenticatorFacadeCros(consumer),
+ expected_username_(expected_username),
+ expected_password_(expected_password) {}
+
+ MOCK_METHOD0(Setup,
+ void());
+ MOCK_METHOD5(AuthenticateToLogin,
+ void(Profile* profile,
+ const std::string& username,
+ const std::string& password,
+ const std::string& login_token,
+ const std::string& login_captcha));
+ MOCK_METHOD2(AuthenticateToUnlock,
+ void(const std::string& username,
+ const std::string& password));
+ const std::string& GetUsername() { return expected_username_; }
+ const std::string& GetPassword() { return expected_password_; }
+
+ protected:
+ std::string expected_username_;
+ std::string expected_password_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockAuthenticatorFacadeCros);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_MOCK_AUTHENTICATOR_FACADE_CROS_H_
diff --git a/chrome/browser/chromeos/dom_ui/login/mock_authenticator_facade_cros_helpers.h b/chrome/browser/chromeos/dom_ui/login/mock_authenticator_facade_cros_helpers.h
new file mode 100644
index 0000000..fc54459
--- /dev/null
+++ b/chrome/browser/chromeos/dom_ui/login/mock_authenticator_facade_cros_helpers.h
@@ -0,0 +1,36 @@
+// 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_MOCK_AUTHENTICATOR_FACADE_CROS_HELPERS_H_
+#define CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_MOCK_AUTHENTICATOR_FACADE_CROS_HELPERS_H_
+#pragma once
+
+#include <string>
+
+#include "chrome/browser/chromeos/dom_ui/login/authenticator_facade_cros_helpers.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace chromeos {
+
+class MockAuthenticatorFacadeCrosHelpers
+ : public AuthenticatorFacadeCrosHelpers {
+ public:
+ MockAuthenticatorFacadeCrosHelpers()
+ : AuthenticatorFacadeCrosHelpers() {}
+
+ MOCK_METHOD1(CreateAuthenticator,
+ Authenticator*(LoginStatusConsumer* consumer));
+ MOCK_METHOD4(PostAuthenticateToLogin,
+ void(Authenticator* authenticator,
+ Profile* profile,
+ const std::string& username,
+ const std::string& password));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockAuthenticatorFacadeCrosHelpers);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_MOCK_AUTHENTICATOR_FACADE_CROS_HELPERS_H_
diff --git a/chrome/browser/chromeos/dom_ui/login/mock_authenticator_facade_stub.h b/chrome/browser/chromeos/dom_ui/login/mock_authenticator_facade_stub.h
new file mode 100644
index 0000000..d1b1389
--- /dev/null
+++ b/chrome/browser/chromeos/dom_ui/login/mock_authenticator_facade_stub.h
@@ -0,0 +1,44 @@
+// 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_MOCK_AUTHENTICATOR_FACADE_STUB_H_
+#define CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_MOCK_AUTHENTICATOR_FACADE_STUB_H_
+#pragma once
+
+#include <string>
+
+#include "chrome/browser/chromeos/dom_ui/login/authenticator_facade_stub.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace chromeos {
+
+class MockAuthenticatorFacadeStub : public AuthenticatorFacadeStub {
+ public:
+ explicit MockAuthenticatorFacadeStub(LoginStatusConsumer* consumer,
+ const std::string& expected_username,
+ const std::string& expected_password)
+ : chromeos::AuthenticatorFacadeStub(consumer,
+ expected_username,
+ expected_password) {}
+ MOCK_METHOD0(Setup,
+ void());
+ MOCK_METHOD5(AuthenticateToLogin,
+ void(Profile* profile,
+ const std::string& username,
+ const std::string& password,
+ const std::string& login_token,
+ const std::string& login_captcha));
+ MOCK_METHOD2(AuthenticateToUnlock,
+ void(const std::string& username,
+ const std::string& password));
+ const std::string& GetUsername() { return expected_username_; }
+ const std::string& GetPassword() { return expected_password_; }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockAuthenticatorFacadeStub);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_MOCK_AUTHENTICATOR_FACADE_STUB_H_
diff --git a/chrome/browser/chromeos/dom_ui/login/mock_login_ui_handler.h b/chrome/browser/chromeos/dom_ui/login/mock_login_ui_handler.h
new file mode 100644
index 0000000..236f5c6
--- /dev/null
+++ b/chrome/browser/chromeos/dom_ui/login/mock_login_ui_handler.h
@@ -0,0 +1,36 @@
+// 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_MOCK_LOGIN_UI_HANDLER_H_
+#define CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_MOCK_LOGIN_UI_HANDLER_H_
+#pragma once
+
+#include <string>
+
+#include "chrome/browser/chromeos/dom_ui/login/login_ui.h"
+#include "chrome/browser/chromeos/dom_ui/login/login_ui_helpers.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace chromeos {
+
+class MockLoginUIHandler : public chromeos::LoginUIHandler {
+ public:
+ MOCK_METHOD1(Attach,
+ DOMMessageHandler*(DOMUI* dom_ui));
+ MOCK_METHOD0(RegisterMessages,
+ void());
+ MOCK_METHOD1(OnLoginFailure,
+ void(const chromeos::LoginFailure& failure));
+ MOCK_METHOD4(OnLoginSuccess,
+ void(const std::string& username,
+ const std::string& password,
+ const GaiaAuthConsumer::ClientLoginResult& credentials,
+ bool pending_requests));
+ MOCK_METHOD0(OnOffTheRecordLoginSuccess,
+ void());
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_MOCK_LOGIN_UI_HANDLER_H_
diff --git a/chrome/browser/chromeos/dom_ui/login/mock_login_ui_helpers.h b/chrome/browser/chromeos/dom_ui/login/mock_login_ui_helpers.h
new file mode 100644
index 0000000..0217abd
--- /dev/null
+++ b/chrome/browser/chromeos/dom_ui/login/mock_login_ui_helpers.h
@@ -0,0 +1,63 @@
+// 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_MOCK_LOGIN_UI_HELPERS_H_
+#define CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_MOCK_LOGIN_UI_HELPERS_H_
+#pragma once
+
+#include <string>
+
+#include "chrome/browser/chromeos/dom_ui/login/login_ui_helpers.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace chromeos {
+
+class MockProfileOperationsInterface
+ : public chromeos::ProfileOperationsInterface {
+ public:
+ MockProfileOperationsInterface() {}
+
+ MOCK_METHOD0(GetDefaultProfile,
+ Profile*());
+ MOCK_METHOD0(GetDefaultProfileByPath,
+ Profile*());
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockProfileOperationsInterface);
+};
+
+class MockBrowserOperationsInterface
+ : public chromeos::BrowserOperationsInterface {
+ public:
+ MockBrowserOperationsInterface() {}
+
+ MOCK_METHOD1(CreateBrowser,
+ Browser*(Profile* profile));
+ MOCK_METHOD1(GetLoginBrowser,
+ Browser*(Profile* profile));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockBrowserOperationsInterface);
+};
+
+class MockHTMLOperationsInterface
+ : public chromeos::HTMLOperationsInterface {
+ public:
+ MockHTMLOperationsInterface() {}
+
+ MOCK_METHOD0(GetLoginHTML,
+ base::StringPiece());
+ MOCK_METHOD2(GetFullHTML,
+ std::string(base::StringPiece login_html,
+ DictionaryValue* localized_strings));
+ MOCK_METHOD1(CreateHTMLBytes,
+ RefCountedBytes*(std::string full_html));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockHTMLOperationsInterface);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_DOM_UI_LOGIN_MOCK_LOGIN_UI_HELPERS_H_
diff --git a/chrome/browser/chromeos/dom_ui/menu_ui.cc b/chrome/browser/chromeos/dom_ui/menu_ui.cc
index 8ffd2a8..1bbc2b4 100644
--- a/chrome/browser/chromeos/dom_ui/menu_ui.cc
+++ b/chrome/browser/chromeos/dom_ui/menu_ui.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/chromeos/dom_ui/menu_ui.h"
+#include <algorithm>
+
#include "app/menus/menu_model.h"
#include "app/resource_bundle.h"
#include "base/callback.h"
@@ -20,7 +22,6 @@
#include "chrome/browser/chromeos/views/domui_menu_widget.h"
#include "chrome/browser/chromeos/views/native_menu_domui.h"
#include "chrome/browser/dom_ui/dom_ui_util.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
#include "chrome/common/url_constants.h"
@@ -314,8 +315,7 @@ MenuUIHTMLSource::MenuUIHTMLSource(const chromeos::MenuSourceDelegate* delegate,
delegate_(delegate),
menu_class_(menu_class),
menu_source_id_(menu_source_id),
- menu_css_id_(menu_css_id)
-{
+ menu_css_id_(menu_css_id) {
}
void MenuUIHTMLSource::StartDataRequest(const std::string& path,
@@ -535,7 +535,7 @@ MenuUI::MenuUI(TabContents* contents) : DOMUI(contents) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(CreateDataSource())));
}
@@ -548,7 +548,7 @@ MenuUI::MenuUI(TabContents* contents, ChromeURLDataManager::DataSource* source)
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(source)));
}
diff --git a/chrome/browser/chromeos/dom_ui/mobile_setup_ui.cc b/chrome/browser/chromeos/dom_ui/mobile_setup_ui.cc
index d254d90..f1e980d 100644
--- a/chrome/browser/chromeos/dom_ui/mobile_setup_ui.cc
+++ b/chrome/browser/chromeos/dom_ui/mobile_setup_ui.cc
@@ -22,14 +22,13 @@
#include "base/values.h"
#include "base/weak_ptr.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/network_library.h"
#include "chrome/browser/chromeos/cros/system_library.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/jstemplate_builder.h"
@@ -1036,7 +1035,7 @@ MobileSetupUI::MobileSetupUI(TabContents* contents) : DOMUI(contents) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(html_source)));
}
diff --git a/chrome/browser/chromeos/dom_ui/network_menu_ui.cc b/chrome/browser/chromeos/dom_ui/network_menu_ui.cc
index a9aa9c4..2973432 100644
--- a/chrome/browser/chromeos/dom_ui/network_menu_ui.cc
+++ b/chrome/browser/chromeos/dom_ui/network_menu_ui.cc
@@ -121,7 +121,7 @@ NetworkMenuUI::NetworkMenuUI(TabContents* contents)
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(theme)));
}
diff --git a/chrome/browser/chromeos/dom_ui/proxy_handler.cc b/chrome/browser/chromeos/dom_ui/proxy_handler.cc
index 7a196f8..759d8bd 100644
--- a/chrome/browser/chromeos/dom_ui/proxy_handler.cc
+++ b/chrome/browser/chromeos/dom_ui/proxy_handler.cc
@@ -13,7 +13,6 @@
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/chromeos/proxy_cros_settings_provider.h"
-#include "chrome/common/notification_service.h"
#include "grit/browser_resources.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
@@ -69,4 +68,4 @@ void ProxyHandler::GetLocalizedValues(
l10n_util::GetStringUTF16(IDS_PROXY_BYPASS));
}
-} // namespace chromeos
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/dom_ui/register_page_ui.cc b/chrome/browser/chromeos/dom_ui/register_page_ui.cc
index 8357fbc..1778490 100644
--- a/chrome/browser/chromeos/dom_ui/register_page_ui.cc
+++ b/chrome/browser/chromeos/dom_ui/register_page_ui.cc
@@ -326,7 +326,7 @@ RegisterPageUI::RegisterPageUI(TabContents* contents) : DOMUI(contents){
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(html_source)));
}
diff --git a/chrome/browser/chromeos/dom_ui/stats_options_handler.cc b/chrome/browser/chromeos/dom_ui/stats_options_handler.cc
index c228946..38ed546 100644
--- a/chrome/browser/chromeos/dom_ui/stats_options_handler.cc
+++ b/chrome/browser/chromeos/dom_ui/stats_options_handler.cc
@@ -9,6 +9,7 @@
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/chromeos/cros_settings_names.h"
+#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/metrics_cros_settings_provider.h"
#include "chrome/browser/metrics/user_metrics.h"
@@ -54,7 +55,7 @@ void StatsOptionsHandler::HandleMetricsReportingCheckbox(
void StatsOptionsHandler::SetupMetricsReportingCheckbox(bool user_changed) {
#if defined(GOOGLE_CHROME_BUILD)
FundamentalValue checked(MetricsCrosSettingsProvider::GetMetricsStatus());
- FundamentalValue disabled(false);
+ FundamentalValue disabled(!UserManager::Get()->current_user_is_owner());
FundamentalValue user_has_changed(user_changed);
dom_ui_->CallJavascriptFunction(
L"options.AdvancedOptions.SetMetricsReportingCheckboxState", checked,
diff --git a/chrome/browser/chromeos/dom_ui/system_info_ui.cc b/chrome/browser/chromeos/dom_ui/system_info_ui.cc
index d9a70da..857c560 100644
--- a/chrome/browser/chromeos/dom_ui/system_info_ui.cc
+++ b/chrome/browser/chromeos/dom_ui/system_info_ui.cc
@@ -182,7 +182,7 @@ SystemInfoUI::SystemInfoUI(TabContents* contents) : DOMUI(contents) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(html_source)));
}
diff --git a/chrome/browser/chromeos/dom_ui/system_options_handler.cc b/chrome/browser/chromeos/dom_ui/system_options_handler.cc
index d47c82c..d543871 100644
--- a/chrome/browser/chromeos/dom_ui/system_options_handler.cc
+++ b/chrome/browser/chromeos/dom_ui/system_options_handler.cc
@@ -14,7 +14,6 @@
#include "base/values.h"
#include "chrome/browser/chromeos/dom_ui/system_settings_provider.h"
#include "chrome/browser/chromeos/language_preferences.h"
-#include "chrome/common/notification_service.h"
#include "grit/browser_resources.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/chromeos/dom_ui/system_settings_provider.cc b/chrome/browser/chromeos/dom_ui/system_settings_provider.cc
index d8b0c10..fcfa7dc 100644
--- a/chrome/browser/chromeos/dom_ui/system_settings_provider.cc
+++ b/chrome/browser/chromeos/dom_ui/system_settings_provider.cc
@@ -214,8 +214,8 @@ void SystemSettingsProvider::DoSet(const std::string& path, Value* in_value) {
bool SystemSettingsProvider::Get(const std::string& path,
Value** out_value) const {
if (path == kSystemTimezone) {
- *out_value = Value::CreateStringValue(
- GetTimezoneID(CrosLibrary::Get()->GetSystemLibrary()->GetTimezone()));
+ *out_value = Value::CreateStringValue(GetKnownTimezoneID(
+ CrosLibrary::Get()->GetSystemLibrary()->GetTimezone()));
return true;
}
return false;
@@ -300,4 +300,17 @@ const icu::TimeZone* SystemSettingsProvider::GetTimezone(
return NULL;
}
+string16 SystemSettingsProvider::GetKnownTimezoneID(
+ const icu::TimeZone& timezone) const {
+ for (std::vector<icu::TimeZone*>::const_iterator iter = timezones_.begin();
+ iter != timezones_.end(); ++iter) {
+ const icu::TimeZone* known_timezone = *iter;
+ if (known_timezone->hasSameRules(timezone))
+ return GetTimezoneID(*known_timezone);
+ }
+
+ // Not able to find a matching timezone in our list.
+ return string16();
+}
+
} // namespace chromeos
diff --git a/chrome/browser/chromeos/dom_ui/system_settings_provider.h b/chrome/browser/chromeos/dom_ui/system_settings_provider.h
index 816ea2c..a355df6 100644
--- a/chrome/browser/chromeos/dom_ui/system_settings_provider.h
+++ b/chrome/browser/chromeos/dom_ui/system_settings_provider.h
@@ -46,6 +46,15 @@ class SystemSettingsProvider : public CrosSettingsProvider,
// Gets timezone object from its id.
const icu::TimeZone* GetTimezone(const string16& timezone_id);
+ // Gets a timezone id from a timezone in |timezones_| that has the same
+ // rule of given |timezone|.
+ // One timezone could have multiple timezones,
+ // e.g.
+ // US/Pacific == America/Los_Angeles
+ // We should always use the known timezone id when passing back as
+ // pref values.
+ string16 GetKnownTimezoneID(const icu::TimeZone& timezone) const;
+
// Timezones.
std::vector<icu::TimeZone*> timezones_;
diff --git a/chrome/browser/chromeos/enterprise_extension_observer.cc b/chrome/browser/chromeos/enterprise_extension_observer.cc
new file mode 100644
index 0000000..9fb6132
--- /dev/null
+++ b/chrome/browser/chromeos/enterprise_extension_observer.cc
@@ -0,0 +1,65 @@
+// 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.
+
+#include "chrome/browser/chromeos/enterprise_extension_observer.h"
+
+#include "base/file_util.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/chromeos/cros/cros_library.h"
+#include "chrome/browser/chromeos/cros/login_library.h"
+#include "chrome/browser/profiles/profile.h"
+
+namespace chromeos {
+
+EnterpriseExtensionObserver::EnterpriseExtensionObserver(Profile* profile)
+ : profile_(profile) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ registrar_.Add(this,
+ NotificationType::EXTENSION_INSTALLED,
+ Source<Profile>(profile_));
+}
+
+void EnterpriseExtensionObserver::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(type == NotificationType::EXTENSION_INSTALLED);
+ if (Source<Profile>(source).ptr() != profile_) {
+ return;
+ }
+ Extension* extension = Details<Extension>(details).ptr();
+ if (extension->location() != Extension::EXTERNAL_POLICY_DOWNLOAD) {
+ return;
+ }
+ BrowserThread::PostTask(
+ BrowserThread::FILE,
+ FROM_HERE,
+ NewRunnableFunction(
+ &EnterpriseExtensionObserver::CheckExtensionAndNotifyEntd,
+ extension->path()));
+}
+
+// static
+void EnterpriseExtensionObserver::CheckExtensionAndNotifyEntd(
+ const FilePath& path) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ if (file_util::PathExists(
+ path.Append(FILE_PATH_LITERAL("isa-cros-policy")))) {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ NewRunnableFunction(&EnterpriseExtensionObserver::NotifyEntd));
+ }
+}
+
+// static
+void EnterpriseExtensionObserver::NotifyEntd() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ CrosLibrary::Get()->GetLoginLibrary()->RestartEntd();
+ return;
+ }
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/enterprise_extension_observer.h b/chrome/browser/chromeos/enterprise_extension_observer.h
new file mode 100644
index 0000000..3e5ed81
--- /dev/null
+++ b/chrome/browser/chromeos/enterprise_extension_observer.h
@@ -0,0 +1,45 @@
+// 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_ENTERPRISE_EXTENSION_OBSERVER_H_
+#define CHROME_BROWSER_CHROMEOS_ENTERPRISE_EXTENSION_OBSERVER_H_
+#pragma once
+
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
+
+class FilePath;
+class Profile;
+
+namespace chromeos {
+
+// This observer listens for installed extensions and restarts the ChromeOS
+// Enterprise daemon if an Enterprise Extension gets installed.
+class EnterpriseExtensionObserver
+ : public NotificationObserver {
+ public:
+ explicit EnterpriseExtensionObserver(Profile* profile);
+ virtual ~EnterpriseExtensionObserver() {}
+
+ void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ private:
+ static void CheckExtensionAndNotifyEntd(const FilePath& path);
+ static void NotifyEntd();
+
+ Profile* profile_;
+ NotificationRegistrar registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(EnterpriseExtensionObserver);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_ENTERPRISE_EXTENSION_OBSERVER_H_
diff --git a/chrome/browser/chromeos/external_protocol_dialog.cc b/chrome/browser/chromeos/external_protocol_dialog.cc
index 38d1cdf..928508f 100644
--- a/chrome/browser/chromeos/external_protocol_dialog.cc
+++ b/chrome/browser/chromeos/external_protocol_dialog.cc
@@ -6,6 +6,7 @@
#include "app/l10n_util.h"
#include "app/message_box_flags.h"
+#include "app/text_elider.h"
#include "base/metrics/histogram.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
@@ -86,7 +87,7 @@ ExternalProtocolDialog::ExternalProtocolDialog(TabContents* tab_contents,
scheme_(url.scheme()) {
const int kMaxUrlWithoutSchemeSize = 256;
std::wstring elided_url_without_scheme;
- ElideString(ASCIIToWide(url.possibly_invalid_spec()),
+ gfx::ElideString(ASCIIToWide(url.possibly_invalid_spec()),
kMaxUrlWithoutSchemeSize, &elided_url_without_scheme);
std::wstring message_text = l10n_util::GetStringF(
diff --git a/chrome/browser/chromeos/frame/browser_frame_chromeos.cc b/chrome/browser/chromeos/frame/browser_frame_chromeos.cc
index e56126c..61d1d97 100644
--- a/chrome/browser/chromeos/frame/browser_frame_chromeos.cc
+++ b/chrome/browser/chromeos/frame/browser_frame_chromeos.cc
@@ -5,9 +5,8 @@
#include "chrome/browser/chromeos/frame/browser_frame_chromeos.h"
#include "base/command_line.h"
-#include "chrome/browser/views/frame/browser_view.h"
-#include "chrome/browser/views/frame/opaque_browser_frame_view.h"
-#include "chrome/browser/views/frame/popup_non_client_frame_view.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"
#include "chrome/common/chrome_switches.h"
// static (Factory method.)
@@ -32,18 +31,12 @@ BrowserFrameChromeos::~BrowserFrameChromeos() {
void BrowserFrameChromeos::Init() {
// NOTE: This logic supersedes the logic in BrowserFrameGtk::Init()
// by always setting browser_frame_view_.
- bool is_popup = browser_view()->IsBrowserTypePopup();
- if (is_popup) {
- // ChromeOS Panels should always use PopupNonClientFrameView.
- set_browser_frame_view(new PopupNonClientFrameView());
- } else {
- // Default FrameView.
- set_browser_frame_view(new OpaqueBrowserFrameView(this, browser_view()));
- }
+ set_browser_frame_view(
+ browser::CreateBrowserNonClientFrameView(this, browser_view()));
BrowserFrameGtk::Init();
- if (!is_popup) {
+ if (!browser_view()->IsBrowserTypePopup()) {
// On chromeos we want windows to always render as active.
GetNonClientView()->DisableInactiveRendering(true);
}
diff --git a/chrome/browser/chromeos/frame/browser_non_client_frame_view_factory_chromeos.cc b/chrome/browser/chromeos/frame/browser_non_client_frame_view_factory_chromeos.cc
new file mode 100644
index 0000000..93b2c8c
--- /dev/null
+++ b/chrome/browser/chromeos/frame/browser_non_client_frame_view_factory_chromeos.cc
@@ -0,0 +1,21 @@
+// 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.
+
+#include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"
+
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/frame/opaque_browser_frame_view.h"
+#include "chrome/browser/ui/views/frame/popup_non_client_frame_view.h"
+
+namespace browser {
+
+BrowserNonClientFrameView* CreateBrowserNonClientFrameView(
+ BrowserFrame* frame, BrowserView* browser_view) {
+ if (browser_view->IsBrowserTypePopup())
+ return new PopupNonClientFrameView();
+ else
+ return new OpaqueBrowserFrameView(frame, browser_view);
+}
+
+} // browser
diff --git a/chrome/browser/chromeos/frame/browser_view.cc b/chrome/browser/chromeos/frame/browser_view.cc
index abb8219..870a4f6 100644
--- a/chrome/browser/chromeos/frame/browser_view.cc
+++ b/chrome/browser/chromeos/frame/browser_view.cc
@@ -27,9 +27,9 @@
#include "chrome/browser/views/theme_background.h"
#include "chrome/browser/views/toolbar_view.h"
#include "chrome/common/chrome_switches.h"
-#include "cros/chromeos_wm_ipc_enums.h"
#include "gfx/canvas.h"
#include "grit/generated_resources.h"
+#include "third_party/cros/chromeos_wm_ipc_enums.h"
#include "views/controls/button/button.h"
#include "views/controls/button/image_button.h"
#include "views/controls/menu/menu_2.h"
diff --git a/chrome/browser/chromeos/frame/bubble_window.cc b/chrome/browser/chromeos/frame/bubble_window.cc
index 8f3f4a4..9fc3684 100644
--- a/chrome/browser/chromeos/frame/bubble_window.cc
+++ b/chrome/browser/chromeos/frame/bubble_window.cc
@@ -8,8 +8,8 @@
#include "chrome/browser/chromeos/frame/bubble_frame_view.h"
#include "chrome/browser/chromeos/wm_ipc.h"
-#include "cros/chromeos_wm_ipc_enums.h"
#include "gfx/skia_utils_gtk.h"
+#include "third_party/cros/chromeos_wm_ipc_enums.h"
#include "views/window/non_client_view.h"
namespace chromeos {
diff --git a/chrome/browser/chromeos/frame/panel_browser_view.cc b/chrome/browser/chromeos/frame/panel_browser_view.cc
index a7f075a..74c08ae 100644
--- a/chrome/browser/chromeos/frame/panel_browser_view.cc
+++ b/chrome/browser/chromeos/frame/panel_browser_view.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/chromeos/frame/panel_browser_view.h"
#include "chrome/browser/chromeos/frame/panel_controller.h"
-#include "cros/chromeos_wm_ipc_enums.h"
+#include "third_party/cros/chromeos_wm_ipc_enums.h"
#include "views/widget/widget.h"
#include "views/window/window.h"
diff --git a/chrome/browser/chromeos/frame/panel_controller.cc b/chrome/browser/chromeos/frame/panel_controller.cc
index ef5d917..31f4961 100644
--- a/chrome/browser/chromeos/frame/panel_controller.cc
+++ b/chrome/browser/chromeos/frame/panel_controller.cc
@@ -15,11 +15,11 @@
#include "chrome/browser/chromeos/wm_ipc.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/notification_service.h"
-#include "cros/chromeos_wm_ipc_enums.h"
#include "gfx/canvas_skia.h"
#include "grit/app_resources.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
+#include "third_party/cros/chromeos_wm_ipc_enums.h"
#include "third_party/skia/include/effects/SkBlurMaskFilter.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
#include "views/controls/button/image_button.h"
diff --git a/chrome/browser/chromeos/frame/panel_controller.h b/chrome/browser/chromeos/frame/panel_controller.h
index 5d4920f..e642cfe 100644
--- a/chrome/browser/chromeos/frame/panel_controller.h
+++ b/chrome/browser/chromeos/frame/panel_controller.h
@@ -9,7 +9,7 @@
#include <gtk/gtk.h>
#include "app/x11_util.h"
-#include "cros/chromeos_wm_ipc_enums.h"
+#include "third_party/cros/chromeos_wm_ipc_enums.h"
#include "views/controls/button/button.h"
class BrowserView;
diff --git a/chrome/browser/chromeos/google_update_chromeos.cc b/chrome/browser/chromeos/google_update_chromeos.cc
index f7aa241..88a63d9 100644
--- a/chrome/browser/chromeos/google_update_chromeos.cc
+++ b/chrome/browser/chromeos/google_update_chromeos.cc
@@ -12,7 +12,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
-#include "cros/chromeos_update.h"
+#include "third_party/cros/chromeos_update.h"
#include "views/window/window.h"
using views::Window;
diff --git a/chrome/browser/chromeos/gview_request_interceptor.cc b/chrome/browser/chromeos/gview_request_interceptor.cc
index 1d2b9cc..5e5c521 100644
--- a/chrome/browser/chromeos/gview_request_interceptor.cc
+++ b/chrome/browser/chromeos/gview_request_interceptor.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// 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.
@@ -33,24 +33,25 @@ static const char* const supported_mime_type_list[] = {
static const char* const kGViewUrlPrefix = "http://docs.google.com/gview?url=";
GViewRequestInterceptor::GViewRequestInterceptor() {
- URLRequest::RegisterRequestInterceptor(this);
+ net::URLRequest::RegisterRequestInterceptor(this);
for (size_t i = 0; i < arraysize(supported_mime_type_list); ++i) {
supported_mime_types_.insert(supported_mime_type_list[i]);
}
}
GViewRequestInterceptor::~GViewRequestInterceptor() {
- URLRequest::UnregisterRequestInterceptor(this);
+ net::URLRequest::UnregisterRequestInterceptor(this);
}
-URLRequestJob* GViewRequestInterceptor::MaybeIntercept(URLRequest* request) {
+net::URLRequestJob* GViewRequestInterceptor::MaybeIntercept(
+ net::URLRequest* request) {
// Don't attempt to intercept here as we want to wait until the mime
// type is fully determined.
return NULL;
}
-URLRequestJob* GViewRequestInterceptor::MaybeInterceptResponse(
- URLRequest* request) {
+net::URLRequestJob* GViewRequestInterceptor::MaybeInterceptResponse(
+ net::URLRequest* request) {
// Do not intercept this request if it is a download.
if (request->load_flags() & net::LOAD_IS_DOWNLOAD) {
return NULL;
@@ -62,9 +63,10 @@ URLRequestJob* GViewRequestInterceptor::MaybeInterceptResponse(
// redirect PDF files to Google Document Viewer.
if (mime_type == kPdfMimeType) {
FilePath pdf_path;
- WebPluginInfo info;
+ webkit::npapi::WebPluginInfo info;
PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_path);
- if (NPAPI::PluginList::Singleton()->GetPluginInfoByPath(pdf_path, &info) &&
+ if (webkit::npapi::PluginList::Singleton()->GetPluginInfoByPath(
+ pdf_path, &info) &&
info.enabled)
return NULL;
}
@@ -74,12 +76,12 @@ URLRequestJob* GViewRequestInterceptor::MaybeInterceptResponse(
if (supported_mime_types_.count(mime_type) > 0) {
std::string url(kGViewUrlPrefix);
url += EscapePath(request->url().spec());
- return new URLRequestRedirectJob(request, GURL(url));
+ return new net::URLRequestRedirectJob(request, GURL(url));
}
return NULL;
}
-URLRequest::Interceptor* GViewRequestInterceptor::GetGViewRequestInterceptor() {
+GViewRequestInterceptor* GViewRequestInterceptor::GetInstance() {
return Singleton<GViewRequestInterceptor>::get();
}
diff --git a/chrome/browser/chromeos/gview_request_interceptor.h b/chrome/browser/chromeos/gview_request_interceptor.h
index 0e698fb..9fe0139 100644
--- a/chrome/browser/chromeos/gview_request_interceptor.h
+++ b/chrome/browser/chromeos/gview_request_interceptor.h
@@ -10,6 +10,8 @@
#include "base/hash_tables.h"
#include "net/url_request/url_request.h"
+template <typename T> struct DefaultSingletonTraits;
+
namespace chromeos {
// This class integrates the Google Document Viewer into ChromeOS,
@@ -18,24 +20,26 @@ namespace chromeos {
// document types (such as PDF) and redirect the request to the Google
// Document Viewer, including the document's original URL as a
// parameter.
-class GViewRequestInterceptor : public URLRequest::Interceptor {
+class GViewRequestInterceptor : public net::URLRequest::Interceptor {
public:
- GViewRequestInterceptor();
- virtual ~GViewRequestInterceptor();
-
// Always returns NULL because we don't want to attempt a redirect
// before seeing the detected mime type of the request.
virtual net::URLRequestJob* MaybeIntercept(net::URLRequest* request);
// Determines if the requested document can be viewed by the Google
- // Document Viewer. If it can, returns a URLRequestJob that
+ // Document Viewer. If it can, returns a net::URLRequestJob that
// redirects the browser to the view URL.
virtual net::URLRequestJob* MaybeInterceptResponse(net::URLRequest* request);
// Singleton accessor.
- static URLRequest::Interceptor* GetGViewRequestInterceptor();
+ static GViewRequestInterceptor* GetInstance();
private:
+ friend struct DefaultSingletonTraits<GViewRequestInterceptor>;
+
+ GViewRequestInterceptor();
+ virtual ~GViewRequestInterceptor();
+
// The list of supported mime types.
base::hash_set<std::string> supported_mime_types_;
};
diff --git a/chrome/browser/chromeos/gview_request_interceptor_unittest.cc b/chrome/browser/chromeos/gview_request_interceptor_unittest.cc
index 7ba3b5d..6f9c68e 100644
--- a/chrome/browser/chromeos/gview_request_interceptor_unittest.cc
+++ b/chrome/browser/chromeos/gview_request_interceptor_unittest.cc
@@ -19,7 +19,7 @@ namespace chromeos {
class GViewURLRequestTestJob : public URLRequestTestJob {
public:
- explicit GViewURLRequestTestJob(URLRequest* request)
+ explicit GViewURLRequestTestJob(net::URLRequest* request)
: URLRequestTestJob(request, true) {
}
@@ -28,7 +28,7 @@ class GViewURLRequestTestJob : public URLRequestTestJob {
// created -- the first is for the viewable document URL, and the
// second is for the rediected URL. In order to test the
// interceptor, the mime type of the first request must be one of
- // the supported viewable mime types. So when the URLRequestJob
+ // the supported viewable mime types. So when the net::URLRequestJob
// is a request for one of the test URLs that point to viewable
// content, return an appropraite mime type. Otherwise, return
// "text/html".
@@ -49,50 +49,51 @@ class GViewURLRequestTestJob : public URLRequestTestJob {
class GViewRequestInterceptorTest : public testing::Test {
public:
virtual void SetUp() {
- URLRequest::RegisterProtocolFactory("http",
+ net::URLRequest::RegisterProtocolFactory("http",
&GViewRequestInterceptorTest::Factory);
- interceptor_ = GViewRequestInterceptor::GetGViewRequestInterceptor();
+ interceptor_ = GViewRequestInterceptor::GetInstance();
ASSERT_TRUE(PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_path_));
}
virtual void TearDown() {
- URLRequest::RegisterProtocolFactory("http", NULL);
+ net::URLRequest::RegisterProtocolFactory("http", NULL);
message_loop_.RunAllPending();
}
- static URLRequestJob* Factory(URLRequest* request,
- const std::string& scheme) {
+ static net::URLRequestJob* Factory(net::URLRequest* request,
+ const std::string& scheme) {
return new GViewURLRequestTestJob(request);
}
void RegisterPDFPlugin() {
- NPAPI::PluginVersionInfo info;
+ webkit::npapi::PluginVersionInfo info;
info.path = pdf_path_;
memset(&info.entry_points, 0, sizeof(info.entry_points));
- NPAPI::PluginList::Singleton()->RegisterInternalPlugin(info);
- NPAPI::PluginList::Singleton()->RefreshPlugins();
+ webkit::npapi::PluginList::Singleton()->RegisterInternalPlugin(info);
+ webkit::npapi::PluginList::Singleton()->RefreshPlugins();
}
void UnregisterPDFPlugin() {
- NPAPI::PluginList::Singleton()->UnregisterInternalPlugin(pdf_path_);
- NPAPI::PluginList::Singleton()->RefreshPlugins();
+ webkit::npapi::PluginList::Singleton()->UnregisterInternalPlugin(pdf_path_);
+ webkit::npapi::PluginList::Singleton()->RefreshPlugins();
}
void SetPDFPluginLoadedState(bool want_loaded, bool* out_is_enabled) {
- WebPluginInfo info;
+ webkit::npapi::WebPluginInfo info;
bool is_loaded =
- NPAPI::PluginList::Singleton()->GetPluginInfoByPath(pdf_path_, &info);
+ webkit::npapi::PluginList::Singleton()->GetPluginInfoByPath(
+ pdf_path_, &info);
if (is_loaded && !want_loaded) {
UnregisterPDFPlugin();
- is_loaded =
- NPAPI::PluginList::Singleton()->GetPluginInfoByPath(pdf_path_, &info);
+ is_loaded = webkit::npapi::PluginList::Singleton()->GetPluginInfoByPath(
+ pdf_path_, &info);
} else if (!is_loaded && want_loaded) {
// This "loads" the plug-in even if it's not present on the
// system - which is OK since we don't actually use it, just
// need it to be "enabled" for the test.
RegisterPDFPlugin();
- is_loaded =
- NPAPI::PluginList::Singleton()->GetPluginInfoByPath(pdf_path_, &info);
+ is_loaded = webkit::npapi::PluginList::Singleton()->GetPluginInfoByPath(
+ pdf_path_, &info);
}
EXPECT_EQ(want_loaded, is_loaded);
*out_is_enabled = info.enabled;
@@ -101,12 +102,12 @@ class GViewRequestInterceptorTest : public testing::Test {
protected:
MessageLoopForIO message_loop_;
TestDelegate test_delegate_;
- URLRequest::Interceptor* interceptor_;
+ net::URLRequest::Interceptor* interceptor_;
FilePath pdf_path_;
};
TEST_F(GViewRequestInterceptorTest, DoNotInterceptHtml) {
- URLRequest request(GURL("http://foo.com/index.html"), &test_delegate_);
+ net::URLRequest request(GURL("http://foo.com/index.html"), &test_delegate_);
request.Start();
MessageLoop::current()->Run();
EXPECT_EQ(0, test_delegate_.received_redirect_count());
@@ -114,7 +115,7 @@ TEST_F(GViewRequestInterceptorTest, DoNotInterceptHtml) {
}
TEST_F(GViewRequestInterceptorTest, DoNotInterceptDownload) {
- URLRequest request(GURL("http://foo.com/file.pdf"), &test_delegate_);
+ net::URLRequest request(GURL("http://foo.com/file.pdf"), &test_delegate_);
request.set_load_flags(net::LOAD_IS_DOWNLOAD);
request.Start();
MessageLoop::current()->Run();
@@ -128,11 +129,11 @@ TEST_F(GViewRequestInterceptorTest, DoNotInterceptPdfWhenEnabled) {
if (!enabled) {
bool pdf_plugin_enabled =
- NPAPI::PluginList::Singleton()->EnablePlugin(pdf_path_);
+ webkit::npapi::PluginList::Singleton()->EnablePlugin(pdf_path_);
EXPECT_TRUE(pdf_plugin_enabled);
}
- URLRequest request(GURL("http://foo.com/file.pdf"), &test_delegate_);
+ net::URLRequest request(GURL("http://foo.com/file.pdf"), &test_delegate_);
request.Start();
MessageLoop::current()->Run();
EXPECT_EQ(0, test_delegate_.received_redirect_count());
@@ -145,11 +146,11 @@ TEST_F(GViewRequestInterceptorTest, InterceptPdfWhenDisabled) {
if (enabled) {
bool pdf_plugin_disabled =
- NPAPI::PluginList::Singleton()->DisablePlugin(pdf_path_);
+ webkit::npapi::PluginList::Singleton()->DisablePlugin(pdf_path_);
EXPECT_TRUE(pdf_plugin_disabled);
}
- URLRequest request(GURL("http://foo.com/file.pdf"), &test_delegate_);
+ net::URLRequest request(GURL("http://foo.com/file.pdf"), &test_delegate_);
request.Start();
MessageLoop::current()->Run();
EXPECT_EQ(1, test_delegate_.received_redirect_count());
@@ -162,7 +163,7 @@ TEST_F(GViewRequestInterceptorTest, InterceptPdfWithNoPlugin) {
bool enabled;
SetPDFPluginLoadedState(false, &enabled);
- URLRequest request(GURL("http://foo.com/file.pdf"), &test_delegate_);
+ net::URLRequest request(GURL("http://foo.com/file.pdf"), &test_delegate_);
request.Start();
MessageLoop::current()->Run();
EXPECT_EQ(1, test_delegate_.received_redirect_count());
@@ -171,7 +172,7 @@ TEST_F(GViewRequestInterceptorTest, InterceptPdfWithNoPlugin) {
}
TEST_F(GViewRequestInterceptorTest, InterceptPowerpoint) {
- URLRequest request(GURL("http://foo.com/file.ppt"), &test_delegate_);
+ net::URLRequest request(GURL("http://foo.com/file.ppt"), &test_delegate_);
request.Start();
MessageLoop::current()->Run();
EXPECT_EQ(1, test_delegate_.received_redirect_count());
diff --git a/chrome/browser/chromeos/input_method/candidate_window.cc b/chrome/browser/chromeos/input_method/candidate_window.cc
index 5e5e723..a88b6bf 100644
--- a/chrome/browser/chromeos/input_method/candidate_window.cc
+++ b/chrome/browser/chromeos/input_method/candidate_window.cc
@@ -14,9 +14,9 @@
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
-#include "cros/chromeos_input_method_ui.h"
#include "gfx/canvas.h"
#include "gfx/font.h"
+#include "third_party/cros/chromeos_input_method_ui.h"
#include "views/controls/label.h"
#include "views/controls/textfield/textfield.h"
#include "views/event.h"
@@ -236,6 +236,15 @@ int ComputeShortcutColumnWidth(
return shortcut_column_width;
}
+// Computes the page index. For instance, if the page size is 9, and the
+// cursor is pointing to 13th candidate, the page index will be 1 (2nd
+// page, as the index is zero-origin). Returns -1 on error.
+int ComputePageIndex(const chromeos::InputMethodLookupTable& lookup_table) {
+ if (lookup_table.page_size > 0)
+ return lookup_table.cursor_absolute_index / lookup_table.page_size;
+ return -1;
+}
+
// Computes candidate column width.
int ComputeCandidateColumnWidth(
const chromeos::InputMethodLookupTable& lookup_table) {
@@ -244,8 +253,9 @@ int ComputeCandidateColumnWidth(
CreateCandidateLabel(lookup_table.orientation));
// Compute the start index of |lookup_table_|.
- const int current_page_index =
- lookup_table.cursor_absolute_index / lookup_table.page_size;
+ const int current_page_index = ComputePageIndex(lookup_table);
+ if (current_page_index < 0)
+ return 0;
const size_t start_from = current_page_index * lookup_table.page_size;
// Compute the max width in candidate labels.
@@ -271,8 +281,9 @@ int ComputeAnnotationColumnWidth(
CreateAnnotationLabel(lookup_table.orientation));
// Compute the start index of |lookup_table_|.
- const int current_page_index =
- lookup_table.cursor_absolute_index / lookup_table.page_size;
+ const int current_page_index = ComputePageIndex(lookup_table);
+ if (current_page_index < 0)
+ return 0;
const size_t start_from = current_page_index * lookup_table.page_size;
// Compute max width in annotation labels.
@@ -345,14 +356,39 @@ class CandidateWindowView : public views::View {
// Updates the auxiliary text.
void UpdateAuxiliaryText(const std::string& utf8_text);
+ // Returns true if we should update candidate views in the window. For
+ // instance, if we are going to show the same candidates as before, we
+ // don't have to update candidate views. This happens when the user just
+ // moves the cursor in the same page in the candidate window.
+ bool ShouldUpdateCandidateViews(
+ const InputMethodLookupTable& old_table,
+ const InputMethodLookupTable& new_table);
+
// Updates candidates of the candidate window from |lookup_table|.
// Candidates are arranged per |orientation|.
void UpdateCandidates(const InputMethodLookupTable& lookup_table);
- // Resizes the parent frame and schedules painting. This needs to be
- // called when the visible contents of the candidate window are
- // modified.
- void ResizeAndSchedulePaint();
+ // Resizes and moves the parent frame. The two actions should be
+ // performed consecutively as resizing may require the candidate window
+ // to move. For instance, we may need to move the candidate window from
+ // below the cursor to above the cursor, if the candidate window becomes
+ // too big to be shown near the bottom of the screen. This function
+ // needs to be called when the visible contents of the candidate window
+ // are modified.
+ void ResizeAndMoveParentFrame();
+
+ // Resizes the parent frame per the current contents size.
+ //
+ // The function is rarely used solely. See comments at
+ // ResizeAndMoveParentFrame().
+ void ResizeParentFrame();
+
+ // Moves the candidate window per the current cursor location, and the
+ // horizontal offset.
+ //
+ // The function is rarely used solely. See comments at
+ // ResizeAndMoveParentFrame().
+ void MoveParentFrame();
// Returns the horizontal offset used for placing the vertical candidate
// window so that the first candidate is aligned with the the text being
@@ -367,6 +403,19 @@ class CandidateWindowView : public views::View {
// Returns 0 if no candidate is present.
int GetHorizontalOffset();
+ void set_cursor_location(const gfx::Rect& cursor_location) {
+ cursor_location_ = cursor_location;
+ }
+
+ const gfx::Rect& cursor_location() const { return cursor_location_; }
+
+ protected:
+ // Override View::VisibilityChanged()
+ virtual void VisibilityChanged(View* starting_from, bool is_visible);
+
+ // Override View::VisibleBoundsInRootChanged()
+ virtual void VisibleBoundsInRootChanged();
+
private:
// Initializes the candidate views if needed.
void MaybeInitializeCandidateViews(
@@ -382,10 +431,6 @@ class CandidateWindowView : public views::View {
// The lookup table (candidates).
InputMethodLookupTable lookup_table_;
- // Zero-origin index of the current page. If the cursor is on the first
- // page, the value will be 0.
- int current_page_index_;
-
// The index in the current page of the candidate currently being selected.
int selected_candidate_index_in_page_;
@@ -427,6 +472,9 @@ class CandidateWindowView : public views::View {
int previous_shortcut_column_width_;
int previous_candidate_column_width_;
int previous_annotation_column_width_;
+
+ // The last cursor location.
+ gfx::Rect cursor_location_;
};
// CandidateRow renderes a row of a candidate.
@@ -508,24 +556,11 @@ class CandidateWindowController::Impl : public CandidateWindowView::Observer {
bool Init();
private:
- // Returns the work area of the monitor nearest the candidate window.
- gfx::Rect GetMonitorWorkAreaNearestWindow();
-
- // Moves the candidate window per the given cursor location, and the
- // horizontal offset.
- void MoveCandidateWindow(const gfx::Rect& cursor_location,
- int horizontal_offset);
-
// CandidateWindowView::Observer implementation.
virtual void OnCandidateCommitted(int index,
int button,
int flags);
- const gfx::Rect& cursor_location() const { return cursor_location_; }
- void set_cursor_location(const gfx::Rect& cursor_location) {
- cursor_location_ = cursor_location;
- }
-
// Creates the candidate window view.
void CreateView();
@@ -570,9 +605,6 @@ class CandidateWindowController::Impl : public CandidateWindowView::Observer {
// This is the outer frame of the candidate window view. The frame will
// own |candidate_window_|.
scoped_ptr<views::Widget> frame_;
-
- // The last cursor location received in OnSetCursorLocation().
- gfx::Rect cursor_location_;
};
CandidateView::CandidateView(
@@ -652,11 +684,14 @@ void CandidateView::Select() {
set_background(
views::Background::CreateSolidBackground(kSelectedRowBackgroundColor));
set_border(views::Border::CreateSolidBorder(1, kSelectedRowFrameColor));
+ // Need to call SchedulePaint() for background and border color changes.
+ SchedulePaint();
}
void CandidateView::Unselect() {
set_background(NULL);
set_border(NULL);
+ SchedulePaint(); // See comments at Select().
}
void CandidateView::SetRowEnabled(bool enabled) {
@@ -696,8 +731,7 @@ void CandidateView::OnMouseReleased(const views::MouseEvent& event,
CandidateWindowView::CandidateWindowView(
views::Widget* parent_frame)
- : current_page_index_(0),
- selected_candidate_index_in_page_(0),
+ : selected_candidate_index_in_page_(0),
parent_frame_(parent_frame),
candidate_area_(NULL),
footer_area_(NULL),
@@ -707,6 +741,8 @@ CandidateWindowView::CandidateWindowView(
previous_shortcut_column_width_(0),
previous_candidate_column_width_(0),
previous_annotation_column_width_(0) {
+
+ SetNotifyWhenVisibleBoundsInRootChanges(true);
}
void CandidateWindowView::Init() {
@@ -753,7 +789,6 @@ void CandidateWindowView::HideAuxiliaryText() {
// Put the place holder to the target display area.
target_area->RemoveAllChildViews(false); // Don't delete child views.
target_area->AddChildView(target_place_holder);
- ResizeAndSchedulePaint();
}
void CandidateWindowView::ShowAuxiliaryText() {
@@ -764,10 +799,12 @@ void CandidateWindowView::ShowAuxiliaryText() {
lookup_table_.orientation == InputMethodLookupTable::kHorizontal ?
header_area_contents_.get() :
footer_area_contents_.get());
- // Put contents to the target display area.
- target_area->RemoveAllChildViews(false); // Don't delete child views.
- target_area->AddChildView(target_contents);
- ResizeAndSchedulePaint();
+
+ if (!target_area->HasChildView(target_contents)) {
+ // If contents not in display area, put it in.
+ target_area->RemoveAllChildViews(false); // Don't delete child views.
+ target_area->AddChildView(target_contents);
+ }
}
void CandidateWindowView::UpdateAuxiliaryText(const std::string& utf8_text) {
@@ -777,64 +814,89 @@ void CandidateWindowView::UpdateAuxiliaryText(const std::string& utf8_text) {
target_label->SetText(UTF8ToWide(utf8_text));
}
+bool CandidateWindowView::ShouldUpdateCandidateViews(
+ const InputMethodLookupTable& old_table,
+ const InputMethodLookupTable& new_table) {
+ // Check if most table contents are identical.
+ if (old_table.page_size == new_table.page_size &&
+ old_table.orientation == new_table.orientation &&
+ old_table.candidates == new_table.candidates &&
+ old_table.labels == new_table.labels &&
+ old_table.annotations == new_table.annotations &&
+ // Check if the page indexes are identical.
+ ComputePageIndex(old_table) == ComputePageIndex(new_table)) {
+ // If all of the conditions are met, we don't have to update candidate
+ // views.
+ return false;
+ }
+ return true;
+}
+
void CandidateWindowView::UpdateCandidates(
- const InputMethodLookupTable& lookup_table) {
- // Initialize candidate views if necessary.
- MaybeInitializeCandidateViews(lookup_table);
-
- // In MaybeInitializeCandidateViews(),
- // |lookup_table| values and |lookup_table_| values are compared,
- // so this substitution is needed after the function.
- lookup_table_ = lookup_table;
-
- // Compute the index of the current page.
- current_page_index_ =
- lookup_table.cursor_absolute_index / lookup_table.page_size;
-
- // Update the candidates in the current page.
- const size_t start_from = current_page_index_ * lookup_table.page_size;
-
- // In some cases, engines send empty shortcut labels. For instance,
- // ibus-mozc sends empty labels when they show suggestions. In this
- // case, we should not show shortcut labels.
- const bool no_shortcut_mode = (start_from < lookup_table_.labels.size() &&
- lookup_table_.labels[start_from] == "");
- for (size_t i = 0; i < candidate_views_.size(); ++i) {
- const size_t index_in_page = i;
- const size_t candidate_index = start_from + index_in_page;
- CandidateView* candidate_view = candidate_views_[index_in_page];
- // Set the shortcut text.
- if (no_shortcut_mode) {
- candidate_view->SetShortcutText(L"");
- } else {
- // At this moment, we don't use labels sent from engines for UX
- // reasons. First, we want to show shortcut labels in empty rows
- // (ex. show 6, 7, 8, ... in empty rows when the number of
- // candidates is 5). Second, we want to add a period after each
- // shortcut label when the candidate window is horizontal.
- candidate_view->SetShortcutText(
- CreateShortcutText(i, lookup_table_.orientation));
+ const InputMethodLookupTable& new_lookup_table) {
+ const bool should_update = ShouldUpdateCandidateViews(lookup_table_,
+ new_lookup_table);
+ // Updating the candidate views is expensive. We'll skip this if possible.
+ if (should_update) {
+ // Initialize candidate views if necessary.
+ MaybeInitializeCandidateViews(new_lookup_table);
+
+ // Compute the index of the current page.
+ const int current_page_index = ComputePageIndex(new_lookup_table);
+ if (current_page_index < 0) {
+ LOG(ERROR) << "Invalid lookup_table: " << new_lookup_table.ToString();
+ return;
}
- // Set the candidate text.
- if (candidate_index < lookup_table_.candidates.size() &&
- candidate_index < lookup_table_.annotations.size()) {
- candidate_view->SetCandidateText(
- UTF8ToWide(lookup_table_.candidates[candidate_index]));
- candidate_view->SetAnnotationText(
- UTF8ToWide(lookup_table_.annotations[candidate_index]));
- candidate_view->SetRowEnabled(true);
- } else {
- // Disable the empty row.
- candidate_view->SetCandidateText(L"");
- candidate_view->SetAnnotationText(L"");
- candidate_view->SetRowEnabled(false);
+
+ // Update the candidates in the current page.
+ const size_t start_from = current_page_index * new_lookup_table.page_size;
+
+ // In some cases, engines send empty shortcut labels. For instance,
+ // ibus-mozc sends empty labels when they show suggestions. In this
+ // case, we should not show shortcut labels.
+ const bool no_shortcut_mode =
+ (start_from < new_lookup_table.labels.size() &&
+ new_lookup_table.labels[start_from] == "");
+ for (size_t i = 0; i < candidate_views_.size(); ++i) {
+ const size_t index_in_page = i;
+ const size_t candidate_index = start_from + index_in_page;
+ CandidateView* candidate_view = candidate_views_[index_in_page];
+ // Set the shortcut text.
+ if (no_shortcut_mode) {
+ candidate_view->SetShortcutText(L"");
+ } else {
+ // At this moment, we don't use labels sent from engines for UX
+ // reasons. First, we want to show shortcut labels in empty rows
+ // (ex. show 6, 7, 8, ... in empty rows when the number of
+ // candidates is 5). Second, we want to add a period after each
+ // shortcut label when the candidate window is horizontal.
+ candidate_view->SetShortcutText(
+ CreateShortcutText(i, new_lookup_table.orientation));
+ }
+ // Set the candidate text.
+ if (candidate_index < new_lookup_table.candidates.size() &&
+ candidate_index < new_lookup_table.annotations.size()) {
+ candidate_view->SetCandidateText(
+ UTF8ToWide(new_lookup_table.candidates[candidate_index]));
+ candidate_view->SetAnnotationText(
+ UTF8ToWide(new_lookup_table.annotations[candidate_index]));
+ candidate_view->SetRowEnabled(true);
+ } else {
+ // Disable the empty row.
+ candidate_view->SetCandidateText(L"");
+ candidate_view->SetAnnotationText(L"");
+ candidate_view->SetRowEnabled(false);
+ }
}
}
-
- // Select the first candidate candidate in the page.
- const int first_candidate_in_page =
- lookup_table.cursor_absolute_index % lookup_table.page_size;
- SelectCandidateAt(first_candidate_in_page);
+ // Update the current lookup table. We'll use lookup_table_ from here.
+ // Note that SelectCandidateAt() uses lookup_table_.
+ lookup_table_ = new_lookup_table;
+
+ // Select the current candidate in the page.
+ const int current_candidate_in_page =
+ lookup_table_.cursor_absolute_index % lookup_table_.page_size;
+ SelectCandidateAt(current_candidate_in_page);
}
void CandidateWindowView::MaybeInitializeCandidateViews(
@@ -858,6 +920,13 @@ void CandidateWindowView::MaybeInitializeCandidateViews(
// If the requested number of views matches the number of current views, and
// previous and current column width are same, just reuse these.
+ //
+ // Note that the early exit logic is not only useful for improving
+ // performance, but also necessary for the horizontal candidate window
+ // to be redrawn properly. If we get rid of the logic, the horizontal
+ // candidate window won't get redrawn properly for some reason when
+ // there is no size change. You can test this by removing "return" here
+ // and type "ni" with Pinyin input method.
if (static_cast<int>(candidate_views_.size()) == page_size &&
lookup_table_.orientation == orientation &&
previous_shortcut_column_width_ == shortcut_column_width &&
@@ -925,7 +994,7 @@ void CandidateWindowView::MaybeInitializeCandidateViews(
// Compute views size in |layout|.
// If we don't call this function, GetHorizontalOffset() often
// returns invalid value (returns 0), then candidate window
- // moves right from the correct position in MoveCandidateWindow().
+ // moves right from the correct position in MoveParentFrame().
// TODO(nhiroki): Figure out why it returns invalid value.
// It seems that the x-position of the candidate labels is not set.
layout->Layout(this);
@@ -996,8 +1065,14 @@ views::View* CandidateWindowView::CreateFooterArea() {
}
void CandidateWindowView::SelectCandidateAt(int index_in_page) {
- int cursor_absolute_index =
- lookup_table_.page_size * current_page_index_ + index_in_page;
+ const int current_page_index = ComputePageIndex(lookup_table_);
+ if (current_page_index < 0) {
+ LOG(ERROR) << "Invalid lookup_table: " << lookup_table_.ToString();
+ return;
+ }
+
+ const int cursor_absolute_index =
+ lookup_table_.page_size * current_page_index + index_in_page;
// Ignore click on out of range views.
if (cursor_absolute_index < 0 ||
cursor_absolute_index >=
@@ -1005,22 +1080,16 @@ void CandidateWindowView::SelectCandidateAt(int index_in_page) {
return;
}
+ // Unselect the currently selected candidate.
+ candidate_views_[selected_candidate_index_in_page_]->Unselect();
// Remember the currently selected candidate index in the current page.
selected_candidate_index_in_page_ = index_in_page;
- // Unselect all the candidate first. Theoretically, we could remember
- // the lastly selected candidate and only unselect it, but unselecting
- // everything is simpler.
- for (size_t i = 0; i < candidate_views_.size(); ++i) {
- candidate_views_[i]->Unselect();
- }
// Select the candidate specified by index_in_page.
candidate_views_[index_in_page]->Select();
// Update the cursor indexes in the model.
lookup_table_.cursor_absolute_index = cursor_absolute_index;
-
- ResizeAndSchedulePaint();
}
void CandidateWindowView::OnCandidateDragged(
@@ -1046,16 +1115,57 @@ void CandidateWindowView::CommitCandidate() {
key_modifilers));
}
-void CandidateWindowView::ResizeAndSchedulePaint() {
+void CandidateWindowView::ResizeAndMoveParentFrame() {
+ ResizeParentFrame();
+ MoveParentFrame();
+}
+
+void CandidateWindowView::ResizeParentFrame() {
// Resize the parent frame, with the current candidate window size.
gfx::Size size = GetPreferredSize();
gfx::Rect bounds;
parent_frame_->GetBounds(&bounds, false);
- bounds.set_width(size.width());
- bounds.set_height(size.height());
- parent_frame_->SetBounds(bounds);
+ // SetBounds() is not cheap. Only call this when the size is changed.
+ if (bounds.size() != size) {
+ bounds.set_size(size);
+ parent_frame_->SetBounds(bounds);
+ }
+}
- SchedulePaint();
+void CandidateWindowView::MoveParentFrame() {
+ const int x = cursor_location_.x();
+ const int y = cursor_location_.y();
+ const int height = cursor_location_.height();
+ const int horizontal_offset = GetHorizontalOffset();
+
+ gfx::Rect frame_bounds;
+ parent_frame_->GetBounds(&frame_bounds, false);
+
+ gfx::Rect screen_bounds = views::Screen::GetMonitorWorkAreaNearestWindow(
+ parent_frame_->GetNativeView());
+
+ // The default position.
+ frame_bounds.set_x(x + horizontal_offset);
+ frame_bounds.set_y(y + height);
+
+ // Handle overflow at the left and the top.
+ frame_bounds.set_x(std::max(frame_bounds.x(), screen_bounds.x()));
+ frame_bounds.set_y(std::max(frame_bounds.y(), screen_bounds.y()));
+
+ // Handle overflow at the right.
+ const int right_overflow = frame_bounds.right() - screen_bounds.right();
+ if (right_overflow > 0) {
+ frame_bounds.set_x(frame_bounds.x() - right_overflow);
+ }
+
+ // Handle overflow at the bottom.
+ const int bottom_overflow = frame_bounds.bottom() - screen_bounds.bottom();
+ if (bottom_overflow > 0) {
+ frame_bounds.set_y(frame_bounds.y() - height - frame_bounds.height());
+ }
+
+ // Move the window per the cursor location.
+ parent_frame_->SetBounds(frame_bounds);
}
int CandidateWindowView::GetHorizontalOffset() {
@@ -1067,6 +1177,20 @@ int CandidateWindowView::GetHorizontalOffset() {
return 0;
}
+void CandidateWindowView::VisibilityChanged(View* starting_from,
+ bool is_visible) {
+ if (is_visible) {
+ // If the visibility of candidate window is changed,
+ // we should move the frame to the right position.
+ MoveParentFrame();
+ }
+}
+
+void CandidateWindowView::VisibleBoundsInRootChanged() {
+ // If the bounds(size) of candidate window is changed,
+ // we should move the frame to the right position.
+ MoveParentFrame();
+}
bool CandidateWindowController::Impl::Init() {
// Initialize the input method UI status connection.
@@ -1129,53 +1253,13 @@ CandidateWindowController::Impl::~Impl() {
chromeos::DisconnectInputMethodUiStatus(ui_status_connection_);
}
-gfx::Rect CandidateWindowController::Impl::GetMonitorWorkAreaNearestWindow() {
- return views::Screen::GetMonitorWorkAreaNearestWindow(
- frame_->GetNativeView());
-}
-
-void CandidateWindowController::Impl::MoveCandidateWindow(
- const gfx::Rect& cursor_location,
- int horizontal_offset) {
- const int x = cursor_location.x();
- const int y = cursor_location.y();
- const int height = cursor_location.height();
-
- gfx::Rect frame_bounds;
- frame_->GetBounds(&frame_bounds, false);
-
- gfx::Rect screen_bounds = GetMonitorWorkAreaNearestWindow();
-
- // The default position.
- frame_bounds.set_x(x + horizontal_offset);
- frame_bounds.set_y(y + height);
-
- // Handle overflow at the left and the top.
- frame_bounds.set_x(std::max(frame_bounds.x(), screen_bounds.x()));
- frame_bounds.set_y(std::max(frame_bounds.y(), screen_bounds.y()));
-
- // Handle overflow at the right.
- const int right_overflow = frame_bounds.right() - screen_bounds.right();
- if (right_overflow > 0) {
- frame_bounds.set_x(frame_bounds.x() - right_overflow);
- }
-
- // Handle overflow at the bottom.
- const int bottom_overflow = frame_bounds.bottom() - screen_bounds.bottom();
- if (bottom_overflow > 0) {
- frame_bounds.set_y(frame_bounds.y() - height - frame_bounds.height());
- }
-
- // Move the window per the cursor location.
- frame_->SetBounds(frame_bounds);
-}
-
void CandidateWindowController::Impl::OnHideAuxiliaryText(
void* input_method_library) {
CandidateWindowController::Impl* controller =
static_cast<CandidateWindowController::Impl*>(input_method_library);
controller->candidate_window_->HideAuxiliaryText();
+ controller->candidate_window_->ResizeParentFrame();
}
void CandidateWindowController::Impl::OnHideLookupTable(
@@ -1198,7 +1282,8 @@ void CandidateWindowController::Impl::OnSetCursorLocation(
// A workaround for http://crosbug.com/6460. We should ignore very short Y
// move to prevent the window from shaking up and down.
const int kKeepPositionThreshold = 2; // px
- const gfx::Rect& last_location = controller->cursor_location();
+ const gfx::Rect& last_location =
+ controller->candidate_window_->cursor_location();
const int delta_y = abs(last_location.y() - y);
if ((last_location.x() == x) && (delta_y <= kKeepPositionThreshold)) {
DLOG(INFO) << "Ignored set_cursor_location signal to prevent window shake";
@@ -1206,14 +1291,10 @@ void CandidateWindowController::Impl::OnSetCursorLocation(
}
// Remember the cursor location.
- controller->set_cursor_location(gfx::Rect(x, y, width, height));
+ controller->candidate_window_->set_cursor_location(
+ gfx::Rect(x, y, width, height));
// Move the window per the cursor location.
- controller->MoveCandidateWindow(
- controller->cursor_location(),
- controller->candidate_window_->GetHorizontalOffset());
- // The call is needed to ensure that the candidate window is redrawed
- // properly after the cursor location is changed.
- controller->candidate_window_->ResizeAndSchedulePaint();
+ controller->candidate_window_->MoveParentFrame();
}
void CandidateWindowController::Impl::OnUpdateAuxiliaryText(
@@ -1229,6 +1310,7 @@ void CandidateWindowController::Impl::OnUpdateAuxiliaryText(
}
controller->candidate_window_->UpdateAuxiliaryText(utf8_text);
controller->candidate_window_->ShowAuxiliaryText();
+ controller->candidate_window_->ResizeParentFrame();
}
void CandidateWindowController::Impl::OnUpdateLookupTable(
@@ -1244,13 +1326,8 @@ void CandidateWindowController::Impl::OnUpdateLookupTable(
}
controller->candidate_window_->UpdateCandidates(lookup_table);
+ controller->candidate_window_->ResizeParentFrame();
controller->frame_->Show();
- // We should call MoveCandidateWindow() after
- // controller->frame_->Show(), as GetHorizontalOffset() returns a valid
- // value only after the Show() method is called.
- controller->MoveCandidateWindow(
- controller->cursor_location(),
- controller->candidate_window_->GetHorizontalOffset());
}
void CandidateWindowController::Impl::OnCandidateCommitted(int index,
diff --git a/chrome/browser/chromeos/input_method/candidate_window_main.cc b/chrome/browser/chromeos/input_method/candidate_window_main.cc
index a8fbb15..a8bc042 100644
--- a/chrome/browser/chromeos/input_method/candidate_window_main.cc
+++ b/chrome/browser/chromeos/input_method/candidate_window_main.cc
@@ -19,8 +19,8 @@
#include "chrome/browser/chromeos/cros/cros_library_loader.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
-#include "cros/chromeos_cros_api.h"
#include "grit/app_locale_settings.h"
+#include "third_party/cros/chromeos_cros_api.h"
#include "views/focus/accelerator_handler.h"
int main(int argc, char** argv) {
diff --git a/chrome/browser/chromeos/input_method/input_method_util.cc b/chrome/browser/chromeos/input_method/input_method_util.cc
index 9f8811d..67fcb5b 100644
--- a/chrome/browser/chromeos/input_method/input_method_util.cc
+++ b/chrome/browser/chromeos/input_method/input_method_util.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/chromeos/input_method/input_method_util.h"
#include <algorithm>
+#include <functional>
#include <map>
#include <utility>
@@ -20,7 +21,6 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/keyboard_library.h"
#include "chrome/browser/chromeos/language_preferences.h"
@@ -64,6 +64,8 @@ const struct InputMethodIdToKeyboardOverlayId {
{ "xkb:us:intl:eng", "en_US" },
{ "xkb:us:altgr-intl:eng", "en_US" },
{ "xkb:us:dvorak:eng", "en_US_dvorak" },
+ // TODO(mazda): Add keyboard overlay definition for US Colemak.
+ { "xkb:us:colemak:eng", "en_US" },
{ "hangul", "ko" },
{ "pinyin", "zh_CN" },
{ "m17n:ar:kbd", "ar" },
@@ -109,6 +111,11 @@ struct IdMaps {
scoped_ptr<std::map<std::string, std::string> > id_to_display_name;
scoped_ptr<std::map<std::string, std::string> > id_to_keyboard_overlay_id;
+ // Returns the singleton instance.
+ static IdMaps* GetInstance() {
+ return Singleton<IdMaps>::get();
+ }
+
void ReloadMaps() {
chromeos::InputMethodLibrary* library =
chromeos::CrosLibrary::Get()->GetInputMethodLibrary();
@@ -273,6 +280,7 @@ const struct EnglishToResouceId {
{ "Serbia", IDS_STATUSBAR_LAYOUT_SERBIA },
{ "Czechia", IDS_STATUSBAR_LAYOUT_CZECHIA },
{ "USA - Dvorak", IDS_STATUSBAR_LAYOUT_USA_DVORAK },
+ { "USA - Colemak", IDS_STATUSBAR_LAYOUT_USA_COLEMAK },
{ "Romania", IDS_STATUSBAR_LAYOUT_ROMANIA },
{ "USA", IDS_STATUSBAR_LAYOUT_USA },
{ "USA - International (AltGr dead keys)",
@@ -536,8 +544,8 @@ std::string GetLanguageCodeFromInputMethodId(
// defined in app/l10_util.cc.
const char kDefaultLanguageCode[] = "en-US";
std::map<std::string, std::string>::const_iterator iter
- = Singleton<IdMaps>::get()->id_to_language_code->find(input_method_id);
- return (iter == Singleton<IdMaps>::get()->id_to_language_code->end()) ?
+ = IdMaps::GetInstance()->id_to_language_code->find(input_method_id);
+ return (iter == IdMaps::GetInstance()->id_to_language_code->end()) ?
// Returning |kDefaultLanguageCode| here is not for Chrome OS but for
// Ubuntu where the ibus-xkb-layouts engine could be missing.
kDefaultLanguageCode : iter->second;
@@ -555,7 +563,7 @@ std::string GetKeyboardLayoutName(const std::string& input_method_id) {
std::string GetKeyboardOverlayId(const std::string& input_method_id) {
const std::map<std::string, std::string>& id_map =
- *(Singleton<IdMaps>::get()->id_to_keyboard_overlay_id);
+ *(IdMaps::GetInstance()->id_to_keyboard_overlay_id);
std::map<std::string, std::string>::const_iterator iter =
id_map.find(input_method_id);
return (iter == id_map.end() ? "" : iter->second);
@@ -565,8 +573,8 @@ std::string GetInputMethodDisplayNameFromId(
const std::string& input_method_id) {
static const char kDefaultDisplayName[] = "USA";
std::map<std::string, std::string>::const_iterator iter
- = Singleton<IdMaps>::get()->id_to_display_name->find(input_method_id);
- return (iter == Singleton<IdMaps>::get()->id_to_display_name->end()) ?
+ = IdMaps::GetInstance()->id_to_display_name->find(input_method_id);
+ return (iter == IdMaps::GetInstance()->id_to_display_name->end()) ?
kDefaultDisplayName : iter->second;
}
@@ -603,7 +611,7 @@ void SortLanguageCodesByNames(std::vector<std::string>* language_codes) {
void SortInputMethodIdsByNames(std::vector<std::string>* input_method_ids) {
SortInputMethodIdsByNamesInternal(
- *(Singleton<IdMaps>::get()->id_to_language_code), input_method_ids);
+ *(IdMaps::GetInstance()->id_to_language_code), input_method_ids);
}
void SortInputMethodIdsByNamesInternal(
@@ -629,7 +637,7 @@ bool GetInputMethodIdsFromLanguageCode(
InputMethodType type,
std::vector<std::string>* out_input_method_ids) {
return GetInputMethodIdsFromLanguageCodeInternal(
- *Singleton<IdMaps>::get()->language_code_to_ids,
+ *IdMaps::GetInstance()->language_code_to_ids,
normalized_language_code, type, out_input_method_ids);
}
@@ -687,7 +695,7 @@ void EnableInputMethods(const std::string& language_code, InputMethodType type,
}
void OnLocaleChanged() {
- Singleton<IdMaps>::get()->ReloadMaps();
+ IdMaps::GetInstance()->ReloadMaps();
}
} // namespace input_method
diff --git a/chrome/browser/chromeos/input_method/input_method_util_unittest.cc b/chrome/browser/chromeos/input_method/input_method_util_unittest.cc
index d89690c..7d4c246 100644
--- a/chrome/browser/chromeos/input_method/input_method_util_unittest.cc
+++ b/chrome/browser/chromeos/input_method/input_method_util_unittest.cc
@@ -134,6 +134,7 @@ TEST(InputMethodUtilTest, GetKeyboardLayoutName) {
EXPECT_EQ("ua", GetKeyboardLayoutName("xkb:ua::ukr"));
EXPECT_EQ("us", GetKeyboardLayoutName("xkb:us::eng"));
EXPECT_EQ("us", GetKeyboardLayoutName("xkb:us:dvorak:eng"));
+ EXPECT_EQ("us", GetKeyboardLayoutName("xkb:us:colemak:eng"));
}
TEST(InputMethodUtilTest, GetKeyboardOverlayId) {
@@ -171,6 +172,8 @@ TEST(InputMethodUtilTest, GetKeyboardOverlayId) {
EXPECT_EQ("en_US", GetKeyboardOverlayId("xkb:us:intl:eng"));
EXPECT_EQ("en_US", GetKeyboardOverlayId("xkb:us:altgr-intl:eng"));
EXPECT_EQ("en_US_dvorak", GetKeyboardOverlayId("xkb:us:dvorak:eng"));
+ // TODO(mazda): Add keyboard overlay definition for US Colemak.
+ EXPECT_EQ("en_US", GetKeyboardOverlayId("xkb:us:colemak:eng"));
EXPECT_EQ("ko", GetKeyboardOverlayId("hangul"));
EXPECT_EQ("zh_CN", GetKeyboardOverlayId("pinyin"));
EXPECT_EQ("ar", GetKeyboardOverlayId("m17n:ar:kbd"));
diff --git a/chrome/browser/chromeos/login/account_creation_view.cc b/chrome/browser/chromeos/login/account_creation_view.cc
index a748155..05c66b5 100644
--- a/chrome/browser/chromeos/login/account_creation_view.cc
+++ b/chrome/browser/chromeos/login/account_creation_view.cc
@@ -68,6 +68,8 @@ class AccountCreationTabContents : public WizardWebPageViewTabContents,
virtual void ShowAutoFillDialog() {}
+ virtual void Reset() {}
+
private:
AccountCreationViewDelegate* delegate_;
diff --git a/chrome/browser/chromeos/login/account_screen.cc b/chrome/browser/chromeos/login/account_screen.cc
index d7298fc..7d08f2a 100644
--- a/chrome/browser/chromeos/login/account_screen.cc
+++ b/chrome/browser/chromeos/login/account_screen.cc
@@ -10,7 +10,7 @@
#include "chrome/browser/chromeos/input_method/input_method_util.h"
#include "chrome/browser/chromeos/login/account_creation_view.h"
#include "chrome/browser/chromeos/login/screen_observer.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/tab_contents/tab_contents.h"
diff --git a/chrome/browser/chromeos/login/account_screen_browsertest.cc b/chrome/browser/chromeos/login/account_screen_browsertest.cc
index 0954013..309d8bc 100644
--- a/chrome/browser/chromeos/login/account_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/account_screen_browsertest.cc
@@ -62,8 +62,8 @@ static void QuitUIMessageLoop() {
static bool inspector_called = false; // had to use global flag as
// InspectorHook() doesn't have context.
-static URLRequestJob* InspectorHook(URLRequest* request,
- const std::string& scheme) {
+static net::URLRequestJob* InspectorHook(net::URLRequest* request,
+ const std::string& scheme) {
VLOG(1) << "Intercepted: " << request->url() << ", scheme: " << scheme;
// Expect that the parameters are the same as new_account.html gave us.
@@ -74,7 +74,7 @@ static URLRequestJob* InspectorHook(URLRequest* request,
NewRunnableFunction(QuitUIMessageLoop));
// Do not navigate to the given URL. Navigate to about:blank instead.
- return new URLRequestAboutJob(request);
+ return new net::URLRequestAboutJob(request);
}
// Sometimes times out: http://crbug.com/60050.
diff --git a/chrome/browser/chromeos/login/apply_services_customization.cc b/chrome/browser/chromeos/login/apply_services_customization.cc
index 314b10b..b778a5e 100644
--- a/chrome/browser/chromeos/login/apply_services_customization.cc
+++ b/chrome/browser/chromeos/login/apply_services_customization.cc
@@ -14,7 +14,7 @@
#include "chrome/browser/chromeos/cros/network_library.h"
#include "chrome/browser/chromeos/customization_document.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "googleurl/src/gurl.h"
namespace {
diff --git a/chrome/browser/chromeos/login/auth_attempt_state.cc b/chrome/browser/chromeos/login/auth_attempt_state.cc
index 459f7e9..830ee4a 100644
--- a/chrome/browser/chromeos/login/auth_attempt_state.cc
+++ b/chrome/browser/chromeos/login/auth_attempt_state.cc
@@ -9,7 +9,7 @@
#include "chrome/browser/browser_thread.h"
#include "chrome/common/net/gaia/gaia_auth_consumer.h"
#include "chrome/common/net/gaia/gaia_auth_fetcher.h"
-#include "cros/chromeos_cryptohome.h"
+#include "third_party/cros/chromeos_cryptohome.h"
namespace chromeos {
diff --git a/chrome/browser/chromeos/login/authenticator.cc b/chrome/browser/chromeos/login/authenticator.cc
index 1b2a42c..07f4560 100644
--- a/chrome/browser/chromeos/login/authenticator.cc
+++ b/chrome/browser/chromeos/login/authenticator.cc
@@ -14,9 +14,6 @@
namespace chromeos {
class LoginStatusConsumer;
-// static
-const char Authenticator::kSpecialCaseDomain[] = "gmail.com";
-
Authenticator::Authenticator(LoginStatusConsumer* consumer)
: consumer_(consumer) {
}
@@ -29,11 +26,7 @@ std::string Authenticator::Canonicalize(const std::string& email_address) {
char at = '@';
base::SplitString(email_address, at, &parts);
DCHECK_EQ(parts.size(), 2U) << "email_address should have only one @";
- if (parts[1] == kSpecialCaseDomain) // only strip '.' for gmail accounts.
- RemoveChars(parts[0], ".", &parts[0]);
- // Technically the '+' handling here could be removed, as the google
- // account servers do not tolerate them, so we don't need to either.
- // TODO(cmasone): remove this, unless this code becomes obsolete altogether.
+ RemoveChars(parts[0], ".", &parts[0]);
if (parts[0].find('+') != std::string::npos)
parts[0].erase(parts[0].find('+'));
std::string new_email = StringToLowerASCII(JoinString(parts, at));
diff --git a/chrome/browser/chromeos/login/authenticator.h b/chrome/browser/chromeos/login/authenticator.h
index 4096b1f..039411c 100644
--- a/chrome/browser/chromeos/login/authenticator.h
+++ b/chrome/browser/chromeos/login/authenticator.h
@@ -23,9 +23,6 @@ namespace chromeos {
// consumer_->OnPasswordChangeDetected() on the UI thread.
class Authenticator : public base::RefCountedThreadSafe<Authenticator> {
public:
- // A domain which requires special-case parsing in canonicalization.
- static const char kSpecialCaseDomain[];
-
explicit Authenticator(LoginStatusConsumer* consumer);
virtual ~Authenticator();
diff --git a/chrome/browser/chromeos/login/authenticator_unittest.cc b/chrome/browser/chromeos/login/authenticator_unittest.cc
index d6bd149..48ab378 100644
--- a/chrome/browser/chromeos/login/authenticator_unittest.cc
+++ b/chrome/browser/chromeos/login/authenticator_unittest.cc
@@ -23,29 +23,19 @@ TEST(AuthenticatorTest, EmailAddressIgnoreDomainCaps) {
Authenticator::Canonicalize("UsEr@what.COM"));
}
-TEST(AuthenticatorTest, EmailAddressRejectOneUsernameDot) {
- EXPECT_NE(Authenticator::Canonicalize("u.ser@what.com"),
- Authenticator::Canonicalize("UsEr@what.com"));
-}
-
-TEST(AuthenticatorTest, EmailAddressMatchWithOneUsernameDot) {
- EXPECT_EQ(Authenticator::Canonicalize("u.ser@what.com"),
- Authenticator::Canonicalize("U.sEr@what.com"));
-}
-
TEST(AuthenticatorTest, EmailAddressIgnoreOneUsernameDot) {
- EXPECT_EQ(Authenticator::Canonicalize("us.er@gmail.com"),
- Authenticator::Canonicalize("UsEr@gmail.com"));
+ EXPECT_EQ(Authenticator::Canonicalize("us.er@what.com"),
+ Authenticator::Canonicalize("UsEr@what.com"));
}
TEST(AuthenticatorTest, EmailAddressIgnoreManyUsernameDots) {
- EXPECT_EQ(Authenticator::Canonicalize("u.ser@gmail.com"),
- Authenticator::Canonicalize("Us.E.r@gmail.com"));
+ EXPECT_EQ(Authenticator::Canonicalize("u.ser@what.com"),
+ Authenticator::Canonicalize("Us.E.r@what.com"));
}
TEST(AuthenticatorTest, EmailAddressIgnoreConsecutiveUsernameDots) {
- EXPECT_EQ(Authenticator::Canonicalize("use.r@gmail.com"),
- Authenticator::Canonicalize("Us....E.r@gmail.com"));
+ EXPECT_EQ(Authenticator::Canonicalize("use.r@what.com"),
+ Authenticator::Canonicalize("Us....E.r@what.com"));
}
TEST(AuthenticatorTest, EmailAddressDifferentOnesRejected) {
diff --git a/chrome/browser/chromeos/login/background_view.cc b/chrome/browser/chromeos/login/background_view.cc
index c4137de..9ce54f6 100644
--- a/chrome/browser/chromeos/login/background_view.cc
+++ b/chrome/browser/chromeos/login/background_view.cc
@@ -6,6 +6,7 @@
#include <string>
#include <vector>
+
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "app/x11_util.h"
@@ -24,15 +25,14 @@
#include "chrome/browser/chromeos/status/network_menu_button.h"
#include "chrome/browser/chromeos/status/status_area_view.h"
#include "chrome/browser/chromeos/wm_ipc.h"
-#include "chrome/browser/profile_manager.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/views/dom_view.h"
-#include "cros/chromeos_wm_ipc_enums.h"
-#include "googleurl/src/gurl.h"
#include "gfx/gtk_util.h"
+#include "googleurl/src/gurl.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
+#include "third_party/cros/chromeos_wm_ipc_enums.h"
#include "views/controls/button/text_button.h"
#include "views/controls/label.h"
#include "views/screen.h"
@@ -40,8 +40,8 @@
// X Windows headers have "#define Status int". That interferes with
// NetworkLibrary header which defines enum "Status".
-#include <X11/cursorfont.h>
-#include <X11/Xcursor/Xcursor.h>
+#include <X11/cursorfont.h> // NOLINT
+#include <X11/Xcursor/Xcursor.h> // NOLINT
using views::WidgetGtk;
diff --git a/chrome/browser/chromeos/login/captcha_view.cc b/chrome/browser/chromeos/login/captcha_view.cc
index 7c55cae..de66b3e 100644
--- a/chrome/browser/chromeos/login/captcha_view.cc
+++ b/chrome/browser/chromeos/login/captcha_view.cc
@@ -7,10 +7,16 @@
#include "app/l10n_util.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
+#include "chrome/browser/chromeos/login/helper.h"
#include "chrome/browser/chromeos/login/image_downloader.h"
+#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
+#include "chrome/browser/chromeos/login/textfield_with_margin.h"
+#include "chrome/browser/chromeos/views/copy_background.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
+#include "views/background.h"
+#include "views/controls/button/text_button.h"
#include "views/controls/image_view.h"
#include "views/controls/label.h"
#include "views/grid_layout.h"
@@ -24,11 +30,57 @@ using views::WidgetGtk;
namespace chromeos {
-CaptchaView::CaptchaView(const GURL& captcha_url)
+namespace {
+
+// A Textfield for captcha input, which also sets focus to itself
+// when a mouse is clicked on it. This is necessary in screen locker mode
+// as mouse events are grabbed in the screen locker.
+class CaptchaField : public TextfieldWithMargin {
+ public:
+ CaptchaField()
+ : TextfieldWithMargin() {
+ }
+
+ // views::View overrides.
+ virtual bool OnMousePressed(const views::MouseEvent& e) {
+ RequestFocus();
+ return false;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CaptchaField);
+};
+
+class WideTextButton : public views::TextButton {
+ public:
+ WideTextButton(views::ButtonListener* listener, const std::wstring& text)
+ : TextButton(listener, text) {
+ SetFont(font().DeriveFont(kFontSizeCorrectionDelta));
+ }
+
+ virtual ~WideTextButton() {}
+
+ private:
+ virtual gfx::Size GetPreferredSize() {
+ gfx::Size preferred_size = TextButton::GetPreferredSize();
+ // Set minimal width.
+ if (preferred_size.width() < login::kButtonMinWidth)
+ preferred_size.set_width(login::kButtonMinWidth);
+ return preferred_size;
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(WideTextButton);
+};
+
+} // namespace
+
+CaptchaView::CaptchaView(const GURL& captcha_url, bool is_standalone)
: delegate_(NULL),
captcha_url_(captcha_url),
captcha_image_(NULL),
- captcha_textfield_(NULL) {
+ captcha_textfield_(NULL),
+ is_standalone_(is_standalone),
+ ok_button_(NULL) {
}
bool CaptchaView::Accept() {
@@ -41,38 +93,67 @@ std::wstring CaptchaView::GetWindowTitle() const {
return l10n_util::GetString(IDS_LOGIN_CAPTCHA_DIALOG_TITLE);
}
+void CaptchaView::SetCaptchaURL(const GURL& captcha_url) {
+ captcha_url_ = captcha_url;
+ captcha_textfield_->SetText(string16());
+ // ImageDownloader will delete itself once URL is fetched.
+ // TODO(nkostylev): Make sure that it works after view is deleted.
+ new ImageDownloader(this, GURL(captcha_url_), std::string());
+}
+
gfx::Size CaptchaView::GetPreferredSize() {
// TODO(nkostylev): Once UI is finalized, create locale settings.
- return gfx::Size(views::Window::GetLocalizedContentsSize(
+ gfx::Size size = gfx::Size(views::Window::GetLocalizedContentsSize(
IDS_CAPTCHA_INPUT_DIALOG_WIDTH_CHARS,
IDS_CAPTCHA_INPUT_DIALOG_HEIGHT_LINES));
+ if (is_standalone_)
+ size.set_height(size.height() + ok_button_->GetPreferredSize().height());
+
+ return size;
}
void CaptchaView::ViewHierarchyChanged(bool is_add,
views::View* parent,
views::View* child) {
- // Can't init before we're inserted into a Container, because we require
- // a HWND to parent native child controls to.
+ // Can't focus before we're inserted into a Container.
if (is_add && child == this)
- Init();
+ captcha_textfield_->RequestFocus();
}
bool CaptchaView::HandleKeystroke(views::Textfield* sender,
const views::Textfield::Keystroke& keystroke) {
if (sender == captcha_textfield_ &&
keystroke.GetKeyboardCode() == app::VKEY_RETURN) {
- GetDialogClientView()->AcceptWindow();
+ if (is_standalone_) {
+ Accept();
+ } else {
+ GetDialogClientView()->AcceptWindow();
+ }
}
return false;
}
void CaptchaView::OnImageDecoded(const SkBitmap& decoded_image) {
captcha_image_->SetImage(decoded_image);
- SchedulePaint();
+ captcha_textfield_->RequestFocus();
Layout();
}
+void CaptchaView::ButtonPressed(views::Button* sender,
+ const views::Event& event) {
+ DCHECK(sender == ok_button_);
+ Accept();
+}
+
void CaptchaView::Init() {
+ if (is_standalone_) {
+ // Use rounded rect background.
+ set_border(CreateWizardBorder(&BorderDefinition::kUserBorder));
+ views::Painter* painter = CreateWizardPainter(
+ &BorderDefinition::kUserBorder);
+ set_background(views::Background::CreateBackgroundPainter(true, painter));
+ }
+
views::GridLayout* layout = CreatePanelGridLayout(this);
SetLayoutManager(layout);
@@ -93,9 +174,10 @@ void CaptchaView::Init() {
layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
layout->StartRow(0, column_view_set_id);
- captcha_textfield_ = new views::Textfield(
- views::Textfield::STYLE_DEFAULT);
+ captcha_textfield_ = new CaptchaField();
captcha_textfield_->SetController(this);
+ if (is_standalone_)
+ captcha_textfield_->set_background(new CopyBackground(this));
layout->AddView(captcha_textfield_);
layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
@@ -106,9 +188,22 @@ void CaptchaView::Init() {
layout->AddView(label);
layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
- captcha_textfield_->RequestFocus();
+ if (is_standalone_) {
+ layout->StartRow(0, column_view_set_id);
+ ok_button_ = new WideTextButton(this, l10n_util::GetString(IDS_OK));
+ ok_button_->set_alignment(views::TextButton::ALIGN_CENTER);
+ ok_button_->SetFocusable(true);
+ ok_button_->SetNormalHasBorder(true);
+ ok_button_->set_animate_on_state_change(false);
+ ok_button_->SetEnabledColor(SK_ColorBLACK);
+ ok_button_->SetHighlightColor(SK_ColorBLACK);
+ ok_button_->SetHoverColor(SK_ColorBLACK);
+ layout->AddView(ok_button_, 1, 1,
+ views::GridLayout::CENTER, views::GridLayout::CENTER);
+ }
- // ImageDownloader will disable itself once URL is fetched.
+ // ImageDownloader will delete itself once URL is fetched.
+ // TODO(nkostylev): Make sure that it works after view is deleted.
new ImageDownloader(this, GURL(captcha_url_), std::string());
}
diff --git a/chrome/browser/chromeos/login/captcha_view.h b/chrome/browser/chromeos/login/captcha_view.h
index 491c438..37de9f9 100644
--- a/chrome/browser/chromeos/login/captcha_view.h
+++ b/chrome/browser/chromeos/login/captcha_view.h
@@ -10,11 +10,13 @@
#include "chrome/browser/chromeos/login/image_decoder.h"
#include "googleurl/src/gurl.h"
+#include "views/controls/button/button.h"
#include "views/controls/textfield/textfield.h"
#include "views/window/dialog_delegate.h"
namespace views {
class ImageView;
+class TextButton;
class View;
class Window;
} // namespace views
@@ -25,7 +27,8 @@ namespace chromeos {
class CaptchaView : public views::View,
public views::DialogDelegate,
public views::Textfield::Controller,
- public ImageDecoder::Delegate {
+ public ImageDecoder::Delegate,
+ public views::ButtonListener {
public:
class Delegate {
public:
@@ -37,7 +40,8 @@ class CaptchaView : public views::View,
};
// |captcha_url| represents CAPTCHA image URL.
- explicit CaptchaView(const GURL& captcha_url);
+ // |is_standalone| is true when CaptchaView is not presented as dialog.
+ CaptchaView(const GURL& captcha_url, bool is_standalone);
virtual ~CaptchaView() {}
// views::DialogDelegate overrides:
@@ -59,10 +63,20 @@ class CaptchaView : public views::View,
// Overriden from ImageDownloader::Delegate:
virtual void OnImageDecoded(const SkBitmap& decoded_image);
+ // Overridden from views::ButtonListener.
+ virtual void ButtonPressed(views::Button* sender, const views::Event& event);
+
+ // Initializes UI.
+ void Init();
+
void set_delegate(Delegate* delegate) {
delegate_ = delegate;
}
+ // Instructs to download and display another captcha image.
+ // Is used when same CaptchaView is reused.
+ void SetCaptchaURL(const GURL& captcha_url);
+
protected:
// views::View overrides:
virtual gfx::Size GetPreferredSize();
@@ -71,14 +85,18 @@ class CaptchaView : public views::View,
views::View* child);
private:
- // Initializes UI.
- void Init();
-
Delegate* delegate_;
GURL captcha_url_;
views::ImageView* captcha_image_;
views::Textfield* captcha_textfield_;
+ // True when view is not hosted inside dialog,
+ // thus should draw OK button/background.
+ bool is_standalone_;
+
+ // Used in standalone mode.
+ views::TextButton* ok_button_;
+
DISALLOW_COPY_AND_ASSIGN(CaptchaView);
};
diff --git a/chrome/browser/chromeos/login/cookie_fetcher.cc b/chrome/browser/chromeos/login/cookie_fetcher.cc
index d73d8da..10dde76 100644
--- a/chrome/browser/chromeos/login/cookie_fetcher.cc
+++ b/chrome/browser/chromeos/login/cookie_fetcher.cc
@@ -6,14 +6,13 @@
#include "base/command_line.h"
#include "base/path_service.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/boot_times_loader.h"
#include "chrome/browser/chromeos/login/client_login_response_handler.h"
#include "chrome/browser/chromeos/login/issue_response_handler.h"
#include "chrome/browser/chromeos/login/login_utils.h"
#include "chrome/browser/net/chrome_url_request_context.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/net/url_fetcher.h"
#include "net/url_request/url_request_status.h"
diff --git a/chrome/browser/chromeos/login/cookie_fetcher.h b/chrome/browser/chromeos/login/cookie_fetcher.h
index 45a20c7..660a164 100644
--- a/chrome/browser/chromeos/login/cookie_fetcher.h
+++ b/chrome/browser/chromeos/login/cookie_fetcher.h
@@ -11,9 +11,10 @@
#include "chrome/browser/chromeos/login/auth_response_handler.h"
#include "chrome/browser/chromeos/login/client_login_response_handler.h"
#include "chrome/browser/chromeos/login/issue_response_handler.h"
-#include "chrome/browser/profile.h"
#include "chrome/common/net/url_fetcher.h"
+class Profile;
+
namespace chromeos {
// Given a SID/LSID pair, this class will attempt to turn them into a
diff --git a/chrome/browser/chromeos/login/cookie_fetcher_unittest.cc b/chrome/browser/chromeos/login/cookie_fetcher_unittest.cc
index 832c877..e188b8f 100644
--- a/chrome/browser/chromeos/login/cookie_fetcher_unittest.cc
+++ b/chrome/browser/chromeos/login/cookie_fetcher_unittest.cc
@@ -3,8 +3,9 @@
// found in the LICENSE file.
#include <errno.h>
+
#include <string>
-#include "chrome/browser/browser_process.h"
+
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/chromeos/login/client_login_response_handler.h"
#include "chrome/browser/chromeos/login/cookie_fetcher.h"
diff --git a/chrome/browser/chromeos/login/cryptohome_op.cc b/chrome/browser/chromeos/login/cryptohome_op.cc
index b73da68..688b2ba 100644
--- a/chrome/browser/chromeos/login/cryptohome_op.cc
+++ b/chrome/browser/chromeos/login/cryptohome_op.cc
@@ -6,6 +6,7 @@
#include <string>
+#include "chrome/browser/browser_thread.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/cryptohome_library.h"
#include "chrome/browser/chromeos/login/auth_attempt_state.h"
diff --git a/chrome/browser/chromeos/login/cryptohome_op.h b/chrome/browser/chromeos/login/cryptohome_op.h
index d1e6e20..959c390 100644
--- a/chrome/browser/chromeos/login/cryptohome_op.h
+++ b/chrome/browser/chromeos/login/cryptohome_op.h
@@ -9,7 +9,6 @@
#include <string>
#include "base/ref_counted.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/chromeos/cros/cryptohome_library.h"
namespace chromeos {
diff --git a/chrome/browser/chromeos/login/eula_view.cc b/chrome/browser/chromeos/login/eula_view.cc
index b089543..b7c688a 100644
--- a/chrome/browser/chromeos/login/eula_view.cc
+++ b/chrome/browser/chromeos/login/eula_view.cc
@@ -25,7 +25,7 @@
#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/chromeos/metrics_cros_settings_provider.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/views/dom_view.h"
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc
index 5cd1745..83aa156 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -30,7 +30,7 @@
#include "chrome/browser/chromeos/user_cros_settings_provider.h"
#include "chrome/browser/chromeos/view_ids.h"
#include "chrome/browser/chromeos/wm_ipc.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/views/window.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/net/gaia/google_service_auth_error.h"
@@ -126,7 +126,8 @@ ExistingUserController::ExistingUserController(
selected_view_index_(kNotSelected),
num_login_attempts_(0),
bubble_(NULL),
- user_settings_(new UserCrosSettingsProvider()) {
+ user_settings_(new UserCrosSettingsProvider),
+ method_factory_(this) {
if (delete_scheduled_instance_)
delete_scheduled_instance_->Delete();
@@ -191,7 +192,7 @@ void ExistingUserController::Init() {
EnableTooltipsIfNeeded(controllers_);
- WmMessageListener::instance()->AddObserver(this);
+ WmMessageListener::GetInstance()->AddObserver(this);
LoginUtils::Get()->PrewarmAuthentication();
if (CrosLibrary::Get()->EnsureLoaded())
@@ -213,14 +214,11 @@ void ExistingUserController::LoginNewUser(const std::string& username,
DCHECK(new_user->is_new_user());
if (!new_user->is_new_user())
return;
- NewUserView* new_user_view = new_user->new_user_view();
- new_user_view->SetUsername(username);
if (password.empty())
return;
- new_user_view->SetPassword(password);
- new_user_view->Login();
+ new_user->OnLogin(username, password);
}
void ExistingUserController::SelectNewUser() {
@@ -239,7 +237,7 @@ ExistingUserController::~ExistingUserController() {
if (background_window_)
background_window_->Close();
- WmMessageListener::instance()->RemoveObserver(this);
+ WmMessageListener::GetInstance()->RemoveObserver(this);
STLDeleteElements(&controllers_);
}
@@ -302,8 +300,19 @@ void ExistingUserController::WhiteListCheckFailed(const std::string& email) {
void ExistingUserController::LoginOffTheRecord() {
// Check allow_guest in case this call is fired from key accelerator.
- if (!UserCrosSettingsProvider::cached_allow_guest())
+ // Must not proceed without signature verification.
+ bool trusted_setting_available = user_settings_->RequestTrustedAllowGuest(
+ method_factory_.NewRunnableMethod(
+ &ExistingUserController::LoginOffTheRecord));
+ if (!trusted_setting_available) {
+ // Value of AllowGuest setting is still not verified.
+ // Another attempt will be invoked again after verification completion.
return;
+ }
+ if (!UserCrosSettingsProvider::cached_allow_guest()) {
+ // Disallowed.
+ return;
+ }
// Disable clicking on other windows.
SendSetLoginState(false);
@@ -349,6 +358,7 @@ void ExistingUserController::ActivateWizard(const std::string& screen_name) {
// is doing an animation with our windows.
DCHECK(!delete_scheduled_instance_);
delete_scheduled_instance_ = this;
+
delete_timer_.Start(base::TimeDelta::FromSeconds(1), this,
&ExistingUserController::Delete);
}
@@ -356,11 +366,10 @@ void ExistingUserController::ActivateWizard(const std::string& screen_name) {
void ExistingUserController::RemoveUser(UserController* source) {
ClearErrors();
- // TODO(xiyuan): Wait for the cached settings update before using them.
- if (UserCrosSettingsProvider::cached_owner() == source->user().email()) {
- // Owner is not allowed to be removed from the device.
- return;
- }
+ // Owner is not allowed to be removed from the device.
+ // It must be enforced at upper levels.
+ DCHECK(user_settings_->RequestTrustedOwner(NULL));
+ DCHECK(source->user().email() != UserCrosSettingsProvider::cached_owner());
UserManager::Get()->RemoveUser(source->user().email());
@@ -404,7 +413,8 @@ void ExistingUserController::OnLoginFailure(const LoginFailure& failure) {
failure.error().state() == GoogleServiceAuthError::CAPTCHA_REQUIRED) {
if (!failure.error().captcha().image_url.is_empty()) {
CaptchaView* view =
- new CaptchaView(failure.error().captcha().image_url);
+ new CaptchaView(failure.error().captcha().image_url, false);
+ view->Init();
view->set_delegate(this);
views::Window* window = browser::CreateViewsWindow(
GetNativeWindow(), gfx::Rect(), view);
@@ -458,7 +468,8 @@ void ExistingUserController::ShowError(int error_id,
// For now just ignore it because error_text contains all required information
// for end users, developers can see details string in Chrome logs.
- gfx::Rect bounds = controllers_[selected_view_index_]->GetScreenBounds();
+ gfx::Rect bounds =
+ controllers_[selected_view_index_]->GetMainInputScreenBounds();
BubbleBorder::ArrowLocation arrow;
if (controllers_[selected_view_index_]->is_new_user()) {
arrow = BubbleBorder::LEFT_TOP;
@@ -498,14 +509,8 @@ void ExistingUserController::OnLoginSuccess(
LoginPerformer* performer = login_performer_.release();
performer = NULL;
bool known_user = UserManager::Get()->IsKnownUser(username);
- if (credentials.two_factor && !known_user && !start_url_.is_valid()) {
- // If we have a two factor error and and this is a new user and we are not
- // already directing the user to a start url (e.g. a help page),
- // direct them to the personal settings page.
- // TODO(stevenjb): direct the user to a lightweight sync login page.
- start_url_ = GURL(kSettingsSyncLoginUrl);
- }
AppendStartUrlToCmdline();
+ controllers_[selected_view_index_]->StopThrobber();
if (selected_view_index_ + 1 == controllers_.size() && !known_user) {
#if defined(OFFICIAL_BUILD)
CommandLine::ForCurrentProcess()->AppendSwitchPath(
@@ -513,9 +518,18 @@ void ExistingUserController::OnLoginSuccess(
FilePath(kGetStartedPath));
CommandLine::ForCurrentProcess()->AppendArg(kGetStartedURL);
#endif // OFFICIAL_BUILD
+ if (credentials.two_factor) {
+ // If we have a two factor error and and this is a new user,
+ // load the personal settings page.
+ // TODO(stevenjb): direct the user to a lightweight sync login page.
+ CommandLine::ForCurrentProcess()->AppendArg(kSettingsSyncLoginUrl);
+ }
// For new user login don't launch browser until we pass image screen.
LoginUtils::Get()->EnableBrowserLaunch(false);
- LoginUtils::Get()->CompleteLogin(username, password, credentials);
+ LoginUtils::Get()->CompleteLogin(username,
+ password,
+ credentials,
+ pending_requests);
ActivateWizard(WizardController::IsDeviceRegistered() ?
WizardController::kUserImageScreenName :
WizardController::kRegistrationScreenName);
@@ -524,7 +538,10 @@ void ExistingUserController::OnLoginSuccess(
WmIpc::Message message(WM_IPC_MESSAGE_WM_HIDE_LOGIN);
WmIpc::instance()->SendMessage(message);
- LoginUtils::Get()->CompleteLogin(username, password, credentials);
+ LoginUtils::Get()->CompleteLogin(username,
+ password,
+ credentials,
+ pending_requests);
// Delay deletion as we're on the stack.
MessageLoop::current()->DeleteSoon(FROM_HERE, this);
@@ -548,9 +565,18 @@ void ExistingUserController::OnPasswordChangeDetected(
return;
}
+ // Must not proceed without signature verification.
+ bool trusted_setting_available = user_settings_->RequestTrustedOwner(
+ method_factory_.NewRunnableMethod(
+ &ExistingUserController::OnPasswordChangeDetected,
+ credentials));
+ if (!trusted_setting_available) {
+ // Value of owner email is still not verified.
+ // Another attempt will be invoked after verification completion.
+ return;
+ }
// TODO(altimofeev): remove this constrain when full sync for the owner will
// be correctly handled.
- // TODO(xiyuan): Wait for the cached settings update before using them.
bool full_sync_disabled = (UserCrosSettingsProvider::cached_owner() ==
controllers_[selected_view_index_]->user().email());
diff --git a/chrome/browser/chromeos/login/existing_user_controller.h b/chrome/browser/chromeos/login/existing_user_controller.h
index e150a31..61e941a 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.h
+++ b/chrome/browser/chromeos/login/existing_user_controller.h
@@ -166,9 +166,12 @@ class ExistingUserController : public WmMessageListener::Observer,
// Help application used for help dialogs.
scoped_ptr<HelpAppLauncher> help_app_;
- // A user settings provider instance to trigger settings cache update.
+ // Triggers prefetching of user settings.
scoped_ptr<UserCrosSettingsProvider> user_settings_;
+ // Factory of callbacks.
+ ScopedRunnableMethodFactory<ExistingUserController> method_factory_;
+
DISALLOW_COPY_AND_ASSIGN(ExistingUserController);
};
diff --git a/chrome/browser/chromeos/login/existing_user_view.cc b/chrome/browser/chromeos/login/existing_user_view.cc
index abe1eb2..ed9ac4e 100644
--- a/chrome/browser/chromeos/login/existing_user_view.cc
+++ b/chrome/browser/chromeos/login/existing_user_view.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/chromeos/login/existing_user_view.h"
#include "app/l10n_util.h"
-#include "chrome/browser/chromeos/login/helper.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/login/user_controller.h"
#include "chrome/browser/chromeos/login/textfield_with_margin.h"
#include "chrome/browser/chromeos/login/wizard_accessibility_helper.h"
@@ -34,8 +34,13 @@ class UserEntryTextfield : public TextfieldWithMargin {
// Overridden from views::View:
virtual bool OnKeyPressed(const views::KeyEvent& e) {
if (e.GetKeyCode() == app::VKEY_TAB) {
- int index = controller_->user_index() + (e.IsShiftDown() ? -1 : 1);
- controller_->SelectUser(index);
+ controller_->SelectUserRelative(e.IsShiftDown() ? -1 : 1);
+ return true;
+ } else if (e.GetKeyCode() == app::VKEY_LEFT) {
+ controller_->SelectUserRelative(-1);
+ return true;
+ } else if (e.GetKeyCode() == app::VKEY_RIGHT) {
+ controller_->SelectUserRelative(1);
return true;
} else {
return false;
@@ -56,15 +61,15 @@ class UserEntryTextfield : public TextfieldWithMargin {
};
-ExistingUserView::ExistingUserView(UserController* uc)
- : accel_login_off_the_record_(
- views::Accelerator(app::VKEY_B, false, false, true)),
+ExistingUserView::ExistingUserView(UserController* user_controller)
+ : user_controller_(user_controller),
password_field_(NULL),
- user_controller_(uc),
- accel_enable_accessibility_(
+ accel_login_off_the_record_(
+ views::Accelerator(app::VKEY_B, false, false, true)),
+ accel_toggle_accessibility_(
WizardAccessibilityHelper::GetAccelerator()) {
AddAccelerator(accel_login_off_the_record_);
- AddAccelerator(accel_enable_accessibility_);
+ AddAccelerator(accel_toggle_accessibility_);
}
void ExistingUserView::RecreateFields() {
@@ -75,9 +80,8 @@ void ExistingUserView::RecreateFields() {
password_field_->set_background(
views::Background::CreateVerticalGradientBackground(
kBackgroundColorTop, kBackgroundColorBottom));
- CorrectTextfieldFontSize(password_field_);
password_field_->SetFocusable(true);
- password_field_->SetController(user_controller_);
+ password_field_->SetController(this);
AddChildView(password_field_);
}
password_field_->set_text_to_display_when_empty(
@@ -91,13 +95,43 @@ bool ExistingUserView::AcceleratorPressed(
if (accelerator == accel_login_off_the_record_) {
user_controller_->OnLoginOffTheRecord();
return true;
- } else if (accelerator == accel_enable_accessibility_) {
- WizardAccessibilityHelper::GetInstance()->EnableAccessibility(this);
+ } else if (accelerator == accel_toggle_accessibility_) {
+ WizardAccessibilityHelper::GetInstance()->ToggleAccessibility(this);
return true;
}
return false;
}
+bool ExistingUserView::HandleKeystroke(
+ views::Textfield* sender,
+ const views::Textfield::Keystroke& keystroke) {
+ if (keystroke.GetKeyboardCode() == app::VKEY_RETURN) {
+ if (!password_field_->text().empty())
+ user_controller_->OnLogin("", UTF16ToUTF8(password_field_->text()));
+ } else {
+ user_controller_->ClearErrors();
+ return false;
+ }
+ return true;
+}
+
+void ExistingUserView::ContentsChanged(views::Textfield* sender,
+ const string16& new_contents) {
+}
+
+void ExistingUserView::EnableInputControls(bool enabled) {
+ password_field_->SetEnabled(enabled);
+}
+
+void ExistingUserView::ClearAndFocusControls() {
+ ClearAndFocusPassword();
+}
+
+void ExistingUserView::ClearAndFocusPassword() {
+ password_field_->SetText(string16());
+ FocusPasswordField();
+}
+
void ExistingUserView::ViewHierarchyChanged(bool is_add,
views::View* parent,
views::View* child) {
@@ -106,9 +140,11 @@ void ExistingUserView::ViewHierarchyChanged(bool is_add,
}
void ExistingUserView::FocusPasswordField() {
- if (GetFocusManager()) {
- password_field()->RequestFocus();
- }
+ password_field_->RequestFocus();
+}
+
+gfx::Rect ExistingUserView::GetMainInputScreenBounds() const {
+ return password_field_->GetScreenBounds();
}
void ExistingUserView::OnLocaleChanged() {
diff --git a/chrome/browser/chromeos/login/existing_user_view.h b/chrome/browser/chromeos/login/existing_user_view.h
index 004ff21..9d3dff8 100644
--- a/chrome/browser/chromeos/login/existing_user_view.h
+++ b/chrome/browser/chromeos/login/existing_user_view.h
@@ -6,6 +6,8 @@
#define CHROME_BROWSER_CHROMEOS_LOGIN_EXISTING_USER_VIEW_H_
#pragma once
+#include "chrome/browser/chromeos/login/helper.h"
+#include "chrome/browser/chromeos/login/user_input.h"
#include "views/accelerator.h"
#include "views/controls/button/native_button.h"
#include "views/controls/textfield/textfield.h"
@@ -15,19 +17,31 @@ namespace chromeos {
class UserController;
-class ExistingUserView : public views::View {
+class ExistingUserView : public ThrobberHostView,
+ public UserInput,
+ public views::Textfield::Controller {
public:
- explicit ExistingUserView(UserController* uc);
+ explicit ExistingUserView(UserController* user_controller);
void RecreateFields();
- views::Textfield* password_field() { return password_field_; }
-
void FocusPasswordField();
// Overridden from views::View:
virtual bool AcceleratorPressed(const views::Accelerator& accelerator);
+ // Overriden from Textfield::Controller:
+ virtual void ContentsChanged(views::Textfield* sender,
+ const string16& new_contents);
+ virtual bool HandleKeystroke(views::Textfield* sender,
+ const views::Textfield::Keystroke& keystroke);
+
+ // Overriden from UserInput:
+ virtual void EnableInputControls(bool enabled);
+ virtual void ClearAndFocusControls();
+ virtual void ClearAndFocusPassword();
+ virtual gfx::Rect GetMainInputScreenBounds() const;
+
protected:
// Overridden from views::View:
virtual void OnLocaleChanged();
@@ -35,15 +49,14 @@ class ExistingUserView : public views::View {
views::View* parent,
views::View* child);
- views::Accelerator accel_login_off_the_record_;
+ private:
+ UserController* user_controller_;
// For editing the password.
views::Textfield* password_field_;
- UserController* user_controller_;
-
- private:
- views::Accelerator accel_enable_accessibility_;
+ views::Accelerator accel_login_off_the_record_;
+ views::Accelerator accel_toggle_accessibility_;
DISALLOW_COPY_AND_ASSIGN(ExistingUserView);
};
diff --git a/chrome/browser/chromeos/login/google_authenticator.cc b/chrome/browser/chromeos/login/google_authenticator.cc
index 230db32..4fa405d 100644
--- a/chrome/browser/chromeos/login/google_authenticator.cc
+++ b/chrome/browser/chromeos/login/google_authenticator.cc
@@ -16,7 +16,6 @@
#include "base/string_util.h"
#include "base/third_party/nss/blapi.h"
#include "base/third_party/nss/sha256.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/chromeos/boot_times_loader.h"
#include "chrome/browser/chromeos/cros/cryptohome_library.h"
@@ -25,8 +24,8 @@
#include "chrome/browser/chromeos/login/login_status_consumer.h"
#include "chrome/browser/chromeos/login/ownership_service.h"
#include "chrome/browser/chromeos/login/user_manager.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/net/gaia/gaia_auth_fetcher.h"
#include "chrome/common/net/gaia/gaia_constants.h"
@@ -205,8 +204,7 @@ void GoogleAuthenticator::OnClientLoginSuccess(
}
void GoogleAuthenticator::OnClientLoginFailure(
- const GoogleServiceAuthError& error) {
-
+ const GoogleServiceAuthError& error) {
if (error.state() == GoogleServiceAuthError::REQUEST_CANCELED) {
if (try_again_) {
try_again_ = false;
diff --git a/chrome/browser/chromeos/login/guest_user_view.cc b/chrome/browser/chromeos/login/guest_user_view.cc
index a06e017..c83d897 100644
--- a/chrome/browser/chromeos/login/guest_user_view.cc
+++ b/chrome/browser/chromeos/login/guest_user_view.cc
@@ -5,7 +5,6 @@
#include "chrome/browser/chromeos/login/guest_user_view.h"
#include "app/l10n_util.h"
-#include "chrome/browser/chromeos/login/helper.h"
#include "chrome/browser/chromeos/login/user_controller.h"
#include "chrome/browser/chromeos/login/wizard_accessibility_helper.h"
#include "grit/generated_resources.h"
@@ -15,16 +14,16 @@ namespace chromeos {
// Button with custom processing for Tab/Shift+Tab to select entries.
class UserEntryButton : public login::WideButton {
public:
- UserEntryButton(UserController* controller,
+ UserEntryButton(views::ButtonListener* button_listener,
+ UserController* user_controller,
const std::wstring& label)
- : WideButton(controller, label),
- controller_(controller) {}
+ : WideButton(button_listener, label),
+ user_controller_(user_controller) {}
// Overridden from views::View:
virtual bool OnKeyPressed(const views::KeyEvent& e) {
if (e.GetKeyCode() == app::VKEY_TAB) {
- int index = controller_->user_index() + (e.IsShiftDown() ? -1 : 1);
- controller_->SelectUser(index);
+ user_controller_->SelectUserRelative(e.IsShiftDown() ? -1 : 1);
return true;
}
return WideButton::OnKeyPressed(e);
@@ -37,7 +36,7 @@ class UserEntryButton : public login::WideButton {
}
private:
- UserController* controller_;
+ UserController* user_controller_;
DISALLOW_COPY_AND_ASSIGN(UserEntryButton);
};
@@ -46,7 +45,7 @@ class UserEntryButton : public login::WideButton {
GuestUserView::GuestUserView(UserController* uc)
: submit_button_(NULL),
user_controller_(uc),
- accel_enable_accessibility_(
+ accel_toggle_accessibility_(
WizardAccessibilityHelper::GetAccelerator()),
accel_login_off_the_record_(
views::Accelerator(app::VKEY_B, false, false, true)),
@@ -54,7 +53,7 @@ GuestUserView::GuestUserView(UserController* uc)
views::Accelerator(app::VKEY_LEFT, false, false, false)),
accel_next_pod_by_arrow_(
views::Accelerator(app::VKEY_RIGHT, false, false, false)) {
- AddAccelerator(accel_enable_accessibility_);
+ AddAccelerator(accel_toggle_accessibility_);
AddAccelerator(accel_login_off_the_record_);
AddAccelerator(accel_previous_pod_by_arrow_);
AddAccelerator(accel_next_pod_by_arrow_);
@@ -63,6 +62,7 @@ GuestUserView::GuestUserView(UserController* uc)
void GuestUserView::RecreateFields() {
delete submit_button_;
submit_button_ = new UserEntryButton(
+ this,
user_controller_,
l10n_util::GetString(IDS_ENTER_GUEST_SESSION_BUTTON));
AddChildView(submit_button_);
@@ -71,25 +71,34 @@ void GuestUserView::RecreateFields() {
}
void GuestUserView::FocusSignInButton() {
- if (GetFocusManager())
- submit_button_->RequestFocus();
+ submit_button_->RequestFocus();
}
bool GuestUserView::AcceleratorPressed(
const views::Accelerator& accelerator) {
if (accelerator == accel_login_off_the_record_)
user_controller_->OnLoginOffTheRecord();
- else if (accelerator == accel_enable_accessibility_)
- WizardAccessibilityHelper::GetInstance()->EnableAccessibility(this);
+ else if (accelerator == accel_toggle_accessibility_)
+ WizardAccessibilityHelper::GetInstance()->ToggleAccessibility(this);
else if (accelerator == accel_previous_pod_by_arrow_)
- user_controller_->SelectUser(user_controller_->user_index() - 1);
+ user_controller_->SelectUserRelative(-1);
else if (accelerator == accel_next_pod_by_arrow_)
- user_controller_->SelectUser(user_controller_->user_index() + 1);
+ user_controller_->SelectUserRelative(1);
else
return false;
return true;
}
+void GuestUserView::ButtonPressed(
+ views::Button* sender, const views::Event& event) {
+ DCHECK(sender == submit_button_);
+ user_controller_->OnLoginOffTheRecord();
+}
+
+void GuestUserView::EnableInputControls(bool enabled) {
+ submit_button_->SetEnabled(enabled);
+}
+
void GuestUserView::ViewHierarchyChanged(bool is_add,
views::View* parent,
views::View* child) {
@@ -111,4 +120,15 @@ void GuestUserView::Layout() {
submit_button_size.height());
}
+void GuestUserView::ClearAndFocusControls() {
+}
+
+void GuestUserView::ClearAndFocusPassword() {
+}
+
+gfx::Rect GuestUserView::GetMainInputScreenBounds() const {
+ NOTREACHED();
+ return gfx::Rect();
+}
+
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/guest_user_view.h b/chrome/browser/chromeos/login/guest_user_view.h
index d9590f5..a7b31b4 100644
--- a/chrome/browser/chromeos/login/guest_user_view.h
+++ b/chrome/browser/chromeos/login/guest_user_view.h
@@ -6,6 +6,8 @@
#define CHROME_BROWSER_CHROMEOS_LOGIN_GUEST_USER_VIEW_H_
#pragma once
+#include "chrome/browser/chromeos/login/helper.h"
+#include "chrome/browser/chromeos/login/user_input.h"
#include "views/accelerator.h"
#include "views/controls/button/native_button.h"
#include "views/controls/textfield/textfield.h"
@@ -18,7 +20,9 @@ class UserController;
// This view is for controls window of Guest mode pod that allows user to
// get temporary profile and use it for browsing. Contains only one Sign-in
// button and handles different common keyboard shortcuts.
-class GuestUserView : public views::View {
+class GuestUserView : public ThrobberHostView,
+ public UserInput,
+ public views::ButtonListener {
public:
explicit GuestUserView(UserController* uc);
@@ -29,6 +33,15 @@ class GuestUserView : public views::View {
// Overridden from views::View:
virtual bool AcceleratorPressed(const views::Accelerator& accelerator);
+ // Overridden from views::ButtonListener.
+ virtual void ButtonPressed(views::Button* sender, const views::Event& event);
+
+ // Overridden from UserInput:
+ virtual void EnableInputControls(bool enabled);
+ virtual void ClearAndFocusControls();
+ virtual void ClearAndFocusPassword();
+ virtual gfx::Rect GetMainInputScreenBounds() const;
+
private:
// Overridden from views::View:
virtual void OnLocaleChanged();
@@ -42,7 +55,7 @@ class GuestUserView : public views::View {
UserController* user_controller_;
- views::Accelerator accel_enable_accessibility_;
+ views::Accelerator accel_toggle_accessibility_;
views::Accelerator accel_login_off_the_record_;
views::Accelerator accel_previous_pod_by_arrow_;
views::Accelerator accel_previous_pod_by_tab_;
diff --git a/chrome/browser/chromeos/login/helper.cc b/chrome/browser/chromeos/login/helper.cc
index 1b7ebba..2cfc600 100644
--- a/chrome/browser/chromeos/login/helper.cc
+++ b/chrome/browser/chromeos/login/helper.cc
@@ -17,6 +17,7 @@
#include "views/controls/throbber.h"
#include "views/painter.h"
#include "views/screen.h"
+#include "views/widget/widget.h"
namespace chromeos {
@@ -67,7 +68,52 @@ class BackgroundPainter : public views::Painter {
} // namespace
-views::Throbber* CreateDefaultSmoothedThrobber() {
+ThrobberHostView::ThrobberHostView()
+ : host_view_(this),
+ throbber_widget_(NULL) {
+}
+
+ThrobberHostView::~ThrobberHostView() {
+ StopThrobber();
+}
+
+void ThrobberHostView::StartThrobber() {
+ StopThrobber();
+ views::Widget* widget = host_view_->GetWidget();
+ if (widget) {
+ views::SmoothedThrobber* throbber = CreateDefaultSmoothedThrobber();
+ throbber->set_stop_delay_ms(0);
+ gfx::Rect throbber_bounds = CalculateThrobberBounds(throbber);
+
+ throbber_widget_ =
+ views::Widget::CreatePopupWidget(views::Widget::Transparent,
+ views::Widget::NotAcceptEvents,
+ views::Widget::DeleteOnDestroy,
+ views::Widget::DontMirrorOriginInRTL);
+ throbber_bounds.Offset(host_view_->GetScreenBounds().origin());
+ throbber_widget_->InitWithWidget(widget, throbber_bounds);
+ throbber_widget_->SetContentsView(throbber);
+ throbber_widget_->Show();
+ throbber->Start();
+ }
+}
+
+void ThrobberHostView::StopThrobber() {
+ if (throbber_widget_) {
+ throbber_widget_->Close();
+ throbber_widget_ = NULL;
+ }
+}
+
+gfx::Rect ThrobberHostView::CalculateThrobberBounds(views::Throbber* throbber) {
+ gfx::Rect bounds(throbber->GetPreferredSize());
+ bounds.set_x(
+ host_view_->width() - login::kThrobberRightMargin - bounds.width());
+ bounds.set_y((host_view_->height() - bounds.height()) / 2);
+ return bounds;
+}
+
+views::SmoothedThrobber* CreateDefaultSmoothedThrobber() {
views::SmoothedThrobber* throbber =
new views::SmoothedThrobber(kThrobberFrameMs);
throbber->SetFrames(
@@ -94,7 +140,6 @@ gfx::Rect CalculateScreenBounds(const gfx::Size& size) {
int vertical_diff = bounds.height() - size.height();
bounds.Inset(horizontal_diff / 2, vertical_diff / 2);
}
-
return bounds;
}
@@ -124,9 +169,6 @@ GURL GetAccountRecoveryHelpUrl() {
namespace login {
-// Minimal width for the button.
-const int kButtonMinWidth = 90;
-
gfx::Size WideButton::GetPreferredSize() {
gfx::Size preferred_size = NativeButton::GetPreferredSize();
// Set minimal width.
@@ -138,4 +180,3 @@ gfx::Size WideButton::GetPreferredSize() {
} // namespace login
} // namespace chromeos
-
diff --git a/chrome/browser/chromeos/login/helper.h b/chrome/browser/chromeos/login/helper.h
index f10ef0a..b613032 100644
--- a/chrome/browser/chromeos/login/helper.h
+++ b/chrome/browser/chromeos/login/helper.h
@@ -8,8 +8,10 @@
#define CHROME_BROWSER_CHROMEOS_LOGIN_HELPER_H_
#pragma once
-#include "views/controls/button/native_button.h"
#include "third_party/skia/include/core/SkColor.h"
+#include "views/controls/button/native_button.h"
+#include "views/view.h"
+#include "views/widget/widget_gtk.h"
class GURL;
@@ -22,14 +24,49 @@ namespace views {
class Label;
class MenuButton;
class Painter;
+class SmoothedThrobber;
class Textfield;
class Throbber;
+class Widget;
} // namespace views
namespace chromeos {
+// View that provides interface for start/stop throbber above the view.
+class ThrobberHostView : public views::View {
+ public:
+ ThrobberHostView();
+ virtual ~ThrobberHostView();
+
+ // Creates throbber above the view in the right side with the default
+ // margin. Also places throbber in the middle of the vertical host size.
+ // Override |CalculateThrobberBounds| method to change the throbber placing.
+ virtual void StartThrobber();
+
+ // Stops the throbber.
+ virtual void StopThrobber();
+
+ protected:
+ // Calculates the bounds of the throbber relatively to the host view.
+ // Default position is vertically centered right side of the host view.
+ virtual gfx::Rect CalculateThrobberBounds(views::Throbber* throbber);
+
+ void set_host_view(views::View* host_view) {
+ host_view_ = host_view;
+ }
+
+ private:
+ // View to show the throbber above (default is |this|).
+ views::View* host_view_;
+
+ // Popup that contains the throbber.
+ views::Widget* throbber_widget_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThrobberHostView);
+};
+
// Creates default smoothed throbber for time consuming operations on login.
-views::Throbber* CreateDefaultSmoothedThrobber();
+views::SmoothedThrobber* CreateDefaultSmoothedThrobber();
// Creates default throbber.
views::Throbber* CreateDefaultThrobber();
@@ -67,7 +104,7 @@ enum Command {
};
// Gap between edge and image view, and image view and controls.
-const int kBorderSize = 6;
+const int kBorderSize = 10;
// The size of user image.
const int kUserImageSize = 256;
@@ -81,18 +118,24 @@ const SkColor kTextColor = SK_ColorWHITE;
// Default link color on login/OOBE controls.
const SkColor kLinkColor = 0xFF0066CC;
+// Right margin for placing throbber above the view.
+const int kThrobberRightMargin = 10;
+
// Default size of the OOBE screen. Includes 10px shadow from each side.
// See rounded_rect_painter.cc for border definitions.
const int kWizardScreenWidth = 800;
const int kWizardScreenHeight = 450;
const int kScreenCornerRadius = 10;
-const int kUserCornerRadius = 5;
+const int kUserCornerRadius = 6;
// Username label height in different states.
const int kSelectedLabelHeight = 25;
const int kUnselectedLabelHeight = 20;
+// Minimal width for the button.
+const int kButtonMinWidth = 90;
+
class WideButton : public views::NativeButton {
public:
WideButton(views::ButtonListener* listener, const std::wstring& text)
diff --git a/chrome/browser/chromeos/login/html_page_screen.cc b/chrome/browser/chromeos/login/html_page_screen.cc
index 0db18c1..ed65068 100644
--- a/chrome/browser/chromeos/login/html_page_screen.cc
+++ b/chrome/browser/chromeos/login/html_page_screen.cc
@@ -9,7 +9,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/input_method/input_method_util.h"
#include "chrome/browser/chromeos/login/screen_observer.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/tab_contents/tab_contents.h"
diff --git a/chrome/browser/chromeos/login/image_downloader.cc b/chrome/browser/chromeos/login/image_downloader.cc
index d480357..943b9e9 100644
--- a/chrome/browser/chromeos/login/image_downloader.cc
+++ b/chrome/browser/chromeos/login/image_downloader.cc
@@ -4,13 +4,14 @@
#include "chrome/browser/chromeos/login/image_downloader.h"
+#include <vector>
+
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/common/net/url_fetcher.h"
namespace chromeos {
@@ -61,4 +62,3 @@ void ImageDownloader::OnURLFetchComplete(const URLFetcher* source,
}
} // namespace chromeos
-
diff --git a/chrome/browser/chromeos/login/keyboard_switch_menu.cc b/chrome/browser/chromeos/login/keyboard_switch_menu.cc
index de2026b..ff11bee 100644
--- a/chrome/browser/chromeos/login/keyboard_switch_menu.cc
+++ b/chrome/browser/chromeos/login/keyboard_switch_menu.cc
@@ -24,8 +24,10 @@ KeyboardSwitchMenu::KeyboardSwitchMenu()
////////////////////////////////////////////////////////////////////////////////
// InputMethodMenu::InputMethodMenuHost implementation.
-void KeyboardSwitchMenu::UpdateUI(
- const std::wstring& name, const std::wstring& tooltip) {
+void KeyboardSwitchMenu::UpdateUI(const std::string& input_method_id,
+ const std::wstring& name,
+ const std::wstring& tooltip,
+ size_t num_active_input_methods) {
// Update all view hierarchies so that the new input method name is shown in
// the menu button.
views::Widget::NotifyLocaleChanged();
diff --git a/chrome/browser/chromeos/login/keyboard_switch_menu.h b/chrome/browser/chromeos/login/keyboard_switch_menu.h
index 64bd2aa..48c0982 100644
--- a/chrome/browser/chromeos/login/keyboard_switch_menu.h
+++ b/chrome/browser/chromeos/login/keyboard_switch_menu.h
@@ -23,8 +23,10 @@ class KeyboardSwitchMenu : public InputMethodMenu {
virtual ~KeyboardSwitchMenu() {}
// InputMethodMenu::InputMethodMenuHost implementation.
- virtual void UpdateUI(
- const std::wstring& name, const std::wstring& tooltip);
+ virtual void UpdateUI(const std::string& input_method_id,
+ const std::wstring& name,
+ const std::wstring& tooltip,
+ size_t num_active_input_methods);
virtual bool ShouldSupportConfigUI() { return false; }
virtual void OpenConfigUI() {}
diff --git a/chrome/browser/chromeos/login/login_browsertest.cc b/chrome/browser/chromeos/login/login_browsertest.cc
index 5e6ee92..fa76953 100644
--- a/chrome/browser/chromeos/login/login_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_browsertest.cc
@@ -14,7 +14,7 @@
#include "chrome/browser/chromeos/cros/mock_screen_lock_library.h"
#include "chrome/browser/chromeos/cros/mock_system_library.h"
#include "chrome/browser/chromeos/cros/mock_touchpad_library.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/in_process_browser_test.h"
@@ -93,7 +93,7 @@ IN_PROC_BROWSER_TEST_F(LoginProfileTest, UserNotPassed) {
EXPECT_EQ("Default", profile->GetPath().BaseName().value());
EXPECT_TRUE(profile->IsOffTheRecord());
// Ensure there's no extension service for this profile.
- EXPECT_EQ(NULL, profile->GetExtensionsService());
+ EXPECT_EQ(NULL, profile->GetExtensionService());
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/login_html_dialog.cc b/chrome/browser/chromeos/login/login_html_dialog.cc
index 7e69af9..52c3635 100644
--- a/chrome/browser/chromeos/login/login_html_dialog.cc
+++ b/chrome/browser/chromeos/login/login_html_dialog.cc
@@ -7,8 +7,8 @@
#include "chrome/browser/chromeos/frame/bubble_frame_view.h"
#include "chrome/browser/chromeos/frame/bubble_window.h"
#include "chrome/browser/chromeos/login/helper.h"
-#include "chrome/browser/profile_manager.h"
-#include "chrome/browser/views/html_dialog_view.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/views/html_dialog_view.h"
#include "chrome/common/notification_service.h"
#include "gfx/native_widget_types.h"
#include "gfx/rect.h"
diff --git a/chrome/browser/chromeos/login/login_performer.cc b/chrome/browser/chromeos/login/login_performer.cc
index eb5304d..c37c404 100644
--- a/chrome/browser/chromeos/login/login_performer.cc
+++ b/chrome/browser/chromeos/login/login_performer.cc
@@ -4,41 +4,102 @@
#include "chrome/browser/chromeos/login/login_performer.h"
+#include <string>
+
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
#include "base/logging.h"
#include "base/message_loop.h"
+#include "base/metrics/histogram.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/chromeos/boot_times_loader.h"
+#include "chrome/browser/chromeos/cros/cros_library.h"
+#include "chrome/browser/chromeos/cros/screen_lock_library.h"
#include "chrome/browser/chromeos/login/login_utils.h"
+#include "chrome/browser/chromeos/login/screen_locker.h"
#include "chrome/browser/chromeos/user_cros_settings_provider.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
+#include "grit/generated_resources.h"
namespace chromeos {
-namespace {
-} // namespace
+// Initialize default LoginPerformer.
+// static
+LoginPerformer* LoginPerformer::default_performer_ = NULL;
LoginPerformer::LoginPerformer(Delegate* delegate)
: last_login_failure_(LoginFailure::None()),
- delegate_(delegate) {}
+ delegate_(delegate),
+ password_changed_(false),
+ screen_lock_requested_(false),
+ initial_online_auth_pending_(false),
+ method_factory_(this) {
+ DCHECK(default_performer_ == NULL)
+ << "LoginPerformer should have only one instance.";
+ default_performer_ = this;
+}
+
+LoginPerformer::~LoginPerformer() {
+ DVLOG(1) << "Deleting LoginPerformer";
+ DCHECK(default_performer_ != NULL) << "Default instance should exist.";
+ default_performer_ = NULL;
+}
////////////////////////////////////////////////////////////////////////////////
// LoginPerformer, LoginStatusConsumer implementation:
void LoginPerformer::OnLoginFailure(const LoginFailure& failure) {
- last_login_failure_ = failure;
- if (delegate_) {
- captcha_.clear();
- captcha_token_.clear();
- if (failure.reason() == LoginFailure::NETWORK_AUTH_FAILED &&
- failure.error().state() == GoogleServiceAuthError::CAPTCHA_REQUIRED) {
- captcha_token_ = failure.error().captcha().token;
- }
- delegate_->OnLoginFailure(failure);
- } else {
- // TODO(nkostylev): Provide blocking UI using ScreenLocker.
- }
+ UserMetrics::RecordAction(UserMetricsAction("Login_Failure"));
+ UMA_HISTOGRAM_ENUMERATION("Login.FailureReason", failure.reason(),
+ LoginFailure::NUM_FAILURE_REASONS);
+
+ DVLOG(1) << "failure.reason " << failure.reason();
+ DVLOG(1) << "failure.error.state " << failure.error().state();
+
+ last_login_failure_ = failure;
+ if (delegate_) {
+ captcha_.clear();
+ captcha_token_.clear();
+ if (failure.reason() == LoginFailure::NETWORK_AUTH_FAILED &&
+ failure.error().state() == GoogleServiceAuthError::CAPTCHA_REQUIRED) {
+ captcha_token_ = failure.error().captcha().token;
+ }
+ delegate_->OnLoginFailure(failure);
+ return;
+ }
+
+ // Consequent online login failure with blocking UI on.
+ // No difference between cases whether screen was locked by the user or
+ // by LoginPerformer except for the very first screen lock while waiting
+ // for online auth. Otherwise it will be SL active > timeout > screen unlock.
+ // Display recoverable error message using ScreenLocker,
+ // force sign out otherwise.
+ if (ScreenLocker::default_screen_locker() && !initial_online_auth_pending_) {
+ ResolveLockLoginFailure();
+ return;
+ }
+ initial_online_auth_pending_ = false;
+
+ // Offline auth - OK, online auth - failed.
+ if (failure.reason() == LoginFailure::NETWORK_AUTH_FAILED) {
+ ResolveInitialNetworkAuthFailure();
+ } else if (failure.reason() == LoginFailure::LOGIN_TIMED_OUT) {
+ VLOG(1) << "Online login timed out. "
+ << "Granting user access based on offline auth only.";
+ // ScreenLock is not active, it's ok to delete itself.
+ MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+ } else {
+ // COULD_NOT_MOUNT_CRYPTOHOME, COULD_NOT_MOUNT_TMPFS:
+ // happens during offline auth only.
+ // UNLOCK_FAILED is used during normal screen lock case.
+ // TODO(nkostylev) DATA_REMOVAL_FAILED - ?
+ NOTREACHED();
+ }
}
void LoginPerformer::OnLoginSuccess(
@@ -46,21 +107,59 @@ void LoginPerformer::OnLoginSuccess(
const std::string& password,
const GaiaAuthConsumer::ClientLoginResult& credentials,
bool pending_requests) {
+ UserMetrics::RecordAction(UserMetricsAction("Login_Success"));
+ // 0 - Login success offline and online. It's a new user. or it's an
+ // existing user and offline auth took longer than online auth.
+ // 1 - Login success offline only. It's an existing user login.
+ UMA_HISTOGRAM_ENUMERATION("Login.SuccessReason", pending_requests, 2);
+
+ VLOG(1) << "LoginSuccess, pending_requests " << pending_requests;
if (delegate_) {
+ // After delegate_->OnLoginSuccess(...) is called, delegate_ releases
+ // LoginPerformer ownership. LP now manages it's lifetime on its own.
+ // 2 things could make it exist longer:
+ // 1. ScreenLock active (pending correct new password input)
+ // 2. Pending online auth request.
+ if (!pending_requests)
+ MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+ else
+ initial_online_auth_pending_ = true;
+
delegate_->OnLoginSuccess(username,
password,
credentials,
pending_requests);
- if (!pending_requests)
- MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+ return;
} else {
- DCHECK(!pending_requests);
- // Online login has succeeded. Delete our instance.
+ DCHECK(!pending_requests)
+ << "Pending request w/o delegate_ should not happen!";
+ // Online login has succeeded.
+ Profile* profile =
+ g_browser_process->profile_manager()->GetDefaultProfile();
+ LoginUtils::Get()->FetchCookies(profile, credentials);
+ LoginUtils::Get()->FetchTokens(profile, credentials);
+
+ // Don't unlock screen if it was locked while we're waiting
+ // for initial online auth.
+ if (ScreenLocker::default_screen_locker() &&
+ !initial_online_auth_pending_) {
+ DVLOG(1) << "Online login OK - unlocking screen.";
+ RequestScreenUnlock();
+ // Do not delete itself just yet, wait for unlock.
+ // See ResolveScreenUnlocked().
+ return;
+ }
+ initial_online_auth_pending_ = false;
+ // There's nothing else that's holding LP from deleting itself -
+ // no ScreenLock, no pending requests.
MessageLoop::current()->DeleteSoon(FROM_HERE, this);
}
}
void LoginPerformer::OnOffTheRecordLoginSuccess() {
+ UserMetrics::RecordAction(
+ UserMetricsAction("Login_GuestLoginSuccess"));
+
if (delegate_)
delegate_->OnOffTheRecordLoginSuccess();
else
@@ -73,16 +172,21 @@ void LoginPerformer::OnPasswordChangeDetected(
if (delegate_) {
delegate_->OnPasswordChangeDetected(credentials);
} else {
- // TODO(nkostylev): Provide blocking UI using ScreenLocker.
+ last_login_failure_ =
+ LoginFailure::FromNetworkAuthFailure(GoogleServiceAuthError(
+ GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
+ password_changed_ = true;
+ DVLOG(1) << "Password change detected - locking screen.";
+ RequestScreenLock();
}
}
////////////////////////////////////////////////////////////////////////////////
// LoginPerformer, SignedSettingsHelper::Callback implementation:
-void LoginPerformer::OnCheckWhiteListCompleted(bool success,
+void LoginPerformer::OnCheckWhitelistCompleted(SignedSettings::ReturnCode code,
const std::string& email) {
- if (success) {
+ if (code == SignedSettings::SUCCESS) {
// Whitelist check passed, continue with authentication.
StartAuthentication();
} else {
@@ -94,14 +198,53 @@ void LoginPerformer::OnCheckWhiteListCompleted(bool success,
}
////////////////////////////////////////////////////////////////////////////////
+// LoginPerformer, NotificationObserver implementation:
+//
+
+void LoginPerformer::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type != NotificationType::SCREEN_LOCK_STATE_CHANGED)
+ return;
+
+ bool is_screen_locked = *Details<bool>(details).ptr();
+ if (is_screen_locked) {
+ if (screen_lock_requested_) {
+ screen_lock_requested_ = false;
+ ResolveScreenLocked();
+ }
+ } else {
+ ResolveScreenUnlocked();
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
// LoginPerformer, public:
void LoginPerformer::Login(const std::string& username,
const std::string& password) {
username_ = username;
password_ = password;
- if (UserCrosSettingsProvider::cached_allow_new_user()) {
- // Starts authentication if guest login is allowed.
+
+ // Whitelist check is always performed during initial login and
+ // should not be performed when ScreenLock is active (pending online auth).
+ if (!ScreenLocker::default_screen_locker()) {
+ // Must not proceed without signature verification.
+ UserCrosSettingsProvider user_settings;
+ bool trusted_setting_available = user_settings.RequestTrustedAllowNewUser(
+ method_factory_.NewRunnableMethod(&LoginPerformer::Login,
+ username,
+ password));
+ if (!trusted_setting_available) {
+ // Value of AllowNewUser setting is still not verified.
+ // Another attempt will be invoked after verification completion.
+ return;
+ }
+ }
+
+ if (ScreenLocker::default_screen_locker() ||
+ UserCrosSettingsProvider::cached_allow_new_user()) {
+ // Starts authentication if guest login is allowed or online auth pending.
StartAuthentication();
} else {
// Otherwise, do whitelist check first.
@@ -140,19 +283,183 @@ void LoginPerformer::ResyncEncryptedData() {
////////////////////////////////////////////////////////////////////////////////
// LoginPerformer, private:
+void LoginPerformer::RequestScreenLock() {
+ DVLOG(1) << "Screen lock requested";
+ // Will receive notifications on screen unlock and delete itself.
+ registrar_.Add(this,
+ NotificationType::SCREEN_LOCK_STATE_CHANGED,
+ NotificationService::AllSources());
+ if (ScreenLocker::default_screen_locker()) {
+ DVLOG(1) << "Screen already locked";
+ ResolveScreenLocked();
+ } else {
+ screen_lock_requested_ = true;
+ chromeos::CrosLibrary::Get()->GetScreenLockLibrary()->
+ NotifyScreenLockRequested();
+ }
+}
+
+void LoginPerformer::RequestScreenUnlock() {
+ DVLOG(1) << "Screen unlock requested";
+ if (ScreenLocker::default_screen_locker()) {
+ chromeos::CrosLibrary::Get()->GetScreenLockLibrary()->
+ NotifyScreenUnlockRequested();
+ // Will unsubscribe from notifications once unlock is successful.
+ } else {
+ LOG(ERROR) << "Screen is not locked";
+ NOTREACHED();
+ }
+}
+
+void LoginPerformer::ResolveInitialNetworkAuthFailure() {
+ DVLOG(1) << "auth_error: " << last_login_failure_.error().state();
+
+ switch (last_login_failure_.error().state()) {
+ case GoogleServiceAuthError::CONNECTION_FAILED:
+ case GoogleServiceAuthError::SERVICE_UNAVAILABLE:
+ case GoogleServiceAuthError::TWO_FACTOR:
+ case GoogleServiceAuthError::REQUEST_CANCELED:
+ // Offline auth already done. Online auth will be done next time
+ // or once user accesses web property.
+ VLOG(1) << "Granting user access based on offline auth only. "
+ << "Online login failed with "
+ << last_login_failure_.error().state();
+ // Resolving initial online auth failure, no ScreenLock is active.
+ MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+ return;
+ case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
+ // Offline auth OK, so it might be the case of changed password.
+ password_changed_ = true;
+ case GoogleServiceAuthError::USER_NOT_SIGNED_UP:
+ case GoogleServiceAuthError::ACCOUNT_DELETED:
+ case GoogleServiceAuthError::ACCOUNT_DISABLED:
+ // Access not granted. User has to sign out.
+ // Request screen lock & show error message there.
+ case GoogleServiceAuthError::CAPTCHA_REQUIRED:
+ // User is requested to enter CAPTCHA challenge.
+ RequestScreenLock();
+ return;
+ default:
+ // Unless there's new GoogleServiceAuthErrors state has been added.
+ NOTREACHED();
+ return;
+ }
+}
+
+void LoginPerformer::ResolveLockLoginFailure() {
+ if (last_login_failure_.reason() == LoginFailure::LOGIN_TIMED_OUT) {
+ LOG(WARNING) << "Online login timed out - unlocking screen. "
+ << "Granting user access based on offline auth only.";
+ RequestScreenUnlock();
+ return;
+ } else if (last_login_failure_.reason() ==
+ LoginFailure::NETWORK_AUTH_FAILED) {
+ ResolveLockNetworkAuthFailure();
+ return;
+ } else if (last_login_failure_.reason() ==
+ LoginFailure::COULD_NOT_MOUNT_CRYPTOHOME ||
+ last_login_failure_.reason() ==
+ LoginFailure::DATA_REMOVAL_FAILED) {
+ LOG(ERROR) << "Cryptohome error, forcing sign out.";
+ } else {
+ // COULD_NOT_MOUNT_TMPFS, UNLOCK_FAILED should not happen here.
+ NOTREACHED();
+ }
+ ScreenLocker::default_screen_locker()->Signout();
+}
+
+void LoginPerformer::ResolveLockNetworkAuthFailure() {
+ DCHECK(ScreenLocker::default_screen_locker())
+ << "ScreenLocker instance doesn't exist.";
+ DCHECK(last_login_failure_.reason() == LoginFailure::NETWORK_AUTH_FAILED);
+
+ std::wstring msg;
+ bool sign_out_only = false;
+
+ DVLOG(1) << "auth_error: " << last_login_failure_.error().state();
+
+ switch (last_login_failure_.error().state()) {
+ case GoogleServiceAuthError::CONNECTION_FAILED:
+ case GoogleServiceAuthError::SERVICE_UNAVAILABLE:
+ case GoogleServiceAuthError::TWO_FACTOR:
+ case GoogleServiceAuthError::REQUEST_CANCELED:
+ // Offline auth already done. Online auth will be done next time
+ // or once user accesses web property.
+ LOG(WARNING) << "Granting user access based on offline auth only. "
+ << "Online login failed with "
+ << last_login_failure_.error().state();
+ RequestScreenUnlock();
+ return;
+ case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
+ // Password change detected.
+ msg = l10n_util::GetString(IDS_LOGIN_ERROR_PASSWORD_CHANGED);
+ break;
+ case GoogleServiceAuthError::USER_NOT_SIGNED_UP:
+ case GoogleServiceAuthError::ACCOUNT_DELETED:
+ case GoogleServiceAuthError::ACCOUNT_DISABLED:
+ // Access not granted. User has to sign out.
+ // Show error message using existing screen lock.
+ msg = l10n_util::GetString(IDS_LOGIN_ERROR_RESTRICTED);
+ sign_out_only = true;
+ break;
+ case GoogleServiceAuthError::CAPTCHA_REQUIRED:
+ // User is requested to enter CAPTCHA challenge.
+ msg = l10n_util::GetString(IDS_LOGIN_ERROR_PASSWORD_CHANGED);
+ ScreenLocker::default_screen_locker()->ShowCaptchaAndErrorMessage(
+ last_login_failure_.error().captcha().image_url,
+ msg);
+ return;
+ default:
+ // Unless there's new GoogleServiceAuthError state has been added.
+ NOTREACHED();
+ break;
+ }
+
+ ScreenLocker::default_screen_locker()->ShowErrorMessage(msg, sign_out_only);
+}
+
+void LoginPerformer::ResolveScreenLocked() {
+ DVLOG(1) << "Screen locked";
+ ResolveLockNetworkAuthFailure();
+}
+
+void LoginPerformer::ResolveScreenUnlocked() {
+ DVLOG(1) << "Screen unlocked";
+ registrar_.RemoveAll();
+ // If screen was unlocked that was for a reason, should delete itself now.
+ MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+}
+
void LoginPerformer::StartAuthentication() {
+ DVLOG(1) << "Auth started";
BootTimesLoader::Get()->AddLoginTimeMarker("AuthStarted", false);
- authenticator_ = LoginUtils::Get()->CreateAuthenticator(this);
Profile* profile = g_browser_process->profile_manager()->GetDefaultProfile();
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(authenticator_.get(),
- &Authenticator::AuthenticateToLogin,
- profile,
- username_,
- password_,
- captcha_token_,
- captcha_));
+ if (delegate_) {
+ authenticator_ = LoginUtils::Get()->CreateAuthenticator(this);
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(authenticator_.get(),
+ &Authenticator::AuthenticateToLogin,
+ profile,
+ username_,
+ password_,
+ captcha_token_,
+ captcha_));
+ } else {
+ DCHECK(authenticator_.get())
+ << "Authenticator instance doesn't exist for login attempt retry.";
+ // At this point offline auth has been successful,
+ // retry online auth, using existing Authenticator instance.
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(authenticator_.get(),
+ &Authenticator::RetryAuth,
+ profile,
+ username_,
+ password_,
+ captcha_token_,
+ captcha_));
+ }
password_.clear();
}
diff --git a/chrome/browser/chromeos/login/login_performer.h b/chrome/browser/chromeos/login/login_performer.h
index e594723..5827601 100644
--- a/chrome/browser/chromeos/login/login_performer.h
+++ b/chrome/browser/chromeos/login/login_performer.h
@@ -10,26 +10,49 @@
#include "base/basictypes.h"
#include "base/ref_counted.h"
+#include "base/task.h"
#include "chrome/browser/chromeos/login/authenticator.h"
#include "chrome/browser/chromeos/login/login_status_consumer.h"
#include "chrome/browser/chromeos/login/signed_settings_helper.h"
#include "chrome/common/net/gaia/google_service_auth_error.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
namespace chromeos {
// This class encapsulates sign in operations.
-// Sign in is performed in a way that offline login is executed first.
-// Once it's successful user homedir is mounted, UI is launched.
-// If concurrent online login operation would fail that means:
-// - User password has changed. Ask user for the new password.
-// - User password has changed & CAPTCHA input is required.
-// If |delegate_| is not NULL it will handle
-// password changed and CAPTCHA dialogs.
+// Sign in is performed in a way that offline auth is executed first.
+// Once offline auth is OK - user homedir is mounted, UI is launched.
+// At this point LoginPerformer |delegate_| is destroyed and it releases
+// LP instance ownership. LP waits for online login result.
+// If auth is succeeded, cookie fetcher is executed, LP instance deletes itself.
+//
+// If online login operation fails that means:
+// (1) User password has changed. Ask user for the new password.
+// (2) User password has changed and/or CAPTCHA input is required.
+// (3) User account is deleted/disabled/not signed up.
+// (4) Timeout/service unavailable/connection failed.
+//
+// Actions:
+// (1)-(3): Request screen lock.
+// (1) Ask for new user password.
+// (2) Ask for new user password and/or CAPTCHA.
+// (3) Display error message and allow "Sign Out" as the only action.
+// (4) Delete LP instance since offline auth was OK.
+//
+// If |delegate_| is not NULL it will handle error messages,
+// CAPTCHA dialog, password input.
// If |delegate_| is NULL that does mean that LoginPerformer instance
-// is waiting for online login operation.
-// In case of failure use ScreenLock and ask for a new password.
+// is waiting for successful online login or blocked on online login failure.
+// In case of failure password/captcha
+// input & error messages display is dedicated to ScreenLocker instance.
+//
+// 2 things make LoginPerfrormer instance exist longer:
+// 1. ScreenLock active (pending correct new password input)
+// 2. Pending online auth request.
class LoginPerformer : public LoginStatusConsumer,
- public SignedSettingsHelper::Callback {
+ public SignedSettingsHelper::Callback,
+ public NotificationObserver {
public:
// Delegate class to get notifications from the LoginPerformer.
class Delegate : public LoginStatusConsumer {
@@ -39,6 +62,14 @@ class LoginPerformer : public LoginStatusConsumer,
};
explicit LoginPerformer(Delegate* delegate);
+ virtual ~LoginPerformer();
+
+ // Returns the default instance if it has been created.
+ // This instance is owned by delegate_ till it's destroyed.
+ // When LP instance lives by itself it's used by ScreenLocker instance.
+ static LoginPerformer* default_performer() {
+ return default_performer_;
+ }
// LoginStatusConsumer implementation:
virtual void OnLoginFailure(const LoginFailure& error);
@@ -51,10 +82,15 @@ class LoginPerformer : public LoginStatusConsumer,
virtual void OnPasswordChangeDetected(
const GaiaAuthConsumer::ClientLoginResult& credentials);
- // SignedSettingsHelper::Callback
- virtual void OnCheckWhiteListCompleted(bool success,
+ // SignedSettingsHelper::Callback implementation:
+ virtual void OnCheckWhitelistCompleted(SignedSettings::ReturnCode code,
const std::string& email);
+ // NotificationObserver implementation:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
// Performs login with the |username| and |password| specified.
void Login(const std::string& username, const std::string& password);
@@ -81,9 +117,33 @@ class LoginPerformer : public LoginStatusConsumer,
void set_delegate(Delegate* delegate) { delegate_ = delegate; }
private:
+ // Requests screen lock and subscribes to screen lock notifications.
+ void RequestScreenLock();
+
+ // Requests screen unlock.
+ void RequestScreenUnlock();
+
+ // Resolves initial LoginFailure::NETWORK_AUTH_FAILED error i.e.
+ // when screen is not locked yet.
+ void ResolveInitialNetworkAuthFailure();
+
+ // Resolves LoginFailure when screen is locked.
+ void ResolveLockLoginFailure();
+
+ // Resolves LoginFailure::NETWORK_AUTH_FAILED error when screen is locked.
+ // Uses ScreenLocker to show error message based on |last_login_failure_|.
+ void ResolveLockNetworkAuthFailure();
+
+ // Resolve ScreenLock changed state.
+ void ResolveScreenLocked();
+ void ResolveScreenUnlocked();
+
// Starts authentication.
void StartAuthentication();
+ // Default performer. Will be used by ScreenLocker.
+ static LoginPerformer* default_performer_;
+
// Used for logging in.
scoped_refptr<Authenticator> authenticator_;
@@ -107,6 +167,24 @@ class LoginPerformer : public LoginStatusConsumer,
// Notifications receiver.
Delegate* delegate_;
+ // True if password change has been detected.
+ // Once correct password is entered homedir migration is executed.
+ bool password_changed_;
+
+ // Used for ScreenLock notifications.
+ NotificationRegistrar registrar_;
+
+ // True if LoginPerformer has requested screen lock. Used to distinguish
+ // such requests with cases when screen is locked on its own.
+ bool screen_lock_requested_;
+
+ // True if LoginPerformer instance is waiting for the initial (very first one)
+ // online authentication response. Used to distinguish cases when screen
+ // is locked during that stage. No need to resolve screen lock action then.
+ bool initial_online_auth_pending_;
+
+ ScopedRunnableMethodFactory<LoginPerformer> method_factory_;
+
DISALLOW_COPY_AND_ASSIGN(LoginPerformer);
};
diff --git a/chrome/browser/chromeos/login/login_screen.cc b/chrome/browser/chromeos/login/login_screen.cc
index 0efde84..5270b5b 100644
--- a/chrome/browser/chromeos/login/login_screen.cc
+++ b/chrome/browser/chromeos/login/login_screen.cc
@@ -21,9 +21,8 @@
#include "chrome/browser/chromeos/login/login_utils.h"
#include "chrome/browser/chromeos/login/message_bubble.h"
#include "chrome/browser/chromeos/login/screen_observer.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/profile_manager.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
@@ -91,7 +90,8 @@ void LoginScreen::OnLoginFailure(const LoginFailure& failure) {
ShowError(IDS_LOGIN_ERROR_AUTHENTICATING_NEW, error);
}
- view()->ClearAndEnablePassword();
+ view()->ClearAndFocusPassword();
+ view()->EnableInputControls(true);
}
void LoginScreen::OnLoginSuccess(
@@ -102,7 +102,10 @@ void LoginScreen::OnLoginSuccess(
delegate()->GetObserver(this)->OnExit(ScreenObserver::LOGIN_SIGN_IN_SELECTED);
AppendStartUrlToCmdline();
- LoginUtils::Get()->CompleteLogin(username, password, credentials);
+ LoginUtils::Get()->CompleteLogin(username,
+ password,
+ credentials,
+ pending_requests);
}
void LoginScreen::OnOffTheRecordLoginSuccess() {
diff --git a/chrome/browser/chromeos/login/login_status_consumer.h b/chrome/browser/chromeos/login/login_status_consumer.h
index da30369..c1a18ab 100644
--- a/chrome/browser/chromeos/login/login_status_consumer.h
+++ b/chrome/browser/chromeos/login/login_status_consumer.h
@@ -24,6 +24,7 @@ class LoginFailure {
LOGIN_TIMED_OUT,
UNLOCK_FAILED,
NETWORK_AUTH_FAILED, // Could not authenticate against Google
+ NUM_FAILURE_REASONS, // This has to be the last item.
};
explicit LoginFailure(FailureReason reason)
diff --git a/chrome/browser/chromeos/login/login_utils.cc b/chrome/browser/chromeos/login/login_utils.cc
index d741caf..82d8e13 100644
--- a/chrome/browser/chromeos/login/login_utils.cc
+++ b/chrome/browser/chromeos/login/login_utils.cc
@@ -31,14 +31,14 @@
#include "chrome/browser/chromeos/login/user_image_downloader.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/proxy_config_service.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/browser/net/gaia/token_service.h"
#include "chrome/browser/net/preconnect.h"
#include "chrome/browser/net/pref_proxy_config_service.h"
#include "chrome/browser/prefs/pref_member.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/ui/browser_init.h"
#include "chrome/common/chrome_paths.h"
@@ -107,12 +107,17 @@ class LoginUtilsImpl : public LoginUtils {
virtual void CompleteLogin(
const std::string& username,
const std::string& password,
- const GaiaAuthConsumer::ClientLoginResult& credentials);
+ const GaiaAuthConsumer::ClientLoginResult& credentials,
+ bool pending_requests);
// Invoked after the tmpfs is successfully mounted.
// Launches a browser in the off the record (incognito) mode.
virtual void CompleteOffTheRecordLogin(const GURL& start_url);
+ // Invoked when the user is logging in for the first time, or is logging in as
+ // a guest user.
+ virtual void SetFirstLoginPrefs(PrefService* prefs);
+
// Creates and returns the authenticator to use. The caller owns the returned
// Authenticator and must delete it when done.
virtual Authenticator* CreateAuthenticator(LoginStatusConsumer* consumer);
@@ -127,6 +132,17 @@ class LoginUtilsImpl : public LoginUtils {
// Warms the url used by authentication.
virtual void PrewarmAuthentication();
+ // Given the credentials try to exchange them for
+ // full-fledged Google authentication cookies.
+ virtual void FetchCookies(
+ Profile* profile,
+ const GaiaAuthConsumer::ClientLoginResult& credentials);
+
+ // Supply credentials for sync and others to use.
+ virtual void FetchTokens(
+ Profile* profile,
+ const GaiaAuthConsumer::ClientLoginResult& credentials);
+
private:
// Check user's profile for kApplicationLocale setting.
void RespectLocalePreference(PrefService* pref);
@@ -139,7 +155,9 @@ class LoginUtilsImpl : public LoginUtils {
class LoginUtilsWrapper {
public:
- LoginUtilsWrapper() {}
+ static LoginUtilsWrapper* GetInstance() {
+ return Singleton<LoginUtilsWrapper>::get();
+ }
LoginUtils* get() {
AutoLock create(create_lock_);
@@ -153,6 +171,10 @@ class LoginUtilsWrapper {
}
private:
+ friend struct DefaultSingletonTraits<LoginUtilsWrapper>;
+
+ LoginUtilsWrapper() {}
+
Lock create_lock_;
scoped_ptr<LoginUtils> ptr_;
@@ -162,7 +184,8 @@ class LoginUtilsWrapper {
void LoginUtilsImpl::CompleteLogin(
const std::string& username,
const std::string& password,
- const GaiaAuthConsumer::ClientLoginResult& credentials) {
+ const GaiaAuthConsumer::ClientLoginResult& credentials,
+ bool pending_requests) {
BootTimesLoader* btl = BootTimesLoader::Get();
VLOG(1) << "Completing login for " << username;
@@ -213,22 +236,20 @@ void LoginUtilsImpl::CompleteLogin(
new ResetDefaultProxyConfigServiceTask(
proxy_config_service));
- // Take the credentials passed in and try to exchange them for
- // full-fledged Google authentication cookies. This is
- // best-effort; it's possible that we'll fail due to network
- // troubles or some such. Either way, |cf| will call
- // DoBrowserLaunch on the UI thread when it's done, and then
- // delete itself.
- CookieFetcher* cf = new CookieFetcher(profile);
- cf->AttemptFetch(credentials.data);
- btl->AddLoginTimeMarker("CookieFetchStarted", false);
+ // Since we're doing parallel authentication, only new user sign in
+ // would perform online auth before calling CompleteLogin.
+ // For existing users there's usually a pending online auth request.
+ // Cookies will be fetched after it's is succeeded.
+ if (!pending_requests) {
+ FetchCookies(profile, credentials);
+ }
// Init extension event routers; this normally happens in browser_main
// but on Chrome OS it has to be deferred until the user finishes
// logging in and the profile is not OTR.
- if (profile->GetExtensionsService() &&
- profile->GetExtensionsService()->extensions_enabled()) {
- profile->GetExtensionsService()->InitEventRouters();
+ if (profile->GetExtensionService() &&
+ profile->GetExtensionService()->extensions_enabled()) {
+ profile->GetExtensionService()->InitEventRouters();
}
btl->AddLoginTimeMarker("ExtensionsServiceStarted", false);
@@ -237,9 +258,11 @@ void LoginUtilsImpl::CompleteLogin(
token_service->Initialize(GaiaConstants::kChromeOSSource,
profile);
token_service->LoadTokensFromDB();
- token_service->UpdateCredentials(credentials);
- if (token_service->AreCredentialsValid()) {
- token_service->StartFetchingTokens();
+
+ // For existing users there's usually a pending online auth request.
+ // Tokens will be fetched after it's is succeeded.
+ if (!pending_requests) {
+ FetchTokens(profile, credentials);
}
btl->AddLoginTimeMarker("TokensGotten", false);
@@ -267,39 +290,8 @@ void LoginUtilsImpl::CompleteLogin(
RespectLocalePreference(profile->GetPrefs());
- static const char kFallbackInputMethodLocale[] = "en-US";
if (first_login) {
- std::string locale(g_browser_process->GetApplicationLocale());
- // Add input methods based on the application locale when the user first
- // logs in. For instance, if the user chooses Japanese as the UI
- // language at the first login, we'll add input methods associated with
- // Japanese, such as mozc.
- if (locale != kFallbackInputMethodLocale) {
- StringPrefMember language_preload_engines;
- language_preload_engines.Init(prefs::kLanguagePreloadEngines,
- profile->GetPrefs(), NULL);
- StringPrefMember language_preferred_languages;
- language_preferred_languages.Init(prefs::kLanguagePreferredLanguages,
- profile->GetPrefs(), NULL);
-
- std::string preload_engines(language_preload_engines.GetValue());
- std::vector<std::string> input_method_ids;
- input_method::GetInputMethodIdsFromLanguageCode(
- locale, input_method::kAllInputMethods, &input_method_ids);
- if (!input_method_ids.empty()) {
- if (!preload_engines.empty())
- preload_engines += ',';
- preload_engines += input_method_ids[0];
- }
- language_preload_engines.SetValue(preload_engines);
-
- // Add the UI language to the preferred languages the user first logs in.
- std::string preferred_languages(locale);
- preferred_languages += ",";
- preferred_languages += kFallbackInputMethodLocale;
- language_preferred_languages.SetValue(preferred_languages);
- btl->AddLoginTimeMarker("IMESTarted", false);
- }
+ SetFirstLoginPrefs(profile->GetPrefs());
}
// We suck. This is a hack since we do not have the enterprise feature
@@ -314,17 +306,49 @@ void LoginUtilsImpl::CompleteLogin(
DoBrowserLaunch(profile);
}
+void LoginUtilsImpl::FetchCookies(
+ Profile* profile,
+ const GaiaAuthConsumer::ClientLoginResult& credentials) {
+ // Take the credentials passed in and try to exchange them for
+ // full-fledged Google authentication cookies. This is
+ // best-effort; it's possible that we'll fail due to network
+ // troubles or some such.
+ // CookieFetcher will delete itself once done.
+ CookieFetcher* cf = new CookieFetcher(profile);
+ cf->AttemptFetch(credentials.data);
+ BootTimesLoader::Get()->AddLoginTimeMarker("CookieFetchStarted", false);
+}
+
+void LoginUtilsImpl::FetchTokens(
+ Profile* profile,
+ const GaiaAuthConsumer::ClientLoginResult& credentials) {
+ TokenService* token_service = profile->GetTokenService();
+ token_service->UpdateCredentials(credentials);
+ if (token_service->AreCredentialsValid()) {
+ token_service->StartFetchingTokens();
+ }
+}
+
void LoginUtilsImpl::RespectLocalePreference(PrefService* pref) {
std::string pref_locale = pref->GetString(prefs::kApplicationLocale);
if (pref_locale.empty()) {
- // TODO(dilmah): current code will clobber existing setting in case
- // language preference was set via another device
- // but still not synced yet. Profile is not synced at this point yet.
- pref->SetString(prefs::kApplicationLocale,
- g_browser_process->GetApplicationLocale());
- } else {
- LanguageSwitchMenu::SwitchLanguage(pref_locale);
+ // Profile synchronization takes time and is not completed at that moment
+ // at first login. So we initialize locale preference in steps:
+ // (1) first save it to temporary backup;
+ // (2) on next login we assume that synchronization is already completed
+ // and we may finalize initialization.
+ std::string pref_locale_backup =
+ pref->GetString(prefs::kApplicationLocaleBackup);
+ if (pref_locale_backup.empty()) {
+ pref->SetString(prefs::kApplicationLocaleBackup,
+ g_browser_process->GetApplicationLocale());
+ return;
+ } else {
+ pref_locale.swap(pref_locale_backup);
+ pref->SetString(prefs::kApplicationLocale, pref_locale);
+ }
}
+ LanguageSwitchMenu::SwitchLanguage(pref_locale);
}
void LoginUtilsImpl::CompleteOffTheRecordLogin(const GURL& start_url) {
@@ -344,8 +368,9 @@ void LoginUtilsImpl::CompleteOffTheRecordLogin(const GURL& start_url) {
switches::kLoginProfile,
switches::kEnableTabbedOptions,
switches::kCompressSystemFeedback,
-#if defined(USE_SECCOMP_SANDBOX)
switches::kDisableSeccompSandbox,
+#if defined(HAVE_XINPUT2)
+ switches::kTouchDevices,
#endif
};
const CommandLine& browser_command_line =
@@ -387,6 +412,44 @@ void LoginUtilsImpl::CompleteOffTheRecordLogin(const GURL& start_url) {
}
}
+void LoginUtilsImpl::SetFirstLoginPrefs(PrefService* prefs) {
+ VLOG(1) << "Setting first login prefs";
+ BootTimesLoader* btl = BootTimesLoader::Get();
+
+ static const char kFallbackInputMethodLocale[] = "en-US";
+ std::string locale(g_browser_process->GetApplicationLocale());
+ // Add input methods based on the application locale when the user first
+ // logs in. For instance, if the user chooses Japanese as the UI
+ // language at the first login, we'll add input methods associated with
+ // Japanese, such as mozc.
+ if (locale != kFallbackInputMethodLocale) {
+ StringPrefMember language_preload_engines;
+ language_preload_engines.Init(prefs::kLanguagePreloadEngines,
+ prefs, NULL);
+ StringPrefMember language_preferred_languages;
+ language_preferred_languages.Init(prefs::kLanguagePreferredLanguages,
+ prefs, NULL);
+
+ std::string preload_engines(language_preload_engines.GetValue());
+ std::vector<std::string> input_method_ids;
+ input_method::GetInputMethodIdsFromLanguageCode(
+ locale, input_method::kAllInputMethods, &input_method_ids);
+ if (!input_method_ids.empty()) {
+ if (!preload_engines.empty())
+ preload_engines += ',';
+ preload_engines += input_method_ids[0];
+ }
+ language_preload_engines.SetValue(preload_engines);
+
+ // Add the UI language to the preferred languages the user first logs in.
+ std::string preferred_languages(locale);
+ preferred_languages += ",";
+ preferred_languages += kFallbackInputMethodLocale;
+ language_preferred_languages.SetValue(preferred_languages);
+ btl->AddLoginTimeMarker("IMEStarted", false);
+ }
+}
+
Authenticator* LoginUtilsImpl::CreateAuthenticator(
LoginStatusConsumer* consumer) {
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kParallelAuth))
@@ -443,11 +506,11 @@ void LoginUtilsImpl::PrewarmAuthentication() {
}
LoginUtils* LoginUtils::Get() {
- return Singleton<LoginUtilsWrapper>::get()->get();
+ return LoginUtilsWrapper::GetInstance()->get();
}
void LoginUtils::Set(LoginUtils* mock) {
- Singleton<LoginUtilsWrapper>::get()->reset(mock);
+ LoginUtilsWrapper::GetInstance()->reset(mock);
}
void LoginUtils::DoBrowserLaunch(Profile* profile) {
diff --git a/chrome/browser/chromeos/login/login_utils.h b/chrome/browser/chromeos/login/login_utils.h
index 26c4c50..165852b 100644
--- a/chrome/browser/chromeos/login/login_utils.h
+++ b/chrome/browser/chromeos/login/login_utils.h
@@ -12,6 +12,7 @@
class GURL;
class Profile;
+class PrefService;
namespace chromeos {
@@ -35,16 +36,22 @@ class LoginUtils {
// Invoked after the user has successfully logged in. This launches a browser
// and does other bookkeeping after logging in.
+ // If |pending_requests| is true, there's a pending online auth request.
virtual void CompleteLogin(
const std::string& username,
const std::string& password,
- const GaiaAuthConsumer::ClientLoginResult& credentials) = 0;
+ const GaiaAuthConsumer::ClientLoginResult& credentials,
+ bool pending_requests) = 0;
// Invoked after the tmpfs is successfully mounted.
// Asks session manager to restart Chrome in Browse Without Sign In mode.
// |start_url| is url for launched browser to open.
virtual void CompleteOffTheRecordLogin(const GURL& start_url) = 0;
+ // Invoked when the user is logging in for the first time, or is logging in as
+ // a guest user.
+ virtual void SetFirstLoginPrefs(PrefService* prefs) = 0;
+
// Creates and returns the authenticator to use. The caller owns the returned
// Authenticator and must delete it when done.
virtual Authenticator* CreateAuthenticator(LoginStatusConsumer* consumer) = 0;
@@ -59,6 +66,17 @@ class LoginUtils {
// Prewarms the authentication network connection.
virtual void PrewarmAuthentication() = 0;
+ // Given the credentials try to exchange them for
+ // full-fledged Google authentication cookies.
+ virtual void FetchCookies(
+ Profile* profile,
+ const GaiaAuthConsumer::ClientLoginResult& credentials) = 0;
+
+ // Supply credentials for sync and others to use.
+ virtual void FetchTokens(
+ Profile* profile,
+ const GaiaAuthConsumer::ClientLoginResult& credentials) = 0;
+
};
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/message_bubble.cc b/chrome/browser/chromeos/login/message_bubble.cc
index ab1ce1e..da2415a 100644
--- a/chrome/browser/chromeos/login/message_bubble.cc
+++ b/chrome/browser/chromeos/login/message_bubble.cc
@@ -27,7 +27,7 @@ MessageBubble::MessageBubble(views::WidgetGtk::Type type,
const std::wstring& help,
bool grab_enabled,
MessageBubbleDelegate* delegate)
- : InfoBubble(type),
+ : InfoBubble(type, false), // don't show while screen is locked
parent_(parent),
help_link_(NULL),
message_delegate_(delegate),
diff --git a/chrome/browser/chromeos/login/mock_authenticator.h b/chrome/browser/chromeos/login/mock_authenticator.h
index d58c110..5e0f708 100644
--- a/chrome/browser/chromeos/login/mock_authenticator.h
+++ b/chrome/browser/chromeos/login/mock_authenticator.h
@@ -112,7 +112,8 @@ class MockLoginUtils : public LoginUtils {
virtual void CompleteLogin(const std::string& username,
const std::string& password,
- const GaiaAuthConsumer::ClientLoginResult& res) {
+ const GaiaAuthConsumer::ClientLoginResult& res,
+ bool pending_requests) {
EXPECT_EQ(expected_username_, username);
EXPECT_EQ(expected_password_, password);
}
@@ -120,6 +121,9 @@ class MockLoginUtils : public LoginUtils {
virtual void CompleteOffTheRecordLogin(const GURL& start_url) {
}
+ virtual void SetFirstLoginPrefs(PrefService* prefs) {
+ }
+
virtual Authenticator* CreateAuthenticator(LoginStatusConsumer* consumer) {
return new MockAuthenticator(
consumer, expected_username_, expected_password_);
@@ -132,11 +136,17 @@ class MockLoginUtils : public LoginUtils {
return true;
}
- virtual const std::string& GetAuthToken() const {
- return auth_token_;
+ virtual void PrewarmAuthentication() {
+ }
+
+ virtual void FetchCookies(
+ Profile* profile,
+ const GaiaAuthConsumer::ClientLoginResult& credentials) {
}
- virtual void PrewarmAuthentication() {
+ virtual void FetchTokens(
+ Profile* profile,
+ const GaiaAuthConsumer::ClientLoginResult& credentials) {
}
private:
diff --git a/chrome/browser/chromeos/login/mock_url_fetchers.h b/chrome/browser/chromeos/login/mock_url_fetchers.h
index 187fc66..c3fd37b 100644
--- a/chrome/browser/chromeos/login/mock_url_fetchers.h
+++ b/chrome/browser/chromeos/login/mock_url_fetchers.h
@@ -6,8 +6,9 @@
#define CHROME_BROWSER_CHROMEOS_LOGIN_MOCK_URL_FETCHERS_H_
#pragma once
+#include <string>
+
#include "base/message_loop.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/common/net/url_fetcher.h"
#include "googleurl/src/gurl.h"
#include "net/url_request/url_request_status.h"
diff --git a/chrome/browser/chromeos/login/network_screen_browsertest.cc b/chrome/browser/chromeos/login/network_screen_browsertest.cc
index c1ac0e4..aa1e845 100644
--- a/chrome/browser/chromeos/login/network_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/network_screen_browsertest.cc
@@ -65,10 +65,6 @@ class NetworkScreenTest : public WizardInProcessBrowserTest {
// Minimal set of expectations needed on NetworkScreen initialization.
// Status bar expectations are defined with RetiresOnSaturation() so
// these mocks will be active once status bar is initialized.
- EXPECT_CALL(*mock_network_library_, active_network())
- .Times(AnyNumber())
- .WillRepeatedly((Return((const Network*)(NULL))))
- .RetiresOnSaturation();
EXPECT_CALL(*mock_network_library_, ethernet_connected())
.Times(2)
.WillRepeatedly(Return(false));
@@ -78,55 +74,34 @@ class NetworkScreenTest : public WizardInProcessBrowserTest {
EXPECT_CALL(*mock_network_library_, wifi_connected())
.Times(1)
.WillRepeatedly(Return(false));
-// EXPECT_CALL(*mock_network_library_, wifi_connecting())
-// .Times(2)
-// .WillRepeatedly(Return(false));
EXPECT_CALL(*mock_network_library_, cellular_connected())
.Times(1)
.WillRepeatedly(Return(false));
-// EXPECT_CALL(*mock_network_library_, cellular_connecting())
-// .Times(2)
-// .WillRepeatedly(Return(false));
- EXPECT_CALL(*mock_network_library_, ethernet_available())
- .Times(1)
- .WillRepeatedly((Return(true)))
- .RetiresOnSaturation();
- EXPECT_CALL(*mock_network_library_, ethernet_enabled())
- .Times(1)
- .WillRepeatedly((Return(true)))
- .RetiresOnSaturation();
+
+ cros_mock_->SetStatusAreaMocksExpectations();
+
+ // Override these return values, but do not set specific expectation:
EXPECT_CALL(*mock_network_library_, wifi_available())
- .Times(1)
- .WillRepeatedly((Return(false)))
- .RetiresOnSaturation();
+ .Times(AnyNumber())
+ .WillRepeatedly((Return(true)));
EXPECT_CALL(*mock_network_library_, wifi_enabled())
- .Times(1)
- .WillRepeatedly((Return(true)))
- .RetiresOnSaturation();
+ .Times(AnyNumber())
+ .WillRepeatedly((Return(true)));
+ EXPECT_CALL(*mock_network_library_, wifi_connecting())
+ .Times(AnyNumber())
+ .WillRepeatedly((Return(false)));
+ EXPECT_CALL(*mock_network_library_, wifi_scanning())
+ .Times(AnyNumber())
+ .WillRepeatedly((Return(false)));
EXPECT_CALL(*mock_network_library_, cellular_available())
- .Times(1)
- .WillRepeatedly((Return(false)))
- .RetiresOnSaturation();
+ .Times(AnyNumber())
+ .WillRepeatedly((Return(true)));
EXPECT_CALL(*mock_network_library_, cellular_enabled())
- .Times(1)
- .WillRepeatedly((Return(true)))
- .RetiresOnSaturation();
-
- // Add a Connecting for prewarming auth url check.
-// EXPECT_CALL(*mock_network_library_, Connecting())
-// .Times(1)
-// .WillRepeatedly(Return(false));
- // Add a Connected for prewarming auth url check.
-// EXPECT_CALL(*mock_network_library_, Connected())
-// .Times(4)
-// .WillRepeatedly(Return(false));
- // Add an Observer for prewarming auth url check.
- EXPECT_CALL(*mock_network_library_, AddNetworkManagerObserver(_))
- .Times(3);
- EXPECT_CALL(*mock_network_library_, RemoveNetworkManagerObserver(_))
- .Times(2);
-
- cros_mock_->SetStatusAreaMocksExpectations();
+ .Times(AnyNumber())
+ .WillRepeatedly((Return(true)));
+ EXPECT_CALL(*mock_network_library_, cellular_connecting())
+ .Times(AnyNumber())
+ .WillRepeatedly((Return(false)));
}
virtual void TearDownInProcessBrowserTestFixture() {
@@ -168,7 +143,6 @@ IN_PROC_BROWSER_TEST_F(NetworkScreenTest, Ethernet) {
NetworkSelectionView* network_view = network_screen->view();
ASSERT_TRUE(network_view != NULL);
- EXPECT_FALSE(network_view->IsContinueEnabled());
EXPECT_CALL(*mock_network_library_, ethernet_connected())
.WillOnce((Return(false)));
@@ -178,20 +152,19 @@ IN_PROC_BROWSER_TEST_F(NetworkScreenTest, Ethernet) {
.WillOnce((Return(false)));
EXPECT_CALL(*mock_network_library_, ethernet_connecting())
.WillOnce((Return(true)));
-
- network_screen->OnNetworkManagerChanged(mock_network_library_);
EXPECT_FALSE(network_view->IsContinueEnabled());
- EXPECT_FALSE(network_view->IsConnecting());
+ network_screen->OnNetworkManagerChanged(mock_network_library_);
EXPECT_CALL(*mock_network_library_, ethernet_connected())
.WillOnce(Return(true));
EXPECT_CALL(*mock_network_library_, Connected())
.Times(2)
.WillRepeatedly(Return(true));
-
+ EXPECT_FALSE(network_view->IsContinueEnabled());
+ EXPECT_FALSE(network_view->IsConnecting());
network_screen->OnNetworkManagerChanged(mock_network_library_);
- EXPECT_TRUE(network_view->IsContinueEnabled());
+ EXPECT_TRUE(network_view->IsContinueEnabled());
EmulateContinueButtonExit(network_screen);
}
@@ -203,7 +176,6 @@ IN_PROC_BROWSER_TEST_F(NetworkScreenTest, Wifi) {
NetworkSelectionView* network_view = network_screen->view();
ASSERT_TRUE(network_view != NULL);
- EXPECT_FALSE(network_view->IsContinueEnabled());
EXPECT_CALL(*mock_network_library_, ethernet_connected())
.WillOnce((Return(false)));
@@ -215,23 +187,26 @@ IN_PROC_BROWSER_TEST_F(NetworkScreenTest, Wifi) {
.WillOnce((Return(false)));
EXPECT_CALL(*mock_network_library_, wifi_connecting())
.WillOnce((Return(true)));
- scoped_ptr<WifiNetwork> wifi(new WifiNetwork());
+ WifiNetwork wifi;
+ WifiNetworkVector wifi_networks;
+ wifi_networks.push_back(&wifi);
EXPECT_CALL(*mock_network_library_, wifi_network())
- .WillOnce(Return(wifi.get()));
-
- network_screen->OnNetworkManagerChanged(mock_network_library_);
+ .WillRepeatedly(Return(&wifi));
+ EXPECT_CALL(*mock_network_library_, wifi_networks())
+ .WillRepeatedly(ReturnRef(wifi_networks));
EXPECT_FALSE(network_view->IsContinueEnabled());
- EXPECT_FALSE(network_view->IsConnecting());
+ network_screen->OnNetworkManagerChanged(mock_network_library_);
EXPECT_CALL(*mock_network_library_, ethernet_connected())
.WillOnce(Return(true));
EXPECT_CALL(*mock_network_library_, Connected())
.Times(2)
.WillRepeatedly(Return(true));
-
+ EXPECT_FALSE(network_view->IsContinueEnabled());
+ EXPECT_FALSE(network_view->IsConnecting());
network_screen->OnNetworkManagerChanged(mock_network_library_);
- EXPECT_TRUE(network_view->IsContinueEnabled());
+ EXPECT_TRUE(network_view->IsContinueEnabled());
EmulateContinueButtonExit(network_screen);
}
@@ -243,7 +218,6 @@ IN_PROC_BROWSER_TEST_F(NetworkScreenTest, Cellular) {
NetworkSelectionView* network_view = network_screen->view();
ASSERT_TRUE(network_view != NULL);
- EXPECT_FALSE(network_view->IsContinueEnabled());
EXPECT_CALL(*mock_network_library_, ethernet_connected())
.WillOnce((Return(false)));
@@ -260,20 +234,19 @@ IN_PROC_BROWSER_TEST_F(NetworkScreenTest, Cellular) {
scoped_ptr<CellularNetwork> cellular(new CellularNetwork());
EXPECT_CALL(*mock_network_library_, cellular_network())
.WillOnce(Return(cellular.get()));
-
- network_screen->OnNetworkManagerChanged(mock_network_library_);
EXPECT_FALSE(network_view->IsContinueEnabled());
- EXPECT_FALSE(network_view->IsConnecting());
+ network_screen->OnNetworkManagerChanged(mock_network_library_);
EXPECT_CALL(*mock_network_library_, ethernet_connected())
.WillOnce(Return(true));
EXPECT_CALL(*mock_network_library_, Connected())
.Times(2)
.WillRepeatedly(Return(true));
-
+ EXPECT_FALSE(network_view->IsContinueEnabled());
+ EXPECT_FALSE(network_view->IsConnecting());
network_screen->OnNetworkManagerChanged(mock_network_library_);
- EXPECT_TRUE(network_view->IsContinueEnabled());
+ EXPECT_TRUE(network_view->IsContinueEnabled());
EmulateContinueButtonExit(network_screen);
}
@@ -285,7 +258,6 @@ IN_PROC_BROWSER_TEST_F(NetworkScreenTest, Timeout) {
NetworkSelectionView* network_view = network_screen->view();
ASSERT_TRUE(network_view != NULL);
- EXPECT_FALSE(network_view->IsContinueEnabled());
EXPECT_CALL(*mock_network_library_, ethernet_connected())
.WillOnce((Return(false)));
@@ -300,19 +272,19 @@ IN_PROC_BROWSER_TEST_F(NetworkScreenTest, Timeout) {
scoped_ptr<WifiNetwork> wifi(new WifiNetwork());
EXPECT_CALL(*mock_network_library_, wifi_network())
.WillOnce(Return(wifi.get()));
+ EXPECT_FALSE(network_view->IsContinueEnabled());
+ network_screen->OnNetworkManagerChanged(mock_network_library_);
+
EXPECT_CALL(*mock_network_library_, Connected())
- .Times(3)
+ .Times(2)
.WillRepeatedly(Return(false));
-
- network_screen->OnNetworkManagerChanged(mock_network_library_);
EXPECT_FALSE(network_view->IsContinueEnabled());
EXPECT_FALSE(network_view->IsConnecting());
-
network_screen->OnConnectionTimeout();
+
+ // Close infobubble with error message - it makes the test stable.
EXPECT_FALSE(network_view->IsContinueEnabled());
EXPECT_FALSE(network_view->IsConnecting());
-
- // Close infobubble with error message - it makes test stable.
network_screen->ClearErrors();
}
diff --git a/chrome/browser/chromeos/login/new_user_view.cc b/chrome/browser/chromeos/login/new_user_view.cc
index 5bdf8ad..d340a0b 100644
--- a/chrome/browser/chromeos/login/new_user_view.cc
+++ b/chrome/browser/chromeos/login/new_user_view.cc
@@ -20,7 +20,6 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
-#include "chrome/browser/chromeos/login/helper.h"
#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
#include "chrome/browser/chromeos/login/textfield_with_margin.h"
#include "chrome/browser/chromeos/login/wizard_accessibility_helper.h"
@@ -59,7 +58,8 @@ const char kDefaultDomain[] = "@gmail.com";
// username doesn't have full domain.
class UsernameField : public chromeos::TextfieldWithMargin {
public:
- UsernameField() {}
+ explicit UsernameField(chromeos::NewUserView* controller)
+ : controller_(controller) {}
// views::Textfield overrides:
virtual void WillLoseFocus() {
@@ -73,6 +73,16 @@ class UsernameField : public chromeos::TextfieldWithMargin {
}
}
+ // Overridden from views::View:
+ virtual bool OnKeyPressed(const views::KeyEvent& e) {
+ if (e.GetKeyCode() == app::VKEY_LEFT) {
+ return controller_->NavigateAway();
+ }
+ return false;
+ }
+
+ private:
+ chromeos::NewUserView* controller_;
DISALLOW_COPY_AND_ASSIGN(UsernameField);
};
@@ -95,12 +105,11 @@ NewUserView::NewUserView(Delegate* delegate,
create_account_link_(NULL),
guest_link_(NULL),
languages_menubutton_(NULL),
- throbber_(NULL),
accel_focus_pass_(views::Accelerator(app::VKEY_P, false, false, true)),
accel_focus_user_(views::Accelerator(app::VKEY_U, false, false, true)),
accel_login_off_the_record_(
views::Accelerator(app::VKEY_B, false, false, true)),
- accel_enable_accessibility_(WizardAccessibilityHelper::GetAccelerator()),
+ accel_toggle_accessibility_(WizardAccessibilityHelper::GetAccelerator()),
delegate_(delegate),
ALLOW_THIS_IN_INITIALIZER_LIST(focus_grabber_factory_(this)),
focus_delayed_(false),
@@ -150,19 +159,16 @@ void NewUserView::Init() {
splitter_down1_ = CreateSplitter(kSplitterDown1Color);
splitter_down2_ = CreateSplitter(kSplitterDown2Color);
- username_field_ = new UsernameField();
- CorrectTextfieldFontSize(username_field_);
+ username_field_ = new UsernameField(this);
username_field_->set_background(new CopyBackground(this));
+ username_field_->SetAccessibleName(
+ ASCIIToWide(l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_USERNAME_LABEL)));
AddChildView(username_field_);
password_field_ = new TextfieldWithMargin(views::Textfield::STYLE_PASSWORD);
- CorrectTextfieldFontSize(password_field_);
password_field_->set_background(new CopyBackground(this));
AddChildView(password_field_);
- throbber_ = CreateDefaultSmoothedThrobber();
- AddChildView(throbber_);
-
language_switch_menu_.InitLanguageMenu();
RecreatePeculiarControls();
@@ -180,7 +186,7 @@ void NewUserView::Init() {
AddAccelerator(accel_focus_user_);
AddAccelerator(accel_focus_pass_);
AddAccelerator(accel_login_off_the_record_);
- AddAccelerator(accel_enable_accessibility_);
+ AddAccelerator(accel_toggle_accessibility_);
OnLocaleChanged();
@@ -203,8 +209,8 @@ bool NewUserView::AcceleratorPressed(const views::Accelerator& accelerator) {
password_field_->RequestFocus();
} else if (accelerator == accel_login_off_the_record_) {
delegate_->OnLoginOffTheRecord();
- } else if (accelerator == accel_enable_accessibility_) {
- WizardAccessibilityHelper::GetInstance()->EnableAccessibility(this);
+ } else if (accelerator == accel_toggle_accessibility_) {
+ WizardAccessibilityHelper::GetInstance()->ToggleAccessibility(this);
} else {
return false;
}
@@ -419,15 +425,8 @@ void NewUserView::Layout() {
y += setViewBounds(username_field_, x, y, width, true) + kRowPad;
y += setViewBounds(password_field_, x, y, width, true) + kRowPad;
- int throbber_y = y;
int sign_in_button_width = sign_in_button_->GetPreferredSize().width();
setViewBounds(sign_in_button_, x, y, sign_in_button_width,true);
- setViewBounds(throbber_,
- x + width - throbber_->GetPreferredSize().width(),
- throbber_y + (sign_in_button_->GetPreferredSize().height() -
- throbber_->GetPreferredSize().height()) / 2,
- width,
- false);
SchedulePaint();
}
@@ -450,9 +449,7 @@ void NewUserView::Login() {
if (login_in_process_ || username_field_->text().empty())
return;
- StartThrobber();
login_in_process_ = true;
- EnableInputControls(false);
std::string username = UTF16ToUTF8(username_field_->text());
// todo(cmasone) Need to sanitize memory used to store password.
std::string password = UTF16ToUTF8(password_field_->text());
@@ -480,37 +477,42 @@ void NewUserView::LinkActivated(views::Link* source, int event_flags) {
}
}
-void NewUserView::ClearAndEnablePassword() {
+void NewUserView::ClearAndFocusControls() {
login_in_process_ = false;
- EnableInputControls(true);
+ SetUsername(std::string());
SetPassword(std::string());
- password_field_->RequestFocus();
- StopThrobber();
+ username_field_->RequestFocus();
}
-void NewUserView::ClearAndEnableFields() {
+void NewUserView::ClearAndFocusPassword() {
login_in_process_ = false;
- EnableInputControls(true);
- SetUsername(std::string());
SetPassword(std::string());
- username_field_->RequestFocus();
- StopThrobber();
+ password_field_->RequestFocus();
}
-gfx::Rect NewUserView::GetPasswordBounds() const {
- return password_field_->GetScreenBounds();
+gfx::Rect NewUserView::GetMainInputScreenBounds() const {
+ return GetUsernameBounds();
}
-gfx::Rect NewUserView::GetUsernameBounds() const {
- return username_field_->GetScreenBounds();
+gfx::Rect NewUserView::CalculateThrobberBounds(views::Throbber* throbber) {
+ DCHECK(password_field_);
+ DCHECK(sign_in_button_);
+
+ gfx::Size throbber_size = throbber->GetPreferredSize();
+ int x = password_field_->x();
+ x += password_field_->width() - throbber_size.width();
+ int y = sign_in_button_->y();
+ y += (sign_in_button_->height() - throbber_size.height()) / 2;
+
+ return gfx::Rect(gfx::Point(x, y), throbber_size);
}
-void NewUserView::StartThrobber() {
- throbber_->Start();
+gfx::Rect NewUserView::GetPasswordBounds() const {
+ return password_field_->GetScreenBounds();
}
-void NewUserView::StopThrobber() {
- throbber_->Stop();
+gfx::Rect NewUserView::GetUsernameBounds() const {
+ return username_field_->GetScreenBounds();
}
bool NewUserView::HandleKeystroke(views::Textfield* s,
@@ -519,16 +521,10 @@ bool NewUserView::HandleKeystroke(views::Textfield* s,
return false;
if (keystroke.GetKeyboardCode() == app::VKEY_RETURN) {
- Login();
+ if (!username_field_->text().empty() && !password_field_->text().empty())
+ Login();
// Return true so that processing ends
return true;
- } else if (keystroke.GetKeyboardCode() == app::VKEY_LEFT) {
- if (s == username_field_ &&
- username_field_->text().empty() &&
- password_field_->text().empty()) {
- delegate_->NavigateAway();
- return true;
- }
}
delegate_->ClearErrors();
// Return false so that processing does not end
@@ -551,7 +547,16 @@ void NewUserView::EnableInputControls(bool enabled) {
if (need_guest_link_) {
guest_link_->SetEnabled(enabled);
}
- delegate_->SetStatusAreaEnabled(enabled);
+}
+
+bool NewUserView::NavigateAway() {
+ if (username_field_->text().empty() &&
+ password_field_->text().empty()) {
+ delegate_->NavigateAway();
+ return true;
+ } else {
+ return false;
+ }
}
void NewUserView::InitLink(views::Link** link) {
diff --git a/chrome/browser/chromeos/login/new_user_view.h b/chrome/browser/chromeos/login/new_user_view.h
index bfeed4e..ee0fd99 100644
--- a/chrome/browser/chromeos/login/new_user_view.h
+++ b/chrome/browser/chromeos/login/new_user_view.h
@@ -9,7 +9,9 @@
#include <string>
#include "base/task.h"
+#include "chrome/browser/chromeos/login/helper.h"
#include "chrome/browser/chromeos/login/language_switch_menu.h"
+#include "chrome/browser/chromeos/login/user_input.h"
#include "views/accelerator.h"
#include "views/controls/button/button.h"
#include "views/controls/button/menu_button.h"
@@ -20,14 +22,14 @@
namespace views {
class Label;
class NativeButton;
-class Throbber;
} // namespace views
namespace chromeos {
// View that is used for new user login. It asks for username and password,
// allows to specify language preferences or initiate new account creation.
-class NewUserView : public views::View,
+class NewUserView : public ThrobberHostView,
+ public UserInput,
public views::Textfield::Controller,
public views::LinkController,
public views::ButtonListener {
@@ -73,18 +75,6 @@ class NewUserView : public views::View,
// Update strings from the resources. Executed on language change.
void UpdateLocalizedStrings();
- // Resets password text and sets the enabled state of the password.
- void ClearAndEnablePassword();
-
- // Resets password and username text and focuses on username.
- void ClearAndEnableFields();
-
- // Starts throbber shown during login.
- void StartThrobber();
-
- // Stops throbber shown during login.
- void StopThrobber();
-
// Returns bounds of password field in screen coordinates.
gfx::Rect GetPasswordBounds() const;
@@ -115,9 +105,21 @@ class NewUserView : public views::View,
// Overridden from views::LinkController.
virtual void LinkActivated(views::Link* source, int event_flags);
-
virtual bool AcceleratorPressed(const views::Accelerator& accelerator);
+ // Overridden from ThrobberHostView:
+ virtual gfx::Rect CalculateThrobberBounds(views::Throbber* throbber);
+
+ // Overridden from UserInput:
+ virtual void EnableInputControls(bool enabled);
+ virtual void ClearAndFocusControls();
+ virtual void ClearAndFocusPassword();
+ virtual gfx::Rect GetMainInputScreenBounds() const;
+
+ // Navigates "away" to other user pods if allowed.
+ // Returns true if event has been processed.
+ bool NavigateAway();
+
protected:
// views::View overrides:
virtual void ViewHierarchyChanged(bool is_add,
@@ -130,8 +132,6 @@ class NewUserView : public views::View,
void AddChildView(View* view);
private:
- // Enables/disables input controls (textfields, buttons).
- void EnableInputControls(bool enabled);
void FocusFirstField();
// Creates Link control and adds it as a child.
@@ -165,12 +165,11 @@ class NewUserView : public views::View,
views::Link* create_account_link_;
views::Link* guest_link_;
views::MenuButton* languages_menubutton_;
- views::Throbber* throbber_;
views::Accelerator accel_focus_pass_;
views::Accelerator accel_focus_user_;
views::Accelerator accel_login_off_the_record_;
- views::Accelerator accel_enable_accessibility_;
+ views::Accelerator accel_toggle_accessibility_;
// Notifications receiver.
Delegate* delegate_;
diff --git a/chrome/browser/chromeos/login/online_attempt.cc b/chrome/browser/chromeos/login/online_attempt.cc
index 597e3e3..2b891bd 100644
--- a/chrome/browser/chromeos/login/online_attempt.cc
+++ b/chrome/browser/chromeos/login/online_attempt.cc
@@ -12,8 +12,8 @@
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/login/auth_attempt_state.h"
#include "chrome/browser/chromeos/login/auth_attempt_state_resolver.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/common/net/gaia/gaia_auth_consumer.h"
#include "chrome/common/net/gaia/gaia_auth_fetcher.h"
#include "chrome/common/net/gaia/gaia_constants.h"
diff --git a/chrome/browser/chromeos/login/online_attempt.h b/chrome/browser/chromeos/login/online_attempt.h
index ed1b447..f91c468 100644
--- a/chrome/browser/chromeos/login/online_attempt.h
+++ b/chrome/browser/chromeos/login/online_attempt.h
@@ -11,11 +11,11 @@
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/chromeos/login/login_status_consumer.h"
#include "chrome/common/net/gaia/gaia_auth_consumer.h"
#include "chrome/common/net/gaia/google_service_auth_error.h"
+class CancelableTask;
class GaiaAuthFetcher;
class Profile;
diff --git a/chrome/browser/chromeos/login/online_attempt_unittest.cc b/chrome/browser/chromeos/login/online_attempt_unittest.cc
index 5ab89c2..9e03a05 100644
--- a/chrome/browser/chromeos/login/online_attempt_unittest.cc
+++ b/chrome/browser/chromeos/login/online_attempt_unittest.cc
@@ -137,7 +137,7 @@ TEST_F(OnlineAttemptTest, LoginCancelRetry) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableFunction(&OnlineAttemptTest::RunThreadTest,
- attempt_.get(), &profile));
+ attempt_, &profile));
MessageLoop::current()->Run();
@@ -164,7 +164,7 @@ TEST_F(OnlineAttemptTest, LoginTimeout) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableFunction(&OnlineAttemptTest::RunThreadTest,
- attempt_.get(), &profile));
+ attempt_, &profile));
// Post a task to cancel the login attempt.
CancelLogin(attempt_.get());
@@ -195,7 +195,7 @@ TEST_F(OnlineAttemptTest, HostedLoginRejected) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableFunction(&OnlineAttemptTest::RunThreadTest,
- attempt_.get(), &profile));
+ attempt_, &profile));
MessageLoop::current()->Run();
@@ -221,7 +221,7 @@ TEST_F(OnlineAttemptTest, FullLogin) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableFunction(&OnlineAttemptTest::RunThreadTest,
- attempt_.get(), &profile));
+ attempt_, &profile));
MessageLoop::current()->Run();
diff --git a/chrome/browser/chromeos/login/owner_key_utils.cc b/chrome/browser/chromeos/login/owner_key_utils.cc
index 3016561..a47722c 100644
--- a/chrome/browser/chromeos/login/owner_key_utils.cc
+++ b/chrome/browser/chromeos/login/owner_key_utils.cc
@@ -4,12 +4,6 @@
#include "chrome/browser/chromeos/login/owner_key_utils.h"
-#include <keyhi.h> // SECKEY_CreateSubjectPublicKeyInfo()
-#include <pk11pub.h>
-#include <prerror.h> // PR_GetError()
-#include <secder.h> // DER_Encode()
-#include <secmod.h>
-
#include <limits>
#include "base/crypto/rsa_private_key.h"
@@ -18,8 +12,6 @@
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
-#include "base/nss_util.h"
-#include "base/nss_util_internal.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
@@ -99,10 +91,7 @@ const char OwnerKeyUtilsImpl::kOwnerKeyFile[] = "/var/lib/whitelist/owner.key";
// static
const uint16 OwnerKeyUtilsImpl::kKeySizeInBits = 2048;
-OwnerKeyUtilsImpl::OwnerKeyUtilsImpl() {
- // Ensure NSS is initialized.
- base::EnsureNSSInit();
-}
+OwnerKeyUtilsImpl::OwnerKeyUtilsImpl() {}
OwnerKeyUtilsImpl::~OwnerKeyUtilsImpl() {}
diff --git a/chrome/browser/chromeos/login/owner_manager.cc b/chrome/browser/chromeos/login/owner_manager.cc
index 71b15a8..389d0a8 100644
--- a/chrome/browser/chromeos/login/owner_manager.cc
+++ b/chrome/browser/chromeos/login/owner_manager.cc
@@ -73,8 +73,16 @@ void OwnerManager::GenerateKeysAndExportPublic() {
}
void OwnerManager::ExportKey() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
VLOG(1) << "Exporting public key";
- if (!utils_->ExportPublicKeyViaDbus(private_key_.get(), this)) {
+ if (utils_->ExportPublicKeyViaDbus(private_key_.get(), this)) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(this,
+ &OwnerManager::SendNotification,
+ NotificationType::OWNERSHIP_TAKEN,
+ NotificationService::NoDetails()));
+ } else {
private_key_.reset(NULL);
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
diff --git a/chrome/browser/chromeos/login/owner_manager_unittest.h b/chrome/browser/chromeos/login/owner_manager_unittest.h
index a3609d6..6d72247 100644
--- a/chrome/browser/chromeos/login/owner_manager_unittest.h
+++ b/chrome/browser/chromeos/login/owner_manager_unittest.h
@@ -8,11 +8,11 @@
#include "chrome/browser/chromeos/login/owner_manager.h"
#include <string>
+#include <vector>
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
diff --git a/chrome/browser/chromeos/login/ownership_service.cc b/chrome/browser/chromeos/login/ownership_service.cc
index 945ab77..c256e96 100644
--- a/chrome/browser/chromeos/login/ownership_service.cc
+++ b/chrome/browser/chromeos/login/ownership_service.cc
@@ -6,13 +6,17 @@
#include "base/file_path.h"
#include "base/file_util.h"
+#include "base/lazy_instance.h"
#include "chrome/browser/browser_thread.h"
namespace chromeos {
+static base::LazyInstance<OwnershipService> g_ownership_service(
+ base::LINKER_INITIALIZED);
+
// static
OwnershipService* OwnershipService::GetSharedInstance() {
- return Singleton<OwnershipService>::get();
+ return g_ownership_service.Pointer();
}
OwnershipService::OwnershipService()
diff --git a/chrome/browser/chromeos/login/ownership_service.h b/chrome/browser/chromeos/login/ownership_service.h
index 4f8227d..bc407d9 100644
--- a/chrome/browser/chromeos/login/ownership_service.h
+++ b/chrome/browser/chromeos/login/ownership_service.h
@@ -9,10 +9,13 @@
#include <string>
#include <vector>
-#include "base/singleton.h"
#include "chrome/browser/chromeos/login/owner_key_utils.h"
#include "chrome/browser/chromeos/login/owner_manager.h"
+namespace base {
+template <typename T> struct DefaultLazyInstanceTraits;
+}
+
namespace chromeos {
class OwnershipService {
@@ -69,7 +72,7 @@ class OwnershipService {
OwnershipService();
private:
- friend struct DefaultSingletonTraits<OwnershipService>;
+ friend struct base::DefaultLazyInstanceTraits<OwnershipService>;
friend class OwnershipServiceTest;
scoped_refptr<OwnerManager> manager_;
diff --git a/chrome/browser/chromeos/login/parallel_authenticator.cc b/chrome/browser/chromeos/login/parallel_authenticator.cc
index ec499fb..9cb025c 100644
--- a/chrome/browser/chromeos/login/parallel_authenticator.cc
+++ b/chrome/browser/chromeos/login/parallel_authenticator.cc
@@ -16,7 +16,6 @@
#include "base/string_util.h"
#include "base/third_party/nss/blapi.h"
#include "base/third_party/nss/sha256.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/chromeos/cros/cryptohome_library.h"
#include "chrome/browser/chromeos/login/auth_response_handler.h"
@@ -24,8 +23,8 @@
#include "chrome/browser/chromeos/login/login_status_consumer.h"
#include "chrome/browser/chromeos/login/ownership_service.h"
#include "chrome/browser/chromeos/login/user_manager.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/net/gaia/gaia_auth_fetcher.h"
#include "chrome/common/net/gaia/gaia_constants.h"
@@ -132,7 +131,7 @@ void ParallelAuthenticator::OnLoginSuccess(
const GaiaAuthConsumer::ClientLoginResult& credentials,
bool request_pending) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- VLOG(1) << "Online login success";
+ VLOG(1) << "Login success";
// Send notification of success
AuthenticationNotificationDetails details(true);
NotificationService::current()->Notify(
@@ -169,7 +168,7 @@ void ParallelAuthenticator::OnPasswordChangeDetected(
void ParallelAuthenticator::CheckLocalaccount(const LoginFailure& error) {
{
AutoLock for_this_block(localaccount_lock_);
- VLOG(1) << "Checking localaccount";
+ VLOG(2) << "Checking localaccount";
if (!checked_for_localaccount_) {
BrowserThread::PostDelayedTask(
BrowserThread::FILE, FROM_HERE,
@@ -227,7 +226,7 @@ void ParallelAuthenticator::RecoverEncryptedData(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(this,
&ParallelAuthenticator::ResyncRecoverHelper,
- key_migrator_.get()));
+ key_migrator_));
}
void ParallelAuthenticator::ResyncEncryptedData(
@@ -238,7 +237,7 @@ void ParallelAuthenticator::ResyncEncryptedData(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(this,
&ParallelAuthenticator::ResyncRecoverHelper,
- data_remover_.get()));
+ data_remover_));
}
void ParallelAuthenticator::ResyncRecoverHelper(CryptohomeOp* to_initiate) {
@@ -273,7 +272,9 @@ void ParallelAuthenticator::Resolve() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
bool request_pending = false;
bool create = false;
- switch (ResolveState()) {
+ ParallelAuthenticator::AuthState state = ResolveState();
+ VLOG(1) << "Resolved state to: " << state;
+ switch (state) {
case CONTINUE:
case POSSIBLE_PW_CHANGE:
case NO_MOUNT:
@@ -364,11 +365,13 @@ void ParallelAuthenticator::Resolve() {
NewRunnableMethod(key_migrator_.get(), &CryptohomeOp::Initiate));
break;
case OFFLINE_LOGIN:
+ VLOG(2) << "Offline login";
request_pending = !current_state_->online_complete();
// Fall through.
case UNLOCK:
// Fall through.
case ONLINE_LOGIN:
+ VLOG(2) << "Online login";
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
NewRunnableMethod(this, &ParallelAuthenticator::OnLoginSuccess,
@@ -553,7 +556,7 @@ void ParallelAuthenticator::LoadLocalaccount(const std::string& filename) {
std::string localaccount;
if (PathService::Get(base::DIR_EXE, &localaccount_file)) {
localaccount_file = localaccount_file.Append(filename);
- VLOG(1) << "Looking for localaccount in " << localaccount_file.value();
+ VLOG(2) << "Looking for localaccount in " << localaccount_file.value();
ReadFileToString(localaccount_file, &localaccount);
TrimWhitespaceASCII(localaccount, TRIM_TRAILING, &localaccount);
diff --git a/chrome/browser/chromeos/login/password_changed_view.cc b/chrome/browser/chromeos/login/password_changed_view.cc
index 22f953f..5a1d2d0 100644
--- a/chrome/browser/chromeos/login/password_changed_view.cc
+++ b/chrome/browser/chromeos/login/password_changed_view.cc
@@ -183,14 +183,4 @@ void PasswordChangedView::ButtonPressed(Button* sender,
}
}
-bool PasswordChangedView::HandleKeystroke(views::Textfield* s,
- const views::Textfield::Keystroke& keystroke) {
- if (keystroke.GetKeyboardCode() == app::VKEY_RETURN) {
- ExitDialog();
- return true;
- }
-
- return false;
-}
-
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/password_changed_view.h b/chrome/browser/chromeos/login/password_changed_view.h
index b7d45da..706e53b 100644
--- a/chrome/browser/chromeos/login/password_changed_view.h
+++ b/chrome/browser/chromeos/login/password_changed_view.h
@@ -63,7 +63,9 @@ class PasswordChangedView : public views::View,
// views::Textfield::Controller overrides:
virtual bool HandleKeystroke(views::Textfield* sender,
- const views::Textfield::Keystroke& keystroke);
+ const views::Textfield::Keystroke& keystroke) {
+ return false;
+ }
virtual void ContentsChanged(views::Textfield* sender,
const string16& new_contents) {}
diff --git a/chrome/browser/chromeos/login/registration_screen.cc b/chrome/browser/chromeos/login/registration_screen.cc
index 6676d97..2cc4325 100644
--- a/chrome/browser/chromeos/login/registration_screen.cc
+++ b/chrome/browser/chromeos/login/registration_screen.cc
@@ -9,7 +9,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/child_process_security_policy.h"
#include "chrome/browser/chromeos/input_method/input_method_util.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/tab_contents/tab_contents.h"
@@ -142,10 +142,10 @@ void RegistrationScreen::CloseScreen(ScreenObserver::ExitCodes code) {
}
// static
-URLRequestJob* RegistrationScreen::Factory(URLRequest* request,
- const std::string& scheme) {
+net::URLRequestJob* RegistrationScreen::Factory(net::URLRequest* request,
+ const std::string& scheme) {
VLOG(1) << "Handling url: " << request->url().spec().c_str();
- return new URLRequestAboutJob(request);
+ return new net::URLRequestAboutJob(request);
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/rounded_view.h b/chrome/browser/chromeos/login/rounded_view.h
new file mode 100644
index 0000000..09877ba
--- /dev/null
+++ b/chrome/browser/chromeos/login/rounded_view.h
@@ -0,0 +1,131 @@
+// 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_ROUNDED_VIEW_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_ROUNDED_VIEW_H_
+
+#include "gfx/canvas.h"
+#include "gfx/canvas_skia.h"
+#include "gfx/rect.h"
+
+namespace chromeos {
+
+namespace rounded_view {
+
+// Corner radius of the RoundedView.
+const SkScalar kCornerRadius = SkIntToScalar(5);
+
+// Stroke width to be used by the RoundedView.
+const SkScalar kStrokeWidth = SkIntToScalar(1);
+
+// Color of the inner frame of the RoundedView.
+const SkColor kInnerFrameColor = SK_ColorWHITE;
+
+// Color of the outer frame of the RoundedView.
+const SkColor kOuterFrameColor = 0xFF555555;
+
+} // namespace rounded_view
+
+// Class that sets up the round rectangle as a clip region of the view.
+// |C| - class inherited from |views::View|.
+template<typename C>
+class RoundedView: public C {
+ public:
+ // Empty constructor.
+ RoundedView() {}
+
+ // One argument constructor.
+ template<typename D>
+ explicit RoundedView(const D &value) : C(value) {}
+
+ // Overrides views::View.
+ virtual void ProcessPaint(gfx::Canvas* canvas);
+
+ protected:
+ // Returns the path that will be used for a clip.
+ virtual SkPath GetClipPath() const;
+
+ // Returns maximal rectangle in the view.
+ virtual SkRect GetViewRect() const;
+
+ // Draws custom frame for the view.
+ virtual void DrawFrame(gfx::Canvas* canvas);
+};
+
+// RoundedView implementation.
+
+template <typename C>
+void RoundedView<C>::ProcessPaint(gfx::Canvas* canvas) {
+ // Setup clip region.
+ canvas->Save();
+ canvas->AsCanvasSkia()->clipPath(GetClipPath());
+ // Do original painting.
+ C::ProcessPaint(canvas);
+ canvas->Restore();
+ // Add frame.
+ DrawFrame(canvas);
+}
+
+template <typename C>
+SkPath RoundedView<C>::GetClipPath() const {
+ SkPath round_view;
+ SkRect view_rect = GetViewRect();
+ view_rect.inset(2 * rounded_view::kStrokeWidth,
+ 2 * rounded_view::kStrokeWidth);
+ // 3 is used instead of 2 to avoid empty points between the clip and
+ // the frame.
+ round_view.addRoundRect(
+ view_rect,
+ rounded_view::kCornerRadius - 3 * rounded_view::kStrokeWidth,
+ rounded_view::kCornerRadius - 3 * rounded_view::kStrokeWidth);
+
+ return round_view;
+}
+
+template <typename C>
+SkRect RoundedView<C>::GetViewRect() const {
+ SkRect view_rect;
+ view_rect.iset(this->x(),
+ this->y(),
+ this->x() + this->width(),
+ this->y() + this->height());
+ return view_rect;
+}
+
+template <typename C>
+void RoundedView<C>::DrawFrame(gfx::Canvas* canvas) {
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(rounded_view::kStrokeWidth);
+ paint.setAntiAlias(true);
+ SkRect view_rect = GetViewRect();
+
+ // Used to make nested rounded rects look better.
+ const SkScalar kOriginShift = 1.0;
+ const SkScalar kDelta = 0.3;
+
+ // Draw inner frame.
+ view_rect.fLeft -= kOriginShift;
+ view_rect.fTop -= kOriginShift;
+ view_rect.inset(rounded_view::kStrokeWidth, rounded_view::kStrokeWidth);
+ paint.setColor(rounded_view::kInnerFrameColor);
+ canvas->AsCanvasSkia()->
+ drawRoundRect(view_rect,
+ rounded_view::kCornerRadius - rounded_view::kStrokeWidth,
+ rounded_view::kCornerRadius - rounded_view::kStrokeWidth,
+ paint);
+
+ // Draw outer frame.
+ view_rect.fLeft -= kDelta;
+ view_rect.fTop -= kDelta;
+ view_rect.offset(rounded_view::kStrokeWidth - kDelta,
+ rounded_view::kStrokeWidth - kDelta);
+ paint.setColor(rounded_view::kOuterFrameColor);
+ canvas->AsCanvasSkia()->drawRoundRect(view_rect, rounded_view::kCornerRadius,
+ rounded_view::kCornerRadius, paint);
+}
+
+}
+
+#endif // CHROME_BROWSER_CHROMEOS_LOGIN_ROUNDED_VIEW_H_
diff --git a/chrome/browser/chromeos/login/screen_lock_view.cc b/chrome/browser/chromeos/login/screen_lock_view.cc
index 883498a..7b3f4ea 100644
--- a/chrome/browser/chromeos/login/screen_lock_view.cc
+++ b/chrome/browser/chromeos/login/screen_lock_view.cc
@@ -7,7 +7,6 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/chromeos/login/helper.h"
#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
#include "chrome/browser/chromeos/login/screen_locker.h"
#include "chrome/browser/chromeos/login/user_manager.h"
@@ -16,7 +15,7 @@
#include "chrome/browser/chromeos/login/wizard_accessibility_helper.h"
#include "chrome/browser/chromeos/login/textfield_with_margin.h"
#include "chrome/browser/chromeos/views/copy_background.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/common/notification_service.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
@@ -40,7 +39,7 @@ class PasswordField : public TextfieldWithMargin {
PasswordField()
: TextfieldWithMargin(views::Textfield::STYLE_PASSWORD) {
set_text_to_display_when_empty(
- l10n_util::GetStringUTF16(IDS_LOGIN_EMPTY_PASSWORD_TEXT));
+ l10n_util::GetStringUTF16(IDS_LOGIN_POD_EMPTY_PASSWORD_TEXT));
}
// views::View overrides.
@@ -67,6 +66,9 @@ ScreenLockView::ScreenLockView(ScreenLocker* screen_locker)
DCHECK(screen_locker_);
}
+ScreenLockView::~ScreenLockView() {
+}
+
gfx::Size ScreenLockView::GetPreferredSize() {
return main_->GetPreferredSize();
}
@@ -100,9 +102,13 @@ void ScreenLockView::Init() {
// Password field.
password_field_ = new PasswordField();
+
password_field_->SetController(this);
password_field_->set_background(new CopyBackground(main_));
+ // Setup ThrobberView's host view.
+ set_host_view(password_field_);
+
// User icon.
UserManager::User user = screen_locker_->user();
user_view_->SetImage(user.image(), user.image());
@@ -123,10 +129,10 @@ void ScreenLockView::Init() {
column_set->AddPaddingColumn(0, kBorderSize);
column_set = layout->AddColumnSet(1);
- column_set->AddPaddingColumn(0, 5);
+ column_set->AddPaddingColumn(0, kBorderSize);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
GridLayout::USE_PREF, 0, 0);
- column_set->AddPaddingColumn(0, 5);
+ column_set->AddPaddingColumn(0, kBorderSize);
layout->AddPaddingRow(0, kBorderSize);
layout->StartRow(0, 0);
@@ -138,7 +144,7 @@ void ScreenLockView::Init() {
AddChildView(main_);
- UsernameView* username = new UsernameView(text);
+ UsernameView* username = UsernameView::CreateShapedUsernameView(text, false);
username_ = username;
username->SetColor(login::kTextColor);
username->SetFont(font);
@@ -160,11 +166,11 @@ gfx::Rect ScreenLockView::GetPasswordBoundsRelativeTo(const views::View* view) {
return gfx::Rect(p, size());
}
+
void ScreenLockView::SetEnabled(bool enabled) {
views::View::SetEnabled(enabled);
if (!enabled) {
- user_view_->StartThrobber();
// TODO(oshima): Re-enabling does not move the focus to the view
// that had a focus (issue http://crbug.com/43131).
// Clear focus on the textfield so that re-enabling can set focus
@@ -173,8 +179,6 @@ void ScreenLockView::SetEnabled(bool enabled) {
// associated Widget yet.
if (password_field_->GetFocusManager())
password_field_->GetFocusManager()->ClearFocus();
- } else {
- user_view_->StopThrobber();
}
password_field_->SetEnabled(enabled);
}
@@ -213,4 +217,5 @@ void ScreenLockView::ViewHierarchyChanged(bool is_add,
if (is_add && this == child)
WizardAccessibilityHelper::GetInstance()->MaybeEnableAccessibility(this);
}
+
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screen_lock_view.h b/chrome/browser/chromeos/login/screen_lock_view.h
index 9ceefd1..1e3916e 100644
--- a/chrome/browser/chromeos/login/screen_lock_view.h
+++ b/chrome/browser/chromeos/login/screen_lock_view.h
@@ -6,6 +6,7 @@
#define CHROME_BROWSER_CHROMEOS_LOGIN_SCREEN_LOCK_VIEW_H_
#pragma once
+#include "chrome/browser/chromeos/login/helper.h"
#include "chrome/browser/chromeos/login/user_view.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
@@ -27,13 +28,13 @@ class ScreenLockerTester;
// ScreenLockView creates view components necessary to authenticate
// a user to unlock the screen.
-class ScreenLockView : public views::View,
+class ScreenLockView : public ThrobberHostView,
public views::Textfield::Controller,
public NotificationObserver,
public UserView::Delegate {
public:
explicit ScreenLockView(ScreenLocker* screen_locker);
- virtual ~ScreenLockView() {}
+ virtual ~ScreenLockView();
void Init();
diff --git a/chrome/browser/chromeos/login/screen_locker.cc b/chrome/browser/chromeos/login/screen_locker.cc
index 87a28dd..0a3ef83 100644
--- a/chrome/browser/chromeos/login/screen_locker.cc
+++ b/chrome/browser/chromeos/login/screen_locker.cc
@@ -16,9 +16,9 @@
#include "app/resource_bundle.h"
#include "app/x11_util.h"
#include "base/command_line.h"
+#include "base/lazy_instance.h"
#include "base/metrics/histogram.h"
#include "base/message_loop.h"
-#include "base/singleton.h"
#include "base/string_util.h"
#include "base/timer.h"
#include "base/utf_string_conversions.h"
@@ -32,6 +32,7 @@
#include "chrome/browser/chromeos/language_preferences.h"
#include "chrome/browser/chromeos/login/authenticator.h"
#include "chrome/browser/chromeos/login/background_view.h"
+#include "chrome/browser/chromeos/login/login_performer.h"
#include "chrome/browser/chromeos/login/login_utils.h"
#include "chrome/browser/chromeos/login/message_bubble.h"
#include "chrome/browser/chromeos/login/screen_lock_view.h"
@@ -39,15 +40,15 @@
#include "chrome/browser/chromeos/system_key_event_listener.h"
#include "chrome/browser/chromeos/wm_ipc.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
-#include "cros/chromeos_wm_ipc_enums.h"
#include "googleurl/src/gurl.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
+#include "third_party/cros/chromeos_wm_ipc_enums.h"
#include "views/screen.h"
#include "views/widget/root_view.h"
#include "views/widget/widget_gtk.h"
@@ -193,6 +194,9 @@ class ScreenLockObserver : public chromeos::ScreenLockLibrary::Observer,
DISALLOW_COPY_AND_ASSIGN(ScreenLockObserver);
};
+static base::LazyInstance<ScreenLockObserver> g_screen_lock_observer(
+ base::LINKER_INITIALIZED);
+
// A ScreenLock window that covers entire screen to keep the keyboard
// focus/events inside the grab widget.
class LockWindow : public views::WidgetGtk {
@@ -245,7 +249,9 @@ class LockWindow : public views::WidgetGtk {
// GrabWidget's root view to layout the ScreenLockView at the center
// and the Shutdown button at the right bottom.
-class GrabWidgetRootView : public views::View {
+class GrabWidgetRootView
+ : public views::View,
+ public chromeos::ScreenLocker::ScreenLockViewContainer {
public:
explicit GrabWidgetRootView(chromeos::ScreenLockView* screen_lock_view)
: screen_lock_view_(screen_lock_view),
@@ -262,6 +268,18 @@ class GrabWidgetRootView : public views::View {
shutdown_button_->LayoutIn(this);
}
+ // ScreenLocker::ScreenLockViewContainer implementation:
+ void SetScreenLockView(views::View* screen_lock_view) {
+ if (screen_lock_view_) {
+ RemoveChildView(screen_lock_view_);
+ }
+ screen_lock_view_ = screen_lock_view;
+ if (screen_lock_view_) {
+ AddChildView(0, screen_lock_view_);
+ }
+ Layout();
+ }
+
private:
views::View* screen_lock_view_;
@@ -431,7 +449,9 @@ void GrabWidget::TryUngrabOtherClients() {
// BackgroundView for ScreenLocker, which layouts a lock widget in
// addition to other background components.
-class ScreenLockerBackgroundView : public chromeos::BackgroundView {
+class ScreenLockerBackgroundView
+ : public chromeos::BackgroundView,
+ public chromeos::ScreenLocker::ScreenLockViewContainer {
public:
ScreenLockerBackgroundView(views::WidgetGtk* lock_widget,
views::View* screen_lock_view)
@@ -459,6 +479,12 @@ class ScreenLockerBackgroundView : public chromeos::BackgroundView {
}
}
+ // ScreenLocker::ScreenLockViewContainer implementation:
+ void SetScreenLockView(views::View* screen_lock_view) {
+ screen_lock_view_ = screen_lock_view;
+ Layout();
+ }
+
private:
views::WidgetGtk* lock_widget_;
@@ -613,6 +639,9 @@ ScreenLocker::ScreenLocker(const UserManager::User& user)
: lock_window_(NULL),
lock_widget_(NULL),
screen_lock_view_(NULL),
+ captcha_view_(NULL),
+ grab_container_(NULL),
+ background_container_(NULL),
user_(user),
error_info_(NULL),
drawn_(false),
@@ -644,6 +673,7 @@ void ScreenLocker::Init() {
screen_lock_view_ = new ScreenLockView(this);
screen_lock_view_->Init();
screen_lock_view_->SetEnabled(false);
+ screen_lock_view_->StartThrobber();
} else {
input_event_observer_.reset(new InputEventObserver(this));
MessageLoopForUI::current()->AddObserver(input_event_observer_.get());
@@ -658,8 +688,9 @@ void ScreenLocker::Init() {
lock_widget_->MakeTransparent();
lock_widget_->InitWithWidget(lock_window_, gfx::Rect());
if (screen_lock_view_) {
- lock_widget_->SetContentsView(
- new GrabWidgetRootView(screen_lock_view_));
+ GrabWidgetRootView* root_view = new GrabWidgetRootView(screen_lock_view_);
+ grab_container_ = root_view;
+ lock_widget_->SetContentsView(root_view);
}
lock_widget_->Show();
@@ -667,8 +698,10 @@ void ScreenLocker::Init() {
std::string url_string =
CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kScreenSaverUrl);
- background_view_ = new ScreenLockerBackgroundView(lock_widget_,
- screen_lock_view_);
+ ScreenLockerBackgroundView* screen_lock_background_view_ =
+ new ScreenLockerBackgroundView(lock_widget_, screen_lock_view_);
+ background_container_ = screen_lock_background_view_;
+ background_view_ = screen_lock_background_view_;
background_view_->Init(GURL(url_string));
if (background_view_->ScreenSaverEnabled())
StartScreenSaver();
@@ -708,7 +741,7 @@ void ScreenLocker::Init() {
// Create the SystemKeyEventListener so it can listen for system keyboard
// messages regardless of focus while screen locked.
- SystemKeyEventListener::instance();
+ SystemKeyEventListener::GetInstance();
}
void ScreenLocker::OnLoginFailure(const LoginFailure& error) {
@@ -725,14 +758,7 @@ void ScreenLocker::OnLoginFailure(const LoginFailure& error) {
EnableInput();
// Don't enable signout button here as we're showing
// MessageBubble.
- gfx::Rect rect = screen_lock_view_->GetPasswordBoundsRelativeTo(
- lock_widget_->GetRootView());
- gfx::Rect lock_widget_bounds;
- lock_widget_->GetBounds(&lock_widget_bounds, false);
- rect.Offset(lock_widget_bounds.x(), lock_widget_bounds.y());
- if (error_info_)
- error_info_->Close();
std::wstring msg = l10n_util::GetString(IDS_LOGIN_ERROR_AUTHENTICATING);
const std::string error_text = error.GetErrorString();
if (!error_text.empty())
@@ -743,21 +769,7 @@ void ScreenLocker::OnLoginFailure(const LoginFailure& error) {
if (input_method_library->GetNumActiveInputMethods() > 1)
msg += L"\n" + l10n_util::GetString(IDS_LOGIN_ERROR_KEYBOARD_SWITCH_HINT);
- error_info_ = MessageBubble::ShowNoGrab(
- lock_window_,
- rect,
- BubbleBorder::BOTTOM_LEFT,
- ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_WARNING),
- msg,
- std::wstring(), // TODO: add help link
- this);
- if (mouse_event_relay_.get()) {
- MessageLoopForUI::current()->RemoveObserver(mouse_event_relay_.get());
- }
- mouse_event_relay_.reset(
- new MouseEventRelay(lock_widget_->GetNativeView()->window,
- error_info_->GetNativeView()->window));
- MessageLoopForUI::current()->AddObserver(mouse_event_relay_.get());
+ ShowErrorBubble(msg, BubbleBorder::BOTTOM_LEFT);
}
void ScreenLocker::OnLoginSuccess(
@@ -797,16 +809,49 @@ void ScreenLocker::InfoBubbleClosing(InfoBubble* info_bubble,
}
}
+void ScreenLocker::OnCaptchaEntered(const std::string& captcha) {
+ // Captcha dialog is only shown when LoginPerformer instance exists,
+ // i.e. blocking UI after password change is in place.
+ DCHECK(LoginPerformer::default_performer());
+ LoginPerformer::default_performer()->set_captcha(captcha);
+
+ // ScreenLockView ownership is passed to grab_container_.
+ // Need to save return value here so that compile
+ // doesn't fail with "unused result" warning.
+ views::View* view = secondary_view_.release();
+ view = NULL;
+ captcha_view_->SetVisible(false);
+ grab_container_->SetScreenLockView(screen_lock_view_);
+ background_container_->SetScreenLockView(screen_lock_view_);
+ screen_lock_view_->SetVisible(true);
+ screen_lock_view_->ClearAndSetFocusToPassword();
+
+ // Take CaptchaView ownership now that it's removed from grab_container_.
+ secondary_view_.reset(captcha_view_);
+ ShowErrorMessage(postponed_error_message_, false);
+ postponed_error_message_.clear();
+}
+
void ScreenLocker::Authenticate(const string16& password) {
authentication_start_time_ = base::Time::Now();
screen_lock_view_->SetEnabled(false);
screen_lock_view_->SetSignoutEnabled(false);
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(authenticator_.get(),
- &Authenticator::AuthenticateToUnlock,
- user_.email(),
- UTF16ToUTF8(password)));
+ screen_lock_view_->StartThrobber();
+
+ // If LoginPerformer instance exists,
+ // initial online login phase is still active.
+ if (LoginPerformer::default_performer()) {
+ DVLOG(1) << "Delegating authentication to LoginPerformer.";
+ LoginPerformer::default_performer()->Login(user_.email(),
+ UTF16ToUTF8(password));
+ } else {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(authenticator_.get(),
+ &Authenticator::AuthenticateToUnlock,
+ user_.email(),
+ UTF16ToUTF8(password)));
+ }
}
void ScreenLocker::ClearErrors() {
@@ -820,6 +865,7 @@ void ScreenLocker::EnableInput() {
if (screen_lock_view_) {
screen_lock_view_->SetEnabled(true);
screen_lock_view_->ClearAndSetFocusToPassword();
+ screen_lock_view_->StopThrobber();
}
}
@@ -835,6 +881,40 @@ void ScreenLocker::Signout() {
}
}
+void ScreenLocker::ShowCaptchaAndErrorMessage(const GURL& captcha_url,
+ const std::wstring& message) {
+ postponed_error_message_ = message;
+ if (captcha_view_) {
+ captcha_view_->SetCaptchaURL(captcha_url);
+ } else {
+ captcha_view_ = new CaptchaView(captcha_url, true);
+ captcha_view_->Init();
+ captcha_view_->set_delegate(this);
+ }
+ // CaptchaView ownership is passed to grab_container_.
+ views::View* view = secondary_view_.release();
+ view = NULL;
+ screen_lock_view_->SetVisible(false);
+ grab_container_->SetScreenLockView(captcha_view_);
+ background_container_->SetScreenLockView(captcha_view_);
+ captcha_view_->SetVisible(true);
+ // Take ScreenLockView ownership now that it's removed from grab_container_.
+ secondary_view_.reset(screen_lock_view_);
+}
+
+void ScreenLocker::ShowErrorMessage(const std::wstring& message,
+ bool sign_out_only) {
+ if (sign_out_only) {
+ screen_lock_view_->SetEnabled(false);
+ } else {
+ EnableInput();
+ }
+ screen_lock_view_->SetSignoutEnabled(sign_out_only);
+ // Make sure that active Sign Out button is not hidden behind the bubble.
+ ShowErrorBubble(message, sign_out_only ?
+ BubbleBorder::BOTTOM_RIGHT : BubbleBorder::BOTTOM_LEFT);
+}
+
void ScreenLocker::OnGrabInputs() {
DVLOG(1) << "OnGrabInputs";
input_grabbed_ = true;
@@ -899,7 +979,7 @@ void ScreenLocker::UnlockScreenFailed() {
// static
void ScreenLocker::InitClass() {
- Singleton<ScreenLockObserver>::get();
+ g_screen_lock_observer.Get();
}
////////////////////////////////////////////////////////////////////////////////
@@ -980,6 +1060,33 @@ void ScreenLocker::OnWindowManagerReady() {
ScreenLockReady();
}
+void ScreenLocker::ShowErrorBubble(const std::wstring& message,
+ BubbleBorder::ArrowLocation arrow_location) {
+ if (error_info_)
+ error_info_->Close();
+
+ gfx::Rect rect = screen_lock_view_->GetPasswordBoundsRelativeTo(
+ lock_widget_->GetRootView());
+ gfx::Rect lock_widget_bounds;
+ lock_widget_->GetBounds(&lock_widget_bounds, false);
+ rect.Offset(lock_widget_bounds.x(), lock_widget_bounds.y());
+ error_info_ = MessageBubble::ShowNoGrab(
+ lock_window_,
+ rect,
+ arrow_location,
+ ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_WARNING),
+ message,
+ std::wstring(), // TODO(nkostylev): Add help link.
+ this);
+
+ if (mouse_event_relay_.get())
+ MessageLoopForUI::current()->RemoveObserver(mouse_event_relay_.get());
+ mouse_event_relay_.reset(
+ new MouseEventRelay(lock_widget_->GetNativeView()->window,
+ error_info_->GetNativeView()->window));
+ MessageLoopForUI::current()->AddObserver(mouse_event_relay_.get());
+}
+
void ScreenLocker::StopScreenSaver() {
if (background_view_->IsScreenSaverVisible()) {
VLOG(1) << "StopScreenSaver";
diff --git a/chrome/browser/chromeos/login/screen_locker.h b/chrome/browser/chromeos/login/screen_locker.h
index 853c40f..a0332cf 100644
--- a/chrome/browser/chromeos/login/screen_locker.h
+++ b/chrome/browser/chromeos/login/screen_locker.h
@@ -8,8 +8,10 @@
#include <string>
+#include "base/scoped_ptr.h"
#include "base/task.h"
#include "base/time.h"
+#include "chrome/browser/chromeos/login/captcha_view.h"
#include "chrome/browser/chromeos/login/login_status_consumer.h"
#include "chrome/browser/chromeos/login/message_bubble.h"
#include "chrome/browser/chromeos/login/user_manager.h"
@@ -20,6 +22,7 @@ class Rect;
} // namespace gfx
namespace views {
+class View;
class WidgetGtk;
} // namespace views
@@ -43,10 +46,25 @@ class ScreenLockerTester;
// delete itself when it's unlocked.
class ScreenLocker : public LoginStatusConsumer,
public MessageBubbleDelegate,
+ public CaptchaView::Delegate,
public views::AcceleratorTarget {
public:
+ // Interface that helps switching from ScreenLockView to CaptchaView.
+ class ScreenLockViewContainer {
+ public:
+ virtual void SetScreenLockView(views::View* screen_lock_view) = 0;
+
+ protected:
+ virtual ~ScreenLockViewContainer() {}
+ };
+
explicit ScreenLocker(const UserManager::User& user);
+ // Returns the default instance if it has been created.
+ static ScreenLocker* default_screen_locker() {
+ return screen_locker_;
+ }
+
// Initialize and show the screen locker.
void Init();
@@ -64,6 +82,9 @@ class ScreenLocker : public LoginStatusConsumer,
virtual bool FadeInOnShow() { return false; }
virtual void OnHelpLinkActivated() {}
+ // CaptchaView::Delegate implementation:
+ virtual void OnCaptchaEntered(const std::string& captcha);
+
// Authenticates the user with given |password| and authenticator.
void Authenticate(const string16& password);
@@ -76,6 +97,16 @@ class ScreenLocker : public LoginStatusConsumer,
// Exit the chrome, which will sign out the current session.
void Signout();
+ // Present user a CAPTCHA challenge with image from |captcha_url|,
+ // After that shows error bubble with |message|.
+ void ShowCaptchaAndErrorMessage(const GURL& captcha_url,
+ const std::wstring& message);
+
+ // Disables all UI needed and shows error bubble with |message|.
+ // If |sign_out_only| is true then all other input except "Sign Out"
+ // button is blocked.
+ void ShowErrorMessage(const std::wstring& message, bool sign_out_only);
+
// Called when the all inputs are grabbed.
void OnGrabInputs();
@@ -117,6 +148,11 @@ class ScreenLocker : public LoginStatusConsumer,
// Called when the window manager is ready to handle locked state.
void OnWindowManagerReady();
+ // Shows error_info_ bubble with the |message| and |arrow_location| specified.
+ // Assumes that UI controls were locked before that.
+ void ShowErrorBubble(const std::wstring& message,
+ BubbleBorder::ArrowLocation arrow_location);
+
// Stops screen saver.
void StopScreenSaver();
@@ -141,6 +177,23 @@ class ScreenLocker : public LoginStatusConsumer,
// A view that can display html page as background.
BackgroundView* background_view_;
+ // View used to present CAPTCHA challenge input.
+ CaptchaView* captcha_view_;
+
+ // Containers that hold currently visible view.
+ // Initially it's ScreenLockView instance.
+ // When CAPTCHA input dialog is presented it's swapped to CaptchaView
+ // instance, then back after CAPTCHA input is done.
+ ScreenLockViewContainer* grab_container_;
+ ScreenLockViewContainer* background_container_;
+
+ // View that's not owned by grab_container_ - either ScreenLockView or
+ // CaptchaView instance. Keep that under scoped_ptr so that it's deleted.
+ scoped_ptr<views::View> secondary_view_;
+
+ // Postponed error message to be shown after CAPTCHA input is done.
+ std::wstring postponed_error_message_;
+
// Logged in user.
UserManager::User user_;
diff --git a/chrome/browser/chromeos/login/screen_locker_browsertest.cc b/chrome/browser/chromeos/login/screen_locker_browsertest.cc
index 321e0c8..0b7023b 100644
--- a/chrome/browser/chromeos/login/screen_locker_browsertest.cc
+++ b/chrome/browser/chromeos/login/screen_locker_browsertest.cc
@@ -6,7 +6,6 @@
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/automation/ui_controls.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
#include "chrome/browser/chromeos/cros/mock_input_method_library.h"
diff --git a/chrome/browser/chromeos/login/screen_locker_tester.cc b/chrome/browser/chromeos/login/screen_locker_tester.cc
index 34f23c8..d139fda 100644
--- a/chrome/browser/chromeos/login/screen_locker_tester.cc
+++ b/chrome/browser/chromeos/login/screen_locker_tester.cc
@@ -14,6 +14,7 @@
#include "views/controls/button/button.h"
#include "views/controls/label.h"
#include "views/controls/textfield/textfield.h"
+#include "views/event.h"
#include "views/widget/root_view.h"
#include "views/widget/widget_gtk.h"
@@ -44,7 +45,8 @@ void ScreenLockerTester::EnterPassword(const char* password) {
GdkEvent* event = gdk_event_new(GDK_KEY_PRESS);
event->key.keyval = GDK_Return;
- views::Textfield::Keystroke ret(&event->key);
+ views::KeyEvent key_event(&event->key);
+ views::Textfield::Keystroke ret(&key_event);
ScreenLocker::screen_locker_->screen_lock_view_->HandleKeystroke(pass, ret);
gdk_event_free(event);
diff --git a/chrome/browser/chromeos/login/signed_settings.cc b/chrome/browser/chromeos/login/signed_settings.cc
index cef4fa1..8e400e4 100644
--- a/chrome/browser/chromeos/login/signed_settings.cc
+++ b/chrome/browser/chromeos/login/signed_settings.cc
@@ -24,12 +24,18 @@ SignedSettings::SignedSettings()
SignedSettings::~SignedSettings() {}
+SignedSettings::ReturnCode SignedSettings::MapKeyOpCode(
+ OwnerManager::KeyOpCode return_code) {
+ return (return_code == OwnerManager::KEY_UNAVAILABLE ?
+ KEY_UNAVAILABLE : OPERATION_FAILED);
+}
+
class CheckWhitelistOp : public SignedSettings {
public:
CheckWhitelistOp(const std::string& email,
SignedSettings::Delegate<bool>* d);
virtual ~CheckWhitelistOp();
- bool Execute();
+ void Execute();
// Implementation of OwnerManager::Delegate::OnKeyOpComplete()
void OnKeyOpComplete(const OwnerManager::KeyOpCode return_code,
const std::vector<uint8>& payload);
@@ -46,7 +52,7 @@ class WhitelistOp : public SignedSettings,
bool add_to_whitelist,
SignedSettings::Delegate<bool>* d);
virtual ~WhitelistOp();
- bool Execute();
+ void Execute();
// Implementation of OwnerManager::Delegate::OnKeyOpComplete()
void OnKeyOpComplete(const OwnerManager::KeyOpCode return_code,
const std::vector<uint8>& payload);
@@ -68,7 +74,7 @@ class StorePropertyOp : public SignedSettings,
const std::string& value,
SignedSettings::Delegate<bool>* d);
virtual ~StorePropertyOp();
- bool Execute();
+ void Execute();
// Implementation of OwnerManager::Delegate::OnKeyOpComplete()
void OnKeyOpComplete(const OwnerManager::KeyOpCode return_code,
const std::vector<uint8>& payload);
@@ -86,7 +92,7 @@ class RetrievePropertyOp : public SignedSettings {
RetrievePropertyOp(const std::string& name,
SignedSettings::Delegate<std::string>* d);
virtual ~RetrievePropertyOp();
- bool Execute();
+ void Execute();
// Implementation of OwnerManager::Delegate::OnKeyOpComplete()
void OnKeyOpComplete(const OwnerManager::KeyOpCode return_code,
const std::vector<uint8>& payload);
@@ -139,15 +145,15 @@ CheckWhitelistOp::CheckWhitelistOp(const std::string& email,
CheckWhitelistOp::~CheckWhitelistOp() {}
-bool CheckWhitelistOp::Execute() {
+void CheckWhitelistOp::Execute() {
CHECK(chromeos::CrosLibrary::Get()->EnsureLoaded());
std::vector<uint8> sig;
- if (!CrosLibrary::Get()->GetLoginLibrary()->CheckWhitelist(email_, &sig))
- return false;
-
+ if (!CrosLibrary::Get()->GetLoginLibrary()->CheckWhitelist(email_, &sig)) {
+ d_->OnSettingsOpCompleted(NOT_FOUND, false);
+ return;
+ }
// Posts a task to the FILE thread to verify |sig|.
service_->StartVerifyAttempt(email_, sig, this);
- return true;
}
void CheckWhitelistOp::OnKeyOpComplete(
@@ -162,10 +168,11 @@ void CheckWhitelistOp::OnKeyOpComplete(
return_code, payload));
return;
}
- if (return_code == OwnerManager::SUCCESS)
- d_->OnSettingsOpSucceeded(true);
- else
- d_->OnSettingsOpFailed();
+ if (return_code == OwnerManager::SUCCESS) {
+ d_->OnSettingsOpCompleted(SUCCESS, true);
+ } else {
+ d_->OnSettingsOpCompleted(SignedSettings::MapKeyOpCode(return_code), false);
+ }
}
WhitelistOp::WhitelistOp(const std::string& email,
@@ -178,10 +185,9 @@ WhitelistOp::WhitelistOp(const std::string& email,
WhitelistOp::~WhitelistOp() {}
-bool WhitelistOp::Execute() {
+void WhitelistOp::Execute() {
// Posts a task to the FILE thread to sign |email_|.
service_->StartSigningAttempt(email_, this);
- return true;
}
void WhitelistOp::OnKeyOpComplete(const OwnerManager::KeyOpCode return_code,
@@ -196,20 +202,20 @@ void WhitelistOp::OnKeyOpComplete(const OwnerManager::KeyOpCode return_code,
return;
}
// Now, sure we're on the UI thread.
- bool success = false;
if (return_code == OwnerManager::SUCCESS) {
- // OnComplete() will be called when this is done.
- success = InitiateWhitelistOp(payload);
+ // OnComplete() will be called by this call, if it succeeds.
+ if (!InitiateWhitelistOp(payload))
+ d_->OnSettingsOpCompleted(OPERATION_FAILED, false);
+ } else {
+ d_->OnSettingsOpCompleted(SignedSettings::MapKeyOpCode(return_code), false);
}
- if (!success)
- d_->OnSettingsOpFailed();
}
void WhitelistOp::OnComplete(bool value) {
if (value)
- d_->OnSettingsOpSucceeded(value);
+ d_->OnSettingsOpCompleted(SUCCESS, value);
else
- d_->OnSettingsOpFailed();
+ d_->OnSettingsOpCompleted(NOT_FOUND, false);
}
bool WhitelistOp::InitiateWhitelistOp(const std::vector<uint8>& signature) {
@@ -229,14 +235,14 @@ StorePropertyOp::StorePropertyOp(const std::string& name,
StorePropertyOp::~StorePropertyOp() {}
-bool StorePropertyOp::Execute() {
+void StorePropertyOp::Execute() {
if (!service_->IsAlreadyOwned()) {
if (g_browser_process &&
g_browser_process->local_state() &&
SignedSettingsTempStorage::Store(name_, value_,
g_browser_process->local_state())) {
- d_->OnSettingsOpSucceeded(true);
- return true;
+ d_->OnSettingsOpCompleted(SUCCESS, true);
+ return;
}
}
// Posts a task to the FILE thread to sign |name_|=|value_|.
@@ -244,7 +250,6 @@ bool StorePropertyOp::Execute() {
name_.c_str(),
value_.c_str());
service_->StartSigningAttempt(to_sign, this);
- return true;
}
void StorePropertyOp::OnKeyOpComplete(const OwnerManager::KeyOpCode return_code,
@@ -258,24 +263,26 @@ void StorePropertyOp::OnKeyOpComplete(const OwnerManager::KeyOpCode return_code,
return_code, payload));
return;
}
+ VLOG(2) << "StorePropertyOp::OnKeyOpComplete return_code = " << return_code;
// Now, sure we're on the UI thread.
- bool success = false;
if (return_code == OwnerManager::SUCCESS) {
- // OnComplete() will be called when this is done.
- success = CrosLibrary::Get()->GetLoginLibrary()->StorePropertyAsync(name_,
- value_,
- payload,
- this);
+ // OnComplete() will be called by this call, if it succeeds.
+ if (!CrosLibrary::Get()->GetLoginLibrary()->StorePropertyAsync(name_,
+ value_,
+ payload,
+ this)) {
+ d_->OnSettingsOpCompleted(OPERATION_FAILED, false);
+ }
+ } else {
+ d_->OnSettingsOpCompleted(SignedSettings::MapKeyOpCode(return_code), false);
}
- if (!success)
- d_->OnSettingsOpFailed();
}
void StorePropertyOp::OnComplete(bool value) {
if (value)
- d_->OnSettingsOpSucceeded(value);
+ d_->OnSettingsOpCompleted(SUCCESS, value);
else
- d_->OnSettingsOpFailed();
+ d_->OnSettingsOpCompleted(NOT_FOUND, false);
}
RetrievePropertyOp::RetrievePropertyOp(const std::string& name,
@@ -286,7 +293,7 @@ RetrievePropertyOp::RetrievePropertyOp(const std::string& name,
RetrievePropertyOp::~RetrievePropertyOp() {}
-bool RetrievePropertyOp::Execute() {
+void RetrievePropertyOp::Execute() {
CHECK(chromeos::CrosLibrary::Get()->EnsureLoaded());
// TODO(dilmah): Fix the race:
// At the moment when device becomes owned there is lapse of time after
@@ -303,21 +310,21 @@ bool RetrievePropertyOp::Execute() {
NewRunnableMethod(this,
&RetrievePropertyOp::OnKeyOpComplete,
OwnerManager::SUCCESS, std::vector<uint8>()));
- return true;
+ return;
}
}
std::vector<uint8> sig;
if (!CrosLibrary::Get()->GetLoginLibrary()->RetrieveProperty(name_,
&value_,
&sig)) {
- return false;
+ d_->OnSettingsOpCompleted(NOT_FOUND, std::string());
+ return;
}
std::string to_verify = base::StringPrintf("%s=%s",
name_.c_str(),
value_.c_str());
// Posts a task to the FILE thread to verify |sig|.
service_->StartVerifyAttempt(to_verify, sig, this);
- return true;
}
void RetrievePropertyOp::OnKeyOpComplete(
@@ -333,9 +340,10 @@ void RetrievePropertyOp::OnKeyOpComplete(
}
// Now, sure we're on the UI thread.
if (return_code == OwnerManager::SUCCESS)
- d_->OnSettingsOpSucceeded(value_);
+ d_->OnSettingsOpCompleted(SUCCESS, value_);
else
- d_->OnSettingsOpFailed();
+ d_->OnSettingsOpCompleted(SignedSettings::MapKeyOpCode(return_code),
+ std::string());
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/signed_settings.h b/chrome/browser/chromeos/login/signed_settings.h
index d1bdc33..61d5e15 100644
--- a/chrome/browser/chromeos/login/signed_settings.h
+++ b/chrome/browser/chromeos/login/signed_settings.h
@@ -35,12 +35,18 @@ class OwnershipService;
class SignedSettings : public base::RefCountedThreadSafe<SignedSettings>,
public OwnerManager::Delegate {
public:
+ enum ReturnCode {
+ SUCCESS,
+ NOT_FOUND, // Email address or property name not found.
+ KEY_UNAVAILABLE, // Owner key not yet configured.
+ OPERATION_FAILED // Signature op or IPC to signed settings daemon failed.
+ };
+
template <class T>
class Delegate {
public:
- // These methods will be called on the UI thread.
- virtual void OnSettingsOpSucceeded(T value) {}
- virtual void OnSettingsOpFailed() {}
+ // This method will be called on the UI thread.
+ virtual void OnSettingsOpCompleted(ReturnCode code, T value) {}
};
SignedSettings();
@@ -67,7 +73,9 @@ class SignedSettings : public base::RefCountedThreadSafe<SignedSettings>,
const std::string& name,
SignedSettings::Delegate<std::string>* d);
- virtual bool Execute() = 0;
+ static ReturnCode MapKeyOpCode(OwnerManager::KeyOpCode code);
+
+ virtual void Execute() = 0;
// Implementation of OwnerManager::Delegate::OnKeyOpComplete()
void OnKeyOpComplete(const OwnerManager::KeyOpCode return_code,
diff --git a/chrome/browser/chromeos/login/signed_settings_helper.cc b/chrome/browser/chromeos/login/signed_settings_helper.cc
index 30c910a..6a1a735 100644
--- a/chrome/browser/chromeos/login/signed_settings_helper.cc
+++ b/chrome/browser/chromeos/login/signed_settings_helper.cc
@@ -7,9 +7,9 @@
#include <string>
#include <vector>
+#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/ref_counted.h"
-#include "base/singleton.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/chromeos/login/signed_settings.h"
@@ -39,13 +39,10 @@ class OpContext {
// So keep a local copy of delegate and executing flag to use after
// the call.
Delegate* delegate = delegate_;
- bool executing = executing_ = op_->Execute();
- if (executing) {
- if (delegate)
- delegate->OnOpStarted(this);
- } else {
- OnOpFailed();
- }
+ executing_ = true;
+ op_->Execute();
+ if (delegate)
+ delegate->OnOpStarted(this);
}
// Cancels the callback.
@@ -93,11 +90,6 @@ class OpContext {
delete this;
}
- // Callback on op failure.
- virtual void OnOpFailed() {
- OnOpCompleted();
- }
-
bool executing_;
Delegate* delegate_;
@@ -124,31 +116,27 @@ class WhitelistOpContext : public SignedSettings::Delegate<bool>,
}
// chromeos::SignedSettings::Delegate implementation
- virtual void OnSettingsOpSucceeded(bool value) {
+ virtual void OnSettingsOpCompleted(SignedSettings::ReturnCode code,
+ bool value) {
if (callback_) {
switch (type_) {
case CHECK:
- callback_->OnCheckWhiteListCompleted(value, email_);
+ callback_->OnCheckWhitelistCompleted(code, email_);
break;
case ADD:
- callback_->OnWhitelistCompleted(value, email_);
+ callback_->OnWhitelistCompleted(code, email_);
break;
case REMOVE:
- callback_->OnUnwhitelistCompleted(value, email_);
+ callback_->OnUnwhitelistCompleted(code, email_);
break;
default:
LOG(ERROR) << "Unknown WhitelistOpContext type " << type_;
break;
}
}
-
OnOpCompleted();
}
- virtual void OnSettingsOpFailed() {
- OnOpFailed();
- }
-
protected:
// OpContext implemenetation
virtual void CreateOp() {
@@ -168,27 +156,6 @@ class WhitelistOpContext : public SignedSettings::Delegate<bool>,
}
}
- virtual void OnOpFailed() {
- if (callback_) {
- switch (type_) {
- case CHECK:
- callback_->OnCheckWhiteListCompleted(false, email_);
- break;
- case ADD:
- callback_->OnWhitelistCompleted(false, email_);
- break;
- case REMOVE:
- callback_->OnUnwhitelistCompleted(false, email_);
- break;
- default:
- LOG(ERROR) << "Unknown WhitelistOpContext type " << type_;
- break;
- }
- }
-
- OnOpCompleted();
- }
-
private:
Type type_;
std::string email_;
@@ -209,28 +176,20 @@ class StorePropertyOpContext : public SignedSettings::Delegate<bool>,
}
// chromeos::SignedSettings::Delegate implementation
- virtual void OnSettingsOpSucceeded(bool value) {
+ virtual void OnSettingsOpCompleted(SignedSettings::ReturnCode code,
+ bool unused) {
+ VLOG(2) << "OnSettingsOpCompleted, code = " << code;
if (callback_)
- callback_->OnStorePropertyCompleted(true, name_, value_);
+ callback_->OnStorePropertyCompleted(code, name_, value_);
OnOpCompleted();
}
- virtual void OnSettingsOpFailed() {
- OnOpFailed();
- }
-
protected:
// OpContext implemenetation
virtual void CreateOp() {
op_ = SignedSettings::CreateStorePropertyOp(name_, value_, this);
}
- virtual void OnOpFailed() {
- if (callback_)
- callback_->OnStorePropertyCompleted(false, name_, value_);
- OnOpCompleted();
- }
-
private:
std::string name_;
std::string value_;
@@ -250,29 +209,20 @@ class RetrievePropertyOpContext
}
// chromeos::SignedSettings::Delegate implementation
- virtual void OnSettingsOpSucceeded(std::string value) {
+ virtual void OnSettingsOpCompleted(SignedSettings::ReturnCode code,
+ std::string value) {
if (callback_)
- callback_->OnRetrievePropertyCompleted(true, name_, value);
+ callback_->OnRetrievePropertyCompleted(code, name_, value);
OnOpCompleted();
}
- virtual void OnSettingsOpFailed() {
- OnOpFailed();
- }
-
protected:
// OpContext implemenetation
virtual void CreateOp() {
op_ = SignedSettings::CreateRetrievePropertyOp(name_, this);
}
- virtual void OnOpFailed() {
- if (callback_)
- callback_->OnRetrievePropertyCompleted(false, name_, std::string());
- OnOpCompleted();
- }
-
private:
std::string name_;
@@ -312,10 +262,13 @@ class SignedSettingsHelperImpl : public SignedSettingsHelper,
std::vector<OpContext*> pending_contexts_;
- friend struct DefaultSingletonTraits<SignedSettingsHelperImpl>;
+ friend struct base::DefaultLazyInstanceTraits<SignedSettingsHelperImpl>;
DISALLOW_COPY_AND_ASSIGN(SignedSettingsHelperImpl);
};
+static base::LazyInstance<SignedSettingsHelperImpl>
+ g_signed_settings_helper_impl(base::LINKER_INITIALIZED);
+
SignedSettingsHelperImpl::SignedSettingsHelperImpl() {
}
@@ -421,7 +374,7 @@ void SignedSettingsHelperImpl::OnOpCompleted(OpContext* context) {
}
SignedSettingsHelper* SignedSettingsHelper::Get() {
- return Singleton<SignedSettingsHelperImpl>::get();
+ return g_signed_settings_helper_impl.Pointer();
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/signed_settings_helper.h b/chrome/browser/chromeos/login/signed_settings_helper.h
index cfe99e4..d65b677 100644
--- a/chrome/browser/chromeos/login/signed_settings_helper.h
+++ b/chrome/browser/chromeos/login/signed_settings_helper.h
@@ -6,7 +6,7 @@
#define CHROME_BROWSER_CHROMEOS_LOGIN_SIGNED_SETTINGS_HELPER_H_
#pragma once
-#include <string>
+#include "chrome/browser/chromeos/login/signed_settings.h"
namespace chromeos {
@@ -20,24 +20,29 @@ class SignedSettingsHelper {
public:
// Callback of CheckWhitelistOp. |success| indicates whether the op succeeds
// or not. |email| is the email that is checked against.
- virtual void OnCheckWhiteListCompleted(
- bool success, const std::string& email) {}
+ virtual void OnCheckWhitelistCompleted(
+ SignedSettings::ReturnCode code,
+ const std::string& email) {}
// Callback of WhitelistOp that adds |email| to the whitelist.
virtual void OnWhitelistCompleted(
- bool success, const std::string& email) {}
+ SignedSettings::ReturnCode code, const std::string& email) {}
// Callback of WhitelistOp that removes |email| to the whitelist.
virtual void OnUnwhitelistCompleted(
- bool success, const std::string& email) {}
+ SignedSettings::ReturnCode code, const std::string& email) {}
// Callback of StorePropertyOp.
virtual void OnStorePropertyCompleted(
- bool success, const std::string& name, const std::string& value) {}
+ SignedSettings::ReturnCode code,
+ const std::string& name,
+ const std::string& value) {}
// Callback of RetrievePropertyOp.
virtual void OnRetrievePropertyCompleted(
- bool success, const std::string& name, const std::string& value) {}
+ SignedSettings::ReturnCode code,
+ const std::string& name,
+ const std::string& value) {}
};
// Class factory
diff --git a/chrome/browser/chromeos/login/signed_settings_helper_unittest.cc b/chrome/browser/chromeos/login/signed_settings_helper_unittest.cc
index 42e2842..df8ad6c 100644
--- a/chrome/browser/chromeos/login/signed_settings_helper_unittest.cc
+++ b/chrome/browser/chromeos/login/signed_settings_helper_unittest.cc
@@ -19,16 +19,20 @@ namespace chromeos {
class MockSignedSettingsHelperCallback : public SignedSettingsHelper::Callback {
public:
- MOCK_METHOD2(OnCheckWhiteListCompleted, void(
- bool success, const std::string& email));
+ MOCK_METHOD2(OnCheckWhitelistCompleted, void(
+ SignedSettings::ReturnCode code, const std::string& email));
MOCK_METHOD2(OnWhitelistCompleted, void(
- bool success, const std::string& email));
+ SignedSettings::ReturnCode code, const std::string& email));
MOCK_METHOD2(OnUnwhitelistCompleted, void(
- bool success, const std::string& email));
+ SignedSettings::ReturnCode code, const std::string& email));
MOCK_METHOD3(OnStorePropertyCompleted, void(
- bool success, const std::string& name, const std::string& value));
+ SignedSettings::ReturnCode code,
+ const std::string& name,
+ const std::string& value));
MOCK_METHOD3(OnRetrievePropertyCompleted, void(
- bool success, const std::string& name, const std::string& value));
+ SignedSettings::ReturnCode code,
+ const std::string& name,
+ const std::string& value));
};
class SignedSettingsHelperTest : public ::testing::Test,
@@ -45,14 +49,12 @@ class SignedSettingsHelperTest : public ::testing::Test,
}
virtual void SetUp() {
- chromeos::CrosLibrary::Get()->GetTestApi()->SetUseStubImpl();
file_thread_.Start();
SignedSettingsHelper::Get()->set_test_delegate(this);
}
virtual void TearDown() {
SignedSettingsHelper::Get()->set_test_delegate(NULL);
- chromeos::CrosLibrary::Get()->GetTestApi()->ResetUseStubImpl();
}
virtual void OnOpCreated(SignedSettings* op) {
@@ -80,26 +82,29 @@ class SignedSettingsHelperTest : public ::testing::Test,
BrowserThread file_thread_;
int pending_ops_;
+
+ ScopedStubCrosEnabler stub_cros_enabler_;
};
TEST_F(SignedSettingsHelperTest, SerializedOps) {
MockSignedSettingsHelperCallback cb;
+ EXPECT_CALL(m_, IsAlreadyOwned()).Times(2);
InSequence s;
EXPECT_CALL(m_, StartVerifyAttempt(_, _, _)).Times(1);
- EXPECT_CALL(cb, OnCheckWhiteListCompleted(true, _))
+ EXPECT_CALL(cb, OnCheckWhitelistCompleted(SignedSettings::SUCCESS, _))
.Times(1);
EXPECT_CALL(m_, StartSigningAttempt(_, _)).Times(1);
- EXPECT_CALL(cb, OnWhitelistCompleted(true, _))
+ EXPECT_CALL(cb, OnWhitelistCompleted(SignedSettings::SUCCESS, _))
.Times(1);
EXPECT_CALL(m_, StartSigningAttempt(_, _)).Times(1);
- EXPECT_CALL(cb, OnUnwhitelistCompleted(true, _))
+ EXPECT_CALL(cb, OnUnwhitelistCompleted(SignedSettings::SUCCESS, _))
.Times(1);
EXPECT_CALL(m_, StartSigningAttempt(_, _)).Times(1);
- EXPECT_CALL(cb, OnStorePropertyCompleted(true, _, _))
+ EXPECT_CALL(cb, OnStorePropertyCompleted(SignedSettings::SUCCESS, _, _))
.Times(1);
EXPECT_CALL(m_, StartVerifyAttempt(_, _, _)).Times(1);
- EXPECT_CALL(cb, OnRetrievePropertyCompleted(true, _, _))
+ EXPECT_CALL(cb, OnRetrievePropertyCompleted(SignedSettings::SUCCESS, _, _))
.Times(1);
pending_ops_ = 5;
@@ -116,15 +121,16 @@ TEST_F(SignedSettingsHelperTest, SerializedOps) {
TEST_F(SignedSettingsHelperTest, CanceledOps) {
MockSignedSettingsHelperCallback cb;
+ EXPECT_CALL(m_, IsAlreadyOwned()).Times(2);
InSequence s;
EXPECT_CALL(m_, StartVerifyAttempt(_, _, _)).Times(1);
- EXPECT_CALL(cb, OnCheckWhiteListCompleted(true, _))
+ EXPECT_CALL(cb, OnCheckWhitelistCompleted(SignedSettings::SUCCESS, _))
.Times(1);
EXPECT_CALL(m_, StartSigningAttempt(_, _)).Times(1);
- EXPECT_CALL(cb, OnWhitelistCompleted(true, _))
+ EXPECT_CALL(cb, OnWhitelistCompleted(SignedSettings::SUCCESS, _))
.Times(1);
EXPECT_CALL(m_, StartSigningAttempt(_, _)).Times(1);
- EXPECT_CALL(cb, OnUnwhitelistCompleted(true, _))
+ EXPECT_CALL(cb, OnUnwhitelistCompleted(SignedSettings::SUCCESS, _))
.Times(1);
// CheckWhitelistOp for cb_to_be_canceled still gets executed but callback
@@ -132,10 +138,10 @@ TEST_F(SignedSettingsHelperTest, CanceledOps) {
EXPECT_CALL(m_, StartVerifyAttempt(_, _, _)).Times(1);
EXPECT_CALL(m_, StartSigningAttempt(_, _)).Times(1);
- EXPECT_CALL(cb, OnStorePropertyCompleted(true, _, _))
+ EXPECT_CALL(cb, OnStorePropertyCompleted(SignedSettings::SUCCESS, _, _))
.Times(1);
EXPECT_CALL(m_, StartVerifyAttempt(_, _, _)).Times(1);
- EXPECT_CALL(cb, OnRetrievePropertyCompleted(true, _, _))
+ EXPECT_CALL(cb, OnRetrievePropertyCompleted(SignedSettings::SUCCESS, _, _))
.Times(1);
pending_ops_ = 6;
diff --git a/chrome/browser/chromeos/login/signed_settings_temp_storage.cc b/chrome/browser/chromeos/login/signed_settings_temp_storage.cc
index d88b075..24a0b38 100644
--- a/chrome/browser/chromeos/login/signed_settings_temp_storage.cc
+++ b/chrome/browser/chromeos/login/signed_settings_temp_storage.cc
@@ -4,13 +4,16 @@
#include "chrome/browser/chromeos/login/signed_settings_temp_storage.h"
+#include "base/lazy_instance.h"
#include "base/values.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/login/ownership_service.h"
#include "chrome/browser/chromeos/login/signed_settings.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/pref_names.h"
+static base::LazyInstance<chromeos::SignedSettings::Delegate<bool> >
+ g_signed_settings_delegate(base::LINKER_INITIALIZED);
+
namespace chromeos {
// static
@@ -67,7 +70,7 @@ void SignedSettingsTempStorage::Finalize(PrefService* local_state) {
temp_storage->GetStringWithoutPathExpansion(*it, &value);
SignedSettings::CreateStorePropertyOp(
*it, value,
- Singleton< SignedSettings::Delegate<bool> >::get())->Execute();
+ g_signed_settings_delegate.Pointer())->Execute();
}
local_state->ClearPref(prefs::kSignedSettingsTempStorage);
}
diff --git a/chrome/browser/chromeos/login/signed_settings_temp_storage_unittest.cc b/chrome/browser/chromeos/login/signed_settings_temp_storage_unittest.cc
index e92917b..837e5f0 100644
--- a/chrome/browser/chromeos/login/signed_settings_temp_storage_unittest.cc
+++ b/chrome/browser/chromeos/login/signed_settings_temp_storage_unittest.cc
@@ -12,7 +12,6 @@
#include "base/file_util.h"
#include "base/scoped_ptr.h"
#include "base/scoped_temp_dir.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/logging_chrome.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -31,7 +30,7 @@ class SignedSettingsTempStorageTest : public ::testing::Test {
FilePath temp_file;
ASSERT_TRUE(
file_util::CreateTemporaryFileInDir(temp_dir_.path(), &temp_file));
- local_state_.reset(PrefService::CreatePrefService(temp_file, NULL));
+ local_state_.reset(PrefService::CreatePrefService(temp_file, NULL, NULL));
ASSERT_TRUE(NULL != local_state_.get());
SignedSettingsTempStorage::RegisterPrefs(local_state_.get());
}
@@ -42,7 +41,7 @@ class SignedSettingsTempStorageTest : public ::testing::Test {
};
TEST_F(SignedSettingsTempStorageTest, Basic) {
- EXPECT_GT(ref_map_.size(), 3u); // Number above 3 is many.
+ EXPECT_GT(ref_map_.size(), 3u); // Number above 3 is many.
typedef std::map<std::string, std::string>::iterator It;
std::vector<It> a_list;
for (It it = ref_map_.begin(); it != ref_map_.end(); ++it) {
@@ -75,4 +74,3 @@ TEST_F(SignedSettingsTempStorageTest, Basic) {
}
} // namespace chromeos
-
diff --git a/chrome/browser/chromeos/login/signed_settings_unittest.cc b/chrome/browser/chromeos/login/signed_settings_unittest.cc
index 88e8811..f3d4a13 100644
--- a/chrome/browser/chromeos/login/signed_settings_unittest.cc
+++ b/chrome/browser/chromeos/login/signed_settings_unittest.cc
@@ -11,12 +11,16 @@
#include "base/stringprintf.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
+#include "chrome/browser/chromeos/cros/mock_library_loader.h"
+#include "chrome/browser/chromeos/cros/mock_login_library.h"
#include "chrome/browser/chromeos/login/mock_owner_key_utils.h"
#include "chrome/browser/chromeos/login/mock_ownership_service.h"
#include "chrome/browser/chromeos/login/owner_manager_unittest.h"
+#include "chrome/test/thread_test_helper.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using ::testing::AnyNumber;
using ::testing::Invoke;
using ::testing::Return;
using ::testing::_;
@@ -29,37 +33,31 @@ class DummyDelegate : public SignedSettings::Delegate<T> {
public:
explicit DummyDelegate(T to_expect)
: expect_success_(false),
+ expected_failure_(SignedSettings::SUCCESS),
expected_(to_expect),
run_(false) {}
virtual ~DummyDelegate() { EXPECT_TRUE(run_); }
- virtual void OnSettingsOpSucceeded(T value) {
+ virtual void OnSettingsOpCompleted(SignedSettings::ReturnCode code,
+ T value) {
run_ = true;
- EXPECT_TRUE(expect_success_);
- EXPECT_EQ(expected_, value);
+ if (expect_success_)
+ EXPECT_EQ(expected_, value);
+ EXPECT_EQ(expected_failure_, code);
}
- virtual void OnSettingsOpFailed() {
- run_ = true;
- EXPECT_FALSE(expect_success_);
+ virtual void expect_success() {
+ expect_success_ = true;
+ expected_failure_ = SignedSettings::SUCCESS;
+ }
+ virtual void expect_failure(SignedSettings::ReturnCode code) {
+ expect_success_ = false;
+ expected_failure_ = code;
}
- virtual void expect_success() { expect_success_ = true; }
bool expect_success_;
+ SignedSettings::ReturnCode expected_failure_;
T expected_;
bool run_;
};
-class Quitter : public DummyDelegate<bool> {
- public:
- explicit Quitter(bool to_expect) : DummyDelegate<bool>(to_expect) {}
- virtual ~Quitter() {}
- void OnSettingsOpSucceeded(bool value) {
- DummyDelegate<bool>::OnSettingsOpSucceeded(value);
- MessageLoop::current()->Quit();
- }
- void OnSettingsOpFailed() {
- DummyDelegate<bool>::OnSettingsOpFailed();
- MessageLoop::current()->Quit();
- }
-};
} // anonymous namespace
class SignedSettingsTest : public ::testing::Test {
@@ -78,13 +76,11 @@ class SignedSettingsTest : public ::testing::Test {
virtual ~SignedSettingsTest() {}
virtual void SetUp() {
- chromeos::CrosLibrary::Get()->GetTestApi()->SetUseStubImpl();
file_thread_.Start();
}
virtual void TearDown() {
OwnerKeyUtils::set_factory(NULL);
- chromeos::CrosLibrary::Get()->GetTestApi()->ResetUseStubImpl();
}
void mock_service(SignedSettings* s, MockOwnershipService* m) {
@@ -95,12 +91,13 @@ class SignedSettingsTest : public ::testing::Test {
DummyDelegate<bool> d(false);
scoped_refptr<SignedSettings> s(
SignedSettings::CreateCheckWhitelistOp(fake_email_, &d));
+ d.expect_failure(SignedSettings::MapKeyOpCode(return_code));
mock_service(s.get(), &m_);
EXPECT_CALL(m_, StartVerifyAttempt(fake_email_, _, _))
.Times(1);
- EXPECT_TRUE(s->Execute());
+ s->Execute();
s->OnKeyOpComplete(return_code, std::vector<uint8>());
}
@@ -108,12 +105,13 @@ class SignedSettingsTest : public ::testing::Test {
DummyDelegate<bool> d(false);
scoped_refptr<SignedSettings> s(
SignedSettings::CreateWhitelistOp(fake_email_, true, &d));
+ d.expect_failure(SignedSettings::MapKeyOpCode(return_code));
mock_service(s.get(), &m_);
EXPECT_CALL(m_, StartSigningAttempt(fake_email_, _))
.Times(1);
- EXPECT_TRUE(s->Execute());
+ s->Execute();
s->OnKeyOpComplete(return_code, std::vector<uint8>());
}
@@ -121,14 +119,17 @@ class SignedSettingsTest : public ::testing::Test {
DummyDelegate<bool> d(false);
scoped_refptr<SignedSettings> s(
SignedSettings::CreateStorePropertyOp(fake_prop_, fake_value_, &d));
+ d.expect_failure(SignedSettings::MapKeyOpCode(return_code));
std::string to_sign = base::StringPrintf("%s=%s",
fake_prop_.c_str(),
fake_value_.c_str());
mock_service(s.get(), &m_);
EXPECT_CALL(m_, StartSigningAttempt(to_sign, _))
.Times(1);
+ EXPECT_CALL(m_, IsAlreadyOwned())
+ .WillOnce(Return(true));
- EXPECT_TRUE(s->Execute());
+ s->Execute();
s->OnKeyOpComplete(return_code, std::vector<uint8>());
}
@@ -136,17 +137,49 @@ class SignedSettingsTest : public ::testing::Test {
DummyDelegate<std::string> d(fake_value_);
scoped_refptr<SignedSettings> s(
SignedSettings::CreateRetrievePropertyOp(fake_prop_, &d));
+ d.expect_failure(SignedSettings::MapKeyOpCode(return_code));
std::string to_verify = base::StringPrintf("%s=%s",
fake_prop_.c_str(),
fake_value_.c_str());
mock_service(s.get(), &m_);
EXPECT_CALL(m_, StartVerifyAttempt(to_verify, _, _))
.Times(1);
+ EXPECT_CALL(m_, IsAlreadyOwned())
+ .WillOnce(Return(true));
- EXPECT_TRUE(s->Execute());
+ s->Execute();
s->OnKeyOpComplete(return_code, std::vector<uint8>());
}
+ MockLoginLibrary* MockLoginLib() {
+ chromeos::CrosLibrary::TestApi* test_api =
+ chromeos::CrosLibrary::Get()->GetTestApi();
+
+ // Mocks, ownership transferred to CrosLibrary class on creation.
+ MockLoginLibrary* mock_library;
+ MockLibraryLoader* loader;
+
+ loader = new MockLibraryLoader();
+ ON_CALL(*loader, Load(_))
+ .WillByDefault(Return(true));
+ EXPECT_CALL(*loader, Load(_))
+ .Times(AnyNumber());
+
+ test_api->SetLibraryLoader(loader, true);
+
+ mock_library = new MockLoginLibrary();
+ test_api->SetLoginLibrary(mock_library, true);
+ return mock_library;
+ }
+
+ void UnMockLoginLib() {
+ // Prevent bogus gMock leak check from firing.
+ chromeos::CrosLibrary::TestApi* test_api =
+ chromeos::CrosLibrary::Get()->GetTestApi();
+ test_api->SetLibraryLoader(NULL, false);
+ test_api->SetLoginLibrary(NULL, false);
+ }
+
const std::string fake_email_;
const std::string fake_prop_;
const std::string fake_value_;
@@ -165,6 +198,7 @@ class SignedSettingsTest : public ::testing::Test {
MockKeyUtils* mock_;
MockInjector injector_;
+ ScopedStubCrosEnabler stub_cros_enabler_;
};
TEST_F(SignedSettingsTest, CheckWhitelist) {
@@ -177,10 +211,23 @@ TEST_F(SignedSettingsTest, CheckWhitelist) {
EXPECT_CALL(m_, StartVerifyAttempt(fake_email_, _, _))
.Times(1);
- EXPECT_TRUE(s->Execute());
+ s->Execute();
s->OnKeyOpComplete(OwnerManager::SUCCESS, std::vector<uint8>());
}
+TEST_F(SignedSettingsTest, CheckWhitelistNotFound) {
+ DummyDelegate<bool> d(true);
+ scoped_refptr<SignedSettings> s(
+ SignedSettings::CreateCheckWhitelistOp(fake_email_, &d));
+ d.expect_failure(SignedSettings::NOT_FOUND);
+ MockLoginLibrary* lib = MockLoginLib();
+ EXPECT_CALL(*lib, CheckWhitelist(fake_email_, _))
+ .WillOnce(Return(false))
+ .RetiresOnSaturation();
+ s->Execute();
+ UnMockLoginLib();
+}
+
TEST_F(SignedSettingsTest, CheckWhitelistNoKey) {
FailingCheckWhitelist(OwnerManager::KEY_UNAVAILABLE);
}
@@ -190,7 +237,7 @@ TEST_F(SignedSettingsTest, CheckWhitelistFailed) {
}
TEST_F(SignedSettingsTest, Whitelist) {
- Quitter d(true);
+ DummyDelegate<bool> d(true);
d.expect_success();
scoped_refptr<SignedSettings> s(
SignedSettings::CreateWhitelistOp(fake_email_, true, &d));
@@ -199,13 +246,13 @@ TEST_F(SignedSettingsTest, Whitelist) {
EXPECT_CALL(m_, StartSigningAttempt(fake_email_, _))
.Times(1);
- EXPECT_TRUE(s->Execute());
+ s->Execute();
s->OnKeyOpComplete(OwnerManager::SUCCESS, std::vector<uint8>());
- message_loop_.Run();
+ message_loop_.RunAllPending();
}
TEST_F(SignedSettingsTest, Unwhitelist) {
- Quitter d(true);
+ DummyDelegate<bool> d(true);
d.expect_success();
scoped_refptr<SignedSettings> s(
SignedSettings::CreateWhitelistOp(fake_email_, false, &d));
@@ -214,9 +261,9 @@ TEST_F(SignedSettingsTest, Unwhitelist) {
EXPECT_CALL(m_, StartSigningAttempt(fake_email_, _))
.Times(1);
- EXPECT_TRUE(s->Execute());
+ s->Execute();
s->OnKeyOpComplete(OwnerManager::SUCCESS, std::vector<uint8>());
- message_loop_.Run();
+ message_loop_.RunAllPending();
}
TEST_F(SignedSettingsTest, WhitelistNoKey) {
@@ -228,7 +275,7 @@ TEST_F(SignedSettingsTest, WhitelistFailed) {
}
TEST_F(SignedSettingsTest, StoreProperty) {
- Quitter d(true);
+ DummyDelegate<bool> d(true);
d.expect_success();
scoped_refptr<SignedSettings> s(
SignedSettings::CreateStorePropertyOp(fake_prop_, fake_value_, &d));
@@ -238,10 +285,12 @@ TEST_F(SignedSettingsTest, StoreProperty) {
mock_service(s.get(), &m_);
EXPECT_CALL(m_, StartSigningAttempt(to_sign, _))
.Times(1);
+ EXPECT_CALL(m_, IsAlreadyOwned())
+ .WillOnce(Return(true));
- EXPECT_TRUE(s->Execute());
+ s->Execute();
s->OnKeyOpComplete(OwnerManager::SUCCESS, std::vector<uint8>());
- message_loop_.Run();
+ message_loop_.RunAllPending();
}
TEST_F(SignedSettingsTest, StorePropertyNoKey) {
@@ -263,11 +312,26 @@ TEST_F(SignedSettingsTest, RetrieveProperty) {
mock_service(s.get(), &m_);
EXPECT_CALL(m_, StartVerifyAttempt(to_verify, _, _))
.Times(1);
+ EXPECT_CALL(m_, IsAlreadyOwned())
+ .WillOnce(Return(true));
- EXPECT_TRUE(s->Execute());
+ s->Execute();
s->OnKeyOpComplete(OwnerManager::SUCCESS, std::vector<uint8>());
}
+TEST_F(SignedSettingsTest, RetrievePropertyNotFound) {
+ DummyDelegate<std::string> d(fake_value_);
+ scoped_refptr<SignedSettings> s(
+ SignedSettings::CreateRetrievePropertyOp(fake_prop_, &d));
+ d.expect_failure(SignedSettings::NOT_FOUND);
+ MockLoginLibrary* lib = MockLoginLib();
+ EXPECT_CALL(*lib, RetrieveProperty(fake_prop_, _, _))
+ .WillOnce(Return(false))
+ .RetiresOnSaturation();
+ s->Execute();
+ UnMockLoginLib();
+}
+
TEST_F(SignedSettingsTest, RetrievePropertyNoKey) {
FailingRetrievePropertyOp(OwnerManager::KEY_UNAVAILABLE);
}
diff --git a/chrome/browser/chromeos/login/test_attempt_state.cc b/chrome/browser/chromeos/login/test_attempt_state.cc
index b9a00b7..ecbf670 100644
--- a/chrome/browser/chromeos/login/test_attempt_state.cc
+++ b/chrome/browser/chromeos/login/test_attempt_state.cc
@@ -7,7 +7,7 @@
#include <string>
#include "chrome/common/net/gaia/gaia_auth_consumer.h"
-#include "cros/chromeos_cryptohome.h"
+#include "third_party/cros/chromeos_cryptohome.h"
namespace chromeos {
diff --git a/chrome/browser/chromeos/login/textfield_with_margin.cc b/chrome/browser/chromeos/login/textfield_with_margin.cc
index 8ad4cee..44d3432 100644
--- a/chrome/browser/chromeos/login/textfield_with_margin.cc
+++ b/chrome/browser/chromeos/login/textfield_with_margin.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/chromeos/login/textfield_with_margin.h"
+#include "chrome/browser/chromeos/login/helper.h"
+
namespace {
// Holds ratio of the margin to the preferred text height.
@@ -17,6 +19,12 @@ const int kVerticalMargin = 3;
namespace chromeos {
TextfieldWithMargin::TextfieldWithMargin() {
+ CorrectTextfieldFontSize(this);
+}
+
+TextfieldWithMargin::TextfieldWithMargin(views::Textfield::StyleFlags style)
+ : Textfield(style) {
+ CorrectTextfieldFontSize(this);
}
void TextfieldWithMargin::Layout() {
diff --git a/chrome/browser/chromeos/login/textfield_with_margin.h b/chrome/browser/chromeos/login/textfield_with_margin.h
index 338f79d..1bf3e54 100644
--- a/chrome/browser/chromeos/login/textfield_with_margin.h
+++ b/chrome/browser/chromeos/login/textfield_with_margin.h
@@ -15,11 +15,10 @@ namespace chromeos {
class TextfieldWithMargin : public views::Textfield {
public:
TextfieldWithMargin();
+ explicit TextfieldWithMargin(views::Textfield::StyleFlags style);
- explicit TextfieldWithMargin(views::Textfield::StyleFlags style)
- : Textfield(style) {}
-
- // Reimplements views::Textfield.
+ protected:
+ // Overridden from views::View:
virtual void Layout();
private:
diff --git a/chrome/browser/chromeos/login/user_controller.cc b/chrome/browser/chromeos/login/user_controller.cc
index f9e9e95..888803a 100644
--- a/chrome/browser/chromeos/login/user_controller.cc
+++ b/chrome/browser/chromeos/login/user_controller.cc
@@ -21,13 +21,14 @@
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
-#include "cros/chromeos_wm_ipc_enums.h"
+#include "third_party/cros/chromeos_wm_ipc_enums.h"
#include "gfx/canvas.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "views/background.h"
#include "views/controls/button/native_button.h"
#include "views/controls/label.h"
+#include "views/controls/throbber.h"
#include "views/grid_layout.h"
#include "views/painter.h"
#include "views/screen.h"
@@ -53,6 +54,9 @@ const int kControlsHeight = 31;
const int kControlsHeight = 28;
#endif
+// Vertical interval between the image and the textfield.
+const int kVerticalIntervalSize = 10;
+
// Widget that notifies window manager about clicking on itself.
// Doesn't send anything if user is selected.
class ClickNotifyingWidget : public views::WidgetGtk {
@@ -66,7 +70,7 @@ class ClickNotifyingWidget : public views::WidgetGtk {
private:
gboolean OnButtonPress(GtkWidget* widget, GdkEventButton* event) {
if (!controller_->is_user_selected())
- controller_->SelectUser(controller_->user_index());
+ controller_->SelectUserRelative(0);
return views::WidgetGtk::OnButtonPress(widget, event);
}
@@ -111,11 +115,11 @@ UserController::UserController(Delegate* delegate, bool is_guest)
label_window_(NULL),
unselected_label_window_(NULL),
user_view_(NULL),
- new_user_view_(NULL),
- existing_user_view_(NULL),
- guest_user_view_(NULL),
label_view_(NULL),
- unselected_label_view_(NULL) {
+ unselected_label_view_(NULL),
+ user_input_(NULL),
+ throbber_host_(NULL),
+ method_factory_(this) {
registrar_.Add(
this,
NotificationType::LOGIN_USER_IMAGE_CHANGED,
@@ -130,9 +134,7 @@ UserController::UserController(Delegate* delegate,
is_guest_(false),
// Empty 'cached_owner()' means that owner hasn't been cached yet, not
// that owner has an empty email.
- is_owner_(
- !user.email().empty() &&
- UserCrosSettingsProvider::cached_owner() == user.email()),
+ is_owner_(user.email() == UserCrosSettingsProvider::cached_owner()),
show_name_tooltip_(false),
user_(user),
delegate_(delegate),
@@ -142,11 +144,12 @@ UserController::UserController(Delegate* delegate,
label_window_(NULL),
unselected_label_window_(NULL),
user_view_(NULL),
- new_user_view_(NULL),
- existing_user_view_(NULL),
- guest_user_view_(NULL),
label_view_(NULL),
- unselected_label_view_(NULL) {
+ unselected_label_view_(NULL),
+ user_input_(NULL),
+ throbber_host_(NULL),
+ method_factory_(this) {
+ DCHECK(!user.email().empty());
registrar_.Add(
this,
NotificationType::LOGIN_USER_IMAGE_CHANGED,
@@ -179,16 +182,12 @@ void UserController::Init(int index,
CreateLabelWindow(index, WM_IPC_WINDOW_LOGIN_UNSELECTED_LABEL);
}
-void UserController::SetPasswordEnabled(bool enable) {
- DCHECK(!is_new_user_);
- existing_user_view_->password_field()->SetEnabled(enable);
- if (enable) {
- user_view_->StopThrobber();
- delegate_->SetStatusAreaEnabled(enable);
- } else {
- delegate_->SetStatusAreaEnabled(enable);
- user_view_->StartThrobber();
- }
+void UserController::StartThrobber() {
+ throbber_host_->StartThrobber();
+}
+
+void UserController::StopThrobber() {
+ throbber_host_->StopThrobber();
}
std::wstring UserController::GetNameTooltip() const {
@@ -213,25 +212,22 @@ std::wstring UserController::GetNameTooltip() const {
domain.c_str()));
}
+void UserController::ClearAndEnableFields() {
+ user_input_->ClearAndFocusControls();
+ user_input_->EnableInputControls(true);
+ SetStatusAreaEnabled(true);
+ StopThrobber();
+}
+
void UserController::ClearAndEnablePassword() {
- if (is_new_user_) {
- // TODO(avayvod): This code seems not reachable to me.
- new_user_view_->ClearAndEnablePassword();
- } else {
- existing_user_view_->password_field()->SetText(string16());
- SetPasswordEnabled(true);
- FocusPasswordField();
- }
+ user_input_->ClearAndFocusPassword();
+ user_input_->EnableInputControls(true);
+ SetStatusAreaEnabled(true);
+ StopThrobber();
}
-void UserController::ClearAndEnableFields() {
- if (is_new_user_) {
- new_user_view_->ClearAndEnableFields();
- } else if (is_guest_) {
- guest_user_view_->FocusSignInButton();
- } else {
- ClearAndEnablePassword();
- }
+gfx::Rect UserController::GetMainInputScreenBounds() const {
+ return user_input_->GetMainInputScreenBounds();
}
void UserController::EnableNameTooltip(bool enable) {
@@ -247,32 +243,6 @@ void UserController::EnableNameTooltip(bool enable) {
unselected_label_view_->SetTooltipText(tooltip_text);
}
-void UserController::ButtonPressed(views::Button* sender,
- const views::Event& event) {
- Login();
-}
-
-bool UserController::HandleKeystroke(
- views::Textfield* sender,
- const views::Textfield::Keystroke& keystroke) {
- if (keystroke.GetKeyboardCode() == app::VKEY_RETURN) {
- Login();
- return true;
- } else if (keystroke.GetKeyboardCode() == app::VKEY_LEFT) {
- SelectUser(user_index() - 1);
- return true;
- } else if (keystroke.GetKeyboardCode() == app::VKEY_RIGHT) {
- SelectUser(user_index() + 1);
- return true;
- }
- delegate_->ClearErrors();
- return false;
-}
-
-void UserController::ContentsChanged(views::Textfield* sender,
- const string16& new_contents) {
-}
-
void UserController::Observe(
NotificationType type,
const NotificationSource& source,
@@ -289,17 +259,6 @@ void UserController::Observe(
user_view_->SetImage(user_.image(), user_.image());
}
-void UserController::Login() {
- if (is_guest_) {
- delegate_->LoginOffTheRecord();
- } else {
- // Delegate will reenable as necessary.
- SetPasswordEnabled(false);
-
- delegate_->Login(this, existing_user_view_->password_field()->text());
- }
-}
-
void UserController::IsActiveChanged(bool active) {
is_user_selected_ = active;
if (active) {
@@ -341,25 +300,30 @@ WidgetGtk* UserController::CreateControlsWindow(
bool need_browse_without_signin) {
views::View* control_view;
if (is_new_user_) {
- new_user_view_ =
+ NewUserView* new_user_view =
new NewUserView(this, true, need_browse_without_signin);
- new_user_view_->Init();
- control_view = new_user_view_;
+ new_user_view->Init();
+ control_view = new_user_view;
+ user_input_ = new_user_view;
+ throbber_host_ = new_user_view;
} else if (is_guest_) {
- guest_user_view_ = new GuestUserView(this);
- guest_user_view_->RecreateFields();
- control_view = guest_user_view_;
+ GuestUserView* guest_user_view = new GuestUserView(this);
+ guest_user_view->RecreateFields();
+ control_view = guest_user_view;
+ user_input_ = guest_user_view;
+ throbber_host_ = guest_user_view;
} else {
- existing_user_view_ = new ExistingUserView(this);
- existing_user_view_->RecreateFields();
- control_view = existing_user_view_;
+ ExistingUserView* existing_user_view = new ExistingUserView(this);
+ existing_user_view->RecreateFields();
+ control_view = existing_user_view;
+ user_input_ = existing_user_view;
+ throbber_host_ = existing_user_view;
}
*height = kControlsHeight;
*width = kUserImageSize;
if (is_new_user_) {
- DCHECK(new_user_view_);
- gfx::Size size = new_user_view_->GetPreferredSize();
+ gfx::Size size = control_view->GetPreferredSize();
*width = size.width();
*height = size.height();
}
@@ -409,7 +373,7 @@ void UserController::CreateBorderWindow(int index,
int height = controls_height;
if (!is_new_user_) {
width += kBorderSize * 2;
- height += 3 * kBorderSize + kUserImageSize;
+ height += 2 * kBorderSize + kUserImageSize + kVerticalIntervalSize;
}
border_window_ = new WidgetGtk(WidgetGtk::TYPE_WINDOW);
@@ -461,8 +425,17 @@ WidgetGtk* UserController::CreateLabelWindow(int index,
text = UTF8ToWide(user_.GetDisplayName());
}
- views::Label *label = is_new_user_ ?
- new views::Label(text) : new UsernameView(text);
+ views::Label *label = NULL;
+
+ if (is_new_user_) {
+ label = new views::Label(text);
+ } else if (type == WM_IPC_WINDOW_LOGIN_LABEL) {
+ label = UsernameView::CreateShapedUsernameView(text, false);
+ } else {
+ DCHECK(type == WM_IPC_WINDOW_LOGIN_UNSELECTED_LABEL);
+ // TODO(altimofeev): switch to the rounded username view.
+ label = UsernameView::CreateShapedUsernameView(text, true);
+ }
label->SetColor(kTextColor);
label->SetFont(font);
@@ -489,16 +462,15 @@ WidgetGtk* UserController::CreateLabelWindow(int index,
return window;
}
-gfx::Rect UserController::GetScreenBounds() const {
- if (is_new_user_)
- return new_user_view_->GetUsernameBounds();
- else
- return existing_user_view_->password_field()->GetScreenBounds();
-}
-
void UserController::OnLogin(const std::string& username,
const std::string& password) {
- user_.set_email(username);
+ if (is_new_user_)
+ user_.set_email(username);
+
+ user_input_->EnableInputControls(false);
+ SetStatusAreaEnabled(false);
+ StartThrobber();
+
delegate_->Login(this, UTF8ToUTF16(password));
}
@@ -507,6 +479,10 @@ void UserController::OnCreateAccount() {
}
void UserController::OnLoginOffTheRecord() {
+ user_input_->EnableInputControls(false);
+ SetStatusAreaEnabled(false);
+ StartThrobber();
+
delegate_->LoginOffTheRecord();
}
@@ -515,19 +491,28 @@ void UserController::ClearErrors() {
}
void UserController::NavigateAway() {
- SelectUser(user_index() - 1);
+ SelectUserRelative(-1);
}
void UserController::OnRemoveUser() {
+ // Must not proceed without signature verification.
+ UserCrosSettingsProvider user_settings;
+ bool trusted_owner_available = user_settings.RequestTrustedOwner(
+ method_factory_.NewRunnableMethod(&UserController::OnRemoveUser));
+ if (!trusted_owner_available) {
+ // Value of owner email is still not verified.
+ // Another attempt will be invoked after verification completion.
+ return;
+ }
+ if (user().email() == UserCrosSettingsProvider::cached_owner()) {
+ // Owner is not allowed to be removed from the device.
+ return;
+ }
delegate_->RemoveUser(this);
}
-void UserController::SelectUser(int index) {
- delegate_->SelectUser(index);
-}
-
-void UserController::FocusPasswordField() {
- existing_user_view_->FocusPasswordField();
+void UserController::SelectUserRelative(int shift) {
+ delegate_->SelectUser(user_index() + shift);
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/user_controller.h b/chrome/browser/chromeos/login/user_controller.h
index 62608e6..7b894f1 100644
--- a/chrome/browser/chromeos/login/user_controller.h
+++ b/chrome/browser/chromeos/login/user_controller.h
@@ -9,6 +9,7 @@
#include <string>
#include "base/string16.h"
+#include "base/task.h"
#include "chrome/browser/chromeos/login/new_user_view.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/login/user_view.h"
@@ -19,23 +20,18 @@
#include "views/controls/button/button.h"
#include "views/controls/textfield/textfield.h"
#include "views/widget/widget_delegate.h"
-
namespace views {
class WidgetGtk;
}
namespace chromeos {
-class ExistingUserView;
-class GuestUserView;
-class UserView;
+class ThrobberManager;
// UserController manages the set of windows needed to login a single existing
// user or first time login for a new user. ExistingUserController creates
// the nececessary set of UserControllers.
-class UserController : public views::ButtonListener,
- public views::Textfield::Controller,
- public views::WidgetDelegate,
+class UserController : public views::WidgetDelegate,
public NewUserView::Delegate,
public NotificationObserver,
public UserView::Delegate {
@@ -80,36 +76,30 @@ class UserController : public views::ButtonListener,
bool is_user_selected() const { return is_user_selected_; }
bool is_new_user() const { return is_new_user_; }
bool is_guest() const { return is_guest_; }
- NewUserView* new_user_view() const { return new_user_view_; }
const UserManager::User& user() const { return user_; }
// Enables or disables tooltip with user's email.
void EnableNameTooltip(bool enable);
- // Resets password text and sets the enabled state of the password.
- void ClearAndEnablePassword();
-
// Called when user view is activated (OnUserSelected).
void ClearAndEnableFields();
- // Returns bounds of password field in screen coordinates.
- // For new user it returns username coordinates.
- gfx::Rect GetScreenBounds() const;
+ // Called when user view is activated (OnUserSelected).
+ void ClearAndEnablePassword();
// Get widget that contains all controls.
views::WidgetGtk* controls_window() {
return controls_window_;
}
- // ButtonListener:
- virtual void ButtonPressed(views::Button* sender, const views::Event& event);
+ // Returns bounds of the main input field in the screen coordinates (e.g.
+ // these bounds could be used to choose positions for the error bubble).
+ gfx::Rect GetMainInputScreenBounds() const;
- // Textfield::Controller:
- virtual void ContentsChanged(views::Textfield* sender,
- const string16& new_contents);
- virtual bool HandleKeystroke(views::Textfield* sender,
- const views::Textfield::Keystroke& keystroke);
+ // Starts/Stops throbber.
+ void StartThrobber();
+ void StopThrobber();
// views::WidgetDelegate:
virtual void IsActiveChanged(bool active);
@@ -136,11 +126,8 @@ class UserController : public views::ButtonListener,
// UserView::Delegate implementation:
virtual void OnRemoveUser();
- // Selects user entry with specified |index|.
- void SelectUser(int index);
-
- // Sets focus on password field.
- void FocusPasswordField();
+ // Selects user relative to the current user.
+ void SelectUserRelative(int shift);
// Padding between the user windows.
static const int kPadding;
@@ -152,9 +139,6 @@ class UserController : public views::ButtonListener,
private:
FRIEND_TEST(UserControllerTest, GetNameTooltip);
- // Invoked when the user wants to login. Forwards the call to the delegate.
- void Login();
-
// Performs common setup for login windows.
void ConfigureLoginWindow(views::WidgetGtk* window,
int index,
@@ -176,9 +160,6 @@ class UserController : public views::ButtonListener,
// itself.
void SetImage(const SkBitmap& image);
- // Sets the enabled state of the password field to |enable|.
- void SetPasswordEnabled(bool enable);
-
// Returns tooltip text for user name.
std::wstring GetNameTooltip() const;
@@ -216,21 +197,20 @@ class UserController : public views::ButtonListener,
// View that shows user image on image window.
UserView* user_view_;
- // View that is used for new user login.
- NewUserView* new_user_view_;
-
- // View that is used for existing user login.
- ExistingUserView* existing_user_view_;
-
- // View that is used for guest user login.
- GuestUserView* guest_user_view_;
-
// Views that show display name of the user.
views::Label* label_view_;
views::Label* unselected_label_view_;
+ // Input controls which are used for username and password.
+ UserInput* user_input_;
+
+ // Throbber host that can show a throbber.
+ ThrobberHostView* throbber_host_;
+
NotificationRegistrar registrar_;
+ ScopedRunnableMethodFactory<UserController> method_factory_;
+
DISALLOW_COPY_AND_ASSIGN(UserController);
};
diff --git a/chrome/browser/chromeos/login/user_image_downloader.cc b/chrome/browser/chromeos/login/user_image_downloader.cc
index 080ca41..2efa796 100644
--- a/chrome/browser/chromeos/login/user_image_downloader.cc
+++ b/chrome/browser/chromeos/login/user_image_downloader.cc
@@ -10,12 +10,11 @@
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/values.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/chromeos/login/authenticator.h"
#include "chrome/browser/chromeos/login/image_downloader.h"
#include "chrome/browser/chromeos/login/user_manager.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/common/net/url_fetcher.h"
#include "googleurl/src/gurl.h"
diff --git a/chrome/browser/chromeos/login/user_image_screen.cc b/chrome/browser/chromeos/login/user_image_screen.cc
index d4b67c4..3c0abff 100644
--- a/chrome/browser/chromeos/login/user_image_screen.cc
+++ b/chrome/browser/chromeos/login/user_image_screen.cc
@@ -133,13 +133,6 @@ void UserImageScreen::OnOK(const SkBitmap& image) {
void UserImageScreen::OnSkip() {
if (camera_.get())
camera_->Uninitialize();
- UserManager* user_manager = UserManager::Get();
- DCHECK(user_manager);
-
- const UserManager::User& user = user_manager->logged_in_user();
- DCHECK(!user.email().empty());
-
- user_manager->SetDefaultUserImage(user.email());
if (delegate())
delegate()->GetObserver(this)->OnExit(ScreenObserver::USER_IMAGE_SKIPPED);
}
diff --git a/chrome/browser/chromeos/login/user_image_view.cc b/chrome/browser/chromeos/login/user_image_view.cc
index d3412ca..5ef45a6 100644
--- a/chrome/browser/chromeos/login/user_image_view.cc
+++ b/chrome/browser/chromeos/login/user_image_view.cc
@@ -12,7 +12,7 @@
#include "chrome/browser/chromeos/login/helper.h"
#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
#include "chrome/browser/chromeos/login/wizard_accessibility_helper.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "gfx/canvas.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
diff --git a/chrome/browser/chromeos/login/user_input.h b/chrome/browser/chromeos/login/user_input.h
new file mode 100644
index 0000000..565f928
--- /dev/null
+++ b/chrome/browser/chromeos/login/user_input.h
@@ -0,0 +1,33 @@
+// 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_USER_INPUT_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_USER_INPUT_H_
+
+#include "gfx/rect.h"
+
+namespace chromeos {
+
+// Interface that is used to manage the state of the user input controls.
+class UserInput {
+ public:
+ virtual ~UserInput() {}
+
+ // Enables/Disables the input controls.
+ virtual void EnableInputControls(bool enabled) = 0;
+
+ // Clears and focuses the controls.
+ virtual void ClearAndFocusControls() = 0;
+
+ // Clears and focuses the password field.
+ virtual void ClearAndFocusPassword() = 0;
+
+ // Returns bounds of the main input field in the screen coordinates (e.g.
+ // these bounds could be used to choose positions for the error bubble).
+ virtual gfx::Rect GetMainInputScreenBounds() const = 0;
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_LOGIN_USER_INPUT_H_
diff --git a/chrome/browser/chromeos/login/user_manager.cc b/chrome/browser/chromeos/login/user_manager.cc
index 57cf4bc..4c325c2 100644
--- a/chrome/browser/chromeos/login/user_manager.cc
+++ b/chrome/browser/chromeos/login/user_manager.cc
@@ -273,6 +273,8 @@ void UserManager::UserLoggedIn(const std::string& email) {
}
prefs->SavePersistentPrefs();
NotifyOnLogin();
+ if (current_user_is_new_)
+ SetDefaultUserImage(email);
}
void UserManager::RemoveUser(const std::string& email) {
diff --git a/chrome/browser/chromeos/login/user_manager.h b/chrome/browser/chromeos/login/user_manager.h
index 01b05d4..428513f 100644
--- a/chrome/browser/chromeos/login/user_manager.h
+++ b/chrome/browser/chromeos/login/user_manager.h
@@ -86,10 +86,6 @@ class UserManager : public UserImageLoader::Delegate,
void SaveUserImage(const std::string& username,
const SkBitmap& image);
- // Sets one of the default images to the specified user and saves this
- // setting in local state.
- void SetDefaultUserImage(const std::string& username);
-
// chromeos::UserImageLoader::Delegate implementation.
virtual void OnImageLoaded(const std::string& username,
const SkBitmap& image);
@@ -125,6 +121,10 @@ class UserManager : public UserImageLoader::Delegate,
// Notifies on new user session.
void NotifyOnLogin();
+ // Sets one of the default images to the specified user and saves this
+ // setting in local state.
+ void SetDefaultUserImage(const std::string& username);
+
// Loads user image from its file.
scoped_refptr<UserImageLoader> image_loader_;
diff --git a/chrome/browser/chromeos/login/user_view.cc b/chrome/browser/chromeos/login/user_view.cc
index 79365ce..e359251 100644
--- a/chrome/browser/chromeos/login/user_view.cc
+++ b/chrome/browser/chromeos/login/user_view.cc
@@ -8,7 +8,11 @@
#include "app/resource_bundle.h"
#include "chrome/browser/chromeos/login/helper.h"
#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
+#include "chrome/browser/chromeos/login/rounded_view.h"
+#include "gfx/canvas.h"
#include "gfx/canvas_skia.h"
+#include "gfx/gtk_util.h"
+#include "gfx/rect.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "views/background.h"
@@ -16,7 +20,6 @@
#include "views/controls/image_view.h"
#include "views/controls/label.h"
#include "views/controls/link.h"
-#include "views/controls/throbber.h"
#include "views/painter.h"
namespace {
@@ -229,6 +232,12 @@ class PodImageView : public views::ImageView {
views::ImageView::SetImage(image_);
}
+ gfx::NativeCursor GetCursorForPoint(
+ views::Event::EventType event_type,
+ const gfx::Point& p) {
+ return gfx::GetCursor(GDK_HAND2);
+ }
+
private:
SkBitmap image_;
SkBitmap image_hot_;
@@ -239,13 +248,17 @@ class PodImageView : public views::ImageView {
UserView::UserView(Delegate* delegate, bool is_login, bool need_background)
: delegate_(delegate),
signout_view_(NULL),
- image_view_(new PodImageView()),
- throbber_(CreateDefaultSmoothedThrobber()),
+ image_view_(NULL),
remove_button_(NULL) {
DCHECK(delegate);
if (!is_login)
signout_view_ = new SignoutView(this);
+ if (need_background)
+ image_view_ = new RoundedView<PodImageView>;
+ else
+ image_view_ = new PodImageView;
+
Init(need_background);
}
@@ -254,20 +267,11 @@ void UserView::Init(bool need_background) {
image_view_->set_background(
views::Background::CreateSolidBackground(kBackgroundColor));
}
- if (throbber_) {
- int w = throbber_->GetPreferredSize().width();
- int h = throbber_->GetPreferredSize().height();
- throbber_->SetBounds(kUserImageSize / 2 - w / 2,
- kUserImageSize / 2 - h / 2 , w, h);
- // Throbber should be actually hidden while stopped so tooltip manager
- // doesn't find it.
- throbber_->SetVisible(false);
- image_view_->AddChildView(throbber_);
- }
// UserView's layout never changes, so let's layout once here.
image_view_->SetBounds(0, 0, kUserImageSize, kUserImageSize);
AddChildView(image_view_);
+
if (signout_view_) {
signout_view_->SetBounds(0, kUserImageSize, kUserImageSize,
signout_view_->GetPreferredSize().height());
@@ -298,16 +302,6 @@ void UserView::SetTooltipText(const std::wstring& text) {
image_view_->SetTooltipText(text);
}
-void UserView::StartThrobber() {
- throbber_->SetVisible(true);
- throbber_->Start();
-}
-
-void UserView::StopThrobber() {
- throbber_->Stop();
- throbber_->SetVisible(false);
-}
-
gfx::Size UserView::GetPreferredSize() {
return gfx::Size(
kUserImageSize,
diff --git a/chrome/browser/chromeos/login/user_view.h b/chrome/browser/chromeos/login/user_view.h
index ed4b030..5d4182c 100644
--- a/chrome/browser/chromeos/login/user_view.h
+++ b/chrome/browser/chromeos/login/user_view.h
@@ -56,10 +56,6 @@ class UserView : public views::View,
// Sets tooltip over the image.
void SetTooltipText(const std::wstring& text);
- // Start/Stop throbber.
- void StartThrobber();
- void StopThrobber();
-
// Show/Hide remove button.
void SetRemoveButtonVisible(bool flag);
@@ -81,8 +77,6 @@ class UserView : public views::View,
SignoutView* signout_view_;
PodImageView* image_view_;
- views::Throbber* throbber_;
-
views::TextButton* remove_button_;
DISALLOW_COPY_AND_ASSIGN(UserView);
diff --git a/chrome/browser/chromeos/login/username_view.cc b/chrome/browser/chromeos/login/username_view.cc
index 526d7c4..5aead72 100644
--- a/chrome/browser/chromeos/login/username_view.cc
+++ b/chrome/browser/chromeos/login/username_view.cc
@@ -6,21 +6,73 @@
#include "base/logging.h"
#include "base/utf_string_conversions.h"
+#include "chrome/browser/chromeos/login/rounded_view.h"
#include "gfx/canvas.h"
#include "gfx/canvas_skia.h"
#include "gfx/rect.h"
+#include "third_party/skia/include/core/SkColorShader.h"
#include "third_party/skia/include/core/SkComposeShader.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
+namespace chromeos {
+
namespace {
// Username label background color.
const SkColor kLabelBackgoundColor = 0x55000000;
// Holds margin to height ratio.
const double kMarginRatio = 1.0 / 3.0;
-} // namespace
-
-namespace chromeos {
+// Holds the frame width for the small shaped username view.
+const SkScalar kSmallShapeFrameWidth = SkIntToScalar(1);
+
+// Class that sets up half rounded rectangle (only the bottom corners are
+// rounded) as a clip region of the view.
+// For more info see the file "chrome/browser/chromeos/login/rounded_view.h".
+template<typename C>
+class HalfRoundedView : public RoundedView<C> {
+ public:
+ HalfRoundedView(const std::wstring &text, bool use_small_shape)
+ : RoundedView<C>(text), use_small_shape_(use_small_shape) {
+ }
+
+ protected:
+ // Overrides ViewFilter.
+ virtual SkPath GetClipPath() const {
+ if (!use_small_shape_) {
+ return RoundedView<C>::GetClipPath();
+ } else {
+ SkPath path;
+ gfx::Rect frame_bounds = this->bounds();
+ frame_bounds.Inset(kSmallShapeFrameWidth, kSmallShapeFrameWidth,
+ kSmallShapeFrameWidth, kSmallShapeFrameWidth);
+ path.addRect(SkIntToScalar(frame_bounds.x()),
+ SkIntToScalar(frame_bounds.y()),
+ SkIntToScalar(frame_bounds.x() + frame_bounds.width()),
+ SkIntToScalar(frame_bounds.y() + frame_bounds.height()));
+ return path;
+ }
+ }
+
+ virtual void DrawFrame(gfx::Canvas* canvas) {
+ // No frame is needed.
+ }
+
+ virtual SkRect GetViewRect() const {
+ SkRect view_rect;
+ // The rectangle will be intersected with the bounds, so the correct half
+ // of the round rectangle will be obtained.
+ view_rect.iset(this->x(),
+ this->y() - this->height(),
+ this->x() + this->width(),
+ this->y() + this->height());
+ return view_rect;
+ }
+
+ private:
+ // Whether the shape for the smaller view should be used.
+ bool use_small_shape_;
+};
+} // namespace
UsernameView::UsernameView(const std::wstring& username)
: views::Label(username) {
}
@@ -29,70 +81,100 @@ void UsernameView::Paint(gfx::Canvas* canvas) {
gfx::Rect bounds = GetLocalBounds(false);
if (!text_image_.get())
PaintUsername(bounds);
-
DCHECK(bounds.size() ==
gfx::Size(text_image_->width(), text_image_->height()));
+ canvas->DrawBitmapInt(*text_image_, bounds.x(), bounds.y());
+}
+
+// static
+UsernameView* UsernameView::CreateShapedUsernameView(
+ const std::wstring& username,
+ bool use_small_shape) {
+ return new HalfRoundedView<UsernameView>(username, use_small_shape);
+}
+
+void UsernameView::PaintUsername(const gfx::Rect& bounds) {
+ margin_width_ = bounds.height() * kMarginRatio;
+ gfx::CanvasSkia canvas(bounds.width(), bounds.height(), false);
+ // Draw transparent background.
+ canvas.drawColor(0);
+
+ // Calculate needed space.
+ int flags = gfx::Canvas::TEXT_ALIGN_LEFT |
+ gfx::Canvas::TEXT_VALIGN_MIDDLE |
+ gfx::Canvas::NO_ELLIPSIS;
+ int text_height, text_width;
+ gfx::CanvasSkia::SizeStringInt(WideToUTF16Hack(GetText()), font(),
+ &text_width, &text_height,
+ flags);
+ text_width += margin_width_;
+
+ // Also leave the right margin.
+ bool use_fading_for_text = text_width + margin_width_ >= bounds.width();
+
// Only alpha channel counts.
SkColor gradient_colors[2];
gradient_colors[0] = 0xFFFFFFFF;
gradient_colors[1] = 0x00FFFFFF;
- int gradient_start = std::min(margin_width_ + text_width_,
- bounds.width() - bounds.height());
+ int gradient_start = use_fading_for_text ?
+ bounds.width() - bounds.height() - margin_width_ :
+ text_width;
+ int gradient_end = std::min(gradient_start + bounds.height(),
+ bounds.width() - margin_width_);
SkPoint gradient_borders[2];
gradient_borders[0].set(SkIntToScalar(gradient_start), SkIntToScalar(0));
- gradient_borders[1].set(SkIntToScalar(
- gradient_start + bounds.height()), SkIntToScalar(0));
+ gradient_borders[1].set(SkIntToScalar(gradient_end), SkIntToScalar(0));
SkShader* gradient_shader =
SkGradientShader::CreateLinear(gradient_borders, gradient_colors, NULL, 2,
SkShader::kClamp_TileMode, NULL);
- SkShader* image_shader = SkShader::CreateBitmapShader(
- *text_image_,
- SkShader::kRepeat_TileMode,
- SkShader::kRepeat_TileMode);
-
- SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrcIn_Mode);
- SkShader* composite_shader = new SkComposeShader(gradient_shader,
- image_shader, mode);
- gradient_shader->unref();
- image_shader->unref();
-
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setFilterBitmap(true);
- paint.setShader(composite_shader)->unref();
- canvas->DrawRectInt(bounds.x(), bounds.y(),
- bounds.width(), bounds.height(), paint);
-}
-void UsernameView::PaintUsername(const gfx::Rect& bounds) {
- margin_width_ = bounds.height() * kMarginRatio;
- gfx::CanvasSkia canvas(bounds.width(), bounds.height(), false);
- // Draw background.
- canvas.drawColor(kLabelBackgoundColor);
- // Calculate needed space.
- int flags = gfx::Canvas::TEXT_ALIGN_LEFT |
- gfx::Canvas::TEXT_VALIGN_MIDDLE |
- gfx::Canvas::NO_ELLIPSIS;
- int text_height;
- gfx::CanvasSkia::SizeStringInt(WideToUTF16Hack(GetText()), font(),
- &text_width_, &text_height,
- flags);
- text_width_ = std::min(text_width_, bounds.width() - margin_width_);
+ if (!use_fading_for_text) {
+ // Draw the final background with the fading in the end.
+ SkShader* solid_shader = new SkColorShader(kLabelBackgoundColor);
+ SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrcIn_Mode);
+ SkShader* composite_shader = new SkComposeShader(gradient_shader,
+ solid_shader, mode);
+ gradient_shader->unref();
+ solid_shader->unref();
+
+ SkPaint paint;
+ paint.setShader(composite_shader)->unref();
+ canvas.drawPaint(paint);
+ }
+
// Draw the text.
// Note, direct call of the DrawStringInt method produces the green dots
// along the text perimeter (when the label is place on the white background).
SkColor kInvisibleHaloColor = 0x00000000;
canvas.DrawStringWithHalo(GetText(), font(), GetColor(), kInvisibleHaloColor,
bounds.x() + margin_width_, bounds.y(),
- bounds.width() - margin_width_, bounds.height(),
+ bounds.width() - 2 * margin_width_, bounds.height(),
flags);
text_image_.reset(new SkBitmap(canvas.ExtractBitmap()));
- text_image_->buildMipMap(false);
+
+ if (use_fading_for_text) {
+ // Fade out only the text in the end. Use regualar background.
+ canvas.drawColor(kLabelBackgoundColor, SkXfermode::kSrc_Mode);
+ SkShader* image_shader = SkShader::CreateBitmapShader(
+ *text_image_,
+ SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode);
+ SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrcIn_Mode);
+ SkShader* composite_shader = new SkComposeShader(gradient_shader,
+ image_shader, mode);
+ gradient_shader->unref();
+ image_shader->unref();
+
+ SkPaint paint;
+ paint.setShader(composite_shader)->unref();
+ canvas.drawPaint(paint);
+ text_image_.reset(new SkBitmap(canvas.ExtractBitmap()));
+ }
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/username_view.h b/chrome/browser/chromeos/login/username_view.h
index f1ad180..3ea81aa 100644
--- a/chrome/browser/chromeos/login/username_view.h
+++ b/chrome/browser/chromeos/login/username_view.h
@@ -20,22 +20,31 @@ namespace chromeos {
// Label with customized paddings and long text fade out.
class UsernameView : public views::Label {
public:
- UsernameView(const std::wstring& username);
virtual ~UsernameView() {}
// Overriden from views::Label.
virtual void Paint(gfx::Canvas* canvas);
+ // Returns the shaped username view to be used on the login screen. If
+ // |user_small_shape| is true, then one pixel margins are used. This is done
+ // to match the shape of the scaled frame of the user image. The caller gets
+ // the ownership.
+ static UsernameView* CreateShapedUsernameView(const std::wstring& username,
+ bool use_small_shape);
+
+ protected:
+ // Constructs username view for the given |username|. Consider using
+ // |CreateShapedUsernameView| to match the login page style.
+ explicit UsernameView(const std::wstring& username);
+
private:
+
// Paints username to the bitmap with the bounds given.
void PaintUsername(const gfx::Rect& bounds);
// Holds painted username.
scoped_ptr<SkBitmap> text_image_;
- // Holds width of the text drawn.
- int text_width_;
-
// Holds margins width (depends on the height).
int margin_width_;
diff --git a/chrome/browser/chromeos/login/wizard_accessibility_handler.cc b/chrome/browser/chromeos/login/wizard_accessibility_handler.cc
index e98201e..ab24214 100644
--- a/chrome/browser/chromeos/login/wizard_accessibility_handler.cc
+++ b/chrome/browser/chromeos/login/wizard_accessibility_handler.cc
@@ -12,15 +12,14 @@
#include "base/scoped_ptr.h"
#include "base/string_number_conversions.h"
#include "chrome/browser/accessibility_events.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/speech_synthesis_library.h"
#include "chrome/browser/extensions/extension_accessibility_api.h"
#include "chrome/browser/extensions/extension_accessibility_api_constants.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/common/notification_details.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
#include "grit/generated_resources.h"
namespace keys = extension_accessibility_api_constants;
diff --git a/chrome/browser/chromeos/login/wizard_accessibility_helper.cc b/chrome/browser/chromeos/login/wizard_accessibility_helper.cc
index 42fb25e..c8c8668 100644
--- a/chrome/browser/chromeos/login/wizard_accessibility_helper.cc
+++ b/chrome/browser/chromeos/login/wizard_accessibility_helper.cc
@@ -4,16 +4,18 @@
#include "chrome/browser/chromeos/login/wizard_accessibility_helper.h"
+#include "app/l10n_util.h"
#include "base/logging.h"
#include "base/stl_util-inl.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extension_accessibility_api.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
+#include "grit/generated_resources.h"
#include "views/accelerator.h"
#include "views/view.h"
@@ -23,13 +25,9 @@ scoped_ptr<views::Accelerator> WizardAccessibilityHelper::accelerator_;
// static
views::Accelerator WizardAccessibilityHelper::GetAccelerator() {
- // Use an accelerator that would never match any hotkey to temporarily
- // disable the accessibility hotkey per http://crosbug.com/9195
- // TODO(xiyuan): Change back to real hotkey as the following
- // new views::Accelerator(app::VKEY_Z, false, true, true)
if (!WizardAccessibilityHelper::accelerator_.get())
WizardAccessibilityHelper::accelerator_.reset(
- new views::Accelerator(app::VKEY_UNKNOWN, 0xdeadbeef));
+ new views::Accelerator(app::VKEY_Z, false, true, true));
return *(WizardAccessibilityHelper::accelerator_.get());
}
@@ -70,12 +68,16 @@ void WizardAccessibilityHelper::UnregisterNotifications() {
registered_notifications_ = false;
}
+bool WizardAccessibilityHelper::IsAccessibilityEnabled() {
+ return g_browser_process &&
+ g_browser_process->local_state()->GetBoolean(
+ prefs::kAccessibilityEnabled);
+}
+
void WizardAccessibilityHelper::MaybeEnableAccessibility(
views::View* view_tree) {
- if (g_browser_process &&
- g_browser_process->local_state()->GetBoolean(
- prefs::kAccessibilityEnabled)) {
- EnableAccessibility(view_tree);
+ if (IsAccessibilityEnabled()) {
+ EnableAccessibilityForView(view_tree);
} else {
AddViewToBuffer(view_tree);
}
@@ -83,39 +85,54 @@ void WizardAccessibilityHelper::MaybeEnableAccessibility(
void WizardAccessibilityHelper::MaybeSpeak(const char* str, bool queue,
bool interruptible) {
- if (g_browser_process &&
- g_browser_process->local_state()->GetBoolean(
- prefs::kAccessibilityEnabled)) {
+ if (IsAccessibilityEnabled()) {
accessibility_handler_->Speak(str, queue, interruptible);
}
}
-void WizardAccessibilityHelper::EnableAccessibility(views::View* view_tree) {
+void WizardAccessibilityHelper::EnableAccessibilityForView(
+ views::View* view_tree) {
VLOG(1) << "Enabling accessibility.";
if (!registered_notifications_)
RegisterNotifications();
+ SetAccessibilityEnabled(true);
+ if (view_tree) {
+ AddViewToBuffer(view_tree);
+ // If accessibility pref is set, enable accessibility for all views in
+ // the buffer for which access is not yet enabled.
+ for (std::map<views::View*, bool>::iterator iter =
+ views_buffer_.begin();
+ iter != views_buffer_.end(); ++iter) {
+ if (!(*iter).second) {
+ AccessibleViewHelper *helper = new AccessibleViewHelper((*iter).first,
+ profile_);
+ accessible_view_helpers_.push_back(helper);
+ (*iter).second = true;
+ }
+ }
+ }
+}
+
+void WizardAccessibilityHelper::ToggleAccessibility(views::View* view_tree) {
+ if (!IsAccessibilityEnabled()) {
+ EnableAccessibilityForView(view_tree);
+ } else {
+ SetAccessibilityEnabled(false);
+ }
+}
+
+void WizardAccessibilityHelper::SetAccessibilityEnabled(bool enabled) {
if (g_browser_process) {
PrefService* prefService = g_browser_process->local_state();
- if (!prefService->GetBoolean(prefs::kAccessibilityEnabled)) {
- prefService->SetBoolean(prefs::kAccessibilityEnabled, true);
- prefService->ScheduleSavePersistentPrefs();
- }
+ prefService->SetBoolean(prefs::kAccessibilityEnabled, enabled);
+ prefService->ScheduleSavePersistentPrefs();
}
ExtensionAccessibilityEventRouter::GetInstance()->
- SetAccessibilityEnabled(true);
- AddViewToBuffer(view_tree);
- // If accessibility pref is set, enable accessibility for all views in
- // the buffer for which access is not yet enabled.
- for (std::map<views::View*, bool>::iterator iter =
- views_buffer_.begin();
- iter != views_buffer_.end(); ++iter) {
- if (!(*iter).second) {
- AccessibleViewHelper *helper = new AccessibleViewHelper((*iter).first,
- profile_);
- accessible_view_helpers_.push_back(helper);
- (*iter).second = true;
- }
- }
+ SetAccessibilityEnabled(enabled);
+ accessibility_handler_->Speak(enabled ?
+ l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_ACCESS_ENABLED).c_str() :
+ l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_ACCESS_DISABLED).c_str(),
+ false, true);
}
void WizardAccessibilityHelper::AddViewToBuffer(views::View* view_tree) {
diff --git a/chrome/browser/chromeos/login/wizard_accessibility_helper.h b/chrome/browser/chromeos/login/wizard_accessibility_helper.h
index f3b2963..c27ef3c 100644
--- a/chrome/browser/chromeos/login/wizard_accessibility_helper.h
+++ b/chrome/browser/chromeos/login/wizard_accessibility_helper.h
@@ -37,7 +37,7 @@ class WizardAccessibilityHelper {
// Enables Accessibility by setting the accessibility pref and registers
// all views in the view buffer to raise accessibility notifications,
// including the specified |view_tree|.
- void EnableAccessibility(views::View* view_tree);
+ void EnableAccessibilityForView(views::View* view_tree);
// Enables accessibility for the specified |view_tree| if the
// accessibility pref is already set. Otherwise the |view_tree| is
@@ -54,6 +54,11 @@ class WizardAccessibilityHelper {
// Unregisters all accessibility notifications
void UnregisterNotifications();
+ // Toggles accessibility support. If |view_tree| is null, only the
+ // access preference setting is toggled. |view_tree| has no effect while
+ // disabling accessibility.
+ void ToggleAccessibility(views::View* view_tree);
+
private:
friend struct DefaultSingletonTraits<WizardAccessibilityHelper>;
@@ -63,6 +68,10 @@ class WizardAccessibilityHelper {
void RegisterNotifications();
+ bool IsAccessibilityEnabled();
+
+ void SetAccessibilityEnabled(bool);
+
static scoped_ptr<views::Accelerator> accelerator_;
void AddViewToBuffer(views::View* view_tree);
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index a937e45..a3b7efd 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -43,12 +43,12 @@
#include "chrome/browser/chromeos/login/wizard_accessibility_helper.h"
#include "chrome/browser/chromeos/wm_ipc.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
-#include "cros/chromeos_wm_ipc_enums.h"
+#include "third_party/cros/chromeos_wm_ipc_enums.h"
#include "unicode/timezone.h"
#include "views/accelerator.h"
#include "views/painter.h"
@@ -80,7 +80,7 @@ const int kWaitForRebootTimeSec = 3;
class ContentView : public views::View {
public:
ContentView()
- : accel_enable_accessibility_(
+ : accel_toggle_accessibility_(
chromeos::WizardAccessibilityHelper::GetAccelerator()) {
#if defined(OFFICIAL_BUILD)
accel_cancel_update_ = views::Accelerator(app::VKEY_ESCAPE,
@@ -110,7 +110,7 @@ class ContentView : public views::View {
AddAccelerator(accel_eula_screen_);
AddAccelerator(accel_register_screen_);
#endif
- AddAccelerator(accel_enable_accessibility_);
+ AddAccelerator(accel_toggle_accessibility_);
AddAccelerator(accel_cancel_update_);
}
@@ -126,8 +126,8 @@ class ContentView : public views::View {
if (!controller)
return false;
- if (accel == accel_enable_accessibility_) {
- chromeos::WizardAccessibilityHelper::GetInstance()->EnableAccessibility(
+ if (accel == accel_toggle_accessibility_) {
+ chromeos::WizardAccessibilityHelper::GetInstance()->ToggleAccessibility(
controller->contents()); }
else if (accel == accel_cancel_update_) {
controller->CancelOOBEUpdate();
@@ -174,7 +174,7 @@ class ContentView : public views::View {
views::Accelerator accel_eula_screen_;
views::Accelerator accel_register_screen_;
#endif
- views::Accelerator accel_enable_accessibility_;
+ views::Accelerator accel_toggle_accessibility_;
views::Accelerator accel_cancel_update_;
DISALLOW_COPY_AND_ASSIGN(ContentView);
diff --git a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
index 9bf0618..7d8121b 100644
--- a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
@@ -15,7 +15,6 @@
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/chromeos/login/wizard_in_process_browser_test.h"
#include "chrome/common/chrome_switches.h"
-#include "chrome/common/notification_service.h"
#include "chrome/test/ui_test_utils.h"
#include "grit/generated_resources.h"
#include "testing/gmock/include/gmock/gmock.h"
diff --git a/chrome/browser/chromeos/metrics_cros_settings_provider.cc b/chrome/browser/chromeos/metrics_cros_settings_provider.cc
index ba36cc2..47759bc 100644
--- a/chrome/browser/chromeos/metrics_cros_settings_provider.cc
+++ b/chrome/browser/chromeos/metrics_cros_settings_provider.cc
@@ -8,7 +8,8 @@
#include "base/values.h"
#include "chrome/browser/chromeos/cros_settings.h"
#include "chrome/browser/chromeos/cros_settings_names.h"
-#include "chrome/browser/options_util.h"
+#include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/ui/options/options_util.h"
#include "chrome/installer/util/google_update_settings.h"
#if defined(USE_LINUX_BREAKPAD)
@@ -36,6 +37,11 @@ bool MetricsCrosSettingsProvider::Get(const std::string& path,
// static
bool MetricsCrosSettingsProvider::SetMetricsStatus(bool enabled) {
+ // We must be not logged in (on EULA page) or logged is as an owner to be able
+ // to modify the setting.
+ UserManager *user = UserManager::Get();
+ if (user->user_is_logged_in() && !user->current_user_is_owner())
+ return false;
VLOG(1) << "Setting cros stats/crash metric reporting to " << enabled;
if (enabled != GoogleUpdateSettings::GetCollectStatsConsent()) {
bool new_enabled = OptionsUtil::ResolveMetricsReportingEnabled(enabled);
diff --git a/chrome/browser/chromeos/network_message_observer.cc b/chrome/browser/chromeos/network_message_observer.cc
index 9a8f2e4..872dc73 100644
--- a/chrome/browser/chromeos/network_message_observer.cc
+++ b/chrome/browser/chromeos/network_message_observer.cc
@@ -16,7 +16,7 @@
#include "chrome/browser/chromeos/notifications/balloon_view_host.h"
#include "chrome/browser/chromeos/options/network_config_view.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/views/window.h"
#include "chrome/common/pref_names.h"
@@ -98,7 +98,7 @@ void NetworkMessageObserver::OpenMoreInfoPage(const ListValue* args) {
return;
chromeos::NetworkLibrary* lib =
chromeos::CrosLibrary::Get()->GetNetworkLibrary();
- chromeos::CellularNetwork* cellular = lib->cellular_network();
+ const chromeos::CellularNetwork* cellular = lib->cellular_network();
if (!cellular)
return;
browser->ShowSingletonTab(GURL(cellular->payment_url()), false);
@@ -132,7 +132,7 @@ void NetworkMessageObserver::OnNetworkManagerChanged(NetworkLibrary* obj) {
if (wifi->error() == ERROR_BAD_PASSPHRASE ||
wifi->error() == ERROR_BAD_WEPKEY) {
// The NetworkConfigView will show the appropriate error message.
- view = new NetworkConfigView(wifi, true);
+ view = new NetworkConfigView(wifi);
// There should only be one wifi network that failed to connect.
// If for some reason, we have more than one failure,
// we only display the first one. So we break here.
diff --git a/chrome/browser/chromeos/network_state_notifier.cc b/chrome/browser/chromeos/network_state_notifier.cc
index 80acfaf..b940845 100644
--- a/chrome/browser/chromeos/network_state_notifier.cc
+++ b/chrome/browser/chromeos/network_state_notifier.cc
@@ -17,7 +17,7 @@ using base::Time;
using base::TimeDelta;
// static
-NetworkStateNotifier* NetworkStateNotifier::Get() {
+NetworkStateNotifier* NetworkStateNotifier::GetInstance() {
return Singleton<NetworkStateNotifier>::get();
}
@@ -27,7 +27,7 @@ TimeDelta NetworkStateNotifier::GetOfflineDuration() {
// TODO(oshima): make this instance method so that
// we can mock this for ui_tests.
// http://crbug.com/4825 .
- return base::Time::Now() - Get()->offline_start_time_;
+ return base::Time::Now() - GetInstance()->offline_start_time_;
}
NetworkStateNotifier::NetworkStateNotifier()
diff --git a/chrome/browser/chromeos/network_state_notifier.h b/chrome/browser/chromeos/network_state_notifier.h
index 94e57f4..31103f0 100644
--- a/chrome/browser/chromeos/network_state_notifier.h
+++ b/chrome/browser/chromeos/network_state_notifier.h
@@ -48,7 +48,7 @@ class NetworkStateDetails {
class NetworkStateNotifier : public NetworkLibrary::NetworkManagerObserver {
public:
// Returns the singleton instance of the network state notifier;
- static NetworkStateNotifier* Get();
+ static NetworkStateNotifier* GetInstance();
// The duration of being in offline. The value is undefined when
// when network is connected.
@@ -56,7 +56,7 @@ class NetworkStateNotifier : public NetworkLibrary::NetworkManagerObserver {
// Returns true if the network is connected.
static bool is_connected() {
- return Get()->state_ == NetworkStateDetails::CONNECTED;
+ return GetInstance()->state_ == NetworkStateDetails::CONNECTED;
}
// NetworkLibrary::NetworkManagerObserver implementation.
diff --git a/chrome/browser/chromeos/network_state_notifier_browsertest.cc b/chrome/browser/chromeos/network_state_notifier_browsertest.cc
index 47ea0de..35490a4 100644
--- a/chrome/browser/chromeos/network_state_notifier_browsertest.cc
+++ b/chrome/browser/chromeos/network_state_notifier_browsertest.cc
@@ -36,7 +36,7 @@ class NetworkStateNotifierTest : public CrosInProcessBrowserTest,
.Times(1)
.WillRepeatedly((Return(true)))
.RetiresOnSaturation();
- NetworkStateNotifier::Get();
+ NetworkStateNotifier::GetInstance();
}
// NotificationObserver overrides.
@@ -69,7 +69,7 @@ IN_PROC_BROWSER_TEST_F(NetworkStateNotifierTest, TestConnected) {
.Times(1)
.WillRepeatedly((Return(true)))
.RetiresOnSaturation();
- NetworkStateNotifier* notifier = NetworkStateNotifier::Get();
+ NetworkStateNotifier* notifier = NetworkStateNotifier::GetInstance();
notifier->OnNetworkManagerChanged(mock_network_library_);
WaitForNotification();
EXPECT_EQ(chromeos::NetworkStateDetails::CONNECTED, state_);
@@ -87,7 +87,7 @@ IN_PROC_BROWSER_TEST_F(NetworkStateNotifierTest, TestConnecting) {
.Times(1)
.WillOnce((Return(true)))
.RetiresOnSaturation();
- NetworkStateNotifier* notifier = NetworkStateNotifier::Get();
+ NetworkStateNotifier* notifier = NetworkStateNotifier::GetInstance();
notifier->OnNetworkManagerChanged(mock_network_library_);
WaitForNotification();
EXPECT_EQ(chromeos::NetworkStateDetails::CONNECTING, state_);
@@ -105,7 +105,7 @@ IN_PROC_BROWSER_TEST_F(NetworkStateNotifierTest, TestDisconnected) {
.Times(1)
.WillOnce((Return(false)))
.RetiresOnSaturation();
- NetworkStateNotifier* notifier = NetworkStateNotifier::Get();
+ NetworkStateNotifier* notifier = NetworkStateNotifier::GetInstance();
notifier->OnNetworkManagerChanged(mock_network_library_);
WaitForNotification();
EXPECT_EQ(chromeos::NetworkStateDetails::DISCONNECTED, state_);
diff --git a/chrome/browser/chromeos/notifications/balloon_collection_impl.cc b/chrome/browser/chromeos/notifications/balloon_collection_impl.cc
index c1a231c..d68978a 100644
--- a/chrome/browser/chromeos/notifications/balloon_collection_impl.cc
+++ b/chrome/browser/chromeos/notifications/balloon_collection_impl.cc
@@ -12,7 +12,7 @@
#include "chrome/browser/chromeos/notifications/notification_panel.h"
#include "chrome/browser/notifications/balloon.h"
#include "chrome/browser/notifications/notification.h"
-#include "chrome/browser/window_sizer.h"
+#include "chrome/browser/ui/window_sizer.h"
#include "chrome/common/notification_service.h"
#include "gfx/rect.h"
#include "gfx/size.h"
@@ -138,12 +138,12 @@ void BalloonCollectionImpl::Observe(NotificationType type,
const NotificationDetails& details) {
DCHECK(type == NotificationType::BROWSER_CLOSED);
bool app_closing = *Details<bool>(details).ptr();
- // When exitting, we need to shutdown all renderers in
+ // When exiting, we need to shutdown all renderers in
// BalloonViewImpl before IO thread gets deleted in the
// BrowserProcessImpl's destructor. See http://crbug.com/40810
// for details.
if (app_closing)
- Shutdown();
+ RemoveAll();
}
void BalloonCollectionImpl::Shutdown() {
diff --git a/chrome/browser/chromeos/notifications/balloon_view.cc b/chrome/browser/chromeos/notifications/balloon_view.cc
index ff5ea0f..8e9bb8d 100644
--- a/chrome/browser/chromeos/notifications/balloon_view.cc
+++ b/chrome/browser/chromeos/notifications/balloon_view.cc
@@ -16,7 +16,7 @@
#include "chrome/browser/notifications/balloon.h"
#include "chrome/browser/notifications/desktop_notification_service.h"
#include "chrome/browser/notifications/notification.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/views/notifications/balloon_view_host.h"
diff --git a/chrome/browser/chromeos/notifications/balloon_view.h b/chrome/browser/chromeos/notifications/balloon_view.h
index e275915..8f00ccd 100644
--- a/chrome/browser/chromeos/notifications/balloon_view.h
+++ b/chrome/browser/chromeos/notifications/balloon_view.h
@@ -14,7 +14,6 @@
#include "chrome/browser/notifications/balloon.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
#include "gfx/path.h"
#include "gfx/point.h"
#include "gfx/rect.h"
diff --git a/chrome/browser/chromeos/notifications/notification_panel.cc b/chrome/browser/chromeos/notifications/notification_panel.cc
index 6ab3b31..4bd0b3a 100644
--- a/chrome/browser/chromeos/notifications/notification_panel.cc
+++ b/chrome/browser/chromeos/notifications/notification_panel.cc
@@ -6,13 +6,17 @@
#include "chrome/browser/chromeos/notifications/notification_panel.h"
+#include <algorithm>
+
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "chrome/browser/chromeos/notifications/balloon_collection_impl.h"
#include "chrome/browser/chromeos/notifications/balloon_view.h"
-#include "cros/chromeos_wm_ipc_enums.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
#include "gfx/canvas.h"
#include "grit/generated_resources.h"
+#include "third_party/cros/chromeos_wm_ipc_enums.h"
#include "views/background.h"
#include "views/controls/native/native_view_host.h"
#include "views/controls/scroll_view.h"
diff --git a/chrome/browser/chromeos/offline/offline_load_page.cc b/chrome/browser/chromeos/offline/offline_load_page.cc
index 32e0202..e466d75 100644
--- a/chrome/browser/chromeos/offline/offline_load_page.cc
+++ b/chrome/browser/chromeos/offline/offline_load_page.cc
@@ -14,8 +14,8 @@
#include "base/values.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
@@ -23,6 +23,7 @@
#include "chrome/browser/ui/browser.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/jstemplate_builder.h"
+#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/url_constants.h"
#include "grit/browser_resources.h"
@@ -108,7 +109,7 @@ std::string OfflineLoadPage::GetHTMLContents() {
Profile* profile = tab()->profile();
DCHECK(profile);
const Extension* extension = NULL;
- ExtensionsService* extensions_service = profile->GetExtensionsService();
+ ExtensionService* extensions_service = profile->GetExtensionService();
// Extension service does not exist in test.
if (extensions_service)
extension = extensions_service->GetExtensionByWebExtent(url());
diff --git a/chrome/browser/chromeos/offline/offline_load_page.h b/chrome/browser/chromeos/offline/offline_load_page.h
index 2708167..e4a6246 100644
--- a/chrome/browser/chromeos/offline/offline_load_page.h
+++ b/chrome/browser/chromeos/offline/offline_load_page.h
@@ -12,7 +12,6 @@
#include "chrome/browser/chromeos/network_state_notifier.h"
#include "chrome/browser/tab_contents/interstitial_page.h"
#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_service.h"
class DictionaryValue;
class Extension;
diff --git a/chrome/browser/chromeos/offline/offline_load_service.cc b/chrome/browser/chromeos/offline/offline_load_service.cc
index 08f2362..c7738c9 100644
--- a/chrome/browser/chromeos/offline/offline_load_service.cc
+++ b/chrome/browser/chromeos/offline/offline_load_service.cc
@@ -4,13 +4,14 @@
#include "chrome/browser/chromeos/offline/offline_load_service.h"
+#include "base/lazy_instance.h"
#include "base/ref_counted.h"
-#include "base/singleton.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_util.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
namespace chromeos {
@@ -24,7 +25,7 @@ class OfflineLoadServiceSingleton {
}
private:
- friend struct DefaultSingletonTraits<OfflineLoadServiceSingleton>;
+ friend struct base::DefaultLazyInstanceTraits<OfflineLoadServiceSingleton>;
OfflineLoadServiceSingleton()
: offline_load_service_(new chromeos::OfflineLoadService()) {}
virtual ~OfflineLoadServiceSingleton() {}
@@ -34,9 +35,12 @@ class OfflineLoadServiceSingleton {
DISALLOW_COPY_AND_ASSIGN(OfflineLoadServiceSingleton);
};
+static base::LazyInstance<OfflineLoadServiceSingleton>
+ g_offline_load_service_singleton(base::LINKER_INITIALIZED);
+
// static
OfflineLoadService* OfflineLoadService::Get() {
- return Singleton<OfflineLoadServiceSingleton>::get()->offline_load_service();
+ return g_offline_load_service_singleton.Get().offline_load_service();
}
void OfflineLoadService::Observe(NotificationType type,
diff --git a/chrome/browser/chromeos/options/cellular_config_view.cc b/chrome/browser/chromeos/options/cellular_config_view.cc
deleted file mode 100644
index be919e9..0000000
--- a/chrome/browser/chromeos/options/cellular_config_view.cc
+++ /dev/null
@@ -1,227 +0,0 @@
-// 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.
-
-#include "chrome/browser/chromeos/options/cellular_config_view.h"
-
-#include "app/l10n_util.h"
-#include "base/i18n/time_formatting.h"
-#include "base/time.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/chromeos/cros/cros_library.h"
-#include "chrome/browser/chromeos/options/network_config_view.h"
-#include "chrome/common/time_format.h"
-#include "grit/generated_resources.h"
-#include "views/controls/button/checkbox.h"
-#include "views/controls/button/native_button.h"
-#include "views/controls/label.h"
-#include "views/grid_layout.h"
-#include "views/standard_layout.h"
-
-namespace {
-
-enum PlanPurchaseType {
- UNKNOWN,
- NO_PURCHASE, // No purchase happened.
- PURCHASED_DATA, // Purchased limited data plan.
- PURCHASED_UNLIMITED_DATA // Purchased unlimited data plan.
-};
-
-struct PlanDetails {
- PlanPurchaseType last_purchase_type;
- base::Time last_purchase_time;
-
- int64 purchased_data;
- base::TimeDelta purchased_time;
-
- int64 remaining_data;
- base::TimeDelta remaining_time;
-};
-
-// TODO(xiyuan): Get real data from libcros when it's ready.
-// Get plan details at the time being called.
-void GetPlanDetails(const chromeos::CellularNetwork* cellular,
- PlanDetails* details) {
- // Free 5M 30day plan.
- details->last_purchase_type = UNKNOWN;
- details->last_purchase_time = base::Time::Now();
- details->purchased_data = 5 * 1024 * 1024;
- details->purchased_time = base::TimeDelta::FromDays(30);
- details->remaining_data = 2 * 1024 * 1024;
- details->remaining_time = base::TimeDelta::FromDays(29);
-}
-
-} // namespace
-
-namespace chromeos {
-
-CellularConfigView::CellularConfigView(NetworkConfigView* parent,
- const CellularNetwork* cellular)
- : parent_(parent),
- cellular_(new CellularNetwork(*cellular)),
- purchase_info_(NULL),
- purchase_more_button_(NULL),
- remaining_data_info_(NULL),
- expiration_info_(NULL),
- show_notification_checkbox_(NULL),
- autoconnect_checkbox_(NULL),
- customer_support_link_(NULL) {
- Init();
-}
-
-CellularConfigView::~CellularConfigView() {
-}
-
-void CellularConfigView::ButtonPressed(views::Button* button,
- const views::Event& event) {
- if (button == purchase_more_button_) {
- // TODO(xiyuan): Purchase more...
- }
-}
-
-void CellularConfigView::LinkActivated(views::Link* source, int event_flags) {
- if (source == customer_support_link_) {
- // TODO(xiyuan): Find out where to go.
- }
-}
-
-bool CellularConfigView::Save() {
- // Save auto-connect here.
- bool auto_connect = autoconnect_checkbox_->checked();
- if (auto_connect != cellular_->auto_connect()) {
- cellular_->set_auto_connect(auto_connect);
- CrosLibrary::Get()->GetNetworkLibrary()->SaveCellularNetwork(
- cellular_.get());
- }
- return true;
-}
-
-void CellularConfigView::Init() {
- views::GridLayout* layout = CreatePanelGridLayout(this);
- SetLayoutManager(layout);
-
- purchase_info_ = new views::Label();
- purchase_more_button_ = new views::NativeButton(this, l10n_util::GetString(
- IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PURCHASE_MORE));
- views::Label* data_remaining_label = new views::Label(l10n_util::GetString(
- IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_DATA_REMAINING));
- remaining_data_info_ = new views::Label();
- views::Label* expires_label = new views::Label(l10n_util::GetString(
- IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_EXPIRES));
- expiration_info_ = new views::Label();
- show_notification_checkbox_ = new views::Checkbox(l10n_util::GetString(
- IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_SHOW_MOBILE_NOTIFICATION));
- autoconnect_checkbox_ = new views::Checkbox(l10n_util::GetString(
- IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_AUTO_CONNECT));
- customer_support_link_ = new views::Link(l10n_util::GetString(
- IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CUSTOMER_SUPPORT));
-
- data_remaining_label->SetFont(data_remaining_label->font().DeriveFont(0,
- gfx::Font::BOLD));
- expires_label->SetFont(data_remaining_label->font());
-
- const int kColumnSetId = 0;
- views::ColumnSet* column_set = layout->AddColumnSet(kColumnSetId);
- column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1,
- views::GridLayout::USE_PREF, 0, 0);
- column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1,
- views::GridLayout::USE_PREF, 0, 0);
- column_set->AddColumn(views::GridLayout::TRAILING, views::GridLayout::FILL, 1,
- views::GridLayout::USE_PREF, 0, 0);
-
- layout->StartRow(0, kColumnSetId);
- layout->AddView(purchase_info_, 2, 1);
- layout->AddView(purchase_more_button_);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
-
- layout->StartRow(0, kColumnSetId);
- layout->AddView(data_remaining_label);
- layout->AddView(remaining_data_info_, 2, 1);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
-
- layout->StartRow(0, kColumnSetId);
- layout->AddView(expires_label);
- layout->AddView(expiration_info_, 2, 1);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
-
- layout->StartRow(0, kColumnSetId);
- layout->AddView(show_notification_checkbox_, 3, 1);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
-
- layout->StartRow(0, kColumnSetId);
- layout->AddView(autoconnect_checkbox_, 3, 1);
- layout->AddPaddingRow(0, kUnrelatedControlVerticalSpacing);
-
- layout->StartRow(0, kColumnSetId);
- layout->AddView(customer_support_link_, 3, 1,
- views::GridLayout::LEADING, views::GridLayout::TRAILING);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
-
- Update();
-}
-
-void CellularConfigView::Update() {
- autoconnect_checkbox_->SetChecked(cellular_->auto_connect());
-
- PlanDetails details;
- GetPlanDetails(cellular_.get(), &details);
-
- switch (details.last_purchase_type) {
- case NO_PURCHASE:
- purchase_info_->SetText(l10n_util::GetStringF(
- IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_RECEIVED_FREE_DATA,
- UTF16ToWide(FormatBytes(details.purchased_data,
- GetByteDisplayUnits(details.purchased_data),
- true)),
- base::TimeFormatFriendlyDate(details.last_purchase_time)));
- remaining_data_info_->SetText(
- UTF16ToWide(FormatBytes(details.remaining_data,
- GetByteDisplayUnits(details.remaining_data),
- true)));
- expiration_info_->SetText(UTF16ToWide(
- TimeFormat::TimeRemaining(details.remaining_time)));
- break;
- case PURCHASED_DATA:
- purchase_info_->SetText(l10n_util::GetStringF(
- IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PURCHASE_DATA,
- UTF16ToWide(FormatBytes(details.purchased_data,
- GetByteDisplayUnits(details.purchased_data),
- true)),
- base::TimeFormatFriendlyDate(details.last_purchase_time)));
- remaining_data_info_->SetText(
- UTF16ToWide(FormatBytes(details.remaining_data,
- GetByteDisplayUnits(details.remaining_data),
- true)));
- expiration_info_->SetText(UTF16ToWide(
- TimeFormat::TimeRemaining(details.remaining_time)));
- break;
- case PURCHASED_UNLIMITED_DATA:
- purchase_info_->SetText(l10n_util::GetStringF(
- IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PURCHASE_UNLIMITED_DATA,
- UTF16ToWide(FormatBytes(details.purchased_data,
- GetByteDisplayUnits(details.purchased_data),
- true)),
- base::TimeFormatFriendlyDate(details.last_purchase_time)));
- remaining_data_info_->SetText(l10n_util::GetString(
- IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_UNLIMITED));
- expiration_info_->SetText(UTF16ToWide(
- TimeFormat::TimeRemaining(details.remaining_time)));
- break;
- case UNKNOWN: {
- // TODO(xiyuan): Remove this when underlying data is provided.
- const wchar_t kPlanType[] = L"Purchased plan: <Not yet implemented>";
- const wchar_t kNotImplemented[] = L"<Not yet implemented>";
- purchase_info_->SetText(kPlanType);
- remaining_data_info_->SetText(kNotImplemented);
- expiration_info_->SetText(kNotImplemented);
- break;
- }
- default:
- NOTREACHED() << "Unknown mobile plan purchase type.";
- break;
- }
-
- Layout();
-}
-
-} // namespace chromeos
diff --git a/chrome/browser/chromeos/options/cellular_config_view.h b/chrome/browser/chromeos/options/cellular_config_view.h
deleted file mode 100644
index 36e64ed..0000000
--- a/chrome/browser/chromeos/options/cellular_config_view.h
+++ /dev/null
@@ -1,68 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_CHROMEOS_OPTIONS_CELLULAR_CONFIG_VIEW_H_
-#define CHROME_BROWSER_CHROMEOS_OPTIONS_CELLULAR_CONFIG_VIEW_H_
-#pragma once
-
-#include "chrome/browser/chromeos/cros/network_library.h"
-#include "views/controls/button/button.h"
-#include "views/controls/link.h"
-#include "views/view.h"
-
-namespace views {
-class Checkbox;
-class Label;
-class NativeButton;
-} // namespace views
-
-namespace chromeos {
-
-class NetworkConfigView;
-
-// A dialog box for showing a password textfield.
-class CellularConfigView : public views::View,
- public views::ButtonListener,
- public views::LinkController {
- public:
- CellularConfigView(NetworkConfigView* parent,
- const CellularNetwork* cellular);
- explicit CellularConfigView(NetworkConfigView* parent);
- virtual ~CellularConfigView();
-
- // views::ButtonListener implementation.
- virtual void ButtonPressed(views::Button* button, const views::Event& event);
-
- // views::LinkController implementation.
- virtual void LinkActivated(views::Link* source, int event_flags);
-
- // Save network information.
- virtual bool Save();
-
- private:
-
- // Initializes UI.
- void Init();
-
- // Updates UI.
- void Update();
-
- NetworkConfigView* parent_;
-
- scoped_ptr<CellularNetwork> cellular_;
-
- views::Label* purchase_info_;
- views::NativeButton* purchase_more_button_;
- views::Label* remaining_data_info_;
- views::Label* expiration_info_;
- views::Checkbox* show_notification_checkbox_;
- views::Checkbox* autoconnect_checkbox_;
- views::Link* customer_support_link_;
-
- DISALLOW_COPY_AND_ASSIGN(CellularConfigView);
-};
-
-} // namespace chromeos
-
-#endif // CHROME_BROWSER_CHROMEOS_OPTIONS_CELLULAR_CONFIG_VIEW_H_
diff --git a/chrome/browser/chromeos/options/internet_page_view.cc b/chrome/browser/chromeos/options/internet_page_view.cc
index 14ad91d..bf5d77e 100644
--- a/chrome/browser/chromeos/options/internet_page_view.cc
+++ b/chrome/browser/chromeos/options/internet_page_view.cc
@@ -272,8 +272,8 @@ void WiredSection::InitSection() {
}
void WiredSection::ButtonClicked(int button, int connection_type, int id) {
- CreateModalPopup(new NetworkConfigView(
- CrosLibrary::Get()->GetNetworkLibrary()->ethernet_network()));
+// CreateModalPopup(new NetworkConfigView(
+// CrosLibrary::Get()->GetNetworkLibrary()->ethernet_network()));
}
////////////////////////////////////////////////////////////////////////////////
@@ -322,7 +322,7 @@ void WirelessSection::InitSection() {
std::wstring name = ASCIIToWide(wifi_networks_[i]->name());
SkBitmap icon = NetworkMenu::IconForNetworkStrength(
- wifi_networks_[i]->strength(), true);
+ wifi_networks_[i], true);
if (wifi_networks_[i]->encrypted()) {
icon = NetworkMenu::IconForDisplay(icon,
*rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_SECURE));
@@ -339,7 +339,7 @@ void WirelessSection::InitSection() {
std::wstring name = ASCIIToWide(cellular_networks_[i]->name());
SkBitmap icon = NetworkMenu::IconForNetworkStrength(
- cellular_networks_[i]->strength(), true);
+ cellular_networks_[i], true);
SkBitmap badge =
NetworkMenu::BadgeForNetworkTechnology(cellular_networks_[i]);
icon = NetworkMenu::IconForDisplay(icon, badge);
@@ -361,7 +361,7 @@ void WirelessSection::ButtonClicked(int button, int connection_type, int id) {
CrosLibrary::Get()->GetNetworkLibrary()->DisconnectFromWirelessNetwork(
cellular_networks_[id]);
} else {
- CreateModalPopup(new NetworkConfigView(cellular_networks_[id]));
+// CreateModalPopup(new NetworkConfigView(cellular_networks_[id]));
}
}
} else if (connection_type == TYPE_WIFI) {
@@ -369,10 +369,10 @@ void WirelessSection::ButtonClicked(int button, int connection_type, int id) {
if (button == CONNECT_BUTTON) {
// Connect to wifi here. Open password page if appropriate.
if (wifi_networks_[id]->encrypted()) {
- NetworkConfigView* view =
- new NetworkConfigView(wifi_networks_[id], true);
- CreateModalPopup(view);
- view->SetLoginTextfieldFocus();
+// NetworkConfigView* view =
+// new NetworkConfigView(wifi_networks_[id], true);
+// CreateModalPopup(view);
+// view->SetLoginTextfieldFocus();
} else {
CrosLibrary::Get()->GetNetworkLibrary()->ConnectToWifiNetwork(
wifi_networks_[id], std::string(), std::string(), std::string());
@@ -381,7 +381,7 @@ void WirelessSection::ButtonClicked(int button, int connection_type, int id) {
CrosLibrary::Get()->GetNetworkLibrary()->DisconnectFromWirelessNetwork(
wifi_networks_[id]);
} else {
- CreateModalPopup(new NetworkConfigView(wifi_networks_[id], false));
+// CreateModalPopup(new NetworkConfigView(wifi_networks_[id], false));
}
}
} else {
diff --git a/chrome/browser/chromeos/options/ip_config_view.cc b/chrome/browser/chromeos/options/ip_config_view.cc
deleted file mode 100644
index b4cfbb1..0000000
--- a/chrome/browser/chromeos/options/ip_config_view.cc
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/chromeos/options/ip_config_view.h"
-
-#include "app/l10n_util.h"
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/chromeos/cros/cros_library.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-#include "grit/locale_settings.h"
-#include "views/controls/label.h"
-#include "views/controls/textfield/textfield.h"
-#include "views/grid_layout.h"
-#include "views/standard_layout.h"
-#include "views/window/window.h"
-
-namespace chromeos {
-
-IPConfigView::IPConfigView(const std::string& device_path)
- : device_path_(device_path),
- ip_configs_(),
- address_textfield_(NULL),
- netmask_textfield_(NULL),
- gateway_textfield_(NULL),
- dnsserver_textfield_(NULL) {
- Init();
- RefreshData();
-}
-
-void IPConfigView::RefreshData() {
- std::string hardware_address;
- NetworkIPConfigVector ipconfigs =
- CrosLibrary::Get()->GetNetworkLibrary()->GetIPConfigs(device_path_,
- &hardware_address);
- for (NetworkIPConfigVector::const_iterator it = ipconfigs.begin();
- it != ipconfigs.end(); ++it) {
- const NetworkIPConfig& ipconfig = *it;
- address_textfield_->SetText(ASCIIToUTF16(ipconfig.address));
- netmask_textfield_->SetText(ASCIIToUTF16(ipconfig.netmask));
- gateway_textfield_->SetText(ASCIIToUTF16(ipconfig.gateway));
- dnsserver_textfield_->SetText(ASCIIToUTF16(ipconfig.name_servers));
- }
-}
-
-void IPConfigView::Init() {
- views::GridLayout* layout = CreatePanelGridLayout(this);
- SetLayoutManager(layout);
-
- int column_view_set_id = 0;
- views::ColumnSet* column_set = layout->AddColumnSet(column_view_set_id);
- column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1,
- views::GridLayout::USE_PREF, 0, 0);
- column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
- views::GridLayout::USE_PREF, 0, 200);
-
- layout->StartRow(0, column_view_set_id);
- layout->AddView(new views::Label(l10n_util::GetString(
- IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_ADDRESS)));
- address_textfield_ = new views::Textfield(views::Textfield::STYLE_DEFAULT);
- address_textfield_->SetEnabled(false);
- layout->AddView(address_textfield_);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
-
- layout->StartRow(0, column_view_set_id);
- layout->AddView(new views::Label(l10n_util::GetString(
- IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_SUBNETMASK)));
- netmask_textfield_ = new views::Textfield(views::Textfield::STYLE_DEFAULT);
- netmask_textfield_->SetEnabled(false);
- layout->AddView(netmask_textfield_);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
-
- layout->StartRow(0, column_view_set_id);
- layout->AddView(new views::Label(l10n_util::GetString(
- IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_GATEWAY)));
- gateway_textfield_ = new views::Textfield(views::Textfield::STYLE_DEFAULT);
- gateway_textfield_->SetEnabled(false);
- layout->AddView(gateway_textfield_);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
-
- layout->StartRow(0, column_view_set_id);
- layout->AddView(new views::Label(l10n_util::GetString(
- IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_DNSSERVER)));
- dnsserver_textfield_ = new views::Textfield(views::Textfield::STYLE_DEFAULT);
- dnsserver_textfield_->SetEnabled(false);
- layout->AddView(dnsserver_textfield_);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
-}
-
-} // namespace chromeos
diff --git a/chrome/browser/chromeos/options/ip_config_view.h b/chrome/browser/chromeos/options/ip_config_view.h
deleted file mode 100644
index c09fcc3..0000000
--- a/chrome/browser/chromeos/options/ip_config_view.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_CHROMEOS_OPTIONS_IP_CONFIG_VIEW_H_
-#define CHROME_BROWSER_CHROMEOS_OPTIONS_IP_CONFIG_VIEW_H_
-#pragma once
-
-#include <string>
-
-#include "chrome/browser/chromeos/cros/network_library.h"
-#include "views/view.h"
-
-namespace views {
-class Textfield;
-}
-
-namespace chromeos {
-
-// A dialog box for showing a password textfield.
-class IPConfigView : public views::View {
- public:
- explicit IPConfigView(const std::string& device_path);
- virtual ~IPConfigView() {}
-
- private:
- // Refreshes IP Config data.
- void RefreshData();
- // Initializes UI.
- void Init();
-
- // The device path of the network.
- std::string device_path_;
-
- NetworkIPConfigVector ip_configs_;
-
- views::Textfield* address_textfield_;
- views::Textfield* netmask_textfield_;
- views::Textfield* gateway_textfield_;
- views::Textfield* dnsserver_textfield_;
-
- DISALLOW_COPY_AND_ASSIGN(IPConfigView);
-};
-
-} // namespace chromeos
-
-#endif // CHROME_BROWSER_CHROMEOS_OPTIONS_IP_CONFIG_VIEW_H_
diff --git a/chrome/browser/chromeos/options/language_chewing_config_view.cc b/chrome/browser/chromeos/options/language_chewing_config_view.cc
index 5b07f33..0d1f31a 100644
--- a/chrome/browser/chromeos/options/language_chewing_config_view.cc
+++ b/chrome/browser/chromeos/options/language_chewing_config_view.cc
@@ -10,7 +10,7 @@
#include "chrome/browser/chromeos/cros/input_method_library.h"
#include "chrome/browser/chromeos/options/language_config_util.h"
#include "chrome/browser/chromeos/preferences.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/chromeos/options/language_config_model.h b/chrome/browser/chromeos/options/language_config_model.h
index 05a63ac..c401c6f 100644
--- a/chrome/browser/chromeos/options/language_config_model.h
+++ b/chrome/browser/chromeos/options/language_config_model.h
@@ -14,9 +14,9 @@
#include "chrome/browser/language_combobox_model.h"
#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/common/notification_service.h"
-#include "cros/chromeos_input_method.h"
+#include "third_party/cros/chromeos_input_method.h"
+
+class Profile;
namespace chromeos {
diff --git a/chrome/browser/chromeos/options/language_config_view.cc b/chrome/browser/chromeos/options/language_config_view.cc
index 95e0aa9..d4b1f62 100644
--- a/chrome/browser/chromeos/options/language_config_view.cc
+++ b/chrome/browser/chromeos/options/language_config_view.cc
@@ -18,7 +18,7 @@
#include "chrome/browser/chromeos/preferences.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/views/restart_message_box.h"
#include "chrome/browser/views/window.h"
#include "chrome/common/notification_type.h"
diff --git a/chrome/browser/chromeos/options/language_hangul_config_view.cc b/chrome/browser/chromeos/options/language_hangul_config_view.cc
index 9055455..e65569b 100644
--- a/chrome/browser/chromeos/options/language_hangul_config_view.cc
+++ b/chrome/browser/chromeos/options/language_hangul_config_view.cc
@@ -12,7 +12,7 @@
#include "chrome/browser/chromeos/cros/input_method_library.h"
#include "chrome/browser/chromeos/language_preferences.h"
#include "chrome/browser/chromeos/preferences.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/chromeos/options/language_mozc_config_view.cc b/chrome/browser/chromeos/options/language_mozc_config_view.cc
index 30eb71b..13d5267 100644
--- a/chrome/browser/chromeos/options/language_mozc_config_view.cc
+++ b/chrome/browser/chromeos/options/language_mozc_config_view.cc
@@ -9,7 +9,7 @@
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/options/language_config_util.h"
#include "chrome/browser/chromeos/preferences.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/chromeos/options/language_pinyin_config_view.cc b/chrome/browser/chromeos/options/language_pinyin_config_view.cc
index 203b3ea..881d31a 100644
--- a/chrome/browser/chromeos/options/language_pinyin_config_view.cc
+++ b/chrome/browser/chromeos/options/language_pinyin_config_view.cc
@@ -10,7 +10,7 @@
#include "chrome/browser/chromeos/cros/input_method_library.h"
#include "chrome/browser/chromeos/options/language_config_util.h"
#include "chrome/browser/chromeos/preferences.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/chromeos/options/network_config_view.cc b/chrome/browser/chromeos/options/network_config_view.cc
index fa9fe74..c35be1a 100644
--- a/chrome/browser/chromeos/options/network_config_view.cc
+++ b/chrome/browser/chromeos/options/network_config_view.cc
@@ -4,11 +4,11 @@
#include "chrome/browser/chromeos/options/network_config_view.h"
+#include <algorithm>
+
#include "app/l10n_util.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/chromeos/options/cellular_config_view.h"
-#include "chrome/browser/chromeos/options/ip_config_view.h"
#include "chrome/browser/chromeos/options/wifi_config_view.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
@@ -22,69 +22,35 @@ using views::WidgetGtk;
namespace chromeos {
-NetworkConfigView::NetworkConfigView(const EthernetNetwork* ethernet)
- : browser_mode_(true),
- flags_(FLAG_ETHERNET | FLAG_SHOW_IPCONFIG),
- ethernet_(new EthernetNetwork(*ethernet)),
- cellularconfig_view_(NULL),
- wificonfig_view_(NULL),
- ipconfig_view_(NULL),
- delegate_(NULL) {
-}
-
-NetworkConfigView::NetworkConfigView(const WifiNetwork* wifi, bool login_only)
- : browser_mode_(true),
- flags_(FLAG_WIFI),
- wifi_(new WifiNetwork(*wifi)),
- cellularconfig_view_(NULL),
- wificonfig_view_(NULL),
- ipconfig_view_(NULL),
- delegate_(NULL) {
- if (login_only)
- flags_ |= FLAG_LOGIN_ONLY;
- else
- flags_ |= FLAG_SHOW_IPCONFIG;
-}
-
-NetworkConfigView::NetworkConfigView(const CellularNetwork* cellular)
+NetworkConfigView::NetworkConfigView(const WifiNetwork* wifi)
: browser_mode_(true),
- flags_(FLAG_CELLULAR | FLAG_SHOW_IPCONFIG),
- cellular_(new CellularNetwork(*cellular)),
- cellularconfig_view_(NULL),
- wificonfig_view_(NULL),
- ipconfig_view_(NULL),
+ title_(ASCIIToWide(wifi->name())),
+ wificonfig_view_(new WifiConfigView(this, wifi)),
delegate_(NULL) {
}
NetworkConfigView::NetworkConfigView()
: browser_mode_(true),
- flags_(FLAG_WIFI | FLAG_LOGIN_ONLY | FLAG_OTHER_NETWORK),
- cellularconfig_view_(NULL),
- wificonfig_view_(NULL),
- ipconfig_view_(NULL),
+ title_(l10n_util::GetString(IDS_OPTIONS_SETTINGS_OTHER_NETWORKS)),
+ wificonfig_view_(new WifiConfigView(this)),
delegate_(NULL) {
}
-NetworkConfigView::~NetworkConfigView() {
-}
-
gfx::NativeWindow NetworkConfigView::GetNativeWindow() const {
return GTK_WINDOW(static_cast<WidgetGtk*>(GetWidget())->GetNativeView());
}
std::wstring NetworkConfigView::GetDialogButtonLabel(
MessageBoxFlags::DialogButton button) const {
- if (button == MessageBoxFlags::DIALOGBUTTON_OK) {
- if (flags_ & FLAG_LOGIN_ONLY)
- return l10n_util::GetString(IDS_OPTIONS_SETTINGS_CONNECT);
- }
+ if (button == MessageBoxFlags::DIALOGBUTTON_OK)
+ return l10n_util::GetString(IDS_OPTIONS_SETTINGS_CONNECT);
return std::wstring();
}
bool NetworkConfigView::IsDialogButtonEnabled(
MessageBoxFlags::DialogButton button) const {
- // For login dialogs, disable ok button if nothing entered in text fields.
- if (flags_ & FLAG_LOGIN_ONLY && button == MessageBoxFlags::DIALOGBUTTON_OK)
+ // Disable connect button if cannot login.
+ if (button == MessageBoxFlags::DIALOGBUTTON_OK)
return wificonfig_view_->can_login();
return true;
}
@@ -92,48 +58,23 @@ bool NetworkConfigView::IsDialogButtonEnabled(
bool NetworkConfigView::Cancel() {
if (delegate_)
delegate_->OnDialogCancelled();
- if (flags_ & FLAG_WIFI)
- wificonfig_view_->Cancel();
+ wificonfig_view_->Cancel();
return true;
}
bool NetworkConfigView::Accept() {
- bool result = true;
- if (flags_ & FLAG_CELLULAR) {
- result = cellularconfig_view_->Save();
- }
- if (flags_ & FLAG_WIFI) {
- if (flags_ & FLAG_LOGIN_ONLY)
- result = wificonfig_view_->Login();
- else
- result = wificonfig_view_->Save();
- }
+ bool result = wificonfig_view_->Login();
if (result && delegate_)
delegate_->OnDialogAccepted();
return result;
}
std::wstring NetworkConfigView::GetWindowTitle() const {
- if (flags_ & FLAG_OTHER_NETWORK)
- return l10n_util::GetString(IDS_OPTIONS_SETTINGS_OTHER_NETWORKS);
- if (flags_ & FLAG_WIFI)
- return ASCIIToWide(wifi_->name());
- if (flags_ & FLAG_CELLULAR)
- return ASCIIToWide(cellular_->name());
- return l10n_util::GetString(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET);
-}
-
-void NetworkConfigView::TabSelectedAt(int index) {
-}
-
-void NetworkConfigView::SetLoginTextfieldFocus() {
- if (wificonfig_view_)
- wificonfig_view_->FocusFirstField();
+ return title_;
}
void NetworkConfigView::Layout() {
- static const int kDialogBottomPadding = 7;
- tabs_->SetBounds(0, 0, width(), height() - kDialogBottomPadding);
+ wificonfig_view_->SetBounds(0, 0, width(), height());
}
gfx::Size NetworkConfigView::GetPreferredSize() {
@@ -141,28 +82,7 @@ gfx::Size NetworkConfigView::GetPreferredSize() {
gfx::Size result(views::Window::GetLocalizedContentsSize(
IDS_IMPORT_DIALOG_WIDTH_CHARS,
IDS_IMPORT_DIALOG_HEIGHT_LINES));
- result.set_height(0); // IMPORT_DIALOG height is too large
- // Expand the default size to fit results if necessary
- if (cellularconfig_view_) {
- gfx::Size s = cellularconfig_view_->GetPreferredSize();
- s.set_height(s.height() + kPanelVertMargin * 2);
- s.set_width(s.width() + kPanelHorizMargin * 2);
- result = gfx::Size(std::max(result.width(), s.width()),
- std::max(result.height(), s.height()));
- } else if (wificonfig_view_) {
- gfx::Size s = wificonfig_view_->GetPreferredSize();
- s.set_height(s.height() + kPanelVertMargin * 2);
- s.set_width(s.width() + kPanelHorizMargin * 2);
- result = gfx::Size(std::max(result.width(), s.width()),
- std::max(result.height(), s.height()));
- }
- if (ipconfig_view_) {
- gfx::Size s = ipconfig_view_->GetPreferredSize();
- s.set_height(s.height() + kPanelVertMargin * 2);
- s.set_width(s.width() + kPanelHorizMargin * 2);
- result = gfx::Size(std::max(result.width(), s.width()),
- std::max(result.height(), s.height()));
- }
+ result.set_height(wificonfig_view_->GetPreferredSize().height());
return result;
}
@@ -171,41 +91,7 @@ void NetworkConfigView::ViewHierarchyChanged(
// Can't init before we're inserted into a Container, because we require
// a HWND to parent native child controls to.
if (is_add && child == this)
- Init();
-}
-
-void NetworkConfigView::Init() {
- tabs_ = new views::TabbedPane();
- tabs_->SetListener(this);
- AddChildView(tabs_);
-
- if (flags_ & FLAG_CELLULAR) {
- cellularconfig_view_ = new CellularConfigView(this, cellular_.get());
- tabs_->AddTab(
- l10n_util::GetString(IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_USAGE),
- cellularconfig_view_);
- }
- if (flags_ & FLAG_WIFI) {
- if (flags_ & FLAG_OTHER_NETWORK)
- wificonfig_view_ = new WifiConfigView(this);
- else
- wificonfig_view_ = new WifiConfigView(this, wifi_.get());
- tabs_->AddTab(
- l10n_util::GetString(IDS_OPTIONS_SETTINGS_SECTION_TITLE_NETWORK_CONFIG),
- wificonfig_view_);
- }
-
- if (flags_ & FLAG_SHOW_IPCONFIG) {
- if (flags_ & FLAG_WIFI)
- ipconfig_view_ = new IPConfigView(wifi_->device_path());
- else if (flags_ & FLAG_CELLULAR)
- ipconfig_view_ = new IPConfigView(cellular_->device_path());
- else
- ipconfig_view_ = new IPConfigView(ethernet_->device_path());
- tabs_->AddTab(
- l10n_util::GetString(IDS_OPTIONS_SETTINGS_SECTION_TITLE_IP_CONFIG),
- ipconfig_view_);
- }
+ AddChildView(wificonfig_view_);
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/options/network_config_view.h b/chrome/browser/chromeos/options/network_config_view.h
index b6f13be..aec302a 100644
--- a/chrome/browser/chromeos/options/network_config_view.h
+++ b/chrome/browser/chromeos/options/network_config_view.h
@@ -6,8 +6,6 @@
#define CHROME_BROWSER_CHROMEOS_OPTIONS_NETWORK_CONFIG_VIEW_H_
#pragma once
-#include <string>
-
#include "chrome/browser/chromeos/cros/network_library.h"
#include "views/controls/tabbed_pane/tabbed_pane.h"
#include "views/window/dialog_delegate.h"
@@ -20,14 +18,11 @@ class Window;
namespace chromeos {
-class IPConfigView;
-class CellularConfigView;
class WifiConfigView;
// A dialog box for showing a password textfield.
class NetworkConfigView : public views::View,
- public views::DialogDelegate,
- views::TabbedPane::Listener {
+ public views::DialogDelegate {
public:
class Delegate {
public:
@@ -41,15 +36,11 @@ class NetworkConfigView : public views::View,
virtual ~Delegate() {}
};
- // Configure dialog for ethernet.
- explicit NetworkConfigView(const EthernetNetwork* ethernet);
- // Configure dialog for wifi. If |login_only|, then only show login tab.
- explicit NetworkConfigView(const WifiNetwork* wifi, bool login_only);
- // Configure dialog for cellular.
- explicit NetworkConfigView(const CellularNetwork* cellular);
+ // Login dialog for wifi.
+ explicit NetworkConfigView(const WifiNetwork* wifi);
// Login dialog for hidden networks.
explicit NetworkConfigView();
- virtual ~NetworkConfigView();
+ virtual ~NetworkConfigView() {}
// Returns corresponding native window.
gfx::NativeWindow GetNativeWindow() const;
@@ -69,12 +60,6 @@ class NetworkConfigView : public views::View,
// views::View overrides.
virtual std::wstring GetWindowTitle() const;
- // views::TabbedPane::Listener overrides.
- virtual void TabSelectedAt(int index);
-
- // Sets the focus on the login tab's first textfield.
- void SetLoginTextfieldFocus();
-
// Getter/setter for browser mode.
void set_browser_mode(bool value) {
browser_mode_ = value;
@@ -96,33 +81,14 @@ class NetworkConfigView : public views::View,
views::View* child);
private:
- enum NetworkConfigFlags {
- FLAG_ETHERNET = 1 << 0,
- FLAG_WIFI = 1 << 1,
- FLAG_CELLULAR = 1 << 2,
- FLAG_SHOW_IPCONFIG = 1 << 3,
- FLAG_LOGIN_ONLY = 1 << 4,
- FLAG_OTHER_NETWORK = 1 << 5,
- };
-
- // Initializes UI.
- void Init();
-
// True when opening in browser, otherwise in OOBE/login mode.
bool browser_mode_;
- views::TabbedPane* tabs_;
-
- // NetworkConfigFlags to specify which UIs to show.
- int flags_;
-
- scoped_ptr<EthernetNetwork> ethernet_;
- scoped_ptr<WifiNetwork> wifi_;
- scoped_ptr<CellularNetwork> cellular_;
+ std::wstring title_;
- CellularConfigView* cellularconfig_view_;
+ // WifiConfig is the only child of this class.
+ // It will get deleted when NetworkConfigView gets cleaned up.
WifiConfigView* wificonfig_view_;
- IPConfigView* ipconfig_view_;
Delegate* delegate_;
diff --git a/chrome/browser/chromeos/options/options_window_view.cc b/chrome/browser/chromeos/options/options_window_view.cc
index 3247430..087a09a 100644
--- a/chrome/browser/chromeos/options/options_window_view.cc
+++ b/chrome/browser/chromeos/options/options_window_view.cc
@@ -2,23 +2,22 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/options_window.h"
-
#include "app/l10n_util.h"
#include "base/scoped_ptr.h"
-#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_window.h"
#include "chrome/browser/chromeos/options/internet_page_view.h"
#include "chrome/browser/chromeos/options/system_page_view.h"
#include "chrome/browser/gtk/options/advanced_page_gtk.h"
#include "chrome/browser/gtk/options/content_page_gtk.h"
#include "chrome/browser/gtk/options/general_page_gtk.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/views/accessible_view_helper.h"
-#include "chrome/browser/views/window.h"
-#include "chrome/browser/window_sizer.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/options/options_window.h"
+#include "chrome/browser/ui/views/accessible_view_helper.h"
+#include "chrome/browser/ui/views/window.h"
+#include "chrome/browser/ui/window_sizer.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/pref_names.h"
#include "grit/chromium_strings.h"
diff --git a/chrome/browser/chromeos/options/system_page_view.cc b/chrome/browser/chromeos/options/system_page_view.cc
index 3569293..5920f82 100644
--- a/chrome/browser/chromeos/options/system_page_view.cc
+++ b/chrome/browser/chromeos/options/system_page_view.cc
@@ -22,7 +22,7 @@
#include "chrome/browser/chromeos/options/language_config_view.h"
#include "chrome/browser/chromeos/options/options_window_view.h"
#include "chrome/browser/prefs/pref_member.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
#include "unicode/timezone.h"
diff --git a/chrome/browser/chromeos/options/wifi_config_view.cc b/chrome/browser/chromeos/options/wifi_config_view.cc
index e920109..91473c6 100644
--- a/chrome/browser/chromeos/options/wifi_config_view.cc
+++ b/chrome/browser/chromeos/options/wifi_config_view.cc
@@ -59,7 +59,6 @@ string16 WifiConfigView::SecurityComboboxModel::GetItemAt(int index) {
WifiConfigView::WifiConfigView(NetworkConfigView* parent,
const WifiNetwork* wifi)
: parent_(parent),
- other_network_(false),
can_login_(false),
wifi_(new WifiNetwork(*wifi)),
ssid_textfield_(NULL),
@@ -69,14 +68,12 @@ WifiConfigView::WifiConfigView(NetworkConfigView* parent,
security_combobox_(NULL),
passphrase_textfield_(NULL),
passphrase_visible_button_(NULL),
- autoconnect_checkbox_(NULL),
error_label_(NULL) {
Init();
}
WifiConfigView::WifiConfigView(NetworkConfigView* parent)
: parent_(parent),
- other_network_(true),
can_login_(false),
ssid_textfield_(NULL),
identity_textfield_(NULL),
@@ -85,7 +82,6 @@ WifiConfigView::WifiConfigView(NetworkConfigView* parent)
security_combobox_(NULL),
passphrase_textfield_(NULL),
passphrase_visible_button_(NULL),
- autoconnect_checkbox_(NULL),
error_label_(NULL) {
Init();
}
@@ -97,7 +93,7 @@ void WifiConfigView::UpdateCanLogin(void) {
static const size_t kMinWirelessPasswordLen = 5;
bool can_login = true;
- if (other_network_) {
+ if (!wifi_.get()) {
// Enforce ssid is non empty.
// If security is not none, also enforce passphrase is non empty.
can_login = !GetSSID().empty() &&
@@ -125,15 +121,6 @@ void WifiConfigView::UpdateCanLogin(void) {
}
}
-void WifiConfigView::UpdateCanViewPassword() {
- if (passphrase_visible_button_ &&
- !passphrase_visible_button_->IsVisible() &&
- passphrase_textfield_->text().empty()) {
- // Once initial password has been deleted, it's safe to show field content.
- passphrase_visible_button_->SetVisible(true);
- }
-}
-
void WifiConfigView::UpdateErrorLabel(bool failed) {
static const int kNoError = -1;
int id = kNoError;
@@ -160,7 +147,6 @@ void WifiConfigView::UpdateErrorLabel(bool failed) {
void WifiConfigView::ContentsChanged(views::Textfield* sender,
const string16& new_contents) {
UpdateCanLogin();
- UpdateCanViewPassword();
}
bool WifiConfigView::HandleKeystroke(
@@ -221,7 +207,7 @@ bool WifiConfigView::Login() {
}
NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary();
bool connected = false;
- if (other_network_) {
+ if (!wifi_.get()) {
ConnectionSecurity sec = SECURITY_UNKNOWN;
int index = security_combobox_->selected_item();
if (index == INDEX_NONE)
@@ -234,8 +220,7 @@ bool WifiConfigView::Login() {
sec = SECURITY_RSN;
connected = cros->ConnectToWifiNetwork(
sec, GetSSID(), GetPassphrase(),
- identity_string, certificate_path_,
- autoconnect_checkbox_ ? autoconnect_checkbox_->checked() : true);
+ identity_string, certificate_path_, true);
} else {
Save();
connected = cros->ConnectToWifiNetwork(
@@ -254,18 +239,10 @@ bool WifiConfigView::Login() {
}
bool WifiConfigView::Save() {
- // Save password and auto-connect here.
- if (!other_network_) {
+ // Save password here.
+ if (wifi_.get()) {
bool changed = false;
- if (autoconnect_checkbox_) {
- bool auto_connect = autoconnect_checkbox_->checked();
- if (auto_connect != wifi_->auto_connect()) {
- wifi_->set_auto_connect(auto_connect);
- changed = true;
- }
- }
-
if (passphrase_textfield_) {
std::string passphrase = UTF16ToUTF8(passphrase_textfield_->text());
if (passphrase != wifi_->passphrase()) {
@@ -305,15 +282,6 @@ const std::string WifiConfigView::GetPassphrase() const {
return result;
}
-void WifiConfigView::FocusFirstField() {
- if (ssid_textfield_)
- ssid_textfield_->RequestFocus();
- else if (identity_textfield_)
- identity_textfield_->RequestFocus();
- else if (passphrase_textfield_)
- passphrase_textfield_->RequestFocus();
-}
-
void WifiConfigView::Init() {
views::GridLayout* layout = CreatePanelGridLayout(this);
SetLayoutManager(layout);
@@ -334,7 +302,7 @@ void WifiConfigView::Init() {
layout->StartRow(0, column_view_set_id);
layout->AddView(new views::Label(l10n_util::GetString(
IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_NETWORK_ID)));
- if (other_network_) {
+ if (!wifi_.get()) {
ssid_textfield_ = new views::Textfield(views::Textfield::STYLE_DEFAULT);
ssid_textfield_->SetController(this);
layout->AddView(ssid_textfield_);
@@ -394,7 +362,7 @@ void WifiConfigView::Init() {
}
// Security select
- if (other_network_) {
+ if (!wifi_.get()) {
layout->StartRow(0, column_view_set_id);
layout->AddView(new views::Label(l10n_util::GetString(
IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_SECURITY)));
@@ -405,41 +373,34 @@ void WifiConfigView::Init() {
}
// Passphrase input
- // Add passphrase if other_network or wifi is encrypted.
- if (other_network_ || (wifi_.get() && wifi_->encrypted() &&
- !certificate_loaded)) {
- layout->StartRow(0, column_view_set_id);
- int label_text_id;
- if (wifi_.get() && wifi_->encryption() == SECURITY_8021X)
- label_text_id =
- IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PRIVATE_KEY_PASSWORD;
- else
- label_text_id = IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PASSPHRASE;
- layout->AddView(new views::Label(l10n_util::GetString(label_text_id)));
- passphrase_textfield_ = new views::Textfield(
- views::Textfield::STYLE_PASSWORD);
- passphrase_textfield_->SetController(this);
- if (wifi_.get() && !wifi_->passphrase().empty())
- passphrase_textfield_->SetText(UTF8ToUTF16(wifi_->passphrase()));
- // Disable passphrase input initially for other network.
- if (other_network_)
- passphrase_textfield_->SetEnabled(false);
- layout->AddView(passphrase_textfield_);
- // Password visible button.
- passphrase_visible_button_ = new views::ImageButton(this);
- passphrase_visible_button_->SetImage(views::ImageButton::BS_NORMAL,
- ResourceBundle::GetSharedInstance().
- GetBitmapNamed(IDR_STATUSBAR_NETWORK_SECURE));
- passphrase_visible_button_->SetImageAlignment(
- views::ImageButton::ALIGN_CENTER, views::ImageButton::ALIGN_MIDDLE);
- // Disable viewing password by unauthenticated user.
- if (wifi_.get() && !wifi_->passphrase().empty() &&
- chromeos::UserManager::Get()->logged_in_user().email().empty()) {
- passphrase_visible_button_->SetVisible(false);
- }
- layout->AddView(passphrase_visible_button_);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
+ layout->StartRow(0, column_view_set_id);
+ int label_text_id;
+ if (wifi_.get() && wifi_->encryption() == SECURITY_8021X) {
+ label_text_id =
+ IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PRIVATE_KEY_PASSWORD;
+ } else {
+ label_text_id = IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PASSPHRASE;
}
+ layout->AddView(new views::Label(l10n_util::GetString(label_text_id)));
+ passphrase_textfield_ = new views::Textfield(
+ views::Textfield::STYLE_PASSWORD);
+ passphrase_textfield_->SetController(this);
+ if (wifi_.get() && !wifi_->passphrase().empty())
+ passphrase_textfield_->SetText(UTF8ToUTF16(wifi_->passphrase()));
+ // Disable passphrase input initially for other network.
+ if (!wifi_.get())
+ passphrase_textfield_->SetEnabled(false);
+ layout->AddView(passphrase_textfield_);
+ // Password visible button.
+ passphrase_visible_button_ = new views::ImageButton(this);
+ passphrase_visible_button_->SetImage(
+ views::ImageButton::BS_NORMAL,
+ ResourceBundle::GetSharedInstance().
+ GetBitmapNamed(IDR_STATUSBAR_NETWORK_SECURE));
+ passphrase_visible_button_->SetImageAlignment(
+ views::ImageButton::ALIGN_CENTER, views::ImageButton::ALIGN_MIDDLE);
+ layout->AddView(passphrase_visible_button_);
+ layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
// Create an error label.
layout->StartRow(0, column_view_set_id);
@@ -451,19 +412,6 @@ void WifiConfigView::Init() {
layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
// Set or hide the error text.
UpdateErrorLabel(false);
-
- // Autoconnect checkbox
- // Only show if this network is already remembered (a favorite).
- if (wifi_.get() && wifi_->favorite()) {
- autoconnect_checkbox_ = new views::Checkbox(l10n_util::GetString(
- IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_AUTO_CONNECT));
- // For other network, default to autoconnect.
- bool autoconnect = other_network_ || wifi_->auto_connect();
- autoconnect_checkbox_->SetChecked(autoconnect);
- layout->StartRow(0, column_view_set_id);
- layout->AddView(autoconnect_checkbox_, 3, 1);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
- }
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/options/wifi_config_view.h b/chrome/browser/chromeos/options/wifi_config_view.h
index 120fd27..beeb5af 100644
--- a/chrome/browser/chromeos/options/wifi_config_view.h
+++ b/chrome/browser/chromeos/options/wifi_config_view.h
@@ -71,14 +71,7 @@ class WifiConfigView : public views::View,
// Returns true if the textfields are non-empty and we can login.
bool can_login() const { return can_login_; }
- // Focus the first field in the UI.
- void FocusFirstField();
-
private:
- FRIEND_TEST_ALL_PREFIXES(WifiConfigViewTest, NoChangeSaveTest);
- FRIEND_TEST_ALL_PREFIXES(WifiConfigViewTest, ChangeAutoConnectSaveTest);
- FRIEND_TEST_ALL_PREFIXES(WifiConfigViewTest, ChangePasswordSaveTest);
-
class SecurityComboboxModel : public ComboboxModel {
public:
SecurityComboboxModel() {}
@@ -95,16 +88,11 @@ class WifiConfigView : public views::View,
// Updates state of the Login button.
void UpdateCanLogin();
- // Updates state of the "view password" button.
- void UpdateCanViewPassword();
-
// Updates the error text label.
void UpdateErrorLabel(bool failed);
NetworkConfigView* parent_;
- bool other_network_;
-
// Whether or not we can log in. This gets recalculated when textfield
// contents change.
bool can_login_;
@@ -119,7 +107,6 @@ class WifiConfigView : public views::View,
views::Combobox* security_combobox_;
views::Textfield* passphrase_textfield_;
views::ImageButton* passphrase_visible_button_;
- views::Checkbox* autoconnect_checkbox_;
views::Label* error_label_;
DISALLOW_COPY_AND_ASSIGN(WifiConfigView);
diff --git a/chrome/browser/chromeos/options/wifi_config_view_browsertest.cc b/chrome/browser/chromeos/options/wifi_config_view_browsertest.cc
deleted file mode 100644
index 02d5066..0000000
--- a/chrome/browser/chromeos/options/wifi_config_view_browsertest.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// 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.
-
-#include "chrome/browser/chromeos/options/wifi_config_view.h"
-
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
-#include "chrome/browser/chromeos/cros/mock_network_library.h"
-
-namespace chromeos {
-using ::testing::AnyNumber;
-using ::testing::InvokeWithoutArgs;
-using ::testing::Return;
-using ::testing::ReturnRef;
-using ::testing::_;
-
-class WifiConfigViewTest : public CrosInProcessBrowserTest {
- protected:
- MockNetworkLibrary *mock_network_library_;
-
- WifiConfigViewTest() : CrosInProcessBrowserTest() {}
-
- virtual void SetUpInProcessBrowserTestFixture() {
- cros_mock_->InitStatusAreaMocks();
- cros_mock_->SetStatusAreaMocksExpectations();
- mock_network_library_ = cros_mock_->mock_network_library();
- }
-};
-
-// Test that if nothing is changed, we don't call SaveWifiNetwork.
-IN_PROC_BROWSER_TEST_F(WifiConfigViewTest, NoChangeSaveTest) {
- EXPECT_CALL(*mock_network_library_, SaveWifiNetwork(_)).Times(0);
- scoped_ptr<WifiNetwork> network(new WifiNetwork());
- WifiConfigView* view = new WifiConfigView(NULL, network.get());
- view->Save();
-}
-
-// Test that if autoconnect was changed, we call SaveWifiNetwork.
-IN_PROC_BROWSER_TEST_F(WifiConfigViewTest, ChangeAutoConnectSaveTest) {
- EXPECT_CALL(*mock_network_library_, SaveWifiNetwork(_)).Times(1);
- scoped_ptr<WifiNetwork> remembered_network(new WifiNetwork());
- remembered_network->favorite_ = true;
- WifiConfigView* view = new WifiConfigView(NULL, remembered_network.get());
- ASSERT_TRUE(view->autoconnect_checkbox_ != NULL);
- view->autoconnect_checkbox_->SetChecked(
- !view->autoconnect_checkbox_->checked());
- view->Save();
-}
-
-// Test that if password was changed, we call SaveWifiNetwork.
-IN_PROC_BROWSER_TEST_F(WifiConfigViewTest, ChangePasswordSaveTest) {
- EXPECT_CALL(*mock_network_library_, SaveWifiNetwork(_)).Times(1);
- scoped_ptr<WifiNetwork> wifi(new WifiNetwork());
- wifi->set_encryption(SECURITY_WEP);
- WifiConfigView* view = new WifiConfigView(NULL, wifi.get());
- view->passphrase_textfield_->SetText(ASCIIToUTF16("test"));
- view->Save();
-}
-
-} // namespace chromeos
diff --git a/chrome/browser/chromeos/panels/panel_browsertest.cc b/chrome/browser/chromeos/panels/panel_browsertest.cc
index f655369..f928371 100644
--- a/chrome/browser/chromeos/panels/panel_browsertest.cc
+++ b/chrome/browser/chromeos/panels/panel_browsertest.cc
@@ -4,16 +4,14 @@
#include "base/command_line.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/chromeos/wm_ipc.h"
#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
-#include "cros/chromeos_wm_ipc_enums.h"
+#include "third_party/cros/chromeos_wm_ipc_enums.h"
namespace chromeos {
@@ -27,7 +25,6 @@ class PanelTest : public InProcessBrowserTest {
virtual void SetUpCommandLine(CommandLine* command_line) {
command_line->AppendSwitch(switches::kDisablePopupBlocking);
}
-
};
// Small popups should open as a panel.
diff --git a/chrome/browser/chromeos/plugin_selection_policy.cc b/chrome/browser/chromeos/plugin_selection_policy.cc
index 477965a..dd261ea 100644
--- a/chrome/browser/chromeos/plugin_selection_policy.cc
+++ b/chrome/browser/chromeos/plugin_selection_policy.cc
@@ -120,8 +120,9 @@ bool PluginSelectionPolicy::InitFromFile(const FilePath& policy_file) {
int PluginSelectionPolicy::FindFirstAllowed(
const GURL& url,
- const std::vector<WebPluginInfo>& info) {
- for (std::vector<WebPluginInfo>::size_type i = 0; i < info.size(); ++i) {
+ const std::vector<webkit::npapi::WebPluginInfo>& info) {
+ for (std::vector<webkit::npapi::WebPluginInfo>::size_type i = 0;
+ i < info.size(); ++i) {
if (IsAllowed(url, info[i].path))
return i;
}
diff --git a/chrome/browser/chromeos/plugin_selection_policy.h b/chrome/browser/chromeos/plugin_selection_policy.h
index 1bf60a0..08816bf 100644
--- a/chrome/browser/chromeos/plugin_selection_policy.h
+++ b/chrome/browser/chromeos/plugin_selection_policy.h
@@ -11,7 +11,7 @@
#include "base/gtest_prod_util.h"
#include "base/ref_counted.h"
-#include "webkit/glue/plugins/webplugininfo.h"
+#include "webkit/plugins/npapi/webplugininfo.h"
class GURL;
class FilePath;
@@ -45,7 +45,8 @@ class PluginSelectionPolicy
// allowed (or if the info vector is empty). InitFromFile must
// complete before any calls to FindFirstAllowed happen or it will
// assert.
- int FindFirstAllowed(const GURL& url, const std::vector<WebPluginInfo>& info);
+ int FindFirstAllowed(const GURL& url,
+ const std::vector<webkit::npapi::WebPluginInfo>& info);
// Applies the current policy to the given path using the url to
// look up what the policy for that domain is. Returns true if the
diff --git a/chrome/browser/chromeos/plugin_selection_policy_unittest.cc b/chrome/browser/chromeos/plugin_selection_policy_unittest.cc
index 4bc4538..279b14f 100644
--- a/chrome/browser/chromeos/plugin_selection_policy_unittest.cc
+++ b/chrome/browser/chromeos/plugin_selection_policy_unittest.cc
@@ -242,8 +242,8 @@ TEST_F(PluginSelectionPolicyTest, FindFirstAllowed) {
FilePath("/usr/local/bin/allow_baz_bim2.so")));
EXPECT_FALSE(policy->IsAllowed(GURL("http://www.google.com/blah.html"),
FilePath("/usr/local/bin/allow_baz_bim2.so")));
- std::vector<WebPluginInfo> info_vector;
- WebPluginInfo info;
+ std::vector<webkit::npapi::WebPluginInfo> info_vector;
+ webkit::npapi::WebPluginInfo info;
// First we test that the one without any policy gets
// selected for all if it's first.
info.path = FilePath("/usr/local/bin/no_policy.so");
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc
index ce0cbf4..0f57dae 100644
--- a/chrome/browser/chromeos/preferences.cc
+++ b/chrome/browser/chromeos/preferences.cc
@@ -7,16 +7,18 @@
#include "base/string_split.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/input_method_library.h"
#include "chrome/browser/chromeos/cros/keyboard_library.h"
#include "chrome/browser/chromeos/cros/power_library.h"
#include "chrome/browser/chromeos/cros/touchpad_library.h"
#include "chrome/browser/chromeos/input_method/input_method_util.h"
+#include "chrome/browser/chromeos/login/login_utils.h"
#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "unicode/timezone.h"
@@ -188,6 +190,12 @@ void Preferences::Init(PrefService* prefs) {
// Initialize touchpad settings to what's saved in user preferences.
NotifyPrefChanged(NULL);
+
+ // If a guest is logged in, initialize the prefs as if this is the first
+ // login.
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kGuestSession)) {
+ LoginUtils::Get()->SetFirstLoginPrefs(prefs);
+ }
}
void Preferences::Observe(NotificationType type,
diff --git a/chrome/browser/chromeos/proxy_config_service_impl.cc b/chrome/browser/chromeos/proxy_config_service_impl.cc
index 5b2902c..862459c 100644
--- a/chrome/browser/chromeos/proxy_config_service_impl.cc
+++ b/chrome/browser/chromeos/proxy_config_service_impl.cc
@@ -357,7 +357,8 @@ ProxyConfigServiceImpl::ProxyConfigServiceImpl()
if (CrosLibrary::Get()->EnsureLoaded()) {
retrieve_property_op_ = SignedSettings::CreateRetrievePropertyOp(
kSettingProxyEverywhere, this);
- if (retrieve_property_op_ && retrieve_property_op_->Execute()) {
+ if (retrieve_property_op_) {
+ retrieve_property_op_->Execute();
VLOG(1) << "Start retrieving proxy setting from device";
use_default = false;
} else {
@@ -488,35 +489,34 @@ bool ProxyConfigServiceImpl::IOGetProxyConfig(net::ProxyConfig* net_config) {
return false;
}
-void ProxyConfigServiceImpl::OnSettingsOpSucceeded(bool value) {
- VLOG(1) << "Stored proxy setting to device";
+void ProxyConfigServiceImpl::OnSettingsOpCompleted(
+ SignedSettings::ReturnCode code,
+ bool value) {
+ if (SignedSettings::SUCCESS == code)
+ VLOG(1) << "Stored proxy setting to device";
+ else
+ LOG(WARNING) << "Error storing proxy setting to device";
store_property_op_ = NULL;
if (persist_to_device_pending_)
PersistConfigToDevice();
}
-void ProxyConfigServiceImpl::OnSettingsOpSucceeded(std::string value) {
- VLOG(1) << "Retrieved proxy setting from device, value=[" << value << "]";
- if (reference_config_.Deserialize(value)) {
- OnUISetProxyConfig(false);
+void ProxyConfigServiceImpl::OnSettingsOpCompleted(
+ SignedSettings::ReturnCode code,
+ std::string value) {
+ if (SignedSettings::SUCCESS == code) {
+ VLOG(1) << "Retrieved proxy setting from device, value=[" << value << "]";
+ if (reference_config_.Deserialize(value)) {
+ OnUISetProxyConfig(false);
+ } else {
+ LOG(WARNING) << "Error deserializing device's proxy setting";
+ InitConfigToDefault(true);
+ }
} else {
- LOG(WARNING) << "Error deserializing device's proxy setting";
- InitConfigToDefault(true);
- }
- retrieve_property_op_ = NULL;
-}
-
-void ProxyConfigServiceImpl::OnSettingsOpFailed() {
- if (retrieve_property_op_) {
LOG(WARNING) << "Error retrieving proxy setting from device";
InitConfigToDefault(true);
- retrieve_property_op_ = NULL;
- } else {
- LOG(WARNING) << "Error storing proxy setting to device";
- store_property_op_ = NULL;
- if (persist_to_device_pending_)
- PersistConfigToDevice();
}
+ retrieve_property_op_ = NULL;
}
//------------------ ProxyConfigServiceImpl: private methods -------------------
@@ -539,14 +539,13 @@ void ProxyConfigServiceImpl::PersistConfigToDevice() {
persist_to_device_pending_ = false;
std::string value;
if (!reference_config_.Serialize(&value)) {
- VLOG(1) << "Error serializing proxy config";
+ LOG(WARNING) << "Error serializing proxy config";
return;
}
store_property_op_ = SignedSettings::CreateStorePropertyOp(
kSettingProxyEverywhere, value, this);
- bool rc = store_property_op_->Execute();
- VLOG(1) << "Start storing proxy setting to device, value=" << value << ", rc="
- << rc;
+ store_property_op_->Execute();
+ VLOG(1) << "Start storing proxy setting to device, value=" << value;
}
void ProxyConfigServiceImpl::OnUISetProxyConfig(bool persist_to_device) {
diff --git a/chrome/browser/chromeos/proxy_config_service_impl.h b/chrome/browser/chromeos/proxy_config_service_impl.h
index 5e562d2..2e605a8 100644
--- a/chrome/browser/chromeos/proxy_config_service_impl.h
+++ b/chrome/browser/chromeos/proxy_config_service_impl.h
@@ -190,9 +190,10 @@ class ProxyConfigServiceImpl
bool UISetProxyConfigBypassRules(const net::ProxyBypassRules& bypass_rules);
// Implementation for SignedSettings::Delegate
- virtual void OnSettingsOpSucceeded(bool value);
- virtual void OnSettingsOpSucceeded(std::string value);
- virtual void OnSettingsOpFailed();
+ virtual void OnSettingsOpCompleted(SignedSettings::ReturnCode code,
+ std::string value);
+ virtual void OnSettingsOpCompleted(SignedSettings::ReturnCode code,
+ bool value);
private:
friend class base::RefCountedThreadSafe<ProxyConfigServiceImpl>;
diff --git a/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc b/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc
index 7ba6def..15a8327 100644
--- a/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc
+++ b/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc
@@ -224,12 +224,10 @@ class ProxyConfigServiceImplTest : public PlatformTest {
ProxyConfigServiceImplTest()
: ui_thread_(BrowserThread::UI, &message_loop_),
io_thread_(BrowserThread::IO, &message_loop_) {
- chromeos::CrosLibrary::Get()->GetTestApi()->SetUseStubImpl();
}
virtual ~ProxyConfigServiceImplTest() {
config_service_ = NULL;
- chromeos::CrosLibrary::Get()->GetTestApi()->ResetUseStubImpl();
MessageLoop::current()->RunAllPending();
}
@@ -311,6 +309,7 @@ class ProxyConfigServiceImplTest : public PlatformTest {
}
private:
+ ScopedStubCrosEnabler stub_cros_enabler_;
MessageLoop message_loop_;
BrowserThread ui_thread_;
BrowserThread io_thread_;
diff --git a/chrome/browser/chromeos/proxy_cros_settings_provider.cc b/chrome/browser/chromeos/proxy_cros_settings_provider.cc
index cc4f586..898a4bc 100644
--- a/chrome/browser/chromeos/proxy_cros_settings_provider.cc
+++ b/chrome/browser/chromeos/proxy_cros_settings_provider.cc
@@ -6,8 +6,8 @@
#include "base/string_util.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
namespace chromeos {
diff --git a/chrome/browser/chromeos/setting_level_bubble.cc b/chrome/browser/chromeos/setting_level_bubble.cc
new file mode 100644
index 0000000..22aeced
--- /dev/null
+++ b/chrome/browser/chromeos/setting_level_bubble.cc
@@ -0,0 +1,152 @@
+// 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.
+
+#include "chrome/browser/chromeos/setting_level_bubble.h"
+
+#include <gdk/gdk.h>
+
+#include "base/timer.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/browser_window.h"
+#include "chrome/browser/chromeos/setting_level_bubble_view.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/views/info_bubble.h"
+#include "views/widget/root_view.h"
+
+namespace {
+
+const int kBubbleShowTimeoutSec = 2;
+const int kAnimationDurationMs = 200;
+
+// Horizontal relative position: 0 - leftmost, 0.5 - center, 1 - rightmost.
+const double kBubbleXRatio = 0.5;
+
+// Vertical gap from the bottom of the screen in pixels.
+const int kBubbleBottomGap = 30;
+
+} // namespace
+
+namespace chromeos {
+
+// Temporary helper routine. Returns the widget from the most-recently-focused
+// normal browser window or NULL.
+// TODO(glotov): remove this in favor of enabling InfoBubble class act
+// without |parent| specified. crosbug.com/4025
+static views::Widget* GetToplevelWidget() {
+ // We just use the default profile here -- this gets overridden as needed
+ // in Chrome OS depending on whether the user is logged in or not.
+ Browser* browser =
+ BrowserList::FindBrowserWithType(
+ ProfileManager::GetDefaultProfile(),
+ Browser::TYPE_NORMAL,
+ true); // match_incognito
+ if (!browser)
+ return NULL;
+
+ views::RootView* root =
+ views::Widget::FindRootView(
+ GTK_WINDOW(browser->window()->GetNativeHandle()));
+ DCHECK(root);
+ if (!root)
+ return NULL;
+
+ return root->GetWidget();
+}
+
+SettingLevelBubble::SettingLevelBubble(SkBitmap* increase_icon,
+ SkBitmap* decrease_icon,
+ SkBitmap* zero_icon)
+ : previous_percent_(-1),
+ current_percent_(-1),
+ increase_icon_(increase_icon),
+ decrease_icon_(decrease_icon),
+ zero_icon_(zero_icon),
+ bubble_(NULL),
+ view_(NULL),
+ animation_(this) {
+ animation_.SetSlideDuration(kAnimationDurationMs);
+ animation_.SetTweenType(Tween::LINEAR);
+}
+
+void SettingLevelBubble::ShowBubble(int percent) {
+ if (percent < 0)
+ percent = 0;
+ if (percent > 100)
+ percent = 100;
+ if (previous_percent_ == -1)
+ previous_percent_ = percent;
+ current_percent_ = percent;
+
+ SkBitmap* icon = increase_icon_;
+ if (current_percent_ == 0)
+ icon = zero_icon_;
+ else if (current_percent_ < previous_percent_)
+ icon = decrease_icon_;
+
+ if (!bubble_) {
+ views::Widget* widget = GetToplevelWidget();
+ if (widget == NULL)
+ return;
+ DCHECK(view_ == NULL);
+ view_ = new SettingLevelBubbleView;
+ view_->Init(icon, previous_percent_);
+ // Calculate position of the bubble.
+ gfx::Rect bounds;
+ widget->GetBounds(&bounds, false);
+ const gfx::Size view_size = view_->GetPreferredSize();
+ // Note that (x, y) is the point of the center of the bubble.
+ const int x = view_size.width() / 2 +
+ kBubbleXRatio * (bounds.width() - view_size.width());
+ const int y = bounds.height() - view_size.height() / 2 - kBubbleBottomGap;
+ bubble_ = InfoBubble::ShowFocusless(widget, // parent
+ gfx::Rect(x, y, 0, 20),
+ BubbleBorder::FLOAT,
+ view_, // contents
+ this, // delegate
+ true); // show while screen is locked
+ } else {
+ DCHECK(view_);
+ timeout_timer_.Stop();
+ view_->SetIcon(icon);
+ }
+ if (animation_.is_animating())
+ animation_.End();
+ animation_.Reset();
+ animation_.Show();
+ timeout_timer_.Start(base::TimeDelta::FromSeconds(kBubbleShowTimeoutSec),
+ this, &SettingLevelBubble::OnTimeout);
+}
+
+void SettingLevelBubble::HideBubble() {
+ if (bubble_)
+ bubble_->Close();
+}
+
+void SettingLevelBubble::OnTimeout() {
+ HideBubble();
+}
+
+void SettingLevelBubble::InfoBubbleClosing(InfoBubble* info_bubble, bool) {
+ DCHECK(info_bubble == bubble_);
+ timeout_timer_.Stop();
+ animation_.Stop();
+ bubble_ = NULL;
+ view_ = NULL;
+}
+
+void SettingLevelBubble::AnimationEnded(const Animation* animation) {
+ previous_percent_ = current_percent_;
+}
+
+void SettingLevelBubble::AnimationProgressed(const Animation* animation) {
+ if (view_) {
+ view_->Update(
+ Tween::ValueBetween(animation->GetCurrentValue(),
+ previous_percent_,
+ current_percent_));
+ }
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/setting_level_bubble.h b/chrome/browser/chromeos/setting_level_bubble.h
new file mode 100644
index 0000000..262bbdc
--- /dev/null
+++ b/chrome/browser/chromeos/setting_level_bubble.h
@@ -0,0 +1,72 @@
+// 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_SETTING_LEVEL_BUBBLE_H_
+#define CHROME_BROWSER_CHROMEOS_SETTING_LEVEL_BUBBLE_H_
+#pragma once
+
+#include "app/animation_delegate.h"
+#include "app/slide_animation.h"
+#include "base/basictypes.h"
+#include "base/timer.h"
+#include "chrome/browser/views/info_bubble.h"
+
+class SkBitmap;
+
+namespace chromeos {
+
+class SettingLevelBubbleView;
+
+// Singleton class controlling a bubble displaying a level-based setting like
+// volume or brightness.
+class SettingLevelBubble : public InfoBubbleDelegate,
+ public AnimationDelegate {
+ public:
+ void ShowBubble(int percent);
+ void HideBubble();
+
+ protected:
+ explicit SettingLevelBubble(SkBitmap* increase_icon,
+ SkBitmap* decrease_icon,
+ SkBitmap* zero_icon);
+ virtual ~SettingLevelBubble() {}
+
+ private:
+ void OnTimeout();
+
+ // Overridden from InfoBubbleDelegate.
+ virtual void InfoBubbleClosing(InfoBubble* info_bubble,
+ bool closed_by_escape);
+ virtual bool CloseOnEscape() { return true; }
+ virtual bool FadeInOnShow() { return false; }
+
+ // Overridden from AnimationDelegate.
+ virtual void AnimationEnded(const Animation* animation);
+ virtual void AnimationProgressed(const Animation* animation);
+
+ // Previous and current percentages, or -1 if not yet shown.
+ int previous_percent_;
+ int current_percent_;
+
+ // Icons displayed in the bubble when increasing or decreasing the level or
+ // setting it to zero. Not owned by us.
+ SkBitmap* increase_icon_;
+ SkBitmap* decrease_icon_;
+ SkBitmap* zero_icon_;
+
+ // Currently shown bubble or NULL.
+ InfoBubble* bubble_;
+
+ // Its contents view, owned by InfoBubble.
+ SettingLevelBubbleView* view_;
+
+ SlideAnimation animation_;
+ base::OneShotTimer<SettingLevelBubble> timeout_timer_;
+
+ DISALLOW_COPY_AND_ASSIGN(SettingLevelBubble);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_SETTING_LEVEL_BUBBLE_H_
diff --git a/chrome/browser/chromeos/setting_level_bubble_view.cc b/chrome/browser/chromeos/setting_level_bubble_view.cc
new file mode 100644
index 0000000..c566124
--- /dev/null
+++ b/chrome/browser/chromeos/setting_level_bubble_view.cc
@@ -0,0 +1,70 @@
+// 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.
+
+#include "chrome/browser/chromeos/setting_level_bubble_view.h"
+
+#include <string>
+
+#include "base/logging.h"
+#include "gfx/canvas.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "views/controls/progress_bar.h"
+
+using views::Background;
+using views::View;
+using views::Widget;
+
+namespace {
+
+// Bubble metrics.
+const int kWidth = 350, kHeight = 100;
+const int kPadding = 20;
+const int kProgressBarWidth = 211;
+const int kProgressBarHeight = 17;
+
+} // namespace
+
+namespace chromeos {
+
+SettingLevelBubbleView::SettingLevelBubbleView()
+ : progress_bar_(NULL),
+ icon_(NULL) {
+}
+
+void SettingLevelBubbleView::Init(SkBitmap* icon, int level_percent) {
+ DCHECK(icon);
+ DCHECK(level_percent >= 0 && level_percent <= 100);
+ icon_ = icon;
+ progress_bar_ = new views::ProgressBar();
+ AddChildView(progress_bar_);
+ Update(level_percent);
+}
+
+void SettingLevelBubbleView::SetIcon(SkBitmap* icon) {
+ DCHECK(icon);
+ icon_ = icon;
+ SchedulePaint();
+}
+
+void SettingLevelBubbleView::Update(int level_percent) {
+ DCHECK(level_percent >= 0 && level_percent <= 100);
+ progress_bar_->SetProgress(level_percent);
+}
+
+void SettingLevelBubbleView::Paint(gfx::Canvas* canvas) {
+ views::View::Paint(canvas);
+ canvas->DrawBitmapInt(*icon_, kPadding, (height() - icon_->height()) / 2);
+}
+
+void SettingLevelBubbleView::Layout() {
+ progress_bar_->SetBounds(width() - kPadding - kProgressBarWidth,
+ (height() - kProgressBarHeight) / 2,
+ kProgressBarWidth, kProgressBarHeight);
+}
+
+gfx::Size SettingLevelBubbleView::GetPreferredSize() {
+ return gfx::Size(kWidth, kHeight);
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/setting_level_bubble_view.h b/chrome/browser/chromeos/setting_level_bubble_view.h
new file mode 100644
index 0000000..519fef8
--- /dev/null
+++ b/chrome/browser/chromeos/setting_level_bubble_view.h
@@ -0,0 +1,50 @@
+// 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_SETTING_LEVEL_BUBBLE_VIEW_H_
+#define CHROME_BROWSER_CHROMEOS_SETTING_LEVEL_BUBBLE_VIEW_H_
+#pragma once
+
+#include "views/view.h"
+
+namespace views {
+class ProgressBar;
+} // namespace views
+
+class SkBitmap;
+
+namespace chromeos {
+
+// SettingLevelBubbleView displays information about the current value of a
+// level-based setting like volume or brightness.
+class SettingLevelBubbleView : public views::View {
+ public:
+ SettingLevelBubbleView();
+
+ // Initialize the view, setting the progress bar to the specified position.
+ // Ownership of |icon| remains with the caller (it's probably a shared
+ // instance from ResourceBundle).
+ void Init(SkBitmap* icon, int level_percent);
+
+ // Change the icon that we're currently displaying.
+ void SetIcon(SkBitmap* icon);
+
+ // Set the progress bar to the specified position and redraw it.
+ void Update(int level_percent);
+
+ // views::View implementation:
+ virtual void Paint(gfx::Canvas* canvas);
+ virtual void Layout();
+ virtual gfx::Size GetPreferredSize();
+
+ private:
+ views::ProgressBar* progress_bar_;
+ SkBitmap* icon_; // not owned
+
+ DISALLOW_COPY_AND_ASSIGN(SettingLevelBubbleView);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_SETTING_LEVEL_BUBBLE_VIEW_H_
diff --git a/chrome/browser/chromeos/status/clock_menu_button.cc b/chrome/browser/chromeos/status/clock_menu_button.cc
index 93e44eb..b239112 100644
--- a/chrome/browser/chromeos/status/clock_menu_button.cc
+++ b/chrome/browser/chromeos/status/clock_menu_button.cc
@@ -12,7 +12,6 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/status/status_area_host.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/pref_names.h"
#include "gfx/canvas.h"
@@ -41,7 +40,7 @@ ClockMenuButton::ClockMenuButton(StatusAreaHost* host)
set_use_menu_button_paint(true);
SetFont(ResourceBundle::GetSharedInstance().GetFont(
ResourceBundle::BaseFont).DeriveFont(kFontSizeDelta));
- SetEnabledColor(0xB3FFFFFF); // White with 70% Alpha
+ SetEnabledColor(0xB3FFFFFF); // White with 70% Alpha
SetShowMultipleIconStates(false);
set_alignment(TextButton::ALIGN_CENTER);
UpdateTextAndSetNextTimer();
@@ -77,8 +76,8 @@ void ClockMenuButton::UpdateTextAndSetNextTimer() {
void ClockMenuButton::UpdateText() {
base::Time time(base::Time::Now());
- SetText(base::TimeFormatTimeOfDay(time));
- SetTooltipText(base::TimeFormatShortDate(time));
+ SetText(UTF16ToWide(base::TimeFormatTimeOfDay(time)));
+ SetTooltipText(UTF16ToWide(base::TimeFormatShortDate(time)));
SchedulePaint();
}
@@ -100,7 +99,7 @@ menus::MenuModel::ItemType ClockMenuButton::GetTypeAt(int index) const {
string16 ClockMenuButton::GetLabelAt(int index) const {
if (index == 0)
- return WideToUTF16(base::TimeFormatFriendlyDate(base::Time::Now()));
+ return base::TimeFormatFriendlyDate(base::Time::Now());
return l10n_util::GetStringUTF16(IDS_STATUSBAR_CLOCK_OPEN_OPTIONS_DIALOG);
}
diff --git a/chrome/browser/chromeos/status/clock_menu_button.h b/chrome/browser/chromeos/status/clock_menu_button.h
index 76f214a..c1bea3c 100644
--- a/chrome/browser/chromeos/status/clock_menu_button.h
+++ b/chrome/browser/chromeos/status/clock_menu_button.h
@@ -11,7 +11,6 @@
#include "chrome/browser/chromeos/cros/system_library.h"
#include "chrome/browser/chromeos/status/status_area_button.h"
#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_service.h"
#include "unicode/calendar.h"
#include "views/controls/button/menu_button.h"
#include "views/controls/menu/menu_2.h"
@@ -37,7 +36,7 @@ class ClockMenuButton : public StatusAreaButton,
virtual menus::MenuModel::ItemType GetTypeAt(int index) const;
virtual int GetCommandIdAt(int index) const { return index; }
virtual string16 GetLabelAt(int index) const;
- virtual bool IsLabelDynamicAt(int index) const { return true; }
+ virtual bool IsItemDynamicAt(int index) const { return true; }
virtual bool GetAcceleratorAt(int index,
menus::Accelerator* accelerator) const { return false; }
virtual bool IsItemCheckedAt(int index) const { return false; }
diff --git a/chrome/browser/chromeos/status/clock_menu_button_browsertest.cc b/chrome/browser/chromeos/status/clock_menu_button_browsertest.cc
index 2d494e1..9f934d6 100644
--- a/chrome/browser/chromeos/status/clock_menu_button_browsertest.cc
+++ b/chrome/browser/chromeos/status/clock_menu_button_browsertest.cc
@@ -11,7 +11,6 @@
#include "chrome/browser/chromeos/status/status_area_view.h"
#include "chrome/browser/chromeos/view_ids.h"
#include "chrome/browser/prefs/pref_member.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/common/pref_names.h"
@@ -51,7 +50,6 @@ IN_PROC_BROWSER_TEST_F(ClockMenuButtonTest, TimezoneTest) {
CrosLibrary::Get()->GetSystemLibrary()->SetTimezone(timezone_second.get());
std::wstring text_after = clock->text();
EXPECT_NE(text_before, text_after);
-
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/status/input_method_menu.cc b/chrome/browser/chromeos/status/input_method_menu.cc
index 027f141..3b81133 100644
--- a/chrome/browser/chromeos/status/input_method_menu.cc
+++ b/chrome/browser/chromeos/status/input_method_menu.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/chromeos/status/input_method_menu.h"
#include <string>
+#include <vector>
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
@@ -19,7 +20,7 @@
#include "chrome/browser/chromeos/language_preferences.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
@@ -85,6 +86,7 @@ const struct {
{ "xkb:us:altgr-intl:eng", "EXTD" },
{ "xkb:us:dvorak:eng", "DV" },
{ "xkb:us:intl:eng", "INTL" },
+ { "xkb:us:colemak:eng", "CO" },
// To distinguish from "xkb:jp::jpn"
{ "mozc", "\xe3\x81\x82" }, // U+3042, Japanese Hiragana letter A in UTF-8.
{ "mozc-dv", "\xe3\x81\x82" },
@@ -181,7 +183,7 @@ int InputMethodMenu::GetCommandIdAt(int index) const {
return 0; // dummy
}
-bool InputMethodMenu::IsLabelDynamicAt(int index) const {
+bool InputMethodMenu::IsItemDynamicAt(int index) const {
// Menu content for the language button could change time by time.
return true;
}
@@ -378,16 +380,20 @@ void InputMethodMenu::RunMenu(
////////////////////////////////////////////////////////////////////////////////
// InputMethodLibrary::Observer implementation:
-void InputMethodMenu::InputMethodChanged(InputMethodLibrary* obj) {
+void InputMethodMenu::InputMethodChanged(
+ InputMethodLibrary* obj,
+ const InputMethodDescriptor& previous_input_method,
+ const InputMethodDescriptor& current_input_method,
+ size_t num_active_input_methods) {
UserMetrics::RecordAction(
UserMetricsAction("LanguageMenuButton_InputMethodChanged"));
+ UpdateUIFromInputMethod(current_input_method, num_active_input_methods);
+}
- const InputMethodDescriptor& previous_input_method =
- obj->previous_input_method();
- const InputMethodDescriptor& current_input_method =
- obj->current_input_method();
- UpdateUIFromInputMethod(current_input_method);
- // Update Chrome prefs as well.
+void InputMethodMenu::PreferenceUpdateNeeded(
+ InputMethodLibrary* obj,
+ const InputMethodDescriptor& previous_input_method,
+ const InputMethodDescriptor& current_input_method) {
if (is_browser_mode_) {
if (pref_service_) { // make sure we're not in unit tests.
// Sometimes (e.g. initial boot) |previous_input_method.id| is empty.
@@ -418,20 +424,21 @@ void InputMethodMenu::PrepareForMenuOpen() {
}
}
-void InputMethodMenu::ActiveInputMethodsChanged(InputMethodLibrary* obj) {
+void InputMethodMenu::ActiveInputMethodsChanged(
+ InputMethodLibrary* obj,
+ const InputMethodDescriptor& current_input_method,
+ size_t num_active_input_methods) {
// Update the icon if active input methods are changed. See also
- // comments in UpdateUI()
- UpdateUIFromInputMethod(obj->current_input_method());
-}
-
-void InputMethodMenu::ImePropertiesChanged(InputMethodLibrary* obj) {
+ // comments in UpdateUI() in input_method_menu_button.cc.
+ UpdateUIFromInputMethod(current_input_method, num_active_input_methods);
}
void InputMethodMenu::UpdateUIFromInputMethod(
- const InputMethodDescriptor& input_method) {
+ const InputMethodDescriptor& input_method,
+ size_t num_active_input_methods) {
const std::wstring name = GetTextForIndicator(input_method);
const std::wstring tooltip = GetTextForMenu(input_method);
- UpdateUI(name, tooltip);
+ UpdateUI(input_method.id, name, tooltip, num_active_input_methods);
}
void InputMethodMenu::RebuildModel() {
diff --git a/chrome/browser/chromeos/status/input_method_menu.h b/chrome/browser/chromeos/status/input_method_menu.h
index a132c87..814526e 100644
--- a/chrome/browser/chromeos/status/input_method_menu.h
+++ b/chrome/browser/chromeos/status/input_method_menu.h
@@ -6,12 +6,13 @@
#define CHROME_BROWSER_CHROMEOS_STATUS_INPUT_METHOD_MENU_H_
#pragma once
+#include <string>
+
#include "app/menus/simple_menu_model.h"
#include "chrome/browser/chromeos/cros/input_method_library.h"
#include "chrome/browser/prefs/pref_member.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "views/controls/menu/menu_2.h"
#include "views/controls/menu/view_menu_delegate.h"
@@ -44,7 +45,7 @@ class InputMethodMenu : public views::ViewMenuDelegate,
virtual menus::MenuModel::ItemType GetTypeAt(int index) const;
virtual int GetCommandIdAt(int index) const;
virtual string16 GetLabelAt(int index) const;
- virtual bool IsLabelDynamicAt(int index) const;
+ virtual bool IsItemDynamicAt(int index) const;
virtual bool GetAcceleratorAt(int index,
menus::Accelerator* accelerator) const;
virtual bool IsItemCheckedAt(int index) const;
@@ -63,9 +64,19 @@ class InputMethodMenu : public views::ViewMenuDelegate,
const gfx::Point& pt);
// InputMethodLibrary::Observer implementation.
- virtual void InputMethodChanged(InputMethodLibrary* obj);
- virtual void ImePropertiesChanged(InputMethodLibrary* obj);
- virtual void ActiveInputMethodsChanged(InputMethodLibrary* obj);
+ virtual void InputMethodChanged(
+ InputMethodLibrary* obj,
+ const InputMethodDescriptor& previous_input_method,
+ const InputMethodDescriptor& current_input_method,
+ size_t num_active_input_methods);
+ virtual void ActiveInputMethodsChanged(
+ InputMethodLibrary* obj,
+ const InputMethodDescriptor& current_input_method,
+ size_t num_active_input_methods);
+ virtual void PreferenceUpdateNeeded(
+ InputMethodLibrary* obj,
+ const InputMethodDescriptor& previous_input_method,
+ const InputMethodDescriptor& current_input_method);
// NotificationObserver implementation.
virtual void Observe(NotificationType type,
@@ -89,7 +100,8 @@ class InputMethodMenu : public views::ViewMenuDelegate,
protected:
// Parses |input_method| and then calls UpdateUI().
- void UpdateUIFromInputMethod(const InputMethodDescriptor& input_method);
+ void UpdateUIFromInputMethod(const InputMethodDescriptor& input_method,
+ size_t num_active_input_methods);
// Rebuilds model and menu2 objects in preparetion to open the menu.
void PrepareForMenuOpen();
@@ -102,8 +114,10 @@ class InputMethodMenu : public views::ViewMenuDelegate,
private:
// Updates UI of a container of the menu (e.g. the "US" menu button in the
// status area). Sub classes have to implement the interface for their own UI.
- virtual void UpdateUI(
- const std::wstring& name, const std::wstring& tooltip) = 0;
+ virtual void UpdateUI(const std::string& input_method_id, // e.g. "mozc"
+ const std::wstring& name, // e.g. "US", "INTL"
+ const std::wstring& tooltip,
+ size_t num_active_input_methods) = 0;
// Sub classes have to implement the interface. This interface should return
// true if the dropdown menu should show an item like "Customize languages
diff --git a/chrome/browser/chromeos/status/input_method_menu_button.cc b/chrome/browser/chromeos/status/input_method_menu_button.cc
index 1fb5fa2..ab5987c 100644
--- a/chrome/browser/chromeos/status/input_method_menu_button.cc
+++ b/chrome/browser/chromeos/status/input_method_menu_button.cc
@@ -7,12 +7,13 @@
#include <string>
#include "app/resource_bundle.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/keyboard_library.h"
#include "chrome/browser/chromeos/input_method/input_method_util.h"
#include "chrome/browser/chromeos/status/status_area_host.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
namespace {
@@ -54,11 +55,16 @@ InputMethodMenuButton::InputMethodMenuButton(StatusAreaHost* host)
SetShowMultipleIconStates(false);
set_alignment(TextButton::ALIGN_CENTER);
+ chromeos::KeyboardLibrary* keyboard_library =
+ chromeos::CrosLibrary::Get()->GetKeyboardLibrary();
+ const std::string hardware_keyboard_id = // e.g. "xkb:us::eng"
+ keyboard_library->GetHardwareKeyboardLayoutName();
+
// Draw the default indicator "US". The default indicator "US" is used when
// |pref_service| is not available (for example, unit tests) or |pref_service|
// is available, but Chrome preferences are not available (for example,
// initial OS boot).
- InputMethodMenuButton::UpdateUI(L"US", L"");
+ InputMethodMenuButton::UpdateUI(hardware_keyboard_id, L"US", L"", 1);
}
////////////////////////////////////////////////////////////////////////////////
@@ -74,9 +80,21 @@ gfx::Size InputMethodMenuButton::GetPreferredSize() {
void InputMethodMenuButton::OnLocaleChanged() {
input_method::OnLocaleChanged();
+
+ chromeos::InputMethodLibrary* input_method_library =
+ chromeos::CrosLibrary::Get()->GetInputMethodLibrary();
const InputMethodDescriptor& input_method =
- CrosLibrary::Get()->GetInputMethodLibrary()->current_input_method();
- UpdateUIFromInputMethod(input_method);
+ input_method_library->current_input_method();
+
+ // In general, we should not call an input method API in the input method
+ // button classes (status/input_menu_button*.cc) for performance reasons (see
+ // http://crosbug.com/8284). However, since OnLocaleChanged is called only in
+ // OOBE/Login screen which does not have two or more Chrome windows, it's okay
+ // to call GetNumActiveInputMethods here.
+ const size_t num_active_input_methods =
+ input_method_library->GetNumActiveInputMethods();
+
+ UpdateUIFromInputMethod(input_method, num_active_input_methods);
Layout();
SchedulePaint();
}
@@ -84,16 +102,16 @@ void InputMethodMenuButton::OnLocaleChanged() {
////////////////////////////////////////////////////////////////////////////////
// InputMethodMenu::InputMethodMenuHost implementation:
-void InputMethodMenuButton::UpdateUI(
- const std::wstring& name, const std::wstring& tooltip) {
+void InputMethodMenuButton::UpdateUI(const std::string& input_method_id,
+ const std::wstring& name,
+ const std::wstring& tooltip,
+ size_t num_active_input_methods) {
// Hide the button only if there is only one input method, and the input
// method is a XKB keyboard layout. We don't hide the button for other
// types of input methods as these might have intra input method modes,
// like Hiragana and Katakana modes in Japanese input methods.
- scoped_ptr<InputMethodDescriptors> active_input_methods(
- CrosLibrary::Get()->GetInputMethodLibrary()->GetActiveInputMethods());
- if (active_input_methods->size() == 1 &&
- input_method::IsKeyboardLayout(active_input_methods->at(0).id) &&
+ if (num_active_input_methods == 1 &&
+ input_method::IsKeyboardLayout(input_method_id) &&
host_->IsBrowserMode()) {
// As the disabled color is set to invisible, disabling makes the
// button disappear.
diff --git a/chrome/browser/chromeos/status/input_method_menu_button.h b/chrome/browser/chromeos/status/input_method_menu_button.h
index d7375d3..3a232eb 100644
--- a/chrome/browser/chromeos/status/input_method_menu_button.h
+++ b/chrome/browser/chromeos/status/input_method_menu_button.h
@@ -29,8 +29,10 @@ class InputMethodMenuButton : public StatusAreaButton,
private:
// InputMethodMenu implementation.
- virtual void UpdateUI(
- const std::wstring& name, const std::wstring& tooltip);
+ virtual void UpdateUI(const std::string& input_method_id,
+ const std::wstring& name,
+ const std::wstring& tooltip,
+ size_t num_active_input_methods);
virtual bool ShouldSupportConfigUI();
virtual void OpenConfigUI();
diff --git a/chrome/browser/chromeos/status/input_method_menu_unittest.cc b/chrome/browser/chromeos/status/input_method_menu_unittest.cc
index 5ff1f11..1ad1d59 100644
--- a/chrome/browser/chromeos/status/input_method_menu_unittest.cc
+++ b/chrome/browser/chromeos/status/input_method_menu_unittest.cc
@@ -35,6 +35,10 @@ TEST(InputMethodMenuTest, GetTextForIndicatorTest) {
EXPECT_EQ(L"DV", InputMethodMenu::GetTextForIndicator(desc));
}
{
+ InputMethodDescriptor desc("xkb:us:colemak:eng", "Colemak", "us", "eng");
+ EXPECT_EQ(L"CO", InputMethodMenu::GetTextForIndicator(desc));
+ }
+ {
InputMethodDescriptor desc("xkb:us:altgr-intl:eng", "US extd", "us", "eng");
EXPECT_EQ(L"EXTD", InputMethodMenu::GetTextForIndicator(desc));
}
diff --git a/chrome/browser/chromeos/status/network_dropdown_button.cc b/chrome/browser/chromeos/status/network_dropdown_button.cc
index 32ff4e6..3b74333 100644
--- a/chrome/browser/chromeos/status/network_dropdown_button.cc
+++ b/chrome/browser/chromeos/status/network_dropdown_button.cc
@@ -75,18 +75,23 @@ void NetworkDropdownButton::OnNetworkManagerChanged(NetworkLibrary* cros) {
if (CrosLibrary::Get()->EnsureLoaded()) {
// Always show the active network, if any
const Network* active_network = cros->active_network();
- const WirelessNetwork* wireless;
if (active_network != NULL) {
animation_connecting_.Stop();
if (active_network->type() == TYPE_ETHERNET) {
SetIcon(*rb.GetBitmapNamed(IDR_STATUSBAR_WIRED));
SetText(l10n_util::GetString(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET));
+ } else if (active_network->type() == TYPE_WIFI) {
+ const WifiNetwork* wifi =
+ static_cast<const WifiNetwork*>(active_network);
+ SetIcon(IconForNetworkStrength(wifi, true));
+ SetText(ASCIIToWide(wifi->name()));
+ } else if (active_network->type() == TYPE_CELLULAR) {
+ const CellularNetwork* cellular =
+ static_cast<const CellularNetwork*>(active_network);
+ SetIcon(IconForNetworkStrength(cellular, true));
+ SetText(ASCIIToWide(cellular->name()));
} else {
- DCHECK(active_network->type() == TYPE_WIFI ||
- active_network->type() == TYPE_CELLULAR);
- wireless = static_cast<const WirelessNetwork*>(active_network);
- SetIcon(IconForNetworkStrength(wireless->strength(), true));
- SetText(ASCIIToWide(wireless->name()));
+ NOTREACHED();
}
} else if (cros->wifi_connecting() || cros->cellular_connecting()) {
if (!animation_connecting_.is_animating()) {
diff --git a/chrome/browser/chromeos/status/network_menu.cc b/chrome/browser/chromeos/status/network_menu.cc
index 9ceb893..9d206cd 100644
--- a/chrome/browser/chromeos/status/network_menu.cc
+++ b/chrome/browser/chromeos/status/network_menu.cc
@@ -45,38 +45,40 @@ namespace chromeos {
// NetworkMenu
// static
-const int NetworkMenu::kNumWifiImages = 4;
+const int NetworkMenu::kNumBarsImages = 4;
// NOTE: Use an array rather than just calculating a resource number to avoid
// creating implicit ordering dependencies on the resource values.
// static
-const int NetworkMenu::kBarsImages[kNumWifiImages] = {
+const int NetworkMenu::kBarsImages[kNumBarsImages] = {
IDR_STATUSBAR_NETWORK_BARS1,
IDR_STATUSBAR_NETWORK_BARS2,
IDR_STATUSBAR_NETWORK_BARS3,
IDR_STATUSBAR_NETWORK_BARS4,
};
// static
-const int NetworkMenu::kBarsImagesBlack[kNumWifiImages] = {
+const int NetworkMenu::kBarsImagesBlack[kNumBarsImages] = {
IDR_STATUSBAR_NETWORK_BARS1_BLACK,
IDR_STATUSBAR_NETWORK_BARS2_BLACK,
IDR_STATUSBAR_NETWORK_BARS3_BLACK,
IDR_STATUSBAR_NETWORK_BARS4_BLACK,
};
+/*
// static
-const int NetworkMenu::kBarsImagesLowData[kNumWifiImages] = {
+const int NetworkMenu::kBarsImagesLowData[kNumBarsImages] = {
IDR_STATUSBAR_NETWORK_BARS1_ORANGE,
IDR_STATUSBAR_NETWORK_BARS2_ORANGE,
IDR_STATUSBAR_NETWORK_BARS3_ORANGE,
IDR_STATUSBAR_NETWORK_BARS4_ORANGE,
};
// static
-const int NetworkMenu::kBarsImagesVLowData[kNumWifiImages] = {
+const int NetworkMenu::kBarsImagesVLowData[kNumBarsImages] = {
IDR_STATUSBAR_NETWORK_BARS1_RED,
IDR_STATUSBAR_NETWORK_BARS2_RED,
IDR_STATUSBAR_NETWORK_BARS3_RED,
IDR_STATUSBAR_NETWORK_BARS4_RED,
};
+*/
NetworkMenu::NetworkMenu()
: min_width_(-1) {
@@ -130,22 +132,10 @@ bool NetworkMenu::GetNetworkAt(int index, NetworkInfo* info) const {
info->message = l10n_util::GetStringUTF8(
IDS_STATUSBAR_NETWORK_DEVICE_DISCONNECTED);
}
- if (wifi->encrypted()) {
- info->need_passphrase = true;
- if (wifi->IsCertificateLoaded() ||
- wifi->encryption() == SECURITY_8021X) {
- info->need_passphrase = false;
- }
- if (wifi->favorite()) {
- info->passphrase = wifi->passphrase();
- info->need_passphrase = false;
- }
- } else {
- info->need_passphrase = false;
- }
+ info->need_passphrase = wifi->IsPassphraseRequired();
info->ip_address = wifi->ip_address();
info->remembered = wifi->favorite();
- info->auto_connect = info->remembered ? wifi->auto_connect() : true;
+ info->auto_connect = wifi->auto_connect();
} else {
res = false; // Network not found, hide entry.
}
@@ -211,38 +201,24 @@ bool NetworkMenu::ConnectToNetworkAt(int index,
// Connect or reconnect.
if (auto_connect >= 0)
wifi->set_auto_connect(auto_connect ? true : false);
- if (wifi->connecting() || wifi->connected()) {
+ if (wifi->connecting_or_connected()) {
// Show the config settings for the active network.
- ShowWifi(wifi, false);
+ ShowTabbedNetworkSettings(wifi);
return true;
}
bool connected = false;
- if (wifi->encrypted()) {
- if (wifi->IsCertificateLoaded()) {
- connected = cros->ConnectToWifiNetwork(
- wifi, std::string(), std::string(), wifi->cert_path());
- } else if (wifi->encryption() == SECURITY_8021X) {
- // Always show the wifi settings/dialog to load/select a certificate.
- ShowWifi(wifi, true);
- return true;
- } else {
- // If a passphrase is provided use it, otherwise use the saved one.
- std::string pass =
- !passphrase.empty() ? passphrase : wifi->passphrase();
- if (MenuUI::IsEnabled() ||
- (!pass.empty() && !wifi->passphrase_required())) {
- connected = cros->ConnectToWifiNetwork(
- wifi, pass, std::string(), std::string());
- }
- }
+ if (wifi->IsPassphraseRequired()) {
+ // Show the connection UI if we require a passphrase.
+ ShowNetworkConfigView(new NetworkConfigView(wifi));
+ return true;
} else {
connected = cros->ConnectToWifiNetwork(
- wifi, std::string(), std::string(), std::string());
+ wifi, passphrase, std::string(), std::string());
}
if (!connected) {
if (!MenuUI::IsEnabled()) {
// Show the wifi dialog on a failed attempt for non DOM UI menus.
- ShowWifi(wifi, true);
+ ShowNetworkConfigView(new NetworkConfigView(wifi));
return true;
} else {
// If the connection attempt failed immediately (e.g. short password)
@@ -259,14 +235,15 @@ bool NetworkMenu::ConnectToNetworkAt(int index,
CellularNetwork* cellular = cros->FindCellularNetworkByPath(
menu_items_[index].wireless_path);
if (cellular) {
- if (cellular->activation_state() != ACTIVATION_STATE_ACTIVATED ||
+ if ((cellular->activation_state() != ACTIVATION_STATE_ACTIVATED &&
+ cellular->activation_state() != ACTIVATION_STATE_UNKNOWN) ||
cellular->needs_new_plan()) {
ActivateCellular(cellular);
return true;
- } else if (cellular->connecting() || cellular->connected()) {
+ } else if (cellular->connecting_or_connected()) {
// Cellular network is connecting or connected,
// so we show the config settings for the cellular network.
- ShowCellular(cellular, false);
+ ShowTabbedNetworkSettings(cellular);
return true;
}
// Clicked on a disconnected cellular network, so connect to it.
@@ -349,7 +326,7 @@ void NetworkMenu::ActivatedAt(int index) {
cros->EnableOfflineMode(!cros->offline_mode());
} else if (flags & FLAG_ETHERNET) {
if (cros->ethernet_connected()) {
- ShowEthernet(cros->ethernet_network());
+ ShowTabbedNetworkSettings(cros->ethernet_network());
}
} else if (flags & FLAG_WIFI) {
ConnectToNetworkAt(index, std::string(), std::string(), -1);
@@ -378,33 +355,32 @@ void NetworkMenu::UpdateMenu() {
}
// static
-SkBitmap NetworkMenu::IconForNetworkStrength(int strength, bool black) {
+SkBitmap NetworkMenu::IconForNetworkStrength(const WifiNetwork* wifi,
+ bool black) {
+ DCHECK(wifi);
// Compose wifi icon by superimposing various icons.
- int index = static_cast<int>(strength / 100.0 *
- nextafter(static_cast<float>(kNumWifiImages), 0));
- index = std::max(std::min(index, kNumWifiImages - 1), 0);
+ int index = static_cast<int>(wifi->strength() / 100.0 *
+ nextafter(static_cast<float>(kNumBarsImages), 0));
+ index = std::max(std::min(index, kNumBarsImages - 1), 0);
const int* images = black ? kBarsImagesBlack : kBarsImages;
return *ResourceBundle::GetSharedInstance().GetBitmapNamed(images[index]);
}
// static
-SkBitmap NetworkMenu::IconForNetworkStrength(const CellularNetwork* cellular) {
+SkBitmap NetworkMenu::IconForNetworkStrength(const CellularNetwork* cellular,
+ bool black) {
DCHECK(cellular);
+ // If no data, then we show 0 bars.
+ if (cellular->GetDataLeft() == CellularNetwork::DATA_NONE) {
+ return *ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ black ? IDR_STATUSBAR_NETWORK_BARS0_BLACK :
+ IDR_STATUSBAR_NETWORK_BARS0);
+ }
// Compose cellular icon by superimposing various icons.
int index = static_cast<int>(cellular->strength() / 100.0 *
- nextafter(static_cast<float>(kNumWifiImages), 0));
- index = std::max(std::min(index, kNumWifiImages - 1), 0);
- const int* images = kBarsImages;
- switch (cellular->GetDataLeft()) {
- case CellularNetwork::DATA_NONE:
- images = kBarsImagesVLowData;
- break;
- case CellularNetwork::DATA_VERY_LOW:
- case CellularNetwork::DATA_LOW:
- case CellularNetwork::DATA_NORMAL:
- images = kBarsImages;
- break;
- }
+ nextafter(static_cast<float>(kNumBarsImages), 0));
+ index = std::max(std::min(index, kNumBarsImages - 1), 0);
+ const int* images = black ? kBarsImagesBlack : kBarsImages;
return *ResourceBundle::GetSharedInstance().GetBitmapNamed(images[index]);
}
@@ -560,8 +536,7 @@ void NetworkMenu::InitMenuItems() {
}
}
- SkBitmap icon = IconForNetworkStrength(wifi_networks[i]->strength(),
- true);
+ SkBitmap icon = IconForNetworkStrength(wifi_networks[i], true);
SkBitmap badge = wifi_networks[i]->encrypted() ?
*rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_SECURE) : SkBitmap();
int flag = FLAG_WIFI;
@@ -621,8 +596,7 @@ void NetworkMenu::InitMenuItems() {
}
}
- SkBitmap icon = IconForNetworkStrength(cell_networks[i]->strength(),
- true);
+ SkBitmap icon = IconForNetworkStrength(cell_networks[i], true);
SkBitmap badge = BadgeForNetworkTechnology(cell_networks[i]);
int flag = FLAG_CELLULAR;
if (!cell_networks[i]->connectable())
@@ -751,36 +725,12 @@ void NetworkMenu::ShowTabbedNetworkSettings(const Network* network) const {
// and the embedded menu UI (and fully deprecated NetworkConfigView).
// Meanwhile, if MenuUI::IsEnabled() is true, always show the settings UI,
// otherwise show NetworkConfigView only to get passwords when not connected.
-void NetworkMenu::ShowNetworkConfigView(NetworkConfigView* view,
- bool focus_login) const {
+void NetworkMenu::ShowNetworkConfigView(NetworkConfigView* view) const {
view->set_browser_mode(IsBrowserMode());
views::Window* window = browser::CreateViewsWindow(
GetNativeWindow(), gfx::Rect(), view);
window->SetIsAlwaysOnTop(true);
window->Show();
- if (focus_login)
- view->SetLoginTextfieldFocus();
-}
-
-void NetworkMenu::ShowWifi(const WifiNetwork* wifi, bool focus_login) const {
- DCHECK(wifi);
- if (use_settings_ui_ &&
- (MenuUI::IsEnabled() || wifi->connected() || wifi->connecting())) {
- ShowTabbedNetworkSettings(wifi);
- } else {
- ShowNetworkConfigView(new NetworkConfigView(wifi, true), focus_login);
- }
-}
-
-void NetworkMenu::ShowCellular(const CellularNetwork* cellular,
- bool focus_login) const {
- DCHECK(cellular);
- // We should always use settings UI for cellular network because native UI
- // is not complete and only settings UI version has full implementation.
- if (use_settings_ui_)
- ShowTabbedNetworkSettings(cellular);
- else
- ShowNetworkConfigView(new NetworkConfigView(cellular), focus_login);
}
void NetworkMenu::ActivateCellular(const CellularNetwork* cellular) const {
@@ -791,17 +741,6 @@ void NetworkMenu::ActivateCellular(const CellularNetwork* cellular) const {
browser->OpenMobilePlanTabAndActivate();
}
-void NetworkMenu::ShowEthernet(const EthernetNetwork* ethernet) const {
- DCHECK(ethernet);
- if (use_settings_ui_ &&
- (MenuUI::IsEnabled() || ethernet->connected() ||
- ethernet->connecting())) {
- ShowTabbedNetworkSettings(ethernet);
- } else {
- ShowNetworkConfigView(new NetworkConfigView(ethernet), false);
- }
-}
-
void NetworkMenu::ShowOther() const {
if (use_settings_ui_ && MenuUI::IsEnabled()) {
Browser* browser = BrowserList::GetLastActive();
@@ -812,8 +751,7 @@ void NetworkMenu::ShowOther() const {
browser->ShowOptionsTab(page);
}
} else {
- const bool kFocusLogin = true;
- ShowNetworkConfigView(new NetworkConfigView(), kFocusLogin);
+ ShowNetworkConfigView(new NetworkConfigView());
}
}
diff --git a/chrome/browser/chromeos/status/network_menu.h b/chrome/browser/chromeos/status/network_menu.h
index 05b941e..4e72ad2 100644
--- a/chrome/browser/chromeos/status/network_menu.h
+++ b/chrome/browser/chromeos/status/network_menu.h
@@ -93,7 +93,7 @@ class NetworkMenu : public views::ViewMenuDelegate,
virtual menus::MenuModel::ItemType GetTypeAt(int index) const;
virtual int GetCommandIdAt(int index) const { return index; }
virtual string16 GetLabelAt(int index) const;
- virtual bool IsLabelDynamicAt(int index) const { return true; }
+ virtual bool IsItemDynamicAt(int index) const { return true; }
virtual const gfx::Font* GetLabelFontAt(int index) const;
virtual bool GetAcceleratorAt(int index,
menus::Accelerator* accelerator) const { return false; }
@@ -114,13 +114,15 @@ class NetworkMenu : public views::ViewMenuDelegate,
// Cancels the active menu.
void CancelMenu();
- // Returns the Icon for a network strength between 0 and 100.
+ // Returns the Icon for a network strength for a WifiNetwork |wifi|.
// |black| is used to specify whether to return a black icon for display
// on a light background or a white icon for display on a dark background.
- static SkBitmap IconForNetworkStrength(int strength, bool black);
+ static SkBitmap IconForNetworkStrength(const WifiNetwork* wifi, bool black);
// Returns the Icon for a network strength for CellularNetwork |cellular|.
- // This returns different colored bars depending on cellular data left.
- static SkBitmap IconForNetworkStrength(const CellularNetwork* cellular);
+ // |black| is used to specify whether to return a black icon for display
+ // on a light background or a white icon for display on a dark background.
+ static SkBitmap IconForNetworkStrength(const CellularNetwork* cellular,
+ bool black);
// Returns the Icon for animating network connecting.
// |animation_value| is the value from Animation.GetCurrentValue()
// |black| is used to specify whether to return a black icon for display
@@ -191,26 +193,23 @@ class NetworkMenu : public views::ViewMenuDelegate,
// Show a NetworkConfigView modal dialog instance.
// TODO(stevenjb): deprecate this once all of the UI is embedded in the menu.
- void ShowNetworkConfigView(NetworkConfigView* view, bool focus_login) const;
+ void ShowNetworkConfigView(NetworkConfigView* view) const;
- // Wrappers for the ShowNetworkConfigView / ShowTabbedNetworkSettings.
- void ShowWifi(const WifiNetwork* wifi, bool focus_login) const;
- void ShowCellular(const CellularNetwork* cellular, bool focus_login) const;
void ActivateCellular(const CellularNetwork* cellular) const;
- void ShowEthernet(const EthernetNetwork* ethernet) const;
void ShowOther() const;
// Set to true if we are currently refreshing the menu.
bool refreshing_menu_;
- // The number of wifi strength images.
- static const int kNumWifiImages;
+ // The number of bars images for representing network strength.
+ static const int kNumBarsImages;
// Bars image resources.
static const int kBarsImages[];
static const int kBarsImagesBlack[];
- static const int kBarsImagesLowData[];
- static const int kBarsImagesVLowData[];
+ // TODO(chocobo): Add these back when we decide to do colored bars again.
+// static const int kBarsImagesLowData[];
+// static const int kBarsImagesVLowData[];
// Our menu items.
MenuItemVector menu_items_;
diff --git a/chrome/browser/chromeos/status/network_menu_button.cc b/chrome/browser/chromeos/status/network_menu_button.cc
index cc0c604..2beb02a 100644
--- a/chrome/browser/chromeos/status/network_menu_button.cc
+++ b/chrome/browser/chromeos/status/network_menu_button.cc
@@ -79,6 +79,8 @@ void NetworkMenuButton::OnNetworkManagerChanged(NetworkLibrary* cros) {
// NetworkMenuButton, NetworkLibrary::NetworkObserver implementation:
void NetworkMenuButton::OnNetworkChanged(NetworkLibrary* cros,
const Network* network) {
+ // This gets called on initialization, so any changes should be reflected
+ // in CrosMock::SetNetworkLibraryStatusAreaExpectations().
SetNetworkIcon(cros, network);
RefreshNetworkObserver(cros);
SchedulePaint();
@@ -167,7 +169,7 @@ void NetworkMenuButton::SetNetworkIcon(NetworkLibrary* cros,
l10n_util::GetString(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET)));
} else if (network->type() == TYPE_WIFI) {
const WifiNetwork* wifi = static_cast<const WifiNetwork*>(network);
- SetIcon(IconForNetworkStrength(wifi->strength(), false));
+ SetIcon(IconForNetworkStrength(wifi, false));
SetBadge(SkBitmap());
SetTooltipText(l10n_util::GetStringF(
IDS_STATUSBAR_NETWORK_CONNECTED_TOOLTIP,
@@ -175,12 +177,7 @@ void NetworkMenuButton::SetNetworkIcon(NetworkLibrary* cros,
} else if (network->type() == TYPE_CELLULAR) {
const CellularNetwork* cellular =
static_cast<const CellularNetwork*>(network);
- if (cellular->GetDataLeft() == CellularNetwork::DATA_NONE) {
- // If no data, then we show 0 bars.
- SetIcon(*rb.GetBitmapNamed(IDR_STATUSBAR_NETWORK_BARS0));
- } else {
- SetIcon(IconForNetworkStrength(cellular));
- }
+ SetIcon(IconForNetworkStrength(cellular, false));
SetBadge(BadgeForNetworkTechnology(cellular));
SetTooltipText(l10n_util::GetStringF(
IDS_STATUSBAR_NETWORK_CONNECTED_TOOLTIP,
diff --git a/chrome/browser/chromeos/status/power_menu_button.h b/chrome/browser/chromeos/status/power_menu_button.h
index b3503e8..d3146ac 100644
--- a/chrome/browser/chromeos/status/power_menu_button.h
+++ b/chrome/browser/chromeos/status/power_menu_button.h
@@ -36,7 +36,7 @@ class PowerMenuButton : public StatusAreaButton,
virtual menus::MenuModel::ItemType GetTypeAt(int index) const;
virtual int GetCommandIdAt(int index) const { return index; }
virtual string16 GetLabelAt(int index) const;
- virtual bool IsLabelDynamicAt(int index) const { return true; }
+ virtual bool IsItemDynamicAt(int index) const { return true; }
virtual bool GetAcceleratorAt(int index,
menus::Accelerator* accelerator) const { return false; }
virtual bool IsItemCheckedAt(int index) const { return false; }
diff --git a/chrome/browser/chromeos/system_key_event_listener.cc b/chrome/browser/chromeos/system_key_event_listener.cc
index 74af308..2df12dd 100644
--- a/chrome/browser/chromeos/system_key_event_listener.cc
+++ b/chrome/browser/chromeos/system_key_event_listener.cc
@@ -8,8 +8,9 @@
#include <X11/XF86keysym.h>
#include "chrome/browser/chromeos/audio_handler.h"
+#include "chrome/browser/chromeos/brightness_bubble.h"
#include "chrome/browser/chromeos/volume_bubble.h"
-#include "cros/chromeos_wm_ipc_enums.h"
+#include "third_party/cros/chromeos_wm_ipc_enums.h"
namespace chromeos {
@@ -20,13 +21,13 @@ const double kStepPercentage = 4.0;
} // namespace
// static
-SystemKeyEventListener* SystemKeyEventListener::instance() {
+SystemKeyEventListener* SystemKeyEventListener::GetInstance() {
return Singleton<SystemKeyEventListener>::get();
}
SystemKeyEventListener::SystemKeyEventListener()
- : audio_handler_(AudioHandler::instance()) {
- WmMessageListener::instance()->AddObserver(this);
+ : audio_handler_(AudioHandler::GetInstance()) {
+ WmMessageListener::GetInstance()->AddObserver(this);
key_volume_mute_ = XKeysymToKeycode(GDK_DISPLAY(), XF86XK_AudioMute);
key_volume_down_ = XKeysymToKeycode(GDK_DISPLAY(), XF86XK_AudioLowerVolume);
@@ -48,7 +49,7 @@ SystemKeyEventListener::SystemKeyEventListener()
}
SystemKeyEventListener::~SystemKeyEventListener() {
- WmMessageListener::instance()->RemoveObserver(this);
+ WmMessageListener::GetInstance()->RemoveObserver(this);
gdk_window_remove_filter(NULL, GdkEventFilter, this);
}
@@ -118,29 +119,31 @@ void SystemKeyEventListener::GrabKey(int32 key, uint32 mask) {
True, GrabModeAsync, GrabModeAsync);
}
-// TODO(davej): Move the ShowVolumeBubble() calls in to AudioHandler so that
-// this function returns faster without blocking on GetVolumePercent(), and
-// still guarantees that the volume displayed will be that after the adjustment.
+// TODO(davej): Move the ShowBubble() calls in to AudioHandler so that this
+// function returns faster without blocking on GetVolumePercent(), and still
+// guarantees that the volume displayed will be that after the adjustment.
-// TODO(davej): The IsMute() check can also be made non-blocking by changing
-// to an AdjustVolumeByPercentOrUnmute() function which can do the steps off
-// of this thread when ShowVolumeBubble() is moved in to AudioHandler.
+// TODO(davej): The IsMute() check can also be made non-blocking by changing to
+// an AdjustVolumeByPercentOrUnmute() function which can do the steps off of
+// this thread when ShowBubble() is moved in to AudioHandler.
void SystemKeyEventListener::OnVolumeMute() {
// Always muting (and not toggling) as per final decision on
// http://crosbug.com/3751
audio_handler_->SetMute(true);
- VolumeBubble::instance()->ShowVolumeBubble(0);
+ VolumeBubble::GetInstance()->ShowBubble(0);
+ BrightnessBubble::GetInstance()->HideBubble();
}
void SystemKeyEventListener::OnVolumeDown() {
if (audio_handler_->IsMute()) {
- VolumeBubble::instance()->ShowVolumeBubble(0);
+ VolumeBubble::GetInstance()->ShowBubble(0);
} else {
audio_handler_->AdjustVolumeByPercent(-kStepPercentage);
- VolumeBubble::instance()->ShowVolumeBubble(
+ VolumeBubble::GetInstance()->ShowBubble(
audio_handler_->GetVolumePercent());
}
+ BrightnessBubble::GetInstance()->HideBubble();
}
void SystemKeyEventListener::OnVolumeUp() {
@@ -148,8 +151,9 @@ void SystemKeyEventListener::OnVolumeUp() {
audio_handler_->SetMute(false);
else
audio_handler_->AdjustVolumeByPercent(kStepPercentage);
- VolumeBubble::instance()->ShowVolumeBubble(
+ VolumeBubble::GetInstance()->ShowBubble(
audio_handler_->GetVolumePercent());
+ BrightnessBubble::GetInstance()->HideBubble();
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/system_key_event_listener.h b/chrome/browser/chromeos/system_key_event_listener.h
index 61a20ca..eb841f9 100644
--- a/chrome/browser/chromeos/system_key_event_listener.h
+++ b/chrome/browser/chromeos/system_key_event_listener.h
@@ -24,7 +24,7 @@ class AudioHandler;
class SystemKeyEventListener : public WmMessageListener::Observer {
public:
- static SystemKeyEventListener* instance();
+ static SystemKeyEventListener* GetInstance();
// WmMessageListener::Observer:
virtual void ProcessWmMessage(const WmIpc::Message& message,
diff --git a/chrome/browser/chromeos/tab_closeable_state_watcher.cc b/chrome/browser/chromeos/tab_closeable_state_watcher.cc
index 4972079..1c638b7 100644
--- a/chrome/browser/chromeos/tab_closeable_state_watcher.cc
+++ b/chrome/browser/chromeos/tab_closeable_state_watcher.cc
@@ -6,12 +6,11 @@
#include "base/command_line.h"
#include "chrome/browser/browser_shutdown.h"
-#include "chrome/browser/defaults.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
diff --git a/chrome/browser/chromeos/tab_closeable_state_watcher_browsertest.cc b/chrome/browser/chromeos/tab_closeable_state_watcher_browsertest.cc
index 6e23c0f..4fb4552 100644
--- a/chrome/browser/chromeos/tab_closeable_state_watcher_browsertest.cc
+++ b/chrome/browser/chromeos/tab_closeable_state_watcher_browsertest.cc
@@ -5,13 +5,13 @@
#include "chrome/browser/chromeos/tab_closeable_state_watcher.h"
#include "base/file_path.h"
-#include "chrome/browser/app_modal_dialog.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
-#include "chrome/browser/native_app_modal_dialog.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
+#include "chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/in_process_browser_test.h"
diff --git a/chrome/browser/chromeos/update_browsertest.cc b/chrome/browser/chromeos/update_browsertest.cc
index 2c0798d..1129e12 100644
--- a/chrome/browser/chromeos/update_browsertest.cc
+++ b/chrome/browser/chromeos/update_browsertest.cc
@@ -7,7 +7,6 @@
#include "chrome/browser/browser_list.h"
#include "chrome/browser/chromeos/cros/mock_update_library.h"
#include "chrome/browser/chromeos/update_observer.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/automation/dom_element_proxy.h"
@@ -118,4 +117,3 @@ IN_PROC_BROWSER_TEST_F(UpdateBrowserTest, Notifications) {
}
} // namespace
-
diff --git a/chrome/browser/chromeos/usb_mount_observer.cc b/chrome/browser/chromeos/usb_mount_observer.cc
index 734f8c6..6f056e8 100644
--- a/chrome/browser/chromeos/usb_mount_observer.cc
+++ b/chrome/browser/chromeos/usb_mount_observer.cc
@@ -5,8 +5,9 @@
#include "chrome/browser/chromeos/usb_mount_observer.h"
#include "base/command_line.h"
+#include "base/singleton.h"
#include "chrome/browser/dom_ui/filebrowse_ui.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
@@ -23,6 +24,11 @@ const int kPopupTop = 0;
const int kPopupWidth = 250;
const int kPopupHeight = 300;
+// static
+USBMountObserver* USBMountObserver::GetInstance() {
+ return Singleton<USBMountObserver>::get();
+}
+
void USBMountObserver::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
diff --git a/chrome/browser/chromeos/usb_mount_observer.h b/chrome/browser/chromeos/usb_mount_observer.h
index 5f30b31..0857197 100644
--- a/chrome/browser/chromeos/usb_mount_observer.h
+++ b/chrome/browser/chromeos/usb_mount_observer.h
@@ -16,6 +16,7 @@
#include "chrome/common/notification_type.h"
class Browser;
+template <typename T> struct DefaultSingletonTraits;
class Profile;
namespace chromeos { // NOLINT
@@ -31,12 +32,8 @@ class USBMountObserver : public chromeos::MountLibrary::Observer,
std::string mount_path;
};
- USBMountObserver() {}
- ~USBMountObserver() {}
+ static USBMountObserver* GetInstance();
- static USBMountObserver* Get() {
- return Singleton<USBMountObserver>::get();
- }
void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details);
@@ -48,9 +45,13 @@ class USBMountObserver : public chromeos::MountLibrary::Observer,
void ScanForDevices(chromeos::MountLibrary* obj);
private:
+ friend struct DefaultSingletonTraits<USBMountObserver>;
typedef std::vector<BrowserWithPath>::iterator BrowserIterator;
BrowserIterator FindBrowserForPath(const std::string& path);
+ USBMountObserver() {}
+ ~USBMountObserver() {}
+
void RemoveBrowserFromVector(const std::string& path);
// Used to create a window of a standard size, and add it to a list
diff --git a/chrome/browser/chromeos/usb_mount_observer_browsertest.cc b/chrome/browser/chromeos/usb_mount_observer_browsertest.cc
index 6c8d12e..c70fbeb 100644
--- a/chrome/browser/chromeos/usb_mount_observer_browsertest.cc
+++ b/chrome/browser/chromeos/usb_mount_observer_browsertest.cc
@@ -42,7 +42,7 @@ IN_PROC_BROWSER_TEST_F(USBMountObserverBrowserTest, PopupOnEvent) {
// Doing this so we have a valid profile
ui_test_utils::NavigateToURL(browser(),
GURL(chrome::kChromeUIDownloadsURL));
- chromeos::USBMountObserver* observe = chromeos::USBMountObserver::Get();
+ chromeos::USBMountObserver* observe = chromeos::USBMountObserver::GetInstance();
observe->set_profile(browser()->profile());
scoped_ptr<chromeos::MockMountLibrary> lib(new chromeos::MockMountLibrary());
lib->AddObserver(observe);
diff --git a/chrome/browser/chromeos/user_cros_settings_provider.cc b/chrome/browser/chromeos/user_cros_settings_provider.cc
index 1cdfd3a..4ee00f1 100644
--- a/chrome/browser/chromeos/user_cros_settings_provider.cc
+++ b/chrome/browser/chromeos/user_cros_settings_provider.cc
@@ -4,21 +4,87 @@
#include "chrome/browser/chromeos/user_cros_settings_provider.h"
+#include <map>
+#include <set>
+
+#include "base/hash_tables.h"
#include "base/logging.h"
+#include "base/singleton.h"
#include "base/string_util.h"
+#include "base/task.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_thread.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/login_library.h"
#include "chrome/browser/chromeos/cros_settings.h"
#include "chrome/browser/chromeos/cros_settings_names.h"
+#include "chrome/browser/chromeos/login/ownership_service.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
namespace chromeos {
namespace {
+const char kTrueIncantation[] = "true";
+const char kFalseIncantation[] = "false";
+const char kTrustedSuffix[] = "/trusted";
+
+// For all our boolean settings following is applicable:
+// true is default permissive value and false is safe prohibitic value.
+const char* kBooleanSettings[] = {
+ kAccountsPrefAllowNewUser,
+ kAccountsPrefAllowGuest,
+ kAccountsPrefShowUserNamesOnSignIn
+};
+
+const char* kStringSettings[] = {
+ kDeviceOwner
+};
+
+const char* kListSettings[] = {
+ kAccountsPrefUsers
+};
+
+bool IsControlledBooleanSetting(const std::string& pref_path) {
+ return std::find(kBooleanSettings,
+ kBooleanSettings + arraysize(kBooleanSettings),
+ pref_path) !=
+ kBooleanSettings + arraysize(kBooleanSettings);
+}
+
+bool IsControlledStringSetting(const std::string& pref_path) {
+ return std::find(kStringSettings,
+ kStringSettings + arraysize(kStringSettings),
+ pref_path) !=
+ kStringSettings + arraysize(kStringSettings);
+}
+
+bool IsControlledListSetting(const std::string& pref_path) {
+ return std::find(kListSettings,
+ kListSettings + arraysize(kListSettings),
+ pref_path) !=
+ kListSettings + arraysize(kListSettings);
+}
+
+void RegisterSetting(PrefService* local_state, const std::string& pref_path) {
+ local_state->RegisterBooleanPref((pref_path + kTrustedSuffix).c_str(),
+ false);
+ if (IsControlledBooleanSetting(pref_path)) {
+ local_state->RegisterBooleanPref(pref_path.c_str(), true);
+ } else if (IsControlledStringSetting(pref_path)) {
+ local_state->RegisterStringPref(pref_path.c_str(), "");
+ } else {
+ DCHECK(IsControlledListSetting(pref_path));
+ local_state->RegisterListPref(pref_path.c_str());
+ }
+}
+
Value* CreateSettingsBooleanValue(bool value, bool managed) {
DictionaryValue* dict = new DictionaryValue;
dict->Set("value", Value::CreateBooleanValue(value));
@@ -26,16 +92,30 @@ Value* CreateSettingsBooleanValue(bool value, bool managed) {
return dict;
}
-// static
-void UpdateCacheBool(const char* name, bool value) {
+enum UseValue {
+ USE_VALUE_SUPPLIED,
+ USE_VALUE_DEFAULT
+};
+
+void UpdateCacheBool(const std::string& name,
+ bool value,
+ UseValue use_value) {
PrefService* prefs = g_browser_process->local_state();
- prefs->SetBoolean(name, value);
+ if (use_value == USE_VALUE_DEFAULT)
+ prefs->ClearPref(name.c_str());
+ else
+ prefs->SetBoolean(name.c_str(), value);
prefs->ScheduleSavePersistentPrefs();
}
-void UpdateCacheString(const char* name, const std::string& value) {
+void UpdateCacheString(const std::string& name,
+ const std::string& value,
+ UseValue use_value) {
PrefService* prefs = g_browser_process->local_state();
- prefs->SetString(name, value);
+ if (use_value == USE_VALUE_DEFAULT)
+ prefs->ClearPref(name.c_str());
+ else
+ prefs->SetString(name.c_str(), value);
prefs->ScheduleSavePersistentPrefs();
}
@@ -74,43 +154,336 @@ bool GetUserWhitelist(ListValue* user_list) {
return true;
}
+class UserCrosSettingsTrust : public SignedSettingsHelper::Callback,
+ public NotificationObserver {
+ public:
+ static UserCrosSettingsTrust* GetInstance() {
+ return Singleton<UserCrosSettingsTrust>::get();
+ }
+
+ // Working horse for UserCrosSettingsProvider::RequestTrusted* family.
+ bool RequestTrustedEntity(const std::string& name, Task* callback) {
+ if (GetOwnershipStatus() == OWNERSHIP_NONE)
+ return true;
+ if (GetOwnershipStatus() == OWNERSHIP_TAKEN) {
+ DCHECK(g_browser_process);
+ PrefService* prefs = g_browser_process->local_state();
+ DCHECK(prefs);
+ if (prefs->GetBoolean((name + kTrustedSuffix).c_str()))
+ return true;
+ }
+ if (callback)
+ callbacks_[name].push_back(callback);
+ return false;
+ }
+
+ void Set(const std::string& path, Value* in_value) {
+ if (!UserManager::Get()->current_user_is_owner()) {
+ LOG(WARNING) << "Changing settings from non-owner, setting=" << path;
+
+ // Revert UI change.
+ CrosSettings::Get()->FireObservers(path.c_str());
+ return;
+ }
+
+ if (IsControlledBooleanSetting(path)) {
+ bool bool_value = false;
+ if (in_value->GetAsBoolean(&bool_value)) {
+ std::string value = bool_value ? kTrueIncantation : kFalseIncantation;
+ SignedSettingsHelper::Get()->StartStorePropertyOp(path, value, this);
+ UpdateCacheBool(path, bool_value, USE_VALUE_SUPPLIED);
+
+ VLOG(1) << "Set cros setting " << path << "=" << value;
+ }
+ } else if (path == kDeviceOwner) {
+ VLOG(1) << "Setting owner is not supported. Please use "
+ "'UpdateCachedOwner' instead.";
+ } else if (path == kAccountsPrefUsers) {
+ VLOG(1) << "Setting user whitelist is not implemented. Please use "
+ "whitelist/unwhitelist instead.";
+ } else {
+ LOG(WARNING) << "Try to set unhandled cros setting " << path;
+ }
+ }
+
+ private:
+ // Listed in upgrade order.
+ enum OwnershipStatus {
+ OWNERSHIP_UNKNOWN = 0,
+ OWNERSHIP_NONE,
+ OWNERSHIP_TAKEN
+ };
+
+ // Used to discriminate different sources of ownership status info.
+ enum OwnershipSource {
+ SOURCE_FETCH, // Info comes from FetchOwnershipStatus method.
+ SOURCE_OBSERVE // Info comes from Observe method.
+ };
+
+ // upper bound for number of retries to fetch a signed setting.
+ static const int kNumRetriesLimit = 9;
+
+ UserCrosSettingsTrust() : ownership_status_(OWNERSHIP_UNKNOWN),
+ retries_left_(kNumRetriesLimit) {
+ notification_registrar_.Add(this,
+ NotificationType::OWNERSHIP_TAKEN,
+ NotificationService::AllSources());
+ // Start getting ownership status.
+ BrowserThread::PostTask(
+ BrowserThread::FILE,
+ FROM_HERE,
+ NewRunnableMethod(this, &UserCrosSettingsTrust::FetchOwnershipStatus));
+ }
+
+ ~UserCrosSettingsTrust() {
+ if (BrowserThread::CurrentlyOn(BrowserThread::UI) &&
+ CrosLibrary::Get()->EnsureLoaded()) {
+ // Cancels all pending callbacks from us.
+ SignedSettingsHelper::Get()->CancelCallback(this);
+ }
+ }
+
+ void FetchOwnershipStatus() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ OwnershipStatus status =
+ OwnershipService::GetSharedInstance()->IsAlreadyOwned() ?
+ OWNERSHIP_TAKEN : OWNERSHIP_NONE;
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(this, &UserCrosSettingsTrust::SetOwnershipStatus,
+ status, SOURCE_FETCH));
+ }
+
+ void SetOwnershipStatus(OwnershipStatus new_status,
+ OwnershipSource source) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(new_status == OWNERSHIP_TAKEN || new_status == OWNERSHIP_NONE);
+ if (source == SOURCE_FETCH) {
+ DCHECK(ownership_status_ != OWNERSHIP_NONE);
+ if (ownership_status_ == OWNERSHIP_TAKEN) {
+ // OWNERSHIP_TAKEN notification was observed earlier.
+ return;
+ }
+ }
+ ownership_status_ = new_status;
+ if (source == SOURCE_FETCH) {
+ // Start prefetching Boolean and String preferences.
+ for (size_t i = 0; i < arraysize(kBooleanSettings); ++i)
+ StartFetchingSetting(kBooleanSettings[i]);
+ for (size_t i = 0; i < arraysize(kStringSettings); ++i)
+ StartFetchingSetting(kStringSettings[i]);
+ }
+ }
+
+ // Returns ownership status.
+ // Called on UI thread unlike OwnershipService::IsAlreadyOwned.
+ OwnershipStatus GetOwnershipStatus() {
+ return ownership_status_;
+ }
+
+ void StartFetchingSetting(const std::string& name) {
+ DCHECK(g_browser_process);
+ PrefService* prefs = g_browser_process->local_state();
+ if (!prefs)
+ return;
+ // Do not trust before fetching complete.
+ prefs->ClearPref((name + kTrustedSuffix).c_str());
+ prefs->ScheduleSavePersistentPrefs();
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ SignedSettingsHelper::Get()->StartRetrieveProperty(name, this);
+ }
+ }
+
+ // Implementation of SignedSettingsHelper::Callback.
+ virtual void OnRetrievePropertyCompleted(SignedSettings::ReturnCode code,
+ const std::string& name,
+ const std::string& value) {
+ if (!IsControlledBooleanSetting(name) && !IsControlledStringSetting(name)) {
+ NOTREACHED();
+ return;
+ }
+ DCHECK(GetOwnershipStatus() != OWNERSHIP_UNKNOWN);
+
+ PrefService* prefs = g_browser_process->local_state();
+ switch (code) {
+ case SignedSettings::SUCCESS:
+ case SignedSettings::NOT_FOUND:
+ case SignedSettings::KEY_UNAVAILABLE: {
+ bool fallback_to_default = (code == SignedSettings::NOT_FOUND) ||
+ (GetOwnershipStatus() == OWNERSHIP_NONE);
+ DCHECK(fallback_to_default || code == SignedSettings::SUCCESS);
+ if (fallback_to_default)
+ VLOG(1) << "Going default for cros setting " << name;
+ else
+ VLOG(1) << "Retrieved cros setting " << name << "=" << value;
+ if (IsControlledBooleanSetting(name)) {
+ // We assume our boolean settings are true before explicitly set.
+ UpdateCacheBool(name, (value == kTrueIncantation),
+ fallback_to_default ? USE_VALUE_DEFAULT : USE_VALUE_SUPPLIED);
+ } else if (IsControlledStringSetting(name)) {
+ UpdateCacheString(name, value,
+ fallback_to_default ? USE_VALUE_DEFAULT : USE_VALUE_SUPPLIED);
+ }
+ break;
+ }
+ case SignedSettings::OPERATION_FAILED:
+ default: {
+ DCHECK(code == SignedSettings::OPERATION_FAILED);
+ DCHECK(GetOwnershipStatus() == OWNERSHIP_TAKEN);
+ LOG(ERROR) << "On owned device: failed to retrieve cros "
+ "setting, name=" << name;
+ if (retries_left_ > 0) {
+ retries_left_ -= 1;
+ StartFetchingSetting(name);
+ return;
+ }
+ LOG(ERROR) << "No retries left";
+ if (IsControlledBooleanSetting(name)) {
+ // For boolean settings we can just set safe (false) values
+ // and continue as trusted.
+ UpdateCacheBool(name, false, USE_VALUE_SUPPLIED);
+ } else {
+ prefs->ClearPref((name + kTrustedSuffix).c_str());
+ return;
+ }
+ break;
+ }
+ }
+ prefs->SetBoolean((name + kTrustedSuffix).c_str(), true);
+ {
+ DCHECK(GetOwnershipStatus() != OWNERSHIP_UNKNOWN);
+ std::vector<Task*>& callbacks_vector = callbacks_[name];
+ for (size_t i = 0; i < callbacks_vector.size(); ++i)
+ MessageLoop::current()->PostTask(FROM_HERE, callbacks_vector[i]);
+ callbacks_vector.clear();
+ }
+ if (code == SignedSettings::SUCCESS)
+ CrosSettings::Get()->FireObservers(name.c_str());
+ }
+
+ // Implementation of SignedSettingsHelper::Callback.
+ virtual void OnStorePropertyCompleted(SignedSettings::ReturnCode code,
+ const std::string& name,
+ const std::string& value) {
+ VLOG(1) << "Store cros setting " << name << "=" << value << ", code="
+ << code;
+
+ // Reload the setting if store op fails.
+ if (code != SignedSettings::SUCCESS)
+ SignedSettingsHelper::Get()->StartRetrieveProperty(name, this);
+ }
+
+ // Implementation of SignedSettingsHelper::Callback.
+ virtual void OnWhitelistCompleted(SignedSettings::ReturnCode code,
+ const std::string& email) {
+ VLOG(1) << "Add " << email << " to whitelist, code=" << code;
+
+ // Reload the whitelist on settings op failure.
+ if (code != SignedSettings::SUCCESS)
+ CrosSettings::Get()->FireObservers(kAccountsPrefUsers);
+ }
+
+ // Implementation of SignedSettingsHelper::Callback.
+ virtual void OnUnwhitelistCompleted(SignedSettings::ReturnCode code,
+ const std::string& email) {
+ VLOG(1) << "Remove " << email << " from whitelist, code=" << code;
+
+ // Reload the whitelist on settings op failure.
+ if (code != SignedSettings::SUCCESS)
+ CrosSettings::Get()->FireObservers(kAccountsPrefUsers);
+ }
+
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type.value == NotificationType::OWNERSHIP_TAKEN) {
+ SetOwnershipStatus(OWNERSHIP_TAKEN, SOURCE_OBSERVE);
+ notification_registrar_.RemoveAll();
+ } else {
+ NOTREACHED();
+ }
+ }
+
+ // Pending callbacks that need to be invoked after settings verification.
+ base::hash_map< std::string, std::vector< Task* > > callbacks_;
+
+ NotificationRegistrar notification_registrar_;
+ OwnershipStatus ownership_status_;
+
+ // In order to guard against occasional failure to fetch a property
+ // we allow for some number of retries.
+ int retries_left_;
+
+ friend class SignedSettingsHelper;
+ friend struct DefaultSingletonTraits<UserCrosSettingsTrust>;
+
+ DISALLOW_COPY_AND_ASSIGN(UserCrosSettingsTrust);
+};
+
} // namespace
-UserCrosSettingsProvider::UserCrosSettingsProvider() {
- StartFetchingBoolSetting(kAccountsPrefAllowGuest);
- StartFetchingBoolSetting(kAccountsPrefAllowNewUser);
- StartFetchingBoolSetting(kAccountsPrefShowUserNamesOnSignIn);
- StartFetchingStringSetting(kDeviceOwner);
-}
+} // namespace chromeos
-UserCrosSettingsProvider::~UserCrosSettingsProvider() {
- // Cancels all pending callbacks from us.
- SignedSettingsHelper::Get()->CancelCallback(this);
+// We want to use NewRunnableMethod with this class but need to disable
+// reference counting since it is singleton.
+DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::UserCrosSettingsTrust);
+
+namespace chromeos {
+
+UserCrosSettingsProvider::UserCrosSettingsProvider() {
+ // Trigger prefetching of settings.
+ UserCrosSettingsTrust::GetInstance();
}
// static
void UserCrosSettingsProvider::RegisterPrefs(PrefService* local_state) {
- // Cached signed settings values
- local_state->RegisterBooleanPref(kAccountsPrefAllowGuest, true);
- local_state->RegisterBooleanPref(kAccountsPrefAllowNewUser, true);
- local_state->RegisterBooleanPref(kAccountsPrefShowUserNamesOnSignIn, true);
- local_state->RegisterListPref(kAccountsPrefUsers);
- local_state->RegisterStringPref(kDeviceOwner, "");
+ for (size_t i = 0; i < arraysize(kBooleanSettings); ++i)
+ RegisterSetting(local_state, kBooleanSettings[i]);
+ for (size_t i = 0; i < arraysize(kStringSettings); ++i)
+ RegisterSetting(local_state, kStringSettings[i]);
+ for (size_t i = 0; i < arraysize(kListSettings); ++i)
+ RegisterSetting(local_state, kListSettings[i]);
+}
+
+bool UserCrosSettingsProvider::RequestTrustedAllowGuest(Task* callback) {
+ return UserCrosSettingsTrust::GetInstance()->RequestTrustedEntity(
+ kAccountsPrefAllowGuest, callback);
+}
+
+bool UserCrosSettingsProvider::RequestTrustedAllowNewUser(Task* callback) {
+ return UserCrosSettingsTrust::GetInstance()->RequestTrustedEntity(
+ kAccountsPrefAllowNewUser, callback);
+}
+
+bool UserCrosSettingsProvider::RequestTrustedShowUsersOnSignin(Task* callback) {
+ return UserCrosSettingsTrust::GetInstance()->RequestTrustedEntity(
+ kAccountsPrefShowUserNamesOnSignIn, callback);
+}
+
+bool UserCrosSettingsProvider::RequestTrustedOwner(Task* callback) {
+ return UserCrosSettingsTrust::GetInstance()->RequestTrustedEntity(
+ kDeviceOwner, callback);
}
// static
bool UserCrosSettingsProvider::cached_allow_guest() {
+ // Trigger prefetching if singleton object still does not exist.
+ UserCrosSettingsTrust::GetInstance();
return g_browser_process->local_state()->GetBoolean(kAccountsPrefAllowGuest);
}
// static
bool UserCrosSettingsProvider::cached_allow_new_user() {
+ // Trigger prefetching if singleton object still does not exist.
+ UserCrosSettingsTrust::GetInstance();
return g_browser_process->local_state()->GetBoolean(
kAccountsPrefAllowNewUser);
}
// static
bool UserCrosSettingsProvider::cached_show_users_on_signin() {
+ // Trigger prefetching if singleton object still does not exist.
+ UserCrosSettingsTrust::GetInstance();
return g_browser_process->local_state()->GetBoolean(
kAccountsPrefShowUserNamesOnSignIn);
}
@@ -132,6 +505,8 @@ const ListValue* UserCrosSettingsProvider::cached_whitelist() {
// static
std::string UserCrosSettingsProvider::cached_owner() {
+ // Trigger prefetching if singleton object still does not exist.
+ UserCrosSettingsTrust::GetInstance();
if (!g_browser_process || !g_browser_process->local_state())
return std::string();
return g_browser_process->local_state()->GetString(kDeviceOwner);
@@ -154,41 +529,12 @@ bool UserCrosSettingsProvider::IsEmailInCachedWhitelist(
void UserCrosSettingsProvider::DoSet(const std::string& path,
Value* in_value) {
- if (!UserManager::Get()->current_user_is_owner()) {
- LOG(WARNING) << "Changing settings from non-owner, setting=" << path;
-
- // Revert UI change.
- CrosSettings::Get()->FireObservers(path.c_str());
- return;
- }
-
- if (path == kAccountsPrefAllowGuest ||
- path == kAccountsPrefAllowNewUser ||
- path == kAccountsPrefShowUserNamesOnSignIn) {
- bool bool_value = false;
- if (in_value->GetAsBoolean(&bool_value)) {
- std::string value = bool_value ? "true" : "false";
- SignedSettingsHelper::Get()->StartStorePropertyOp(path, value, this);
- UpdateCacheBool(path.c_str(), bool_value);
-
- VLOG(1) << "Set cros setting " << path << "=" << value;
- }
- } else if (path == kDeviceOwner) {
- VLOG(1) << "Setting owner is not supported. Please use 'UpdateCachedOwner' "
- "instead.";
- } else if (path == kAccountsPrefUsers) {
- VLOG(1) << "Setting user whitelist is not implemented. Please use "
- "whitelist/unwhitelist instead.";
- } else {
- LOG(WARNING) << "Try to set unhandled cros setting " << path;
- }
+ UserCrosSettingsTrust::GetInstance()->Set(path, in_value);
}
bool UserCrosSettingsProvider::Get(const std::string& path,
Value** out_value) const {
- if (path == kAccountsPrefAllowGuest ||
- path == kAccountsPrefAllowNewUser ||
- path == kAccountsPrefShowUserNamesOnSignIn) {
+ if (IsControlledBooleanSetting(path)) {
*out_value = CreateSettingsBooleanValue(
g_browser_process->local_state()->GetBoolean(path.c_str()),
!UserManager::Get()->current_user_is_owner());
@@ -207,57 +553,9 @@ bool UserCrosSettingsProvider::HandlesSetting(const std::string& path) {
return ::StartsWithASCII(path, "cros.accounts.", true);
}
-void UserCrosSettingsProvider::OnWhitelistCompleted(bool success,
- const std::string& email) {
- VLOG(1) << "Add " << email << " to whitelist, success=" << success;
-
- // Reload the whitelist on settings op failure.
- if (!success)
- CrosSettings::Get()->FireObservers(kAccountsPrefUsers);
-}
-
-void UserCrosSettingsProvider::OnUnwhitelistCompleted(bool success,
- const std::string& email) {
- VLOG(1) << "Remove " << email << " from whitelist, success=" << success;
-
- // Reload the whitelist on settings op failure.
- if (!success)
- CrosSettings::Get()->FireObservers(kAccountsPrefUsers);
-}
-
-void UserCrosSettingsProvider::OnStorePropertyCompleted(
- bool success, const std::string& name, const std::string& value) {
- VLOG(1) << "Store cros setting " << name << "=" << value << ", success="
- << success;
-
- // Reload the setting if store op fails.
- if (!success)
- SignedSettingsHelper::Get()->StartRetrieveProperty(name, this);
-}
-
-void UserCrosSettingsProvider::OnRetrievePropertyCompleted(
- bool success, const std::string& name, const std::string& value) {
- if (!success) {
- LOG(WARNING) << "Failed to retrieve cros setting, name=" << name;
- return;
- }
-
- VLOG(1) << "Retrieved cros setting " << name << "=" << value;
-
- if (bool_settings_.count(name)) {
- UpdateCacheBool(name.c_str(), value == "true" ? true : false);
- }
-
- if (string_settings_.count(name)) {
- UpdateCacheString(name.c_str(), value);
- }
-
- CrosSettings::Get()->FireObservers(name.c_str());
-}
-
void UserCrosSettingsProvider::WhitelistUser(const std::string& email) {
- SignedSettingsHelper::Get()->StartWhitelistOp(email, true, this);
-
+ SignedSettingsHelper::Get()->StartWhitelistOp(
+ email, true, UserCrosSettingsTrust::GetInstance());
PrefService* prefs = g_browser_process->local_state();
ListValue* cached_whitelist = prefs->GetMutableList(kAccountsPrefUsers);
cached_whitelist->Append(Value::CreateStringValue(email));
@@ -265,7 +563,8 @@ void UserCrosSettingsProvider::WhitelistUser(const std::string& email) {
}
void UserCrosSettingsProvider::UnwhitelistUser(const std::string& email) {
- SignedSettingsHelper::Get()->StartWhitelistOp(email, false, this);
+ SignedSettingsHelper::Get()->StartWhitelistOp(
+ email, false, UserCrosSettingsTrust::GetInstance());
PrefService* prefs = g_browser_process->local_state();
ListValue* cached_whitelist = prefs->GetMutableList(kAccountsPrefUsers);
@@ -276,25 +575,7 @@ void UserCrosSettingsProvider::UnwhitelistUser(const std::string& email) {
// static
void UserCrosSettingsProvider::UpdateCachedOwner(const std::string& email) {
- UpdateCacheString(kDeviceOwner, email);
-}
-
-void UserCrosSettingsProvider::StartFetchingBoolSetting(
- const std::string& name) {
- bool_settings_.insert(name);
- StartFetchingSetting(name);
-}
-
-void UserCrosSettingsProvider::StartFetchingStringSetting(
- const std::string& name) {
- string_settings_.insert(name);
- StartFetchingSetting(name);
-}
-
-void UserCrosSettingsProvider::StartFetchingSetting(
- const std::string& name) {
- if (CrosLibrary::Get()->EnsureLoaded())
- SignedSettingsHelper::Get()->StartRetrieveProperty(name, this);
+ UpdateCacheString(kDeviceOwner, email, USE_VALUE_SUPPLIED);
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/user_cros_settings_provider.h b/chrome/browser/chromeos/user_cros_settings_provider.h
index aa7db0f..7b000ca 100644
--- a/chrome/browser/chromeos/user_cros_settings_provider.h
+++ b/chrome/browser/chromeos/user_cros_settings_provider.h
@@ -9,24 +9,33 @@
#include <string>
#include "base/basictypes.h"
-#include "base/hash_tables.h"
#include "chrome/browser/chromeos/cros_settings_provider.h"
#include "chrome/browser/chromeos/login/signed_settings_helper.h"
class ListValue;
class PrefService;
+class Task;
namespace chromeos {
-class UserCrosSettingsProvider : public CrosSettingsProvider,
- public SignedSettingsHelper::Callback {
+class UserCrosSettingsProvider : public CrosSettingsProvider {
public:
UserCrosSettingsProvider();
- virtual ~UserCrosSettingsProvider();
+ virtual ~UserCrosSettingsProvider() {}
// Registers cached users settings in preferences.
static void RegisterPrefs(PrefService* local_state);
+ // Methods to use when trusted (signature verified) values are required.
+ // Return true if subsequent call to corresponding cached_* getter shall
+ // return trusted value.
+ // Return false if trusted values are unavailable at a moment.
+ // In latter case passed task will be posted when ready.
+ bool RequestTrustedAllowGuest(Task* callback);
+ bool RequestTrustedAllowNewUser(Task* callback);
+ bool RequestTrustedShowUsersOnSignin(Task* callback);
+ bool RequestTrustedOwner(Task* callback);
+
// Helper functions to access cached settings.
static bool cached_allow_guest();
static bool cached_allow_new_user();
@@ -43,14 +52,6 @@ class UserCrosSettingsProvider : public CrosSettingsProvider,
virtual bool Get(const std::string& path, Value** out_value) const;
virtual bool HandlesSetting(const std::string& path);
- // SignedSettingsHelper::Callback overrides.
- virtual void OnWhitelistCompleted(bool success, const std::string& email);
- virtual void OnUnwhitelistCompleted(bool success, const std::string& email);
- virtual void OnStorePropertyCompleted(
- bool success, const std::string& name, const std::string& value);
- virtual void OnRetrievePropertyCompleted(
- bool success, const std::string& name, const std::string& value);
-
void WhitelistUser(const std::string& email);
void UnwhitelistUser(const std::string& email);
@@ -61,13 +62,6 @@ class UserCrosSettingsProvider : public CrosSettingsProvider,
// CrosSettingsProvider implementation.
virtual void DoSet(const std::string& path, Value* value);
- void StartFetchingBoolSetting(const std::string& name);
- void StartFetchingStringSetting(const std::string& name);
- void StartFetchingSetting(const std::string& name);
-
- base::hash_set<std::string> bool_settings_;
- base::hash_set<std::string> string_settings_;
-
DISALLOW_COPY_AND_ASSIGN(UserCrosSettingsProvider);
};
diff --git a/chrome/browser/chromeos/view_ids.h b/chrome/browser/chromeos/view_ids.h
index f8b2794..e32e94e 100644
--- a/chrome/browser/chromeos/view_ids.h
+++ b/chrome/browser/chromeos/view_ids.h
@@ -6,7 +6,7 @@
#define CHROME_BROWSER_CHROMEOS_VIEW_IDS_H_
#pragma once
-#include "chrome/browser/view_ids.h"
+#include "chrome/browser/ui/view_ids.h"
// View ID used in ChromeOS.
enum ChromeOSViewIds {
diff --git a/chrome/browser/chromeos/views/domui_menu_widget.cc b/chrome/browser/chromeos/views/domui_menu_widget.cc
index 6231d6a..8a5e360 100644
--- a/chrome/browser/chromeos/views/domui_menu_widget.cc
+++ b/chrome/browser/chromeos/views/domui_menu_widget.cc
@@ -4,10 +4,11 @@
#include "chrome/browser/chromeos/views/domui_menu_widget.h"
+#include <algorithm>
+
#include "base/stringprintf.h"
#include "base/singleton.h"
#include "base/task.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/chromeos/views/menu_locator.h"
#include "chrome/browser/chromeos/views/native_menu_domui.h"
#include "chrome/browser/chromeos/wm_ipc.h"
@@ -15,11 +16,10 @@
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/views/dom_view.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
-#include "cros/chromeos_wm_ipc_enums.h"
#include "gfx/canvas_skia.h"
#include "googleurl/src/gurl.h"
+#include "third_party/cros/chromeos_wm_ipc_enums.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
#include "views/border.h"
#include "views/layout_manager.h"
@@ -210,7 +210,7 @@ gboolean MapToFocus(GtkWidget* widget, GdkEvent* event, gpointer data) {
void DOMUIMenuWidget::EnableScroll(bool enable) {
ExecuteJavascript(StringPrintf(
- L"enableScroll(%ls)", enable ? L"true" : L"false" ));
+ L"enableScroll(%ls)", enable ? L"true" : L"false"));
}
void DOMUIMenuWidget::EnableInput(bool select_item) {
diff --git a/chrome/browser/chromeos/views/native_menu_domui.cc b/chrome/browser/chromeos/views/native_menu_domui.cc
index ed30c93..5ffb24f 100644
--- a/chrome/browser/chromeos/views/native_menu_domui.cc
+++ b/chrome/browser/chromeos/views/native_menu_domui.cc
@@ -12,18 +12,20 @@
#include "chrome/browser/chromeos/dom_ui/menu_ui.h"
#include "chrome/browser/chromeos/views/domui_menu_widget.h"
#include "chrome/browser/chromeos/views/menu_locator.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/common/url_constants.h"
#include "gfx/rect.h"
#include "views/controls/menu/menu_2.h"
-#include "views/controls/menu/native_menu_gtk.h"
#include "views/controls/menu/nested_dispatcher_gtk.h"
#if defined(TOUCH_UI)
#include "views/focus/accelerator_handler.h"
+#include "views/controls/menu/native_menu_x.h"
+#else
+#include "views/controls/menu/native_menu_gtk.h"
#endif
namespace {
@@ -249,8 +251,12 @@ bool NativeMenuDOMUI::Dispatch(GdkEvent* event) {
}
#if defined(TOUCH_UI)
-bool NativeMenuDOMUI::Dispatch(XEvent* xevent) {
- return views::DispatchXEvent(xevent);
+base::MessagePumpGlibXDispatcher::DispatchStatus NativeMenuDOMUI::Dispatch(
+ XEvent* xevent) {
+ return views::DispatchXEvent(xevent) ?
+ base::MessagePumpGlibXDispatcher::EVENT_PROCESSED :
+ base::MessagePumpGlibXDispatcher::EVENT_IGNORED;
+
}
#endif
@@ -406,7 +412,11 @@ MenuWrapper* MenuWrapper::CreateWrapper(Menu2* menu) {
if (chromeos::MenuUI::IsEnabled()) {
return new chromeos::NativeMenuDOMUI(model, true);
} else {
+#if defined(TOUCH_UI)
+ return new NativeMenuX(menu);
+#else
return new NativeMenuGtk(menu);
+#endif
}
}
diff --git a/chrome/browser/chromeos/views/native_menu_domui.h b/chrome/browser/chromeos/views/native_menu_domui.h
index 03a6b92..53ef488 100644
--- a/chrome/browser/chromeos/views/native_menu_domui.h
+++ b/chrome/browser/chromeos/views/native_menu_domui.h
@@ -64,7 +64,8 @@ class NativeMenuDOMUI : public views::MenuWrapper,
// Overriden from MessageLoopForUI::Dispatcher:
virtual bool Dispatch(GdkEvent* event);
#if defined(TOUCH_UI)
- virtual bool Dispatch(XEvent* xevent);
+ virtual base::MessagePumpGlibXDispatcher::DispatchStatus Dispatch(
+ XEvent* xevent);
#endif
// Overriden from DOMUIMenuControl;
diff --git a/chrome/browser/chromeos/volume_bubble.cc b/chrome/browser/chromeos/volume_bubble.cc
index 512dac7..ec9d365 100644
--- a/chrome/browser/chromeos/volume_bubble.cc
+++ b/chrome/browser/chromeos/volume_bubble.cc
@@ -4,132 +4,25 @@
#include "chrome/browser/chromeos/volume_bubble.h"
-#include <gdk/gdk.h>
-
-#include "base/timer.h"
-#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_window.h"
-#include "chrome/browser/profile_manager.h"
-#include "chrome/browser/chromeos/volume_bubble_view.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/views/info_bubble.h"
-#include "views/widget/root_view.h"
-
-namespace {
-
-const int kBubbleShowTimeoutSec = 2;
-const int kAnimationDurationMs = 200;
-
-// Horizontal relative position: 0 - leftmost, 0.5 - center, 1 - rightmost.
-const double kVolumeBubbleXRatio = 0.5;
-
-// Vertical gap from the bottom of the screen in pixels.
-const int kVolumeBubbleBottomGap = 30;
-
-} // namespace
+#include "app/resource_bundle.h"
+#include "base/singleton.h"
+#include "grit/theme_resources.h"
namespace chromeos {
-// Temporary helper routine. Returns the widget from the most-recently-focused
-// normal browser window or NULL.
-// TODO(glotov): remove this in favor of enabling InfoBubble class act
-// without |parent| specified. crosbug.com/4025
-static views::Widget* GetToplevelWidget() {
- // We just use the default profile here -- this gets overridden as needed
- // in Chrome OS depending on whether the user is logged in or not.
- Browser* browser =
- BrowserList::FindBrowserWithType(
- ProfileManager::GetDefaultProfile(),
- Browser::TYPE_NORMAL,
- true); // match_incognito
- if (!browser)
- return NULL;
-
- views::RootView* root =
- views::Widget::FindRootView(
- GTK_WINDOW(browser->window()->GetNativeHandle()));
- DCHECK(root);
- if (!root)
- return NULL;
-
- return root->GetWidget();
-}
-
VolumeBubble::VolumeBubble()
- : previous_percent_(-1),
- current_percent_(-1),
- bubble_(NULL),
- view_(NULL),
- animation_(this) {
- animation_.SetSlideDuration(kAnimationDurationMs);
- animation_.SetTweenType(Tween::LINEAR);
-}
-
-void VolumeBubble::ShowVolumeBubble(int percent) {
- if (percent < 0)
- percent = 0;
- if (percent > 100)
- percent = 100;
- if (previous_percent_ == -1)
- previous_percent_ = percent;
- current_percent_ = percent;
- if (!bubble_) {
- views::Widget* widget = GetToplevelWidget();
- if (widget == NULL)
- return;
- DCHECK(view_ == NULL);
- view_ = new VolumeBubbleView;
- view_->Init(previous_percent_);
- // Calculate position of the volume bubble.
- // TODO(glotov): Place volume bubble over the keys initiated the
- // volume change. This metric must be specific to the given
- // architecture. crosbug.com/4028
- gfx::Rect bounds;
- widget->GetBounds(&bounds, false);
- const gfx::Size view_size = view_->GetPreferredSize();
- // Note that (x, y) is the point of the center of the bubble.
- const int x = view_size.width() / 2 +
- kVolumeBubbleXRatio * (bounds.width() - view_size.width());
- const int y = bounds.height() - view_size.height() / 2 -
- kVolumeBubbleBottomGap;
- bubble_ = InfoBubble::ShowFocusless(widget, gfx::Rect(x, y, 0, 20),
- BubbleBorder::FLOAT, view_, this);
- } else {
- DCHECK(view_);
- timeout_timer_.Stop();
- }
- if (animation_.is_animating())
- animation_.End();
- animation_.Reset();
- animation_.Show();
- timeout_timer_.Start(base::TimeDelta::FromSeconds(kBubbleShowTimeoutSec),
- this, &VolumeBubble::OnTimeout);
-}
-
-void VolumeBubble::OnTimeout() {
- if (bubble_)
- bubble_->Close();
-}
-
-void VolumeBubble::InfoBubbleClosing(InfoBubble* info_bubble, bool) {
- DCHECK(info_bubble == bubble_);
- timeout_timer_.Stop();
- animation_.Stop();
- bubble_ = NULL;
- view_ = NULL;
-}
-
-void VolumeBubble::AnimationEnded(const Animation* animation) {
- previous_percent_ = current_percent_;
+ : SettingLevelBubble(
+ ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_VOLUME_BUBBLE_UP_ICON),
+ ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_VOLUME_BUBBLE_DOWN_ICON),
+ ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_VOLUME_BUBBLE_MUTE_ICON)) {
}
-void VolumeBubble::AnimationProgressed(const Animation* animation) {
- if (view_) {
- view_->Update(
- Tween::ValueBetween(animation->GetCurrentValue(),
- previous_percent_,
- current_percent_));
- }
+// static
+VolumeBubble* VolumeBubble::GetInstance() {
+ return Singleton<VolumeBubble>::get();
}
} // namespace chromeos
diff --git a/chrome/browser/chromeos/volume_bubble.h b/chrome/browser/chromeos/volume_bubble.h
index 7496055..17f72fc 100644
--- a/chrome/browser/chromeos/volume_bubble.h
+++ b/chrome/browser/chromeos/volume_bubble.h
@@ -6,58 +6,27 @@
#define CHROME_BROWSER_CHROMEOS_VOLUME_BUBBLE_H_
#pragma once
-#include "app/animation_delegate.h"
-#include "app/slide_animation.h"
-#include "base/singleton.h"
-#include "base/timer.h"
-#include "chrome/browser/views/info_bubble.h"
+#include "base/basictypes.h"
+#include "chrome/browser/chromeos/setting_level_bubble.h"
-namespace chromeos {
+template <typename T> struct DefaultSingletonTraits;
-class VolumeBubbleView;
+namespace chromeos {
// Singleton class controlling volume bubble.
-class VolumeBubble : public InfoBubbleDelegate,
- public AnimationDelegate {
+class VolumeBubble : public SettingLevelBubble {
public:
- static VolumeBubble* instance() {
- return Singleton<VolumeBubble>::get();
- }
-
- void ShowVolumeBubble(int percent);
+ static VolumeBubble* GetInstance();
private:
friend struct DefaultSingletonTraits<VolumeBubble>;
VolumeBubble();
- void OnTimeout();
-
- // Overridden from InfoBubbleDelegate.
- virtual void InfoBubbleClosing(InfoBubble* info_bubble,
- bool closed_by_escape);
- virtual bool CloseOnEscape() { return true; }
- virtual bool FadeInOnShow() { return false; }
-
- // Overridden from AnimationDelegate.
- virtual void AnimationEnded(const Animation* animation);
- virtual void AnimationProgressed(const Animation* animation);
-
- // Previous and current volume percentages, -1 if not yet shown.
- int previous_percent_;
- int current_percent_;
-
- // Currently shown bubble or NULL.
- InfoBubble* bubble_;
-
- // Its contents view, owned by InfoBubble.
- VolumeBubbleView* view_;
-
- SlideAnimation animation_;
- base::OneShotTimer<VolumeBubble> timeout_timer_;
+ virtual ~VolumeBubble() {}
DISALLOW_COPY_AND_ASSIGN(VolumeBubble);
};
-} // namespace
+} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_VOLUME_BUBBLE_H_
diff --git a/chrome/browser/chromeos/volume_bubble_view.cc b/chrome/browser/chromeos/volume_bubble_view.cc
deleted file mode 100644
index 7bb500f..0000000
--- a/chrome/browser/chromeos/volume_bubble_view.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-// 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.
-
-#include "chrome/browser/chromeos/volume_bubble_view.h"
-
-#include <string>
-
-#include "app/resource_bundle.h"
-#include "base/logging.h"
-#include "gfx/canvas.h"
-#include "grit/theme_resources.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "views/controls/progress_bar.h"
-
-using views::Background;
-using views::View;
-using views::Widget;
-
-namespace {
-
-// Volume bubble metrics.
-const int kWidth = 300, kHeight = 75;
-const int kMargin = 25;
-const int kProgressBarHeight = 20;
-
-} // namespace
-
-namespace chromeos {
-
-VolumeBubbleView::VolumeBubbleView() : progress_bar_(NULL) {
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- volume_icon_ = rb.GetBitmapNamed(IDR_VOLUMEBUBBLE_ICON);
-}
-
-void VolumeBubbleView::Init(int volume_level_percent) {
- DCHECK(volume_level_percent >= 0 && volume_level_percent <= 100);
- progress_bar_ = new views::ProgressBar();
- AddChildView(progress_bar_);
- Update(volume_level_percent);
-}
-
-void VolumeBubbleView::Update(int volume_level_percent) {
- DCHECK(volume_level_percent >= 0 && volume_level_percent <= 100);
- progress_bar_->SetProgress(volume_level_percent);
-}
-
-void VolumeBubbleView::Paint(gfx::Canvas* canvas) {
- views::View::Paint(canvas);
- canvas->DrawBitmapInt(*volume_icon_,
- volume_icon_->width(),
- (height() - volume_icon_->height()) / 2);
-}
-
-void VolumeBubbleView::Layout() {
- progress_bar_->SetBounds(volume_icon_->width() + kMargin * 2,
- (height() - kProgressBarHeight) / 2,
- width() - volume_icon_->width() - kMargin * 3,
- kProgressBarHeight);
-}
-
-gfx::Size VolumeBubbleView::GetPreferredSize() {
- return gfx::Size(kWidth, kHeight);
-}
-
-} // namespace chromeos
diff --git a/chrome/browser/chromeos/volume_bubble_view.h b/chrome/browser/chromeos/volume_bubble_view.h
deleted file mode 100644
index f9ec0b0..0000000
--- a/chrome/browser/chromeos/volume_bubble_view.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_CHROMEOS_VOLUME_BUBBLE_VIEW_H_
-#define CHROME_BROWSER_CHROMEOS_VOLUME_BUBBLE_VIEW_H_
-#pragma once
-
-#include "views/view.h"
-
-namespace views {
-class ProgressBar;
-} // namespace views
-
-class SkBitmap;
-
-namespace chromeos {
-
-class VolumeBubbleView : public views::View {
- public:
- VolumeBubbleView();
-
- // Initialize the view. Set the volume progress bar to the specified position.
- void Init(int volume_level_percent);
-
- // Set the volume progress bar to the specified position and redraw it.
- void Update(int volume_level_percent);
-
- // views::View implementation:
- virtual void Paint(gfx::Canvas* canvas);
- virtual void Layout();
- virtual gfx::Size GetPreferredSize();
-
- private:
- views::ProgressBar* progress_bar_;
- SkBitmap* volume_icon_;
-
- DISALLOW_COPY_AND_ASSIGN(VolumeBubbleView);
-};
-
-} // namespace chromeos
-
-#endif // CHROME_BROWSER_CHROMEOS_VOLUME_BUBBLE_VIEW_H_
diff --git a/chrome/browser/chromeos/wm_ipc.cc b/chrome/browser/chromeos/wm_ipc.cc
index 1dd0af5..aa09dd7 100644
--- a/chrome/browser/chromeos/wm_ipc.cc
+++ b/chrome/browser/chromeos/wm_ipc.cc
@@ -10,9 +10,9 @@ extern "C" {
}
#include "app/x11_util.h"
+#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
-#include "base/singleton.h"
namespace chromeos {
@@ -59,12 +59,11 @@ bool SetIntProperty(XID xid, Atom xatom, const std::vector<int>& values) {
} // namespace
+static base::LazyInstance<WmIpc> g_wm_ipc(base::LINKER_INITIALIZED);
+
// static
WmIpc* WmIpc::instance() {
- static WmIpc* instance = NULL;
- if (!instance)
- instance = Singleton<WmIpc>::get();
- return instance;
+ return g_wm_ipc.Pointer();
}
bool WmIpc::SetWindowType(GtkWidget* widget,
diff --git a/chrome/browser/chromeos/wm_ipc.h b/chrome/browser/chromeos/wm_ipc.h
index 92fef71..a0c8abd 100644
--- a/chrome/browser/chromeos/wm_ipc.h
+++ b/chrome/browser/chromeos/wm_ipc.h
@@ -12,12 +12,15 @@
#include <vector>
#include "base/logging.h"
-#include "base/singleton.h"
-#include "cros/chromeos_wm_ipc_enums.h"
+#include "third_party/cros/chromeos_wm_ipc_enums.h"
typedef unsigned long Atom;
typedef unsigned long XID;
+namespace base {
+template <typename T> struct DefaultLazyInstanceTraits;
+}
+
namespace chromeos {
class WmIpc {
@@ -113,7 +116,7 @@ class WmIpc {
void SetLoggedInProperty(bool logged_in);
private:
- friend struct DefaultSingletonTraits<WmIpc>;
+ friend struct base::DefaultLazyInstanceTraits<WmIpc>;
WmIpc();
diff --git a/chrome/browser/chromeos/wm_message_listener.cc b/chrome/browser/chromeos/wm_message_listener.cc
index adbba2e..c0815e4 100644
--- a/chrome/browser/chromeos/wm_message_listener.cc
+++ b/chrome/browser/chromeos/wm_message_listener.cc
@@ -7,7 +7,7 @@
namespace chromeos {
// static
-WmMessageListener* WmMessageListener::instance() {
+WmMessageListener* WmMessageListener::GetInstance() {
static WmMessageListener* instance = NULL;
if (!instance) {
instance = Singleton<WmMessageListener>::get();
diff --git a/chrome/browser/chromeos/wm_message_listener.h b/chrome/browser/chromeos/wm_message_listener.h
index f389c4c..36ba475 100644
--- a/chrome/browser/chromeos/wm_message_listener.h
+++ b/chrome/browser/chromeos/wm_message_listener.h
@@ -31,7 +31,7 @@ class WmMessageListener : public MessageLoopForUI::Observer {
GdkWindow* window) = 0;
};
- static WmMessageListener* instance();
+ static WmMessageListener* GetInstance();
void AddObserver(Observer* observer) {
observers_.AddObserver(observer);
diff --git a/chrome/browser/chromeos/wm_overview_controller.cc b/chrome/browser/chromeos/wm_overview_controller.cc
index d4625de..778af64 100644
--- a/chrome/browser/chromeos/wm_overview_controller.cc
+++ b/chrome/browser/chromeos/wm_overview_controller.cc
@@ -19,9 +19,9 @@
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/tab_contents/thumbnail_generator.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/browser/views/frame/browser_view.h"
#include "chrome/common/notification_service.h"
#include "views/widget/root_view.h"
@@ -453,7 +453,7 @@ void BrowserListener::RenumberSnapshots(int start_index) {
// WmOverviewController methods
// static
-WmOverviewController* WmOverviewController::instance() {
+WmOverviewController* WmOverviewController::GetInstance() {
static WmOverviewController* instance = NULL;
if (!instance) {
instance = Singleton<WmOverviewController>::get();
@@ -483,11 +483,11 @@ WmOverviewController::WmOverviewController()
}
BrowserList::AddObserver(this);
- WmMessageListener::instance()->AddObserver(this);
+ WmMessageListener::GetInstance()->AddObserver(this);
}
WmOverviewController::~WmOverviewController() {
- WmMessageListener::instance()->RemoveObserver(this);
+ WmMessageListener::GetInstance()->RemoveObserver(this);
BrowserList::RemoveObserver(this);
listeners_.clear();
}
@@ -687,7 +687,7 @@ void WmOverviewController::UpdateSnapshots() {
}
// Found next one;
- browser_listener_index ++;
+ browser_listener_index++;
browser_listener_index = browser_listener_index % listeners_.size();
tab_contents_index = -1;
@@ -715,8 +715,7 @@ void WmOverviewController::AddAllBrowsers() {
// Don't add a browser to the list if that type of browser doesn't
// have snapshots in overview mode.
if ((*iterator)->type() != Browser::TYPE_NORMAL &&
- (*iterator)->type() != Browser::TYPE_APP &&
- (*iterator)->type() != Browser::TYPE_EXTENSION_APP) {
+ (*iterator)->type() != Browser::TYPE_APP) {
++iterator;
continue;
}
diff --git a/chrome/browser/chromeos/wm_overview_controller.h b/chrome/browser/chromeos/wm_overview_controller.h
index 8618e3e..d5999b5 100644
--- a/chrome/browser/chromeos/wm_overview_controller.h
+++ b/chrome/browser/chromeos/wm_overview_controller.h
@@ -64,7 +64,7 @@ class WmOverviewController : public BrowserList::Observer,
};
// This class is a singleton.
- static WmOverviewController* instance();
+ static WmOverviewController* GetInstance();
// BrowserList::Observer methods
void OnBrowserAdded(const Browser* browser) {}
diff --git a/chrome/browser/chromeos/wm_overview_fav_icon.cc b/chrome/browser/chromeos/wm_overview_fav_icon.cc
index dea1b0e..ad9dfa8 100644
--- a/chrome/browser/chromeos/wm_overview_fav_icon.cc
+++ b/chrome/browser/chromeos/wm_overview_fav_icon.cc
@@ -9,8 +9,8 @@
#include "app/x11_util.h"
#include "chrome/browser/chromeos/wm_ipc.h"
#include "chrome/browser/chromeos/wm_overview_snapshot.h"
-#include "cros/chromeos_wm_ipc_enums.h"
#include "skia/ext/image_operations.h"
+#include "third_party/cros/chromeos_wm_ipc_enums.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "views/controls/image_view.h"
#include "views/controls/label.h"
diff --git a/chrome/browser/chromeos/wm_overview_title.cc b/chrome/browser/chromeos/wm_overview_title.cc
index a5ce96e..7c6c5b6 100644
--- a/chrome/browser/chromeos/wm_overview_title.cc
+++ b/chrome/browser/chromeos/wm_overview_title.cc
@@ -14,7 +14,7 @@
#include "chrome/browser/chromeos/wm_ipc.h"
#include "chrome/browser/chromeos/wm_overview_snapshot.h"
#include "chrome/browser/ui/browser.h"
-#include "cros/chromeos_wm_ipc_enums.h"
+#include "third_party/cros/chromeos_wm_ipc_enums.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "views/border.h"
#include "views/grid_layout.h"
diff --git a/chrome/browser/cocoa/about_ipc_bridge.h b/chrome/browser/cocoa/about_ipc_bridge.h
deleted file mode 100644
index 0d91e3c..0000000
--- a/chrome/browser/cocoa/about_ipc_bridge.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_ABOUT_IPC_BRIDGE_H_
-#define CHROME_BROWSER_COCOA_ABOUT_IPC_BRIDGE_H_
-#pragma once
-
-#include "ipc/ipc_logging.h"
-#include "ipc/ipc_message_utils.h"
-
-#if defined(IPC_MESSAGE_LOG_ENABLED)
-
-@class AboutIPCController;
-
-// On Windows, the AboutIPCDialog is a views::View. On Mac we have a
-// Cocoa dialog. This class bridges from C++ to ObjC.
-class AboutIPCBridge : public IPC::Logging::Consumer {
- public:
- AboutIPCBridge(AboutIPCController* controller) : controller_(controller) { }
- virtual ~AboutIPCBridge() { }
-
- // IPC::Logging::Consumer implementation.
- virtual void Log(const IPC::LogData& data);
-
- private:
- AboutIPCController* controller_; // weak; owns me
- DISALLOW_COPY_AND_ASSIGN(AboutIPCBridge);
-};
-
-#endif // IPC_MESSAGE_LOG_ENABLED
-
-#endif // CHROME_BROWSER_COCOA_ABOUT_IPC_BRIDGE_H_
diff --git a/chrome/browser/cocoa/about_ipc_bridge.mm b/chrome/browser/cocoa/about_ipc_bridge.mm
deleted file mode 100644
index ee02e94..0000000
--- a/chrome/browser/cocoa/about_ipc_bridge.mm
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/about_ipc_bridge.h"
-#include "chrome/browser/cocoa/about_ipc_controller.h"
-
-#if defined(IPC_MESSAGE_LOG_ENABLED)
-
-void AboutIPCBridge::Log(const IPC::LogData& data) {
- CocoaLogData* cocoa_data = [[CocoaLogData alloc] initWithLogData:data];
- if ([NSThread isMainThread]) {
- [controller_ log:cocoa_data];
- } else {
- [controller_ performSelectorOnMainThread:@selector(log:)
- withObject:cocoa_data
- waitUntilDone:NO];
- }
-}
-
-#endif
diff --git a/chrome/browser/cocoa/about_ipc_controller.h b/chrome/browser/cocoa/about_ipc_controller.h
deleted file mode 100644
index c6e8dc0..0000000
--- a/chrome/browser/cocoa/about_ipc_controller.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_ABOUT_IPC_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_ABOUT_IPC_CONTROLLER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_ptr.h"
-#include "ipc/ipc_logging.h"
-#include "ipc/ipc_message_utils.h"
-#include "third_party/GTM/Foundation/GTMRegex.h"
-
-// Must be included after IPC_MESSAGE_LOG_ENABLED gets defined
-#import "chrome/browser/cocoa/about_ipc_bridge.h"
-
-#if defined(IPC_MESSAGE_LOG_ENABLED)
-
-// An objc wrapper for IPC::LogData to allow use of Cocoa bindings.
-@interface CocoaLogData : NSObject {
- @private
- IPC::LogData data_;
-}
-- (id)initWithLogData:(const IPC::LogData&)data;
-@end
-
-
-// A window controller that handles the about:ipc non-modal dialog.
-@interface AboutIPCController : NSWindowController {
- @private
- scoped_ptr<AboutIPCBridge> bridge_;
- IBOutlet NSButton* startStopButton_;
- IBOutlet NSTableView* tableView_;
- IBOutlet NSArrayController* dataController_;
- IBOutlet NSTextField* eventCount_;
- IBOutlet NSTextField* filteredEventCount_;
- IBOutlet NSTextField* userStringTextField1_;
- IBOutlet NSTextField* userStringTextField2_;
- IBOutlet NSTextField* userStringTextField3_;
- // Count of filtered events.
- int filteredEventCounter_;
- // Cocoa-bound to check boxes for filtering messages.
- // Each BOOL allows events that have that name prefix.
- // E.g. if set, appCache_ allows events named AppCache*.
- // The actual string to match is defined in the xib.
- // The userStrings allow a user-specified prefix.
- BOOL appCache_;
- BOOL view_;
- BOOL utilityHost_;
- BOOL viewHost_;
- BOOL plugin_;
- BOOL npObject_;
- BOOL devTools_;
- BOOL pluginProcessing_;
- BOOL userString1_;
- BOOL userString2_;
- BOOL userString3_;
-}
-
-+ (AboutIPCController*)sharedController;
-
-- (IBAction)startStop:(id)sender;
-- (IBAction)clear:(id)sender;
-
-// Called from our C++ bridge class. To accomodate multithreaded
-// ownership issues, this method ACCEPTS OWNERSHIP of the arg passed
-// in.
-- (void)log:(CocoaLogData*)data;
-
-// Update visible state (e.g. Start/Stop button) based on logging run
-// state. Does not change state.
-- (void)updateVisibleRunState;
-
-@end
-
-@interface AboutIPCController(TestingAPI)
-- (BOOL)filterOut:(CocoaLogData*)data;
-- (void)setDisplayViewMessages:(BOOL)display;
-@end
-
-#endif // IPC_MESSAGE_LOG_ENABLED
-#endif // CHROME_BROWSER_COCOA_ABOUT_IPC_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/about_ipc_controller.mm b/chrome/browser/cocoa/about_ipc_controller.mm
deleted file mode 100644
index ccccf8b..0000000
--- a/chrome/browser/cocoa/about_ipc_controller.mm
+++ /dev/null
@@ -1,198 +0,0 @@
-// Copyright (c) 2009 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/logging.h"
-#include "base/mac_util.h"
-#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
-#include "base/time.h"
-#include "chrome/browser/browser_process.h"
-#import "chrome/browser/cocoa/about_ipc_controller.h"
-
-#if defined(IPC_MESSAGE_LOG_ENABLED)
-
-@implementation CocoaLogData
-
-- (id)initWithLogData:(const IPC::LogData&)data {
- if ((self = [super init])) {
- data_ = data;
- // data_.message_name may not have been filled in if it originated
- // somewhere other than the browser process.
- IPC::Logging::GetMessageText(data_.type, &data_.message_name, NULL, NULL);
- }
- return self;
-}
-
-- (NSString*)time {
- base::Time t = base::Time::FromInternalValue(data_.sent);
- base::Time::Exploded exploded;
- t.LocalExplode(&exploded);
- return [NSString stringWithFormat:@"%02d:%02d:%02d.%03d",
- exploded.hour, exploded.minute,
- exploded.second, exploded.millisecond];
-}
-
-- (NSString*)channel {
- return base::SysUTF8ToNSString(data_.channel);
-}
-
-- (NSString*)message {
- if (data_.message_name == "") {
- int high = data_.type >> 12;
- int low = data_.type - (high<<12);
- return [NSString stringWithFormat:@"type=(%d,%d) 0x%x,0x%x",
- high, low, high, low];
- }
- else {
- return base::SysUTF8ToNSString(data_.message_name);
- }
-}
-
-- (NSString*)flags {
- return base::SysUTF8ToNSString(data_.flags);
-}
-
-- (NSString*)dispatch {
- base::Time sent = base::Time::FromInternalValue(data_.sent);
- int64 delta = (base::Time::FromInternalValue(data_.receive) -
- sent).InMilliseconds();
- return [NSString stringWithFormat:@"%d", delta ? (int)delta : 0];
-}
-
-- (NSString*)process {
- base::TimeDelta delta = (base::Time::FromInternalValue(data_.dispatch) -
- base::Time::FromInternalValue(data_.receive));
- int64 t = delta.InMilliseconds();
- return [NSString stringWithFormat:@"%d", t ? (int)t : 0];
-}
-
-- (NSString*)parameters {
- return base::SysUTF8ToNSString(data_.params);
-}
-
-@end
-
-namespace {
-AboutIPCController* gSharedController = nil;
-}
-
-@implementation AboutIPCController
-
-+ (AboutIPCController*)sharedController {
- if (gSharedController == nil)
- gSharedController = [[AboutIPCController alloc] init];
- return gSharedController;
-}
-
-- (id)init {
- NSString* nibpath = [mac_util::MainAppBundle() pathForResource:@"AboutIPC"
- ofType:@"nib"];
- if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
- // Default to all on
- appCache_ = view_ = utilityHost_ = viewHost_ = plugin_ =
- npObject_ = devTools_ = pluginProcessing_ = userString1_ =
- userString2_ = userString3_ = YES;
- }
- return self;
-}
-
-- (void)dealloc {
- if (gSharedController == self)
- gSharedController = nil;
- if (g_browser_process)
- g_browser_process->SetIPCLoggingEnabled(false); // just in case...
- IPC::Logging::current()->SetConsumer(NULL);
- [super dealloc];
-}
-
-- (void)awakeFromNib {
- // Running Chrome with the --ipc-logging switch might cause it to
- // be enabled before the about:ipc window comes up; accomodate.
- [self updateVisibleRunState];
-
- // We are now able to display information, so let'er rip.
- bridge_.reset(new AboutIPCBridge(self));
- IPC::Logging::current()->SetConsumer(bridge_.get());
-}
-
-// Delegate callback. Closing the window means there is no more need
-// for the me, the controller.
-- (void)windowWillClose:(NSNotification*)notification {
- [self autorelease];
-}
-
-- (void)updateVisibleRunState {
- if (IPC::Logging::current()->Enabled())
- [startStopButton_ setTitle:@"Stop"];
- else
- [startStopButton_ setTitle:@"Start"];
-}
-
-- (IBAction)startStop:(id)sender {
- g_browser_process->SetIPCLoggingEnabled(!IPC::Logging::current()->Enabled());
- [self updateVisibleRunState];
-}
-
-- (IBAction)clear:(id)sender {
- [dataController_ setContent:[NSMutableArray array]];
- [eventCount_ setStringValue:@"0"];
- [filteredEventCount_ setStringValue:@"0"];
- filteredEventCounter_ = 0;
-}
-
-// Return YES if we should filter this out; else NO.
-// Just to be clear, [@"any string" hasPrefix:@""] returns NO.
-- (BOOL)filterOut:(CocoaLogData*)data {
- NSString* name = [data message];
- if ((appCache_) && [name hasPrefix:@"AppCache"])
- return NO;
- if ((view_) && [name hasPrefix:@"ViewMsg"])
- return NO;
- if ((utilityHost_) && [name hasPrefix:@"UtilityHost"])
- return NO;
- if ((viewHost_) && [name hasPrefix:@"ViewHost"])
- return NO;
- if ((plugin_) && [name hasPrefix:@"PluginMsg"])
- return NO;
- if ((npObject_) && [name hasPrefix:@"NPObject"])
- return NO;
- if ((devTools_) && [name hasPrefix:@"DevTools"])
- return NO;
- if ((pluginProcessing_) && [name hasPrefix:@"PluginProcessing"])
- return NO;
- if ((userString1_) && ([name hasPrefix:[userStringTextField1_ stringValue]]))
- return NO;
- if ((userString2_) && ([name hasPrefix:[userStringTextField2_ stringValue]]))
- return NO;
- if ((userString3_) && ([name hasPrefix:[userStringTextField3_ stringValue]]))
- return NO;
-
- // Special case the unknown type.
- if ([name hasPrefix:@"type="])
- return NO;
-
- return YES; // filter out.
-}
-
-- (void)log:(CocoaLogData*)data {
- if ([self filterOut:data]) {
- [filteredEventCount_ setStringValue:[NSString stringWithFormat:@"%d",
- ++filteredEventCounter_]];
- return;
- }
- [dataController_ addObject:data];
- NSUInteger count = [[dataController_ arrangedObjects] count];
- // Uncomment if you want scroll-to-end behavior... but seems expensive.
- // [tableView_ scrollRowToVisible:count-1];
- [eventCount_ setStringValue:[NSString stringWithFormat:@"%d", count]];
-}
-
-- (void)setDisplayViewMessages:(BOOL)display {
- view_ = display;
-}
-
-@end
-
-#endif // IPC_MESSAGE_LOG_ENABLED
-
diff --git a/chrome/browser/cocoa/about_ipc_controller_unittest.mm b/chrome/browser/cocoa/about_ipc_controller_unittest.mm
deleted file mode 100644
index b36100a..0000000
--- a/chrome/browser/cocoa/about_ipc_controller_unittest.mm
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (c) 2009 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>
-
-#import "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/about_ipc_controller.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-#if defined(IPC_MESSAGE_LOG_ENABLED)
-
-namespace {
-
-class AboutIPCControllerTest : public CocoaTest {
-};
-
-TEST_F(AboutIPCControllerTest, TestFilter) {
- AboutIPCController* controller = [[AboutIPCController alloc] init];
- EXPECT_TRUE([controller window]); // force nib load.
- IPC::LogData data;
-
- // Make sure generic names do NOT get filtered.
- std::string names[] = { "PluginProcessingIsMyLife",
- "ViewMsgFoo",
- "NPObjectHell" };
- for (size_t i = 0; i < arraysize(names); i++) {
- data.message_name = names[i];
- scoped_nsobject<CocoaLogData> cdata([[CocoaLogData alloc]
- initWithLogData:data]);
- EXPECT_FALSE([controller filterOut:cdata.get()]);
- }
-
- // Flip a checkbox, see it filtered, flip back, all is fine.
- data.message_name = "ViewMsgFoo";
- scoped_nsobject<CocoaLogData> cdata([[CocoaLogData alloc]
- initWithLogData:data]);
- [controller setDisplayViewMessages:NO];
- EXPECT_TRUE([controller filterOut:cdata.get()]);
- [controller setDisplayViewMessages:YES];
- EXPECT_FALSE([controller filterOut:cdata.get()]);
- [controller close];
-}
-
-} // namespace
-
-#endif // IPC_MESSAGE_LOG_ENABLED
diff --git a/chrome/browser/cocoa/about_ipc_dialog.h b/chrome/browser/cocoa/about_ipc_dialog.h
deleted file mode 100644
index c819769..0000000
--- a/chrome/browser/cocoa/about_ipc_dialog.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_ABOUT_IPC_DIALOG_H_
-#define CHROME_BROWSER_COCOA_ABOUT_IPC_DIALOG_H_
-#pragma once
-
-#include "ipc/ipc_message.h"
-
-#if defined(IPC_MESSAGE_LOG_ENABLED)
-
-namespace AboutIPCDialog {
-// The dialog is a singleton. If the dialog is already opened, it won't do
-// anything, so you can just blindly call this function all you want.
-// RunDialog() is Called from chrome/browser/browser_about_handler.cc
-// in response to an about:ipc URL.
-void RunDialog();
-};
-
-
-#endif /* IPC_MESSAGE_LOG_ENABLED */
-
-#endif /* CHROME_BROWSER_COCOA_ABOUT_IPC_DIALOG_H_ */
diff --git a/chrome/browser/cocoa/about_ipc_dialog.mm b/chrome/browser/cocoa/about_ipc_dialog.mm
deleted file mode 100644
index d9b9448..0000000
--- a/chrome/browser/cocoa/about_ipc_dialog.mm
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/about_ipc_dialog.h"
-#include "chrome/browser/cocoa/about_ipc_controller.h"
-
-#if defined(IPC_MESSAGE_LOG_ENABLED)
-
-namespace AboutIPCDialog {
-
-void RunDialog() {
- // The controller gets deallocated when then window is closed,
- // so it is safe to "fire and forget".
- AboutIPCController* controller = [AboutIPCController sharedController];
- [[controller window] makeKeyAndOrderFront:controller];
-}
-
-}; // namespace AboutIPCDialog
-
-#endif // IPC_MESSAGE_LOG_ENABLED
diff --git a/chrome/browser/cocoa/about_window_controller.h b/chrome/browser/cocoa/about_window_controller.h
deleted file mode 100644
index 6578c46..0000000
--- a/chrome/browser/cocoa/about_window_controller.h
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_ABOUT_WINDOW_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_ABOUT_WINDOW_CONTROLLER_H_
-#pragma once
-
-#import <AppKit/AppKit.h>
-
-@class BackgroundTileView;
-class Profile;
-
-// This simple subclass of |NSTextView| just doesn't show the (text) cursor
-// (|NSTextView| displays the cursor with full keyboard accessibility enabled).
-@interface AboutLegalTextView : NSTextView
-@end
-
-// A window controller that handles the About box.
-@interface AboutWindowController : NSWindowController {
- @private
- IBOutlet NSTextField* version_;
- IBOutlet BackgroundTileView* backgroundView_;
- IBOutlet NSImageView* logoView_;
- IBOutlet NSView* legalBlock_;
- IBOutlet AboutLegalTextView* legalText_;
-
- // updateBlock_ holds the update image or throbber, update text, and update
- // button.
- IBOutlet NSView* updateBlock_;
-
- IBOutlet NSProgressIndicator* spinner_;
- IBOutlet NSImageView* updateStatusIndicator_;
- IBOutlet NSTextField* updateText_;
- IBOutlet NSButton* updateNowButton_;
- IBOutlet NSButton* promoteButton_;
-
- Profile* profile_; // Weak, probably the default profile.
-
- // The window frame height. During an animation, this will contain the
- // height being animated to.
- CGFloat windowHeight_;
-}
-
-// Initialize the controller with the given profile, but does not show it.
-// Callers still need to call showWindow: to put it on screen.
-- (id)initWithProfile:(Profile*)profile;
-
-// Trigger an update right now, as initiated by a button.
-- (IBAction)updateNow:(id)sender;
-
-// Install a system Keystone if necessary and promote the ticket to a system
-// ticket.
-- (IBAction)promoteUpdater:(id)sender;
-
-@end // @interface AboutWindowController
-
-@interface AboutWindowController(JustForTesting)
-
-- (NSTextView*)legalText;
-- (NSButton*)updateButton;
-- (NSTextField*)updateText;
-
-// Returns an NSAttributedString that contains locale-specific legal text.
-+ (NSAttributedString*)legalTextBlock;
-
-@end // @interface AboutWindowController(JustForTesting)
-
-#endif // CHROME_BROWSER_COCOA_ABOUT_WINDOW_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/about_window_controller.mm b/chrome/browser/cocoa/about_window_controller.mm
deleted file mode 100644
index ef33ef1..0000000
--- a/chrome/browser/cocoa/about_window_controller.mm
+++ /dev/null
@@ -1,761 +0,0 @@
-// 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 "chrome/browser/cocoa/about_window_controller.h"
-
-#include "app/l10n_util.h"
-#include "app/l10n_util_mac.h"
-#include "app/resource_bundle.h"
-#include "base/logging.h"
-#include "base/mac_util.h"
-#include "base/string_number_conversions.h"
-#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_window.h"
-#include "chrome/browser/platform_util.h"
-#import "chrome/browser/cocoa/background_tile_view.h"
-#import "chrome/browser/cocoa/keystone_glue.h"
-#include "chrome/browser/cocoa/restart_browser.h"
-#include "chrome/common/url_constants.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#include "grit/locale_settings.h"
-#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-
-namespace {
-
-void AttributedStringAppendString(NSMutableAttributedString* attr_str,
- NSString* str) {
- // You might think doing [[attr_str mutableString] appendString:str] would
- // work, but it causes any trailing style to get extened, meaning as we
- // append links, they grow to include the new text, not what we want.
- NSAttributedString* new_attr_str =
- [[[NSAttributedString alloc] initWithString:str] autorelease];
- [attr_str appendAttributedString:new_attr_str];
-}
-
-void AttributedStringAppendHyperlink(NSMutableAttributedString* attr_str,
- NSString* text, NSString* url_str) {
- // Figure out the range of the text we're adding and add the text.
- NSRange range = NSMakeRange([attr_str length], [text length]);
- AttributedStringAppendString(attr_str, text);
-
- // Add the link
- [attr_str addAttribute:NSLinkAttributeName value:url_str range:range];
-
- // Blue and underlined
- [attr_str addAttribute:NSForegroundColorAttributeName
- value:[NSColor blueColor]
- range:range];
- [attr_str addAttribute:NSUnderlineStyleAttributeName
- value:[NSNumber numberWithInt:NSSingleUnderlineStyle]
- range:range];
- [attr_str addAttribute:NSCursorAttributeName
- value:[NSCursor pointingHandCursor]
- range:range];
-}
-
-} // namespace
-
-@interface AboutWindowController(Private)
-
-// Launches a check for available updates.
-- (void)checkForUpdate;
-
-// Turns the update and promotion blocks on and off as needed based on whether
-// updates are possible and promotion is desired or required.
-- (void)adjustUpdateUIVisibility;
-
-// Maintains the update and promotion block visibility and window sizing.
-// This uses bool instead of BOOL for the convenience of the internal
-// implementation.
-- (void)setAllowsUpdate:(bool)update allowsPromotion:(bool)promotion;
-
-// Notification callback, called with the status of asynchronous
-// -checkForUpdate and -updateNow: operations.
-- (void)updateStatus:(NSNotification*)notification;
-
-// These methods maintain the image (or throbber) and text displayed regarding
-// update status. -setUpdateThrobberMessage: starts a progress throbber and
-// sets the text. -setUpdateImage:message: displays an image and sets the
-// text.
-- (void)setUpdateThrobberMessage:(NSString*)message;
-- (void)setUpdateImage:(int)imageID message:(NSString*)message;
-
-@end // @interface AboutWindowController(Private)
-
-@implementation AboutLegalTextView
-
-// Never draw the insertion point (otherwise, it shows up without any user
-// action if full keyboard accessibility is enabled).
-- (BOOL)shouldDrawInsertionPoint {
- return NO;
-}
-
-@end
-
-@implementation AboutWindowController
-
-- (id)initWithProfile:(Profile*)profile {
- NSString* nibPath = [mac_util::MainAppBundle() pathForResource:@"About"
- ofType:@"nib"];
- if ((self = [super initWithWindowNibPath:nibPath owner:self])) {
- profile_ = profile;
- NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
- [center addObserver:self
- selector:@selector(updateStatus:)
- name:kAutoupdateStatusNotification
- object:nil];
- }
- return self;
-}
-
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [super dealloc];
-}
-
-// YES when an About box is currently showing the kAutoupdateInstallFailed
-// status, or if no About box is visible, if the most recent About box to be
-// closed was closed while showing this status. When an About box opens, if
-// the recent status is kAutoupdateInstallFailed or kAutoupdatePromoteFailed
-// and recentShownUserActionFailedStatus is NO, the failure needs to be shown
-// instead of launching a new update check. recentShownInstallFailedStatus is
-// maintained by -updateStatus:.
-static BOOL recentShownUserActionFailedStatus = NO;
-
-- (void)awakeFromNib {
- NSBundle* bundle = mac_util::MainAppBundle();
- NSString* chromeVersion =
- [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
-
- NSString* versionModifier = @"";
- NSString* svnRevision = @"";
- std::string modifier = platform_util::GetVersionStringModifier();
- if (!modifier.empty())
- versionModifier = [NSString stringWithFormat:@" %@",
- base::SysUTF8ToNSString(modifier)];
-
-#if !defined(GOOGLE_CHROME_BUILD)
- svnRevision = [NSString stringWithFormat:@" (%@)",
- [bundle objectForInfoDictionaryKey:@"SVNRevision"]];
-#endif
- // The format string is not localized, but this is how the displayed version
- // is built on Windows too.
- NSString* version =
- [NSString stringWithFormat:@"%@%@%@",
- chromeVersion, svnRevision, versionModifier];
-
- [version_ setStringValue:version];
-
- // Put the two images into the UI.
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- NSImage* backgroundImage = rb.GetNativeImageNamed(IDR_ABOUT_BACKGROUND_COLOR);
- DCHECK(backgroundImage);
- [backgroundView_ setTileImage:backgroundImage];
- NSImage* logoImage = rb.GetNativeImageNamed(IDR_ABOUT_BACKGROUND);
- DCHECK(logoImage);
- [logoView_ setImage:logoImage];
-
- [[legalText_ textStorage] setAttributedString:[[self class] legalTextBlock]];
-
- // Resize our text view now so that the |updateShift| below is set
- // correctly. The About box has its controls manually positioned, so we need
- // to calculate how much larger (or smaller) our text box is and store that
- // difference in |legalShift|. We do something similar with |updateShift|
- // below, which is either 0, or the amount of space to offset the window size
- // because the view that contains the update button has been removed because
- // this build doesn't have Keystone.
- NSRect oldLegalRect = [legalBlock_ frame];
- [legalText_ sizeToFit];
- NSRect newRect = oldLegalRect;
- newRect.size.height = [legalText_ frame].size.height;
- [legalBlock_ setFrame:newRect];
- CGFloat legalShift = newRect.size.height - oldLegalRect.size.height;
-
- NSRect backgroundFrame = [backgroundView_ frame];
- backgroundFrame.origin.y += legalShift;
- [backgroundView_ setFrame:backgroundFrame];
-
- NSSize windowDelta = NSMakeSize(0.0, legalShift);
- [GTMUILocalizerAndLayoutTweaker
- resizeWindowWithoutAutoResizingSubViews:[self window]
- delta:windowDelta];
-
- windowHeight_ = [[self window] frame].size.height;
-
- [self adjustUpdateUIVisibility];
-
- // Don't do anything update-related if adjustUpdateUIVisibility decided that
- // updates aren't possible.
- if (![updateBlock_ isHidden]) {
- KeystoneGlue* keystoneGlue = [KeystoneGlue defaultKeystoneGlue];
- AutoupdateStatus recentStatus = [keystoneGlue recentStatus];
- if ([keystoneGlue asyncOperationPending] ||
- recentStatus == kAutoupdateRegisterFailed ||
- ((recentStatus == kAutoupdateInstallFailed ||
- recentStatus == kAutoupdatePromoteFailed) &&
- !recentShownUserActionFailedStatus)) {
- // If an asynchronous update operation is currently pending, such as a
- // check for updates or an update installation attempt, set the status
- // up correspondingly without launching a new update check.
- //
- // If registration failed, no other operations make sense, so just go
- // straight to the error.
- //
- // If a previous update or promotion attempt was unsuccessful but no
- // About box was around to report the error, show it now, and allow
- // another chance to perform the action.
- [self updateStatus:[keystoneGlue recentNotification]];
- } else {
- // Launch a new update check, even if one was already completed, because
- // a new update may be available or a new update may have been installed
- // in the background since the last time an About box was displayed.
- [self checkForUpdate];
- }
- }
-
- [[self window] center];
-}
-
-- (void)windowWillClose:(NSNotification*)notification {
- [self autorelease];
-}
-
-- (void)adjustUpdateUIVisibility {
- bool allowUpdate;
- bool allowPromotion;
-
- KeystoneGlue* keystoneGlue = [KeystoneGlue defaultKeystoneGlue];
- if (keystoneGlue && ![keystoneGlue isOnReadOnlyFilesystem]) {
- AutoupdateStatus recentStatus = [keystoneGlue recentStatus];
- if (recentStatus == kAutoupdateRegistering ||
- recentStatus == kAutoupdateRegisterFailed ||
- recentStatus == kAutoupdatePromoted) {
- // Show the update block while registering so that there's a progress
- // spinner, and if registration failed so that there's an error message.
- // Show it following a promotion because updates should be possible
- // after promotion successfully completes.
- allowUpdate = true;
-
- // Promotion isn't possible at this point.
- allowPromotion = false;
- } else if (recentStatus == kAutoupdatePromoteFailed) {
- // TODO(mark): Add kAutoupdatePromoting to this block. KSRegistration
- // currently handles the promotion synchronously, meaning that the main
- // thread's loop doesn't spin, meaning that animations and other updates
- // to the window won't occur until KSRegistration is done with
- // promotion. This looks laggy and bad and probably qualifies as
- // "jank." For now, there just won't be any visual feedback while
- // promotion is in progress, but it should complete (or fail) very
- // quickly. http://b/2290009.
- //
- // Also see the TODO for kAutoupdatePromoting in -updateStatus:version:.
- //
- // Show the update block so that there's some visual feedback that
- // promotion is under way or that it's failed. Show the promotion block
- // because the user either just clicked that button or because the user
- // should be able to click it again.
- allowUpdate = true;
- allowPromotion = true;
- } else {
- // Show the update block only if a promotion is not absolutely required.
- allowUpdate = ![keystoneGlue needsPromotion];
-
- // Show the promotion block if promotion is a possibility.
- allowPromotion = [keystoneGlue wantsPromotion];
- }
- } else {
- // There is no glue, or the application is on a read-only filesystem.
- // Updates and promotions are impossible.
- allowUpdate = false;
- allowPromotion = false;
- }
-
- [self setAllowsUpdate:allowUpdate allowsPromotion:allowPromotion];
-}
-
-- (void)setAllowsUpdate:(bool)update allowsPromotion:(bool)promotion {
- bool oldUpdate = ![updateBlock_ isHidden];
- bool oldPromotion = ![promoteButton_ isHidden];
-
- if (promotion == oldPromotion && update == oldUpdate) {
- return;
- }
-
- NSRect updateFrame = [updateBlock_ frame];
- CGFloat delta = 0.0;
-
- if (update != oldUpdate) {
- [updateBlock_ setHidden:!update];
- delta += (update ? 1.0 : -1.0) * NSHeight(updateFrame);
- }
-
- if (promotion != oldPromotion) {
- [promoteButton_ setHidden:!promotion];
- }
-
- NSRect legalFrame = [legalBlock_ frame];
-
- if (delta) {
- updateFrame.origin.y += delta;
- [updateBlock_ setFrame:updateFrame];
-
- legalFrame.origin.y += delta;
- [legalBlock_ setFrame:legalFrame];
-
- NSRect backgroundFrame = [backgroundView_ frame];
- backgroundFrame.origin.y += delta;
- [backgroundView_ setFrame:backgroundFrame];
-
- // GTMUILocalizerAndLayoutTweaker resizes the window without any
- // opportunity for animation. In order to animate, disable window
- // updates, save the current frame, let GTMUILocalizerAndLayoutTweaker do
- // its thing, save the desired frame, restore the original frame, and then
- // animate.
- NSWindow* window = [self window];
- [window disableScreenUpdatesUntilFlush];
-
- NSRect oldFrame = [window frame];
-
- // GTMUILocalizerAndLayoutTweaker applies its delta to the window's
- // current size (like oldFrame.size), but oldFrame isn't trustworthy if
- // an animation is in progress. Set the window's frame to
- // intermediateFrame, which is a frame of the size that an existing
- // animation is animating to, so that GTM can apply the delta to the right
- // size.
- NSRect intermediateFrame = oldFrame;
- intermediateFrame.origin.y -= intermediateFrame.size.height - windowHeight_;
- intermediateFrame.size.height = windowHeight_;
- [window setFrame:intermediateFrame display:NO];
-
- NSSize windowDelta = NSMakeSize(0.0, delta);
- [GTMUILocalizerAndLayoutTweaker
- resizeWindowWithoutAutoResizingSubViews:window
- delta:windowDelta];
- [window setFrameTopLeftPoint:NSMakePoint(NSMinX(intermediateFrame),
- NSMaxY(intermediateFrame))];
- NSRect newFrame = [window frame];
-
- windowHeight_ += delta;
-
- if (![[self window] isVisible]) {
- // Don't animate if the window isn't on screen yet.
- [window setFrame:newFrame display:NO];
- } else {
- [window setFrame:oldFrame display:NO];
- [window setFrame:newFrame display:YES animate:YES];
- }
- }
-}
-
-- (void)setUpdateThrobberMessage:(NSString*)message {
- [updateStatusIndicator_ setHidden:YES];
-
- [spinner_ setHidden:NO];
- [spinner_ startAnimation:self];
-
- [updateText_ setStringValue:message];
-}
-
-- (void)setUpdateImage:(int)imageID message:(NSString*)message {
- [spinner_ stopAnimation:self];
- [spinner_ setHidden:YES];
-
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- NSImage* statusImage = rb.GetNativeImageNamed(imageID);
- DCHECK(statusImage);
- [updateStatusIndicator_ setImage:statusImage];
- [updateStatusIndicator_ setHidden:NO];
-
- [updateText_ setStringValue:message];
-}
-
-- (void)checkForUpdate {
- [[KeystoneGlue defaultKeystoneGlue] checkForUpdate];
-
- // Immediately, kAutoupdateStatusNotification will be posted, and
- // -updateStatus: will be called with status kAutoupdateChecking.
- //
- // Upon completion, kAutoupdateStatusNotification will be posted, and
- // -updateStatus: will be called with a status indicating the result of the
- // check.
-}
-
-- (IBAction)updateNow:(id)sender {
- [[KeystoneGlue defaultKeystoneGlue] installUpdate];
-
- // Immediately, kAutoupdateStatusNotification will be posted, and
- // -updateStatus: will be called with status kAutoupdateInstalling.
- //
- // Upon completion, kAutoupdateStatusNotification will be posted, and
- // -updateStatus: will be called with a status indicating the result of the
- // installation attempt.
-}
-
-- (IBAction)promoteUpdater:(id)sender {
- [[KeystoneGlue defaultKeystoneGlue] promoteTicket];
-
- // Immediately, kAutoupdateStatusNotification will be posted, and
- // -updateStatus: will be called with status kAutoupdatePromoting.
- //
- // Upon completion, kAutoupdateStatusNotification will be posted, and
- // -updateStatus: will be called with a status indicating a result of the
- // installation attempt.
- //
- // If the promotion was successful, KeystoneGlue will re-register the ticket
- // and -updateStatus: will be called again indicating first that
- // registration is in progress and subsequently that it has completed.
-}
-
-- (void)updateStatus:(NSNotification*)notification {
- recentShownUserActionFailedStatus = NO;
-
- NSDictionary* dictionary = [notification userInfo];
- AutoupdateStatus status = static_cast<AutoupdateStatus>(
- [[dictionary objectForKey:kAutoupdateStatusStatus] intValue]);
-
- // Don't assume |version| is a real string. It may be nil.
- NSString* version = [dictionary objectForKey:kAutoupdateStatusVersion];
-
- bool updateMessage = true;
- bool throbber = false;
- int imageID = 0;
- NSString* message;
- bool enableUpdateButton = false;
- bool enablePromoteButton = true;
-
- switch (status) {
- case kAutoupdateRegistering:
- // When registering, use the "checking" message. The check will be
- // launched if appropriate immediately after registration.
- throbber = true;
- message = l10n_util::GetNSStringWithFixup(IDS_UPGRADE_CHECK_STARTED);
- enablePromoteButton = false;
-
- break;
-
- case kAutoupdateRegistered:
- // Once registered, the ability to update and promote is known.
- [self adjustUpdateUIVisibility];
-
- if (![updateBlock_ isHidden]) {
- // If registration completes while the window is visible, go straight
- // into an update check. Return immediately, this routine will be
- // re-entered shortly with kAutoupdateChecking.
- [self checkForUpdate];
- return;
- }
-
- // Nothing actually failed, but updates aren't possible. The throbber
- // and message are hidden, but they'll be reset to these dummy values
- // just to get the throbber to stop spinning if it's running.
- imageID = IDR_UPDATE_FAIL;
- message = l10n_util::GetNSStringFWithFixup(IDS_UPGRADE_ERROR,
- base::IntToString16(status));
-
- break;
-
- case kAutoupdateChecking:
- throbber = true;
- message = l10n_util::GetNSStringWithFixup(IDS_UPGRADE_CHECK_STARTED);
- enablePromoteButton = false;
-
- break;
-
- case kAutoupdateCurrent:
- imageID = IDR_UPDATE_UPTODATE;
- message = l10n_util::GetNSStringFWithFixup(
- IDS_UPGRADE_ALREADY_UP_TO_DATE,
- l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
- base::SysNSStringToUTF16(version));
-
- break;
-
- case kAutoupdateAvailable:
- imageID = IDR_UPDATE_AVAILABLE;
- message = l10n_util::GetNSStringFWithFixup(
- IDS_UPGRADE_AVAILABLE, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
- enableUpdateButton = true;
-
- break;
-
- case kAutoupdateInstalling:
- throbber = true;
- message = l10n_util::GetNSStringWithFixup(IDS_UPGRADE_STARTED);
- enablePromoteButton = false;
-
- break;
-
- case kAutoupdateInstalled:
- {
- imageID = IDR_UPDATE_UPTODATE;
- string16 productName = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
- if (version) {
- message = l10n_util::GetNSStringFWithFixup(
- IDS_UPGRADE_SUCCESSFUL,
- productName,
- base::SysNSStringToUTF16(version));
- } else {
- message = l10n_util::GetNSStringFWithFixup(
- IDS_UPGRADE_SUCCESSFUL_NOVERSION, productName);
- }
-
- // TODO(mark): Turn the button in the dialog into a restart button
- // instead of springing this sheet or dialog.
- NSWindow* window = [self window];
- NSWindow* restartDialogParent = [window isVisible] ? window : nil;
- restart_browser::RequestRestart(restartDialogParent);
- }
-
- break;
-
- case kAutoupdatePromoting:
-#if 1
- // TODO(mark): See the TODO in -adjustUpdateUIVisibility for an
- // explanation of why nothing can be done here at the moment. When
- // KSRegistration handles promotion asynchronously, this dummy block can
- // be replaced with the #else block. For now, just leave the messaging
- // alone. http://b/2290009.
- updateMessage = false;
-#else
- // The visibility may be changing.
- [self adjustUpdateUIVisibility];
-
- // This is not a terminal state, and kAutoupdatePromoted or
- // kAutoupdatePromoteFailed will follow. Use the throbber and
- // "checking" message so that it looks like something's happening.
- throbber = true;
- message = l10n_util::GetNSStringWithFixup(IDS_UPGRADE_CHECK_STARTED);
-#endif
-
- enablePromoteButton = false;
-
- break;
-
- case kAutoupdatePromoted:
- // The visibility may be changing.
- [self adjustUpdateUIVisibility];
-
- if (![updateBlock_ isHidden]) {
- // If promotion completes while the window is visible, go straight
- // into an update check. Return immediately, this routine will be
- // re-entered shortly with kAutoupdateChecking.
- [self checkForUpdate];
- return;
- }
-
- // Nothing actually failed, but updates aren't possible. The throbber
- // and message are hidden, but they'll be reset to these dummy values
- // just to get the throbber to stop spinning if it's running.
- imageID = IDR_UPDATE_FAIL;
- message = l10n_util::GetNSStringFWithFixup(IDS_UPGRADE_ERROR,
- base::IntToString16(status));
-
- break;
-
- case kAutoupdateRegisterFailed:
- imageID = IDR_UPDATE_FAIL;
- message = l10n_util::GetNSStringFWithFixup(IDS_UPGRADE_ERROR,
- base::IntToString16(status));
- enablePromoteButton = false;
-
- break;
-
- case kAutoupdateCheckFailed:
- imageID = IDR_UPDATE_FAIL;
- message = l10n_util::GetNSStringFWithFixup(IDS_UPGRADE_ERROR,
- base::IntToString16(status));
-
- break;
-
- case kAutoupdateInstallFailed:
- recentShownUserActionFailedStatus = YES;
-
- imageID = IDR_UPDATE_FAIL;
- message = l10n_util::GetNSStringFWithFixup(IDS_UPGRADE_ERROR,
- base::IntToString16(status));
-
- // Allow another chance.
- enableUpdateButton = true;
-
- break;
-
- case kAutoupdatePromoteFailed:
- recentShownUserActionFailedStatus = YES;
-
- imageID = IDR_UPDATE_FAIL;
- message = l10n_util::GetNSStringFWithFixup(IDS_UPGRADE_ERROR,
- base::IntToString16(status));
-
- break;
-
- default:
- NOTREACHED();
-
- return;
- }
-
- if (updateMessage) {
- if (throbber) {
- [self setUpdateThrobberMessage:message];
- } else {
- DCHECK_NE(imageID, 0);
- [self setUpdateImage:imageID message:message];
- }
- }
-
- // Note that these buttons may be hidden depending on what
- // -adjustUpdateUIVisibility did. Their enabled/disabled status doesn't
- // necessarily have anything to do with their visibility.
- [updateNowButton_ setEnabled:enableUpdateButton];
- [promoteButton_ setEnabled:enablePromoteButton];
-}
-
-- (BOOL)textView:(NSTextView *)aTextView
- clickedOnLink:(id)link
- atIndex:(NSUInteger)charIndex {
- // We always create a new window, so there's no need to try to re-use
- // an existing one just to pass in the NEW_WINDOW disposition.
- Browser* browser = Browser::Create(profile_);
- browser->OpenURL(GURL([link UTF8String]), GURL(), NEW_FOREGROUND_TAB,
- PageTransition::LINK);
- browser->window()->Show();
- return YES;
-}
-
-- (NSTextView*)legalText {
- return legalText_;
-}
-
-- (NSButton*)updateButton {
- return updateNowButton_;
-}
-
-- (NSTextField*)updateText {
- return updateText_;
-}
-
-+ (NSAttributedString*)legalTextBlock {
- // Windows builds this up in a very complex way, we're just trying to model
- // it the best we can to get all the information in (they actually do it
- // but created Labels and Links that they carefully place to make it appear
- // to be a paragraph of text).
- // src/chrome/browser/views/about_chrome_view.cc AboutChromeView::Init()
-
- NSMutableAttributedString* legal_block =
- [[[NSMutableAttributedString alloc] init] autorelease];
- [legal_block beginEditing];
-
- NSString* copyright =
- l10n_util::GetNSStringWithFixup(IDS_ABOUT_VERSION_COPYRIGHT);
- AttributedStringAppendString(legal_block, copyright);
-
- // These are the markers directly in IDS_ABOUT_VERSION_LICENSE
- NSString* kBeginLinkChr = @"BEGIN_LINK_CHR";
- NSString* kBeginLinkOss = @"BEGIN_LINK_OSS";
- NSString* kEndLinkChr = @"END_LINK_CHR";
- NSString* kEndLinkOss = @"END_LINK_OSS";
- // The CHR link should go to here
- NSString* kChromiumProject = l10n_util::GetNSString(IDS_CHROMIUM_PROJECT_URL);
- // The OSS link should go to here
- NSString* kAcknowledgements =
- [NSString stringWithUTF8String:chrome::kAboutCreditsURL];
-
- // Now fetch the license string and deal with the markers
-
- NSString* license =
- l10n_util::GetNSStringWithFixup(IDS_ABOUT_VERSION_LICENSE);
-
- NSRange begin_chr = [license rangeOfString:kBeginLinkChr];
- NSRange begin_oss = [license rangeOfString:kBeginLinkOss];
- NSRange end_chr = [license rangeOfString:kEndLinkChr];
- NSRange end_oss = [license rangeOfString:kEndLinkOss];
- DCHECK_NE(begin_chr.location, NSNotFound);
- DCHECK_NE(begin_oss.location, NSNotFound);
- DCHECK_NE(end_chr.location, NSNotFound);
- DCHECK_NE(end_oss.location, NSNotFound);
-
- // We don't know which link will come first, so we have to deal with things
- // like this:
- // [text][begin][text][end][text][start][text][end][text]
-
- bool chromium_link_first = begin_chr.location < begin_oss.location;
-
- NSRange* begin1 = &begin_chr;
- NSRange* begin2 = &begin_oss;
- NSRange* end1 = &end_chr;
- NSRange* end2 = &end_oss;
- NSString* link1 = kChromiumProject;
- NSString* link2 = kAcknowledgements;
- if (!chromium_link_first) {
- // OSS came first, switch!
- begin2 = &begin_chr;
- begin1 = &begin_oss;
- end2 = &end_chr;
- end1 = &end_oss;
- link2 = kChromiumProject;
- link1 = kAcknowledgements;
- }
-
- NSString *sub_str;
-
- AttributedStringAppendString(legal_block, @"\n");
- sub_str = [license substringWithRange:NSMakeRange(0, begin1->location)];
- AttributedStringAppendString(legal_block, sub_str);
- sub_str = [license substringWithRange:NSMakeRange(NSMaxRange(*begin1),
- end1->location -
- NSMaxRange(*begin1))];
- AttributedStringAppendHyperlink(legal_block, sub_str, link1);
- sub_str = [license substringWithRange:NSMakeRange(NSMaxRange(*end1),
- begin2->location -
- NSMaxRange(*end1))];
- AttributedStringAppendString(legal_block, sub_str);
- sub_str = [license substringWithRange:NSMakeRange(NSMaxRange(*begin2),
- end2->location -
- NSMaxRange(*begin2))];
- AttributedStringAppendHyperlink(legal_block, sub_str, link2);
- sub_str = [license substringWithRange:NSMakeRange(NSMaxRange(*end2),
- [license length] -
- NSMaxRange(*end2))];
- AttributedStringAppendString(legal_block, sub_str);
-
-#if defined(GOOGLE_CHROME_BUILD)
- // Terms of service is only valid for Google Chrome
-
- // The url within terms should point here:
- NSString* kTOS = [NSString stringWithUTF8String:chrome::kAboutTermsURL];
- // Following Windows. There is one marker in the string for where the terms
- // link goes, but the text of the link comes from a second string resources.
- std::vector<size_t> url_offsets;
- NSString* about_terms = l10n_util::GetNSStringF(IDS_ABOUT_TERMS_OF_SERVICE,
- string16(),
- string16(),
- &url_offsets);
- DCHECK_EQ(url_offsets.size(), 1U);
- NSString* terms_link_text =
- l10n_util::GetNSStringWithFixup(IDS_TERMS_OF_SERVICE);
-
- AttributedStringAppendString(legal_block, @"\n\n");
- sub_str = [about_terms substringToIndex:url_offsets[0]];
- AttributedStringAppendString(legal_block, sub_str);
- AttributedStringAppendHyperlink(legal_block, terms_link_text, kTOS);
- sub_str = [about_terms substringFromIndex:url_offsets[0]];
- AttributedStringAppendString(legal_block, sub_str);
-#endif // GOOGLE_CHROME_BUILD
-
- // We need to explicitly select Lucida Grande because once we click on
- // the NSTextView, it changes to Helvetica 12 otherwise.
- NSRange string_range = NSMakeRange(0, [legal_block length]);
- [legal_block addAttribute:NSFontAttributeName
- value:[NSFont labelFontOfSize:11]
- range:string_range];
-
- [legal_block endEditing];
- return legal_block;
-}
-
-@end // @implementation AboutWindowController
diff --git a/chrome/browser/cocoa/about_window_controller_unittest.mm b/chrome/browser/cocoa/about_window_controller_unittest.mm
deleted file mode 100644
index 3538dda..0000000
--- a/chrome/browser/cocoa/about_window_controller_unittest.mm
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright (c) 2009 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>
-
-#import "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/about_window_controller.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/keystone_glue.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-namespace {
-
-void PostAutoupdateStatusNotification(AutoupdateStatus status,
- NSString* version) {
- NSNumber* statusNumber = [NSNumber numberWithInt:status];
- NSMutableDictionary* dictionary =
- [NSMutableDictionary dictionaryWithObjects:&statusNumber
- forKeys:&kAutoupdateStatusStatus
- count:1];
- if (version) {
- [dictionary setObject:version forKey:kAutoupdateStatusVersion];
- }
-
- NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
- [center postNotificationName:kAutoupdateStatusNotification
- object:nil
- userInfo:dictionary];
-}
-
-class AboutWindowControllerTest : public CocoaTest {
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
- about_window_controller_ =
- [[AboutWindowController alloc] initWithProfile:nil];
- EXPECT_TRUE([about_window_controller_ window]);
- }
-
- virtual void TearDown() {
- [about_window_controller_ close];
- CocoaTest::TearDown();
- }
-
- AboutWindowController* about_window_controller_;
-};
-
-TEST_F(AboutWindowControllerTest, TestCopyright) {
- NSString* text = [[AboutWindowController legalTextBlock] string];
-
- // Make sure we have the word "Copyright" in it, which is present in all
- // locales.
- NSRange range = [text rangeOfString:@"Copyright"];
- EXPECT_NE(NSNotFound, range.location);
-}
-
-TEST_F(AboutWindowControllerTest, RemovesLinkAnchors) {
- NSString* text = [[AboutWindowController legalTextBlock] string];
-
- // Make sure that we removed the "BEGIN_LINK" and "END_LINK" anchors.
- NSRange range = [text rangeOfString:@"BEGIN_LINK"];
- EXPECT_EQ(NSNotFound, range.location);
-
- range = [text rangeOfString:@"END_LINK"];
- EXPECT_EQ(NSNotFound, range.location);
-}
-
-TEST_F(AboutWindowControllerTest, AwakeNibSetsString) {
- NSAttributedString* legal_text = [AboutWindowController legalTextBlock];
- NSAttributedString* text_storage =
- [[about_window_controller_ legalText] textStorage];
-
- EXPECT_TRUE([legal_text isEqualToAttributedString:text_storage]);
-}
-
-TEST_F(AboutWindowControllerTest, TestButton) {
- NSButton* button = [about_window_controller_ updateButton];
- ASSERT_TRUE(button);
-
- // Not enabled until we know if updates are available.
- ASSERT_FALSE([button isEnabled]);
- PostAutoupdateStatusNotification(kAutoupdateAvailable, nil);
- ASSERT_TRUE([button isEnabled]);
-
- // Make sure the button is hooked up
- ASSERT_EQ([button target], about_window_controller_);
- ASSERT_EQ([button action], @selector(updateNow:));
-}
-
-// Doesn't confirm correctness, but does confirm something happens.
-TEST_F(AboutWindowControllerTest, TestCallbacks) {
- NSString *lastText = [[about_window_controller_ updateText]
- stringValue];
- PostAutoupdateStatusNotification(kAutoupdateCurrent, @"foo");
- ASSERT_NSNE(lastText, [[about_window_controller_ updateText] stringValue]);
-
- lastText = [[about_window_controller_ updateText] stringValue];
- PostAutoupdateStatusNotification(kAutoupdateCurrent, @"foo");
- ASSERT_NSEQ(lastText, [[about_window_controller_ updateText] stringValue]);
-
- lastText = [[about_window_controller_ updateText] stringValue];
- PostAutoupdateStatusNotification(kAutoupdateCurrent, @"bar");
- ASSERT_NSNE(lastText, [[about_window_controller_ updateText] stringValue]);
-
- lastText = [[about_window_controller_ updateText] stringValue];
- PostAutoupdateStatusNotification(kAutoupdateAvailable, nil);
- ASSERT_NSNE(lastText, [[about_window_controller_ updateText] stringValue]);
-
- lastText = [[about_window_controller_ updateText] stringValue];
- PostAutoupdateStatusNotification(kAutoupdateCheckFailed, nil);
- ASSERT_NSNE(lastText, [[about_window_controller_ updateText] stringValue]);
-
-#if 0
- // TODO(mark): The kAutoupdateInstalled portion of the test is disabled
- // because it leaks restart dialogs. If the About box is revised to use
- // a button within the box to advise a restart instead of popping dialogs,
- // these tests should be enabled.
-
- lastText = [[about_window_controller_ updateText] stringValue];
- PostAutoupdateStatusNotification(kAutoupdateInstalled, @"ver");
- ASSERT_NSNE(lastText, [[about_window_controller_ updateText] stringValue]);
-
- lastText = [[about_window_controller_ updateText] stringValue];
- PostAutoupdateStatusNotification(kAutoupdateInstalled, nil);
- ASSERT_NSNE(lastText, [[about_window_controller_ updateText] stringValue]);
-#endif
-
- lastText = [[about_window_controller_ updateText] stringValue];
- PostAutoupdateStatusNotification(kAutoupdateInstallFailed, nil);
- ASSERT_NSNE(lastText, [[about_window_controller_ updateText] stringValue]);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/accelerators_cocoa.h b/chrome/browser/cocoa/accelerators_cocoa.h
deleted file mode 100644
index e43c550..0000000
--- a/chrome/browser/cocoa/accelerators_cocoa.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_ACCELERATORS_COCOA_H_
-#define CHROME_BROWSER_COCOA_ACCELERATORS_COCOA_H_
-#pragma once
-
-#include <map>
-
-#include "app/menus/accelerator_cocoa.h"
-
-// This class maintains a map of command_ids to AcceleratorCocoa objects (see
-// chrome/app/chrome_command_ids.h). Currently, this only lists the commands
-// that are used in the Wrench menu.
-//
-// It is recommended that this class be used as a singleton so that the key map
-// isn't created multiple places.
-//
-// #import "base/singleton.h"
-// ...
-// AcceleratorsCocoa* keymap = Singleton<AcceleratorsCocoa>::get();
-// return keymap->GetAcceleratorForCommand(IDC_COPY);
-//
-class AcceleratorsCocoa {
- public:
- AcceleratorsCocoa();
- ~AcceleratorsCocoa() {}
-
- typedef std::map<int, menus::AcceleratorCocoa> AcceleratorCocoaMap;
-
- // Returns NULL if there is no accelerator for the command.
- const menus::AcceleratorCocoa* GetAcceleratorForCommand(int command_id);
-
- private:
- AcceleratorCocoaMap accelerators_;
-
- DISALLOW_COPY_AND_ASSIGN(AcceleratorsCocoa);
-};
-
-#endif // CHROME_BROWSER_COCOA_ACCELERATORS_COCOA_H_
diff --git a/chrome/browser/cocoa/accelerators_cocoa.mm b/chrome/browser/cocoa/accelerators_cocoa.mm
deleted file mode 100644
index 4b1eb5d..0000000
--- a/chrome/browser/cocoa/accelerators_cocoa.mm
+++ /dev/null
@@ -1,57 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/accelerators_cocoa.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include "chrome/app/chrome_command_ids.h"
-
-namespace {
-
-const struct AcceleratorMapping {
- int command_id;
- NSString* key;
- NSUInteger modifiers;
-} kAcceleratorMap[] = {
- { IDC_CLEAR_BROWSING_DATA, @"\x8", NSCommandKeyMask | NSShiftKeyMask },
- { IDC_COPY, @"c", NSCommandKeyMask },
- { IDC_CUT, @"x", NSCommandKeyMask },
- { IDC_DEV_TOOLS, @"i", NSCommandKeyMask | NSAlternateKeyMask },
- { IDC_DEV_TOOLS_CONSOLE, @"j", NSCommandKeyMask | NSAlternateKeyMask },
- { IDC_FIND, @"f", NSCommandKeyMask },
- { IDC_FULLSCREEN, @"f", NSCommandKeyMask | NSShiftKeyMask },
- { IDC_NEW_INCOGNITO_WINDOW, @"n", NSCommandKeyMask | NSShiftKeyMask },
- { IDC_NEW_TAB, @"t", NSCommandKeyMask },
- { IDC_NEW_WINDOW, @"n", NSCommandKeyMask },
- { IDC_OPTIONS, @",", NSCommandKeyMask },
- { IDC_PASTE, @"v", NSCommandKeyMask },
- { IDC_PRINT, @"p", NSCommandKeyMask },
- { IDC_SAVE_PAGE, @"s", NSCommandKeyMask },
- { IDC_SHOW_BOOKMARK_BAR, @"b", NSCommandKeyMask | NSShiftKeyMask },
- { IDC_SHOW_BOOKMARK_MANAGER, @"b", NSCommandKeyMask | NSAlternateKeyMask },
- { IDC_SHOW_DOWNLOADS, @"j", NSCommandKeyMask | NSShiftKeyMask },
- { IDC_SHOW_HISTORY, @"y", NSCommandKeyMask },
- { IDC_VIEW_SOURCE, @"u", NSCommandKeyMask | NSAlternateKeyMask },
- { IDC_ZOOM_MINUS, @"-", NSCommandKeyMask },
- { IDC_ZOOM_PLUS, @"+", NSCommandKeyMask }
-};
-
-} // namespace
-
-AcceleratorsCocoa::AcceleratorsCocoa() {
- for (size_t i = 0; i < arraysize(kAcceleratorMap); ++i) {
- const AcceleratorMapping& entry = kAcceleratorMap[i];
- menus::AcceleratorCocoa accelerator(entry.key, entry.modifiers);
- accelerators_.insert(std::make_pair(entry.command_id, accelerator));
- }
-}
-
-const menus::AcceleratorCocoa* AcceleratorsCocoa::GetAcceleratorForCommand(
- int command_id) {
- AcceleratorCocoaMap::iterator it = accelerators_.find(command_id);
- if (it == accelerators_.end())
- return NULL;
- return &it->second;
-}
diff --git a/chrome/browser/cocoa/accelerators_cocoa_unittest.mm b/chrome/browser/cocoa/accelerators_cocoa_unittest.mm
deleted file mode 100644
index 3f0e307..0000000
--- a/chrome/browser/cocoa/accelerators_cocoa_unittest.mm
+++ /dev/null
@@ -1,28 +0,0 @@
-// 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 "app/menus/accelerator_cocoa.h"
-#include "base/singleton.h"
-#include "chrome/app/chrome_command_ids.h"
-#import "chrome/browser/cocoa/accelerators_cocoa.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/gtest_mac.h"
-
-TEST(AcceleratorsCocoaTest, GetAccelerator) {
- AcceleratorsCocoa* keymap = Singleton<AcceleratorsCocoa>::get();
- const menus::AcceleratorCocoa* accelerator =
- keymap->GetAcceleratorForCommand(IDC_COPY);
- ASSERT_TRUE(accelerator);
- EXPECT_NSEQ(@"c", accelerator->characters());
- EXPECT_EQ(static_cast<int>(NSCommandKeyMask), accelerator->modifiers());
-}
-
-TEST(AcceleratorsCocoaTest, GetNullAccelerator) {
- AcceleratorsCocoa* keymap = Singleton<AcceleratorsCocoa>::get();
- const menus::AcceleratorCocoa* accelerator =
- keymap->GetAcceleratorForCommand(314159265);
- EXPECT_FALSE(accelerator);
-}
diff --git a/chrome/browser/cocoa/animatable_image.h b/chrome/browser/cocoa/animatable_image.h
deleted file mode 100644
index d61187d..0000000
--- a/chrome/browser/cocoa/animatable_image.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_ANIMATABLE_IMAGE_H_
-#define CHROME_BROWSER_COCOA_ANIMATABLE_IMAGE_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-#import <QuartzCore/QuartzCore.h>
-
-#include "base/scoped_nsobject.h"
-
-// This class helps animate an NSImage's frame and opacity. It works by creating
-// a blank NSWindow in the size specified and giving it a layer on which the
-// image can be animated. Clients are free to embed this object as a child
-// window for easier window management. This class will clean itself up when
-// the animation has finished. Clients that install this as a child window
-// should listen for the NSWindowWillCloseNotification to perform any additional
-// cleanup.
-@interface AnimatableImage : NSWindow {
- @private
- // The image to animate.
- scoped_nsobject<NSImage> image_;
-
- // The frame of the image before and after the animation. This is in this
- // window's coordinate system.
- CGRect startFrame_;
- CGRect endFrame_;
-
- // Opacity values for the animation.
- CGFloat startOpacity_;
- CGFloat endOpacity_;
-
- // The amount of time it takes to animate the image.
- CGFloat duration_;
-}
-
-@property (nonatomic) CGRect startFrame;
-@property (nonatomic) CGRect endFrame;
-@property (nonatomic) CGFloat startOpacity;
-@property (nonatomic) CGFloat endOpacity;
-@property (nonatomic) CGFloat duration;
-
-// Designated initializer. Do not use any other NSWindow initializers. Creates
-// but does not show the blank animation window of the given size. The
-// |animationFrame| should usually be big enough to contain the |startFrame|
-// and |endFrame| properties of the animation.
-- (id)initWithImage:(NSImage*)image
- animationFrame:(NSRect)animationFrame;
-
-// Begins the animation.
-- (void)startAnimation;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_ANIMATABLE_IMAGE_H_
diff --git a/chrome/browser/cocoa/animatable_image.mm b/chrome/browser/cocoa/animatable_image.mm
deleted file mode 100644
index 2169843..0000000
--- a/chrome/browser/cocoa/animatable_image.mm
+++ /dev/null
@@ -1,145 +0,0 @@
-// 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 "chrome/browser/cocoa/animatable_image.h"
-
-#include "base/logging.h"
-#import "base/mac_util.h"
-#include "base/mac/scoped_cftyperef.h"
-#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
-
-@interface AnimatableImage (Private)
-- (void)setLayerContents:(CALayer*)layer;
-@end
-
-@implementation AnimatableImage
-
-@synthesize startFrame = startFrame_;
-@synthesize endFrame = endFrame_;
-@synthesize startOpacity = startOpacity_;
-@synthesize endOpacity = endOpacity_;
-@synthesize duration = duration_;
-
-- (id)initWithImage:(NSImage*)image
- animationFrame:(NSRect)animationFrame {
- if ((self = [super initWithContentRect:animationFrame
- styleMask:NSBorderlessWindowMask
- backing:NSBackingStoreBuffered
- defer:NO])) {
- DCHECK(image);
- image_.reset([image retain]);
- duration_ = 1.0;
- startOpacity_ = 1.0;
- endOpacity_ = 1.0;
-
- [self setOpaque:NO];
- [self setBackgroundColor:[NSColor clearColor]];
- [self setIgnoresMouseEvents:YES];
-
- // Must be set or else self will be leaked.
- [self setReleasedWhenClosed:YES];
- }
- return self;
-}
-
-- (void)startAnimation {
- // Set up the root layer. By calling -setLayer: followed by -setWantsLayer:
- // the view becomes a layer hosting view as opposed to a layer backed view.
- NSView* view = [self contentView];
- CALayer* rootLayer = [CALayer layer];
- [view setLayer:rootLayer];
- [view setWantsLayer:YES];
-
- // Create the layer that will be animated.
- CALayer* layer = [CALayer layer];
- [self setLayerContents:layer];
- [layer setAnchorPoint:CGPointMake(0, 1)];
- [layer setFrame:[self startFrame]];
- [layer setNeedsDisplayOnBoundsChange:YES];
- [rootLayer addSublayer:layer];
-
- // Common timing function for all animations.
- CAMediaTimingFunction* mediaFunction =
- [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
-
- // Animate the bounds only if the image is resized.
- CABasicAnimation* boundsAnimation = nil;
- if (CGRectGetWidth([self startFrame]) != CGRectGetWidth([self endFrame]) ||
- CGRectGetHeight([self startFrame]) != CGRectGetHeight([self endFrame])) {
- boundsAnimation = [CABasicAnimation animationWithKeyPath:@"bounds"];
- NSRect startRect = NSMakeRect(0, 0,
- CGRectGetWidth([self startFrame]),
- CGRectGetHeight([self startFrame]));
- [boundsAnimation setFromValue:[NSValue valueWithRect:startRect]];
- NSRect endRect = NSMakeRect(0, 0,
- CGRectGetWidth([self endFrame]),
- CGRectGetHeight([self endFrame]));
- [boundsAnimation setToValue:[NSValue valueWithRect:endRect]];
- [boundsAnimation gtm_setDuration:[self duration]
- eventMask:NSLeftMouseUpMask];
- [boundsAnimation setTimingFunction:mediaFunction];
- }
-
- // Positional animation.
- CABasicAnimation* positionAnimation =
- [CABasicAnimation animationWithKeyPath:@"position"];
- [positionAnimation setFromValue:
- [NSValue valueWithPoint:NSPointFromCGPoint([self startFrame].origin)]];
- [positionAnimation setToValue:
- [NSValue valueWithPoint:NSPointFromCGPoint([self endFrame].origin)]];
- [positionAnimation gtm_setDuration:[self duration]
- eventMask:NSLeftMouseUpMask];
- [positionAnimation setTimingFunction:mediaFunction];
-
- // Opacity animation.
- CABasicAnimation* opacityAnimation =
- [CABasicAnimation animationWithKeyPath:@"opacity"];
- [opacityAnimation setFromValue:
- [NSNumber numberWithFloat:[self startOpacity]]];
- [opacityAnimation setToValue:[NSNumber numberWithFloat:[self endOpacity]]];
- [opacityAnimation gtm_setDuration:[self duration]
- eventMask:NSLeftMouseUpMask];
- [opacityAnimation setTimingFunction:mediaFunction];
- // Set the delegate just for one of the animations so that this window can
- // be closed upon completion.
- [opacityAnimation setDelegate:self];
-
- // The CAAnimations only affect the presentational value of a layer, not the
- // model value. This means that after the animation is done, it can flicker
- // back to the original values. To avoid this, create an implicit animation of
- // the values, which are then overridden with the CABasicAnimations.
- //
- // Ideally, a call to |-setBounds:| should be here, but, for reasons that
- // are not understood, doing so causes the animation to break.
- [layer setPosition:[self endFrame].origin];
- [layer setOpacity:[self endOpacity]];
-
- // Start the animations.
- [CATransaction begin];
- [CATransaction setValue:[NSNumber numberWithFloat:[self duration]]
- forKey:kCATransactionAnimationDuration];
- if (boundsAnimation) {
- [layer addAnimation:boundsAnimation forKey:@"bounds"];
- }
- [layer addAnimation:positionAnimation forKey:@"position"];
- [layer addAnimation:opacityAnimation forKey:@"opacity"];
- [CATransaction commit];
-}
-
-// Sets the layer contents by converting the NSImage to a CGImageRef. This will
-// rasterize PDF resources.
-- (void)setLayerContents:(CALayer*)layer {
- base::mac::ScopedCFTypeRef<CGImageRef> image(
- mac_util::CopyNSImageToCGImage(image_.get()));
- // Create the layer that will be animated.
- [layer setContents:(id)image.get()];
-}
-
-// CAAnimation delegate method called when the animation is complete.
-- (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)flag {
- // Close the window, releasing self.
- [self close];
-}
-
-@end
diff --git a/chrome/browser/cocoa/animatable_image_unittest.mm b/chrome/browser/cocoa/animatable_image_unittest.mm
deleted file mode 100644
index af2bc6a..0000000
--- a/chrome/browser/cocoa/animatable_image_unittest.mm
+++ /dev/null
@@ -1,46 +0,0 @@
-// 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>
-
-#import "base/nsimage_cache_mac.h"
-#import "chrome/browser/cocoa/animatable_image.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-namespace {
-
-class AnimatableImageTest : public CocoaTest {
- public:
- AnimatableImageTest() {
- NSRect frame = NSMakeRect(0, 0, 500, 500);
- NSImage* image = nsimage_cache::ImageNamed(@"forward_Template.pdf");
- animation_ = [[AnimatableImage alloc] initWithImage:image
- animationFrame:frame];
- }
-
- AnimatableImage* animation_;
-};
-
-TEST_F(AnimatableImageTest, BasicAnimation) {
- [animation_ setStartFrame:CGRectMake(0, 0, 10, 10)];
- [animation_ setEndFrame:CGRectMake(500, 500, 100, 100)];
- [animation_ setStartOpacity:0.1];
- [animation_ setEndOpacity:1.0];
- [animation_ setDuration:0.5];
- [animation_ startAnimation];
-}
-
-TEST_F(AnimatableImageTest, CancelAnimation) {
- [animation_ setStartFrame:CGRectMake(0, 0, 10, 10)];
- [animation_ setEndFrame:CGRectMake(500, 500, 100, 100)];
- [animation_ setStartOpacity:0.1];
- [animation_ setEndOpacity:1.0];
- [animation_ setDuration:5.0]; // Long enough to be able to test cancelling.
- [animation_ startAnimation];
- [animation_ close];
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/animatable_view.h b/chrome/browser/cocoa/animatable_view.h
deleted file mode 100644
index 9c8a456..0000000
--- a/chrome/browser/cocoa/animatable_view.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_ANIMATABLE_VIEW_H_
-#define CHROME_BROWSER_COCOA_ANIMATABLE_VIEW_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/cocoa_protocols_mac.h"
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/background_gradient_view.h"
-#import "chrome/browser/cocoa/view_resizer.h"
-
-// A view that provides an animatable height property. Provides methods to
-// animate to a new height, set a new height immediately, or cancel any running
-// animations.
-//
-// AnimatableView sends an |animationDidEnd:| message to its delegate when the
-// animation ends normally and an |animationDidStop:| message when the animation
-// was canceled (even when canceled as a result of a new animation starting).
-
-@interface AnimatableView : BackgroundGradientView<NSAnimationDelegate> {
- @protected
- IBOutlet id delegate_; // weak, used to send animation ended messages.
-
- @private
- scoped_nsobject<NSAnimation> currentAnimation_;
- id<ViewResizer> resizeDelegate_; // weak, usually owns us
-}
-
-// Properties for bindings.
-@property(assign, nonatomic) id delegate;
-@property(assign, nonatomic) id<ViewResizer> resizeDelegate;
-
-// Gets the current height of the view. If an animation is currently running,
-// this will give the current height at the time of the call, not the target
-// height at the end of the animation.
-- (CGFloat)height;
-
-// Sets the height of the view immediately. Cancels any running animations.
-- (void)setHeight:(CGFloat)newHeight;
-
-// Starts a new animation to the given |newHeight| for the given |duration|.
-// Cancels any running animations.
-- (void)animateToNewHeight:(CGFloat)newHeight
- duration:(NSTimeInterval)duration;
-
-// Cancels any running animations, leaving the view at its current
-// (mid-animation) height.
-- (void)stopAnimation;
-
-// Gets the progress of any current animation.
-- (NSAnimationProgress)currentAnimationProgress;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_ANIMATABLE_VIEW_H_
diff --git a/chrome/browser/cocoa/animatable_view.mm b/chrome/browser/cocoa/animatable_view.mm
deleted file mode 100644
index 7488a45..0000000
--- a/chrome/browser/cocoa/animatable_view.mm
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright (c) 2009 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>
-#import <QuartzCore/QuartzCore.h>
-
-#import "chrome/browser/cocoa/animatable_view.h"
-#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
-
-// NSAnimation subclass that animates the height of an AnimatableView. Allows
-// the caller to start and cancel the animation as desired.
-@interface HeightAnimation : NSAnimation {
- @private
- AnimatableView* view_; // weak, owns us.
- CGFloat startHeight_;
- CGFloat endHeight_;
-}
-
-// Initialize a new height animation for the given view. The animation will not
-// start until startAnimation: is called.
-- (id)initWithView:(AnimatableView*)view
- finalHeight:(CGFloat)height
- duration:(NSTimeInterval)duration;
-@end
-
-@implementation HeightAnimation
-- (id)initWithView:(AnimatableView*)view
- finalHeight:(CGFloat)height
- duration:(NSTimeInterval)duration {
- if ((self = [super gtm_initWithDuration:duration
- eventMask:NSLeftMouseUpMask
- animationCurve:NSAnimationEaseIn])) {
- view_ = view;
- startHeight_ = [view_ height];
- endHeight_ = height;
- [self setAnimationBlockingMode:NSAnimationNonblocking];
- [self setDelegate:view_];
- }
- return self;
-}
-
-// Overridden to call setHeight for each progress tick.
-- (void)setCurrentProgress:(NSAnimationProgress)progress {
- [super setCurrentProgress:progress];
- [view_ setHeight:((progress * (endHeight_ - startHeight_)) + startHeight_)];
-}
-@end
-
-
-@implementation AnimatableView
-@synthesize delegate = delegate_;
-@synthesize resizeDelegate = resizeDelegate_;
-
-- (void)dealloc {
- // Stop the animation if it is running, since it holds a pointer to this view.
- [self stopAnimation];
- [super dealloc];
-}
-
-- (CGFloat)height {
- return [self frame].size.height;
-}
-
-- (void)setHeight:(CGFloat)newHeight {
- // Force the height to be an integer because some animations look terrible
- // with non-integer intermediate heights. We only ever set integer heights
- // for our views, so this shouldn't be a limitation in practice.
- int height = floor(newHeight);
- [resizeDelegate_ resizeView:self newHeight:height];
-}
-
-- (void)animateToNewHeight:(CGFloat)newHeight
- duration:(NSTimeInterval)duration {
- [currentAnimation_ stopAnimation];
-
- currentAnimation_.reset([[HeightAnimation alloc] initWithView:self
- finalHeight:newHeight
- duration:duration]);
- if ([resizeDelegate_ respondsToSelector:@selector(setAnimationInProgress:)])
- [resizeDelegate_ setAnimationInProgress:YES];
- [currentAnimation_ startAnimation];
-}
-
-- (void)stopAnimation {
- [currentAnimation_ stopAnimation];
-}
-
-- (NSAnimationProgress)currentAnimationProgress {
- return [currentAnimation_ currentProgress];
-}
-
-- (void)animationDidStop:(NSAnimation*)animation {
- if ([resizeDelegate_ respondsToSelector:@selector(setAnimationInProgress:)])
- [resizeDelegate_ setAnimationInProgress:NO];
- if ([delegate_ respondsToSelector:@selector(animationDidStop:)])
- [delegate_ animationDidStop:animation];
- currentAnimation_.reset(nil);
-}
-
-- (void)animationDidEnd:(NSAnimation*)animation {
- if ([resizeDelegate_ respondsToSelector:@selector(setAnimationInProgress:)])
- [resizeDelegate_ setAnimationInProgress:NO];
- if ([delegate_ respondsToSelector:@selector(animationDidEnd:)])
- [delegate_ animationDidEnd:animation];
- currentAnimation_.reset(nil);
-}
-
-@end
diff --git a/chrome/browser/cocoa/animatable_view_unittest.mm b/chrome/browser/cocoa/animatable_view_unittest.mm
deleted file mode 100644
index 35a7e8f..0000000
--- a/chrome/browser/cocoa/animatable_view_unittest.mm
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2009 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 "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/animatable_view.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/view_resizer_pong.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-namespace {
-
-class AnimatableViewTest : public CocoaTest {
- public:
- AnimatableViewTest() {
- NSRect frame = NSMakeRect(0, 0, 100, 100);
- view_.reset([[AnimatableView alloc] initWithFrame:frame]);
- [[test_window() contentView] addSubview:view_.get()];
-
- resizeDelegate_.reset([[ViewResizerPong alloc] init]);
- [view_ setResizeDelegate:resizeDelegate_.get()];
- }
-
- scoped_nsobject<ViewResizerPong> resizeDelegate_;
- scoped_nsobject<AnimatableView> view_;
-};
-
-// Basic view tests (AddRemove, Display).
-TEST_VIEW(AnimatableViewTest, view_);
-
-TEST_F(AnimatableViewTest, GetAndSetHeight) {
- // Make sure the view's height starts out at 100.
- NSRect initialFrame = [view_ frame];
- ASSERT_EQ(100, initialFrame.size.height);
- EXPECT_EQ(initialFrame.size.height, [view_ height]);
-
- // Set it directly to 50 and make sure it takes effect.
- [resizeDelegate_ setHeight:-1];
- [view_ setHeight:50];
- EXPECT_EQ(50, [resizeDelegate_ height]);
-}
-
-// TODO(rohitrao): Find a way to unittest the animations and delegate messages.
-
-} // namespace
diff --git a/chrome/browser/cocoa/applescript/bookmark_applescript_utils_unittest.h b/chrome/browser/cocoa/applescript/bookmark_applescript_utils_unittest.h
deleted file mode 100644
index bb77726..0000000
--- a/chrome/browser/cocoa/applescript/bookmark_applescript_utils_unittest.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_APPLESCRIPT_BOOKMARK_APPLESCRIPT_UTILS_UNITTEST_H_
-#define CHROME_BROWSER_COCOA_APPLESCRIPT_BOOKMARK_APPLESCRIPT_UTILS_UNITTEST_H_
-
-#import <objc/objc-runtime.h>
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/app_controller_mac.h"
-#import "chrome/browser/cocoa/applescript/bookmark_folder_applescript.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/test/model_test_utils.h"
-#include "testing/platform_test.h"
-
-class BookmarkModel;
-
-// The fake object that acts as our app's delegate, useful for testing purposes.
-@interface FakeAppDelegate : AppController {
- @public
- BrowserTestHelper* helper_; // weak.
-}
-@property (nonatomic) BrowserTestHelper* helper;
-// Return the |TestingProfile*| which is used for testing.
-- (Profile*)defaultProfile;
-@end
-
-
-// Used to emulate an active running script, useful for testing purposes.
-@interface FakeScriptCommand : NSScriptCommand {
- Method originalMethod_;
- Method alternateMethod_;
-}
-@end
-
-
-// The base class for all our bookmark releated unit tests.
-class BookmarkAppleScriptTest : public CocoaTest {
- public:
- BookmarkAppleScriptTest();
- private:
- BrowserTestHelper helper_;
- scoped_nsobject<FakeAppDelegate> appDelegate_;
- protected:
- scoped_nsobject<BookmarkFolderAppleScript> bookmarkBar_;
- BookmarkModel& model();
-};
-
-#endif
-// CHROME_BROWSER_COCOA_APPLESCRIPT_BOOKMARK_APPLESCRIPT_UTILS_UNITTEST_H_
diff --git a/chrome/browser/cocoa/applescript/bookmark_applescript_utils_unittest.mm b/chrome/browser/cocoa/applescript/bookmark_applescript_utils_unittest.mm
deleted file mode 100644
index bea8970..0000000
--- a/chrome/browser/cocoa/applescript/bookmark_applescript_utils_unittest.mm
+++ /dev/null
@@ -1,62 +0,0 @@
-// 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 "chrome/browser/cocoa/applescript/bookmark_applescript_utils_unittest.h"
-
-#include "chrome/browser/bookmarks/bookmark_model.h"
-
-@implementation FakeAppDelegate
-
-@synthesize helper = helper_;
-
-- (Profile*)defaultProfile {
- if (!helper_)
- return NULL;
- return helper_->profile();
-}
-@end
-
-// Represents the current fake command that is executing.
-static FakeScriptCommand* kFakeCurrentCommand;
-
-@implementation FakeScriptCommand
-
-- (id)init {
- if ((self = [super init])) {
- originalMethod_ = class_getClassMethod([NSScriptCommand class],
- @selector(currentCommand));
- alternateMethod_ = class_getClassMethod([self class],
- @selector(currentCommand));
- method_exchangeImplementations(originalMethod_, alternateMethod_);
- kFakeCurrentCommand = self;
- }
- return self;
-}
-
-+ (NSScriptCommand*)currentCommand {
- return kFakeCurrentCommand;
-}
-
-- (void)dealloc {
- method_exchangeImplementations(originalMethod_, alternateMethod_);
- kFakeCurrentCommand = nil;
- [super dealloc];
-}
-
-@end
-
-BookmarkAppleScriptTest::BookmarkAppleScriptTest() {
- appDelegate_.reset([[FakeAppDelegate alloc] init]);
- [appDelegate_.get() setHelper:&helper_];
- [NSApp setDelegate:appDelegate_];
- const BookmarkNode* root = model().GetBookmarkBarNode();
- const std::string modelString("a f1:[ b d c ] d f2:[ e f g ] h ");
- model_test_utils::AddNodesFromModelString(model(), root, modelString);
- bookmarkBar_.reset([[BookmarkFolderAppleScript alloc]
- initWithBookmarkNode:model().GetBookmarkBarNode()]);
-}
-
-BookmarkModel& BookmarkAppleScriptTest::model() {
- return *helper_.profile()->GetBookmarkModel();
-}
diff --git a/chrome/browser/cocoa/applescript/bookmark_folder_applescript.h b/chrome/browser/cocoa/applescript/bookmark_folder_applescript.h
deleted file mode 100644
index f56a3f9..0000000
--- a/chrome/browser/cocoa/applescript/bookmark_folder_applescript.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_APPLESCRIPT_BOOKMARK_FOLDER_APPLESCRIPT_H_
-#define CHROME_BROWSER_COCOA_APPLESCRIPT_BOOKMARK_FOLDER_APPLESCRIPT_H_
-
-#import <Cocoa/Cocoa.h>
-
-#import "chrome/browser/cocoa/applescript/bookmark_node_applescript.h"
-
-@class BookmarkItemAppleScript;
-
-// Represent a bookmark folder scriptable object in applescript.
-@interface BookmarkFolderAppleScript : BookmarkNodeAppleScript {
-
-}
-
-// Bookmark folder manipulation methods.
-// Returns an array of |BookmarkFolderAppleScript*| of all the bookmark folders
-// contained within this particular folder.
-- (NSArray*)bookmarkFolders;
-
-// Inserts a bookmark folder at the end.
-- (void)insertInBookmarkFolders:(id)aBookmarkFolder;
-
-// Inserts a bookmark folder at some position in the list.
-// Called by applescript which takes care of bounds checking, make sure of it
-// before calling directly.
-- (void)insertInBookmarkFolders:(id)aBookmarkFolder atIndex:(int)index;
-
-// Remove a bookmark folder from the list.
-// Called by applescript which takes care of bounds checking, make sure of it
-// before calling directly.
-- (void)removeFromBookmarkFoldersAtIndex:(int)index;
-
-// Bookmark item manipulation methods.
-// Returns an array of |BookmarkItemAppleScript*| of all the bookmark items
-// contained within this particular folder.
-- (NSArray*)bookmarkItems;
-
-// Inserts a bookmark item at the end.
-- (void)insertInBookmarkItems:(BookmarkItemAppleScript*)aBookmarkItem;
-
-// Inserts a bookmark item at some position in the list.
-// Called by applescript which takes care of bounds checking, make sure of it
-// before calling directly.
-- (void)insertInBookmarkItems:(BookmarkItemAppleScript*)aBookmarkItem
- atIndex:(int)index;
-
-// Removes a bookmarks folder from the list.
-// Called by applescript which takes care of bounds checking, make sure of it
-// before calling directly.
-- (void)removeFromBookmarkItemsAtIndex:(int)index;
-
-// Returns the position of a bookmark folder within the current bookmark folder
-// which consists of bookmark folders as well as bookmark items.
-// AppleScript makes sure that there is a bookmark folder before calling this
-// method, make sure of that before calling directly.
-- (int)calculatePositionOfBookmarkFolderAt:(int)index;
-
-// Returns the position of a bookmark item within the current bookmark folder
-// which consists of bookmark folders as well as bookmark items.
-// AppleScript makes sure that there is a bookmark item before calling this
-// method, make sure of that before calling directly.
-- (int)calculatePositionOfBookmarkItemAt:(int)index;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_APPLESCRIPT_BOOKMARK_FOLDER_APPLESCRIPT_H_
diff --git a/chrome/browser/cocoa/applescript/bookmark_folder_applescript.mm b/chrome/browser/cocoa/applescript/bookmark_folder_applescript.mm
deleted file mode 100644
index 203a954..0000000
--- a/chrome/browser/cocoa/applescript/bookmark_folder_applescript.mm
+++ /dev/null
@@ -1,204 +0,0 @@
-// 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 "chrome/browser/cocoa/applescript/bookmark_folder_applescript.h"
-
-#import "base/scoped_nsobject.h"
-#import "base/string16.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#import "chrome/browser/cocoa/applescript/bookmark_item_applescript.h"
-#import "chrome/browser/cocoa/applescript/constants_applescript.h"
-#include "chrome/browser/cocoa/applescript/error_applescript.h"
-#include "googleurl/src/gurl.h"
-
-@implementation BookmarkFolderAppleScript
-
-- (NSArray*)bookmarkFolders {
- NSMutableArray* bookmarkFolders = [NSMutableArray
- arrayWithCapacity:bookmarkNode_->GetChildCount()];
-
- for (int i = 0; i < bookmarkNode_->GetChildCount(); ++i) {
- const BookmarkNode* node = bookmarkNode_->GetChild(i);
-
- if (!node->is_folder())
- continue;
- scoped_nsobject<BookmarkFolderAppleScript> bookmarkFolder(
- [[BookmarkFolderAppleScript alloc]
- initWithBookmarkNode:node]);
- [bookmarkFolder setContainer:self
- property:AppleScript::kBookmarkFoldersProperty];
- [bookmarkFolders addObject:bookmarkFolder];
- }
-
- return bookmarkFolders;
-}
-
-- (void)insertInBookmarkFolders:(id)aBookmarkFolder {
- // This method gets called when a new bookmark folder is created so
- // the container and property are set here.
- [aBookmarkFolder setContainer:self
- property:AppleScript::kBookmarkFoldersProperty];
- BookmarkModel* model = [self bookmarkModel];
- if (!model)
- return;
-
- const BookmarkNode* node = model->AddGroup(bookmarkNode_,
- bookmarkNode_->GetChildCount(),
- string16());
- if (!node) {
- AppleScript::SetError(AppleScript::errCreateBookmarkFolder);
- return;
- }
-
- [aBookmarkFolder setBookmarkNode:node];
-}
-
-- (void)insertInBookmarkFolders:(id)aBookmarkFolder atIndex:(int)index {
- // This method gets called when a new bookmark folder is created so
- // the container and property are set here.
- [aBookmarkFolder setContainer:self
- property:AppleScript::kBookmarkFoldersProperty];
- int position = [self calculatePositionOfBookmarkFolderAt:index];
-
- BookmarkModel* model = [self bookmarkModel];
- if (!model)
- return;
-
- const BookmarkNode* node = model->AddGroup(bookmarkNode_,
- position,
- string16());
- if (!node) {
- AppleScript::SetError(AppleScript::errCreateBookmarkFolder);
- return;
- }
-
- [aBookmarkFolder setBookmarkNode:node];
-}
-
-- (void)removeFromBookmarkFoldersAtIndex:(int)index {
- int position = [self calculatePositionOfBookmarkFolderAt:index];
-
- BookmarkModel* model = [self bookmarkModel];
- if (!model)
- return;
-
- model->Remove(bookmarkNode_, position);
-}
-
-- (NSArray*)bookmarkItems {
- NSMutableArray* bookmarkItems = [NSMutableArray
- arrayWithCapacity:bookmarkNode_->GetChildCount()];
-
- for (int i = 0; i < bookmarkNode_->GetChildCount(); ++i) {
- const BookmarkNode* node = bookmarkNode_->GetChild(i);
-
- if (!node->is_url())
- continue;
- scoped_nsobject<BookmarkFolderAppleScript> bookmarkItem(
- [[BookmarkItemAppleScript alloc]
- initWithBookmarkNode:node]);
- [bookmarkItem setContainer:self
- property:AppleScript::kBookmarkItemsProperty];
- [bookmarkItems addObject:bookmarkItem];
- }
-
- return bookmarkItems;
-}
-
-- (void)insertInBookmarkItems:(BookmarkItemAppleScript*)aBookmarkItem {
- // This method gets called when a new bookmark item is created so
- // the container and property are set here.
- [aBookmarkItem setContainer:self
- property:AppleScript::kBookmarkItemsProperty];
-
- BookmarkModel* model = [self bookmarkModel];
- if (!model)
- return;
-
- GURL url = GURL(base::SysNSStringToUTF8([aBookmarkItem URL]));
- if (!url.is_valid()) {
- AppleScript::SetError(AppleScript::errInvalidURL);
- return;
- }
-
- const BookmarkNode* node = model->AddURL(bookmarkNode_,
- bookmarkNode_->GetChildCount(),
- string16(),
- url);
- if (!node) {
- AppleScript::SetError(AppleScript::errCreateBookmarkItem);
- return;
- }
-
- [aBookmarkItem setBookmarkNode:node];
-}
-
-- (void)insertInBookmarkItems:(BookmarkItemAppleScript*)aBookmarkItem
- atIndex:(int)index {
- // This method gets called when a new bookmark item is created so
- // the container and property are set here.
- [aBookmarkItem setContainer:self
- property:AppleScript::kBookmarkItemsProperty];
- int position = [self calculatePositionOfBookmarkItemAt:index];
-
- BookmarkModel* model = [self bookmarkModel];
- if (!model)
- return;
-
- GURL url(base::SysNSStringToUTF8([aBookmarkItem URL]));
- if (!url.is_valid()) {
- AppleScript::SetError(AppleScript::errInvalidURL);
- return;
- }
-
- const BookmarkNode* node = model->AddURL(bookmarkNode_,
- position,
- string16(),
- url);
- if (!node) {
- AppleScript::SetError(AppleScript::errCreateBookmarkItem);
- return;
- }
-
- [aBookmarkItem setBookmarkNode:node];
-}
-
-- (void)removeFromBookmarkItemsAtIndex:(int)index {
- int position = [self calculatePositionOfBookmarkItemAt:index];
-
- BookmarkModel* model = [self bookmarkModel];
- if (!model)
- return;
-
- model->Remove(bookmarkNode_, position);
-}
-
-- (int)calculatePositionOfBookmarkFolderAt:(int)index {
- // Traverse through all the child nodes till the required node is found and
- // return its position.
- // AppleScript is 1-based therefore index is incremented by 1.
- ++index;
- int count = -1;
- while (index) {
- if (bookmarkNode_->GetChild(++count)->is_folder())
- --index;
- }
- return count;
-}
-
-- (int)calculatePositionOfBookmarkItemAt:(int)index {
- // Traverse through all the child nodes till the required node is found and
- // return its position.
- // AppleScript is 1-based therefore index is incremented by 1.
- ++index;
- int count = -1;
- while (index) {
- if (bookmarkNode_->GetChild(++count)->is_url())
- --index;
- }
- return count;
-}
-
-@end
diff --git a/chrome/browser/cocoa/applescript/bookmark_folder_applescript_unittest.mm b/chrome/browser/cocoa/applescript/bookmark_folder_applescript_unittest.mm
deleted file mode 100644
index 658f1fc..0000000
--- a/chrome/browser/cocoa/applescript/bookmark_folder_applescript_unittest.mm
+++ /dev/null
@@ -1,200 +0,0 @@
-// 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 "base/scoped_nsobject.h"
-#include "base/sys_string_conversions.h"
-#import "chrome/browser/cocoa/applescript/bookmark_applescript_utils_unittest.h"
-#import "chrome/browser/cocoa/applescript/bookmark_folder_applescript.h"
-#import "chrome/browser/cocoa/applescript/bookmark_item_applescript.h"
-#import "chrome/browser/cocoa/applescript/constants_applescript.h"
-#import "chrome/browser/cocoa/applescript/error_applescript.h"
-#include "googleurl/src/gurl.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-typedef BookmarkAppleScriptTest BookmarkFolderAppleScriptTest;
-
-namespace {
-
-// Test all the bookmark folders within.
-TEST_F(BookmarkFolderAppleScriptTest, BookmarkFolders) {
- NSArray* bookmarkFolders = [bookmarkBar_.get() bookmarkFolders];
-
- EXPECT_EQ(2U, [bookmarkFolders count]);
-
- BookmarkFolderAppleScript* f1 = [bookmarkFolders objectAtIndex:0];
- BookmarkFolderAppleScript* f2 = [bookmarkFolders objectAtIndex:1];
- EXPECT_NSEQ(@"f1", [f1 title]);
- EXPECT_NSEQ(@"f2", [f2 title]);
- EXPECT_EQ(2, [[f1 index] intValue]);
- EXPECT_EQ(4, [[f2 index] intValue]);
-
- for (BookmarkFolderAppleScript* bookmarkFolder in bookmarkFolders) {
- EXPECT_EQ([bookmarkFolder container], bookmarkBar_.get());
- EXPECT_NSEQ(AppleScript::kBookmarkFoldersProperty,
- [bookmarkFolder containerProperty]);
- }
-}
-
-// Insert a new bookmark folder.
-TEST_F(BookmarkFolderAppleScriptTest, InsertBookmarkFolder) {
- // Emulate what applescript would do when inserting a new bookmark folder.
- // Emulates a script like |set var to make new bookmark folder with
- // properties {title:"foo"}|.
- scoped_nsobject<BookmarkFolderAppleScript> bookmarkFolder(
- [[BookmarkFolderAppleScript alloc] init]);
- scoped_nsobject<NSNumber> var([[bookmarkFolder.get() uniqueID] copy]);
- [bookmarkFolder.get() setTitle:@"foo"];
- [bookmarkBar_.get() insertInBookmarkFolders:bookmarkFolder.get()];
-
- // Represents the bookmark folder after its added.
- BookmarkFolderAppleScript* bf =
- [[bookmarkBar_.get() bookmarkFolders] objectAtIndex:2];
- EXPECT_NSEQ(@"foo", [bf title]);
- EXPECT_EQ([bf container], bookmarkBar_.get());
- EXPECT_NSEQ(AppleScript::kBookmarkFoldersProperty,
- [bf containerProperty]);
- EXPECT_NSEQ(var.get(), [bf uniqueID]);
-}
-
-// Insert a new bookmark folder at a particular position.
-TEST_F(BookmarkFolderAppleScriptTest, InsertBookmarkFolderAtPosition) {
- // Emulate what applescript would do when inserting a new bookmark folder.
- // Emulates a script like |set var to make new bookmark folder with
- // properties {title:"foo"} at after bookmark folder 1|.
- scoped_nsobject<BookmarkFolderAppleScript> bookmarkFolder(
- [[BookmarkFolderAppleScript alloc] init]);
- scoped_nsobject<NSNumber> var([[bookmarkFolder.get() uniqueID] copy]);
- [bookmarkFolder.get() setTitle:@"foo"];
- [bookmarkBar_.get() insertInBookmarkFolders:bookmarkFolder.get() atIndex:1];
-
- // Represents the bookmark folder after its added.
- BookmarkFolderAppleScript* bf =
- [[bookmarkBar_.get() bookmarkFolders] objectAtIndex:1];
- EXPECT_NSEQ(@"foo", [bf title]);
- EXPECT_EQ([bf container], bookmarkBar_.get());
- EXPECT_NSEQ(AppleScript::kBookmarkFoldersProperty, [bf containerProperty]);
- EXPECT_NSEQ(var.get(), [bf uniqueID]);
-}
-
-// Delete bookmark folders.
-TEST_F(BookmarkFolderAppleScriptTest, DeleteBookmarkFolders) {
- unsigned int folderCount = 2, itemCount = 3;
- for (unsigned int i = 0; i < folderCount; ++i) {
- EXPECT_EQ(folderCount - i, [[bookmarkBar_.get() bookmarkFolders] count]);
- EXPECT_EQ(itemCount, [[bookmarkBar_.get() bookmarkItems] count]);
- [bookmarkBar_.get() removeFromBookmarkFoldersAtIndex:0];
- }
-}
-
-// Test all the bookmark items within.
-TEST_F(BookmarkFolderAppleScriptTest, BookmarkItems) {
- NSArray* bookmarkItems = [bookmarkBar_.get() bookmarkItems];
-
- EXPECT_EQ(3U, [bookmarkItems count]);
-
- BookmarkItemAppleScript* i1 = [bookmarkItems objectAtIndex:0];
- BookmarkItemAppleScript* i2 = [bookmarkItems objectAtIndex:1];
- BookmarkItemAppleScript* i3 = [bookmarkItems objectAtIndex:2];
- EXPECT_NSEQ(@"a", [i1 title]);
- EXPECT_NSEQ(@"d", [i2 title]);
- EXPECT_NSEQ(@"h", [i3 title]);
- EXPECT_EQ(1, [[i1 index] intValue]);
- EXPECT_EQ(3, [[i2 index] intValue]);
- EXPECT_EQ(5, [[i3 index] intValue]);
-
- for (BookmarkItemAppleScript* bookmarkItem in bookmarkItems) {
- EXPECT_EQ([bookmarkItem container], bookmarkBar_.get());
- EXPECT_NSEQ(AppleScript::kBookmarkItemsProperty,
- [bookmarkItem containerProperty]);
- }
-}
-
-// Insert a new bookmark item.
-TEST_F(BookmarkFolderAppleScriptTest, InsertBookmarkItem) {
- // Emulate what applescript would do when inserting a new bookmark folder.
- // Emulates a script like |set var to make new bookmark item with
- // properties {title:"Google", URL:"http://google.com"}|.
- scoped_nsobject<BookmarkItemAppleScript> bookmarkItem(
- [[BookmarkItemAppleScript alloc] init]);
- scoped_nsobject<NSNumber> var([[bookmarkItem.get() uniqueID] copy]);
- [bookmarkItem.get() setTitle:@"Google"];
- [bookmarkItem.get() setURL:@"http://google.com"];
- [bookmarkBar_.get() insertInBookmarkItems:bookmarkItem.get()];
-
- // Represents the bookmark item after its added.
- BookmarkItemAppleScript* bi =
- [[bookmarkBar_.get() bookmarkItems] objectAtIndex:3];
- EXPECT_NSEQ(@"Google", [bi title]);
- EXPECT_EQ(GURL("http://google.com/"),
- GURL(base::SysNSStringToUTF8([bi URL])));
- EXPECT_EQ([bi container], bookmarkBar_.get());
- EXPECT_NSEQ(AppleScript::kBookmarkItemsProperty, [bi containerProperty]);
- EXPECT_NSEQ(var.get(), [bi uniqueID]);
-
- // Test to see no bookmark item is created when no/invlid URL is entered.
- scoped_nsobject<FakeScriptCommand> fakeScriptCommand(
- [[FakeScriptCommand alloc] init]);
- bookmarkItem.reset([[BookmarkItemAppleScript alloc] init]);
- [bookmarkBar_.get() insertInBookmarkItems:bookmarkItem.get()];
- EXPECT_EQ((int)AppleScript::errInvalidURL,
- [fakeScriptCommand.get() scriptErrorNumber]);
-}
-
-// Insert a new bookmark item at a particular position.
-TEST_F(BookmarkFolderAppleScriptTest, InsertBookmarkItemAtPosition) {
- // Emulate what applescript would do when inserting a new bookmark item.
- // Emulates a script like |set var to make new bookmark item with
- // properties {title:"XKCD", URL:"http://xkcd.org}
- // at after bookmark item 1|.
- scoped_nsobject<BookmarkItemAppleScript> bookmarkItem(
- [[BookmarkItemAppleScript alloc] init]);
- scoped_nsobject<NSNumber> var([[bookmarkItem.get() uniqueID] copy]);
- [bookmarkItem.get() setTitle:@"XKCD"];
- [bookmarkItem.get() setURL:@"http://xkcd.org"];
-
- [bookmarkBar_.get() insertInBookmarkItems:bookmarkItem.get() atIndex:1];
-
- // Represents the bookmark item after its added.
- BookmarkItemAppleScript* bi =
- [[bookmarkBar_.get() bookmarkItems] objectAtIndex:1];
- EXPECT_NSEQ(@"XKCD", [bi title]);
- EXPECT_EQ(GURL("http://xkcd.org/"),
- GURL(base::SysNSStringToUTF8([bi URL])));
- EXPECT_EQ([bi container], bookmarkBar_.get());
- EXPECT_NSEQ(AppleScript::kBookmarkItemsProperty,
- [bi containerProperty]);
- EXPECT_NSEQ(var.get(), [bi uniqueID]);
-
- // Test to see no bookmark item is created when no/invlid URL is entered.
- scoped_nsobject<FakeScriptCommand> fakeScriptCommand(
- [[FakeScriptCommand alloc] init]);
- bookmarkItem.reset([[BookmarkItemAppleScript alloc] init]);
- [bookmarkBar_.get() insertInBookmarkItems:bookmarkItem.get() atIndex:1];
- EXPECT_EQ((int)AppleScript::errInvalidURL,
- [fakeScriptCommand.get() scriptErrorNumber]);
-}
-
-// Delete bookmark items.
-TEST_F(BookmarkFolderAppleScriptTest, DeleteBookmarkItems) {
- unsigned int folderCount = 2, itemCount = 3;
- for (unsigned int i = 0; i < itemCount; ++i) {
- EXPECT_EQ(folderCount, [[bookmarkBar_.get() bookmarkFolders] count]);
- EXPECT_EQ(itemCount - i, [[bookmarkBar_.get() bookmarkItems] count]);
- [bookmarkBar_.get() removeFromBookmarkItemsAtIndex:0];
- }
-}
-
-// Set and get title.
-TEST_F(BookmarkFolderAppleScriptTest, GetAndSetTitle) {
- NSArray* bookmarkFolders = [bookmarkBar_.get() bookmarkFolders];
- BookmarkFolderAppleScript* folder1 = [bookmarkFolders objectAtIndex:0];
- [folder1 setTitle:@"Foo"];
- EXPECT_NSEQ(@"Foo", [folder1 title]);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/applescript/bookmark_item_applescript.h b/chrome/browser/cocoa/applescript/bookmark_item_applescript.h
deleted file mode 100644
index 97c07af..0000000
--- a/chrome/browser/cocoa/applescript/bookmark_item_applescript.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_APPLESCRIPT_BOOKMARK_ITEM_APPLESCRIPT_H_
-#define CHROME_BROWSER_COCOA_APPLESCRIPT_BOOKMARK_ITEM_APPLESCRIPT_H_
-
-#import <Cocoa/Cocoa.h>
-
-#import "chrome/browser/cocoa/applescript/bookmark_node_applescript.h"
-
-// Represents a bookmark item scriptable object in applescript.
-@interface BookmarkItemAppleScript : BookmarkNodeAppleScript {
- @private
- // Contains the temporary title when a user creates a new item with
- // title specified like
- // |make new bookmarks item with properties {title:"foo"}|.
- NSString* tempURL_;
-}
-
-// Assigns a node, sets its unique ID and also copies temporary values.
-- (void)setBookmarkNode:(const BookmarkNode*)aBookmarkNode;
-
-// Returns the URL that the bookmark item holds.
-- (NSString*)URL;
-
-// Sets the URL of the bookmark item, displays error in applescript console
-// if URL is invalid.
-- (void)setURL:(NSString*)aURL;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_APPLESCRIPT_BOOKMARK_ITEM_APPLESCRIPT_H_
diff --git a/chrome/browser/cocoa/applescript/bookmark_item_applescript.mm b/chrome/browser/cocoa/applescript/bookmark_item_applescript.mm
deleted file mode 100644
index e42a764..0000000
--- a/chrome/browser/cocoa/applescript/bookmark_item_applescript.mm
+++ /dev/null
@@ -1,66 +0,0 @@
-// 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 "chrome/browser/cocoa/applescript/bookmark_item_applescript.h"
-
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#import "chrome/browser/cocoa/applescript/error_applescript.h"
-#include "chrome/browser/profile_manager.h"
-
-@interface BookmarkItemAppleScript()
-@property (nonatomic, copy) NSString* tempURL;
-@end
-
-@implementation BookmarkItemAppleScript
-
-@synthesize tempURL = tempURL_;
-
-- (id)init {
- if ((self = [super init])) {
- [self setTempURL:@""];
- }
- return self;
-}
-
-- (void)dealloc {
- [tempURL_ release];
- [super dealloc];
-}
-
-- (void)setBookmarkNode:(const BookmarkNode*)aBookmarkNode {
- [super setBookmarkNode:aBookmarkNode];
- [self setURL:[self tempURL]];
-}
-
-- (NSString*)URL {
- if (!bookmarkNode_)
- return tempURL_;
-
- const GURL& url = bookmarkNode_->GetURL();
- return base::SysUTF8ToNSString(url.spec());
-}
-
-- (void)setURL:(NSString*)aURL {
- // If a scripter sets a URL before the node is added, URL is saved at a
- // temporary location.
- if (!bookmarkNode_) {
- [self setTempURL:aURL];
- return;
- }
-
- BookmarkModel* model = [self bookmarkModel];
- if (!model)
- return;
-
- GURL url(base::SysNSStringToUTF8(aURL));
- if (!url.is_valid()) {
- AppleScript::SetError(AppleScript::errInvalidURL);
- return;
- }
-
- model->SetURL(bookmarkNode_, url);
-}
-
-@end
diff --git a/chrome/browser/cocoa/applescript/bookmark_item_applescript_unittest.mm b/chrome/browser/cocoa/applescript/bookmark_item_applescript_unittest.mm
deleted file mode 100644
index 68289dc..0000000
--- a/chrome/browser/cocoa/applescript/bookmark_item_applescript_unittest.mm
+++ /dev/null
@@ -1,45 +0,0 @@
-// 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 "base/scoped_nsobject.h"
-#include "base/sys_string_conversions.h"
-#import "chrome/browser/cocoa/applescript/bookmark_applescript_utils_unittest.h"
-#import "chrome/browser/cocoa/applescript/bookmark_item_applescript.h"
-#import "chrome/browser/cocoa/applescript/error_applescript.h"
-#include "googleurl/src/gurl.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-typedef BookmarkAppleScriptTest BookmarkItemAppleScriptTest;
-
-namespace {
-
-// Set and get title.
-TEST_F(BookmarkItemAppleScriptTest, GetAndSetTitle) {
- NSArray* bookmarkItems = [bookmarkBar_.get() bookmarkItems];
- BookmarkItemAppleScript* item1 = [bookmarkItems objectAtIndex:0];
- [item1 setTitle:@"Foo"];
- EXPECT_NSEQ(@"Foo", [item1 title]);
-}
-
-// Set and get URL.
-TEST_F(BookmarkItemAppleScriptTest, GetAndSetURL) {
- NSArray* bookmarkItems = [bookmarkBar_.get() bookmarkItems];
- BookmarkItemAppleScript* item1 = [bookmarkItems objectAtIndex:0];
- [item1 setURL:@"http://foo-bar.org"];
- EXPECT_EQ(GURL("http://foo-bar.org"),
- GURL(base::SysNSStringToUTF8([item1 URL])));
-
- // If scripter enters invalid URL.
- scoped_nsobject<FakeScriptCommand> fakeScriptCommand(
- [[FakeScriptCommand alloc] init]);
- [item1 setURL:@"invalid-url.org"];
- EXPECT_EQ((int)AppleScript::errInvalidURL,
- [fakeScriptCommand.get() scriptErrorNumber]);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/applescript/bookmark_node_applescript.h b/chrome/browser/cocoa/applescript/bookmark_node_applescript.h
deleted file mode 100644
index 7ec8856..0000000
--- a/chrome/browser/cocoa/applescript/bookmark_node_applescript.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_APPLESCRIPT_BOOKMARK_NODE_APPLESCRIPT_H_
-#define CHROME_BROWSER_COCOA_APPLESCRIPT_BOOKMARK_NODE_APPLESCRIPT_H_
-
-#import <Cocoa/Cocoa.h>
-
-#import "chrome/browser/cocoa/applescript/element_applescript.h"
-
-class BookmarkModel;
-class BookmarkNode;
-
-// Contains all the elements that are common to both a bookmark folder and
-// bookmark item.
-@interface BookmarkNodeAppleScript : ElementAppleScript {
- @protected
- const BookmarkNode* bookmarkNode_; // weak.
- // Contains the temporary title when a scripter creates a new folder/item with
- // title specified like
- // |make new bookmark folder with properties {title:"foo"}|.
- NSString* tempTitle_;
-}
-
-// Does not actually create a folder/item but just sets its ID, the folder is
-// created in insertInBookmarksFolder: in the corresponding bookmarks folder.
-- (id)init;
-
-// Does not make a folder/item but instead uses an existing one.
-- (id)initWithBookmarkNode:(const BookmarkNode*)aBookmarkNode;
-
-// Assigns a node, sets its unique ID and also copies temporary values.
-- (void)setBookmarkNode:(const BookmarkNode*)aBookmarkNode;
-
-// Get and Set title.
-- (NSString*)title;
-- (void)setTitle:(NSString*)aTitle;
-
-// Returns the index with respect to its parent bookmark folder.
-- (NSNumber*)index;
-
-// Returns the bookmark model of the browser, returns NULL if there is an error.
-- (BookmarkModel*)bookmarkModel;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_APPLESCRIPT_BOOKMARK_NODE_APPLESCRIPT_H_
diff --git a/chrome/browser/cocoa/applescript/bookmark_node_applescript.mm b/chrome/browser/cocoa/applescript/bookmark_node_applescript.mm
deleted file mode 100644
index 9ad57bd..0000000
--- a/chrome/browser/cocoa/applescript/bookmark_node_applescript.mm
+++ /dev/null
@@ -1,130 +0,0 @@
-// 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 "chrome/browser/cocoa/applescript/bookmark_node_applescript.h"
-
-#include "base/logging.h"
-#include "base/sys_string_conversions.h"
-#import "base/scoped_nsobject.h"
-#import "chrome/browser/app_controller_mac.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#import "chrome/browser/chrome_browser_application_mac.h"
-#import "chrome/browser/cocoa/applescript/error_applescript.h"
-#include "chrome/browser/profile.h"
-#import "chrome/browser/cocoa/applescript/bookmark_item_applescript.h"
-
-@interface BookmarkNodeAppleScript()
-@property (nonatomic, copy) NSString* tempTitle;
-@end
-
-@implementation BookmarkNodeAppleScript
-
-@synthesize tempTitle = tempTitle_;
-
-- (id)init {
- if ((self = [super init])) {
- BookmarkModel* model = [self bookmarkModel];
- if (!model) {
- [self release];
- return nil;
- }
-
- scoped_nsobject<NSNumber> numID(
- [[NSNumber alloc] initWithLongLong:model->next_node_id()]);
- [self setUniqueID:numID];
- [self setTempTitle:@""];
- }
- return self;
-}
-
-- (void)dealloc {
- [tempTitle_ release];
- [super dealloc];
-}
-
-
-- (id)initWithBookmarkNode:(const BookmarkNode*)aBookmarkNode {
- if (!aBookmarkNode) {
- [self release];
- return nil;
- }
-
- if ((self = [super init])) {
- // It is safe to be weak, if a bookmark item/folder goes away
- // (eg user deleting a folder) the applescript runtime calls
- // bookmarkFolders/bookmarkItems in BookmarkFolderAppleScript
- // and this particular bookmark item/folder is never returned.
- bookmarkNode_ = aBookmarkNode;
-
- scoped_nsobject<NSNumber> numID(
- [[NSNumber alloc] initWithLongLong:aBookmarkNode->id()]);
- [self setUniqueID:numID];
- }
- return self;
-}
-
-- (void)setBookmarkNode:(const BookmarkNode*)aBookmarkNode {
- DCHECK(aBookmarkNode);
- // It is safe to be weak, if a bookmark item/folder goes away
- // (eg user deleting a folder) the applescript runtime calls
- // bookmarkFolders/bookmarkItems in BookmarkFolderAppleScript
- // and this particular bookmark item/folder is never returned.
- bookmarkNode_ = aBookmarkNode;
-
- scoped_nsobject<NSNumber> numID(
- [[NSNumber alloc] initWithLongLong:aBookmarkNode->id()]);
- [self setUniqueID:numID];
-
- [self setTitle:[self tempTitle]];
-}
-
-- (NSString*)title {
- if (!bookmarkNode_)
- return tempTitle_;
-
- return base::SysUTF16ToNSString(bookmarkNode_->GetTitle());
-}
-
-- (void)setTitle:(NSString*)aTitle {
- // If the scripter enters |make new bookmarks folder with properties
- // {title:"foo"}|, the node has not yet been created so title is stored in the
- // temp title.
- if (!bookmarkNode_) {
- [self setTempTitle:aTitle];
- return;
- }
-
- BookmarkModel* model = [self bookmarkModel];
- if (!model)
- return;
-
- model->SetTitle(bookmarkNode_, base::SysNSStringToUTF16(aTitle));
-}
-
-- (NSNumber*)index {
- const BookmarkNode* parent = bookmarkNode_->GetParent();
- int index = parent->IndexOfChild(bookmarkNode_);
- // NOTE: AppleScript is 1-Based.
- return [NSNumber numberWithInt:index+1];
-}
-
-- (BookmarkModel*)bookmarkModel {
- AppController* appDelegate = [NSApp delegate];
-
- Profile* defaultProfile = [appDelegate defaultProfile];
- if (!defaultProfile) {
- AppleScript::SetError(AppleScript::errGetProfile);
- return NULL;
- }
-
- BookmarkModel* model = defaultProfile->GetBookmarkModel();
- if (!model->IsLoaded()) {
- AppleScript::SetError(AppleScript::errBookmarkModelLoad);
- return NULL;
- }
-
- return model;
-}
-
-@end
diff --git a/chrome/browser/cocoa/applescript/browsercrapplication+applescript.h b/chrome/browser/cocoa/applescript/browsercrapplication+applescript.h
deleted file mode 100644
index 527df48..0000000
--- a/chrome/browser/cocoa/applescript/browsercrapplication+applescript.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_APPLESCRIPT_BROWSERCRAPPLICATION_APPLESCRIPT_H_
-#define CHROME_BROWSER_COCOA_APPLESCRIPT_BROWSERCRAPPLICATION_APPLESCRIPT_H_
-
-#import <Cocoa/Cocoa.h>
-
-#import "chrome/browser/chrome_browser_application_mac.h"
-
-@class BookmarkFolderAppleScript;
-@class WindowAppleScript;
-
-// Represent the top level application scripting object in applescript.
-@interface BrowserCrApplication (AppleScriptAdditions)
-
-// Application window manipulation methods.
-// Returns an array of |WindowAppleScript*| of all windows present in the
-// application.
-- (NSArray*)appleScriptWindows;
-
-// Inserts a window at the beginning.
-- (void)insertInAppleScriptWindows:(WindowAppleScript*)aWindow;
-
-// Inserts a window at some position in the list.
-// Called by applescript which takes care of bounds checking, make sure of it
-// before calling directly.
-- (void)insertInAppleScriptWindows:(WindowAppleScript*)aWindow
- atIndex:(int)index;
-
-// Removes a window from the list.
-// Called by applescript which takes care of bounds checking, make sure of it
-// before calling directly.
-- (void)removeFromAppleScriptWindowsAtIndex:(int)index;
-
-// Always returns nil to indicate that it is the root container object.
-- (NSScriptObjectSpecifier*)objectSpecifier;
-
-// Returns the other bookmarks bookmark folder,
-// returns nil if there is an error.
-- (BookmarkFolderAppleScript*)otherBookmarks;
-
-// Returns the bookmarks bar bookmark folder, return nil if there is an error.
-- (BookmarkFolderAppleScript*)bookmarksBar;
-
-// Returns the Bookmarks Bar and Other Bookmarks Folders, each is of type
-// |BookmarkFolderAppleScript*|.
-- (NSArray*)bookmarkFolders;
-
-// Required functions, even though bookmarkFolders is declared as
-// read-only, cocoa scripting does not currently prevent writing.
-- (void)insertInBookmarksFolders:(id)aBookmarkFolder;
-- (void)insertInBookmarksFolders:(id)aBookmarkFolder atIndex:(int)index;
-- (void)removeFromBookmarksFoldersAtIndex:(int)index;
-
-@end
-
-#endif// CHROME_BROWSER_COCOA_APPLESCRIPT_BROWSERCRAPPLICATION_APPLESCRIPT_H_
diff --git a/chrome/browser/cocoa/applescript/browsercrapplication+applescript.mm b/chrome/browser/cocoa/applescript/browsercrapplication+applescript.mm
deleted file mode 100644
index 1ac4165..0000000
--- a/chrome/browser/cocoa/applescript/browsercrapplication+applescript.mm
+++ /dev/null
@@ -1,136 +0,0 @@
-// 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 "chrome/browser/cocoa/applescript/browsercrapplication+applescript.h"
-
-#include "base/logging.h"
-#import "base/scoped_nsobject.h"
-#import "chrome/browser/app_controller_mac.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#include "chrome/browser/browser_list.h"
-#import "chrome/browser/cocoa/applescript/bookmark_folder_applescript.h"
-#import "chrome/browser/cocoa/applescript/constants_applescript.h"
-#import "chrome/browser/cocoa/applescript/error_applescript.h"
-#import "chrome/browser/cocoa/applescript/window_applescript.h"
-#include "chrome/browser/profile.h"
-
-@implementation BrowserCrApplication (AppleScriptAdditions)
-
-- (NSArray*)appleScriptWindows {
- NSMutableArray* appleScriptWindows = [NSMutableArray
- arrayWithCapacity:BrowserList::size()];
- // Iterate through all browsers and check if it closing,
- // if not add it to list.
- for (BrowserList::const_iterator browserIterator = BrowserList::begin();
- browserIterator != BrowserList::end(); ++browserIterator) {
- if ((*browserIterator)->IsAttemptingToCloseBrowser())
- continue;
-
- scoped_nsobject<WindowAppleScript> window(
- [[WindowAppleScript alloc] initWithBrowser:*browserIterator]);
- [window setContainer:NSApp
- property:AppleScript::kWindowsProperty];
- [appleScriptWindows addObject:window];
- }
- // Windows sorted by their index value, which is obtained by calling
- // orderedIndex: on each window.
- [appleScriptWindows sortUsingSelector:@selector(windowComparator:)];
- return appleScriptWindows;
-}
-
-- (void)insertInAppleScriptWindows:(WindowAppleScript*)aWindow {
- // This method gets called when a new window is created so
- // the container and property are set here.
- [aWindow setContainer:self
- property:AppleScript::kWindowsProperty];
-}
-
-- (void)insertInAppleScriptWindows:(WindowAppleScript*)aWindow
- atIndex:(int)index {
- // This method gets called when a new window is created so
- // the container and property are set here.
- [aWindow setContainer:self
- property:AppleScript::kWindowsProperty];
- // Note: AppleScript is 1-based.
- index--;
- [aWindow setOrderedIndex:[NSNumber numberWithInt:index]];
-}
-
-- (void)removeFromAppleScriptWindowsAtIndex:(int)index {
- [[[self appleScriptWindows] objectAtIndex:index]
- handlesCloseScriptCommand:nil];
-}
-
-- (NSScriptObjectSpecifier*)objectSpecifier {
- return nil;
-}
-
-- (BookmarkFolderAppleScript*)otherBookmarks {
- AppController* appDelegate = [NSApp delegate];
-
- Profile* defaultProfile = [appDelegate defaultProfile];
- if (!defaultProfile) {
- AppleScript::SetError(AppleScript::errGetProfile);
- return nil;
- }
-
- BookmarkModel* model = defaultProfile->GetBookmarkModel();
- if (!model->IsLoaded()) {
- AppleScript::SetError(AppleScript::errBookmarkModelLoad);
- return nil;
- }
-
- BookmarkFolderAppleScript* otherBookmarks =
- [[[BookmarkFolderAppleScript alloc]
- initWithBookmarkNode:model->other_node()] autorelease];
- [otherBookmarks setContainer:self
- property:AppleScript::kBookmarkFoldersProperty];
- return otherBookmarks;
-}
-
-- (BookmarkFolderAppleScript*)bookmarksBar {
- AppController* appDelegate = [NSApp delegate];
-
- Profile* defaultProfile = [appDelegate defaultProfile];
- if (!defaultProfile) {
- AppleScript::SetError(AppleScript::errGetProfile);
- return nil;
- }
-
- BookmarkModel* model = defaultProfile->GetBookmarkModel();
- if (!model->IsLoaded()) {
- AppleScript::SetError(AppleScript::errBookmarkModelLoad);
- return NULL;
- }
-
- BookmarkFolderAppleScript* bookmarksBar =
- [[[BookmarkFolderAppleScript alloc]
- initWithBookmarkNode:model->GetBookmarkBarNode()] autorelease];
- [bookmarksBar setContainer:self
- property:AppleScript::kBookmarkFoldersProperty];
- return bookmarksBar;
-}
-
-- (NSArray*)bookmarkFolders {
- BookmarkFolderAppleScript* otherBookmarks = [self otherBookmarks];
- BookmarkFolderAppleScript* bookmarksBar = [self bookmarksBar];
- NSArray* folderArray = [NSArray arrayWithObjects:otherBookmarks,
- bookmarksBar,
- nil];
- return folderArray;
-}
-
-- (void)insertInBookmarksFolders:(id)aBookmarkFolder {
- NOTIMPLEMENTED();
-}
-
-- (void)insertInBookmarksFolders:(id)aBookmarkFolder atIndex:(int)index {
- NOTIMPLEMENTED();
-}
-
-- (void)removeFromBookmarksFoldersAtIndex:(int)index {
- NOTIMPLEMENTED();
-}
-
-@end
diff --git a/chrome/browser/cocoa/applescript/browsercrapplication+applescript_test.mm b/chrome/browser/cocoa/applescript/browsercrapplication+applescript_test.mm
deleted file mode 100644
index 15c654f..0000000
--- a/chrome/browser/cocoa/applescript/browsercrapplication+applescript_test.mm
+++ /dev/null
@@ -1,107 +0,0 @@
-// 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>
-
-#import "chrome/browser/cocoa/applescript/browsercrapplication+applescript.h"
-#import "chrome/browser/cocoa/applescript/constants_applescript.h"
-#import "chrome/browser/cocoa/applescript/window_applescript.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/test/in_process_browser_test.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/gtest_mac.h"
-
-typedef InProcessBrowserTest BrowserCrApplicationAppleScriptTest;
-
-// Create windows of different |Type|.
-IN_PROC_BROWSER_TEST_F(BrowserCrApplicationAppleScriptTest, Creation) {
- // Create additional |Browser*| objects of different type.
- Profile* profile = browser()->profile();
- Browser* b1 = Browser::CreateForType(Browser::TYPE_POPUP, profile);
- Browser* b2 = Browser::CreateForApp("", NULL, profile, true);
- Browser* b3 = Browser::CreateForApp("", NULL, profile, false);
-
- EXPECT_EQ(4U, [[NSApp appleScriptWindows] count]);
- for (WindowAppleScript* window in [NSApp appleScriptWindows]) {
- EXPECT_NSEQ(AppleScript::kWindowsProperty,
- [window containerProperty]);
- EXPECT_NSEQ(NSApp, [window container]);
- }
-
- // Close the additional browsers.
- b1->CloseAllTabs();
- b2->CloseAllTabs();
- b3->CloseAllTabs();
-}
-
-// Insert a new window.
-IN_PROC_BROWSER_TEST_F(BrowserCrApplicationAppleScriptTest, InsertWindow) {
- // Emulate what applescript would do when creating a new window.
- // Emulate a script like |set var to make new window with properties
- // {visible:false}|.
- scoped_nsobject<WindowAppleScript> aWindow([[WindowAppleScript alloc] init]);
- scoped_nsobject<NSNumber> var([[aWindow.get() uniqueID] copy]);
- [aWindow.get() setValue:[NSNumber numberWithBool:YES] forKey:@"isVisible"];
-
- [NSApp insertInAppleScriptWindows:aWindow.get()];
-
- // Represents the window after it is added.
- WindowAppleScript* window = [[NSApp appleScriptWindows] objectAtIndex:0];
- EXPECT_NSEQ([NSNumber numberWithBool:YES],
- [aWindow.get() valueForKey:@"isVisible"]);
- EXPECT_EQ([window container], NSApp);
- EXPECT_NSEQ(AppleScript::kWindowsProperty,
- [window containerProperty]);
- EXPECT_NSEQ(var, [window uniqueID]);
-}
-
-// Inserting and deleting windows.
-IN_PROC_BROWSER_TEST_F(BrowserCrApplicationAppleScriptTest,
- InsertAndDeleteWindows) {
- scoped_nsobject<WindowAppleScript> aWindow;
- int count;
- // Create a bunch of windows.
- for (int i = 0; i < 5; ++i) {
- for (int j = 0; j < 3; ++j) {
- aWindow.reset([[WindowAppleScript alloc] init]);
- [NSApp insertInAppleScriptWindows:aWindow.get()];
- }
- count = 3 * i + 4;
- EXPECT_EQ(count, (int)[[NSApp appleScriptWindows] count]);
- }
-
- // Remove all the windows, just created.
- count = (int)[[NSApp appleScriptWindows] count];
- for (int i = 0; i < 5; ++i) {
- for(int j = 0; j < 3; ++j) {
- [NSApp removeFromAppleScriptWindowsAtIndex:0];
- }
- count = count - 3;
- EXPECT_EQ(count, (int)[[NSApp appleScriptWindows] count]);
- }
-}
-
-// Check for objectSpecifer of the root scripting object.
-IN_PROC_BROWSER_TEST_F(BrowserCrApplicationAppleScriptTest, ObjectSpecifier) {
- // Should always return nil to indicate its the root scripting object.
- EXPECT_EQ(nil, [NSApp objectSpecifier]);
-}
-
-// Bookmark folders at the root level.
-IN_PROC_BROWSER_TEST_F(BrowserCrApplicationAppleScriptTest, BookmarkFolders) {
- NSArray* bookmarkFolders = [NSApp bookmarkFolders];
- EXPECT_EQ(2U, [bookmarkFolders count]);
-
- for (BookmarkFolderAppleScript* bookmarkFolder in bookmarkFolders) {
- EXPECT_EQ(NSApp,
- [bookmarkFolder container]);
- EXPECT_NSEQ(AppleScript::kBookmarkFoldersProperty,
- [bookmarkFolder containerProperty]);
- }
-
- EXPECT_NSEQ(@"Other Bookmarks", [[NSApp otherBookmarks] title]);
- EXPECT_NSEQ(@"Bookmarks Bar", [[NSApp bookmarksBar] title]);
-}
-
diff --git a/chrome/browser/cocoa/applescript/constants_applescript.h b/chrome/browser/cocoa/applescript/constants_applescript.h
deleted file mode 100644
index 13a96df..0000000
--- a/chrome/browser/cocoa/applescript/constants_applescript.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_APPLESCRIPT_CONSTANTS_APPLESCRIPT_H_
-#define CHROME_BROWSER_COCOA_APPLESCRIPT_CONSTANTS_APPLESCRIPT_H_
-
-#import <Cocoa/Cocoa.h>
-
-// This file contains the constant that are use to set the property of an
-// applescript scriptable item.
-namespace AppleScript {
-// Property to access windows.
-extern NSString* const kWindowsProperty;
-
-// Property to access tabs.
-extern NSString* const kTabsProperty;
-
-// Property to access bookmarks folders.
-extern NSString* const kBookmarkFoldersProperty;
-
-// Property to access bookmark items.
-extern NSString* const kBookmarkItemsProperty;
-
-// To indicate a window in normal mode.
-extern NSString* const kNormalWindowMode;
-
-// To indicate a window in incognito mode.
-extern NSString* const kIncognitoWindowMode;
-}
-#endif // CHROME_BROWSER_COCOA_APPLESCRIPT_CONSTANTS_APPLESCRIPT_H_
diff --git a/chrome/browser/cocoa/applescript/constants_applescript.mm b/chrome/browser/cocoa/applescript/constants_applescript.mm
deleted file mode 100644
index 3eddc9a..0000000
--- a/chrome/browser/cocoa/applescript/constants_applescript.mm
+++ /dev/null
@@ -1,25 +0,0 @@
-// 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 "chrome/browser/cocoa/applescript/constants_applescript.h"
-
-namespace AppleScript {
-// Property to access windows.
-NSString* const kWindowsProperty = @"appleScriptWindows";
-
-// Property to access tabs.
-NSString* const kTabsProperty = @"tabs";
-
-// Property to access bookmarks folders.
-NSString* const kBookmarkFoldersProperty = @"bookmarkFolders";
-
-// Property to access bookmark items.
-NSString* const kBookmarkItemsProperty = @"bookmarkItems";
-
-// To indicate a window in normal mode.
-NSString* const kNormalWindowMode = @"normal";
-
-// To indicate a window in incognito mode.
-NSString* const kIncognitoWindowMode = @"incognito";
-}
diff --git a/chrome/browser/cocoa/applescript/element_applescript.h b/chrome/browser/cocoa/applescript/element_applescript.h
deleted file mode 100644
index ba3d65c..0000000
--- a/chrome/browser/cocoa/applescript/element_applescript.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_APPLESCRIPT_ELEMENT_APPLESCRIPT_H_
-#define CHROME_BROWSER_COCOA_APPLESCRIPT_ELEMENT_APPLESCRIPT_H_
-
-#import <Cocoa/Cocoa.h>
-
-// This class is the root class for all the other applescript classes.
-// It takes care of all the infrastructure type operations.
-@interface ElementAppleScript : NSObject {
- @protected
- // Used by the applescript runtime to identify each unique scriptable object.
- NSNumber* uniqueID_;
- // Used by object specifier to find a scriptable object's place in a
- // collection.
- id container_;
- NSString* containerProperty_;
-}
-
-@property (nonatomic, copy) NSNumber* uniqueID;
-@property (nonatomic, retain) id container;
-@property (nonatomic, copy) NSString* containerProperty;
-
-// Calculates the objectspecifier by using the uniqueID, container and
-// container property.
-// An object specifier is used to identify objects within a
-// collection.
-- (NSScriptObjectSpecifier*)objectSpecifier;
-
-// Sets both container and property, retains container and copies property.
-- (void)setContainer:(id)value property:(NSString*)property;
-
-@end
-
-#endif// CHROME_BROWSER_COCOA_APPLESCRIPT_ELEMENT_APPLESCRIPT_H_
diff --git a/chrome/browser/cocoa/applescript/element_applescript.mm b/chrome/browser/cocoa/applescript/element_applescript.mm
deleted file mode 100644
index 270fd25..0000000
--- a/chrome/browser/cocoa/applescript/element_applescript.mm
+++ /dev/null
@@ -1,38 +0,0 @@
-// 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 "chrome/browser/cocoa/applescript/element_applescript.h"
-
-@implementation ElementAppleScript
-
-@synthesize uniqueID = uniqueID_;
-@synthesize container = container_;
-@synthesize containerProperty = containerProperty_;
-
-// calling objectSpecifier asks an object to return an object specifier
-// record referring to itself. You must call setContainer:property: before
-// you can call this method.
-- (NSScriptObjectSpecifier*)objectSpecifier {
- return [[NSUniqueIDSpecifier allocWithZone:[self zone]]
- initWithContainerClassDescription:
- (NSScriptClassDescription*)[[self container] classDescription]
- containerSpecifier:
- [[self container] objectSpecifier]
- key:[self containerProperty]
- uniqueID:[self uniqueID]];
-}
-
-- (void)setContainer:(id)value property:(NSString*)property {
- [self setContainer:value];
- [self setContainerProperty:property];
-}
-
-- (void)dealloc {
- [uniqueID_ release];
- [container_ release];
- [containerProperty_ release];
- [super dealloc];
-}
-
-@end
diff --git a/chrome/browser/cocoa/applescript/error_applescript.h b/chrome/browser/cocoa/applescript/error_applescript.h
deleted file mode 100644
index 2635b2f..0000000
--- a/chrome/browser/cocoa/applescript/error_applescript.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_APPLESCRIPT_ERROR_APPLESCRIPT_H_
-#define CHROME_BROWSER_COCOA_APPLESCRIPT_ERROR_APPLESCRIPT_H_
-
-#import <Cocoa/Cocoa.h>
-
-namespace AppleScript {
-
-enum ErrorCode {
- // Error when default profile cannot be obtained.
- errGetProfile = 1,
- // Error when bookmark model fails to load.
- errBookmarkModelLoad,
- // Error when bookmark folder cannot be created.
- errCreateBookmarkFolder,
- // Error when bookmark item cannot be created.
- errCreateBookmarkItem,
- // Error when URL entered is invalid.
- errInvalidURL,
- // Error when printing cannot be initiated.
- errInitiatePrinting,
- // Error when invalid tab save type is entered.
- errInvalidSaveType,
- // Error when invalid browser mode is entered.
- errInvalidMode,
- // Error when tab index is out of bounds.
- errInvalidTabIndex,
- // Error when mode is set after browser window is created.
- errSetMode,
- // Error when index of browser window is out of bounds.
- errWrongIndex
-};
-
-// This function sets an error message to the currently executing command.
-void SetError(ErrorCode errorCode);
-}
-
-#endif // CHROME_BROWSER_COCOA_APPLESCRIPT_ERROR_APPLESCRIPT_H_
diff --git a/chrome/browser/cocoa/applescript/error_applescript.mm b/chrome/browser/cocoa/applescript/error_applescript.mm
deleted file mode 100644
index cc25ad3..0000000
--- a/chrome/browser/cocoa/applescript/error_applescript.mm
+++ /dev/null
@@ -1,56 +0,0 @@
-// 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 "chrome/browser/cocoa/applescript/error_applescript.h"
-
-#import "app/l10n_util_mac.h"
-#include "base/logging.h"
-#include "grit/generated_resources.h"
-
-void AppleScript::SetError(AppleScript::ErrorCode errorCode) {
- using namespace l10n_util;
- NSScriptCommand* current_command = [NSScriptCommand currentCommand];
- [current_command setScriptErrorNumber:(int)errorCode];
- NSString* error_string = @"";
- switch (errorCode) {
- case errGetProfile:
- error_string = GetNSString(IDS_GET_PROFILE_ERROR_APPLESCRIPT_MAC);
- break;
- case errBookmarkModelLoad:
- error_string = GetNSString(IDS_BOOKMARK_MODEL_LOAD_ERROR_APPLESCRIPT_MAC);
- break;
- case errCreateBookmarkFolder:
- error_string =
- GetNSString(IDS_CREATE_BOOKMARK_FOLDER_ERROR_APPLESCRIPT_MAC);
- break;
- case errCreateBookmarkItem:
- error_string =
- GetNSString(IDS_CREATE_BOOKMARK_ITEM_ERROR_APPLESCRIPT_MAC);
- break;
- case errInvalidURL:
- error_string = GetNSString(IDS_INVALID_URL_APPLESCRIPT_MAC);
- break;
- case errInitiatePrinting:
- error_string = GetNSString(IDS_INITIATE_PRINTING_ERROR_APPLESCRIPT_MAC);
- break;
- case errInvalidSaveType:
- error_string = GetNSString(IDS_INVALID_SAVE_TYPE_ERROR_APPLESCRIPT_MAC);
- break;
- case errInvalidMode:
- error_string = GetNSString(IDS_INVALID_MODE_ERROR_APPLESCRIPT_MAC);
- break;
- case errInvalidTabIndex:
- error_string = GetNSString(IDS_INVALID_TAB_INDEX_APPLESCRIPT_MAC);
- break;
- case errSetMode:
- error_string = GetNSString(IDS_SET_MODE_APPLESCRIPT_MAC);
- break;
- case errWrongIndex:
- error_string = GetNSString(IDS_WRONG_INDEX_ERROR_APPLESCRIPT_MAC);
- break;
- default:
- NOTREACHED();
- }
- [current_command setScriptErrorString:error_string];
-}
diff --git a/chrome/browser/cocoa/applescript/tab_applescript.h b/chrome/browser/cocoa/applescript/tab_applescript.h
deleted file mode 100644
index 28ba1fe..0000000
--- a/chrome/browser/cocoa/applescript/tab_applescript.h
+++ /dev/null
@@ -1,79 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_APPLESCRIPT_TAB_APPLESCRIPT_H_
-#define CHROME_BROWSER_COCOA_APPLESCRIPT_TAB_APPLESCRIPT_H_
-
-#import <Cocoa/Cocoa.h>
-
-#import "chrome/browser/cocoa/applescript/element_applescript.h"
-
-class TabContents;
-
-// Represents a tab scriptable item in applescript.
-@interface TabAppleScript : ElementAppleScript {
- @private
- TabContents* tabContents_; // weak.
- // Contains the temporary URL when a user creates a new folder/item with
- // url specified like
- // |make new tab with properties {url:"http://google.com"}|.
- NSString* tempURL_;
-}
-
-// Doesn't actually create the tab here but just assigns the ID, tab is created
-// when it calls insertInTabs: of a particular window, it is used in cases
-// where user assigns a tab to a variable like |set var to make new tab|.
-- (id)init;
-
-// Does not create a new tab but uses an existing one.
-- (id)initWithTabContent:(TabContents*)aTabContent;
-
-// Assigns a tab, sets its unique ID and also copies temporary values.
-- (void)setTabContent:(TabContents*)aTabContent;
-
-// Return the URL currently visible to the user in the location bar.
-- (NSString*)URL;
-
-// Sets the URL, returns an error if it is invalid.
-- (void)setURL:(NSString*)aURL;
-
-// The title of the tab.
-- (NSString*)title;
-
-// Is the tab loading any resource?
-- (NSNumber*)loading;
-
-// Standard user commands.
-- (void)handlesUndoScriptCommand:(NSScriptCommand*)command;
-- (void)handlesRedoScriptCommand:(NSScriptCommand*)command;
-
-// Edit operations on the page.
-- (void)handlesCutScriptCommand:(NSScriptCommand*)command;
-- (void)handlesCopyScriptCommand:(NSScriptCommand*)command;
-- (void)handlesPasteScriptCommand:(NSScriptCommand*)command;
-
-// Selects all contents on the page.
-- (void)handlesSelectAllScriptCommand:(NSScriptCommand*)command;
-
-// Navigation operations.
-- (void)handlesGoBackScriptCommand:(NSScriptCommand*)command;
-- (void)handlesGoForwardScriptCommand:(NSScriptCommand*)command;
-- (void)handlesReloadScriptCommand:(NSScriptCommand*)command;
-- (void)handlesStopScriptCommand:(NSScriptCommand*)command;
-
-// Used to print a tab.
-- (void)handlesPrintScriptCommand:(NSScriptCommand*)command;
-
-// Used to save a tab, if no file is specified, prompts the user to enter it.
-- (void)handlesSaveScriptCommand:(NSScriptCommand*)command;
-
-// Displays the HTML of the tab in a new tab.
-- (void)handlesViewSourceScriptCommand:(NSScriptCommand*)command;
-
-// Executes a piece of javascript in the tab.
-- (id)handlesExecuteJavascriptScriptCommand:(NSScriptCommand*)command;
-
-@end
-
-#endif// CHROME_BROWSER_COCOA_APPLESCRIPT_TAB_APPLESCRIPT_H_
diff --git a/chrome/browser/cocoa/applescript/tab_applescript.mm b/chrome/browser/cocoa/applescript/tab_applescript.mm
deleted file mode 100644
index ee4af12..0000000
--- a/chrome/browser/cocoa/applescript/tab_applescript.mm
+++ /dev/null
@@ -1,296 +0,0 @@
-// 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 "chrome/browser/cocoa/applescript/tab_applescript.h"
-
-#include "base/file_path.h"
-#include "base/logging.h"
-#import "base/scoped_nsobject.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/cocoa/applescript/error_applescript.h"
-#include "chrome/browser/download/save_package.h"
-#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/tab_contents/navigation_controller.h"
-#include "chrome/browser/tab_contents/navigation_entry.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/sessions/session_id.h"
-#include "chrome/common/url_constants.h"
-#include "googleurl/src/gurl.h"
-
-@interface TabAppleScript()
-@property (nonatomic, copy) NSString* tempURL;
-@end
-
-@implementation TabAppleScript
-
-@synthesize tempURL = tempURL_;
-
-- (id)init {
- if ((self = [super init])) {
- SessionID session;
- SessionID::id_type futureSessionIDOfTab = session.id() + 1;
- // Holds the SessionID that the new tab is going to get.
- scoped_nsobject<NSNumber> numID(
- [[NSNumber alloc]
- initWithInt:futureSessionIDOfTab]);
- [self setUniqueID:numID];
- [self setTempURL:@""];
- }
- return self;
-}
-
-- (void)dealloc {
- [tempURL_ release];
- [super dealloc];
-}
-
-- (id)initWithTabContent:(TabContents*)aTabContent {
- if (!aTabContent) {
- [self release];
- return nil;
- }
-
- if ((self = [super init])) {
- // It is safe to be weak, if a tab goes away (eg user closing a tab)
- // the applescript runtime calls tabs in AppleScriptWindow and this
- // particular tab is never returned.
- tabContents_ = aTabContent;
- scoped_nsobject<NSNumber> numID(
- [[NSNumber alloc]
- initWithInt:tabContents_->controller().session_id().id()]);
- [self setUniqueID:numID];
- }
- return self;
-}
-
-- (void)setTabContent:(TabContents*)aTabContent {
- DCHECK(aTabContent);
- // It is safe to be weak, if a tab goes away (eg user closing a tab)
- // the applescript runtime calls tabs in AppleScriptWindow and this
- // particular tab is never returned.
- tabContents_ = aTabContent;
- scoped_nsobject<NSNumber> numID(
- [[NSNumber alloc]
- initWithInt:tabContents_->controller().session_id().id()]);
- [self setUniqueID:numID];
-
- [self setURL:[self tempURL]];
-}
-
-- (NSString*)URL {
- if (!tabContents_) {
- return nil;
- }
-
- NavigationEntry* entry = tabContents_->controller().GetActiveEntry();
- if (!entry) {
- return nil;
- }
- const GURL& url = entry->virtual_url();
- return base::SysUTF8ToNSString(url.spec());
-}
-
-- (void)setURL:(NSString*)aURL {
- // If a scripter sets a URL before the node is added save it at a temporary
- // location.
- if (!tabContents_) {
- [self setTempURL:aURL];
- return;
- }
-
- GURL url(base::SysNSStringToUTF8(aURL));
- // check for valid url.
- if (!url.is_empty() && !url.is_valid()) {
- AppleScript::SetError(AppleScript::errInvalidURL);
- return;
- }
-
- NavigationEntry* entry = tabContents_->controller().GetActiveEntry();
- if (!entry)
- return;
-
- const GURL& previousURL = entry->virtual_url();
- tabContents_->OpenURL(url,
- previousURL,
- CURRENT_TAB,
- PageTransition::TYPED);
-}
-
-- (NSString*)title {
- NavigationEntry* entry = tabContents_->controller().GetActiveEntry();
- if (!entry)
- return nil;
-
- std::wstring title;
- if (entry != NULL) {
- title = UTF16ToWideHack(entry->title());
- }
-
- return base::SysWideToNSString(title);
-}
-
-- (NSNumber*)loading {
- BOOL loadingValue = tabContents_->is_loading() ? YES : NO;
- return [NSNumber numberWithBool:loadingValue];
-}
-
-- (void)handlesUndoScriptCommand:(NSScriptCommand*)command {
- RenderViewHost* view = tabContents_->render_view_host();
- if (!view) {
- NOTREACHED();
- return;
- }
-
- view->Undo();
-}
-
-- (void)handlesRedoScriptCommand:(NSScriptCommand*)command {
- RenderViewHost* view = tabContents_->render_view_host();
- if (!view) {
- NOTREACHED();
- return;
- }
-
- view->Redo();
-}
-
-- (void)handlesCutScriptCommand:(NSScriptCommand*)command {
- RenderViewHost* view = tabContents_->render_view_host();
- if (!view) {
- NOTREACHED();
- return;
- }
-
- view->Cut();
-}
-
-- (void)handlesCopyScriptCommand:(NSScriptCommand*)command {
- RenderViewHost* view = tabContents_->render_view_host();
- if (!view) {
- NOTREACHED();
- return;
- }
-
- view->Copy();
-}
-
-- (void)handlesPasteScriptCommand:(NSScriptCommand*)command {
- RenderViewHost* view = tabContents_->render_view_host();
- if (!view) {
- NOTREACHED();
- return;
- }
-
- view->Paste();
-}
-
-- (void)handlesSelectAllScriptCommand:(NSScriptCommand*)command {
- RenderViewHost* view = tabContents_->render_view_host();
- if (!view) {
- NOTREACHED();
- return;
- }
-
- view->SelectAll();
-}
-
-- (void)handlesGoBackScriptCommand:(NSScriptCommand*)command {
- NavigationController& navigationController = tabContents_->controller();
- if (navigationController.CanGoBack())
- navigationController.GoBack();
-}
-
-- (void)handlesGoForwardScriptCommand:(NSScriptCommand*)command {
- NavigationController& navigationController = tabContents_->controller();
- if (navigationController.CanGoForward())
- navigationController.GoForward();
-}
-
-- (void)handlesReloadScriptCommand:(NSScriptCommand*)command {
- NavigationController& navigationController = tabContents_->controller();
- const bool checkForRepost = true;
- navigationController.Reload(checkForRepost);
-}
-
-- (void)handlesStopScriptCommand:(NSScriptCommand*)command {
- RenderViewHost* view = tabContents_->render_view_host();
- if (!view) {
- // We tolerate Stop being called even before a view has been created.
- // So just log a warning instead of a NOTREACHED().
- DLOG(WARNING) << "Stop: no view for handle ";
- return;
- }
-
- view->Stop();
-}
-
-- (void)handlesPrintScriptCommand:(NSScriptCommand*)command {
- bool initiateStatus = tabContents_->PrintNow();
- if (initiateStatus == false) {
- AppleScript::SetError(AppleScript::errInitiatePrinting);
- }
-}
-
-- (void)handlesSaveScriptCommand:(NSScriptCommand*)command {
- NSDictionary* dictionary = [command evaluatedArguments];
-
- NSURL* fileURL = [dictionary objectForKey:@"File"];
- // Scripter has not specifed the location at which to save, so we prompt for
- // it.
- if (!fileURL) {
- tabContents_->OnSavePage();
- return;
- }
-
- FilePath mainFile(base::SysNSStringToUTF8([fileURL path]));
- // We create a directory path at the folder within which the file exists.
- // Eg. if main_file = '/Users/Foo/Documents/Google.html'
- // then directory_path = '/Users/Foo/Documents/Google_files/'.
- FilePath directoryPath = mainFile.RemoveExtension();
- directoryPath = directoryPath.InsertBeforeExtension(std::string("_files/"));
-
- NSString* saveType = [dictionary objectForKey:@"FileType"];
-
- SavePackage::SavePackageType savePackageType =
- SavePackage::SAVE_AS_COMPLETE_HTML;
- if (saveType) {
- if ([saveType isEqualToString:@"only html"]) {
- savePackageType = SavePackage::SAVE_AS_ONLY_HTML;
- } else if ([saveType isEqualToString:@"complete html"]) {
- savePackageType = SavePackage::SAVE_AS_COMPLETE_HTML;
- } else {
- AppleScript::SetError(AppleScript::errInvalidSaveType);
- return;
- }
- }
-
- tabContents_->SavePage(mainFile, directoryPath, savePackageType);
-}
-
-
-- (void)handlesViewSourceScriptCommand:(NSScriptCommand*)command {
- NavigationEntry* entry = tabContents_->controller().GetLastCommittedEntry();
- if (entry) {
- tabContents_->OpenURL(GURL(chrome::kViewSourceScheme + std::string(":") +
- entry->url().spec()), GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
- }
-}
-
-- (id)handlesExecuteJavascriptScriptCommand:(NSScriptCommand*)command {
- RenderViewHost* view = tabContents_->render_view_host();
- if (!view) {
- NOTREACHED();
- return nil;
- }
-
- std::wstring script = base::SysNSStringToWide(
- [[command evaluatedArguments] objectForKey:@"javascript"]);
- view->ExecuteJavascriptInWebFrame(L"", script);
-
- // TODO(Shreyas): Figure out a way to get the response back.
- return nil;
-}
-
-@end
diff --git a/chrome/browser/cocoa/applescript/window_applescript.h b/chrome/browser/cocoa/applescript/window_applescript.h
deleted file mode 100644
index 5bda32f..0000000
--- a/chrome/browser/cocoa/applescript/window_applescript.h
+++ /dev/null
@@ -1,81 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_APPLESCRIPT_WINDOW_APPLESCRIPT_H_
-#define CHROME_BROWSER_COCOA_APPLESCRIPT_WINDOW_APPLESCRIPT_H_
-
-#import <Cocoa/Cocoa.h>
-
-#import "chrome/browser/cocoa/applescript/element_applescript.h"
-
-class Browser;
-class Profile;
-@class TabAppleScript;
-
-// Represents a window class.
-@interface WindowAppleScript : ElementAppleScript {
- @private
- Browser* browser_; // weak.
-}
-
-// Creates a new window, returns nil if there is an error.
-- (id)init;
-
-// Creates a new window with a particular profile.
-- (id)initWithProfile:(Profile*)aProfile;
-
-// Does not create a new window but uses an existing one.
-- (id)initWithBrowser:(Browser*)aBrowser;
-
-// Sets and gets the index of the currently selected tab.
-- (NSNumber*)activeTabIndex;
-- (void)setActiveTabIndex:(NSNumber*)anActiveTabIndex;
-
-// Mode refers to whether a window is a normal window or an incognito window
-// it can be set only once while creating the window.
-- (NSString*)mode;
-- (void)setMode:(NSString*)theMode;
-
-// Returns the currently selected tab.
-- (TabAppleScript*)activeTab;
-
-// Tab manipulation functions.
-// The tabs inside the window.
-// Returns |TabAppleScript*| of all the tabs contained
-// within this particular folder.
-- (NSArray*)tabs;
-
-// Insert a tab at the end.
-- (void)insertInTabs:(TabAppleScript*)aTab;
-
-// Insert a tab at some position in the list.
-// Called by applescript which takes care of bounds checking, make sure of it
-// before calling directly.
-- (void)insertInTabs:(TabAppleScript*)aTab atIndex:(int)index;
-
-// Remove a window from the list.
-// Called by applescript which takes care of bounds checking, make sure of it
-// before calling directly.
-- (void)removeFromTabsAtIndex:(int)index;
-
-// Set the index of a window.
-- (void)setOrderedIndex:(NSNumber*)anIndex;
-
-// Used to sort windows by index.
-- (NSComparisonResult)windowComparator:(WindowAppleScript*)otherWindow;
-
-// For standard window functions like zoomable, bounds etc, we dont handle it
-// but instead pass it onto the NSWindow associated with the window.
-- (id)valueForUndefinedKey:(NSString*)key;
-- (void)setValue:(id)value forUndefinedKey:(NSString*)key;
-
-// Used to close window.
-- (void)handlesCloseScriptCommand:(NSCloseCommand*)command;
-
-// The index of the window, windows are ordered front to back.
-- (NSNumber*)orderedIndex;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_APPLESCRIPT_WINDOW_APPLESCRIPT_H_
diff --git a/chrome/browser/cocoa/applescript/window_applescript.mm b/chrome/browser/cocoa/applescript/window_applescript.mm
deleted file mode 100644
index 0f279ac..0000000
--- a/chrome/browser/cocoa/applescript/window_applescript.mm
+++ /dev/null
@@ -1,246 +0,0 @@
-// 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 "chrome/browser/cocoa/applescript/window_applescript.h"
-
-#include "base/logging.h"
-#import "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-#include "base/time.h"
-#import "chrome/browser/app_controller_mac.h"
-#import "chrome/browser/chrome_browser_application_mac.h"
-#include "chrome/browser/cocoa/applescript/constants_applescript.h"
-#include "chrome/browser/cocoa/applescript/error_applescript.h"
-#import "chrome/browser/cocoa/applescript/tab_applescript.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
-#include "chrome/browser/tabs/tab_strip_model.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_list.h"
-#include "chrome/browser/ui/browser_navigator.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/common/url_constants.h"
-
-@interface WindowAppleScript(WindowAppleScriptPrivateMethods)
-// The NSWindow that corresponds to this window.
-- (NSWindow*)nativeHandle;
-@end
-
-@implementation WindowAppleScript
-
-- (id)init {
- // Check which mode to open a new window.
- NSScriptCommand* command = [NSScriptCommand currentCommand];
- NSString* mode = [[[command evaluatedArguments]
- objectForKey:@"KeyDictionary"] objectForKey:@"mode"];
- AppController* appDelegate = [NSApp delegate];
-
- Profile* defaultProfile = [appDelegate defaultProfile];
-
- if (!defaultProfile) {
- AppleScript::SetError(AppleScript::errGetProfile);
- return nil;
- }
-
- Profile* profile;
- if ([mode isEqualToString:AppleScript::kIncognitoWindowMode]) {
- profile = defaultProfile->GetOffTheRecordProfile();
- }
- else if ([mode isEqualToString:AppleScript::kNormalWindowMode] || !mode) {
- profile = defaultProfile;
- } else {
- // Mode cannot be anything else
- AppleScript::SetError(AppleScript::errInvalidMode);
- return nil;
- }
- // Set the mode to nil, to ensure that it is not set once more.
- [[[command evaluatedArguments] objectForKey:@"KeyDictionary"]
- setValue:nil forKey:@"mode"];
- return [self initWithProfile:profile];
-}
-
-- (id)initWithProfile:(Profile*)aProfile {
- if (!aProfile) {
- [self release];
- return nil;
- }
-
- if ((self = [super init])) {
- browser_ = Browser::Create(aProfile);
- browser_->NewTab();
- browser_->window()->Show();
- scoped_nsobject<NSNumber> numID(
- [[NSNumber alloc] initWithInt:browser_->session_id().id()]);
- [self setUniqueID:numID];
- }
- return self;
-}
-
-- (id)initWithBrowser:(Browser*)aBrowser {
- if (!aBrowser) {
- [self release];
- return nil;
- }
-
- if ((self = [super init])) {
- // It is safe to be weak, if a window goes away (eg user closing a window)
- // the applescript runtime calls appleScriptWindows in
- // BrowserCrApplication and this particular window is never returned.
- browser_ = aBrowser;
- scoped_nsobject<NSNumber> numID(
- [[NSNumber alloc] initWithInt:browser_->session_id().id()]);
- [self setUniqueID:numID];
- }
- return self;
-}
-
-- (NSWindow*)nativeHandle {
- // window() can be NULL during startup.
- if (browser_->window())
- return browser_->window()->GetNativeHandle();
- return nil;
-}
-
-- (NSNumber*)activeTabIndex {
- // Note: applescript is 1-based, that is lists begin with index 1.
- int activeTabIndex = browser_->selected_index() + 1;
- if (!activeTabIndex) {
- return nil;
- }
- return [NSNumber numberWithInt:activeTabIndex];
-}
-
-- (void)setActiveTabIndex:(NSNumber*)anActiveTabIndex {
- // Note: applescript is 1-based, that is lists begin with index 1.
- int atIndex = [anActiveTabIndex intValue] - 1;
- if (atIndex >= 0 && atIndex < browser_->tab_count())
- browser_->SelectTabContentsAt(atIndex, true);
- else
- AppleScript::SetError(AppleScript::errInvalidTabIndex);
-}
-
-- (NSString*)mode {
- Profile* profile = browser_->profile();
- if (profile->IsOffTheRecord())
- return AppleScript::kIncognitoWindowMode;
- return AppleScript::kNormalWindowMode;
-}
-
-- (void)setMode:(NSString*)theMode {
- // cannot set mode after window is created.
- if (theMode) {
- AppleScript::SetError(AppleScript::errSetMode);
- }
-}
-
-- (TabAppleScript*)activeTab {
- TabAppleScript* currentTab = [[[TabAppleScript alloc]
- initWithTabContent:browser_->GetSelectedTabContents()] autorelease];
- [currentTab setContainer:self
- property:AppleScript::kTabsProperty];
- return currentTab;
-}
-
-- (NSArray*)tabs {
- NSMutableArray* tabs = [NSMutableArray
- arrayWithCapacity:browser_->tab_count()];
-
- for (int i = 0; i < browser_->tab_count(); ++i) {
- // Check to see if tab is closing.
- if (browser_->GetTabContentsAt(i)->is_being_destroyed()) {
- continue;
- }
-
- scoped_nsobject<TabAppleScript> tab(
- [[TabAppleScript alloc]
- initWithTabContent:(browser_->GetTabContentsAt(i))]);
- [tab setContainer:self
- property:AppleScript::kTabsProperty];
- [tabs addObject:tab];
- }
- return tabs;
-}
-
-- (void)insertInTabs:(TabAppleScript*)aTab {
- // This method gets called when a new tab is created so
- // the container and property are set here.
- [aTab setContainer:self
- property:AppleScript::kTabsProperty];
-
- // Set how long it takes a tab to be created.
- base::TimeTicks newTabStartTime = base::TimeTicks::Now();
- TabContentsWrapper* contents =
- browser_->AddSelectedTabWithURL(GURL(chrome::kChromeUINewTabURL),
- PageTransition::TYPED);
- contents->tab_contents()->set_new_tab_start_time(newTabStartTime);
- [aTab setTabContent:contents->tab_contents()];
-}
-
-- (void)insertInTabs:(TabAppleScript*)aTab atIndex:(int)index {
- // This method gets called when a new tab is created so
- // This method gets called when a new tab is created so
- // the container and property are set here.
- [aTab setContainer:self
- property:AppleScript::kTabsProperty];
-
- // Set how long it takes a tab to be created.
- base::TimeTicks newTabStartTime = base::TimeTicks::Now();
- browser::NavigateParams params(browser_,
- GURL(chrome::kChromeUINewTabURL),
- PageTransition::TYPED);
- params.disposition = NEW_FOREGROUND_TAB;
- params.tabstrip_index = index;
- browser::Navigate(&params);
- params.target_contents->tab_contents()->set_new_tab_start_time(
- newTabStartTime);
-
- [aTab setTabContent:params.target_contents->tab_contents()];
-}
-
-- (void)removeFromTabsAtIndex:(int)index {
- browser_->tabstrip_model()->DetachTabContentsAt(index);
-}
-
-- (NSNumber*)orderedIndex{
- return [NSNumber numberWithInt:[[self nativeHandle] orderedIndex]];
-}
-
-- (void)setOrderedIndex:(NSNumber*)anIndex {
- int index = [anIndex intValue] - 1;
- if (index < 0 || index >= (int)BrowserList::size()) {
- AppleScript::SetError(AppleScript::errWrongIndex);
- return;
- }
- [[self nativeHandle] setOrderedIndex:index];
-}
-
-- (NSComparisonResult)windowComparator:(WindowAppleScript*)otherWindow {
- int thisIndex = [[self orderedIndex] intValue];
- int otherIndex = [[otherWindow orderedIndex] intValue];
- if (thisIndex < otherIndex)
- return NSOrderedAscending;
- else if (thisIndex > otherIndex)
- return NSOrderedDescending;
- // Indexes can never be same.
- NOTREACHED();
- return NSOrderedSame;
-}
-
-// Get and set values from the associated NSWindow.
-- (id)valueForUndefinedKey:(NSString*)key {
- return [[self nativeHandle] valueForKey:key];
-}
-
-- (void)setValue:(id)value forUndefinedKey:(NSString*)key {
- [[self nativeHandle] setValue:(id)value forKey:key];
-}
-
-- (void)handlesCloseScriptCommand:(NSCloseCommand*)command {
- // window() can be NULL during startup.
- if (browser_->window())
- browser_->window()->Close();
-}
-
-@end
diff --git a/chrome/browser/cocoa/applescript/window_applescript_test.mm b/chrome/browser/cocoa/applescript/window_applescript_test.mm
deleted file mode 100644
index 6d0a9d3..0000000
--- a/chrome/browser/cocoa/applescript/window_applescript_test.mm
+++ /dev/null
@@ -1,178 +0,0 @@
-// 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>
-
-#import "base/scoped_nsobject.h"
-#include "base/sys_string_conversions.h"
-#import "chrome/browser/app_controller_mac.h"
-#import "chrome/browser/chrome_browser_application_mac.h"
-#import "chrome/browser/cocoa/applescript/constants_applescript.h"
-#import "chrome/browser/cocoa/applescript/error_applescript.h"
-#import "chrome/browser/cocoa/applescript/tab_applescript.h"
-#import "chrome/browser/cocoa/applescript/window_applescript.h"
-#include "chrome/browser/profile.h"
-#include "chrome/test/in_process_browser_test.h"
-#include "googleurl/src/gurl.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-
-typedef InProcessBrowserTest WindowAppleScriptTest;
-
-// Create a window in default/normal mode.
-IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, DefaultCreation) {
- scoped_nsobject<WindowAppleScript> aWindow(
- [[WindowAppleScript alloc] init]);
- EXPECT_TRUE(aWindow.get());
- NSString* mode = [aWindow.get() mode];
- EXPECT_NSEQ(AppleScript::kNormalWindowMode,
- mode);
-}
-
-// Create a window with a |NULL profile|.
-IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, CreationWithNoProfile) {
- scoped_nsobject<WindowAppleScript> aWindow(
- [[WindowAppleScript alloc] initWithProfile:NULL]);
- EXPECT_FALSE(aWindow.get());
-}
-
-// Create a window with a particular profile.
-IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, CreationWithProfile) {
- Profile* defaultProfile = [[NSApp delegate] defaultProfile];
- scoped_nsobject<WindowAppleScript> aWindow(
- [[WindowAppleScript alloc] initWithProfile:defaultProfile]);
- EXPECT_TRUE(aWindow.get());
- EXPECT_TRUE([aWindow.get() uniqueID]);
-}
-
-// Create a window with no |Browser*|.
-IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, CreationWithNoBrowser) {
- scoped_nsobject<WindowAppleScript> aWindow(
- [[WindowAppleScript alloc] initWithBrowser:NULL]);
- EXPECT_FALSE(aWindow.get());
-}
-
-// Create a window with |Browser*| already present.
-IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, CreationWithBrowser) {
- scoped_nsobject<WindowAppleScript> aWindow(
- [[WindowAppleScript alloc] initWithBrowser:browser()]);
- EXPECT_TRUE(aWindow.get());
- EXPECT_TRUE([aWindow.get() uniqueID]);
-}
-
-// Tabs within the window.
-IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, Tabs) {
- scoped_nsobject<WindowAppleScript> aWindow(
- [[WindowAppleScript alloc] initWithBrowser:browser()]);
- NSArray* tabs = [aWindow.get() tabs];
- EXPECT_EQ(1U, [tabs count]);
- TabAppleScript* tab1 = [tabs objectAtIndex:0];
- EXPECT_EQ([tab1 container], aWindow.get());
- EXPECT_NSEQ(AppleScript::kTabsProperty,
- [tab1 containerProperty]);
-}
-
-// Insert a new tab.
-IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, InsertTab) {
- // Emulate what applescript would do when creating a new tab.
- // Emulates a script like |set var to make new tab with
- // properties URL:"http://google.com"}|.
- scoped_nsobject<TabAppleScript> aTab([[TabAppleScript alloc] init]);
- scoped_nsobject<NSNumber> var([[aTab.get() uniqueID] copy]);
- [aTab.get() setURL:@"http://google.com"];
- scoped_nsobject<WindowAppleScript> aWindow(
- [[WindowAppleScript alloc] initWithBrowser:browser()]);
- [aWindow.get() insertInTabs:aTab.get()];
-
- // Represents the tab after it is inserted.
- TabAppleScript* tab = [[aWindow.get() tabs] objectAtIndex:1];
- EXPECT_EQ(GURL("http://google.com"),
- GURL(base::SysNSStringToUTF8([tab URL])));
- EXPECT_EQ([tab container], aWindow.get());
- EXPECT_NSEQ(AppleScript::kTabsProperty,
- [tab containerProperty]);
- EXPECT_NSEQ(var.get(), [tab uniqueID]);
-}
-
-// Insert a new tab at a particular position
-IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, InsertTabAtPosition) {
- // Emulate what applescript would do when creating a new tab.
- // Emulates a script like |set var to make new tab with
- // properties URL:"http://google.com"} at before tab 1|.
- scoped_nsobject<TabAppleScript> aTab([[TabAppleScript alloc] init]);
- scoped_nsobject<NSNumber> var([[aTab.get() uniqueID] copy]);
- [aTab.get() setURL:@"http://google.com"];
- scoped_nsobject<WindowAppleScript> aWindow(
- [[WindowAppleScript alloc] initWithBrowser:browser()]);
- [aWindow.get() insertInTabs:aTab.get() atIndex:0];
-
- // Represents the tab after it is inserted.
- TabAppleScript* tab = [[aWindow.get() tabs] objectAtIndex:0];
- EXPECT_EQ(GURL("http://google.com"),
- GURL(base::SysNSStringToUTF8([tab URL])));
- EXPECT_EQ([tab container], aWindow.get());
- EXPECT_NSEQ(AppleScript::kTabsProperty, [tab containerProperty]);
- EXPECT_NSEQ(var.get(), [tab uniqueID]);
-}
-
-// Inserting and deleting tabs.
-IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, InsertAndDeleteTabs) {
- scoped_nsobject<WindowAppleScript> aWindow(
- [[WindowAppleScript alloc] initWithBrowser:browser()]);
- scoped_nsobject<TabAppleScript> aTab;
- int count;
- for (int i = 0; i < 5; ++i) {
- for (int j = 0; j < 3; ++j) {
- aTab.reset([[TabAppleScript alloc] init]);
- [aWindow.get() insertInTabs:aTab.get()];
- }
- count = 3 * i + 4;
- EXPECT_EQ((int)[[aWindow.get() tabs] count], count);
- }
-
- count = (int)[[aWindow.get() tabs] count];
- for (int i = 0; i < 5; ++i) {
- for(int j = 0; j < 3; ++j) {
- [aWindow.get() removeFromTabsAtIndex:0];
- }
- count = count - 3;
- EXPECT_EQ((int)[[aWindow.get() tabs] count], count);
- }
-}
-
-// Getting and setting values from the NSWindow.
-IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, NSWindowTest) {
- scoped_nsobject<WindowAppleScript> aWindow(
- [[WindowAppleScript alloc] initWithBrowser:browser()]);
- [aWindow.get() setValue:[NSNumber numberWithBool:YES]
- forKey:@"isMiniaturized"];
- EXPECT_TRUE([[aWindow.get() valueForKey:@"isMiniaturized"] boolValue]);
- [aWindow.get() setValue:[NSNumber numberWithBool:NO]
- forKey:@"isMiniaturized"];
- EXPECT_FALSE([[aWindow.get() valueForKey:@"isMiniaturized"] boolValue]);
-}
-
-// Getting and setting the active tab.
-IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, ActiveTab) {
- scoped_nsobject<WindowAppleScript> aWindow(
- [[WindowAppleScript alloc] initWithBrowser:browser()]);
- scoped_nsobject<TabAppleScript> aTab([[TabAppleScript alloc] init]);
- [aWindow.get() insertInTabs:aTab.get()];
- [aWindow.get() setActiveTabIndex:[NSNumber numberWithInt:2]];
- EXPECT_EQ(2, [[aWindow.get() activeTabIndex] intValue]);
- TabAppleScript* tab2 = [[aWindow.get() tabs] objectAtIndex:1];
- EXPECT_NSEQ([[aWindow.get() activeTab] uniqueID],
- [tab2 uniqueID]);
-}
-
-// Order of windows.
-IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, WindowOrder) {
- scoped_nsobject<WindowAppleScript> window2(
- [[WindowAppleScript alloc] initWithBrowser:browser()]);
- scoped_nsobject<WindowAppleScript> window1(
- [[WindowAppleScript alloc] init]);
- EXPECT_EQ([window1.get() windowComparator:window2.get()], NSOrderedAscending);
- EXPECT_EQ([window2.get() windowComparator:window1.get()],
- NSOrderedDescending);
-}
diff --git a/chrome/browser/cocoa/authorization_util.h b/chrome/browser/cocoa/authorization_util.h
deleted file mode 100644
index d5daf4a..0000000
--- a/chrome/browser/cocoa/authorization_util.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_AUTHORIZATION_UTIL_H_
-#define CHROME_BROWSER_COCOA_AUTHORIZATION_UTIL_H_
-#pragma once
-
-// AuthorizationExecuteWithPrivileges fork()s and exec()s the tool, but it
-// does not wait() for it. It also doesn't provide the caller with access to
-// the forked pid. If used irresponsibly, zombie processes will accumulate.
-//
-// Apple's really gotten us between a rock and a hard place, here.
-//
-// Fortunately, AuthorizationExecuteWithPrivileges does give access to the
-// tool's stdout (and stdin) via a FILE* pipe. The tool can output its pid
-// to this pipe, and the main program can read it, and then have something
-// that it can wait() for.
-//
-// The contract is that any tool executed by the wrappers declared in this
-// file must print its pid to stdout on a line by itself before doing anything
-// else.
-//
-// http://developer.apple.com/mac/library/samplecode/BetterAuthorizationSample/listing1.html
-// (Look for "What's This About Zombies?")
-
-#include <CoreFoundation/CoreFoundation.h>
-#include <Security/Authorization.h>
-#include <stdio.h>
-#include <sys/types.h>
-
-namespace authorization_util {
-
-// Obtains an AuthorizationRef that can be used to run commands as root. If
-// necessary, prompts the user for authentication. If the user is prompted,
-// |prompt| will be used as the prompt string and an icon appropriate for the
-// application will be displayed in a prompt dialog. Note that the system
-// appends its own text to the prompt string. Returns NULL on failure.
-AuthorizationRef AuthorizationCreateToRunAsRoot(CFStringRef prompt);
-
-// Calls straight through to AuthorizationExecuteWithPrivileges. If that
-// call succeeds, |pid| will be set to the pid of the executed tool. If the
-// pid can't be determined, |pid| will be set to -1. |pid| must not be NULL.
-// |pipe| may be NULL, but the tool will always be executed with a pipe in
-// order to read the pid from its stdout.
-OSStatus ExecuteWithPrivilegesAndGetPID(AuthorizationRef authorization,
- const char* tool_path,
- AuthorizationFlags options,
- const char** arguments,
- FILE** pipe,
- pid_t* pid);
-
-// Calls ExecuteWithPrivilegesAndGetPID, and if that call succeeds, calls
-// waitpid() to wait for the process to exit. If waitpid() succeeds, the
-// exit status is placed in |exit_status|, otherwise, -1 is stored.
-// |exit_status| may be NULL and this function will still wait for the process
-// to exit.
-OSStatus ExecuteWithPrivilegesAndWait(AuthorizationRef authorization,
- const char* tool_path,
- AuthorizationFlags options,
- const char** arguments,
- FILE** pipe,
- int* exit_status);
-
-} // namespace authorization_util
-
-#endif // CHROME_BROWSER_COCOA_AUTHORIZATION_UTIL_H_
diff --git a/chrome/browser/cocoa/authorization_util.mm b/chrome/browser/cocoa/authorization_util.mm
deleted file mode 100644
index e255993..0000000
--- a/chrome/browser/cocoa/authorization_util.mm
+++ /dev/null
@@ -1,184 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/authorization_util.h"
-
-#import <Foundation/Foundation.h>
-#include <sys/wait.h>
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/eintr_wrapper.h"
-#include "base/logging.h"
-#import "base/mac_util.h"
-#include "base/string_number_conversions.h"
-#include "base/string_util.h"
-#include "chrome/browser/cocoa/scoped_authorizationref.h"
-
-namespace authorization_util {
-
-AuthorizationRef AuthorizationCreateToRunAsRoot(CFStringRef prompt) {
- // Create an empty AuthorizationRef.
- scoped_AuthorizationRef authorization;
- OSStatus status = AuthorizationCreate(NULL,
- kAuthorizationEmptyEnvironment,
- kAuthorizationFlagDefaults,
- &authorization);
- if (status != errAuthorizationSuccess) {
- LOG(ERROR) << "AuthorizationCreate: " << status;
- return NULL;
- }
-
- // Specify the "system.privilege.admin" right, which allows
- // AuthorizationExecuteWithPrivileges to run commands as root.
- AuthorizationItem right_items[] = {
- {kAuthorizationRightExecute, 0, NULL, 0}
- };
- AuthorizationRights rights = {arraysize(right_items), right_items};
-
- // product_logo_32.png is used instead of app.icns because Authorization
- // Services can't deal with .icns files.
- NSString* icon_path =
- [mac_util::MainAppBundle() pathForResource:@"product_logo_32"
- ofType:@"png"];
- const char* icon_path_c = [icon_path fileSystemRepresentation];
- size_t icon_path_length = icon_path_c ? strlen(icon_path_c) : 0;
-
- // The OS will append " Type an administrator's name and password to allow
- // <CFBundleDisplayName> to make changes."
- NSString* prompt_ns = const_cast<NSString*>(
- reinterpret_cast<const NSString*>(prompt));
- const char* prompt_c = [prompt_ns UTF8String];
- size_t prompt_length = prompt_c ? strlen(prompt_c) : 0;
-
- AuthorizationItem environment_items[] = {
- {kAuthorizationEnvironmentIcon, icon_path_length, (void*)icon_path_c, 0},
- {kAuthorizationEnvironmentPrompt, prompt_length, (void*)prompt_c, 0}
- };
-
- AuthorizationEnvironment environment = {arraysize(environment_items),
- environment_items};
-
- AuthorizationFlags flags = kAuthorizationFlagDefaults |
- kAuthorizationFlagInteractionAllowed |
- kAuthorizationFlagExtendRights |
- kAuthorizationFlagPreAuthorize;
-
- status = AuthorizationCopyRights(authorization,
- &rights,
- &environment,
- flags,
- NULL);
- if (status != errAuthorizationSuccess) {
- if (status != errAuthorizationCanceled) {
- LOG(ERROR) << "AuthorizationCopyRights: " << status;
- }
- return NULL;
- }
-
- return authorization.release();
-}
-
-OSStatus ExecuteWithPrivilegesAndGetPID(AuthorizationRef authorization,
- const char* tool_path,
- AuthorizationFlags options,
- const char** arguments,
- FILE** pipe,
- pid_t* pid) {
- // pipe may be NULL, but this function needs one. In that case, use a local
- // pipe.
- FILE* local_pipe;
- FILE** pipe_pointer;
- if (pipe) {
- pipe_pointer = pipe;
- } else {
- pipe_pointer = &local_pipe;
- }
-
- // AuthorizationExecuteWithPrivileges wants |char* const*| for |arguments|,
- // but it doesn't actually modify the arguments, and that type is kind of
- // silly and callers probably aren't dealing with that. Put the cast here
- // to make things a little easier on callers.
- OSStatus status = AuthorizationExecuteWithPrivileges(authorization,
- tool_path,
- options,
- (char* const*)arguments,
- pipe_pointer);
- if (status != errAuthorizationSuccess) {
- return status;
- }
-
- int line_pid = -1;
- size_t line_length = 0;
- char* line_c = fgetln(*pipe_pointer, &line_length);
- if (line_c) {
- if (line_length > 0 && line_c[line_length - 1] == '\n') {
- // line_c + line_length is the start of the next line if there is one.
- // Back up one character.
- --line_length;
- }
- std::string line(line_c, line_length);
- if (!base::StringToInt(line, &line_pid)) {
- // StringToInt may have set line_pid to something, but if the conversion
- // was imperfect, use -1.
- LOG(ERROR) << "ExecuteWithPrivilegesAndGetPid: funny line: " << line;
- line_pid = -1;
- }
- } else {
- LOG(ERROR) << "ExecuteWithPrivilegesAndGetPid: no line";
- }
-
- if (!pipe) {
- fclose(*pipe_pointer);
- }
-
- if (pid) {
- *pid = line_pid;
- }
-
- return status;
-}
-
-OSStatus ExecuteWithPrivilegesAndWait(AuthorizationRef authorization,
- const char* tool_path,
- AuthorizationFlags options,
- const char** arguments,
- FILE** pipe,
- int* exit_status) {
- pid_t pid;
- OSStatus status = ExecuteWithPrivilegesAndGetPID(authorization,
- tool_path,
- options,
- arguments,
- pipe,
- &pid);
- if (status != errAuthorizationSuccess) {
- return status;
- }
-
- // exit_status may be NULL, but this function needs it. In that case, use a
- // local version.
- int local_exit_status;
- int* exit_status_pointer;
- if (exit_status) {
- exit_status_pointer = exit_status;
- } else {
- exit_status_pointer = &local_exit_status;
- }
-
- if (pid != -1) {
- pid_t wait_result = HANDLE_EINTR(waitpid(pid, exit_status_pointer, 0));
- if (wait_result != pid) {
- PLOG(ERROR) << "waitpid";
- *exit_status_pointer = -1;
- }
- } else {
- *exit_status_pointer = -1;
- }
-
- return status;
-}
-
-} // namespace authorization_util
diff --git a/chrome/browser/cocoa/back_forward_menu_controller.h b/chrome/browser/cocoa/back_forward_menu_controller.h
deleted file mode 100644
index 8e0bef1..0000000
--- a/chrome/browser/cocoa/back_forward_menu_controller.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_BACK_FORWARD_MENU_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_BACK_FORWARD_MENU_CONTROLLER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-#include "chrome/browser/back_forward_menu_model.h"
-
-@class DelayedMenuButton;
-
-typedef BackForwardMenuModel::ModelType BackForwardMenuType;
-const BackForwardMenuType BACK_FORWARD_MENU_TYPE_BACK =
- BackForwardMenuModel::BACKWARD_MENU;
-const BackForwardMenuType BACK_FORWARD_MENU_TYPE_FORWARD =
- BackForwardMenuModel::FORWARD_MENU;
-
-// A class that manages the back/forward menu (and delayed-menu button, and
-// model).
-
-@interface BackForwardMenuController : NSObject {
- @private
- BackForwardMenuType type_;
- DelayedMenuButton* button_; // Weak; comes from nib.
- scoped_ptr<BackForwardMenuModel> model_;
- scoped_nsobject<NSMenu> backForwardMenu_;
-}
-
-// Type (back or forwards); can only be set on initialization.
-@property(readonly, nonatomic) BackForwardMenuType type;
-
-- (id)initWithBrowser:(Browser*)browser
- modelType:(BackForwardMenuType)type
- button:(DelayedMenuButton*)button;
-
-@end // @interface BackForwardMenuController
-
-#endif // CHROME_BROWSER_COCOA_BACK_FORWARD_MENU_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/back_forward_menu_controller.mm b/chrome/browser/cocoa/back_forward_menu_controller.mm
deleted file mode 100644
index 2fca91d..0000000
--- a/chrome/browser/cocoa/back_forward_menu_controller.mm
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/back_forward_menu_controller.h"
-
-#include "base/logging.h"
-#include "base/scoped_ptr.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/back_forward_menu_model.h"
-#import "chrome/browser/cocoa/delayedmenu_button.h"
-#import "chrome/browser/cocoa/event_utils.h"
-#include "skia/ext/skia_utils_mac.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-using base::SysUTF16ToNSString;
-using gfx::SkBitmapToNSImage;
-
-@implementation BackForwardMenuController
-
-// Accessors and mutators:
-
-@synthesize type = type_;
-
-// Own methods:
-
-- (id)initWithBrowser:(Browser*)browser
- modelType:(BackForwardMenuType)type
- button:(DelayedMenuButton*)button {
- if ((self = [super init])) {
- type_ = type;
- button_ = button;
- model_.reset(new BackForwardMenuModel(browser, type_));
- DCHECK(model_.get());
- backForwardMenu_.reset([[NSMenu alloc] initWithTitle:@""]);
- DCHECK(backForwardMenu_.get());
- [backForwardMenu_ setDelegate:self];
-
- [button_ setAttachedMenu:backForwardMenu_];
- [button_ setAttachedMenuEnabled:YES];
- }
- return self;
-}
-
-// Methods as delegate:
-
-// Called by backForwardMenu_ just before tracking begins.
-//TODO(viettrungluu): should we do anything for chapter stops (see model)?
-- (void)menuNeedsUpdate:(NSMenu*)menu {
- DCHECK(menu == backForwardMenu_);
-
- // Remove old menu items (backwards order is as good as any).
- for (NSInteger i = [menu numberOfItems]; i > 0; i--)
- [menu removeItemAtIndex:(i - 1)];
-
- // 0-th item must be blank. (This is because we use a pulldown list, for which
- // Cocoa uses the 0-th item as "title" in the button.)
- [menu insertItemWithTitle:@""
- action:nil
- keyEquivalent:@""
- atIndex:0];
- for (int menuID = 0; menuID < model_->GetItemCount(); menuID++) {
- if (model_->IsSeparator(menuID)) {
- [menu insertItem:[NSMenuItem separatorItem]
- atIndex:(menuID + 1)];
- } else {
- // Create a menu item with the right label.
- NSMenuItem* menuItem = [[NSMenuItem alloc]
- initWithTitle:SysUTF16ToNSString(model_->GetLabelAt(menuID))
- action:nil
- keyEquivalent:@""];
- [menuItem autorelease];
-
- SkBitmap icon;
- // Icon (if it has one).
- if (model_->GetIconAt(menuID, &icon))
- [menuItem setImage:SkBitmapToNSImage(icon)];
-
- // This will make it call our |-executeMenuItem:| method. We store the
- // |menuID| (or |menu_id|) in the tag.
- [menuItem setTag:menuID];
- [menuItem setTarget:self];
- [menuItem setAction:@selector(executeMenuItem:)];
-
- // Put it in the menu!
- [menu insertItem:menuItem
- atIndex:(menuID + 1)];
- }
- }
-}
-
-// Action methods:
-
-- (void)executeMenuItem:(id)sender {
- DCHECK([sender isKindOfClass:[NSMenuItem class]]);
- int menuID = [sender tag];
- model_->ActivatedAtWithDisposition(
- menuID,
- event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]));
-}
-
-@end // @implementation BackForwardMenuController
diff --git a/chrome/browser/cocoa/background_gradient_view.h b/chrome/browser/cocoa/background_gradient_view.h
deleted file mode 100644
index be5a433..0000000
--- a/chrome/browser/cocoa/background_gradient_view.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_BACKGROUND_GRADIENT_VIEW_H_
-#define CHROME_BROWSER_COCOA_BACKGROUND_GRADIENT_VIEW_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-// A custom view that draws a 'standard' background gradient.
-// Base class for other Chromium views.
-@interface BackgroundGradientView : NSView {
- @private
- BOOL showsDivider_;
-}
-
-// The color used for the bottom stroke. Public so subclasses can use.
-- (NSColor *)strokeColor;
-
-// Draws the background for this view. Make sure that your patternphase
-// is set up correctly in your graphics context before calling.
-- (void)drawBackground;
-
-// Controls whether the bar draws a dividing line at the bottom.
-@property(nonatomic, assign) BOOL showsDivider;
-@end
-
-#endif // CHROME_BROWSER_COCOA_BACKGROUND_GRADIENT_VIEW_H_
diff --git a/chrome/browser/cocoa/background_gradient_view.mm b/chrome/browser/cocoa/background_gradient_view.mm
deleted file mode 100644
index 9910412..0000000
--- a/chrome/browser/cocoa/background_gradient_view.mm
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/background_gradient_view.h"
-
-#import "chrome/browser/cocoa/themed_window.h"
-#import "chrome/browser/themes/browser_theme_provider.h"
-#include "grit/theme_resources.h"
-
-#define kToolbarTopOffset 12
-#define kToolbarMaxHeight 100
-
-@implementation BackgroundGradientView
-@synthesize showsDivider = showsDivider_;
-
-- (id)initWithFrame:(NSRect)frameRect {
- self = [super initWithFrame:frameRect];
- if (self != nil) {
- showsDivider_ = YES;
- }
- return self;
-}
-
-- (void)awakeFromNib {
- showsDivider_ = YES;
-}
-
-- (void)setShowsDivider:(BOOL)show {
- showsDivider_ = show;
- [self setNeedsDisplay:YES];
-}
-
-- (void)drawBackground {
- BOOL isKey = [[self window] isKeyWindow];
- ThemeProvider* themeProvider = [[self window] themeProvider];
- if (themeProvider) {
- NSColor* backgroundImageColor =
- themeProvider->GetNSImageColorNamed(IDR_THEME_TOOLBAR, false);
- if (backgroundImageColor) {
- [backgroundImageColor set];
- NSRectFill([self bounds]);
- } else {
- CGFloat winHeight = NSHeight([[self window] frame]);
- NSGradient* gradient = themeProvider->GetNSGradient(
- isKey ? BrowserThemeProvider::GRADIENT_TOOLBAR :
- BrowserThemeProvider::GRADIENT_TOOLBAR_INACTIVE);
- NSPoint startPoint =
- [self convertPoint:NSMakePoint(0, winHeight - kToolbarTopOffset)
- fromView:nil];
- NSPoint endPoint =
- NSMakePoint(0, winHeight - kToolbarTopOffset - kToolbarMaxHeight);
- endPoint = [self convertPoint:endPoint fromView:nil];
-
- [gradient drawFromPoint:startPoint
- toPoint:endPoint
- options:(NSGradientDrawsBeforeStartingLocation |
- NSGradientDrawsAfterEndingLocation)];
- }
-
- if (showsDivider_) {
- // Draw bottom stroke
- [[self strokeColor] set];
- NSRect borderRect, contentRect;
- NSDivideRect([self bounds], &borderRect, &contentRect, 1, NSMinYEdge);
- NSRectFillUsingOperation(borderRect, NSCompositeSourceOver);
- }
- }
-}
-
-- (NSColor*)strokeColor {
- BOOL isKey = [[self window] isKeyWindow];
- ThemeProvider* themeProvider = [[self window] themeProvider];
- if (!themeProvider)
- return [NSColor blackColor];
- return themeProvider->GetNSColor(
- isKey ? BrowserThemeProvider::COLOR_TOOLBAR_STROKE :
- BrowserThemeProvider::COLOR_TOOLBAR_STROKE_INACTIVE, true);
-}
-
-@end
diff --git a/chrome/browser/cocoa/background_gradient_view_unittest.mm b/chrome/browser/cocoa/background_gradient_view_unittest.mm
deleted file mode 100644
index b0d0d5c..0000000
--- a/chrome/browser/cocoa/background_gradient_view_unittest.mm
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2009 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 "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/background_gradient_view.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-// Since BackgroundGradientView doesn't do any drawing by default, we
-// create a subclass to call its draw method for us.
-@interface BackgroundGradientSubClassTest : BackgroundGradientView
-@end
-
-@implementation BackgroundGradientSubClassTest
-- (void)drawRect:(NSRect)rect {
- [self drawBackground];
-}
-@end
-
-namespace {
-
-class BackgroundGradientViewTest : public CocoaTest {
- public:
- BackgroundGradientViewTest() {
- NSRect frame = NSMakeRect(0, 0, 100, 30);
- scoped_nsobject<BackgroundGradientSubClassTest> view;
- view.reset([[BackgroundGradientSubClassTest alloc] initWithFrame:frame]);
- view_ = view.get();
- [[test_window() contentView] addSubview:view_];
- }
-
- BackgroundGradientSubClassTest* view_;
-};
-
-TEST_VIEW(BackgroundGradientViewTest, view_)
-
-// Test drawing, mostly to ensure nothing leaks or crashes.
-TEST_F(BackgroundGradientViewTest, DisplayWithDivider) {
- [view_ setShowsDivider:YES];
- [view_ display];
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/background_tile_view.h b/chrome/browser/cocoa/background_tile_view.h
deleted file mode 100644
index 1b947c5..0000000
--- a/chrome/browser/cocoa/background_tile_view.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_BACKGROUND_TILE_VIEW_H_
-#define CHROME_BROWSER_COCOA_BACKGROUND_TILE_VIEW_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-// A custom view that draws a image tiled as the background. This isn't meant
-// to be used where themes might be need, and is for other windows (about box).
-
-@interface BackgroundTileView : NSView {
- @private
- BOOL showsDivider_;
- NSImage* tileImage_;
-}
-
-@property(nonatomic, retain) NSImage* tileImage;
-@end
-
-#endif // CHROME_BROWSER_COCOA_BACKGROUND_TILE_VIEW_H_
diff --git a/chrome/browser/cocoa/background_tile_view.mm b/chrome/browser/cocoa/background_tile_view.mm
deleted file mode 100644
index cab5046..0000000
--- a/chrome/browser/cocoa/background_tile_view.mm
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/background_tile_view.h"
-
-@implementation BackgroundTileView
-@synthesize tileImage = tileImage_;
-
-- (void)setTileImage:(NSImage*)tileImage {
- [tileImage_ autorelease];
- tileImage_ = [tileImage retain];
- [self setNeedsDisplay:YES];
-}
-
-- (void)drawRect:(NSRect)rect {
- // Tile within the view, so set the phase to start at the view bottom.
- NSPoint phase = NSMakePoint(0.0, NSMinY([self frame]));
- [[NSGraphicsContext currentContext] setPatternPhase:phase];
-
- if (tileImage_) {
- NSColor *color = [NSColor colorWithPatternImage:tileImage_];
- [color set];
- } else {
- // Something to catch the missing image
- [[NSColor magentaColor] set];
- }
-
- NSRectFill([self bounds]);
-}
-
-@end
diff --git a/chrome/browser/cocoa/background_tile_view_unittest.mm b/chrome/browser/cocoa/background_tile_view_unittest.mm
deleted file mode 100644
index 8bc6d94..0000000
--- a/chrome/browser/cocoa/background_tile_view_unittest.mm
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) 2009 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 "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/background_tile_view.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-namespace {
-
-class BackgroundTileViewTest : public CocoaTest {
- public:
- BackgroundTileViewTest() {
- NSRect frame = NSMakeRect(0, 0, 100, 30);
- scoped_nsobject<BackgroundTileView> view([[BackgroundTileView alloc]
- initWithFrame:frame]);
- view_ = view.get();
- [[test_window() contentView] addSubview:view_];
- }
-
- BackgroundTileView *view_;
-};
-
-TEST_VIEW(BackgroundTileViewTest, view_)
-
-// Test drawing with an Image
-TEST_F(BackgroundTileViewTest, DisplayImage) {
- NSImage* image = [NSImage imageNamed:@"NSApplicationIcon"];
- [view_ setTileImage:image];
- [view_ display];
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/base_bubble_controller.h b/chrome/browser/cocoa/base_bubble_controller.h
deleted file mode 100644
index 7cc2c5b..0000000
--- a/chrome/browser/cocoa/base_bubble_controller.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// 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>
-
-#import "base/cocoa_protocols_mac.h"
-#include "base/scoped_ptr.h"
-
-namespace BaseBubbleControllerInternal {
-class Bridge;
-}
-
-@class InfoBubbleView;
-
-// Base class for bubble controllers. Manages a xib that contains an
-// InfoBubbleWindow which contains an InfoBubbleView. Contains code to close
-// the bubble window on clicks outside of the window, and the like.
-// To use this class:
-// 1. Create a new xib that contains a window. Change the window's class to
-// InfoBubbleWindow. Give it a child view that autosizes to the window's full
-// size, give it class InfoBubbleView. Make the controller the window's
-// delegate.
-// 2. Create a subclass of BaseBubbleController.
-// 3. Change the xib's File Owner to your subclass.
-// 4. Hook up the File Owner's |bubble_| to the InfoBubbleView in the xib.
-@interface BaseBubbleController : NSWindowController<NSWindowDelegate> {
- @private
- NSWindow* parentWindow_; // weak
- NSPoint anchor_;
- IBOutlet InfoBubbleView* bubble_; // to set arrow position
- // Bridge that listens for notifications.
- scoped_ptr<BaseBubbleControllerInternal::Bridge> base_bridge_;
-}
-
-@property (nonatomic, readonly) NSWindow* parentWindow;
-@property (nonatomic, assign) NSPoint anchorPoint;
-@property (nonatomic, readonly) InfoBubbleView* bubble;
-
-// Creates a bubble. |nibPath| is just the basename, e.g. @"FirstRunBubble".
-// |anchoredAt| is in screen space. You need to call -showWindow: to make the
-// bubble visible. It will autorelease itself when the user dismisses the
-// bubble.
-// This is the designated initializer.
-- (id)initWithWindowNibPath:(NSString*)nibPath
- parentWindow:(NSWindow*)parentWindow
- anchoredAt:(NSPoint)anchoredAt;
-
-
-// Creates a bubble. |nibPath| is just the basename, e.g. @"FirstRunBubble".
-// |view| must be in a window. The bubble will point at |offset| relative to
-// |view|'s lower left corner. You need to call -showWindow: to make the
-// bubble visible. It will autorelease itself when the user dismisses the
-// bubble.
-- (id)initWithWindowNibPath:(NSString*)nibPath
- relativeToView:(NSView*)view
- offset:(NSPoint)offset;
-
-
-// For subclasses that do not load from a XIB, this will simply set the instance
-// variables appropriately. This will also replace the |-[self window]|'s
-// contentView with an instance of InfoBubbleView.
-- (id)initWithWindow:(NSWindow*)theWindow
- parentWindow:(NSWindow*)parentWindow
- anchoredAt:(NSPoint)anchoredAt;
-
-@end
diff --git a/chrome/browser/cocoa/base_bubble_controller.mm b/chrome/browser/cocoa/base_bubble_controller.mm
deleted file mode 100644
index e9804c5..0000000
--- a/chrome/browser/cocoa/base_bubble_controller.mm
+++ /dev/null
@@ -1,201 +0,0 @@
-// 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 "chrome/browser/cocoa/base_bubble_controller.h"
-
-#include "app/l10n_util.h"
-#include "base/logging.h"
-#include "base/mac_util.h"
-#include "base/scoped_nsobject.h"
-#include "base/string_util.h"
-#import "chrome/browser/cocoa/info_bubble_view.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/notification_type.h"
-#include "grit/generated_resources.h"
-
-@interface BaseBubbleController (Private)
-- (void)updateOriginFromAnchor;
-@end
-
-namespace BaseBubbleControllerInternal {
-
-// This bridge listens for notifications so that the bubble closes when a user
-// switches tabs (including by opening a new one).
-class Bridge : public NotificationObserver {
- public:
- explicit Bridge(BaseBubbleController* controller) : controller_(controller) {
- registrar_.Add(this, NotificationType::TAB_CONTENTS_HIDDEN,
- NotificationService::AllSources());
- }
-
- // NotificationObserver:
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- [controller_ close];
- }
-
- private:
- BaseBubbleController* controller_; // Weak, owns this.
- NotificationRegistrar registrar_;
-};
-
-} // namespace BaseBubbleControllerInternal
-
-@implementation BaseBubbleController
-
-@synthesize parentWindow = parentWindow_;
-@synthesize anchorPoint = anchor_;
-@synthesize bubble = bubble_;
-
-- (id)initWithWindowNibPath:(NSString*)nibPath
- parentWindow:(NSWindow*)parentWindow
- anchoredAt:(NSPoint)anchoredAt {
- nibPath = [mac_util::MainAppBundle() pathForResource:nibPath
- ofType:@"nib"];
- if ((self = [super initWithWindowNibPath:nibPath owner:self])) {
- parentWindow_ = parentWindow;
- anchor_ = anchoredAt;
-
- // Watch to see if the parent window closes, and if so, close this one.
- NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
- [center addObserver:self
- selector:@selector(parentWindowWillClose:)
- name:NSWindowWillCloseNotification
- object:parentWindow_];
- }
- return self;
-}
-
-- (id)initWithWindowNibPath:(NSString*)nibPath
- relativeToView:(NSView*)view
- offset:(NSPoint)offset {
- DCHECK([view window]);
- NSWindow* window = [view window];
- NSRect bounds = [view convertRect:[view bounds] toView:nil];
- NSPoint anchor = NSMakePoint(NSMinX(bounds) + offset.x,
- NSMinY(bounds) + offset.y);
- anchor = [window convertBaseToScreen:anchor];
- return [self initWithWindowNibPath:nibPath
- parentWindow:window
- anchoredAt:anchor];
-}
-
-- (id)initWithWindow:(NSWindow*)theWindow
- parentWindow:(NSWindow*)parentWindow
- anchoredAt:(NSPoint)anchoredAt {
- DCHECK(theWindow);
- if ((self = [super initWithWindow:theWindow])) {
- parentWindow_ = parentWindow;
- anchor_ = anchoredAt;
-
- DCHECK(![[self window] delegate]);
- [theWindow setDelegate:self];
-
- scoped_nsobject<InfoBubbleView> contentView(
- [[InfoBubbleView alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)]);
- [theWindow setContentView:contentView.get()];
- bubble_ = contentView.get();
-
- // Watch to see if the parent window closes, and if so, close this one.
- NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
- [center addObserver:self
- selector:@selector(parentWindowWillClose:)
- name:NSWindowWillCloseNotification
- object:parentWindow_];
-
- [self awakeFromNib];
- }
- return self;
-}
-
-- (void)awakeFromNib {
- // Check all connections have been made in Interface Builder.
- DCHECK([self window]);
- DCHECK(bubble_);
- DCHECK_EQ(self, [[self window] delegate]);
-
- base_bridge_.reset(new BaseBubbleControllerInternal::Bridge(self));
-
- [bubble_ setBubbleType:info_bubble::kWhiteInfoBubble];
- [bubble_ setArrowLocation:info_bubble::kTopRight];
-}
-
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [super dealloc];
-}
-
-- (void)setAnchorPoint:(NSPoint)anchor {
- anchor_ = anchor;
- [self updateOriginFromAnchor];
-}
-
-- (void)parentWindowWillClose:(NSNotification*)notification {
- [self close];
-}
-
-- (void)windowWillClose:(NSNotification*)notification {
- // We caught a close so we don't need to watch for the parent closing.
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [self autorelease];
-}
-
-// We want this to be a child of a browser window. addChildWindow:
-// (called from this function) will bring the window on-screen;
-// unfortunately, [NSWindowController showWindow:] will also bring it
-// on-screen (but will cause unexpected changes to the window's
-// position). We cannot have an addChildWindow: and a subsequent
-// showWindow:. Thus, we have our own version.
-- (void)showWindow:(id)sender {
- NSWindow* window = [self window]; // completes nib load
- [self updateOriginFromAnchor];
- [parentWindow_ addChildWindow:window ordered:NSWindowAbove];
- [window makeKeyAndOrderFront:self];
-}
-
-- (void)close {
- [parentWindow_ removeChildWindow:[self window]];
- [super close];
-}
-
-// The controller is the delegate of the window so it receives did resign key
-// notifications. When key is resigned mirror Windows behavior and close the
-// window.
-- (void)windowDidResignKey:(NSNotification*)notification {
- NSWindow* window = [self window];
- DCHECK_EQ([notification object], window);
- if ([window isVisible]) {
- // If the window isn't visible, it is already closed, and this notification
- // has been sent as part of the closing operation, so no need to close.
- [self close];
- }
-}
-
-// By implementing this, ESC causes the window to go away.
-- (IBAction)cancel:(id)sender {
- // This is not a "real" cancel as potential changes to the radio group are not
- // undone. That's ok.
- [self close];
-}
-
-// Takes the |anchor_| point and adjusts the window's origin accordingly.
-- (void)updateOriginFromAnchor {
- NSWindow* window = [self window];
- NSPoint origin = anchor_;
- NSSize offsets = NSMakeSize(info_bubble::kBubbleArrowXOffset +
- info_bubble::kBubbleArrowWidth / 2.0, 0);
- offsets = [[parentWindow_ contentView] convertSize:offsets toView:nil];
- if ([bubble_ arrowLocation] == info_bubble::kTopRight) {
- origin.x -= NSWidth([window frame]) - offsets.width;
- } else {
- origin.x -= offsets.width;
- }
- origin.y -= NSHeight([window frame]);
- [window setFrameOrigin:origin];
-}
-
-@end // BaseBubbleController
diff --git a/chrome/browser/cocoa/base_view.h b/chrome/browser/cocoa/base_view.h
deleted file mode 100644
index bece608..0000000
--- a/chrome/browser/cocoa/base_view.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_BASE_VIEW_H_
-#define CHROME_BROWSER_COCOA_BASE_VIEW_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_nsobject.h"
-#include "gfx/rect.h"
-
-// A view that provides common functionality that many views will need:
-// - Automatic registration for mouse-moved events.
-// - Funneling of mouse and key events to two methods
-// - Coordinate conversion utilities
-
-@interface BaseView : NSView {
- @private
- NSTrackingArea *trackingArea_;
- BOOL dragging_;
- scoped_nsobject<NSEvent> pendingExitEvent_;
-}
-
-- (id)initWithFrame:(NSRect)frame;
-
-// Override these methods in a subclass.
-- (void)mouseEvent:(NSEvent *)theEvent;
-- (void)keyEvent:(NSEvent *)theEvent;
-
-// Useful rect conversions (doing coordinate flipping)
-- (gfx::Rect)flipNSRectToRect:(NSRect)rect;
-- (NSRect)flipRectToNSRect:(gfx::Rect)rect;
-
-@end
-
-// A notification that a view may issue when it receives first responder status.
-// The name is |kViewDidBecomeFirstResponder|, the object is the view, and the
-// NSSelectionDirection is wrapped in an NSNumber under the key
-// |kSelectionDirection|.
-extern NSString* kViewDidBecomeFirstResponder;
-extern NSString* kSelectionDirection;
-
-#endif // CHROME_BROWSER_COCOA_BASE_VIEW_H_
diff --git a/chrome/browser/cocoa/base_view.mm b/chrome/browser/cocoa/base_view.mm
deleted file mode 100644
index 433733e..0000000
--- a/chrome/browser/cocoa/base_view.mm
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/base_view.h"
-
-NSString* kViewDidBecomeFirstResponder =
- @"Chromium.kViewDidBecomeFirstResponder";
-NSString* kSelectionDirection = @"Chromium.kSelectionDirection";
-
-@implementation BaseView
-
-- (id)initWithFrame:(NSRect)frame {
- self = [super initWithFrame:frame];
- if (self) {
- trackingArea_ =
- [[NSTrackingArea alloc] initWithRect:frame
- options:NSTrackingMouseMoved |
- NSTrackingMouseEnteredAndExited |
- NSTrackingActiveInActiveApp |
- NSTrackingInVisibleRect
- owner:self
- userInfo:nil];
- [self addTrackingArea:trackingArea_];
- }
- return self;
-}
-
-- (void)dealloc {
- [self removeTrackingArea:trackingArea_];
- [trackingArea_ release];
-
- [super dealloc];
-}
-
-- (void)mouseEvent:(NSEvent *)theEvent {
- // This method left intentionally blank.
-}
-
-- (void)keyEvent:(NSEvent *)theEvent {
- // This method left intentionally blank.
-}
-
-- (void)mouseDown:(NSEvent *)theEvent {
- dragging_ = YES;
- [self mouseEvent:theEvent];
-}
-
-- (void)rightMouseDown:(NSEvent *)theEvent {
- [self mouseEvent:theEvent];
-}
-
-- (void)otherMouseDown:(NSEvent *)theEvent {
- [self mouseEvent:theEvent];
-}
-
-- (void)mouseUp:(NSEvent *)theEvent {
- [self mouseEvent:theEvent];
-
- dragging_ = NO;
- if (pendingExitEvent_.get()) {
- NSEvent* exitEvent =
- [NSEvent enterExitEventWithType:NSMouseExited
- location:[theEvent locationInWindow]
- modifierFlags:[theEvent modifierFlags]
- timestamp:[theEvent timestamp]
- windowNumber:[theEvent windowNumber]
- context:[theEvent context]
- eventNumber:[pendingExitEvent_.get() eventNumber]
- trackingNumber:[pendingExitEvent_.get() trackingNumber]
- userData:[pendingExitEvent_.get() userData]];
- [self mouseEvent:exitEvent];
- pendingExitEvent_.reset();
- }
-}
-
-- (void)rightMouseUp:(NSEvent *)theEvent {
- [self mouseEvent:theEvent];
-}
-
-- (void)otherMouseUp:(NSEvent *)theEvent {
- [self mouseEvent:theEvent];
-}
-
-- (void)mouseMoved:(NSEvent *)theEvent {
- [self mouseEvent:theEvent];
-}
-
-- (void)mouseDragged:(NSEvent *)theEvent {
- [self mouseEvent:theEvent];
-}
-
-- (void)rightMouseDragged:(NSEvent *)theEvent {
- [self mouseEvent:theEvent];
-}
-
-- (void)otherMouseDragged:(NSEvent *)theEvent {
- [self mouseEvent:theEvent];
-}
-
-- (void)mouseEntered:(NSEvent *)theEvent {
- if (pendingExitEvent_.get()) {
- pendingExitEvent_.reset();
- return;
- }
-
- [self mouseEvent:theEvent];
-}
-
-- (void)mouseExited:(NSEvent *)theEvent {
- // The tracking area will send an exit event even during a drag, which isn't
- // how the event flow for drags should work. This stores the exit event, and
- // sends it when the drag completes instead.
- if (dragging_) {
- pendingExitEvent_.reset([theEvent retain]);
- return;
- }
-
- [self mouseEvent:theEvent];
-}
-
-- (void)keyDown:(NSEvent *)theEvent {
- [self keyEvent:theEvent];
-}
-
-- (void)keyUp:(NSEvent *)theEvent {
- [self keyEvent:theEvent];
-}
-
-- (void)flagsChanged:(NSEvent *)theEvent {
- [self keyEvent:theEvent];
-}
-
-- (gfx::Rect)flipNSRectToRect:(NSRect)rect {
- gfx::Rect new_rect(NSRectToCGRect(rect));
- new_rect.set_y([self bounds].size.height - new_rect.y() - new_rect.height());
- return new_rect;
-}
-
-- (NSRect)flipRectToNSRect:(gfx::Rect)rect {
- NSRect new_rect(NSRectFromCGRect(rect.ToCGRect()));
- new_rect.origin.y =
- [self bounds].size.height - new_rect.origin.y - new_rect.size.height;
- return new_rect;
-}
-
-@end
diff --git a/chrome/browser/cocoa/base_view_unittest.mm b/chrome/browser/cocoa/base_view_unittest.mm
deleted file mode 100644
index ff97571..0000000
--- a/chrome/browser/cocoa/base_view_unittest.mm
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2009 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 "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/base_view.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-namespace {
-
-class BaseViewTest : public CocoaTest {
- public:
- BaseViewTest() {
- NSRect frame = NSMakeRect(0, 0, 100, 100);
- scoped_nsobject<BaseView> view([[BaseView alloc] initWithFrame:frame]);
- view_ = view.get();
- [[test_window() contentView] addSubview:view_];
- }
-
- BaseView* view_; // weak
-};
-
-TEST_VIEW(BaseViewTest, view_)
-
-// Convert a rect in |view_|'s Cocoa coordinate system to gfx::Rect's top-left
-// coordinate system. Repeat the process in reverse and make sure we come out
-// with the original rect.
-TEST_F(BaseViewTest, flipNSRectToRect) {
- NSRect convert = NSMakeRect(10, 10, 50, 50);
- gfx::Rect converted = [view_ flipNSRectToRect:convert];
- EXPECT_EQ(converted.x(), 10);
- EXPECT_EQ(converted.y(), 40); // Due to view being 100px tall.
- EXPECT_EQ(converted.width(), convert.size.width);
- EXPECT_EQ(converted.height(), convert.size.height);
-
- // Go back the other way.
- NSRect back_again = [view_ flipRectToNSRect:converted];
- EXPECT_EQ(back_again.origin.x, convert.origin.x);
- EXPECT_EQ(back_again.origin.y, convert.origin.y);
- EXPECT_EQ(back_again.size.width, convert.size.width);
- EXPECT_EQ(back_again.size.height, convert.size.height);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_all_tabs_controller.h b/chrome/browser/cocoa/bookmarks/bookmark_all_tabs_controller.h
deleted file mode 100644
index 4c6a57c..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_all_tabs_controller.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_ALL_TABS_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_ALL_TABS_CONTROLLER_H_
-#pragma once
-
-#include <utility>
-#include <vector>
-
-#include "base/string16.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_editor_base_controller.h"
-
-// A list of pairs containing the name and URL associated with each
-// currently active tab in the active browser window.
-typedef std::pair<string16, GURL> ActiveTabNameURLPair;
-typedef std::vector<ActiveTabNameURLPair> ActiveTabsNameURLPairVector;
-
-// A controller for the Bookmark All Tabs sheet which is presented upon
-// selecting the Bookmark All Tabs... menu item shown by the contextual
-// menu in the bookmarks bar.
-@interface BookmarkAllTabsController : BookmarkEditorBaseController {
- @private
- ActiveTabsNameURLPairVector activeTabPairsVector_;
-}
-
-- (id)initWithParentWindow:(NSWindow*)parentWindow
- profile:(Profile*)profile
- parent:(const BookmarkNode*)parent
- configuration:(BookmarkEditor::Configuration)configuration;
-
-@end
-
-@interface BookmarkAllTabsController(TestingAPI)
-
-// Initializes the list of all tab names and URLs. Overridden by unit test
-// to provide canned test data.
-- (void)UpdateActiveTabPairs;
-
-// Provides testing access to tab pairs list.
-- (ActiveTabsNameURLPairVector*)activeTabPairsVector;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_ALL_TABS_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_all_tabs_controller.mm b/chrome/browser/cocoa/bookmarks/bookmark_all_tabs_controller.mm
deleted file mode 100644
index 961d37a..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_all_tabs_controller.mm
+++ /dev/null
@@ -1,88 +0,0 @@
-// 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 "chrome/browser/cocoa/bookmarks/bookmark_all_tabs_controller.h"
-
-#include "app/l10n_util_mac.h"
-#include "base/string16.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
-#include "chrome/browser/tabs/tab_strip_model.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_list.h"
-#include "grit/generated_resources.h"
-
-@implementation BookmarkAllTabsController
-
-- (id)initWithParentWindow:(NSWindow*)parentWindow
- profile:(Profile*)profile
- parent:(const BookmarkNode*)parent
- configuration:(BookmarkEditor::Configuration)configuration {
- NSString* nibName = @"BookmarkAllTabs";
- if ((self = [super initWithParentWindow:parentWindow
- nibName:nibName
- profile:profile
- parent:parent
- configuration:configuration])) {
- }
- return self;
-}
-
-- (void)awakeFromNib {
- [self setInitialName:
- l10n_util::GetNSStringWithFixup(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME)];
- [super awakeFromNib];
-}
-
-#pragma mark Bookmark Editing
-
-- (void)UpdateActiveTabPairs {
- activeTabPairsVector_.clear();
- Browser* browser = BrowserList::GetLastActive();
- TabStripModel* tabstrip_model = browser->tabstrip_model();
- const int tabCount = tabstrip_model->count();
- for (int i = 0; i < tabCount; ++i) {
- TabContents* tc = tabstrip_model->GetTabContentsAt(i)->tab_contents();
- const string16 tabTitle = tc->GetTitle();
- const GURL& tabURL(tc->GetURL());
- ActiveTabNameURLPair tabPair(tabTitle, tabURL);
- activeTabPairsVector_.push_back(tabPair);
- }
-}
-
-// Called by -[BookmarkEditorBaseController ok:]. Creates the container
-// folder for the tabs and then the bookmarks in that new folder.
-// Returns a BOOL as an NSNumber indicating that the commit may proceed.
-- (NSNumber*)didCommit {
- NSString* name = [[self displayName] stringByTrimmingCharactersInSet:
- [NSCharacterSet newlineCharacterSet]];
- std::wstring newTitle = base::SysNSStringToWide(name);
- const BookmarkNode* newParentNode = [self selectedNode];
- int newIndex = newParentNode->GetChildCount();
- // Create the new folder which will contain all of the tab URLs.
- NSString* newFolderName = [self displayName];
- string16 newFolderString = base::SysNSStringToUTF16(newFolderName);
- BookmarkModel* model = [self bookmarkModel];
- const BookmarkNode* newFolder = model->AddGroup(newParentNode, newIndex,
- newFolderString);
- // Get a list of all open tabs, create nodes for them, and add
- // to the new folder node.
- [self UpdateActiveTabPairs];
- int i = 0;
- for (ActiveTabsNameURLPairVector::const_iterator it =
- activeTabPairsVector_.begin();
- it != activeTabPairsVector_.end(); ++it, ++i) {
- model->AddURL(newFolder, i, it->first, it->second);
- }
- return [NSNumber numberWithBool:YES];
-}
-
-- (ActiveTabsNameURLPairVector*)activeTabPairsVector {
- return &activeTabPairsVector_;
-}
-
-@end // BookmarkAllTabsController
-
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_all_tabs_controller_unittest.mm b/chrome/browser/cocoa/bookmarks/bookmark_all_tabs_controller_unittest.mm
deleted file mode 100644
index 2fb42f0..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_all_tabs_controller_unittest.mm
+++ /dev/null
@@ -1,82 +0,0 @@
-// 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 "base/scoped_nsobject.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_all_tabs_controller.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-@interface BookmarkAllTabsControllerOverride : BookmarkAllTabsController
-@end
-
-@implementation BookmarkAllTabsControllerOverride
-
-- (void)UpdateActiveTabPairs {
- ActiveTabsNameURLPairVector* activeTabPairsVector =
- [self activeTabPairsVector];
- activeTabPairsVector->clear();
- activeTabPairsVector->push_back(
- ActiveTabNameURLPair(ASCIIToUTF16("at-0"), GURL("http://at-0.com")));
- activeTabPairsVector->push_back(
- ActiveTabNameURLPair(ASCIIToUTF16("at-1"), GURL("http://at-1.com")));
- activeTabPairsVector->push_back(
- ActiveTabNameURLPair(ASCIIToUTF16("at-2"), GURL("http://at-2.com")));
-}
-
-@end
-
-class BookmarkAllTabsControllerTest : public CocoaTest {
- public:
- BrowserTestHelper helper_;
- const BookmarkNode* parent_node_;
- BookmarkAllTabsControllerOverride* controller_;
- const BookmarkNode* group_a_;
-
- BookmarkAllTabsControllerTest() {
- BookmarkModel& model(*(helper_.profile()->GetBookmarkModel()));
- const BookmarkNode* root = model.GetBookmarkBarNode();
- group_a_ = model.AddGroup(root, 0, ASCIIToUTF16("a"));
- model.AddURL(group_a_, 0, ASCIIToUTF16("a-0"), GURL("http://a-0.com"));
- model.AddURL(group_a_, 1, ASCIIToUTF16("a-1"), GURL("http://a-1.com"));
- model.AddURL(group_a_, 2, ASCIIToUTF16("a-2"), GURL("http://a-2.com"));
- }
-
- virtual BookmarkAllTabsControllerOverride* CreateController() {
- return [[BookmarkAllTabsControllerOverride alloc]
- initWithParentWindow:test_window()
- profile:helper_.profile()
- parent:group_a_
- configuration:BookmarkEditor::SHOW_TREE];
- }
-
- virtual void SetUp() {
- CocoaTest::SetUp();
- controller_ = CreateController();
- [controller_ runAsModalSheet];
- }
-
- virtual void TearDown() {
- controller_ = NULL;
- CocoaTest::TearDown();
- }
-};
-
-TEST_F(BookmarkAllTabsControllerTest, BookmarkAllTabs) {
- // OK button should always be enabled.
- EXPECT_TRUE([controller_ okButtonEnabled]);
- [controller_ selectTestNodeInBrowser:group_a_];
- [controller_ setDisplayName:@"ALL MY TABS"];
- [controller_ ok:nil];
- EXPECT_EQ(4, group_a_->GetChildCount());
- const BookmarkNode* folderChild = group_a_->GetChild(3);
- EXPECT_EQ(folderChild->GetTitle(), ASCIIToUTF16("ALL MY TABS"));
- EXPECT_EQ(3, folderChild->GetChildCount());
-}
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_bridge.h b/chrome/browser/cocoa/bookmarks/bookmark_bar_bridge.h
deleted file mode 100644
index a0bc1a7..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_bridge.h
+++ /dev/null
@@ -1,60 +0,0 @@
-// 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.
-
-// C++ bridge class between Chromium and Cocoa to connect the
-// Bookmarks (model) with the Bookmark Bar (view).
-//
-// There is exactly one BookmarkBarBridge per BookmarkBarController /
-// BrowserWindowController / Browser.
-
-#ifndef CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BAR_BRIDGE_H_
-#define CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BAR_BRIDGE_H_
-#pragma once
-
-#include "base/basictypes.h"
-#include "chrome/browser/bookmarks/bookmark_model_observer.h"
-
-class Browser;
-@class BookmarkBarController;
-
-class BookmarkBarBridge : public BookmarkModelObserver {
- public:
- BookmarkBarBridge(BookmarkBarController* controller,
- BookmarkModel* model);
- virtual ~BookmarkBarBridge();
-
- // Overridden from BookmarkModelObserver
- virtual void Loaded(BookmarkModel* model);
- virtual void BookmarkModelBeingDeleted(BookmarkModel* model);
- virtual void BookmarkNodeMoved(BookmarkModel* model,
- const BookmarkNode* old_parent,
- int old_index,
- const BookmarkNode* new_parent,
- int new_index);
- virtual void BookmarkNodeAdded(BookmarkModel* model,
- const BookmarkNode* parent,
- int index);
- virtual void BookmarkNodeRemoved(BookmarkModel* model,
- const BookmarkNode* parent,
- int old_index,
- const BookmarkNode* node);
- virtual void BookmarkNodeChanged(BookmarkModel* model,
- const BookmarkNode* node);
- virtual void BookmarkNodeFavIconLoaded(BookmarkModel* model,
- const BookmarkNode* node);
- virtual void BookmarkNodeChildrenReordered(BookmarkModel* model,
- const BookmarkNode* node);
-
- virtual void BookmarkImportBeginning(BookmarkModel* model);
- virtual void BookmarkImportEnding(BookmarkModel* model);
-
- private:
- BookmarkBarController* controller_; // weak; owns me
- BookmarkModel* model_; // weak; it is owned by a Profile.
- bool batch_mode_;
-
- DISALLOW_COPY_AND_ASSIGN(BookmarkBarBridge);
-};
-
-#endif // CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BAR_BRIDGE_H_
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_bridge.mm b/chrome/browser/cocoa/bookmarks/bookmark_bar_bridge.mm
deleted file mode 100644
index dc38b91..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_bridge.mm
+++ /dev/null
@@ -1,82 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/bookmarks/bookmark_bar_bridge.h"
-
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#include "chrome/browser/cocoa/bookmarks/bookmark_bar_controller.h"
-
-BookmarkBarBridge::BookmarkBarBridge(BookmarkBarController* controller,
- BookmarkModel* model)
- : controller_(controller),
- model_(model),
- batch_mode_(false) {
- model_->AddObserver(this);
-
- // Bookmark loading is async; it may may not have happened yet.
- // We will be notified when that happens with the AddObserver() call.
- if (model->IsLoaded())
- Loaded(model);
-}
-
-BookmarkBarBridge::~BookmarkBarBridge() {
- model_->RemoveObserver(this);
-}
-
-void BookmarkBarBridge::Loaded(BookmarkModel* model) {
- [controller_ loaded:model];
-}
-
-void BookmarkBarBridge::BookmarkModelBeingDeleted(BookmarkModel* model) {
- [controller_ beingDeleted:model];
-}
-
-void BookmarkBarBridge::BookmarkNodeMoved(BookmarkModel* model,
- const BookmarkNode* old_parent,
- int old_index,
- const BookmarkNode* new_parent,
- int new_index) {
- [controller_ nodeMoved:model
- oldParent:old_parent oldIndex:old_index
- newParent:new_parent newIndex:new_index];
-}
-
-void BookmarkBarBridge::BookmarkNodeAdded(BookmarkModel* model,
- const BookmarkNode* parent,
- int index) {
- if (!batch_mode_) {
- [controller_ nodeAdded:model parent:parent index:index];
- }
-}
-
-void BookmarkBarBridge::BookmarkNodeRemoved(BookmarkModel* model,
- const BookmarkNode* parent,
- int old_index,
- const BookmarkNode* node) {
- [controller_ nodeRemoved:model parent:parent index:old_index];
-}
-
-void BookmarkBarBridge::BookmarkNodeChanged(BookmarkModel* model,
- const BookmarkNode* node) {
- [controller_ nodeChanged:model node:node];
-}
-
-void BookmarkBarBridge::BookmarkNodeFavIconLoaded(BookmarkModel* model,
- const BookmarkNode* node) {
- [controller_ nodeFavIconLoaded:model node:node];
-}
-
-void BookmarkBarBridge::BookmarkNodeChildrenReordered(
- BookmarkModel* model, const BookmarkNode* node) {
- [controller_ nodeChildrenReordered:model node:node];
-}
-
-void BookmarkBarBridge::BookmarkImportBeginning(BookmarkModel* model) {
- batch_mode_ = true;
-}
-
-void BookmarkBarBridge::BookmarkImportEnding(BookmarkModel* model) {
- batch_mode_ = false;
- [controller_ loaded:model];
-}
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_bridge_unittest.mm b/chrome/browser/cocoa/bookmarks/bookmark_bar_bridge_unittest.mm
deleted file mode 100644
index 567761e..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_bridge_unittest.mm
+++ /dev/null
@@ -1,135 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/bookmarks/bookmark_bar_bridge.h"
-#include "chrome/browser/cocoa/bookmarks/bookmark_bar_controller.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-// TODO(jrg): use OCMock.
-
-namespace {
-
-// Information needed to open a URL, as passed to the
-// BookmarkBarController's delegate.
-typedef std::pair<GURL,WindowOpenDisposition> OpenInfo;
-
-} // The namespace must end here -- I need to use OpenInfo in
- // FakeBookmarkBarController but can't place
- // FakeBookmarkBarController itself in the namespace ("error:
- // Objective-C declarations may only appear in global scope")
-
-// Oddly, we are our own delegate.
-@interface FakeBookmarkBarController : BookmarkBarController {
- @public
- scoped_nsobject<NSMutableArray> callbacks_;
- std::vector<OpenInfo> opens_;
-}
-@end
-
-@implementation FakeBookmarkBarController
-
-- (id)initWithBrowser:(Browser*)browser {
- if ((self = [super initWithBrowser:browser
- initialWidth:100 // arbitrary
- delegate:nil
- resizeDelegate:nil])) {
- callbacks_.reset([[NSMutableArray alloc] init]);
- }
- return self;
-}
-
-- (void)loaded:(BookmarkModel*)model {
- [callbacks_ addObject:[NSNumber numberWithInt:0]];
-}
-
-- (void)beingDeleted:(BookmarkModel*)model {
- [callbacks_ addObject:[NSNumber numberWithInt:1]];
-}
-
-- (void)nodeMoved:(BookmarkModel*)model
- oldParent:(const BookmarkNode*)oldParent oldIndex:(int)oldIndex
- newParent:(const BookmarkNode*)newParent newIndex:(int)newIndex {
- [callbacks_ addObject:[NSNumber numberWithInt:2]];
-}
-
-- (void)nodeAdded:(BookmarkModel*)model
- parent:(const BookmarkNode*)oldParent index:(int)index {
- [callbacks_ addObject:[NSNumber numberWithInt:3]];
-}
-
-- (void)nodeChanged:(BookmarkModel*)model
- node:(const BookmarkNode*)node {
- [callbacks_ addObject:[NSNumber numberWithInt:4]];
-}
-
-- (void)nodeFavIconLoaded:(BookmarkModel*)model
- node:(const BookmarkNode*)node {
- [callbacks_ addObject:[NSNumber numberWithInt:5]];
-}
-
-- (void)nodeChildrenReordered:(BookmarkModel*)model
- node:(const BookmarkNode*)node {
- [callbacks_ addObject:[NSNumber numberWithInt:6]];
-}
-
-- (void)nodeRemoved:(BookmarkModel*)model
- parent:(const BookmarkNode*)oldParent index:(int)index {
- [callbacks_ addObject:[NSNumber numberWithInt:7]];
-}
-
-// Save the request.
-- (void)openBookmarkURL:(const GURL&)url
- disposition:(WindowOpenDisposition)disposition {
- opens_.push_back(OpenInfo(url, disposition));
-}
-
-@end
-
-
-class BookmarkBarBridgeTest : public CocoaTest {
- public:
- BrowserTestHelper browser_test_helper_;
-};
-
-// Call all the callbacks; make sure they are all redirected to the objc object.
-TEST_F(BookmarkBarBridgeTest, TestRedirect) {
- Browser* browser = browser_test_helper_.browser();
- Profile* profile = browser_test_helper_.profile();
- BookmarkModel* model = profile->GetBookmarkModel();
-
- scoped_nsobject<NSView> parentView([[NSView alloc]
- initWithFrame:NSMakeRect(0,0,100,100)]);
- scoped_nsobject<NSView> webView([[NSView alloc]
- initWithFrame:NSMakeRect(0,0,100,100)]);
- scoped_nsobject<NSView> infoBarsView(
- [[NSView alloc] initWithFrame:NSMakeRect(0,0,100,100)]);
-
- scoped_nsobject<FakeBookmarkBarController>
- controller([[FakeBookmarkBarController alloc] initWithBrowser:browser]);
- EXPECT_TRUE(controller.get());
- scoped_ptr<BookmarkBarBridge> bridge(new BookmarkBarBridge(controller.get(),
- model));
- EXPECT_TRUE(bridge.get());
-
- bridge->Loaded(NULL);
- bridge->BookmarkModelBeingDeleted(NULL);
- bridge->BookmarkNodeMoved(NULL, NULL, 0, NULL, 0);
- bridge->BookmarkNodeAdded(NULL, NULL, 0);
- bridge->BookmarkNodeChanged(NULL, NULL);
- bridge->BookmarkNodeFavIconLoaded(NULL, NULL);
- bridge->BookmarkNodeChildrenReordered(NULL, NULL);
- bridge->BookmarkNodeRemoved(NULL, NULL, 0, NULL);
-
- // 8 calls above plus an initial Loaded() in init routine makes 9
- EXPECT_TRUE([controller.get()->callbacks_ count] == 9);
-
- for (int x = 1; x < 9; x++) {
- NSNumber* num = [NSNumber numberWithInt:x-1];
- EXPECT_NSEQ(num, [controller.get()->callbacks_ objectAtIndex:x]);
- }
-}
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_constants.h b/chrome/browser/cocoa/bookmarks/bookmark_bar_constants.h
deleted file mode 100644
index d1be28f..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_constants.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// 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.
-
-// Constants used for positioning the bookmark bar. These aren't placed in a
-// different file because they're conditionally included in cross platform code
-// and thus no Objective-C++ stuff.
-
-#ifndef CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BAR_CONSTANTS_H_
-#define CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BAR_CONSTANTS_H_
-#pragma once
-
-namespace bookmarks {
-
-// Correction used for computing other values based on the height.
-const int kVisualHeightOffset = 2;
-
-// Bar height, when opened in "always visible" mode. This is actually a little
-// smaller than it should be (by |kVisualHeightOffset| points) because of the
-// visual overlap with the main toolbar. When using this to compute values
-// other than the actual height of the toolbar, be sure to add
-// |kVisualHeightOffset|.
-const int kBookmarkBarHeight = 26;
-
-// Our height, when visible in "new tab page" mode.
-const int kNTPBookmarkBarHeight = 40;
-
-// The amount of space between the inner bookmark bar and the outer toolbar on
-// new tab pages.
-const int kNTPBookmarkBarPadding =
- (kNTPBookmarkBarHeight - (kBookmarkBarHeight + kVisualHeightOffset)) / 2;
-
-// The height of buttons in the bookmark bar.
-const int kBookmarkButtonHeight = kBookmarkBarHeight + kVisualHeightOffset;
-
-} // namespace bookmarks
-
-#endif // CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BAR_CONSTANTS_H_
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_controller.h b/chrome/browser/cocoa/bookmarks/bookmark_bar_controller.h
deleted file mode 100644
index 6d0a0f6..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_controller.h
+++ /dev/null
@@ -1,399 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BAR_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BAR_CONTROLLER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-#include <map>
-
-#import "base/chrome_application_mac.h"
-#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-#include "chrome/browser/cocoa/bookmarks/bookmark_bar_bridge.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_constants.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_state.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_toolbar_view.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_button.h"
-#include "chrome/browser/cocoa/tab_strip_model_observer_bridge.h"
-#include "webkit/glue/window_open_disposition.h"
-
-@class BookmarkBarController;
-@class BookmarkBarFolderController;
-@class BookmarkBarView;
-@class BookmarkButton;
-@class BookmarkButtonCell;
-@class BookmarkFolderTarget;
-class BookmarkModel;
-@class BookmarkMenu;
-class BookmarkNode;
-class Browser;
-class GURL;
-class PrefService;
-class TabContents;
-@class ToolbarController;
-@protocol ViewResizer;
-
-namespace bookmarks {
-
-// Magic numbers from Cole
-// TODO(jrg): create an objc-friendly version of bookmark_bar_constants.h?
-
-// Used as a maximum width for buttons on the bar.
-const CGFloat kDefaultBookmarkWidth = 150.0;
-
-// Horizontal frame inset for buttons in the bookmark bar.
-const CGFloat kBookmarkHorizontalPadding = 1.0;
-
-// Vertical frame inset for buttons in the bookmark bar.
-const CGFloat kBookmarkVerticalPadding = 2.0;
-
-// Used as a min/max width for buttons on menus (not on the bar).
-const CGFloat kBookmarkMenuButtonMinimumWidth = 100.0;
-const CGFloat kBookmarkMenuButtonMaximumWidth = 485.0;
-
-// Horizontal separation between a menu button and both edges of its menu.
-const CGFloat kBookmarkSubMenuHorizontalPadding = 5.0;
-
-// TODO(mrossetti): Add constant (kBookmarkVerticalSeparation) for the gap
-// between buttons in a folder menu. Right now we're using
-// kBookmarkVerticalPadding, which is dual purpose and wrong.
-// http://crbug.com/59057
-
-// Convenience constant giving the vertical distance from the top extent of one
-// folder button to the next button.
-const CGFloat kBookmarkButtonVerticalSpan =
- kBookmarkButtonHeight + kBookmarkVerticalPadding;
-
-// The minimum separation between a folder menu and the edge of the screen.
-// If the menu gets closer to the edge of the screen (either right or left)
-// then it is pops up in the opposite direction.
-// (See -[BookmarkBarFolderController childFolderWindowLeftForWidth:]).
-const CGFloat kBookmarkHorizontalScreenPadding = 8.0;
-
-// Our NSScrollView is supposed to be just barely big enough to fit its
-// contentView. It is actually a hair too small.
-// This turns on horizontal scrolling which, although slight, is awkward.
-// Make sure our window (and NSScrollView) are wider than its documentView
-// by at least this much.
-const CGFloat kScrollViewContentWidthMargin = 2;
-
-// Make subfolder menus overlap their parent menu a bit to give a better
-// perception of a menuing system.
-const CGFloat kBookmarkMenuOverlap = 5.0;
-
-// Delay before opening a subfolder (and closing the previous one)
-// when hovering over a folder button.
-const NSTimeInterval kHoverOpenDelay = 0.3;
-
-// Delay on hover before a submenu opens when dragging.
-// Experimentally a drag hover open delay needs to be bigger than a
-// normal (non-drag) menu hover open such as used in the bookmark folder.
-// TODO(jrg): confirm feel of this constant with ui-team.
-// http://crbug.com/36276
-const NSTimeInterval kDragHoverOpenDelay = 0.7;
-
-// Notes on use of kDragHoverCloseDelay in
-// -[BookmarkBarFolderController draggingEntered:].
-//
-// We have an implicit delay on stop-hover-open before a submenu
-// closes. This cannot be zero since it's nice to move the mouse in a
-// direct line from "current position" to "position of item in
-// submenu". However, by doing so, it's possible to overlap a
-// different button on the current menu. Example:
-//
-// Folder1
-// Folder2 ---> Sub1
-// Folder3 Sub2
-// Sub3
-//
-// If you hover over the F in Folder2 to open the sub, and then want to
-// select Sub3, a direct line movement of the mouse may cross over
-// Folder3. Without this delay, that'll cause Sub to be closed before
-// you get there, since a "hover over" of Folder3 gets activated.
-// It's subtle but without the delay it feels broken.
-//
-// This is only really a problem with vertical menu --> vertical menu
-// movement; the bookmark bar (horizontal menu, sort of) seems fine,
-// perhaps because mouse move direction is purely vertical so there is
-// no opportunity for overlap.
-const NSTimeInterval kDragHoverCloseDelay = 0.4;
-
-} // namespace bookmarks
-
-// The interface for the bookmark bar controller's delegate. Currently, the
-// delegate is the BWC and is responsible for ensuring that the toolbar is
-// displayed correctly (as specified by |-getDesiredToolbarHeightCompression|
-// and |-toolbarDividerOpacity|) at the beginning and at the end of an animation
-// (or after a state change).
-@protocol BookmarkBarControllerDelegate
-
-// Sent when the state has changed (after any animation), but before the final
-// display update.
-- (void)bookmarkBar:(BookmarkBarController*)controller
- didChangeFromState:(bookmarks::VisualState)oldState
- toState:(bookmarks::VisualState)newState;
-
-// Sent before the animation begins.
-- (void)bookmarkBar:(BookmarkBarController*)controller
-willAnimateFromState:(bookmarks::VisualState)oldState
- toState:(bookmarks::VisualState)newState;
-
-@end
-
-// A controller for the bookmark bar in the browser window. Handles showing
-// and hiding based on the preference in the given profile.
-@interface BookmarkBarController :
- NSViewController<BookmarkBarState,
- BookmarkBarToolbarViewController,
- BookmarkButtonDelegate,
- BookmarkButtonControllerProtocol,
- CrApplicationEventHookProtocol,
- NSUserInterfaceValidations> {
- @private
- // The visual state of the bookmark bar. If an animation is running, this is
- // set to the "destination" and |lastVisualState_| is set to the "original"
- // state. This is set to |kInvalidState| on initialization (when the
- // appropriate state is not yet known).
- bookmarks::VisualState visualState_;
-
- // The "original" state of the bookmark bar if an animation is running,
- // otherwise it should be |kInvalidState|.
- bookmarks::VisualState lastVisualState_;
-
- Browser* browser_; // weak; owned by its window
- BookmarkModel* bookmarkModel_; // weak; part of the profile owned by the
- // top-level Browser object.
-
- // Our initial view width, which is applied in awakeFromNib.
- CGFloat initialWidth_;
-
- // BookmarkNodes have a 64bit id. NSMenuItems have a 32bit tag used
- // to represent the bookmark node they refer to. This map provides
- // a mapping from one to the other, so we can properly identify the
- // node from the item. When adding items in, we start with seedId_.
- int32 seedId_;
- std::map<int32,int64> menuTagMap_;
-
- // Our bookmark buttons, ordered from L-->R.
- scoped_nsobject<NSMutableArray> buttons_;
-
- // The folder image so we can use one copy for all buttons
- scoped_nsobject<NSImage> folderImage_;
-
- // The default image, so we can use one copy for all buttons.
- scoped_nsobject<NSImage> defaultImage_;
-
- // If the bar is disabled, we hide it and ignore show/hide commands.
- // Set when using fullscreen mode.
- BOOL barIsEnabled_;
-
- // Bridge from Chrome-style C++ notifications (e.g. derived from
- // BookmarkModelObserver)
- scoped_ptr<BookmarkBarBridge> bridge_;
-
- // Delegate that is informed about state changes in the bookmark bar.
- id<BookmarkBarControllerDelegate> delegate_; // weak
-
- // Delegate that can resize us.
- id<ViewResizer> resizeDelegate_; // weak
-
- // Logic for dealing with a click on a bookmark folder button.
- scoped_nsobject<BookmarkFolderTarget> folderTarget_;
-
- // A controller for a pop-up bookmark folder window (custom menu).
- // This is not a scoped_nsobject because it owns itself (when its
- // window closes the controller gets autoreleased).
- BookmarkBarFolderController* folderController_;
-
- // Are watching for a "click outside" or other event which would
- // signal us to close the bookmark bar folder menus?
- BOOL watchingForExitEvent_;
-
- IBOutlet BookmarkBarView* buttonView_; // Contains 'no items' text fields.
- IBOutlet BookmarkButton* offTheSideButton_; // aka the chevron.
- IBOutlet NSMenu* buttonContextMenu_;
-
- NSRect originalNoItemsRect_; // Original, pre-resized field rect.
- NSRect originalImportBookmarksRect_; // Original, pre-resized field rect.
-
- // "Other bookmarks" button on the right side.
- scoped_nsobject<BookmarkButton> otherBookmarksButton_;
-
- // We have a special menu for folder buttons. This starts as a copy
- // of the bar menu.
- scoped_nsobject<BookmarkMenu> buttonFolderContextMenu_;
-
- // When doing a drag, this is folder button "hovered over" which we
- // may want to open after a short delay. There are cases where a
- // mouse-enter can open a folder (e.g. if the menus are "active")
- // but that doesn't use this variable or need a delay so "hover" is
- // the wrong term.
- scoped_nsobject<BookmarkButton> hoverButton_;
-
- // We save the view width when we add bookmark buttons. This lets
- // us avoid a rebuild until we've grown the window bigger than our
- // initial build.
- CGFloat savedFrameWidth_;
-
- // The number of buttons we display in the bookmark bar. This does
- // not include the "off the side" chevron or the "Other Bookmarks"
- // button. We use this number to determine if we need to display
- // the chevron, and to know what to place in the chevron's menu.
- // Since we create everything before doing layout we can't be sure
- // that all bookmark buttons we create will be visible. Thus,
- // [buttons_ count] isn't a definitive check.
- int displayedButtonCount_;
-
- // A state flag which tracks when the bar's folder menus should be shown.
- // An initial click in any of the folder buttons turns this on and
- // one of the following will turn it off: another click in the button,
- // the window losing focus, a click somewhere other than in the bar
- // or a folder menu.
- BOOL showFolderMenus_;
-
- // Set to YES to prevent any node animations. Useful for unit testing so that
- // incomplete animations do not cause valgrind complaints.
- BOOL ignoreAnimations_;
-}
-
-@property(readonly, nonatomic) bookmarks::VisualState visualState;
-@property(readonly, nonatomic) bookmarks::VisualState lastVisualState;
-@property(assign, nonatomic) id<BookmarkBarControllerDelegate> delegate;
-
-// Initializes the bookmark bar controller with the given browser
-// profile and delegates.
-- (id)initWithBrowser:(Browser*)browser
- initialWidth:(CGFloat)initialWidth
- delegate:(id<BookmarkBarControllerDelegate>)delegate
- resizeDelegate:(id<ViewResizer>)resizeDelegate;
-
-// Updates the bookmark bar (from its current, possibly in-transition) state to
-// the one appropriate for the new conditions.
-- (void)updateAndShowNormalBar:(BOOL)showNormalBar
- showDetachedBar:(BOOL)showDetachedBar
- withAnimation:(BOOL)animate;
-
-// Update the visible state of the bookmark bar.
-- (void)updateVisibility;
-
-// Turn on or off the bookmark bar and prevent or reallow its appearance. On
-// disable, toggle off if shown. On enable, show only if needed. App and popup
-// windows do not show a bookmark bar.
-- (void)setBookmarkBarEnabled:(BOOL)enabled;
-
-// Returns the amount by which the toolbar above should be compressed.
-- (CGFloat)getDesiredToolbarHeightCompression;
-
-// Gets the appropriate opacity for the toolbar's divider; 0 means that it
-// shouldn't be shown.
-- (CGFloat)toolbarDividerOpacity;
-
-// Updates the sizes and positions of the subviews.
-// TODO(viettrungluu): I'm not convinced this should be public, but I currently
-// need it for animations. Try not to propagate its use.
-- (void)layoutSubviews;
-
-// Called by our view when it is moved to a window.
-- (void)viewDidMoveToWindow;
-
-// Import bookmarks from another browser.
-- (IBAction)importBookmarks:(id)sender;
-
-// Provide a favIcon for a bookmark node. May return nil.
-- (NSImage*)favIconForNode:(const BookmarkNode*)node;
-
-// Used for situations where the bookmark bar folder menus should no longer
-// be actively popping up. Called when the window loses focus, a click has
-// occured outside the menus or a bookmark has been activated. (Note that this
-// differs from the behavior of the -[BookmarkButtonControllerProtocol
-// closeAllBookmarkFolders] method in that the latter does not terminate menu
-// tracking since it may be being called in response to actions (such as
-// dragging) where a 'stale' menu presentation should first be collapsed before
-// presenting a new menu.)
-- (void)closeFolderAndStopTrackingMenus;
-
-// Checks if operations such as edit or delete are allowed.
-- (BOOL)canEditBookmark:(const BookmarkNode*)node;
-
-// Actions for manipulating bookmarks.
-// Open a normal bookmark or folder from a button, ...
-- (IBAction)openBookmark:(id)sender;
-- (IBAction)openBookmarkFolderFromButton:(id)sender;
-// From the "off the side" button, ...
-- (IBAction)openOffTheSideFolderFromButton:(id)sender;
-// From a context menu over the button, ...
-- (IBAction)openBookmarkInNewForegroundTab:(id)sender;
-- (IBAction)openBookmarkInNewWindow:(id)sender;
-- (IBAction)openBookmarkInIncognitoWindow:(id)sender;
-- (IBAction)editBookmark:(id)sender;
-- (IBAction)cutBookmark:(id)sender;
-- (IBAction)copyBookmark:(id)sender;
-- (IBAction)pasteBookmark:(id)sender;
-- (IBAction)deleteBookmark:(id)sender;
-// From a context menu over the bar, ...
-- (IBAction)openAllBookmarks:(id)sender;
-- (IBAction)openAllBookmarksNewWindow:(id)sender;
-- (IBAction)openAllBookmarksIncognitoWindow:(id)sender;
-// Or from a context menu over either the bar or a button.
-- (IBAction)addPage:(id)sender;
-- (IBAction)addFolder:(id)sender;
-
-@end
-
-// Redirects from BookmarkBarBridge, the C++ object which glues us to
-// the rest of Chromium. Internal to BookmarkBarController.
-@interface BookmarkBarController(BridgeRedirect)
-- (void)loaded:(BookmarkModel*)model;
-- (void)beingDeleted:(BookmarkModel*)model;
-- (void)nodeAdded:(BookmarkModel*)model
- parent:(const BookmarkNode*)oldParent index:(int)index;
-- (void)nodeChanged:(BookmarkModel*)model
- node:(const BookmarkNode*)node;
-- (void)nodeMoved:(BookmarkModel*)model
- oldParent:(const BookmarkNode*)oldParent oldIndex:(int)oldIndex
- newParent:(const BookmarkNode*)newParent newIndex:(int)newIndex;
-- (void)nodeRemoved:(BookmarkModel*)model
- parent:(const BookmarkNode*)oldParent index:(int)index;
-- (void)nodeFavIconLoaded:(BookmarkModel*)model
- node:(const BookmarkNode*)node;
-- (void)nodeChildrenReordered:(BookmarkModel*)model
- node:(const BookmarkNode*)node;
-@end
-
-// These APIs should only be used by unit tests (or used internally).
-@interface BookmarkBarController(InternalOrTestingAPI)
-- (BookmarkBarView*)buttonView;
-- (NSMutableArray*)buttons;
-- (NSMenu*)offTheSideMenu;
-- (NSButton*)offTheSideButton;
-- (BOOL)offTheSideButtonIsHidden;
-- (BookmarkButton*)otherBookmarksButton;
-- (BookmarkBarFolderController*)folderController;
-- (id)folderTarget;
-- (int)displayedButtonCount;
-- (void)openURL:(GURL)url disposition:(WindowOpenDisposition)disposition;
-- (void)clearBookmarkBar;
-- (BookmarkButtonCell*)cellForBookmarkNode:(const BookmarkNode*)node;
-- (NSRect)frameForBookmarkButtonFromCell:(NSCell*)cell xOffset:(int*)xOffset;
-- (void)checkForBookmarkButtonGrowth:(NSButton*)button;
-- (void)frameDidChange;
-- (int64)nodeIdFromMenuTag:(int32)tag;
-- (int32)menuTagFromNodeId:(int64)menuid;
-- (const BookmarkNode*)nodeFromMenuItem:(id)sender;
-- (void)updateTheme:(ThemeProvider*)themeProvider;
-- (BookmarkButton*)buttonForDroppingOnAtPoint:(NSPoint)point;
-- (BOOL)isEventAnExitEvent:(NSEvent*)event;
-- (BOOL)shrinkOrHideView:(NSView*)view forMaxX:(CGFloat)maxViewX;
-
-// The following are for testing purposes only and are not used internally.
-- (NSMenu *)menuForFolderNode:(const BookmarkNode*)node;
-- (NSMenu*)buttonContextMenu;
-- (void)setButtonContextMenu:(id)menu;
-// Set to YES in order to prevent animations.
-- (void)setIgnoreAnimations:(BOOL)ignore;
-@end
-
-#endif // CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BAR_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_controller.mm b/chrome/browser/cocoa/bookmarks/bookmark_bar_controller.mm
deleted file mode 100644
index 3ba0fc9..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_controller.mm
+++ /dev/null
@@ -1,2497 +0,0 @@
-// 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 "chrome/browser/cocoa/bookmarks/bookmark_bar_controller.h"
-
-#include "app/l10n_util_mac.h"
-#include "app/resource_bundle.h"
-#include "base/mac_util.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/bookmarks/bookmark_editor.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#include "chrome/browser/bookmarks/bookmark_utils.h"
-#import "chrome/browser/cocoa/background_gradient_view.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_bridge.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_folder_controller.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_folder_window.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_toolbar_view.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_view.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_button.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_button_cell.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_editor_controller.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_folder_target.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_menu.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_menu_cocoa_controller.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_name_folder_controller.h"
-#import "chrome/browser/cocoa/browser_window_controller.h"
-#import "chrome/browser/cocoa/event_utils.h"
-#import "chrome/browser/cocoa/fullscreen_controller.h"
-#import "chrome/browser/cocoa/import_settings_dialog.h"
-#import "chrome/browser/cocoa/menu_button.h"
-#import "chrome/browser/cocoa/themed_window.h"
-#import "chrome/browser/cocoa/toolbar_controller.h"
-#import "chrome/browser/cocoa/view_id_util.h"
-#import "chrome/browser/cocoa/view_resizer.h"
-#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents/tab_contents_view.h"
-#import "chrome/browser/themes/browser_theme_provider.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_list.h"
-#include "chrome/common/pref_names.h"
-#include "grit/app_resources.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#include "skia/ext/skia_utils_mac.h"
-
-// Bookmark bar state changing and animations
-//
-// The bookmark bar has three real states: "showing" (a normal bar attached to
-// the toolbar), "hidden", and "detached" (pretending to be part of the web
-// content on the NTP). It can, or at least should be able to, animate between
-// these states. There are several complications even without animation:
-// - The placement of the bookmark bar is done by the BWC, and it needs to know
-// the state in order to place the bookmark bar correctly (immediately below
-// the toolbar when showing, below the infobar when detached).
-// - The "divider" (a black line) needs to be drawn by either the toolbar (when
-// the bookmark bar is hidden or detached) or by the bookmark bar (when it is
-// showing). It should not be drawn by both.
-// - The toolbar needs to vertically "compress" when the bookmark bar is
-// showing. This ensures the proper display of both the bookmark bar and the
-// toolbar, and gives a padded area around the bookmark bar items for right
-// clicks, etc.
-//
-// Our model is that the BWC controls us and also the toolbar. We try not to
-// talk to the browser nor the toolbar directly, instead centralizing control in
-// the BWC. The key method by which the BWC controls us is
-// |-updateAndShowNormalBar:showDetachedBar:withAnimation:|. This invokes state
-// changes, and at appropriate times we request that the BWC do things for us
-// via either the resize delegate or our general delegate. If the BWC needs any
-// information about what it should do, or tell the toolbar to do, it can then
-// query us back (e.g., |-isShownAs...|, |-getDesiredToolbarHeightCompression|,
-// |-toolbarDividerOpacity|, etc.).
-//
-// Animation-related complications:
-// - Compression of the toolbar is touchy during animation. It must not be
-// compressed while the bookmark bar is animating to/from showing (from/to
-// hidden), otherwise it would look like the bookmark bar's contents are
-// sliding out of the controls inside the toolbar. As such, we have to make
-// sure that the bookmark bar is shown at the right location and at the
-// right height (at various points in time).
-// - Showing the divider is also complicated during animation between hidden
-// and showing. We have to make sure that the toolbar does not show the
-// divider despite the fact that it's not compressed. The exception to this
-// is at the beginning/end of the animation when the toolbar is still
-// uncompressed but the bookmark bar has height 0. If we're not careful, we
-// get a flicker at this point.
-// - We have to ensure that we do the right thing if we're told to change state
-// while we're running an animation. The generic/easy thing to do is to jump
-// to the end state of our current animation, and (if the new state change
-// again involves an animation) begin the new animation. We can do better
-// than that, however, and sometimes just change the current animation to go
-// to the new end state (e.g., by "reversing" the animation in the showing ->
-// hidden -> showing case). We also have to ensure that demands to
-// immediately change state are always honoured.
-//
-// Pointers to animation logic:
-// - |-moveToVisualState:withAnimation:| starts animations, deciding which ones
-// we know how to handle.
-// - |-doBookmarkBarAnimation| has most of the actual logic.
-// - |-getDesiredToolbarHeightCompression| and |-toolbarDividerOpacity| contain
-// related logic.
-// - The BWC's |-layoutSubviews| needs to know how to position things.
-// - The BWC should implement |-bookmarkBar:didChangeFromState:toState:| and
-// |-bookmarkBar:willAnimateFromState:toState:| in order to inform the
-// toolbar of required changes.
-
-namespace {
-
-// Overlap (in pixels) between the toolbar and the bookmark bar (when showing in
-// normal mode).
-const CGFloat kBookmarkBarOverlap = 3.0;
-
-// Duration of the bookmark bar animations.
-const NSTimeInterval kBookmarkBarAnimationDuration = 0.12;
-
-} // namespace
-
-@interface BookmarkBarController(Private)
-
-// Determines the appropriate state for the given situation.
-+ (bookmarks::VisualState)visualStateToShowNormalBar:(BOOL)showNormalBar
- showDetachedBar:(BOOL)showDetachedBar;
-
-// Moves to the given next state (from the current state), possibly animating.
-// If |animate| is NO, it will stop any running animation and jump to the given
-// state. If YES, it may either (depending on implementation) jump to the end of
-// the current animation and begin the next one, or stop the current animation
-// mid-flight and animate to the next state.
-- (void)moveToVisualState:(bookmarks::VisualState)nextVisualState
- withAnimation:(BOOL)animate;
-
-// Return the backdrop to the bookmark bar as various types.
-- (BackgroundGradientView*)backgroundGradientView;
-- (AnimatableView*)animatableView;
-
-// Create buttons for all items in the given bookmark node tree.
-// Modifies self->buttons_. Do not add more buttons than will fit on the view.
-- (void)addNodesToButtonList:(const BookmarkNode*)node;
-
-// Create an autoreleased button appropriate for insertion into the bookmark
-// bar. Update |xOffset| with the offset appropriate for the subsequent button.
-- (BookmarkButton*)buttonForNode:(const BookmarkNode*)node
- xOffset:(int*)xOffset;
-
-// Puts stuff into the final visual state without animating, stopping a running
-// animation if necessary.
-- (void)finalizeVisualState;
-
-// Stops any current animation in its tracks (midway).
-- (void)stopCurrentAnimation;
-
-// Show/hide the bookmark bar.
-// if |animate| is YES, the changes are made using the animator; otherwise they
-// are made immediately.
-- (void)showBookmarkBarWithAnimation:(BOOL)animate;
-
-// Handles animating the resize of the content view. Returns YES if it handled
-// the animation, NO if not (and hence it should be done instantly).
-- (BOOL)doBookmarkBarAnimation;
-
-// |point| is in the base coordinate system of the destination window;
-// it comes from an id<NSDraggingInfo>. |copy| is YES if a copy is to be
-// made and inserted into the new location while leaving the bookmark in
-// the old location, otherwise move the bookmark by removing from its old
-// location and inserting into the new location.
-- (BOOL)dragBookmark:(const BookmarkNode*)sourceNode
- to:(NSPoint)point
- copy:(BOOL)copy;
-
-// Returns the index in the model for a drag to the location given by
-// |point|. This is determined by finding the first button before the center
-// of which |point| falls, scanning left to right. Note that, currently, only
-// the x-coordinate of |point| is considered. Though not currently implemented,
-// we may check for errors, in which case this would return negative value;
-// callers should check for this.
-- (int)indexForDragToPoint:(NSPoint)point;
-
-// Add or remove buttons to/from the bar until it is filled but not overflowed.
-- (void)redistributeButtonsOnBarAsNeeded;
-
-// Determine the nature of the bookmark bar contents based on the number of
-// buttons showing. If too many then show the off-the-side list, if none
-// then show the no items label.
-- (void)reconfigureBookmarkBar;
-
-- (void)addNode:(const BookmarkNode*)child toMenu:(NSMenu*)menu;
-- (void)addFolderNode:(const BookmarkNode*)node toMenu:(NSMenu*)menu;
-- (void)tagEmptyMenu:(NSMenu*)menu;
-- (void)clearMenuTagMap;
-- (int)preferredHeight;
-- (void)addNonBookmarkButtonsToView;
-- (void)addButtonsToView;
-- (void)centerNoItemsLabel;
-- (void)setNodeForBarMenu;
-
-- (void)watchForExitEvent:(BOOL)watch;
-
-@end
-
-@implementation BookmarkBarController
-
-@synthesize visualState = visualState_;
-@synthesize lastVisualState = lastVisualState_;
-@synthesize delegate = delegate_;
-
-- (id)initWithBrowser:(Browser*)browser
- initialWidth:(float)initialWidth
- delegate:(id<BookmarkBarControllerDelegate>)delegate
- resizeDelegate:(id<ViewResizer>)resizeDelegate {
- if ((self = [super initWithNibName:@"BookmarkBar"
- bundle:mac_util::MainAppBundle()])) {
- // Initialize to an invalid state.
- visualState_ = bookmarks::kInvalidState;
- lastVisualState_ = bookmarks::kInvalidState;
-
- browser_ = browser;
- initialWidth_ = initialWidth;
- bookmarkModel_ = browser_->profile()->GetBookmarkModel();
- buttons_.reset([[NSMutableArray alloc] init]);
- delegate_ = delegate;
- resizeDelegate_ = resizeDelegate;
- folderTarget_.reset([[BookmarkFolderTarget alloc] initWithController:self]);
-
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- folderImage_.reset(
- [rb.GetNativeImageNamed(IDR_BOOKMARK_BAR_FOLDER) retain]);
- defaultImage_.reset([rb.GetNativeImageNamed(IDR_DEFAULT_FAVICON) retain]);
-
- // Register for theme changes, bookmark button pulsing, ...
- NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
- [defaultCenter addObserver:self
- selector:@selector(themeDidChangeNotification:)
- name:kBrowserThemeDidChangeNotification
- object:nil];
- [defaultCenter addObserver:self
- selector:@selector(pulseBookmarkNotification:)
- name:bookmark_button::kPulseBookmarkButtonNotification
- object:nil];
-
- // This call triggers an awakeFromNib, which builds the bar, which
- // might uses folderImage_. So make sure it happens after
- // folderImage_ is loaded.
- [[self animatableView] setResizeDelegate:resizeDelegate];
- }
- return self;
-}
-
-- (void)pulseBookmarkNotification:(NSNotification*)notification {
- NSDictionary* dict = [notification userInfo];
- const BookmarkNode* node = NULL;
- NSValue *value = [dict objectForKey:bookmark_button::kBookmarkKey];
- DCHECK(value);
- if (value)
- node = static_cast<const BookmarkNode*>([value pointerValue]);
- NSNumber* number = [dict
- objectForKey:bookmark_button::kBookmarkPulseFlagKey];
- DCHECK(number);
- BOOL doPulse = number ? [number boolValue] : NO;
-
- // 3 cases:
- // button on the bar: flash it
- // button in "other bookmarks" folder: flash other bookmarks
- // button in "off the side" folder: flash the chevron
- for (BookmarkButton* button in [self buttons]) {
- if ([button bookmarkNode] == node) {
- [button setIsContinuousPulsing:doPulse];
- return;
- }
- }
- if ([otherBookmarksButton_ bookmarkNode] == node) {
- [otherBookmarksButton_ setIsContinuousPulsing:doPulse];
- return;
- }
- if (node->GetParent() == bookmarkModel_->GetBookmarkBarNode()) {
- [offTheSideButton_ setIsContinuousPulsing:doPulse];
- return;
- }
-
- NOTREACHED() << "no bookmark button found to pulse!";
-}
-
-- (void)dealloc {
- // We better stop any in-flight animation if we're being killed.
- [[self animatableView] stopAnimation];
-
- // Remove our view from its superview so it doesn't attempt to reference
- // it when the controller is gone.
- //TODO(dmaclach): Remove -- http://crbug.com/25845
- [[self view] removeFromSuperview];
-
- // Be sure there is no dangling pointer.
- if ([[self view] respondsToSelector:@selector(setController:)])
- [[self view] performSelector:@selector(setController:) withObject:nil];
-
- // For safety, make sure the buttons can no longer call us.
- for (BookmarkButton* button in buttons_.get()) {
- [button setDelegate:nil];
- [button setTarget:nil];
- [button setAction:nil];
- }
-
- bridge_.reset(NULL);
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [self watchForExitEvent:NO];
- [super dealloc];
-}
-
-- (void)awakeFromNib {
- // We default to NOT open, which means height=0.
- DCHECK([[self view] isHidden]); // Hidden so it's OK to change.
-
- // Set our initial height to zero, since that is what the superview
- // expects. We will resize ourselves open later if needed.
- [[self view] setFrame:NSMakeRect(0, 0, initialWidth_, 0)];
-
- // Complete init of the "off the side" button, as much as we can.
- [offTheSideButton_ setDraggable:NO];
-
- // We are enabled by default.
- barIsEnabled_ = YES;
-
- // Remember the original sizes of the 'no items' and 'import bookmarks'
- // fields to aid in resizing when the window frame changes.
- originalNoItemsRect_ = [[buttonView_ noItemTextfield] frame];
- originalImportBookmarksRect_ = [[buttonView_ importBookmarksButton] frame];
-
- // To make life happier when the bookmark bar is floating, the chevron is a
- // child of the button view.
- [offTheSideButton_ removeFromSuperview];
- [buttonView_ addSubview:offTheSideButton_];
-
- // Copy the bar menu so we know if it's from the bar or a folder.
- // Then we set its represented item to be the bookmark bar.
- buttonFolderContextMenu_.reset([[[self view] menu] copy]);
-
- // When resized we may need to add new buttons, or remove them (if
- // no longer visible), or add/remove the "off the side" menu.
- [[self view] setPostsFrameChangedNotifications:YES];
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(frameDidChange)
- name:NSViewFrameDidChangeNotification
- object:[self view]];
-
- // Watch for things going to or from fullscreen.
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(willEnterOrLeaveFullscreen:)
- name:kWillEnterFullscreenNotification
- object:nil];
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(willEnterOrLeaveFullscreen:)
- name:kWillLeaveFullscreenNotification
- object:nil];
-
- // Don't pass ourself along (as 'self') until our init is completely
- // done. Thus, this call is (almost) last.
- bridge_.reset(new BookmarkBarBridge(self, bookmarkModel_));
-}
-
-// Called by our main view (a BookmarkBarView) when it gets moved to a
-// window. We perform operations which need to know the relevant
-// window (e.g. watch for a window close) so they can't be performed
-// earlier (such as in awakeFromNib).
-- (void)viewDidMoveToWindow {
- NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
-
- // Remove any existing notifications before registering for new ones.
- [defaultCenter removeObserver:self
- name:NSWindowWillCloseNotification
- object:nil];
- [defaultCenter removeObserver:self
- name:NSWindowDidResignKeyNotification
- object:nil];
-
- [defaultCenter addObserver:self
- selector:@selector(parentWindowWillClose:)
- name:NSWindowWillCloseNotification
- object:[[self view] window]];
- [defaultCenter addObserver:self
- selector:@selector(parentWindowDidResignKey:)
- name:NSWindowDidResignKeyNotification
- object:[[self view] window]];
-}
-
-// When going fullscreen we can run into trouble. Our view is removed
-// from the non-fullscreen window before the non-fullscreen window
-// loses key, so our parentDidResignKey: callback never gets called.
-// In addition, a bookmark folder controller needs to be autoreleased
-// (in case it's in the event chain when closed), but the release
-// implicitly needs to happen while it's connected to the original
-// (non-fullscreen) window to "unlock bar visibility". Such a
-// contract isn't honored when going fullscreen with the menu option
-// (not with the keyboard shortcut). We fake it as best we can here.
-// We have a similar problem leaving fullscreen.
-- (void)willEnterOrLeaveFullscreen:(NSNotification*)notification {
- if (folderController_) {
- [self childFolderWillClose:folderController_];
- [self closeFolderAndStopTrackingMenus];
- }
-}
-
-// NSNotificationCenter callback.
-- (void)parentWindowWillClose:(NSNotification*)notification {
- [self closeFolderAndStopTrackingMenus];
-}
-
-// NSNotificationCenter callback.
-- (void)parentWindowDidResignKey:(NSNotification*)notification {
- [self closeFolderAndStopTrackingMenus];
-}
-
-// Change the layout of the bookmark bar's subviews in response to a visibility
-// change (e.g., show or hide the bar) or style change (attached or floating).
-- (void)layoutSubviews {
- NSRect frame = [[self view] frame];
- NSRect buttonViewFrame = NSMakeRect(0, 0, NSWidth(frame), NSHeight(frame));
-
- // The state of our morph (if any); 1 is total bubble, 0 is the regular bar.
- CGFloat morph = [self detachedMorphProgress];
-
- // Add padding to the detached bookmark bar.
- buttonViewFrame = NSInsetRect(buttonViewFrame,
- morph * bookmarks::kNTPBookmarkBarPadding,
- morph * bookmarks::kNTPBookmarkBarPadding);
-
- [buttonView_ setFrame:buttonViewFrame];
-}
-
-// We don't change a preference; we only change visibility. Preference changing
-// (global state) is handled in |BrowserWindowCocoa::ToggleBookmarkBar()|. We
-// simply update based on what we're told.
-- (void)updateVisibility {
- [self showBookmarkBarWithAnimation:NO];
-}
-
-- (void)setBookmarkBarEnabled:(BOOL)enabled {
- if (enabled != barIsEnabled_) {
- barIsEnabled_ = enabled;
- [self updateVisibility];
- }
-}
-
-- (CGFloat)getDesiredToolbarHeightCompression {
- // Some special cases....
- if (!barIsEnabled_)
- return 0;
-
- if ([self isAnimationRunning]) {
- // No toolbar compression when animating between hidden and showing, nor
- // between showing and detached.
- if ([self isAnimatingBetweenState:bookmarks::kHiddenState
- andState:bookmarks::kShowingState] ||
- [self isAnimatingBetweenState:bookmarks::kShowingState
- andState:bookmarks::kDetachedState])
- return 0;
-
- // If we ever need any other animation cases, code would go here.
- }
-
- return [self isInState:bookmarks::kShowingState] ? kBookmarkBarOverlap : 0;
-}
-
-- (CGFloat)toolbarDividerOpacity {
- // Some special cases....
- if ([self isAnimationRunning]) {
- // In general, the toolbar shouldn't show a divider while we're animating
- // between showing and hidden. The exception is when our height is < 1, in
- // which case we can't draw it. It's all-or-nothing (no partial opacity).
- if ([self isAnimatingBetweenState:bookmarks::kHiddenState
- andState:bookmarks::kShowingState])
- return (NSHeight([[self view] frame]) < 1) ? 1 : 0;
-
- // The toolbar should show the divider when animating between showing and
- // detached (but opacity will vary).
- if ([self isAnimatingBetweenState:bookmarks::kShowingState
- andState:bookmarks::kDetachedState])
- return static_cast<CGFloat>([self detachedMorphProgress]);
-
- // If we ever need any other animation cases, code would go here.
- }
-
- // In general, only show the divider when it's in the normal showing state.
- return [self isInState:bookmarks::kShowingState] ? 0 : 1;
-}
-
-- (NSImage*)favIconForNode:(const BookmarkNode*)node {
- if (!node)
- return defaultImage_;
-
- if (node->is_folder())
- return folderImage_;
-
- const SkBitmap& favIcon = bookmarkModel_->GetFavIcon(node);
- if (!favIcon.isNull())
- return gfx::SkBitmapToNSImage(favIcon);
-
- return defaultImage_;
-}
-
-- (void)closeFolderAndStopTrackingMenus {
- showFolderMenus_ = NO;
- [self closeAllBookmarkFolders];
-}
-
-- (BOOL)canEditBookmark:(const BookmarkNode*)node {
- // Don't allow edit/delete of the bar node, or of "Other Bookmarks"
- if ((node == nil) ||
- (node == bookmarkModel_->other_node()) ||
- (node == bookmarkModel_->GetBookmarkBarNode()))
- return NO;
- return YES;
-}
-
-#pragma mark Actions
-
-- (IBAction)openBookmark:(id)sender {
- [self closeFolderAndStopTrackingMenus];
- DCHECK([sender respondsToSelector:@selector(bookmarkNode)]);
- const BookmarkNode* node = [sender bookmarkNode];
- WindowOpenDisposition disposition =
- event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
- [self openURL:node->GetURL() disposition:disposition];
-}
-
-// Redirect to our logic shared with BookmarkBarFolderController.
-- (IBAction)openBookmarkFolderFromButton:(id)sender {
- if (sender != offTheSideButton_) {
- // Toggle presentation of bar folder menus.
- showFolderMenus_ = !showFolderMenus_;
- [folderTarget_ openBookmarkFolderFromButton:sender];
- } else {
- // Off-the-side requires special handling.
- [self openOffTheSideFolderFromButton:sender];
- }
-}
-
-// The button that sends this one is special; the "off the side"
-// button (chevron) opens like a folder button but isn't exactly a
-// parent folder.
-- (IBAction)openOffTheSideFolderFromButton:(id)sender {
- DCHECK([sender isKindOfClass:[BookmarkButton class]]);
- DCHECK([[sender cell] isKindOfClass:[BookmarkButtonCell class]]);
- [[sender cell] setStartingChildIndex:displayedButtonCount_];
- [folderTarget_ openBookmarkFolderFromButton:sender];
-}
-
-- (IBAction)openBookmarkInNewForegroundTab:(id)sender {
- const BookmarkNode* node = [self nodeFromMenuItem:sender];
- if (node)
- [self openURL:node->GetURL() disposition:NEW_FOREGROUND_TAB];
- [self closeAllBookmarkFolders];
-}
-
-- (IBAction)openBookmarkInNewWindow:(id)sender {
- const BookmarkNode* node = [self nodeFromMenuItem:sender];
- if (node)
- [self openURL:node->GetURL() disposition:NEW_WINDOW];
-}
-
-- (IBAction)openBookmarkInIncognitoWindow:(id)sender {
- const BookmarkNode* node = [self nodeFromMenuItem:sender];
- if (node)
- [self openURL:node->GetURL() disposition:OFF_THE_RECORD];
-}
-
-- (IBAction)editBookmark:(id)sender {
- const BookmarkNode* node = [self nodeFromMenuItem:sender];
- if (!node)
- return;
-
- if (node->is_folder()) {
- BookmarkNameFolderController* controller =
- [[BookmarkNameFolderController alloc]
- initWithParentWindow:[[self view] window]
- profile:browser_->profile()
- node:node];
- [controller runAsModalSheet];
- return;
- }
-
- // There is no real need to jump to a platform-common routine at
- // this point (which just jumps back to objc) other than consistency
- // across platforms.
- //
- // TODO(jrg): identify when we NO_TREE. I can see it in the code
- // for the other platforms but can't find a way to trigger it in the
- // UI.
- BookmarkEditor::Show([[self view] window],
- browser_->profile(),
- node->GetParent(),
- BookmarkEditor::EditDetails(node),
- BookmarkEditor::SHOW_TREE);
-}
-
-- (IBAction)cutBookmark:(id)sender {
- const BookmarkNode* node = [self nodeFromMenuItem:sender];
- if (node) {
- std::vector<const BookmarkNode*> nodes;
- nodes.push_back(node);
- bookmark_utils::CopyToClipboard(bookmarkModel_, nodes, true);
- }
-}
-
-- (IBAction)copyBookmark:(id)sender {
- const BookmarkNode* node = [self nodeFromMenuItem:sender];
- if (node) {
- std::vector<const BookmarkNode*> nodes;
- nodes.push_back(node);
- bookmark_utils::CopyToClipboard(bookmarkModel_, nodes, false);
- }
-}
-
-// Paste the copied node immediately after the node for which the context
-// menu has been presented if the node is a non-folder bookmark, otherwise
-// past at the end of the folder node.
-- (IBAction)pasteBookmark:(id)sender {
- const BookmarkNode* node = [self nodeFromMenuItem:sender];
- if (node) {
- int index = -1;
- if (node != bookmarkModel_->GetBookmarkBarNode() && !node->is_folder()) {
- const BookmarkNode* parent = node->GetParent();
- index = parent->IndexOfChild(node) + 1;
- if (index > parent->GetChildCount())
- index = -1;
- node = parent;
- }
- bookmark_utils::PasteFromClipboard(bookmarkModel_, node, index);
- }
-}
-
-- (IBAction)deleteBookmark:(id)sender {
- const BookmarkNode* node = [self nodeFromMenuItem:sender];
- if (node) {
- bookmarkModel_->Remove(node->GetParent(),
- node->GetParent()->IndexOfChild(node));
- }
-}
-
-- (IBAction)openAllBookmarks:(id)sender {
- const BookmarkNode* node = [self nodeFromMenuItem:sender];
- if (node) {
- [self openAll:node disposition:NEW_FOREGROUND_TAB];
- UserMetrics::RecordAction(UserMetricsAction("OpenAllBookmarks"),
- browser_->profile());
- }
-}
-
-- (IBAction)openAllBookmarksNewWindow:(id)sender {
- const BookmarkNode* node = [self nodeFromMenuItem:sender];
- if (node) {
- [self openAll:node disposition:NEW_WINDOW];
- UserMetrics::RecordAction(UserMetricsAction("OpenAllBookmarksNewWindow"),
- browser_->profile());
- }
-}
-
-- (IBAction)openAllBookmarksIncognitoWindow:(id)sender {
- const BookmarkNode* node = [self nodeFromMenuItem:sender];
- if (node) {
- [self openAll:node disposition:OFF_THE_RECORD];
- UserMetrics::RecordAction(
- UserMetricsAction("OpenAllBookmarksIncognitoWindow"),
- browser_->profile());
- }
-}
-
-// May be called from the bar or from a folder button.
-// If called from a button, that button becomes the parent.
-- (IBAction)addPage:(id)sender {
- const BookmarkNode* parent = [self nodeFromMenuItem:sender];
- if (!parent)
- parent = bookmarkModel_->GetBookmarkBarNode();
- BookmarkEditor::Show([[self view] window],
- browser_->profile(),
- parent,
- BookmarkEditor::EditDetails(),
- BookmarkEditor::SHOW_TREE);
-}
-
-// Might be called from the context menu over the bar OR over a
-// button. If called from a button, that button becomes a sibling of
-// the new node. If called from the bar, add to the end of the bar.
-- (IBAction)addFolder:(id)sender {
- const BookmarkNode* senderNode = [self nodeFromMenuItem:sender];
- const BookmarkNode* parent = NULL;
- int newIndex = 0;
- // If triggered from the bar, folder or "others" folder - add as a child to
- // the end.
- // If triggered from a bookmark, add as next sibling.
- BookmarkNode::Type type = senderNode->type();
- if (type == BookmarkNode::BOOKMARK_BAR ||
- type == BookmarkNode::OTHER_NODE ||
- type == BookmarkNode::FOLDER) {
- parent = senderNode;
- newIndex = parent->GetChildCount();
- } else {
- parent = senderNode->GetParent();
- newIndex = parent->IndexOfChild(senderNode) + 1;
- }
- BookmarkNameFolderController* controller =
- [[BookmarkNameFolderController alloc]
- initWithParentWindow:[[self view] window]
- profile:browser_->profile()
- parent:parent
- newIndex:newIndex];
- [controller runAsModalSheet];
-}
-
-- (IBAction)importBookmarks:(id)sender {
- [ImportSettingsDialogController showImportSettingsDialogForProfile:
- browser_->profile()];
-}
-
-#pragma mark Private Methods
-
-// Called after the current theme has changed.
-- (void)themeDidChangeNotification:(NSNotification*)aNotification {
- ThemeProvider* themeProvider =
- static_cast<ThemeProvider*>([[aNotification object] pointerValue]);
- [self updateTheme:themeProvider];
-}
-
-// (Private) Method is the same as [self view], but is provided to be explicit.
-- (BackgroundGradientView*)backgroundGradientView {
- DCHECK([[self view] isKindOfClass:[BackgroundGradientView class]]);
- return (BackgroundGradientView*)[self view];
-}
-
-// (Private) Method is the same as [self view], but is provided to be explicit.
-- (AnimatableView*)animatableView {
- DCHECK([[self view] isKindOfClass:[AnimatableView class]]);
- return (AnimatableView*)[self view];
-}
-
-// Position the off-the-side chevron to the left of the otherBookmarks button.
-- (void)positionOffTheSideButton {
- NSRect frame = [offTheSideButton_ frame];
- if (otherBookmarksButton_.get()) {
- frame.origin.x = ([otherBookmarksButton_ frame].origin.x -
- (frame.size.width +
- bookmarks::kBookmarkHorizontalPadding));
- [offTheSideButton_ setFrame:frame];
- }
-}
-
-// Configure the off-the-side button (e.g. specify the node range,
-// check if we should enable or disable it, etc).
-- (void)configureOffTheSideButtonContentsAndVisibility {
- // If deleting a button while off-the-side is open, buttons may be
- // promoted from off-the-side to the bar. Accomodate.
- if (folderController_ &&
- ([folderController_ parentButton] == offTheSideButton_)) {
- [folderController_ reconfigureMenu];
- }
-
- [[offTheSideButton_ cell] setStartingChildIndex:displayedButtonCount_];
- [[offTheSideButton_ cell]
- setBookmarkNode:bookmarkModel_->GetBookmarkBarNode()];
- int bookmarkChildren = bookmarkModel_->GetBookmarkBarNode()->GetChildCount();
- if (bookmarkChildren > displayedButtonCount_) {
- [offTheSideButton_ setHidden:NO];
- } else {
- // If we just deleted the last item in an off-the-side menu so the
- // button will be going away, make sure the menu goes away.
- if (folderController_ &&
- ([folderController_ parentButton] == offTheSideButton_))
- [self closeAllBookmarkFolders];
- // (And hide the button, too.)
- [offTheSideButton_ setHidden:YES];
- }
-}
-
-// Begin (or end) watching for a click outside this window. Unlike
-// normal NSWindows, bookmark folder "fake menu" windows do not become
-// key or main. Thus, traditional notification (e.g. WillResignKey)
-// won't work. Our strategy is to watch (at the app level) for a
-// "click outside" these windows to detect when they logically lose
-// focus.
-- (void)watchForExitEvent:(BOOL)watch {
- CrApplication* app = static_cast<CrApplication*>([NSApplication
- sharedApplication]);
- DCHECK([app isKindOfClass:[CrApplication class]]);
- if (watch) {
- if (!watchingForExitEvent_)
- [app addEventHook:self];
- } else {
- if (watchingForExitEvent_)
- [app removeEventHook:self];
- }
- watchingForExitEvent_ = watch;
-}
-
-// Keep the "no items" label centered in response to a frame size change.
-- (void)centerNoItemsLabel {
- // Note that this computation is done in the parent's coordinate system,
- // which is unflipped. Also, we want the label to be a fixed distance from
- // the bottom, so that it slides up properly (on animating to hidden).
- // The textfield sits in the itemcontainer, so to center it we maintain
- // equal vertical padding on the top and bottom.
- int yoffset = (NSHeight([[buttonView_ noItemTextfield] frame]) -
- NSHeight([[buttonView_ noItemContainer] frame])) / 2;
- [[buttonView_ noItemContainer] setFrameOrigin:NSMakePoint(0, yoffset)];
-}
-
-// (Private)
-- (void)showBookmarkBarWithAnimation:(BOOL)animate {
- if (animate && !ignoreAnimations_) {
- // If |-doBookmarkBarAnimation| does the animation, we're done.
- if ([self doBookmarkBarAnimation])
- return;
-
- // Else fall through and do the change instantly.
- }
-
- // Set our height.
- [resizeDelegate_ resizeView:[self view]
- newHeight:[self preferredHeight]];
-
- // Only show the divider if showing the normal bookmark bar.
- BOOL showsDivider = [self isInState:bookmarks::kShowingState];
- [[self backgroundGradientView] setShowsDivider:showsDivider];
-
- // Make sure we're shown.
- [[self view] setHidden:![self isVisible]];
-
- // Update everything else.
- [self layoutSubviews];
- [self frameDidChange];
-}
-
-// (Private)
-- (BOOL)doBookmarkBarAnimation {
- if ([self isAnimatingFromState:bookmarks::kHiddenState
- toState:bookmarks::kShowingState]) {
- [[self backgroundGradientView] setShowsDivider:YES];
- [[self view] setHidden:NO];
- AnimatableView* view = [self animatableView];
- // Height takes into account the extra height we have since the toolbar
- // only compresses when we're done.
- [view animateToNewHeight:(bookmarks::kBookmarkBarHeight -
- kBookmarkBarOverlap)
- duration:kBookmarkBarAnimationDuration];
- } else if ([self isAnimatingFromState:bookmarks::kShowingState
- toState:bookmarks::kHiddenState]) {
- [[self backgroundGradientView] setShowsDivider:YES];
- [[self view] setHidden:NO];
- AnimatableView* view = [self animatableView];
- [view animateToNewHeight:0
- duration:kBookmarkBarAnimationDuration];
- } else if ([self isAnimatingFromState:bookmarks::kShowingState
- toState:bookmarks::kDetachedState]) {
- [[self backgroundGradientView] setShowsDivider:YES];
- [[self view] setHidden:NO];
- AnimatableView* view = [self animatableView];
- [view animateToNewHeight:bookmarks::kNTPBookmarkBarHeight
- duration:kBookmarkBarAnimationDuration];
- } else if ([self isAnimatingFromState:bookmarks::kDetachedState
- toState:bookmarks::kShowingState]) {
- [[self backgroundGradientView] setShowsDivider:YES];
- [[self view] setHidden:NO];
- AnimatableView* view = [self animatableView];
- // Height takes into account the extra height we have since the toolbar
- // only compresses when we're done.
- [view animateToNewHeight:(bookmarks::kBookmarkBarHeight -
- kBookmarkBarOverlap)
- duration:kBookmarkBarAnimationDuration];
- } else {
- // Oops! An animation we don't know how to handle.
- return NO;
- }
-
- return YES;
-}
-
-// Enable or disable items. We are the menu delegate for both the bar
-// and for bookmark folder buttons.
-- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)anItem {
- // NSUserInterfaceValidations says that the passed-in object has type
- // |id<NSValidatedUserInterfaceItem>|, but this function needs to call the
- // NSObject method -isKindOfClass: on the parameter. In theory, this is not
- // correct, but this is probably a bug in the method signature.
- NSMenuItem* item = static_cast<NSMenuItem*>(anItem);
- // Yes for everything we don't explicitly deny.
- if (![item isKindOfClass:[NSMenuItem class]])
- return YES;
-
- // Yes if we're not a special BookmarkMenu.
- if (![[item menu] isKindOfClass:[BookmarkMenu class]])
- return YES;
-
- // No if we think it's a special BookmarkMenu but have trouble.
- const BookmarkNode* node = [self nodeFromMenuItem:item];
- if (!node)
- return NO;
-
- // If this is the bar menu, we only have things to do if there are
- // buttons. If this is a folder button menu, we only have things to
- // do if the folder has items.
- NSMenu* menu = [item menu];
- BOOL thingsToDo = NO;
- if (menu == [[self view] menu]) {
- thingsToDo = [buttons_ count] ? YES : NO;
- } else {
- if (node && node->is_folder() && node->GetChildCount()) {
- thingsToDo = YES;
- }
- }
-
- // Disable openAll* if we have nothing to do.
- SEL action = [item action];
- if ((!thingsToDo) &&
- ((action == @selector(openAllBookmarks:)) ||
- (action == @selector(openAllBookmarksNewWindow:)) ||
- (action == @selector(openAllBookmarksIncognitoWindow:)))) {
- return NO;
- }
-
- if ((action == @selector(editBookmark:)) ||
- (action == @selector(deleteBookmark:)) ||
- (action == @selector(cutBookmark:)) ||
- (action == @selector(copyBookmark:))) {
- if (![self canEditBookmark:node]) {
- return NO;
- }
- }
-
- if (action == @selector(pasteBookmark:) &&
- !bookmark_utils::CanPasteFromClipboard(node))
- return NO;
-
- // If this is an incognito window, don't allow "open in incognito".
- if ((action == @selector(openBookmarkInIncognitoWindow:)) ||
- (action == @selector(openAllBookmarksIncognitoWindow:))) {
- if (browser_->profile()->IsOffTheRecord()) {
- return NO;
- }
- }
-
- // Enabled by default.
- return YES;
-}
-
-// Actually open the URL. This is the last chance for a unit test to
-// override.
-- (void)openURL:(GURL)url disposition:(WindowOpenDisposition)disposition {
- browser_->OpenURL(url, GURL(), disposition, PageTransition::AUTO_BOOKMARK);
-}
-
-- (void)clearMenuTagMap {
- seedId_ = 0;
- menuTagMap_.clear();
-}
-
-- (int)preferredHeight {
- DCHECK(![self isAnimationRunning]);
-
- if (!barIsEnabled_)
- return 0;
-
- switch (visualState_) {
- case bookmarks::kShowingState:
- return bookmarks::kBookmarkBarHeight;
- case bookmarks::kDetachedState:
- return bookmarks::kNTPBookmarkBarHeight;
- case bookmarks::kHiddenState:
- return 0;
- case bookmarks::kInvalidState:
- default:
- NOTREACHED();
- return 0;
- }
-}
-
-// Recursively add the given bookmark node and all its children to
-// menu, one menu item per node.
-- (void)addNode:(const BookmarkNode*)child toMenu:(NSMenu*)menu {
- NSString* title = [BookmarkMenuCocoaController menuTitleForNode:child];
- NSMenuItem* item = [[[NSMenuItem alloc] initWithTitle:title
- action:nil
- keyEquivalent:@""] autorelease];
- [menu addItem:item];
- [item setImage:[self favIconForNode:child]];
- if (child->is_folder()) {
- NSMenu* submenu = [[[NSMenu alloc] initWithTitle:title] autorelease];
- [menu setSubmenu:submenu forItem:item];
- if (child->GetChildCount()) {
- [self addFolderNode:child toMenu:submenu]; // potentially recursive
- } else {
- [self tagEmptyMenu:submenu];
- }
- } else {
- [item setTarget:self];
- [item setAction:@selector(openBookmarkMenuItem:)];
- [item setTag:[self menuTagFromNodeId:child->id()]];
- // Add a tooltip
- std::string url_string = child->GetURL().possibly_invalid_spec();
- NSString* tooltip = [NSString stringWithFormat:@"%@\n%s",
- base::SysUTF16ToNSString(child->GetTitle()),
- url_string.c_str()];
- [item setToolTip:tooltip];
- }
-}
-
-// Empty menus are odd; if empty, add something to look at.
-// Matches windows behavior.
-- (void)tagEmptyMenu:(NSMenu*)menu {
- NSString* empty_menu_title = l10n_util::GetNSString(IDS_MENU_EMPTY_SUBMENU);
- [menu addItem:[[[NSMenuItem alloc] initWithTitle:empty_menu_title
- action:NULL
- keyEquivalent:@""] autorelease]];
-}
-
-// Add the children of the given bookmark node (and their children...)
-// to menu, one menu item per node.
-- (void)addFolderNode:(const BookmarkNode*)node toMenu:(NSMenu*)menu {
- for (int i = 0; i < node->GetChildCount(); i++) {
- const BookmarkNode* child = node->GetChild(i);
- [self addNode:child toMenu:menu];
- }
-}
-
-// Return an autoreleased NSMenu that represents the given bookmark
-// folder node.
-- (NSMenu *)menuForFolderNode:(const BookmarkNode*)node {
- if (!node->is_folder())
- return nil;
- NSString* title = base::SysUTF16ToNSString(node->GetTitle());
- NSMenu* menu = [[[NSMenu alloc] initWithTitle:title] autorelease];
- [self addFolderNode:node toMenu:menu];
-
- if (![menu numberOfItems]) {
- [self tagEmptyMenu:menu];
- }
- return menu;
-}
-
-// Return an appropriate width for the given bookmark button cell.
-// The "+2" is needed because, sometimes, Cocoa is off by a tad.
-// Example: for a bookmark named "Moma" or "SFGate", it is one pixel
-// too small. For "FBL" it is 2 pixels too small.
-// For a bookmark named "SFGateFooWoo", it is just fine.
-- (CGFloat)widthForBookmarkButtonCell:(NSCell*)cell {
- CGFloat desired = [cell cellSize].width + 2;
- return std::min(desired, bookmarks::kDefaultBookmarkWidth);
-}
-
-- (IBAction)openBookmarkMenuItem:(id)sender {
- int64 tag = [self nodeIdFromMenuTag:[sender tag]];
- const BookmarkNode* node = bookmarkModel_->GetNodeByID(tag);
- WindowOpenDisposition disposition =
- event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
- [self openURL:node->GetURL() disposition:disposition];
-}
-
-// For the given root node of the bookmark bar, show or hide (as
-// appropriate) the "no items" container (text which says "bookmarks
-// go here").
-- (void)showOrHideNoItemContainerForNode:(const BookmarkNode*)node {
- BOOL hideNoItemWarning = node->GetChildCount() > 0;
- [[buttonView_ noItemContainer] setHidden:hideNoItemWarning];
-}
-
-// TODO(jrg): write a "build bar" so there is a nice spot for things
-// like the contextual menu which is invoked when not over a
-// bookmark. On Safari that menu has a "new folder" option.
-- (void)addNodesToButtonList:(const BookmarkNode*)node {
- [self showOrHideNoItemContainerForNode:node];
-
- CGFloat maxViewX = NSMaxX([[self view] bounds]);
- int xOffset = 0;
- for (int i = 0; i < node->GetChildCount(); i++) {
- const BookmarkNode* child = node->GetChild(i);
- BookmarkButton* button = [self buttonForNode:child xOffset:&xOffset];
- if (NSMinX([button frame]) >= maxViewX)
- break;
- [buttons_ addObject:button];
- }
-}
-
-- (BookmarkButton*)buttonForNode:(const BookmarkNode*)node
- xOffset:(int*)xOffset {
- BookmarkButtonCell* cell = [self cellForBookmarkNode:node];
- NSRect frame = [self frameForBookmarkButtonFromCell:cell xOffset:xOffset];
-
- scoped_nsobject<BookmarkButton>
- button([[BookmarkButton alloc] initWithFrame:frame]);
- DCHECK(button.get());
-
- // [NSButton setCell:] warns to NOT use setCell: other than in the
- // initializer of a control. However, we are using a basic
- // NSButton whose initializer does not take an NSCell as an
- // object. To honor the assumed semantics, we do nothing with
- // NSButton between alloc/init and setCell:.
- [button setCell:cell];
- [button setDelegate:self];
-
- // We cannot set the button cell's text color until it is placed in
- // the button (e.g. the [button setCell:cell] call right above). We
- // also cannot set the cell's text color until the view is added to
- // the hierarchy. If that second part is now true, set the color.
- // (If not we'll set the color on the 1st themeChanged:
- // notification.)
- ThemeProvider* themeProvider = [[[self view] window] themeProvider];
- if (themeProvider) {
- NSColor* color =
- themeProvider->GetNSColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT,
- true);
- [cell setTextColor:color];
- }
-
- if (node->is_folder()) {
- [button setTarget:self];
- [button setAction:@selector(openBookmarkFolderFromButton:)];
- } else {
- // Make the button do something
- [button setTarget:self];
- [button setAction:@selector(openBookmark:)];
- // Add a tooltip.
- NSString* title = base::SysUTF16ToNSString(node->GetTitle());
- std::string url_string = node->GetURL().possibly_invalid_spec();
- NSString* tooltip = [NSString stringWithFormat:@"%@\n%s", title,
- url_string.c_str()];
- [button setToolTip:tooltip];
- }
- return [[button.get() retain] autorelease];
-}
-
-// Add non-bookmark buttons to the view. This includes the chevron
-// and the "other bookmarks" button. Technically "other bookmarks" is
-// a bookmark button but it is treated specially. Only needs to be
-// called when these buttons are new or when the bookmark bar is
-// cleared (e.g. on a loaded: call). Unlike addButtonsToView below,
-// we don't need to add/remove these dynamically in response to window
-// resize.
-- (void)addNonBookmarkButtonsToView {
- [buttonView_ addSubview:otherBookmarksButton_.get()];
- [buttonView_ addSubview:offTheSideButton_];
-}
-
-// Add bookmark buttons to the view only if they are completely
-// visible and don't overlap the "other bookmarks". Remove buttons
-// which are clipped. Called when building the bookmark bar the first time.
-- (void)addButtonsToView {
- displayedButtonCount_ = 0;
- NSMutableArray* buttons = [self buttons];
- for (NSButton* button in buttons) {
- if (NSMaxX([button frame]) > (NSMinX([offTheSideButton_ frame]) -
- bookmarks::kBookmarkHorizontalPadding))
- break;
- [buttonView_ addSubview:button];
- ++displayedButtonCount_;
- }
- NSUInteger removalCount =
- [buttons count] - (NSUInteger)displayedButtonCount_;
- if (removalCount > 0) {
- NSRange removalRange = NSMakeRange(displayedButtonCount_, removalCount);
- [buttons removeObjectsInRange:removalRange];
- }
-}
-
-// Create the button for "Other Bookmarks" on the right of the bar.
-- (void)createOtherBookmarksButton {
- // Can't create this until the model is loaded, but only need to
- // create it once.
- if (otherBookmarksButton_.get())
- return;
-
- // TODO(jrg): remove duplicate code
- NSCell* cell = [self cellForBookmarkNode:bookmarkModel_->other_node()];
- int ignored = 0;
- NSRect frame = [self frameForBookmarkButtonFromCell:cell xOffset:&ignored];
- frame.origin.x = [[self buttonView] bounds].size.width - frame.size.width;
- frame.origin.x -= bookmarks::kBookmarkHorizontalPadding;
- BookmarkButton* button = [[BookmarkButton alloc] initWithFrame:frame];
- [button setDraggable:NO];
- otherBookmarksButton_.reset(button);
- view_id_util::SetID(button, VIEW_ID_OTHER_BOOKMARKS);
-
- // Make sure this button, like all other BookmarkButtons, lives
- // until the end of the current event loop.
- [[button retain] autorelease];
-
- // Peg at right; keep same height as bar.
- [button setAutoresizingMask:(NSViewMinXMargin)];
- [button setCell:cell];
- [button setDelegate:self];
- [button setTarget:self];
- [button setAction:@selector(openBookmarkFolderFromButton:)];
- [buttonView_ addSubview:button];
-
- // Now that it's here, move the chevron over.
- [self positionOffTheSideButton];
-}
-
-// Now that the model is loaded, set the bookmark bar root as the node
-// represented by the bookmark bar (default, background) menu.
-- (void)setNodeForBarMenu {
- const BookmarkNode* node = bookmarkModel_->GetBookmarkBarNode();
- BookmarkMenu* menu = static_cast<BookmarkMenu*>([[self view] menu]);
-
- // Make sure types are compatible
- DCHECK(sizeof(long long) == sizeof(int64));
- [menu setRepresentedObject:[NSNumber numberWithLongLong:node->id()]];
-}
-
-// To avoid problems with sync, changes that may impact the current
-// bookmark (e.g. deletion) make sure context menus are closed. This
-// prevents deleting a node which no longer exists.
-- (void)cancelMenuTracking {
- [buttonContextMenu_ cancelTracking];
- [buttonFolderContextMenu_ cancelTracking];
-}
-
-// Determines the appropriate state for the given situation.
-+ (bookmarks::VisualState)visualStateToShowNormalBar:(BOOL)showNormalBar
- showDetachedBar:(BOOL)showDetachedBar {
- if (showNormalBar)
- return bookmarks::kShowingState;
- if (showDetachedBar)
- return bookmarks::kDetachedState;
- return bookmarks::kHiddenState;
-}
-
-- (void)moveToVisualState:(bookmarks::VisualState)nextVisualState
- withAnimation:(BOOL)animate {
- BOOL isAnimationRunning = [self isAnimationRunning];
-
- // No-op if the next state is the same as the "current" one, subject to the
- // following conditions:
- // - no animation is running; or
- // - an animation is running and |animate| is YES ([*] if it's NO, we'd want
- // to cancel the animation and jump to the final state).
- if ((nextVisualState == visualState_) && (!isAnimationRunning || animate))
- return;
-
- // If an animation is running, we want to finalize it. Otherwise we'd have to
- // be able to animate starting from the middle of one type of animation. We
- // assume that animations that we know about can be "reversed".
- if (isAnimationRunning) {
- // Don't cancel if we're going to reverse the animation.
- if (nextVisualState != lastVisualState_) {
- [self stopCurrentAnimation];
- [self finalizeVisualState];
- }
-
- // If we're in case [*] above, we can stop here.
- if (nextVisualState == visualState_)
- return;
- }
-
- // Now update with the new state change.
- lastVisualState_ = visualState_;
- visualState_ = nextVisualState;
-
- // Animate only if told to and if bar is enabled.
- if (animate && !ignoreAnimations_ && barIsEnabled_) {
- [self closeAllBookmarkFolders];
- // Take care of any animation cases we know how to handle.
-
- // We know how to handle hidden <-> normal, normal <-> detached....
- if ([self isAnimatingBetweenState:bookmarks::kHiddenState
- andState:bookmarks::kShowingState] ||
- [self isAnimatingBetweenState:bookmarks::kShowingState
- andState:bookmarks::kDetachedState]) {
- [delegate_ bookmarkBar:self willAnimateFromState:lastVisualState_
- toState:visualState_];
- [self showBookmarkBarWithAnimation:YES];
- return;
- }
-
- // If we ever need any other animation cases, code would go here.
- // Let any animation cases which we don't know how to handle fall through to
- // the unanimated case.
- }
-
- // Just jump to the state.
- [self finalizeVisualState];
-}
-
-// N.B.: |-moveToVisualState:...| will check if this should be a no-op or not.
-- (void)updateAndShowNormalBar:(BOOL)showNormalBar
- showDetachedBar:(BOOL)showDetachedBar
- withAnimation:(BOOL)animate {
- bookmarks::VisualState newVisualState =
- [BookmarkBarController visualStateToShowNormalBar:showNormalBar
- showDetachedBar:showDetachedBar];
- [self moveToVisualState:newVisualState
- withAnimation:animate && !ignoreAnimations_];
-}
-
-// (Private)
-- (void)finalizeVisualState {
- // We promise that our delegate that the variables will be finalized before
- // the call to |-bookmarkBar:didChangeFromState:toState:|.
- bookmarks::VisualState oldVisualState = lastVisualState_;
- lastVisualState_ = bookmarks::kInvalidState;
-
- // Notify our delegate.
- [delegate_ bookmarkBar:self didChangeFromState:oldVisualState
- toState:visualState_];
-
- // Update ourselves visually.
- [self updateVisibility];
-}
-
-// (Private)
-- (void)stopCurrentAnimation {
- [[self animatableView] stopAnimation];
-}
-
-// Delegate method for |AnimatableView| (a superclass of
-// |BookmarkBarToolbarView|).
-- (void)animationDidEnd:(NSAnimation*)animation {
- [self finalizeVisualState];
-}
-
-- (void)reconfigureBookmarkBar {
- [self redistributeButtonsOnBarAsNeeded];
- [self positionOffTheSideButton];
- [self configureOffTheSideButtonContentsAndVisibility];
- [self centerNoItemsLabel];
-}
-
-// Determine if the given |view| can completely fit within the constraint of
-// maximum x, given by |maxViewX|, and, if not, narrow the view up to a minimum
-// width. If the minimum width is not achievable then hide the view. Return YES
-// if the view was hidden.
-- (BOOL)shrinkOrHideView:(NSView*)view forMaxX:(CGFloat)maxViewX {
- BOOL wasHidden = NO;
- // See if the view needs to be narrowed.
- NSRect frame = [view frame];
- if (NSMaxX(frame) > maxViewX) {
- // Resize if more than 30 pixels are showing, otherwise hide.
- if (NSMinX(frame) + 30.0 < maxViewX) {
- frame.size.width = maxViewX - NSMinX(frame);
- [view setFrame:frame];
- } else {
- [view setHidden:YES];
- wasHidden = YES;
- }
- }
- return wasHidden;
-}
-
-// Adjust the horizontal width and the visibility of the "For quick access"
-// text field and "Import bookmarks..." button based on the current width
-// of the containing |buttonView_| (which is affected by window width).
-- (void)adjustNoItemContainerWidthsForMaxX:(CGFloat)maxViewX {
- if (![[buttonView_ noItemContainer] isHidden]) {
- // Reset initial frames for the two items, then adjust as necessary.
- NSTextField* noItemTextfield = [buttonView_ noItemTextfield];
- [noItemTextfield setFrame:originalNoItemsRect_];
- [noItemTextfield setHidden:NO];
- NSButton* importBookmarksButton = [buttonView_ importBookmarksButton];
- [importBookmarksButton setFrame:originalImportBookmarksRect_];
- [importBookmarksButton setHidden:NO];
- // Check each to see if they need to be shrunk or hidden.
- if ([self shrinkOrHideView:importBookmarksButton forMaxX:maxViewX])
- [self shrinkOrHideView:noItemTextfield forMaxX:maxViewX];
- }
-}
-
-- (void)redistributeButtonsOnBarAsNeeded {
- const BookmarkNode* node = bookmarkModel_->GetBookmarkBarNode();
- NSInteger barCount = node->GetChildCount();
-
- // Determine the current maximum extent of the visible buttons.
- CGFloat maxViewX = NSMaxX([[self view] bounds]);
- NSButton* otherBookmarksButton = otherBookmarksButton_.get();
- // If necessary, pull in the width to account for the Other Bookmarks button.
- if (otherBookmarksButton_)
- maxViewX = [otherBookmarksButton frame].origin.x -
- bookmarks::kBookmarkHorizontalPadding;
- // If we're already overflowing, then we need to account for the chevron.
- if (barCount > displayedButtonCount_)
- maxViewX = [offTheSideButton_ frame].origin.x -
- bookmarks::kBookmarkHorizontalPadding;
-
- // As a result of pasting or dragging, the bar may now have more buttons
- // than will fit so remove any which overflow. They will be shown in
- // the off-the-side folder.
- while (displayedButtonCount_ > 0) {
- BookmarkButton* button = [buttons_ lastObject];
- if (NSMaxX([button frame]) < maxViewX)
- break;
- [buttons_ removeLastObject];
- [button setDelegate:nil];
- [button removeFromSuperview];
- --displayedButtonCount_;
- }
-
- // As a result of cutting, deleting and dragging, the bar may now have room
- // for more buttons.
- int xOffset = displayedButtonCount_ > 0 ?
- NSMaxX([[buttons_ lastObject] frame]) +
- bookmarks::kBookmarkHorizontalPadding : 0;
- for (int i = displayedButtonCount_; i < barCount; ++i) {
- const BookmarkNode* child = node->GetChild(i);
- BookmarkButton* button = [self buttonForNode:child xOffset:&xOffset];
- // If we're testing against the last possible button then account
- // for the chevron no longer needing to be shown.
- if (i == barCount + 1)
- maxViewX += NSWidth([offTheSideButton_ frame]) +
- bookmarks::kBookmarkHorizontalPadding;
- if (NSMaxX([button frame]) >= maxViewX)
- break;
- ++displayedButtonCount_;
- [buttons_ addObject:button];
- [buttonView_ addSubview:button];
- }
-
- // While we're here, adjust the horizontal width and the visibility
- // of the "For quick access" and "Import bookmarks..." text fields.
- if (![buttons_ count])
- [self adjustNoItemContainerWidthsForMaxX:maxViewX];
-}
-
-#pragma mark Private Methods Exposed for Testing
-
-- (BookmarkBarView*)buttonView {
- return buttonView_;
-}
-
-- (NSMutableArray*)buttons {
- return buttons_.get();
-}
-
-- (NSButton*)offTheSideButton {
- return offTheSideButton_;
-}
-
-- (BOOL)offTheSideButtonIsHidden {
- return [offTheSideButton_ isHidden];
-}
-
-- (BookmarkButton*)otherBookmarksButton {
- return otherBookmarksButton_.get();
-}
-
-- (BookmarkBarFolderController*)folderController {
- return folderController_;
-}
-
-- (id)folderTarget {
- return folderTarget_.get();
-}
-
-- (int)displayedButtonCount {
- return displayedButtonCount_;
-}
-
-// Delete all buttons (bookmarks, chevron, "other bookmarks") from the
-// bookmark bar; reset knowledge of bookmarks.
-- (void)clearBookmarkBar {
- for (BookmarkButton* button in buttons_.get()) {
- [button setDelegate:nil];
- [button removeFromSuperview];
- }
- [buttons_ removeAllObjects];
- [self clearMenuTagMap];
- displayedButtonCount_ = 0;
-
- // Make sure there are no stale pointers in the pasteboard. This
- // can be important if a bookmark is deleted (via bookmark sync)
- // while in the middle of a drag. The "drag completed" code
- // (e.g. [BookmarkBarView performDragOperationForBookmarkButton:]) is
- // careful enough to bail if there is no data found at "drop" time.
- //
- // Unfortunately the clearContents selector is 10.6 only. The best
- // we can do is make sure something else is present in place of the
- // stale bookmark.
- NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
- [pboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:self];
- [pboard setString:@"" forType:NSStringPboardType];
-}
-
-// Return an autoreleased NSCell suitable for a bookmark button.
-// TODO(jrg): move much of the cell config into the BookmarkButtonCell class.
-- (BookmarkButtonCell*)cellForBookmarkNode:(const BookmarkNode*)node {
- NSImage* image = node ? [self favIconForNode:node] : nil;
- NSMenu* menu = node && node->is_folder() ? buttonFolderContextMenu_ :
- buttonContextMenu_;
- BookmarkButtonCell* cell = [BookmarkButtonCell buttonCellForNode:node
- contextMenu:menu
- cellText:nil
- cellImage:image];
- [cell setTag:kStandardButtonTypeWithLimitedClickFeedback];
-
- // Note: a quirk of setting a cell's text color is that it won't work
- // until the cell is associated with a button, so we can't theme the cell yet.
-
- return cell;
-}
-
-// Returns a frame appropriate for the given bookmark cell, suitable
-// for creating an NSButton that will contain it. |xOffset| is the X
-// offset for the frame; it is increased to be an appropriate X offset
-// for the next button.
-- (NSRect)frameForBookmarkButtonFromCell:(NSCell*)cell
- xOffset:(int*)xOffset {
- DCHECK(xOffset);
- NSRect bounds = [buttonView_ bounds];
- bounds.size.height = bookmarks::kBookmarkButtonHeight;
-
- NSRect frame = NSInsetRect(bounds,
- bookmarks::kBookmarkHorizontalPadding,
- bookmarks::kBookmarkVerticalPadding);
- frame.size.width = [self widthForBookmarkButtonCell:cell];
-
- // Add an X offset based on what we've already done
- frame.origin.x += *xOffset;
-
- // And up the X offset for next time.
- *xOffset = NSMaxX(frame);
-
- return frame;
-}
-
-// A bookmark button's contents changed. Check for growth
-// (e.g. increase the width up to the maximum). If we grew, move
-// other bookmark buttons over.
-- (void)checkForBookmarkButtonGrowth:(NSButton*)button {
- NSRect frame = [button frame];
- CGFloat desiredSize = [self widthForBookmarkButtonCell:[button cell]];
- CGFloat delta = desiredSize - frame.size.width;
- if (delta) {
- frame.size.width = desiredSize;
- [button setFrame:frame];
- for (NSButton* button in buttons_.get()) {
- NSRect buttonFrame = [button frame];
- if (buttonFrame.origin.x > frame.origin.x) {
- buttonFrame.origin.x += delta;
- [button setFrame:buttonFrame];
- }
- }
- }
- // We may have just crossed a threshold to enable the off-the-side
- // button.
- [self configureOffTheSideButtonContentsAndVisibility];
-}
-
-// Called when our controlled frame has changed size.
-- (void)frameDidChange {
- if (!bookmarkModel_->IsLoaded())
- return;
- [self updateTheme:[[[self view] window] themeProvider]];
- [self reconfigureBookmarkBar];
-}
-
-// Given a NSMenuItem tag, return the appropriate bookmark node id.
-- (int64)nodeIdFromMenuTag:(int32)tag {
- return menuTagMap_[tag];
-}
-
-// Create and return a new tag for the given node id.
-- (int32)menuTagFromNodeId:(int64)menuid {
- int tag = seedId_++;
- menuTagMap_[tag] = menuid;
- return tag;
-}
-
-// Return the BookmarkNode associated with the given NSMenuItem. Can
-// return NULL which means "do nothing". One case where it would
-// return NULL is if the bookmark model gets modified while you have a
-// context menu open.
-- (const BookmarkNode*)nodeFromMenuItem:(id)sender {
- const BookmarkNode* node = NULL;
- BookmarkMenu* menu = (BookmarkMenu*)[sender menu];
- if ([menu isKindOfClass:[BookmarkMenu class]]) {
- int64 id = [menu id];
- node = bookmarkModel_->GetNodeByID(id);
- }
- return node;
-}
-
-// Adapt appearance of buttons to the current theme. Called after
-// theme changes, or when our view is added to the view hierarchy.
-// Oddly, the view pings us instead of us pinging our view. This is
-// because our trigger is an [NSView viewWillMoveToWindow:], which the
-// controller doesn't normally know about. Otherwise we don't have
-// access to the theme before we know what window we will be on.
-- (void)updateTheme:(ThemeProvider*)themeProvider {
- if (!themeProvider)
- return;
- NSColor* color =
- themeProvider->GetNSColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT,
- true);
- for (BookmarkButton* button in buttons_.get()) {
- BookmarkButtonCell* cell = [button cell];
- [cell setTextColor:color];
- }
- [[otherBookmarksButton_ cell] setTextColor:color];
-}
-
-// Return YES if the event indicates an exit from the bookmark bar
-// folder menus. E.g. "click outside" of the area we are watching.
-// At this time we are watching the area that includes all popup
-// bookmark folder windows.
-- (BOOL)isEventAnExitEvent:(NSEvent*)event {
- NSWindow* eventWindow = [event window];
- NSWindow* myWindow = [[self view] window];
- switch ([event type]) {
- case NSLeftMouseDown:
- case NSRightMouseDown:
- // If the click is in my window but NOT in the bookmark bar, consider
- // it a click 'outside'. Clicks directly on an active button (i.e. one
- // that is a folder and for which its folder menu is showing) are 'in'.
- // All other clicks on the bookmarks bar are counted as 'outside'
- // because they should close any open bookmark folder menu.
- if (eventWindow == myWindow) {
- NSView* hitView =
- [[eventWindow contentView] hitTest:[event locationInWindow]];
- if (hitView == [folderController_ parentButton])
- return NO;
- if (![hitView isDescendantOf:[self view]] || hitView == buttonView_)
- return YES;
- }
- // If a click in a bookmark bar folder window and that isn't
- // one of my bookmark bar folders, YES is click outside.
- if (![eventWindow isKindOfClass:[BookmarkBarFolderWindow
- class]]) {
- return YES;
- }
- break;
- case NSKeyDown:
- case NSKeyUp:
- // Any key press ends things.
- return YES;
- case NSLeftMouseDragged:
- // We can get here with the following sequence:
- // - open a bookmark folder
- // - right-click (and unclick) on it to open context menu
- // - move mouse to window titlebar then click-drag it by the titlebar
- // http://crbug.com/49333
- return YES;
- default:
- break;
- }
- return NO;
-}
-
-#pragma mark Drag & Drop
-
-// Find something like std::is_between<T>? I can't believe one doesn't exist.
-static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) {
- return ((value >= low) && (value <= high));
-}
-
-// Return the proposed drop target for a hover open button from the
-// given array, or nil if none. We use this for distinguishing
-// between a hover-open candidate or drop-indicator draw.
-// Helper for buttonForDroppingOnAtPoint:.
-// Get UI review on "middle half" ness.
-// http://crbug.com/36276
-- (BookmarkButton*)buttonForDroppingOnAtPoint:(NSPoint)point
- fromArray:(NSArray*)array {
- for (BookmarkButton* button in array) {
- // Break early if we've gone too far.
- if ((NSMinX([button frame]) > point.x) || (![button superview]))
- return nil;
- // Careful -- this only applies to the bar with horiz buttons.
- // Intentionally NOT using NSPointInRect() so that scrolling into
- // a submenu doesn't cause it to be closed.
- if (ValueInRangeInclusive(NSMinX([button frame]),
- point.x,
- NSMaxX([button frame]))) {
- // Over a button but let's be a little more specific (make sure
- // it's over the middle half, not just over it).
- NSRect frame = [button frame];
- NSRect middleHalfOfButton = NSInsetRect(frame, frame.size.width / 4, 0);
- if (ValueInRangeInclusive(NSMinX(middleHalfOfButton),
- point.x,
- NSMaxX(middleHalfOfButton))) {
- // It makes no sense to drop on a non-folder; there is no hover.
- if (![button isFolder])
- return nil;
- // Got it!
- return button;
- } else {
- // Over a button but not over the middle half.
- return nil;
- }
- }
- }
- // Not hovering over a button.
- return nil;
-}
-
-// Return the proposed drop target for a hover open button, or nil if
-// none. Works with both the bookmark buttons and the "Other
-// Bookmarks" button. Point is in [self view] coordinates.
-- (BookmarkButton*)buttonForDroppingOnAtPoint:(NSPoint)point {
- point = [[self view] convertPoint:point
- fromView:[[[self view] window] contentView]];
- BookmarkButton* button = [self buttonForDroppingOnAtPoint:point
- fromArray:buttons_.get()];
- // One more chance -- try "Other Bookmarks" and "off the side" (if visible).
- // This is different than BookmarkBarFolderController.
- if (!button) {
- NSMutableArray* array = [NSMutableArray array];
- if (![self offTheSideButtonIsHidden])
- [array addObject:offTheSideButton_];
- [array addObject:otherBookmarksButton_];
- button = [self buttonForDroppingOnAtPoint:point
- fromArray:array];
- }
- return button;
-}
-
-- (int)indexForDragToPoint:(NSPoint)point {
- // TODO(jrg): revisit position info based on UI team feedback.
- // dropLocation is in bar local coordinates.
- NSPoint dropLocation =
- [[self view] convertPoint:point
- fromView:[[[self view] window] contentView]];
- BookmarkButton* buttonToTheRightOfDraggedButton = nil;
- for (BookmarkButton* button in buttons_.get()) {
- CGFloat midpoint = NSMidX([button frame]);
- if (dropLocation.x <= midpoint) {
- buttonToTheRightOfDraggedButton = button;
- break;
- }
- }
- if (buttonToTheRightOfDraggedButton) {
- const BookmarkNode* afterNode =
- [buttonToTheRightOfDraggedButton bookmarkNode];
- DCHECK(afterNode);
- int index = afterNode->GetParent()->IndexOfChild(afterNode);
- // Make sure we don't get confused by buttons which aren't visible.
- return std::min(index, displayedButtonCount_);
- }
-
- // If nothing is to my right I am at the end!
- return displayedButtonCount_;
-}
-
-// TODO(mrossetti,jrg): Yet more duplicated code.
-// http://crbug.com/35966
-- (BOOL)dragBookmark:(const BookmarkNode*)sourceNode
- to:(NSPoint)point
- copy:(BOOL)copy {
- DCHECK(sourceNode);
- // Drop destination.
- const BookmarkNode* destParent = NULL;
- int destIndex = 0;
-
- // First check if we're dropping on a button. If we have one, and
- // it's a folder, drop in it.
- BookmarkButton* button = [self buttonForDroppingOnAtPoint:point];
- if ([button isFolder]) {
- destParent = [button bookmarkNode];
- // Drop it at the end.
- destIndex = [button bookmarkNode]->GetChildCount();
- } else {
- // Else we're dropping somewhere on the bar, so find the right spot.
- destParent = bookmarkModel_->GetBookmarkBarNode();
- destIndex = [self indexForDragToPoint:point];
- }
-
- // Be sure we don't try and drop a folder into itself.
- if (sourceNode != destParent) {
- if (copy)
- bookmarkModel_->Copy(sourceNode, destParent, destIndex);
- else
- bookmarkModel_->Move(sourceNode, destParent, destIndex);
- }
-
- [self closeFolderAndStopTrackingMenus];
-
- // Movement of a node triggers observers (like us) to rebuild the
- // bar so we don't have to do so explicitly.
-
- return YES;
-}
-
-- (void)draggingEnded:(id<NSDraggingInfo>)info {
- [self closeFolderAndStopTrackingMenus];
-}
-
-#pragma mark Bridge Notification Handlers
-
-// TODO(jrg): for now this is brute force.
-- (void)loaded:(BookmarkModel*)model {
- DCHECK(model == bookmarkModel_);
- if (!model->IsLoaded())
- return;
-
- // If this is a rebuild request while we have a folder open, close it.
- // TODO(mrossetti): Eliminate the need for this because it causes the folder
- // menu to disappear after a cut/copy/paste/delete change.
- // See: http://crbug.com/36614
- if (folderController_)
- [self closeAllBookmarkFolders];
-
- // Brute force nuke and build.
- savedFrameWidth_ = NSWidth([[self view] frame]);
- const BookmarkNode* node = model->GetBookmarkBarNode();
- [self clearBookmarkBar];
- [self addNodesToButtonList:node];
- [self createOtherBookmarksButton];
- [self updateTheme:[[[self view] window] themeProvider]];
- [self positionOffTheSideButton];
- [self addNonBookmarkButtonsToView];
- [self addButtonsToView];
- [self configureOffTheSideButtonContentsAndVisibility];
- [self setNodeForBarMenu];
-}
-
-- (void)beingDeleted:(BookmarkModel*)model {
- // The browser may be being torn down; little is safe to do. As an
- // example, it may not be safe to clear the pasteboard.
- // http://crbug.com/38665
-}
-
-- (void)nodeAdded:(BookmarkModel*)model
- parent:(const BookmarkNode*)newParent index:(int)newIndex {
- // If a context menu is open, close it.
- [self cancelMenuTracking];
-
- const BookmarkNode* newNode = newParent->GetChild(newIndex);
- id<BookmarkButtonControllerProtocol> newController =
- [self controllerForNode:newParent];
- [newController addButtonForNode:newNode atIndex:newIndex];
- // If we go from 0 --> 1 bookmarks we may need to hide the
- // "bookmarks go here" text container.
- [self showOrHideNoItemContainerForNode:model->GetBookmarkBarNode()];
-}
-
-// TODO(jrg): for now this is brute force.
-- (void)nodeChanged:(BookmarkModel*)model
- node:(const BookmarkNode*)node {
- [self loaded:model];
-}
-
-- (void)nodeMoved:(BookmarkModel*)model
- oldParent:(const BookmarkNode*)oldParent oldIndex:(int)oldIndex
- newParent:(const BookmarkNode*)newParent newIndex:(int)newIndex {
- const BookmarkNode* movedNode = newParent->GetChild(newIndex);
- id<BookmarkButtonControllerProtocol> oldController =
- [self controllerForNode:oldParent];
- id<BookmarkButtonControllerProtocol> newController =
- [self controllerForNode:newParent];
- if (newController == oldController) {
- [oldController moveButtonFromIndex:oldIndex toIndex:newIndex];
- } else {
- [oldController removeButton:oldIndex animate:NO];
- [newController addButtonForNode:movedNode atIndex:newIndex];
- }
- // If the bar is one of the parents we may need to update the visibility
- // of the "bookmarks go here" presentation.
- [self showOrHideNoItemContainerForNode:model->GetBookmarkBarNode()];
- // If we moved the only item on the "off the side" menu somewhere
- // else, we may no longer need to show it.
- [self configureOffTheSideButtonContentsAndVisibility];
-}
-
-- (void)nodeRemoved:(BookmarkModel*)model
- parent:(const BookmarkNode*)oldParent index:(int)index {
- // If a context menu is open, close it.
- [self cancelMenuTracking];
-
- // Locate the parent node. The parent may not be showing, in which case
- // we do nothing.
- id<BookmarkButtonControllerProtocol> parentController =
- [self controllerForNode:oldParent];
- [parentController removeButton:index animate:YES];
- // If we go from 1 --> 0 bookmarks we may need to show the
- // "bookmarks go here" text container.
- [self showOrHideNoItemContainerForNode:model->GetBookmarkBarNode()];
- // If we deleted the only item on the "off the side" menu we no
- // longer need to show it.
- [self configureOffTheSideButtonContentsAndVisibility];
-}
-
-// TODO(jrg): linear searching is bad.
-// Need a BookmarkNode-->NSCell mapping.
-//
-// TODO(jrg): if the bookmark bar is open on launch, we see the
-// buttons all placed, then "scooted over" as the favicons load. If
-// this looks bad I may need to change widthForBookmarkButtonCell to
-// add space for an image even if not there on the assumption that
-// favicons will eventually load.
-- (void)nodeFavIconLoaded:(BookmarkModel*)model
- node:(const BookmarkNode*)node {
- for (BookmarkButton* button in buttons_.get()) {
- const BookmarkNode* cellnode = [button bookmarkNode];
- if (cellnode == node) {
- [[button cell] setBookmarkCellText:[button title]
- image:[self favIconForNode:node]];
- // Adding an image means we might need more room for the
- // bookmark. Test for it by growing the button (if needed)
- // and shifting everything else over.
- [self checkForBookmarkButtonGrowth:button];
- }
- }
-}
-
-// TODO(jrg): for now this is brute force.
-- (void)nodeChildrenReordered:(BookmarkModel*)model
- node:(const BookmarkNode*)node {
- [self loaded:model];
-}
-
-#pragma mark BookmarkBarState Protocol
-
-// (BookmarkBarState protocol)
-- (BOOL)isVisible {
- return barIsEnabled_ && (visualState_ == bookmarks::kShowingState ||
- visualState_ == bookmarks::kDetachedState ||
- lastVisualState_ == bookmarks::kShowingState ||
- lastVisualState_ == bookmarks::kDetachedState);
-}
-
-// (BookmarkBarState protocol)
-- (BOOL)isAnimationRunning {
- return lastVisualState_ != bookmarks::kInvalidState;
-}
-
-// (BookmarkBarState protocol)
-- (BOOL)isInState:(bookmarks::VisualState)state {
- return visualState_ == state &&
- lastVisualState_ == bookmarks::kInvalidState;
-}
-
-// (BookmarkBarState protocol)
-- (BOOL)isAnimatingToState:(bookmarks::VisualState)state {
- return visualState_ == state &&
- lastVisualState_ != bookmarks::kInvalidState;
-}
-
-// (BookmarkBarState protocol)
-- (BOOL)isAnimatingFromState:(bookmarks::VisualState)state {
- return lastVisualState_ == state;
-}
-
-// (BookmarkBarState protocol)
-- (BOOL)isAnimatingFromState:(bookmarks::VisualState)fromState
- toState:(bookmarks::VisualState)toState {
- return lastVisualState_ == fromState && visualState_ == toState;
-}
-
-// (BookmarkBarState protocol)
-- (BOOL)isAnimatingBetweenState:(bookmarks::VisualState)fromState
- andState:(bookmarks::VisualState)toState {
- return (lastVisualState_ == fromState && visualState_ == toState) ||
- (visualState_ == fromState && lastVisualState_ == toState);
-}
-
-// (BookmarkBarState protocol)
-- (CGFloat)detachedMorphProgress {
- if ([self isInState:bookmarks::kDetachedState]) {
- return 1;
- }
- if ([self isAnimatingToState:bookmarks::kDetachedState]) {
- return static_cast<CGFloat>(
- [[self animatableView] currentAnimationProgress]);
- }
- if ([self isAnimatingFromState:bookmarks::kDetachedState]) {
- return static_cast<CGFloat>(
- 1 - [[self animatableView] currentAnimationProgress]);
- }
- return 0;
-}
-
-#pragma mark BookmarkBarToolbarViewController Protocol
-
-- (int)currentTabContentsHeight {
- TabContents* tc = browser_->GetSelectedTabContents();
- return tc ? tc->view()->GetContainerSize().height() : 0;
-}
-
-- (ThemeProvider*)themeProvider {
- return browser_->profile()->GetThemeProvider();
-}
-
-#pragma mark BookmarkButtonDelegate Protocol
-
-- (void)fillPasteboard:(NSPasteboard*)pboard
- forDragOfButton:(BookmarkButton*)button {
- [[self folderTarget] fillPasteboard:pboard forDragOfButton:button];
-}
-
-// BookmarkButtonDelegate protocol implementation. When menus are
-// "active" (e.g. you clicked to open one), moving the mouse over
-// another folder button should close the 1st and open the 2nd (like
-// real menus). We detect and act here.
-- (void)mouseEnteredButton:(id)sender event:(NSEvent*)event {
- DCHECK([sender isKindOfClass:[BookmarkButton class]]);
-
- // If folder menus are not being shown, do nothing. This is different from
- // BookmarkBarFolderController's implementation because the bar should NOT
- // automatically open folder menus when the mouse passes over a folder
- // button while the BookmarkBarFolderController DOES automically open
- // a subfolder menu.
- if (!showFolderMenus_)
- return;
-
- // From here down: same logic as BookmarkBarFolderController.
- // TODO(jrg): find a way to share these 4 non-comment lines?
- // http://crbug.com/35966
- // If already opened, then we exited but re-entered the button, so do nothing.
- if ([folderController_ parentButton] == sender)
- return;
- // Else open a new one if it makes sense to do so.
- if ([sender bookmarkNode]->is_folder()) {
- [folderTarget_ openBookmarkFolderFromButton:sender];
- } else {
- // We're over a non-folder bookmark so close any old folders.
- [folderController_ close];
- folderController_ = nil;
- }
-}
-
-// BookmarkButtonDelegate protocol implementation.
-- (void)mouseExitedButton:(id)sender event:(NSEvent*)event {
- // Don't care; do nothing.
- // This is different behavior that the folder menus.
-}
-
-- (NSWindow*)browserWindow {
- return [[self view] window];
-}
-
-- (BOOL)canDragBookmarkButtonToTrash:(BookmarkButton*)button {
- return [self canEditBookmark:[button bookmarkNode]];
-}
-
-- (void)didDragBookmarkToTrash:(BookmarkButton*)button {
- // TODO(mrossetti): Refactor BookmarkBarFolder common code.
- // http://crbug.com/35966
- const BookmarkNode* node = [button bookmarkNode];
- if (node) {
- const BookmarkNode* parent = node->GetParent();
- bookmarkModel_->Remove(parent,
- parent->IndexOfChild(node));
- }
-}
-
-#pragma mark BookmarkButtonControllerProtocol
-
-// Close all bookmark folders. "Folder" here is the fake menu for
-// bookmark folders, not a button context menu.
-- (void)closeAllBookmarkFolders {
- [self watchForExitEvent:NO];
- [folderController_ close];
- folderController_ = nil;
-}
-
-- (void)closeBookmarkFolder:(id)sender {
- // We're the top level, so close one means close them all.
- [self closeAllBookmarkFolders];
-}
-
-- (BookmarkModel*)bookmarkModel {
- return bookmarkModel_;
-}
-
-// TODO(jrg): much of this logic is duped with
-// [BookmarkBarFolderController draggingEntered:] except when noted.
-// http://crbug.com/35966
-- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info {
- NSPoint point = [info draggingLocation];
- BookmarkButton* button = [self buttonForDroppingOnAtPoint:point];
-
- // Don't allow drops that would result in cycles.
- if (button) {
- NSData* data = [[info draggingPasteboard]
- dataForType:kBookmarkButtonDragType];
- if (data && [info draggingSource]) {
- BookmarkButton* sourceButton = nil;
- [data getBytes:&sourceButton length:sizeof(sourceButton)];
- const BookmarkNode* sourceNode = [sourceButton bookmarkNode];
- const BookmarkNode* destNode = [button bookmarkNode];
- if (destNode->HasAncestor(sourceNode))
- button = nil;
- }
- }
-
- if ([button isFolder]) {
- if (hoverButton_ == button) {
- return NSDragOperationMove; // already open or timed to open
- }
- if (hoverButton_) {
- // Oops, another one triggered or open.
- [NSObject cancelPreviousPerformRequestsWithTarget:[hoverButton_
- target]];
- // Unlike BookmarkBarFolderController, we do not delay the close
- // of the previous one. Given the lack of diagonal movement,
- // there is no need, and it feels awkward to do so. See
- // comments about kDragHoverCloseDelay in
- // bookmark_bar_folder_controller.mm for more details.
- [[hoverButton_ target] closeBookmarkFolder:hoverButton_];
- hoverButton_.reset();
- }
- hoverButton_.reset([button retain]);
- DCHECK([[hoverButton_ target]
- respondsToSelector:@selector(openBookmarkFolderFromButton:)]);
- [[hoverButton_ target]
- performSelector:@selector(openBookmarkFolderFromButton:)
- withObject:hoverButton_
- afterDelay:bookmarks::kDragHoverOpenDelay];
- }
- if (!button) {
- if (hoverButton_) {
- [NSObject cancelPreviousPerformRequestsWithTarget:[hoverButton_ target]];
- [[hoverButton_ target] closeBookmarkFolder:hoverButton_];
- hoverButton_.reset();
- }
- }
-
- // Thrown away but kept to be consistent with the draggingEntered: interface.
- return NSDragOperationMove;
-}
-
-- (void)draggingExited:(id<NSDraggingInfo>)info {
- // NOT the same as a cancel --> we may have moved the mouse into the submenu.
- if (hoverButton_) {
- [NSObject cancelPreviousPerformRequestsWithTarget:[hoverButton_ target]];
- hoverButton_.reset();
- }
-}
-
-- (BOOL)dragShouldLockBarVisibility {
- return ![self isInState:bookmarks::kDetachedState] &&
- ![self isAnimatingToState:bookmarks::kDetachedState];
-}
-
-// TODO(mrossetti,jrg): Yet more code dup with BookmarkBarFolderController.
-// http://crbug.com/35966
-- (BOOL)dragButton:(BookmarkButton*)sourceButton
- to:(NSPoint)point
- copy:(BOOL)copy {
- DCHECK([sourceButton isKindOfClass:[BookmarkButton class]]);
- const BookmarkNode* sourceNode = [sourceButton bookmarkNode];
- return [self dragBookmark:sourceNode to:point copy:copy];
-}
-
-- (BOOL)dragBookmarkData:(id<NSDraggingInfo>)info {
- BOOL dragged = NO;
- std::vector<const BookmarkNode*> nodes([self retrieveBookmarkNodeData]);
- if (nodes.size()) {
- BOOL copy = !([info draggingSourceOperationMask] & NSDragOperationMove);
- NSPoint dropPoint = [info draggingLocation];
- for (std::vector<const BookmarkNode*>::const_iterator it = nodes.begin();
- it != nodes.end(); ++it) {
- const BookmarkNode* sourceNode = *it;
- dragged = [self dragBookmark:sourceNode to:dropPoint copy:copy];
- }
- }
- return dragged;
-}
-
-- (std::vector<const BookmarkNode*>)retrieveBookmarkNodeData {
- std::vector<const BookmarkNode*> dragDataNodes;
- BookmarkNodeData dragData;
- if(dragData.ReadFromDragClipboard()) {
- BookmarkModel* bookmarkModel = [self bookmarkModel];
- Profile* profile = bookmarkModel->profile();
- std::vector<const BookmarkNode*> nodes(dragData.GetNodes(profile));
- dragDataNodes.assign(nodes.begin(), nodes.end());
- }
- return dragDataNodes;
-}
-
-// Return YES if we should show the drop indicator, else NO.
-- (BOOL)shouldShowIndicatorShownForPoint:(NSPoint)point {
- return ![self buttonForDroppingOnAtPoint:point];
-}
-
-// Return the x position for a drop indicator.
-- (CGFloat)indicatorPosForDragToPoint:(NSPoint)point {
- CGFloat x = 0;
- int destIndex = [self indexForDragToPoint:point];
- int numButtons = displayedButtonCount_;
-
- // If it's a drop strictly between existing buttons ...
- if (destIndex >= 0 && destIndex < numButtons) {
- // ... put the indicator right between the buttons.
- BookmarkButton* button =
- [buttons_ objectAtIndex:static_cast<NSUInteger>(destIndex)];
- DCHECK(button);
- NSRect buttonFrame = [button frame];
- x = buttonFrame.origin.x - 0.5 * bookmarks::kBookmarkHorizontalPadding;
-
- // If it's a drop at the end (past the last button, if there are any) ...
- } else if (destIndex == numButtons) {
- // and if it's past the last button ...
- if (numButtons > 0) {
- // ... find the last button, and put the indicator to its right.
- BookmarkButton* button =
- [buttons_ objectAtIndex:static_cast<NSUInteger>(destIndex - 1)];
- DCHECK(button);
- NSRect buttonFrame = [button frame];
- x = NSMaxX(buttonFrame) + 0.5 * bookmarks::kBookmarkHorizontalPadding;
-
- // Otherwise, put it right at the beginning.
- } else {
- x = 0.5 * bookmarks::kBookmarkHorizontalPadding;
- }
- } else {
- NOTREACHED();
- }
-
- return x;
-}
-
-- (void)childFolderWillShow:(id<BookmarkButtonControllerProtocol>)child {
- // If the bookmarkbar is not in detached mode, lock bar visibility, forcing
- // the overlay to stay open when in fullscreen mode.
- if (![self isInState:bookmarks::kDetachedState] &&
- ![self isAnimatingToState:bookmarks::kDetachedState]) {
- BrowserWindowController* browserController =
- [BrowserWindowController browserWindowControllerForView:[self view]];
- [browserController lockBarVisibilityForOwner:child
- withAnimation:NO
- delay:NO];
- }
-}
-
-- (void)childFolderWillClose:(id<BookmarkButtonControllerProtocol>)child {
- // Release bar visibility, allowing the overlay to close if in fullscreen
- // mode.
- BrowserWindowController* browserController =
- [BrowserWindowController browserWindowControllerForView:[self view]];
- [browserController releaseBarVisibilityForOwner:child
- withAnimation:NO
- delay:NO];
-}
-
-// Add a new folder controller as triggered by the given folder button.
-- (void)addNewFolderControllerWithParentButton:(BookmarkButton*)parentButton {
-
- // If doing a close/open, make sure the fullscreen chrome doesn't
- // have a chance to begin animating away in the middle of things.
- BrowserWindowController* browserController =
- [BrowserWindowController browserWindowControllerForView:[self view]];
- // Confirm we're not re-locking with ourself as an owner before locking.
- DCHECK([browserController isBarVisibilityLockedForOwner:self] == NO);
- [browserController lockBarVisibilityForOwner:self
- withAnimation:NO
- delay:NO];
-
- if (folderController_)
- [self closeAllBookmarkFolders];
-
- // Folder controller, like many window controllers, owns itself.
- folderController_ =
- [[BookmarkBarFolderController alloc] initWithParentButton:parentButton
- parentController:nil
- barController:self];
- [folderController_ showWindow:self];
-
- // Only BookmarkBarController has this; the
- // BookmarkBarFolderController does not.
- [self watchForExitEvent:YES];
-
- // No longer need to hold the lock; the folderController_ now owns it.
- [browserController releaseBarVisibilityForOwner:self
- withAnimation:NO
- delay:NO];
-}
-
-- (void)openAll:(const BookmarkNode*)node
- disposition:(WindowOpenDisposition)disposition {
- [self closeFolderAndStopTrackingMenus];
- bookmark_utils::OpenAll([[self view] window],
- browser_->profile(),
- browser_,
- node,
- disposition);
-}
-
-- (void)addButtonForNode:(const BookmarkNode*)node
- atIndex:(NSInteger)buttonIndex {
- int newOffset = 0;
- if (buttonIndex == -1)
- buttonIndex = [buttons_ count]; // New button goes at the end.
- if (buttonIndex <= (NSInteger)[buttons_ count]) {
- if (buttonIndex) {
- BookmarkButton* targetButton = [buttons_ objectAtIndex:buttonIndex - 1];
- NSRect targetFrame = [targetButton frame];
- newOffset = targetFrame.origin.x + NSWidth(targetFrame) +
- bookmarks::kBookmarkHorizontalPadding;
- }
- BookmarkButton* newButton = [self buttonForNode:node xOffset:&newOffset];
- CGFloat xOffset =
- NSWidth([newButton frame]) + bookmarks::kBookmarkHorizontalPadding;
- NSUInteger buttonCount = [buttons_ count];
- for (NSUInteger i = buttonIndex; i < buttonCount; ++i) {
- BookmarkButton* button = [buttons_ objectAtIndex:i];
- NSPoint buttonOrigin = [button frame].origin;
- buttonOrigin.x += xOffset;
- [button setFrameOrigin:buttonOrigin];
- }
- ++displayedButtonCount_;
- [buttons_ insertObject:newButton atIndex:buttonIndex];
- [buttonView_ addSubview:newButton];
-
- // See if any buttons need to be pushed off to or brought in from the side.
- [self reconfigureBookmarkBar];
- } else {
- // A button from somewhere else (not the bar) is being moved to the
- // off-the-side so insure it gets redrawn if its showing.
- [self reconfigureBookmarkBar];
- [folderController_ reconfigureMenu];
- }
-}
-
-// TODO(mrossetti): Duplicate code with BookmarkBarFolderController.
-// http://crbug.com/35966
-- (BOOL)addURLs:(NSArray*)urls withTitles:(NSArray*)titles at:(NSPoint)point {
- DCHECK([urls count] == [titles count]);
- BOOL nodesWereAdded = NO;
- // Figure out where these new bookmarks nodes are to be added.
- BookmarkButton* button = [self buttonForDroppingOnAtPoint:point];
- const BookmarkNode* destParent = NULL;
- int destIndex = 0;
- if ([button isFolder]) {
- destParent = [button bookmarkNode];
- // Drop it at the end.
- destIndex = [button bookmarkNode]->GetChildCount();
- } else {
- // Else we're dropping somewhere on the bar, so find the right spot.
- destParent = bookmarkModel_->GetBookmarkBarNode();
- destIndex = [self indexForDragToPoint:point];
- }
-
- // Don't add the bookmarks if the destination index shows an error.
- if (destIndex >= 0) {
- // Create and add the new bookmark nodes.
- size_t urlCount = [urls count];
- for (size_t i = 0; i < urlCount; ++i) {
- GURL gurl;
- const char* string = [[urls objectAtIndex:i] UTF8String];
- if (string)
- gurl = GURL(string);
- // We only expect to receive valid URLs.
- DCHECK(gurl.is_valid());
- if (gurl.is_valid()) {
- bookmarkModel_->AddURL(destParent,
- destIndex++,
- base::SysNSStringToUTF16(
- [titles objectAtIndex:i]),
- gurl);
- nodesWereAdded = YES;
- }
- }
- }
- return nodesWereAdded;
-}
-
-// TODO(mrossetti): jrg wants this broken up into smaller functions.
-- (void)moveButtonFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex {
- if (fromIndex != toIndex) {
- NSInteger buttonCount = (NSInteger)[buttons_ count];
- if (toIndex == -1)
- toIndex = buttonCount;
- // See if we have a simple move within the bar, which will be the case if
- // both button indexes are in the visible space.
- if (fromIndex < buttonCount && toIndex < buttonCount) {
- BookmarkButton* movedButton = [buttons_ objectAtIndex:fromIndex];
- NSRect movedFrame = [movedButton frame];
- NSPoint toOrigin = movedFrame.origin;
- CGFloat xOffset =
- NSWidth(movedFrame) + bookmarks::kBookmarkHorizontalPadding;
- // Hide the button to reduce flickering while drawing the window.
- [movedButton setHidden:YES];
- [buttons_ removeObjectAtIndex:fromIndex];
- if (fromIndex < toIndex) {
- // Move the button from left to right within the bar.
- BookmarkButton* targetButton = [buttons_ objectAtIndex:toIndex - 1];
- NSRect toFrame = [targetButton frame];
- toOrigin.x = toFrame.origin.x - NSWidth(movedFrame) + NSWidth(toFrame);
- for (NSInteger i = fromIndex; i < toIndex; ++i) {
- BookmarkButton* button = [buttons_ objectAtIndex:i];
- NSRect frame = [button frame];
- frame.origin.x -= xOffset;
- [button setFrameOrigin:frame.origin];
- }
- } else {
- // Move the button from right to left within the bar.
- BookmarkButton* targetButton = [buttons_ objectAtIndex:toIndex];
- toOrigin = [targetButton frame].origin;
- for (NSInteger i = fromIndex - 1; i >= toIndex; --i) {
- BookmarkButton* button = [buttons_ objectAtIndex:i];
- NSRect buttonFrame = [button frame];
- buttonFrame.origin.x += xOffset;
- [button setFrameOrigin:buttonFrame.origin];
- }
- }
- [buttons_ insertObject:movedButton atIndex:toIndex];
- [movedButton setFrameOrigin:toOrigin];
- [movedButton setHidden:NO];
- } else if (fromIndex < buttonCount) {
- // A button is being removed from the bar and added to off-the-side.
- // By now the node has already been inserted into the model so the
- // button to be added is represented by |toIndex|. Things get
- // complicated because the off-the-side is showing and must be redrawn
- // while possibly re-laying out the bookmark bar.
- [self removeButton:fromIndex animate:NO];
- [self reconfigureBookmarkBar];
- [folderController_ reconfigureMenu];
- } else if (toIndex < buttonCount) {
- // A button is being added to the bar and removed from off-the-side.
- // By now the node has already been inserted into the model so the
- // button to be added is represented by |toIndex|.
- const BookmarkNode* node = bookmarkModel_->GetBookmarkBarNode();
- const BookmarkNode* movedNode = node->GetChild(toIndex);
- DCHECK(movedNode);
- [self addButtonForNode:movedNode atIndex:toIndex];
- [self reconfigureBookmarkBar];
- } else {
- // A button is being moved within the off-the-side.
- fromIndex -= buttonCount;
- toIndex -= buttonCount;
- [folderController_ moveButtonFromIndex:fromIndex toIndex:toIndex];
- }
- }
-}
-
-- (void)removeButton:(NSInteger)buttonIndex animate:(BOOL)animate {
- if (buttonIndex < (NSInteger)[buttons_ count]) {
- // The button being removed is showing in the bar.
- BookmarkButton* oldButton = [buttons_ objectAtIndex:buttonIndex];
- if (oldButton == [folderController_ parentButton]) {
- // If we are deleting a button whose folder is currently open, close it!
- [self closeAllBookmarkFolders];
- }
- NSPoint poofPoint = [oldButton screenLocationForRemoveAnimation];
- NSRect oldFrame = [oldButton frame];
- [oldButton setDelegate:nil];
- [oldButton removeFromSuperview];
- if (animate && !ignoreAnimations_ && [self isVisible])
- NSShowAnimationEffect(NSAnimationEffectDisappearingItemDefault, poofPoint,
- NSZeroSize, nil, nil, nil);
- CGFloat xOffset = NSWidth(oldFrame) + bookmarks::kBookmarkHorizontalPadding;
- [buttons_ removeObjectAtIndex:buttonIndex];
- NSUInteger buttonCount = [buttons_ count];
- for (NSUInteger i = buttonIndex; i < buttonCount; ++i) {
- BookmarkButton* button = [buttons_ objectAtIndex:i];
- NSRect buttonFrame = [button frame];
- buttonFrame.origin.x -= xOffset;
- [button setFrame:buttonFrame];
- // If this button is showing its menu then we need to move the menu, too.
- if (button == [folderController_ parentButton])
- [folderController_ offsetFolderMenuWindow:NSMakeSize(xOffset, 0.0)];
- }
- --displayedButtonCount_;
- [self reconfigureBookmarkBar];
- } else if (folderController_ &&
- [folderController_ parentButton] == offTheSideButton_) {
- // The button being removed is in the OTS (off-the-side) and the OTS
- // menu is showing so we need to remove the button.
- NSInteger index = buttonIndex - displayedButtonCount_;
- [folderController_ removeButton:index animate:YES];
- }
-}
-
-- (id<BookmarkButtonControllerProtocol>)controllerForNode:
- (const BookmarkNode*)node {
- // See if it's in the bar, then if it is in the hierarchy of visible
- // folder menus.
- if (bookmarkModel_->GetBookmarkBarNode() == node)
- return self;
- return [folderController_ controllerForNode:node];
-}
-
-#pragma mark BookmarkButtonControllerProtocol
-
-// NOT an override of a standard Cocoa call made to NSViewControllers.
-- (void)hookForEvent:(NSEvent*)theEvent {
- if ([self isEventAnExitEvent:theEvent])
- [self closeFolderAndStopTrackingMenus];
-}
-
-#pragma mark TestingAPI Only
-
-- (NSMenu*)buttonContextMenu {
- return buttonContextMenu_;
-}
-
-// Intentionally ignores ownership issues; used for testing and we try
-// to minimize touching the object passed in (likely a mock).
-- (void)setButtonContextMenu:(id)menu {
- buttonContextMenu_ = menu;
-}
-
-- (void)setIgnoreAnimations:(BOOL)ignore {
- ignoreAnimations_ = ignore;
-}
-
-@end
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_controller_unittest.mm b/chrome/browser/cocoa/bookmarks/bookmark_bar_controller_unittest.mm
deleted file mode 100644
index 2d72804..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_controller_unittest.mm
+++ /dev/null
@@ -1,2169 +0,0 @@
-// 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 "app/theme_provider.h"
-#include "base/basictypes.h"
-#include "base/scoped_nsobject.h"
-#include "base/string16.h"
-#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_constants.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_controller.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_folder_window.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_unittest_helper.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_view.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_button.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_button_cell.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_menu.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/cocoa/test_event_utils.h"
-#import "chrome/browser/cocoa/view_resizer_pong.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/test/model_test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-#import "third_party/ocmock/OCMock/OCMock.h"
-
-// Just like a BookmarkBarController but openURL: is stubbed out.
-@interface BookmarkBarControllerNoOpen : BookmarkBarController {
- @public
- std::vector<GURL> urls_;
- std::vector<WindowOpenDisposition> dispositions_;
-}
-@end
-
-@implementation BookmarkBarControllerNoOpen
-- (void)openURL:(GURL)url disposition:(WindowOpenDisposition)disposition {
- urls_.push_back(url);
- dispositions_.push_back(disposition);
-}
-- (void)clear {
- urls_.clear();
- dispositions_.clear();
-}
-@end
-
-
-// NSCell that is pre-provided with a desired size that becomes the
-// return value for -(NSSize)cellSize:.
-@interface CellWithDesiredSize : NSCell {
- @private
- NSSize cellSize_;
-}
-@property (nonatomic, readonly) NSSize cellSize;
-@end
-
-@implementation CellWithDesiredSize
-
-@synthesize cellSize = cellSize_;
-
-- (id)initTextCell:(NSString*)string desiredSize:(NSSize)size {
- if ((self = [super initTextCell:string])) {
- cellSize_ = size;
- }
- return self;
-}
-
-@end
-
-// Remember the number of times we've gotten a frameDidChange notification.
-@interface BookmarkBarControllerTogglePong : BookmarkBarControllerNoOpen {
- @private
- int toggles_;
-}
-@property (nonatomic, readonly) int toggles;
-@end
-
-@implementation BookmarkBarControllerTogglePong
-
-@synthesize toggles = toggles_;
-
-- (void)frameDidChange {
- toggles_++;
-}
-
-@end
-
-// Remembers if a notification callback was called.
-@interface BookmarkBarControllerNotificationPong : BookmarkBarControllerNoOpen {
- BOOL windowWillCloseReceived_;
- BOOL windowDidResignKeyReceived_;
-}
-@property (nonatomic, readonly) BOOL windowWillCloseReceived;
-@property (nonatomic, readonly) BOOL windowDidResignKeyReceived;
-@end
-
-@implementation BookmarkBarControllerNotificationPong
-@synthesize windowWillCloseReceived = windowWillCloseReceived_;
-@synthesize windowDidResignKeyReceived = windowDidResignKeyReceived_;
-
-// Override NSNotificationCenter callback.
-- (void)parentWindowWillClose:(NSNotification*)notification {
- windowWillCloseReceived_ = YES;
-}
-
-// NSNotificationCenter callback.
-- (void)parentWindowDidResignKey:(NSNotification*)notification {
- windowDidResignKeyReceived_ = YES;
-}
-@end
-
-// Remembers if and what kind of openAll was performed.
-@interface BookmarkBarControllerOpenAllPong : BookmarkBarControllerNoOpen {
- WindowOpenDisposition dispositionDetected_;
-}
-@property (nonatomic) WindowOpenDisposition dispositionDetected;
-@end
-
-@implementation BookmarkBarControllerOpenAllPong
-@synthesize dispositionDetected = dispositionDetected_;
-
-// Intercede for the openAll:disposition: method.
-- (void)openAll:(const BookmarkNode*)node
- disposition:(WindowOpenDisposition)disposition {
- [self setDispositionDetected:disposition];
-}
-
-@end
-
-// Just like a BookmarkBarController but intercedes when providing
-// pasteboard drag data.
-@interface BookmarkBarControllerDragData : BookmarkBarController {
- const BookmarkNode* dragDataNode_; // Weak
-}
-- (void)setDragDataNode:(const BookmarkNode*)node;
-@end
-
-@implementation BookmarkBarControllerDragData
-
-- (id)initWithBrowser:(Browser*)browser
- initialWidth:(CGFloat)initialWidth
- delegate:(id<BookmarkBarControllerDelegate>)delegate
- resizeDelegate:(id<ViewResizer>)resizeDelegate {
- if ((self = [super initWithBrowser:browser
- initialWidth:initialWidth
- delegate:delegate
- resizeDelegate:resizeDelegate])) {
- dragDataNode_ = NULL;
- }
- return self;
-}
-
-- (void)setDragDataNode:(const BookmarkNode*)node {
- dragDataNode_ = node;
-}
-
-- (std::vector<const BookmarkNode*>)retrieveBookmarkNodeData {
- std::vector<const BookmarkNode*> dragDataNodes;
- if(dragDataNode_) {
- dragDataNodes.push_back(dragDataNode_);
- }
- return dragDataNodes;
-}
-
-@end
-
-
-class FakeTheme : public ThemeProvider {
- public:
- FakeTheme(NSColor* color) : color_(color) { }
- scoped_nsobject<NSColor> color_;
-
- virtual void Init(Profile* profile) { }
- virtual SkBitmap* GetBitmapNamed(int id) const { return nil; }
- virtual SkColor GetColor(int id) const { return SkColor(); }
- virtual bool GetDisplayProperty(int id, int* result) const { return false; }
- virtual bool ShouldUseNativeFrame() const { return false; }
- virtual bool HasCustomImage(int id) const { return false; }
- virtual RefCountedMemory* GetRawData(int id) const { return NULL; }
- virtual NSImage* GetNSImageNamed(int id, bool allow_default) const {
- return nil;
- }
- virtual NSColor* GetNSImageColorNamed(int id, bool allow_default) const {
- return nil;
- }
- virtual NSColor* GetNSColor(int id, bool allow_default) const {
- return color_.get();
- }
- virtual NSColor* GetNSColorTint(int id, bool allow_default) const {
- return nil;
- }
- virtual NSGradient* GetNSGradient(int id) const {
- return nil;
- }
-};
-
-
-@interface FakeDragInfo : NSObject {
- @public
- NSPoint dropLocation_;
- NSDragOperation sourceMask_;
-}
-@property (nonatomic, assign) NSPoint dropLocation;
-- (void)setDraggingSourceOperationMask:(NSDragOperation)mask;
-@end
-
-@implementation FakeDragInfo
-
-@synthesize dropLocation = dropLocation_;
-
-- (id)init {
- if ((self = [super init])) {
- dropLocation_ = NSZeroPoint;
- sourceMask_ = NSDragOperationMove;
- }
- return self;
-}
-
-// NSDraggingInfo protocol functions.
-
-- (id)draggingPasteboard {
- return self;
-}
-
-- (id)draggingSource {
- return self;
-}
-
-- (NSDragOperation)draggingSourceOperationMask {
- return sourceMask_;
-}
-
-- (NSPoint)draggingLocation {
- return dropLocation_;
-}
-
-// Other functions.
-
-- (void)setDraggingSourceOperationMask:(NSDragOperation)mask {
- sourceMask_ = mask;
-}
-
-@end
-
-
-namespace {
-
-class BookmarkBarControllerTestBase : public CocoaTest {
- public:
- BrowserTestHelper helper_;
- scoped_nsobject<NSView> parent_view_;
- scoped_nsobject<ViewResizerPong> resizeDelegate_;
-
- BookmarkBarControllerTestBase() {
- resizeDelegate_.reset([[ViewResizerPong alloc] init]);
- NSRect parent_frame = NSMakeRect(0, 0, 800, 50);
- parent_view_.reset([[NSView alloc] initWithFrame:parent_frame]);
- [parent_view_ setHidden:YES];
- }
-
- void InstallAndToggleBar(BookmarkBarController* bar) {
- // Force loading of the nib.
- [bar view];
- // Awkwardness to look like we've been installed.
- for (NSView* subView in [parent_view_ subviews])
- [subView removeFromSuperview];
- [parent_view_ addSubview:[bar view]];
- NSRect frame = [[[bar view] superview] frame];
- frame.origin.y = 100;
- [[[bar view] superview] setFrame:frame];
-
- // Make sure it's on in a window so viewDidMoveToWindow is called
- NSView* contentView = [test_window() contentView];
- if (![parent_view_ isDescendantOf:contentView])
- [contentView addSubview:parent_view_];
-
- // Make sure it's open so certain things aren't no-ops.
- [bar updateAndShowNormalBar:YES
- showDetachedBar:NO
- withAnimation:NO];
- }
-};
-
-class BookmarkBarControllerTest : public BookmarkBarControllerTestBase {
- public:
- scoped_nsobject<BookmarkMenu> menu_;
- scoped_nsobject<NSMenuItem> menu_item_;
- scoped_nsobject<NSButtonCell> cell_;
- scoped_nsobject<BookmarkBarControllerNoOpen> bar_;
-
- BookmarkBarControllerTest() {
- bar_.reset(
- [[BookmarkBarControllerNoOpen alloc]
- initWithBrowser:helper_.browser()
- initialWidth:NSWidth([parent_view_ frame])
- delegate:nil
- resizeDelegate:resizeDelegate_.get()]);
-
- InstallAndToggleBar(bar_.get());
-
- // Create a menu/item to act like a sender
- menu_.reset([[BookmarkMenu alloc] initWithTitle:@"I_dont_care"]);
- menu_item_.reset([[NSMenuItem alloc]
- initWithTitle:@"still_dont_care"
- action:NULL
- keyEquivalent:@""]);
- cell_.reset([[NSButtonCell alloc] init]);
- [menu_item_ setMenu:menu_.get()];
- [menu_ setDelegate:cell_.get()];
- }
-
- // Return a menu item that points to the given URL.
- NSMenuItem* ItemForBookmarkBarMenu(GURL& gurl) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- const BookmarkNode* node = model->AddURL(parent, parent->GetChildCount(),
- ASCIIToUTF16("A title"), gurl);
- [menu_ setRepresentedObject:[NSNumber numberWithLongLong:node->id()]];
- return menu_item_;
- }
-
- // Does NOT take ownership of node.
- NSMenuItem* ItemForBookmarkBarMenu(const BookmarkNode* node) {
- [menu_ setRepresentedObject:[NSNumber numberWithLongLong:node->id()]];
- return menu_item_;
- }
-
- BookmarkBarControllerNoOpen* noOpenBar() {
- return (BookmarkBarControllerNoOpen*)bar_.get();
- }
-};
-
-TEST_F(BookmarkBarControllerTest, ShowWhenShowBookmarkBarTrue) {
- [bar_ updateAndShowNormalBar:YES
- showDetachedBar:NO
- withAnimation:NO];
- EXPECT_TRUE([bar_ isInState:bookmarks::kShowingState]);
- EXPECT_FALSE([bar_ isInState:bookmarks::kDetachedState]);
- EXPECT_TRUE([bar_ isVisible]);
- EXPECT_FALSE([bar_ isAnimationRunning]);
- EXPECT_FALSE([[bar_ view] isHidden]);
- EXPECT_GT([resizeDelegate_ height], 0);
- EXPECT_GT([[bar_ view] frame].size.height, 0);
-}
-
-TEST_F(BookmarkBarControllerTest, HideWhenShowBookmarkBarFalse) {
- [bar_ updateAndShowNormalBar:NO
- showDetachedBar:NO
- withAnimation:NO];
- EXPECT_FALSE([bar_ isInState:bookmarks::kShowingState]);
- EXPECT_FALSE([bar_ isInState:bookmarks::kDetachedState]);
- EXPECT_FALSE([bar_ isVisible]);
- EXPECT_FALSE([bar_ isAnimationRunning]);
- EXPECT_TRUE([[bar_ view] isHidden]);
- EXPECT_EQ(0, [resizeDelegate_ height]);
- EXPECT_EQ(0, [[bar_ view] frame].size.height);
-}
-
-TEST_F(BookmarkBarControllerTest, HideWhenShowBookmarkBarTrueButDisabled) {
- [bar_ setBookmarkBarEnabled:NO];
- [bar_ updateAndShowNormalBar:YES
- showDetachedBar:NO
- withAnimation:NO];
- EXPECT_TRUE([bar_ isInState:bookmarks::kShowingState]);
- EXPECT_FALSE([bar_ isInState:bookmarks::kDetachedState]);
- EXPECT_FALSE([bar_ isVisible]);
- EXPECT_FALSE([bar_ isAnimationRunning]);
- EXPECT_TRUE([[bar_ view] isHidden]);
- EXPECT_EQ(0, [resizeDelegate_ height]);
- EXPECT_EQ(0, [[bar_ view] frame].size.height);
-}
-
-TEST_F(BookmarkBarControllerTest, ShowOnNewTabPage) {
- [bar_ updateAndShowNormalBar:NO
- showDetachedBar:YES
- withAnimation:NO];
- EXPECT_FALSE([bar_ isInState:bookmarks::kShowingState]);
- EXPECT_TRUE([bar_ isInState:bookmarks::kDetachedState]);
- EXPECT_TRUE([bar_ isVisible]);
- EXPECT_FALSE([bar_ isAnimationRunning]);
- EXPECT_FALSE([[bar_ view] isHidden]);
- EXPECT_GT([resizeDelegate_ height], 0);
- EXPECT_GT([[bar_ view] frame].size.height, 0);
-
- // Make sure no buttons fall off the bar, either now or when resized
- // bigger or smaller.
- CGFloat sizes[] = { 300.0, -100.0, 200.0, -420.0 };
- CGFloat previousX = 0.0;
- for (unsigned x = 0; x < arraysize(sizes); x++) {
- // Confirm the buttons moved from the last check (which may be
- // init but that's fine).
- CGFloat newX = [[bar_ offTheSideButton] frame].origin.x;
- EXPECT_NE(previousX, newX);
- previousX = newX;
-
- // Confirm the buttons have a reasonable bounds. Recall that |-frame|
- // returns rectangles in the superview's coordinates.
- NSRect buttonViewFrame =
- [[bar_ buttonView] convertRect:[[bar_ buttonView] frame]
- fromView:[[bar_ buttonView] superview]];
- EXPECT_EQ([bar_ buttonView], [[bar_ offTheSideButton] superview]);
- EXPECT_TRUE(NSContainsRect(buttonViewFrame,
- [[bar_ offTheSideButton] frame]));
- EXPECT_EQ([bar_ buttonView], [[bar_ otherBookmarksButton] superview]);
- EXPECT_TRUE(NSContainsRect(buttonViewFrame,
- [[bar_ otherBookmarksButton] frame]));
-
- // Now move them implicitly.
- // We confirm FrameChangeNotification works in the next unit test;
- // we simply assume it works here to resize or reposition the
- // buttons above.
- NSRect frame = [[bar_ view] frame];
- frame.size.width += sizes[x];
- [[bar_ view] setFrame:frame];
- }
-}
-
-// Test whether |-updateAndShowNormalBar:...| sets states as we expect. Make
-// sure things don't crash.
-TEST_F(BookmarkBarControllerTest, StateChanges) {
- // First, go in one-at-a-time cycle.
- [bar_ updateAndShowNormalBar:NO
- showDetachedBar:NO
- withAnimation:NO];
- EXPECT_EQ(bookmarks::kHiddenState, [bar_ visualState]);
- EXPECT_FALSE([bar_ isVisible]);
- EXPECT_FALSE([bar_ isAnimationRunning]);
- [bar_ updateAndShowNormalBar:YES
- showDetachedBar:NO
- withAnimation:NO];
- EXPECT_EQ(bookmarks::kShowingState, [bar_ visualState]);
- EXPECT_TRUE([bar_ isVisible]);
- EXPECT_FALSE([bar_ isAnimationRunning]);
- [bar_ updateAndShowNormalBar:YES
- showDetachedBar:YES
- withAnimation:NO];
- EXPECT_EQ(bookmarks::kShowingState, [bar_ visualState]);
- EXPECT_TRUE([bar_ isVisible]);
- EXPECT_FALSE([bar_ isAnimationRunning]);
- [bar_ updateAndShowNormalBar:NO
- showDetachedBar:YES
- withAnimation:NO];
- EXPECT_EQ(bookmarks::kDetachedState, [bar_ visualState]);
- EXPECT_TRUE([bar_ isVisible]);
- EXPECT_FALSE([bar_ isAnimationRunning]);
-
- // Now try some "jumps".
- for (int i = 0; i < 2; i++) {
- [bar_ updateAndShowNormalBar:NO
- showDetachedBar:NO
- withAnimation:NO];
- EXPECT_EQ(bookmarks::kHiddenState, [bar_ visualState]);
- EXPECT_FALSE([bar_ isVisible]);
- EXPECT_FALSE([bar_ isAnimationRunning]);
- [bar_ updateAndShowNormalBar:YES
- showDetachedBar:YES
- withAnimation:NO];
- EXPECT_EQ(bookmarks::kShowingState, [bar_ visualState]);
- EXPECT_TRUE([bar_ isVisible]);
- EXPECT_FALSE([bar_ isAnimationRunning]);
- }
-
- // Now try some "jumps".
- for (int i = 0; i < 2; i++) {
- [bar_ updateAndShowNormalBar:YES
- showDetachedBar:NO
- withAnimation:NO];
- EXPECT_EQ(bookmarks::kShowingState, [bar_ visualState]);
- EXPECT_TRUE([bar_ isVisible]);
- EXPECT_FALSE([bar_ isAnimationRunning]);
- [bar_ updateAndShowNormalBar:NO
- showDetachedBar:YES
- withAnimation:NO];
- EXPECT_EQ(bookmarks::kDetachedState, [bar_ visualState]);
- EXPECT_TRUE([bar_ isVisible]);
- EXPECT_FALSE([bar_ isAnimationRunning]);
- }
-}
-
-// Make sure we're watching for frame change notifications.
-TEST_F(BookmarkBarControllerTest, FrameChangeNotification) {
- scoped_nsobject<BookmarkBarControllerTogglePong> bar;
- bar.reset(
- [[BookmarkBarControllerTogglePong alloc]
- initWithBrowser:helper_.browser()
- initialWidth:100 // arbitrary
- delegate:nil
- resizeDelegate:resizeDelegate_.get()]);
- InstallAndToggleBar(bar.get());
-
- // Send a frame did change notification for the pong's view.
- [[NSNotificationCenter defaultCenter]
- postNotificationName:NSViewFrameDidChangeNotification
- object:[bar view]];
-
- EXPECT_GT([bar toggles], 0);
-}
-
-// Confirm our "no items" container goes away when we add the 1st
-// bookmark, and comes back when we delete the bookmark.
-TEST_F(BookmarkBarControllerTest, NoItemContainerGoesAway) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- const BookmarkNode* bar = model->GetBookmarkBarNode();
-
- [bar_ loaded:model];
- BookmarkBarView* view = [bar_ buttonView];
- DCHECK(view);
- NSView* noItemContainer = [view noItemContainer];
- DCHECK(noItemContainer);
-
- EXPECT_FALSE([noItemContainer isHidden]);
- const BookmarkNode* node = model->AddURL(bar, bar->GetChildCount(),
- ASCIIToUTF16("title"),
- GURL("http://www.google.com"));
- EXPECT_TRUE([noItemContainer isHidden]);
- model->Remove(bar, bar->IndexOfChild(node));
- EXPECT_FALSE([noItemContainer isHidden]);
-
- // Now try it using a bookmark from the Other Bookmarks.
- const BookmarkNode* otherBookmarks = model->other_node();
- node = model->AddURL(otherBookmarks, otherBookmarks->GetChildCount(),
- ASCIIToUTF16("TheOther"),
- GURL("http://www.other.com"));
- EXPECT_FALSE([noItemContainer isHidden]);
- // Move it from Other Bookmarks to the bar.
- model->Move(node, bar, 0);
- EXPECT_TRUE([noItemContainer isHidden]);
- // Move it back to Other Bookmarks from the bar.
- model->Move(node, otherBookmarks, 0);
- EXPECT_FALSE([noItemContainer isHidden]);
-}
-
-// Confirm off the side button only enabled when reasonable.
-TEST_F(BookmarkBarControllerTest, OffTheSideButtonHidden) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- [bar_ setIgnoreAnimations:YES];
-
- [bar_ loaded:model];
- EXPECT_TRUE([bar_ offTheSideButtonIsHidden]);
-
- for (int i = 0; i < 2; i++) {
- model->SetURLStarred(GURL("http://www.foo.com"), ASCIIToUTF16("small"),
- true);
- EXPECT_TRUE([bar_ offTheSideButtonIsHidden]);
- }
-
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- for (int i = 0; i < 20; i++) {
- model->AddURL(parent, parent->GetChildCount(),
- ASCIIToUTF16("super duper wide title"),
- GURL("http://superfriends.hall-of-justice.edu"));
- }
- EXPECT_FALSE([bar_ offTheSideButtonIsHidden]);
-
- // Open the "off the side" and start deleting nodes. Make sure
- // deletion of the last node in "off the side" causes the folder to
- // close.
- EXPECT_FALSE([bar_ offTheSideButtonIsHidden]);
- NSButton* offTheSideButton = [bar_ offTheSideButton];
- // Open "off the side" menu.
- [bar_ openOffTheSideFolderFromButton:offTheSideButton];
- BookmarkBarFolderController* bbfc = [bar_ folderController];
- EXPECT_TRUE(bbfc);
- [bbfc setIgnoreAnimations:YES];
- while (parent->GetChildCount()) {
- // We've completed the job so we're done.
- if ([bar_ offTheSideButtonIsHidden])
- break;
- // Delete the last button.
- model->Remove(parent, parent->GetChildCount()-1);
- // If last one make sure the menu is closed and the button is hidden.
- // Else make sure menu stays open.
- if ([bar_ offTheSideButtonIsHidden]) {
- EXPECT_FALSE([bar_ folderController]);
- } else {
- EXPECT_TRUE([bar_ folderController]);
- }
- }
-}
-
-// http://crbug.com/46175 is a crash when deleting bookmarks from the
-// off-the-side menu while it is open. This test tries to bang hard
-// in this area to reproduce the crash.
-TEST_F(BookmarkBarControllerTest, DeleteFromOffTheSideWhileItIsOpen) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- [bar_ setIgnoreAnimations:YES];
- [bar_ loaded:model];
-
- // Add a lot of bookmarks (per the bug).
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- for (int i = 0; i < 100; i++) {
- std::ostringstream title;
- title << "super duper wide title " << i;
- model->AddURL(parent, parent->GetChildCount(), ASCIIToUTF16(title.str()),
- GURL("http://superfriends.hall-of-justice.edu"));
- }
- EXPECT_FALSE([bar_ offTheSideButtonIsHidden]);
-
- // Open "off the side" menu.
- NSButton* offTheSideButton = [bar_ offTheSideButton];
- [bar_ openOffTheSideFolderFromButton:offTheSideButton];
- BookmarkBarFolderController* bbfc = [bar_ folderController];
- EXPECT_TRUE(bbfc);
- [bbfc setIgnoreAnimations:YES];
-
- // Start deleting items; try and delete randomish ones in case it
- // makes a difference.
- int indices[] = { 2, 4, 5, 1, 7, 9, 2, 0, 10, 9 };
- while (parent->GetChildCount()) {
- for (unsigned int i = 0; i < arraysize(indices); i++) {
- if (indices[i] < parent->GetChildCount()) {
- // First we mouse-enter the button to make things harder.
- NSArray* buttons = [bbfc buttons];
- for (BookmarkButton* button in buttons) {
- if ([button bookmarkNode] == parent->GetChild(indices[i])) {
- [bbfc mouseEnteredButton:button event:nil];
- break;
- }
- }
- // Then we remove the node. This triggers the button to get
- // deleted.
- model->Remove(parent, indices[i]);
- // Force visual update which is otherwise delayed.
- [[bbfc window] displayIfNeeded];
- }
- }
- }
-}
-
-// Test whether |-dragShouldLockBarVisibility| returns NO iff the bar is
-// detached.
-TEST_F(BookmarkBarControllerTest, TestDragShouldLockBarVisibility) {
- [bar_ updateAndShowNormalBar:NO
- showDetachedBar:NO
- withAnimation:NO];
- EXPECT_TRUE([bar_ dragShouldLockBarVisibility]);
-
- [bar_ updateAndShowNormalBar:YES
- showDetachedBar:NO
- withAnimation:NO];
- EXPECT_TRUE([bar_ dragShouldLockBarVisibility]);
-
- [bar_ updateAndShowNormalBar:YES
- showDetachedBar:YES
- withAnimation:NO];
- EXPECT_TRUE([bar_ dragShouldLockBarVisibility]);
-
- [bar_ updateAndShowNormalBar:NO
- showDetachedBar:YES
- withAnimation:NO];
- EXPECT_FALSE([bar_ dragShouldLockBarVisibility]);
-}
-
-TEST_F(BookmarkBarControllerTest, TagMap) {
- int64 ids[] = { 1, 3, 4, 40, 400, 4000, 800000000, 2, 123456789 };
- std::vector<int32> tags;
-
- // Generate some tags
- for (unsigned int i = 0; i < arraysize(ids); i++) {
- tags.push_back([bar_ menuTagFromNodeId:ids[i]]);
- }
-
- // Confirm reverse mapping.
- for (unsigned int i = 0; i < arraysize(ids); i++) {
- EXPECT_EQ(ids[i], [bar_ nodeIdFromMenuTag:tags[i]]);
- }
-
- // Confirm uniqueness.
- std::sort(tags.begin(), tags.end());
- for (unsigned int i=0; i<(tags.size()-1); i++) {
- EXPECT_NE(tags[i], tags[i+1]);
- }
-}
-
-TEST_F(BookmarkBarControllerTest, MenuForFolderNode) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
-
- // First make sure something (e.g. "(empty)" string) is always present.
- NSMenu* menu = [bar_ menuForFolderNode:model->GetBookmarkBarNode()];
- EXPECT_GT([menu numberOfItems], 0);
-
- // Test two bookmarks.
- GURL gurl("http://www.foo.com");
- model->SetURLStarred(gurl, ASCIIToUTF16("small"), true);
- model->SetURLStarred(GURL("http://www.cnn.com"), ASCIIToUTF16("bigger title"),
- true);
- menu = [bar_ menuForFolderNode:model->GetBookmarkBarNode()];
- EXPECT_EQ([menu numberOfItems], 2);
- NSMenuItem *item = [menu itemWithTitle:@"bigger title"];
- EXPECT_TRUE(item);
- item = [menu itemWithTitle:@"small"];
- EXPECT_TRUE(item);
- if (item) {
- int64 tag = [bar_ nodeIdFromMenuTag:[item tag]];
- const BookmarkNode* node = model->GetNodeByID(tag);
- EXPECT_TRUE(node);
- EXPECT_EQ(gurl, node->GetURL());
- }
-
- // Test with an actual folder as well
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- const BookmarkNode* folder = model->AddGroup(parent,
- parent->GetChildCount(),
- ASCIIToUTF16("group"));
- model->AddURL(folder, folder->GetChildCount(),
- ASCIIToUTF16("f1"), GURL("http://framma-lamma.com"));
- model->AddURL(folder, folder->GetChildCount(),
- ASCIIToUTF16("f2"), GURL("http://framma-lamma-ding-dong.com"));
- menu = [bar_ menuForFolderNode:model->GetBookmarkBarNode()];
- EXPECT_EQ([menu numberOfItems], 3);
-
- item = [menu itemWithTitle:@"group"];
- EXPECT_TRUE(item);
- EXPECT_TRUE([item hasSubmenu]);
- NSMenu *submenu = [item submenu];
- EXPECT_TRUE(submenu);
- EXPECT_EQ(2, [submenu numberOfItems]);
- EXPECT_TRUE([submenu itemWithTitle:@"f1"]);
- EXPECT_TRUE([submenu itemWithTitle:@"f2"]);
-}
-
-// Confirm openBookmark: forwards the request to the controller's delegate
-TEST_F(BookmarkBarControllerTest, OpenBookmark) {
- GURL gurl("http://walla.walla.ding.dong.com");
- scoped_ptr<BookmarkNode> node(new BookmarkNode(gurl));
-
- scoped_nsobject<BookmarkButtonCell> cell([[BookmarkButtonCell alloc] init]);
- [cell setBookmarkNode:node.get()];
- scoped_nsobject<BookmarkButton> button([[BookmarkButton alloc] init]);
- [button setCell:cell.get()];
- [cell setRepresentedObject:[NSValue valueWithPointer:node.get()]];
-
- [bar_ openBookmark:button];
- EXPECT_EQ(noOpenBar()->urls_[0], node->GetURL());
- EXPECT_EQ(noOpenBar()->dispositions_[0], CURRENT_TAB);
-}
-
-// Confirm opening of bookmarks works from the menus (different
-// dispositions than clicking on the button).
-TEST_F(BookmarkBarControllerTest, OpenBookmarkFromMenus) {
- const char* urls[] = { "http://walla.walla.ding.dong.com",
- "http://i_dont_know.com",
- "http://cee.enn.enn.dot.com" };
- SEL selectors[] = { @selector(openBookmarkInNewForegroundTab:),
- @selector(openBookmarkInNewWindow:),
- @selector(openBookmarkInIncognitoWindow:) };
- WindowOpenDisposition dispositions[] = { NEW_FOREGROUND_TAB,
- NEW_WINDOW,
- OFF_THE_RECORD };
- for (unsigned int i = 0; i < arraysize(dispositions); i++) {
- GURL gurl(urls[i]);
- [bar_ performSelector:selectors[i]
- withObject:ItemForBookmarkBarMenu(gurl)];
- EXPECT_EQ(noOpenBar()->urls_[0], gurl);
- EXPECT_EQ(noOpenBar()->dispositions_[0], dispositions[i]);
- [bar_ clear];
- }
-}
-
-TEST_F(BookmarkBarControllerTest, TestAddRemoveAndClear) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- NSView* buttonView = [bar_ buttonView];
- EXPECT_EQ(0U, [[bar_ buttons] count]);
- unsigned int initial_subview_count = [[buttonView subviews] count];
-
- // Make sure a redundant call doesn't choke
- [bar_ clearBookmarkBar];
- EXPECT_EQ(0U, [[bar_ buttons] count]);
- EXPECT_EQ(initial_subview_count, [[buttonView subviews] count]);
-
- GURL gurl1("http://superfriends.hall-of-justice.edu");
- // Short titles increase the chances of this test succeeding if the view is
- // narrow.
- // TODO(viettrungluu): make the test independent of window/view size, font
- // metrics, button size and spacing, and everything else.
- string16 title1(ASCIIToUTF16("x"));
- model->SetURLStarred(gurl1, title1, true);
- EXPECT_EQ(1U, [[bar_ buttons] count]);
- EXPECT_EQ(1+initial_subview_count, [[buttonView subviews] count]);
-
- GURL gurl2("http://legion-of-doom.gov");
- string16 title2(ASCIIToUTF16("y"));
- model->SetURLStarred(gurl2, title2, true);
- EXPECT_EQ(2U, [[bar_ buttons] count]);
- EXPECT_EQ(2+initial_subview_count, [[buttonView subviews] count]);
-
- for (int i = 0; i < 3; i++) {
- // is_starred=false --> remove the bookmark
- model->SetURLStarred(gurl2, title2, false);
- EXPECT_EQ(1U, [[bar_ buttons] count]);
- EXPECT_EQ(1+initial_subview_count, [[buttonView subviews] count]);
-
- // and bring it back
- model->SetURLStarred(gurl2, title2, true);
- EXPECT_EQ(2U, [[bar_ buttons] count]);
- EXPECT_EQ(2+initial_subview_count, [[buttonView subviews] count]);
- }
-
- [bar_ clearBookmarkBar];
- EXPECT_EQ(0U, [[bar_ buttons] count]);
- EXPECT_EQ(initial_subview_count, [[buttonView subviews] count]);
-
- // Explicit test of loaded: since this is a convenient spot
- [bar_ loaded:model];
- EXPECT_EQ(2U, [[bar_ buttons] count]);
- EXPECT_EQ(2+initial_subview_count, [[buttonView subviews] count]);
-}
-
-// Make sure we don't create too many buttons; we only really need
-// ones that will be visible.
-TEST_F(BookmarkBarControllerTest, TestButtonLimits) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- EXPECT_EQ(0U, [[bar_ buttons] count]);
- // Add one; make sure we see it.
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- model->AddURL(parent, parent->GetChildCount(),
- ASCIIToUTF16("title"), GURL("http://www.google.com"));
- EXPECT_EQ(1U, [[bar_ buttons] count]);
-
- // Add 30 which we expect to be 'too many'. Make sure we don't see
- // 30 buttons.
- model->Remove(parent, 0);
- EXPECT_EQ(0U, [[bar_ buttons] count]);
- for (int i=0; i<30; i++) {
- model->AddURL(parent, parent->GetChildCount(),
- ASCIIToUTF16("title"), GURL("http://www.google.com"));
- }
- int count = [[bar_ buttons] count];
- EXPECT_LT(count, 30L);
-
- // Add 10 more (to the front of the list so the on-screen buttons
- // would change) and make sure the count stays the same.
- for (int i=0; i<10; i++) {
- model->AddURL(parent, 0, /* index is 0, so front, not end */
- ASCIIToUTF16("title"), GURL("http://www.google.com"));
- }
-
- // Finally, grow the view and make sure the button count goes up.
- NSRect frame = [[bar_ view] frame];
- frame.size.width += 600;
- [[bar_ view] setFrame:frame];
- int finalcount = [[bar_ buttons] count];
- EXPECT_GT(finalcount, count);
-}
-
-// Make sure that each button we add marches to the right and does not
-// overlap with the previous one.
-TEST_F(BookmarkBarControllerTest, TestButtonMarch) {
- scoped_nsobject<NSMutableArray> cells([[NSMutableArray alloc] init]);
-
- CGFloat widths[] = { 10, 10, 100, 10, 500, 500, 80000, 60000, 1, 345 };
- for (unsigned int i = 0; i < arraysize(widths); i++) {
- NSCell* cell = [[CellWithDesiredSize alloc]
- initTextCell:@"foo"
- desiredSize:NSMakeSize(widths[i], 30)];
- [cells addObject:cell];
- [cell release];
- }
-
- int x_offset = 0;
- CGFloat x_end = x_offset; // end of the previous button
- for (unsigned int i = 0; i < arraysize(widths); i++) {
- NSRect r = [bar_ frameForBookmarkButtonFromCell:[cells objectAtIndex:i]
- xOffset:&x_offset];
- EXPECT_GE(r.origin.x, x_end);
- x_end = NSMaxX(r);
- }
-}
-
-TEST_F(BookmarkBarControllerTest, CheckForGrowth) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- GURL gurl1("http://www.google.com");
- string16 title1(ASCIIToUTF16("x"));
- model->SetURLStarred(gurl1, title1, true);
-
- GURL gurl2("http://www.google.com/blah");
- string16 title2(ASCIIToUTF16("y"));
- model->SetURLStarred(gurl2, title2, true);
-
- EXPECT_EQ(2U, [[bar_ buttons] count]);
- CGFloat width_1 = [[[bar_ buttons] objectAtIndex:0] frame].size.width;
- CGFloat x_2 = [[[bar_ buttons] objectAtIndex:1] frame].origin.x;
-
- NSButton* first = [[bar_ buttons] objectAtIndex:0];
- [[first cell] setTitle:@"This is a really big title; watch out mom!"];
- [bar_ checkForBookmarkButtonGrowth:first];
-
- // Make sure the 1st button is now wider, the 2nd one is moved over,
- // and they don't overlap.
- NSRect frame_1 = [[[bar_ buttons] objectAtIndex:0] frame];
- NSRect frame_2 = [[[bar_ buttons] objectAtIndex:1] frame];
- EXPECT_GT(frame_1.size.width, width_1);
- EXPECT_GT(frame_2.origin.x, x_2);
- EXPECT_GE(frame_2.origin.x, frame_1.origin.x + frame_1.size.width);
-}
-
-TEST_F(BookmarkBarControllerTest, DeleteBookmark) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
-
- const char* urls[] = { "https://secret.url.com",
- "http://super.duper.web.site.for.doodz.gov",
- "http://www.foo-bar-baz.com/" };
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- for (unsigned int i = 0; i < arraysize(urls); i++) {
- model->AddURL(parent, parent->GetChildCount(),
- ASCIIToUTF16("title"), GURL(urls[i]));
- }
- EXPECT_EQ(3, parent->GetChildCount());
- const BookmarkNode* middle_node = parent->GetChild(1);
-
- NSMenuItem* item = ItemForBookmarkBarMenu(middle_node);
- [bar_ deleteBookmark:item];
- EXPECT_EQ(2, parent->GetChildCount());
- EXPECT_EQ(parent->GetChild(0)->GetURL(), GURL(urls[0]));
- // node 2 moved into spot 1
- EXPECT_EQ(parent->GetChild(1)->GetURL(), GURL(urls[2]));
-}
-
-// TODO(jrg): write a test to confirm that nodeFavIconLoaded calls
-// checkForBookmarkButtonGrowth:.
-
-TEST_F(BookmarkBarControllerTest, Cell) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- [bar_ loaded:model];
-
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- model->AddURL(parent, parent->GetChildCount(),
- ASCIIToUTF16("supertitle"),
- GURL("http://superfriends.hall-of-justice.edu"));
- const BookmarkNode* node = parent->GetChild(0);
-
- NSCell* cell = [bar_ cellForBookmarkNode:node];
- EXPECT_TRUE(cell);
- EXPECT_NSEQ(@"supertitle", [cell title]);
- EXPECT_EQ(node, [[cell representedObject] pointerValue]);
- EXPECT_TRUE([cell menu]);
-
- // Empty cells have no menu.
- cell = [bar_ cellForBookmarkNode:nil];
- EXPECT_FALSE([cell menu]);
- // Even empty cells have a title (of "(empty)")
- EXPECT_TRUE([cell title]);
-
- // cell is autoreleased; no need to release here
-}
-
-// Test drawing, mostly to ensure nothing leaks or crashes.
-TEST_F(BookmarkBarControllerTest, Display) {
- [[bar_ view] display];
-}
-
-// Test that middle clicking on a bookmark button results in an open action.
-TEST_F(BookmarkBarControllerTest, MiddleClick) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- GURL gurl1("http://www.google.com/");
- string16 title1(ASCIIToUTF16("x"));
- model->SetURLStarred(gurl1, title1, true);
-
- EXPECT_EQ(1U, [[bar_ buttons] count]);
- NSButton* first = [[bar_ buttons] objectAtIndex:0];
- EXPECT_TRUE(first);
-
- [first otherMouseUp:test_event_utils::MakeMouseEvent(NSOtherMouseUp, 0)];
- EXPECT_EQ(noOpenBar()->urls_.size(), 1U);
-}
-
-TEST_F(BookmarkBarControllerTest, DisplaysHelpMessageOnEmpty) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- [bar_ loaded:model];
- EXPECT_FALSE([[[bar_ buttonView] noItemContainer] isHidden]);
-}
-
-TEST_F(BookmarkBarControllerTest, HidesHelpMessageWithBookmark) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
-
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- model->AddURL(parent, parent->GetChildCount(),
- ASCIIToUTF16("title"), GURL("http://one.com"));
-
- [bar_ loaded:model];
- EXPECT_TRUE([[[bar_ buttonView] noItemContainer] isHidden]);
-}
-
-TEST_F(BookmarkBarControllerTest, BookmarkButtonSizing) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
-
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- model->AddURL(parent, parent->GetChildCount(),
- ASCIIToUTF16("title"), GURL("http://one.com"));
-
- [bar_ loaded:model];
-
- // Make sure the internal bookmark button also is the correct height.
- NSArray* buttons = [bar_ buttons];
- EXPECT_GT([buttons count], 0u);
- for (NSButton* button in buttons) {
- EXPECT_FLOAT_EQ(
- (bookmarks::kBookmarkBarHeight + bookmarks::kVisualHeightOffset) - 2 *
- bookmarks::kBookmarkVerticalPadding,
- [button frame].size.height);
- }
-}
-
-TEST_F(BookmarkBarControllerTest, DropBookmarks) {
- const char* urls[] = {
- "http://qwantz.com",
- "http://xkcd.com",
- "javascript:alert('lolwut')",
- "file://localhost/tmp/local-file.txt" // As if dragged from the desktop.
- };
- const char* titles[] = {
- "Philosophoraptor",
- "Can't draw",
- "Inspiration",
- "Frum stuf"
- };
- EXPECT_EQ(arraysize(urls), arraysize(titles));
-
- NSMutableArray* nsurls = [NSMutableArray array];
- NSMutableArray* nstitles = [NSMutableArray array];
- for (size_t i = 0; i < arraysize(urls); ++i) {
- [nsurls addObject:base::SysUTF8ToNSString(urls[i])];
- [nstitles addObject:base::SysUTF8ToNSString(titles[i])];
- }
-
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- [bar_ addURLs:nsurls withTitles:nstitles at:NSZeroPoint];
- EXPECT_EQ(4, parent->GetChildCount());
- for (int i = 0; i < parent->GetChildCount(); ++i) {
- GURL gurl = parent->GetChild(i)->GetURL();
- if (gurl.scheme() == "http" ||
- gurl.scheme() == "javascript") {
- EXPECT_EQ(parent->GetChild(i)->GetURL(), GURL(urls[i]));
- } else {
- // Be flexible if the scheme needed to be added.
- std::string gurl_string = gurl.spec();
- std::string my_string = parent->GetChild(i)->GetURL().spec();
- EXPECT_NE(gurl_string.find(my_string), std::string::npos);
- }
- EXPECT_EQ(parent->GetChild(i)->GetTitle(), ASCIIToUTF16(titles[i]));
- }
-}
-
-TEST_F(BookmarkBarControllerTest, TestButtonOrBar) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- GURL gurl1("http://www.google.com");
- string16 title1(ASCIIToUTF16("x"));
- model->SetURLStarred(gurl1, title1, true);
-
- GURL gurl2("http://www.google.com/gurl_power");
- string16 title2(ASCIIToUTF16("gurl power"));
- model->SetURLStarred(gurl2, title2, true);
-
- NSButton* first = [[bar_ buttons] objectAtIndex:0];
- NSButton* second = [[bar_ buttons] objectAtIndex:1];
- EXPECT_TRUE(first && second);
-
- NSMenuItem* menuItem = [[[first cell] menu] itemAtIndex:0];
- const BookmarkNode* node = [bar_ nodeFromMenuItem:menuItem];
- EXPECT_TRUE(node);
- EXPECT_EQ(node, model->GetBookmarkBarNode()->GetChild(0));
-
- menuItem = [[[second cell] menu] itemAtIndex:0];
- node = [bar_ nodeFromMenuItem:menuItem];
- EXPECT_TRUE(node);
- EXPECT_EQ(node, model->GetBookmarkBarNode()->GetChild(1));
-
- menuItem = [[[bar_ view] menu] itemAtIndex:0];
- node = [bar_ nodeFromMenuItem:menuItem];
- EXPECT_TRUE(node);
- EXPECT_EQ(node, model->GetBookmarkBarNode());
-}
-
-TEST_F(BookmarkBarControllerTest, TestMenuNodeAndDisable) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- const BookmarkNode* folder = model->AddGroup(parent,
- parent->GetChildCount(),
- ASCIIToUTF16("group"));
- NSButton* button = [[bar_ buttons] objectAtIndex:0];
- EXPECT_TRUE(button);
-
- // Confirm the menu knows which node it is talking about
- BookmarkMenu* menu = static_cast<BookmarkMenu*>([[button cell] menu]);
- EXPECT_TRUE(menu);
- EXPECT_TRUE([menu isKindOfClass:[BookmarkMenu class]]);
- EXPECT_EQ(folder->id(), [menu id]);
-
- // Make sure "Open All" is disabled (nothing to open -- no children!)
- // (Assumes "Open All" is the 1st item)
- NSMenuItem* item = [menu itemAtIndex:0];
- EXPECT_FALSE([bar_ validateUserInterfaceItem:item]);
-
- // Now add a child and make sure the item would be enabled.
- model->AddURL(folder, folder->GetChildCount(),
- ASCIIToUTF16("super duper wide title"),
- GURL("http://superfriends.hall-of-justice.edu"));
- EXPECT_TRUE([bar_ validateUserInterfaceItem:item]);
-}
-
-TEST_F(BookmarkBarControllerTest, TestDragButton) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
-
- GURL gurls[] = { GURL("http://www.google.com/a"),
- GURL("http://www.google.com/b"),
- GURL("http://www.google.com/c") };
- string16 titles[] = { ASCIIToUTF16("a"),
- ASCIIToUTF16("b"),
- ASCIIToUTF16("c") };
- for (unsigned i = 0; i < arraysize(titles); i++) {
- model->SetURLStarred(gurls[i], titles[i], true);
- }
-
- EXPECT_EQ([[bar_ buttons] count], arraysize(titles));
- EXPECT_NSEQ(@"a", [[[bar_ buttons] objectAtIndex:0] title]);
-
- [bar_ dragButton:[[bar_ buttons] objectAtIndex:2]
- to:NSMakePoint(0, 0)
- copy:NO];
- EXPECT_NSEQ(@"c", [[[bar_ buttons] objectAtIndex:0] title]);
- // Make sure a 'copy' did not happen.
- EXPECT_EQ([[bar_ buttons] count], arraysize(titles));
-
- [bar_ dragButton:[[bar_ buttons] objectAtIndex:1]
- to:NSMakePoint(1000, 0)
- copy:NO];
- EXPECT_NSEQ(@"c", [[[bar_ buttons] objectAtIndex:0] title]);
- EXPECT_NSEQ(@"b", [[[bar_ buttons] objectAtIndex:1] title]);
- EXPECT_NSEQ(@"a", [[[bar_ buttons] objectAtIndex:2] title]);
- EXPECT_EQ([[bar_ buttons] count], arraysize(titles));
-
- // A drop of the 1st between the next 2.
- CGFloat x = NSMinX([[[bar_ buttons] objectAtIndex:2] frame]);
- x += [[bar_ view] frame].origin.x;
- [bar_ dragButton:[[bar_ buttons] objectAtIndex:0]
- to:NSMakePoint(x, 0)
- copy:NO];
- EXPECT_NSEQ(@"b", [[[bar_ buttons] objectAtIndex:0] title]);
- EXPECT_NSEQ(@"c", [[[bar_ buttons] objectAtIndex:1] title]);
- EXPECT_NSEQ(@"a", [[[bar_ buttons] objectAtIndex:2] title]);
- EXPECT_EQ([[bar_ buttons] count], arraysize(titles));
-
- // A drop on a non-folder button. (Shouldn't try and go in it.)
- x = NSMidX([[[bar_ buttons] objectAtIndex:0] frame]);
- x += [[bar_ view] frame].origin.x;
- [bar_ dragButton:[[bar_ buttons] objectAtIndex:2]
- to:NSMakePoint(x, 0)
- copy:NO];
- EXPECT_EQ(arraysize(titles), [[bar_ buttons] count]);
-
- // A drop on a folder button.
- const BookmarkNode* folder = model->AddGroup(model->GetBookmarkBarNode(),
- 0,
- ASCIIToUTF16("awesome group"));
- DCHECK(folder);
- model->AddURL(folder, 0, ASCIIToUTF16("already"),
- GURL("http://www.google.com"));
- EXPECT_EQ(arraysize(titles) + 1, [[bar_ buttons] count]);
- EXPECT_EQ(1, folder->GetChildCount());
- x = NSMidX([[[bar_ buttons] objectAtIndex:0] frame]);
- x += [[bar_ view] frame].origin.x;
- string16 title = [[[bar_ buttons] objectAtIndex:2] bookmarkNode]->GetTitle();
- [bar_ dragButton:[[bar_ buttons] objectAtIndex:2]
- to:NSMakePoint(x, 0)
- copy:NO];
- // Gone from the bar
- EXPECT_EQ(arraysize(titles), [[bar_ buttons] count]);
- // In the folder
- EXPECT_EQ(2, folder->GetChildCount());
- // At the end
- EXPECT_EQ(title, folder->GetChild(1)->GetTitle());
-}
-
-TEST_F(BookmarkBarControllerTest, TestCopyButton) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
-
- GURL gurls[] = { GURL("http://www.google.com/a"),
- GURL("http://www.google.com/b"),
- GURL("http://www.google.com/c") };
- string16 titles[] = { ASCIIToUTF16("a"),
- ASCIIToUTF16("b"),
- ASCIIToUTF16("c") };
- for (unsigned i = 0; i < arraysize(titles); i++) {
- model->SetURLStarred(gurls[i], titles[i], true);
- }
- EXPECT_EQ([[bar_ buttons] count], arraysize(titles));
- EXPECT_NSEQ(@"a", [[[bar_ buttons] objectAtIndex:0] title]);
-
- // Drag 'a' between 'b' and 'c'.
- CGFloat x = NSMinX([[[bar_ buttons] objectAtIndex:2] frame]);
- x += [[bar_ view] frame].origin.x;
- [bar_ dragButton:[[bar_ buttons] objectAtIndex:0]
- to:NSMakePoint(x, 0)
- copy:YES];
- EXPECT_NSEQ(@"a", [[[bar_ buttons] objectAtIndex:0] title]);
- EXPECT_NSEQ(@"b", [[[bar_ buttons] objectAtIndex:1] title]);
- EXPECT_NSEQ(@"a", [[[bar_ buttons] objectAtIndex:2] title]);
- EXPECT_NSEQ(@"c", [[[bar_ buttons] objectAtIndex:3] title]);
- EXPECT_EQ([[bar_ buttons] count], 4U);
-}
-
-// Fake a theme with colored text. Apply it and make sure bookmark
-// buttons have the same colored text. Repeat more than once.
-TEST_F(BookmarkBarControllerTest, TestThemedButton) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- model->SetURLStarred(GURL("http://www.foo.com"), ASCIIToUTF16("small"), true);
- BookmarkButton* button = [[bar_ buttons] objectAtIndex:0];
- EXPECT_TRUE(button);
-
- NSArray* colors = [NSArray arrayWithObjects:[NSColor redColor],
- [NSColor blueColor],
- nil];
- for (NSColor* color in colors) {
- FakeTheme theme(color);
- [bar_ updateTheme:&theme];
- NSAttributedString* astr = [button attributedTitle];
- EXPECT_TRUE(astr);
- EXPECT_NSEQ(@"small", [astr string]);
- // Pick a char in the middle to test (index 3)
- NSDictionary* attributes = [astr attributesAtIndex:3 effectiveRange:NULL];
- NSColor* newColor =
- [attributes objectForKey:NSForegroundColorAttributeName];
- EXPECT_NSEQ(newColor, color);
- }
-}
-
-// Test that delegates and targets of buttons are cleared on dealloc.
-TEST_F(BookmarkBarControllerTest, TestClearOnDealloc) {
- // Make some bookmark buttons.
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- GURL gurls[] = { GURL("http://www.foo.com/"),
- GURL("http://www.bar.com/"),
- GURL("http://www.baz.com/") };
- string16 titles[] = { ASCIIToUTF16("a"),
- ASCIIToUTF16("b"),
- ASCIIToUTF16("c") };
- for (size_t i = 0; i < arraysize(titles); i++)
- model->SetURLStarred(gurls[i], titles[i], true);
-
- // Get and retain the buttons so we can examine them after dealloc.
- scoped_nsobject<NSArray> buttons([[bar_ buttons] retain]);
- EXPECT_EQ([buttons count], arraysize(titles));
-
- // Make sure that everything is set.
- for (BookmarkButton* button in buttons.get()) {
- ASSERT_TRUE([button isKindOfClass:[BookmarkButton class]]);
- EXPECT_TRUE([button delegate]);
- EXPECT_TRUE([button target]);
- EXPECT_TRUE([button action]);
- }
-
- // This will dealloc....
- bar_.reset();
-
- // Make sure that everything is cleared.
- for (BookmarkButton* button in buttons.get()) {
- EXPECT_FALSE([button delegate]);
- EXPECT_FALSE([button target]);
- EXPECT_FALSE([button action]);
- }
-}
-
-TEST_F(BookmarkBarControllerTest, TestFolders) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
-
- // Create some folder buttons.
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- const BookmarkNode* folder = model->AddGroup(parent,
- parent->GetChildCount(),
- ASCIIToUTF16("group"));
- model->AddURL(folder, folder->GetChildCount(),
- ASCIIToUTF16("f1"), GURL("http://framma-lamma.com"));
- folder = model->AddGroup(parent, parent->GetChildCount(),
- ASCIIToUTF16("empty"));
-
- EXPECT_EQ([[bar_ buttons] count], 2U);
-
- // First confirm mouseEntered does nothing if "menus" aren't active.
- NSEvent* event = test_event_utils::MakeMouseEvent(NSOtherMouseUp, 0);
- [bar_ mouseEnteredButton:[[bar_ buttons] objectAtIndex:0] event:event];
- EXPECT_FALSE([bar_ folderController]);
-
- // Make one active. Entering it is now a no-op.
- [bar_ openBookmarkFolderFromButton:[[bar_ buttons] objectAtIndex:0]];
- BookmarkBarFolderController* bbfc = [bar_ folderController];
- EXPECT_TRUE(bbfc);
- [bar_ mouseEnteredButton:[[bar_ buttons] objectAtIndex:0] event:event];
- EXPECT_EQ(bbfc, [bar_ folderController]);
-
- // Enter a different one; a new folderController is active.
- [bar_ mouseEnteredButton:[[bar_ buttons] objectAtIndex:1] event:event];
- EXPECT_NE(bbfc, [bar_ folderController]);
-
- // Confirm exited is a no-op.
- [bar_ mouseExitedButton:[[bar_ buttons] objectAtIndex:1] event:event];
- EXPECT_NE(bbfc, [bar_ folderController]);
-
- // Clean up.
- [bar_ closeBookmarkFolder:nil];
-}
-
-// Verify that the folder menu presentation properly tracks mouse movements
-// over the bar. Until there is a click no folder menus should show. After a
-// click on a folder folder menus should show until another click on a folder
-// button, and a click outside the bar and its folder menus.
-TEST_F(BookmarkBarControllerTest, TestFolderButtons) {
- BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
- const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::string model_string("1b 2f:[ 2f1b 2f2b ] 3b 4f:[ 4f1b 4f2b ] ");
- model_test_utils::AddNodesFromModelString(model, root, model_string);
-
- // Validate initial model and that we do not have a folder controller.
- std::string actualModelString = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(model_string, actualModelString);
- EXPECT_FALSE([bar_ folderController]);
-
- // Add a real bookmark so we can click on it.
- const BookmarkNode* folder = root->GetChild(3);
- model.AddURL(folder, folder->GetChildCount(), ASCIIToUTF16("CLICK ME"),
- GURL("http://www.google.com/"));
-
- // Click on a folder button.
- BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"4f"];
- EXPECT_TRUE(button);
- [bar_ openBookmarkFolderFromButton:button];
- BookmarkBarFolderController* bbfc = [bar_ folderController];
- EXPECT_TRUE(bbfc);
-
- // Make sure a 2nd click on the same button closes things.
- [bar_ openBookmarkFolderFromButton:button];
- EXPECT_FALSE([bar_ folderController]);
-
- // Next open is a different button.
- button = [bar_ buttonWithTitleEqualTo:@"2f"];
- EXPECT_TRUE(button);
- [bar_ openBookmarkFolderFromButton:button];
- EXPECT_TRUE([bar_ folderController]);
-
- // Mouse over a non-folder button and confirm controller has gone away.
- button = [bar_ buttonWithTitleEqualTo:@"1b"];
- EXPECT_TRUE(button);
- NSEvent* event = test_event_utils::MouseEventAtPoint([button center],
- NSMouseMoved, 0);
- [bar_ mouseEnteredButton:button event:event];
- EXPECT_FALSE([bar_ folderController]);
-
- // Mouse over the original folder and confirm a new controller.
- button = [bar_ buttonWithTitleEqualTo:@"2f"];
- EXPECT_TRUE(button);
- [bar_ mouseEnteredButton:button event:event];
- BookmarkBarFolderController* oldBBFC = [bar_ folderController];
- EXPECT_TRUE(oldBBFC);
-
- // 'Jump' over to a different folder and confirm a new controller.
- button = [bar_ buttonWithTitleEqualTo:@"4f"];
- EXPECT_TRUE(button);
- [bar_ mouseEnteredButton:button event:event];
- BookmarkBarFolderController* newBBFC = [bar_ folderController];
- EXPECT_TRUE(newBBFC);
- EXPECT_NE(oldBBFC, newBBFC);
-
- // A click on a real bookmark should close and stop tracking the folder menus.
- BookmarkButton* bookmarkButton = [newBBFC buttonWithTitleEqualTo:@"CLICK ME"];
- EXPECT_TRUE(bookmarkButton);
- [newBBFC openBookmark:bookmarkButton];
- EXPECT_FALSE([bar_ folderController]);
- [bar_ mouseEnteredButton:button event:event];
- EXPECT_FALSE([bar_ folderController]);
-}
-
-// Make sure the "off the side" folder looks like a bookmark folder
-// but only contains "off the side" items.
-TEST_F(BookmarkBarControllerTest, OffTheSideFolder) {
-
- // It starts hidden.
- EXPECT_TRUE([bar_ offTheSideButtonIsHidden]);
-
- // Create some buttons.
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- for (int x = 0; x < 30; x++) {
- model->AddURL(parent, parent->GetChildCount(),
- ASCIIToUTF16("medium-size-title"),
- GURL("http://framma-lamma.com"));
- }
- // Add a couple more so we can delete one and make sure its button goes away.
- model->AddURL(parent, parent->GetChildCount(),
- ASCIIToUTF16("DELETE_ME"), GURL("http://ashton-tate.com"));
- model->AddURL(parent, parent->GetChildCount(),
- ASCIIToUTF16("medium-size-title"),
- GURL("http://framma-lamma.com"));
-
- // Should no longer be hidden.
- EXPECT_FALSE([bar_ offTheSideButtonIsHidden]);
-
- // Open it; make sure we have a folder controller.
- EXPECT_FALSE([bar_ folderController]);
- [bar_ openOffTheSideFolderFromButton:[bar_ offTheSideButton]];
- BookmarkBarFolderController* bbfc = [bar_ folderController];
- EXPECT_TRUE(bbfc);
-
- // Confirm the contents are only buttons which fell off the side by
- // making sure that none of the nodes in the off-the-side folder are
- // found in bar buttons. Be careful since not all the bar buttons
- // may be currently displayed.
- NSArray* folderButtons = [bbfc buttons];
- NSArray* barButtons = [bar_ buttons];
- for (BookmarkButton* folderButton in folderButtons) {
- for (BookmarkButton* barButton in barButtons) {
- if ([barButton superview]) {
- EXPECT_NE([folderButton bookmarkNode], [barButton bookmarkNode]);
- }
- }
- }
-
- // Delete a bookmark in the off-the-side and verify it's gone.
- BookmarkButton* button = [bbfc buttonWithTitleEqualTo:@"DELETE_ME"];
- EXPECT_TRUE(button);
- model->Remove(parent, parent->GetChildCount() - 2);
- button = [bbfc buttonWithTitleEqualTo:@"DELETE_ME"];
- EXPECT_FALSE(button);
-}
-
-TEST_F(BookmarkBarControllerTest, EventToExitCheck) {
- NSEvent* event = test_event_utils::MakeMouseEvent(NSMouseMoved, 0);
- EXPECT_FALSE([bar_ isEventAnExitEvent:event]);
-
- BookmarkBarFolderWindow* folderWindow = [[[BookmarkBarFolderWindow alloc]
- init] autorelease];
- [[[bar_ view] window] addChildWindow:folderWindow
- ordered:NSWindowAbove];
- event = test_event_utils::LeftMouseDownAtPointInWindow(NSMakePoint(1,1),
- folderWindow);
- EXPECT_FALSE([bar_ isEventAnExitEvent:event]);
-
- event = test_event_utils::LeftMouseDownAtPointInWindow(NSMakePoint(100,100),
- test_window());
- EXPECT_TRUE([bar_ isEventAnExitEvent:event]);
-
- // Many components are arbitrary (e.g. location, keycode).
- event = [NSEvent keyEventWithType:NSKeyDown
- location:NSMakePoint(1,1)
- modifierFlags:0
- timestamp:0
- windowNumber:0
- context:nil
- characters:@"x"
- charactersIgnoringModifiers:@"x"
- isARepeat:NO
- keyCode:87];
- EXPECT_TRUE([bar_ isEventAnExitEvent:event]);
-
- [[[bar_ view] window] removeChildWindow:folderWindow];
-}
-
-TEST_F(BookmarkBarControllerTest, DropDestination) {
- // Make some buttons.
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- model->AddGroup(parent, parent->GetChildCount(), ASCIIToUTF16("group 1"));
- model->AddGroup(parent, parent->GetChildCount(), ASCIIToUTF16("group 2"));
- EXPECT_EQ([[bar_ buttons] count], 2U);
-
- // Confirm "off to left" and "off to right" match nothing.
- NSPoint p = NSMakePoint(-1, 2);
- EXPECT_FALSE([bar_ buttonForDroppingOnAtPoint:p]);
- EXPECT_TRUE([bar_ shouldShowIndicatorShownForPoint:p]);
- p = NSMakePoint(50000, 10);
- EXPECT_FALSE([bar_ buttonForDroppingOnAtPoint:p]);
- EXPECT_TRUE([bar_ shouldShowIndicatorShownForPoint:p]);
-
- // Confirm "right in the center" (give or take a pixel) is a match,
- // and confirm "just barely in the button" is not. Anything more
- // specific seems likely to be tweaked.
- CGFloat viewFrameXOffset = [[bar_ view] frame].origin.x;
- for (BookmarkButton* button in [bar_ buttons]) {
- CGFloat x = NSMidX([button frame]) + viewFrameXOffset;
- // Somewhere near the center: a match
- EXPECT_EQ(button,
- [bar_ buttonForDroppingOnAtPoint:NSMakePoint(x-1, 10)]);
- EXPECT_EQ(button,
- [bar_ buttonForDroppingOnAtPoint:NSMakePoint(x+1, 10)]);
- EXPECT_FALSE([bar_ shouldShowIndicatorShownForPoint:NSMakePoint(x, 10)]);;
-
- // On the very edges: NOT a match
- x = NSMinX([button frame]) + viewFrameXOffset;
- EXPECT_NE(button,
- [bar_ buttonForDroppingOnAtPoint:NSMakePoint(x, 9)]);
- x = NSMaxX([button frame]) + viewFrameXOffset;
- EXPECT_NE(button,
- [bar_ buttonForDroppingOnAtPoint:NSMakePoint(x, 11)]);
- }
-}
-
-TEST_F(BookmarkBarControllerTest, NodeDeletedWhileMenuIsOpen) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- [bar_ loaded:model];
-
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- const BookmarkNode* initialNode = model->AddURL(
- parent, parent->GetChildCount(),
- ASCIIToUTF16("initial"),
- GURL("http://www.google.com"));
-
- NSMenuItem* item = ItemForBookmarkBarMenu(initialNode);
- EXPECT_EQ(0U, noOpenBar()->urls_.size());
-
- // Basic check of the menu item and an IBOutlet it can call.
- EXPECT_EQ(initialNode, [bar_ nodeFromMenuItem:item]);
- [bar_ openBookmarkInNewWindow:item];
- EXPECT_EQ(1U, noOpenBar()->urls_.size());
- [bar_ clear];
-
- // Now delete the node and make sure things are happy (no crash,
- // NULL node caught).
- model->Remove(parent, parent->IndexOfChild(initialNode));
- EXPECT_EQ(nil, [bar_ nodeFromMenuItem:item]);
- // Should not crash by referencing a deleted node.
- [bar_ openBookmarkInNewWindow:item];
- // Confirm the above did nothing in case it somehow didn't crash.
- EXPECT_EQ(0U, noOpenBar()->urls_.size());
-
- // Confirm some more non-crashes.
- [bar_ openBookmarkInNewForegroundTab:item];
- [bar_ openBookmarkInIncognitoWindow:item];
- [bar_ editBookmark:item];
- [bar_ copyBookmark:item];
- [bar_ deleteBookmark:item];
- [bar_ openAllBookmarks:item];
- [bar_ openAllBookmarksNewWindow:item];
- [bar_ openAllBookmarksIncognitoWindow:item];
-}
-
-TEST_F(BookmarkBarControllerTest, NodeDeletedWhileContextMenuIsOpen) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- [bar_ loaded:model];
-
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- const BookmarkNode* folder = model->AddGroup(parent,
- parent->GetChildCount(),
- ASCIIToUTF16("group"));
- const BookmarkNode* framma = model->AddURL(folder, folder->GetChildCount(),
- ASCIIToUTF16("f1"),
- GURL("http://framma-lamma.com"));
-
- // Mock in a menu
- id origMenu = [bar_ buttonContextMenu];
- id fakeMenu = [OCMockObject partialMockForObject:origMenu];
- [[fakeMenu expect] cancelTracking];
- [bar_ setButtonContextMenu:fakeMenu];
-
- // Force a delete which should cancelTracking on the menu.
- model->Remove(framma->GetParent(), framma->GetParent()->IndexOfChild(framma));
-
- // Restore, then confirm cancelTracking was called.
- [bar_ setButtonContextMenu:origMenu];
- [fakeMenu verify];
-}
-
-TEST_F(BookmarkBarControllerTest, CloseFolderOnAnimate) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- const BookmarkNode* folder = model->AddGroup(parent,
- parent->GetChildCount(),
- ASCIIToUTF16("group"));
- model->AddGroup(parent, parent->GetChildCount(),
- ASCIIToUTF16("sibbling group"));
- model->AddURL(folder, folder->GetChildCount(), ASCIIToUTF16("title a"),
- GURL("http://www.google.com/a"));
- model->AddURL(folder, folder->GetChildCount(),
- ASCIIToUTF16("title super duper long long whoa momma title you betcha"),
- GURL("http://www.google.com/b"));
- BookmarkButton* button = [[bar_ buttons] objectAtIndex:0];
- EXPECT_FALSE([bar_ folderController]);
- [bar_ openBookmarkFolderFromButton:button];
- BookmarkBarFolderController* bbfc = [bar_ folderController];
- // The following tells us that the folder menu is showing. We want to make
- // sure the folder menu goes away if the bookmark bar is hidden.
- EXPECT_TRUE(bbfc);
- EXPECT_TRUE([bar_ isVisible]);
-
- // Hide the bookmark bar.
- [bar_ updateAndShowNormalBar:NO
- showDetachedBar:YES
- withAnimation:YES];
- EXPECT_TRUE([bar_ isAnimationRunning]);
-
- // Now that we've closed the bookmark bar (with animation) the folder menu
- // should have been closed thus releasing the folderController.
- EXPECT_FALSE([bar_ folderController]);
-}
-
-TEST_F(BookmarkBarControllerTest, MoveRemoveAddButtons) {
- BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
- const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::string model_string("1b 2f:[ 2f1b 2f2b ] 3b ");
- model_test_utils::AddNodesFromModelString(model, root, model_string);
-
- // Validate initial model.
- std::string actualModelString = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(model_string, actualModelString);
-
- // Remember how many buttons are showing.
- int oldDisplayedButtons = [bar_ displayedButtonCount];
- NSArray* buttons = [bar_ buttons];
-
- // Move a button around a bit.
- [bar_ moveButtonFromIndex:0 toIndex:2];
- EXPECT_NSEQ(@"2f", [[buttons objectAtIndex:0] title]);
- EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:1] title]);
- EXPECT_NSEQ(@"1b", [[buttons objectAtIndex:2] title]);
- EXPECT_EQ(oldDisplayedButtons, [bar_ displayedButtonCount]);
- [bar_ moveButtonFromIndex:2 toIndex:0];
- EXPECT_NSEQ(@"1b", [[buttons objectAtIndex:0] title]);
- EXPECT_NSEQ(@"2f", [[buttons objectAtIndex:1] title]);
- EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:2] title]);
- EXPECT_EQ(oldDisplayedButtons, [bar_ displayedButtonCount]);
-
- // Add a couple of buttons.
- const BookmarkNode* parent = root->GetChild(1); // Purloin an existing node.
- const BookmarkNode* node = parent->GetChild(0);
- [bar_ addButtonForNode:node atIndex:0];
- EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:0] title]);
- EXPECT_NSEQ(@"1b", [[buttons objectAtIndex:1] title]);
- EXPECT_NSEQ(@"2f", [[buttons objectAtIndex:2] title]);
- EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:3] title]);
- EXPECT_EQ(oldDisplayedButtons + 1, [bar_ displayedButtonCount]);
- node = parent->GetChild(1);
- [bar_ addButtonForNode:node atIndex:-1];
- EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:0] title]);
- EXPECT_NSEQ(@"1b", [[buttons objectAtIndex:1] title]);
- EXPECT_NSEQ(@"2f", [[buttons objectAtIndex:2] title]);
- EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:3] title]);
- EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:4] title]);
- EXPECT_EQ(oldDisplayedButtons + 2, [bar_ displayedButtonCount]);
-
- // Remove a couple of buttons.
- [bar_ removeButton:4 animate:NO];
- [bar_ removeButton:1 animate:NO];
- EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:0] title]);
- EXPECT_NSEQ(@"2f", [[buttons objectAtIndex:1] title]);
- EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:2] title]);
- EXPECT_EQ(oldDisplayedButtons, [bar_ displayedButtonCount]);
-}
-
-TEST_F(BookmarkBarControllerTest, ShrinkOrHideView) {
- NSRect viewFrame = NSMakeRect(0.0, 0.0, 500.0, 50.0);
- NSView* view = [[[NSView alloc] initWithFrame:viewFrame] autorelease];
- EXPECT_FALSE([view isHidden]);
- [bar_ shrinkOrHideView:view forMaxX:500.0];
- EXPECT_EQ(500.0, NSWidth([view frame]));
- EXPECT_FALSE([view isHidden]);
- [bar_ shrinkOrHideView:view forMaxX:450.0];
- EXPECT_EQ(450.0, NSWidth([view frame]));
- EXPECT_FALSE([view isHidden]);
- [bar_ shrinkOrHideView:view forMaxX:40.0];
- EXPECT_EQ(40.0, NSWidth([view frame]));
- EXPECT_FALSE([view isHidden]);
- [bar_ shrinkOrHideView:view forMaxX:31.0];
- EXPECT_EQ(31.0, NSWidth([view frame]));
- EXPECT_FALSE([view isHidden]);
- [bar_ shrinkOrHideView:view forMaxX:29.0];
- EXPECT_TRUE([view isHidden]);
-}
-
-class BookmarkBarControllerOpenAllTest : public BookmarkBarControllerTest {
-public:
- BookmarkBarControllerOpenAllTest() {
- resizeDelegate_.reset([[ViewResizerPong alloc] init]);
- NSRect parent_frame = NSMakeRect(0, 0, 800, 50);
- bar_.reset(
- [[BookmarkBarControllerOpenAllPong alloc]
- initWithBrowser:helper_.browser()
- initialWidth:NSWidth(parent_frame)
- delegate:nil
- resizeDelegate:resizeDelegate_.get()]);
- [bar_ view];
- // Awkwardness to look like we've been installed.
- [parent_view_ addSubview:[bar_ view]];
- NSRect frame = [[[bar_ view] superview] frame];
- frame.origin.y = 100;
- [[[bar_ view] superview] setFrame:frame];
-
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- parent_ = model->GetBookmarkBarNode();
- // { one, { two-one, two-two }, three }
- model->AddURL(parent_, parent_->GetChildCount(), ASCIIToUTF16("title"),
- GURL("http://one.com"));
- folder_ = model->AddGroup(parent_, parent_->GetChildCount(),
- ASCIIToUTF16("group"));
- model->AddURL(folder_, folder_->GetChildCount(),
- ASCIIToUTF16("title"), GURL("http://two-one.com"));
- model->AddURL(folder_, folder_->GetChildCount(),
- ASCIIToUTF16("title"), GURL("http://two-two.com"));
- model->AddURL(parent_, parent_->GetChildCount(),
- ASCIIToUTF16("title"), GURL("https://three.com"));
- }
- const BookmarkNode* parent_; // Weak
- const BookmarkNode* folder_; // Weak
-};
-
-TEST_F(BookmarkBarControllerOpenAllTest, OpenAllBookmarks) {
- // Our first OpenAll... is from the bar itself.
- [bar_ openAllBookmarks:ItemForBookmarkBarMenu(parent_)];
- BookmarkBarControllerOpenAllPong* specialBar =
- (BookmarkBarControllerOpenAllPong*)bar_.get();
- EXPECT_EQ([specialBar dispositionDetected], NEW_FOREGROUND_TAB);
-
- // Now try an OpenAll... from a folder node.
- [specialBar setDispositionDetected:IGNORE_ACTION]; // Reset
- [bar_ openAllBookmarks:ItemForBookmarkBarMenu(folder_)];
- EXPECT_EQ([specialBar dispositionDetected], NEW_FOREGROUND_TAB);
-}
-
-TEST_F(BookmarkBarControllerOpenAllTest, OpenAllNewWindow) {
- // Our first OpenAll... is from the bar itself.
- [bar_ openAllBookmarksNewWindow:ItemForBookmarkBarMenu(parent_)];
- BookmarkBarControllerOpenAllPong* specialBar =
- (BookmarkBarControllerOpenAllPong*)bar_.get();
- EXPECT_EQ([specialBar dispositionDetected], NEW_WINDOW);
-
- // Now try an OpenAll... from a folder node.
- [specialBar setDispositionDetected:IGNORE_ACTION]; // Reset
- [bar_ openAllBookmarksNewWindow:ItemForBookmarkBarMenu(folder_)];
- EXPECT_EQ([specialBar dispositionDetected], NEW_WINDOW);
-}
-
-TEST_F(BookmarkBarControllerOpenAllTest, OpenAllIncognito) {
- // Our first OpenAll... is from the bar itself.
- [bar_ openAllBookmarksIncognitoWindow:ItemForBookmarkBarMenu(parent_)];
- BookmarkBarControllerOpenAllPong* specialBar =
- (BookmarkBarControllerOpenAllPong*)bar_.get();
- EXPECT_EQ([specialBar dispositionDetected], OFF_THE_RECORD);
-
- // Now try an OpenAll... from a folder node.
- [specialBar setDispositionDetected:IGNORE_ACTION]; // Reset
- [bar_ openAllBookmarksIncognitoWindow:ItemForBookmarkBarMenu(folder_)];
- EXPECT_EQ([specialBar dispositionDetected], OFF_THE_RECORD);
-}
-
-// Command-click on a folder should open all the bookmarks in it.
-TEST_F(BookmarkBarControllerOpenAllTest, CommandClickOnFolder) {
- NSButton* first = [[bar_ buttons] objectAtIndex:0];
- EXPECT_TRUE(first);
-
- // Create the right kind of event; mock NSApp so [NSApp
- // currentEvent] finds it.
- NSEvent* commandClick = test_event_utils::MouseEventAtPoint(NSZeroPoint,
- NSLeftMouseDown,
- NSCommandKeyMask);
- id fakeApp = [OCMockObject partialMockForObject:NSApp];
- [[[fakeApp stub] andReturn:commandClick] currentEvent];
- id oldApp = NSApp;
- NSApp = fakeApp;
- size_t originalDispositionCount = noOpenBar()->dispositions_.size();
-
- // Click!
- [first performClick:first];
-
- size_t dispositionCount = noOpenBar()->dispositions_.size();
- EXPECT_EQ(originalDispositionCount+1, dispositionCount);
- EXPECT_EQ(noOpenBar()->dispositions_[dispositionCount-1], NEW_BACKGROUND_TAB);
-
- // Replace NSApp
- NSApp = oldApp;
-}
-
-class BookmarkBarControllerNotificationTest : public CocoaTest {
- public:
- BookmarkBarControllerNotificationTest() {
- resizeDelegate_.reset([[ViewResizerPong alloc] init]);
- NSRect parent_frame = NSMakeRect(0, 0, 800, 50);
- parent_view_.reset([[NSView alloc] initWithFrame:parent_frame]);
- [parent_view_ setHidden:YES];
- bar_.reset(
- [[BookmarkBarControllerNotificationPong alloc]
- initWithBrowser:helper_.browser()
- initialWidth:NSWidth(parent_frame)
- delegate:nil
- resizeDelegate:resizeDelegate_.get()]);
-
- // Force loading of the nib.
- [bar_ view];
- // Awkwardness to look like we've been installed.
- [parent_view_ addSubview:[bar_ view]];
- NSRect frame = [[[bar_ view] superview] frame];
- frame.origin.y = 100;
- [[[bar_ view] superview] setFrame:frame];
-
- // Do not add the bar to a window, yet.
- }
-
- BrowserTestHelper helper_;
- scoped_nsobject<NSView> parent_view_;
- scoped_nsobject<ViewResizerPong> resizeDelegate_;
- scoped_nsobject<BookmarkBarControllerNotificationPong> bar_;
-};
-
-TEST_F(BookmarkBarControllerNotificationTest, DeregistersForNotifications) {
- NSWindow* window = [[CocoaTestHelperWindow alloc] init];
- [window setReleasedWhenClosed:YES];
-
- // First add the bookmark bar to the temp window, then to another window.
- [[window contentView] addSubview:parent_view_];
- [[test_window() contentView] addSubview:parent_view_];
-
- // Post a fake windowDidResignKey notification for the temp window and make
- // sure the bookmark bar controller wasn't listening.
- [[NSNotificationCenter defaultCenter]
- postNotificationName:NSWindowDidResignKeyNotification
- object:window];
- EXPECT_FALSE([bar_ windowDidResignKeyReceived]);
-
- // Close the temp window and make sure no notification was received.
- [window close];
- EXPECT_FALSE([bar_ windowWillCloseReceived]);
-}
-
-
-// TODO(jrg): draggingEntered: and draggingExited: trigger timers so
-// they are hard to test. Factor out "fire timers" into routines
-// which can be overridden to fire immediately to make behavior
-// confirmable.
-
-// TODO(jrg): add unit test to make sure "Other Bookmarks" responds
-// properly to a hover open.
-
-// TODO(viettrungluu): figure out how to test animations.
-
-class BookmarkBarControllerDragDropTest : public BookmarkBarControllerTestBase {
- public:
- scoped_nsobject<BookmarkBarControllerDragData> bar_;
-
- BookmarkBarControllerDragDropTest() {
- bar_.reset(
- [[BookmarkBarControllerDragData alloc]
- initWithBrowser:helper_.browser()
- initialWidth:NSWidth([parent_view_ frame])
- delegate:nil
- resizeDelegate:resizeDelegate_.get()]);
- InstallAndToggleBar(bar_.get());
- }
-};
-
-TEST_F(BookmarkBarControllerDragDropTest, DragMoveBarBookmarkToOffTheSide) {
- BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
- const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::string model_string("1bWithLongName 2fWithLongName:[ "
- "2f1bWithLongName 2f2fWithLongName:[ 2f2f1bWithLongName "
- "2f2f2bWithLongName 2f2f3bWithLongName 2f4b ] 2f3bWithLongName ] "
- "3bWithLongName 4bWithLongName 5bWithLongName 6bWithLongName "
- "7bWithLongName 8bWithLongName 9bWithLongName 10bWithLongName "
- "11bWithLongName 12bWithLongName 13b ");
- model_test_utils::AddNodesFromModelString(model, root, model_string);
-
- // Validate initial model.
- std::string actualModelString = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(model_string, actualModelString);
-
- // Insure that the off-the-side is not showing.
- ASSERT_FALSE([bar_ offTheSideButtonIsHidden]);
-
- // Remember how many buttons are showing and are available.
- int oldDisplayedButtons = [bar_ displayedButtonCount];
- int oldChildCount = root->GetChildCount();
-
- // Pop up the off-the-side menu.
- BookmarkButton* otsButton = (BookmarkButton*)[bar_ offTheSideButton];
- ASSERT_TRUE(otsButton);
- [[otsButton target] performSelector:@selector(openOffTheSideFolderFromButton:)
- withObject:otsButton];
- BookmarkBarFolderController* otsController = [bar_ folderController];
- EXPECT_TRUE(otsController);
- NSWindow* toWindow = [otsController window];
- EXPECT_TRUE(toWindow);
- BookmarkButton* draggedButton =
- [bar_ buttonWithTitleEqualTo:@"3bWithLongName"];
- ASSERT_TRUE(draggedButton);
- int oldOTSCount = (int)[[otsController buttons] count];
- EXPECT_EQ(oldOTSCount, oldChildCount - oldDisplayedButtons);
- BookmarkButton* targetButton = [[otsController buttons] objectAtIndex:0];
- ASSERT_TRUE(targetButton);
- [otsController dragButton:draggedButton
- to:[targetButton center]
- copy:YES];
- // There should still be the same number of buttons in the bar
- // and off-the-side should have one more.
- int newDisplayedButtons = [bar_ displayedButtonCount];
- int newChildCount = root->GetChildCount();
- int newOTSCount = (int)[[otsController buttons] count];
- EXPECT_EQ(oldDisplayedButtons, newDisplayedButtons);
- EXPECT_EQ(oldChildCount + 1, newChildCount);
- EXPECT_EQ(oldOTSCount + 1, newOTSCount);
- EXPECT_EQ(newOTSCount, newChildCount - newDisplayedButtons);
-}
-
-TEST_F(BookmarkBarControllerDragDropTest, DragOffTheSideToOther) {
- BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
- const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::string model_string("1bWithLongName 2bWithLongName "
- "3bWithLongName 4bWithLongName 5bWithLongName 6bWithLongName "
- "7bWithLongName 8bWithLongName 9bWithLongName 10bWithLongName "
- "11bWithLongName 12bWithLongName 13bWithLongName 14bWithLongName "
- "15bWithLongName 16bWithLongName 17bWithLongName 18bWithLongName "
- "19bWithLongName 20bWithLongName ");
- model_test_utils::AddNodesFromModelString(model, root, model_string);
-
- const BookmarkNode* other = model.other_node();
- const std::string other_string("1other 2other 3other ");
- model_test_utils::AddNodesFromModelString(model, other, other_string);
-
- // Validate initial model.
- std::string actualModelString = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(model_string, actualModelString);
- std::string actualOtherString = model_test_utils::ModelStringFromNode(other);
- EXPECT_EQ(other_string, actualOtherString);
-
- // Insure that the off-the-side is showing.
- ASSERT_FALSE([bar_ offTheSideButtonIsHidden]);
-
- // Remember how many buttons are showing and are available.
- int oldDisplayedButtons = [bar_ displayedButtonCount];
- int oldRootCount = root->GetChildCount();
- int oldOtherCount = other->GetChildCount();
-
- // Pop up the off-the-side menu.
- BookmarkButton* otsButton = (BookmarkButton*)[bar_ offTheSideButton];
- ASSERT_TRUE(otsButton);
- [[otsButton target] performSelector:@selector(openOffTheSideFolderFromButton:)
- withObject:otsButton];
- BookmarkBarFolderController* otsController = [bar_ folderController];
- EXPECT_TRUE(otsController);
- int oldOTSCount = (int)[[otsController buttons] count];
- EXPECT_EQ(oldOTSCount, oldRootCount - oldDisplayedButtons);
-
- // Pick an off-the-side button and drag it to the other bookmarks.
- BookmarkButton* draggedButton =
- [otsController buttonWithTitleEqualTo:@"20bWithLongName"];
- ASSERT_TRUE(draggedButton);
- BookmarkButton* targetButton = [bar_ otherBookmarksButton];
- ASSERT_TRUE(targetButton);
- [bar_ dragButton:draggedButton to:[targetButton center] copy:NO];
-
- // There should one less button in the bar, one less in off-the-side,
- // and one more in other bookmarks.
- int newRootCount = root->GetChildCount();
- int newOTSCount = (int)[[otsController buttons] count];
- int newOtherCount = other->GetChildCount();
- EXPECT_EQ(oldRootCount - 1, newRootCount);
- EXPECT_EQ(oldOTSCount - 1, newOTSCount);
- EXPECT_EQ(oldOtherCount + 1, newOtherCount);
-}
-
-TEST_F(BookmarkBarControllerDragDropTest, DragBookmarkData) {
- BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
- const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
- "2f3b ] 3b 4b ");
- model_test_utils::AddNodesFromModelString(model, root, model_string);
- const BookmarkNode* other = model.other_node();
- const std::string other_string("O1b O2b O3f:[ O3f1b O3f2f ] "
- "O4f:[ O4f1b O4f2f ] 05b ");
- model_test_utils::AddNodesFromModelString(model, other, other_string);
-
- // Validate initial model.
- std::string actual = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(model_string, actual);
- actual = model_test_utils::ModelStringFromNode(other);
- EXPECT_EQ(other_string, actual);
-
- // Remember the little ones.
- int oldChildCount = root->GetChildCount();
-
- BookmarkButton* targetButton = [bar_ buttonWithTitleEqualTo:@"3b"];
- ASSERT_TRUE(targetButton);
-
- // Gen up some dragging data.
- const BookmarkNode* newNode = other->GetChild(2);
- [bar_ setDragDataNode:newNode];
- scoped_nsobject<FakeDragInfo> dragInfo([[FakeDragInfo alloc] init]);
- [dragInfo setDropLocation:[targetButton center]];
- [bar_ dragBookmarkData:(id<NSDraggingInfo>)dragInfo.get()];
-
- // There should one more button in the bar.
- int newChildCount = root->GetChildCount();
- EXPECT_EQ(oldChildCount + 1, newChildCount);
- // Verify the model.
- const std::string expected("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
- "2f3b ] O3f:[ O3f1b O3f2f ] 3b 4b ");
- actual = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(expected, actual);
- oldChildCount = newChildCount;
-
- // Now do it over a folder button.
- targetButton = [bar_ buttonWithTitleEqualTo:@"2f"];
- ASSERT_TRUE(targetButton);
- NSPoint targetPoint = [targetButton center];
- newNode = other->GetChild(2); // Should be O4f.
- EXPECT_EQ(newNode->GetTitle(), ASCIIToUTF16("O4f"));
- [bar_ setDragDataNode:newNode];
- [dragInfo setDropLocation:targetPoint];
- [bar_ dragBookmarkData:(id<NSDraggingInfo>)dragInfo.get()];
-
- newChildCount = root->GetChildCount();
- EXPECT_EQ(oldChildCount, newChildCount);
- // Verify the model.
- const std::string expected1("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
- "2f3b O4f:[ O4f1b O4f2f ] ] O3f:[ O3f1b O3f2f ] "
- "3b 4b ");
- actual = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(expected1, actual);
-}
-
-TEST_F(BookmarkBarControllerDragDropTest, AddURLs) {
- BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
- const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
- "2f3b ] 3b 4b ");
- model_test_utils::AddNodesFromModelString(model, root, model_string);
-
- // Validate initial model.
- std::string actual = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(model_string, actual);
-
- // Remember the children.
- int oldChildCount = root->GetChildCount();
-
- BookmarkButton* targetButton = [bar_ buttonWithTitleEqualTo:@"3b"];
- ASSERT_TRUE(targetButton);
-
- NSArray* urls = [NSArray arrayWithObjects: @"http://www.a.com/",
- @"http://www.b.com/", nil];
- NSArray* titles = [NSArray arrayWithObjects: @"SiteA", @"SiteB", nil];
- [bar_ addURLs:urls withTitles:titles at:[targetButton center]];
-
- // There should two more nodes in the bar.
- int newChildCount = root->GetChildCount();
- EXPECT_EQ(oldChildCount + 2, newChildCount);
- // Verify the model.
- const std::string expected("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
- "2f3b ] SiteA SiteB 3b 4b ");
- actual = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(expected, actual);
-}
-
-TEST_F(BookmarkBarControllerDragDropTest, ControllerForNode) {
- BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
- const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::string model_string("1b 2f:[ 2f1b 2f2b ] 3b ");
- model_test_utils::AddNodesFromModelString(model, root, model_string);
-
- // Validate initial model.
- std::string actualModelString = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(model_string, actualModelString);
-
- // Find the main bar controller.
- const void* expectedController = bar_;
- const void* actualController = [bar_ controllerForNode:root];
- EXPECT_EQ(expectedController, actualController);
-}
-
-TEST_F(BookmarkBarControllerDragDropTest, DropPositionIndicator) {
- BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
- const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::string model_string("1b 2f:[ 2f1b 2f2b 2f3b ] 3b 4b ");
- model_test_utils::AddNodesFromModelString(model, root, model_string);
-
- // Validate initial model.
- std::string actualModel = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(model_string, actualModel);
-
- // Test a series of points starting at the right edge of the bar.
- BookmarkButton* targetButton = [bar_ buttonWithTitleEqualTo:@"1b"];
- ASSERT_TRUE(targetButton);
- NSPoint targetPoint = [targetButton left];
- const CGFloat xDelta = 0.5 * bookmarks::kBookmarkHorizontalPadding;
- const CGFloat baseOffset = targetPoint.x;
- CGFloat expected = xDelta;
- CGFloat actual = [bar_ indicatorPosForDragToPoint:targetPoint];
- EXPECT_CGFLOAT_EQ(expected, actual);
- targetButton = [bar_ buttonWithTitleEqualTo:@"2f"];
- actual = [bar_ indicatorPosForDragToPoint:[targetButton right]];
- targetButton = [bar_ buttonWithTitleEqualTo:@"3b"];
- expected = [targetButton left].x - baseOffset + xDelta;
- EXPECT_CGFLOAT_EQ(expected, actual);
- targetButton = [bar_ buttonWithTitleEqualTo:@"4b"];
- targetPoint = [targetButton right];
- targetPoint.x += 100; // Somewhere off to the right.
- expected = NSMaxX([targetButton frame]) + xDelta;
- actual = [bar_ indicatorPosForDragToPoint:targetPoint];
- EXPECT_CGFLOAT_EQ(expected, actual);
-}
-
-TEST_F(BookmarkBarControllerDragDropTest, PulseButton) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- const BookmarkNode* root = model->GetBookmarkBarNode();
- GURL gurl("http://www.google.com");
- const BookmarkNode* node = model->AddURL(root, root->GetChildCount(),
- ASCIIToUTF16("title"), gurl);
-
- BookmarkButton* button = [[bar_ buttons] objectAtIndex:0];
- EXPECT_FALSE([button isContinuousPulsing]);
-
- NSValue *value = [NSValue valueWithPointer:node];
- NSDictionary *dict = [NSDictionary
- dictionaryWithObjectsAndKeys:value,
- bookmark_button::kBookmarkKey,
- [NSNumber numberWithBool:YES],
- bookmark_button::kBookmarkPulseFlagKey,
- nil];
- [[NSNotificationCenter defaultCenter]
- postNotificationName:bookmark_button::kPulseBookmarkButtonNotification
- object:nil
- userInfo:dict];
- EXPECT_TRUE([button isContinuousPulsing]);
-
- dict = [NSDictionary dictionaryWithObjectsAndKeys:value,
- bookmark_button::kBookmarkKey,
- [NSNumber numberWithBool:NO],
- bookmark_button::kBookmarkPulseFlagKey,
- nil];
- [[NSNotificationCenter defaultCenter]
- postNotificationName:bookmark_button::kPulseBookmarkButtonNotification
- object:nil
- userInfo:dict];
- EXPECT_FALSE([button isContinuousPulsing]);
-}
-
-TEST_F(BookmarkBarControllerDragDropTest, DragBookmarkDataToTrash) {
- BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
- const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
- "2f3b ] 3b 4b ");
- model_test_utils::AddNodesFromModelString(model, root, model_string);
-
- // Validate initial model.
- std::string actual = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(model_string, actual);
-
- int oldChildCount = root->GetChildCount();
-
- // Drag a button to the trash.
- BookmarkButton* buttonToDelete = [bar_ buttonWithTitleEqualTo:@"3b"];
- ASSERT_TRUE(buttonToDelete);
- EXPECT_TRUE([bar_ canDragBookmarkButtonToTrash:buttonToDelete]);
- [bar_ didDragBookmarkToTrash:buttonToDelete];
-
- // There should be one less button in the bar.
- int newChildCount = root->GetChildCount();
- EXPECT_EQ(oldChildCount - 1, newChildCount);
- // Verify the model.
- const std::string expected("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
- "2f3b ] 4b ");
- actual = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(expected, actual);
-
- // Verify that the other bookmark folder can't be deleted.
- BookmarkButton *otherButton = [bar_ otherBookmarksButton];
- EXPECT_FALSE([bar_ canDragBookmarkButtonToTrash:otherButton]);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_button_cell.h b/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_button_cell.h
deleted file mode 100644
index c8eaf71..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_button_cell.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BAR_FOLDER_BUTTON_CELL_H_
-#define CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BAR_FOLDER_BUTTON_CELL_H_
-#pragma once
-
-#import "chrome/browser/cocoa/bookmarks/bookmark_button_cell.h"
-
-class BookmarkNode;
-
-// A button cell that handles drawing/highlighting of buttons in the
-// bookmark bar. This cell forwards mouseEntered/mouseExited events
-// to its control view so that pseudo-menu operations
-// (e.g. hover-over to open) can be implemented.
-@interface BookmarkBarFolderButtonCell : BookmarkButtonCell {
- @private
- scoped_nsobject<NSColor> frameColor_;
-}
-
-// Create a button cell which draws without a theme and with a frame
-// color provided by the BrowserThemeProvider defaults.
-+ (id)buttonCellForNode:(const BookmarkNode*)node
- contextMenu:(NSMenu*)contextMenu
- cellText:(NSString*)cellText
- cellImage:(NSImage*)cellImage;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BAR_FOLDER_BUTTON_CELL_H_
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_button_cell.mm b/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_button_cell.mm
deleted file mode 100644
index a3a73a3..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_button_cell.mm
+++ /dev/null
@@ -1,22 +0,0 @@
-// 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 "chrome/browser/cocoa/bookmarks/bookmark_bar_folder_button_cell.h"
-
-@implementation BookmarkBarFolderButtonCell
-
-+ (id)buttonCellForNode:(const BookmarkNode*)node
- contextMenu:(NSMenu*)contextMenu
- cellText:(NSString*)cellText
- cellImage:(NSImage*)cellImage {
- id buttonCell =
- [[[BookmarkBarFolderButtonCell alloc] initForNode:node
- contextMenu:contextMenu
- cellText:cellText
- cellImage:cellImage]
- autorelease];
- return buttonCell;
-}
-
-@end
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_button_cell_unittest.mm b/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_button_cell_unittest.mm
deleted file mode 100644
index 0fb8ae3..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_button_cell_unittest.mm
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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.
-
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_folder_button_cell.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-
-namespace {
-
-class BookmarkBarFolderButtonCellTest : public CocoaTest {
-};
-
-// Basic creation.
-TEST_F(BookmarkBarFolderButtonCellTest, Create) {
- scoped_nsobject<BookmarkBarFolderButtonCell> cell;
- cell.reset([[BookmarkBarFolderButtonCell buttonCellForNode:nil
- contextMenu:nil
- cellText:nil
- cellImage:nil] retain]);
- EXPECT_TRUE(cell);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_controller.h b/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_controller.h
deleted file mode 100644
index 1511f11..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_controller.h
+++ /dev/null
@@ -1,182 +0,0 @@
-// 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 "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_button.h"
-
-@class BookmarkBarController;
-@class BookmarkBarFolderView;
-@class BookmarkFolderTarget;
-@class BookmarkBarFolderHoverState;
-
-// A controller for the pop-up windows from bookmark folder buttons
-// which look sort of like menus.
-@interface BookmarkBarFolderController :
- NSWindowController<BookmarkButtonDelegate,
- BookmarkButtonControllerProtocol> {
- @private
- // The button whose click opened us.
- scoped_nsobject<BookmarkButton> parentButton_;
-
- // Bookmark bar folder controller chains are torn down in two ways:
- // 1. Clicking "outside" the folder (see use of
- // CrApplicationEventHookProtocol in the bookmark bar controller).
- // 2. Engaging a different folder (via hover over or explicit click).
- //
- // In either case, the BookmarkButtonControllerProtocol method
- // closeAllBookmarkFolders gets called. For bookmark bar folder
- // controllers, this is passed up the chain so we begin with a top
- // level "close".
- // When any bookmark folder window closes, it necessarily tells
- // subcontroller windows to close (down the chain), and autoreleases
- // the controller. (Must autorelease since the controller can still
- // get delegate events such as windowDidClose).
- //
- // Bookmark bar folder controllers own their buttons. When doing
- // drag and drop of a button from one sub-sub-folder to a different
- // sub-sub-folder, we need to make sure the button's pointers stay
- // valid until we've dropped (or cancelled). Note that such a drag
- // causes the source sub-sub-folder (previous parent window) to go
- // away (windows close, controllers autoreleased) since you're
- // hovering over a different folder chain for dropping. To keep
- // things valid (like the button's target, its delegate, the parent
- // cotroller that we have a pointer to below [below], etc), we heep
- // strong pointers to our owning controller, so the entire chain
- // stays owned.
-
- // Our parent controller, if we are a nested folder, otherwise nil.
- // Strong to insure the object lives as long as we need it.
- scoped_nsobject<BookmarkBarFolderController> parentController_;
-
- // The main bar controller from whence we or a parent sprang.
- BookmarkBarController* barController_; // WEAK: It owns us.
-
- // Our buttons. We do not have buttons for nested folders.
- scoped_nsobject<NSMutableArray> buttons_;
-
- // The scroll view that contains our main button view (below).
- IBOutlet NSScrollView* scrollView_;
-
- // Are we scrollable? If no, the full contents of the folder are
- // always visible.
- BOOL scrollable_;
-
- BOOL scrollUpArrowShown_;
- BOOL scrollDownArrowShown_;
-
- // YES if subfolders should grow to the right (the default).
- // Direction switches if we'd grow off the screen.
- BOOL subFolderGrowthToRight_;
-
- // The main view of this window (where the buttons go).
- IBOutlet BookmarkBarFolderView* mainView_;
-
- // Weak; we keep track to work around a
- // setShowsBorderOnlyWhileMouseInside bug.
- BookmarkButton* buttonThatMouseIsIn_;
-
- // The context menu for a bookmark button which represents an URL.
- IBOutlet NSMenu* buttonMenu_;
-
- // The context menu for a bookmark button which represents a folder.
- IBOutlet NSMenu* folderMenu_;
-
- // We model hover state as a state machine with specific allowable
- // transitions. |hoverState_| is the state of this machine at any
- // given time.
- scoped_nsobject<BookmarkBarFolderHoverState> hoverState_;
-
- // Logic for dealing with a click on a bookmark folder button.
- scoped_nsobject<BookmarkFolderTarget> folderTarget_;
-
- // A controller for a pop-up bookmark folder window (custom menu).
- // We (self) are the parentController_ for our folderController_.
- // This is not a scoped_nsobject because it owns itself (when its
- // window closes the controller gets autoreleased).
- BookmarkBarFolderController* folderController_;
-
- // Implement basic menu scrolling through this tracking area.
- scoped_nsobject<NSTrackingArea> scrollTrackingArea_;
-
- // Timer to continue scrolling as needed. We own the timer but
- // don't release it when done (we invalidate it).
- NSTimer* scrollTimer_;
-
- // Amount to scroll by on each timer fire. Can be + or -.
- CGFloat verticalScrollDelta_;
-
- // We need to know the size of the vertical scrolling arrows so we
- // can obscure/unobscure them.
- CGFloat verticalScrollArrowHeight_;
-
- // Set to YES to prevent any node animations. Useful for unit testing so that
- // incomplete animations do not cause valgrind complaints.
- BOOL ignoreAnimations_;
-}
-
-// Designated initializer.
-- (id)initWithParentButton:(BookmarkButton*)button
- parentController:(BookmarkBarFolderController*)parentController
- barController:(BookmarkBarController*)barController;
-
-// Return the parent button that owns the bookmark folder we represent.
-- (BookmarkButton*)parentButton;
-
-// Offset our folder menu window. This is usually needed in response to a
-// parent folder menu window or the bookmark bar changing position due to
-// the dragging of a bookmark node from the parent into this folder menu.
-- (void)offsetFolderMenuWindow:(NSSize)offset;
-
-// Re-layout the window menu in case some buttons were added or removed,
-// specifically as a result of the bookmark bar changing configuration
-// and altering the contents of the off-the-side folder.
-- (void)reconfigureMenu;
-
-// Actions from a context menu over a button or folder.
-- (IBAction)cutBookmark:(id)sender;
-- (IBAction)copyBookmark:(id)sender;
-- (IBAction)pasteBookmark:(id)sender;
-- (IBAction)deleteBookmark:(id)sender;
-
-// Passed up by a child view to tell us of a desire to scroll.
-- (void)scrollWheel:(NSEvent *)theEvent;
-
-// Forwarded to the associated BookmarkBarController.
-- (IBAction)addFolder:(id)sender;
-- (IBAction)addPage:(id)sender;
-- (IBAction)editBookmark:(id)sender;
-- (IBAction)openBookmark:(id)sender;
-- (IBAction)openAllBookmarks:(id)sender;
-- (IBAction)openAllBookmarksIncognitoWindow:(id)sender;
-- (IBAction)openAllBookmarksNewWindow:(id)sender;
-- (IBAction)openBookmarkInIncognitoWindow:(id)sender;
-- (IBAction)openBookmarkInNewForegroundTab:(id)sender;
-- (IBAction)openBookmarkInNewWindow:(id)sender;
-
-@property (assign, nonatomic) BOOL subFolderGrowthToRight;
-
-@end
-
-@interface BookmarkBarFolderController(TestingAPI)
-- (NSView*)mainView;
-- (NSPoint)windowTopLeftForWidth:(int)windowWidth;
-- (NSArray*)buttons;
-- (BookmarkBarFolderController*)folderController;
-- (id)folderTarget;
-- (void)configureWindowLevel;
-- (void)performOneScroll:(CGFloat)delta;
-- (BookmarkButton*)buttonThatMouseIsIn;
-// Set to YES in order to prevent animations.
-- (void)setIgnoreAnimations:(BOOL)ignore;
-
-// Return YES if we can scroll up or down.
-- (BOOL)canScrollUp;
-- (BOOL)canScrollDown;
-// Return YES if the scrollable_ flag has been set.
-- (BOOL)scrollable;
-
-- (BookmarkButton*)buttonForDroppingOnAtPoint:(NSPoint)point;
-@end
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_controller.mm b/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_controller.mm
deleted file mode 100644
index 55fa2d0..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_controller.mm
+++ /dev/null
@@ -1,1459 +0,0 @@
-// 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 "chrome/browser/cocoa/bookmarks/bookmark_bar_folder_controller.h"
-
-#include "base/mac_util.h"
-#include "base/nsimage_cache_mac.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#include "chrome/browser/bookmarks/bookmark_utils.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_constants.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_controller.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_folder_button_cell.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_folder_hover_state.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_folder_view.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_folder_target.h"
-#import "chrome/browser/cocoa/browser_window_controller.h"
-#import "chrome/browser/cocoa/event_utils.h"
-#import "chrome/browser/themes/browser_theme_provider.h"
-
-namespace {
-
-// Frequency of the scrolling timer in seconds.
-const NSTimeInterval kBookmarkBarFolderScrollInterval = 0.1;
-
-// Amount to scroll by per timer fire. We scroll rather slowly; to
-// accomodate we do several at a time.
-const CGFloat kBookmarkBarFolderScrollAmount =
- 3 * bookmarks::kBookmarkButtonVerticalSpan;
-
-// Amount to scroll for each scroll wheel delta.
-const CGFloat kBookmarkBarFolderScrollWheelAmount =
- 1 * bookmarks::kBookmarkButtonVerticalSpan;
-
-// When constraining a scrolling bookmark bar folder window to the
-// screen, shrink the "constrain" by this much vertically. Currently
-// this is 0.0 to avoid a problem with tracking areas leaving the
-// window, but should probably be 8.0 or something.
-// TODO(jrg): http://crbug.com/36225
-const CGFloat kScrollWindowVerticalMargin = 0.0;
-
-} // namespace
-
-@interface BookmarkBarFolderController(Private)
-- (void)configureWindow;
-- (void)addOrUpdateScrollTracking;
-- (void)removeScrollTracking;
-- (void)endScroll;
-- (void)addScrollTimerWithDelta:(CGFloat)delta;
-
-// Determine the best button width (which will be the widest button or the
-// maximum allowable button width, whichever is less) and resize all buttons.
-// Return the new width (so that the window can be adjusted, if necessary).
-- (CGFloat)adjustButtonWidths;
-
-// Returns the total menu height needed to display |buttonCount| buttons.
-// Does not do any fancy tricks like trimming the height to fit on the screen.
-- (int)windowHeightForButtonCount:(int)buttonCount;
-
-// Adjust the height and horizontal position of the window such that the
-// scroll arrows are shown as needed and the window appears completely
-// on screen.
-- (void)adjustWindowForHeight:(int)windowHeight;
-
-// Show or hide the scroll arrows at the top/bottom of the window.
-- (void)showOrHideScrollArrows;
-
-// |point| is in the base coordinate system of the destination window;
-// it comes from an id<NSDraggingInfo>. |copy| is YES if a copy is to be
-// made and inserted into the new location while leaving the bookmark in
-// the old location, otherwise move the bookmark by removing from its old
-// location and inserting into the new location.
-- (BOOL)dragBookmark:(const BookmarkNode*)sourceNode
- to:(NSPoint)point
- copy:(BOOL)copy;
-
-@end
-
-@interface BookmarkButton (BookmarkBarFolderMenuHighlighting)
-
-// Make the button's border frame always appear when |forceOn| is YES,
-// otherwise only border the button when the mouse is inside the button.
-- (void)forceButtonBorderToStayOnAlways:(BOOL)forceOn;
-
-// On 10.6 event dispatch for an NSButtonCell's
-// showsBorderOnlyWhileMouseInside seems broken if scrolling the
-// view that contains the button. It appears that a mouseExited:
-// gets lost, so the button stays highlit forever. We accomodate
-// here.
-- (void)toggleButtonBorderingWhileMouseInside;
-@end
-
-@implementation BookmarkButton (BookmarkBarFolderMenuHighlighting)
-
-- (void)forceButtonBorderToStayOnAlways:(BOOL)forceOn {
- [self setShowsBorderOnlyWhileMouseInside:!forceOn];
- [self setNeedsDisplay];
-}
-
-- (void)toggleButtonBorderingWhileMouseInside {
- BOOL toggle = [self showsBorderOnlyWhileMouseInside];
- [self setShowsBorderOnlyWhileMouseInside:!toggle];
- [self setShowsBorderOnlyWhileMouseInside:toggle];
-}
-
-@end
-
-@implementation BookmarkBarFolderController
-
-@synthesize subFolderGrowthToRight = subFolderGrowthToRight_;
-
-- (id)initWithParentButton:(BookmarkButton*)button
- parentController:(BookmarkBarFolderController*)parentController
- barController:(BookmarkBarController*)barController {
- NSString* nibPath =
- [mac_util::MainAppBundle() pathForResource:@"BookmarkBarFolderWindow"
- ofType:@"nib"];
- if ((self = [super initWithWindowNibPath:nibPath owner:self])) {
- parentButton_.reset([button retain]);
-
- // We want the button to remain bordered as part of the menu path.
- [button forceButtonBorderToStayOnAlways:YES];
-
- parentController_.reset([parentController retain]);
- if (!parentController_)
- [self setSubFolderGrowthToRight:YES];
- else
- [self setSubFolderGrowthToRight:[parentController
- subFolderGrowthToRight]];
- barController_ = barController; // WEAK
- buttons_.reset([[NSMutableArray alloc] init]);
- folderTarget_.reset([[BookmarkFolderTarget alloc] initWithController:self]);
- NSImage* image = nsimage_cache::ImageNamed(@"menu_overflow_up.pdf");
- DCHECK(image);
- verticalScrollArrowHeight_ = [image size].height;
- [self configureWindow];
- hoverState_.reset([[BookmarkBarFolderHoverState alloc] init]);
- }
- return self;
-}
-
-- (void)dealloc {
- // The button is no longer part of the menu path.
- [parentButton_ forceButtonBorderToStayOnAlways:NO];
- [parentButton_ setNeedsDisplay];
-
- [self removeScrollTracking];
- [self endScroll];
- [hoverState_ draggingExited];
-
- // Delegate pattern does not retain; make sure pointers to us are removed.
- for (BookmarkButton* button in buttons_.get()) {
- [button setDelegate:nil];
- [button setTarget:nil];
- [button setAction:nil];
- }
-
- // Note: we don't need to
- // [NSObject cancelPreviousPerformRequestsWithTarget:self];
- // Because all of our performSelector: calls use withDelay: which
- // retains us.
- [super dealloc];
-}
-
-// Overriden from NSWindowController to call childFolderWillShow: before showing
-// the window.
-- (void)showWindow:(id)sender {
- [barController_ childFolderWillShow:self];
- [super showWindow:sender];
-}
-
-- (BookmarkButton*)parentButton {
- return parentButton_.get();
-}
-
-- (void)offsetFolderMenuWindow:(NSSize)offset {
- NSWindow* window = [self window];
- NSRect windowFrame = [window frame];
- windowFrame.origin.x -= offset.width;
- windowFrame.origin.y += offset.height; // Yes, in the opposite direction!
- [window setFrame:windowFrame display:YES];
- [folderController_ offsetFolderMenuWindow:offset];
-}
-
-- (void)reconfigureMenu {
- [NSObject cancelPreviousPerformRequestsWithTarget:self];
- for (BookmarkButton* button in buttons_.get()) {
- [button setDelegate:nil];
- [button removeFromSuperview];
- }
- [buttons_ removeAllObjects];
- [self configureWindow];
-}
-
-#pragma mark Private Methods
-
-- (BookmarkButtonCell*)cellForBookmarkNode:(const BookmarkNode*)child {
- NSImage* image = child ? [barController_ favIconForNode:child] : nil;
- NSMenu* menu = child ? child->is_folder() ? folderMenu_ : buttonMenu_ : nil;
- BookmarkBarFolderButtonCell* cell =
- [BookmarkBarFolderButtonCell buttonCellForNode:child
- contextMenu:menu
- cellText:nil
- cellImage:image];
- [cell setTag:kStandardButtonTypeWithLimitedClickFeedback];
- return cell;
-}
-
-// Redirect to our logic shared with BookmarkBarController.
-- (IBAction)openBookmarkFolderFromButton:(id)sender {
- [folderTarget_ openBookmarkFolderFromButton:sender];
-}
-
-// Create a bookmark button for the given node using frame.
-//
-// If |node| is NULL this is an "(empty)" button.
-// Does NOT add this button to our button list.
-// Returns an autoreleased button.
-// Adjusts the input frame width as appropriate.
-//
-// TODO(jrg): combine with addNodesToButtonList: code from
-// bookmark_bar_controller.mm, and generalize that to use both x and y
-// offsets.
-// http://crbug.com/35966
-- (BookmarkButton*)makeButtonForNode:(const BookmarkNode*)node
- frame:(NSRect)frame {
- BookmarkButtonCell* cell = [self cellForBookmarkNode:node];
- DCHECK(cell);
-
- // We must decide if we draw the folder arrow before we ask the cell
- // how big it needs to be.
- if (node && node->is_folder()) {
- // Warning when combining code with bookmark_bar_controller.mm:
- // this call should NOT be made for the bar buttons; only for the
- // subfolder buttons.
- [cell setDrawFolderArrow:YES];
- }
-
- // The "+2" is needed because, sometimes, Cocoa is off by a tad when
- // returning the value it thinks it needs.
- CGFloat desired = [cell cellSize].width + 2;
- // The width is determined from the maximum of the proposed width
- // (provided in |frame|) or the natural width of the title, then
- // limited by the abolute minimum and maximum allowable widths.
- frame.size.width =
- std::min(std::max(bookmarks::kBookmarkMenuButtonMinimumWidth,
- std::max(frame.size.width, desired)),
- bookmarks::kBookmarkMenuButtonMaximumWidth);
-
- BookmarkButton* button = [[[BookmarkButton alloc] initWithFrame:frame]
- autorelease];
- DCHECK(button);
-
- [button setCell:cell];
- [button setDelegate:self];
- if (node) {
- if (node->is_folder()) {
- [button setTarget:self];
- [button setAction:@selector(openBookmarkFolderFromButton:)];
- } else {
- // Make the button do something.
- [button setTarget:self];
- [button setAction:@selector(openBookmark:)];
- // Add a tooltip.
- NSString* title = base::SysUTF16ToNSString(node->GetTitle());
- std::string urlString = node->GetURL().possibly_invalid_spec();
- NSString* tooltip = [NSString stringWithFormat:@"%@\n%s", title,
- urlString.c_str()];
- [button setToolTip:tooltip];
- }
- } else {
- [button setEnabled:NO];
- [button setBordered:NO];
- }
- return button;
-}
-
-// Exposed for testing.
-- (NSView*)mainView {
- return mainView_;
-}
-
-- (id)folderTarget {
- return folderTarget_.get();
-}
-
-
-// Our parent controller is another BookmarkBarFolderController, so
-// our window is to the right or left of it. We use a little overlap
-// since it looks much more menu-like than with none. If we would
-// grow off the screen, switch growth to the other direction. Growth
-// direction sticks for folder windows which are descendents of us.
-// If we have tried both directions and neither fits, degrade to a
-// default.
-- (CGFloat)childFolderWindowLeftForWidth:(int)windowWidth {
- // We may legitimately need to try two times (growth to right and
- // left but not in that order). Limit us to three tries in case
- // the folder window can't fit on either side of the screen; we
- // don't want to loop forever.
- CGFloat x;
- int tries = 0;
- while (tries < 2) {
- // Try to grow right.
- if ([self subFolderGrowthToRight]) {
- tries++;
- x = NSMaxX([[parentButton_ window] frame]) -
- bookmarks::kBookmarkMenuOverlap;
- // If off the screen, switch direction.
- if ((x + windowWidth +
- bookmarks::kBookmarkHorizontalScreenPadding) >
- NSMaxX([[[self window] screen] frame])) {
- [self setSubFolderGrowthToRight:NO];
- } else {
- return x;
- }
- }
- // Try to grow left.
- if (![self subFolderGrowthToRight]) {
- tries++;
- x = NSMinX([[parentButton_ window] frame]) +
- bookmarks::kBookmarkMenuOverlap -
- windowWidth;
- // If off the screen, switch direction.
- if (x < NSMinX([[[self window] screen] frame])) {
- [self setSubFolderGrowthToRight:YES];
- } else {
- return x;
- }
- }
- }
- // Unhappy; do the best we can.
- return NSMaxX([[[self window] screen] frame]) - windowWidth;
-}
-
-
-// Compute and return the top left point of our window (screen
-// coordinates). The top left is positioned in a manner similar to
-// cascading menus. Windows may grow to either the right or left of
-// their parent (if a sub-folder) so we need to know |windowWidth|.
-- (NSPoint)windowTopLeftForWidth:(int)windowWidth {
- NSPoint newWindowTopLeft;
- if (![parentController_ isKindOfClass:[self class]]) {
- // If we're not popping up from one of ourselves, we must be
- // popping up from the bookmark bar itself. In this case, start
- // BELOW the parent button. Our left is the button left; our top
- // is bottom of button's parent view.
- NSPoint buttonBottomLeftInScreen =
- [[parentButton_ window]
- convertBaseToScreen:[parentButton_
- convertPoint:NSZeroPoint toView:nil]];
- NSPoint bookmarkBarBottomLeftInScreen =
- [[parentButton_ window]
- convertBaseToScreen:[[parentButton_ superview]
- convertPoint:NSZeroPoint toView:nil]];
- newWindowTopLeft = NSMakePoint(buttonBottomLeftInScreen.x,
- bookmarkBarBottomLeftInScreen.y);
- // Make sure the window is on-screen; if not, push left. It is
- // intentional that top level folders "push left" slightly
- // different than subfolders.
- NSRect screenFrame = [[[parentButton_ window] screen] frame];
- CGFloat spillOff = (newWindowTopLeft.x + windowWidth) - NSMaxX(screenFrame);
- if (spillOff > 0.0) {
- newWindowTopLeft.x = std::max(newWindowTopLeft.x - spillOff,
- NSMinX(screenFrame));
- }
- } else {
- // Parent is a folder; grow right/left.
- newWindowTopLeft.x = [self childFolderWindowLeftForWidth:windowWidth];
- NSPoint top = NSMakePoint(0, (NSMaxY([parentButton_ frame]) +
- bookmarks::kBookmarkVerticalPadding));
- NSPoint topOfWindow =
- [[parentButton_ window]
- convertBaseToScreen:[[parentButton_ superview]
- convertPoint:top toView:nil]];
- newWindowTopLeft.y = topOfWindow.y;
- }
- return newWindowTopLeft;
-}
-
-// Set our window level to the right spot so we're above the menubar, dock, etc.
-// Factored out so we can override/noop in a unit test.
-- (void)configureWindowLevel {
- [[self window] setLevel:NSPopUpMenuWindowLevel];
-}
-
-- (int)windowHeightForButtonCount:(int)buttonCount {
- return (buttonCount * bookmarks::kBookmarkButtonVerticalSpan) +
- bookmarks::kBookmarkVerticalPadding;
-}
-
-- (void)adjustWindowForHeight:(int)windowHeight {
- // Adjust all button widths to be consistent, determine the best size for
- // the window, and set the window frame.
- CGFloat windowWidth =
- [self adjustButtonWidths] +
- (2 * bookmarks::kBookmarkSubMenuHorizontalPadding);
- NSPoint newWindowTopLeft = [self windowTopLeftForWidth:windowWidth];
- NSSize windowSize = NSMakeSize(windowWidth, windowHeight);
- windowSize = [scrollView_ convertSize:windowSize toView:nil];
- NSWindow* window = [self window];
- // If the window is already visible then make sure its top remains stable.
- BOOL windowAlreadyShowing = [window isVisible];
- CGFloat deltaY = windowHeight - NSHeight([mainView_ frame]);
- if (windowAlreadyShowing) {
- NSRect oldFrame = [window frame];
- newWindowTopLeft.y = oldFrame.origin.y + NSHeight(oldFrame);
- }
- NSRect windowFrame = NSMakeRect(newWindowTopLeft.x,
- newWindowTopLeft.y - windowHeight, windowSize.width, windowHeight);
- // Make the scrolled content be the right size (full size).
- NSRect mainViewFrame = NSMakeRect(0, 0, NSWidth(windowFrame) -
- bookmarks::kScrollViewContentWidthMargin, NSHeight(windowFrame));
- [mainView_ setFrame:mainViewFrame];
- // Make sure the window fits on the screen. If not, constrain.
- // We'll scroll to allow the user to see all the content.
- NSRect screenFrame = [[[self window] screen] frame];
- screenFrame = NSInsetRect(screenFrame, 0, kScrollWindowVerticalMargin);
- BOOL wasScrollable = scrollable_;
- if (!NSContainsRect(screenFrame, windowFrame)) {
- scrollable_ = YES;
- windowFrame = NSIntersectionRect(screenFrame, windowFrame);
- } else {
- scrollable_ = NO;
- }
- [window setFrame:windowFrame display:NO];
- if (wasScrollable != scrollable_) {
- // If scrollability changed then rework visibility of the scroll arrows
- // and the scroll offset of the menu view.
- NSSize windowLocalSize =
- [scrollView_ convertSize:windowFrame.size fromView:nil];
- CGFloat scrollPointY = NSHeight(mainViewFrame) - windowLocalSize.height +
- bookmarks::kBookmarkVerticalPadding;
- [mainView_ scrollPoint:NSMakePoint(0, scrollPointY)];
- [self showOrHideScrollArrows];
- [self addOrUpdateScrollTracking];
- } else if (scrollable_ && windowAlreadyShowing) {
- // If the window was already showing and is still scrollable then make
- // sure the main view moves upward, not downward so that the content
- // at the bottom of the menu, not the top, appears to move.
- // The edge case is when the menu is scrolled all the way to top (hence
- // the test of scrollDownArrowShown_) - don't scroll then.
- NSView* superView = [mainView_ superview];
- DCHECK([superView isKindOfClass:[NSClipView class]]);
- NSClipView* clipView = static_cast<NSClipView*>(superView);
- CGFloat scrollPointY = [clipView bounds].origin.y +
- bookmarks::kBookmarkVerticalPadding;
- if (scrollDownArrowShown_ || deltaY > 0.0)
- scrollPointY += deltaY;
- [mainView_ scrollPoint:NSMakePoint(0, scrollPointY)];
- }
- [window display];
-}
-
-// Determine window size and position.
-// Create buttons for all our nodes.
-// TODO(jrg): break up into more and smaller routines for easier unit testing.
-- (void)configureWindow {
- const BookmarkNode* node = [parentButton_ bookmarkNode];
- DCHECK(node);
- int startingIndex = [[parentButton_ cell] startingChildIndex];
- DCHECK_LE(startingIndex, node->GetChildCount());
- // Must have at least 1 button (for "empty")
- int buttons = std::max(node->GetChildCount() - startingIndex, 1);
-
- // Prelim height of the window. We'll trim later as needed.
- int height = [self windowHeightForButtonCount:buttons];
- // We'll need this soon...
- [self window];
-
- // TODO(jrg): combine with frame code in bookmark_bar_controller.mm
- // http://crbug.com/35966
- NSRect buttonsOuterFrame = NSMakeRect(
- bookmarks::kBookmarkSubMenuHorizontalPadding,
- (height - bookmarks::kBookmarkButtonVerticalSpan),
- bookmarks::kDefaultBookmarkWidth,
- bookmarks::kBookmarkButtonHeight);
-
- // TODO(jrg): combine with addNodesToButtonList: code from
- // bookmark_bar_controller.mm (but use y offset)
- // http://crbug.com/35966
- if (!node->GetChildCount()) {
- // If no children we are the empty button.
- BookmarkButton* button = [self makeButtonForNode:nil
- frame:buttonsOuterFrame];
- [buttons_ addObject:button];
- [mainView_ addSubview:button];
- } else {
- for (int i = startingIndex;
- i < node->GetChildCount();
- i++) {
- const BookmarkNode* child = node->GetChild(i);
- BookmarkButton* button = [self makeButtonForNode:child
- frame:buttonsOuterFrame];
- [buttons_ addObject:button];
- [mainView_ addSubview:button];
- buttonsOuterFrame.origin.y -= bookmarks::kBookmarkButtonVerticalSpan;
- }
- }
-
- [self adjustWindowForHeight:height];
- // Finally pop me up.
- [self configureWindowLevel];
-}
-
-// TODO(mrossetti): See if the following can be moved into view's viewWillDraw:.
-- (CGFloat)adjustButtonWidths {
- CGFloat width = bookmarks::kBookmarkMenuButtonMinimumWidth;
- // Use the cell's size as the base for determining the desired width of the
- // button rather than the button's current width. -[cell cellSize] always
- // returns the 'optimum' size of the cell based on the cell's contents even
- // if it's less than the current button size. Relying on the button size
- // would result in buttons that could only get wider but we want to handle
- // the case where the widest button gets removed from a folder menu.
- for (BookmarkButton* button in buttons_.get())
- width = std::max(width, [[button cell] cellSize].width);
- width = std::min(width, bookmarks::kBookmarkMenuButtonMaximumWidth);
- // Things look and feel more menu-like if all the buttons are the
- // full width of the window, especially if there are submenus.
- for (BookmarkButton* button in buttons_.get()) {
- NSRect buttonFrame = [button frame];
- buttonFrame.size.width = width;
- [button setFrame:buttonFrame];
- }
- return width;
-}
-
-- (BOOL)canScrollUp {
- // If removal of an arrow would make things "finished", state as
- // such.
- CGFloat scrollY = [scrollView_ documentVisibleRect].origin.y;
- if (scrollUpArrowShown_)
- scrollY -= verticalScrollArrowHeight_;
-
- if (scrollY <= 0)
- return NO;
- return YES;
-}
-
-- (BOOL)canScrollDown {
- CGFloat arrowAdjustment = 0.0;
-
- // We do NOT adjust based on the scrollDOWN arrow. This keeps
- // things from "jumping"; if removal of the down arrow (at the top
- // of the window) would cause a scroll to end, we'll end.
- if (scrollUpArrowShown_)
- arrowAdjustment += verticalScrollArrowHeight_;
-
- NSPoint scrollPosition = [scrollView_ documentVisibleRect].origin;
- NSRect documentRect = [[scrollView_ documentView] frame];
-
- // If we are exactly the right height, return no. We need this
- // extra conditional in the case where we've just scrolled/grown
- // into position.
- if (NSHeight([[self window] frame]) == NSHeight(documentRect))
- return NO;
-
- if ((scrollPosition.y + NSHeight([[self window] frame])) >=
- (NSHeight(documentRect) + arrowAdjustment)) {
- return NO;
- }
- return YES;
-}
-
-- (void)showOrHideScrollArrows {
- NSRect frame = [scrollView_ frame];
- CGFloat scrollDelta = 0.0;
- BOOL canScrollDown = [self canScrollDown];
- BOOL canScrollUp = [self canScrollUp];
-
- if (canScrollUp != scrollUpArrowShown_) {
- if (scrollUpArrowShown_) {
- frame.origin.y -= verticalScrollArrowHeight_;
- frame.size.height += verticalScrollArrowHeight_;
- scrollDelta = verticalScrollArrowHeight_;
- } else {
- frame.origin.y += verticalScrollArrowHeight_;
- frame.size.height -= verticalScrollArrowHeight_;
- scrollDelta = -verticalScrollArrowHeight_;
- }
- }
- if (canScrollDown != scrollDownArrowShown_) {
- if (scrollDownArrowShown_) {
- frame.size.height += verticalScrollArrowHeight_;
- } else {
- frame.size.height -= verticalScrollArrowHeight_;
- }
- }
- scrollUpArrowShown_ = canScrollUp;
- scrollDownArrowShown_ = canScrollDown;
- [scrollView_ setFrame:frame];
-
- // Adjust scroll based on new frame. For example, if we make room
- // for an arrow at the bottom, adjust the scroll so the topmost item
- // is still fully visible.
- if (scrollDelta) {
- NSPoint scrollPosition = [scrollView_ documentVisibleRect].origin;
- scrollPosition.y -= scrollDelta;
- [[scrollView_ documentView] scrollPoint:scrollPosition];
- }
-}
-
-- (BOOL)scrollable {
- return scrollable_;
-}
-
-// Start a "scroll up" timer.
-- (void)beginScrollWindowUp {
- [self addScrollTimerWithDelta:kBookmarkBarFolderScrollAmount];
-}
-
-// Start a "scroll down" timer.
-- (void)beginScrollWindowDown {
- [self addScrollTimerWithDelta:-kBookmarkBarFolderScrollAmount];
-}
-
-// End a scrolling timer. Can be called excessively with no harm.
-- (void)endScroll {
- if (scrollTimer_) {
- [scrollTimer_ invalidate];
- scrollTimer_ = nil;
- verticalScrollDelta_ = 0;
- }
-}
-
-// Perform a single scroll of the specified amount.
-// Scroll up:
-// Scroll the documentView by the growth amount.
-// If we cannot grow the window, simply scroll the documentView.
-// If we can grow the window up without falling off the screen, do it.
-// Scroll down:
-// Never change the window size; only scroll the documentView.
-- (void)performOneScroll:(CGFloat)delta {
- NSRect windowFrame = [[self window] frame];
- NSRect screenFrame = [[[self window] screen] frame];
-
- // First scroll the "document" area.
- NSPoint scrollPosition = [scrollView_ documentVisibleRect].origin;
- scrollPosition.y -= delta;
- [[scrollView_ documentView] scrollPoint:scrollPosition];
-
- if (buttonThatMouseIsIn_)
- [buttonThatMouseIsIn_ toggleButtonBorderingWhileMouseInside];
-
- // We update the window size after shifting the scroll to avoid a race.
- CGFloat screenHeightMinusMargin = (NSHeight(screenFrame) -
- (2 * kScrollWindowVerticalMargin));
- if (delta) {
- // If we can, grow the window (up).
- if (NSHeight(windowFrame) < screenHeightMinusMargin) {
- CGFloat growAmount = delta;
- // Don't scroll more than enough to "finish".
- if (scrollPosition.y < 0)
- growAmount += scrollPosition.y;
- windowFrame.size.height += growAmount;
- windowFrame.size.height = std::min(NSHeight(windowFrame),
- screenHeightMinusMargin);
- // Watch out for a finish that isn't the full height of the screen.
- // We get here if using the scroll wheel to scroll by small amounts.
- windowFrame.size.height = std::min(NSHeight(windowFrame),
- NSHeight([mainView_ frame]));
- // Don't allow scrolling to make the window smaller, ever. This
- // conditional is important when processing scrollWheel events.
- if (windowFrame.size.height > [[self window] frame].size.height) {
- [[self window] setFrame:windowFrame display:YES];
- [self addOrUpdateScrollTracking];
- }
- }
- }
-
- // If we're at either end, happiness.
- if ((scrollPosition.y <= 0) ||
- ((scrollPosition.y + NSHeight(windowFrame) >=
- NSHeight([mainView_ frame])) &&
- (windowFrame.size.height == screenHeightMinusMargin))) {
- [self endScroll];
-
- // If we can't scroll either up or down we are completely done.
- // For example, perhaps we've scrolled a little and grown the
- // window on-screen until there is now room for everything.
- if (![self canScrollUp] && ![self canScrollDown]) {
- scrollable_ = NO;
- [self removeScrollTracking];
- }
- }
-
- [self showOrHideScrollArrows];
-}
-
-// Perform a scroll of the window on the screen.
-// Called by a timer when scrolling.
-- (void)performScroll:(NSTimer*)timer {
- DCHECK(verticalScrollDelta_);
- [self performOneScroll:verticalScrollDelta_];
-}
-
-
-// Add a timer to fire at a regular interveral which scrolls the
-// window vertically |delta|.
-- (void)addScrollTimerWithDelta:(CGFloat)delta {
- if (scrollTimer_ && verticalScrollDelta_ == delta)
- return;
- [self endScroll];
- verticalScrollDelta_ = delta;
- scrollTimer_ =
- [NSTimer scheduledTimerWithTimeInterval:kBookmarkBarFolderScrollInterval
- target:self
- selector:@selector(performScroll:)
- userInfo:nil
- repeats:YES];
-}
-
-// Called as a result of our tracking area. Warning: on the main
-// screen (of a single-screened machine), the minimum mouse y value is
-// 1, not 0. Also, we do not get events when the mouse is above the
-// menubar (to be fixed by setting the proper window level; see
-// initializer).
-- (void)mouseMoved:(NSEvent*)theEvent {
- DCHECK([theEvent window] == [self window]);
-
- NSPoint eventScreenLocation =
- [[theEvent window] convertBaseToScreen:[theEvent locationInWindow]];
-
- // We use frame (not visibleFrame) since our bookmark folder is on
- // TOP of the menubar.
- NSRect visibleRect = [[[self window] screen] frame];
- CGFloat closeToTopOfScreen = NSMaxY(visibleRect) -
- verticalScrollArrowHeight_;
- CGFloat closeToBottomOfScreen = NSMinY(visibleRect) +
- verticalScrollArrowHeight_;
-
- if (eventScreenLocation.y <= closeToBottomOfScreen) {
- [self beginScrollWindowUp];
- } else if (eventScreenLocation.y > closeToTopOfScreen) {
- [self beginScrollWindowDown];
- } else {
- [self endScroll];
- }
-}
-
-- (void)mouseExited:(NSEvent*)theEvent {
- [self endScroll];
-}
-
-// Add a tracking area so we know when the mouse is pinned to the top
-// or bottom of the screen. If that happens, and if the mouse
-// position overlaps the window, scroll it.
-- (void)addOrUpdateScrollTracking {
- [self removeScrollTracking];
- NSView* view = [[self window] contentView];
- scrollTrackingArea_.reset([[NSTrackingArea alloc]
- initWithRect:[view bounds]
- options:(NSTrackingMouseMoved |
- NSTrackingMouseEnteredAndExited |
- NSTrackingActiveAlways)
- owner:self
- userInfo:nil]);
- [view addTrackingArea:scrollTrackingArea_];
-}
-
-// Remove the tracking area associated with scrolling.
-- (void)removeScrollTracking {
- if (scrollTrackingArea_.get()) {
- [[[self window] contentView] removeTrackingArea:scrollTrackingArea_];
- }
- scrollTrackingArea_.reset();
-}
-
-// Delegate callback.
-- (void)windowWillClose:(NSNotification*)notification {
- // If a "hover open" is pending when the bookmark bar folder is
- // closed, be sure it gets cancelled.
- [NSObject cancelPreviousPerformRequestsWithTarget:self];
-
- [barController_ childFolderWillClose:self];
- [self closeBookmarkFolder:self];
- [self autorelease];
-}
-
-// Close the old hover-open bookmark folder, and open a new one. We
-// do both in one step to allow for a delay in closing the old one.
-// See comments above kDragHoverCloseDelay (bookmark_bar_controller.h)
-// for more details.
-- (void)openBookmarkFolderFromButtonAndCloseOldOne:(id)sender {
- // If an old submenu exists, close it immediately.
- [self closeBookmarkFolder:sender];
-
- // Open a new one if meaningful.
- if ([sender isFolder])
- [folderTarget_ openBookmarkFolderFromButton:sender];
-}
-
-- (NSArray*)buttons {
- return buttons_.get();
-}
-
-- (void)close {
- [folderController_ close];
- [super close];
-}
-
-- (void)scrollWheel:(NSEvent *)theEvent {
- if (scrollable_) {
- // We go negative since an NSScrollView has a flipped coordinate frame.
- CGFloat amt = kBookmarkBarFolderScrollWheelAmount * -[theEvent deltaY];
- [self performOneScroll:amt];
- }
-}
-
-#pragma mark Actions Forwarded to Parent BookmarkBarController
-
-- (IBAction)openBookmark:(id)sender {
- [barController_ openBookmark:sender];
-}
-
-- (IBAction)openBookmarkInNewForegroundTab:(id)sender {
- [barController_ openBookmarkInNewForegroundTab:sender];
-}
-
-- (IBAction)openBookmarkInNewWindow:(id)sender {
- [barController_ openBookmarkInNewWindow:sender];
-}
-
-- (IBAction)openBookmarkInIncognitoWindow:(id)sender {
- [barController_ openBookmarkInIncognitoWindow:sender];
-}
-
-- (IBAction)editBookmark:(id)sender {
- [barController_ editBookmark:sender];
-}
-
-- (IBAction)cutBookmark:(id)sender {
- [self closeBookmarkFolder:self];
- [barController_ cutBookmark:sender];
-}
-
-- (IBAction)copyBookmark:(id)sender {
- [barController_ copyBookmark:sender];
-}
-
-- (IBAction)pasteBookmark:(id)sender {
- [barController_ pasteBookmark:sender];
-}
-
-- (IBAction)deleteBookmark:(id)sender {
- [self closeBookmarkFolder:self];
- [barController_ deleteBookmark:sender];
-}
-
-- (IBAction)openAllBookmarks:(id)sender {
- [barController_ openAllBookmarks:sender];
-}
-
-- (IBAction)openAllBookmarksNewWindow:(id)sender {
- [barController_ openAllBookmarksNewWindow:sender];
-}
-
-- (IBAction)openAllBookmarksIncognitoWindow:(id)sender {
- [barController_ openAllBookmarksIncognitoWindow:sender];
-}
-
-- (IBAction)addPage:(id)sender {
- [barController_ addPage:sender];
-}
-
-- (IBAction)addFolder:(id)sender {
- [barController_ addFolder:sender];
-}
-
-#pragma mark Drag & Drop
-
-// Find something like std::is_between<T>? I can't believe one doesn't exist.
-// http://crbug.com/35966
-static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) {
- return ((value >= low) && (value <= high));
-}
-
-// Return the proposed drop target for a hover open button, or nil if none.
-//
-// TODO(jrg): this is just like the version in
-// bookmark_bar_controller.mm, but vertical instead of horizontal.
-// Generalize to be axis independent then share code.
-// http://crbug.com/35966
-- (BookmarkButton*)buttonForDroppingOnAtPoint:(NSPoint)point {
- for (BookmarkButton* button in buttons_.get()) {
- // No early break -- makes no assumption about button ordering.
-
- // Intentionally NOT using NSPointInRect() so that scrolling into
- // a submenu doesn't cause it to be closed.
- if (ValueInRangeInclusive(NSMinY([button frame]),
- point.y,
- NSMaxY([button frame]))) {
-
- // Over a button but let's be a little more specific
- // (e.g. over the middle half).
- NSRect frame = [button frame];
- NSRect middleHalfOfButton = NSInsetRect(frame, 0, frame.size.height / 4);
- if (ValueInRangeInclusive(NSMinY(middleHalfOfButton),
- point.y,
- NSMaxY(middleHalfOfButton))) {
- // It makes no sense to drop on a non-folder; there is no hover.
- if (![button isFolder])
- return nil;
- // Got it!
- return button;
- } else {
- // Over a button but not over the middle half.
- return nil;
- }
- }
- }
- // Not hovering over a button.
- return nil;
-}
-
-// TODO(jrg): again we have code dup, sort of, with
-// bookmark_bar_controller.mm, but the axis is changed. One minor
-// difference is accomodation for the "empty" button (which may not
-// exist in the future).
-// http://crbug.com/35966
-- (int)indexForDragToPoint:(NSPoint)point {
- // Identify which buttons we are between. For now, assume a button
- // location is at the center point of its view, and that an exact
- // match means "place before".
- // TODO(jrg): revisit position info based on UI team feedback.
- // dropLocation is in bar local coordinates.
- // http://crbug.com/36276
- NSPoint dropLocation =
- [mainView_ convertPoint:point
- fromView:[[self window] contentView]];
- BookmarkButton* buttonToTheTopOfDraggedButton = nil;
- // Buttons are laid out in this array from top to bottom (screen
- // wise), which means "biggest y" --> "smallest y".
- for (BookmarkButton* button in buttons_.get()) {
- CGFloat midpoint = NSMidY([button frame]);
- if (dropLocation.y > midpoint) {
- break;
- }
- buttonToTheTopOfDraggedButton = button;
- }
-
- // TODO(jrg): On Windows, dropping onto (empty) highlights the
- // entire drop location and does not use an insertion point.
- // http://crbug.com/35967
- if (!buttonToTheTopOfDraggedButton) {
- // We are at the very top (we broke out of the loop on the first try).
- return 0;
- }
- if ([buttonToTheTopOfDraggedButton isEmpty]) {
- // There is a button but it's an empty placeholder.
- // Default to inserting on top of it.
- return 0;
- }
- const BookmarkNode* beforeNode = [buttonToTheTopOfDraggedButton
- bookmarkNode];
- DCHECK(beforeNode);
- // Be careful if the number of buttons != number of nodes.
- return ((beforeNode->GetParent()->IndexOfChild(beforeNode) + 1) -
- [[parentButton_ cell] startingChildIndex]);
-}
-
-// TODO(jrg): Yet more code dup.
-// http://crbug.com/35966
-- (BOOL)dragBookmark:(const BookmarkNode*)sourceNode
- to:(NSPoint)point
- copy:(BOOL)copy {
- DCHECK(sourceNode);
-
- // Drop destination.
- const BookmarkNode* destParent = NULL;
- int destIndex = 0;
-
- // First check if we're dropping on a button. If we have one, and
- // it's a folder, drop in it.
- BookmarkButton* button = [self buttonForDroppingOnAtPoint:point];
- if ([button isFolder]) {
- destParent = [button bookmarkNode];
- // Drop it at the end.
- destIndex = [button bookmarkNode]->GetChildCount();
- } else {
- // Else we're dropping somewhere in the folder, so find the right spot.
- destParent = [parentButton_ bookmarkNode];
- destIndex = [self indexForDragToPoint:point];
- // Be careful if the number of buttons != number of nodes.
- destIndex += [[parentButton_ cell] startingChildIndex];
- }
-
- // Prevent cycles.
- BOOL wasCopiedOrMoved = NO;
- if (!destParent->HasAncestor(sourceNode)) {
- if (copy)
- [self bookmarkModel]->Copy(sourceNode, destParent, destIndex);
- else
- [self bookmarkModel]->Move(sourceNode, destParent, destIndex);
- wasCopiedOrMoved = YES;
- // Movement of a node triggers observers (like us) to rebuild the
- // bar so we don't have to do so explicitly.
- }
-
- return wasCopiedOrMoved;
-}
-
-#pragma mark BookmarkButtonDelegate Protocol
-
-- (void)fillPasteboard:(NSPasteboard*)pboard
- forDragOfButton:(BookmarkButton*)button {
- [[self folderTarget] fillPasteboard:pboard forDragOfButton:button];
-
- // Close our folder menu and submenus since we know we're going to be dragged.
- [self closeBookmarkFolder:self];
-}
-
-// Called from BookmarkButton.
-// Unlike bookmark_bar_controller's version, we DO default to being enabled.
-- (void)mouseEnteredButton:(id)sender event:(NSEvent*)event {
- buttonThatMouseIsIn_ = sender;
-
- // Cancel a previous hover if needed.
- [NSObject cancelPreviousPerformRequestsWithTarget:self];
-
- // If already opened, then we exited but re-entered the button
- // (without entering another button open), do nothing.
- if ([folderController_ parentButton] == sender)
- return;
-
- [self performSelector:@selector(openBookmarkFolderFromButtonAndCloseOldOne:)
- withObject:sender
- afterDelay:bookmarks::kHoverOpenDelay];
-}
-
-// Called from the BookmarkButton
-- (void)mouseExitedButton:(id)sender event:(NSEvent*)event {
- if (buttonThatMouseIsIn_ == sender)
- buttonThatMouseIsIn_ = nil;
-
- // Stop any timer about opening a new hover-open folder.
-
- // Since a performSelector:withDelay: on self retains self, it is
- // possible that a cancelPreviousPerformRequestsWithTarget: reduces
- // the refcount to 0, releasing us. That's a bad thing to do while
- // this object (or others it may own) is in the event chain. Thus
- // we have a retain/autorelease.
- [self retain];
- [NSObject cancelPreviousPerformRequestsWithTarget:self];
- [self autorelease];
-}
-
-- (NSWindow*)browserWindow {
- return [parentController_ browserWindow];
-}
-
-- (BOOL)canDragBookmarkButtonToTrash:(BookmarkButton*)button {
- return [barController_ canEditBookmark:[button bookmarkNode]];
-}
-
-- (void)didDragBookmarkToTrash:(BookmarkButton*)button {
- // TODO(mrossetti): Refactor BookmarkBarFolder common code.
- // http://crbug.com/35966
- const BookmarkNode* node = [button bookmarkNode];
- if (node) {
- const BookmarkNode* parent = node->GetParent();
- [self bookmarkModel]->Remove(parent,
- parent->IndexOfChild(node));
- }
-}
-
-#pragma mark BookmarkButtonControllerProtocol
-
-// Recursively close all bookmark folders.
-- (void)closeAllBookmarkFolders {
- // Closing the top level implicitly closes all children.
- [barController_ closeAllBookmarkFolders];
-}
-
-// Close our bookmark folder (a sub-controller) if we have one.
-- (void)closeBookmarkFolder:(id)sender {
- if (folderController_) {
- [self setSubFolderGrowthToRight:YES];
- [[folderController_ window] close];
- folderController_ = nil;
- }
-}
-
-- (BookmarkModel*)bookmarkModel {
- return [barController_ bookmarkModel];
-}
-
-// TODO(jrg): Refactor BookmarkBarFolder common code. http://crbug.com/35966
-// Most of the work (e.g. drop indicator) is taken care of in the
-// folder_view. Here we handle hover open issues for subfolders.
-// Caution: there are subtle differences between this one and
-// bookmark_bar_controller.mm's version.
-- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info {
- NSPoint currentLocation = [info draggingLocation];
- BookmarkButton* button = [self buttonForDroppingOnAtPoint:currentLocation];
-
- // Don't allow drops that would result in cycles.
- if (button) {
- NSData* data = [[info draggingPasteboard]
- dataForType:kBookmarkButtonDragType];
- if (data && [info draggingSource]) {
- BookmarkButton* sourceButton = nil;
- [data getBytes:&sourceButton length:sizeof(sourceButton)];
- const BookmarkNode* sourceNode = [sourceButton bookmarkNode];
- const BookmarkNode* destNode = [button bookmarkNode];
- if (destNode->HasAncestor(sourceNode))
- button = nil;
- }
- }
- // Delegate handling of dragging over a button to the |hoverState_| member.
- return [hoverState_ draggingEnteredButton:button];
-}
-
-// Unlike bookmark_bar_controller, we need to keep track of dragging state.
-// We also need to make sure we cancel the delayed hover close.
-- (void)draggingExited:(id<NSDraggingInfo>)info {
- // NOT the same as a cancel --> we may have moved the mouse into the submenu.
- // Delegate handling of the hover button to the |hoverState_| member.
- [hoverState_ draggingExited];
-}
-
-- (BOOL)dragShouldLockBarVisibility {
- return [parentController_ dragShouldLockBarVisibility];
-}
-
-// TODO(jrg): ARGH more code dup.
-// http://crbug.com/35966
-- (BOOL)dragButton:(BookmarkButton*)sourceButton
- to:(NSPoint)point
- copy:(BOOL)copy {
- DCHECK([sourceButton isKindOfClass:[BookmarkButton class]]);
- const BookmarkNode* sourceNode = [sourceButton bookmarkNode];
- return [self dragBookmark:sourceNode to:point copy:copy];
-}
-
-// TODO(mrossetti,jrg): Identical to the same function in BookmarkBarController.
-// http://crbug.com/35966
-- (BOOL)dragBookmarkData:(id<NSDraggingInfo>)info {
- BOOL dragged = NO;
- std::vector<const BookmarkNode*> nodes([self retrieveBookmarkNodeData]);
- if (nodes.size()) {
- BOOL copy = !([info draggingSourceOperationMask] & NSDragOperationMove);
- NSPoint dropPoint = [info draggingLocation];
- for (std::vector<const BookmarkNode*>::const_iterator it = nodes.begin();
- it != nodes.end(); ++it) {
- const BookmarkNode* sourceNode = *it;
- dragged = [self dragBookmark:sourceNode to:dropPoint copy:copy];
- }
- }
- return dragged;
-}
-
-// TODO(mrossetti,jrg): Identical to the same function in BookmarkBarController.
-// http://crbug.com/35966
-- (std::vector<const BookmarkNode*>)retrieveBookmarkNodeData {
- std::vector<const BookmarkNode*> dragDataNodes;
- BookmarkNodeData dragData;
- if(dragData.ReadFromDragClipboard()) {
- BookmarkModel* bookmarkModel = [self bookmarkModel];
- Profile* profile = bookmarkModel->profile();
- std::vector<const BookmarkNode*> nodes(dragData.GetNodes(profile));
- dragDataNodes.assign(nodes.begin(), nodes.end());
- }
- return dragDataNodes;
-}
-
-// Return YES if we should show the drop indicator, else NO.
-// TODO(jrg): ARGH code dup!
-// http://crbug.com/35966
-- (BOOL)shouldShowIndicatorShownForPoint:(NSPoint)point {
- return ![self buttonForDroppingOnAtPoint:point];
-}
-
-// Return the y position for a drop indicator.
-//
-// TODO(jrg): again we have code dup, sort of, with
-// bookmark_bar_controller.mm, but the axis is changed.
-// http://crbug.com/35966
-- (CGFloat)indicatorPosForDragToPoint:(NSPoint)point {
- CGFloat y = 0;
- int destIndex = [self indexForDragToPoint:point];
- int numButtons = static_cast<int>([buttons_ count]);
-
- // If it's a drop strictly between existing buttons or at the very beginning
- if (destIndex >= 0 && destIndex < numButtons) {
- // ... put the indicator right between the buttons.
- BookmarkButton* button =
- [buttons_ objectAtIndex:static_cast<NSUInteger>(destIndex)];
- DCHECK(button);
- NSRect buttonFrame = [button frame];
- y = NSMaxY(buttonFrame) + 0.5 * bookmarks::kBookmarkVerticalPadding;
-
- // If it's a drop at the end (past the last button, if there are any) ...
- } else if (destIndex == numButtons) {
- // and if it's past the last button ...
- if (numButtons > 0) {
- // ... find the last button, and put the indicator below it.
- BookmarkButton* button =
- [buttons_ objectAtIndex:static_cast<NSUInteger>(destIndex - 1)];
- DCHECK(button);
- NSRect buttonFrame = [button frame];
- y = buttonFrame.origin.y - 0.5 * bookmarks::kBookmarkVerticalPadding;
-
- }
- } else {
- NOTREACHED();
- }
-
- return y;
-}
-
-- (ThemeProvider*)themeProvider {
- return [parentController_ themeProvider];
-}
-
-- (void)childFolderWillShow:(id<BookmarkButtonControllerProtocol>)child {
- // Do nothing.
-}
-
-- (void)childFolderWillClose:(id<BookmarkButtonControllerProtocol>)child {
- // Do nothing.
-}
-
-- (BookmarkBarFolderController*)folderController {
- return folderController_;
-}
-
-// Add a new folder controller as triggered by the given folder button.
-- (void)addNewFolderControllerWithParentButton:(BookmarkButton*)parentButton {
- if (folderController_)
- [self closeBookmarkFolder:self];
-
- // Folder controller, like many window controllers, owns itself.
- folderController_ =
- [[BookmarkBarFolderController alloc] initWithParentButton:parentButton
- parentController:self
- barController:barController_];
- [folderController_ showWindow:self];
-}
-
-- (void)openAll:(const BookmarkNode*)node
- disposition:(WindowOpenDisposition)disposition {
- [barController_ openAll:node disposition:disposition];
-}
-
-- (void)addButtonForNode:(const BookmarkNode*)node
- atIndex:(NSInteger)buttonIndex {
- // Propose the frame for the new button. By default, this will be set to the
- // topmost button's frame (and there will always be one) offset upward in
- // anticipation of insertion.
- NSRect newButtonFrame = [[buttons_ objectAtIndex:0] frame];
- newButtonFrame.origin.y += bookmarks::kBookmarkButtonVerticalSpan;
- // When adding a button to an empty folder we must remove the 'empty'
- // placeholder button. This can be detected by checking for a parent
- // child count of 1.
- const BookmarkNode* parentNode = node->GetParent();
- if (parentNode->GetChildCount() == 1) {
- BookmarkButton* emptyButton = [buttons_ lastObject];
- newButtonFrame = [emptyButton frame];
- [emptyButton setDelegate:nil];
- [emptyButton removeFromSuperview];
- [buttons_ removeLastObject];
- }
-
- if (buttonIndex == -1 || buttonIndex > (NSInteger)[buttons_ count])
- buttonIndex = [buttons_ count];
-
- // Offset upward by one button height all buttons above insertion location.
- BookmarkButton* button = nil; // Remember so it can be de-highlighted.
- for (NSInteger i = 0; i < buttonIndex; ++i) {
- button = [buttons_ objectAtIndex:i];
- // Remember this location in case it's the last button being moved
- // which is where the new button will be located.
- newButtonFrame = [button frame];
- NSRect buttonFrame = [button frame];
- buttonFrame.origin.y += bookmarks::kBookmarkButtonVerticalSpan;
- [button setFrame:buttonFrame];
- }
- [[button cell] mouseExited:nil]; // De-highlight.
- BookmarkButton* newButton = [self makeButtonForNode:node
- frame:newButtonFrame];
- [buttons_ insertObject:newButton atIndex:buttonIndex];
- [mainView_ addSubview:newButton];
-
- // Close any child folder(s) which may still be open.
- [self closeBookmarkFolder:self];
-
- // Prelim height of the window. We'll trim later as needed.
- int height = [self windowHeightForButtonCount:[buttons_ count]];
- [self adjustWindowForHeight:height];
-}
-
-// More code which essentially duplicates that of BookmarkBarController.
-// TODO(mrossetti,jrg): http://crbug.com/35966
-- (BOOL)addURLs:(NSArray*)urls withTitles:(NSArray*)titles at:(NSPoint)point {
- DCHECK([urls count] == [titles count]);
- BOOL nodesWereAdded = NO;
- // Figure out where these new bookmarks nodes are to be added.
- BookmarkButton* button = [self buttonForDroppingOnAtPoint:point];
- BookmarkModel* bookmarkModel = [self bookmarkModel];
- const BookmarkNode* destParent = NULL;
- int destIndex = 0;
- if ([button isFolder]) {
- destParent = [button bookmarkNode];
- // Drop it at the end.
- destIndex = [button bookmarkNode]->GetChildCount();
- } else {
- // Else we're dropping somewhere in the folder, so find the right spot.
- destParent = [parentButton_ bookmarkNode];
- destIndex = [self indexForDragToPoint:point];
- // Be careful if the number of buttons != number of nodes.
- destIndex += [[parentButton_ cell] startingChildIndex];
- }
-
- // Create and add the new bookmark nodes.
- size_t urlCount = [urls count];
- for (size_t i = 0; i < urlCount; ++i) {
- GURL gurl;
- const char* string = [[urls objectAtIndex:i] UTF8String];
- if (string)
- gurl = GURL(string);
- // We only expect to receive valid URLs.
- DCHECK(gurl.is_valid());
- if (gurl.is_valid()) {
- bookmarkModel->AddURL(destParent,
- destIndex++,
- base::SysNSStringToUTF16([titles objectAtIndex:i]),
- gurl);
- nodesWereAdded = YES;
- }
- }
- return nodesWereAdded;
-}
-
-- (void)moveButtonFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex {
- if (fromIndex != toIndex) {
- if (toIndex == -1)
- toIndex = [buttons_ count];
- BookmarkButton* movedButton = [buttons_ objectAtIndex:fromIndex];
- [buttons_ removeObjectAtIndex:fromIndex];
- NSRect movedFrame = [movedButton frame];
- NSPoint toOrigin = movedFrame.origin;
- [movedButton setHidden:YES];
- if (fromIndex < toIndex) {
- BookmarkButton* targetButton = [buttons_ objectAtIndex:toIndex - 1];
- toOrigin = [targetButton frame].origin;
- for (NSInteger i = fromIndex; i < toIndex; ++i) {
- BookmarkButton* button = [buttons_ objectAtIndex:i];
- NSRect frame = [button frame];
- frame.origin.y += bookmarks::kBookmarkButtonVerticalSpan;
- [button setFrameOrigin:frame.origin];
- }
- } else {
- BookmarkButton* targetButton = [buttons_ objectAtIndex:toIndex];
- toOrigin = [targetButton frame].origin;
- for (NSInteger i = fromIndex - 1; i >= toIndex; --i) {
- BookmarkButton* button = [buttons_ objectAtIndex:i];
- NSRect buttonFrame = [button frame];
- buttonFrame.origin.y -= bookmarks::kBookmarkButtonVerticalSpan;
- [button setFrameOrigin:buttonFrame.origin];
- }
- }
- [buttons_ insertObject:movedButton atIndex:toIndex];
- [movedButton setFrameOrigin:toOrigin];
- [movedButton setHidden:NO];
- }
-}
-
-// TODO(jrg): Refactor BookmarkBarFolder common code. http://crbug.com/35966
-- (void)removeButton:(NSInteger)buttonIndex animate:(BOOL)animate {
- // TODO(mrossetti): Get disappearing animation to work. http://crbug.com/42360
- BookmarkButton* oldButton = [buttons_ objectAtIndex:buttonIndex];
- NSPoint poofPoint = [oldButton screenLocationForRemoveAnimation];
-
- // If a hover-open is pending, cancel it.
- if (oldButton == buttonThatMouseIsIn_) {
- [NSObject cancelPreviousPerformRequestsWithTarget:self];
- buttonThatMouseIsIn_ = nil;
- }
-
- // Deleting a button causes rearrangement that enables us to lose a
- // mouse-exited event. This problem doesn't appear to exist with
- // other keep-menu-open options (e.g. add folder). Since the
- // showsBorderOnlyWhileMouseInside uses a tracking area, simple
- // tricks (e.g. sending an extra mouseExited: to the button) don't
- // fix the problem.
- // http://crbug.com/54324
- for (NSButton* button in buttons_.get()) {
- if ([button showsBorderOnlyWhileMouseInside]) {
- [button setShowsBorderOnlyWhileMouseInside:NO];
- [button setShowsBorderOnlyWhileMouseInside:YES];
- }
- }
-
- [oldButton setDelegate:nil];
- [oldButton removeFromSuperview];
- if (animate && !ignoreAnimations_)
- NSShowAnimationEffect(NSAnimationEffectDisappearingItemDefault, poofPoint,
- NSZeroSize, nil, nil, nil);
- [buttons_ removeObjectAtIndex:buttonIndex];
- for (NSInteger i = 0; i < buttonIndex; ++i) {
- BookmarkButton* button = [buttons_ objectAtIndex:i];
- NSRect buttonFrame = [button frame];
- buttonFrame.origin.y -= bookmarks::kBookmarkButtonVerticalSpan;
- [button setFrame:buttonFrame];
- }
- // Search for and adjust submenus, if necessary.
- NSInteger buttonCount = [buttons_ count];
- if (buttonCount) {
- BookmarkButton* subButton = [folderController_ parentButton];
- for (NSInteger i = buttonIndex; i < buttonCount; ++i) {
- BookmarkButton* aButton = [buttons_ objectAtIndex:i];
- // If this button is showing its menu then we need to move the menu, too.
- if (aButton == subButton)
- [folderController_ offsetFolderMenuWindow:NSMakeSize(0.0,
- bookmarks::kBookmarkBarHeight)];
- }
- } else {
- // If all nodes have been removed from this folder then add in the
- // 'empty' placeholder button.
- NSRect buttonFrame =
- NSMakeRect(bookmarks::kBookmarkSubMenuHorizontalPadding,
- bookmarks::kBookmarkButtonHeight -
- (bookmarks::kBookmarkBarHeight -
- bookmarks::kBookmarkVerticalPadding),
- bookmarks::kDefaultBookmarkWidth,
- (bookmarks::kBookmarkBarHeight -
- 2 * bookmarks::kBookmarkVerticalPadding));
- BookmarkButton* button = [self makeButtonForNode:nil
- frame:buttonFrame];
- [buttons_ addObject:button];
- [mainView_ addSubview:button];
- buttonCount = 1;
- }
-
- // Propose a height for the window. We'll trim later as needed.
- [self adjustWindowForHeight:[self windowHeightForButtonCount:buttonCount]];
-}
-
-- (id<BookmarkButtonControllerProtocol>)controllerForNode:
- (const BookmarkNode*)node {
- // See if we are holding this node, otherwise see if it is in our
- // hierarchy of visible folder menus.
- if ([parentButton_ bookmarkNode] == node)
- return self;
- return [folderController_ controllerForNode:node];
-}
-
-#pragma mark TestingAPI Only
-
-- (void)setIgnoreAnimations:(BOOL)ignore {
- ignoreAnimations_ = ignore;
-}
-
-- (BookmarkButton*)buttonThatMouseIsIn {
- return buttonThatMouseIsIn_;
-}
-
-@end // BookmarkBarFolderController
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_controller_unittest.mm b/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_controller_unittest.mm
deleted file mode 100644
index 890c0fc..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_controller_unittest.mm
+++ /dev/null
@@ -1,1552 +0,0 @@
-// 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 "base/basictypes.h"
-#include "base/scoped_nsobject.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_constants.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_controller.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_folder_button_cell.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_folder_controller.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_unittest_helper.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/view_resizer_pong.h"
-#include "chrome/test/model_test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-// Add a redirect to make testing easier.
-@interface BookmarkBarFolderController(MakeTestingEasier)
-- (IBAction)openBookmarkFolderFromButton:(id)sender;
-- (void)validateMenuSpacing;
-@end
-
-@implementation BookmarkBarFolderController(MakeTestingEasier)
-- (IBAction)openBookmarkFolderFromButton:(id)sender {
- [[self folderTarget] openBookmarkFolderFromButton:sender];
-}
-
-// Utility function to verify that the buttons in this folder are all
-// evenly spaced in a progressive manner.
-- (void)validateMenuSpacing {
- BOOL firstButton = YES;
- CGFloat lastVerticalOffset = 0.0;
- for (BookmarkButton* button in [self buttons]) {
- if (firstButton) {
- firstButton = NO;
- lastVerticalOffset = [button frame].origin.y;
- } else {
- CGFloat nextVerticalOffset = [button frame].origin.y;
- EXPECT_CGFLOAT_EQ(lastVerticalOffset -
- bookmarks::kBookmarkButtonVerticalSpan,
- nextVerticalOffset);
- lastVerticalOffset = nextVerticalOffset;
- }
- }
-}
-@end
-
-// Don't use a high window level when running unit tests -- it'll
-// interfere with anything else you are working on.
-// For testing.
-@interface BookmarkBarFolderControllerNoLevel : BookmarkBarFolderController
-@end
-
-@implementation BookmarkBarFolderControllerNoLevel
-- (void)configureWindowLevel {
- // Intentionally empty.
-}
-@end
-
-// No window level and the ability to fake the "top left" point of the window.
-// For testing.
-@interface BookmarkBarFolderControllerLow : BookmarkBarFolderControllerNoLevel {
- BOOL realTopLeft_; // Use the real windowTopLeft call?
-}
-@property (nonatomic) BOOL realTopLeft;
-@end
-
-
-@implementation BookmarkBarFolderControllerLow
-
-@synthesize realTopLeft = realTopLeft_;
-
-- (NSPoint)windowTopLeftForWidth:(int)width {
- return realTopLeft_ ? [super windowTopLeftForWidth:width] :
- NSMakePoint(200,200);
-}
-
-@end
-
-
-@interface BookmarkBarFolderControllerPong : BookmarkBarFolderControllerLow {
- BOOL childFolderWillShow_;
- BOOL childFolderWillClose_;
-}
-@property (nonatomic, readonly) BOOL childFolderWillShow;
-@property (nonatomic, readonly) BOOL childFolderWillClose;
-@end
-
-@implementation BookmarkBarFolderControllerPong
-@synthesize childFolderWillShow = childFolderWillShow_;
-@synthesize childFolderWillClose = childFolderWillClose_;
-
-- (void)childFolderWillShow:(id<BookmarkButtonControllerProtocol>)child {
- childFolderWillShow_ = YES;
-}
-
-- (void)childFolderWillClose:(id<BookmarkButtonControllerProtocol>)child {
- childFolderWillClose_ = YES;
-}
-
-// We don't have a real BookmarkBarController as our parent root so
-// we fake this one out.
-- (void)closeAllBookmarkFolders {
- [self closeBookmarkFolder:self];
-}
-
-@end
-
-namespace {
-const int kLotsOfNodesCount = 150;
-};
-
-
-// Redirect certain calls so they can be seen by tests.
-
-@interface BookmarkBarControllerChildFolderRedirect : BookmarkBarController {
- BookmarkBarFolderController* childFolderDelegate_;
-}
-@property (nonatomic, assign) BookmarkBarFolderController* childFolderDelegate;
-@end
-
-@implementation BookmarkBarControllerChildFolderRedirect
-
-@synthesize childFolderDelegate = childFolderDelegate_;
-
-- (void)childFolderWillShow:(id<BookmarkButtonControllerProtocol>)child {
- [childFolderDelegate_ childFolderWillShow:child];
-}
-
-- (void)childFolderWillClose:(id<BookmarkButtonControllerProtocol>)child {
- [childFolderDelegate_ childFolderWillClose:child];
-}
-
-@end
-
-
-class BookmarkBarFolderControllerTest : public CocoaTest {
- public:
- BrowserTestHelper helper_;
- scoped_nsobject<BookmarkBarControllerChildFolderRedirect> bar_;
- const BookmarkNode* folderA_; // owned by model
- const BookmarkNode* longTitleNode_; // owned by model
-
- BookmarkBarFolderControllerTest() {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- const BookmarkNode* folderA = model->AddGroup(parent,
- parent->GetChildCount(),
- ASCIIToUTF16("group"));
- folderA_ = folderA;
- model->AddGroup(parent, parent->GetChildCount(),
- ASCIIToUTF16("sibbling group"));
- const BookmarkNode* folderB = model->AddGroup(folderA,
- folderA->GetChildCount(),
- ASCIIToUTF16("subgroup 1"));
- model->AddGroup(folderA,
- folderA->GetChildCount(),
- ASCIIToUTF16("subgroup 2"));
- model->AddURL(folderA, folderA->GetChildCount(), ASCIIToUTF16("title a"),
- GURL("http://www.google.com/a"));
- longTitleNode_ = model->AddURL(
- folderA, folderA->GetChildCount(),
- ASCIIToUTF16("title super duper long long whoa momma title you betcha"),
- GURL("http://www.google.com/b"));
- model->AddURL(folderB, folderB->GetChildCount(), ASCIIToUTF16("t"),
- GURL("http://www.google.com/c"));
-
- bar_.reset(
- [[BookmarkBarControllerChildFolderRedirect alloc]
- initWithBrowser:helper_.browser()
- initialWidth:300
- delegate:nil
- resizeDelegate:nil]);
- [bar_ loaded:model];
- // Make parent frame for bookmark bar then open it.
- NSRect frame = [[test_window() contentView] frame];
- frame = NSInsetRect(frame, 100, 200);
- NSView* fakeToolbarView = [[[NSView alloc] initWithFrame:frame]
- autorelease];
- [[test_window() contentView] addSubview:fakeToolbarView];
- [fakeToolbarView addSubview:[bar_ view]];
- [bar_ setBookmarkBarEnabled:YES];
- }
-
- // Remove the bookmark with the long title.
- void RemoveLongTitleNode() {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- model->Remove(longTitleNode_->GetParent(),
- longTitleNode_->GetParent()->IndexOfChild(longTitleNode_));
- }
-
- // Add LOTS of nodes to our model if needed (e.g. scrolling).
- // Returns the number of nodes added.
- int AddLotsOfNodes() {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- for (int i = 0; i < kLotsOfNodesCount; i++) {
- model->AddURL(folderA_, folderA_->GetChildCount(),
- ASCIIToUTF16("repeated title"),
- GURL("http://www.google.com/repeated/url"));
- }
- return kLotsOfNodesCount;
- }
-
- // Return a simple BookmarkBarFolderController.
- BookmarkBarFolderControllerPong* SimpleBookmarkBarFolderController() {
- BookmarkButton* parentButton = [[bar_ buttons] objectAtIndex:0];
- BookmarkBarFolderControllerPong* c =
- [[BookmarkBarFolderControllerPong alloc]
- initWithParentButton:parentButton
- parentController:nil
- barController:bar_];
- [c window]; // Force nib load.
- return c;
- }
-};
-
-TEST_F(BookmarkBarFolderControllerTest, InitCreateAndDelete) {
- scoped_nsobject<BookmarkBarFolderController> bbfc;
- bbfc.reset(SimpleBookmarkBarFolderController());
-
- // Make sure none of the buttons overlap, that all are inside
- // the content frame, and their cells are of the proper class.
- NSArray* buttons = [bbfc buttons];
- EXPECT_TRUE([buttons count]);
- for (unsigned int i = 0; i < ([buttons count]-1); i++) {
- EXPECT_FALSE(NSContainsRect([[buttons objectAtIndex:i] frame],
- [[buttons objectAtIndex:i+1] frame]));
- }
- Class cellClass = [BookmarkBarFolderButtonCell class];
- for (BookmarkButton* button in buttons) {
- NSRect r = [[bbfc mainView] convertRect:[button frame] fromView:button];
- // TODO(jrg): remove this adjustment.
- NSRect bigger = NSInsetRect([[bbfc mainView] frame], -2, 0);
- EXPECT_TRUE(NSContainsRect(bigger, r));
- EXPECT_TRUE([[button cell] isKindOfClass:cellClass]);
- }
-
- // Confirm folder buttons have no tooltip. The important thing
- // really is that we insure folders and non-folders are treated
- // differently; not sure of any other generic way to do this.
- for (BookmarkButton* button in buttons) {
- if ([button isFolder])
- EXPECT_FALSE([button toolTip]);
- else
- EXPECT_TRUE([button toolTip]);
- }
-}
-
-// Make sure closing of the window releases the controller.
-// (e.g. valgrind shouldn't complain if we do this).
-TEST_F(BookmarkBarFolderControllerTest, ReleaseOnClose) {
- scoped_nsobject<BookmarkBarFolderController> bbfc;
- bbfc.reset(SimpleBookmarkBarFolderController());
- EXPECT_TRUE(bbfc.get());
-
- [bbfc retain]; // stop the scoped_nsobject from doing anything
- [[bbfc window] close]; // trigger an autorelease of bbfc.get()
-}
-
-TEST_F(BookmarkBarFolderControllerTest, BasicPosition) {
- BookmarkButton* parentButton = [[bar_ buttons] objectAtIndex:0];
- EXPECT_TRUE(parentButton);
-
- // If parent is a BookmarkBarController, grow down.
- scoped_nsobject<BookmarkBarFolderControllerLow> bbfc;
- bbfc.reset([[BookmarkBarFolderControllerLow alloc]
- initWithParentButton:parentButton
- parentController:nil
- barController:bar_]);
- [bbfc window];
- [bbfc setRealTopLeft:YES];
- NSPoint pt = [bbfc windowTopLeftForWidth:0]; // screen coords
- NSPoint buttonOriginInScreen =
- [[parentButton window]
- convertBaseToScreen:[parentButton
- convertRectToBase:[parentButton frame]].origin];
- // Within margin
- EXPECT_LE(abs(pt.x - buttonOriginInScreen.x),
- bookmarks::kBookmarkMenuOverlap+1);
- EXPECT_LE(abs(pt.y - buttonOriginInScreen.y),
- bookmarks::kBookmarkMenuOverlap+1);
-
- // Make sure we see the window shift left if it spills off the screen
- pt = [bbfc windowTopLeftForWidth:0];
- NSPoint shifted = [bbfc windowTopLeftForWidth:9999999];
- EXPECT_LT(shifted.x, pt.x);
-
- // If parent is a BookmarkBarFolderController, grow right.
- scoped_nsobject<BookmarkBarFolderControllerLow> bbfc2;
- bbfc2.reset([[BookmarkBarFolderControllerLow alloc]
- initWithParentButton:[[bbfc buttons] objectAtIndex:0]
- parentController:bbfc.get()
- barController:bar_]);
- [bbfc2 window];
- [bbfc2 setRealTopLeft:YES];
- pt = [bbfc2 windowTopLeftForWidth:0];
- // We're now overlapping the window a bit.
- EXPECT_EQ(pt.x, NSMaxX([[bbfc.get() window] frame]) -
- bookmarks::kBookmarkMenuOverlap);
-}
-
-// Confirm we grow right until end of screen, then start growing left
-// until end of screen again, then right.
-TEST_F(BookmarkBarFolderControllerTest, PositionRightLeftRight) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- const BookmarkNode* folder = parent;
-
- const int count = 100;
- int i;
- // Make some super duper deeply nested folders.
- for (i=0; i<count; i++) {
- folder = model->AddGroup(folder, 0, ASCIIToUTF16("nested folder"));
- }
-
- // Setup initial state for opening all folders.
- folder = parent;
- BookmarkButton* parentButton = [[bar_ buttons] objectAtIndex:0];
- BookmarkBarFolderController* parentController = nil;
- EXPECT_TRUE(parentButton);
-
- // Open them all.
- scoped_nsobject<NSMutableArray> folder_controller_array;
- folder_controller_array.reset([[NSMutableArray array] retain]);
- for (i=0; i<count; i++) {
- BookmarkBarFolderControllerNoLevel* bbfcl =
- [[BookmarkBarFolderControllerNoLevel alloc]
- initWithParentButton:parentButton
- parentController:parentController
- barController:bar_];
- [folder_controller_array addObject:bbfcl];
- [bbfcl autorelease];
- [bbfcl window];
- parentController = bbfcl;
- parentButton = [[bbfcl buttons] objectAtIndex:0];
- }
-
- // Make vector of all x positions.
- std::vector<CGFloat> leftPositions;
- for (i=0; i<count; i++) {
- CGFloat x = [[[folder_controller_array objectAtIndex:i] window]
- frame].origin.x;
- leftPositions.push_back(x);
- }
-
- // Make sure the first few grow right.
- for (i=0; i<3; i++)
- EXPECT_TRUE(leftPositions[i+1] > leftPositions[i]);
-
- // Look for the first "grow left".
- while (leftPositions[i] > leftPositions[i-1])
- i++;
- // Confirm the next few also grow left.
- int j;
- for (j=i; j<i+3; j++)
- EXPECT_TRUE(leftPositions[j+1] < leftPositions[j]);
- i = j;
-
- // Finally, confirm we see a "grow right" once more.
- while (leftPositions[i] < leftPositions[i-1])
- i++;
- // (No need to EXPECT a final "grow right"; if we didn't find one
- // we'd get a C++ array bounds exception).
-}
-
-TEST_F(BookmarkBarFolderControllerTest, DropDestination) {
- scoped_nsobject<BookmarkBarFolderController> bbfc;
- bbfc.reset(SimpleBookmarkBarFolderController());
- EXPECT_TRUE(bbfc.get());
-
- // Confirm "off the top" and "off the bottom" match no buttons.
- NSPoint p = NSMakePoint(NSMidX([[bbfc mainView] frame]), 10000);
- EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:p]);
- EXPECT_TRUE([bbfc shouldShowIndicatorShownForPoint:p]);
- p = NSMakePoint(NSMidX([[bbfc mainView] frame]), -1);
- EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:p]);
- EXPECT_TRUE([bbfc shouldShowIndicatorShownForPoint:p]);
-
- // Confirm "right in the center" (give or take a pixel) is a match,
- // and confirm "just barely in the button" is not. Anything more
- // specific seems likely to be tweaked. We don't loop over all
- // buttons because the scroll view makes them not visible.
- for (BookmarkButton* button in [bbfc buttons]) {
- CGFloat x = NSMidX([button frame]);
- CGFloat y = NSMidY([button frame]);
- // Somewhere near the center: a match (but only if a folder!)
- if ([button isFolder]) {
- EXPECT_EQ(button,
- [bbfc buttonForDroppingOnAtPoint:NSMakePoint(x-1, y+1)]);
- EXPECT_EQ(button,
- [bbfc buttonForDroppingOnAtPoint:NSMakePoint(x+1, y-1)]);
- EXPECT_FALSE([bbfc shouldShowIndicatorShownForPoint:NSMakePoint(x, y)]);;
- } else {
- // If not a folder we don't drop into it.
- EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:NSMakePoint(x-1, y+1)]);
- EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:NSMakePoint(x+1, y-1)]);
- EXPECT_TRUE([bbfc shouldShowIndicatorShownForPoint:NSMakePoint(x, y)]);;
- }
- }
-}
-
-TEST_F(BookmarkBarFolderControllerTest, OpenFolder) {
- scoped_nsobject<BookmarkBarFolderController> bbfc;
- bbfc.reset(SimpleBookmarkBarFolderController());
- EXPECT_TRUE(bbfc.get());
-
- EXPECT_FALSE([bbfc folderController]);
- BookmarkButton* button = [[bbfc buttons] objectAtIndex:0];
- [bbfc openBookmarkFolderFromButton:button];
- id controller = [bbfc folderController];
- EXPECT_TRUE(controller);
- EXPECT_EQ([controller parentButton], button);
-
- // Click the same one --> it gets closed.
- [bbfc openBookmarkFolderFromButton:[[bbfc buttons] objectAtIndex:0]];
- EXPECT_FALSE([bbfc folderController]);
-
- // Open a new one --> change.
- [bbfc openBookmarkFolderFromButton:[[bbfc buttons] objectAtIndex:1]];
- EXPECT_NE(controller, [bbfc folderController]);
- EXPECT_NE([[bbfc folderController] parentButton], button);
-
- // Close it --> all gone!
- [bbfc closeBookmarkFolder:nil];
- EXPECT_FALSE([bbfc folderController]);
-}
-
-TEST_F(BookmarkBarFolderControllerTest, ChildFolderCallbacks) {
- scoped_nsobject<BookmarkBarFolderControllerPong> bbfc;
- bbfc.reset(SimpleBookmarkBarFolderController());
- EXPECT_TRUE(bbfc.get());
- [bar_ setChildFolderDelegate:bbfc.get()];
-
- EXPECT_FALSE([bbfc childFolderWillShow]);
- [bbfc openBookmarkFolderFromButton:[[bbfc buttons] objectAtIndex:0]];
- EXPECT_TRUE([bbfc childFolderWillShow]);
-
- EXPECT_FALSE([bbfc childFolderWillClose]);
- [bbfc closeBookmarkFolder:nil];
- EXPECT_TRUE([bbfc childFolderWillClose]);
-
- [bar_ setChildFolderDelegate:nil];
-}
-
-// Make sure bookmark folders have variable widths.
-TEST_F(BookmarkBarFolderControllerTest, ChildFolderWidth) {
- scoped_nsobject<BookmarkBarFolderController> bbfc;
-
- bbfc.reset(SimpleBookmarkBarFolderController());
- EXPECT_TRUE(bbfc.get());
- [bbfc showWindow:bbfc.get()];
- CGFloat wideWidth = NSWidth([[bbfc window] frame]);
-
- RemoveLongTitleNode();
- bbfc.reset(SimpleBookmarkBarFolderController());
- EXPECT_TRUE(bbfc.get());
- CGFloat thinWidth = NSWidth([[bbfc window] frame]);
-
- // Make sure window size changed as expected.
- EXPECT_GT(wideWidth, thinWidth);
-}
-
-// Simple scrolling tests.
-TEST_F(BookmarkBarFolderControllerTest, SimpleScroll) {
- scoped_nsobject<BookmarkBarFolderController> bbfc;
-
- int nodecount = AddLotsOfNodes();
- bbfc.reset(SimpleBookmarkBarFolderController());
- EXPECT_TRUE(bbfc.get());
- [bbfc showWindow:bbfc.get()];
-
- // Make sure the window fits on the screen.
- EXPECT_LT(NSHeight([[bbfc window] frame]),
- NSHeight([[NSScreen mainScreen] frame]));
-
- // Verify the logic used by the scroll arrow code.
- EXPECT_TRUE([bbfc canScrollUp]);
- EXPECT_FALSE([bbfc canScrollDown]);
-
- // Scroll it up. Make sure the window has gotten bigger each time.
- // Also, for each scroll, make sure our hit test finds a new button
- // (to confirm the content area changed).
- NSView* savedHit = nil;
- for (int i=0; i<3; i++) {
- CGFloat height = NSHeight([[bbfc window] frame]);
- [bbfc performOneScroll:60];
- EXPECT_GT(NSHeight([[bbfc window] frame]), height);
- NSView* hit = [[[bbfc window] contentView] hitTest:NSMakePoint(22, 22)];
- EXPECT_NE(hit, savedHit);
- savedHit = hit;
- }
-
- // Keep scrolling up; make sure we never get bigger than the screen.
- // Also confirm we never scroll the window off the screen.
- bool bothAtOnce = false;
- NSRect screenFrame = [[NSScreen mainScreen] frame];
- for (int i = 0; i < nodecount; i++) {
- [bbfc performOneScroll:60];
- EXPECT_TRUE(NSContainsRect(screenFrame,
- [[bbfc window] frame]));
- // Make sure, sometime during our scroll, we have the ability to
- // scroll in either direction.
- if ([bbfc canScrollUp] &&
- [bbfc canScrollDown])
- bothAtOnce = true;
- }
- EXPECT_TRUE(bothAtOnce);
-
- // Once we've scrolled to the end, our only option should be to scroll back.
- EXPECT_FALSE([bbfc canScrollUp]);
- EXPECT_TRUE([bbfc canScrollDown]);
-
- // Now scroll down and make sure the window size does not change.
- // Also confirm we never scroll the window off the screen the other
- // way.
- for (int i=0; i<nodecount+50; i++) {
- CGFloat height = NSHeight([[bbfc window] frame]);
- [bbfc performOneScroll:-60];
- EXPECT_EQ(height, NSHeight([[bbfc window] frame]));
- EXPECT_TRUE(NSContainsRect(screenFrame,
- [[bbfc window] frame]));
- }
-}
-
-// Folder menu sizing and placementwhile deleting bookmarks and scrolling tests.
-TEST_F(BookmarkBarFolderControllerTest, MenuPlacementWhileScrollingDeleting) {
- scoped_nsobject<BookmarkBarFolderController> bbfc;
- AddLotsOfNodes();
- bbfc.reset(SimpleBookmarkBarFolderController());
- [bbfc showWindow:bbfc.get()];
- NSWindow* menuWindow = [bbfc window];
- BookmarkBarFolderController* folder = [bar_ folderController];
- NSArray* buttons = [folder buttons];
-
- // Before scrolling any, delete a bookmark and make sure the window top has
- // not moved. Pick a button which is near the top and visible.
- CGFloat oldTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
- BookmarkButton* button = [buttons objectAtIndex:3];
- [folder deleteBookmark:button];
- CGFloat newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
- EXPECT_CGFLOAT_EQ(oldTop, newTop);
-
- // Scroll so that both the top and bottom scroll arrows show, make sure
- // the top of the window has moved up, then delete a visible button and
- // make sure the top has not moved.
- oldTop = newTop;
- const CGFloat scrollOneBookmark = bookmarks::kBookmarkButtonHeight +
- bookmarks::kBookmarkVerticalPadding;
- NSUInteger buttonCounter = 0;
- NSUInteger extraButtonLimit = 3;
- while (![bbfc canScrollDown] || extraButtonLimit > 0) {
- [bbfc performOneScroll:scrollOneBookmark];
- ++buttonCounter;
- if ([bbfc canScrollDown])
- --extraButtonLimit;
- }
- newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
- EXPECT_NE(oldTop, newTop);
- oldTop = newTop;
- button = [buttons objectAtIndex:buttonCounter + 3];
- [folder deleteBookmark:button];
- newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
- EXPECT_CGFLOAT_EQ(oldTop, newTop);
-
- // Scroll so that the top scroll arrow is no longer showing, make sure
- // the top of the window has not moved, then delete a visible button and
- // make sure the top has not moved.
- while ([bbfc canScrollDown]) {
- [bbfc performOneScroll:-scrollOneBookmark];
- --buttonCounter;
- }
- button = [buttons objectAtIndex:buttonCounter + 3];
- [folder deleteBookmark:button];
- newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
- EXPECT_CGFLOAT_EQ(oldTop, newTop);
-}
-
-@interface FakedDragInfo : NSObject {
-@public
- NSPoint dropLocation_;
- NSDragOperation sourceMask_;
-}
-@property (nonatomic, assign) NSPoint dropLocation;
-- (void)setDraggingSourceOperationMask:(NSDragOperation)mask;
-@end
-
-@implementation FakedDragInfo
-
-@synthesize dropLocation = dropLocation_;
-
-- (id)init {
- if ((self = [super init])) {
- dropLocation_ = NSZeroPoint;
- sourceMask_ = NSDragOperationMove;
- }
- return self;
-}
-
-// NSDraggingInfo protocol functions.
-
-- (id)draggingPasteboard {
- return self;
-}
-
-- (id)draggingSource {
- return self;
-}
-
-- (NSDragOperation)draggingSourceOperationMask {
- return sourceMask_;
-}
-
-- (NSPoint)draggingLocation {
- return dropLocation_;
-}
-
-// Other functions.
-
-- (void)setDraggingSourceOperationMask:(NSDragOperation)mask {
- sourceMask_ = mask;
-}
-
-@end
-
-
-class BookmarkBarFolderControllerMenuTest : public CocoaTest {
- public:
- BrowserTestHelper helper_;
- scoped_nsobject<NSView> parent_view_;
- scoped_nsobject<ViewResizerPong> resizeDelegate_;
- scoped_nsobject<BookmarkBarController> bar_;
-
- BookmarkBarFolderControllerMenuTest() {
- resizeDelegate_.reset([[ViewResizerPong alloc] init]);
- NSRect parent_frame = NSMakeRect(0, 0, 800, 50);
- parent_view_.reset([[NSView alloc] initWithFrame:parent_frame]);
- [parent_view_ setHidden:YES];
- bar_.reset([[BookmarkBarController alloc]
- initWithBrowser:helper_.browser()
- initialWidth:NSWidth(parent_frame)
- delegate:nil
- resizeDelegate:resizeDelegate_.get()]);
- InstallAndToggleBar(bar_.get());
- }
-
- void InstallAndToggleBar(BookmarkBarController* bar) {
- // Force loading of the nib.
- [bar view];
- // Awkwardness to look like we've been installed.
- [parent_view_ addSubview:[bar view]];
- NSRect frame = [[[bar view] superview] frame];
- frame.origin.y = 100;
- [[[bar view] superview] setFrame:frame];
-
- // Make sure it's on in a window so viewDidMoveToWindow is called
- [[test_window() contentView] addSubview:parent_view_];
-
- // Make sure it's open so certain things aren't no-ops.
- [bar updateAndShowNormalBar:YES
- showDetachedBar:NO
- withAnimation:NO];
- }
-};
-
-TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveBarBookmarkToFolder) {
- BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
- const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
- "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
- "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
- model_test_utils::AddNodesFromModelString(model, root, model_string);
-
- // Validate initial model.
- std::string actualModelString = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(model_string, actualModelString);
-
- // Pop up a folder menu and drag in a button from the bar.
- BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"2f"];
- NSRect oldToFolderFrame = [toFolder frame];
- [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
- withObject:toFolder];
- BookmarkBarFolderController* folderController = [bar_ folderController];
- EXPECT_TRUE(folderController);
- NSWindow* toWindow = [folderController window];
- EXPECT_TRUE(toWindow);
- NSRect oldToWindowFrame = [toWindow frame];
- // Drag a bar button onto a bookmark (i.e. not a folder) in a folder
- // so it should end up below the target bookmark.
- BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"1b"];
- ASSERT_TRUE(draggedButton);
- CGFloat horizontalShift =
- NSWidth([draggedButton frame]) + bookmarks::kBookmarkHorizontalPadding;
- BookmarkButton* targetButton =
- [folderController buttonWithTitleEqualTo:@"2f1b"];
- ASSERT_TRUE(targetButton);
- [folderController dragButton:draggedButton
- to:[targetButton center]
- copy:NO];
- // The button should have landed just after "2f1b".
- const std::string expected_string("2f:[ 2f1b 1b 2f2f:[ 2f2f1b "
- "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
- "4f2f1b 4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
- EXPECT_EQ(expected_string, model_test_utils::ModelStringFromNode(root));
-
- // Verify the window still appears by looking for its controller.
- EXPECT_TRUE([bar_ folderController]);
-
- // Gather the new frames.
- NSRect newToFolderFrame = [toFolder frame];
- NSRect newToWindowFrame = [toWindow frame];
- // The toFolder should have shifted left horizontally but not vertically.
- NSRect expectedToFolderFrame =
- NSOffsetRect(oldToFolderFrame, -horizontalShift, 0);
- EXPECT_NSRECT_EQ(expectedToFolderFrame, newToFolderFrame);
- // The toWindow should have shifted left horizontally, down vertically,
- // and grown vertically.
- NSRect expectedToWindowFrame = oldToWindowFrame;
- expectedToWindowFrame.origin.x -= horizontalShift;
- CGFloat diff = (bookmarks::kBookmarkBarHeight +
- 2*bookmarks::kBookmarkVerticalPadding);
- expectedToWindowFrame.origin.y -= diff;
- expectedToWindowFrame.size.height += diff;
- EXPECT_NSRECT_EQ(expectedToWindowFrame, newToWindowFrame);
-
- // Check button spacing.
- [folderController validateMenuSpacing];
-
- // Move the button back to the bar at the beginning.
- draggedButton = [folderController buttonWithTitleEqualTo:@"1b"];
- ASSERT_TRUE(draggedButton);
- targetButton = [bar_ buttonWithTitleEqualTo:@"2f"];
- ASSERT_TRUE(targetButton);
- [bar_ dragButton:draggedButton
- to:[targetButton left]
- copy:NO];
- EXPECT_EQ(model_string, model_test_utils::ModelStringFromNode(root));
- // Don't check the folder window since it's not supposed to be showing.
-}
-
-TEST_F(BookmarkBarFolderControllerMenuTest, DragCopyBarBookmarkToFolder) {
- BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
- const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
- "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
- "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
- model_test_utils::AddNodesFromModelString(model, root, model_string);
-
- // Validate initial model.
- std::string actualModelString = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(model_string, actualModelString);
-
- // Pop up a folder menu and copy in a button from the bar.
- BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"2f"];
- ASSERT_TRUE(toFolder);
- NSRect oldToFolderFrame = [toFolder frame];
- [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
- withObject:toFolder];
- BookmarkBarFolderController* folderController = [bar_ folderController];
- EXPECT_TRUE(folderController);
- NSWindow* toWindow = [folderController window];
- EXPECT_TRUE(toWindow);
- NSRect oldToWindowFrame = [toWindow frame];
- // Drag a bar button onto a bookmark (i.e. not a folder) in a folder
- // so it should end up below the target bookmark.
- BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"1b"];
- ASSERT_TRUE(draggedButton);
- BookmarkButton* targetButton =
- [folderController buttonWithTitleEqualTo:@"2f1b"];
- ASSERT_TRUE(targetButton);
- [folderController dragButton:draggedButton
- to:[targetButton center]
- copy:YES];
- // The button should have landed just after "2f1b".
- const std::string expected_1("1b 2f:[ 2f1b 1b 2f2f:[ 2f2f1b "
- "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
- "4f2f1b 4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
- EXPECT_EQ(expected_1, model_test_utils::ModelStringFromNode(root));
-
- // Gather the new frames.
- NSRect newToFolderFrame = [toFolder frame];
- NSRect newToWindowFrame = [toWindow frame];
- // The toFolder should have shifted.
- EXPECT_NSRECT_EQ(oldToFolderFrame, newToFolderFrame);
- // The toWindow should have shifted down vertically and grown vertically.
- NSRect expectedToWindowFrame = oldToWindowFrame;
- CGFloat diff = (bookmarks::kBookmarkBarHeight +
- 2*bookmarks::kBookmarkVerticalPadding);
- expectedToWindowFrame.origin.y -= diff;
- expectedToWindowFrame.size.height += diff;
- EXPECT_NSRECT_EQ(expectedToWindowFrame, newToWindowFrame);
-
- // Copy the button back to the bar after "3b".
- draggedButton = [folderController buttonWithTitleEqualTo:@"1b"];
- ASSERT_TRUE(draggedButton);
- targetButton = [bar_ buttonWithTitleEqualTo:@"4f"];
- ASSERT_TRUE(targetButton);
- [bar_ dragButton:draggedButton
- to:[targetButton left]
- copy:YES];
- const std::string expected_2("1b 2f:[ 2f1b 1b 2f2f:[ 2f2f1b "
- "2f2f2b 2f2f3b ] 2f3b ] 3b 1b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
- "4f2f1b 4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
- EXPECT_EQ(expected_2, model_test_utils::ModelStringFromNode(root));
-}
-
-TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveBarBookmarkToSubfolder) {
- BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
- const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
- "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
- "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
- model_test_utils::AddNodesFromModelString(model, root, model_string);
-
- // Validate initial model.
- std::string actualModelString = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(model_string, actualModelString);
-
- // Pop up a folder menu and a subfolder menu.
- BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"4f"];
- ASSERT_TRUE(toFolder);
- [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
- withObject:toFolder];
- BookmarkBarFolderController* folderController = [bar_ folderController];
- EXPECT_TRUE(folderController);
- NSWindow* toWindow = [folderController window];
- EXPECT_TRUE(toWindow);
- NSRect oldToWindowFrame = [toWindow frame];
- BookmarkButton* toSubfolder =
- [folderController buttonWithTitleEqualTo:@"4f2f"];
- ASSERT_TRUE(toSubfolder);
- [[toSubfolder target] performSelector:@selector(openBookmarkFolderFromButton:)
- withObject:toSubfolder];
- BookmarkBarFolderController* subfolderController =
- [folderController folderController];
- EXPECT_TRUE(subfolderController);
- NSWindow* toSubwindow = [subfolderController window];
- EXPECT_TRUE(toSubwindow);
- NSRect oldToSubwindowFrame = [toSubwindow frame];
- // Drag a bar button onto a bookmark (i.e. not a folder) in a folder
- // so it should end up below the target bookmark.
- BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"5b"];
- ASSERT_TRUE(draggedButton);
- BookmarkButton* targetButton =
- [subfolderController buttonWithTitleEqualTo:@"4f2f3b"];
- ASSERT_TRUE(targetButton);
- [subfolderController dragButton:draggedButton
- to:[targetButton center]
- copy:NO];
- // The button should have landed just after "2f".
- const std::string expected_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b "
- "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
- "4f2f1b 4f2f2b 4f2f3b 5b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] ");
- EXPECT_EQ(expected_string, model_test_utils::ModelStringFromNode(root));
-
- // Check button spacing.
- [folderController validateMenuSpacing];
- [subfolderController validateMenuSpacing];
-
- // Check the window layouts. The folder window should not have changed,
- // but the subfolder window should have shifted vertically and grown.
- NSRect newToWindowFrame = [toWindow frame];
- EXPECT_NSRECT_EQ(oldToWindowFrame, newToWindowFrame);
- NSRect newToSubwindowFrame = [toSubwindow frame];
- NSRect expectedToSubwindowFrame = oldToSubwindowFrame;
- expectedToSubwindowFrame.origin.y -=
- bookmarks::kBookmarkBarHeight + bookmarks::kVisualHeightOffset;
- expectedToSubwindowFrame.size.height +=
- bookmarks::kBookmarkBarHeight + bookmarks::kVisualHeightOffset;
- EXPECT_NSRECT_EQ(expectedToSubwindowFrame, newToSubwindowFrame);
-}
-
-TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveWithinFolder) {
- BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
- const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
- "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
- "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
- model_test_utils::AddNodesFromModelString(model, root, model_string);
-
- // Validate initial model.
- std::string actualModelString = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(model_string, actualModelString);
-
- // Pop up a folder menu.
- BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"4f"];
- ASSERT_TRUE(toFolder);
- [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
- withObject:toFolder];
- BookmarkBarFolderController* folderController = [bar_ folderController];
- EXPECT_TRUE(folderController);
- NSWindow* toWindow = [folderController window];
- EXPECT_TRUE(toWindow);
- NSRect oldToWindowFrame = [toWindow frame];
- // Drag a folder button to the top within the same parent.
- BookmarkButton* draggedButton =
- [folderController buttonWithTitleEqualTo:@"4f2f"];
- ASSERT_TRUE(draggedButton);
- BookmarkButton* targetButton =
- [folderController buttonWithTitleEqualTo:@"4f1f"];
- ASSERT_TRUE(targetButton);
- [folderController dragButton:draggedButton
- to:[targetButton top]
- copy:NO];
- // The button should have landed above "4f1f".
- const std::string expected_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b "
- "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f2f:[ 4f2f1b 4f2f2b 4f2f3b ] "
- "4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
- EXPECT_EQ(expected_string, model_test_utils::ModelStringFromNode(root));
-
- // The window should not have gone away.
- EXPECT_TRUE([bar_ folderController]);
-
- // The folder window should not have changed.
- NSRect newToWindowFrame = [toWindow frame];
- EXPECT_NSRECT_EQ(oldToWindowFrame, newToWindowFrame);
-
- // Check button spacing.
- [folderController validateMenuSpacing];
-}
-
-TEST_F(BookmarkBarFolderControllerMenuTest, DragParentOntoChild) {
- BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
- const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
- "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
- "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
- model_test_utils::AddNodesFromModelString(model, root, model_string);
-
- // Validate initial model.
- std::string actualModelString = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(model_string, actualModelString);
-
- // Pop up a folder menu.
- BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"4f"];
- ASSERT_TRUE(toFolder);
- [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
- withObject:toFolder];
- BookmarkBarFolderController* folderController = [bar_ folderController];
- EXPECT_TRUE(folderController);
- NSWindow* toWindow = [folderController window];
- EXPECT_TRUE(toWindow);
- // Drag a folder button to one of its children.
- BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"4f"];
- ASSERT_TRUE(draggedButton);
- BookmarkButton* targetButton =
- [folderController buttonWithTitleEqualTo:@"4f3f"];
- ASSERT_TRUE(targetButton);
- [folderController dragButton:draggedButton
- to:[targetButton top]
- copy:NO];
- // The model should not have changed.
- EXPECT_EQ(model_string, model_test_utils::ModelStringFromNode(root));
-
- // Check button spacing.
- [folderController validateMenuSpacing];
-}
-
-TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveChildToParent) {
- BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
- const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
- "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
- "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
- model_test_utils::AddNodesFromModelString(model, root, model_string);
-
- // Validate initial model.
- std::string actualModelString = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(model_string, actualModelString);
-
- // Pop up a folder menu and a subfolder menu.
- BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"4f"];
- ASSERT_TRUE(toFolder);
- [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
- withObject:toFolder];
- BookmarkBarFolderController* folderController = [bar_ folderController];
- EXPECT_TRUE(folderController);
- BookmarkButton* toSubfolder =
- [folderController buttonWithTitleEqualTo:@"4f2f"];
- ASSERT_TRUE(toSubfolder);
- [[toSubfolder target] performSelector:@selector(openBookmarkFolderFromButton:)
- withObject:toSubfolder];
- BookmarkBarFolderController* subfolderController =
- [folderController folderController];
- EXPECT_TRUE(subfolderController);
-
- // Drag a subfolder bookmark to the parent folder.
- BookmarkButton* draggedButton =
- [subfolderController buttonWithTitleEqualTo:@"4f2f3b"];
- ASSERT_TRUE(draggedButton);
- BookmarkButton* targetButton =
- [folderController buttonWithTitleEqualTo:@"4f2f"];
- ASSERT_TRUE(targetButton);
- [folderController dragButton:draggedButton
- to:[targetButton top]
- copy:NO];
- // The button should have landed above "4f2f".
- const std::string expected_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
- "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f3b 4f2f:[ "
- "4f2f1b 4f2f2b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
- EXPECT_EQ(expected_string, model_test_utils::ModelStringFromNode(root));
-
- // Check button spacing.
- [folderController validateMenuSpacing];
- // The window should not have gone away.
- EXPECT_TRUE([bar_ folderController]);
- // The subfolder should have gone away.
- EXPECT_FALSE([folderController folderController]);
-}
-
-TEST_F(BookmarkBarFolderControllerMenuTest, DragWindowResizing) {
- BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
- const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::string
- model_string("a b:[ b1 b2 b3 ] reallyReallyLongBookmarkName c ");
- model_test_utils::AddNodesFromModelString(model, root, model_string);
-
- // Validate initial model.
- std::string actualModelString = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(model_string, actualModelString);
-
- // Pop up a folder menu.
- BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"b"];
- ASSERT_TRUE(toFolder);
- [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
- withObject:toFolder];
- BookmarkBarFolderController* folderController = [bar_ folderController];
- EXPECT_TRUE(folderController);
- NSWindow* toWindow = [folderController window];
- EXPECT_TRUE(toWindow);
- CGFloat oldWidth = NSWidth([toWindow frame]);
- // Drag the bookmark with a long name to the folder.
- BookmarkButton* draggedButton =
- [bar_ buttonWithTitleEqualTo:@"reallyReallyLongBookmarkName"];
- ASSERT_TRUE(draggedButton);
- BookmarkButton* targetButton =
- [folderController buttonWithTitleEqualTo:@"b1"];
- ASSERT_TRUE(targetButton);
- [folderController dragButton:draggedButton
- to:[targetButton center]
- copy:NO];
- // Verify the model change.
- const std::string
- expected_string("a b:[ b1 reallyReallyLongBookmarkName b2 b3 ] c ");
- EXPECT_EQ(expected_string, model_test_utils::ModelStringFromNode(root));
- // Verify the window grew. Just test a reasonable width gain.
- CGFloat newWidth = NSWidth([toWindow frame]);
- EXPECT_LT(oldWidth + 30.0, newWidth);
-}
-
-TEST_F(BookmarkBarFolderControllerMenuTest, MoveRemoveAddButtons) {
- BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
- const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::string model_string("1b 2f:[ 2f1b 2f2b 2f3b ] 3b 4b ");
- model_test_utils::AddNodesFromModelString(model, root, model_string);
-
- // Validate initial model.
- std::string actualModelString = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(model_string, actualModelString);
-
- // Pop up a folder menu.
- BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"2f"];
- ASSERT_TRUE(toFolder);
- [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
- withObject:toFolder];
- BookmarkBarFolderController* folder = [bar_ folderController];
- EXPECT_TRUE(folder);
-
- // Remember how many buttons are showing.
- NSArray* buttons = [folder buttons];
- NSUInteger oldDisplayedButtons = [buttons count];
-
- // Move a button around a bit.
- [folder moveButtonFromIndex:0 toIndex:2];
- EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:0] title]);
- EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:1] title]);
- EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:2] title]);
- EXPECT_EQ(oldDisplayedButtons, [buttons count]);
- [folder moveButtonFromIndex:2 toIndex:0];
- EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:0] title]);
- EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:1] title]);
- EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:2] title]);
- EXPECT_EQ(oldDisplayedButtons, [buttons count]);
-
- // Add a couple of buttons.
- const BookmarkNode* node = root->GetChild(2); // Purloin an existing node.
- [folder addButtonForNode:node atIndex:0];
- EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:0] title]);
- EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:1] title]);
- EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:2] title]);
- EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:3] title]);
- EXPECT_EQ(oldDisplayedButtons + 1, [buttons count]);
- node = root->GetChild(3);
- [folder addButtonForNode:node atIndex:-1];
- EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:0] title]);
- EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:1] title]);
- EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:2] title]);
- EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:3] title]);
- EXPECT_NSEQ(@"4b", [[buttons objectAtIndex:4] title]);
- EXPECT_EQ(oldDisplayedButtons + 2, [buttons count]);
-
- // Remove a couple of buttons.
- [folder removeButton:4 animate:NO];
- [folder removeButton:1 animate:NO];
- EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:0] title]);
- EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:1] title]);
- EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:2] title]);
- EXPECT_EQ(oldDisplayedButtons, [buttons count]);
-
- // Check button spacing.
- [folder validateMenuSpacing];
-}
-
-TEST_F(BookmarkBarFolderControllerMenuTest, ControllerForNode) {
- BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
- const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::string model_string("1b 2f:[ 2f1b 2f2b ] 3b ");
- model_test_utils::AddNodesFromModelString(model, root, model_string);
-
- // Validate initial model.
- std::string actualModelString = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(model_string, actualModelString);
-
- // Find the main bar controller.
- const void* expectedController = bar_;
- const void* actualController = [bar_ controllerForNode:root];
- EXPECT_EQ(expectedController, actualController);
-
- // Pop up the folder menu.
- BookmarkButton* targetFolder = [bar_ buttonWithTitleEqualTo:@"2f"];
- ASSERT_TRUE(targetFolder);
- [[targetFolder target]
- performSelector:@selector(openBookmarkFolderFromButton:)
- withObject:targetFolder];
- BookmarkBarFolderController* folder = [bar_ folderController];
- EXPECT_TRUE(folder);
-
- // Find the folder controller using the folder controller.
- const BookmarkNode* targetNode = root->GetChild(1);
- expectedController = folder;
- actualController = [bar_ controllerForNode:targetNode];
- EXPECT_EQ(expectedController, actualController);
-
- // Find the folder controller from the bar.
- actualController = [folder controllerForNode:targetNode];
- EXPECT_EQ(expectedController, actualController);
-}
-
-TEST_F(BookmarkBarFolderControllerMenuTest, MenuSizingAndScrollArrows) {
- BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
- const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::string model_string("1b 2b 3b ");
- model_test_utils::AddNodesFromModelString(model, root, model_string);
-
- // Validate initial model.
- std::string actualModelString = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(model_string, actualModelString);
-
- const BookmarkNode* parent = model.GetBookmarkBarNode();
- const BookmarkNode* folder = model.AddGroup(parent,
- parent->GetChildCount(),
- ASCIIToUTF16("BIG"));
-
- // Pop open the new folder window and verify it has one (empty) item.
- BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"BIG"];
- [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
- withObject:button];
- BookmarkBarFolderController* folderController = [bar_ folderController];
- EXPECT_TRUE(folderController);
- NSWindow* folderMenu = [folderController window];
- EXPECT_TRUE(folderMenu);
- CGFloat expectedHeight = (CGFloat)bookmarks::kBookmarkButtonHeight +
- (2*bookmarks::kBookmarkVerticalPadding);
- NSRect menuFrame = [folderMenu frame];
- CGFloat menuHeight = NSHeight(menuFrame);
- EXPECT_CGFLOAT_EQ(expectedHeight, menuHeight);
- EXPECT_FALSE([folderController scrollable]);
-
- // Now add a real bookmark and reopen.
- model.AddURL(folder, folder->GetChildCount(), ASCIIToUTF16("a"),
- GURL("http://a.com/"));
- folderController = [bar_ folderController];
- EXPECT_TRUE(folderController);
- folderMenu = [folderController window];
- EXPECT_TRUE(folderMenu);
- menuFrame = [folderMenu frame];
- menuHeight = NSHeight(menuFrame);
- EXPECT_CGFLOAT_EQ(expectedHeight, menuHeight);
- CGFloat menuWidth = NSWidth(menuFrame);
- button = [folderController buttonWithTitleEqualTo:@"a"];
- CGFloat buttonWidth = NSWidth([button frame]);
- CGFloat expectedWidth =
- buttonWidth + (2 * bookmarks::kBookmarkSubMenuHorizontalPadding);
- EXPECT_CGFLOAT_EQ(expectedWidth, menuWidth);
-
- // Add a wider bookmark and make sure the button widths match.
- model.AddURL(folder, folder->GetChildCount(),
- ASCIIToUTF16("A really, really long name"),
- GURL("http://www.google.com/a"));
- EXPECT_LT(menuWidth, NSWidth([folderMenu frame]));
- EXPECT_LT(buttonWidth, NSWidth([button frame]));
- buttonWidth = NSWidth([button frame]);
- BookmarkButton* buttonB =
- [folderController buttonWithTitleEqualTo:@"A really, really long name"];
- EXPECT_TRUE(buttonB);
- CGFloat buttonWidthB = NSWidth([buttonB frame]);
- EXPECT_CGFLOAT_EQ(buttonWidth, buttonWidthB);
- // Add a bunch of bookmarks until the window grows no more, then check for
- // a scroll down arrow.
- CGFloat oldMenuHeight = 0.0; // It just has to be different for first run.
- menuHeight = NSHeight([folderMenu frame]);
- NSUInteger tripWire = 0; // Prevent a runaway.
- while (![folderController scrollable] && ++tripWire < 100) {
- model.AddURL(folder, folder->GetChildCount(), ASCIIToUTF16("B"),
- GURL("http://b.com/"));
- oldMenuHeight = menuHeight;
- menuHeight = NSHeight([folderMenu frame]);
- }
- EXPECT_TRUE([folderController scrollable]);
- EXPECT_TRUE([folderController canScrollUp]);
-
- // Remove one bookmark and make sure the scroll down arrow has been removed.
- // We'll remove the really long node so we can see if the buttons get resized.
- menuWidth = NSWidth([folderMenu frame]);
- buttonWidth = NSWidth([button frame]);
- model.Remove(folder, 1);
- EXPECT_FALSE([folderController scrollable]);
- EXPECT_FALSE([folderController canScrollUp]);
- EXPECT_FALSE([folderController canScrollDown]);
-
- // Check the size. It should have reduced.
- EXPECT_GT(menuWidth, NSWidth([folderMenu frame]));
- EXPECT_GT(buttonWidth, NSWidth([button frame]));
-
- // Check button spacing.
- [folderController validateMenuSpacing];
-}
-
-// See http://crbug.com/46101
-TEST_F(BookmarkBarFolderControllerMenuTest, HoverThenDeleteBookmark) {
- BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
- const BookmarkNode* root = model.GetBookmarkBarNode();
- const BookmarkNode* folder = model.AddGroup(root,
- root->GetChildCount(),
- ASCIIToUTF16("BIG"));
- for (int i = 0; i < kLotsOfNodesCount; i++)
- model.AddURL(folder, folder->GetChildCount(), ASCIIToUTF16("kid"),
- GURL("http://kid.com/smile"));
-
- // Pop open the new folder window and hover one of its kids.
- BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"BIG"];
- [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
- withObject:button];
- BookmarkBarFolderController* bbfc = [bar_ folderController];
- NSArray* buttons = [bbfc buttons];
-
- // Hover over a button and verify that it is now known.
- button = [buttons objectAtIndex:3];
- BookmarkButton* buttonThatMouseIsIn = [bbfc buttonThatMouseIsIn];
- EXPECT_FALSE(buttonThatMouseIsIn);
- [bbfc mouseEnteredButton:button event:nil];
- buttonThatMouseIsIn = [bbfc buttonThatMouseIsIn];
- EXPECT_EQ(button, buttonThatMouseIsIn);
-
- // Delete the bookmark and verify that it is now not known.
- model.Remove(folder, 3);
- buttonThatMouseIsIn = [bbfc buttonThatMouseIsIn];
- EXPECT_FALSE(buttonThatMouseIsIn);
-}
-
-// Just like a BookmarkBarFolderController but intercedes when providing
-// pasteboard drag data.
-@interface BookmarkBarFolderControllerDragData : BookmarkBarFolderController {
- const BookmarkNode* dragDataNode_; // Weak
-}
-- (void)setDragDataNode:(const BookmarkNode*)node;
-@end
-
-@implementation BookmarkBarFolderControllerDragData
-
-- (id)initWithParentButton:(BookmarkButton*)button
- parentController:(BookmarkBarFolderController*)parentController
- barController:(BookmarkBarController*)barController {
- if ((self = [super initWithParentButton:button
- parentController:parentController
- barController:barController])) {
- dragDataNode_ = NULL;
- }
- return self;
-}
-
-- (void)setDragDataNode:(const BookmarkNode*)node {
- dragDataNode_ = node;
-}
-
-- (std::vector<const BookmarkNode*>)retrieveBookmarkNodeData {
- std::vector<const BookmarkNode*> dragDataNodes;
- if(dragDataNode_) {
- dragDataNodes.push_back(dragDataNode_);
- }
- return dragDataNodes;
-}
-
-@end
-
-TEST_F(BookmarkBarFolderControllerMenuTest, DragBookmarkData) {
- BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
- const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
- "2f3b ] 3b 4b ");
- model_test_utils::AddNodesFromModelString(model, root, model_string);
- const BookmarkNode* other = model.other_node();
- const std::string other_string("O1b O2b O3f:[ O3f1b O3f2f ] "
- "O4f:[ O4f1b O4f2f ] 05b ");
- model_test_utils::AddNodesFromModelString(model, other, other_string);
-
- // Validate initial model.
- std::string actual = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(model_string, actual);
- actual = model_test_utils::ModelStringFromNode(other);
- EXPECT_EQ(other_string, actual);
-
- // Pop open a folder.
- BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"];
- scoped_nsobject<BookmarkBarFolderControllerDragData> folderController;
- folderController.reset([[BookmarkBarFolderControllerDragData alloc]
- initWithParentButton:button
- parentController:nil
- barController:bar_]);
- BookmarkButton* targetButton =
- [folderController buttonWithTitleEqualTo:@"2f1b"];
- ASSERT_TRUE(targetButton);
-
- // Gen up some dragging data.
- const BookmarkNode* newNode = other->GetChild(2);
- [folderController setDragDataNode:newNode];
- scoped_nsobject<FakedDragInfo> dragInfo([[FakedDragInfo alloc] init]);
- [dragInfo setDropLocation:[targetButton top]];
- [folderController dragBookmarkData:(id<NSDraggingInfo>)dragInfo.get()];
-
- // Verify the model.
- const std::string expected("1b 2f:[ O3f:[ O3f1b O3f2f ] 2f1b 2f2f:[ 2f2f1b "
- "2f2f2b 2f2f3b ] 2f3b ] 3b 4b ");
- actual = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(expected, actual);
-
- // Now drag over a folder button.
- targetButton = [folderController buttonWithTitleEqualTo:@"2f2f"];
- ASSERT_TRUE(targetButton);
- newNode = other->GetChild(2); // Should be O4f.
- EXPECT_EQ(newNode->GetTitle(), ASCIIToUTF16("O4f"));
- [folderController setDragDataNode:newNode];
- [dragInfo setDropLocation:[targetButton center]];
- [folderController dragBookmarkData:(id<NSDraggingInfo>)dragInfo.get()];
-
- // Verify the model.
- const std::string expectedA("1b 2f:[ O3f:[ O3f1b O3f2f ] 2f1b 2f2f:[ "
- "2f2f1b 2f2f2b 2f2f3b O4f:[ O4f1b O4f2f ] ] "
- "2f3b ] 3b 4b ");
- actual = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(expectedA, actual);
-
- // Check button spacing.
- [folderController validateMenuSpacing];
-}
-
-TEST_F(BookmarkBarFolderControllerMenuTest, DragBookmarkDataToTrash) {
- BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
- const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
- "2f3b ] 3b 4b ");
- model_test_utils::AddNodesFromModelString(model, root, model_string);
-
- // Validate initial model.
- std::string actual = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(model_string, actual);
-
- const BookmarkNode* folderNode = root->GetChild(1);
- int oldFolderChildCount = folderNode->GetChildCount();
-
- // Pop open a folder.
- BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"];
- scoped_nsobject<BookmarkBarFolderControllerDragData> folderController;
- folderController.reset([[BookmarkBarFolderControllerDragData alloc]
- initWithParentButton:button
- parentController:nil
- barController:bar_]);
-
- // Drag a button to the trash.
- BookmarkButton* buttonToDelete =
- [folderController buttonWithTitleEqualTo:@"2f1b"];
- ASSERT_TRUE(buttonToDelete);
- EXPECT_TRUE([folderController canDragBookmarkButtonToTrash:buttonToDelete]);
- [folderController didDragBookmarkToTrash:buttonToDelete];
-
- // There should be one less button in the folder.
- int newFolderChildCount = folderNode->GetChildCount();
- EXPECT_EQ(oldFolderChildCount - 1, newFolderChildCount);
- // Verify the model.
- const std::string expected("1b 2f:[ 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
- "2f3b ] 3b 4b ");
- actual = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(expected, actual);
-
- // Check button spacing.
- [folderController validateMenuSpacing];
-}
-
-TEST_F(BookmarkBarFolderControllerMenuTest, AddURLs) {
- BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
- const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
- "2f3b ] 3b 4b ");
- model_test_utils::AddNodesFromModelString(model, root, model_string);
-
- // Validate initial model.
- std::string actual = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(model_string, actual);
-
- // Pop open a folder.
- BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"];
- [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
- withObject:button];
- BookmarkBarFolderController* folderController = [bar_ folderController];
- EXPECT_TRUE(folderController);
- NSArray* buttons = [folderController buttons];
- EXPECT_TRUE(buttons);
-
- // Remember how many buttons are showing.
- int oldDisplayedButtons = [buttons count];
-
- BookmarkButton* targetButton =
- [folderController buttonWithTitleEqualTo:@"2f1b"];
- ASSERT_TRUE(targetButton);
-
- NSArray* urls = [NSArray arrayWithObjects: @"http://www.a.com/",
- @"http://www.b.com/", nil];
- NSArray* titles = [NSArray arrayWithObjects: @"SiteA", @"SiteB", nil];
- [folderController addURLs:urls withTitles:titles at:[targetButton top]];
-
- // There should two more buttons in the folder.
- int newDisplayedButtons = [buttons count];
- EXPECT_EQ(oldDisplayedButtons + 2, newDisplayedButtons);
- // Verify the model.
- const std::string expected("1b 2f:[ SiteA SiteB 2f1b 2f2f:[ 2f2f1b 2f2f2b "
- "2f2f3b ] 2f3b ] 3b 4b ");
- actual = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(expected, actual);
-
- // Check button spacing.
- [folderController validateMenuSpacing];
-}
-
-TEST_F(BookmarkBarFolderControllerMenuTest, DropPositionIndicator) {
- BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
- const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
- "2f3b ] 3b 4b ");
- model_test_utils::AddNodesFromModelString(model, root, model_string);
-
- // Validate initial model.
- std::string actual = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(model_string, actual);
-
- // Pop open the folder.
- BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"];
- [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
- withObject:button];
- BookmarkBarFolderController* folder = [bar_ folderController];
- EXPECT_TRUE(folder);
-
- // Test a series of points starting at the top of the folder.
- const CGFloat yOffset = 0.5 * bookmarks::kBookmarkVerticalPadding;
- BookmarkButton* targetButton = [folder buttonWithTitleEqualTo:@"2f1b"];
- ASSERT_TRUE(targetButton);
- NSPoint targetPoint = [targetButton top];
- CGFloat pos = [folder indicatorPosForDragToPoint:targetPoint];
- EXPECT_CGFLOAT_EQ(targetPoint.y + yOffset, pos);
- pos = [folder indicatorPosForDragToPoint:[targetButton bottom]];
- targetButton = [folder buttonWithTitleEqualTo:@"2f2f"];
- EXPECT_CGFLOAT_EQ([targetButton top].y + yOffset, pos);
- pos = [folder indicatorPosForDragToPoint:NSMakePoint(10,0)];
- targetButton = [folder buttonWithTitleEqualTo:@"2f3b"];
- EXPECT_CGFLOAT_EQ([targetButton bottom].y - yOffset, pos);
-}
-
-@interface BookmarkBarControllerNoDelete : BookmarkBarController
-- (IBAction)deleteBookmark:(id)sender;
-@end
-
-@implementation BookmarkBarControllerNoDelete
-- (IBAction)deleteBookmark:(id)sender {
- // NOP
-}
-@end
-
-class BookmarkBarFolderControllerClosingTest : public
- BookmarkBarFolderControllerMenuTest {
- public:
- BookmarkBarFolderControllerClosingTest() {
- bar_.reset([[BookmarkBarControllerNoDelete alloc]
- initWithBrowser:helper_.browser()
- initialWidth:NSWidth([parent_view_ frame])
- delegate:nil
- resizeDelegate:resizeDelegate_.get()]);
- InstallAndToggleBar(bar_.get());
- }
-};
-
-TEST_F(BookmarkBarFolderControllerClosingTest, DeleteClosesFolder) {
- BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
- const BookmarkNode* root = model.GetBookmarkBarNode();
- const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b ] "
- "2f3b ] 3b ");
- model_test_utils::AddNodesFromModelString(model, root, model_string);
-
- // Validate initial model.
- std::string actualModelString = model_test_utils::ModelStringFromNode(root);
- EXPECT_EQ(model_string, actualModelString);
-
- // Open the folder menu and submenu.
- BookmarkButton* target = [bar_ buttonWithTitleEqualTo:@"2f"];
- ASSERT_TRUE(target);
- [[target target] performSelector:@selector(openBookmarkFolderFromButton:)
- withObject:target];
- BookmarkBarFolderController* folder = [bar_ folderController];
- EXPECT_TRUE(folder);
- BookmarkButton* subTarget = [folder buttonWithTitleEqualTo:@"2f2f"];
- ASSERT_TRUE(subTarget);
- [[subTarget target] performSelector:@selector(openBookmarkFolderFromButton:)
- withObject:subTarget];
- BookmarkBarFolderController* subFolder = [folder folderController];
- EXPECT_TRUE(subFolder);
-
- // Delete the folder node and verify the window closed down by looking
- // for its controller again.
- [folder deleteBookmark:folder];
- EXPECT_FALSE([folder folderController]);
-}
-
-// TODO(jrg): draggingEntered: and draggingExited: trigger timers so
-// they are hard to test. Factor out "fire timers" into routines
-// which can be overridden to fire immediately to make behavior
-// confirmable.
-// There is a similar problem with mouseEnteredButton: and
-// mouseExitedButton:.
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_hover_state.h b/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_hover_state.h
deleted file mode 100644
index 21d0658..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_hover_state.h
+++ /dev/null
@@ -1,78 +0,0 @@
-// 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 "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_button.h"
-
-// Hover state machine. Encapsulates the hover state for
-// BookmarkBarFolderController.
-// A strict call order is implied with these calls. It is ONLY valid to make
-// the following state transitions:
-// From: To: Via:
-// closed opening scheduleOpen...:
-// opening closed cancelPendingOpen...: or
-// open scheduleOpen...: completes.
-// open closing scheduleClose...:
-// closing open cancelPendingClose...: or
-// closed scheduleClose...: completes.
-//
-@interface BookmarkBarFolderHoverState : NSObject {
- @private
- // Enumeration of the valid states that the |hoverButton_| member can be in.
- // Because the opening and closing of hover views can be done asyncronously
- // there are periods where the hover state is in transtion between open and
- // closed. During those times of transition the opening or closing operation
- // can be cancelled. We serialize the opening and closing of the
- // |hoverButton_| using this state information. This serialization is to
- // avoid race conditions where one hover button is being opened while another
- // is closing.
- enum HoverState {
- kHoverStateClosed = 0,
- kHoverStateOpening = 1,
- kHoverStateOpen = 2,
- kHoverStateClosing = 3
- };
-
- // Like normal menus, hovering over a folder button causes it to
- // open. This variable is set when a hover is initiated (but has
- // not necessarily fired yet).
- scoped_nsobject<BookmarkButton> hoverButton_;
-
- // We model hover state as a state machine with specific allowable
- // transitions. |hoverState_| is the state of this machine at any
- // given time.
- HoverState hoverState_;
-}
-
-// Designated initializer.
-- (id)init;
-
-// The BookmarkBarFolderHoverState decides when it is appropriate to hide
-// and show the button that the BookmarkBarFolderController drags over.
-- (NSDragOperation)draggingEnteredButton:(BookmarkButton*)button;
-
-// The BookmarkBarFolderHoverState decides the fate of the hover button
-// when the BookmarkBarFolderController's view is exited.
-- (void)draggingExited;
-
-@end
-
-// Exposing these for unit testing purposes. They are used privately in the
-// implementation as well.
-@interface BookmarkBarFolderHoverState(PrivateAPI)
-// State change APIs.
-- (void)scheduleCloseBookmarkFolderOnHoverButton;
-- (void)cancelPendingCloseBookmarkFolderOnHoverButton;
-- (void)scheduleOpenBookmarkFolderOnHoverButton:(BookmarkButton*)hoverButton;
-- (void)cancelPendingOpenBookmarkFolderOnHoverButton;
-@end
-
-// Exposing these for unit testing purposes. They are used only in tests.
-@interface BookmarkBarFolderHoverState(TestingAPI)
-// Accessors and setters for button and hover state.
-- (BookmarkButton*)hoverButton;
-- (HoverState)hoverState;
-@end
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_hover_state.mm b/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_hover_state.mm
deleted file mode 100644
index 2c6feee..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_hover_state.mm
+++ /dev/null
@@ -1,171 +0,0 @@
-// 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 "chrome/browser/cocoa/bookmarks/bookmark_bar_folder_hover_state.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_controller.h"
-
-@interface BookmarkBarFolderHoverState(Private)
-- (void)setHoverState:(HoverState)state;
-- (void)closeBookmarkFolderOnHoverButton:(BookmarkButton*)button;
-- (void)openBookmarkFolderOnHoverButton:(BookmarkButton*)button;
-@end
-
-@implementation BookmarkBarFolderHoverState
-
-- (id)init {
- if ((self = [super init])) {
- hoverState_ = kHoverStateClosed;
- }
- return self;
-}
-
-- (NSDragOperation)draggingEnteredButton:(BookmarkButton*)button {
- if ([button isFolder]) {
- if (hoverButton_ == button) {
- // CASE A: hoverButton_ == button implies we've dragged over
- // the same folder so no need to open or close anything new.
- } else if (hoverButton_ &&
- hoverButton_ != button) {
- // CASE B: we have a hoverButton_ but it is different from the new button.
- // This implies we've dragged over a new folder, so we'll close the old
- // and open the new.
- // Note that we only schedule the open or close if we have no other tasks
- // currently pending.
-
- if (hoverState_ == kHoverStateOpen) {
- // Close the old.
- [self scheduleCloseBookmarkFolderOnHoverButton];
- } else if (hoverState_ == kHoverStateClosed) {
- // Open the new.
- [self scheduleOpenBookmarkFolderOnHoverButton:button];
- }
- } else if (!hoverButton_) {
- // CASE C: we don't have a current hoverButton_ but we have dragged onto
- // a new folder so we open the new one.
- [self scheduleOpenBookmarkFolderOnHoverButton:button];
- }
- } else if (!button) {
- if (hoverButton_) {
- // CASE D: We have a hoverButton_ but we've moved onto an area that
- // requires no hover. We close the hoverButton_ in this case. This
- // means cancelling if the open is pending (i.e. |kHoverStateOpening|)
- // or closing if we don't alrealy have once in progress.
-
- // Intiate close only if we have not already done so.
- if (hoverState_ == kHoverStateOpening) {
- // Cancel the pending open.
- [self cancelPendingOpenBookmarkFolderOnHoverButton];
- } else if (hoverState_ != kHoverStateClosing) {
- // Schedule the close.
- [self scheduleCloseBookmarkFolderOnHoverButton];
- }
- } else {
- // CASE E: We have neither a hoverButton_ nor a new button that requires
- // a hover. In this case we do nothing.
- }
- }
-
- return NSDragOperationMove;
-}
-
-- (void)draggingExited {
- if (hoverButton_) {
- if (hoverState_ == kHoverStateOpening) {
- [self cancelPendingOpenBookmarkFolderOnHoverButton];
- } else if (hoverState_ == kHoverStateClosing) {
- [self cancelPendingCloseBookmarkFolderOnHoverButton];
- }
- }
-}
-
-// Schedule close of hover button. Transition to kHoverStateClosing state.
-- (void)scheduleCloseBookmarkFolderOnHoverButton {
- DCHECK(hoverButton_);
- [self setHoverState:kHoverStateClosing];
- [self performSelector:@selector(closeBookmarkFolderOnHoverButton:)
- withObject:hoverButton_
- afterDelay:bookmarks::kDragHoverCloseDelay];
-}
-
-// Cancel pending hover close. Transition to kHoverStateOpen state.
-- (void)cancelPendingCloseBookmarkFolderOnHoverButton {
- [self setHoverState:kHoverStateOpen];
- [NSObject
- cancelPreviousPerformRequestsWithTarget:self
- selector:@selector(closeBookmarkFolderOnHoverButton:)
- object:hoverButton_];
-}
-
-// Schedule open of hover button. Transition to kHoverStateOpening state.
-- (void)scheduleOpenBookmarkFolderOnHoverButton:(BookmarkButton*)button {
- DCHECK(button);
- hoverButton_.reset([button retain]);
- [self setHoverState:kHoverStateOpening];
- [self performSelector:@selector(openBookmarkFolderOnHoverButton:)
- withObject:hoverButton_
- afterDelay:bookmarks::kDragHoverOpenDelay];
-}
-
-// Cancel pending hover open. Transition to kHoverStateClosed state.
-- (void)cancelPendingOpenBookmarkFolderOnHoverButton {
- [self setHoverState:kHoverStateClosed];
- [NSObject
- cancelPreviousPerformRequestsWithTarget:self
- selector:@selector(openBookmarkFolderOnHoverButton:)
- object:hoverButton_];
- hoverButton_.reset();
-}
-
-// Hover button accessor. For testing only.
-- (BookmarkButton*)hoverButton {
- return hoverButton_;
-}
-
-// Hover state accessor. For testing only.
-- (HoverState)hoverState {
- return hoverState_;
-}
-
-// This method encodes the rules of our |hoverButton_| state machine. Only
-// specific state transitions are allowable (encoded in the DCHECK).
-// Note that there is no state for simultaneously opening and closing. A
-// pending open must complete before scheduling a close, and vice versa. And
-// it is not possible to make a transition directly from open to closed, and
-// vice versa.
-- (void)setHoverState:(HoverState)state {
- DCHECK(
- (hoverState_ == kHoverStateClosed && state == kHoverStateOpening) ||
- (hoverState_ == kHoverStateOpening && state == kHoverStateClosed) ||
- (hoverState_ == kHoverStateOpening && state == kHoverStateOpen) ||
- (hoverState_ == kHoverStateOpen && state == kHoverStateClosing) ||
- (hoverState_ == kHoverStateClosing && state == kHoverStateOpen) ||
- (hoverState_ == kHoverStateClosing && state == kHoverStateClosed)
- ) << "bad transition: old = " << hoverState_ << " new = " << state;
-
- hoverState_ = state;
-}
-
-// Called after a delay to close a previously hover-opened folder.
-// Note: this method is not meant to be invoked directly, only through
-// a delayed call to |scheduleCloseBookmarkFolderOnHoverButton:|.
-- (void)closeBookmarkFolderOnHoverButton:(BookmarkButton*)button {
- [NSObject
- cancelPreviousPerformRequestsWithTarget:self
- selector:@selector(closeBookmarkFolderOnHoverButton:)
- object:hoverButton_];
- [self setHoverState:kHoverStateClosed];
- [[button target] closeBookmarkFolder:button];
- hoverButton_.reset();
-}
-
-// Called after a delay to open a new hover folder.
-// Note: this method is not meant to be invoked directly, only through
-// a delayed call to |scheduleOpenBookmarkFolderOnHoverButton:|.
-- (void)openBookmarkFolderOnHoverButton:(BookmarkButton*)button {
- [self setHoverState:kHoverStateOpen];
- [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
- withObject:button];
-}
-
-@end
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_hover_state_unittest.mm b/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_hover_state_unittest.mm
deleted file mode 100644
index bcd1293..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_hover_state_unittest.mm
+++ /dev/null
@@ -1,77 +0,0 @@
-// 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 "base/message_loop.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_controller.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_folder_hover_state.h"
-#import "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-
-namespace {
-
-typedef CocoaTest BookmarkBarFolderHoverStateTest;
-
-// Hover state machine interface.
-// A strict call order is implied with these calls. It is ONLY valid to make
-// these specific state transitions.
-TEST(BookmarkBarFolderHoverStateTest, HoverState) {
- BrowserTestHelper helper;
- scoped_nsobject<BookmarkBarFolderHoverState> bbfhs;
- bbfhs.reset([[BookmarkBarFolderHoverState alloc] init]);
-
- // Initial state.
- EXPECT_FALSE([bbfhs hoverButton]);
- ASSERT_EQ(kHoverStateClosed, [bbfhs hoverState]);
-
- scoped_nsobject<BookmarkButton> button;
- button.reset([[BookmarkButton alloc] initWithFrame:NSMakeRect(0, 0, 20, 20)]);
-
- // Test transition from closed to opening.
- ASSERT_EQ(kHoverStateClosed, [bbfhs hoverState]);
- [bbfhs scheduleOpenBookmarkFolderOnHoverButton:button];
- ASSERT_EQ(kHoverStateOpening, [bbfhs hoverState]);
-
- // Test transition from opening to closed (aka cancel open).
- [bbfhs cancelPendingOpenBookmarkFolderOnHoverButton];
- ASSERT_EQ(kHoverStateClosed, [bbfhs hoverState]);
- ASSERT_EQ(nil, [bbfhs hoverButton]);
-
- // Test transition from closed to opening.
- ASSERT_EQ(kHoverStateClosed, [bbfhs hoverState]);
- [bbfhs scheduleOpenBookmarkFolderOnHoverButton:button];
- ASSERT_EQ(kHoverStateOpening, [bbfhs hoverState]);
-
- // Test transition from opening to opened.
- MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- new MessageLoop::QuitTask,
- bookmarks::kDragHoverOpenDelay * 1000.0 * 1.5);
- MessageLoop::current()->Run();
- ASSERT_EQ(kHoverStateOpen, [bbfhs hoverState]);
- ASSERT_EQ(button, [bbfhs hoverButton]);
-
- // Test transition from opening to opened.
- [bbfhs scheduleCloseBookmarkFolderOnHoverButton];
- ASSERT_EQ(kHoverStateClosing, [bbfhs hoverState]);
-
- // Test transition from closing to open (aka cancel close).
- [bbfhs cancelPendingCloseBookmarkFolderOnHoverButton];
- ASSERT_EQ(kHoverStateOpen, [bbfhs hoverState]);
- ASSERT_EQ(button, [bbfhs hoverButton]);
-
- // Test transition from closing to closed.
- [bbfhs scheduleCloseBookmarkFolderOnHoverButton];
- ASSERT_EQ(kHoverStateClosing, [bbfhs hoverState]);
- MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- new MessageLoop::QuitTask,
- bookmarks::kDragHoverCloseDelay * 1000.0 * 1.5);
- MessageLoop::current()->Run();
- ASSERT_EQ(kHoverStateClosed, [bbfhs hoverState]);
- ASSERT_EQ(nil, [bbfhs hoverButton]);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_view.mm b/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_view.mm
deleted file mode 100644
index 7cf18af..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_view.mm
+++ /dev/null
@@ -1,204 +0,0 @@
-// 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 "chrome/browser/cocoa/bookmarks/bookmark_bar_folder_view.h"
-
-#include "chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_controller.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_folder_target.h"
-#include "chrome/browser/metrics/user_metrics.h"
-#import "third_party/mozilla/NSPasteboard+Utils.h"
-
-@implementation BookmarkBarFolderView
-
-@synthesize dropIndicatorShown = dropIndicatorShown_;
-@synthesize dropIndicatorPosition = dropIndicatorPosition_;
-
-- (void)awakeFromNib {
- NSArray* types = [NSArray arrayWithObjects:
- NSStringPboardType,
- NSHTMLPboardType,
- NSURLPboardType,
- kBookmarkButtonDragType,
- kBookmarkDictionaryListPboardType,
- nil];
- [self registerForDraggedTypes:types];
-}
-
-- (void)dealloc {
- [self unregisterDraggedTypes];
- [super dealloc];
-}
-
-- (id<BookmarkButtonControllerProtocol>)controller {
- // When needed for testing, set the local data member |controller_| to
- // the test controller.
- return controller_ ? controller_ : [[self window] windowController];
-}
-
-- (void)setController:(id)controller {
- controller_ = controller;
-}
-
-- (void)drawRect:(NSRect)rect {
- // TODO(jrg): copied from bookmark_bar_view but orientation changed.
- // Code dup sucks but I'm not sure I can take 16 lines and make it
- // generic for horiz vs vertical while keeping things simple.
- // TODO(jrg): when throwing it all away and using animations, try
- // hard to make a common routine for both.
- // http://crbug.com/35966, http://crbug.com/35968
-
- // Draw the bookmark-button-dragging drop indicator if necessary.
- if (dropIndicatorShown_) {
- const CGFloat kBarHeight = 1;
- const CGFloat kBarHorizPad = 4;
- const CGFloat kBarOpacity = 0.85;
-
- NSRect uglyBlackBar =
- NSMakeRect(kBarHorizPad, dropIndicatorPosition_,
- NSWidth([self bounds]) - 2*kBarHorizPad,
- kBarHeight);
- NSColor* uglyBlackBarColor = [NSColor blackColor];
- [[uglyBlackBarColor colorWithAlphaComponent:kBarOpacity] setFill];
- [[NSBezierPath bezierPathWithRect:uglyBlackBar] fill];
- }
-}
-
-// TODO(mrossetti,jrg): Identical to -[BookmarkBarView
-// dragClipboardContainsBookmarks]. http://crbug.com/35966
-// Shim function to assist in unit testing.
-- (BOOL)dragClipboardContainsBookmarks {
- return bookmark_pasteboard_helper_mac::DragClipboardContainsBookmarks();
-}
-
-// Virtually identical to [BookmarkBarView draggingEntered:].
-// TODO(jrg): find a way to share code. Lack of multiple inheritance
-// makes things more of a pain but there should be no excuse for laziness.
-// http://crbug.com/35966
-- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info {
- inDrag_ = YES;
- if ([[info draggingPasteboard] dataForType:kBookmarkButtonDragType] ||
- [self dragClipboardContainsBookmarks] ||
- [[info draggingPasteboard] containsURLData]) {
- // Find the position of the drop indicator.
- BOOL showIt = [[self controller]
- shouldShowIndicatorShownForPoint:[info draggingLocation]];
- if (!showIt) {
- if (dropIndicatorShown_) {
- dropIndicatorShown_ = NO;
- [self setNeedsDisplay:YES];
- }
- } else {
- CGFloat y =
- [[self controller]
- indicatorPosForDragToPoint:[info draggingLocation]];
-
- // Need an update if the indicator wasn't previously shown or if it has
- // moved.
- if (!dropIndicatorShown_ || dropIndicatorPosition_ != y) {
- dropIndicatorShown_ = YES;
- dropIndicatorPosition_ = y;
- [self setNeedsDisplay:YES];
- }
- }
-
- [[self controller] draggingEntered:info]; // allow hover-open to work
- return [info draggingSource] ? NSDragOperationMove : NSDragOperationCopy;
- }
- return NSDragOperationNone;
-}
-
-- (void)draggingExited:(id<NSDraggingInfo>)info {
- [[self controller] draggingExited:info];
-
- // Regardless of the type of dragging which ended, we need to get rid of the
- // drop indicator if one was shown.
- if (dropIndicatorShown_) {
- dropIndicatorShown_ = NO;
- [self setNeedsDisplay:YES];
- }
-}
-
-- (void)draggingEnded:(id<NSDraggingInfo>)info {
- // Awkwardness since views open and close out from under us.
- if (inDrag_) {
- inDrag_ = NO;
- }
-
- [self draggingExited:info];
-}
-
-- (BOOL)wantsPeriodicDraggingUpdates {
- // TODO(jrg): This should probably return |YES| and the controller should
- // slide the existing bookmark buttons interactively to the side to make
- // room for the about-to-be-dropped bookmark.
- // http://crbug.com/35968
- return NO;
-}
-
-- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)info {
- // For now it's the same as draggingEntered:.
- // TODO(jrg): once we return YES for wantsPeriodicDraggingUpdates,
- // this should ping the [self controller] to perform animations.
- // http://crbug.com/35968
- return [self draggingEntered:info];
-}
-
-- (BOOL)prepareForDragOperation:(id<NSDraggingInfo>)info {
- return YES;
-}
-
-// This code is practically identical to the same function in BookmarkBarView
-// with the only difference being how the controller is retrieved.
-// TODO(mrossetti,jrg): http://crbug.com/35966
-// Implement NSDraggingDestination protocol method
-// performDragOperation: for URLs.
-- (BOOL)performDragOperationForURL:(id<NSDraggingInfo>)info {
- NSPasteboard* pboard = [info draggingPasteboard];
- DCHECK([pboard containsURLData]);
-
- NSArray* urls = nil;
- NSArray* titles = nil;
- [pboard getURLs:&urls andTitles:&titles convertingFilenames:YES];
-
- return [[self controller] addURLs:urls
- withTitles:titles
- at:[info draggingLocation]];
-}
-
-// This code is practically identical to the same function in BookmarkBarView
-// with the only difference being how the controller is retrieved.
-// http://crbug.com/35966
-// Implement NSDraggingDestination protocol method
-// performDragOperation: for bookmark buttons.
-- (BOOL)performDragOperationForBookmarkButton:(id<NSDraggingInfo>)info {
- BOOL doDrag = NO;
- NSData* data = [[info draggingPasteboard]
- dataForType:kBookmarkButtonDragType];
- // [info draggingSource] is nil if not the same application.
- if (data && [info draggingSource]) {
- BookmarkButton* button = nil;
- [data getBytes:&button length:sizeof(button)];
- BOOL copy = !([info draggingSourceOperationMask] & NSDragOperationMove);
- doDrag = [[self controller] dragButton:button
- to:[info draggingLocation]
- copy:copy];
- UserMetrics::RecordAction(UserMetricsAction("BookmarkBarFolder_DragEnd"));
- }
- return doDrag;
-}
-
-- (BOOL)performDragOperation:(id<NSDraggingInfo>)info {
- if ([[self controller] dragBookmarkData:info])
- return YES;
- NSPasteboard* pboard = [info draggingPasteboard];
- if ([pboard dataForType:kBookmarkButtonDragType] &&
- [self performDragOperationForBookmarkButton:info])
- return YES;
- if ([pboard containsURLData] && [self performDragOperationForURL:info])
- return YES;
- return NO;
-}
-
-@end
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_view_unittest.mm b/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_view_unittest.mm
deleted file mode 100644
index 9abe55a..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_view_unittest.mm
+++ /dev/null
@@ -1,211 +0,0 @@
-// 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.
-
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_controller.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_folder_view.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_button.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_folder_target.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/url_drop_target.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-#import "third_party/mozilla/NSPasteboard+Utils.h"
-
-namespace {
- const CGFloat kFakeIndicatorPos = 7.0;
-};
-
-// Fake DraggingInfo, fake BookmarkBarController, fake NSPasteboard...
-@interface FakeDraggingInfo : NSObject {
- @public
- BOOL dragButtonToPong_;
- BOOL dragURLsPong_;
- BOOL dragBookmarkDataPong_;
- BOOL dropIndicatorShown_;
- BOOL draggingEnteredCalled_;
- // Only mock one type of drag data at a time.
- NSString* dragDataType_;
-}
-@property (readwrite) BOOL dropIndicatorShown;
-@property (readwrite) BOOL draggingEnteredCalled;
-@property (copy) NSString* dragDataType;
-@end
-
-@implementation FakeDraggingInfo
-
-@synthesize dropIndicatorShown = dropIndicatorShown_;
-@synthesize draggingEnteredCalled = draggingEnteredCalled_;
-@synthesize dragDataType = dragDataType_;
-
-- (id)init {
- if ((self = [super init])) {
- dropIndicatorShown_ = YES;
- }
- return self;
-}
-
-- (void)dealloc {
- [dragDataType_ release];
- [super dealloc];
-}
-
-- (void)reset {
- [dragDataType_ release];
- dragDataType_ = nil;
- dragButtonToPong_ = NO;
- dragURLsPong_ = NO;
- dragBookmarkDataPong_ = NO;
- dropIndicatorShown_ = YES;
- draggingEnteredCalled_ = NO;
-}
-
-// NSDragInfo mocking functions.
-
-- (id)draggingPasteboard {
- return self;
-}
-
-// So we can look local.
-- (id)draggingSource {
- return self;
-}
-
-- (NSDragOperation)draggingSourceOperationMask {
- return NSDragOperationCopy | NSDragOperationMove;
-}
-
-- (NSPoint)draggingLocation {
- return NSMakePoint(10, 10);
-}
-
-// NSPasteboard mocking functions.
-
-- (BOOL)containsURLData {
- NSArray* urlTypes = [URLDropTargetHandler handledDragTypes];
- if (dragDataType_)
- return [urlTypes containsObject:dragDataType_];
- return NO;
-}
-
-- (NSData*)dataForType:(NSString*)type {
- if (dragDataType_ && [dragDataType_ isEqualToString:type])
- return [NSData data]; // Return something, anything.
- return nil;
-}
-
-// Fake a controller for callback ponging
-
-- (BOOL)dragButton:(BookmarkButton*)button to:(NSPoint)point copy:(BOOL)copy {
- dragButtonToPong_ = YES;
- return YES;
-}
-
-- (BOOL)addURLs:(NSArray*)urls withTitles:(NSArray*)titles at:(NSPoint)point {
- dragURLsPong_ = YES;
- return YES;
-}
-
-- (void)getURLs:(NSArray**)outUrls
- andTitles:(NSArray**)outTitles
- convertingFilenames:(BOOL)convertFilenames {
-}
-
-- (BOOL)dragBookmarkData:(id<NSDraggingInfo>)info {
- dragBookmarkDataPong_ = YES;
- return NO;
-}
-
-// Confirm the pongs.
-
-- (BOOL)dragButtonToPong {
- return dragButtonToPong_;
-}
-
-- (BOOL)dragURLsPong {
- return dragURLsPong_;
-}
-
-- (BOOL)dragBookmarkDataPong {
- return dragBookmarkDataPong_;
-}
-
-- (CGFloat)indicatorPosForDragToPoint:(NSPoint)point {
- return kFakeIndicatorPos;
-}
-
-- (BOOL)shouldShowIndicatorShownForPoint:(NSPoint)point {
- return dropIndicatorShown_;
-}
-
-- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info {
- draggingEnteredCalled_ = YES;
- return NSDragOperationNone;
-}
-
-@end
-
-namespace {
-
-class BookmarkBarFolderViewTest : public CocoaTest {
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
- view_.reset([[BookmarkBarFolderView alloc] init]);
- }
-
- scoped_nsobject<BookmarkBarFolderView> view_;
-};
-
-TEST_F(BookmarkBarFolderViewTest, BookmarkButtonDragAndDrop) {
- [view_ awakeFromNib];
- scoped_nsobject<FakeDraggingInfo> info([[FakeDraggingInfo alloc] init]);
- [view_ setController:info.get()];
- [info reset];
-
- [info setDragDataType:kBookmarkButtonDragType];
- EXPECT_EQ([view_ draggingEntered:(id)info.get()], NSDragOperationMove);
- EXPECT_TRUE([view_ performDragOperation:(id)info.get()]);
- EXPECT_TRUE([info dragButtonToPong]);
- EXPECT_FALSE([info dragURLsPong]);
- EXPECT_TRUE([info dragBookmarkDataPong]);
-}
-
-TEST_F(BookmarkBarFolderViewTest, URLDragAndDrop) {
- [view_ awakeFromNib];
- scoped_nsobject<FakeDraggingInfo> info([[FakeDraggingInfo alloc] init]);
- [view_ setController:info.get()];
- [info reset];
-
- NSArray* dragTypes = [URLDropTargetHandler handledDragTypes];
- for (NSString* type in dragTypes) {
- [info setDragDataType:type];
- EXPECT_EQ([view_ draggingEntered:(id)info.get()], NSDragOperationMove);
- EXPECT_TRUE([view_ performDragOperation:(id)info.get()]);
- EXPECT_FALSE([info dragButtonToPong]);
- EXPECT_TRUE([info dragURLsPong]);
- EXPECT_TRUE([info dragBookmarkDataPong]);
- [info reset];
- }
-}
-
-TEST_F(BookmarkBarFolderViewTest, BookmarkButtonDropIndicator) {
- [view_ awakeFromNib];
- scoped_nsobject<FakeDraggingInfo> info([[FakeDraggingInfo alloc] init]);
- [view_ setController:info.get()];
- [info reset];
-
- [info setDragDataType:kBookmarkButtonDragType];
- EXPECT_FALSE([info draggingEnteredCalled]);
- EXPECT_EQ([view_ draggingEntered:(id)info.get()], NSDragOperationMove);
- EXPECT_TRUE([info draggingEnteredCalled]); // Ensure controller pinged.
- EXPECT_TRUE([view_ dropIndicatorShown]);
- EXPECT_EQ([view_ dropIndicatorPosition], kFakeIndicatorPos);
-
- [info setDropIndicatorShown:NO];
- EXPECT_EQ([view_ draggingEntered:(id)info.get()], NSDragOperationMove);
- EXPECT_FALSE([view_ dropIndicatorShown]);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_window.h b/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_window.h
deleted file mode 100644
index 4b85277..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_window.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BAR_FOLDER_WINDOW_H_
-#define CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BAR_FOLDER_WINDOW_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-#import "base/cocoa_protocols_mac.h"
-#include "base/scoped_nsobject.h"
-
-
-// Window for a bookmark folder "menu". This menu pops up when you
-// click on a bookmark button that represents a folder of bookmarks.
-// This window is borderless.
-@interface BookmarkBarFolderWindow : NSWindow
-@end
-
-// Content view for the above window. "Stock" other than the drawing
-// of rounded corners. Only used in the nib.
-@interface BookmarkBarFolderWindowContentView : NSView {
- // Arrows to show ability to scroll up and down as needed.
- scoped_nsobject<NSImage> arrowUpImage_;
- scoped_nsobject<NSImage> arrowDownImage_;
-}
-@end
-
-// Scroll view that contains the main view (where the buttons go).
-@interface BookmarkBarFolderWindowScrollView : NSScrollView
-@end
-
-
-#endif // CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BAR_FOLDER_WINDOW_H_
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_window.mm b/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_window.mm
deleted file mode 100644
index 5e51a81..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_window.mm
+++ /dev/null
@@ -1,136 +0,0 @@
-// 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 "chrome/browser/cocoa/bookmarks/bookmark_bar_folder_window.h"
-
-#import "base/logging.h"
-#include "base/nsimage_cache_mac.h"
-#import "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_folder_controller.h"
-#import "chrome/browser/cocoa/image_utils.h"
-#import "third_party/GTM/AppKit/GTMNSColor+Luminance.h"
-#import "third_party/GTM/AppKit/GTMNSBezierPath+RoundRect.h"
-
-
-@implementation BookmarkBarFolderWindow
-
-- (id)initWithContentRect:(NSRect)contentRect
- styleMask:(NSUInteger)windowStyle
- backing:(NSBackingStoreType)bufferingType
- defer:(BOOL)deferCreation {
- if ((self = [super initWithContentRect:contentRect
- styleMask:NSBorderlessWindowMask // override
- backing:bufferingType
- defer:deferCreation])) {
- [self setBackgroundColor:[NSColor clearColor]];
- [self setOpaque:NO];
- }
- return self;
-}
-
-@end
-
-
-namespace {
-// Corner radius for our bookmark bar folder window.
-// Copied from bubble_view.mm.
-const CGFloat kViewCornerRadius = 4.0;
-}
-
-@implementation BookmarkBarFolderWindowContentView
-
-- (void)awakeFromNib {
- arrowUpImage_.reset([nsimage_cache::ImageNamed(@"menu_overflow_up.pdf")
- retain]);
- arrowDownImage_.reset([nsimage_cache::ImageNamed(@"menu_overflow_down.pdf")
- retain]);
-}
-
-// Draw the arrows at the top and bottom of the folder window as a
-// visual indication that scrolling is possible. We always draw the
-// scrolling arrows; when not relevant (e.g. when not scrollable), the
-// scroll view overlaps the window and the arrows aren't visible.
-- (void)drawScrollArrows:(NSRect)rect {
- NSRect visibleRect = [self bounds];
-
- // On top
- NSRect imageRect = NSZeroRect;
- imageRect.size = [arrowUpImage_ size];
- NSRect drawRect = NSOffsetRect(
- imageRect,
- (NSWidth(visibleRect) - NSWidth(imageRect)) / 2,
- NSHeight(visibleRect) - NSHeight(imageRect));
- [arrowUpImage_ drawInRect:drawRect
- fromRect:imageRect
- operation:NSCompositeSourceOver
- fraction:1.0
- neverFlipped:YES];
-
- // On bottom
- imageRect = NSZeroRect;
- imageRect.size = [arrowDownImage_ size];
- drawRect = NSOffsetRect(imageRect,
- (NSWidth(visibleRect) - NSWidth(imageRect)) / 2,
- 0);
- [arrowDownImage_ drawInRect:drawRect
- fromRect:imageRect
- operation:NSCompositeSourceOver
- fraction:1.0
- neverFlipped:YES];
-}
-
-- (void)drawRect:(NSRect)rect {
- NSRect bounds = [self bounds];
- // Like NSMenus, only the bottom corners are rounded.
- NSBezierPath* bezier =
- [NSBezierPath gtm_bezierPathWithRoundRect:bounds
- topLeftCornerRadius:0
- topRightCornerRadius:0
- bottomLeftCornerRadius:kViewCornerRadius
- bottomRightCornerRadius:kViewCornerRadius];
- [bezier closePath];
-
- // TODO(jrg): share code with info_bubble_view.mm? Or bubble_view.mm?
- NSColor* base_color = [NSColor colorWithCalibratedWhite:0.5 alpha:1.0];
- NSColor* startColor =
- [base_color gtm_colorAdjustedFor:GTMColorationLightHighlight
- faded:YES];
- NSColor* midColor =
- [base_color gtm_colorAdjustedFor:GTMColorationLightMidtone
- faded:YES];
- NSColor* endColor =
- [base_color gtm_colorAdjustedFor:GTMColorationLightShadow
- faded:YES];
- NSColor* glowColor =
- [base_color gtm_colorAdjustedFor:GTMColorationLightPenumbra
- faded:YES];
-
- scoped_nsobject<NSGradient> gradient(
- [[NSGradient alloc] initWithColorsAndLocations:startColor, 0.0,
- midColor, 0.25,
- endColor, 0.5,
- glowColor, 0.75,
- nil]);
- [gradient drawInBezierPath:bezier angle:0.0];
-
- [self drawScrollArrows:rect];
-}
-
-@end
-
-
-@implementation BookmarkBarFolderWindowScrollView
-
-// We want "draw background" of the NSScrollView in the xib to be NOT
-// checked. That allows us to round the bottom corners of the folder
-// window. However that also allows some scrollWheel: events to leak
-// into the NSWindow behind it (even in a different application).
-// Better to plug the scroll leak than to round corners for M5.
-- (void)scrollWheel:(NSEvent *)theEvent {
- DCHECK([[[self window] windowController]
- respondsToSelector:@selector(scrollWheel:)]);
- [[[self window] windowController] scrollWheel:theEvent];
-}
-
-@end
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_window_unittest.mm b/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_window_unittest.mm
deleted file mode 100644
index d291390..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_window_unittest.mm
+++ /dev/null
@@ -1,49 +0,0 @@
-// 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.
-
-#include "base/scoped_ptr.h"
-#include "chrome/browser/cocoa/bookmarks/bookmark_bar_folder_window.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-class BookmarkBarFolderWindowTest : public CocoaTest {
-};
-
-TEST_F(BookmarkBarFolderWindowTest, Borderless) {
- scoped_nsobject<BookmarkBarFolderWindow> window_;
- window_.reset([[BookmarkBarFolderWindow alloc]
- initWithContentRect:NSMakeRect(0,0,20,20)
- styleMask:0
- backing:NSBackingStoreBuffered
- defer:NO]);
- EXPECT_EQ(NSBorderlessWindowMask, [window_ styleMask]);
-}
-
-
-class BookmarkBarFolderWindowContentViewTest : public CocoaTest {
- public:
- BookmarkBarFolderWindowContentViewTest() {
- view_.reset([[BookmarkBarFolderWindowContentView alloc]
- initWithFrame:NSMakeRect(0, 0, 100, 100)]);
- [[test_window() contentView] addSubview:view_.get()];
- }
- scoped_nsobject<BookmarkBarFolderWindowContentView> view_;
- scoped_nsobject<BookmarkBarFolderWindowScrollView> scroll_view_;
-};
-
-TEST_VIEW(BookmarkBarFolderWindowContentViewTest, view_);
-
-
-class BookmarkBarFolderWindowScrollViewTest : public CocoaTest {
- public:
- BookmarkBarFolderWindowScrollViewTest() {
- scroll_view_.reset([[BookmarkBarFolderWindowScrollView alloc]
- initWithFrame:NSMakeRect(0, 0, 100, 100)]);
- [[test_window() contentView] addSubview:scroll_view_.get()];
- }
- scoped_nsobject<BookmarkBarFolderWindowScrollView> scroll_view_;
-};
-
-TEST_VIEW(BookmarkBarFolderWindowScrollViewTest, scroll_view_);
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_state.h b/chrome/browser/cocoa/bookmarks/bookmark_bar_state.h
deleted file mode 100644
index 4f98b5c..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_state.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BAR_STATE_H_
-#define CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BAR_STATE_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-namespace bookmarks {
-
-// States for the bookmark bar.
-enum VisualState {
- kInvalidState = 0,
- kHiddenState = 1,
- kShowingState = 2,
- kDetachedState = 3,
-};
-
-} // namespace bookmarks
-
-// The interface for controllers (etc.) which can give information about the
-// bookmark bar's state.
-@protocol BookmarkBarState
-
-// Returns YES if the bookmark bar is currently visible (as a normal toolbar or
-// as a detached bar on the NTP), NO otherwise.
-- (BOOL)isVisible;
-
-// Returns YES if an animation is currently running, NO otherwise.
-- (BOOL)isAnimationRunning;
-
-// Returns YES if the bookmark bar is in the given state and not in an
-// animation, NO otherwise.
-- (BOOL)isInState:(bookmarks::VisualState)state;
-
-// Returns YES if the bookmark bar is animating from the given state (to any
-// other state), NO otherwise.
-- (BOOL)isAnimatingToState:(bookmarks::VisualState)state;
-
-// Returns YES if the bookmark bar is animating to the given state (from any
-// other state), NO otherwise.
-- (BOOL)isAnimatingFromState:(bookmarks::VisualState)state;
-
-// Returns YES if the bookmark bar is animating from the first given state to
-// the second given state, NO otherwise.
-- (BOOL)isAnimatingFromState:(bookmarks::VisualState)fromState
- toState:(bookmarks::VisualState)toState;
-
-// Returns YES if the bookmark bar is animating between the two given states (in
-// either direction), NO otherwise.
-- (BOOL)isAnimatingBetweenState:(bookmarks::VisualState)fromState
- andState:(bookmarks::VisualState)toState;
-
-// Returns how morphed into the detached bubble the bookmark bar should be (1 =
-// completely detached, 0 = normal).
-- (CGFloat)detachedMorphProgress;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BAR_STATE_H_
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_toolbar_view.h b/chrome/browser/cocoa/bookmarks/bookmark_bar_toolbar_view.h
deleted file mode 100644
index cdc6e9c..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_toolbar_view.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// 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.
-
-// The BookmarkBarToolbarView is responsible for drawing the background of the
-// BookmarkBar's toolbar in either of its two display modes - permanently
-// attached (slimline with a stroke at the bottom edge) or New Tab Page style
-// (padded with a round rect border and the New Tab Page theme behind).
-
-#ifndef CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BAR_TOOLBAR_VIEW_H_
-#define CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BAR_TOOLBAR_VIEW_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#import "chrome/browser/cocoa/animatable_view.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_state.h"
-
-@class BookmarkBarView;
-class TabContents;
-class ThemeProvider;
-
-// An interface to allow mocking of a BookmarkBarController by the
-// BookmarkBarToolbarView.
-@protocol BookmarkBarToolbarViewController <BookmarkBarState>
-// Displaying the bookmark toolbar background in bubble (floating) mode requires
-// the size of the currently selected tab to properly calculate where the
-// background image is joined.
-- (int)currentTabContentsHeight;
-
-// Current theme provider, passed to the cross platform NtpBackgroundUtil class.
-- (ThemeProvider*)themeProvider;
-
-@end
-
-@interface BookmarkBarToolbarView : AnimatableView {
- @private
- // The controller which tells us how we should be drawing (as normal or as a
- // floating bar).
- IBOutlet id<BookmarkBarToolbarViewController> controller_;
-}
-@end
-
-#endif // CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BAR_TOOLBAR_VIEW_H_
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_toolbar_view.mm b/chrome/browser/cocoa/bookmarks/bookmark_bar_toolbar_view.mm
deleted file mode 100644
index 6abf516..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_toolbar_view.mm
+++ /dev/null
@@ -1,135 +0,0 @@
-// 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 "chrome/browser/cocoa/bookmarks/bookmark_bar_toolbar_view.h"
-
-#include "app/theme_provider.h"
-#include "gfx/rect.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_constants.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_controller.h"
-#import "chrome/browser/cocoa/browser_window_controller.h"
-#import "chrome/browser/cocoa/themed_window.h"
-#include "chrome/browser/ntp_background_util.h"
-#include "chrome/browser/themes/browser_theme_provider.h"
-#include "gfx/canvas_skia_paint.h"
-
-const CGFloat kBorderRadius = 3.0;
-
-@interface BookmarkBarToolbarView (Private)
-- (void)drawRectAsBubble:(NSRect)rect;
-@end
-
-@implementation BookmarkBarToolbarView
-
-- (BOOL)isOpaque {
- return [controller_ isInState:bookmarks::kDetachedState];
-}
-
-- (void)drawRect:(NSRect)rect {
- if ([controller_ isInState:bookmarks::kDetachedState] ||
- [controller_ isAnimatingToState:bookmarks::kDetachedState] ||
- [controller_ isAnimatingFromState:bookmarks::kDetachedState]) {
- [self drawRectAsBubble:rect];
- } else {
- NSPoint phase = [[self window] themePatternPhase];
- [[NSGraphicsContext currentContext] setPatternPhase:phase];
- [self drawBackground];
- }
-}
-
-- (void)drawRectAsBubble:(NSRect)rect {
- // The state of our morph; 1 is total bubble, 0 is the regular bar. We use it
- // to morph the bubble to a regular bar (shape and colour).
- CGFloat morph = [controller_ detachedMorphProgress];
-
- NSRect bounds = [self bounds];
-
- ThemeProvider* themeProvider = [controller_ themeProvider];
- if (!themeProvider)
- return;
-
- NSGraphicsContext* context = [NSGraphicsContext currentContext];
- [context saveGraphicsState];
-
- // Draw the background.
- {
- // CanvasSkiaPaint draws to the NSGraphicsContext during its destructor, so
- // explicitly scope this.
- //
- // Paint the entire bookmark bar, even if the damage rect is much smaller
- // because PaintBackgroundDetachedMode() assumes that area's origin is
- // (0, 0) and that its size is the size of the bookmark bar.
- //
- // In practice, this sounds worse than it is because redraw time is still
- // minimal compared to the pause between frames of animations. We were
- // already repainting the rest of the bookmark bar below without setting a
- // clip area, anyway. Also, the only time we weren't asked to redraw the
- // whole bookmark bar is when the find bar is drawn over it.
- gfx::CanvasSkiaPaint canvas(bounds, true);
- gfx::Rect area(0, 0, NSWidth(bounds), NSHeight(bounds));
-
- NtpBackgroundUtil::PaintBackgroundDetachedMode(themeProvider, &canvas,
- area, [controller_ currentTabContentsHeight]);
- }
-
- // Draw our bookmark bar border on top of the background.
- NSRect frameRect =
- NSMakeRect(
- morph * bookmarks::kNTPBookmarkBarPadding,
- morph * bookmarks::kNTPBookmarkBarPadding,
- NSWidth(bounds) - 2 * morph * bookmarks::kNTPBookmarkBarPadding,
- NSHeight(bounds) - 2 * morph * bookmarks::kNTPBookmarkBarPadding);
- // Now draw a bezier path with rounded rectangles around the area.
- frameRect = NSInsetRect(frameRect, morph * 0.5, morph * 0.5);
- NSBezierPath* border =
- [NSBezierPath bezierPathWithRoundedRect:frameRect
- xRadius:(morph * kBorderRadius)
- yRadius:(morph * kBorderRadius)];
-
- // Draw the rounded rectangle.
- NSColor* toolbarColor =
- themeProvider->GetNSColor(BrowserThemeProvider::COLOR_TOOLBAR, true);
- CGFloat alpha = morph * [toolbarColor alphaComponent];
- [[toolbarColor colorWithAlphaComponent:alpha] set]; // Set with opacity.
- [border fill];
-
- // Fade in/out the background.
- [context saveGraphicsState];
- [border setClip];
- CGContextRef cgContext = (CGContextRef)[context graphicsPort];
- CGContextBeginTransparencyLayer(cgContext, NULL);
- CGContextSetAlpha(cgContext, 1 - morph);
- [context setPatternPhase:[[self window] themePatternPhase]];
- [self drawBackground];
- CGContextEndTransparencyLayer(cgContext);
- [context restoreGraphicsState];
-
- // Draw the border of the rounded rectangle.
- NSColor* borderColor = themeProvider->GetNSColor(
- BrowserThemeProvider::COLOR_TOOLBAR_BUTTON_STROKE, true);
- alpha = morph * [borderColor alphaComponent];
- [[borderColor colorWithAlphaComponent:alpha] set]; // Set with opacity.
- [border stroke];
-
- // Fade in/out the divider.
- // TODO(viettrungluu): It's not obvious that this divider lines up exactly
- // with |BackgroundGradientView|'s (in fact, it probably doesn't).
- NSColor* strokeColor = [self strokeColor];
- alpha = (1 - morph) * [strokeColor alphaComponent];
- [[strokeColor colorWithAlphaComponent:alpha] set];
- NSBezierPath* divider = [NSBezierPath bezierPath];
- NSPoint dividerStart =
- NSMakePoint(morph * bookmarks::kNTPBookmarkBarPadding + morph * 0.5,
- morph * bookmarks::kNTPBookmarkBarPadding + morph * 0.5);
- CGFloat dividerWidth =
- NSWidth(bounds) - 2 * morph * bookmarks::kNTPBookmarkBarPadding - 2 * 0.5;
- [divider moveToPoint:dividerStart];
- [divider relativeLineToPoint:NSMakePoint(dividerWidth, 0)];
- [divider stroke];
-
- // Restore the graphics context.
- [context restoreGraphicsState];
-}
-
-@end // @implementation BookmarkBarToolbarView
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_toolbar_view_unittest.mm b/chrome/browser/cocoa/bookmarks/bookmark_bar_toolbar_view_unittest.mm
deleted file mode 100644
index aecdf84..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_toolbar_view_unittest.mm
+++ /dev/null
@@ -1,191 +0,0 @@
-// 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 "app/theme_provider.h"
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_controller.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_toolbar_view.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/themes/browser_theme_provider.h"
-#include "grit/theme_resources.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkColor.h"
-
-using ::testing::_;
-using ::testing::DoAll;
-using ::testing::Return;
-using ::testing::SetArgumentPointee;
-
-// When testing the floating drawing, we need to have a source of theme data.
-class MockThemeProvider : public ThemeProvider {
- public:
- // Cross platform methods
- MOCK_METHOD1(Init, void(Profile*));
- MOCK_CONST_METHOD1(GetBitmapNamed, SkBitmap*(int));
- MOCK_CONST_METHOD1(GetColor, SkColor(int));
- MOCK_CONST_METHOD2(GetDisplayProperty, bool(int, int*));
- MOCK_CONST_METHOD0(ShouldUseNativeFrame, bool());
- MOCK_CONST_METHOD1(HasCustomImage, bool(int));
- MOCK_CONST_METHOD1(GetRawData, RefCountedMemory*(int));
-
- // OSX stuff
- MOCK_CONST_METHOD2(GetNSImageNamed, NSImage*(int, bool));
- MOCK_CONST_METHOD2(GetNSImageColorNamed, NSColor*(int, bool));
- MOCK_CONST_METHOD2(GetNSColor, NSColor*(int, bool));
- MOCK_CONST_METHOD2(GetNSColorTint, NSColor*(int, bool));
- MOCK_CONST_METHOD1(GetNSGradient, NSGradient*(int));
-};
-
-// Allows us to inject our fake controller below.
-@interface BookmarkBarToolbarView (TestingAPI)
--(void)setController:(id<BookmarkBarToolbarViewController>)controller;
-@end
-
-@implementation BookmarkBarToolbarView (TestingAPI)
--(void)setController:(id<BookmarkBarToolbarViewController>)controller {
- controller_ = controller;
-}
-@end
-
-// Allows us to control which way the view is rendered.
-@interface DrawDetachedBarFakeController :
- NSObject<BookmarkBarState, BookmarkBarToolbarViewController> {
- @private
- int currentTabContentsHeight_;
- ThemeProvider* themeProvider_;
- bookmarks::VisualState visualState_;
-}
-@property (nonatomic, assign) int currentTabContentsHeight;
-@property (nonatomic, assign) ThemeProvider* themeProvider;
-@property (nonatomic, assign) bookmarks::VisualState visualState;
-
-// |BookmarkBarState| protocol:
-- (BOOL)isVisible;
-- (BOOL)isAnimationRunning;
-- (BOOL)isInState:(bookmarks::VisualState)state;
-- (BOOL)isAnimatingToState:(bookmarks::VisualState)state;
-- (BOOL)isAnimatingFromState:(bookmarks::VisualState)state;
-- (BOOL)isAnimatingFromState:(bookmarks::VisualState)fromState
- toState:(bookmarks::VisualState)toState;
-- (BOOL)isAnimatingBetweenState:(bookmarks::VisualState)fromState
- andState:(bookmarks::VisualState)toState;
-- (CGFloat)detachedMorphProgress;
-@end
-
-@implementation DrawDetachedBarFakeController
-@synthesize currentTabContentsHeight = currentTabContentsHeight_;
-@synthesize themeProvider = themeProvider_;
-@synthesize visualState = visualState_;
-
-- (id)init {
- if ((self = [super init])) {
- [self setVisualState:bookmarks::kHiddenState];
- }
- return self;
-}
-
-- (BOOL)isVisible { return YES; }
-- (BOOL)isAnimationRunning { return NO; }
-- (BOOL)isInState:(bookmarks::VisualState)state
- { return ([self visualState] == state) ? YES : NO; }
-- (BOOL)isAnimatingToState:(bookmarks::VisualState)state { return NO; }
-- (BOOL)isAnimatingFromState:(bookmarks::VisualState)state { return NO; }
-- (BOOL)isAnimatingFromState:(bookmarks::VisualState)fromState
- toState:(bookmarks::VisualState)toState { return NO; }
-- (BOOL)isAnimatingBetweenState:(bookmarks::VisualState)fromState
- andState:(bookmarks::VisualState)toState { return NO; }
-- (CGFloat)detachedMorphProgress { return 1; }
-@end
-
-class BookmarkBarToolbarViewTest : public CocoaTest {
- public:
- BookmarkBarToolbarViewTest() {
- controller_.reset([[DrawDetachedBarFakeController alloc] init]);
- NSRect frame = NSMakeRect(0, 0, 400, 40);
- scoped_nsobject<BookmarkBarToolbarView> view(
- [[BookmarkBarToolbarView alloc] initWithFrame:frame]);
- view_ = view.get();
- [[test_window() contentView] addSubview:view_];
- [view_ setController:controller_.get()];
- }
-
- scoped_nsobject<DrawDetachedBarFakeController> controller_;
- BookmarkBarToolbarView* view_;
-};
-
-TEST_VIEW(BookmarkBarToolbarViewTest, view_)
-
-// Test drawing (part 1), mostly to ensure nothing leaks or crashes.
-TEST_F(BookmarkBarToolbarViewTest, DisplayAsNormalBar) {
- [controller_.get() setVisualState:bookmarks::kShowingState];
- [view_ display];
-}
-
-// Test drawing (part 2), mostly to ensure nothing leaks or crashes.
-TEST_F(BookmarkBarToolbarViewTest, DisplayAsDetachedBarWithNoImage) {
- [controller_.get() setVisualState:bookmarks::kDetachedState];
-
- // Tests where we don't have a background image, only a color.
- MockThemeProvider provider;
- EXPECT_CALL(provider, GetColor(BrowserThemeProvider::COLOR_NTP_BACKGROUND))
- .WillRepeatedly(Return(SK_ColorWHITE));
- EXPECT_CALL(provider, HasCustomImage(IDR_THEME_NTP_BACKGROUND))
- .WillRepeatedly(Return(false));
- [controller_.get() setThemeProvider:&provider];
-
- [view_ display];
-}
-
-// Actions used in DisplayAsDetachedBarWithBgImage.
-ACTION(SetBackgroundTiling) {
- *arg1 = BrowserThemeProvider::NO_REPEAT;
- return true;
-}
-
-ACTION(SetAlignLeft) {
- *arg1 = BrowserThemeProvider::ALIGN_LEFT;
- return true;
-}
-
-// Test drawing (part 3), mostly to ensure nothing leaks or crashes.
-TEST_F(BookmarkBarToolbarViewTest, DisplayAsDetachedBarWithBgImage) {
- [controller_.get() setVisualState:bookmarks::kDetachedState];
-
- // Tests where we have a background image, with positioning information.
- MockThemeProvider provider;
-
- // Advertise having an image.
- EXPECT_CALL(provider, GetColor(BrowserThemeProvider::COLOR_NTP_BACKGROUND))
- .WillRepeatedly(Return(SK_ColorRED));
- EXPECT_CALL(provider, HasCustomImage(IDR_THEME_NTP_BACKGROUND))
- .WillRepeatedly(Return(true));
-
- // Return the correct tiling/alignment information.
- EXPECT_CALL(provider,
- GetDisplayProperty(BrowserThemeProvider::NTP_BACKGROUND_TILING, _))
- .WillRepeatedly(SetBackgroundTiling());
- EXPECT_CALL(provider,
- GetDisplayProperty(BrowserThemeProvider::NTP_BACKGROUND_ALIGNMENT, _))
- .WillRepeatedly(SetAlignLeft());
-
- // Create a dummy bitmap full of not-red to blit with.
- SkBitmap fake_bg;
- fake_bg.setConfig(SkBitmap::kARGB_8888_Config, 800, 800);
- fake_bg.allocPixels();
- fake_bg.eraseColor(SK_ColorGREEN);
- EXPECT_CALL(provider, GetBitmapNamed(IDR_THEME_NTP_BACKGROUND))
- .WillRepeatedly(Return(&fake_bg));
-
- [controller_.get() setThemeProvider:&provider];
- [controller_.get() setCurrentTabContentsHeight:200];
-
- [view_ display];
-}
-
-// TODO(viettrungluu): write more unit tests, especially after my refactoring.
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_unittest_helper.h b/chrome/browser/cocoa/bookmarks/bookmark_bar_unittest_helper.h
deleted file mode 100644
index edd60d2..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_unittest_helper.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BAR_UNITTEST_HELPER_H_
-#define CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BAR_UNITTEST_HELPER_H_
-#pragma once
-
-#import <Foundation/Foundation.h>
-
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_controller.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_folder_controller.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_button.h"
-
-@interface BookmarkBarController (BookmarkBarUnitTestHelper)
-
-// Return the bookmark button from this bar controller with the given
-// |title|, otherwise nil. This does not recurse into folders.
-- (BookmarkButton*)buttonWithTitleEqualTo:(NSString*)title;
-
-@end
-
-
-@interface BookmarkBarFolderController (BookmarkBarUnitTestHelper)
-
-// Return the bookmark button from this folder controller with the given
-// |title|, otherwise nil. This does not recurse into subfolders.
-- (BookmarkButton*)buttonWithTitleEqualTo:(NSString*)title;
-
-@end
-
-
-@interface BookmarkButton (BookmarkBarUnitTestHelper)
-
-// Return the center of the button in the base coordinate system of the
-// containing window. Useful for simulating mouse clicks or drags.
-- (NSPoint)center;
-
-// Return the top of the button in the base coordinate system of the
-// containing window.
-- (NSPoint)top;
-
-// Return the bottom of the button in the base coordinate system of the
-// containing window.
-- (NSPoint)bottom;
-
-// Return the center-left point of the button in the base coordinate system
-// of the containing window.
-- (NSPoint)left;
-
-// Return the center-right point of the button in the base coordinate system
-// of the containing window.
-- (NSPoint)right;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BAR_UNITTEST_HELPER_H_
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_unittest_helper.mm b/chrome/browser/cocoa/bookmarks/bookmark_bar_unittest_helper.mm
deleted file mode 100644
index c8eefdb..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_unittest_helper.mm
+++ /dev/null
@@ -1,81 +0,0 @@
-// 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 "chrome/browser/cocoa/bookmarks/bookmark_bar_unittest_helper.h"
-
-@interface NSArray (BookmarkBarUnitTestHelper)
-
-// A helper function for scanning an array of buttons looking for the
-// button with the given |title|.
-- (BookmarkButton*)buttonWithTitleEqualTo:(NSString*)title;
-
-@end
-
-
-@implementation NSArray (BookmarkBarUnitTestHelper)
-
-- (BookmarkButton*)buttonWithTitleEqualTo:(NSString*)title {
- for (BookmarkButton* button in self) {
- if ([[button title] isEqualToString:title])
- return button;
- }
- return nil;
-}
-
-@end
-
-@implementation BookmarkBarController (BookmarkBarUnitTestHelper)
-
-- (BookmarkButton*)buttonWithTitleEqualTo:(NSString*)title {
- return [[self buttons] buttonWithTitleEqualTo:title];
-}
-
-@end
-
-@implementation BookmarkBarFolderController(BookmarkBarUnitTestHelper)
-
-- (BookmarkButton*)buttonWithTitleEqualTo:(NSString*)title {
- return [[self buttons] buttonWithTitleEqualTo:title];
-}
-
-@end
-
-@implementation BookmarkButton(BookmarkBarUnitTestHelper)
-
-- (NSPoint)center {
- NSRect frame = [self frame];
- NSPoint center = NSMakePoint(NSMidX(frame), NSMidY(frame));
- center = [[self superview] convertPoint:center toView:nil];
- return center;
-}
-
-- (NSPoint)top {
- NSRect frame = [self frame];
- NSPoint top = NSMakePoint(NSMidX(frame), NSMaxY(frame));
- top = [[self superview] convertPoint:top toView:nil];
- return top;
-}
-
-- (NSPoint)bottom {
- NSRect frame = [self frame];
- NSPoint bottom = NSMakePoint(NSMidX(frame), NSMinY(frame));
- bottom = [[self superview] convertPoint:bottom toView:nil];
- return bottom;
-}
-
-- (NSPoint)left {
- NSRect frame = [self frame];
- NSPoint left = NSMakePoint(NSMinX(frame), NSMidY(frame));
- left = [[self superview] convertPoint:left toView:nil];
- return left;
-}
-
-- (NSPoint)right {
- NSRect frame = [self frame];
- NSPoint right = NSMakePoint(NSMaxX(frame), NSMidY(frame));
- right = [[self superview] convertPoint:right toView:nil];
- return right;
-}
-
-@end
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_view.h b/chrome/browser/cocoa/bookmarks/bookmark_bar_view.h
deleted file mode 100644
index a409171..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_view.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// 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.
-//
-// A simple custom NSView for the bookmark bar used to prevent clicking and
-// dragging from moving the browser window.
-
-#ifndef CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BAR_VIEW_H_
-#define CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BAR_VIEW_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#import "chrome/browser/cocoa/background_gradient_view.h"
-
-@class BookmarkBarController;
-
-@interface BookmarkBarView : BackgroundGradientView {
- @private
- BOOL dropIndicatorShown_;
- CGFloat dropIndicatorPosition_; // x position
-
- IBOutlet BookmarkBarController* controller_;
- IBOutlet NSTextField* noItemTextfield_;
- IBOutlet NSButton* importBookmarksButton_;
- NSView* noItemContainer_;
-}
-- (NSTextField*)noItemTextfield;
-- (NSButton*)importBookmarksButton;
-- (BookmarkBarController*)controller;
-
-@property (nonatomic, assign) IBOutlet NSView* noItemContainer;
-@end
-
-@interface BookmarkBarView() // TestingOrInternalAPI
-@property (nonatomic, readonly) BOOL dropIndicatorShown;
-@property (nonatomic, readonly) CGFloat dropIndicatorPosition;
-- (void)setController:(id)controller;
-@end
-
-#endif // CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BAR_VIEW_H_
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_view.mm b/chrome/browser/cocoa/bookmarks/bookmark_bar_view.mm
deleted file mode 100644
index 667cff1..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_view.mm
+++ /dev/null
@@ -1,259 +0,0 @@
-// 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 "chrome/browser/cocoa/bookmarks/bookmark_bar_view.h"
-
-#include "chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_controller.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_button.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_folder_target.h"
-#import "chrome/browser/cocoa/themed_window.h"
-#import "chrome/browser/cocoa/view_id_util.h"
-#include "chrome/browser/metrics/user_metrics.h"
-#import "chrome/browser/themes/browser_theme_provider.h"
-#import "third_party/mozilla/NSPasteboard+Utils.h"
-
-@interface BookmarkBarView (Private)
-- (void)themeDidChangeNotification:(NSNotification*)aNotification;
-- (void)updateTheme:(ThemeProvider*)themeProvider;
-@end
-
-@implementation BookmarkBarView
-
-@synthesize dropIndicatorShown = dropIndicatorShown_;
-@synthesize dropIndicatorPosition = dropIndicatorPosition_;
-@synthesize noItemContainer = noItemContainer_;
-
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- // This probably isn't strictly necessary, but can't hurt.
- [self unregisterDraggedTypes];
- [super dealloc];
-
- // To be clear, our controller_ is an IBOutlet and owns us, so we
- // don't deallocate it explicitly. It is owned by the browser
- // window controller, so gets deleted with a browser window is
- // closed.
-}
-
-- (void)awakeFromNib {
- NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
- [defaultCenter addObserver:self
- selector:@selector(themeDidChangeNotification:)
- name:kBrowserThemeDidChangeNotification
- object:nil];
-
- DCHECK(controller_) << "Expected this to be hooked up via Interface Builder";
- NSArray* types = [NSArray arrayWithObjects:
- NSStringPboardType,
- NSHTMLPboardType,
- NSURLPboardType,
- kBookmarkButtonDragType,
- kBookmarkDictionaryListPboardType,
- nil];
- [self registerForDraggedTypes:types];
-}
-
-// We need the theme to color the bookmark buttons properly. But our
-// controller desn't have access to it until it's placed in the view
-// hierarchy. This is the spot where we close the loop.
-- (void)viewWillMoveToWindow:(NSWindow*)window {
- ThemeProvider* themeProvider = [window themeProvider];
- [self updateTheme:themeProvider];
- [controller_ updateTheme:themeProvider];
-}
-
-- (void)viewDidMoveToWindow {
- [controller_ viewDidMoveToWindow];
-}
-
-// Called after the current theme has changed.
-- (void)themeDidChangeNotification:(NSNotification*)aNotification {
- ThemeProvider* themeProvider =
- static_cast<ThemeProvider*>([[aNotification object] pointerValue]);
- [self updateTheme:themeProvider];
-}
-
-// Adapt appearance to the current theme. Called after theme changes and before
-// this is shown for the first time.
-- (void)updateTheme:(ThemeProvider*)themeProvider {
- if (!themeProvider)
- return;
-
- NSColor* color =
- themeProvider->GetNSColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT,
- true);
- [noItemTextfield_ setTextColor:color];
-}
-
-// Mouse down events on the bookmark bar should not allow dragging the parent
-// window around.
-- (BOOL)mouseDownCanMoveWindow {
- return NO;
-}
-
--(NSTextField*)noItemTextfield {
- return noItemTextfield_;
-}
-
--(NSButton*)importBookmarksButton {
- return importBookmarksButton_;
-}
-
-- (BookmarkBarController*)controller {
- return controller_;
-}
-
--(void)drawRect:(NSRect)dirtyRect {
- [super drawRect:dirtyRect];
-
- // Draw the bookmark-button-dragging drop indicator if necessary.
- if (dropIndicatorShown_) {
- const CGFloat kBarWidth = 1;
- const CGFloat kBarHalfWidth = kBarWidth / 2.0;
- const CGFloat kBarVertPad = 4;
- const CGFloat kBarOpacity = 0.85;
-
- // Prevent the indicator from being clipped on the left.
- CGFloat xLeft = MAX(dropIndicatorPosition_ - kBarHalfWidth, 0);
-
- NSRect uglyBlackBar =
- NSMakeRect(xLeft, kBarVertPad,
- kBarWidth, NSHeight([self bounds]) - 2 * kBarVertPad);
- NSColor* uglyBlackBarColor = [[self window] themeProvider]->
- GetNSColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT, true);
- [[uglyBlackBarColor colorWithAlphaComponent:kBarOpacity] setFill];
- [[NSBezierPath bezierPathWithRect:uglyBlackBar] fill];
- }
-}
-
-// Shim function to assist in unit testing.
-- (BOOL)dragClipboardContainsBookmarks {
- return bookmark_pasteboard_helper_mac::DragClipboardContainsBookmarks();
-}
-
-// NSDraggingDestination methods
-
-- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info {
- if ([[info draggingPasteboard] dataForType:kBookmarkButtonDragType] ||
- [self dragClipboardContainsBookmarks] ||
- [[info draggingPasteboard] containsURLData]) {
- // We only show the drop indicator if we're not in a position to
- // perform a hover-open since it doesn't make sense to do both.
- BOOL showIt = [controller_ shouldShowIndicatorShownForPoint:
- [info draggingLocation]];
- if (!showIt) {
- if (dropIndicatorShown_) {
- dropIndicatorShown_ = NO;
- [self setNeedsDisplay:YES];
- }
- } else {
- CGFloat x =
- [controller_ indicatorPosForDragToPoint:[info draggingLocation]];
- // Need an update if the indicator wasn't previously shown or if it has
- // moved.
- if (!dropIndicatorShown_ || dropIndicatorPosition_ != x) {
- dropIndicatorShown_ = YES;
- dropIndicatorPosition_ = x;
- [self setNeedsDisplay:YES];
- }
- }
-
- [controller_ draggingEntered:info]; // allow hover-open to work.
- return [info draggingSource] ? NSDragOperationMove : NSDragOperationCopy;
- }
- return NSDragOperationNone;
-}
-
-- (void)draggingExited:(id<NSDraggingInfo>)info {
- // Regardless of the type of dragging which ended, we need to get rid of the
- // drop indicator if one was shown.
- if (dropIndicatorShown_) {
- dropIndicatorShown_ = NO;
- [self setNeedsDisplay:YES];
- }
-}
-
-- (void)draggingEnded:(id<NSDraggingInfo>)info {
- // For now, we just call |-draggingExited:|.
- [self draggingExited:info];
-}
-
-- (BOOL)wantsPeriodicDraggingUpdates {
- // TODO(port): This should probably return |YES| and the controller should
- // slide the existing bookmark buttons interactively to the side to make
- // room for the about-to-be-dropped bookmark.
- return NO;
-}
-
-- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)info {
- // For now it's the same as draggingEntered:.
- // TODO(jrg): once we return YES for wantsPeriodicDraggingUpdates,
- // this should ping the controller_ to perform animations.
- return [self draggingEntered:info];
-}
-
-- (BOOL)prepareForDragOperation:(id<NSDraggingInfo>)info {
- return YES;
-}
-
-// Implement NSDraggingDestination protocol method
-// performDragOperation: for URLs.
-- (BOOL)performDragOperationForURL:(id<NSDraggingInfo>)info {
- NSPasteboard* pboard = [info draggingPasteboard];
- DCHECK([pboard containsURLData]);
-
- NSArray* urls = nil;
- NSArray* titles = nil;
- [pboard getURLs:&urls andTitles:&titles convertingFilenames:YES];
-
- return [controller_ addURLs:urls
- withTitles:titles
- at:[info draggingLocation]];
-}
-
-// Implement NSDraggingDestination protocol method
-// performDragOperation: for bookmark buttons.
-- (BOOL)performDragOperationForBookmarkButton:(id<NSDraggingInfo>)info {
- BOOL rtn = NO;
- NSData* data = [[info draggingPasteboard]
- dataForType:kBookmarkButtonDragType];
- // [info draggingSource] is nil if not the same application.
- if (data && [info draggingSource]) {
- BookmarkButton* button = nil;
- [data getBytes:&button length:sizeof(button)];
- BOOL copy = !([info draggingSourceOperationMask] & NSDragOperationMove);
- rtn = [controller_ dragButton:button
- to:[info draggingLocation]
- copy:copy];
- UserMetrics::RecordAction(UserMetricsAction("BookmarkBar_DragEnd"));
- }
- return rtn;
-}
-
-- (BOOL)performDragOperation:(id<NSDraggingInfo>)info {
- if ([controller_ dragBookmarkData:info])
- return YES;
- NSPasteboard* pboard = [info draggingPasteboard];
- if ([pboard dataForType:kBookmarkButtonDragType]) {
- if ([self performDragOperationForBookmarkButton:info])
- return YES;
- // Fall through....
- }
- if ([pboard containsURLData]) {
- if ([self performDragOperationForURL:info])
- return YES;
- }
- return NO;
-}
-
-- (void)setController:(id)controller {
- controller_ = controller;
-}
-
-- (ViewID)viewID {
- return VIEW_ID_BOOKMARK_BAR;
-}
-
-@end // @implementation BookmarkBarView
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_view_unittest.mm b/chrome/browser/cocoa/bookmarks/bookmark_bar_view_unittest.mm
deleted file mode 100644
index 3d7725d..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_view_unittest.mm
+++ /dev/null
@@ -1,215 +0,0 @@
-// 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.
-
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_controller.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_view.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_button.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_folder_target.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/url_drop_target.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-#import "third_party/mozilla/NSPasteboard+Utils.h"
-
-namespace {
- const CGFloat kFakeIndicatorPos = 7.0;
-};
-
-// Fake DraggingInfo, fake BookmarkBarController, fake NSPasteboard...
-@interface FakeBookmarkDraggingInfo : NSObject {
- @public
- BOOL dragButtonToPong_;
- BOOL dragURLsPong_;
- BOOL dragBookmarkDataPong_;
- BOOL dropIndicatorShown_;
- BOOL draggingEnteredCalled_;
- // Only mock one type of drag data at a time.
- NSString* dragDataType_;
-}
-@property (nonatomic) BOOL dropIndicatorShown;
-@property (nonatomic) BOOL draggingEnteredCalled;
-@property (nonatomic, copy) NSString* dragDataType;
-@end
-
-@implementation FakeBookmarkDraggingInfo
-
-@synthesize dropIndicatorShown = dropIndicatorShown_;
-@synthesize draggingEnteredCalled = draggingEnteredCalled_;
-@synthesize dragDataType = dragDataType_;
-
-- (id)init {
- if ((self = [super init])) {
- dropIndicatorShown_ = YES;
- }
- return self;
-}
-
-- (void)dealloc {
- [dragDataType_ release];
- [super dealloc];
-}
-
-- (void)reset {
- [dragDataType_ release];
- dragDataType_ = nil;
- dragButtonToPong_ = NO;
- dragURLsPong_ = NO;
- dragBookmarkDataPong_ = NO;
- dropIndicatorShown_ = YES;
- draggingEnteredCalled_ = NO;
-}
-
-// NSDragInfo mocking functions.
-
-- (id)draggingPasteboard {
- return self;
-}
-
-// So we can look local.
-- (id)draggingSource {
- return self;
-}
-
-- (NSDragOperation)draggingSourceOperationMask {
- return NSDragOperationCopy | NSDragOperationMove;
-}
-
-- (NSPoint)draggingLocation {
- return NSMakePoint(10, 10);
-}
-
-// NSPasteboard mocking functions.
-
-- (BOOL)containsURLData {
- NSArray* urlTypes = [URLDropTargetHandler handledDragTypes];
- if (dragDataType_)
- return [urlTypes containsObject:dragDataType_];
- return NO;
-}
-
-- (NSData*)dataForType:(NSString*)type {
- if (dragDataType_ && [dragDataType_ isEqualToString:type])
- return [NSData data]; // Return something, anything.
- return nil;
-}
-
-// Fake a controller for callback ponging
-
-- (BOOL)dragButton:(BookmarkButton*)button to:(NSPoint)point copy:(BOOL)copy {
- dragButtonToPong_ = YES;
- return YES;
-}
-
-- (BOOL)addURLs:(NSArray*)urls withTitles:(NSArray*)titles at:(NSPoint)point {
- dragURLsPong_ = YES;
- return YES;
-}
-
-- (void)getURLs:(NSArray**)outUrls
- andTitles:(NSArray**)outTitles
- convertingFilenames:(BOOL)convertFilenames {
-}
-
-- (BOOL)dragBookmarkData:(id<NSDraggingInfo>)info {
- dragBookmarkDataPong_ = YES;
- return NO;
-}
-
-// Confirm the pongs.
-
-- (BOOL)dragButtonToPong {
- return dragButtonToPong_;
-}
-
-- (BOOL)dragURLsPong {
- return dragURLsPong_;
-}
-
-- (BOOL)dragBookmarkDataPong {
- return dragBookmarkDataPong_;
-}
-
-- (CGFloat)indicatorPosForDragToPoint:(NSPoint)point {
- return kFakeIndicatorPos;
-}
-
-- (BOOL)shouldShowIndicatorShownForPoint:(NSPoint)point {
- return dropIndicatorShown_;
-}
-
-- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info {
- draggingEnteredCalled_ = YES;
- return NSDragOperationNone;
-}
-
-@end
-
-namespace {
-
-class BookmarkBarViewTest : public CocoaTest {
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
- view_.reset([[BookmarkBarView alloc] init]);
- }
-
- scoped_nsobject<BookmarkBarView> view_;
-};
-
-TEST_F(BookmarkBarViewTest, CanDragWindow) {
- EXPECT_FALSE([view_ mouseDownCanMoveWindow]);
-}
-
-TEST_F(BookmarkBarViewTest, BookmarkButtonDragAndDrop) {
- scoped_nsobject<FakeBookmarkDraggingInfo>
- info([[FakeBookmarkDraggingInfo alloc] init]);
- [view_ setController:info.get()];
- [info reset];
-
- [info setDragDataType:kBookmarkButtonDragType];
- EXPECT_EQ([view_ draggingEntered:(id)info.get()], NSDragOperationMove);
- EXPECT_TRUE([view_ performDragOperation:(id)info.get()]);
- EXPECT_TRUE([info dragButtonToPong]);
- EXPECT_FALSE([info dragURLsPong]);
- EXPECT_TRUE([info dragBookmarkDataPong]);
-}
-
-TEST_F(BookmarkBarViewTest, URLDragAndDrop) {
- scoped_nsobject<FakeBookmarkDraggingInfo>
- info([[FakeBookmarkDraggingInfo alloc] init]);
- [view_ setController:info.get()];
- [info reset];
-
- NSArray* dragTypes = [URLDropTargetHandler handledDragTypes];
- for (NSString* type in dragTypes) {
- [info setDragDataType:type];
- EXPECT_EQ([view_ draggingEntered:(id)info.get()], NSDragOperationMove);
- EXPECT_TRUE([view_ performDragOperation:(id)info.get()]);
- EXPECT_FALSE([info dragButtonToPong]);
- EXPECT_TRUE([info dragURLsPong]);
- EXPECT_TRUE([info dragBookmarkDataPong]);
- [info reset];
- }
-}
-
-TEST_F(BookmarkBarViewTest, BookmarkButtonDropIndicator) {
- scoped_nsobject<FakeBookmarkDraggingInfo>
- info([[FakeBookmarkDraggingInfo alloc] init]);
- [view_ setController:info.get()];
-
- [info reset];
- [info setDragDataType:kBookmarkButtonDragType];
- EXPECT_FALSE([info draggingEnteredCalled]);
- EXPECT_EQ([view_ draggingEntered:(id)info.get()], NSDragOperationMove);
- EXPECT_TRUE([info draggingEnteredCalled]); // Ensure controller pinged.
- EXPECT_TRUE([view_ dropIndicatorShown]);
- EXPECT_EQ([view_ dropIndicatorPosition], kFakeIndicatorPos);
-
- [info setDropIndicatorShown:NO];
- EXPECT_EQ([view_ draggingEntered:(id)info.get()], NSDragOperationMove);
- EXPECT_FALSE([view_ dropIndicatorShown]);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bubble_controller.h b/chrome/browser/cocoa/bookmarks/bookmark_bubble_controller.h
deleted file mode 100644
index 9ceee17..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bubble_controller.h
+++ /dev/null
@@ -1,81 +0,0 @@
-// 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>
-
-#import "base/cocoa_protocols_mac.h"
-#include "base/scoped_ptr.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_model_observer_for_cocoa.h"
-
-class BookmarkBubbleNotificationBridge;
-class BookmarkModel;
-class BookmarkNode;
-@class BookmarkBubbleController;
-@class InfoBubbleView;
-
-
-// Controller for the bookmark bubble. The bookmark bubble is a
-// bubble that pops up when clicking on the STAR next to the URL to
-// add or remove it as a bookmark. This bubble allows for editing of
-// the bookmark in various ways (name, folder, etc.)
-@interface BookmarkBubbleController : NSWindowController<NSWindowDelegate> {
- @private
- NSWindow* parentWindow_; // weak
-
- // Both weak; owned by the current browser's profile
- BookmarkModel* model_; // weak
- const BookmarkNode* node_; // weak
-
- // The bookmark node whose button we asked to pulse.
- const BookmarkNode* pulsingBookmarkNode_; // weak
-
- BOOL alreadyBookmarked_;
-
- // Ping me when the bookmark model changes out from under us.
- scoped_ptr<BookmarkModelObserverForCocoa> bookmark_observer_;
-
- // Ping me when other Chrome things change out from under us.
- scoped_ptr<BookmarkBubbleNotificationBridge> chrome_observer_;
-
- IBOutlet NSTextField* bigTitle_; // "Bookmark" or "Bookmark Added!"
- IBOutlet NSTextField* nameTextField_;
- IBOutlet NSPopUpButton* folderPopUpButton_;
- IBOutlet InfoBubbleView* bubble_; // to set arrow position
-}
-
-@property (readonly, nonatomic) const BookmarkNode* node;
-
-// |node| is the bookmark node we edit in this bubble.
-// |alreadyBookmarked| tells us if the node was bookmarked before the
-// user clicked on the star. (if NO, this is a brand new bookmark).
-// The owner of this object is responsible for showing the bubble if
-// it desires it to be visible on the screen. It is not shown by the
-// init routine. Closing of the window happens implicitly on dealloc.
-- (id)initWithParentWindow:(NSWindow*)parentWindow
- model:(BookmarkModel*)model
- node:(const BookmarkNode*)node
- alreadyBookmarked:(BOOL)alreadyBookmarked;
-
-// Actions for buttons in the dialog.
-- (IBAction)ok:(id)sender;
-- (IBAction)remove:(id)sender;
-- (IBAction)cancel:(id)sender;
-
-// These actions send a -editBookmarkNode: action up the responder chain.
-- (IBAction)edit:(id)sender;
-- (IBAction)folderChanged:(id)sender;
-
-@end
-
-
-// Exposed only for unit testing.
-@interface BookmarkBubbleController(ExposedForUnitTesting)
-- (void)addFolderNodes:(const BookmarkNode*)parent
- toPopUpButton:(NSPopUpButton*)button
- indentation:(int)indentation;
-- (void)setTitle:(NSString*)title parentFolder:(const BookmarkNode*)parent;
-- (void)setParentFolderSelection:(const BookmarkNode*)parent;
-+ (NSString*)chooseAnotherFolderString;
-- (NSPopUpButton*)folderPopUpButton;
-@end
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bubble_controller.mm b/chrome/browser/cocoa/bookmarks/bookmark_bubble_controller.mm
deleted file mode 100644
index d367ff9..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bubble_controller.mm
+++ /dev/null
@@ -1,428 +0,0 @@
-// 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 "chrome/browser/cocoa/bookmarks/bookmark_bubble_controller.h"
-
-#include "app/l10n_util_mac.h"
-#include "base/mac_util.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h" // TODO(viettrungluu): remove
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_button.h"
-#import "chrome/browser/cocoa/browser_window_controller.h"
-#import "chrome/browser/cocoa/info_bubble_view.h"
-#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
-#include "grit/generated_resources.h"
-
-
-// Simple class to watch for tab creation/destruction and close the bubble.
-// Bridge between Chrome-style notifications and ObjC-style notifications.
-class BookmarkBubbleNotificationBridge : public NotificationObserver {
- public:
- BookmarkBubbleNotificationBridge(BookmarkBubbleController* controller,
- SEL selector);
- virtual ~BookmarkBubbleNotificationBridge() {}
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
- private:
- NotificationRegistrar registrar_;
- BookmarkBubbleController* controller_; // weak; owns us.
- SEL selector_; // SEL sent to controller_ on notification.
-};
-
-BookmarkBubbleNotificationBridge::BookmarkBubbleNotificationBridge(
- BookmarkBubbleController* controller, SEL selector)
- : controller_(controller), selector_(selector) {
- // registrar_ will automatically RemoveAll() when destroyed so we
- // don't need to do so explicitly.
- registrar_.Add(this, NotificationType::TAB_CONTENTS_CONNECTED,
- NotificationService::AllSources());
- registrar_.Add(this, NotificationType::TAB_CLOSED,
- NotificationService::AllSources());
-}
-
-// At this time all notifications instigate the same behavior (go
-// away) so we don't bother checking which notification came in.
-void BookmarkBubbleNotificationBridge::Observe(
- NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- [controller_ performSelector:selector_ withObject:controller_];
-}
-
-
-// An object to represent the ChooseAnotherFolder item in the pop up.
-@interface ChooseAnotherFolder : NSObject
-@end
-
-@implementation ChooseAnotherFolder
-@end
-
-@interface BookmarkBubbleController (PrivateAPI)
-- (void)updateBookmarkNode;
-- (void)fillInFolderList;
-- (void)parentWindowWillClose:(NSNotification*)notification;
-@end
-
-@implementation BookmarkBubbleController
-
-@synthesize node = node_;
-
-+ (id)chooseAnotherFolderObject {
- // Singleton object to act as a representedObject for the "choose another
- // folder" item in the pop up.
- static ChooseAnotherFolder* object = nil;
- if (!object) {
- object = [[ChooseAnotherFolder alloc] init];
- }
- return object;
-}
-
-- (id)initWithParentWindow:(NSWindow*)parentWindow
- model:(BookmarkModel*)model
- node:(const BookmarkNode*)node
- alreadyBookmarked:(BOOL)alreadyBookmarked {
- NSString* nibPath =
- [mac_util::MainAppBundle() pathForResource:@"BookmarkBubble"
- ofType:@"nib"];
- if ((self = [super initWithWindowNibPath:nibPath owner:self])) {
- parentWindow_ = parentWindow;
- model_ = model;
- node_ = node;
- alreadyBookmarked_ = alreadyBookmarked;
-
- // Watch to see if the parent window closes, and if so, close this one.
- NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
- [center addObserver:self
- selector:@selector(parentWindowWillClose:)
- name:NSWindowWillCloseNotification
- object:parentWindow_];
- }
- return self;
-}
-
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [super dealloc];
-}
-
-// If this is a new bookmark somewhere visible (e.g. on the bookmark
-// bar), pulse it. Else, call ourself recursively with our parent
-// until we find something visible to pulse.
-- (void)startPulsingBookmarkButton:(const BookmarkNode*)node {
- while (node) {
- if ((node->GetParent() == model_->GetBookmarkBarNode()) ||
- (node == model_->other_node())) {
- pulsingBookmarkNode_ = node;
- NSValue *value = [NSValue valueWithPointer:node];
- NSDictionary *dict = [NSDictionary
- dictionaryWithObjectsAndKeys:value,
- bookmark_button::kBookmarkKey,
- [NSNumber numberWithBool:YES],
- bookmark_button::kBookmarkPulseFlagKey,
- nil];
- [[NSNotificationCenter defaultCenter]
- postNotificationName:bookmark_button::kPulseBookmarkButtonNotification
- object:self
- userInfo:dict];
- return;
- }
- node = node->GetParent();
- }
-}
-
-- (void)stopPulsingBookmarkButton {
- if (!pulsingBookmarkNode_)
- return;
- NSValue *value = [NSValue valueWithPointer:pulsingBookmarkNode_];
- pulsingBookmarkNode_ = NULL;
- NSDictionary *dict = [NSDictionary
- dictionaryWithObjectsAndKeys:value,
- bookmark_button::kBookmarkKey,
- [NSNumber numberWithBool:NO],
- bookmark_button::kBookmarkPulseFlagKey,
- nil];
- [[NSNotificationCenter defaultCenter]
- postNotificationName:bookmark_button::kPulseBookmarkButtonNotification
- object:self
- userInfo:dict];
-}
-
-// Close the bookmark bubble without changing anything. Unlike a
-// typical dialog's OK/Cancel, where Cancel is "do nothing", all
-// buttons on the bubble have the capacity to change the bookmark
-// model. This is an IBOutlet-looking entry point to remove the
-// dialog without touching the model.
-- (void)dismissWithoutEditing:(id)sender {
- [self close];
-}
-
-- (void)parentWindowWillClose:(NSNotification*)notification {
- [self close];
-}
-
-- (void)windowWillClose:(NSNotification*)notification {
- // We caught a close so we don't need to watch for the parent closing.
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- bookmark_observer_.reset(NULL);
- chrome_observer_.reset(NULL);
- [self stopPulsingBookmarkButton];
- [self autorelease];
-}
-
-// We want this to be a child of a browser window. addChildWindow:
-// (called from this function) will bring the window on-screen;
-// unfortunately, [NSWindowController showWindow:] will also bring it
-// on-screen (but will cause unexpected changes to the window's
-// position). We cannot have an addChildWindow: and a subsequent
-// showWindow:. Thus, we have our own version.
-- (void)showWindow:(id)sender {
- BrowserWindowController* bwc =
- [BrowserWindowController browserWindowControllerForWindow:parentWindow_];
- [bwc lockBarVisibilityForOwner:self withAnimation:NO delay:NO];
- NSWindow* window = [self window]; // completes nib load
- [bubble_ setArrowLocation:info_bubble::kTopRight];
- // Insure decent positioning even in the absence of a browser controller,
- // which will occur for some unit tests.
- NSPoint arrowtip = bwc ? [bwc bookmarkBubblePoint] :
- NSMakePoint([window frame].size.width, [window frame].size.height);
- NSPoint origin = [parentWindow_ convertBaseToScreen:arrowtip];
- NSPoint bubbleArrowtip = [bubble_ arrowTip];
- bubbleArrowtip = [bubble_ convertPoint:bubbleArrowtip toView:nil];
- origin.y -= bubbleArrowtip.y;
- origin.x -= bubbleArrowtip.x;
- [window setFrameOrigin:origin];
- [parentWindow_ addChildWindow:window ordered:NSWindowAbove];
- // Default is IDS_BOOMARK_BUBBLE_PAGE_BOOKMARK; "Bookmark".
- // If adding for the 1st time the string becomes "Bookmark Added!"
- if (!alreadyBookmarked_) {
- NSString* title =
- l10n_util::GetNSString(IDS_BOOMARK_BUBBLE_PAGE_BOOKMARKED);
- [bigTitle_ setStringValue:title];
- }
-
- [self fillInFolderList];
-
- // Ping me when things change out from under us. Unlike a normal
- // dialog, the bookmark bubble's cancel: means "don't add this as a
- // bookmark", not "cancel editing". We must take extra care to not
- // touch the bookmark in this selector.
- bookmark_observer_.reset(new BookmarkModelObserverForCocoa(
- node_, model_,
- self,
- @selector(dismissWithoutEditing:)));
- chrome_observer_.reset(new BookmarkBubbleNotificationBridge(
- self, @selector(dismissWithoutEditing:)));
-
- // Pulse something interesting on the bookmark bar.
- [self startPulsingBookmarkButton:node_];
-
- [window makeKeyAndOrderFront:self];
-}
-
-- (void)close {
- [[BrowserWindowController browserWindowControllerForWindow:parentWindow_]
- releaseBarVisibilityForOwner:self withAnimation:YES delay:NO];
- [parentWindow_ removeChildWindow:[self window]];
-
- // If you quit while the bubble is open, sometimes we get a
- // DidResignKey before we get our parent's WindowWillClose and
- // sometimes not. We protect against a multiple close (or reference
- // to parentWindow_ at a bad time) by clearing it out once we're
- // done, and by removing ourself from future notifications.
- [[NSNotificationCenter defaultCenter]
- removeObserver:self
- name:NSWindowWillCloseNotification
- object:parentWindow_];
- parentWindow_ = nil;
-
- [super close];
-}
-
-// Shows the bookmark editor sheet for more advanced editing.
-- (void)showEditor {
- [self ok:self];
- // Send the action up through the responder chain.
- [NSApp sendAction:@selector(editBookmarkNode:) to:nil from:self];
-}
-
-- (IBAction)edit:(id)sender {
- UserMetrics::RecordAction(UserMetricsAction("BookmarkBubble_Edit"),
- model_->profile());
- [self showEditor];
-}
-
-- (IBAction)ok:(id)sender {
- [self stopPulsingBookmarkButton]; // before parent changes
- [self updateBookmarkNode];
- [self close];
-}
-
-// By implementing this, ESC causes the window to go away. If clicking the
-// star was what prompted this bubble to appear (i.e., not already bookmarked),
-// remove the bookmark.
-- (IBAction)cancel:(id)sender {
- if (!alreadyBookmarked_) {
- // |-remove:| calls |-close| so don't do it.
- [self remove:sender];
- } else {
- [self ok:sender];
- }
-}
-
-- (IBAction)remove:(id)sender {
- [self stopPulsingBookmarkButton];
- // TODO(viettrungluu): get rid of conversion and utf_string_conversions.h.
- model_->SetURLStarred(node_->GetURL(), node_->GetTitle(), false);
- UserMetrics::RecordAction(UserMetricsAction("BookmarkBubble_Unstar"),
- model_->profile());
- node_ = NULL; // no longer valid
- [self ok:sender];
-}
-
-// The controller is the target of the pop up button box action so it can
-// handle when "choose another folder" was picked.
-- (IBAction)folderChanged:(id)sender {
- DCHECK([sender isEqual:folderPopUpButton_]);
- // It is possible that due to model change our parent window has been closed
- // but the popup is still showing and able to notify the controller of a
- // folder change. We ignore the sender in this case.
- if (!parentWindow_)
- return;
- NSMenuItem* selected = [folderPopUpButton_ selectedItem];
- ChooseAnotherFolder* chooseItem = [[self class] chooseAnotherFolderObject];
- if ([[selected representedObject] isEqual:chooseItem]) {
- UserMetrics::RecordAction(
- UserMetricsAction("BookmarkBubble_EditFromCombobox"),
- model_->profile());
- [self showEditor];
- }
-}
-
-// The controller is the delegate of the window so it receives did resign key
-// notifications. When key is resigned mirror Windows behavior and close the
-// window.
-- (void)windowDidResignKey:(NSNotification*)notification {
- NSWindow* window = [self window];
- DCHECK_EQ([notification object], window);
- if ([window isVisible]) {
- // If the window isn't visible, it is already closed, and this notification
- // has been sent as part of the closing operation, so no need to close.
- [self ok:self];
- }
-}
-
-// Look at the dialog; if the user has changed anything, update the
-// bookmark node to reflect this.
-- (void)updateBookmarkNode {
- if (!node_) return;
-
- // First the title...
- NSString* oldTitle = base::SysUTF16ToNSString(node_->GetTitle());
- NSString* newTitle = [nameTextField_ stringValue];
- if (![oldTitle isEqual:newTitle]) {
- model_->SetTitle(node_, base::SysNSStringToUTF16(newTitle));
- UserMetrics::RecordAction(
- UserMetricsAction("BookmarkBubble_ChangeTitleInBubble"),
- model_->profile());
- }
- // Then the parent folder.
- const BookmarkNode* oldParent = node_->GetParent();
- NSMenuItem* selectedItem = [folderPopUpButton_ selectedItem];
- id representedObject = [selectedItem representedObject];
- if ([representedObject isEqual:[[self class] chooseAnotherFolderObject]]) {
- // "Choose another folder..."
- return;
- }
- const BookmarkNode* newParent =
- static_cast<const BookmarkNode*>([representedObject pointerValue]);
- DCHECK(newParent);
- if (oldParent != newParent) {
- int index = newParent->GetChildCount();
- model_->Move(node_, newParent, index);
- UserMetrics::RecordAction(UserMetricsAction("BookmarkBubble_ChangeParent"),
- model_->profile());
- }
-}
-
-// Fill in all information related to the folder pop up button.
-- (void)fillInFolderList {
- [nameTextField_ setStringValue:base::SysUTF16ToNSString(node_->GetTitle())];
- DCHECK([folderPopUpButton_ numberOfItems] == 0);
- [self addFolderNodes:model_->root_node()
- toPopUpButton:folderPopUpButton_
- indentation:0];
- NSMenu* menu = [folderPopUpButton_ menu];
- NSString* title = [[self class] chooseAnotherFolderString];
- NSMenuItem *item = [menu addItemWithTitle:title
- action:NULL
- keyEquivalent:@""];
- ChooseAnotherFolder* obj = [[self class] chooseAnotherFolderObject];
- [item setRepresentedObject:obj];
- // Finally, select the current parent.
- NSValue* parentValue = [NSValue valueWithPointer:node_->GetParent()];
- NSInteger idx = [menu indexOfItemWithRepresentedObject:parentValue];
- [folderPopUpButton_ selectItemAtIndex:idx];
-}
-
-@end // BookmarkBubbleController
-
-
-@implementation BookmarkBubbleController(ExposedForUnitTesting)
-
-+ (NSString*)chooseAnotherFolderString {
- return l10n_util::GetNSStringWithFixup(
- IDS_BOOMARK_BUBBLE_CHOOSER_ANOTHER_FOLDER);
-}
-
-// For the given folder node, walk the tree and add folder names to
-// the given pop up button.
-- (void)addFolderNodes:(const BookmarkNode*)parent
- toPopUpButton:(NSPopUpButton*)button
- indentation:(int)indentation {
- if (!model_->is_root(parent)) {
- NSString* title = base::SysUTF16ToNSString(parent->GetTitle());
- NSMenu* menu = [button menu];
- NSMenuItem* item = [menu addItemWithTitle:title
- action:NULL
- keyEquivalent:@""];
- [item setRepresentedObject:[NSValue valueWithPointer:parent]];
- [item setIndentationLevel:indentation];
- ++indentation;
- }
- for (int i = 0; i < parent->GetChildCount(); i++) {
- const BookmarkNode* child = parent->GetChild(i);
- if (child->is_folder())
- [self addFolderNodes:child
- toPopUpButton:button
- indentation:indentation];
- }
-}
-
-- (void)setTitle:(NSString*)title parentFolder:(const BookmarkNode*)parent {
- [nameTextField_ setStringValue:title];
- [self setParentFolderSelection:parent];
-}
-
-// Pick a specific parent node in the selection by finding the right
-// pop up button index.
-- (void)setParentFolderSelection:(const BookmarkNode*)parent {
- // Expectation: There is a parent mapping for all items in the
- // folderPopUpButton except the last one ("Choose another folder...").
- NSMenu* menu = [folderPopUpButton_ menu];
- NSValue* parentValue = [NSValue valueWithPointer:parent];
- NSInteger idx = [menu indexOfItemWithRepresentedObject:parentValue];
- DCHECK(idx != -1);
- [folderPopUpButton_ selectItemAtIndex:idx];
-}
-
-- (NSPopUpButton*)folderPopUpButton {
- return folderPopUpButton_;
-}
-
-@end // implementation BookmarkBubbleController(ExposedForUnitTesting)
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bubble_controller_unittest.mm b/chrome/browser/cocoa/bookmarks/bookmark_bubble_controller_unittest.mm
deleted file mode 100644
index 4a5b600..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_bubble_controller_unittest.mm
+++ /dev/null
@@ -1,490 +0,0 @@
-// 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 "base/basictypes.h"
-#include "base/scoped_nsobject.h"
-#include "base/utf_string_conversions.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bubble_controller.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#include "chrome/browser/cocoa/browser_window_controller.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/info_bubble_window.h"
-#include "chrome/common/notification_service.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-// Watch for bookmark pulse notifications so we can confirm they were sent.
-@interface BookmarkPulseObserver : NSObject {
- int notifications_;
-}
-@property (assign, nonatomic) int notifications;
-@end
-
-
-@implementation BookmarkPulseObserver
-
-@synthesize notifications = notifications_;
-
-- (id)init {
- if ((self = [super init])) {
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(pulseBookmarkNotification:)
- name:bookmark_button::kPulseBookmarkButtonNotification
- object:nil];
- }
- return self;
-}
-
-- (void)pulseBookmarkNotification:(NSNotificationCenter *)notification {
- notifications_++;
-}
-
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [super dealloc];
-}
-
-@end
-
-
-namespace {
-
-class BookmarkBubbleControllerTest : public CocoaTest {
- public:
- static int edits_;
- BrowserTestHelper helper_;
- BookmarkBubbleController* controller_;
-
- BookmarkBubbleControllerTest() : controller_(nil) {
- edits_ = 0;
- }
-
- virtual void TearDown() {
- [controller_ close];
- CocoaTest::TearDown();
- }
-
- // Returns a controller but ownership not transferred.
- // Only one of these will be valid at a time.
- BookmarkBubbleController* ControllerForNode(const BookmarkNode* node) {
- if (controller_ && !IsWindowClosing()) {
- [controller_ close];
- controller_ = nil;
- }
- controller_ = [[BookmarkBubbleController alloc]
- initWithParentWindow:test_window()
- model:helper_.profile()->GetBookmarkModel()
- node:node
- alreadyBookmarked:YES];
- EXPECT_TRUE([controller_ window]);
- // The window must be gone or we'll fail a unit test with windows left open.
- [static_cast<InfoBubbleWindow*>([controller_ window]) setDelayOnClose:NO];
- [controller_ showWindow:nil];
- return controller_;
- }
-
- BookmarkModel* GetBookmarkModel() {
- return helper_.profile()->GetBookmarkModel();
- }
-
- bool IsWindowClosing() {
- return [static_cast<InfoBubbleWindow*>([controller_ window]) isClosing];
- }
-};
-
-// static
-int BookmarkBubbleControllerTest::edits_;
-
-// Confirm basics about the bubble window (e.g. that it is inside the
-// parent window)
-TEST_F(BookmarkBubbleControllerTest, TestBubbleWindow) {
- BookmarkModel* model = GetBookmarkModel();
- const BookmarkNode* node = model->AddURL(model->GetBookmarkBarNode(),
- 0,
- ASCIIToUTF16("Bookie markie title"),
- GURL("http://www.google.com"));
- BookmarkBubbleController* controller = ControllerForNode(node);
- EXPECT_TRUE(controller);
- NSWindow* window = [controller window];
- EXPECT_TRUE(window);
- EXPECT_TRUE(NSContainsRect([test_window() frame],
- [window frame]));
-}
-
-// Test that we can handle closing the parent window
-TEST_F(BookmarkBubbleControllerTest, TestClosingParentWindow) {
- BookmarkModel* model = GetBookmarkModel();
- const BookmarkNode* node = model->AddURL(model->GetBookmarkBarNode(),
- 0,
- ASCIIToUTF16("Bookie markie title"),
- GURL("http://www.google.com"));
- BookmarkBubbleController* controller = ControllerForNode(node);
- EXPECT_TRUE(controller);
- NSWindow* window = [controller window];
- EXPECT_TRUE(window);
- base::mac::ScopedNSAutoreleasePool pool;
- [test_window() performClose:NSApp];
-}
-
-
-// Confirm population of folder list
-TEST_F(BookmarkBubbleControllerTest, TestFillInFolder) {
- // Create some folders, including a nested folder
- BookmarkModel* model = GetBookmarkModel();
- EXPECT_TRUE(model);
- const BookmarkNode* bookmarkBarNode = model->GetBookmarkBarNode();
- EXPECT_TRUE(bookmarkBarNode);
- const BookmarkNode* node1 = model->AddGroup(bookmarkBarNode, 0,
- ASCIIToUTF16("one"));
- EXPECT_TRUE(node1);
- const BookmarkNode* node2 = model->AddGroup(bookmarkBarNode, 1,
- ASCIIToUTF16("two"));
- EXPECT_TRUE(node2);
- const BookmarkNode* node3 = model->AddGroup(bookmarkBarNode, 2,
- ASCIIToUTF16("three"));
- EXPECT_TRUE(node3);
- const BookmarkNode* node4 = model->AddGroup(node2, 0, ASCIIToUTF16("sub"));
- EXPECT_TRUE(node4);
- const BookmarkNode* node5 = model->AddURL(node1, 0, ASCIIToUTF16("title1"),
- GURL("http://www.google.com"));
- EXPECT_TRUE(node5);
- const BookmarkNode* node6 = model->AddURL(node3, 0, ASCIIToUTF16("title2"),
- GURL("http://www.google.com"));
- EXPECT_TRUE(node6);
- const BookmarkNode* node7 = model->AddURL(node4, 0, ASCIIToUTF16("title3"),
- GURL("http://www.google.com/reader"));
- EXPECT_TRUE(node7);
-
- BookmarkBubbleController* controller = ControllerForNode(node4);
- EXPECT_TRUE(controller);
-
- NSArray* titles =
- [[[controller folderPopUpButton] itemArray] valueForKey:@"title"];
- EXPECT_TRUE([titles containsObject:@"one"]);
- EXPECT_TRUE([titles containsObject:@"two"]);
- EXPECT_TRUE([titles containsObject:@"three"]);
- EXPECT_TRUE([titles containsObject:@"sub"]);
- EXPECT_FALSE([titles containsObject:@"title1"]);
- EXPECT_FALSE([titles containsObject:@"title2"]);
-}
-
-// Confirm ability to handle folders with blank name.
-TEST_F(BookmarkBubbleControllerTest, TestFolderWithBlankName) {
- // Create some folders, including a nested folder
- BookmarkModel* model = GetBookmarkModel();
- EXPECT_TRUE(model);
- const BookmarkNode* bookmarkBarNode = model->GetBookmarkBarNode();
- EXPECT_TRUE(bookmarkBarNode);
- const BookmarkNode* node1 = model->AddGroup(bookmarkBarNode, 0,
- ASCIIToUTF16("one"));
- EXPECT_TRUE(node1);
- const BookmarkNode* node2 = model->AddGroup(bookmarkBarNode, 1,
- ASCIIToUTF16(""));
- EXPECT_TRUE(node2);
- const BookmarkNode* node3 = model->AddGroup(bookmarkBarNode, 2,
- ASCIIToUTF16("three"));
- EXPECT_TRUE(node3);
- const BookmarkNode* node2_1 = model->AddURL(node2, 0, ASCIIToUTF16("title1"),
- GURL("http://www.google.com"));
- EXPECT_TRUE(node2_1);
-
- BookmarkBubbleController* controller = ControllerForNode(node1);
- EXPECT_TRUE(controller);
-
- // One of the items should be blank and its node should be node2.
- NSArray* items = [[controller folderPopUpButton] itemArray];
- EXPECT_GT([items count], 4U);
- BOOL blankFolderFound = NO;
- for (NSMenuItem* item in [[controller folderPopUpButton] itemArray]) {
- if ([[item title] length] == 0 &&
- static_cast<const BookmarkNode*>([[item representedObject]
- pointerValue]) == node2) {
- blankFolderFound = YES;
- break;
- }
- }
- EXPECT_TRUE(blankFolderFound);
-}
-
-
-// Click on edit; bubble gets closed.
-TEST_F(BookmarkBubbleControllerTest, TestEdit) {
- BookmarkModel* model = GetBookmarkModel();
- const BookmarkNode* node = model->AddURL(model->GetBookmarkBarNode(),
- 0,
- ASCIIToUTF16("Bookie markie title"),
- GURL("http://www.google.com"));
- BookmarkBubbleController* controller = ControllerForNode(node);
- EXPECT_TRUE(controller);
-
- EXPECT_EQ(edits_, 0);
- EXPECT_FALSE(IsWindowClosing());
- [controller edit:controller];
- EXPECT_EQ(edits_, 1);
- EXPECT_TRUE(IsWindowClosing());
-}
-
-// CallClose; bubble gets closed.
-// Also confirm pulse notifications get sent.
-TEST_F(BookmarkBubbleControllerTest, TestClose) {
- BookmarkModel* model = GetBookmarkModel();
- const BookmarkNode* node = model->AddURL(
- model->GetBookmarkBarNode(), 0, ASCIIToUTF16("Bookie markie title"),
- GURL("http://www.google.com"));
- EXPECT_EQ(edits_, 0);
-
- scoped_nsobject<BookmarkPulseObserver> observer([[BookmarkPulseObserver alloc]
- init]);
- EXPECT_EQ([observer notifications], 0);
- BookmarkBubbleController* controller = ControllerForNode(node);
- EXPECT_TRUE(controller);
- EXPECT_FALSE(IsWindowClosing());
- EXPECT_EQ([observer notifications], 1);
- [controller ok:controller];
- EXPECT_EQ(edits_, 0);
- EXPECT_TRUE(IsWindowClosing());
- EXPECT_EQ([observer notifications], 2);
-}
-
-// User changes title and parent folder in the UI
-TEST_F(BookmarkBubbleControllerTest, TestUserEdit) {
- BookmarkModel* model = GetBookmarkModel();
- EXPECT_TRUE(model);
- const BookmarkNode* bookmarkBarNode = model->GetBookmarkBarNode();
- EXPECT_TRUE(bookmarkBarNode);
- const BookmarkNode* node = model->AddURL(bookmarkBarNode,
- 0,
- ASCIIToUTF16("short-title"),
- GURL("http://www.google.com"));
- const BookmarkNode* grandma = model->AddGroup(bookmarkBarNode, 0,
- ASCIIToUTF16("grandma"));
- EXPECT_TRUE(grandma);
- const BookmarkNode* grandpa = model->AddGroup(bookmarkBarNode, 0,
- ASCIIToUTF16("grandpa"));
- EXPECT_TRUE(grandpa);
-
- BookmarkBubbleController* controller = ControllerForNode(node);
- EXPECT_TRUE(controller);
-
- // simulate a user edit
- [controller setTitle:@"oops" parentFolder:grandma];
- [controller edit:controller];
-
- // Make sure bookmark has changed
- EXPECT_EQ(node->GetTitle(), ASCIIToUTF16("oops"));
- EXPECT_EQ(node->GetParent()->GetTitle(), ASCIIToUTF16("grandma"));
-}
-
-// Confirm happiness with parent nodes that have the same name.
-TEST_F(BookmarkBubbleControllerTest, TestNewParentSameName) {
- BookmarkModel* model = GetBookmarkModel();
- EXPECT_TRUE(model);
- const BookmarkNode* bookmarkBarNode = model->GetBookmarkBarNode();
- EXPECT_TRUE(bookmarkBarNode);
- for (int i=0; i<2; i++) {
- const BookmarkNode* node = model->AddURL(bookmarkBarNode,
- 0,
- ASCIIToUTF16("short-title"),
- GURL("http://www.google.com"));
- EXPECT_TRUE(node);
- const BookmarkNode* group = model->AddGroup(bookmarkBarNode, 0,
- ASCIIToUTF16("NAME"));
- EXPECT_TRUE(group);
- group = model->AddGroup(bookmarkBarNode, 0, ASCIIToUTF16("NAME"));
- EXPECT_TRUE(group);
- group = model->AddGroup(bookmarkBarNode, 0, ASCIIToUTF16("NAME"));
- EXPECT_TRUE(group);
- BookmarkBubbleController* controller = ControllerForNode(node);
- EXPECT_TRUE(controller);
-
- // simulate a user edit
- [controller setParentFolderSelection:bookmarkBarNode->GetChild(i)];
- [controller edit:controller];
-
- // Make sure bookmark has changed, and that the parent is what we
- // expect. This proves nobody did searching based on name.
- EXPECT_EQ(node->GetParent(), bookmarkBarNode->GetChild(i));
- }
-}
-
-// Confirm happiness with nodes with the same Name
-TEST_F(BookmarkBubbleControllerTest, TestDuplicateNodeNames) {
- BookmarkModel* model = GetBookmarkModel();
- const BookmarkNode* bookmarkBarNode = model->GetBookmarkBarNode();
- EXPECT_TRUE(bookmarkBarNode);
- const BookmarkNode* node1 = model->AddGroup(bookmarkBarNode, 0,
- ASCIIToUTF16("NAME"));
- EXPECT_TRUE(node1);
- const BookmarkNode* node2 = model->AddGroup(bookmarkBarNode, 0,
- ASCIIToUTF16("NAME"));
- EXPECT_TRUE(node2);
- BookmarkBubbleController* controller = ControllerForNode(bookmarkBarNode);
- EXPECT_TRUE(controller);
-
- NSPopUpButton* button = [controller folderPopUpButton];
- [controller setParentFolderSelection:node1];
- NSMenuItem* item = [button selectedItem];
- id itemObject = [item representedObject];
- EXPECT_NSEQ([NSValue valueWithPointer:node1], itemObject);
- [controller setParentFolderSelection:node2];
- item = [button selectedItem];
- itemObject = [item representedObject];
- EXPECT_NSEQ([NSValue valueWithPointer:node2], itemObject);
-}
-
-// Click the "remove" button
-TEST_F(BookmarkBubbleControllerTest, TestRemove) {
- BookmarkModel* model = GetBookmarkModel();
- GURL gurl("http://www.google.com");
- const BookmarkNode* node = model->AddURL(model->GetBookmarkBarNode(),
- 0,
- ASCIIToUTF16("Bookie markie title"),
- gurl);
- BookmarkBubbleController* controller = ControllerForNode(node);
- EXPECT_TRUE(controller);
- EXPECT_TRUE(model->IsBookmarked(gurl));
-
- [controller remove:controller];
- EXPECT_FALSE(model->IsBookmarked(gurl));
- EXPECT_TRUE(IsWindowClosing());
-}
-
-// Confirm picking "choose another folder" caused edit: to be called.
-TEST_F(BookmarkBubbleControllerTest, PopUpSelectionChanged) {
- BookmarkModel* model = GetBookmarkModel();
- GURL gurl("http://www.google.com");
- const BookmarkNode* node = model->AddURL(model->GetBookmarkBarNode(),
- 0, ASCIIToUTF16("super-title"),
- gurl);
- BookmarkBubbleController* controller = ControllerForNode(node);
- EXPECT_TRUE(controller);
-
- NSPopUpButton* button = [controller folderPopUpButton];
- [button selectItemWithTitle:[[controller class] chooseAnotherFolderString]];
- EXPECT_EQ(edits_, 0);
- [button sendAction:[button action] to:[button target]];
- EXPECT_EQ(edits_, 1);
-}
-
-// Create a controller that simulates the bookmark just now being created by
-// the user clicking the star, then sending the "cancel" command to represent
-// them pressing escape. The bookmark should not be there.
-TEST_F(BookmarkBubbleControllerTest, EscapeRemovesNewBookmark) {
- BookmarkModel* model = GetBookmarkModel();
- GURL gurl("http://www.google.com");
- const BookmarkNode* node = model->AddURL(model->GetBookmarkBarNode(),
- 0,
- ASCIIToUTF16("Bookie markie title"),
- gurl);
- BookmarkBubbleController* controller =
- [[BookmarkBubbleController alloc]
- initWithParentWindow:test_window()
- model:helper_.profile()->GetBookmarkModel()
- node:node
- alreadyBookmarked:NO]; // The last param is the key difference.
- EXPECT_TRUE([controller window]);
- // Calls release on controller.
- [controller cancel:nil];
- EXPECT_FALSE(model->IsBookmarked(gurl));
-}
-
-// Create a controller where the bookmark already existed prior to clicking
-// the star and test that sending a cancel command doesn't change the state
-// of the bookmark.
-TEST_F(BookmarkBubbleControllerTest, EscapeDoesntTouchExistingBookmark) {
- BookmarkModel* model = GetBookmarkModel();
- GURL gurl("http://www.google.com");
- const BookmarkNode* node = model->AddURL(model->GetBookmarkBarNode(),
- 0,
- ASCIIToUTF16("Bookie markie title"),
- gurl);
- BookmarkBubbleController* controller = ControllerForNode(node);
- EXPECT_TRUE(controller);
-
- [(id)controller cancel:nil];
- EXPECT_TRUE(model->IsBookmarked(gurl));
-}
-
-// Confirm indentation of items in pop-up menu
-TEST_F(BookmarkBubbleControllerTest, TestMenuIndentation) {
- // Create some folders, including a nested folder
- BookmarkModel* model = GetBookmarkModel();
- EXPECT_TRUE(model);
- const BookmarkNode* bookmarkBarNode = model->GetBookmarkBarNode();
- EXPECT_TRUE(bookmarkBarNode);
- const BookmarkNode* node1 = model->AddGroup(bookmarkBarNode, 0,
- ASCIIToUTF16("one"));
- EXPECT_TRUE(node1);
- const BookmarkNode* node2 = model->AddGroup(bookmarkBarNode, 1,
- ASCIIToUTF16("two"));
- EXPECT_TRUE(node2);
- const BookmarkNode* node2_1 = model->AddGroup(node2, 0,
- ASCIIToUTF16("two dot one"));
- EXPECT_TRUE(node2_1);
- const BookmarkNode* node3 = model->AddGroup(bookmarkBarNode, 2,
- ASCIIToUTF16("three"));
- EXPECT_TRUE(node3);
-
- BookmarkBubbleController* controller = ControllerForNode(node1);
- EXPECT_TRUE(controller);
-
- // Compare the menu item indents against expectations.
- static const int kExpectedIndent[] = {0, 1, 1, 2, 1, 0};
- NSArray* items = [[controller folderPopUpButton] itemArray];
- ASSERT_GE([items count], 6U);
- for(int itemNo = 0; itemNo < 6; itemNo++) {
- NSMenuItem* item = [items objectAtIndex:itemNo];
- EXPECT_EQ(kExpectedIndent[itemNo], [item indentationLevel])
- << "Unexpected indent for menu item #" << itemNo;
- }
-}
-
-// Confirm bubble goes away when a new tab is created.
-TEST_F(BookmarkBubbleControllerTest, BubbleGoesAwayOnNewTab) {
-
- BookmarkModel* model = GetBookmarkModel();
- const BookmarkNode* node = model->AddURL(model->GetBookmarkBarNode(),
- 0,
- ASCIIToUTF16("Bookie markie title"),
- GURL("http://www.google.com"));
- EXPECT_EQ(edits_, 0);
-
- BookmarkBubbleController* controller = ControllerForNode(node);
- EXPECT_TRUE(controller);
- EXPECT_FALSE(IsWindowClosing());
-
- // We can't actually create a new tab here, e.g.
- // helper_.browser()->AddTabWithURL(...);
- // Many of our browser objects (Browser, Profile, RequestContext)
- // are "just enough" to run tests without being complete. Instead
- // we fake the notification that would be triggered by a tab
- // creation.
- NotificationService::current()->Notify(
- NotificationType::TAB_CONTENTS_CONNECTED,
- Source<TabContentsDelegate>(NULL),
- Details<TabContents>(NULL));
-
- // Confirm bubble going bye-bye.
- EXPECT_TRUE(IsWindowClosing());
-}
-
-
-} // namespace
-
-@implementation NSApplication (BookmarkBubbleUnitTest)
-// Add handler for the editBookmarkNode: action to NSApp for testing purposes.
-// Normally this would be sent up the responder tree correctly, but since
-// tests run in the background, key window and main window are never set on
-// NSApplication. Adding it to NSApplication directly removes the need for
-// worrying about what the current window with focus is.
-- (void)editBookmarkNode:(id)sender {
- EXPECT_TRUE([sender respondsToSelector:@selector(node)]);
- BookmarkBubbleControllerTest::edits_++;
-}
-
-@end
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_button.h b/chrome/browser/cocoa/bookmarks/bookmark_button.h
deleted file mode 100644
index 5d8574c..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_button.h
+++ /dev/null
@@ -1,243 +0,0 @@
-// 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 <vector>
-#import "chrome/browser/cocoa/draggable_button.h"
-#include "webkit/glue/window_open_disposition.h"
-
-@class BookmarkBarFolderController;
-@class BookmarkButton;
-struct BookmarkNodeData;
-class BookmarkModel;
-class BookmarkNode;
-@class BrowserWindowController;
-class ThemeProvider;
-
-// Protocol for a BookmarkButton's delegate, responsible for doing
-// things on behalf of a bookmark button.
-@protocol BookmarkButtonDelegate
-
-// Fill the given pasteboard with appropriate data when the given button is
-// dragged. Since the delegate has no way of providing pasteboard data later,
-// all data must actually be put into the pasteboard and not merely promised.
-- (void)fillPasteboard:(NSPasteboard*)pboard
- forDragOfButton:(BookmarkButton*)button;
-
-// Bookmark buttons pass mouseEntered: and mouseExited: events to
-// their delegate. This allows the delegate to decide (for example)
-// which one, if any, should perform a hover-open.
-- (void)mouseEnteredButton:(id)button event:(NSEvent*)event;
-- (void)mouseExitedButton:(id)button event:(NSEvent*)event;
-
-// Returns YES if a drag operation should lock the fullscreen overlay bar
-// visibility before starting. For example, dragging a bookmark button should
-// not lock the overlay if the bookmark bar is currently showing in detached
-// mode on the NTP.
-- (BOOL)dragShouldLockBarVisibility;
-
-// Returns the top-level window for this button.
-- (NSWindow*)browserWindow;
-
-// Returns YES if the bookmark button can be dragged to the trash, NO otherwise.
-- (BOOL)canDragBookmarkButtonToTrash:(BookmarkButton*)button;
-
-// This is called after the user has dropped the bookmark button on the trash.
-// The delegate can use this event to delete the bookmark.
-- (void)didDragBookmarkToTrash:(BookmarkButton*)button;
-
-@end
-
-
-// Protocol to be implemented by controllers that logically own
-// bookmark buttons. The controller may be either an NSViewController
-// or NSWindowController. The BookmarkButton doesn't use this
-// protocol directly; it is used when BookmarkButton controllers talk
-// to each other.
-//
-// Other than the top level owner (the bookmark bar), all bookmark
-// button controllers have a parent controller.
-@protocol BookmarkButtonControllerProtocol
-
-// Close all bookmark folders, walking up the ownership chain.
-- (void)closeAllBookmarkFolders;
-
-// Close just my bookmark folder.
-- (void)closeBookmarkFolder:(id)sender;
-
-// Return the bookmark model for this controller.
-- (BookmarkModel*)bookmarkModel;
-
-// Perform drag enter/exit operations, such as hover-open and hover-close.
-- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info;
-- (void)draggingExited:(id<NSDraggingInfo>)info;
-
-// Returns YES if a drag operation should lock the fullscreen overlay bar
-// visibility before starting. For example, dragging a bookmark button should
-// not lock the overlay if the bookmark bar is currently showing in detached
-// mode on the NTP.
-- (BOOL)dragShouldLockBarVisibility;
-
-// Perform the actual DnD of a bookmark or bookmark button.
-
-// |point| is in the base coordinate system of the destination window;
-// |it comes from an id<NSDraggingInfo>. |copy| is YES if a copy is to be
-// made and inserted into the new location while leaving the bookmark in
-// the old location, otherwise move the bookmark by removing from its old
-// location and inserting into the new location.
-- (BOOL)dragButton:(BookmarkButton*)sourceButton
- to:(NSPoint)point
- copy:(BOOL)copy;
-
-// Determine if the pasteboard from |info| has dragging data containing
-// bookmark(s) and perform the drag and return YES, otherwise return NO.
-- (BOOL)dragBookmarkData:(id<NSDraggingInfo>)info;
-
-// Determine if the drag pasteboard has any drag data of type
-// kBookmarkDictionaryListPboardType and, if so, return those elements
-// otherwise return an empty vector.
-- (std::vector<const BookmarkNode*>)retrieveBookmarkNodeData;
-
-// Return YES if we should show the drop indicator, else NO. In some
-// cases (e.g. hover open) we don't want to show the drop indicator.
-// |point| is in the base coordinate system of the destination window;
-// |it comes from an id<NSDraggingInfo>.
-- (BOOL)shouldShowIndicatorShownForPoint:(NSPoint)point;
-
-// The x or y coordinate of (the middle of) the indicator to draw for
-// a drag of the source button to the given point (given in window
-// coordinates).
-// |point| is in the base coordinate system of the destination window;
-// |it comes from an id<NSDraggingInfo>.
-// TODO(viettrungluu,jrg): instead of this, make buttons move around.
-// http://crbug.com/35968
-- (CGFloat)indicatorPosForDragToPoint:(NSPoint)point;
-
-// Return the theme provider associated with this browser window.
-- (ThemeProvider*)themeProvider;
-
-// Called just before a child folder puts itself on screen.
-- (void)childFolderWillShow:(id<BookmarkButtonControllerProtocol>)child;
-
-// Called just before a child folder closes.
-- (void)childFolderWillClose:(id<BookmarkButtonControllerProtocol>)child;
-
-// Return a controller's folder controller for a subfolder, or nil.
-- (BookmarkBarFolderController*)folderController;
-
-// Add a new folder controller as triggered by the given folder button.
-// If there is a current folder controller, close it.
-- (void)addNewFolderControllerWithParentButton:(BookmarkButton*)parentButton;
-
-// Open all of the nodes for the given node with disposition.
-- (void)openAll:(const BookmarkNode*)node
- disposition:(WindowOpenDisposition)disposition;
-
-// There are several operations which may affect the contents of a bookmark
-// button controller after it has been created, primary of which are
-// cut/paste/delete and drag/drop. Such changes may involve coordinating
-// the bookmark button contents of two controllers (such as when a bookmark is
-// dragged from one folder to another). The bookmark bar controller
-// coordinates in response to notifications propogated by the bookmark model
-// through BookmarkBarBridge calls. The following three functions are
-// implemented by the controllers and are dispatched by the bookmark bar
-// controller in response to notifications coming in from the BookmarkBarBridge.
-
-// Add a button for the given node to the bar or folder menu. This is safe
-// to call when a folder menu window is open as that window will be updated.
-// And index of -1 means to append to the end (bottom).
-- (void)addButtonForNode:(const BookmarkNode*)node
- atIndex:(NSInteger)buttonIndex;
-
-// Given a list or |urls| and |titles|, create new bookmark nodes and add
-// them to the bookmark model such that they will be 1) added to the folder
-// represented by the button at |point| if it is a folder, or 2) inserted
-// into the parent of the non-folder bookmark at |point| in front of that
-// button. Returns YES if at least one bookmark was added.
-// TODO(mrossetti): Change function to use a pair-like structure for
-// URLs and titles. http://crbug.com/44411
-- (BOOL)addURLs:(NSArray*)urls withTitles:(NSArray*)titles at:(NSPoint)point;
-
-// Move a button from one place in the menu to another. This is safe
-// to call when a folder menu window is open as that window will be updated.
-- (void)moveButtonFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex;
-
-// Remove the bookmark button at the given index. Show the poof animation
-// if |animate:| is YES. It may be obvious, but this is safe
-// to call when a folder menu window is open as that window will be updated.
-- (void)removeButton:(NSInteger)buttonIndex animate:(BOOL)poof;
-
-// Determine the controller containing the button representing |node|, if any.
-- (id<BookmarkButtonControllerProtocol>)controllerForNode:
- (const BookmarkNode*)node;
-
-@end // @protocol BookmarkButtonControllerProtocol
-
-
-// Class for bookmark bar buttons that can be drag sources.
-@interface BookmarkButton : DraggableButton {
- @private
- IBOutlet NSObject<BookmarkButtonDelegate>* delegate_; // Weak.
-
- // Saved pointer to the BWC for the browser window that contains this button.
- // Used to lock and release bar visibility during a drag. The pointer is
- // saved because the bookmark button is no longer a part of a window at the
- // end of a drag operation (or, in fact, can be dragged to a completely
- // different window), so there is no way to retrieve the same BWC object after
- // a drag.
- BrowserWindowController* visibilityDelegate_; // weak
-
- NSPoint dragMouseOffset_;
- NSPoint dragEndScreenLocation_;
- BOOL dragPending_;
-}
-
-@property(assign, nonatomic) NSObject<BookmarkButtonDelegate>* delegate;
-
-// Return the bookmark node associated with this button, or NULL.
-- (const BookmarkNode*)bookmarkNode;
-
-// Return YES if this is a folder button (the node has subnodes).
-- (BOOL)isFolder;
-
-// At this time we represent an empty folder (e.g. the string
-// '(empty)') as a disabled button with no associated node.
-//
-// TODO(jrg): improve; things work but are slightly ugly since "empty"
-// and "one disabled button" are not the same thing.
-// http://crbug.com/35967
-- (BOOL)isEmpty;
-
-// Turn on or off pulsing of a bookmark button.
-// Triggered by the bookmark bubble.
-- (void)setIsContinuousPulsing:(BOOL)flag;
-
-// Return continuous pulse state.
-- (BOOL)isContinuousPulsing;
-
-// Return the location in screen coordinates where the remove animation should
-// be displayed.
-- (NSPoint)screenLocationForRemoveAnimation;
-
-@end // @interface BookmarkButton
-
-
-@interface BookmarkButton(TestingAPI)
-- (void)beginDrag:(NSEvent*)event;
-@end
-
-namespace bookmark_button {
-
-// Notifications for pulsing of bookmarks.
-extern NSString* const kPulseBookmarkButtonNotification;
-
-// Key for userInfo dict of a kPulseBookmarkButtonNotification.
-// Value is a [NSValue valueWithPointer:]; pointer is a (const BookmarkNode*).
-extern NSString* const kBookmarkKey;
-
-// Key for userInfo dict of a kPulseBookmarkButtonNotification.
-// Value is a [NSNumber numberWithBool:] to turn pulsing on or off.
-extern NSString* const kBookmarkPulseFlagKey;
-
-};
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_button.mm b/chrome/browser/cocoa/bookmarks/bookmark_button.mm
deleted file mode 100644
index 9728e67..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_button.mm
+++ /dev/null
@@ -1,238 +0,0 @@
-// 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 "chrome/browser/cocoa/bookmarks/bookmark_button.h"
-
-#include "base/logging.h"
-#import "base/scoped_nsobject.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_button_cell.h"
-#import "chrome/browser/cocoa/browser_window_controller.h"
-#import "chrome/browser/cocoa/view_id_util.h"
-#include "chrome/browser/metrics/user_metrics.h"
-
-// The opacity of the bookmark button drag image.
-static const CGFloat kDragImageOpacity = 0.7;
-
-
-namespace bookmark_button {
-
-NSString* const kPulseBookmarkButtonNotification =
- @"PulseBookmarkButtonNotification";
-NSString* const kBookmarkKey = @"BookmarkKey";
-NSString* const kBookmarkPulseFlagKey = @"BookmarkPulseFlagKey";
-
-};
-
-@interface BookmarkButton(Private)
-
-// Make a drag image for the button.
-- (NSImage*)dragImage;
-
-@end // @interface BookmarkButton(Private)
-
-
-@implementation BookmarkButton
-
-@synthesize delegate = delegate_;
-
-- (id)initWithFrame:(NSRect)frameRect {
- // BookmarkButton's ViewID may be changed to VIEW_ID_OTHER_BOOKMARKS in
- // BookmarkBarController, so we can't just override -viewID method to return
- // it.
- if ((self = [super initWithFrame:frameRect]))
- view_id_util::SetID(self, VIEW_ID_BOOKMARK_BAR_ELEMENT);
- return self;
-}
-
-- (void)dealloc {
- if ([[self cell] respondsToSelector:@selector(safelyStopPulsing)])
- [[self cell] safelyStopPulsing];
- view_id_util::UnsetID(self);
- [super dealloc];
-}
-
-- (const BookmarkNode*)bookmarkNode {
- return [[self cell] bookmarkNode];
-}
-
-- (BOOL)isFolder {
- const BookmarkNode* node = [self bookmarkNode];
- return (node && node->is_folder());
-}
-
-- (BOOL)isEmpty {
- return [self bookmarkNode] ? NO : YES;
-}
-
-- (void)setIsContinuousPulsing:(BOOL)flag {
- [[self cell] setIsContinuousPulsing:flag];
-}
-
-- (BOOL)isContinuousPulsing {
- return [[self cell] isContinuousPulsing];
-}
-
-- (NSPoint)screenLocationForRemoveAnimation {
- NSPoint point;
-
- if (dragPending_) {
- // Use the position of the mouse in the drag image as the location.
- point = dragEndScreenLocation_;
- point.x += dragMouseOffset_.x;
- if ([self isFlipped]) {
- point.y += [self bounds].size.height - dragMouseOffset_.y;
- } else {
- point.y += dragMouseOffset_.y;
- }
- } else {
- // Use the middle of this button as the location.
- NSRect bounds = [self bounds];
- point = NSMakePoint(NSMidX(bounds), NSMidY(bounds));
- point = [self convertPoint:point toView:nil];
- point = [[self window] convertBaseToScreen:point];
- }
-
- return point;
-}
-
-// By default, NSButton ignores middle-clicks.
-// But we want them.
-- (void)otherMouseUp:(NSEvent*)event {
- [self performClick:self];
-}
-
-// Overridden from DraggableButton.
-- (void)beginDrag:(NSEvent*)event {
- // Don't allow a drag of the empty node.
- // The empty node is a placeholder for "(empty)", to be revisited.
- if ([self isEmpty])
- return;
-
- if (![self delegate]) {
- NOTREACHED();
- return;
- }
- // Ask our delegate to fill the pasteboard for us.
- NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
- [[self delegate] fillPasteboard:pboard forDragOfButton:self];
-
- // At the moment, moving bookmarks causes their buttons (like me!)
- // to be destroyed and rebuilt. Make sure we don't go away while on
- // the stack.
- [self retain];
-
- // Lock bar visibility, forcing the overlay to stay visible if we are in
- // fullscreen mode.
- if ([[self delegate] dragShouldLockBarVisibility]) {
- DCHECK(!visibilityDelegate_);
- NSWindow* window = [[self delegate] browserWindow];
- visibilityDelegate_ =
- [BrowserWindowController browserWindowControllerForWindow:window];
- [visibilityDelegate_ lockBarVisibilityForOwner:self
- withAnimation:NO
- delay:NO];
- }
- const BookmarkNode* node = [self bookmarkNode];
- const BookmarkNode* parent = node ? node->GetParent() : NULL;
- if (parent && parent->type() == BookmarkNode::FOLDER) {
- UserMetrics::RecordAction(UserMetricsAction("BookmarkBarFolder_DragStart"));
- } else {
- UserMetrics::RecordAction(UserMetricsAction("BookmarkBar_DragStart"));
- }
-
- dragMouseOffset_ = [self convertPointFromBase:[event locationInWindow]];
- dragPending_ = YES;
-
- CGFloat yAt = [self bounds].size.height;
- NSSize dragOffset = NSMakeSize(0.0, 0.0);
- [self dragImage:[self dragImage] at:NSMakePoint(0, yAt) offset:dragOffset
- event:event pasteboard:pboard source:self slideBack:YES];
-
- // And we're done.
- dragPending_ = NO;
- [self autorelease];
-}
-
-// Overridden to release bar visibility.
-- (void)endDrag {
- // visibilityDelegate_ can be nil if we're detached, and that's fine.
- [visibilityDelegate_ releaseBarVisibilityForOwner:self
- withAnimation:YES
- delay:YES];
- visibilityDelegate_ = nil;
- [super endDrag];
-}
-
-- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal {
- NSDragOperation operation = NSDragOperationCopy;
- if (isLocal) {
- operation |= NSDragOperationMove;
- }
- if ([delegate_ canDragBookmarkButtonToTrash:self]) {
- operation |= NSDragOperationDelete;
- }
- return operation;
-}
-
-- (void)draggedImage:(NSImage *)anImage
- endedAt:(NSPoint)aPoint
- operation:(NSDragOperation)operation {
- if (operation & NSDragOperationDelete) {
- dragEndScreenLocation_ = aPoint;
- [delegate_ didDragBookmarkToTrash:self];
- }
-}
-
-// mouseEntered: and mouseExited: are called from our
-// BookmarkButtonCell. We redirect this information to our delegate.
-// The controller can then perform menu-like actions (e.g. "hover over
-// to open menu").
-- (void)mouseEntered:(NSEvent*)event {
- [delegate_ mouseEnteredButton:self event:event];
-}
-
-// See comments above mouseEntered:.
-- (void)mouseExited:(NSEvent*)event {
- [delegate_ mouseExitedButton:self event:event];
-}
-
-@end
-
-@implementation BookmarkButton(Private)
-
-- (NSImage*)dragImage {
- NSRect bounds = [self bounds];
-
- // Grab the image from the screen and put it in an |NSImage|. We can't use
- // this directly since we need to clip it and set its opacity. This won't work
- // if the source view is clipped. Fortunately, we don't display clipped
- // bookmark buttons.
- [self lockFocus];
- scoped_nsobject<NSBitmapImageRep>
- bitmap([[NSBitmapImageRep alloc] initWithFocusedViewRect:bounds]);
- [self unlockFocus];
- scoped_nsobject<NSImage> image([[NSImage alloc] initWithSize:[bitmap size]]);
- [image addRepresentation:bitmap];
-
- // Make an autoreleased |NSImage|, which will be returned, and draw into it.
- // By default, the |NSImage| will be completely transparent.
- NSImage* dragImage =
- [[[NSImage alloc] initWithSize:[bitmap size]] autorelease];
- [dragImage lockFocus];
-
- // Draw the image with the appropriate opacity, clipping it tightly.
- GradientButtonCell* cell = static_cast<GradientButtonCell*>([self cell]);
- DCHECK([cell isKindOfClass:[GradientButtonCell class]]);
- [[cell clipPathForFrame:bounds inView:self] setClip];
- [image drawAtPoint:NSMakePoint(0, 0)
- fromRect:NSMakeRect(0, 0, NSWidth(bounds), NSHeight(bounds))
- operation:NSCompositeSourceOver
- fraction:kDragImageOpacity];
-
- [dragImage unlockFocus];
- return dragImage;
-}
-
-@end // @implementation BookmarkButton(Private)
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_button_cell.h b/chrome/browser/cocoa/bookmarks/bookmark_button_cell.h
deleted file mode 100644
index 45d83e3..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_button_cell.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BUTTON_CELL_H_
-#define CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BUTTON_CELL_H_
-#pragma once
-
-#import "base/cocoa_protocols_mac.h"
-#import "chrome/browser/cocoa/gradient_button_cell.h"
-
-class BookmarkNode;
-
-// A button cell that handles drawing/highlighting of buttons in the
-// bookmark bar. This cell forwards mouseEntered/mouseExited events
-// to its control view so that pseudo-menu operations
-// (e.g. hover-over to open) can be implemented.
-@interface BookmarkButtonCell : GradientButtonCell<NSMenuDelegate> {
- @private
- BOOL empty_; // is this an "empty" button placeholder button cell?
-
- // Starting index of bookmarkFolder children that we care to use.
- int startingChildIndex_;
-
- // Should we draw the folder arrow as needed? Not used for the bar
- // itself but used on the folder windows.
- BOOL drawFolderArrow_;
-
- // Arrow for folders
- scoped_nsobject<NSImage> arrowImage_;
-}
-
-@property (nonatomic, readwrite, assign) const BookmarkNode* bookmarkNode;
-@property (nonatomic, readwrite, assign) int startingChildIndex;
-@property (nonatomic, readwrite, assign) BOOL drawFolderArrow;
-
-// Create a button cell which draws with a theme.
-+ (id)buttonCellForNode:(const BookmarkNode*)node
- contextMenu:(NSMenu*)contextMenu
- cellText:(NSString*)cellText
- cellImage:(NSImage*)cellImage;
-
-// Initialize a button cell which draws with a theme.
-// Designated initializer.
-- (id)initForNode:(const BookmarkNode*)node
- contextMenu:(NSMenu*)contextMenu
- cellText:(NSString*)cellText
- cellImage:(NSImage*)cellImage;
-
-- (BOOL)empty; // returns YES if empty.
-- (void)setEmpty:(BOOL)empty;
-
-// |-setBookmarkCellText:image:| is used to set the text and image of
-// a BookmarkButtonCell, and align the image to the left (NSImageLeft)
-// if there is text in the title, and centered (NSImageCenter) if
-// there is not. If |title| is nil, do not reset the title.
-- (void)setBookmarkCellText:(NSString*)title
- image:(NSImage*)image;
-
-// Set the color of text in this cell.
-- (void)setTextColor:(NSColor*)color;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_BUTTON_CELL_H_
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_button_cell.mm b/chrome/browser/cocoa/bookmarks/bookmark_button_cell.mm
deleted file mode 100644
index 8cb59e9..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_button_cell.mm
+++ /dev/null
@@ -1,246 +0,0 @@
-// 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 "chrome/browser/cocoa/bookmarks/bookmark_button_cell.h"
-
-#include "app/l10n_util_mac.h"
-#include "base/logging.h"
-#include "base/nsimage_cache_mac.h"
-#include "base/sys_string_conversions.h"
-#import "chrome/browser/bookmarks/bookmark_model.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_menu.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_button.h"
-#import "chrome/browser/cocoa/image_utils.h"
-#include "chrome/browser/metrics/user_metrics.h"
-#include "grit/generated_resources.h"
-
-
-@interface BookmarkButtonCell(Private)
-- (void)configureBookmarkButtonCell;
-@end
-
-
-@implementation BookmarkButtonCell
-
-@synthesize startingChildIndex = startingChildIndex_;
-@synthesize drawFolderArrow = drawFolderArrow_;
-
-+ (id)buttonCellForNode:(const BookmarkNode*)node
- contextMenu:(NSMenu*)contextMenu
- cellText:(NSString*)cellText
- cellImage:(NSImage*)cellImage {
- id buttonCell =
- [[[BookmarkButtonCell alloc] initForNode:node
- contextMenu:contextMenu
- cellText:cellText
- cellImage:cellImage]
- autorelease];
- return buttonCell;
-}
-
-- (id)initForNode:(const BookmarkNode*)node
- contextMenu:(NSMenu*)contextMenu
- cellText:(NSString*)cellText
- cellImage:(NSImage*)cellImage {
- if ((self = [super initTextCell:cellText])) {
- [self configureBookmarkButtonCell];
-
- [self setBookmarkNode:node];
-
- if (node) {
- NSString* title = base::SysUTF16ToNSString(node->GetTitle());
- [self setBookmarkCellText:title image:cellImage];
- [self setMenu:contextMenu];
- } else {
- [self setEmpty:YES];
- [self setBookmarkCellText:l10n_util::GetNSString(IDS_MENU_EMPTY_SUBMENU)
- image:nil];
- }
- }
-
- return self;
-}
-
-- (id)initTextCell:(NSString*)string {
- return [self initForNode:nil contextMenu:nil cellText:string cellImage:nil];
-}
-
-// Used by the off-the-side menu, the only case where a
-// BookmarkButtonCell is loaded from a nib.
-- (void)awakeFromNib {
- [self configureBookmarkButtonCell];
-}
-
-// Perform all normal init routines specific to the BookmarkButtonCell.
-- (void)configureBookmarkButtonCell {
- [self setButtonType:NSMomentaryPushInButton];
- [self setBezelStyle:NSShadowlessSquareBezelStyle];
- [self setShowsBorderOnlyWhileMouseInside:YES];
- [self setControlSize:NSSmallControlSize];
- [self setAlignment:NSLeftTextAlignment];
- [self setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
- [self setWraps:NO];
- // NSLineBreakByTruncatingMiddle seems more common on OSX but let's
- // try to match Windows for a bit to see what happens.
- [self setLineBreakMode:NSLineBreakByTruncatingTail];
-
- // Theming doesn't work for bookmark buttons yet (cell text is chucked).
- [super setShouldTheme:NO];
-}
-
-- (BOOL)empty {
- return empty_;
-}
-
-- (void)setEmpty:(BOOL)empty {
- empty_ = empty;
- [self setShowsBorderOnlyWhileMouseInside:!empty];
-}
-
-- (NSSize)cellSizeForBounds:(NSRect)aRect {
- NSSize size = [super cellSizeForBounds:aRect];
- // Cocoa seems to slightly underestimate how much space we need, so we
- // compensate here to avoid a clipped rendering.
- size.width += 2;
- size.height += 4;
- return size;
-}
-
-- (void)setBookmarkCellText:(NSString*)title
- image:(NSImage*)image {
- title = [title stringByReplacingOccurrencesOfString:@"\n"
- withString:@" "];
- title = [title stringByReplacingOccurrencesOfString:@"\r"
- withString:@" "];
- // If there is no title, squeeze things tight by displaying only the image; by
- // default, Cocoa leaves extra space in an attempt to display an empty title.
- if ([title length]) {
- [self setImagePosition:NSImageLeft];
- [self setTitle:title];
- } else {
- [self setImagePosition:NSImageOnly];
- }
-
- if (image)
- [self setImage:image];
-}
-
-- (void)setBookmarkNode:(const BookmarkNode*)node {
- [self setRepresentedObject:[NSValue valueWithPointer:node]];
-}
-
-- (const BookmarkNode*)bookmarkNode {
- return static_cast<const BookmarkNode*>([[self representedObject]
- pointerValue]);
-}
-
-// We share the context menu among all bookmark buttons. To allow us
-// to disambiguate when needed (e.g. "open bookmark"), we set the
-// menu's associated bookmark node ID to be our represented object.
-- (NSMenu*)menu {
- if (empty_)
- return nil;
- BookmarkMenu* menu = (BookmarkMenu*)[super menu];
- const BookmarkNode* node =
- static_cast<const BookmarkNode*>([[self representedObject] pointerValue]);
-
- if (node->GetParent() && node->GetParent()->type() == BookmarkNode::FOLDER) {
- UserMetrics::RecordAction(UserMetricsAction("BookmarkBarFolder_CtxMenu"));
- } else {
- UserMetrics::RecordAction(UserMetricsAction("BookmarkBar_CtxMenu"));
- }
-
- [menu setRepresentedObject:[NSNumber numberWithLongLong:node->id()]];
-
- return menu;
-}
-
-// Unfortunately, NSCell doesn't already have something like this.
-// TODO(jrg): consider placing in GTM.
-- (void)setTextColor:(NSColor*)color {
-
- // We can't properly set the cell's text color without a control.
- // In theory we could just save the next for later and wait until
- // the cell is moved to a control, but there is no obvious way to
- // accomplish that (e.g. no "cellDidMoveToControl" notification.)
- DCHECK([self controlView]);
-
- scoped_nsobject<NSMutableParagraphStyle> style([NSMutableParagraphStyle new]);
- [style setAlignment:NSLeftTextAlignment];
- NSDictionary* dict = [NSDictionary
- dictionaryWithObjectsAndKeys:color,
- NSForegroundColorAttributeName,
- [self font], NSFontAttributeName,
- style.get(), NSParagraphStyleAttributeName,
- nil];
- scoped_nsobject<NSAttributedString> ats([[NSAttributedString alloc]
- initWithString:[self title]
- attributes:dict]);
- NSButton* button = static_cast<NSButton*>([self controlView]);
- if (button) {
- DCHECK([button isKindOfClass:[NSButton class]]);
- [button setAttributedTitle:ats.get()];
- }
-}
-
-// To implement "hover open a bookmark button to open the folder"
-// which feels like menus, we override NSButtonCell's mouseEntered:
-// and mouseExited:, then and pass them along to our owning control.
-// Note: as verified in a debugger, mouseEntered: does NOT increase
-// the retainCount of the cell or its owning control.
-- (void)mouseEntered:(NSEvent*)event {
- [super mouseEntered:event];
- [[self controlView] mouseEntered:event];
-}
-
-// See comment above mouseEntered:, above.
-- (void)mouseExited:(NSEvent*)event {
- [[self controlView] mouseExited:event];
- [super mouseExited:event];
-}
-
-- (void)setDrawFolderArrow:(BOOL)draw {
- drawFolderArrow_ = draw;
- if (draw && !arrowImage_) {
- arrowImage_.reset([nsimage_cache::ImageNamed(@"menu_hierarchy_arrow.pdf")
- retain]);
- }
-}
-
-// Add extra size for the arrow so it doesn't overlap the text.
-// Does not sanity check to be sure this is actually a folder node.
-- (NSSize)cellSize {
- NSSize cellSize = [super cellSize];
- if (drawFolderArrow_) {
- cellSize.width += [arrowImage_ size].width; // plus margin?
- }
- return cellSize;
-}
-
-// Override cell drawing to add a submenu arrow like a real menu.
-- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
- // First draw "everything else".
- [super drawInteriorWithFrame:cellFrame inView:controlView];
-
- // If asked to do so, and if a folder, draw the arrow.
- if (!drawFolderArrow_)
- return;
- BookmarkButton* button = static_cast<BookmarkButton*>([self controlView]);
- DCHECK([button respondsToSelector:@selector(isFolder)]);
- if ([button isFolder]) {
- NSRect imageRect = NSZeroRect;
- imageRect.size = [arrowImage_ size];
- NSRect drawRect = NSOffsetRect(imageRect,
- NSWidth(cellFrame) - NSWidth(imageRect),
- (NSHeight(cellFrame) / 2.0) -
- (NSHeight(imageRect) / 2.0));
- [arrowImage_ drawInRect:drawRect
- fromRect:imageRect
- operation:NSCompositeSourceOver
- fraction:[self isEnabled] ? 1.0 : 0.5
- neverFlipped:YES];
- }
-}
-
-@end
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_button_cell_unittest.mm b/chrome/browser/cocoa/bookmarks/bookmark_button_cell_unittest.mm
deleted file mode 100644
index 1c4e89f..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_button_cell_unittest.mm
+++ /dev/null
@@ -1,183 +0,0 @@
-// 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.
-
-#include "app/resource_bundle.h"
-#include "base/scoped_nsobject.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_button_cell.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_menu.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "grit/app_resources.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-// Simple class to remember how many mouseEntered: and mouseExited:
-// calls it gets. Only used by BookmarkMouseForwarding but placed
-// at the top of the file to keep it outside the anon namespace.
-@interface ButtonRemembersMouseEnterExit : NSButton {
- @public
- int enters_;
- int exits_;
-}
-@end
-
-@implementation ButtonRemembersMouseEnterExit
-- (void)mouseEntered:(NSEvent*)event {
- enters_++;
-}
-- (void)mouseExited:(NSEvent*)event {
- exits_++;
-}
-@end
-
-
-namespace {
-
-class BookmarkButtonCellTest : public CocoaTest {
- public:
- BrowserTestHelper helper_;
-};
-
-// Make sure it's not totally bogus
-TEST_F(BookmarkButtonCellTest, SizeForBounds) {
- NSRect frame = NSMakeRect(0, 0, 50, 30);
- scoped_nsobject<NSButton> view([[NSButton alloc] initWithFrame:frame]);
- scoped_nsobject<BookmarkButtonCell> cell(
- [[BookmarkButtonCell alloc] initTextCell:@"Testing"]);
- [view setCell:cell.get()];
- [[test_window() contentView] addSubview:view];
-
- NSRect r = NSMakeRect(0, 0, 100, 100);
- NSSize size = [cell.get() cellSizeForBounds:r];
- EXPECT_TRUE(size.width > 0 && size.height > 0);
- EXPECT_TRUE(size.width < 200 && size.height < 200);
-}
-
-// Make sure icon-only buttons are squeezed tightly.
-TEST_F(BookmarkButtonCellTest, IconOnlySqueeze) {
- NSRect frame = NSMakeRect(0, 0, 50, 30);
- scoped_nsobject<NSButton> view([[NSButton alloc] initWithFrame:frame]);
- scoped_nsobject<BookmarkButtonCell> cell(
- [[BookmarkButtonCell alloc] initTextCell:@"Testing"]);
- [view setCell:cell.get()];
- [[test_window() contentView] addSubview:view];
-
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- scoped_nsobject<NSImage> image([rb.GetNativeImageNamed(IDR_DEFAULT_FAVICON)
- retain]);
- EXPECT_TRUE(image.get());
-
- NSRect r = NSMakeRect(0, 0, 100, 100);
- [cell setBookmarkCellText:@" " image:image];
- CGFloat two_space_width = [cell.get() cellSizeForBounds:r].width;
- [cell setBookmarkCellText:@" " image:image];
- CGFloat one_space_width = [cell.get() cellSizeForBounds:r].width;
- [cell setBookmarkCellText:@"" image:image];
- CGFloat zero_space_width = [cell.get() cellSizeForBounds:r].width;
-
- // Make sure the switch to "no title" is more significant than we
- // would otherwise see by decreasing the length of the title.
- CGFloat delta1 = two_space_width - one_space_width;
- CGFloat delta2 = one_space_width - zero_space_width;
- EXPECT_GT(delta2, delta1);
-
-}
-
-// Make sure the default from the base class is overridden.
-TEST_F(BookmarkButtonCellTest, MouseEnterStuff) {
- scoped_nsobject<BookmarkButtonCell> cell(
- [[BookmarkButtonCell alloc] initTextCell:@"Testing"]);
- // Setting the menu should have no affect since we either share or
- // dynamically compose the menu given a node.
- [cell setMenu:[[[BookmarkMenu alloc] initWithTitle:@"foo"] autorelease]];
- EXPECT_FALSE([cell menu]);
-
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- const BookmarkNode* node = model->GetBookmarkBarNode();
- [cell setEmpty:NO];
- [cell setBookmarkNode:node];
- EXPECT_TRUE([cell showsBorderOnlyWhileMouseInside]);
- EXPECT_TRUE([cell menu]);
-
- [cell setEmpty:YES];
- EXPECT_FALSE([cell.get() showsBorderOnlyWhileMouseInside]);
- EXPECT_FALSE([cell menu]);
-}
-
-TEST_F(BookmarkButtonCellTest, BookmarkNode) {
- BookmarkModel& model(*(helper_.profile()->GetBookmarkModel()));
- scoped_nsobject<BookmarkButtonCell> cell(
- [[BookmarkButtonCell alloc] initTextCell:@"Testing"]);
-
- const BookmarkNode* node = model.GetBookmarkBarNode();
- [cell setBookmarkNode:node];
- EXPECT_EQ(node, [cell bookmarkNode]);
-
- node = model.other_node();
- [cell setBookmarkNode:node];
- EXPECT_EQ(node, [cell bookmarkNode]);
-}
-
-TEST_F(BookmarkButtonCellTest, BookmarkMouseForwarding) {
- scoped_nsobject<BookmarkButtonCell> cell(
- [[BookmarkButtonCell alloc] initTextCell:@"Testing"]);
- scoped_nsobject<ButtonRemembersMouseEnterExit>
- button([[ButtonRemembersMouseEnterExit alloc]
- initWithFrame:NSMakeRect(0,0,50,50)]);
- [button setCell:cell.get()];
- EXPECT_EQ(0, button.get()->enters_);
- EXPECT_EQ(0, button.get()->exits_);
- NSEvent* event = [NSEvent mouseEventWithType:NSMouseMoved
- location:NSMakePoint(10,10)
- modifierFlags:0
- timestamp:0
- windowNumber:0
- context:nil
- eventNumber:0
- clickCount:0
- pressure:0];
- [cell mouseEntered:event];
- EXPECT_TRUE(button.get()->enters_ && !button.get()->exits_);
-
- for (int i = 0; i < 3; i++)
- [cell mouseExited:event];
- EXPECT_EQ(button.get()->enters_, 1);
- EXPECT_EQ(button.get()->exits_, 3);
-}
-
-// Confirms a cell created in a nib is initialized properly
-TEST_F(BookmarkButtonCellTest, Awake) {
- scoped_nsobject<BookmarkButtonCell> cell([[BookmarkButtonCell alloc] init]);
- [cell awakeFromNib];
- EXPECT_EQ(NSLeftTextAlignment, [cell alignment]);
-}
-
-// Subfolder arrow details.
-TEST_F(BookmarkButtonCellTest, FolderArrow) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- const BookmarkNode* bar = model->GetBookmarkBarNode();
- const BookmarkNode* node = model->AddURL(bar, bar->GetChildCount(),
- ASCIIToUTF16("title"),
- GURL("http://www.google.com"));
- scoped_nsobject<BookmarkButtonCell> cell(
- [[BookmarkButtonCell alloc] initForNode:node
- contextMenu:nil
- cellText:@"small"
- cellImage:nil]);
- EXPECT_TRUE(cell.get());
-
- NSSize size = [cell cellSize];
- // sanity check
- EXPECT_GE(size.width, 2);
- EXPECT_GE(size.height, 2);
-
- // Once we turn on arrow drawing make sure there is now room for it.
- [cell setDrawFolderArrow:YES];
- NSSize arrowSize = [cell cellSize];
- EXPECT_GT(arrowSize.width, size.width);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_button_unittest.mm b/chrome/browser/cocoa/bookmarks/bookmark_button_unittest.mm
deleted file mode 100644
index ed8964a..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_button_unittest.mm
+++ /dev/null
@@ -1,174 +0,0 @@
-// 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.
-
-#include "base/scoped_nsobject.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_button.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_button_cell.h"
-#import "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/test_event_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-// Fake BookmarkButton delegate to get a pong on mouse entered/exited
-@interface FakeButtonDelegate : NSObject<BookmarkButtonDelegate> {
- @public
- int entered_;
- int exited_;
- BOOL canDragToTrash_;
- int didDragToTrashCount_;
-}
-@end
-
-@implementation FakeButtonDelegate
-
-- (void)fillPasteboard:(NSPasteboard*)pboard
- forDragOfButton:(BookmarkButton*)button {
-}
-
-- (void)mouseEnteredButton:(id)buton event:(NSEvent*)event {
- entered_++;
-}
-
-- (void)mouseExitedButton:(id)buton event:(NSEvent*)event {
- exited_++;
-}
-
-- (BOOL)dragShouldLockBarVisibility {
- return NO;
-}
-
-- (NSWindow*)browserWindow {
- return nil;
-}
-
-- (BOOL)canDragBookmarkButtonToTrash:(BookmarkButton*)button {
- return canDragToTrash_;
-}
-
-- (void)didDragBookmarkToTrash:(BookmarkButton*)button {
- didDragToTrashCount_++;
-}
-
-@end
-
-namespace {
-
-class BookmarkButtonTest : public CocoaTest {
-};
-
-// Make sure nothing leaks
-TEST_F(BookmarkButtonTest, Create) {
- scoped_nsobject<BookmarkButton> button;
- button.reset([[BookmarkButton alloc] initWithFrame:NSMakeRect(0,0,500,500)]);
-}
-
-// Test folder and empty node queries.
-TEST_F(BookmarkButtonTest, FolderAndEmptyOrNot) {
- BrowserTestHelper helper_;
- scoped_nsobject<BookmarkButton> button;
- scoped_nsobject<BookmarkButtonCell> cell;
-
- button.reset([[BookmarkButton alloc] initWithFrame:NSMakeRect(0,0,500,500)]);
- cell.reset([[BookmarkButtonCell alloc] initTextCell:@"hi mom"]);
- [button setCell:cell];
-
- EXPECT_TRUE([button isEmpty]);
- EXPECT_FALSE([button isFolder]);
- EXPECT_FALSE([button bookmarkNode]);
-
- NSEvent* downEvent =
- test_event_utils::LeftMouseDownAtPoint(NSMakePoint(10,10));
- // Since this returns (does not actually begin a modal drag), success!
- [button beginDrag:downEvent];
-
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- const BookmarkNode* node = model->GetBookmarkBarNode();
- [cell setBookmarkNode:node];
- EXPECT_FALSE([button isEmpty]);
- EXPECT_TRUE([button isFolder]);
- EXPECT_EQ([button bookmarkNode], node);
-
- node = model->AddURL(node, 0, ASCIIToUTF16("hi mom"),
- GURL("http://www.google.com"));
- [cell setBookmarkNode:node];
- EXPECT_FALSE([button isEmpty]);
- EXPECT_FALSE([button isFolder]);
- EXPECT_EQ([button bookmarkNode], node);
-}
-
-TEST_F(BookmarkButtonTest, MouseEnterExitRedirect) {
- NSEvent* moveEvent =
- test_event_utils::MouseEventAtPoint(NSMakePoint(10,10), NSMouseMoved, 0);
- scoped_nsobject<BookmarkButton> button;
- scoped_nsobject<BookmarkButtonCell> cell;
- scoped_nsobject<FakeButtonDelegate>
- delegate([[FakeButtonDelegate alloc] init]);
- button.reset([[BookmarkButton alloc] initWithFrame:NSMakeRect(0,0,500,500)]);
- cell.reset([[BookmarkButtonCell alloc] initTextCell:@"hi mom"]);
- [button setCell:cell];
- [button setDelegate:delegate];
-
- EXPECT_EQ(0, delegate.get()->entered_);
- EXPECT_EQ(0, delegate.get()->exited_);
-
- [button mouseEntered:moveEvent];
- EXPECT_EQ(1, delegate.get()->entered_);
- EXPECT_EQ(0, delegate.get()->exited_);
-
- [button mouseExited:moveEvent];
- [button mouseExited:moveEvent];
- EXPECT_EQ(1, delegate.get()->entered_);
- EXPECT_EQ(2, delegate.get()->exited_);
-}
-
-TEST_F(BookmarkButtonTest, DragToTrash) {
- BrowserTestHelper helper_;
-
- scoped_nsobject<BookmarkButton> button;
- scoped_nsobject<BookmarkButtonCell> cell;
- scoped_nsobject<FakeButtonDelegate>
- delegate([[FakeButtonDelegate alloc] init]);
- button.reset([[BookmarkButton alloc] initWithFrame:NSMakeRect(0,0,500,500)]);
- cell.reset([[BookmarkButtonCell alloc] initTextCell:@"hi mom"]);
- [button setCell:cell];
- [button setDelegate:delegate];
-
- // Add a deletable bookmark to the button.
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- const BookmarkNode* barNode = model->GetBookmarkBarNode();
- const BookmarkNode* node = model->AddURL(barNode, 0, ASCIIToUTF16("hi mom"),
- GURL("http://www.google.com"));
- [cell setBookmarkNode:node];
-
- // Verify that if canDragBookmarkButtonToTrash is NO then the button can't
- // be dragged to the trash.
- delegate.get()->canDragToTrash_ = NO;
- NSDragOperation operation = [button draggingSourceOperationMaskForLocal:NO];
- EXPECT_EQ(0u, operation & NSDragOperationDelete);
- operation = [button draggingSourceOperationMaskForLocal:YES];
- EXPECT_EQ(0u, operation & NSDragOperationDelete);
-
- // Verify that if canDragBookmarkButtonToTrash is YES then the button can
- // be dragged to the trash.
- delegate.get()->canDragToTrash_ = YES;
- operation = [button draggingSourceOperationMaskForLocal:NO];
- EXPECT_EQ(NSDragOperationDelete, operation & NSDragOperationDelete);
- operation = [button draggingSourceOperationMaskForLocal:YES];
- EXPECT_EQ(NSDragOperationDelete, operation & NSDragOperationDelete);
-
- // Verify that canDragBookmarkButtonToTrash is called when expected.
- delegate.get()->canDragToTrash_ = YES;
- EXPECT_EQ(0, delegate.get()->didDragToTrashCount_);
- [button draggedImage:nil endedAt:NSZeroPoint operation:NSDragOperationCopy];
- EXPECT_EQ(0, delegate.get()->didDragToTrashCount_);
- [button draggedImage:nil endedAt:NSZeroPoint operation:NSDragOperationMove];
- EXPECT_EQ(0, delegate.get()->didDragToTrashCount_);
- [button draggedImage:nil endedAt:NSZeroPoint operation:NSDragOperationDelete];
- EXPECT_EQ(1, delegate.get()->didDragToTrashCount_);
-}
-
-}
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_drag_source.h b/chrome/browser/cocoa/bookmarks/bookmark_drag_source.h
deleted file mode 100644
index 5c33797..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_drag_source.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// 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 "chrome/browser/bookmarks/bookmark_node_data.h"
-#include "chrome/browser/cocoa/web_contents_drag_source.h"
-
-// A class that handles tracking and event processing for a drag and drop
-// originating from the content area.
-@interface BookmarkDragSource : WebContentsDragSource {
- @private
- // Our drop data. Should only be initialized once.
- std::vector<BookmarkNodeData::Element> dropData_;
-
- Profile* profile_;
-}
-
-// Initialize a DragDataSource object for a drag (originating on the given
-// contentsView and with the given dropData and pboard). Fill the pasteboard
-// with data types appropriate for dropData.
-- (id)initWithContentsView:(TabContentsViewCocoa*)contentsView
- dropData:
- (const std::vector<BookmarkNodeData::Element>&)dropData
- profile:(Profile*)profile
- pasteboard:(NSPasteboard*)pboard
- dragOperationMask:(NSDragOperation)dragOperationMask;
-
-@end
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_drag_source.mm b/chrome/browser/cocoa/bookmarks/bookmark_drag_source.mm
deleted file mode 100644
index 64f9de2..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_drag_source.mm
+++ /dev/null
@@ -1,43 +0,0 @@
-// 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 "chrome/browser/cocoa/bookmarks/bookmark_drag_source.h"
-
-#include "chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/tab_contents/tab_contents_view_mac.h"
-
-@implementation BookmarkDragSource
-
-- (id)initWithContentsView:(TabContentsViewCocoa*)contentsView
- dropData:
- (const std::vector<BookmarkNodeData::Element>&)dropData
- profile:(Profile*)profile
- pasteboard:(NSPasteboard*)pboard
- dragOperationMask:(NSDragOperation)dragOperationMask {
- self = [super initWithContentsView:contentsView
- pasteboard:pboard
- dragOperationMask:dragOperationMask];
- if (self) {
- dropData_ = dropData;
- profile_ = profile;
- }
-
- return self;
-}
-
-- (void)fillPasteboard {
- bookmark_pasteboard_helper_mac::WriteToDragClipboard(dropData_,
- profile_->GetPath().value());
-}
-
-- (NSImage*)dragImage {
- // TODO(feldstein): Do something better than this. Should have badging
- // and a single drag image.
- // http://crbug.com/37264
- return [NSImage imageNamed:NSImageNameMultipleDocuments];
-}
-
-@end // @implementation BookmarkDragSource
-
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_editor_base_controller.h b/chrome/browser/cocoa/bookmarks/bookmark_editor_base_controller.h
deleted file mode 100644
index 5880d79..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_editor_base_controller.h
+++ /dev/null
@@ -1,171 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_EDITOR_BASE_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_EDITOR_BASE_CONTROLLER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/cocoa_protocols_mac.h"
-#include "base/scoped_ptr.h"
-#include "base/scoped_nsobject.h"
-#include "chrome/browser/bookmarks/bookmark_editor.h"
-
-class BookmarkEditorBaseControllerBridge;
-class BookmarkModel;
-@class BookmarkTreeBrowserCell;
-
-// A base controller class for bookmark creation and editing dialogs which
-// present the current bookmark folder structure in a tree view. Do not
-// instantiate this controller directly -- use one of its derived classes.
-// NOTE: If a derived class is intended to be dispatched via the
-// BookmarkEditor::Show static function found in the accompanying
-// implementation, that function will need to be update.
-@interface BookmarkEditorBaseController : NSWindowController {
- @private
- IBOutlet NSButton* newFolderButton_;
- IBOutlet NSButton* okButton_; // Used for unit testing only.
- IBOutlet NSTreeController* folderTreeController_;
- IBOutlet NSOutlineView* folderTreeView_;
-
- NSWindow* parentWindow_; // weak
- Profile* profile_; // weak
- const BookmarkNode* parentNode_; // weak; owned by the model
- BookmarkEditor::Configuration configuration_;
- NSString* initialName_;
- NSString* displayName_; // Bound to a text field in the dialog.
- BOOL okEnabled_; // Bound to the OK button.
- // An array of BookmarkFolderInfo where each item describes a folder in the
- // BookmarkNode structure.
- scoped_nsobject<NSArray> folderTreeArray_;
- // Bound to the table view giving a path to the current selections, of which
- // there should only ever be one.
- scoped_nsobject<NSArray> tableSelectionPaths_;
- // C++ bridge object that observes the BookmarkModel for me.
- scoped_ptr<BookmarkEditorBaseControllerBridge> observer_;
-}
-
-@property (nonatomic, copy) NSString* initialName;
-@property (nonatomic, copy) NSString* displayName;
-@property (nonatomic, assign) BOOL okEnabled;
-@property (nonatomic, retain, readonly) NSArray* folderTreeArray;
-@property (nonatomic, copy) NSArray* tableSelectionPaths;
-
-// Designated initializer. Derived classes should call through to this init.
-- (id)initWithParentWindow:(NSWindow*)parentWindow
- nibName:(NSString*)nibName
- profile:(Profile*)profile
- parent:(const BookmarkNode*)parent
- configuration:(BookmarkEditor::Configuration)configuration;
-
-// Run the bookmark editor as a modal sheet. Does not block.
-- (void)runAsModalSheet;
-
-// Create a new folder at the end of the selected parent folder, give it
-// an untitled name, and put it into editing mode.
-- (IBAction)newFolder:(id)sender;
-
-// The cancel action will dismiss the dialog. Derived classes which
-// override cancel:, must call this after accessing any dialog-related
-// data.
-- (IBAction)cancel:(id)sender;
-
-// The OK action will dismiss the dialog. This action is bound
-// to the OK button of a dialog which presents a tree view of a profile's
-// folder hierarchy and allows the creation of new folders within that tree.
-// When the OK button is pressed, this function will: 1) call the derived
-// class's -[willCommit] function, 2) create any new folders created by
-// the user while the dialog is presented, 3) call the derived class's
-// -[didCommit] function, and then 4) dismiss the dialog. At least one
-// of -[willCommit] and -[didCommit] must be provided by the derived class
-// and should return a NSNumber containing a BOOL or nil ('nil' means YES)
-// indicating if the operation should be allowed to continue.
-// Note: A derived class should not override the ok: action.
-- (IBAction)ok:(id)sender;
-
-// Methods for use by derived classes only.
-
-// Determine and returns the rightmost selected/highlighted element (node)
-// in the bookmark tree view if the tree view is showing, otherwise returns
-// the original |parentNode_|. If the tree view is showing but nothing is
-// selected then the root node is returned.
-- (const BookmarkNode*)selectedNode;
-
-// Select/highlight the given node within the browser tree view. If the
-// node is nil then select the bookmark bar node. Exposed for unit test.
-- (void)selectNodeInBrowser:(const BookmarkNode*)node;
-
-// Notifications called when the BookmarkModel changes out from under me.
-- (void)nodeRemoved:(const BookmarkNode*)node
- fromParent:(const BookmarkNode*)parent;
-- (void)modelChangedPreserveSelection:(BOOL)preserve;
-
-// Accessors
-- (BookmarkModel*)bookmarkModel;
-- (const BookmarkNode*)parentNode;
-
-@end
-
-// Describes the profile's bookmark folder structure: the folder name, the
-// original BookmarkNode pointer (if the folder already exists), a BOOL
-// indicating if the folder is new (meaning: created during this session
-// but not yet committed to the bookmark structure), and an NSArray of
-// child folder BookmarkFolderInfo's following this same structure.
-@interface BookmarkFolderInfo : NSObject {
- @private
- NSString* folderName_;
- const BookmarkNode* folderNode_; // weak
- NSMutableArray* children_;
- BOOL newFolder_;
-}
-
-@property (nonatomic, copy) NSString* folderName;
-@property (nonatomic, assign) const BookmarkNode* folderNode;
-@property (nonatomic, retain) NSMutableArray* children;
-@property (nonatomic, assign) BOOL newFolder;
-
-// Convenience creator for adding a new folder to the editor's bookmark
-// structure. This folder will be added to the bookmark model when the
-// user accepts the dialog. |folderName| must be provided.
-+ (id)bookmarkFolderInfoWithFolderName:(NSString*)folderName;
-
-// Designated initializer. |folderName| must be provided. For folders which
-// already exist in the bookmark model, |folderNode| and |children| (if any
-// children are already attached to this folder) must be provided and
-// |newFolder| should be NO. For folders which the user has added during
-// this session and which have not been committed yet, |newFolder| should be
-// YES and |folderNode| and |children| should be NULL/nil.
-- (id)initWithFolderName:(NSString*)folderName
- folderNode:(const BookmarkNode*)folderNode
- children:(NSMutableArray*)children
- newFolder:(BOOL)newFolder;
-
-// Convenience creator used during construction of the editor's bookmark
-// structure. |folderName| and |folderNode| must be provided. |children|
-// is optional. Private: exposed here for unit testing purposes.
-+ (id)bookmarkFolderInfoWithFolderName:(NSString*)folderName
- folderNode:(const BookmarkNode*)folderNode
- children:(NSMutableArray*)children;
-
-@end
-
-@interface BookmarkEditorBaseController(TestingAPI)
-
-@property (nonatomic, readonly) BOOL okButtonEnabled;
-
-// Create any newly added folders. New folders are nodes in folderTreeArray
-// which are marked as being new (i.e. their kFolderTreeNewFolderKey
-// dictionary item is YES). This is called by -[ok:].
-- (void)createNewFolders;
-
-// Select the given bookmark node within the tree view.
-- (void)selectTestNodeInBrowser:(const BookmarkNode*)node;
-
-// Return the dictionary for the folder selected in the tree.
-- (BookmarkFolderInfo*)selectedFolder;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_EDITOR_BASE_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_editor_base_controller.mm b/chrome/browser/cocoa/bookmarks/bookmark_editor_base_controller.mm
deleted file mode 100644
index 1f0274e..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_editor_base_controller.mm
+++ /dev/null
@@ -1,604 +0,0 @@
-// 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.
-
-#include <stack>
-
-#import "chrome/browser/cocoa/bookmarks/bookmark_editor_base_controller.h"
-
-#include "app/l10n_util.h"
-#include "app/l10n_util_mac.h"
-#include "base/logging.h"
-#include "base/mac_util.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_all_tabs_controller.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_editor_controller.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_tree_browser_cell.h"
-#import "chrome/browser/cocoa/browser_window_controller.h"
-#include "chrome/browser/profile.h"
-#include "grit/generated_resources.h"
-
-@interface BookmarkEditorBaseController ()
-
-// Return the folder tree object for the given path.
-- (BookmarkFolderInfo*)folderForIndexPath:(NSIndexPath*)path;
-
-// (Re)build the folder tree from the BookmarkModel's current state.
-- (void)buildFolderTree;
-
-// Notifies the controller that the bookmark model has changed.
-// |selection| specifies if the current selection should be
-// maintained (usually YES).
-- (void)modelChangedPreserveSelection:(BOOL)preserve;
-
-// Notifies the controller that a node has been removed.
-- (void)nodeRemoved:(const BookmarkNode*)node
- fromParent:(const BookmarkNode*)parent;
-
-// Given a folder node, collect an array containing BookmarkFolderInfos
-// describing its subchildren which are also folders.
-- (NSMutableArray*)addChildFoldersFromNode:(const BookmarkNode*)node;
-
-// Scan the folder tree stemming from the given tree folder and create
-// any newly added folders. Pass down info for the folder which was
-// selected before we began creating folders.
-- (void)createNewFoldersForFolder:(BookmarkFolderInfo*)treeFolder
- selectedFolderInfo:(BookmarkFolderInfo*)selectedFolderInfo;
-
-// Scan the folder tree looking for the given bookmark node and return
-// the selection path thereto.
-- (NSIndexPath*)selectionPathForNode:(const BookmarkNode*)node;
-
-@end
-
-// static; implemented for each platform. Update this function for new
-// classes derived from BookmarkEditorBaseController.
-void BookmarkEditor::Show(gfx::NativeWindow parent_hwnd,
- Profile* profile,
- const BookmarkNode* parent,
- const EditDetails& details,
- Configuration configuration) {
- BookmarkEditorBaseController* controller = nil;
- if (details.type == EditDetails::NEW_FOLDER) {
- controller = [[BookmarkAllTabsController alloc]
- initWithParentWindow:parent_hwnd
- profile:profile
- parent:parent
- configuration:configuration];
- } else {
- controller = [[BookmarkEditorController alloc]
- initWithParentWindow:parent_hwnd
- profile:profile
- parent:parent
- node:details.existing_node
- configuration:configuration];
- }
- [controller runAsModalSheet];
-}
-
-// Adapter to tell BookmarkEditorBaseController when bookmarks change.
-class BookmarkEditorBaseControllerBridge : public BookmarkModelObserver {
- public:
- BookmarkEditorBaseControllerBridge(BookmarkEditorBaseController* controller)
- : controller_(controller),
- importing_(false)
- { }
-
- virtual void Loaded(BookmarkModel* model) {
- [controller_ modelChangedPreserveSelection:YES];
- }
-
- virtual void BookmarkNodeMoved(BookmarkModel* model,
- const BookmarkNode* old_parent,
- int old_index,
- const BookmarkNode* new_parent,
- int new_index) {
- if (!importing_ && new_parent->GetChild(new_index)->is_folder())
- [controller_ modelChangedPreserveSelection:YES];
- }
-
- virtual void BookmarkNodeAdded(BookmarkModel* model,
- const BookmarkNode* parent,
- int index) {
- if (!importing_ && parent->GetChild(index)->is_folder())
- [controller_ modelChangedPreserveSelection:YES];
- }
-
- virtual void BookmarkNodeRemoved(BookmarkModel* model,
- const BookmarkNode* parent,
- int old_index,
- const BookmarkNode* node) {
- [controller_ nodeRemoved:node fromParent:parent];
- if (node->is_folder())
- [controller_ modelChangedPreserveSelection:NO];
- }
-
- virtual void BookmarkNodeChanged(BookmarkModel* model,
- const BookmarkNode* node) {
- if (!importing_ && node->is_folder())
- [controller_ modelChangedPreserveSelection:YES];
- }
-
- virtual void BookmarkNodeChildrenReordered(BookmarkModel* model,
- const BookmarkNode* node) {
- if (!importing_)
- [controller_ modelChangedPreserveSelection:YES];
- }
-
- virtual void BookmarkNodeFavIconLoaded(BookmarkModel* model,
- const BookmarkNode* node) {
- // I care nothing for these 'favicons': I only show folders.
- }
-
- virtual void BookmarkImportBeginning(BookmarkModel* model) {
- importing_ = true;
- }
-
- // Invoked after a batch import finishes. This tells observers to update
- // themselves if they were waiting for the update to finish.
- virtual void BookmarkImportEnding(BookmarkModel* model) {
- importing_ = false;
- [controller_ modelChangedPreserveSelection:YES];
- }
-
- private:
- BookmarkEditorBaseController* controller_; // weak
- bool importing_;
-};
-
-
-#pragma mark -
-
-@implementation BookmarkEditorBaseController
-
-@synthesize initialName = initialName_;
-@synthesize displayName = displayName_;
-@synthesize okEnabled = okEnabled_;
-
-- (id)initWithParentWindow:(NSWindow*)parentWindow
- nibName:(NSString*)nibName
- profile:(Profile*)profile
- parent:(const BookmarkNode*)parent
- configuration:(BookmarkEditor::Configuration)configuration {
- NSString* nibpath = [mac_util::MainAppBundle()
- pathForResource:nibName
- ofType:@"nib"];
- if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
- parentWindow_ = parentWindow;
- profile_ = profile;
- parentNode_ = parent;
- configuration_ = configuration;
- initialName_ = [@"" retain];
- observer_.reset(new BookmarkEditorBaseControllerBridge(self));
- [self bookmarkModel]->AddObserver(observer_.get());
- }
- return self;
-}
-
-- (void)dealloc {
- [self bookmarkModel]->RemoveObserver(observer_.get());
- [initialName_ release];
- [displayName_ release];
- [super dealloc];
-}
-
-- (void)awakeFromNib {
- [self setDisplayName:[self initialName]];
-
- if (configuration_ != BookmarkEditor::SHOW_TREE) {
- // Remember the tree view's height; we will shrink our frame by that much.
- NSRect frame = [[self window] frame];
- CGFloat browserHeight = [folderTreeView_ frame].size.height;
- frame.size.height -= browserHeight;
- frame.origin.y += browserHeight;
- // Remove the folder tree and "new folder" button.
- [folderTreeView_ removeFromSuperview];
- [newFolderButton_ removeFromSuperview];
- // Finally, commit the size change.
- [[self window] setFrame:frame display:YES];
- }
-
- // Build up a tree of the current folder configuration.
- [self buildFolderTree];
-}
-
-- (void)windowDidLoad {
- if (configuration_ == BookmarkEditor::SHOW_TREE) {
- [self selectNodeInBrowser:parentNode_];
- }
-}
-
-/* TODO(jrg):
-// Implementing this informal protocol allows us to open the sheet
-// somewhere other than at the top of the window. NOTE: this means
-// that I, the controller, am also the window's delegate.
-- (NSRect)window:(NSWindow*)window willPositionSheet:(NSWindow*)sheet
- usingRect:(NSRect)rect {
- // adjust rect.origin.y to be the bottom of the toolbar
- return rect;
-}
-*/
-
-// TODO(jrg): consider NSModalSession.
-- (void)runAsModalSheet {
- // Lock down floating bar when in full-screen mode. Don't animate
- // otherwise the pane will be misplaced.
- [[BrowserWindowController browserWindowControllerForWindow:parentWindow_]
- lockBarVisibilityForOwner:self withAnimation:NO delay:NO];
- [NSApp beginSheet:[self window]
- modalForWindow:parentWindow_
- modalDelegate:self
- didEndSelector:@selector(didEndSheet:returnCode:contextInfo:)
- contextInfo:nil];
-}
-
-- (BOOL)okEnabled {
- return YES;
-}
-
-- (IBAction)ok:(id)sender {
- // At least one of these two functions should be provided by derived classes.
- BOOL hasWillCommit = [self respondsToSelector:@selector(willCommit)];
- BOOL hasDidCommit = [self respondsToSelector:@selector(didCommit)];
- DCHECK(hasWillCommit || hasDidCommit);
- BOOL shouldContinue = YES;
- if (hasWillCommit) {
- NSNumber* hasWillContinue = [self performSelector:@selector(willCommit)];
- if (hasWillContinue && [hasWillContinue isKindOfClass:[NSNumber class]])
- shouldContinue = [hasWillContinue boolValue];
- }
- if (shouldContinue)
- [self createNewFolders];
- if (hasDidCommit) {
- NSNumber* hasDidContinue = [self performSelector:@selector(didCommit)];
- if (hasDidContinue && [hasDidContinue isKindOfClass:[NSNumber class]])
- shouldContinue = [hasDidContinue boolValue];
- }
- if (shouldContinue)
- [NSApp endSheet:[self window]];
-}
-
-- (IBAction)cancel:(id)sender {
- [NSApp endSheet:[self window]];
-}
-
-- (void)didEndSheet:(NSWindow*)sheet
- returnCode:(int)returnCode
- contextInfo:(void*)contextInfo {
- [sheet close];
- [[BrowserWindowController browserWindowControllerForWindow:parentWindow_]
- releaseBarVisibilityForOwner:self withAnimation:YES delay:NO];
-}
-
-- (void)windowWillClose:(NSNotification*)notification {
- [self autorelease];
-}
-
-#pragma mark Folder Tree Management
-
-- (BookmarkModel*)bookmarkModel {
- return profile_->GetBookmarkModel();
-}
-
-- (const BookmarkNode*)parentNode {
- return parentNode_;
-}
-
-- (BookmarkFolderInfo*)folderForIndexPath:(NSIndexPath*)indexPath {
- NSUInteger pathCount = [indexPath length];
- BookmarkFolderInfo* item = nil;
- NSArray* treeNode = [self folderTreeArray];
- for (NSUInteger i = 0; i < pathCount; ++i) {
- item = [treeNode objectAtIndex:[indexPath indexAtPosition:i]];
- treeNode = [item children];
- }
- return item;
-}
-
-- (NSIndexPath*)selectedIndexPath {
- NSIndexPath* selectedIndexPath = nil;
- NSArray* selections = [self tableSelectionPaths];
- if ([selections count]) {
- DCHECK([selections count] == 1); // Should be exactly one selection.
- selectedIndexPath = [selections objectAtIndex:0];
- }
- return selectedIndexPath;
-}
-
-- (BookmarkFolderInfo*)selectedFolder {
- BookmarkFolderInfo* item = nil;
- NSIndexPath* selectedIndexPath = [self selectedIndexPath];
- if (selectedIndexPath) {
- item = [self folderForIndexPath:selectedIndexPath];
- }
- return item;
-}
-
-- (const BookmarkNode*)selectedNode {
- const BookmarkNode* selectedNode = NULL;
- // Determine a new parent node only if the browser is showing.
- if (configuration_ == BookmarkEditor::SHOW_TREE) {
- BookmarkFolderInfo* folderInfo = [self selectedFolder];
- if (folderInfo)
- selectedNode = [folderInfo folderNode];
- } else {
- // If the tree is not showing then we use the original parent.
- selectedNode = parentNode_;
- }
- return selectedNode;
-}
-
-- (NSArray*)folderTreeArray {
- return folderTreeArray_.get();
-}
-
-- (NSArray*)tableSelectionPaths {
- return tableSelectionPaths_.get();
-}
-
-- (void)setTableSelectionPath:(NSIndexPath*)tableSelectionPath {
- [self setTableSelectionPaths:[NSArray arrayWithObject:tableSelectionPath]];
-}
-
-- (void)setTableSelectionPaths:(NSArray*)tableSelectionPaths {
- tableSelectionPaths_.reset([tableSelectionPaths retain]);
-}
-
-- (void)selectNodeInBrowser:(const BookmarkNode*)node {
- DCHECK(configuration_ == BookmarkEditor::SHOW_TREE);
- NSIndexPath* selectionPath = [self selectionPathForNode:node];
- [self willChangeValueForKey:@"okEnabled"];
- [self setTableSelectionPath:selectionPath];
- [self didChangeValueForKey:@"okEnabled"];
-}
-
-- (NSIndexPath*)selectionPathForNode:(const BookmarkNode*)desiredNode {
- // Back up the parent chaing for desiredNode, building up a stack
- // of ancestor nodes. Then crawl down the folderTreeArray looking
- // for each ancestor in order while building up the selectionPath.
- std::stack<const BookmarkNode*> nodeStack;
- BookmarkModel* model = profile_->GetBookmarkModel();
- const BookmarkNode* rootNode = model->root_node();
- const BookmarkNode* node = desiredNode;
- while (node != rootNode) {
- DCHECK(node);
- nodeStack.push(node);
- node = node->GetParent();
- }
- NSUInteger stackSize = nodeStack.size();
-
- NSIndexPath* path = nil;
- NSArray* folders = [self folderTreeArray];
- while (!nodeStack.empty()) {
- node = nodeStack.top();
- nodeStack.pop();
- // Find node in the current folders array.
- NSUInteger i = 0;
- for (BookmarkFolderInfo *folderInfo in folders) {
- const BookmarkNode* testNode = [folderInfo folderNode];
- if (testNode == node) {
- path = path ? [path indexPathByAddingIndex:i] :
- [NSIndexPath indexPathWithIndex:i];
- folders = [folderInfo children];
- break;
- }
- ++i;
- }
- }
- DCHECK([path length] == stackSize);
- return path;
-}
-
-- (NSMutableArray*)addChildFoldersFromNode:(const BookmarkNode*)node {
- NSMutableArray* childFolders = nil;
- int childCount = node->GetChildCount();
- for (int i = 0; i < childCount; ++i) {
- const BookmarkNode* childNode = node->GetChild(i);
- if (childNode->type() != BookmarkNode::URL) {
- NSString* childName = base::SysUTF16ToNSString(childNode->GetTitle());
- NSMutableArray* children = [self addChildFoldersFromNode:childNode];
- BookmarkFolderInfo* folderInfo =
- [BookmarkFolderInfo bookmarkFolderInfoWithFolderName:childName
- folderNode:childNode
- children:children];
- if (!childFolders)
- childFolders = [NSMutableArray arrayWithObject:folderInfo];
- else
- [childFolders addObject:folderInfo];
- }
- }
- return childFolders;
-}
-
-- (void)buildFolderTree {
- // Build up a tree of the current folder configuration.
- BookmarkModel* model = profile_->GetBookmarkModel();
- const BookmarkNode* rootNode = model->root_node();
- NSMutableArray* baseArray = [self addChildFoldersFromNode:rootNode];
- DCHECK(baseArray);
- [self willChangeValueForKey:@"folderTreeArray"];
- folderTreeArray_.reset([baseArray retain]);
- [self didChangeValueForKey:@"folderTreeArray"];
-}
-
-- (void)modelChangedPreserveSelection:(BOOL)preserve {
- const BookmarkNode* selectedNode = [self selectedNode];
- [self buildFolderTree];
- if (preserve &&
- selectedNode &&
- configuration_ == BookmarkEditor::SHOW_TREE)
- [self selectNodeInBrowser:selectedNode];
-}
-
-- (void)nodeRemoved:(const BookmarkNode*)node
- fromParent:(const BookmarkNode*)parent {
- if (node->is_folder()) {
- if (parentNode_ == node || parentNode_->HasAncestor(node)) {
- parentNode_ = [self bookmarkModel]->GetBookmarkBarNode();
- if (configuration_ != BookmarkEditor::SHOW_TREE) {
- // The user can't select a different folder, so just close up shop.
- [self cancel:self];
- return;
- }
- }
-
- if (configuration_ == BookmarkEditor::SHOW_TREE) {
- // For safety's sake, in case deleted node was an ancestor of selection,
- // go back to a known safe place.
- [self selectNodeInBrowser:parentNode_];
- }
- }
-}
-
-#pragma mark New Folder Handler
-
-- (void)createNewFoldersForFolder:(BookmarkFolderInfo*)folderInfo
- selectedFolderInfo:(BookmarkFolderInfo*)selectedFolderInfo {
- NSArray* subfolders = [folderInfo children];
- const BookmarkNode* parentNode = [folderInfo folderNode];
- DCHECK(parentNode);
- NSUInteger i = 0;
- for (BookmarkFolderInfo* subFolderInfo in subfolders) {
- if ([subFolderInfo newFolder]) {
- BookmarkModel* model = [self bookmarkModel];
- const BookmarkNode* newFolder =
- model->AddGroup(parentNode, i,
- base::SysNSStringToUTF16([subFolderInfo folderName]));
- // Update our dictionary with the actual folder node just created.
- [subFolderInfo setFolderNode:newFolder];
- [subFolderInfo setNewFolder:NO];
- // If the newly created folder was selected, update the selection path.
- if (subFolderInfo == selectedFolderInfo) {
- NSIndexPath* selectionPath = [self selectionPathForNode:newFolder];
- [self setTableSelectionPath:selectionPath];
- }
- }
- [self createNewFoldersForFolder:subFolderInfo
- selectedFolderInfo:selectedFolderInfo];
- ++i;
- }
-}
-
-- (IBAction)newFolder:(id)sender {
- // Create a new folder off of the selected folder node.
- BookmarkFolderInfo* parentInfo = [self selectedFolder];
- if (parentInfo) {
- NSIndexPath* selection = [self selectedIndexPath];
- NSString* newFolderName =
- l10n_util::GetNSStringWithFixup(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME);
- BookmarkFolderInfo* folderInfo =
- [BookmarkFolderInfo bookmarkFolderInfoWithFolderName:newFolderName];
- [self willChangeValueForKey:@"folderTreeArray"];
- NSMutableArray* children = [parentInfo children];
- if (children) {
- [children addObject:folderInfo];
- } else {
- children = [NSMutableArray arrayWithObject:folderInfo];
- [parentInfo setChildren:children];
- }
- [self didChangeValueForKey:@"folderTreeArray"];
-
- // Expose the parent folder children.
- [folderTreeView_ expandItem:parentInfo];
-
- // Select the new folder node and put the folder name into edit mode.
- selection = [selection indexPathByAddingIndex:[children count] - 1];
- [self setTableSelectionPath:selection];
- NSInteger row = [folderTreeView_ selectedRow];
- DCHECK(row >= 0);
- [folderTreeView_ editColumn:0 row:row withEvent:nil select:YES];
- }
-}
-
-- (void)createNewFolders {
- // Turn off notifications while "importing" folders (as created in the sheet).
- observer_->BookmarkImportBeginning([self bookmarkModel]);
- // Scan the tree looking for nodes marked 'newFolder' and create those nodes.
- NSArray* folderTreeArray = [self folderTreeArray];
- for (BookmarkFolderInfo *folderInfo in folderTreeArray) {
- [self createNewFoldersForFolder:folderInfo
- selectedFolderInfo:[self selectedFolder]];
- }
- // Notifications back on.
- observer_->BookmarkImportEnding([self bookmarkModel]);
-}
-
-#pragma mark For Unit Test Use Only
-
-- (BOOL)okButtonEnabled {
- return [okButton_ isEnabled];
-}
-
-- (void)selectTestNodeInBrowser:(const BookmarkNode*)node {
- [self selectNodeInBrowser:node];
-}
-
-@end // BookmarkEditorBaseController
-
-@implementation BookmarkFolderInfo
-
-@synthesize folderName = folderName_;
-@synthesize folderNode = folderNode_;
-@synthesize children = children_;
-@synthesize newFolder = newFolder_;
-
-+ (id)bookmarkFolderInfoWithFolderName:(NSString*)folderName
- folderNode:(const BookmarkNode*)folderNode
- children:(NSMutableArray*)children {
- return [[[BookmarkFolderInfo alloc] initWithFolderName:folderName
- folderNode:folderNode
- children:children
- newFolder:NO]
- autorelease];
-}
-
-+ (id)bookmarkFolderInfoWithFolderName:(NSString*)folderName {
- return [[[BookmarkFolderInfo alloc] initWithFolderName:folderName
- folderNode:NULL
- children:nil
- newFolder:YES]
- autorelease];
-}
-
-- (id)initWithFolderName:(NSString*)folderName
- folderNode:(const BookmarkNode*)folderNode
- children:(NSMutableArray*)children
- newFolder:(BOOL)newFolder {
- if ((self = [super init])) {
- // A folderName is always required, and if newFolder is NO then there
- // should be a folderNode. Children is optional.
- DCHECK(folderName && (newFolder || folderNode));
- if (folderName && (newFolder || folderNode)) {
- folderName_ = [folderName copy];
- folderNode_ = folderNode;
- children_ = [children retain];
- newFolder_ = newFolder;
- } else {
- NOTREACHED(); // Invalid init.
- [self release];
- self = nil;
- }
- }
- return self;
-}
-
-- (id)init {
- NOTREACHED(); // Should never be called.
- return [self initWithFolderName:nil folderNode:nil children:nil newFolder:NO];
-}
-
-- (void)dealloc {
- [folderName_ release];
- [children_ release];
- [super dealloc];
-}
-
-// Implementing isEqual: allows the NSTreeController to preserve the selection
-// and open/shut state of outline items when the data changes.
-- (BOOL)isEqual:(id)other {
- return [other isKindOfClass:[BookmarkFolderInfo class]] &&
- folderNode_ == [(BookmarkFolderInfo*)other folderNode];
-}
-
-@end
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_editor_base_controller_unittest.mm b/chrome/browser/cocoa/bookmarks/bookmark_editor_base_controller_unittest.mm
deleted file mode 100644
index daac540..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_editor_base_controller_unittest.mm
+++ /dev/null
@@ -1,235 +0,0 @@
-// 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 "app/l10n_util_mac.h"
-#include "base/scoped_nsobject.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_editor_controller.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "grit/generated_resources.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-class BookmarkEditorBaseControllerTest : public CocoaTest {
- public:
- BrowserTestHelper browser_helper_;
- BookmarkEditorBaseController* controller_; // weak
- const BookmarkNode* group_a_;
- const BookmarkNode* group_b_;
- const BookmarkNode* group_b_0_;
- const BookmarkNode* group_b_3_;
- const BookmarkNode* group_c_;
-
- BookmarkEditorBaseControllerTest() {
- // Set up a small bookmark hierarchy, which will look as follows:
- // a b c d
- // a-0 b-0 c-0
- // a-1 b-00 c-1
- // a-2 b-1 c-2
- // b-2 c-3
- // b-3
- // b-30
- // b-31
- // b-4
- BookmarkModel& model(*(browser_helper_.profile()->GetBookmarkModel()));
- const BookmarkNode* root = model.GetBookmarkBarNode();
- group_a_ = model.AddGroup(root, 0, ASCIIToUTF16("a"));
- model.AddURL(group_a_, 0, ASCIIToUTF16("a-0"), GURL("http://a-0.com"));
- model.AddURL(group_a_, 1, ASCIIToUTF16("a-1"), GURL("http://a-1.com"));
- model.AddURL(group_a_, 2, ASCIIToUTF16("a-2"), GURL("http://a-2.com"));
-
- group_b_ = model.AddGroup(root, 1, ASCIIToUTF16("b"));
- group_b_0_ = model.AddGroup(group_b_, 0, ASCIIToUTF16("b-0"));
- model.AddURL(group_b_0_, 0, ASCIIToUTF16("bb-0"), GURL("http://bb-0.com"));
- model.AddURL(group_b_, 1, ASCIIToUTF16("b-1"), GURL("http://b-1.com"));
- model.AddURL(group_b_, 2, ASCIIToUTF16("b-2"), GURL("http://b-2.com"));
- group_b_3_ = model.AddGroup(group_b_, 3, ASCIIToUTF16("b-3"));
- model.AddURL(group_b_3_, 0, ASCIIToUTF16("b-30"), GURL("http://b-30.com"));
- model.AddURL(group_b_3_, 1, ASCIIToUTF16("b-31"), GURL("http://b-31.com"));
- model.AddURL(group_b_, 4, ASCIIToUTF16("b-4"), GURL("http://b-4.com"));
-
- group_c_ = model.AddGroup(root, 2, ASCIIToUTF16("c"));
- model.AddURL(group_c_, 0, ASCIIToUTF16("c-0"), GURL("http://c-0.com"));
- model.AddURL(group_c_, 1, ASCIIToUTF16("c-1"), GURL("http://c-1.com"));
- model.AddURL(group_c_, 2, ASCIIToUTF16("c-2"), GURL("http://c-2.com"));
- model.AddURL(group_c_, 3, ASCIIToUTF16("c-3"), GURL("http://c-3.com"));
-
- model.AddURL(root, 3, ASCIIToUTF16("d"), GURL("http://d-0.com"));
- }
-
- virtual BookmarkEditorBaseController* CreateController() {
- return [[BookmarkEditorBaseController alloc]
- initWithParentWindow:test_window()
- nibName:@"BookmarkAllTabs"
- profile:browser_helper_.profile()
- parent:group_b_0_
- configuration:BookmarkEditor::SHOW_TREE];
- }
-
- virtual void SetUp() {
- CocoaTest::SetUp();
- controller_ = CreateController();
- EXPECT_TRUE([controller_ window]);
- [controller_ runAsModalSheet];
- }
-
- virtual void TearDown() {
- controller_ = NULL;
- CocoaTest::TearDown();
- }
-};
-
-TEST_F(BookmarkEditorBaseControllerTest, VerifyBookmarkTestModel) {
- BookmarkModel& model(*(browser_helper_.profile()->GetBookmarkModel()));
- const BookmarkNode& root(*model.GetBookmarkBarNode());
- EXPECT_EQ(4, root.GetChildCount());
- // a
- const BookmarkNode* child = root.GetChild(0);
- EXPECT_EQ(3, child->GetChildCount());
- const BookmarkNode* subchild = child->GetChild(0);
- EXPECT_EQ(0, subchild->GetChildCount());
- subchild = child->GetChild(1);
- EXPECT_EQ(0, subchild->GetChildCount());
- subchild = child->GetChild(2);
- EXPECT_EQ(0, subchild->GetChildCount());
- // b
- child = root.GetChild(1);
- EXPECT_EQ(5, child->GetChildCount());
- subchild = child->GetChild(0);
- EXPECT_EQ(1, subchild->GetChildCount());
- const BookmarkNode* subsubchild = subchild->GetChild(0);
- EXPECT_EQ(0, subsubchild->GetChildCount());
- subchild = child->GetChild(1);
- EXPECT_EQ(0, subchild->GetChildCount());
- subchild = child->GetChild(2);
- EXPECT_EQ(0, subchild->GetChildCount());
- subchild = child->GetChild(3);
- EXPECT_EQ(2, subchild->GetChildCount());
- subsubchild = subchild->GetChild(0);
- EXPECT_EQ(0, subsubchild->GetChildCount());
- subsubchild = subchild->GetChild(1);
- EXPECT_EQ(0, subsubchild->GetChildCount());
- subchild = child->GetChild(4);
- EXPECT_EQ(0, subchild->GetChildCount());
- // c
- child = root.GetChild(2);
- EXPECT_EQ(4, child->GetChildCount());
- subchild = child->GetChild(0);
- EXPECT_EQ(0, subchild->GetChildCount());
- subchild = child->GetChild(1);
- EXPECT_EQ(0, subchild->GetChildCount());
- subchild = child->GetChild(2);
- EXPECT_EQ(0, subchild->GetChildCount());
- subchild = child->GetChild(3);
- EXPECT_EQ(0, subchild->GetChildCount());
- // d
- child = root.GetChild(3);
- EXPECT_EQ(0, child->GetChildCount());
- [controller_ cancel:nil];
-}
-
-TEST_F(BookmarkEditorBaseControllerTest, NodeSelection) {
- EXPECT_TRUE([controller_ folderTreeArray]);
- [controller_ selectTestNodeInBrowser:group_b_3_];
- const BookmarkNode* node = [controller_ selectedNode];
- EXPECT_EQ(node, group_b_3_);
- [controller_ cancel:nil];
-}
-
-TEST_F(BookmarkEditorBaseControllerTest, CreateFolder) {
- EXPECT_EQ(2, group_b_3_->GetChildCount());
- [controller_ selectTestNodeInBrowser:group_b_3_];
- NSString* expectedName =
- l10n_util::GetNSStringWithFixup(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME);
- [controller_ setDisplayName:expectedName];
- [controller_ newFolder:nil];
- NSArray* selectionPaths = [controller_ tableSelectionPaths];
- EXPECT_EQ(1U, [selectionPaths count]);
- NSIndexPath* selectionPath = [selectionPaths objectAtIndex:0];
- EXPECT_EQ(4U, [selectionPath length]);
- BookmarkFolderInfo* newFolderInfo = [controller_ selectedFolder];
- EXPECT_TRUE(newFolderInfo);
- NSString* newFolderName = [newFolderInfo folderName];
- EXPECT_NSEQ(expectedName, newFolderName);
- [controller_ createNewFolders];
- // Verify that the tab folder was added to the new folder.
- EXPECT_EQ(3, group_b_3_->GetChildCount());
- [controller_ cancel:nil];
-}
-
-TEST_F(BookmarkEditorBaseControllerTest, CreateTwoFolders) {
- BookmarkModel* model = browser_helper_.profile()->GetBookmarkModel();
- const BookmarkNode* bar = model->GetBookmarkBarNode();
- // Create 2 folders which are children of the bar.
- [controller_ selectTestNodeInBrowser:bar];
- [controller_ newFolder:nil];
- [controller_ selectTestNodeInBrowser:bar];
- [controller_ newFolder:nil];
- // If we do NOT crash on createNewFolders, success!
- // (e.g. http://crbug.com/47877 is fixed).
- [controller_ createNewFolders];
- [controller_ cancel:nil];
-}
-
-TEST_F(BookmarkEditorBaseControllerTest, SelectedFolderDeleted) {
- BookmarkModel& model(*(browser_helper_.profile()->GetBookmarkModel()));
- [controller_ selectTestNodeInBrowser:group_b_3_];
- EXPECT_EQ(group_b_3_, [controller_ selectedNode]);
-
- // Delete the selected node, and verify it's no longer selected:
- model.Remove(group_b_, 3);
- EXPECT_NE(group_b_3_, [controller_ selectedNode]);
-
- [controller_ cancel:nil];
-}
-
-TEST_F(BookmarkEditorBaseControllerTest, SelectedFoldersParentDeleted) {
- BookmarkModel& model(*(browser_helper_.profile()->GetBookmarkModel()));
- const BookmarkNode* root = model.GetBookmarkBarNode();
- [controller_ selectTestNodeInBrowser:group_b_3_];
- EXPECT_EQ(group_b_3_, [controller_ selectedNode]);
-
- // Delete the selected node's parent, and verify it's no longer selected:
- model.Remove(root, 1);
- EXPECT_NE(group_b_3_, [controller_ selectedNode]);
-
- [controller_ cancel:nil];
-}
-
-TEST_F(BookmarkEditorBaseControllerTest, FolderAdded) {
- BookmarkModel& model(*(browser_helper_.profile()->GetBookmarkModel()));
- const BookmarkNode* root = model.GetBookmarkBarNode();
-
- // Add a group node to the model, and verify it can be selected in the tree:
- const BookmarkNode* group_added = model.AddGroup(root, 0,
- ASCIIToUTF16("added"));
- [controller_ selectTestNodeInBrowser:group_added];
- EXPECT_EQ(group_added, [controller_ selectedNode]);
-
- [controller_ cancel:nil];
-}
-
-
-class BookmarkFolderInfoTest : public CocoaTest { };
-
-TEST_F(BookmarkFolderInfoTest, Construction) {
- NSMutableArray* children = [NSMutableArray arrayWithObject:@"child"];
- // We just need a pointer, and any pointer will do.
- const BookmarkNode* fakeNode =
- reinterpret_cast<const BookmarkNode*>(&children);
- BookmarkFolderInfo* info =
- [BookmarkFolderInfo bookmarkFolderInfoWithFolderName:@"name"
- folderNode:fakeNode
- children:children];
- EXPECT_TRUE(info);
- EXPECT_EQ([info folderName], @"name");
- EXPECT_EQ([info children], children);
- EXPECT_EQ([info folderNode], fakeNode);
-}
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_editor_controller.h b/chrome/browser/cocoa/bookmarks/bookmark_editor_controller.h
deleted file mode 100644
index 11bd58c..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_editor_controller.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_EDITOR_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_EDITOR_CONTROLLER_H_
-#pragma once
-
-#import "chrome/browser/cocoa/bookmarks/bookmark_editor_base_controller.h"
-
-// A controller for the bookmark editor, opened by 1) Edit... from the
-// context menu of a bookmark button, and 2) Bookmark this Page...'s Edit
-// button.
-@interface BookmarkEditorController : BookmarkEditorBaseController {
- @private
- const BookmarkNode* node_; // weak; owned by the model
- scoped_nsobject<NSString> initialUrl_;
- NSString* displayURL_; // Bound to a text field in the dialog.
- IBOutlet NSTextField* urlField_;
-}
-
-@property (nonatomic, copy) NSString* displayURL;
-
-- (id)initWithParentWindow:(NSWindow*)parentWindow
- profile:(Profile*)profile
- parent:(const BookmarkNode*)parent
- node:(const BookmarkNode*)node
- configuration:(BookmarkEditor::Configuration)configuration;
-
-@end
-
-@interface BookmarkEditorController (UnitTesting)
-- (NSColor *)urlFieldColor;
-@end
-
-#endif // CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_EDITOR_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_editor_controller.mm b/chrome/browser/cocoa/bookmarks/bookmark_editor_controller.mm
deleted file mode 100644
index 14500c9..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_editor_controller.mm
+++ /dev/null
@@ -1,143 +0,0 @@
-// 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 "chrome/browser/cocoa/bookmarks/bookmark_editor_controller.h"
-
-#include "app/l10n_util.h"
-#include "base/string16.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-
-@interface BookmarkEditorController (Private)
-
-// Grab the url from the text field and convert.
-- (GURL)GURLFromUrlField;
-
-@end
-
-@implementation BookmarkEditorController
-
-@synthesize displayURL = displayURL_;
-
-+ (NSSet*)keyPathsForValuesAffectingOkEnabled {
- return [NSSet setWithObject:@"displayURL"];
-}
-
-- (id)initWithParentWindow:(NSWindow*)parentWindow
- profile:(Profile*)profile
- parent:(const BookmarkNode*)parent
- node:(const BookmarkNode*)node
- configuration:(BookmarkEditor::Configuration)configuration {
- if ((self = [super initWithParentWindow:parentWindow
- nibName:@"BookmarkEditor"
- profile:profile
- parent:parent
- configuration:configuration])) {
- // "Add Page..." has no "node" so this may be NULL.
- node_ = node;
- }
- return self;
-}
-
-- (void)dealloc {
- [displayURL_ release];
- [super dealloc];
-}
-
-- (void)awakeFromNib {
- // Set text fields to match our bookmark. If the node is NULL we
- // arrived here from an "Add Page..." item in a context menu.
- if (node_) {
- [self setInitialName:base::SysUTF16ToNSString(node_->GetTitle())];
- std::string url_string = node_->GetURL().possibly_invalid_spec();
- initialUrl_.reset([[NSString stringWithUTF8String:url_string.c_str()]
- retain]);
- } else {
- initialUrl_.reset([@"" retain]);
- }
- [self setDisplayURL:initialUrl_];
- [super awakeFromNib];
-}
-
-- (void)nodeRemoved:(const BookmarkNode*)node
- fromParent:(const BookmarkNode*)parent
-{
- // Be conservative; it is needed (e.g. "Add Page...")
- node_ = NULL;
- [self cancel:self];
-}
-
-#pragma mark Bookmark Editing
-
-// If possible, return a valid GURL from the URL text field.
-- (GURL)GURLFromUrlField {
- NSString* url = [self displayURL];
- GURL newURL = GURL([url UTF8String]);
- if (!newURL.is_valid()) {
- // Mimic observed friendliness from Windows
- newURL = GURL([[NSString stringWithFormat:@"http://%@", url] UTF8String]);
- }
- return newURL;
-}
-
-// Enable the OK button if there is a valid URL.
-- (BOOL)okEnabled {
- BOOL okEnabled = NO;
- if ([[self displayURL] length]) {
- GURL newURL = [self GURLFromUrlField];
- okEnabled = (newURL.is_valid()) ? YES : NO;
- }
- if (okEnabled)
- [urlField_ setBackgroundColor:[NSColor whiteColor]];
- else
- [urlField_ setBackgroundColor:[NSColor colorWithCalibratedRed:1.0
- green:0.67
- blue:0.67
- alpha:1.0]];
- return okEnabled;
-}
-
-// The the bookmark's URL is assumed to be valid (otherwise the OK button
-// should not be enabled). Previously existing bookmarks for which the
-// parent has not changed are updated in-place. Those for which the parent
-// has changed are removed with a new node created under the new parent.
-// Called by -[BookmarkEditorBaseController ok:].
-- (NSNumber*)didCommit {
- NSString* name = [[self displayName] stringByTrimmingCharactersInSet:
- [NSCharacterSet newlineCharacterSet]];
- string16 newTitle = base::SysNSStringToUTF16(name);
- const BookmarkNode* newParentNode = [self selectedNode];
- GURL newURL = [self GURLFromUrlField];
- if (!newURL.is_valid()) {
- // Shouldn't be reached -- OK button should be disabled if not valid!
- NOTREACHED();
- return [NSNumber numberWithBool:NO];
- }
-
- // Determine where the new/replacement bookmark is to go.
- BookmarkModel* model = [self bookmarkModel];
- // If there was an old node then we update the node, and move it to its new
- // parent if the parent has changed (rather than deleting it from the old
- // parent and adding to the new -- which also prevents the 'poofing' that
- // occurs when a node is deleted).
- if (node_) {
- model->SetURL(node_, newURL);
- model->SetTitle(node_, newTitle);
- const BookmarkNode* oldParentNode = [self parentNode];
- if (newParentNode != oldParentNode)
- model->Move(node_, newParentNode, newParentNode->GetChildCount());
- } else {
- // Otherwise, add a new bookmark at the end of the newly selected folder.
- model->AddURL(newParentNode, newParentNode->GetChildCount(), newTitle,
- newURL);
- }
- return [NSNumber numberWithBool:YES];
-}
-
-- (NSColor *)urlFieldColor {
- return [urlField_ backgroundColor];
-}
-
-@end // BookmarkEditorController
-
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_editor_controller_unittest.mm b/chrome/browser/cocoa/bookmarks/bookmark_editor_controller_unittest.mm
deleted file mode 100644
index e19898d..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_editor_controller_unittest.mm
+++ /dev/null
@@ -1,423 +0,0 @@
-// 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 "base/string16.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_editor_controller.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-class BookmarkEditorControllerTest : public CocoaTest {
- public:
- BrowserTestHelper browser_helper_;
- const BookmarkNode* default_node_;
- const BookmarkNode* default_parent_;
- const char* default_name_;
- string16 default_title_;
- BookmarkEditorController* controller_;
-
- virtual void SetUp() {
- CocoaTest::SetUp();
- BookmarkModel* model = browser_helper_.profile()->GetBookmarkModel();
- default_parent_ = model->GetBookmarkBarNode();
- default_name_ = "http://www.zim-bop-a-dee.com/";
- default_title_ = ASCIIToUTF16("ooh title");
- const BookmarkNode* default_node = model->AddURL(default_parent_, 0,
- default_title_,
- GURL(default_name_));
- controller_ = [[BookmarkEditorController alloc]
- initWithParentWindow:test_window()
- profile:browser_helper_.profile()
- parent:default_parent_
- node:default_node
- configuration:BookmarkEditor::NO_TREE];
- [controller_ runAsModalSheet];
- }
-
- virtual void TearDown() {
- controller_ = NULL;
- CocoaTest::TearDown();
- }
-};
-
-TEST_F(BookmarkEditorControllerTest, NoEdit) {
- [controller_ cancel:nil];
- ASSERT_EQ(default_parent_->GetChildCount(), 1);
- const BookmarkNode* child = default_parent_->GetChild(0);
- EXPECT_EQ(child->GetTitle(), default_title_);
- EXPECT_EQ(child->GetURL(), GURL(default_name_));
-}
-
-TEST_F(BookmarkEditorControllerTest, EditTitle) {
- [controller_ setDisplayName:@"whamma jamma bamma"];
- [controller_ ok:nil];
- ASSERT_EQ(default_parent_->GetChildCount(), 1);
- const BookmarkNode* child = default_parent_->GetChild(0);
- EXPECT_EQ(child->GetTitle(), ASCIIToUTF16("whamma jamma bamma"));
- EXPECT_EQ(child->GetURL(), GURL(default_name_));
-}
-
-TEST_F(BookmarkEditorControllerTest, EditURL) {
- EXPECT_TRUE([controller_ okButtonEnabled]);
- [controller_ setDisplayURL:@"http://yellow-sneakers.com/"];
- EXPECT_TRUE([controller_ okButtonEnabled]);
- [controller_ ok:nil];
- ASSERT_EQ(default_parent_->GetChildCount(), 1);
- const BookmarkNode* child = default_parent_->GetChild(0);
- EXPECT_EQ(child->GetTitle(), default_title_);
- EXPECT_EQ(child->GetURL(), GURL("http://yellow-sneakers.com/"));
-}
-
-TEST_F(BookmarkEditorControllerTest, EditAndFixPrefix) {
- [controller_ setDisplayURL:@"x"];
- [controller_ ok:nil];
- ASSERT_EQ(default_parent_->GetChildCount(), 1);
- const BookmarkNode* child = default_parent_->GetChild(0);
- EXPECT_TRUE(child->GetURL().is_valid());
-}
-
-TEST_F(BookmarkEditorControllerTest, NodeDeleted) {
- // Delete the bookmark being edited and verify the sheet cancels itself:
- ASSERT_TRUE([test_window() attachedSheet]);
- BookmarkModel* model = browser_helper_.profile()->GetBookmarkModel();
- model->Remove(default_parent_, 0);
- ASSERT_FALSE([test_window() attachedSheet]);
-}
-
-TEST_F(BookmarkEditorControllerTest, EditAndConfirmOKButton) {
- // Confirm OK button enabled/disabled as appropriate:
- // First test the URL.
- EXPECT_TRUE([controller_ okButtonEnabled]);
- [controller_ setDisplayURL:@""];
- EXPECT_FALSE([controller_ okButtonEnabled]);
- [controller_ setDisplayURL:@"http://www.cnn.com"];
- EXPECT_TRUE([controller_ okButtonEnabled]);
- // Then test the name.
- [controller_ setDisplayName:@""];
- EXPECT_TRUE([controller_ okButtonEnabled]);
- [controller_ setDisplayName:@" "];
- EXPECT_TRUE([controller_ okButtonEnabled]);
- // Then little mix of both.
- [controller_ setDisplayName:@"name"];
- EXPECT_TRUE([controller_ okButtonEnabled]);
- [controller_ setDisplayURL:@""];
- EXPECT_FALSE([controller_ okButtonEnabled]);
- [controller_ cancel:nil];
-}
-
-TEST_F(BookmarkEditorControllerTest, GoodAndBadURLsChangeColor) {
- // Confirm that the background color of the URL edit field changes
- // based on whether it contains a valid or invalid URL.
- [controller_ setDisplayURL:@"http://www.cnn.com"];
- NSColor *urlColorA = [controller_ urlFieldColor];
- EXPECT_TRUE(urlColorA);
- [controller_ setDisplayURL:@""];
- NSColor *urlColorB = [controller_ urlFieldColor];
- EXPECT_TRUE(urlColorB);
- EXPECT_NSNE(urlColorA, urlColorB);
- [controller_ setDisplayURL:@"http://www.google.com"];
- [controller_ cancel:nil];
- urlColorB = [controller_ urlFieldColor];
- EXPECT_TRUE(urlColorB);
- EXPECT_NSEQ(urlColorA, urlColorB);
-}
-
-class BookmarkEditorControllerNoNodeTest : public CocoaTest {
- public:
- BrowserTestHelper browser_helper_;
- BookmarkEditorController* controller_;
-
- virtual void SetUp() {
- CocoaTest::SetUp();
- BookmarkModel* model = browser_helper_.profile()->GetBookmarkModel();
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- controller_ = [[BookmarkEditorController alloc]
- initWithParentWindow:test_window()
- profile:browser_helper_.profile()
- parent:parent
- node:NULL
- configuration:BookmarkEditor::NO_TREE];
-
- [controller_ runAsModalSheet];
- }
-
- virtual void TearDown() {
- controller_ = NULL;
- CocoaTest::TearDown();
- }
-};
-
-TEST_F(BookmarkEditorControllerNoNodeTest, NoNodeNoTree) {
- EXPECT_EQ(@"", [controller_ displayName]);
- EXPECT_EQ(@"", [controller_ displayURL]);
- EXPECT_FALSE([controller_ okButtonEnabled]);
- [controller_ cancel:nil];
-}
-
-class BookmarkEditorControllerYesNodeTest : public CocoaTest {
- public:
- BrowserTestHelper browser_helper_;
- string16 default_title_;
- const char* url_name_;
- BookmarkEditorController* controller_;
-
- virtual void SetUp() {
- CocoaTest::SetUp();
- BookmarkModel* model = browser_helper_.profile()->GetBookmarkModel();
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- default_title_ = ASCIIToUTF16("wooh title");
- url_name_ = "http://www.zoom-baby-doo-da.com/";
- const BookmarkNode* node = model->AddURL(parent, 0, default_title_,
- GURL(url_name_));
- controller_ = [[BookmarkEditorController alloc]
- initWithParentWindow:test_window()
- profile:browser_helper_.profile()
- parent:parent
- node:node
- configuration:BookmarkEditor::NO_TREE];
-
- [controller_ runAsModalSheet];
- }
-
- virtual void TearDown() {
- controller_ = NULL;
- CocoaTest::TearDown();
- }
-};
-
-TEST_F(BookmarkEditorControllerYesNodeTest, YesNodeShowTree) {
- EXPECT_NSEQ(base::SysUTF16ToNSString(default_title_),
- [controller_ displayName]);
- EXPECT_NSEQ([NSString stringWithCString:url_name_
- encoding:NSUTF8StringEncoding],
- [controller_ displayURL]);
- [controller_ cancel:nil];
-}
-
-class BookmarkEditorControllerTreeTest : public CocoaTest {
-
- public:
- BrowserTestHelper browser_helper_;
- BookmarkEditorController* controller_;
- const BookmarkNode* group_a_;
- const BookmarkNode* group_b_;
- const BookmarkNode* group_bb_;
- const BookmarkNode* group_c_;
- const BookmarkNode* bookmark_bb_3_;
- GURL bb3_url_1_;
- GURL bb3_url_2_;
-
- BookmarkEditorControllerTreeTest() {
- // Set up a small bookmark hierarchy, which will look as follows:
- // a b c d
- // a-0 b-0 c-0
- // a-1 bb-0 c-1
- // a-2 bb-1 c-2
- // bb-2
- // bb-3
- // bb-4
- // b-1
- // b-2
- BookmarkModel& model(*(browser_helper_.profile()->GetBookmarkModel()));
- const BookmarkNode* root = model.GetBookmarkBarNode();
- group_a_ = model.AddGroup(root, 0, ASCIIToUTF16("a"));
- model.AddURL(group_a_, 0, ASCIIToUTF16("a-0"), GURL("http://a-0.com"));
- model.AddURL(group_a_, 1, ASCIIToUTF16("a-1"), GURL("http://a-1.com"));
- model.AddURL(group_a_, 2, ASCIIToUTF16("a-2"), GURL("http://a-2.com"));
-
- group_b_ = model.AddGroup(root, 1, ASCIIToUTF16("b"));
- model.AddURL(group_b_, 0, ASCIIToUTF16("b-0"), GURL("http://b-0.com"));
- group_bb_ = model.AddGroup(group_b_, 1, ASCIIToUTF16("bb"));
- model.AddURL(group_bb_, 0, ASCIIToUTF16("bb-0"), GURL("http://bb-0.com"));
- model.AddURL(group_bb_, 1, ASCIIToUTF16("bb-1"), GURL("http://bb-1.com"));
- model.AddURL(group_bb_, 2, ASCIIToUTF16("bb-2"), GURL("http://bb-2.com"));
-
- // To find it later, this bookmark name must always have a URL
- // of http://bb-3.com or https://bb-3.com
- bb3_url_1_ = GURL("http://bb-3.com");
- bb3_url_2_ = GURL("https://bb-3.com");
- bookmark_bb_3_ = model.AddURL(group_bb_, 3, ASCIIToUTF16("bb-3"),
- bb3_url_1_);
-
- model.AddURL(group_bb_, 4, ASCIIToUTF16("bb-4"), GURL("http://bb-4.com"));
- model.AddURL(group_b_, 2, ASCIIToUTF16("b-1"), GURL("http://b-2.com"));
- model.AddURL(group_b_, 3, ASCIIToUTF16("b-2"), GURL("http://b-3.com"));
-
- group_c_ = model.AddGroup(root, 2, ASCIIToUTF16("c"));
- model.AddURL(group_c_, 0, ASCIIToUTF16("c-0"), GURL("http://c-0.com"));
- model.AddURL(group_c_, 1, ASCIIToUTF16("c-1"), GURL("http://c-1.com"));
- model.AddURL(group_c_, 2, ASCIIToUTF16("c-2"), GURL("http://c-2.com"));
- model.AddURL(group_c_, 3, ASCIIToUTF16("c-3"), GURL("http://c-3.com"));
-
- model.AddURL(root, 3, ASCIIToUTF16("d"), GURL("http://d-0.com"));
- }
-
- virtual BookmarkEditorController* CreateController() {
- return [[BookmarkEditorController alloc]
- initWithParentWindow:test_window()
- profile:browser_helper_.profile()
- parent:group_bb_
- node:bookmark_bb_3_
- configuration:BookmarkEditor::SHOW_TREE];
- }
-
- virtual void SetUp() {
- controller_ = CreateController();
- [controller_ runAsModalSheet];
- }
-
- virtual void TearDown() {
- controller_ = NULL;
- CocoaTest::TearDown();
- }
-
- // After changing a node, pointers to the node may be invalid. This
- // is because the node itself may not be updated; it may removed and
- // a new one is added in that location. (Implementation detail of
- // BookmarkEditorController). This method updates the class's
- // bookmark_bb_3_ so that it points to the new node for testing.
- void UpdateBB3() {
- std::vector<const BookmarkNode*> nodes;
- BookmarkModel* model = browser_helper_.profile()->GetBookmarkModel();
- model->GetNodesByURL(bb3_url_1_, &nodes);
- if (nodes.size() == 0)
- model->GetNodesByURL(bb3_url_2_, &nodes);
- DCHECK(nodes.size());
- bookmark_bb_3_ = nodes[0];
- }
-
-};
-
-TEST_F(BookmarkEditorControllerTreeTest, VerifyBookmarkTestModel) {
- BookmarkModel& model(*(browser_helper_.profile()->GetBookmarkModel()));
- model.root_node();
- const BookmarkNode& root(*model.GetBookmarkBarNode());
- EXPECT_EQ(4, root.GetChildCount());
- const BookmarkNode* child = root.GetChild(0);
- EXPECT_EQ(3, child->GetChildCount());
- const BookmarkNode* subchild = child->GetChild(0);
- EXPECT_EQ(0, subchild->GetChildCount());
- subchild = child->GetChild(1);
- EXPECT_EQ(0, subchild->GetChildCount());
- subchild = child->GetChild(2);
- EXPECT_EQ(0, subchild->GetChildCount());
-
- child = root.GetChild(1);
- EXPECT_EQ(4, child->GetChildCount());
- subchild = child->GetChild(0);
- EXPECT_EQ(0, subchild->GetChildCount());
- subchild = child->GetChild(1);
- EXPECT_EQ(5, subchild->GetChildCount());
- const BookmarkNode* subsubchild = subchild->GetChild(0);
- EXPECT_EQ(0, subsubchild->GetChildCount());
- subsubchild = subchild->GetChild(1);
- EXPECT_EQ(0, subsubchild->GetChildCount());
- subsubchild = subchild->GetChild(2);
- EXPECT_EQ(0, subsubchild->GetChildCount());
- subsubchild = subchild->GetChild(3);
- EXPECT_EQ(0, subsubchild->GetChildCount());
- subsubchild = subchild->GetChild(4);
- EXPECT_EQ(0, subsubchild->GetChildCount());
- subchild = child->GetChild(2);
- EXPECT_EQ(0, subchild->GetChildCount());
- subchild = child->GetChild(3);
- EXPECT_EQ(0, subchild->GetChildCount());
-
- child = root.GetChild(2);
- EXPECT_EQ(4, child->GetChildCount());
- subchild = child->GetChild(0);
- EXPECT_EQ(0, subchild->GetChildCount());
- subchild = child->GetChild(1);
- EXPECT_EQ(0, subchild->GetChildCount());
- subchild = child->GetChild(2);
- EXPECT_EQ(0, subchild->GetChildCount());
- subchild = child->GetChild(3);
- EXPECT_EQ(0, subchild->GetChildCount());
-
- child = root.GetChild(3);
- EXPECT_EQ(0, child->GetChildCount());
- [controller_ cancel:nil];
-}
-
-TEST_F(BookmarkEditorControllerTreeTest, RenameBookmarkInPlace) {
- const BookmarkNode* oldParent = bookmark_bb_3_->GetParent();
- [controller_ setDisplayName:@"NEW NAME"];
- [controller_ ok:nil];
- UpdateBB3();
- const BookmarkNode* newParent = bookmark_bb_3_->GetParent();
- ASSERT_EQ(newParent, oldParent);
- int childIndex = newParent->IndexOfChild(bookmark_bb_3_);
- ASSERT_EQ(3, childIndex);
-}
-
-TEST_F(BookmarkEditorControllerTreeTest, ChangeBookmarkURLInPlace) {
- const BookmarkNode* oldParent = bookmark_bb_3_->GetParent();
- [controller_ setDisplayURL:@"https://bb-3.com"];
- [controller_ ok:nil];
- UpdateBB3();
- const BookmarkNode* newParent = bookmark_bb_3_->GetParent();
- ASSERT_EQ(newParent, oldParent);
- int childIndex = newParent->IndexOfChild(bookmark_bb_3_);
- ASSERT_EQ(3, childIndex);
-}
-
-TEST_F(BookmarkEditorControllerTreeTest, ChangeBookmarkGroup) {
- [controller_ selectTestNodeInBrowser:group_c_];
- [controller_ ok:nil];
- UpdateBB3();
- const BookmarkNode* parent = bookmark_bb_3_->GetParent();
- ASSERT_EQ(parent, group_c_);
- int childIndex = parent->IndexOfChild(bookmark_bb_3_);
- ASSERT_EQ(4, childIndex);
-}
-
-TEST_F(BookmarkEditorControllerTreeTest, ChangeNameAndBookmarkGroup) {
- [controller_ setDisplayName:@"NEW NAME"];
- [controller_ selectTestNodeInBrowser:group_c_];
- [controller_ ok:nil];
- UpdateBB3();
- const BookmarkNode* parent = bookmark_bb_3_->GetParent();
- ASSERT_EQ(parent, group_c_);
- int childIndex = parent->IndexOfChild(bookmark_bb_3_);
- ASSERT_EQ(4, childIndex);
- EXPECT_EQ(bookmark_bb_3_->GetTitle(), ASCIIToUTF16("NEW NAME"));
-}
-
-TEST_F(BookmarkEditorControllerTreeTest, AddFolderWithGroupSelected) {
- // Folders are NOT added unless the OK button is pressed.
- [controller_ newFolder:nil];
- [controller_ cancel:nil];
- EXPECT_EQ(5, group_bb_->GetChildCount());
-}
-
-class BookmarkEditorControllerTreeNoNodeTest :
- public BookmarkEditorControllerTreeTest {
- public:
- virtual BookmarkEditorController* CreateController() {
- return [[BookmarkEditorController alloc]
- initWithParentWindow:test_window()
- profile:browser_helper_.profile()
- parent:group_bb_
- node:nil
- configuration:BookmarkEditor::SHOW_TREE];
- }
-
-};
-
-TEST_F(BookmarkEditorControllerTreeNoNodeTest, NewBookmarkNoNode) {
- [controller_ setDisplayName:@"NEW BOOKMARK"];
- [controller_ setDisplayURL:@"http://NEWURL.com"];
- [controller_ ok:nil];
- const BookmarkNode* new_node = group_bb_->GetChild(5);
- ASSERT_EQ(0, new_node->GetChildCount());
- EXPECT_EQ(new_node->GetTitle(), ASCIIToUTF16("NEW BOOKMARK"));
- EXPECT_EQ(new_node->GetURL(), GURL("http://NEWURL.com"));
-}
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_folder_target.h b/chrome/browser/cocoa/bookmarks/bookmark_folder_target.h
deleted file mode 100644
index c877f72..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_folder_target.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_FOLDER_TARGET_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_FOLDER_TARGET_CONTROLLER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-@class BookmarkButton;
-@protocol BookmarkButtonControllerProtocol;
-class BookmarkNode;
-
-// Target (in the target/action sense) of a bookmark folder button.
-// Since ObjC doesn't have multiple inheritance we use has-a instead
-// of is-a to share behavior between the BookmarkBarFolderController
-// (NSWindowController) and the BookmarkBarController
-// (NSViewController).
-//
-// This class is unit tested in the context of a BookmarkBarController.
-@interface BookmarkFolderTarget : NSObject {
- // The owner of the bookmark folder button
- id<BookmarkButtonControllerProtocol> controller_; // weak
-}
-
-- (id)initWithController:(id<BookmarkButtonControllerProtocol>)controller;
-
-// Main IBAction for a button click.
-- (IBAction)openBookmarkFolderFromButton:(id)sender;
-
-// Copies the given bookmark node to the given pasteboard, declaring appropriate
-// types (to paste a URL with a title).
-- (void)copyBookmarkNode:(const BookmarkNode*)node
- toPasteboard:(NSPasteboard*)pboard;
-
-// Fill the given pasteboard with appropriate data when the given button is
-// dragged. Since the delegate has no way of providing pasteboard data later,
-// all data must actually be put into the pasteboard and not merely promised.
-- (void)fillPasteboard:(NSPasteboard*)pboard
- forDragOfButton:(BookmarkButton*)button;
-
-@end
-
-// The (internal) |NSPasteboard| type string for bookmark button drags, used for
-// dragging buttons around the bookmark bar. The data for this type is just a
-// pointer to the |BookmarkButton| being dragged.
-extern NSString* kBookmarkButtonDragType;
-
-#endif // CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_FOLDER_TARGET_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_folder_target.mm b/chrome/browser/cocoa/bookmarks/bookmark_folder_target.mm
deleted file mode 100644
index 3fb1507..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_folder_target.mm
+++ /dev/null
@@ -1,118 +0,0 @@
-// 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 "chrome/browser/cocoa/bookmarks/bookmark_folder_target.h"
-
-#include "base/logging.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_folder_controller.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_button.h"
-#import "chrome/browser/cocoa/event_utils.h"
-#import "third_party/mozilla/NSPasteboard+Utils.h"
-
-NSString* kBookmarkButtonDragType = @"ChromiumBookmarkButtonDragType";
-
-@implementation BookmarkFolderTarget
-
-- (id)initWithController:(id<BookmarkButtonControllerProtocol>)controller {
- if ((self = [super init])) {
- controller_ = controller;
- }
- return self;
-}
-
-// This IBAction is called when the user clicks (mouseUp, really) on a
-// "folder" bookmark button. (In this context, "Click" does not
-// include right-click to open a context menu which follows a
-// different path). Scenarios when folder X is clicked:
-// *Predicate* *Action*
-// (nothing) Open Folder X
-// Folder X open Close folder X
-// Folder Y open Close Y, open X
-// Cmd-click Open All with proper disposition
-//
-// Note complication in which a click-drag engages drag and drop, not
-// a click-to-open. Thus the path to get here is a little twisted.
-- (IBAction)openBookmarkFolderFromButton:(id)sender {
- DCHECK(sender);
- // Watch out for a modifier click. For example, command-click
- // should open all.
- //
- // NOTE: we cannot use [[sender cell] mouseDownFlags] because we
- // thwart the normal mouse click mechanism to make buttons
- // draggable. Thus we must use [NSApp currentEvent].
- //
- // Holding command while using the scroll wheel (or moving around
- // over a bookmark folder) can confuse us. Unless we check the
- // event type, we are not sure if this is an "open folder" due to a
- // hover-open or "open folder" due to a click. It doesn't matter
- // (both do the same thing) unless a modifier is held, since
- // command-click should "open all" but command-move should not.
- // WindowOpenDispositionFromNSEvent does not consider the event
- // type; only the modifiers. Thus the need for an extra
- // event-type-check here.
- DCHECK([sender bookmarkNode]->is_folder());
- NSEvent* event = [NSApp currentEvent];
- WindowOpenDisposition disposition =
- event_utils::WindowOpenDispositionFromNSEvent(event);
- if (([event type] != NSMouseEntered) &&
- ([event type] != NSMouseMoved) &&
- ([event type] != NSScrollWheel) &&
- (disposition == NEW_BACKGROUND_TAB)) {
- [controller_ closeAllBookmarkFolders];
- [controller_ openAll:[sender bookmarkNode] disposition:disposition];
- return;
- }
-
- // If click on same folder, close it and be done.
- // Else we clicked on a different folder so more work to do.
- if ([[controller_ folderController] parentButton] == sender) {
- [controller_ closeBookmarkFolder:controller_];
- return;
- }
-
- [controller_ addNewFolderControllerWithParentButton:sender];
-}
-
-- (void)copyBookmarkNode:(const BookmarkNode*)node
- toPasteboard:(NSPasteboard*)pboard {
- if (!node) {
- NOTREACHED();
- return;
- }
-
- if (node->is_folder()) {
- // TODO(viettrungluu): I'm not sure what we should do, so just declare the
- // "additional" types we're given for now. Maybe we want to add a list of
- // URLs? Would we then have to recurse if there were subfolders?
- // In the meanwhile, we *must* set it to a known state. (If this survives to
- // a 10.6-only release, it can be replaced with |-clearContents|.)
- [pboard declareTypes:[NSArray array] owner:nil];
- } else {
- const std::string spec = node->GetURL().spec();
- NSString* url = base::SysUTF8ToNSString(spec);
- NSString* title = base::SysUTF16ToNSString(node->GetTitle());
- [pboard declareURLPasteboardWithAdditionalTypes:[NSArray array]
- owner:nil];
- [pboard setDataForURL:url title:title];
- }
-}
-
-- (void)fillPasteboard:(NSPasteboard*)pboard
- forDragOfButton:(BookmarkButton*)button {
- if (const BookmarkNode* node = [button bookmarkNode]) {
- // Put the bookmark information into the pasteboard, and then write our own
- // data for |kBookmarkButtonDragType|.
- [self copyBookmarkNode:node toPasteboard:pboard];
- [pboard addTypes:[NSArray arrayWithObject:kBookmarkButtonDragType]
- owner:nil];
- [pboard setData:[NSData dataWithBytes:&button length:sizeof(button)]
- forType:kBookmarkButtonDragType];
- } else {
- NOTREACHED();
- }
-}
-
-@end
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_folder_target_unittest.mm b/chrome/browser/cocoa/bookmarks/bookmark_folder_target_unittest.mm
deleted file mode 100644
index 403002d..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_folder_target_unittest.mm
+++ /dev/null
@@ -1,125 +0,0 @@
-// 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.
-
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_controller.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_folder_controller.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_folder_target.h"
-#include "chrome/browser/cocoa/bookmarks/bookmark_button.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-#import "third_party/ocmock/OCMock/OCMock.h"
-
-@interface OCMockObject(PreventRetainCycle)
-- (void)clearRecordersAndExpectations;
-@end
-
-@implementation OCMockObject(PreventRetainCycle)
-
-// We need a mechanism to clear the invocation handlers to break a
-// retain cycle (see below; search for "retain cycle").
-- (void)clearRecordersAndExpectations {
- [recorders removeAllObjects];
- [expectations removeAllObjects];
-}
-
-@end
-
-
-class BookmarkFolderTargetTest : public CocoaTest {
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- bmbNode_ = model->GetBookmarkBarNode();
- }
- virtual void TearDown() {
- pool_.Recycle();
- CocoaTest::TearDown();
- }
-
- BrowserTestHelper helper_;
- const BookmarkNode* bmbNode_;
- base::mac::ScopedNSAutoreleasePool pool_;
-};
-
-TEST_F(BookmarkFolderTargetTest, StartWithNothing) {
- // Need a fake "button" which has a bookmark node.
- id sender = [OCMockObject mockForClass:[BookmarkButton class]];
- [[[sender stub] andReturnValue:OCMOCK_VALUE(bmbNode_)] bookmarkNode];
-
- // Fake controller
- id controller = [OCMockObject mockForClass:[BookmarkBarFolderController
- class]];
- // No current folder
- [[[controller stub] andReturn:nil] folderController];
-
- // Make sure we get an addNew
- [[controller expect] addNewFolderControllerWithParentButton:sender];
-
- scoped_nsobject<BookmarkFolderTarget> target(
- [[BookmarkFolderTarget alloc] initWithController:controller]);
-
- [target openBookmarkFolderFromButton:sender];
- [controller verify];
-}
-
-TEST_F(BookmarkFolderTargetTest, ReopenSameFolder) {
- // Need a fake "button" which has a bookmark node.
- id sender = [OCMockObject mockForClass:[BookmarkButton class]];
- [[[sender stub] andReturnValue:OCMOCK_VALUE(bmbNode_)] bookmarkNode];
-
- // Fake controller
- id controller = [OCMockObject mockForClass:[BookmarkBarFolderController
- class]];
- // YES a current folder. Self-mock that as well, so "same" will be
- // true. Note this creates a retain cycle in OCMockObject; we
- // accomodate at the end of this function.
- [[[controller stub] andReturn:controller] folderController];
- [[[controller stub] andReturn:sender] parentButton];
-
- // The folder is open, so a click should close just that folder (and
- // any subfolders).
- [[controller expect] closeBookmarkFolder:controller];
-
- scoped_nsobject<BookmarkFolderTarget> target(
- [[BookmarkFolderTarget alloc] initWithController:controller]);
-
- [target openBookmarkFolderFromButton:sender];
- [controller verify];
-
- // Our use of OCMockObject means an object can return itself. This
- // creates a retain cycle, since OCMock retains all objects used in
- // mock creation. Clear out the invocation handlers of all
- // OCMockRecorders we used to break the cycles.
- [controller clearRecordersAndExpectations];
-}
-
-TEST_F(BookmarkFolderTargetTest, ReopenNotSame) {
- // Need a fake "button" which has a bookmark node.
- id sender = [OCMockObject mockForClass:[BookmarkButton class]];
- [[[sender stub] andReturnValue:OCMOCK_VALUE(bmbNode_)] bookmarkNode];
-
- // Fake controller
- id controller = [OCMockObject mockForClass:[BookmarkBarFolderController
- class]];
- // YES a current folder but NOT same.
- [[[controller stub] andReturn:controller] folderController];
- [[[controller stub] andReturn:nil] parentButton];
-
- // Insure the controller gets a chance to decide which folders to
- // close and open.
- [[controller expect] addNewFolderControllerWithParentButton:sender];
-
- scoped_nsobject<BookmarkFolderTarget> target(
- [[BookmarkFolderTarget alloc] initWithController:controller]);
-
- [target openBookmarkFolderFromButton:sender];
- [controller verify];
-
- // Break retain cycles.
- [controller clearRecordersAndExpectations];
-}
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_menu.mm b/chrome/browser/cocoa/bookmarks/bookmark_menu.mm
deleted file mode 100644
index 9be848b..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_menu.mm
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/bookmarks/bookmark_menu.h"
-
-
-@implementation BookmarkMenu
-
-@synthesize id = id_;
-
-// Convention in the bookmark bar controller: the bookmark button
-// cells have a BookmarkNode as their represented object. This object
-// is placed in a BookmarkMenu at the time a cell is asked for its
-// menu.
-- (void)setRepresentedObject:(id)object {
- if ([object isKindOfClass:[NSNumber class]]) {
- id_ = static_cast<int64>([object longLongValue]);
- }
-}
-
-@end
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_menu_bridge.h b/chrome/browser/cocoa/bookmarks/bookmark_menu_bridge.h
deleted file mode 100644
index bc606fc..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_menu_bridge.h
+++ /dev/null
@@ -1,123 +0,0 @@
-// 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.
-
-// C++ controller for the bookmark menu; one per AppController (which
-// means there is only one). When bookmarks are changed, this class
-// takes care of updating Cocoa bookmark menus. This is not named
-// BookmarkMenuController to help avoid confusion between languages.
-// This class needs to be C++, not ObjC, since it derives from
-// BookmarkModelObserver.
-//
-// Most Chromium Cocoa menu items are static from a nib (e.g. New
-// Tab), but may be enabled/disabled under certain circumstances
-// (e.g. Cut and Paste). In addition, most Cocoa menu items have
-// firstResponder: as a target. Unusually, bookmark menu items are
-// created dynamically. They also have a target of
-// BookmarkMenuCocoaController instead of firstResponder.
-// See BookmarkMenuBridge::AddNodeToMenu()).
-
-#ifndef CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_MENU_BRIDGE_H_
-#define CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_MENU_BRIDGE_H_
-#pragma once
-
-#include <map>
-
-#include "base/scoped_nsobject.h"
-#include "chrome/browser/bookmarks/bookmark_model_observer.h"
-
-class BookmarkNode;
-class Profile;
-@class NSImage;
-@class NSMenu;
-@class NSMenuItem;
-@class BookmarkMenuCocoaController;
-
-class BookmarkMenuBridge : public BookmarkModelObserver {
- public:
- BookmarkMenuBridge(Profile* profile);
- virtual ~BookmarkMenuBridge();
-
- // Overridden from BookmarkModelObserver
- virtual void Loaded(BookmarkModel* model);
- virtual void BookmarkModelBeingDeleted(BookmarkModel* model);
- virtual void BookmarkNodeMoved(BookmarkModel* model,
- const BookmarkNode* old_parent,
- int old_index,
- const BookmarkNode* new_parent,
- int new_index);
- virtual void BookmarkNodeAdded(BookmarkModel* model,
- const BookmarkNode* parent,
- int index);
- virtual void BookmarkNodeRemoved(BookmarkModel* model,
- const BookmarkNode* parent,
- int old_index,
- const BookmarkNode* node);
- virtual void BookmarkNodeChanged(BookmarkModel* model,
- const BookmarkNode* node);
- virtual void BookmarkNodeFavIconLoaded(BookmarkModel* model,
- const BookmarkNode* node);
- virtual void BookmarkNodeChildrenReordered(BookmarkModel* model,
- const BookmarkNode* node);
-
- // Rebuilds the bookmark menu, if it has been marked invalid.
- void UpdateMenu(NSMenu* bookmark_menu);
-
- // I wish I had a "friend @class" construct.
- BookmarkModel* GetBookmarkModel();
- Profile* GetProfile();
-
- protected:
- // Clear all bookmarks from the given bookmark menu.
- void ClearBookmarkMenu(NSMenu* menu);
-
- // Mark the bookmark menu as being invalid.
- void InvalidateMenu() { menuIsValid_ = false; }
-
- // Helper for adding the node as a submenu to the menu with the
- // given title.
- void AddNodeAsSubmenu(NSMenu* menu,
- const BookmarkNode* node,
- NSString* title);
-
- // Helper for recursively adding items to our bookmark menu
- // All children of |node| will be added to |menu|.
- // TODO(jrg): add a counter to enforce maximum nodes added
- void AddNodeToMenu(const BookmarkNode* node, NSMenu* menu);
-
- // This configures an NSMenuItem with all the data from a BookmarkNode. This
- // is used to update existing menu items, as well as to configure newly
- // created ones, like in AddNodeToMenu().
- // |set_title| is optional since it is only needed when we get a
- // node changed notification. On initial build of the menu we set
- // the title as part of alloc/init.
- void ConfigureMenuItem(const BookmarkNode* node, NSMenuItem* item,
- bool set_title);
-
- // Returns the NSMenuItem for a given BookmarkNode.
- NSMenuItem* MenuItemForNode(const BookmarkNode* node);
-
- // Return the Bookmark menu.
- virtual NSMenu* BookmarkMenu();
-
- // Start watching the bookmarks for changes.
- void ObserveBookmarkModel();
-
- private:
- friend class BookmarkMenuBridgeTest;
-
- // True iff the menu is up-to-date with the actual BookmarkModel.
- bool menuIsValid_;
-
- Profile* profile_; // weak
- BookmarkMenuCocoaController* controller_; // strong
-
- // The folder image so we can use one copy for all.
- scoped_nsobject<NSImage> folder_image_;
-
- // In order to appropriately update items in the bookmark menu, without
- // forcing a rebuild, map the model's nodes to menu items.
- std::map<const BookmarkNode*, NSMenuItem*> bookmark_nodes_;
-};
-
-#endif // CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_MENU_BRIDGE_H_
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_menu_bridge.mm b/chrome/browser/cocoa/bookmarks/bookmark_menu_bridge.mm
deleted file mode 100644
index 7145285..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_menu_bridge.mm
+++ /dev/null
@@ -1,253 +0,0 @@
-// 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 <AppKit/AppKit.h>
-
-#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
-#include "base/nsimage_cache_mac.h"
-#include "base/sys_string_conversions.h"
-#import "chrome/browser/app_controller_mac.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#include "chrome/browser/cocoa/bookmarks/bookmark_menu_bridge.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_menu_cocoa_controller.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/profile_manager.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_list.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#include "skia/ext/skia_utils_mac.h"
-
-BookmarkMenuBridge::BookmarkMenuBridge(Profile* profile)
- : menuIsValid_(false),
- profile_(profile),
- controller_([[BookmarkMenuCocoaController alloc] initWithBridge:this]) {
- if (GetBookmarkModel())
- ObserveBookmarkModel();
-}
-
-BookmarkMenuBridge::~BookmarkMenuBridge() {
- BookmarkModel *model = GetBookmarkModel();
- if (model)
- model->RemoveObserver(this);
- [controller_ release];
-}
-
-NSMenu* BookmarkMenuBridge::BookmarkMenu() {
- return [controller_ menu];
-}
-
-void BookmarkMenuBridge::Loaded(BookmarkModel* model) {
- InvalidateMenu();
-}
-
-void BookmarkMenuBridge::UpdateMenu(NSMenu* bookmark_menu) {
- DCHECK(bookmark_menu);
- if (menuIsValid_)
- return;
- BookmarkModel* model = GetBookmarkModel();
- if (!model || !model->IsLoaded())
- return;
-
- if (!folder_image_) {
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- folder_image_.reset(
- [rb.GetNativeImageNamed(IDR_BOOKMARK_BAR_FOLDER) retain]);
- }
-
- ClearBookmarkMenu(bookmark_menu);
-
- // Add bookmark bar items, if any.
- const BookmarkNode* barNode = model->GetBookmarkBarNode();
- CHECK(barNode);
- if (barNode->GetChildCount()) {
- [bookmark_menu addItem:[NSMenuItem separatorItem]];
- AddNodeToMenu(barNode, bookmark_menu);
- }
-
- // Create a submenu for "other bookmarks", and fill it in.
- NSString* other_items_title =
- l10n_util::GetNSString(IDS_BOOMARK_BAR_OTHER_FOLDER_NAME);
- [bookmark_menu addItem:[NSMenuItem separatorItem]];
- AddNodeAsSubmenu(bookmark_menu,
- model->other_node(),
- other_items_title);
-
- menuIsValid_ = true;
-}
-
-void BookmarkMenuBridge::BookmarkModelBeingDeleted(BookmarkModel* model) {
- NSMenu* bookmark_menu = BookmarkMenu();
- if (bookmark_menu == nil)
- return;
-
- ClearBookmarkMenu(bookmark_menu);
-}
-
-void BookmarkMenuBridge::BookmarkNodeMoved(BookmarkModel* model,
- const BookmarkNode* old_parent,
- int old_index,
- const BookmarkNode* new_parent,
- int new_index) {
- InvalidateMenu();
-}
-
-void BookmarkMenuBridge::BookmarkNodeAdded(BookmarkModel* model,
- const BookmarkNode* parent,
- int index) {
- InvalidateMenu();
-}
-
-void BookmarkMenuBridge::BookmarkNodeRemoved(BookmarkModel* model,
- const BookmarkNode* parent,
- int old_index,
- const BookmarkNode* node) {
- InvalidateMenu();
-}
-
-void BookmarkMenuBridge::BookmarkNodeChanged(BookmarkModel* model,
- const BookmarkNode* node) {
- NSMenuItem* item = MenuItemForNode(node);
- if (item)
- ConfigureMenuItem(node, item, true);
-}
-
-void BookmarkMenuBridge::BookmarkNodeFavIconLoaded(BookmarkModel* model,
- const BookmarkNode* node) {
- NSMenuItem* item = MenuItemForNode(node);
- if (item)
- ConfigureMenuItem(node, item, false);
-}
-
-void BookmarkMenuBridge::BookmarkNodeChildrenReordered(
- BookmarkModel* model, const BookmarkNode* node) {
- InvalidateMenu();
-}
-
-// Watch for changes.
-void BookmarkMenuBridge::ObserveBookmarkModel() {
- BookmarkModel* model = GetBookmarkModel();
- model->AddObserver(this);
- if (model->IsLoaded())
- Loaded(model);
-}
-
-BookmarkModel* BookmarkMenuBridge::GetBookmarkModel() {
- if (!profile_)
- return NULL;
- return profile_->GetBookmarkModel();
-}
-
-Profile* BookmarkMenuBridge::GetProfile() {
- return profile_;
-}
-
-void BookmarkMenuBridge::ClearBookmarkMenu(NSMenu* menu) {
- bookmark_nodes_.clear();
- // Recursively delete all menus that look like a bookmark. Assume
- // all items with submenus contain only bookmarks. Also delete all
- // separator items since we explicirly add them back in. This should
- // deletes everything except the first item ("Add Bookmark...").
- NSArray* items = [menu itemArray];
- for (NSMenuItem* item in items) {
- // Convention: items in the bookmark list which are bookmarks have
- // an action of openBookmarkMenuItem:. Also, assume all items
- // with submenus are submenus of bookmarks.
- if (([item action] == @selector(openBookmarkMenuItem:)) ||
- [item hasSubmenu] ||
- [item isSeparatorItem]) {
- // This will eventually [obj release] all its kids, if it has
- // any.
- [menu removeItem:item];
- } else {
- // Leave it alone.
- }
- }
-}
-
-void BookmarkMenuBridge::AddNodeAsSubmenu(NSMenu* menu,
- const BookmarkNode* node,
- NSString* title) {
- NSMenuItem* items = [[[NSMenuItem alloc]
- initWithTitle:title
- action:nil
- keyEquivalent:@""] autorelease];
- [items setImage:folder_image_];
- [menu addItem:items];
- NSMenu* other_submenu = [[[NSMenu alloc] initWithTitle:title]
- autorelease];
- [menu setSubmenu:other_submenu forItem:items];
- AddNodeToMenu(node, other_submenu);
-}
-
-// TODO(jrg): limit the number of bookmarks in the menubar?
-void BookmarkMenuBridge::AddNodeToMenu(const BookmarkNode* node, NSMenu* menu) {
- int child_count = node->GetChildCount();
- if (!child_count) {
- NSString* empty_string = l10n_util::GetNSString(IDS_MENU_EMPTY_SUBMENU);
- NSMenuItem* item = [[[NSMenuItem alloc] initWithTitle:empty_string
- action:nil
- keyEquivalent:@""] autorelease];
- [menu addItem:item];
- } else for (int i = 0; i < child_count; i++) {
- const BookmarkNode* child = node->GetChild(i);
- NSString* title = [BookmarkMenuCocoaController menuTitleForNode:child];
- NSMenuItem* item = [[[NSMenuItem alloc] initWithTitle:title
- action:nil
- keyEquivalent:@""] autorelease];
- [menu addItem:item];
- bookmark_nodes_[child] = item;
- if (child->is_folder()) {
- [item setImage:folder_image_];
- NSMenu* submenu = [[[NSMenu alloc] initWithTitle:title] autorelease];
- [menu setSubmenu:submenu forItem:item];
- AddNodeToMenu(child, submenu); // recursive call
- } else {
- ConfigureMenuItem(child, item, false);
- }
- }
-}
-
-void BookmarkMenuBridge::ConfigureMenuItem(const BookmarkNode* node,
- NSMenuItem* item,
- bool set_title) {
- if (set_title) {
- NSString* title = [BookmarkMenuCocoaController menuTitleForNode:node];
- [item setTitle:title];
- }
- [item setTarget:controller_];
- [item setAction:@selector(openBookmarkMenuItem:)];
- [item setTag:node->id()];
- // Add a tooltip
- std::string url_string = node->GetURL().possibly_invalid_spec();
- NSString* tooltip = [NSString stringWithFormat:@"%@\n%s",
- base::SysUTF16ToNSString(node->GetTitle()),
- url_string.c_str()];
- [item setToolTip:tooltip];
-
- // Check to see if we have a favicon.
- NSImage* favicon = nil;
- BookmarkModel* model = GetBookmarkModel();
- if (model) {
- const SkBitmap& bitmap = model->GetFavIcon(node);
- if (!bitmap.isNull())
- favicon = gfx::SkBitmapToNSImage(bitmap);
- }
- // Either we do not have a loaded favicon or the conversion from SkBitmap
- // failed. Use the default site image instead.
- if (!favicon)
- favicon = nsimage_cache::ImageNamed(@"nav.pdf");
- [item setImage:favicon];
-}
-
-NSMenuItem* BookmarkMenuBridge::MenuItemForNode(const BookmarkNode* node) {
- if (!node)
- return nil;
- std::map<const BookmarkNode*, NSMenuItem*>::iterator it =
- bookmark_nodes_.find(node);
- if (it == bookmark_nodes_.end())
- return nil;
- return it->second;
-}
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_menu_bridge_unittest.mm b/chrome/browser/cocoa/bookmarks/bookmark_menu_bridge_unittest.mm
deleted file mode 100644
index 5f06ce5..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_menu_bridge_unittest.mm
+++ /dev/null
@@ -1,317 +0,0 @@
-// 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 <AppKit/AppKit.h>
-
-#import "base/scoped_nsobject.h"
-#include "base/string16.h"
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#include "chrome/browser/cocoa/bookmarks/bookmark_menu_bridge.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#include "chrome/browser/ui/browser.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-class TestBookmarkMenuBridge : public BookmarkMenuBridge {
- public:
- TestBookmarkMenuBridge(Profile* profile)
- : BookmarkMenuBridge(profile),
- menu_([[NSMenu alloc] initWithTitle:@"test"]) {
- }
- virtual ~TestBookmarkMenuBridge() {}
-
- scoped_nsobject<NSMenu> menu_;
-
- protected:
- // Overridden from BookmarkMenuBridge.
- virtual NSMenu* BookmarkMenu() {
- return menu_;
- }
-};
-
-// TODO(jrg): see refactor comment in bookmark_bar_state_controller_unittest.mm
-class BookmarkMenuBridgeTest : public PlatformTest {
- public:
-
- void SetUp() {
- bridge_.reset(new TestBookmarkMenuBridge(browser_test_helper_.profile()));
- EXPECT_TRUE(bridge_.get());
- }
-
- // We are a friend of BookmarkMenuBridge (and have access to
- // protected methods), but none of the classes generated by TEST_F()
- // are. This (and AddNodeToMenu()) are simple wrappers to let
- // derived test classes have access to protected methods.
- void ClearBookmarkMenu(BookmarkMenuBridge* bridge, NSMenu* menu) {
- bridge->ClearBookmarkMenu(menu);
- }
-
- void InvalidateMenu() { bridge_->InvalidateMenu(); }
- bool menu_is_valid() { return bridge_->menuIsValid_; }
-
- void AddNodeToMenu(BookmarkMenuBridge* bridge, const BookmarkNode* root,
- NSMenu* menu) {
- bridge->AddNodeToMenu(root, menu);
- }
-
- NSMenuItem* MenuItemForNode(BookmarkMenuBridge* bridge,
- const BookmarkNode* node) {
- return bridge->MenuItemForNode(node);
- }
-
- NSMenuItem* AddItemToMenu(NSMenu *menu, NSString *title, SEL selector) {
- NSMenuItem *item = [[[NSMenuItem alloc] initWithTitle:title action:NULL
- keyEquivalent:@""] autorelease];
- if (selector)
- [item setAction:selector];
- [menu addItem:item];
- return item;
- }
-
- BrowserTestHelper browser_test_helper_;
- scoped_ptr<TestBookmarkMenuBridge> bridge_;
-};
-
-TEST_F(BookmarkMenuBridgeTest, TestBookmarkMenuAutoSeparator) {
- BookmarkModel* model = bridge_->GetBookmarkModel();
- bridge_->Loaded(model);
- NSMenu* menu = bridge_->menu_.get();
- bridge_->UpdateMenu(menu);
- // The bare menu after loading has a separator and an "Other Bookmarks"
- // submenu.
- EXPECT_EQ(2, [menu numberOfItems]);
- // Add a bookmark and reload and there should be 4 items: the previous
- // menu contents plus a new separator and the new bookmark.
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- const char* url = "http://www.zim-bop-a-dee.com/";
- model->AddURL(parent, 0, ASCIIToUTF16("Bookmark"), GURL(url));
- bridge_->UpdateMenu(menu);
- EXPECT_EQ(4, [menu numberOfItems]);
- // Remove the new bookmark and reload and we should have 2 items again
- // because the separator should have been removed as well.
- model->Remove(parent, 0);
- bridge_->UpdateMenu(menu);
- EXPECT_EQ(2, [menu numberOfItems]);
-}
-
-// Test that ClearBookmarkMenu() removes all bookmark menus.
-TEST_F(BookmarkMenuBridgeTest, TestClearBookmarkMenu) {
- NSMenu* menu = bridge_->menu_.get();
-
- AddItemToMenu(menu, @"hi mom", nil);
- AddItemToMenu(menu, @"not", @selector(openBookmarkMenuItem:));
- NSMenuItem* item = AddItemToMenu(menu, @"hi mom", nil);
- [item setSubmenu:[[[NSMenu alloc] initWithTitle:@"bar"] autorelease]];
- AddItemToMenu(menu, @"not", @selector(openBookmarkMenuItem:));
- AddItemToMenu(menu, @"zippy", @selector(length));
- [menu addItem:[NSMenuItem separatorItem]];
-
- ClearBookmarkMenu(bridge_.get(), menu);
-
- // Make sure all bookmark items are removed, all items with
- // submenus removed, and all separator items are gone.
- EXPECT_EQ(2, [menu numberOfItems]);
- for (NSMenuItem *item in [menu itemArray]) {
- EXPECT_NSNE(@"not", [item title]);
- }
-}
-
-// Test invalidation
-TEST_F(BookmarkMenuBridgeTest, TestInvalidation) {
- BookmarkModel* model = bridge_->GetBookmarkModel();
- bridge_->Loaded(model);
-
- EXPECT_FALSE(menu_is_valid());
- bridge_->UpdateMenu(bridge_->menu_);
- EXPECT_TRUE(menu_is_valid());
-
- InvalidateMenu();
- EXPECT_FALSE(menu_is_valid());
- InvalidateMenu();
- EXPECT_FALSE(menu_is_valid());
- bridge_->UpdateMenu(bridge_->menu_);
- EXPECT_TRUE(menu_is_valid());
- bridge_->UpdateMenu(bridge_->menu_);
- EXPECT_TRUE(menu_is_valid());
-
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- const char* url = "http://www.zim-bop-a-dee.com/";
- model->AddURL(parent, 0, ASCIIToUTF16("Bookmark"), GURL(url));
-
- EXPECT_FALSE(menu_is_valid());
- bridge_->UpdateMenu(bridge_->menu_);
- EXPECT_TRUE(menu_is_valid());
-}
-
-// Test that AddNodeToMenu() properly adds bookmark nodes as menus,
-// including the recursive case.
-TEST_F(BookmarkMenuBridgeTest, TestAddNodeToMenu) {
- string16 empty;
- NSMenu* menu = bridge_->menu_.get();
-
- BookmarkModel* model = bridge_->GetBookmarkModel();
- const BookmarkNode* root = model->GetBookmarkBarNode();
- EXPECT_TRUE(model && root);
-
- const char* short_url = "http://foo/";
- const char* long_url = "http://super-duper-long-url--."
- "that.cannot.possibly.fit.even-in-80-columns"
- "or.be.reasonably-displayed-in-a-menu"
- "without.looking-ridiculous.com/"; // 140 chars total
-
- // 3 nodes; middle one has a child, last one has a HUGE URL
- // Set their titles to be the same as the URLs
- const BookmarkNode* node = NULL;
- model->AddURL(root, 0, ASCIIToUTF16(short_url), GURL(short_url));
- bridge_->UpdateMenu(menu);
- int prev_count = [menu numberOfItems] - 1; // "extras" added at this point
- node = model->AddGroup(root, 1, empty);
- model->AddURL(root, 2, ASCIIToUTF16(long_url), GURL(long_url));
-
- // And the submenu fo the middle one
- model->AddURL(node, 0, empty, GURL("http://sub"));
- bridge_->UpdateMenu(menu);
-
- EXPECT_EQ((NSInteger)(prev_count+3), [menu numberOfItems]);
-
- // Verify the 1st one is there with the right action.
- NSMenuItem* item = [menu itemWithTitle:[NSString
- stringWithUTF8String:short_url]];
- EXPECT_TRUE(item);
- EXPECT_EQ(@selector(openBookmarkMenuItem:), [item action]);
- EXPECT_EQ(NO, [item hasSubmenu]);
- NSMenuItem* short_item = item;
- NSMenuItem* long_item = nil;
-
- // Now confirm we have 2 submenus (the one we added, plus "other")
- int subs = 0;
- for (item in [menu itemArray]) {
- if ([item hasSubmenu])
- subs++;
- }
- EXPECT_EQ(2, subs);
-
- for (item in [menu itemArray]) {
- if ([[item title] hasPrefix:@"http://super-duper"]) {
- long_item = item;
- break;
- }
- }
- EXPECT_TRUE(long_item);
-
- // Make sure a short title looks fine
- NSString* s = [short_item title];
- EXPECT_NSEQ([NSString stringWithUTF8String:short_url], s);
-
- // Make sure a super-long title gets trimmed
- s = [long_item title];
- EXPECT_TRUE([s length] < strlen(long_url));
-
- // Confirm tooltips and confirm they are not trimmed (like the item
- // name might be). Add tolerance for URL fixer-upping;
- // e.g. http://foo becomes http://foo/)
- EXPECT_GE([[short_item toolTip] length], (2*strlen(short_url) - 5));
- EXPECT_GE([[long_item toolTip] length], (2*strlen(long_url) - 5));
-
- // Make sure the favicon is non-nil (should be either the default site
- // icon or a favicon, if present).
- EXPECT_TRUE([short_item image]);
- EXPECT_TRUE([long_item image]);
-}
-
-// Makes sure our internal map of BookmarkNode to NSMenuItem works.
-TEST_F(BookmarkMenuBridgeTest, TestGetMenuItemForNode) {
- string16 empty;
- NSMenu* menu = bridge_->menu_.get();
-
- BookmarkModel* model = bridge_->GetBookmarkModel();
- const BookmarkNode* bookmark_bar = model->GetBookmarkBarNode();
- const BookmarkNode* root = model->AddGroup(bookmark_bar, 0, empty);
- EXPECT_TRUE(model && root);
-
- model->AddURL(root, 0, ASCIIToUTF16("Test Item"), GURL("http://test"));
- AddNodeToMenu(bridge_.get(), root, menu);
- EXPECT_TRUE(MenuItemForNode(bridge_.get(), root->GetChild(0)));
-
- model->AddURL(root, 1, ASCIIToUTF16("Test 2"), GURL("http://second-test"));
- AddNodeToMenu(bridge_.get(), root, menu);
- EXPECT_TRUE(MenuItemForNode(bridge_.get(), root->GetChild(0)));
- EXPECT_TRUE(MenuItemForNode(bridge_.get(), root->GetChild(1)));
-
- const BookmarkNode* removed_node = root->GetChild(0);
- EXPECT_EQ(2, root->GetChildCount());
- model->Remove(root, 0);
- EXPECT_EQ(1, root->GetChildCount());
- bridge_->UpdateMenu(menu);
- EXPECT_FALSE(MenuItemForNode(bridge_.get(), removed_node));
- EXPECT_TRUE(MenuItemForNode(bridge_.get(), root->GetChild(0)));
-
- const BookmarkNode empty_node(GURL("http://no-where/"));
- EXPECT_FALSE(MenuItemForNode(bridge_.get(), &empty_node));
- EXPECT_FALSE(MenuItemForNode(bridge_.get(), NULL));
-}
-
-// Test that Loaded() adds both the bookmark bar nodes and the "other" nodes.
-TEST_F(BookmarkMenuBridgeTest, TestAddNodeToOther) {
- NSMenu* menu = bridge_->menu_.get();
-
- BookmarkModel* model = bridge_->GetBookmarkModel();
- const BookmarkNode* root = model->other_node();
- EXPECT_TRUE(model && root);
-
- const char* short_url = "http://foo/";
- model->AddURL(root, 0, ASCIIToUTF16(short_url), GURL(short_url));
-
- bridge_->UpdateMenu(menu);
- ASSERT_GT([menu numberOfItems], 0);
- NSMenuItem* other = [menu itemAtIndex:([menu numberOfItems]-1)];
- EXPECT_TRUE(other);
- EXPECT_TRUE([other hasSubmenu]);
- ASSERT_GT([[other submenu] numberOfItems], 0);
- EXPECT_NSEQ(@"http://foo/", [[[other submenu] itemAtIndex:0] title]);
-}
-
-TEST_F(BookmarkMenuBridgeTest, TestFavIconLoading) {
- NSMenu* menu = bridge_->menu_;
-
- BookmarkModel* model = bridge_->GetBookmarkModel();
- const BookmarkNode* root = model->GetBookmarkBarNode();
- EXPECT_TRUE(model && root);
-
- const BookmarkNode* node =
- model->AddURL(root, 0, ASCIIToUTF16("Test Item"),
- GURL("http://favicon-test"));
- bridge_->UpdateMenu(menu);
- NSMenuItem* item = [menu itemWithTitle:@"Test Item"];
- EXPECT_TRUE([item image]);
- [item setImage:nil];
- bridge_->BookmarkNodeFavIconLoaded(model, node);
- EXPECT_TRUE([item image]);
-}
-
-TEST_F(BookmarkMenuBridgeTest, TestChangeTitle) {
- NSMenu* menu = bridge_->menu_;
- BookmarkModel* model = bridge_->GetBookmarkModel();
- const BookmarkNode* root = model->GetBookmarkBarNode();
- EXPECT_TRUE(model && root);
-
- const BookmarkNode* node =
- model->AddURL(root, 0, ASCIIToUTF16("Test Item"),
- GURL("http://title-test"));
- bridge_->UpdateMenu(menu);
- NSMenuItem* item = [menu itemWithTitle:@"Test Item"];
- EXPECT_TRUE([item image]);
-
- model->SetTitle(node, ASCIIToUTF16("New Title"));
-
- item = [menu itemWithTitle:@"Test Item"];
- EXPECT_FALSE(item);
- item = [menu itemWithTitle:@"New Title"];
- EXPECT_TRUE(item);
-}
-
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_menu_cocoa_controller.h b/chrome/browser/cocoa/bookmarks/bookmark_menu_cocoa_controller.h
deleted file mode 100644
index dc5c221..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_menu_cocoa_controller.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// 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.
-
-// Controller (MVC) for the bookmark menu.
-// All bookmark menu item commands get directed here.
-// Unfortunately there is already a C++ class named BookmarkMenuController.
-
-#ifndef CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_MENU_COCOA_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_MENU_COCOA_CONTROLLER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/cocoa_protocols_mac.h"
-
-class BookmarkNode;
-class BookmarkMenuBridge;
-
-@interface BookmarkMenuCocoaController : NSObject<NSMenuDelegate> {
- @private
- BookmarkMenuBridge* bridge_; // weak; owns me
-}
-
-// The Bookmarks menu
-@property (nonatomic, readonly) NSMenu* menu;
-
-// Return an autoreleased string to be used as a menu title for the
-// given bookmark node.
-+ (NSString*)menuTitleForNode:(const BookmarkNode*)node;
-
-- (id)initWithBridge:(BookmarkMenuBridge *)bridge;
-
-// Called by any Bookmark menu item.
-// The menu item's tag is the bookmark ID.
-- (IBAction)openBookmarkMenuItem:(id)sender;
-
-@end // BookmarkMenuCocoaController
-
-
-@interface BookmarkMenuCocoaController (ExposedForUnitTests)
-- (const BookmarkNode*)nodeForIdentifier:(int)identifier;
-- (void)openURLForNode:(const BookmarkNode*)node;
-@end // BookmarkMenuCocoaController (ExposedForUnitTests)
-
-#endif // CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_MENU_COCOA_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm b/chrome/browser/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm
deleted file mode 100644
index 93ff846..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm
+++ /dev/null
@@ -1,98 +0,0 @@
-// 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 "chrome/browser/cocoa/bookmarks/bookmark_menu_cocoa_controller.h"
-
-#include "app/text_elider.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/app/chrome_command_ids.h" // IDC_BOOKMARK_MENU
-#import "chrome/browser/app_controller_mac.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_menu_bridge.h"
-#include "chrome/browser/cocoa/event_utils.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/ui/browser.h"
-#include "webkit/glue/window_open_disposition.h"
-
-namespace {
-
-// Menus more than this many pixels wide will get trimmed
-// TODO(jrg): ask UI dudes what a good value is.
-const NSUInteger kMaximumMenuPixelsWide = 300;
-
-}
-
-@implementation BookmarkMenuCocoaController
-
-+ (NSString*)menuTitleForNode:(const BookmarkNode*)node {
- NSFont* nsfont = [NSFont menuBarFontOfSize:0]; // 0 means "default"
- gfx::Font font(base::SysNSStringToWide([nsfont fontName]),
- static_cast<int>([nsfont pointSize]));
- string16 title = gfx::ElideText(node->GetTitle(),
- font,
- kMaximumMenuPixelsWide,
- false);
- return base::SysUTF16ToNSString(title);
-}
-
-- (id)initWithBridge:(BookmarkMenuBridge *)bridge {
- if ((self = [super init])) {
- bridge_ = bridge;
- DCHECK(bridge_);
- [[self menu] setDelegate:self];
- }
- return self;
-}
-
-- (void)dealloc {
- [[self menu] setDelegate:nil];
- [super dealloc];
-}
-
-- (NSMenu*)menu {
- return [[[NSApp mainMenu] itemWithTag:IDC_BOOKMARK_MENU] submenu];
-}
-
-- (BOOL)validateMenuItem:(NSMenuItem*)menuItem {
- AppController* controller = [NSApp delegate];
- return [controller keyWindowIsNotModal];
-}
-
-// NSMenu delegate method: called just before menu is displayed.
-- (void)menuNeedsUpdate:(NSMenu*)menu {
- bridge_->UpdateMenu(menu);
-}
-
-// Return the a BookmarkNode that has the given id (called
-// "identifier" here to avoid conflict with objc's concept of "id").
-- (const BookmarkNode*)nodeForIdentifier:(int)identifier {
- return bridge_->GetBookmarkModel()->GetNodeByID(identifier);
-}
-
-// Open the URL of the given BookmarkNode in the current tab.
-- (void)openURLForNode:(const BookmarkNode*)node {
- Browser* browser = Browser::GetTabbedBrowser(bridge_->GetProfile(), true);
- if (!browser)
- browser = Browser::Create(bridge_->GetProfile());
- WindowOpenDisposition disposition =
- event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
- browser->OpenURL(node->GetURL(), GURL(), disposition,
- PageTransition::AUTO_BOOKMARK);
-}
-
-- (IBAction)openBookmarkMenuItem:(id)sender {
- NSInteger tag = [sender tag];
- int identifier = tag;
- const BookmarkNode* node = [self nodeForIdentifier:identifier];
- DCHECK(node);
- if (!node)
- return; // shouldn't be reached
-
- [self openURLForNode:node];
-}
-
-@end // BookmarkMenuCocoaController
-
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_menu_cocoa_controller_unittest.mm b/chrome/browser/cocoa/bookmarks/bookmark_menu_cocoa_controller_unittest.mm
deleted file mode 100644
index 8c0b4cd..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_menu_cocoa_controller_unittest.mm
+++ /dev/null
@@ -1,66 +0,0 @@
-// 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.
-
-#include "base/string16.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_menu_cocoa_controller.h"
-#include "chrome/browser/ui/browser.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-@interface FakeBookmarkMenuController : BookmarkMenuCocoaController {
- @public
- BrowserTestHelper* helper_;
- const BookmarkNode* nodes_[2];
- BOOL opened_[2];
-}
-@end
-
-@implementation FakeBookmarkMenuController
-
-- (id)init {
- if ((self = [super init])) {
- string16 empty;
- helper_ = new BrowserTestHelper();
- BookmarkModel* model = helper_->browser()->profile()->GetBookmarkModel();
- const BookmarkNode* bookmark_bar = model->GetBookmarkBarNode();
- nodes_[0] = model->AddURL(bookmark_bar, 0, empty, GURL("http://0.com"));
- nodes_[1] = model->AddURL(bookmark_bar, 1, empty, GURL("http://1.com"));
- }
- return self;
-}
-
-- (void)dealloc {
- delete helper_;
- [super dealloc];
-}
-
-- (const BookmarkNode*)nodeForIdentifier:(int)identifier {
- if ((identifier < 0) || (identifier >= 2))
- return NULL;
- return nodes_[identifier];
-}
-
-- (void)openURLForNode:(const BookmarkNode*)node {
- std::string url = node->GetURL().possibly_invalid_spec();
- if (url.find("http://0.com") != std::string::npos)
- opened_[0] = YES;
- if (url.find("http://1.com") != std::string::npos)
- opened_[1] = YES;
-}
-
-@end // FakeBookmarkMenuController
-
-
-TEST(BookmarkMenuCocoaControllerTest, TestOpenItem) {
- FakeBookmarkMenuController *c = [[FakeBookmarkMenuController alloc] init];
- NSMenuItem *item = [[[NSMenuItem alloc] init] autorelease];
- for (int i = 0; i < 2; i++) {
- [item setTag:i];
- ASSERT_EQ(c->opened_[i], NO);
- [c openBookmarkMenuItem:item];
- ASSERT_NE(c->opened_[i], NO);
- }
- [c release];
-}
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_menu_unittest.mm b/chrome/browser/cocoa/bookmarks/bookmark_menu_unittest.mm
deleted file mode 100644
index bed4f55..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_menu_unittest.mm
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2009 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/scoped_nsobject.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_menu.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-namespace {
-
-class BookmarkMenuTest : public CocoaTest {
-};
-
-TEST_F(BookmarkMenuTest, Basics) {
- scoped_nsobject<BookmarkMenu> menu([[BookmarkMenu alloc]
- initWithTitle:@"title"]);
- scoped_nsobject<NSMenuItem> item([[NSMenuItem alloc] initWithTitle:@"item"
- action:NULL
- keyEquivalent:@""]);
- [menu addItem:item];
- long long l = 103849459459598948LL; // arbitrary
- NSNumber* number = [NSNumber numberWithLongLong:l];
- [menu setRepresentedObject:number];
- EXPECT_EQ(l, [menu id]);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_model_observer_for_cocoa.h b/chrome/browser/cocoa/bookmarks/bookmark_model_observer_for_cocoa.h
deleted file mode 100644
index 4acc972..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_model_observer_for_cocoa.h
+++ /dev/null
@@ -1,116 +0,0 @@
-// 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.
-
-// C++ bridge class to send a selector to a Cocoa object when the
-// bookmark model changes. Some Cocoa objects edit the bookmark model
-// and temporarily save a copy of the state (e.g. bookmark button
-// editor). As a fail-safe, these objects want an easy cancel if the
-// model changes out from under them. For example, if you have the
-// bookmark button editor sheet open, then edit the bookmark in the
-// bookmark manager, we'd want to simply cancel the editor.
-//
-// This class is conservative and may result in notifications which
-// aren't strictly necessary. For example, node removal only needs to
-// cancel an edit if the removed node is a folder (editors often have
-// a list of "new parents"). But, just to be sure, notification
-// happens on any removal.
-
-#ifndef CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_MODEL_OBSERVER_FOR_COCOA_H
-#define CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_MODEL_OBSERVER_FOR_COCOA_H
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/basictypes.h"
-#include "base/scoped_nsobject.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#include "chrome/browser/bookmarks/bookmark_model_observer.h"
-
-class BookmarkModelObserverForCocoa : public BookmarkModelObserver {
- public:
- // When |node| in |model| changes, send |selector| to |object|.
- // Assumes |selector| is a selector that takes one arg, like an
- // IBOutlet. The arg passed is nil.
- // Many notifications happen independently of node
- // (e.g. BeingDeleted), so |node| can be nil.
- //
- // |object| is NOT retained, since the expected use case is for
- // ||object| to own the BookmarkModelObserverForCocoa and we don't
- // want a retain cycle.
- BookmarkModelObserverForCocoa(const BookmarkNode* node,
- BookmarkModel* model,
- NSObject* object,
- SEL selector) {
- DCHECK(model);
- node_ = node;
- model_ = model;
- object_ = object;
- selector_ = selector;
- model_->AddObserver(this);
- }
- virtual ~BookmarkModelObserverForCocoa() {
- model_->RemoveObserver(this);
- }
-
- virtual void BookmarkModelBeingDeleted(BookmarkModel* model) {
- Notify();
- }
- virtual void BookmarkNodeMoved(BookmarkModel* model,
- const BookmarkNode* old_parent,
- int old_index,
- const BookmarkNode* new_parent,
- int new_index) {
- // Editors often have a tree of parents, so movement of folders
- // must cause a cancel.
- Notify();
- }
- virtual void BookmarkNodeRemoved(BookmarkModel* model,
- const BookmarkNode* parent,
- int old_index,
- const BookmarkNode* node) {
- // See comment in BookmarkNodeMoved.
- Notify();
- }
- virtual void BookmarkNodeChanged(BookmarkModel* model,
- const BookmarkNode* node) {
- if ((node_ == node) || (!node_))
- Notify();
- }
- virtual void BookmarkImportBeginning(BookmarkModel* model) {
- // Be conservative.
- Notify();
- }
-
- // Some notifications we don't care about, but by being pure virtual
- // in the base class we must implement them.
- virtual void Loaded(BookmarkModel* model) {
- }
- virtual void BookmarkNodeAdded(BookmarkModel* model,
- const BookmarkNode* parent,
- int index) {
- }
- virtual void BookmarkNodeFavIconLoaded(BookmarkModel* model,
- const BookmarkNode* node) {
- }
- virtual void BookmarkNodeChildrenReordered(BookmarkModel* model,
- const BookmarkNode* node) {
- }
-
- virtual void BookmarkImportEnding(BookmarkModel* model) {
- }
-
- private:
- const BookmarkNode* node_; // Weak; owned by a BookmarkModel.
- BookmarkModel* model_; // Weak; it is owned by a Profile.
- NSObject* object_; // Weak, like a delegate.
- SEL selector_;
-
- void Notify() {
- [object_ performSelector:selector_ withObject:nil];
- }
-
- DISALLOW_COPY_AND_ASSIGN(BookmarkModelObserverForCocoa);
-};
-
-#endif // CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_MODEL_OBSERVER_FOR_COCOA_H
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_model_observer_for_cocoa_unittest.mm b/chrome/browser/cocoa/bookmarks/bookmark_model_observer_for_cocoa_unittest.mm
deleted file mode 100644
index a84cc53..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_model_observer_for_cocoa_unittest.mm
+++ /dev/null
@@ -1,68 +0,0 @@
-// 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 "base/scoped_ptr.h"
-#include "base/scoped_nsobject.h"
-#include "base/utf_string_conversions.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_model_observer_for_cocoa.h"
-#import "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-
-// Keep track of bookmark pings.
-@interface ObserverPingTracker : NSObject {
- @public
- int pings;
-}
-@end
-
-@implementation ObserverPingTracker
-- (void)pingMe:(id)sender {
- pings++;
-}
-@end
-
-namespace {
-
-class BookmarkModelObserverForCocoaTest : public CocoaTest {
- public:
- BrowserTestHelper helper_;
-
- BookmarkModelObserverForCocoaTest() {}
- virtual ~BookmarkModelObserverForCocoaTest() {}
- private:
- DISALLOW_COPY_AND_ASSIGN(BookmarkModelObserverForCocoaTest);
-};
-
-
-TEST_F(BookmarkModelObserverForCocoaTest, TestCallback) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- const BookmarkNode* node = model->AddURL(model->GetBookmarkBarNode(),
- 0, ASCIIToUTF16("super"),
- GURL("http://www.google.com"));
-
- scoped_nsobject<ObserverPingTracker>
- pingCount([[ObserverPingTracker alloc] init]);
-
- scoped_ptr<BookmarkModelObserverForCocoa>
- observer(new BookmarkModelObserverForCocoa(node, model,
- pingCount,
- @selector(pingMe:)));
-
- EXPECT_EQ(0, pingCount.get()->pings);
-
- model->SetTitle(node, ASCIIToUTF16("duper"));
- EXPECT_EQ(1, pingCount.get()->pings);
- model->SetURL(node, GURL("http://www.google.com/reader"));
- EXPECT_EQ(2, pingCount.get()->pings);
-
- model->Move(node, model->other_node(), 0);
- EXPECT_EQ(3, pingCount.get()->pings);
-
- model->Remove(node->GetParent(), 0);
- EXPECT_EQ(4, pingCount.get()->pings);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_name_folder_controller.h b/chrome/browser/cocoa/bookmarks/bookmark_name_folder_controller.h
deleted file mode 100644
index 7de139f..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_name_folder_controller.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_NAME_FOLDER_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_NAME_FOLDER_CONTROLLER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-
-class BookmarkModelObserverForCocoa;
-
-// A controller for dialog to let the user create a new folder or
-// rename an existing folder. Accessible from a context menu on a
-// bookmark button or the bookmark bar.
-@interface BookmarkNameFolderController : NSWindowController {
- @private
- IBOutlet NSTextField* nameField_;
- IBOutlet NSButton* okButton_;
-
- NSWindow* parentWindow_; // weak
- Profile* profile_; // weak
-
- // Weak; owned by the model. Can be NULL (see below). Either node_
- // is non-NULL (renaming a folder), or parent_ is non-NULL (adding a
- // new one).
- const BookmarkNode* node_;
- const BookmarkNode* parent_;
- int newIndex_;
-
- scoped_nsobject<NSString> initialName_;
-
- // Ping me when things change out from under us.
- scoped_ptr<BookmarkModelObserverForCocoa> observer_;
-}
-
-// Use the 1st initializer for a "rename existing folder" request.
-//
-// Use the 2nd initializer for an "add folder" request. If creating a
-// new folder |parent| and |newIndex| specify where to put the new
-// node.
-- (id)initWithParentWindow:(NSWindow*)window
- profile:(Profile*)profile
- node:(const BookmarkNode*)node;
-- (id)initWithParentWindow:(NSWindow*)window
- profile:(Profile*)profile
- parent:(const BookmarkNode*)parent
- newIndex:(int)newIndex;
-- (void)runAsModalSheet;
-- (IBAction)cancel:(id)sender;
-- (IBAction)ok:(id)sender;
-@end
-
-@interface BookmarkNameFolderController(TestingAPI)
-- (NSString*)folderName;
-- (void)setFolderName:(NSString*)name;
-- (NSButton*)okButton;
-@end
-
-#endif // CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_NAME_FOLDER_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_name_folder_controller.mm b/chrome/browser/cocoa/bookmarks/bookmark_name_folder_controller.mm
deleted file mode 100644
index fe8cdfd..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_name_folder_controller.mm
+++ /dev/null
@@ -1,123 +0,0 @@
-// 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 "chrome/browser/cocoa/bookmarks/bookmark_name_folder_controller.h"
-
-#include "app/l10n_util.h"
-#include "app/l10n_util_mac.h"
-#include "base/mac_util.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/cocoa/bookmarks/bookmark_model_observer_for_cocoa.h"
-#include "chrome/browser/profile.h"
-#include "grit/generated_resources.h"
-
-@implementation BookmarkNameFolderController
-
-// Common initializer (private).
-- (id)initWithParentWindow:(NSWindow*)window
- profile:(Profile*)profile
- node:(const BookmarkNode*)node
- parent:(const BookmarkNode*)parent
- newIndex:(int)newIndex {
- NSString* nibpath = [mac_util::MainAppBundle()
- pathForResource:@"BookmarkNameFolder"
- ofType:@"nib"];
- if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
- parentWindow_ = window;
- profile_ = profile;
- node_ = node;
- parent_ = parent;
- newIndex_ = newIndex;
- if (parent) {
- DCHECK_LE(newIndex, parent->GetChildCount());
- }
- if (node_) {
- initialName_.reset([base::SysUTF16ToNSString(node_->GetTitle()) retain]);
- } else {
- NSString* newString =
- l10n_util::GetNSStringWithFixup(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME);
- initialName_.reset([newString retain]);
- }
- }
- return self;
-}
-
-- (id)initWithParentWindow:(NSWindow*)window
- profile:(Profile*)profile
- node:(const BookmarkNode*)node {
- DCHECK(node);
- return [self initWithParentWindow:window
- profile:profile
- node:node
- parent:nil
- newIndex:0];
-}
-
-- (id)initWithParentWindow:(NSWindow*)window
- profile:(Profile*)profile
- parent:(const BookmarkNode*)parent
- newIndex:(int)newIndex {
- DCHECK(parent);
- return [self initWithParentWindow:window
- profile:profile
- node:nil
- parent:parent
- newIndex:newIndex];
-}
-
-- (void)awakeFromNib {
- [nameField_ setStringValue:initialName_.get()];
-}
-
-- (void)runAsModalSheet {
- // Ping me when things change out from under us.
- observer_.reset(new BookmarkModelObserverForCocoa(
- node_, profile_->GetBookmarkModel(),
- self,
- @selector(cancel:)));
- [NSApp beginSheet:[self window]
- modalForWindow:parentWindow_
- modalDelegate:self
- didEndSelector:@selector(didEndSheet:returnCode:contextInfo:)
- contextInfo:nil];
-}
-
-- (IBAction)cancel:(id)sender {
- [NSApp endSheet:[self window]];
-}
-
-- (IBAction)ok:(id)sender {
- NSString* name = [nameField_ stringValue];
- BookmarkModel* model = profile_->GetBookmarkModel();
- if (node_) {
- model->SetTitle(node_, base::SysNSStringToUTF16(name));
- } else {
- model->AddGroup(parent_,
- newIndex_,
- base::SysNSStringToUTF16(name));
- }
- [NSApp endSheet:[self window]];
-}
-
-- (void)didEndSheet:(NSWindow*)sheet
- returnCode:(int)returnCode
- contextInfo:(void*)contextInfo {
- [[self window] orderOut:self];
- observer_.reset(NULL);
- [self autorelease];
-}
-
-- (NSString*)folderName {
- return [nameField_ stringValue];
-}
-
-- (void)setFolderName:(NSString*)name {
- [nameField_ setStringValue:name];
-}
-
-- (NSButton*)okButton {
- return okButton_;
-}
-
-@end // BookmarkNameFolderController
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_name_folder_controller_unittest.mm b/chrome/browser/cocoa/bookmarks/bookmark_name_folder_controller_unittest.mm
deleted file mode 100644
index 3a435f7..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_name_folder_controller_unittest.mm
+++ /dev/null
@@ -1,172 +0,0 @@
-// 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 "base/scoped_nsobject.h"
-#include "base/utf_string_conversions.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_name_folder_controller.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-class BookmarkNameFolderControllerTest : public CocoaTest {
- public:
- BrowserTestHelper helper_;
-};
-
-
-// Simple add of a node (at the end).
-TEST_F(BookmarkNameFolderControllerTest, AddNew) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- EXPECT_EQ(0, parent->GetChildCount());
-
- scoped_nsobject<BookmarkNameFolderController>
- controller([[BookmarkNameFolderController alloc]
- initWithParentWindow:test_window()
- profile:helper_.profile()
- parent:parent
- newIndex:0]);
- [controller window]; // force nib load
-
- // Do nothing.
- [controller cancel:nil];
- EXPECT_EQ(0, parent->GetChildCount());
-
- // Change name then cancel.
- [controller setFolderName:@"Bozo"];
- [controller cancel:nil];
- EXPECT_EQ(0, parent->GetChildCount());
-
- // Add a new folder.
- [controller ok:nil];
- EXPECT_EQ(1, parent->GetChildCount());
- EXPECT_TRUE(parent->GetChild(0)->is_folder());
- EXPECT_EQ(ASCIIToUTF16("Bozo"), parent->GetChild(0)->GetTitle());
-}
-
-// Add new but specify a sibling.
-TEST_F(BookmarkNameFolderControllerTest, AddNewWithSibling) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- const BookmarkNode* parent = model->GetBookmarkBarNode();
-
- // Add 2 nodes. We will place the new folder in the middle of these.
- model->AddURL(parent, 0, ASCIIToUTF16("title 1"),
- GURL("http://www.google.com"));
- model->AddURL(parent, 1, ASCIIToUTF16("title 3"),
- GURL("http://www.google.com"));
- EXPECT_EQ(2, parent->GetChildCount());
-
- scoped_nsobject<BookmarkNameFolderController>
- controller([[BookmarkNameFolderController alloc]
- initWithParentWindow:test_window()
- profile:helper_.profile()
- parent:parent
- newIndex:1]);
- [controller window]; // force nib load
-
- // Add a new folder.
- [controller setFolderName:@"middle"];
- [controller ok:nil];
-
- // Confirm we now have 3, and that the new one is in the middle.
- EXPECT_EQ(3, parent->GetChildCount());
- EXPECT_TRUE(parent->GetChild(1)->is_folder());
- EXPECT_EQ(ASCIIToUTF16("middle"), parent->GetChild(1)->GetTitle());
-}
-
-// Make sure we are allowed to create a folder named "New Folder".
-TEST_F(BookmarkNameFolderControllerTest, AddNewDefaultName) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- EXPECT_EQ(0, parent->GetChildCount());
-
- scoped_nsobject<BookmarkNameFolderController>
- controller([[BookmarkNameFolderController alloc]
- initWithParentWindow:test_window()
- profile:helper_.profile()
- parent:parent
- newIndex:0]);
-
- [controller window]; // force nib load
-
- // Click OK without changing the name
- [controller ok:nil];
- EXPECT_EQ(1, parent->GetChildCount());
- EXPECT_TRUE(parent->GetChild(0)->is_folder());
-}
-
-// Make sure we are allowed to create a folder with an empty name.
-TEST_F(BookmarkNameFolderControllerTest, AddNewBlankName) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- EXPECT_EQ(0, parent->GetChildCount());
-
- scoped_nsobject<BookmarkNameFolderController>
- controller([[BookmarkNameFolderController alloc]
- initWithParentWindow:test_window()
- profile:helper_.profile()
- parent:parent
- newIndex:0]);
- [controller window]; // force nib load
-
- // Change the name to blank, click OK.
- [controller setFolderName:@""];
- [controller ok:nil];
- EXPECT_EQ(1, parent->GetChildCount());
- EXPECT_TRUE(parent->GetChild(0)->is_folder());
-}
-
-TEST_F(BookmarkNameFolderControllerTest, Rename) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- const BookmarkNode* folder = model->AddGroup(parent,
- parent->GetChildCount(),
- ASCIIToUTF16("group"));
-
- // Rename the folder by creating a controller that originates from
- // the node.
- scoped_nsobject<BookmarkNameFolderController>
- controller([[BookmarkNameFolderController alloc]
- initWithParentWindow:test_window()
- profile:helper_.profile()
- node:folder]);
- [controller window]; // force nib load
-
- EXPECT_NSEQ(@"group", [controller folderName]);
- [controller setFolderName:@"Zobo"];
- [controller ok:nil];
- EXPECT_EQ(1, parent->GetChildCount());
- EXPECT_TRUE(parent->GetChild(0)->is_folder());
- EXPECT_EQ(ASCIIToUTF16("Zobo"), parent->GetChild(0)->GetTitle());
-}
-
-TEST_F(BookmarkNameFolderControllerTest, EditAndConfirmOKButton) {
- BookmarkModel* model = helper_.profile()->GetBookmarkModel();
- const BookmarkNode* parent = model->GetBookmarkBarNode();
- EXPECT_EQ(0, parent->GetChildCount());
-
- scoped_nsobject<BookmarkNameFolderController>
- controller([[BookmarkNameFolderController alloc]
- initWithParentWindow:test_window()
- profile:helper_.profile()
- parent:parent
- newIndex:0]);
- [controller window]; // force nib load
-
- // We start enabled since the default "New Folder" is added for us.
- EXPECT_TRUE([[controller okButton] isEnabled]);
-
- [controller setFolderName:@"Bozo"];
- EXPECT_TRUE([[controller okButton] isEnabled]);
- [controller setFolderName:@" "];
- EXPECT_TRUE([[controller okButton] isEnabled]);
-
- [controller setFolderName:@""];
- EXPECT_TRUE([[controller okButton] isEnabled]);
-}
-
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_tree_browser_cell.h b/chrome/browser/cocoa/bookmarks/bookmark_tree_browser_cell.h
deleted file mode 100644
index 7cdee51..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_tree_browser_cell.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_TREE_BROWSER_CELL_H_
-#define CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_TREE_BROWSER_CELL_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-class BookmarkNode;
-
-// Provides a custom cell as used in the BookmarkEditor.xib's folder tree
-// browser view. This cell customization adds target and action support
-// not provided by the NSBrowserCell as well as contextual information
-// identifying the bookmark node being edited and the column matrix
-// control in which is contained the cell.
-@interface BookmarkTreeBrowserCell : NSBrowserCell {
- @private
- const BookmarkNode* bookmarkNode_; // weak
- NSMatrix* matrix_; // weak
- id target_; // weak
- SEL action_;
-}
-
-@property (nonatomic, assign) NSMatrix* matrix;
-@property (nonatomic, assign) id target;
-@property (nonatomic, assign) SEL action;
-
-- (const BookmarkNode*)bookmarkNode;
-- (void)setBookmarkNode:(const BookmarkNode*)bookmarkNode;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_BOOKMARKS_BOOKMARK_TREE_BROWSER_CELL_H_
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_tree_browser_cell.mm b/chrome/browser/cocoa/bookmarks/bookmark_tree_browser_cell.mm
deleted file mode 100644
index b778858..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_tree_browser_cell.mm
+++ /dev/null
@@ -1,23 +0,0 @@
-// 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 "chrome/browser/cocoa/bookmarks/bookmark_tree_browser_cell.h"
-
-#include "chrome/browser/bookmarks/bookmark_model.h"
-
-@implementation BookmarkTreeBrowserCell
-
-@synthesize matrix = matrix_;
-@synthesize target = target_;
-@synthesize action = action_;
-
-- (const BookmarkNode*)bookmarkNode {
- return bookmarkNode_;
-}
-
-- (void)setBookmarkNode:(const BookmarkNode*)bookmarkNode {
- bookmarkNode_ = bookmarkNode;
-}
-
-@end
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_tree_browser_cell_unittest.mm b/chrome/browser/cocoa/bookmarks/bookmark_tree_browser_cell_unittest.mm
deleted file mode 100644
index a8418e2..0000000
--- a/chrome/browser/cocoa/bookmarks/bookmark_tree_browser_cell_unittest.mm
+++ /dev/null
@@ -1,43 +0,0 @@
-// 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 "chrome/browser/bookmarks/bookmark_model.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_tree_browser_cell.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/platform_test.h"
-
-class BookmarkTreeBrowserCellTest : public PlatformTest {
- public:
- BookmarkTreeBrowserCellTest() {
- // Set up our mocks.
- GURL gurl;
- bookmarkNodeMock_.reset(new BookmarkNode(gurl));
- matrixMock_.reset([[NSMatrix alloc] init]);
- targetMock_.reset([[NSObject alloc] init]);
- }
-
- scoped_ptr<BookmarkNode> bookmarkNodeMock_;
- scoped_nsobject<NSMatrix> matrixMock_;
- scoped_nsobject<NSObject> targetMock_;
-};
-
-TEST_F(BookmarkTreeBrowserCellTest, BasicAllocDealloc) {
- BookmarkTreeBrowserCell* cell = [[[BookmarkTreeBrowserCell alloc]
- initTextCell:@"TEST STRING"] autorelease];
- [cell setMatrix:matrixMock_.get()];
- [cell setTarget:targetMock_.get()];
- [cell setAction:@selector(mockAction:)];
- [cell setBookmarkNode:bookmarkNodeMock_.get()];
-
- NSMatrix* testMatrix = [cell matrix];
- EXPECT_EQ(testMatrix, matrixMock_.get());
- id testTarget = [cell target];
- EXPECT_EQ(testTarget, targetMock_.get());
- SEL testAction = [cell action];
- EXPECT_EQ(testAction, @selector(mockAction:));
- const BookmarkNode* testBookmarkNode = [cell bookmarkNode];
- EXPECT_EQ(testBookmarkNode, bookmarkNodeMock_.get());
-}
diff --git a/chrome/browser/cocoa/browser_frame_view.mm b/chrome/browser/cocoa/browser_frame_view.mm
deleted file mode 100644
index 87c27a0..0000000
--- a/chrome/browser/cocoa/browser_frame_view.mm
+++ /dev/null
@@ -1,399 +0,0 @@
-// 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 "chrome/browser/cocoa/browser_frame_view.h"
-
-#import <objc/runtime.h>
-#import <Carbon/Carbon.h>
-
-#include "base/logging.h"
-#include "base/mac/scoped_nsautorelease_pool.h"
-#import "chrome/browser/cocoa/framed_browser_window.h"
-#import "chrome/browser/cocoa/themed_window.h"
-#import "chrome/browser/themes/browser_theme_provider.h"
-#include "grit/theme_resources.h"
-
-static const CGFloat kBrowserFrameViewPaintHeight = 60.0;
-static const NSPoint kBrowserFrameViewPatternPhaseOffset = { -5, 3 };
-
-static BOOL gCanDrawTitle = NO;
-static BOOL gCanGetCornerRadius = NO;
-
-@interface NSView (Swizzles)
-- (void)drawRectOriginal:(NSRect)rect;
-- (BOOL)_mouseInGroup:(NSButton*)widget;
-- (void)updateTrackingAreas;
-- (NSUInteger)_shadowFlagsOriginal;
-@end
-
-// Undocumented APIs. They are really on NSGrayFrame rather than
-// BrowserFrameView, but we call them from methods swizzled onto NSGrayFrame.
-@interface BrowserFrameView (UndocumentedAPI)
-
-- (float)roundedCornerRadius;
-- (CGRect)_titlebarTitleRect;
-- (void)_drawTitleStringIn:(struct CGRect)arg1 withColor:(id)color;
-- (NSUInteger)_shadowFlags;
-
-@end
-
-@implementation BrowserFrameView
-
-+ (void)load {
- // This is where we swizzle drawRect, and add in two methods that we
- // need. If any of these fail it shouldn't affect the functionality of the
- // others. If they all fail, we will lose window frame theming and
- // roll overs for our close widgets, but things should still function
- // correctly.
- base::mac::ScopedNSAutoreleasePool pool;
- Class grayFrameClass = NSClassFromString(@"NSGrayFrame");
- DCHECK(grayFrameClass);
- if (!grayFrameClass) return;
-
- // Exchange draw rect.
- Method m0 = class_getInstanceMethod([self class], @selector(drawRect:));
- DCHECK(m0);
- if (m0) {
- BOOL didAdd = class_addMethod(grayFrameClass,
- @selector(drawRectOriginal:),
- method_getImplementation(m0),
- method_getTypeEncoding(m0));
- DCHECK(didAdd);
- if (didAdd) {
- Method m1 = class_getInstanceMethod(grayFrameClass, @selector(drawRect:));
- Method m2 = class_getInstanceMethod(grayFrameClass,
- @selector(drawRectOriginal:));
- DCHECK(m1 && m2);
- if (m1 && m2) {
- method_exchangeImplementations(m1, m2);
- }
- }
- }
-
- // Add _mouseInGroup.
- m0 = class_getInstanceMethod([self class], @selector(_mouseInGroup:));
- DCHECK(m0);
- if (m0) {
- BOOL didAdd = class_addMethod(grayFrameClass,
- @selector(_mouseInGroup:),
- method_getImplementation(m0),
- method_getTypeEncoding(m0));
- DCHECK(didAdd);
- }
- // Add updateTrackingArea.
- m0 = class_getInstanceMethod([self class], @selector(updateTrackingAreas));
- DCHECK(m0);
- if (m0) {
- BOOL didAdd = class_addMethod(grayFrameClass,
- @selector(updateTrackingAreas),
- method_getImplementation(m0),
- method_getTypeEncoding(m0));
- DCHECK(didAdd);
- }
-
- gCanDrawTitle =
- [grayFrameClass
- instancesRespondToSelector:@selector(_titlebarTitleRect)] &&
- [grayFrameClass
- instancesRespondToSelector:@selector(_drawTitleStringIn:withColor:)];
- gCanGetCornerRadius =
- [grayFrameClass
- instancesRespondToSelector:@selector(roundedCornerRadius)];
-
- // Add _shadowFlags. This is a method on NSThemeFrame, not on NSGrayFrame.
- // NSThemeFrame is NSGrayFrame's superclass.
- Class themeFrameClass = NSClassFromString(@"NSThemeFrame");
- DCHECK(themeFrameClass);
- if (!themeFrameClass) return;
- m0 = class_getInstanceMethod([self class], @selector(_shadowFlags));
- DCHECK(m0);
- if (m0) {
- BOOL didAdd = class_addMethod(themeFrameClass,
- @selector(_shadowFlagsOriginal),
- method_getImplementation(m0),
- method_getTypeEncoding(m0));
- DCHECK(didAdd);
- if (didAdd) {
- Method m1 = class_getInstanceMethod(themeFrameClass,
- @selector(_shadowFlags));
- Method m2 = class_getInstanceMethod(themeFrameClass,
- @selector(_shadowFlagsOriginal));
- DCHECK(m1 && m2);
- if (m1 && m2) {
- method_exchangeImplementations(m1, m2);
- }
- }
- }
-}
-
-- (id)initWithFrame:(NSRect)frame {
- // This class is not for instantiating.
- [self doesNotRecognizeSelector:_cmd];
- return nil;
-}
-
-- (id)initWithCoder:(NSCoder*)coder {
- // This class is not for instantiating.
- [self doesNotRecognizeSelector:_cmd];
- return nil;
-}
-
-// Here is our custom drawing for our frame.
-- (void)drawRect:(NSRect)rect {
- // If this isn't the window class we expect, then pass it on to the
- // original implementation.
- if (![[self window] isKindOfClass:[FramedBrowserWindow class]]) {
- [self drawRectOriginal:rect];
- return;
- }
-
- // WARNING: There is an obvious optimization opportunity here that you DO NOT
- // want to take. To save painting cycles, you might think it would be a good
- // idea to call out to -drawRectOriginal: only if no theme were drawn. In
- // reality, however, if you fail to call -drawRectOriginal:, or if you call it
- // after a clipping path is set, the rounded corners at the top of the window
- // will not draw properly. Do not try to be smart here.
-
- // Only paint the top of the window.
- NSWindow* window = [self window];
- NSRect windowRect = [self convertRect:[window frame] fromView:nil];
- windowRect.origin = NSMakePoint(0, 0);
-
- NSRect paintRect = windowRect;
- paintRect.origin.y = NSMaxY(paintRect) - kBrowserFrameViewPaintHeight;
- paintRect.size.height = kBrowserFrameViewPaintHeight;
- rect = NSIntersectionRect(paintRect, rect);
- [self drawRectOriginal:rect];
-
- // Set up our clip.
- float cornerRadius = 4.0;
- if (gCanGetCornerRadius)
- cornerRadius = [self roundedCornerRadius];
- [[NSBezierPath bezierPathWithRoundedRect:windowRect
- xRadius:cornerRadius
- yRadius:cornerRadius] addClip];
- [[NSBezierPath bezierPathWithRect:rect] addClip];
-
- // Do the theming.
- BOOL themed = [BrowserFrameView drawWindowThemeInDirtyRect:rect
- forView:self
- bounds:windowRect
- offset:NSZeroPoint
- forceBlackBackground:NO];
-
- // If the window needs a title and we painted over the title as drawn by the
- // default window paint, paint it ourselves.
- if (themed && gCanDrawTitle && ![[self window] _isTitleHidden]) {
- [self _drawTitleStringIn:[self _titlebarTitleRect]
- withColor:[BrowserFrameView titleColorForThemeView:self]];
- }
-
- // Pinstripe the top.
- if (themed) {
- NSSize windowPixel = [self convertSizeFromBase:NSMakeSize(1, 1)];
-
- windowRect = [self convertRect:[window frame] fromView:nil];
- windowRect.origin = NSMakePoint(0, 0);
- windowRect.origin.y -= 0.5 * windowPixel.height;
- windowRect.origin.x -= 0.5 * windowPixel.width;
- windowRect.size.width += windowPixel.width;
- [[NSColor colorWithCalibratedWhite:1.0 alpha:0.5] set];
- NSBezierPath* path = [NSBezierPath bezierPathWithRoundedRect:windowRect
- xRadius:cornerRadius
- yRadius:cornerRadius];
- [path setLineWidth:windowPixel.width];
- [path stroke];
- }
-}
-
-+ (BOOL)drawWindowThemeInDirtyRect:(NSRect)dirtyRect
- forView:(NSView*)view
- bounds:(NSRect)bounds
- offset:(NSPoint)offset
- forceBlackBackground:(BOOL)forceBlackBackground {
- ThemeProvider* themeProvider = [[view window] themeProvider];
- if (!themeProvider)
- return NO;
-
- ThemedWindowStyle windowStyle = [[view window] themedWindowStyle];
-
- // Devtools windows don't get themed.
- if (windowStyle & THEMED_DEVTOOLS)
- return NO;
-
- BOOL active = [[view window] isMainWindow];
- BOOL incognito = windowStyle & THEMED_INCOGNITO;
- BOOL popup = windowStyle & THEMED_POPUP;
-
- // Find a theme image.
- NSColor* themeImageColor = nil;
- int themeImageID;
- if (popup && active)
- themeImageID = IDR_THEME_TOOLBAR;
- else if (popup && !active)
- themeImageID = IDR_THEME_TAB_BACKGROUND;
- else if (!popup && active && incognito)
- themeImageID = IDR_THEME_FRAME_INCOGNITO;
- else if (!popup && active && !incognito)
- themeImageID = IDR_THEME_FRAME;
- else if (!popup && !active && incognito)
- themeImageID = IDR_THEME_FRAME_INCOGNITO_INACTIVE;
- else
- themeImageID = IDR_THEME_FRAME_INACTIVE;
- if (themeProvider->HasCustomImage(IDR_THEME_FRAME))
- themeImageColor = themeProvider->GetNSImageColorNamed(themeImageID, true);
-
- // If no theme image, use a gradient if incognito.
- NSGradient* gradient = nil;
- if (!themeImageColor && incognito)
- gradient = themeProvider->GetNSGradient(
- active ? BrowserThemeProvider::GRADIENT_FRAME_INCOGNITO :
- BrowserThemeProvider::GRADIENT_FRAME_INCOGNITO_INACTIVE);
-
- BOOL themed = NO;
- if (themeImageColor) {
- // The titlebar/tabstrip header on the mac is slightly smaller than on
- // Windows. To keep the window background lined up with the tab and toolbar
- // patterns, we have to shift the pattern slightly, rather than simply
- // drawing it from the top left corner. The offset below was empirically
- // determined in order to line these patterns up.
- //
- // This will make the themes look slightly different than in Windows/Linux
- // because of the differing heights between window top and tab top, but this
- // has been approved by UI.
- NSView* frameView = [[[view window] contentView] superview];
- NSPoint topLeft = NSMakePoint(NSMinX(bounds), NSMaxY(bounds));
- NSPoint topLeftInFrameCoordinates =
- [view convertPoint:topLeft toView:frameView];
-
- NSPoint phase = kBrowserFrameViewPatternPhaseOffset;
- phase.x += (offset.x + topLeftInFrameCoordinates.x);
- phase.y += (offset.y + topLeftInFrameCoordinates.y);
-
- // Align the phase to physical pixels so resizing the window under HiDPI
- // doesn't cause wiggling of the theme.
- phase = [frameView convertPointToBase:phase];
- phase.x = floor(phase.x);
- phase.y = floor(phase.y);
- phase = [frameView convertPointFromBase:phase];
-
- // Default to replacing any existing pixels with the theme image, but if
- // asked paint black first and blend the theme with black.
- NSCompositingOperation operation = NSCompositeCopy;
- if (forceBlackBackground) {
- [[NSColor blackColor] set];
- NSRectFill(dirtyRect);
- operation = NSCompositeSourceOver;
- }
-
- [[NSGraphicsContext currentContext] setPatternPhase:phase];
- [themeImageColor set];
- NSRectFillUsingOperation(dirtyRect, operation);
- themed = YES;
- } else if (gradient) {
- NSPoint startPoint = NSMakePoint(NSMinX(bounds), NSMaxY(bounds));
- NSPoint endPoint = startPoint;
- endPoint.y -= kBrowserFrameViewPaintHeight;
- [gradient drawFromPoint:startPoint toPoint:endPoint options:0];
- themed = YES;
- }
-
- // Check to see if we have an overlay image.
- NSImage* overlayImage = nil;
- if (themeProvider->HasCustomImage(IDR_THEME_FRAME_OVERLAY)) {
- overlayImage = themeProvider->
- GetNSImageNamed(active ? IDR_THEME_FRAME_OVERLAY :
- IDR_THEME_FRAME_OVERLAY_INACTIVE,
- true);
- }
-
- if (overlayImage) {
- // Anchor to top-left and don't scale.
- NSSize overlaySize = [overlayImage size];
- NSRect imageFrame = NSMakeRect(0, 0, overlaySize.width, overlaySize.height);
- [overlayImage drawAtPoint:NSMakePoint(offset.x,
- NSHeight(bounds) + offset.y -
- overlaySize.height)
- fromRect:imageFrame
- operation:NSCompositeSourceOver
- fraction:1.0];
- }
-
- return themed;
-}
-
-+ (NSColor*)titleColorForThemeView:(NSView*)view {
- ThemeProvider* themeProvider = [[view window] themeProvider];
- if (!themeProvider)
- return [NSColor windowFrameTextColor];
-
- ThemedWindowStyle windowStyle = [[view window] themedWindowStyle];
- BOOL active = [[view window] isMainWindow];
- BOOL incognito = windowStyle & THEMED_INCOGNITO;
- BOOL popup = windowStyle & THEMED_POPUP;
-
- NSColor* titleColor = nil;
- if (popup && active) {
- titleColor = themeProvider->GetNSColor(
- BrowserThemeProvider::COLOR_TAB_TEXT, false);
- } else if (popup && !active) {
- titleColor = themeProvider->GetNSColor(
- BrowserThemeProvider::COLOR_BACKGROUND_TAB_TEXT, false);
- }
-
- if (titleColor)
- return titleColor;
-
- if (incognito)
- return [NSColor whiteColor];
- else
- return [NSColor windowFrameTextColor];
-}
-
-// Check to see if the mouse is currently in one of our window widgets.
-- (BOOL)_mouseInGroup:(NSButton*)widget {
- BOOL mouseInGroup = NO;
- if ([[self window] isKindOfClass:[FramedBrowserWindow class]]) {
- FramedBrowserWindow* window =
- static_cast<FramedBrowserWindow*>([self window]);
- mouseInGroup = [window mouseInGroup:widget];
- } else if ([super respondsToSelector:@selector(_mouseInGroup:)]) {
- mouseInGroup = [super _mouseInGroup:widget];
- }
- return mouseInGroup;
-}
-
-// Let our window handle updating the window widget tracking area.
-- (void)updateTrackingAreas {
- [super updateTrackingAreas];
- if ([[self window] isKindOfClass:[FramedBrowserWindow class]]) {
- FramedBrowserWindow* window =
- static_cast<FramedBrowserWindow*>([self window]);
- [window updateTrackingAreas];
- }
-}
-
-// When the compositor is active, the whole content area is transparent (with
-// an OpenGL surface behind it), so Cocoa draws the shadow only around the
-// toolbar area.
-// Tell the window server that we want a shadow as if none of the content
-// area is transparent.
-- (NSUInteger)_shadowFlags {
- // A slightly less intrusive hack would be to call
- // _setContentHasShadow:NO on the window. That seems to be what Terminal.app
- // is doing. However, it leads to this function returning 'code | 64', which
- // doesn't do what we want. For some reason, it does the right thing in
- // Terminal.app.
- // TODO(thakis): Figure out why -_setContentHasShadow: works in Terminal.app
- // and use that technique instead. http://crbug.com/53382
-
- // If this isn't the window class we expect, then pass it on to the
- // original implementation.
- if (![[self window] isKindOfClass:[FramedBrowserWindow class]])
- return [self _shadowFlagsOriginal];
-
- return [self _shadowFlagsOriginal] | 128;
-}
-
-@end
diff --git a/chrome/browser/cocoa/browser_frame_view_unittest.mm b/chrome/browser/cocoa/browser_frame_view_unittest.mm
deleted file mode 100644
index 90d51c7..0000000
--- a/chrome/browser/cocoa/browser_frame_view_unittest.mm
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2009 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 <objc/runtime.h>
-
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/browser_frame_view.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-class BrowserFrameViewTest : public PlatformTest {
- public:
- BrowserFrameViewTest() {
- NSRect frame = NSMakeRect(0, 0, 50, 50);
- // We create NSGrayFrame instead of BrowserFrameView because
- // we are swizzling into NSGrayFrame.
- Class browserFrameClass = NSClassFromString(@"NSGrayFrame");
- view_.reset([[browserFrameClass alloc] initWithFrame:frame]);
- }
-
- scoped_nsobject<NSView> view_;
-};
-
-// Test to make sure our class modifications were successful.
-TEST_F(BrowserFrameViewTest, SuccessfulClassModifications) {
- unsigned int count;
- BOOL foundMouseInGroup = NO;
- BOOL foundDrawRectOriginal = NO;
- BOOL foundUpdateTrackingAreas = NO;
-
- Method* methods = class_copyMethodList([view_ class], &count);
- for (unsigned int i = 0; i < count; ++i) {
- SEL selector = method_getName(methods[i]);
- if (selector == @selector(_mouseInGroup:)) {
- foundMouseInGroup = YES;
- } else if (selector == @selector(drawRectOriginal:)) {
- foundDrawRectOriginal = YES;
- } else if (selector == @selector(updateTrackingAreas)) {
- foundUpdateTrackingAreas = YES;
- }
- }
- EXPECT_TRUE(foundMouseInGroup);
- EXPECT_TRUE(foundDrawRectOriginal);
- EXPECT_TRUE(foundUpdateTrackingAreas);
- free(methods);
-}
diff --git a/chrome/browser/cocoa/browser_test_helper.h b/chrome/browser/cocoa/browser_test_helper.h
deleted file mode 100644
index 22d0efc..0000000
--- a/chrome/browser/cocoa/browser_test_helper.h
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_BROWSER_TEST_HELPER_H_
-#define CHROME_BROWSER_COCOA_BROWSER_TEST_HELPER_H_
-#pragma once
-
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/test/testing_profile.h"
-
-// Base class which contains a valid Browser*. Lots of boilerplate to
-// recycle between unit test classes.
-//
-// This class creates fake UI, file, and IO threads because many objects that
-// are attached to the TestingProfile (and other objects) have traits that limit
-// their destruction to certain threads. For example, the URLRequestContext can
-// only be deleted on the IO thread; without this fake IO thread, the object
-// would never be deleted and would report as a leak under Valgrind. Note that
-// these are fake threads and they all share the same MessageLoop.
-//
-// TODO(jrg): move up a level (chrome/browser/cocoa -->
-// chrome/browser), and use in non-Mac unit tests such as
-// back_forward_menu_model_unittest.cc,
-// navigation_controller_unittest.cc, ..
-class BrowserTestHelper {
- public:
- BrowserTestHelper()
- : ui_thread_(BrowserThread::UI, &message_loop_),
- file_thread_(new BrowserThread(BrowserThread::FILE, &message_loop_)),
- io_thread_(new BrowserThread(BrowserThread::IO, &message_loop_)) {
- profile_.reset(new TestingProfile());
- profile_->CreateBookmarkModel(true);
- profile_->BlockUntilBookmarkModelLoaded();
-
- // TODO(shess): These are needed in case someone creates a browser
- // window off of browser_. pkasting indicates that other
- // platforms use a stub |BrowserWindow| and thus don't need to do
- // this.
- // http://crbug.com/39725
- profile_->CreateAutocompleteClassifier();
- profile_->CreateTemplateURLModel();
-
- browser_.reset(new Browser(Browser::TYPE_NORMAL, profile_.get()));
- }
-
- virtual ~BrowserTestHelper() {
- // Delete the testing profile on the UI thread. But first release the
- // browser, since it may trigger accesses to the profile upon destruction.
- browser_.reset();
-
- // Drop any new tasks for the IO and FILE threads.
- io_thread_.reset();
- file_thread_.reset();
-
- message_loop_.DeleteSoon(FROM_HERE, profile_.release());
- message_loop_.RunAllPending();
- }
-
- virtual TestingProfile* profile() const { return profile_.get(); }
- Browser* browser() const { return browser_.get(); }
-
- // Creates the browser window. To close this window call |CloseBrowserWindow|.
- // Do NOT call close directly on the window.
- BrowserWindow* CreateBrowserWindow() {
- browser_->CreateBrowserWindow();
- return browser_->window();
- }
-
- // Closes the window for this browser. This must only be called after
- // CreateBrowserWindow().
- void CloseBrowserWindow() {
- // Check to make sure a window was actually created.
- DCHECK(browser_->window());
- browser_->CloseAllTabs();
- browser_->CloseWindow();
- // |browser_| will be deleted by its BrowserWindowController.
- ignore_result(browser_.release());
- }
-
- private:
- scoped_ptr<TestingProfile> profile_;
- scoped_ptr<Browser> browser_;
- MessageLoopForUI message_loop_;
- BrowserThread ui_thread_;
- scoped_ptr<BrowserThread> file_thread_;
- scoped_ptr<BrowserThread> io_thread_;
-};
-
-#endif // CHROME_BROWSER_COCOA_BROWSER_TEST_HELPER_H_
diff --git a/chrome/browser/cocoa/browser_window_cocoa.h b/chrome/browser/cocoa/browser_window_cocoa.h
deleted file mode 100644
index bbb3789..0000000
--- a/chrome/browser/cocoa/browser_window_cocoa.h
+++ /dev/null
@@ -1,143 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_BROWSER_WINDOW_COCOA_H_
-#define CHROME_BROWSER_COCOA_BROWSER_WINDOW_COCOA_H_
-#pragma once
-
-#include "base/scoped_nsobject.h"
-#include "base/task.h"
-#include "chrome/browser/browser_window.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#include "chrome/common/notification_registrar.h"
-
-class Browser;
-@class BrowserWindowController;
-@class FindBarCocoaController;
-@class NSEvent;
-@class NSMenu;
-@class NSWindow;
-
-// An implementation of BrowserWindow for Cocoa. Bridges between C++ and
-// the Cocoa NSWindow. Cross-platform code will interact with this object when
-// it needs to manipulate the window.
-
-class BrowserWindowCocoa : public BrowserWindow,
- public NotificationObserver {
- public:
- BrowserWindowCocoa(Browser* browser,
- BrowserWindowController* controller,
- NSWindow* window);
- virtual ~BrowserWindowCocoa();
-
- // Overridden from BrowserWindow
- virtual void Show();
- virtual void SetBounds(const gfx::Rect& bounds);
- virtual void Close();
- virtual void Activate();
- virtual void Deactivate();
- virtual bool IsActive() const;
- virtual void FlashFrame();
- virtual gfx::NativeWindow GetNativeHandle();
- virtual BrowserWindowTesting* GetBrowserWindowTesting();
- virtual StatusBubble* GetStatusBubble();
- virtual void SelectedTabToolbarSizeChanged(bool is_animating);
- virtual void UpdateTitleBar();
- virtual void ShelfVisibilityChanged();
- virtual void UpdateDevTools();
- virtual void UpdateLoadingAnimations(bool should_animate);
- virtual void SetStarredState(bool is_starred);
- virtual gfx::Rect GetRestoredBounds() const;
- virtual bool IsMaximized() const;
- virtual void SetFullscreen(bool fullscreen);
- virtual bool IsFullscreen() const;
- virtual bool IsFullscreenBubbleVisible() const;
- virtual LocationBar* GetLocationBar() const;
- virtual void SetFocusToLocationBar(bool select_all);
- virtual void UpdateReloadStopState(bool is_loading, bool force);
- virtual void UpdateToolbar(TabContentsWrapper* contents,
- bool should_restore_state);
- virtual void FocusToolbar();
- virtual void FocusAppMenu();
- virtual void FocusBookmarksToolbar();
- virtual void FocusChromeOSStatus();
- virtual void RotatePaneFocus(bool forwards);
- virtual bool IsBookmarkBarVisible() const;
- virtual bool IsBookmarkBarAnimating() const;
- virtual bool IsToolbarVisible() const;
- virtual void ConfirmAddSearchProvider(const TemplateURL* template_url,
- Profile* profile);
- virtual void ToggleBookmarkBar();
- virtual views::Window* ShowAboutChromeDialog();
- virtual void ShowUpdateChromeDialog();
- virtual void ShowTaskManager();
- virtual void ShowBookmarkBubble(const GURL& url, bool already_bookmarked);
- virtual bool IsDownloadShelfVisible() const;
- virtual DownloadShelf* GetDownloadShelf();
- virtual void ShowReportBugDialog();
- virtual void ShowClearBrowsingDataDialog();
- virtual void ShowImportDialog();
- virtual void ShowSearchEnginesDialog();
- virtual void ShowPasswordManager();
- virtual void ShowRepostFormWarningDialog(TabContents* tab_contents);
- virtual void ShowContentSettingsWindow(ContentSettingsType content_type,
- Profile* profile);
- virtual void ShowCollectedCookiesDialog(TabContents* tab_contents);
- virtual void ShowProfileErrorDialog(int message_id);
- virtual void ShowThemeInstallBubble();
- virtual void ConfirmBrowserCloseWithPendingDownloads();
- virtual void ShowHTMLDialog(HtmlDialogUIDelegate* delegate,
- gfx::NativeWindow parent_window);
- virtual void UserChangedTheme();
- virtual int GetExtraRenderViewHeight() const;
- virtual void TabContentsFocused(TabContents* tab_contents);
- virtual void ShowPageInfo(Profile* profile,
- const GURL& url,
- const NavigationEntry::SSLStatus& ssl,
- bool show_history);
- virtual void ShowAppMenu();
- virtual bool PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
- bool* is_keyboard_shortcut);
- virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event);
- virtual void ShowCreateWebAppShortcutsDialog(TabContents* tab_contents);
- virtual void ShowCreateChromeAppShortcutsDialog(Profile* profile,
- const Extension* app);
- virtual void Cut();
- virtual void Copy();
- virtual void Paste();
- virtual void ToggleTabStripMode();
- virtual void OpenTabpose();
- virtual void PrepareForInstant();
- virtual void ShowInstant(TabContents* preview_contents);
- virtual void HideInstant(bool instant_is_active);
- virtual gfx::Rect GetInstantBounds();
-
- // Overridden from NotificationObserver
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- // Adds the given FindBar cocoa controller to this browser window.
- void AddFindBar(FindBarCocoaController* find_bar_cocoa_controller);
-
- // Returns the cocoa-world BrowserWindowController
- BrowserWindowController* cocoa_controller() { return controller_; }
-
- protected:
- virtual void DestroyBrowser();
-
- private:
- int GetCommandId(const NativeWebKeyboardEvent& event);
- bool HandleKeyboardEventInternal(NSEvent* event);
- NSWindow* window() const; // Accessor for the (current) |NSWindow|.
- void UpdateSidebarForContents(TabContents* tab_contents);
-
- NotificationRegistrar registrar_;
- Browser* browser_; // weak, owned by controller
- BrowserWindowController* controller_; // weak, owns us
- ScopedRunnableMethodFactory<Browser> confirm_close_factory_;
- scoped_nsobject<NSString> pending_window_title_;
-};
-
-#endif // CHROME_BROWSER_COCOA_BROWSER_WINDOW_COCOA_H_
diff --git a/chrome/browser/cocoa/browser_window_cocoa.mm b/chrome/browser/cocoa/browser_window_cocoa.mm
deleted file mode 100644
index 6bb9607..0000000
--- a/chrome/browser/cocoa/browser_window_cocoa.mm
+++ /dev/null
@@ -1,640 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/browser_window_cocoa.h"
-
-#include "app/l10n_util_mac.h"
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "base/message_loop.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/bookmarks/bookmark_utils.h"
-#import "chrome/browser/cocoa/browser_window_controller.h"
-#import "chrome/browser/cocoa/bug_report_window_controller.h"
-#import "chrome/browser/cocoa/chrome_event_processing_window.h"
-#import "chrome/browser/cocoa/clear_browsing_data_controller.h"
-#import "chrome/browser/cocoa/collected_cookies_mac.h"
-#import "chrome/browser/cocoa/content_settings_dialog_controller.h"
-#import "chrome/browser/cocoa/download/download_shelf_controller.h"
-#import "chrome/browser/cocoa/edit_search_engine_cocoa_controller.h"
-#import "chrome/browser/cocoa/html_dialog_window_controller.h"
-#import "chrome/browser/cocoa/import_settings_dialog.h"
-#import "chrome/browser/cocoa/keyword_editor_cocoa_controller.h"
-#import "chrome/browser/cocoa/location_bar/location_bar_view_mac.h"
-#import "chrome/browser/cocoa/nsmenuitem_additions.h"
-#include "chrome/browser/cocoa/repost_form_warning_mac.h"
-#include "chrome/browser/cocoa/restart_browser.h"
-#include "chrome/browser/cocoa/status_bubble_mac.h"
-#include "chrome/browser/cocoa/task_manager_mac.h"
-#import "chrome/browser/cocoa/theme_install_bubble_view.h"
-#import "chrome/browser/cocoa/toolbar_controller.h"
-#include "chrome/browser/download/download_shelf.h"
-#include "chrome/browser/global_keyboard_shortcuts_mac.h"
-#include "chrome/browser/page_info_window.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/sidebar/sidebar_container.h"
-#include "chrome/browser/sidebar/sidebar_manager.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_list.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/native_web_keyboard_event.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/pref_names.h"
-#include "gfx/rect.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-
-BrowserWindowCocoa::BrowserWindowCocoa(Browser* browser,
- BrowserWindowController* controller,
- NSWindow* window)
- : browser_(browser),
- controller_(controller),
- confirm_close_factory_(browser) {
- // This pref applies to all windows, so all must watch for it.
- registrar_.Add(this, NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED,
- NotificationService::AllSources());
- registrar_.Add(this, NotificationType::SIDEBAR_CHANGED,
- NotificationService::AllSources());
-}
-
-BrowserWindowCocoa::~BrowserWindowCocoa() {
-}
-
-void BrowserWindowCocoa::Show() {
- // The Browser associated with this browser window must become the active
- // browser at the time |Show()| is called. This is the natural behaviour under
- // Windows, but |-makeKeyAndOrderFront:| won't send |-windowDidBecomeMain:|
- // until we return to the runloop. Therefore any calls to
- // |BrowserList::GetLastActive()| (for example, in bookmark_util), will return
- // the previous browser instead if we don't explicitly set it here.
- BrowserList::SetLastActive(browser_);
-
- [window() makeKeyAndOrderFront:controller_];
-}
-
-void BrowserWindowCocoa::SetBounds(const gfx::Rect& bounds) {
- NSRect cocoa_bounds = NSMakeRect(bounds.x(), 0, bounds.width(),
- bounds.height());
- // Flip coordinates based on the primary screen.
- NSScreen* screen = [[NSScreen screens] objectAtIndex:0];
- cocoa_bounds.origin.y =
- [screen frame].size.height - bounds.height() - bounds.y();
-
- [window() setFrame:cocoa_bounds display:YES];
-}
-
-// Callers assume that this doesn't immediately delete the Browser object.
-// The controller implementing the window delegate methods called from
-// |-performClose:| must take precautions to ensure that.
-void BrowserWindowCocoa::Close() {
- // If there is an overlay window, we contain a tab being dragged between
- // windows. Don't hide the window as it makes the UI extra confused. We can
- // still close the window, as that will happen when the drag completes.
- if ([controller_ overlayWindow]) {
- [controller_ deferPerformClose];
- } else {
- // Make sure we hide the window immediately. Even though performClose:
- // calls orderOut: eventually, it leaves the window on-screen long enough
- // that we start to see tabs shutting down. http://crbug.com/23959
- // TODO(viettrungluu): This is kind of bad, since |-performClose:| calls
- // |-windowShouldClose:| (on its delegate, which is probably the
- // controller) which may return |NO| causing the window to not be closed,
- // thereby leaving a hidden window. In fact, our window-closing procedure
- // involves a (indirect) recursion on |-performClose:|, which is also bad.
- [window() orderOut:controller_];
- [window() performClose:controller_];
- }
-}
-
-void BrowserWindowCocoa::Activate() {
- [controller_ activate];
-}
-
-void BrowserWindowCocoa::Deactivate() {
- // TODO(jcivelli): http://crbug.com/51364 Implement me.
- NOTIMPLEMENTED();
-}
-
-void BrowserWindowCocoa::FlashFrame() {
- [NSApp requestUserAttention:NSInformationalRequest];
-}
-
-bool BrowserWindowCocoa::IsActive() const {
- return [window() isKeyWindow];
-}
-
-gfx::NativeWindow BrowserWindowCocoa::GetNativeHandle() {
- return window();
-}
-
-BrowserWindowTesting* BrowserWindowCocoa::GetBrowserWindowTesting() {
- return NULL;
-}
-
-StatusBubble* BrowserWindowCocoa::GetStatusBubble() {
- return [controller_ statusBubble];
-}
-
-void BrowserWindowCocoa::SelectedTabToolbarSizeChanged(bool is_animating) {
- // According to beng, this is an ugly method that comes from the days when the
- // download shelf was a ChromeView attached to the TabContents, and as its
- // size changed via animation it notified through TCD/etc to the browser view
- // to relayout for each tick of the animation. We don't need anything of the
- // sort on Mac.
-}
-
-void BrowserWindowCocoa::UpdateTitleBar() {
- NSString* newTitle =
- base::SysUTF16ToNSString(browser_->GetWindowTitleForCurrentTab());
-
- // Work around Cocoa bug: if a window changes title during the tracking of the
- // Window menu it doesn't display well and the constant re-sorting of the list
- // makes it difficult for the user to pick the desired window. Delay window
- // title updates until the default run-loop mode.
-
- if (pending_window_title_.get())
- [[NSRunLoop currentRunLoop]
- cancelPerformSelector:@selector(setTitle:)
- target:window()
- argument:pending_window_title_.get()];
-
- pending_window_title_.reset([newTitle copy]);
- [[NSRunLoop currentRunLoop]
- performSelector:@selector(setTitle:)
- target:window()
- argument:newTitle
- order:0
- modes:[NSArray arrayWithObject:NSDefaultRunLoopMode]];
-}
-
-void BrowserWindowCocoa::ShelfVisibilityChanged() {
- // Mac doesn't yet support showing the bookmark bar at a different size on
- // the new tab page. When it does, this method should attempt to relayout the
- // bookmark bar/extension shelf as their preferred height may have changed.
- // http://crbug.com/43346
-}
-
-void BrowserWindowCocoa::UpdateDevTools() {
- [controller_ updateDevToolsForContents:
- browser_->GetSelectedTabContents()];
-}
-
-void BrowserWindowCocoa::UpdateLoadingAnimations(bool should_animate) {
- // Do nothing on Mac.
-}
-
-void BrowserWindowCocoa::SetStarredState(bool is_starred) {
- [controller_ setStarredState:is_starred ? YES : NO];
-}
-
-gfx::Rect BrowserWindowCocoa::GetRestoredBounds() const {
- // Flip coordinates based on the primary screen.
- NSScreen* screen = [[NSScreen screens] objectAtIndex:0];
- NSRect frame = [controller_ regularWindowFrame];
- gfx::Rect bounds(frame.origin.x, 0, frame.size.width, frame.size.height);
- bounds.set_y([screen frame].size.height - frame.origin.y - frame.size.height);
- return bounds;
-}
-
-bool BrowserWindowCocoa::IsMaximized() const {
- return [window() isZoomed];
-}
-
-void BrowserWindowCocoa::SetFullscreen(bool fullscreen) {
- [controller_ setFullscreen:fullscreen];
-}
-
-bool BrowserWindowCocoa::IsFullscreen() const {
- return !![controller_ isFullscreen];
-}
-
-bool BrowserWindowCocoa::IsFullscreenBubbleVisible() const {
- return false;
-}
-
-void BrowserWindowCocoa::ConfirmAddSearchProvider(
- const TemplateURL* template_url,
- Profile* profile) {
- // The controller will release itself when the window closes.
- EditSearchEngineCocoaController* editor =
- [[EditSearchEngineCocoaController alloc] initWithProfile:profile
- delegate:NULL
- templateURL:template_url];
- [NSApp beginSheet:[editor window]
- modalForWindow:window()
- modalDelegate:controller_
- didEndSelector:@selector(sheetDidEnd:returnCode:context:)
- contextInfo:NULL];
-}
-
-LocationBar* BrowserWindowCocoa::GetLocationBar() const {
- return [controller_ locationBarBridge];
-}
-
-void BrowserWindowCocoa::SetFocusToLocationBar(bool select_all) {
- [controller_ focusLocationBar:select_all ? YES : NO];
-}
-
-void BrowserWindowCocoa::UpdateReloadStopState(bool is_loading, bool force) {
- [controller_ setIsLoading:is_loading force:force];
-}
-
-void BrowserWindowCocoa::UpdateToolbar(TabContentsWrapper* contents,
- bool should_restore_state) {
- [controller_ updateToolbarWithContents:contents->tab_contents()
- shouldRestoreState:should_restore_state ? YES : NO];
-}
-
-void BrowserWindowCocoa::FocusToolbar() {
- // Not needed on the Mac.
-}
-
-void BrowserWindowCocoa::FocusAppMenu() {
- // Chrome uses the standard Mac OS X menu bar, so this isn't needed.
-}
-
-void BrowserWindowCocoa::RotatePaneFocus(bool forwards) {
- // Not needed on the Mac.
-}
-
-void BrowserWindowCocoa::FocusBookmarksToolbar() {
- // Not needed on the Mac.
-}
-
-void BrowserWindowCocoa::FocusChromeOSStatus() {
- // Not needed on the Mac.
-}
-
-bool BrowserWindowCocoa::IsBookmarkBarVisible() const {
- return browser_->profile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar);
-}
-
-bool BrowserWindowCocoa::IsBookmarkBarAnimating() const {
- return [controller_ isBookmarkBarAnimating];
-}
-
-bool BrowserWindowCocoa::IsToolbarVisible() const {
- return browser_->SupportsWindowFeature(Browser::FEATURE_TOOLBAR) ||
- browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR);
-}
-
-// This is called from Browser, which in turn is called directly from
-// a menu option. All we do here is set a preference. The act of
-// setting the preference sends notifications to all windows who then
-// know what to do.
-void BrowserWindowCocoa::ToggleBookmarkBar() {
- bookmark_utils::ToggleWhenVisible(browser_->profile());
-}
-
-void BrowserWindowCocoa::AddFindBar(
- FindBarCocoaController* find_bar_cocoa_controller) {
- return [controller_ addFindBar:find_bar_cocoa_controller];
-}
-
-views::Window* BrowserWindowCocoa::ShowAboutChromeDialog() {
- NOTIMPLEMENTED();
- return NULL;
-}
-
-void BrowserWindowCocoa::ShowUpdateChromeDialog() {
- restart_browser::RequestRestart(nil);
-}
-
-void BrowserWindowCocoa::ShowTaskManager() {
- TaskManagerMac::Show();
-}
-
-void BrowserWindowCocoa::ShowBookmarkBubble(const GURL& url,
- bool already_bookmarked) {
- [controller_ showBookmarkBubbleForURL:url
- alreadyBookmarked:(already_bookmarked ? YES : NO)];
-}
-
-bool BrowserWindowCocoa::IsDownloadShelfVisible() const {
- return [controller_ isDownloadShelfVisible] != NO;
-}
-
-DownloadShelf* BrowserWindowCocoa::GetDownloadShelf() {
- DownloadShelfController* shelfController = [controller_ downloadShelf];
- return [shelfController bridge];
-}
-
-void BrowserWindowCocoa::ShowReportBugDialog() {
- TabContents* current_tab = browser_->GetSelectedTabContents();
- if (current_tab && current_tab->controller().GetActiveEntry()) {
- browser_->ShowBrokenPageTab(current_tab);
- }
-}
-
-void BrowserWindowCocoa::ShowClearBrowsingDataDialog() {
- [ClearBrowsingDataController
- showClearBrowsingDialogForProfile:browser_->profile()];
-}
-
-void BrowserWindowCocoa::ShowImportDialog() {
- [ImportSettingsDialogController
- showImportSettingsDialogForProfile:browser_->profile()];
-}
-
-void BrowserWindowCocoa::ShowSearchEnginesDialog() {
- [KeywordEditorCocoaController showKeywordEditor:browser_->profile()];
-}
-
-void BrowserWindowCocoa::ShowPasswordManager() {
- NOTIMPLEMENTED();
-}
-
-void BrowserWindowCocoa::ShowRepostFormWarningDialog(
- TabContents* tab_contents) {
- RepostFormWarningMac::Create(GetNativeHandle(), tab_contents);
-}
-
-void BrowserWindowCocoa::ShowContentSettingsWindow(
- ContentSettingsType settings_type,
- Profile* profile) {
- [ContentSettingsDialogController showContentSettingsForType:settings_type
- profile:profile];
-}
-
-void BrowserWindowCocoa::ShowCollectedCookiesDialog(TabContents* tab_contents) {
- // Deletes itself on close.
- new CollectedCookiesMac(GetNativeHandle(), tab_contents);
-}
-
-void BrowserWindowCocoa::ShowProfileErrorDialog(int message_id) {
- scoped_nsobject<NSAlert> alert([[NSAlert alloc] init]);
- [alert addButtonWithTitle:l10n_util::GetNSStringWithFixup(IDS_OK)];
- [alert setMessageText:l10n_util::GetNSStringWithFixup(IDS_PRODUCT_NAME)];
- [alert setInformativeText:l10n_util::GetNSStringWithFixup(message_id)];
- [alert setAlertStyle:NSWarningAlertStyle];
- [alert runModal];
-}
-
-void BrowserWindowCocoa::ShowThemeInstallBubble() {
- ThemeInstallBubbleView::Show(window());
-}
-
-// We allow closing the window here since the real quit decision on Mac is made
-// in [AppController quit:].
-void BrowserWindowCocoa::ConfirmBrowserCloseWithPendingDownloads() {
- // Call InProgressDownloadResponse asynchronously to avoid a crash when the
- // browser window is closed here (http://crbug.com/44454).
- MessageLoop::current()->PostTask(
- FROM_HERE,
- confirm_close_factory_.NewRunnableMethod(
- &Browser::InProgressDownloadResponse,
- true));
-}
-
-void BrowserWindowCocoa::ShowHTMLDialog(HtmlDialogUIDelegate* delegate,
- gfx::NativeWindow parent_window) {
- [HtmlDialogWindowController showHtmlDialog:delegate
- profile:browser_->profile()];
-}
-
-void BrowserWindowCocoa::UserChangedTheme() {
- [controller_ userChangedTheme];
-}
-
-int BrowserWindowCocoa::GetExtraRenderViewHeight() const {
- // Currently this is only used on linux.
- return 0;
-}
-
-void BrowserWindowCocoa::TabContentsFocused(TabContents* tab_contents) {
- NOTIMPLEMENTED();
-}
-
-void BrowserWindowCocoa::ShowPageInfo(Profile* profile,
- const GURL& url,
- const NavigationEntry::SSLStatus& ssl,
- bool show_history) {
- browser::ShowPageInfoBubble(window(), profile, url, ssl, show_history);
-}
-
-void BrowserWindowCocoa::ShowAppMenu() {
- // No-op. Mac doesn't support showing the menus via alt keys.
-}
-
-bool BrowserWindowCocoa::PreHandleKeyboardEvent(
- const NativeWebKeyboardEvent& event, bool* is_keyboard_shortcut) {
- if (event.skip_in_browser || event.type == NativeWebKeyboardEvent::Char)
- return false;
-
- DCHECK(event.os_event != NULL);
- int id = GetCommandId(event);
- if (id == -1)
- return false;
-
- if (browser_->IsReservedCommand(id))
- return HandleKeyboardEventInternal(event.os_event);
-
- DCHECK(is_keyboard_shortcut != NULL);
- *is_keyboard_shortcut = true;
-
- return false;
-}
-
-void BrowserWindowCocoa::HandleKeyboardEvent(
- const NativeWebKeyboardEvent& event) {
- if (event.skip_in_browser || event.type == NativeWebKeyboardEvent::Char)
- return;
-
- DCHECK(event.os_event != NULL);
- HandleKeyboardEventInternal(event.os_event);
-}
-
-@interface MenuWalker : NSObject
-+ (NSMenuItem*)itemForKeyEquivalent:(NSEvent*)key
- menu:(NSMenu*)menu;
-@end
-
-@implementation MenuWalker
-+ (NSMenuItem*)itemForKeyEquivalent:(NSEvent*)key
- menu:(NSMenu*)menu {
- NSMenuItem* result = nil;
-
- for (NSMenuItem *item in [menu itemArray]) {
- NSMenu* submenu = [item submenu];
- if (submenu) {
- if (submenu != [NSApp servicesMenu])
- result = [self itemForKeyEquivalent:key
- menu:submenu];
- } else if ([item cr_firesForKeyEvent:key]) {
- result = item;
- }
-
- if (result)
- break;
- }
-
- return result;
-}
-@end
-
-int BrowserWindowCocoa::GetCommandId(const NativeWebKeyboardEvent& event) {
- if ([event.os_event type] != NSKeyDown)
- return -1;
-
- // Look in menu.
- NSMenuItem* item = [MenuWalker itemForKeyEquivalent:event.os_event
- menu:[NSApp mainMenu]];
-
- if (item && [item action] == @selector(commandDispatch:) && [item tag] > 0)
- return [item tag];
-
- // "Close window" doesn't use the |commandDispatch:| mechanism. Menu items
- // that do not correspond to IDC_ constants need no special treatment however,
- // as they can't be blacklisted in |Browser::IsReservedCommand()| anyhow.
- if (item && [item action] == @selector(performClose:))
- return IDC_CLOSE_WINDOW;
-
- // "Exit" doesn't use the |commandDispatch:| mechanism either.
- if (item && [item action] == @selector(terminate:))
- return IDC_EXIT;
-
- // Look in secondary keyboard shortcuts.
- NSUInteger modifiers = [event.os_event modifierFlags];
- const bool cmdKey = (modifiers & NSCommandKeyMask) != 0;
- const bool shiftKey = (modifiers & NSShiftKeyMask) != 0;
- const bool cntrlKey = (modifiers & NSControlKeyMask) != 0;
- const bool optKey = (modifiers & NSAlternateKeyMask) != 0;
- const int keyCode = [event.os_event keyCode];
- const unichar keyChar = KeyCharacterForEvent(event.os_event);
-
- int cmdNum = CommandForWindowKeyboardShortcut(
- cmdKey, shiftKey, cntrlKey, optKey, keyCode, keyChar);
- if (cmdNum != -1)
- return cmdNum;
-
- cmdNum = CommandForBrowserKeyboardShortcut(
- cmdKey, shiftKey, cntrlKey, optKey, keyCode, keyChar);
- if (cmdNum != -1)
- return cmdNum;
-
- return -1;
-}
-
-bool BrowserWindowCocoa::HandleKeyboardEventInternal(NSEvent* event) {
- ChromeEventProcessingWindow* event_window =
- static_cast<ChromeEventProcessingWindow*>(window());
- DCHECK([event_window isKindOfClass:[ChromeEventProcessingWindow class]]);
-
- // Do not fire shortcuts on key up.
- if ([event type] == NSKeyDown) {
- // Send the event to the menu before sending it to the browser/window
- // shortcut handling, so that if a user configures cmd-left to mean
- // "previous tab", it takes precedence over the built-in "history back"
- // binding. Other than that, the |-redispatchKeyEvent:| call would take care
- // of invoking the original menu item shortcut as well.
-
- if ([[NSApp mainMenu] performKeyEquivalent:event])
- return true;
-
- if ([event_window handleExtraBrowserKeyboardShortcut:event])
- return true;
-
- if ([event_window handleExtraWindowKeyboardShortcut:event])
- return true;
-
- if ([event_window handleDelayedWindowKeyboardShortcut:event])
- return true;
- }
-
- return [event_window redispatchKeyEvent:event];
-}
-
-void BrowserWindowCocoa::ShowCreateWebAppShortcutsDialog(
- TabContents* tab_contents) {
- NOTIMPLEMENTED();
-}
-
-void BrowserWindowCocoa::ShowCreateChromeAppShortcutsDialog(
- Profile* profile, const Extension* app) {
- NOTIMPLEMENTED();
-}
-
-void BrowserWindowCocoa::Cut() {
- [NSApp sendAction:@selector(cut:) to:nil from:nil];
-}
-
-void BrowserWindowCocoa::Copy() {
- [NSApp sendAction:@selector(copy:) to:nil from:nil];
-}
-
-void BrowserWindowCocoa::Paste() {
- [NSApp sendAction:@selector(paste:) to:nil from:nil];
-}
-
-void BrowserWindowCocoa::ToggleTabStripMode() {
- [controller_ toggleTabStripDisplayMode];
-}
-
-void BrowserWindowCocoa::OpenTabpose() {
- [controller_ openTabpose];
-}
-
-void BrowserWindowCocoa::PrepareForInstant() {
- // TODO: implement fade as done on windows.
-}
-
-void BrowserWindowCocoa::ShowInstant(TabContents* preview_contents) {
- [controller_ showInstant:preview_contents];
-}
-
-void BrowserWindowCocoa::HideInstant(bool instant_is_active) {
- [controller_ hideInstant];
-
- // TODO: add support for |instant_is_active|.
-}
-
-gfx::Rect BrowserWindowCocoa::GetInstantBounds() {
- // Flip coordinates based on the primary screen.
- NSScreen* screen = [[NSScreen screens] objectAtIndex:0];
- NSRect monitorFrame = [screen frame];
- NSRect frame = [controller_ instantFrame];
- gfx::Rect bounds(NSRectToCGRect(frame));
- bounds.set_y(NSHeight(monitorFrame) - bounds.y() - bounds.height());
- return bounds;
-}
-
-void BrowserWindowCocoa::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- switch (type.value) {
- // Only the key window gets a direct toggle from the menu.
- // Other windows hear about it from the notification.
- case NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED:
- [controller_ updateBookmarkBarVisibilityWithAnimation:YES];
- break;
- case NotificationType::SIDEBAR_CHANGED:
- UpdateSidebarForContents(
- Details<SidebarContainer>(details)->tab_contents());
- break;
- default:
- NOTREACHED(); // we don't ask for anything else!
- break;
- }
-}
-
-void BrowserWindowCocoa::DestroyBrowser() {
- [controller_ destroyBrowser];
-
- // at this point the controller is dead (autoreleased), so
- // make sure we don't try to reference it any more.
-}
-
-NSWindow* BrowserWindowCocoa::window() const {
- return [controller_ window];
-}
-
-void BrowserWindowCocoa::UpdateSidebarForContents(TabContents* tab_contents) {
- if (tab_contents == browser_->GetSelectedTabContents()) {
- [controller_ updateSidebarForContents:tab_contents];
- }
-}
diff --git a/chrome/browser/cocoa/browser_window_cocoa_unittest.mm b/chrome/browser/cocoa/browser_window_cocoa_unittest.mm
deleted file mode 100644
index 2512d3b..0000000
--- a/chrome/browser/cocoa/browser_window_cocoa_unittest.mm
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright (c) 2009 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/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-#include "base/string_util.h"
-#include "chrome/browser/bookmarks/bookmark_utils.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#include "chrome/browser/cocoa/browser_window_cocoa.h"
-#include "chrome/browser/cocoa/browser_window_controller.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/common/notification_type.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-// A BrowserWindowCocoa that goes PONG when
-// BOOKMARK_BAR_VISIBILITY_PREF_CHANGED is sent. This is so we can be
-// sure we are observing it.
-class BrowserWindowCocoaPong : public BrowserWindowCocoa {
- public:
- BrowserWindowCocoaPong(Browser* browser,
- BrowserWindowController* controller) :
- BrowserWindowCocoa(browser, controller, [controller window]) {
- pong_ = false;
- }
- virtual ~BrowserWindowCocoaPong() { }
-
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- if (type.value == NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED)
- pong_ = true;
- BrowserWindowCocoa::Observe(type, source, details);
- }
-
- bool pong_;
-};
-
-// Main test class.
-class BrowserWindowCocoaTest : public CocoaTest {
- virtual void SetUp() {
- CocoaTest::SetUp();
- Browser* browser = browser_helper_.browser();
- controller_ = [[BrowserWindowController alloc] initWithBrowser:browser
- takeOwnership:NO];
- }
-
- virtual void TearDown() {
- [controller_ close];
- CocoaTest::TearDown();
- }
-
- public:
- BrowserTestHelper browser_helper_;
- BrowserWindowController* controller_;
-};
-
-
-TEST_F(BrowserWindowCocoaTest, TestNotification) {
- BrowserWindowCocoaPong *bwc =
- new BrowserWindowCocoaPong(browser_helper_.browser(), controller_);
-
- EXPECT_FALSE(bwc->pong_);
- bookmark_utils::ToggleWhenVisible(browser_helper_.profile());
- // Confirm we are listening
- EXPECT_TRUE(bwc->pong_);
- delete bwc;
- // If this does NOT crash it confirms we stopped listening in the destructor.
- bookmark_utils::ToggleWhenVisible(browser_helper_.profile());
-}
-
-
-TEST_F(BrowserWindowCocoaTest, TestBookmarkBarVisible) {
- BrowserWindowCocoaPong *bwc = new BrowserWindowCocoaPong(
- browser_helper_.browser(),
- controller_);
- scoped_ptr<BrowserWindowCocoaPong> scoped_bwc(bwc);
-
- bool before = bwc->IsBookmarkBarVisible();
- bookmark_utils::ToggleWhenVisible(browser_helper_.profile());
- EXPECT_NE(before, bwc->IsBookmarkBarVisible());
-
- bookmark_utils::ToggleWhenVisible(browser_helper_.profile());
- EXPECT_EQ(before, bwc->IsBookmarkBarVisible());
-}
-
-@interface FakeController : NSWindowController {
- BOOL fullscreen_;
-}
-@end
-
-@implementation FakeController
-- (void)setFullscreen:(BOOL)fullscreen {
- fullscreen_ = fullscreen;
-}
-- (BOOL)isFullscreen {
- return fullscreen_;
-}
-@end
-
-TEST_F(BrowserWindowCocoaTest, TestFullscreen) {
- // Wrap the FakeController in a scoped_nsobject instead of autoreleasing in
- // windowWillClose: because we never actually open a window in this test (so
- // windowWillClose: never gets called).
- scoped_nsobject<FakeController> fake_controller(
- [[FakeController alloc] init]);
- BrowserWindowCocoaPong *bwc = new BrowserWindowCocoaPong(
- browser_helper_.browser(),
- (BrowserWindowController*)fake_controller.get());
- scoped_ptr<BrowserWindowCocoaPong> scoped_bwc(bwc);
-
- EXPECT_FALSE(bwc->IsFullscreen());
- bwc->SetFullscreen(true);
- EXPECT_TRUE(bwc->IsFullscreen());
- bwc->SetFullscreen(false);
- EXPECT_FALSE(bwc->IsFullscreen());
- [fake_controller close];
-}
-
-// TODO(???): test other methods of BrowserWindowCocoa
diff --git a/chrome/browser/cocoa/browser_window_controller.h b/chrome/browser/cocoa/browser_window_controller.h
deleted file mode 100644
index fae4f2b..0000000
--- a/chrome/browser/cocoa/browser_window_controller.h
+++ /dev/null
@@ -1,397 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_BROWSER_WINDOW_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_BROWSER_WINDOW_CONTROLLER_H_
-#pragma once
-
-// A class acting as the Objective-C controller for the Browser
-// object. Handles interactions between Cocoa and the cross-platform
-// code. Each window has a single toolbar and, by virtue of being a
-// TabWindowController, a tab strip along the top.
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_controller.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bubble_controller.h"
-#import "chrome/browser/cocoa/browser_command_executor.h"
-#import "chrome/browser/cocoa/tab_contents_controller.h"
-#import "chrome/browser/cocoa/tab_strip_controller.h"
-#import "chrome/browser/cocoa/tab_window_controller.h"
-#import "chrome/browser/cocoa/themed_window.h"
-#import "chrome/browser/cocoa/url_drop_target.h"
-#import "chrome/browser/cocoa/view_resizer.h"
-#include "chrome/browser/sync/sync_ui_util.h"
-
-
-class Browser;
-class BrowserWindow;
-class BrowserWindowCocoa;
-class ConstrainedWindowMac;
-@class DevToolsController;
-@class DownloadShelfController;
-@class FindBarCocoaController;
-@class FullscreenController;
-@class GTMWindowSheetController;
-@class IncognitoImageView;
-@class InfoBarContainerController;
-class LocationBarViewMac;
-@class PreviewableContentsController;
-@class SidebarController;
-class StatusBubbleMac;
-class TabContents;
-@class TabStripController;
-@class TabStripView;
-@class ToolbarController;
-
-
-@interface BrowserWindowController :
- TabWindowController<NSUserInterfaceValidations,
- BookmarkBarControllerDelegate,
- BrowserCommandExecutor,
- ViewResizer,
- TabContentsControllerDelegate,
- TabStripControllerDelegate> {
- @private
- // The ordering of these members is important as it determines the order in
- // which they are destroyed. |browser_| needs to be destroyed last as most of
- // the other objects hold weak references to it or things it owns
- // (tab/toolbar/bookmark models, profiles, etc).
- scoped_ptr<Browser> browser_;
- NSWindow* savedRegularWindow_;
- scoped_ptr<BrowserWindowCocoa> windowShim_;
- scoped_nsobject<ToolbarController> toolbarController_;
- scoped_nsobject<TabStripController> tabStripController_;
- scoped_nsobject<FindBarCocoaController> findBarCocoaController_;
- scoped_nsobject<InfoBarContainerController> infoBarContainerController_;
- scoped_nsobject<DownloadShelfController> downloadShelfController_;
- scoped_nsobject<BookmarkBarController> bookmarkBarController_;
- scoped_nsobject<DevToolsController> devToolsController_;
- scoped_nsobject<SidebarController> sidebarController_;
- scoped_nsobject<PreviewableContentsController> previewableContentsController_;
- scoped_nsobject<FullscreenController> fullscreenController_;
-
- // Strong. StatusBubble is a special case of a strong reference that
- // we don't wrap in a scoped_ptr because it is acting the same
- // as an NSWindowController in that it wraps a window that must
- // be shut down before our destructors are called.
- StatusBubbleMac* statusBubble_;
-
- BookmarkBubbleController* bookmarkBubbleController_; // Weak.
- BOOL initializing_; // YES while we are currently in initWithBrowser:
- BOOL ownsBrowser_; // Only ever NO when testing
-
- // The total amount by which we've grown the window up or down (to display a
- // bookmark bar and/or download shelf), respectively; reset to 0 when moved
- // away from the bottom/top or resized (or zoomed).
- CGFloat windowTopGrowth_;
- CGFloat windowBottomGrowth_;
-
- // YES only if we're shrinking the window from an apparent zoomed state (which
- // we'll only do if we grew it to the zoomed state); needed since we'll then
- // restrict the amount of shrinking by the amounts specified above. Reset to
- // NO on growth.
- BOOL isShrinkingFromZoomed_;
-
- // The raw accumulated zoom value and the actual zoom increments made for an
- // an in-progress pinch gesture.
- CGFloat totalMagnifyGestureAmount_;
- NSInteger currentZoomStepDelta_;
-
- // The view which shows the incognito badge (NULL if not an incognito window).
- // Needed to access the view to move it to/from the fullscreen window.
- scoped_nsobject<IncognitoImageView> incognitoBadge_;
-
- // Lazily created view which draws the background for the floating set of bars
- // in fullscreen mode (for window types having a floating bar; it remains nil
- // for those which don't).
- scoped_nsobject<NSView> floatingBarBackingView_;
-
- // Tracks whether the floating bar is above or below the bookmark bar, in
- // terms of z-order.
- BOOL floatingBarAboveBookmarkBar_;
-
- // The proportion of the floating bar which is shown (in fullscreen mode).
- CGFloat floatingBarShownFraction_;
-
- // Various UI elements/events may want to ensure that the floating bar is
- // visible (in fullscreen mode), e.g., because of where the mouse is or where
- // keyboard focus is. Whenever an object requires bar visibility, it has
- // itself added to |barVisibilityLocks_|. When it no longer requires bar
- // visibility, it has itself removed.
- scoped_nsobject<NSMutableSet> barVisibilityLocks_;
-
- // Bar visibility locks and releases only result (when appropriate) in changes
- // in visible state when the following is |YES|.
- BOOL barVisibilityUpdatesEnabled_;
-}
-
-// A convenience class method which gets the |BrowserWindowController| for a
-// given window. This method returns nil if no window in the chain has a BWC.
-+ (BrowserWindowController*)browserWindowControllerForWindow:(NSWindow*)window;
-
-// A convenience class method which gets the |BrowserWindowController| for a
-// given view. This is the controller for the window containing |view|, if it
-// is a BWC, or the first controller in the parent-window chain that is a
-// BWC. This method returns nil if no window in the chain has a BWC.
-+ (BrowserWindowController*)browserWindowControllerForView:(NSView*)view;
-
-// Load the browser window nib and do any Cocoa-specific initialization.
-// Takes ownership of |browser|.
-- (id)initWithBrowser:(Browser*)browser;
-
-// Call to make the browser go away from other places in the cross-platform
-// code.
-- (void)destroyBrowser;
-
-// Access the C++ bridge between the NSWindow and the rest of Chromium.
-- (BrowserWindow*)browserWindow;
-
-// Return a weak pointer to the toolbar controller.
-- (ToolbarController*)toolbarController;
-
-// Return a weak pointer to the tab strip controller.
-- (TabStripController*)tabStripController;
-
-// Access the C++ bridge object representing the status bubble for the window.
-- (StatusBubbleMac*)statusBubble;
-
-// Access the C++ bridge object representing the location bar.
-- (LocationBarViewMac*)locationBarBridge;
-
-// Updates the toolbar (and transitively the location bar) with the states of
-// the specified |tab|. If |shouldRestore| is true, we're switching
-// (back?) to this tab and should restore any previous location bar state
-// (such as user editing) as well.
-- (void)updateToolbarWithContents:(TabContents*)tab
- shouldRestoreState:(BOOL)shouldRestore;
-
-// Sets whether or not the current page in the frontmost tab is bookmarked.
-- (void)setStarredState:(BOOL)isStarred;
-
-// Called to tell the selected tab to update its loading state.
-// |force| is set if the update is due to changing tabs, as opposed to
-// the page-load finishing. See comment in reload_button.h.
-- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force;
-
-// Brings this controller's window to the front.
-- (void)activate;
-
-// Make the location bar the first responder, if possible.
-- (void)focusLocationBar:(BOOL)selectAll;
-
-// Make the (currently-selected) tab contents the first responder, if possible.
-- (void)focusTabContents;
-
-// Returns the frame of the regular (non-fullscreened) window (even if the
-// window is currently in fullscreen mode). The frame is returned in Cocoa
-// coordinates (origin in bottom-left).
-- (NSRect)regularWindowFrame;
-
-- (BOOL)isBookmarkBarVisible;
-
-// Returns YES if the bookmark bar is currently animating.
-- (BOOL)isBookmarkBarAnimating;
-
-// Called after bookmark bar visibility changes (due to pref change or change in
-// tab/tab contents).
-- (void)updateBookmarkBarVisibilityWithAnimation:(BOOL)animate;
-
-- (BOOL)isDownloadShelfVisible;
-
-// Lazily creates the download shelf in visible state if it doesn't exist yet.
-- (DownloadShelfController*)downloadShelf;
-
-// Retains the given FindBarCocoaController and adds its view to this
-// browser window. Must only be called once per
-// BrowserWindowController.
-- (void)addFindBar:(FindBarCocoaController*)findBarCocoaController;
-
-// The user changed the theme.
-- (void)userChangedTheme;
-
-// Executes the command in the context of the current browser.
-// |command| is an integer value containing one of the constants defined in the
-// "chrome/app/chrome_command_ids.h" file.
-- (void)executeCommand:(int)command;
-
-// Delegate method for the status bubble to query its base frame.
-- (NSRect)statusBubbleBaseFrame;
-
-// Show the bookmark bubble (e.g. user just clicked on the STAR)
-- (void)showBookmarkBubbleForURL:(const GURL&)url
- alreadyBookmarked:(BOOL)alreadyBookmarked;
-
-// Returns the (lazily created) window sheet controller of this window. Used
-// for the per-tab sheets.
-- (GTMWindowSheetController*)sheetController;
-
-// Requests that |window| is opened as a per-tab sheet to the current tab.
-- (void)attachConstrainedWindow:(ConstrainedWindowMac*)window;
-// Closes the tab sheet |window| and potentially shows the next sheet in the
-// tab's sheet queue.
-- (void)removeConstrainedWindow:(ConstrainedWindowMac*)window;
-// Returns NO if constrained windows cannot be attached to this window.
-- (BOOL)canAttachConstrainedWindow;
-
-// Shows or hides the docked web inspector depending on |contents|'s state.
-- (void)updateDevToolsForContents:(TabContents*)contents;
-
-// Displays the active sidebar linked to the |contents| or hides sidebar UI,
-// if there's no such sidebar.
-- (void)updateSidebarForContents:(TabContents*)contents;
-
-// Gets the current theme provider.
-- (ThemeProvider*)themeProvider;
-
-// Gets the window style.
-- (ThemedWindowStyle)themedWindowStyle;
-
-// Gets the pattern phase for the window.
-- (NSPoint)themePatternPhase;
-
-// Return the point to which a bubble window's arrow should point.
-- (NSPoint)bookmarkBubblePoint;
-
-// Call when the user changes the tab strip display mode, enabling or
-// disabling vertical tabs for this browser. Re-flows the contents of the
-// browser.
-- (void)toggleTabStripDisplayMode;
-
-// Shows or hides the Instant preview contents.
-- (void)showInstant:(TabContents*)previewContents;
-- (void)hideInstant;
-
-// Returns the frame, in Cocoa (unflipped) screen coordinates, of the area where
-// Instant results are. If Instant is not showing, returns the frame of where
-// it would be.
-- (NSRect)instantFrame;
-
-// Called when the Add Search Engine dialog is closed.
-- (void)sheetDidEnd:(NSWindow*)sheet
- returnCode:(NSInteger)code
- context:(void*)context;
-
-@end // @interface BrowserWindowController
-
-
-// Methods having to do with the window type (normal/popup/app, and whether the
-// window has various features; fullscreen methods are separate).
-@interface BrowserWindowController(WindowType)
-
-// Determines whether this controller's window supports a given feature (i.e.,
-// whether a given feature is or can be shown in the window).
-// TODO(viettrungluu): |feature| is really should be |Browser::Feature|, but I
-// don't want to include browser.h (and you can't forward declare enums).
-- (BOOL)supportsWindowFeature:(int)feature;
-
-// Called to check whether or not this window has a normal title bar (YES if it
-// does, NO otherwise). (E.g., normal browser windows do not, pop-ups do.)
-- (BOOL)hasTitleBar;
-
-// Called to check whether or not this window has a toolbar (YES if it does, NO
-// otherwise). (E.g., normal browser windows do, pop-ups do not.)
-- (BOOL)hasToolbar;
-
-// Called to check whether or not this window has a location bar (YES if it
-// does, NO otherwise). (E.g., normal browser windows do, pop-ups may or may
-// not.)
-- (BOOL)hasLocationBar;
-
-// Called to check whether or not this window can have bookmark bar (YES if it
-// does, NO otherwise). (E.g., normal browser windows may, pop-ups may not.)
-- (BOOL)supportsBookmarkBar;
-
-// Called to check if this controller's window is a normal window (e.g., not a
-// pop-up window). Returns YES if it is, NO otherwise.
-// Note: The |-has...| methods are usually preferred, so this method is largely
-// deprecated.
-- (BOOL)isNormalWindow;
-
-@end // @interface BrowserWindowController(WindowType)
-
-
-// Methods having to do with fullscreen mode.
-@interface BrowserWindowController(Fullscreen)
-
-// Enters (or exits) fullscreen mode.
-- (void)setFullscreen:(BOOL)fullscreen;
-
-// Returns fullscreen state.
-- (BOOL)isFullscreen;
-
-// Resizes the fullscreen window to fit the screen it's currently on. Called by
-// the FullscreenController when there is a change in monitor placement or
-// resolution.
-- (void)resizeFullscreenWindow;
-
-// Gets or sets the fraction of the floating bar (fullscreen overlay) that is
-// shown. 0 is completely hidden, 1 is fully shown.
-- (CGFloat)floatingBarShownFraction;
-- (void)setFloatingBarShownFraction:(CGFloat)fraction;
-
-// Query/lock/release the requirement that the tab strip/toolbar/attached
-// bookmark bar bar cluster is visible (e.g., when one of its elements has
-// focus). This is required for the floating bar in fullscreen mode, but should
-// also be called when not in fullscreen mode; see the comments for
-// |barVisibilityLocks_| for more details. Double locks/releases by the same
-// owner are ignored. If |animate:| is YES, then an animation may be performed,
-// possibly after a small delay if |delay:| is YES. If |animate:| is NO,
-// |delay:| will be ignored. In the case of multiple calls, later calls have
-// precedence with the rule that |animate:NO| has precedence over |animate:YES|,
-// and |delay:NO| has precedence over |delay:YES|.
-- (BOOL)isBarVisibilityLockedForOwner:(id)owner;
-- (void)lockBarVisibilityForOwner:(id)owner
- withAnimation:(BOOL)animate
- delay:(BOOL)delay;
-- (void)releaseBarVisibilityForOwner:(id)owner
- withAnimation:(BOOL)animate
- delay:(BOOL)delay;
-
-// Returns YES if any of the views in the floating bar currently has focus.
-- (BOOL)floatingBarHasFocus;
-
-// Opens the tabpose window.
-- (void)openTabpose;
-
-@end // @interface BrowserWindowController(Fullscreen)
-
-
-// Methods which are either only for testing, or only public for testing.
-@interface BrowserWindowController(TestingAPI)
-
-// Put the incognito badge on the browser and adjust the tab strip
-// accordingly.
-- (void)installIncognitoBadge;
-
-// Allows us to initWithBrowser withOUT taking ownership of the browser.
-- (id)initWithBrowser:(Browser*)browser takeOwnership:(BOOL)ownIt;
-
-// Adjusts the window height by the given amount. If the window spans from the
-// top of the current workspace to the bottom of the current workspace, the
-// height is not adjusted. If growing the window by the requested amount would
-// size the window to be taller than the current workspace, the window height is
-// capped to be equal to the height of the current workspace. If the window is
-// partially offscreen, its height is not adjusted at all. This function
-// prefers to grow the window down, but will grow up if needed. Calls to this
-// function should be followed by a call to |layoutSubviews|.
-- (void)adjustWindowHeightBy:(CGFloat)deltaH;
-
-// Return an autoreleased NSWindow suitable for fullscreen use.
-- (NSWindow*)createFullscreenWindow;
-
-// Resets any saved state about window growth (due to showing the bookmark bar
-// or the download shelf), so that future shrinking will occur from the bottom.
-- (void)resetWindowGrowthState;
-
-// Computes by how far in each direction, horizontal and vertical, the
-// |source| rect doesn't fit into |target|.
-- (NSSize)overflowFrom:(NSRect)source
- to:(NSRect)target;
-@end // @interface BrowserWindowController(TestingAPI)
-
-
-#endif // CHROME_BROWSER_COCOA_BROWSER_WINDOW_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/browser_window_controller.mm b/chrome/browser/cocoa/browser_window_controller.mm
deleted file mode 100644
index 3face17..0000000
--- a/chrome/browser/cocoa/browser_window_controller.mm
+++ /dev/null
@@ -1,2059 +0,0 @@
-// 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 "chrome/browser/cocoa/browser_window_controller.h"
-
-#include <Carbon/Carbon.h>
-
-#include "app/l10n_util.h"
-#include "app/l10n_util_mac.h"
-#include "base/mac_util.h"
-#include "app/mac/scoped_nsdisable_screen_updates.h"
-#include "base/nsimage_cache_mac.h"
-#import "base/scoped_nsobject.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/app/chrome_command_ids.h" // IDC_*
-#include "chrome/browser/bookmarks/bookmark_editor.h"
-#import "chrome/browser/cocoa/background_gradient_view.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_controller.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_editor_controller.h"
-#import "chrome/browser/cocoa/browser_window_cocoa.h"
-#import "chrome/browser/cocoa/browser_window_controller_private.h"
-#import "chrome/browser/cocoa/dev_tools_controller.h"
-#import "chrome/browser/cocoa/download/download_shelf_controller.h"
-#import "chrome/browser/cocoa/event_utils.h"
-#import "chrome/browser/cocoa/fast_resize_view.h"
-#import "chrome/browser/cocoa/find_bar_bridge.h"
-#import "chrome/browser/cocoa/find_bar_cocoa_controller.h"
-#import "chrome/browser/cocoa/focus_tracker.h"
-#import "chrome/browser/cocoa/fullscreen_controller.h"
-#import "chrome/browser/cocoa/fullscreen_window.h"
-#import "chrome/browser/cocoa/infobar_container_controller.h"
-#import "chrome/browser/cocoa/location_bar/autocomplete_text_field_editor.h"
-#import "chrome/browser/cocoa/previewable_contents_controller.h"
-#import "chrome/browser/cocoa/nswindow_additions.h"
-#import "chrome/browser/cocoa/sad_tab_controller.h"
-#import "chrome/browser/cocoa/sidebar_controller.h"
-#import "chrome/browser/cocoa/status_bubble_mac.h"
-#import "chrome/browser/cocoa/tab_contents_controller.h"
-#import "chrome/browser/cocoa/tab_strip_controller.h"
-#import "chrome/browser/cocoa/tab_strip_view.h"
-#import "chrome/browser/cocoa/tab_view.h"
-#import "chrome/browser/cocoa/tabpose_window.h"
-#import "chrome/browser/cocoa/toolbar_controller.h"
-#include "chrome/browser/dock_info.h"
-#include "chrome/browser/encoding_menu_controller.h"
-#include "chrome/browser/google/google_util.h"
-#include "chrome/browser/location_bar.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/renderer_host/render_widget_host_view.h"
-#include "chrome/browser/sync/profile_sync_service.h"
-#include "chrome/browser/sync/sync_ui_util_mac.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents/tab_contents_view_mac.h"
-#include "chrome/browser/tab_contents_wrapper.h"
-#include "chrome/browser/tabs/tab_strip_model.h"
-#include "chrome/browser/themes/browser_theme_provider.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_list.h"
-#include "chrome/browser/window_sizer.h"
-#include "chrome/common/url_constants.h"
-#include "grit/generated_resources.h"
-#include "grit/locale_settings.h"
-
-// ORGANIZATION: This is a big file. It is (in principle) organized as follows
-// (in order):
-// 1. Interfaces. Very short, one-time-use classes may include an implementation
-// immediately after their interface.
-// 2. The general implementation section, ordered as follows:
-// i. Public methods and overrides.
-// ii. Overrides/implementations of undocumented methods.
-// iii. Delegate methods for various protocols, formal and informal, to which
-// |BrowserWindowController| conforms.
-// 3. (temporary) Implementation sections for various categories.
-//
-// Private methods are defined and implemented separately in
-// browser_window_controller_private.{h,mm}.
-//
-// Not all of the above guidelines are followed and more (re-)organization is
-// needed. BUT PLEASE TRY TO KEEP THIS FILE ORGANIZED. I'd rather re-organize as
-// little as possible, since doing so messes up the file's history.
-//
-// TODO(viettrungluu): [crbug.com/35543] on-going re-organization, splitting
-// things into multiple files -- the plan is as follows:
-// - in general, everything stays in browser_window_controller.h, but is split
-// off into categories (see below)
-// - core stuff stays in browser_window_controller.mm
-// - ... overrides also stay (without going into a category, in particular)
-// - private stuff which everyone needs goes into
-// browser_window_controller_private.{h,mm}; if no one else needs them, they
-// can go in individual files (see below)
-// - area/task-specific stuff go in browser_window_controller_<area>.mm
-// - ... in categories called "(<Area>)" or "(<PrivateArea>)"
-// Plan of action:
-// - first re-organize into categories
-// - then split into files
-
-// Notes on self-inflicted (not user-inflicted) window resizing and moving:
-//
-// When the bookmark bar goes from hidden to shown (on a non-NTP) page, or when
-// the download shelf goes from hidden to shown, we grow the window downwards in
-// order to maintain a constant content area size. When either goes from shown
-// to hidden, we consequently shrink the window from the bottom, also to keep
-// the content area size constant. To keep things simple, if the window is not
-// entirely on-screen, we don't grow/shrink the window.
-//
-// The complications come in when there isn't enough room (on screen) below the
-// window to accomodate the growth. In this case, we grow the window first
-// downwards, and then upwards. So, when it comes to shrinking, we do the
-// opposite: shrink from the top by the amount by which we grew at the top, and
-// then from the bottom -- unless the user moved/resized/zoomed the window, in
-// which case we "reset state" and just shrink from the bottom.
-//
-// A further complication arises due to the way in which "zoom" ("maximize")
-// works on Mac OS X. Basically, for our purposes, a window is "zoomed" whenever
-// it occupies the full available vertical space. (Note that the green zoom
-// button does not track zoom/unzoomed state per se, but basically relies on
-// this heuristic.) We don't, in general, want to shrink the window if the
-// window is zoomed (scenario: window is zoomed, download shelf opens -- which
-// doesn't cause window growth, download shelf closes -- shouldn't cause the
-// window to become unzoomed!). However, if we grew the window
-// (upwards/downwards) to become zoomed in the first place, we *should* shrink
-// the window by the amounts by which we grew (scenario: window occupies *most*
-// of vertical space, download shelf opens causing growth so that window
-// occupies all of vertical space -- i.e., window is effectively zoomed,
-// download shelf closes -- should return the window to its previous state).
-//
-// A major complication is caused by the way grows/shrinks are handled and
-// animated. Basically, the BWC doesn't see the global picture, but it sees
-// grows and shrinks in small increments (as dictated by the animation). Thus
-// window growth/shrinkage (at the top/bottom) have to be tracked incrementally.
-// Allowing shrinking from the zoomed state also requires tracking: We check on
-// any shrink whether we're both zoomed and have previously grown -- if so, we
-// set a flag, and constrain any resize by the allowed amounts. On further
-// shrinks, we check the flag (since the size/position of the window will no
-// longer indicate that the window is shrinking from an apparent zoomed state)
-// and if it's set we continue to constrain the resize.
-
-
-@interface NSWindow(NSPrivateApis)
-// Note: These functions are private, use -[NSObject respondsToSelector:]
-// before calling them.
-
-- (void)setBottomCornerRounded:(BOOL)rounded;
-
-- (NSRect)_growBoxRect;
-
-@end
-
-
-// IncognitoImageView subclasses NSImageView to allow mouse events to pass
-// through it so you can drag the window by dragging on the spy guy
-@interface IncognitoImageView : NSImageView
-@end
-
-@implementation IncognitoImageView
-- (BOOL)mouseDownCanMoveWindow {
- return YES;
-}
-@end
-
-
-@implementation BrowserWindowController
-
-+ (BrowserWindowController*)browserWindowControllerForWindow:(NSWindow*)window {
- while (window) {
- id controller = [window windowController];
- if ([controller isKindOfClass:[BrowserWindowController class]])
- return (BrowserWindowController*)controller;
- window = [window parentWindow];
- }
- return nil;
-}
-
-+ (BrowserWindowController*)browserWindowControllerForView:(NSView*)view {
- NSWindow* window = [view window];
- return [BrowserWindowController browserWindowControllerForWindow:window];
-}
-
-// Load the browser window nib and do any Cocoa-specific initialization.
-// Takes ownership of |browser|. Note that the nib also sets this controller
-// up as the window's delegate.
-- (id)initWithBrowser:(Browser*)browser {
- return [self initWithBrowser:browser takeOwnership:YES];
-}
-
-// Private(TestingAPI) init routine with testing options.
-- (id)initWithBrowser:(Browser*)browser takeOwnership:(BOOL)ownIt {
- // Use initWithWindowNibPath:: instead of initWithWindowNibName: so we
- // can override it in a unit test.
- NSString* nibpath = [mac_util::MainAppBundle()
- pathForResource:@"BrowserWindow"
- ofType:@"nib"];
- if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
- DCHECK(browser);
- initializing_ = YES;
- browser_.reset(browser);
- ownsBrowser_ = ownIt;
- NSWindow* window = [self window];
- windowShim_.reset(new BrowserWindowCocoa(browser, self, window));
-
- // Create the bar visibility lock set; 10 is arbitrary, but should hopefully
- // be big enough to hold all locks that'll ever be needed.
- barVisibilityLocks_.reset([[NSMutableSet setWithCapacity:10] retain]);
-
- // Sets the window to not have rounded corners, which prevents
- // the resize control from being inset slightly and looking ugly.
- if ([window respondsToSelector:@selector(setBottomCornerRounded:)])
- [window setBottomCornerRounded:NO];
-
- // Get the most appropriate size for the window, then enforce the
- // minimum width and height. The window shim will handle flipping
- // the coordinates for us so we can use it to save some code.
- // Note that this may leave a significant portion of the window
- // offscreen, but there will always be enough window onscreen to
- // drag the whole window back into view.
- NSSize minSize = [[self window] minSize];
- gfx::Rect desiredContentRect = browser_->GetSavedWindowBounds();
- gfx::Rect windowRect = desiredContentRect;
- if (windowRect.width() < minSize.width)
- windowRect.set_width(minSize.width);
- if (windowRect.height() < minSize.height)
- windowRect.set_height(minSize.height);
-
- // When we are given x/y coordinates of 0 on a created popup window, assume
- // none were given by the window.open() command.
- if (browser_->type() & Browser::TYPE_POPUP &&
- windowRect.x() == 0 && windowRect.y() == 0) {
- gfx::Size size = windowRect.size();
- windowRect.set_origin(WindowSizer::GetDefaultPopupOrigin(size));
- }
-
- // Size and position the window. Note that it is not yet onscreen. Popup
- // windows may get resized later on in this function, once the actual size
- // of the toolbar/tabstrip is known.
- windowShim_->SetBounds(windowRect);
-
- // Puts the incognito badge on the window frame, if necessary.
- [self installIncognitoBadge];
-
- // Create a sub-controller for the docked devTools and add its view to the
- // hierarchy. This must happen before the sidebar controller is
- // instantiated.
- devToolsController_.reset(
- [[DevToolsController alloc] initWithDelegate:self]);
- [[devToolsController_ view] setFrame:[[self tabContentArea] bounds]];
- [[self tabContentArea] addSubview:[devToolsController_ view]];
-
- // Create a sub-controller for the docked sidebar and add its view to the
- // hierarchy. This must happen before the previewable contents controller
- // is instantiated.
- sidebarController_.reset([[SidebarController alloc] initWithDelegate:self]);
- [[sidebarController_ view] setFrame:[[devToolsController_ view] bounds]];
- [[devToolsController_ view] addSubview:[sidebarController_ view]];
-
- // Create the previewable contents controller. This provides the switch
- // view that TabStripController needs.
- previewableContentsController_.reset(
- [[PreviewableContentsController alloc] init]);
- [[previewableContentsController_ view]
- setFrame:[[sidebarController_ view] bounds]];
- [[sidebarController_ view]
- addSubview:[previewableContentsController_ view]];
-
- // Create a controller for the tab strip, giving it the model object for
- // this window's Browser and the tab strip view. The controller will handle
- // registering for the appropriate tab notifications from the back-end and
- // managing the creation of new tabs.
- [self createTabStripController];
-
- // Create the infobar container view, so we can pass it to the
- // ToolbarController.
- infoBarContainerController_.reset(
- [[InfoBarContainerController alloc] initWithResizeDelegate:self]);
- [[[self window] contentView] addSubview:[infoBarContainerController_ view]];
-
- // Create a controller for the toolbar, giving it the toolbar model object
- // and the toolbar view from the nib. The controller will handle
- // registering for the appropriate command state changes from the back-end.
- // Adds the toolbar to the content area.
- toolbarController_.reset([[ToolbarController alloc]
- initWithModel:browser->toolbar_model()
- commands:browser->command_updater()
- profile:browser->profile()
- browser:browser
- resizeDelegate:self]);
- [toolbarController_ setHasToolbar:[self hasToolbar]
- hasLocationBar:[self hasLocationBar]];
- [[[self window] contentView] addSubview:[toolbarController_ view]];
-
- // Create a sub-controller for the bookmark bar.
- bookmarkBarController_.reset(
- [[BookmarkBarController alloc]
- initWithBrowser:browser_.get()
- initialWidth:NSWidth([[[self window] contentView] frame])
- delegate:self
- resizeDelegate:self]);
-
- // Add bookmark bar to the view hierarchy, which also triggers the nib load.
- // The bookmark bar is defined (in the nib) to be bottom-aligned to its
- // parent view (among other things), so position and resize properties don't
- // need to be set.
- [[[self window] contentView] addSubview:[bookmarkBarController_ view]
- positioned:NSWindowBelow
- relativeTo:[toolbarController_ view]];
- [bookmarkBarController_ setBookmarkBarEnabled:[self supportsBookmarkBar]];
-
- // We don't want to try and show the bar before it gets placed in its parent
- // view, so this step shoudn't be inside the bookmark bar controller's
- // |-awakeFromNib|.
- [self updateBookmarkBarVisibilityWithAnimation:NO];
-
- // Allow bar visibility to be changed.
- [self enableBarVisibilityUpdates];
-
- // Force a relayout of all the various bars.
- [self layoutSubviews];
-
- // For a popup window, |desiredContentRect| contains the desired height of
- // the content, not of the whole window. Now that all the views are laid
- // out, measure the current content area size and grow if needed. The
- // window has not been placed onscreen yet, so this extra resize will not
- // cause visible jank.
- if (browser_->type() & Browser::TYPE_POPUP) {
- CGFloat deltaH = desiredContentRect.height() -
- NSHeight([[self tabContentArea] frame]);
- // Do not shrink the window, as that may break minimum size invariants.
- if (deltaH > 0) {
- // Convert from tabContentArea coordinates to window coordinates.
- NSSize convertedSize =
- [[self tabContentArea] convertSize:NSMakeSize(0, deltaH)
- toView:nil];
- NSRect frame = [[self window] frame];
- frame.size.height += convertedSize.height;
- frame.origin.y -= convertedSize.height;
- [[self window] setFrame:frame display:NO];
- }
- }
-
- // Create the bridge for the status bubble.
- statusBubble_ = new StatusBubbleMac([self window], self);
-
- // 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];
-
- // This must be done after the view is added to the window since it relies
- // on the window bounds to determine whether to show buttons or not.
- if ([self hasToolbar]) // Do not create the buttons in popups.
- [toolbarController_ createBrowserActionButtons];
-
- // We are done initializing now.
- initializing_ = NO;
- }
- return self;
-}
-
-- (void)dealloc {
- browser_->CloseAllTabs();
- [downloadShelfController_ exiting];
-
- // Explicitly release |fullscreenController_| here, as it may call back to
- // this BWC in |-dealloc|. We are required to call |-exitFullscreen| before
- // releasing the controller.
- [fullscreenController_ exitFullscreen];
- fullscreenController_.reset();
-
- // Under certain testing configurations we may not actually own the browser.
- if (ownsBrowser_ == NO)
- ignore_result(browser_.release());
-
- [[NSNotificationCenter defaultCenter] removeObserver:self];
-
- [super dealloc];
-}
-
-- (BrowserWindow*)browserWindow {
- return windowShim_.get();
-}
-
-- (ToolbarController*)toolbarController {
- return toolbarController_.get();
-}
-
-- (TabStripController*)tabStripController {
- return tabStripController_.get();
-}
-
-- (StatusBubbleMac*)statusBubble {
- return statusBubble_;
-}
-
-- (LocationBarViewMac*)locationBarBridge {
- return [toolbarController_ locationBarBridge];
-}
-
-- (void)destroyBrowser {
- [NSApp removeWindowsItem:[self window]];
-
- // We need the window to go away now.
- // We can't actually use |-autorelease| here because there's an embedded
- // run loop in the |-performClose:| which contains its own autorelease pool.
- // Instead call it after a zero-length delay, which gets us back to the main
- // event loop.
- [self performSelector:@selector(autorelease)
- withObject:nil
- afterDelay:0];
-}
-
-// Called when the window meets the criteria to be closed (ie,
-// |-windowShouldClose:| returns YES). We must be careful to preserve the
-// semantics of BrowserWindow::Close() and not call the Browser's dtor directly
-// from this method.
-- (void)windowWillClose:(NSNotification*)notification {
- DCHECK_EQ([notification object], [self window]);
- DCHECK(browser_->tabstrip_model()->empty());
- [savedRegularWindow_ close];
- // We delete statusBubble here because we need to kill off the dependency
- // that its window has on our window before our window goes away.
- delete statusBubble_;
- statusBubble_ = NULL;
- // We can't actually use |-autorelease| here because there's an embedded
- // run loop in the |-performClose:| which contains its own autorelease pool.
- // Instead call it after a zero-length delay, which gets us back to the main
- // event loop.
- [self performSelector:@selector(autorelease)
- withObject:nil
- afterDelay:0];
-}
-
-- (void)attachConstrainedWindow:(ConstrainedWindowMac*)window {
- [tabStripController_ attachConstrainedWindow:window];
-}
-
-- (void)removeConstrainedWindow:(ConstrainedWindowMac*)window {
- [tabStripController_ removeConstrainedWindow:window];
-}
-
-- (BOOL)canAttachConstrainedWindow {
- return ![previewableContentsController_ isShowingPreview];
-}
-
-- (void)updateDevToolsForContents:(TabContents*)contents {
- [devToolsController_ updateDevToolsForTabContents:contents];
- [devToolsController_ ensureContentsVisible];
-}
-
-- (void)updateSidebarForContents:(TabContents*)contents {
- [sidebarController_ updateSidebarForTabContents:contents];
- [sidebarController_ ensureContentsVisible];
-}
-
-// Called when the user wants to close a window or from the shutdown process.
-// The Browser object is in control of whether or not we're allowed to close. It
-// may defer closing due to several states, such as onUnload handlers needing to
-// be fired. If closing is deferred, the Browser will handle the processing
-// required to get us to the closing state and (by watching for all the tabs
-// going away) will again call to close the window when it's finally ready.
-- (BOOL)windowShouldClose:(id)sender {
- // Disable updates while closing all tabs to avoid flickering.
- app::mac::ScopedNSDisableScreenUpdates disabler;
- // Give beforeunload handlers the chance to cancel the close before we hide
- // the window below.
- if (!browser_->ShouldCloseWindow())
- return NO;
-
- // saveWindowPositionIfNeeded: only works if we are the last active
- // window, but orderOut: ends up activating another window, so we
- // have to save the window position before we call orderOut:.
- [self saveWindowPositionIfNeeded];
-
- if (!browser_->tabstrip_model()->empty()) {
- // Tab strip isn't empty. Hide the frame (so it appears to have closed
- // immediately) and close all the tabs, allowing the renderers to shut
- // down. When the tab strip is empty we'll be called back again.
- [[self window] orderOut:self];
- browser_->OnWindowClosing();
- return NO;
- }
-
- // the tab strip is empty, it's ok to close the window
- return YES;
-}
-
-// Called right after our window became the main window.
-- (void)windowDidBecomeMain:(NSNotification*)notification {
- BrowserList::SetLastActive(browser_.get());
- [self saveWindowPositionIfNeeded];
-
- // TODO(dmaclach): Instead of redrawing the whole window, views that care
- // about the active window state should be registering for notifications.
- [[self window] setViewsNeedDisplay:YES];
-
- // TODO(viettrungluu): For some reason, the above doesn't suffice.
- if ([self isFullscreen])
- [floatingBarBackingView_ setNeedsDisplay:YES]; // Okay even if nil.
-}
-
-- (void)windowDidResignMain:(NSNotification*)notification {
- // TODO(dmaclach): Instead of redrawing the whole window, views that care
- // about the active window state should be registering for notifications.
- [[self window] setViewsNeedDisplay:YES];
-
- // TODO(viettrungluu): For some reason, the above doesn't suffice.
- if ([self isFullscreen])
- [floatingBarBackingView_ setNeedsDisplay:YES]; // Okay even if nil.
-}
-
-// Called when we are activated (when we gain focus).
-- (void)windowDidBecomeKey:(NSNotification*)notification {
- // We need to activate the controls (in the "WebView"). To do this, get the
- // selected TabContents's RenderWidgetHostViewMac and tell it to activate.
- if (TabContents* contents = browser_->GetSelectedTabContents()) {
- if (RenderWidgetHostView* rwhv = contents->GetRenderWidgetHostView())
- rwhv->SetActive(true);
- }
-}
-
-// Called when we are deactivated (when we lose focus).
-- (void)windowDidResignKey:(NSNotification*)notification {
- // If our app is still active and we're still the key window, ignore this
- // message, since it just means that a menu extra (on the "system status bar")
- // was activated; we'll get another |-windowDidResignKey| if we ever really
- // lose key window status.
- if ([NSApp isActive] && ([NSApp keyWindow] == [self window]))
- return;
-
- // We need to deactivate the controls (in the "WebView"). To do this, get the
- // selected TabContents's RenderWidgetHostView and tell it to deactivate.
- if (TabContents* contents = browser_->GetSelectedTabContents()) {
- if (RenderWidgetHostView* rwhv = contents->GetRenderWidgetHostView())
- rwhv->SetActive(false);
- }
-}
-
-// Called when we have been minimized.
-- (void)windowDidMiniaturize:(NSNotification *)notification {
- // Let the selected RenderWidgetHostView know, so that it can tell plugins.
- if (TabContents* contents = browser_->GetSelectedTabContents()) {
- if (RenderWidgetHostView* rwhv = contents->GetRenderWidgetHostView())
- rwhv->SetWindowVisibility(false);
- }
-}
-
-// Called when we have been unminimized.
-- (void)windowDidDeminiaturize:(NSNotification *)notification {
- // Let the selected RenderWidgetHostView know, so that it can tell plugins.
- if (TabContents* contents = browser_->GetSelectedTabContents()) {
- if (RenderWidgetHostView* rwhv = contents->GetRenderWidgetHostView())
- rwhv->SetWindowVisibility(true);
- }
-}
-
-// Called when the application has been hidden.
-- (void)applicationDidHide:(NSNotification *)notification {
- // Let the selected RenderWidgetHostView know, so that it can tell plugins
- // (unless we are minimized, in which case nothing has really changed).
- if (![[self window] isMiniaturized]) {
- if (TabContents* contents = browser_->GetSelectedTabContents()) {
- if (RenderWidgetHostView* rwhv = contents->GetRenderWidgetHostView())
- rwhv->SetWindowVisibility(false);
- }
- }
-}
-
-// Called when the application has been unhidden.
-- (void)applicationDidUnhide:(NSNotification *)notification {
- // Let the selected RenderWidgetHostView know, so that it can tell plugins
- // (unless we are minimized, in which case nothing has really changed).
- if (![[self window] isMiniaturized]) {
- if (TabContents* contents = browser_->GetSelectedTabContents()) {
- if (RenderWidgetHostView* rwhv = contents->GetRenderWidgetHostView())
- rwhv->SetWindowVisibility(true);
- }
- }
-}
-
-// Called when the user clicks the zoom button (or selects it from the Window
-// menu) to determine the "standard size" of the window, based on the content
-// and other factors. If the current size/location differs nontrivally from the
-// standard size, Cocoa resizes the window to the standard size, and saves the
-// current size as the "user size". If the current size/location is the same (up
-// to a fudge factor) as the standard size, Cocoa resizes the window to the
-// saved user size. (It is possible for the two to coincide.) In this way, the
-// zoom button acts as a toggle. We determine the standard size based on the
-// content, but enforce a minimum width (calculated using the dimensions of the
-// screen) to ensure websites with small intrinsic width (such as google.com)
-// don't end up with a wee window. Moreover, we always declare the standard
-// width to be at least as big as the current width, i.e., we never want zooming
-// to the standard width to shrink the window. This is consistent with other
-// browsers' behaviour, and is desirable in multi-tab situations. Note, however,
-// that the "toggle" behaviour means that the window can still be "unzoomed" to
-// the user size.
-- (NSRect)windowWillUseStandardFrame:(NSWindow*)window
- defaultFrame:(NSRect)frame {
- // Forget that we grew the window up (if we in fact did).
- [self resetWindowGrowthState];
-
- // |frame| already fills the current screen. Never touch y and height since we
- // always want to fill vertically.
-
- // If the shift key is down, maximize. Hopefully this should make the
- // "switchers" happy.
- if ([[NSApp currentEvent] modifierFlags] & NSShiftKeyMask) {
- return frame;
- }
-
- // To prevent strange results on portrait displays, the basic minimum zoomed
- // width is the larger of: 60% of available width, 60% of available height
- // (bounded by available width).
- const CGFloat kProportion = 0.6;
- CGFloat zoomedWidth =
- std::max(kProportion * frame.size.width,
- std::min(kProportion * frame.size.height, frame.size.width));
-
- TabContents* contents = browser_->GetSelectedTabContents();
- if (contents) {
- // If the intrinsic width is bigger, then make it the zoomed width.
- const int kScrollbarWidth = 16; // TODO(viettrungluu): ugh.
- TabContentsViewMac* tab_contents_view =
- static_cast<TabContentsViewMac*>(contents->view());
- CGFloat intrinsicWidth = static_cast<CGFloat>(
- tab_contents_view->preferred_width() + kScrollbarWidth);
- zoomedWidth = std::max(zoomedWidth,
- std::min(intrinsicWidth, frame.size.width));
- }
-
- // Never shrink from the current size on zoom (see above).
- NSRect currentFrame = [[self window] frame];
- zoomedWidth = std::max(zoomedWidth, currentFrame.size.width);
-
- // |frame| determines our maximum extents. We need to set the origin of the
- // frame -- and only move it left if necessary.
- if (currentFrame.origin.x + zoomedWidth > frame.origin.x + frame.size.width)
- frame.origin.x = frame.origin.x + frame.size.width - zoomedWidth;
- else
- frame.origin.x = currentFrame.origin.x;
-
- // Set the width. Don't touch y or height.
- frame.size.width = zoomedWidth;
-
- return frame;
-}
-
-- (void)activate {
- [[self window] makeKeyAndOrderFront:self];
-}
-
-// Determine whether we should let a window zoom/unzoom to the given |newFrame|.
-// We avoid letting unzoom move windows between screens, because it's really
-// strange and unintuitive.
-- (BOOL)windowShouldZoom:(NSWindow*)window toFrame:(NSRect)newFrame {
- // Figure out which screen |newFrame| is on.
- NSScreen* newScreen = nil;
- CGFloat newScreenOverlapArea = 0.0;
- for (NSScreen* screen in [NSScreen screens]) {
- NSRect overlap = NSIntersectionRect(newFrame, [screen frame]);
- CGFloat overlapArea = overlap.size.width * overlap.size.height;
- if (overlapArea > newScreenOverlapArea) {
- newScreen = screen;
- newScreenOverlapArea = overlapArea;
- }
- }
- // If we're somehow not on any screen, allow the zoom.
- if (!newScreen)
- return YES;
-
- // If the new screen is the current screen, we can return a definitive YES.
- // Note: This check is not strictly necessary, but just short-circuits in the
- // "no-brainer" case. To test the complicated logic below, comment this out!
- NSScreen* curScreen = [window screen];
- if (newScreen == curScreen)
- return YES;
-
- // Worry a little: What happens when a window is on two (or more) screens?
- // E.g., what happens in a 50-50 scenario? Cocoa may reasonably elect to zoom
- // to the other screen rather than staying on the officially current one. So
- // we compare overlaps with the current window frame, and see if Cocoa's
- // choice was reasonable (allowing a small rounding error). This should
- // hopefully avoid us ever erroneously denying a zoom when a window is on
- // multiple screens.
- NSRect curFrame = [window frame];
- NSRect newScrIntersectCurFr = NSIntersectionRect([newScreen frame], curFrame);
- NSRect curScrIntersectCurFr = NSIntersectionRect([curScreen frame], curFrame);
- if (newScrIntersectCurFr.size.width*newScrIntersectCurFr.size.height >=
- (curScrIntersectCurFr.size.width*curScrIntersectCurFr.size.height - 1.0))
- return YES;
-
- // If it wasn't reasonable, return NO.
- return NO;
-}
-
-// Adjusts the window height by the given amount.
-- (void)adjustWindowHeightBy:(CGFloat)deltaH {
- // By not adjusting the window height when initializing, we can ensure that
- // the window opens with the same size that was saved on close.
- if (initializing_ || [self isFullscreen] || deltaH == 0)
- return;
-
- NSWindow* window = [self window];
- NSRect windowFrame = [window frame];
- NSRect workarea = [[window screen] visibleFrame];
-
- // If the window is not already fully in the workarea, do not adjust its frame
- // at all.
- if (!NSContainsRect(workarea, windowFrame))
- return;
-
- // Record the position of the top/bottom of the window, so we can easily check
- // whether we grew the window upwards/downwards.
- CGFloat oldWindowMaxY = NSMaxY(windowFrame);
- CGFloat oldWindowMinY = NSMinY(windowFrame);
-
- // We are "zoomed" if we occupy the full vertical space.
- bool isZoomed = (windowFrame.origin.y == workarea.origin.y &&
- windowFrame.size.height == workarea.size.height);
-
- // If we're shrinking the window....
- if (deltaH < 0) {
- bool didChange = false;
-
- // Don't reset if not currently zoomed since shrinking can take several
- // steps!
- if (isZoomed)
- isShrinkingFromZoomed_ = YES;
-
- // If we previously grew at the top, shrink as much as allowed at the top
- // first.
- if (windowTopGrowth_ > 0) {
- CGFloat shrinkAtTopBy = MIN(-deltaH, windowTopGrowth_);
- windowFrame.size.height -= shrinkAtTopBy; // Shrink the window.
- deltaH += shrinkAtTopBy; // Update the amount left to shrink.
- windowTopGrowth_ -= shrinkAtTopBy; // Update the growth state.
- didChange = true;
- }
-
- // Similarly for the bottom (not an "else if" since we may have to
- // simultaneously shrink at both the top and at the bottom). Note that
- // |deltaH| may no longer be nonzero due to the above.
- if (deltaH < 0 && windowBottomGrowth_ > 0) {
- CGFloat shrinkAtBottomBy = MIN(-deltaH, windowBottomGrowth_);
- windowFrame.origin.y += shrinkAtBottomBy; // Move the window up.
- windowFrame.size.height -= shrinkAtBottomBy; // Shrink the window.
- deltaH += shrinkAtBottomBy; // Update the amount left....
- windowBottomGrowth_ -= shrinkAtBottomBy; // Update the growth state.
- didChange = true;
- }
-
- // If we're shrinking from zoomed but we didn't change the top or bottom
- // (since we've reached the limits imposed by |window...Growth_|), then stop
- // here. Don't reset |isShrinkingFromZoomed_| since we might get called
- // again for the same shrink.
- if (isShrinkingFromZoomed_ && !didChange)
- return;
- } else {
- isShrinkingFromZoomed_ = NO;
-
- // Don't bother with anything else.
- if (isZoomed)
- return;
- }
-
- // Shrinking from zoomed is handled above (and is constrained by
- // |window...Growth_|).
- if (!isShrinkingFromZoomed_) {
- // Resize the window down until it hits the bottom of the workarea, then if
- // needed continue resizing upwards. Do not resize the window to be taller
- // than the current workarea.
- // Resize the window as requested, keeping the top left corner fixed.
- windowFrame.origin.y -= deltaH;
- windowFrame.size.height += deltaH;
-
- // If the bottom left corner is now outside the visible frame, move the
- // window up to make it fit, but make sure not to move the top left corner
- // out of the visible frame.
- if (windowFrame.origin.y < workarea.origin.y) {
- windowFrame.origin.y = workarea.origin.y;
- windowFrame.size.height =
- std::min(windowFrame.size.height, workarea.size.height);
- }
-
- // Record (if applicable) how much we grew the window in either direction.
- // (N.B.: These only record growth, not shrinkage.)
- if (NSMaxY(windowFrame) > oldWindowMaxY)
- windowTopGrowth_ += NSMaxY(windowFrame) - oldWindowMaxY;
- if (NSMinY(windowFrame) < oldWindowMinY)
- windowBottomGrowth_ += oldWindowMinY - NSMinY(windowFrame);
- }
-
- // Disable subview resizing while resizing the window, or else we will get
- // unwanted renderer resizes. The calling code must call layoutSubviews to
- // make things right again.
- NSView* contentView = [window contentView];
- [contentView setAutoresizesSubviews:NO];
- [window setFrame:windowFrame display:NO];
- [contentView setAutoresizesSubviews:YES];
-}
-
-// Main method to resize browser window subviews. This method should be called
-// when resizing any child of the content view, rather than resizing the views
-// directly. If the view is already the correct height, does not force a
-// relayout.
-- (void)resizeView:(NSView*)view newHeight:(CGFloat)height {
- // We should only ever be called for one of the following four views.
- // |downloadShelfController_| may be nil. If we are asked to size the bookmark
- // bar directly, its superview must be this controller's content view.
- DCHECK(view);
- DCHECK(view == [toolbarController_ view] ||
- view == [infoBarContainerController_ view] ||
- view == [downloadShelfController_ view] ||
- view == [bookmarkBarController_ view]);
-
- // Change the height of the view and call |-layoutSubViews|. We set the height
- // here without regard to where the view is on the screen or whether it needs
- // to "grow up" or "grow down." The below call to |-layoutSubviews| will
- // position each view correctly.
- NSRect frame = [view frame];
- if (NSHeight(frame) == height)
- return;
-
- // Grow or shrink the window by the amount of the height change. We adjust
- // the window height only in two cases:
- // 1) We are adjusting the height of the bookmark bar and it is currently
- // animating either open or closed.
- // 2) We are adjusting the height of the download shelf.
- //
- // We do not adjust the window height for bookmark bar changes on the NTP.
- BOOL shouldAdjustBookmarkHeight =
- [bookmarkBarController_ isAnimatingBetweenState:bookmarks::kHiddenState
- andState:bookmarks::kShowingState];
- if ((shouldAdjustBookmarkHeight && view == [bookmarkBarController_ view]) ||
- view == [downloadShelfController_ view]) {
- [[self window] disableScreenUpdatesUntilFlush];
- CGFloat deltaH = height - frame.size.height;
- [self adjustWindowHeightBy:deltaH];
- }
-
- frame.size.height = height;
- // TODO(rohitrao): Determine if calling setFrame: twice is bad.
- [view setFrame:frame];
- [self layoutSubviews];
-}
-
-- (void)setAnimationInProgress:(BOOL)inProgress {
- [[self tabContentArea] setFastResizeMode:inProgress];
-}
-
-// Update a toggle state for an NSMenuItem if modified.
-// Take care to ensure |item| looks like a NSMenuItem.
-// Called by validateUserInterfaceItem:.
-- (void)updateToggleStateWithTag:(NSInteger)tag forItem:(id)item {
- if (![item respondsToSelector:@selector(state)] ||
- ![item respondsToSelector:@selector(setState:)])
- return;
-
- // On Windows this logic happens in bookmark_bar_view.cc. On the
- // Mac we're a lot more MVC happy so we've moved it into a
- // controller. To be clear, this simply updates the menu item; it
- // does not display the bookmark bar itself.
- if (tag == IDC_SHOW_BOOKMARK_BAR) {
- bool toggled = windowShim_->IsBookmarkBarVisible();
- NSInteger oldState = [item state];
- NSInteger newState = toggled ? NSOnState : NSOffState;
- if (oldState != newState)
- [item setState:newState];
- }
-
- // Update the checked/Unchecked state of items in the encoding menu.
- // On Windows, this logic is part of |EncodingMenuModel| in
- // browser/views/toolbar_view.h.
- EncodingMenuController encoding_controller;
- if (encoding_controller.DoesCommandBelongToEncodingMenu(tag)) {
- DCHECK(browser_.get());
- Profile* profile = browser_->profile();
- DCHECK(profile);
- TabContents* current_tab = browser_->GetSelectedTabContents();
- if (!current_tab) {
- return;
- }
- const std::string encoding = current_tab->encoding();
-
- bool toggled = encoding_controller.IsItemChecked(profile, encoding, tag);
- NSInteger oldState = [item state];
- NSInteger newState = toggled ? NSOnState : NSOffState;
- if (oldState != newState)
- [item setState:newState];
- }
-}
-
-- (BOOL)supportsFullscreen {
- // TODO(avi, thakis): GTMWindowSheetController has no api to move
- // tabsheets between windows. Until then, we have to prevent having to
- // move a tabsheet between windows, e.g. no fullscreen toggling
- NSArray* a = [[tabStripController_ sheetController] viewsWithAttachedSheets];
- return [a count] == 0;
-}
-
-// Called to validate menu and toolbar items when this window is key. All the
-// items we care about have been set with the |-commandDispatch:| or
-// |-commandDispatchUsingKeyModifiers:| actions and a target of FirstResponder
-// in IB. If it's not one of those, let it continue up the responder chain to be
-// handled elsewhere. We pull out the tag as the cross-platform constant to
-// differentiate and dispatch the various commands.
-// NOTE: we might have to handle state for app-wide menu items,
-// although we could cheat and directly ask the app controller if our
-// command_updater doesn't support the command. This may or may not be an issue,
-// too early to tell.
-- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
- SEL action = [item action];
- BOOL enable = NO;
- if (action == @selector(commandDispatch:) ||
- action == @selector(commandDispatchUsingKeyModifiers:)) {
- NSInteger tag = [item tag];
- if (browser_->command_updater()->SupportsCommand(tag)) {
- // Generate return value (enabled state)
- enable = browser_->command_updater()->IsCommandEnabled(tag);
- switch (tag) {
- case IDC_CLOSE_TAB:
- // Disable "close tab" if we're not the key window or if there's only
- // one tab.
- enable &= [self numberOfTabs] > 1 && [[self window] isKeyWindow];
- break;
- case IDC_FULLSCREEN: {
- enable &= [self supportsFullscreen];
- if ([static_cast<NSObject*>(item) isKindOfClass:[NSMenuItem class]]) {
- NSString* menuTitle = l10n_util::GetNSString(
- [self isFullscreen] ? IDS_EXIT_FULLSCREEN_MAC :
- IDS_ENTER_FULLSCREEN_MAC);
- [static_cast<NSMenuItem*>(item) setTitle:menuTitle];
- }
- break;
- }
- case IDC_SYNC_BOOKMARKS:
- enable &= browser_->profile()->IsSyncAccessible();
- sync_ui_util::UpdateSyncItem(item, enable, browser_->profile());
- break;
- default:
- // Special handling for the contents of the Text Encoding submenu. On
- // Mac OS, instead of enabling/disabling the top-level menu item, we
- // enable/disable the submenu's contents (per Apple's HIG).
- EncodingMenuController encoding_controller;
- if (encoding_controller.DoesCommandBelongToEncodingMenu(tag)) {
- enable &= browser_->command_updater()->IsCommandEnabled(
- IDC_ENCODING_MENU) ? YES : NO;
- }
- }
-
- // If the item is toggleable, find its toggle state and
- // try to update it. This is a little awkward, but the alternative is
- // to check after a commandDispatch, which seems worse.
- [self updateToggleStateWithTag:tag forItem:item];
- }
- }
- return enable;
-}
-
-// Called when the user picks a menu or toolbar item when this window is key.
-// Calls through to the browser object to execute the command. This assumes that
-// the command is supported and doesn't check, otherwise it would have been
-// disabled in the UI in validateUserInterfaceItem:.
-- (void)commandDispatch:(id)sender {
- DCHECK(sender);
- // Identify the actual BWC to which the command should be dispatched. It might
- // belong to a background window, yet this controller gets it because it is
- // the foreground window's controller and thus in the responder chain. Some
- // senders don't have this problem (for example, menus only operate on the
- // foreground window), so this is only an issue for senders that are part of
- // windows.
- BrowserWindowController* targetController = self;
- if ([sender respondsToSelector:@selector(window)])
- targetController = [[sender window] windowController];
- DCHECK([targetController isKindOfClass:[BrowserWindowController class]]);
- DCHECK(targetController->browser_.get());
- targetController->browser_->ExecuteCommand([sender tag]);
-}
-
-// Same as |-commandDispatch:|, but executes commands using a disposition
-// determined by the key flags. If the window is in the background and the
-// command key is down, ignore the command key, but process any other modifiers.
-- (void)commandDispatchUsingKeyModifiers:(id)sender {
- DCHECK(sender);
- // See comment above for why we do this.
- BrowserWindowController* targetController = self;
- if ([sender respondsToSelector:@selector(window)])
- targetController = [[sender window] windowController];
- DCHECK([targetController isKindOfClass:[BrowserWindowController class]]);
- NSInteger command = [sender tag];
- NSUInteger modifierFlags = [[NSApp currentEvent] modifierFlags];
- if ((command == IDC_RELOAD) &&
- (modifierFlags & (NSShiftKeyMask | NSControlKeyMask))) {
- command = IDC_RELOAD_IGNORING_CACHE;
- // Mask off Shift and Control so they don't affect the disposition below.
- modifierFlags &= ~(NSShiftKeyMask | NSControlKeyMask);
- }
- if (![[sender window] isMainWindow]) {
- // Remove the command key from the flags, it means "keep the window in
- // the background" in this case.
- modifierFlags &= ~NSCommandKeyMask;
- }
- WindowOpenDisposition disposition =
- event_utils::WindowOpenDispositionFromNSEventWithFlags(
- [NSApp currentEvent], modifierFlags);
- switch (command) {
- case IDC_BACK:
- case IDC_FORWARD:
- case IDC_RELOAD:
- case IDC_RELOAD_IGNORING_CACHE:
- if (disposition == CURRENT_TAB) {
- // Forcibly reset the location bar, since otherwise it won't discard any
- // ongoing user edits, since it doesn't realize this is a user-initiated
- // action.
- [targetController locationBarBridge]->Revert();
- }
- }
- DCHECK(targetController->browser_.get());
- targetController->browser_->ExecuteCommandWithDisposition(command,
- disposition);
-}
-
-// Called when another part of the internal codebase needs to execute a
-// command.
-- (void)executeCommand:(int)command {
- if (browser_->command_updater()->IsCommandEnabled(command))
- browser_->ExecuteCommand(command);
-}
-
-// StatusBubble delegate method: tell the status bubble the frame it should
-// position itself in.
-- (NSRect)statusBubbleBaseFrame {
- NSView* view = [previewableContentsController_ view];
- return [view convertRect:[view bounds] toView:nil];
-}
-
-- (GTMWindowSheetController*)sheetController {
- return [tabStripController_ sheetController];
-}
-
-- (void)updateToolbarWithContents:(TabContents*)tab
- shouldRestoreState:(BOOL)shouldRestore {
- [toolbarController_ updateToolbarWithContents:tab
- shouldRestoreState:shouldRestore];
-}
-
-- (void)setStarredState:(BOOL)isStarred {
- [toolbarController_ setStarredState:isStarred];
-}
-
-// Accept tabs from a BrowserWindowController with the same Profile.
-- (BOOL)canReceiveFrom:(TabWindowController*)source {
- if (![source isKindOfClass:[BrowserWindowController class]]) {
- return NO;
- }
-
- BrowserWindowController* realSource =
- static_cast<BrowserWindowController*>(source);
- if (browser_->profile() != realSource->browser_->profile()) {
- return NO;
- }
-
- // Can't drag a tab from a normal browser to a pop-up
- if (browser_->type() != realSource->browser_->type()) {
- return NO;
- }
-
- return YES;
-}
-
-// Move a given tab view to the location of the current placeholder. If there is
-// no placeholder, it will go at the end. |controller| is the window controller
-// of a tab being dropped from a different window. It will be nil if the drag is
-// within the window, otherwise the tab is removed from that window before being
-// placed into this one. The implementation will call |-removePlaceholder| since
-// the drag is now complete. This also calls |-layoutTabs| internally so
-// clients do not need to call it again.
-- (void)moveTabView:(NSView*)view
- fromController:(TabWindowController*)dragController {
- if (dragController) {
- // Moving between windows. Figure out the TabContents to drop into our tab
- // model from the source window's model.
- BOOL isBrowser =
- [dragController isKindOfClass:[BrowserWindowController class]];
- DCHECK(isBrowser);
- if (!isBrowser) return;
- BrowserWindowController* dragBWC = (BrowserWindowController*)dragController;
- int index = [dragBWC->tabStripController_ modelIndexForTabView:view];
- TabContentsWrapper* contents =
- dragBWC->browser_->GetTabContentsWrapperAt(index);
- // The tab contents may have gone away if given a window.close() while it
- // is being dragged. If so, bail, we've got nothing to drop.
- if (!contents)
- return;
-
- // Convert |view|'s frame (which starts in the source tab strip's coordinate
- // system) to the coordinate system of the destination tab strip. This needs
- // to be done before being detached so the window transforms can be
- // performed.
- NSRect destinationFrame = [view frame];
- NSPoint tabOrigin = destinationFrame.origin;
- tabOrigin = [[dragController tabStripView] convertPoint:tabOrigin
- toView:nil];
- tabOrigin = [[view window] convertBaseToScreen:tabOrigin];
- tabOrigin = [[self window] convertScreenToBase:tabOrigin];
- tabOrigin = [[self tabStripView] convertPoint:tabOrigin fromView:nil];
- destinationFrame.origin = tabOrigin;
-
- // Before the tab is detached from its originating tab strip, store the
- // pinned state so that it can be maintained between the windows.
- bool isPinned = dragBWC->browser_->tabstrip_model()->IsTabPinned(index);
-
- // Now that we have enough information about the tab, we can remove it from
- // the dragging window. We need to do this *before* we add it to the new
- // window as this will remove the TabContents' delegate.
- [dragController detachTabView:view];
-
- // Deposit it into our model at the appropriate location (it already knows
- // where it should go from tracking the drag). Doing this sets the tab's
- // delegate to be the Browser.
- [tabStripController_ dropTabContents:contents
- withFrame:destinationFrame
- asPinnedTab:isPinned];
- } else {
- // Moving within a window.
- int index = [tabStripController_ modelIndexForTabView:view];
- [tabStripController_ moveTabFromIndex:index];
- }
-
- // Remove the placeholder since the drag is now complete.
- [self removePlaceholder];
-}
-
-// Tells the tab strip to forget about this tab in preparation for it being
-// put into a different tab strip, such as during a drop on another window.
-- (void)detachTabView:(NSView*)view {
- int index = [tabStripController_ modelIndexForTabView:view];
- browser_->tabstrip_model()->DetachTabContentsAt(index);
-}
-
-- (NSView*)selectedTabView {
- return [tabStripController_ selectedTabView];
-}
-
-- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force {
- [toolbarController_ setIsLoading:isLoading force:force];
-}
-
-// Make the location bar the first responder, if possible.
-- (void)focusLocationBar:(BOOL)selectAll {
- [toolbarController_ focusLocationBar:selectAll];
-}
-
-- (void)focusTabContents {
- [[self window] makeFirstResponder:[tabStripController_ selectedTabView]];
-}
-
-- (void)layoutTabs {
- [tabStripController_ layoutTabs];
-}
-
-- (TabWindowController*)detachTabToNewWindow:(TabView*)tabView {
- // Disable screen updates so that this appears as a single visual change.
- app::mac::ScopedNSDisableScreenUpdates disabler;
-
- // Fetch the tab contents for the tab being dragged.
- int index = [tabStripController_ modelIndexForTabView:tabView];
- TabContentsWrapper* contents = browser_->GetTabContentsWrapperAt(index);
-
- // Set the window size. Need to do this before we detach the tab so it's
- // still in the window. We have to flip the coordinates as that's what
- // is expected by the Browser code.
- NSWindow* sourceWindow = [tabView window];
- NSRect windowRect = [sourceWindow frame];
- NSScreen* screen = [sourceWindow screen];
- windowRect.origin.y =
- [screen frame].size.height - windowRect.size.height -
- windowRect.origin.y;
- gfx::Rect browserRect(windowRect.origin.x, windowRect.origin.y,
- windowRect.size.width, windowRect.size.height);
-
- NSRect sourceTabRect = [tabView frame];
- NSView* tabStrip = [self tabStripView];
-
- // Pushes tabView's frame back inside the tabstrip.
- NSSize tabOverflow =
- [self overflowFrom:[tabStrip convertRectToBase:sourceTabRect]
- to:[tabStrip frame]];
- NSRect tabRect = NSOffsetRect(sourceTabRect,
- -tabOverflow.width, -tabOverflow.height);
-
- // Before detaching the tab, store the pinned state.
- bool isPinned = browser_->tabstrip_model()->IsTabPinned(index);
-
- // Detach it from the source window, which just updates the model without
- // deleting the tab contents. This needs to come before creating the new
- // Browser because it clears the TabContents' delegate, which gets hooked
- // up during creation of the new window.
- browser_->tabstrip_model()->DetachTabContentsAt(index);
-
- // Create the new window with a single tab in its model, the one being
- // dragged.
- DockInfo dockInfo;
- Browser* newBrowser = browser_->tabstrip_model()->delegate()->
- CreateNewStripWithContents(contents, browserRect, dockInfo, false);
-
- // Propagate the tab pinned state of the new tab (which is the only tab in
- // this new window).
- newBrowser->tabstrip_model()->SetTabPinned(0, isPinned);
-
- // Get the new controller by asking the new window for its delegate.
- BrowserWindowController* controller =
- reinterpret_cast<BrowserWindowController*>(
- [newBrowser->window()->GetNativeHandle() delegate]);
- DCHECK(controller && [controller isKindOfClass:[TabWindowController class]]);
-
- // Force the added tab to the right size (remove stretching.)
- tabRect.size.height = [TabStripController defaultTabHeight];
-
- // And make sure we use the correct frame in the new view.
- [[controller tabStripController] setFrameOfSelectedTab:tabRect];
- return controller;
-}
-
-- (void)insertPlaceholderForTab:(TabView*)tab
- frame:(NSRect)frame
- yStretchiness:(CGFloat)yStretchiness {
- [super insertPlaceholderForTab:tab frame:frame yStretchiness:yStretchiness];
- [tabStripController_ insertPlaceholderForTab:tab
- frame:frame
- yStretchiness:yStretchiness];
-}
-
-- (void)removePlaceholder {
- [super removePlaceholder];
- [tabStripController_ insertPlaceholderForTab:nil
- frame:NSZeroRect
- yStretchiness:0];
-}
-
-- (BOOL)tabDraggingAllowed {
- return [tabStripController_ tabDraggingAllowed];
-}
-
-- (BOOL)tabTearingAllowed {
- return ![self isFullscreen];
-}
-
-- (BOOL)windowMovementAllowed {
- return ![self isFullscreen];
-}
-
-- (BOOL)isTabFullyVisible:(TabView*)tab {
- return [tabStripController_ isTabFullyVisible:tab];
-}
-
-- (void)showNewTabButton:(BOOL)show {
- [tabStripController_ showNewTabButton:show];
-}
-
-- (BOOL)isBookmarkBarVisible {
- return [bookmarkBarController_ isVisible];
-}
-
-- (BOOL)isBookmarkBarAnimating {
- return [bookmarkBarController_ isAnimationRunning];
-}
-
-- (void)updateBookmarkBarVisibilityWithAnimation:(BOOL)animate {
- [bookmarkBarController_
- updateAndShowNormalBar:[self shouldShowBookmarkBar]
- showDetachedBar:[self shouldShowDetachedBookmarkBar]
- withAnimation:animate];
-}
-
-- (BOOL)isDownloadShelfVisible {
- return downloadShelfController_ != nil &&
- [downloadShelfController_ isVisible];
-}
-
-- (DownloadShelfController*)downloadShelf {
- if (!downloadShelfController_.get()) {
- downloadShelfController_.reset([[DownloadShelfController alloc]
- initWithBrowser:browser_.get() resizeDelegate:self]);
- [[[self window] contentView] addSubview:[downloadShelfController_ view]];
- [downloadShelfController_ show:nil];
- }
- return downloadShelfController_;
-}
-
-- (void)addFindBar:(FindBarCocoaController*)findBarCocoaController {
- // Shouldn't call addFindBar twice.
- DCHECK(!findBarCocoaController_.get());
-
- // Create a controller for the findbar.
- findBarCocoaController_.reset([findBarCocoaController retain]);
- NSView *contentView = [[self window] contentView];
- [contentView addSubview:[findBarCocoaController_ view]
- positioned:NSWindowAbove
- relativeTo:[toolbarController_ view]];
-
- // Place the find bar immediately below the toolbar/attached bookmark bar. In
- // fullscreen mode, it hangs off the top of the screen when the bar is hidden.
- CGFloat maxY = [self placeBookmarkBarBelowInfoBar] ?
- NSMinY([[toolbarController_ view] frame]) :
- NSMinY([[bookmarkBarController_ view] frame]);
- CGFloat maxWidth = NSWidth([contentView frame]);
- [findBarCocoaController_ positionFindBarViewAtMaxY:maxY maxWidth:maxWidth];
-}
-
-- (NSWindow*)createFullscreenWindow {
- return [[[FullscreenWindow alloc] initForScreen:[[self window] screen]]
- autorelease];
-}
-
-- (NSInteger)numberOfTabs {
- // count() includes pinned tabs.
- return browser_->tabstrip_model()->count();
-}
-
-- (BOOL)hasLiveTabs {
- return !browser_->tabstrip_model()->empty();
-}
-
-- (NSString*)selectedTabTitle {
- TabContents* contents = browser_->GetSelectedTabContents();
- return base::SysUTF16ToNSString(contents->GetTitle());
-}
-
-- (NSRect)regularWindowFrame {
- return [self isFullscreen] ? [savedRegularWindow_ frame] :
- [[self window] frame];
-}
-
-// (Override of |TabWindowController| method.)
-- (BOOL)hasTabStrip {
- return [self supportsWindowFeature:Browser::FEATURE_TABSTRIP];
-}
-
-// TabContentsControllerDelegate protocol.
-- (void)tabContentsViewFrameWillChange:(TabContentsController*)source
- frameRect:(NSRect)frameRect {
- TabContents* contents = [source tabContents];
- RenderWidgetHostView* render_widget_host_view = contents ?
- contents->GetRenderWidgetHostView() : NULL;
- if (!render_widget_host_view)
- return;
-
- gfx::Rect reserved_rect;
-
- NSWindow* window = [self window];
- if ([window respondsToSelector:@selector(_growBoxRect)]) {
- NSView* view = [source view];
- if (view && [view superview]) {
- NSRect windowGrowBoxRect = [window _growBoxRect];
- NSRect viewRect = [[view superview] convertRect:frameRect toView:nil];
- NSRect growBoxRect = NSIntersectionRect(windowGrowBoxRect, viewRect);
- if (!NSIsEmptyRect(growBoxRect)) {
- // Before we return a rect, we need to convert it from window
- // coordinates to content area coordinates and flip the coordinate
- // system.
- // Superview is used here because, first, it's a frame rect, so it is
- // specified in the parent's coordinates and, second, view is not
- // positioned yet.
- growBoxRect = [[view superview] convertRect:growBoxRect fromView:nil];
- growBoxRect.origin.y =
- NSHeight(frameRect) - NSHeight(growBoxRect);
- growBoxRect =
- NSOffsetRect(growBoxRect, -frameRect.origin.x, -frameRect.origin.y);
-
- reserved_rect =
- gfx::Rect(growBoxRect.origin.x, growBoxRect.origin.y,
- growBoxRect.size.width, growBoxRect.size.height);
- }
- }
- }
-
- render_widget_host_view->set_reserved_contents_rect(reserved_rect);
-}
-
-// TabStripControllerDelegate protocol.
-- (void)onSelectTabWithContents:(TabContents*)contents {
- // Update various elements that are interested in knowing the current
- // TabContents.
-
- // Update all the UI bits.
- windowShim_->UpdateTitleBar();
-
- [sidebarController_ updateSidebarForTabContents:contents];
- [devToolsController_ updateDevToolsForTabContents:contents];
-
- // Update the bookmark bar.
- // Must do it after sidebar and devtools update, otherwise bookmark bar might
- // call resizeView -> layoutSubviews and cause unnecessary relayout.
- // TODO(viettrungluu): perhaps update to not terminate running animations (if
- // applicable)?
- [self updateBookmarkBarVisibilityWithAnimation:NO];
-
- [infoBarContainerController_ changeTabContents:contents];
-
- // Update devTools and sidebar contents after size for all views is set.
- [sidebarController_ ensureContentsVisible];
- [devToolsController_ ensureContentsVisible];
-}
-
-- (void)onReplaceTabWithContents:(TabContents*)contents {
- // This is only called when instant results are committed. Simply remove the
- // preview view; the tab strip controller will reinstall the view as the
- // active view.
- [previewableContentsController_ hidePreview];
- [self updateBookmarkBarVisibilityWithAnimation:NO];
-}
-
-- (void)onSelectedTabChange:(TabStripModelObserver::TabChangeType)change {
- // Update titles if this is the currently selected tab and if it isn't just
- // the loading state which changed.
- if (change != TabStripModelObserver::LOADING_ONLY)
- windowShim_->UpdateTitleBar();
-
- // Update the bookmark bar if this is the currently selected tab and if it
- // isn't just the title which changed. This for transitions between the NTP
- // (showing its floating bookmark bar) and normal web pages (showing no
- // bookmark bar).
- // TODO(viettrungluu): perhaps update to not terminate running animations?
- if (change != TabStripModelObserver::TITLE_NOT_LOADING)
- [self updateBookmarkBarVisibilityWithAnimation:NO];
-}
-
-- (void)onTabDetachedWithContents:(TabContents*)contents {
- [infoBarContainerController_ tabDetachedWithContents:contents];
-}
-
-- (void)userChangedTheme {
- // TODO(dmaclach): Instead of redrawing the whole window, views that care
- // about the active window state should be registering for notifications.
- [[self window] setViewsNeedDisplay:YES];
-}
-
-- (ThemeProvider*)themeProvider {
- return browser_->profile()->GetThemeProvider();
-}
-
-- (ThemedWindowStyle)themedWindowStyle {
- ThemedWindowStyle style = 0;
- if (browser_->profile()->IsOffTheRecord())
- style |= THEMED_INCOGNITO;
-
- Browser::Type type = browser_->type();
- if (type == Browser::TYPE_POPUP)
- style |= THEMED_POPUP;
- else if (type == Browser::TYPE_DEVTOOLS)
- style |= THEMED_DEVTOOLS;
-
- return style;
-}
-
-- (NSPoint)themePatternPhase {
- // Our patterns want to be drawn from the upper left hand corner of the view.
- // Cocoa wants to do it from the lower left of the window.
- //
- // Rephase our pattern to fit this view. Some other views (Tabs, Toolbar etc.)
- // will phase their patterns relative to this so all the views look right.
- //
- // To line up the background pattern with the pattern in the browser window
- // the background pattern for the tabs needs to be moved left by 5 pixels.
- const CGFloat kPatternHorizontalOffset = -5;
- NSView* tabStripView = [self tabStripView];
- NSRect tabStripViewWindowBounds = [tabStripView bounds];
- NSView* windowChromeView = [[[self window] contentView] superview];
- tabStripViewWindowBounds =
- [tabStripView convertRect:tabStripViewWindowBounds
- toView:windowChromeView];
- NSPoint phase = NSMakePoint(NSMinX(tabStripViewWindowBounds)
- + kPatternHorizontalOffset,
- NSMinY(tabStripViewWindowBounds)
- + [TabStripController defaultTabHeight]);
- return phase;
-}
-
-- (NSPoint)bookmarkBubblePoint {
- return [toolbarController_ bookmarkBubblePoint];
-}
-
-// Show the bookmark bubble (e.g. user just clicked on the STAR).
-- (void)showBookmarkBubbleForURL:(const GURL&)url
- alreadyBookmarked:(BOOL)alreadyMarked {
- if (!bookmarkBubbleController_) {
- BookmarkModel* model = browser_->profile()->GetBookmarkModel();
- const BookmarkNode* node = model->GetMostRecentlyAddedNodeForURL(url);
- bookmarkBubbleController_ =
- [[BookmarkBubbleController alloc] initWithParentWindow:[self window]
- model:model
- node:node
- alreadyBookmarked:alreadyMarked];
- [bookmarkBubbleController_ showWindow:self];
- NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
- [center addObserver:self
- selector:@selector(bubbleWindowWillClose:)
- name:NSWindowWillCloseNotification
- object:[bookmarkBubbleController_ window]];
- }
-}
-
-// Nil out the weak bookmark bubble controller reference.
-- (void)bubbleWindowWillClose:(NSNotification*)notification {
- DCHECK([notification object] == [bookmarkBubbleController_ window]);
- NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
- [center removeObserver:self
- name:NSWindowWillCloseNotification
- object:[bookmarkBubbleController_ window]];
- bookmarkBubbleController_ = nil;
-}
-
-// Handle the editBookmarkNode: action sent from bookmark bubble controllers.
-- (void)editBookmarkNode:(id)sender {
- BOOL responds = [sender respondsToSelector:@selector(node)];
- DCHECK(responds);
- if (responds) {
- const BookmarkNode* node = [sender node];
- if (node) {
- // A BookmarkEditorController is a sheet that owns itself, and
- // deallocates itself when closed.
- [[[BookmarkEditorController alloc]
- initWithParentWindow:[self window]
- profile:browser_->profile()
- parent:node->GetParent()
- node:node
- configuration:BookmarkEditor::SHOW_TREE]
- runAsModalSheet];
- }
- }
-}
-
-// If the browser is in incognito mode, install the image view to decorate
-// the window at the upper right. Use the same base y coordinate as the
-// tab strip.
-- (void)installIncognitoBadge {
- // Only install if this browser window is OTR and has a tab strip.
- if (!browser_->profile()->IsOffTheRecord() || ![self hasTabStrip])
- return;
-
- // Install the image into the badge view and size the view appropriately.
- // Hide it for now; positioning and showing will be done by the layout code.
- NSImage* image = nsimage_cache::ImageNamed(@"otr_icon.pdf");
- incognitoBadge_.reset([[IncognitoImageView alloc] init]);
- [incognitoBadge_ setImage:image];
- [incognitoBadge_ setFrameSize:[image size]];
- [incognitoBadge_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
- [incognitoBadge_ setHidden:YES];
-
- // Give it a shadow.
- scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
- [shadow.get() setShadowColor:[NSColor colorWithCalibratedWhite:0.0
- alpha:0.5]];
- [shadow.get() setShadowOffset:NSMakeSize(0, -1)];
- [shadow setShadowBlurRadius:2.0];
- [incognitoBadge_ setShadow:shadow];
-
- // Install the view.
- [[[[self window] contentView] superview] addSubview:incognitoBadge_];
-}
-
-// Documented in 10.6+, but present starting in 10.5. Called when we get a
-// three-finger swipe.
-- (void)swipeWithEvent:(NSEvent*)event {
- // Map forwards and backwards to history; left is positive, right is negative.
- unsigned int command = 0;
- if ([event deltaX] > 0.5) {
- command = IDC_BACK;
- } else if ([event deltaX] < -0.5) {
- command = IDC_FORWARD;
- } else if ([event deltaY] > 0.5) {
- // TODO(pinkerton): figure out page-up, http://crbug.com/16305
- } else if ([event deltaY] < -0.5) {
- // TODO(pinkerton): figure out page-down, http://crbug.com/16305
- browser_->ExecuteCommand(IDC_TABPOSE);
- }
-
- // Ensure the command is valid first (ExecuteCommand() won't do that) and
- // then make it so.
- if (browser_->command_updater()->IsCommandEnabled(command))
- browser_->ExecuteCommandWithDisposition(command,
- event_utils::WindowOpenDispositionFromNSEvent(event));
-}
-
-// Documented in 10.6+, but present starting in 10.5. Called repeatedly during
-// a pinch gesture, with incremental change values.
-- (void)magnifyWithEvent:(NSEvent*)event {
- // The deltaZ difference necessary to trigger a zoom action. Derived from
- // experimentation to find a value that feels reasonable.
- const float kZoomStepValue = 150;
-
- // Find the (absolute) thresholds on either side of the current zoom factor,
- // then convert those to actual numbers to trigger a zoom in or out.
- // This logic deliberately makes the range around the starting zoom value for
- // the gesture twice as large as the other ranges (i.e., the notches are at
- // ..., -3*step, -2*step, -step, step, 2*step, 3*step, ... but not at 0)
- // so that it's easier to get back to your starting point than it is to
- // overshoot.
- float nextStep = (abs(currentZoomStepDelta_) + 1) * kZoomStepValue;
- float backStep = abs(currentZoomStepDelta_) * kZoomStepValue;
- float zoomInThreshold = (currentZoomStepDelta_ >= 0) ? nextStep : -backStep;
- float zoomOutThreshold = (currentZoomStepDelta_ <= 0) ? -nextStep : backStep;
-
- unsigned int command = 0;
- totalMagnifyGestureAmount_ += [event deltaZ];
- if (totalMagnifyGestureAmount_ > zoomInThreshold) {
- command = IDC_ZOOM_PLUS;
- } else if (totalMagnifyGestureAmount_ < zoomOutThreshold) {
- command = IDC_ZOOM_MINUS;
- }
-
- if (command && browser_->command_updater()->IsCommandEnabled(command)) {
- currentZoomStepDelta_ += (command == IDC_ZOOM_PLUS) ? 1 : -1;
- browser_->ExecuteCommandWithDisposition(command,
- event_utils::WindowOpenDispositionFromNSEvent(event));
- }
-}
-
-// Documented in 10.6+, but present starting in 10.5. Called at the beginning
-// of a gesture.
-- (void)beginGestureWithEvent:(NSEvent*)event {
- totalMagnifyGestureAmount_ = 0;
- currentZoomStepDelta_ = 0;
-}
-
-// Delegate method called when window is resized.
-- (void)windowDidResize:(NSNotification*)notification {
- // Resize (and possibly move) the status bubble. Note that we may get called
- // when the status bubble does not exist.
- if (statusBubble_) {
- statusBubble_->UpdateSizeAndPosition();
- }
-
- // Let the selected RenderWidgetHostView know, so that it can tell plugins.
- if (TabContents* contents = browser_->GetSelectedTabContents()) {
- if (RenderWidgetHostView* rwhv = contents->GetRenderWidgetHostView())
- rwhv->WindowFrameChanged();
- }
-}
-
-// Handle the openLearnMoreAboutCrashLink: action from SadTabController when
-// "Learn more" link in "Aw snap" page (i.e. crash page or sad tab) is
-// clicked. Decoupling the action from its target makes unitestting possible.
-- (void)openLearnMoreAboutCrashLink:(id)sender {
- if ([sender isKindOfClass:[SadTabController class]]) {
- SadTabController* sad_tab = static_cast<SadTabController*>(sender);
- TabContents* tab_contents = [sad_tab tabContents];
- if (tab_contents) {
- GURL helpUrl =
- google_util::AppendGoogleLocaleParam(GURL(chrome::kCrashReasonURL));
- tab_contents->OpenURL(helpUrl, GURL(), CURRENT_TAB, PageTransition::LINK);
- }
- }
-}
-
-// Delegate method called when window did move. (See below for why we don't use
-// |-windowWillMove:|, which is called less frequently than |-windowDidMove|
-// instead.)
-- (void)windowDidMove:(NSNotification*)notification {
- NSWindow* window = [self window];
- NSRect windowFrame = [window frame];
- NSRect workarea = [[window screen] visibleFrame];
-
- // We reset the window growth state whenever the window is moved out of the
- // work area or away (up or down) from the bottom or top of the work area.
- // Unfortunately, Cocoa sends |-windowWillMove:| too frequently (including
- // when clicking on the title bar to activate), and of course
- // |-windowWillMove| is called too early for us to apply our heuristic. (The
- // heuristic we use for detecting window movement is that if |windowTopGrowth_
- // > 0|, then we should be at the bottom of the work area -- if we're not,
- // we've moved. Similarly for the other side.)
- if (!NSContainsRect(workarea, windowFrame) ||
- (windowTopGrowth_ > 0 && NSMinY(windowFrame) != NSMinY(workarea)) ||
- (windowBottomGrowth_ > 0 && NSMaxY(windowFrame) != NSMaxY(workarea)))
- [self resetWindowGrowthState];
-
- // Let the selected RenderWidgetHostView know, so that it can tell plugins.
- if (TabContents* contents = browser_->GetSelectedTabContents()) {
- if (RenderWidgetHostView* rwhv = contents->GetRenderWidgetHostView())
- rwhv->WindowFrameChanged();
- }
-}
-
-// Delegate method called when window will be resized; not called for
-// |-setFrame:display:|.
-- (NSSize)windowWillResize:(NSWindow*)sender toSize:(NSSize)frameSize {
- [self resetWindowGrowthState];
- return frameSize;
-}
-
-// Delegate method: see |NSWindowDelegate| protocol.
-- (id)windowWillReturnFieldEditor:(NSWindow*)sender toObject:(id)obj {
- // Ask the toolbar controller if it wants to return a custom field editor
- // for the specific object.
- return [toolbarController_ customFieldEditorForObject:obj];
-}
-
-// (Needed for |BookmarkBarControllerDelegate| protocol.)
-- (void)bookmarkBar:(BookmarkBarController*)controller
- didChangeFromState:(bookmarks::VisualState)oldState
- toState:(bookmarks::VisualState)newState {
- [toolbarController_
- setDividerOpacity:[bookmarkBarController_ toolbarDividerOpacity]];
- [self adjustToolbarAndBookmarkBarForCompression:
- [controller getDesiredToolbarHeightCompression]];
-}
-
-// (Needed for |BookmarkBarControllerDelegate| protocol.)
-- (void)bookmarkBar:(BookmarkBarController*)controller
-willAnimateFromState:(bookmarks::VisualState)oldState
- toState:(bookmarks::VisualState)newState {
- [toolbarController_
- setDividerOpacity:[bookmarkBarController_ toolbarDividerOpacity]];
- [self adjustToolbarAndBookmarkBarForCompression:
- [controller getDesiredToolbarHeightCompression]];
-}
-
-// (Private/TestingAPI)
-- (void)resetWindowGrowthState {
- windowTopGrowth_ = 0;
- windowBottomGrowth_ = 0;
- isShrinkingFromZoomed_ = NO;
-}
-
-- (NSSize)overflowFrom:(NSRect)source
- to:(NSRect)target {
- // If |source|'s boundary is outside of |target|'s, set its distance
- // to |x|. Note that |source| can overflow to both side, but we
- // have nothing to do for such case.
- CGFloat x = 0;
- if (NSMaxX(target) < NSMaxX(source)) // |source| overflows to right
- x = NSMaxX(source) - NSMaxX(target);
- else if (NSMinX(source) < NSMinX(target)) // |source| overflows to left
- x = NSMinX(source) - NSMinX(target);
-
- // Same as |x| above.
- CGFloat y = 0;
- if (NSMaxY(target) < NSMaxY(source))
- y = NSMaxY(source) - NSMaxY(target);
- else if (NSMinY(source) < NSMinY(target))
- y = NSMinY(source) - NSMinY(target);
-
- return NSMakeSize(x, y);
-}
-
-// Override to swap in the correct tab strip controller based on the new
-// tab strip mode.
-- (void)toggleTabStripDisplayMode {
- [super toggleTabStripDisplayMode];
- [self createTabStripController];
-}
-
-- (BOOL)useVerticalTabs {
- return browser_->tabstrip_model()->delegate()->UseVerticalTabs();
-}
-
-- (void)showInstant:(TabContents*)previewContents {
- [previewableContentsController_ showPreview:previewContents];
- [self updateBookmarkBarVisibilityWithAnimation:NO];
-}
-
-- (void)hideInstant {
- // TODO(rohitrao): Revisit whether or not this method should be called when
- // instant isn't showing.
- if (![previewableContentsController_ isShowingPreview])
- return;
-
- [previewableContentsController_ hidePreview];
- [self updateBookmarkBarVisibilityWithAnimation:NO];
-}
-
-- (NSRect)instantFrame {
- // The view's bounds are in its own coordinate system. Convert that to the
- // window base coordinate system, then translate it into the screen's
- // coordinate system.
- NSView* view = [previewableContentsController_ view];
- if (!view)
- return NSZeroRect;
-
- NSRect frame = [view convertRect:[view bounds] toView:nil];
- NSPoint originInScreenCoords =
- [[view window] convertBaseToScreen:frame.origin];
- frame.origin = originInScreenCoords;
- return frame;
-}
-
-- (void)sheetDidEnd:(NSWindow*)sheet
- returnCode:(NSInteger)code
- context:(void*)context {
- [sheet orderOut:self];
-}
-
-@end // @implementation BrowserWindowController
-
-
-@implementation BrowserWindowController(Fullscreen)
-
-- (void)setFullscreen:(BOOL)fullscreen {
- // The logic in this function is a bit complicated and very carefully
- // arranged. See the below comments for more details.
-
- if (fullscreen == [self isFullscreen])
- return;
-
- if (![self supportsFullscreen])
- return;
-
- // Fade to black.
- const CGDisplayReservationInterval kFadeDurationSeconds = 0.6;
- Boolean didFadeOut = NO;
- CGDisplayFadeReservationToken token;
- if (CGAcquireDisplayFadeReservation(kFadeDurationSeconds, &token)
- == kCGErrorSuccess) {
- didFadeOut = YES;
- CGDisplayFade(token, kFadeDurationSeconds / 2, kCGDisplayBlendNormal,
- kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, /*synchronous=*/true);
- }
-
- // Close the bookmark bubble, if it's open. We use |-ok:| instead of
- // |-cancel:| or |-close| because that matches the behavior when the bubble
- // loses key status.
- [bookmarkBubbleController_ ok:self];
-
- // Save the current first responder so we can restore after views are moved.
- NSWindow* window = [self window];
- scoped_nsobject<FocusTracker> focusTracker(
- [[FocusTracker alloc] initWithWindow:window]);
- BOOL showDropdown = [self floatingBarHasFocus];
-
- // While we move views (and focus) around, disable any bar visibility changes.
- [self disableBarVisibilityUpdates];
-
- // If we're entering fullscreen, create the fullscreen controller. If we're
- // exiting fullscreen, kill the controller.
- if (fullscreen) {
- fullscreenController_.reset([[FullscreenController alloc]
- initWithBrowserController:self]);
- } else {
- [fullscreenController_ exitFullscreen];
- fullscreenController_.reset();
- }
-
- // Destroy the tab strip's sheet controller. We will recreate it in the new
- // window when needed.
- [tabStripController_ destroySheetController];
-
- // Retain the tab strip view while we remove it from its superview.
- scoped_nsobject<NSView> tabStripView;
- if ([self hasTabStrip] && ![self useVerticalTabs]) {
- tabStripView.reset([[self tabStripView] retain]);
- [tabStripView removeFromSuperview];
- }
-
- // Ditto for the content view.
- scoped_nsobject<NSView> contentView([[window contentView] retain]);
- // Disable autoresizing of subviews while we move views around. This prevents
- // spurious renderer resizes.
- [contentView setAutoresizesSubviews:NO];
- [contentView removeFromSuperview];
-
- NSWindow* destWindow = nil;
- if (fullscreen) {
- DCHECK(!savedRegularWindow_);
- savedRegularWindow_ = [window retain];
- destWindow = [self createFullscreenWindow];
- } else {
- DCHECK(savedRegularWindow_);
- destWindow = [savedRegularWindow_ autorelease];
- savedRegularWindow_ = nil;
-
- CGSWorkspaceID workspace;
- if ([window cr_workspace:&workspace]) {
- [destWindow cr_moveToWorkspace:workspace];
- }
- }
- DCHECK(destWindow);
-
- // Have to do this here, otherwise later calls can crash because the window
- // has no delegate.
- [window setDelegate:nil];
- [destWindow setDelegate:self];
-
- // With this call, valgrind complains that a "Conditional jump or move depends
- // on uninitialised value(s)". The error happens in -[NSThemeFrame
- // drawOverlayRect:]. I'm pretty convinced this is an Apple bug, but there is
- // no visual impact. I have been unable to tickle it away with other window
- // or view manipulation Cocoa calls. Stack added to suppressions_mac.txt.
- [contentView setAutoresizesSubviews:YES];
- [destWindow setContentView:contentView];
-
- // Move the incognito badge if present.
- if (incognitoBadge_.get()) {
- [incognitoBadge_ removeFromSuperview];
- [incognitoBadge_ setHidden:YES]; // Will be shown in layout.
- [[[destWindow contentView] superview] addSubview:incognitoBadge_];
- }
-
- // Add the tab strip after setting the content view and moving the incognito
- // badge (if any), so that the tab strip will be on top (in the z-order).
- if ([self hasTabStrip] && ![self useVerticalTabs])
- [[[destWindow contentView] superview] addSubview:tabStripView];
-
- [window setWindowController:nil];
- [self setWindow:destWindow];
- [destWindow setWindowController:self];
- [self adjustUIForFullscreen:fullscreen];
-
- // When entering fullscreen mode, the controller forces a layout for us. When
- // exiting, we need to call layoutSubviews manually.
- if (fullscreen) {
- [fullscreenController_ enterFullscreenForContentView:contentView
- showDropdown:showDropdown];
- } else {
- [self layoutSubviews];
- }
-
- // Move the status bubble over, if we have one.
- if (statusBubble_)
- statusBubble_->SwitchParentWindow(destWindow);
-
- // Move the title over.
- [destWindow setTitle:[window title]];
-
- // The window needs to be onscreen before we can set its first responder.
- [destWindow makeKeyAndOrderFront:self];
- [focusTracker restoreFocusInWindow:destWindow];
- [window orderOut:self];
-
- // We're done moving focus, so re-enable bar visibility changes.
- [self enableBarVisibilityUpdates];
-
- // Fade back in.
- if (didFadeOut) {
- CGDisplayFade(token, kFadeDurationSeconds / 2, kCGDisplayBlendSolidColor,
- kCGDisplayBlendNormal, 0.0, 0.0, 0.0, /*synchronous=*/false);
- CGReleaseDisplayFadeReservation(token);
- }
-}
-
-- (BOOL)isFullscreen {
- return fullscreenController_.get() && [fullscreenController_ isFullscreen];
-}
-
-- (void)resizeFullscreenWindow {
- DCHECK([self isFullscreen]);
- if (![self isFullscreen])
- return;
-
- NSWindow* window = [self window];
- [window setFrame:[[window screen] frame] display:YES];
- [self layoutSubviews];
-}
-
-- (CGFloat)floatingBarShownFraction {
- return floatingBarShownFraction_;
-}
-
-- (void)setFloatingBarShownFraction:(CGFloat)fraction {
- floatingBarShownFraction_ = fraction;
- [self layoutSubviews];
-}
-
-- (BOOL)isBarVisibilityLockedForOwner:(id)owner {
- DCHECK(owner);
- DCHECK(barVisibilityLocks_);
- return [barVisibilityLocks_ containsObject:owner];
-}
-
-- (void)lockBarVisibilityForOwner:(id)owner
- withAnimation:(BOOL)animate
- delay:(BOOL)delay {
- if (![self isBarVisibilityLockedForOwner:owner]) {
- [barVisibilityLocks_ addObject:owner];
-
- // If enabled, show the overlay if necessary (and if in fullscreen mode).
- if (barVisibilityUpdatesEnabled_) {
- [fullscreenController_ ensureOverlayShownWithAnimation:animate
- delay:delay];
- }
- }
-}
-
-- (void)releaseBarVisibilityForOwner:(id)owner
- withAnimation:(BOOL)animate
- delay:(BOOL)delay {
- if ([self isBarVisibilityLockedForOwner:owner]) {
- [barVisibilityLocks_ removeObject:owner];
-
- // If enabled, hide the overlay if necessary (and if in fullscreen mode).
- if (barVisibilityUpdatesEnabled_ &&
- ![barVisibilityLocks_ count]) {
- [fullscreenController_ ensureOverlayHiddenWithAnimation:animate
- delay:delay];
- }
- }
-}
-
-- (BOOL)floatingBarHasFocus {
- NSResponder* focused = [[self window] firstResponder];
- return [focused isKindOfClass:[AutocompleteTextFieldEditor class]];
-}
-
-- (void)openTabpose {
- NSUInteger modifierFlags = [[NSApp currentEvent] modifierFlags];
- BOOL slomo = (modifierFlags & NSShiftKeyMask) != 0;
-
- // Cover info bars, inspector window, and detached bookmark bar on NTP.
- // Do not cover download shelf.
- NSRect activeArea = [[self tabContentArea] frame];
- activeArea.size.height +=
- NSHeight([[infoBarContainerController_ view] frame]);
- if ([self isBookmarkBarVisible] && [self placeBookmarkBarBelowInfoBar]) {
- NSView* bookmarkBarView = [bookmarkBarController_ view];
- activeArea.size.height += NSHeight([bookmarkBarView frame]);
- }
-
- [TabposeWindow openTabposeFor:[self window]
- rect:activeArea
- slomo:slomo
- tabStripModel:browser_->tabstrip_model()];
-}
-
-@end // @implementation BrowserWindowController(Fullscreen)
-
-
-@implementation BrowserWindowController(WindowType)
-
-- (BOOL)supportsWindowFeature:(int)feature {
- return browser_->SupportsWindowFeature(
- static_cast<Browser::WindowFeature>(feature));
-}
-
-- (BOOL)hasTitleBar {
- return [self supportsWindowFeature:Browser::FEATURE_TITLEBAR];
-}
-
-- (BOOL)hasToolbar {
- return [self supportsWindowFeature:Browser::FEATURE_TOOLBAR];
-}
-
-- (BOOL)hasLocationBar {
- return [self supportsWindowFeature:Browser::FEATURE_LOCATIONBAR];
-}
-
-- (BOOL)supportsBookmarkBar {
- return [self supportsWindowFeature:Browser::FEATURE_BOOKMARKBAR];
-}
-
-- (BOOL)isNormalWindow {
- return browser_->type() == Browser::TYPE_NORMAL;
-}
-
-@end // @implementation BrowserWindowController(WindowType)
diff --git a/chrome/browser/cocoa/browser_window_controller_private.h b/chrome/browser/cocoa/browser_window_controller_private.h
deleted file mode 100644
index ec93540..0000000
--- a/chrome/browser/cocoa/browser_window_controller_private.h
+++ /dev/null
@@ -1,119 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_BROWSER_WINDOW_CONTROLLER_PRIVATE_H_
-#define CHROME_BROWSER_COCOA_BROWSER_WINDOW_CONTROLLER_PRIVATE_H_
-#pragma once
-
-#import "chrome/browser/cocoa/browser_window_controller.h"
-
-
-// Private methods for the |BrowserWindowController|. This category should
-// contain the private methods used by different parts of the BWC; private
-// methods used only by single parts should be declared in their own file.
-// TODO(viettrungluu): [crbug.com/35543] work on splitting out stuff from the
-// BWC, and figuring out which methods belong here (need to unravel
-// "dependencies").
-@interface BrowserWindowController(Private)
-
-// Create the appropriate tab strip controller based on whether or not side
-// tabs are enabled. Replaces the current controller.
-- (void)createTabStripController;
-
-// Saves the window's position in the local state preferences.
-- (void)saveWindowPositionIfNeeded;
-
-// Saves the window's position to the given pref service.
-- (void)saveWindowPositionToPrefs:(PrefService*)prefs;
-
-// We need to adjust where sheets come out of the window, as by default they
-// erupt from the omnibox, which is rather weird.
-- (NSRect)window:(NSWindow*)window
- willPositionSheet:(NSWindow*)sheet
- usingRect:(NSRect)defaultSheetRect;
-
-// Repositions the window's subviews. From the top down: toolbar, normal
-// bookmark bar (if shown), infobar, NTP detached bookmark bar (if shown),
-// content area, download shelf (if any).
-- (void)layoutSubviews;
-
-// Find the total height of the floating bar (in fullscreen mode). Safe to call
-// even when not in fullscreen mode.
-- (CGFloat)floatingBarHeight;
-
-// Lays out the tab strip at the given maximum y-coordinate, with the given
-// width, possibly for fullscreen mode; returns the new maximum y (below the tab
-// strip). This is safe to call even when there is no tab strip.
-- (CGFloat)layoutTabStripAtMaxY:(CGFloat)maxY
- width:(CGFloat)width
- fullscreen:(BOOL)fullscreen;
-
-// Lays out the toolbar (or just location bar for popups) at the given maximum
-// y-coordinate, with the given width; returns the new maximum y (below the
-// toolbar).
-- (CGFloat)layoutToolbarAtMinX:(CGFloat)minX
- maxY:(CGFloat)maxY
- width:(CGFloat)width;
-
-// Returns YES if the bookmark bar should be placed below the infobar, NO
-// otherwise.
-- (BOOL)placeBookmarkBarBelowInfoBar;
-
-// Lays out the bookmark bar at the given maximum y-coordinate, with the given
-// width; returns the new maximum y (below the bookmark bar). Note that one must
-// call it with the appropriate |maxY| which depends on whether or not the
-// bookmark bar is shown as the NTP bubble or not (use
-// |-placeBookmarkBarBelowInfoBar|).
-- (CGFloat)layoutBookmarkBarAtMinX:(CGFloat)minX
- maxY:(CGFloat)maxY
- width:(CGFloat)width;
-
-// Lay out the view which draws the background for the floating bar when in
-// fullscreen mode, with the given frame and fullscreen-mode-status. Should be
-// called even when not in fullscreen mode to hide the backing view.
-- (void)layoutFloatingBarBackingView:(NSRect)frame
- fullscreen:(BOOL)fullscreen;
-
-// Lays out the infobar at the given maximum y-coordinate, with the given width;
-// returns the new maximum y (below the infobar).
-- (CGFloat)layoutInfoBarAtMinX:(CGFloat)minX
- maxY:(CGFloat)maxY
- width:(CGFloat)width;
-
-// Lays out the download shelf, if there is one, at the given minimum
-// y-coordinate, with the given width; returns the new minimum y (above the
-// download shelf). This is safe to call even if there is no download shelf.
-- (CGFloat)layoutDownloadShelfAtMinX:(CGFloat)minX
- minY:(CGFloat)minY
- width:(CGFloat)width;
-
-// Lays out the tab content area in the given frame. If the height changes,
-// sends a message to the renderer to resize.
-- (void)layoutTabContentArea:(NSRect)frame;
-
-// Should we show the normal bookmark bar?
-- (BOOL)shouldShowBookmarkBar;
-
-// Is the current page one for which the bookmark should be shown detached *if*
-// the normal bookmark bar is not shown?
-- (BOOL)shouldShowDetachedBookmarkBar;
-
-// Sets the toolbar's height to a value appropriate for the given compression.
-// Also adjusts the bookmark bar's height by the opposite amount in order to
-// keep the total height of the two views constant.
-- (void)adjustToolbarAndBookmarkBarForCompression:(CGFloat)compression;
-
-// Adjust the UI when entering or leaving fullscreen mode.
-- (void)adjustUIForFullscreen:(BOOL)fullscreen;
-
-// Allows/prevents bar visibility locks and releases from updating the visual
-// state. Enabling makes changes instantaneously; disabling cancels any
-// timers/animation.
-- (void)enableBarVisibilityUpdates;
-- (void)disableBarVisibilityUpdates;
-
-@end // @interface BrowserWindowController(Private)
-
-
-#endif // CHROME_BROWSER_COCOA_BROWSER_WINDOW_CONTROLLER_PRIVATE_H_
diff --git a/chrome/browser/cocoa/browser_window_controller_private.mm b/chrome/browser/cocoa/browser_window_controller_private.mm
deleted file mode 100644
index cb4270d..0000000
--- a/chrome/browser/cocoa/browser_window_controller_private.mm
+++ /dev/null
@@ -1,509 +0,0 @@
-// 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 "chrome/browser/cocoa/browser_window_controller_private.h"
-
-#include "base/mac_util.h"
-#import "base/scoped_nsobject.h"
-#include "chrome/browser/browser_process.h"
-#import "chrome/browser/cocoa/fast_resize_view.h"
-#import "chrome/browser/cocoa/find_bar_cocoa_controller.h"
-#import "chrome/browser/cocoa/floating_bar_backing_view.h"
-#import "chrome/browser/cocoa/framed_browser_window.h"
-#import "chrome/browser/cocoa/fullscreen_controller.h"
-#import "chrome/browser/cocoa/previewable_contents_controller.h"
-#import "chrome/browser/cocoa/side_tab_strip_controller.h"
-#import "chrome/browser/cocoa/tab_strip_controller.h"
-#import "chrome/browser/cocoa/tab_strip_view.h"
-#import "chrome/browser/cocoa/toolbar_controller.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/renderer_host/render_widget_host_view.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents/tab_contents_view.h"
-#include "chrome/browser/themes/browser_theme_provider.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_list.h"
-#include "chrome/common/pref_names.h"
-
-namespace {
-
-// Space between the incognito badge and the right edge of the window.
-const CGFloat kIncognitoBadgeOffset = 4;
-
-// Insets for the location bar, used when the full toolbar is hidden.
-// TODO(viettrungluu): We can argue about the "correct" insetting; I like the
-// following best, though arguably 0 inset is better/more correct.
-const CGFloat kLocBarLeftRightInset = 1;
-const CGFloat kLocBarTopInset = 0;
-const CGFloat kLocBarBottomInset = 1;
-
-} // end namespace
-
-
-@implementation BrowserWindowController(Private)
-
-// Create the appropriate tab strip controller based on whether or not side
-// tabs are enabled.
-- (void)createTabStripController {
- Class factory = [TabStripController class];
- if ([self useVerticalTabs])
- factory = [SideTabStripController class];
-
- DCHECK([previewableContentsController_ activeContainer]);
- DCHECK([[previewableContentsController_ activeContainer] window]);
- tabStripController_.reset([[factory alloc]
- initWithView:[self tabStripView]
- switchView:[previewableContentsController_ activeContainer]
- browser:browser_.get()
- delegate:self]);
-}
-
-- (void)saveWindowPositionIfNeeded {
- if (browser_ != BrowserList::GetLastActive())
- return;
-
- if (!g_browser_process || !g_browser_process->local_state() ||
- !browser_->ShouldSaveWindowPlacement())
- return;
-
- [self saveWindowPositionToPrefs:g_browser_process->local_state()];
-}
-
-- (void)saveWindowPositionToPrefs:(PrefService*)prefs {
- // If we're in fullscreen mode, save the position of the regular window
- // instead.
- NSWindow* window = [self isFullscreen] ? savedRegularWindow_ : [self window];
-
- // Window positions are stored relative to the origin of the primary monitor.
- NSRect monitorFrame = [[[NSScreen screens] objectAtIndex:0] frame];
- NSScreen* windowScreen = [window screen];
-
- // |windowScreen| can be nil (for example, if the monitor arrangement was
- // changed while in fullscreen mode). If we see a nil screen, return without
- // saving.
- // TODO(rohitrao): We should just not save anything for fullscreen windows.
- // http://crbug.com/36479.
- if (!windowScreen)
- return;
-
- // Start with the window's frame, which is in virtual coordinates.
- // Do some y twiddling to flip the coordinate system.
- gfx::Rect bounds(NSRectToCGRect([window frame]));
- bounds.set_y(monitorFrame.size.height - bounds.y() - bounds.height());
-
- // We also need to save the current work area, in flipped coordinates.
- gfx::Rect workArea(NSRectToCGRect([windowScreen visibleFrame]));
- workArea.set_y(monitorFrame.size.height - workArea.y() - workArea.height());
-
- // Browser::SaveWindowPlacement is used for session restore.
- if (browser_->ShouldSaveWindowPlacement())
- browser_->SaveWindowPlacement(bounds, /*maximized=*/ false);
-
- DictionaryValue* windowPreferences = prefs->GetMutableDictionary(
- browser_->GetWindowPlacementKey().c_str());
- windowPreferences->SetInteger("left", bounds.x());
- windowPreferences->SetInteger("top", bounds.y());
- windowPreferences->SetInteger("right", bounds.right());
- windowPreferences->SetInteger("bottom", bounds.bottom());
- windowPreferences->SetBoolean("maximized", false);
- windowPreferences->SetBoolean("always_on_top", false);
- windowPreferences->SetInteger("work_area_left", workArea.x());
- windowPreferences->SetInteger("work_area_top", workArea.y());
- windowPreferences->SetInteger("work_area_right", workArea.right());
- windowPreferences->SetInteger("work_area_bottom", workArea.bottom());
-}
-
-- (NSRect)window:(NSWindow*)window
-willPositionSheet:(NSWindow*)sheet
- usingRect:(NSRect)defaultSheetRect {
- // Position the sheet as follows:
- // - If the bookmark bar is hidden or shown as a bubble (on the NTP when the
- // bookmark bar is disabled), position the sheet immediately below the
- // normal toolbar.
- // - If the bookmark bar is shown (attached to the normal toolbar), position
- // the sheet below the bookmark bar.
- // - If the bookmark bar is currently animating, position the sheet according
- // to where the bar will be when the animation ends.
- switch ([bookmarkBarController_ visualState]) {
- case bookmarks::kShowingState: {
- NSRect bookmarkBarFrame = [[bookmarkBarController_ view] frame];
- defaultSheetRect.origin.y = bookmarkBarFrame.origin.y;
- break;
- }
- case bookmarks::kHiddenState:
- case bookmarks::kDetachedState: {
- NSRect toolbarFrame = [[toolbarController_ view] frame];
- defaultSheetRect.origin.y = toolbarFrame.origin.y;
- break;
- }
- case bookmarks::kInvalidState:
- default:
- NOTREACHED();
- }
- return defaultSheetRect;
-}
-
-- (void)layoutSubviews {
- // With the exception of the top tab strip, the subviews which we lay out are
- // subviews of the content view, so we mainly work in the content view's
- // coordinate system. Note, however, that the content view's coordinate system
- // and the window's base coordinate system should coincide.
- NSWindow* window = [self window];
- NSView* contentView = [window contentView];
- NSRect contentBounds = [contentView bounds];
- CGFloat minX = NSMinX(contentBounds);
- CGFloat minY = NSMinY(contentBounds);
- CGFloat width = NSWidth(contentBounds);
-
- // Suppress title drawing if necessary.
- if ([window respondsToSelector:@selector(setShouldHideTitle:)])
- [(id)window setShouldHideTitle:![self hasTitleBar]];
-
- BOOL isFullscreen = [self isFullscreen];
- CGFloat floatingBarHeight = [self floatingBarHeight];
- // In fullscreen mode, |yOffset| accounts for the sliding position of the
- // floating bar and the extra offset needed to dodge the menu bar.
- CGFloat yOffset = isFullscreen ?
- (floor((1 - floatingBarShownFraction_) * floatingBarHeight) -
- [fullscreenController_ floatingBarVerticalOffset]) : 0;
- CGFloat maxY = NSMaxY(contentBounds) + yOffset;
- CGFloat startMaxY = maxY;
-
- if ([self hasTabStrip] && ![self useVerticalTabs]) {
- // If we need to lay out the top tab strip, replace |maxY| and |startMaxY|
- // with higher values, and then lay out the tab strip.
- NSRect windowFrame = [contentView convertRect:[window frame] fromView:nil];
- startMaxY = maxY = NSHeight(windowFrame) + yOffset;
- maxY = [self layoutTabStripAtMaxY:maxY width:width fullscreen:isFullscreen];
- }
-
- // Sanity-check |maxY|.
- DCHECK_GE(maxY, minY);
- DCHECK_LE(maxY, NSMaxY(contentBounds) + yOffset);
-
- // The base class already positions the side tab strip on the left side
- // of the window's content area and sizes it to take the entire vertical
- // height. All that's needed here is to push everything over to the right,
- // if necessary.
- if ([self useVerticalTabs]) {
- const CGFloat sideTabWidth = [[self tabStripView] bounds].size.width;
- minX += sideTabWidth;
- width -= sideTabWidth;
- }
-
- // Place the toolbar at the top of the reserved area.
- maxY = [self layoutToolbarAtMinX:minX maxY:maxY width:width];
-
- // If we're not displaying the bookmark bar below the infobar, then it goes
- // immediately below the toolbar.
- BOOL placeBookmarkBarBelowInfoBar = [self placeBookmarkBarBelowInfoBar];
- if (!placeBookmarkBarBelowInfoBar)
- maxY = [self layoutBookmarkBarAtMinX:minX maxY:maxY width:width];
-
- // The floating bar backing view doesn't actually add any height.
- NSRect floatingBarBackingRect =
- NSMakeRect(minX, maxY, width, floatingBarHeight);
- [self layoutFloatingBarBackingView:floatingBarBackingRect
- fullscreen:isFullscreen];
-
- // Place the find bar immediately below the toolbar/attached bookmark bar. In
- // fullscreen mode, it hangs off the top of the screen when the bar is hidden.
- // The find bar is unaffected by the side tab positioning.
- [findBarCocoaController_ positionFindBarViewAtMaxY:maxY maxWidth:width];
-
- // If in fullscreen mode, reset |maxY| to top of screen, so that the floating
- // bar slides over the things which appear to be in the content area.
- if (isFullscreen)
- maxY = NSMaxY(contentBounds);
-
- // Also place the infobar container immediate below the toolbar, except in
- // fullscreen mode in which case it's at the top of the visual content area.
- maxY = [self layoutInfoBarAtMinX:minX maxY:maxY width:width];
-
- // If the bookmark bar is detached, place it next in the visual content area.
- if (placeBookmarkBarBelowInfoBar)
- maxY = [self layoutBookmarkBarAtMinX:minX maxY:maxY width:width];
-
- // Place the download shelf, if any, at the bottom of the view.
- minY = [self layoutDownloadShelfAtMinX:minX minY:minY width:width];
-
- // Finally, the content area takes up all of the remaining space.
- NSRect contentAreaRect = NSMakeRect(minX, minY, width, maxY - minY);
- [self layoutTabContentArea:contentAreaRect];
-
- // Normally, we don't need to tell the toolbar whether or not to show the
- // divider, but things break down during animation.
- [toolbarController_
- setDividerOpacity:[bookmarkBarController_ toolbarDividerOpacity]];
-}
-
-- (CGFloat)floatingBarHeight {
- if (![self isFullscreen])
- return 0;
-
- CGFloat totalHeight = [fullscreenController_ floatingBarVerticalOffset];
-
- if ([self hasTabStrip])
- totalHeight += NSHeight([[self tabStripView] frame]);
-
- if ([self hasToolbar]) {
- totalHeight += NSHeight([[toolbarController_ view] frame]);
- } else if ([self hasLocationBar]) {
- totalHeight += NSHeight([[toolbarController_ view] frame]) +
- kLocBarTopInset + kLocBarBottomInset;
- }
-
- if (![self placeBookmarkBarBelowInfoBar])
- totalHeight += NSHeight([[bookmarkBarController_ view] frame]);
-
- return totalHeight;
-}
-
-- (CGFloat)layoutTabStripAtMaxY:(CGFloat)maxY
- width:(CGFloat)width
- fullscreen:(BOOL)fullscreen {
- // Nothing to do if no tab strip.
- if (![self hasTabStrip])
- return maxY;
-
- NSView* tabStripView = [self tabStripView];
- CGFloat tabStripHeight = NSHeight([tabStripView frame]);
- maxY -= tabStripHeight;
- [tabStripView setFrame:NSMakeRect(0, maxY, width, tabStripHeight)];
-
- // Set indentation.
- [tabStripController_ setIndentForControls:(fullscreen ? 0 :
- [[tabStripController_ class] defaultIndentForControls])];
-
- // TODO(viettrungluu): Seems kind of bad -- shouldn't |-layoutSubviews| do
- // this? Moreover, |-layoutTabs| will try to animate....
- [tabStripController_ layoutTabs];
-
- // Now lay out incognito badge together with the tab strip.
- if (incognitoBadge_.get()) {
- // Actually place the badge *above* |maxY|.
- NSPoint origin = NSMakePoint(width - NSWidth([incognitoBadge_ frame]) -
- kIncognitoBadgeOffset, maxY);
- [incognitoBadge_ setFrameOrigin:origin];
- [incognitoBadge_ setHidden:NO]; // Make sure it's shown.
- }
-
- return maxY;
-}
-
-- (CGFloat)layoutToolbarAtMinX:(CGFloat)minX
- maxY:(CGFloat)maxY
- width:(CGFloat)width {
- NSView* toolbarView = [toolbarController_ view];
- NSRect toolbarFrame = [toolbarView frame];
- if ([self hasToolbar]) {
- // The toolbar is present in the window, so we make room for it.
- DCHECK(![toolbarView isHidden]);
- toolbarFrame.origin.x = minX;
- toolbarFrame.origin.y = maxY - NSHeight(toolbarFrame);
- toolbarFrame.size.width = width;
- maxY -= NSHeight(toolbarFrame);
- } else {
- if ([self hasLocationBar]) {
- // Location bar is present with no toolbar. Put a border of
- // |kLocBar...Inset| pixels around the location bar.
- // TODO(viettrungluu): This is moderately ridiculous. The toolbar should
- // really be aware of what its height should be (the way the toolbar
- // compression stuff is currently set up messes things up).
- DCHECK(![toolbarView isHidden]);
- toolbarFrame.origin.x = kLocBarLeftRightInset;
- toolbarFrame.origin.y = maxY - NSHeight(toolbarFrame) - kLocBarTopInset;
- toolbarFrame.size.width = width - 2 * kLocBarLeftRightInset;
- maxY -= kLocBarTopInset + NSHeight(toolbarFrame) + kLocBarBottomInset;
- } else {
- DCHECK([toolbarView isHidden]);
- }
- }
- [toolbarView setFrame:toolbarFrame];
- return maxY;
-}
-
-- (BOOL)placeBookmarkBarBelowInfoBar {
- // If we are currently displaying the NTP detached bookmark bar or animating
- // to/from it (from/to anything else), we display the bookmark bar below the
- // infobar.
- return [bookmarkBarController_ isInState:bookmarks::kDetachedState] ||
- [bookmarkBarController_ isAnimatingToState:bookmarks::kDetachedState] ||
- [bookmarkBarController_ isAnimatingFromState:bookmarks::kDetachedState];
-}
-
-- (CGFloat)layoutBookmarkBarAtMinX:(CGFloat)minX
- maxY:(CGFloat)maxY
- width:(CGFloat)width {
- NSView* bookmarkBarView = [bookmarkBarController_ view];
- NSRect bookmarkBarFrame = [bookmarkBarView frame];
- BOOL oldHidden = [bookmarkBarView isHidden];
- BOOL newHidden = ![self isBookmarkBarVisible];
- if (oldHidden != newHidden)
- [bookmarkBarView setHidden:newHidden];
- bookmarkBarFrame.origin.x = minX;
- bookmarkBarFrame.origin.y = maxY - NSHeight(bookmarkBarFrame);
- bookmarkBarFrame.size.width = width;
- [bookmarkBarView setFrame:bookmarkBarFrame];
- maxY -= NSHeight(bookmarkBarFrame);
-
- // TODO(viettrungluu): Does this really belong here? Calling it shouldn't be
- // necessary in the non-NTP case.
- [bookmarkBarController_ layoutSubviews];
-
- return maxY;
-}
-
-- (void)layoutFloatingBarBackingView:(NSRect)frame
- fullscreen:(BOOL)fullscreen {
- // Only display when in fullscreen mode.
- if (fullscreen) {
- // For certain window types such as app windows (e.g., the dev tools
- // window), there's no actual overlay. (Displaying one would result in an
- // overly sliding in only under the menu, which gives an ugly effect.)
- if (floatingBarBackingView_.get()) {
- BOOL aboveBookmarkBar = [self placeBookmarkBarBelowInfoBar];
-
- // Insert it into the view hierarchy if necessary.
- if (![floatingBarBackingView_ superview] ||
- aboveBookmarkBar != floatingBarAboveBookmarkBar_) {
- NSView* contentView = [[self window] contentView];
- // z-order gets messed up unless we explicitly remove the floatingbar
- // view and re-add it.
- [floatingBarBackingView_ removeFromSuperview];
- [contentView addSubview:floatingBarBackingView_
- positioned:(aboveBookmarkBar ?
- NSWindowAbove : NSWindowBelow)
- relativeTo:[bookmarkBarController_ view]];
- floatingBarAboveBookmarkBar_ = aboveBookmarkBar;
- }
-
- // Set its frame.
- [floatingBarBackingView_ setFrame:frame];
- }
-
- // But we want the logic to work as usual (for show/hide/etc. purposes).
- [fullscreenController_ overlayFrameChanged:frame];
- } else {
- // Okay to call even if |floatingBarBackingView_| is nil.
- if ([floatingBarBackingView_ superview])
- [floatingBarBackingView_ removeFromSuperview];
- }
-}
-
-- (CGFloat)layoutInfoBarAtMinX:(CGFloat)minX
- maxY:(CGFloat)maxY
- width:(CGFloat)width {
- NSView* infoBarView = [infoBarContainerController_ view];
- NSRect infoBarFrame = [infoBarView frame];
- infoBarFrame.origin.x = minX;
- infoBarFrame.origin.y = maxY - NSHeight(infoBarFrame);
- infoBarFrame.size.width = width;
- [infoBarView setFrame:infoBarFrame];
- maxY -= NSHeight(infoBarFrame);
- return maxY;
-}
-
-- (CGFloat)layoutDownloadShelfAtMinX:(CGFloat)minX
- minY:(CGFloat)minY
- width:(CGFloat)width {
- if (downloadShelfController_.get()) {
- NSView* downloadView = [downloadShelfController_ view];
- NSRect downloadFrame = [downloadView frame];
- downloadFrame.origin.x = minX;
- downloadFrame.origin.y = minY;
- downloadFrame.size.width = width;
- [downloadView setFrame:downloadFrame];
- minY += NSHeight(downloadFrame);
- }
- return minY;
-}
-
-- (void)layoutTabContentArea:(NSRect)newFrame {
- NSView* tabContentView = [self tabContentArea];
- NSRect tabContentFrame = [tabContentView frame];
-
- bool contentShifted =
- NSMaxY(tabContentFrame) != NSMaxY(newFrame) ||
- NSMinX(tabContentFrame) != NSMinX(newFrame);
-
- tabContentFrame = newFrame;
- [tabContentView setFrame:tabContentFrame];
-
- // If the relayout shifts the content area up or down, let the renderer know.
- if (contentShifted) {
- if (TabContents* contents = browser_->GetSelectedTabContents()) {
- if (RenderWidgetHostView* rwhv = contents->GetRenderWidgetHostView())
- rwhv->WindowFrameChanged();
- }
- }
-}
-
-- (BOOL)shouldShowBookmarkBar {
- DCHECK(browser_.get());
- return browser_->profile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar) ?
- YES : NO;
-}
-
-- (BOOL)shouldShowDetachedBookmarkBar {
- DCHECK(browser_.get());
- TabContents* contents = browser_->GetSelectedTabContents();
- return (contents &&
- contents->ShouldShowBookmarkBar() &&
- ![previewableContentsController_ isShowingPreview]);
-}
-
-- (void)adjustToolbarAndBookmarkBarForCompression:(CGFloat)compression {
- CGFloat newHeight =
- [toolbarController_ desiredHeightForCompression:compression];
- NSRect toolbarFrame = [[toolbarController_ view] frame];
- CGFloat deltaH = newHeight - toolbarFrame.size.height;
-
- if (deltaH == 0)
- return;
-
- toolbarFrame.size.height = newHeight;
- NSRect bookmarkFrame = [[bookmarkBarController_ view] frame];
- bookmarkFrame.size.height = bookmarkFrame.size.height - deltaH;
- [[toolbarController_ view] setFrame:toolbarFrame];
- [[bookmarkBarController_ view] setFrame:bookmarkFrame];
- [self layoutSubviews];
-}
-
-// TODO(rohitrao): This function has shrunk into uselessness, and
-// |-setFullscreen:| has grown rather large. Find a good way to break up
-// |-setFullscreen:| into smaller pieces. http://crbug.com/36449
-- (void)adjustUIForFullscreen:(BOOL)fullscreen {
- // Create the floating bar backing view if necessary.
- if (fullscreen && !floatingBarBackingView_.get() &&
- ([self hasTabStrip] || [self hasToolbar] || [self hasLocationBar])) {
- floatingBarBackingView_.reset(
- [[FloatingBarBackingView alloc] initWithFrame:NSZeroRect]);
- }
-}
-
-- (void)enableBarVisibilityUpdates {
- // Early escape if there's nothing to do.
- if (barVisibilityUpdatesEnabled_)
- return;
-
- barVisibilityUpdatesEnabled_ = YES;
-
- if ([barVisibilityLocks_ count])
- [fullscreenController_ ensureOverlayShownWithAnimation:NO delay:NO];
- else
- [fullscreenController_ ensureOverlayHiddenWithAnimation:NO delay:NO];
-}
-
-- (void)disableBarVisibilityUpdates {
- // Early escape if there's nothing to do.
- if (!barVisibilityUpdatesEnabled_)
- return;
-
- barVisibilityUpdatesEnabled_ = NO;
- [fullscreenController_ cancelAnimationAndTimers];
-}
-
-@end // @implementation BrowserWindowController(Private)
diff --git a/chrome/browser/cocoa/browser_window_controller_unittest.mm b/chrome/browser/cocoa/browser_window_controller_unittest.mm
deleted file mode 100644
index 4e3a5ac..0000000
--- a/chrome/browser/cocoa/browser_window_controller_unittest.mm
+++ /dev/null
@@ -1,670 +0,0 @@
-// 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.
-
-#include "app/l10n_util_mac.h"
-#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_window.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#include "chrome/browser/cocoa/browser_window_controller.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/cocoa/find_bar_bridge.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/sync/sync_ui_util.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/test/testing_browser_process.h"
-#include "chrome/test/testing_profile.h"
-#include "grit/generated_resources.h"
-
-@interface BrowserWindowController (JustForTesting)
-// Already defined in BWC.
-- (void)saveWindowPositionToPrefs:(PrefService*)prefs;
-- (void)layoutSubviews;
-@end
-
-@interface BrowserWindowController (ExposedForTesting)
-// Implementations are below.
-- (NSView*)infoBarContainerView;
-- (NSView*)toolbarView;
-- (NSView*)bookmarkView;
-- (BOOL)bookmarkBarVisible;
-@end
-
-@implementation BrowserWindowController (ExposedForTesting)
-- (NSView*)infoBarContainerView {
- return [infoBarContainerController_ view];
-}
-
-- (NSView*)toolbarView {
- return [toolbarController_ view];
-}
-
-- (NSView*)bookmarkView {
- return [bookmarkBarController_ view];
-}
-
-- (NSView*)findBarView {
- return [findBarCocoaController_ view];
-}
-
-- (NSSplitView*)devToolsView {
- return static_cast<NSSplitView*>([devToolsController_ view]);
-}
-
-- (NSView*)sidebarView {
- return [sidebarController_ view];
-}
-
-- (BOOL)bookmarkBarVisible {
- return [bookmarkBarController_ isVisible];
-}
-@end
-
-class BrowserWindowControllerTest : public CocoaTest {
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
- Browser* browser = browser_helper_.browser();
- controller_ = [[BrowserWindowController alloc] initWithBrowser:browser
- takeOwnership:NO];
- }
-
- virtual void TearDown() {
- [controller_ close];
- CocoaTest::TearDown();
- }
-
- public:
- BrowserTestHelper browser_helper_;
- BrowserWindowController* controller_;
-};
-
-TEST_F(BrowserWindowControllerTest, TestSaveWindowPosition) {
- PrefService* prefs = browser_helper_.profile()->GetPrefs();
- ASSERT_TRUE(prefs != NULL);
-
- // Check to make sure there is no existing pref for window placement.
- ASSERT_TRUE(prefs->GetDictionary(prefs::kBrowserWindowPlacement) == NULL);
-
- // Ask the window to save its position, then check that a preference
- // exists. We're technically passing in a pointer to the user prefs
- // and not the local state prefs, but a PrefService* is a
- // PrefService*, and this is a unittest.
- [controller_ saveWindowPositionToPrefs:prefs];
- EXPECT_TRUE(prefs->GetDictionary(prefs::kBrowserWindowPlacement) != NULL);
-}
-
-TEST_F(BrowserWindowControllerTest, TestFullScreenWindow) {
- // Confirm that |-createFullscreenWindow| doesn't return nil.
- // See BrowserWindowFullScreenControllerTest for more fullscreen tests.
- EXPECT_TRUE([controller_ createFullscreenWindow]);
-}
-
-TEST_F(BrowserWindowControllerTest, TestNormal) {
- // Force the bookmark bar to be shown.
- browser_helper_.profile()->GetPrefs()->
- SetBoolean(prefs::kShowBookmarkBar, true);
- [controller_ updateBookmarkBarVisibilityWithAnimation:NO];
-
- // Make sure a normal BrowserWindowController is, uh, normal.
- EXPECT_TRUE([controller_ isNormalWindow]);
- EXPECT_TRUE([controller_ hasTabStrip]);
- EXPECT_FALSE([controller_ hasTitleBar]);
- EXPECT_TRUE([controller_ isBookmarkBarVisible]);
-
- // And make sure a controller for a pop-up window is not normal.
- // popup_browser will be owned by its window.
- Browser *popup_browser(Browser::CreateForType(Browser::TYPE_POPUP,
- browser_helper_.profile()));
- NSWindow *cocoaWindow = popup_browser->window()->GetNativeHandle();
- BrowserWindowController* controller =
- static_cast<BrowserWindowController*>([cocoaWindow windowController]);
- ASSERT_TRUE([controller isKindOfClass:[BrowserWindowController class]]);
- EXPECT_FALSE([controller isNormalWindow]);
- EXPECT_FALSE([controller hasTabStrip]);
- EXPECT_TRUE([controller hasTitleBar]);
- EXPECT_FALSE([controller isBookmarkBarVisible]);
- [controller close];
-}
-
-TEST_F(BrowserWindowControllerTest, TestTheme) {
- [controller_ userChangedTheme];
-}
-
-TEST_F(BrowserWindowControllerTest, BookmarkBarControllerIndirection) {
- EXPECT_FALSE([controller_ isBookmarkBarVisible]);
-
- // Explicitly show the bar. Can't use bookmark_utils::ToggleWhenVisible()
- // because of the notification issues.
- browser_helper_.profile()->GetPrefs()->
- SetBoolean(prefs::kShowBookmarkBar, true);
-
- [controller_ updateBookmarkBarVisibilityWithAnimation:NO];
- EXPECT_TRUE([controller_ isBookmarkBarVisible]);
-}
-
-#if 0
-// TODO(jrg): This crashes trying to create the BookmarkBarController, adding
-// an observer to the BookmarkModel.
-TEST_F(BrowserWindowControllerTest, TestIncognitoWidthSpace) {
- scoped_ptr<TestingProfile> incognito_profile(new TestingProfile());
- incognito_profile->set_off_the_record(true);
- scoped_ptr<Browser> browser(new Browser(Browser::TYPE_NORMAL,
- incognito_profile.get()));
- controller_.reset([[BrowserWindowController alloc]
- initWithBrowser:browser.get()
- takeOwnership:NO]);
-
- NSRect tabFrame = [[controller_ tabStripView] frame];
- [controller_ installIncognitoBadge];
- NSRect newTabFrame = [[controller_ tabStripView] frame];
- EXPECT_GT(tabFrame.size.width, newTabFrame.size.width);
-
- controller_.release();
-}
-#endif
-
-namespace {
-// Verifies that the toolbar, infobar, tab content area, and download shelf
-// completely fill the area under the tabstrip.
-void CheckViewPositions(BrowserWindowController* controller) {
- NSRect contentView = [[[controller window] contentView] bounds];
- NSRect tabstrip = [[controller tabStripView] frame];
- NSRect toolbar = [[controller toolbarView] frame];
- NSRect infobar = [[controller infoBarContainerView] frame];
- NSRect contentArea = [[controller tabContentArea] frame];
- NSRect download = [[[controller downloadShelf] view] frame];
-
- EXPECT_EQ(NSMinY(contentView), NSMinY(download));
- EXPECT_EQ(NSMaxY(download), NSMinY(contentArea));
- EXPECT_EQ(NSMaxY(contentArea), NSMinY(infobar));
-
- // Bookmark bar frame is random memory when hidden.
- if ([controller bookmarkBarVisible]) {
- NSRect bookmark = [[controller bookmarkView] frame];
- EXPECT_EQ(NSMaxY(infobar), NSMinY(bookmark));
- EXPECT_EQ(NSMaxY(bookmark), NSMinY(toolbar));
- EXPECT_FALSE([[controller bookmarkView] isHidden]);
- } else {
- EXPECT_EQ(NSMaxY(infobar), NSMinY(toolbar));
- EXPECT_TRUE([[controller bookmarkView] isHidden]);
- }
-
- // Toolbar should start immediately under the tabstrip, but the tabstrip is
- // not necessarily fixed with respect to the content view.
- EXPECT_EQ(NSMinY(tabstrip), NSMaxY(toolbar));
-}
-} // end namespace
-
-TEST_F(BrowserWindowControllerTest, TestAdjustWindowHeight) {
- NSWindow* window = [controller_ window];
- NSRect workarea = [[window screen] visibleFrame];
-
- // Place the window well above the bottom of the screen and try to adjust its
- // height. It should change appropriately (and only downwards). Then get it to
- // shrink by the same amount; it should return to its original state.
- NSRect initialFrame = NSMakeRect(workarea.origin.x, workarea.origin.y + 100,
- 200, 200);
- [window setFrame:initialFrame display:YES];
- [controller_ resetWindowGrowthState];
- [controller_ adjustWindowHeightBy:40];
- NSRect finalFrame = [window frame];
- EXPECT_FALSE(NSEqualRects(finalFrame, initialFrame));
- EXPECT_FLOAT_EQ(NSMaxY(finalFrame), NSMaxY(initialFrame));
- EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) + 40);
- [controller_ adjustWindowHeightBy:-40];
- finalFrame = [window frame];
- EXPECT_FLOAT_EQ(NSMaxY(finalFrame), NSMaxY(initialFrame));
- EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame));
-
- // Place the window at the bottom of the screen and try again. Its height
- // should still change, but it should not grow down below the work area; it
- // should instead move upwards. Then shrink it and make sure it goes back to
- // the way it was.
- initialFrame = NSMakeRect(workarea.origin.x, workarea.origin.y, 200, 200);
- [window setFrame:initialFrame display:YES];
- [controller_ resetWindowGrowthState];
- [controller_ adjustWindowHeightBy:40];
- finalFrame = [window frame];
- EXPECT_FALSE(NSEqualRects(finalFrame, initialFrame));
- EXPECT_FLOAT_EQ(NSMinY(finalFrame), NSMinY(initialFrame));
- EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) + 40);
- [controller_ adjustWindowHeightBy:-40];
- finalFrame = [window frame];
- EXPECT_FLOAT_EQ(NSMinY(finalFrame), NSMinY(initialFrame));
- EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame));
-
- // Put the window slightly offscreen and try again. The height should not
- // change this time.
- initialFrame = NSMakeRect(workarea.origin.x - 10, 0, 200, 200);
- [window setFrame:initialFrame display:YES];
- [controller_ resetWindowGrowthState];
- [controller_ adjustWindowHeightBy:40];
- EXPECT_TRUE(NSEqualRects([window frame], initialFrame));
- [controller_ adjustWindowHeightBy:-40];
- EXPECT_TRUE(NSEqualRects([window frame], initialFrame));
-
- // Make the window the same size as the workarea. Resizing both larger and
- // smaller should have no effect.
- [window setFrame:workarea display:YES];
- [controller_ resetWindowGrowthState];
- [controller_ adjustWindowHeightBy:40];
- EXPECT_TRUE(NSEqualRects([window frame], workarea));
- [controller_ adjustWindowHeightBy:-40];
- EXPECT_TRUE(NSEqualRects([window frame], workarea));
-
- // Make the window smaller than the workarea and place it near the bottom of
- // the workarea. The window should grow down until it hits the bottom and
- // then continue to grow up. Then shrink it, and it should return to where it
- // was.
- initialFrame = NSMakeRect(workarea.origin.x, workarea.origin.y + 5,
- 200, 200);
- [window setFrame:initialFrame display:YES];
- [controller_ resetWindowGrowthState];
- [controller_ adjustWindowHeightBy:40];
- finalFrame = [window frame];
- EXPECT_FLOAT_EQ(NSMinY(workarea), NSMinY(finalFrame));
- EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) + 40);
- [controller_ adjustWindowHeightBy:-40];
- finalFrame = [window frame];
- EXPECT_FLOAT_EQ(NSMinY(initialFrame), NSMinY(finalFrame));
- EXPECT_FLOAT_EQ(NSHeight(initialFrame), NSHeight(finalFrame));
-
- // Inset the window slightly from the workarea. It should not grow to be
- // larger than the workarea. Shrink it; it should return to where it started.
- initialFrame = NSInsetRect(workarea, 0, 5);
- [window setFrame:initialFrame display:YES];
- [controller_ resetWindowGrowthState];
- [controller_ adjustWindowHeightBy:40];
- finalFrame = [window frame];
- EXPECT_FLOAT_EQ(NSMinY(workarea), NSMinY(finalFrame));
- EXPECT_FLOAT_EQ(NSHeight(workarea), NSHeight(finalFrame));
- [controller_ adjustWindowHeightBy:-40];
- finalFrame = [window frame];
- EXPECT_FLOAT_EQ(NSMinY(initialFrame), NSMinY(finalFrame));
- EXPECT_FLOAT_EQ(NSHeight(initialFrame), NSHeight(finalFrame));
-
- // Place the window at the bottom of the screen and grow; it should grow
- // upwards. Move the window off the bottom, then shrink. It should then shrink
- // from the bottom.
- initialFrame = NSMakeRect(workarea.origin.x, workarea.origin.y, 200, 200);
- [window setFrame:initialFrame display:YES];
- [controller_ resetWindowGrowthState];
- [controller_ adjustWindowHeightBy:40];
- finalFrame = [window frame];
- EXPECT_FALSE(NSEqualRects(finalFrame, initialFrame));
- EXPECT_FLOAT_EQ(NSMinY(finalFrame), NSMinY(initialFrame));
- EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) + 40);
- NSPoint oldOrigin = initialFrame.origin;
- NSPoint newOrigin = NSMakePoint(oldOrigin.x, oldOrigin.y + 10);
- [window setFrameOrigin:newOrigin];
- initialFrame = [window frame];
- EXPECT_FLOAT_EQ(NSMinY(initialFrame), oldOrigin.y + 10);
- [controller_ adjustWindowHeightBy:-40];
- finalFrame = [window frame];
- EXPECT_FLOAT_EQ(NSMinY(finalFrame), NSMinY(initialFrame) + 40);
- EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) - 40);
-
- // Do the "inset" test above, but using multiple calls to
- // |-adjustWindowHeightBy|; the result should be the same.
- initialFrame = NSInsetRect(workarea, 0, 5);
- [window setFrame:initialFrame display:YES];
- [controller_ resetWindowGrowthState];
- for (int i = 0; i < 8; i++)
- [controller_ adjustWindowHeightBy:5];
- finalFrame = [window frame];
- EXPECT_FLOAT_EQ(NSMinY(workarea), NSMinY(finalFrame));
- EXPECT_FLOAT_EQ(NSHeight(workarea), NSHeight(finalFrame));
- for (int i = 0; i < 8; i++)
- [controller_ adjustWindowHeightBy:-5];
- finalFrame = [window frame];
- EXPECT_FLOAT_EQ(NSMinY(initialFrame), NSMinY(finalFrame));
- EXPECT_FLOAT_EQ(NSHeight(initialFrame), NSHeight(finalFrame));
-}
-
-// Test to make sure resizing and relaying-out subviews works correctly.
-TEST_F(BrowserWindowControllerTest, TestResizeViews) {
- TabStripView* tabstrip = [controller_ tabStripView];
- NSView* contentView = [[tabstrip window] contentView];
- NSView* toolbar = [controller_ toolbarView];
- NSView* infobar = [controller_ infoBarContainerView];
-
- // We need to muck with the views a bit to put us in a consistent state before
- // we start resizing. In particular, we need to move the tab strip to be
- // immediately above the content area, since we layout views to be directly
- // under the tab strip.
- NSRect tabstripFrame = [tabstrip frame];
- tabstripFrame.origin.y = NSMaxY([contentView frame]);
- [tabstrip setFrame:tabstripFrame];
-
- // The download shelf is created lazily. Force-create it and set its initial
- // height to 0.
- NSView* download = [[controller_ downloadShelf] view];
- NSRect downloadFrame = [download frame];
- downloadFrame.size.height = 0;
- [download setFrame:downloadFrame];
-
- // Force a layout and check each view's frame.
- [controller_ layoutSubviews];
- CheckViewPositions(controller_);
-
- // Expand the infobar to 60px and recheck
- [controller_ resizeView:infobar newHeight:60];
- CheckViewPositions(controller_);
-
- // Expand the toolbar to 64px and recheck
- [controller_ resizeView:toolbar newHeight:64];
- CheckViewPositions(controller_);
-
- // Add a 30px download shelf and recheck
- [controller_ resizeView:download newHeight:30];
- CheckViewPositions(controller_);
-
- // Shrink the infobar to 0px and toolbar to 39px and recheck
- [controller_ resizeView:infobar newHeight:0];
- [controller_ resizeView:toolbar newHeight:39];
- CheckViewPositions(controller_);
-}
-
-TEST_F(BrowserWindowControllerTest, TestResizeViewsWithBookmarkBar) {
- // Force a display of the bookmark bar.
- browser_helper_.profile()->GetPrefs()->
- SetBoolean(prefs::kShowBookmarkBar, true);
- [controller_ updateBookmarkBarVisibilityWithAnimation:NO];
-
- TabStripView* tabstrip = [controller_ tabStripView];
- NSView* contentView = [[tabstrip window] contentView];
- NSView* toolbar = [controller_ toolbarView];
- NSView* bookmark = [controller_ bookmarkView];
- NSView* infobar = [controller_ infoBarContainerView];
-
- // We need to muck with the views a bit to put us in a consistent state before
- // we start resizing. In particular, we need to move the tab strip to be
- // immediately above the content area, since we layout views to be directly
- // under the tab strip.
- NSRect tabstripFrame = [tabstrip frame];
- tabstripFrame.origin.y = NSMaxY([contentView frame]);
- [tabstrip setFrame:tabstripFrame];
-
- // The download shelf is created lazily. Force-create it and set its initial
- // height to 0.
- NSView* download = [[controller_ downloadShelf] view];
- NSRect downloadFrame = [download frame];
- downloadFrame.size.height = 0;
- [download setFrame:downloadFrame];
-
- // Force a layout and check each view's frame.
- [controller_ layoutSubviews];
- CheckViewPositions(controller_);
-
- // Add the bookmark bar and recheck.
- [controller_ resizeView:bookmark newHeight:40];
- CheckViewPositions(controller_);
-
- // Expand the infobar to 60px and recheck
- [controller_ resizeView:infobar newHeight:60];
- CheckViewPositions(controller_);
-
- // Expand the toolbar to 64px and recheck
- [controller_ resizeView:toolbar newHeight:64];
- CheckViewPositions(controller_);
-
- // Add a 30px download shelf and recheck
- [controller_ resizeView:download newHeight:30];
- CheckViewPositions(controller_);
-
- // Remove the bookmark bar and recheck
- browser_helper_.profile()->GetPrefs()->
- SetBoolean(prefs::kShowBookmarkBar, false);
- [controller_ resizeView:bookmark newHeight:0];
- CheckViewPositions(controller_);
-
- // Shrink the infobar to 0px and toolbar to 39px and recheck
- [controller_ resizeView:infobar newHeight:0];
- [controller_ resizeView:toolbar newHeight:39];
- CheckViewPositions(controller_);
-}
-
-// Make sure, by default, the bookmark bar and the toolbar are the same width.
-TEST_F(BrowserWindowControllerTest, BookmarkBarIsSameWidth) {
- // Set the pref to the bookmark bar is visible when the toolbar is
- // first created.
- browser_helper_.profile()->GetPrefs()->SetBoolean(
- prefs::kShowBookmarkBar, true);
-
- // Make sure the bookmark bar is the same width as the toolbar
- NSView* bookmarkBarView = [controller_ bookmarkView];
- NSView* toolbarView = [controller_ toolbarView];
- EXPECT_EQ([toolbarView frame].size.width,
- [bookmarkBarView frame].size.width);
-}
-
-TEST_F(BrowserWindowControllerTest, TestTopRightForBubble) {
- NSPoint p = [controller_ bookmarkBubblePoint];
- NSRect all = [[controller_ window] frame];
-
- // As a sanity check make sure the point is vaguely in the top right
- // of the window.
- EXPECT_GT(p.y, all.origin.y + (all.size.height/2));
- EXPECT_GT(p.x, all.origin.x + (all.size.width/2));
-}
-
-// By the "zoom frame", we mean what Apple calls the "standard frame".
-TEST_F(BrowserWindowControllerTest, TestZoomFrame) {
- NSWindow* window = [controller_ window];
- ASSERT_TRUE(window);
- NSRect screenFrame = [[window screen] visibleFrame];
- ASSERT_FALSE(NSIsEmptyRect(screenFrame));
-
- // Minimum zoomed width is the larger of 60% of available horizontal space or
- // 60% of available vertical space, subject to available horizontal space.
- CGFloat minZoomWidth =
- std::min(std::max((CGFloat)0.6 * screenFrame.size.width,
- (CGFloat)0.6 * screenFrame.size.height),
- screenFrame.size.width);
-
- // |testFrame| is the size of the window we start out with, and |zoomFrame| is
- // the one returned by |-windowWillUseStandardFrame:defaultFrame:|.
- NSRect testFrame;
- NSRect zoomFrame;
-
- // 1. Test a case where it zooms the window both horizontally and vertically,
- // and only moves it vertically. "+ 32", etc. are just arbitrary constants
- // used to check that the window is moved properly and not just to the origin;
- // they should be small enough to not shove windows off the screen.
- testFrame.size.width = 0.5 * minZoomWidth;
- testFrame.size.height = 0.5 * screenFrame.size.height;
- testFrame.origin.x = screenFrame.origin.x + 32; // See above.
- testFrame.origin.y = screenFrame.origin.y + 23;
- [window setFrame:testFrame display:NO];
- zoomFrame = [controller_ windowWillUseStandardFrame:window
- defaultFrame:screenFrame];
- EXPECT_LE(minZoomWidth, zoomFrame.size.width);
- EXPECT_EQ(screenFrame.size.height, zoomFrame.size.height);
- EXPECT_EQ(testFrame.origin.x, zoomFrame.origin.x);
- EXPECT_EQ(screenFrame.origin.y, zoomFrame.origin.y);
-
- // 2. Test a case where it zooms the window only horizontally, and only moves
- // it horizontally.
- testFrame.size.width = 0.5 * minZoomWidth;
- testFrame.size.height = screenFrame.size.height;
- testFrame.origin.x = screenFrame.origin.x + screenFrame.size.width -
- testFrame.size.width;
- testFrame.origin.y = screenFrame.origin.y;
- [window setFrame:testFrame display:NO];
- zoomFrame = [controller_ windowWillUseStandardFrame:window
- defaultFrame:screenFrame];
- EXPECT_LE(minZoomWidth, zoomFrame.size.width);
- EXPECT_EQ(screenFrame.size.height, zoomFrame.size.height);
- EXPECT_EQ(screenFrame.origin.x + screenFrame.size.width -
- zoomFrame.size.width, zoomFrame.origin.x);
- EXPECT_EQ(screenFrame.origin.y, zoomFrame.origin.y);
-
- // 3. Test a case where it zooms the window only vertically, and only moves it
- // vertically.
- testFrame.size.width = std::min((CGFloat)1.1 * minZoomWidth,
- screenFrame.size.width);
- testFrame.size.height = 0.3 * screenFrame.size.height;
- testFrame.origin.x = screenFrame.origin.x + 32; // See above (in 1.).
- testFrame.origin.y = screenFrame.origin.y + 123;
- [window setFrame:testFrame display:NO];
- zoomFrame = [controller_ windowWillUseStandardFrame:window
- defaultFrame:screenFrame];
- // Use the actual width of the window frame, since it's subject to rounding.
- EXPECT_EQ([window frame].size.width, zoomFrame.size.width);
- EXPECT_EQ(screenFrame.size.height, zoomFrame.size.height);
- EXPECT_EQ(testFrame.origin.x, zoomFrame.origin.x);
- EXPECT_EQ(screenFrame.origin.y, zoomFrame.origin.y);
-
- // 4. Test a case where zooming should do nothing (i.e., we're already at a
- // zoomed frame).
- testFrame.size.width = std::min((CGFloat)1.1 * minZoomWidth,
- screenFrame.size.width);
- testFrame.size.height = screenFrame.size.height;
- testFrame.origin.x = screenFrame.origin.x + 32; // See above (in 1.).
- testFrame.origin.y = screenFrame.origin.y;
- [window setFrame:testFrame display:NO];
- zoomFrame = [controller_ windowWillUseStandardFrame:window
- defaultFrame:screenFrame];
- // Use the actual width of the window frame, since it's subject to rounding.
- EXPECT_EQ([window frame].size.width, zoomFrame.size.width);
- EXPECT_EQ(screenFrame.size.height, zoomFrame.size.height);
- EXPECT_EQ(testFrame.origin.x, zoomFrame.origin.x);
- EXPECT_EQ(screenFrame.origin.y, zoomFrame.origin.y);
-}
-
-TEST_F(BrowserWindowControllerTest, TestFindBarOnTop) {
- FindBarBridge bridge;
- [controller_ addFindBar:bridge.find_bar_cocoa_controller()];
-
- // Test that the Z-order of the find bar is on top of everything.
- NSArray* subviews = [[[controller_ window] contentView] subviews];
- NSUInteger findBar_index =
- [subviews indexOfObject:[controller_ findBarView]];
- EXPECT_NE(NSNotFound, findBar_index);
- NSUInteger toolbar_index =
- [subviews indexOfObject:[controller_ toolbarView]];
- EXPECT_NE(NSNotFound, toolbar_index);
- NSUInteger bookmark_index =
- [subviews indexOfObject:[controller_ bookmarkView]];
- EXPECT_NE(NSNotFound, bookmark_index);
-
- EXPECT_GT(findBar_index, toolbar_index);
- EXPECT_GT(findBar_index, bookmark_index);
-}
-
-// Tests that the sidebar view and devtools view are both non-opaque.
-TEST_F(BrowserWindowControllerTest, TestSplitViewsAreNotOpaque) {
- // Add a subview to the sidebar view to mimic what happens when a tab is added
- // to the window. NSSplitView only marks itself as non-opaque when one of its
- // subviews is non-opaque, so the test will not pass without this subview.
- scoped_nsobject<NSView> view(
- [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 10, 10)]);
- [[controller_ sidebarView] addSubview:view];
-
- EXPECT_FALSE([[controller_ tabContentArea] isOpaque]);
- EXPECT_FALSE([[controller_ devToolsView] isOpaque]);
- EXPECT_FALSE([[controller_ sidebarView] isOpaque]);
-}
-
-// Tests that status bubble's base frame does move when devTools are docked.
-TEST_F(BrowserWindowControllerTest, TestStatusBubblePositioning) {
- ASSERT_EQ(1U, [[[controller_ devToolsView] subviews] count]);
-
- NSPoint bubbleOrigin = [controller_ statusBubbleBaseFrame].origin;
-
- // Add a fake subview to devToolsView to emulate docked devTools.
- scoped_nsobject<NSView> view(
- [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 10, 10)]);
- [[controller_ devToolsView] addSubview:view];
- [[controller_ devToolsView] adjustSubviews];
-
- NSPoint bubbleOriginWithDevTools = [controller_ statusBubbleBaseFrame].origin;
-
- // Make sure that status bubble frame is moved.
- EXPECT_FALSE(NSEqualPoints(bubbleOrigin, bubbleOriginWithDevTools));
-}
-
-@interface BrowserWindowControllerFakeFullscreen : BrowserWindowController {
- @private
- // We release the window ourselves, so we don't have to rely on the unittest
- // doing it for us.
- scoped_nsobject<NSWindow> fullscreenWindow_;
-}
-@end
-
-class BrowserWindowFullScreenControllerTest : public CocoaTest {
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
- Browser* browser = browser_helper_.browser();
- controller_ =
- [[BrowserWindowControllerFakeFullscreen alloc] initWithBrowser:browser
- takeOwnership:NO];
- }
-
- virtual void TearDown() {
- [controller_ close];
- CocoaTest::TearDown();
- }
-
- public:
- BrowserTestHelper browser_helper_;
- BrowserWindowController* controller_;
-};
-
-@interface BrowserWindowController (PrivateAPI)
-- (BOOL)supportsFullscreen;
-@end
-
-TEST_F(BrowserWindowFullScreenControllerTest, TestFullscreen) {
- EXPECT_FALSE([controller_ isFullscreen]);
- [controller_ setFullscreen:YES];
- EXPECT_TRUE([controller_ isFullscreen]);
- [controller_ setFullscreen:NO];
- EXPECT_FALSE([controller_ isFullscreen]);
-}
-
-// If this test fails, it is usually a sign that the bots have some sort of
-// problem (such as a modal dialog up). This tests is a very useful canary, so
-// please do not mark it as flaky without first verifying that there are no bot
-// problems.
-TEST_F(BrowserWindowFullScreenControllerTest, TestActivate) {
- EXPECT_FALSE([controller_ isFullscreen]);
-
- [controller_ activate];
- NSWindow* frontmostWindow = [[NSApp orderedWindows] objectAtIndex:0];
- EXPECT_EQ(frontmostWindow, [controller_ window]);
-
- [controller_ setFullscreen:YES];
- [controller_ activate];
- frontmostWindow = [[NSApp orderedWindows] objectAtIndex:0];
- EXPECT_EQ(frontmostWindow, [controller_ createFullscreenWindow]);
-
- // We have to cleanup after ourselves by unfullscreening.
- [controller_ setFullscreen:NO];
-}
-
-@implementation BrowserWindowControllerFakeFullscreen
-// Override |-createFullscreenWindow| to return a dummy window. This isn't
-// needed to pass the test, but because the dummy window is only 100x100, it
-// prevents the real fullscreen window from flashing up and taking over the
-// whole screen. We have to return an actual window because |-layoutSubviews|
-// looks at the window's frame.
-- (NSWindow*)createFullscreenWindow {
- if (fullscreenWindow_.get())
- return fullscreenWindow_.get();
-
- fullscreenWindow_.reset(
- [[NSWindow alloc] initWithContentRect:NSMakeRect(0,0,400,400)
- styleMask:NSBorderlessWindowMask
- backing:NSBackingStoreBuffered
- defer:NO]);
- return fullscreenWindow_.get();
-}
-@end
-
-/* TODO(???): test other methods of BrowserWindowController */
diff --git a/chrome/browser/cocoa/browser_window_factory.mm b/chrome/browser/cocoa/browser_window_factory.mm
deleted file mode 100644
index 41d2de4..0000000
--- a/chrome/browser/cocoa/browser_window_factory.mm
+++ /dev/null
@@ -1,32 +0,0 @@
-// 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.
-
-#include "base/basictypes.h"
-#include "chrome/browser/cocoa/browser_window_cocoa.h"
-#include "chrome/browser/cocoa/browser_window_controller.h"
-#include "chrome/browser/cocoa/find_bar_bridge.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_window.h"
-
-// Create the controller for the Browser, which handles loading the browser
-// window from the nib. The controller takes ownership of |browser|.
-// static
-BrowserWindow* BrowserWindow::CreateBrowserWindow(Browser* browser) {
- BrowserWindowController* controller =
- [[BrowserWindowController alloc] initWithBrowser:browser];
- return [controller browserWindow];
-}
-
-// static
-FindBar* BrowserWindow::CreateFindBar(Browser* browser) {
- // We could push the AddFindBar() call into the FindBarBridge
- // constructor or the FindBarCocoaController init, but that makes
- // unit testing difficult, since we would also require a
- // BrowserWindow object.
- BrowserWindowCocoa* window =
- static_cast<BrowserWindowCocoa*>(browser->window());
- FindBarBridge* bridge = new FindBarBridge();
- window->AddFindBar(bridge->find_bar_cocoa_controller());
- return bridge;
-}
diff --git a/chrome/browser/cocoa/bubble_view.mm b/chrome/browser/cocoa/bubble_view.mm
deleted file mode 100644
index e7815b8..0000000
--- a/chrome/browser/cocoa/bubble_view.mm
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/bubble_view.h"
-
-#import "chrome/browser/cocoa/themed_window.h"
-#include "chrome/browser/themes/browser_theme_provider.h"
-#import "third_party/GTM/AppKit/GTMNSBezierPath+RoundRect.h"
-#import "third_party/GTM/AppKit/GTMNSColor+Luminance.h"
-
-// The roundedness of the edges of our bubble.
-const int kBubbleCornerRadius = 4.0f;
-const float kWindowEdge = 0.7f;
-
-@implementation BubbleView
-
-// Designated initializer. |provider| is the window from which we get the
-// current theme to draw text and backgrounds. If nil, the current window will
-// be checked. The caller needs to ensure |provider| can't go away as it will
-// not be retained. Defaults to all corners being rounded.
-- (id)initWithFrame:(NSRect)frame themeProvider:(NSWindow*)provider {
- if ((self = [super initWithFrame:frame])) {
- cornerFlags_ = kRoundedAllCorners;
- themeProvider_ = provider;
- }
- return self;
-}
-
-// Sets the string displayed in the bubble. A copy of the string is made.
-- (void)setContent:(NSString*)content {
- if ([content_ isEqualToString:content])
- return;
- content_.reset([content copy]);
- [self setNeedsDisplay:YES];
-}
-
-// Sets which corners will be rounded.
-- (void)setCornerFlags:(unsigned long)flags {
- if (cornerFlags_ == flags)
- return;
- cornerFlags_ = flags;
- [self setNeedsDisplay:YES];
-}
-
-- (void)setThemeProvider:(NSWindow*)provider {
- if (themeProvider_ == provider)
- return;
- themeProvider_ = provider;
- [self setNeedsDisplay:YES];
-}
-
-- (NSString*)content {
- return content_.get();
-}
-
-- (unsigned long)cornerFlags {
- return cornerFlags_;
-}
-
-// The font used to display the content string.
-- (NSFont*)font {
- return [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
-}
-
-// Draws the themed background and the text. Will draw a gray bg if no theme.
-- (void)drawRect:(NSRect)rect {
- float topLeftRadius =
- cornerFlags_ & kRoundedTopLeftCorner ? kBubbleCornerRadius : 0;
- float topRightRadius =
- cornerFlags_ & kRoundedTopRightCorner ? kBubbleCornerRadius : 0;
- float bottomLeftRadius =
- cornerFlags_ & kRoundedBottomLeftCorner ? kBubbleCornerRadius : 0;
- float bottomRightRadius =
- cornerFlags_ & kRoundedBottomRightCorner ? kBubbleCornerRadius : 0;
-
- ThemeProvider* themeProvider =
- themeProvider_ ? [themeProvider_ themeProvider] :
- [[self window] themeProvider];
-
- // Background / Edge
-
- NSRect bounds = [self bounds];
- bounds = NSInsetRect(bounds, 0.5, 0.5);
- NSBezierPath* border =
- [NSBezierPath gtm_bezierPathWithRoundRect:bounds
- topLeftCornerRadius:topLeftRadius
- topRightCornerRadius:topRightRadius
- bottomLeftCornerRadius:bottomLeftRadius
- bottomRightCornerRadius:bottomRightRadius];
-
- if (themeProvider)
- [themeProvider->GetNSColor(BrowserThemeProvider::COLOR_TOOLBAR, true) set];
- [border fill];
-
- [[NSColor colorWithDeviceWhite:kWindowEdge alpha:1.0f] set];
- [border stroke];
-
- // Text
- NSColor* textColor = [NSColor blackColor];
- if (themeProvider)
- textColor = themeProvider->GetNSColor(BrowserThemeProvider::COLOR_TAB_TEXT,
- true);
- NSFont* textFont = [self font];
- scoped_nsobject<NSShadow> textShadow([[NSShadow alloc] init]);
- [textShadow setShadowBlurRadius:0.0f];
- [textShadow.get() setShadowColor:[textColor gtm_legibleTextColor]];
- [textShadow.get() setShadowOffset:NSMakeSize(0.0f, -1.0f)];
-
- NSDictionary* textDict = [NSDictionary dictionaryWithObjectsAndKeys:
- textColor, NSForegroundColorAttributeName,
- textFont, NSFontAttributeName,
- textShadow.get(), NSShadowAttributeName,
- nil];
- [content_ drawAtPoint:NSMakePoint(kBubbleViewTextPositionX,
- kBubbleViewTextPositionY)
- withAttributes:textDict];
-}
-
-@end
diff --git a/chrome/browser/cocoa/bubble_view_unittest.mm b/chrome/browser/cocoa/bubble_view_unittest.mm
deleted file mode 100644
index 3b3bf77..0000000
--- a/chrome/browser/cocoa/bubble_view_unittest.mm
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2009 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/scoped_nsobject.h"
-#import "chrome/browser/cocoa/bubble_view.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "testing/gtest_mac.h"
-
-class BubbleViewTest : public CocoaTest {
- public:
- BubbleViewTest() {
- NSRect frame = NSMakeRect(0, 0, 50, 50);
- scoped_nsobject<BubbleView> view(
- [[BubbleView alloc] initWithFrame:frame themeProvider:test_window()]);
- view_ = view.get();
- [[test_window() contentView] addSubview:view_];
- [view_ setContent:@"Hi there, I'm a bubble view"];
- }
-
- BubbleView* view_;
-};
-
-TEST_VIEW(BubbleViewTest, view_);
-
-// Test a nil themeProvider in init.
-TEST_F(BubbleViewTest, NilThemeProvider) {
- NSRect frame = NSMakeRect(0, 0, 50, 50);
- scoped_nsobject<BubbleView> view(
- [[BubbleView alloc] initWithFrame:frame themeProvider:nil]);
- [[test_window() contentView] addSubview:view.get()];
- [view display];
-}
-
-// Make sure things don't go haywire when given invalid or long strings.
-TEST_F(BubbleViewTest, SetContent) {
- [view_ setContent:nil];
- EXPECT_TRUE([view_ content] == nil);
- [view_ setContent:@""];
- EXPECT_NSEQ(@"", [view_ content]);
- NSString* str = @"This is a really really long string that's just too long";
- [view_ setContent:str];
- EXPECT_NSEQ(str, [view_ content]);
-}
-
-TEST_F(BubbleViewTest, CornerFlags) {
- // Set some random flags just to check.
- [view_ setCornerFlags:kRoundedTopRightCorner | kRoundedTopLeftCorner];
- EXPECT_EQ([view_ cornerFlags],
- (unsigned long)kRoundedTopRightCorner | kRoundedTopLeftCorner);
- // Set no flags (all 4 draw corners are square).
- [view_ setCornerFlags:0];
- EXPECT_EQ([view_ cornerFlags], 0UL);
- // Set all bits. Meaningless past the first 4, but harmless to set too many.
- [view_ setCornerFlags:0xFFFFFFFF];
- EXPECT_EQ([view_ cornerFlags], 0xFFFFFFFF);
-}
diff --git a/chrome/browser/cocoa/bug_report_window_controller.h b/chrome/browser/cocoa/bug_report_window_controller.h
deleted file mode 100644
index 116044a..0000000
--- a/chrome/browser/cocoa/bug_report_window_controller.h
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_BUG_REPORT_WINDOW_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_BUG_REPORT_WINDOW_CONTROLLER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include <vector>
-
-#include "base/scoped_nsobject.h"
-
-class Profile;
-class TabContents;
-
-// A window controller for managing the "Report Bug" feature. Modally
-// presents a dialog that allows the user to either file a bug report on
-// a broken page, or go directly to Google's "Report Phishing" page and
-// file a report there.
-@interface BugReportWindowController : NSWindowController {
- @private
- TabContents* currentTab_; // Weak, owned by browser.
- Profile* profile_; // Weak, owned by browser.
-
- // Holds screenshot of current tab.
- std::vector<unsigned char> pngData_;
- // Width and height of the current tab's screenshot.
- int pngWidth_;
- int pngHeight_;
-
- // Values bound to data in the dialog box. These values cannot be boxed in
- // scoped_nsobjects because we use them for bindings.
- NSString* bugDescription_; // Strong.
- NSUInteger bugTypeIndex_;
- NSString* pageTitle_; // Strong.
- NSString* pageURL_; // Strong.
-
- // We keep a pointer to this button so we can change its title.
- IBOutlet NSButton* sendReportButton_;
-
- // This button must be moved when the send report button changes title.
- IBOutlet NSButton* cancelButton_;
-
- // The popup button that allows choice of bug type.
- IBOutlet NSPopUpButton* bugTypePopUpButton_;
-
- // YES sends a screenshot along with the bug report.
- BOOL sendScreenshot_;
-
- // Disable screenshot if no browser window is open.
- BOOL disableScreenshotCheckbox_;
-
- // Menu for the bug type popup button. We create it here instead of in
- // IB so that we can nicely check whether the phishing page is selected,
- // and so that we can create a menu without "page" options when no browser
- // window is open.
- NSMutableArray* bugTypeList_; // Strong.
-
- // When dialog switches from regular bug reports to phishing page, "save
- // screenshot" and "description" are disabled. Save the state of this value
- // to restore if the user switches back to a regular bug report before
- // sending.
- BOOL saveSendScreenshot_;
- scoped_nsobject<NSString> saveBugDescription_; // Strong
-
- // Maps bug type menu item title strings to BugReportUtil::BugType ints.
- NSDictionary* bugTypeDictionary_; // Strong
-}
-
-// Initialize with the contents of the tab to be reported as buggy / wrong.
-// If dialog is called without an open window, currentTab may be null; in
-// that case, a dialog is opened with options for reporting a bugs not
-// related to a specific page. Profile is passed to BugReportUtil, who
-// will not send a report if the value is null.
-- (id)initWithTabContents:(TabContents*)currentTab profile:(Profile*)profile;
-
-// Run the dialog with an application-modal event loop. If the user accepts,
-// send the report of the bug or broken web site.
-- (void)runModalDialog;
-
-// IBActions for the dialog buttons.
-- (IBAction)sendReport:(id)sender;
-- (IBAction)cancel:(id)sender;
-
-// YES if the user has selected the phishing report option.
-- (BOOL)isPhishingReport;
-
-// Converts the bug type from the menu into the correct value for the bug type
-// from BugReportUtil::BugType.
-- (int)bugTypeFromIndex;
-
-// Force the description text field to allow "return" to go to the next line
-// within the description field. Without this delegate method, "return" falls
-// back to the "Send Report" action, because this button has been bound to
-// the return key in IB.
-- (BOOL)control:(NSControl*)control textView:(NSTextView*)textView
- doCommandBySelector:(SEL)commandSelector;
-
-// Properties for bindings.
-@property (nonatomic, copy) NSString* bugDescription;
-@property (nonatomic) NSUInteger bugTypeIndex;
-@property (nonatomic, copy) NSString* pageTitle;
-@property (nonatomic, copy) NSString* pageURL;
-@property (nonatomic) BOOL sendScreenshot;
-@property (nonatomic) BOOL disableScreenshotCheckbox;
-@property (nonatomic, readonly) NSArray* bugTypeList;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_BUG_REPORT_WINDOW_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/bug_report_window_controller.mm b/chrome/browser/cocoa/bug_report_window_controller.mm
deleted file mode 100644
index df29f99..0000000
--- a/chrome/browser/cocoa/bug_report_window_controller.mm
+++ /dev/null
@@ -1,231 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/bug_report_window_controller.h"
-
-#include "app/l10n_util_mac.h"
-#include "base/mac_util.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/bug_report_util.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents/tab_contents_view.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-
-@implementation BugReportWindowController
-
-@synthesize bugDescription = bugDescription_;
-@synthesize bugTypeIndex = bugTypeIndex_;
-@synthesize pageURL = pageURL_;
-@synthesize pageTitle = pageTitle_;
-@synthesize sendScreenshot = sendScreenshot_;
-@synthesize disableScreenshotCheckbox = disableScreenshotCheckbox_;
-@synthesize bugTypeList = bugTypeList_;
-
-- (id)initWithTabContents:(TabContents*)currentTab
- profile:(Profile*)profile {
- NSString* nibpath = [mac_util::MainAppBundle() pathForResource:@"ReportBug"
- ofType:@"nib"];
- if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
- currentTab_ = currentTab;
- profile_ = profile;
-
- // The order of strings in this array must match the order of the bug types
- // declared below in the bugTypeFromIndex function.
- bugTypeList_ = [[NSMutableArray alloc] initWithObjects:
- l10n_util::GetNSStringWithFixup(IDS_BUGREPORT_CHROME_MISBEHAVES),
- l10n_util::GetNSStringWithFixup(IDS_BUGREPORT_SOMETHING_MISSING),
- l10n_util::GetNSStringWithFixup(IDS_BUGREPORT_BROWSER_CRASH),
- l10n_util::GetNSStringWithFixup(IDS_BUGREPORT_OTHER_PROBLEM),
- nil];
-
- if (currentTab_ != NULL) {
- // Get data from current tab, if one exists. This dialog could be called
- // from the main menu with no tab contents, so currentTab_ is not
- // guaranteed to be non-NULL.
- // TODO(mirandac): This dialog should be a tab-modal sheet if a browser
- // window exists.
- [self setSendScreenshot:YES];
- [self setDisableScreenshotCheckbox:NO];
- // Insert menu items about bugs related to specific pages.
- [bugTypeList_ insertObjects:
- [NSArray arrayWithObjects:
- l10n_util::GetNSStringWithFixup(IDS_BUGREPORT_PAGE_WONT_LOAD),
- l10n_util::GetNSStringWithFixup(IDS_BUGREPORT_PAGE_LOOKS_ODD),
- l10n_util::GetNSStringWithFixup(IDS_BUGREPORT_PHISHING_PAGE),
- l10n_util::GetNSStringWithFixup(IDS_BUGREPORT_CANT_SIGN_IN),
- nil]
- atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 4)]];
-
- [self setPageURL:base::SysUTF8ToNSString(
- currentTab_->controller().GetActiveEntry()->url().spec())];
- [self setPageTitle:base::SysUTF16ToNSString(currentTab_->GetTitle())];
- mac_util::GrabWindowSnapshot(
- currentTab_->view()->GetTopLevelNativeWindow(), &pngData_,
- &pngWidth_, &pngHeight_);
- } else {
- // If no current tab exists, create a menu without the "broken page"
- // options, with page URL and title empty, and screenshot disabled.
- [self setSendScreenshot:NO];
- [self setDisableScreenshotCheckbox:YES];
- }
-
- pngHeight_ = 0;
- pngWidth_ = 0;
- }
- return self;
-}
-
-- (void)dealloc {
- [pageURL_ release];
- [pageTitle_ release];
- [bugDescription_ release];
- [bugTypeList_ release];
- [bugTypeDictionary_ release];
- [super dealloc];
-}
-
-// Delegate callback so that closing the window deletes the controller.
-- (void)windowWillClose:(NSNotification*)notification {
- [self autorelease];
-}
-
-- (void)closeDialog {
- [NSApp stopModal];
- [[self window] close];
-}
-
-- (void)runModalDialog {
- NSWindow* bugReportWindow = [self window];
- [bugReportWindow center];
- [NSApp runModalForWindow:bugReportWindow];
-}
-
-- (IBAction)sendReport:(id)sender {
- if ([self isPhishingReport]) {
- BugReportUtil::ReportPhishing(currentTab_,
- pageURL_ ? base::SysNSStringToUTF8(pageURL_) : "");
- } else {
- BugReportUtil::SendReport(
- profile_,
- base::SysNSStringToUTF8(pageTitle_),
- [self bugTypeFromIndex],
- base::SysNSStringToUTF8(pageURL_),
- base::SysNSStringToUTF8(bugDescription_),
- sendScreenshot_ && !pngData_.empty() ?
- reinterpret_cast<const char *>(&(pngData_[0])) : NULL,
- pngData_.size(), pngWidth_, pngHeight_);
- }
- [self closeDialog];
-}
-
-- (IBAction)cancel:(id)sender {
- [self closeDialog];
-}
-
-- (BOOL)isPhishingReport {
- return [self bugTypeFromIndex] == BugReportUtil::PHISHING_PAGE;
-}
-
-- (int)bugTypeFromIndex {
- // The order of these bugs must match the ordering in the bugTypeList_,
- // and thereby the menu in the popup button in the dialog box.
- const BugReportUtil::BugType typesForMenuIndices[] = {
- BugReportUtil::PAGE_WONT_LOAD,
- BugReportUtil::PAGE_LOOKS_ODD,
- BugReportUtil::PHISHING_PAGE,
- BugReportUtil::CANT_SIGN_IN,
- BugReportUtil::CHROME_MISBEHAVES,
- BugReportUtil::SOMETHING_MISSING,
- BugReportUtil::BROWSER_CRASH,
- BugReportUtil::OTHER_PROBLEM
- };
- // The bugs for the shorter menu start at index 4.
- NSUInteger adjustedBugTypeIndex_ = [bugTypeList_ count] == 8 ? bugTypeIndex_ :
- bugTypeIndex_ + 4;
- DCHECK_LT(adjustedBugTypeIndex_, arraysize(typesForMenuIndices));
- return typesForMenuIndices[adjustedBugTypeIndex_];
-}
-
-// Custom setter to update the UI for different bug types.
-- (void)setBugTypeIndex:(NSUInteger)bugTypeIndex {
- bugTypeIndex_ = bugTypeIndex;
-
- // The "send" button's title is based on the type of report.
- NSString* buttonTitle = [self isPhishingReport] ?
- l10n_util::GetNSStringWithFixup(IDS_BUGREPORT_SEND_PHISHING_REPORT) :
- l10n_util::GetNSStringWithFixup(IDS_BUGREPORT_SEND_REPORT);
- if (![buttonTitle isEqualTo:[sendReportButton_ title]]) {
- NSRect sendFrame1 = [sendReportButton_ frame];
- NSRect cancelFrame1 = [cancelButton_ frame];
-
- [sendReportButton_ setTitle:buttonTitle];
- CGFloat deltaWidth =
- [GTMUILocalizerAndLayoutTweaker sizeToFitView:sendReportButton_].width;
-
- NSRect sendFrame2 = [sendReportButton_ frame];
- sendFrame2.origin.x -= deltaWidth;
- NSRect cancelFrame2 = cancelFrame1;
- cancelFrame2.origin.x -= deltaWidth;
-
- // Since the buttons get updated/resize, use a quick animation so it is
- // a little less jarring in the UI.
- NSDictionary* sendReportButtonResize =
- [NSDictionary dictionaryWithObjectsAndKeys:
- sendReportButton_, NSViewAnimationTargetKey,
- [NSValue valueWithRect:sendFrame1], NSViewAnimationStartFrameKey,
- [NSValue valueWithRect:sendFrame2], NSViewAnimationEndFrameKey,
- nil];
- NSDictionary* cancelButtonResize =
- [NSDictionary dictionaryWithObjectsAndKeys:
- cancelButton_, NSViewAnimationTargetKey,
- [NSValue valueWithRect:cancelFrame1], NSViewAnimationStartFrameKey,
- [NSValue valueWithRect:cancelFrame2], NSViewAnimationEndFrameKey,
- nil];
- NSAnimation* animation =
- [[[NSViewAnimation alloc] initWithViewAnimations:
- [NSArray arrayWithObjects:sendReportButtonResize, cancelButtonResize,
- nil]] autorelease];
- const NSTimeInterval kQuickTransitionInterval = 0.1;
- [animation setDuration:kQuickTransitionInterval];
- [animation startAnimation];
-
- // Save or reload description when moving between phishing page and other
- // bug report types.
- if ([self isPhishingReport]) {
- saveBugDescription_.reset([[self bugDescription] retain]);
- [self setBugDescription:nil];
- saveSendScreenshot_ = sendScreenshot_;
- [self setSendScreenshot:NO];
- } else {
- [self setBugDescription:saveBugDescription_.get()];
- saveBugDescription_.reset();
- [self setSendScreenshot:saveSendScreenshot_];
- }
- }
-}
-
-- (BOOL)control:(NSControl*)control textView:(NSTextView*)textView
- doCommandBySelector:(SEL)commandSelector {
- if (commandSelector == @selector(insertNewline:)) {
- [textView insertNewlineIgnoringFieldEditor:self];
- return YES;
- }
- return NO;
-}
-
-// BugReportWindowController needs to change the title of the Send Report
-// button when the user chooses the phishing bug type, so we need to bind
-// the function that changes the button title to the bug type key.
-+ (NSSet*)keyPathsForValuesAffectingValueForKey:(NSString*)key {
- NSSet* paths = [super keyPathsForValuesAffectingValueForKey:key];
- if ([key isEqualToString:@"isPhishingReport"]) {
- paths = [paths setByAddingObject:@"bugTypeIndex"];
- }
- return paths;
-}
-
-@end
-
diff --git a/chrome/browser/cocoa/bug_report_window_controller_unittest.mm b/chrome/browser/cocoa/bug_report_window_controller_unittest.mm
deleted file mode 100644
index ab17359..0000000
--- a/chrome/browser/cocoa/bug_report_window_controller_unittest.mm
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright (c) 2009 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 "base/ref_counted.h"
-#include "chrome/browser/browser_thread.h"
-#import "chrome/browser/cocoa/bug_report_window_controller.h"
-#include "chrome/browser/renderer_host/site_instance.h"
-#include "chrome/browser/renderer_host/test/test_render_view_host.h"
-#include "chrome/browser/tab_contents/test_tab_contents.h"
-#include "chrome/browser/profile.h"
-#include "chrome/test/testing_profile.h"
-#import "testing/gtest_mac.h"
-
-namespace {
-
-class BugReportWindowControllerUnittest : public RenderViewHostTestHarness {
-};
-
-// See http://crbug.com/29019 for why it's disabled.
-TEST_F(BugReportWindowControllerUnittest, DISABLED_ReportBugWithNewTabPageOpen) {
- BrowserThread ui_thread(BrowserThread::UI, MessageLoop::current());
- // Create a "chrome://newtab" test tab. SiteInstance will be deleted when
- // tabContents is deleted.
- SiteInstance* instance =
- SiteInstance::CreateSiteInstance(profile_.get());
- TestTabContents* tabContents = new TestTabContents(profile_.get(),
- instance);
- tabContents->controller().LoadURL(GURL("chrome://newtab"),
- GURL(), PageTransition::START_PAGE);
-
- BugReportWindowController* controller = [[BugReportWindowController alloc]
- initWithTabContents:tabContents
- profile:profile_.get()];
-
- // The phishing report bug is stored at index 2 in the Report Bug dialog.
- [controller setBugTypeIndex:2];
- EXPECT_TRUE([controller isPhishingReport]);
- [controller setBugTypeIndex:1];
- EXPECT_FALSE([controller isPhishingReport]);
-
- // Make sure that the tab was correctly recorded.
- EXPECT_NSEQ(@"chrome://newtab/", [controller pageURL]);
- EXPECT_NSEQ(@"New Tab", [controller pageTitle]);
-
- // When we call "report bug" with non-empty tab contents, all menu options
- // should be available, and we should send screenshot by default.
- EXPECT_EQ([[controller bugTypeList] count], 8U);
- EXPECT_TRUE([controller sendScreenshot]);
-
- delete tabContents;
- [controller release];
-}
-
-// See http://crbug.com/29019 for why it's disabled.
-TEST_F(BugReportWindowControllerUnittest, DISABLED_ReportBugWithNoWindowOpen) {
- BugReportWindowController* controller = [[BugReportWindowController alloc]
- initWithTabContents:NULL
- profile:profile_.get()];
-
- // Make sure that no page title or URL are recorded. Note that IB reports
- // empty textfields as NULL values.
- EXPECT_FALSE([controller pageURL]);
- EXPECT_FALSE([controller pageTitle]);
-
- // When we call "report bug" with empty tab contents, only menu options
- // that don't refer to a specific page should be available, and the send
- // screenshot option should be turned off.
- EXPECT_EQ([[controller bugTypeList] count], 4U);
- EXPECT_FALSE([controller sendScreenshot]);
-
- [controller release];
-}
-
-} // namespace
-
diff --git a/chrome/browser/cocoa/chrome_browser_window.h b/chrome/browser/cocoa/chrome_browser_window.h
deleted file mode 100644
index 488bf0b..0000000
--- a/chrome/browser/cocoa/chrome_browser_window.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_CHROME_BROWSER_WINDOW_H_
-#define CHROME_BROWSER_COCOA_CHROME_BROWSER_WINDOW_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "chrome/browser/cocoa/chrome_event_processing_window.h"
-
-// Common base class for chrome browser windows. Contains methods relating to
-// theming and hole punching that are shared between framed and fullscreen
-// windows.
-@interface ChromeBrowserWindow : ChromeEventProcessingWindow {
- @private
- int underlaySurfaceCount_;
-}
-
-// Informs the window that an underlay surface has been added/removed. The
-// window is non-opaque while underlay surfaces are present.
-- (void)underlaySurfaceAdded;
-- (void)underlaySurfaceRemoved;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_CHROME_BROWSER_WINDOW_H_
diff --git a/chrome/browser/cocoa/chrome_browser_window.mm b/chrome/browser/cocoa/chrome_browser_window.mm
deleted file mode 100644
index 6dc6cea..0000000
--- a/chrome/browser/cocoa/chrome_browser_window.mm
+++ /dev/null
@@ -1,52 +0,0 @@
-// 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 "chrome/browser/cocoa/chrome_browser_window.h"
-
-#include "base/logging.h"
-#import "chrome/browser/cocoa/themed_window.h"
-#include "chrome/browser/themes/browser_theme_provider.h"
-
-@implementation ChromeBrowserWindow
-
-- (void)underlaySurfaceAdded {
- DCHECK_GE(underlaySurfaceCount_, 0);
- ++underlaySurfaceCount_;
-
- // We're having the OpenGL surface render under the window, so the window
- // needs to be not opaque.
- if (underlaySurfaceCount_ == 1)
- [self setOpaque:NO];
-}
-
-- (void)underlaySurfaceRemoved {
- --underlaySurfaceCount_;
- DCHECK_GE(underlaySurfaceCount_, 0);
-
- if (underlaySurfaceCount_ == 0)
- [self setOpaque:YES];
-}
-
-- (ThemeProvider*)themeProvider {
- id delegate = [self delegate];
- if (![delegate respondsToSelector:@selector(themeProvider)])
- return NULL;
- return [delegate themeProvider];
-}
-
-- (ThemedWindowStyle)themedWindowStyle {
- id delegate = [self delegate];
- if (![delegate respondsToSelector:@selector(themedWindowStyle)])
- return THEMED_NORMAL;
- return [delegate themedWindowStyle];
-}
-
-- (NSPoint)themePatternPhase {
- id delegate = [self delegate];
- if (![delegate respondsToSelector:@selector(themePatternPhase)])
- return NSMakePoint(0, 0);
- return [delegate themePatternPhase];
-}
-
-@end
diff --git a/chrome/browser/cocoa/chrome_browser_window_unittest.mm b/chrome/browser/cocoa/chrome_browser_window_unittest.mm
deleted file mode 100644
index fc39ccd..0000000
--- a/chrome/browser/cocoa/chrome_browser_window_unittest.mm
+++ /dev/null
@@ -1,45 +0,0 @@
-// 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 "base/debug/debugger.h"
-#import "chrome/browser/cocoa/chrome_browser_window.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-class ChromeBrowserWindowTest : public CocoaTest {
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
- // Create a window.
- const NSUInteger mask = NSTitledWindowMask | NSClosableWindowMask |
- NSMiniaturizableWindowMask | NSResizableWindowMask;
- window_ = [[ChromeBrowserWindow alloc]
- initWithContentRect:NSMakeRect(0, 0, 800, 600)
- styleMask:mask
- backing:NSBackingStoreBuffered
- defer:NO];
- if (base::debug::BeingDebugged()) {
- [window_ orderFront:nil];
- } else {
- [window_ orderBack:nil];
- }
- }
-
- virtual void TearDown() {
- [window_ close];
- CocoaTest::TearDown();
- }
-
- ChromeBrowserWindow* window_;
-};
-
-// Baseline test that the window creates, displays, closes, and
-// releases.
-TEST_F(ChromeBrowserWindowTest, ShowAndClose) {
- [window_ display];
-}
diff --git a/chrome/browser/cocoa/chrome_event_processing_window.h b/chrome/browser/cocoa/chrome_event_processing_window.h
deleted file mode 100644
index a470ddd..0000000
--- a/chrome/browser/cocoa/chrome_event_processing_window.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_CHROME_EVENT_PROCESSING_WINDOW_H_
-#define CHROME_BROWSER_COCOA_CHROME_EVENT_PROCESSING_WINDOW_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_nsobject.h"
-
-// Override NSWindow to access unhandled keyboard events (for command
-// processing); subclassing NSWindow is the only method to do
-// this.
-@interface ChromeEventProcessingWindow : NSWindow {
- @private
- BOOL redispatchingEvent_;
- BOOL eventHandled_;
-}
-
-// Sends a key event to |NSApp sendEvent:|, but also makes sure that it's not
-// short-circuited to the RWHV. This is used to send keyboard events to the menu
-// and the cmd-` handler if a keyboard event comes back unhandled from the
-// renderer. The event must be of type |NSKeyDown|, |NSKeyUp|, or
-// |NSFlagsChanged|.
-// Returns |YES| if |event| has been handled.
-- (BOOL)redispatchKeyEvent:(NSEvent*)event;
-
-// See global_keyboard_shortcuts_mac.h for details on the next two functions.
-
-// Checks if |event| is a window keyboard shortcut. If so, dispatches it to the
-// window controller's |executeCommand:| and returns |YES|.
-- (BOOL)handleExtraWindowKeyboardShortcut:(NSEvent*)event;
-
-// Checks if |event| is a delayed window keyboard shortcut. If so, dispatches
-// it to the window controller's |executeCommand:| and returns |YES|.
-- (BOOL)handleDelayedWindowKeyboardShortcut:(NSEvent*)event;
-
-// Checks if |event| is a browser keyboard shortcut. If so, dispatches it to the
-// window controller's |executeCommand:| and returns |YES|.
-- (BOOL)handleExtraBrowserKeyboardShortcut:(NSEvent*)event;
-
-// Override, so we can handle global keyboard events.
-- (BOOL)performKeyEquivalent:(NSEvent*)theEvent;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_CHROME_EVENT_PROCESSING_WINDOW_H_
diff --git a/chrome/browser/cocoa/chrome_event_processing_window.mm b/chrome/browser/cocoa/chrome_event_processing_window.mm
deleted file mode 100644
index 7426a94..0000000
--- a/chrome/browser/cocoa/chrome_event_processing_window.mm
+++ /dev/null
@@ -1,164 +0,0 @@
-// 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 "chrome/browser/cocoa/chrome_event_processing_window.h"
-
-#include "base/logging.h"
-#import "chrome/browser/cocoa/browser_command_executor.h"
-#import "chrome/browser/cocoa/browser_frame_view.h"
-#import "chrome/browser/cocoa/tab_strip_controller.h"
-#import "chrome/browser/renderer_host/render_widget_host_view_mac.h"
-#include "chrome/browser/global_keyboard_shortcuts_mac.h"
-
-typedef int (*KeyToCommandMapper)(bool, bool, bool, bool, int, unichar);
-
-@interface ChromeEventProcessingWindow ()
-// Duplicate the given key event, but changing the associated window.
-- (NSEvent*)keyEventForWindow:(NSWindow*)window fromKeyEvent:(NSEvent*)event;
-@end
-
-@implementation ChromeEventProcessingWindow
-
-- (BOOL)handleExtraKeyboardShortcut:(NSEvent*)event fromTable:
- (KeyToCommandMapper)commandForKeyboardShortcut {
- // Extract info from |event|.
- NSUInteger modifers = [event modifierFlags];
- const bool cmdKey = modifers & NSCommandKeyMask;
- const bool shiftKey = modifers & NSShiftKeyMask;
- const bool cntrlKey = modifers & NSControlKeyMask;
- const bool optKey = modifers & NSAlternateKeyMask;
- const unichar keyCode = [event keyCode];
- const unichar keyChar = KeyCharacterForEvent(event);
-
- int cmdNum = commandForKeyboardShortcut(cmdKey, shiftKey, cntrlKey, optKey,
- keyCode, keyChar);
-
- if (cmdNum != -1) {
- id executor = [self delegate];
- // A bit of sanity.
- DCHECK([executor conformsToProtocol:@protocol(BrowserCommandExecutor)]);
- DCHECK([executor respondsToSelector:@selector(executeCommand:)]);
- [executor executeCommand:cmdNum];
- return YES;
- }
- return NO;
-}
-
-- (BOOL)handleExtraWindowKeyboardShortcut:(NSEvent*)event {
- return [self handleExtraKeyboardShortcut:event
- fromTable:CommandForWindowKeyboardShortcut];
-}
-
-- (BOOL)handleDelayedWindowKeyboardShortcut:(NSEvent*)event {
- return [self handleExtraKeyboardShortcut:event
- fromTable:CommandForDelayedWindowKeyboardShortcut];
-}
-
-- (BOOL)handleExtraBrowserKeyboardShortcut:(NSEvent*)event {
- return [self handleExtraKeyboardShortcut:event
- fromTable:CommandForBrowserKeyboardShortcut];
-}
-
-- (BOOL)performKeyEquivalent:(NSEvent*)event {
- if (redispatchingEvent_)
- return NO;
-
- // Give the web site a chance to handle the event. If it doesn't want to
- // handle it, it will call us back with one of the |handle*| methods above.
- NSResponder* r = [self firstResponder];
- if ([r isKindOfClass:[RenderWidgetHostViewCocoa class]])
- return [r performKeyEquivalent:event];
-
- // If the delegate does not implement the BrowserCommandExecutor protocol,
- // then we don't need to handle browser specific shortcut keys.
- if (![[self delegate] conformsToProtocol:@protocol(BrowserCommandExecutor)])
- return [super performKeyEquivalent:event];
-
- // Handle per-window shortcuts like cmd-1, but do not handle browser-level
- // shortcuts like cmd-left (else, cmd-left would do history navigation even
- // if e.g. the Omnibox has focus).
- if ([self handleExtraWindowKeyboardShortcut:event])
- return YES;
-
- if ([super performKeyEquivalent:event])
- return YES;
-
- // Handle per-window shortcuts like Esc after giving everybody else a chance
- // to handle them
- return [self handleDelayedWindowKeyboardShortcut:event];
-}
-
-- (BOOL)redispatchKeyEvent:(NSEvent*)event {
- DCHECK(event);
- NSEventType eventType = [event type];
- if (eventType != NSKeyDown &&
- eventType != NSKeyUp &&
- eventType != NSFlagsChanged) {
- NOTREACHED();
- return YES; // Pretend it's been handled in an effort to limit damage.
- }
-
- // Ordinarily, the event's window should be this window. However, when
- // switching between normal and fullscreen mode, we switch out the window, and
- // the event's window might be the previous window (or even an earlier one if
- // the renderer is running slowly and several mode switches occur). In this
- // rare case, we synthesize a new key event so that its associate window
- // (number) is our own.
- if ([event window] != self)
- event = [self keyEventForWindow:self fromKeyEvent:event];
-
- // Redispatch the event.
- eventHandled_ = YES;
- redispatchingEvent_ = YES;
- [NSApp sendEvent:event];
- redispatchingEvent_ = NO;
-
- // If the event was not handled by [NSApp sendEvent:], the sendEvent:
- // method below will be called, and because |redispatchingEvent_| is YES,
- // |eventHandled_| will be set to NO.
- return eventHandled_;
-}
-
-- (void)sendEvent:(NSEvent*)event {
- if (!redispatchingEvent_)
- [super sendEvent:event];
- else
- eventHandled_ = NO;
-}
-
-- (NSEvent*)keyEventForWindow:(NSWindow*)window fromKeyEvent:(NSEvent*)event {
- NSEventType eventType = [event type];
-
- // Convert the event's location from the original window's coordinates into
- // our own.
- NSPoint eventLoc = [event locationInWindow];
- eventLoc = [[event window] convertBaseToScreen:eventLoc];
- eventLoc = [self convertScreenToBase:eventLoc];
-
- // Various things *only* apply to key down/up.
- BOOL eventIsARepeat = NO;
- NSString* eventCharacters = nil;
- NSString* eventUnmodCharacters = nil;
- if (eventType == NSKeyDown || eventType == NSKeyUp) {
- eventIsARepeat = [event isARepeat];
- eventCharacters = [event characters];
- eventUnmodCharacters = [event charactersIgnoringModifiers];
- }
-
- // This synthesis may be slightly imperfect: we provide nil for the context,
- // since I (viettrungluu) am sceptical that putting in the original context
- // (if one is given) is valid.
- return [NSEvent keyEventWithType:eventType
- location:eventLoc
- modifierFlags:[event modifierFlags]
- timestamp:[event timestamp]
- windowNumber:[window windowNumber]
- context:nil
- characters:eventCharacters
- charactersIgnoringModifiers:eventUnmodCharacters
- isARepeat:eventIsARepeat
- keyCode:[event keyCode]];
-}
-
-@end // ChromeEventProcessingWindow
diff --git a/chrome/browser/cocoa/chrome_event_processing_window_unittest.mm b/chrome/browser/cocoa/chrome_event_processing_window_unittest.mm
deleted file mode 100644
index ebcd3f3..0000000
--- a/chrome/browser/cocoa/chrome_event_processing_window_unittest.mm
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright (c) 2009 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/debug/debugger.h"
-#include "base/scoped_nsobject.h"
-#include "chrome/app/chrome_command_ids.h"
-#import "chrome/browser/cocoa/chrome_event_processing_window.h"
-#import "chrome/browser/cocoa/browser_window_controller.h"
-#import "chrome/browser/cocoa/browser_frame_view.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "third_party/ocmock/OCMock/OCMock.h"
-
-namespace {
-
-NSEvent* KeyEvent(const NSUInteger flags, const NSUInteger keyCode) {
- return [NSEvent keyEventWithType:NSKeyDown
- location:NSZeroPoint
- modifierFlags:flags
- timestamp:0.0
- windowNumber:0
- context:nil
- characters:@""
- charactersIgnoringModifiers:@""
- isARepeat:NO
- keyCode:keyCode];
-}
-
-class ChromeEventProcessingWindowTest : public CocoaTest {
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
- // Create a window.
- const NSUInteger mask = NSTitledWindowMask | NSClosableWindowMask |
- NSMiniaturizableWindowMask | NSResizableWindowMask;
- window_ = [[ChromeEventProcessingWindow alloc]
- initWithContentRect:NSMakeRect(0, 0, 800, 600)
- styleMask:mask
- backing:NSBackingStoreBuffered
- defer:NO];
- if (base::debug::BeingDebugged()) {
- [window_ orderFront:nil];
- } else {
- [window_ orderBack:nil];
- }
- }
-
- virtual void TearDown() {
- [window_ close];
- CocoaTest::TearDown();
- }
-
- ChromeEventProcessingWindow* window_;
-};
-
-id CreateBrowserWindowControllerMock() {
- id delegate = [OCMockObject mockForClass:[BrowserWindowController class]];
- // Make conformsToProtocol return YES for @protocol(BrowserCommandExecutor)
- // to satisfy the DCHECK() in handleExtraKeyboardShortcut.
- //
- // TODO(akalin): Figure out how to replace OCMOCK_ANY below with
- // @protocol(BrowserCommandExecutor) and have it work.
- BOOL yes = YES;
- [[[delegate stub] andReturnValue:OCMOCK_VALUE(yes)]
- conformsToProtocol:OCMOCK_ANY];
- return delegate;
-}
-
-// Verify that the window intercepts a particular key event and
-// forwards it to [delegate executeCommand:]. Assume that other
-// CommandForKeyboardShortcut() will work the same for the rest.
-TEST_F(ChromeEventProcessingWindowTest,
- PerformKeyEquivalentForwardToExecuteCommand) {
- NSEvent* event = KeyEvent(NSCommandKeyMask, kVK_ANSI_1);
-
- id delegate = CreateBrowserWindowControllerMock();
- [[delegate expect] executeCommand:IDC_SELECT_TAB_0];
-
- [window_ setDelegate:delegate];
- [window_ performKeyEquivalent:event];
-
- // Don't wish to mock all the way down...
- [window_ setDelegate:nil];
- [delegate verify];
-}
-
-// Verify that an unhandled shortcut does not get forwarded via
-// -executeCommand:.
-// TODO(shess) Think of a way to test that it is sent to the
-// superclass.
-TEST_F(ChromeEventProcessingWindowTest, PerformKeyEquivalentNoForward) {
- NSEvent* event = KeyEvent(0, 0);
-
- id delegate = CreateBrowserWindowControllerMock();
-
- [window_ setDelegate:delegate];
- [window_ performKeyEquivalent:event];
-
- // Don't wish to mock all the way down...
- [window_ setDelegate:nil];
- [delegate verify];
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/clear_browsing_data_controller.h b/chrome/browser/cocoa/clear_browsing_data_controller.h
deleted file mode 100644
index 7be460e..0000000
--- a/chrome/browser/cocoa/clear_browsing_data_controller.h
+++ /dev/null
@@ -1,87 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_CLEAR_BROWSING_DATA_CONTROLLER_
-#define CHROME_BROWSER_COCOA_CLEAR_BROWSING_DATA_CONTROLLER_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_ptr.h"
-
-class BrowsingDataRemover;
-class ClearBrowsingObserver;
-class Profile;
-@class ThrobberView;
-
-// Name of notification that is called when data is cleared.
-extern NSString* const kClearBrowsingDataControllerDidDelete;
-// A key in the above notification's userInfo. Contains a NSNumber with the
-// logically-ored constants defined in BrowsingDataRemover for the removal.
-extern NSString* const kClearBrowsingDataControllerRemoveMask;
-
-// A window controller for managing the "Clear Browsing Data" feature. Modally
-// presents a dialog offering the user a set of choices of what browsing data
-// to delete and does so if the user chooses.
-
-@interface ClearBrowsingDataController : NSWindowController {
- @private
- Profile* profile_; // Weak, owned by browser.
- // If non-null means there is a removal in progress. Member used mainly for
- // automated tests. The remove deletes itself when it's done, so this is a
- // weak reference.
- BrowsingDataRemover* remover_;
- scoped_ptr<ClearBrowsingObserver> observer_;
- BOOL isClearing_; // YES while clearing data is ongoing.
-
- // Values for checkboxes, kept in sync with bindings. These values get
- // persisted into prefs if the user accepts the dialog.
- BOOL clearBrowsingHistory_;
- BOOL clearDownloadHistory_;
- BOOL emptyCache_;
- BOOL deleteCookies_;
- BOOL clearSavedPasswords_;
- BOOL clearFormData_;
- NSInteger timePeriod_;
-}
-
-// Show the clear browsing data window. Do not use |-initWithProfile:|,
-// go through this instead so we don't end up with multiple instances.
-// This function does not block, so it can be used from DOMUI calls.
-+ (void)showClearBrowsingDialogForProfile:(Profile*)profile;
-+ (ClearBrowsingDataController*)controllerForProfile:(Profile*)profile;
-
-// Run the dialog with an application-modal event loop. If the user accepts,
-// performs the deletion of the selected browsing data. The values of the
-// checkboxes will be persisted into prefs for next time.
-- (void)runModalDialog;
-
-// IBActions for the dialog buttons
-- (IBAction)clearData:(id)sender;
-- (IBAction)cancel:(id)sender;
-- (IBAction)openFlashPlayerSettings:(id)sender;
-
-// Properties for bindings
-@property (nonatomic) BOOL clearBrowsingHistory;
-@property (nonatomic) BOOL clearDownloadHistory;
-@property (nonatomic) BOOL emptyCache;
-@property (nonatomic) BOOL deleteCookies;
-@property (nonatomic) BOOL clearSavedPasswords;
-@property (nonatomic) BOOL clearFormData;
-@property (nonatomic) NSInteger timePeriod;
-@property (nonatomic) BOOL isClearing;
-
-@end
-
-
-@interface ClearBrowsingDataController (ExposedForUnitTests)
-// Create the controller with the given profile (which must not be NULL).
-- (id)initWithProfile:(Profile*)profile;
-@property (readonly) int removeMask;
-- (void)persistToPrefs;
-- (void)closeDialog;
-- (void)dataRemoverDidFinish;
-@end
-
-#endif // CHROME_BROWSER_COCOA_CLEAR_BROWSING_DATA_CONTROLLER_
diff --git a/chrome/browser/cocoa/clear_browsing_data_controller.mm b/chrome/browser/cocoa/clear_browsing_data_controller.mm
deleted file mode 100644
index acbf7c0..0000000
--- a/chrome/browser/cocoa/clear_browsing_data_controller.mm
+++ /dev/null
@@ -1,264 +0,0 @@
-// 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 "chrome/browser/cocoa/clear_browsing_data_controller.h"
-
-#include "app/l10n_util.h"
-#include "base/mac_util.h"
-#include "base/scoped_nsobject.h"
-#include "base/singleton.h"
-#include "chrome/browser/browsing_data_remover.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/common/pref_names.h"
-#include "grit/locale_settings.h"
-#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-
-NSString* const kClearBrowsingDataControllerDidDelete =
- @"kClearBrowsingDataControllerDidDelete";
-NSString* const kClearBrowsingDataControllerRemoveMask =
- @"kClearBrowsingDataControllerRemoveMask";
-
-@interface ClearBrowsingDataController(Private)
-- (void)initFromPrefs;
-- (void)persistToPrefs;
-- (void)dataRemoverDidFinish;
-@end
-
-class ClearBrowsingObserver : public BrowsingDataRemover::Observer {
- public:
- ClearBrowsingObserver(ClearBrowsingDataController* controller)
- : controller_(controller) { }
- void OnBrowsingDataRemoverDone() { [controller_ dataRemoverDidFinish]; }
- private:
- ClearBrowsingDataController* controller_;
-};
-
-namespace {
-
-typedef std::map<Profile*, ClearBrowsingDataController*> ProfileControllerMap;
-
-} // namespace
-
-@implementation ClearBrowsingDataController
-
-@synthesize clearBrowsingHistory = clearBrowsingHistory_;
-@synthesize clearDownloadHistory = clearDownloadHistory_;
-@synthesize emptyCache = emptyCache_;
-@synthesize deleteCookies = deleteCookies_;
-@synthesize clearSavedPasswords = clearSavedPasswords_;
-@synthesize clearFormData = clearFormData_;
-@synthesize timePeriod = timePeriod_;
-@synthesize isClearing = isClearing_;
-
-+ (void)showClearBrowsingDialogForProfile:(Profile*)profile {
- ClearBrowsingDataController* controller =
- [ClearBrowsingDataController controllerForProfile:profile];
- if (![controller isWindowLoaded]) {
- // This function needs to return instead of blocking, to match the windows
- // api call. It caused problems when launching the dialog from the
- // DomUI history page. See bug and code review for more details.
- // http://crbug.com/37976
- [controller performSelector:@selector(runModalDialog)
- withObject:nil
- afterDelay:0];
- }
-}
-
-+ (ClearBrowsingDataController *)controllerForProfile:(Profile*)profile {
- // Get the original profile in case we get here from an incognito window
- // |GetOriginalProfile()| will return the same profile if it is the original
- // profile.
- profile = profile->GetOriginalProfile();
-
- ProfileControllerMap* map = Singleton<ProfileControllerMap>::get();
- DCHECK(map != NULL);
- ProfileControllerMap::iterator it = map->find(profile);
- if (it == map->end()) {
- // Since we don't currently support multiple profiles, this class
- // has not been tested against this case.
- if (map->size() != 0) {
- return nil;
- }
-
- ClearBrowsingDataController* controller =
- [[self alloc] initWithProfile:profile];
- it = map->insert(std::make_pair(profile, controller)).first;
- }
- return it->second;
-}
-
-- (id)initWithProfile:(Profile*)profile {
- DCHECK(profile);
- // Use initWithWindowNibPath:: instead of initWithWindowNibName: so we
- // can override it in a unit test.
- NSString *nibpath = [mac_util::MainAppBundle()
- pathForResource:@"ClearBrowsingData"
- ofType:@"nib"];
- if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
- profile_ = profile;
- observer_.reset(new ClearBrowsingObserver(self));
- [self initFromPrefs];
- }
- return self;
-}
-
-- (void)dealloc {
- if (remover_) {
- // We were destroyed while clearing history was in progress. This can only
- // occur during automated tests (normally the user can't close the dialog
- // while clearing is in progress as the dialog is modal and not closeable).
- remover_->RemoveObserver(observer_.get());
- }
-
- [super dealloc];
-}
-
-// Run application modal.
-- (void)runModalDialog {
- // Check again to make sure there is only one window. Since we use
- // |performSelector:afterDelay:| it is possible for this to somehow be
- // triggered twice.
- DCHECK([NSThread isMainThread]);
- if (![self isWindowLoaded]) {
- // The Window size in the nib is a min size, loop over the views collecting
- // the max they grew by, that is how much the window needs to be widened by.
- CGFloat maxWidthGrowth = 0.0;
- NSWindow* window = [self window];
- NSView* contentView = [window contentView];
- Class widthBasedTweakerClass = [GTMWidthBasedTweaker class];
- for (id subView in [contentView subviews]) {
- if ([subView isKindOfClass:widthBasedTweakerClass]) {
- GTMWidthBasedTweaker* tweaker = subView;
- CGFloat delta = [tweaker changedWidth];
- maxWidthGrowth = std::max(maxWidthGrowth, delta);
- }
- }
- if (maxWidthGrowth > 0.0) {
- NSRect rect = [contentView convertRect:[window frame] fromView:nil];
- rect.size.width += maxWidthGrowth;
- rect = [contentView convertRect:rect toView:nil];
- [window setFrame:rect display:NO];
- // For some reason the content view is resizing, but some times not
- // adjusting its origin, so correct it manually.
- [contentView setFrameOrigin:NSZeroPoint];
- }
- // Now start the modal loop.
- [NSApp runModalForWindow:window];
- }
-}
-
-- (int)removeMask {
- int removeMask = 0L;
- if (clearBrowsingHistory_)
- removeMask |= BrowsingDataRemover::REMOVE_HISTORY;
- if (clearDownloadHistory_)
- removeMask |= BrowsingDataRemover::REMOVE_DOWNLOADS;
- if (emptyCache_)
- removeMask |= BrowsingDataRemover::REMOVE_CACHE;
- if (deleteCookies_)
- removeMask |= BrowsingDataRemover::REMOVE_COOKIES;
- if (clearSavedPasswords_)
- removeMask |= BrowsingDataRemover::REMOVE_PASSWORDS;
- if (clearFormData_)
- removeMask |= BrowsingDataRemover::REMOVE_FORM_DATA;
- return removeMask;
-}
-
-// Called when the user clicks the "clear" button. Do the work and persist
-// the prefs for next time. We don't stop the modal session until we get
-// the callback from the BrowsingDataRemover so the window stays on the screen.
-// While we're working, dim the buttons so the user can't click them.
-- (IBAction)clearData:(id)sender {
- // Set that we're working so that the buttons disable.
- [self setIsClearing:YES];
-
- [self persistToPrefs];
-
- // BrowsingDataRemover deletes itself when done.
- remover_ = new BrowsingDataRemover(profile_,
- static_cast<BrowsingDataRemover::TimePeriod>(timePeriod_),
- base::Time());
- remover_->AddObserver(observer_.get());
- remover_->Remove([self removeMask]);
-}
-
-// Called when the user clicks the cancel button. All we need to do is stop
-// the modal session.
-- (IBAction)cancel:(id)sender {
- [self closeDialog];
-}
-
-// Called when the user clicks the "Flash Player storage settings" button.
-- (IBAction)openFlashPlayerSettings:(id)sender {
- // The "Clear Data" dialog is app-modal on OS X. Hence, close it before
- // opening a tab with flash settings.
- [self closeDialog];
-
- Browser* browser = Browser::Create(profile_);
- browser->OpenURL(GURL(l10n_util::GetStringUTF8(IDS_FLASH_STORAGE_URL)),
- GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
- browser->window()->Show();
-}
-
-- (void)closeDialog {
- ProfileControllerMap* map = Singleton<ProfileControllerMap>::get();
- ProfileControllerMap::iterator it = map->find(profile_);
- if (it != map->end()) {
- map->erase(it);
- }
- [self autorelease];
- [[self window] orderOut:self];
- [NSApp stopModal];
-}
-
-// Initialize the bools from prefs using the setters to be KVO-compliant.
-- (void)initFromPrefs {
- PrefService* prefs = profile_->GetPrefs();
- [self setClearBrowsingHistory:
- prefs->GetBoolean(prefs::kDeleteBrowsingHistory)];
- [self setClearDownloadHistory:
- prefs->GetBoolean(prefs::kDeleteDownloadHistory)];
- [self setEmptyCache:prefs->GetBoolean(prefs::kDeleteCache)];
- [self setDeleteCookies:prefs->GetBoolean(prefs::kDeleteCookies)];
- [self setClearSavedPasswords:prefs->GetBoolean(prefs::kDeletePasswords)];
- [self setClearFormData:prefs->GetBoolean(prefs::kDeleteFormData)];
- [self setTimePeriod:prefs->GetInteger(prefs::kDeleteTimePeriod)];
-}
-
-// Save the checkbox values to the preferences.
-- (void)persistToPrefs {
- PrefService* prefs = profile_->GetPrefs();
- prefs->SetBoolean(prefs::kDeleteBrowsingHistory,
- [self clearBrowsingHistory]);
- prefs->SetBoolean(prefs::kDeleteDownloadHistory,
- [self clearDownloadHistory]);
- prefs->SetBoolean(prefs::kDeleteCache, [self emptyCache]);
- prefs->SetBoolean(prefs::kDeleteCookies, [self deleteCookies]);
- prefs->SetBoolean(prefs::kDeletePasswords, [self clearSavedPasswords]);
- prefs->SetBoolean(prefs::kDeleteFormData, [self clearFormData]);
- prefs->SetInteger(prefs::kDeleteTimePeriod, [self timePeriod]);
-}
-
-// Called when the data remover object is done with its work. Close the window.
-// The remover will delete itself. End the modal session at this point.
-- (void)dataRemoverDidFinish {
- NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
- int removeMask = [self removeMask];
- NSDictionary* userInfo =
- [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:removeMask]
- forKey:kClearBrowsingDataControllerRemoveMask];
- [center postNotificationName:kClearBrowsingDataControllerDidDelete
- object:self
- userInfo:userInfo];
-
- [self closeDialog];
- [[self window] orderOut:self];
- [self setIsClearing:NO];
- remover_ = NULL;
-}
-
-@end
diff --git a/chrome/browser/cocoa/clear_browsing_data_controller_unittest.mm b/chrome/browser/cocoa/clear_browsing_data_controller_unittest.mm
deleted file mode 100644
index 9de805e..0000000
--- a/chrome/browser/cocoa/clear_browsing_data_controller_unittest.mm
+++ /dev/null
@@ -1,149 +0,0 @@
-// 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 "base/scoped_nsobject.h"
-#include "chrome/browser/browsing_data_remover.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/clear_browsing_data_controller.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/common/pref_names.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-#import "third_party/ocmock/OCMock/OCMock.h"
-
-namespace {
-
-class ClearBrowsingDataControllerTest : public CocoaTest {
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
- // Set up some interesting prefs:
- PrefService* prefs = helper_.profile()->GetPrefs();
- prefs->SetBoolean(prefs::kDeleteBrowsingHistory, true);
- prefs->SetBoolean(prefs::kDeleteDownloadHistory, false);
- prefs->SetBoolean(prefs::kDeleteCache, true);
- prefs->SetBoolean(prefs::kDeleteCookies, false);
- prefs->SetBoolean(prefs::kDeletePasswords, true);
- prefs->SetBoolean(prefs::kDeleteFormData, false);
- prefs->SetInteger(prefs::kDeleteTimePeriod,
- BrowsingDataRemover::FOUR_WEEKS);
- controller_ =
- [ClearBrowsingDataController controllerForProfile:helper_.profile()];
- }
-
- virtual void TearDown() {
- [controller_ closeDialog];
- CocoaTest::TearDown();
- }
-
- BrowserTestHelper helper_;
- ClearBrowsingDataController* controller_;
-};
-
-TEST_F(ClearBrowsingDataControllerTest, InitialState) {
- // Check properties match the prefs set above:
- EXPECT_TRUE([controller_ clearBrowsingHistory]);
- EXPECT_FALSE([controller_ clearDownloadHistory]);
- EXPECT_TRUE([controller_ emptyCache]);
- EXPECT_FALSE([controller_ deleteCookies]);
- EXPECT_TRUE([controller_ clearSavedPasswords]);
- EXPECT_FALSE([controller_ clearFormData]);
- EXPECT_EQ(BrowsingDataRemover::FOUR_WEEKS,
- [controller_ timePeriod]);
-}
-
-TEST_F(ClearBrowsingDataControllerTest, InitialRemoveMask) {
- // Check that the remove-mask matches the initial properties:
- EXPECT_EQ(BrowsingDataRemover::REMOVE_HISTORY |
- BrowsingDataRemover::REMOVE_CACHE |
- BrowsingDataRemover::REMOVE_PASSWORDS,
- [controller_ removeMask]);
-}
-
-TEST_F(ClearBrowsingDataControllerTest, ModifiedRemoveMask) {
- // Invert all properties and check that the remove-mask is still correct:
- [controller_ setClearBrowsingHistory:false];
- [controller_ setClearDownloadHistory:true];
- [controller_ setEmptyCache:false];
- [controller_ setDeleteCookies:true];
- [controller_ setClearSavedPasswords:false];
- [controller_ setClearFormData:true];
-
- EXPECT_EQ(BrowsingDataRemover::REMOVE_DOWNLOADS |
- BrowsingDataRemover::REMOVE_COOKIES |
- BrowsingDataRemover::REMOVE_FORM_DATA,
- [controller_ removeMask]);
-}
-
-TEST_F(ClearBrowsingDataControllerTest, EmptyRemoveMask) {
- // Clear all properties and check that the remove-mask is zero:
- [controller_ setClearBrowsingHistory:false];
- [controller_ setClearDownloadHistory:false];
- [controller_ setEmptyCache:false];
- [controller_ setDeleteCookies:false];
- [controller_ setClearSavedPasswords:false];
- [controller_ setClearFormData:false];
-
- EXPECT_EQ(0,
- [controller_ removeMask]);
-}
-
-TEST_F(ClearBrowsingDataControllerTest, PersistToPrefs) {
- // Change some settings and store to prefs:
- [controller_ setClearBrowsingHistory:false];
- [controller_ setClearDownloadHistory:true];
- [controller_ persistToPrefs];
-
- // Test that the modified settings were stored to prefs:
- PrefService* prefs = helper_.profile()->GetPrefs();
- EXPECT_FALSE(prefs->GetBoolean(prefs::kDeleteBrowsingHistory));
- EXPECT_TRUE(prefs->GetBoolean(prefs::kDeleteDownloadHistory));
-
- // Make sure the rest of the prefs didn't change:
- EXPECT_TRUE(prefs->GetBoolean(prefs::kDeleteCache));
- EXPECT_FALSE(prefs->GetBoolean(prefs::kDeleteCookies));
- EXPECT_TRUE(prefs->GetBoolean(prefs::kDeletePasswords));
- EXPECT_FALSE(prefs->GetBoolean(prefs::kDeleteFormData));
- EXPECT_EQ(BrowsingDataRemover::FOUR_WEEKS,
- prefs->GetInteger(prefs::kDeleteTimePeriod));
-}
-
-TEST_F(ClearBrowsingDataControllerTest, SameControllerForProfile) {
- ClearBrowsingDataController* controller =
- [ClearBrowsingDataController controllerForProfile:helper_.profile()];
- EXPECT_EQ(controller_, controller);
-}
-
-TEST_F(ClearBrowsingDataControllerTest, DataRemoverDidFinish) {
- id observer = [OCMockObject observerMock];
- // Don't use |controller_| as the object because it will free itself twice
- // because both |-dataRemoverDidFinish| and TearDown() call |-closeDialog|.
- ClearBrowsingDataController* controller =
- [[ClearBrowsingDataController alloc] initWithProfile:helper_.profile()];
-
- NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
- [center addMockObserver:observer
- name:kClearBrowsingDataControllerDidDelete
- object:controller];
-
- int mask = [controller removeMask];
- NSDictionary* expectedInfo =
- [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:mask]
- forKey:kClearBrowsingDataControllerRemoveMask];
- [[observer expect]
- notificationWithName:kClearBrowsingDataControllerDidDelete
- object:controller
- userInfo:expectedInfo];
-
- // This calls |-closeDialog| and cleans the controller up.
- [controller dataRemoverDidFinish];
-
- [observer verify];
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/clickhold_button_cell.h b/chrome/browser/cocoa/clickhold_button_cell.h
deleted file mode 100644
index e80edc5..0000000
--- a/chrome/browser/cocoa/clickhold_button_cell.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_CLICKHOLD_BUTTON_CELL_H_
-#define CHROME_BROWSER_COCOA_CLICKHOLD_BUTTON_CELL_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/gradient_button_cell.h"
-
-// A button cell that implements "click hold" behavior after a specified delay
-// or after dragging. If click-hold is never enabled (e.g., if
-// |-setEnableClickHold:| is never called), this behaves like a normal button.
-@interface ClickHoldButtonCell : GradientButtonCell {
- @private
- BOOL enableClickHold_;
- NSTimeInterval clickHoldTimeout_;
- id clickHoldTarget_; // Weak.
- SEL clickHoldAction_;
- BOOL trackOnlyInRect_;
- BOOL activateOnDrag_;
-}
-
-// Enable click-hold? Default: NO.
-@property(assign, nonatomic) BOOL enableClickHold;
-
-// Timeout is in seconds (at least 0.0, at most 5; 0.0 means that the button
-// will always have its click-hold action activated immediately on press).
-// Default: 0.25 (a guess at a Cocoa-ish value).
-@property(assign, nonatomic) NSTimeInterval clickHoldTimeout;
-
-// Track only in the frame rectangle? Default: NO.
-@property(assign, nonatomic) BOOL trackOnlyInRect;
-
-// Activate (click-hold) immediately on a sufficiently-large drag (if not,
-// always wait for timeout)? Default: YES.
-@property(assign, nonatomic) BOOL activateOnDrag;
-
-// Defines what to do when click-held (as per usual action/target).
-@property(assign, nonatomic) id clickHoldTarget;
-@property(assign, nonatomic) SEL clickHoldAction;
-
-@end // @interface ClickHoldButtonCell
-
-#endif // CHROME_BROWSER_COCOA_CLICKHOLD_BUTTON_CELL_H_
diff --git a/chrome/browser/cocoa/clickhold_button_cell.mm b/chrome/browser/cocoa/clickhold_button_cell.mm
deleted file mode 100644
index 0dd5c3f..0000000
--- a/chrome/browser/cocoa/clickhold_button_cell.mm
+++ /dev/null
@@ -1,190 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/clickhold_button_cell.h"
-
-#include "base/logging.h"
-
-// Minimum and maximum click-hold timeout.
-static const NSTimeInterval kMinTimeout = 0.0;
-static const NSTimeInterval kMaxTimeout = 5.0;
-
-// Drag distance threshold to activate click-hold; should be >= 0.
-static const CGFloat kDragDistThreshold = 2.5;
-
-// See |-resetToDefaults| (and header file) for other default values.
-
-@interface ClickHoldButtonCell (Private)
-- (void)resetToDefaults;
-@end // @interface ClickHoldButtonCell (Private)
-
-@implementation ClickHoldButtonCell
-
-// Overrides:
-
-+ (BOOL)prefersTrackingUntilMouseUp {
- return NO;
-}
-
-- (id)init {
- if ((self = [super init]))
- [self resetToDefaults];
- return self;
-}
-
-- (id)initWithCoder:(NSCoder*)decoder {
- if ((self = [super initWithCoder:decoder]))
- [self resetToDefaults];
- return self;
-}
-
-- (id)initImageCell:(NSImage*)image {
- if ((self = [super initImageCell:image]))
- [self resetToDefaults];
- return self;
-}
-
-- (id)initTextCell:(NSString*)string {
- if ((self = [super initTextCell:string]))
- [self resetToDefaults];
- return self;
-}
-
-- (BOOL)startTrackingAt:(NSPoint)startPoint
- inView:(NSView*)controlView {
- return enableClickHold_ ? YES :
- [super startTrackingAt:startPoint
- inView:controlView];
-}
-
-- (BOOL)continueTracking:(NSPoint)lastPoint
- at:(NSPoint)currentPoint
- inView:(NSView*)controlView {
- return enableClickHold_ ? YES :
- [super continueTracking:lastPoint
- at:currentPoint
- inView:controlView];
-}
-
-- (BOOL)trackMouse:(NSEvent*)originalEvent
- inRect:(NSRect)cellFrame
- ofView:(NSView*)controlView
- untilMouseUp:(BOOL)untilMouseUp {
- if (!enableClickHold_) {
- return [super trackMouse:originalEvent
- inRect:cellFrame
- ofView:controlView
- untilMouseUp:untilMouseUp];
- }
-
- // If doing click-hold, track the mouse ourselves.
- NSPoint currPoint = [controlView convertPoint:[originalEvent locationInWindow]
- fromView:nil];
- NSPoint lastPoint = currPoint;
- NSPoint firstPoint = currPoint;
- NSTimeInterval timeout =
- MAX(MIN(clickHoldTimeout_, kMaxTimeout), kMinTimeout);
- NSDate* clickHoldBailTime = [NSDate dateWithTimeIntervalSinceNow:timeout];
-
- if (![self startTrackingAt:currPoint inView:controlView])
- return NO;
-
- enum {
- kContinueTrack, kStopClickHold, kStopMouseUp, kStopLeftRect, kStopNoContinue
- } state = kContinueTrack;
- do {
- NSEvent* event = [NSApp nextEventMatchingMask:(NSLeftMouseDraggedMask |
- NSLeftMouseUpMask)
- untilDate:clickHoldBailTime
- inMode:NSEventTrackingRunLoopMode
- dequeue:YES];
- currPoint = [controlView convertPoint:[event locationInWindow]
- fromView:nil];
-
- // Time-out.
- if (!event) {
- state = kStopClickHold;
-
- // Drag? (If distance meets threshold.)
- } else if (activateOnDrag_ && ([event type] == NSLeftMouseDragged)) {
- CGFloat dx = currPoint.x - firstPoint.x;
- CGFloat dy = currPoint.y - firstPoint.y;
- if ((dx*dx + dy*dy) >= (kDragDistThreshold*kDragDistThreshold))
- state = kStopClickHold;
-
- // Mouse up.
- } else if ([event type] == NSLeftMouseUp) {
- state = kStopMouseUp;
-
- // Stop tracking if mouse left frame rectangle (if requested to do so).
- } else if (trackOnlyInRect_ && ![controlView mouse:currPoint
- inRect:cellFrame]) {
- state = kStopLeftRect;
-
- // Stop tracking if instructed to.
- } else if (![self continueTracking:lastPoint
- at:currPoint
- inView:controlView]) {
- state = kStopNoContinue;
- }
-
- lastPoint = currPoint;
- } while (state == kContinueTrack);
-
- [self stopTracking:lastPoint
- at:lastPoint
- inView:controlView
- mouseIsUp:NO];
-
- switch (state) {
- case kStopClickHold:
- if (clickHoldAction_) {
- [static_cast<NSControl*>(controlView) sendAction:clickHoldAction_
- to:clickHoldTarget_];
- }
- return YES;
-
- case kStopMouseUp:
- if ([self action]) {
- [static_cast<NSControl*>(controlView) sendAction:[self action]
- to:[self target]];
- }
- return YES;
-
- case kStopLeftRect:
- case kStopNoContinue:
- return NO;
-
- default:
- NOTREACHED() << "Unknown terminating state!";
- }
-
- return NO;
-}
-
-// Accessors and mutators:
-
-@synthesize enableClickHold = enableClickHold_;
-@synthesize clickHoldTimeout = clickHoldTimeout_;
-@synthesize trackOnlyInRect = trackOnlyInRect_;
-@synthesize activateOnDrag = activateOnDrag_;
-@synthesize clickHoldTarget = clickHoldTarget_;
-@synthesize clickHoldAction = clickHoldAction_;
-
-@end // @implementation ClickHoldButtonCell
-
-@implementation ClickHoldButtonCell (Private)
-
-// Resets various members to defaults indicated in the header file. (Those
-// without indicated defaults are *not* touched.) Please keep the values below
-// in sync with the header file, and please be aware of side-effects on code
-// which relies on the "published" defaults.
-- (void)resetToDefaults {
- [self setEnableClickHold:NO];
- [self setClickHoldTimeout:0.25];
- [self setTrackOnlyInRect:NO];
- [self setActivateOnDrag:YES];
-}
-
-@end // @implementation ClickHoldButtonCell (Private)
diff --git a/chrome/browser/cocoa/clickhold_button_cell_unittest.mm b/chrome/browser/cocoa/clickhold_button_cell_unittest.mm
deleted file mode 100644
index 99f5dcc..0000000
--- a/chrome/browser/cocoa/clickhold_button_cell_unittest.mm
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (c) 2009 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 "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/clickhold_button_cell.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-namespace {
-
-class ClickHoldButtonCellTest : public CocoaTest {
- public:
- ClickHoldButtonCellTest() {
- NSRect frame = NSMakeRect(0, 0, 50, 30);
- scoped_nsobject<NSButton> view([[NSButton alloc] initWithFrame:frame]);
- view_ = view.get();
- scoped_nsobject<ClickHoldButtonCell> cell(
- [[ClickHoldButtonCell alloc] initTextCell:@"Testing"]);
- [view_ setCell:cell.get()];
- [[test_window() contentView] addSubview:view_];
- }
-
- NSButton* view_;
-};
-
-TEST_VIEW(ClickHoldButtonCellTest, view_)
-
-// Test default values; make sure they are what they should be.
-TEST_F(ClickHoldButtonCellTest, Defaults) {
- ClickHoldButtonCell* cell = static_cast<ClickHoldButtonCell*>([view_ cell]);
- ASSERT_TRUE([cell isKindOfClass:[ClickHoldButtonCell class]]);
-
- EXPECT_FALSE([cell enableClickHold]);
-
- NSTimeInterval clickHoldTimeout = [cell clickHoldTimeout];
- EXPECT_GE(clickHoldTimeout, 0.15); // Check for a "Cocoa-ish" value.
- EXPECT_LE(clickHoldTimeout, 0.35);
-
- EXPECT_FALSE([cell trackOnlyInRect]);
- EXPECT_TRUE([cell activateOnDrag]);
-}
-
-// TODO(viettrungluu): (1) Enable click-hold and figure out how to test the
-// tracking loop (i.e., |-trackMouse:...|), which is the nontrivial part.
-// (2) Test various initialization code paths (in particular, loading from nib).
-
-} // namespace
diff --git a/chrome/browser/cocoa/cocoa_test_helper.h b/chrome/browser/cocoa/cocoa_test_helper.h
deleted file mode 100644
index 58b5a36..0000000
--- a/chrome/browser/cocoa/cocoa_test_helper.h
+++ /dev/null
@@ -1,153 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_COCOA_TEST_HELPER_H_
-#define CHROME_BROWSER_COCOA_COCOA_TEST_HELPER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/chrome_application_mac.h"
-#include "base/debug_util.h"
-#include "base/mac_util.h"
-#include "base/path_service.h"
-#import "base/mac/scoped_nsautorelease_pool.h"
-#import "base/scoped_nsobject.h"
-#include "chrome/common/chrome_constants.h"
-#include "testing/platform_test.h"
-
-// Background windows normally will not display things such as focus
-// rings. This class allows -isKeyWindow to be manipulated to test
-// such things.
-@interface CocoaTestHelperWindow : NSWindow {
- @private
- BOOL pretendIsKeyWindow_;
-}
-
-// Init a borderless non-deferred window with a backing store.
-- (id)initWithContentRect:(NSRect)contentRect;
-
-// Init with a default frame.
-- (id)init;
-
-// Sets the responder passed in as first responder, and sets the window
-// so that it will return "YES" if asked if it key window. It does not actually
-// make the window key.
-- (void)makePretendKeyWindowAndSetFirstResponder:(NSResponder*)responder;
-
-// Clears the first responder duty for the window and returns the window
-// to being non-key.
-- (void)clearPretendKeyWindowAndFirstResponder;
-
-// Set value to return for -isKeyWindow.
-- (void)setPretendIsKeyWindow:(BOOL)isKeyWindow;
-
-- (BOOL)isKeyWindow;
-
-@end
-
-// A test class that all tests that depend on AppKit should inherit from.
-// Sets up NSApplication and paths correctly, and makes sure that any windows
-// created in the test are closed down properly by the test. If you need to
-// inherit from a different test class, but need to set up the AppKit runtime
-// environment, you can call BootstrapCocoa directly from your test class. You
-// will have to deal with windows on your own though.
-class CocoaTest : public PlatformTest {
- public:
- // Sets up AppKit and paths correctly for unit tests. If you can't inherit
- // from CocoaTest but are going to be using any AppKit features directly,
- // or indirectly, you should be calling this from the c'tor or SetUp methods
- // of your test class.
- static void BootstrapCocoa();
-
- CocoaTest();
- virtual ~CocoaTest();
-
- // Must be called by subclasses that override TearDown. We verify that it
- // is called in our destructor. Takes care of making sure that all windows
- // are closed off correctly. If your tests open windows, they must be sure
- // to close them before CocoaTest::TearDown is called. A standard way of doing
- // this would be to create them in SetUp (after calling CocoaTest::Setup) and
- // then close them in TearDown before calling CocoaTest::TearDown.
- virtual void TearDown();
-
- // Retuns a test window that can be used by views and other UI objects
- // as part of their tests. Is created lazily, and will be closed correctly
- // in CocoaTest::TearDown. Note that it is a CocoaTestHelperWindow which
- // has special handling for being Key.
- CocoaTestHelperWindow* test_window();
-
- private:
- // Return a set of currently open windows. Avoiding NSArray so
- // contents aren't retained, the pointer values can only be used for
- // comparison purposes. Using std::set to make progress-checking
- // convenient.
- static std::set<NSWindow*> ApplicationWindows();
-
- // Return a set of windows which are in |ApplicationWindows()| but
- // not |initial_windows_|.
- std::set<NSWindow*> WindowsLeft();
-
- bool called_tear_down_;
- base::mac::ScopedNSAutoreleasePool pool_;
-
- // Windows which existed at the beginning of the test.
- std::set<NSWindow*> initial_windows_;
-
- // Strong. Lazily created. This isn't wrapped in a scoped_nsobject because
- // we want to call [close] to destroy it rather than calling [release]. We
- // want to verify that [close] is actually removing our window and that it's
- // not hanging around because releaseWhenClosed was set to "no" on the window.
- // It isn't wrapped in a different wrapper class to close it because we
- // need to close it at a very specific time; just before we enter our clean
- // up loop in TearDown.
- CocoaTestHelperWindow* test_window_;
-};
-
-// A macro defining a standard set of tests to run on a view. Since we can't
-// inherit tests, this macro saves us a lot of duplicate code. Handles simply
-// displaying the view to make sure it won't crash, as well as removing it
-// from a window. All tests that work with NSView subclasses and/or
-// NSViewController subclasses should use it.
-#define TEST_VIEW(test_fixture, test_view) \
- TEST_F(test_fixture, AddRemove##test_fixture) { \
- scoped_nsobject<NSView> view([test_view retain]); \
- EXPECT_EQ([test_window() contentView], [view superview]); \
- [view removeFromSuperview]; \
- EXPECT_FALSE([view superview]); \
- } \
- TEST_F(test_fixture, Display##test_fixture) { \
- [test_view display]; \
- }
-
-// A macro which determines the proper float epsilon for a CGFloat.
-#if CGFLOAT_IS_DOUBLE
-#define CGFLOAT_EPSILON DBL_EPSILON
-#else
-#define CGFLOAT_EPSILON FLT_EPSILON
-#endif
-
-// A macro which which determines if two CGFloats are equal taking a
-// proper epsilon into consideration.
-#define CGFLOAT_EQ(expected, actual) \
- (actual >= (expected - CGFLOAT_EPSILON) && \
- actual <= (expected + CGFLOAT_EPSILON))
-
-// A test support macro which ascertains if two CGFloats are equal.
-#define EXPECT_CGFLOAT_EQ(expected, actual) \
- EXPECT_TRUE(CGFLOAT_EQ(expected, actual)) << \
- expected << " != " << actual
-
-// A test support macro which compares two NSRects for equality taking
-// the float epsilon into consideration.
-#define EXPECT_NSRECT_EQ(expected, actual) \
- EXPECT_TRUE(CGFLOAT_EQ(expected.origin.x, actual.origin.x) && \
- CGFLOAT_EQ(expected.origin.y, actual.origin.y) && \
- CGFLOAT_EQ(expected.size.width, actual.size.width) && \
- CGFLOAT_EQ(expected.size.height, actual.size.height)) << \
- "Rects do not match: " << \
- [NSStringFromRect(expected) UTF8String] << \
- " != " << [NSStringFromRect(actual) UTF8String]
-
-#endif // CHROME_BROWSER_COCOA_COCOA_TEST_HELPER_H_
diff --git a/chrome/browser/cocoa/cocoa_test_helper.mm b/chrome/browser/cocoa/cocoa_test_helper.mm
deleted file mode 100644
index 885a88a..0000000
--- a/chrome/browser/cocoa/cocoa_test_helper.mm
+++ /dev/null
@@ -1,205 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/cocoa_test_helper.h"
-
-#include "base/debug/debugger.h"
-#include "base/logging.h"
-#include "base/test/test_timeouts.h"
-#import "chrome/browser/chrome_browser_application_mac.h"
-
-@implementation CocoaTestHelperWindow
-
-- (id)initWithContentRect:(NSRect)contentRect {
- return [self initWithContentRect:contentRect
- styleMask:NSBorderlessWindowMask
- backing:NSBackingStoreBuffered
- defer:NO];
-}
-
-- (id)init {
- return [self initWithContentRect:NSMakeRect(0, 0, 800, 600)];
-}
-
-- (void)dealloc {
- // Just a good place to put breakpoints when having problems with
- // unittests and CocoaTestHelperWindow.
- [super dealloc];
-}
-
-- (void)makePretendKeyWindowAndSetFirstResponder:(NSResponder*)responder {
- EXPECT_TRUE([self makeFirstResponder:responder]);
- [self setPretendIsKeyWindow:YES];
-}
-
-- (void)clearPretendKeyWindowAndFirstResponder {
- [self setPretendIsKeyWindow:NO];
- EXPECT_TRUE([self makeFirstResponder:NSApp]);
-}
-
-- (void)setPretendIsKeyWindow:(BOOL)flag {
- pretendIsKeyWindow_ = flag;
-}
-
-- (BOOL)isKeyWindow {
- return pretendIsKeyWindow_;
-}
-
-@end
-
-CocoaTest::CocoaTest() : called_tear_down_(false), test_window_(nil) {
- BootstrapCocoa();
-
- // Set the duration of AppKit-evaluated animations (such as frame changes)
- // to zero for testing purposes. That way they take effect immediately.
- [[NSAnimationContext currentContext] setDuration:0.0];
-
- // The above does not affect window-resize time, such as for an
- // attached sheet dropping in. Set that duration for the current
- // process (this is not persisted). Empirically, the value of 0.0
- // is ignored.
- NSDictionary* dict =
- [NSDictionary dictionaryWithObject:@"0.01" forKey:@"NSWindowResizeTime"];
- [[NSUserDefaults standardUserDefaults] registerDefaults:dict];
-
- // Collect the list of windows that were open when the test started so
- // that we don't wait for them to close in TearDown. Has to be done
- // after BootstrapCocoa is called.
- initial_windows_ = ApplicationWindows();
-}
-
-CocoaTest::~CocoaTest() {
- // Must call CocoaTest's teardown from your overrides.
- DCHECK(called_tear_down_);
-}
-
-void CocoaTest::BootstrapCocoa() {
- // Look in the framework bundle for resources.
- FilePath path;
- PathService::Get(base::DIR_EXE, &path);
- path = path.Append(chrome::kFrameworkName);
- mac_util::SetOverrideAppBundlePath(path);
-
- // Bootstrap Cocoa. It's very unhappy without this.
- [CrApplication sharedApplication];
-}
-
-void CocoaTest::TearDown() {
- called_tear_down_ = true;
- // Call close on our test_window to clean it up if one was opened.
- [test_window_ close];
- test_window_ = nil;
-
- // Recycle the pool to clean up any stuff that was put on the
- // autorelease pool due to window or windowcontroller closures.
- pool_.Recycle();
-
- // Some controls (NSTextFields, NSComboboxes etc) use
- // performSelector:withDelay: to clean up drag handlers and other
- // things (Radar 5851458 "Closing a window with a NSTextView in it
- // should get rid of it immediately"). The event loop must be spun
- // to get everything cleaned up correctly. It normally only takes
- // one to two spins through the event loop to see a change.
-
- // NOTE(shess): Under valgrind, -nextEventMatchingMask:* in one test
- // needed to run twice, once taking .2 seconds, the next time .6
- // seconds. The loop exit condition attempts to be scalable.
-
- // Get the set of windows which weren't present when the test
- // started.
- std::set<NSWindow*> windows_left(WindowsLeft());
-
- while (windows_left.size() > 0) {
- // Cover delayed actions by spinning the loop at least once after
- // this timeout.
- const NSTimeInterval kCloseTimeoutSeconds =
- TestTimeouts::action_timeout_ms() / 1000.0;
-
- // Cover chains of delayed actions by spinning the loop at least
- // this many times.
- const int kCloseSpins = 3;
-
- // Track the set of remaining windows so that everything can be
- // reset if progress is made.
- std::set<NSWindow*> still_left = windows_left;
-
- NSDate* start_date = [NSDate date];
- bool one_more_time = true;
- int spins = 0;
- while (still_left.size() == windows_left.size() &&
- (spins < kCloseSpins || one_more_time)) {
- // Check the timeout before pumping events, so that we'll spin
- // the loop once after the timeout.
- one_more_time = ([start_date timeIntervalSinceNow] > -kCloseTimeoutSeconds);
-
- // Autorelease anything thrown up by the event loop.
- {
- base::mac::ScopedNSAutoreleasePool pool;
- ++spins;
- NSEvent *next_event = [NSApp nextEventMatchingMask:NSAnyEventMask
- untilDate:nil
- inMode:NSDefaultRunLoopMode
- dequeue:YES];
- [NSApp sendEvent:next_event];
- [NSApp updateWindows];
- }
-
- // Refresh the outstanding windows.
- still_left = WindowsLeft();
- }
-
- // If no progress is being made, log a failure and continue.
- if (still_left.size() == windows_left.size()) {
- // NOTE(shess): Failing this expectation means that the test
- // opened windows which have not been fully released. Either
- // there is a leak, or perhaps one of |kCloseTimeoutSeconds| or
- // |kCloseSpins| needs adjustment.
- EXPECT_EQ(0U, windows_left.size());
- for (std::set<NSWindow*>::iterator iter = windows_left.begin();
- iter != windows_left.end(); ++iter) {
- const char* desc = [[*iter description] UTF8String];
- LOG(WARNING) << "Didn't close window " << desc;
- }
- break;
- }
-
- windows_left = still_left;
- }
- PlatformTest::TearDown();
-}
-
-std::set<NSWindow*> CocoaTest::ApplicationWindows() {
- // This must NOT retain the windows it is returning.
- std::set<NSWindow*> windows;
-
- // Must create a pool here because [NSApp windows] has created an array
- // with retains on all the windows in it.
- base::mac::ScopedNSAutoreleasePool pool;
- NSArray *appWindows = [NSApp windows];
- for (NSWindow *window in appWindows) {
- windows.insert(window);
- }
- return windows;
-}
-
-std::set<NSWindow*> CocoaTest::WindowsLeft() {
- const std::set<NSWindow*> windows(ApplicationWindows());
- std::set<NSWindow*> windows_left;
- std::set_difference(windows.begin(), windows.end(),
- initial_windows_.begin(), initial_windows_.end(),
- std::inserter(windows_left, windows_left.begin()));
- return windows_left;
-}
-
-CocoaTestHelperWindow* CocoaTest::test_window() {
- if (!test_window_) {
- test_window_ = [[CocoaTestHelperWindow alloc] init];
- if (base::debug::BeingDebugged()) {
- [test_window_ orderFront:nil];
- } else {
- [test_window_ orderBack:nil];
- }
- }
- return test_window_;
-}
diff --git a/chrome/browser/cocoa/collected_cookies_mac.h b/chrome/browser/cocoa/collected_cookies_mac.h
deleted file mode 100644
index 2392763..0000000
--- a/chrome/browser/cocoa/collected_cookies_mac.h
+++ /dev/null
@@ -1,123 +0,0 @@
-// 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 "base/cocoa_protocols_mac.h"
-#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-#include "chrome/browser/cocoa/constrained_window_mac.h"
-#import "chrome/browser/cocoa/cookie_tree_node.h"
-#include "chrome/browser/cookies_tree_model.h"
-#include "chrome/common/notification_registrar.h"
-
-@class CollectedCookiesWindowController;
-@class VerticalGradientView;
-class TabContents;
-
-// The constrained window delegate reponsible for managing the collected
-// cookies dialog.
-class CollectedCookiesMac : public ConstrainedWindowMacDelegateCustomSheet,
- public NotificationObserver {
- public:
- CollectedCookiesMac(NSWindow* parent, TabContents* tab_contents);
-
- void OnSheetDidEnd(NSWindow* sheet);
-
- // ConstrainedWindowMacDelegateCustomSheet implementation.
- virtual void DeleteDelegate();
-
- private:
- virtual ~CollectedCookiesMac();
-
- // NotificationObserver implementation.
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- NotificationRegistrar registrar_;
-
- ConstrainedWindow* window_;
-
- TabContents* tab_contents_;
-
- CollectedCookiesWindowController* sheet_controller_;
-
- DISALLOW_COPY_AND_ASSIGN(CollectedCookiesMac);
-};
-
-// Controller for the collected cookies dialog. This class stores an internal
-// copy of the CookiesTreeModel but with Cocoa-converted values (NSStrings and
-// NSImages instead of std::strings and SkBitmaps). Doing this allows us to use
-// bindings for the interface. Changes are pushed to this internal model via a
-// very thin bridge (see cookies_window_controller.h).
-@interface CollectedCookiesWindowController : NSWindowController
- <NSOutlineViewDelegate,
- NSWindowDelegate> {
- @private
- // Platform-independent model.
- scoped_ptr<CookiesTreeModel> allowedTreeModel_;
- scoped_ptr<CookiesTreeModel> blockedTreeModel_;
-
- // Cached array of icons.
- scoped_nsobject<NSMutableArray> icons_;
-
- // Our Cocoa copy of the model.
- scoped_nsobject<CocoaCookieTreeNode> cocoaAllowedTreeModel_;
- scoped_nsobject<CocoaCookieTreeNode> cocoaBlockedTreeModel_;
-
- BOOL allowedCookiesButtonsEnabled_;
- BOOL blockedCookiesButtonsEnabled_;
-
- IBOutlet NSTreeController* allowedTreeController_;
- IBOutlet NSTreeController* blockedTreeController_;
- IBOutlet NSOutlineView* allowedOutlineView_;
- IBOutlet NSOutlineView* blockedOutlineView_;
- IBOutlet VerticalGradientView* infoBar_;
- IBOutlet NSImageView* infoBarIcon_;
- IBOutlet NSTextField* infoBarText_;
- IBOutlet NSSplitView* splitView_;
- IBOutlet NSScrollView* lowerScrollView_;
- IBOutlet NSTextField* blockedCookiesText_;
-
- scoped_nsobject<NSViewAnimation> animation_;
-
- TabContents* tabContents_; // weak
-
- BOOL infoBarVisible_;
-}
-@property (readonly, nonatomic) NSTreeController* allowedTreeController;
-@property (readonly, nonatomic) NSTreeController* blockedTreeController;
-
-@property (assign, nonatomic) BOOL allowedCookiesButtonsEnabled;
-@property (assign, nonatomic) BOOL blockedCookiesButtonsEnabled;
-
-// Designated initializer. TabContents cannot be NULL.
-- (id)initWithTabContents:(TabContents*)tabContents;
-
-// Closes the sheet and ends the modal loop. This will also cleanup the memory.
-- (IBAction)closeSheet:(id)sender;
-
-- (IBAction)allowOrigin:(id)sender;
-- (IBAction)allowForSessionFromOrigin:(id)sender;
-- (IBAction)blockOrigin:(id)sender;
-
-// NSSplitView delegate methods:
-- (CGFloat) splitView:(NSSplitView *)sender
- constrainMinCoordinate:(CGFloat)proposedMin
- ofSubviewAt:(NSInteger)offset;
-- (BOOL)splitView:(NSSplitView *)sender canCollapseSubview:(NSView *)subview;
-
-// Returns the cocoaAllowedTreeModel_ and cocoaBlockedTreeModel_.
-- (CocoaCookieTreeNode*)cocoaAllowedTreeModel;
-- (CocoaCookieTreeNode*)cocoaBlockedTreeModel;
-- (void)setCocoaAllowedTreeModel:(CocoaCookieTreeNode*)model;
-- (void)setCocoaBlockedTreeModel:(CocoaCookieTreeNode*)model;
-
-// Returns the allowedTreeModel_ and blockedTreeModel_.
-- (CookiesTreeModel*)allowedTreeModel;
-- (CookiesTreeModel*)blockedTreeModel;
-
-- (void)loadTreeModelFromTabContents;
-@end
diff --git a/chrome/browser/cocoa/collected_cookies_mac.mm b/chrome/browser/cocoa/collected_cookies_mac.mm
deleted file mode 100644
index 7195c4d..0000000
--- a/chrome/browser/cocoa/collected_cookies_mac.mm
+++ /dev/null
@@ -1,499 +0,0 @@
-// 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 "chrome/browser/cocoa/collected_cookies_mac.h"
-
-#include <vector>
-
-#include "app/l10n_util_mac.h"
-#include "app/resource_bundle.h"
-#import "base/mac_util.h"
-#include "base/sys_string_conversions.h"
-#import "chrome/browser/cocoa/vertical_gradient_view.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/notification_service.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#include "skia/ext/skia_utils_mac.h"
-#include "third_party/apple/ImageAndTextCell.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
-#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-
-namespace {
-// Colors for the infobar.
-const double kBannerGradientColorTop[3] =
- {255.0 / 255.0, 242.0 / 255.0, 183.0 / 255.0};
-const double kBannerGradientColorBottom[3] =
- {250.0 / 255.0, 230.0 / 255.0, 145.0 / 255.0};
-const double kBannerStrokeColor = 135.0 / 255.0;
-
-// Minimal height for the collected cookies dialog.
-const CGFloat kMinCollectedCookiesViewHeight = 116;
-} // namespace
-
-#pragma mark Bridge between the constrained window delegate and the sheet
-
-// The delegate used to forward the events from the sheet to the constrained
-// window delegate.
-@interface CollectedCookiesSheetBridge : NSObject {
- CollectedCookiesMac* collectedCookies_; // weak
-}
-- (id)initWithCollectedCookiesMac:(CollectedCookiesMac*)collectedCookies;
-- (void)sheetDidEnd:(NSWindow*)sheet
- returnCode:(int)returnCode
- contextInfo:(void*)contextInfo;
-@end
-
-@implementation CollectedCookiesSheetBridge
-- (id)initWithCollectedCookiesMac:(CollectedCookiesMac*)collectedCookies {
- if ((self = [super init])) {
- collectedCookies_ = collectedCookies;
- }
- return self;
-}
-
-- (void)sheetDidEnd:(NSWindow*)sheet
- returnCode:(int)returnCode
- contextInfo:(void*)contextInfo {
- collectedCookies_->OnSheetDidEnd(sheet);
-}
-@end
-
-#pragma mark Constrained window delegate
-
-CollectedCookiesMac::CollectedCookiesMac(NSWindow* parent,
- TabContents* tab_contents)
- : ConstrainedWindowMacDelegateCustomSheet(
- [[[CollectedCookiesSheetBridge alloc]
- initWithCollectedCookiesMac:this] autorelease],
- @selector(sheetDidEnd:returnCode:contextInfo:)),
- tab_contents_(tab_contents) {
- TabSpecificContentSettings* content_settings =
- tab_contents->GetTabSpecificContentSettings();
- registrar_.Add(this, NotificationType::COLLECTED_COOKIES_SHOWN,
- Source<TabSpecificContentSettings>(content_settings));
-
- sheet_controller_ = [[CollectedCookiesWindowController alloc]
- initWithTabContents:tab_contents];
-
- set_sheet([sheet_controller_ window]);
-
- window_ = tab_contents->CreateConstrainedDialog(this);
-}
-
-CollectedCookiesMac::~CollectedCookiesMac() {
- NSWindow* window = [sheet_controller_ window];
- if (window_ && window && is_sheet_open()) {
- window_ = NULL;
- [NSApp endSheet:window];
- }
-}
-
-void CollectedCookiesMac::DeleteDelegate() {
- delete this;
-}
-
-void CollectedCookiesMac::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- DCHECK(type == NotificationType::COLLECTED_COOKIES_SHOWN);
- DCHECK_EQ(Source<TabSpecificContentSettings>(source).ptr(),
- tab_contents_->GetTabSpecificContentSettings());
- window_->CloseConstrainedWindow();
-}
-
-void CollectedCookiesMac::OnSheetDidEnd(NSWindow* sheet) {
- [sheet orderOut:sheet_controller_];
- if (window_)
- window_->CloseConstrainedWindow();
-}
-
-#pragma mark Window Controller
-
-@interface CollectedCookiesWindowController(Private)
--(void)showInfoBarForDomain:(const string16&)domain
- setting:(ContentSetting)setting;
--(void)showInfoBarForMultipleDomainsAndSetting:(ContentSetting)setting;
--(void)animateInfoBar;
-@end
-
-@implementation CollectedCookiesWindowController
-
-@synthesize allowedCookiesButtonsEnabled =
- allowedCookiesButtonsEnabled_;
-@synthesize blockedCookiesButtonsEnabled =
- blockedCookiesButtonsEnabled_;
-
-@synthesize allowedTreeController = allowedTreeController_;
-@synthesize blockedTreeController = blockedTreeController_;
-
-- (id)initWithTabContents:(TabContents*)tabContents {
- DCHECK(tabContents);
- infoBarVisible_ = NO;
- tabContents_ = tabContents;
-
- NSString* nibpath =
- [mac_util::MainAppBundle() pathForResource:@"CollectedCookies"
- ofType:@"nib"];
- if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
- [self loadTreeModelFromTabContents];
-
- animation_.reset([[NSViewAnimation alloc] init]);
- [animation_ setAnimationBlockingMode:NSAnimationNonblocking];
- }
- return self;
-}
-
-- (void)awakeFromNib {
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- NSImage* infoIcon = rb.GetNativeImageNamed(IDR_INFO);
- DCHECK(infoIcon);
- [infoBarIcon_ setImage:infoIcon];
-
- // Initialize the banner gradient and stroke color.
- NSColor* bannerStartingColor =
- [NSColor colorWithCalibratedRed:kBannerGradientColorTop[0]
- green:kBannerGradientColorTop[1]
- blue:kBannerGradientColorTop[2]
- alpha:1.0];
- NSColor* bannerEndingColor =
- [NSColor colorWithCalibratedRed:kBannerGradientColorBottom[0]
- green:kBannerGradientColorBottom[1]
- blue:kBannerGradientColorBottom[2]
- alpha:1.0];
- scoped_nsobject<NSGradient> bannerGradient(
- [[NSGradient alloc] initWithStartingColor:bannerStartingColor
- endingColor:bannerEndingColor]);
- [infoBar_ setGradient:bannerGradient];
-
- NSColor* bannerStrokeColor =
- [NSColor colorWithCalibratedWhite:kBannerStrokeColor
- alpha:1.0];
- [infoBar_ setStrokeColor:bannerStrokeColor];
-
- // Change the label of the blocked cookies part if necessary.
- if (tabContents_->profile()->GetHostContentSettingsMap()->
- BlockThirdPartyCookies()) {
- [blockedCookiesText_ setStringValue:l10n_util::GetNSString(
- IDS_COLLECTED_COOKIES_BLOCKED_THIRD_PARTY_BLOCKING_ENABLED)];
- CGFloat textDeltaY = [GTMUILocalizerAndLayoutTweaker
- sizeToFitFixedWidthTextField:blockedCookiesText_];
-
- // Shrink the upper custom view.
- NSView* upperContentView = [[splitView_ subviews] objectAtIndex:0];
- NSRect frame = [upperContentView frame];
- [splitView_ setPosition:(frame.size.height - textDeltaY/2.0)
- ofDividerAtIndex:0];
-
- // Shrink the lower outline view.
- frame = [lowerScrollView_ frame];
- frame.size.height -= textDeltaY;
- [lowerScrollView_ setFrame:frame];
-
- // Move the label down so it actually fits.
- frame = [blockedCookiesText_ frame];
- frame.origin.y -= textDeltaY;
- [blockedCookiesText_ setFrame:frame];
- }
-}
-
-- (void)windowWillClose:(NSNotification*)notif {
- [allowedOutlineView_ setDelegate:nil];
- [blockedOutlineView_ setDelegate:nil];
- [animation_ stopAnimation];
- [self autorelease];
-}
-
-- (IBAction)closeSheet:(id)sender {
- [NSApp endSheet:[self window]];
-}
-
-- (void)addException:(ContentSetting)setting
- forTreeController:(NSTreeController*)controller {
- NSArray* nodes = [controller selectedNodes];
- BOOL multipleDomainsChanged = NO;
- string16 lastDomain;
- for (NSTreeNode* treeNode in nodes) {
- CocoaCookieTreeNode* node = [treeNode representedObject];
- CookieTreeNode* cookie = static_cast<CookieTreeNode*>([node treeNode]);
- if (cookie->GetDetailedInfo().node_type !=
- CookieTreeNode::DetailedInfo::TYPE_ORIGIN) {
- continue;
- }
- CookieTreeOriginNode* origin_node =
- static_cast<CookieTreeOriginNode*>(cookie);
- origin_node->CreateContentException(
- tabContents_->profile()->GetHostContentSettingsMap(),
- setting);
- if (!lastDomain.empty())
- multipleDomainsChanged = YES;
- lastDomain = origin_node->GetTitle();
- }
- if (multipleDomainsChanged)
- [self showInfoBarForMultipleDomainsAndSetting:setting];
- else
- [self showInfoBarForDomain:lastDomain setting:setting];
-}
-
-- (IBAction)allowOrigin:(id)sender {
- [self addException:CONTENT_SETTING_ALLOW
- forTreeController:blockedTreeController_];
-}
-
-- (IBAction)allowForSessionFromOrigin:(id)sender {
- [self addException:CONTENT_SETTING_SESSION_ONLY
- forTreeController:blockedTreeController_];
-}
-
-- (IBAction)blockOrigin:(id)sender {
- [self addException:CONTENT_SETTING_BLOCK
- forTreeController:allowedTreeController_];
-}
-
-- (CGFloat) splitView:(NSSplitView *)sender
- constrainMinCoordinate:(CGFloat)proposedMin
- ofSubviewAt:(NSInteger)offset {
- return proposedMin + kMinCollectedCookiesViewHeight;
-}
-- (CGFloat) splitView:(NSSplitView *)sender
- constrainMaxCoordinate:(CGFloat)proposedMax
- ofSubviewAt:(NSInteger)offset {
- return proposedMax - kMinCollectedCookiesViewHeight;
-}
-- (BOOL)splitView:(NSSplitView *)sender canCollapseSubview:(NSView *)subview {
- return YES;
-}
-
-- (CocoaCookieTreeNode*)cocoaAllowedTreeModel {
- return cocoaAllowedTreeModel_.get();
-}
-- (void)setCocoaAllowedTreeModel:(CocoaCookieTreeNode*)model {
- cocoaAllowedTreeModel_.reset([model retain]);
-}
-
-- (CookiesTreeModel*)allowedTreeModel {
- return allowedTreeModel_.get();
-}
-
-- (CocoaCookieTreeNode*)cocoaBlockedTreeModel {
- return cocoaBlockedTreeModel_.get();
-}
-- (void)setCocoaBlockedTreeModel:(CocoaCookieTreeNode*)model {
- cocoaBlockedTreeModel_.reset([model retain]);
-}
-
-- (CookiesTreeModel*)blockedTreeModel {
- return blockedTreeModel_.get();
-}
-
-- (void)outlineView:(NSOutlineView*)outlineView
- willDisplayCell:(id)cell
- forTableColumn:(NSTableColumn*)tableColumn
- item:(id)item {
- CocoaCookieTreeNode* node = [item representedObject];
- int index;
- if (outlineView == allowedOutlineView_)
- index = allowedTreeModel_->GetIconIndex([node treeNode]);
- else
- index = blockedTreeModel_->GetIconIndex([node treeNode]);
- NSImage* icon = nil;
- if (index >= 0)
- icon = [icons_ objectAtIndex:index];
- else
- icon = [icons_ lastObject];
- DCHECK([cell isKindOfClass:[ImageAndTextCell class]]);
- [static_cast<ImageAndTextCell*>(cell) setImage:icon];
-}
-
-- (void)outlineViewSelectionDidChange:(NSNotification*)notif {
- BOOL isAllowedOutlineView;
- if ([notif object] == allowedOutlineView_) {
- isAllowedOutlineView = YES;
- } else if ([notif object] == blockedOutlineView_) {
- isAllowedOutlineView = NO;
- } else {
- NOTREACHED();
- return;
- }
- NSTreeController* controller =
- isAllowedOutlineView ? allowedTreeController_ : blockedTreeController_;
-
- NSArray* nodes = [controller selectedNodes];
- for (NSTreeNode* treeNode in nodes) {
- CocoaCookieTreeNode* node = [treeNode representedObject];
- CookieTreeNode* cookie = static_cast<CookieTreeNode*>([node treeNode]);
- if (cookie->GetDetailedInfo().node_type !=
- CookieTreeNode::DetailedInfo::TYPE_ORIGIN) {
- continue;
- }
- CookieTreeOriginNode* origin_node =
- static_cast<CookieTreeOriginNode*>(cookie);
- if (origin_node->CanCreateContentException()) {
- if (isAllowedOutlineView) {
- [self setAllowedCookiesButtonsEnabled:YES];
- } else {
- [self setBlockedCookiesButtonsEnabled:YES];
- }
- return;
- }
- }
- if (isAllowedOutlineView) {
- [self setAllowedCookiesButtonsEnabled:NO];
- } else {
- [self setBlockedCookiesButtonsEnabled:NO];
- }
-}
-
-// Initializes the |allowedTreeModel_| and |blockedTreeModel_|, and builds
-// the |cocoaAllowedTreeModel_| and |cocoaBlockedTreeModel_|.
-- (void)loadTreeModelFromTabContents {
- TabSpecificContentSettings* content_settings =
- tabContents_->GetTabSpecificContentSettings();
- allowedTreeModel_.reset(content_settings->GetAllowedCookiesTreeModel());
- blockedTreeModel_.reset(content_settings->GetBlockedCookiesTreeModel());
-
- // Convert the model's icons from Skia to Cocoa.
- std::vector<SkBitmap> skiaIcons;
- allowedTreeModel_->GetIcons(&skiaIcons);
- icons_.reset([[NSMutableArray alloc] init]);
- for (std::vector<SkBitmap>::iterator it = skiaIcons.begin();
- it != skiaIcons.end(); ++it) {
- [icons_ addObject:gfx::SkBitmapToNSImage(*it)];
- }
-
- // Default icon will be the last item in the array.
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- // TODO(rsesek): Rename this resource now that it's in multiple places.
- [icons_ addObject:rb.GetNativeImageNamed(IDR_BOOKMARK_BAR_FOLDER)];
-
- // Create the Cocoa model.
- CookieTreeNode* root =
- static_cast<CookieTreeNode*>(allowedTreeModel_->GetRoot());
- scoped_nsobject<CocoaCookieTreeNode> model(
- [[CocoaCookieTreeNode alloc] initWithNode:root]);
- [self setCocoaAllowedTreeModel:model.get()]; // Takes ownership.
- root = static_cast<CookieTreeNode*>(blockedTreeModel_->GetRoot());
- model.reset(
- [[CocoaCookieTreeNode alloc] initWithNode:root]);
- [self setCocoaBlockedTreeModel:model.get()]; // Takes ownership.
-}
-
--(void)showInfoBarForMultipleDomainsAndSetting:(ContentSetting)setting {
- NSString* label;
- switch (setting) {
- case CONTENT_SETTING_BLOCK:
- label = l10n_util::GetNSString(
- IDS_COLLECTED_COOKIES_MULTIPLE_BLOCK_RULES_CREATED);
- break;
-
- case CONTENT_SETTING_ALLOW:
- label = l10n_util::GetNSString(
- IDS_COLLECTED_COOKIES_MULTIPLE_ALLOW_RULES_CREATED);
- break;
-
- case CONTENT_SETTING_SESSION_ONLY:
- label = l10n_util::GetNSString(
- IDS_COLLECTED_COOKIES_MULTIPLE_SESSION_RULES_CREATED);
- break;
-
- default:
- NOTREACHED();
- label = [[[NSString alloc] init] autorelease];
- }
- [infoBarText_ setStringValue:label];
- [self animateInfoBar];
-}
-
--(void)showInfoBarForDomain:(const string16&)domain
- setting:(ContentSetting)setting {
- NSString* label;
- switch (setting) {
- case CONTENT_SETTING_BLOCK:
- label = l10n_util::GetNSStringF(
- IDS_COLLECTED_COOKIES_BLOCK_RULE_CREATED,
- domain);
- break;
-
- case CONTENT_SETTING_ALLOW:
- label = l10n_util::GetNSStringF(
- IDS_COLLECTED_COOKIES_ALLOW_RULE_CREATED,
- domain);
- break;
-
- case CONTENT_SETTING_SESSION_ONLY:
- label = l10n_util::GetNSStringF(
- IDS_COLLECTED_COOKIES_SESSION_RULE_CREATED,
- domain);
- break;
-
- default:
- NOTREACHED();
- label = [[[NSString alloc] init] autorelease];
- }
- [infoBarText_ setStringValue:label];
- [self animateInfoBar];
-}
-
--(void)animateInfoBar {
- if (infoBarVisible_)
- return;
-
- infoBarVisible_ = YES;
-
- NSMutableArray* animations = [NSMutableArray arrayWithCapacity:3];
-
- NSWindow* sheet = [self window];
- NSRect sheetFrame = [sheet frame];
- NSRect infoBarFrame = [infoBar_ frame];
- NSRect splitViewFrame = [splitView_ frame];
-
- // Calculate the end position of the info bar and set it to its start
- // position.
- infoBarFrame.origin.y = NSHeight(sheetFrame);
- infoBarFrame.size.width = NSWidth(sheetFrame);
- NSRect infoBarStartFrame = infoBarFrame;
- infoBarStartFrame.origin.y += NSHeight(infoBarFrame);
- infoBarStartFrame.size.height = 0.0;
- [infoBar_ setFrame:infoBarStartFrame];
- [[[self window] contentView] addSubview:infoBar_];
-
- // Calculate the new position of the sheet.
- sheetFrame.origin.y -= NSHeight(infoBarFrame);
- sheetFrame.size.height += NSHeight(infoBarFrame);
-
- // Slide the infobar in.
- [animations addObject:
- [NSDictionary dictionaryWithObjectsAndKeys:
- infoBar_, NSViewAnimationTargetKey,
- [NSValue valueWithRect:infoBarFrame],
- NSViewAnimationEndFrameKey,
- [NSValue valueWithRect:infoBarStartFrame],
- NSViewAnimationStartFrameKey,
- nil]];
- // Make sure the split view ends up in the right position.
- [animations addObject:
- [NSDictionary dictionaryWithObjectsAndKeys:
- splitView_, NSViewAnimationTargetKey,
- [NSValue valueWithRect:splitViewFrame],
- NSViewAnimationEndFrameKey,
- nil]];
-
- // Grow the sheet.
- [animations addObject:
- [NSDictionary dictionaryWithObjectsAndKeys:
- sheet, NSViewAnimationTargetKey,
- [NSValue valueWithRect:sheetFrame],
- NSViewAnimationEndFrameKey,
- nil]];
- [animation_ setViewAnimations:animations];
- // The default duration is 0.5s, which actually feels slow in here, so speed
- // it up a bit.
- [animation_ gtm_setDuration:0.2
- eventMask:NSLeftMouseUpMask];
- [animation_ startAnimation];
-}
-
-@end
diff --git a/chrome/browser/cocoa/collected_cookies_mac_unittest.mm b/chrome/browser/cocoa/collected_cookies_mac_unittest.mm
deleted file mode 100644
index c0a8490..0000000
--- a/chrome/browser/cocoa/collected_cookies_mac_unittest.mm
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) 2009 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>
-
-#import "chrome/browser/cocoa/collected_cookies_mac.h"
-
-#include "base/ref_counted.h"
-#include "chrome/browser/renderer_host/site_instance.h"
-#include "chrome/browser/renderer_host/test/test_render_view_host.h"
-#include "chrome/browser/tab_contents/test_tab_contents.h"
-#include "chrome/browser/profile.h"
-#include "chrome/test/testing_profile.h"
-
-namespace {
-
-class CollectedCookiesWindowControllerTest : public RenderViewHostTestHarness {
-};
-
-TEST_F(CollectedCookiesWindowControllerTest, Construction) {
- BrowserThread ui_thread(BrowserThread::UI, MessageLoop::current());
- // Create a test tab. SiteInstance will be deleted when tabContents is
- // deleted.
- SiteInstance* instance =
- SiteInstance::CreateSiteInstance(profile_.get());
- TestTabContents* tabContents = new TestTabContents(profile_.get(),
- instance);
- CollectedCookiesWindowController* controller =
- [[CollectedCookiesWindowController alloc]
- initWithTabContents:tabContents];
-
- [controller release];
-
- delete tabContents;
-}
-
-} // namespace
-
diff --git a/chrome/browser/cocoa/command_observer_bridge.h b/chrome/browser/cocoa/command_observer_bridge.h
deleted file mode 100644
index 83b5577..0000000
--- a/chrome/browser/cocoa/command_observer_bridge.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_COMMAND_OBSERVER_BRIDGE
-#define CHROME_BROWSER_COCOA_COMMAND_OBSERVER_BRIDGE
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "chrome/browser/command_updater.h"
-
-@protocol CommandObserverProtocol;
-
-// A C++ bridge class that handles listening for updates to commands and
-// passing them back to an object that supports the protocol delcared below.
-// The observer will create one of these bridges, call ObserveCommand() on the
-// command ids it cares about, and then wait for update notifications,
-// delivered via -enabledStateChangedForCommand:enabled:. Destroying this
-// bridge will handle automatically unregistering for updates, so there's no
-// need to do that manually.
-
-class CommandObserverBridge : public CommandUpdater::CommandObserver {
- public:
- CommandObserverBridge(id<CommandObserverProtocol> observer,
- CommandUpdater* commands);
- virtual ~CommandObserverBridge();
-
- // Register for updates about |command|.
- void ObserveCommand(int command);
-
- protected:
- // Overridden from CommandUpdater::CommandObserver
- virtual void EnabledStateChangedForCommand(int command, bool enabled);
-
- private:
- id<CommandObserverProtocol> observer_; // weak, owns me
- CommandUpdater* commands_; // weak
-};
-
-// Implemented by the observing Objective-C object, called when there is a
-// state change for the given command.
-@protocol CommandObserverProtocol
-- (void)enabledStateChangedForCommand:(NSInteger)command enabled:(BOOL)enabled;
-@end
-
-#endif // CHROME_BROWSER_COCOA_COMMAND_OBSERVER_BRIDGE
diff --git a/chrome/browser/cocoa/command_observer_bridge.mm b/chrome/browser/cocoa/command_observer_bridge.mm
deleted file mode 100644
index cc4fc22..0000000
--- a/chrome/browser/cocoa/command_observer_bridge.mm
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/command_observer_bridge.h"
-
-#include "base/logging.h"
-
-CommandObserverBridge::CommandObserverBridge(
- id<CommandObserverProtocol> observer, CommandUpdater* commands)
- : observer_(observer), commands_(commands) {
- DCHECK(observer_ && commands_);
-}
-
-CommandObserverBridge::~CommandObserverBridge() {
- // Unregister the notifications
- commands_->RemoveCommandObserver(this);
-}
-
-void CommandObserverBridge::ObserveCommand(int command) {
- commands_->AddCommandObserver(command, this);
-}
-
-void CommandObserverBridge::EnabledStateChangedForCommand(int command,
- bool enabled) {
- [observer_ enabledStateChangedForCommand:command
- enabled:enabled ? YES : NO];
-}
diff --git a/chrome/browser/cocoa/command_observer_bridge_unittest.mm b/chrome/browser/cocoa/command_observer_bridge_unittest.mm
deleted file mode 100644
index 40fed56..0000000
--- a/chrome/browser/cocoa/command_observer_bridge_unittest.mm
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright (c) 2009 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 "base/scoped_ptr.h"
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/command_observer_bridge.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-// Implements the callback interface. Records the last command id and
-// enabled state it has received so it can be queried by the tests to see
-// if we got a notification or not.
-@interface CommandTestObserver : NSObject<CommandObserverProtocol> {
- @private
- int lastCommand_; // id of last received state change
- bool lastState_; // state of last received state change
-}
-- (int)lastCommand;
-- (bool)lastState;
-@end
-
-@implementation CommandTestObserver
-- (void)enabledStateChangedForCommand:(NSInteger)command enabled:(BOOL)enabled {
- lastCommand_ = command;
- lastState_ = enabled;
-}
-- (int)lastCommand {
- return lastCommand_;
-}
-- (bool)lastState {
- return lastState_;
-}
-@end
-
-namespace {
-
-class CommandObserverBridgeTest : public PlatformTest {
- public:
- CommandObserverBridgeTest()
- : updater_(new CommandUpdater(NULL)),
- observer_([[CommandTestObserver alloc] init]) {
- }
- scoped_ptr<CommandUpdater> updater_;
- scoped_nsobject<CommandTestObserver> observer_;
-};
-
-// Tests creation and deletion. NULL arguments aren't allowed.
-TEST_F(CommandObserverBridgeTest, Create) {
- CommandObserverBridge bridge(observer_.get(), updater_.get());
-}
-
-// Observes state changes on command ids 1 and 2. Ensure we don't get
-// a notification of a state change on a command we're not observing (3).
-// Commands start off enabled in CommandUpdater.
-TEST_F(CommandObserverBridgeTest, Observe) {
- CommandObserverBridge bridge(observer_.get(), updater_.get());
- bridge.ObserveCommand(1);
- bridge.ObserveCommand(2);
-
- // Validate initial state assumptions.
- EXPECT_EQ([observer_ lastCommand], 0);
- EXPECT_EQ([observer_ lastState], false);
- EXPECT_EQ(updater_->IsCommandEnabled(1), true);
- EXPECT_EQ(updater_->IsCommandEnabled(2), true);
-
- updater_->UpdateCommandEnabled(1, false);
- EXPECT_EQ([observer_ lastCommand], 1);
- EXPECT_EQ([observer_ lastState], false);
-
- updater_->UpdateCommandEnabled(2, false);
- EXPECT_EQ([observer_ lastCommand], 2);
- EXPECT_EQ([observer_ lastState], false);
-
- updater_->UpdateCommandEnabled(1, true);
- EXPECT_EQ([observer_ lastCommand], 1);
- EXPECT_EQ([observer_ lastState], true);
-
- // Change something we're not watching and make sure the last state hasn't
- // changed.
- updater_->UpdateCommandEnabled(3, false);
- EXPECT_EQ([observer_ lastCommand], 1);
- EXPECT_NE([observer_ lastCommand], 3);
- EXPECT_EQ([observer_ lastState], true);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/confirm_quit_panel_controller.h b/chrome/browser/cocoa/confirm_quit_panel_controller.h
deleted file mode 100644
index fccafa9..0000000
--- a/chrome/browser/cocoa/confirm_quit_panel_controller.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// 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 "base/cocoa_protocols_mac.h"
-
-// The ConfirmQuitPanelController manages the black HUD window that tells users
-// to "Hold Cmd+Q to Quit".
-@interface ConfirmQuitPanelController : NSWindowController<NSWindowDelegate> {
-}
-
-// Returns a singleton instance of the Controller. This will create one if it
-// does not currently exist.
-+ (ConfirmQuitPanelController*)sharedController;
-
-// Shows the window.
-- (void)showWindow:(id)sender;
-
-// If the user did not confirm quit, send this message to give the user
-// instructions on how to quit.
-- (void)dismissPanel;
-
-@end
diff --git a/chrome/browser/cocoa/confirm_quit_panel_controller.mm b/chrome/browser/cocoa/confirm_quit_panel_controller.mm
deleted file mode 100644
index 131c40d..0000000
--- a/chrome/browser/cocoa/confirm_quit_panel_controller.mm
+++ /dev/null
@@ -1,85 +0,0 @@
-// 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>
-#import <QuartzCore/QuartzCore.h>
-
-#include "base/logging.h"
-#include "base/mac_util.h"
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/confirm_quit_panel_controller.h"
-
-@interface ConfirmQuitPanelController (Private)
-- (id)initInternal;
-- (void)animateFadeOut;
-@end
-
-ConfirmQuitPanelController* g_confirmQuitPanelController = nil;
-
-@implementation ConfirmQuitPanelController
-
-+ (ConfirmQuitPanelController*)sharedController {
- if (!g_confirmQuitPanelController) {
- g_confirmQuitPanelController =
- [[ConfirmQuitPanelController alloc] initInternal];
- }
- return g_confirmQuitPanelController;
-}
-
-- (id)initInternal {
- NSString* nibPath =
- [mac_util::MainAppBundle() pathForResource:@"ConfirmQuitPanel"
- ofType:@"nib"];
- if ((self = [super initWithWindowNibPath:nibPath owner:self])) {
- }
- return self;
-}
-
-- (void)awakeFromNib {
- DCHECK([self window]);
- DCHECK_EQ(self, [[self window] delegate]);
-}
-
-- (void)windowWillClose:(NSNotification*)notif {
- // Release all animations because CAAnimation retains its delegate (self),
- // which will cause a retain cycle. Break it!
- [[self window] setAnimations:[NSDictionary dictionary]];
- g_confirmQuitPanelController = nil;
- [self autorelease];
-}
-
-- (void)showWindow:(id)sender {
- // If a panel that is fading out is going to be reused here, make sure it
- // does not get released when the animation finishes.
- scoped_nsobject<ConfirmQuitPanelController> stayAlive([self retain]);
- [[self window] setAnimations:[NSDictionary dictionary]];
- [[self window] center];
- [[self window] setAlphaValue:1.0];
- [super showWindow:sender];
-}
-
-- (void)dismissPanel {
- [self performSelector:@selector(animateFadeOut)
- withObject:nil
- afterDelay:1.0];
-}
-
-- (void)animateFadeOut {
- NSWindow* window = [self window];
- scoped_nsobject<CAAnimation> animation(
- [[window animationForKey:@"alphaValue"] copy]);
- [animation setDelegate:self];
- [animation setDuration:0.2];
- NSMutableDictionary* dictionary =
- [NSMutableDictionary dictionaryWithDictionary:[window animations]];
- [dictionary setObject:animation forKey:@"alphaValue"];
- [window setAnimations:dictionary];
- [[window animator] setAlphaValue:0.0];
-}
-
-- (void)animationDidStop:(CAAnimation*)theAnimation finished:(BOOL)finished {
- [self close];
-}
-
-@end
diff --git a/chrome/browser/cocoa/confirm_quit_panel_controller_unittest.mm b/chrome/browser/cocoa/confirm_quit_panel_controller_unittest.mm
deleted file mode 100644
index 93de9ba..0000000
--- a/chrome/browser/cocoa/confirm_quit_panel_controller_unittest.mm
+++ /dev/null
@@ -1,28 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/confirm_quit_panel_controller.h"
-
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-
-namespace {
-
-class ConfirmQuitPanelControllerTest : public CocoaTest {
-};
-
-
-TEST_F(ConfirmQuitPanelControllerTest, ShowAndDismiss) {
- ConfirmQuitPanelController* controller =
- [ConfirmQuitPanelController sharedController];
- // Test singleton.
- EXPECT_EQ(controller, [ConfirmQuitPanelController sharedController]);
- [controller showWindow:nil];
- [controller dismissPanel]; // Releases self.
- // The controller should still be the singleton instance until after the
- // animation runs and the window closes. That will happen after this test body
- // finishes executing.
- EXPECT_EQ(controller, [ConfirmQuitPanelController sharedController]);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/constrained_html_delegate_mac.mm b/chrome/browser/cocoa/constrained_html_delegate_mac.mm
deleted file mode 100644
index efb228a..0000000
--- a/chrome/browser/cocoa/constrained_html_delegate_mac.mm
+++ /dev/null
@@ -1,153 +0,0 @@
-// 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.
-
-#include "chrome/browser/dom_ui/constrained_html_ui.h"
-
-#include "base/scoped_nsobject.h"
-#include "chrome/browser/cocoa/constrained_window_mac.h"
-#include "chrome/browser/dom_ui/html_dialog_ui.h"
-#include "chrome/browser/dom_ui/html_dialog_tab_contents_delegate.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#import <Cocoa/Cocoa.h>
-#include "ipc/ipc_message.h"
-
-class ConstrainedHtmlDelegateMac :
- public ConstrainedWindowMacDelegateCustomSheet,
- public HtmlDialogTabContentsDelegate,
- public ConstrainedHtmlUIDelegate {
-
- public:
- ConstrainedHtmlDelegateMac(Profile* profile,
- HtmlDialogUIDelegate* delegate);
- ~ConstrainedHtmlDelegateMac() {}
-
- // ConstrainedWindowMacDelegateCustomSheet -----------------------------------
- virtual void DeleteDelegate() {
- // From ConstrainedWindowMacDelegate: "you MUST close the sheet belonging to
- // your delegate in this method."
- if (is_sheet_open())
- [NSApp endSheet:sheet()];
- html_delegate_->OnDialogClosed("");
- delete this;
- }
-
- // ConstrainedHtmlDelegate ---------------------------------------------------
- virtual HtmlDialogUIDelegate* GetHtmlDialogUIDelegate();
- virtual void OnDialogClose();
-
- // HtmlDialogTabContentsDelegate ---------------------------------------------
- void MoveContents(TabContents* source, const gfx::Rect& pos) {}
- void ToolbarSizeChanged(TabContents* source, bool is_animating) {}
- void HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {}
-
- void set_window(ConstrainedWindow* window) {
- constrained_window_ = window;
- }
-
- private:
- TabContents tab_contents_; // Holds the HTML to be displayed in the sheet.
- HtmlDialogUIDelegate* html_delegate_; // weak.
-
- // The constrained window that owns |this|. Saved here because it needs to be
- // closed in response to the DOMUI OnDialogClose callback.
- ConstrainedWindow* constrained_window_;
-
- DISALLOW_COPY_AND_ASSIGN(ConstrainedHtmlDelegateMac);
-};
-
-// The delegate used to forward events from the sheet to the constrained
-// window delegate. This bridge needs to be passed into the customsheet
-// to allow the HtmlDialog to know when the sheet closes.
-@interface ConstrainedHtmlDialogSheetCocoa : NSObject {
- ConstrainedHtmlDelegateMac* constrainedHtmlDelegate_; // weak
-}
-- (id)initWithConstrainedHtmlDelegateMac:
- (ConstrainedHtmlDelegateMac*)ConstrainedHtmlDelegateMac;
-- (void)sheetDidEnd:(NSWindow*)sheet
- returnCode:(int)returnCode
- contextInfo:(void*)contextInfo;
-@end
-
-ConstrainedHtmlDelegateMac::ConstrainedHtmlDelegateMac(
- Profile* profile,
- HtmlDialogUIDelegate* delegate)
- : HtmlDialogTabContentsDelegate(profile),
- tab_contents_(profile, NULL, MSG_ROUTING_NONE, NULL, NULL),
- html_delegate_(delegate),
- constrained_window_(NULL) {
- tab_contents_.set_delegate(this);
-
- // Set |this| as a property on the tab contents so that the ConstrainedHtmlUI
- // can get a reference to |this|.
- ConstrainedHtmlUI::GetPropertyAccessor().SetProperty(
- tab_contents_.property_bag(), this);
-
- tab_contents_.controller().LoadURL(delegate->GetDialogContentURL(),
- GURL(), PageTransition::START_PAGE);
-
- // Create NSWindow to hold tab_contents in the constrained sheet:
- gfx::Size size;
- delegate->GetDialogSize(&size);
- NSRect frame = NSMakeRect(0, 0, size.width(), size.height());
-
- // |window| is retained by the ConstrainedWindowMacDelegateCustomSheet when
- // the sheet is initialized.
- scoped_nsobject<NSWindow> window;
- window.reset(
- [[NSWindow alloc] initWithContentRect:frame
- styleMask:NSTitledWindowMask
- backing:NSBackingStoreBuffered
- defer:YES]);
-
- [window.get() setContentView:tab_contents_.GetNativeView()];
-
- // Set the custom sheet to point to the new window.
- ConstrainedWindowMacDelegateCustomSheet::init(
- window.get(),
- [[[ConstrainedHtmlDialogSheetCocoa alloc]
- initWithConstrainedHtmlDelegateMac:this] autorelease],
- @selector(sheetDidEnd:returnCode:contextInfo:));
-}
-
-HtmlDialogUIDelegate* ConstrainedHtmlDelegateMac::GetHtmlDialogUIDelegate() {
- return html_delegate_;
-}
-
-void ConstrainedHtmlDelegateMac::OnDialogClose() {
- DCHECK(constrained_window_);
- if (constrained_window_)
- constrained_window_->CloseConstrainedWindow();
-}
-
-// static
-void ConstrainedHtmlUI::CreateConstrainedHtmlDialog(
- Profile* profile,
- HtmlDialogUIDelegate* delegate,
- TabContents* overshadowed) {
- // Deleted when ConstrainedHtmlDelegateMac::DeleteDelegate() runs.
- ConstrainedHtmlDelegateMac* constrained_delegate =
- new ConstrainedHtmlDelegateMac(profile, delegate);
- // Deleted when ConstrainedHtmlDelegateMac::OnDialogClose() runs.
- ConstrainedWindow* constrained_window =
- overshadowed->CreateConstrainedDialog(constrained_delegate);
- constrained_delegate->set_window(constrained_window);
-}
-
-@implementation ConstrainedHtmlDialogSheetCocoa
-
-- (id)initWithConstrainedHtmlDelegateMac:
- (ConstrainedHtmlDelegateMac*)ConstrainedHtmlDelegateMac {
- if ((self = [super init]))
- constrainedHtmlDelegate_ = ConstrainedHtmlDelegateMac;
- return self;
-}
-
-- (void)sheetDidEnd:(NSWindow*)sheet
- returnCode:(int)returnCode
- contextInfo:(void *)contextInfo {
- [sheet orderOut:self];
-}
-
-@end
diff --git a/chrome/browser/cocoa/constrained_window_mac.h b/chrome/browser/cocoa/constrained_window_mac.h
deleted file mode 100644
index 321f9c7..0000000
--- a/chrome/browser/cocoa/constrained_window_mac.h
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_CONSTRAINED_WINDOW_MAC_H_
-#define CHROME_BROWSER_COCOA_CONSTRAINED_WINDOW_MAC_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "chrome/browser/tab_contents/constrained_window.h"
-
-#include "base/basictypes.h"
-#include "base/logging.h"
-#include "base/scoped_nsobject.h"
-
-@class BrowserWindowController;
-@class GTMWindowSheetController;
-@class NSView;
-@class NSWindow;
-class TabContents;
-
-// Base class for constrained dialog delegates. Never inherit from this
-// directly.
-class ConstrainedWindowMacDelegate {
- public:
- ConstrainedWindowMacDelegate() : is_sheet_open_(false) { }
- virtual ~ConstrainedWindowMacDelegate();
-
- // Tells the delegate to either delete itself or set up a task to delete
- // itself later. Note that you MUST close the sheet belonging to your delegate
- // in this method.
- virtual void DeleteDelegate() = 0;
-
- // Called by the tab controller, you do not need to do anything yourself
- // with this method.
- virtual void RunSheet(GTMWindowSheetController* sheetController,
- NSView* view) = 0;
- protected:
- // Returns true if this delegate's sheet is currently showing.
- bool is_sheet_open() { return is_sheet_open_; }
-
- private:
- bool is_sheet_open_;
- void set_sheet_open(bool is_open) { is_sheet_open_ = is_open; }
- friend class ConstrainedWindowMac;
-};
-
-// Subclass this for a dialog delegate that displays a system sheet such as
-// an NSAlert, an open or save file panel, etc.
-class ConstrainedWindowMacDelegateSystemSheet
- : public ConstrainedWindowMacDelegate {
- public:
- ConstrainedWindowMacDelegateSystemSheet(id delegate, SEL didEndSelector)
- : systemSheet_(nil),
- delegate_([delegate retain]),
- didEndSelector_(didEndSelector) { }
-
- protected:
- void set_sheet(id sheet) { systemSheet_.reset([sheet retain]); }
- id sheet() { return systemSheet_; }
-
- // Returns an NSArray to be passed as parameters to GTMWindowSheetController.
- // Array's contents should be the arguments passed to the system sheet's
- // beginSheetForWindow:... method. The window argument must be [NSNull null].
- //
- // The default implementation returns
- // [null window, delegate, didEndSelector, null contextInfo]
- // Subclasses may override this if they show a system sheet which takes
- // different parameters.
- virtual NSArray* GetSheetParameters(id delegate, SEL didEndSelector);
-
- private:
- virtual void RunSheet(GTMWindowSheetController* sheetController,
- NSView* view);
- scoped_nsobject<id> systemSheet_;
- scoped_nsobject<id> delegate_;
- SEL didEndSelector_;
-};
-
-// Subclass this for a dialog delegate that displays a custom sheet, e.g. loaded
-// from a nib file.
-class ConstrainedWindowMacDelegateCustomSheet
- : public ConstrainedWindowMacDelegate {
- public:
- ConstrainedWindowMacDelegateCustomSheet()
- : customSheet_(nil),
- delegate_(nil),
- didEndSelector_(NULL) { }
-
- ConstrainedWindowMacDelegateCustomSheet(id delegate, SEL didEndSelector)
- : customSheet_(nil),
- delegate_([delegate retain]),
- didEndSelector_(didEndSelector) { }
-
- protected:
- // For when you need to delay initalization after the constructor call.
- void init(NSWindow* sheet, id delegate, SEL didEndSelector) {
- DCHECK(!delegate_.get());
- DCHECK(!didEndSelector_);
- customSheet_.reset([sheet retain]);
- delegate_.reset([delegate retain]);
- didEndSelector_ = didEndSelector;
- DCHECK(delegate_.get());
- DCHECK(didEndSelector_);
- }
- void set_sheet(NSWindow* sheet) { customSheet_.reset([sheet retain]); }
- NSWindow* sheet() { return customSheet_; }
-
- private:
- virtual void RunSheet(GTMWindowSheetController* sheetController,
- NSView* view);
- scoped_nsobject<NSWindow> customSheet_;
- scoped_nsobject<id> delegate_;
- SEL didEndSelector_;
-};
-
-// Constrained window implementation for the Mac port. A constrained window
-// is a per-tab sheet on OS X.
-//
-// Constrained windows work slightly differently on OS X than on the other
-// platforms:
-// 1. A constrained window is bound to both a tab and window on OS X.
-// 2. The delegate is responsible for closing the sheet again when it is
-// deleted.
-class ConstrainedWindowMac : public ConstrainedWindow {
- public:
- virtual ~ConstrainedWindowMac();
-
- // Overridden from ConstrainedWindow:
- virtual void ShowConstrainedWindow();
- virtual void CloseConstrainedWindow();
-
- // Returns the TabContents that constrains this Constrained Window.
- TabContents* owner() const { return owner_; }
-
- // Returns the window's delegate.
- ConstrainedWindowMacDelegate* delegate() { return delegate_; }
-
- // Makes the constrained window visible, if it is not yet visible.
- void Realize(BrowserWindowController* controller);
-
- private:
- friend class ConstrainedWindow;
-
- ConstrainedWindowMac(TabContents* owner,
- ConstrainedWindowMacDelegate* delegate);
-
- // The TabContents that owns and constrains this ConstrainedWindow.
- TabContents* owner_;
-
- // Delegate that provides the contents of this constrained window.
- ConstrainedWindowMacDelegate* delegate_;
-
- // Controller of the window that contains this sheet.
- BrowserWindowController* controller_;
-
- // Stores if |ShowConstrainedWindow()| was called.
- bool should_be_visible_;
-
- DISALLOW_COPY_AND_ASSIGN(ConstrainedWindowMac);
-};
-
-#endif // CHROME_BROWSER_COCOA_CONSTRAINED_WINDOW_MAC_H_
-
diff --git a/chrome/browser/cocoa/constrained_window_mac.mm b/chrome/browser/cocoa/constrained_window_mac.mm
deleted file mode 100644
index 3843c50..0000000
--- a/chrome/browser/cocoa/constrained_window_mac.mm
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/constrained_window_mac.h"
-
-#import "chrome/browser/cocoa/browser_window_controller.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents/tab_contents_view.h"
-#import "third_party/GTM/AppKit/GTMWindowSheetController.h"
-
-ConstrainedWindowMacDelegate::~ConstrainedWindowMacDelegate() {}
-
-NSArray* ConstrainedWindowMacDelegateSystemSheet::GetSheetParameters(
- id delegate,
- SEL didEndSelector) {
- return [NSArray arrayWithObjects:
- [NSNull null], // window, must be [NSNull null]
- delegate,
- [NSValue valueWithPointer:didEndSelector],
- [NSValue valueWithPointer:NULL], // context info for didEndSelector_.
- nil];
-}
-
-void ConstrainedWindowMacDelegateSystemSheet::RunSheet(
- GTMWindowSheetController* sheetController,
- NSView* view) {
- NSArray* params = GetSheetParameters(delegate_.get(), didEndSelector_);
- [sheetController beginSystemSheet:systemSheet_
- modalForView:view
- withParameters:params];
-}
-
-void ConstrainedWindowMacDelegateCustomSheet::RunSheet(
- GTMWindowSheetController* sheetController,
- NSView* view) {
- [sheetController beginSheet:customSheet_.get()
- modalForView:view
- modalDelegate:delegate_.get()
- didEndSelector:didEndSelector_
- contextInfo:NULL];
-}
-
-// static
-ConstrainedWindow* ConstrainedWindow::CreateConstrainedDialog(
- TabContents* parent,
- ConstrainedWindowMacDelegate* delegate) {
- return new ConstrainedWindowMac(parent, delegate);
-}
-
-ConstrainedWindowMac::ConstrainedWindowMac(
- TabContents* owner, ConstrainedWindowMacDelegate* delegate)
- : owner_(owner),
- delegate_(delegate),
- controller_(nil),
- should_be_visible_(false) {
- DCHECK(owner);
- DCHECK(delegate);
-}
-
-ConstrainedWindowMac::~ConstrainedWindowMac() {}
-
-void ConstrainedWindowMac::ShowConstrainedWindow() {
- should_be_visible_ = true;
- // The TabContents only has a native window if it is currently visible. In
- // this case, open the sheet now. Else, Realize() will be called later, when
- // our tab becomes visible.
- NSWindow* browserWindow = owner_->view()->GetTopLevelNativeWindow();
- NSWindowController* controller = [browserWindow windowController];
- if (controller != nil) {
- DCHECK([controller isKindOfClass:[BrowserWindowController class]]);
- BrowserWindowController* browser_controller =
- static_cast<BrowserWindowController*>(controller);
- if ([browser_controller canAttachConstrainedWindow])
- Realize(browser_controller);
- }
-}
-
-void ConstrainedWindowMac::CloseConstrainedWindow() {
- // Note: controller_ can be `nil` here if the sheet was never realized. That's
- // ok.
- [controller_ removeConstrainedWindow:this];
- delegate_->DeleteDelegate();
- owner_->WillClose(this);
-
- delete this;
-}
-
-void ConstrainedWindowMac::Realize(BrowserWindowController* controller) {
- if (!should_be_visible_)
- return;
-
- if (controller_ != nil) {
- DCHECK(controller_ == controller);
- return;
- }
- DCHECK(controller != nil);
-
- // Remember the controller we're adding ourselves to, so that we can later
- // remove us from it.
- controller_ = controller;
- [controller_ attachConstrainedWindow:this];
- delegate_->set_sheet_open(true);
-}
diff --git a/chrome/browser/cocoa/content_exceptions_window_controller.h b/chrome/browser/cocoa/content_exceptions_window_controller.h
deleted file mode 100644
index 98af089..0000000
--- a/chrome/browser/cocoa/content_exceptions_window_controller.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// 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 "base/cocoa_protocols_mac.h"
-#include "base/scoped_ptr.h"
-#include "chrome/browser/host_content_settings_map.h"
-#include "chrome/common/content_settings_types.h"
-
-class ContentExceptionsTableModel;
-class ContentSettingComboModel;
-class UpdatingContentSettingsObserver;
-
-// Controller for the content exception dialogs.
-@interface ContentExceptionsWindowController : NSWindowController
- <NSWindowDelegate,
- NSTableViewDataSource,
- NSTableViewDelegate> {
- @private
- IBOutlet NSTableView* tableView_;
- IBOutlet NSButton* addButton_;
- IBOutlet NSButton* removeButton_;
- IBOutlet NSButton* removeAllButton_;
- IBOutlet NSButton* doneButton_;
-
- ContentSettingsType settingsType_;
- HostContentSettingsMap* settingsMap_; // weak
- HostContentSettingsMap* otrSettingsMap_; // weak
- scoped_ptr<ContentExceptionsTableModel> model_;
- scoped_ptr<ContentSettingComboModel> popup_model_;
-
- // Is set if adding and editing exceptions for the current OTR session should
- // be allowed.
- BOOL otrAllowed_;
-
- // Listens for changes to the content settings and reloads the data when they
- // change. See comment in -modelDidChange in the mm file for details.
- scoped_ptr<UpdatingContentSettingsObserver> tableObserver_;
-
- // If this is set to NO, notifications by |tableObserver_| are ignored. This
- // is used to suppress updates at bad times.
- BOOL updatesEnabled_;
-
- // This is non-NULL only while a new element is being added and its pattern
- // is being edited.
- scoped_ptr<HostContentSettingsMap::PatternSettingPair> newException_;
-}
-
-// Returns the content exceptions window controller for |settingsType|.
-// Changes made by the user in the window are persisted in |settingsMap|.
-+ (id)controllerForType:(ContentSettingsType)settingsType
- settingsMap:(HostContentSettingsMap*)settingsMap
- otrSettingsMap:(HostContentSettingsMap*)otrSettingsMap;
-
-// Shows the exceptions dialog as a modal sheet attached to |window|.
-- (void)attachSheetTo:(NSWindow*)window;
-
-// Sets the minimum width of the sheet and resizes it if necessary.
-- (void)setMinWidth:(CGFloat)minWidth;
-
-- (IBAction)addException:(id)sender;
-- (IBAction)removeException:(id)sender;
-- (IBAction)removeAllExceptions:(id)sender;
-// Closes the sheet and ends the modal loop.
-- (IBAction)closeSheet:(id)sender;
-
-@end
-
-@interface ContentExceptionsWindowController(VisibleForTesting)
-- (void)cancel:(id)sender;
-- (BOOL)editingNewException;
-@end
diff --git a/chrome/browser/cocoa/content_exceptions_window_controller.mm b/chrome/browser/cocoa/content_exceptions_window_controller.mm
deleted file mode 100644
index b50204f..0000000
--- a/chrome/browser/cocoa/content_exceptions_window_controller.mm
+++ /dev/null
@@ -1,490 +0,0 @@
-// 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 "chrome/browser/cocoa/content_exceptions_window_controller.h"
-
-#include "app/l10n_util.h"
-#include "app/l10n_util_mac.h"
-#include "app/table_model_observer.h"
-#include "base/command_line.h"
-#import "base/mac_util.h"
-#import "base/scoped_nsobject.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/content_exceptions_table_model.h"
-#include "chrome/browser/content_setting_combo_model.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
-#include "grit/generated_resources.h"
-#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-
-@interface ContentExceptionsWindowController (Private)
-- (id)initWithType:(ContentSettingsType)settingsType
- settingsMap:(HostContentSettingsMap*)settingsMap
- otrSettingsMap:(HostContentSettingsMap*)otrSettingsMap;
-- (void)updateRow:(NSInteger)row
- withEntry:(const HostContentSettingsMap::PatternSettingPair&)entry
- forOtr:(BOOL)isOtr;
-- (void)adjustEditingButtons;
-- (void)modelDidChange;
-- (NSString*)titleForIndex:(size_t)index;
-@end
-
-////////////////////////////////////////////////////////////////////////////////
-// PatternFormatter
-
-// A simple formatter that accepts text that vaguely looks like a pattern.
-@interface PatternFormatter : NSFormatter
-@end
-
-@implementation PatternFormatter
-- (NSString*)stringForObjectValue:(id)object {
- if (![object isKindOfClass:[NSString class]])
- return nil;
- return object;
-}
-
-- (BOOL)getObjectValue:(id*)object
- forString:(NSString*)string
- errorDescription:(NSString**)error {
- if ([string length]) {
- if (HostContentSettingsMap::Pattern(
- base::SysNSStringToUTF8(string)).IsValid()) {
- *object = string;
- return YES;
- }
- }
- if (error)
- *error = @"Invalid pattern";
- return NO;
-}
-
-- (NSAttributedString*)attributedStringForObjectValue:(id)object
- withDefaultAttributes:(NSDictionary*)attribs {
- return nil;
-}
-@end
-
-////////////////////////////////////////////////////////////////////////////////
-// UpdatingContentSettingsObserver
-
-// UpdatingContentSettingsObserver is a notification observer that tells a
-// window controller to update its data on every notification.
-class UpdatingContentSettingsObserver : public NotificationObserver {
- public:
- UpdatingContentSettingsObserver(ContentExceptionsWindowController* controller)
- : controller_(controller) {
- // One would think one could register a TableModelObserver to be notified of
- // changes to ContentExceptionsTableModel. One would be wrong: The table
- // model only sends out changes that are made through the model, not for
- // changes made directly to its backing HostContentSettings object (that
- // happens e.g. if the user uses the cookie confirmation dialog). Hence,
- // observe the CONTENT_SETTINGS_CHANGED notification directly.
- registrar_.Add(this, NotificationType::CONTENT_SETTINGS_CHANGED,
- NotificationService::AllSources());
- }
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
- private:
- NotificationRegistrar registrar_;
- ContentExceptionsWindowController* controller_;
-};
-
-void UpdatingContentSettingsObserver::Observe(
- NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- [controller_ modelDidChange];
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Static functions
-
-namespace {
-
-NSString* GetWindowTitle(ContentSettingsType settingsType) {
- switch (settingsType) {
- case CONTENT_SETTINGS_TYPE_COOKIES:
- return l10n_util::GetNSStringWithFixup(IDS_COOKIE_EXCEPTION_TITLE);
- case CONTENT_SETTINGS_TYPE_IMAGES:
- return l10n_util::GetNSStringWithFixup(IDS_IMAGES_EXCEPTION_TITLE);
- case CONTENT_SETTINGS_TYPE_JAVASCRIPT:
- return l10n_util::GetNSStringWithFixup(IDS_JS_EXCEPTION_TITLE);
- case CONTENT_SETTINGS_TYPE_PLUGINS:
- return l10n_util::GetNSStringWithFixup(IDS_PLUGINS_EXCEPTION_TITLE);
- case CONTENT_SETTINGS_TYPE_POPUPS:
- return l10n_util::GetNSStringWithFixup(IDS_POPUP_EXCEPTION_TITLE);
- default:
- NOTREACHED();
- }
- return @"";
-}
-
-const CGFloat kButtonBarHeight = 35.0;
-
-} // namespace
-
-////////////////////////////////////////////////////////////////////////////////
-// ContentExceptionsWindowController implementation
-
-static ContentExceptionsWindowController*
- g_exceptionWindows[CONTENT_SETTINGS_NUM_TYPES] = { nil };
-
-@implementation ContentExceptionsWindowController
-
-+ (id)controllerForType:(ContentSettingsType)settingsType
- settingsMap:(HostContentSettingsMap*)settingsMap
- otrSettingsMap:(HostContentSettingsMap*)otrSettingsMap {
- if (!g_exceptionWindows[settingsType]) {
- g_exceptionWindows[settingsType] =
- [[ContentExceptionsWindowController alloc]
- initWithType:settingsType
- settingsMap:settingsMap
- otrSettingsMap:otrSettingsMap];
- }
- return g_exceptionWindows[settingsType];
-}
-
-- (id)initWithType:(ContentSettingsType)settingsType
- settingsMap:(HostContentSettingsMap*)settingsMap
- otrSettingsMap:(HostContentSettingsMap*)otrSettingsMap {
- NSString* nibpath =
- [mac_util::MainAppBundle() pathForResource:@"ContentExceptionsWindow"
- ofType:@"nib"];
- if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
- settingsType_ = settingsType;
- settingsMap_ = settingsMap;
- otrSettingsMap_ = otrSettingsMap;
- model_.reset(new ContentExceptionsTableModel(
- settingsMap_, otrSettingsMap_, settingsType_));
- popup_model_.reset(new ContentSettingComboModel(settingsType_));
- otrAllowed_ = otrSettingsMap != NULL;
- tableObserver_.reset(new UpdatingContentSettingsObserver(self));
- updatesEnabled_ = YES;
-
- // TODO(thakis): autoremember window rect.
- // TODO(thakis): sorting support.
- }
- return self;
-}
-
-- (void)awakeFromNib {
- DCHECK([self window]);
- DCHECK_EQ(self, [[self window] delegate]);
- DCHECK(tableView_);
- DCHECK_EQ(self, [tableView_ dataSource]);
- DCHECK_EQ(self, [tableView_ delegate]);
-
- [[self window] setTitle:GetWindowTitle(settingsType_)];
-
- CGFloat minWidth = [[addButton_ superview] bounds].size.width +
- [[doneButton_ superview] bounds].size.width;
- [self setMinWidth:minWidth];
-
- [self adjustEditingButtons];
-
- // Initialize menu for the data cell in the "action" column.
- scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@"exceptionMenu"]);
- for (int i = 0; i < popup_model_->GetItemCount(); ++i) {
- NSString* title =
- l10n_util::FixUpWindowsStyleLabel(popup_model_->GetItemAt(i));
- scoped_nsobject<NSMenuItem> allowItem(
- [[NSMenuItem alloc] initWithTitle:title action:NULL keyEquivalent:@""]);
- [allowItem.get() setTag:popup_model_->SettingForIndex(i)];
- [menu.get() addItem:allowItem.get()];
- }
- NSCell* menuCell =
- [[tableView_ tableColumnWithIdentifier:@"action"] dataCell];
- [menuCell setMenu:menu.get()];
-
- NSCell* patternCell =
- [[tableView_ tableColumnWithIdentifier:@"pattern"] dataCell];
- [patternCell setFormatter:[[[PatternFormatter alloc] init] autorelease]];
-
- if (!otrAllowed_) {
- [tableView_
- removeTableColumn:[tableView_ tableColumnWithIdentifier:@"otr"]];
- }
-}
-
-- (void)setMinWidth:(CGFloat)minWidth {
- NSWindow* window = [self window];
- [window setMinSize:NSMakeSize(minWidth, [window minSize].height)];
- if ([window frame].size.width < minWidth) {
- NSRect frame = [window frame];
- frame.size.width = minWidth;
- [window setFrame:frame display:NO];
- }
-}
-
-- (void)windowWillClose:(NSNotification*)notification {
- // Without this, some of the unit tests fail on 10.6:
- [tableView_ setDataSource:nil];
-
- g_exceptionWindows[settingsType_] = nil;
- [self autorelease];
-}
-
-- (BOOL)editingNewException {
- return newException_.get() != NULL;
-}
-
-// Let esc cancel editing if the user is currently editing a pattern. Else, let
-// esc close the window.
-- (void)cancel:(id)sender {
- if ([tableView_ currentEditor] != nil) {
- [tableView_ abortEditing];
- [[self window] makeFirstResponder:tableView_]; // Re-gain focus.
-
- if ([tableView_ selectedRow] == model_->RowCount()) {
- // Cancel addition of new row.
- [self removeException:self];
- }
- } else {
- [self closeSheet:self];
- }
-}
-
-- (void)keyDown:(NSEvent*)event {
- NSString* chars = [event charactersIgnoringModifiers];
- if ([chars length] == 1) {
- switch ([chars characterAtIndex:0]) {
- case NSDeleteCharacter:
- case NSDeleteFunctionKey:
- // Delete deletes.
- if ([[tableView_ selectedRowIndexes] count] > 0)
- [self removeException:self];
- return;
- case NSCarriageReturnCharacter:
- case NSEnterCharacter:
- // Return enters rename mode.
- if ([[tableView_ selectedRowIndexes] count] == 1) {
- [tableView_ editColumn:0
- row:[[tableView_ selectedRowIndexes] lastIndex]
- withEvent:nil
- select:YES];
- }
- return;
- }
- }
- [super keyDown:event];
-}
-
-- (void)attachSheetTo:(NSWindow*)window {
- [NSApp beginSheet:[self window]
- modalForWindow:window
- modalDelegate:self
- didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
- contextInfo:nil];
-}
-
-- (void)sheetDidEnd:(NSWindow*)sheet
- returnCode:(NSInteger)returnCode
- contextInfo:(void*)context {
- [sheet close];
- [sheet orderOut:self];
-}
-
-- (IBAction)addException:(id)sender {
- if (newException_.get()) {
- // The invariant is that |newException_| is non-NULL exactly if the pattern
- // of a new exception is currently being edited - so there's nothing to do
- // in that case.
- return;
- }
- newException_.reset(new HostContentSettingsMap::PatternSettingPair);
- newException_->first = HostContentSettingsMap::Pattern(
- l10n_util::GetStringUTF8(IDS_EXCEPTIONS_SAMPLE_PATTERN));
- newException_->second = CONTENT_SETTING_BLOCK;
- [tableView_ reloadData];
-
- [self adjustEditingButtons];
- int index = model_->RowCount();
- NSIndexSet* selectedSet = [NSIndexSet indexSetWithIndex:index];
- [tableView_ selectRowIndexes:selectedSet byExtendingSelection:NO];
- [tableView_ editColumn:0 row:index withEvent:nil select:YES];
-}
-
-- (IBAction)removeException:(id)sender {
- updatesEnabled_ = NO;
- NSIndexSet* selection = [tableView_ selectedRowIndexes];
- [tableView_ deselectAll:self]; // Else we'll get a -setObjectValue: later.
- DCHECK_GT([selection count], 0U);
- NSUInteger index = [selection lastIndex];
- while (index != NSNotFound) {
- if (index == static_cast<NSUInteger>(model_->RowCount()))
- newException_.reset();
- else
- model_->RemoveException(index);
- index = [selection indexLessThanIndex:index];
- }
- updatesEnabled_ = YES;
- [self modelDidChange];
-}
-
-- (IBAction)removeAllExceptions:(id)sender {
- updatesEnabled_ = NO;
- [tableView_ deselectAll:self]; // Else we'll get a -setObjectValue: later.
- newException_.reset();
- model_->RemoveAll();
- updatesEnabled_ = YES;
- [self modelDidChange];
-}
-
-- (IBAction)closeSheet:(id)sender {
- [NSApp endSheet:[self window]];
-}
-
-// Table View Data Source -----------------------------------------------------
-
-- (NSInteger)numberOfRowsInTableView:(NSTableView*)table {
- return model_->RowCount() + (newException_.get() ? 1 : 0);
-}
-
-- (id)tableView:(NSTableView*)tv
- objectValueForTableColumn:(NSTableColumn*)tableColumn
- row:(NSInteger)row {
- const HostContentSettingsMap::PatternSettingPair* entry;
- int isOtr;
- if (newException_.get() && row >= model_->RowCount()) {
- entry = newException_.get();
- isOtr = 0;
- } else {
- entry = &model_->entry_at(row);
- isOtr = model_->entry_is_off_the_record(row) ? 1 : 0;
- }
-
- NSObject* result = nil;
- NSString* identifier = [tableColumn identifier];
- if ([identifier isEqualToString:@"pattern"]) {
- result = base::SysUTF8ToNSString(entry->first.AsString());
- } else if ([identifier isEqualToString:@"action"]) {
- result =
- [NSNumber numberWithInt:popup_model_->IndexForSetting(entry->second)];
- } else if ([identifier isEqualToString:@"otr"]) {
- result = [NSNumber numberWithInt:isOtr];
- } else {
- NOTREACHED();
- }
- return result;
-}
-
-// Updates exception at |row| to contain the data in |entry|.
-- (void)updateRow:(NSInteger)row
- withEntry:(const HostContentSettingsMap::PatternSettingPair&)entry
- forOtr:(BOOL)isOtr {
- // TODO(thakis): This apparently moves an edited row to the back of the list.
- // It's what windows and linux do, but it's kinda sucky. Fix.
- // http://crbug.com/36904
- updatesEnabled_ = NO;
- if (row < model_->RowCount())
- model_->RemoveException(row);
- model_->AddException(entry.first, entry.second, isOtr);
- updatesEnabled_ = YES;
- [self modelDidChange];
-
- // For now, at least re-select the edited element.
- int newIndex = model_->IndexOfExceptionByPattern(entry.first, isOtr);
- DCHECK(newIndex != -1);
- [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:newIndex]
- byExtendingSelection:NO];
-}
-
-- (void) tableView:(NSTableView*)tv
- setObjectValue:(id)object
- forTableColumn:(NSTableColumn*)tableColumn
- row:(NSInteger)row {
- // -remove: and -removeAll: both call |tableView_|'s -deselectAll:, which
- // calls this method if a cell is currently being edited. Do not commit edits
- // of rows that are about to be deleted.
- if (!updatesEnabled_) {
- // If this method gets called, the pattern filed of the new exception can no
- // longer be being edited. Reset |newException_| to keep the invariant true.
- newException_.reset();
- return;
- }
-
- // Get model object.
- bool isNewRow = newException_.get() && row >= model_->RowCount();
- HostContentSettingsMap::PatternSettingPair originalEntry =
- isNewRow ? *newException_ : model_->entry_at(row);
- HostContentSettingsMap::PatternSettingPair entry = originalEntry;
- bool isOtr =
- isNewRow ? 0 : model_->entry_is_off_the_record(row);
- bool wasOtr = isOtr;
-
- // Modify it.
- NSString* identifier = [tableColumn identifier];
- if ([identifier isEqualToString:@"pattern"]) {
- entry.first = HostContentSettingsMap::Pattern(
- base::SysNSStringToUTF8(object));
- }
- if ([identifier isEqualToString:@"action"]) {
- int index = [object intValue];
- entry.second = popup_model_->SettingForIndex(index);
- }
- if ([identifier isEqualToString:@"otr"]) {
- isOtr = [object intValue] != 0;
- }
-
- // Commit modification, if any.
- if (isNewRow) {
- newException_.reset();
- if (![identifier isEqualToString:@"pattern"]) {
- [tableView_ reloadData];
- [self adjustEditingButtons];
- return; // Commit new rows only when the pattern has been set.
- }
- int newIndex = model_->IndexOfExceptionByPattern(entry.first, false);
- if (newIndex != -1) {
- // The new pattern was already in the table. Focus existing row instead of
- // overwriting it with a new one.
- [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:newIndex]
- byExtendingSelection:NO];
- [tableView_ reloadData];
- [self adjustEditingButtons];
- return;
- }
- }
- if (entry != originalEntry || wasOtr != isOtr || isNewRow)
- [self updateRow:row withEntry:entry forOtr:isOtr];
-}
-
-
-// Table View Delegate --------------------------------------------------------
-
-// When the selection in the table view changes, we need to adjust buttons.
-- (void)tableViewSelectionDidChange:(NSNotification*)notification {
- [self adjustEditingButtons];
-}
-
-// Private --------------------------------------------------------------------
-
-// This method appropriately sets the enabled states on the table's editing
-// buttons.
-- (void)adjustEditingButtons {
- NSIndexSet* selection = [tableView_ selectedRowIndexes];
- [removeButton_ setEnabled:([selection count] > 0)];
- [removeAllButton_ setEnabled:([tableView_ numberOfRows] > 0)];
-}
-
-- (void)modelDidChange {
- // Some calls on |model_|, e.g. RemoveException(), change something on the
- // backing content settings map object (which sends a notification) and then
- // change more stuff in |model_|. If |model_| is deleted when the notification
- // is sent, this second access causes a segmentation violation. Hence, disable
- // resetting |model_| while updates can be in progress.
- if (!updatesEnabled_)
- return;
-
- // The model caches its data, meaning we need to recreate it on every change.
- model_.reset(new ContentExceptionsTableModel(
- settingsMap_, otrSettingsMap_, settingsType_));
-
- [tableView_ reloadData];
- [self adjustEditingButtons];
-}
-
-@end
diff --git a/chrome/browser/cocoa/content_exceptions_window_controller_unittest.mm b/chrome/browser/cocoa/content_exceptions_window_controller_unittest.mm
deleted file mode 100644
index b5beb62..0000000
--- a/chrome/browser/cocoa/content_exceptions_window_controller_unittest.mm
+++ /dev/null
@@ -1,252 +0,0 @@
-// 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 "chrome/browser/cocoa/content_exceptions_window_controller.h"
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/scoped_nsobject.h"
-#include "base/ref_counted.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-namespace {
-
-void ProcessEvents() {
- for (;;) {
- base::mac::ScopedNSAutoreleasePool pool;
- NSEvent* next_event = [NSApp nextEventMatchingMask:NSAnyEventMask
- untilDate:nil
- inMode:NSDefaultRunLoopMode
- dequeue:YES];
- if (!next_event)
- break;
- [NSApp sendEvent:next_event];
- }
-}
-
-void SendKeyEvents(NSString* characters) {
- for (NSUInteger i = 0; i < [characters length]; ++i) {
- unichar character = [characters characterAtIndex:i];
- NSString* charString = [NSString stringWithCharacters:&character length:1];
- NSEvent* event = [NSEvent keyEventWithType:NSKeyDown
- location:NSZeroPoint
- modifierFlags:0
- timestamp:0.0
- windowNumber:0
- context:nil
- characters:charString
- charactersIgnoringModifiers:charString
- isARepeat:NO
- keyCode:0];
- [NSApp sendEvent:event];
- }
-}
-
-class ContentExceptionsWindowControllerTest : public CocoaTest {
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
- TestingProfile* profile = browser_helper_.profile();
- settingsMap_ = new HostContentSettingsMap(profile);
- }
-
- ContentExceptionsWindowController* GetController(ContentSettingsType type) {
- id controller = [ContentExceptionsWindowController
- controllerForType:type
- settingsMap:settingsMap_.get()
- otrSettingsMap:NULL];
- [controller showWindow:nil];
- return controller;
- }
-
- void ClickAdd(ContentExceptionsWindowController* controller) {
- [controller addException:nil];
- ProcessEvents();
- }
-
- void ClickRemove(ContentExceptionsWindowController* controller) {
- [controller removeException:nil];
- ProcessEvents();
- }
-
- void ClickRemoveAll(ContentExceptionsWindowController* controller) {
- [controller removeAllExceptions:nil];
- ProcessEvents();
- }
-
- void EnterText(NSString* str) {
- SendKeyEvents(str);
- ProcessEvents();
- }
-
- void HitEscape(ContentExceptionsWindowController* controller) {
- [controller cancel:nil];
- ProcessEvents();
- }
-
- protected:
- BrowserTestHelper browser_helper_;
- scoped_refptr<HostContentSettingsMap> settingsMap_;
-};
-
-TEST_F(ContentExceptionsWindowControllerTest, Construction) {
- ContentExceptionsWindowController* controller =
- [ContentExceptionsWindowController
- controllerForType:CONTENT_SETTINGS_TYPE_PLUGINS
- settingsMap:settingsMap_.get()
- otrSettingsMap:NULL];
- [controller showWindow:nil];
- [controller close]; // Should autorelease.
-}
-
-// Regression test for http://crbug.com/37137
-TEST_F(ContentExceptionsWindowControllerTest, AddRemove) {
- ContentExceptionsWindowController* controller =
- GetController(CONTENT_SETTINGS_TYPE_PLUGINS);
-
- HostContentSettingsMap::SettingsForOneType settings;
-
- ClickAdd(controller);
- settingsMap_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
- "",
- &settings);
- EXPECT_EQ(0u, settings.size());
-
- ClickRemove(controller);
-
- EXPECT_FALSE([controller editingNewException]);
- [controller close];
-
- settingsMap_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
- "",
- &settings);
- EXPECT_EQ(0u, settings.size());
-}
-
-// Regression test for http://crbug.com/37137
-TEST_F(ContentExceptionsWindowControllerTest, AddRemoveAll) {
- ContentExceptionsWindowController* controller =
- GetController(CONTENT_SETTINGS_TYPE_PLUGINS);
-
- ClickAdd(controller);
- ClickRemoveAll(controller);
-
- EXPECT_FALSE([controller editingNewException]);
- [controller close];
-
- HostContentSettingsMap::SettingsForOneType settings;
- settingsMap_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
- "",
- &settings);
- EXPECT_EQ(0u, settings.size());
-}
-
-TEST_F(ContentExceptionsWindowControllerTest, Add) {
- ContentExceptionsWindowController* controller =
- GetController(CONTENT_SETTINGS_TYPE_PLUGINS);
-
- ClickAdd(controller);
- EnterText(@"addedhost\n");
-
- EXPECT_FALSE([controller editingNewException]);
- [controller close];
-
- HostContentSettingsMap::SettingsForOneType settings;
- settingsMap_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
- "",
- &settings);
- EXPECT_EQ(1u, settings.size());
- EXPECT_EQ(HostContentSettingsMap::Pattern("addedhost"), settings[0].first);
-}
-
-TEST_F(ContentExceptionsWindowControllerTest, AddEscDoesNotAdd) {
- ContentExceptionsWindowController* controller =
- GetController(CONTENT_SETTINGS_TYPE_PLUGINS);
-
- ClickAdd(controller);
- EnterText(@"addedhost"); // but do not press enter
- HitEscape(controller);
-
- HostContentSettingsMap::SettingsForOneType settings;
- settingsMap_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
- "",
- &settings);
- EXPECT_EQ(0u, settings.size());
- EXPECT_FALSE([controller editingNewException]);
-
- [controller close];
-}
-
-// Regression test for http://crbug.com/37208
-TEST_F(ContentExceptionsWindowControllerTest, AddEditAddAdd) {
- ContentExceptionsWindowController* controller =
- GetController(CONTENT_SETTINGS_TYPE_PLUGINS);
-
- ClickAdd(controller);
- EnterText(@"testtesttest"); // but do not press enter
- ClickAdd(controller);
- ClickAdd(controller);
-
- EXPECT_TRUE([controller editingNewException]);
- [controller close];
-
- HostContentSettingsMap::SettingsForOneType settings;
- settingsMap_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
- "",
- &settings);
- EXPECT_EQ(0u, settings.size());
-}
-
-TEST_F(ContentExceptionsWindowControllerTest, AddExistingEditAdd) {
- settingsMap_->SetContentSetting(HostContentSettingsMap::Pattern("myhost"),
- CONTENT_SETTINGS_TYPE_PLUGINS,
- "",
- CONTENT_SETTING_BLOCK);
-
- ContentExceptionsWindowController* controller =
- GetController(CONTENT_SETTINGS_TYPE_PLUGINS);
-
- ClickAdd(controller);
- EnterText(@"myhost"); // but do not press enter
- ClickAdd(controller);
-
- EXPECT_TRUE([controller editingNewException]);
- [controller close];
-
-
- HostContentSettingsMap::SettingsForOneType settings;
- settingsMap_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
- "",
- &settings);
- EXPECT_EQ(1u, settings.size());
-}
-
-TEST_F(ContentExceptionsWindowControllerTest, AddExistingDoesNotOverwrite) {
- settingsMap_->SetContentSetting(HostContentSettingsMap::Pattern("myhost"),
- CONTENT_SETTINGS_TYPE_COOKIES,
- "",
- CONTENT_SETTING_SESSION_ONLY);
-
- ContentExceptionsWindowController* controller =
- GetController(CONTENT_SETTINGS_TYPE_COOKIES);
-
- ClickAdd(controller);
- EnterText(@"myhost\n");
-
- EXPECT_FALSE([controller editingNewException]);
- [controller close];
-
- HostContentSettingsMap::SettingsForOneType settings;
- settingsMap_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_COOKIES,
- "",
- &settings);
- EXPECT_EQ(1u, settings.size());
- EXPECT_EQ(CONTENT_SETTING_SESSION_ONLY, settings[0].second);
-}
-
-
-} // namespace
diff --git a/chrome/browser/cocoa/content_setting_bubble_cocoa.h b/chrome/browser/cocoa/content_setting_bubble_cocoa.h
deleted file mode 100644
index 7914808..0000000
--- a/chrome/browser/cocoa/content_setting_bubble_cocoa.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// 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.
-
-#include <map>
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/cocoa_protocols_mac.h"
-#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-#import "chrome/browser/cocoa/base_bubble_controller.h"
-
-class ContentSettingBubbleModel;
-@class InfoBubbleView;
-
-namespace content_setting_bubble {
-// For every "show popup" button, remember the index of the popup tab contents
-// it should open when clicked.
-typedef std::map<NSButton*, int> PopupLinks;
-}
-
-// Manages a "content blocked" bubble.
-@interface ContentSettingBubbleController : BaseBubbleController {
- @private
- IBOutlet NSTextField* titleLabel_;
- IBOutlet NSMatrix* allowBlockRadioGroup_;
-
- IBOutlet NSButton* manageButton_;
- IBOutlet NSButton* doneButton_;
- IBOutlet NSButton* loadAllPluginsButton_;
-
- // The container for the bubble contents of the geolocation bubble.
- IBOutlet NSView* contentsContainer_;
-
- // The info button of the cookies bubble.
- IBOutlet NSButton* infoButton_;
-
- IBOutlet NSTextField* blockedResourcesField_;
-
- scoped_ptr<ContentSettingBubbleModel> contentSettingBubbleModel_;
- content_setting_bubble::PopupLinks popupLinks_;
-}
-
-// Creates and shows a content blocked bubble. Takes ownership of
-// |contentSettingBubbleModel| but not of the other objects.
-+ (ContentSettingBubbleController*)
- showForModel:(ContentSettingBubbleModel*)contentSettingBubbleModel
- parentWindow:(NSWindow*)parentWindow
- anchoredAt:(NSPoint)anchoredAt;
-
-// Callback for the "don't block / continue blocking" radio group.
-- (IBAction)allowBlockToggled:(id)sender;
-
-// Callback for "close" button.
-- (IBAction)closeBubble:(id)sender;
-
-// Callback for "manage" button.
-- (IBAction)manageBlocking:(id)sender;
-
-// Callback for "info" link.
-- (IBAction)showMoreInfo:(id)sender;
-
-// Callback for "load all plugins" button.
-- (IBAction)loadAllPlugins:(id)sender;
-
-@end
diff --git a/chrome/browser/cocoa/content_setting_bubble_cocoa.mm b/chrome/browser/cocoa/content_setting_bubble_cocoa.mm
deleted file mode 100644
index dc8b967..0000000
--- a/chrome/browser/cocoa/content_setting_bubble_cocoa.mm
+++ /dev/null
@@ -1,487 +0,0 @@
-// 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 "chrome/browser/cocoa/content_setting_bubble_cocoa.h"
-
-#include "app/l10n_util.h"
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/blocked_content_container.h"
-#import "chrome/browser/cocoa/content_settings_dialog_controller.h"
-#import "chrome/browser/cocoa/hyperlink_button_cell.h"
-#import "chrome/browser/cocoa/info_bubble_view.h"
-#import "chrome/browser/cocoa/l10n_util.h"
-#include "chrome/browser/content_setting_bubble_model.h"
-#include "chrome/browser/host_content_settings_map.h"
-#include "chrome/browser/plugin_updater.h"
-#include "chrome/common/chrome_switches.h"
-#include "grit/generated_resources.h"
-#include "skia/ext/skia_utils_mac.h"
-#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-#include "webkit/glue/plugins/plugin_list.h"
-
-namespace {
-
-// Must match the tag of the unblock radio button in the xib files.
-const int kAllowTag = 1;
-
-// Must match the tag of the block radio button in the xib files.
-const int kBlockTag = 2;
-
-// Height of one link in the popup list.
-const int kLinkHeight = 16;
-
-// Space between two popup links.
-const int kLinkPadding = 4;
-
-// Space taken in total by one popup link.
-const int kLinkLineHeight = kLinkHeight + kLinkPadding;
-
-// Space between popup list and surrounding UI elements.
-const int kLinkOuterPadding = 8;
-
-// Height of each of the labels in the geolocation bubble.
-const int kGeoLabelHeight = 14;
-
-// Height of the "Clear" button in the geolocation bubble.
-const int kGeoClearButtonHeight = 17;
-
-// Padding between radio buttons and "Load all plugins" button
-// in the plugin bubble.
-const int kLoadAllPluginsButtonVerticalPadding = 8;
-
-// General padding between elements in the geolocation bubble.
-const int kGeoPadding = 8;
-
-// Padding between host names in the geolocation bubble.
-const int kGeoHostPadding = 4;
-
-// Minimal padding between "Manage" and "Done" buttons.
-const int kManageDonePadding = 8;
-
-void SetControlSize(NSControl* control, NSControlSize controlSize) {
- CGFloat fontSize = [NSFont systemFontSizeForControlSize:controlSize];
- NSCell* cell = [control cell];
- NSFont* font = [NSFont fontWithName:[[cell font] fontName] size:fontSize];
- [cell setFont:font];
- [cell setControlSize:controlSize];
-}
-
-// Returns an autoreleased NSTextField that is configured to look like a Label
-// looks in Interface Builder.
-NSTextField* LabelWithFrame(NSString* text, const NSRect& frame) {
- NSTextField* label = [[NSTextField alloc] initWithFrame:frame];
- [label setStringValue:text];
- [label setSelectable:NO];
- [label setBezeled:NO];
- return [label autorelease];
-}
-
-} // namespace
-
-@interface ContentSettingBubbleController(Private)
-- (id)initWithModel:(ContentSettingBubbleModel*)settingsBubbleModel
- parentWindow:(NSWindow*)parentWindow
- anchoredAt:(NSPoint)anchoredAt;
-- (NSButton*)hyperlinkButtonWithFrame:(NSRect)frame
- title:(NSString*)title
- icon:(NSImage*)icon
- referenceFrame:(NSRect)referenceFrame;
-- (void)initializeBlockedPluginsList;
-- (void)initializeTitle;
-- (void)initializeRadioGroup;
-- (void)initializePopupList;
-- (void)initializeGeoLists;
-- (void)sizeToFitLoadPluginsButton;
-- (void)sizeToFitManageDoneButtons;
-- (void)removeInfoButton;
-- (void)popupLinkClicked:(id)sender;
-- (void)clearGeolocationForCurrentHost:(id)sender;
-@end
-
-@implementation ContentSettingBubbleController
-
-+ (ContentSettingBubbleController*)
- showForModel:(ContentSettingBubbleModel*)contentSettingBubbleModel
- parentWindow:(NSWindow*)parentWindow
- anchoredAt:(NSPoint)anchor {
- // Autoreleases itself on bubble close.
- return [[ContentSettingBubbleController alloc]
- initWithModel:contentSettingBubbleModel
- parentWindow:parentWindow
- anchoredAt:anchor];
-}
-
-- (id)initWithModel:(ContentSettingBubbleModel*)contentSettingBubbleModel
- parentWindow:(NSWindow*)parentWindow
- anchoredAt:(NSPoint)anchoredAt {
- // This method takes ownership of |contentSettingBubbleModel| in all cases.
- scoped_ptr<ContentSettingBubbleModel> model(contentSettingBubbleModel);
- DCHECK(model.get());
-
- NSString* const nibPaths[] = {
- @"ContentBlockedCookies",
- @"ContentBlockedImages",
- @"ContentBlockedJavaScript",
- @"ContentBlockedPlugins",
- @"ContentBlockedPopups",
- @"ContentBubbleGeolocation",
- @"", // Notifications do not have a bubble.
- };
- COMPILE_ASSERT(arraysize(nibPaths) == CONTENT_SETTINGS_NUM_TYPES,
- nibPaths_requires_an_entry_for_every_setting_type);
- const int settingsType = model->content_type();
- // Nofifications do not have a bubble.
- CHECK_NE(settingsType, CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
- DCHECK_LT(settingsType, CONTENT_SETTINGS_NUM_TYPES);
- if ((self = [super initWithWindowNibPath:nibPaths[settingsType]
- parentWindow:parentWindow
- anchoredAt:anchoredAt])) {
- contentSettingBubbleModel_.reset(model.release());
- [self showWindow:nil];
- }
- return self;
-}
-
-- (void)initializeTitle {
- if (!titleLabel_)
- return;
-
- NSString* label = base::SysUTF8ToNSString(
- contentSettingBubbleModel_->bubble_content().title);
- [titleLabel_ setStringValue:label];
-
- // Layout title post-localization.
- CGFloat deltaY = [GTMUILocalizerAndLayoutTweaker
- sizeToFitFixedWidthTextField:titleLabel_];
- NSRect windowFrame = [[self window] frame];
- windowFrame.size.height += deltaY;
- [[self window] setFrame:windowFrame display:NO];
- NSRect titleFrame = [titleLabel_ frame];
- titleFrame.origin.y -= deltaY;
- [titleLabel_ setFrame:titleFrame];
-}
-
-- (void)initializeRadioGroup {
- // Configure the radio group. For now, only deal with the
- // strictly needed case of group containing 2 radio buttons.
- const ContentSettingBubbleModel::RadioGroup& radio_group =
- contentSettingBubbleModel_->bubble_content().radio_group;
-
- // Select appropriate radio button.
- [allowBlockRadioGroup_ selectCellWithTag:
- radio_group.default_item == 0 ? kAllowTag : kBlockTag];
-
- const ContentSettingBubbleModel::RadioItems& radio_items =
- radio_group.radio_items;
- DCHECK_EQ(2u, radio_items.size()) << "Only 2 radio items per group supported";
- // Set radio group labels from model.
- NSCell* radioCell = [allowBlockRadioGroup_ cellWithTag:kAllowTag];
- [radioCell setTitle:base::SysUTF8ToNSString(radio_items[0])];
-
- radioCell = [allowBlockRadioGroup_ cellWithTag:kBlockTag];
- [radioCell setTitle:base::SysUTF8ToNSString(radio_items[1])];
-
- // Layout radio group labels post-localization.
- [GTMUILocalizerAndLayoutTweaker
- wrapRadioGroupForWidth:allowBlockRadioGroup_];
- CGFloat radioDeltaY = [GTMUILocalizerAndLayoutTweaker
- sizeToFitView:allowBlockRadioGroup_].height;
- NSRect windowFrame = [[self window] frame];
- windowFrame.size.height += radioDeltaY;
- [[self window] setFrame:windowFrame display:NO];
-}
-
-- (NSButton*)hyperlinkButtonWithFrame:(NSRect)frame
- title:(NSString*)title
- icon:(NSImage*)icon
- referenceFrame:(NSRect)referenceFrame {
- scoped_nsobject<HyperlinkButtonCell> cell([[HyperlinkButtonCell alloc]
- initTextCell:title]);
- [cell.get() setAlignment:NSNaturalTextAlignment];
- if (icon) {
- [cell.get() setImagePosition:NSImageLeft];
- [cell.get() setImage:icon];
- } else {
- [cell.get() setImagePosition:NSNoImage];
- }
- [cell.get() setControlSize:NSSmallControlSize];
-
- NSButton* button = [[[NSButton alloc] initWithFrame:frame] autorelease];
- // Cell must be set immediately after construction.
- [button setCell:cell.get()];
-
- // If the link text is too long, clamp it.
- [button sizeToFit];
- int maxWidth = NSWidth([[self bubble] frame]) - 2 * NSMinX(referenceFrame);
- NSRect buttonFrame = [button frame];
- if (NSWidth(buttonFrame) > maxWidth) {
- buttonFrame.size.width = maxWidth;
- [button setFrame:buttonFrame];
- }
-
- [button setTarget:self];
- [button setAction:@selector(popupLinkClicked:)];
- return button;
-}
-
-- (void)initializeBlockedPluginsList {
- NSMutableArray* pluginArray = [NSMutableArray array];
- const std::set<std::string>& plugins =
- contentSettingBubbleModel_->bubble_content().resource_identifiers;
- if (plugins.empty()) {
- int delta = NSMinY([titleLabel_ frame]) -
- NSMinY([blockedResourcesField_ frame]);
- [blockedResourcesField_ removeFromSuperview];
- NSRect frame = [[self window] frame];
- frame.size.height -= delta;
- [[self window] setFrame:frame display:NO];
- } else {
- for (std::set<std::string>::iterator it = plugins.begin();
- it != plugins.end(); ++it) {
- NSString* name;
- NPAPI::PluginList::PluginMap groups;
- NPAPI::PluginList::Singleton()->GetPluginGroups(false, &groups);
- if (groups.find(*it) != groups.end())
- name = base::SysUTF16ToNSString(groups[*it]->GetGroupName());
- else
- name = base::SysUTF8ToNSString(*it);
- [pluginArray addObject:name];
- }
- [blockedResourcesField_
- setStringValue:[pluginArray componentsJoinedByString:@"\n"]];
- [GTMUILocalizerAndLayoutTweaker
- sizeToFitFixedWidthTextField:blockedResourcesField_];
- }
-}
-
-- (void)initializePopupList {
- // I didn't put the buttons into a NSMatrix because then they are only one
- // entity in the key view loop. This way, one can tab through all of them.
- const ContentSettingBubbleModel::PopupItems& popupItems =
- contentSettingBubbleModel_->bubble_content().popup_items;
-
- // Get the pre-resize frame of the radio group. Its origin is where the
- // popup list should go.
- NSRect radioFrame = [allowBlockRadioGroup_ frame];
-
- // Make room for the popup list. The bubble view and its subviews autosize
- // themselves when the window is enlarged.
- // Heading and radio box are already 1 * kLinkOuterPadding apart in the nib,
- // so only 1 * kLinkOuterPadding more is needed.
- int delta = popupItems.size() * kLinkLineHeight - kLinkPadding +
- kLinkOuterPadding;
- NSSize deltaSize = NSMakeSize(0, delta);
- deltaSize = [[[self window] contentView] convertSize:deltaSize toView:nil];
- NSRect windowFrame = [[self window] frame];
- windowFrame.size.height += deltaSize.height;
- [[self window] setFrame:windowFrame display:NO];
-
- // Create popup list.
- int topLinkY = NSMaxY(radioFrame) + delta - kLinkHeight;
- int row = 0;
- for (std::vector<ContentSettingBubbleModel::PopupItem>::const_iterator
- it(popupItems.begin()); it != popupItems.end(); ++it, ++row) {
- const SkBitmap& icon = it->bitmap;
- NSImage* image = nil;
- if (!icon.empty())
- image = gfx::SkBitmapToNSImage(icon);
-
- std::string title(it->title);
- // The popup may not have committed a load yet, in which case it won't
- // have a URL or title.
- if (title.empty())
- title = l10n_util::GetStringUTF8(IDS_TAB_LOADING_TITLE);
-
- NSRect linkFrame =
- NSMakeRect(NSMinX(radioFrame), topLinkY - kLinkLineHeight * row,
- 200, kLinkHeight);
- NSButton* button = [self
- hyperlinkButtonWithFrame:linkFrame
- title:base::SysUTF8ToNSString(title)
- icon:image
- referenceFrame:radioFrame];
- [[self bubble] addSubview:button];
- popupLinks_[button] = row;
- }
-}
-
-- (void)initializeGeoLists {
- // Cocoa has its origin in the lower left corner. This means elements are
- // added from bottom to top, which explains why loops run backwards and the
- // order of operations is the other way than on Linux/Windows.
- const ContentSettingBubbleModel::BubbleContent& content =
- contentSettingBubbleModel_->bubble_content();
- NSRect containerFrame = [contentsContainer_ frame];
- NSRect frame = NSMakeRect(0, 0, NSWidth(containerFrame), kGeoLabelHeight);
-
- // "Clear" button.
- if (!content.clear_link.empty()) {
- NSRect buttonFrame = NSMakeRect(0, 0,
- NSWidth(containerFrame),
- kGeoClearButtonHeight);
- scoped_nsobject<NSButton> button([[NSButton alloc]
- initWithFrame:buttonFrame]);
- [button setTitle:base::SysUTF8ToNSString(content.clear_link)];
- [button setTarget:self];
- [button setAction:@selector(clearGeolocationForCurrentHost:)];
- [button setBezelStyle:NSRoundRectBezelStyle];
- SetControlSize(button, NSSmallControlSize);
- [button sizeToFit];
-
- // If the button is wider than the container, widen the window.
- CGFloat buttonWidth = NSWidth([button frame]);
- if (buttonWidth > NSWidth(containerFrame)) {
- NSRect windowFrame = [[self window] frame];
- windowFrame.size.width += buttonWidth - NSWidth(containerFrame);
- [[self window] setFrame:windowFrame display:NO];
- // Fetch the updated sizes.
- containerFrame = [contentsContainer_ frame];
- frame = NSMakeRect(0, 0, NSWidth(containerFrame), kGeoLabelHeight);
- }
-
- // Add the button.
- [contentsContainer_ addSubview:button];
-
- frame.origin.y = NSMaxY([button frame]) + kGeoPadding;
- }
-
- typedef
- std::vector<ContentSettingBubbleModel::DomainList>::const_reverse_iterator
- GeolocationGroupIterator;
- for (GeolocationGroupIterator i = content.domain_lists.rbegin();
- i != content.domain_lists.rend(); ++i) {
- // Add all hosts in the current domain list.
- for (std::set<std::string>::const_reverse_iterator j = i->hosts.rbegin();
- j != i->hosts.rend(); ++j) {
- NSTextField* title = LabelWithFrame(base::SysUTF8ToNSString(*j), frame);
- SetControlSize(title, NSSmallControlSize);
- [contentsContainer_ addSubview:title];
-
- frame.origin.y = NSMaxY(frame) + kGeoHostPadding +
- [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:title];
- }
- if (!i->hosts.empty())
- frame.origin.y += kGeoPadding - kGeoHostPadding;
-
- // Add the domain list's title.
- NSTextField* title =
- LabelWithFrame(base::SysUTF8ToNSString(i->title), frame);
- SetControlSize(title, NSSmallControlSize);
- [contentsContainer_ addSubview:title];
-
- frame.origin.y = NSMaxY(frame) + kGeoPadding +
- [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:title];
- }
-
- CGFloat containerHeight = frame.origin.y;
- // Undo last padding.
- if (!content.domain_lists.empty())
- containerHeight -= kGeoPadding;
-
- // Resize container to fit its subviews, and window to fit the container.
- NSRect windowFrame = [[self window] frame];
- windowFrame.size.height += containerHeight - NSHeight(containerFrame);
- [[self window] setFrame:windowFrame display:NO];
- containerFrame.size.height = containerHeight;
- [contentsContainer_ setFrame:containerFrame];
-}
-
-- (void)sizeToFitLoadPluginsButton {
- const ContentSettingBubbleModel::BubbleContent& content =
- contentSettingBubbleModel_->bubble_content();
- [loadAllPluginsButton_ setEnabled:content.load_plugins_link_enabled];
-
- // Resize horizontally to fit button if necessary.
- NSRect windowFrame = [[self window] frame];
- int widthNeeded = NSWidth([loadAllPluginsButton_ frame]) +
- 2 * NSMinX([loadAllPluginsButton_ frame]);
- if (NSWidth(windowFrame) < widthNeeded) {
- windowFrame.size.width = widthNeeded;
- [[self window] setFrame:windowFrame display:NO];
- }
-}
-
-- (void)sizeToFitManageDoneButtons {
- CGFloat actualWidth = NSWidth([[[self window] contentView] frame]);
- CGFloat requiredWidth = NSMaxX([manageButton_ frame]) + kManageDonePadding +
- NSWidth([[doneButton_ superview] frame]) - NSMinX([doneButton_ frame]);
- if (requiredWidth <= actualWidth || !doneButton_ || !manageButton_)
- return;
-
- // Resize window, autoresizing takes care of the rest.
- NSSize size = NSMakeSize(requiredWidth - actualWidth, 0);
- size = [[[self window] contentView] convertSize:size toView:nil];
- NSRect frame = [[self window] frame];
- frame.origin.x -= size.width;
- frame.size.width += size.width;
- [[self window] setFrame:frame display:NO];
-}
-
-- (void)awakeFromNib {
- [super awakeFromNib];
-
- [[self bubble] setBubbleType:info_bubble::kWhiteInfoBubble];
- [[self bubble] setArrowLocation:info_bubble::kTopRight];
-
- // Adapt window size to bottom buttons. Do this before all other layouting.
- [self sizeToFitManageDoneButtons];
-
- [self initializeTitle];
-
- ContentSettingsType type = contentSettingBubbleModel_->content_type();
- if (type == CONTENT_SETTINGS_TYPE_PLUGINS) {
- [self sizeToFitLoadPluginsButton];
- [self initializeBlockedPluginsList];
- }
- if (allowBlockRadioGroup_) // not bound in cookie bubble xib
- [self initializeRadioGroup];
-
- if (type == CONTENT_SETTINGS_TYPE_POPUPS)
- [self initializePopupList];
- if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION)
- [self initializeGeoLists];
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Actual application logic
-
-- (IBAction)allowBlockToggled:(id)sender {
- NSButtonCell *selectedCell = [sender selectedCell];
- contentSettingBubbleModel_->OnRadioClicked(
- [selectedCell tag] == kAllowTag ? 0 : 1);
-}
-
-- (IBAction)closeBubble:(id)sender {
- [self close];
-}
-
-- (IBAction)manageBlocking:(id)sender {
- contentSettingBubbleModel_->OnManageLinkClicked();
-}
-
-- (IBAction)showMoreInfo:(id)sender {
- contentSettingBubbleModel_->OnInfoLinkClicked();
- [self close];
-}
-
-- (IBAction)loadAllPlugins:(id)sender {
- contentSettingBubbleModel_->OnLoadPluginsLinkClicked();
- [self close];
-}
-
-- (void)popupLinkClicked:(id)sender {
- content_setting_bubble::PopupLinks::iterator i(popupLinks_.find(sender));
- DCHECK(i != popupLinks_.end());
- contentSettingBubbleModel_->OnPopupClicked(i->second);
-}
-
-- (void)clearGeolocationForCurrentHost:(id)sender {
- contentSettingBubbleModel_->OnClearLinkClicked();
- [self close];
-}
-
-@end // ContentSettingBubbleController
diff --git a/chrome/browser/cocoa/content_setting_bubble_cocoa_unittest.mm b/chrome/browser/cocoa/content_setting_bubble_cocoa_unittest.mm
deleted file mode 100644
index 3485782..0000000
--- a/chrome/browser/cocoa/content_setting_bubble_cocoa_unittest.mm
+++ /dev/null
@@ -1,63 +0,0 @@
-// 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 "chrome/browser/cocoa/content_setting_bubble_cocoa.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/debug/debugger.h"
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/content_setting_bubble_model.h"
-#include "chrome/common/content_settings_types.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-class DummyContentSettingBubbleModel : public ContentSettingBubbleModel {
- public:
- DummyContentSettingBubbleModel(ContentSettingsType content_type)
- : ContentSettingBubbleModel(NULL, NULL, content_type) {
- RadioGroup radio_group;
- radio_group.default_item = 0;
- radio_group.radio_items.resize(2);
- set_radio_group(radio_group);
- }
-};
-
-class ContentSettingBubbleControllerTest : public CocoaTest {
-};
-
-// Check that the bubble doesn't crash or leak for any settings type
-TEST_F(ContentSettingBubbleControllerTest, Init) {
- for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
- if (i == CONTENT_SETTINGS_TYPE_NOTIFICATIONS)
- continue; // Notifications have no bubble.
-
- ContentSettingsType settingsType = static_cast<ContentSettingsType>(i);
-
- scoped_nsobject<NSWindow> parent([[NSWindow alloc]
- initWithContentRect:NSMakeRect(0, 0, 800, 600)
- styleMask:NSBorderlessWindowMask
- backing:NSBackingStoreBuffered
- defer:NO]);
- [parent setReleasedWhenClosed:NO];
- if (base::debug::BeingDebugged())
- [parent.get() orderFront:nil];
- else
- [parent.get() orderBack:nil];
-
- ContentSettingBubbleController* controller = [ContentSettingBubbleController
- showForModel:new DummyContentSettingBubbleModel(settingsType)
- parentWindow:parent
- anchoredAt:NSMakePoint(50, 20)];
- EXPECT_TRUE(controller != nil);
- EXPECT_TRUE([[controller window] isVisible]);
- [parent.get() close];
- }
-}
-
-} // namespace
-
-
diff --git a/chrome/browser/cocoa/content_settings_dialog_controller.h b/chrome/browser/cocoa/content_settings_dialog_controller.h
deleted file mode 100644
index 432a3dc..0000000
--- a/chrome/browser/cocoa/content_settings_dialog_controller.h
+++ /dev/null
@@ -1,102 +0,0 @@
-// 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>
-
-#import "base/cocoa_protocols_mac.h"
-#include "base/scoped_ptr.h"
-#include "chrome/common/content_settings_types.h"
-#include "chrome/browser/prefs/pref_change_registrar.h"
-#include "chrome/browser/prefs/pref_member.h"
-
-// Index of the "enabled" and "disabled" radio group settings in all tabs except
-// the ones below.
-const NSInteger kContentSettingsEnabledIndex = 0;
-const NSInteger kContentSettingsDisabledIndex = 1;
-
-// Indices of the various cookie settings in the cookie radio group.
-const NSInteger kCookieEnabledIndex = 0;
-const NSInteger kCookieDisabledIndex = 1;
-
-// Indices of the various plugin settings in the plugins radio group.
-const NSInteger kPluginsAllowIndex = 0;
-const NSInteger kPluginsAskIndex = 1;
-const NSInteger kPluginsBlockIndex = 2;
-
-// Indices of the various geolocation settings in the geolocation radio group.
-const NSInteger kGeolocationEnabledIndex = 0;
-const NSInteger kGeolocationAskIndex = 1;
-const NSInteger kGeolocationDisabledIndex = 2;
-
-// Indices of the various notifications settings in the geolocation radio group.
-const NSInteger kNotificationsEnabledIndex = 0;
-const NSInteger kNotificationsAskIndex = 1;
-const NSInteger kNotificationsDisabledIndex = 2;
-
-namespace ContentSettingsDialogControllerInternal {
-class PrefObserverBridge;
-}
-
-class Profile;
-@class TabViewPickerTable;
-
-// This controller manages a dialog that lets the user manage the content
-// settings for several content setting types.
-@interface ContentSettingsDialogController
- : NSWindowController<NSWindowDelegate, NSTabViewDelegate> {
- @private
- IBOutlet NSTabView* tabView_;
- IBOutlet TabViewPickerTable* tabViewPicker_;
- IBOutlet NSMatrix* pluginDefaultSettingMatrix_;
- Profile* profile_; // weak
- IntegerPrefMember lastSelectedTab_;
- BooleanPrefMember clearSiteDataOnExit_;
- PrefChangeRegistrar registrar_;
- scoped_ptr<ContentSettingsDialogControllerInternal::PrefObserverBridge>
- observer_; // Watches for pref changes.
-}
-
-// Show the content settings dialog associated with the given profile (or the
-// original profile if this is an incognito profile). If no content settings
-// dialog exists for this profile, create one and show it. Any resulting
-// editor releases itself when closed.
-+(id)showContentSettingsForType:(ContentSettingsType)settingsType
- profile:(Profile*)profile;
-
-// Closes an exceptions sheet, if one is attached.
-- (void)closeExceptionsSheet;
-
-- (IBAction)showCookies:(id)sender;
-- (IBAction)openFlashPlayerSettings:(id)sender;
-- (IBAction)openPluginsPage:(id)sender;
-
-- (IBAction)showCookieExceptions:(id)sender;
-- (IBAction)showImagesExceptions:(id)sender;
-- (IBAction)showJavaScriptExceptions:(id)sender;
-- (IBAction)showPluginsExceptions:(id)sender;
-- (IBAction)showPopupsExceptions:(id)sender;
-- (IBAction)showGeolocationExceptions:(id)sender;
-- (IBAction)showNotificationsExceptions:(id)sender;
-
-@end
-
-@interface ContentSettingsDialogController (TestingAPI)
-// Properties that the radio groups and checkboxes are bound to.
-@property(nonatomic) NSInteger cookieSettingIndex;
-@property(nonatomic) BOOL blockThirdPartyCookies;
-@property(nonatomic) BOOL clearSiteDataOnExit;
-@property(nonatomic) NSInteger imagesEnabledIndex;
-@property(nonatomic) NSInteger javaScriptEnabledIndex;
-@property(nonatomic) NSInteger popupsEnabledIndex;
-@property(nonatomic) NSInteger pluginsEnabledIndex;
-@property(nonatomic) NSInteger geolocationSettingIndex;
-@property(nonatomic) NSInteger notificationsSettingIndex;
-
-@property(nonatomic, readonly) BOOL blockThirdPartyCookiesManaged;
-@property(nonatomic, readonly) BOOL cookieSettingsManaged;
-@property(nonatomic, readonly) BOOL imagesSettingsManaged;
-@property(nonatomic, readonly) BOOL javaScriptSettingsManaged;
-@property(nonatomic, readonly) BOOL pluginsSettingsManaged;
-@property(nonatomic, readonly) BOOL popupsSettingsManaged;
-@end
diff --git a/chrome/browser/cocoa/content_settings_dialog_controller.mm b/chrome/browser/cocoa/content_settings_dialog_controller.mm
deleted file mode 100644
index 5126647..0000000
--- a/chrome/browser/cocoa/content_settings_dialog_controller.mm
+++ /dev/null
@@ -1,647 +0,0 @@
-// 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 "chrome/browser/cocoa/content_settings_dialog_controller.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include "app/l10n_util.h"
-#include "base/command_line.h"
-#include "base/mac_util.h"
-#import "chrome/browser/cocoa/content_exceptions_window_controller.h"
-#import "chrome/browser/cocoa/cookies_window_controller.h"
-#import "chrome/browser/cocoa/simple_content_exceptions_window_controller.h"
-#import "chrome/browser/cocoa/l10n_util.h"
-#import "chrome/browser/cocoa/tab_view_picker_table.h"
-#import "chrome/browser/geolocation/geolocation_content_settings_map.h"
-#import "chrome/browser/geolocation/geolocation_exceptions_table_model.h"
-#import "chrome/browser/host_content_settings_map.h"
-#import "chrome/browser/notifications/desktop_notification_service.h"
-#import "chrome/browser/notifications/notification_exceptions_table_model.h"
-#include "chrome/browser/plugin_exceptions_table_model.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/url_constants.h"
-#include "grit/locale_settings.h"
-#include "grit/generated_resources.h"
-
-namespace {
-
-// Stores the currently visible content settings dialog, if any.
-ContentSettingsDialogController* g_instance = nil;
-
-} // namespace
-
-
-@interface ContentSettingsDialogController(Private)
-- (id)initWithProfile:(Profile*)profile;
-- (void)selectTab:(ContentSettingsType)settingsType;
-- (void)showExceptionsForType:(ContentSettingsType)settingsType;
-
-// Callback when preferences are changed. |prefName| is the name of the
-// pref that has changed.
-- (void)prefChanged:(const std::string&)prefName;
-
-// Callback when content settings are changed.
-- (void)contentSettingsChanged:
- (HostContentSettingsMap::ContentSettingsDetails*)details;
-
-@end
-
-namespace ContentSettingsDialogControllerInternal {
-
-// A C++ class registered for changes in preferences.
-class PrefObserverBridge : public NotificationObserver {
- public:
- PrefObserverBridge(ContentSettingsDialogController* controller)
- : controller_(controller), disabled_(false) {}
-
- virtual ~PrefObserverBridge() {}
-
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- if (disabled_)
- return;
-
- // This is currently used by most notifications.
- if (type == NotificationType::PREF_CHANGED) {
- std::string* detail = Details<std::string>(details).ptr();
- if (detail)
- [controller_ prefChanged:*detail];
- }
-
- // This is sent when the "is managed" state changes.
- // TODO(markusheintz): Move all content settings to this notification.
- if (type == NotificationType::CONTENT_SETTINGS_CHANGED) {
- HostContentSettingsMap::ContentSettingsDetails* settings_details =
- Details<HostContentSettingsMap::ContentSettingsDetails>(details).ptr();
- [controller_ contentSettingsChanged:settings_details];
- }
- }
-
- void SetDisabled(bool disabled) {
- disabled_ = disabled;
- }
-
- private:
- ContentSettingsDialogController* controller_; // weak, owns us
- bool disabled_; // true if notifications should be ignored.
-};
-
-// A C++ utility class to disable notifications for PrefsObserverBridge.
-// The intended usage is to create this on the stack.
-class PrefObserverDisabler {
- public:
- PrefObserverDisabler(PrefObserverBridge *bridge) : bridge_(bridge) {
- bridge_->SetDisabled(true);
- }
-
- ~PrefObserverDisabler() {
- bridge_->SetDisabled(false);
- }
-
- private:
- PrefObserverBridge *bridge_;
-};
-
-} // ContentSettingsDialogControllerInternal
-
-@implementation ContentSettingsDialogController
-
-+ (id)showContentSettingsForType:(ContentSettingsType)settingsType
- profile:(Profile*)profile {
- profile = profile->GetOriginalProfile();
- if (!g_instance)
- g_instance = [[self alloc] initWithProfile:profile];
-
- // The code doesn't expect multiple profiles. Check that support for that
- // hasn't been added.
- DCHECK(g_instance->profile_ == profile);
-
- // Select desired tab.
- if (settingsType == CONTENT_SETTINGS_TYPE_DEFAULT) {
- // Remember the last visited page from local state.
- int value = g_instance->lastSelectedTab_.GetValue();
- if (value >= 0 && value < CONTENT_SETTINGS_NUM_TYPES)
- settingsType = static_cast<ContentSettingsType>(value);
- if (settingsType == CONTENT_SETTINGS_TYPE_DEFAULT)
- settingsType = CONTENT_SETTINGS_TYPE_COOKIES;
- }
- // TODO(thakis): Autosave window pos.
-
- [g_instance selectTab:settingsType];
- [g_instance showWindow:nil];
- [g_instance closeExceptionsSheet];
- return g_instance;
-}
-
-- (id)initWithProfile:(Profile*)profile {
- DCHECK(profile);
- NSString* nibpath =
- [mac_util::MainAppBundle() pathForResource:@"ContentSettings"
- ofType:@"nib"];
- if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
- profile_ = profile;
-
- observer_.reset(
- new ContentSettingsDialogControllerInternal::PrefObserverBridge(self));
- clearSiteDataOnExit_.Init(prefs::kClearSiteDataOnExit,
- profile_->GetPrefs(), observer_.get());
-
- // Manually observe notifications for preferences that are grouped in
- // the HostContentSettingsMap or GeolocationContentSettingsMap.
- PrefService* prefs = profile_->GetPrefs();
- registrar_.Init(prefs);
- registrar_.Add(prefs::kBlockThirdPartyCookies, observer_.get());
- registrar_.Add(prefs::kBlockNonsandboxedPlugins, observer_.get());
- registrar_.Add(prefs::kDefaultContentSettings, observer_.get());
- registrar_.Add(prefs::kGeolocationDefaultContentSetting, observer_.get());
-
- // We don't need to observe changes in this value.
- lastSelectedTab_.Init(prefs::kContentSettingsWindowLastTabIndex,
- profile_->GetPrefs(), NULL);
- }
- return self;
-}
-
-- (void)closeExceptionsSheet {
- NSWindow* attachedSheet = [[self window] attachedSheet];
- if (attachedSheet) {
- [NSApp endSheet:attachedSheet];
- }
-}
-
-- (void)awakeFromNib {
- DCHECK([self window]);
- DCHECK(tabView_);
- DCHECK(tabViewPicker_);
- DCHECK_EQ(self, [[self window] delegate]);
-
- // Adapt views to potentially long localized strings.
- CGFloat windowDelta = 0;
- for (NSTabViewItem* tab in [tabView_ tabViewItems]) {
- NSArray* subviews = [[tab view] subviews];
- windowDelta = MAX(windowDelta,
- cocoa_l10n_util::VerticallyReflowGroup(subviews));
-
- for (NSView* view in subviews) {
- // Since the tab pane is in a horizontal resizer in IB, it's convenient
- // to give all the subviews flexible width so that their sizes are
- // autoupdated in IB. However, in chrome, the subviews shouldn't have
- // flexible widths as this looks weird.
- [view setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
- }
- }
-
- NSString* label =
- l10n_util::GetNSStringWithFixup(IDS_CONTENT_SETTINGS_FEATURES_LABEL);
- label = [label stringByReplacingOccurrencesOfString:@":" withString:@""];
- [tabViewPicker_ setHeading:label];
-
- if (!CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableClickToPlay)) {
- // The |pluginsEnabledIndex| property is bound to the selected *tag*,
- // so we don't have to worry about index shifts when removing a row
- // from the matrix.
- [pluginDefaultSettingMatrix_ removeRow:kPluginsAskIndex];
- NSArray* siblingViews = [[pluginDefaultSettingMatrix_ superview] subviews];
- for (NSView* view in siblingViews) {
- NSRect frame = [view frame];
- if (frame.origin.y < [pluginDefaultSettingMatrix_ frame].origin.y) {
- frame.origin.y +=
- ([pluginDefaultSettingMatrix_ cellSize].height +
- [pluginDefaultSettingMatrix_ intercellSpacing].height);
- [view setFrame:frame];
- }
- }
- }
-
- NSRect frame = [[self window] frame];
- frame.origin.y -= windowDelta;
- frame.size.height += windowDelta;
- [[self window] setFrame:frame display:NO];
-}
-
-// NSWindowDelegate method.
-- (void)windowWillClose:(NSNotification*)notification {
- [self autorelease];
- g_instance = nil;
-}
-
-- (void)selectTab:(ContentSettingsType)settingsType {
- [self window]; // Make sure the nib file is loaded.
- DCHECK(tabView_);
- [tabView_ selectTabViewItemAtIndex:settingsType];
-}
-
-// NSTabViewDelegate method.
-- (void) tabView:(NSTabView*)tabView
- didSelectTabViewItem:(NSTabViewItem*)tabViewItem {
- DCHECK_EQ(tabView_, tabView);
- NSInteger index = [tabView indexOfTabViewItem:tabViewItem];
- DCHECK_GT(index, CONTENT_SETTINGS_TYPE_DEFAULT);
- DCHECK_LT(index, CONTENT_SETTINGS_NUM_TYPES);
- if (index > CONTENT_SETTINGS_TYPE_DEFAULT &&
- index < CONTENT_SETTINGS_NUM_TYPES)
- lastSelectedTab_.SetValue(index);
-}
-
-// Let esc close the window.
-- (void)cancel:(id)sender {
- [self close];
-}
-
-- (void)setCookieSettingIndex:(NSInteger)value {
- ContentSetting setting = CONTENT_SETTING_DEFAULT;
- switch (value) {
- case kCookieEnabledIndex: setting = CONTENT_SETTING_ALLOW; break;
- case kCookieDisabledIndex: setting = CONTENT_SETTING_BLOCK; break;
- default:
- NOTREACHED();
- }
- ContentSettingsDialogControllerInternal::PrefObserverDisabler
- disabler(observer_.get());
- profile_->GetHostContentSettingsMap()->SetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_COOKIES,
- setting);
-}
-
-- (NSInteger)cookieSettingIndex {
- switch (profile_->GetHostContentSettingsMap()->GetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_COOKIES)) {
- case CONTENT_SETTING_ALLOW: return kCookieEnabledIndex;
- case CONTENT_SETTING_BLOCK: return kCookieDisabledIndex;
- default:
- NOTREACHED();
- return kCookieEnabledIndex;
- }
-}
-
-- (BOOL)cookieSettingsManaged {
- return profile_->GetHostContentSettingsMap()->IsDefaultContentSettingManaged(
- CONTENT_SETTINGS_TYPE_COOKIES);
-}
-
-- (BOOL)blockThirdPartyCookies {
- HostContentSettingsMap* settingsMap = profile_->GetHostContentSettingsMap();
- return settingsMap->BlockThirdPartyCookies();
-}
-
-- (void)setBlockThirdPartyCookies:(BOOL)value {
- HostContentSettingsMap* settingsMap = profile_->GetHostContentSettingsMap();
- ContentSettingsDialogControllerInternal::PrefObserverDisabler
- disabler(observer_.get());
- settingsMap->SetBlockThirdPartyCookies(value);
-}
-
-- (BOOL)blockThirdPartyCookiesManaged {
- HostContentSettingsMap* settingsMap = profile_->GetHostContentSettingsMap();
- return settingsMap->IsBlockThirdPartyCookiesManaged();
-}
-
-- (BOOL)clearSiteDataOnExit {
- return clearSiteDataOnExit_.GetValue();
-}
-
-- (void)setClearSiteDataOnExit:(BOOL)value {
- ContentSettingsDialogControllerInternal::PrefObserverDisabler
- disabler(observer_.get());
- clearSiteDataOnExit_.SetValue(value);
-}
-
-// Shows the cookies controller.
-- (IBAction)showCookies:(id)sender {
- // The cookie controller will autorelease itself when it's closed.
- BrowsingDataDatabaseHelper* databaseHelper =
- new BrowsingDataDatabaseHelper(profile_);
- BrowsingDataLocalStorageHelper* storageHelper =
- new BrowsingDataLocalStorageHelper(profile_);
- BrowsingDataAppCacheHelper* appcacheHelper =
- new BrowsingDataAppCacheHelper(profile_);
- BrowsingDataIndexedDBHelper* indexedDBHelper =
- BrowsingDataIndexedDBHelper::Create(profile_);
- CookiesWindowController* controller =
- [[CookiesWindowController alloc] initWithProfile:profile_
- databaseHelper:databaseHelper
- storageHelper:storageHelper
- appcacheHelper:appcacheHelper
- indexedDBHelper:indexedDBHelper];
- [controller attachSheetTo:[self window]];
-}
-
-// Called when the user clicks the "Flash Player storage settings" button.
-- (IBAction)openFlashPlayerSettings:(id)sender {
- Browser* browser = Browser::Create(profile_);
- browser->OpenURL(GURL(l10n_util::GetStringUTF8(IDS_FLASH_STORAGE_URL)),
- GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
- browser->window()->Show();
-}
-
-// Called when the user clicks the "Disable individual plug-ins..." button.
-- (IBAction)openPluginsPage:(id)sender {
- Browser* browser = Browser::Create(profile_);
- browser->OpenURL(GURL(chrome::kChromeUIPluginsURL),
- GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
- browser->window()->Show();
-}
-
-- (IBAction)showCookieExceptions:(id)sender {
- [self showExceptionsForType:CONTENT_SETTINGS_TYPE_COOKIES];
-}
-
-- (IBAction)showImagesExceptions:(id)sender {
- [self showExceptionsForType:CONTENT_SETTINGS_TYPE_IMAGES];
-}
-
-- (IBAction)showJavaScriptExceptions:(id)sender {
- [self showExceptionsForType:CONTENT_SETTINGS_TYPE_JAVASCRIPT];
-}
-
-- (IBAction)showPluginsExceptions:(id)sender {
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableResourceContentSettings)) {
- HostContentSettingsMap* settingsMap = profile_->GetHostContentSettingsMap();
- HostContentSettingsMap* offTheRecordSettingsMap =
- profile_->HasOffTheRecordProfile() ?
- profile_->GetOffTheRecordProfile()->GetHostContentSettingsMap() :
- NULL;
- PluginExceptionsTableModel* model =
- new PluginExceptionsTableModel(settingsMap, offTheRecordSettingsMap);
- model->LoadSettings();
- [[SimpleContentExceptionsWindowController controllerWithTableModel:model]
- attachSheetTo:[self window]];
- } else {
- [self showExceptionsForType:CONTENT_SETTINGS_TYPE_PLUGINS];
- }
-}
-
-- (IBAction)showPopupsExceptions:(id)sender {
- [self showExceptionsForType:CONTENT_SETTINGS_TYPE_POPUPS];
-}
-
-- (IBAction)showGeolocationExceptions:(id)sender {
- GeolocationContentSettingsMap* settingsMap =
- profile_->GetGeolocationContentSettingsMap();
- GeolocationExceptionsTableModel* model = // Freed by window controller.
- new GeolocationExceptionsTableModel(settingsMap);
- [[SimpleContentExceptionsWindowController controllerWithTableModel:model]
- attachSheetTo:[self window]];
-}
-
-- (IBAction)showNotificationsExceptions:(id)sender {
- DesktopNotificationService* service =
- profile_->GetDesktopNotificationService();
- NotificationExceptionsTableModel* model = // Freed by window controller.
- new NotificationExceptionsTableModel(service);
- [[SimpleContentExceptionsWindowController controllerWithTableModel:model]
- attachSheetTo:[self window]];
-}
-
-- (void)showExceptionsForType:(ContentSettingsType)settingsType {
- HostContentSettingsMap* settingsMap = profile_->GetHostContentSettingsMap();
- HostContentSettingsMap* offTheRecordSettingsMap =
- profile_->HasOffTheRecordProfile() ?
- profile_->GetOffTheRecordProfile()->GetHostContentSettingsMap() :
- NULL;
- [[ContentExceptionsWindowController controllerForType:settingsType
- settingsMap:settingsMap
- otrSettingsMap:offTheRecordSettingsMap]
- attachSheetTo:[self window]];
-}
-
-- (void)setImagesEnabledIndex:(NSInteger)value {
- ContentSetting setting = value == kContentSettingsEnabledIndex ?
- CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK;
- ContentSettingsDialogControllerInternal::PrefObserverDisabler
- disabler(observer_.get());
- profile_->GetHostContentSettingsMap()->SetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_IMAGES, setting);
-}
-
-- (NSInteger)imagesEnabledIndex {
- HostContentSettingsMap* settingsMap = profile_->GetHostContentSettingsMap();
- bool enabled =
- settingsMap->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_IMAGES) ==
- CONTENT_SETTING_ALLOW;
- return enabled ? kContentSettingsEnabledIndex : kContentSettingsDisabledIndex;
-}
-
-- (BOOL)imagesSettingsManaged {
- return profile_->GetHostContentSettingsMap()->IsDefaultContentSettingManaged(
- CONTENT_SETTINGS_TYPE_IMAGES);
-}
-
-- (void)setJavaScriptEnabledIndex:(NSInteger)value {
- ContentSetting setting = value == kContentSettingsEnabledIndex ?
- CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK;
- ContentSettingsDialogControllerInternal::PrefObserverDisabler
- disabler(observer_.get());
- profile_->GetHostContentSettingsMap()->SetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_JAVASCRIPT, setting);
-}
-
-- (NSInteger)javaScriptEnabledIndex {
- HostContentSettingsMap* settingsMap = profile_->GetHostContentSettingsMap();
- bool enabled =
- settingsMap->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_JAVASCRIPT) ==
- CONTENT_SETTING_ALLOW;
- return enabled ? kContentSettingsEnabledIndex : kContentSettingsDisabledIndex;
-}
-
-- (BOOL)javaScriptSettingsManaged {
- return profile_->GetHostContentSettingsMap()->IsDefaultContentSettingManaged(
- CONTENT_SETTINGS_TYPE_JAVASCRIPT);
-}
-
-- (void)setPluginsEnabledIndex:(NSInteger)value {
- ContentSetting setting = CONTENT_SETTING_DEFAULT;
- switch (value) {
- case kPluginsAllowIndex:
- setting = CONTENT_SETTING_ALLOW;
- break;
- case kPluginsAskIndex:
- setting = CONTENT_SETTING_ASK;
- break;
- case kPluginsBlockIndex:
- setting = CONTENT_SETTING_BLOCK;
- break;
- default:
- NOTREACHED();
- }
- ContentSettingsDialogControllerInternal::PrefObserverDisabler
- disabler(observer_.get());
- profile_->GetHostContentSettingsMap()->SetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_PLUGINS, setting);
-}
-
-- (NSInteger)pluginsEnabledIndex {
- HostContentSettingsMap* map = profile_->GetHostContentSettingsMap();
- ContentSetting setting =
- map->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS);
- switch (setting) {
- case CONTENT_SETTING_ALLOW:
- return kPluginsAllowIndex;
- case CONTENT_SETTING_ASK:
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableClickToPlay))
- return kPluginsAskIndex;
- // Fall through to the next case.
- case CONTENT_SETTING_BLOCK:
- return kPluginsBlockIndex;
- default:
- NOTREACHED();
- return kPluginsAllowIndex;
- }
-}
-
-- (BOOL)pluginsSettingsManaged {
- return profile_->GetHostContentSettingsMap()->IsDefaultContentSettingManaged(
- CONTENT_SETTINGS_TYPE_PLUGINS);
-}
-
-- (void)setPopupsEnabledIndex:(NSInteger)value {
- ContentSetting setting = value == kContentSettingsEnabledIndex ?
- CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK;
- ContentSettingsDialogControllerInternal::PrefObserverDisabler
- disabler(observer_.get());
- profile_->GetHostContentSettingsMap()->SetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_POPUPS, setting);
-}
-
-- (NSInteger)popupsEnabledIndex {
- HostContentSettingsMap* settingsMap = profile_->GetHostContentSettingsMap();
- bool enabled =
- settingsMap->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_POPUPS) ==
- CONTENT_SETTING_ALLOW;
- return enabled ? kContentSettingsEnabledIndex : kContentSettingsDisabledIndex;
-}
-
-- (BOOL)popupsSettingsManaged {
- return profile_->GetHostContentSettingsMap()->IsDefaultContentSettingManaged(
- CONTENT_SETTINGS_TYPE_POPUPS);
-}
-
-- (void)setGeolocationSettingIndex:(NSInteger)value {
- ContentSetting setting = CONTENT_SETTING_DEFAULT;
- switch (value) {
- case kGeolocationEnabledIndex: setting = CONTENT_SETTING_ALLOW; break;
- case kGeolocationAskIndex: setting = CONTENT_SETTING_ASK; break;
- case kGeolocationDisabledIndex: setting = CONTENT_SETTING_BLOCK; break;
- default:
- NOTREACHED();
- }
- ContentSettingsDialogControllerInternal::PrefObserverDisabler
- disabler(observer_.get());
- profile_->GetGeolocationContentSettingsMap()->SetDefaultContentSetting(
- setting);
-}
-
-- (NSInteger)geolocationSettingIndex {
- ContentSetting setting =
- profile_->GetGeolocationContentSettingsMap()->GetDefaultContentSetting();
- switch (setting) {
- case CONTENT_SETTING_ALLOW: return kGeolocationEnabledIndex;
- case CONTENT_SETTING_ASK: return kGeolocationAskIndex;
- case CONTENT_SETTING_BLOCK: return kGeolocationDisabledIndex;
- default:
- NOTREACHED();
- return kGeolocationAskIndex;
- }
-}
-
-- (void)setNotificationsSettingIndex:(NSInteger)value {
- ContentSetting setting = CONTENT_SETTING_DEFAULT;
- switch (value) {
- case kNotificationsEnabledIndex: setting = CONTENT_SETTING_ALLOW; break;
- case kNotificationsAskIndex: setting = CONTENT_SETTING_ASK; break;
- case kNotificationsDisabledIndex: setting = CONTENT_SETTING_BLOCK; break;
- default:
- NOTREACHED();
- }
- ContentSettingsDialogControllerInternal::PrefObserverDisabler
- disabler(observer_.get());
- profile_->GetDesktopNotificationService()->SetDefaultContentSetting(
- setting);
-}
-
-- (NSInteger)notificationsSettingIndex {
- ContentSetting setting =
- profile_->GetDesktopNotificationService()->GetDefaultContentSetting();
- switch (setting) {
- case CONTENT_SETTING_ALLOW: return kNotificationsEnabledIndex;
- case CONTENT_SETTING_ASK: return kNotificationsAskIndex;
- case CONTENT_SETTING_BLOCK: return kNotificationsDisabledIndex;
- default:
- NOTREACHED();
- return kGeolocationAskIndex;
- }
-}
-
-// Callback when preferences are changed. |prefName| is the name of the
-// pref that has changed and should not be NULL.
-- (void)prefChanged:(const std::string&)prefName {
- if (prefName == prefs::kClearSiteDataOnExit) {
- [self willChangeValueForKey:@"clearSiteDataOnExit"];
- [self didChangeValueForKey:@"clearSiteDataOnExit"];
- }
- if (prefName == prefs::kBlockThirdPartyCookies) {
- [self willChangeValueForKey:@"blockThirdPartyCookies"];
- [self didChangeValueForKey:@"blockThirdPartyCookies"];
- [self willChangeValueForKey:@"blockThirdPartyCookiesManaged"];
- [self didChangeValueForKey:@"blockThirdPartyCookiesManaged"];
- }
- if (prefName == prefs::kBlockNonsandboxedPlugins) {
- [self willChangeValueForKey:@"pluginsEnabledIndex"];
- [self didChangeValueForKey:@"pluginsEnabledIndex"];
- }
- if (prefName == prefs::kDefaultContentSettings) {
- // We don't know exactly which setting has changed, so we'll tickle all
- // of the properties that apply to kDefaultContentSettings. This will
- // keep the UI up-to-date.
- [self willChangeValueForKey:@"cookieSettingIndex"];
- [self didChangeValueForKey:@"cookieSettingIndex"];
- [self willChangeValueForKey:@"imagesEnabledIndex"];
- [self didChangeValueForKey:@"imagesEnabledIndex"];
- [self willChangeValueForKey:@"javaScriptEnabledIndex"];
- [self didChangeValueForKey:@"javaScriptEnabledIndex"];
- [self willChangeValueForKey:@"pluginsEnabledIndex"];
- [self didChangeValueForKey:@"pluginsEnabledIndex"];
- [self willChangeValueForKey:@"popupsEnabledIndex"];
- [self didChangeValueForKey:@"popupsEnabledIndex"];
-
- // Updates the "Enable" state of the radio groups and the exception buttons.
- [self willChangeValueForKey:@"cookieSettingsManaged"];
- [self didChangeValueForKey:@"cookieSettingsManaged"];
- [self willChangeValueForKey:@"imagesSettingsManaged"];
- [self didChangeValueForKey:@"imagesSettingsManaged"];
- [self willChangeValueForKey:@"javaScriptSettingsManaged"];
- [self didChangeValueForKey:@"javaScriptSettingsManaged"];
- [self willChangeValueForKey:@"pluginsSettingsManaged"];
- [self didChangeValueForKey:@"pluginsSettingsManaged"];
- [self willChangeValueForKey:@"popupsSettingsManaged"];
- [self didChangeValueForKey:@"popupsSettingsManaged"];
- }
- if (prefName == prefs::kGeolocationDefaultContentSetting) {
- [self willChangeValueForKey:@"geolocationSettingIndex"];
- [self didChangeValueForKey:@"geolocationSettingIndex"];
- }
- if (prefName == prefs::kDesktopNotificationDefaultContentSetting) {
- [self willChangeValueForKey:@"notificationsSettingIndex"];
- [self didChangeValueForKey:@"notificationsSettingIndex"];
- }
-}
-
-- (void)contentSettingsChanged:
- (HostContentSettingsMap::ContentSettingsDetails*)details {
- [self prefChanged:prefs::kBlockNonsandboxedPlugins];
- [self prefChanged:prefs::kDefaultContentSettings];
-}
-
-@end
diff --git a/chrome/browser/cocoa/content_settings_dialog_controller_unittest.mm b/chrome/browser/cocoa/content_settings_dialog_controller_unittest.mm
deleted file mode 100644
index 3558b62..0000000
--- a/chrome/browser/cocoa/content_settings_dialog_controller_unittest.mm
+++ /dev/null
@@ -1,289 +0,0 @@
-// 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 "chrome/browser/cocoa/content_settings_dialog_controller.h"
-
-#include "base/auto_reset.h"
-#include "base/command_line.h"
-#import "base/scoped_nsobject.h"
-#include "base/ref_counted.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
-#include "chrome/browser/host_content_settings_map.h"
-#include "chrome/browser/notifications/desktop_notification_service.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/chrome_switches.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-namespace {
-
-class ContentSettingsDialogControllerTest : public CocoaTest {
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
- TestingProfile* profile = browser_helper_.profile();
- settingsMap_ = new HostContentSettingsMap(profile);
- geoSettingsMap_ = new GeolocationContentSettingsMap(profile);
- notificationsService_.reset(new DesktopNotificationService(profile, NULL));
- controller_ = [ContentSettingsDialogController
- showContentSettingsForType:CONTENT_SETTINGS_TYPE_DEFAULT
- profile:browser_helper_.profile()];
- }
-
- virtual void TearDown() {
- [controller_ close];
- CocoaTest::TearDown();
- }
-
- protected:
- ContentSettingsDialogController* controller_;
- BrowserTestHelper browser_helper_;
- scoped_refptr<HostContentSettingsMap> settingsMap_;
- scoped_refptr<GeolocationContentSettingsMap> geoSettingsMap_;
- scoped_ptr<DesktopNotificationService> notificationsService_;
-};
-
-// Test that +showContentSettingsDialogForProfile brings up the existing editor
-// and doesn't leak or crash.
-TEST_F(ContentSettingsDialogControllerTest, CreateDialog) {
- EXPECT_TRUE(controller_);
-}
-
-TEST_F(ContentSettingsDialogControllerTest, CookieSetting) {
- // Change setting, check dialog property.
- settingsMap_->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_COOKIES,
- CONTENT_SETTING_ALLOW);
- EXPECT_EQ([controller_ cookieSettingIndex], kCookieEnabledIndex);
-
- settingsMap_->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_COOKIES,
- CONTENT_SETTING_BLOCK);
- EXPECT_EQ([controller_ cookieSettingIndex], kCookieDisabledIndex);
-
- // Change dialog property, check setting.
- NSInteger setting;
- [controller_ setCookieSettingIndex:kCookieEnabledIndex];
- setting =
- settingsMap_->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_COOKIES);
- EXPECT_EQ(setting, CONTENT_SETTING_ALLOW);
-
- [controller_ setCookieSettingIndex:kCookieDisabledIndex];
- setting =
- settingsMap_->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_COOKIES);
- EXPECT_EQ(setting, CONTENT_SETTING_BLOCK);
-}
-
-TEST_F(ContentSettingsDialogControllerTest, BlockThirdPartyCookiesSetting) {
- // Change setting, check dialog property.
- settingsMap_->SetBlockThirdPartyCookies(YES);
- EXPECT_TRUE([controller_ blockThirdPartyCookies]);
-
- settingsMap_->SetBlockThirdPartyCookies(NO);
- EXPECT_FALSE([controller_ blockThirdPartyCookies]);
-
- // Change dialog property, check setting.
- [controller_ setBlockThirdPartyCookies:YES];
- EXPECT_TRUE(settingsMap_->BlockThirdPartyCookies());
-
- [controller_ setBlockThirdPartyCookies:NO];
- EXPECT_FALSE(settingsMap_->BlockThirdPartyCookies());
-}
-
-TEST_F(ContentSettingsDialogControllerTest, ClearSiteDataOnExitSetting) {
- TestingProfile* profile = browser_helper_.profile();
-
- // Change setting, check dialog property.
- profile->GetPrefs()->SetBoolean(prefs::kClearSiteDataOnExit, true);
- EXPECT_TRUE([controller_ clearSiteDataOnExit]);
-
- profile->GetPrefs()->SetBoolean(prefs::kClearSiteDataOnExit, false);
- EXPECT_FALSE([controller_ clearSiteDataOnExit]);
-
- // Change dialog property, check setting.
- [controller_ setClearSiteDataOnExit:YES];
- EXPECT_TRUE(profile->GetPrefs()->GetBoolean(prefs::kClearSiteDataOnExit));
-
- [controller_ setClearSiteDataOnExit:NO];
- EXPECT_FALSE(profile->GetPrefs()->GetBoolean(prefs::kClearSiteDataOnExit));
-}
-
-TEST_F(ContentSettingsDialogControllerTest, ImagesSetting) {
- // Change setting, check dialog property.
- settingsMap_->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_IMAGES,
- CONTENT_SETTING_ALLOW);
- EXPECT_EQ([controller_ imagesEnabledIndex], kContentSettingsEnabledIndex);
-
- settingsMap_->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_IMAGES,
- CONTENT_SETTING_BLOCK);
- EXPECT_EQ([controller_ imagesEnabledIndex], kContentSettingsDisabledIndex);
-
- // Change dialog property, check setting.
- NSInteger setting;
- [controller_ setImagesEnabledIndex:kContentSettingsEnabledIndex];
- setting =
- settingsMap_->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_IMAGES);
- EXPECT_EQ(setting, CONTENT_SETTING_ALLOW);
-
- [controller_ setImagesEnabledIndex:kContentSettingsDisabledIndex];
- setting =
- settingsMap_->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_IMAGES);
- EXPECT_EQ(setting, CONTENT_SETTING_BLOCK);
-}
-
-TEST_F(ContentSettingsDialogControllerTest, JavaScriptSetting) {
- // Change setting, check dialog property.
- settingsMap_->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_JAVASCRIPT,
- CONTENT_SETTING_ALLOW);
- EXPECT_EQ([controller_ javaScriptEnabledIndex], kContentSettingsEnabledIndex);
-
- settingsMap_->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_JAVASCRIPT,
- CONTENT_SETTING_BLOCK);
- EXPECT_EQ([controller_ javaScriptEnabledIndex],
- kContentSettingsDisabledIndex);
-
- // Change dialog property, check setting.
- NSInteger setting;
- [controller_ setJavaScriptEnabledIndex:kContentSettingsEnabledIndex];
- setting =
- settingsMap_->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_JAVASCRIPT);
- EXPECT_EQ(setting, CONTENT_SETTING_ALLOW);
-
- [controller_ setJavaScriptEnabledIndex:kContentSettingsDisabledIndex];
- setting =
- settingsMap_->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_JAVASCRIPT);
- EXPECT_EQ(setting, CONTENT_SETTING_BLOCK);
-}
-
-TEST_F(ContentSettingsDialogControllerTest, PluginsSetting) {
- // Change setting, check dialog property.
- settingsMap_->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS,
- CONTENT_SETTING_ALLOW);
- EXPECT_EQ(kPluginsAllowIndex, [controller_ pluginsEnabledIndex]);
-
- settingsMap_->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS,
- CONTENT_SETTING_BLOCK);
- EXPECT_EQ(kPluginsBlockIndex, [controller_ pluginsEnabledIndex]);
-
- {
- // Click-to-play needs to be enabled to set the content setting to ASK.
- CommandLine* cmd = CommandLine::ForCurrentProcess();
- AutoReset<CommandLine> auto_reset(cmd, *cmd);
- cmd->AppendSwitch(switches::kEnableClickToPlay);
-
- settingsMap_->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS,
- CONTENT_SETTING_ASK);
- EXPECT_EQ(kPluginsAskIndex, [controller_ pluginsEnabledIndex]);
- }
-
- // Change dialog property, check setting.
- NSInteger setting;
- [controller_ setPluginsEnabledIndex:kPluginsAllowIndex];
- setting =
- settingsMap_->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS);
- EXPECT_EQ(CONTENT_SETTING_ALLOW, setting);
-
- [controller_ setPluginsEnabledIndex:kPluginsBlockIndex];
- setting =
- settingsMap_->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS);
- EXPECT_EQ(CONTENT_SETTING_BLOCK, setting);
-
- {
- CommandLine* cmd = CommandLine::ForCurrentProcess();
- AutoReset<CommandLine> auto_reset(cmd, *cmd);
- cmd->AppendSwitch(switches::kEnableClickToPlay);
-
- [controller_ setPluginsEnabledIndex:kPluginsAskIndex];
- setting =
- settingsMap_->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS);
- EXPECT_EQ(CONTENT_SETTING_ASK, setting);
- }
-}
-
-TEST_F(ContentSettingsDialogControllerTest, PopupsSetting) {
- // Change setting, check dialog property.
- settingsMap_->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_POPUPS,
- CONTENT_SETTING_ALLOW);
- EXPECT_EQ([controller_ popupsEnabledIndex], kContentSettingsEnabledIndex);
-
- settingsMap_->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_POPUPS,
- CONTENT_SETTING_BLOCK);
- EXPECT_EQ([controller_ popupsEnabledIndex], kContentSettingsDisabledIndex);
-
- // Change dialog property, check setting.
- NSInteger setting;
- [controller_ setPopupsEnabledIndex:kContentSettingsEnabledIndex];
- setting =
- settingsMap_->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_POPUPS);
- EXPECT_EQ(setting, CONTENT_SETTING_ALLOW);
-
- [controller_ setPopupsEnabledIndex:kContentSettingsDisabledIndex];
- setting =
- settingsMap_->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_POPUPS);
- EXPECT_EQ(setting, CONTENT_SETTING_BLOCK);
-}
-
-TEST_F(ContentSettingsDialogControllerTest, GeolocationSetting) {
- // Change setting, check dialog property.
- geoSettingsMap_->SetDefaultContentSetting(CONTENT_SETTING_ALLOW);
- EXPECT_EQ([controller_ geolocationSettingIndex], kGeolocationEnabledIndex);
-
- geoSettingsMap_->SetDefaultContentSetting(CONTENT_SETTING_ASK);
- EXPECT_EQ([controller_ geolocationSettingIndex], kGeolocationAskIndex);
-
- geoSettingsMap_->SetDefaultContentSetting(CONTENT_SETTING_BLOCK);
- EXPECT_EQ([controller_ geolocationSettingIndex], kGeolocationDisabledIndex);
-
- // Change dialog property, check setting.
- NSInteger setting;
- [controller_ setGeolocationSettingIndex:kGeolocationEnabledIndex];
- setting =
- geoSettingsMap_->GetDefaultContentSetting();
- EXPECT_EQ(setting, CONTENT_SETTING_ALLOW);
-
- [controller_ setGeolocationSettingIndex:kGeolocationAskIndex];
- setting =
- geoSettingsMap_->GetDefaultContentSetting();
- EXPECT_EQ(setting, CONTENT_SETTING_ASK);
-
- [controller_ setGeolocationSettingIndex:kGeolocationDisabledIndex];
- setting =
- geoSettingsMap_->GetDefaultContentSetting();
- EXPECT_EQ(setting, CONTENT_SETTING_BLOCK);
-}
-
-TEST_F(ContentSettingsDialogControllerTest, NotificationsSetting) {
- // Change setting, check dialog property.
- notificationsService_->SetDefaultContentSetting(CONTENT_SETTING_ALLOW);
- EXPECT_EQ([controller_ notificationsSettingIndex],
- kNotificationsEnabledIndex);
-
- notificationsService_->SetDefaultContentSetting(CONTENT_SETTING_ASK);
- EXPECT_EQ([controller_ notificationsSettingIndex], kNotificationsAskIndex);
-
- notificationsService_->SetDefaultContentSetting(CONTENT_SETTING_BLOCK);
- EXPECT_EQ([controller_ notificationsSettingIndex],
- kNotificationsDisabledIndex);
-
- // Change dialog property, check setting.
- NSInteger setting;
- [controller_ setNotificationsSettingIndex:kNotificationsEnabledIndex];
- setting =
- notificationsService_->GetDefaultContentSetting();
- EXPECT_EQ(setting, CONTENT_SETTING_ALLOW);
-
- [controller_ setNotificationsSettingIndex:kNotificationsAskIndex];
- setting =
- notificationsService_->GetDefaultContentSetting();
- EXPECT_EQ(setting, CONTENT_SETTING_ASK);
-
- [controller_ setNotificationsSettingIndex:kNotificationsDisabledIndex];
- setting =
- notificationsService_->GetDefaultContentSetting();
- EXPECT_EQ(setting, CONTENT_SETTING_BLOCK);
-}
-
-} // namespace
-
diff --git a/chrome/browser/cocoa/cookie_details.mm b/chrome/browser/cocoa/cookie_details.mm
deleted file mode 100644
index b60e005..0000000
--- a/chrome/browser/cocoa/cookie_details.mm
+++ /dev/null
@@ -1,299 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/cookie_details.h"
-
-#include "app/l10n_util_mac.h"
-#import "base/i18n/time_formatting.h"
-#include "base/sys_string_conversions.h"
-#include "grit/generated_resources.h"
-#include "chrome/browser/cookies_tree_model.h"
-#include "webkit/appcache/appcache_service.h"
-
-#pragma mark Cocoa Cookie Details
-
-@implementation CocoaCookieDetails
-
-@synthesize canEditExpiration = canEditExpiration_;
-@synthesize hasExpiration = hasExpiration_;
-@synthesize type = type_;
-
-- (BOOL)shouldHideCookieDetailsView {
- return type_ != kCocoaCookieDetailsTypeFolder &&
- type_ != kCocoaCookieDetailsTypeCookie;
-}
-
-- (BOOL)shouldShowLocalStorageTreeDetailsView {
- return type_ == kCocoaCookieDetailsTypeTreeLocalStorage;
-}
-
-- (BOOL)shouldShowLocalStoragePromptDetailsView {
- return type_ == kCocoaCookieDetailsTypePromptLocalStorage;
-}
-
-- (BOOL)shouldShowDatabaseTreeDetailsView {
- return type_ == kCocoaCookieDetailsTypeTreeDatabase;
-}
-
-- (BOOL)shouldShowAppCacheTreeDetailsView {
- return type_ == kCocoaCookieDetailsTypeTreeAppCache;
-}
-
-- (BOOL)shouldShowDatabasePromptDetailsView {
- return type_ == kCocoaCookieDetailsTypePromptDatabase;
-}
-
-- (BOOL)shouldShowAppCachePromptDetailsView {
- return type_ == kCocoaCookieDetailsTypePromptAppCache;
-}
-
-- (BOOL)shouldShowIndexedDBTreeDetailsView {
- return type_ == kCocoaCookieDetailsTypeTreeIndexedDB;
-}
-
-- (NSString*)name {
- return name_.get();
-}
-
-- (NSString*)content {
- return content_.get();
-}
-
-- (NSString*)domain {
- return domain_.get();
-}
-
-- (NSString*)path {
- return path_.get();
-}
-
-- (NSString*)sendFor {
- return sendFor_.get();
-}
-
-- (NSString*)created {
- return created_.get();
-}
-
-- (NSString*)expires {
- return expires_.get();
-}
-
-- (NSString*)fileSize {
- return fileSize_.get();
-}
-
-- (NSString*)lastModified {
- return lastModified_.get();
-}
-
-- (NSString*)lastAccessed {
- return lastAccessed_.get();
-}
-
-- (NSString*)databaseDescription {
- return databaseDescription_.get();
-}
-
-- (NSString*)localStorageKey {
- return localStorageKey_.get();
-}
-
-- (NSString*)localStorageValue {
- return localStorageValue_.get();
-}
-
-- (NSString*)manifestURL {
- return manifestURL_.get();
-}
-
-- (id)initAsFolder {
- if ((self = [super init])) {
- type_ = kCocoaCookieDetailsTypeFolder;
- }
- return self;
-}
-
-- (id)initWithCookie:(const net::CookieMonster::CanonicalCookie*)cookie
- origin:(NSString*)origin
- canEditExpiration:(BOOL)canEditExpiration {
- if ((self = [super init])) {
- type_ = kCocoaCookieDetailsTypeCookie;
- hasExpiration_ = cookie->DoesExpire();
- canEditExpiration_ = canEditExpiration && hasExpiration_;
- name_.reset([base::SysUTF8ToNSString(cookie->Name()) retain]);
- content_.reset([base::SysUTF8ToNSString(cookie->Value()) retain]);
- path_.reset([base::SysUTF8ToNSString(cookie->Path()) retain]);
- domain_.reset([origin retain]);
-
- if (cookie->DoesExpire()) {
- expires_.reset([base::SysWideToNSString(
- base::TimeFormatFriendlyDateAndTime(cookie->ExpiryDate())) retain]);
- } else {
- expires_.reset([l10n_util::GetNSStringWithFixup(
- IDS_COOKIES_COOKIE_EXPIRES_SESSION) retain]);
- }
-
- created_.reset([base::SysWideToNSString(
- base::TimeFormatFriendlyDateAndTime(cookie->CreationDate())) retain]);
-
- if (cookie->IsSecure()) {
- sendFor_.reset([l10n_util::GetNSStringWithFixup(
- IDS_COOKIES_COOKIE_SENDFOR_SECURE) retain]);
- } else {
- sendFor_.reset([l10n_util::GetNSStringWithFixup(
- IDS_COOKIES_COOKIE_SENDFOR_ANY) retain]);
- }
- }
- return self;
-}
-
-- (id)initWithDatabase:(const BrowsingDataDatabaseHelper::DatabaseInfo*)
- databaseInfo {
- if ((self = [super init])) {
- type_ = kCocoaCookieDetailsTypeTreeDatabase;
- canEditExpiration_ = NO;
- databaseDescription_.reset([base::SysUTF8ToNSString(
- databaseInfo->description) retain]);
- fileSize_.reset([base::SysUTF16ToNSString(FormatBytes(databaseInfo->size,
- GetByteDisplayUnits(databaseInfo->size), true)) retain]);
- lastModified_.reset([base::SysWideToNSString(
- base::TimeFormatFriendlyDateAndTime(
- databaseInfo->last_modified)) retain]);
- }
- return self;
-}
-
-- (id)initWithLocalStorage:(
- const BrowsingDataLocalStorageHelper::LocalStorageInfo*)storageInfo {
- if ((self = [super init])) {
- type_ = kCocoaCookieDetailsTypeTreeLocalStorage;
- canEditExpiration_ = NO;
- domain_.reset([base::SysUTF8ToNSString(storageInfo->origin) retain]);
- fileSize_.reset([base::SysUTF16ToNSString(FormatBytes(storageInfo->size,
- GetByteDisplayUnits(storageInfo->size), true)) retain]);
- lastModified_.reset([base::SysWideToNSString(
- base::TimeFormatFriendlyDateAndTime(
- storageInfo->last_modified)) retain]);
- }
- return self;
-}
-
-- (id)initWithAppCacheInfo:(const appcache::AppCacheInfo*)appcacheInfo {
- if ((self = [super init])) {
- type_ = kCocoaCookieDetailsTypeTreeAppCache;
- canEditExpiration_ = NO;
- manifestURL_.reset([base::SysUTF8ToNSString(
- appcacheInfo->manifest_url.spec()) retain]);
- fileSize_.reset([base::SysUTF16ToNSString(FormatBytes(appcacheInfo->size,
- GetByteDisplayUnits(appcacheInfo->size), true)) retain]);
- created_.reset([base::SysWideToNSString(
- base::TimeFormatFriendlyDateAndTime(
- appcacheInfo->creation_time)) retain]);
- lastAccessed_.reset([base::SysWideToNSString(
- base::TimeFormatFriendlyDateAndTime(
- appcacheInfo->last_access_time)) retain]);
- }
- return self;
-}
-
-- (id)initWithDatabase:(const std::string&)domain
- databaseName:(const string16&)databaseName
- databaseDescription:(const string16&)databaseDescription
- fileSize:(unsigned long)fileSize {
- if ((self = [super init])) {
- type_ = kCocoaCookieDetailsTypePromptDatabase;
- canEditExpiration_ = NO;
- name_.reset([base::SysUTF16ToNSString(databaseName) retain]);
- domain_.reset([base::SysUTF8ToNSString(domain) retain]);
- databaseDescription_.reset(
- [base::SysUTF16ToNSString(databaseDescription) retain]);
- fileSize_.reset([base::SysUTF16ToNSString(FormatBytes(fileSize,
- GetByteDisplayUnits(fileSize), true)) retain]);
- }
- return self;
-}
-
-- (id)initWithLocalStorage:(const std::string&)domain
- key:(const string16&)key
- value:(const string16&)value {
- if ((self = [super init])) {
- type_ = kCocoaCookieDetailsTypePromptLocalStorage;
- canEditExpiration_ = NO;
- domain_.reset([base::SysUTF8ToNSString(domain) retain]);
- localStorageKey_.reset([base::SysUTF16ToNSString(key) retain]);
- localStorageValue_.reset([base::SysUTF16ToNSString(value) retain]);
- }
- return self;
-}
-
-- (id)initWithAppCacheManifestURL:(const std::string&)manifestURL {
- if ((self = [super init])) {
- type_ = kCocoaCookieDetailsTypePromptAppCache;
- canEditExpiration_ = NO;
- manifestURL_.reset([base::SysUTF8ToNSString(manifestURL) retain]);
- }
- return self;
-}
-
-- (id)initWithIndexedDBInfo:
- (const BrowsingDataIndexedDBHelper::IndexedDBInfo*)indexedDBInfo {
- if ((self = [super init])) {
- type_ = kCocoaCookieDetailsTypeTreeIndexedDB;
- canEditExpiration_ = NO;
- domain_.reset([base::SysUTF8ToNSString(indexedDBInfo->origin) retain]);
- fileSize_.reset([base::SysUTF16ToNSString(FormatBytes(indexedDBInfo->size,
- GetByteDisplayUnits(indexedDBInfo->size), true)) retain]);
- lastModified_.reset([base::SysWideToNSString(
- base::TimeFormatFriendlyDateAndTime(
- indexedDBInfo->last_modified)) retain]);
- }
- return self;
-}
-
-+ (CocoaCookieDetails*)createFromCookieTreeNode:(CookieTreeNode*)treeNode {
- CookieTreeNode::DetailedInfo info = treeNode->GetDetailedInfo();
- CookieTreeNode::DetailedInfo::NodeType nodeType = info.node_type;
- NSString* origin;
- switch (nodeType) {
- case CookieTreeNode::DetailedInfo::TYPE_COOKIE:
- origin = base::SysWideToNSString(info.origin.c_str());
- return [[[CocoaCookieDetails alloc] initWithCookie:info.cookie
- origin:origin
- canEditExpiration:NO] autorelease];
- case CookieTreeNode::DetailedInfo::TYPE_DATABASE:
- return [[[CocoaCookieDetails alloc]
- initWithDatabase:info.database_info] autorelease];
- case CookieTreeNode::DetailedInfo::TYPE_LOCAL_STORAGE:
- return [[[CocoaCookieDetails alloc]
- initWithLocalStorage:info.local_storage_info] autorelease];
- case CookieTreeNode::DetailedInfo::TYPE_APPCACHE:
- return [[[CocoaCookieDetails alloc]
- initWithAppCacheInfo:info.appcache_info] autorelease];
- case CookieTreeNode::DetailedInfo::TYPE_INDEXED_DB:
- return [[[CocoaCookieDetails alloc]
- initWithIndexedDBInfo:info.indexed_db_info] autorelease];
- default:
- return [[[CocoaCookieDetails alloc] initAsFolder] autorelease];
- }
-}
-
-@end
-
-#pragma mark Content Object Adapter
-
-@implementation CookiePromptContentDetailsAdapter
-
-- (id)initWithDetails:(CocoaCookieDetails*)details {
- if ((self = [super init])) {
- details_.reset([details retain]);
- }
- return self;
-}
-
-- (CocoaCookieDetails*)details {
- return details_.get();
-}
-
-@end
diff --git a/chrome/browser/cocoa/cookie_details_unittest.mm b/chrome/browser/cocoa/cookie_details_unittest.mm
deleted file mode 100644
index 305c0f9..0000000
--- a/chrome/browser/cocoa/cookie_details_unittest.mm
+++ /dev/null
@@ -1,247 +0,0 @@
-// 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.
-
-#include "base/sys_string_conversions.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/cocoa/cookie_details.h"
-#include "googleurl/src/gurl.h"
-#import "testing/gtest_mac.h"
-
-namespace {
-
-class CookiesDetailsTest : public CocoaTest {
-};
-
-TEST_F(CookiesDetailsTest, CreateForFolder) {
- scoped_nsobject<CocoaCookieDetails> details;
- details.reset([[CocoaCookieDetails alloc] initAsFolder]);
-
- EXPECT_EQ([details.get() type], kCocoaCookieDetailsTypeFolder);
-}
-
-TEST_F(CookiesDetailsTest, CreateForCookie) {
- scoped_nsobject<CocoaCookieDetails> details;
- GURL url("http://chromium.org");
- std::string cookieLine(
- "PHPSESSID=0123456789abcdef0123456789abcdef; path=/");
- net::CookieMonster::ParsedCookie pc(cookieLine);
- net::CookieMonster::CanonicalCookie cookie(url, pc);
- NSString* origin = base::SysUTF8ToNSString("http://chromium.org");
- details.reset([[CocoaCookieDetails alloc] initWithCookie:&cookie
- origin:origin
- canEditExpiration:NO]);
-
- EXPECT_EQ([details.get() type], kCocoaCookieDetailsTypeCookie);
- EXPECT_NSEQ(@"PHPSESSID", [details.get() name]);
- EXPECT_NSEQ(@"0123456789abcdef0123456789abcdef",
- [details.get() content]);
- EXPECT_NSEQ(@"http://chromium.org", [details.get() domain]);
- EXPECT_NSEQ(@"/", [details.get() path]);
- EXPECT_NSNE(@"", [details.get() lastModified]);
- EXPECT_NSNE(@"", [details.get() created]);
- EXPECT_NSNE(@"", [details.get() sendFor]);
-
- EXPECT_FALSE([details.get() shouldHideCookieDetailsView]);
- EXPECT_FALSE([details.get() shouldShowLocalStorageTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowDatabaseTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowAppCacheTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowIndexedDBTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowLocalStoragePromptDetailsView]);
- EXPECT_FALSE([details.get() shouldShowDatabasePromptDetailsView]);
- EXPECT_FALSE([details.get() shouldShowAppCachePromptDetailsView]);
-}
-
-TEST_F(CookiesDetailsTest, CreateForTreeDatabase) {
- scoped_nsobject<CocoaCookieDetails> details;
- std::string host("http://chromium.org");
- std::string database_name("sassolungo");
- std::string origin_identifier("dolomites");
- std::string description("a great place to climb");
- int64 size = 1234;
- base::Time last_modified = base::Time::Now();
- BrowsingDataDatabaseHelper::DatabaseInfo info(host, database_name,
- origin_identifier, description, host, size, last_modified);
- details.reset([[CocoaCookieDetails alloc] initWithDatabase:&info]);
-
- EXPECT_EQ([details.get() type], kCocoaCookieDetailsTypeTreeDatabase);
- EXPECT_NSEQ(@"a great place to climb", [details.get() databaseDescription]);
- EXPECT_NSEQ(@"1234 B", [details.get() fileSize]);
- EXPECT_NSNE(@"", [details.get() lastModified]);
-
- EXPECT_TRUE([details.get() shouldHideCookieDetailsView]);
- EXPECT_FALSE([details.get() shouldShowLocalStorageTreeDetailsView]);
- EXPECT_TRUE([details.get() shouldShowDatabaseTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowAppCacheTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowIndexedDBTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowLocalStoragePromptDetailsView]);
- EXPECT_FALSE([details.get() shouldShowDatabasePromptDetailsView]);
- EXPECT_FALSE([details.get() shouldShowAppCachePromptDetailsView]);
-}
-
-TEST_F(CookiesDetailsTest, CreateForTreeLocalStorage) {
- scoped_nsobject<CocoaCookieDetails> details;
- std::string protocol("http");
- std::string host("chromium.org");
- unsigned short port = 80;
- std::string database_identifier("id");
- std::string origin("chromium.org");
- FilePath file_path(FILE_PATH_LITERAL("/"));
- int64 size = 1234;
- base::Time last_modified = base::Time::Now();
- BrowsingDataLocalStorageHelper::LocalStorageInfo info(protocol, host, port,
- database_identifier, origin, file_path, size, last_modified);
- details.reset([[CocoaCookieDetails alloc] initWithLocalStorage:&info]);
-
- EXPECT_EQ([details.get() type], kCocoaCookieDetailsTypeTreeLocalStorage);
- EXPECT_NSEQ(@"chromium.org", [details.get() domain]);
- EXPECT_NSEQ(@"1234 B", [details.get() fileSize]);
- EXPECT_NSNE(@"", [details.get() lastModified]);
-
- EXPECT_TRUE([details.get() shouldHideCookieDetailsView]);
- EXPECT_TRUE([details.get() shouldShowLocalStorageTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowDatabaseTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowAppCacheTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowIndexedDBTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowLocalStoragePromptDetailsView]);
- EXPECT_FALSE([details.get() shouldShowDatabasePromptDetailsView]);
- EXPECT_FALSE([details.get() shouldShowAppCachePromptDetailsView]);
-}
-
-TEST_F(CookiesDetailsTest, CreateForTreeAppCache) {
- scoped_nsobject<CocoaCookieDetails> details;
-
- GURL url("http://chromium.org/stuff.manifest");
- appcache::AppCacheInfo info;
- info.creation_time = base::Time::Now();
- info.last_update_time = base::Time::Now();
- info.last_access_time = base::Time::Now();
- info.size=2678;
- info.manifest_url = url;
- details.reset([[CocoaCookieDetails alloc] initWithAppCacheInfo:&info]);
-
- EXPECT_EQ([details.get() type], kCocoaCookieDetailsTypeTreeAppCache);
- EXPECT_NSEQ(@"http://chromium.org/stuff.manifest",
- [details.get() manifestURL]);
- EXPECT_NSEQ(@"2678 B", [details.get() fileSize]);
- EXPECT_NSNE(@"", [details.get() lastAccessed]);
- EXPECT_NSNE(@"", [details.get() created]);
-
- EXPECT_TRUE([details.get() shouldHideCookieDetailsView]);
- EXPECT_FALSE([details.get() shouldShowLocalStorageTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowDatabaseTreeDetailsView]);
- EXPECT_TRUE([details.get() shouldShowAppCacheTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowIndexedDBTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowLocalStoragePromptDetailsView]);
- EXPECT_FALSE([details.get() shouldShowDatabasePromptDetailsView]);
- EXPECT_FALSE([details.get() shouldShowAppCachePromptDetailsView]);
-}
-
-TEST_F(CookiesDetailsTest, CreateForTreeIndexedDB) {
- scoped_nsobject<CocoaCookieDetails> details;
-
- std::string protocol("http");
- std::string host("moose.org");
- unsigned short port = 80;
- std::string database_identifier("id");
- std::string origin("moose.org");
- FilePath file_path(FILE_PATH_LITERAL("/"));
- int64 size = 1234;
- base::Time last_modified = base::Time::Now();
- BrowsingDataIndexedDBHelper::IndexedDBInfo info(protocol,
- host,
- port,
- database_identifier,
- origin,
- file_path,
- size,
- last_modified);
-
- details.reset([[CocoaCookieDetails alloc] initWithIndexedDBInfo:&info]);
-
- EXPECT_EQ([details.get() type], kCocoaCookieDetailsTypeTreeIndexedDB);
- EXPECT_NSEQ(@"moose.org", [details.get() domain]);
- EXPECT_NSEQ(@"1234 B", [details.get() fileSize]);
- EXPECT_NSNE(@"", [details.get() lastModified]);
-
- EXPECT_TRUE([details.get() shouldHideCookieDetailsView]);
- EXPECT_FALSE([details.get() shouldShowLocalStorageTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowDatabaseTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowAppCacheTreeDetailsView]);
- EXPECT_TRUE([details.get() shouldShowIndexedDBTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowLocalStoragePromptDetailsView]);
- EXPECT_FALSE([details.get() shouldShowDatabasePromptDetailsView]);
- EXPECT_FALSE([details.get() shouldShowAppCachePromptDetailsView]);
-}
-
-TEST_F(CookiesDetailsTest, CreateForPromptDatabase) {
- scoped_nsobject<CocoaCookieDetails> details;
- std::string domain("chromium.org");
- string16 name(base::SysNSStringToUTF16(@"wicked_name"));
- string16 desc(base::SysNSStringToUTF16(@"desc"));
- details.reset([[CocoaCookieDetails alloc] initWithDatabase:domain
- databaseName:name
- databaseDescription:desc
- fileSize:94]);
-
- EXPECT_EQ([details.get() type], kCocoaCookieDetailsTypePromptDatabase);
- EXPECT_NSEQ(@"chromium.org", [details.get() domain]);
- EXPECT_NSEQ(@"wicked_name", [details.get() name]);
- EXPECT_NSEQ(@"desc", [details.get() databaseDescription]);
- EXPECT_NSEQ(@"94 B", [details.get() fileSize]);
-
- EXPECT_TRUE([details.get() shouldHideCookieDetailsView]);
- EXPECT_FALSE([details.get() shouldShowLocalStorageTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowDatabaseTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowAppCacheTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowIndexedDBTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowLocalStoragePromptDetailsView]);
- EXPECT_TRUE([details.get() shouldShowDatabasePromptDetailsView]);
- EXPECT_FALSE([details.get() shouldShowAppCachePromptDetailsView]);
-}
-
-TEST_F(CookiesDetailsTest, CreateForPromptLocalStorage) {
- scoped_nsobject<CocoaCookieDetails> details;
- std::string domain("chromium.org");
- string16 key(base::SysNSStringToUTF16(@"testKey"));
- string16 value(base::SysNSStringToUTF16(@"testValue"));
- details.reset([[CocoaCookieDetails alloc] initWithLocalStorage:domain
- key:key
- value:value]);
-
- EXPECT_EQ([details.get() type], kCocoaCookieDetailsTypePromptLocalStorage);
- EXPECT_NSEQ(@"chromium.org", [details.get() domain]);
- EXPECT_NSEQ(@"testKey", [details.get() localStorageKey]);
- EXPECT_NSEQ(@"testValue", [details.get() localStorageValue]);
-
- EXPECT_TRUE([details.get() shouldHideCookieDetailsView]);
- EXPECT_FALSE([details.get() shouldShowLocalStorageTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowDatabaseTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowAppCacheTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowIndexedDBTreeDetailsView]);
- EXPECT_TRUE([details.get() shouldShowLocalStoragePromptDetailsView]);
- EXPECT_FALSE([details.get() shouldShowDatabasePromptDetailsView]);
- EXPECT_FALSE([details.get() shouldShowAppCachePromptDetailsView]);
-}
-
-TEST_F(CookiesDetailsTest, CreateForPromptAppCache) {
- scoped_nsobject<CocoaCookieDetails> details;
- std::string manifestURL("http://html5demos.com/html5demo.manifest");
- details.reset([[CocoaCookieDetails alloc]
- initWithAppCacheManifestURL:manifestURL.c_str()]);
-
- EXPECT_EQ([details.get() type], kCocoaCookieDetailsTypePromptAppCache);
- EXPECT_NSEQ(@"http://html5demos.com/html5demo.manifest",
- [details.get() manifestURL]);
-
- EXPECT_TRUE([details.get() shouldHideCookieDetailsView]);
- EXPECT_FALSE([details.get() shouldShowLocalStorageTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowDatabaseTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowAppCacheTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowIndexedDBTreeDetailsView]);
- EXPECT_FALSE([details.get() shouldShowLocalStoragePromptDetailsView]);
- EXPECT_FALSE([details.get() shouldShowDatabasePromptDetailsView]);
- EXPECT_TRUE([details.get() shouldShowAppCachePromptDetailsView]);
-}
-
-}
diff --git a/chrome/browser/cocoa/cookie_details_view_controller.h b/chrome/browser/cocoa/cookie_details_view_controller.h
deleted file mode 100644
index cad42f4..0000000
--- a/chrome/browser/cocoa/cookie_details_view_controller.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// 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 "base/cocoa_protocols_mac.h"
-#include "net/base/cookie_monster.h"
-
-@class CocoaCookieTreeNode;
-@class GTMUILocalizerAndLayoutTweaker;
-
-// Controller for the view that displays the details of a cookie,
-// used both in the cookie prompt dialog as well as the
-// show cookies preference sheet of content settings preferences.
-@interface CookieDetailsViewController : NSViewController {
- @private
- // Allows direct access to the object controller for
- // the displayed cookie information.
- IBOutlet NSObjectController* objectController_;
-
- // This explicit reference to the layout tweaker is
- // required because it's necessary to reformat the view when
- // the content object changes, since the content object may
- // alter the widths of some of the fields displayed in the view.
- IBOutlet GTMUILocalizerAndLayoutTweaker* tweaker_;
-}
-
-@property (nonatomic, readonly) BOOL hasExpiration;
-
-- (id)init;
-
-// Configures the cookie detail view that is managed by the controller
-// to display the information about a single cookie, the information
-// for which is explicitly passed in the parameter |content|.
-- (void)setContentObject:(id)content;
-
-// Adjust the size of the view to exactly fix the information text fields
-// that are visible inside it.
-- (void)shrinkViewToFit;
-
-// Called by the cookie tree dialog to establish a binding between
-// the the detail view's object controller and the tree controller.
-// This binding allows the cookie tree to use the detail view unmodified.
-- (void)configureBindingsForTreeController:(NSTreeController*)controller;
-
-// Action sent by the expiration date popup when the user
-// selects the menu item "When I close my browser".
-- (IBAction)setCookieDoesntHaveExplicitExpiration:(id)sender;
-
-// Action sent by the expiration date popup when the user
-// selects the menu item with an explicit date/time of expiration.
-- (IBAction)setCookieHasExplicitExpiration:(id)sender;
-
-@end
-
diff --git a/chrome/browser/cocoa/cookie_details_view_controller.mm b/chrome/browser/cocoa/cookie_details_view_controller.mm
deleted file mode 100644
index 885779b..0000000
--- a/chrome/browser/cocoa/cookie_details_view_controller.mm
+++ /dev/null
@@ -1,110 +0,0 @@
-// 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 "chrome/browser/cocoa/cookie_details_view_controller.h"
-
-#include "app/l10n_util_mac.h"
-#include "app/resource_bundle.h"
-#import "base/mac_util.h"
-#include "base/sys_string_conversions.h"
-#import "chrome/browser/cocoa/cookie_tree_node.h"
-#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-
-namespace {
-static const int kExtraMarginBelowWhenExpirationEditable = 5;
-}
-
-#pragma mark View Controller
-
-@implementation CookieDetailsViewController
-@dynamic hasExpiration;
-
-- (id)init {
- return [super initWithNibName:@"CookieDetailsView"
- bundle:mac_util::MainAppBundle()];
-}
-
-- (void)awakeFromNib {
- DCHECK(objectController_);
-}
-
-// Finds and returns the y offset of the lowest-most non-hidden
-// text field in the view. This is used to shrink the view
-// appropriately so that it just fits its visible content.
-- (void)getLowestLabelVerticalPosition:(NSView*)view
- lowestLabelPosition:(float&)lowestLabelPosition {
- if (![view isHidden]) {
- if ([view isKindOfClass:[NSTextField class]]) {
- NSRect frame = [view frame];
- if (frame.origin.y < lowestLabelPosition) {
- lowestLabelPosition = frame.origin.y;
- }
- }
- for (NSView* subview in [view subviews]) {
- [self getLowestLabelVerticalPosition:subview
- lowestLabelPosition:lowestLabelPosition];
- }
- }
-}
-
-- (void)setContentObject:(id)content {
- // Make sure the view is loaded before we set the content object,
- // otherwise, the KVO notifications to update the content don't
- // reach the view and all of the detail values are default
- // strings.
- NSView* view = [self view];
-
- [objectController_ setValue:content forKey:@"content"];
-
- // View needs to be re-tweaked after setting the content object,
- // since the expiration date may have changed, changing the
- // size of the expiration popup.
- [tweaker_ tweakUI:view];
-}
-
-- (void)shrinkViewToFit {
- // Adjust the information pane to be exactly the right size
- // to hold the visible text information fields.
- NSView* view = [self view];
- NSRect frame = [view frame];
- float lowestLabelPosition = frame.origin.y + frame.size.height;
- [self getLowestLabelVerticalPosition:view
- lowestLabelPosition:lowestLabelPosition];
- float verticalDelta = lowestLabelPosition - frame.origin.y;
-
- // Popup menu for the expiration is taller than the plain
- // text, give it some more room.
- if ([[[objectController_ content] details] canEditExpiration]) {
- verticalDelta -= kExtraMarginBelowWhenExpirationEditable;
- }
-
- frame.origin.y += verticalDelta;
- frame.size.height -= verticalDelta;
- [[self view] setFrame:frame];
-}
-
-- (void)configureBindingsForTreeController:(NSTreeController*)treeController {
- // There seems to be a bug in the binding logic that it's not possible
- // to bind to the selection of the tree controller, the bind seems to
- // require an additional path segment in the key, thus the use of
- // selection.self rather than just selection below.
- [objectController_ bind:@"contentObject"
- toObject:treeController
- withKeyPath:@"selection.self"
- options:nil];
-}
-
-- (IBAction)setCookieDoesntHaveExplicitExpiration:(id)sender {
- [[[objectController_ content] details] setHasExpiration:NO];
-}
-
-- (IBAction)setCookieHasExplicitExpiration:(id)sender {
- [[[objectController_ content] details] setHasExpiration:YES];
-}
-
-- (BOOL)hasExpiration {
- return [[[objectController_ content] details] hasExpiration];
-}
-
-@end
diff --git a/chrome/browser/cocoa/cookie_details_view_controller_unittest.mm b/chrome/browser/cocoa/cookie_details_view_controller_unittest.mm
deleted file mode 100644
index a1df90e..0000000
--- a/chrome/browser/cocoa/cookie_details_view_controller_unittest.mm
+++ /dev/null
@@ -1,88 +0,0 @@
-// 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.
-
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/cocoa/cookie_details.h"
-#include "chrome/browser/cocoa/cookie_details_view_controller.h"
-
-namespace {
-
-class CookieDetailsViewControllerTest : public CocoaTest {
-};
-
-static CocoaCookieDetails* CreateTestCookieDetails(BOOL canEditExpiration) {
- GURL url("http://chromium.org");
- std::string cookieLine(
- "PHPSESSID=0123456789abcdef0123456789abcdef; path=/");
- net::CookieMonster::ParsedCookie pc(cookieLine);
- net::CookieMonster::CanonicalCookie cookie(url, pc);
- NSString* origin = base::SysUTF8ToNSString("http://chromium.org");
- CocoaCookieDetails* details = [CocoaCookieDetails alloc];
- [details initWithCookie:&cookie
- origin:origin
- canEditExpiration:canEditExpiration];
- return [details autorelease];
-}
-
-static CookiePromptContentDetailsAdapter* CreateCookieTestContent(
- BOOL canEditExpiration) {
- CocoaCookieDetails* details = CreateTestCookieDetails(canEditExpiration);
- return [[[CookiePromptContentDetailsAdapter alloc] initWithDetails:details]
- autorelease];
-}
-
-static CocoaCookieDetails* CreateTestDatabaseDetails() {
- std::string domain("chromium.org");
- string16 name(base::SysNSStringToUTF16(@"wicked_name"));
- string16 desc(base::SysNSStringToUTF16(@"wicked_desc"));
- CocoaCookieDetails* details = [CocoaCookieDetails alloc];
- [details initWithDatabase:domain
- databaseName:name
- databaseDescription:desc
- fileSize:2222];
- return [details autorelease];
-}
-
-static CookiePromptContentDetailsAdapter* CreateDatabaseTestContent() {
- CocoaCookieDetails* details = CreateTestDatabaseDetails();
- return [[[CookiePromptContentDetailsAdapter alloc] initWithDetails:details]
- autorelease];
-}
-
-TEST_F(CookieDetailsViewControllerTest, Create) {
- scoped_nsobject<CookieDetailsViewController> detailsViewController(
- [[CookieDetailsViewController alloc] init]);
-}
-
-TEST_F(CookieDetailsViewControllerTest, ShrinkToFit) {
- scoped_nsobject<CookieDetailsViewController> detailsViewController(
- [[CookieDetailsViewController alloc] init]);
- scoped_nsobject<CookiePromptContentDetailsAdapter> adapter(
- [CreateDatabaseTestContent() retain]);
- [detailsViewController.get() setContentObject:adapter.get()];
- NSRect beforeFrame = [[detailsViewController.get() view] frame];
- [detailsViewController.get() shrinkViewToFit];
- NSRect afterFrame = [[detailsViewController.get() view] frame];
-
- EXPECT_TRUE(afterFrame.size.height < beforeFrame.size.width);
-}
-
-TEST_F(CookieDetailsViewControllerTest, ExpirationEditability) {
- scoped_nsobject<CookieDetailsViewController> detailsViewController(
- [[CookieDetailsViewController alloc] init]);
- [detailsViewController view];
- scoped_nsobject<CookiePromptContentDetailsAdapter> adapter(
- [CreateCookieTestContent(YES) retain]);
- [detailsViewController.get() setContentObject:adapter.get()];
-
- EXPECT_FALSE([detailsViewController.get() hasExpiration]);
- [detailsViewController.get() setCookieHasExplicitExpiration:adapter.get()];
- EXPECT_TRUE([detailsViewController.get() hasExpiration]);
- [detailsViewController.get()
- setCookieDoesntHaveExplicitExpiration:adapter.get()];
- EXPECT_FALSE([detailsViewController.get() hasExpiration]);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/cookie_tree_node.h b/chrome/browser/cocoa/cookie_tree_node.h
deleted file mode 100644
index 827c784..0000000
--- a/chrome/browser/cocoa/cookie_tree_node.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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 "base/scoped_nsobject.h"
-#include "chrome/browser/cookies_tree_model.h"
-#include "chrome/browser/cocoa/cookie_details.h"
-
-@interface CocoaCookieTreeNode : NSObject {
- scoped_nsobject<NSString> title_;
- scoped_nsobject<NSMutableArray> children_;
- scoped_nsobject<CocoaCookieDetails> details_;
- CookieTreeNode* treeNode_; // weak
-}
-
-// Designated initializer.
-- (id)initWithNode:(CookieTreeNode*)node;
-
-// Re-sets all the members of the node based on |treeNode_|.
-- (void)rebuild;
-
-// Common getters..
-- (NSString*)title;
-- (CocoaCookieDetailsType)nodeType;
-- (TreeModelNode*)treeNode;
-
-// |-mutableChildren| exists so that the CookiesTreeModelObserverBridge can
-// operate on the children. Note that this lazily creates children.
-- (NSMutableArray*)mutableChildren;
-- (NSArray*)children;
-- (BOOL)isLeaf;
-
-- (CocoaCookieDetails*)details;
-
-@end
diff --git a/chrome/browser/cocoa/cookie_tree_node.mm b/chrome/browser/cocoa/cookie_tree_node.mm
deleted file mode 100644
index 4b0dd6f..0000000
--- a/chrome/browser/cocoa/cookie_tree_node.mm
+++ /dev/null
@@ -1,73 +0,0 @@
-// 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 "chrome/browser/cocoa/cookie_tree_node.h"
-
-#include "base/sys_string_conversions.h"
-
-@implementation CocoaCookieTreeNode
-
-- (id)initWithNode:(CookieTreeNode*)node {
- if ((self = [super init])) {
- DCHECK(node);
- treeNode_ = node;
- [self rebuild];
- }
- return self;
-}
-
-- (void)rebuild {
- title_.reset([base::SysUTF16ToNSString(treeNode_->GetTitle()) retain]);
- children_.reset();
- // The tree node assumes ownership of the cookie details object
- details_.reset([[CocoaCookieDetails createFromCookieTreeNode:(treeNode_)]
- retain]);
-}
-
-- (NSString*)title {
- return title_.get();
-}
-
-- (CocoaCookieDetailsType)nodeType {
- return [details_.get() type];
-}
-
-- (TreeModelNode*)treeNode {
- return treeNode_;
-}
-
-- (NSMutableArray*)mutableChildren {
- if (!children_.get()) {
- const int childCount = treeNode_->GetChildCount();
- children_.reset([[NSMutableArray alloc] initWithCapacity:childCount]);
- for (int i = 0; i < childCount; ++i) {
- CookieTreeNode* child = treeNode_->GetChild(i);
- scoped_nsobject<CocoaCookieTreeNode> childNode(
- [[CocoaCookieTreeNode alloc] initWithNode:child]);
- [children_ addObject:childNode.get()];
- }
- }
- return children_.get();
-}
-
-- (NSArray*)children {
- return [self mutableChildren];
-}
-
-- (BOOL)isLeaf {
- return [self nodeType] != kCocoaCookieDetailsTypeFolder;
-};
-
-- (NSString*)description {
- NSString* format =
- @"<CocoaCookieTreeNode @ %p (title=%@, nodeType=%d, childCount=%u)";
- return [NSString stringWithFormat:format, self, [self title],
- [self nodeType], [[self children] count]];
-}
-
-- (CocoaCookieDetails*)details {
- return details_;
-}
-
-@end
diff --git a/chrome/browser/cocoa/cookies_window_controller.h b/chrome/browser/cocoa/cookies_window_controller.h
deleted file mode 100644
index 0f2098b..0000000
--- a/chrome/browser/cocoa/cookies_window_controller.h
+++ /dev/null
@@ -1,146 +0,0 @@
-// 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 "base/cocoa_protocols_mac.h"
-#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-#import "chrome/browser/cocoa/cookie_tree_node.h"
-#include "chrome/browser/cookies_tree_model.h"
-#include "net/base/cookie_monster.h"
-
-@class CookiesWindowController;
-@class CookieDetailsViewController;
-class Profile;
-class TreeModel;
-class TreeModelNode;
-
-namespace {
-class CookiesWindowControllerTest;
-}
-
-// Thin bridge to the window controller that performs model update actions
-// directly on the treeController_.
-class CookiesTreeModelObserverBridge : public CookiesTreeModel::Observer {
- public:
- explicit CookiesTreeModelObserverBridge(CookiesWindowController* controller);
-
- // Begin TreeModelObserver implementation.
- virtual void TreeNodesAdded(TreeModel* model,
- TreeModelNode* parent,
- int start,
- int count);
- virtual void TreeNodesRemoved(TreeModel* model,
- TreeModelNode* parent,
- int start,
- int count);
- virtual void TreeNodeChanged(TreeModel* model, TreeModelNode* node);
- // End TreeModelObserver implementation.
-
- virtual void TreeModelBeginBatch(CookiesTreeModel* model);
- virtual void TreeModelEndBatch(CookiesTreeModel* model);
-
- // Invalidates the Cocoa model. This is used to tear down the Cocoa model
- // when we're about to entirely rebuild it.
- void InvalidateCocoaModel();
-
- private:
- friend class ::CookiesWindowControllerTest;
-
- // Creates a CocoaCookieTreeNode from a platform-independent one.
- // Return value is autoreleased. This creates child nodes recusively.
- CocoaCookieTreeNode* CocoaNodeFromTreeNode(TreeModelNode* node);
-
- // Finds the Cocoa model node based on a platform-independent one. This is
- // done by comparing the treeNode pointers. |start| is the node to start
- // searching at. If |start| is nil, the root is used.
- CocoaCookieTreeNode* FindCocoaNode(TreeModelNode* node,
- CocoaCookieTreeNode* start);
-
- // Returns whether or not the Cocoa tree model is built.
- bool HasCocoaModel();
-
- CookiesWindowController* window_controller_; // weak, owns us.
-
- // If this is true, then the Model has informed us that it is batching
- // updates. Rather than updating the Cocoa side of the model, we ignore those
- // small changes and rebuild once at the end.
- bool batch_update_;
-};
-
-// Controller for the cookies manager. This class stores an internal copy of
-// the CookiesTreeModel but with Cocoa-converted values (NSStrings and NSImages
-// instead of std::strings and SkBitmaps). Doing this allows us to use bindings
-// for the interface. Changes are pushed to this internal model via a very thin
-// bridge (see above).
-@interface CookiesWindowController : NSWindowController
- <NSOutlineViewDelegate,
- NSWindowDelegate> {
- @private
- // Platform-independent model and C++/Obj-C bridge components.
- scoped_ptr<CookiesTreeModel> treeModel_;
- scoped_ptr<CookiesTreeModelObserverBridge> modelObserver_;
-
- // Cached array of icons.
- scoped_nsobject<NSMutableArray> icons_;
-
- // Our Cocoa copy of the model.
- scoped_nsobject<CocoaCookieTreeNode> cocoaTreeModel_;
-
- // A flag indicating whether or not the "Remove" button should be enabled.
- BOOL removeButtonEnabled_;
-
- IBOutlet NSTreeController* treeController_;
- IBOutlet NSOutlineView* outlineView_;
- IBOutlet NSSearchField* searchField_;
- IBOutlet NSView* cookieDetailsViewPlaceholder_;
- IBOutlet NSButton* removeButton_;
-
- scoped_nsobject<CookieDetailsViewController> detailsViewController_;
- Profile* profile_; // weak
- BrowsingDataDatabaseHelper* databaseHelper_; // weak
- BrowsingDataLocalStorageHelper* storageHelper_; // weak
- BrowsingDataAppCacheHelper* appcacheHelper_; // weak
- BrowsingDataIndexedDBHelper* indexedDBHelper_; // weak
-}
-@property (assign, nonatomic) BOOL removeButtonEnabled;
-@property (readonly, nonatomic) NSTreeController* treeController;
-
-// Designated initializer. Profile cannot be NULL.
-- (id)initWithProfile:(Profile*)profile
- databaseHelper:(BrowsingDataDatabaseHelper*)databaseHelper
- storageHelper:(BrowsingDataLocalStorageHelper*)storageHelper
- appcacheHelper:(BrowsingDataAppCacheHelper*)appcacheHelper
- indexedDBHelper:(BrowsingDataIndexedDBHelper*)indexedDBHelper;
-
-// Shows the cookies window as a modal sheet attached to |window|.
-- (void)attachSheetTo:(NSWindow*)window;
-
-// Updates the filter from the search field.
-- (IBAction)updateFilter:(id)sender;
-
-// Delete cookie actions.
-- (IBAction)deleteCookie:(id)sender;
-- (IBAction)deleteAllCookies:(id)sender;
-
-// Closes the sheet and ends the modal loop. This will also cleanup the memory.
-- (IBAction)closeSheet:(id)sender;
-
-// Returns the cocoaTreeModel_.
-- (CocoaCookieTreeNode*)cocoaTreeModel;
-- (void)setCocoaTreeModel:(CocoaCookieTreeNode*)model;
-
-// Returns the treeModel_.
-- (CookiesTreeModel*)treeModel;
-
-@end
-
-@interface CookiesWindowController (UnitTesting)
-- (void)deleteNodeAtIndexPath:(NSIndexPath*)path;
-- (void)clearBrowsingDataNotification:(NSNotification*)notif;
-- (CookiesTreeModelObserverBridge*)modelObserver;
-- (NSArray*)icons;
-- (void)loadTreeModelFromProfile;
-@end
diff --git a/chrome/browser/cocoa/cookies_window_controller.mm b/chrome/browser/cocoa/cookies_window_controller.mm
deleted file mode 100644
index 1f655b5..0000000
--- a/chrome/browser/cocoa/cookies_window_controller.mm
+++ /dev/null
@@ -1,448 +0,0 @@
-// 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 "chrome/browser/cocoa/cookies_window_controller.h"
-
-#include <queue>
-#include <vector>
-
-#include "app/l10n_util_mac.h"
-#include "app/resource_bundle.h"
-#import "base/mac_util.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/browsing_data_remover.h"
-#include "chrome/browser/cocoa/clear_browsing_data_controller.h"
-#include "chrome/browser/cocoa/cookie_details_view_controller.h"
-#include "chrome/browser/profile.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#include "skia/ext/skia_utils_mac.h"
-#include "third_party/apple/ImageAndTextCell.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-// Key path used for notifying KVO.
-static NSString* const kCocoaTreeModel = @"cocoaTreeModel";
-
-CookiesTreeModelObserverBridge::CookiesTreeModelObserverBridge(
- CookiesWindowController* controller)
- : window_controller_(controller),
- batch_update_(false) {
-}
-
-// Notification that nodes were added to the specified parent.
-void CookiesTreeModelObserverBridge::TreeNodesAdded(TreeModel* model,
- TreeModelNode* parent,
- int start,
- int count) {
- // We're in for a major rebuild. Ignore this request.
- if (batch_update_ || !HasCocoaModel())
- return;
-
- CocoaCookieTreeNode* cocoa_parent = FindCocoaNode(parent, nil);
- NSMutableArray* cocoa_children = [cocoa_parent mutableChildren];
-
- [window_controller_ willChangeValueForKey:kCocoaTreeModel];
- CookieTreeNode* cookie_parent = static_cast<CookieTreeNode*>(parent);
- for (int i = 0; i < count; ++i) {
- CookieTreeNode* cookie_child = cookie_parent->GetChild(start + i);
- CocoaCookieTreeNode* new_child = CocoaNodeFromTreeNode(cookie_child);
- [cocoa_children addObject:new_child];
- }
- [window_controller_ didChangeValueForKey:kCocoaTreeModel];
-}
-
-// Notification that nodes were removed from the specified parent.
-void CookiesTreeModelObserverBridge::TreeNodesRemoved(TreeModel* model,
- TreeModelNode* parent,
- int start,
- int count) {
- // We're in for a major rebuild. Ignore this request.
- if (batch_update_ || !HasCocoaModel())
- return;
-
- CocoaCookieTreeNode* cocoa_parent = FindCocoaNode(parent, nil);
- [window_controller_ willChangeValueForKey:kCocoaTreeModel];
- NSMutableArray* cocoa_children = [cocoa_parent mutableChildren];
- for (int i = start + count - 1; i >= start; --i) {
- [cocoa_children removeObjectAtIndex:i];
- }
- [window_controller_ didChangeValueForKey:kCocoaTreeModel];
-}
-
-// Notification that the contents of a node has changed.
-void CookiesTreeModelObserverBridge::TreeNodeChanged(TreeModel* model,
- TreeModelNode* node) {
- // If we don't have a Cocoa model, only let the root node change.
- if (batch_update_ || (!HasCocoaModel() && model->GetRoot() != node))
- return;
-
- if (HasCocoaModel()) {
- // We still have a Cocoa model, so just rebuild the node.
- [window_controller_ willChangeValueForKey:kCocoaTreeModel];
- CocoaCookieTreeNode* changed_node = FindCocoaNode(node, nil);
- [changed_node rebuild];
- [window_controller_ didChangeValueForKey:kCocoaTreeModel];
- } else {
- // Full rebuild.
- [window_controller_ setCocoaTreeModel:CocoaNodeFromTreeNode(node)];
- }
-}
-
-void CookiesTreeModelObserverBridge::TreeModelBeginBatch(
- CookiesTreeModel* model) {
- batch_update_ = true;
-}
-
-void CookiesTreeModelObserverBridge::TreeModelEndBatch(
- CookiesTreeModel* model) {
- DCHECK(batch_update_);
- CocoaCookieTreeNode* root = CocoaNodeFromTreeNode(model->GetRoot());
- [window_controller_ setCocoaTreeModel:root];
- batch_update_ = false;
-}
-
-void CookiesTreeModelObserverBridge::InvalidateCocoaModel() {
- [[[window_controller_ cocoaTreeModel] mutableChildren] removeAllObjects];
-}
-
-CocoaCookieTreeNode* CookiesTreeModelObserverBridge::CocoaNodeFromTreeNode(
- TreeModelNode* node) {
- CookieTreeNode* cookie_node = static_cast<CookieTreeNode*>(node);
- return [[[CocoaCookieTreeNode alloc] initWithNode:cookie_node] autorelease];
-}
-
-// Does breadth-first search on the tree to find |node|. This method is most
-// commonly used to find origin/folder nodes, which are at the first level off
-// the root (hence breadth-first search).
-CocoaCookieTreeNode* CookiesTreeModelObserverBridge::FindCocoaNode(
- TreeModelNode* target, CocoaCookieTreeNode* start) {
- if (!start) {
- start = [window_controller_ cocoaTreeModel];
- }
- if ([start treeNode] == target) {
- return start;
- }
-
- // Enqueue the root node of the search (sub-)tree.
- std::queue<CocoaCookieTreeNode*> horizon;
- horizon.push(start);
-
- // Loop until we've looked at every node or we found the target.
- while (!horizon.empty()) {
- // Dequeue the item at the front.
- CocoaCookieTreeNode* node = horizon.front();
- horizon.pop();
-
- // If this is the droid we're looking for, report it.
- if ([node treeNode] == target)
- return node;
-
- // "Move along, move along." by adding all child nodes to the queue.
- if (![node isLeaf]) {
- NSArray* children = [node children];
- for (CocoaCookieTreeNode* child in children) {
- horizon.push(child);
- }
- }
- }
-
- return nil; // We couldn't find the node.
-}
-
-// Returns whether or not the Cocoa tree model is built.
-bool CookiesTreeModelObserverBridge::HasCocoaModel() {
- return ([[[window_controller_ cocoaTreeModel] children] count] > 0U);
-}
-
-#pragma mark Window Controller
-
-@implementation CookiesWindowController
-
-@synthesize removeButtonEnabled = removeButtonEnabled_;
-@synthesize treeController = treeController_;
-
-- (id)initWithProfile:(Profile*)profile
- databaseHelper:(BrowsingDataDatabaseHelper*)databaseHelper
- storageHelper:(BrowsingDataLocalStorageHelper*)storageHelper
- appcacheHelper:(BrowsingDataAppCacheHelper*)appcacheHelper
- indexedDBHelper:(BrowsingDataIndexedDBHelper*)indexedDBHelper {
- DCHECK(profile);
- NSString* nibpath = [mac_util::MainAppBundle() pathForResource:@"Cookies"
- ofType:@"nib"];
- if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
- profile_ = profile;
- databaseHelper_ = databaseHelper;
- storageHelper_ = storageHelper;
- appcacheHelper_ = appcacheHelper;
- indexedDBHelper_ = indexedDBHelper;
-
- [self loadTreeModelFromProfile];
-
- // Register for Clear Browsing Data controller so we update appropriately.
- ClearBrowsingDataController* clearingController =
- [ClearBrowsingDataController controllerForProfile:profile_];
- if (clearingController) {
- NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
- [center addObserver:self
- selector:@selector(clearBrowsingDataNotification:)
- name:kClearBrowsingDataControllerDidDelete
- object:clearingController];
- }
- }
- return self;
-}
-
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [super dealloc];
-}
-
-- (void)awakeFromNib {
- DCHECK([self window]);
- DCHECK_EQ(self, [[self window] delegate]);
-
- detailsViewController_.reset([[CookieDetailsViewController alloc] init]);
-
- NSView* detailView = [detailsViewController_.get() view];
- NSRect viewFrameRect = [cookieDetailsViewPlaceholder_ frame];
- [[detailsViewController_.get() view] setFrame:viewFrameRect];
- [[cookieDetailsViewPlaceholder_ superview]
- replaceSubview:cookieDetailsViewPlaceholder_
- with:detailView];
-
- [detailsViewController_ configureBindingsForTreeController:treeController_];
-}
-
-- (void)windowWillClose:(NSNotification*)notif {
- [searchField_ setTarget:nil];
- [outlineView_ setDelegate:nil];
- [self autorelease];
-}
-
-- (void)attachSheetTo:(NSWindow*)window {
- [NSApp beginSheet:[self window]
- modalForWindow:window
- modalDelegate:self
- didEndSelector:@selector(sheetEndSheet:returnCode:contextInfo:)
- contextInfo:nil];
-}
-
-- (void)sheetEndSheet:(NSWindow*)sheet
- returnCode:(NSInteger)returnCode
- contextInfo:(void*)context {
- [sheet close];
- [sheet orderOut:self];
-}
-
-- (IBAction)updateFilter:(id)sender {
- DCHECK([sender isKindOfClass:[NSSearchField class]]);
- NSString* string = [sender stringValue];
- // Invalidate the model here because all the nodes are going to be removed
- // in UpdateSearchResults(). This could lead to there temporarily being
- // invalid pointers in the Cocoa model.
- modelObserver_->InvalidateCocoaModel();
- treeModel_->UpdateSearchResults(base::SysNSStringToWide(string));
-}
-
-- (IBAction)deleteCookie:(id)sender {
- DCHECK_EQ(1U, [[treeController_ selectedObjects] count]);
- [self deleteNodeAtIndexPath:[treeController_ selectionIndexPath]];
-}
-
-// This will delete the Cocoa model node as well as the backing model object at
-// the specified index path in the Cocoa model. If the node that was deleted
-// was the sole child of the parent node, this will be called recursively to
-// delete empty parents.
-- (void)deleteNodeAtIndexPath:(NSIndexPath*)path {
- NSTreeNode* treeNode =
- [[treeController_ arrangedObjects] descendantNodeAtIndexPath:path];
- if (!treeNode)
- return;
-
- CocoaCookieTreeNode* node = [treeNode representedObject];
- CookieTreeNode* cookie = static_cast<CookieTreeNode*>([node treeNode]);
- treeModel_->DeleteCookieNode(cookie);
- // If there is a next cookie, this will select it because items will slide
- // up. If there is no next cookie, this is a no-op.
- [treeController_ setSelectionIndexPath:path];
- // If the above setting of the selection was in fact a no-op, find the next
- // node to select.
- if (![[treeController_ selectedObjects] count]) {
- NSUInteger lastIndex = [path indexAtPosition:[path length] - 1];
- if (lastIndex != 0) {
- // If there any nodes remaining, select the node that is in the list
- // before this one.
- path = [path indexPathByRemovingLastIndex];
- path = [path indexPathByAddingIndex:lastIndex - 1];
- [treeController_ setSelectionIndexPath:path];
- }
- }
-}
-
-- (IBAction)deleteAllCookies:(id)sender {
- // Preemptively delete all cookies in the Cocoa model.
- modelObserver_->InvalidateCocoaModel();
- treeModel_->DeleteAllStoredObjects();
-}
-
-- (IBAction)closeSheet:(id)sender {
- [NSApp endSheet:[self window]];
-}
-
-- (void)clearBrowsingDataNotification:(NSNotification*)notif {
- NSNumber* removeMask =
- [[notif userInfo] objectForKey:kClearBrowsingDataControllerRemoveMask];
- if ([removeMask intValue] & BrowsingDataRemover::REMOVE_COOKIES) {
- [self loadTreeModelFromProfile];
- }
-}
-
-// Override keyDown on the controller (which is the first responder) to allow
-// both backspace and delete to be captured by the Remove button.
-- (void)keyDown:(NSEvent*)theEvent {
- NSString* keys = [theEvent characters];
- if ([keys length]) {
- unichar key = [keys characterAtIndex:0];
- // The button has a key equivalent of backspace, so examine this event for
- // forward delete.
- if ((key == NSDeleteCharacter || key == NSDeleteFunctionKey) &&
- [self removeButtonEnabled]) {
- [removeButton_ performClick:self];
- return;
- }
- }
- [super keyDown:theEvent];
-}
-
-#pragma mark Getters and Setters
-
-- (CocoaCookieTreeNode*)cocoaTreeModel {
- return cocoaTreeModel_.get();
-}
-- (void)setCocoaTreeModel:(CocoaCookieTreeNode*)model {
- cocoaTreeModel_.reset([model retain]);
-}
-
-- (CookiesTreeModel*)treeModel {
- return treeModel_.get();
-}
-
-#pragma mark Outline View Delegate
-
-- (void)outlineView:(NSOutlineView*)outlineView
- willDisplayCell:(id)cell
- forTableColumn:(NSTableColumn*)tableColumn
- item:(id)item {
- CocoaCookieTreeNode* node = [item representedObject];
- int index = treeModel_->GetIconIndex([node treeNode]);
- NSImage* icon = nil;
- if (index >= 0)
- icon = [icons_ objectAtIndex:index];
- else
- icon = [icons_ lastObject];
- [(ImageAndTextCell*)cell setImage:icon];
-}
-
-- (void)outlineViewItemDidExpand:(NSNotification*)notif {
- NSTreeNode* item = [[notif userInfo] objectForKey:@"NSObject"];
- CocoaCookieTreeNode* node = [item representedObject];
- NSArray* children = [node children];
- if ([children count] == 1U) {
- // The node that will expand has one child. Do the user a favor and expand
- // that node (saving her a click) if it is non-leaf.
- CocoaCookieTreeNode* child = [children lastObject];
- if (![child isLeaf]) {
- NSOutlineView* outlineView = [notif object];
- // Tell the OutlineView to expand the NSTreeNode, not the model object.
- children = [item childNodes];
- DCHECK_EQ([children count], 1U);
- [outlineView expandItem:[children lastObject]];
- // Select the first node in that child set.
- NSTreeNode* folderChild = [children lastObject];
- if ([[folderChild childNodes] count] > 0) {
- NSTreeNode* firstCookieChild =
- [[folderChild childNodes] objectAtIndex:0];
- [treeController_ setSelectionIndexPath:[firstCookieChild indexPath]];
- }
- }
- }
-}
-
-- (void)outlineViewSelectionDidChange:(NSNotification*)notif {
- // Multi-selection should be disabled in the UI, but for sanity, double-check
- // that they can't do it here.
- NSArray* selectedObjects = [treeController_ selectedObjects];
- NSUInteger count = [selectedObjects count];
- if (count != 1U) {
- DCHECK_LT(count, 1U) << "User was able to select more than 1 cookie node!";
- [self setRemoveButtonEnabled:NO];
- return;
- }
-
- // Go through the selection's indexPath and make sure that the node that is
- // being referenced actually exists in the Cocoa model.
- NSIndexPath* selection = [treeController_ selectionIndexPath];
- NSUInteger length = [selection length];
- CocoaCookieTreeNode* node = [self cocoaTreeModel];
- for (NSUInteger i = 0; i < length; ++i) {
- NSUInteger childIndex = [selection indexAtPosition:i];
- if (childIndex >= [[node children] count]) {
- [self setRemoveButtonEnabled:NO];
- return;
- }
- node = [[node children] objectAtIndex:childIndex];
- }
-
- // If there is a valid selection, make sure that the remove
- // button is enabled.
- [self setRemoveButtonEnabled:YES];
-}
-
-#pragma mark Unit Testing
-
-- (CookiesTreeModelObserverBridge*)modelObserver {
- return modelObserver_.get();
-}
-
-- (NSArray*)icons {
- return icons_.get();
-}
-
-// Re-initializes the |treeModel_|, creates a new observer for it, and re-
-// builds the |cocoaTreeModel_|. We use this to initialize the controller and
-// to rebuild after the user clears browsing data. Because the models get
-// clobbered, we rebuild the icon cache for safety (though they do not change).
-- (void)loadTreeModelFromProfile {
- treeModel_.reset(new CookiesTreeModel(
- profile_->GetRequestContext()->GetCookieStore()->GetCookieMonster(),
- databaseHelper_,
- storageHelper_,
- NULL,
- appcacheHelper_,
- indexedDBHelper_));
- modelObserver_.reset(new CookiesTreeModelObserverBridge(self));
- treeModel_->AddObserver(modelObserver_.get());
-
- // Convert the model's icons from Skia to Cocoa.
- std::vector<SkBitmap> skiaIcons;
- treeModel_->GetIcons(&skiaIcons);
- icons_.reset([[NSMutableArray alloc] init]);
- for (std::vector<SkBitmap>::iterator it = skiaIcons.begin();
- it != skiaIcons.end(); ++it) {
- [icons_ addObject:gfx::SkBitmapToNSImage(*it)];
- }
-
- // Default icon will be the last item in the array.
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- // TODO(rsesek): Rename this resource now that it's in multiple places.
- [icons_ addObject:rb.GetNativeImageNamed(IDR_BOOKMARK_BAR_FOLDER)];
-
- // Create the Cocoa model.
- CookieTreeNode* root = static_cast<CookieTreeNode*>(treeModel_->GetRoot());
- scoped_nsobject<CocoaCookieTreeNode> model(
- [[CocoaCookieTreeNode alloc] initWithNode:root]);
- [self setCocoaTreeModel:model.get()]; // Takes ownership.
-}
-
-@end
diff --git a/chrome/browser/cocoa/cookies_window_controller_unittest.mm b/chrome/browser/cocoa/cookies_window_controller_unittest.mm
deleted file mode 100644
index 7b63243..0000000
--- a/chrome/browser/cocoa/cookies_window_controller_unittest.mm
+++ /dev/null
@@ -1,687 +0,0 @@
-// 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 "app/l10n_util_mac.h"
-#include "app/tree_model.h"
-#import "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#include "chrome/browser/browsing_data_remover.h"
-#include "chrome/browser/cocoa/clear_browsing_data_controller.h"
-#import "chrome/browser/cocoa/cookies_window_controller.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/mock_browsing_data_database_helper.h"
-#include "chrome/browser/mock_browsing_data_local_storage_helper.h"
-#include "chrome/browser/mock_browsing_data_appcache_helper.h"
-#include "chrome/browser/cookies_tree_model.h"
-#include "chrome/browser/profile.h"
-#include "chrome/common/net/url_request_context_getter.h"
-#include "chrome/test/testing_profile.h"
-#include "googleurl/src/gurl.h"
-#include "grit/generated_resources.h"
-#include "net/url_request/url_request_context.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-#import "third_party/ocmock/OCMock/OCMock.h"
-
-// Used to test FindCocoaNode. This only sets the title and node, without
-// initializing any other members.
-@interface FakeCocoaCookieTreeNode : CocoaCookieTreeNode {
- TreeModelNode* testNode_;
-}
-- (id)initWithTreeNode:(TreeModelNode*)node;
-@end
-@implementation FakeCocoaCookieTreeNode
-- (id)initWithTreeNode:(TreeModelNode*)node {
- if ((self = [super init])) {
- testNode_ = node;
- children_.reset([[NSMutableArray alloc] init]);
- }
- return self;
-}
-- (TreeModelNode*)treeNode {
- return testNode_;
-}
-@end
-
-namespace {
-
-class CookiesWindowControllerTest : public CocoaTest {
- public:
-
- virtual void SetUp() {
- CocoaTest::SetUp();
- TestingProfile* profile = browser_helper_.profile();
- profile->CreateRequestContext();
- database_helper_ = new MockBrowsingDataDatabaseHelper(profile);
- local_storage_helper_ = new MockBrowsingDataLocalStorageHelper(profile);
- appcache_helper_ = new MockBrowsingDataAppCacheHelper(profile);
- controller_.reset(
- [[CookiesWindowController alloc] initWithProfile:profile
- databaseHelper:database_helper_
- storageHelper:local_storage_helper_
- appcacheHelper:appcache_helper_]
- );
- }
-
- virtual void TearDown() {
- CocoaTest::TearDown();
- }
-
- CocoaCookieTreeNode* CocoaNodeFromTreeNode(TreeModelNode* node) {
- return [controller_ modelObserver]->CocoaNodeFromTreeNode(node);
- }
-
- CocoaCookieTreeNode* FindCocoaNode(TreeModelNode* node,
- CocoaCookieTreeNode* start) {
- return [controller_ modelObserver]->FindCocoaNode(node, start);
- }
-
- protected:
- BrowserTestHelper browser_helper_;
- scoped_nsobject<CookiesWindowController> controller_;
- MockBrowsingDataDatabaseHelper* database_helper_;
- MockBrowsingDataLocalStorageHelper* local_storage_helper_;
- MockBrowsingDataAppCacheHelper* appcache_helper_;
-};
-
-TEST_F(CookiesWindowControllerTest, Construction) {
- std::vector<SkBitmap> skia_icons;
- [controller_ treeModel]->GetIcons(&skia_icons);
-
- EXPECT_EQ([[controller_ icons] count], skia_icons.size() + 1U);
-}
-
-TEST_F(CookiesWindowControllerTest, FindCocoaNodeRoot) {
- scoped_ptr< TreeNodeWithValue<int> > search(new TreeNodeWithValue<int>(42));
- scoped_nsobject<FakeCocoaCookieTreeNode> node(
- [[FakeCocoaCookieTreeNode alloc] initWithTreeNode:search.get()]);
- EXPECT_EQ(node.get(), FindCocoaNode(search.get(), node.get()));
-}
-
-TEST_F(CookiesWindowControllerTest, FindCocoaNodeImmediateChild) {
- scoped_ptr< TreeNodeWithValue<int> > parent(new TreeNodeWithValue<int>(100));
- scoped_ptr< TreeNodeWithValue<int> > child1(new TreeNodeWithValue<int>(10));
- scoped_ptr< TreeNodeWithValue<int> > child2(new TreeNodeWithValue<int>(20));
- scoped_nsobject<FakeCocoaCookieTreeNode> cocoaParent(
- [[FakeCocoaCookieTreeNode alloc] initWithTreeNode:parent.get()]);
- scoped_nsobject<FakeCocoaCookieTreeNode> cocoaChild1(
- [[FakeCocoaCookieTreeNode alloc] initWithTreeNode:child1.get()]);
- scoped_nsobject<FakeCocoaCookieTreeNode> cocoaChild2(
- [[FakeCocoaCookieTreeNode alloc] initWithTreeNode:child2.get()]);
- [[cocoaParent mutableChildren] addObject:cocoaChild1.get()];
- [[cocoaParent mutableChildren] addObject:cocoaChild2.get()];
-
- EXPECT_EQ(cocoaChild2.get(), FindCocoaNode(child2.get(), cocoaParent.get()));
-}
-
-TEST_F(CookiesWindowControllerTest, FindCocoaNodeRecursive) {
- scoped_ptr< TreeNodeWithValue<int> > parent(new TreeNodeWithValue<int>(100));
- scoped_ptr< TreeNodeWithValue<int> > child1(new TreeNodeWithValue<int>(10));
- scoped_ptr< TreeNodeWithValue<int> > child2(new TreeNodeWithValue<int>(20));
- scoped_nsobject<FakeCocoaCookieTreeNode> cocoaParent(
- [[FakeCocoaCookieTreeNode alloc] initWithTreeNode:parent.get()]);
- scoped_nsobject<FakeCocoaCookieTreeNode> cocoaChild1(
- [[FakeCocoaCookieTreeNode alloc] initWithTreeNode:child1.get()]);
- scoped_nsobject<FakeCocoaCookieTreeNode> cocoaChild2(
- [[FakeCocoaCookieTreeNode alloc] initWithTreeNode:child2.get()]);
- [[cocoaParent mutableChildren] addObject:cocoaChild1.get()];
- [[cocoaChild1 mutableChildren] addObject:cocoaChild2.get()];
-
- EXPECT_EQ(cocoaChild2.get(), FindCocoaNode(child2.get(), cocoaParent.get()));
-}
-
-TEST_F(CookiesWindowControllerTest, CocoaNodeFromTreeNodeCookie) {
- net::CookieMonster* cm = browser_helper_.profile()->GetCookieMonster();
- cm->SetCookie(GURL("http://foo.com"), "A=B");
- CookiesTreeModel model(cm, database_helper_, local_storage_helper_, nil, nil);
-
- // Root --> foo.com --> Cookies --> A. Create node for 'A'.
- TreeModelNode* node = model.GetRoot()->GetChild(0)->GetChild(0)->GetChild(0);
- CocoaCookieTreeNode* cookie = CocoaNodeFromTreeNode(node);
-
- CocoaCookieDetails* details = [cookie details];
- EXPECT_NSEQ(@"B", [details content]);
- EXPECT_NSEQ(l10n_util::GetNSString(IDS_COOKIES_COOKIE_EXPIRES_SESSION),
- [details expires]);
- EXPECT_NSEQ(l10n_util::GetNSString(IDS_COOKIES_COOKIE_SENDFOR_ANY),
- [details sendFor]);
- EXPECT_NSEQ(@"A", [cookie title]);
- EXPECT_NSEQ(@"A", [details name]);
- EXPECT_NSEQ(@"/", [details path]);
- EXPECT_EQ(0U, [[cookie children] count]);
- EXPECT_TRUE([details created]);
- EXPECT_TRUE([cookie isLeaf]);
- EXPECT_EQ(node, [cookie treeNode]);
-}
-
-TEST_F(CookiesWindowControllerTest, CocoaNodeFromTreeNodeRecursive) {
- net::CookieMonster* cm = browser_helper_.profile()->GetCookieMonster();
- cm->SetCookie(GURL("http://foo.com"), "A=B");
- CookiesTreeModel model(cm, database_helper_, local_storage_helper_, nil, nil);
-
- // Root --> foo.com --> Cookies --> A. Create node for 'foo.com'.
- CookieTreeNode* node = model.GetRoot()->GetChild(0);
- CocoaCookieTreeNode* domain = CocoaNodeFromTreeNode(node);
- CocoaCookieTreeNode* cookies = [[domain children] objectAtIndex:0];
- CocoaCookieTreeNode* cookie = [[cookies children] objectAtIndex:0];
-
- // Test domain-level node.
- EXPECT_NSEQ(@"foo.com", [domain title]);
-
- EXPECT_FALSE([domain isLeaf]);
- EXPECT_EQ(1U, [[domain children] count]);
- EXPECT_EQ(node, [domain treeNode]);
-
- // Test "Cookies" folder node.
- EXPECT_NSEQ(l10n_util::GetNSString(IDS_COOKIES_COOKIES), [cookies title]);
- EXPECT_FALSE([cookies isLeaf]);
- EXPECT_EQ(1U, [[cookies children] count]);
- EXPECT_EQ(node->GetChild(0), [cookies treeNode]);
-
- // Test cookie node. This is the same as CocoaNodeFromTreeNodeCookie.
- CocoaCookieDetails* details = [cookie details];
- EXPECT_NSEQ(@"B", [details content]);
- EXPECT_NSEQ(l10n_util::GetNSString(IDS_COOKIES_COOKIE_EXPIRES_SESSION),
- [details expires]);
- EXPECT_NSEQ(l10n_util::GetNSString(IDS_COOKIES_COOKIE_SENDFOR_ANY),
- [details sendFor]);
- EXPECT_NSEQ(@"A", [cookie title]);
- EXPECT_NSEQ(@"A", [details name]);
- EXPECT_NSEQ(@"/", [details path]);
- EXPECT_NSEQ(@"foo.com", [details domain]);
- EXPECT_EQ(0U, [[cookie children] count]);
- EXPECT_TRUE([details created]);
- EXPECT_TRUE([cookie isLeaf]);
- EXPECT_EQ(node->GetChild(0)->GetChild(0), [cookie treeNode]);
-}
-
-TEST_F(CookiesWindowControllerTest, TreeNodesAdded) {
- const GURL url = GURL("http://foo.com");
- TestingProfile* profile = browser_helper_.profile();
- net::CookieMonster* cm = profile->GetCookieMonster();
- cm->SetCookie(url, "A=B");
-
- controller_.reset(
- [[CookiesWindowController alloc] initWithProfile:profile
- databaseHelper:database_helper_
- storageHelper:local_storage_helper_
- appcacheHelper:appcache_helper_]);
-
- // Root --> foo.com --> Cookies.
- NSMutableArray* cocoa_children =
- [[[[[[controller_ cocoaTreeModel] children] objectAtIndex:0]
- children] objectAtIndex:0] mutableChildren];
- EXPECT_EQ(1U, [cocoa_children count]);
-
- // Create some cookies.
- cm->SetCookie(url, "C=D");
- cm->SetCookie(url, "E=F");
-
- net::CookieMonster::CookieList list = cm->GetAllCookies();
- CookiesTreeModel* model = [controller_ treeModel];
- // Root --> foo.com --> Cookies.
- CookieTreeNode* parent = model->GetRoot()->GetChild(0)->GetChild(0);
-
- ASSERT_EQ(3U, list.size());
-
- // Add the cookie nodes.
- CookieTreeCookieNode* cnode = new CookieTreeCookieNode(&list[1]);
- parent->Add(1, cnode); // |parent| takes ownership.
- cnode = new CookieTreeCookieNode(&list[2]);
- parent->Add(2, cnode);
-
- // Manually notify the observer.
- [controller_ modelObserver]->TreeNodesAdded(model, parent, 1, 2);
-
- // Check that we have created 2 more Cocoa nodes.
- EXPECT_EQ(3U, [cocoa_children count]);
-}
-
-TEST_F(CookiesWindowControllerTest, TreeNodesRemoved) {
- const GURL url = GURL("http://foo.com");
- TestingProfile* profile = browser_helper_.profile();
- net::CookieMonster* cm = profile->GetCookieMonster();
- cm->SetCookie(url, "A=B");
- cm->SetCookie(url, "C=D");
- cm->SetCookie(url, "E=F");
-
- controller_.reset(
- [[CookiesWindowController alloc] initWithProfile:profile
- databaseHelper:database_helper_
- storageHelper:local_storage_helper_
- appcacheHelper:appcache_helper_]);
-
- // Root --> foo.com --> Cookies.
- NSMutableArray* cocoa_children =
- [[[[[[controller_ cocoaTreeModel] children] objectAtIndex:0]
- children] objectAtIndex:0] mutableChildren];
- EXPECT_EQ(3U, [cocoa_children count]);
-
- CookiesTreeModel* model = [controller_ treeModel];
- // Root --> foo.com --> Cookies.
- CookieTreeNode* parent = model->GetRoot()->GetChild(0)->GetChild(0);
-
- // Pretend to remove the nodes.
- [controller_ modelObserver]->TreeNodesRemoved(model, parent, 1, 2);
-
- EXPECT_EQ(1U, [cocoa_children count]);
-
- NSString* title = [[[cocoa_children objectAtIndex:0] details] name];
- EXPECT_NSEQ(@"A", title);
-}
-
-TEST_F(CookiesWindowControllerTest, TreeNodeChanged) {
- const GURL url = GURL("http://foo.com");
- TestingProfile* profile = browser_helper_.profile();
- net::CookieMonster* cm = profile->GetCookieMonster();
- cm->SetCookie(url, "A=B");
-
- controller_.reset(
- [[CookiesWindowController alloc] initWithProfile:profile
- databaseHelper:database_helper_
- storageHelper:local_storage_helper_
- appcacheHelper:appcache_helper_]);
-
- CookiesTreeModel* model = [controller_ treeModel];
- // Root --> foo.com --> Cookies.
- CookieTreeNode* node = model->GetRoot()->GetChild(0)->GetChild(0);
-
- // Root --> foo.com --> Cookies.
- CocoaCookieTreeNode* cocoa_node =
- [[[[[controller_ cocoaTreeModel] children] objectAtIndex:0]
- children] objectAtIndex:0];
-
- EXPECT_NSEQ(l10n_util::GetNSString(IDS_COOKIES_COOKIES),
- [cocoa_node title]);
-
- // Fake update the cookie folder's title. This would never happen in reality,
- // but it tests the code path that ultimately calls CocoaNodeFromTreeNode,
- // which is tested elsewhere.
- node->SetTitle(ASCIIToUTF16("Silly Change"));
- [controller_ modelObserver]->TreeNodeChanged(model, node);
-
- EXPECT_NSEQ(@"Silly Change", [cocoa_node title]);
-}
-
-TEST_F(CookiesWindowControllerTest, DeleteCookie) {
- const GURL url = GURL("http://foo.com");
- TestingProfile* profile = browser_helper_.profile();
- net::CookieMonster* cm = profile->GetCookieMonster();
- cm->SetCookie(url, "A=B");
- cm->SetCookie(url, "C=D");
- cm->SetCookie(GURL("http://google.com"), "E=F");
-
- // This will clean itself up when we call |-closeSheet:|. If we reset the
- // scoper, we'd get a double-free.
- CookiesWindowController* controller =
- [[CookiesWindowController alloc] initWithProfile:profile
- databaseHelper:database_helper_
- storageHelper:local_storage_helper_
- appcacheHelper:appcache_helper_];
- [controller attachSheetTo:test_window()];
- NSTreeController* treeController = [controller treeController];
-
- // Select cookie A.
- NSUInteger pathA[3] = {0, 0, 0};
- NSIndexPath* indexPath = [NSIndexPath indexPathWithIndexes:pathA length:3];
- [treeController setSelectionIndexPath:indexPath];
-
- // Press the "Delete" button.
- [controller deleteCookie:nil];
-
- // Root --> foo.com --> Cookies.
- NSArray* cookies = [[[[[[controller cocoaTreeModel] children]
- objectAtIndex:0] children] objectAtIndex:0] children];
- EXPECT_EQ(1U, [cookies count]);
- EXPECT_NSEQ(@"C", [[cookies lastObject] title]);
- EXPECT_NSEQ(indexPath, [treeController selectionIndexPath]);
-
- // Select cookie E.
- NSUInteger pathE[3] = {1, 0, 0};
- indexPath = [NSIndexPath indexPathWithIndexes:pathE length:3];
- [treeController setSelectionIndexPath:indexPath];
-
- // Perform delete.
- [controller deleteCookie:nil];
-
- // Make sure that both the domain level node and the Cookies folder node got
- // deleted because there was only one leaf node.
- EXPECT_EQ(1U, [[[controller cocoaTreeModel] children] count]);
-
- // Select cookie C.
- NSUInteger pathC[3] = {0, 0, 0};
- indexPath = [NSIndexPath indexPathWithIndexes:pathC length:3];
- [treeController setSelectionIndexPath:indexPath];
-
- // Perform delete.
- [controller deleteCookie:nil];
-
- // Make sure the world didn't explode and that there's nothing in the tree.
- EXPECT_EQ(0U, [[[controller cocoaTreeModel] children] count]);
-
- [controller closeSheet:nil];
-}
-
-TEST_F(CookiesWindowControllerTest, DidExpandItem) {
- const GURL url = GURL("http://foo.com");
- TestingProfile* profile = browser_helper_.profile();
- net::CookieMonster* cm = profile->GetCookieMonster();
- cm->SetCookie(url, "A=B");
- cm->SetCookie(url, "C=D");
-
- controller_.reset(
- [[CookiesWindowController alloc] initWithProfile:profile
- databaseHelper:database_helper_
- storageHelper:local_storage_helper_
- appcacheHelper:appcache_helper_]);
-
- // Root --> foo.com.
- CocoaCookieTreeNode* foo =
- [[[controller_ cocoaTreeModel] children] objectAtIndex:0];
-
- // Create the objects we are going to be testing with.
- id outlineView = [OCMockObject mockForClass:[NSOutlineView class]];
- id treeNode = [OCMockObject mockForClass:[NSTreeNode class]];
- NSTreeNode* childTreeNode =
- [NSTreeNode treeNodeWithRepresentedObject:[[foo children] lastObject]];
- NSArray* fakeChildren = [NSArray arrayWithObject:childTreeNode];
-
- // Set up the mock object.
- [[[treeNode stub] andReturn:foo] representedObject];
- [[[treeNode stub] andReturn:fakeChildren] childNodes];
-
- // Create a fake "ItemDidExpand" notification.
- NSDictionary* userInfo = [NSDictionary dictionaryWithObject:treeNode
- forKey:@"NSObject"];
- NSNotification* notif =
- [NSNotification notificationWithName:@"ItemDidExpandNotification"
- object:outlineView
- userInfo:userInfo];
-
- // Make sure we work correctly.
- [[outlineView expect] expandItem:childTreeNode];
- [controller_ outlineViewItemDidExpand:notif];
- [outlineView verify];
-}
-
-TEST_F(CookiesWindowControllerTest, ClearBrowsingData) {
- const GURL url = GURL("http://foo.com");
- TestingProfile* profile = browser_helper_.profile();
- net::CookieMonster* cm = profile->GetCookieMonster();
- cm->SetCookie(url, "A=B");
- cm->SetCookie(url, "C=D");
- cm->SetCookie(url, "E=F");
-
- id mock = [OCMockObject partialMockForObject:controller_.get()];
- [[mock expect] loadTreeModelFromProfile];
-
- NSNumber* mask =
- [NSNumber numberWithInt:BrowsingDataRemover::REMOVE_COOKIES];
- NSDictionary* userInfo =
- [NSDictionary dictionaryWithObject:mask
- forKey:kClearBrowsingDataControllerRemoveMask];
- NSNotification* notif =
- [NSNotification notificationWithName:kClearBrowsingDataControllerDidDelete
- object:nil
- userInfo:userInfo];
- [controller_ clearBrowsingDataNotification:notif];
-
- [mock verify];
-}
-
-// This test has been flaky under Valgrind and turns the bot red since r38504.
-// Under Mac Tests 10.5, it occasionally reports:
-// malloc: *** error for object 0x31e0468: Non-aligned pointer being freed
-// *** set a breakpoint in malloc_error_break to debug
-// Attempts to reproduce locally were not successful. This code is likely
-// changing in the future, so it's marked flaky for now. http://crbug.com/35327
-TEST_F(CookiesWindowControllerTest, FLAKY_RemoveButtonEnabled) {
- const GURL url = GURL("http://foo.com");
- TestingProfile* profile = browser_helper_.profile();
- net::CookieMonster* cm = profile->GetCookieMonster();
- cm->SetCookie(url, "A=B");
- cm->SetCookie(url, "C=D");
-
- // This will clean itself up when we call |-closeSheet:|. If we reset the
- // scoper, we'd get a double-free.
- database_helper_ = new MockBrowsingDataDatabaseHelper(profile);
- local_storage_helper_ = new MockBrowsingDataLocalStorageHelper(profile);
- local_storage_helper_->AddLocalStorageSamples();
- CookiesWindowController* controller =
- [[CookiesWindowController alloc] initWithProfile:profile
- databaseHelper:database_helper_
- storageHelper:local_storage_helper_
- appcacheHelper:appcache_helper_];
- local_storage_helper_->Notify();
- [controller attachSheetTo:test_window()];
-
- // Nothing should be selected right now.
- EXPECT_FALSE([controller removeButtonEnabled]);
-
- {
- // Pretend to select cookie A.
- NSUInteger path[3] = {0, 0, 0};
- NSIndexPath* indexPath = [NSIndexPath indexPathWithIndexes:path length:3];
- [[controller treeController] setSelectionIndexPath:indexPath];
- [controller outlineViewSelectionDidChange:nil];
- EXPECT_TRUE([controller removeButtonEnabled]);
- }
-
- {
- // Pretend to select cookie C.
- NSUInteger path[3] = {0, 0, 1};
- NSIndexPath* indexPath = [NSIndexPath indexPathWithIndexes:path length:3];
- [[controller treeController] setSelectionIndexPath:indexPath];
- [controller outlineViewSelectionDidChange:nil];
- EXPECT_TRUE([controller removeButtonEnabled]);
- }
-
- {
- // Select a local storage node.
- NSUInteger path[3] = {2, 0, 0};
- NSIndexPath* indexPath = [NSIndexPath indexPathWithIndexes:path length:3];
- [[controller treeController] setSelectionIndexPath:indexPath];
- [controller outlineViewSelectionDidChange:nil];
- EXPECT_TRUE([controller removeButtonEnabled]);
- }
-
- {
- // Pretend to select something that isn't there!
- NSUInteger path[3] = {0, 0, 2};
- NSIndexPath* indexPath = [NSIndexPath indexPathWithIndexes:path length:3];
- [[controller treeController] setSelectionIndexPath:indexPath];
- [controller outlineViewSelectionDidChange:nil];
- EXPECT_FALSE([controller removeButtonEnabled]);
- }
-
- {
- // Try selecting something that doesn't exist again.
- NSUInteger path[3] = {7, 1, 4};
- NSIndexPath* indexPath = [NSIndexPath indexPathWithIndexes:path length:3];
- [[controller treeController] setSelectionIndexPath:indexPath];
- [controller outlineViewSelectionDidChange:nil];
- EXPECT_FALSE([controller removeButtonEnabled]);
- }
-
- [controller closeSheet:nil];
-}
-
-TEST_F(CookiesWindowControllerTest, UpdateFilter) {
- const GURL url = GURL("http://foo.com");
- TestingProfile* profile = browser_helper_.profile();
- net::CookieMonster* cm = profile->GetCookieMonster();
- cm->SetCookie(GURL("http://a.com"), "A=B");
- cm->SetCookie(GURL("http://aa.com"), "C=D");
- cm->SetCookie(GURL("http://b.com"), "E=F");
- cm->SetCookie(GURL("http://d.com"), "G=H");
- cm->SetCookie(GURL("http://dd.com"), "I=J");
-
- controller_.reset(
- [[CookiesWindowController alloc] initWithProfile:profile
- databaseHelper:database_helper_
- storageHelper:local_storage_helper_
- appcacheHelper:appcache_helper_]);
-
- // Make sure we registered all five cookies.
- EXPECT_EQ(5U, [[[controller_ cocoaTreeModel] children] count]);
-
- NSSearchField* field =
- [[NSSearchField alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
-
- // Make sure we still have five cookies.
- [field setStringValue:@""];
- [controller_ updateFilter:field];
- EXPECT_EQ(5U, [[[controller_ cocoaTreeModel] children] count]);
-
- // Search for "a".
- [field setStringValue:@"a"];
- [controller_ updateFilter:field];
- EXPECT_EQ(2U, [[[controller_ cocoaTreeModel] children] count]);
-
- // Search for "b".
- [field setStringValue:@"b"];
- [controller_ updateFilter:field];
- EXPECT_EQ(1U, [[[controller_ cocoaTreeModel] children] count]);
-
- // Search for "d".
- [field setStringValue:@"d"];
- [controller_ updateFilter:field];
- EXPECT_EQ(2U, [[[controller_ cocoaTreeModel] children] count]);
-
- // Search for "e".
- [field setStringValue:@"e"];
- [controller_ updateFilter:field];
- EXPECT_EQ(0U, [[[controller_ cocoaTreeModel] children] count]);
-
- // Search for "aa".
- [field setStringValue:@"aa"];
- [controller_ updateFilter:field];
- EXPECT_EQ(1U, [[[controller_ cocoaTreeModel] children] count]);
-}
-
-TEST_F(CookiesWindowControllerTest, CreateDatabaseStorageNodes) {
- TestingProfile* profile = browser_helper_.profile();
- database_helper_ = new MockBrowsingDataDatabaseHelper(profile);
- local_storage_helper_ = new MockBrowsingDataLocalStorageHelper(profile);
- database_helper_->AddDatabaseSamples();
- controller_.reset(
- [[CookiesWindowController alloc] initWithProfile:profile
- databaseHelper:database_helper_
- storageHelper:local_storage_helper_
- appcacheHelper:appcache_helper_]);
- database_helper_->Notify();
-
- ASSERT_EQ(2U, [[[controller_ cocoaTreeModel] children] count]);
-
- // Root --> gdbhost1.
- CocoaCookieTreeNode* node =
- [[[controller_ cocoaTreeModel] children] objectAtIndex:0];
- EXPECT_NSEQ(@"gdbhost1", [node title]);
- EXPECT_EQ(kCocoaCookieDetailsTypeFolder, [node nodeType]);
- EXPECT_EQ(1U, [[node children] count]);
-
- // host1 --> Web Databases.
- node = [[node children] lastObject];
- EXPECT_NSEQ(l10n_util::GetNSString(IDS_COOKIES_WEB_DATABASES), [node title]);
- EXPECT_EQ(kCocoaCookieDetailsTypeFolder, [node nodeType]);
- EXPECT_EQ(1U, [[node children] count]);
-
- // Database Storage --> db1.
- node = [[node children] lastObject];
- EXPECT_NSEQ(@"db1", [node title]);
- EXPECT_EQ(kCocoaCookieDetailsTypeTreeDatabase, [node nodeType]);
- CocoaCookieDetails* details = [node details];
- EXPECT_NSEQ(@"description 1", [details databaseDescription]);
- EXPECT_TRUE([details lastModified]);
- EXPECT_TRUE([details fileSize]);
-
- // Root --> gdbhost2.
- node =
- [[[controller_ cocoaTreeModel] children] objectAtIndex:1];
- EXPECT_NSEQ(@"gdbhost2", [node title]);
- EXPECT_EQ(kCocoaCookieDetailsTypeFolder, [node nodeType]);
- EXPECT_EQ(1U, [[node children] count]);
-
- // host1 --> Web Databases.
- node = [[node children] lastObject];
- EXPECT_NSEQ(l10n_util::GetNSString(IDS_COOKIES_WEB_DATABASES), [node title]);
- EXPECT_EQ(kCocoaCookieDetailsTypeFolder, [node nodeType]);
- EXPECT_EQ(1U, [[node children] count]);
-
- // Database Storage --> db2.
- node = [[node children] lastObject];
- EXPECT_NSEQ(@"db2", [node title]);
- EXPECT_EQ(kCocoaCookieDetailsTypeTreeDatabase, [node nodeType]);
- details = [node details];
- EXPECT_NSEQ(@"description 2", [details databaseDescription]);
- EXPECT_TRUE([details lastModified]);
- EXPECT_TRUE([details fileSize]);
-}
-
-TEST_F(CookiesWindowControllerTest, CreateLocalStorageNodes) {
- TestingProfile* profile = browser_helper_.profile();
- net::CookieMonster* cm = profile->GetCookieMonster();
- cm->SetCookie(GURL("http://google.com"), "A=B");
- cm->SetCookie(GURL("http://dev.chromium.org"), "C=D");
- database_helper_ = new MockBrowsingDataDatabaseHelper(profile);
- local_storage_helper_ = new MockBrowsingDataLocalStorageHelper(profile);
- local_storage_helper_->AddLocalStorageSamples();
- controller_.reset(
- [[CookiesWindowController alloc] initWithProfile:profile
- databaseHelper:database_helper_
- storageHelper:local_storage_helper_
- appcacheHelper:appcache_helper_]);
- local_storage_helper_->Notify();
-
- ASSERT_EQ(4U, [[[controller_ cocoaTreeModel] children] count]);
-
- // Root --> host1.
- CocoaCookieTreeNode* node =
- [[[controller_ cocoaTreeModel] children] objectAtIndex:2];
- EXPECT_NSEQ(@"host1", [node title]);
- EXPECT_EQ(kCocoaCookieDetailsTypeFolder, [node nodeType]);
- EXPECT_EQ(1U, [[node children] count]);
-
- // host1 --> Local Storage.
- node = [[node children] lastObject];
- EXPECT_NSEQ(l10n_util::GetNSString(IDS_COOKIES_LOCAL_STORAGE), [node title]);
- EXPECT_EQ(kCocoaCookieDetailsTypeFolder, [node nodeType]);
- EXPECT_EQ(1U, [[node children] count]);
-
- // Local Storage --> http://host1:1/.
- node = [[node children] lastObject];
- EXPECT_NSEQ(@"http://host1:1/", [node title]);
- EXPECT_EQ(kCocoaCookieDetailsTypeTreeLocalStorage, [node nodeType]);
- EXPECT_NSEQ(@"http://host1:1/", [[node details] domain]);
- EXPECT_TRUE([[node details] lastModified]);
- EXPECT_TRUE([[node details] fileSize]);
-
- // Root --> host2.
- node =
- [[[controller_ cocoaTreeModel] children] objectAtIndex:3];
- EXPECT_NSEQ(@"host2", [node title]);
- EXPECT_EQ(kCocoaCookieDetailsTypeFolder, [node nodeType]);
- EXPECT_EQ(1U, [[node children] count]);
-
- // host2 --> Local Storage.
- node = [[node children] lastObject];
- EXPECT_NSEQ(l10n_util::GetNSString(IDS_COOKIES_LOCAL_STORAGE), [node title]);
- EXPECT_EQ(kCocoaCookieDetailsTypeFolder, [node nodeType]);
- EXPECT_EQ(1U, [[node children] count]);
-
- // Local Storage --> http://host2:2/.
- node = [[node children] lastObject];
- EXPECT_NSEQ(@"http://host2:2/", [node title]);
- EXPECT_EQ(kCocoaCookieDetailsTypeTreeLocalStorage, [node nodeType]);
- EXPECT_NSEQ(@"http://host2:2/", [[node details] domain]);
- EXPECT_TRUE([[node details] lastModified]);
- EXPECT_TRUE([[node details] fileSize]);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/custom_home_pages_model.h b/chrome/browser/cocoa/custom_home_pages_model.h
deleted file mode 100644
index 962bc79..0000000
--- a/chrome/browser/cocoa/custom_home_pages_model.h
+++ /dev/null
@@ -1,91 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_CUSTOM_HOME_PAGES_MODEL_H_
-#define CHROME_BROWSER_COCOA_CUSTOM_HOME_PAGES_MODEL_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include <vector>
-#include "base/scoped_nsobject.h"
-#include "chrome/browser/history/history.h"
-#include "googleurl/src/gurl.h"
-
-class Profile;
-
-// The model for the "custom home pages" table in preferences. Contains a list
-// of CustomHomePageEntry objects. This is intended to be used with Cocoa
-// bindings.
-//
-// The supported binding is |customHomePages|, a to-many relationship which
-// can be observed with an array controller.
-
-@interface CustomHomePagesModel : NSObject {
- @private
- scoped_nsobject<NSMutableArray> entries_;
- Profile* profile_; // weak, used for loading favicons
-}
-
-// Initialize with |profile|, which must not be NULL. The profile is used for
-// loading favicons for urls.
-- (id)initWithProfile:(Profile*)profile;
-
-// Get/set the urls the model currently contains as a group. Only one change
-// notification will be sent.
-- (std::vector<GURL>)URLs;
-- (void)setURLs:(const std::vector<GURL>&)urls;
-
-// Reloads the URLs from their stored state. This will notify using KVO
-// |customHomePages|.
-- (void)reloadURLs;
-
-// Validates the set of URLs stored in the model. The user may have input bad
-// data. This function removes invalid entries from the model, which will result
-// in anyone observing being updated.
-- (void)validateURLs;
-
-// For binding |customHomePages| to a mutable array controller.
-- (NSUInteger)countOfCustomHomePages;
-- (id)objectInCustomHomePagesAtIndex:(NSUInteger)index;
-- (void)insertObject:(id)object inCustomHomePagesAtIndex:(NSUInteger)index;
-- (void)removeObjectFromCustomHomePagesAtIndex:(NSUInteger)index;
-@end
-
-////////////////////////////////////////////////////////////////////////////////
-
-// An entry representing a single item in the custom home page model. Stores
-// a url and a favicon.
-@interface CustomHomePageEntry : NSObject {
- @private
- scoped_nsobject<NSString> url_;
- scoped_nsobject<NSImage> icon_;
-
- // If non-zero, indicates we're loading the favicon for the page.
- HistoryService::Handle icon_handle_;
-}
-
-@property(nonatomic, copy) NSString* URL;
-@property(nonatomic, retain) NSImage* image;
-
-@end
-
-////////////////////////////////////////////////////////////////////////////////
-
-@interface CustomHomePagesModel (InternalOrTestingAPI)
-
-// Clears the URL string at the specified index. This constitutes bad data. The
-// validator should scrub the entry from the list the next time it is run.
-- (void)setURLStringEmptyAt:(NSUInteger)index;
-
-@end
-
-// A notification that fires when the URL of one of the entries changes.
-// Prevents interested parties from having to observe all model objects in order
-// to persist changes to a single entry. Changes to the number of items in the
-// model can be observed by watching |customHomePages| via KVO so an additional
-// notification is not sent.
-extern NSString* const kHomepageEntryChangedNotification;
-
-#endif // CHROME_BROWSER_COCOA_CUSTOM_HOME_PAGES_MODEL_H_
diff --git a/chrome/browser/cocoa/custom_home_pages_model.mm b/chrome/browser/cocoa/custom_home_pages_model.mm
deleted file mode 100644
index 692150d..0000000
--- a/chrome/browser/cocoa/custom_home_pages_model.mm
+++ /dev/null
@@ -1,140 +0,0 @@
-// 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 "chrome/browser/cocoa/custom_home_pages_model.h"
-
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/net/url_fixer_upper.h"
-#include "chrome/browser/prefs/session_startup_pref.h"
-
-NSString* const kHomepageEntryChangedNotification =
- @"kHomepageEntryChangedNotification";
-
-@interface CustomHomePagesModel (Private)
-- (void)setURLsInternal:(const std::vector<GURL>&)urls;
-@end
-
-@implementation CustomHomePagesModel
-
-- (id)initWithProfile:(Profile*)profile {
- if ((self = [super init])) {
- profile_ = profile;
- entries_.reset([[NSMutableArray alloc] init]);
- }
- return self;
-}
-
-- (NSUInteger)countOfCustomHomePages {
- return [entries_ count];
-}
-
-- (id)objectInCustomHomePagesAtIndex:(NSUInteger)index {
- return [entries_ objectAtIndex:index];
-}
-
-- (void)insertObject:(id)object inCustomHomePagesAtIndex:(NSUInteger)index {
- [entries_ insertObject:object atIndex:index];
-}
-
-- (void)removeObjectFromCustomHomePagesAtIndex:(NSUInteger)index {
- [entries_ removeObjectAtIndex:index];
- // Force a save.
- [self validateURLs];
-}
-
-// Get/set the urls the model currently contains as a group. These will weed
-// out any URLs that are empty and not add them to the model. As a result,
-// the next time they're persisted to the prefs backend, they'll disappear.
-- (std::vector<GURL>)URLs {
- std::vector<GURL> urls;
- for (CustomHomePageEntry* entry in entries_.get()) {
- const char* urlString = [[entry URL] UTF8String];
- if (urlString && std::strlen(urlString)) {
- urls.push_back(GURL(std::string(urlString)));
- }
- }
- return urls;
-}
-
-- (void)setURLs:(const std::vector<GURL>&)urls {
- [self willChangeValueForKey:@"customHomePages"];
- [self setURLsInternal:urls];
- SessionStartupPref pref(SessionStartupPref::GetStartupPref(profile_));
- pref.urls = urls;
- SessionStartupPref::SetStartupPref(profile_, pref);
- [self didChangeValueForKey:@"customHomePages"];
-}
-
-// Converts the C++ URLs to Cocoa objects without notifying KVO.
-- (void)setURLsInternal:(const std::vector<GURL>&)urls {
- [entries_ removeAllObjects];
- for (size_t i = 0; i < urls.size(); ++i) {
- scoped_nsobject<CustomHomePageEntry> entry(
- [[CustomHomePageEntry alloc] init]);
- const char* urlString = urls[i].spec().c_str();
- if (urlString && std::strlen(urlString)) {
- [entry setURL:[NSString stringWithCString:urlString
- encoding:NSUTF8StringEncoding]];
- [entries_ addObject:entry];
- }
- }
-}
-
-- (void)reloadURLs {
- [self willChangeValueForKey:@"customHomePages"];
- SessionStartupPref pref(SessionStartupPref::GetStartupPref(profile_));
- [self setURLsInternal:pref.urls];
- [self didChangeValueForKey:@"customHomePages"];
-}
-
-- (void)validateURLs {
- [self setURLs:[self URLs]];
-}
-
-- (void)setURLStringEmptyAt:(NSUInteger)index {
- // This replaces the data at |index| with an empty (invalid) URL string.
- CustomHomePageEntry* entry = [entries_ objectAtIndex:index];
- [entry setURL:[NSString stringWithString:@""]];
-}
-
-@end
-
-//---------------------------------------------------------------------------
-
-@implementation CustomHomePageEntry
-
-- (void)setURL:(NSString*)url {
- // |url| can be nil if the user cleared the text from the edit field.
- if (!url)
- url = [NSString stringWithString:@""];
-
- // Make sure the url is valid before setting it by fixing it up.
- std::string fixedUrl(URLFixerUpper::FixupURL(
- base::SysNSStringToUTF8(url), std::string()).possibly_invalid_spec());
- url_.reset([base::SysUTF8ToNSString(fixedUrl) retain]);
-
- // Broadcast that an individual item has changed.
- [[NSNotificationCenter defaultCenter]
- postNotificationName:kHomepageEntryChangedNotification object:nil];
-
- // TODO(pinkerton): fetch favicon, convert to NSImage http://crbug.com/34642
-}
-
-- (NSString*)URL {
- return url_.get();
-}
-
-- (void)setImage:(NSImage*)image {
- icon_.reset(image);
-}
-
-- (NSImage*)image {
- return icon_.get();
-}
-
-- (NSString*)description {
- return url_.get();
-}
-
-@end
diff --git a/chrome/browser/cocoa/custom_home_pages_model_unittest.mm b/chrome/browser/cocoa/custom_home_pages_model_unittest.mm
deleted file mode 100644
index 534f681..0000000
--- a/chrome/browser/cocoa/custom_home_pages_model_unittest.mm
+++ /dev/null
@@ -1,196 +0,0 @@
-// 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.
-
-#include "base/scoped_nsobject.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/custom_home_pages_model.h"
-#include "chrome/browser/prefs/session_startup_pref.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-// A helper for KVO and NSNotifications. Makes a note that it's been called
-// back.
-@interface CustomHomePageHelper : NSObject {
- @public
- BOOL sawNotification_;
-}
-@end
-
-@implementation CustomHomePageHelper
-- (void)observeValueForKeyPath:(NSString*)keyPath
- ofObject:(id)object
- change:(NSDictionary*)change
- context:(void*)context {
- sawNotification_ = YES;
-}
-
-- (void)entryChanged:(NSNotification*)notify {
- sawNotification_ = YES;
-}
-@end
-
-@interface NSObject ()
-- (void)setURL:(NSString*)url;
-@end
-
-namespace {
-
-// Helper that creates an autoreleased entry.
-CustomHomePageEntry* MakeEntry(NSString* url) {
- CustomHomePageEntry* entry = [[[CustomHomePageEntry alloc] init] autorelease];
- [entry setURL:url];
- return entry;
-}
-
-// Helper that casts from |id| to the Entry type and returns the URL string.
-NSString* EntryURL(id entry) {
- return [static_cast<CustomHomePageEntry*>(entry) URL];
-}
-
-class CustomHomePagesModelTest : public PlatformTest {
- public:
- CustomHomePagesModelTest() {
- model_.reset([[CustomHomePagesModel alloc]
- initWithProfile:helper_.profile()]);
- }
- ~CustomHomePagesModelTest() { }
-
- BrowserTestHelper helper_;
- scoped_nsobject<CustomHomePagesModel> model_;
-};
-
-TEST_F(CustomHomePagesModelTest, Init) {
- scoped_nsobject<CustomHomePagesModel> model(
- [[CustomHomePagesModel alloc] initWithProfile:helper_.profile()]);
-}
-
-TEST_F(CustomHomePagesModelTest, GetSetURLs) {
- // Basic test.
- std::vector<GURL> urls;
- urls.push_back(GURL("http://www.google.com"));
- [model_ setURLs:urls];
- std::vector<GURL> received_urls = [model_.get() URLs];
- EXPECT_EQ(received_urls.size(), 1U);
- EXPECT_TRUE(urls[0] == received_urls[0]);
-
- // Set an empty list, make sure we get back an empty list.
- std::vector<GURL> empty;
- [model_ setURLs:empty];
- received_urls = [model_.get() URLs];
- EXPECT_EQ(received_urls.size(), 0U);
-
- // Give it a list with not well-formed URLs and make sure we get back.
- // only the good ones.
- std::vector<GURL> poorly_formed;
- poorly_formed.push_back(GURL("http://www.google.com")); // good
- poorly_formed.push_back(GURL("www.google.com")); // bad
- poorly_formed.push_back(GURL("www.yahoo.")); // bad
- poorly_formed.push_back(GURL("http://www.yahoo.com")); // good
- [model_ setURLs:poorly_formed];
- received_urls = [model_.get() URLs];
- EXPECT_EQ(received_urls.size(), 2U);
-}
-
-// Test that we get a KVO notification when called setURLs.
-TEST_F(CustomHomePagesModelTest, KVOObserveWhenListChanges) {
- scoped_nsobject<CustomHomePageHelper> kvo_helper(
- [[CustomHomePageHelper alloc] init]);
- [model_ addObserver:kvo_helper
- forKeyPath:@"customHomePages"
- options:0L
- context:NULL];
- EXPECT_FALSE(kvo_helper.get()->sawNotification_);
-
- std::vector<GURL> urls;
- urls.push_back(GURL("http://www.google.com"));
- [model_ setURLs:urls]; // Should send kvo change notification.
- EXPECT_TRUE(kvo_helper.get()->sawNotification_);
-
- [model_ removeObserver:kvo_helper forKeyPath:@"customHomePages"];
-}
-
-// Test the KVO "to-many" bindings for |customHomePages| and the KVO
-// notifiation when items are added to and removed from the list.
-TEST_F(CustomHomePagesModelTest, KVO) {
- EXPECT_EQ([model_ countOfCustomHomePages], 0U);
-
- scoped_nsobject<CustomHomePageHelper> kvo_helper(
- [[CustomHomePageHelper alloc] init]);
- [model_ addObserver:kvo_helper
- forKeyPath:@"customHomePages"
- options:0L
- context:NULL];
- EXPECT_FALSE(kvo_helper.get()->sawNotification_);
-
- // Cheat and insert NSString objects into the array. As long as we don't
- // call -URLs, we'll be ok.
- [model_ insertObject:MakeEntry(@"www.google.com") inCustomHomePagesAtIndex:0];
- EXPECT_TRUE(kvo_helper.get()->sawNotification_);
- [model_ insertObject:MakeEntry(@"www.yahoo.com") inCustomHomePagesAtIndex:1];
- [model_ insertObject:MakeEntry(@"dev.chromium.org")
- inCustomHomePagesAtIndex:2];
- EXPECT_EQ([model_ countOfCustomHomePages], 3U);
-
- EXPECT_NSEQ(@"http://www.yahoo.com/",
- EntryURL([model_ objectInCustomHomePagesAtIndex:1]));
-
- kvo_helper.get()->sawNotification_ = NO;
- [model_ removeObjectFromCustomHomePagesAtIndex:1];
- EXPECT_TRUE(kvo_helper.get()->sawNotification_);
- EXPECT_EQ([model_ countOfCustomHomePages], 2U);
- EXPECT_NSEQ(@"http://dev.chromium.org/",
- EntryURL([model_ objectInCustomHomePagesAtIndex:1]));
- EXPECT_NSEQ(@"http://www.google.com/",
- EntryURL([model_ objectInCustomHomePagesAtIndex:0]));
-
- [model_ removeObserver:kvo_helper forKeyPath:@"customHomePages"];
-}
-
-// Test that when individual items are changed that they broadcast a message.
-TEST_F(CustomHomePagesModelTest, ModelChangedNotification) {
- scoped_nsobject<CustomHomePageHelper> kvo_helper(
- [[CustomHomePageHelper alloc] init]);
- [[NSNotificationCenter defaultCenter]
- addObserver:kvo_helper
- selector:@selector(entryChanged:)
- name:kHomepageEntryChangedNotification
- object:nil];
-
- std::vector<GURL> urls;
- urls.push_back(GURL("http://www.google.com"));
- [model_ setURLs:urls];
- NSObject* entry = [model_ objectInCustomHomePagesAtIndex:0];
- [entry setURL:@"http://www.foo.bar"];
- EXPECT_TRUE(kvo_helper.get()->sawNotification_);
- [[NSNotificationCenter defaultCenter] removeObserver:kvo_helper];
-}
-
-TEST_F(CustomHomePagesModelTest, ReloadURLs) {
- scoped_nsobject<CustomHomePageHelper> kvo_helper(
- [[CustomHomePageHelper alloc] init]);
- [model_ addObserver:kvo_helper
- forKeyPath:@"customHomePages"
- options:0L
- context:NULL];
- EXPECT_FALSE(kvo_helper.get()->sawNotification_);
- EXPECT_EQ([model_ countOfCustomHomePages], 0U);
-
- std::vector<GURL> urls;
- urls.push_back(GURL("http://www.google.com"));
- SessionStartupPref pref;
- pref.urls = urls;
- SessionStartupPref::SetStartupPref(helper_.profile(), pref);
-
- [model_ reloadURLs];
-
- EXPECT_TRUE(kvo_helper.get()->sawNotification_);
- EXPECT_EQ([model_ countOfCustomHomePages], 1U);
- EXPECT_NSEQ(@"http://www.google.com/",
- EntryURL([model_ objectInCustomHomePagesAtIndex:0]));
-
- [model_ removeObserver:kvo_helper.get() forKeyPath:@"customHomePages"];
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/delayedmenu_button.h b/chrome/browser/cocoa/delayedmenu_button.h
deleted file mode 100644
index f626f71..0000000
--- a/chrome/browser/cocoa/delayedmenu_button.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_DELAYEDMENU_BUTTON_H_
-#define CHROME_BROWSER_COCOA_DELAYEDMENU_BUTTON_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_nsobject.h"
-
-@interface DelayedMenuButton : NSButton {
- NSMenu* attachedMenu_; // Strong (retained).
- BOOL attachedMenuEnabled_;
- scoped_nsobject<NSPopUpButtonCell> popUpCell_;
-}
-
-// The menu to display. Note that it should have no (i.e., a blank) title and
-// that the 0-th entry should be blank (and won't be displayed). (This is
-// because we use a pulldown list, for which Cocoa uses the 0-th item as "title"
-// in the button. This might change if we ever switch to a pop-up. Our direct
-// use of the given NSMenu object means that the one can set and use NSMenu's
-// delegate as usual.)
-@property(retain, nonatomic) NSMenu* attachedMenu;
-
-// Is the menu enabled? (If not, don't act like a click-hold button.)
-@property(assign, nonatomic) BOOL attachedMenuEnabled;
-
-@end // @interface DelayedMenuButton
-
-#endif // CHROME_BROWSER_COCOA_DELAYEDMENU_BUTTON_H_
diff --git a/chrome/browser/cocoa/delayedmenu_button.mm b/chrome/browser/cocoa/delayedmenu_button.mm
deleted file mode 100644
index dbbde4a..0000000
--- a/chrome/browser/cocoa/delayedmenu_button.mm
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/delayedmenu_button.h"
-
-#include "base/logging.h"
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/clickhold_button_cell.h"
-
-@interface DelayedMenuButton (Private)
-
-- (void)setupCell;
-- (void)attachedMenuAction:(id)sender;
-
-@end // @interface DelayedMenuButton (Private)
-
-@implementation DelayedMenuButton
-
-// Overrides:
-
-+ (Class)cellClass {
- return [ClickHoldButtonCell class];
-}
-
-- (id)init {
- if ((self = [super init]))
- [self setupCell];
- return self;
-}
-
-- (id)initWithCoder:(NSCoder*)decoder {
- if ((self = [super initWithCoder:decoder]))
- [self setupCell];
- return self;
-}
-
-- (id)initWithFrame:(NSRect)frameRect {
- if ((self = [super initWithFrame:frameRect]))
- [self setupCell];
- return self;
-}
-
-- (void)dealloc {
- [attachedMenu_ release];
- [super dealloc];
-}
-
-- (void)awakeFromNib {
- [self setupCell];
-}
-
-- (void)setCell:(NSCell*)cell {
- [super setCell:cell];
- [self setupCell];
-}
-
-// Accessors and mutators:
-
-@synthesize attachedMenu = attachedMenu_;
-
-// Don't synthesize for attachedMenuEnabled_; its mutator must do other things.
-- (void)setAttachedMenuEnabled:(BOOL)enabled {
- attachedMenuEnabled_ = enabled;
- [[self cell] setEnableClickHold:attachedMenuEnabled_];
-}
-
-- (BOOL)attachedMenuEnabled {
- return attachedMenuEnabled_;
-}
-
-@end // @implementation DelayedMenuButton
-
-@implementation DelayedMenuButton (Private)
-
-// Set up the button's cell if we've reached a point where it's been set.
-- (void)setupCell {
- ClickHoldButtonCell* cell = [self cell];
- if (cell) {
- DCHECK([cell isKindOfClass:[ClickHoldButtonCell class]]);
- [self setEnabled:NO]; // Make the controller put in a menu and
- // enable it explicitly. This also takes
- // care of |[cell setEnableClickHold:]|.
- [cell setClickHoldAction:@selector(attachedMenuAction:)];
- [cell setClickHoldTarget:self];
- }
-}
-
-// Display the menu.
-- (void)attachedMenuAction:(id)sender {
- // We shouldn't get here unless the menu is enabled.
- DCHECK(attachedMenuEnabled_);
-
- // If we don't have a menu (in which case the person using this control is
- // being bad), just wait for a mouse up.
- if (!attachedMenu_) {
- LOG(WARNING) << "No menu available.";
- [NSApp nextEventMatchingMask:NSLeftMouseUpMask
- untilDate:[NSDate distantFuture]
- inMode:NSEventTrackingRunLoopMode
- dequeue:YES];
- return;
- }
-
- // TODO(viettrungluu): We have some fudge factors below to make things line up
- // (approximately). I wish I knew how to get rid of them. (Note that our view
- // is flipped, and that frame should be in our coordinates.) The y/height is
- // very odd, since it doesn't seem to respond to changes the way that it
- // should. I don't understand it.
- NSRect frame = [self convertRect:[self frame]
- fromView:[self superview]];
- frame.origin.x -= 2.0;
- frame.size.height += 10.0;
-
- // Make our pop-up button cell and set things up. This is, as of 10.5, the
- // official Apple-recommended hack. Later, perhaps |-[NSMenu
- // popUpMenuPositioningItem:atLocation:inView:]| may be a better option.
- // However, using a pulldown has the benefit that Cocoa automatically places
- // the menu correctly even when we're at the edge of the screen (including
- // "dragging upwards" when the button is close to the bottom of the screen).
- // A |scoped_nsobject| local variable cannot be used here because
- // Accessibility on 10.5 grabs the NSPopUpButtonCell without retaining it, and
- // uses it later. (This is fixed in 10.6.)
- if (!popUpCell_.get()) {
- popUpCell_.reset([[NSPopUpButtonCell alloc] initTextCell:@""
- pullsDown:YES]);
- }
- DCHECK(popUpCell_.get());
- [popUpCell_ setMenu:attachedMenu_];
- [popUpCell_ selectItem:nil];
- [popUpCell_ attachPopUpWithFrame:frame
- inView:self];
- [popUpCell_ performClickWithFrame:frame
- inView:self];
-}
-
-@end // @implementation DelayedMenuButton (Private)
diff --git a/chrome/browser/cocoa/delayedmenu_button_unittest.mm b/chrome/browser/cocoa/delayedmenu_button_unittest.mm
deleted file mode 100644
index 10f54a1..0000000
--- a/chrome/browser/cocoa/delayedmenu_button_unittest.mm
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (c) 2009 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 "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/clickhold_button_cell.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/delayedmenu_button.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-namespace {
-
-class DelayedMenuButtonTest : public CocoaTest {
- public:
- DelayedMenuButtonTest() {
- NSRect frame = NSMakeRect(0, 0, 50, 30);
- scoped_nsobject<DelayedMenuButton>button([[DelayedMenuButton alloc]
- initWithFrame:frame]);
- button_ = button.get();
- scoped_nsobject<ClickHoldButtonCell> cell(
- [[ClickHoldButtonCell alloc] initTextCell:@"Testing"]);
- [button_ setCell:cell.get()];
- [[test_window() contentView] addSubview:button_];
- }
-
- DelayedMenuButton* button_;
-};
-
-TEST_VIEW(DelayedMenuButtonTest, button_)
-
-// Test assigning and enabling a menu, again mostly to ensure nothing leaks or
-// crashes.
-TEST_F(DelayedMenuButtonTest, MenuAssign) {
- scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@""]);
- ASSERT_TRUE(menu.get());
-
- [menu insertItemWithTitle:@"" action:nil keyEquivalent:@"" atIndex:0];
- [menu insertItemWithTitle:@"foo" action:nil keyEquivalent:@"" atIndex:1];
- [menu insertItemWithTitle:@"bar" action:nil keyEquivalent:@"" atIndex:2];
- [menu insertItemWithTitle:@"baz" action:nil keyEquivalent:@"" atIndex:3];
-
- [button_ setAttachedMenu:menu];
- EXPECT_TRUE([button_ attachedMenu]);
-
- [button_ setAttachedMenuEnabled:YES];
- EXPECT_TRUE([button_ attachedMenuEnabled]);
-
- // TODO(viettrungluu): Display the menu. (Calling DelayedMenuButton's private
- // |-attachedMenuAction:| method displays it fine, but the problem is
- // getting rid of the menu. We can catch the
- // |NSMenuDidBeginTrackingNotification| from |menu| fine, but then
- // |-cancelTracking| doesn't dismiss it. I don't know why.)
-}
-
-// TODO(viettrungluu): Test the two actions of the button (the normal one and
-// displaying the menu, also making sure the latter drags correctly)? It would
-// require "emulating" a mouse....
-
-} // namespace
diff --git a/chrome/browser/cocoa/dev_tools_controller.h b/chrome/browser/cocoa/dev_tools_controller.h
deleted file mode 100644
index 05aaca4..0000000
--- a/chrome/browser/cocoa/dev_tools_controller.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_DEV_TOOLS_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_DEV_TOOLS_CONTROLLER_H_
-#pragma once
-
-#import <Foundation/Foundation.h>
-
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/tab_contents_controller.h"
-
-@class NSSplitView;
-@class NSView;
-
-class TabContents;
-
-// A class that handles updates of the devTools view within a browser window.
-// It swaps in the relevant devTools contents for a given TabContents or removes
-// the vew, if there's no devTools contents to show.
-@interface DevToolsController : NSObject {
- @private
- // A view hosting docked devTools contents.
- scoped_nsobject<NSSplitView> splitView_;
-
- // Manages currently displayed devTools contents.
- scoped_nsobject<TabContentsController> contentsController_;
-}
-
-- (id)initWithDelegate:(id<TabContentsControllerDelegate>)delegate;
-
-// This controller's view.
-- (NSView*)view;
-
-// The compiler seems to have trouble handling a function named "view" that
-// returns an NSSplitView, so provide a differently-named method.
-- (NSSplitView*)splitView;
-
-// Depending on |contents|'s state, decides whether the docked web inspector
-// should be shown or hidden and adjusts its height (|delegate_| handles
-// the actual resize).
-- (void)updateDevToolsForTabContents:(TabContents*)contents;
-
-// Call when the devTools view is properly sized and the render widget host view
-// should be put into the view hierarchy.
-- (void)ensureContentsVisible;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_DEV_TOOLS_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/dev_tools_controller.mm b/chrome/browser/cocoa/dev_tools_controller.mm
deleted file mode 100644
index 1e1e8f4..0000000
--- a/chrome/browser/cocoa/dev_tools_controller.mm
+++ /dev/null
@@ -1,164 +0,0 @@
-// 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 "chrome/browser/cocoa/dev_tools_controller.h"
-
-#include <algorithm>
-
-#include <Cocoa/Cocoa.h>
-
-#include "chrome/browser/browser_process.h"
-#import "chrome/browser/cocoa/view_id_util.h"
-#include "chrome/browser/debugger/devtools_window.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/common/pref_names.h"
-
-namespace {
-
-// Default offset of the contents splitter in pixels.
-const int kDefaultContentsSplitOffset = 400;
-
-// Never make the web part of the tab contents smaller than this (needed if the
-// window is only a few pixels high).
-const int kMinWebHeight = 50;
-
-} // end namespace
-
-
-@interface DevToolsController (Private)
-- (void)showDevToolsContents:(TabContents*)devToolsContents;
-- (void)resizeDevToolsToNewHeight:(CGFloat)height;
-@end
-
-
-@implementation DevToolsController
-
-- (id)initWithDelegate:(id<TabContentsControllerDelegate>)delegate {
- if ((self = [super init])) {
- splitView_.reset([[NSSplitView alloc] initWithFrame:NSZeroRect]);
- [splitView_ setDividerStyle:NSSplitViewDividerStyleThin];
- [splitView_ setVertical:NO];
- [splitView_ setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
- [splitView_ setDelegate:self];
-
- contentsController_.reset(
- [[TabContentsController alloc] initWithContents:NULL
- delegate:delegate]);
- }
- return self;
-}
-
-- (void)dealloc {
- [splitView_ setDelegate:nil];
- [super dealloc];
-}
-
-- (NSView*)view {
- return splitView_.get();
-}
-
-- (NSSplitView*)splitView {
- return splitView_.get();
-}
-
-- (void)updateDevToolsForTabContents:(TabContents*)contents {
- // Get current devtools content.
- TabContents* devToolsContents = contents ?
- DevToolsWindow::GetDevToolsContents(contents) : NULL;
-
- [self showDevToolsContents:devToolsContents];
-}
-
-- (void)ensureContentsVisible {
- [contentsController_ ensureContentsVisible];
-}
-
-- (void)showDevToolsContents:(TabContents*)devToolsContents {
- [contentsController_ ensureContentsSizeDoesNotChange];
-
- NSArray* subviews = [splitView_ subviews];
- if (devToolsContents) {
- DCHECK_GE([subviews count], 1u);
-
- // |devToolsView| is a TabContentsViewCocoa object, whose ViewID was
- // set to VIEW_ID_TAB_CONTAINER initially, so we need to change it to
- // VIEW_ID_DEV_TOOLS_DOCKED here.
- view_id_util::SetID(
- devToolsContents->GetNativeView(), VIEW_ID_DEV_TOOLS_DOCKED);
-
- CGFloat splitOffset = 0;
- if ([subviews count] == 1) {
- // Load the default split offset.
- splitOffset = g_browser_process->local_state()->GetInteger(
- prefs::kDevToolsSplitLocation);
- if (splitOffset < 0) {
- // Initial load, set to default value.
- splitOffset = kDefaultContentsSplitOffset;
- }
- [splitView_ addSubview:[contentsController_ view]];
- } else {
- DCHECK_EQ([subviews count], 2u);
- // If devtools are already visible, keep the current size.
- splitOffset = NSHeight([[subviews objectAtIndex:1] frame]);
- }
-
- // Make sure |splitOffset| isn't too large or too small.
- splitOffset = std::max(static_cast<CGFloat>(kMinWebHeight), splitOffset);
- splitOffset =
- std::min(splitOffset, NSHeight([splitView_ frame]) - kMinWebHeight);
- DCHECK_GE(splitOffset, 0) << "kMinWebHeight needs to be smaller than "
- << "smallest available tab contents space.";
-
- [self resizeDevToolsToNewHeight:splitOffset];
- } else {
- if ([subviews count] > 1) {
- NSView* oldDevToolsContentsView = [subviews objectAtIndex:1];
- // Store split offset when hiding devtools window only.
- int splitOffset = NSHeight([oldDevToolsContentsView frame]);
- g_browser_process->local_state()->SetInteger(
- prefs::kDevToolsSplitLocation, splitOffset);
- [oldDevToolsContentsView removeFromSuperview];
- [splitView_ adjustSubviews];
- }
- }
-
- [contentsController_ changeTabContents:devToolsContents];
-}
-
-- (void)resizeDevToolsToNewHeight:(CGFloat)height {
- NSArray* subviews = [splitView_ subviews];
-
- // It seems as if |-setPosition:ofDividerAtIndex:| should do what's needed,
- // but I can't figure out how to use it. Manually resize web and devtools.
- // TODO(alekseys): either make setPosition:ofDividerAtIndex: work or to add a
- // category on NSSplitView to handle manual resizing.
- NSView* devToolsView = [subviews objectAtIndex:1];
- NSRect devToolsFrame = [devToolsView frame];
- devToolsFrame.size.height = height;
- [devToolsView setFrame:devToolsFrame];
-
- NSView* webView = [subviews objectAtIndex:0];
- NSRect webFrame = [webView frame];
- webFrame.size.height =
- NSHeight([splitView_ frame]) - ([splitView_ dividerThickness] + height);
- [webView setFrame:webFrame];
-
- [splitView_ adjustSubviews];
-}
-
-// NSSplitViewDelegate protocol.
-- (BOOL)splitView:(NSSplitView *)splitView
- shouldAdjustSizeOfSubview:(NSView *)subview {
- // Return NO for the devTools view to indicate that it should not be resized
- // automatically. It preserves the height set by the user and also keeps
- // view height the same while changing tabs when one of the tabs shows infobar
- // and others are not.
- if ([[splitView_ subviews] indexOfObject:subview] == 1)
- return NO;
- return YES;
-}
-
-@end
diff --git a/chrome/browser/cocoa/dock_icon.mm b/chrome/browser/cocoa/dock_icon.mm
deleted file mode 100644
index 330b88a..0000000
--- a/chrome/browser/cocoa/dock_icon.mm
+++ /dev/null
@@ -1,224 +0,0 @@
-// 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 "chrome/browser/cocoa/dock_icon.h"
-
-#include "base/scoped_nsobject.h"
-
-// The fraction of the size of the dock icon that the badge is.
-static const float kBadgeFraction = 0.4f;
-
-// The indentation of the badge.
-static const float kBadgeIndent = 5.0f;
-
-// A view that draws our dock tile.
-@interface DockTileView : NSView {
- @private
- int downloads_;
- BOOL indeterminate_;
- float progress_;
-}
-
-// Indicates how many downloads are in progress.
-@property (nonatomic) int downloads;
-
-// Indicates whether the progress indicator should be in an indeterminate state
-// or not.
-@property (nonatomic) BOOL indeterminate;
-
-// Indicates the amount of progress made of the download. Ranges from [0..1].
-@property (nonatomic) float progress;
-
-@end
-
-@implementation DockTileView
-
-@synthesize downloads = downloads_;
-@synthesize indeterminate = indeterminate_;
-@synthesize progress = progress_;
-
-- (void)drawRect:(NSRect)dirtyRect {
- // Not -[NSApplication applicationIconImage]; that fails to return a pasted
- // custom icon.
- NSString* appPath = [[NSBundle mainBundle] bundlePath];
- NSImage* appIcon = [[NSWorkspace sharedWorkspace] iconForFile:appPath];
- [appIcon drawInRect:[self bounds]
- fromRect:NSZeroRect
- operation:NSCompositeSourceOver
- fraction:1.0];
-
- if (downloads_ == 0)
- return;
-
- NSRect badgeRect = [self bounds];
- badgeRect.size.height = (int)(kBadgeFraction * badgeRect.size.height);
- int newWidth = kBadgeFraction * badgeRect.size.width;
- badgeRect.origin.x = badgeRect.size.width - newWidth;
- badgeRect.size.width = newWidth;
-
- CGFloat badgeRadius = NSMidY(badgeRect);
-
- badgeRect.origin.x -= kBadgeIndent;
- badgeRect.origin.y += kBadgeIndent;
-
- NSPoint badgeCenter = NSMakePoint(NSMidX(badgeRect),
- NSMidY(badgeRect));
-
- // Background
- NSColor* backgroundColor = [NSColor colorWithCalibratedRed:0.85
- green:0.85
- blue:0.85
- alpha:1.0];
- NSColor* backgroundHighlight =
- [backgroundColor blendedColorWithFraction:0.85
- ofColor:[NSColor whiteColor]];
- scoped_nsobject<NSGradient> backgroundGradient(
- [[NSGradient alloc] initWithStartingColor:backgroundHighlight
- endingColor:backgroundColor]);
- NSBezierPath* badgeEdge = [NSBezierPath bezierPathWithOvalInRect:badgeRect];
- [NSGraphicsContext saveGraphicsState];
- [badgeEdge addClip];
- [backgroundGradient drawFromCenter:badgeCenter
- radius:0.0
- toCenter:badgeCenter
- radius:badgeRadius
- options:0];
- [NSGraphicsContext restoreGraphicsState];
-
- // Slice
- if (!indeterminate_) {
- NSColor* sliceColor = [NSColor colorWithCalibratedRed:0.45
- green:0.8
- blue:0.25
- alpha:1.0];
- NSColor* sliceHighlight =
- [sliceColor blendedColorWithFraction:0.4
- ofColor:[NSColor whiteColor]];
- scoped_nsobject<NSGradient> sliceGradient(
- [[NSGradient alloc] initWithStartingColor:sliceHighlight
- endingColor:sliceColor]);
- NSBezierPath* progressSlice;
- if (progress_ >= 1.0) {
- progressSlice = [NSBezierPath bezierPathWithOvalInRect:badgeRect];
- } else {
- CGFloat endAngle = 90.0 - 360.0 * progress_;
- if (endAngle < 0.0)
- endAngle += 360.0;
- progressSlice = [NSBezierPath bezierPath];
- [progressSlice moveToPoint:badgeCenter];
- [progressSlice appendBezierPathWithArcWithCenter:badgeCenter
- radius:badgeRadius
- startAngle:90.0
- endAngle:endAngle
- clockwise:YES];
- [progressSlice closePath];
- }
- [NSGraphicsContext saveGraphicsState];
- [progressSlice addClip];
- [sliceGradient drawFromCenter:badgeCenter
- radius:0.0
- toCenter:badgeCenter
- radius:badgeRadius
- options:0];
- [NSGraphicsContext restoreGraphicsState];
- }
-
- // Edge
- [NSGraphicsContext saveGraphicsState];
- [[NSColor whiteColor] set];
- scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
- [shadow.get() setShadowOffset:NSMakeSize(0, -2)];
- [shadow setShadowBlurRadius:2];
- [shadow set];
- [badgeEdge setLineWidth:2];
- [badgeEdge stroke];
- [NSGraphicsContext restoreGraphicsState];
-
- // Download count
- scoped_nsobject<NSNumberFormatter> formatter(
- [[NSNumberFormatter alloc] init]);
- NSString* countString =
- [formatter stringFromNumber:[NSNumber numberWithInt:downloads_]];
-
- scoped_nsobject<NSShadow> countShadow([[NSShadow alloc] init]);
- [countShadow setShadowBlurRadius:3.0];
- [countShadow.get() setShadowColor:[NSColor whiteColor]];
- [countShadow.get() setShadowOffset:NSMakeSize(0.0, 0.0)];
- NSMutableDictionary* countAttrsDict =
- [NSMutableDictionary dictionaryWithObjectsAndKeys:
- [NSColor blackColor], NSForegroundColorAttributeName,
- countShadow.get(), NSShadowAttributeName,
- nil];
- CGFloat countFontSize = badgeRadius;
- NSSize countSize = NSZeroSize;
- scoped_nsobject<NSAttributedString> countAttrString;
- while (1) {
- NSFont* countFont = [NSFont fontWithName:@"Helvetica-Bold"
- size:countFontSize];
- [countAttrsDict setObject:countFont forKey:NSFontAttributeName];
- countAttrString.reset(
- [[NSAttributedString alloc] initWithString:countString
- attributes:countAttrsDict]);
- countSize = [countAttrString size];
- if (countSize.width > badgeRadius * 1.5) {
- countFontSize -= 1.0;
- } else {
- break;
- }
- }
-
- NSPoint countOrigin = badgeCenter;
- countOrigin.x -= countSize.width / 2;
- countOrigin.y -= countSize.height / 2.2; // tweak; otherwise too low
-
- [countAttrString.get() drawAtPoint:countOrigin];
-}
-
-@end
-
-
-@implementation DockIcon
-
-+ (DockIcon*)sharedDockIcon {
- static DockIcon* icon;
- if (!icon) {
- NSDockTile* dockTile = [[NSApplication sharedApplication] dockTile];
-
- scoped_nsobject<DockTileView> dockTileView([[DockTileView alloc] init]);
- [dockTile setContentView:dockTileView];
-
- icon = [[DockIcon alloc] init];
- }
-
- return icon;
-}
-
-- (void)updateIcon {
- NSDockTile* dockTile = [[NSApplication sharedApplication] dockTile];
-
- [dockTile display];
-}
-
-- (void)setDownloads:(int)downloads {
- NSDockTile* dockTile = [[NSApplication sharedApplication] dockTile];
- DockTileView* dockTileView = (DockTileView*)([dockTile contentView]);
-
- [dockTileView setDownloads:downloads];
-}
-
-- (void)setIndeterminate:(BOOL)indeterminate {
- NSDockTile* dockTile = [[NSApplication sharedApplication] dockTile];
- DockTileView* dockTileView = (DockTileView*)([dockTile contentView]);
-
- [dockTileView setIndeterminate:indeterminate];
-}
-
-- (void)setProgress:(float)progress {
- NSDockTile* dockTile = [[NSApplication sharedApplication] dockTile];
- DockTileView* dockTileView = (DockTileView*)([dockTile contentView]);
-
- [dockTileView setProgress:progress];
-}
-
-@end
diff --git a/chrome/browser/cocoa/download/download_item_button.h b/chrome/browser/cocoa/download/download_item_button.h
deleted file mode 100644
index 2b38399..0000000
--- a/chrome/browser/cocoa/download/download_item_button.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// 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>
-
-#import "base/cocoa_protocols_mac.h"
-#include "base/file_path.h"
-#import "chrome/browser/cocoa/draggable_button.h"
-
-@class DownloadItemController;
-
-// A button that is a drag source for a file and that displays a context menu
-// instead of firing an action when clicked in a certain area.
-@interface DownloadItemButton : DraggableButton<NSMenuDelegate> {
- @private
- FilePath downloadPath_;
- DownloadItemController* controller_; // weak
-}
-
-@property(assign, nonatomic) FilePath download;
-@property(assign, nonatomic) DownloadItemController* controller;
-
-// Overridden from DraggableButton.
-- (void)beginDrag:(NSEvent*)event;
-
-@end
diff --git a/chrome/browser/cocoa/download/download_item_button.mm b/chrome/browser/cocoa/download/download_item_button.mm
deleted file mode 100644
index 34ba144..0000000
--- a/chrome/browser/cocoa/download/download_item_button.mm
+++ /dev/null
@@ -1,50 +0,0 @@
-// 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 "chrome/browser/cocoa/download/download_item_button.h"
-
-#include "base/logging.h"
-#include "base/sys_string_conversions.h"
-#import "chrome/browser/cocoa/download/download_item_cell.h"
-#import "chrome/browser/cocoa/download/download_item_controller.h"
-
-@implementation DownloadItemButton
-
-@synthesize download = downloadPath_;
-@synthesize controller = controller_;
-
-// Overridden from DraggableButton.
-- (void)beginDrag:(NSEvent*)event {
- if (!downloadPath_.empty()) {
- NSString* filename = base::SysUTF8ToNSString(downloadPath_.value());
- [self dragFile:filename fromRect:[self bounds] slideBack:YES event:event];
- }
-}
-
-// Override to show a context menu on mouse down if clicked over the context
-// menu area.
-- (void)mouseDown:(NSEvent*)event {
- DCHECK(controller_);
- // Override so that we can pop up a context menu on mouse down.
- NSCell* cell = [self cell];
- DCHECK([cell respondsToSelector:@selector(isMouseOverButtonPart)]);
- if ([reinterpret_cast<DownloadItemCell*>(cell) isMouseOverButtonPart]) {
- [super mouseDown:event];
- } else {
- // Hold a reference to our controller in case the download completes and we
- // represent a file that's auto-removed (e.g. a theme).
- scoped_nsobject<DownloadItemController> ref([controller_ retain]);
- [cell setHighlighted:YES];
- [[self menu] setDelegate:self];
- [NSMenu popUpContextMenu:[self menu]
- withEvent:[NSApp currentEvent]
- forView:self];
- }
-}
-
-- (void)menuDidClose:(NSMenu*)menu {
- [[self cell] setHighlighted:NO];
-}
-
-@end
diff --git a/chrome/browser/cocoa/download/download_item_button_unittest.mm b/chrome/browser/cocoa/download/download_item_button_unittest.mm
deleted file mode 100644
index a8610a0..0000000
--- a/chrome/browser/cocoa/download/download_item_button_unittest.mm
+++ /dev/null
@@ -1,21 +0,0 @@
-// 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.
-
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/download/download_item_button.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-// Make sure nothing leaks.
-TEST(DownloadItemButtonTest, Create) {
- scoped_nsobject<DownloadItemButton> button;
- button.reset([[DownloadItemButton alloc]
- initWithFrame:NSMakeRect(0,0,500,500)]);
-
- // Test setter
- FilePath path("foo");
- [button.get() setDownload:path];
- EXPECT_EQ(path.value(), [button.get() download].value());
-}
diff --git a/chrome/browser/cocoa/download/download_item_cell.h b/chrome/browser/cocoa/download/download_item_cell.h
deleted file mode 100644
index f97e1b8..0000000
--- a/chrome/browser/cocoa/download/download_item_cell.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_DOWNLOAD_DOWNLOAD_ITEM_CELL_H_
-#define CHROME_BROWSER_COCOA_DOWNLOAD_DOWNLOAD_ITEM_CELL_H_
-#pragma once
-
-#import "base/cocoa_protocols_mac.h"
-#include "base/scoped_ptr.h"
-#import "chrome/browser/cocoa/gradient_button_cell.h"
-
-#include "base/file_path.h"
-
-class BaseDownloadItemModel;
-
-// A button cell that implements the weird button/popup button hybrid that is
-// used by the download items.
-
-// The button represented by this cell consists of a button part on the left
-// and a dropdown-menu part on the right. This enum describes which part the
-// mouse cursor is over currently.
-enum DownloadItemMousePosition {
- kDownloadItemMouseOutside,
- kDownloadItemMouseOverButtonPart,
- kDownloadItemMouseOverDropdownPart
-};
-
-@interface DownloadItemCell : GradientButtonCell<NSAnimationDelegate> {
- @private
- // Track which part of the button the mouse is over
- DownloadItemMousePosition mousePosition_;
- int mouseInsideCount_;
- scoped_nsobject<NSTrackingArea> trackingAreaButton_;
- scoped_nsobject<NSTrackingArea> trackingAreaDropdown_;
-
- FilePath downloadPath_; // stored unelided
- NSString* secondaryTitle_;
- NSFont* secondaryFont_;
- int percentDone_;
- scoped_nsobject<NSAnimation> completionAnimation_;
-
- BOOL isStatusTextVisible_;
- CGFloat titleY_;
- CGFloat statusAlpha_;
- scoped_nsobject<NSAnimation> hideStatusAnimation_;
-
- scoped_ptr<ThemeProvider> themeProvider_;
-}
-
-- (void)setStateFromDownload:(BaseDownloadItemModel*)downloadModel;
-
-@property (nonatomic, copy) NSString* secondaryTitle;
-@property (nonatomic, retain) NSFont* secondaryFont;
-
-// Returns if the mouse is over the button part of the cell.
-- (BOOL)isMouseOverButtonPart;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_DOWNLOAD_DOWNLOAD_ITEM_CELL_H_
diff --git a/chrome/browser/cocoa/download/download_item_cell.mm b/chrome/browser/cocoa/download/download_item_cell.mm
deleted file mode 100644
index 2f5d856..0000000
--- a/chrome/browser/cocoa/download/download_item_cell.mm
+++ /dev/null
@@ -1,708 +0,0 @@
-// 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 "chrome/browser/cocoa/download/download_item_cell.h"
-
-#include "app/l10n_util.h"
-#include "app/text_elider.h"
-#include "base/mac_util.h"
-#include "base/sys_string_conversions.h"
-#import "chrome/browser/cocoa/download/download_item_cell.h"
-#import "chrome/browser/cocoa/image_utils.h"
-#import "chrome/browser/cocoa/themed_window.h"
-#include "chrome/browser/download/download_item.h"
-#include "chrome/browser/download/download_item_model.h"
-#include "chrome/browser/download/download_manager.h"
-#include "chrome/browser/download/download_util.h"
-#import "chrome/browser/themes/browser_theme_provider.h"
-#include "gfx/canvas_skia_paint.h"
-#include "grit/theme_resources.h"
-#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
-#import "third_party/GTM/AppKit/GTMNSColor+Luminance.h"
-
-namespace {
-
-// Distance from top border to icon
-const CGFloat kImagePaddingTop = 7;
-
-// Distance from left border to icon
-const CGFloat kImagePaddingLeft = 9;
-
-// Width of icon
-const CGFloat kImageWidth = 16;
-
-// Height of icon
-const CGFloat kImageHeight = 16;
-
-// x coordinate of download name string, in view coords
-const CGFloat kTextPosLeft = kImagePaddingLeft +
- kImageWidth + download_util::kSmallProgressIconOffset;
-
-// Distance from end of download name string to dropdown area
-const CGFloat kTextPaddingRight = 3;
-
-// y coordinate of download name string, in view coords, when status message
-// is visible
-const CGFloat kPrimaryTextPosTop = 3;
-
-// y coordinate of download name string, in view coords, when status message
-// is not visible
-const CGFloat kPrimaryTextOnlyPosTop = 10;
-
-// y coordinate of status message, in view coords
-const CGFloat kSecondaryTextPosTop = 18;
-
-// Grey value of status text
-const CGFloat kSecondaryTextColor = 0.5;
-
-// Width of dropdown area on the right (includes 1px for the border on each
-// side).
-const CGFloat kDropdownAreaWidth = 14;
-
-// Width of dropdown arrow
-const CGFloat kDropdownArrowWidth = 5;
-
-// Height of dropdown arrow
-const CGFloat kDropdownArrowHeight = 3;
-
-// Vertical displacement of dropdown area, relative to the "centered" position.
-const CGFloat kDropdownAreaY = -2;
-
-// Duration of the two-lines-to-one-line animation, in seconds
-NSTimeInterval kHideStatusDuration = 0.3;
-
-// Duration of the 'download complete' animation, in seconds
-const int kCompleteAnimationDuration = 2.5;
-
-}
-
-// This is a helper class to animate the fading out of the status text.
-@interface DownloadItemCellAnimation : NSAnimation {
- DownloadItemCell* cell_;
-}
-- (id)initWithDownloadItemCell:(DownloadItemCell*)cell
- duration:(NSTimeInterval)duration
- animationCurve:(NSAnimationCurve)animationCurve;
-@end
-
-class BackgroundTheme : public ThemeProvider {
-public:
- BackgroundTheme(ThemeProvider* provider);
-
- virtual void Init(Profile* profile) { }
- virtual SkBitmap* GetBitmapNamed(int id) const { return nil; }
- virtual SkColor GetColor(int id) const { return SkColor(); }
- virtual bool GetDisplayProperty(int id, int* result) const { return false; }
- virtual bool ShouldUseNativeFrame() const { return false; }
- virtual bool HasCustomImage(int id) const { return false; }
- virtual RefCountedMemory* GetRawData(int id) const { return NULL; }
- virtual NSImage* GetNSImageNamed(int id, bool allow_default) const;
- virtual NSColor* GetNSImageColorNamed(int id, bool allow_default) const;
- virtual NSColor* GetNSColor(int id, bool allow_default) const;
- virtual NSColor* GetNSColorTint(int id, bool allow_default) const;
- virtual NSGradient* GetNSGradient(int id) const;
-
-private:
- ThemeProvider* provider_;
- scoped_nsobject<NSGradient> buttonGradient_;
- scoped_nsobject<NSGradient> buttonPressedGradient_;
- scoped_nsobject<NSColor> borderColor_;
-};
-
-BackgroundTheme::BackgroundTheme(ThemeProvider* provider) :
- provider_(provider) {
- NSColor* bgColor = [NSColor colorWithCalibratedRed:241/255.0
- green:245/255.0
- blue:250/255.0
- alpha:77/255.0];
- NSColor* clickedColor = [NSColor colorWithCalibratedRed:239/255.0
- green:245/255.0
- blue:252/255.0
- alpha:51/255.0];
-
- borderColor_.reset(
- [[NSColor colorWithCalibratedWhite:0 alpha:36/255.0] retain]);
- buttonGradient_.reset([[NSGradient alloc]
- initWithColors:[NSArray arrayWithObject:bgColor]]);
- buttonPressedGradient_.reset([[NSGradient alloc]
- initWithColors:[NSArray arrayWithObject:clickedColor]]);
-}
-
-NSImage* BackgroundTheme::GetNSImageNamed(int id, bool allow_default) const {
- return nil;
-}
-
-NSColor* BackgroundTheme::GetNSImageColorNamed(int id,
- bool allow_default) const {
- return nil;
-}
-
-NSColor* BackgroundTheme::GetNSColor(int id, bool allow_default) const {
- return provider_->GetNSColor(id, allow_default);
-}
-
-NSColor* BackgroundTheme::GetNSColorTint(int id, bool allow_default) const {
- if (id == BrowserThemeProvider::TINT_BUTTONS)
- return borderColor_.get();
-
- return provider_->GetNSColorTint(id, allow_default);
-}
-
-NSGradient* BackgroundTheme::GetNSGradient(int id) const {
- switch (id) {
- case BrowserThemeProvider::GRADIENT_TOOLBAR_BUTTON:
- case BrowserThemeProvider::GRADIENT_TOOLBAR_BUTTON_INACTIVE:
- return buttonGradient_.get();
- case BrowserThemeProvider::GRADIENT_TOOLBAR_BUTTON_PRESSED:
- case BrowserThemeProvider::GRADIENT_TOOLBAR_BUTTON_PRESSED_INACTIVE:
- return buttonPressedGradient_.get();
- default:
- return provider_->GetNSGradient(id);
- }
-}
-
-@interface DownloadItemCell(Private)
-- (void)updateTrackingAreas:(id)sender;
-- (void)hideSecondaryTitle;
-- (void)animation:(NSAnimation*)animation
- progressed:(NSAnimationProgress)progress;
-- (NSString*)elideTitle:(int)availableWidth;
-- (NSString*)elideStatus:(int)availableWidth;
-- (ThemeProvider*)backgroundThemeWrappingProvider:(ThemeProvider*)provider;
-- (BOOL)pressedWithDefaultThemeOnPart:(DownloadItemMousePosition)part;
-- (NSColor*)titleColorForPart:(DownloadItemMousePosition)part;
-- (void)drawSecondaryTitleInRect:(NSRect)innerFrame;
-@end
-
-@implementation DownloadItemCell
-
-@synthesize secondaryTitle = secondaryTitle_;
-@synthesize secondaryFont = secondaryFont_;
-
-- (void)setInitialState {
- isStatusTextVisible_ = NO;
- titleY_ = kPrimaryTextPosTop;
- statusAlpha_ = 1.0;
-
- [self setFont:[NSFont systemFontOfSize:
- [NSFont systemFontSizeForControlSize:NSSmallControlSize]]];
- [self setSecondaryFont:[NSFont systemFontOfSize:
- [NSFont systemFontSizeForControlSize:NSSmallControlSize]]];
-
- [self updateTrackingAreas:self];
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(updateTrackingAreas:)
- name:NSViewFrameDidChangeNotification
- object:[self controlView]];
-}
-
-// For nib instantiations
-- (id)initWithCoder:(NSCoder*)decoder {
- if ((self = [super initWithCoder:decoder])) {
- [self setInitialState];
- }
- return self;
-}
-
-// For programmatic instantiations.
-- (id)initTextCell:(NSString *)string {
- if ((self = [super initTextCell:string])) {
- [self setInitialState];
- }
- return self;
-}
-
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- if ([completionAnimation_ isAnimating])
- [completionAnimation_ stopAnimation];
- if ([hideStatusAnimation_ isAnimating])
- [hideStatusAnimation_ stopAnimation];
- if (trackingAreaButton_) {
- [[self controlView] removeTrackingArea:trackingAreaButton_];
- trackingAreaButton_.reset();
- }
- if (trackingAreaDropdown_) {
- [[self controlView] removeTrackingArea:trackingAreaDropdown_];
- trackingAreaDropdown_.reset();
- }
- [secondaryTitle_ release];
- [secondaryFont_ release];
- [super dealloc];
-}
-
-- (void)setStateFromDownload:(BaseDownloadItemModel*)downloadModel {
- // Set the name of the download.
- downloadPath_ = downloadModel->download()->GetFileNameToReportUser();
-
- std::wstring statusText = downloadModel->GetStatusText();
- if (statusText.empty()) {
- // Remove the status text label.
- [self hideSecondaryTitle];
- isStatusTextVisible_ = NO;
- } else {
- // Set status text.
- NSString* statusString = base::SysWideToNSString(statusText);
- [self setSecondaryTitle:statusString];
- isStatusTextVisible_ = YES;
- }
-
- switch (downloadModel->download()->state()) {
- case DownloadItem::COMPLETE:
- // Small downloads may start in a complete state due to asynchronous
- // notifications. In this case, we'll get a second complete notification
- // via the observers, so we ignore it and avoid creating a second complete
- // animation.
- if (completionAnimation_.get())
- break;
- completionAnimation_.reset([[DownloadItemCellAnimation alloc]
- initWithDownloadItemCell:self
- duration:kCompleteAnimationDuration
- animationCurve:NSAnimationLinear]);
- [completionAnimation_.get() setDelegate:self];
- [completionAnimation_.get() startAnimation];
- percentDone_ = -1;
- break;
- case DownloadItem::CANCELLED:
- percentDone_ = -1;
- break;
- case DownloadItem::IN_PROGRESS:
- percentDone_ = downloadModel->download()->is_paused() ?
- -1 : downloadModel->download()->PercentComplete();
- break;
- default:
- NOTREACHED();
- }
-
- [[self controlView] setNeedsDisplay:YES];
-}
-
-- (void)updateTrackingAreas:(id)sender {
- if (trackingAreaButton_) {
- [[self controlView] removeTrackingArea:trackingAreaButton_.get()];
- trackingAreaButton_.reset(nil);
- }
- if (trackingAreaDropdown_) {
- [[self controlView] removeTrackingArea:trackingAreaDropdown_.get()];
- trackingAreaDropdown_.reset(nil);
- }
-
- // Use two distinct tracking rects for left and right parts.
- // The tracking areas are also used to decide how to handle clicks. They must
- // always be active, so the click is handled correctly when a download item
- // is clicked while chrome is not the active app ( http://crbug.com/21916 ).
- NSRect bounds = [[self controlView] bounds];
- NSRect buttonRect, dropdownRect;
- NSDivideRect(bounds, &dropdownRect, &buttonRect,
- kDropdownAreaWidth, NSMaxXEdge);
-
- trackingAreaButton_.reset([[NSTrackingArea alloc]
- initWithRect:buttonRect
- options:(NSTrackingMouseEnteredAndExited |
- NSTrackingActiveAlways)
- owner:self
- userInfo:nil]);
- [[self controlView] addTrackingArea:trackingAreaButton_.get()];
-
- trackingAreaDropdown_.reset([[NSTrackingArea alloc]
- initWithRect:dropdownRect
- options:(NSTrackingMouseEnteredAndExited |
- NSTrackingActiveAlways)
- owner:self
- userInfo:nil]);
- [[self controlView] addTrackingArea:trackingAreaDropdown_.get()];
-}
-
-- (void)setShowsBorderOnlyWhileMouseInside:(BOOL)showOnly {
- // Override to make sure it doesn't do anything if it's called accidentally.
-}
-
-- (void)mouseEntered:(NSEvent*)theEvent {
- mouseInsideCount_++;
- if ([theEvent trackingArea] == trackingAreaButton_.get())
- mousePosition_ = kDownloadItemMouseOverButtonPart;
- else if ([theEvent trackingArea] == trackingAreaDropdown_.get())
- mousePosition_ = kDownloadItemMouseOverDropdownPart;
- [[self controlView] setNeedsDisplay:YES];
-}
-
-- (void)mouseExited:(NSEvent *)theEvent {
- mouseInsideCount_--;
- if (mouseInsideCount_ == 0)
- mousePosition_ = kDownloadItemMouseOutside;
- [[self controlView] setNeedsDisplay:YES];
-}
-
-- (BOOL)isMouseInside {
- return mousePosition_ != kDownloadItemMouseOutside;
-}
-
-- (BOOL)isMouseOverButtonPart {
- return mousePosition_ == kDownloadItemMouseOverButtonPart;
-}
-
-- (BOOL)isButtonPartPressed {
- return [self isHighlighted]
- && mousePosition_ == kDownloadItemMouseOverButtonPart;
-}
-
-- (BOOL)isMouseOverDropdownPart {
- return mousePosition_ == kDownloadItemMouseOverDropdownPart;
-}
-
-- (BOOL)isDropdownPartPressed {
- return [self isHighlighted]
- && mousePosition_ == kDownloadItemMouseOverDropdownPart;
-}
-
-- (NSBezierPath*)leftRoundedPath:(CGFloat)radius inRect:(NSRect)rect {
-
- NSPoint topLeft = NSMakePoint(NSMinX(rect), NSMaxY(rect));
- NSPoint topRight = NSMakePoint(NSMaxX(rect), NSMaxY(rect));
- NSPoint bottomRight = NSMakePoint(NSMaxX(rect) , NSMinY(rect));
-
- NSBezierPath* path = [NSBezierPath bezierPath];
- [path moveToPoint:topRight];
- [path appendBezierPathWithArcFromPoint:topLeft
- toPoint:rect.origin
- radius:radius];
- [path appendBezierPathWithArcFromPoint:rect.origin
- toPoint:bottomRight
- radius:radius];
- [path lineToPoint:bottomRight];
- return path;
-}
-
-- (NSBezierPath*)rightRoundedPath:(CGFloat)radius inRect:(NSRect)rect {
-
- NSPoint topLeft = NSMakePoint(NSMinX(rect), NSMaxY(rect));
- NSPoint topRight = NSMakePoint(NSMaxX(rect), NSMaxY(rect));
- NSPoint bottomRight = NSMakePoint(NSMaxX(rect), NSMinY(rect));
-
- NSBezierPath* path = [NSBezierPath bezierPath];
- [path moveToPoint:rect.origin];
- [path appendBezierPathWithArcFromPoint:bottomRight
- toPoint:topRight
- radius:radius];
- [path appendBezierPathWithArcFromPoint:topRight
- toPoint:topLeft
- radius:radius];
- [path lineToPoint:topLeft];
- return path;
-}
-
-- (NSString*)elideTitle:(int)availableWidth {
- NSFont* font = [self font];
- gfx::Font font_chr(base::SysNSStringToWide([font fontName]),
- [font pointSize]);
-
- return base::SysUTF16ToNSString(
- ElideFilename(downloadPath_, font_chr, availableWidth));
-}
-
-- (NSString*)elideStatus:(int)availableWidth {
- NSFont* font = [self secondaryFont];
- gfx::Font font_chr(base::SysNSStringToWide([font fontName]),
- [font pointSize]);
-
- return base::SysUTF16ToNSString(ElideText(
- base::SysNSStringToUTF16([self secondaryTitle]),
- font_chr,
- availableWidth,
- false));
-}
-
-- (ThemeProvider*)backgroundThemeWrappingProvider:(ThemeProvider*)provider {
- if (!themeProvider_.get()) {
- themeProvider_.reset(new BackgroundTheme(provider));
- }
-
- return themeProvider_.get();
-}
-
-// Returns if |part| was pressed while the default theme was active.
-- (BOOL)pressedWithDefaultThemeOnPart:(DownloadItemMousePosition)part {
- ThemeProvider* themeProvider = [[[self controlView] window] themeProvider];
- bool isDefaultTheme =
- !themeProvider->HasCustomImage(IDR_THEME_BUTTON_BACKGROUND);
- return isDefaultTheme && [self isHighlighted] && mousePosition_ == part;
-}
-
-// Returns the text color that should be used to draw text on |part|.
-- (NSColor*)titleColorForPart:(DownloadItemMousePosition)part {
- ThemeProvider* themeProvider = [[[self controlView] window] themeProvider];
- NSColor* themeTextColor =
- themeProvider->GetNSColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT,
- true);
- return [self pressedWithDefaultThemeOnPart:part]
- ? [NSColor alternateSelectedControlTextColor] : themeTextColor;
-}
-
-- (void)drawSecondaryTitleInRect:(NSRect)innerFrame {
- if (![self secondaryTitle] || statusAlpha_ <= 0)
- return;
-
- CGFloat textWidth = innerFrame.size.width -
- (kTextPosLeft + kTextPaddingRight + kDropdownAreaWidth);
- NSString* secondaryText = [self elideStatus:textWidth];
- NSColor* secondaryColor =
- [self titleColorForPart:kDownloadItemMouseOverButtonPart];
-
- // If text is light-on-dark, lightening it alone will do nothing.
- // Therefore we mute luminance a wee bit before drawing in this case.
- if (![secondaryColor gtm_isDarkColor])
- secondaryColor = [secondaryColor gtm_colorByAdjustingLuminance:-0.2];
-
- NSDictionary* secondaryTextAttributes =
- [NSDictionary dictionaryWithObjectsAndKeys:
- secondaryColor, NSForegroundColorAttributeName,
- [self secondaryFont], NSFontAttributeName,
- nil];
- NSPoint secondaryPos =
- NSMakePoint(innerFrame.origin.x + kTextPosLeft, kSecondaryTextPosTop);
- [secondaryText drawAtPoint:secondaryPos
- withAttributes:secondaryTextAttributes];
-}
-
-- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
- // Constants from Cole. Will kConstant them once the feedback loop
- // is complete.
- NSRect drawFrame = NSInsetRect(cellFrame, 1.5, 1.5);
- NSRect innerFrame = NSInsetRect(cellFrame, 2, 2);
-
- const float radius = 5;
- NSWindow* window = [controlView window];
- BOOL active = [window isKeyWindow] || [window isMainWindow];
-
- // In the default theme, draw download items with the bookmark button
- // gradient. For some themes, this leads to unreadable text, so draw the item
- // with a background that looks like windows (some transparent white) if a
- // theme is used. Use custom theme object with a white color gradient to trick
- // the superclass into drawing what we want.
- ThemeProvider* themeProvider = [[[self controlView] window] themeProvider];
- bool isDefaultTheme =
- !themeProvider->HasCustomImage(IDR_THEME_BUTTON_BACKGROUND);
-
- NSGradient* bgGradient = nil;
- if (!isDefaultTheme) {
- themeProvider = [self backgroundThemeWrappingProvider:themeProvider];
- bgGradient = themeProvider->GetNSGradient(
- active ? BrowserThemeProvider::GRADIENT_TOOLBAR_BUTTON :
- BrowserThemeProvider::GRADIENT_TOOLBAR_BUTTON_INACTIVE);
- }
-
- NSRect buttonDrawRect, dropdownDrawRect;
- NSDivideRect(drawFrame, &dropdownDrawRect, &buttonDrawRect,
- kDropdownAreaWidth, NSMaxXEdge);
-
- NSBezierPath* buttonInnerPath = [self
- leftRoundedPath:radius inRect:buttonDrawRect];
- NSBezierPath* dropdownInnerPath = [self
- rightRoundedPath:radius inRect:dropdownDrawRect];
-
- // Draw secondary title, if any. Do this before drawing the (transparent)
- // fill so that the text becomes a bit lighter. The default theme's "pressed"
- // gradient is not transparent, so only do this if a theme is active.
- bool drawStatusOnTop =
- [self pressedWithDefaultThemeOnPart:kDownloadItemMouseOverButtonPart];
- if (!drawStatusOnTop)
- [self drawSecondaryTitleInRect:innerFrame];
-
- // Stroke the borders and appropriate fill gradient.
- [self drawBorderAndFillForTheme:themeProvider
- controlView:controlView
- innerPath:buttonInnerPath
- showClickedGradient:[self isButtonPartPressed]
- showHighlightGradient:[self isMouseOverButtonPart]
- hoverAlpha:0.0
- active:active
- cellFrame:cellFrame
- defaultGradient:bgGradient];
-
- [self drawBorderAndFillForTheme:themeProvider
- controlView:controlView
- innerPath:dropdownInnerPath
- showClickedGradient:[self isDropdownPartPressed]
- showHighlightGradient:[self isMouseOverDropdownPart]
- hoverAlpha:0.0
- active:active
- cellFrame:cellFrame
- defaultGradient:bgGradient];
-
- [self drawInteriorWithFrame:innerFrame inView:controlView];
-
- // For the default theme, draw the status text on top of the (opaque) button
- // gradient.
- if (drawStatusOnTop)
- [self drawSecondaryTitleInRect:innerFrame];
-}
-
-- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
- // Draw title
- CGFloat textWidth = cellFrame.size.width -
- (kTextPosLeft + kTextPaddingRight + kDropdownAreaWidth);
- [self setTitle:[self elideTitle:textWidth]];
-
- NSColor* color = [self titleColorForPart:kDownloadItemMouseOverButtonPart];
- NSString* primaryText = [self title];
-
- NSDictionary* primaryTextAttributes =
- [NSDictionary dictionaryWithObjectsAndKeys:
- color, NSForegroundColorAttributeName,
- [self font], NSFontAttributeName,
- nil];
- NSPoint primaryPos = NSMakePoint(
- cellFrame.origin.x + kTextPosLeft,
- titleY_);
-
- [primaryText drawAtPoint:primaryPos withAttributes:primaryTextAttributes];
-
- // Draw progress disk
- {
- // CanvasSkiaPaint draws its content to the current NSGraphicsContext in its
- // destructor, which needs to be invoked before the icon is drawn below -
- // hence this nested block.
-
- // Always repaint the whole disk.
- NSPoint imagePosition = [self imageRectForBounds:cellFrame].origin;
- int x = imagePosition.x - download_util::kSmallProgressIconOffset;
- int y = imagePosition.y - download_util::kSmallProgressIconOffset;
- NSRect dirtyRect = NSMakeRect(
- x, y,
- download_util::kSmallProgressIconSize,
- download_util::kSmallProgressIconSize);
-
- gfx::CanvasSkiaPaint canvas(dirtyRect, false);
- canvas.set_composite_alpha(true);
- if (completionAnimation_.get()) {
- if ([completionAnimation_ isAnimating]) {
- download_util::PaintDownloadComplete(&canvas,
- x, y,
- [completionAnimation_ currentValue],
- download_util::SMALL);
- }
- } else if (percentDone_ >= 0) {
- download_util::PaintDownloadProgress(&canvas,
- x, y,
- download_util::kStartAngleDegrees, // TODO(thakis): Animate
- percentDone_,
- download_util::SMALL);
- }
- }
-
- // Draw icon
- NSRect imageRect = NSZeroRect;
- imageRect.size = [[self image] size];
- [[self image] drawInRect:[self imageRectForBounds:cellFrame]
- fromRect:imageRect
- operation:NSCompositeSourceOver
- fraction:[self isEnabled] ? 1.0 : 0.5
- neverFlipped:YES];
-
- // Separator between button and popup parts
- CGFloat lx = NSMaxX(cellFrame) - kDropdownAreaWidth + 0.5;
- [[NSColor colorWithDeviceWhite:0.0 alpha:0.1] set];
- [NSBezierPath strokeLineFromPoint:NSMakePoint(lx, NSMinY(cellFrame) + 1)
- toPoint:NSMakePoint(lx, NSMaxY(cellFrame) - 1)];
- [[NSColor colorWithDeviceWhite:1.0 alpha:0.1] set];
- [NSBezierPath strokeLineFromPoint:NSMakePoint(lx + 1, NSMinY(cellFrame) + 1)
- toPoint:NSMakePoint(lx + 1, NSMaxY(cellFrame) - 1)];
-
- // Popup arrow. Put center of mass of the arrow in the center of the
- // dropdown area.
- CGFloat cx = NSMaxX(cellFrame) - kDropdownAreaWidth/2 + 0.5;
- CGFloat cy = NSMidY(cellFrame);
- NSPoint p1 = NSMakePoint(cx - kDropdownArrowWidth/2,
- cy - kDropdownArrowHeight/3 + kDropdownAreaY);
- NSPoint p2 = NSMakePoint(cx + kDropdownArrowWidth/2,
- cy - kDropdownArrowHeight/3 + kDropdownAreaY);
- NSPoint p3 = NSMakePoint(cx, cy + kDropdownArrowHeight*2/3 + kDropdownAreaY);
- NSBezierPath *triangle = [NSBezierPath bezierPath];
- [triangle moveToPoint:p1];
- [triangle lineToPoint:p2];
- [triangle lineToPoint:p3];
- [triangle closePath];
-
- NSGraphicsContext* context = [NSGraphicsContext currentContext];
- [context saveGraphicsState];
-
- scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
- [shadow.get() setShadowColor:[NSColor whiteColor]];
- [shadow.get() setShadowOffset:NSMakeSize(0, -1)];
- [shadow setShadowBlurRadius:0.0];
- [shadow set];
-
- NSColor* fill = [self titleColorForPart:kDownloadItemMouseOverDropdownPart];
- [fill setFill];
-
- [triangle fill];
-
- [context restoreGraphicsState];
-}
-
-- (NSRect)imageRectForBounds:(NSRect)cellFrame {
- return NSMakeRect(cellFrame.origin.x + kImagePaddingLeft,
- cellFrame.origin.y + kImagePaddingTop,
- kImageWidth,
- kImageHeight);
-}
-
-- (void)hideSecondaryTitle {
- if (isStatusTextVisible_) {
- // No core animation -- text in CA layers is not subpixel antialiased :-/
- hideStatusAnimation_.reset([[DownloadItemCellAnimation alloc]
- initWithDownloadItemCell:self
- duration:kHideStatusDuration
- animationCurve:NSAnimationEaseIn]);
- [hideStatusAnimation_.get() setDelegate:self];
- [hideStatusAnimation_.get() startAnimation];
- } else {
- // If the download is done so quickly that the status line is never visible,
- // don't show an animation
- [self animation:nil progressed:1.0];
- }
-}
-
-- (void)animation:(NSAnimation*)animation
- progressed:(NSAnimationProgress)progress {
- if (animation == hideStatusAnimation_ || animation == nil) {
- titleY_ = progress*kPrimaryTextOnlyPosTop +
- (1 - progress)*kPrimaryTextPosTop;
- statusAlpha_ = 1 - progress;
- [[self controlView] setNeedsDisplay:YES];
- } else if (animation == completionAnimation_) {
- [[self controlView] setNeedsDisplay:YES];
- }
-}
-
-- (void)animationDidEnd:(NSAnimation *)animation {
- if (animation == hideStatusAnimation_)
- hideStatusAnimation_.reset();
- else if (animation == completionAnimation_)
- completionAnimation_.reset();
-}
-
-@end
-
-@implementation DownloadItemCellAnimation
-
-- (id)initWithDownloadItemCell:(DownloadItemCell*)cell
- duration:(NSTimeInterval)duration
- animationCurve:(NSAnimationCurve)animationCurve {
- if ((self = [super gtm_initWithDuration:duration
- eventMask:NSLeftMouseDownMask
- animationCurve:animationCurve])) {
- cell_ = cell;
- [self setAnimationBlockingMode:NSAnimationNonblocking];
- }
- return self;
-}
-
-- (void)setCurrentProgress:(NSAnimationProgress)progress {
- [super setCurrentProgress:progress];
- [cell_ animation:self progressed:progress];
-}
-
-@end
diff --git a/chrome/browser/cocoa/download/download_item_controller.h b/chrome/browser/cocoa/download/download_item_controller.h
deleted file mode 100644
index dea7722..0000000
--- a/chrome/browser/cocoa/download/download_item_controller.h
+++ /dev/null
@@ -1,105 +0,0 @@
-// 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 "base/scoped_ptr.h"
-#include "base/time.h"
-
-class BaseDownloadItemModel;
-@class ChromeUILocalizer;
-@class DownloadItemCell;
-class DownloadItem;
-@class DownloadItemButton;
-class DownloadItemMac;
-class DownloadShelfContextMenuMac;
-@class DownloadShelfController;
-@class GTMWidthBasedTweaker;
-
-// A controller class that manages one download item.
-
-@interface DownloadItemController : NSViewController {
- @private
- IBOutlet DownloadItemButton* progressView_;
- IBOutlet DownloadItemCell* cell_;
-
- IBOutlet NSMenu* activeDownloadMenu_;
- IBOutlet NSMenu* completeDownloadMenu_;
-
- // This is shown instead of progressView_ for dangerous downloads.
- IBOutlet NSView* dangerousDownloadView_;
- IBOutlet NSTextField* dangerousDownloadLabel_;
- IBOutlet NSButton* dangerousDownloadConfirmButton_;
-
- // Needed to find out how much the tweaker changed sizes to update the
- // other views.
- IBOutlet GTMWidthBasedTweaker* buttonTweaker_;
-
- // Because the confirm text and button for dangerous downloads are determined
- // at runtime, an outlet to the localizer is needed to construct the layout
- // tweaker in awakeFromNib in order to adjust the UI after all strings are
- // determined.
- IBOutlet ChromeUILocalizer* localizer_;
-
- IBOutlet NSImageView* image_;
-
- scoped_ptr<DownloadItemMac> bridge_;
- scoped_ptr<DownloadShelfContextMenuMac> menuBridge_;
-
- // Weak pointer to the shelf that owns us.
- DownloadShelfController* shelf_;
-
- // The time at which this view was created.
- base::Time creationTime_;
-
- // The state of this item.
- enum DownoadItemState {
- kNormal,
- kDangerous
- } state_;
-};
-
-// Takes ownership of |downloadModel|.
-- (id)initWithModel:(BaseDownloadItemModel*)downloadModel
- shelf:(DownloadShelfController*)shelf;
-
-// Updates the UI and menu state from |downloadModel|.
-- (void)setStateFromDownload:(BaseDownloadItemModel*)downloadModel;
-
-// Remove ourself from the download UI.
-- (void)remove;
-
-// Update item's visibility depending on if the item is still completely
-// contained in its parent.
-- (void)updateVisibility:(id)sender;
-
-// Asynchronous icon loading callback.
-- (void)setIcon:(NSImage*)icon;
-
-// Download item button clicked
-- (IBAction)handleButtonClick:(id)sender;
-
-// Returns the size this item wants to have.
-- (NSSize)preferredSize;
-
-// Returns the DownloadItem model object belonging to this item.
-- (DownloadItem*)download;
-
-// Updates the tooltip with the download's path.
-- (void)updateToolTip;
-
-// Handling of dangerous downloads
-- (void)clearDangerousMode;
-- (BOOL)isDangerousMode;
-- (IBAction)saveDownload:(id)sender;
-- (IBAction)discardDownload:(id)sender;
-
-// Context menu handlers.
-- (IBAction)handleOpen:(id)sender;
-- (IBAction)handleAlwaysOpen:(id)sender;
-- (IBAction)handleReveal:(id)sender;
-- (IBAction)handleCancel:(id)sender;
-- (IBAction)handleTogglePause:(id)sender;
-
-@end
diff --git a/chrome/browser/cocoa/download/download_item_controller.mm b/chrome/browser/cocoa/download/download_item_controller.mm
deleted file mode 100644
index c210a3b..0000000
--- a/chrome/browser/cocoa/download/download_item_controller.mm
+++ /dev/null
@@ -1,398 +0,0 @@
-// 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 "chrome/browser/cocoa/download/download_item_controller.h"
-
-#include "app/l10n_util_mac.h"
-#include "app/resource_bundle.h"
-#include "app/text_elider.h"
-#include "base/mac_util.h"
-#include "base/metrics/histogram.h"
-#include "base/string16.h"
-#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#import "chrome/browser/cocoa/download/download_item_button.h"
-#import "chrome/browser/cocoa/download/download_item_cell.h"
-#include "chrome/browser/cocoa/download/download_item_mac.h"
-#import "chrome/browser/cocoa/download/download_shelf_controller.h"
-#import "chrome/browser/cocoa/themed_window.h"
-#import "chrome/browser/cocoa/ui_localizer.h"
-#include "chrome/browser/download/download_item.h"
-#include "chrome/browser/download/download_item_model.h"
-#include "chrome/browser/download/download_shelf.h"
-#include "chrome/browser/download/download_util.h"
-#import "chrome/browser/themes/browser_theme_provider.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-
-namespace {
-
-// NOTE: Mac currently doesn't use this like Windows does. Mac uses this to
-// control the min size on the dangerous download text. TVL sent a query off to
-// UX to fully spec all the the behaviors of download items and truncations
-// rules so all platforms can get inline in the future.
-const int kTextWidth = 140; // Pixels
-
-// The maximum number of characters we show in a file name when displaying the
-// dangerous download message.
-const int kFileNameMaxLength = 20;
-
-// The maximum width in pixels for the file name tooltip.
-const int kToolTipMaxWidth = 900;
-
-
-// Helper to widen a view.
-void WidenView(NSView* view, CGFloat widthChange) {
- // If it is an NSBox, the autoresize of the contentView is the issue.
- NSView* contentView = view;
- if ([view isKindOfClass:[NSBox class]]) {
- contentView = [(NSBox*)view contentView];
- }
- BOOL autoresizesSubviews = [contentView autoresizesSubviews];
- if (autoresizesSubviews) {
- [contentView setAutoresizesSubviews:NO];
- }
-
- NSRect frame = [view frame];
- frame.size.width += widthChange;
- [view setFrame:frame];
-
- if (autoresizesSubviews) {
- [contentView setAutoresizesSubviews:YES];
- }
-}
-
-} // namespace
-
-// A class for the chromium-side part of the download shelf context menu.
-
-class DownloadShelfContextMenuMac : public DownloadShelfContextMenu {
- public:
- DownloadShelfContextMenuMac(BaseDownloadItemModel* model)
- : DownloadShelfContextMenu(model) { }
-
- using DownloadShelfContextMenu::ExecuteCommand;
- using DownloadShelfContextMenu::IsCommandIdChecked;
- using DownloadShelfContextMenu::IsCommandIdEnabled;
-
- using DownloadShelfContextMenu::SHOW_IN_FOLDER;
- using DownloadShelfContextMenu::OPEN_WHEN_COMPLETE;
- using DownloadShelfContextMenu::ALWAYS_OPEN_TYPE;
- using DownloadShelfContextMenu::CANCEL;
- using DownloadShelfContextMenu::TOGGLE_PAUSE;
-};
-
-@interface DownloadItemController (Private)
-- (void)themeDidChangeNotification:(NSNotification*)aNotification;
-- (void)updateTheme:(ThemeProvider*)themeProvider;
-- (void)setState:(DownoadItemState)state;
-@end
-
-// Implementation of DownloadItemController
-
-@implementation DownloadItemController
-
-- (id)initWithModel:(BaseDownloadItemModel*)downloadModel
- shelf:(DownloadShelfController*)shelf {
- if ((self = [super initWithNibName:@"DownloadItem"
- bundle:mac_util::MainAppBundle()])) {
- // Must be called before [self view], so that bridge_ is set in awakeFromNib
- bridge_.reset(new DownloadItemMac(downloadModel, self));
- menuBridge_.reset(new DownloadShelfContextMenuMac(downloadModel));
-
- NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
- [defaultCenter addObserver:self
- selector:@selector(themeDidChangeNotification:)
- name:kBrowserThemeDidChangeNotification
- object:nil];
-
- shelf_ = shelf;
- state_ = kNormal;
- creationTime_ = base::Time::Now();
- }
- return self;
-}
-
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [progressView_ setController:nil];
- [[self view] removeFromSuperview];
- [super dealloc];
-}
-
-- (void)awakeFromNib {
- [progressView_ setController:self];
-
- [self setStateFromDownload:bridge_->download_model()];
-
- GTMUILocalizerAndLayoutTweaker* localizerAndLayoutTweaker =
- [[[GTMUILocalizerAndLayoutTweaker alloc] init] autorelease];
- [localizerAndLayoutTweaker applyLocalizer:localizer_ tweakingUI:[self view]];
-
- // The strings are based on the download item's name, sizing tweaks have to be
- // manually done.
- DCHECK(buttonTweaker_ != nil);
- CGFloat widthChange = [buttonTweaker_ changedWidth];
- // If it's a dangerous download, size the two lines so the text/filename
- // is always visible.
- if ([self isDangerousMode]) {
- widthChange +=
- [GTMUILocalizerAndLayoutTweaker
- sizeToFitFixedHeightTextField:dangerousDownloadLabel_
- minWidth:kTextWidth];
- }
- // Grow the parent views
- WidenView([self view], widthChange);
- WidenView(dangerousDownloadView_, widthChange);
- // Slide the two buttons over.
- NSPoint frameOrigin = [buttonTweaker_ frame].origin;
- frameOrigin.x += widthChange;
- [buttonTweaker_ setFrameOrigin:frameOrigin];
-
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- NSImage* alertIcon = rb.GetNativeImageNamed(IDR_WARNING);
- DCHECK(alertIcon);
- [image_ setImage:alertIcon];
-
- bridge_->LoadIcon();
- [self updateToolTip];
-}
-
-- (void)setStateFromDownload:(BaseDownloadItemModel*)downloadModel {
- DCHECK_EQ(bridge_->download_model(), downloadModel);
-
- // Handle dangerous downloads.
- if (downloadModel->download()->safety_state() == DownloadItem::DANGEROUS) {
- [self setState:kDangerous];
-
- NSString* dangerousWarning;
- NSString* confirmButtonTitle;
- // The dangerous download label and button text are different for an
- // extension file.
- if (downloadModel->download()->is_extension_install()) {
- dangerousWarning = l10n_util::GetNSStringWithFixup(
- IDS_PROMPT_DANGEROUS_DOWNLOAD_EXTENSION);
- confirmButtonTitle = l10n_util::GetNSStringWithFixup(
- IDS_CONTINUE_EXTENSION_DOWNLOAD);
- } else {
- // This basic fixup copies Windows DownloadItemView::DownloadItemView().
-
- // Extract the file extension (if any).
- FilePath filename(downloadModel->download()->target_name());
- FilePath::StringType extension = filename.Extension();
-
- // Remove leading '.' from the extension
- if (extension.length() > 0)
- extension = extension.substr(1);
-
- // Elide giant extensions.
- if (extension.length() > kFileNameMaxLength / 2) {
- std::wstring wide_extension;
- ElideString(UTF8ToWide(extension), kFileNameMaxLength / 2,
- &wide_extension);
- extension = WideToUTF8(wide_extension);
- }
-
- // Rebuild the filename.extension.
- std::wstring rootname = UTF8ToWide(filename.RemoveExtension().value());
- ElideString(rootname, kFileNameMaxLength - extension.length(), &rootname);
- std::string new_filename = WideToUTF8(rootname);
- if (extension.length())
- new_filename += std::string(".") + extension;
-
- dangerousWarning = l10n_util::GetNSStringFWithFixup(
- IDS_PROMPT_DANGEROUS_DOWNLOAD, UTF8ToUTF16(new_filename));
- confirmButtonTitle = l10n_util::GetNSStringWithFixup(IDS_SAVE_DOWNLOAD);
- }
- [dangerousDownloadLabel_ setStringValue:dangerousWarning];
- [dangerousDownloadConfirmButton_ setTitle:confirmButtonTitle];
- return;
- }
-
- // Set correct popup menu. Also, set draggable download on completion.
- if (downloadModel->download()->state() == DownloadItem::COMPLETE) {
- [progressView_ setMenu:completeDownloadMenu_];
- [progressView_ setDownload:downloadModel->download()->full_path()];
- } else {
- [progressView_ setMenu:activeDownloadMenu_];
- }
-
- [cell_ setStateFromDownload:downloadModel];
-}
-
-- (void)setIcon:(NSImage*)icon {
- [cell_ setImage:icon];
-}
-
-- (void)remove {
- // We are deleted after this!
- [shelf_ remove:self];
-}
-
-- (void)updateVisibility:(id)sender {
- if ([[self view] window])
- [self updateTheme:[[[self view] window] themeProvider]];
-
- // TODO(thakis): Make this prettier, by fading the items out or overlaying
- // the partial visible one with a horizontal alpha gradient -- crbug.com/17830
- NSView* view = [self view];
- NSRect containerFrame = [[view superview] frame];
- [view setHidden:(NSMaxX([view frame]) > NSWidth(containerFrame))];
-}
-
-- (IBAction)handleButtonClick:(id)sender {
- NSEvent* event = [NSApp currentEvent];
- if ([event modifierFlags] & NSCommandKeyMask) {
- // Let cmd-click show the file in Finder, like e.g. in Safari and Spotlight.
- menuBridge_->ExecuteCommand(DownloadShelfContextMenuMac::SHOW_IN_FOLDER);
- } else {
- DownloadItem* download = bridge_->download_model()->download();
- download->OpenDownload();
- }
-}
-
-- (NSSize)preferredSize {
- if (state_ == kNormal)
- return [progressView_ frame].size;
- DCHECK_EQ(kDangerous, state_);
- return [dangerousDownloadView_ frame].size;
-}
-
-- (DownloadItem*)download {
- return bridge_->download_model()->download();
-}
-
-- (void)updateToolTip {
- string16 elidedFilename = gfx::ElideFilename(
- [self download]->GetFileNameToReportUser(),
- gfx::Font(), kToolTipMaxWidth);
- [progressView_ setToolTip:base::SysUTF16ToNSString(elidedFilename)];
-}
-
-- (void)clearDangerousMode {
- [self setState:kNormal];
- // The state change hide the dangerouse download view and is now showing the
- // download progress view. This means the view is likely to be a different
- // size, so trigger a shelf layout to fix up spacing.
- [shelf_ layoutItems];
-}
-
-- (BOOL)isDangerousMode {
- return state_ == kDangerous;
-}
-
-- (void)setState:(DownoadItemState)state {
- if (state_ == state)
- return;
- state_ = state;
- if (state_ == kNormal) {
- [progressView_ setHidden:NO];
- [dangerousDownloadView_ setHidden:YES];
- } else {
- DCHECK_EQ(kDangerous, state_);
- [progressView_ setHidden:YES];
- [dangerousDownloadView_ setHidden:NO];
- }
- // NOTE: Do not relayout the shelf, as this could get called during initial
- // setup of the the item, so the localized text and sizing might not have
- // happened yet.
-}
-
-// Called after the current theme has changed.
-- (void)themeDidChangeNotification:(NSNotification*)aNotification {
- ThemeProvider* themeProvider =
- static_cast<ThemeProvider*>([[aNotification object] pointerValue]);
- [self updateTheme:themeProvider];
-}
-
-// Adapt appearance to the current theme. Called after theme changes and before
-// this is shown for the first time.
-- (void)updateTheme:(ThemeProvider*)themeProvider {
- NSColor* color =
- themeProvider->GetNSColor(BrowserThemeProvider::COLOR_TAB_TEXT, true);
- [dangerousDownloadLabel_ setTextColor:color];
-}
-
-- (IBAction)saveDownload:(id)sender {
- // The user has confirmed a dangerous download. We record how quickly the
- // user did this to detect whether we're being clickjacked.
- UMA_HISTOGRAM_LONG_TIMES("clickjacking.save_download",
- base::Time::Now() - creationTime_);
- // This will change the state and notify us.
- bridge_->download_model()->download()->DangerousDownloadValidated();
-}
-
-- (IBAction)discardDownload:(id)sender {
- UMA_HISTOGRAM_LONG_TIMES("clickjacking.discard_download",
- base::Time::Now() - creationTime_);
- if (bridge_->download_model()->download()->state() ==
- DownloadItem::IN_PROGRESS)
- bridge_->download_model()->download()->Cancel(true);
- bridge_->download_model()->download()->Remove(true);
- // WARNING: we are deleted at this point. Don't access 'this'.
-}
-
-
-// Sets the enabled and checked state of a particular menu item for this
-// download. We translate the NSMenuItem selection to menu selections understood
-// by the non platform specific download context menu.
-- (BOOL)validateMenuItem:(NSMenuItem *)item {
- SEL action = [item action];
-
- int actionId = 0;
- if (action == @selector(handleOpen:)) {
- actionId = DownloadShelfContextMenuMac::OPEN_WHEN_COMPLETE;
- } else if (action == @selector(handleAlwaysOpen:)) {
- actionId = DownloadShelfContextMenuMac::ALWAYS_OPEN_TYPE;
- } else if (action == @selector(handleReveal:)) {
- actionId = DownloadShelfContextMenuMac::SHOW_IN_FOLDER;
- } else if (action == @selector(handleCancel:)) {
- actionId = DownloadShelfContextMenuMac::CANCEL;
- } else if (action == @selector(handleTogglePause:)) {
- actionId = DownloadShelfContextMenuMac::TOGGLE_PAUSE;
- } else {
- NOTREACHED();
- return YES;
- }
-
- if (menuBridge_->IsCommandIdChecked(actionId))
- [item setState:NSOnState];
- else
- [item setState:NSOffState];
-
- return menuBridge_->IsCommandIdEnabled(actionId) ? YES : NO;
-}
-
-- (IBAction)handleOpen:(id)sender {
- menuBridge_->ExecuteCommand(
- DownloadShelfContextMenuMac::OPEN_WHEN_COMPLETE);
-}
-
-- (IBAction)handleAlwaysOpen:(id)sender {
- menuBridge_->ExecuteCommand(
- DownloadShelfContextMenuMac::ALWAYS_OPEN_TYPE);
-}
-
-- (IBAction)handleReveal:(id)sender {
- menuBridge_->ExecuteCommand(DownloadShelfContextMenuMac::SHOW_IN_FOLDER);
-}
-
-- (IBAction)handleCancel:(id)sender {
- menuBridge_->ExecuteCommand(DownloadShelfContextMenuMac::CANCEL);
-}
-
-- (IBAction)handleTogglePause:(id)sender {
- if([sender state] == NSOnState) {
- [sender setTitle:l10n_util::GetNSStringWithFixup(
- IDS_DOWNLOAD_MENU_PAUSE_ITEM)];
- } else {
- [sender setTitle:l10n_util::GetNSStringWithFixup(
- IDS_DOWNLOAD_MENU_RESUME_ITEM)];
- }
- menuBridge_->ExecuteCommand(DownloadShelfContextMenuMac::TOGGLE_PAUSE);
-}
-
-@end
diff --git a/chrome/browser/cocoa/download/download_item_mac.h b/chrome/browser/cocoa/download/download_item_mac.h
deleted file mode 100644
index d31b19d..0000000
--- a/chrome/browser/cocoa/download/download_item_mac.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_DOWNLOAD_DOWNLOAD_ITEM_MAC_H_
-#define CHROME_BROWSER_COCOA_DOWNLOAD_DOWNLOAD_ITEM_MAC_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-#include "chrome/browser/cancelable_request.h"
-#include "chrome/browser/download/download_item.h"
-#include "chrome/browser/download/download_manager.h"
-#include "chrome/browser/icon_manager.h"
-
-class BaseDownloadItemModel;
-@class DownloadItemController;
-
-// A class that bridges the visible mac download items to chromium's download
-// model. The owning object (DownloadItemController) must explicitly call
-// |LoadIcon| if it wants to display the icon associated with this download.
-
-class DownloadItemMac : DownloadItem::Observer {
- public:
- // DownloadItemMac takes ownership of |download_model|.
- DownloadItemMac(BaseDownloadItemModel* download_model,
- DownloadItemController* controller);
-
- // Destructor.
- ~DownloadItemMac();
-
- // DownloadItem::Observer implementation
- virtual void OnDownloadUpdated(DownloadItem* download);
- virtual void OnDownloadFileCompleted(DownloadItem* download) { }
- virtual void OnDownloadOpened(DownloadItem* download) { }
-
- BaseDownloadItemModel* download_model() { return download_model_.get(); }
-
- // Asynchronous icon loading support.
- void LoadIcon();
-
- private:
- // Callback for asynchronous icon loading.
- void OnExtractIconComplete(IconManager::Handle handle, SkBitmap* icon_bitmap);
-
- // The download item model we represent.
- scoped_ptr<BaseDownloadItemModel> download_model_;
-
- // The objective-c controller object.
- DownloadItemController* item_controller_; // weak, owns us.
-
- // For canceling an in progress icon request.
- CancelableRequestConsumerT<int, 0> icon_consumer_;
-
- // Stores the last known path where the file will be saved.
- FilePath lastFilePath_;
-
- DISALLOW_COPY_AND_ASSIGN(DownloadItemMac);
-};
-
-#endif // CHROME_BROWSER_COCOA_DOWNLOAD_DOWNLOAD_ITEM_MAC_H_
diff --git a/chrome/browser/cocoa/download/download_item_mac.mm b/chrome/browser/cocoa/download/download_item_mac.mm
deleted file mode 100644
index 836a041..0000000
--- a/chrome/browser/cocoa/download/download_item_mac.mm
+++ /dev/null
@@ -1,96 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/download/download_item_mac.h"
-
-#include "base/callback.h"
-#include "chrome/browser/browser_process.h"
-#import "chrome/browser/cocoa/download/download_item_controller.h"
-#include "chrome/browser/cocoa/download/download_util_mac.h"
-#include "chrome/browser/download/download_item.h"
-#include "chrome/browser/download/download_item_model.h"
-#include "skia/ext/skia_utils_mac.h"
-
-// DownloadItemMac -------------------------------------------------------------
-
-DownloadItemMac::DownloadItemMac(BaseDownloadItemModel* download_model,
- DownloadItemController* controller)
- : download_model_(download_model), item_controller_(controller) {
- download_model_->download()->AddObserver(this);
-}
-
-DownloadItemMac::~DownloadItemMac() {
- download_model_->download()->RemoveObserver(this);
- icon_consumer_.CancelAllRequests();
-}
-
-void DownloadItemMac::OnDownloadUpdated(DownloadItem* download) {
- DCHECK_EQ(download, download_model_->download());
-
- if ([item_controller_ isDangerousMode] &&
- download->safety_state() == DownloadItem::DANGEROUS_BUT_VALIDATED) {
- // We have been approved.
- [item_controller_ clearDangerousMode];
- }
-
- if (download->GetUserVerifiedFilePath() != lastFilePath_) {
- // Turns out the file path is "unconfirmed %d.crdownload" for dangerous
- // downloads. When the download is confirmed, the file is renamed on
- // another thread, so reload the icon if the download filename changes.
- LoadIcon();
- lastFilePath_ = download->GetUserVerifiedFilePath();
-
- [item_controller_ updateToolTip];
- }
-
- switch (download->state()) {
- case DownloadItem::REMOVING:
- [item_controller_ remove]; // We're deleted now!
- break;
- case DownloadItem::COMPLETE:
- if (download->auto_opened()) {
- [item_controller_ remove]; // We're deleted now!
- return;
- }
- download_util::NotifySystemOfDownloadComplete(download->full_path());
- // fall through
- case DownloadItem::IN_PROGRESS:
- case DownloadItem::CANCELLED:
- [item_controller_ setStateFromDownload:download_model_.get()];
- break;
- default:
- NOTREACHED();
- }
-}
-
-void DownloadItemMac::LoadIcon() {
- IconManager* icon_manager = g_browser_process->icon_manager();
- if (!icon_manager) {
- NOTREACHED();
- return;
- }
-
- // We may already have this particular image cached.
- FilePath file = download_model_->download()->GetUserVerifiedFilePath();
- SkBitmap* icon_bitmap = icon_manager->LookupIcon(file, IconLoader::SMALL);
- if (icon_bitmap) {
- NSImage* icon = gfx::SkBitmapToNSImage(*icon_bitmap);
- [item_controller_ setIcon:icon];
- return;
- }
-
- // The icon isn't cached, load it asynchronously.
- icon_manager->LoadIcon(file, IconLoader::SMALL, &icon_consumer_,
- NewCallback(this,
- &DownloadItemMac::OnExtractIconComplete));
-}
-
-void DownloadItemMac::OnExtractIconComplete(IconManager::Handle handle,
- SkBitmap* icon_bitmap) {
- if (!icon_bitmap)
- return;
-
- NSImage* icon = gfx::SkBitmapToNSImage(*icon_bitmap);
- [item_controller_ setIcon:icon];
-}
diff --git a/chrome/browser/cocoa/download/download_shelf_controller.h b/chrome/browser/cocoa/download/download_shelf_controller.h
deleted file mode 100644
index 5895cfc..0000000
--- a/chrome/browser/cocoa/download/download_shelf_controller.h
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright (c) 2009 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>
-
-#import "base/cocoa_protocols_mac.h"
-#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-#import "chrome/browser/cocoa/view_resizer.h"
-
-@class AnimatableView;
-class BaseDownloadItemModel;
-class Browser;
-@class BrowserWindowController;
-@class DownloadItemController;
-class DownloadShelf;
-@class DownloadShelfView;
-@class HyperlinkButtonCell;
-
-// A controller class that manages the download shelf for one window. It is
-// responsible for the behavior of the shelf itself (showing/hiding, handling
-// the link, layout) as well as for managing the download items it contains.
-//
-// All the files in cocoa/downloads_* are related as follows:
-//
-// download_shelf_mac bridges calls from chromium's c++ world to the objc
-// download_shelf_controller for the shelf (this file). The shelf's background
-// is drawn by download_shelf_view. Every item in a shelf is controlled by a
-// download_item_controller.
-//
-// download_item_mac bridges calls from chromium's c++ world to the objc
-// download_item_controller, which is responsible for managing a single item
-// on the shelf. The item controller loads its UI from a xib file, where the
-// UI of an item itself is represented by a button that is drawn by
-// download_item_cell.
-
-@interface DownloadShelfController : NSViewController<NSTextViewDelegate> {
- @private
- IBOutlet HyperlinkButtonCell* showAllDownloadsCell_;
-
- IBOutlet NSImageView* image_;
-
- BOOL barIsVisible_;
-
- scoped_ptr<DownloadShelf> bridge_;
-
- // Height of the shelf when it's fully visible.
- CGFloat maxShelfHeight_;
-
- // Current height of the shelf. Changes while the shelf is animating in or
- // out.
- CGFloat currentShelfHeight_;
-
- // The download items we have added to our shelf.
- scoped_nsobject<NSMutableArray> downloadItemControllers_;
-
- // The container that contains (and clamps) all the download items.
- IBOutlet NSView* itemContainerView_;
-
- // Delegate that handles resizing our view.
- id<ViewResizer> resizeDelegate_;
-};
-
-- (id)initWithBrowser:(Browser*)browser
- resizeDelegate:(id<ViewResizer>)resizeDelegate;
-
-- (IBAction)showDownloadsTab:(id)sender;
-
-// Returns our view cast as an AnimatableView.
-- (AnimatableView*)animatableView;
-
-- (DownloadShelf*)bridge;
-- (BOOL)isVisible;
-
-- (IBAction)show:(id)sender;
-
-// Run when the user clicks the close button on the right side of the shelf.
-- (IBAction)hide:(id)sender;
-
-- (void)addDownloadItem:(BaseDownloadItemModel*)model;
-
-// Remove a download, possibly via clearing browser data.
-- (void)remove:(DownloadItemController*)download;
-
-// Notification that we are closing and should release our downloads.
-- (void)exiting;
-
-// Return the height of the download shelf.
-- (float)height;
-
-// Re-layouts all download items based on their current state.
-- (void)layoutItems;
-
-@end
diff --git a/chrome/browser/cocoa/download/download_shelf_controller.mm b/chrome/browser/cocoa/download/download_shelf_controller.mm
deleted file mode 100644
index a15e0bb..0000000
--- a/chrome/browser/cocoa/download/download_shelf_controller.mm
+++ /dev/null
@@ -1,327 +0,0 @@
-// 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 "chrome/browser/cocoa/download/download_shelf_controller.h"
-
-#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
-#include "base/mac_util.h"
-#include "base/sys_string_conversions.h"
-#import "chrome/browser/cocoa/animatable_view.h"
-#include "chrome/browser/cocoa/browser_window_cocoa.h"
-#import "chrome/browser/cocoa/browser_window_controller.h"
-#include "chrome/browser/cocoa/download/download_item_controller.h"
-#include "chrome/browser/cocoa/download/download_shelf_mac.h"
-#import "chrome/browser/cocoa/download/download_shelf_view.h"
-#import "chrome/browser/cocoa/hyperlink_button_cell.h"
-#include "chrome/browser/download/download_item.h"
-#include "chrome/browser/download/download_manager.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/themes/browser_theme_provider.h"
-#include "chrome/browser/ui/browser.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
-
-namespace {
-
-// Max number of download views we'll contain. Any time a view is added and
-// we already have this many download views, one is removed.
-const size_t kMaxDownloadItemCount = 16;
-
-// Horizontal padding between two download items.
-const int kDownloadItemPadding = 0;
-
-// Duration for the open-new-leftmost-item animation, in seconds.
-const NSTimeInterval kDownloadItemOpenDuration = 0.8;
-
-// Duration for download shelf closing animation, in seconds.
-const NSTimeInterval kDownloadShelfCloseDuration = 0.12;
-
-} // namespace
-
-@interface DownloadShelfController(Private)
-- (void)showDownloadShelf:(BOOL)enable;
-- (void)layoutItems:(BOOL)skipFirst;
-- (void)closed;
-
-- (void)updateTheme;
-- (void)themeDidChangeNotification:(NSNotification*)notification;
-- (void)viewFrameDidChange:(NSNotification*)notification;
-@end
-
-
-@implementation DownloadShelfController
-
-- (id)initWithBrowser:(Browser*)browser
- resizeDelegate:(id<ViewResizer>)resizeDelegate {
- if ((self = [super initWithNibName:@"DownloadShelf"
- bundle:mac_util::MainAppBundle()])) {
- resizeDelegate_ = resizeDelegate;
- maxShelfHeight_ = NSHeight([[self view] bounds]);
- currentShelfHeight_ = maxShelfHeight_;
-
- // Reset the download shelf's frame height to zero. It will be properly
- // positioned and sized the first time we try to set its height. (Just
- // setting the rect to NSZeroRect does not work: it confuses Cocoa's view
- // layout logic. If the shelf's width is too small, cocoa makes the download
- // item container view wider than the browser window).
- NSRect frame = [[self view] frame];
- frame.size.height = 0;
- [[self view] setFrame:frame];
-
- downloadItemControllers_.reset([[NSMutableArray alloc] init]);
-
- bridge_.reset(new DownloadShelfMac(browser, self));
- }
- return self;
-}
-
-- (void)awakeFromNib {
- NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
- [defaultCenter addObserver:self
- selector:@selector(themeDidChangeNotification:)
- name:kBrowserThemeDidChangeNotification
- object:nil];
-
- [[self animatableView] setResizeDelegate:resizeDelegate_];
- [[self view] setPostsFrameChangedNotifications:YES];
- [defaultCenter addObserver:self
- selector:@selector(viewFrameDidChange:)
- name:NSViewFrameDidChangeNotification
- object:[self view]];
-
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- NSImage* favicon = rb.GetNativeImageNamed(IDR_DOWNLOADS_FAVICON);
- DCHECK(favicon);
- [image_ setImage:favicon];
-}
-
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
-
- // The controllers will unregister themselves as observers when they are
- // deallocated. No need to do that here.
- [super dealloc];
-}
-
-// Called after the current theme has changed.
-- (void)themeDidChangeNotification:(NSNotification*)notification {
- [self updateTheme];
-}
-
-// Called after the frame's rect has changed; usually when the height is
-// animated.
-- (void)viewFrameDidChange:(NSNotification*)notification {
- // Anchor subviews at the top of |view|, so that it looks like the shelf
- // is sliding out.
- CGFloat newShelfHeight = NSHeight([[self view] frame]);
- if (newShelfHeight == currentShelfHeight_)
- return;
-
- for (NSView* view in [[self view] subviews]) {
- NSRect frame = [view frame];
- frame.origin.y -= currentShelfHeight_ - newShelfHeight;
- [view setFrame:frame];
- }
- currentShelfHeight_ = newShelfHeight;
-}
-
-// Adapt appearance to the current theme. Called after theme changes and before
-// this is shown for the first time.
-- (void)updateTheme {
- NSColor* color = nil;
-
- if (bridge_.get() && bridge_->browser() && bridge_->browser()->profile()) {
- ThemeProvider* provider = bridge_->browser()->profile()->GetThemeProvider();
-
- color =
- provider->GetNSColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT, false);
- }
-
- if (!color)
- color = [HyperlinkButtonCell defaultTextColor];
-
- [showAllDownloadsCell_ setTextColor:color];
-}
-
-- (AnimatableView*)animatableView {
- return static_cast<AnimatableView*>([self view]);
-}
-
-- (void)showDownloadsTab:(id)sender {
- bridge_->browser()->ShowDownloadsTab();
-}
-
-- (void)remove:(DownloadItemController*)download {
- // Look for the download in our controller array and remove it. This will
- // explicity release it so that it removes itself as an Observer of the
- // DownloadItem. We don't want to wait for autorelease since the DownloadItem
- // we are observing will likely be gone by then.
- [[NSNotificationCenter defaultCenter] removeObserver:download];
-
- // TODO(dmaclach): Remove -- http://crbug.com/25845
- [[download view] removeFromSuperview];
-
- [downloadItemControllers_ removeObject:download];
-
- [self layoutItems];
-
- // Check to see if we have any downloads remaining and if not, hide the shelf.
- if (![downloadItemControllers_ count])
- [self showDownloadShelf:NO];
-}
-
-// We need to explicitly release our download controllers here since they need
-// to remove themselves as observers before the remaining shutdown happens.
-- (void)exiting {
- [[self animatableView] stopAnimation];
- downloadItemControllers_.reset();
-}
-
-// Show or hide the bar based on the value of |enable|. Handles animating the
-// resize of the content view.
-- (void)showDownloadShelf:(BOOL)enable {
- if ([self isVisible] == enable)
- return;
-
- if ([[self view] window])
- [self updateTheme];
-
- // Animate the shelf out, but not in.
- // TODO(rohitrao): We do not animate on the way in because Cocoa is already
- // doing a lot of work to set up the download arrow animation. I've chosen to
- // do no animation over janky animation. Find a way to make animating in
- // smoother.
- AnimatableView* view = [self animatableView];
- if (enable)
- [view setHeight:maxShelfHeight_];
- else
- [view animateToNewHeight:0 duration:kDownloadShelfCloseDuration];
-
- barIsVisible_ = enable;
-}
-
-- (DownloadShelf*)bridge {
- return bridge_.get();
-}
-
-- (BOOL)isVisible {
- return barIsVisible_;
-}
-
-- (void)show:(id)sender {
- [self showDownloadShelf:YES];
-}
-
-- (void)hide:(id)sender {
- // If |sender| isn't nil, then we're being closed from the UI by the user and
- // we need to tell our shelf implementation to close. Otherwise, we're being
- // closed programmatically by our shelf implementation.
- if (sender)
- bridge_->Close();
- else
- [self showDownloadShelf:NO];
-}
-
-- (void)animationDidEnd:(NSAnimation*)animation {
- if (![self isVisible])
- [self closed];
-}
-
-- (float)height {
- return maxShelfHeight_;
-}
-
-// If |skipFirst| is true, the frame of the leftmost item is not set.
-- (void)layoutItems:(BOOL)skipFirst {
- CGFloat currentX = 0;
- for (DownloadItemController* itemController
- in downloadItemControllers_.get()) {
- NSRect frame = [[itemController view] frame];
- frame.origin.x = currentX;
- frame.size.width = [itemController preferredSize].width;
- if (!skipFirst)
- [[[itemController view] animator] setFrame:frame];
- currentX += frame.size.width + kDownloadItemPadding;
- skipFirst = NO;
- }
-}
-
-- (void)layoutItems {
- [self layoutItems:NO];
-}
-
-- (void)addDownloadItem:(BaseDownloadItemModel*)model {
- DCHECK([NSThread isMainThread]);
- // Insert new item at the left.
- scoped_nsobject<DownloadItemController> controller(
- [[DownloadItemController alloc] initWithModel:model shelf:self]);
-
- // Adding at index 0 in NSMutableArrays is O(1).
- [downloadItemControllers_ insertObject:controller.get() atIndex:0];
-
- [itemContainerView_ addSubview:[controller view]];
-
- // The controller is in charge of removing itself as an observer in its
- // dealloc.
- [[NSNotificationCenter defaultCenter]
- addObserver:controller
- selector:@selector(updateVisibility:)
- name:NSViewFrameDidChangeNotification
- object:[controller view]];
- [[NSNotificationCenter defaultCenter]
- addObserver:controller
- selector:@selector(updateVisibility:)
- name:NSViewFrameDidChangeNotification
- object:itemContainerView_];
-
- // Start at width 0...
- NSSize size = [controller preferredSize];
- NSRect frame = NSMakeRect(0, 0, 0, size.height);
- [[controller view] setFrame:frame];
-
- // ...then animate in
- frame.size.width = size.width;
- [NSAnimationContext beginGrouping];
- [[NSAnimationContext currentContext]
- gtm_setDuration:kDownloadItemOpenDuration
- eventMask:NSLeftMouseUpMask];
- [[[controller view] animator] setFrame:frame];
- [NSAnimationContext endGrouping];
-
- // Keep only a limited number of items in the shelf.
- if ([downloadItemControllers_ count] > kMaxDownloadItemCount) {
- DCHECK(kMaxDownloadItemCount > 0);
-
- // Since no user will ever see the item being removed (needs a horizontal
- // screen resolution greater than 3200 at 16 items at 200 pixels each),
- // there's no point in animating the removal.
- [self remove:[downloadItemControllers_ lastObject]];
- }
-
- // Finally, move the remaining items to the right. Skip the first item when
- // laying out the items, so that the longer animation duration we set up above
- // is not overwritten.
- [self layoutItems:YES];
-}
-
-- (void)closed {
- NSUInteger i = 0;
- while (i < [downloadItemControllers_ count]) {
- DownloadItemController* itemController =
- [downloadItemControllers_ objectAtIndex:i];
- bool isTransferDone =
- [itemController download]->state() == DownloadItem::COMPLETE ||
- [itemController download]->state() == DownloadItem::CANCELLED;
- if (isTransferDone &&
- [itemController download]->safety_state() != DownloadItem::DANGEROUS) {
- [self remove:itemController];
- } else {
- ++i;
- }
- }
-}
-
-@end
diff --git a/chrome/browser/cocoa/download/download_shelf_mac.h b/chrome/browser/cocoa/download/download_shelf_mac.h
deleted file mode 100644
index d7e83a6..0000000
--- a/chrome/browser/cocoa/download/download_shelf_mac.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_DOWNLOAD_DOWNLOAD_SHELF_MAC_H_
-#define CHROME_BROWSER_COCOA_DOWNLOAD_DOWNLOAD_SHELF_MAC_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "chrome/browser/download/download_shelf.h"
-
-class BaseDownloadItemModel;
-class CustomDrawButton;
-class DownloadItemMac;
-
-@class ShelfView;
-@class DownloadShelfController;
-
-// A class to bridge the chromium download shelf to mac gui. This is just a
-// wrapper class that forward everything to DownloadShelfController.
-
-class DownloadShelfMac : public DownloadShelf {
- public:
- explicit DownloadShelfMac(Browser* browser,
- DownloadShelfController* controller);
-
- // DownloadShelf implementation.
- virtual void AddDownload(BaseDownloadItemModel* download_model);
- virtual bool IsShowing() const;
- virtual bool IsClosing() const;
- virtual void Show();
- virtual void Close();
- virtual Browser* browser() const { return browser_; }
-
- private:
- // The browser that owns this shelf.
- Browser* browser_;
-
- DownloadShelfController* shelf_controller_; // weak, owns us
-};
-
-#endif // CHROME_BROWSER_COCOA_DOWNLOAD_DOWNLOAD_SHELF_MAC_H_
diff --git a/chrome/browser/cocoa/download/download_shelf_mac.mm b/chrome/browser/cocoa/download/download_shelf_mac.mm
deleted file mode 100644
index 0bfbecd..0000000
--- a/chrome/browser/cocoa/download/download_shelf_mac.mm
+++ /dev/null
@@ -1,40 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/download/download_shelf_mac.h"
-
-#import "chrome/browser/cocoa/download/download_shelf_controller.h"
-#include "chrome/browser/cocoa/download/download_item_mac.h"
-#include "chrome/browser/download/download_item_model.h"
-#include "chrome/browser/ui/browser.h"
-
-DownloadShelfMac::DownloadShelfMac(Browser* browser,
- DownloadShelfController* controller)
- : browser_(browser),
- shelf_controller_(controller) {
-}
-
-void DownloadShelfMac::AddDownload(BaseDownloadItemModel* download_model) {
- [shelf_controller_ addDownloadItem:download_model];
- Show();
-}
-
-bool DownloadShelfMac::IsShowing() const {
- return [shelf_controller_ isVisible] == YES;
-}
-
-bool DownloadShelfMac::IsClosing() const {
- // TODO(estade): This is never called. For now just return false.
- return false;
-}
-
-void DownloadShelfMac::Show() {
- [shelf_controller_ show:nil];
- browser_->UpdateDownloadShelfVisibility(true);
-}
-
-void DownloadShelfMac::Close() {
- [shelf_controller_ hide:nil];
- browser_->UpdateDownloadShelfVisibility(false);
-}
diff --git a/chrome/browser/cocoa/download/download_shelf_mac_unittest.mm b/chrome/browser/cocoa/download/download_shelf_mac_unittest.mm
deleted file mode 100644
index f6e93ae..0000000
--- a/chrome/browser/cocoa/download/download_shelf_mac_unittest.mm
+++ /dev/null
@@ -1,91 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/cocoa/download/download_shelf_mac.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-// A fake implementation of DownloadShelfController. It implements only the
-// methods that DownloadShelfMac call during the tests in this file. We get this
-// class into the DownloadShelfMac constructor by some questionable casting --
-// Objective C is a dynamic language, so we pretend that's ok.
-
-@interface FakeDownloadShelfController : NSObject {
- @public
- int callCountIsVisible;
- int callCountShow;
- int callCountHide;
-}
-
-- (BOOL)isVisible;
-- (IBAction)show:(id)sender;
-- (IBAction)hide:(id)sender;
-@end
-
-@implementation FakeDownloadShelfController
-
-- (BOOL)isVisible {
- ++callCountIsVisible;
- return YES;
-}
-
-- (IBAction)show:(id)sender {
- ++callCountShow;
-}
-
-- (IBAction)hide:(id)sender {
- ++callCountHide;
-}
-
-@end
-
-
-namespace {
-
-class DownloadShelfMacTest : public CocoaTest {
-
- virtual void SetUp() {
- CocoaTest::SetUp();
- shelf_controller_.reset([[FakeDownloadShelfController alloc] init]);
- }
-
- protected:
- scoped_nsobject<FakeDownloadShelfController> shelf_controller_;
- BrowserTestHelper browser_helper_;
-};
-
-TEST_F(DownloadShelfMacTest, CreationDoesNotCallShow) {
- // Also make sure the DownloadShelfMacTest constructor doesn't crash.
- DownloadShelfMac shelf(browser_helper_.browser(),
- (DownloadShelfController*)shelf_controller_.get());
- EXPECT_EQ(0, shelf_controller_.get()->callCountShow);
-}
-
-TEST_F(DownloadShelfMacTest, ForwardsShow) {
- DownloadShelfMac shelf(browser_helper_.browser(),
- (DownloadShelfController*)shelf_controller_.get());
- EXPECT_EQ(0, shelf_controller_.get()->callCountShow);
- shelf.Show();
- EXPECT_EQ(1, shelf_controller_.get()->callCountShow);
-}
-
-TEST_F(DownloadShelfMacTest, ForwardsHide) {
- DownloadShelfMac shelf(browser_helper_.browser(),
- (DownloadShelfController*)shelf_controller_.get());
- EXPECT_EQ(0, shelf_controller_.get()->callCountHide);
- shelf.Close();
- EXPECT_EQ(1, shelf_controller_.get()->callCountHide);
-}
-
-TEST_F(DownloadShelfMacTest, ForwardsIsShowing) {
- DownloadShelfMac shelf(browser_helper_.browser(),
- (DownloadShelfController*)shelf_controller_.get());
- EXPECT_EQ(0, shelf_controller_.get()->callCountIsVisible);
- shelf.IsShowing();
- EXPECT_EQ(1, shelf_controller_.get()->callCountIsVisible);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/download/download_shelf_view.h b/chrome/browser/cocoa/download/download_shelf_view.h
deleted file mode 100644
index 0408bb6..0000000
--- a/chrome/browser/cocoa/download/download_shelf_view.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_DOWNLOAD_DOWNLOAD_SHELF_VIEW_H_
-#define CHROME_BROWSER_COCOA_DOWNLOAD_DOWNLOAD_SHELF_VIEW_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#import "chrome/browser/cocoa/animatable_view.h"
-
-// A view that handles any special rendering for the download shelf, painting
-// a gradient and managing a set of DownloadItemViews.
-
-@interface DownloadShelfView : AnimatableView {
-}
-@end
-
-#endif // CHROME_BROWSER_COCOA_DOWNLOAD_DOWNLOAD_SHELF_VIEW_H_
diff --git a/chrome/browser/cocoa/download/download_shelf_view.mm b/chrome/browser/cocoa/download/download_shelf_view.mm
deleted file mode 100644
index ba32728..0000000
--- a/chrome/browser/cocoa/download/download_shelf_view.mm
+++ /dev/null
@@ -1,71 +0,0 @@
-// 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 "chrome/browser/cocoa/download/download_shelf_view.h"
-
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/themed_window.h"
-#import "chrome/browser/cocoa/view_id_util.h"
-#include "chrome/browser/themes/browser_theme_provider.h"
-#include "grit/theme_resources.h"
-
-@implementation DownloadShelfView
-
-- (NSColor*)strokeColor {
- BOOL isKey = [[self window] isKeyWindow];
- ThemeProvider* themeProvider = [[self window] themeProvider];
- return themeProvider ? themeProvider->GetNSColor(
- isKey ? BrowserThemeProvider::COLOR_TOOLBAR_STROKE :
- BrowserThemeProvider::COLOR_TOOLBAR_STROKE_INACTIVE, true) :
- [NSColor blackColor];
-}
-
-- (void)drawRect:(NSRect)rect {
- BOOL isKey = [[self window] isKeyWindow];
- ThemeProvider* themeProvider = [[self window] themeProvider];
- if (!themeProvider)
- return;
-
- NSColor* backgroundImageColor =
- themeProvider->GetNSImageColorNamed(IDR_THEME_TOOLBAR, false);
- if (backgroundImageColor) {
- // We want our backgrounds for the shelf to be phased from the upper
- // left hand corner of the view.
- NSPoint phase = NSMakePoint(0, NSHeight([self bounds]));
- [[NSGraphicsContext currentContext] setPatternPhase:phase];
- [backgroundImageColor set];
- NSRectFill([self bounds]);
- } else {
- NSGradient* gradient = themeProvider->GetNSGradient(
- isKey ? BrowserThemeProvider::GRADIENT_TOOLBAR :
- BrowserThemeProvider::GRADIENT_TOOLBAR_INACTIVE);
- NSPoint startPoint = [self convertPoint:NSMakePoint(0, 0) fromView:nil];
- NSPoint endPoint =
- [self convertPoint:NSMakePoint(0, [self frame].size.height)
- fromView:nil];
-
- [gradient drawFromPoint:startPoint
- toPoint:endPoint
- options:NSGradientDrawsBeforeStartingLocation |
- NSGradientDrawsAfterEndingLocation];
- }
-
- // Draw top stroke
- [[self strokeColor] set];
- NSRect borderRect, contentRect;
- NSDivideRect([self bounds], &borderRect, &contentRect, 1, NSMaxYEdge);
- NSRectFillUsingOperation(borderRect, NSCompositeSourceOver);
-}
-
-// Mouse down events on the download shelf should not allow dragging the parent
-// window around.
-- (BOOL)mouseDownCanMoveWindow {
- return NO;
-}
-
-- (ViewID)viewID {
- return VIEW_ID_DOWNLOAD_SHELF;
-}
-
-@end
diff --git a/chrome/browser/cocoa/download/download_shelf_view_unittest.mm b/chrome/browser/cocoa/download/download_shelf_view_unittest.mm
deleted file mode 100644
index 2f4a730..0000000
--- a/chrome/browser/cocoa/download/download_shelf_view_unittest.mm
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2009 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/scoped_nsobject.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/download/download_shelf_view.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-namespace {
-
-class DownloadShelfViewTest : public CocoaTest {
-};
-
-// This class only needs to do one thing: prevent mouse down events from moving
-// the parent window around.
-TEST_F(DownloadShelfViewTest, CanDragWindow) {
- scoped_nsobject<DownloadShelfView> view([[DownloadShelfView alloc] init]);
- EXPECT_FALSE([view mouseDownCanMoveWindow]);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/download/download_started_animation_mac.mm b/chrome/browser/cocoa/download/download_started_animation_mac.mm
deleted file mode 100644
index 2c0d7f2..0000000
--- a/chrome/browser/cocoa/download/download_started_animation_mac.mm
+++ /dev/null
@@ -1,195 +0,0 @@
-// 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.
-//
-// This file contains the Mac implementation the download animation, displayed
-// at the start of a download. The animation produces an arrow pointing
-// downwards and animates towards the bottom of the window where the new
-// download appears in the download shelf.
-
-#include "chrome/browser/download/download_started_animation.h"
-
-#import <QuartzCore/QuartzCore.h>
-
-#include "app/resource_bundle.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents/tab_contents_view_mac.h"
-#import "chrome/browser/cocoa/animatable_image.h"
-#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
-#include "grit/theme_resources.h"
-#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
-#include "third_party/skia/include/utils/mac/SkCGUtils.h"
-
-class DownloadAnimationTabObserver;
-
-// A class for managing the Core Animation download animation.
-// Should be instantiated using +startAnimationWithTabContents:.
-@interface DownloadStartedAnimationMac : NSObject {
- @private
- // The observer for the TabContents we are drawing on.
- scoped_ptr<DownloadAnimationTabObserver> observer_;
- CGFloat imageWidth_;
- AnimatableImage* animation_;
-};
-
-+ (void)startAnimationWithTabContents:(TabContents*)tabContents;
-
-// Called by the Observer if the tab is hidden or closed.
-- (void)closeAnimation;
-
-@end
-
-// A helper class to monitor tab hidden and closed notifications. If we receive
-// such a notification, we stop the animation.
-class DownloadAnimationTabObserver : public NotificationObserver {
- public:
- DownloadAnimationTabObserver(DownloadStartedAnimationMac* owner,
- TabContents* tab_contents)
- : owner_(owner),
- tab_contents_(tab_contents) {
- registrar_.Add(this,
- NotificationType::TAB_CONTENTS_HIDDEN,
- Source<TabContents>(tab_contents_));
- registrar_.Add(this,
- NotificationType::TAB_CONTENTS_DESTROYED,
- Source<TabContents>(tab_contents_));
- }
-
- // Runs when a tab is hidden or destroyed. Let our owner know we should end
- // the animation.
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- // This ends up deleting us.
- [owner_ closeAnimation];
- }
-
- private:
- // The object we need to inform when we get a notification. Weak.
- DownloadStartedAnimationMac* owner_;
-
- // The tab we are observing. Weak.
- TabContents* tab_contents_;
-
- // Used for registering to receive notifications and automatic clean up.
- NotificationRegistrar registrar_;
-
- DISALLOW_COPY_AND_ASSIGN(DownloadAnimationTabObserver);
-};
-
-@implementation DownloadStartedAnimationMac
-
-- (id)initWithTabContents:(TabContents*)tabContents {
- if ((self = [super init])) {
- // Load the image of the download arrow.
- ResourceBundle& bundle = ResourceBundle::GetSharedInstance();
- NSImage* image = bundle.GetNativeImageNamed(IDR_DOWNLOAD_ANIMATION_BEGIN);
-
- // Figure out the positioning in the current tab. Try to position the layer
- // against the left edge, and three times the download image's height from
- // the bottom of the tab, assuming there is enough room. If there isn't
- // enough, don't show the animation and let the shelf speak for itself.
- gfx::Rect bounds;
- tabContents->GetContainerBounds(&bounds);
- imageWidth_ = [image size].width;
- CGFloat imageHeight = [image size].height;
-
- // Sanity check the size in case there's no room to display the animation.
- if (bounds.height() < imageHeight) {
- [self release];
- return nil;
- }
-
- NSView* tabContentsView = tabContents->GetNativeView();
- NSWindow* parentWindow = [tabContentsView window];
- if (!parentWindow) {
- // The tab is no longer frontmost.
- [self release];
- return nil;
- }
-
- NSPoint origin = [tabContentsView frame].origin;
- origin = [tabContentsView convertPoint:origin toView:nil];
- origin = [parentWindow convertBaseToScreen:origin];
-
- // Create the animation object to assist in animating and fading.
- CGFloat animationHeight = MIN(bounds.height(), 4 * imageHeight);
- NSRect frame = NSMakeRect(origin.x, origin.y, imageWidth_, animationHeight);
- animation_ = [[AnimatableImage alloc] initWithImage:image
- animationFrame:frame];
- [parentWindow addChildWindow:animation_ ordered:NSWindowAbove];
-
- animationHeight = MIN(bounds.height(), 3 * imageHeight);
- [animation_ setStartFrame:CGRectMake(0, animationHeight,
- imageWidth_, imageHeight)];
- [animation_ setEndFrame:CGRectMake(0, imageHeight,
- imageWidth_, imageHeight)];
- [animation_ setStartOpacity:1.0];
- [animation_ setEndOpacity:0.4];
- [animation_ setDuration:0.6];
-
- observer_.reset(new DownloadAnimationTabObserver(self, tabContents));
-
- // Set up to get notified about resize events on the parent window.
- NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
- [center addObserver:self
- selector:@selector(parentWindowChanged:)
- name:NSWindowDidResizeNotification
- object:parentWindow];
- // When the animation window closes, it needs to be removed from the
- // parent window.
- [center addObserver:self
- selector:@selector(windowWillClose:)
- name:NSWindowWillCloseNotification
- object:animation_];
- }
- return self;
-}
-
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [super dealloc];
-}
-
-// Called when the parent window is resized.
-- (void)parentWindowChanged:(NSNotification*)notification {
- NSWindow* parentWindow = [animation_ parentWindow];
- DCHECK([[notification object] isEqual:parentWindow]);
- NSRect parentFrame = [parentWindow frame];
- NSRect frame = parentFrame;
- frame.size.width = MIN(imageWidth_, NSWidth(parentFrame));
- [animation_ setFrame:frame display:YES];
-}
-
-- (void)closeAnimation {
- [animation_ close];
-}
-
-// When the animation closes, release self.
-- (void)windowWillClose:(NSNotification*)notification {
- DCHECK([[notification object] isEqual:animation_]);
- [[animation_ parentWindow] removeChildWindow:animation_];
- [self release];
-}
-
-+ (void)startAnimationWithTabContents:(TabContents*)contents {
- // Will be deleted when the animation window closes.
- DownloadStartedAnimationMac* controller =
- [[self alloc] initWithTabContents:contents];
- // The initializer can return nil.
- if (!controller)
- return;
-
- // The |animation_| releases itself when done.
- [controller->animation_ startAnimation];
-}
-
-@end
-
-void DownloadStartedAnimation::Show(TabContents* tab_contents) {
- DCHECK(tab_contents);
-
- // Will be deleted when the animation is complete.
- [DownloadStartedAnimationMac startAnimationWithTabContents:tab_contents];
-}
diff --git a/chrome/browser/cocoa/download/download_util_mac.h b/chrome/browser/cocoa/download/download_util_mac.h
deleted file mode 100644
index 30ca42a..0000000
--- a/chrome/browser/cocoa/download/download_util_mac.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// 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.
-//
-// Download utility functions for Mac OS X.
-
-#ifndef CHROME_BROWSER_COCOA_DOWNLOAD_DOWNLOAD_UTIL_MAC_H_
-#define CHROME_BROWSER_COCOA_DOWNLOAD_DOWNLOAD_UTIL_MAC_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-class FilePath;
-
-namespace download_util {
-
-void AddFileToPasteboard(NSPasteboard* pasteboard, const FilePath& path);
-
-// Notify the system that a download completed. This will cause the download
-// folder in the dock to bounce.
-void NotifySystemOfDownloadComplete(const FilePath& path);
-
-} // namespace download_util
-
-#endif // CHROME_BROWSER_COCOA_DOWNLOAD_DOWNLOAD_UTIL_MAC_H_
diff --git a/chrome/browser/cocoa/download/download_util_mac.mm b/chrome/browser/cocoa/download/download_util_mac.mm
deleted file mode 100644
index 486406f..0000000
--- a/chrome/browser/cocoa/download/download_util_mac.mm
+++ /dev/null
@@ -1,83 +0,0 @@
-// 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.
-//
-// Download utility implementation for Mac OS X.
-
-#include "chrome/browser/cocoa/download/download_util_mac.h"
-
-#include "base/sys_string_conversions.h"
-#import "chrome/browser/cocoa/dock_icon.h"
-#include "chrome/browser/download/download_item.h"
-#include "chrome/browser/download/download_manager.h"
-#include "gfx/native_widget_types.h"
-#include "skia/ext/skia_utils_mac.h"
-
-namespace download_util {
-
-void AddFileToPasteboard(NSPasteboard* pasteboard, const FilePath& path) {
- // Write information about the file being dragged to the pasteboard.
- NSString* file = base::SysUTF8ToNSString(path.value());
- NSArray* fileList = [NSArray arrayWithObject:file];
- [pasteboard declareTypes:[NSArray arrayWithObject:NSFilenamesPboardType]
- owner:nil];
- [pasteboard setPropertyList:fileList forType:NSFilenamesPboardType];
-}
-
-void NotifySystemOfDownloadComplete(const FilePath& path) {
- NSString* filePath = base::SysUTF8ToNSString(path.value());
- [[NSDistributedNotificationCenter defaultCenter]
- postNotificationName:@"com.apple.DownloadFileFinished"
- object:filePath];
-
- NSString* parentPath = [filePath stringByDeletingLastPathComponent];
- FNNotifyByPath(
- reinterpret_cast<const UInt8*>([parentPath fileSystemRepresentation]),
- kFNDirectoryModifiedMessage,
- kNilOptions);
-}
-
-void DragDownload(const DownloadItem* download,
- SkBitmap* icon,
- gfx::NativeView view) {
- NSPasteboard* pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard];
- AddFileToPasteboard(pasteboard, download->full_path());
-
- // Convert to an NSImage.
- NSImage* dragImage = gfx::SkBitmapToNSImage(*icon);
-
- // Synthesize a drag event, since we don't have access to the actual event
- // that initiated a drag (possibly consumed by the DOM UI, for example).
- NSPoint position = [[view window] mouseLocationOutsideOfEventStream];
- NSTimeInterval eventTime = [[NSApp currentEvent] timestamp];
- NSEvent* dragEvent = [NSEvent mouseEventWithType:NSLeftMouseDragged
- location:position
- modifierFlags:NSLeftMouseDraggedMask
- timestamp:eventTime
- windowNumber:[[view window] windowNumber]
- context:nil
- eventNumber:0
- clickCount:1
- pressure:1.0];
-
- // Run the drag operation.
- [[view window] dragImage:dragImage
- at:position
- offset:NSZeroSize
- event:dragEvent
- pasteboard:pasteboard
- source:view
- slideBack:YES];
-}
-
-void UpdateAppIconDownloadProgress(int download_count,
- bool progress_known,
- float progress) {
- DockIcon* dock_icon = [DockIcon sharedDockIcon];
- [dock_icon setDownloads:download_count];
- [dock_icon setIndeterminate:!progress_known];
- [dock_icon setProgress:progress];
- [dock_icon updateIcon];
-}
-
-} // namespace download_util
diff --git a/chrome/browser/cocoa/download/download_util_mac_unittest.mm b/chrome/browser/cocoa/download/download_util_mac_unittest.mm
deleted file mode 100644
index a6b0939..0000000
--- a/chrome/browser/cocoa/download/download_util_mac_unittest.mm
+++ /dev/null
@@ -1,58 +0,0 @@
-// 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.
-
-// Download utility test for Mac OS X.
-
-#include "base/path_service.h"
-#include "base/sys_string_conversions.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/download/download_util_mac.h"
-#include "chrome/common/chrome_paths.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-namespace {
-
-class DownloadUtilMacTest : public CocoaTest {
- public:
- DownloadUtilMacTest() {
- pasteboard_ = [NSPasteboard pasteboardWithUniqueName];
- }
-
- virtual ~DownloadUtilMacTest() {
- [pasteboard_ releaseGlobally];
- }
-
- NSPasteboard* const pasteboard() { return pasteboard_; }
-
- private:
- NSPasteboard* pasteboard_;
-};
-
-// Ensure adding files to the pasteboard methods works as expected.
-TEST_F(DownloadUtilMacTest, AddFileToPasteboardTest) {
- // Get a download test file for addition to the pasteboard.
- FilePath testPath;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &testPath));
- FilePath testFile(FILE_PATH_LITERAL("download-test1.lib"));
- testPath = testPath.Append(testFile);
-
- // Add a test file to the pasteboard via the download_util method.
- download_util::AddFileToPasteboard(pasteboard(), testPath);
-
- // Test to see that the object type for dragging files is available.
- NSArray* types = [NSArray arrayWithObject:NSFilenamesPboardType];
- NSString* available = [pasteboard() availableTypeFromArray:types];
- EXPECT_TRUE(available != nil);
-
- // Ensure the path is what we expect.
- NSArray* files = [pasteboard() propertyListForType:NSFilenamesPboardType];
- ASSERT_TRUE(files != nil);
- NSString* expectedPath = [files objectAtIndex:0];
- NSString* realPath = base::SysWideToNSString(testPath.ToWStringHack());
- EXPECT_NSEQ(expectedPath, realPath);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/draggable_button.mm b/chrome/browser/cocoa/draggable_button.mm
deleted file mode 100644
index 8eb7f98..0000000
--- a/chrome/browser/cocoa/draggable_button.mm
+++ /dev/null
@@ -1,150 +0,0 @@
-// 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 "chrome/browser/cocoa/draggable_button.h"
-
-#include "base/logging.h"
-#import "base/scoped_nsobject.h"
-
-namespace {
-
-// Code taken from <http://codereview.chromium.org/180036/diff/3001/3004>.
-// TODO(viettrungluu): Do we want common, standard code for drag hysteresis?
-const CGFloat kWebDragStartHysteresisX = 5.0;
-const CGFloat kWebDragStartHysteresisY = 5.0;
-const CGFloat kDragExpirationTimeout = 1.0;
-
-}
-
-@implementation DraggableButton
-
-@synthesize draggable = draggable_;
-
-- (id)initWithFrame:(NSRect)frame {
- if ((self = [super initWithFrame:frame])) {
- draggable_ = YES;
- }
- return self;
-}
-
-- (id)initWithCoder:(NSCoder*)coder {
- if ((self = [super initWithCoder:coder])) {
- draggable_ = YES;
- }
- return self;
-}
-
-// Determine whether a mouse down should turn into a drag; started as copy of
-// NSTableView code.
-- (BOOL)dragShouldBeginFromMouseDown:(NSEvent*)mouseDownEvent
- withExpiration:(NSDate*)expiration
- xHysteresis:(float)xHysteresis
- yHysteresis:(float)yHysteresis {
- if ([mouseDownEvent type] != NSLeftMouseDown) {
- return NO;
- }
-
- NSEvent* nextEvent = nil;
- NSEvent* firstEvent = nil;
- NSEvent* dragEvent = nil;
- NSEvent* mouseUp = nil;
- BOOL dragIt = NO;
-
- while ((nextEvent = [[self window]
- nextEventMatchingMask:(NSLeftMouseUpMask | NSLeftMouseDraggedMask)
- untilDate:expiration
- inMode:NSEventTrackingRunLoopMode
- dequeue:YES]) != nil) {
- if (firstEvent == nil) {
- firstEvent = nextEvent;
- }
- if ([nextEvent type] == NSLeftMouseDragged) {
- float deltax = ABS([nextEvent locationInWindow].x -
- [mouseDownEvent locationInWindow].x);
- float deltay = ABS([nextEvent locationInWindow].y -
- [mouseDownEvent locationInWindow].y);
- dragEvent = nextEvent;
- if (deltax >= xHysteresis) {
- dragIt = YES;
- break;
- }
- if (deltay >= yHysteresis) {
- dragIt = YES;
- break;
- }
- } else if ([nextEvent type] == NSLeftMouseUp) {
- mouseUp = nextEvent;
- break;
- }
- }
-
- // Since we've been dequeuing the events (If we don't, we'll never see
- // the mouse up...), we need to push some of the events back on.
- // It makes sense to put the first and last drag events and the mouse
- // up if there was one.
- if (mouseUp != nil) {
- [NSApp postEvent:mouseUp atStart:YES];
- }
- if (dragEvent != nil) {
- [NSApp postEvent:dragEvent atStart:YES];
- }
- if (firstEvent != mouseUp && firstEvent != dragEvent) {
- [NSApp postEvent:firstEvent atStart:YES];
- }
-
- return dragIt;
-}
-
-- (BOOL)dragShouldBeginFromMouseDown:(NSEvent*)mouseDownEvent
- withExpiration:(NSDate*)expiration {
- return [self dragShouldBeginFromMouseDown:mouseDownEvent
- withExpiration:expiration
- xHysteresis:kWebDragStartHysteresisX
- yHysteresis:kWebDragStartHysteresisY];
-}
-
-- (void)mouseUp:(NSEvent*)theEvent {
- if (!draggable_) {
- [super mouseUp:theEvent];
- return;
- }
-
- // There are non-drag cases where a mouseUp: may happen
- // (e.g. mouse-down, cmd-tab to another application, move mouse,
- // mouse-up). So we check.
- NSPoint viewLocal = [self convertPoint:[theEvent locationInWindow]
- fromView:[[self window] contentView]];
- if (NSPointInRect(viewLocal, [self bounds])) {
- [self performClick:self];
- }
-}
-
-// Mimic "begin a click" operation visually. Do NOT follow through
-// with normal button event handling.
-- (void)mouseDown:(NSEvent*)theEvent {
- if (draggable_) {
- [[self cell] setHighlighted:YES];
- NSDate* date = [NSDate dateWithTimeIntervalSinceNow:kDragExpirationTimeout];
- if ([self dragShouldBeginFromMouseDown:theEvent
- withExpiration:date]) {
- [self beginDrag:theEvent];
- [self endDrag];
- } else {
- [super mouseDown:theEvent];
- }
- } else {
- [super mouseDown:theEvent];
- }
-}
-
-- (void)beginDrag:(NSEvent*)dragEvent {
- // Must be overridden by subclasses.
- NOTREACHED();
-}
-
-- (void)endDrag {
- [[self cell] setHighlighted:NO];
-}
-
-@end // @interface DraggableButton
diff --git a/chrome/browser/cocoa/draggable_button_unittest.mm b/chrome/browser/cocoa/draggable_button_unittest.mm
deleted file mode 100644
index e6f153d..0000000
--- a/chrome/browser/cocoa/draggable_button_unittest.mm
+++ /dev/null
@@ -1,137 +0,0 @@
-// 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.
-
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/draggable_button.h"
-#import "chrome/browser/cocoa/test_event_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-@interface TestableDraggableButton : DraggableButton {
- NSUInteger dragCount_;
- BOOL wasTriggered_;
-}
-- (void)trigger:(id)sender;
-- (BOOL)wasTriggered;
-- (NSUInteger)dragCount;
-@end
-
-@implementation TestableDraggableButton
-- (id)initWithFrame:(NSRect)frame {
- if ((self = [super initWithFrame:frame])) {
- dragCount_ = 0;
- wasTriggered_ = NO;
- }
- return self;
-}
-- (void)beginDrag:(NSEvent*)theEvent {
- dragCount_++;
-}
-
-- (void)trigger:(id)sender {
- wasTriggered_ = YES;
-}
-
-- (BOOL)wasTriggered {
- return wasTriggered_;
-}
-
-- (NSUInteger)dragCount {
- return dragCount_;
-}
-@end
-
-class DraggableButtonTest : public CocoaTest {};
-
-// Make sure the basic case of "click" still works.
-TEST_F(DraggableButtonTest, DownUp) {
- scoped_nsobject<TestableDraggableButton> button(
- [[TestableDraggableButton alloc] initWithFrame:NSMakeRect(0,0,500,500)]);
- [[test_window() contentView] addSubview:button.get()];
- [button setTarget:button];
- [button setAction:@selector(trigger:)];
- EXPECT_FALSE([button wasTriggered]);
- NSEvent* downEvent =
- test_event_utils::MouseEventAtPoint(NSMakePoint(10,10),
- NSLeftMouseDown, 0);
- NSEvent* upEvent =
- test_event_utils::MouseEventAtPoint(NSMakePoint(10,10),
- NSLeftMouseUp, 0);
- [NSApp postEvent:upEvent atStart:YES];
- [test_window() sendEvent:downEvent];
- EXPECT_TRUE([button wasTriggered]); // confirms target/action fired
-}
-
-TEST_F(DraggableButtonTest, DraggableHysteresis) {
- scoped_nsobject<TestableDraggableButton> button(
- [[TestableDraggableButton alloc] initWithFrame:NSMakeRect(0,0,500,500)]);
- [[test_window() contentView] addSubview:button.get()];
- NSEvent* downEvent =
- test_event_utils::MouseEventAtPoint(NSMakePoint(10,10),
- NSLeftMouseDown,
- 0);
- NSEvent* firstMove =
- test_event_utils::MouseEventAtPoint(NSMakePoint(11,11),
- NSLeftMouseDragged,
- 0);
- NSEvent* firstUpEvent =
- test_event_utils::MouseEventAtPoint(NSMakePoint(11,11),
- NSLeftMouseUp,
- 0);
- NSEvent* secondMove =
- test_event_utils::MouseEventAtPoint(NSMakePoint(100,100),
- NSLeftMouseDragged,
- 0);
- NSEvent* secondUpEvent =
- test_event_utils::MouseEventAtPoint(NSMakePoint(100,100),
- NSLeftMouseUp,
- 0);
- // If the mouse only moves one pixel in each direction
- // it should not cause a drag.
- [NSApp postEvent:firstUpEvent atStart:YES];
- [NSApp postEvent:firstMove atStart:YES];
- [button mouseDown:downEvent];
- EXPECT_EQ(0U, [button dragCount]);
-
- // If the mouse moves > 5 pixels in either direciton
- // it should cause a drag.
- [NSApp postEvent:secondUpEvent atStart:YES];
- [NSApp postEvent:secondMove atStart:YES];
- [button mouseDown:downEvent];
- EXPECT_EQ(1U, [button dragCount]);
-}
-
-TEST_F(DraggableButtonTest, ResetState) {
- scoped_nsobject<TestableDraggableButton> button(
- [[TestableDraggableButton alloc] initWithFrame:NSMakeRect(0,0,500,500)]);
- [[test_window() contentView] addSubview:button.get()];
- NSEvent* downEvent =
- test_event_utils::MouseEventAtPoint(NSMakePoint(10,10),
- NSLeftMouseDown,
- 0);
- NSEvent* moveEvent =
- test_event_utils::MouseEventAtPoint(NSMakePoint(100,100),
- NSLeftMouseDragged,
- 0);
- NSEvent* upEvent =
- test_event_utils::MouseEventAtPoint(NSMakePoint(100,100),
- NSLeftMouseUp,
- 0);
- // If the mouse moves > 5 pixels in either direciton it should cause a drag.
- [NSApp postEvent:upEvent atStart:YES];
- [NSApp postEvent:moveEvent atStart:YES];
- [button mouseDown:downEvent];
-
- // The button should not be highlighted after the drag finishes.
- EXPECT_FALSE([[button cell] isHighlighted]);
- EXPECT_EQ(1U, [button dragCount]);
-
- // We should be able to initiate another drag immediately after the first one.
- [NSApp postEvent:upEvent atStart:YES];
- [NSApp postEvent:moveEvent atStart:YES];
- [button mouseDown:downEvent];
- EXPECT_EQ(2U, [button dragCount]);
- EXPECT_FALSE([[button cell] isHighlighted]);
-}
diff --git a/chrome/browser/cocoa/edit_search_engine_cocoa_controller.h b/chrome/browser/cocoa/edit_search_engine_cocoa_controller.h
deleted file mode 100644
index b1bfabc..0000000
--- a/chrome/browser/cocoa/edit_search_engine_cocoa_controller.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) 2009 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>
-
-class TemplateURL;
-
-#include "base/cocoa_protocols_mac.h"
-#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-#include "chrome/browser/search_engines/edit_search_engine_controller.h"
-
-// This controller presents a dialog that allows a user to add or edit a search
-// engine. If constructed with a nil |templateURL| then it is an add operation,
-// otherwise it will modify the passed URL. A |delegate| is necessary to
-// perform the actual database modifications, and should probably be an
-// instance of KeywordEditorModelObserver.
-
-@interface EditSearchEngineCocoaController :
- NSWindowController<NSWindowDelegate> {
- IBOutlet NSTextField* nameField_;
- IBOutlet NSTextField* keywordField_;
- IBOutlet NSTextField* urlField_;
- IBOutlet NSImageView* nameImage_;
- IBOutlet NSImageView* keywordImage_;
- IBOutlet NSImageView* urlImage_;
- IBOutlet NSButton* doneButton_;
- IBOutlet NSTextField* urlDescriptionField_;
- IBOutlet NSView* labelContainer_;
- IBOutlet NSBox* fieldAndImageContainer_;
-
- // Refs to the good and bad images used in the interface validation.
- scoped_nsobject<NSImage> goodImage_;
- scoped_nsobject<NSImage> badImage_;
-
- Profile* profile_; // weak
- const TemplateURL* templateURL_; // weak
- scoped_ptr<EditSearchEngineController> controller_;
-}
-
-- (id)initWithProfile:(Profile*)profile
- delegate:(EditSearchEngineControllerDelegate*)delegate
- templateURL:(const TemplateURL*)url;
-
-- (IBAction)cancel:(id)sender;
-- (IBAction)save:(id)sender;
-
-@end
-
-@interface EditSearchEngineCocoaController (ExposedForTesting)
-- (BOOL)validateFields;
-@end
diff --git a/chrome/browser/cocoa/edit_search_engine_cocoa_controller.mm b/chrome/browser/cocoa/edit_search_engine_cocoa_controller.mm
deleted file mode 100644
index 89050c6..0000000
--- a/chrome/browser/cocoa/edit_search_engine_cocoa_controller.mm
+++ /dev/null
@@ -1,187 +0,0 @@
-// 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 "chrome/browser/cocoa/edit_search_engine_cocoa_controller.h"
-
-#include "app/l10n_util_mac.h"
-#include "app/resource_bundle.h"
-#include "base/logging.h"
-#import "base/mac_util.h"
-#include "base/string16.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "grit/app_resources.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-
-namespace {
-
-void ShiftOriginY(NSView* view, CGFloat amount) {
- NSPoint origin = [view frame].origin;
- origin.y += amount;
- [view setFrameOrigin:origin];
-}
-
-} // namespace
-
-@implementation EditSearchEngineCocoaController
-
-- (id)initWithProfile:(Profile*)profile
- delegate:(EditSearchEngineControllerDelegate*)delegate
- templateURL:(const TemplateURL*)url {
- DCHECK(profile);
- NSString* nibpath = [mac_util::MainAppBundle()
- pathForResource:@"EditSearchEngine"
- ofType:@"nib"];
- if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
- profile_ = profile;
- templateURL_ = url;
- controller_.reset(
- new EditSearchEngineController(templateURL_, delegate, profile_));
- }
- return self;
-}
-
-- (void)awakeFromNib {
- DCHECK([self window]);
- DCHECK_EQ(self, [[self window] delegate]);
-
- // Make sure the url description field fits the text in it.
- CGFloat descriptionShift = [GTMUILocalizerAndLayoutTweaker
- sizeToFitFixedWidthTextField:urlDescriptionField_];
-
- // Move the label container above the url description.
- ShiftOriginY(labelContainer_, descriptionShift);
- // There was no way via view containment to use a helper view to move all
- // the textfields and images at once, most move them all on their own so
- // they stay above the url description.
- ShiftOriginY(nameField_, descriptionShift);
- ShiftOriginY(keywordField_, descriptionShift);
- ShiftOriginY(urlField_, descriptionShift);
- ShiftOriginY(nameImage_, descriptionShift);
- ShiftOriginY(keywordImage_, descriptionShift);
- ShiftOriginY(urlImage_, descriptionShift);
-
- // Resize the containing box for the name/keyword/url fields/images since it
- // also contains the url description (which just grew).
- [[fieldAndImageContainer_ contentView] setAutoresizesSubviews:NO];
- NSRect rect = [fieldAndImageContainer_ frame];
- rect.size.height += descriptionShift;
- [fieldAndImageContainer_ setFrame:rect];
- [[fieldAndImageContainer_ contentView] setAutoresizesSubviews:YES];
-
- // Resize the window.
- NSWindow* window = [self window];
- NSSize windowDelta = NSMakeSize(0, descriptionShift);
- [GTMUILocalizerAndLayoutTweaker
- resizeWindowWithoutAutoResizingSubViews:window
- delta:windowDelta];
-
- ResourceBundle& bundle = ResourceBundle::GetSharedInstance();
- goodImage_.reset([bundle.GetNativeImageNamed(IDR_INPUT_GOOD) retain]);
- badImage_.reset([bundle.GetNativeImageNamed(IDR_INPUT_ALERT) retain]);
- if (templateURL_) {
- // Defaults to |..._NEW_WINDOW_TITLE|.
- [window setTitle:l10n_util::GetNSString(
- IDS_SEARCH_ENGINES_EDITOR_EDIT_WINDOW_TITLE)];
- [nameField_ setStringValue:
- base::SysWideToNSString(templateURL_->short_name())];
- [keywordField_ setStringValue:
- base::SysWideToNSString(templateURL_->keyword())];
- [urlField_ setStringValue:
- base::SysWideToNSString(templateURL_->url()->DisplayURL())];
- [urlField_ setEnabled:(templateURL_->prepopulate_id() == 0)];
- }
- // When creating a new keyword, this will mark the fields as "invalid" and
- // will not let the user save. If this is an edit, then this will set all
- // the images to the "valid" state.
- [self validateFields];
-}
-
-// When the window closes, clean ourselves up.
-- (void)windowWillClose:(NSNotification*)notif {
- [self autorelease];
-}
-
-// Performs the logic of closing the window. If we are a sheet, then it ends the
-// modal session; otherwise, it closes the window.
-- (void)doClose {
- if ([[self window] isSheet]) {
- [NSApp endSheet:[self window]];
- } else {
- [[self window] close];
- }
-}
-
-- (IBAction)cancel:(id)sender {
- [self doClose];
-}
-
-- (IBAction)save:(id)sender {
- DCHECK([self validateFields]);
- string16 title = base::SysNSStringToUTF16([nameField_ stringValue]);
- string16 keyword = base::SysNSStringToUTF16([keywordField_ stringValue]);
- std::string url = base::SysNSStringToUTF8([urlField_ stringValue]);
- controller_->AcceptAddOrEdit(title, keyword, url);
- [self doClose];
-}
-
-// Delegate method for the text fields.
-
-- (void)controlTextDidChange:(NSNotification*)notif {
- [self validateFields];
-}
-
-- (void)controlTextDidEndEditing:(NSNotification*)notif {
- [self validateFields];
-}
-
-// Private --------------------------------------------------------------------
-
-// Sets the appropriate image and tooltip based on a boolean |valid|.
-- (void)setIsValid:(BOOL)valid
- toolTip:(int)messageID
- forImageView:(NSImageView*)imageView
- textField:(NSTextField*)textField {
- NSImage* image = (valid) ? goodImage_ : badImage_;
- [imageView setImage:image];
-
- NSString* toolTip = nil;
- if (!valid)
- toolTip = l10n_util::GetNSString(messageID);
- [textField setToolTip:toolTip];
- [imageView setToolTip:toolTip];
-}
-
-// This sets the image state for all the controls and enables or disables the
-// done button. Returns YES if all the fields are valid.
-- (BOOL)validateFields {
- string16 title = base::SysNSStringToUTF16([nameField_ stringValue]);
- BOOL titleValid = controller_->IsTitleValid(title);
- [self setIsValid:titleValid
- toolTip:IDS_SEARCH_ENGINES_INVALID_TITLE_TT
- forImageView:nameImage_
- textField:nameField_];
-
- string16 keyword = base::SysNSStringToUTF16([keywordField_ stringValue]);
- BOOL keywordValid = controller_->IsKeywordValid(keyword);
- [self setIsValid:keywordValid
- toolTip:IDS_SEARCH_ENGINES_INVALID_KEYWORD_TT
- forImageView:keywordImage_
- textField:keywordField_];
-
- std::string url = base::SysNSStringToUTF8([urlField_ stringValue]);
- BOOL urlValid = controller_->IsURLValid(url);
- [self setIsValid:urlValid
- toolTip:IDS_SEARCH_ENGINES_INVALID_URL_TT
- forImageView:urlImage_
- textField:urlField_];
-
- BOOL isValid = (titleValid && keywordValid && urlValid);
- [doneButton_ setEnabled:isValid];
- return isValid;
-}
-
-@end
diff --git a/chrome/browser/cocoa/edit_search_engine_cocoa_controller_unittest.mm b/chrome/browser/cocoa/edit_search_engine_cocoa_controller_unittest.mm
deleted file mode 100644
index 1ee7d99..0000000
--- a/chrome/browser/cocoa/edit_search_engine_cocoa_controller_unittest.mm
+++ /dev/null
@@ -1,233 +0,0 @@
-// Copyright (c) 2009 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 "app/l10n_util_mac.h"
-#include "base/scoped_nsobject.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/edit_search_engine_cocoa_controller.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/test/testing_profile.h"
-#include "grit/generated_resources.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-@interface FakeEditSearchEngineController : EditSearchEngineCocoaController {
-}
-@property (nonatomic, readonly) NSTextField* nameField;
-@property (nonatomic, readonly) NSTextField* keywordField;
-@property (nonatomic, readonly) NSTextField* urlField;
-@property (nonatomic, readonly) NSImageView* nameImage;
-@property (nonatomic, readonly) NSImageView* keywordImage;
-@property (nonatomic, readonly) NSImageView* urlImage;
-@property (nonatomic, readonly) NSButton* doneButton;
-@property (nonatomic, readonly) NSImage* goodImage;
-@property (nonatomic, readonly) NSImage* badImage;
-@end
-
-@implementation FakeEditSearchEngineController
-@synthesize nameField = nameField_;
-@synthesize keywordField = keywordField_;
-@synthesize urlField = urlField_;
-@synthesize nameImage = nameImage_;
-@synthesize keywordImage = keywordImage_;
-@synthesize urlImage = urlImage_;
-@synthesize doneButton = doneButton_;
-- (NSImage*)goodImage {
- return goodImage_.get();
-}
-- (NSImage*)badImage {
- return badImage_.get();
-}
-@end
-
-namespace {
-
-class EditSearchEngineControllerTest : public CocoaTest {
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
- TestingProfile* profile =
- static_cast<TestingProfile*>(browser_helper_.profile());
- profile->CreateTemplateURLModel();
- controller_ = [[FakeEditSearchEngineController alloc]
- initWithProfile:profile
- delegate:nil
- templateURL:nil];
- }
-
- virtual void TearDown() {
- // Force the window to load so we hit |-awakeFromNib| to register as the
- // window's delegate so that the controller can clean itself up in
- // |-windowWillClose:|.
- ASSERT_TRUE([controller_ window]);
-
- [controller_ close];
- CocoaTest::TearDown();
- }
-
- BrowserTestHelper browser_helper_;
- FakeEditSearchEngineController* controller_;
-};
-
-TEST_F(EditSearchEngineControllerTest, ValidImageOriginals) {
- EXPECT_FALSE([controller_ goodImage]);
- EXPECT_FALSE([controller_ badImage]);
-
- EXPECT_TRUE([controller_ window]); // Force the window to load.
-
- EXPECT_TRUE([[controller_ goodImage] isKindOfClass:[NSImage class]]);
- EXPECT_TRUE([[controller_ badImage] isKindOfClass:[NSImage class]]);
-
- // Test window title is set correctly.
- NSString* title = l10n_util::GetNSString(
- IDS_SEARCH_ENGINES_EDITOR_NEW_WINDOW_TITLE);
- EXPECT_NSEQ(title, [[controller_ window] title]);
-}
-
-TEST_F(EditSearchEngineControllerTest, SetImageViews) {
- EXPECT_TRUE([controller_ window]); // Force the window to load.
- EXPECT_EQ([controller_ badImage], [[controller_ nameImage] image]);
- // An empty keyword is not OK.
- EXPECT_EQ([controller_ badImage], [[controller_ keywordImage] image]);
- EXPECT_EQ([controller_ badImage], [[controller_ urlImage] image]);
-}
-
-// This test ensures that on creating a new keyword, we are in an "invalid"
-// state that cannot save.
-TEST_F(EditSearchEngineControllerTest, InvalidState) {
- EXPECT_TRUE([controller_ window]); // Force window to load.
- NSString* toolTip = nil;
- EXPECT_FALSE([controller_ validateFields]);
-
- EXPECT_NSEQ(@"", [[controller_ nameField] stringValue]);
- EXPECT_EQ([controller_ badImage], [[controller_ nameImage] image]);
- toolTip = l10n_util::GetNSString(IDS_SEARCH_ENGINES_INVALID_TITLE_TT);
- EXPECT_NSEQ(toolTip, [[controller_ nameField] toolTip]);
- EXPECT_NSEQ(toolTip, [[controller_ nameImage] toolTip]);
-
- // Keywords can not be empty strings.
- EXPECT_NSEQ(@"", [[controller_ keywordField] stringValue]);
- EXPECT_EQ([controller_ badImage], [[controller_ keywordImage] image]);
- EXPECT_TRUE([[controller_ keywordField] toolTip]);
- EXPECT_TRUE([[controller_ keywordImage] toolTip]);
-
- EXPECT_NSEQ(@"", [[controller_ urlField] stringValue]);
- EXPECT_EQ([controller_ badImage], [[controller_ urlImage] image]);
- toolTip = l10n_util::GetNSString(IDS_SEARCH_ENGINES_INVALID_URL_TT);
- EXPECT_NSEQ(toolTip, [[controller_ urlField] toolTip]);
- EXPECT_NSEQ(toolTip, [[controller_ urlImage] toolTip]);
-}
-
-// Tests that the single name field validates.
-TEST_F(EditSearchEngineControllerTest, ValidateName) {
- EXPECT_TRUE([controller_ window]); // Force window to load.
-
- EXPECT_EQ([controller_ badImage], [[controller_ nameImage] image]);
- EXPECT_FALSE([controller_ validateFields]);
- NSString* toolTip =
- l10n_util::GetNSString(IDS_SEARCH_ENGINES_INVALID_TITLE_TT);
- EXPECT_NSEQ(toolTip, [[controller_ nameField] toolTip]);
- EXPECT_NSEQ(toolTip, [[controller_ nameImage] toolTip]);
- [[controller_ nameField] setStringValue:@"Test Name"];
- EXPECT_FALSE([controller_ validateFields]);
- EXPECT_EQ([controller_ goodImage], [[controller_ nameImage] image]);
- EXPECT_FALSE([[controller_ nameField] toolTip]);
- EXPECT_FALSE([[controller_ nameImage] toolTip]);
- EXPECT_FALSE([[controller_ doneButton] isEnabled]);
-}
-
-// The keyword field is not valid if it is empty.
-TEST_F(EditSearchEngineControllerTest, ValidateKeyword) {
- EXPECT_TRUE([controller_ window]); // Force window load.
-
- EXPECT_EQ([controller_ badImage], [[controller_ keywordImage] image]);
- EXPECT_FALSE([controller_ validateFields]);
- EXPECT_TRUE([[controller_ keywordField] toolTip]);
- EXPECT_TRUE([[controller_ keywordImage] toolTip]);
- [[controller_ keywordField] setStringValue:@"foobar"];
- EXPECT_FALSE([controller_ validateFields]);
- EXPECT_EQ([controller_ goodImage], [[controller_ keywordImage] image]);
- EXPECT_FALSE([[controller_ keywordField] toolTip]);
- EXPECT_FALSE([[controller_ keywordImage] toolTip]);
- EXPECT_FALSE([[controller_ doneButton] isEnabled]);
-}
-
-// Tests that the URL field validates.
-TEST_F(EditSearchEngineControllerTest, ValidateURL) {
- EXPECT_TRUE([controller_ window]); // Force window to load.
-
- EXPECT_EQ([controller_ badImage], [[controller_ urlImage] image]);
- EXPECT_FALSE([controller_ validateFields]);
- NSString* toolTip =
- l10n_util::GetNSString(IDS_SEARCH_ENGINES_INVALID_URL_TT);
- EXPECT_NSEQ(toolTip, [[controller_ urlField] toolTip]);
- EXPECT_NSEQ(toolTip, [[controller_ urlImage] toolTip]);
- [[controller_ urlField] setStringValue:@"http://foo-bar.com"];
- EXPECT_FALSE([controller_ validateFields]);
- EXPECT_EQ([controller_ goodImage], [[controller_ urlImage] image]);
- EXPECT_FALSE([[controller_ urlField] toolTip]);
- EXPECT_FALSE([[controller_ urlImage] toolTip]);
- EXPECT_FALSE([[controller_ doneButton] isEnabled]);
-}
-
-// Tests that if the user enters all valid data that the UI reflects that
-// and that they can save.
-TEST_F(EditSearchEngineControllerTest, ValidateFields) {
- EXPECT_TRUE([controller_ window]); // Force window to load.
-
- // State before entering data.
- EXPECT_EQ([controller_ badImage], [[controller_ nameImage] image]);
- EXPECT_EQ([controller_ badImage], [[controller_ keywordImage] image]);
- EXPECT_EQ([controller_ badImage], [[controller_ urlImage] image]);
- EXPECT_FALSE([[controller_ doneButton] isEnabled]);
- EXPECT_FALSE([controller_ validateFields]);
-
- [[controller_ nameField] setStringValue:@"Test Name"];
- EXPECT_FALSE([controller_ validateFields]);
- EXPECT_EQ([controller_ goodImage], [[controller_ nameImage] image]);
- EXPECT_FALSE([[controller_ doneButton] isEnabled]);
-
- [[controller_ keywordField] setStringValue:@"foobar"];
- EXPECT_FALSE([controller_ validateFields]);
- EXPECT_EQ([controller_ goodImage], [[controller_ keywordImage] image]);
- EXPECT_FALSE([[controller_ doneButton] isEnabled]);
-
- // Once the URL is entered, we should have all 3 valid fields.
- [[controller_ urlField] setStringValue:@"http://foo-bar.com"];
- EXPECT_TRUE([controller_ validateFields]);
- EXPECT_EQ([controller_ goodImage], [[controller_ urlImage] image]);
- EXPECT_TRUE([[controller_ doneButton] isEnabled]);
-}
-
-// Tests editing an existing TemplateURL.
-TEST_F(EditSearchEngineControllerTest, EditTemplateURL) {
- TemplateURL url;
- url.set_short_name(L"Foobar");
- url.set_keyword(L"keyword");
- std::string urlString = TemplateURLRef::DisplayURLToURLRef(
- L"http://foo-bar.com");
- url.SetURL(urlString, 0, 1);
- TestingProfile* profile = browser_helper_.profile();
- FakeEditSearchEngineController *controller =
- [[FakeEditSearchEngineController alloc] initWithProfile:profile
- delegate:nil
- templateURL:&url];
- EXPECT_TRUE([controller window]);
- NSString* title = l10n_util::GetNSString(
- IDS_SEARCH_ENGINES_EDITOR_EDIT_WINDOW_TITLE);
- EXPECT_NSEQ(title, [[controller window] title]);
- NSString* nameString = [[controller nameField] stringValue];
- EXPECT_NSEQ(@"Foobar", nameString);
- NSString* keywordString = [[controller keywordField] stringValue];
- EXPECT_NSEQ(@"keyword", keywordString);
- NSString* urlValueString = [[controller urlField] stringValue];
- EXPECT_NSEQ(@"http://foo-bar.com", urlValueString);
- EXPECT_TRUE([controller validateFields]);
- [controller close];
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/encoding_menu_controller_delegate_mac.h b/chrome/browser/cocoa/encoding_menu_controller_delegate_mac.h
deleted file mode 100644
index cca76b5..0000000
--- a/chrome/browser/cocoa/encoding_menu_controller_delegate_mac.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_ENCODING_MENU_CONTROLLER_DELEGATE_MAC_H_
-#define CHROME_BROWSER_COCOA_ENCODING_MENU_CONTROLLER_DELEGATE_MAC_H_
-#pragma once
-
-#include "base/basictypes.h" // For DISALLOW_IMPLICIT_CONSTRUCTORS
-
-@class NSMenu;
-class Profile;
-
-// The Windows version of this class manages the Encoding Menu, but since Cocoa
-// does that for us automagically, the only thing left to do is construct
-// the encoding menu.
-class EncodingMenuControllerDelegate {
- public:
- static void BuildEncodingMenu(Profile *profile, NSMenu* encoding_menu);
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(EncodingMenuControllerDelegate);
-};
-
-#endif // CHROME_BROWSER_COCOA_ENCODING_MENU_CONTROLLER_DELEGATE_MAC_H_
diff --git a/chrome/browser/cocoa/encoding_menu_controller_delegate_mac.mm b/chrome/browser/cocoa/encoding_menu_controller_delegate_mac.mm
deleted file mode 100644
index 4540477..0000000
--- a/chrome/browser/cocoa/encoding_menu_controller_delegate_mac.mm
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/encoding_menu_controller_delegate_mac.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/string16.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/encoding_menu_controller.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/ui/browser.h"
-
-namespace {
-
-void AddSeparatorToMenu(NSMenu *parent_menu) {
- NSMenuItem* separator = [NSMenuItem separatorItem];
- [parent_menu addItem:separator];
-}
-
-void AppendMenuItem(NSMenu *parent_menu, int tag, NSString *title) {
-
- NSMenuItem* item = [[[NSMenuItem alloc] initWithTitle:title
- action:nil
- keyEquivalent:@""] autorelease];
- [parent_menu addItem:item];
- [item setAction:@selector(commandDispatch:)];
- [item setTag:tag];
-}
-
-} // namespace
-
-// static
-void EncodingMenuControllerDelegate::BuildEncodingMenu(Profile *profile,
- NSMenu* encoding_menu) {
- DCHECK(profile);
-
- typedef EncodingMenuController::EncodingMenuItemList EncodingMenuItemList;
- EncodingMenuItemList menuItems;
- EncodingMenuController controller;
- controller.GetEncodingMenuItems(profile, &menuItems);
-
- for (EncodingMenuItemList::iterator it = menuItems.begin();
- it != menuItems.end();
- ++it) {
- int item_id = it->first;
- string16 &localized_title_string16 = it->second;
-
- if (item_id == 0) {
- AddSeparatorToMenu(encoding_menu);
- } else {
- NSString *localized_title =
- base::SysUTF16ToNSString(localized_title_string16);
- AppendMenuItem(encoding_menu, item_id, localized_title);
- }
- }
-
-}
diff --git a/chrome/browser/cocoa/event_utils.h b/chrome/browser/cocoa/event_utils.h
deleted file mode 100644
index fb33cd0..0000000
--- a/chrome/browser/cocoa/event_utils.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_EVENT_UTILS_H_
-#define CHROME_BROWSER_COCOA_EVENT_UTILS_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "webkit/glue/window_open_disposition.h"
-
-namespace event_utils {
-
-// Retrieves the WindowOpenDisposition used to open a link from a user gesture
-// represented by |event|. For example, a Cmd+Click would mean open the
-// associated link in a background tab.
-WindowOpenDisposition WindowOpenDispositionFromNSEvent(NSEvent* event);
-
-// Retrieves the WindowOpenDisposition used to open a link from a user gesture
-// represented by |event|, but instead use the modifier flags given by |flags|,
-// which is the same format as |-NSEvent modifierFlags|. This allows
-// substitution of the modifiers without having to create a new event from
-// scratch.
-WindowOpenDisposition WindowOpenDispositionFromNSEventWithFlags(
- NSEvent* event, NSUInteger flags);
-
-} // namespace event_utils
-
-#endif // CHROME_BROWSER_COCOA_EVENT_UTILS_H_
diff --git a/chrome/browser/cocoa/event_utils.mm b/chrome/browser/cocoa/event_utils.mm
deleted file mode 100644
index 2f65d9a..0000000
--- a/chrome/browser/cocoa/event_utils.mm
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/event_utils.h"
-
-namespace event_utils {
-
-WindowOpenDisposition WindowOpenDispositionFromNSEvent(NSEvent* event) {
- NSUInteger modifiers = [event modifierFlags];
- return WindowOpenDispositionFromNSEventWithFlags(event, modifiers);
-}
-
-WindowOpenDisposition WindowOpenDispositionFromNSEventWithFlags(
- NSEvent* event, NSUInteger flags) {
- if ([event buttonNumber] == 2 || flags & NSCommandKeyMask)
- return flags & NSShiftKeyMask ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB;
- return flags & NSShiftKeyMask ? NEW_WINDOW : CURRENT_TAB;
-}
-
-} // namespace event_utils
diff --git a/chrome/browser/cocoa/event_utils_unittest.mm b/chrome/browser/cocoa/event_utils_unittest.mm
deleted file mode 100644
index ff12416..0000000
--- a/chrome/browser/cocoa/event_utils_unittest.mm
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) 2009 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 <objc/objc-class.h>
-
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/cocoa/event_utils.h"
-#include "chrome/browser/cocoa/test_event_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-// We provide a donor class with a specially modified |modifierFlags|
-// implementation that we swap with NSEvent's. This is because we can't create a
-// NSEvent that represents a middle click with modifiers.
-@interface TestEvent : NSObject
-@end
-@implementation TestEvent
-- (NSUInteger)modifierFlags { return NSShiftKeyMask; }
-@end
-
-namespace {
-
-class EventUtilsTest : public CocoaTest {
-};
-
-TEST_F(EventUtilsTest, TestWindowOpenDispositionFromNSEvent) {
- // Left Click = same tab.
- NSEvent* me = test_event_utils::MakeMouseEvent(NSLeftMouseUp, 0);
- EXPECT_EQ(CURRENT_TAB, event_utils::WindowOpenDispositionFromNSEvent(me));
-
- // Middle Click = new background tab.
- me = test_event_utils::MakeMouseEvent(NSOtherMouseUp, 0);
- EXPECT_EQ(NEW_BACKGROUND_TAB,
- event_utils::WindowOpenDispositionFromNSEvent(me));
-
- // Shift+Middle Click = new foreground tab.
- {
- ScopedClassSwizzler swizzler([NSEvent class], [TestEvent class],
- @selector(modifierFlags));
- me = test_event_utils::MakeMouseEvent(NSOtherMouseUp, NSShiftKeyMask);
- EXPECT_EQ(NEW_FOREGROUND_TAB,
- event_utils::WindowOpenDispositionFromNSEvent(me));
- }
-
- // Cmd+Left Click = new background tab.
- me = test_event_utils::MakeMouseEvent(NSLeftMouseUp, NSCommandKeyMask);
- EXPECT_EQ(NEW_BACKGROUND_TAB,
- event_utils::WindowOpenDispositionFromNSEvent(me));
-
- // Cmd+Shift+Left Click = new foreground tab.
- me = test_event_utils::MakeMouseEvent(NSLeftMouseUp, NSCommandKeyMask | NSShiftKeyMask);
- EXPECT_EQ(NEW_FOREGROUND_TAB,
- event_utils::WindowOpenDispositionFromNSEvent(me));
-
- // Shift+Left Click = new window
- me = test_event_utils::MakeMouseEvent(NSLeftMouseUp, NSShiftKeyMask);
- EXPECT_EQ(NEW_WINDOW, event_utils::WindowOpenDispositionFromNSEvent(me));
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/extension_installed_bubble_bridge.h b/chrome/browser/cocoa/extension_installed_bubble_bridge.h
deleted file mode 100644
index d878d70..0000000
--- a/chrome/browser/cocoa/extension_installed_bubble_bridge.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// 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.
-
-// C++ bridge function to connect ExtensionInstallUI to the Cocoa-based
-// extension installed bubble.
-
-#ifndef CHROME_BROWSER_COCOA_EXTENSION_INSTALLED_BUBBLE_BRIDGE_H_
-#define CHROME_BROWSER_COCOA_EXTENSION_INSTALLED_BUBBLE_BRIDGE_H_
-#pragma once
-
-#include "gfx/native_widget_types.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-class Browser;
-class Extension;
-
-namespace ExtensionInstalledBubbleCocoa {
-
-// This function is called by the ExtensionInstallUI when an extension has been
-// installed.
-void ShowExtensionInstalledBubble(gfx::NativeWindow window,
- const Extension* extension,
- Browser* browser,
- SkBitmap icon);
-}
-
-#endif // CHROME_BROWSER_COCOA_EXTENSION_INSTALLED_BUBBLE_BRIDGE_H_
diff --git a/chrome/browser/cocoa/extension_installed_bubble_bridge.mm b/chrome/browser/cocoa/extension_installed_bubble_bridge.mm
deleted file mode 100644
index eadf9ac..0000000
--- a/chrome/browser/cocoa/extension_installed_bubble_bridge.mm
+++ /dev/null
@@ -1,25 +0,0 @@
-// 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>
-
-#import "extension_installed_bubble_bridge.h"
-
-#import "chrome/browser/cocoa/extension_installed_bubble_controller.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/common/extensions/extension.h"
-
-void ExtensionInstalledBubbleCocoa::ShowExtensionInstalledBubble(
- gfx::NativeWindow window,
- const Extension* extension,
- Browser* browser,
- SkBitmap icon) {
- // The controller is deallocated when the window is closed, so no need to
- // worry about it here.
- [[ExtensionInstalledBubbleController alloc]
- initWithParentWindow:window
- extension:extension
- browser:browser
- icon:icon];
-}
diff --git a/chrome/browser/cocoa/extension_installed_bubble_controller.h b/chrome/browser/cocoa/extension_installed_bubble_controller.h
deleted file mode 100644
index 7d0417f..0000000
--- a/chrome/browser/cocoa/extension_installed_bubble_controller.h
+++ /dev/null
@@ -1,112 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_EXTENSION_INSTALLED_BUBBLE_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_EXTENSION_INSTALLED_BUBBLE_CONTROLLER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/cocoa_protocols_mac.h"
-#include "base/scoped_ptr.h"
-#import "chrome/browser/cocoa/browser_window_controller.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-class Browser;
-class Extension;
-class ExtensionLoadedNotificationObserver;
-@class HoverCloseButton;
-@class InfoBubbleView;
-
-namespace extension_installed_bubble {
-
-// Maximum height or width of extension's icon (corresponds to Windows & GTK).
-const int kIconSize = 43;
-
-// Outer vertical margin for text, icon, and closing x.
-const int kOuterVerticalMargin = 15;
-
-// Inner vertical margin for text messages.
-const int kInnerVerticalMargin = 10;
-
-// We use a different kind of notification for each of these extension types.
-typedef enum {
- kBrowserAction,
- kGeneric,
- kOmniboxKeyword,
- kPageAction
-} ExtensionType;
-
-}
-
-// Controller for the extension installed bubble. This bubble pops up after
-// an extension has been installed to inform the user that the install happened
-// properly, and to let the user know how to manage this extension in the
-// future.
-@interface ExtensionInstalledBubbleController :
- NSWindowController<NSWindowDelegate> {
- @private
- NSWindow* parentWindow_; // weak
- const Extension* extension_; // weak
- Browser* browser_; // weak
- scoped_nsobject<NSImage> icon_;
-
- extension_installed_bubble::ExtensionType type_;
-
- // We need to remove the page action immediately when the browser window
- // closes while this bubble is still open, so the bubble's closing animation
- // doesn't overlap browser destruction.
- BOOL pageActionRemoved_;
-
- // Lets us register for EXTENSION_LOADED notifications. The actual
- // notifications are sent to the observer object, which proxies them
- // back to the controller.
- scoped_ptr<ExtensionLoadedNotificationObserver> extensionObserver_;
-
- // References below are weak, being obtained from the nib.
- IBOutlet InfoBubbleView* infoBubbleView_;
- IBOutlet HoverCloseButton* closeButton_;
- IBOutlet NSImageView* iconImage_;
- IBOutlet NSTextField* extensionInstalledMsg_;
- // Only shown for page actions and omnibox keywords.
- IBOutlet NSTextField* extraInfoMsg_;
- IBOutlet NSTextField* extensionInstalledInfoMsg_;
-}
-
-@property (nonatomic, readonly) const Extension* extension;
-@property (nonatomic) BOOL pageActionRemoved;
-
-// Initialize the window, and then create observers to wait for the extension
-// to complete loading, or the browser window to close.
-- (id)initWithParentWindow:(NSWindow*)parentWindow
- extension:(const Extension*)extension
- browser:(Browser*)browser
- icon:(SkBitmap)icon;
-
-// Action for close button.
-- (IBAction)closeWindow:(id)sender;
-
-// Displays the extension installed bubble. This callback is triggered by
-// the extensionObserver when the extension has completed loading.
-- (void)showWindow:(id)sender;
-
-// Clears our weak pointer to the Extension. This callback is triggered by
-// the extensionObserver when the extension is unloaded.
-- (void)extensionUnloaded:(id)sender;
-
-@end
-
-@interface ExtensionInstalledBubbleController(ExposedForTesting)
-
-- (void)removePageActionPreviewIfNecessary;
-- (NSWindow*)initializeWindow;
-- (int)calculateWindowHeight;
-- (void)setMessageFrames:(int)newWindowHeight;
-- (NSRect)getExtensionInstalledMsgFrame;
-- (NSRect)getExtraInfoMsgFrame;
-- (NSRect)getExtensionInstalledInfoMsgFrame;
-
-@end // ExtensionInstalledBubbleController(ExposedForTesting)
-
-#endif // CHROME_BROWSER_COCOA_EXTENSION_INSTALLED_BUBBLE_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/extension_installed_bubble_controller.mm b/chrome/browser/cocoa/extension_installed_bubble_controller.mm
deleted file mode 100644
index adb92ca..0000000
--- a/chrome/browser/cocoa/extension_installed_bubble_controller.mm
+++ /dev/null
@@ -1,374 +0,0 @@
-// 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 "extension_installed_bubble_controller.h"
-
-#include "app/l10n_util.h"
-#include "base/mac_util.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/cocoa/browser_window_cocoa.h"
-#include "chrome/browser/cocoa/browser_window_controller.h"
-#include "chrome/browser/cocoa/extensions/browser_actions_controller.h"
-#include "chrome/browser/cocoa/hover_close_button.h"
-#include "chrome/browser/cocoa/info_bubble_view.h"
-#include "chrome/browser/cocoa/location_bar/location_bar_view_mac.h"
-#include "chrome/browser/cocoa/toolbar_controller.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_action.h"
-#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
-#include "grit/generated_resources.h"
-#import "skia/ext/skia_utils_mac.h"
-#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-
-
-// C++ class that receives EXTENSION_LOADED notifications and proxies them back
-// to |controller|.
-class ExtensionLoadedNotificationObserver : public NotificationObserver {
- public:
- ExtensionLoadedNotificationObserver(
- ExtensionInstalledBubbleController* controller, Profile* profile)
- : controller_(controller) {
- registrar_.Add(this, NotificationType::EXTENSION_LOADED,
- Source<Profile>(profile));
- registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
- Source<Profile>(profile));
- }
-
- private:
- // NotificationObserver implementation. Tells the controller to start showing
- // its window on the main thread when the extension has finished loading.
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- if (type == NotificationType::EXTENSION_LOADED) {
- const Extension* extension = Details<const Extension>(details).ptr();
- if (extension == [controller_ extension]) {
- [controller_ performSelectorOnMainThread:@selector(showWindow:)
- withObject:controller_
- waitUntilDone:NO];
- }
- } else if (type == NotificationType::EXTENSION_UNLOADED) {
- const Extension* extension = Details<const Extension>(details).ptr();
- if (extension == [controller_ extension]) {
- [controller_ performSelectorOnMainThread:@selector(extensionUnloaded:)
- withObject:controller_
- waitUntilDone:NO];
- }
- } else {
- NOTREACHED() << "Received unexpected notification.";
- }
- }
-
- NotificationRegistrar registrar_;
- ExtensionInstalledBubbleController* controller_; // weak, owns us
-};
-
-@implementation ExtensionInstalledBubbleController
-
-@synthesize extension = extension_;
-@synthesize pageActionRemoved = pageActionRemoved_; // Exposed for unit test.
-
-- (id)initWithParentWindow:(NSWindow*)parentWindow
- extension:(const Extension*)extension
- browser:(Browser*)browser
- icon:(SkBitmap)icon {
- NSString* nibPath =
- [mac_util::MainAppBundle() pathForResource:@"ExtensionInstalledBubble"
- ofType:@"nib"];
- if ((self = [super initWithWindowNibPath:nibPath owner:self])) {
- DCHECK(parentWindow);
- parentWindow_ = parentWindow;
- DCHECK(extension);
- extension_ = extension;
- DCHECK(browser);
- browser_ = browser;
- icon_.reset([gfx::SkBitmapToNSImage(icon) retain]);
- pageActionRemoved_ = NO;
-
- if (!extension->omnibox_keyword().empty()) {
- type_ = extension_installed_bubble::kOmniboxKeyword;
- } else if (extension->browser_action()) {
- type_ = extension_installed_bubble::kBrowserAction;
- } else if (extension->page_action() &&
- !extension->page_action()->default_icon_path().empty()) {
- type_ = extension_installed_bubble::kPageAction;
- } else {
- NOTREACHED(); // kGeneric installs handled in the extension_install_ui.
- }
-
- // Start showing window only after extension has fully loaded.
- extensionObserver_.reset(new ExtensionLoadedNotificationObserver(
- self, browser->profile()));
- }
- return self;
-}
-
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [super dealloc];
-}
-
-- (void)close {
- [parentWindow_ removeChildWindow:[self window]];
- [super close];
-}
-
-- (void)windowWillClose:(NSNotification*)notification {
- // Turn off page action icon preview when the window closes, unless we
- // already removed it when the window resigned key status.
- [self removePageActionPreviewIfNecessary];
- extension_ = NULL;
- browser_ = NULL;
- parentWindow_ = nil;
- // We caught a close so we don't need to watch for the parent closing.
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [self autorelease];
-}
-
-// The controller is the delegate of the window, so it receives "did resign
-// key" notifications. When key is resigned, close the window.
-- (void)windowDidResignKey:(NSNotification*)notification {
- NSWindow* window = [self window];
- DCHECK_EQ([notification object], window);
- DCHECK([window isVisible]);
-
- // If the browser window is closing, we need to remove the page action
- // immediately, otherwise the closing animation may overlap with
- // browser destruction.
- [self removePageActionPreviewIfNecessary];
- [self close];
-}
-
-- (IBAction)closeWindow:(id)sender {
- DCHECK([[self window] isVisible]);
- [self close];
-}
-
-// Extracted to a function here so that it can be overwritten for unit
-// testing.
-- (void)removePageActionPreviewIfNecessary {
- if (!extension_ || !extension_->page_action() || pageActionRemoved_)
- return;
- pageActionRemoved_ = YES;
-
- BrowserWindowCocoa* window =
- static_cast<BrowserWindowCocoa*>(browser_->window());
- LocationBarViewMac* locationBarView =
- [window->cocoa_controller() locationBarBridge];
- locationBarView->SetPreviewEnabledPageAction(extension_->page_action(),
- false); // disables preview.
-}
-
-// The extension installed bubble points at the browser action icon or the
-// page action icon (shown as a preview), depending on the extension type.
-// We need to calculate the location of these icons and the size of the
-// message itself (which varies with the title of the extension) in order
-// to figure out the origin point for the extension installed bubble.
-// TODO(mirandac): add framework to easily test extension UI components!
-- (NSPoint)calculateArrowPoint {
- BrowserWindowCocoa* window =
- static_cast<BrowserWindowCocoa*>(browser_->window());
- NSPoint arrowPoint = NSZeroPoint;
-
- switch(type_) {
- case extension_installed_bubble::kOmniboxKeyword: {
- LocationBarViewMac* locationBarView =
- [window->cocoa_controller() locationBarBridge];
- arrowPoint = locationBarView->GetPageInfoBubblePoint();
- break;
- }
- case extension_installed_bubble::kBrowserAction: {
- BrowserActionsController* controller =
- [[window->cocoa_controller() toolbarController]
- browserActionsController];
- arrowPoint = [controller popupPointForBrowserAction:extension_];
- break;
- }
- case extension_installed_bubble::kPageAction: {
- LocationBarViewMac* locationBarView =
- [window->cocoa_controller() locationBarBridge];
-
- // Tell the location bar to show a preview of the page action icon, which
- // would ordinarily only be displayed on a page of the appropriate type.
- // We remove this preview when the extension installed bubble closes.
- locationBarView->SetPreviewEnabledPageAction(extension_->page_action(),
- true);
-
- // Find the center of the bottom of the page action icon.
- arrowPoint =
- locationBarView->GetPageActionBubblePoint(extension_->page_action());
- break;
- }
- default: {
- NOTREACHED() << "Generic extension type not allowed in install bubble.";
- }
- }
- return arrowPoint;
-}
-
-// We want this to be a child of a browser window. addChildWindow:
-// (called from this function) will bring the window on-screen;
-// unfortunately, [NSWindowController showWindow:] will also bring it
-// on-screen (but will cause unexpected changes to the window's
-// position). We cannot have an addChildWindow: and a subsequent
-// showWindow:. Thus, we have our own version.
-- (void)showWindow:(id)sender {
- // Generic extensions get an infobar rather than a bubble.
- DCHECK(type_ != extension_installed_bubble::kGeneric);
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // Load nib and calculate height based on messages to be shown.
- NSWindow* window = [self initializeWindow];
- int newWindowHeight = [self calculateWindowHeight];
- [infoBubbleView_ setFrameSize:NSMakeSize(
- NSWidth([[window contentView] bounds]), newWindowHeight)];
- NSSize windowDelta = NSMakeSize(
- 0, newWindowHeight - NSHeight([[window contentView] bounds]));
- windowDelta = [[window contentView] convertSize:windowDelta toView:nil];
- NSRect newFrame = [window frame];
- newFrame.size.height += windowDelta.height;
- [window setFrame:newFrame display:NO];
-
- // Now that we have resized the window, adjust y pos of the messages.
- [self setMessageFrames:newWindowHeight];
-
- // Find window origin, taking into account bubble size and arrow location.
- NSPoint origin =
- [parentWindow_ convertBaseToScreen:[self calculateArrowPoint]];
- NSSize offsets = NSMakeSize(info_bubble::kBubbleArrowXOffset +
- info_bubble::kBubbleArrowWidth / 2.0, 0);
- offsets = [[window contentView] convertSize:offsets toView:nil];
- if ([infoBubbleView_ arrowLocation] == info_bubble::kTopRight)
- origin.x -= NSWidth([window frame]) - offsets.width;
- origin.y -= NSHeight([window frame]);
- [window setFrameOrigin:origin];
-
- [parentWindow_ addChildWindow:window
- ordered:NSWindowAbove];
- [window makeKeyAndOrderFront:self];
-}
-
-// Finish nib loading, set arrow location and load icon into window. This
-// function is exposed for unit testing.
-- (NSWindow*)initializeWindow {
- NSWindow* window = [self window]; // completes nib load
-
- if (type_ == extension_installed_bubble::kOmniboxKeyword) {
- [infoBubbleView_ setArrowLocation:info_bubble::kTopLeft];
- } else {
- [infoBubbleView_ setArrowLocation:info_bubble::kTopRight];
- }
-
- // Set appropriate icon, resizing if necessary.
- if ([icon_ size].width > extension_installed_bubble::kIconSize) {
- [icon_ setSize:NSMakeSize(extension_installed_bubble::kIconSize,
- extension_installed_bubble::kIconSize)];
- }
- [iconImage_ setImage:icon_];
- [iconImage_ setNeedsDisplay:YES];
- return window;
- }
-
-// Calculate the height of each install message, resizing messages in their
-// frames to fit window width. Return the new window height, based on the
-// total of all message heights.
-- (int)calculateWindowHeight {
- // Adjust the window height to reflect the sum height of all messages
- // and vertical padding.
- int newWindowHeight = 2 * extension_installed_bubble::kOuterVerticalMargin;
-
- // First part of extension installed message.
- [extensionInstalledMsg_ setStringValue:l10n_util::GetNSStringF(
- IDS_EXTENSION_INSTALLED_HEADING, UTF8ToUTF16(extension_->name()))];
- [GTMUILocalizerAndLayoutTweaker
- sizeToFitFixedWidthTextField:extensionInstalledMsg_];
- newWindowHeight += [extensionInstalledMsg_ frame].size.height +
- extension_installed_bubble::kInnerVerticalMargin;
-
- // If type is page action, include a special message about page actions.
- if (type_ == extension_installed_bubble::kPageAction) {
- [extraInfoMsg_ setHidden:NO];
- [[extraInfoMsg_ cell]
- setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
- [GTMUILocalizerAndLayoutTweaker
- sizeToFitFixedWidthTextField:extraInfoMsg_];
- newWindowHeight += [extraInfoMsg_ frame].size.height +
- extension_installed_bubble::kInnerVerticalMargin;
- }
-
- // If type is omnibox keyword, include a special message about the keyword.
- if (type_ == extension_installed_bubble::kOmniboxKeyword) {
- [extraInfoMsg_ setStringValue:l10n_util::GetNSStringF(
- IDS_EXTENSION_INSTALLED_OMNIBOX_KEYWORD_INFO,
- UTF8ToUTF16(extension_->omnibox_keyword()))];
- [extraInfoMsg_ setHidden:NO];
- [[extraInfoMsg_ cell]
- setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
- [GTMUILocalizerAndLayoutTweaker
- sizeToFitFixedWidthTextField:extraInfoMsg_];
- newWindowHeight += [extraInfoMsg_ frame].size.height +
- extension_installed_bubble::kInnerVerticalMargin;
- }
-
- // Second part of extension installed message.
- [[extensionInstalledInfoMsg_ cell]
- setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
- [GTMUILocalizerAndLayoutTweaker
- sizeToFitFixedWidthTextField:extensionInstalledInfoMsg_];
- newWindowHeight += [extensionInstalledInfoMsg_ frame].size.height;
-
- return newWindowHeight;
-}
-
-// Adjust y-position of messages to sit properly in new window height.
-- (void)setMessageFrames:(int)newWindowHeight {
- // The extension messages will always be shown.
- NSRect extensionMessageFrame1 = [extensionInstalledMsg_ frame];
- NSRect extensionMessageFrame2 = [extensionInstalledInfoMsg_ frame];
-
- extensionMessageFrame1.origin.y = newWindowHeight - (
- extensionMessageFrame1.size.height +
- extension_installed_bubble::kOuterVerticalMargin);
- [extensionInstalledMsg_ setFrame:extensionMessageFrame1];
- if (type_ == extension_installed_bubble::kPageAction ||
- type_ == extension_installed_bubble::kOmniboxKeyword) {
- // The extra message is only shown when appropriate.
- NSRect extraMessageFrame = [extraInfoMsg_ frame];
- extraMessageFrame.origin.y = extensionMessageFrame1.origin.y - (
- extraMessageFrame.size.height +
- extension_installed_bubble::kInnerVerticalMargin);
- [extraInfoMsg_ setFrame:extraMessageFrame];
- extensionMessageFrame2.origin.y = extraMessageFrame.origin.y - (
- extensionMessageFrame2.size.height +
- extension_installed_bubble::kInnerVerticalMargin);
- } else {
- extensionMessageFrame2.origin.y = extensionMessageFrame1.origin.y - (
- extensionMessageFrame2.size.height +
- extension_installed_bubble::kInnerVerticalMargin);
- }
- [extensionInstalledInfoMsg_ setFrame:extensionMessageFrame2];
-}
-
-// Exposed for unit testing.
-- (NSRect)getExtensionInstalledMsgFrame {
- return [extensionInstalledMsg_ frame];
-}
-
-- (NSRect)getExtraInfoMsgFrame {
- return [extraInfoMsg_ frame];
-}
-
-- (NSRect)getExtensionInstalledInfoMsgFrame {
- return [extensionInstalledInfoMsg_ frame];
-}
-
-- (void)extensionUnloaded:(id)sender {
- extension_ = NULL;
-}
-
-@end
diff --git a/chrome/browser/cocoa/extension_installed_bubble_controller_unittest.mm b/chrome/browser/cocoa/extension_installed_bubble_controller_unittest.mm
deleted file mode 100644
index 9113960..0000000
--- a/chrome/browser/cocoa/extension_installed_bubble_controller_unittest.mm
+++ /dev/null
@@ -1,202 +0,0 @@
-// 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 "base/basictypes.h"
-#include "base/file_path.h"
-#include "base/file_util.h"
-#include "base/path_service.h"
-#include "base/scoped_ptr.h"
-#include "base/values.h"
-#import "chrome/browser/browser_window.h"
-#import "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/extension_installed_bubble_controller.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_constants.h"
-#include "webkit/glue/image_decoder.h"
-
-// ExtensionInstalledBubbleController with removePageActionPreview overridden
-// to a no-op, because pageActions are not yet hooked up in the test browser.
-@interface ExtensionInstalledBubbleControllerForTest :
- ExtensionInstalledBubbleController {
-}
-
-// Do nothing, because browser window is not set up with page actions
-// for unit testing.
-- (void)removePageActionPreview;
-
-@end
-
-@implementation ExtensionInstalledBubbleControllerForTest
-
-- (void)removePageActionPreview { }
-
-@end
-
-namespace keys = extension_manifest_keys;
-
-class ExtensionInstalledBubbleControllerTest : public CocoaTest {
-
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
- browser_ = helper_.browser();
- window_ = helper_.CreateBrowserWindow()->GetNativeHandle();
- icon_ = LoadTestIcon();
- }
-
- virtual void TearDown() {
- helper_.CloseBrowserWindow();
- CocoaTest::TearDown();
- }
-
- // Load test icon from extension test directory.
- SkBitmap LoadTestIcon() {
- FilePath path;
- PathService::Get(chrome::DIR_TEST_DATA, &path);
- path = path.AppendASCII("extensions").AppendASCII("icon1.png");
-
- std::string file_contents;
- file_util::ReadFileToString(path, &file_contents);
- const unsigned char* data =
- reinterpret_cast<const unsigned char*>(file_contents.data());
-
- SkBitmap bitmap;
- webkit_glue::ImageDecoder decoder;
- bitmap = decoder.Decode(data, file_contents.length());
-
- return bitmap;
- }
-
- // Create a skeletal framework of either page action or browser action
- // type. This extension only needs to have a type and a name to initialize
- // the ExtensionInstalledBubble for unit testing.
- scoped_refptr<Extension> CreateExtension(
- extension_installed_bubble::ExtensionType type) {
- FilePath path;
- PathService::Get(chrome::DIR_TEST_DATA, &path);
- path = path.AppendASCII("extensions").AppendASCII("dummy");
-
- DictionaryValue extension_input_value;
- extension_input_value.SetString(keys::kVersion, "1.0.0.0");
- if (type == extension_installed_bubble::kPageAction) {
- extension_input_value.SetString(keys::kName, "page action extension");
- DictionaryValue* action = new DictionaryValue;
- action->SetString(keys::kPageActionId, "ExtensionActionId");
- action->SetString(keys::kPageActionDefaultTitle, "ExtensionActionTitle");
- action->SetString(keys::kPageActionDefaultIcon, "image1.png");
- ListValue* action_list = new ListValue;
- action_list->Append(action);
- extension_input_value.Set(keys::kPageActions, action_list);
- } else {
- extension_input_value.SetString(keys::kName, "browser action extension");
- DictionaryValue* browser_action = new DictionaryValue;
- // An empty dictionary is enough to create a Browser Action.
- extension_input_value.Set(keys::kBrowserAction, browser_action);
- }
-
- std::string error;
- return Extension::Create(
- path, Extension::INVALID, extension_input_value, false, &error);
- }
-
- // Allows us to create the window and browser for testing.
- BrowserTestHelper helper_;
-
- // Required to initialize the extension installed bubble.
- NSWindow* window_; // weak, owned by BrowserTestHelper.
-
- // Required to initialize the extension installed bubble.
- Browser* browser_; // weak, owned by BrowserTestHelper.
-
- // Skeleton extension to be tested; reinitialized for each test.
- scoped_refptr<Extension> extension_;
-
- // The icon_ to be loaded into the bubble window.
- SkBitmap icon_;
-};
-
-// Confirm that window sizes are set correctly for a page action extension.
-TEST_F(ExtensionInstalledBubbleControllerTest, PageActionTest) {
- extension_ = CreateExtension(extension_installed_bubble::kPageAction);
- ExtensionInstalledBubbleControllerForTest* controller =
- [[ExtensionInstalledBubbleControllerForTest alloc]
- initWithParentWindow:window_
- extension:extension_.get()
- browser:browser_
- icon:icon_];
- EXPECT_TRUE(controller);
-
- // Initialize window without having to calculate tabstrip locations.
- [controller initializeWindow];
- EXPECT_TRUE([controller window]);
-
- int height = [controller calculateWindowHeight];
- // Height should equal the vertical padding + height of all messages.
- int correctHeight = 2 * extension_installed_bubble::kOuterVerticalMargin +
- 2 * extension_installed_bubble::kInnerVerticalMargin +
- [controller getExtensionInstalledMsgFrame].size.height +
- [controller getExtensionInstalledInfoMsgFrame].size.height +
- [controller getExtraInfoMsgFrame].size.height;
- EXPECT_EQ(height, correctHeight);
-
- [controller setMessageFrames:height];
- NSRect msg3Frame = [controller getExtensionInstalledInfoMsgFrame];
- // Bottom message should be kOuterVerticalMargin pixels above window edge.
- EXPECT_EQ(msg3Frame.origin.y,
- extension_installed_bubble::kOuterVerticalMargin);
- NSRect msg2Frame = [controller getExtraInfoMsgFrame];
- // Pageaction message should be kInnerVerticalMargin pixels above bottom msg.
- EXPECT_EQ(msg2Frame.origin.y,
- msg3Frame.origin.y + msg3Frame.size.height +
- extension_installed_bubble::kInnerVerticalMargin);
- NSRect msg1Frame = [controller getExtensionInstalledMsgFrame];
- // Top message should be kInnerVerticalMargin pixels above Pageaction msg.
- EXPECT_EQ(msg1Frame.origin.y,
- msg2Frame.origin.y + msg2Frame.size.height +
- extension_installed_bubble::kInnerVerticalMargin);
-
- [controller setPageActionRemoved:YES];
- [controller close];
-}
-
-TEST_F(ExtensionInstalledBubbleControllerTest, BrowserActionTest) {
- extension_ = CreateExtension(extension_installed_bubble::kBrowserAction);
- ExtensionInstalledBubbleControllerForTest* controller =
- [[ExtensionInstalledBubbleControllerForTest alloc]
- initWithParentWindow:window_
- extension:extension_.get()
- browser:browser_
- icon:icon_];
- EXPECT_TRUE(controller);
-
- // Initialize window without having to calculate tabstrip locations.
- [controller initializeWindow];
- EXPECT_TRUE([controller window]);
-
- int height = [controller calculateWindowHeight];
- // Height should equal the vertical padding + height of all messages.
- int correctHeight = 2 * extension_installed_bubble::kOuterVerticalMargin +
- extension_installed_bubble::kInnerVerticalMargin +
- [controller getExtensionInstalledMsgFrame].size.height +
- [controller getExtensionInstalledInfoMsgFrame].size.height;
- EXPECT_EQ(height, correctHeight);
-
- [controller setMessageFrames:height];
- NSRect msg3Frame = [controller getExtensionInstalledInfoMsgFrame];
- // Bottom message should start kOuterVerticalMargin pixels above window edge.
- EXPECT_EQ(msg3Frame.origin.y,
- extension_installed_bubble::kOuterVerticalMargin);
- NSRect msg1Frame = [controller getExtensionInstalledMsgFrame];
- // Top message should start kInnerVerticalMargin pixels above top of
- // extensionInstalled message, because page action message is hidden.
- EXPECT_EQ(msg1Frame.origin.y,
- msg3Frame.origin.y + msg3Frame.size.height +
- extension_installed_bubble::kInnerVerticalMargin);
-
- [controller close];
-}
diff --git a/chrome/browser/cocoa/extension_view_mac.h b/chrome/browser/cocoa/extension_view_mac.h
deleted file mode 100644
index 6534ed3..0000000
--- a/chrome/browser/cocoa/extension_view_mac.h
+++ /dev/null
@@ -1,88 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_EXTENSION_VIEW_MAC_H_
-#define CHROME_BROWSER_COCOA_EXTENSION_VIEW_MAC_H_
-#pragma once
-
-#include "base/basictypes.h"
-#include "gfx/native_widget_types.h"
-#include "gfx/size.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-class Browser;
-class ExtensionHost;
-class RenderViewHost;
-class RenderWidgetHostViewMac;
-class SkBitmap;
-
-// This class represents extension views. An extension view internally contains
-// a bridge to an extension process, which draws to the extension view's
-// native view object through IPC.
-class ExtensionViewMac {
- public:
- ExtensionViewMac(ExtensionHost* extension_host, Browser* browser);
- ~ExtensionViewMac();
-
- // Starts the extension process and creates the native view. You must call
- // this method before calling any of this class's other methods.
- void Init();
-
- // Returns the extension's native view.
- gfx::NativeView native_view();
-
- // Returns the browser the extension belongs to.
- Browser* browser() const { return browser_; }
-
- // Does this extension live as a toolstrip in an extension shelf?
- bool is_toolstrip() const { return is_toolstrip_; }
- void set_is_toolstrip(bool is_toolstrip) { is_toolstrip_ = is_toolstrip; }
-
- // Sets the extensions's background image.
- void SetBackground(const SkBitmap& background);
-
- // Method for the ExtensionHost to notify us about the correct size for
- // extension contents.
- void UpdatePreferredSize(const gfx::Size& new_size);
-
- // Method for the ExtensionHost to notify us when the RenderViewHost has a
- // connection.
- void RenderViewCreated();
-
- // Informs the view that its containing window's frame changed.
- void WindowFrameChanged();
-
- // The minimum/maximum dimensions of the popup.
- // The minimum is just a little larger than the size of the button itself.
- // The maximum is an arbitrary number that should be smaller than most
- // screens.
- static const CGFloat kMinWidth;
- static const CGFloat kMinHeight;
- static const CGFloat kMaxWidth;
- static const CGFloat kMaxHeight;
-
- private:
- RenderViewHost* render_view_host() const;
-
- void CreateWidgetHostView();
-
- // True if the contents are being displayed inside the extension shelf.
- bool is_toolstrip_;
-
- Browser* browser_; // weak
-
- ExtensionHost* extension_host_; // weak
-
- // Created by us, but owned by its |native_view()|. We |release| the
- // rwhv's native view in our destructor, effectively freeing this.
- RenderWidgetHostViewMac* render_widget_host_view_;
-
- // The background the view should have once it is initialized. This is set
- // when the view has a custom background, but hasn't been initialized yet.
- SkBitmap pending_background_;
-
- DISALLOW_COPY_AND_ASSIGN(ExtensionViewMac);
-};
-
-#endif // CHROME_BROWSER_COCOA_EXTENSION_VIEW_MAC_H_
diff --git a/chrome/browser/cocoa/extension_view_mac.mm b/chrome/browser/cocoa/extension_view_mac.mm
deleted file mode 100644
index feab70c..0000000
--- a/chrome/browser/cocoa/extension_view_mac.mm
+++ /dev/null
@@ -1,112 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/extension_view_mac.h"
-
-#include "chrome/browser/extensions/extension_host.h"
-#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/renderer_host/render_widget_host_view_mac.h"
-
-// The minimum/maximum dimensions of the popup.
-const CGFloat ExtensionViewMac::kMinWidth = 25.0;
-const CGFloat ExtensionViewMac::kMinHeight = 25.0;
-const CGFloat ExtensionViewMac::kMaxWidth = 800.0;
-const CGFloat ExtensionViewMac::kMaxHeight = 600.0;
-
-ExtensionViewMac::ExtensionViewMac(ExtensionHost* extension_host,
- Browser* browser)
- : is_toolstrip_(true),
- browser_(browser),
- extension_host_(extension_host),
- render_widget_host_view_(NULL) {
- DCHECK(extension_host_);
-}
-
-ExtensionViewMac::~ExtensionViewMac() {
- if (render_widget_host_view_)
- [render_widget_host_view_->native_view() release];
-}
-
-void ExtensionViewMac::Init() {
- CreateWidgetHostView();
-}
-
-gfx::NativeView ExtensionViewMac::native_view() {
- DCHECK(render_widget_host_view_);
- return render_widget_host_view_->native_view();
-}
-
-RenderViewHost* ExtensionViewMac::render_view_host() const {
- return extension_host_->render_view_host();
-}
-
-void ExtensionViewMac::SetBackground(const SkBitmap& background) {
- DCHECK(render_widget_host_view_);
- if (render_view_host()->IsRenderViewLive()) {
- render_widget_host_view_->SetBackground(background);
- } else {
- pending_background_ = background;
- }
-}
-
-void ExtensionViewMac::UpdatePreferredSize(const gfx::Size& new_size) {
- // TODO(thakis, erikkay): Windows does some tricks to resize the extension
- // view not before it's visible. Do something similar here.
-
- // No need to use CA here, our caller calls us repeatedly to animate the
- // resizing.
- NSView* view = native_view();
- NSRect frame = [view frame];
- frame.size.width = new_size.width();
- frame.size.height = new_size.height();
-
- // On first display of some extensions, this function is called with zero
- // width after the correct size has been set. Bail if zero is seen, assuming
- // that an extension's view doesn't want any dimensions to ever be zero.
- // TODO(andybons): Verify this assumption and look into WebCore's
- // |contentesPreferredWidth| to see why this is occurring.
- if (NSIsEmptyRect(frame))
- return;
-
- DCHECK([view isKindOfClass:[RenderWidgetHostViewCocoa class]]);
- RenderWidgetHostViewCocoa* hostView = (RenderWidgetHostViewCocoa*)view;
-
- // RenderWidgetHostViewCocoa overrides setFrame but not setFrameSize.
- // We need to defer the update back to the RenderWidgetHost so we don't
- // get the flickering effect on 10.5 of http://crbug.com/31970
- [hostView setFrameWithDeferredUpdate:frame];
- [hostView setNeedsDisplay:YES];
-}
-
-void ExtensionViewMac::RenderViewCreated() {
- // Do not allow webkit to draw scroll bars on views smaller than
- // the largest size view allowed. The view will be resized to make
- // scroll bars unnecessary. Scroll bars change the height of the
- // view, so not drawing them is necessary to avoid infinite resizing.
- gfx::Size largest_popup_size(
- CGSizeMake(ExtensionViewMac::kMaxWidth, ExtensionViewMac::kMaxHeight));
- extension_host_->DisableScrollbarsForSmallWindows(largest_popup_size);
-
- if (!pending_background_.empty() && render_view_host()->view()) {
- render_widget_host_view_->SetBackground(pending_background_);
- pending_background_.reset();
- }
-}
-
-void ExtensionViewMac::WindowFrameChanged() {
- if (render_widget_host_view_)
- render_widget_host_view_->WindowFrameChanged();
-}
-
-void ExtensionViewMac::CreateWidgetHostView() {
- DCHECK(!render_widget_host_view_);
- render_widget_host_view_ = new RenderWidgetHostViewMac(render_view_host());
-
- // The RenderWidgetHostViewMac is owned by its native view, which is created
- // in an autoreleased state. retain it, so that it doesn't immediately
- // disappear.
- [render_widget_host_view_->native_view() retain];
-
- extension_host_->CreateRenderViewSoon(render_widget_host_view_);
-}
diff --git a/chrome/browser/cocoa/extensions/browser_action_button.h b/chrome/browser/cocoa/extensions/browser_action_button.h
deleted file mode 100644
index 1205c80..0000000
--- a/chrome/browser/cocoa/extensions/browser_action_button.h
+++ /dev/null
@@ -1,98 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_EXTENSIONS_BROWSER_ACTION_BUTTON_H_
-#define CHROME_BROWSER_COCOA_EXTENSIONS_BROWSER_ACTION_BUTTON_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-#import "chrome/browser/cocoa/gradient_button_cell.h"
-
-class Extension;
-class ExtensionAction;
-class ExtensionImageTrackerBridge;
-class Profile;
-
-// Fired when the Browser Action's state has changed. Usually the image needs to
-// be updated.
-extern NSString* const kBrowserActionButtonUpdatedNotification;
-
-// Fired on each drag event while the user is moving the button.
-extern NSString* const kBrowserActionButtonDraggingNotification;
-// Fired when the user drops the button.
-extern NSString* const kBrowserActionButtonDragEndNotification;
-
-@interface BrowserActionButton : NSButton {
- @private
- // Bridge to proxy Chrome notifications to the Obj-C class as well as load the
- // extension's icon.
- scoped_ptr<ExtensionImageTrackerBridge> imageLoadingBridge_;
-
- // The default icon of the Button.
- scoped_nsobject<NSImage> defaultIcon_;
-
- // The icon specific to the active tab.
- scoped_nsobject<NSImage> tabSpecificIcon_;
-
- // Used to move the button and query whether a button is currently animating.
- scoped_nsobject<NSViewAnimation> moveAnimation_;
-
- // The extension for this button. Weak.
- const Extension* extension_;
-
- // The ID of the active tab.
- int tabId_;
-
- // Whether the button is currently being dragged.
- BOOL isBeingDragged_;
-
- // Drag events could be intercepted by other buttons, so to make sure that
- // this is the only button moving if it ends up being dragged. This is set to
- // YES upon |mouseDown:|.
- BOOL dragCouldStart_;
-}
-
-- (id)initWithFrame:(NSRect)frame
- extension:(const Extension*)extension
- profile:(Profile*)profile
- tabId:(int)tabId;
-
-- (void)setFrame:(NSRect)frameRect animate:(BOOL)animate;
-
-- (void)setDefaultIcon:(NSImage*)image;
-
-- (void)setTabSpecificIcon:(NSImage*)image;
-
-- (void)updateState;
-
-- (BOOL)isAnimating;
-
-// Returns a pointer to an autoreleased NSImage with the badge, shadow and
-// cell image drawn into it.
-- (NSImage*)compositedImage;
-
-@property(readonly, nonatomic) BOOL isBeingDragged;
-@property(readonly, nonatomic) const Extension* extension;
-@property(readwrite, nonatomic) int tabId;
-
-@end
-
-@interface BrowserActionCell : GradientButtonCell {
- @private
- // The current tab ID used when drawing the cell.
- int tabId_;
-
- // The action we're drawing the cell for. Weak.
- ExtensionAction* extensionAction_;
-}
-
-@property(readwrite, nonatomic) int tabId;
-@property(readwrite, nonatomic) ExtensionAction* extensionAction;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_EXTENSIONS_BROWSER_ACTION_BUTTON_H_
diff --git a/chrome/browser/cocoa/extensions/browser_action_button.mm b/chrome/browser/cocoa/extensions/browser_action_button.mm
deleted file mode 100644
index 0cdaee5..0000000
--- a/chrome/browser/cocoa/extensions/browser_action_button.mm
+++ /dev/null
@@ -1,333 +0,0 @@
-// 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 "chrome/browser/cocoa/extensions/browser_action_button.h"
-
-#include <algorithm>
-#include <cmath>
-
-#include "base/logging.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/cocoa/extensions/extension_action_context_menu.h"
-#import "chrome/browser/cocoa/image_utils.h"
-#include "chrome/browser/extensions/image_loading_tracker.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_action.h"
-#include "chrome/common/extensions/extension_resource.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_source.h"
-#include "chrome/common/notification_type.h"
-#include "gfx/canvas_skia_paint.h"
-#include "gfx/rect.h"
-#include "gfx/size.h"
-#include "skia/ext/skia_utils_mac.h"
-#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
-
-NSString* const kBrowserActionButtonUpdatedNotification =
- @"BrowserActionButtonUpdatedNotification";
-
-NSString* const kBrowserActionButtonDraggingNotification =
- @"BrowserActionButtonDraggingNotification";
-NSString* const kBrowserActionButtonDragEndNotification =
- @"BrowserActionButtonDragEndNotification";
-
-static const CGFloat kBrowserActionBadgeOriginYOffset = 5;
-
-namespace {
-const CGFloat kAnimationDuration = 0.2;
-const CGFloat kShadowOffset = 2.0;
-} // anonymous namespace
-
-// A helper class to bridge the asynchronous Skia bitmap loading mechanism to
-// the extension's button.
-class ExtensionImageTrackerBridge : public NotificationObserver,
- public ImageLoadingTracker::Observer {
- public:
- ExtensionImageTrackerBridge(BrowserActionButton* owner,
- const Extension* extension)
- : owner_(owner),
- tracker_(this) {
- // The Browser Action API does not allow the default icon path to be
- // changed at runtime, so we can load this now and cache it.
- std::string path = extension->browser_action()->default_icon_path();
- if (!path.empty()) {
- tracker_.LoadImage(extension, extension->GetResource(path),
- gfx::Size(Extension::kBrowserActionIconMaxSize,
- Extension::kBrowserActionIconMaxSize),
- ImageLoadingTracker::DONT_CACHE);
- }
- registrar_.Add(this, NotificationType::EXTENSION_BROWSER_ACTION_UPDATED,
- Source<ExtensionAction>(extension->browser_action()));
- }
-
- ~ExtensionImageTrackerBridge() {}
-
- // ImageLoadingTracker::Observer implementation.
- void OnImageLoaded(SkBitmap* image, ExtensionResource resource, int index) {
- if (image)
- [owner_ setDefaultIcon:gfx::SkBitmapToNSImage(*image)];
- [owner_ updateState];
- }
-
- // Overridden from NotificationObserver.
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- if (type == NotificationType::EXTENSION_BROWSER_ACTION_UPDATED)
- [owner_ updateState];
- else
- NOTREACHED();
- }
-
- private:
- // Weak. Owns us.
- BrowserActionButton* owner_;
-
- // Loads the button's icons for us on the file thread.
- ImageLoadingTracker tracker_;
-
- // Used for registering to receive notifications and automatic clean up.
- NotificationRegistrar registrar_;
-
- DISALLOW_COPY_AND_ASSIGN(ExtensionImageTrackerBridge);
-};
-
-@interface BrowserActionCell(Internals)
-- (void)setIconShadow;
-- (void)drawBadgeWithinFrame:(NSRect)frame;
-@end
-
-@interface BrowserActionButton(Private)
-- (void)endDrag;
-@end
-
-@implementation BrowserActionButton
-
-@synthesize isBeingDragged = isBeingDragged_;
-@synthesize extension = extension_;
-@synthesize tabId = tabId_;
-
-+ (Class)cellClass {
- return [BrowserActionCell class];
-}
-
-- (id)initWithFrame:(NSRect)frame
- extension:(const Extension*)extension
- profile:(Profile*)profile
- tabId:(int)tabId {
- if ((self = [super initWithFrame:frame])) {
- BrowserActionCell* cell = [[[BrowserActionCell alloc] init] autorelease];
- // [NSButton setCell:] warns to NOT use setCell: other than in the
- // initializer of a control. However, we are using a basic
- // NSButton whose initializer does not take an NSCell as an
- // object. To honor the assumed semantics, we do nothing with
- // NSButton between alloc/init and setCell:.
- [self setCell:cell];
- [cell setTabId:tabId];
- [cell setExtensionAction:extension->browser_action()];
-
- [self setTitle:@""];
- [self setButtonType:NSMomentaryChangeButton];
- [self setShowsBorderOnlyWhileMouseInside:YES];
-
- [self setMenu:[[[ExtensionActionContextMenu alloc]
- initWithExtension:extension
- profile:profile
- extensionAction:extension->browser_action()] autorelease]];
-
- tabId_ = tabId;
- extension_ = extension;
- imageLoadingBridge_.reset(new ExtensionImageTrackerBridge(self, extension));
-
- moveAnimation_.reset([[NSViewAnimation alloc] init]);
- [moveAnimation_ gtm_setDuration:kAnimationDuration
- eventMask:NSLeftMouseUpMask];
- [moveAnimation_ setAnimationBlockingMode:NSAnimationNonblocking];
-
- [self updateState];
- }
-
- return self;
-}
-
-- (BOOL)acceptsFirstResponder {
- return YES;
-}
-
-- (void)mouseDown:(NSEvent*)theEvent {
- [[self cell] setHighlighted:YES];
- dragCouldStart_ = YES;
-}
-
-- (void)mouseDragged:(NSEvent*)theEvent {
- if (!dragCouldStart_)
- return;
-
- if (!isBeingDragged_) {
- // The start of a drag. Position the button above all others.
- [[self superview] addSubview:self positioned:NSWindowAbove relativeTo:nil];
- }
- isBeingDragged_ = YES;
- NSRect buttonFrame = [self frame];
- // TODO(andybons): Constrain the buttons to be within the container.
- // Clamp the button to be within its superview along the X-axis.
- buttonFrame.origin.x += [theEvent deltaX];
- [self setFrame:buttonFrame];
- [self setNeedsDisplay:YES];
- [[NSNotificationCenter defaultCenter]
- postNotificationName:kBrowserActionButtonDraggingNotification
- object:self];
-}
-
-- (void)mouseUp:(NSEvent*)theEvent {
- dragCouldStart_ = NO;
- // There are non-drag cases where a mouseUp: may happen
- // (e.g. mouse-down, cmd-tab to another application, move mouse,
- // mouse-up).
- NSPoint location = [self convertPoint:[theEvent locationInWindow]
- fromView:nil];
- if (NSPointInRect(location, [self bounds]) && !isBeingDragged_) {
- // Only perform the click if we didn't drag the button.
- [self performClick:self];
- } else {
- // Make sure an ESC to end a drag doesn't trigger 2 endDrags.
- if (isBeingDragged_) {
- [self endDrag];
- } else {
- [super mouseUp:theEvent];
- }
- }
-}
-
-- (void)endDrag {
- isBeingDragged_ = NO;
- [[NSNotificationCenter defaultCenter]
- postNotificationName:kBrowserActionButtonDragEndNotification
- object:self];
- [[self cell] setHighlighted:NO];
-}
-
-- (void)setFrame:(NSRect)frameRect animate:(BOOL)animate {
- if (!animate) {
- [self setFrame:frameRect];
- } else {
- if ([moveAnimation_ isAnimating])
- [moveAnimation_ stopAnimation];
-
- NSDictionary* animationDictionary =
- [NSDictionary dictionaryWithObjectsAndKeys:
- self, NSViewAnimationTargetKey,
- [NSValue valueWithRect:[self frame]], NSViewAnimationStartFrameKey,
- [NSValue valueWithRect:frameRect], NSViewAnimationEndFrameKey,
- nil];
- [moveAnimation_ setViewAnimations:
- [NSArray arrayWithObject:animationDictionary]];
- [moveAnimation_ startAnimation];
- }
-}
-
-- (void)setDefaultIcon:(NSImage*)image {
- defaultIcon_.reset([image retain]);
-}
-
-- (void)setTabSpecificIcon:(NSImage*)image {
- tabSpecificIcon_.reset([image retain]);
-}
-
-- (void)updateState {
- if (tabId_ < 0)
- return;
-
- std::string tooltip = extension_->browser_action()->GetTitle(tabId_);
- if (tooltip.empty()) {
- [self setToolTip:nil];
- } else {
- [self setToolTip:base::SysUTF8ToNSString(tooltip)];
- }
-
- SkBitmap image = extension_->browser_action()->GetIcon(tabId_);
- if (!image.isNull()) {
- [self setTabSpecificIcon:gfx::SkBitmapToNSImage(image)];
- [self setImage:tabSpecificIcon_];
- } else if (defaultIcon_) {
- [self setImage:defaultIcon_];
- }
-
- [[self cell] setTabId:tabId_];
-
- [self setNeedsDisplay:YES];
-
- [[NSNotificationCenter defaultCenter]
- postNotificationName:kBrowserActionButtonUpdatedNotification
- object:self];
-}
-
-- (BOOL)isAnimating {
- return [moveAnimation_ isAnimating];
-}
-
-- (NSImage*)compositedImage {
- NSRect bounds = [self bounds];
- NSImage* image = [[[NSImage alloc] initWithSize:bounds.size] autorelease];
- [image lockFocus];
-
- [[NSColor clearColor] set];
- NSRectFill(bounds);
- [[self cell] setIconShadow];
-
- NSImage* actionImage = [self image];
- const NSSize imageSize = [actionImage size];
- const NSRect imageRect =
- NSMakeRect(std::floor((NSWidth(bounds) - imageSize.width) / 2.0),
- std::floor((NSHeight(bounds) - imageSize.height) / 2.0),
- imageSize.width, imageSize.height);
- [actionImage drawInRect:imageRect
- fromRect:NSZeroRect
- operation:NSCompositeSourceOver
- fraction:1.0
- neverFlipped:YES];
-
- bounds.origin.y += kShadowOffset - kBrowserActionBadgeOriginYOffset;
- bounds.origin.x -= kShadowOffset;
- [[self cell] drawBadgeWithinFrame:bounds];
-
- [image unlockFocus];
- return image;
-}
-
-@end
-
-@implementation BrowserActionCell
-
-@synthesize tabId = tabId_;
-@synthesize extensionAction = extensionAction_;
-
-- (void)setIconShadow {
- // Create the shadow below and to the right of the drawn image.
- scoped_nsobject<NSShadow> imgShadow([[NSShadow alloc] init]);
- [imgShadow.get() setShadowOffset:NSMakeSize(kShadowOffset, -kShadowOffset)];
- [imgShadow setShadowBlurRadius:2.0];
- [imgShadow.get() setShadowColor:[[NSColor blackColor]
- colorWithAlphaComponent:0.3]];
- [imgShadow set];
-}
-
-- (void)drawBadgeWithinFrame:(NSRect)frame {
- gfx::CanvasSkiaPaint canvas(frame, false);
- canvas.set_composite_alpha(true);
- gfx::Rect boundingRect(NSRectToCGRect(frame));
- extensionAction_->PaintBadge(&canvas, boundingRect, tabId_);
-}
-
-- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
- [NSGraphicsContext saveGraphicsState];
- [self setIconShadow];
- [super drawInteriorWithFrame:cellFrame inView:controlView];
- cellFrame.origin.y += kBrowserActionBadgeOriginYOffset;
- [self drawBadgeWithinFrame:cellFrame];
- [NSGraphicsContext restoreGraphicsState];
-}
-
-@end
diff --git a/chrome/browser/cocoa/extensions/browser_actions_container_view.h b/chrome/browser/cocoa/extensions/browser_actions_container_view.h
deleted file mode 100644
index d90851e..0000000
--- a/chrome/browser/cocoa/extensions/browser_actions_container_view.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_EXTENSIONS_BROWSER_ACTIONS_CONTAINER_VIEW_
-#define CHROME_BROWSER_COCOA_EXTENSIONS_BROWSER_ACTIONS_CONTAINER_VIEW_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-// Sent when a user-initiated drag to resize the container is initiated.
-extern NSString* const kBrowserActionGrippyDragStartedNotification;
-
-// Sent when a user-initiated drag is resizing the container.
-extern NSString* const kBrowserActionGrippyDraggingNotification;
-
-// Sent when a user-initiated drag to resize the container has finished.
-extern NSString* const kBrowserActionGrippyDragFinishedNotification;
-
-// The view that encompasses the Browser Action buttons in the toolbar and
-// provides mechanisms for resizing.
-@interface BrowserActionsContainerView : NSView {
- @private
- // The frame encompasing the grippy used for resizing the container.
- NSRect grippyRect_;
-
- // The end frame of the animation currently running for this container or
- // NSZeroRect if none is in progress.
- NSRect animationEndFrame_;
-
- // Used to cache the original position within the container that initiated the
- // drag.
- NSPoint initialDragPoint_;
-
- // Used to cache the previous x-pos of the frame rect for resizing purposes.
- CGFloat lastXPos_;
-
- // The maximum width of the container.
- CGFloat maxWidth_;
-
- // Whether the container is currently being resized by the user.
- BOOL userIsResizing_;
-
- // Whether the user can resize this at all. Resizing is disabled in incognito
- // mode since any changes done in incognito mode are not saved anyway, and
- // also to avoid a crash. http://crbug.com/42848
- BOOL resizable_;
-
- // Whether the user is allowed to drag the grippy to the left. NO if all
- // extensions are shown or the location bar has hit its minimum width (handled
- // within toolbar_controller.mm).
- BOOL canDragLeft_;
-
- // Whether the user is allowed to drag the grippy to the right. NO if all
- // extensions are hidden.
- BOOL canDragRight_;
-
- // When the left grippy is pinned, resizing the window has no effect on its
- // position. This prevents it from overlapping with other elements as well
- // as letting the container expand when the window is going from super small
- // to large.
- BOOL grippyPinned_;
-}
-
-// Resizes the container to the given ideal width, adjusting the |lastXPos_| so
-// that |resizeDeltaX| is accurate.
-- (void)resizeToWidth:(CGFloat)width animate:(BOOL)animate;
-
-// Returns the change in the x-pos of the frame rect during resizing. Meant to
-// be queried when a NSViewFrameDidChangeNotification is fired to determine
-// placement of surrounding elements.
-- (CGFloat)resizeDeltaX;
-
-@property(nonatomic, readonly) NSRect animationEndFrame;
-@property(nonatomic) BOOL canDragLeft;
-@property(nonatomic) BOOL canDragRight;
-@property(nonatomic) BOOL grippyPinned;
-@property(nonatomic,getter=isResizable) BOOL resizable;
-@property(nonatomic) CGFloat maxWidth;
-@property(readonly, nonatomic) BOOL userIsResizing;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_EXTENSIONS_BROWSER_ACTIONS_CONTAINER_VIEW_
diff --git a/chrome/browser/cocoa/extensions/browser_actions_container_view.mm b/chrome/browser/cocoa/extensions/browser_actions_container_view.mm
deleted file mode 100644
index e4bf961..0000000
--- a/chrome/browser/cocoa/extensions/browser_actions_container_view.mm
+++ /dev/null
@@ -1,192 +0,0 @@
-// 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 "chrome/browser/cocoa/extensions/browser_actions_container_view.h"
-
-#include <algorithm>
-
-#include "base/basictypes.h"
-#import "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/view_id_util.h"
-
-NSString* const kBrowserActionGrippyDragStartedNotification =
- @"BrowserActionGrippyDragStartedNotification";
-NSString* const kBrowserActionGrippyDraggingNotification =
- @"BrowserActionGrippyDraggingNotification";
-NSString* const kBrowserActionGrippyDragFinishedNotification =
- @"BrowserActionGrippyDragFinishedNotification";
-
-namespace {
-const CGFloat kAnimationDuration = 0.2;
-const CGFloat kGrippyWidth = 4.0;
-const CGFloat kMinimumContainerWidth = 10.0;
-} // namespace
-
-@interface BrowserActionsContainerView(Private)
-// Returns the cursor that should be shown when hovering over the grippy based
-// on |canDragLeft_| and |canDragRight_|.
-- (NSCursor*)appropriateCursorForGrippy;
-@end
-
-@implementation BrowserActionsContainerView
-
-@synthesize animationEndFrame = animationEndFrame_;
-@synthesize canDragLeft = canDragLeft_;
-@synthesize canDragRight = canDragRight_;
-@synthesize grippyPinned = grippyPinned_;
-@synthesize maxWidth = maxWidth_;
-@synthesize userIsResizing = userIsResizing_;
-
-#pragma mark -
-#pragma mark Overridden Class Functions
-
-- (id)initWithFrame:(NSRect)frameRect {
- if ((self = [super initWithFrame:frameRect])) {
- grippyRect_ = NSMakeRect(0.0, 0.0, kGrippyWidth, NSHeight([self bounds]));
- canDragLeft_ = YES;
- canDragRight_ = YES;
- resizable_ = YES;
- [self setHidden:YES];
- }
- return self;
-}
-
-- (void)setResizable:(BOOL)resizable {
- if (resizable == resizable_)
- return;
- resizable_ = resizable;
- [self setNeedsDisplay:YES];
-}
-
-- (BOOL)isResizable {
- return resizable_;
-}
-
-- (void)resetCursorRects {
- [self discardCursorRects];
- [self addCursorRect:grippyRect_ cursor:[self appropriateCursorForGrippy]];
-}
-
-- (BOOL)acceptsFirstResponder {
- return YES;
-}
-
-- (void)mouseDown:(NSEvent*)theEvent {
- initialDragPoint_ = [self convertPoint:[theEvent locationInWindow]
- fromView:nil];
- if (!resizable_ ||
- !NSMouseInRect(initialDragPoint_, grippyRect_, [self isFlipped]))
- return;
-
- lastXPos_ = [self frame].origin.x;
- userIsResizing_ = YES;
-
- [[self appropriateCursorForGrippy] push];
- // Disable cursor rects so that the Omnibox and other UI elements don't push
- // cursors while the user is dragging. The cursor should be grippy until
- // the |-mouseUp:| message is received.
- [[self window] disableCursorRects];
-
- [[NSNotificationCenter defaultCenter]
- postNotificationName:kBrowserActionGrippyDragStartedNotification
- object:self];
-}
-
-- (void)mouseUp:(NSEvent*)theEvent {
- if (!userIsResizing_)
- return;
-
- [NSCursor pop];
- [[self window] enableCursorRects];
-
- userIsResizing_ = NO;
- [[NSNotificationCenter defaultCenter]
- postNotificationName:kBrowserActionGrippyDragFinishedNotification
- object:self];
-}
-
-- (void)mouseDragged:(NSEvent*)theEvent {
- if (!userIsResizing_)
- return;
-
- NSPoint location = [self convertPoint:[theEvent locationInWindow]
- fromView:nil];
- NSRect containerFrame = [self frame];
- CGFloat dX = [theEvent deltaX];
- CGFloat withDelta = location.x - dX;
- canDragRight_ = (withDelta >= initialDragPoint_.x) &&
- (NSWidth(containerFrame) > kMinimumContainerWidth);
- canDragLeft_ = (withDelta <= initialDragPoint_.x) &&
- (NSWidth(containerFrame) < maxWidth_);
- if ((dX < 0.0 && !canDragLeft_) || (dX > 0.0 && !canDragRight_))
- return;
-
- containerFrame.size.width =
- std::max(NSWidth(containerFrame) - dX, kMinimumContainerWidth);
-
- if (NSWidth(containerFrame) == kMinimumContainerWidth)
- return;
-
- containerFrame.origin.x += dX;
-
- [self setFrame:containerFrame];
- [self setNeedsDisplay:YES];
-
- [[NSNotificationCenter defaultCenter]
- postNotificationName:kBrowserActionGrippyDraggingNotification
- object:self];
-
- lastXPos_ += dX;
-}
-
-- (ViewID)viewID {
- return VIEW_ID_BROWSER_ACTION_TOOLBAR;
-}
-
-#pragma mark -
-#pragma mark Public Methods
-
-- (void)resizeToWidth:(CGFloat)width animate:(BOOL)animate {
- width = std::max(width, kMinimumContainerWidth);
- NSRect frame = [self frame];
- lastXPos_ = frame.origin.x;
- CGFloat dX = frame.size.width - width;
- frame.size.width = width;
- NSRect newFrame = NSOffsetRect(frame, dX, 0);
- if (animate) {
- [NSAnimationContext beginGrouping];
- [[NSAnimationContext currentContext] setDuration:kAnimationDuration];
- [[self animator] setFrame:newFrame];
- [NSAnimationContext endGrouping];
- animationEndFrame_ = newFrame;
- } else {
- [self setFrame:newFrame];
- [self setNeedsDisplay:YES];
- }
-}
-
-- (CGFloat)resizeDeltaX {
- return [self frame].origin.x - lastXPos_;
-}
-
-#pragma mark -
-#pragma mark Private Methods
-
-// Returns the cursor to display over the grippy hover region depending on the
-// current drag state.
-- (NSCursor*)appropriateCursorForGrippy {
- NSCursor* retVal;
- if (!resizable_ || (!canDragLeft_ && !canDragRight_)) {
- retVal = [NSCursor arrowCursor];
- } else if (!canDragLeft_) {
- retVal = [NSCursor resizeRightCursor];
- } else if (!canDragRight_) {
- retVal = [NSCursor resizeLeftCursor];
- } else {
- retVal = [NSCursor resizeLeftRightCursor];
- }
- return retVal;
-}
-
-@end
diff --git a/chrome/browser/cocoa/extensions/browser_actions_container_view_unittest.mm b/chrome/browser/cocoa/extensions/browser_actions_container_view_unittest.mm
deleted file mode 100644
index ad120d7..0000000
--- a/chrome/browser/cocoa/extensions/browser_actions_container_view_unittest.mm
+++ /dev/null
@@ -1,52 +0,0 @@
-// 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.
-
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/extensions/browser_actions_container_view.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-namespace {
-
-const CGFloat kContainerHeight = 15.0;
-const CGFloat kMinimumContainerWidth = 10.0;
-
-class BrowserActionsContainerViewTest : public CocoaTest {
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
- view_.reset([[BrowserActionsContainerView alloc]
- initWithFrame:NSMakeRect(0, 0, 0, kContainerHeight)]);
- }
-
- scoped_nsobject<BrowserActionsContainerView> view_;
-};
-
-TEST_F(BrowserActionsContainerViewTest, BasicTests) {
- EXPECT_TRUE([view_ isResizable]);
- EXPECT_TRUE([view_ canDragLeft]);
- EXPECT_TRUE([view_ canDragRight]);
- EXPECT_TRUE([view_ isHidden]);
-}
-
-TEST_F(BrowserActionsContainerViewTest, SetWidthTests) {
- // Try setting below the minimum width (10 pixels).
- [view_ resizeToWidth:5.0 animate:NO];
- EXPECT_EQ(kMinimumContainerWidth, NSWidth([view_ frame])) << "Frame width is "
- << "less than the minimum allowed.";
- // Since the frame expands to the left, the x-position delta value will be
- // negative.
- EXPECT_EQ(-kMinimumContainerWidth, [view_ resizeDeltaX]);
-
- [view_ resizeToWidth:35.0 animate:NO];
- EXPECT_EQ(35.0, NSWidth([view_ frame]));
- EXPECT_EQ(-25.0, [view_ resizeDeltaX]);
-
- [view_ resizeToWidth:20.0 animate:NO];
- EXPECT_EQ(20.0, NSWidth([view_ frame]));
- EXPECT_EQ(15.0, [view_ resizeDeltaX]);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/extensions/browser_actions_controller.h b/chrome/browser/cocoa/extensions/browser_actions_controller.h
deleted file mode 100644
index 8f039ce..0000000
--- a/chrome/browser/cocoa/extensions/browser_actions_controller.h
+++ /dev/null
@@ -1,117 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_EXTENSIONS_BROWSER_ACTIONS_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_EXTENSIONS_BROWSER_ACTIONS_CONTROLLER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-
-class Browser;
-@class BrowserActionButton;
-@class BrowserActionsContainerView;
-class Extension;
-@class ExtensionPopupController;
-class ExtensionToolbarModel;
-class ExtensionsServiceObserverBridge;
-@class MenuButton;
-class PrefService;
-class Profile;
-
-// Sent when the visibility of the Browser Actions changes.
-extern NSString* const kBrowserActionVisibilityChangedNotification;
-
-// Handles state and provides an interface for controlling the Browser Actions
-// container within the Toolbar.
-@interface BrowserActionsController : NSObject {
- @private
- // Reference to the current browser. Weak.
- Browser* browser_;
-
- // The view from Toolbar.xib we'll be rendering our browser actions in. Weak.
- BrowserActionsContainerView* containerView_;
-
- // The current profile. Weak.
- Profile* profile_;
-
- // The model that tracks the order of the toolbar icons. Weak.
- ExtensionToolbarModel* toolbarModel_;
-
- // The observer for the ExtensionsService we're getting events from.
- scoped_ptr<ExtensionsServiceObserverBridge> observer_;
-
- // A dictionary of Extension ID -> BrowserActionButton pairs representing the
- // buttons present in the container view. The ID is a string unique to each
- // extension.
- scoped_nsobject<NSMutableDictionary> buttons_;
-
- // Array of hidden buttons in the correct order in which the user specified.
- scoped_nsobject<NSMutableArray> hiddenButtons_;
-
- // The currently running chevron animation (fade in/out).
- scoped_nsobject<NSViewAnimation> chevronAnimation_;
-
- // The chevron button used when Browser Actions are hidden.
- scoped_nsobject<MenuButton> chevronMenuButton_;
-
- // The Browser Actions overflow menu.
- scoped_nsobject<NSMenu> overflowMenu_;
-}
-
-@property(readonly, nonatomic) BrowserActionsContainerView* containerView;
-
-// Initializes the controller given the current browser and container view that
-// will hold the browser action buttons.
-- (id)initWithBrowser:(Browser*)browser
- containerView:(BrowserActionsContainerView*)container;
-
-// Update the display of all buttons.
-- (void)update;
-
-// Returns the current number of browser action buttons within the container,
-// whether or not they are displayed.
-- (NSUInteger)buttonCount;
-
-// Returns the current number of browser action buttons displayed in the
-// container.
-- (NSUInteger)visibleButtonCount;
-
-// Returns a pointer to the chevron menu button.
-- (MenuButton*)chevronMenuButton;
-
-// Resizes the container given the number of visible buttons, taking into
-// account the size of the grippy. Also updates the persistent width preference.
-- (void)resizeContainerAndAnimate:(BOOL)animate;
-
-// Returns the NSView for the action button associated with an extension.
-- (NSView*)browserActionViewForExtension:(const Extension*)extension;
-
-// Returns the saved width determined by the number of shown Browser Actions
-// preference property. If no preference is found, then the width for the
-// container is returned as if all buttons are shown.
-- (CGFloat)savedWidth;
-
-// Returns where the popup arrow should point to for a given Browser Action. If
-// it is passed an extension that is not a Browser Action, then it will return
-// NSZeroPoint.
-- (NSPoint)popupPointForBrowserAction:(const Extension*)extension;
-
-// Returns whether the chevron button is currently hidden or in the process of
-// being hidden (fading out). Will return NO if it is not hidden or is in the
-// process of fading in.
-- (BOOL)chevronIsHidden;
-
-// Registers the user preferences used by this class.
-+ (void)registerUserPrefs:(PrefService*)prefs;
-
-@end // @interface BrowserActionsController
-
-@interface BrowserActionsController(TestingAPI)
-- (NSButton*)buttonWithIndex:(NSUInteger)index;
-@end
-
-#endif // CHROME_BROWSER_COCOA_EXTENSIONS_BROWSER_ACTIONS_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/extensions/browser_actions_controller.mm b/chrome/browser/cocoa/extensions/browser_actions_controller.mm
deleted file mode 100644
index f7b0965..0000000
--- a/chrome/browser/cocoa/extensions/browser_actions_controller.mm
+++ /dev/null
@@ -1,863 +0,0 @@
-// 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 "browser_actions_controller.h"
-
-#include <cmath>
-#include <string>
-
-#include "base/nsimage_cache_mac.h"
-#include "base/sys_string_conversions.h"
-#import "chrome/browser/cocoa/extensions/browser_action_button.h"
-#import "chrome/browser/cocoa/extensions/browser_actions_container_view.h"
-#import "chrome/browser/cocoa/extensions/chevron_menu_button.h"
-#import "chrome/browser/cocoa/extensions/extension_popup_controller.h"
-#import "chrome/browser/cocoa/menu_button.h"
-#include "chrome/browser/extensions/extension_browser_event_router.h"
-#include "chrome/browser/extensions/extension_host.h"
-#include "chrome/browser/extensions/extension_toolbar_model.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/common/extensions/extension_action.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
-#include "chrome/common/pref_names.h"
-#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
-
-NSString* const kBrowserActionVisibilityChangedNotification =
- @"BrowserActionVisibilityChangedNotification";
-
-namespace {
-const CGFloat kAnimationDuration = 0.2;
-
-const CGFloat kChevronWidth = 14.0;
-
-// Image used for the overflow button.
-NSString* const kOverflowChevronsName =
- @"browser_actions_overflow_Template.pdf";
-
-// Since the container is the maximum height of the toolbar, we have
-// to move the buttons up by this amount in order to have them look
-// vertically centered within the toolbar.
-const CGFloat kBrowserActionOriginYOffset = 5.0;
-
-// The size of each button on the toolbar.
-const CGFloat kBrowserActionHeight = 29.0;
-const CGFloat kBrowserActionWidth = 29.0;
-
-// The padding between browser action buttons.
-const CGFloat kBrowserActionButtonPadding = 2.0;
-
-// Padding between Omnibox and first button. Since the buttons have a
-// pixel of internal padding, this needs an extra pixel.
-const CGFloat kBrowserActionLeftPadding = kBrowserActionButtonPadding + 1.0;
-
-// How far to inset from the bottom of the view to get the top border
-// of the popup 2px below the bottom of the Omnibox.
-const CGFloat kBrowserActionBubbleYOffset = 3.0;
-
-} // namespace
-
-@interface BrowserActionsController(Private)
-// Used during initialization to create the BrowserActionButton objects from the
-// stored toolbar model.
-- (void)createButtons;
-
-// Creates and then adds the given extension's action button to the container
-// at the given index within the container. It does not affect the toolbar model
-// object since it is called when the toolbar model changes.
-- (void)createActionButtonForExtension:(const Extension*)extension
- withIndex:(NSUInteger)index;
-
-// Removes an action button for the given extension from the container. This
-// method also does not affect the underlying toolbar model since it is called
-// when the toolbar model changes.
-- (void)removeActionButtonForExtension:(const Extension*)extension;
-
-// Useful in the case of a Browser Action being added/removed from the middle of
-// the container, this method repositions each button according to the current
-// toolbar model.
-- (void)positionActionButtonsAndAnimate:(BOOL)animate;
-
-// During container resizing, buttons become more transparent as they are pushed
-// off the screen. This method updates each button's opacity determined by the
-// position of the button.
-- (void)updateButtonOpacity;
-
-// Returns the existing button with the given extension backing it; nil if it
-// cannot be found or the extension's ID is invalid.
-- (BrowserActionButton*)buttonForExtension:(const Extension*)extension;
-
-// Returns the preferred width of the container given the number of visible
-// buttons |buttonCount|.
-- (CGFloat)containerWidthWithButtonCount:(NSUInteger)buttonCount;
-
-// Returns the number of buttons that can fit in the container according to its
-// current size.
-- (NSUInteger)containerButtonCapacity;
-
-// Notification handlers for events registered by the class.
-
-// Updates each button's opacity, the cursor rects and chevron position.
-- (void)containerFrameChanged:(NSNotification*)notification;
-
-// Hides the chevron and unhides every hidden button so that dragging the
-// container out smoothly shows the Browser Action buttons.
-- (void)containerDragStart:(NSNotification*)notification;
-
-// Sends a notification for the toolbar to reposition surrounding UI elements.
-- (void)containerDragging:(NSNotification*)notification;
-
-// Determines which buttons need to be hidden based on the new size, hides them
-// and updates the chevron overflow menu. Also fires a notification to let the
-// toolbar know that the drag has finished.
-- (void)containerDragFinished:(NSNotification*)notification;
-
-// Updates the image associated with the button should it be within the chevron
-// menu.
-- (void)actionButtonUpdated:(NSNotification*)notification;
-
-// Adjusts the position of the surrounding action buttons depending on where the
-// button is within the container.
-- (void)actionButtonDragging:(NSNotification*)notification;
-
-// Updates the position of the Browser Actions within the container. This fires
-// when _any_ Browser Action button is done dragging to keep all open windows in
-// sync visually.
-- (void)actionButtonDragFinished:(NSNotification*)notification;
-
-// Moves the given button both visually and within the toolbar model to the
-// specified index.
-- (void)moveButton:(BrowserActionButton*)button
- toIndex:(NSUInteger)index
- animate:(BOOL)animate;
-
-// Handles when the given BrowserActionButton object is clicked.
-- (void)browserActionClicked:(BrowserActionButton*)button;
-
-// Returns whether the given extension should be displayed. Only displays
-// incognito-enabled extensions in incognito mode. Otherwise returns YES.
-- (BOOL)shouldDisplayBrowserAction:(const Extension*)extension;
-
-// The reason |frame| is specified in these chevron functions is because the
-// container may be animating and the end frame of the animation should be
-// passed instead of the current frame (which may be off and cause the chevron
-// to jump at the end of its animation).
-
-// Shows the overflow chevron button depending on whether there are any hidden
-// extensions within the frame given.
-- (void)showChevronIfNecessaryInFrame:(NSRect)frame animate:(BOOL)animate;
-
-// Moves the chevron to its correct position within |frame|.
-- (void)updateChevronPositionInFrame:(NSRect)frame;
-
-// Shows or hides the chevron, animating as specified by |animate|.
-- (void)setChevronHidden:(BOOL)hidden
- inFrame:(NSRect)frame
- animate:(BOOL)animate;
-
-// Handles when a menu item within the chevron overflow menu is selected.
-- (void)chevronItemSelected:(id)menuItem;
-
-// Clears and then populates the overflow menu based on the contents of
-// |hiddenButtons_|.
-- (void)updateOverflowMenu;
-
-// Updates the container's grippy cursor based on the number of hidden buttons.
-- (void)updateGrippyCursors;
-
-// Returns the ID of the currently selected tab or -1 if none exists.
-- (int)currentTabId;
-@end
-
-// A helper class to proxy extension notifications to the view controller's
-// appropriate methods.
-class ExtensionsServiceObserverBridge : public NotificationObserver,
- public ExtensionToolbarModel::Observer {
- public:
- ExtensionsServiceObserverBridge(BrowserActionsController* owner,
- Profile* profile) : owner_(owner) {
- registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE,
- Source<Profile>(profile));
- }
-
- // Overridden from NotificationObserver.
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- switch (type.value) {
- case NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE: {
- ExtensionPopupController* popup = [ExtensionPopupController popup];
- if (popup && ![popup isClosing])
- [popup close];
-
- break;
- }
- default:
- NOTREACHED() << L"Unexpected notification";
- }
- }
-
- // ExtensionToolbarModel::Observer implementation.
- void BrowserActionAdded(const Extension* extension, int index) {
- [owner_ createActionButtonForExtension:extension withIndex:index];
- [owner_ resizeContainerAndAnimate:NO];
- }
-
- void BrowserActionRemoved(const Extension* extension) {
- [owner_ removeActionButtonForExtension:extension];
- [owner_ resizeContainerAndAnimate:NO];
- }
-
- private:
- // The object we need to inform when we get a notification. Weak. Owns us.
- BrowserActionsController* owner_;
-
- // Used for registering to receive notifications and automatic clean up.
- NotificationRegistrar registrar_;
-
- DISALLOW_COPY_AND_ASSIGN(ExtensionsServiceObserverBridge);
-};
-
-@implementation BrowserActionsController
-
-@synthesize containerView = containerView_;
-
-#pragma mark -
-#pragma mark Public Methods
-
-- (id)initWithBrowser:(Browser*)browser
- containerView:(BrowserActionsContainerView*)container {
- DCHECK(browser && container);
-
- if ((self = [super init])) {
- browser_ = browser;
- profile_ = browser->profile();
-
- if (!profile_->GetPrefs()->FindPreference(
- prefs::kBrowserActionContainerWidth))
- [BrowserActionsController registerUserPrefs:profile_->GetPrefs()];
-
- observer_.reset(new ExtensionsServiceObserverBridge(self, profile_));
- ExtensionsService* extensionsService = profile_->GetExtensionsService();
- // |extensionsService| can be NULL in Incognito.
- if (extensionsService) {
- toolbarModel_ = extensionsService->toolbar_model();
- toolbarModel_->AddObserver(observer_.get());
- }
-
- containerView_ = container;
- [containerView_ setPostsFrameChangedNotifications:YES];
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(containerFrameChanged:)
- name:NSViewFrameDidChangeNotification
- object:containerView_];
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(containerDragStart:)
- name:kBrowserActionGrippyDragStartedNotification
- object:containerView_];
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(containerDragging:)
- name:kBrowserActionGrippyDraggingNotification
- object:containerView_];
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(containerDragFinished:)
- name:kBrowserActionGrippyDragFinishedNotification
- object:containerView_];
- // Listen for a finished drag from any button to make sure each open window
- // stays in sync.
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(actionButtonDragFinished:)
- name:kBrowserActionButtonDragEndNotification
- object:nil];
-
- chevronAnimation_.reset([[NSViewAnimation alloc] init]);
- [chevronAnimation_ gtm_setDuration:kAnimationDuration
- eventMask:NSLeftMouseUpMask];
- [chevronAnimation_ setAnimationBlockingMode:NSAnimationNonblocking];
-
- hiddenButtons_.reset([[NSMutableArray alloc] init]);
- buttons_.reset([[NSMutableDictionary alloc] init]);
- [self createButtons];
- [self showChevronIfNecessaryInFrame:[containerView_ frame] animate:NO];
- [self updateGrippyCursors];
- [container setResizable:!profile_->IsOffTheRecord()];
- }
-
- return self;
-}
-
-- (void)dealloc {
- if (toolbarModel_)
- toolbarModel_->RemoveObserver(observer_.get());
-
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [super dealloc];
-}
-
-- (void)update {
- for (BrowserActionButton* button in [buttons_ allValues]) {
- [button setTabId:[self currentTabId]];
- [button updateState];
- }
-}
-
-- (NSUInteger)buttonCount {
- return [buttons_ count];
-}
-
-- (NSUInteger)visibleButtonCount {
- return [self buttonCount] - [hiddenButtons_ count];
-}
-
-- (MenuButton*)chevronMenuButton {
- return chevronMenuButton_.get();
-}
-
-- (void)resizeContainerAndAnimate:(BOOL)animate {
- int iconCount = toolbarModel_->GetVisibleIconCount();
- if (iconCount < 0) // If no buttons are hidden.
- iconCount = [self buttonCount];
-
- [containerView_ resizeToWidth:[self containerWidthWithButtonCount:iconCount]
- animate:animate];
- NSRect frame = animate ? [containerView_ animationEndFrame] :
- [containerView_ frame];
-
- [self showChevronIfNecessaryInFrame:frame animate:animate];
-
- if (!animate) {
- [[NSNotificationCenter defaultCenter]
- postNotificationName:kBrowserActionVisibilityChangedNotification
- object:self];
- }
-}
-
-- (NSView*)browserActionViewForExtension:(const Extension*)extension {
- for (BrowserActionButton* button in [buttons_ allValues]) {
- if ([button extension] == extension)
- return button;
- }
- NOTREACHED();
- return nil;
-}
-
-- (CGFloat)savedWidth {
- if (!toolbarModel_)
- return 0;
- if (!profile_->GetPrefs()->HasPrefPath(prefs::kExtensionToolbarSize)) {
- // Migration code to the new VisibleIconCount pref.
- // TODO(mpcomplete): remove this at some point.
- double predefinedWidth =
- profile_->GetPrefs()->GetReal(prefs::kBrowserActionContainerWidth);
- if (predefinedWidth != 0) {
- int iconWidth = kBrowserActionWidth + kBrowserActionButtonPadding;
- int extraWidth = kChevronWidth;
- toolbarModel_->SetVisibleIconCount(
- (predefinedWidth - extraWidth) / iconWidth);
- }
- }
-
- int savedButtonCount = toolbarModel_->GetVisibleIconCount();
- if (savedButtonCount < 0 || // all icons are visible
- static_cast<NSUInteger>(savedButtonCount) > [self buttonCount])
- savedButtonCount = [self buttonCount];
- return [self containerWidthWithButtonCount:savedButtonCount];
-}
-
-- (NSPoint)popupPointForBrowserAction:(const Extension*)extension {
- if (!extension->browser_action())
- return NSZeroPoint;
-
- NSButton* button = [self buttonForExtension:extension];
- if (!button)
- return NSZeroPoint;
-
- if ([hiddenButtons_ containsObject:button])
- button = chevronMenuButton_.get();
-
- // Anchor point just above the center of the bottom.
- const NSRect bounds = [button bounds];
- DCHECK([button isFlipped]);
- NSPoint anchor = NSMakePoint(NSMidX(bounds),
- NSMaxY(bounds) - kBrowserActionBubbleYOffset);
- return [button convertPoint:anchor toView:nil];
-}
-
-- (BOOL)chevronIsHidden {
- if (!chevronMenuButton_.get())
- return YES;
-
- if (![chevronAnimation_ isAnimating])
- return [chevronMenuButton_ isHidden];
-
- DCHECK([[chevronAnimation_ viewAnimations] count] > 0);
-
- // The chevron is animating in or out. Determine which one and have the return
- // value reflect where the animation is headed.
- NSString* effect = [[[chevronAnimation_ viewAnimations] objectAtIndex:0]
- valueForKey:NSViewAnimationEffectKey];
- if (effect == NSViewAnimationFadeInEffect) {
- return NO;
- } else if (effect == NSViewAnimationFadeOutEffect) {
- return YES;
- }
-
- NOTREACHED();
- return YES;
-}
-
-+ (void)registerUserPrefs:(PrefService*)prefs {
- prefs->RegisterRealPref(prefs::kBrowserActionContainerWidth, 0);
-}
-
-#pragma mark -
-#pragma mark Private Methods
-
-- (void)createButtons {
- if (!toolbarModel_)
- return;
-
- NSUInteger i = 0;
- for (ExtensionList::iterator iter = toolbarModel_->begin();
- iter != toolbarModel_->end(); ++iter) {
- if (![self shouldDisplayBrowserAction:*iter])
- continue;
-
- [self createActionButtonForExtension:*iter withIndex:i++];
- }
-
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(actionButtonUpdated:)
- name:kBrowserActionButtonUpdatedNotification
- object:nil];
-
- CGFloat width = [self savedWidth];
- [containerView_ resizeToWidth:width animate:NO];
-}
-
-- (void)createActionButtonForExtension:(const Extension*)extension
- withIndex:(NSUInteger)index {
- if (!extension->browser_action())
- return;
-
- if (![self shouldDisplayBrowserAction:extension])
- return;
-
- if (profile_->IsOffTheRecord())
- index = toolbarModel_->OriginalIndexToIncognito(index);
-
- // Show the container if it's the first button. Otherwise it will be shown
- // already.
- if ([self buttonCount] == 0)
- [containerView_ setHidden:NO];
-
- NSRect buttonFrame = NSMakeRect(0.0, kBrowserActionOriginYOffset,
- kBrowserActionWidth, kBrowserActionHeight);
- BrowserActionButton* newButton =
- [[[BrowserActionButton alloc]
- initWithFrame:buttonFrame
- extension:extension
- profile:profile_
- tabId:[self currentTabId]] autorelease];
- [newButton setTarget:self];
- [newButton setAction:@selector(browserActionClicked:)];
- NSString* buttonKey = base::SysUTF8ToNSString(extension->id());
- if (!buttonKey)
- return;
- [buttons_ setObject:newButton forKey:buttonKey];
-
- [self positionActionButtonsAndAnimate:NO];
-
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(actionButtonDragging:)
- name:kBrowserActionButtonDraggingNotification
- object:newButton];
-
-
- [containerView_ setMaxWidth:
- [self containerWidthWithButtonCount:[self buttonCount]]];
- [containerView_ setNeedsDisplay:YES];
-}
-
-- (void)removeActionButtonForExtension:(const Extension*)extension {
- if (!extension->browser_action())
- return;
-
- NSString* buttonKey = base::SysUTF8ToNSString(extension->id());
- if (!buttonKey)
- return;
-
- BrowserActionButton* button = [buttons_ objectForKey:buttonKey];
- // This could be the case in incognito, where only a subset of extensions are
- // shown.
- if (!button)
- return;
-
- [button removeFromSuperview];
- // It may or may not be hidden, but it won't matter to NSMutableArray either
- // way.
- [hiddenButtons_ removeObject:button];
- [self updateOverflowMenu];
-
- [buttons_ removeObjectForKey:buttonKey];
- if ([self buttonCount] == 0) {
- // No more buttons? Hide the container.
- [containerView_ setHidden:YES];
- } else {
- [self positionActionButtonsAndAnimate:NO];
- }
- [containerView_ setMaxWidth:
- [self containerWidthWithButtonCount:[self buttonCount]]];
- [containerView_ setNeedsDisplay:YES];
-}
-
-- (void)positionActionButtonsAndAnimate:(BOOL)animate {
- NSUInteger i = 0;
- for (ExtensionList::iterator iter = toolbarModel_->begin();
- iter != toolbarModel_->end(); ++iter) {
- if (![self shouldDisplayBrowserAction:*iter])
- continue;
- BrowserActionButton* button = [self buttonForExtension:(*iter)];
- if (!button)
- continue;
- if (![button isBeingDragged])
- [self moveButton:button toIndex:i animate:animate];
- ++i;
- }
-}
-
-- (void)updateButtonOpacity {
- for (BrowserActionButton* button in [buttons_ allValues]) {
- NSRect buttonFrame = [button frame];
- if (NSContainsRect([containerView_ bounds], buttonFrame)) {
- if ([button alphaValue] != 1.0)
- [button setAlphaValue:1.0];
-
- continue;
- }
- CGFloat intersectionWidth =
- NSWidth(NSIntersectionRect([containerView_ bounds], buttonFrame));
- CGFloat alpha = std::max(0.0f, intersectionWidth / NSWidth(buttonFrame));
- [button setAlphaValue:alpha];
- [button setNeedsDisplay:YES];
- }
-}
-
-- (BrowserActionButton*)buttonForExtension:(const Extension*)extension {
- NSString* extensionId = base::SysUTF8ToNSString(extension->id());
- DCHECK(extensionId);
- if (!extensionId)
- return nil;
- return [buttons_ objectForKey:extensionId];
-}
-
-- (CGFloat)containerWidthWithButtonCount:(NSUInteger)buttonCount {
- // Left-side padding which works regardless of whether a button or
- // chevron leads.
- CGFloat width = kBrowserActionLeftPadding;
-
- // Include the buttons and padding between.
- if (buttonCount > 0) {
- width += buttonCount * kBrowserActionWidth;
- width += (buttonCount - 1) * kBrowserActionButtonPadding;
- }
-
- // Make room for the chevron if any buttons are hidden.
- if ([self buttonCount] != [self visibleButtonCount]) {
- // Chevron and buttons both include 1px padding w/in their bounds,
- // so this leaves 2px between the last browser action and chevron,
- // and also works right if the chevron is the only button.
- width += kChevronWidth;
- }
-
- return width;
-}
-
-- (NSUInteger)containerButtonCapacity {
- // Edge-to-edge span of the browser action buttons.
- CGFloat actionSpan = [self savedWidth] - kBrowserActionLeftPadding;
-
- // Add in some padding for the browser action on the end, then
- // divide out to get the number of action buttons that fit.
- return (actionSpan + kBrowserActionButtonPadding) /
- (kBrowserActionWidth + kBrowserActionButtonPadding);
-}
-
-- (void)containerFrameChanged:(NSNotification*)notification {
- [self updateButtonOpacity];
- [[containerView_ window] invalidateCursorRectsForView:containerView_];
- [self updateChevronPositionInFrame:[containerView_ frame]];
-}
-
-- (void)containerDragStart:(NSNotification*)notification {
- [self setChevronHidden:YES inFrame:[containerView_ frame] animate:YES];
- while([hiddenButtons_ count] > 0) {
- [containerView_ addSubview:[hiddenButtons_ objectAtIndex:0]];
- [hiddenButtons_ removeObjectAtIndex:0];
- }
-}
-
-- (void)containerDragging:(NSNotification*)notification {
- [[NSNotificationCenter defaultCenter]
- postNotificationName:kBrowserActionGrippyDraggingNotification
- object:self];
-}
-
-- (void)containerDragFinished:(NSNotification*)notification {
- for (ExtensionList::iterator iter = toolbarModel_->begin();
- iter != toolbarModel_->end(); ++iter) {
- BrowserActionButton* button = [self buttonForExtension:(*iter)];
- NSRect buttonFrame = [button frame];
- if (NSContainsRect([containerView_ bounds], buttonFrame))
- continue;
-
- CGFloat intersectionWidth =
- NSWidth(NSIntersectionRect([containerView_ bounds], buttonFrame));
- // Pad the threshold by 5 pixels in order to have the buttons hide more
- // easily.
- if (([containerView_ grippyPinned] && intersectionWidth > 0) ||
- (intersectionWidth <= (NSWidth(buttonFrame) / 2) + 5.0)) {
- [button setAlphaValue:0.0];
- [button removeFromSuperview];
- [hiddenButtons_ addObject:button];
- }
- }
- [self updateOverflowMenu];
- [self updateGrippyCursors];
-
- if (!profile_->IsOffTheRecord())
- toolbarModel_->SetVisibleIconCount([self visibleButtonCount]);
-
- [[NSNotificationCenter defaultCenter]
- postNotificationName:kBrowserActionGrippyDragFinishedNotification
- object:self];
-}
-
-- (void)actionButtonUpdated:(NSNotification*)notification {
- BrowserActionButton* button = [notification object];
- if (![hiddenButtons_ containsObject:button])
- return;
-
- // +1 item because of the title placeholder. See |updateOverflowMenu|.
- NSUInteger menuIndex = [hiddenButtons_ indexOfObject:button] + 1;
- NSMenuItem* item = [[chevronMenuButton_ attachedMenu] itemAtIndex:menuIndex];
- DCHECK(button == [item representedObject]);
- [item setImage:[button compositedImage]];
-}
-
-- (void)actionButtonDragging:(NSNotification*)notification {
- if (![self chevronIsHidden])
- [self setChevronHidden:YES inFrame:[containerView_ frame] animate:YES];
-
- // Determine what index the dragged button should lie in, alter the model and
- // reposition the buttons.
- CGFloat dragThreshold = std::floor(kBrowserActionWidth / 2);
- BrowserActionButton* draggedButton = [notification object];
- NSRect draggedButtonFrame = [draggedButton frame];
-
- NSUInteger index = 0;
- for (ExtensionList::iterator iter = toolbarModel_->begin();
- iter != toolbarModel_->end(); ++iter) {
- BrowserActionButton* button = [self buttonForExtension:(*iter)];
- CGFloat intersectionWidth =
- NSWidth(NSIntersectionRect(draggedButtonFrame, [button frame]));
-
- if (intersectionWidth > dragThreshold && button != draggedButton &&
- ![button isAnimating] && index < [self visibleButtonCount]) {
- toolbarModel_->MoveBrowserAction([draggedButton extension], index);
- [self positionActionButtonsAndAnimate:YES];
- return;
- }
- ++index;
- }
-}
-
-- (void)actionButtonDragFinished:(NSNotification*)notification {
- [self showChevronIfNecessaryInFrame:[containerView_ frame] animate:YES];
- [self positionActionButtonsAndAnimate:YES];
-}
-
-- (void)moveButton:(BrowserActionButton*)button
- toIndex:(NSUInteger)index
- animate:(BOOL)animate {
- CGFloat xOffset = kBrowserActionLeftPadding +
- (index * (kBrowserActionWidth + kBrowserActionButtonPadding));
- NSRect buttonFrame = [button frame];
- buttonFrame.origin.x = xOffset;
- [button setFrame:buttonFrame animate:animate];
-
- if (index < [self containerButtonCapacity]) {
- // Make sure the button is within the visible container.
- if ([button superview] != containerView_) {
- [containerView_ addSubview:button];
- [button setAlphaValue:1.0];
- [hiddenButtons_ removeObjectIdenticalTo:button];
- }
- } else if (![hiddenButtons_ containsObject:button]) {
- [hiddenButtons_ addObject:button];
- [button removeFromSuperview];
- [button setAlphaValue:0.0];
- [self updateOverflowMenu];
- }
-}
-
-- (void)browserActionClicked:(BrowserActionButton*)button {
- int tabId = [self currentTabId];
- if (tabId < 0) {
- NOTREACHED() << "No current tab.";
- return;
- }
-
- ExtensionAction* action = [button extension]->browser_action();
- if (action->HasPopup(tabId)) {
- GURL popupUrl = action->GetPopupUrl(tabId);
- // If a popup is already showing, check if the popup URL is the same. If so,
- // then close the popup.
- ExtensionPopupController* popup = [ExtensionPopupController popup];
- if (popup &&
- [[popup window] isVisible] &&
- [popup extensionHost]->GetURL() == popupUrl) {
- [popup close];
- return;
- }
- NSPoint arrowPoint = [self popupPointForBrowserAction:[button extension]];
- [ExtensionPopupController showURL:popupUrl
- inBrowser:browser_
- anchoredAt:arrowPoint
- arrowLocation:info_bubble::kTopRight
- devMode:NO];
- } else {
- ExtensionBrowserEventRouter::GetInstance()->BrowserActionExecuted(
- profile_, action->extension_id(), browser_);
- }
-}
-
-- (BOOL)shouldDisplayBrowserAction:(const Extension*)extension {
- // Only display incognito-enabled extensions while in incognito mode.
- return (!profile_->IsOffTheRecord() ||
- profile_->GetExtensionsService()->IsIncognitoEnabled(extension));
-}
-
-- (void)showChevronIfNecessaryInFrame:(NSRect)frame animate:(BOOL)animate {
- [self setChevronHidden:([self buttonCount] == [self visibleButtonCount])
- inFrame:frame
- animate:animate];
-}
-
-- (void)updateChevronPositionInFrame:(NSRect)frame {
- CGFloat xPos = NSWidth(frame) - kChevronWidth;
- NSRect buttonFrame = NSMakeRect(xPos,
- kBrowserActionOriginYOffset,
- kChevronWidth,
- kBrowserActionHeight);
- [chevronMenuButton_ setFrame:buttonFrame];
-}
-
-- (void)setChevronHidden:(BOOL)hidden
- inFrame:(NSRect)frame
- animate:(BOOL)animate {
- if (hidden == [self chevronIsHidden])
- return;
-
- if (!chevronMenuButton_.get()) {
- chevronMenuButton_.reset([[ChevronMenuButton alloc] init]);
- [chevronMenuButton_ setBordered:NO];
- [chevronMenuButton_ setShowsBorderOnlyWhileMouseInside:YES];
- NSImage* chevronImage = nsimage_cache::ImageNamed(kOverflowChevronsName);
- [chevronMenuButton_ setImage:chevronImage];
- [containerView_ addSubview:chevronMenuButton_];
- }
-
- if (!hidden)
- [self updateOverflowMenu];
-
- [self updateChevronPositionInFrame:frame];
-
- // Stop any running animation.
- [chevronAnimation_ stopAnimation];
-
- if (!animate) {
- [chevronMenuButton_ setHidden:hidden];
- return;
- }
-
- NSDictionary* animationDictionary;
- if (hidden) {
- animationDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
- chevronMenuButton_.get(), NSViewAnimationTargetKey,
- NSViewAnimationFadeOutEffect, NSViewAnimationEffectKey,
- nil];
- } else {
- [chevronMenuButton_ setHidden:NO];
- animationDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
- chevronMenuButton_.get(), NSViewAnimationTargetKey,
- NSViewAnimationFadeInEffect, NSViewAnimationEffectKey,
- nil];
- }
- [chevronAnimation_ setViewAnimations:
- [NSArray arrayWithObject:animationDictionary]];
- [chevronAnimation_ startAnimation];
-}
-
-- (void)chevronItemSelected:(id)menuItem {
- [self browserActionClicked:[menuItem representedObject]];
-}
-
-- (void)updateOverflowMenu {
- overflowMenu_.reset([[NSMenu alloc] initWithTitle:@""]);
- // See menu_button.h for documentation on why this is needed.
- [overflowMenu_ addItemWithTitle:@"" action:nil keyEquivalent:@""];
-
- for (BrowserActionButton* button in hiddenButtons_.get()) {
- NSString* name = base::SysUTF8ToNSString([button extension]->name());
- NSMenuItem* item =
- [overflowMenu_ addItemWithTitle:name
- action:@selector(chevronItemSelected:)
- keyEquivalent:@""];
- [item setRepresentedObject:button];
- [item setImage:[button compositedImage]];
- [item setTarget:self];
- }
- [chevronMenuButton_ setAttachedMenu:overflowMenu_];
-}
-
-- (void)updateGrippyCursors {
- [containerView_ setCanDragLeft:[hiddenButtons_ count] > 0];
- [containerView_ setCanDragRight:[self visibleButtonCount] > 0];
- [[containerView_ window] invalidateCursorRectsForView:containerView_];
-}
-
-- (int)currentTabId {
- TabContents* selected_tab = browser_->GetSelectedTabContents();
- if (!selected_tab)
- return -1;
-
- return selected_tab->controller().session_id().id();
-}
-
-#pragma mark -
-#pragma mark Testing Methods
-
-- (NSButton*)buttonWithIndex:(NSUInteger)index {
- if (profile_->IsOffTheRecord())
- index = toolbarModel_->IncognitoIndexToOriginal(index);
- if (index < toolbarModel_->size()) {
- const Extension* extension = toolbarModel_->GetExtensionByIndex(index);
- return [buttons_ objectForKey:base::SysUTF8ToNSString(extension->id())];
- }
- return nil;
-}
-
-@end
diff --git a/chrome/browser/cocoa/extensions/chevron_menu_button.h b/chrome/browser/cocoa/extensions/chevron_menu_button.h
deleted file mode 100644
index ea4ccc2..0000000
--- a/chrome/browser/cocoa/extensions/chevron_menu_button.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_EXTENSIONS_CHEVRON_MENU_BUTTON_H_
-#define CHROME_BROWSER_COCOA_EXTENSIONS_CHEVRON_MENU_BUTTON_H_
-#pragma once
-
-#import "chrome/browser/cocoa/menu_button.h"
-
-@interface ChevronMenuButton : MenuButton {
-}
-
-// Overrides cell class with |ChevronMenuButtonCell|.
-+ (Class)cellClass;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_EXTENSIONS_CHEVRON_MENU_BUTTON_H_
diff --git a/chrome/browser/cocoa/extensions/chevron_menu_button.mm b/chrome/browser/cocoa/extensions/chevron_menu_button.mm
deleted file mode 100644
index 37159ae..0000000
--- a/chrome/browser/cocoa/extensions/chevron_menu_button.mm
+++ /dev/null
@@ -1,15 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/extensions/chevron_menu_button.h"
-
-#include "chrome/browser/cocoa/extensions/chevron_menu_button_cell.h"
-
-@implementation ChevronMenuButton
-
-+ (Class)cellClass {
- return [ChevronMenuButtonCell class];
-}
-
-@end
diff --git a/chrome/browser/cocoa/extensions/chevron_menu_button_cell.h b/chrome/browser/cocoa/extensions/chevron_menu_button_cell.h
deleted file mode 100644
index c3217e3..0000000
--- a/chrome/browser/cocoa/extensions/chevron_menu_button_cell.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_EXTENSIONS_CHEVRON_MENU_BUTTON_CELL_H_
-#define CHROME_BROWSER_COCOA_EXTENSIONS_CHEVRON_MENU_BUTTON_CELL_H_
-#pragma once
-
-#import "chrome/browser/cocoa/clickhold_button_cell.h"
-
-@interface ChevronMenuButtonCell : ClickHoldButtonCell {
-}
-
-// Adds a gradient border to the RHS of the cell when not hovered.
-- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_EXTENSIONS_CHEVRON_MENU_BUTTON_CELL_H_
diff --git a/chrome/browser/cocoa/extensions/chevron_menu_button_cell.mm b/chrome/browser/cocoa/extensions/chevron_menu_button_cell.mm
deleted file mode 100644
index 6a8b829..0000000
--- a/chrome/browser/cocoa/extensions/chevron_menu_button_cell.mm
+++ /dev/null
@@ -1,47 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/extensions/chevron_menu_button_cell.h"
-
-namespace {
-
-// Width of the divider.
-const CGFloat kDividerWidth = 1.0;
-
-// Vertical inset from edge of cell to divider start.
-const CGFloat kDividerInset = 3.0;
-
-// Grayscale for the center of the divider.
-const CGFloat kDividerGrayscale = 0.5;
-
-} // namespace
-
-@implementation ChevronMenuButtonCell
-
-- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
- [super drawWithFrame:cellFrame inView:controlView];
-
- if ([self isMouseInside])
- return;
-
- NSColor* middleColor =
- [NSColor colorWithCalibratedWhite:kDividerGrayscale alpha:1.0];
- NSColor* endPointColor = [middleColor colorWithAlphaComponent:0.0];
-
- // Blend from background to |kDividerGrayscale| and back to
- // background.
- scoped_nsobject<NSGradient> borderGradient([[NSGradient alloc]
- initWithColorsAndLocations:endPointColor, (CGFloat)0.0,
- middleColor, (CGFloat)0.5,
- endPointColor, (CGFloat)1.0,
- nil]);
-
- NSRect edgeRect, remainder;
- NSDivideRect(cellFrame, &edgeRect, &remainder, kDividerWidth, NSMaxXEdge);
- edgeRect = NSInsetRect(edgeRect, 0.0, kDividerInset);
-
- [borderGradient drawInRect:edgeRect angle:90.0];
-}
-
-@end
diff --git a/chrome/browser/cocoa/extensions/chevron_menu_button_unittest.mm b/chrome/browser/cocoa/extensions/chevron_menu_button_unittest.mm
deleted file mode 100644
index e5c2f77..0000000
--- a/chrome/browser/cocoa/extensions/chevron_menu_button_unittest.mm
+++ /dev/null
@@ -1,50 +0,0 @@
-// 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 "chrome/browser/cocoa/extensions/chevron_menu_button.h"
-#import "chrome/browser/cocoa/extensions/chevron_menu_button_cell.h"
-
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-
-namespace {
-
-class ChevronMenuButtonTest : public CocoaTest {
- public:
- ChevronMenuButtonTest() {
- NSRect frame = NSMakeRect(0, 0, 50, 30);
- scoped_nsobject<ChevronMenuButton> button(
- [[ChevronMenuButton alloc] initWithFrame:frame]);
- button_ = button.get();
- [[test_window() contentView] addSubview:button_];
- }
-
- ChevronMenuButton* button_;
-};
-
-// Test basic view operation.
-TEST_VIEW(ChevronMenuButtonTest, button_);
-
-// |ChevronMenuButton exists entirely to override the cell class.
-TEST_F(ChevronMenuButtonTest, CellSubclass) {
- EXPECT_TRUE([[button_ cell] isKindOfClass:[ChevronMenuButtonCell class]]);
-}
-
-// Test both hovered and non-hovered display.
-TEST_F(ChevronMenuButtonTest, HoverAndNonHoverDisplay) {
- ChevronMenuButtonCell* cell = [button_ cell];
- EXPECT_FALSE([cell showsBorderOnlyWhileMouseInside]);
- EXPECT_FALSE([cell isMouseInside]);
-
- [cell setShowsBorderOnlyWhileMouseInside:YES];
- [cell mouseEntered:nil];
- EXPECT_TRUE([cell isMouseInside]);
- [button_ display];
-
- [cell mouseExited:nil];
- EXPECT_FALSE([cell isMouseInside]);
- [button_ display];
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/extensions/extension_action_context_menu.h b/chrome/browser/cocoa/extensions/extension_action_context_menu.h
deleted file mode 100644
index 80e8398..0000000
--- a/chrome/browser/cocoa/extensions/extension_action_context_menu.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_EXTENSIONS_EXTENSION_ACTION_CONTEXT_MENU_H_
-#define CHROME_BROWSER_COCOA_EXTENSIONS_EXTENSION_ACTION_CONTEXT_MENU_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_ptr.h"
-#include "base/scoped_nsobject.h"
-
-class AsyncUninstaller;
-class DevmodeObserver;
-class Extension;
-class ExtensionAction;
-class NotificationRegistrar;
-class Profile;
-
-namespace extension_action_context_menu {
-
-class DevmodeObserver;
-
-} // namespace extension_action_context_menu
-
-// A context menu used by any extension UI components that require it.
-@interface ExtensionActionContextMenu : NSMenu {
- @private
- // The extension that this menu belongs to. Weak.
- const Extension* extension_;
-
- // The extension action this menu belongs to. Weak.
- ExtensionAction* action_;
-
- // The browser profile of the window that contains this extension. Weak.
- Profile* profile_;
-
- // The inspector menu item. Need to keep this around to add and remove it.
- scoped_nsobject<NSMenuItem> inspectorItem_;
-
- // The observer used to listen for pref changed notifications.
- scoped_ptr<extension_action_context_menu::DevmodeObserver> observer_;
-
- // Used to load the extension icon asynchronously on the I/O thread then show
- // the uninstall confirmation dialog.
- scoped_ptr<AsyncUninstaller> uninstaller_;
-}
-
-// Initializes and returns a context menu for the given extension and profile.
-- (id)initWithExtension:(const Extension*)extension
- profile:(Profile*)profile
- extensionAction:(ExtensionAction*)action;
-
-// Show or hide the inspector menu item.
-- (void)updateInspectorItem;
-
-@end
-
-typedef ExtensionActionContextMenu ExtensionActionContextMenuMac;
-
-#endif // CHROME_BROWSER_COCOA_EXTENSIONS_EXTENSION_ACTION_CONTEXT_MENU_H_
diff --git a/chrome/browser/cocoa/extensions/extension_action_context_menu.mm b/chrome/browser/cocoa/extensions/extension_action_context_menu.mm
deleted file mode 100644
index 36ff520..0000000
--- a/chrome/browser/cocoa/extensions/extension_action_context_menu.mm
+++ /dev/null
@@ -1,278 +0,0 @@
-// 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 "chrome/browser/cocoa/extensions/extension_action_context_menu.h"
-
-#include "app/l10n_util_mac.h"
-#include "base/sys_string_conversions.h"
-#include "base/task.h"
-#include "chrome/browser/browser_list.h"
-#include "chrome/browser/cocoa/browser_window_cocoa.h"
-#include "chrome/browser/cocoa/browser_window_controller.h"
-#include "chrome/browser/cocoa/extensions/browser_actions_controller.h"
-#include "chrome/browser/cocoa/extensions/extension_popup_controller.h"
-#include "chrome/browser/cocoa/info_bubble_view.h"
-#import "chrome/browser/cocoa/location_bar/location_bar_view_mac.h"
-#include "chrome/browser/cocoa/toolbar_controller.h"
-#include "chrome/browser/extensions/extension_install_ui.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/extensions/extension_tabs_module.h"
-#include "chrome/browser/prefs/pref_change_registrar.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_action.h"
-#include "chrome/common/extensions/extension_constants.h"
-#include "chrome/common/notification_details.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_type.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/url_constants.h"
-#include "grit/generated_resources.h"
-
-// A class that loads the extension icon on the I/O thread before showing the
-// confirmation dialog to uninstall the given extension.
-// Also acts as the extension's UI delegate in order to display the dialog.
-class AsyncUninstaller : public ExtensionInstallUI::Delegate {
- public:
- AsyncUninstaller(const Extension* extension, Profile* profile)
- : extension_(extension),
- profile_(profile) {
- install_ui_.reset(new ExtensionInstallUI(profile));
- install_ui_->ConfirmUninstall(this, extension_);
- }
-
- ~AsyncUninstaller() {}
-
- // Overridden by ExtensionInstallUI::Delegate.
- virtual void InstallUIProceed() {
- profile_->GetExtensionsService()->
- UninstallExtension(extension_->id(), false);
- }
-
- virtual void InstallUIAbort() {}
-
- private:
- // The extension that we're loading the icon for. Weak.
- const Extension* extension_;
-
- // The current profile. Weak.
- Profile* profile_;
-
- scoped_ptr<ExtensionInstallUI> install_ui_;
-
- DISALLOW_COPY_AND_ASSIGN(AsyncUninstaller);
-};
-
-namespace extension_action_context_menu {
-
-class DevmodeObserver : public NotificationObserver {
- public:
- DevmodeObserver(ExtensionActionContextMenu* menu,
- PrefService* service)
- : menu_(menu), pref_service_(service) {
- registrar_.Init(pref_service_);
- registrar_.Add(prefs::kExtensionsUIDeveloperMode, this);
- }
- virtual ~DevmodeObserver() {}
-
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- if (type == NotificationType::PREF_CHANGED)
- [menu_ updateInspectorItem];
- else
- NOTREACHED();
- }
-
- private:
- ExtensionActionContextMenu* menu_;
- PrefService* pref_service_;
- PrefChangeRegistrar registrar_;
-};
-
-} // namespace extension_action_context_menu
-
-@interface ExtensionActionContextMenu(Private)
-// Callback for the context menu items.
-- (void)dispatch:(id)menuItem;
-@end
-
-@implementation ExtensionActionContextMenu
-
-namespace {
-// Enum of menu item choices to their respective indices.
-// NOTE: You MUST keep this in sync with the |menuItems| NSArray below.
-enum {
- kExtensionContextName = 0,
- kExtensionContextOptions = 2,
- kExtensionContextDisable = 3,
- kExtensionContextUninstall = 4,
- kExtensionContextManage = 6,
- kExtensionContextInspect = 7
-};
-
-int CurrentTabId() {
- Browser* browser = BrowserList::GetLastActive();
- if(!browser)
- return -1;
- TabContents* contents = browser->GetSelectedTabContents();
- if (!contents)
- return -1;
- return ExtensionTabUtil::GetTabId(contents);
-}
-
-} // namespace
-
-- (id)initWithExtension:(const Extension*)extension
- profile:(Profile*)profile
- extensionAction:(ExtensionAction*)action{
- if ((self = [super initWithTitle:@""])) {
- action_ = action;
- extension_ = extension;
- profile_ = profile;
-
- NSArray* menuItems = [NSArray arrayWithObjects:
- base::SysUTF8ToNSString(extension->name()),
- [NSMenuItem separatorItem],
- l10n_util::GetNSStringWithFixup(IDS_EXTENSIONS_OPTIONS),
- l10n_util::GetNSStringWithFixup(IDS_EXTENSIONS_DISABLE),
- l10n_util::GetNSStringWithFixup(IDS_EXTENSIONS_UNINSTALL),
- [NSMenuItem separatorItem],
- l10n_util::GetNSStringWithFixup(IDS_MANAGE_EXTENSIONS),
- nil];
-
- for (id item in menuItems) {
- if ([item isKindOfClass:[NSMenuItem class]]) {
- [self addItem:item];
- } else if ([item isKindOfClass:[NSString class]]) {
- NSMenuItem* itemObj = [self addItemWithTitle:item
- action:@selector(dispatch:)
- keyEquivalent:@""];
- // The tag should correspond to the enum above.
- // NOTE: The enum and the order of the menu items MUST be in sync.
- [itemObj setTag:[self indexOfItem:itemObj]];
-
- // Disable the 'Options' item if there are no options to set.
- if ([itemObj tag] == kExtensionContextOptions &&
- extension_->options_url().spec().length() <= 0) {
- // Setting the target to nil will disable the item. For some reason
- // setEnabled:NO does not work.
- [itemObj setTarget:nil];
- } else {
- [itemObj setTarget:self];
- }
- }
- }
-
- NSString* inspectorTitle =
- l10n_util::GetNSStringWithFixup(IDS_EXTENSION_ACTION_INSPECT_POPUP);
- inspectorItem_.reset([[NSMenuItem alloc] initWithTitle:inspectorTitle
- action:@selector(dispatch:)
- keyEquivalent:@""]);
- [inspectorItem_.get() setTarget:self];
- [inspectorItem_.get() setTag:kExtensionContextInspect];
-
- PrefService* service = profile_->GetPrefs();
- observer_.reset(
- new extension_action_context_menu::DevmodeObserver(self, service));
-
- [self updateInspectorItem];
- return self;
- }
- return nil;
-}
-
-- (void)updateInspectorItem {
- PrefService* service = profile_->GetPrefs();
- bool devmode = service->GetBoolean(prefs::kExtensionsUIDeveloperMode);
- if (devmode) {
- if ([self indexOfItem:inspectorItem_.get()] == -1)
- [self addItem:inspectorItem_.get()];
- } else {
- if ([self indexOfItem:inspectorItem_.get()] != -1)
- [self removeItem:inspectorItem_.get()];
- }
-}
-
-- (void)dispatch:(id)menuItem {
- Browser* browser = BrowserList::FindBrowserWithProfile(profile_);
- if (!browser)
- return;
-
- NSMenuItem* item = (NSMenuItem*)menuItem;
- switch ([item tag]) {
- case kExtensionContextName: {
- GURL url(std::string(extension_urls::kGalleryBrowsePrefix) +
- std::string("/detail/") + extension_->id());
- browser->OpenURL(url, GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
- break;
- }
- case kExtensionContextOptions: {
- DCHECK(!extension_->options_url().is_empty());
- profile_->GetExtensionProcessManager()->OpenOptionsPage(extension_,
- browser);
- break;
- }
- case kExtensionContextDisable: {
- ExtensionsService* extensionService = profile_->GetExtensionsService();
- if (!extensionService)
- return; // Incognito mode.
- extensionService->DisableExtension(extension_->id());
- break;
- }
- case kExtensionContextUninstall: {
- uninstaller_.reset(new AsyncUninstaller(extension_, profile_));
- break;
- }
- case kExtensionContextManage: {
- browser->OpenURL(GURL(chrome::kChromeUIExtensionsURL), GURL(),
- NEW_FOREGROUND_TAB, PageTransition::LINK);
- break;
- }
- case kExtensionContextInspect: {
- BrowserWindowCocoa* window =
- static_cast<BrowserWindowCocoa*>(browser->window());
- ToolbarController* toolbarController =
- [window->cocoa_controller() toolbarController];
- LocationBarViewMac* locationBarView =
- [toolbarController locationBarBridge];
-
- NSPoint popupPoint = NSZeroPoint;
- if (extension_->page_action() == action_) {
- popupPoint = locationBarView->GetPageActionBubblePoint(action_);
-
- } else if (extension_->browser_action() == action_) {
- BrowserActionsController* controller =
- [toolbarController browserActionsController];
- popupPoint = [controller popupPointForBrowserAction:extension_];
-
- } else {
- NOTREACHED() << "action_ is not a page action or browser action?";
- }
-
- int tabId = CurrentTabId();
- GURL url = action_->GetPopupUrl(tabId);
- DCHECK(url.is_valid());
- [ExtensionPopupController showURL:url
- inBrowser:BrowserList::GetLastActive()
- anchoredAt:popupPoint
- arrowLocation:info_bubble::kTopRight
- devMode:YES];
- break;
- }
- default:
- NOTREACHED();
- break;
- }
-}
-
-- (BOOL)validateMenuItem:(NSMenuItem*)menuItem {
- if([menuItem isEqualTo:inspectorItem_.get()]) {
- return action_ && action_->HasPopup(CurrentTabId());
- }
- return YES;
-}
-
-@end
diff --git a/chrome/browser/cocoa/extensions/extension_infobar_controller.h b/chrome/browser/cocoa/extensions/extension_infobar_controller.h
deleted file mode 100644
index f17a785..0000000
--- a/chrome/browser/cocoa/extensions/extension_infobar_controller.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_EXTENSIONS_EXTENSION_INFOBAR_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_EXTENSIONS_EXTENSION_INFOBAR_CONTROLLER_H_
-#pragma once
-
-#import "chrome/browser/cocoa/infobar_controller.h"
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-
-@class ExtensionActionContextMenu;
-class ExtensionInfoBarDelegate;
-class InfobarBridge;
-@class MenuButton;
-
-@interface ExtensionInfoBarController : InfoBarController {
- // The native extension view retrieved from the extension host. Weak.
- NSView* extensionView_;
-
- // The window containing this InfoBar. Weak.
- NSWindow* window_;
-
- // The InfoBar's button with the Extension's icon that launches the context
- // menu.
- scoped_nsobject<MenuButton> dropdownButton_;
-
- // The context menu that pops up when the left button is clicked.
- scoped_nsobject<ExtensionActionContextMenu> contextMenu_;
-
- // Helper class to bridge C++ and ObjC functionality together for the infobar.
- scoped_ptr<InfobarBridge> bridge_;
-}
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_EXTENSIONS_EXTENSION_INFOBAR_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/extensions/extension_infobar_controller.mm b/chrome/browser/cocoa/extensions/extension_infobar_controller.mm
deleted file mode 100644
index a2a38f2..0000000
--- a/chrome/browser/cocoa/extensions/extension_infobar_controller.mm
+++ /dev/null
@@ -1,266 +0,0 @@
-// 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 "chrome/browser/cocoa/extensions/extension_infobar_controller.h"
-
-#include <cmath>
-
-#include "app/resource_bundle.h"
-#import "chrome/browser/cocoa/animatable_view.h"
-#import "chrome/browser/cocoa/extensions/extension_action_context_menu.h"
-#import "chrome/browser/cocoa/menu_button.h"
-#include "chrome/browser/cocoa/infobar.h"
-#include "chrome/browser/extensions/extension_host.h"
-#include "chrome/browser/extensions/extension_infobar_delegate.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_icon_set.h"
-#include "chrome/common/extensions/extension_resource.h"
-#include "gfx/canvas_skia.h"
-#include "grit/theme_resources.h"
-#include "skia/ext/skia_utils_mac.h"
-
-namespace {
-const CGFloat kAnimationDuration = 0.12;
-const CGFloat kBottomBorderHeightPx = 1.0;
-const CGFloat kButtonHeightPx = 26.0;
-const CGFloat kButtonLeftMarginPx = 2.0;
-const CGFloat kButtonWidthPx = 34.0;
-const CGFloat kDropArrowLeftMarginPx = 3.0;
-const CGFloat kToolbarMinHeightPx = 36.0;
-const CGFloat kToolbarMaxHeightPx = 72.0;
-} // namespace
-
-@interface ExtensionInfoBarController(Private)
-// Called when the extension's hosted NSView has been resized.
-- (void)extensionViewFrameChanged;
-// Returns the clamped height of the extension view to be within the min and max
-// values defined above.
-- (CGFloat)clampedExtensionViewHeight;
-// Adjusts the width of the extension's hosted view to match the window's width
-// and sets the proper height for it as well.
-- (void)adjustExtensionViewSize;
-// Sets the image to be used in the button on the left side of the infobar.
-- (void)setButtonImage:(NSImage*)image;
-@end
-
-// A helper class to bridge the asynchronous Skia bitmap loading mechanism to
-// the extension's button.
-class InfobarBridge : public ExtensionInfoBarDelegate::DelegateObserver,
- public ImageLoadingTracker::Observer {
- public:
- explicit InfobarBridge(ExtensionInfoBarController* owner)
- : owner_(owner),
- delegate_([owner delegate]->AsExtensionInfoBarDelegate()),
- tracker_(this) {
- delegate_->set_observer(this);
- LoadIcon();
- }
-
- virtual ~InfobarBridge() {
- if (delegate_)
- delegate_->set_observer(NULL);
- }
-
- // Load the Extension's icon image.
- void LoadIcon() {
- const Extension* extension = delegate_->extension_host()->extension();
- ExtensionResource icon_resource = extension->GetIconResource(
- Extension::EXTENSION_ICON_BITTY, ExtensionIconSet::MATCH_EXACTLY);
- if (!icon_resource.relative_path().empty()) {
- tracker_.LoadImage(extension, icon_resource,
- gfx::Size(Extension::EXTENSION_ICON_BITTY,
- Extension::EXTENSION_ICON_BITTY),
- ImageLoadingTracker::DONT_CACHE);
- } else {
- OnImageLoaded(NULL, icon_resource, 0);
- }
- }
-
- // ImageLoadingTracker::Observer implementation.
- // TODO(andybons): The infobar view implementations share a lot of the same
- // code. Come up with a strategy to share amongst them.
- virtual void OnImageLoaded(
- SkBitmap* image, ExtensionResource resource, int index) {
- if (!delegate_)
- return; // The delegate can go away while the image asynchronously loads.
-
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-
- // Fall back on the default extension icon on failure.
- SkBitmap* icon;
- if (!image || image->empty())
- icon = rb.GetBitmapNamed(IDR_EXTENSIONS_SECTION);
- else
- icon = image;
-
- SkBitmap* drop_image = rb.GetBitmapNamed(IDR_APP_DROPARROW);
-
- const int image_size = Extension::EXTENSION_ICON_BITTY;
- scoped_ptr<gfx::CanvasSkia> canvas(
- new gfx::CanvasSkia(
- image_size + kDropArrowLeftMarginPx + drop_image->width(),
- image_size, false));
- canvas->DrawBitmapInt(*icon,
- 0, 0, icon->width(), icon->height(),
- 0, 0, image_size, image_size,
- false);
- canvas->DrawBitmapInt(*drop_image,
- image_size + kDropArrowLeftMarginPx,
- image_size / 2);
- [owner_ setButtonImage:gfx::SkBitmapToNSImage(canvas->ExtractBitmap())];
- }
-
- // Overridden from ExtensionInfoBarDelegate::DelegateObserver:
- virtual void OnDelegateDeleted() {
- delegate_ = NULL;
- }
-
- private:
- // Weak. Owns us.
- ExtensionInfoBarController* owner_;
-
- // Weak.
- ExtensionInfoBarDelegate* delegate_;
-
- // Loads the extensions's icon on the file thread.
- ImageLoadingTracker tracker_;
-
- DISALLOW_COPY_AND_ASSIGN(InfobarBridge);
-};
-
-
-@implementation ExtensionInfoBarController
-
-- (id)initWithDelegate:(InfoBarDelegate*)delegate
- window:(NSWindow*)window {
- if ((self = [super initWithDelegate:delegate])) {
- window_ = window;
- dropdownButton_.reset([[MenuButton alloc] init]);
-
- ExtensionHost* extensionHost = delegate_->AsExtensionInfoBarDelegate()->
- extension_host();
- contextMenu_.reset([[ExtensionActionContextMenu alloc]
- initWithExtension:extensionHost->extension()
- profile:extensionHost->profile()
- extensionAction:NULL]);
- // See menu_button.h for documentation on why this is needed.
- NSMenuItem* dummyItem =
- [[[NSMenuItem alloc] initWithTitle:@""
- action:nil
- keyEquivalent:@""] autorelease];
- [contextMenu_ insertItem:dummyItem atIndex:0];
- [dropdownButton_ setAttachedMenu:contextMenu_.get()];
-
- bridge_.reset(new InfobarBridge(self));
- }
- return self;
-}
-
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [super dealloc];
-}
-
-- (void)addAdditionalControls {
- [self removeButtons];
-
- extensionView_ = delegate_->AsExtensionInfoBarDelegate()->extension_host()->
- view()->native_view();
-
- // Add the extension's RenderWidgetHostViewMac to the view hierarchy of the
- // InfoBar and make sure to place it below the Close button.
- [infoBarView_ addSubview:extensionView_
- positioned:NSWindowBelow
- relativeTo:(NSView*)closeButton_];
-
- // Add the context menu button to the hierarchy.
- [dropdownButton_ setShowsBorderOnlyWhileMouseInside:YES];
- CGFloat buttonY =
- std::floor(NSMidY([infoBarView_ frame]) - (kButtonHeightPx / 2.0)) +
- kBottomBorderHeightPx;
- NSRect buttonFrame = NSMakeRect(
- kButtonLeftMarginPx, buttonY, kButtonWidthPx, kButtonHeightPx);
- [dropdownButton_ setFrame:buttonFrame];
- [dropdownButton_ setAutoresizingMask:NSViewMinYMargin | NSViewMaxYMargin];
- [infoBarView_ addSubview:dropdownButton_];
-
- // Because the parent view has a bottom border, account for it during
- // positioning.
- NSRect extensionFrame = [extensionView_ frame];
- extensionFrame.origin.y = kBottomBorderHeightPx;
-
- [extensionView_ setFrame:extensionFrame];
- // The extension's native view will only have a height that is non-zero if it
- // already has been loaded and rendered, which is the case when you switch
- // back to a tab with an extension infobar within it. The reason this is
- // needed is because the extension view's frame will not have changed in the
- // above case, so the NSViewFrameDidChangeNotification registered below will
- // never fire.
- if (NSHeight(extensionFrame) > 0.0) {
- NSSize infoBarSize = [[self view] frame].size;
- infoBarSize.height = [self clampedExtensionViewHeight] +
- kBottomBorderHeightPx;
- [[self view] setFrameSize:infoBarSize];
- [infoBarView_ setFrameSize:infoBarSize];
- }
-
- [self adjustExtensionViewSize];
-
- // These two notification handlers are here to ensure the width of the
- // native extension view is the same as the browser window's width and that
- // the parent infobar view matches the height of the extension's native view.
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(extensionViewFrameChanged)
- name:NSViewFrameDidChangeNotification
- object:extensionView_];
-
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(adjustWidthToFitWindow)
- name:NSWindowDidResizeNotification
- object:window_];
-}
-
-- (void)extensionViewFrameChanged {
- [self adjustExtensionViewSize];
-
- AnimatableView* view = [self animatableView];
- NSRect infoBarFrame = [view frame];
- CGFloat newHeight = [self clampedExtensionViewHeight] + kBottomBorderHeightPx;
- [infoBarView_ setPostsFrameChangedNotifications:NO];
- infoBarFrame.size.height = newHeight;
- [infoBarView_ setFrame:infoBarFrame];
- [infoBarView_ setPostsFrameChangedNotifications:YES];
- [view animateToNewHeight:newHeight duration:kAnimationDuration];
-}
-
-- (CGFloat)clampedExtensionViewHeight {
- return std::max(kToolbarMinHeightPx,
- std::min(NSHeight([extensionView_ frame]), kToolbarMaxHeightPx));
-}
-
-- (void)adjustExtensionViewSize {
- [extensionView_ setPostsFrameChangedNotifications:NO];
- NSSize extensionViewSize = [extensionView_ frame].size;
- extensionViewSize.width = NSWidth([window_ frame]);
- extensionViewSize.height = [self clampedExtensionViewHeight];
- [extensionView_ setFrameSize:extensionViewSize];
- [extensionView_ setPostsFrameChangedNotifications:YES];
-}
-
-- (void)setButtonImage:(NSImage*)image {
- [dropdownButton_ setImage:image];
-}
-
-@end
-
-InfoBar* ExtensionInfoBarDelegate::CreateInfoBar() {
- NSWindow* window = [(NSView*)tab_contents_->GetContentNativeView() window];
- ExtensionInfoBarController* controller =
- [[ExtensionInfoBarController alloc] initWithDelegate:this
- window:window];
- return new InfoBar(controller);
-}
diff --git a/chrome/browser/cocoa/extensions/extension_install_prompt_controller.h b/chrome/browser/cocoa/extensions/extension_install_prompt_controller.h
deleted file mode 100644
index 8a6a4ce..0000000
--- a/chrome/browser/cocoa/extensions/extension_install_prompt_controller.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_EXTENSION_INSTALL_PROMPT_H_
-#define CHROME_BROWSER_COCOA_EXTENSION_INSTALL_PROMPT_H_
-#pragma once
-
-#include <vector>
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_nsobject.h"
-#include "base/string16.h"
-#include "chrome/browser/extensions/extension_install_ui.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-class Extension;
-class Profile;
-
-// A controller for dialog to let the user install an extension. Created by
-// CrxInstaller.
-@interface ExtensionInstallPromptController : NSWindowController {
-@private
- IBOutlet NSImageView* iconView_;
- IBOutlet NSTextField* titleField_;
- IBOutlet NSTextField* subtitleField_;
- IBOutlet NSTextField* warningsField_;
- IBOutlet NSBox* warningsBox_;
- IBOutlet NSButton* cancelButton_;
- IBOutlet NSButton* okButton_;
-
- NSWindow* parentWindow_; // weak
- Profile* profile_; // weak
- ExtensionInstallUI::Delegate* delegate_; // weak
-
- scoped_nsobject<NSString> title_;
- scoped_nsobject<NSString> warnings_;
- SkBitmap icon_;
-}
-
-@property (nonatomic, readonly) NSImageView* iconView;
-@property (nonatomic, readonly) NSTextField* titleField;
-@property (nonatomic, readonly) NSTextField* subtitleField;
-@property (nonatomic, readonly) NSTextField* warningsField;
-@property (nonatomic, readonly) NSBox* warningsBox;
-@property (nonatomic, readonly) NSButton* cancelButton;
-@property (nonatomic, readonly) NSButton* okButton;
-
-- (id)initWithParentWindow:(NSWindow*)window
- profile:(Profile*)profile
- extension:(const Extension*)extension
- delegate:(ExtensionInstallUI::Delegate*)delegate
- icon:(SkBitmap*)bitmap
- warnings:(const std::vector<string16>&)warnings;
-- (void)runAsModalSheet;
-- (IBAction)cancel:(id)sender;
-- (IBAction)ok:(id)sender;
-
-@end
-
-#endif /* CHROME_BROWSER_COCOA_EXTENSION_INSTALL_PROMPT_H_ */
diff --git a/chrome/browser/cocoa/extensions/extension_install_prompt_controller.mm b/chrome/browser/cocoa/extensions/extension_install_prompt_controller.mm
deleted file mode 100644
index 478eda3..0000000
--- a/chrome/browser/cocoa/extensions/extension_install_prompt_controller.mm
+++ /dev/null
@@ -1,217 +0,0 @@
-// 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 "chrome/browser/cocoa/extensions/extension_install_prompt_controller.h"
-
-#include "app/l10n_util.h"
-#include "app/l10n_util_mac.h"
-#include "base/mac_util.h"
-#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_list.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/common/extensions/extension.h"
-#include "grit/generated_resources.h"
-#include "skia/ext/skia_utils_mac.h"
-
-namespace {
-
-// Maximum height we will adjust controls to when trying to accomodate their
-// contents.
-const CGFloat kMaxControlHeight = 400;
-
-// Adjust a control's height so that its content its not clipped. Returns the
-// amount the control's height had to be adjusted.
-CGFloat AdjustControlHeightToFitContent(NSControl* control) {
- NSRect currentRect = [control frame];
- NSRect fitRect = currentRect;
- fitRect.size.height = kMaxControlHeight;
- CGFloat desiredHeight = [[control cell] cellSizeForBounds:fitRect].height;
- CGFloat offset = desiredHeight - currentRect.size.height;
-
- [control setFrameSize:NSMakeSize(currentRect.size.width,
- currentRect.size.height + offset)];
- return offset;
-}
-
-// Moves the control vertically by the specified amount.
-void OffsetControlVertically(NSControl* control, CGFloat amount) {
- NSPoint origin = [control frame].origin;
- origin.y += amount;
- [control setFrameOrigin:origin];
-}
-
-}
-
-@implementation ExtensionInstallPromptController
-
-@synthesize iconView = iconView_;
-@synthesize titleField = titleField_;
-@synthesize subtitleField = subtitleField_;
-@synthesize warningsField = warningsField_;
-@synthesize warningsBox= warningsBox_;
-@synthesize cancelButton = cancelButton_;
-@synthesize okButton = okButton_;
-
-- (id)initWithParentWindow:(NSWindow*)window
- profile:(Profile*)profile
- extension:(const Extension*)extension
- delegate:(ExtensionInstallUI::Delegate*)delegate
- icon:(SkBitmap*)icon
- warnings:(const std::vector<string16>&)warnings {
- NSString* nibpath = nil;
-
- // We use a different XIB in the case of no warnings, that is a little bit
- // more nicely laid out.
- if (warnings.empty()) {
- nibpath = [mac_util::MainAppBundle()
- pathForResource:@"ExtensionInstallPromptNoWarnings"
- ofType:@"nib"];
- } else {
- nibpath = [mac_util::MainAppBundle()
- pathForResource:@"ExtensionInstallPrompt"
- ofType:@"nib"];
- }
-
- if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
- parentWindow_ = window;
- profile_ = profile;
- icon_ = *icon;
- delegate_ = delegate;
-
- title_.reset(
- [l10n_util::GetNSStringF(IDS_EXTENSION_INSTALL_PROMPT_HEADING,
- UTF8ToUTF16(extension->name())) retain]);
-
- // We display the warnings as a simple text string, separated by newlines.
- if (!warnings.empty()) {
- string16 joined_warnings;
- for (size_t i = 0; i < warnings.size(); ++i) {
- if (i > 0)
- joined_warnings += UTF8ToUTF16("\n\n");
-
- joined_warnings += warnings[i];
- }
-
- warnings_.reset(
- [base::SysUTF16ToNSString(joined_warnings) retain]);
- }
- }
- return self;
-}
-
-- (void)runAsModalSheet {
- [NSApp beginSheet:[self window]
- modalForWindow:parentWindow_
- modalDelegate:self
- didEndSelector:@selector(didEndSheet:returnCode:contextInfo:)
- contextInfo:nil];
-}
-
-- (IBAction)cancel:(id)sender {
- delegate_->InstallUIAbort();
- [NSApp endSheet:[self window]];
-}
-
-- (IBAction)ok:(id)sender {
- delegate_->InstallUIProceed();
- [NSApp endSheet:[self window]];
-}
-
-- (void)awakeFromNib {
- [titleField_ setStringValue:title_.get()];
-
- NSImage* image = gfx::SkBitmapToNSImage(icon_);
- [iconView_ setImage:image];
-
- // Make sure we're the window's delegate as set in the nib.
- DCHECK_EQ(self, static_cast<ExtensionInstallPromptController*>(
- [[self window] delegate]));
-
- // If there are any warnings, then we have to do some special layout.
- if ([warnings_.get() length] > 0) {
- [warningsField_ setStringValue:warnings_.get()];
-
- // The dialog is laid out in the NIB exactly how we want it assuming that
- // each label fits on one line. However, for each label, we want to allow
- // wrapping onto multiple lines. So we accumulate an offset by measuring how
- // big each label wants to be, and comparing it to how bit it actually is.
- // Then we shift each label down and resize by the appropriate amount, then
- // finally resize the window.
- CGFloat totalOffset = 0.0;
-
- // Text fields.
- totalOffset += AdjustControlHeightToFitContent(titleField_);
- OffsetControlVertically(titleField_, -totalOffset);
-
- totalOffset += AdjustControlHeightToFitContent(subtitleField_);
- OffsetControlVertically(subtitleField_, -totalOffset);
-
- CGFloat warningsOffset = AdjustControlHeightToFitContent(warningsField_);
- OffsetControlVertically(warningsField_, -warningsOffset);
- totalOffset += warningsOffset;
-
- NSRect warningsBoxRect = [warningsBox_ frame];
- warningsBoxRect.origin.y -= totalOffset;
- warningsBoxRect.size.height += warningsOffset;
- [warningsBox_ setFrame:warningsBoxRect];
-
- // buttons are positioned automatically in the XIB.
-
- // Finally, adjust the window size.
- NSRect currentRect = [[self window] frame];
- [[self window] setFrame:NSMakeRect(currentRect.origin.x,
- currentRect.origin.y - totalOffset,
- currentRect.size.width,
- currentRect.size.height + totalOffset)
- display:NO];
- }
-}
-
-- (void)didEndSheet:(NSWindow*)sheet
- returnCode:(int)returnCode
- contextInfo:(void*)contextInfo {
- [sheet close];
-}
-
-- (void)windowWillClose:(NSNotification*)notification {
- [self autorelease];
-}
-
-@end // ExtensionInstallPromptController
-
-
-void ExtensionInstallUI::ShowExtensionInstallUIPrompt2Impl(
- Profile* profile,
- Delegate* delegate,
- const Extension* extension,
- SkBitmap* icon,
- const std::vector<string16>& warnings) {
- Browser* browser = BrowserList::GetLastActiveWithProfile(profile);
- if (!browser) {
- delegate->InstallUIAbort();
- return;
- }
-
- BrowserWindow* window = browser->window();
- if (!window) {
- delegate->InstallUIAbort();
- return;
- }
-
- gfx::NativeWindow native_window = window->GetNativeHandle();
-
- ExtensionInstallPromptController* controller =
- [[ExtensionInstallPromptController alloc]
- initWithParentWindow:native_window
- profile:profile
- extension:extension
- delegate:delegate
- icon:icon
- warnings:warnings];
-
- [controller runAsModalSheet];
-}
diff --git a/chrome/browser/cocoa/extensions/extension_install_prompt_controller_unittest.mm b/chrome/browser/cocoa/extensions/extension_install_prompt_controller_unittest.mm
deleted file mode 100644
index 12eadff..0000000
--- a/chrome/browser/cocoa/extensions/extension_install_prompt_controller_unittest.mm
+++ /dev/null
@@ -1,286 +0,0 @@
-// 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 "base/file_path.h"
-#include "base/file_util.h"
-#include "base/path_service.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "base/values.h"
-#import "chrome/browser/cocoa/extensions/extension_install_prompt_controller.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/extensions/extension_install_ui.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/json_value_serializer.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "webkit/glue/image_decoder.h"
-
-
-// Base class for our tests.
-class ExtensionInstallPromptControllerTest : public CocoaTest {
-public:
- ExtensionInstallPromptControllerTest() {
- PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_);
- test_data_dir_ = test_data_dir_.AppendASCII("extensions")
- .AppendASCII("install_prompt");
-
- LoadIcon();
- LoadExtension();
- }
-
- protected:
- void LoadIcon() {
- std::string file_contents;
- file_util::ReadFileToString(test_data_dir_.AppendASCII("icon.png"),
- &file_contents);
-
- webkit_glue::ImageDecoder decoder;
- icon_ = decoder.Decode(
- reinterpret_cast<const unsigned char*>(file_contents.c_str()),
- file_contents.length());
- }
-
- void LoadExtension() {
- FilePath path = test_data_dir_.AppendASCII("extension.json");
-
- std::string error;
- JSONFileValueSerializer serializer(path);
- scoped_ptr<DictionaryValue> value(static_cast<DictionaryValue*>(
- serializer.Deserialize(NULL, &error)));
- if (!value.get()) {
- LOG(ERROR) << error;
- return;
- }
-
- extension_ = Extension::Create(
- path.DirName(), Extension::INVALID, *value, false, &error);
- if (!extension_.get()) {
- LOG(ERROR) << error;
- return;
- }
- }
-
- BrowserTestHelper helper_;
- FilePath test_data_dir_;
- SkBitmap icon_;
- scoped_refptr<Extension> extension_;
-};
-
-
-// Mock out the ExtensionInstallUI::Delegate interface so we can ensure the
-// dialog is interacting with it correctly.
-class MockExtensionInstallUIDelegate : public ExtensionInstallUI::Delegate {
- public:
- MockExtensionInstallUIDelegate()
- : proceed_count_(0),
- abort_count_(0) {}
-
- // ExtensionInstallUI::Delegate overrides.
- virtual void InstallUIProceed() {
- proceed_count_++;
- }
-
- virtual void InstallUIAbort() {
- abort_count_++;
- }
-
- int proceed_count() { return proceed_count_; }
- int abort_count() { return abort_count_; }
-
- protected:
- int proceed_count_;
- int abort_count_;
-};
-
-// Test that we can load the two kinds of prompts correctly, that the outlets
-// are hooked up, and that the dialog calls cancel when cancel is pressed.
-TEST_F(ExtensionInstallPromptControllerTest, BasicsNormalCancel) {
- scoped_ptr<MockExtensionInstallUIDelegate> delegate(
- new MockExtensionInstallUIDelegate);
-
- std::vector<string16> warnings;
- warnings.push_back(UTF8ToUTF16("warning 1"));
-
- scoped_nsobject<ExtensionInstallPromptController>
- controller([[ExtensionInstallPromptController alloc]
- initWithParentWindow:test_window()
- profile:helper_.profile()
- extension:extension_.get()
- delegate:delegate.get()
- icon:&icon_
- warnings:warnings]);
-
- [controller window]; // force nib load
-
- // Test the right nib loaded.
- EXPECT_NSEQ(@"ExtensionInstallPrompt", [controller windowNibName]);
-
- // Check all the controls.
- // Make sure everything is non-nil, and that the fields that are
- // auto-translated don't start with a caret (that would indicate that they
- // were not translated).
- EXPECT_TRUE([controller iconView] != nil);
- EXPECT_TRUE([[controller iconView] image] != nil);
-
- EXPECT_TRUE([controller titleField] != nil);
- EXPECT_NE(0u, [[[controller titleField] stringValue] length]);
-
- EXPECT_TRUE([controller subtitleField] != nil);
- EXPECT_NE(0u, [[[controller subtitleField] stringValue] length]);
- EXPECT_NE('^', [[[controller subtitleField] stringValue] characterAtIndex:0]);
-
- EXPECT_TRUE([controller warningsField] != nil);
- EXPECT_NSEQ([[controller warningsField] stringValue],
- base::SysUTF16ToNSString(warnings[0]));
-
- EXPECT_TRUE([controller warningsBox] != nil);
-
- EXPECT_TRUE([controller cancelButton] != nil);
- EXPECT_NE(0u, [[[controller cancelButton] stringValue] length]);
- EXPECT_NE('^', [[[controller cancelButton] stringValue] characterAtIndex:0]);
-
- EXPECT_TRUE([controller okButton] != nil);
- EXPECT_NE(0u, [[[controller okButton] stringValue] length]);
- EXPECT_NE('^', [[[controller okButton] stringValue] characterAtIndex:0]);
-
- // Test that cancel calls our delegate.
- [controller cancel:nil];
- EXPECT_EQ(1, delegate->abort_count());
- EXPECT_EQ(0, delegate->proceed_count());
-}
-
-
-TEST_F(ExtensionInstallPromptControllerTest, BasicsNormalOK) {
- scoped_ptr<MockExtensionInstallUIDelegate> delegate(
- new MockExtensionInstallUIDelegate);
-
- std::vector<string16> warnings;
- warnings.push_back(UTF8ToUTF16("warning 1"));
-
- scoped_nsobject<ExtensionInstallPromptController>
- controller([[ExtensionInstallPromptController alloc]
- initWithParentWindow:test_window()
- profile:helper_.profile()
- extension:extension_.get()
- delegate:delegate.get()
- icon:&icon_
- warnings:warnings]);
-
- [controller window]; // force nib load
- [controller ok:nil];
-
- EXPECT_EQ(0, delegate->abort_count());
- EXPECT_EQ(1, delegate->proceed_count());
-}
-
-// Test that controls get repositioned when there are two warnings vs one
-// warning.
-TEST_F(ExtensionInstallPromptControllerTest, MultipleWarnings) {
- scoped_ptr<MockExtensionInstallUIDelegate> delegate1(
- new MockExtensionInstallUIDelegate);
- scoped_ptr<MockExtensionInstallUIDelegate> delegate2(
- new MockExtensionInstallUIDelegate);
-
- std::vector<string16> one_warning;
- one_warning.push_back(UTF8ToUTF16("warning 1"));
-
- std::vector<string16> two_warnings;
- two_warnings.push_back(UTF8ToUTF16("warning 1"));
- two_warnings.push_back(UTF8ToUTF16("warning 2"));
-
- scoped_nsobject<ExtensionInstallPromptController>
- controller1([[ExtensionInstallPromptController alloc]
- initWithParentWindow:test_window()
- profile:helper_.profile()
- extension:extension_.get()
- delegate:delegate1.get()
- icon:&icon_
- warnings:one_warning]);
-
- [controller1 window]; // force nib load
-
- scoped_nsobject<ExtensionInstallPromptController>
- controller2([[ExtensionInstallPromptController alloc]
- initWithParentWindow:test_window()
- profile:helper_.profile()
- extension:extension_.get()
- delegate:delegate2.get()
- icon:&icon_
- warnings:two_warnings]);
-
- [controller2 window]; // force nib load
-
- // Test control positioning. We don't test exact positioning because we don't
- // want this to depend on string details and localization. But we do know the
- // relative effect that adding a second warning should have on the layout.
- ASSERT_LT([[controller1 window] frame].size.height,
- [[controller2 window] frame].size.height);
-
- ASSERT_LT([[controller1 warningsField] frame].size.height,
- [[controller2 warningsField] frame].size.height);
-
- ASSERT_LT([[controller1 warningsBox] frame].size.height,
- [[controller2 warningsBox] frame].size.height);
-
- ASSERT_EQ([[controller1 warningsBox] frame].origin.y,
- [[controller2 warningsBox] frame].origin.y);
-
- ASSERT_LT([[controller1 subtitleField] frame].origin.y,
- [[controller2 subtitleField] frame].origin.y);
-
- ASSERT_LT([[controller1 titleField] frame].origin.y,
- [[controller2 titleField] frame].origin.y);
-}
-
-// Test that we can load the skinny prompt correctly, and that the outlets are
-// are hooked up.
-TEST_F(ExtensionInstallPromptControllerTest, BasicsSkinny) {
- scoped_ptr<MockExtensionInstallUIDelegate> delegate(
- new MockExtensionInstallUIDelegate);
-
- // No warnings should trigger skinny prompt.
- std::vector<string16> warnings;
-
- scoped_nsobject<ExtensionInstallPromptController>
- controller([[ExtensionInstallPromptController alloc]
- initWithParentWindow:test_window()
- profile:helper_.profile()
- extension:extension_.get()
- delegate:delegate.get()
- icon:&icon_
- warnings:warnings]);
-
- [controller window]; // force nib load
-
- // Test the right nib loaded.
- EXPECT_NSEQ(@"ExtensionInstallPromptNoWarnings", [controller windowNibName]);
-
- // Check all the controls.
- // In the skinny prompt, only the icon, title and buttons are non-nill.
- // Everything else is nil.
- EXPECT_TRUE([controller iconView] != nil);
- EXPECT_TRUE([[controller iconView] image] != nil);
-
- EXPECT_TRUE([controller titleField] != nil);
- EXPECT_NE(0u, [[[controller titleField] stringValue] length]);
-
- EXPECT_TRUE([controller cancelButton] != nil);
- EXPECT_NE(0u, [[[controller cancelButton] stringValue] length]);
- EXPECT_NE('^', [[[controller cancelButton] stringValue] characterAtIndex:0]);
-
- EXPECT_TRUE([controller okButton] != nil);
- EXPECT_NE(0u, [[[controller okButton] stringValue] length]);
- EXPECT_NE('^', [[[controller okButton] stringValue] characterAtIndex:0]);
-
- EXPECT_TRUE([controller subtitleField] == nil);
- EXPECT_TRUE([controller warningsField] == nil);
- EXPECT_TRUE([controller warningsBox] == nil);
-}
diff --git a/chrome/browser/cocoa/extensions/extension_popup_controller.h b/chrome/browser/cocoa/extensions/extension_popup_controller.h
deleted file mode 100644
index 4fd4c81..0000000
--- a/chrome/browser/cocoa/extensions/extension_popup_controller.h
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_EXTENSIONS_EXTENSION_POPUP_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_EXTENSIONS_EXTENSION_POPUP_CONTROLLER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/cocoa_protocols_mac.h"
-#import "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-#include "chrome/browser/cocoa/info_bubble_view.h"
-#include "googleurl/src/gurl.h"
-
-
-class Browser;
-class DevtoolsNotificationBridge;
-class ExtensionHost;
-@class InfoBubbleWindow;
-class NotificationRegistrar;
-
-// This controller manages a single browser action popup that can appear once a
-// user has clicked on a browser action button. It instantiates the extension
-// popup view showing the content and resizes the window to accomodate any size
-// changes as they occur.
-//
-// There can only be one browser action popup open at a time, so a static
-// variable holds a reference to the current popup.
-@interface ExtensionPopupController : NSWindowController<NSWindowDelegate> {
- @private
- // The native extension view retrieved from the extension host. Weak.
- NSView* extensionView_;
-
- // The popup's parent window. Weak.
- NSWindow* parentWindow_;
-
- // Where the window is anchored. Right now it's the bottom center of the
- // browser action button.
- NSPoint anchor_;
-
- // The current frame of the extension view. Cached to prevent setting the
- // frame if the size hasn't changed.
- NSRect extensionFrame_;
-
- // The extension host object.
- scoped_ptr<ExtensionHost> host_;
-
- scoped_ptr<NotificationRegistrar> registrar_;
- scoped_ptr<DevtoolsNotificationBridge> notificationBridge_;
-
- // Whether the popup has a devtools window attached to it.
- BOOL beingInspected_;
-}
-
-// Returns the ExtensionHost object associated with this popup.
-- (ExtensionHost*)extensionHost;
-
-// Starts the process of showing the given popup URL. Instantiates an
-// ExtensionPopupController with the parent window retrieved from |browser|, a
-// host for the popup created by the extension process manager specific to the
-// browser profile and the remaining arguments |anchoredAt| and |arrowLocation|.
-// |anchoredAt| is expected to be in the window's coordinates at the bottom
-// center of the browser action button.
-// The actual display of the popup is delayed until the page contents finish
-// loading in order to minimize UI flashing and resizing.
-// Passing YES to |devMode| will launch the webkit inspector for the popup,
-// and prevent the popup from closing when focus is lost. It will be closed
-// after the inspector is closed, or another popup is opened.
-+ (ExtensionPopupController*)showURL:(GURL)url
- inBrowser:(Browser*)browser
- anchoredAt:(NSPoint)anchoredAt
- arrowLocation:(info_bubble::BubbleArrowLocation)
- arrowLocation
- devMode:(BOOL)devMode;
-
-// Returns the controller used to display the popup being shown. If no popup is
-// currently open, then nil is returned. Static because only one extension popup
-// window can be open at a time.
-+ (ExtensionPopupController*)popup;
-
-// Whether the popup is in the process of closing (via Core Animation).
-- (BOOL)isClosing;
-
-// Show the dev tools attached to the popup.
-- (void)showDevTools;
-@end
-
-@interface ExtensionPopupController(TestingAPI)
-// Returns a weak pointer to the current popup's view.
-- (NSView*)view;
-// Returns the minimum allowed size for an extension popup.
-+ (NSSize)minPopupSize;
-// Returns the maximum allowed size for an extension popup.
-+ (NSSize)maxPopupSize;
-@end
-
-#endif // CHROME_BROWSER_COCOA_EXTENSIONS_EXTENSION_POPUP_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/extensions/extension_popup_controller.mm b/chrome/browser/cocoa/extensions/extension_popup_controller.mm
deleted file mode 100644
index 55a5ce5..0000000
--- a/chrome/browser/cocoa/extensions/extension_popup_controller.mm
+++ /dev/null
@@ -1,338 +0,0 @@
-// 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 "chrome/browser/cocoa/extensions/extension_popup_controller.h"
-
-#include <algorithm>
-
-#import "chrome/browser/cocoa/browser_window_cocoa.h"
-#import "chrome/browser/cocoa/extension_view_mac.h"
-#import "chrome/browser/cocoa/info_bubble_window.h"
-#include "chrome/browser/debugger/devtools_manager.h"
-#include "chrome/browser/extensions/extension_host.h"
-#include "chrome/browser/extensions/extension_process_manager.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
-
-namespace {
-// The duration for any animations that might be invoked by this controller.
-const NSTimeInterval kAnimationDuration = 0.2;
-
-// There should only be one extension popup showing at one time. Keep a
-// reference to it here.
-static ExtensionPopupController* gPopup;
-
-// Given a value and a rage, clamp the value into the range.
-CGFloat Clamp(CGFloat value, CGFloat min, CGFloat max) {
- return std::max(min, std::min(max, value));
-}
-
-} // namespace
-
-class DevtoolsNotificationBridge : public NotificationObserver {
- public:
- explicit DevtoolsNotificationBridge(ExtensionPopupController* controller)
- : controller_(controller) {}
-
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- switch (type.value) {
- case NotificationType::EXTENSION_HOST_DID_STOP_LOADING: {
- if (Details<ExtensionHost>([controller_ extensionHost]) == details)
- [controller_ showDevTools];
- break;
- }
- case NotificationType::DEVTOOLS_WINDOW_CLOSING: {
- RenderViewHost* rvh = [controller_ extensionHost]->render_view_host();
- if (Details<RenderViewHost>(rvh) == details)
- // Allow the devtools to finish detaching before we close the popup
- [controller_ performSelector:@selector(close)
- withObject:nil
- afterDelay:0.0];
- break;
- }
- default: {
- NOTREACHED() << "Received unexpected notification";
- break;
- }
- };
- }
-
- private:
- ExtensionPopupController* controller_;
-};
-
-@interface ExtensionPopupController(Private)
-// Callers should be using the public static method for initialization.
-// NOTE: This takes ownership of |host|.
-- (id)initWithHost:(ExtensionHost*)host
- parentWindow:(NSWindow*)parentWindow
- anchoredAt:(NSPoint)anchoredAt
- arrowLocation:(info_bubble::BubbleArrowLocation)arrowLocation
- devMode:(BOOL)devMode;
-
-// Called when the extension's hosted NSView has been resized.
-- (void)extensionViewFrameChanged;
-@end
-
-@implementation ExtensionPopupController
-
-- (id)initWithHost:(ExtensionHost*)host
- parentWindow:(NSWindow*)parentWindow
- anchoredAt:(NSPoint)anchoredAt
- arrowLocation:(info_bubble::BubbleArrowLocation)arrowLocation
- devMode:(BOOL)devMode {
-
- parentWindow_ = parentWindow;
- anchor_ = [parentWindow convertBaseToScreen:anchoredAt];
- host_.reset(host);
- beingInspected_ = devMode;
-
- scoped_nsobject<InfoBubbleView> view([[InfoBubbleView alloc] init]);
- if (!view.get())
- return nil;
- [view setArrowLocation:arrowLocation];
- [view setBubbleType:info_bubble::kWhiteInfoBubble];
-
- host->view()->set_is_toolstrip(NO);
-
- extensionView_ = host->view()->native_view();
- NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
- [center addObserver:self
- selector:@selector(extensionViewFrameChanged)
- name:NSViewFrameDidChangeNotification
- object:extensionView_];
-
- // Watch to see if the parent window closes, and if so, close this one.
- [center addObserver:self
- selector:@selector(parentWindowWillClose:)
- name:NSWindowWillCloseNotification
- object:parentWindow_];
-
- [view addSubview:extensionView_];
- scoped_nsobject<InfoBubbleWindow> window(
- [[InfoBubbleWindow alloc]
- initWithContentRect:NSZeroRect
- styleMask:NSBorderlessWindowMask
- backing:NSBackingStoreBuffered
- defer:YES]);
- if (!window.get())
- return nil;
-
- [window setDelegate:self];
- [window setContentView:view];
- self = [super initWithWindow:window];
- if (beingInspected_) {
- // Listen for the the devtools window closing.
- notificationBridge_.reset(new DevtoolsNotificationBridge(self));
- registrar_.reset(new NotificationRegistrar);
- registrar_->Add(notificationBridge_.get(),
- NotificationType::DEVTOOLS_WINDOW_CLOSING,
- Source<Profile>(host->profile()));
- registrar_->Add(notificationBridge_.get(),
- NotificationType::EXTENSION_HOST_DID_STOP_LOADING,
- Source<Profile>(host->profile()));
- }
- return self;
-}
-
-- (void)showDevTools {
- DevToolsManager::GetInstance()->OpenDevToolsWindow(host_->render_view_host());
-}
-
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [super dealloc];
-}
-
-- (void)parentWindowWillClose:(NSNotification*)notification {
- [self close];
-}
-
-- (void)windowWillClose:(NSNotification *)notification {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [gPopup autorelease];
- gPopup = nil;
-}
-
-- (void)windowDidResignKey:(NSNotification *)notification {
- NSWindow* window = [self window];
- DCHECK_EQ([notification object], window);
- // If the window isn't visible, it is already closed, and this notification
- // has been sent as part of the closing operation, so no need to close.
- if ([window isVisible] && !beingInspected_) {
- [self close];
- }
-}
-
-- (void)close {
- [parentWindow_ removeChildWindow:[self window]];
-
- // No longer have a parent window, so nil out the pointer and deregister for
- // notifications.
- NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
- [center removeObserver:self
- name:NSWindowWillCloseNotification
- object:parentWindow_];
- parentWindow_ = nil;
- [super close];
-}
-
-- (BOOL)isClosing {
- return [static_cast<InfoBubbleWindow*>([self window]) isClosing];
-}
-
-- (ExtensionHost*)extensionHost {
- return host_.get();
-}
-
-+ (ExtensionPopupController*)showURL:(GURL)url
- inBrowser:(Browser*)browser
- anchoredAt:(NSPoint)anchoredAt
- arrowLocation:(info_bubble::BubbleArrowLocation)
- arrowLocation
- devMode:(BOOL)devMode {
- DCHECK([NSThread isMainThread]);
- DCHECK(browser);
- if (!browser)
- return nil;
-
- ExtensionProcessManager* manager =
- browser->profile()->GetExtensionProcessManager();
- DCHECK(manager);
- if (!manager)
- return nil;
-
- ExtensionHost* host = manager->CreatePopup(url, browser);
- DCHECK(host);
- if (!host)
- return nil;
-
- // Make absolutely sure that no popups are leaked.
- if (gPopup) {
- if ([[gPopup window] isVisible])
- [gPopup close];
-
- [gPopup autorelease];
- gPopup = nil;
- }
- DCHECK(!gPopup);
-
- // Takes ownership of |host|. Also will autorelease itself when the popup is
- // closed, so no need to do that here.
- gPopup = [[ExtensionPopupController alloc]
- initWithHost:host
- parentWindow:browser->window()->GetNativeHandle()
- anchoredAt:anchoredAt
- arrowLocation:arrowLocation
- devMode:devMode];
- return gPopup;
-}
-
-+ (ExtensionPopupController*)popup {
- return gPopup;
-}
-
-- (void)extensionViewFrameChanged {
- // If there are no changes in the width or height of the frame, then ignore.
- if (NSEqualSizes([extensionView_ frame].size, extensionFrame_.size))
- return;
-
- extensionFrame_ = [extensionView_ frame];
- // Constrain the size of the view.
- [extensionView_ setFrameSize:NSMakeSize(
- Clamp(NSWidth(extensionFrame_),
- ExtensionViewMac::kMinWidth,
- ExtensionViewMac::kMaxWidth),
- Clamp(NSHeight(extensionFrame_),
- ExtensionViewMac::kMinHeight,
- ExtensionViewMac::kMaxHeight))];
-
- // Pad the window by half of the rounded corner radius to prevent the
- // extension's view from bleeding out over the corners.
- CGFloat inset = info_bubble::kBubbleCornerRadius / 2.0;
- [extensionView_ setFrameOrigin:NSMakePoint(inset, inset)];
-
- NSRect frame = [extensionView_ frame];
- frame.size.height += info_bubble::kBubbleArrowHeight +
- info_bubble::kBubbleCornerRadius;
- frame.size.width += info_bubble::kBubbleCornerRadius;
- frame = [extensionView_ convertRectToBase:frame];
- // Adjust the origin according to the height and width so that the arrow is
- // positioned correctly at the middle and slightly down from the button.
- NSPoint windowOrigin = anchor_;
- NSSize offsets = NSMakeSize(info_bubble::kBubbleArrowXOffset +
- info_bubble::kBubbleArrowWidth / 2.0,
- info_bubble::kBubbleArrowHeight / 2.0);
- offsets = [extensionView_ convertSize:offsets toView:nil];
- windowOrigin.x -= NSWidth(frame) - offsets.width;
- windowOrigin.y -= NSHeight(frame) - offsets.height;
- frame.origin = windowOrigin;
-
- // Is the window still animating in? If so, then cancel that and create a new
- // animation setting the opacity and new frame value. Otherwise the current
- // animation will continue after this frame is set, reverting the frame to
- // what it was when the animation started.
- NSWindow* window = [self window];
- if ([window isVisible] && [[window animator] alphaValue] < 1.0) {
- [NSAnimationContext beginGrouping];
- [[NSAnimationContext currentContext] setDuration:kAnimationDuration];
- [[window animator] setAlphaValue:1.0];
- [[window animator] setFrame:frame display:YES];
- [NSAnimationContext endGrouping];
- } else {
- [window setFrame:frame display:YES];
- }
-
- // A NSViewFrameDidChangeNotification won't be sent until the extension view
- // content is loaded. The window is hidden on init, so show it the first time
- // the notification is fired (and consequently the view contents have loaded).
- if (![window isVisible]) {
- [self showWindow:self];
- }
-}
-
-// We want this to be a child of a browser window. addChildWindow: (called from
-// this function) will bring the window on-screen; unfortunately,
-// [NSWindowController showWindow:] will also bring it on-screen (but will cause
-// unexpected changes to the window's position). We cannot have an
-// addChildWindow: and a subsequent showWindow:. Thus, we have our own version.
-- (void)showWindow:(id)sender {
- [parentWindow_ addChildWindow:[self window] ordered:NSWindowAbove];
- [[self window] makeKeyAndOrderFront:self];
-}
-
-- (void)windowDidResize:(NSNotification*)notification {
- // Let the extension view know, so that it can tell plugins.
- if (host_->view())
- host_->view()->WindowFrameChanged();
-}
-
-- (void)windowDidMove:(NSNotification*)notification {
- // Let the extension view know, so that it can tell plugins.
- if (host_->view())
- host_->view()->WindowFrameChanged();
-}
-
-// Private (TestingAPI)
-- (NSView*)view {
- return extensionView_;
-}
-
-// Private (TestingAPI)
-+ (NSSize)minPopupSize {
- NSSize minSize = {ExtensionViewMac::kMinWidth, ExtensionViewMac::kMinHeight};
- return minSize;
-}
-
-// Private (TestingAPI)
-+ (NSSize)maxPopupSize {
- NSSize maxSize = {ExtensionViewMac::kMaxWidth, ExtensionViewMac::kMaxHeight};
- return maxSize;
-}
-
-@end
diff --git a/chrome/browser/cocoa/extensions/extension_popup_controller_unittest.mm b/chrome/browser/cocoa/extensions/extension_popup_controller_unittest.mm
deleted file mode 100644
index ba7e2b7..0000000
--- a/chrome/browser/cocoa/extensions/extension_popup_controller_unittest.mm
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright (c) 2009 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/scoped_nsobject.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/cocoa/extensions/extension_popup_controller.h"
-#include "chrome/browser/extensions/extension_process_manager.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/test/testing_profile.h"
-
-namespace {
-
-class ExtensionTestingProfile : public TestingProfile {
- public:
- ExtensionTestingProfile() {}
-
- FilePath GetExtensionsInstallDir() {
- return GetPath().AppendASCII(ExtensionsService::kInstallDirectoryName);
- }
-
- void InitExtensionProfile() {
- DCHECK(!GetExtensionProcessManager());
- DCHECK(!GetExtensionsService());
-
- manager_.reset(ExtensionProcessManager::Create(this));
- service_ = new ExtensionsService(this,
- CommandLine::ForCurrentProcess(),
- GetExtensionsInstallDir(),
- false);
- service_->set_extensions_enabled(true);
- service_->set_show_extensions_prompts(false);
- service_->ClearProvidersForTesting();
- service_->Init();
- }
-
- void ShutdownExtensionProfile() {
- manager_.reset();
- service_ = NULL;
- }
-
- virtual ExtensionProcessManager* GetExtensionProcessManager() {
- return manager_.get();
- }
-
- virtual ExtensionsService* GetExtensionsService() {
- return service_.get();
- }
-
- private:
- scoped_ptr<ExtensionProcessManager> manager_;
- scoped_refptr<ExtensionsService> service_;
-
- DISALLOW_COPY_AND_ASSIGN(ExtensionTestingProfile);
-};
-
-class ExtensionPopupControllerTest : public CocoaTest {
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
- profile_.reset(new ExtensionTestingProfile());
- profile_->InitExtensionProfile();
- browser_.reset(new Browser(Browser::TYPE_NORMAL, profile_.get()));
- [ExtensionPopupController showURL:GURL("http://google.com")
- inBrowser:browser_.get()
- anchoredAt:NSZeroPoint
- arrowLocation:info_bubble::kTopRight
- devMode:NO];
- }
- virtual void TearDown() {
- profile_->ShutdownExtensionProfile();
- [[ExtensionPopupController popup] close];
- CocoaTest::TearDown();
- }
-
- protected:
- scoped_ptr<Browser> browser_;
- scoped_ptr<ExtensionTestingProfile> profile_;
-};
-
-TEST_F(ExtensionPopupControllerTest, DISABLED_Basics) {
- // TODO(andybons): Better mechanisms for mocking out the extensions service
- // and extensions for easy testing need to be implemented.
- // http://crbug.com/28316
- EXPECT_TRUE([ExtensionPopupController popup]);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/external_protocol_dialog.mm b/chrome/browser/cocoa/external_protocol_dialog.mm
deleted file mode 100644
index 0513ae0..0000000
--- a/chrome/browser/cocoa/external_protocol_dialog.mm
+++ /dev/null
@@ -1,152 +0,0 @@
-// 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 "chrome/browser/cocoa/external_protocol_dialog.h"
-
-#include "app/l10n_util_mac.h"
-#include "base/message_loop.h"
-#include "base/metrics/histogram.h"
-#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/external_protocol_handler.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-
-///////////////////////////////////////////////////////////////////////////////
-// ExternalProtocolHandler
-
-// static
-void ExternalProtocolHandler::RunExternalProtocolDialog(
- const GURL& url, int render_process_host_id, int routing_id) {
- [[ExternalProtocolDialogController alloc] initWithGURL:&url];
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// ExternalProtocolDialogController
-
-@interface ExternalProtocolDialogController(Private)
-- (void)alertEnded:(NSAlert *)alert
- returnCode:(int)returnCode
- contextInfo:(void*)contextInfo;
-- (string16)appNameForProtocol;
-@end
-
-@implementation ExternalProtocolDialogController
-- (id)initWithGURL:(const GURL*)url {
- DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type());
-
- url_ = *url;
- creation_time_ = base::Time::Now();
-
- string16 appName = [self appNameForProtocol];
- if (appName.length() == 0) {
- // No registered apps for this protocol; give up and go home.
- [self autorelease];
- return nil;
- }
-
- alert_ = [[NSAlert alloc] init];
-
- [alert_ setMessageText:
- l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_TITLE)];
-
- NSButton* allowButton = [alert_ addButtonWithTitle:
- l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_OK_BUTTON_TEXT)];
- [allowButton setKeyEquivalent:@""]; // disallow as default
- [alert_ addButtonWithTitle:
- l10n_util::GetNSStringWithFixup(
- IDS_EXTERNAL_PROTOCOL_CANCEL_BUTTON_TEXT)];
-
- const int kMaxUrlWithoutSchemeSize = 256;
- std::wstring elided_url_without_scheme;
- ElideString(ASCIIToWide(url_.possibly_invalid_spec()),
- kMaxUrlWithoutSchemeSize, &elided_url_without_scheme);
-
- NSString* urlString = l10n_util::GetNSStringFWithFixup(
- IDS_EXTERNAL_PROTOCOL_INFORMATION,
- ASCIIToUTF16(url_.scheme() + ":"),
- WideToUTF16(elided_url_without_scheme));
- NSString* appString = l10n_util::GetNSStringFWithFixup(
- IDS_EXTERNAL_PROTOCOL_APPLICATION_TO_LAUNCH,
- appName);
- NSString* warningString =
- l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_WARNING);
- NSString* informativeText =
- [NSString stringWithFormat:@"%@\n\n%@\n\n%@",
- urlString,
- appString,
- warningString];
-
- [alert_ setInformativeText:informativeText];
-
- [alert_ setShowsSuppressionButton:YES];
- [[alert_ suppressionButton] setTitle:
- l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_CHECKBOX_TEXT)];
-
- [alert_ beginSheetModalForWindow:nil // nil here makes it app-modal
- modalDelegate:self
- didEndSelector:@selector(alertEnded:returnCode:contextInfo:)
- contextInfo:nil];
-
- return self;
-}
-
-- (void)dealloc {
- [alert_ release];
-
- [super dealloc];
-}
-
-- (void)alertEnded:(NSAlert *)alert
- returnCode:(int)returnCode
- contextInfo:(void*)contextInfo {
- ExternalProtocolHandler::BlockState blockState =
- ExternalProtocolHandler::UNKNOWN;
- switch (returnCode) {
- case NSAlertFirstButtonReturn:
- blockState = ExternalProtocolHandler::DONT_BLOCK;
- break;
- case NSAlertSecondButtonReturn:
- blockState = ExternalProtocolHandler::BLOCK;
- break;
- default:
- NOTREACHED();
- }
-
- // Set the "don't warn me again" info.
- if ([[alert_ suppressionButton] state] == NSOnState)
- ExternalProtocolHandler::SetBlockState(url_.scheme(), blockState);
-
- if (blockState == ExternalProtocolHandler::DONT_BLOCK) {
- UMA_HISTOGRAM_LONG_TIMES("clickjacking.launch_url",
- base::Time::Now() - creation_time_);
-
- ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(url_);
- }
-
- [self autorelease];
-}
-
-- (string16)appNameForProtocol {
- NSURL* url = [NSURL URLWithString:
- base::SysUTF8ToNSString(url_.possibly_invalid_spec())];
- CFURLRef openingApp = NULL;
- OSStatus status = LSGetApplicationForURL((CFURLRef)url,
- kLSRolesAll,
- NULL,
- &openingApp);
- if (status != noErr) {
- // likely kLSApplicationNotFoundErr
- return string16();
- }
- NSString* appPath = [(NSURL*)openingApp path];
- CFRelease(openingApp); // NOT A BUG; LSGetApplicationForURL retains for us
- NSString* appDisplayName =
- [[NSFileManager defaultManager] displayNameAtPath:appPath];
-
- return base::SysNSStringToUTF16(appDisplayName);
-}
-
-@end
diff --git a/chrome/browser/cocoa/fast_resize_view.h b/chrome/browser/cocoa/fast_resize_view.h
deleted file mode 100644
index d6e8bed..0000000
--- a/chrome/browser/cocoa/fast_resize_view.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_FAST_RESIZE_VIEW_H_
-#define CHROME_BROWSER_COCOA_FAST_RESIZE_VIEW_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-// A Cocoa view that supports an alternate resizing mode, normally used when
-// animations are in progress. In normal resizing mode, subviews are sized to
-// completely fill this view's bounds. In fast resizing mode, the subviews'
-// size is not changed and the subview is clipped to fit, if necessary. Fast
-// resize mode is useful when animating a view that normally takes a significant
-// amount of time to relayout and redraw when its size is changed.
-@interface FastResizeView : NSView {
- @private
- BOOL fastResizeMode_;
-}
-
-// Turns fast resizing mode on or off, which determines how this view resizes
-// its subviews. Turning fast resizing mode off has the effect of immediately
-// resizing subviews to fit; callers do not need to explictly call |setFrame:|
-// to trigger a resize.
-- (void)setFastResizeMode:(BOOL)fastResizeMode;
-@end
-
-#endif // CHROME_BROWSER_COCOA_FAST_RESIZE_VIEW_H_
diff --git a/chrome/browser/cocoa/fast_resize_view.mm b/chrome/browser/cocoa/fast_resize_view.mm
deleted file mode 100644
index 97c1d82..0000000
--- a/chrome/browser/cocoa/fast_resize_view.mm
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright (c) 2009 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>
-#import "chrome/browser/cocoa/fast_resize_view.h"
-
-#include "base/logging.h"
-
-@interface FastResizeView (PrivateMethods)
-// Lays out this views subviews. If fast resize mode is on, does not resize any
-// subviews and instead pegs them to the top left. If fast resize mode is off,
-// sets the subviews' frame to be equal to this view's bounds.
-- (void)layoutSubviews;
-@end
-
-@implementation FastResizeView
-- (void)setFastResizeMode:(BOOL)fastResizeMode {
- fastResizeMode_ = fastResizeMode;
-
- // Force a relayout when coming out of fast resize mode.
- if (!fastResizeMode_)
- [self layoutSubviews];
-}
-
-- (void)resizeSubviewsWithOldSize:(NSSize)oldSize {
- [self layoutSubviews];
-}
-
-- (void)drawRect:(NSRect)dirtyRect {
- // If we are in fast resize mode, our subviews may not completely cover our
- // bounds, so we fill with white. If we are not in fast resize mode, we do
- // not need to draw anything.
- if (fastResizeMode_) {
- [[NSColor whiteColor] set];
- NSRectFill(dirtyRect);
- }
-}
-
-
-@end
-
-@implementation FastResizeView (PrivateMethods)
-- (void)layoutSubviews {
- // There should never be more than one subview. There can be zero, if we are
- // in the process of switching tabs or closing the window. In those cases, no
- // layout is needed.
- NSArray* subviews = [self subviews];
- DCHECK([subviews count] <= 1);
- if ([subviews count] < 1)
- return;
-
- NSView* subview = [subviews objectAtIndex:0];
- NSRect bounds = [self bounds];
-
- if (fastResizeMode_) {
- NSRect frame = [subview frame];
- frame.origin.x = 0;
- frame.origin.y = NSHeight(bounds) - NSHeight(frame);
- [subview setFrame:frame];
- } else {
- [subview setFrame:bounds];
- }
-}
-@end
diff --git a/chrome/browser/cocoa/fast_resize_view_unittest.mm b/chrome/browser/cocoa/fast_resize_view_unittest.mm
deleted file mode 100644
index ee6f34d..0000000
--- a/chrome/browser/cocoa/fast_resize_view_unittest.mm
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright (c) 2009 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/scoped_nsobject.h"
-#import "chrome/browser/cocoa/fast_resize_view.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-
-namespace {
-
-class FastResizeViewTest : public CocoaTest {
- public:
- FastResizeViewTest() {
- NSRect frame = NSMakeRect(0, 0, 100, 30);
- scoped_nsobject<FastResizeView> view(
- [[FastResizeView alloc] initWithFrame:frame]);
- view_ = view.get();
- [[test_window() contentView] addSubview:view_];
-
- scoped_nsobject<NSView> childView([[NSView alloc] initWithFrame:frame]);
- childView_ = childView.get();
- [view_ addSubview:childView_];
- }
-
- FastResizeView* view_;
- NSView* childView_;
-};
-
-TEST_VIEW(FastResizeViewTest, view_);
-
-TEST_F(FastResizeViewTest, TestResizingOfChildren) {
- NSRect squareFrame = NSMakeRect(0, 0, 200, 200);
- NSRect rectFrame = NSMakeRect(1, 1, 150, 300);
-
- // Test that changing the view's frame also changes the child's frame.
- [view_ setFrame:squareFrame];
- EXPECT_TRUE(NSEqualRects([view_ bounds], [childView_ frame]));
-
- // Turn fast resize mode on and change the view's frame. This time, the child
- // should not resize, but it should be anchored to the top left.
- [view_ setFastResizeMode:YES];
- [view_ setFrame:NSMakeRect(15, 30, 250, 250)];
- EXPECT_TRUE(NSEqualSizes([childView_ frame].size, squareFrame.size));
- EXPECT_EQ(NSMinX([view_ bounds]), NSMinX([childView_ frame]));
- EXPECT_EQ(NSMaxY([view_ bounds]), NSMaxY([childView_ frame]));
-
- // Another resize with fast resize mode on.
- [view_ setFrame:rectFrame];
- EXPECT_TRUE(NSEqualSizes([childView_ frame].size, squareFrame.size));
- EXPECT_EQ(NSMinX([view_ bounds]), NSMinX([childView_ frame]));
- EXPECT_EQ(NSMaxY([view_ bounds]), NSMaxY([childView_ frame]));
-
- // Turn fast resize mode off. This should initiate an immediate resize, even
- // though we haven't called setFrame directly.
- [view_ setFastResizeMode:NO];
- EXPECT_TRUE(NSEqualRects([view_ frame], rectFrame));
- EXPECT_TRUE(NSEqualRects([view_ bounds], [childView_ frame]));
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/file_metadata.h b/chrome/browser/cocoa/file_metadata.h
deleted file mode 100644
index e7448d7..0000000
--- a/chrome/browser/cocoa/file_metadata.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_FILE_METADATA_H_
-#define CHROME_BROWSER_COCOA_FILE_METADATA_H_
-#pragma once
-
-class FilePath;
-class GURL;
-
-namespace file_metadata {
-
-// Adds origin metadata to the file.
-// |source| should be the source URL for the download, and |referrer| should be
-// the URL the user initiated the download from.
-void AddOriginMetadataToFile(const FilePath& file, const GURL& source,
- const GURL& referrer);
-
-// Adds quarantine metadata to the file, assuming it has already been
-// quarantined by the OS.
-// |source| should be the source URL for the download, and |referrer| should be
-// the URL the user initiated the download from.
-void AddQuarantineMetadataToFile(const FilePath& file, const GURL& source,
- const GURL& referrer);
-
-} // namespace file_metadata
-
-#endif // CHROME_BROWSER_COCOA_FILE_METADATA_H_
diff --git a/chrome/browser/cocoa/file_metadata.mm b/chrome/browser/cocoa/file_metadata.mm
deleted file mode 100644
index ad3a92f..0000000
--- a/chrome/browser/cocoa/file_metadata.mm
+++ /dev/null
@@ -1,167 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/file_metadata.h"
-
-#include <ApplicationServices/ApplicationServices.h>
-#include <Foundation/Foundation.h>
-
-#include "base/file_path.h"
-#include "base/logging.h"
-#include "base/mac_util.h"
-#include "base/mac/scoped_cftyperef.h"
-#include "googleurl/src/gurl.h"
-
-namespace file_metadata {
-
-// As of Mac OS X 10.4 ("Tiger"), files can be tagged with metadata describing
-// various attributes. Metadata is integrated with the system's Spotlight
-// feature and is searchable. Ordinarily, metadata can only be set by
-// Spotlight importers, which requires that the importer own the target file.
-// However, there's an attribute intended to describe the origin of a
-// file, that can store the source URL and referrer of a downloaded file.
-// It's stored as a "com.apple.metadata:kMDItemWhereFroms" extended attribute,
-// structured as a binary1-format plist containing a list of sources. This
-// attribute can only be populated by the downloader, not a Spotlight importer.
-// Safari on 10.4 and later populates this attribute.
-//
-// With this metadata set, you can locate downloads by performing a Spotlight
-// search for their source or referrer URLs, either from within the Spotlight
-// UI or from the command line:
-// mdfind 'kMDItemWhereFroms == "http://releases.mozilla.org/*"'
-//
-// There is no documented API to set metadata on a file directly as of the
-// 10.5 SDK. The MDSetItemAttribute function does exist to perform this task,
-// but it's undocumented.
-void AddOriginMetadataToFile(const FilePath& file, const GURL& source,
- const GURL& referrer) {
- // There's no declaration for MDItemSetAttribute in any known public SDK.
- // It exists in the 10.4 and 10.5 runtimes. To play it safe, do the lookup
- // at runtime instead of declaring it ourselves and linking against what's
- // provided. This has two benefits:
- // - If Apple relents and declares the function in a future SDK (it's
- // happened before), our build won't break.
- // - If Apple removes or renames the function in a future runtime, the
- // loader won't refuse to let the application launch. Instead, we'll
- // silently fail to set any metadata.
- typedef OSStatus (*MDItemSetAttribute_type)(MDItemRef, CFStringRef,
- CFTypeRef);
- static MDItemSetAttribute_type md_item_set_attribute_func = NULL;
-
- static bool did_symbol_lookup = false;
- if (!did_symbol_lookup) {
- did_symbol_lookup = true;
- CFBundleRef metadata_bundle =
- CFBundleGetBundleWithIdentifier(CFSTR("com.apple.Metadata"));
- if (!metadata_bundle)
- return;
-
- md_item_set_attribute_func = (MDItemSetAttribute_type)
- CFBundleGetFunctionPointerForName(metadata_bundle,
- CFSTR("MDItemSetAttribute"));
- }
- if (!md_item_set_attribute_func)
- return;
-
- NSString* file_path =
- [NSString stringWithUTF8String:file.value().c_str()];
- if (!file_path)
- return;
-
- base::mac::ScopedCFTypeRef<MDItemRef> md_item(
- MDItemCreate(NULL, reinterpret_cast<CFStringRef>(file_path)));
- if (!md_item)
- return;
-
- // We won't put any more than 2 items into the attribute.
- NSMutableArray* list = [NSMutableArray arrayWithCapacity:2];
-
- // Follow Safari's lead: the first item in the list is the source URL of
- // the downloaded file. If the referrer is known, store that, too.
- NSString* origin_url = [NSString stringWithUTF8String:source.spec().c_str()];
- if (origin_url)
- [list addObject:origin_url];
- NSString* referrer_url =
- [NSString stringWithUTF8String:referrer.spec().c_str()];
- if (referrer_url)
- [list addObject:referrer_url];
-
- md_item_set_attribute_func(md_item, kMDItemWhereFroms,
- reinterpret_cast<CFArrayRef>(list));
-}
-
-// The OS will automatically quarantine files due to the
-// LSFileQuarantineEnabled entry in our Info.plist, but it knows relatively
-// little about the files. We add more information about the download to
-// improve the UI shown by the OS when the users tries to open the file.
-void AddQuarantineMetadataToFile(const FilePath& file, const GURL& source,
- const GURL& referrer) {
- FSRef file_ref;
- if (!mac_util::FSRefFromPath(file.value(), &file_ref))
- return;
-
- NSMutableDictionary* quarantine_properties = nil;
- CFTypeRef quarantine_properties_base = NULL;
- if (LSCopyItemAttribute(&file_ref, kLSRolesAll, kLSItemQuarantineProperties,
- &quarantine_properties_base) == noErr) {
- if (CFGetTypeID(quarantine_properties_base) ==
- CFDictionaryGetTypeID()) {
- // Quarantine properties will already exist if LSFileQuarantineEnabled
- // is on and the file doesn't match an exclusion.
- quarantine_properties =
- [[(NSDictionary*)quarantine_properties_base mutableCopy] autorelease];
- } else {
- LOG(WARNING) << "kLSItemQuarantineProperties is not a dictionary on file "
- << file.value();
- }
- CFRelease(quarantine_properties_base);
- }
-
- if (!quarantine_properties) {
- // If there are no quarantine properties, then the file isn't quarantined
- // (e.g., because the user has set up exclusions for certain file types).
- // We don't want to add any metadata, because that will cause the file to
- // be quarantined against the user's wishes.
- return;
- }
-
- // kLSQuarantineAgentNameKey, kLSQuarantineAgentBundleIdentifierKey, and
- // kLSQuarantineTimeStampKey are set for us (see LSQuarantine.h), so we only
- // need to set the values that the OS can't infer.
-
- if (![quarantine_properties valueForKey:(NSString*)kLSQuarantineTypeKey]) {
- CFStringRef type = (source.SchemeIs("http") || source.SchemeIs("https"))
- ? kLSQuarantineTypeWebDownload
- : kLSQuarantineTypeOtherDownload;
- [quarantine_properties setValue:(NSString*)type
- forKey:(NSString*)kLSQuarantineTypeKey];
- }
-
- if (![quarantine_properties
- valueForKey:(NSString*)kLSQuarantineOriginURLKey] &&
- referrer.is_valid()) {
- NSString* referrer_url =
- [NSString stringWithUTF8String:referrer.spec().c_str()];
- [quarantine_properties setValue:referrer_url
- forKey:(NSString*)kLSQuarantineOriginURLKey];
- }
-
- if (![quarantine_properties valueForKey:(NSString*)kLSQuarantineDataURLKey] &&
- source.is_valid()) {
- NSString* origin_url =
- [NSString stringWithUTF8String:source.spec().c_str()];
- [quarantine_properties setValue:origin_url
- forKey:(NSString*)kLSQuarantineDataURLKey];
- }
-
- OSStatus os_error = LSSetItemAttribute(&file_ref, kLSRolesAll,
- kLSItemQuarantineProperties,
- quarantine_properties);
- if (os_error != noErr) {
- LOG(WARNING) << "Unable to set quarantine attributes on file "
- << file.value();
- }
-}
-
-} // namespace file_metadata
diff --git a/chrome/browser/cocoa/find_bar_bridge.h b/chrome/browser/cocoa/find_bar_bridge.h
deleted file mode 100644
index 5623ca4..0000000
--- a/chrome/browser/cocoa/find_bar_bridge.h
+++ /dev/null
@@ -1,95 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_FIND_BAR_BRIDGE_H_
-#define CHROME_BROWSER_COCOA_FIND_BAR_BRIDGE_H_
-#pragma once
-
-#include "base/logging.h"
-#include "chrome/browser/find_bar.h"
-
-class BrowserWindowCocoa;
-class FindBarController;
-
-// This class is included by find_bar_host_browsertest.cc, so it has to be
-// objc-free.
-#ifdef __OBJC__
-@class FindBarCocoaController;
-#else
-class FindBarCocoaController;
-#endif
-
-// Implementation of FindBar for the Mac. This class simply passes
-// each message along to |cocoa_controller_|.
-//
-// The initialization here is a bit complicated. FindBarBridge is
-// created by a static method in BrowserWindow. The FindBarBridge
-// constructor creates a FindBarCocoaController, which in turn loads a
-// FindBarView from a nib file. All of this is happening outside of
-// the main view hierarchy, so the static method also calls
-// BrowserWindowCocoa::AddFindBar() in order to add its FindBarView to
-// the cocoa views hierarchy.
-//
-// Memory ownership is relatively straightforward. The FindBarBridge
-// object is owned by the Browser. FindBarCocoaController is retained
-// by bother FindBarBridge and BrowserWindowController, since both use it.
-
-class FindBarBridge : public FindBar,
- public FindBarTesting {
- public:
- FindBarBridge();
- virtual ~FindBarBridge();
-
- FindBarCocoaController* find_bar_cocoa_controller() {
- return cocoa_controller_;
- }
-
- virtual void SetFindBarController(FindBarController* find_bar_controller) {
- find_bar_controller_ = find_bar_controller;
- }
-
- virtual FindBarController* GetFindBarController() const {
- DCHECK(find_bar_controller_);
- return find_bar_controller_;
- }
-
- virtual FindBarTesting* GetFindBarTesting() {
- return this;
- }
-
- // Methods from FindBar.
- virtual void Show(bool animate);
- virtual void Hide(bool animate);
- virtual void SetFocusAndSelection();
- virtual void ClearResults(const FindNotificationDetails& results);
- virtual void StopAnimation();
- virtual void SetFindText(const string16& find_text);
- virtual void UpdateUIForFindResult(const FindNotificationDetails& result,
- const string16& find_text);
- virtual void AudibleAlert();
- virtual bool IsFindBarVisible();
- virtual void RestoreSavedFocus();
- virtual void MoveWindowIfNecessary(const gfx::Rect& selection_rect,
- bool no_redraw);
-
- // Methods from FindBarTesting.
- virtual bool GetFindBarWindowInfo(gfx::Point* position,
- bool* fully_visible);
- virtual string16 GetFindText();
-
- // Used to disable find bar animations when testing.
- static bool disable_animations_during_testing_;
-
- private:
- // Pointer to the cocoa controller which manages the cocoa view. Is
- // never nil.
- FindBarCocoaController* cocoa_controller_;
-
- // Pointer back to the owning controller.
- FindBarController* find_bar_controller_; // weak, owns us
-
- DISALLOW_COPY_AND_ASSIGN(FindBarBridge);
-};
-
-#endif // CHROME_BROWSER_COCOA_FIND_BAR_BRIDGE_H_
diff --git a/chrome/browser/cocoa/find_bar_bridge.mm b/chrome/browser/cocoa/find_bar_bridge.mm
deleted file mode 100644
index 3c97412..0000000
--- a/chrome/browser/cocoa/find_bar_bridge.mm
+++ /dev/null
@@ -1,96 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/find_bar_bridge.h"
-
-#include "base/sys_string_conversions.h"
-#import "chrome/browser/cocoa/find_bar_cocoa_controller.h"
-
-// static
-bool FindBarBridge::disable_animations_during_testing_ = false;
-
-FindBarBridge::FindBarBridge()
- : find_bar_controller_(NULL) {
- cocoa_controller_ = [[FindBarCocoaController alloc] init];
- [cocoa_controller_ setFindBarBridge:this];
-}
-
-FindBarBridge::~FindBarBridge() {
- [cocoa_controller_ release];
-}
-
-void FindBarBridge::Show(bool animate) {
- bool really_animate = animate && !disable_animations_during_testing_;
- [cocoa_controller_ showFindBar:(really_animate ? YES : NO)];
-}
-
-void FindBarBridge::Hide(bool animate) {
- bool really_animate = animate && !disable_animations_during_testing_;
- [cocoa_controller_ hideFindBar:(really_animate ? YES : NO)];
-}
-
-void FindBarBridge::SetFocusAndSelection() {
- [cocoa_controller_ setFocusAndSelection];
-}
-
-void FindBarBridge::ClearResults(const FindNotificationDetails& results) {
- [cocoa_controller_ clearResults:results];
-}
-
-void FindBarBridge::SetFindText(const string16& find_text) {
- [cocoa_controller_ setFindText:base::SysUTF16ToNSString(find_text)];
-}
-
-void FindBarBridge::UpdateUIForFindResult(const FindNotificationDetails& result,
- const string16& find_text) {
- [cocoa_controller_ updateUIForFindResult:result withText:find_text];
-}
-
-void FindBarBridge::AudibleAlert() {
- // Beep beep, beep beep, Yeah!
- NSBeep();
-}
-
-bool FindBarBridge::IsFindBarVisible() {
- return [cocoa_controller_ isFindBarVisible] ? true : false;
-}
-
-void FindBarBridge::MoveWindowIfNecessary(const gfx::Rect& selection_rect,
- bool no_redraw) {
- // http://crbug.com/11084
- // http://crbug.com/22036
-}
-
-void FindBarBridge::StopAnimation() {
- [cocoa_controller_ stopAnimation];
-}
-
-void FindBarBridge::RestoreSavedFocus() {
- [cocoa_controller_ restoreSavedFocus];
-}
-
-bool FindBarBridge::GetFindBarWindowInfo(gfx::Point* position,
- bool* fully_visible) {
- // TODO(rohitrao): Return the proper position. http://crbug.com/22036
- if (position)
- *position = gfx::Point(0, 0);
-
- NSWindow* window = [[cocoa_controller_ view] window];
- bool window_visible = [window isVisible] ? true : false;
- if (fully_visible) {
- *fully_visible = window_visible &&
- [cocoa_controller_ isFindBarVisible] &&
- ![cocoa_controller_ isFindBarAnimating];
- }
- return window_visible;
-}
-
-string16 FindBarBridge::GetFindText() {
- // This function is currently only used in Windows and Linux specific browser
- // tests (testing prepopulate values that Mac's don't rely on), but if we add
- // more tests that are non-platform specific, we need to flesh out this
- // function.
- NOTIMPLEMENTED();
- return string16();
-}
diff --git a/chrome/browser/cocoa/find_bar_bridge_unittest.mm b/chrome/browser/cocoa/find_bar_bridge_unittest.mm
deleted file mode 100644
index c0cf6b4..0000000
--- a/chrome/browser/cocoa/find_bar_bridge_unittest.mm
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/find_bar_controller.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/cocoa/find_bar_bridge.h"
-
-namespace {
-
-class FindBarBridgeTest : public CocoaTest {
-};
-
-TEST_F(FindBarBridgeTest, Creation) {
- // Make sure the FindBarBridge constructor doesn't crash and
- // properly initializes its FindBarCocoaController.
- FindBarBridge bridge;
- EXPECT_TRUE(bridge.find_bar_cocoa_controller() != NULL);
-}
-
-TEST_F(FindBarBridgeTest, Accessors) {
- // Get/SetFindBarController are virtual methods implemented in
- // FindBarBridge, so we test them here.
- FindBarBridge* bridge = new FindBarBridge();
- FindBarController controller(bridge); // takes ownership of |bridge|.
- bridge->SetFindBarController(&controller);
-
- EXPECT_EQ(&controller, bridge->GetFindBarController());
-}
-} // namespace
diff --git a/chrome/browser/cocoa/find_bar_cocoa_controller.h b/chrome/browser/cocoa/find_bar_cocoa_controller.h
deleted file mode 100644
index b6e66db..0000000
--- a/chrome/browser/cocoa/find_bar_cocoa_controller.h
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright (c) 2009 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>
-
-#import "chrome/browser/cocoa/find_bar_cocoa_controller.h"
-
-#include "base/scoped_nsobject.h"
-#include "base/string16.h"
-
-class BrowserWindowCocoa;
-class FindBarBridge;
-@class FindBarTextField;
-class FindNotificationDetails;
-@class FocusTracker;
-
-// A controller for the find bar in the browser window. Manages
-// updating the state of the find bar and provides a target for the
-// next/previous/close buttons. Certain operations require a pointer
-// to the cross-platform FindBarController, so be sure to call
-// setFindBarBridge: after creating this controller.
-
-@interface FindBarCocoaController : NSViewController {
- @private
- IBOutlet NSView* findBarView_;
- IBOutlet FindBarTextField* findText_;
- IBOutlet NSButton* nextButton_;
- IBOutlet NSButton* previousButton_;
-
- // Needed to call methods on FindBarController.
- FindBarBridge* findBarBridge_; // weak
-
- scoped_nsobject<FocusTracker> focusTracker_;
-
- // The currently-running animation. This is defined to be non-nil if an
- // animation is running, and is always nil otherwise. The
- // FindBarCocoaController should not be deallocated while an animation is
- // running (stopAnimation is currently called before the last tab in a
- // window is removed).
- scoped_nsobject<NSViewAnimation> currentAnimation_;
-
- // If YES, do nothing as a result of find pasteboard update notifications.
- BOOL suppressPboardUpdateActions_;
-};
-
-// Initializes a new FindBarCocoaController.
-- (id)init;
-
-- (void)setFindBarBridge:(FindBarBridge*)findBar;
-
-- (IBAction)close:(id)sender;
-
-- (IBAction)nextResult:(id)sender;
-
-- (IBAction)previousResult:(id)sender;
-
-// Position the find bar at the given maximum y-coordinate (the min-y of the
-// bar -- toolbar + possibly bookmark bar, but not including the infobars) with
-// the given maximum width (i.e., the find bar should fit between 0 and
-// |maxWidth|).
-- (void)positionFindBarViewAtMaxY:(CGFloat)maxY maxWidth:(CGFloat)maxWidth;
-
-// Methods called from FindBarBridge.
-- (void)showFindBar:(BOOL)animate;
-- (void)hideFindBar:(BOOL)animate;
-- (void)stopAnimation;
-- (void)setFocusAndSelection;
-- (void)restoreSavedFocus;
-- (void)setFindText:(NSString*)findText;
-
-- (void)clearResults:(const FindNotificationDetails&)results;
-- (void)updateUIForFindResult:(const FindNotificationDetails&)results
- withText:(const string16&)findText;
-- (BOOL)isFindBarVisible;
-- (BOOL)isFindBarAnimating;
-
-@end
diff --git a/chrome/browser/cocoa/find_bar_cocoa_controller.mm b/chrome/browser/cocoa/find_bar_cocoa_controller.mm
deleted file mode 100644
index 2845e3e..0000000
--- a/chrome/browser/cocoa/find_bar_cocoa_controller.mm
+++ /dev/null
@@ -1,384 +0,0 @@
-// Copyright (c) 2009 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 "base/mac_util.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/find_bar_controller.h"
-#include "chrome/browser/cocoa/browser_window_cocoa.h"
-#import "chrome/browser/cocoa/find_bar_cocoa_controller.h"
-#import "chrome/browser/cocoa/find_bar_bridge.h"
-#import "chrome/browser/cocoa/find_bar_text_field.h"
-#import "chrome/browser/cocoa/find_bar_text_field_cell.h"
-#import "chrome/browser/cocoa/find_pasteboard.h"
-#import "chrome/browser/cocoa/focus_tracker.h"
-#import "chrome/browser/cocoa/tab_strip_controller.h"
-#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
-
-namespace {
-const float kFindBarOpenDuration = 0.2;
-const float kFindBarCloseDuration = 0.15;
-}
-
-@interface FindBarCocoaController (PrivateMethods)
-// Returns the appropriate frame for a hidden find bar.
-- (NSRect)hiddenFindBarFrame;
-
-// Sets the frame of |findBarView_|. |duration| is ignored if |animate| is NO.
-- (void)setFindBarFrame:(NSRect)endFrame
- animate:(BOOL)animate
- duration:(float)duration;
-
-// Optionally stops the current search, puts |text| into the find bar, and
-// enables the buttons, but doesn't start a new search for |text|.
-- (void)prepopulateText:(NSString*)text stopSearch:(BOOL)stopSearch;
-@end
-
-@implementation FindBarCocoaController
-
-- (id)init {
- if ((self = [super initWithNibName:@"FindBar"
- bundle:mac_util::MainAppBundle()])) {
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(findPboardUpdated:)
- name:kFindPasteboardChangedNotification
- object:[FindPasteboard sharedInstance]];
- }
- return self;
-}
-
-- (void)dealloc {
- // All animations should be explicitly stopped by the TabContents before a tab
- // is closed.
- DCHECK(!currentAnimation_.get());
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [super dealloc];
-}
-
-- (void)setFindBarBridge:(FindBarBridge*)findBarBridge {
- DCHECK(!findBarBridge_); // should only be called once.
- findBarBridge_ = findBarBridge;
-}
-
-- (void)awakeFromNib {
- [findBarView_ setFrame:[self hiddenFindBarFrame]];
-
- // Stopping the search requires a findbar controller, which isn't valid yet
- // during setup. Furthermore, there is no active search yet anyway.
- [self prepopulateText:[[FindPasteboard sharedInstance] findText]
- stopSearch:NO];
-}
-
-- (IBAction)close:(id)sender {
- if (findBarBridge_)
- findBarBridge_->GetFindBarController()->EndFindSession(
- FindBarController::kKeepSelection);
-}
-
-- (IBAction)previousResult:(id)sender {
- if (findBarBridge_)
- findBarBridge_->GetFindBarController()->tab_contents()->StartFinding(
- base::SysNSStringToUTF16([findText_ stringValue]),
- false, false);
-}
-
-- (IBAction)nextResult:(id)sender {
- if (findBarBridge_)
- findBarBridge_->GetFindBarController()->tab_contents()->StartFinding(
- base::SysNSStringToUTF16([findText_ stringValue]),
- true, false);
-}
-
-- (void)findPboardUpdated:(NSNotification*)notification {
- if (suppressPboardUpdateActions_)
- return;
- [self prepopulateText:[[FindPasteboard sharedInstance] findText]
- stopSearch:YES];
-}
-
-- (void)positionFindBarViewAtMaxY:(CGFloat)maxY maxWidth:(CGFloat)maxWidth {
- static const CGFloat kRightEdgeOffset = 25;
- NSView* containerView = [self view];
- CGFloat containerHeight = NSHeight([containerView frame]);
- CGFloat containerWidth = NSWidth([containerView frame]);
-
- // Adjust where we'll actually place the find bar.
- CGFloat maxX = maxWidth - kRightEdgeOffset;
- DLOG_IF(WARNING, maxX < 0) << "Window too narrow for find bar";
- maxY += 1;
-
- NSRect newFrame = NSMakeRect(maxX - containerWidth, maxY - containerHeight,
- containerWidth, containerHeight);
- [containerView setFrame:newFrame];
-}
-
-// NSControl delegate method.
-- (void)controlTextDidChange:(NSNotification *)aNotification {
- if (!findBarBridge_)
- return;
-
- TabContents* tab_contents =
- findBarBridge_->GetFindBarController()->tab_contents();
- if (!tab_contents)
- return;
-
- NSString* findText = [findText_ stringValue];
- suppressPboardUpdateActions_ = YES;
- [[FindPasteboard sharedInstance] setFindText:findText];
- suppressPboardUpdateActions_ = NO;
-
- if ([findText length] > 0) {
- tab_contents->StartFinding(base::SysNSStringToUTF16(findText), true, false);
- } else {
- // The textbox is empty so we reset.
- tab_contents->StopFinding(FindBarController::kClearSelection);
- [self updateUIForFindResult:tab_contents->find_result()
- withText:string16()];
- }
-}
-
-// NSControl delegate method
-- (BOOL)control:(NSControl*)control
- textView:(NSTextView*)textView
- doCommandBySelector:(SEL)command {
- if (command == @selector(insertNewline:)) {
- // Pressing Return
- NSEvent* event = [NSApp currentEvent];
-
- if ([event modifierFlags] & NSShiftKeyMask)
- [previousButton_ performClick:nil];
- else
- [nextButton_ performClick:nil];
-
- return YES;
- } else if (command == @selector(insertLineBreak:)) {
- // Pressing Ctrl-Return
- if (findBarBridge_) {
- findBarBridge_->GetFindBarController()->EndFindSession(
- FindBarController::kActivateSelection);
- }
- return YES;
- } else if (command == @selector(pageUp:) ||
- command == @selector(pageUpAndModifySelection:) ||
- command == @selector(scrollPageUp:) ||
- command == @selector(pageDown:) ||
- command == @selector(pageDownAndModifySelection:) ||
- command == @selector(scrollPageDown:) ||
- command == @selector(scrollToBeginningOfDocument:) ||
- command == @selector(scrollToEndOfDocument:) ||
- command == @selector(moveUp:) ||
- command == @selector(moveDown:)) {
- TabContents* contents =
- findBarBridge_->GetFindBarController()->tab_contents();
- if (!contents)
- return NO;
-
- // Sanity-check to make sure we got a keyboard event.
- NSEvent* event = [NSApp currentEvent];
- if ([event type] != NSKeyDown && [event type] != NSKeyUp)
- return NO;
-
- // Forward the event to the renderer.
- // TODO(rohitrao): Should this call -[BaseView keyEvent:]? Is there code in
- // that function that we want to keep or avoid? Calling
- // |ForwardKeyboardEvent()| directly ignores edit commands, which breaks
- // cmd-up/down if we ever decide to include |moveToBeginningOfDocument:| in
- // the list above.
- RenderViewHost* render_view_host = contents->render_view_host();
- render_view_host->ForwardKeyboardEvent(NativeWebKeyboardEvent(event));
- return YES;
- }
-
- return NO;
-}
-
-// Methods from FindBar
-- (void)showFindBar:(BOOL)animate {
- // Save the currently-focused view. |findBarView_| is in the view
- // hierarchy by now. showFindBar can be called even when the
- // findbar is already open, so do not overwrite an already saved
- // view.
- if (!focusTracker_.get())
- focusTracker_.reset(
- [[FocusTracker alloc] initWithWindow:[findBarView_ window]]);
-
- // Animate the view into place.
- NSRect frame = [findBarView_ frame];
- frame.origin = NSMakePoint(0, 0);
- [self setFindBarFrame:frame animate:animate duration:kFindBarOpenDuration];
-}
-
-- (void)hideFindBar:(BOOL)animate {
- NSRect frame = [self hiddenFindBarFrame];
- [self setFindBarFrame:frame animate:animate duration:kFindBarCloseDuration];
-}
-
-- (void)stopAnimation {
- if (currentAnimation_.get()) {
- [currentAnimation_ stopAnimation];
- currentAnimation_.reset(nil);
- }
-}
-
-- (void)setFocusAndSelection {
- [[findText_ window] makeFirstResponder:findText_];
-
- // Enable the buttons if the find text is non-empty.
- BOOL buttonsEnabled = ([[findText_ stringValue] length] > 0) ? YES : NO;
- [previousButton_ setEnabled:buttonsEnabled];
- [nextButton_ setEnabled:buttonsEnabled];
-}
-
-- (void)restoreSavedFocus {
- if (!(focusTracker_.get() &&
- [focusTracker_ restoreFocusInWindow:[findBarView_ window]])) {
- // Fall back to giving focus to the tab contents.
- findBarBridge_->GetFindBarController()->tab_contents()->Focus();
- }
- focusTracker_.reset(nil);
-}
-
-- (void)setFindText:(NSString*)findText {
- [findText_ setStringValue:findText];
-
- // Make sure the text in the find bar always ends up in the find pasteboard
- // (and, via notifications, in the other find bars too).
- [[FindPasteboard sharedInstance] setFindText:findText];
-}
-
-- (void)clearResults:(const FindNotificationDetails&)results {
- // Just call updateUIForFindResult, which will take care of clearing
- // the search text and the results label.
- [self updateUIForFindResult:results withText:string16()];
-}
-
-- (void)updateUIForFindResult:(const FindNotificationDetails&)result
- withText:(const string16&)findText {
- // If we don't have any results and something was passed in, then
- // that means someone pressed Cmd-G while the Find box was
- // closed. In that case we need to repopulate the Find box with what
- // was passed in.
- if ([[findText_ stringValue] length] == 0 && !findText.empty()) {
- [findText_ setStringValue:base::SysUTF16ToNSString(findText)];
- [findText_ selectText:self];
- }
-
- // Make sure Find Next and Find Previous are enabled if we found any matches.
- BOOL buttonsEnabled = result.number_of_matches() > 0 ? YES : NO;
- [previousButton_ setEnabled:buttonsEnabled];
- [nextButton_ setEnabled:buttonsEnabled];
-
- // Update the results label.
- BOOL validRange = result.active_match_ordinal() != -1 &&
- result.number_of_matches() != -1;
- NSString* searchString = [findText_ stringValue];
- if ([searchString length] > 0 && validRange) {
- [[findText_ findBarTextFieldCell]
- setActiveMatch:result.active_match_ordinal()
- of:result.number_of_matches()];
- } else {
- // If there was no text entered, we don't show anything in the results area.
- [[findText_ findBarTextFieldCell] clearResults];
- }
-
- [findText_ resetFieldEditorFrameIfNeeded];
-
- // If we found any results, reset the focus tracker, so we always
- // restore focus to the tab contents.
- if (result.number_of_matches() > 0)
- focusTracker_.reset(nil);
-}
-
-- (BOOL)isFindBarVisible {
- // Find bar is visible if any part of it is on the screen.
- return NSIntersectsRect([[self view] bounds], [findBarView_ frame]);
-}
-
-- (BOOL)isFindBarAnimating {
- return (currentAnimation_.get() != nil);
-}
-
-// NSAnimation delegate methods.
-- (void)animationDidEnd:(NSAnimation*)animation {
- // Autorelease the animation (cannot use release because the animation object
- // is still on the stack.
- DCHECK(animation == currentAnimation_.get());
- [currentAnimation_.release() autorelease];
-
- // If the find bar is not visible, make it actually hidden, so it'll no longer
- // respond to key events.
- [findBarView_ setHidden:![self isFindBarVisible]];
-}
-
-@end
-
-@implementation FindBarCocoaController (PrivateMethods)
-
-- (NSRect)hiddenFindBarFrame {
- NSRect frame = [findBarView_ frame];
- NSRect containerBounds = [[self view] bounds];
- frame.origin = NSMakePoint(NSMinX(containerBounds), NSMaxY(containerBounds));
- return frame;
-}
-
-- (void)setFindBarFrame:(NSRect)endFrame
- animate:(BOOL)animate
- duration:(float)duration {
- // Save the current frame.
- NSRect startFrame = [findBarView_ frame];
-
- // Stop any existing animations.
- [currentAnimation_ stopAnimation];
-
- if (!animate) {
- [findBarView_ setFrame:endFrame];
- [findBarView_ setHidden:![self isFindBarVisible]];
- currentAnimation_.reset(nil);
- return;
- }
-
- // If animating, ensure that the find bar is not hidden. Hidden status will be
- // updated at the end of the animation.
- [findBarView_ setHidden:NO];
-
- // Reset the frame to what was saved above.
- [findBarView_ setFrame:startFrame];
- NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
- findBarView_, NSViewAnimationTargetKey,
- [NSValue valueWithRect:endFrame], NSViewAnimationEndFrameKey, nil];
-
- currentAnimation_.reset(
- [[NSViewAnimation alloc]
- initWithViewAnimations:[NSArray arrayWithObjects:dict, nil]]);
- [currentAnimation_ gtm_setDuration:duration
- eventMask:NSLeftMouseUpMask];
- [currentAnimation_ setDelegate:self];
- [currentAnimation_ startAnimation];
-}
-
-- (void)prepopulateText:(NSString*)text stopSearch:(BOOL)stopSearch{
- [self setFindText:text];
-
- // End the find session, hide the "x of y" text and disable the
- // buttons, but do not close the find bar or raise the window here.
- if (stopSearch && findBarBridge_) {
- TabContents* contents =
- findBarBridge_->GetFindBarController()->tab_contents();
- if (contents) {
- contents->StopFinding(FindBarController::kClearSelection);
- findBarBridge_->ClearResults(contents->find_result());
- }
- }
-
- // Has to happen after |ClearResults()| above.
- BOOL buttonsEnabled = [text length] > 0 ? YES : NO;
- [previousButton_ setEnabled:buttonsEnabled];
- [nextButton_ setEnabled:buttonsEnabled];
-}
-
-@end
diff --git a/chrome/browser/cocoa/find_bar_cocoa_controller_unittest.mm b/chrome/browser/cocoa/find_bar_cocoa_controller_unittest.mm
deleted file mode 100644
index eb5e3fc..0000000
--- a/chrome/browser/cocoa/find_bar_cocoa_controller_unittest.mm
+++ /dev/null
@@ -1,138 +0,0 @@
-// Copyright (c) 2009 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/string_util.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/browser_window.h"
-#include "chrome/browser/find_notification_details.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/find_bar_cocoa_controller.h"
-#import "chrome/browser/cocoa/find_pasteboard.h"
-#import "chrome/browser/cocoa/find_bar_text_field.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-// Expose private variables to make testing easier.
-@interface FindBarCocoaController(Testing)
-- (NSView*)findBarView;
-- (NSString*)findText;
-- (FindBarTextField*)findTextField;
-@end
-
-@implementation FindBarCocoaController(Testing)
-- (NSView*)findBarView {
- return findBarView_;
-}
-
-- (NSString*)findText {
- return [findText_ stringValue];
-}
-
-- (FindBarTextField*)findTextField {
- return findText_;
-}
-
-- (NSButton*)nextButton {
- return nextButton_;
-}
-
-- (NSButton*)previousButton {
- return previousButton_;
-}
-@end
-
-namespace {
-
-class FindBarCocoaControllerTest : public CocoaTest {
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
- controller_.reset([[FindBarCocoaController alloc] init]);
- [[test_window() contentView] addSubview:[controller_ view]];
- }
-
- protected:
- scoped_nsobject<FindBarCocoaController> controller_;
-};
-
-TEST_VIEW(FindBarCocoaControllerTest, [controller_ view])
-
-TEST_F(FindBarCocoaControllerTest, ImagesLoadedProperly) {
- EXPECT_TRUE([[[controller_ nextButton] image] isValid]);
- EXPECT_TRUE([[[controller_ previousButton] image] isValid]);
-}
-
-TEST_F(FindBarCocoaControllerTest, ShowAndHide) {
- NSView* findBarView = [controller_ findBarView];
-
- ASSERT_GT([findBarView frame].origin.y, 0);
- ASSERT_FALSE([controller_ isFindBarVisible]);
-
- [controller_ showFindBar:NO];
- EXPECT_EQ([findBarView frame].origin.y, 0);
- EXPECT_TRUE([controller_ isFindBarVisible]);
-
- [controller_ hideFindBar:NO];
- EXPECT_GT([findBarView frame].origin.y, 0);
- EXPECT_FALSE([controller_ isFindBarVisible]);
-}
-
-TEST_F(FindBarCocoaControllerTest, SetFindText) {
- NSTextField* findTextField = [controller_ findTextField];
-
- // Start by making the find bar visible.
- [controller_ showFindBar:NO];
- EXPECT_TRUE([controller_ isFindBarVisible]);
-
- // Set the find text.
- NSString* const kFindText = @"Google";
- [controller_ setFindText:kFindText];
- EXPECT_EQ(
- NSOrderedSame,
- [[findTextField stringValue] compare:kFindText]);
-
- // Call clearResults, which doesn't actually clear the find text but
- // simply sets it back to what it was before. This is silly, but
- // matches the behavior on other platforms. |details| isn't used by
- // our implementation of clearResults, so it's ok to pass in an
- // empty |details|.
- FindNotificationDetails details;
- [controller_ clearResults:details];
- EXPECT_EQ(
- NSOrderedSame,
- [[findTextField stringValue] compare:kFindText]);
-}
-
-TEST_F(FindBarCocoaControllerTest, ResultLabelUpdatesCorrectly) {
- // TODO(rohitrao): Test this. It may involve creating some dummy
- // FindNotificationDetails objects.
-}
-
-TEST_F(FindBarCocoaControllerTest, FindTextIsGlobal) {
- scoped_nsobject<FindBarCocoaController> otherController(
- [[FindBarCocoaController alloc] init]);
- [[test_window() contentView] addSubview:[otherController view]];
-
- // Setting the text in one controller should update the other controller's
- // text as well.
- NSString* const kFindText = @"Respect to the man in the ice cream van";
- [controller_ setFindText:kFindText];
- EXPECT_EQ(
- NSOrderedSame,
- [[controller_ findText] compare:kFindText]);
- EXPECT_EQ(
- NSOrderedSame,
- [[otherController.get() findText] compare:kFindText]);
-}
-
-TEST_F(FindBarCocoaControllerTest, SettingFindTextUpdatesFindPboard) {
- NSString* const kFindText =
- @"It's not a bird, it's not a plane, it must be Dave who's on the train";
- [controller_ setFindText:kFindText];
- EXPECT_EQ(
- NSOrderedSame,
- [[[FindPasteboard sharedInstance] findText] compare:kFindText]);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/find_bar_text_field.h b/chrome/browser/cocoa/find_bar_text_field.h
deleted file mode 100644
index 714fbdb..0000000
--- a/chrome/browser/cocoa/find_bar_text_field.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2009 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>
-#import "chrome/browser/cocoa/styled_text_field.h"
-
-@class FindBarTextFieldCell;
-
-// TODO(rohitrao): This class may not need to exist, since it does not really
-// add any functionality over StyledTextField. See if we can change the nib
-// file to put a FindBarTextFieldCell into a StyledTextField.
-
-// Extends StyledTextField to use a custom cell class (FindBarTextFieldCell).
-@interface FindBarTextField : StyledTextField {
-}
-
-// Convenience method to return the cell, casted appropriately.
-- (FindBarTextFieldCell*)findBarTextFieldCell;
-
-@end
diff --git a/chrome/browser/cocoa/find_bar_text_field.mm b/chrome/browser/cocoa/find_bar_text_field.mm
deleted file mode 100644
index da36f12..0000000
--- a/chrome/browser/cocoa/find_bar_text_field.mm
+++ /dev/null
@@ -1,40 +0,0 @@
-// 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 "chrome/browser/cocoa/find_bar_text_field.h"
-
-#include "base/logging.h"
-#import "chrome/browser/cocoa/find_bar_text_field_cell.h"
-#import "chrome/browser/cocoa/view_id_util.h"
-
-@implementation FindBarTextField
-
-+ (Class)cellClass {
- return [FindBarTextFieldCell class];
-}
-
-- (void)awakeFromNib {
- DCHECK([[self cell] isKindOfClass:[FindBarTextFieldCell class]]);
-
- [self registerForDraggedTypes:
- [NSArray arrayWithObjects:NSStringPboardType, nil]];
-}
-
-- (FindBarTextFieldCell*)findBarTextFieldCell {
- DCHECK([[self cell] isKindOfClass:[FindBarTextFieldCell class]]);
- return static_cast<FindBarTextFieldCell*>([self cell]);
-}
-
-- (ViewID)viewID {
- return VIEW_ID_FIND_IN_PAGE_TEXT_FIELD;
-}
-
-- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info {
- // When a drag enters the text field, focus the field. This will swap in the
- // field editor, which will then handle the drag itself.
- [[self window] makeFirstResponder:self];
- return NSDragOperationNone;
-}
-
-@end
diff --git a/chrome/browser/cocoa/find_bar_text_field_cell.h b/chrome/browser/cocoa/find_bar_text_field_cell.h
deleted file mode 100644
index 2ca447a..0000000
--- a/chrome/browser/cocoa/find_bar_text_field_cell.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) 2009 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>
-
-#import "chrome/browser/cocoa/styled_text_field_cell.h"
-
-#include "base/scoped_nsobject.h"
-
-// FindBarTextFieldCell extends StyledTextFieldCell to provide support for a
-// results label rooted at the right edge of the cell.
-@interface FindBarTextFieldCell : StyledTextFieldCell {
- @private
- // Set if there is a results label to display on the right side of the cell.
- scoped_nsobject<NSAttributedString> resultsString_;
-}
-
-// Sets the results label to the localized equivalent of "X of Y".
-- (void)setActiveMatch:(NSInteger)current of:(NSInteger)total;
-
-- (void)clearResults;
-
-@end
diff --git a/chrome/browser/cocoa/find_bar_text_field_cell.mm b/chrome/browser/cocoa/find_bar_text_field_cell.mm
deleted file mode 100644
index 62f2564..0000000
--- a/chrome/browser/cocoa/find_bar_text_field_cell.mm
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/find_bar_text_field_cell.h"
-
-#include "app/l10n_util.h"
-#include "base/logging.h"
-#include "base/string_number_conversions.h"
-#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
-#include "grit/generated_resources.h"
-
-namespace {
-
-const CGFloat kBaselineAdjust = 1.0;
-
-// How far to offset the keyword token into the field.
-const NSInteger kResultsXOffset = 3;
-
-// How much width (beyond text) to add to the keyword token on each
-// side.
-const NSInteger kResultsTokenInset = 3;
-
-// How far to shift bounding box of hint down from top of field.
-// Assumes -setFlipped:YES.
-const NSInteger kResultsYOffset = 4;
-
-// How far the editor insets itself, for purposes of determining if
-// decorations need to be trimmed.
-const CGFloat kEditorHorizontalInset = 3.0;
-
-// Conveniences to centralize width+offset calculations.
-CGFloat WidthForResults(NSAttributedString* resultsString) {
- return kResultsXOffset + ceil([resultsString size].width) +
- 2 * kResultsTokenInset;
-}
-
-} // namespace
-
-@implementation FindBarTextFieldCell
-
-- (CGFloat)baselineAdjust {
- return kBaselineAdjust;
-}
-
-- (CGFloat)cornerRadius {
- return 4.0;
-}
-
-- (StyledTextFieldCellRoundedFlags)roundedFlags {
- return StyledTextFieldCellRoundedLeft;
-}
-
-// @synthesize doesn't seem to compile for this transition.
-- (NSAttributedString*)resultsString {
- return resultsString_.get();
-}
-
-// Convenience for the attributes used in the right-justified info
-// cells. Sets the background color to red if |foundMatches| is YES.
-- (NSDictionary*)resultsAttributes:(BOOL)foundMatches {
- scoped_nsobject<NSMutableParagraphStyle> style(
- [[NSMutableParagraphStyle alloc] init]);
- [style setAlignment:NSRightTextAlignment];
-
- return [NSDictionary dictionaryWithObjectsAndKeys:
- [self font], NSFontAttributeName,
- [NSColor lightGrayColor], NSForegroundColorAttributeName,
- [NSColor whiteColor], NSBackgroundColorAttributeName,
- style.get(), NSParagraphStyleAttributeName,
- nil];
-}
-
-- (void)setActiveMatch:(NSInteger)current of:(NSInteger)total {
- NSString* results =
- base::SysUTF16ToNSString(l10n_util::GetStringFUTF16(
- IDS_FIND_IN_PAGE_COUNT,
- base::IntToString16(current),
- base::IntToString16(total)));
- resultsString_.reset([[NSAttributedString alloc]
- initWithString:results
- attributes:[self resultsAttributes:(total > 0)]]);
-}
-
-- (void)clearResults {
- resultsString_.reset(nil);
-}
-
-- (NSRect)textFrameForFrame:(NSRect)cellFrame {
- NSRect textFrame([super textFrameForFrame:cellFrame]);
- if (resultsString_)
- textFrame.size.width -= WidthForResults(resultsString_);
- return textFrame;
-}
-
-// Do not show the I-beam cursor over the results label.
-- (NSRect)textCursorFrameForFrame:(NSRect)cellFrame {
- return [self textFrameForFrame:cellFrame];
-}
-
-- (void)drawResultsWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
- DCHECK(resultsString_);
-
- NSRect textFrame = [self textFrameForFrame:cellFrame];
- NSRect infoFrame(NSMakeRect(NSMaxX(textFrame),
- cellFrame.origin.y + kResultsYOffset,
- ceil([resultsString_ size].width),
- cellFrame.size.height - kResultsYOffset));
- [resultsString_.get() drawInRect:infoFrame];
-}
-
-- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
- if (resultsString_)
- [self drawResultsWithFrame:cellFrame inView:controlView];
- [super drawInteriorWithFrame:cellFrame inView:controlView];
-}
-
-@end
diff --git a/chrome/browser/cocoa/find_bar_text_field_cell_unittest.mm b/chrome/browser/cocoa/find_bar_text_field_cell_unittest.mm
deleted file mode 100644
index 56864dc..0000000
--- a/chrome/browser/cocoa/find_bar_text_field_cell_unittest.mm
+++ /dev/null
@@ -1,135 +0,0 @@
-// Copyright (c) 2009 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 "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/find_bar_text_field_cell.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-@interface FindBarTextFieldCell (ExposedForTesting)
-- (NSAttributedString*)resultsString;
-@end
-
-@implementation FindBarTextFieldCell (ExposedForTesting)
-- (NSAttributedString*)resultsString {
- return resultsString_.get();
-}
-@end
-
-namespace {
-
-// Width of the field so that we don't have to ask |field_| for it all
-// the time.
-const CGFloat kWidth(300.0);
-
-// A narrow width for tests which test things that don't fit.
-const CGFloat kNarrowWidth(5.0);
-
-class FindBarTextFieldCellTest : public CocoaTest {
- public:
- FindBarTextFieldCellTest() {
- // Make sure this is wide enough to play games with the cell
- // decorations.
- const NSRect frame = NSMakeRect(0, 0, kWidth, 30);
-
- scoped_nsobject<FindBarTextFieldCell> cell(
- [[FindBarTextFieldCell alloc] initTextCell:@"Testing"]);
- cell_ = cell;
- [cell_ setEditable:YES];
- [cell_ setBordered:YES];
-
- scoped_nsobject<NSTextField> view(
- [[NSTextField alloc] initWithFrame:frame]);
- view_ = view;
- [view_ setCell:cell_];
-
- [[test_window() contentView] addSubview:view_];
- }
-
- NSTextField* view_;
- FindBarTextFieldCell* cell_;
-};
-
-// Basic view tests (AddRemove, Display).
-TEST_VIEW(FindBarTextFieldCellTest, view_);
-
-// Test drawing, mostly to ensure nothing leaks or crashes.
-TEST_F(FindBarTextFieldCellTest, FocusedDisplay) {
- [view_ display];
-
- // Test focused drawing.
- [test_window() makePretendKeyWindowAndSetFirstResponder:view_];
- [view_ display];
- [test_window() clearPretendKeyWindowAndFirstResponder];
-
- // Test display of various cell configurations.
- [cell_ setActiveMatch:4 of:30];
- [view_ display];
-
- [cell_ setActiveMatch:0 of:0];
- [view_ display];
-
- [cell_ clearResults];
- [view_ display];
-}
-
-// Verify that setting and clearing the find results changes the results string
-// appropriately.
-TEST_F(FindBarTextFieldCellTest, SetAndClearFindResults) {
- [cell_ setActiveMatch:10 of:30];
- scoped_nsobject<NSAttributedString> tenString([[cell_ resultsString] copy]);
- EXPECT_GT([tenString length], 0U);
-
- [cell_ setActiveMatch:0 of:0];
- scoped_nsobject<NSAttributedString> zeroString([[cell_ resultsString] copy]);
- EXPECT_GT([zeroString length], 0U);
- EXPECT_FALSE([tenString isEqualToAttributedString:zeroString]);
-
- [cell_ clearResults];
- EXPECT_EQ(0U, [[cell_ resultsString] length]);
-}
-
-TEST_F(FindBarTextFieldCellTest, TextFrame) {
- const NSRect bounds = [view_ bounds];
- NSRect textFrame = [cell_ textFrameForFrame:bounds];
- NSRect cursorFrame = [cell_ textCursorFrameForFrame:bounds];
-
- // At default settings, everything goes to the text area.
- EXPECT_FALSE(NSIsEmptyRect(textFrame));
- EXPECT_TRUE(NSContainsRect(bounds, textFrame));
- EXPECT_EQ(NSMinX(bounds), NSMinX(textFrame));
- EXPECT_EQ(NSMaxX(bounds), NSMaxX(textFrame));
- EXPECT_TRUE(NSEqualRects(cursorFrame, textFrame));
-
- // Setting an active match leaves text frame to left.
- [cell_ setActiveMatch:4 of:5];
- textFrame = [cell_ textFrameForFrame:bounds];
- cursorFrame = [cell_ textCursorFrameForFrame:bounds];
- EXPECT_FALSE(NSIsEmptyRect(textFrame));
- EXPECT_TRUE(NSContainsRect(bounds, textFrame));
- EXPECT_LT(NSMaxX(textFrame), NSMaxX(bounds));
- EXPECT_TRUE(NSEqualRects(cursorFrame, textFrame));
-
-}
-
-// The editor frame should be slightly inset from the text frame.
-TEST_F(FindBarTextFieldCellTest, DrawingRectForBounds) {
- const NSRect bounds = [view_ bounds];
- NSRect textFrame = [cell_ textFrameForFrame:bounds];
- NSRect drawingRect = [cell_ drawingRectForBounds:bounds];
-
- EXPECT_FALSE(NSIsEmptyRect(drawingRect));
- EXPECT_TRUE(NSContainsRect(textFrame, NSInsetRect(drawingRect, 1, 1)));
-
- [cell_ setActiveMatch:4 of:5];
- textFrame = [cell_ textFrameForFrame:bounds];
- drawingRect = [cell_ drawingRectForBounds:bounds];
- EXPECT_FALSE(NSIsEmptyRect(drawingRect));
- EXPECT_TRUE(NSContainsRect(textFrame, NSInsetRect(drawingRect, 1, 1)));
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/find_bar_text_field_unittest.mm b/chrome/browser/cocoa/find_bar_text_field_unittest.mm
deleted file mode 100644
index fdb1b38..0000000
--- a/chrome/browser/cocoa/find_bar_text_field_unittest.mm
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright (c) 2009 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>
-
-#import "base/cocoa_protocols_mac.h"
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/find_bar_text_field.h"
-#import "chrome/browser/cocoa/find_bar_text_field_cell.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-#import "third_party/ocmock/OCMock/OCMock.h"
-
-// OCMock wants to mock a concrete class or protocol. This should
-// provide a correct protocol for newer versions of the SDK, while
-// providing something mockable for older versions.
-
-@protocol MockTextEditingDelegate<NSControlTextEditingDelegate>
-- (void)controlTextDidBeginEditing:(NSNotification*)aNotification;
-- (BOOL)control:(NSControl*)control textShouldEndEditing:(NSText*)fieldEditor;
-@end
-
-namespace {
-
-// Width of the field so that we don't have to ask |field_| for it all
-// the time.
-static const CGFloat kWidth(300.0);
-
-class FindBarTextFieldTest : public CocoaTest {
- public:
- FindBarTextFieldTest() {
- // Make sure this is wide enough to play games with the cell
- // decorations.
- NSRect frame = NSMakeRect(0, 0, kWidth, 30);
- scoped_nsobject<FindBarTextField> field(
- [[FindBarTextField alloc] initWithFrame:frame]);
- field_ = field.get();
-
- [field_ setStringValue:@"Test test"];
- [[test_window() contentView] addSubview:field_];
- }
-
- FindBarTextField* field_;
-};
-
-// Basic view tests (AddRemove, Display).
-TEST_VIEW(FindBarTextFieldTest, field_);
-
-// Test that we have the right cell class.
-TEST_F(FindBarTextFieldTest, CellClass) {
- EXPECT_TRUE([[field_ cell] isKindOfClass:[FindBarTextFieldCell class]]);
-}
-
-// Test that we get the same cell from -cell and
-// -findBarTextFieldCell.
-TEST_F(FindBarTextFieldTest, Cell) {
- FindBarTextFieldCell* cell = [field_ findBarTextFieldCell];
- EXPECT_EQ(cell, [field_ cell]);
- EXPECT_TRUE(cell != nil);
-}
-
-// Test that becoming first responder sets things up correctly.
-TEST_F(FindBarTextFieldTest, FirstResponder) {
- EXPECT_EQ(nil, [field_ currentEditor]);
- EXPECT_EQ([[field_ subviews] count], 0U);
- [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
- EXPECT_FALSE(nil == [field_ currentEditor]);
- EXPECT_EQ([[field_ subviews] count], 1U);
- EXPECT_TRUE([[field_ currentEditor] isDescendantOf:field_]);
-}
-
-// Test drawing, mostly to ensure nothing leaks or crashes.
-TEST_F(FindBarTextFieldTest, Display) {
- [field_ display];
-
- // Test focussed drawing.
- [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
- [field_ display];
- [test_window() clearPretendKeyWindowAndFirstResponder];
-
- // Test display of various cell configurations.
- FindBarTextFieldCell* cell = [field_ findBarTextFieldCell];
- [cell setActiveMatch:4 of:5];
- [field_ display];
-
- [cell clearResults];
- [field_ display];
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/find_bar_view.h b/chrome/browser/cocoa/find_bar_view.h
deleted file mode 100644
index 41d1ec3..0000000
--- a/chrome/browser/cocoa/find_bar_view.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_FIND_BAR_VIEW_H_
-#define CHROME_BROWSER_COCOA_FIND_BAR_VIEW_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "chrome/browser/cocoa/background_gradient_view.h"
-
-// A view that handles painting the border for the FindBar.
-
-@interface FindBarView : BackgroundGradientView {
-}
-@end
-
-#endif // CHROME_BROWSER_COCOA_FIND_BAR_VIEW_H_
diff --git a/chrome/browser/cocoa/find_bar_view.mm b/chrome/browser/cocoa/find_bar_view.mm
deleted file mode 100644
index a928452..0000000
--- a/chrome/browser/cocoa/find_bar_view.mm
+++ /dev/null
@@ -1,131 +0,0 @@
-// 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 "chrome/browser/cocoa/find_bar_view.h"
-
-#import "chrome/browser/cocoa/themed_window.h"
-#import "chrome/browser/cocoa/view_id_util.h"
-#import "chrome/browser/cocoa/url_drop_target.h"
-
-namespace {
-CGFloat kCurveSize = 8;
-} // end namespace
-
-@implementation FindBarView
-
-- (void)awakeFromNib {
- // Register for all the drag types handled by the RWHVCocoa.
- [self registerForDraggedTypes:[URLDropTargetHandler handledDragTypes]];
-}
-
-- (void)drawRect:(NSRect)rect {
- // TODO(rohitrao): Make this prettier.
- rect = NSInsetRect([self bounds], 0.5, 0.5);
- rect = NSOffsetRect(rect, 0, 1.0);
-
- NSPoint topLeft = NSMakePoint(NSMinX(rect), NSMaxY(rect));
- NSPoint topRight = NSMakePoint(NSMaxX(rect), NSMaxY(rect));
- NSPoint midLeft1 =
- NSMakePoint(NSMinX(rect) + kCurveSize, NSMaxY(rect) - kCurveSize);
- NSPoint midLeft2 =
- NSMakePoint(NSMinX(rect) + kCurveSize, NSMinY(rect) + kCurveSize);
- NSPoint midRight1 =
- NSMakePoint(NSMaxX(rect) - kCurveSize, NSMinY(rect) + kCurveSize);
- NSPoint midRight2 =
- NSMakePoint(NSMaxX(rect) - kCurveSize, NSMaxY(rect) - kCurveSize);
- NSPoint bottomLeft =
- NSMakePoint(NSMinX(rect) + (2 * kCurveSize), NSMinY(rect));
- NSPoint bottomRight =
- NSMakePoint(NSMaxX(rect) - (2 * kCurveSize), NSMinY(rect));
-
- NSBezierPath* path = [NSBezierPath bezierPath];
- [path moveToPoint:topLeft];
- [path curveToPoint:midLeft1
- controlPoint1:NSMakePoint(midLeft1.x, topLeft.y)
- controlPoint2:NSMakePoint(midLeft1.x, topLeft.y)];
- [path lineToPoint:midLeft2];
- [path curveToPoint:bottomLeft
- controlPoint1:NSMakePoint(midLeft2.x, bottomLeft.y)
- controlPoint2:NSMakePoint(midLeft2.x, bottomLeft.y)];
-
- [path lineToPoint:bottomRight];
- [path curveToPoint:midRight1
- controlPoint1:NSMakePoint(midRight1.x, bottomLeft.y)
- controlPoint2:NSMakePoint(midRight1.x, bottomLeft.y)];
- [path lineToPoint:midRight2];
- [path curveToPoint:topRight
- controlPoint1:NSMakePoint(midRight2.x, topLeft.y)
- controlPoint2:NSMakePoint(midRight2.x, topLeft.y)];
- NSGraphicsContext* context = [NSGraphicsContext currentContext];
- [context saveGraphicsState];
- [path addClip];
-
- // Set the pattern phase
- NSPoint phase = [[self window] themePatternPhase];
-
- [context setPatternPhase:phase];
- [super drawBackground];
- [context restoreGraphicsState];
-
- [[self strokeColor] set];
- [path stroke];
-}
-
-// The findbar is mostly opaque, but has an 8px transparent border on the left
-// and right sides (see |kCurveSize|). This is an artifact of the way it is
-// drawn. We override hitTest to return nil for points in this transparent
-// area.
-- (NSView*)hitTest:(NSPoint)point {
- NSView* hitView = [super hitTest:point];
- if (hitView == self) {
- // |rect| is approximately equivalent to the opaque area of the findbar.
- NSRect rect = NSInsetRect([self bounds], kCurveSize, 0);
- if (!NSMouseInRect(point, rect, [self isFlipped]))
- return nil;
- }
-
- return hitView;
-}
-
-// Eat all mouse events, to prevent clicks from falling through to views below.
-- (void)mouseDown:(NSEvent *)theEvent {
-}
-
-- (void)rightMouseDown:(NSEvent *)theEvent {
-}
-
-- (void)otherMouseDown:(NSEvent *)theEvent {
-}
-
-- (void)mouseUp:(NSEvent *)theEvent {
-}
-
-- (void)rightMouseUp:(NSEvent *)theEvent {
-}
-
-- (void)otherMouseUp:(NSEvent *)theEvent {
-}
-
-- (void)mouseMoved:(NSEvent *)theEvent {
-}
-
-- (void)mouseDragged:(NSEvent *)theEvent {
-}
-
-- (void)rightMouseDragged:(NSEvent *)theEvent {
-}
-
-- (void)otherMouseDragged:(NSEvent *)theEvent {
-}
-
-// Eat drag operations, to prevent drags from going through to the views below.
-- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info {
- return NSDragOperationNone;
-}
-
-- (ViewID)viewID {
- return VIEW_ID_FIND_IN_PAGE;
-}
-
-@end
diff --git a/chrome/browser/cocoa/find_bar_view_unittest.mm b/chrome/browser/cocoa/find_bar_view_unittest.mm
deleted file mode 100644
index c4fb773..0000000
--- a/chrome/browser/cocoa/find_bar_view_unittest.mm
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright (c) 2009 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 "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/find_bar_view.h"
-#include "chrome/browser/cocoa/test_event_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-@interface MouseDownViewPong : NSView {
- BOOL pong_;
-}
-@property (nonatomic, assign) BOOL pong;
-@end
-
-@implementation MouseDownViewPong
-@synthesize pong = pong_;
-- (void)mouseDown:(NSEvent*)event {
- pong_ = YES;
-}
-@end
-
-
-namespace {
-
-class FindBarViewTest : public CocoaTest {
- public:
- FindBarViewTest() {
- NSRect frame = NSMakeRect(0, 0, 100, 30);
- scoped_nsobject<FindBarView> view(
- [[FindBarView alloc] initWithFrame:frame]);
- view_ = view.get();
- [[test_window() contentView] addSubview:view_];
- }
-
- FindBarView* view_;
-};
-
-TEST_VIEW(FindBarViewTest, view_)
-
-TEST_F(FindBarViewTest, FindBarEatsMouseClicksInBackgroundArea) {
- scoped_nsobject<MouseDownViewPong> pongView(
- [[MouseDownViewPong alloc] initWithFrame:NSMakeRect(0, 0, 200, 200)]);
-
- // Remove all of the subviews of the findbar, to make sure we don't
- // accidentally hit a subview when trying to simulate a click in the
- // background area.
- [view_ setSubviews:[NSArray array]];
- [view_ setFrame:NSMakeRect(0, 0, 200, 200)];
-
- // Add the pong view as a sibling of the findbar.
- [[test_window() contentView] addSubview:pongView.get()
- positioned:NSWindowBelow
- relativeTo:view_];
-
- // Synthesize a mousedown event and send it to the window. The event is
- // placed in the center of the find bar.
- NSPoint pointInCenterOfFindBar = NSMakePoint(100, 100);
- [pongView setPong:NO];
- [test_window()
- sendEvent:test_event_utils::LeftMouseDownAtPoint(pointInCenterOfFindBar)];
- // Click gets eaten by findbar, not passed through to underlying view.
- EXPECT_FALSE([pongView pong]);
-}
-
-TEST_F(FindBarViewTest, FindBarPassesThroughClicksInTransparentArea) {
- scoped_nsobject<MouseDownViewPong> pongView(
- [[MouseDownViewPong alloc] initWithFrame:NSMakeRect(0, 0, 200, 200)]);
- [view_ setFrame:NSMakeRect(0, 0, 200, 200)];
-
- // Add the pong view as a sibling of the findbar.
- [[test_window() contentView] addSubview:pongView.get()
- positioned:NSWindowBelow
- relativeTo:view_];
-
- // Synthesize a mousedown event and send it to the window. The event is inset
- // a few pixels from the lower left corner of the window, which places it in
- // the transparent area surrounding the findbar.
- NSPoint pointInTransparentArea = NSMakePoint(2, 2);
- [pongView setPong:NO];
- [test_window()
- sendEvent:test_event_utils::LeftMouseDownAtPoint(pointInTransparentArea)];
- // Click is ignored by findbar, passed through to underlying view.
- EXPECT_TRUE([pongView pong]);
-}
-} // namespace
diff --git a/chrome/browser/cocoa/find_pasteboard.h b/chrome/browser/cocoa/find_pasteboard.h
deleted file mode 100644
index 6460997..0000000
--- a/chrome/browser/cocoa/find_pasteboard.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_FIND_PASTEBOARD_H_
-#define CHROME_BROWSER_COCOA_FIND_PASTEBOARD_H_
-#pragma once
-
-#include "base/string16.h"
-
-#ifdef __OBJC__
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_nsobject.h"
-
-extern NSString* kFindPasteboardChangedNotification;
-
-// Manages the find pasteboard. Use this to copy text to the find pasteboard,
-// to get the text currently on the find pasteboard, and to receive
-// notifications when the text on the find pasteboard has changed. You should
-// always use this class instead of accessing
-// [NSPasteboard pasteboardWithName:NSFindPboard] directly.
-//
-// This is not thread-safe and must be used on the main thread.
-//
-// This is supposed to be a singleton.
-@interface FindPasteboard : NSObject {
- @private
- scoped_nsobject<NSString> findText_;
-}
-
-// Returns the singleton instance of this class.
-+ (FindPasteboard*)sharedInstance;
-
-// Returns the current find text. This is never nil; if there is no text on the
-// find pasteboard, this returns an empty string.
-- (NSString*)findText;
-
-// Sets the current find text to |newText| and sends a
-// |kFindPasteboardChangedNotification| to the default notification center if
-// it the new text different from the current text. |newText| must not be nil.
-- (void)setFindText:(NSString*)newText;
-@end
-
-@interface FindPasteboard (TestingAPI)
-- (void)loadTextFromPasteboard:(NSNotification*)notification;
-
-// This methods is meant to be overridden in tests.
-- (NSPasteboard*)findPboard;
-@end
-
-#endif // __OBJC__
-
-// Also provide a c++ interface
-string16 GetFindPboardText();
-
-#endif // CHROME_BROWSER_COCOA_FIND_PASTEBOARD_H_
diff --git a/chrome/browser/cocoa/find_pasteboard.mm b/chrome/browser/cocoa/find_pasteboard.mm
deleted file mode 100644
index 0d081d0..0000000
--- a/chrome/browser/cocoa/find_pasteboard.mm
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/find_pasteboard.h"
-
-#include "base/logging.h"
-#include "base/sys_string_conversions.h"
-
-NSString* kFindPasteboardChangedNotification =
- @"kFindPasteboardChangedNotification_Chrome";
-
-@implementation FindPasteboard
-
-+ (FindPasteboard*)sharedInstance {
- static FindPasteboard* instance = nil;
- if (!instance) {
- instance = [[FindPasteboard alloc] init];
- }
- return instance;
-}
-
-- (id)init {
- if ((self = [super init])) {
- findText_.reset([[NSString alloc] init]);
-
- // Check if the text in the findboard has changed on app activate.
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(loadTextFromPasteboard:)
- name:NSApplicationDidBecomeActiveNotification
- object:nil];
- [self loadTextFromPasteboard:nil];
- }
- return self;
-}
-
-- (void)dealloc {
- // Since this is a singleton, this should only be executed in test code.
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [super dealloc];
-}
-
-- (NSPasteboard*)findPboard {
- return [NSPasteboard pasteboardWithName:NSFindPboard];
-}
-
-- (void)loadTextFromPasteboard:(NSNotification*)notification {
- NSPasteboard* findPboard = [self findPboard];
- if ([[findPboard types] containsObject:NSStringPboardType])
- [self setFindText:[findPboard stringForType:NSStringPboardType]];
-}
-
-- (NSString*)findText {
- return findText_;
-}
-
-- (void)setFindText:(NSString*)newText {
- DCHECK(newText);
- if (!newText)
- return;
-
- DCHECK([NSThread isMainThread]);
-
- BOOL needToSendNotification = ![findText_.get() isEqualToString:newText];
- if (needToSendNotification) {
- findText_.reset([newText copy]);
- NSPasteboard* findPboard = [self findPboard];
- [findPboard declareTypes:[NSArray arrayWithObject:NSStringPboardType]
- owner:nil];
- [findPboard setString:findText_.get() forType:NSStringPboardType];
- [[NSNotificationCenter defaultCenter]
- postNotificationName:kFindPasteboardChangedNotification
- object:self];
- }
-}
-
-@end
-
-string16 GetFindPboardText() {
- return base::SysNSStringToUTF16([[FindPasteboard sharedInstance] findText]);
-}
diff --git a/chrome/browser/cocoa/find_pasteboard_unittest.mm b/chrome/browser/cocoa/find_pasteboard_unittest.mm
deleted file mode 100644
index 3dcfb36..0000000
--- a/chrome/browser/cocoa/find_pasteboard_unittest.mm
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (c) 2009 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 "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/find_pasteboard.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-// A subclass of FindPasteboard that doesn't write to the real find pasteboard.
-@interface FindPasteboardTesting : FindPasteboard {
- @public
- int notificationCount_;
- @private
- NSPasteboard* pboard_;
-}
-- (NSPasteboard*)findPboard;
-
-- (void)callback:(id)sender;
-
-// These are for checking that pasteboard content is copied to/from the
-// FindPasteboard correctly.
-- (NSString*)findPboardText;
-- (void)setFindPboardText:(NSString*)text;
-@end
-
-@implementation FindPasteboardTesting
-
-- (id)init {
- if ((self = [super init])) {
- pboard_ = [NSPasteboard pasteboardWithUniqueName];
- }
- return self;
-}
-
-- (void)dealloc {
- [pboard_ releaseGlobally];
- [super dealloc];
-}
-
-- (NSPasteboard*)findPboard {
- return pboard_;
-}
-
-- (void)callback:(id)sender {
- ++notificationCount_;
-}
-
-- (void)setFindPboardText:(NSString*)text {
- [pboard_ declareTypes:[NSArray arrayWithObject:NSStringPboardType]
- owner:nil];
- [pboard_ setString:text forType:NSStringPboardType];
-}
-
-- (NSString*)findPboardText {
- return [pboard_ stringForType:NSStringPboardType];
-}
-@end
-
-namespace {
-
-class FindPasteboardTest : public CocoaTest {
- public:
- FindPasteboardTest() {
- pboard_.reset([[FindPasteboardTesting alloc] init]);
- }
- protected:
- scoped_nsobject<FindPasteboardTesting> pboard_;
-};
-
-TEST_F(FindPasteboardTest, SettingTextUpdatesPboard) {
- [pboard_.get() setFindText:@"text"];
- EXPECT_EQ(
- NSOrderedSame,
- [[pboard_.get() findPboardText] compare:@"text"]);
-}
-
-TEST_F(FindPasteboardTest, ReadingFromPboardUpdatesFindText) {
- [pboard_.get() setFindPboardText:@"text"];
- [pboard_.get() loadTextFromPasteboard:nil];
- EXPECT_EQ(
- NSOrderedSame,
- [[pboard_.get() findText] compare:@"text"]);
-}
-
-TEST_F(FindPasteboardTest, SendsNotificationWhenTextChanges) {
- [[NSNotificationCenter defaultCenter]
- addObserver:pboard_.get()
- selector:@selector(callback:)
- name:kFindPasteboardChangedNotification
- object:pboard_.get()];
- EXPECT_EQ(0, pboard_.get()->notificationCount_);
- [pboard_.get() setFindText:@"text"];
- EXPECT_EQ(1, pboard_.get()->notificationCount_);
- [pboard_.get() setFindText:@"text"];
- EXPECT_EQ(1, pboard_.get()->notificationCount_);
- [pboard_.get() setFindText:@"other text"];
- EXPECT_EQ(2, pboard_.get()->notificationCount_);
-
- [pboard_.get() setFindPboardText:@"other text"];
- [pboard_.get() loadTextFromPasteboard:nil];
- EXPECT_EQ(2, pboard_.get()->notificationCount_);
-
- [pboard_.get() setFindPboardText:@"otherer text"];
- [pboard_.get() loadTextFromPasteboard:nil];
- EXPECT_EQ(3, pboard_.get()->notificationCount_);
-
- [[NSNotificationCenter defaultCenter] removeObserver:pboard_.get()];
-}
-
-
-} // namespace
diff --git a/chrome/browser/cocoa/first_run_bubble_controller.h b/chrome/browser/cocoa/first_run_bubble_controller.h
deleted file mode 100644
index 4e5fac5..0000000
--- a/chrome/browser/cocoa/first_run_bubble_controller.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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>
-
-#import "chrome/browser/cocoa/base_bubble_controller.h"
-
-class Profile;
-
-// Manages the first run bubble.
-@interface FirstRunBubbleController : BaseBubbleController {
- @private
- // Header label.
- IBOutlet NSTextField* header_;
-
- Profile* profile_;
-}
-
-// Creates and shows a firstRun bubble.
-+ (FirstRunBubbleController*) showForView:(NSView*)view
- offset:(NSPoint)offset
- profile:(Profile*)profile;
-@end
diff --git a/chrome/browser/cocoa/first_run_bubble_controller.mm b/chrome/browser/cocoa/first_run_bubble_controller.mm
deleted file mode 100644
index 0469eee..0000000
--- a/chrome/browser/cocoa/first_run_bubble_controller.mm
+++ /dev/null
@@ -1,84 +0,0 @@
-// 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 "chrome/browser/cocoa/first_run_bubble_controller.h"
-
-#include "app/l10n_util.h"
-#include "base/logging.h"
-#include "base/utf_string_conversions.h"
-#import "chrome/browser/cocoa/l10n_util.h"
-#import "chrome/browser/cocoa/info_bubble_view.h"
-#include "chrome/browser/search_engines/util.h"
-#include "grit/generated_resources.h"
-
-@interface FirstRunBubbleController(Private)
-- (id)initRelativeToView:(NSView*)view
- offset:(NSPoint)offset
- profile:(Profile*)profile;
-- (void)closeIfNotKey;
-@end
-
-@implementation FirstRunBubbleController
-
-+ (FirstRunBubbleController*) showForView:(NSView*)view
- offset:(NSPoint)offset
- profile:(Profile*)profile {
- // Autoreleases itself on bubble close.
- return [[FirstRunBubbleController alloc] initRelativeToView:view
- offset:offset
- profile:profile];
-}
-
-- (id)initRelativeToView:(NSView*)view
- offset:(NSPoint)offset
- profile:(Profile*)profile {
- if ((self = [super initWithWindowNibPath:@"FirstRunBubble"
- relativeToView:view
- offset:offset])) {
- profile_ = profile;
- [self showWindow:nil];
-
- // On 10.5, the first run bubble sometimes does not disappear when clicking
- // the omnibox. This happens if the bubble never became key, due to it
- // showing up so early in the startup sequence. As a workaround, close it
- // automatically after a few seconds if it doesn't become key.
- // http://crbug.com/52726
- [self performSelector:@selector(closeIfNotKey) withObject:nil afterDelay:3];
- }
- return self;
-}
-
-- (void)awakeFromNib {
- [[self bubble] setBubbleType:info_bubble::kWhiteInfoBubble];
-
- DCHECK(header_);
- [header_ setStringValue:cocoa_l10n_util::ReplaceNSStringPlaceholders(
- [header_ stringValue], GetDefaultSearchEngineName(profile_), NULL)];
-
- // Adapt window size to bottom buttons. Do this before all other layouting.
- CGFloat dy = cocoa_l10n_util::VerticallyReflowGroup([[self bubble] subviews]);
- NSSize ds = NSMakeSize(0, dy);
- ds = [[self bubble] convertSize:ds toView:nil];
-
- NSRect frame = [[self window] frame];
- frame.origin.y -= ds.height;
- frame.size.height += ds.height;
- [[self window] setFrame:frame display:YES];
-}
-
-- (void)close {
- // If the window is closed before the timer is fired, cancel the timer, since
- // it retains the controller.
- [NSObject cancelPreviousPerformRequestsWithTarget:self
- selector:@selector(closeIfNotKey)
- object:nil];
- [super close];
-}
-
-- (void)closeIfNotKey {
- if (![[self window] isKeyWindow])
- [self close];
-}
-
-@end // FirstRunBubbleController
diff --git a/chrome/browser/cocoa/first_run_bubble_controller_unittest.mm b/chrome/browser/cocoa/first_run_bubble_controller_unittest.mm
deleted file mode 100644
index 094b1f6..0000000
--- a/chrome/browser/cocoa/first_run_bubble_controller_unittest.mm
+++ /dev/null
@@ -1,44 +0,0 @@
-// 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 "chrome/browser/cocoa/first_run_bubble_controller.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/debug/debugger.h"
-#include "base/scoped_nsobject.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-class FirstRunBubbleControllerTest : public CocoaTest {
- public:
- BrowserTestHelper helper_;
-};
-
-// Check that the bubble doesn't crash or leak.
-TEST_F(FirstRunBubbleControllerTest, Init) {
- scoped_nsobject<NSWindow> parent([[NSWindow alloc]
- initWithContentRect:NSMakeRect(0, 0, 800, 600)
- styleMask:NSBorderlessWindowMask
- backing:NSBackingStoreBuffered
- defer:NO]);
- [parent setReleasedWhenClosed:NO];
- if (base::debug::BeingDebugged())
- [parent.get() orderFront:nil];
- else
- [parent.get() orderBack:nil];
-
- FirstRunBubbleController* controller = [FirstRunBubbleController
- showForView:[parent.get() contentView]
- offset:NSMakePoint(300, 300)
- profile:helper_.profile()];
- EXPECT_TRUE(controller != nil);
- EXPECT_TRUE([[controller window] isVisible]);
- [parent.get() close];
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/first_run_dialog.mm b/chrome/browser/cocoa/first_run_dialog.mm
deleted file mode 100644
index 5b97bde..0000000
--- a/chrome/browser/cocoa/first_run_dialog.mm
+++ /dev/null
@@ -1,195 +0,0 @@
-// 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 "chrome/browser/cocoa/first_run_dialog.h"
-
-#include "app/l10n_util_mac.h"
-#include "base/mac_util.h"
-#include "base/message_loop.h"
-#include "base/ref_counted.h"
-#include "grit/locale_settings.h"
-#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-
-@interface FirstRunDialogController (PrivateMethods)
-// Show the dialog.
-- (void)show;
-@end
-
-namespace {
-
-// Compare function for -[NSArray sortedArrayUsingFunction:context:] that
-// sorts the views in Y order bottom up.
-NSInteger CompareFrameY(id view1, id view2, void* context) {
- CGFloat y1 = NSMinY([view1 frame]);
- CGFloat y2 = NSMinY([view2 frame]);
- if (y1 < y2)
- return NSOrderedAscending;
- else if (y1 > y2)
- return NSOrderedDescending;
- else
- return NSOrderedSame;
-}
-
-class FirstRunShowBridge : public base::RefCounted<FirstRunShowBridge> {
- public:
- FirstRunShowBridge(FirstRunDialogController* controller);
-
- void ShowDialog();
- private:
- FirstRunDialogController* controller_;
-};
-
-FirstRunShowBridge::FirstRunShowBridge(
- FirstRunDialogController* controller) : controller_(controller) {
-}
-
-void FirstRunShowBridge::ShowDialog() {
- [controller_ show];
- MessageLoop::current()->QuitNow();
-}
-
-};
-
-@implementation FirstRunDialogController
-
-@synthesize statsEnabled = statsEnabled_;
-@synthesize makeDefaultBrowser = makeDefaultBrowser_;
-
-- (id)init {
- NSString* nibpath =
- [mac_util::MainAppBundle() pathForResource:@"FirstRunDialog"
- ofType:@"nib"];
- self = [super initWithWindowNibPath:nibpath owner:self];
- if (self != nil) {
- // Bound to the dialog checkbox, default to true.
- makeDefaultBrowser_ = YES;
- }
- return self;
-}
-
-- (void)dealloc {
- [super dealloc];
-}
-
-- (IBAction)showWindow:(id)sender {
- // The main MessageLoop has not yet run, but has been spun. If we call
- // -[NSApplication runModalForWindow:] we will hang <http://crbug.com/54248>.
- // Therefore the main MessageLoop is run so things work.
-
- scoped_refptr<FirstRunShowBridge> bridge(new FirstRunShowBridge(self));
- MessageLoop::current()->PostTask(
- FROM_HERE,
- NewRunnableMethod(bridge.get(),
- &FirstRunShowBridge::ShowDialog));
- MessageLoop::current()->Run();
-}
-
-- (void)show {
- NSWindow* win = [self window];
-
- // Only support the sizing the window once.
- DCHECK(!beenSized_) << "ShowWindow was called twice?";
- if (!beenSized_) {
- beenSized_ = YES;
- DCHECK_GT([objectsToSize_ count], 0U);
-
- // Size everything to fit, collecting the widest growth needed (XIB provides
- // the min size, i.e.-never shrink, just grow).
- CGFloat largestWidthChange = 0.0;
- for (NSView* view in objectsToSize_) {
- DCHECK_NE(statsCheckbox_, view) << "Stats checkbox shouldn't be in list";
- if (![view isHidden]) {
- NSSize delta = [GTMUILocalizerAndLayoutTweaker sizeToFitView:view];
- DCHECK_EQ(delta.height, 0.0)
- << "Didn't expect anything to change heights";
- if (largestWidthChange < delta.width)
- largestWidthChange = delta.width;
- }
- }
-
- // Make the window wide enough to fit everything.
- if (largestWidthChange > 0.0) {
- NSView* contentView = [win contentView];
- NSRect windowFrame = [contentView convertRect:[win frame] fromView:nil];
- windowFrame.size.width += largestWidthChange;
- windowFrame = [contentView convertRect:windowFrame toView:nil];
- [win setFrame:windowFrame display:NO];
- }
-
- // The stats checkbox gets some really long text, so it gets word wrapped
- // and then sized.
- DCHECK(statsCheckbox_);
- CGFloat statsCheckboxHeightChange = 0.0;
- [GTMUILocalizerAndLayoutTweaker wrapButtonTitleForWidth:statsCheckbox_];
- statsCheckboxHeightChange =
- [GTMUILocalizerAndLayoutTweaker sizeToFitView:statsCheckbox_].height;
-
- // Walk bottom up shuffling for all the hidden views.
- NSArray* subViews =
- [[[win contentView] subviews] sortedArrayUsingFunction:CompareFrameY
- context:NULL];
- CGFloat moveDown = 0.0;
- NSUInteger numSubViews = [subViews count];
- for (NSUInteger idx = 0 ; idx < numSubViews ; ++idx) {
- NSView* view = [subViews objectAtIndex:idx];
-
- // If the view is hidden, collect the amount to move everything above it
- // down, if it's not hidden, apply any shift down.
- if ([view isHidden]) {
- DCHECK_GT((numSubViews - 1), idx)
- << "Don't support top view being hidden";
- NSView* nextView = [subViews objectAtIndex:(idx + 1)];
- CGFloat viewBottom = [view frame].origin.y;
- CGFloat nextViewBottom = [nextView frame].origin.y;
- moveDown += nextViewBottom - viewBottom;
- } else {
- if (moveDown != 0.0) {
- NSPoint origin = [view frame].origin;
- origin.y -= moveDown;
- [view setFrameOrigin:origin];
- }
- }
- // Special case, if this is the stats checkbox, everything above it needs
- // to get moved up by the amount it changed height.
- if (view == statsCheckbox_) {
- moveDown -= statsCheckboxHeightChange;
- }
- }
-
- // Resize the window for any height change from hidden views, etc.
- if (moveDown != 0.0) {
- NSView* contentView = [win contentView];
- [contentView setAutoresizesSubviews:NO];
- NSRect windowFrame = [contentView convertRect:[win frame] fromView:nil];
- windowFrame.size.height -= moveDown;
- windowFrame = [contentView convertRect:windowFrame toView:nil];
- [win setFrame:windowFrame display:NO];
- [contentView setAutoresizesSubviews:YES];
- }
-
- }
-
- // Neat weirdness in the below code - the Application menu stays enabled
- // while the window is open but selecting items from it (e.g. Quit) has
- // no effect. I'm guessing that this is an artifact of us being a
- // background-only application at this stage and displaying a modal
- // window.
-
- // Display dialog.
- [win center];
- [NSApp runModalForWindow:win];
-}
-
-- (IBAction)ok:(id)sender {
- [[self window] close];
- [NSApp stopModal];
-}
-
-- (IBAction)learnMore:(id)sender {
- NSString* urlStr = l10n_util::GetNSString(IDS_LEARN_MORE_REPORTING_URL);
- NSURL* learnMoreUrl = [NSURL URLWithString:urlStr];
- [[NSWorkspace sharedWorkspace] openURL:learnMoreUrl];
-}
-
-@end
diff --git a/chrome/browser/cocoa/floating_bar_backing_view.h b/chrome/browser/cocoa/floating_bar_backing_view.h
deleted file mode 100644
index c5e503e..0000000
--- a/chrome/browser/cocoa/floating_bar_backing_view.h
+++ /dev/null
@@ -1,15 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_FLOATING_BAR_BACKING_VIEW_H_
-#define CHROME_BROWSER_COCOA_FLOATING_BAR_BACKING_VIEW_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-// A custom view that draws the tab strip background for fullscreen windows.
-@interface FloatingBarBackingView : NSView
-@end
-
-#endif // CHROME_BROWSER_COCOA_FLOATING_BAR_BACKING_VIEW_H_
diff --git a/chrome/browser/cocoa/floating_bar_backing_view.mm b/chrome/browser/cocoa/floating_bar_backing_view.mm
deleted file mode 100644
index a3c1b0f..0000000
--- a/chrome/browser/cocoa/floating_bar_backing_view.mm
+++ /dev/null
@@ -1,51 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/floating_bar_backing_view.h"
-
-#include "base/mac_util.h"
-#import "chrome/browser/cocoa/browser_frame_view.h"
-
-@implementation FloatingBarBackingView
-
-- (void)drawRect:(NSRect)rect {
- NSWindow* window = [self window];
- BOOL isMainWindow = [window isMainWindow];
-
- if (isMainWindow)
- [[NSColor windowFrameColor] set];
- else
- [[NSColor windowBackgroundColor] set];
- NSRectFill(rect);
-
- // TODO(rohitrao): Don't assume -22 here.
- [BrowserFrameView drawWindowThemeInDirtyRect:rect
- forView:self
- bounds:[self bounds]
- offset:NSMakePoint(0, -22)
- forceBlackBackground:YES];
-
-}
-
-// Eat all mouse events (and do *not* pass them on to the next responder!).
-- (void)mouseDown:(NSEvent*)event {}
-- (void)rightMouseDown:(NSEvent*)event {}
-- (void)otherMouseDown:(NSEvent*)event {}
-- (void)rightMouseUp:(NSEvent*)event {}
-- (void)otherMouseUp:(NSEvent*)event {}
-- (void)mouseMoved:(NSEvent*)event {}
-- (void)mouseDragged:(NSEvent*)event {}
-- (void)rightMouseDragged:(NSEvent*)event {}
-- (void)otherMouseDragged:(NSEvent*)event {}
-
-// Eat this too, except that ...
-- (void)mouseUp:(NSEvent*)event {
- // a double-click in the blank area should try to minimize, to be consistent
- // with double-clicks on the contiguous tab strip area. (It'll fail and beep.)
- if ([event clickCount] == 2 &&
- mac_util::ShouldWindowsMiniaturizeOnDoubleClick())
- [[self window] performMiniaturize:self];
-}
-
-@end // @implementation FloatingBarBackingView
diff --git a/chrome/browser/cocoa/floating_bar_backing_view_unittest.mm b/chrome/browser/cocoa/floating_bar_backing_view_unittest.mm
deleted file mode 100644
index 94d395f..0000000
--- a/chrome/browser/cocoa/floating_bar_backing_view_unittest.mm
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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 "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/floating_bar_backing_view.h"
-
-namespace {
-
-class FloatingBarBackingViewTest : public CocoaTest {
- public:
- FloatingBarBackingViewTest() {
- NSRect content_frame = [[test_window() contentView] frame];
- scoped_nsobject<FloatingBarBackingView> view(
- [[FloatingBarBackingView alloc] initWithFrame:content_frame]);
- view_ = view.get();
- [[test_window() contentView] addSubview:view_];
- }
-
- FloatingBarBackingView* view_; // Weak. Owned by the view hierarchy.
-};
-
-// Tests display, add/remove.
-TEST_VIEW(FloatingBarBackingViewTest, view_);
-
-} // namespace
diff --git a/chrome/browser/cocoa/focus_tracker.mm b/chrome/browser/cocoa/focus_tracker.mm
deleted file mode 100644
index 86b612d..0000000
--- a/chrome/browser/cocoa/focus_tracker.mm
+++ /dev/null
@@ -1,46 +0,0 @@
-// 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 "chrome/browser/cocoa/focus_tracker.h"
-
-#include "base/basictypes.h"
-
-@implementation FocusTracker
-
-- (id)initWithWindow:(NSWindow*)window {
- if ((self = [super init])) {
- NSResponder* current_focus = [window firstResponder];
-
- // Special case NSTextViews, because they are removed from the
- // view hierarchy when their text field does not have focus. If
- // an NSTextView is the current first responder, save a pointer to
- // its NSTextField delegate instead.
- if ([current_focus isKindOfClass:[NSTextView class]]) {
- id delegate = [(NSTextView*)current_focus delegate];
- if ([delegate isKindOfClass:[NSTextField class]])
- current_focus = delegate;
- else
- current_focus = nil;
- }
-
- if ([current_focus isKindOfClass:[NSView class]]) {
- NSView* current_focus_view = (NSView*)current_focus;
- focusedView_.reset([current_focus_view retain]);
- }
- }
-
- return self;
-}
-
-- (BOOL)restoreFocusInWindow:(NSWindow*)window {
- if (!focusedView_.get())
- return NO;
-
- if ([focusedView_ window] && [focusedView_ window] == window)
- return [window makeFirstResponder:focusedView_.get()];
-
- return NO;
-}
-
-@end
diff --git a/chrome/browser/cocoa/focus_tracker_unittest.mm b/chrome/browser/cocoa/focus_tracker_unittest.mm
deleted file mode 100644
index f2fb64f..0000000
--- a/chrome/browser/cocoa/focus_tracker_unittest.mm
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright (c) 2009 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 "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/focus_tracker.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-namespace {
-
-class FocusTrackerTest : public CocoaTest {
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
- scoped_nsobject<NSView> view([[NSView alloc] initWithFrame:NSZeroRect]);
- viewA_ = view.get();
- [[test_window() contentView] addSubview:viewA_];
-
- view.reset([[NSView alloc] initWithFrame:NSZeroRect]);
- viewB_ = view.get();
- [[test_window() contentView] addSubview:viewB_];
- }
-
- protected:
- NSView* viewA_;
- NSView* viewB_;
-};
-
-TEST_F(FocusTrackerTest, SaveRestore) {
- NSWindow* window = test_window();
- ASSERT_TRUE([window makeFirstResponder:viewA_]);
- scoped_nsobject<FocusTracker> tracker(
- [[FocusTracker alloc] initWithWindow:window]);
- // Give focus to |viewB_|, then try and restore it to view1.
- ASSERT_TRUE([window makeFirstResponder:viewB_]);
- EXPECT_TRUE([tracker restoreFocusInWindow:window]);
- EXPECT_EQ(viewA_, [window firstResponder]);
-}
-
-TEST_F(FocusTrackerTest, SaveRestoreWithTextView) {
- // Valgrind will complain if the text field has zero size.
- NSRect frame = NSMakeRect(0, 0, 100, 20);
- NSWindow* window = test_window();
- scoped_nsobject<NSTextField> text([[NSTextField alloc] initWithFrame:frame]);
- [[window contentView] addSubview:text];
-
- ASSERT_TRUE([window makeFirstResponder:text]);
- scoped_nsobject<FocusTracker> tracker([[FocusTracker alloc]
- initWithWindow:window]);
- // Give focus to |viewB_|, then try and restore it to the text field.
- ASSERT_TRUE([window makeFirstResponder:viewB_]);
- EXPECT_TRUE([tracker restoreFocusInWindow:window]);
- EXPECT_TRUE([[window firstResponder] isKindOfClass:[NSTextView class]]);
-}
-
-TEST_F(FocusTrackerTest, DontRestoreToViewNotInWindow) {
- NSWindow* window = test_window();
- scoped_nsobject<NSView> viewC([[NSView alloc] initWithFrame:NSZeroRect]);
- [[window contentView] addSubview:viewC];
-
- ASSERT_TRUE([window makeFirstResponder:viewC]);
- scoped_nsobject<FocusTracker> tracker(
- [[FocusTracker alloc] initWithWindow:window]);
-
- // Give focus to |viewB_|, then remove viewC from the hierarchy and try
- // to restore focus. The restore should fail.
- ASSERT_TRUE([window makeFirstResponder:viewB_]);
- [viewC removeFromSuperview];
- EXPECT_FALSE([tracker restoreFocusInWindow:window]);
-}
-
-TEST_F(FocusTrackerTest, DontRestoreFocusToViewInDifferentWindow) {
- NSWindow* window = test_window();
- ASSERT_TRUE([window makeFirstResponder:viewA_]);
- scoped_nsobject<FocusTracker> tracker(
- [[FocusTracker alloc] initWithWindow:window]);
-
- // Give focus to |viewB_|, then try and restore focus in a different
- // window. It is ok to pass a nil NSWindow here because we only use
- // it for direct comparison.
- ASSERT_TRUE([window makeFirstResponder:viewB_]);
- EXPECT_FALSE([tracker restoreFocusInWindow:nil]);
-}
-
-
-} // namespace
diff --git a/chrome/browser/cocoa/font_language_settings_controller.h b/chrome/browser/cocoa/font_language_settings_controller.h
deleted file mode 100644
index 9e03323..0000000
--- a/chrome/browser/cocoa/font_language_settings_controller.h
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright (c) 2009 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 "base/cocoa_protocols_mac.h"
-#include "base/scoped_nsobject.h"
-#include "chrome/browser/prefs/pref_member.h"
-
-class Profile;
-
-// Used to keep track of which type of font the user is currently selecting.
-enum FontSettingType {
- FontSettingSerif,
- FontSettingSansSerif,
- FontSettingFixed
-};
-
-// Keys for the dictionaries in the |encodings_| array.
-extern NSString* const kCharacterInfoEncoding; // NSString value.
-extern NSString* const kCharacterInfoName; // NSString value.
-extern NSString* const kCharacterInfoID; // NSNumber value.
-
-// A window controller that allows the user to change the default WebKit fonts
-// and language encodings for web pages. This window controller is meant to be
-// used as a modal sheet on another window.
-@interface FontLanguageSettingsController : NSWindowController
- <NSWindowDelegate> {
- @private
- // The font that we are currently changing.
- NSFont* currentFont_; // weak
- FontSettingType currentType_;
-
- IBOutlet NSButton* serifButton_;
- IBOutlet NSTextField* serifField_;
- scoped_nsobject<NSFont> serifFont_;
- IBOutlet NSTextField* serifLabel_;
- BOOL changedSerif_;
-
- IBOutlet NSButton* sansSerifButton_;
- IBOutlet NSTextField* sansSerifField_;
- scoped_nsobject<NSFont> sansSerifFont_;
- IBOutlet NSTextField* sansSerifLabel_;
- BOOL changedSansSerif_;
-
- IBOutlet NSButton* fixedWidthButton_;
- IBOutlet NSTextField* fixedWidthField_;
- scoped_nsobject<NSFont> fixedWidthFont_;
- IBOutlet NSTextField* fixedWidthLabel_;
- BOOL changedFixedWidth_;
-
- // The actual preference members.
- StringPrefMember serifName_;
- StringPrefMember sansSerifName_;
- StringPrefMember fixedWidthName_;
- IntegerPrefMember serifSize_;
- IntegerPrefMember sansSerifSize_;
- IntegerPrefMember fixedWidthSize_;
-
- // Array of dictionaries that contain the canonical encoding name, human-
- // readable name, and the ID. See the constants defined at the top of this
- // file for the keys.
- scoped_nsobject<NSMutableArray> encodings_;
-
- IBOutlet NSPopUpButton* encodingsMenu_;
- NSInteger defaultEncodingIndex_;
- StringPrefMember defaultEncoding_;
- BOOL changedEncoding_;
-
- Profile* profile_; // weak
-}
-
-// Profile cannot be NULL. Caller is responsible for showing the window as a
-// modal sheet.
-- (id)initWithProfile:(Profile*)profile;
-
-// Action for all the font changing buttons. This starts the font picker.
-- (IBAction)selectFont:(id)sender;
-
-// Sent by the FontManager after the user has selected a font.
-- (void)changeFont:(id)fontManager;
-
-// Performs the closing of the window. This is used by both the cancel button
-// and |-save:| after it persists the settings.
-- (IBAction)closeSheet:(id)sender;
-
-// Persists the new values into the preferences and closes the sheet.
-- (IBAction)save:(id)sender;
-
-// Returns the |encodings_| array. This is used by bindings for KVO/KVC.
-- (NSArray*)encodings;
-
-@end
diff --git a/chrome/browser/cocoa/font_language_settings_controller.mm b/chrome/browser/cocoa/font_language_settings_controller.mm
deleted file mode 100644
index 6395a1e..0000000
--- a/chrome/browser/cocoa/font_language_settings_controller.mm
+++ /dev/null
@@ -1,280 +0,0 @@
-// 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 "chrome/browser/cocoa/font_language_settings_controller.h"
-
-#import <Cocoa/Cocoa.h>
-#import "base/mac_util.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/character_encoding.h"
-#include "chrome/browser/fonts_languages_window.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/common/pref_names.h"
-
-NSString* const kCharacterInfoEncoding = @"encoding";
-NSString* const kCharacterInfoName = @"name";
-NSString* const kCharacterInfoID = @"id";
-
-void ShowFontsLanguagesWindow(gfx::NativeWindow window,
- FontsLanguagesPage page,
- Profile* profile) {
- NOTIMPLEMENTED();
-}
-
-@interface FontLanguageSettingsController (Private)
-- (void)updateDisplayField:(NSTextField*)field
- withFont:(NSFont*)font
- withLabel:(NSTextField*)label;
-@end
-
-@implementation FontLanguageSettingsController
-
-- (id)initWithProfile:(Profile*)profile {
- DCHECK(profile);
- NSString* nibpath = [mac_util::MainAppBundle()
- pathForResource:@"FontLanguageSettings"
- ofType:@"nib"];
- if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
- profile_ = profile;
-
- // Convert the name/size preference values to NSFont objects.
- serifName_.Init(prefs::kWebKitSerifFontFamily, profile->GetPrefs(), NULL);
- serifSize_.Init(prefs::kWebKitDefaultFontSize, profile->GetPrefs(), NULL);
- NSString* serif = base::SysUTF8ToNSString(serifName_.GetValue());
- serifFont_.reset(
- [[NSFont fontWithName:serif size:serifSize_.GetValue()] retain]);
-
- sansSerifName_.Init(prefs::kWebKitSansSerifFontFamily, profile->GetPrefs(),
- NULL);
- sansSerifSize_.Init(prefs::kWebKitDefaultFontSize, profile->GetPrefs(),
- NULL);
- NSString* sansSerif = base::SysUTF8ToNSString(sansSerifName_.GetValue());
- sansSerifFont_.reset(
- [[NSFont fontWithName:sansSerif
- size:sansSerifSize_.GetValue()] retain]);
-
- fixedWidthName_.Init(prefs::kWebKitFixedFontFamily, profile->GetPrefs(),
- NULL);
- fixedWidthSize_.Init(prefs::kWebKitDefaultFixedFontSize,
- profile->GetPrefs(), NULL);
- NSString* fixedWidth = base::SysUTF8ToNSString(fixedWidthName_.GetValue());
- fixedWidthFont_.reset(
- [[NSFont fontWithName:fixedWidth
- size:fixedWidthSize_.GetValue()] retain]);
-
- // Generate a list of encodings.
- NSInteger count = CharacterEncoding::GetSupportCanonicalEncodingCount();
- NSMutableArray* encodings = [NSMutableArray arrayWithCapacity:count];
- for (NSInteger i = 0; i < count; ++i) {
- int commandId = CharacterEncoding::GetEncodingCommandIdByIndex(i);
- string16 name = CharacterEncoding::\
- GetCanonicalEncodingDisplayNameByCommandId(commandId);
- std::string encoding =
- CharacterEncoding::GetCanonicalEncodingNameByCommandId(commandId);
- NSDictionary* strings = [NSDictionary dictionaryWithObjectsAndKeys:
- base::SysUTF16ToNSString(name), kCharacterInfoName,
- base::SysUTF8ToNSString(encoding), kCharacterInfoEncoding,
- [NSNumber numberWithInt:commandId], kCharacterInfoID,
- nil
- ];
- [encodings addObject:strings];
- }
-
- // Sort the encodings.
- scoped_nsobject<NSSortDescriptor> sorter(
- [[NSSortDescriptor alloc] initWithKey:kCharacterInfoName
- ascending:YES]);
- NSArray* sorterArray = [NSArray arrayWithObject:sorter.get()];
- encodings_.reset(
- [[encodings sortedArrayUsingDescriptors:sorterArray] retain]);
-
- // Find and set the default encoding.
- defaultEncoding_.Init(prefs::kDefaultCharset, profile->GetPrefs(), NULL);
- NSString* defaultEncoding =
- base::SysUTF8ToNSString(defaultEncoding_.GetValue());
- NSUInteger index = 0;
- for (NSDictionary* entry in encodings_.get()) {
- NSString* encoding = [entry objectForKey:kCharacterInfoEncoding];
- if ([encoding isEqualToString:defaultEncoding]) {
- defaultEncodingIndex_ = index;
- break;
- }
- ++index;
- }
-
- // Register as a KVO observer so we can receive updates when the encoding
- // changes.
- [self addObserver:self
- forKeyPath:@"defaultEncodingIndex_"
- options:NSKeyValueObservingOptionNew
- context:NULL];
- }
- return self;
-}
-
-- (void)dealloc {
- [self removeObserver:self forKeyPath:@"defaultEncodingIndex_"];
- [super dealloc];
-}
-
-- (void)awakeFromNib {
- DCHECK([self window]);
- [[self window] setDelegate:self];
-
- // Set up the font display.
- [self updateDisplayField:serifField_
- withFont:serifFont_.get()
- withLabel:serifLabel_];
- [self updateDisplayField:sansSerifField_
- withFont:sansSerifFont_.get()
- withLabel:sansSerifLabel_];
- [self updateDisplayField:fixedWidthField_
- withFont:fixedWidthFont_.get()
- withLabel:fixedWidthLabel_];
-}
-
-- (void)windowWillClose:(NSNotification*)notif {
- [self autorelease];
-}
-
-- (IBAction)selectFont:(id)sender {
- if (sender == serifButton_) {
- currentFont_ = serifFont_.get();
- currentType_ = FontSettingSerif;
- } else if (sender == sansSerifButton_) {
- currentFont_ = sansSerifFont_.get();
- currentType_ = FontSettingSansSerif;
- } else if (sender == fixedWidthButton_) {
- currentFont_ = fixedWidthFont_.get();
- currentType_ = FontSettingFixed;
- } else {
- NOTREACHED();
- }
-
- // Validate whatever editing is currently happening.
- if ([[self window] makeFirstResponder:nil]) {
- NSFontManager* manager = [NSFontManager sharedFontManager];
- [manager setTarget:self];
- [manager setSelectedFont:currentFont_ isMultiple:NO];
- [manager orderFrontFontPanel:self];
- }
-}
-
-// Called by the font manager when the user has selected a new font. We should
-// then persist those changes into the preference system.
-- (void)changeFont:(id)fontManager {
- switch (currentType_) {
- case FontSettingSerif:
- serifFont_.reset([[fontManager convertFont:serifFont_] retain]);
- [self updateDisplayField:serifField_
- withFont:serifFont_.get()
- withLabel:serifLabel_];
- changedSerif_ = YES;
- break;
- case FontSettingSansSerif:
- sansSerifFont_.reset([[fontManager convertFont:sansSerifFont_] retain]);
- [self updateDisplayField:sansSerifField_
- withFont:sansSerifFont_.get()
- withLabel:sansSerifLabel_];
- changedSansSerif_ = YES;
- break;
- case FontSettingFixed:
- fixedWidthFont_.reset(
- [[fontManager convertFont:fixedWidthFont_] retain]);
- [self updateDisplayField:fixedWidthField_
- withFont:fixedWidthFont_.get()
- withLabel:fixedWidthLabel_];
- changedFixedWidth_ = YES;
- break;
- default:
- NOTREACHED();
- }
-}
-
-- (IBAction)closeSheet:(id)sender {
- NSFontPanel* panel = [[NSFontManager sharedFontManager] fontPanel:NO];
- [panel close];
- [NSApp endSheet:[self window]];
-}
-
-- (IBAction)save:(id)sender {
- if (changedSerif_) {
- serifName_.SetValue(base::SysNSStringToUTF8([serifFont_ fontName]));
- serifSize_.SetValue([serifFont_ pointSize]);
- }
- if (changedSansSerif_) {
- sansSerifName_.SetValue(
- base::SysNSStringToUTF8([sansSerifFont_ fontName]));
- sansSerifSize_.SetValue([sansSerifFont_ pointSize]);
- }
- if (changedFixedWidth_) {
- fixedWidthName_.SetValue(
- base::SysNSStringToUTF8([fixedWidthFont_ fontName]));
- fixedWidthSize_.SetValue([fixedWidthFont_ pointSize]);
- }
- if (changedEncoding_) {
- NSDictionary* object = [encodings_ objectAtIndex:defaultEncodingIndex_];
- NSString* newEncoding = [object objectForKey:kCharacterInfoEncoding];
- std::string encoding = base::SysNSStringToUTF8(newEncoding);
- defaultEncoding_.SetValue(encoding);
- }
- [self closeSheet:sender];
-}
-
-- (NSArray*)encodings {
- return encodings_.get();
-}
-
-// KVO notification.
-- (void)observeValueForKeyPath:(NSString*)keyPath
- ofObject:(id)object
- change:(NSDictionary*)change
- context:(void*)context {
- // If this is the default encoding, then set the flag to persist the value.
- if ([keyPath isEqual:@"defaultEncodingIndex_"]) {
- changedEncoding_ = YES;
- return;
- }
-
- [super observeValueForKeyPath:keyPath
- ofObject:object
- change:change
- context:context];
-}
-
-#pragma mark Private
-
-// Set the baseline for the font field to be aligned with the baseline
-// of its corresponding label.
-- (NSPoint)getFontFieldOrigin:(NSTextField*)field
- forLabel:(NSTextField*)label {
- [field sizeToFit];
- NSRect labelFrame = [label frame];
- NSPoint newOrigin =
- [[label superview] convertPoint:labelFrame.origin
- toView:[field superview]];
- newOrigin.x = 0; // Left-align font field.
- newOrigin.y += [[field font] descender] - [[label font] descender];
- return newOrigin;
-}
-
-// This will set the font on |field| to be |font|, and will set the string
-// value to something human-readable.
-- (void)updateDisplayField:(NSTextField*)field
- withFont:(NSFont*)font
- withLabel:(NSTextField*)label {
- if (!font) {
- // Something has gone really wrong. Don't make things worse by showing the
- // user "(null)".
- return;
- }
- [field setFont:font];
- NSString* value =
- [NSString stringWithFormat:@"%@, %g", [font fontName], [font pointSize]];
- [field setStringValue:value];
- [field setFrameOrigin:[self getFontFieldOrigin:field forLabel:label]];
-}
-
-@end
diff --git a/chrome/browser/cocoa/font_language_settings_controller_unittest.mm b/chrome/browser/cocoa/font_language_settings_controller_unittest.mm
deleted file mode 100644
index 075d495..0000000
--- a/chrome/browser/cocoa/font_language_settings_controller_unittest.mm
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright (c) 2009 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/scoped_nsobject.h"
-#include "chrome/browser/character_encoding.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/font_language_settings_controller.h"
-#include "chrome/browser/profile.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-// The FontLanguageSettingsControllerForTest overrides the getFontFieldOrigin
-// method to provide a dummy point, so we don't have to actually display the
-// window to test the controller.
-@interface FontLanguageSettingsControllerForTest :
- FontLanguageSettingsController {
-}
-
-- (NSPoint)getFontFieldOrigin:(NSTextField*)field
- forLabel:(NSTextField*)label;
-
-@end
-
-@implementation FontLanguageSettingsControllerForTest
-
-- (NSPoint)getFontFieldOrigin:(NSTextField*)field
- forLabel:(NSTextField*)label {
- return NSMakePoint(10, 10);
-}
-
-@end
-
-@interface FontLanguageSettingsController (Testing)
-- (void)updateDisplayField:(NSTextField*)field
- withFont:(NSFont*)font
- withLabel:(NSTextField*)label;
-@end
-
-class FontLanguageSettingsControllerTest : public CocoaTest {
- public:
- FontLanguageSettingsControllerTest() {
- Profile* profile = helper_.profile();
- font_controller_.reset(
- [[FontLanguageSettingsControllerForTest alloc] initWithProfile:profile]);
- }
- ~FontLanguageSettingsControllerTest() {}
-
- BrowserTestHelper helper_;
- scoped_nsobject<FontLanguageSettingsController> font_controller_;
-};
-
-TEST_F(FontLanguageSettingsControllerTest, Init) {
- ASSERT_EQ(CharacterEncoding::GetSupportCanonicalEncodingCount(),
- static_cast<int>([[font_controller_ encodings] count]));
-}
-
-TEST_F(FontLanguageSettingsControllerTest, UpdateDisplayField) {
- NSFont* font = [NSFont fontWithName:@"Times-Roman" size:12.0];
- scoped_nsobject<NSTextField> field(
- [[NSTextField alloc] initWithFrame:NSMakeRect(100, 100, 100, 100)]);
- scoped_nsobject<NSTextField> label(
- [[NSTextField alloc] initWithFrame:NSMakeRect(100, 100, 100, 100)]);
- [font_controller_ updateDisplayField:field.get()
- withFont:font
- withLabel:label];
-
- ASSERT_NSEQ([font fontName], [[field font] fontName]);
- ASSERT_NSEQ(@"Times-Roman, 12", [field stringValue]);
-}
-
-TEST_F(FontLanguageSettingsControllerTest, UpdateDisplayFieldNilFont) {
- scoped_nsobject<NSTextField> field(
- [[NSTextField alloc] initWithFrame:NSMakeRect(100, 100, 100, 100)]);
- scoped_nsobject<NSTextField> label(
- [[NSTextField alloc] initWithFrame:NSMakeRect(100, 100, 100, 100)]);
- [field setStringValue:@"foo"];
- [font_controller_ updateDisplayField:field.get()
- withFont:nil
- withLabel:label];
-
- ASSERT_NSEQ(@"foo", [field stringValue]);
-}
-
-TEST_F(FontLanguageSettingsControllerTest, UpdateDisplayFieldNilField) {
- // Don't crash.
- NSFont* font = [NSFont fontWithName:@"Times-Roman" size:12.0];
- [font_controller_ updateDisplayField:nil withFont:font withLabel:nil];
-}
diff --git a/chrome/browser/cocoa/framed_browser_window.h b/chrome/browser/cocoa/framed_browser_window.h
deleted file mode 100644
index 80d0815..0000000
--- a/chrome/browser/cocoa/framed_browser_window.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_FRAMED_BROWSER_WINDOW_H_
-#define CHROME_BROWSER_COCOA_FRAMED_BROWSER_WINDOW_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_nsobject.h"
-#include "chrome/browser/cocoa/chrome_browser_window.h"
-
-// Offset from the top of the window frame to the top of the window controls
-// (zoom, close, miniaturize) for a window with a tabstrip.
-const NSInteger kFramedWindowButtonsWithTabStripOffsetFromTop = 6;
-
-// Offset from the top of the window frame to the top of the window controls
-// (zoom, close, miniaturize) for a window without a tabstrip.
-const NSInteger kFramedWindowButtonsWithoutTabStripOffsetFromTop = 4;
-
-// Offset from the left of the window frame to the top of the window controls
-// (zoom, close, miniaturize).
-const NSInteger kFramedWindowButtonsOffsetFromLeft = 8;
-
-// Offset between the window controls (zoom, close, miniaturize).
-const NSInteger kFramedWindowButtonsInterButtonSpacing = 7;
-
-// Cocoa class representing a framed browser window.
-// We need to override NSWindow with our own class since we need access to all
-// unhandled keyboard events and subclassing NSWindow is the only method to do
-// this. We also handle our own window controls and custom window frame drawing.
-@interface FramedBrowserWindow : ChromeBrowserWindow {
- @private
- BOOL shouldHideTitle_;
- NSButton* closeButton_;
- NSButton* miniaturizeButton_;
- NSButton* zoomButton_;
- BOOL entered_;
- scoped_nsobject<NSTrackingArea> widgetTrackingArea_;
-}
-
-// Tells the window to suppress title drawing.
-- (void)setShouldHideTitle:(BOOL)flag;
-
-// Return true if the mouse is currently in our tracking area for our window
-// widgets.
-- (BOOL)mouseInGroup:(NSButton*)widget;
-
-// Update the tracking areas for our window widgets as appropriate.
-- (void)updateTrackingAreas;
-
-@end
-
-@interface NSWindow (UndocumentedAPI)
-
-// Undocumented Cocoa API to suppress drawing of the window's title.
-// -setTitle: still works, but the title set only applies to the
-// miniwindow and menus (and, importantly, Expose). Overridden to
-// return |shouldHideTitle_|.
--(BOOL)_isTitleHidden;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_FRAMED_BROWSER_WINDOW_H_
diff --git a/chrome/browser/cocoa/framed_browser_window.mm b/chrome/browser/cocoa/framed_browser_window.mm
deleted file mode 100644
index 4ca7ba2..0000000
--- a/chrome/browser/cocoa/framed_browser_window.mm
+++ /dev/null
@@ -1,350 +0,0 @@
-// 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 "chrome/browser/cocoa/framed_browser_window.h"
-
-#include "base/logging.h"
-#import "chrome/browser/cocoa/browser_frame_view.h"
-#import "chrome/browser/cocoa/browser_window_controller.h"
-#import "chrome/browser/cocoa/tab_strip_controller.h"
-#import "chrome/browser/cocoa/themed_window.h"
-#include "chrome/browser/global_keyboard_shortcuts_mac.h"
-#import "chrome/browser/renderer_host/render_widget_host_view_mac.h"
-#include "chrome/browser/themes/browser_theme_provider.h"
-
-namespace {
- // Size of the gradient. Empirically determined so that the gradient looks
- // like what the heuristic does when there are just a few tabs.
- const CGFloat kWindowGradientHeight = 24.0;
-}
-
-// Our browser window does some interesting things to get the behaviors that
-// we want. We replace the standard window controls (zoom, close, miniaturize)
-// with our own versions, so that we can position them slightly differently than
-// the default window has them. To do this, we hide the ones that Apple provides
-// us with, and create our own. This requires us to handle tracking for the
-// buttons (so that they highlight and activate correctly) as well as implement
-// the private method _mouseInGroup in our frame view class which is required
-// to get the rollover highlight drawing to draw correctly.
-@interface FramedBrowserWindow(PrivateMethods)
-// Return the view that does the "frame" drawing.
-- (NSView*)frameView;
-@end
-
-@implementation FramedBrowserWindow
-
-- (id)initWithContentRect:(NSRect)contentRect
- styleMask:(NSUInteger)aStyle
- backing:(NSBackingStoreType)bufferingType
- defer:(BOOL)flag {
- if ((self = [super initWithContentRect:contentRect
- styleMask:aStyle
- backing:bufferingType
- defer:flag])) {
- if (aStyle & NSTexturedBackgroundWindowMask) {
- // The following two calls fix http://www.crbug.com/25684 by preventing
- // the window from recalculating the border thickness as the window is
- // resized.
- // This was causing the window tint to change for the default system theme
- // when the window was being resized.
- [self setAutorecalculatesContentBorderThickness:NO forEdge:NSMaxYEdge];
- [self setContentBorderThickness:kWindowGradientHeight forEdge:NSMaxYEdge];
- }
- }
- return self;
-}
-
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [[NSDistributedNotificationCenter defaultCenter] removeObserver:self];
- if (widgetTrackingArea_) {
- [[self frameView] removeTrackingArea:widgetTrackingArea_];
- widgetTrackingArea_.reset();
- }
- [super dealloc];
-}
-
-- (void)setWindowController:(NSWindowController*)controller {
- if (controller == [self windowController]) {
- return;
- }
- // Clean up our old stuff.
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [[NSDistributedNotificationCenter defaultCenter] removeObserver:self];
- [closeButton_ removeFromSuperview];
- closeButton_ = nil;
- [miniaturizeButton_ removeFromSuperview];
- miniaturizeButton_ = nil;
- [zoomButton_ removeFromSuperview];
- zoomButton_ = nil;
-
- [super setWindowController:controller];
-
- BrowserWindowController* browserController
- = static_cast<BrowserWindowController*>(controller);
- if ([browserController isKindOfClass:[BrowserWindowController class]]) {
- NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
- [defaultCenter addObserver:self
- selector:@selector(themeDidChangeNotification:)
- name:kBrowserThemeDidChangeNotification
- object:nil];
-
- // Hook ourselves up to get notified if the user changes the system
- // theme on us.
- NSDistributedNotificationCenter* distCenter =
- [NSDistributedNotificationCenter defaultCenter];
- [distCenter addObserver:self
- selector:@selector(systemThemeDidChangeNotification:)
- name:@"AppleAquaColorVariantChanged"
- object:nil];
- // Set up our buttons how we like them.
- NSView* frameView = [self frameView];
- NSRect frameViewBounds = [frameView bounds];
-
- // Find all the "original" buttons, and hide them. We can't use the original
- // buttons because the OS likes to move them around when we resize windows
- // and will put them back in what it considers to be their "preferred"
- // locations.
- NSButton* oldButton = [self standardWindowButton:NSWindowCloseButton];
- [oldButton setHidden:YES];
- oldButton = [self standardWindowButton:NSWindowMiniaturizeButton];
- [oldButton setHidden:YES];
- oldButton = [self standardWindowButton:NSWindowZoomButton];
- [oldButton setHidden:YES];
-
- // Create and position our new buttons.
- NSUInteger aStyle = [self styleMask];
- closeButton_ = [NSWindow standardWindowButton:NSWindowCloseButton
- forStyleMask:aStyle];
- NSRect closeButtonFrame = [closeButton_ frame];
- CGFloat yOffset = [browserController hasTabStrip] ?
- kFramedWindowButtonsWithTabStripOffsetFromTop :
- kFramedWindowButtonsWithoutTabStripOffsetFromTop;
- closeButtonFrame.origin =
- NSMakePoint(kFramedWindowButtonsOffsetFromLeft,
- (NSHeight(frameViewBounds) -
- NSHeight(closeButtonFrame) - yOffset));
-
- [closeButton_ setFrame:closeButtonFrame];
- [closeButton_ setTarget:self];
- [closeButton_ setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
- [frameView addSubview:closeButton_];
-
- miniaturizeButton_ =
- [NSWindow standardWindowButton:NSWindowMiniaturizeButton
- forStyleMask:aStyle];
- NSRect miniaturizeButtonFrame = [miniaturizeButton_ frame];
- miniaturizeButtonFrame.origin =
- NSMakePoint((NSMaxX(closeButtonFrame) +
- kFramedWindowButtonsInterButtonSpacing),
- NSMinY(closeButtonFrame));
- [miniaturizeButton_ setFrame:miniaturizeButtonFrame];
- [miniaturizeButton_ setTarget:self];
- [miniaturizeButton_ setAutoresizingMask:(NSViewMaxXMargin |
- NSViewMinYMargin)];
- [frameView addSubview:miniaturizeButton_];
-
- zoomButton_ = [NSWindow standardWindowButton:NSWindowZoomButton
- forStyleMask:aStyle];
- NSRect zoomButtonFrame = [zoomButton_ frame];
- zoomButtonFrame.origin =
- NSMakePoint((NSMaxX(miniaturizeButtonFrame) +
- kFramedWindowButtonsInterButtonSpacing),
- NSMinY(miniaturizeButtonFrame));
- [zoomButton_ setFrame:zoomButtonFrame];
- [zoomButton_ setTarget:self];
- [zoomButton_ setAutoresizingMask:(NSViewMaxXMargin |
- NSViewMinYMargin)];
-
- [frameView addSubview:zoomButton_];
- }
-
- // Update our tracking areas. We want to update them even if we haven't
- // added buttons above as we need to remove the old tracking area. If the
- // buttons aren't to be shown, updateTrackingAreas won't add new ones.
- [self updateTrackingAreas];
-}
-
-- (NSView*)frameView {
- return [[self contentView] superview];
-}
-
-// The tab strip view covers our window buttons. So we add hit testing here
-// to find them properly and return them to the accessibility system.
-- (id)accessibilityHitTest:(NSPoint)point {
- NSPoint windowPoint = [self convertScreenToBase:point];
- NSControl* controls[] = { closeButton_, zoomButton_, miniaturizeButton_ };
- id value = nil;
- for (size_t i = 0; i < sizeof(controls) / sizeof(controls[0]); ++i) {
- if (NSPointInRect(windowPoint, [controls[i] frame])) {
- value = [controls[i] accessibilityHitTest:point];
- break;
- }
- }
- if (!value) {
- value = [super accessibilityHitTest:point];
- }
- return value;
-}
-
-// Map our custom buttons into the accessibility hierarchy correctly.
-- (id)accessibilityAttributeValue:(NSString*)attribute {
- id value = nil;
- struct {
- NSString* attribute_;
- id value_;
- } attributeMap[] = {
- { NSAccessibilityCloseButtonAttribute, [closeButton_ cell]},
- { NSAccessibilityZoomButtonAttribute, [zoomButton_ cell]},
- { NSAccessibilityMinimizeButtonAttribute, [miniaturizeButton_ cell]},
- };
-
- for (size_t i = 0; i < sizeof(attributeMap) / sizeof(attributeMap[0]); ++i) {
- if ([attributeMap[i].attribute_ isEqualToString:attribute]) {
- value = attributeMap[i].value_;
- break;
- }
- }
- if (!value) {
- value = [super accessibilityAttributeValue:attribute];
- }
- return value;
-}
-
-- (void)updateTrackingAreas {
- NSView* frameView = [self frameView];
- if (widgetTrackingArea_) {
- [frameView removeTrackingArea:widgetTrackingArea_];
- }
- if (closeButton_) {
- NSRect trackingRect = [closeButton_ frame];
- trackingRect.size.width = NSMaxX([zoomButton_ frame]) -
- NSMinX(trackingRect);
- widgetTrackingArea_.reset(
- [[NSTrackingArea alloc] initWithRect:trackingRect
- options:(NSTrackingMouseEnteredAndExited |
- NSTrackingActiveAlways)
- owner:self
- userInfo:nil]);
- [frameView addTrackingArea:widgetTrackingArea_];
-
- // Check to see if the cursor is still in trackingRect.
- NSPoint point = [self mouseLocationOutsideOfEventStream];
- point = [[self contentView] convertPoint:point fromView:nil];
- BOOL newEntered = NSPointInRect (point, trackingRect);
- if (newEntered != entered_) {
- // Buttons have moved, so update button state.
- entered_ = newEntered;
- [closeButton_ setNeedsDisplay];
- [zoomButton_ setNeedsDisplay];
- [miniaturizeButton_ setNeedsDisplay];
- }
- }
-}
-
-- (void)windowMainStatusChanged {
- [closeButton_ setNeedsDisplay];
- [zoomButton_ setNeedsDisplay];
- [miniaturizeButton_ setNeedsDisplay];
- NSView* frameView = [self frameView];
- NSView* contentView = [self contentView];
- NSRect updateRect = [frameView frame];
- NSRect contentRect = [contentView frame];
- CGFloat tabStripHeight = [TabStripController defaultTabHeight];
- updateRect.size.height -= NSHeight(contentRect) - tabStripHeight;
- updateRect.origin.y = NSMaxY(contentRect) - tabStripHeight;
- [[self frameView] setNeedsDisplayInRect:updateRect];
-}
-
-- (void)becomeMainWindow {
- [self windowMainStatusChanged];
- [super becomeMainWindow];
-}
-
-- (void)resignMainWindow {
- [self windowMainStatusChanged];
- [super resignMainWindow];
-}
-
-// Called after the current theme has changed.
-- (void)themeDidChangeNotification:(NSNotification*)aNotification {
- [[self frameView] setNeedsDisplay:YES];
-}
-
-- (void)systemThemeDidChangeNotification:(NSNotification*)aNotification {
- [closeButton_ setNeedsDisplay];
- [zoomButton_ setNeedsDisplay];
- [miniaturizeButton_ setNeedsDisplay];
-}
-
-- (void)sendEvent:(NSEvent*)event {
- // For cocoa windows, clicking on the close and the miniaturize (but not the
- // zoom buttons) while a window is in the background does NOT bring that
- // window to the front. We don't get that behavior for free, so we handle
- // it here. Zoom buttons do bring the window to the front. Note that
- // Finder windows (in Leopard) behave differently in this regard in that
- // zoom buttons don't bring the window to the foreground.
- BOOL eventHandled = NO;
- if (![self isMainWindow]) {
- if ([event type] == NSLeftMouseDown) {
- NSView* frameView = [self frameView];
- NSPoint mouse = [frameView convertPoint:[event locationInWindow]
- fromView:nil];
- if (NSPointInRect(mouse, [closeButton_ frame])) {
- [closeButton_ mouseDown:event];
- eventHandled = YES;
- } else if (NSPointInRect(mouse, [miniaturizeButton_ frame])) {
- [miniaturizeButton_ mouseDown:event];
- eventHandled = YES;
- }
- }
- }
- if (!eventHandled) {
- [super sendEvent:event];
- }
-}
-
-// Update our buttons so that they highlight correctly.
-- (void)mouseEntered:(NSEvent*)event {
- entered_ = YES;
- [closeButton_ setNeedsDisplay];
- [zoomButton_ setNeedsDisplay];
- [miniaturizeButton_ setNeedsDisplay];
-}
-
-// Update our buttons so that they highlight correctly.
-- (void)mouseExited:(NSEvent*)event {
- entered_ = NO;
- [closeButton_ setNeedsDisplay];
- [zoomButton_ setNeedsDisplay];
- [miniaturizeButton_ setNeedsDisplay];
-}
-
-- (BOOL)mouseInGroup:(NSButton*)widget {
- return entered_;
-}
-
-- (void)setShouldHideTitle:(BOOL)flag {
- shouldHideTitle_ = flag;
-}
-
--(BOOL)_isTitleHidden {
- return shouldHideTitle_;
-}
-
-// This method is called whenever a window is moved in order to ensure it fits
-// on the screen. We cannot always handle resizes without breaking, so we
-// prevent frame constraining in those cases.
-- (NSRect)constrainFrameRect:(NSRect)frame toScreen:(NSScreen*)screen {
- // Do not constrain the frame rect if our delegate says no. In this case,
- // return the original (unconstrained) frame.
- id delegate = [self delegate];
- if ([delegate respondsToSelector:@selector(shouldConstrainFrameRect)] &&
- ![delegate shouldConstrainFrameRect])
- return frame;
-
- return [super constrainFrameRect:frame toScreen:screen];
-}
-
-@end
diff --git a/chrome/browser/cocoa/framed_browser_window_unittest.mm b/chrome/browser/cocoa/framed_browser_window_unittest.mm
deleted file mode 100644
index 5638561..0000000
--- a/chrome/browser/cocoa/framed_browser_window_unittest.mm
+++ /dev/null
@@ -1,184 +0,0 @@
-// Copyright (c) 2009 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 "base/debug/debugger.h"
-#include "base/scoped_nsobject.h"
-#include "chrome/app/chrome_command_ids.h"
-#import "chrome/browser/cocoa/browser_window_controller.h"
-#import "chrome/browser/cocoa/browser_frame_view.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/framed_browser_window.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-#import "third_party/ocmock/OCMock/OCMock.h"
-
-class FramedBrowserWindowTest : public CocoaTest {
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
- // Create a window.
- const NSUInteger mask = NSTitledWindowMask | NSClosableWindowMask |
- NSMiniaturizableWindowMask | NSResizableWindowMask;
- window_ = [[FramedBrowserWindow alloc]
- initWithContentRect:NSMakeRect(0, 0, 800, 600)
- styleMask:mask
- backing:NSBackingStoreBuffered
- defer:NO];
- if (base::debug::BeingDebugged()) {
- [window_ orderFront:nil];
- } else {
- [window_ orderBack:nil];
- }
- }
-
- virtual void TearDown() {
- [window_ close];
- CocoaTest::TearDown();
- }
-
- // Returns a canonical snapshot of the window.
- NSData* WindowContentsAsTIFF() {
- [window_ display];
-
- NSView* frameView = [window_ contentView];
- while ([frameView superview]) {
- frameView = [frameView superview];
- }
- const NSRect bounds = [frameView bounds];
-
- [frameView lockFocus];
- scoped_nsobject<NSBitmapImageRep> bitmap(
- [[NSBitmapImageRep alloc] initWithFocusedViewRect:bounds]);
- [frameView unlockFocus];
-
- return [bitmap TIFFRepresentation];
- }
-
- FramedBrowserWindow* window_;
-};
-
-// Baseline test that the window creates, displays, closes, and
-// releases.
-TEST_F(FramedBrowserWindowTest, ShowAndClose) {
- [window_ display];
-}
-
-// Test that undocumented title-hiding API we're using does the job.
-TEST_F(FramedBrowserWindowTest, DoesHideTitle) {
- // The -display calls are not strictly necessary, but they do
- // make it easier to see what's happening when debugging (without
- // them the changes are never flushed to the screen).
-
- [window_ setTitle:@""];
- [window_ display];
- NSData* emptyTitleData = WindowContentsAsTIFF();
-
- [window_ setTitle:@"This is a title"];
- [window_ display];
- NSData* thisTitleData = WindowContentsAsTIFF();
-
- // The default window with a title should look different from the
- // window with an empty title.
- EXPECT_FALSE([emptyTitleData isEqualToData:thisTitleData]);
-
- [window_ setShouldHideTitle:YES];
- [window_ setTitle:@""];
- [window_ display];
- [window_ setTitle:@"This is a title"];
- [window_ display];
- NSData* hiddenTitleData = WindowContentsAsTIFF();
-
- // With our magic setting, the window with a title should look the
- // same as the window with an empty title.
- EXPECT_TRUE([window_ _isTitleHidden]);
- EXPECT_TRUE([emptyTitleData isEqualToData:hiddenTitleData]);
-}
-
-// Test to make sure that our window widgets are in the right place.
-TEST_F(FramedBrowserWindowTest, WindowWidgetLocation) {
- // First without tabstrip.
- NSCell* closeBoxCell = [window_ accessibilityAttributeValue:
- NSAccessibilityCloseButtonAttribute];
- NSView* closeBoxControl = [closeBoxCell controlView];
- EXPECT_TRUE(closeBoxControl);
- NSRect closeBoxFrame = [closeBoxControl frame];
- NSRect windowBounds = [window_ frame];
- windowBounds.origin = NSZeroPoint;
- EXPECT_EQ(NSMaxY(closeBoxFrame),
- NSMaxY(windowBounds) -
- kFramedWindowButtonsWithoutTabStripOffsetFromTop);
- EXPECT_EQ(NSMinX(closeBoxFrame), kFramedWindowButtonsOffsetFromLeft);
-
- NSCell* miniaturizeCell = [window_ accessibilityAttributeValue:
- NSAccessibilityMinimizeButtonAttribute];
- NSView* miniaturizeControl = [miniaturizeCell controlView];
- EXPECT_TRUE(miniaturizeControl);
- NSRect miniaturizeFrame = [miniaturizeControl frame];
- EXPECT_EQ(NSMaxY(miniaturizeFrame),
- NSMaxY(windowBounds) -
- kFramedWindowButtonsWithoutTabStripOffsetFromTop);
- EXPECT_EQ(NSMinX(miniaturizeFrame),
- NSMaxX(closeBoxFrame) + kFramedWindowButtonsInterButtonSpacing);
-
- // Then with a tabstrip.
- id controller = [OCMockObject mockForClass:[BrowserWindowController class]];
- BOOL yes = YES;
- BOOL no = NO;
- [[[controller stub] andReturnValue:OCMOCK_VALUE(yes)]
- isKindOfClass:[BrowserWindowController class]];
- [[[controller expect] andReturnValue:OCMOCK_VALUE(yes)] hasTabStrip];
- [[[controller expect] andReturnValue:OCMOCK_VALUE(no)] hasTitleBar];
- [[[controller expect] andReturnValue:OCMOCK_VALUE(yes)] isNormalWindow];
- [window_ setWindowController:controller];
-
- closeBoxCell = [window_ accessibilityAttributeValue:
- NSAccessibilityCloseButtonAttribute];
- closeBoxControl = [closeBoxCell controlView];
- EXPECT_TRUE(closeBoxControl);
- closeBoxFrame = [closeBoxControl frame];
- windowBounds = [window_ frame];
- windowBounds.origin = NSZeroPoint;
- EXPECT_EQ(NSMaxY(closeBoxFrame),
- NSMaxY(windowBounds) -
- kFramedWindowButtonsWithTabStripOffsetFromTop);
- EXPECT_EQ(NSMinX(closeBoxFrame), kFramedWindowButtonsOffsetFromLeft);
-
- miniaturizeCell = [window_ accessibilityAttributeValue:
- NSAccessibilityMinimizeButtonAttribute];
- miniaturizeControl = [miniaturizeCell controlView];
- EXPECT_TRUE(miniaturizeControl);
- miniaturizeFrame = [miniaturizeControl frame];
- EXPECT_EQ(NSMaxY(miniaturizeFrame),
- NSMaxY(windowBounds) -
- kFramedWindowButtonsWithTabStripOffsetFromTop);
- EXPECT_EQ(NSMinX(miniaturizeFrame),
- NSMaxX(closeBoxFrame) + kFramedWindowButtonsInterButtonSpacing);
- [window_ setWindowController:nil];
-}
-
-// Test that we actually have a tracking area in place.
-TEST_F(FramedBrowserWindowTest, WindowWidgetTrackingArea) {
- NSCell* closeBoxCell =
- [window_ accessibilityAttributeValue:NSAccessibilityCloseButtonAttribute];
- NSView* closeBoxControl = [closeBoxCell controlView];
- NSView* frameView = [[window_ contentView] superview];
- NSArray* trackingAreas = [frameView trackingAreas];
- NSPoint point = [closeBoxControl frame].origin;
- point.x += 1;
- point.y += 1;
- BOOL foundArea = NO;
- for (NSTrackingArea* area in trackingAreas) {
- NSRect rect = [area rect];
- foundArea = NSPointInRect(point, rect);
- if (foundArea) {
- EXPECT_NSEQ(frameView, [area owner]);
- break;
- }
- }
- EXPECT_TRUE(foundArea);
-}
-
diff --git a/chrome/browser/cocoa/fullscreen_controller.h b/chrome/browser/cocoa/fullscreen_controller.h
deleted file mode 100644
index f213fa3..0000000
--- a/chrome/browser/cocoa/fullscreen_controller.h
+++ /dev/null
@@ -1,122 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_FULLSCREEN_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_FULLSCREEN_CONTROLLER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/cocoa_protocols_mac.h"
-#include "base/mac_util.h"
-#include "chrome/browser/cocoa/location_bar/location_bar_view_mac.h"
-
-@class BrowserWindowController;
-@class DropdownAnimation;
-
-// Provides a controller to manage fullscreen mode for a single browser window.
-// This class handles running animations, showing and hiding the floating
-// dropdown bar, and managing the tracking area associated with the dropdown.
-// This class does not directly manage any views -- the BrowserWindowController
-// is responsible for positioning and z-ordering views.
-//
-// Tracking areas are disabled while animations are running. If
-// |overlayFrameChanged:| is called while an animation is running, the
-// controller saves the new frame and installs the appropriate tracking area
-// when the animation finishes. This is largely done for ease of
-// implementation; it is easier to check the mouse location at each animation
-// step than it is to manage a constantly-changing tracking area.
-@interface FullscreenController : NSObject<NSAnimationDelegate> {
- @private
- // Our parent controller.
- BrowserWindowController* browserController_; // weak
-
- // The content view for the fullscreen window. This is nil when not in
- // fullscreen mode.
- NSView* contentView_; // weak
-
- // Whether or not we are in fullscreen mode.
- BOOL isFullscreen_;
-
- // The tracking area associated with the floating dropdown bar. This tracking
- // area is attached to |contentView_|, because when the dropdown is completely
- // hidden, we still need to keep a 1px tall tracking area visible. Attaching
- // to the content view allows us to do this. |trackingArea_| can be nil if
- // not in fullscreen mode or during animations.
- scoped_nsobject<NSTrackingArea> trackingArea_;
-
- // Pointer to the currently running animation. Is nil if no animation is
- // running.
- scoped_nsobject<DropdownAnimation> currentAnimation_;
-
- // Timers for scheduled showing/hiding of the bar (which are always done with
- // animation).
- scoped_nsobject<NSTimer> showTimer_;
- scoped_nsobject<NSTimer> hideTimer_;
-
- // Holds the current bounds of |trackingArea_|, even if |trackingArea_| is
- // currently nil. Used to restore the tracking area when an animation
- // completes.
- NSRect trackingAreaBounds_;
-
- // Tracks the currently requested fullscreen mode. This should be
- // |kFullScreenModeNormal| when the window is not main or not fullscreen,
- // |kFullScreenModeHideAll| while the overlay is hidden, and
- // |kFullScreenModeHideDock| while the overlay is shown. If the window is not
- // on the primary screen, this should always be |kFullScreenModeNormal|. This
- // value can get out of sync with the correct state if we miss a notification
- // (which can happen when a fullscreen window is closed). Used to track the
- // current state and make sure we properly restore the menu bar when this
- // controller is destroyed.
- mac_util::FullScreenMode currentFullscreenMode_;
-}
-
-@property(readonly, nonatomic) BOOL isFullscreen;
-
-// Designated initializer.
-- (id)initWithBrowserController:(BrowserWindowController*)controller;
-
-// Informs the controller that the browser has entered or exited fullscreen
-// mode. |-enterFullscreenForContentView:showDropdown:| should be called after
-// the fullscreen window is setup, just before it is shown. |-exitFullscreen|
-// should be called before any views are moved back to the non-fullscreen
-// window. If |-enterFullscreenForContentView:showDropdown:| is called, it must
-// be followed with a call to |-exitFullscreen| before the controller is
-// released.
-- (void)enterFullscreenForContentView:(NSView*)contentView
- showDropdown:(BOOL)showDropdown;
-- (void)exitFullscreen;
-
-// Returns the amount by which the floating bar should be offset downwards (to
-// avoid the menu) and by which the overlay view should be enlarged vertically.
-// Generally, this is > 0 when the fullscreen window is on the primary screen
-// and 0 otherwise.
-- (CGFloat)floatingBarVerticalOffset;
-
-// Informs the controller that the overlay's frame has changed. The controller
-// uses this information to update its tracking areas.
-- (void)overlayFrameChanged:(NSRect)frame;
-
-// Informs the controller that the overlay should be shown/hidden, possibly with
-// animation, possibly after a delay (only applicable for the animated case).
-- (void)ensureOverlayShownWithAnimation:(BOOL)animate delay:(BOOL)delay;
-- (void)ensureOverlayHiddenWithAnimation:(BOOL)animate delay:(BOOL)delay;
-
-// Cancels any running animation and timers.
-- (void)cancelAnimationAndTimers;
-
-// Gets the current floating bar shown fraction.
-- (CGFloat)floatingBarShownFraction;
-
-// Sets a new current floating bar shown fraction. NOTE: This function has side
-// effects, such as modifying the fullscreen mode (menu bar shown state).
-- (void)changeFloatingBarShownFraction:(CGFloat)fraction;
-
-@end
-
-// Notification posted when we're about to enter or leave fullscreen.
-extern NSString* const kWillEnterFullscreenNotification;
-extern NSString* const kWillLeaveFullscreenNotification;
-
-#endif // CHROME_BROWSER_COCOA_FULLSCREEN_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/fullscreen_controller.mm b/chrome/browser/cocoa/fullscreen_controller.mm
deleted file mode 100644
index d0604f3..0000000
--- a/chrome/browser/cocoa/fullscreen_controller.mm
+++ /dev/null
@@ -1,633 +0,0 @@
-// 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 "chrome/browser/cocoa/fullscreen_controller.h"
-
-#include <algorithm>
-
-#import "chrome/browser/cocoa/browser_window_controller.h"
-#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
-
-NSString* const kWillEnterFullscreenNotification =
- @"WillEnterFullscreenNotification";
-NSString* const kWillLeaveFullscreenNotification =
- @"WillLeaveFullscreenNotification";
-
-namespace {
-// The activation zone for the main menu is 4 pixels high; if we make it any
-// smaller, then the menu can be made to appear without the bar sliding down.
-const CGFloat kDropdownActivationZoneHeight = 4;
-const NSTimeInterval kDropdownAnimationDuration = 0.12;
-const NSTimeInterval kMouseExitCheckDelay = 0.1;
-// This show delay attempts to match the delay for the main menu.
-const NSTimeInterval kDropdownShowDelay = 0.3;
-const NSTimeInterval kDropdownHideDelay = 0.2;
-
-// The amount by which the floating bar is offset downwards (to avoid the menu)
-// in fullscreen mode. (We can't use |-[NSMenu menuBarHeight]| since it returns
-// 0 when the menu bar is hidden.)
-const CGFloat kFloatingBarVerticalOffset = 22;
-
-} // end namespace
-
-
-// Helper class to manage animations for the fullscreen dropdown bar. Calls
-// [FullscreenController changeFloatingBarShownFraction] once per animation
-// step.
-@interface DropdownAnimation : NSAnimation {
- @private
- FullscreenController* controller_;
- CGFloat startFraction_;
- CGFloat endFraction_;
-}
-
-@property(readonly, nonatomic) CGFloat startFraction;
-@property(readonly, nonatomic) CGFloat endFraction;
-
-// Designated initializer. Asks |controller| for the current shown fraction, so
-// if the bar is already partially shown or partially hidden, the animation
-// duration may be less than |fullDuration|.
-- (id)initWithFraction:(CGFloat)fromFraction
- fullDuration:(CGFloat)fullDuration
- animationCurve:(NSInteger)animationCurve
- controller:(FullscreenController*)controller;
-
-@end
-
-@implementation DropdownAnimation
-
-@synthesize startFraction = startFraction_;
-@synthesize endFraction = endFraction_;
-
-- (id)initWithFraction:(CGFloat)toFraction
- fullDuration:(CGFloat)fullDuration
- animationCurve:(NSInteger)animationCurve
- controller:(FullscreenController*)controller {
- // Calculate the effective duration, based on the current shown fraction.
- DCHECK(controller);
- CGFloat fromFraction = [controller floatingBarShownFraction];
- CGFloat effectiveDuration = fabs(fullDuration * (fromFraction - toFraction));
-
- if ((self = [super gtm_initWithDuration:effectiveDuration
- eventMask:NSLeftMouseDownMask
- animationCurve:animationCurve])) {
- startFraction_ = fromFraction;
- endFraction_ = toFraction;
- controller_ = controller;
- }
- return self;
-}
-
-// Called once per animation step. Overridden to change the floating bar's
-// position based on the animation's progress.
-- (void)setCurrentProgress:(NSAnimationProgress)progress {
- CGFloat fraction =
- startFraction_ + (progress * (endFraction_ - startFraction_));
- [controller_ changeFloatingBarShownFraction:fraction];
-}
-
-@end
-
-
-@interface FullscreenController (PrivateMethods)
-
-// Returns YES if the fullscreen window is on the primary screen.
-- (BOOL)isWindowOnPrimaryScreen;
-
-// Returns YES if it is ok to show and hide the menu bar in response to the
-// overlay opening and closing. Will return NO if the window is not main or not
-// on the primary monitor.
-- (BOOL)shouldToggleMenuBar;
-
-// Returns |kFullScreenModeHideAll| when the overlay is hidden and
-// |kFullScreenModeHideDock| when the overlay is shown.
-- (mac_util::FullScreenMode)desiredFullscreenMode;
-
-// Change the overlay to the given fraction, with or without animation. Only
-// guaranteed to work properly with |fraction == 0| or |fraction == 1|. This
-// performs the show/hide (animation) immediately. It does not touch the timers.
-- (void)changeOverlayToFraction:(CGFloat)fraction
- withAnimation:(BOOL)animate;
-
-// Schedule the floating bar to be shown/hidden because of mouse position.
-- (void)scheduleShowForMouse;
-- (void)scheduleHideForMouse;
-
-// Set up the tracking area used to activate the sliding bar or keep it active
-// using with the rectangle in |trackingAreaBounds_|, or remove the tracking
-// area if one was previously set up.
-- (void)setupTrackingArea;
-- (void)removeTrackingAreaIfNecessary;
-
-// Returns YES if the mouse is currently in any current tracking rectangle, NO
-// otherwise.
-- (BOOL)mouseInsideTrackingRect;
-
-// The tracking area can "falsely" report exits when the menu slides down over
-// it. In that case, we have to monitor for a "real" mouse exit on a timer.
-// |-setupMouseExitCheck| schedules a check; |-cancelMouseExitCheck| cancels any
-// scheduled check.
-- (void)setupMouseExitCheck;
-- (void)cancelMouseExitCheck;
-
-// Called (after a delay) by |-setupMouseExitCheck|, to check whether the mouse
-// has exited or not; if it hasn't, it will schedule another check.
-- (void)checkForMouseExit;
-
-// Start timers for showing/hiding the floating bar.
-- (void)startShowTimer;
-- (void)startHideTimer;
-- (void)cancelShowTimer;
-- (void)cancelHideTimer;
-- (void)cancelAllTimers;
-
-// Methods called when the show/hide timers fire. Do not call directly.
-- (void)showTimerFire:(NSTimer*)timer;
-- (void)hideTimerFire:(NSTimer*)timer;
-
-// Stops any running animations, removes tracking areas, etc.
-- (void)cleanup;
-
-// Shows and hides the UI associated with this window being active (having main
-// status). This includes hiding the menu bar and displaying the "Exit
-// Fullscreen" button. These functions are called when the window gains or
-// loses main status as well as in |-cleanup|.
-- (void)showActiveWindowUI;
-- (void)hideActiveWindowUI;
-
-@end
-
-
-@implementation FullscreenController
-
-@synthesize isFullscreen = isFullscreen_;
-
-- (id)initWithBrowserController:(BrowserWindowController*)controller {
- if ((self == [super init])) {
- browserController_ = controller;
- currentFullscreenMode_ = mac_util::kFullScreenModeNormal;
- }
-
- // Let the world know what we're up to.
- [[NSNotificationCenter defaultCenter]
- postNotificationName:kWillEnterFullscreenNotification
- object:nil];
-
- return self;
-}
-
-- (void)dealloc {
- DCHECK(!isFullscreen_);
- DCHECK(!trackingArea_);
- [super dealloc];
-}
-
-- (void)enterFullscreenForContentView:(NSView*)contentView
- showDropdown:(BOOL)showDropdown {
- DCHECK(!isFullscreen_);
- isFullscreen_ = YES;
- contentView_ = contentView;
- [self changeFloatingBarShownFraction:(showDropdown ? 1 : 0)];
-
- // Register for notifications. Self is removed as an observer in |-cleanup|.
- NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
- NSWindow* window = [browserController_ window];
- [nc addObserver:self
- selector:@selector(windowDidChangeScreen:)
- name:NSWindowDidChangeScreenNotification
- object:window];
-
- [nc addObserver:self
- selector:@selector(windowDidMove:)
- name:NSWindowDidMoveNotification
- object:window];
-
- [nc addObserver:self
- selector:@selector(windowDidBecomeMain:)
- name:NSWindowDidBecomeMainNotification
- object:window];
-
- [nc addObserver:self
- selector:@selector(windowDidResignMain:)
- name:NSWindowDidResignMainNotification
- object:window];
-}
-
-- (void)exitFullscreen {
- [[NSNotificationCenter defaultCenter]
- postNotificationName:kWillLeaveFullscreenNotification
- object:nil];
- DCHECK(isFullscreen_);
- [self cleanup];
- isFullscreen_ = NO;
-}
-
-- (void)windowDidChangeScreen:(NSNotification*)notification {
- [browserController_ resizeFullscreenWindow];
-}
-
-- (void)windowDidMove:(NSNotification*)notification {
- [browserController_ resizeFullscreenWindow];
-}
-
-- (void)windowDidBecomeMain:(NSNotification*)notification {
- [self showActiveWindowUI];
-}
-
-- (void)windowDidResignMain:(NSNotification*)notification {
- [self hideActiveWindowUI];
-}
-
-- (CGFloat)floatingBarVerticalOffset {
- return [self isWindowOnPrimaryScreen] ? kFloatingBarVerticalOffset : 0;
-}
-
-- (void)overlayFrameChanged:(NSRect)frame {
- if (!isFullscreen_)
- return;
-
- // Make sure |trackingAreaBounds_| always reflects either the tracking area or
- // the desired tracking area.
- trackingAreaBounds_ = frame;
- // The tracking area should always be at least the height of activation zone.
- NSRect contentBounds = [contentView_ bounds];
- trackingAreaBounds_.origin.y =
- std::min(trackingAreaBounds_.origin.y,
- NSMaxY(contentBounds) - kDropdownActivationZoneHeight);
- trackingAreaBounds_.size.height =
- NSMaxY(contentBounds) - trackingAreaBounds_.origin.y + 1;
-
- // If an animation is currently running, do not set up a tracking area now.
- // Instead, leave it to be created it in |-animationDidEnd:|.
- if (currentAnimation_)
- return;
-
- [self setupTrackingArea];
-}
-
-- (void)ensureOverlayShownWithAnimation:(BOOL)animate delay:(BOOL)delay {
- if (!isFullscreen_)
- return;
-
- if (animate) {
- if (delay) {
- [self startShowTimer];
- } else {
- [self cancelAllTimers];
- [self changeOverlayToFraction:1 withAnimation:YES];
- }
- } else {
- DCHECK(!delay);
- [self cancelAllTimers];
- [self changeOverlayToFraction:1 withAnimation:NO];
- }
-}
-
-- (void)ensureOverlayHiddenWithAnimation:(BOOL)animate delay:(BOOL)delay {
- if (!isFullscreen_)
- return;
-
- if (animate) {
- if (delay) {
- [self startHideTimer];
- } else {
- [self cancelAllTimers];
- [self changeOverlayToFraction:0 withAnimation:YES];
- }
- } else {
- DCHECK(!delay);
- [self cancelAllTimers];
- [self changeOverlayToFraction:0 withAnimation:NO];
- }
-}
-
-- (void)cancelAnimationAndTimers {
- [self cancelAllTimers];
- [currentAnimation_ stopAnimation];
- currentAnimation_.reset();
-}
-
-- (CGFloat)floatingBarShownFraction {
- return [browserController_ floatingBarShownFraction];
-}
-
-- (void)changeFloatingBarShownFraction:(CGFloat)fraction {
- [browserController_ setFloatingBarShownFraction:fraction];
-
- mac_util::FullScreenMode desiredMode = [self desiredFullscreenMode];
- if (desiredMode != currentFullscreenMode_ && [self shouldToggleMenuBar]) {
- if (currentFullscreenMode_ == mac_util::kFullScreenModeNormal)
- mac_util::RequestFullScreen(desiredMode);
- else
- mac_util::SwitchFullScreenModes(currentFullscreenMode_, desiredMode);
- currentFullscreenMode_ = desiredMode;
- }
-}
-
-// Used to activate the floating bar in fullscreen mode.
-- (void)mouseEntered:(NSEvent*)event {
- DCHECK(isFullscreen_);
-
- // Having gotten a mouse entered, we no longer need to do exit checks.
- [self cancelMouseExitCheck];
-
- NSTrackingArea* trackingArea = [event trackingArea];
- if (trackingArea == trackingArea_) {
- // The tracking area shouldn't be active during animation.
- DCHECK(!currentAnimation_);
- [self scheduleShowForMouse];
- }
-}
-
-// Used to deactivate the floating bar in fullscreen mode.
-- (void)mouseExited:(NSEvent*)event {
- DCHECK(isFullscreen_);
-
- NSTrackingArea* trackingArea = [event trackingArea];
- if (trackingArea == trackingArea_) {
- // The tracking area shouldn't be active during animation.
- DCHECK(!currentAnimation_);
-
- // We can get a false mouse exit when the menu slides down, so if the mouse
- // is still actually over the tracking area, we ignore the mouse exit, but
- // we set up to check the mouse position again after a delay.
- if ([self mouseInsideTrackingRect]) {
- [self setupMouseExitCheck];
- return;
- }
-
- [self scheduleHideForMouse];
- }
-}
-
-- (void)animationDidStop:(NSAnimation*)animation {
- // Reset the |currentAnimation_| pointer now that the animation is over.
- currentAnimation_.reset();
-
- // Invariant says that the tracking area is not installed while animations are
- // in progress. Ensure this is true.
- DCHECK(!trackingArea_);
- [self removeTrackingAreaIfNecessary]; // For paranoia.
-
- // Don't automatically set up a new tracking area. When explicitly stopped,
- // either another animation is going to start immediately or the state will be
- // changed immediately.
-}
-
-- (void)animationDidEnd:(NSAnimation*)animation {
- [self animationDidStop:animation];
-
- // |trackingAreaBounds_| contains the correct tracking area bounds, including
- // |any updates that may have come while the animation was running. Install a
- // new tracking area with these bounds.
- [self setupTrackingArea];
-
- // TODO(viettrungluu): Better would be to check during the animation; doing it
- // here means that the timing is slightly off.
- if (![self mouseInsideTrackingRect])
- [self scheduleHideForMouse];
-}
-
-@end
-
-
-@implementation FullscreenController (PrivateMethods)
-
-- (BOOL)isWindowOnPrimaryScreen {
- NSScreen* screen = [[browserController_ window] screen];
- NSScreen* primaryScreen = [[NSScreen screens] objectAtIndex:0];
- return (screen == primaryScreen);
-}
-
-- (BOOL)shouldToggleMenuBar {
- return [self isWindowOnPrimaryScreen] &&
- [[browserController_ window] isMainWindow];
-}
-
-- (mac_util::FullScreenMode)desiredFullscreenMode {
- if ([browserController_ floatingBarShownFraction] >= 1.0)
- return mac_util::kFullScreenModeHideDock;
- return mac_util::kFullScreenModeHideAll;
-}
-
-- (void)changeOverlayToFraction:(CGFloat)fraction
- withAnimation:(BOOL)animate {
- // The non-animated case is really simple, so do it and return.
- if (!animate) {
- [currentAnimation_ stopAnimation];
- [self changeFloatingBarShownFraction:fraction];
- return;
- }
-
- // If we're already animating to the given fraction, then there's nothing more
- // to do.
- if (currentAnimation_ && [currentAnimation_ endFraction] == fraction)
- return;
-
- // In all other cases, we want to cancel any running animation (which may be
- // to show or to hide).
- [currentAnimation_ stopAnimation];
-
- // Now, if it happens to already be in the right state, there's nothing more
- // to do.
- if ([browserController_ floatingBarShownFraction] == fraction)
- return;
-
- // Create the animation and set it up.
- currentAnimation_.reset(
- [[DropdownAnimation alloc] initWithFraction:fraction
- fullDuration:kDropdownAnimationDuration
- animationCurve:NSAnimationEaseOut
- controller:self]);
- DCHECK(currentAnimation_);
- [currentAnimation_ setAnimationBlockingMode:NSAnimationNonblocking];
- [currentAnimation_ setDelegate:self];
-
- // If there is an existing tracking area, remove it. We do not track mouse
- // movements during animations (see class comment in the header file).
- [self removeTrackingAreaIfNecessary];
-
- [currentAnimation_ startAnimation];
-}
-
-- (void)scheduleShowForMouse {
- [browserController_ lockBarVisibilityForOwner:self
- withAnimation:YES
- delay:YES];
-}
-
-- (void)scheduleHideForMouse {
- [browserController_ releaseBarVisibilityForOwner:self
- withAnimation:YES
- delay:YES];
-}
-
-- (void)setupTrackingArea {
- if (trackingArea_) {
- // If the tracking rectangle is already |trackingAreaBounds_|, quit early.
- NSRect oldRect = [trackingArea_ rect];
- if (NSEqualRects(trackingAreaBounds_, oldRect))
- return;
-
- // Otherwise, remove it.
- [self removeTrackingAreaIfNecessary];
- }
-
- // Create and add a new tracking area for |frame|.
- trackingArea_.reset(
- [[NSTrackingArea alloc] initWithRect:trackingAreaBounds_
- options:NSTrackingMouseEnteredAndExited |
- NSTrackingActiveInKeyWindow
- owner:self
- userInfo:nil]);
- DCHECK(contentView_);
- [contentView_ addTrackingArea:trackingArea_];
-}
-
-- (void)removeTrackingAreaIfNecessary {
- if (trackingArea_) {
- DCHECK(contentView_); // |contentView_| better be valid.
- [contentView_ removeTrackingArea:trackingArea_];
- trackingArea_.reset();
- }
-}
-
-- (BOOL)mouseInsideTrackingRect {
- NSWindow* window = [browserController_ window];
- NSPoint mouseLoc = [window mouseLocationOutsideOfEventStream];
- NSPoint mousePos = [contentView_ convertPoint:mouseLoc fromView:nil];
- return NSMouseInRect(mousePos, trackingAreaBounds_, [contentView_ isFlipped]);
-}
-
-- (void)setupMouseExitCheck {
- [self performSelector:@selector(checkForMouseExit)
- withObject:nil
- afterDelay:kMouseExitCheckDelay];
-}
-
-- (void)cancelMouseExitCheck {
- [NSObject cancelPreviousPerformRequestsWithTarget:self
- selector:@selector(checkForMouseExit) object:nil];
-}
-
-- (void)checkForMouseExit {
- if ([self mouseInsideTrackingRect])
- [self setupMouseExitCheck];
- else
- [self scheduleHideForMouse];
-}
-
-- (void)startShowTimer {
- // If there's already a show timer going, just keep it.
- if (showTimer_) {
- DCHECK([showTimer_ isValid]);
- DCHECK(!hideTimer_);
- return;
- }
-
- // Cancel the hide timer (if necessary) and set up the new show timer.
- [self cancelHideTimer];
- showTimer_.reset(
- [[NSTimer scheduledTimerWithTimeInterval:kDropdownShowDelay
- target:self
- selector:@selector(showTimerFire:)
- userInfo:nil
- repeats:NO] retain]);
- DCHECK([showTimer_ isValid]); // This also checks that |showTimer_ != nil|.
-}
-
-- (void)startHideTimer {
- // If there's already a hide timer going, just keep it.
- if (hideTimer_) {
- DCHECK([hideTimer_ isValid]);
- DCHECK(!showTimer_);
- return;
- }
-
- // Cancel the show timer (if necessary) and set up the new hide timer.
- [self cancelShowTimer];
- hideTimer_.reset(
- [[NSTimer scheduledTimerWithTimeInterval:kDropdownHideDelay
- target:self
- selector:@selector(hideTimerFire:)
- userInfo:nil
- repeats:NO] retain]);
- DCHECK([hideTimer_ isValid]); // This also checks that |hideTimer_ != nil|.
-}
-
-- (void)cancelShowTimer {
- [showTimer_ invalidate];
- showTimer_.reset();
-}
-
-- (void)cancelHideTimer {
- [hideTimer_ invalidate];
- hideTimer_.reset();
-}
-
-- (void)cancelAllTimers {
- [self cancelShowTimer];
- [self cancelHideTimer];
-}
-
-- (void)showTimerFire:(NSTimer*)timer {
- DCHECK_EQ(showTimer_, timer); // This better be our show timer.
- [showTimer_ invalidate]; // Make sure it doesn't repeat.
- showTimer_.reset(); // And get rid of it.
- [self changeOverlayToFraction:1 withAnimation:YES];
-}
-
-- (void)hideTimerFire:(NSTimer*)timer {
- DCHECK_EQ(hideTimer_, timer); // This better be our hide timer.
- [hideTimer_ invalidate]; // Make sure it doesn't repeat.
- hideTimer_.reset(); // And get rid of it.
- [self changeOverlayToFraction:0 withAnimation:YES];
-}
-
-- (void)cleanup {
- [self cancelMouseExitCheck];
- [self cancelAnimationAndTimers];
- [[NSNotificationCenter defaultCenter] removeObserver:self];
-
- [self removeTrackingAreaIfNecessary];
- contentView_ = nil;
-
- // This isn't tracked when not in fullscreen mode.
- [browserController_ releaseBarVisibilityForOwner:self
- withAnimation:NO
- delay:NO];
-
- // Call the main status resignation code to perform the associated cleanup,
- // since we will no longer be receiving actual status resignation
- // notifications.
- [self hideActiveWindowUI];
-
- // No more calls back up to the BWC.
- browserController_ = nil;
-}
-
-- (void)showActiveWindowUI {
- DCHECK_EQ(currentFullscreenMode_, mac_util::kFullScreenModeNormal);
- if (currentFullscreenMode_ != mac_util::kFullScreenModeNormal)
- return;
-
- if ([self shouldToggleMenuBar]) {
- mac_util::FullScreenMode desiredMode = [self desiredFullscreenMode];
- mac_util::RequestFullScreen(desiredMode);
- currentFullscreenMode_ = desiredMode;
- }
-
- // TODO(rohitrao): Insert the Exit Fullscreen button. http://crbug.com/35956
-}
-
-- (void)hideActiveWindowUI {
- if (currentFullscreenMode_ != mac_util::kFullScreenModeNormal) {
- mac_util::ReleaseFullScreen(currentFullscreenMode_);
- currentFullscreenMode_ = mac_util::kFullScreenModeNormal;
- }
-
- // TODO(rohitrao): Remove the Exit Fullscreen button. http://crbug.com/35956
-}
-
-@end
diff --git a/chrome/browser/cocoa/fullscreen_window.h b/chrome/browser/cocoa/fullscreen_window.h
deleted file mode 100644
index ba01abf..0000000
--- a/chrome/browser/cocoa/fullscreen_window.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// 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.
-
-#include <Cocoa/Cocoa.h>
-#import "chrome/browser/cocoa/chrome_browser_window.h"
-
-// A FullscreenWindow is a borderless window suitable for going fullscreen. The
-// returned window is NOT release when closed and is not initially visible.
-// FullscreenWindow derives from ChromeBrowserWindow to inherit hole punching,
-// theming methods, and special event handling
-// (e.g. handleExtraKeyboardShortcut).
-@interface FullscreenWindow : ChromeBrowserWindow
-
-// Initialize a FullscreenWindow for the given screen.
-// Designated initializer.
-- (id)initForScreen:(NSScreen*)screen;
-
-@end
diff --git a/chrome/browser/cocoa/fullscreen_window.mm b/chrome/browser/cocoa/fullscreen_window.mm
deleted file mode 100644
index 47582b2..0000000
--- a/chrome/browser/cocoa/fullscreen_window.mm
+++ /dev/null
@@ -1,100 +0,0 @@
-// 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 "chrome/browser/cocoa/fullscreen_window.h"
-
-#include "base/mac_util.h"
-#import "chrome/browser/cocoa/themed_window.h"
-#include "chrome/browser/themes/browser_theme_provider.h"
-
-@implementation FullscreenWindow
-
-// Make sure our designated initializer gets called.
-- (id)init {
- return [self initForScreen:[NSScreen mainScreen]];
-}
-
-- (id)initForScreen:(NSScreen*)screen {
- NSRect contentRect;
- contentRect.origin = NSZeroPoint;
- contentRect.size = [screen frame].size;
-
- if ((self = [super initWithContentRect:contentRect
- styleMask:NSBorderlessWindowMask
- backing:NSBackingStoreBuffered
- defer:YES
- screen:screen])) {
- [self setReleasedWhenClosed:NO];
- // Borderless windows don't usually show up in the Windows menu so whine at
- // Cocoa until it complies. See -dealloc and -setTitle: as well.
- [NSApp addWindowsItem:self title:@"" filename:NO];
- }
- return self;
-}
-
-- (void)dealloc {
- // Paranoia; doesn't seem to be necessary but it doesn't hurt.
- [NSApp removeWindowsItem:self];
-
- [super dealloc];
-}
-
-- (void)setTitle:(NSString *)title {
- [NSApp changeWindowsItem:self title:title filename:NO];
- [super setTitle:title];
-}
-
-// According to
-// http://www.cocoabuilder.com/archive/message/cocoa/2006/6/19/165953 ,
-// NSBorderlessWindowMask windows cannot become key or main.
-// In our case, however, we don't want that behavior, so we override
-// canBecomeKeyWindow and canBecomeMainWindow.
-
-- (BOOL)canBecomeKeyWindow {
- return YES;
-}
-
-- (BOOL)canBecomeMainWindow {
- return YES;
-}
-
-// When becoming/resigning main status, explicitly set the background color,
-// which is required by |TabView|.
-- (void)becomeMainWindow {
- [super becomeMainWindow];
- [self setBackgroundColor:[NSColor windowFrameColor]];
-}
-
-- (void)resignMainWindow {
- [super resignMainWindow];
- [self setBackgroundColor:[NSColor windowBackgroundColor]];
-}
-
-// We need our own version, since the default one wants to flash the close
-// button (and possibly other things), which results in nothing happening.
-- (void)performClose:(id)sender {
- BOOL shouldClose = YES;
-
- // If applicable, check if this window should close.
- id delegate = [self delegate];
- if ([delegate respondsToSelector:@selector(windowShouldClose:)])
- shouldClose = [delegate windowShouldClose:self];
-
- if (shouldClose) {
- [self close];
- }
-}
-
-- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
- SEL action = [item action];
-
- // Explicitly enable |-performClose:| (see above); otherwise the fact that
- // this window does not have a close button results in it being disabled.
- if (action == @selector(performClose:))
- return YES;
-
- return [super validateUserInterfaceItem:item];
-}
-
-@end
diff --git a/chrome/browser/cocoa/fullscreen_window_unittest.mm b/chrome/browser/cocoa/fullscreen_window_unittest.mm
deleted file mode 100644
index 5f6df44..0000000
--- a/chrome/browser/cocoa/fullscreen_window_unittest.mm
+++ /dev/null
@@ -1,47 +0,0 @@
-// 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.
-
-#include "base/scoped_ptr.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/cocoa/fullscreen_window.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-@interface PerformCloseUIItem : NSObject<NSValidatedUserInterfaceItem>
-@end
-
-@implementation PerformCloseUIItem
-- (SEL)action {
- return @selector(performClose:);
-}
-
-- (NSInteger)tag {
- return 0;
-}
-@end
-
-class FullscreenWindowTest : public CocoaTest {
-};
-
-TEST_F(FullscreenWindowTest, Basics) {
- scoped_nsobject<FullscreenWindow> window;
- window.reset([[FullscreenWindow alloc] init]);
-
- EXPECT_EQ([NSScreen mainScreen], [window screen]);
- EXPECT_TRUE([window canBecomeKeyWindow]);
- EXPECT_TRUE([window canBecomeMainWindow]);
- EXPECT_EQ(NSBorderlessWindowMask, [window styleMask]);
- EXPECT_TRUE(NSEqualRects([[NSScreen mainScreen] frame], [window frame]));
- EXPECT_FALSE([window isReleasedWhenClosed]);
-}
-
-TEST_F(FullscreenWindowTest, CanPerformClose) {
- scoped_nsobject<FullscreenWindow> window;
- window.reset([[FullscreenWindow alloc] init]);
-
- scoped_nsobject<PerformCloseUIItem> item;
- item.reset([[PerformCloseUIItem alloc] init]);
-
- EXPECT_TRUE([window validateUserInterfaceItem:item.get()]);
-}
diff --git a/chrome/browser/cocoa/gradient_button_cell.h b/chrome/browser/cocoa/gradient_button_cell.h
deleted file mode 100644
index 9280ce3..0000000
--- a/chrome/browser/cocoa/gradient_button_cell.h
+++ /dev/null
@@ -1,120 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_GRADIENT_BUTTON_CELL_H_
-#define CHROME_BROWSER_COCOA_GRADIENT_BUTTON_CELL_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_nsobject.h"
-
-class ThemeProvider;
-
-// Base class for button cells for toolbar and bookmark bar.
-//
-// This is a button cell that handles drawing/highlighting of buttons.
-// The appearance is determined by setting the cell's tag (not the
-// view's) to one of the constants below (ButtonType).
-
-// Set this as the cell's tag.
-enum {
- kLeftButtonType = -1,
- kLeftButtonWithShadowType = -2,
- kStandardButtonType = 0,
- kRightButtonType = 1,
- kMiddleButtonType = 2,
- // Draws like a standard button, except when clicked where the interior
- // doesn't darken using the theme's "pressed" gradient. Instead uses the
- // normal un-pressed gradient.
- kStandardButtonTypeWithLimitedClickFeedback = 3,
-};
-typedef NSInteger ButtonType;
-
-namespace gradient_button_cell {
-
-// Pulsing state for this button.
-typedef enum {
- // Stable states.
- kPulsedOn,
- kPulsedOff,
- // In motion which will end in a stable state.
- kPulsingOn,
- kPulsingOff,
- // In continuous motion.
- kPulsingContinuous,
-} PulseState;
-
-};
-
-
-@interface GradientButtonCell : NSButtonCell {
- @private
- // Custom drawing means we need to perform our own mouse tracking if
- // the cell is setShowsBorderOnlyWhileMouseInside:YES.
- BOOL isMouseInside_;
- scoped_nsobject<NSTrackingArea> trackingArea_;
- BOOL shouldTheme_;
- CGFloat hoverAlpha_; // 0-1. Controls the alpha during mouse hover
- NSTimeInterval lastHoverUpdate_;
- scoped_nsobject<NSGradient> gradient_;
- gradient_button_cell::PulseState pulseState_;
- CGFloat pulseMultiplier_; // for selecting pulse direction when continuous.
- CGFloat outerStrokeAlphaMult_; // For pulsing.
- scoped_nsobject<NSImage> overlayImage_;
-}
-
-// Turn off theming. Temporary work-around.
-- (void)setShouldTheme:(BOOL)shouldTheme;
-
-- (void)drawBorderAndFillForTheme:(ThemeProvider*)themeProvider
- controlView:(NSView*)controlView
- innerPath:(NSBezierPath*)innerPath
- showClickedGradient:(BOOL)showClickedGradient
- showHighlightGradient:(BOOL)showHighlightGradient
- hoverAlpha:(CGFloat)hoverAlpha
- active:(BOOL)active
- cellFrame:(NSRect)cellFrame
- defaultGradient:(NSGradient*)defaultGradient;
-
-// Let the view know when the mouse moves in and out. A timer will update
-// the current hoverAlpha_ based on these events.
-- (void)setMouseInside:(BOOL)flag animate:(BOOL)animate;
-
-// Gets the path which tightly bounds the outside of the button. This is needed
-// to produce images of clear buttons which only include the area inside, since
-// the background of the button is drawn by someone else.
-- (NSBezierPath*)clipPathForFrame:(NSRect)cellFrame
- inView:(NSView*)controlView;
-
-// Turn on or off continuous pulsing. When turning off continuous
-// pulsing, leave our pulse state in the correct ending position for
-// our isMouseInside_ property. Public since it's called from the
-// bookmark bubble.
-- (void)setIsContinuousPulsing:(BOOL)continuous;
-
-// Returns continuous pulse state.
-- (BOOL)isContinuousPulsing;
-
-// Safely stop continuous pulsing by turning off all timers.
-// May leave the cell in an odd state.
-// Needed by an owning control's dealloc routine.
-- (void)safelyStopPulsing;
-
-@property(assign, nonatomic) CGFloat hoverAlpha;
-
-// An image that will be drawn after the normal content of the button cell,
-// overlaying it. Never themed.
-@property(retain, nonatomic) NSImage* overlayImage;
-
-@end
-
-@interface GradientButtonCell(TestingAPI)
-- (BOOL)isMouseInside;
-- (BOOL)pulsing;
-- (gradient_button_cell::PulseState)pulseState;
-- (void)setPulseState:(gradient_button_cell::PulseState)pstate;
-@end
-
-#endif // CHROME_BROWSER_COCOA_GRADIENT_BUTTON_CELL_H_
diff --git a/chrome/browser/cocoa/gradient_button_cell.mm b/chrome/browser/cocoa/gradient_button_cell.mm
deleted file mode 100644
index 8b99fa5..0000000
--- a/chrome/browser/cocoa/gradient_button_cell.mm
+++ /dev/null
@@ -1,719 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/gradient_button_cell.h"
-
-#include "base/logging.h"
-#import "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/image_utils.h"
-#import "chrome/browser/cocoa/themed_window.h"
-#import "chrome/browser/themes/browser_theme_provider.h"
-#include "grit/theme_resources.h"
-#import "third_party/GTM/AppKit/GTMNSColor+Luminance.h"
-
-@interface GradientButtonCell (Private)
-- (void)sharedInit;
-
-// Get drawing parameters for a given cell frame in a given view. The inner
-// frame is the one required by |-drawInteriorWithFrame:inView:|. The inner and
-// outer paths are the ones required by |-drawBorderAndFillForTheme:...|. The
-// outer path also gives the area in which to clip. Any of the |return...|
-// arguments may be NULL (in which case the given parameter won't be returned).
-// If |returnInnerPath| or |returnOuterPath|, |*returnInnerPath| or
-// |*returnOuterPath| should be nil, respectively.
-- (void)getDrawParamsForFrame:(NSRect)cellFrame
- inView:(NSView*)controlView
- innerFrame:(NSRect*)returnInnerFrame
- innerPath:(NSBezierPath**)returnInnerPath
- clipPath:(NSBezierPath**)returnClipPath;
-
-
-@end
-
-
-static const NSTimeInterval kAnimationShowDuration = 0.2;
-
-// Note: due to a bug (?), drawWithFrame:inView: does not call
-// drawBorderAndFillForTheme::::: unless the mouse is inside. The net
-// effect is that our "fade out" when the mouse leaves becaumes
-// instantaneous. When I "fixed" it things looked horrible; the
-// hover-overed bookmark button would stay highlit for 0.4 seconds
-// which felt like latency/lag. I'm leaving the "bug" in place for
-// now so we don't suck. -jrg
-static const NSTimeInterval kAnimationHideDuration = 0.4;
-
-static const NSTimeInterval kAnimationContinuousCycleDuration = 0.4;
-
-@implementation GradientButtonCell
-
-@synthesize hoverAlpha = hoverAlpha_;
-
-// For nib instantiations
-- (id)initWithCoder:(NSCoder*)decoder {
- if ((self = [super initWithCoder:decoder])) {
- [self sharedInit];
- }
- return self;
-}
-
-// For programmatic instantiations
-- (id)initTextCell:(NSString*)string {
- if ((self = [super initTextCell:string])) {
- [self sharedInit];
- }
- return self;
-}
-
-- (void)dealloc {
- if (trackingArea_) {
- [[self controlView] removeTrackingArea:trackingArea_];
- trackingArea_.reset();
- }
- [super dealloc];
-}
-
-// Return YES if we are pulsing (towards another state or continuously).
-- (BOOL)pulsing {
- if ((pulseState_ == gradient_button_cell::kPulsingOn) ||
- (pulseState_ == gradient_button_cell::kPulsingOff) ||
- (pulseState_ == gradient_button_cell::kPulsingContinuous))
- return YES;
- return NO;
-}
-
-// Perform one pulse step when animating a pulse.
-- (void)performOnePulseStep {
- NSTimeInterval thisUpdate = [NSDate timeIntervalSinceReferenceDate];
- NSTimeInterval elapsed = thisUpdate - lastHoverUpdate_;
- CGFloat opacity = [self hoverAlpha];
-
- // Update opacity based on state.
- // Adjust state if we have finished.
- switch (pulseState_) {
- case gradient_button_cell::kPulsingOn:
- opacity += elapsed / kAnimationShowDuration;
- if (opacity > 1.0) {
- [self setPulseState:gradient_button_cell::kPulsedOn];
- return;
- }
- break;
- case gradient_button_cell::kPulsingOff:
- opacity -= elapsed / kAnimationHideDuration;
- if (opacity < 0.0) {
- [self setPulseState:gradient_button_cell::kPulsedOff];
- return;
- }
- break;
- case gradient_button_cell::kPulsingContinuous:
- opacity += elapsed / kAnimationContinuousCycleDuration * pulseMultiplier_;
- if (opacity > 1.0) {
- opacity = 1.0;
- pulseMultiplier_ *= -1.0;
- } else if (opacity < 0.0) {
- opacity = 0.0;
- pulseMultiplier_ *= -1.0;
- }
- outerStrokeAlphaMult_ = opacity;
- break;
- default:
- NOTREACHED() << "unknown pulse state";
- }
-
- // Update our control.
- lastHoverUpdate_ = thisUpdate;
- [self setHoverAlpha:opacity];
- [[self controlView] setNeedsDisplay:YES];
-
- // If our state needs it, keep going.
- if ([self pulsing]) {
- [self performSelector:_cmd withObject:nil afterDelay:0.02];
- }
-}
-
-- (gradient_button_cell::PulseState)pulseState {
- return pulseState_;
-}
-
-// Set the pulsing state. This can either set the pulse to on or off
-// immediately (e.g. kPulsedOn, kPulsedOff) or initiate an animated
-// state change.
-- (void)setPulseState:(gradient_button_cell::PulseState)pstate {
- pulseState_ = pstate;
- pulseMultiplier_ = 0.0;
- [NSObject cancelPreviousPerformRequestsWithTarget:self];
- lastHoverUpdate_ = [NSDate timeIntervalSinceReferenceDate];
-
- switch (pstate) {
- case gradient_button_cell::kPulsedOn:
- case gradient_button_cell::kPulsedOff:
- outerStrokeAlphaMult_ = 1.0;
- [self setHoverAlpha:((pulseState_ == gradient_button_cell::kPulsedOn) ?
- 1.0 : 0.0)];
- [[self controlView] setNeedsDisplay:YES];
- break;
- case gradient_button_cell::kPulsingOn:
- case gradient_button_cell::kPulsingOff:
- outerStrokeAlphaMult_ = 1.0;
- // Set initial value then engage timer.
- [self setHoverAlpha:((pulseState_ == gradient_button_cell::kPulsingOn) ?
- 0.0 : 1.0)];
- [self performOnePulseStep];
- break;
- case gradient_button_cell::kPulsingContinuous:
- // Semantics of continuous pulsing are that we pulse independent
- // of mouse position.
- pulseMultiplier_ = 1.0;
- [self performOnePulseStep];
- break;
- default:
- CHECK(0);
- break;
- }
-}
-
-- (void)safelyStopPulsing {
- [NSObject cancelPreviousPerformRequestsWithTarget:self];
-}
-
-- (void)setIsContinuousPulsing:(BOOL)continuous {
- if (!continuous && pulseState_ != gradient_button_cell::kPulsingContinuous)
- return;
- if (continuous) {
- [self setPulseState:gradient_button_cell::kPulsingContinuous];
- } else {
- [self setPulseState:(isMouseInside_ ? gradient_button_cell::kPulsedOn :
- gradient_button_cell::kPulsedOff)];
- }
-}
-
-- (BOOL)isContinuousPulsing {
- return (pulseState_ == gradient_button_cell::kPulsingContinuous) ?
- YES : NO;
-}
-
-#if 1
-// If we are not continuously pulsing, perform a pulse animation to
-// reflect our new state.
-- (void)setMouseInside:(BOOL)flag animate:(BOOL)animated {
- isMouseInside_ = flag;
- if (pulseState_ != gradient_button_cell::kPulsingContinuous) {
- if (animated) {
- [self setPulseState:(isMouseInside_ ? gradient_button_cell::kPulsingOn :
- gradient_button_cell::kPulsingOff)];
- } else {
- [self setPulseState:(isMouseInside_ ? gradient_button_cell::kPulsedOn :
- gradient_button_cell::kPulsedOff)];
- }
- }
-}
-#else
-
-- (void)adjustHoverValue {
- NSTimeInterval thisUpdate = [NSDate timeIntervalSinceReferenceDate];
-
- NSTimeInterval elapsed = thisUpdate - lastHoverUpdate_;
-
- CGFloat opacity = [self hoverAlpha];
- if (isMouseInside_) {
- opacity += elapsed / kAnimationShowDuration;
- } else {
- opacity -= elapsed / kAnimationHideDuration;
- }
-
- if (!isMouseInside_ && opacity < 0) {
- opacity = 0;
- } else if (isMouseInside_ && opacity > 1) {
- opacity = 1;
- } else {
- [self performSelector:_cmd withObject:nil afterDelay:0.02];
- }
- lastHoverUpdate_ = thisUpdate;
- [self setHoverAlpha:opacity];
-
- [[self controlView] setNeedsDisplay:YES];
-}
-
-- (void)setMouseInside:(BOOL)flag animate:(BOOL)animated {
- isMouseInside_ = flag;
- if (animated) {
- lastHoverUpdate_ = [NSDate timeIntervalSinceReferenceDate];
- [self adjustHoverValue];
- } else {
- [NSObject cancelPreviousPerformRequestsWithTarget:self];
- [self setHoverAlpha:flag ? 1.0 : 0.0];
- }
- [[self controlView] setNeedsDisplay:YES];
-}
-
-
-
-#endif
-
-- (NSGradient*)gradientForHoverAlpha:(CGFloat)hoverAlpha
- isThemed:(BOOL)themed {
- CGFloat startAlpha = 0.6 + 0.3 * hoverAlpha;
- CGFloat endAlpha = 0.333 * hoverAlpha;
-
- if (themed) {
- startAlpha = 0.2 + 0.35 * hoverAlpha;
- endAlpha = 0.333 * hoverAlpha;
- }
-
- NSColor* startColor =
- [NSColor colorWithCalibratedWhite:1.0
- alpha:startAlpha];
- NSColor* endColor =
- [NSColor colorWithCalibratedWhite:1.0 - 0.15 * hoverAlpha
- alpha:endAlpha];
- NSGradient* gradient = [[NSGradient alloc] initWithColorsAndLocations:
- startColor, hoverAlpha * 0.33,
- endColor, 1.0, nil];
-
- return [gradient autorelease];
-}
-
-- (void)sharedInit {
- shouldTheme_ = YES;
- pulseState_ = gradient_button_cell::kPulsedOff;
- pulseMultiplier_ = 1.0;
- outerStrokeAlphaMult_ = 1.0;
- gradient_.reset([[self gradientForHoverAlpha:0.0 isThemed:NO] retain]);
-}
-
-- (void)setShouldTheme:(BOOL)shouldTheme {
- shouldTheme_ = shouldTheme;
-}
-
-- (NSImage*)overlayImage {
- return overlayImage_.get();
-}
-
-- (void)setOverlayImage:(NSImage*)image {
- overlayImage_.reset([image retain]);
- [[self controlView] setNeedsDisplay:YES];
-}
-
-- (NSBackgroundStyle)interiorBackgroundStyle {
- // Never lower the interior, since that just leads to a weird shadow which can
- // often interact badly with the theme.
- return NSBackgroundStyleRaised;
-}
-
-- (void)mouseEntered:(NSEvent*)theEvent {
- [self setMouseInside:YES animate:YES];
-}
-
-- (void)mouseExited:(NSEvent*)theEvent {
- [self setMouseInside:NO animate:YES];
-}
-
-- (BOOL)isMouseInside {
- return trackingArea_ && isMouseInside_;
-}
-
-// Since we have our own drawWithFrame:, we need to also have our own
-// logic for determining when the mouse is inside for honoring this
-// request.
-- (void)setShowsBorderOnlyWhileMouseInside:(BOOL)showOnly {
- [super setShowsBorderOnlyWhileMouseInside:showOnly];
- if (showOnly) {
- if (trackingArea_.get()) {
- [self setShowsBorderOnlyWhileMouseInside:NO];
- [[self controlView] removeTrackingArea:trackingArea_];
- }
- trackingArea_.reset([[NSTrackingArea alloc]
- initWithRect:[[self controlView]
- bounds]
- options:(NSTrackingMouseEnteredAndExited |
- NSTrackingActiveInActiveApp)
- owner:self
- userInfo:nil]);
- [[self controlView] addTrackingArea:trackingArea_];
- } else {
- if (trackingArea_) {
- [[self controlView] removeTrackingArea:trackingArea_];
- trackingArea_.reset(nil);
- isMouseInside_ = NO;
- }
- }
-}
-
-// TODO(viettrungluu): clean up/reorganize.
-- (void)drawBorderAndFillForTheme:(ThemeProvider*)themeProvider
- controlView:(NSView*)controlView
- innerPath:(NSBezierPath*)innerPath
- showClickedGradient:(BOOL)showClickedGradient
- showHighlightGradient:(BOOL)showHighlightGradient
- hoverAlpha:(CGFloat)hoverAlpha
- active:(BOOL)active
- cellFrame:(NSRect)cellFrame
- defaultGradient:(NSGradient*)defaultGradient {
- BOOL isFlatButton = [self showsBorderOnlyWhileMouseInside];
-
- // For flat (unbordered when not hovered) buttons, never use the toolbar
- // button background image, but the modest gradient used for themed buttons.
- // To make things even more modest, scale the hover alpha down by 40 percent
- // unless clicked.
- NSColor* backgroundImageColor;
- BOOL useThemeGradient;
- if (isFlatButton) {
- backgroundImageColor = nil;
- useThemeGradient = YES;
- if (!showClickedGradient)
- hoverAlpha *= 0.6;
- } else {
- backgroundImageColor =
- themeProvider ?
- themeProvider->GetNSImageColorNamed(IDR_THEME_BUTTON_BACKGROUND,
- false) :
- nil;
- useThemeGradient = backgroundImageColor ? YES : NO;
- }
-
- // The basic gradient shown inside; see above.
- NSGradient* gradient;
- if (hoverAlpha == 0 && !useThemeGradient) {
- gradient = defaultGradient ? defaultGradient
- : gradient_;
- } else {
- gradient = [self gradientForHoverAlpha:hoverAlpha
- isThemed:useThemeGradient];
- }
-
- // If we're drawing a background image, show that; else possibly show the
- // clicked gradient.
- if (backgroundImageColor) {
- [backgroundImageColor set];
- // Set the phase to match window.
- NSRect trueRect = [controlView convertRect:cellFrame toView:nil];
- [[NSGraphicsContext currentContext]
- setPatternPhase:NSMakePoint(NSMinX(trueRect), NSMaxY(trueRect))];
- [innerPath fill];
- } else {
- if (showClickedGradient) {
- NSGradient* clickedGradient = nil;
- if (isFlatButton &&
- [self tag] == kStandardButtonTypeWithLimitedClickFeedback) {
- clickedGradient = gradient;
- } else {
- clickedGradient = themeProvider ? themeProvider->GetNSGradient(
- active ?
- BrowserThemeProvider::GRADIENT_TOOLBAR_BUTTON_PRESSED :
- BrowserThemeProvider::GRADIENT_TOOLBAR_BUTTON_PRESSED_INACTIVE) :
- nil;
- }
- [clickedGradient drawInBezierPath:innerPath angle:90.0];
- }
- }
-
- // Visually indicate unclicked, enabled buttons.
- if (!showClickedGradient && [self isEnabled]) {
- [NSGraphicsContext saveGraphicsState];
- [innerPath addClip];
-
- // Draw the inner glow.
- if (hoverAlpha > 0) {
- [innerPath setLineWidth:2];
- [[NSColor colorWithCalibratedWhite:1.0 alpha:0.2 * hoverAlpha] setStroke];
- [innerPath stroke];
- }
-
- // Draw the top inner highlight.
- NSAffineTransform* highlightTransform = [NSAffineTransform transform];
- [highlightTransform translateXBy:1 yBy:1];
- scoped_nsobject<NSBezierPath> highlightPath([innerPath copy]);
- [highlightPath transformUsingAffineTransform:highlightTransform];
- [[NSColor colorWithCalibratedWhite:1.0 alpha:0.2] setStroke];
- [highlightPath stroke];
-
- // Draw the gradient inside.
- [gradient drawInBezierPath:innerPath angle:90.0];
-
- [NSGraphicsContext restoreGraphicsState];
- }
-
- // Don't draw anything else for disabled flat buttons.
- if (isFlatButton && ![self isEnabled])
- return;
-
- // Draw the outer stroke.
- NSColor* strokeColor = nil;
- if (showClickedGradient) {
- strokeColor = [NSColor
- colorWithCalibratedWhite:0.0
- alpha:0.3 * outerStrokeAlphaMult_];
- } else {
- strokeColor = themeProvider ? themeProvider->GetNSColor(
- active ? BrowserThemeProvider::COLOR_TOOLBAR_BUTTON_STROKE :
- BrowserThemeProvider::COLOR_TOOLBAR_BUTTON_STROKE_INACTIVE,
- true) : [NSColor colorWithCalibratedWhite:0.0
- alpha:0.3 * outerStrokeAlphaMult_];
- }
- [strokeColor setStroke];
-
- [innerPath setLineWidth:1];
- [innerPath stroke];
-}
-
-// TODO(viettrungluu): clean this up.
-// (Private)
-- (void)getDrawParamsForFrame:(NSRect)cellFrame
- inView:(NSView*)controlView
- innerFrame:(NSRect*)returnInnerFrame
- innerPath:(NSBezierPath**)returnInnerPath
- clipPath:(NSBezierPath**)returnClipPath {
- // Constants from Cole. Will kConstant them once the feedback loop
- // is complete.
- NSRect drawFrame = NSInsetRect(cellFrame, 1.5, 1.5);
- NSRect innerFrame = NSInsetRect(cellFrame, 2, 1);
- const CGFloat radius = 3.5;
-
- ButtonType type = [[(NSControl*)controlView cell] tag];
- switch (type) {
- case kMiddleButtonType:
- drawFrame.size.width += 20;
- innerFrame.size.width += 2;
- // Fallthrough
- case kRightButtonType:
- drawFrame.origin.x -= 20;
- innerFrame.origin.x -= 2;
- // Fallthrough
- case kLeftButtonType:
- case kLeftButtonWithShadowType:
- drawFrame.size.width += 20;
- innerFrame.size.width += 2;
- default:
- break;
- }
- if (type == kLeftButtonWithShadowType)
- innerFrame.size.width -= 1.0;
-
- // Return results if |return...| not null.
- if (returnInnerFrame)
- *returnInnerFrame = innerFrame;
- if (returnInnerPath) {
- DCHECK(*returnInnerPath == nil);
- *returnInnerPath = [NSBezierPath bezierPathWithRoundedRect:drawFrame
- xRadius:radius
- yRadius:radius];
- }
- if (returnClipPath) {
- DCHECK(*returnClipPath == nil);
- NSRect clipPathRect = NSInsetRect(drawFrame, -0.5, -0.5);
- *returnClipPath = [NSBezierPath bezierPathWithRoundedRect:clipPathRect
- xRadius:radius + 0.5
- yRadius:radius + 0.5];
- }
-}
-
-// TODO(viettrungluu): clean this up.
-- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
- NSRect innerFrame;
- NSBezierPath* innerPath = nil;
- [self getDrawParamsForFrame:cellFrame
- inView:controlView
- innerFrame:&innerFrame
- innerPath:&innerPath
- clipPath:NULL];
-
- BOOL pressed = ([((NSControl*)[self controlView]) isEnabled] &&
- [self isHighlighted]);
- NSWindow* window = [controlView window];
- ThemeProvider* themeProvider = [window themeProvider];
- BOOL active = [window isKeyWindow] || [window isMainWindow];
-
- // Stroke the borders and appropriate fill gradient. If we're borderless, the
- // only time we want to draw the inner gradient is if we're highlighted or if
- // we're the first responder (when "Full Keyboard Access" is turned on).
- if (([self isBordered] && ![self showsBorderOnlyWhileMouseInside]) ||
- pressed ||
- [self isMouseInside] ||
- [self isContinuousPulsing] ||
- [self showsFirstResponder]) {
-
- // When pulsing we want the bookmark to stand out a little more.
- BOOL showClickedGradient = pressed ||
- (pulseState_ == gradient_button_cell::kPulsingContinuous);
-
- // When first responder, turn the hover alpha all the way up.
- CGFloat hoverAlpha = [self hoverAlpha];
- if ([self showsFirstResponder])
- hoverAlpha = 1.0;
-
- [self drawBorderAndFillForTheme:themeProvider
- controlView:controlView
- innerPath:innerPath
- showClickedGradient:showClickedGradient
- showHighlightGradient:[self isHighlighted]
- hoverAlpha:hoverAlpha
- active:active
- cellFrame:cellFrame
- defaultGradient:nil];
- }
-
- // If this is the left side of a segmented button, draw a slight shadow.
- ButtonType type = [[(NSControl*)controlView cell] tag];
- if (type == kLeftButtonWithShadowType) {
- NSRect borderRect, contentRect;
- NSDivideRect(cellFrame, &borderRect, &contentRect, 1.0, NSMaxXEdge);
- NSColor* stroke = themeProvider ? themeProvider->GetNSColor(
- active ? BrowserThemeProvider::COLOR_TOOLBAR_BUTTON_STROKE :
- BrowserThemeProvider::COLOR_TOOLBAR_BUTTON_STROKE_INACTIVE,
- true) : [NSColor blackColor];
-
- [[stroke colorWithAlphaComponent:0.2] set];
- NSRectFillUsingOperation(NSInsetRect(borderRect, 0, 2),
- NSCompositeSourceOver);
- }
- [self drawInteriorWithFrame:innerFrame inView:controlView];
-}
-
-- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
- if (shouldTheme_) {
- BOOL isTemplate = [[self image] isTemplate];
-
- [NSGraphicsContext saveGraphicsState];
-
- CGContextRef context =
- (CGContextRef)([[NSGraphicsContext currentContext] graphicsPort]);
-
- BrowserThemeProvider* themeProvider = static_cast<BrowserThemeProvider*>(
- [[controlView window] themeProvider]);
- NSColor* color = themeProvider ?
- themeProvider->GetNSColorTint(BrowserThemeProvider::TINT_BUTTONS,
- true) :
- [NSColor blackColor];
-
- if (isTemplate && themeProvider && themeProvider->UsingDefaultTheme()) {
- scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
- [shadow.get() setShadowColor:themeProvider->GetNSColor(
- BrowserThemeProvider::COLOR_TOOLBAR_BEZEL, true)];
- [shadow.get() setShadowOffset:NSMakeSize(0.0, -1.0)];
- [shadow setShadowBlurRadius:1.0];
- [shadow set];
- }
-
- CGContextBeginTransparencyLayer(context, 0);
- NSRect imageRect = NSZeroRect;
- imageRect.size = [[self image] size];
- NSRect drawRect = [self imageRectForBounds:cellFrame];
- [[self image] drawInRect:drawRect
- fromRect:imageRect
- operation:NSCompositeSourceOver
- fraction:[self isEnabled] ? 1.0 : 0.5
- neverFlipped:YES];
- if (isTemplate && color) {
- [color set];
- NSRectFillUsingOperation(cellFrame, NSCompositeSourceAtop);
- }
- CGContextEndTransparencyLayer(context);
-
- [NSGraphicsContext restoreGraphicsState];
- } else {
- // NSCell draws these off-center for some reason, probably because of the
- // positioning of the control in the xib.
- [super drawInteriorWithFrame:NSOffsetRect(cellFrame, 0, 1)
- inView:controlView];
- }
-
- if (overlayImage_) {
- NSRect imageRect = NSZeroRect;
- imageRect.size = [overlayImage_ size];
- [overlayImage_ drawInRect:[self imageRectForBounds:cellFrame]
- fromRect:imageRect
- operation:NSCompositeSourceOver
- fraction:[self isEnabled] ? 1.0 : 0.5
- neverFlipped:YES];
- }
-}
-
-// Overriden from NSButtonCell so we can display a nice fadeout effect for
-// button titles that overflow.
-// This method is copied in the most part from GTMFadeTruncatingTextFieldCell,
-// the only difference is that here we draw the text ourselves rather than
-// calling the super to do the work.
-// We can't use GTMFadeTruncatingTextFieldCell because there's no easy way to
-// get it to work with NSButtonCell.
-// TODO(jeremy): Move this to GTM.
-- (NSRect)drawTitle:(NSAttributedString *)title
- withFrame:(NSRect)cellFrame
- inView:(NSView *)controlView {
- NSSize size = [title size];
-
- // Empirically, Cocoa will draw an extra 2 pixels past NSWidth(cellFrame)
- // before it clips the text.
- const CGFloat kOverflowBeforeClip = 2;
- // Don't complicate drawing unless we need to clip.
- if (floor(size.width) <= (NSWidth(cellFrame) + kOverflowBeforeClip)) {
- return [super drawTitle:title withFrame:cellFrame inView:controlView];
- }
-
- // Gradient is about twice our line height long.
- CGFloat gradientWidth = MIN(size.height * 2, NSWidth(cellFrame) / 4);
-
- NSRect solidPart, gradientPart;
- NSDivideRect(cellFrame, &gradientPart, &solidPart, gradientWidth, NSMaxXEdge);
-
- // Draw non-gradient part without transparency layer, as light text on a dark
- // background looks bad with a gradient layer.
- [[NSGraphicsContext currentContext] saveGraphicsState];
- [NSBezierPath clipRect:solidPart];
-
- // 11 is the magic number needed to make this match the native NSButtonCell's
- // label display.
- CGFloat textLeft = [[self image] size].width + 11;
-
- // For some reason, the height of cellFrame as passed in is totally bogus.
- // For vertical centering purposes, we need the bounds of the containing
- // view.
- NSRect buttonFrame = [[self controlView] frame];
-
- // Off-by-one to match native NSButtonCell's version.
- NSPoint textOffset = NSMakePoint(textLeft,
- (NSHeight(buttonFrame) - size.height)/2 + 1);
- [title drawAtPoint:textOffset];
- [[NSGraphicsContext currentContext] restoreGraphicsState];
-
- // Draw the gradient part with a transparency layer. This makes the text look
- // suboptimal, but since it fades out, that's ok.
- [[NSGraphicsContext currentContext] saveGraphicsState];
- [NSBezierPath clipRect:gradientPart];
- CGContextRef context = static_cast<CGContextRef>(
- [[NSGraphicsContext currentContext] graphicsPort]);
- CGContextBeginTransparencyLayerWithRect(context,
- NSRectToCGRect(gradientPart), 0);
- [title drawAtPoint:textOffset];
-
- // TODO(alcor): switch this to GTMLinearRGBShading if we ever need on 10.4
- NSColor *color = [NSColor textColor]; //[self textColor];
- NSColor *alphaColor = [color colorWithAlphaComponent:0.0];
- NSGradient *mask = [[NSGradient alloc] initWithStartingColor:color
- endingColor:alphaColor];
-
- // Draw the gradient mask
- CGContextSetBlendMode(context, kCGBlendModeDestinationIn);
- [mask drawFromPoint:NSMakePoint(NSMaxX(cellFrame) - gradientWidth,
- NSMinY(cellFrame))
- toPoint:NSMakePoint(NSMaxX(cellFrame),
- NSMinY(cellFrame))
- options:NSGradientDrawsBeforeStartingLocation];
- [mask release];
- CGContextEndTransparencyLayer(context);
- [[NSGraphicsContext currentContext] restoreGraphicsState];
-
- return cellFrame;
-}
-
-- (NSBezierPath*)clipPathForFrame:(NSRect)cellFrame
- inView:(NSView*)controlView {
- NSBezierPath* boundingPath = nil;
- [self getDrawParamsForFrame:cellFrame
- inView:controlView
- innerFrame:NULL
- innerPath:NULL
- clipPath:&boundingPath];
- return boundingPath;
-}
-
-@end
diff --git a/chrome/browser/cocoa/gradient_button_cell_unittest.mm b/chrome/browser/cocoa/gradient_button_cell_unittest.mm
deleted file mode 100644
index 1290e11..0000000
--- a/chrome/browser/cocoa/gradient_button_cell_unittest.mm
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright (c) 2009 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 "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/gradient_button_cell.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-@interface GradientButtonCell (HoverValueTesting)
-- (void)performOnePulseStep;
-@end
-
-namespace {
-
-class GradientButtonCellTest : public CocoaTest {
- public:
- GradientButtonCellTest() {
- NSRect frame = NSMakeRect(0, 0, 50, 30);
- scoped_nsobject<NSButton>view([[NSButton alloc] initWithFrame:frame]);
- view_ = view.get();
- scoped_nsobject<GradientButtonCell> cell([[GradientButtonCell alloc]
- initTextCell:@"Testing"]);
- [view_ setCell:cell.get()];
- [[test_window() contentView] addSubview:view_];
- }
-
- NSButton* view_;
-};
-
-TEST_VIEW(GradientButtonCellTest, view_)
-
-// Test drawing, mostly to ensure nothing leaks or crashes.
-TEST_F(GradientButtonCellTest, DisplayWithHover) {
- [[view_ cell] setHoverAlpha:0.0];
- [view_ display];
- [[view_ cell] setHoverAlpha:0.5];
- [view_ display];
- [[view_ cell] setHoverAlpha:1.0];
- [view_ display];
-}
-
-// Test hover, mostly to ensure nothing leaks or crashes.
-TEST_F(GradientButtonCellTest, Hover) {
- GradientButtonCell* cell = [view_ cell];
- [cell setMouseInside:YES animate:NO];
- EXPECT_EQ([[view_ cell] hoverAlpha], 1.0);
-
- [cell setMouseInside:NO animate:YES];
- CGFloat alpha1 = [cell hoverAlpha];
- [cell performOnePulseStep];
- CGFloat alpha2 = [cell hoverAlpha];
- EXPECT_TRUE(alpha2 < alpha1);
-}
-
-// Tracking rects
-TEST_F(GradientButtonCellTest, TrackingRects) {
- GradientButtonCell* cell = [view_ cell];
- EXPECT_FALSE([cell showsBorderOnlyWhileMouseInside]);
- EXPECT_FALSE([cell isMouseInside]);
-
- [cell setShowsBorderOnlyWhileMouseInside:YES];
- [cell mouseEntered:nil];
- EXPECT_TRUE([cell isMouseInside]);
- [cell mouseExited:nil];
- EXPECT_FALSE([cell isMouseInside]);
-
- [cell setShowsBorderOnlyWhileMouseInside:NO];
- EXPECT_FALSE([cell isMouseInside]);
-
- [cell setShowsBorderOnlyWhileMouseInside:YES];
- [cell setShowsBorderOnlyWhileMouseInside:YES];
- [cell setShowsBorderOnlyWhileMouseInside:NO];
- [cell setShowsBorderOnlyWhileMouseInside:NO];
-}
-
-TEST_F(GradientButtonCellTest, ContinuousPulseOnOff) {
- GradientButtonCell* cell = [view_ cell];
-
- // On/off
- EXPECT_FALSE([cell isContinuousPulsing]);
- [cell setIsContinuousPulsing:YES];
- EXPECT_TRUE([cell isContinuousPulsing]);
- EXPECT_TRUE([cell pulsing]);
- [cell setIsContinuousPulsing:NO];
- EXPECT_FALSE([cell isContinuousPulsing]);
-
- // On/safeOff
- [cell setIsContinuousPulsing:YES];
- EXPECT_TRUE([cell isContinuousPulsing]);
- [cell safelyStopPulsing];
-}
-
-// More for valgrind; we don't confirm state change does anything useful.
-TEST_F(GradientButtonCellTest, PulseState) {
- GradientButtonCell* cell = [view_ cell];
-
- [cell setMouseInside:YES animate:YES];
- // Allow for immediate state changes to keep test unflaky
- EXPECT_TRUE(([cell pulseState] == gradient_button_cell::kPulsingOn) ||
- ([cell pulseState] == gradient_button_cell::kPulsedOn));
-
- [cell setMouseInside:NO animate:YES];
- // Allow for immediate state changes to keep test unflaky
- EXPECT_TRUE(([cell pulseState] == gradient_button_cell::kPulsingOff) ||
- ([cell pulseState] == gradient_button_cell::kPulsedOff));
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/history_menu_bridge.h b/chrome/browser/cocoa/history_menu_bridge.h
deleted file mode 100644
index 2743752..0000000
--- a/chrome/browser/cocoa/history_menu_bridge.h
+++ /dev/null
@@ -1,232 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_HISTORY_MENU_BRIDGE_H_
-#define CHROME_BROWSER_COCOA_HISTORY_MENU_BRIDGE_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-#include <map>
-
-#include "base/ref_counted.h"
-#include "base/scoped_nsobject.h"
-#include "chrome/browser/cancelable_request.h"
-#import "chrome/browser/favicon_service.h"
-#include "chrome/browser/history/history.h"
-#include "chrome/browser/sessions/session_id.h"
-#include "chrome/browser/sessions/tab_restore_service.h"
-#include "chrome/browser/sessions/tab_restore_service_observer.h"
-#include "chrome/common/notification_observer.h"
-
-class NavigationEntry;
-class NotificationRegistrar;
-class PageUsageData;
-class Profile;
-class TabNavigationEntry;
-class TabRestoreService;
-@class HistoryMenuCocoaController;
-
-namespace {
-
-class HistoryMenuBridgeTest;
-
-}
-
-// C++ bridge for the history menu; one per AppController (means there
-// is only one). This class observes various data sources, namely the
-// HistoryService and the TabRestoreService, and then updates the NSMenu when
-// there is new data.
-//
-// The history menu is broken up into sections: most visisted and recently
-// closed. The overall menu has a tag of IDC_HISTORY_MENU, with the user content
-// items having the local tags defined in the enum below. Items within a section
-// all share the same tag. The structure of the menu is laid out in MainMenu.xib
-// and the generated content is inserted after the Title elements. The recently
-// closed section is special in that those menu items can have submenus to list
-// all the tabs within that closed window. By convention, these submenu items
-// have a tag that's equal to the parent + 1. Tags within the history menu have
-// a range of [400,500) and do not go through CommandDispatch for their target-
-// action mechanism.
-//
-// These menu items do not use firstResponder as their target. Rather, they are
-// hooked directly up to the HistoryMenuCocoaController that then bridges back
-// to this class. These items are created via the AddItemToMenu() helper. Also,
-// unlike the typical ownership model, this bridge owns its controller. The
-// controller is very thin and only exists to interact with Cocoa, but this
-// class does the bulk of the work.
-class HistoryMenuBridge : public NotificationObserver,
- public TabRestoreServiceObserver {
- public:
- // This is a generalization of the data we store in the history menu because
- // we pull things from different sources with different data types.
- struct HistoryItem {
- public:
- HistoryItem();
- // Copy constructor allowed.
- HistoryItem(const HistoryItem& copy);
- ~HistoryItem();
-
- // The title for the menu item.
- string16 title;
- // The URL that will be navigated to if the user selects this item.
- GURL url;
- // Favicon for the URL.
- scoped_nsobject<NSImage> icon;
-
- // If the icon is being requested from the FaviconService, |icon_requested|
- // will be true and |icon_handle| will be non-NULL. If this is false, then
- // |icon_handle| will be NULL.
- bool icon_requested;
- // The Handle given to us by the FaviconService for the icon fetch request.
- FaviconService::Handle icon_handle;
-
- // The pointer to the item after it has been created. Strong; NSMenu also
- // retains this. During a rebuild flood (if the user closes a lot of tabs
- // quickly), the NSMenu can release the item before the HistoryItem has
- // been fully deleted. If this were a weak pointer, it would result in a
- // zombie.
- scoped_nsobject<NSMenuItem> menu_item;
-
- // This ID is unique for a browser session and can be passed to the
- // TabRestoreService to re-open the closed window or tab that this
- // references. A non-0 session ID indicates that this is an entry can be
- // restored that way. Otherwise, the URL will be used to open the item and
- // this ID will be 0.
- SessionID::id_type session_id;
-
- // If the HistoryItem is a window, this will be the vector of tabs. Note
- // that this is a list of weak references. The |menu_item_map_| is the owner
- // of all items. If it is not a window, then the entry is a single page and
- // the vector will be empty.
- std::vector<HistoryItem*> tabs;
-
- private:
- // Copying is explicitly allowed, but assignment is not.
- void operator=(const HistoryItem&);
- };
-
- // These tags are not global view tags and are local to the history menu. The
- // normal procedure for menu items is to go through CommandDispatch, but since
- // history menu items are hooked directly up to their target, they do not need
- // to have the global IDC view tags.
- enum Tags {
- kMostVisitedSeparator = 400, // Separator before most visited section.
- kMostVisitedTitle = 401, // Title of the most visited section.
- kMostVisited = 420, // Used for all entries in the most visited section.
- kRecentlyClosedSeparator = 440, // Item before recently closed section.
- kRecentlyClosedTitle = 441, // Title of recently closed section.
- kRecentlyClosed = 460, // Used for items in the recently closed section.
- kShowFullSeparator = 480 // Separator after the recently closed section.
- };
-
- explicit HistoryMenuBridge(Profile* profile);
- virtual ~HistoryMenuBridge();
-
- // Overriden from NotificationObserver.
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- // For TabRestoreServiceObserver
- virtual void TabRestoreServiceChanged(TabRestoreService* service);
- virtual void TabRestoreServiceDestroyed(TabRestoreService* service);
-
- // Looks up an NSMenuItem in the |menu_item_map_| and returns the
- // corresponding HistoryItem.
- HistoryItem* HistoryItemForMenuItem(NSMenuItem* item);
-
- // I wish I has a "friend @class" construct. These are used by the HMCC
- // to access model information when responding to actions.
- HistoryService* service();
- Profile* profile();
-
- protected:
- // Return the History menu.
- virtual NSMenu* HistoryMenu();
-
- // Clear items in the given |menu|. Menu items in the same section are given
- // the same tag. This will go through the entire history menu, removing all
- // items with a given tag. Note that this will recurse to submenus, removing
- // child items from the menu item map. This will only remove items that have
- // a target hooked up to the |controller_|.
- void ClearMenuSection(NSMenu* menu, NSInteger tag);
-
- // Adds a given title and URL to the passed-in menu with a certain tag and
- // index. This will add |item| and the newly created menu item to the
- // |menu_item_map_|, which takes ownership. Items are deleted in
- // ClearMenuSection(). This returns the new menu item that was just added.
- NSMenuItem* AddItemToMenu(HistoryItem* item,
- NSMenu* menu,
- NSInteger tag,
- NSInteger index);
-
- // Called by the ctor if |service_| is ready at the time, or by a
- // notification receiver. Finishes initialization tasks by subscribing for
- // change notifications and calling CreateMenu().
- void Init();
-
- // Does the query for the history information to create the menu.
- void CreateMenu();
-
- // Callback method for when HistoryService query results are ready with the
- // most recently-visited sites.
- void OnVisitedHistoryResults(CancelableRequestProvider::Handle handle,
- std::vector<PageUsageData*>* results);
-
- // Creates a HistoryItem* for the given tab entry. Caller takes ownership of
- // the result and must delete it when finished.
- HistoryItem* HistoryItemForTab(const TabRestoreService::Tab& entry);
-
- // Helper function that sends an async request to the FaviconService to get
- // an icon. The callback will update the NSMenuItem directly.
- void GetFaviconForHistoryItem(HistoryItem* item);
-
- // Callback for the FaviconService to return favicon image data when we
- // request it. This decodes the raw data, updates the HistoryItem, and then
- // sets the image on the menu. Called on the same same thread that
- // GetFaviconForHistoryItem() was called on (UI thread).
- void GotFaviconData(FaviconService::Handle handle,
- bool know_favicon,
- scoped_refptr<RefCountedMemory> data,
- bool expired,
- GURL url);
-
- // Cancels a favicon load request for a given HistoryItem, if one is in
- // progress.
- void CancelFaviconRequest(HistoryItem* item);
-
- private:
- friend class ::HistoryMenuBridgeTest;
- friend class HistoryMenuCocoaControllerTest;
-
- scoped_nsobject<HistoryMenuCocoaController> controller_; // strong
-
- Profile* profile_; // weak
- HistoryService* history_service_; // weak
- TabRestoreService* tab_restore_service_; // weak
-
- NotificationRegistrar registrar_;
- CancelableRequestConsumer cancelable_request_consumer_;
-
- // Mapping of NSMenuItems to HistoryItems. This owns the HistoryItems until
- // they are removed and deleted via ClearMenuSection().
- std::map<NSMenuItem*, HistoryItem*> menu_item_map_;
-
- // Maps HistoryItems to favicon request Handles.
- CancelableRequestConsumerTSimple<HistoryItem*> favicon_consumer_;
-
- // Requests to re-create the menu are coalesced. |create_in_progress_| is true
- // when either waiting for the history service to return query results, or
- // when the menu is rebuilding. |need_recreate_| is true whenever a rebuild
- // has been scheduled but is waiting for the current one to finish.
- bool create_in_progress_;
- bool need_recreate_;
-
- // The default favicon if a HistoryItem does not have one.
- scoped_nsobject<NSImage> default_favicon_;
-
- DISALLOW_COPY_AND_ASSIGN(HistoryMenuBridge);
-};
-
-#endif // CHROME_BROWSER_COCOA_HISTORY_MENU_BRIDGE_H_
diff --git a/chrome/browser/cocoa/history_menu_bridge.mm b/chrome/browser/cocoa/history_menu_bridge.mm
deleted file mode 100644
index 0b975ec..0000000
--- a/chrome/browser/cocoa/history_menu_bridge.mm
+++ /dev/null
@@ -1,470 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/history_menu_bridge.h"
-
-#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
-#include "base/callback.h"
-#include "base/stl_util-inl.h"
-#include "base/string_number_conversions.h"
-#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/app/chrome_command_ids.h" // IDC_HISTORY_MENU
-#import "chrome/browser/app_controller_mac.h"
-#import "chrome/browser/cocoa/history_menu_cocoa_controller.h"
-#include "chrome/browser/history/page_usage_data.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/sessions/session_types.h"
-#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/url_constants.h"
-#include "gfx/codec/png_codec.h"
-#include "grit/app_resources.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#include "skia/ext/skia_utils_mac.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-namespace {
-
-// Menus more than this many chars long will get trimmed.
-const NSUInteger kMaximumMenuWidthInChars = 50;
-
-// When trimming, use this many chars from each side.
-const NSUInteger kMenuTrimSizeInChars = 25;
-
-// Number of days to consider when getting the number of most visited items.
-const int kMostVisitedScope = 90;
-
-// The number of most visisted results to get.
-const int kMostVisitedCount = 9;
-
-// The number of recently closed items to get.
-const unsigned int kRecentlyClosedCount = 10;
-
-} // namespace
-
-HistoryMenuBridge::HistoryItem::HistoryItem()
- : icon_requested(false),
- menu_item(nil),
- session_id(0) {
-}
-
-HistoryMenuBridge::HistoryItem::HistoryItem(const HistoryItem& copy)
- : title(copy.title),
- url(copy.url),
- icon_requested(false),
- menu_item(nil),
- session_id(copy.session_id) {
-}
-
-HistoryMenuBridge::HistoryItem::~HistoryItem() {
-}
-
-HistoryMenuBridge::HistoryMenuBridge(Profile* profile)
- : controller_([[HistoryMenuCocoaController alloc] initWithBridge:this]),
- profile_(profile),
- history_service_(NULL),
- tab_restore_service_(NULL),
- create_in_progress_(false),
- need_recreate_(false) {
- // If we don't have a profile, do not bother initializing our data sources.
- // This shouldn't happen except in unit tests.
- if (profile_) {
- // Check to see if the history service is ready. Because it loads async, it
- // may not be ready when the Bridge is created. If this happens, register
- // for a notification that tells us the HistoryService is ready.
- HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
- if (hs != NULL && hs->BackendLoaded()) {
- history_service_ = hs;
- Init();
- }
-
- // TODO(???): NULL here means we're OTR. Show this in the GUI somehow?
- tab_restore_service_ = profile_->GetTabRestoreService();
- if (tab_restore_service_) {
- tab_restore_service_->AddObserver(this);
- tab_restore_service_->LoadTabsFromLastSession();
- }
- }
-
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- default_favicon_.reset([rb.GetNativeImageNamed(IDR_DEFAULT_FAVICON) retain]);
-
- // Set the static icons in the menu.
- NSMenuItem* item = [HistoryMenu() itemWithTag:IDC_SHOW_HISTORY];
- [item setImage:rb.GetNativeImageNamed(IDR_HISTORY_FAVICON)];
-
- // The service is not ready for use yet, so become notified when it does.
- if (!history_service_) {
- registrar_.Add(this,
- NotificationType::HISTORY_LOADED,
- NotificationService::AllSources());
- }
-}
-
-// Note that all requests sent to either the history service or the favicon
-// service will be automatically cancelled by their respective Consumers, so
-// task cancellation is not done manually here in the dtor.
-HistoryMenuBridge::~HistoryMenuBridge() {
- // Unregister ourselves as observers and notifications.
- const NotificationSource& src = NotificationService::AllSources();
- if (history_service_) {
- registrar_.Remove(this, NotificationType::HISTORY_TYPED_URLS_MODIFIED, src);
- registrar_.Remove(this, NotificationType::HISTORY_URL_VISITED, src);
- registrar_.Remove(this, NotificationType::HISTORY_URLS_DELETED, src);
- } else {
- registrar_.Remove(this, NotificationType::HISTORY_LOADED, src);
- }
-
- if (tab_restore_service_)
- tab_restore_service_->RemoveObserver(this);
-
- // Since the map owns the HistoryItems, delete anything that still exists.
- std::map<NSMenuItem*, HistoryItem*>::iterator it = menu_item_map_.begin();
- while (it != menu_item_map_.end()) {
- HistoryItem* item = it->second;
- menu_item_map_.erase(it++);
- delete item;
- }
-}
-
-void HistoryMenuBridge::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- // A history service is now ready. Check to see if it's the one for the main
- // profile. If so, perform final initialization.
- if (type == NotificationType::HISTORY_LOADED) {
- HistoryService* hs =
- profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
- if (hs != NULL && hs->BackendLoaded()) {
- history_service_ = hs;
- Init();
-
- // Found our HistoryService, so stop listening for this notification.
- registrar_.Remove(this,
- NotificationType::HISTORY_LOADED,
- NotificationService::AllSources());
- }
- }
-
- // All other notification types that we observe indicate that the history has
- // changed and we need to rebuild.
- need_recreate_ = true;
- CreateMenu();
-}
-
-void HistoryMenuBridge::TabRestoreServiceChanged(TabRestoreService* service) {
- const TabRestoreService::Entries& entries = service->entries();
-
- // Clear the history menu before rebuilding.
- NSMenu* menu = HistoryMenu();
- ClearMenuSection(menu, kRecentlyClosed);
-
- // Index for the next menu item.
- NSInteger index = [menu indexOfItemWithTag:kRecentlyClosedTitle] + 1;
- NSUInteger added_count = 0;
-
- for (TabRestoreService::Entries::const_iterator it = entries.begin();
- it != entries.end() && added_count < kRecentlyClosedCount; ++it) {
- TabRestoreService::Entry* entry = *it;
-
- // If this is a window, create a submenu for all of its tabs.
- if (entry->type == TabRestoreService::WINDOW) {
- TabRestoreService::Window* entry_win = (TabRestoreService::Window*)entry;
- std::vector<TabRestoreService::Tab>& tabs = entry_win->tabs;
- if (!tabs.size())
- continue;
-
- // Create the item for the parent/window. Do not set the title yet because
- // the actual number of items that are in the menu will not be known until
- // things like the NTP are filtered out, which is done when the tab items
- // are actually created.
- HistoryItem* item = new HistoryItem();
- item->session_id = entry_win->id;
-
- // Create the submenu.
- scoped_nsobject<NSMenu> submenu([[NSMenu alloc] init]);
-
- // Create standard items within the window submenu.
- NSString* restore_title = l10n_util::GetNSString(
- IDS_HISTORY_CLOSED_RESTORE_WINDOW_MAC);
- scoped_nsobject<NSMenuItem> restore_item(
- [[NSMenuItem alloc] initWithTitle:restore_title
- action:@selector(openHistoryMenuItem:)
- keyEquivalent:@""]);
- [restore_item setTarget:controller_.get()];
- // Duplicate the HistoryItem otherwise the different NSMenuItems will
- // point to the same HistoryItem, which would then be double-freed when
- // removing the items from the map or in the dtor.
- HistoryItem* dup_item = new HistoryItem(*item);
- menu_item_map_.insert(std::make_pair(restore_item.get(), dup_item));
- [submenu addItem:restore_item.get()];
- [submenu addItem:[NSMenuItem separatorItem]];
-
- // Loop over the window's tabs and add them to the submenu.
- NSInteger subindex = [[submenu itemArray] count];
- std::vector<TabRestoreService::Tab>::const_iterator it;
- for (it = tabs.begin(); it != tabs.end(); ++it) {
- TabRestoreService::Tab tab = *it;
- HistoryItem* tab_item = HistoryItemForTab(tab);
- if (tab_item) {
- item->tabs.push_back(tab_item);
- AddItemToMenu(tab_item, submenu.get(), kRecentlyClosed + 1,
- subindex++);
- }
- }
-
- // Now that the number of tabs that has been added is known, set the title
- // of the parent menu item.
- if (item->tabs.size() == 1) {
- item->title = l10n_util::GetStringUTF16(
- IDS_NEW_TAB_RECENTLY_CLOSED_WINDOW_SINGLE);
- } else {
- item->title =l10n_util::GetStringFUTF16(
- IDS_NEW_TAB_RECENTLY_CLOSED_WINDOW_MULTIPLE,
- base::IntToString16(item->tabs.size()));
- }
-
- // Sometimes it is possible for there to not be any subitems for a given
- // window; if that is the case, do not add the entry to the main menu.
- if ([[submenu itemArray] count] > 2) {
- // Create the menu item parent.
- NSMenuItem* parent_item =
- AddItemToMenu(item, menu, kRecentlyClosed, index++);
- [parent_item setSubmenu:submenu.get()];
- ++added_count;
- }
- } else if (entry->type == TabRestoreService::TAB) {
- TabRestoreService::Tab* tab =
- static_cast<TabRestoreService::Tab*>(entry);
- HistoryItem* item = HistoryItemForTab(*tab);
- if (item) {
- AddItemToMenu(item, menu, kRecentlyClosed, index++);
- ++added_count;
- }
- }
- }
-}
-
-void HistoryMenuBridge::TabRestoreServiceDestroyed(
- TabRestoreService* service) {
- // Intentionally left blank. We hold a weak reference to the service.
-}
-
-HistoryMenuBridge::HistoryItem* HistoryMenuBridge::HistoryItemForMenuItem(
- NSMenuItem* item) {
- std::map<NSMenuItem*, HistoryItem*>::iterator it = menu_item_map_.find(item);
- if (it != menu_item_map_.end()) {
- return it->second;
- }
- return NULL;
-}
-
-HistoryService* HistoryMenuBridge::service() {
- return history_service_;
-}
-
-Profile* HistoryMenuBridge::profile() {
- return profile_;
-}
-
-NSMenu* HistoryMenuBridge::HistoryMenu() {
- NSMenu* history_menu = [[[NSApp mainMenu] itemWithTag:IDC_HISTORY_MENU]
- submenu];
- return history_menu;
-}
-
-void HistoryMenuBridge::ClearMenuSection(NSMenu* menu, NSInteger tag) {
- for (NSMenuItem* menu_item in [menu itemArray]) {
- if ([menu_item tag] == tag && [menu_item target] == controller_.get()) {
- // This is an item that should be removed, so find the corresponding model
- // item.
- HistoryItem* item = HistoryItemForMenuItem(menu_item);
-
- // Cancel favicon requests that could hold onto stale pointers. Also
- // remove the item from the mapping.
- if (item) {
- CancelFaviconRequest(item);
- menu_item_map_.erase(menu_item);
- delete item;
- }
-
- // If this menu item has a submenu, recurse.
- if ([menu_item hasSubmenu]) {
- ClearMenuSection([menu_item submenu], tag + 1);
- }
-
- // Now actually remove the item from the menu.
- [menu removeItem:menu_item];
- }
- }
-}
-
-NSMenuItem* HistoryMenuBridge::AddItemToMenu(HistoryItem* item,
- NSMenu* menu,
- NSInteger tag,
- NSInteger index) {
- NSString* title = base::SysUTF16ToNSString(item->title);
- std::string url_string = item->url.possibly_invalid_spec();
-
- // If we don't have a title, use the URL.
- if ([title isEqualToString:@""])
- title = base::SysUTF8ToNSString(url_string);
- NSString* full_title = title;
- if ([title length] > kMaximumMenuWidthInChars) {
- // TODO(rsesek): use app/text_elider.h once it uses string16 and can
- // take out the middle of strings.
- title = [NSString stringWithFormat:@"%@…%@",
- [title substringToIndex:kMenuTrimSizeInChars],
- [title substringFromIndex:([title length] -
- kMenuTrimSizeInChars)]];
- }
- item->menu_item.reset(
- [[NSMenuItem alloc] initWithTitle:title
- action:nil
- keyEquivalent:@""]);
- [item->menu_item setTarget:controller_];
- [item->menu_item setAction:@selector(openHistoryMenuItem:)];
- [item->menu_item setTag:tag];
- if (item->icon.get())
- [item->menu_item setImage:item->icon.get()];
- else if (!item->tabs.size())
- [item->menu_item setImage:default_favicon_.get()];
-
- // Add a tooltip.
- NSString* tooltip = [NSString stringWithFormat:@"%@\n%s", full_title,
- url_string.c_str()];
- [item->menu_item setToolTip:tooltip];
-
- [menu insertItem:item->menu_item.get() atIndex:index];
- menu_item_map_.insert(std::make_pair(item->menu_item.get(), item));
-
- return item->menu_item.get();
-}
-
-void HistoryMenuBridge::Init() {
- const NotificationSource& source = NotificationService::AllSources();
- registrar_.Add(this, NotificationType::HISTORY_TYPED_URLS_MODIFIED, source);
- registrar_.Add(this, NotificationType::HISTORY_URL_VISITED, source);
- registrar_.Add(this, NotificationType::HISTORY_URLS_DELETED, source);
-}
-
-void HistoryMenuBridge::CreateMenu() {
- // If we're currently running CreateMenu(), wait until it finishes.
- if (create_in_progress_)
- return;
- create_in_progress_ = true;
- need_recreate_ = false;
-
- history_service_->QuerySegmentUsageSince(
- &cancelable_request_consumer_,
- base::Time::Now() - base::TimeDelta::FromDays(kMostVisitedScope),
- kMostVisitedCount,
- NewCallback(this, &HistoryMenuBridge::OnVisitedHistoryResults));
-}
-
-void HistoryMenuBridge::OnVisitedHistoryResults(
- CancelableRequestProvider::Handle handle,
- std::vector<PageUsageData*>* results) {
- NSMenu* menu = HistoryMenu();
- ClearMenuSection(menu, kMostVisited);
- NSInteger top_item = [menu indexOfItemWithTag:kMostVisitedTitle] + 1;
-
- size_t count = results->size();
- for (size_t i = 0; i < count; ++i) {
- PageUsageData* history_item = (*results)[i];
-
- HistoryItem* item = new HistoryItem();
- item->title = history_item->GetTitle();
- item->url = history_item->GetURL();
- if (history_item->HasFavIcon()) {
- const SkBitmap* icon = history_item->GetFavIcon();
- item->icon.reset([gfx::SkBitmapToNSImage(*icon) retain]);
- } else {
- GetFaviconForHistoryItem(item);
- }
- // This will add |item| to the |menu_item_map_|, which takes ownership.
- AddItemToMenu(item, HistoryMenu(), kMostVisited, top_item + i);
- }
-
- // We are already invalid by the time we finished, darn.
- if (need_recreate_)
- CreateMenu();
-
- create_in_progress_ = false;
-}
-
-HistoryMenuBridge::HistoryItem* HistoryMenuBridge::HistoryItemForTab(
- const TabRestoreService::Tab& entry) {
- if (entry.navigations.empty())
- return NULL;
-
- const TabNavigation& current_navigation =
- entry.navigations.at(entry.current_navigation_index);
- if (current_navigation.virtual_url() == GURL(chrome::kChromeUINewTabURL))
- return NULL;
-
- HistoryItem* item = new HistoryItem();
- item->title = current_navigation.title();
- item->url = current_navigation.virtual_url();
- item->session_id = entry.id;
-
- // Tab navigations don't come with icons, so we always have to request them.
- GetFaviconForHistoryItem(item);
-
- return item;
-}
-
-void HistoryMenuBridge::GetFaviconForHistoryItem(HistoryItem* item) {
- FaviconService* service =
- profile_->GetFaviconService(Profile::EXPLICIT_ACCESS);
- FaviconService::Handle handle = service->GetFaviconForURL(item->url,
- &favicon_consumer_,
- NewCallback(this, &HistoryMenuBridge::GotFaviconData));
- favicon_consumer_.SetClientData(service, handle, item);
- item->icon_handle = handle;
- item->icon_requested = true;
-}
-
-void HistoryMenuBridge::GotFaviconData(FaviconService::Handle handle,
- bool know_favicon,
- scoped_refptr<RefCountedMemory> data,
- bool expired,
- GURL url) {
- // Since we're going to do Cocoa-y things, make sure this is the main thread.
- DCHECK([NSThread isMainThread]);
-
- HistoryItem* item =
- favicon_consumer_.GetClientData(
- profile_->GetFaviconService(Profile::EXPLICIT_ACCESS), handle);
- DCHECK(item);
- item->icon_requested = false;
- item->icon_handle = NULL;
-
- // Convert the raw data to Skia and then to a NSImage.
- // TODO(rsesek): Is there an easier way to do this?
- SkBitmap icon;
- if (know_favicon && data.get() && data->size() &&
- gfx::PNGCodec::Decode(data->front(), data->size(), &icon)) {
- NSImage* image = gfx::SkBitmapToNSImage(icon);
- if (image) {
- // The conversion was successful.
- item->icon.reset([image retain]);
- [item->menu_item setImage:item->icon.get()];
- }
- }
-}
-
-void HistoryMenuBridge::CancelFaviconRequest(HistoryItem* item) {
- DCHECK(item);
- if (item->icon_requested) {
- FaviconService* service =
- profile_->GetFaviconService(Profile::EXPLICIT_ACCESS);
- service->CancelRequest(item->icon_handle);
- item->icon_requested = false;
- item->icon_handle = NULL;
- }
-}
diff --git a/chrome/browser/cocoa/history_menu_bridge_unittest.mm b/chrome/browser/cocoa/history_menu_bridge_unittest.mm
deleted file mode 100644
index c0d109b..0000000
--- a/chrome/browser/cocoa/history_menu_bridge_unittest.mm
+++ /dev/null
@@ -1,386 +0,0 @@
-// 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 <vector>
-
-#include "base/ref_counted_memory.h"
-#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/cancelable_request.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/cocoa/history_menu_bridge.h"
-#include "chrome/browser/sessions/tab_restore_service.h"
-#include "chrome/browser/ui/browser.h"
-#include "gfx/codec/png_codec.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-
-namespace {
-
-class MockTRS : public TabRestoreService {
- public:
- MockTRS(Profile* profile) : TabRestoreService(profile, NULL) {}
- MOCK_CONST_METHOD0(entries, const TabRestoreService::Entries&());
-};
-
-class MockBridge : public HistoryMenuBridge {
- public:
- MockBridge(Profile* profile)
- : HistoryMenuBridge(profile),
- menu_([[NSMenu alloc] initWithTitle:@"History"]) {}
-
- virtual NSMenu* HistoryMenu() {
- return menu_.get();
- }
-
- private:
- scoped_nsobject<NSMenu> menu_;
-};
-
-class HistoryMenuBridgeTest : public CocoaTest {
- public:
-
- virtual void SetUp() {
- CocoaTest::SetUp();
- browser_test_helper_.profile()->CreateFaviconService();
- bridge_.reset(new MockBridge(browser_test_helper_.profile()));
- }
-
- // We are a friend of HistoryMenuBridge (and have access to
- // protected methods), but none of the classes generated by TEST_F()
- // are. Wraps common commands.
- void ClearMenuSection(NSMenu* menu,
- NSInteger tag) {
- bridge_->ClearMenuSection(menu, tag);
- }
-
- void AddItemToBridgeMenu(HistoryMenuBridge::HistoryItem* item,
- NSMenu* menu,
- NSInteger tag,
- NSInteger index) {
- bridge_->AddItemToMenu(item, menu, tag, index);
- }
-
- NSMenuItem* AddItemToMenu(NSMenu* menu,
- NSString* title,
- SEL selector,
- int tag) {
- NSMenuItem* item = [[[NSMenuItem alloc] initWithTitle:title action:NULL
- keyEquivalent:@""] autorelease];
- [item setTag:tag];
- if (selector) {
- [item setAction:selector];
- [item setTarget:bridge_->controller_.get()];
- }
- [menu addItem:item];
- return item;
- }
-
- HistoryMenuBridge::HistoryItem* CreateItem(const string16& title) {
- HistoryMenuBridge::HistoryItem* item =
- new HistoryMenuBridge::HistoryItem();
- item->title = title;
- item->url = GURL(title);
- return item;
- }
-
- MockTRS::Tab CreateSessionTab(const GURL& url, const string16& title) {
- MockTRS::Tab tab;
- tab.current_navigation_index = 0;
- tab.navigations.push_back(
- TabNavigation(0, url, GURL(), title, std::string(),
- PageTransition::LINK));
- return tab;
- }
-
- void GetFaviconForHistoryItem(HistoryMenuBridge::HistoryItem* item) {
- bridge_->GetFaviconForHistoryItem(item);
- }
-
- void GotFaviconData(FaviconService::Handle handle,
- bool know_favicon,
- scoped_refptr<RefCountedBytes> data,
- bool expired,
- GURL url) {
- bridge_->GotFaviconData(handle, know_favicon, data, expired, url);
- }
-
- CancelableRequestConsumerTSimple<HistoryMenuBridge::HistoryItem*>&
- favicon_consumer() {
- return bridge_->favicon_consumer_;
- }
-
- BrowserTestHelper browser_test_helper_;
- scoped_ptr<MockBridge> bridge_;
-};
-
-// Edge case test for clearing until the end of a menu.
-TEST_F(HistoryMenuBridgeTest, ClearHistoryMenuUntilEnd) {
- NSMenu* menu = [[[NSMenu alloc] initWithTitle:@"history foo"] autorelease];
- AddItemToMenu(menu, @"HEADER", NULL, HistoryMenuBridge::kMostVisitedTitle);
-
- NSInteger tag = HistoryMenuBridge::kMostVisited;
- AddItemToMenu(menu, @"alpha", @selector(openHistoryMenuItem:), tag);
- AddItemToMenu(menu, @"bravo", @selector(openHistoryMenuItem:), tag);
- AddItemToMenu(menu, @"charlie", @selector(openHistoryMenuItem:), tag);
- AddItemToMenu(menu, @"delta", @selector(openHistoryMenuItem:), tag);
-
- ClearMenuSection(menu, HistoryMenuBridge::kMostVisited);
-
- EXPECT_EQ(1, [menu numberOfItems]);
- EXPECT_NSEQ(@"HEADER",
- [[menu itemWithTag:HistoryMenuBridge::kMostVisitedTitle] title]);
-}
-
-// Skip menu items that are not hooked up to |-openHistoryMenuItem:|.
-TEST_F(HistoryMenuBridgeTest, ClearHistoryMenuSkipping) {
- NSMenu* menu = [[[NSMenu alloc] initWithTitle:@"history foo"] autorelease];
- AddItemToMenu(menu, @"HEADER", NULL, HistoryMenuBridge::kMostVisitedTitle);
-
- NSInteger tag = HistoryMenuBridge::kMostVisited;
- AddItemToMenu(menu, @"alpha", @selector(openHistoryMenuItem:), tag);
- AddItemToMenu(menu, @"bravo", @selector(openHistoryMenuItem:), tag);
- AddItemToMenu(menu, @"TITLE", NULL, HistoryMenuBridge::kRecentlyClosedTitle);
- AddItemToMenu(menu, @"charlie", @selector(openHistoryMenuItem:), tag);
-
- ClearMenuSection(menu, tag);
-
- EXPECT_EQ(2, [menu numberOfItems]);
- EXPECT_NSEQ(@"HEADER",
- [[menu itemWithTag:HistoryMenuBridge::kMostVisitedTitle] title]);
- EXPECT_NSEQ(@"TITLE",
- [[menu itemAtIndex:1] title]);
-}
-
-// Edge case test for clearing an empty menu.
-TEST_F(HistoryMenuBridgeTest, ClearHistoryMenuEmpty) {
- NSMenu* menu = [[[NSMenu alloc] initWithTitle:@"history foo"] autorelease];
- AddItemToMenu(menu, @"HEADER", NULL, HistoryMenuBridge::kMostVisited);
-
- ClearMenuSection(menu, HistoryMenuBridge::kMostVisited);
-
- EXPECT_EQ(1, [menu numberOfItems]);
- EXPECT_NSEQ(@"HEADER",
- [[menu itemWithTag:HistoryMenuBridge::kMostVisited] title]);
-}
-
-// Test that AddItemToMenu() properly adds HistoryItem objects as menus.
-TEST_F(HistoryMenuBridgeTest, AddItemToMenu) {
- NSMenu* menu = [[[NSMenu alloc] initWithTitle:@"history foo"] autorelease];
-
- const string16 short_url = ASCIIToUTF16("http://foo/");
- const string16 long_url = ASCIIToUTF16("http://super-duper-long-url--."
- "that.cannot.possibly.fit.even-in-80-columns"
- "or.be.reasonably-displayed-in-a-menu"
- "without.looking-ridiculous.com/"); // 140 chars total
-
- // HistoryItems are owned by the HistoryMenuBridge when AddItemToBridgeMenu()
- // is called, which places them into the |menu_item_map_|, which owns them.
- HistoryMenuBridge::HistoryItem* item1 = CreateItem(short_url);
- AddItemToBridgeMenu(item1, menu, 100, 0);
-
- HistoryMenuBridge::HistoryItem* item2 = CreateItem(long_url);
- AddItemToBridgeMenu(item2, menu, 101, 1);
-
- EXPECT_EQ(2, [menu numberOfItems]);
-
- EXPECT_EQ(@selector(openHistoryMenuItem:), [[menu itemAtIndex:0] action]);
- EXPECT_EQ(@selector(openHistoryMenuItem:), [[menu itemAtIndex:1] action]);
-
- EXPECT_EQ(100, [[menu itemAtIndex:0] tag]);
- EXPECT_EQ(101, [[menu itemAtIndex:1] tag]);
-
- // Make sure a short title looks fine
- NSString* s = [[menu itemAtIndex:0] title];
- EXPECT_EQ(base::SysNSStringToUTF16(s), short_url);
-
- // Make sure a super-long title gets trimmed
- s = [[menu itemAtIndex:0] title];
- EXPECT_TRUE([s length] < long_url.length());
-
- // Confirm tooltips and confirm they are not trimmed (like the item
- // name might be). Add tolerance for URL fixer-upping;
- // e.g. http://foo becomes http://foo/)
- EXPECT_GE([[[menu itemAtIndex:0] toolTip] length], (2*short_url.length()-5));
- EXPECT_GE([[[menu itemAtIndex:1] toolTip] length], (2*long_url.length()-5));
-}
-
-// Test that the menu is created for a set of simple tabs.
-TEST_F(HistoryMenuBridgeTest, RecentlyClosedTabs) {
- scoped_refptr<MockTRS> trs(new MockTRS(browser_test_helper_.profile()));
- MockTRS::Entries entries;
-
- MockTRS::Tab tab1 = CreateSessionTab(GURL("http://google.com"),
- ASCIIToUTF16("Google"));
- tab1.id = 24;
- entries.push_back(&tab1);
-
- MockTRS::Tab tab2 = CreateSessionTab(GURL("http://apple.com"),
- ASCIIToUTF16("Apple"));
- tab2.id = 42;
- entries.push_back(&tab2);
-
- using ::testing::ReturnRef;
- EXPECT_CALL(*trs.get(), entries()).WillOnce(ReturnRef(entries));
-
- bridge_->TabRestoreServiceChanged(trs.get());
-
- NSMenu* menu = bridge_->HistoryMenu();
- ASSERT_EQ(2U, [[menu itemArray] count]);
-
- NSMenuItem* item1 = [menu itemAtIndex:0];
- MockBridge::HistoryItem* hist1 = bridge_->HistoryItemForMenuItem(item1);
- EXPECT_TRUE(hist1);
- EXPECT_EQ(24, hist1->session_id);
- EXPECT_NSEQ(@"Google", [item1 title]);
-
- NSMenuItem* item2 = [menu itemAtIndex:1];
- MockBridge::HistoryItem* hist2 = bridge_->HistoryItemForMenuItem(item2);
- EXPECT_TRUE(hist2);
- EXPECT_EQ(42, hist2->session_id);
- EXPECT_NSEQ(@"Apple", [item2 title]);
-}
-
-// Test that the menu is created for a mix of windows and tabs.
-TEST_F(HistoryMenuBridgeTest, RecentlyClosedTabsAndWindows) {
- scoped_refptr<MockTRS> trs(new MockTRS(browser_test_helper_.profile()));
- MockTRS::Entries entries;
-
- MockTRS::Tab tab1 = CreateSessionTab(GURL("http://google.com"),
- ASCIIToUTF16("Google"));
- tab1.id = 24;
- entries.push_back(&tab1);
-
- MockTRS::Window win1;
- win1.id = 30;
- win1.tabs.push_back(
- CreateSessionTab(GURL("http://foo.com"), ASCIIToUTF16("foo")));
- win1.tabs[0].id = 31;
- win1.tabs.push_back(
- CreateSessionTab(GURL("http://bar.com"), ASCIIToUTF16("bar")));
- win1.tabs[1].id = 32;
- entries.push_back(&win1);
-
- MockTRS::Tab tab2 = CreateSessionTab(GURL("http://apple.com"),
- ASCIIToUTF16("Apple"));
- tab2.id = 42;
- entries.push_back(&tab2);
-
- MockTRS::Window win2;
- win2.id = 50;
- win2.tabs.push_back(
- CreateSessionTab(GURL("http://magic.com"), ASCIIToUTF16("magic")));
- win2.tabs[0].id = 51;
- win2.tabs.push_back(
- CreateSessionTab(GURL("http://goats.com"), ASCIIToUTF16("goats")));
- win2.tabs[1].id = 52;
- win2.tabs.push_back(
- CreateSessionTab(GURL("http://teleporter.com"),
- ASCIIToUTF16("teleporter")));
- win2.tabs[1].id = 53;
- entries.push_back(&win2);
-
- using ::testing::ReturnRef;
- EXPECT_CALL(*trs.get(), entries()).WillOnce(ReturnRef(entries));
-
- bridge_->TabRestoreServiceChanged(trs.get());
-
- NSMenu* menu = bridge_->HistoryMenu();
- ASSERT_EQ(4U, [[menu itemArray] count]);
-
- NSMenuItem* item1 = [menu itemAtIndex:0];
- MockBridge::HistoryItem* hist1 = bridge_->HistoryItemForMenuItem(item1);
- EXPECT_TRUE(hist1);
- EXPECT_EQ(24, hist1->session_id);
- EXPECT_NSEQ(@"Google", [item1 title]);
-
- NSMenuItem* item2 = [menu itemAtIndex:1];
- MockBridge::HistoryItem* hist2 = bridge_->HistoryItemForMenuItem(item2);
- EXPECT_TRUE(hist2);
- EXPECT_EQ(30, hist2->session_id);
- EXPECT_EQ(2U, hist2->tabs.size());
- // Do not test menu item title because it is localized.
- NSMenu* submenu1 = [item2 submenu];
- EXPECT_EQ(4U, [[submenu1 itemArray] count]);
- // Do not test Restore All Tabs because it is localiced.
- EXPECT_TRUE([[submenu1 itemAtIndex:1] isSeparatorItem]);
- EXPECT_NSEQ(@"foo", [[submenu1 itemAtIndex:2] title]);
- EXPECT_NSEQ(@"bar", [[submenu1 itemAtIndex:3] title]);
-
- NSMenuItem* item3 = [menu itemAtIndex:2];
- MockBridge::HistoryItem* hist3 = bridge_->HistoryItemForMenuItem(item3);
- EXPECT_TRUE(hist3);
- EXPECT_EQ(42, hist3->session_id);
- EXPECT_NSEQ(@"Apple", [item3 title]);
-
- NSMenuItem* item4 = [menu itemAtIndex:3];
- MockBridge::HistoryItem* hist4 = bridge_->HistoryItemForMenuItem(item4);
- EXPECT_TRUE(hist4);
- EXPECT_EQ(50, hist4->session_id);
- EXPECT_EQ(3U, hist4->tabs.size());
- // Do not test menu item title because it is localized.
- NSMenu* submenu2 = [item4 submenu];
- EXPECT_EQ(5U, [[submenu2 itemArray] count]);
- // Do not test Restore All Tabs because it is localiced.
- EXPECT_TRUE([[submenu2 itemAtIndex:1] isSeparatorItem]);
- EXPECT_NSEQ(@"magic", [[submenu2 itemAtIndex:2] title]);
- EXPECT_NSEQ(@"goats", [[submenu2 itemAtIndex:3] title]);
- EXPECT_NSEQ(@"teleporter", [[submenu2 itemAtIndex:4] title]);
-}
-
-// Tests that we properly request an icon from the FaviconService.
-TEST_F(HistoryMenuBridgeTest, GetFaviconForHistoryItem) {
- // Create a fake item.
- HistoryMenuBridge::HistoryItem item;
- item.title = ASCIIToUTF16("Title");
- item.url = GURL("http://google.com");
-
- // Request the icon.
- GetFaviconForHistoryItem(&item);
-
- // Make sure that there is ClientData for the request.
- std::vector<HistoryMenuBridge::HistoryItem*> data;
- favicon_consumer().GetAllClientData(&data);
- ASSERT_EQ(data.size(), 1U);
- EXPECT_EQ(&item, data[0]);
-
- // Make sure the item was modified properly.
- EXPECT_TRUE(item.icon_requested);
- EXPECT_GT(item.icon_handle, 0);
-}
-
-TEST_F(HistoryMenuBridgeTest, GotFaviconData) {
- // Create a dummy bitmap.
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, 25, 25);
- bitmap.allocPixels();
- bitmap.eraseRGB(255, 0, 0);
-
- // Convert it to raw PNG bytes. We totally ignore color order here because
- // we just want to test the roundtrip through the Bridge, not that we can
- // make icons look pretty.
- std::vector<unsigned char> raw;
- gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, true, &raw);
- scoped_refptr<RefCountedBytes> bytes(new RefCountedBytes(raw));
-
- // Set up the HistoryItem.
- HistoryMenuBridge::HistoryItem item;
- item.menu_item.reset([[NSMenuItem alloc] init]);
- GetFaviconForHistoryItem(&item);
-
- // Pretend to be called back.
- GotFaviconData(item.icon_handle, true, bytes, false, GURL());
-
- // Make sure the callback works.
- EXPECT_FALSE(item.icon_requested);
- EXPECT_TRUE(item.icon.get());
- EXPECT_TRUE([item.menu_item image]);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/history_menu_cocoa_controller.h b/chrome/browser/cocoa/history_menu_cocoa_controller.h
deleted file mode 100644
index 4cb6dc6..0000000
--- a/chrome/browser/cocoa/history_menu_cocoa_controller.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// 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.
-
-// Controller (MVC) for the history menu. All history menu item commands get
-// directed here. This class only responds to menu events, but the actual
-// creation and maintenance of the menu happens in the Bridge.
-
-#ifndef CHROME_BROWSER_COCOA_HISTORY_MENU_COCOA_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_HISTORY_MENU_COCOA_CONTROLLER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-#import "chrome/browser/cocoa/history_menu_bridge.h"
-
-@interface HistoryMenuCocoaController : NSObject {
- @private
- HistoryMenuBridge* bridge_; // weak; owns us
-}
-
-- (id)initWithBridge:(HistoryMenuBridge*)bridge;
-
-// Called by any history menu item.
-- (IBAction)openHistoryMenuItem:(id)sender;
-
-@end // HistoryMenuCocoaController
-
-@interface HistoryMenuCocoaController (ExposedForUnitTests)
-- (void)openURLForItem:(const HistoryMenuBridge::HistoryItem*)node;
-@end // HistoryMenuCocoaController (ExposedForUnitTests)
-
-#endif // CHROME_BROWSER_COCOA_HISTORY_MENU_COCOA_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/history_menu_cocoa_controller.mm b/chrome/browser/cocoa/history_menu_cocoa_controller.mm
deleted file mode 100644
index fb58682..0000000
--- a/chrome/browser/cocoa/history_menu_cocoa_controller.mm
+++ /dev/null
@@ -1,58 +0,0 @@
-// 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 "chrome/browser/cocoa/history_menu_cocoa_controller.h"
-
-#include "base/scoped_vector.h"
-#include "chrome/app/chrome_command_ids.h" // IDC_HISTORY_MENU
-#import "chrome/browser/app_controller_mac.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/cocoa/event_utils.h"
-#include "chrome/browser/history/history.h"
-#include "chrome/browser/history/history_types.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/ui/browser.h"
-#include "webkit/glue/window_open_disposition.h"
-
-@implementation HistoryMenuCocoaController
-
-- (id)initWithBridge:(HistoryMenuBridge*)bridge {
- if ((self = [super init])) {
- bridge_ = bridge;
- DCHECK(bridge_);
- }
- return self;
-}
-
-- (BOOL)validateMenuItem:(NSMenuItem*)menuItem {
- AppController* controller = [NSApp delegate];
- return [controller keyWindowIsNotModal];
-}
-
-// Open the URL of the given history item in the current tab.
-- (void)openURLForItem:(const HistoryMenuBridge::HistoryItem*)node {
- Browser* browser = Browser::GetOrCreateTabbedBrowser(bridge_->profile());
- WindowOpenDisposition disposition =
- event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
-
- // If this item can be restored using TabRestoreService, do so. Otherwise,
- // just load the URL.
- TabRestoreService* service = bridge_->profile()->GetTabRestoreService();
- if (node->session_id && service) {
- service->RestoreEntryById(browser, node->session_id, false);
- } else {
- DCHECK(node->url.is_valid());
- browser->OpenURL(node->url, GURL(), disposition,
- PageTransition::AUTO_BOOKMARK);
- }
-}
-
-- (IBAction)openHistoryMenuItem:(id)sender {
- const HistoryMenuBridge::HistoryItem* item =
- bridge_->HistoryItemForMenuItem(sender);
- [self openURLForItem:item];
-}
-
-@end // HistoryMenuCocoaController
diff --git a/chrome/browser/cocoa/history_menu_cocoa_controller_unittest.mm b/chrome/browser/cocoa/history_menu_cocoa_controller_unittest.mm
deleted file mode 100644
index cf259cc..0000000
--- a/chrome/browser/cocoa/history_menu_cocoa_controller_unittest.mm
+++ /dev/null
@@ -1,91 +0,0 @@
-// 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.
-
-#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/cocoa/history_menu_bridge.h"
-#include "chrome/browser/cocoa/history_menu_cocoa_controller.h"
-#include "chrome/browser/ui/browser.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-@interface FakeHistoryMenuController : HistoryMenuCocoaController {
- @public
- BOOL opened_[2];
-}
-@end
-
-@implementation FakeHistoryMenuController
-
-- (id)initTest {
- if ((self = [super init])) {
- opened_[0] = NO;
- opened_[1] = NO;
- }
- return self;
-}
-
-- (void)openURLForItem:(HistoryMenuBridge::HistoryItem*)item {
- opened_[item->session_id] = YES;
-}
-
-@end // FakeHistoryMenuController
-
-class HistoryMenuCocoaControllerTest : public CocoaTest {
- public:
-
- virtual void SetUp() {
- CocoaTest::SetUp();
- bridge_.reset(new HistoryMenuBridge(browser_test_helper_.profile()));
- bridge_->controller_.reset(
- [[FakeHistoryMenuController alloc] initWithBridge:bridge_.get()]);
- [controller() initTest];
- }
-
- void CreateItems(NSMenu* menu) {
- HistoryMenuBridge::HistoryItem* item = new HistoryMenuBridge::HistoryItem();
- item->url = GURL("http://google.com");
- item->session_id = 0;
- bridge_->AddItemToMenu(item, menu, HistoryMenuBridge::kMostVisited, 0);
-
- item = new HistoryMenuBridge::HistoryItem();
- item->url = GURL("http://apple.com");
- item->session_id = 1;
- bridge_->AddItemToMenu(item, menu, HistoryMenuBridge::kMostVisited, 1);
- }
-
- std::map<NSMenuItem*, HistoryMenuBridge::HistoryItem*>& menu_item_map() {
- return bridge_->menu_item_map_;
- }
-
- FakeHistoryMenuController* controller() {
- return static_cast<FakeHistoryMenuController*>(bridge_->controller_.get());
- }
-
- private:
- BrowserTestHelper browser_test_helper_;
- scoped_ptr<HistoryMenuBridge> bridge_;
-};
-
-TEST_F(HistoryMenuCocoaControllerTest, OpenURLForItem) {
-
- scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@"History"]);
- CreateItems(menu.get());
-
- std::map<NSMenuItem*, HistoryMenuBridge::HistoryItem*>& items =
- menu_item_map();
- std::map<NSMenuItem*, HistoryMenuBridge::HistoryItem*>::iterator it =
- items.begin();
-
- for ( ; it != items.end(); ++it) {
- HistoryMenuBridge::HistoryItem* item = it->second;
- EXPECT_FALSE(controller()->opened_[item->session_id]);
- [controller() openHistoryMenuItem:it->first];
- EXPECT_TRUE(controller()->opened_[item->session_id]);
- }
-}
diff --git a/chrome/browser/cocoa/hover_button.mm b/chrome/browser/cocoa/hover_button.mm
deleted file mode 100644
index 38874e3..0000000
--- a/chrome/browser/cocoa/hover_button.mm
+++ /dev/null
@@ -1,97 +0,0 @@
-// 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 "chrome/browser/cocoa/hover_button.h"
-
-@implementation HoverButton
-
-- (id)initWithFrame:(NSRect)frameRect {
- if ((self = [super initWithFrame:frameRect])) {
- [self setTrackingEnabled:YES];
- hoverState_ = kHoverStateNone;
- [self updateTrackingAreas];
- }
- return self;
-}
-
-- (void)awakeFromNib {
- [self setTrackingEnabled:YES];
- hoverState_ = kHoverStateNone;
- [self updateTrackingAreas];
-}
-
-- (void)dealloc {
- [self setTrackingEnabled:NO];
- [super dealloc];
-}
-
-- (void)mouseEntered:(NSEvent*)theEvent {
- hoverState_ = kHoverStateMouseOver;
- [self setNeedsDisplay:YES];
-}
-
-- (void)mouseExited:(NSEvent*)theEvent {
- hoverState_ = kHoverStateNone;
- [self setNeedsDisplay:YES];
-}
-
-- (void)mouseDown:(NSEvent*)theEvent {
- hoverState_ = kHoverStateMouseDown;
- [self setNeedsDisplay:YES];
- // The hover button needs to hold onto itself here for a bit. Otherwise,
- // it can be freed while |super mouseDown:| is in it's loop, and the
- // |checkImageState| call will crash.
- // http://crbug.com/28220
- scoped_nsobject<HoverButton> myself([self retain]);
-
- [super mouseDown:theEvent];
- // We need to check the image state after the mouseDown event loop finishes.
- // It's possible that we won't get a mouseExited event if the button was
- // moved under the mouse during tab resize, instead of the mouse moving over
- // the button.
- // http://crbug.com/31279
- [self checkImageState];
-}
-
-- (void)setTrackingEnabled:(BOOL)enabled {
- if (enabled) {
- trackingArea_.reset(
- [[NSTrackingArea alloc] initWithRect:[self bounds]
- options:NSTrackingMouseEnteredAndExited |
- NSTrackingActiveAlways
- owner:self
- userInfo:nil]);
- [self addTrackingArea:trackingArea_.get()];
-
- // If you have a separate window that overlaps the close button, and you
- // move the mouse directly over the close button without entering another
- // part of the tab strip, we don't get any mouseEntered event since the
- // tracking area was disabled when we entered.
- [self checkImageState];
- } else {
- if (trackingArea_.get()) {
- [self removeTrackingArea:trackingArea_.get()];
- trackingArea_.reset(nil);
- }
- }
-}
-
-- (void)updateTrackingAreas {
- [super updateTrackingAreas];
- [self checkImageState];
-}
-
-- (void)checkImageState {
- if (!trackingArea_.get())
- return;
-
- // Update the button's state if the button has moved.
- NSPoint mouseLoc = [[self window] mouseLocationOutsideOfEventStream];
- mouseLoc = [self convertPoint:mouseLoc fromView:nil];
- hoverState_ = NSPointInRect(mouseLoc, [self bounds]) ?
- kHoverStateMouseOver : kHoverStateNone;
- [self setNeedsDisplay:YES];
-}
-
-@end
diff --git a/chrome/browser/cocoa/hover_close_button.h b/chrome/browser/cocoa/hover_close_button.h
deleted file mode 100644
index da1180a..0000000
--- a/chrome/browser/cocoa/hover_close_button.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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 "base/scoped_nsobject.h"
-#include "chrome/browser/cocoa/hover_button.h"
-
-// The standard close button for our Mac UI which is the "x" that changes to a
-// dark circle with the "x" when you hover over it. At this time it is used by
-// the popup blocker, download bar, info bar and tabs.
-@interface HoverCloseButton : HoverButton {
- @private
- // Bezier path for drawing the 'x' within the button.
- scoped_nsobject<NSBezierPath> xPath_;
-
- // Bezier path for drawing the hover state circle behind the 'x'.
- scoped_nsobject<NSBezierPath> circlePath_;
-}
-
-// Sets up the button's tracking areas and accessibility info when instantiated
-// via initWithFrame or awakeFromNib.
-- (void)commonInit;
-
-@end
diff --git a/chrome/browser/cocoa/hover_close_button.mm b/chrome/browser/cocoa/hover_close_button.mm
deleted file mode 100644
index 7620e95..0000000
--- a/chrome/browser/cocoa/hover_close_button.mm
+++ /dev/null
@@ -1,108 +0,0 @@
-// 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 "chrome/browser/cocoa/hover_close_button.h"
-
-#include "app/l10n_util.h"
-#include "base/scoped_nsobject.h"
-#include "grit/generated_resources.h"
-#import "third_party/molokocacao/NSBezierPath+MCAdditions.h"
-
-namespace {
-// Convenience function to return the middle point of the given |rect|.
-static NSPoint MidRect(NSRect rect) {
- return NSMakePoint(NSMidX(rect), NSMidY(rect));
-}
-
-const CGFloat kCircleRadiusPercentage = 0.415;
-const CGFloat kCircleHoverWhite = 0.565;
-const CGFloat kCircleClickWhite = 0.396;
-const CGFloat kXShadowAlpha = 0.75;
-const CGFloat kXShadowCircleAlpha = 0.1;
-} // namespace
-
-@interface HoverCloseButton(Private)
-- (void)setUpDrawingPaths;
-@end
-
-@implementation HoverCloseButton
-
-- (id)initWithFrame:(NSRect)frameRect {
- if ((self = [super initWithFrame:frameRect])) {
- [self commonInit];
- }
- return self;
-}
-
-- (void)awakeFromNib {
- [super awakeFromNib];
- [self commonInit];
-}
-
-- (void)drawRect:(NSRect)rect {
- if (!circlePath_.get() || !xPath_.get())
- [self setUpDrawingPaths];
-
- // If the user is hovering over the button, a light/dark gray circle is drawn
- // behind the 'x'.
- if (hoverState_ != kHoverStateNone) {
- // Adjust the darkness of the circle depending on whether it is being
- // clicked.
- CGFloat white = (hoverState_ == kHoverStateMouseOver) ?
- kCircleHoverWhite : kCircleClickWhite;
- [[NSColor colorWithCalibratedWhite:white alpha:1.0] set];
- [circlePath_ fill];
- }
-
- [[NSColor whiteColor] set];
- [xPath_ fill];
-
- // Give the 'x' an inner shadow for depth. If the button is in a hover state
- // (circle behind it), then adjust the shadow accordingly (not as harsh).
- NSShadow* shadow = [[[NSShadow alloc] init] autorelease];
- CGFloat alpha = (hoverState_ != kHoverStateNone) ?
- kXShadowCircleAlpha : kXShadowAlpha;
- [shadow setShadowColor:[NSColor colorWithCalibratedWhite:0.15
- alpha:alpha]];
- [shadow setShadowOffset:NSMakeSize(0.0, 0.0)];
- [shadow setShadowBlurRadius:2.5];
- [xPath_ fillWithInnerShadow:shadow];
-}
-
-- (void)commonInit {
- // Set accessibility description.
- NSString* description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_CLOSE);
- [[self cell]
- accessibilitySetOverrideValue:description
- forAttribute:NSAccessibilityDescriptionAttribute];
-}
-
-- (void)setUpDrawingPaths {
- NSPoint viewCenter = MidRect([self bounds]);
-
- circlePath_.reset([[NSBezierPath bezierPath] retain]);
- [circlePath_ moveToPoint:viewCenter];
- CGFloat radius = kCircleRadiusPercentage * NSWidth([self bounds]);
- [circlePath_ appendBezierPathWithArcWithCenter:viewCenter
- radius:radius
- startAngle:0.0
- endAngle:365.0];
-
- // Construct an 'x' by drawing two intersecting rectangles in the shape of a
- // cross and then rotating the path by 45 degrees.
- xPath_.reset([[NSBezierPath bezierPath] retain]);
- [xPath_ appendBezierPathWithRect:NSMakeRect(3.5, 7.0, 9.0, 2.0)];
- [xPath_ appendBezierPathWithRect:NSMakeRect(7.0, 3.5, 2.0, 9.0)];
-
- NSPoint pathCenter = MidRect([xPath_ bounds]);
-
- NSAffineTransform* transform = [NSAffineTransform transform];
- [transform translateXBy:viewCenter.x yBy:viewCenter.y];
- [transform rotateByDegrees:45.0];
- [transform translateXBy:-pathCenter.x yBy:-pathCenter.y];
-
- [xPath_ transformUsingAffineTransform:transform];
-}
-
-@end
diff --git a/chrome/browser/cocoa/hover_image_button.h b/chrome/browser/cocoa/hover_image_button.h
deleted file mode 100644
index ef1f0071..0000000
--- a/chrome/browser/cocoa/hover_image_button.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// 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 "base/scoped_nsobject.h"
-#include "chrome/browser/cocoa/hover_button.h"
-
-// A button that changes images when you hover over it and click it.
-@interface HoverImageButton : HoverButton {
- @private
- float defaultOpacity_;
- float hoverOpacity_;
- float pressedOpacity_;
-
- scoped_nsobject<NSImage> defaultImage_;
- scoped_nsobject<NSImage> hoverImage_;
- scoped_nsobject<NSImage> pressedImage_;
-}
-
-// Sets the default image.
-- (void)setDefaultImage:(NSImage*)image;
-
-// Sets the hover image.
-- (void)setHoverImage:(NSImage*)image;
-
-// Sets the pressed image.
-- (void)setPressedImage:(NSImage*)image;
-
-// Sets the default opacity.
-- (void)setDefaultOpacity:(float)opacity;
-
-// Sets the opacity on hover.
-- (void)setHoverOpacity:(float)opacity;
-
-// Sets the opacity when pressed.
-- (void)setPressedOpacity:(float)opacity;
-
-@end
diff --git a/chrome/browser/cocoa/hover_image_button.mm b/chrome/browser/cocoa/hover_image_button.mm
deleted file mode 100644
index e5a3e35..0000000
--- a/chrome/browser/cocoa/hover_image_button.mm
+++ /dev/null
@@ -1,52 +0,0 @@
-// 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 "chrome/browser/cocoa/hover_image_button.h"
-
-#include "app/l10n_util.h"
-#include "base/scoped_nsobject.h"
-#include "grit/generated_resources.h"
-
-@implementation HoverImageButton
-
-- (void)drawRect:(NSRect)rect {
- if (hoverState_ == kHoverStateMouseDown && pressedImage_) {
- [super setImage:pressedImage_.get()];
- [super setAlphaValue:pressedOpacity_];
- } else if (hoverState_ == kHoverStateMouseOver && hoverImage_) {
- [super setImage:hoverImage_.get()];
- [super setAlphaValue:hoverOpacity_];
- } else {
- [super setImage:defaultImage_.get()];
- [super setAlphaValue:defaultOpacity_];
- }
-
- [super drawRect:rect];
-}
-
-- (void)setDefaultImage:(NSImage*)image {
- defaultImage_.reset([image retain]);
-}
-
-- (void)setDefaultOpacity:(float)opacity {
- defaultOpacity_ = opacity;
-}
-
-- (void)setHoverImage:(NSImage*)image {
- hoverImage_.reset([image retain]);
-}
-
-- (void)setHoverOpacity:(float)opacity {
- hoverOpacity_ = opacity;
-}
-
-- (void)setPressedImage:(NSImage*)image {
- pressedImage_.reset([image retain]);
-}
-
-- (void)setPressedOpacity:(float)opacity {
- pressedOpacity_ = opacity;
-}
-
-@end
diff --git a/chrome/browser/cocoa/hover_image_button_unittest.mm b/chrome/browser/cocoa/hover_image_button_unittest.mm
deleted file mode 100644
index f8eb3f5..0000000
--- a/chrome/browser/cocoa/hover_image_button_unittest.mm
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright (c) 2009 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 "app/resource_bundle.h"
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/hover_image_button.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-#include "grit/theme_resources.h"
-
-namespace {
-
-class HoverImageButtonTest : public CocoaTest {
- public:
- HoverImageButtonTest() {
- NSRect content_frame = [[test_window() contentView] frame];
- scoped_nsobject<HoverImageButton> button(
- [[HoverImageButton alloc] initWithFrame:content_frame]);
- button_ = button.get();
- [[test_window() contentView] addSubview:button_];
- }
-
- virtual void SetUp() {
- CocoaTest::BootstrapCocoa();
- }
-
- HoverImageButton* button_;
-};
-
-// Test mouse events.
-TEST_F(HoverImageButtonTest, ImageSwap) {
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- NSImage* image = rb.GetNativeImageNamed(IDR_HOME);
- NSImage* hover = rb.GetNativeImageNamed(IDR_BACK);
- [button_ setDefaultImage:image];
- [button_ setHoverImage:hover];
-
- [button_ mouseEntered:nil];
- [button_ drawRect:[button_ frame]];
- EXPECT_EQ([button_ image], hover);
- [button_ mouseExited:nil];
- [button_ drawRect:[button_ frame]];
- EXPECT_EQ([button_ image], image);
-}
-
-// Test mouse events.
-TEST_F(HoverImageButtonTest, Opacity) {
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- NSImage* image = rb.GetNativeImageNamed(IDR_HOME);
- [button_ setDefaultImage:image];
- [button_ setDefaultOpacity:0.5];
- [button_ setHoverImage:image];
- [button_ setHoverOpacity:1.0];
-
- [button_ mouseEntered:nil];
- [button_ drawRect:[button_ frame]];
- EXPECT_EQ([button_ alphaValue], 1.0);
- [button_ mouseExited:nil];
- [button_ drawRect:[button_ frame]];
- EXPECT_EQ([button_ alphaValue], 0.5);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/html_dialog_window_controller.h b/chrome/browser/cocoa/html_dialog_window_controller.h
deleted file mode 100644
index ae2e109..0000000
--- a/chrome/browser/cocoa/html_dialog_window_controller.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_HTML_DIALOG_WINDOW_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_HTML_DIALOG_WINDOW_CONTROLLER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/basictypes.h"
-#include "base/scoped_ptr.h"
-#include "chrome/browser/dom_ui/html_dialog_ui.h"
-
-class HtmlDialogWindowDelegateBridge;
-class Profile;
-class TabContents;
-
-// This controller manages a dialog box with properties and HTML content taken
-// from a HTMLDialogUIDelegate object.
-@interface HtmlDialogWindowController : NSWindowController {
- @private
- // Order here is important, as tab_contents_ may send messages to
- // delegate_ when it gets destroyed.
- scoped_ptr<HtmlDialogWindowDelegateBridge> delegate_;
- scoped_ptr<TabContents> tabContents_;
-}
-
-// Creates and shows an HtmlDialogWindowController with the given
-// delegate and profile. The window is automatically destroyed when
-// it is closed. Returns the created window.
-//
-// Make sure to use the returned window only when you know it is safe
-// to do so, i.e. before OnDialogClosed() is called on the delegate.
-+ (NSWindow*)showHtmlDialog:(HtmlDialogUIDelegate*)delegate
- profile:(Profile*)profile;
-
-@end
-
-@interface HtmlDialogWindowController (TestingAPI)
-
-// This is the designated initializer. However, this is exposed only
-// for testing; use showHtmlDialog instead.
-- (id)initWithDelegate:(HtmlDialogUIDelegate*)delegate
- profile:(Profile*)profile;
-
-// Loads the HTML content from the delegate; this is not a lightweight
-// process which is why it is not part of the constructor. Must be
-// called before showWindow.
-- (void)loadDialogContents;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_HTML_DIALOG_WINDOW_CONTROLLER_H_
-
diff --git a/chrome/browser/cocoa/html_dialog_window_controller.mm b/chrome/browser/cocoa/html_dialog_window_controller.mm
deleted file mode 100644
index aed0d83..0000000
--- a/chrome/browser/cocoa/html_dialog_window_controller.mm
+++ /dev/null
@@ -1,293 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/html_dialog_window_controller.h"
-
-#include "app/keyboard_codes.h"
-#include "base/logging.h"
-#include "base/scoped_nsobject.h"
-#include "base/sys_string_conversions.h"
-#import "chrome/browser/cocoa/browser_command_executor.h"
-#import "chrome/browser/cocoa/chrome_event_processing_window.h"
-#include "chrome/browser/dom_ui/html_dialog_ui.h"
-#include "chrome/browser/dom_ui/html_dialog_tab_contents_delegate.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/native_web_keyboard_event.h"
-#include "gfx/size.h"
-#include "ipc/ipc_message.h"
-
-// Thin bridge that routes notifications to
-// HtmlDialogWindowController's member variables.
-class HtmlDialogWindowDelegateBridge : public HtmlDialogUIDelegate,
- public HtmlDialogTabContentsDelegate {
-public:
- // All parameters must be non-NULL/non-nil.
- HtmlDialogWindowDelegateBridge(HtmlDialogWindowController* controller,
- Profile* profile,
- HtmlDialogUIDelegate* delegate);
-
- virtual ~HtmlDialogWindowDelegateBridge();
-
- // Called when the window is directly closed, e.g. from the close
- // button or from an accelerator.
- void WindowControllerClosed();
-
- // HtmlDialogUIDelegate declarations.
- virtual bool IsDialogModal() const;
- virtual std::wstring GetDialogTitle() const;
- virtual GURL GetDialogContentURL() const;
- virtual void GetDOMMessageHandlers(
- std::vector<DOMMessageHandler*>* handlers) const;
- virtual void GetDialogSize(gfx::Size* size) const;
- virtual std::string GetDialogArgs() const;
- virtual void OnDialogClosed(const std::string& json_retval);
- virtual void OnCloseContents(TabContents* source, bool* out_close_dialog) { }
- virtual bool ShouldShowDialogTitle() const { return true; }
-
- // HtmlDialogTabContentsDelegate declarations.
- virtual void MoveContents(TabContents* source, const gfx::Rect& pos);
- virtual void ToolbarSizeChanged(TabContents* source, bool is_animating);
- virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event);
-
-private:
- HtmlDialogWindowController* controller_; // weak
- HtmlDialogUIDelegate* delegate_; // weak, owned by controller_
-
- // Calls delegate_'s OnDialogClosed() exactly once, nulling it out
- // afterwards so that no other HtmlDialogUIDelegate calls are sent
- // to it. Returns whether or not the OnDialogClosed() was actually
- // called on the delegate.
- bool DelegateOnDialogClosed(const std::string& json_retval);
-
- DISALLOW_COPY_AND_ASSIGN(HtmlDialogWindowDelegateBridge);
-};
-
-// ChromeEventProcessingWindow expects its controller to implement the
-// BrowserCommandExecutor protocol.
-@interface HtmlDialogWindowController (InternalAPI) <BrowserCommandExecutor>
-
-// BrowserCommandExecutor methods.
-- (void)executeCommand:(int)command;
-
-@end
-
-namespace html_dialog_window_controller {
-
-gfx::NativeWindow ShowHtmlDialog(
- HtmlDialogUIDelegate* delegate, Profile* profile) {
- return [HtmlDialogWindowController showHtmlDialog:delegate profile:profile];
-}
-
-} // namespace html_dialog_window_controller
-
-HtmlDialogWindowDelegateBridge::HtmlDialogWindowDelegateBridge(
- HtmlDialogWindowController* controller, Profile* profile,
- HtmlDialogUIDelegate* delegate)
- : HtmlDialogTabContentsDelegate(profile),
- controller_(controller), delegate_(delegate) {
- DCHECK(controller_);
- DCHECK(delegate_);
-}
-
-HtmlDialogWindowDelegateBridge::~HtmlDialogWindowDelegateBridge() {}
-
-void HtmlDialogWindowDelegateBridge::WindowControllerClosed() {
- Detach();
- controller_ = nil;
- DelegateOnDialogClosed("");
-}
-
-bool HtmlDialogWindowDelegateBridge::DelegateOnDialogClosed(
- const std::string& json_retval) {
- if (delegate_) {
- HtmlDialogUIDelegate* real_delegate = delegate_;
- delegate_ = NULL;
- real_delegate->OnDialogClosed(json_retval);
- return true;
- }
- return false;
-}
-
-// HtmlDialogUIDelegate definitions.
-
-// All of these functions check for NULL first since delegate_ is set
-// to NULL when the window is closed.
-
-bool HtmlDialogWindowDelegateBridge::IsDialogModal() const {
- // TODO(akalin): Support modal dialog boxes.
- if (delegate_ && delegate_->IsDialogModal()) {
- LOG(WARNING) << "Modal HTML dialogs are not supported yet";
- }
- return false;
-}
-
-std::wstring HtmlDialogWindowDelegateBridge::GetDialogTitle() const {
- return delegate_ ? delegate_->GetDialogTitle() : L"";
-}
-
-GURL HtmlDialogWindowDelegateBridge::GetDialogContentURL() const {
- return delegate_ ? delegate_->GetDialogContentURL() : GURL();
-}
-
-void HtmlDialogWindowDelegateBridge::GetDOMMessageHandlers(
- std::vector<DOMMessageHandler*>* handlers) const {
- if (delegate_) {
- delegate_->GetDOMMessageHandlers(handlers);
- } else {
- // TODO(akalin): Add this clause in the windows version. Also
- // make sure that everything expects handlers to be non-NULL and
- // document it.
- handlers->clear();
- }
-}
-
-void HtmlDialogWindowDelegateBridge::GetDialogSize(gfx::Size* size) const {
- if (delegate_) {
- delegate_->GetDialogSize(size);
- } else {
- *size = gfx::Size();
- }
-}
-
-std::string HtmlDialogWindowDelegateBridge::GetDialogArgs() const {
- return delegate_ ? delegate_->GetDialogArgs() : "";
-}
-
-void HtmlDialogWindowDelegateBridge::OnDialogClosed(
- const std::string& json_retval) {
- Detach();
- // [controller_ close] should be called at most once, too.
- if (DelegateOnDialogClosed(json_retval)) {
- [controller_ close];
- }
- controller_ = nil;
-}
-
-void HtmlDialogWindowDelegateBridge::MoveContents(TabContents* source,
- const gfx::Rect& pos) {
- // TODO(akalin): Actually set the window bounds.
-}
-
-void HtmlDialogWindowDelegateBridge::ToolbarSizeChanged(
- TabContents* source, bool is_animating) {
- // TODO(akalin): Figure out what to do here.
-}
-
-// A simplified version of BrowserWindowCocoa::HandleKeyboardEvent().
-// We don't handle global keyboard shortcuts here, but that's fine since
-// they're all browser-specific. (This may change in the future.)
-void HtmlDialogWindowDelegateBridge::HandleKeyboardEvent(
- const NativeWebKeyboardEvent& event) {
- if (event.skip_in_browser || event.type == NativeWebKeyboardEvent::Char)
- return;
-
- // Close ourselves if the user hits Esc or Command-. . The normal
- // way to do this is to implement (void)cancel:(int)sender, but
- // since we handle keyboard events ourselves we can't do that.
- //
- // According to experiments, hitting Esc works regardless of the
- // presence of other modifiers (as long as it's not an app-level
- // shortcut, e.g. Commmand-Esc for Front Row) but no other modifiers
- // can be present for Command-. to work.
- //
- // TODO(thakis): It would be nice to get cancel: to work somehow.
- // Bug: http://code.google.com/p/chromium/issues/detail?id=32828 .
- if (event.type == NativeWebKeyboardEvent::RawKeyDown &&
- ((event.windowsKeyCode == app::VKEY_ESCAPE) ||
- (event.windowsKeyCode == app::VKEY_OEM_PERIOD &&
- event.modifiers == NativeWebKeyboardEvent::MetaKey))) {
- [controller_ close];
- return;
- }
-
- ChromeEventProcessingWindow* event_window =
- static_cast<ChromeEventProcessingWindow*>([controller_ window]);
- DCHECK([event_window isKindOfClass:[ChromeEventProcessingWindow class]]);
- [event_window redispatchKeyEvent:event.os_event];
-}
-
-@implementation HtmlDialogWindowController (InternalAPI)
-
-// This gets called whenever a chrome-specific keyboard shortcut is performed
-// in the HTML dialog window. We simply swallow all those events.
-- (void)executeCommand:(int)command {}
-
-@end
-
-@implementation HtmlDialogWindowController
-
-// NOTE(akalin): We'll probably have to add the parentWindow parameter back
-// in once we implement modal dialogs.
-
-+ (NSWindow*)showHtmlDialog:(HtmlDialogUIDelegate*)delegate
- profile:(Profile*)profile {
- HtmlDialogWindowController* htmlDialogWindowController =
- [[HtmlDialogWindowController alloc] initWithDelegate:delegate
- profile:profile];
- [htmlDialogWindowController loadDialogContents];
- [htmlDialogWindowController showWindow:nil];
- return [htmlDialogWindowController window];
-}
-
-- (id)initWithDelegate:(HtmlDialogUIDelegate*)delegate
- profile:(Profile*)profile {
- DCHECK(delegate);
- DCHECK(profile);
-
- gfx::Size dialogSize;
- delegate->GetDialogSize(&dialogSize);
- NSRect dialogRect = NSMakeRect(0, 0, dialogSize.width(), dialogSize.height());
- // TODO(akalin): Make the window resizable (but with the minimum size being
- // dialog_size and always on top (but not modal) to match the Windows
- // behavior. On the other hand, the fact that HTML dialogs on Windows
- // are resizable could just be an accident. Investigate futher...
- NSUInteger style = NSTitledWindowMask | NSClosableWindowMask;
- scoped_nsobject<ChromeEventProcessingWindow> window(
- [[ChromeEventProcessingWindow alloc]
- initWithContentRect:dialogRect
- styleMask:style
- backing:NSBackingStoreBuffered
- defer:YES]);
- if (!window.get()) {
- return nil;
- }
- self = [super initWithWindow:window];
- if (!self) {
- return nil;
- }
- [window setWindowController:self];
- [window setDelegate:self];
- [window setTitle:base::SysWideToNSString(delegate->GetDialogTitle())];
- [window center];
- delegate_.reset(new HtmlDialogWindowDelegateBridge(self, profile, delegate));
- return self;
-}
-
-- (void)loadDialogContents {
- tabContents_.reset(new TabContents(
- delegate_->profile(), NULL, MSG_ROUTING_NONE, NULL, NULL));
- [[self window] setContentView:tabContents_->GetNativeView()];
- tabContents_->set_delegate(delegate_.get());
-
- // This must be done before loading the page; see the comments in
- // HtmlDialogUI.
- HtmlDialogUI::GetPropertyAccessor().SetProperty(tabContents_->property_bag(),
- delegate_.get());
-
- tabContents_->controller().LoadURL(delegate_->GetDialogContentURL(),
- GURL(), PageTransition::START_PAGE);
-
- // TODO(akalin): add accelerator for ESC to close the dialog box.
- //
- // TODO(akalin): Figure out why implementing (void)cancel:(id)sender
- // to do the above doesn't work.
-}
-
-- (void)windowWillClose:(NSNotification*)notification {
- delegate_->WindowControllerClosed();
- [self autorelease];
-}
-
-@end
diff --git a/chrome/browser/cocoa/html_dialog_window_controller_cppsafe.h b/chrome/browser/cocoa/html_dialog_window_controller_cppsafe.h
deleted file mode 100644
index 41279ff..0000000
--- a/chrome/browser/cocoa/html_dialog_window_controller_cppsafe.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_HTML_DIALOG_WINDOW_CONTROLLER_CPPSAFE_H_
-#define CHROME_BROWSER_COCOA_HTML_DIALOG_WINDOW_CONTROLLER_CPPSAFE_H_
-#pragma once
-
-#include "gfx/native_widget_types.h"
-
-// We declare this in a separate file that is safe for including in C++ code.
-
-// TODO(akalin): It would be nice if there were a platform-agnostic way to
-// create a browser-independent HTML dialog. However, this would require
-// some invasive changes on the Windows/Linux side. Remove this file once
-// We have this platform-agnostic API.
-
-namespace html_dialog_window_controller {
-
-// Creates and shows an HtmlDialogWindowController with the given
-// delegate and profile. The window is automatically destroyed when it is
-// closed. Returns the created window.
-//
-// Make sure to use the returned window only when you know it is safe
-// to do so, i.e. before OnDialogClosed() is called on the delegate.
-gfx::NativeWindow ShowHtmlDialog(
- HtmlDialogUIDelegate* delegate, Profile* profile);
-
-} // namespace html_dialog_window_controller
-
-#endif // CHROME_BROWSER_COCOA_HTML_DIALOG_WINDOW_CONTROLLER_CPPSAFE_H_
-
diff --git a/chrome/browser/cocoa/html_dialog_window_controller_unittest.mm b/chrome/browser/cocoa/html_dialog_window_controller_unittest.mm
deleted file mode 100644
index c8cdfb7..0000000
--- a/chrome/browser/cocoa/html_dialog_window_controller_unittest.mm
+++ /dev/null
@@ -1,94 +0,0 @@
-// 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 "chrome/browser/cocoa/html_dialog_window_controller.h"
-
-#include <string>
-#include <vector>
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/mac/scoped_nsautorelease_pool.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/dom_ui/dom_ui.h"
-#include "chrome/browser/dom_ui/html_dialog_ui.h"
-#include "chrome/test/browser_with_test_window_test.h"
-#include "chrome/test/testing_profile.h"
-#include "gfx/size.h"
-#include "googleurl/src/gurl.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-class MockDelegate : public HtmlDialogUIDelegate {
-public:
- MOCK_CONST_METHOD0(IsDialogModal, bool());
- MOCK_CONST_METHOD0(GetDialogTitle, std::wstring());
- MOCK_CONST_METHOD0(GetDialogContentURL, GURL());
- MOCK_CONST_METHOD1(GetDOMMessageHandlers,
- void(std::vector<DOMMessageHandler*>*));
- MOCK_CONST_METHOD1(GetDialogSize, void(gfx::Size*));
- MOCK_CONST_METHOD0(GetDialogArgs, std::string());
- MOCK_METHOD1(OnDialogClosed, void(const std::string& json_retval));
- MOCK_METHOD2(OnCloseContents,
- void(TabContents* source, bool* out_close_dialog));
- MOCK_CONST_METHOD0(ShouldShowDialogTitle, bool());
-};
-
-class HtmlDialogWindowControllerTest : public BrowserWithTestWindowTest {
- public:
- virtual void SetUp() {
- BrowserWithTestWindowTest::SetUp();
- CocoaTest::BootstrapCocoa();
- title_ = L"Mock Title";
- size_ = gfx::Size(50, 100);
- gurl_ = GURL("");
- }
-
- protected:
- std::wstring title_;
- gfx::Size size_;
- GURL gurl_;
-
- // Order here is important.
- MockDelegate delegate_;
-};
-
-using ::testing::_;
-using ::testing::Return;
-using ::testing::SetArgumentPointee;
-
-// TODO(akalin): We can't test much more than the below without a real browser.
-// In particular, GetDOMMessageHandlers() and GetDialogArgs() are never called.
-// This should be fixed.
-
-TEST_F(HtmlDialogWindowControllerTest, showDialog) {
- // We want to make sure html_dialog_window_controller below gets
- // destroyed before delegate_, so we specify our own autorelease pool.
- //
- // TODO(dmaclach): Remove this once
- // http://code.google.com/p/chromium/issues/detail?id=26133 is fixed.
- base::mac::ScopedNSAutoreleasePool release_pool;
-
- EXPECT_CALL(delegate_, GetDialogTitle())
- .WillOnce(Return(title_));
- EXPECT_CALL(delegate_, GetDialogSize(_))
- .WillOnce(SetArgumentPointee<0>(size_));
- EXPECT_CALL(delegate_, GetDialogContentURL())
- .WillOnce(Return(gurl_));
- EXPECT_CALL(delegate_, OnDialogClosed(_))
- .Times(1);
-
- HtmlDialogWindowController* html_dialog_window_controller =
- [[HtmlDialogWindowController alloc] initWithDelegate:&delegate_
- profile:profile()];
-
- [html_dialog_window_controller loadDialogContents];
- [html_dialog_window_controller showWindow:nil];
- [html_dialog_window_controller close];
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/hung_renderer_controller.h b/chrome/browser/cocoa/hung_renderer_controller.h
deleted file mode 100644
index 8635a53..0000000
--- a/chrome/browser/cocoa/hung_renderer_controller.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_HUNG_RENDERER_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_HUNG_RENDERER_CONTROLLER_H_
-#pragma once
-
-// A controller for the Mac hung renderer dialog window. Only one
-// instance of this controller can exist at any time, although a given
-// controller is destroyed when its window is closed.
-//
-// The dialog itself displays a list of frozen tabs, all of which
-// share a render process. Since there can only be a single dialog
-// open at a time, if showForTabContents is called for a different
-// tab, the dialog is repurposed to show a warning for the new tab.
-//
-// The caller is required to call endForTabContents before deleting
-// any TabContents object.
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/cocoa_protocols_mac.h"
-#import "base/scoped_nsobject.h"
-
-@class MultiKeyEquivalentButton;
-class TabContents;
-
-@interface HungRendererController : NSWindowController<NSTableViewDataSource> {
- @private
- IBOutlet MultiKeyEquivalentButton* waitButton_;
- IBOutlet NSButton* killButton_;
- IBOutlet NSTableView* tableView_;
- IBOutlet NSImageView* imageView_;
- IBOutlet NSTextField* messageView_;
-
- // The TabContents for which this dialog is open. Should never be
- // NULL while this dialog is open.
- TabContents* hungContents_;
-
- // Backing data for |tableView_|. Titles of each TabContents that
- // shares a renderer process with |hungContents_|.
- scoped_nsobject<NSArray> hungTitles_;
-
- // Favicons of each TabContents that shares a renderer process with
- // |hungContents_|.
- scoped_nsobject<NSArray> hungFavicons_;
-}
-
-// Kills the hung renderers.
-- (IBAction)kill:(id)sender;
-
-// Waits longer for the renderers to respond.
-- (IBAction)wait:(id)sender;
-
-// Modifies the dialog to show a warning for the given tab contents.
-// The dialog will contain a list of all tabs that share a renderer
-// process with |contents|. The caller must not delete any tab
-// contents without first calling endForTabContents.
-- (void)showForTabContents:(TabContents*)contents;
-
-// Notifies the dialog that |contents| is either responsive or closed.
-// If |contents| shares the same render process as the tab contents
-// this dialog was created for, this function will close the dialog.
-// If |contents| has a different process, this function does nothing.
-- (void)endForTabContents:(TabContents*)contents;
-
-@end // HungRendererController
-
-
-@interface HungRendererController (JustForTesting)
-- (NSButton*)killButton;
-- (MultiKeyEquivalentButton*)waitButton;
-@end
-
-#endif // CHROME_BROWSER_COCOA_HUNG_RENDERER_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/hung_renderer_controller.mm b/chrome/browser/cocoa/hung_renderer_controller.mm
deleted file mode 100644
index 086bbbc..0000000
--- a/chrome/browser/cocoa/hung_renderer_controller.mm
+++ /dev/null
@@ -1,203 +0,0 @@
-// 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 "chrome/browser/cocoa/hung_renderer_controller.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include "app/resource_bundle.h"
-#include "app/l10n_util_mac.h"
-#include "base/mac_util.h"
-#include "base/process_util.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/browser_list.h"
-#include "chrome/browser/hung_renderer_dialog.h"
-#import "chrome/browser/cocoa/multi_key_equivalent_button.h"
-#include "chrome/browser/renderer_host/render_process_host.h"
-#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/logging_chrome.h"
-#include "chrome/common/result_codes.h"
-#include "grit/chromium_strings.h"
-#include "grit/app_resources.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#include "skia/ext/skia_utils_mac.h"
-#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-
-namespace {
-// We only support showing one of these at a time per app. The
-// controller owns itself and is released when its window is closed.
-HungRendererController* g_instance = NULL;
-} // end namespace
-
-@implementation HungRendererController
-
-- (id)initWithWindowNibName:(NSString*)nibName {
- NSString* nibpath = [mac_util::MainAppBundle() pathForResource:nibName
- ofType:@"nib"];
- self = [super initWithWindowNibPath:nibpath owner:self];
- if (self) {
- [tableView_ setDataSource:self];
- }
- return self;
-}
-
-- (void)dealloc {
- DCHECK(!g_instance);
- [tableView_ setDataSource:nil];
- [super dealloc];
-}
-
-- (void)awakeFromNib {
- // Load in the image
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- NSImage* backgroundImage = rb.GetNativeImageNamed(IDR_FROZEN_TAB_ICON);
- DCHECK(backgroundImage);
- [imageView_ setImage:backgroundImage];
-
- // Make the message fit.
- CGFloat messageShift =
- [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:messageView_];
-
- // Move the graphic up to be top even with the message.
- NSRect graphicFrame = [imageView_ frame];
- graphicFrame.origin.y += messageShift;
- [imageView_ setFrame:graphicFrame];
-
- // Make the window taller to fit everything.
- NSSize windowDelta = NSMakeSize(0, messageShift);
- [GTMUILocalizerAndLayoutTweaker
- resizeWindowWithoutAutoResizingSubViews:[self window]
- delta:windowDelta];
-
- // Make the "wait" button respond to additional keys. By setting this to
- // @"\e", it will respond to both Esc and Command-. (period).
- KeyEquivalentAndModifierMask key;
- key.charCode = @"\e";
- [waitButton_ addKeyEquivalent:key];
-}
-
-- (IBAction)kill:(id)sender {
- if (hungContents_)
- base::KillProcess(hungContents_->GetRenderProcessHost()->GetHandle(),
- ResultCodes::HUNG, false);
- // Cannot call performClose:, because the close button is disabled.
- [self close];
-}
-
-- (IBAction)wait:(id)sender {
- if (hungContents_ && hungContents_->render_view_host())
- hungContents_->render_view_host()->RestartHangMonitorTimeout();
- // Cannot call performClose:, because the close button is disabled.
- [self close];
-}
-
-- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView {
- return [hungTitles_ count];
-}
-
-- (id)tableView:(NSTableView*)aTableView
- objectValueForTableColumn:(NSTableColumn*)column
- row:(NSInteger)rowIndex {
- return [NSNumber numberWithInt:NSOffState];
-}
-
-- (NSCell*)tableView:(NSTableView*)tableView
- dataCellForTableColumn:(NSTableColumn*)tableColumn
- row:(NSInteger)rowIndex {
- NSCell* cell = [tableColumn dataCellForRow:rowIndex];
-
- if ([[tableColumn identifier] isEqualToString:@"title"]) {
- DCHECK([cell isKindOfClass:[NSButtonCell class]]);
- NSButtonCell* buttonCell = static_cast<NSButtonCell*>(cell);
- [buttonCell setTitle:[hungTitles_ objectAtIndex:rowIndex]];
- [buttonCell setImage:[hungFavicons_ objectAtIndex:rowIndex]];
- [buttonCell setRefusesFirstResponder:YES]; // Don't push in like a button.
- [buttonCell setHighlightsBy:NSNoCellMask];
- }
- return cell;
-}
-
-- (void)windowWillClose:(NSNotification*)notification {
- // We have to reset g_instance before autoreleasing the window,
- // because we want to avoid reusing the same dialog if someone calls
- // hung_renderer_dialog::ShowForTabContents() between the autorelease
- // call and the actual dealloc.
- g_instance = nil;
-
- [self autorelease];
-}
-
-- (void)showForTabContents:(TabContents*)contents {
- DCHECK(contents);
- hungContents_ = contents;
- scoped_nsobject<NSMutableArray> titles([[NSMutableArray alloc] init]);
- scoped_nsobject<NSMutableArray> favicons([[NSMutableArray alloc] init]);
- for (TabContentsIterator it; !it.done(); ++it) {
- if (it->GetRenderProcessHost() == hungContents_->GetRenderProcessHost()) {
- string16 title = (*it)->GetTitle();
- if (title.empty())
- title = TabContents::GetDefaultTitle();
- [titles addObject:base::SysUTF16ToNSString(title)];
-
- // TabContents can return a null SkBitmap if it has no favicon. If this
- // happens, use the default favicon.
- const SkBitmap& bitmap = it->GetFavIcon();
- if (!bitmap.isNull()) {
- [favicons addObject:gfx::SkBitmapToNSImage(bitmap)];
- } else {
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- [favicons addObject:rb.GetNativeImageNamed(IDR_DEFAULT_FAVICON)];
- }
- }
- }
- hungTitles_.reset([titles copy]);
- hungFavicons_.reset([favicons copy]);
- [tableView_ reloadData];
-
- [[self window] center];
- [self showWindow:self];
-}
-
-- (void)endForTabContents:(TabContents*)contents {
- DCHECK(contents);
- DCHECK(hungContents_);
- if (hungContents_ && hungContents_->GetRenderProcessHost() ==
- contents->GetRenderProcessHost()) {
- // Cannot call performClose:, because the close button is disabled.
- [self close];
- }
-}
-
-@end
-
-@implementation HungRendererController (JustForTesting)
-- (NSButton*)killButton {
- return killButton_;
-}
-
-- (MultiKeyEquivalentButton*)waitButton {
- return waitButton_;
-}
-@end
-
-namespace hung_renderer_dialog {
-
-void ShowForTabContents(TabContents* contents) {
- if (!logging::DialogsAreSuppressed()) {
- if (!g_instance)
- g_instance = [[HungRendererController alloc]
- initWithWindowNibName:@"HungRendererDialog"];
- [g_instance showForTabContents:contents];
- }
-}
-
-// static
-void HideForTabContents(TabContents* contents) {
- if (!logging::DialogsAreSuppressed() && g_instance)
- [g_instance endForTabContents:contents];
-}
-
-} // namespace hung_renderer_dialog
diff --git a/chrome/browser/cocoa/hung_renderer_controller_unittest.mm b/chrome/browser/cocoa/hung_renderer_controller_unittest.mm
deleted file mode 100644
index e0d958f..0000000
--- a/chrome/browser/cocoa/hung_renderer_controller_unittest.mm
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (c) 2009 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>
-
-#import "base/scoped_nsobject.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/hung_renderer_controller.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-namespace {
-
-class HungRendererControllerTest : public CocoaTest {
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
- hung_renderer_controller_ = [[HungRendererController alloc]
- initWithWindowNibName:@"HungRendererDialog"];
- }
- HungRendererController* hung_renderer_controller_; // owned by its window
-};
-
-TEST_F(HungRendererControllerTest, TestShowAndClose) {
- // Doesn't test much functionality-wise, but makes sure we can
- // display and tear down a window.
- [hung_renderer_controller_ showWindow:nil];
- // Cannot call performClose:, because the close button is disabled.
- [hung_renderer_controller_ close];
-}
-
-TEST_F(HungRendererControllerTest, TestKillButton) {
- // We can't test killing a process because we have no running
- // process to kill, but we can make sure that pressing the kill
- // button closes the window.
- [hung_renderer_controller_ showWindow:nil];
- [[hung_renderer_controller_ killButton] performClick:nil];
-}
-
-TEST_F(HungRendererControllerTest, TestWaitButton) {
- // We can't test waiting because we have no running process to wait
- // for, but we can make sure that pressing the wait button closes
- // the window.
- [hung_renderer_controller_ showWindow:nil];
- [[hung_renderer_controller_ waitButton] performClick:nil];
-}
-
-} // namespace
-
diff --git a/chrome/browser/cocoa/hyperlink_button_cell.mm b/chrome/browser/cocoa/hyperlink_button_cell.mm
deleted file mode 100644
index 12c4fec..0000000
--- a/chrome/browser/cocoa/hyperlink_button_cell.mm
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/hyperlink_button_cell.h"
-
-@interface HyperlinkButtonCell (Private)
-- (NSDictionary*)linkAttributres;
-- (void)customizeButtonCell;
-@end
-
-@implementation HyperlinkButtonCell
-@dynamic textColor;
-
-+ (NSColor*)defaultTextColor {
- return [NSColor blueColor];
-}
-
-// Designated initializer.
-- (id)init {
- if ((self = [super init])) {
- [self customizeButtonCell];
- }
- return self;
-}
-
-// Initializer called when the cell is loaded from the NIB.
-- (id)initWithCoder:(NSCoder*)aDecoder {
- if ((self = [super initWithCoder:aDecoder])) {
- [self customizeButtonCell];
- }
- return self;
-}
-
-// Initializer for code-based creation.
-- (id)initTextCell:(NSString*)title {
- if ((self = [super initTextCell:title])) {
- [self customizeButtonCell];
- }
- return self;
-}
-
-// Because an NSButtonCell has multiple initializers, this method performs the
-// common cell customization code.
-- (void)customizeButtonCell {
- [self setBordered:NO];
- [self setTextColor:[HyperlinkButtonCell defaultTextColor]];
-
- CGFloat fontSize = [NSFont systemFontSizeForControlSize:[self controlSize]];
- NSFont* font = [NSFont controlContentFontOfSize:fontSize];
- [self setFont:font];
-
- // Do not change button appearance when we are pushed.
- // TODO(rsesek): Change text color to red?
- [self setHighlightsBy:NSNoCellMask];
-
- // We need to set this so that we can override |-mouseEntered:| and
- // |-mouseExited:| to change the cursor style on hover states.
- [self setShowsBorderOnlyWhileMouseInside:YES];
-}
-
-- (void)setControlSize:(NSControlSize)size {
- [super setControlSize:size];
- [self customizeButtonCell]; // recompute |font|.
-}
-
-// Creates the NSDictionary of attributes for the attributed string.
-- (NSDictionary*)linkAttributes {
- NSUInteger underlineMask = NSUnderlinePatternSolid | NSUnderlineStyleSingle;
- scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
- [[NSParagraphStyle defaultParagraphStyle] mutableCopy]);
- [paragraphStyle setAlignment:[self alignment]];
-
- return [NSDictionary dictionaryWithObjectsAndKeys:
- [self textColor], NSForegroundColorAttributeName,
- [NSNumber numberWithInt:underlineMask], NSUnderlineStyleAttributeName,
- [self font], NSFontAttributeName,
- [NSCursor pointingHandCursor], NSCursorAttributeName,
- paragraphStyle.get(), NSParagraphStyleAttributeName,
- nil
- ];
-}
-
-// Override the drawing for the cell so that the custom style attributes
-// can always be applied and so that ellipses will appear when appropriate.
-- (NSRect)drawTitle:(NSAttributedString*)title
- withFrame:(NSRect)frame
- inView:(NSView*)controlView {
- NSDictionary* linkAttributes = [self linkAttributes];
- NSString* plainTitle = [title string];
- [plainTitle drawWithRect:frame
- options:(NSStringDrawingUsesLineFragmentOrigin |
- NSStringDrawingTruncatesLastVisibleLine)
- attributes:linkAttributes];
- return frame;
-}
-
-// Override the default behavior to draw the border. Instead, change the cursor.
-- (void)mouseEntered:(NSEvent*)event {
- [[NSCursor pointingHandCursor] push];
-}
-
-- (void)mouseExited:(NSEvent*)event {
- [NSCursor pop];
-}
-
-// Setters and getters.
-- (NSColor*)textColor {
- return textColor_.get();
-}
-
-- (void)setTextColor:(NSColor*)color {
- textColor_.reset([color retain]);
-}
-
-@end
diff --git a/chrome/browser/cocoa/hyperlink_button_cell_unittest.mm b/chrome/browser/cocoa/hyperlink_button_cell_unittest.mm
deleted file mode 100644
index 16ed781..0000000
--- a/chrome/browser/cocoa/hyperlink_button_cell_unittest.mm
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) 2009 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 "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/hyperlink_button_cell.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-namespace {
-
-class HyperlinkButtonCellTest : public CocoaTest {
- public:
- HyperlinkButtonCellTest() {
- NSRect frame = NSMakeRect(0, 0, 50, 30);
- scoped_nsobject<NSButton> view([[NSButton alloc] initWithFrame:frame]);
- view_ = view.get();
- scoped_nsobject<HyperlinkButtonCell> cell(
- [[HyperlinkButtonCell alloc] initTextCell:@"Testing"]);
- cell_ = cell.get();
- [view_ setCell:cell_];
- [[test_window() contentView] addSubview:view_];
- }
-
- void TestCellCustomization(HyperlinkButtonCell* cell) {
- EXPECT_FALSE([cell isBordered]);
- EXPECT_EQ(NSNoCellMask, [cell_ highlightsBy]);
- EXPECT_TRUE([cell showsBorderOnlyWhileMouseInside]);
- EXPECT_TRUE([cell textColor]);
- }
-
- NSButton* view_;
- HyperlinkButtonCell* cell_;
-};
-
-TEST_VIEW(HyperlinkButtonCellTest, view_)
-
-// Tests the three designated intializers.
-TEST_F(HyperlinkButtonCellTest, Initializers) {
- TestCellCustomization(cell_); // |-initTextFrame:|
- scoped_nsobject<HyperlinkButtonCell> cell([[HyperlinkButtonCell alloc] init]);
- TestCellCustomization(cell.get());
-
- // Need to create a dummy archiver to test |-initWithCoder:|.
- NSData* emptyData = [NSKeyedArchiver archivedDataWithRootObject:@""];
- NSCoder* coder =
- [[[NSKeyedUnarchiver alloc] initForReadingWithData:emptyData] autorelease];
- cell.reset([[HyperlinkButtonCell alloc] initWithCoder:coder]);
- TestCellCustomization(cell);
-}
-
-// Test set color.
-TEST_F(HyperlinkButtonCellTest, SetTextColor) {
- NSColor* textColor = [NSColor redColor];
- EXPECT_NE(textColor, [cell_ textColor]);
- [cell_ setTextColor:textColor];
- EXPECT_EQ(textColor, [cell_ textColor]);
-}
-
-// Test mouse events.
-// TODO(rsesek): See if we can synthesize mouse events to more accurately
-// test this.
-TEST_F(HyperlinkButtonCellTest, MouseHover) {
- [[NSCursor disappearingItemCursor] push]; // Set a known state.
- [cell_ mouseEntered:nil];
- EXPECT_EQ([NSCursor pointingHandCursor], [NSCursor currentCursor]);
- [cell_ mouseExited:nil];
- EXPECT_EQ([NSCursor disappearingItemCursor], [NSCursor currentCursor]);
- [NSCursor pop];
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/image_utils.h b/chrome/browser/cocoa/image_utils.h
deleted file mode 100644
index 22ed80e..0000000
--- a/chrome/browser/cocoa/image_utils.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_IMAGE_UTILS_H_
-#define CHROME_BROWSER_COCOA_IMAGE_UTILS_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-@interface NSImage (FlippedAdditions)
-
-// Works like |-drawInRect:fromRect:operation:fraction:|, except that
-// if |neverFlipped| is |YES|, and the context is flipped, the a
-// transform is applied to flip it again before drawing the image.
-//
-// Compare to the 10.6 method
-// |-drawInRect:fromRect:operation:fraction:respectFlipped:hints:|.
-- (void)drawInRect:(NSRect)dstRect
- fromRect:(NSRect)srcRect
- operation:(NSCompositingOperation)op
- fraction:(CGFloat)requestedAlpha
- neverFlipped:(BOOL)neverFlipped;
-@end
-
-#endif // CHROME_BROWSER_COCOA_IMAGE_UTILS_H_
diff --git a/chrome/browser/cocoa/image_utils.mm b/chrome/browser/cocoa/image_utils.mm
deleted file mode 100644
index 80188e5..0000000
--- a/chrome/browser/cocoa/image_utils.mm
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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 "chrome/browser/cocoa/image_utils.h"
-
-@implementation NSImage (FlippedAdditions)
-
-- (void)drawInRect:(NSRect)dstRect
- fromRect:(NSRect)srcRect
- operation:(NSCompositingOperation)op
- fraction:(CGFloat)requestedAlpha
- neverFlipped:(BOOL)neverFlipped {
- NSAffineTransform *transform = nil;
-
- // Flip drawing and adjust the origin to make the image come out
- // right.
- if (neverFlipped && [[NSGraphicsContext currentContext] isFlipped]) {
- transform = [NSAffineTransform transform];
- [transform scaleXBy:1.0 yBy:-1.0];
- [transform concat];
-
- // The lower edge of the image is as far from the origin as the
- // upper edge was, plus it's on the other side of the origin.
- dstRect.origin.y -= NSMaxY(dstRect) + NSMinY(dstRect);
- }
-
- [self drawInRect:dstRect
- fromRect:srcRect
- operation:op
- fraction:requestedAlpha];
-
- // Flip drawing back, if needed.
- [transform concat];
-}
-
-@end
diff --git a/chrome/browser/cocoa/image_utils_unittest.mm b/chrome/browser/cocoa/image_utils_unittest.mm
deleted file mode 100644
index 4d97ed1..0000000
--- a/chrome/browser/cocoa/image_utils_unittest.mm
+++ /dev/null
@@ -1,138 +0,0 @@
-// 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 "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/cocoa/image_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-@interface ImageUtilsTestView : NSView {
- @private
- // Determine whether the view is flipped.
- BOOL isFlipped_;
-
- // Determines whether to draw using the new method with
- // |neverFlipped:|.
- BOOL useNeverFlipped_;
-
- // Passed to |neverFlipped:| when drawing |image_|.
- BOOL neverFlipped_;
-
- scoped_nsobject<NSImage> image_;
-}
-@property(assign, nonatomic) BOOL isFlipped;
-@property(assign, nonatomic) BOOL useNeverFlipped;
-@property(assign, nonatomic) BOOL neverFlipped;
-@end
-
-@implementation ImageUtilsTestView
-@synthesize isFlipped = isFlipped_;
-@synthesize useNeverFlipped = useNeverFlipped_;
-@synthesize neverFlipped = neverFlipped_;
-
-- (id)initWithFrame:(NSRect)rect {
- self = [super initWithFrame:rect];
- if (self) {
- rect = NSInsetRect(rect, 5.0, 5.0);
- rect.origin = NSZeroPoint;
- const NSSize imageSize = NSInsetRect(rect, 5.0, 5.0).size;
- image_.reset([[NSImage alloc] initWithSize:imageSize]);
-
- NSBezierPath* path = [NSBezierPath bezierPath];
- [path moveToPoint:NSMakePoint(NSMinX(rect), NSMinY(rect))];
- [path lineToPoint:NSMakePoint(NSMinX(rect), NSMaxY(rect))];
- [path lineToPoint:NSMakePoint(NSMaxX(rect), NSMinY(rect))];
- [path closePath];
-
- [image_ lockFocus];
- [[NSColor blueColor] setFill];
- [path fill];
- [image_ unlockFocus];
- }
- return self;
-}
-
-- (void)drawRect:(NSRect)rect {
- NSBezierPath* path = [NSBezierPath bezierPath];
- [path moveToPoint:NSMakePoint(NSMinX(rect), NSMinY(rect))];
- [path lineToPoint:NSMakePoint(NSMinX(rect), NSMaxY(rect))];
- [path lineToPoint:NSMakePoint(NSMaxX(rect), NSMinY(rect))];
- [path closePath];
-
- [[NSColor redColor] setFill];
- [path fill];
-
- rect = NSInsetRect(rect, 5.0, 5.0);
- rect = NSOffsetRect(rect, 2.0, 2.0);
-
- if (useNeverFlipped_) {
- [image_ drawInRect:rect
- fromRect:NSZeroRect
- operation:NSCompositeCopy
- fraction:1.0
- neverFlipped:neverFlipped_];
- } else {
- [image_ drawInRect:rect
- fromRect:NSZeroRect
- operation:NSCompositeCopy
- fraction:1.0];
- }
-}
-
-@end
-
-namespace {
-
-class ImageUtilTest : public CocoaTest {
- public:
- ImageUtilTest() {
- const NSRect frame = NSMakeRect(0, 0, 300, 100);
- scoped_nsobject<ImageUtilsTestView> view(
- [[ImageUtilsTestView alloc] initWithFrame: frame]);
- view_ = view.get();
- [[test_window() contentView] addSubview:view_];
- }
-
- NSData* SnapshotView() {
- [view_ display];
-
- const NSRect bounds = [view_ bounds];
-
- [view_ lockFocus];
- scoped_nsobject<NSBitmapImageRep> bitmap(
- [[NSBitmapImageRep alloc] initWithFocusedViewRect:bounds]);
- [view_ unlockFocus];
-
- return [bitmap TIFFRepresentation];
- }
-
- NSData* SnapshotViewBase() {
- [view_ setUseNeverFlipped:NO];
- return SnapshotView();
- }
-
- NSData* SnapshotViewNeverFlipped(BOOL neverFlipped) {
- [view_ setUseNeverFlipped:YES];
- [view_ setNeverFlipped:neverFlipped];
- return SnapshotView();
- }
-
- ImageUtilsTestView* view_;
-};
-
-TEST_F(ImageUtilTest, Test) {
- // When not flipped, both drawing methods return the same data.
- [view_ setIsFlipped:NO];
- NSData* baseSnapshotData = SnapshotViewBase();
- EXPECT_TRUE([baseSnapshotData isEqualToData:SnapshotViewNeverFlipped(YES)]);
- EXPECT_TRUE([baseSnapshotData isEqualToData:SnapshotViewNeverFlipped(NO)]);
-
- // When flipped, there's only a difference when the context flip is
- // not being respected.
- [view_ setIsFlipped:YES];
- baseSnapshotData = SnapshotViewBase();
- EXPECT_FALSE([baseSnapshotData isEqualToData:SnapshotViewNeverFlipped(YES)]);
- EXPECT_TRUE([baseSnapshotData isEqualToData:SnapshotViewNeverFlipped(NO)]);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/import_progress_dialog.mm b/chrome/browser/cocoa/import_progress_dialog.mm
deleted file mode 100644
index f40ae5f..0000000
--- a/chrome/browser/cocoa/import_progress_dialog.mm
+++ /dev/null
@@ -1,192 +0,0 @@
-// 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 "chrome/browser/cocoa/import_progress_dialog.h"
-
-#include "app/l10n_util.h"
-#include "app/l10n_util_mac.h"
-#include "base/logging.h"
-#include "base/mac_util.h"
-#include "base/message_loop.h"
-#import "base/scoped_nsobject.h"
-#import "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-
-namespace {
-
-// Convert ImportItem enum into the name of the ImportProgressDialogController
-// property corresponding to the text for that item, this makes the code to
-// change the values for said properties much more readable.
-NSString* keyForImportItem(importer::ImportItem item) {
- switch(item) {
- case importer::HISTORY:
- return @"historyStatusText";
- case importer::FAVORITES:
- return @"favoritesStatusText";
- case importer::PASSWORDS:
- return @"savedPasswordStatusText";
- case importer::SEARCH_ENGINES:
- return @"searchStatusText";
- default:
- DCHECK(false);
- break;
- }
- return nil;
-}
-
-} // namespace
-
-@implementation ImportProgressDialogController
-
-@synthesize explanatoryText = explanatory_text_;
-@synthesize favoritesStatusText = favorites_status_text_;
-@synthesize searchStatusText = search_status_text_;
-@synthesize savedPasswordStatusText = saved_password_status_text_;
-@synthesize historyStatusText = history_status_text_;
-
-@synthesize favoritesImportEnabled = favorites_import_enabled_;
-@synthesize searchImportEnabled = search_import_enabled_;
-@synthesize passwordImportEnabled = password_import_enabled_;
-@synthesize historyImportEnabled = history_import_enabled_;
-
-- (id)initWithImporterHost:(ImporterHost*)host
- browserName:(string16)browserName
- observer:(ImportObserver*)observer
- itemsEnabled:(int16)items {
- NSString* nib_path =
- [mac_util::MainAppBundle() pathForResource:@"ImportProgressDialog"
- ofType:@"nib"];
- self = [super initWithWindowNibPath:nib_path owner:self];
- if (self != nil) {
- importer_host_ = host;
- observer_ = observer;
- import_host_observer_bridge_.reset(new ImporterObserverBridge(self));
- importer_host_->SetObserver(import_host_observer_bridge_.get());
-
- string16 productName = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
- NSString* explanatory_text = l10n_util::GetNSStringF(
- IDS_IMPORT_PROGRESS_EXPLANATORY_TEXT_MAC,
- productName,
- browserName);
- [self setExplanatoryText:explanatory_text];
-
- progress_text_ =
- [l10n_util::GetNSStringWithFixup(IDS_IMPORT_IMPORTING_PROGRESS_TEXT_MAC)
- retain];
- done_text_ =
- [l10n_util::GetNSStringWithFixup(IDS_IMPORT_IMPORTING_DONE_TEXT_MAC)
- retain];
-
- // Enable/disable item titles.
- NSColor* disabled = [NSColor disabledControlTextColor];
- NSColor* active = [NSColor textColor];
- [self setFavoritesImportEnabled:items & importer::FAVORITES ? active :
- disabled];
- [self setSearchImportEnabled:items & importer::SEARCH_ENGINES ? active :
- disabled];
- [self setPasswordImportEnabled:items & importer::PASSWORDS ? active :
- disabled];
- [self setHistoryImportEnabled:items & importer::HISTORY ? active :
- disabled];
- }
- return self;
-}
-
-- (void)dealloc {
- [explanatory_text_ release];
- [favorites_status_text_ release];
- [search_status_text_ release];
- [saved_password_status_text_ release];
- [history_status_text_ release];
-
- [favorites_import_enabled_ release];
- [search_import_enabled_ release];
- [password_import_enabled_ release];
- [history_import_enabled_ release];
-
- [progress_text_ release];
- [done_text_ release];
-
- [super dealloc];
-}
-
-- (IBAction)showWindow:(id)sender {
- NSWindow* win = [self window];
- [win center];
- [super showWindow:nil];
-}
-
-- (void)closeDialog {
- if ([[self window] isVisible]) {
- [[self window] close];
- }
-}
-
-- (IBAction)cancel:(id)sender {
- // The ImporterHost will notify import_host_observer_bridge_ that import has
- // ended, which will trigger the ImportEnded method, in which this object is
- // released.
- importer_host_->Cancel();
-}
-
-- (void)ImportItemStarted:(importer::ImportItem)item {
- [self setValue:progress_text_ forKey:keyForImportItem(item)];
-}
-
-- (void)ImportItemEnded:(importer::ImportItem)item {
- [self setValue:done_text_ forKey:keyForImportItem(item)];
-}
-
-- (void)ImportEnded {
- importer_host_->SetObserver(NULL);
- if (observer_)
- observer_->ImportComplete();
- [self closeDialog];
- [self release];
-
- // Break out of modal event loop.
- [NSApp stopModal];
-}
-
-@end
-
-void StartImportingWithUI(gfx::NativeWindow parent_window,
- uint16 items,
- ImporterHost* coordinator,
- const importer::ProfileInfo& source_profile,
- Profile* target_profile,
- ImportObserver* observer,
- bool first_run) {
- DCHECK(items != 0);
-
- // Retrieve name of browser we're importing from and do a little dance to
- // convert wstring -> string16.
- string16 import_browser_name = WideToUTF16Hack(source_profile.description);
-
- // progress_dialog_ is responsible for deleting itself.
- ImportProgressDialogController* progress_dialog_ =
- [[ImportProgressDialogController alloc]
- initWithImporterHost:coordinator
- browserName:import_browser_name
- observer:observer
- itemsEnabled:items];
- // Call is async.
- coordinator->StartImportSettings(source_profile, target_profile, items,
- new ProfileWriter(target_profile),
- first_run);
-
- // Display the window while spinning a message loop.
- // For details on why we need a modal message loop see http://crbug.com/19169
- NSWindow* progress_window = [progress_dialog_ window];
- NSModalSession session = [NSApp beginModalSessionForWindow:progress_window];
- [progress_dialog_ showWindow:nil];
- while (true) {
- if ([NSApp runModalSession:session] != NSRunContinuesResponse)
- break;
- MessageLoop::current()->RunAllPending();
- }
- [NSApp endModalSession:session];
-}
diff --git a/chrome/browser/cocoa/import_settings_dialog.h b/chrome/browser/cocoa/import_settings_dialog.h
deleted file mode 100644
index d31433c..0000000
--- a/chrome/browser/cocoa/import_settings_dialog.h
+++ /dev/null
@@ -1,98 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_IMPORT_SETTINGS_DIALOG_H_
-#define CHROME_BROWSER_COCOA_IMPORT_SETTINGS_DIALOG_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_nsobject.h"
-#include "chrome/browser/importer/importer.h"
-
-class Profile;
-
-// Controller for the Import Bookmarks and Settings dialog. This controller
-// automatically autoreleases itself when its associated dialog is dismissed.
-@interface ImportSettingsDialogController : NSWindowController {
- @private
- NSWindow* parentWindow_; // weak
- Profile* profile_; // weak
- scoped_ptr<ImporterList> importerList_;
- scoped_nsobject<NSArray> sourceBrowsersList_;
- NSUInteger sourceBrowserIndex_;
- // The following are all bound via the properties below.
- BOOL importHistory_;
- BOOL importFavorites_;
- BOOL importPasswords_;
- BOOL importSearchEngines_;
- BOOL historyAvailable_;
- BOOL favoritesAvailable_;
- BOOL passwordsAvailable_;
- BOOL searchEnginesAvailable_;
-}
-
-// Show the import settings window. Window is displayed as an app modal dialog.
-// If the dialog is already being displayed, this method whill return with
-// no error.
-+ (void)showImportSettingsDialogForProfile:(Profile*)profile;
-
-// Called when the "Import" button is pressed.
-- (IBAction)ok:(id)sender;
-
-// Cancel button calls this.
-- (IBAction)cancel:(id)sender;
-
-// An array of ImportSettingsProfiles, provide the list of browser profiles
-// available for importing. Bound to the Browser List array controller.
-- (NSArray*)sourceBrowsersList;
-
-// Properties for bindings.
-@property(assign, nonatomic) NSUInteger sourceBrowserIndex;
-@property(assign, readonly, nonatomic) BOOL importSomething;
-// Bindings for the value of the import checkboxes.
-@property(assign, nonatomic) BOOL importHistory;
-@property(assign, nonatomic) BOOL importFavorites;
-@property(assign, nonatomic) BOOL importPasswords;
-@property(assign, nonatomic) BOOL importSearchEngines;
-// Bindings for enabling/disabling the checkboxes.
-@property(assign, readonly, nonatomic) BOOL historyAvailable;
-@property(assign, readonly, nonatomic) BOOL favoritesAvailable;
-@property(assign, readonly, nonatomic) BOOL passwordsAvailable;
-@property(assign, readonly, nonatomic) BOOL searchEnginesAvailable;
-
-@end
-
-@interface ImportSettingsDialogController (TestingAPI)
-
-// Initialize by providing an array of profile dictionaries. Exposed for
-// unit testing but also called by -[initWithProfile:].
-- (id)initWithProfiles:(NSArray*)profiles;
-
-// Return selected services to import as mapped by the ImportItem enum.
-- (uint16)servicesToImport;
-
-@end
-
-// Utility class used as array elements for sourceBrowsersList, above.
-@interface ImportSettingsProfile : NSObject {
- @private
- NSString* browserName_;
- uint16 services_; // Services as defined by enum ImportItem.
-}
-
-// Convenience creator. |services| is a bitfield of enum ImportItems.
-+ (id)importSettingsProfileWithBrowserName:(NSString*)browserName
- services:(uint16)services;
-
-// Designated initializer. |services| is a bitfield of enum ImportItems.
-- (id)initWithBrowserName:(NSString*)browserName
- services:(uint16)services; // Bitfield of enum ImportItems.
-
-@property(copy, nonatomic) NSString* browserName;
-@property(assign, nonatomic) uint16 services; // Bitfield of enum ImportItems.
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_IMPORT_SETTINGS_DIALOG_H_
diff --git a/chrome/browser/cocoa/import_settings_dialog.mm b/chrome/browser/cocoa/import_settings_dialog.mm
deleted file mode 100644
index d18dec8..0000000
--- a/chrome/browser/cocoa/import_settings_dialog.mm
+++ /dev/null
@@ -1,245 +0,0 @@
-// 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 "chrome/browser/cocoa/import_settings_dialog.h"
-
-#include "base/mac_util.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/importer/importer_data_types.h"
-#include "chrome/browser/importer/importer_list.h"
-#include "chrome/browser/profile.h"
-
-namespace {
-
-bool importSettingsDialogVisible = false;
-
-} // namespace
-
-@interface ImportSettingsDialogController ()
-
-@property(assign, readwrite, nonatomic) BOOL historyAvailable;
-@property(assign, readwrite, nonatomic) BOOL favoritesAvailable;
-@property(assign, readwrite, nonatomic) BOOL passwordsAvailable;
-@property(assign, readwrite, nonatomic) BOOL searchEnginesAvailable;
-
-@end
-
-@implementation ImportSettingsProfile
-
-@synthesize browserName = browserName_;
-@synthesize services = services_;
-
-+ (id)importSettingsProfileWithBrowserName:(NSString*)browserName
- services:(uint16)services {
- id settingsProfile = [[[ImportSettingsProfile alloc]
- initWithBrowserName:browserName
- services:services] autorelease];
- return settingsProfile;
-}
-
-- (id)initWithBrowserName:(NSString*)browserName
- services:(uint16)services {
- DCHECK(browserName && services);
- if ((self = [super init])) {
- if (browserName && services != 0) {
- browserName_ = [browserName retain];
- services_ = services;
- } else {
- [self release];
- self = nil;
- }
- }
- return self;
-}
-
-- (id)init {
- NOTREACHED(); // Should never be called.
- return [self initWithBrowserName:NULL services:0];
-}
-
-- (void)dealloc {
- [browserName_ release];
- [super dealloc];
-}
-
-@end
-
-@interface ImportSettingsDialogController (Private)
-
-// Initialize the dialog controller with either the default profile or
-// the profile for the current browser.
-- (id)initWithProfile:(Profile*)profile;
-
-// Present the app modal dialog.
-- (void)runModalDialog;
-
-// Close the modal dialog.
-- (void)closeDialog;
-
-@end
-
-@implementation ImportSettingsDialogController
-
-@synthesize sourceBrowserIndex = sourceBrowserIndex_;
-@synthesize importHistory = importHistory_;
-@synthesize importFavorites = importFavorites_;
-@synthesize importPasswords = importPasswords_;
-@synthesize importSearchEngines = importSearchEngines_;
-@synthesize historyAvailable = historyAvailable_;
-@synthesize favoritesAvailable = favoritesAvailable_;
-@synthesize passwordsAvailable = passwordsAvailable_;
-@synthesize searchEnginesAvailable = searchEnginesAvailable_;
-
-// Set bindings dependencies for importSomething property.
-+ (NSSet*)keyPathsForValuesAffectingImportSomething {
- return [NSSet setWithObjects:@"importHistory", @"importFavorites",
- @"importPasswords", @"importSearchEngines", nil];
-}
-
-+ (void)showImportSettingsDialogForProfile:(Profile*)profile {
- // Don't display if already visible.
- if (importSettingsDialogVisible)
- return;
- ImportSettingsDialogController* controller =
- [[ImportSettingsDialogController alloc] initWithProfile:profile];
- [controller runModalDialog];
-}
-
-- (id)initWithProfile:(Profile*)profile {
- // Collect profile information (profile name and the services which can
- // be imported from each) into an array of ImportSettingsProfile which
- // are bound to the Browser List array controller and the popup name
- // presentation. The services element is used to indirectly control
- // checkbox enabling.
- importerList_.reset(new ImporterList);
- ImporterList& importerList(*(importerList_.get()));
- importerList.DetectSourceProfiles();
- int profilesCount = importerList.GetAvailableProfileCount();
- // There shoule be at least the default profile so this should never be zero.
- DCHECK(profilesCount > 0);
- NSMutableArray* browserProfiles =
- [NSMutableArray arrayWithCapacity:profilesCount];
- for (int i = 0; i < profilesCount; ++i) {
- const importer::ProfileInfo& sourceProfile =
- importerList.GetSourceProfileInfoAt(i);
- NSString* browserName =
- base::SysWideToNSString(sourceProfile.description);
- uint16 browserServices = sourceProfile.services_supported;
- ImportSettingsProfile* settingsProfile =
- [ImportSettingsProfile
- importSettingsProfileWithBrowserName:browserName
- services:browserServices];
- [browserProfiles addObject:settingsProfile];
- }
- if ((self = [self initWithProfiles:browserProfiles])) {
- profile_ = profile;
- }
- return self;
-}
-
-- (id)initWithProfiles:(NSArray*)profiles {
- NSString* nibpath =
- [mac_util::MainAppBundle() pathForResource:@"ImportSettingsDialog"
- ofType:@"nib"];
- if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
- sourceBrowsersList_.reset([profiles retain]);
- // Create and initialize an importerList_ when running unit tests.
- if (!importerList_.get()) {
- importerList_.reset(new ImporterList);
- ImporterList& importerList(*(importerList_.get()));
- importerList.DetectSourceProfiles();
- }
- }
- return self;
-}
-
-- (id)init {
- return [self initWithProfile:NULL];
-}
-
-- (void)awakeFromNib {
- // Force an update of the checkbox enabled states.
- [self setSourceBrowserIndex:0];
-}
-
-// Run application modal.
-- (void)runModalDialog {
- importSettingsDialogVisible = true;
- [NSApp runModalForWindow:[self window]];
-}
-
-- (IBAction)ok:(id)sender {
- [self closeDialog];
- const importer::ProfileInfo& sourceProfile =
- importerList_.get()->GetSourceProfileInfoAt([self sourceBrowserIndex]);
- uint16 items = sourceProfile.services_supported;
- uint16 servicesToImport = items & [self servicesToImport];
- if (servicesToImport) {
- if (profile_) {
- ImporterHost* importerHost = new ExternalProcessImporterHost;
- // Note that a side effect of the following call is to cause the
- // importerHost to be disposed once the import has completed.
- StartImportingWithUI(nil, servicesToImport, importerHost,
- sourceProfile, profile_, nil, false);
- }
- } else {
- LOG(WARNING) << "There were no settings to import from '"
- << sourceProfile.description << "'.";
- }
-}
-
-- (IBAction)cancel:(id)sender {
- [self closeDialog];
-}
-
-- (void)closeDialog {
- importSettingsDialogVisible = false;
- [[self window] orderOut:self];
- [NSApp stopModal];
- [self autorelease];
-}
-
-#pragma mark Accessors
-
-- (NSArray*)sourceBrowsersList {
- return sourceBrowsersList_.get();
-}
-
-// Accessor which cascades selected-browser changes into a re-evaluation of the
-// available services and the associated checkbox enable and checked states.
-- (void)setSourceBrowserIndex:(NSUInteger)browserIndex {
- sourceBrowserIndex_ = browserIndex;
- ImportSettingsProfile* profile =
- [sourceBrowsersList_.get() objectAtIndex:browserIndex];
- uint16 items = [profile services];
- [self setHistoryAvailable:(items & importer::HISTORY) ? YES : NO];
- [self setImportHistory:[self historyAvailable]];
- [self setFavoritesAvailable:(items & importer::FAVORITES) ? YES : NO];
- [self setImportFavorites:[self favoritesAvailable]];
- [self setPasswordsAvailable:(items & importer::PASSWORDS) ? YES : NO];
- [self setImportPasswords:[self passwordsAvailable]];
- [self setSearchEnginesAvailable:(items & importer::SEARCH_ENGINES) ?
- YES : NO];
- [self setImportSearchEngines:[self searchEnginesAvailable]];
-}
-
-- (uint16)servicesToImport {
- uint16 servicesToImport = 0;
- if ([self importHistory]) servicesToImport |= importer::HISTORY;
- if ([self importFavorites]) servicesToImport |= importer::FAVORITES;
- if ([self importPasswords]) servicesToImport |= importer::PASSWORDS;
- if ([self importSearchEngines]) servicesToImport |=
- importer::SEARCH_ENGINES;
- return servicesToImport;
-}
-
-// KVO accessor which returns YES if at least one of the services
-// provided by the selected profile has been marked for importing
-// and bound to the OK button's enable property.
-- (BOOL)importSomething {
- return [self importHistory] || [self importFavorites] ||
- [self importPasswords] || [self importSearchEngines];
-}
-
-@end
diff --git a/chrome/browser/cocoa/import_settings_dialog_unittest.mm b/chrome/browser/cocoa/import_settings_dialog_unittest.mm
deleted file mode 100644
index f75a79a..0000000
--- a/chrome/browser/cocoa/import_settings_dialog_unittest.mm
+++ /dev/null
@@ -1,130 +0,0 @@
-// 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 "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/import_settings_dialog.h"
-#include "chrome/browser/importer/importer.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-using importer::HISTORY;
-using importer::FAVORITES;
-using importer::COOKIES;
-using importer::PASSWORDS;
-using importer::SEARCH_ENGINES;
-using importer::NONE;
-
-class ImportSettingsDialogTest : public CocoaTest {
- public:
- ImportSettingsDialogController* controller_;
-
- virtual void SetUp() {
- CocoaTest::SetUp();
- unsigned int safariServices =
- HISTORY | FAVORITES | COOKIES | PASSWORDS | SEARCH_ENGINES;
- ImportSettingsProfile* mockSafari =
- [ImportSettingsProfile
- importSettingsProfileWithBrowserName:@"MockSafari"
- services:safariServices];
- unsigned int firefoxServices = HISTORY | FAVORITES | COOKIES | PASSWORDS;
- ImportSettingsProfile* mockFirefox =
- [ImportSettingsProfile
- importSettingsProfileWithBrowserName:@"MockFirefox"
- services:firefoxServices];
- unsigned int caminoServices = HISTORY | COOKIES | SEARCH_ENGINES;
- ImportSettingsProfile* mockCamino =
- [ImportSettingsProfile
- importSettingsProfileWithBrowserName:@"MockCamino"
- services:caminoServices];
- NSArray* browsers = [NSArray arrayWithObjects:
- mockSafari, mockFirefox, mockCamino, nil];
- controller_ = [[ImportSettingsDialogController alloc]
- initWithProfiles:browsers];
- }
-
- virtual void TearDown() {
- controller_ = NULL;
- CocoaTest::TearDown();
- }
-};
-
-TEST_F(ImportSettingsDialogTest, CancelDialog) {
- [controller_ cancel:nil];
-}
-
-TEST_F(ImportSettingsDialogTest, ChooseVariousBrowsers) {
- // Initial choice should already be MockSafari with all items enabled.
- [controller_ setSourceBrowserIndex:0];
- EXPECT_TRUE([controller_ importHistory]);
- EXPECT_TRUE([controller_ historyAvailable]);
- EXPECT_TRUE([controller_ importFavorites]);
- EXPECT_TRUE([controller_ favoritesAvailable]);
- EXPECT_TRUE([controller_ importPasswords]);
- EXPECT_TRUE([controller_ passwordsAvailable]);
- EXPECT_TRUE([controller_ importSearchEngines]);
- EXPECT_TRUE([controller_ searchEnginesAvailable]);
- EXPECT_EQ(HISTORY | FAVORITES | PASSWORDS | SEARCH_ENGINES,
- [controller_ servicesToImport]);
-
- // Next choice we test is MockCamino.
- [controller_ setSourceBrowserIndex:2];
- EXPECT_TRUE([controller_ importHistory]);
- EXPECT_TRUE([controller_ historyAvailable]);
- EXPECT_FALSE([controller_ importFavorites]);
- EXPECT_FALSE([controller_ favoritesAvailable]);
- EXPECT_FALSE([controller_ importPasswords]);
- EXPECT_FALSE([controller_ passwordsAvailable]);
- EXPECT_TRUE([controller_ importSearchEngines]);
- EXPECT_TRUE([controller_ searchEnginesAvailable]);
- EXPECT_EQ(HISTORY | SEARCH_ENGINES, [controller_ servicesToImport]);
-
- // Next choice we test is MockFirefox.
- [controller_ setSourceBrowserIndex:1];
- EXPECT_TRUE([controller_ importHistory]);
- EXPECT_TRUE([controller_ historyAvailable]);
- EXPECT_TRUE([controller_ importFavorites]);
- EXPECT_TRUE([controller_ favoritesAvailable]);
- EXPECT_TRUE([controller_ importPasswords]);
- EXPECT_TRUE([controller_ passwordsAvailable]);
- EXPECT_FALSE([controller_ importSearchEngines]);
- EXPECT_FALSE([controller_ searchEnginesAvailable]);
- EXPECT_EQ(HISTORY | FAVORITES | PASSWORDS, [controller_ servicesToImport]);
-
- [controller_ cancel:nil];
-}
-
-TEST_F(ImportSettingsDialogTest, SetVariousSettings) {
- // Leave the choice MockSafari, but toggle the settings.
- [controller_ setImportHistory:NO];
- [controller_ setImportFavorites:NO];
- [controller_ setImportPasswords:NO];
- [controller_ setImportSearchEngines:NO];
- EXPECT_EQ(NONE, [controller_ servicesToImport]);
- EXPECT_FALSE([controller_ importSomething]);
-
- [controller_ setImportHistory:YES];
- EXPECT_EQ(HISTORY, [controller_ servicesToImport]);
- EXPECT_TRUE([controller_ importSomething]);
-
- [controller_ setImportHistory:NO];
- [controller_ setImportFavorites:YES];
- EXPECT_EQ(FAVORITES, [controller_ servicesToImport]);
- EXPECT_TRUE([controller_ importSomething]);
- [controller_ setImportFavorites:NO];
-
- [controller_ setImportPasswords:YES];
- EXPECT_EQ(PASSWORDS, [controller_ servicesToImport]);
- EXPECT_TRUE([controller_ importSomething]);
-
- [controller_ setImportPasswords:NO];
- [controller_ setImportSearchEngines:YES];
- EXPECT_EQ(SEARCH_ENGINES, [controller_ servicesToImport]);
- EXPECT_TRUE([controller_ importSomething]);
-
- [controller_ cancel:nil];
-}
diff --git a/chrome/browser/cocoa/importer_lock_dialog.h b/chrome/browser/cocoa/importer_lock_dialog.h
deleted file mode 100644
index adf3a55..0000000
--- a/chrome/browser/cocoa/importer_lock_dialog.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_IMPORTER_LOCK_DIALOG_H_
-#define CHROME_BROWSER_COCOA_IMPORTER_LOCK_DIALOG_H_
-#pragma once
-
-class ImporterHost;
-
-namespace ImportLockDialogCocoa {
-
-// This function is called by an ImporterHost, and displays the Firefox profile
-// locked warning by creating a modal NSAlert. On the closing of the alert
-// box, the ImportHost receives a callback with the message either to skip the
-// import, or to try again.
-void ShowWarning(ImporterHost* importer);
-
-}
-
-#endif // CHROME_BROWSER_COCOA_IMPORTER_LOCK_DIALOG_H_
diff --git a/chrome/browser/cocoa/info_bubble_view.h b/chrome/browser/cocoa/info_bubble_view.h
deleted file mode 100644
index 326fada..0000000
--- a/chrome/browser/cocoa/info_bubble_view.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_INFO_BUBBLE_VIEW_H_
-#define CHROME_BROWSER_COCOA_INFO_BUBBLE_VIEW_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-namespace info_bubble {
-
-const CGFloat kBubbleArrowHeight = 8.0;
-const CGFloat kBubbleArrowWidth = 15.0;
-const CGFloat kBubbleCornerRadius = 8.0;
-const CGFloat kBubbleArrowXOffset = kBubbleArrowWidth + kBubbleCornerRadius;
-
-enum BubbleArrowLocation {
- kTopLeft,
- kTopRight,
-};
-
-enum InfoBubbleType {
- kWhiteInfoBubble,
- // Gradient bubbles are deprecated, per alcor@google.com. Please use white.
- kGradientInfoBubble
-};
-
-} // namespace info_bubble
-
-// Content view for a bubble with an arrow showing arbitrary content.
-// This is where nonrectangular drawing happens.
-@interface InfoBubbleView : NSView {
- @private
- info_bubble::BubbleArrowLocation arrowLocation_;
-
- // The type simply is used to determine what sort of background it should
- // draw.
- info_bubble::InfoBubbleType bubbleType_;
-}
-
-@property (assign, nonatomic) info_bubble::BubbleArrowLocation arrowLocation;
-@property (assign, nonatomic) info_bubble::InfoBubbleType bubbleType;
-
-// Returns the point location in view coordinates of the tip of the arrow.
-- (NSPoint)arrowTip;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_INFO_BUBBLE_VIEW_H_
diff --git a/chrome/browser/cocoa/info_bubble_view.mm b/chrome/browser/cocoa/info_bubble_view.mm
deleted file mode 100644
index b54e875..0000000
--- a/chrome/browser/cocoa/info_bubble_view.mm
+++ /dev/null
@@ -1,103 +0,0 @@
-// 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 "chrome/browser/cocoa/info_bubble_view.h"
-
-#include "base/logging.h"
-#include "base/scoped_nsobject.h"
-#import "third_party/GTM/AppKit/GTMNSColor+Luminance.h"
-
-@implementation InfoBubbleView
-
-@synthesize arrowLocation = arrowLocation_;
-@synthesize bubbleType = bubbleType_;
-
-- (id)initWithFrame:(NSRect)frameRect {
- if ((self = [super initWithFrame:frameRect])) {
- arrowLocation_ = info_bubble::kTopLeft;
- bubbleType_ = info_bubble::kWhiteInfoBubble;
- }
-
- return self;
-}
-
-- (void)drawRect:(NSRect)rect {
- // Make room for the border to be seen.
- NSRect bounds = [self bounds];
- bounds.size.height -= info_bubble::kBubbleArrowHeight;
- NSBezierPath* bezier = [NSBezierPath bezierPath];
- rect.size.height -= info_bubble::kBubbleArrowHeight;
-
- // Start with a rounded rectangle.
- [bezier appendBezierPathWithRoundedRect:bounds
- xRadius:info_bubble::kBubbleCornerRadius
- yRadius:info_bubble::kBubbleCornerRadius];
-
- // Add the bubble arrow.
- CGFloat dX = 0;
- switch (arrowLocation_) {
- case info_bubble::kTopLeft:
- dX = info_bubble::kBubbleArrowXOffset;
- break;
- case info_bubble::kTopRight:
- dX = NSWidth(bounds) - info_bubble::kBubbleArrowXOffset -
- info_bubble::kBubbleArrowWidth;
- break;
- default:
- NOTREACHED();
- break;
- }
- NSPoint arrowStart = NSMakePoint(NSMinX(bounds), NSMaxY(bounds));
- arrowStart.x += dX;
- [bezier moveToPoint:NSMakePoint(arrowStart.x, arrowStart.y)];
- [bezier lineToPoint:NSMakePoint(arrowStart.x +
- info_bubble::kBubbleArrowWidth / 2.0,
- arrowStart.y +
- info_bubble::kBubbleArrowHeight)];
- [bezier lineToPoint:NSMakePoint(arrowStart.x + info_bubble::kBubbleArrowWidth,
- arrowStart.y)];
- [bezier closePath];
-
- // Then fill the inside depending on the type of bubble.
- if (bubbleType_ == info_bubble::kGradientInfoBubble) {
- NSColor* base_color = [NSColor colorWithCalibratedWhite:0.5 alpha:1.0];
- NSColor* startColor =
- [base_color gtm_colorAdjustedFor:GTMColorationLightHighlight
- faded:YES];
- NSColor* midColor =
- [base_color gtm_colorAdjustedFor:GTMColorationLightMidtone
- faded:YES];
- NSColor* endColor =
- [base_color gtm_colorAdjustedFor:GTMColorationLightShadow
- faded:YES];
- NSColor* glowColor =
- [base_color gtm_colorAdjustedFor:GTMColorationLightPenumbra
- faded:YES];
-
- scoped_nsobject<NSGradient> gradient(
- [[NSGradient alloc] initWithColorsAndLocations:startColor, 0.0,
- midColor, 0.25,
- endColor, 0.5,
- glowColor, 0.75,
- nil]);
-
- [gradient.get() drawInBezierPath:bezier angle:0.0];
- } else if (bubbleType_ == info_bubble::kWhiteInfoBubble) {
- [[NSColor whiteColor] set];
- [bezier fill];
- }
-}
-
-- (NSPoint)arrowTip {
- NSRect bounds = [self bounds];
- CGFloat tipXOffset =
- info_bubble::kBubbleArrowXOffset + info_bubble::kBubbleArrowWidth / 2.0;
- CGFloat xOffset =
- (arrowLocation_ == info_bubble::kTopRight) ? NSMaxX(bounds) - tipXOffset :
- NSMinX(bounds) + tipXOffset;
- NSPoint arrowTip = NSMakePoint(xOffset, NSMaxY(bounds));
- return arrowTip;
-}
-
-@end
diff --git a/chrome/browser/cocoa/info_bubble_view_unittest.mm b/chrome/browser/cocoa/info_bubble_view_unittest.mm
deleted file mode 100644
index 2f07c8b..0000000
--- a/chrome/browser/cocoa/info_bubble_view_unittest.mm
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2009 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/scoped_nsobject.h"
-#import "chrome/browser/cocoa/info_bubble_view.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-
-namespace {
-
-class InfoBubbleViewTest : public CocoaTest {
- public:
- InfoBubbleViewTest() {
- NSRect frame = NSMakeRect(0, 0, 100, 30);
- scoped_nsobject<InfoBubbleView> view(
- [[InfoBubbleView alloc] initWithFrame:frame]);
- view_ = view.get();
- [[test_window() contentView] addSubview:view_];
- }
-
- InfoBubbleView* view_;
-};
-
-TEST_VIEW(InfoBubbleViewTest, view_);
-
-} // namespace
diff --git a/chrome/browser/cocoa/info_bubble_window.h b/chrome/browser/cocoa/info_bubble_window.h
deleted file mode 100644
index e8d8096..0000000
--- a/chrome/browser/cocoa/info_bubble_window.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// 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 "base/scoped_ptr.h"
-#import "chrome/browser/cocoa/chrome_event_processing_window.h"
-
-class AppNotificationBridge;
-
-// A rounded window with an arrow used for example when you click on the STAR
-// button or that pops up within our first-run UI.
-@interface InfoBubbleWindow : ChromeEventProcessingWindow {
- @private
- // Is self in the process of closing.
- BOOL closing_;
- // If NO the window will close immediately instead of fading out.
- // Default YES.
- BOOL delayOnClose_;
- // Bridge to proxy Chrome notifications to the window.
- scoped_ptr<AppNotificationBridge> notificationBridge_;
-}
-
-// Returns YES if the window is in the process of closing.
-// Can't use "windowWillClose" notification because that will be sent
-// after the closing animation has completed.
-- (BOOL)isClosing;
-
-@property (nonatomic) BOOL delayOnClose;
-
-@end
diff --git a/chrome/browser/cocoa/info_bubble_window.mm b/chrome/browser/cocoa/info_bubble_window.mm
deleted file mode 100644
index ea3ebcd..0000000
--- a/chrome/browser/cocoa/info_bubble_window.mm
+++ /dev/null
@@ -1,222 +0,0 @@
-// 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 "chrome/browser/cocoa/info_bubble_window.h"
-
-#include "base/basictypes.h"
-#include "base/logging.h"
-#include "base/scoped_nsobject.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/notification_type.h"
-#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
-
-namespace {
-const CGFloat kOrderInSlideOffset = 10;
-const NSTimeInterval kOrderInAnimationDuration = 0.2;
-const NSTimeInterval kOrderOutAnimationDuration = 0.15;
-// The minimum representable time interval. This can be used as the value
-// passed to +[NSAnimationContext setDuration:] to stop an in-progress
-// animation as quickly as possible.
-const NSTimeInterval kMinimumTimeInterval =
- std::numeric_limits<NSTimeInterval>::min();
-}
-
-@interface InfoBubbleWindow(Private)
-- (void)appIsTerminating;
-- (void)finishCloseAfterAnimation;
-@end
-
-// A helper class to proxy app notifications to the window.
-class AppNotificationBridge : public NotificationObserver {
- public:
- explicit AppNotificationBridge(InfoBubbleWindow* owner) : owner_(owner) {
- registrar_.Add(this, NotificationType::APP_TERMINATING,
- NotificationService::AllSources());
- }
-
- // Overridden from NotificationObserver.
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- switch (type.value) {
- case NotificationType::APP_TERMINATING:
- [owner_ appIsTerminating];
- break;
- default:
- NOTREACHED() << L"Unexpected notification";
- }
- }
-
- private:
- // The object we need to inform when we get a notification. Weak. Owns us.
- InfoBubbleWindow* owner_;
-
- // Used for registering to receive notifications and automatic clean up.
- NotificationRegistrar registrar_;
-
- DISALLOW_COPY_AND_ASSIGN(AppNotificationBridge);
-};
-
-// A delegate object for watching the alphaValue animation on InfoBubbleWindows.
-// An InfoBubbleWindow instance cannot be the delegate for its own animation
-// because CAAnimations retain their delegates, and since the InfoBubbleWindow
-// retains its animations a retain loop would be formed.
-@interface InfoBubbleWindowCloser : NSObject {
- @private
- InfoBubbleWindow* window_; // Weak. Window to close.
-}
-- (id)initWithWindow:(InfoBubbleWindow*)window;
-@end
-
-@implementation InfoBubbleWindowCloser
-
-- (id)initWithWindow:(InfoBubbleWindow*)window {
- if ((self = [super init])) {
- window_ = window;
- }
- return self;
-}
-
-// Callback for the alpha animation. Closes window_ if appropriate.
-- (void)animationDidStop:(CAAnimation*)anim finished:(BOOL)flag {
- // When alpha reaches zero, close window_.
- if ([window_ alphaValue] == 0.0) {
- [window_ finishCloseAfterAnimation];
- }
-}
-
-@end
-
-
-@implementation InfoBubbleWindow
-
-@synthesize delayOnClose = delayOnClose_;
-
-- (id)initWithContentRect:(NSRect)contentRect
- styleMask:(NSUInteger)aStyle
- backing:(NSBackingStoreType)bufferingType
- defer:(BOOL)flag {
- if ((self = [super initWithContentRect:contentRect
- styleMask:NSBorderlessWindowMask
- backing:bufferingType
- defer:flag])) {
- [self setBackgroundColor:[NSColor clearColor]];
- [self setExcludedFromWindowsMenu:YES];
- [self setOpaque:NO];
- [self setHasShadow:YES];
- delayOnClose_ = YES;
- notificationBridge_.reset(new AppNotificationBridge(self));
-
- // Start invisible. Will be made visible when ordered front.
- [self setAlphaValue:0.0];
-
- // Set up alphaValue animation so that self is delegate for the animation.
- // Setting up the delegate is required so that the
- // animationDidStop:finished: callback can be handled.
- // Notice that only the alphaValue Animation is replaced in case
- // superclasses set up animations.
- CAAnimation* alphaAnimation = [CABasicAnimation animation];
- scoped_nsobject<InfoBubbleWindowCloser> delegate(
- [[InfoBubbleWindowCloser alloc] initWithWindow:self]);
- [alphaAnimation setDelegate:delegate];
- NSMutableDictionary* animations =
- [NSMutableDictionary dictionaryWithDictionary:[self animations]];
- [animations setObject:alphaAnimation forKey:@"alphaValue"];
- [self setAnimations:animations];
- }
- return self;
-}
-
-// According to
-// http://www.cocoabuilder.com/archive/message/cocoa/2006/6/19/165953,
-// NSBorderlessWindowMask windows cannot become key or main. In this
-// case, this is not a desired behavior. As an example, the bubble could have
-// buttons.
-- (BOOL)canBecomeKeyWindow {
- return YES;
-}
-
-- (void)close {
- // Block the window from receiving events while it fades out.
- closing_ = YES;
-
- if (!delayOnClose_) {
- [self finishCloseAfterAnimation];
- } else {
- // Apply animations to hide self.
- [NSAnimationContext beginGrouping];
- [[NSAnimationContext currentContext]
- gtm_setDuration:kOrderOutAnimationDuration
- eventMask:NSLeftMouseUpMask];
- [[self animator] setAlphaValue:0.0];
- [NSAnimationContext endGrouping];
- }
-}
-
-// If the app is terminating but the window is still fading out, cancel the
-// animation and close the window to prevent it from leaking.
-// See http://crbug.com/37717
-- (void)appIsTerminating {
- if (!delayOnClose_)
- return; // The close has already happened with no Core Animation.
-
- // Cancel the current animation so that it closes immediately, triggering
- // |finishCloseAfterAnimation|.
- [NSAnimationContext beginGrouping];
- [[NSAnimationContext currentContext] setDuration:kMinimumTimeInterval];
- [[self animator] setAlphaValue:0.0];
- [NSAnimationContext endGrouping];
-}
-
-// Called by InfoBubbleWindowCloser when the window is to be really closed
-// after the fading animation is complete.
-- (void)finishCloseAfterAnimation {
- if (closing_)
- [super close];
-}
-
-// Adds animation for info bubbles being ordered to the front.
-- (void)orderWindow:(NSWindowOrderingMode)orderingMode
- relativeTo:(NSInteger)otherWindowNumber {
- // According to the documentation '0' is the otherWindowNumber when the window
- // is ordered front.
- if (orderingMode == NSWindowAbove && otherWindowNumber == 0) {
- // Order self appropriately assuming that its alpha is zero as set up
- // in the designated initializer.
- [super orderWindow:orderingMode relativeTo:otherWindowNumber];
-
- // Set up frame so it can be adjust down by a few pixels.
- NSRect frame = [self frame];
- NSPoint newOrigin = frame.origin;
- newOrigin.y += kOrderInSlideOffset;
- [self setFrameOrigin:newOrigin];
-
- // Apply animations to show and move self.
- [NSAnimationContext beginGrouping];
- // The star currently triggers on mouse down, not mouse up.
- [[NSAnimationContext currentContext]
- gtm_setDuration:kOrderInAnimationDuration
- eventMask:NSLeftMouseUpMask|NSLeftMouseDownMask];
- [[self animator] setAlphaValue:1.0];
- [[self animator] setFrame:frame display:YES];
- [NSAnimationContext endGrouping];
- } else {
- [super orderWindow:orderingMode relativeTo:otherWindowNumber];
- }
-}
-
-// If the window is currently animating a close, block all UI events to the
-// window.
-- (void)sendEvent:(NSEvent*)theEvent {
- if (!closing_)
- [super sendEvent:theEvent];
-}
-
-- (BOOL)isClosing {
- return closing_;
-}
-
-@end
diff --git a/chrome/browser/cocoa/info_bubble_window_unittest.mm b/chrome/browser/cocoa/info_bubble_window_unittest.mm
deleted file mode 100644
index 11a07fe..0000000
--- a/chrome/browser/cocoa/info_bubble_window_unittest.mm
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) 2009 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/scoped_ptr.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/cocoa/info_bubble_window.h"
-
-class InfoBubbleWindowTest : public CocoaTest {};
-
-TEST_F(InfoBubbleWindowTest, Basics) {
- InfoBubbleWindow* window =
- [[InfoBubbleWindow alloc] initWithContentRect:NSMakeRect(0, 0, 10, 10)
- styleMask:NSBorderlessWindowMask
- backing:NSBackingStoreBuffered
- defer:NO];
- EXPECT_TRUE([window canBecomeKeyWindow]);
- EXPECT_FALSE([window canBecomeMainWindow]);
-
- EXPECT_TRUE([window isExcludedFromWindowsMenu]);
- [window close];
-}
diff --git a/chrome/browser/cocoa/infobar.h b/chrome/browser/cocoa/infobar.h
deleted file mode 100644
index 9c8ed05..0000000
--- a/chrome/browser/cocoa/infobar.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_INFOBAR_H_
-#define CHROME_BROWSER_COCOA_INFOBAR_H_
-#pragma once
-
-#include "base/logging.h" // for DCHECK
-
-@class InfoBarController;
-
-// A C++ wrapper around an Objective-C InfoBarController. This class
-// exists solely to be the return value for InfoBarDelegate::CreateInfoBar(),
-// as defined in chrome/browser/tab_contents/infobar_delegate.h. This
-// class would be analogous to the various bridge classes we already
-// have, but since there is no pre-defined InfoBar interface, it is
-// easier to simply throw away this object and deal with the
-// controller directly rather than pass messages through a bridge.
-//
-// Callers should delete the returned InfoBar immediately after
-// calling CreateInfoBar(), as the returned InfoBar* object is not
-// pointed to by anyone. Expected usage:
-//
-// scoped_ptr<InfoBar> infobar(delegate->CreateInfoBar());
-// InfoBarController* controller = infobar->controller();
-// // Do something with the controller, and save a pointer so it can be
-// // deleted later. |infobar| will be deleted automatically.
-
-class InfoBar {
- public:
- InfoBar(InfoBarController* controller) {
- DCHECK(controller);
- controller_ = controller;
- }
-
- InfoBarController* controller() {
- return controller_;
- }
-
- private:
- // Pointer to the infobar controller. Is never null.
- InfoBarController* controller_; // weak
-
- DISALLOW_COPY_AND_ASSIGN(InfoBar);
-};
-
-#endif // CHROME_BROWSER_COCOA_INFOBAR_H_
diff --git a/chrome/browser/cocoa/infobar_container_controller.h b/chrome/browser/cocoa/infobar_container_controller.h
deleted file mode 100644
index 495b6e8..0000000
--- a/chrome/browser/cocoa/infobar_container_controller.h
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_INFOBAR_CONTAINER_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_INFOBAR_CONTAINER_CONTROLLER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-#import "chrome/browser/cocoa/view_resizer.h"
-#include "chrome/common/notification_registrar.h"
-
-@class InfoBarController;
-class InfoBarDelegate;
-class InfoBarNotificationObserver;
-class TabContents;
-class TabStripModel;
-
-// Protocol for basic container methods, as needed by an InfoBarController.
-// This protocol exists to make mocking easier in unittests.
-@protocol InfoBarContainer
-- (void)removeDelegate:(InfoBarDelegate*)delegate;
-- (void)removeController:(InfoBarController*)controller;
-@end
-
-// Controller for the infobar container view, which is the superview
-// of all the infobar views. This class owns zero or more
-// InfoBarControllers, which manage the infobar views. This class
-// also receives tab strip model notifications and handles
-// adding/removing infobars when needed.
-@interface InfoBarContainerController : NSViewController <ViewResizer,
- InfoBarContainer> {
- @private
- // Needed to send resize messages when infobars are added or removed.
- id<ViewResizer> resizeDelegate_; // weak
-
- // The TabContents we are currently showing infobars for.
- TabContents* currentTabContents_; // weak
-
- // Holds the InfoBarControllers currently owned by this container.
- scoped_nsobject<NSMutableArray> infobarControllers_;
-
- // Lets us registers for INFOBAR_ADDED/INFOBAR_REMOVED
- // notifications. The actual notifications are sent to the
- // InfoBarNotificationObserver object, which proxies them back to us.
- NotificationRegistrar registrar_;
- scoped_ptr<InfoBarNotificationObserver> infoBarObserver_;
-}
-
-- (id)initWithResizeDelegate:(id<ViewResizer>)resizeDelegate;
-
-// Informs the selected TabContents that the infobars for the given
-// |delegate| need to be removed. Does not remove any infobar views
-// directly, as they will be removed when handling the subsequent
-// INFOBAR_REMOVED notification. Does not notify |delegate| that the
-// infobar was closed.
-- (void)removeDelegate:(InfoBarDelegate*)delegate;
-
-// Removes |controller| from the list of controllers in this container and
-// removes its view from the view hierarchy. This method is safe to call while
-// |controller| is still on the call stack.
-- (void)removeController:(InfoBarController*)controller;
-
-// Modifies this container to display infobars for the given
-// |contents|. Registers for INFOBAR_ADDED and INFOBAR_REMOVED
-// notifications for |contents|. If we are currently showing any
-// infobars, removes them first and deregisters for any
-// notifications. |contents| can be NULL, in which case no infobars
-// are shown and no notifications are registered for.
-- (void)changeTabContents:(TabContents*)contents;
-
-// Stripped down version of TabStripModelObserverBridge:tabDetachedWithContents.
-// Forwarded by BWC. Removes all infobars and deregisters for any notifications
-// if |contents| is the current tab contents.
-- (void)tabDetachedWithContents:(TabContents*)contents;
-
-@end
-
-
-@interface InfoBarContainerController (ForTheObserverAndTesting)
-
-// Adds an infobar view for the given delegate.
-- (void)addInfoBar:(InfoBarDelegate*)delegate animate:(BOOL)animate;
-
-// Closes all the infobar views for a given delegate, either immediately or by
-// starting a close animation.
-- (void)closeInfoBarsForDelegate:(InfoBarDelegate*)delegate
- animate:(BOOL)animate;
-
-// Replaces all info bars for the delegate with a new info bar.
-// This simply calls closeInfoBarsForDelegate: and then addInfoBar:.
-- (void)replaceInfoBarsForDelegate:(InfoBarDelegate*)old_delegate
- with:(InfoBarDelegate*)new_delegate;
-
-// Positions the infobar views in the container view and notifies
-// |browser_controller_| that it needs to resize the container view.
-- (void)positionInfoBarsAndRedraw;
-
-@end
-
-
-@interface InfoBarContainerController (JustForTesting)
-
-// Removes all infobar views. Callers must call
-// positionInfoBarsAndRedraw() after calling this method.
-- (void)removeAllInfoBars;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_INFOBAR_CONTAINER_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/infobar_container_controller.mm b/chrome/browser/cocoa/infobar_container_controller.mm
deleted file mode 100644
index 7fe8aed..0000000
--- a/chrome/browser/cocoa/infobar_container_controller.mm
+++ /dev/null
@@ -1,228 +0,0 @@
-// 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.
-
-#include "base/logging.h"
-#include "base/mac_util.h"
-#import "chrome/browser/cocoa/animatable_view.h"
-#include "chrome/browser/cocoa/infobar.h"
-#import "chrome/browser/cocoa/infobar_container_controller.h"
-#import "chrome/browser/cocoa/infobar_controller.h"
-#import "chrome/browser/cocoa/view_id_util.h"
-#include "chrome/browser/tab_contents/infobar_delegate.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/notification_service.h"
-#include "skia/ext/skia_utils_mac.h"
-
-// C++ class that receives INFOBAR_ADDED and INFOBAR_REMOVED
-// notifications and proxies them back to |controller|.
-class InfoBarNotificationObserver : public NotificationObserver {
- public:
- InfoBarNotificationObserver(InfoBarContainerController* controller)
- : controller_(controller) {
- }
-
- private:
- // NotificationObserver implementation
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- switch (type.value) {
- case NotificationType::TAB_CONTENTS_INFOBAR_ADDED:
- [controller_ addInfoBar:Details<InfoBarDelegate>(details).ptr()
- animate:YES];
- break;
- case NotificationType::TAB_CONTENTS_INFOBAR_REMOVED:
- [controller_
- closeInfoBarsForDelegate:Details<InfoBarDelegate>(details).ptr()
- animate:YES];
- break;
- case NotificationType::TAB_CONTENTS_INFOBAR_REPLACED: {
- typedef std::pair<InfoBarDelegate*, InfoBarDelegate*>
- InfoBarDelegatePair;
- InfoBarDelegatePair* delegates =
- Details<InfoBarDelegatePair>(details).ptr();
- [controller_
- replaceInfoBarsForDelegate:delegates->first with:delegates->second];
- break;
- }
- default:
- NOTREACHED(); // we don't ask for anything else!
- break;
- }
-
- [controller_ positionInfoBarsAndRedraw];
- }
-
- InfoBarContainerController* controller_; // weak, owns us.
-};
-
-
-@interface InfoBarContainerController (PrivateMethods)
-// Returns the desired height of the container view, computed by
-// adding together the heights of all its subviews.
-- (CGFloat)desiredHeight;
-
-@end
-
-
-@implementation InfoBarContainerController
-- (id)initWithResizeDelegate:(id<ViewResizer>)resizeDelegate {
- DCHECK(resizeDelegate);
- if ((self = [super initWithNibName:@"InfoBarContainer"
- bundle:mac_util::MainAppBundle()])) {
- resizeDelegate_ = resizeDelegate;
- infoBarObserver_.reset(new InfoBarNotificationObserver(self));
-
- // NSMutableArray needs an initial capacity, and we rarely ever see
- // more than two infobars at a time, so that seems like a good choice.
- infobarControllers_.reset([[NSMutableArray alloc] initWithCapacity:2]);
- }
- return self;
-}
-
-- (void)dealloc {
- DCHECK([infobarControllers_ count] == 0);
- view_id_util::UnsetID([self view]);
- [super dealloc];
-}
-
-- (void)awakeFromNib {
- // The info bar container view is an ordinary NSView object, so we set its
- // ViewID here.
- view_id_util::SetID([self view], VIEW_ID_INFO_BAR_CONTAINER);
-}
-
-- (void)removeDelegate:(InfoBarDelegate*)delegate {
- DCHECK(currentTabContents_);
- currentTabContents_->RemoveInfoBar(delegate);
-}
-
-- (void)removeController:(InfoBarController*)controller {
- if (![infobarControllers_ containsObject:controller])
- return;
-
- // This code can be executed while InfoBarController is still on the stack, so
- // we retain and autorelease the controller to prevent it from being
- // dealloc'ed too early.
- [[controller retain] autorelease];
- [[controller view] removeFromSuperview];
- [infobarControllers_ removeObject:controller];
- [self positionInfoBarsAndRedraw];
-}
-
-- (void)changeTabContents:(TabContents*)contents {
- registrar_.RemoveAll();
- [self removeAllInfoBars];
-
- currentTabContents_ = contents;
- if (currentTabContents_) {
- for (int i = 0; i < currentTabContents_->infobar_delegate_count(); ++i) {
- [self addInfoBar:currentTabContents_->GetInfoBarDelegateAt(i)
- animate:NO];
- }
-
- Source<TabContents> source(currentTabContents_);
- registrar_.Add(infoBarObserver_.get(),
- NotificationType::TAB_CONTENTS_INFOBAR_ADDED, source);
- registrar_.Add(infoBarObserver_.get(),
- NotificationType::TAB_CONTENTS_INFOBAR_REMOVED, source);
- registrar_.Add(infoBarObserver_.get(),
- NotificationType::TAB_CONTENTS_INFOBAR_REPLACED, source);
- }
-
- [self positionInfoBarsAndRedraw];
-}
-
-- (void)tabDetachedWithContents:(TabContents*)contents {
- if (currentTabContents_ == contents)
- [self changeTabContents:NULL];
-}
-
-- (void)resizeView:(NSView*)view newHeight:(CGFloat)height {
- NSRect frame = [view frame];
- frame.size.height = height;
- [view setFrame:frame];
- [self positionInfoBarsAndRedraw];
-}
-
-- (void)setAnimationInProgress:(BOOL)inProgress {
- if ([resizeDelegate_ respondsToSelector:@selector(setAnimationInProgress:)])
- [resizeDelegate_ setAnimationInProgress:inProgress];
-}
-
-@end
-
-@implementation InfoBarContainerController (PrivateMethods)
-
-- (CGFloat)desiredHeight {
- CGFloat height = 0;
- for (InfoBarController* controller in infobarControllers_.get())
- height += NSHeight([[controller view] frame]);
- return height;
-}
-
-- (void)addInfoBar:(InfoBarDelegate*)delegate animate:(BOOL)animate {
- scoped_ptr<InfoBar> infobar(delegate->CreateInfoBar());
- InfoBarController* controller = infobar->controller();
- [controller setContainerController:self];
- [[controller animatableView] setResizeDelegate:self];
- [[self view] addSubview:[controller view]];
- [infobarControllers_ addObject:[controller autorelease]];
-
- if (animate)
- [controller animateOpen];
- else
- [controller open];
-}
-
-- (void)closeInfoBarsForDelegate:(InfoBarDelegate*)delegate
- animate:(BOOL)animate {
- for (InfoBarController* controller in
- [NSArray arrayWithArray:infobarControllers_.get()]) {
- if ([controller delegate] == delegate) {
- if (animate)
- [controller animateClosed];
- else
- [controller close];
- }
- }
-}
-
-- (void)replaceInfoBarsForDelegate:(InfoBarDelegate*)old_delegate
- with:(InfoBarDelegate*)new_delegate {
- [self closeInfoBarsForDelegate:old_delegate animate:NO];
- [self addInfoBar:new_delegate animate:NO];
-}
-
-- (void)removeAllInfoBars {
- for (InfoBarController* controller in infobarControllers_.get()) {
- [[controller animatableView] stopAnimation];
- [[controller view] removeFromSuperview];
- }
- [infobarControllers_ removeAllObjects];
-}
-
-- (void)positionInfoBarsAndRedraw {
- NSRect containerBounds = [[self view] bounds];
- int minY = 0;
-
- // Stack the infobars at the bottom of the view, starting with the
- // last infobar and working our way to the front of the array. This
- // way we ensure that the first infobar added shows up on top, with
- // the others below.
- for (InfoBarController* controller in
- [infobarControllers_ reverseObjectEnumerator]) {
- NSView* view = [controller view];
- NSRect frame = [view frame];
- frame.origin.x = NSMinX(containerBounds);
- frame.size.width = NSWidth(containerBounds);
- frame.origin.y = minY;
- minY += frame.size.height;
- [view setFrame:frame];
- }
-
- [resizeDelegate_ resizeView:[self view] newHeight:[self desiredHeight]];
-}
-
-@end
diff --git a/chrome/browser/cocoa/infobar_container_controller_unittest.mm b/chrome/browser/cocoa/infobar_container_controller_unittest.mm
deleted file mode 100644
index b9f74c7..0000000
--- a/chrome/browser/cocoa/infobar_container_controller_unittest.mm
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright (c) 2009 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 "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/infobar_container_controller.h"
-#include "chrome/browser/cocoa/infobar_test_helper.h"
-#import "chrome/browser/cocoa/view_resizer_pong.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-namespace {
-
-class InfoBarContainerControllerTest : public CocoaTest {
- virtual void SetUp() {
- CocoaTest::SetUp();
- resizeDelegate_.reset([[ViewResizerPong alloc] init]);
- ViewResizerPong *viewResizer = resizeDelegate_.get();
- controller_ =
- [[InfoBarContainerController alloc] initWithResizeDelegate:viewResizer];
- NSView* view = [controller_ view];
- [[test_window() contentView] addSubview:view];
- }
-
- virtual void TearDown() {
- [[controller_ view] removeFromSuperviewWithoutNeedingDisplay];
- [controller_ release];
- CocoaTest::TearDown();
- }
-
- public:
- scoped_nsobject<ViewResizerPong> resizeDelegate_;
- InfoBarContainerController* controller_;
-};
-
-TEST_VIEW(InfoBarContainerControllerTest, [controller_ view])
-
-TEST_F(InfoBarContainerControllerTest, BWCPong) {
- // Call positionInfoBarsAndResize and check that |resizeDelegate_| got a
- // resize message.
- [resizeDelegate_ setHeight:-1];
- [controller_ positionInfoBarsAndRedraw];
- EXPECT_NE(-1, [resizeDelegate_ height]);
-}
-
-TEST_F(InfoBarContainerControllerTest, AddAndRemoveInfoBars) {
- NSView* view = [controller_ view];
-
- // Add three infobars, one of each type, and then remove them.
- // After each step check to make sure we have the correct number of
- // infobar subviews.
- MockAlertInfoBarDelegate alertDelegate;
- MockLinkInfoBarDelegate linkDelegate;
- MockConfirmInfoBarDelegate confirmDelegate;
-
- [controller_ addInfoBar:&alertDelegate animate:NO];
- EXPECT_EQ(1U, [[view subviews] count]);
-
- [controller_ addInfoBar:&linkDelegate animate:NO];
- EXPECT_EQ(2U, [[view subviews] count]);
-
- [controller_ addInfoBar:&confirmDelegate animate:NO];
- EXPECT_EQ(3U, [[view subviews] count]);
-
- // Just to mix things up, remove them in a different order.
- [controller_ closeInfoBarsForDelegate:&linkDelegate animate:NO];
- EXPECT_EQ(2U, [[view subviews] count]);
-
- [controller_ closeInfoBarsForDelegate:&confirmDelegate animate:NO];
- EXPECT_EQ(1U, [[view subviews] count]);
-
- [controller_ closeInfoBarsForDelegate:&alertDelegate animate:NO];
- EXPECT_EQ(0U, [[view subviews] count]);
-}
-
-TEST_F(InfoBarContainerControllerTest, RemoveAllInfoBars) {
- NSView* view = [controller_ view];
-
- // Add three infobars and then remove them all.
- MockAlertInfoBarDelegate alertDelegate;
- MockLinkInfoBarDelegate linkDelegate;
- MockConfirmInfoBarDelegate confirmDelegate;
-
- [controller_ addInfoBar:&alertDelegate animate:NO];
- [controller_ addInfoBar:&linkDelegate animate:NO];
- [controller_ addInfoBar:&confirmDelegate animate:NO];
- EXPECT_EQ(3U, [[view subviews] count]);
-
- [controller_ removeAllInfoBars];
- EXPECT_EQ(0U, [[view subviews] count]);
-}
-} // namespace
diff --git a/chrome/browser/cocoa/infobar_controller.h b/chrome/browser/cocoa/infobar_controller.h
deleted file mode 100644
index 265700c..0000000
--- a/chrome/browser/cocoa/infobar_controller.h
+++ /dev/null
@@ -1,106 +0,0 @@
-// 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>
-
-#import "base/cocoa_protocols_mac.h"
-#include "base/scoped_nsobject.h"
-
-@class AnimatableView;
-@class HoverCloseButton;
-@protocol InfoBarContainer;
-class InfoBarDelegate;
-@class InfoBarGradientView;
-
-// A controller for an infobar in the browser window. There is one
-// controller per infobar view. The base InfoBarController is able to
-// draw an icon, a text message, and a close button. Subclasses can
-// override addAdditionalControls to customize the UI.
-@interface InfoBarController : NSViewController<NSTextViewDelegate> {
- @private
- id<InfoBarContainer> containerController_; // weak, owns us
- BOOL infoBarClosing_;
-
- @protected
- IBOutlet InfoBarGradientView* infoBarView_;
- IBOutlet NSImageView* image_;
- IBOutlet NSTextField* labelPlaceholder_;
- IBOutlet NSButton* okButton_;
- IBOutlet NSButton* cancelButton_;
- IBOutlet HoverCloseButton* closeButton_;
-
- // In rare instances, it can be possible for |delegate_| to delete itself
- // while this controller is still alive. Always check |delegate_| against
- // NULL before using it.
- InfoBarDelegate* delegate_; // weak, can be NULL
-
- // Text fields don't work as well with embedded links as text views, but
- // text views cannot conveniently be created in IB. The xib file contains
- // a text field |labelPlaceholder_| that's replaced by this text view |label_|
- // in -awakeFromNib.
- scoped_nsobject<NSTextView> label_;
-};
-
-// Initializes a new InfoBarController.
-- (id)initWithDelegate:(InfoBarDelegate*)delegate;
-
-// Called when someone clicks on the OK or Cancel buttons. Subclasses
-// must override if they do not hide the buttons.
-- (void)ok:(id)sender;
-- (void)cancel:(id)sender;
-
-// Called when someone clicks on the close button. Dismisses the
-// infobar without taking any action.
-- (IBAction)dismiss:(id)sender;
-
-// Returns a pointer to this controller's view, cast as an AnimatableView.
-- (AnimatableView*)animatableView;
-
-// Open or animate open the infobar.
-- (void)open;
-- (void)animateOpen;
-
-// Close or animate close the infobar.
-- (void)close;
-- (void)animateClosed;
-
-// Subclasses can override this method to add additional controls to
-// the infobar view. This method is called by awakeFromNib. The
-// default implementation does nothing.
-- (void)addAdditionalControls;
-
-// Sets the info bar message to the specified |message|.
-- (void)setLabelToMessage:(NSString*)message;
-
-// Removes the OK and Cancel buttons and resizes the textfield to use the
-// space.
-- (void)removeButtons;
-
-@property(nonatomic, assign) id<InfoBarContainer> containerController;
-@property(nonatomic, readonly) InfoBarDelegate* delegate;
-
-@end
-
-/////////////////////////////////////////////////////////////////////////
-// InfoBarController subclasses, one for each InfoBarDelegate
-// subclass. Each of these subclasses overrides addAdditionalControls to
-// configure its view as necessary.
-
-@interface AlertInfoBarController : InfoBarController
-@end
-
-
-@interface LinkInfoBarController : InfoBarController
-// Called when there is a click on the link in the infobar.
-- (void)linkClicked;
-@end
-
-
-@interface ConfirmInfoBarController : InfoBarController
-// Called when the OK and Cancel buttons are clicked.
-- (IBAction)ok:(id)sender;
-- (IBAction)cancel:(id)sender;
-// Called when there is a click on the link in the infobar.
-- (void)linkClicked;
-@end
diff --git a/chrome/browser/cocoa/infobar_controller.mm b/chrome/browser/cocoa/infobar_controller.mm
deleted file mode 100644
index 8ccc9c5..0000000
--- a/chrome/browser/cocoa/infobar_controller.mm
+++ /dev/null
@@ -1,534 +0,0 @@
-// 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 "base/logging.h" // for NOTREACHED()
-#include "base/mac_util.h"
-#include "base/sys_string_conversions.h"
-#import "chrome/browser/cocoa/animatable_view.h"
-#include "chrome/browser/cocoa/event_utils.h"
-#include "chrome/browser/cocoa/infobar.h"
-#import "chrome/browser/cocoa/infobar_container_controller.h"
-#import "chrome/browser/cocoa/infobar_controller.h"
-#include "chrome/browser/tab_contents/infobar_delegate.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "skia/ext/skia_utils_mac.h"
-#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-#include "webkit/glue/window_open_disposition.h"
-
-namespace {
-// Durations set to match the default SlideAnimation duration.
-const float kAnimateOpenDuration = 0.12;
-const float kAnimateCloseDuration = 0.12;
-}
-
-// This simple subclass of |NSTextView| just doesn't show the (text) cursor
-// (|NSTextView| displays the cursor with full keyboard accessibility enabled).
-@interface InfoBarTextView : NSTextView
-- (void)fixupCursor;
-@end
-
-@implementation InfoBarTextView
-
-// Never draw the insertion point (otherwise, it shows up without any user
-// action if full keyboard accessibility is enabled).
-- (BOOL)shouldDrawInsertionPoint {
- return NO;
-}
-
-- (NSRange)selectionRangeForProposedRange:(NSRange)proposedSelRange
- granularity:(NSSelectionGranularity)granularity {
- // Do not allow selections.
- return NSMakeRange(0, 0);
-}
-
-// Convince NSTextView to not show an I-Beam cursor when the cursor is over the
-// text view but not over actual text.
-//
-// http://www.mail-archive.com/cocoa-dev@lists.apple.com/msg10791.html
-// "NSTextView sets the cursor over itself dynamically, based on considerations
-// including the text under the cursor. It does so in -mouseEntered:,
-// -mouseMoved:, and -cursorUpdate:, so those would be points to consider
-// overriding."
-- (void)mouseMoved:(NSEvent*)e {
- [super mouseMoved:e];
- [self fixupCursor];
-}
-
-- (void)mouseEntered:(NSEvent*)e {
- [super mouseEntered:e];
- [self fixupCursor];
-}
-
-- (void)cursorUpdate:(NSEvent*)e {
- [super cursorUpdate:e];
- [self fixupCursor];
-}
-
-- (void)fixupCursor {
- if ([[NSCursor currentCursor] isEqual:[NSCursor IBeamCursor]])
- [[NSCursor arrowCursor] set];
-}
-
-@end
-
-@interface InfoBarController (PrivateMethods)
-// Sets |label_| based on |labelPlaceholder_|, sets |labelPlaceholder_| to nil.
-- (void)initializeLabel;
-
-// Asks the container controller to remove the infobar for this delegate. This
-// call will trigger a notification that starts the infobar animating closed.
-- (void)removeInfoBar;
-
-// Performs final cleanup after an animation is finished or stopped, including
-// notifying the InfoBarDelegate that the infobar was closed and removing the
-// infobar from its container, if necessary.
-- (void)cleanUpAfterAnimation:(BOOL)finished;
-
-// Sets the info bar message to the specified |message|, with a hypertext
-// style link. |link| will be inserted into message at |linkOffset|.
-- (void)setLabelToMessage:(NSString*)message
- withLink:(NSString*)link
- atOffset:(NSUInteger)linkOffset;
-@end
-
-@implementation InfoBarController
-
-@synthesize containerController = containerController_;
-@synthesize delegate = delegate_;
-
-- (id)initWithDelegate:(InfoBarDelegate*)delegate {
- DCHECK(delegate);
- if ((self = [super initWithNibName:@"InfoBar"
- bundle:mac_util::MainAppBundle()])) {
- delegate_ = delegate;
- }
- return self;
-}
-
-// All infobars have an icon, so we set up the icon in the base class
-// awakeFromNib.
-- (void)awakeFromNib {
- DCHECK(delegate_);
- if (delegate_->GetIcon()) {
- [image_ setImage:gfx::SkBitmapToNSImage(*(delegate_->GetIcon()))];
- } else {
- // No icon, remove it from the view and grow the textfield to include the
- // space.
- NSRect imageFrame = [image_ frame];
- NSRect labelFrame = [labelPlaceholder_ frame];
- labelFrame.size.width += NSMinX(imageFrame) - NSMinX(labelFrame);
- labelFrame.origin.x = imageFrame.origin.x;
- [image_ removeFromSuperview];
- [labelPlaceholder_ setFrame:labelFrame];
- }
- [self initializeLabel];
-
- [self addAdditionalControls];
-}
-
-// Called when someone clicks on the embedded link.
-- (BOOL) textView:(NSTextView*)textView
- clickedOnLink:(id)link
- atIndex:(NSUInteger)charIndex {
- if ([self respondsToSelector:@selector(linkClicked)])
- [self performSelector:@selector(linkClicked)];
- return YES;
-}
-
-// Called when someone clicks on the ok button.
-- (void)ok:(id)sender {
- // Subclasses must override this method if they do not hide the ok button.
- NOTREACHED();
-}
-
-// Called when someone clicks on the cancel button.
-- (void)cancel:(id)sender {
- // Subclasses must override this method if they do not hide the cancel button.
- NOTREACHED();
-}
-
-// Called when someone clicks on the close button.
-- (void)dismiss:(id)sender {
- [self removeInfoBar];
-}
-
-- (AnimatableView*)animatableView {
- return static_cast<AnimatableView*>([self view]);
-}
-
-- (void)open {
- // Simply reset the frame size to its opened size, forcing a relayout.
- CGFloat finalHeight = [[self view] frame].size.height;
- [[self animatableView] setHeight:finalHeight];
-}
-
-- (void)animateOpen {
- // Force the frame size to be 0 and then start an animation.
- NSRect frame = [[self view] frame];
- CGFloat finalHeight = frame.size.height;
- frame.size.height = 0;
- [[self view] setFrame:frame];
- [[self animatableView] animateToNewHeight:finalHeight
- duration:kAnimateOpenDuration];
-}
-
-- (void)close {
- // Stop any running animations.
- [[self animatableView] stopAnimation];
- infoBarClosing_ = YES;
- [self cleanUpAfterAnimation:YES];
-}
-
-- (void)animateClosed {
- // Start animating closed. We will receive a notification when the animation
- // is done, at which point we can remove our view from the hierarchy and
- // notify the delegate that the infobar was closed.
- [[self animatableView] animateToNewHeight:0 duration:kAnimateCloseDuration];
-
- // The above call may trigger an animationDidStop: notification for any
- // currently-running animations, so do not set |infoBarClosing_| until after
- // starting the animation.
- infoBarClosing_ = YES;
-}
-
-- (void)addAdditionalControls {
- // Default implementation does nothing.
-}
-
-- (void)setLabelToMessage:(NSString*)message {
- NSMutableDictionary* attributes = [NSMutableDictionary dictionary];
- NSFont* font = [NSFont labelFontOfSize:
- [NSFont systemFontSizeForControlSize:NSRegularControlSize]];
- [attributes setObject:font
- forKey:NSFontAttributeName];
- [attributes setObject:[NSCursor arrowCursor]
- forKey:NSCursorAttributeName];
- scoped_nsobject<NSAttributedString> attributedString(
- [[NSAttributedString alloc] initWithString:message
- attributes:attributes]);
- [[label_.get() textStorage] setAttributedString:attributedString];
-}
-
-- (void)removeButtons {
- // Extend the label all the way across.
- NSRect labelFrame = [label_.get() frame];
- labelFrame.size.width = NSMaxX([cancelButton_ frame]) - NSMinX(labelFrame);
- [okButton_ removeFromSuperview];
- [cancelButton_ removeFromSuperview];
- [label_.get() setFrame:labelFrame];
-}
-
-@end
-
-@implementation InfoBarController (PrivateMethods)
-
-- (void)initializeLabel {
- // Replace the label placeholder NSTextField with the real label NSTextView.
- // The former doesn't show links in a nice way, but the latter can't be added
- // in IB without a containing scroll view, so create the NSTextView
- // programmatically.
- label_.reset([[InfoBarTextView alloc]
- initWithFrame:[labelPlaceholder_ frame]]);
- [label_.get() setAutoresizingMask:[labelPlaceholder_ autoresizingMask]];
- [[labelPlaceholder_ superview]
- replaceSubview:labelPlaceholder_ with:label_.get()];
- labelPlaceholder_ = nil; // Now released.
- [label_.get() setDelegate:self];
- [label_.get() setEditable:NO];
- [label_.get() setDrawsBackground:NO];
- [label_.get() setHorizontallyResizable:NO];
- [label_.get() setVerticallyResizable:NO];
-}
-
-- (void)removeInfoBar {
- // TODO(rohitrao): This method can be called even if the infobar has already
- // been removed and |delegate_| is NULL. Is there a way to rewrite the code
- // so that inner event loops don't cause us to try and remove the infobar
- // twice? http://crbug.com/54253
- [containerController_ removeDelegate:delegate_];
-}
-
-- (void)cleanUpAfterAnimation:(BOOL)finished {
- // Don't need to do any cleanup if the bar was animating open.
- if (!infoBarClosing_)
- return;
-
- // Notify the delegate that the infobar was closed. The delegate may delete
- // itself as a result of InfoBarClosed(), so we null out its pointer.
- if (delegate_) {
- delegate_->InfoBarClosed();
- delegate_ = NULL;
- }
-
- // If the animation ran to completion, then we need to remove ourselves from
- // the container. If the animation was interrupted, then the container will
- // take care of removing us.
- // TODO(rohitrao): UGH! This works for now, but should be cleaner.
- if (finished)
- [containerController_ removeController:self];
-}
-
-- (void)animationDidStop:(NSAnimation*)animation {
- [self cleanUpAfterAnimation:NO];
-}
-
-- (void)animationDidEnd:(NSAnimation*)animation {
- [self cleanUpAfterAnimation:YES];
-}
-
-// TODO(joth): This method factors out some common functionality between the
-// various derived infobar classes, however the class hierarchy itself could
-// use refactoring to reduce this duplication. http://crbug.com/38924
-- (void)setLabelToMessage:(NSString*)message
- withLink:(NSString*)link
- atOffset:(NSUInteger)linkOffset {
- if (linkOffset == std::wstring::npos) {
- // linkOffset == std::wstring::npos means the link should be right-aligned,
- // which is not supported on Mac (http://crbug.com/47728).
- NOTIMPLEMENTED();
- linkOffset = [message length];
- }
- // Create an attributes dictionary for the entire message. We have
- // to expicitly set the font the control's font. We also override
- // the cursor to give us the normal cursor rather than the text
- // insertion cursor.
- NSMutableDictionary* linkAttributes = [NSMutableDictionary dictionary];
- [linkAttributes setObject:[NSCursor arrowCursor]
- forKey:NSCursorAttributeName];
- NSFont* font = [NSFont labelFontOfSize:
- [NSFont systemFontSizeForControlSize:NSRegularControlSize]];
- [linkAttributes setObject:font
- forKey:NSFontAttributeName];
-
- // Create the attributed string for the main message text.
- scoped_nsobject<NSMutableAttributedString> infoText(
- [[NSMutableAttributedString alloc] initWithString:message]);
- [infoText.get() addAttributes:linkAttributes
- range:NSMakeRange(0, [infoText.get() length])];
- // Add additional attributes to style the link text appropriately as
- // well as linkify it.
- [linkAttributes setObject:[NSColor blueColor]
- forKey:NSForegroundColorAttributeName];
- [linkAttributes setObject:[NSNumber numberWithBool:YES]
- forKey:NSUnderlineStyleAttributeName];
- [linkAttributes setObject:[NSCursor pointingHandCursor]
- forKey:NSCursorAttributeName];
- [linkAttributes setObject:[NSNumber numberWithInt:NSSingleUnderlineStyle]
- forKey:NSUnderlineStyleAttributeName];
- [linkAttributes setObject:[NSString string] // dummy value
- forKey:NSLinkAttributeName];
-
- // Insert the link text into the string at the appropriate offset.
- scoped_nsobject<NSAttributedString> attributedString(
- [[NSAttributedString alloc] initWithString:link
- attributes:linkAttributes]);
- [infoText.get() insertAttributedString:attributedString.get()
- atIndex:linkOffset];
- // Update the label view with the new text.
- [[label_.get() textStorage] setAttributedString:infoText];
-}
-
-@end
-
-
-/////////////////////////////////////////////////////////////////////////
-// AlertInfoBarController implementation
-
-@implementation AlertInfoBarController
-
-// Alert infobars have a text message.
-- (void)addAdditionalControls {
- // No buttons.
- [self removeButtons];
-
- // Insert the text.
- AlertInfoBarDelegate* delegate = delegate_->AsAlertInfoBarDelegate();
- DCHECK(delegate);
- [self setLabelToMessage:base::SysUTF16ToNSString(delegate->GetMessageText())];
-}
-
-@end
-
-
-/////////////////////////////////////////////////////////////////////////
-// LinkInfoBarController implementation
-
-@implementation LinkInfoBarController
-
-// Link infobars have a text message, of which part is linkified. We
-// use an NSAttributedString to display styled text, and we set a
-// NSLink attribute on the hyperlink portion of the message. Infobars
-// use a custom NSTextField subclass, which allows us to override
-// textView:clickedOnLink:atIndex: and intercept clicks.
-//
-- (void)addAdditionalControls {
- // No buttons.
- [self removeButtons];
-
- LinkInfoBarDelegate* delegate = delegate_->AsLinkInfoBarDelegate();
- DCHECK(delegate);
- size_t offset = std::wstring::npos;
- string16 message = delegate->GetMessageTextWithOffset(&offset);
- [self setLabelToMessage:base::SysUTF16ToNSString(message)
- withLink:base::SysUTF16ToNSString(delegate->GetLinkText())
- atOffset:offset];
-}
-
-// Called when someone clicks on the link in the infobar. This method
-// is called by the InfobarTextField on its delegate (the
-// LinkInfoBarController).
-- (void)linkClicked {
- WindowOpenDisposition disposition =
- event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
- if (delegate_ && delegate_->AsLinkInfoBarDelegate()->LinkClicked(disposition))
- [self removeInfoBar];
-}
-
-@end
-
-
-/////////////////////////////////////////////////////////////////////////
-// ConfirmInfoBarController implementation
-
-@implementation ConfirmInfoBarController
-
-// Called when someone clicks on the "OK" button.
-- (IBAction)ok:(id)sender {
- if (delegate_ && delegate_->AsConfirmInfoBarDelegate()->Accept())
- [self removeInfoBar];
-}
-
-// Called when someone clicks on the "Cancel" button.
-- (IBAction)cancel:(id)sender {
- if (delegate_ && delegate_->AsConfirmInfoBarDelegate()->Cancel())
- [self removeInfoBar];
-}
-
-// Confirm infobars can have OK and/or cancel buttons, depending on
-// the return value of GetButtons(). We create each button if
-// required and position them to the left of the close button.
-- (void)addAdditionalControls {
- ConfirmInfoBarDelegate* delegate = delegate_->AsConfirmInfoBarDelegate();
- DCHECK(delegate);
- int visibleButtons = delegate->GetButtons();
-
- NSRect okButtonFrame = [okButton_ frame];
- NSRect cancelButtonFrame = [cancelButton_ frame];
-
- DCHECK(NSMaxX(okButtonFrame) < NSMinX(cancelButtonFrame))
- << "Cancel button expected to be on the right of the Ok button in nib";
-
- CGFloat rightEdge = NSMaxX(cancelButtonFrame);
- CGFloat spaceBetweenButtons =
- NSMinX(cancelButtonFrame) - NSMaxX(okButtonFrame);
- CGFloat spaceBeforeButtons =
- NSMinX(okButtonFrame) - NSMaxX([label_.get() frame]);
-
- // Update and position the Cancel button if needed. Otherwise, hide it.
- if (visibleButtons & ConfirmInfoBarDelegate::BUTTON_CANCEL) {
- [cancelButton_ setTitle:base::SysUTF16ToNSString(
- delegate->GetButtonLabel(ConfirmInfoBarDelegate::BUTTON_CANCEL))];
- [GTMUILocalizerAndLayoutTweaker sizeToFitView:cancelButton_];
- cancelButtonFrame = [cancelButton_ frame];
-
- // Position the cancel button to the left of the Close button.
- cancelButtonFrame.origin.x = rightEdge - cancelButtonFrame.size.width;
- [cancelButton_ setFrame:cancelButtonFrame];
-
- // Update the rightEdge
- rightEdge = NSMinX(cancelButtonFrame);
- } else {
- [cancelButton_ removeFromSuperview];
- }
-
- // Update and position the OK button if needed. Otherwise, hide it.
- if (visibleButtons & ConfirmInfoBarDelegate::BUTTON_OK) {
- [okButton_ setTitle:base::SysUTF16ToNSString(
- delegate->GetButtonLabel(ConfirmInfoBarDelegate::BUTTON_OK))];
- [GTMUILocalizerAndLayoutTweaker sizeToFitView:okButton_];
- okButtonFrame = [okButton_ frame];
-
- // If we had a Cancel button, leave space between the buttons.
- if (visibleButtons & ConfirmInfoBarDelegate::BUTTON_CANCEL) {
- rightEdge -= spaceBetweenButtons;
- }
-
- // Position the OK button on our current right edge.
- okButtonFrame.origin.x = rightEdge - okButtonFrame.size.width;
- [okButton_ setFrame:okButtonFrame];
-
-
- // Update the rightEdge
- rightEdge = NSMinX(okButtonFrame);
- } else {
- [okButton_ removeFromSuperview];
- }
-
- // If we had either button, leave space before the edge of the textfield.
- if ((visibleButtons & ConfirmInfoBarDelegate::BUTTON_CANCEL) ||
- (visibleButtons & ConfirmInfoBarDelegate::BUTTON_OK)) {
- rightEdge -= spaceBeforeButtons;
- }
-
- NSRect frame = [label_.get() frame];
- DCHECK(rightEdge > NSMinX(frame))
- << "Need to make the xib larger to handle buttons with text this long";
- frame.size.width = rightEdge - NSMinX(frame);
- [label_.get() setFrame:frame];
-
- // Set the text and link.
- NSString* message = base::SysUTF16ToNSString(delegate->GetMessageText());
- string16 link = delegate->GetLinkText();
- if (link.empty()) {
- // Simple case: no link, so just set the message directly.
- [self setLabelToMessage:message];
- } else {
- // Inserting the link unintentionally causes the text to have a slightly
- // different result to the simple case above: text is truncated on word
- // boundaries (if needed) rather than elided with ellipses.
-
- // Add spacing between the label and the link.
- message = [message stringByAppendingString:@" "];
- [self setLabelToMessage:message
- withLink:base::SysUTF16ToNSString(link)
- atOffset:[message length]];
- }
-}
-
-// Called when someone clicks on the link in the infobar. This method
-// is called by the InfobarTextField on its delegate (the
-// LinkInfoBarController).
-- (void)linkClicked {
- WindowOpenDisposition disposition =
- event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
- if (delegate_ &&
- delegate_->AsConfirmInfoBarDelegate()->LinkClicked(disposition))
- [self removeInfoBar];
-}
-
-@end
-
-
-//////////////////////////////////////////////////////////////////////////
-// CreateInfoBar() implementations
-
-InfoBar* AlertInfoBarDelegate::CreateInfoBar() {
- AlertInfoBarController* controller =
- [[AlertInfoBarController alloc] initWithDelegate:this];
- return new InfoBar(controller);
-}
-
-InfoBar* LinkInfoBarDelegate::CreateInfoBar() {
- LinkInfoBarController* controller =
- [[LinkInfoBarController alloc] initWithDelegate:this];
- return new InfoBar(controller);
-}
-
-InfoBar* ConfirmInfoBarDelegate::CreateInfoBar() {
- ConfirmInfoBarController* controller =
- [[ConfirmInfoBarController alloc] initWithDelegate:this];
- return new InfoBar(controller);
-}
diff --git a/chrome/browser/cocoa/infobar_controller_unittest.mm b/chrome/browser/cocoa/infobar_controller_unittest.mm
deleted file mode 100644
index 114a94c..0000000
--- a/chrome/browser/cocoa/infobar_controller_unittest.mm
+++ /dev/null
@@ -1,284 +0,0 @@
-// Copyright (c) 2009 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 "base/scoped_nsobject.h"
-#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/infobar_container_controller.h"
-#import "chrome/browser/cocoa/infobar_controller.h"
-#include "chrome/browser/cocoa/infobar_test_helper.h"
-#include "chrome/browser/tab_contents/infobar_delegate.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-@interface InfoBarController (ExposedForTesting)
-- (NSString*)labelString;
-- (NSRect)labelFrame;
-@end
-
-@implementation InfoBarController (ExposedForTesting)
-- (NSString*)labelString {
- return [label_.get() string];
-}
-- (NSRect)labelFrame {
- return [label_.get() frame];
-}
-@end
-
-
-// Calls to removeDelegate: normally start an animation, which removes the
-// infobar completely when finished. For unittesting purposes, we create a mock
-// container which calls close: immediately, rather than kicking off an
-// animation.
-@interface InfoBarContainerTest : NSObject <InfoBarContainer> {
- InfoBarController* controller_;
-}
-- (id)initWithController:(InfoBarController*)controller;
-- (void)removeDelegate:(InfoBarDelegate*)delegate;
-- (void)removeController:(InfoBarController*)controller;
-@end
-
-@implementation InfoBarContainerTest
-- (id)initWithController:(InfoBarController*)controller {
- if ((self = [super init])) {
- controller_ = controller;
- }
- return self;
-}
-
-- (void)removeDelegate:(InfoBarDelegate*)delegate {
- [controller_ close];
-}
-
-- (void)removeController:(InfoBarController*)controller {
- DCHECK(controller_ == controller);
- controller_ = nil;
-}
-@end
-
-namespace {
-
-///////////////////////////////////////////////////////////////////////////
-// Test fixtures
-
-class AlertInfoBarControllerTest : public CocoaTest {
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
-
- controller_.reset(
- [[AlertInfoBarController alloc] initWithDelegate:&delegate_]);
- container_.reset(
- [[InfoBarContainerTest alloc] initWithController:controller_]);
- [controller_ setContainerController:container_];
- [[test_window() contentView] addSubview:[controller_ view]];
- }
-
- protected:
- MockAlertInfoBarDelegate delegate_;
- scoped_nsobject<id> container_;
- scoped_nsobject<AlertInfoBarController> controller_;
-};
-
-class LinkInfoBarControllerTest : public CocoaTest {
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
-
- controller_.reset(
- [[LinkInfoBarController alloc] initWithDelegate:&delegate_]);
- container_.reset(
- [[InfoBarContainerTest alloc] initWithController:controller_]);
- [controller_ setContainerController:container_];
- [[test_window() contentView] addSubview:[controller_ view]];
- }
-
- protected:
- MockLinkInfoBarDelegate delegate_;
- scoped_nsobject<id> container_;
- scoped_nsobject<LinkInfoBarController> controller_;
-};
-
-class ConfirmInfoBarControllerTest : public CocoaTest {
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
-
- controller_.reset(
- [[ConfirmInfoBarController alloc] initWithDelegate:&delegate_]);
- container_.reset(
- [[InfoBarContainerTest alloc] initWithController:controller_]);
- [controller_ setContainerController:container_];
- [[test_window() contentView] addSubview:[controller_ view]];
- }
-
- protected:
- MockConfirmInfoBarDelegate delegate_;
- scoped_nsobject<id> container_;
- scoped_nsobject<ConfirmInfoBarController> controller_;
-};
-
-
-////////////////////////////////////////////////////////////////////////////
-// Tests
-
-TEST_VIEW(AlertInfoBarControllerTest, [controller_ view]);
-
-TEST_F(AlertInfoBarControllerTest, ShowAndDismiss) {
- // Make sure someone looked at the message and icon.
- EXPECT_TRUE(delegate_.message_text_accessed);
- EXPECT_TRUE(delegate_.icon_accessed);
-
- // Check to make sure the infobar message was set properly.
- EXPECT_EQ(kMockAlertInfoBarMessage,
- base::SysNSStringToUTF8([controller_.get() labelString]));
-
- // Check that dismissing the infobar calls InfoBarClosed() on the delegate.
- [controller_ dismiss:nil];
- EXPECT_TRUE(delegate_.closed);
-}
-
-TEST_F(AlertInfoBarControllerTest, DeallocController) {
- // Test that dealloc'ing the controller does not send an
- // InfoBarClosed() message to the delegate.
- controller_.reset(nil);
- EXPECT_FALSE(delegate_.closed);
-}
-
-TEST_F(AlertInfoBarControllerTest, ResizeView) {
- NSRect originalLabelFrame = [controller_ labelFrame];
-
- // Expand the view by 20 pixels and make sure the label frame changes
- // accordingly.
- const CGFloat width = 20;
- NSRect newViewFrame = [[controller_ view] frame];
- newViewFrame.size.width += width;
- [[controller_ view] setFrame:newViewFrame];
-
- NSRect newLabelFrame = [controller_ labelFrame];
- EXPECT_EQ(NSWidth(newLabelFrame), NSWidth(originalLabelFrame) + width);
-}
-
-TEST_VIEW(LinkInfoBarControllerTest, [controller_ view]);
-
-TEST_F(LinkInfoBarControllerTest, ShowAndDismiss) {
- // Make sure someone looked at the message, link, and icon.
- EXPECT_TRUE(delegate_.message_text_accessed);
- EXPECT_TRUE(delegate_.link_text_accessed);
- EXPECT_TRUE(delegate_.icon_accessed);
-
- // Check that dismissing the infobar calls InfoBarClosed() on the delegate.
- [controller_ dismiss:nil];
- EXPECT_FALSE(delegate_.link_clicked);
- EXPECT_TRUE(delegate_.closed);
-}
-
-TEST_F(LinkInfoBarControllerTest, ShowAndClickLink) {
- // Check that clicking on the link calls LinkClicked() on the
- // delegate. It should also close the infobar.
- [controller_ linkClicked];
- EXPECT_TRUE(delegate_.link_clicked);
- EXPECT_TRUE(delegate_.closed);
-}
-
-TEST_F(LinkInfoBarControllerTest, ShowAndClickLinkWithoutClosing) {
- delegate_.closes_on_action = false;
-
- // Check that clicking on the link calls LinkClicked() on the
- // delegate. It should not close the infobar.
- [controller_ linkClicked];
- EXPECT_TRUE(delegate_.link_clicked);
- EXPECT_FALSE(delegate_.closed);
-}
-
-TEST_VIEW(ConfirmInfoBarControllerTest, [controller_ view]);
-
-TEST_F(ConfirmInfoBarControllerTest, ShowAndDismiss) {
- // Make sure someone looked at the message, link, and icon.
- EXPECT_TRUE(delegate_.message_text_accessed);
- EXPECT_TRUE(delegate_.link_text_accessed);
- EXPECT_TRUE(delegate_.icon_accessed);
-
- // Check to make sure the infobar message was set properly.
- EXPECT_EQ(kMockConfirmInfoBarMessage,
- base::SysNSStringToUTF8([controller_.get() labelString]));
-
- // Check that dismissing the infobar calls InfoBarClosed() on the delegate.
- [controller_ dismiss:nil];
- EXPECT_FALSE(delegate_.ok_clicked);
- EXPECT_FALSE(delegate_.cancel_clicked);
- EXPECT_FALSE(delegate_.link_clicked);
- EXPECT_TRUE(delegate_.closed);
-}
-
-TEST_F(ConfirmInfoBarControllerTest, ShowAndClickOK) {
- // Check that clicking the OK button calls Accept() and then closes
- // the infobar.
- [controller_ ok:nil];
- EXPECT_TRUE(delegate_.ok_clicked);
- EXPECT_FALSE(delegate_.cancel_clicked);
- EXPECT_FALSE(delegate_.link_clicked);
- EXPECT_TRUE(delegate_.closed);
-}
-
-TEST_F(ConfirmInfoBarControllerTest, ShowAndClickOKWithoutClosing) {
- delegate_.closes_on_action = false;
-
- // Check that clicking the OK button calls Accept() but does not close
- // the infobar.
- [controller_ ok:nil];
- EXPECT_TRUE(delegate_.ok_clicked);
- EXPECT_FALSE(delegate_.cancel_clicked);
- EXPECT_FALSE(delegate_.link_clicked);
- EXPECT_FALSE(delegate_.closed);
-}
-
-TEST_F(ConfirmInfoBarControllerTest, ShowAndClickCancel) {
- // Check that clicking the cancel button calls Cancel() and closes
- // the infobar.
- [controller_ cancel:nil];
- EXPECT_FALSE(delegate_.ok_clicked);
- EXPECT_TRUE(delegate_.cancel_clicked);
- EXPECT_FALSE(delegate_.link_clicked);
- EXPECT_TRUE(delegate_.closed);
-}
-
-TEST_F(ConfirmInfoBarControllerTest, ShowAndClickCancelWithoutClosing) {
- delegate_.closes_on_action = false;
-
- // Check that clicking the cancel button calls Cancel() but does not close
- // the infobar.
- [controller_ cancel:nil];
- EXPECT_FALSE(delegate_.ok_clicked);
- EXPECT_TRUE(delegate_.cancel_clicked);
- EXPECT_FALSE(delegate_.link_clicked);
- EXPECT_FALSE(delegate_.closed);
-}
-
-TEST_F(ConfirmInfoBarControllerTest, ShowAndClickLink) {
- // Check that clicking on the link calls LinkClicked() on the
- // delegate. It should also close the infobar.
- [controller_ linkClicked];
- EXPECT_FALSE(delegate_.ok_clicked);
- EXPECT_FALSE(delegate_.cancel_clicked);
- EXPECT_TRUE(delegate_.link_clicked);
- EXPECT_TRUE(delegate_.closed);
-}
-
-TEST_F(ConfirmInfoBarControllerTest, ShowAndClickLinkWithoutClosing) {
- delegate_.closes_on_action = false;
-
- // Check that clicking on the link calls LinkClicked() on the
- // delegate. It should not close the infobar.
- [controller_ linkClicked];
- EXPECT_FALSE(delegate_.ok_clicked);
- EXPECT_FALSE(delegate_.cancel_clicked);
- EXPECT_TRUE(delegate_.link_clicked);
- EXPECT_FALSE(delegate_.closed);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/infobar_gradient_view.h b/chrome/browser/cocoa/infobar_gradient_view.h
deleted file mode 100644
index c5f3c1d..0000000
--- a/chrome/browser/cocoa/infobar_gradient_view.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_INFOBAR_GRADIENT_VIEW_H_
-#define CHROME_BROWSER_COCOA_INFOBAR_GRADIENT_VIEW_H_
-#pragma once
-
-#import "chrome/browser/cocoa/vertical_gradient_view.h"
-
-#import <Cocoa/Cocoa.h>
-
-// A custom view that draws the background gradient for an infobar.
-@interface InfoBarGradientView : VerticalGradientView {
-}
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_INFOBAR_GRADIENT_VIEW_H_
diff --git a/chrome/browser/cocoa/infobar_gradient_view.mm b/chrome/browser/cocoa/infobar_gradient_view.mm
deleted file mode 100644
index 180a286..0000000
--- a/chrome/browser/cocoa/infobar_gradient_view.mm
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/infobar_gradient_view.h"
-
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/themed_window.h"
-#import "chrome/browser/themes/browser_theme_provider.h"
-
-namespace {
-
-const double kBackgroundColorTop[3] =
- {255.0 / 255.0, 242.0 / 255.0, 183.0 / 255.0};
-const double kBackgroundColorBottom[3] =
- {250.0 / 255.0, 230.0 / 255.0, 145.0 / 255.0};
-}
-
-@implementation InfoBarGradientView
-
-- (id)initWithFrame:(NSRect)frameRect {
- if ((self = [super initWithFrame:frameRect])) {
- NSColor* startingColor =
- [NSColor colorWithCalibratedRed:kBackgroundColorTop[0]
- green:kBackgroundColorTop[1]
- blue:kBackgroundColorTop[2]
- alpha:1.0];
- NSColor* endingColor =
- [NSColor colorWithCalibratedRed:kBackgroundColorBottom[0]
- green:kBackgroundColorBottom[1]
- blue:kBackgroundColorBottom[2]
- alpha:1.0];
- scoped_nsobject<NSGradient> gradient(
- [[NSGradient alloc] initWithStartingColor:startingColor
- endingColor:endingColor]);
- [self setGradient:gradient];
- }
- return self;
-}
-
-- (NSColor*)strokeColor {
- ThemeProvider* themeProvider = [[self window] themeProvider];
- if (!themeProvider)
- return [NSColor blackColor];
-
- BOOL active = [[self window] isMainWindow];
- return themeProvider->GetNSColor(
- active ? BrowserThemeProvider::COLOR_TOOLBAR_STROKE :
- BrowserThemeProvider::COLOR_TOOLBAR_STROKE_INACTIVE,
- true);
-}
-
-- (BOOL)mouseDownCanMoveWindow {
- return NO;
-}
-
-// This view is intentionally not opaque because it overlaps with the findbar.
-
-- (BOOL)accessibilityIsIgnored {
- return NO;
-}
-
-- (id)accessibilityAttributeValue:(NSString*)attribute {
- if ([attribute isEqual:NSAccessibilityRoleAttribute])
- return NSAccessibilityGroupRole;
-
- return [super accessibilityAttributeValue:attribute];
-}
-
-@end
diff --git a/chrome/browser/cocoa/infobar_gradient_view_unittest.mm b/chrome/browser/cocoa/infobar_gradient_view_unittest.mm
deleted file mode 100644
index 2c1ec21..0000000
--- a/chrome/browser/cocoa/infobar_gradient_view_unittest.mm
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) 2009 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/scoped_nsobject.h"
-#import "chrome/browser/cocoa/infobar_gradient_view.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-
-namespace {
-
-class InfoBarGradientViewTest : public CocoaTest {
- public:
- InfoBarGradientViewTest() {
- NSRect frame = NSMakeRect(0, 0, 100, 30);
- scoped_nsobject<InfoBarGradientView> view(
- [[InfoBarGradientView alloc] initWithFrame:frame]);
- view_ = view.get();
- [[test_window() contentView] addSubview:view_];
- }
-
- InfoBarGradientView* view_; // Weak. Retained by view hierarchy.
-};
-
-TEST_VIEW(InfoBarGradientViewTest, view_);
-
-// Assert that the view is non-opaque, because otherwise we will end
-// up with findbar painting issues.
-TEST_F(InfoBarGradientViewTest, AssertViewNonOpaque) {
- EXPECT_FALSE([view_ isOpaque]);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/install_from_dmg.h b/chrome/browser/cocoa/install_from_dmg.h
deleted file mode 100644
index ec9248a..0000000
--- a/chrome/browser/cocoa/install_from_dmg.h
+++ /dev/null
@@ -1,15 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_INSTALL_FROM_DMG_H_
-#define CHROME_BROWSER_COCOA_INSTALL_FROM_DMG_H_
-#pragma once
-
-// If the application is running from a read-only disk image, prompts the user
-// to install it to the hard drive. If the user approves, the application
-// will be installed and launched, and MaybeInstallFromDiskImage will return
-// true. In that case, the caller must exit expeditiously.
-bool MaybeInstallFromDiskImage();
-
-#endif // CHROME_BROWSER_COCOA_INSTALL_FROM_DMG_H_
diff --git a/chrome/browser/cocoa/install_from_dmg.mm b/chrome/browser/cocoa/install_from_dmg.mm
deleted file mode 100644
index df24d5c..0000000
--- a/chrome/browser/cocoa/install_from_dmg.mm
+++ /dev/null
@@ -1,438 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/install_from_dmg.h"
-
-#include <ApplicationServices/ApplicationServices.h>
-#import <AppKit/AppKit.h>
-#include <CoreFoundation/CoreFoundation.h>
-#include <CoreServices/CoreServices.h>
-#include <IOKit/IOKitLib.h>
-#include <string.h>
-#include <sys/param.h>
-#include <sys/mount.h>
-
-#include "app/l10n_util.h"
-#import "app/l10n_util_mac.h"
-#include "base/basictypes.h"
-#include "base/command_line.h"
-#include "base/logging.h"
-#import "base/mac_util.h"
-#include "base/mac/scoped_nsautorelease_pool.h"
-#include "chrome/browser/cocoa/authorization_util.h"
-#include "chrome/browser/cocoa/scoped_authorizationref.h"
-#import "chrome/browser/cocoa/keystone_glue.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-
-// When C++ exceptions are disabled, the C++ library defines |try| and
-// |catch| so as to allow exception-expecting C++ code to build properly when
-// language support for exceptions is not present. These macros interfere
-// with the use of |@try| and |@catch| in Objective-C files such as this one.
-// Undefine these macros here, after everything has been #included, since
-// there will be no C++ uses and only Objective-C uses from this point on.
-#undef try
-#undef catch
-
-namespace {
-
-// Just like ScopedCFTypeRef but for io_object_t and subclasses.
-template<typename IOT>
-class scoped_ioobject {
- public:
- typedef IOT element_type;
-
- explicit scoped_ioobject(IOT object = NULL)
- : object_(object) {
- }
-
- ~scoped_ioobject() {
- if (object_)
- IOObjectRelease(object_);
- }
-
- void reset(IOT object = NULL) {
- if (object_)
- IOObjectRelease(object_);
- object_ = object;
- }
-
- bool operator==(IOT that) const {
- return object_ == that;
- }
-
- bool operator!=(IOT that) const {
- return object_ != that;
- }
-
- operator IOT() const {
- return object_;
- }
-
- IOT get() const {
- return object_;
- }
-
- void swap(scoped_ioobject& that) {
- IOT temp = that.object_;
- that.object_ = object_;
- object_ = temp;
- }
-
- IOT release() {
- IOT temp = object_;
- object_ = NULL;
- return temp;
- }
-
- private:
- IOT object_;
-
- DISALLOW_COPY_AND_ASSIGN(scoped_ioobject);
-};
-
-// Returns true if |path| is located on a read-only filesystem of a disk
-// image. Returns false if not, or in the event of an error.
-bool IsPathOnReadOnlyDiskImage(const char path[]) {
- struct statfs statfs_buf;
- if (statfs(path, &statfs_buf) != 0) {
- PLOG(ERROR) << "statfs " << path;
- return false;
- }
-
- if (!(statfs_buf.f_flags & MNT_RDONLY)) {
- // Not on a read-only filesystem.
- return false;
- }
-
- const char dev_root[] = "/dev/";
- const int dev_root_length = arraysize(dev_root) - 1;
- if (strncmp(statfs_buf.f_mntfromname, dev_root, dev_root_length) != 0) {
- // Not rooted at dev_root, no BSD name to search on.
- return false;
- }
-
- // BSD names in IOKit don't include dev_root.
- const char* bsd_device_name = statfs_buf.f_mntfromname + dev_root_length;
-
- const mach_port_t master_port = kIOMasterPortDefault;
-
- // IOBSDNameMatching gives ownership of match_dict to the caller, but
- // IOServiceGetMatchingServices will assume that reference.
- CFMutableDictionaryRef match_dict = IOBSDNameMatching(master_port,
- 0,
- bsd_device_name);
- if (!match_dict) {
- LOG(ERROR) << "IOBSDNameMatching " << bsd_device_name;
- return false;
- }
-
- io_iterator_t iterator_ref;
- kern_return_t kr = IOServiceGetMatchingServices(master_port,
- match_dict,
- &iterator_ref);
- if (kr != KERN_SUCCESS) {
- LOG(ERROR) << "IOServiceGetMatchingServices " << bsd_device_name
- << ": kernel error " << kr;
- return false;
- }
- scoped_ioobject<io_iterator_t> iterator(iterator_ref);
- iterator_ref = NULL;
-
- // There needs to be exactly one matching service.
- scoped_ioobject<io_service_t> filesystem_service(IOIteratorNext(iterator));
- if (!filesystem_service) {
- LOG(ERROR) << "IOIteratorNext " << bsd_device_name << ": no service";
- return false;
- }
- scoped_ioobject<io_service_t> unexpected_service(IOIteratorNext(iterator));
- if (unexpected_service) {
- LOG(ERROR) << "IOIteratorNext " << bsd_device_name << ": too many services";
- return false;
- }
-
- iterator.reset();
-
- const char disk_image_class[] = "IOHDIXController";
-
- // This is highly unlikely. The filesystem service is expected to be of
- // class IOMedia. Since the filesystem service's entire ancestor chain
- // will be checked, though, check the filesystem service's class itself.
- if (IOObjectConformsTo(filesystem_service, disk_image_class)) {
- return true;
- }
-
- kr = IORegistryEntryCreateIterator(filesystem_service,
- kIOServicePlane,
- kIORegistryIterateRecursively |
- kIORegistryIterateParents,
- &iterator_ref);
- if (kr != KERN_SUCCESS) {
- LOG(ERROR) << "IORegistryEntryCreateIterator " << bsd_device_name
- << ": kernel error " << kr;
- return false;
- }
- iterator.reset(iterator_ref);
- iterator_ref = NULL;
-
- // Look at each of the filesystem service's ancestor services, beginning
- // with the parent, iterating all the way up to the device tree's root. If
- // any ancestor service matches the class used for disk images, the
- // filesystem resides on a disk image.
- for(scoped_ioobject<io_service_t> ancestor_service(IOIteratorNext(iterator));
- ancestor_service;
- ancestor_service.reset(IOIteratorNext(iterator))) {
- if (IOObjectConformsTo(ancestor_service, disk_image_class)) {
- return true;
- }
- }
-
- // The filesystem does not reside on a disk image.
- return false;
-}
-
-// Returns true if the application is located on a read-only filesystem of a
-// disk image. Returns false if not, or in the event of an error.
-bool IsAppRunningFromReadOnlyDiskImage() {
- return IsPathOnReadOnlyDiskImage(
- [[[NSBundle mainBundle] bundlePath] fileSystemRepresentation]);
-}
-
-// Shows a dialog asking the user whether or not to install from the disk
-// image. Returns true if the user approves installation.
-bool ShouldInstallDialog() {
- NSString* title = l10n_util::GetNSStringFWithFixup(
- IDS_INSTALL_FROM_DMG_TITLE, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
- NSString* prompt = l10n_util::GetNSStringFWithFixup(
- IDS_INSTALL_FROM_DMG_PROMPT, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
- NSString* yes = l10n_util::GetNSStringWithFixup(IDS_INSTALL_FROM_DMG_YES);
- NSString* no = l10n_util::GetNSStringWithFixup(IDS_INSTALL_FROM_DMG_NO);
-
- NSAlert* alert = [[[NSAlert alloc] init] autorelease];
-
- [alert setAlertStyle:NSInformationalAlertStyle];
- [alert setMessageText:title];
- [alert setInformativeText:prompt];
- [alert addButtonWithTitle:yes];
- NSButton* cancel_button = [alert addButtonWithTitle:no];
- [cancel_button setKeyEquivalent:@"\e"];
-
- NSInteger result = [alert runModal];
-
- return result == NSAlertFirstButtonReturn;
-}
-
-// Potentially shows an authorization dialog to request authentication to
-// copy. If application_directory appears to be unwritable, attempts to
-// obtain authorization, which may result in the display of the dialog.
-// Returns NULL if authorization is not performed because it does not appear
-// to be necessary because the user has permission to write to
-// application_directory. Returns NULL if authorization fails.
-AuthorizationRef MaybeShowAuthorizationDialog(NSString* application_directory) {
- NSFileManager* file_manager = [NSFileManager defaultManager];
- if ([file_manager isWritableFileAtPath:application_directory]) {
- return NULL;
- }
-
- NSString* prompt = l10n_util::GetNSStringFWithFixup(
- IDS_INSTALL_FROM_DMG_AUTHENTICATION_PROMPT,
- l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
- return authorization_util::AuthorizationCreateToRunAsRoot(
- reinterpret_cast<CFStringRef>(prompt));
-}
-
-// Invokes the installer program at installer_path to copy source_path to
-// target_path and perform any additional on-disk bookkeeping needed to be
-// able to launch target_path properly. If authorization_arg is non-NULL,
-// function will assume ownership of it, will invoke the installer with that
-// authorization reference, and will attempt Keystone ticket promotion.
-bool InstallFromDiskImage(AuthorizationRef authorization_arg,
- NSString* installer_path,
- NSString* source_path,
- NSString* target_path) {
- scoped_AuthorizationRef authorization(authorization_arg);
- authorization_arg = NULL;
- int exit_status;
- if (authorization) {
- const char* installer_path_c = [installer_path fileSystemRepresentation];
- const char* source_path_c = [source_path fileSystemRepresentation];
- const char* target_path_c = [target_path fileSystemRepresentation];
- const char* arguments[] = {source_path_c, target_path_c, NULL};
-
- OSStatus status = authorization_util::ExecuteWithPrivilegesAndWait(
- authorization,
- installer_path_c,
- kAuthorizationFlagDefaults,
- arguments,
- NULL, // pipe
- &exit_status);
- if (status != errAuthorizationSuccess) {
- LOG(ERROR) << "AuthorizationExecuteWithPrivileges install: " << status;
- return false;
- }
- } else {
- NSArray* arguments = [NSArray arrayWithObjects:source_path,
- target_path,
- nil];
-
- NSTask* task;
- @try {
- task = [NSTask launchedTaskWithLaunchPath:installer_path
- arguments:arguments];
- } @catch(NSException* exception) {
- LOG(ERROR) << "+[NSTask launchedTaskWithLaunchPath:arguments:]: "
- << [[exception description] UTF8String];
- return false;
- }
-
- [task waitUntilExit];
- exit_status = [task terminationStatus];
- }
-
- if (exit_status != 0) {
- LOG(ERROR) << "install.sh: exit status " << exit_status;
- return false;
- }
-
- if (authorization) {
- // As long as an AuthorizationRef is available, promote the Keystone
- // ticket. Inform KeystoneGlue of the new path to use.
- KeystoneGlue* keystone_glue = [KeystoneGlue defaultKeystoneGlue];
- [keystone_glue setAppPath:target_path];
- [keystone_glue promoteTicketWithAuthorization:authorization.release()
- synchronous:YES];
- }
-
- return true;
-}
-
-// Launches the application at app_path. The arguments passed to app_path
-// will be the same as the arguments used to invoke this process, except any
-// arguments beginning with -psn_ will be stripped.
-bool LaunchInstalledApp(NSString* app_path) {
- const UInt8* app_path_c =
- reinterpret_cast<const UInt8*>([app_path fileSystemRepresentation]);
- FSRef app_fsref;
- OSStatus err = FSPathMakeRef(app_path_c, &app_fsref, NULL);
- if (err != noErr) {
- LOG(ERROR) << "FSPathMakeRef: " << err;
- return false;
- }
-
- const std::vector<std::string>& argv =
- CommandLine::ForCurrentProcess()->argv();
- NSMutableArray* arguments =
- [NSMutableArray arrayWithCapacity:argv.size() - 1];
- // Start at argv[1]. LSOpenApplication adds its own argv[0] as the path of
- // the launched executable.
- for (size_t index = 1; index < argv.size(); ++index) {
- std::string argument = argv[index];
- const char psn_flag[] = "-psn_";
- const int psn_flag_length = arraysize(psn_flag) - 1;
- if (argument.compare(0, psn_flag_length, psn_flag) != 0) {
- // Strip any -psn_ arguments, as they apply to a specific process.
- [arguments addObject:[NSString stringWithUTF8String:argument.c_str()]];
- }
- }
-
- struct LSApplicationParameters parameters = {0};
- parameters.flags = kLSLaunchDefaults;
- parameters.application = &app_fsref;
- parameters.argv = reinterpret_cast<CFArrayRef>(arguments);
-
- err = LSOpenApplication(&parameters, NULL);
- if (err != noErr) {
- LOG(ERROR) << "LSOpenApplication: " << err;
- return false;
- }
-
- return true;
-}
-
-void ShowErrorDialog() {
- NSString* title = l10n_util::GetNSStringWithFixup(
- IDS_INSTALL_FROM_DMG_ERROR_TITLE);
- NSString* error = l10n_util::GetNSStringFWithFixup(
- IDS_INSTALL_FROM_DMG_ERROR, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
- NSString* ok = l10n_util::GetNSStringWithFixup(IDS_OK);
-
- NSAlert* alert = [[[NSAlert alloc] init] autorelease];
-
- [alert setAlertStyle:NSWarningAlertStyle];
- [alert setMessageText:title];
- [alert setInformativeText:error];
- [alert addButtonWithTitle:ok];
-
- [alert runModal];
-}
-
-} // namespace
-
-bool MaybeInstallFromDiskImage() {
- base::mac::ScopedNSAutoreleasePool autorelease_pool;
-
- if (!IsAppRunningFromReadOnlyDiskImage()) {
- return false;
- }
-
- NSArray* application_directories =
- NSSearchPathForDirectoriesInDomains(NSApplicationDirectory,
- NSLocalDomainMask,
- YES);
- if ([application_directories count] == 0) {
- LOG(ERROR) << "NSSearchPathForDirectoriesInDomains: "
- << "no local application directories";
- return false;
- }
- NSString* application_directory = [application_directories objectAtIndex:0];
-
- NSFileManager* file_manager = [NSFileManager defaultManager];
-
- BOOL is_directory;
- if (![file_manager fileExistsAtPath:application_directory
- isDirectory:&is_directory] ||
- !is_directory) {
- VLOG(1) << "No application directory at "
- << [application_directory UTF8String];
- return false;
- }
-
- NSString* source_path = [[NSBundle mainBundle] bundlePath];
- NSString* application_name = [source_path lastPathComponent];
- NSString* target_path =
- [application_directory stringByAppendingPathComponent:application_name];
-
- if ([file_manager fileExistsAtPath:target_path]) {
- VLOG(1) << "Something already exists at " << [target_path UTF8String];
- return false;
- }
-
- NSString* installer_path =
- [mac_util::MainAppBundle() pathForResource:@"install" ofType:@"sh"];
- if (!installer_path) {
- VLOG(1) << "Could not locate install.sh";
- return false;
- }
-
- if (!ShouldInstallDialog()) {
- return false;
- }
-
- scoped_AuthorizationRef authorization(
- MaybeShowAuthorizationDialog(application_directory));
- // authorization will be NULL if it's deemed unnecessary or if
- // authentication fails. In either case, try to install without privilege
- // escalation.
-
- if (!InstallFromDiskImage(authorization.release(),
- installer_path,
- source_path,
- target_path) ||
- !LaunchInstalledApp(target_path)) {
- ShowErrorDialog();
- return false;
- }
-
- return true;
-}
diff --git a/chrome/browser/cocoa/instant_confirm_window_controller.h b/chrome/browser/cocoa/instant_confirm_window_controller.h
deleted file mode 100644
index f721af7..0000000
--- a/chrome/browser/cocoa/instant_confirm_window_controller.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_INSTANT_CONFIRM_WINDOW_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_INSTANT_CONFIRM_WINDOW_CONTROLLER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/cocoa_protocols_mac.h"
-
-class Profile;
-
-// This controller manages a dialog that informs the user about Instant search.
-// The recommended API is to not use this class directly, but instead to use
-// the functions in //chrome/browser/instant/instant_confirm_dialog.h:
-// void ShowInstantConfirmDialog[IfNecessary](gfx::NativeWindow* parent, ...)
-// Which will attach the window to |parent| as a sheet.
-@interface InstantConfirmWindowController : NSWindowController<NSWindowDelegate>
-{
- @private
- // The long description about Instant that needs to be sized-to-fit.
- IBOutlet NSTextField* description_;
-
- Profile* profile_; // weak
-}
-
-// Designated initializer. The controller will release itself on window close.
-- (id)initWithProfile:(Profile*)profile;
-
-// Action for the "Learn more" link.
-- (IBAction)learnMore:(id)sender;
-
-// The user has opted in to Instant. This enables the Instant preference.
-- (IBAction)ok:(id)sender;
-
-// Closes the sheet without altering the preference value.
-- (IBAction)cancel:(id)sender;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_INSTANT_CONFIRM_WINDOW_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/instant_confirm_window_controller.mm b/chrome/browser/cocoa/instant_confirm_window_controller.mm
deleted file mode 100644
index 93367d6..0000000
--- a/chrome/browser/cocoa/instant_confirm_window_controller.mm
+++ /dev/null
@@ -1,76 +0,0 @@
-// 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 "chrome/browser/cocoa/instant_confirm_window_controller.h"
-
-#include "base/logging.h"
-#include "base/mac_util.h"
-#include "chrome/browser/instant/instant_confirm_dialog.h"
-#include "chrome/browser/instant/instant_controller.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/show_options_url.h"
-#include "gfx/native_widget_types.h"
-#include "googleurl/src/gurl.h"
-#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-
-namespace browser {
-
-void ShowInstantConfirmDialog(gfx::NativeWindow parent, Profile* profile) {
- InstantConfirmWindowController* controller =
- [[InstantConfirmWindowController alloc] initWithProfile:profile];
- [NSApp beginSheet:[controller window]
- modalForWindow:parent
- modalDelegate:nil
- didEndSelector:NULL
- contextInfo:NULL];
-}
-
-} // namespace browser
-
-@implementation InstantConfirmWindowController
-
-- (id)initWithProfile:(Profile*)profile {
- NSString* nibPath = [mac_util::MainAppBundle()
- pathForResource:@"InstantConfirm"
- ofType:@"nib"];
- if ((self = [super initWithWindowNibPath:nibPath owner:self])) {
- profile_ = profile;
- }
- return self;
-}
-
-- (void)awakeFromNib {
- DCHECK([self window]);
- DCHECK_EQ(self, [[self window] delegate]);
-
- CGFloat delta = [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:
- description_];
- NSRect descriptionFrame = [description_ frame];
- descriptionFrame.origin.y -= delta;
- [description_ setFrame:descriptionFrame];
-
- NSRect frame = [[self window] frame];
- frame.size.height += delta;
- [[self window] setFrame:frame display:YES];
-}
-
-- (void)windowWillClose:(NSNotification*)notif {
- [self autorelease];
-}
-
-- (IBAction)learnMore:(id)sender {
- browser::ShowOptionsURL(profile_, browser::InstantLearnMoreURL());
-}
-
-- (IBAction)ok:(id)sender {
- InstantController::Enable(profile_);
- [self cancel:sender];
-}
-
-- (IBAction)cancel:(id)sender {
- [NSApp endSheet:[self window]];
- [[self window] close];
-}
-
-@end
diff --git a/chrome/browser/cocoa/instant_confirm_window_controller_unittest.mm b/chrome/browser/cocoa/instant_confirm_window_controller_unittest.mm
deleted file mode 100644
index ec545bc..0000000
--- a/chrome/browser/cocoa/instant_confirm_window_controller_unittest.mm
+++ /dev/null
@@ -1,36 +0,0 @@
-// 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 "chrome/browser/cocoa/instant_confirm_window_controller.h"
-
-#import "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/instant/instant_confirm_dialog.h"
-
-namespace {
-
-class InstantConfirmWindowControllerTest : public CocoaTest {
- public:
- InstantConfirmWindowControllerTest() : controller_(nil) {}
-
- BrowserTestHelper helper_;
- InstantConfirmWindowController* controller_; // Weak. Owns self.
-};
-
-TEST_F(InstantConfirmWindowControllerTest, Init) {
- controller_ =
- [[InstantConfirmWindowController alloc] initWithProfile:
- helper_.profile()];
- EXPECT_TRUE([controller_ window]);
- [controller_ release];
-}
-
-TEST_F(InstantConfirmWindowControllerTest, Show) {
- browser::ShowInstantConfirmDialog(test_window(), helper_.profile());
- controller_ = [[test_window() attachedSheet] windowController];
- EXPECT_TRUE(controller_);
- [controller_ cancel:nil];
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/js_modal_dialog_cocoa.h b/chrome/browser/cocoa/js_modal_dialog_cocoa.h
deleted file mode 100644
index b31b1c2..0000000
--- a/chrome/browser/cocoa/js_modal_dialog_cocoa.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_JS_MODAL_DIALOG_COCOA_H_
-#define CHROME_BROWSER_COCOA_JS_MODAL_DIALOG_COCOA_H_
-#pragma once
-
-#include "chrome/browser/native_app_modal_dialog.h"
-
-#include "base/logging.h"
-#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-
-#if __OBJC__
-@class NSAlert;
-@class JavaScriptAppModalDialogHelper;
-#else
-class NSAlert;
-class JavaScriptAppModalDialogHelper;
-#endif
-
-class JSModalDialogCocoa : public NativeAppModalDialog {
- public:
- explicit JSModalDialogCocoa(JavaScriptAppModalDialog* dialog);
- virtual ~JSModalDialogCocoa();
-
- // Overridden from NativeAppModalDialog:
- virtual int GetAppModalDialogButtons() const;
- virtual void ShowAppModalDialog();
- virtual void ActivateAppModalDialog();
- virtual void CloseAppModalDialog();
- virtual void AcceptAppModalDialog();
- virtual void CancelAppModalDialog();
-
- JavaScriptAppModalDialog* dialog() const { return dialog_.get(); }
-
- private:
- scoped_ptr<JavaScriptAppModalDialog> dialog_;
-
- scoped_nsobject<JavaScriptAppModalDialogHelper> helper_;
- NSAlert* alert_; // weak, owned by |helper_|.
-
- DISALLOW_COPY_AND_ASSIGN(JSModalDialogCocoa);
-};
-
-#endif // CHROME_BROWSER_COCOA_JS_MODAL_DIALOG_COCOA_H_
-
diff --git a/chrome/browser/cocoa/js_modal_dialog_cocoa.mm b/chrome/browser/cocoa/js_modal_dialog_cocoa.mm
deleted file mode 100644
index ff1d349..0000000
--- a/chrome/browser/cocoa/js_modal_dialog_cocoa.mm
+++ /dev/null
@@ -1,219 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/js_modal_dialog_cocoa.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include "app/l10n_util_mac.h"
-#include "app/message_box_flags.h"
-#import "base/cocoa_protocols_mac.h"
-#include "base/logging.h"
-#include "base/sys_string_conversions.h"
-#import "chrome/browser/chrome_browser_application_mac.h"
-#include "chrome/browser/js_modal_dialog.h"
-#include "grit/app_strings.h"
-#include "grit/generated_resources.h"
-
-// Helper object that receives the notification that the dialog/sheet is
-// going away. Is responsible for cleaning itself up.
-@interface JavaScriptAppModalDialogHelper : NSObject<NSAlertDelegate> {
- @private
- NSAlert* alert_;
- NSTextField* textField_; // WEAK; owned by alert_
-}
-
-- (NSAlert*)alert;
-- (NSTextField*)textField;
-- (void)alertDidEnd:(NSAlert *)alert
- returnCode:(int)returnCode
- contextInfo:(void*)contextInfo;
-
-@end
-
-@implementation JavaScriptAppModalDialogHelper
-
-- (NSAlert*)alert {
- alert_ = [[NSAlert alloc] init];
- return alert_;
-}
-
-- (NSTextField*)textField {
- textField_ = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 300, 22)];
- [alert_ setAccessoryView:textField_];
- [textField_ release];
-
- return textField_;
-}
-
-- (void)dealloc {
- [alert_ release];
- [super dealloc];
-}
-
-// |contextInfo| is the JSModalDialogCocoa that owns us.
-- (void)alertDidEnd:(NSAlert*)alert
- returnCode:(int)returnCode
- contextInfo:(void*)contextInfo {
- scoped_ptr<JSModalDialogCocoa> native_dialog(
- reinterpret_cast<JSModalDialogCocoa*>(contextInfo));
- std::wstring input;
- if (textField_)
- input = base::SysNSStringToWide([textField_ stringValue]);
- bool shouldSuppress = false;
- if ([alert showsSuppressionButton])
- shouldSuppress = [[alert suppressionButton] state] == NSOnState;
- switch (returnCode) {
- case NSAlertFirstButtonReturn: { // OK
- native_dialog->dialog()->OnAccept(input, shouldSuppress);
- break;
- }
- case NSAlertSecondButtonReturn: { // Cancel
- // If the user wants to stay on this page, stop quitting (if a quit is in
- // progress).
- if (native_dialog->dialog()->is_before_unload_dialog())
- chrome_browser_application_mac::CancelTerminate();
- native_dialog->dialog()->OnCancel(shouldSuppress);
- break;
- }
- case NSRunStoppedResponse: { // Window was closed underneath us
- // Need to call OnCancel() because there is some cleanup that needs
- // to be done. It won't call back to the javascript since the
- // JavaScriptAppModalDialog knows that the TabContents was destroyed.
- native_dialog->dialog()->OnCancel(shouldSuppress);
- break;
- }
- default: {
- NOTREACHED();
- }
- }
-}
-@end
-
-////////////////////////////////////////////////////////////////////////////////
-// JSModalDialogCocoa, public:
-
-JSModalDialogCocoa::JSModalDialogCocoa(JavaScriptAppModalDialog* dialog)
- : dialog_(dialog),
- helper_(NULL) {
- // Determine the names of the dialog buttons based on the flags. "Default"
- // is the OK button. "Other" is the cancel button. We don't use the
- // "Alternate" button in NSRunAlertPanel.
- NSString* default_button = l10n_util::GetNSStringWithFixup(IDS_APP_OK);
- NSString* other_button = l10n_util::GetNSStringWithFixup(IDS_APP_CANCEL);
- bool text_field = false;
- bool one_button = false;
- switch (dialog_->dialog_flags()) {
- case MessageBoxFlags::kIsJavascriptAlert:
- one_button = true;
- break;
- case MessageBoxFlags::kIsJavascriptConfirm:
- if (dialog_->is_before_unload_dialog()) {
- default_button = l10n_util::GetNSStringWithFixup(
- IDS_BEFOREUNLOAD_MESSAGEBOX_OK_BUTTON_LABEL);
- other_button = l10n_util::GetNSStringWithFixup(
- IDS_BEFOREUNLOAD_MESSAGEBOX_CANCEL_BUTTON_LABEL);
- }
- break;
- case MessageBoxFlags::kIsJavascriptPrompt:
- text_field = true;
- break;
-
- default:
- NOTREACHED();
- }
-
- // Create a helper which will receive the sheet ended selector. It will
- // delete itself when done. It doesn't need anything passed to its init
- // as it will get a contextInfo parameter.
- helper_.reset([[JavaScriptAppModalDialogHelper alloc] init]);
-
- // Show the modal dialog.
- alert_ = [helper_ alert];
- NSTextField* field = nil;
- if (text_field) {
- field = [helper_ textField];
- [field setStringValue:base::SysWideToNSString(
- dialog_->default_prompt_text())];
- }
- [alert_ setDelegate:helper_];
- [alert_ setInformativeText:base::SysWideToNSString(dialog_->message_text())];
- [alert_ setMessageText:base::SysWideToNSString(dialog_->title())];
- [alert_ addButtonWithTitle:default_button];
- if (!one_button) {
- NSButton* other = [alert_ addButtonWithTitle:other_button];
- [other setKeyEquivalent:@"\e"];
- }
- if (dialog_->display_suppress_checkbox()) {
- [alert_ setShowsSuppressionButton:YES];
- NSString* suppression_title = l10n_util::GetNSStringWithFixup(
- IDS_JAVASCRIPT_MESSAGEBOX_SUPPRESS_OPTION);
- [[alert_ suppressionButton] setTitle:suppression_title];
- }
-}
-
-JSModalDialogCocoa::~JSModalDialogCocoa() {
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// JSModalDialogCocoa, NativeAppModalDialog implementation:
-
-int JSModalDialogCocoa::GetAppModalDialogButtons() const {
- // From the above, it is the case that if there is 1 button, it is always the
- // OK button. The second button, if it exists, is always the Cancel button.
- int num_buttons = [[alert_ buttons] count];
- switch (num_buttons) {
- case 1:
- return MessageBoxFlags::DIALOGBUTTON_OK;
- case 2:
- return MessageBoxFlags::DIALOGBUTTON_OK |
- MessageBoxFlags::DIALOGBUTTON_CANCEL;
- default:
- NOTREACHED();
- return 0;
- }
-}
-
-void JSModalDialogCocoa::ShowAppModalDialog() {
- [alert_
- beginSheetModalForWindow:nil // nil here makes it app-modal
- modalDelegate:helper_.get()
- didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
- contextInfo:this];
-
- if ([alert_ accessoryView])
- [[alert_ window] makeFirstResponder:[alert_ accessoryView]];
-}
-
-void JSModalDialogCocoa::ActivateAppModalDialog() {
-}
-
-void JSModalDialogCocoa::CloseAppModalDialog() {
- DCHECK([alert_ isKindOfClass:[NSAlert class]]);
-
- // Note: the call below will delete |this|,
- // see JavaScriptAppModalDialogHelper's alertDidEnd.
- [NSApp endSheet:[alert_ window]];
-}
-
-void JSModalDialogCocoa::AcceptAppModalDialog() {
- NSButton* first = [[alert_ buttons] objectAtIndex:0];
- [first performClick:nil];
-}
-
-void JSModalDialogCocoa::CancelAppModalDialog() {
- DCHECK([[alert_ buttons] count] >= 2);
- NSButton* second = [[alert_ buttons] objectAtIndex:1];
- [second performClick:nil];
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// NativeAppModalDialog, public:
-
-// static
-NativeAppModalDialog* NativeAppModalDialog::CreateNativeJavaScriptPrompt(
- JavaScriptAppModalDialog* dialog,
- gfx::NativeWindow parent_window) {
- return new JSModalDialogCocoa(dialog);
-}
diff --git a/chrome/browser/cocoa/keystone_glue.h b/chrome/browser/cocoa/keystone_glue.h
deleted file mode 100644
index 69b5351..0000000
--- a/chrome/browser/cocoa/keystone_glue.h
+++ /dev/null
@@ -1,209 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_KEYSTONE_GLUE_H_
-#define CHROME_BROWSER_COCOA_KEYSTONE_GLUE_H_
-#pragma once
-
-#include "base/string16.h"
-
-#if defined(__OBJC__)
-
-#import <Foundation/Foundation.h>
-
-#import "base/scoped_nsobject.h"
-#include "chrome/browser/cocoa/scoped_authorizationref.h"
-
-// Possible outcomes of various operations. A version may accompany some of
-// these, but beware: a version is never required. For statuses that can be
-// accompanied by a version, the comment indicates what version is referenced.
-// A notification posted containing an asynchronous status will always be
-// followed by a notification with a terminal status.
-enum AutoupdateStatus {
- kAutoupdateNone = 0, // no version (initial state only)
- kAutoupdateRegistering, // no version (asynchronous operation in progress)
- kAutoupdateRegistered, // no version
- kAutoupdateChecking, // no version (asynchronous operation in progress)
- kAutoupdateCurrent, // version of the running application
- kAutoupdateAvailable, // version of the update that is available
- kAutoupdateInstalling, // no version (asynchronous operation in progress)
- kAutoupdateInstalled, // version of the update that was installed
- kAutoupdatePromoting, // no version (asynchronous operation in progress)
- kAutoupdatePromoted, // no version
- kAutoupdateRegisterFailed, // no version
- kAutoupdateCheckFailed, // no version
- kAutoupdateInstallFailed, // no version
- kAutoupdatePromoteFailed, // no version
-};
-
-// kAutoupdateStatusNotification is the name of the notification posted when
-// -checkForUpdate and -installUpdate complete. This notification will be
-// sent with with its sender object set to the KeystoneGlue instance sending
-// the notification. Its userInfo dictionary will contain an AutoupdateStatus
-// value as an intValue at key kAutoupdateStatusStatus. If a version is
-// available (see AutoupdateStatus), it will be present at key
-// kAutoupdateStatusVersion.
-extern NSString* const kAutoupdateStatusNotification;
-extern NSString* const kAutoupdateStatusStatus;
-extern NSString* const kAutoupdateStatusVersion;
-
-namespace {
-
-enum BrandFileType {
- kBrandFileTypeNotDetermined = 0,
- kBrandFileTypeNone,
- kBrandFileTypeUser,
- kBrandFileTypeSystem,
-};
-
-} // namespace
-
-// KeystoneGlue is an adapter around the KSRegistration class, allowing it to
-// be used without linking directly against its containing KeystoneRegistration
-// framework. This is used in an environment where most builds (such as
-// developer builds) don't want or need Keystone support and might not even
-// have the framework available. Enabling Keystone support in an application
-// that uses KeystoneGlue is as simple as dropping
-// KeystoneRegistration.framework in the application's Frameworks directory
-// and providing the relevant information in its Info.plist. KeystoneGlue
-// requires that the KSUpdateURL key be set in the application's Info.plist,
-// and that it contain a string identifying the update URL to be used by
-// Keystone.
-
-@class KSRegistration;
-
-@interface KeystoneGlue : NSObject {
- @protected
-
- // Data for Keystone registration
- NSString* productID_;
- NSString* appPath_;
- NSString* url_;
- NSString* version_;
- NSString* channel_; // Logically: Dev, Beta, or Stable.
- BrandFileType brandFileType_;
-
- // And the Keystone registration itself, with the active timer
- KSRegistration* registration_; // strong
- NSTimer* timer_; // strong
-
- // The most recent kAutoupdateStatusNotification notification posted.
- scoped_nsobject<NSNotification> recentNotification_;
-
- // The authorization object, when it needs to persist because it's being
- // carried across threads.
- scoped_AuthorizationRef authorization_;
-
- // YES if a synchronous promotion operation is in progress (promotion during
- // installation).
- BOOL synchronousPromotion_;
-
- // YES if an update was ever successfully installed by -installUpdate.
- BOOL updateSuccessfullyInstalled_;
-}
-
-// Return the default Keystone Glue object.
-+ (id)defaultKeystoneGlue;
-
-// Load KeystoneRegistration.framework if present, call into it to register
-// with Keystone, and set up periodic activity pings.
-- (void)registerWithKeystone;
-
-// -checkForUpdate launches a check for updates, and -installUpdate begins
-// installing an available update. For each, status will be communicated via
-// a kAutoupdateStatusNotification notification, and will also be available
-// through -recentNotification.
-- (void)checkForUpdate;
-- (void)installUpdate;
-
-// Accessor for recentNotification_. Returns an autoreleased NSNotification.
-- (NSNotification*)recentNotification;
-
-// Accessor for the kAutoupdateStatusStatus field of recentNotification_'s
-// userInfo dictionary.
-- (AutoupdateStatus)recentStatus;
-
-// Returns YES if an asynchronous operation is pending: if an update check or
-// installation attempt is currently in progress.
-- (BOOL)asyncOperationPending;
-
-// Returns YES if the application is running from a read-only filesystem,
-// such as a disk image.
-- (BOOL)isOnReadOnlyFilesystem;
-
-// -needsPromotion is YES if the application needs its ticket promoted to
-// a system ticket. This will be YES when the application is on a user
-// ticket and determines that the current user does not have sufficient
-// permission to perform the update.
-//
-// -wantsPromotion is YES if the application wants its ticket promoted to
-// a system ticket, even if it doesn't need it as determined by
-// -needsPromotion. -wantsPromotion will always be YES if -needsPromotion is,
-// and it will additionally be YES when the application is on a user ticket
-// and appears to be installed in a system-wide location such as
-// /Applications.
-//
-// Use -needsPromotion to decide whether to show any update UI at all. If
-// it's YES, there's no sense in asking the user to "update now" because it
-// will fail given the rights and permissions involved. On the other hand,
-// when -needsPromotion is YES, the application can encourage the user to
-// promote the ticket so that updates will work properly.
-//
-// Use -wantsPromotion to decide whether to allow the user to promote. The
-// user shouldn't be nagged about promotion on the basis of -wantsPromotion,
-// but if it's YES, the user should be allowed to promote the ticket.
-- (BOOL)needsPromotion;
-- (BOOL)wantsPromotion;
-
-// Promotes the Keystone ticket into the system store. System Keystone will
-// be installed if necessary. If synchronous is NO, the promotion may occur
-// in the background. synchronous should be YES for promotion during
-// installation. The KeystoneGlue object assumes ownership of
-// authorization_arg.
-- (void)promoteTicketWithAuthorization:(AuthorizationRef)authorization_arg
- synchronous:(BOOL)synchronous;
-
-// Requests authorization and calls -promoteTicketWithAuthorization: in
-// asynchronous mode.
-- (void)promoteTicket;
-
-// Sets a new value for appPath. Used during installation to point a ticket
-// at the installed copy.
-- (void)setAppPath:(NSString*)appPath;
-
-@end // @interface KeystoneGlue
-
-@interface KeystoneGlue(ExposedForTesting)
-
-// Load any params we need for configuring Keystone.
-- (void)loadParameters;
-
-// Load the Keystone registration object.
-// Return NO on failure.
-- (BOOL)loadKeystoneRegistration;
-
-- (void)stopTimer;
-
-// Called when a checkForUpdate: notification completes.
-- (void)checkForUpdateComplete:(NSNotification*)notification;
-
-// Called when an installUpdate: notification completes.
-- (void)installUpdateComplete:(NSNotification*)notification;
-
-@end // @interface KeystoneGlue(ExposedForTesting)
-
-#endif // __OBJC__
-
-// Functions that may be accessed from non-Objective-C C/C++ code.
-namespace keystone_glue {
-
-// True if Keystone is enabled.
-bool KeystoneEnabled();
-
-// The version of the application currently installed on disk.
-string16 CurrentlyInstalledVersion();
-
-} // namespace keystone_glue
-
-#endif // CHROME_BROWSER_COCOA_KEYSTONE_GLUE_H_
diff --git a/chrome/browser/cocoa/keystone_glue.mm b/chrome/browser/cocoa/keystone_glue.mm
deleted file mode 100644
index 4ba9b21..0000000
--- a/chrome/browser/cocoa/keystone_glue.mm
+++ /dev/null
@@ -1,959 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/keystone_glue.h"
-
-#include <sys/param.h>
-#include <sys/mount.h>
-
-#include <vector>
-
-#include "app/l10n_util.h"
-#import "app/l10n_util_mac.h"
-#include "base/logging.h"
-#include "base/mac_util.h"
-#include "base/mac/scoped_nsautorelease_pool.h"
-#include "base/sys_string_conversions.h"
-#import "base/worker_pool_mac.h"
-#include "base/ref_counted.h"
-#include "base/task.h"
-#include "base/worker_pool.h"
-#include "chrome/browser/cocoa/authorization_util.h"
-#include "chrome/common/chrome_constants.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-
-namespace {
-
-// Provide declarations of the Keystone registration bits needed here. From
-// KSRegistration.h.
-typedef enum {
- kKSPathExistenceChecker,
-} KSExistenceCheckerType;
-
-typedef enum {
- kKSRegistrationUserTicket,
- kKSRegistrationSystemTicket,
- kKSRegistrationDontKnowWhatKindOfTicket,
-} KSRegistrationTicketType;
-
-NSString* const KSRegistrationVersionKey = @"Version";
-NSString* const KSRegistrationExistenceCheckerTypeKey = @"ExistenceCheckerType";
-NSString* const KSRegistrationExistenceCheckerStringKey =
- @"ExistenceCheckerString";
-NSString* const KSRegistrationServerURLStringKey = @"URLString";
-NSString* const KSRegistrationPreserveTrustedTesterTokenKey = @"PreserveTTT";
-NSString* const KSRegistrationTagKey = @"Tag";
-NSString* const KSRegistrationTagPathKey = @"TagPath";
-NSString* const KSRegistrationTagKeyKey = @"TagKey";
-NSString* const KSRegistrationBrandPathKey = @"BrandPath";
-NSString* const KSRegistrationBrandKeyKey = @"BrandKey";
-
-NSString* const KSRegistrationDidCompleteNotification =
- @"KSRegistrationDidCompleteNotification";
-NSString* const KSRegistrationPromotionDidCompleteNotification =
- @"KSRegistrationPromotionDidCompleteNotification";
-
-NSString* const KSRegistrationCheckForUpdateNotification =
- @"KSRegistrationCheckForUpdateNotification";
-NSString* KSRegistrationStatusKey = @"Status";
-NSString* KSRegistrationUpdateCheckErrorKey = @"Error";
-
-NSString* const KSRegistrationStartUpdateNotification =
- @"KSRegistrationStartUpdateNotification";
-NSString* const KSUpdateCheckSuccessfulKey = @"CheckSuccessful";
-NSString* const KSUpdateCheckSuccessfullyInstalledKey =
- @"SuccessfullyInstalled";
-
-NSString* const KSRegistrationRemoveExistingTag = @"";
-#define KSRegistrationPreserveExistingTag nil
-
-// Constants for the brand file (uses an external file so it can survive updates
-// to Chrome.
-
-#if defined(GOOGLE_CHROME_BUILD)
-#define kBrandFileName @"Google Chrome Brand.plist";
-#elif defined(CHROMIUM_BUILD)
-#define kBrandFileName @"Chromium Brand.plist";
-#else
-#error Unknown branding
-#endif
-
-// These directories are hardcoded in Keystone promotion preflight and the
-// Keystone install script, so NSSearchPathForDirectoriesInDomains isn't used
-// since the scripts couldn't use anything like that.
-NSString* kBrandUserFile = @"~/Library/Google/" kBrandFileName;
-NSString* kBrandSystemFile = @"/Library/Google/" kBrandFileName;
-
-NSString* UserBrandFilePath() {
- return [kBrandUserFile stringByStandardizingPath];
-}
-NSString* SystemBrandFilePath() {
- return [kBrandSystemFile stringByStandardizingPath];
-}
-
-// Adaptor for scheduling an Objective-C method call on a |WorkerPool|
-// thread.
-// TODO(shess): Move this into workerpool_mac.h?
-class PerformBridge : public base::RefCountedThreadSafe<PerformBridge> {
- public:
-
- // Call |sel| on |target| with |arg| in a WorkerPool thread.
- // |target| and |arg| are retained, |arg| may be |nil|.
- static void PostPerform(id target, SEL sel, id arg) {
- DCHECK(target);
- DCHECK(sel);
-
- scoped_refptr<PerformBridge> op = new PerformBridge(target, sel, arg);
- WorkerPool::PostTask(
- FROM_HERE, NewRunnableMethod(op.get(), &PerformBridge::Run), true);
- }
-
- // Convenience for the no-argument case.
- static void PostPerform(id target, SEL sel) {
- PostPerform(target, sel, nil);
- }
-
- private:
- // Allow RefCountedThreadSafe<> to delete.
- friend class base::RefCountedThreadSafe<PerformBridge>;
-
- PerformBridge(id target, SEL sel, id arg)
- : target_([target retain]),
- sel_(sel),
- arg_([arg retain]) {
- }
-
- ~PerformBridge() {}
-
- // Happens on a WorkerPool thread.
- void Run() {
- base::mac::ScopedNSAutoreleasePool pool;
- [target_ performSelector:sel_ withObject:arg_];
- }
-
- scoped_nsobject<id> target_;
- SEL sel_;
- scoped_nsobject<id> arg_;
-};
-
-} // namespace
-
-@interface KSRegistration : NSObject
-
-+ (id)registrationWithProductID:(NSString*)productID;
-
-- (BOOL)registerWithParameters:(NSDictionary*)args;
-
-- (BOOL)promoteWithParameters:(NSDictionary*)args
- authorization:(AuthorizationRef)authorization;
-
-- (void)setActive;
-- (void)checkForUpdate;
-- (void)startUpdate;
-- (KSRegistrationTicketType)ticketType;
-
-@end // @interface KSRegistration
-
-@interface KeystoneGlue(Private)
-
-// Returns the path to the application's Info.plist file. This returns the
-// outer application bundle's Info.plist, not the framework's Info.plist.
-- (NSString*)appInfoPlistPath;
-
-// Returns a dictionary containing parameters to be used for a KSRegistration
-// -registerWithParameters: or -promoteWithParameters:authorization: call.
-- (NSDictionary*)keystoneParameters;
-
-// Called when Keystone registration completes.
-- (void)registrationComplete:(NSNotification*)notification;
-
-// Called periodically to announce activity by pinging the Keystone server.
-- (void)markActive:(NSTimer*)timer;
-
-// Called when an update check or update installation is complete. Posts the
-// kAutoupdateStatusNotification notification to the default notification
-// center.
-- (void)updateStatus:(AutoupdateStatus)status version:(NSString*)version;
-
-// Returns the version of the currently-installed application on disk.
-- (NSString*)currentlyInstalledVersion;
-
-// These three methods are used to determine the version of the application
-// currently installed on disk, compare that to the currently-running version,
-// decide whether any updates have been installed, and call
-// -updateStatus:version:.
-//
-// In order to check the version on disk, the installed application's
-// Info.plist dictionary must be read; in order to see changes as updates are
-// applied, the dictionary must be read each time, bypassing any caches such
-// as the one that NSBundle might be maintaining. Reading files can be a
-// blocking operation, and blocking operations are to be avoided on the main
-// thread. I'm not quite sure what jank means, but I bet that a blocked main
-// thread would cause some of it.
-//
-// -determineUpdateStatusAsync is called on the main thread to initiate the
-// operation. It performs initial set-up work that must be done on the main
-// thread and arranges for -determineUpdateStatus to be called on a work queue
-// thread managed by WorkerPool.
-// -determineUpdateStatus then reads the Info.plist, gets the version from the
-// CFBundleShortVersionString key, and performs
-// -determineUpdateStatusForVersion: on the main thread.
-// -determineUpdateStatusForVersion: does the actual comparison of the version
-// on disk with the running version and calls -updateStatus:version: with the
-// results of its analysis.
-- (void)determineUpdateStatusAsync;
-- (void)determineUpdateStatus;
-- (void)determineUpdateStatusForVersion:(NSString*)version;
-
-// Returns YES if registration_ is definitely on a user ticket. If definitely
-// on a system ticket, or uncertain of ticket type (due to an older version
-// of Keystone being used), returns NO.
-- (BOOL)isUserTicket;
-
-// Called when ticket promotion completes.
-- (void)promotionComplete:(NSNotification*)notification;
-
-// Changes the application's ownership and permissions so that all files are
-// owned by root:wheel and all files and directories are writable only by
-// root, but readable and executable as needed by everyone.
-// -changePermissionsForPromotionAsync is called on the main thread by
-// -promotionComplete. That routine calls
-// -changePermissionsForPromotionWithTool: on a work queue thread. When done,
-// -changePermissionsForPromotionComplete is called on the main thread.
-- (void)changePermissionsForPromotionAsync;
-- (void)changePermissionsForPromotionWithTool:(NSString*)toolPath;
-- (void)changePermissionsForPromotionComplete;
-
-// Returns the brand file path to use for Keystone.
-- (NSString*)brandFilePath;
-
-@end // @interface KeystoneGlue(Private)
-
-NSString* const kAutoupdateStatusNotification = @"AutoupdateStatusNotification";
-NSString* const kAutoupdateStatusStatus = @"status";
-NSString* const kAutoupdateStatusVersion = @"version";
-
-namespace {
-
-NSString* const kChannelKey = @"KSChannelID";
-NSString* const kBrandKey = @"KSBrandID";
-
-} // namespace
-
-@implementation KeystoneGlue
-
-+ (id)defaultKeystoneGlue {
- static bool sTriedCreatingDefaultKeystoneGlue = false;
- // TODO(jrg): use base::SingletonObjC<KeystoneGlue>
- static KeystoneGlue* sDefaultKeystoneGlue = nil; // leaked
-
- if (!sTriedCreatingDefaultKeystoneGlue) {
- sTriedCreatingDefaultKeystoneGlue = true;
-
- sDefaultKeystoneGlue = [[KeystoneGlue alloc] init];
- [sDefaultKeystoneGlue loadParameters];
- if (![sDefaultKeystoneGlue loadKeystoneRegistration]) {
- [sDefaultKeystoneGlue release];
- sDefaultKeystoneGlue = nil;
- }
- }
- return sDefaultKeystoneGlue;
-}
-
-- (id)init {
- if ((self = [super init])) {
- NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
-
- [center addObserver:self
- selector:@selector(registrationComplete:)
- name:KSRegistrationDidCompleteNotification
- object:nil];
-
- [center addObserver:self
- selector:@selector(promotionComplete:)
- name:KSRegistrationPromotionDidCompleteNotification
- object:nil];
-
- [center addObserver:self
- selector:@selector(checkForUpdateComplete:)
- name:KSRegistrationCheckForUpdateNotification
- object:nil];
-
- [center addObserver:self
- selector:@selector(installUpdateComplete:)
- name:KSRegistrationStartUpdateNotification
- object:nil];
- }
-
- return self;
-}
-
-- (void)dealloc {
- [productID_ release];
- [appPath_ release];
- [url_ release];
- [version_ release];
- [channel_ release];
- [registration_ release];
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [super dealloc];
-}
-
-- (NSDictionary*)infoDictionary {
- // Use [NSBundle mainBundle] to get the application's own bundle identifier
- // and path, not the framework's. For auto-update, the application is
- // what's significant here: it's used to locate the outermost part of the
- // application for the existence checker and other operations that need to
- // see the entire application bundle.
- return [[NSBundle mainBundle] infoDictionary];
-}
-
-- (void)loadParameters {
- NSBundle* appBundle = [NSBundle mainBundle];
- NSDictionary* infoDictionary = [self infoDictionary];
-
- NSString* productID = [infoDictionary objectForKey:@"KSProductID"];
- if (productID == nil) {
- productID = [appBundle bundleIdentifier];
- }
-
- NSString* appPath = [appBundle bundlePath];
- NSString* url = [infoDictionary objectForKey:@"KSUpdateURL"];
- NSString* version = [infoDictionary objectForKey:@"KSVersion"];
-
- if (!productID || !appPath || !url || !version) {
- // If parameters required for Keystone are missing, don't use it.
- return;
- }
-
- NSString* channel = [infoDictionary objectForKey:kChannelKey];
- // The stable channel has no tag. If updating to stable, remove the
- // dev and beta tags since we've been "promoted".
- if (channel == nil)
- channel = KSRegistrationRemoveExistingTag;
-
- productID_ = [productID retain];
- appPath_ = [appPath retain];
- url_ = [url retain];
- version_ = [version retain];
- channel_ = [channel retain];
-}
-
-- (NSString*)brandFilePath {
- DCHECK(version_ != nil) << "-loadParameters must be called first";
-
- if (brandFileType_ == kBrandFileTypeNotDetermined) {
-
- // Default to none.
- brandFileType_ = kBrandFileTypeNone;
-
- // Having a channel means Dev/Beta, so there is no brand code to go with
- // those.
- if ([channel_ length] == 0) {
-
- NSString* userBrandFile = UserBrandFilePath();
- NSString* systemBrandFile = SystemBrandFilePath();
-
- NSFileManager* fm = [NSFileManager defaultManager];
-
- // If there is a system brand file, use it.
- if ([fm fileExistsAtPath:systemBrandFile]) {
- // System
-
- // Use the system file that is there.
- brandFileType_ = kBrandFileTypeSystem;
-
- // Clean up any old user level file.
- if ([fm fileExistsAtPath:userBrandFile]) {
- [fm removeItemAtPath:userBrandFile error:NULL];
- }
-
- } else {
- // User
-
- NSDictionary* infoDictionary = [self infoDictionary];
- NSString* appBundleBrandID = [infoDictionary objectForKey:kBrandKey];
-
- NSString* storedBrandID = nil;
- if ([fm fileExistsAtPath:userBrandFile]) {
- NSDictionary* storedBrandDict =
- [NSDictionary dictionaryWithContentsOfFile:userBrandFile];
- storedBrandID = [storedBrandDict objectForKey:kBrandKey];
- }
-
- if ((appBundleBrandID != nil) &&
- (![storedBrandID isEqualTo:appBundleBrandID])) {
- // App and store don't match, update store and use it.
- NSDictionary* storedBrandDict =
- [NSDictionary dictionaryWithObject:appBundleBrandID
- forKey:kBrandKey];
- // If Keystone hasn't been installed yet, the location the brand file
- // is written to won't exist, so manually create the directory.
- NSString *userBrandFileDirectory =
- [userBrandFile stringByDeletingLastPathComponent];
- if (![fm fileExistsAtPath:userBrandFileDirectory]) {
- if (![fm createDirectoryAtPath:userBrandFileDirectory
- withIntermediateDirectories:YES
- attributes:nil
- error:NULL]) {
- LOG(ERROR) << "Failed to create the directory for the brand file";
- }
- }
- if ([storedBrandDict writeToFile:userBrandFile atomically:YES]) {
- brandFileType_ = kBrandFileTypeUser;
- }
- } else if (storedBrandID) {
- // Had stored brand, use it.
- brandFileType_ = kBrandFileTypeUser;
- }
- }
- }
-
- }
-
- NSString* result = nil;
- switch (brandFileType_) {
- case kBrandFileTypeUser:
- result = UserBrandFilePath();
- break;
-
- case kBrandFileTypeSystem:
- result = SystemBrandFilePath();
- break;
-
- case kBrandFileTypeNotDetermined:
- NOTIMPLEMENTED();
- // Fall through
- case kBrandFileTypeNone:
- // Clear the value.
- result = @"";
- break;
-
- }
- return result;
-}
-
-- (BOOL)loadKeystoneRegistration {
- if (!productID_ || !appPath_ || !url_ || !version_)
- return NO;
-
- // Load the KeystoneRegistration framework bundle if present. It lives
- // inside the framework, so use mac_util::MainAppBundle();
- NSString* ksrPath =
- [[mac_util::MainAppBundle() privateFrameworksPath]
- stringByAppendingPathComponent:@"KeystoneRegistration.framework"];
- NSBundle* ksrBundle = [NSBundle bundleWithPath:ksrPath];
- [ksrBundle load];
-
- // Harness the KSRegistration class.
- Class ksrClass = [ksrBundle classNamed:@"KSRegistration"];
- KSRegistration* ksr = [ksrClass registrationWithProductID:productID_];
- if (!ksr)
- return NO;
-
- registration_ = [ksr retain];
- return YES;
-}
-
-- (NSString*)appInfoPlistPath {
- // NSBundle ought to have a way to access this path directly, but it
- // doesn't.
- return [[appPath_ stringByAppendingPathComponent:@"Contents"]
- stringByAppendingPathComponent:@"Info.plist"];
-}
-
-- (NSDictionary*)keystoneParameters {
- NSNumber* xcType = [NSNumber numberWithInt:kKSPathExistenceChecker];
- NSNumber* preserveTTToken = [NSNumber numberWithBool:YES];
- NSString* tagPath = [self appInfoPlistPath];
-
- NSString* brandKey = kBrandKey;
- NSString* brandPath = [self brandFilePath];
-
- if ([brandPath length] == 0) {
- // Brand path and brand key must be cleared together or ksadmin seems
- // to throw an error.
- brandKey = @"";
- }
-
- return [NSDictionary dictionaryWithObjectsAndKeys:
- version_, KSRegistrationVersionKey,
- xcType, KSRegistrationExistenceCheckerTypeKey,
- appPath_, KSRegistrationExistenceCheckerStringKey,
- url_, KSRegistrationServerURLStringKey,
- preserveTTToken, KSRegistrationPreserveTrustedTesterTokenKey,
- channel_, KSRegistrationTagKey,
- tagPath, KSRegistrationTagPathKey,
- kChannelKey, KSRegistrationTagKeyKey,
- brandPath, KSRegistrationBrandPathKey,
- brandKey, KSRegistrationBrandKeyKey,
- nil];
-}
-
-- (void)registerWithKeystone {
- [self updateStatus:kAutoupdateRegistering version:nil];
-
- NSDictionary* parameters = [self keystoneParameters];
- if (![registration_ registerWithParameters:parameters]) {
- [self updateStatus:kAutoupdateRegisterFailed version:nil];
- return;
- }
-
- // Upon completion, KSRegistrationDidCompleteNotification will be posted,
- // and -registrationComplete: will be called.
-
- // Mark an active RIGHT NOW; don't wait an hour for the first one.
- [registration_ setActive];
-
- // Set up hourly activity pings.
- timer_ = [NSTimer scheduledTimerWithTimeInterval:60 * 60 // One hour
- target:self
- selector:@selector(markActive:)
- userInfo:registration_
- repeats:YES];
-}
-
-- (void)registrationComplete:(NSNotification*)notification {
- NSDictionary* userInfo = [notification userInfo];
- if ([[userInfo objectForKey:KSRegistrationStatusKey] boolValue]) {
- [self updateStatus:kAutoupdateRegistered version:nil];
- } else {
- // Dump registration_?
- [self updateStatus:kAutoupdateRegisterFailed version:nil];
- }
-}
-
-- (void)stopTimer {
- [timer_ invalidate];
-}
-
-- (void)markActive:(NSTimer*)timer {
- KSRegistration* ksr = [timer userInfo];
- [ksr setActive];
-}
-
-- (void)checkForUpdate {
- DCHECK(![self asyncOperationPending]);
-
- if (!registration_) {
- [self updateStatus:kAutoupdateCheckFailed version:nil];
- return;
- }
-
- [self updateStatus:kAutoupdateChecking version:nil];
-
- [registration_ checkForUpdate];
-
- // Upon completion, KSRegistrationCheckForUpdateNotification will be posted,
- // and -checkForUpdateComplete: will be called.
-}
-
-- (void)checkForUpdateComplete:(NSNotification*)notification {
- NSDictionary* userInfo = [notification userInfo];
-
- if ([[userInfo objectForKey:KSRegistrationUpdateCheckErrorKey] boolValue]) {
- [self updateStatus:kAutoupdateCheckFailed version:nil];
- } else if ([[userInfo objectForKey:KSRegistrationStatusKey] boolValue]) {
- // If an update is known to be available, go straight to
- // -updateStatus:version:. It doesn't matter what's currently on disk.
- NSString* version = [userInfo objectForKey:KSRegistrationVersionKey];
- [self updateStatus:kAutoupdateAvailable version:version];
- } else {
- // If no updates are available, check what's on disk, because an update
- // may have already been installed. This check happens on another thread,
- // and -updateStatus:version: will be called on the main thread when done.
- [self determineUpdateStatusAsync];
- }
-}
-
-- (void)installUpdate {
- DCHECK(![self asyncOperationPending]);
-
- if (!registration_) {
- [self updateStatus:kAutoupdateInstallFailed version:nil];
- return;
- }
-
- [self updateStatus:kAutoupdateInstalling version:nil];
-
- [registration_ startUpdate];
-
- // Upon completion, KSRegistrationStartUpdateNotification will be posted,
- // and -installUpdateComplete: will be called.
-}
-
-- (void)installUpdateComplete:(NSNotification*)notification {
- NSDictionary* userInfo = [notification userInfo];
-
- if (![[userInfo objectForKey:KSUpdateCheckSuccessfulKey] boolValue] ||
- ![[userInfo objectForKey:KSUpdateCheckSuccessfullyInstalledKey]
- intValue]) {
- [self updateStatus:kAutoupdateInstallFailed version:nil];
- } else {
- updateSuccessfullyInstalled_ = YES;
-
- // Nothing in the notification dictionary reports the version that was
- // installed. Figure it out based on what's on disk.
- [self determineUpdateStatusAsync];
- }
-}
-
-- (NSString*)currentlyInstalledVersion {
- NSString* appInfoPlistPath = [self appInfoPlistPath];
- NSDictionary* infoPlist =
- [NSDictionary dictionaryWithContentsOfFile:appInfoPlistPath];
- return [infoPlist objectForKey:@"CFBundleShortVersionString"];
-}
-
-// Runs on the main thread.
-- (void)determineUpdateStatusAsync {
- DCHECK([NSThread isMainThread]);
-
- PerformBridge::PostPerform(self, @selector(determineUpdateStatus));
-}
-
-// Runs on a thread managed by WorkerPool.
-- (void)determineUpdateStatus {
- DCHECK(![NSThread isMainThread]);
-
- NSString* version = [self currentlyInstalledVersion];
-
- [self performSelectorOnMainThread:@selector(determineUpdateStatusForVersion:)
- withObject:version
- waitUntilDone:NO];
-}
-
-// Runs on the main thread.
-- (void)determineUpdateStatusForVersion:(NSString*)version {
- DCHECK([NSThread isMainThread]);
-
- AutoupdateStatus status;
- if (updateSuccessfullyInstalled_) {
- // If an update was successfully installed and this object saw it happen,
- // then don't even bother comparing versions.
- status = kAutoupdateInstalled;
- } else {
- NSString* currentVersion =
- [NSString stringWithUTF8String:chrome::kChromeVersion];
- if (!version) {
- // If the version on disk could not be determined, assume that
- // whatever's running is current.
- version = currentVersion;
- status = kAutoupdateCurrent;
- } else if ([version isEqualToString:currentVersion]) {
- status = kAutoupdateCurrent;
- } else {
- // If the version on disk doesn't match what's currently running, an
- // update must have been applied in the background, without this app's
- // direct participation. Leave updateSuccessfullyInstalled_ alone
- // because there's no direct knowledge of what actually happened.
- status = kAutoupdateInstalled;
- }
- }
-
- [self updateStatus:status version:version];
-}
-
-- (void)updateStatus:(AutoupdateStatus)status version:(NSString*)version {
- NSNumber* statusNumber = [NSNumber numberWithInt:status];
- NSMutableDictionary* dictionary =
- [NSMutableDictionary dictionaryWithObject:statusNumber
- forKey:kAutoupdateStatusStatus];
- if (version) {
- [dictionary setObject:version forKey:kAutoupdateStatusVersion];
- }
-
- NSNotification* notification =
- [NSNotification notificationWithName:kAutoupdateStatusNotification
- object:self
- userInfo:dictionary];
- recentNotification_.reset([notification retain]);
-
- [[NSNotificationCenter defaultCenter] postNotification:notification];
-}
-
-- (NSNotification*)recentNotification {
- return [[recentNotification_ retain] autorelease];
-}
-
-- (AutoupdateStatus)recentStatus {
- NSDictionary* dictionary = [recentNotification_ userInfo];
- return static_cast<AutoupdateStatus>(
- [[dictionary objectForKey:kAutoupdateStatusStatus] intValue]);
-}
-
-- (BOOL)asyncOperationPending {
- AutoupdateStatus status = [self recentStatus];
- return status == kAutoupdateRegistering ||
- status == kAutoupdateChecking ||
- status == kAutoupdateInstalling ||
- status == kAutoupdatePromoting;
-}
-
-- (BOOL)isUserTicket {
- return [registration_ ticketType] == kKSRegistrationUserTicket;
-}
-
-- (BOOL)isOnReadOnlyFilesystem {
- const char* appPathC = [appPath_ fileSystemRepresentation];
- struct statfs statfsBuf;
-
- if (statfs(appPathC, &statfsBuf) != 0) {
- PLOG(ERROR) << "statfs";
- // Be optimistic about the filesystem's writability.
- return NO;
- }
-
- return (statfsBuf.f_flags & MNT_RDONLY) != 0;
-}
-
-- (BOOL)needsPromotion {
- if (![self isUserTicket] || [self isOnReadOnlyFilesystem]) {
- return NO;
- }
-
- // Check the outermost bundle directory, the main executable path, and the
- // framework directory. It may be enough to just look at the outermost
- // bundle directory, but checking an interior file and directory can be
- // helpful in case permissions are set differently only on the outermost
- // directory. An interior file and directory are both checked because some
- // file operations, such as Snow Leopard's Finder's copy operation when
- // authenticating, may actually result in different ownership being applied
- // to files and directories.
- NSFileManager* fileManager = [NSFileManager defaultManager];
- NSString* executablePath = [[NSBundle mainBundle] executablePath];
- NSString* frameworkPath = [mac_util::MainAppBundle() bundlePath];
- return ![fileManager isWritableFileAtPath:appPath_] ||
- ![fileManager isWritableFileAtPath:executablePath] ||
- ![fileManager isWritableFileAtPath:frameworkPath];
-}
-
-- (BOOL)wantsPromotion {
- // -needsPromotion checks these too, but this method doesn't necessarily
- // return NO just becuase -needsPromotion returns NO, so another check is
- // needed here.
- if (![self isUserTicket] || [self isOnReadOnlyFilesystem]) {
- return NO;
- }
-
- if ([self needsPromotion]) {
- return YES;
- }
-
- return [appPath_ hasPrefix:@"/Applications/"];
-}
-
-- (void)promoteTicket {
- if ([self asyncOperationPending] || ![self wantsPromotion]) {
- // Because there are multiple ways of reaching promoteTicket that might
- // not lock each other out, it may be possible to arrive here while an
- // asynchronous operation is pending, or even after promotion has already
- // occurred. Just quietly return without doing anything.
- return;
- }
-
- NSString* prompt = l10n_util::GetNSStringFWithFixup(
- IDS_PROMOTE_AUTHENTICATION_PROMPT,
- l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
- scoped_AuthorizationRef authorization(
- authorization_util::AuthorizationCreateToRunAsRoot(
- reinterpret_cast<CFStringRef>(prompt)));
- if (!authorization.get()) {
- return;
- }
-
- [self promoteTicketWithAuthorization:authorization.release() synchronous:NO];
-}
-
-- (void)promoteTicketWithAuthorization:(AuthorizationRef)authorization_arg
- synchronous:(BOOL)synchronous {
- scoped_AuthorizationRef authorization(authorization_arg);
- authorization_arg = NULL;
-
- if ([self asyncOperationPending]) {
- // Starting a synchronous operation while an asynchronous one is pending
- // could be trouble.
- return;
- }
- if (!synchronous && ![self wantsPromotion]) {
- // If operating synchronously, the call came from the installer, which
- // means that a system ticket is required. Otherwise, only allow
- // promotion if it's wanted.
- return;
- }
-
- synchronousPromotion_ = synchronous;
-
- [self updateStatus:kAutoupdatePromoting version:nil];
-
- // TODO(mark): Remove when able!
- //
- // keystone_promote_preflight will copy the current brand information out to
- // the system level so all users can share the data as part of the ticket
- // promotion.
- //
- // It will also ensure that the Keystone system ticket store is in a usable
- // state for all users on the system. Ideally, Keystone's installer or
- // another part of Keystone would handle this. The underlying problem is
- // http://b/2285921, and it causes http://b/2289908, which this workaround
- // addresses.
- //
- // This is run synchronously, which isn't optimal, but
- // -[KSRegistration promoteWithParameters:authorization:] is currently
- // synchronous too, and this operation needs to happen before that one.
- //
- // TODO(mark): Make asynchronous. That only makes sense if the promotion
- // operation itself is asynchronous too. http://b/2290009. Hopefully,
- // the Keystone promotion code will just be changed to do what preflight
- // now does, and then the preflight script can be removed instead.
- // However, preflight operation (and promotion) should only be asynchronous
- // if the synchronous parameter is NO.
- NSString* preflightPath =
- [mac_util::MainAppBundle() pathForResource:@"keystone_promote_preflight"
- ofType:@"sh"];
- const char* preflightPathC = [preflightPath fileSystemRepresentation];
- const char* userBrandFile = NULL;
- const char* systemBrandFile = NULL;
- if (brandFileType_ == kBrandFileTypeUser) {
- // Running with user level brand file, promote to the system level.
- userBrandFile = [UserBrandFilePath() fileSystemRepresentation];
- systemBrandFile = [SystemBrandFilePath() fileSystemRepresentation];
- }
- const char* arguments[] = {userBrandFile, systemBrandFile, NULL};
-
- int exit_status;
- OSStatus status = authorization_util::ExecuteWithPrivilegesAndWait(
- authorization,
- preflightPathC,
- kAuthorizationFlagDefaults,
- arguments,
- NULL, // pipe
- &exit_status);
- if (status != errAuthorizationSuccess) {
- LOG(ERROR) << "AuthorizationExecuteWithPrivileges preflight: " << status;
- [self updateStatus:kAutoupdatePromoteFailed version:nil];
- return;
- }
- if (exit_status != 0) {
- LOG(ERROR) << "keystone_promote_preflight status " << exit_status;
- [self updateStatus:kAutoupdatePromoteFailed version:nil];
- return;
- }
-
- // Hang on to the AuthorizationRef so that it can be used once promotion is
- // complete. Do this before asking Keystone to promote the ticket, because
- // -promotionComplete: may be called from inside the Keystone promotion
- // call.
- authorization_.swap(authorization);
-
- NSDictionary* parameters = [self keystoneParameters];
-
- // If the brand file is user level, update parameters to point to the new
- // system level file during promotion.
- if (brandFileType_ == kBrandFileTypeUser) {
- NSMutableDictionary* temp_parameters =
- [[parameters mutableCopy] autorelease];
- [temp_parameters setObject:SystemBrandFilePath()
- forKey:KSRegistrationBrandPathKey];
- parameters = temp_parameters;
- }
-
- if (![registration_ promoteWithParameters:parameters
- authorization:authorization_]) {
- [self updateStatus:kAutoupdatePromoteFailed version:nil];
- authorization_.reset();
- return;
- }
-
- // Upon completion, KSRegistrationPromotionDidCompleteNotification will be
- // posted, and -promotionComplete: will be called.
-}
-
-- (void)promotionComplete:(NSNotification*)notification {
- NSDictionary* userInfo = [notification userInfo];
- if ([[userInfo objectForKey:KSRegistrationStatusKey] boolValue]) {
- if (synchronousPromotion_) {
- // Short-circuit: if performing a synchronous promotion, the promotion
- // came from the installer, which already set the permissions properly.
- // Rather than run a duplicate permission-changing operation, jump
- // straight to "done."
- [self changePermissionsForPromotionComplete];
- } else {
- [self changePermissionsForPromotionAsync];
- }
- } else {
- authorization_.reset();
- [self updateStatus:kAutoupdatePromoteFailed version:nil];
- }
-}
-
-- (void)changePermissionsForPromotionAsync {
- // NSBundle is not documented as being thread-safe. Do NSBundle operations
- // on the main thread before jumping over to a WorkerPool-managed
- // thread to run the tool.
- DCHECK([NSThread isMainThread]);
-
- SEL selector = @selector(changePermissionsForPromotionWithTool:);
- NSString* toolPath =
- [mac_util::MainAppBundle() pathForResource:@"keystone_promote_postflight"
- ofType:@"sh"];
-
- PerformBridge::PostPerform(self, selector, toolPath);
-}
-
-- (void)changePermissionsForPromotionWithTool:(NSString*)toolPath {
- const char* toolPathC = [toolPath fileSystemRepresentation];
-
- const char* appPathC = [appPath_ fileSystemRepresentation];
- const char* arguments[] = {appPathC, NULL};
-
- int exit_status;
- OSStatus status = authorization_util::ExecuteWithPrivilegesAndWait(
- authorization_,
- toolPathC,
- kAuthorizationFlagDefaults,
- arguments,
- NULL, // pipe
- &exit_status);
- if (status != errAuthorizationSuccess) {
- LOG(ERROR) << "AuthorizationExecuteWithPrivileges postflight: " << status;
- } else if (exit_status != 0) {
- LOG(ERROR) << "keystone_promote_postflight status " << exit_status;
- }
-
- SEL selector = @selector(changePermissionsForPromotionComplete);
- [self performSelectorOnMainThread:selector
- withObject:nil
- waitUntilDone:NO];
-}
-
-- (void)changePermissionsForPromotionComplete {
- authorization_.reset();
-
- [self updateStatus:kAutoupdatePromoted version:nil];
-}
-
-- (void)setAppPath:(NSString*)appPath {
- if (appPath != appPath_) {
- [appPath_ release];
- appPath_ = [appPath copy];
- }
-}
-
-@end // @implementation KeystoneGlue
-
-namespace keystone_glue {
-
-bool KeystoneEnabled() {
- return [KeystoneGlue defaultKeystoneGlue] != nil;
-}
-
-string16 CurrentlyInstalledVersion() {
- KeystoneGlue* keystoneGlue = [KeystoneGlue defaultKeystoneGlue];
- NSString* version = [keystoneGlue currentlyInstalledVersion];
- return base::SysNSStringToUTF16(version);
-}
-
-} // namespace keystone_glue
diff --git a/chrome/browser/cocoa/keystone_glue_unittest.mm b/chrome/browser/cocoa/keystone_glue_unittest.mm
deleted file mode 100644
index 9d49a09..0000000
--- a/chrome/browser/cocoa/keystone_glue_unittest.mm
+++ /dev/null
@@ -1,184 +0,0 @@
-// Copyright (c) 2009 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 <Foundation/Foundation.h>
-#import <objc/objc-class.h>
-
-#import "chrome/browser/cocoa/keystone_glue.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-@interface FakeGlueRegistration : NSObject
-@end
-
-
-@implementation FakeGlueRegistration
-
-// Send the notifications that a real KeystoneGlue object would send.
-
-- (void)checkForUpdate {
- NSNumber* yesNumber = [NSNumber numberWithBool:YES];
- NSString* statusKey = @"Status";
- NSDictionary* dictionary = [NSDictionary dictionaryWithObject:yesNumber
- forKey:statusKey];
- NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
- [center postNotificationName:@"KSRegistrationCheckForUpdateNotification"
- object:nil
- userInfo:dictionary];
-}
-
-- (void)startUpdate {
- NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
- [center postNotificationName:@"KSRegistrationStartUpdateNotification"
- object:nil];
-}
-
-@end
-
-
-@interface FakeKeystoneGlue : KeystoneGlue {
- @public
- BOOL upToDate_;
- NSString *latestVersion_;
- BOOL successful_;
- int installs_;
-}
-
-- (void)fakeAboutWindowCallback:(NSNotification*)notification;
-@end
-
-
-@implementation FakeKeystoneGlue
-
-- (id)init {
- if ((self = [super init])) {
- // some lies
- upToDate_ = YES;
- latestVersion_ = @"foo bar";
- successful_ = YES;
- installs_ = 1010101010;
-
- // Set up an observer that takes the notification that the About window
- // listens for.
- NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
- [center addObserver:self
- selector:@selector(fakeAboutWindowCallback:)
- name:kAutoupdateStatusNotification
- object:nil];
- }
- return self;
-}
-
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [super dealloc];
-}
-
-// For mocking
-- (NSDictionary*)infoDictionary {
- NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
- @"http://foo.bar", @"KSUpdateURL",
- @"com.google.whatever", @"KSProductID",
- @"0.0.0.1", @"KSVersion",
- nil];
- return dict;
-}
-
-// For mocking
-- (BOOL)loadKeystoneRegistration {
- return YES;
-}
-
-// Confirms certain things are happy
-- (BOOL)dictReadCorrectly {
- return ([url_ isEqual:@"http://foo.bar"] &&
- [productID_ isEqual:@"com.google.whatever"] &&
- [version_ isEqual:@"0.0.0.1"]);
-}
-
-// Confirms certain things are happy
-- (BOOL)hasATimer {
- return timer_ ? YES : NO;
-}
-
-- (void)addFakeRegistration {
- registration_ = [[FakeGlueRegistration alloc] init];
-}
-
-- (void)fakeAboutWindowCallback:(NSNotification*)notification {
- NSDictionary* dictionary = [notification userInfo];
- AutoupdateStatus status = static_cast<AutoupdateStatus>(
- [[dictionary objectForKey:kAutoupdateStatusStatus] intValue]);
-
- if (status == kAutoupdateAvailable) {
- upToDate_ = NO;
- latestVersion_ = [dictionary objectForKey:kAutoupdateStatusVersion];
- } else if (status == kAutoupdateInstallFailed) {
- successful_ = NO;
- installs_ = 0;
- }
-}
-
-// Confirm we look like callbacks with nil NSNotifications
-- (BOOL)confirmCallbacks {
- return (!upToDate_ &&
- (latestVersion_ == nil) &&
- !successful_ &&
- (installs_ == 0));
-}
-
-@end
-
-
-namespace {
-
-class KeystoneGlueTest : public PlatformTest {
-};
-
-// DISABLED because the mocking isn't currently working.
-TEST_F(KeystoneGlueTest, DISABLED_BasicGlobalCreate) {
- // Allow creation of a KeystoneGlue by mocking out a few calls
- SEL ids = @selector(infoDictionary);
- IMP oldInfoImp_ = [[KeystoneGlue class] instanceMethodForSelector:ids];
- IMP newInfoImp_ = [[FakeKeystoneGlue class] instanceMethodForSelector:ids];
- Method infoMethod_ = class_getInstanceMethod([KeystoneGlue class], ids);
- method_setImplementation(infoMethod_, newInfoImp_);
-
- SEL lks = @selector(loadKeystoneRegistration);
- IMP oldLoadImp_ = [[KeystoneGlue class] instanceMethodForSelector:lks];
- IMP newLoadImp_ = [[FakeKeystoneGlue class] instanceMethodForSelector:lks];
- Method loadMethod_ = class_getInstanceMethod([KeystoneGlue class], lks);
- method_setImplementation(loadMethod_, newLoadImp_);
-
- KeystoneGlue *glue = [KeystoneGlue defaultKeystoneGlue];
- ASSERT_TRUE(glue);
-
- // Fix back up the class to the way we found it.
- method_setImplementation(infoMethod_, oldInfoImp_);
- method_setImplementation(loadMethod_, oldLoadImp_);
-}
-
-// DISABLED because the mocking isn't currently working.
-TEST_F(KeystoneGlueTest, DISABLED_BasicUse) {
- FakeKeystoneGlue* glue = [[[FakeKeystoneGlue alloc] init] autorelease];
- [glue loadParameters];
- ASSERT_TRUE([glue dictReadCorrectly]);
-
- // Likely returns NO in the unit test, but call it anyway to make
- // sure it doesn't crash.
- [glue loadKeystoneRegistration];
-
- // Confirm we start up an active timer
- [glue registerWithKeystone];
- ASSERT_TRUE([glue hasATimer]);
- [glue stopTimer];
-
- // Brief exercise of callbacks
- [glue addFakeRegistration];
- [glue checkForUpdate];
- [glue installUpdate];
- ASSERT_TRUE([glue confirmCallbacks]);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/keystone_infobar.h b/chrome/browser/cocoa/keystone_infobar.h
deleted file mode 100644
index 9a89027..0000000
--- a/chrome/browser/cocoa/keystone_infobar.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_KEYSTONE_INFOBAR_H_
-#define CHROME_BROWSER_COCOA_KEYSTONE_INFOBAR_H_
-#pragma once
-
-class Profile;
-
-class KeystoneInfoBar {
- public:
- // If the application is Keystone-enabled and not on a read-only filesystem
- // (capable of being auto-updated), and Keystone indicates that it needs
- // ticket promotion, PromotionInfoBar displays an info bar asking the user
- // to promote the ticket. The user will need to authenticate in order to
- // gain authorization to perform the promotion. The info bar is not shown
- // if its "don't ask" button was ever clicked, if the "don't check default
- // browser" command-line flag is present, on the very first launch, or if
- // another info bar is already showing in the active tab.
- static void PromotionInfoBar(Profile* profile);
-};
-
-#endif // CHROME_BROWSER_COCOA_KEYSTONE_INFOBAR_H_
diff --git a/chrome/browser/cocoa/keystone_infobar.mm b/chrome/browser/cocoa/keystone_infobar.mm
deleted file mode 100644
index bb62d10..0000000
--- a/chrome/browser/cocoa/keystone_infobar.mm
+++ /dev/null
@@ -1,212 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/keystone_infobar.h"
-
-#import <AppKit/AppKit.h>
-
-#include <string>
-
-#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
-#include "base/command_line.h"
-#include "base/message_loop.h"
-#include "base/task.h"
-#import "chrome/browser/cocoa/keystone_glue.h"
-#include "chrome/browser/first_run/first_run.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/tab_contents/infobar_delegate.h"
-#include "chrome/browser/tab_contents/navigation_controller.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_list.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/pref_names.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-
-class SkBitmap;
-
-namespace {
-
-class KeystonePromotionInfoBarDelegate : public ConfirmInfoBarDelegate {
- public:
- KeystonePromotionInfoBarDelegate(TabContents* tab_contents)
- : ConfirmInfoBarDelegate(tab_contents),
- profile_(tab_contents->profile()),
- can_expire_(false),
- ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
- const int kCanExpireOnNavigationAfterMilliseconds = 8 * 1000;
- MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- method_factory_.NewRunnableMethod(
- &KeystonePromotionInfoBarDelegate::SetCanExpire),
- kCanExpireOnNavigationAfterMilliseconds);
- }
-
- virtual ~KeystonePromotionInfoBarDelegate() {}
-
- // Inherited from InfoBarDelegate and overridden.
-
- virtual bool ShouldExpire(
- const NavigationController::LoadCommittedDetails& details) {
- return can_expire_;
- }
-
- virtual void InfoBarClosed() {
- delete this;
- }
-
- // Inherited from AlertInfoBarDelegate and overridden.
-
- virtual string16 GetMessageText() const {
- return l10n_util::GetStringFUTF16(IDS_PROMOTE_INFOBAR_TEXT,
- l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
- }
-
- virtual SkBitmap* GetIcon() const {
- return ResourceBundle::GetSharedInstance().GetBitmapNamed(
- IDR_PRODUCT_ICON_32);
- }
-
- // Inherited from ConfirmInfoBarDelegate and overridden.
-
- virtual int GetButtons() const {
- return BUTTON_OK | BUTTON_CANCEL | BUTTON_OK_DEFAULT;
- }
-
- virtual string16 GetButtonLabel(InfoBarButton button) const {
- return button == BUTTON_OK ?
- l10n_util::GetStringUTF16(IDS_PROMOTE_INFOBAR_PROMOTE_BUTTON) :
- l10n_util::GetStringUTF16(IDS_PROMOTE_INFOBAR_DONT_ASK_BUTTON);
- }
-
- virtual bool Accept() {
- [[KeystoneGlue defaultKeystoneGlue] promoteTicket];
- return true;
- }
-
- virtual bool Cancel() {
- profile_->GetPrefs()->SetBoolean(prefs::kShowUpdatePromotionInfoBar, false);
- return true;
- }
-
- private:
- // Sets this info bar to be able to expire. Called a predetermined amount
- // of time after this object is created.
- void SetCanExpire() {
- can_expire_ = true;
- }
-
- // The TabContents' profile.
- Profile* profile_; // weak
-
- // Whether the info bar should be dismissed on the next navigation.
- bool can_expire_;
-
- // Used to delay the expiration of the info bar.
- ScopedRunnableMethodFactory<KeystonePromotionInfoBarDelegate> method_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(KeystonePromotionInfoBarDelegate);
-};
-
-} // namespace
-
-@interface KeystonePromotionInfoBar : NSObject
-- (void)checkAndShowInfoBarForProfile:(Profile*)profile;
-- (void)updateStatus:(NSNotification*)notification;
-- (void)removeObserver;
-@end // @interface KeystonePromotionInfoBar
-
-@implementation KeystonePromotionInfoBar
-
-- (void)dealloc {
- [self removeObserver];
- [super dealloc];
-}
-
-- (void)checkAndShowInfoBarForProfile:(Profile*)profile {
- // If this is the first run, the user clicked the "don't ask again" button
- // at some point in the past, or if the "don't ask about the default
- // browser" command-line switch is present, bail out. That command-line
- // switch is recycled here because it's likely that the set of users that
- // don't want to be nagged about the default browser also don't want to be
- // nagged about the update check. (Automated testers, I'm thinking of
- // you...)
- CommandLine* commandLine = CommandLine::ForCurrentProcess();
- if (FirstRun::IsChromeFirstRun() ||
- !profile->GetPrefs()->GetBoolean(prefs::kShowUpdatePromotionInfoBar) ||
- commandLine->HasSwitch(switches::kNoDefaultBrowserCheck)) {
- return;
- }
-
- // If there is no Keystone glue (maybe because this application isn't
- // Keystone-enabled) or the application is on a read-only filesystem,
- // doing anything related to auto-update is pointless. Bail out.
- KeystoneGlue* keystoneGlue = [KeystoneGlue defaultKeystoneGlue];
- if (!keystoneGlue || [keystoneGlue isOnReadOnlyFilesystem]) {
- return;
- }
-
- // Stay alive as long as needed. This is balanced by a release in
- // -updateStatus:.
- [self retain];
-
- AutoupdateStatus recentStatus = [keystoneGlue recentStatus];
- if (recentStatus == kAutoupdateNone ||
- recentStatus == kAutoupdateRegistering) {
- NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
- [center addObserver:self
- selector:@selector(updateStatus:)
- name:kAutoupdateStatusNotification
- object:nil];
- } else {
- [self updateStatus:[keystoneGlue recentNotification]];
- }
-}
-
-- (void)updateStatus:(NSNotification*)notification {
- NSDictionary* dictionary = [notification userInfo];
- AutoupdateStatus status = static_cast<AutoupdateStatus>(
- [[dictionary objectForKey:kAutoupdateStatusStatus] intValue]);
-
- if (status == kAutoupdateNone || status == kAutoupdateRegistering) {
- return;
- }
-
- [self removeObserver];
-
- if (status != kAutoupdateRegisterFailed &&
- [[KeystoneGlue defaultKeystoneGlue] needsPromotion]) {
- Browser* browser = BrowserList::GetLastActive();
- if (browser) {
- TabContents* tabContents = browser->GetSelectedTabContents();
-
- // Only show if no other info bars are showing, because that's how the
- // default browser info bar works.
- if (tabContents && tabContents->infobar_delegate_count() == 0) {
- tabContents->AddInfoBar(
- new KeystonePromotionInfoBarDelegate(tabContents));
- }
- }
- }
-
- [self release];
-}
-
-- (void)removeObserver {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
-}
-
-@end // @implementation KeystonePromotionInfoBar
-
-// static
-void KeystoneInfoBar::PromotionInfoBar(Profile* profile) {
- KeystonePromotionInfoBar* promotionInfoBar =
- [[[KeystonePromotionInfoBar alloc] init] autorelease];
-
- [promotionInfoBar checkAndShowInfoBarForProfile:profile];
-}
diff --git a/chrome/browser/cocoa/keystone_promote_postflight.sh b/chrome/browser/cocoa/keystone_promote_postflight.sh
deleted file mode 100755
index 510e5d2..0000000
--- a/chrome/browser/cocoa/keystone_promote_postflight.sh
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/bin/bash -p
-
-# Copyright (c) 2009 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.
-
-# Called as root after Keystone ticket promotion to change the owner, group,
-# and permissions on the application. The application bundle and its contents
-# are set to owner root, group wheel, and to be writable only by root, but
-# readable and executable (when appropriate) by everyone.
-#
-# Note that this script will be invoked with the real user ID set to the
-# user's ID, but the effective user ID set to 0 (root). bash -p is used on
-# the first line to prevent bash from setting the effective user ID to the
-# real user ID (dropping root privileges).
-#
-# WARNING: This script is NOT currently run when the Keystone ticket is
-# promoted during application installation directly from the disk image,
-# because the installation process itself handles the same permission fix-ups
-# that this script normally would.
-
-set -e
-
-# This script runs as root, so be paranoid about things like ${PATH}.
-export PATH="/usr/bin:/usr/sbin:/bin:/sbin"
-
-# Output the pid to stdout before doing anything else. See
-# chrome/browser/cocoa/authorization_util.h.
-echo "${$}"
-
-if [ ${#} -ne 1 ] ; then
- echo "usage: ${0} APP" >& 2
- exit 2
-fi
-
-APP="${1}"
-
-# Make sure that APP is an absolute path and that it exists.
-if [ -z "${APP}" ] || [ "${APP:0:1}" != "/" ] || [ ! -d "${APP}" ] ; then
- echo "${0}: must provide an absolute path naming an extant directory" >& 2
- exit 3
-fi
-
-OWNER_GROUP="root:wheel"
-chown -Rh "${OWNER_GROUP}" "${APP}" >& /dev/null
-
-CHMOD_MODE="a+rX,u+w,go-w"
-chmod -R "${CHMOD_MODE}" "${APP}" >& /dev/null
-
-# On the Mac, or at least on HFS+, symbolic link permissions are significant,
-# but chmod -R and -h can't be used together. Do another pass to fix the
-# permissions on any symbolic links.
-find "${APP}" -type l -exec chmod -h "${CHMOD_MODE}" {} + >& /dev/null
-
-exit 0
diff --git a/chrome/browser/cocoa/keyword_editor_cocoa_controller.h b/chrome/browser/cocoa/keyword_editor_cocoa_controller.h
deleted file mode 100644
index d833cec..0000000
--- a/chrome/browser/cocoa/keyword_editor_cocoa_controller.h
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright (c) 2009 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 "app/table_model_observer.h"
-#import "base/cocoa_protocols_mac.h"
-#include "base/scoped_ptr.h"
-#include "base/string16.h"
-#include "chrome/browser/cocoa/table_row_nsimage_cache.h"
-#include "chrome/browser/search_engines/edit_search_engine_controller.h"
-#include "chrome/browser/search_engines/keyword_editor_controller.h"
-#include "chrome/browser/search_engines/template_url_model_observer.h"
-
-class EditSearchEngineControllerDelegate;
-@class KeywordEditorCocoaController;
-class Profile;
-@class WindowSizeAutosaver;
-
-// Very thin bridge that simply pushes notifications from C++ to ObjC.
-class KeywordEditorModelObserver : public TemplateURLModelObserver,
- public EditSearchEngineControllerDelegate,
- public TableModelObserver,
- public TableRowNSImageCache::Table {
- public:
- explicit KeywordEditorModelObserver(KeywordEditorCocoaController* controller);
- virtual ~KeywordEditorModelObserver();
-
- // Notification that the template url model has changed in some way.
- virtual void OnTemplateURLModelChanged();
-
- // Invoked from the EditSearchEngineController when the user accepts the
- // edits. NOTE: |template_url| is the value supplied to
- // EditSearchEngineController's constructor, and may be NULL. A NULL value
- // indicates a new TemplateURL should be created rather than modifying an
- // existing TemplateURL.
- virtual void OnEditedKeyword(const TemplateURL* template_url,
- const string16& title,
- const string16& keyword,
- const std::string& url);
-
- // TableModelObserver overrides. Invalidate icon cache.
- virtual void OnModelChanged();
- virtual void OnItemsChanged(int start, int length);
- virtual void OnItemsAdded(int start, int length);
- virtual void OnItemsRemoved(int start, int length);
-
- // TableRowNSImageCache::Table
- virtual int RowCount() const;
- virtual SkBitmap GetIcon(int row) const;
-
- // Lazily converts the image at the given row and caches it in |icon_cache_|.
- NSImage* GetImageForRow(int row);
-
- private:
- KeywordEditorCocoaController* controller_;
-
- TableRowNSImageCache icon_cache_;
-
- DISALLOW_COPY_AND_ASSIGN(KeywordEditorModelObserver);
-};
-
-// This controller manages a window with a table view of search engines. It
-// acts as |tableView_|'s data source and delegate, feeding it data from the
-// KeywordEditorController's |table_model()|.
-
-@interface KeywordEditorCocoaController : NSWindowController
- <NSWindowDelegate,
- NSTableViewDataSource,
- NSTableViewDelegate> {
- IBOutlet NSTableView* tableView_;
- IBOutlet NSButton* addButton_;
- IBOutlet NSButton* removeButton_;
- IBOutlet NSButton* makeDefaultButton_;
-
- scoped_nsobject<NSTextFieldCell> groupCell_;
-
- Profile* profile_; // weak
- scoped_ptr<KeywordEditorController> controller_;
- scoped_ptr<KeywordEditorModelObserver> observer_;
-
- scoped_nsobject<WindowSizeAutosaver> sizeSaver_;
-}
-@property (nonatomic, readonly) KeywordEditorController* controller;
-
-// Show the keyword editor associated with the given profile (or the
-// original profile if this is an incognito profile). If no keyword
-// editor exists for this profile, create one and show it. Any
-// resulting editor releases itself when closed.
-+ (void)showKeywordEditor:(Profile*)profile;
-
-- (KeywordEditorController*)controller;
-
-// Message forwarded by KeywordEditorModelObserver.
-- (void)modelChanged;
-
-- (IBAction)addKeyword:(id)sender;
-- (IBAction)deleteKeyword:(id)sender;
-- (IBAction)makeDefault:(id)sender;
-
-@end
-
-@interface KeywordEditorCocoaController (TestingAPI)
-
-// Instances of this class are managed, use +showKeywordEditor:.
-- (id)initWithProfile:(Profile*)profile;
-
-// Returns a reference to the shared instance for the given profile,
-// or nil if there is none.
-+ (KeywordEditorCocoaController*)sharedInstanceForProfile:(Profile*)profile;
-
-// Converts a row index in our table view (which has group header rows) into
-// one in the |controller_|'s model, which does not have them.
-- (int)indexInModelForRow:(NSUInteger)row;
-
-@end
diff --git a/chrome/browser/cocoa/keyword_editor_cocoa_controller.mm b/chrome/browser/cocoa/keyword_editor_cocoa_controller.mm
deleted file mode 100644
index 20a3c93..0000000
--- a/chrome/browser/cocoa/keyword_editor_cocoa_controller.mm
+++ /dev/null
@@ -1,422 +0,0 @@
-// Copyright (c) 2009 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>
-
-#import "chrome/browser/cocoa/keyword_editor_cocoa_controller.h"
-
-#import "base/mac_util.h"
-#include "base/singleton.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/browser_process.h"
-#import "chrome/browser/cocoa/edit_search_engine_cocoa_controller.h"
-#import "chrome/browser/cocoa/window_size_autosaver.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/search_engines/template_url_model.h"
-#include "chrome/browser/search_engines/template_url_table_model.h"
-#include "chrome/common/pref_names.h"
-#include "grit/generated_resources.h"
-#include "skia/ext/skia_utils_mac.h"
-#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-namespace {
-
-const CGFloat kButtonBarHeight = 35.0;
-
-} // namespace
-
-@interface KeywordEditorCocoaController (Private)
-- (void)adjustEditingButtons;
-- (void)editKeyword:(id)sender;
-- (int)indexInModelForRow:(NSUInteger)row;
-@end
-
-// KeywordEditorModelObserver -------------------------------------------------
-
-KeywordEditorModelObserver::KeywordEditorModelObserver(
- KeywordEditorCocoaController* controller)
- : controller_(controller),
- icon_cache_(this) {
-}
-
-KeywordEditorModelObserver::~KeywordEditorModelObserver() {
-}
-
-// Notification that the template url model has changed in some way.
-void KeywordEditorModelObserver::OnTemplateURLModelChanged() {
- [controller_ modelChanged];
-}
-
-void KeywordEditorModelObserver::OnEditedKeyword(
- const TemplateURL* template_url,
- const string16& title,
- const string16& keyword,
- const std::string& url) {
- KeywordEditorController* controller = [controller_ controller];
- if (template_url) {
- controller->ModifyTemplateURL(template_url, title, keyword, url);
- } else {
- controller->AddTemplateURL(title, keyword, url);
- }
-}
-
-void KeywordEditorModelObserver::OnModelChanged() {
- icon_cache_.OnModelChanged();
- [controller_ modelChanged];
-}
-
-void KeywordEditorModelObserver::OnItemsChanged(int start, int length) {
- icon_cache_.OnItemsChanged(start, length);
- [controller_ modelChanged];
-}
-
-void KeywordEditorModelObserver::OnItemsAdded(int start, int length) {
- icon_cache_.OnItemsAdded(start, length);
- [controller_ modelChanged];
-}
-
-void KeywordEditorModelObserver::OnItemsRemoved(int start, int length) {
- icon_cache_.OnItemsRemoved(start, length);
- [controller_ modelChanged];
-}
-
-int KeywordEditorModelObserver::RowCount() const {
- return [controller_ controller]->table_model()->RowCount();
-}
-
-SkBitmap KeywordEditorModelObserver::GetIcon(int row) const {
- return [controller_ controller]->table_model()->GetIcon(row);
-}
-
-NSImage* KeywordEditorModelObserver::GetImageForRow(int row) {
- return icon_cache_.GetImageForRow(row);
-}
-
-// KeywordEditorCocoaController -----------------------------------------------
-
-namespace {
-
-typedef std::map<Profile*,KeywordEditorCocoaController*> ProfileControllerMap;
-
-} // namespace
-
-@implementation KeywordEditorCocoaController
-
-+ (KeywordEditorCocoaController*)sharedInstanceForProfile:(Profile*)profile {
- ProfileControllerMap* map = Singleton<ProfileControllerMap>::get();
- DCHECK(map != NULL);
- ProfileControllerMap::iterator it = map->find(profile);
- if (it != map->end()) {
- return it->second;
- }
- return nil;
-}
-
-// TODO(shess): The Windows code watches a single global window which
-// is not distinguished by profile. This code could distinguish by
-// profile by checking the controller's class and profile.
-+ (void)showKeywordEditor:(Profile*)profile {
- // http://crbug.com/23359 describes a case where this panel is
- // opened from an incognito window, which can leave the panel
- // holding onto a stale profile. Since the same panel is used
- // either way, arrange to use the original profile instead.
- profile = profile->GetOriginalProfile();
-
- ProfileControllerMap* map = Singleton<ProfileControllerMap>::get();
- DCHECK(map != NULL);
- ProfileControllerMap::iterator it = map->find(profile);
- if (it == map->end()) {
- // Since we don't currently support multiple profiles, this class
- // has not been tested against them, so document that assumption.
- DCHECK_EQ(map->size(), 0U);
-
- KeywordEditorCocoaController* controller =
- [[self alloc] initWithProfile:profile];
- it = map->insert(std::make_pair(profile, controller)).first;
- }
-
- [it->second showWindow:nil];
-}
-
-- (id)initWithProfile:(Profile*)profile {
- DCHECK(profile);
- NSString* nibpath = [mac_util::MainAppBundle()
- pathForResource:@"KeywordEditor"
- ofType:@"nib"];
- if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
- profile_ = profile;
- controller_.reset(new KeywordEditorController(profile_));
- observer_.reset(new KeywordEditorModelObserver(self));
- controller_->table_model()->SetObserver(observer_.get());
- controller_->url_model()->AddObserver(observer_.get());
- groupCell_.reset([[NSTextFieldCell alloc] init]);
-
- if (g_browser_process && g_browser_process->local_state()) {
- sizeSaver_.reset([[WindowSizeAutosaver alloc]
- initWithWindow:[self window]
- prefService:g_browser_process->local_state()
- path:prefs::kKeywordEditorWindowPlacement]);
- }
- }
- return self;
-}
-
-- (void)dealloc {
- controller_->table_model()->SetObserver(NULL);
- controller_->url_model()->RemoveObserver(observer_.get());
- [tableView_ setDataSource:nil];
- observer_.reset();
- [super dealloc];
-}
-
-- (void)awakeFromNib {
- // Make sure the button fits its label, but keep it the same height as the
- // other two buttons.
- [GTMUILocalizerAndLayoutTweaker sizeToFitView:makeDefaultButton_];
- NSSize size = [makeDefaultButton_ frame].size;
- size.height = NSHeight([addButton_ frame]);
- [makeDefaultButton_ setFrameSize:size];
-
- [[self window] setAutorecalculatesContentBorderThickness:NO
- forEdge:NSMinYEdge];
- [[self window] setContentBorderThickness:kButtonBarHeight
- forEdge:NSMinYEdge];
-
- [self adjustEditingButtons];
- [tableView_ setDoubleAction:@selector(editKeyword:)];
- [tableView_ setTarget:self];
-}
-
-// When the window closes, clean ourselves up.
-- (void)windowWillClose:(NSNotification*)notif {
- [self autorelease];
-
- ProfileControllerMap* map = Singleton<ProfileControllerMap>::get();
- ProfileControllerMap::iterator it = map->find(profile_);
- // It should not be possible for this to be missing.
- // TODO(shess): Except that the unit test reaches in directly.
- // Consider circling around and refactoring that.
- //DCHECK(it != map->end());
- if (it != map->end()) {
- map->erase(it);
- }
-}
-
-- (void)modelChanged {
- [tableView_ reloadData];
- [self adjustEditingButtons];
-}
-
-- (KeywordEditorController*)controller {
- return controller_.get();
-}
-
-- (void)sheetDidEnd:(NSWindow*)sheet
- returnCode:(NSInteger)code
- context:(void*)context {
- [sheet orderOut:self];
-}
-
-- (IBAction)addKeyword:(id)sender {
- // The controller will release itself when the window closes.
- EditSearchEngineCocoaController* editor =
- [[EditSearchEngineCocoaController alloc] initWithProfile:profile_
- delegate:observer_.get()
- templateURL:NULL];
- [NSApp beginSheet:[editor window]
- modalForWindow:[self window]
- modalDelegate:self
- didEndSelector:@selector(sheetDidEnd:returnCode:context:)
- contextInfo:NULL];
-}
-
-- (void)editKeyword:(id)sender {
- const NSInteger clickedRow = [tableView_ clickedRow];
- if (clickedRow < 0 || [self tableView:tableView_ isGroupRow:clickedRow])
- return;
- const TemplateURL* url = controller_->GetTemplateURL(
- [self indexInModelForRow:clickedRow]);
- // The controller will release itself when the window closes.
- EditSearchEngineCocoaController* editor =
- [[EditSearchEngineCocoaController alloc] initWithProfile:profile_
- delegate:observer_.get()
- templateURL:url];
- [NSApp beginSheet:[editor window]
- modalForWindow:[self window]
- modalDelegate:self
- didEndSelector:@selector(sheetDidEnd:returnCode:context:)
- contextInfo:NULL];
-}
-
-- (IBAction)deleteKeyword:(id)sender {
- NSIndexSet* selection = [tableView_ selectedRowIndexes];
- DCHECK_GT([selection count], 0U);
- NSUInteger index = [selection lastIndex];
- while (index != NSNotFound) {
- controller_->RemoveTemplateURL([self indexInModelForRow:index]);
- index = [selection indexLessThanIndex:index];
- }
-}
-
-- (IBAction)makeDefault:(id)sender {
- NSIndexSet* selection = [tableView_ selectedRowIndexes];
- DCHECK_EQ([selection count], 1U);
- int row = [self indexInModelForRow:[selection firstIndex]];
- controller_->MakeDefaultTemplateURL(row);
-}
-
-// Called when the user hits the escape key. Closes the window.
-- (void)cancel:(id)sender {
- [[self window] performClose:self];
-}
-
-// Table View Data Source -----------------------------------------------------
-
-- (NSInteger)numberOfRowsInTableView:(NSTableView*)table {
- int rowCount = controller_->table_model()->RowCount();
- int numGroups = controller_->table_model()->GetGroups().size();
- if ([self tableView:table isGroupRow:rowCount + numGroups - 1]) {
- // Don't show a group header with no rows underneath it.
- --numGroups;
- }
- return rowCount + numGroups;
-}
-
-- (id)tableView:(NSTableView*)tv
- objectValueForTableColumn:(NSTableColumn*)tableColumn
- row:(NSInteger)row {
- if ([self tableView:tv isGroupRow:row]) {
- DCHECK(!tableColumn);
- TableModel::Groups groups = controller_->table_model()->GetGroups();
- if (row == 0) {
- return base::SysWideToNSString(groups[0].title);
- } else {
- return base::SysWideToNSString(groups[1].title);
- }
- }
-
- NSString* identifier = [tableColumn identifier];
- if ([identifier isEqualToString:@"name"]) {
- // The name column is an NSButtonCell so we can have text and image in the
- // same cell. As such, the "object value" for a button cell is either on
- // or off, so we always return off so we don't act like a button.
- return [NSNumber numberWithInt:NSOffState];
- }
- if ([identifier isEqualToString:@"keyword"]) {
- // The keyword object value is a normal string.
- int index = [self indexInModelForRow:row];
- int columnID = IDS_SEARCH_ENGINES_EDITOR_KEYWORD_COLUMN;
- std::wstring text = controller_->table_model()->GetText(index, columnID);
- return base::SysWideToNSString(text);
- }
-
- // And we shouldn't have any other columns...
- NOTREACHED();
- return nil;
-}
-
-// Table View Delegate --------------------------------------------------------
-
-// When the selection in the table view changes, we need to adjust buttons.
-- (void)tableViewSelectionDidChange:(NSNotification*)aNotification {
- [self adjustEditingButtons];
-}
-
-// Disallow selection of the group header rows.
-- (BOOL)tableView:(NSTableView*)table shouldSelectRow:(NSInteger)row {
- return ![self tableView:table isGroupRow:row];
-}
-
-- (BOOL)tableView:(NSTableView*)table isGroupRow:(NSInteger)row {
- int otherGroupRow =
- controller_->table_model()->last_search_engine_index() + 1;
- return (row == 0 || row == otherGroupRow);
-}
-
-- (NSCell*)tableView:(NSTableView*)tableView
- dataCellForTableColumn:(NSTableColumn*)tableColumn
- row:(NSInteger)row {
- static const CGFloat kCellFontSize = 12.0;
-
- // Check to see if we are a grouped row.
- if ([self tableView:tableView isGroupRow:row]) {
- DCHECK(!tableColumn); // This would violate the group row contract.
- return groupCell_.get();
- }
-
- NSCell* cell = [tableColumn dataCellForRow:row];
- int offsetRow = [self indexInModelForRow:row];
-
- // Set the favicon and title for the search engine in the name column.
- if ([[tableColumn identifier] isEqualToString:@"name"]) {
- DCHECK([cell isKindOfClass:[NSButtonCell class]]);
- NSButtonCell* buttonCell = static_cast<NSButtonCell*>(cell);
- std::wstring title = controller_->table_model()->GetText(offsetRow,
- IDS_SEARCH_ENGINES_EDITOR_DESCRIPTION_COLUMN);
- [buttonCell setTitle:base::SysWideToNSString(title)];
- [buttonCell setImage:observer_->GetImageForRow(offsetRow)];
- [buttonCell setRefusesFirstResponder:YES]; // Don't push in like a button.
- [buttonCell setHighlightsBy:NSNoCellMask];
- }
-
- // The default search engine should be in bold font.
- const TemplateURL* defaultEngine =
- controller_->url_model()->GetDefaultSearchProvider();
- int rowIndex = controller_->table_model()->IndexOfTemplateURL(defaultEngine);
- if (rowIndex == offsetRow) {
- [cell setFont:[NSFont boldSystemFontOfSize:kCellFontSize]];
- } else {
- [cell setFont:[NSFont systemFontOfSize:kCellFontSize]];
- }
- return cell;
-}
-
-// Private --------------------------------------------------------------------
-
-// This function appropriately sets the enabled states on the table's editing
-// buttons.
-- (void)adjustEditingButtons {
- NSIndexSet* selection = [tableView_ selectedRowIndexes];
- BOOL canRemove = ([selection count] > 0);
- NSUInteger index = [selection firstIndex];
-
- // Delete button.
- while (canRemove && index != NSNotFound) {
- int modelIndex = [self indexInModelForRow:index];
- const TemplateURL& url =
- controller_->table_model()->GetTemplateURL(modelIndex);
- if (!controller_->CanRemove(&url))
- canRemove = NO;
- index = [selection indexGreaterThanIndex:index];
- }
- [removeButton_ setEnabled:canRemove];
-
- // Make default button.
- if ([selection count] != 1) {
- [makeDefaultButton_ setEnabled:NO];
- } else {
- int row = [self indexInModelForRow:[selection firstIndex]];
- const TemplateURL& url =
- controller_->table_model()->GetTemplateURL(row);
- [makeDefaultButton_ setEnabled:controller_->CanMakeDefault(&url)];
- }
-}
-
-// This converts a row index in our table view to an index in the model by
-// computing the group offsets.
-- (int)indexInModelForRow:(NSUInteger)row {
- DCHECK_GT(row, 0U);
- unsigned otherGroupId =
- controller_->table_model()->last_search_engine_index() + 1;
- DCHECK_NE(row, otherGroupId);
- if (row >= otherGroupId) {
- return row - 2; // Other group.
- } else {
- return row - 1; // Default group.
- }
-}
-
-@end
diff --git a/chrome/browser/cocoa/keyword_editor_cocoa_controller_unittest.mm b/chrome/browser/cocoa/keyword_editor_cocoa_controller_unittest.mm
deleted file mode 100644
index b2bd0fc..0000000
--- a/chrome/browser/cocoa/keyword_editor_cocoa_controller_unittest.mm
+++ /dev/null
@@ -1,227 +0,0 @@
-// Copyright (c) 2009 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/mac/scoped_nsautorelease_pool.h"
-#include "base/scoped_nsobject.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/keyword_editor_cocoa_controller.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_model.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/test/testing_profile.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-@interface FakeKeywordEditorController : KeywordEditorCocoaController {
- @public
- BOOL modelChanged_;
-}
-- (void)modelChanged;
-- (BOOL)hasModelChanged;
-- (KeywordEditorModelObserver*)observer;
-@end
-
-@implementation FakeKeywordEditorController
-
-- (void)modelChanged {
- modelChanged_ = YES;
-}
-
-- (BOOL)hasModelChanged {
- return modelChanged_;
-}
-
-- (KeywordEditorModelObserver*)observer {
- return observer_.get();
-}
-
-- (NSTableView*)tableView {
- return tableView_;
-}
-
-@end
-
-// TODO(rsesek): Figure out a good way to test this class (crbug.com/21640).
-
-namespace {
-
-class KeywordEditorCocoaControllerTest : public CocoaTest {
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
- TestingProfile* profile =
- static_cast<TestingProfile*>(browser_helper_.profile());
- profile->CreateTemplateURLModel();
-
- controller_ =
- [[FakeKeywordEditorController alloc] initWithProfile:profile];
- }
-
- virtual void TearDown() {
- // Force the window to load so we hit |-awakeFromNib| to register as the
- // window's delegate so that the controller can clean itself up in
- // |-windowWillClose:|.
- ASSERT_TRUE([controller_ window]);
-
- [controller_ close];
- CocoaTest::TearDown();
- }
-
- // Helper to count the keyword editors.
- NSUInteger CountKeywordEditors() {
- base::mac::ScopedNSAutoreleasePool pool;
- NSUInteger count = 0;
- for (NSWindow* window in [NSApp windows]) {
- id controller = [window windowController];
- if ([controller isKindOfClass:[KeywordEditorCocoaController class]]) {
- ++count;
- }
- }
- return count;
- }
-
- BrowserTestHelper browser_helper_;
- FakeKeywordEditorController* controller_;
-};
-
-TEST_F(KeywordEditorCocoaControllerTest, TestModelChanged) {
- EXPECT_FALSE([controller_ hasModelChanged]);
- KeywordEditorModelObserver* observer = [controller_ observer];
- observer->OnTemplateURLModelChanged();
- EXPECT_TRUE([controller_ hasModelChanged]);
-}
-
-// Test that +showKeywordEditor brings up the existing editor and
-// creates one if needed.
-TEST_F(KeywordEditorCocoaControllerTest, ShowKeywordEditor) {
- // No outstanding editors.
- Profile* profile(browser_helper_.profile());
- KeywordEditorCocoaController* sharedInstance =
- [KeywordEditorCocoaController sharedInstanceForProfile:profile];
- EXPECT_TRUE(nil == sharedInstance);
- EXPECT_EQ(CountKeywordEditors(), 0U);
-
- const NSUInteger initial_window_count([[NSApp windows] count]);
-
- // The window unwinds using -autorelease, so we need to introduce an
- // autorelease pool to really test whether it went away or not.
- {
- base::mac::ScopedNSAutoreleasePool pool;
-
- // +showKeywordEditor: creates a new controller.
- [KeywordEditorCocoaController showKeywordEditor:profile];
- sharedInstance =
- [KeywordEditorCocoaController sharedInstanceForProfile:profile];
- EXPECT_TRUE(sharedInstance);
- EXPECT_EQ(CountKeywordEditors(), 1U);
-
- // Another call doesn't create another controller.
- [KeywordEditorCocoaController showKeywordEditor:profile];
- EXPECT_TRUE(sharedInstance ==
- [KeywordEditorCocoaController sharedInstanceForProfile:profile]);
- EXPECT_EQ(CountKeywordEditors(), 1U);
-
- [sharedInstance close];
- }
-
- // No outstanding editors.
- sharedInstance =
- [KeywordEditorCocoaController sharedInstanceForProfile:profile];
- EXPECT_TRUE(nil == sharedInstance);
- EXPECT_EQ(CountKeywordEditors(), 0U);
-
- // Windows we created should be gone.
- EXPECT_EQ([[NSApp windows] count], initial_window_count);
-
- // Get a new editor, should be different from the previous one.
- [KeywordEditorCocoaController showKeywordEditor:profile];
- KeywordEditorCocoaController* newSharedInstance =
- [KeywordEditorCocoaController sharedInstanceForProfile:profile];
- EXPECT_TRUE(sharedInstance != newSharedInstance);
- EXPECT_EQ(CountKeywordEditors(), 1U);
- [newSharedInstance close];
-}
-
-TEST_F(KeywordEditorCocoaControllerTest, IndexInModelForRowMixed) {
- [controller_ window]; // Force |-awakeFromNib|.
- TemplateURLModel* template_model = [controller_ controller]->url_model();
-
- // Add a default engine.
- TemplateURL* t_url = new TemplateURL();
- t_url->SetURL("http://test1/{searchTerms}", 0, 0);
- t_url->set_keyword(L"test1");
- t_url->set_short_name(L"Test1");
- t_url->set_show_in_default_list(true);
- template_model->Add(t_url);
-
- // Add a non-default engine.
- t_url = new TemplateURL();
- t_url->SetURL("http://test2/{searchTerms}", 0, 0);
- t_url->set_keyword(L"test2");
- t_url->set_short_name(L"Test2");
- t_url->set_show_in_default_list(false);
- template_model->Add(t_url);
-
- // Two headers with a single row underneath each.
- NSTableView* table = [controller_ tableView];
- [table reloadData];
- ASSERT_EQ(4, [[controller_ tableView] numberOfRows]);
-
- // Index 0 is the group header, index 1 should be the first engine.
- ASSERT_EQ(0, [controller_ indexInModelForRow:1]);
-
- // Index 2 should be the group header, so index 3 should be the non-default
- // engine.
- ASSERT_EQ(1, [controller_ indexInModelForRow:3]);
-
- ASSERT_TRUE([controller_ tableView:table isGroupRow:0]);
- ASSERT_FALSE([controller_ tableView:table isGroupRow:1]);
- ASSERT_TRUE([controller_ tableView:table isGroupRow:2]);
- ASSERT_FALSE([controller_ tableView:table isGroupRow:3]);
-
- ASSERT_FALSE([controller_ tableView:table shouldSelectRow:0]);
- ASSERT_TRUE([controller_ tableView:table shouldSelectRow:1]);
- ASSERT_FALSE([controller_ tableView:table shouldSelectRow:2]);
- ASSERT_TRUE([controller_ tableView:table shouldSelectRow:3]);
-}
-
-TEST_F(KeywordEditorCocoaControllerTest, IndexInModelForDefault) {
- [controller_ window]; // Force |-awakeFromNib|.
- TemplateURLModel* template_model = [controller_ controller]->url_model();
-
- // Add 2 default engines.
- TemplateURL* t_url = new TemplateURL();
- t_url->SetURL("http://test1/{searchTerms}", 0, 0);
- t_url->set_keyword(L"test1");
- t_url->set_short_name(L"Test1");
- t_url->set_show_in_default_list(true);
- template_model->Add(t_url);
-
- t_url = new TemplateURL();
- t_url->SetURL("http://test2/{searchTerms}", 0, 0);
- t_url->set_keyword(L"test2");
- t_url->set_short_name(L"Test2");
- t_url->set_show_in_default_list(true);
- template_model->Add(t_url);
-
- // One header and two rows.
- NSTableView* table = [controller_ tableView];
- [table reloadData];
- ASSERT_EQ(3, [[controller_ tableView] numberOfRows]);
-
- // Index 0 is the group header, index 1 should be the first engine.
- ASSERT_EQ(0, [controller_ indexInModelForRow:1]);
- ASSERT_EQ(1, [controller_ indexInModelForRow:2]);
-
- ASSERT_TRUE([controller_ tableView:table isGroupRow:0]);
- ASSERT_FALSE([controller_ tableView:table isGroupRow:1]);
- ASSERT_FALSE([controller_ tableView:table isGroupRow:2]);
-
- ASSERT_FALSE([controller_ tableView:table shouldSelectRow:0]);
- ASSERT_TRUE([controller_ tableView:table shouldSelectRow:1]);
- ASSERT_TRUE([controller_ tableView:table shouldSelectRow:2]);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/l10n_util.mm b/chrome/browser/cocoa/l10n_util.mm
deleted file mode 100644
index e39bdb3..0000000
--- a/chrome/browser/cocoa/l10n_util.mm
+++ /dev/null
@@ -1,78 +0,0 @@
-// 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 "chrome/browser/cocoa/l10n_util.h"
-
-#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
-#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-
-namespace cocoa_l10n_util {
-
-NSInteger CompareFrameY(id view1, id view2, void* context) {
- CGFloat y1 = NSMinY([view1 frame]);
- CGFloat y2 = NSMinY([view2 frame]);
- if (y1 < y2)
- return NSOrderedAscending;
- else if (y1 > y2)
- return NSOrderedDescending;
- else
- return NSOrderedSame;
-}
-
-NSSize WrapOrSizeToFit(NSView* view) {
- if ([view isKindOfClass:[NSTextField class]]) {
- NSTextField* textField = static_cast<NSTextField*>(view);
- if ([textField isEditable])
- return NSZeroSize;
- CGFloat heightChange =
- [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:textField];
- return NSMakeSize(0.0, heightChange);
- }
- if ([view isKindOfClass:[NSMatrix class]]) {
- NSMatrix* radioGroup = static_cast<NSMatrix*>(view);
- [GTMUILocalizerAndLayoutTweaker wrapRadioGroupForWidth:radioGroup];
- return [GTMUILocalizerAndLayoutTweaker sizeToFitView:view];
- }
- if ([view isKindOfClass:[NSButton class]]) {
- NSButton* button = static_cast<NSButton*>(view);
- NSButtonCell* buttonCell = [button cell];
- // Decide it's a checkbox via showsStateBy and highlightsBy.
- if (([buttonCell showsStateBy] == NSCellState) &&
- ([buttonCell highlightsBy] == NSCellState)) {
- [GTMUILocalizerAndLayoutTweaker wrapButtonTitleForWidth:button];
- return [GTMUILocalizerAndLayoutTweaker sizeToFitView:view];
- }
- }
- return [GTMUILocalizerAndLayoutTweaker sizeToFitView:view];
-}
-
-CGFloat VerticallyReflowGroup(NSArray* views) {
- views = [views sortedArrayUsingFunction:CompareFrameY
- context:NULL];
- CGFloat localVerticalShift = 0;
- for (NSInteger index = [views count] - 1; index >= 0; --index) {
- NSView* view = [views objectAtIndex:index];
-
- NSSize delta = WrapOrSizeToFit(view);
- localVerticalShift += delta.height;
- if (localVerticalShift) {
- NSPoint origin = [view frame].origin;
- origin.y -= localVerticalShift;
- [view setFrameOrigin:origin];
- }
- }
- return localVerticalShift;
-}
-
-NSString* ReplaceNSStringPlaceholders(NSString* formatString,
- const string16& a,
- size_t* offset) {
- return base::SysUTF16ToNSString(
- ReplaceStringPlaceholders(base::SysNSStringToUTF16(formatString),
- a,
- offset));
-}
-
-} // namespace cocoa_l10n_util
diff --git a/chrome/browser/cocoa/location_bar/autocomplete_text_field.h b/chrome/browser/cocoa/location_bar/autocomplete_text_field.h
deleted file mode 100644
index 9123578..0000000
--- a/chrome/browser/cocoa/location_bar/autocomplete_text_field.h
+++ /dev/null
@@ -1,144 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_AUTOCOMPLETE_TEXT_FIELD_H_
-#define CHROME_BROWSER_COCOA_AUTOCOMPLETE_TEXT_FIELD_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/cocoa_protocols_mac.h"
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/styled_text_field.h"
-#import "chrome/browser/cocoa/url_drop_target.h"
-
-@class AutocompleteTextFieldCell;
-
-// AutocompleteTextField intercepts UI actions for forwarding to
-// AutocompleteEditViewMac (*), and provides a custom look. It works
-// together with AutocompleteTextFieldEditor (mostly for intercepting
-// user actions) and AutocompleteTextFieldCell (mostly for custom
-// drawing).
-//
-// For historical reasons, chrome/browser/autocomplete is the core
-// implementation of the Omnibox. Chrome code seems to vary between
-// autocomplete and Omnibox in describing this.
-//
-// (*) AutocompleteEditViewMac is a view in the MVC sense for the
-// Chrome internals, though it's really more of a mish-mash of model,
-// view, and controller.
-
-// Provides a hook so that we can call directly down to
-// AutocompleteEditViewMac rather than traversing the delegate chain.
-class AutocompleteTextFieldObserver {
- public:
- // Called before changing the selected range of the field.
- virtual NSRange SelectionRangeForProposedRange(NSRange proposed_range) = 0;
-
- // Called when the control-key state changes while the field is
- // first responder.
- virtual void OnControlKeyChanged(bool pressed) = 0;
-
- // Called when the user pastes into the field.
- virtual void OnPaste() = 0;
-
- // Return |true| if there is a selection to copy.
- virtual bool CanCopy() = 0;
-
- // Clears the |pboard| and adds the field's current selection.
- // Called when the user does a copy or drag.
- virtual void CopyToPasteboard(NSPasteboard* pboard) = 0;
-
- // Returns true if the current clipboard text supports paste and go
- // (or paste and search).
- virtual bool CanPasteAndGo() = 0;
-
- // Returns the appropriate "Paste and Go" or "Paste and Search"
- // context menu string, depending on what is currently in the
- // clipboard. Must not be called unless CanPasteAndGo() returns
- // true.
- virtual int GetPasteActionStringId() = 0;
-
- // Called when the user initiates a "paste and go" or "paste and
- // search" into the field.
- virtual void OnPasteAndGo() = 0;
-
- // Called when the field's frame changes.
- virtual void OnFrameChanged() = 0;
-
- // Called when the popup is no longer appropriate, such as when the
- // field's window loses focus or a page action is clicked.
- virtual void ClosePopup() = 0;
-
- // Called when the user begins editing the field, for every edit,
- // and when the user is done editing the field.
- virtual void OnDidBeginEditing() = 0;
- virtual void OnDidChange() = 0;
- virtual void OnDidEndEditing() = 0;
-
- // NSResponder translates certain keyboard actions into selectors
- // passed to -doCommandBySelector:. The selector is forwarded here,
- // return true if |cmd| is handled, false if the caller should
- // handle it.
- // TODO(shess): For now, I think having the code which makes these
- // decisions closer to the other autocomplete code is worthwhile,
- // since it calls a wide variety of methods which otherwise aren't
- // clearly relevent to expose here. But consider pulling more of
- // the AutocompleteEditViewMac calls up to here.
- virtual bool OnDoCommandBySelector(SEL cmd) = 0;
-
- // Called whenever the autocomplete text field gets focused.
- virtual void OnSetFocus(bool control_down) = 0;
-
- // Called whenever the autocomplete text field is losing focus.
- virtual void OnKillFocus() = 0;
-
- protected:
- virtual ~AutocompleteTextFieldObserver() {}
-};
-
-@interface AutocompleteTextField : StyledTextField<NSTextViewDelegate,
- URLDropTarget> {
- @private
- // Undo manager for this text field. We use a specific instance rather than
- // the standard undo manager in order to let us clear the undo stack at will.
- scoped_nsobject<NSUndoManager> undoManager_;
-
- AutocompleteTextFieldObserver* observer_; // weak, owned by location bar.
-
- // Handles being a drag-and-drop target.
- scoped_nsobject<URLDropTargetHandler> dropHandler_;
-
- // Holds current tooltip strings, to keep them from being dealloced.
- scoped_nsobject<NSMutableArray> currentToolTips_;
-}
-
-@property (nonatomic) AutocompleteTextFieldObserver* observer;
-
-// Convenience method to return the cell, casted appropriately.
-- (AutocompleteTextFieldCell*)cell;
-
-// Superclass aborts editing before changing the string, which causes
-// problems for undo. This version modifies the field editor's
-// contents if the control is already being edited.
-- (void)setAttributedStringValue:(NSAttributedString*)aString;
-
-// Clears the undo chain for this text field.
-- (void)clearUndoChain;
-
-// Updates cursor and tooltip rects depending on the contents of the text field
-// e.g. the security icon should have a default pointer shown on hover instead
-// of an I-beam.
-- (void)updateCursorAndToolTipRects;
-
-// Return the appropriate menu for any decoration under |event|.
-- (NSMenu*)decorationMenuForEvent:(NSEvent*)event;
-
-// Retains |tooltip| (in |currentToolTips_|) and adds this tooltip
-// via -[NSView addToolTipRect:owner:userData:].
-- (void)addToolTip:(NSString*)tooltip forRect:(NSRect)aRect;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_AUTOCOMPLETE_TEXT_FIELD_H_
diff --git a/chrome/browser/cocoa/location_bar/autocomplete_text_field.mm b/chrome/browser/cocoa/location_bar/autocomplete_text_field.mm
deleted file mode 100644
index f340b70..0000000
--- a/chrome/browser/cocoa/location_bar/autocomplete_text_field.mm
+++ /dev/null
@@ -1,385 +0,0 @@
-// 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 "chrome/browser/cocoa/location_bar/autocomplete_text_field.h"
-
-#include "base/logging.h"
-#import "chrome/browser/cocoa/browser_window_controller.h"
-#import "chrome/browser/cocoa/location_bar/autocomplete_text_field_cell.h"
-#import "chrome/browser/cocoa/location_bar/autocomplete_text_field_editor.h"
-#import "chrome/browser/cocoa/toolbar_controller.h"
-#import "chrome/browser/cocoa/url_drop_target.h"
-#import "chrome/browser/cocoa/view_id_util.h"
-
-@implementation AutocompleteTextField
-
-@synthesize observer = observer_;
-
-+ (Class)cellClass {
- return [AutocompleteTextFieldCell class];
-}
-
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [super dealloc];
-}
-
-- (void)awakeFromNib {
- DCHECK([[self cell] isKindOfClass:[AutocompleteTextFieldCell class]]);
- [[self cell] setTruncatesLastVisibleLine:YES];
- [[self cell] setLineBreakMode:NSLineBreakByTruncatingTail];
- currentToolTips_.reset([[NSMutableArray alloc] init]);
-}
-
-- (void)flagsChanged:(NSEvent*)theEvent {
- if (observer_) {
- const bool controlFlag = ([theEvent modifierFlags]&NSControlKeyMask) != 0;
- observer_->OnControlKeyChanged(controlFlag);
- }
-}
-
-- (AutocompleteTextFieldCell*)cell {
- NSCell* cell = [super cell];
- if (!cell)
- return nil;
-
- DCHECK([cell isKindOfClass:[AutocompleteTextFieldCell class]]);
- return static_cast<AutocompleteTextFieldCell*>(cell);
-}
-
-// Reroute events for the decoration area to the field editor. This
-// will cause the cursor to be moved as close to the edge where the
-// event was seen as possible.
-//
-// The reason for this code's existence is subtle. NSTextField
-// implements text selection and editing in terms of a "field editor".
-// This is an NSTextView which is installed as a subview of the
-// control when the field becomes first responder. When the field
-// editor is installed, it will get -mouseDown: events and handle
-// them, rather than the text field - EXCEPT for the event which
-// caused the change in first responder, or events which fall in the
-// decorations outside the field editor's area. In that case, the
-// default NSTextField code will setup the field editor all over
-// again, which has the side effect of doing "select all" on the text.
-// This effect can be observed with a normal NSTextField if you click
-// in the narrow border area, and is only really a problem because in
-// our case the focus ring surrounds decorations which look clickable.
-//
-// When the user first clicks on the field, after installing the field
-// editor the default NSTextField code detects if the hit is in the
-// field editor area, and if so sets the selection to {0,0} to clear
-// the selection before forwarding the event to the field editor for
-// processing (it will set the cursor position). This also starts the
-// click-drag selection machinery.
-//
-// This code does the same thing for cases where the click was in the
-// decoration area. This allows the user to click-drag starting from
-// a decoration area and get the expected selection behaviour,
-// likewise for multiple clicks in those areas.
-- (void)mouseDown:(NSEvent*)theEvent {
- // Close the popup before processing the event. This prevents the
- // popup from being visible while a right-click context menu or
- // page-action menu is visible. Also, it matches other platforms.
- if (observer_)
- observer_->ClosePopup();
-
- // If the click was a Control-click, bring up the context menu.
- // |NSTextField| handles these cases inconsistently if the field is
- // not already first responder.
- if (([theEvent modifierFlags] & NSControlKeyMask) != 0) {
- NSText* editor = [self currentEditor];
- NSMenu* menu = [editor menuForEvent:theEvent];
- [NSMenu popUpContextMenu:menu withEvent:theEvent forView:editor];
- return;
- }
-
- const NSPoint location =
- [self convertPoint:[theEvent locationInWindow] fromView:nil];
- const NSRect bounds([self bounds]);
-
- AutocompleteTextFieldCell* cell = [self cell];
- const NSRect textFrame([cell textFrameForFrame:bounds]);
-
- // A version of the textFrame which extends across the field's
- // entire width.
-
- const NSRect fullFrame(NSMakeRect(bounds.origin.x, textFrame.origin.y,
- bounds.size.width, textFrame.size.height));
-
- // If the mouse is in the editing area, or above or below where the
- // editing area would be if we didn't add decorations, forward to
- // NSTextField -mouseDown: because it does the right thing. The
- // above/below test is needed because NSTextView treats mouse events
- // above/below as select-to-end-in-that-direction, which makes
- // things janky.
- BOOL flipped = [self isFlipped];
- if (NSMouseInRect(location, textFrame, flipped) ||
- !NSMouseInRect(location, fullFrame, flipped)) {
- [super mouseDown:theEvent];
-
- // After the event has been handled, if the current event is a
- // mouse up and no selection was created (the mouse didn't move),
- // select the entire field.
- // NOTE(shess): This does not interfere with single-clicking to
- // place caret after a selection is made. An NSTextField only has
- // a selection when it has a field editor. The field editor is an
- // NSText subview, which will receive the -mouseDown: in that
- // case, and this code will never fire.
- NSText* editor = [self currentEditor];
- if (editor) {
- NSEvent* currentEvent = [NSApp currentEvent];
- if ([currentEvent type] == NSLeftMouseUp &&
- ![editor selectedRange].length) {
- [editor selectAll:nil];
- }
- }
-
- return;
- }
-
- // Give the cell a chance to intercept clicks in page-actions and
- // other decorative items.
- if ([cell mouseDown:theEvent inRect:bounds ofView:self]) {
- return;
- }
-
- NSText* editor = [self currentEditor];
-
- // We should only be here if we accepted first-responder status and
- // have a field editor. If one of these fires, it means some
- // assumptions are being broken.
- DCHECK(editor != nil);
- DCHECK([editor isDescendantOf:self]);
-
- // -becomeFirstResponder does a select-all, which we don't want
- // because it can lead to a dragged-text situation. Clear the
- // selection (any valid empty selection will do).
- [editor setSelectedRange:NSMakeRange(0, 0)];
-
- // If the event is to the right of the editing area, scroll the
- // field editor to the end of the content so that the selection
- // doesn't initiate from somewhere in the middle of the text.
- if (location.x > NSMaxX(textFrame)) {
- [editor scrollRangeToVisible:NSMakeRange([[self stringValue] length], 0)];
- }
-
- [editor mouseDown:theEvent];
-}
-
-// Overridden to pass OnFrameChanged() notifications to |observer_|.
-// Additionally, cursor and tooltip rects need to be updated.
-- (void)setFrame:(NSRect)frameRect {
- [super setFrame:frameRect];
- if (observer_) {
- observer_->OnFrameChanged();
- }
- [self updateCursorAndToolTipRects];
-}
-
-// Due to theming, parts of the field are transparent.
-- (BOOL)isOpaque {
- return NO;
-}
-
-- (void)setAttributedStringValue:(NSAttributedString*)aString {
- AutocompleteTextFieldEditor* editor =
- static_cast<AutocompleteTextFieldEditor*>([self currentEditor]);
-
- if (!editor) {
- [super setAttributedStringValue:aString];
- } else {
- // The type of the field editor must be AutocompleteTextFieldEditor,
- // otherwise things won't work.
- DCHECK([editor isKindOfClass:[AutocompleteTextFieldEditor class]]);
-
- [editor setAttributedString:aString];
- }
-}
-
-- (NSUndoManager*)undoManagerForTextView:(NSTextView*)textView {
- if (!undoManager_.get())
- undoManager_.reset([[NSUndoManager alloc] init]);
- return undoManager_.get();
-}
-
-- (void)clearUndoChain {
- [undoManager_ removeAllActions];
-}
-
-- (NSRange)textView:(NSTextView *)aTextView
- willChangeSelectionFromCharacterRange:(NSRange)oldRange
- toCharacterRange:(NSRange)newRange {
- if (observer_)
- return observer_->SelectionRangeForProposedRange(newRange);
- return newRange;
-}
-
-- (void)addToolTip:(NSString*)tooltip forRect:(NSRect)aRect {
- [currentToolTips_ addObject:tooltip];
- [self addToolTipRect:aRect owner:tooltip userData:nil];
-}
-
-// TODO(shess): -resetFieldEditorFrameIfNeeded is the place where
-// changes to the cell layout should be flushed. LocationBarViewMac
-// and ToolbarController are calling this routine directly, and I
-// think they are probably wrong.
-// http://crbug.com/40053
-- (void)updateCursorAndToolTipRects {
- // This will force |resetCursorRects| to be called, as it is not to be called
- // directly.
- [[self window] invalidateCursorRectsForView:self];
-
- // |removeAllToolTips| only removes those set on the current NSView, not any
- // subviews. Unless more tooltips are added to this view, this should suffice
- // in place of managing a set of NSToolTipTag objects.
- [self removeAllToolTips];
-
- // Reload the decoration tooltips.
- [currentToolTips_ removeAllObjects];
- [[self cell] updateToolTipsInRect:[self bounds] ofView:self];
-}
-
-// NOTE(shess): http://crbug.com/19116 describes a weird bug which
-// happens when the user runs a Print panel on Leopard. After that,
-// spurious -controlTextDidBeginEditing notifications are sent when an
-// NSTextField is firstResponder, even though -currentEditor on that
-// field returns nil. That notification caused significant problems
-// in AutocompleteEditViewMac. -textDidBeginEditing: was NOT being
-// sent in those cases, so this approach doesn't have the problem.
-- (void)textDidBeginEditing:(NSNotification*)aNotification {
- [super textDidBeginEditing:aNotification];
- if (observer_) {
- observer_->OnDidBeginEditing();
- }
-}
-
-- (void)textDidEndEditing:(NSNotification *)aNotification {
- [super textDidEndEditing:aNotification];
- if (observer_) {
- observer_->OnDidEndEditing();
- }
-}
-
-// When the window resigns, make sure the autocomplete popup is no
-// longer visible, since the user's focus is elsewhere.
-- (void)windowDidResignKey:(NSNotification*)notification {
- DCHECK_EQ([self window], [notification object]);
- if (observer_)
- observer_->ClosePopup();
-}
-
-- (void)viewWillMoveToWindow:(NSWindow*)newWindow {
- if ([self window]) {
- NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
- [nc removeObserver:self
- name:NSWindowDidResignKeyNotification
- object:[self window]];
- }
-}
-
-- (void)viewDidMoveToWindow {
- if ([self window]) {
- NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
- [nc addObserver:self
- selector:@selector(windowDidResignKey:)
- name:NSWindowDidResignKeyNotification
- object:[self window]];
- // Only register for drops if not in a popup window. Lazily create the
- // drop handler when the type of window is known.
- BrowserWindowController* windowController =
- [BrowserWindowController browserWindowControllerForView:self];
- if ([windowController isNormalWindow])
- dropHandler_.reset([[URLDropTargetHandler alloc] initWithView:self]);
- }
-}
-
-// NSTextField becomes first responder by installing a "field editor"
-// subview. Clicks outside the field editor (such as a decoration)
-// will attempt to make the field the first-responder again, which
-// causes a select-all, even if the decoration handles the click. If
-// the field editor is already in place, don't accept first responder
-// again. This allows the selection to be unmodified if the click is
-// handled by a decoration or context menu (|-mouseDown:| will still
-// change it if appropriate).
-- (BOOL)acceptsFirstResponder {
- if ([self currentEditor]) {
- DCHECK_EQ([self currentEditor], [[self window] firstResponder]);
- return NO;
- }
- return [super acceptsFirstResponder];
-}
-
-// (Overridden from NSResponder)
-- (BOOL)becomeFirstResponder {
- BOOL doAccept = [super becomeFirstResponder];
- if (doAccept) {
- [[BrowserWindowController browserWindowControllerForView:self]
- lockBarVisibilityForOwner:self withAnimation:YES delay:NO];
-
- // Tells the observer that we get the focus.
- // But we can't call observer_->OnKillFocus() in resignFirstResponder:,
- // because the first responder will be immediately set to the field editor
- // when calling [super becomeFirstResponder], thus we won't receive
- // resignFirstResponder: anymore when losing focus.
- if (observer_) {
- NSEvent* theEvent = [NSApp currentEvent];
- const bool controlDown = ([theEvent modifierFlags]&NSControlKeyMask) != 0;
- observer_->OnSetFocus(controlDown);
- }
- }
- return doAccept;
-}
-
-// (Overridden from NSResponder)
-- (BOOL)resignFirstResponder {
- BOOL doResign = [super resignFirstResponder];
- if (doResign) {
- [[BrowserWindowController browserWindowControllerForView:self]
- releaseBarVisibilityForOwner:self withAnimation:YES delay:YES];
- }
- return doResign;
-}
-
-// (URLDropTarget protocol)
-- (id<URLDropTargetController>)urlDropController {
- BrowserWindowController* windowController =
- [BrowserWindowController browserWindowControllerForView:self];
- return [windowController toolbarController];
-}
-
-// (URLDropTarget protocol)
-- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
- // Make ourself the first responder, which will select the text to indicate
- // that our contents would be replaced by a drop.
- // TODO(viettrungluu): crbug.com/30809 -- this is a hack since it steals focus
- // and doesn't return it.
- [[self window] makeFirstResponder:self];
- return [dropHandler_ draggingEntered:sender];
-}
-
-// (URLDropTarget protocol)
-- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender {
- return [dropHandler_ draggingUpdated:sender];
-}
-
-// (URLDropTarget protocol)
-- (void)draggingExited:(id<NSDraggingInfo>)sender {
- return [dropHandler_ draggingExited:sender];
-}
-
-// (URLDropTarget protocol)
-- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
- return [dropHandler_ performDragOperation:sender];
-}
-
-- (NSMenu*)decorationMenuForEvent:(NSEvent*)event {
- AutocompleteTextFieldCell* cell = [self cell];
- return [cell decorationMenuForEvent:event inRect:[self bounds] ofView:self];
-}
-
-- (ViewID)viewID {
- return VIEW_ID_LOCATION_BAR;
-}
-
-@end
diff --git a/chrome/browser/cocoa/location_bar/autocomplete_text_field_cell.h b/chrome/browser/cocoa/location_bar/autocomplete_text_field_cell.h
deleted file mode 100644
index b003af1..0000000
--- a/chrome/browser/cocoa/location_bar/autocomplete_text_field_cell.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// 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.
-
-#include <vector>
-
-#import <Cocoa/Cocoa.h>
-
-#import "chrome/browser/cocoa/styled_text_field_cell.h"
-
-@class AutocompleteTextField;
-class LocationBarDecoration;
-
-// AutocompleteTextFieldCell extends StyledTextFieldCell to provide support for
-// certain decorations to be applied to the field. These are the search hint
-// ("Type to search" on the right-hand side), the keyword hint ("Press [Tab] to
-// search Engine" on the right-hand side), and keyword mode ("Search Engine:" in
-// a button-like token on the left-hand side).
-@interface AutocompleteTextFieldCell : StyledTextFieldCell {
- @private
- // Decorations which live to the left and right of the text, ordered
- // from outside in. Decorations are owned by |LocationBarViewMac|.
- std::vector<LocationBarDecoration*> leftDecorations_;
- std::vector<LocationBarDecoration*> rightDecorations_;
-}
-
-// Clear |leftDecorations_| and |rightDecorations_|.
-- (void)clearDecorations;
-
-// Add a new left-side decoration to the right of the existing
-// left-side decorations.
-- (void)addLeftDecoration:(LocationBarDecoration*)decoration;
-
-// Add a new right-side decoration to the left of the existing
-// right-side decorations.
-- (void)addRightDecoration:(LocationBarDecoration*)decoration;
-
-// The width available after accounting for decorations.
-- (CGFloat)availableWidthInFrame:(const NSRect)frame;
-
-// Return the frame for |aDecoration| if the cell is in |cellFrame|.
-// Returns |NSZeroRect| for decorations which are not currently
-// visible.
-- (NSRect)frameForDecoration:(const LocationBarDecoration*)aDecoration
- inFrame:(NSRect)cellFrame;
-
-// Find the decoration under the event. |NULL| if |theEvent| is not
-// over anything.
-- (LocationBarDecoration*)decorationForEvent:(NSEvent*)theEvent
- inRect:(NSRect)cellFrame
- ofView:(AutocompleteTextField*)field;
-
-// Return the appropriate menu for any decorations under event.
-// Returns nil if no menu is present for the decoration, or if the
-// event is not over a decoration.
-- (NSMenu*)decorationMenuForEvent:(NSEvent*)theEvent
- inRect:(NSRect)cellFrame
- ofView:(AutocompleteTextField*)controlView;
-
-// Called by |AutocompleteTextField| to let page actions intercept
-// clicks. Returns |YES| if the click has been intercepted.
-- (BOOL)mouseDown:(NSEvent*)theEvent
- inRect:(NSRect)cellFrame
- ofView:(AutocompleteTextField*)controlView;
-
-// Overridden from StyledTextFieldCell to include decorations adjacent
-// to the text area which don't handle mouse clicks themselves.
-// Keyword-search bubble, for instance.
-- (NSRect)textCursorFrameForFrame:(NSRect)cellFrame;
-
-// Setup decoration tooltips on |controlView| by calling
-// |-addToolTip:forRect:|.
-- (void)updateToolTipsInRect:(NSRect)cellFrame
- ofView:(AutocompleteTextField*)controlView;
-
-@end
diff --git a/chrome/browser/cocoa/location_bar/autocomplete_text_field_cell.mm b/chrome/browser/cocoa/location_bar/autocomplete_text_field_cell.mm
deleted file mode 100644
index 5d1742b..0000000
--- a/chrome/browser/cocoa/location_bar/autocomplete_text_field_cell.mm
+++ /dev/null
@@ -1,402 +0,0 @@
-// 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 "chrome/browser/cocoa/location_bar/autocomplete_text_field_cell.h"
-
-#include "base/logging.h"
-#import "chrome/browser/cocoa/image_utils.h"
-#import "chrome/browser/cocoa/location_bar/autocomplete_text_field.h"
-#import "chrome/browser/cocoa/location_bar/location_bar_decoration.h"
-
-namespace {
-
-const CGFloat kBaselineAdjust = 3.0;
-
-// Matches the clipping radius of |GradientButtonCell|.
-const CGFloat kCornerRadius = 4.0;
-
-// How far to inset the left-hand decorations from the field's bounds.
-const CGFloat kLeftDecorationXOffset = 5.0;
-
-// How far to inset the right-hand decorations from the field's bounds.
-// TODO(shess): Why is this different from |kLeftDecorationXOffset|?
-// |kDecorationOuterXOffset|?
-const CGFloat kRightDecorationXOffset = 5.0;
-
-// The amount of padding on either side reserved for drawing
-// decorations. [Views has |kItemPadding| == 3.]
-const CGFloat kDecorationHorizontalPad = 3.0;
-
-// How long to wait for mouse-up on the location icon before assuming
-// that the user wants to drag.
-const NSTimeInterval kLocationIconDragTimeout = 0.25;
-
-// Calculate the positions for a set of decorations. |frame| is the
-// overall frame to do layout in, |remaining_frame| will get the
-// left-over space. |all_decorations| is the set of decorations to
-// lay out, |decorations| will be set to the decorations which are
-// visible and which fit, in the same order as |all_decorations|,
-// while |decoration_frames| will be the corresponding frames.
-// |x_edge| describes the edge to layout the decorations against
-// (|NSMinXEdge| or |NSMaxXEdge|). |initial_padding| is the padding
-// from the edge of |cell_frame| (|kDecorationHorizontalPad| is used
-// between decorations).
-void CalculatePositionsHelper(
- NSRect frame,
- const std::vector<LocationBarDecoration*>& all_decorations,
- NSRectEdge x_edge,
- CGFloat initial_padding,
- std::vector<LocationBarDecoration*>* decorations,
- std::vector<NSRect>* decoration_frames,
- NSRect* remaining_frame) {
- DCHECK(x_edge == NSMinXEdge || x_edge == NSMaxXEdge);
- DCHECK_EQ(decorations->size(), decoration_frames->size());
-
- // The outer-most decoration will be inset a bit further from the
- // edge.
- CGFloat padding = initial_padding;
-
- for (size_t i = 0; i < all_decorations.size(); ++i) {
- if (all_decorations[i]->IsVisible()) {
- NSRect padding_rect, available;
-
- // Peel off the outside padding.
- NSDivideRect(frame, &padding_rect, &available, padding, x_edge);
-
- // Find out how large the decoration will be in the remaining
- // space.
- const CGFloat used_width =
- all_decorations[i]->GetWidthForSpace(NSWidth(available));
-
- if (used_width != LocationBarDecoration::kOmittedWidth) {
- DCHECK_GT(used_width, 0.0);
- NSRect decoration_frame;
-
- // Peel off the desired width, leaving the remainder in
- // |frame|.
- NSDivideRect(available, &decoration_frame, &frame,
- used_width, x_edge);
-
- decorations->push_back(all_decorations[i]);
- decoration_frames->push_back(decoration_frame);
- DCHECK_EQ(decorations->size(), decoration_frames->size());
-
- // Adjust padding for between decorations.
- padding = kDecorationHorizontalPad;
- }
- }
- }
-
- DCHECK_EQ(decorations->size(), decoration_frames->size());
- *remaining_frame = frame;
-}
-
-// Helper function for calculating placement of decorations w/in the
-// cell. |frame| is the cell's boundary rectangle, |remaining_frame|
-// will get any space left after decorations are laid out (for text).
-// |left_decorations| is a set of decorations for the left-hand side
-// of the cell, |right_decorations| for the right-hand side.
-// |decorations| will contain the resulting visible decorations, and
-// |decoration_frames| will contain their frames in the same
-// coordinates as |frame|. Decorations will be ordered left to right.
-// As a convenience returns the index of the first right-hand
-// decoration.
-size_t CalculatePositionsInFrame(
- NSRect frame,
- const std::vector<LocationBarDecoration*>& left_decorations,
- const std::vector<LocationBarDecoration*>& right_decorations,
- std::vector<LocationBarDecoration*>* decorations,
- std::vector<NSRect>* decoration_frames,
- NSRect* remaining_frame) {
- decorations->clear();
- decoration_frames->clear();
-
- // Layout |left_decorations| against the LHS.
- CalculatePositionsHelper(frame, left_decorations,
- NSMinXEdge, kLeftDecorationXOffset,
- decorations, decoration_frames, &frame);
- DCHECK_EQ(decorations->size(), decoration_frames->size());
-
- // Capture the number of visible left-hand decorations.
- const size_t left_count = decorations->size();
-
- // Layout |right_decorations| against the RHS.
- CalculatePositionsHelper(frame, right_decorations,
- NSMaxXEdge, kRightDecorationXOffset,
- decorations, decoration_frames, &frame);
- DCHECK_EQ(decorations->size(), decoration_frames->size());
-
- // Reverse the right-hand decorations so that overall everything is
- // sorted left to right.
- std::reverse(decorations->begin() + left_count, decorations->end());
- std::reverse(decoration_frames->begin() + left_count,
- decoration_frames->end());
-
- *remaining_frame = frame;
- return left_count;
-}
-
-} // namespace
-
-@implementation AutocompleteTextFieldCell
-
-- (CGFloat)baselineAdjust {
- return kBaselineAdjust;
-}
-
-- (CGFloat)cornerRadius {
- return kCornerRadius;
-}
-
-- (BOOL)shouldDrawBezel {
- return YES;
-}
-
-- (void)clearDecorations {
- leftDecorations_.clear();
- rightDecorations_.clear();
-}
-
-- (void)addLeftDecoration:(LocationBarDecoration*)decoration {
- leftDecorations_.push_back(decoration);
-}
-
-- (void)addRightDecoration:(LocationBarDecoration*)decoration {
- rightDecorations_.push_back(decoration);
-}
-
-- (CGFloat)availableWidthInFrame:(const NSRect)frame {
- std::vector<LocationBarDecoration*> decorations;
- std::vector<NSRect> decorationFrames;
- NSRect textFrame;
- CalculatePositionsInFrame(frame, leftDecorations_, rightDecorations_,
- &decorations, &decorationFrames, &textFrame);
-
- return NSWidth(textFrame);
-}
-
-- (NSRect)frameForDecoration:(const LocationBarDecoration*)aDecoration
- inFrame:(NSRect)cellFrame {
- // Short-circuit if the decoration is known to be not visible.
- if (aDecoration && !aDecoration->IsVisible())
- return NSZeroRect;
-
- // Layout the decorations.
- std::vector<LocationBarDecoration*> decorations;
- std::vector<NSRect> decorationFrames;
- NSRect textFrame;
- CalculatePositionsInFrame(cellFrame, leftDecorations_, rightDecorations_,
- &decorations, &decorationFrames, &textFrame);
-
- // Find our decoration and return the corresponding frame.
- std::vector<LocationBarDecoration*>::const_iterator iter =
- std::find(decorations.begin(), decorations.end(), aDecoration);
- if (iter != decorations.end()) {
- const size_t index = iter - decorations.begin();
- return decorationFrames[index];
- }
-
- // Decorations which are not visible should have been filtered out
- // at the top, but return |NSZeroRect| rather than a 0-width rect
- // for consistency.
- NOTREACHED();
- return NSZeroRect;
-}
-
-// Overriden to account for the decorations.
-- (NSRect)textFrameForFrame:(NSRect)cellFrame {
- // Get the frame adjusted for decorations.
- std::vector<LocationBarDecoration*> decorations;
- std::vector<NSRect> decorationFrames;
- NSRect textFrame = [super textFrameForFrame:cellFrame];
- CalculatePositionsInFrame(textFrame, leftDecorations_, rightDecorations_,
- &decorations, &decorationFrames, &textFrame);
-
- // NOTE: This function must closely match the logic in
- // |-drawInteriorWithFrame:inView:|.
-
- return textFrame;
-}
-
-- (NSRect)textCursorFrameForFrame:(NSRect)cellFrame {
- std::vector<LocationBarDecoration*> decorations;
- std::vector<NSRect> decorationFrames;
- NSRect textFrame;
- size_t left_count =
- CalculatePositionsInFrame(cellFrame, leftDecorations_, rightDecorations_,
- &decorations, &decorationFrames, &textFrame);
-
- // Determine the left-most extent for the i-beam cursor.
- CGFloat minX = NSMinX(textFrame);
- for (size_t index = left_count; index--; ) {
- if (decorations[index]->AcceptsMousePress())
- break;
-
- // If at leftmost decoration, expand to edge of cell.
- if (!index) {
- minX = NSMinX(cellFrame);
- } else {
- minX = NSMinX(decorationFrames[index]) - kDecorationHorizontalPad;
- }
- }
-
- // Determine the right-most extent for the i-beam cursor.
- CGFloat maxX = NSMaxX(textFrame);
- for (size_t index = left_count; index < decorations.size(); ++index) {
- if (decorations[index]->AcceptsMousePress())
- break;
-
- // If at rightmost decoration, expand to edge of cell.
- if (index == decorations.size() - 1) {
- maxX = NSMaxX(cellFrame);
- } else {
- maxX = NSMaxX(decorationFrames[index]) + kDecorationHorizontalPad;
- }
- }
-
- // I-beam cursor covers left-most to right-most.
- return NSMakeRect(minX, NSMinY(textFrame), maxX - minX, NSHeight(textFrame));
-}
-
-- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
- std::vector<LocationBarDecoration*> decorations;
- std::vector<NSRect> decorationFrames;
- NSRect workingFrame;
- CalculatePositionsInFrame(cellFrame, leftDecorations_, rightDecorations_,
- &decorations, &decorationFrames, &workingFrame);
-
- // Draw the decorations.
- for (size_t i = 0; i < decorations.size(); ++i) {
- if (decorations[i])
- decorations[i]->DrawInFrame(decorationFrames[i], controlView);
- }
-
- // NOTE: This function must closely match the logic in
- // |-textFrameForFrame:|.
-
- // Superclass draws text portion WRT original |cellFrame|.
- [super drawInteriorWithFrame:cellFrame inView:controlView];
-}
-
-- (LocationBarDecoration*)decorationForEvent:(NSEvent*)theEvent
- inRect:(NSRect)cellFrame
- ofView:(AutocompleteTextField*)controlView
-{
- const BOOL flipped = [controlView isFlipped];
- const NSPoint location =
- [controlView convertPoint:[theEvent locationInWindow] fromView:nil];
-
- std::vector<LocationBarDecoration*> decorations;
- std::vector<NSRect> decorationFrames;
- NSRect textFrame;
- CalculatePositionsInFrame(cellFrame, leftDecorations_, rightDecorations_,
- &decorations, &decorationFrames, &textFrame);
-
- for (size_t i = 0; i < decorations.size(); ++i) {
- if (NSMouseInRect(location, decorationFrames[i], flipped))
- return decorations[i];
- }
-
- return NULL;
-}
-
-- (NSMenu*)decorationMenuForEvent:(NSEvent*)theEvent
- inRect:(NSRect)cellFrame
- ofView:(AutocompleteTextField*)controlView {
- LocationBarDecoration* decoration =
- [self decorationForEvent:theEvent inRect:cellFrame ofView:controlView];
- if (decoration)
- return decoration->GetMenu();
- return nil;
-}
-
-- (BOOL)mouseDown:(NSEvent*)theEvent
- inRect:(NSRect)cellFrame
- ofView:(AutocompleteTextField*)controlView {
- LocationBarDecoration* decoration =
- [self decorationForEvent:theEvent inRect:cellFrame ofView:controlView];
- if (!decoration || !decoration->AcceptsMousePress())
- return NO;
-
- NSRect decorationRect =
- [self frameForDecoration:decoration inFrame:cellFrame];
-
- // If the decoration is draggable, then initiate a drag if the user
- // drags or holds the mouse down for awhile.
- if (decoration->IsDraggable()) {
- NSDate* timeout =
- [NSDate dateWithTimeIntervalSinceNow:kLocationIconDragTimeout];
- NSEvent* event = [NSApp nextEventMatchingMask:(NSLeftMouseDraggedMask |
- NSLeftMouseUpMask)
- untilDate:timeout
- inMode:NSEventTrackingRunLoopMode
- dequeue:YES];
- if (!event || [event type] == NSLeftMouseDragged) {
- NSPasteboard* pboard = decoration->GetDragPasteboard();
- DCHECK(pboard);
-
- NSImage* image = decoration->GetDragImage();
- DCHECK(image);
-
- NSRect dragImageRect = decoration->GetDragImageFrame(decorationRect);
-
- // If the original click is not within |dragImageRect|, then
- // center the image under the mouse. Otherwise, will drag from
- // where the click was on the image.
- const NSPoint mousePoint =
- [controlView convertPoint:[theEvent locationInWindow] fromView:nil];
- if (!NSMouseInRect(mousePoint, dragImageRect, [controlView isFlipped])) {
- dragImageRect.origin =
- NSMakePoint(mousePoint.x - NSWidth(dragImageRect) / 2.0,
- mousePoint.y - NSHeight(dragImageRect) / 2.0);
- }
-
- // -[NSView dragImage:at:*] wants the images lower-left point,
- // regardless of -isFlipped. Converting the rect to window base
- // coordinates doesn't require any special-casing. Note that
- // -[NSView dragFile:fromRect:*] takes a rect rather than a
- // point, likely for this exact reason.
- const NSPoint dragPoint =
- [controlView convertRect:dragImageRect toView:nil].origin;
- [[controlView window] dragImage:image
- at:dragPoint
- offset:NSZeroSize
- event:theEvent
- pasteboard:pboard
- source:self
- slideBack:YES];
-
- return YES;
- }
-
- // On mouse-up fall through to mouse-pressed case.
- DCHECK_EQ([event type], NSLeftMouseUp);
- }
-
- if (!decoration->OnMousePressed(decorationRect))
- return NO;
-
- return YES;
-}
-
-- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal {
- return NSDragOperationCopy;
-}
-
-- (void)updateToolTipsInRect:(NSRect)cellFrame
- ofView:(AutocompleteTextField*)controlView {
- std::vector<LocationBarDecoration*> decorations;
- std::vector<NSRect> decorationFrames;
- NSRect textFrame;
- CalculatePositionsInFrame(cellFrame, leftDecorations_, rightDecorations_,
- &decorations, &decorationFrames, &textFrame);
-
- for (size_t i = 0; i < decorations.size(); ++i) {
- NSString* tooltip = decorations[i]->GetToolTip();
- if ([tooltip length] > 0)
- [controlView addToolTip:tooltip forRect:decorationFrames[i]];
- }
-}
-
-@end
diff --git a/chrome/browser/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm b/chrome/browser/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm
deleted file mode 100644
index 19ff05b..0000000
--- a/chrome/browser/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm
+++ /dev/null
@@ -1,300 +0,0 @@
-// 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 "app/resource_bundle.h"
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/location_bar/autocomplete_text_field.h"
-#import "chrome/browser/cocoa/location_bar/autocomplete_text_field_cell.h"
-#import "chrome/browser/cocoa/location_bar/ev_bubble_decoration.h"
-#import "chrome/browser/cocoa/location_bar/keyword_hint_decoration.h"
-#import "chrome/browser/cocoa/location_bar/location_bar_decoration.h"
-#import "chrome/browser/cocoa/location_bar/location_icon_decoration.h"
-#import "chrome/browser/cocoa/location_bar/selected_keyword_decoration.h"
-#import "chrome/browser/cocoa/location_bar/star_decoration.h"
-#include "grit/theme_resources.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-#import "third_party/ocmock/OCMock/OCMock.h"
-
-using ::testing::Return;
-using ::testing::StrictMock;
-using ::testing::_;
-
-namespace {
-
-// Width of the field so that we don't have to ask |field_| for it all
-// the time.
-const CGFloat kWidth(300.0);
-
-// A narrow width for tests which test things that don't fit.
-const CGFloat kNarrowWidth(5.0);
-
-class MockDecoration : public LocationBarDecoration {
- public:
- virtual CGFloat GetWidthForSpace(CGFloat width) { return 20.0; }
-
- MOCK_METHOD2(DrawInFrame, void(NSRect frame, NSView* control_view));
- MOCK_METHOD0(GetToolTip, NSString*());
-};
-
-class AutocompleteTextFieldCellTest : public CocoaTest {
- public:
- AutocompleteTextFieldCellTest() {
- // Make sure this is wide enough to play games with the cell
- // decorations.
- const NSRect frame = NSMakeRect(0, 0, kWidth, 30);
-
- scoped_nsobject<NSTextField> view(
- [[NSTextField alloc] initWithFrame:frame]);
- view_ = view.get();
-
- scoped_nsobject<AutocompleteTextFieldCell> cell(
- [[AutocompleteTextFieldCell alloc] initTextCell:@"Testing"]);
- [cell setEditable:YES];
- [cell setBordered:YES];
-
- [cell clearDecorations];
- mock_left_decoration_.SetVisible(false);
- [cell addLeftDecoration:&mock_left_decoration_];
- mock_right_decoration0_.SetVisible(false);
- mock_right_decoration1_.SetVisible(false);
- [cell addRightDecoration:&mock_right_decoration0_];
- [cell addRightDecoration:&mock_right_decoration1_];
-
- [view_ setCell:cell.get()];
-
- [[test_window() contentView] addSubview:view_];
- }
-
- NSTextField* view_;
- MockDecoration mock_left_decoration_;
- MockDecoration mock_right_decoration0_;
- MockDecoration mock_right_decoration1_;
-};
-
-// Basic view tests (AddRemove, Display).
-TEST_VIEW(AutocompleteTextFieldCellTest, view_);
-
-// Test drawing, mostly to ensure nothing leaks or crashes.
-// Flaky, disabled. Bug http://crbug.com/49522
-TEST_F(AutocompleteTextFieldCellTest, DISABLED_FocusedDisplay) {
- [view_ display];
-
- // Test focused drawing.
- [test_window() makePretendKeyWindowAndSetFirstResponder:view_];
- [view_ display];
- [test_window() clearPretendKeyWindowAndFirstResponder];
-
- // Test display of various cell configurations.
- AutocompleteTextFieldCell* cell =
- static_cast<AutocompleteTextFieldCell*>([view_ cell]);
-
- // Load available decorations and try drawing. To make sure that
- // they are actually drawn, check that |GetWidthForSpace()| doesn't
- // indicate that they should be omitted.
- const CGFloat kVeryWide = 1000.0;
-
- SelectedKeywordDecoration selected_keyword_decoration([view_ font]);
- selected_keyword_decoration.SetVisible(true);
- selected_keyword_decoration.SetKeyword(std::wstring(L"Google"), false);
- [cell addLeftDecoration:&selected_keyword_decoration];
- EXPECT_NE(selected_keyword_decoration.GetWidthForSpace(kVeryWide),
- LocationBarDecoration::kOmittedWidth);
-
- // TODO(shess): This really wants a |LocationBarViewMac|, but only a
- // few methods reference it, so this works well enough. But
- // something better would be nice.
- LocationIconDecoration location_icon_decoration(NULL);
- location_icon_decoration.SetVisible(true);
- location_icon_decoration.SetImage([NSImage imageNamed:@"NSApplicationIcon"]);
- [cell addLeftDecoration:&location_icon_decoration];
- EXPECT_NE(location_icon_decoration.GetWidthForSpace(kVeryWide),
- LocationBarDecoration::kOmittedWidth);
-
- EVBubbleDecoration ev_bubble_decoration(&location_icon_decoration,
- [view_ font]);
- ev_bubble_decoration.SetVisible(true);
- ev_bubble_decoration.SetImage([NSImage imageNamed:@"NSApplicationIcon"]);
- ev_bubble_decoration.SetLabel(@"Application");
- [cell addLeftDecoration:&ev_bubble_decoration];
- EXPECT_NE(ev_bubble_decoration.GetWidthForSpace(kVeryWide),
- LocationBarDecoration::kOmittedWidth);
-
- StarDecoration star_decoration(NULL);
- star_decoration.SetVisible(true);
- [cell addRightDecoration:&star_decoration];
- EXPECT_NE(star_decoration.GetWidthForSpace(kVeryWide),
- LocationBarDecoration::kOmittedWidth);
-
- KeywordHintDecoration keyword_hint_decoration([view_ font]);
- keyword_hint_decoration.SetVisible(true);
- keyword_hint_decoration.SetKeyword(std::wstring(L"google"), false);
- [cell addRightDecoration:&keyword_hint_decoration];
- EXPECT_NE(keyword_hint_decoration.GetWidthForSpace(kVeryWide),
- LocationBarDecoration::kOmittedWidth);
-
- // Make sure we're actually calling |DrawInFrame()|.
- StrictMock<MockDecoration> mock_decoration;
- mock_decoration.SetVisible(true);
- [cell addLeftDecoration:&mock_decoration];
- EXPECT_CALL(mock_decoration, DrawInFrame(_, _));
- EXPECT_NE(mock_decoration.GetWidthForSpace(kVeryWide),
- LocationBarDecoration::kOmittedWidth);
-
- [view_ display];
-
- [cell clearDecorations];
-}
-
-TEST_F(AutocompleteTextFieldCellTest, TextFrame) {
- AutocompleteTextFieldCell* cell =
- static_cast<AutocompleteTextFieldCell*>([view_ cell]);
- const NSRect bounds([view_ bounds]);
- NSRect textFrame;
-
- // The cursor frame should stay the same throughout.
- const NSRect cursorFrame([cell textCursorFrameForFrame:bounds]);
- EXPECT_TRUE(NSEqualRects(cursorFrame, bounds));
-
- // At default settings, everything goes to the text area.
- textFrame = [cell textFrameForFrame:bounds];
- EXPECT_FALSE(NSIsEmptyRect(textFrame));
- EXPECT_TRUE(NSContainsRect(bounds, textFrame));
- EXPECT_EQ(NSMinX(bounds), NSMinX(textFrame));
- EXPECT_EQ(NSMaxX(bounds), NSMaxX(textFrame));
- EXPECT_TRUE(NSContainsRect(cursorFrame, textFrame));
-
- // Decoration on the left takes up space.
- mock_left_decoration_.SetVisible(true);
- textFrame = [cell textFrameForFrame:bounds];
- EXPECT_FALSE(NSIsEmptyRect(textFrame));
- EXPECT_TRUE(NSContainsRect(bounds, textFrame));
- EXPECT_GT(NSMinX(textFrame), NSMinX(bounds));
- EXPECT_TRUE(NSContainsRect(cursorFrame, textFrame));
-}
-
-// The editor frame should be slightly inset from the text frame.
-TEST_F(AutocompleteTextFieldCellTest, DrawingRectForBounds) {
- AutocompleteTextFieldCell* cell =
- static_cast<AutocompleteTextFieldCell*>([view_ cell]);
- const NSRect bounds([view_ bounds]);
- NSRect textFrame, drawingRect;
-
- textFrame = [cell textFrameForFrame:bounds];
- drawingRect = [cell drawingRectForBounds:bounds];
- EXPECT_FALSE(NSIsEmptyRect(drawingRect));
- EXPECT_TRUE(NSContainsRect(textFrame, NSInsetRect(drawingRect, 1, 1)));
-
- // Save the starting frame for after clear.
- const NSRect originalDrawingRect = drawingRect;
-
- mock_left_decoration_.SetVisible(true);
- textFrame = [cell textFrameForFrame:bounds];
- drawingRect = [cell drawingRectForBounds:bounds];
- EXPECT_FALSE(NSIsEmptyRect(drawingRect));
- EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect));
-
- mock_right_decoration0_.SetVisible(true);
- textFrame = [cell textFrameForFrame:bounds];
- drawingRect = [cell drawingRectForBounds:bounds];
- EXPECT_FALSE(NSIsEmptyRect(drawingRect));
- EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect));
-
- mock_left_decoration_.SetVisible(false);
- mock_right_decoration0_.SetVisible(false);
- drawingRect = [cell drawingRectForBounds:bounds];
- EXPECT_FALSE(NSIsEmptyRect(drawingRect));
- EXPECT_TRUE(NSEqualRects(drawingRect, originalDrawingRect));
-}
-
-// Test that left decorations are at the correct edge of the cell.
-TEST_F(AutocompleteTextFieldCellTest, LeftDecorationFrame) {
- AutocompleteTextFieldCell* cell =
- static_cast<AutocompleteTextFieldCell*>([view_ cell]);
- const NSRect bounds = [view_ bounds];
-
- mock_left_decoration_.SetVisible(true);
- const NSRect decorationRect =
- [cell frameForDecoration:&mock_left_decoration_ inFrame:bounds];
- EXPECT_FALSE(NSIsEmptyRect(decorationRect));
- EXPECT_TRUE(NSContainsRect(bounds, decorationRect));
-
- // Decoration should be left of |drawingRect|.
- const NSRect drawingRect = [cell drawingRectForBounds:bounds];
- EXPECT_GT(NSMinX(drawingRect), NSMinX(decorationRect));
-
- // Decoration should be left of |textFrame|.
- const NSRect textFrame = [cell textFrameForFrame:bounds];
- EXPECT_GT(NSMinX(textFrame), NSMinX(decorationRect));
-}
-
-// Test that right decorations are at the correct edge of the cell.
-TEST_F(AutocompleteTextFieldCellTest, RightDecorationFrame) {
- AutocompleteTextFieldCell* cell =
- static_cast<AutocompleteTextFieldCell*>([view_ cell]);
- const NSRect bounds = [view_ bounds];
-
- mock_right_decoration0_.SetVisible(true);
- mock_right_decoration1_.SetVisible(true);
-
- const NSRect decoration0Rect =
- [cell frameForDecoration:&mock_right_decoration0_ inFrame:bounds];
- EXPECT_FALSE(NSIsEmptyRect(decoration0Rect));
- EXPECT_TRUE(NSContainsRect(bounds, decoration0Rect));
-
- // Right-side decorations are ordered from rightmost to leftmost.
- // Outer decoration (0) to right of inner decoration (1).
- const NSRect decoration1Rect =
- [cell frameForDecoration:&mock_right_decoration1_ inFrame:bounds];
- EXPECT_FALSE(NSIsEmptyRect(decoration1Rect));
- EXPECT_TRUE(NSContainsRect(bounds, decoration1Rect));
- EXPECT_LT(NSMinX(decoration1Rect), NSMinX(decoration0Rect));
-
- // Decoration should be right of |drawingRect|.
- const NSRect drawingRect = [cell drawingRectForBounds:bounds];
- EXPECT_LT(NSMinX(drawingRect), NSMinX(decoration1Rect));
-
- // Decoration should be right of |textFrame|.
- const NSRect textFrame = [cell textFrameForFrame:bounds];
- EXPECT_LT(NSMinX(textFrame), NSMinX(decoration1Rect));
-}
-
-// Verify -[AutocompleteTextFieldCell updateToolTipsInRect:ofView:].
-TEST_F(AutocompleteTextFieldCellTest, UpdateToolTips) {
- NSString* tooltip = @"tooltip";
-
- // Left decoration returns a tooltip, make sure it is called at
- // least once.
- mock_left_decoration_.SetVisible(true);
- EXPECT_CALL(mock_left_decoration_, GetToolTip())
- .WillOnce(Return(tooltip))
- .WillRepeatedly(Return(tooltip));
-
- // Right decoration returns no tooltip, make sure it is called at
- // least once.
- mock_right_decoration0_.SetVisible(true);
- EXPECT_CALL(mock_right_decoration0_, GetToolTip())
- .WillOnce(Return((NSString*)nil))
- .WillRepeatedly(Return((NSString*)nil));
-
- AutocompleteTextFieldCell* cell =
- static_cast<AutocompleteTextFieldCell*>([view_ cell]);
- const NSRect bounds = [view_ bounds];
- const NSRect leftDecorationRect =
- [cell frameForDecoration:&mock_left_decoration_ inFrame:bounds];
-
- // |controlView| gets the tooltip for the left decoration.
- id controlView = [OCMockObject mockForClass:[AutocompleteTextField class]];
- [[controlView expect] addToolTip:tooltip forRect:leftDecorationRect];
-
- [cell updateToolTipsInRect:bounds ofView:controlView];
-
- [controlView verify];
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/location_bar/autocomplete_text_field_editor.h b/chrome/browser/cocoa/location_bar/autocomplete_text_field_editor.h
deleted file mode 100644
index 127f8ed..0000000
--- a/chrome/browser/cocoa/location_bar/autocomplete_text_field_editor.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// 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 "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/url_drop_target.h"
-
-@class AutocompleteTextField;
-class AutocompleteTextFieldObserver;
-
-// AutocompleteTextFieldEditor customized the AutocompletTextField
-// field editor (helper text-view used in editing). It intercepts UI
-// events for forwarding to the core Omnibox code. It also undoes
-// some of the effects of using styled text in the Omnibox (the text
-// is styled but should not appear that way when copied to the
-// pasteboard).
-
-// Field editor used for the autocomplete field.
-@interface AutocompleteTextFieldEditor : NSTextView<URLDropTarget> {
- // Handles being a drag-and-drop target. We handle DnD directly instead
- // allowing the |AutocompletTextField| to handle it (by making an empty
- // |-updateDragTypeRegistration|), since the latter results in a weird
- // start-up time regression.
- scoped_nsobject<URLDropTargetHandler> dropHandler_;
-
- scoped_nsobject<NSCharacterSet> forbiddenCharacters_;
-
- // Indicates if the field editor's interpretKeyEvents: method is being called.
- // If it's YES, then we should postpone the call to the observer's
- // OnDidChange() method after the field editor's interpretKeyEvents: method
- // is finished, rather than calling it in textDidChange: method. Because the
- // input method may update the marked text after inserting some text, but we
- // need the observer be aware of the marked text as well.
- BOOL interpretingKeyEvents_;
-
- // Indicates if the text has been changed by key events.
- BOOL textChangedByKeyEvents_;
-}
-
-// The delegate is always an AutocompleteTextField*. Override the superclass
-// implementations to allow for proper typing.
-- (AutocompleteTextField*)delegate;
-- (void)setDelegate:(AutocompleteTextField*)delegate;
-
-// Sets attributed string programatically through the field editor's text
-// storage object.
-- (void)setAttributedString:(NSAttributedString*)aString;
-
-@end
-
-@interface AutocompleteTextFieldEditor(PrivateTestMethods)
-- (AutocompleteTextFieldObserver*)observer;
-- (void)pasteAndGo:sender;
-@end
diff --git a/chrome/browser/cocoa/location_bar/autocomplete_text_field_editor.mm b/chrome/browser/cocoa/location_bar/autocomplete_text_field_editor.mm
deleted file mode 100644
index 9275945..0000000
--- a/chrome/browser/cocoa/location_bar/autocomplete_text_field_editor.mm
+++ /dev/null
@@ -1,371 +0,0 @@
-// 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 "chrome/browser/cocoa/location_bar/autocomplete_text_field_editor.h"
-
-#include "app/l10n_util_mac.h"
-#include "base/string_util.h"
-#include "grit/generated_resources.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/app/chrome_command_ids.h" // IDC_*
-#include "chrome/browser/browser_list.h"
-#import "chrome/browser/cocoa/browser_window_controller.h"
-#import "chrome/browser/cocoa/location_bar/autocomplete_text_field.h"
-#import "chrome/browser/cocoa/location_bar/autocomplete_text_field_cell.h"
-#import "chrome/browser/cocoa/toolbar_controller.h"
-
-@implementation AutocompleteTextFieldEditor
-
-- (id)initWithFrame:(NSRect)frameRect {
- if ((self = [super initWithFrame:frameRect])) {
- dropHandler_.reset([[URLDropTargetHandler alloc] initWithView:self]);
-
- forbiddenCharacters_.reset([[NSCharacterSet controlCharacterSet] retain]);
- }
- return self;
-}
-
-// If the entire field is selected, drag the same data as would be
-// dragged from the field's location icon. In some cases the textual
-// contents will not contain relevant data (for instance, "http://" is
-// stripped from URLs).
-- (BOOL)dragSelectionWithEvent:(NSEvent *)event
- offset:(NSSize)mouseOffset
- slideBack:(BOOL)slideBack {
- AutocompleteTextFieldObserver* observer = [self observer];
- DCHECK(observer);
- if (observer && observer->CanCopy()) {
- NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
- observer->CopyToPasteboard(pboard);
-
- NSPoint p;
- NSImage* image = [self dragImageForSelectionWithEvent:event origin:&p];
-
- [self dragImage:image
- at:p
- offset:mouseOffset
- event:event
- pasteboard:pboard
- source:self
- slideBack:slideBack];
- return YES;
- }
- return [super dragSelectionWithEvent:event
- offset:mouseOffset
- slideBack:slideBack];
-}
-
-- (void)copy:(id)sender {
- AutocompleteTextFieldObserver* observer = [self observer];
- DCHECK(observer);
- if (observer && observer->CanCopy())
- observer->CopyToPasteboard([NSPasteboard generalPasteboard]);
-}
-
-- (void)cut:(id)sender {
- [self copy:sender];
- [self delete:nil];
-}
-
-// This class assumes that the delegate is an AutocompleteTextField.
-// Enforce that assumption.
-- (AutocompleteTextField*)delegate {
- AutocompleteTextField* delegate =
- static_cast<AutocompleteTextField*>([super delegate]);
- DCHECK(delegate == nil ||
- [delegate isKindOfClass:[AutocompleteTextField class]]);
- return delegate;
-}
-
-- (void)setDelegate:(AutocompleteTextField*)delegate {
- DCHECK(delegate == nil ||
- [delegate isKindOfClass:[AutocompleteTextField class]]);
- [super setDelegate:delegate];
-}
-
-// Convenience method for retrieving the observer from the delegate.
-- (AutocompleteTextFieldObserver*)observer {
- return [[self delegate] observer];
-}
-
-- (void)paste:(id)sender {
- AutocompleteTextFieldObserver* observer = [self observer];
- DCHECK(observer);
- if (observer) {
- observer->OnPaste();
- }
-}
-
-- (void)pasteAndGo:sender {
- AutocompleteTextFieldObserver* observer = [self observer];
- DCHECK(observer);
- if (observer) {
- observer->OnPasteAndGo();
- }
-}
-
-// We have rich text, but it shouldn't be modified by the user, so
-// don't update the font panel. In theory, -setUsesFontPanel: should
-// accomplish this, but that gets called frequently with YES when
-// NSTextField and NSTextView synchronize their contents. That is
-// probably unavoidable because in most cases having rich text in the
-// field you probably would expect it to update the font panel.
-- (void)updateFontPanel {}
-
-// No ruler bar, so don't update any of that state, either.
-- (void)updateRuler {}
-
-- (NSMenu*)menuForEvent:(NSEvent*)event {
- // Give the control a chance to provide page-action menus.
- // NOTE: Note that page actions aren't even in the editor's
- // boundaries! The Cocoa control implementation seems to do a
- // blanket forward to here if nothing more specific is returned from
- // the control and cell calls.
- // TODO(shess): Determine if the page-action part of this can be
- // moved to the cell.
- NSMenu* actionMenu = [[self delegate] decorationMenuForEvent:event];
- if (actionMenu)
- return actionMenu;
-
- NSMenu* menu = [[[NSMenu alloc] initWithTitle:@"TITLE"] autorelease];
- [menu addItemWithTitle:l10n_util::GetNSStringWithFixup(IDS_CUT)
- action:@selector(cut:)
- keyEquivalent:@""];
- [menu addItemWithTitle:l10n_util::GetNSStringWithFixup(IDS_COPY)
- action:@selector(copy:)
- keyEquivalent:@""];
- [menu addItemWithTitle:l10n_util::GetNSStringWithFixup(IDS_PASTE)
- action:@selector(paste:)
- keyEquivalent:@""];
-
- // TODO(shess): If the control is not editable, should we show a
- // greyed-out "Paste and Go"?
- if ([self isEditable]) {
- // Paste and go/search.
- AutocompleteTextFieldObserver* observer = [self observer];
- DCHECK(observer);
- if (observer && observer->CanPasteAndGo()) {
- const int string_id = observer->GetPasteActionStringId();
- NSString* label = l10n_util::GetNSStringWithFixup(string_id);
-
- // TODO(rohitrao): If the clipboard is empty, should we show a
- // greyed-out "Paste and Go" or nothing at all?
- if ([label length]) {
- [menu addItemWithTitle:label
- action:@selector(pasteAndGo:)
- keyEquivalent:@""];
- }
- }
-
- NSString* label = l10n_util::GetNSStringWithFixup(IDS_EDIT_SEARCH_ENGINES);
- DCHECK([label length]);
- if ([label length]) {
- [menu addItem:[NSMenuItem separatorItem]];
- NSMenuItem* item = [menu addItemWithTitle:label
- action:@selector(commandDispatch:)
- keyEquivalent:@""];
- [item setTag:IDC_EDIT_SEARCH_ENGINES];
- }
- }
-
- return menu;
-}
-
-// (Overridden from NSResponder)
-- (BOOL)becomeFirstResponder {
- BOOL doAccept = [super becomeFirstResponder];
- AutocompleteTextField* field = [self delegate];
- // Only lock visibility if we've been set up with a delegate (the text field).
- if (doAccept && field) {
- // Give the text field ownership of the visibility lock. (The first
- // responder dance between the field and the field editor is a little
- // weird.)
- [[BrowserWindowController browserWindowControllerForView:field]
- lockBarVisibilityForOwner:field withAnimation:YES delay:NO];
- }
- return doAccept;
-}
-
-// (Overridden from NSResponder)
-- (BOOL)resignFirstResponder {
- BOOL doResign = [super resignFirstResponder];
- AutocompleteTextField* field = [self delegate];
- // Only lock visibility if we've been set up with a delegate (the text field).
- if (doResign && field) {
- // Give the text field ownership of the visibility lock.
- [[BrowserWindowController browserWindowControllerForView:field]
- releaseBarVisibilityForOwner:field withAnimation:YES delay:YES];
-
- AutocompleteTextFieldObserver* observer = [self observer];
- if (observer)
- observer->OnKillFocus();
- }
- return doResign;
-}
-
-// (URLDropTarget protocol)
-- (id<URLDropTargetController>)urlDropController {
- BrowserWindowController* windowController =
- [BrowserWindowController browserWindowControllerForView:self];
- return [windowController toolbarController];
-}
-
-// (URLDropTarget protocol)
-- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
- // Make ourself the first responder (even though we're presumably already the
- // first responder), which will select the text to indicate that our contents
- // would be replaced by a drop.
- [[self window] makeFirstResponder:self];
- return [dropHandler_ draggingEntered:sender];
-}
-
-// (URLDropTarget protocol)
-- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender {
- return [dropHandler_ draggingUpdated:sender];
-}
-
-// (URLDropTarget protocol)
-- (void)draggingExited:(id<NSDraggingInfo>)sender {
- return [dropHandler_ draggingExited:sender];
-}
-
-// (URLDropTarget protocol)
-- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
- return [dropHandler_ performDragOperation:sender];
-}
-
-// Prevent control characters from being entered into the Omnibox.
-// This is invoked for keyboard entry, not for pasting.
-- (void)insertText:(id)aString {
- // This method is documented as received either |NSString| or
- // |NSAttributedString|. The autocomplete code will restyle the
- // results in any case, so simplify by always using |NSString|.
- if ([aString isKindOfClass:[NSAttributedString class]])
- aString = [aString string];
-
- // Repeatedly remove control characters. The loop will only ever
- // execute at allwhen the user enters control characters (using
- // Ctrl-Alt- or Ctrl-Q). Making this generally efficient would
- // probably be a loss, since the input always seems to be a single
- // character.
- NSRange range = [aString rangeOfCharacterFromSet:forbiddenCharacters_];
- while (range.location != NSNotFound) {
- aString = [aString stringByReplacingCharactersInRange:range withString:@""];
- range = [aString rangeOfCharacterFromSet:forbiddenCharacters_];
- }
- DCHECK_EQ(range.length, 0U);
-
- // NOTE: If |aString| is empty, this intentionally replaces the
- // selection with empty. This seems consistent with the case where
- // the input contained a mixture of characters and the string ended
- // up not empty.
- [super insertText:aString];
-}
-
-- (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange {
- [super setMarkedText:aString selectedRange:selRange];
-
- // Because the AutocompleteEditViewMac class treats marked text as content,
- // we need to treat the change to marked text as content change as well.
- [self didChangeText];
-}
-
-- (NSRange)selectionRangeForProposedRange:(NSRange)proposedSelRange
- granularity:(NSSelectionGranularity)granularity {
- AutocompleteTextFieldObserver* observer = [self observer];
- NSRange modifiedRange = [super selectionRangeForProposedRange:proposedSelRange
- granularity:granularity];
- if (observer)
- return observer->SelectionRangeForProposedRange(modifiedRange);
- return modifiedRange;
-}
-
-
-
-
-- (void)setSelectedRange:(NSRange)charRange
- affinity:(NSSelectionAffinity)affinity
- stillSelecting:(BOOL)flag {
- [super setSelectedRange:charRange affinity:affinity stillSelecting:flag];
-
- // We're only interested in selection changes directly caused by keyboard
- // input from the user.
- if (interpretingKeyEvents_)
- textChangedByKeyEvents_ = YES;
-}
-
-- (void)interpretKeyEvents:(NSArray *)eventArray {
- DCHECK(!interpretingKeyEvents_);
- interpretingKeyEvents_ = YES;
- textChangedByKeyEvents_ = NO;
- [super interpretKeyEvents:eventArray];
-
- AutocompleteTextFieldObserver* observer = [self observer];
- if (textChangedByKeyEvents_ && observer)
- observer->OnDidChange();
-
- DCHECK(interpretingKeyEvents_);
- interpretingKeyEvents_ = NO;
-}
-
-- (void)didChangeText {
- [super didChangeText];
-
- AutocompleteTextFieldObserver* observer = [self observer];
- if (observer) {
- if (!interpretingKeyEvents_)
- observer->OnDidChange();
- else
- textChangedByKeyEvents_ = YES;
- }
-}
-
-- (void)doCommandBySelector:(SEL)cmd {
- // TODO(shess): Review code for cases where we're fruitlessly attempting to
- // work in spite of not having an observer.
- AutocompleteTextFieldObserver* observer = [self observer];
-
- if (observer && observer->OnDoCommandBySelector(cmd)) {
- // The observer should already be aware of any changes to the text, so
- // setting |textChangedByKeyEvents_| to NO to prevent its OnDidChange()
- // method from being called unnecessarily.
- textChangedByKeyEvents_ = NO;
- return;
- }
-
- // If the escape key was pressed and no revert happened and we're in
- // fullscreen mode, make it resign key.
- if (cmd == @selector(cancelOperation:)) {
- BrowserWindowController* windowController =
- [BrowserWindowController browserWindowControllerForView:self];
- if ([windowController isFullscreen]) {
- [windowController focusTabContents];
- return;
- }
- }
-
- [super doCommandBySelector:cmd];
-}
-
-- (void)setAttributedString:(NSAttributedString*)aString {
- NSTextStorage* textStorage = [self textStorage];
- DCHECK(textStorage);
- [textStorage setAttributedString:aString];
-
- // The text has been changed programmatically. The observer should know
- // this change, so setting |textChangedByKeyEvents_| to NO to
- // prevent its OnDidChange() method from being called unnecessarily.
- textChangedByKeyEvents_ = NO;
-}
-
-- (void)mouseDown:(NSEvent*)theEvent {
- // Close the popup before processing the event.
- AutocompleteTextFieldObserver* observer = [self observer];
- if (observer)
- observer->ClosePopup();
-
- [super mouseDown:theEvent];
-}
-
-@end
diff --git a/chrome/browser/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm b/chrome/browser/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm
deleted file mode 100644
index 04342ce..0000000
--- a/chrome/browser/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm
+++ /dev/null
@@ -1,297 +0,0 @@
-// 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 "chrome/browser/cocoa/location_bar/autocomplete_text_field_editor.h"
-
-#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-#include "base/string_util.h"
-#include "chrome/app/chrome_command_ids.h" // IDC_*
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/location_bar/autocomplete_text_field_unittest_helper.h"
-#import "chrome/browser/cocoa/test_event_utils.h"
-#include "grit/generated_resources.h"
-#include "testing/gmock/include/gmock/gmock-matchers.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-#import "third_party/ocmock/OCMock/OCMock.h"
-
-using ::testing::Return;
-using ::testing::ReturnArg;
-using ::testing::StrictMock;
-using ::testing::A;
-
-namespace {
-
-// TODO(shess): Very similar to AutocompleteTextFieldTest. Maybe
-// those can be shared.
-
-class AutocompleteTextFieldEditorTest : public CocoaTest {
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
- NSRect frame = NSMakeRect(0, 0, 50, 30);
- scoped_nsobject<AutocompleteTextField> field(
- [[AutocompleteTextField alloc] initWithFrame:frame]);
- field_ = field.get();
- [field_ setStringValue:@"Testing"];
- [[test_window() contentView] addSubview:field_];
-
- // Arrange for |field_| to get the right field editor.
- window_delegate_.reset(
- [[AutocompleteTextFieldWindowTestDelegate alloc] init]);
- [test_window() setDelegate:window_delegate_.get()];
-
- // Get the field editor setup.
- [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
- editor_ = static_cast<AutocompleteTextFieldEditor*>([field_ currentEditor]);
-
- EXPECT_TRUE(editor_);
- EXPECT_TRUE([editor_ isKindOfClass:[AutocompleteTextFieldEditor class]]);
- }
-
- AutocompleteTextFieldEditor* editor_;
- AutocompleteTextField* field_;
- scoped_nsobject<AutocompleteTextFieldWindowTestDelegate> window_delegate_;
-};
-
-// Disabled because it crashes sometimes. http://crbug.com/49522
-// Can't rename DISABLED_ because the TEST_VIEW macro prepends.
-// http://crbug.com/53621
-#if 0
-TEST_VIEW(AutocompleteTextFieldEditorTest, field_);
-#endif
-
-// Test that control characters are stripped from insertions.
-TEST_F(AutocompleteTextFieldEditorTest, InsertStripsControlChars) {
- // Sets a string in the field.
- NSString* test_string = @"astring";
- [field_ setStringValue:test_string];
- [editor_ selectAll:nil];
-
- [editor_ insertText:@"t"];
- EXPECT_NSEQ(@"t", [field_ stringValue]);
-
- [editor_ insertText:@"h"];
- EXPECT_NSEQ(@"th", [field_ stringValue]);
-
- // TAB doesn't get inserted.
- [editor_ insertText:[NSString stringWithFormat:@"%c", 7]];
- EXPECT_NSEQ(@"th", [field_ stringValue]);
-
- // Newline doesn't get inserted.
- [editor_ insertText:[NSString stringWithFormat:@"%c", 12]];
- EXPECT_NSEQ(@"th", [field_ stringValue]);
-
- // Multi-character strings get through.
- [editor_ insertText:[NSString stringWithFormat:@"i%cs%c", 8, 127]];
- EXPECT_NSEQ(@"this", [field_ stringValue]);
-
- // Attempting to insert newline when everything is selected clears
- // the field.
- [editor_ selectAll:nil];
- [editor_ insertText:[NSString stringWithFormat:@"%c", 12]];
- EXPECT_NSEQ(@"", [field_ stringValue]);
-}
-
-// Test that |delegate| can provide page action menus.
-TEST_F(AutocompleteTextFieldEditorTest, PageActionMenus) {
- // The event just needs to be something the mock can recognize.
- NSEvent* event =
- test_event_utils::MouseEventAtPoint(NSZeroPoint, NSRightMouseDown, 0);
-
- // Trivial menu which we can recognize and which doesn't look like
- // the default editor context menu.
- scoped_nsobject<id> menu([[NSMenu alloc] initWithTitle:@"Menu"]);
- [menu addItemWithTitle:@"Go Fish"
- action:@selector(goFish:)
- keyEquivalent:@""];
-
- // For OCMOCK_VALUE().
- BOOL yes = YES;
-
- // So that we don't have to mock the observer.
- [editor_ setEditable:NO];
-
- // The delegate's intercept point gets called, and results are
- // propagated back.
- {
- id delegate = [OCMockObject mockForClass:[AutocompleteTextField class]];
- [[[delegate stub] andReturnValue:OCMOCK_VALUE(yes)]
- isKindOfClass:[AutocompleteTextField class]];
- [[[delegate expect] andReturn:menu.get()] decorationMenuForEvent:event];
- [editor_ setDelegate:delegate];
- NSMenu* contextMenu = [editor_ menuForEvent:event];
- [delegate verify];
- [editor_ setDelegate:nil];
-
- EXPECT_EQ(contextMenu, menu.get());
- }
-
- // If the delegate does not return any menu, the default menu is
- // returned.
- {
- id delegate = [OCMockObject mockForClass:[AutocompleteTextField class]];
- [[[delegate stub] andReturnValue:OCMOCK_VALUE(yes)]
- isKindOfClass:[AutocompleteTextField class]];
- [[[delegate expect] andReturn:nil] decorationMenuForEvent:event];
- [editor_ setDelegate:delegate];
- NSMenu* contextMenu = [editor_ menuForEvent:event];
- [delegate verify];
- [editor_ setDelegate:nil];
-
- EXPECT_NE(contextMenu, menu.get());
- NSArray* items = [contextMenu itemArray];
- ASSERT_GT([items count], 0U);
- EXPECT_EQ(@selector(cut:), [[items objectAtIndex:0] action])
- << "action is: " << sel_getName([[items objectAtIndex:0] action]);
- }
-}
-
-// Base class for testing AutocompleteTextFieldObserver messages.
-class AutocompleteTextFieldEditorObserverTest
- : public AutocompleteTextFieldEditorTest {
- public:
- virtual void SetUp() {
- AutocompleteTextFieldEditorTest::SetUp();
- [field_ setObserver:&field_observer_];
- }
-
- virtual void TearDown() {
- // Clear the observer so that we don't show output for
- // uninteresting messages to the mock (for instance, if |field_| has
- // focus at the end of the test).
- [field_ setObserver:NULL];
-
- AutocompleteTextFieldEditorTest::TearDown();
- }
-
- StrictMock<MockAutocompleteTextFieldObserver> field_observer_;
-};
-
-// Test that the field editor is linked in correctly.
-TEST_F(AutocompleteTextFieldEditorTest, FirstResponder) {
- EXPECT_EQ(editor_, [field_ currentEditor]);
- EXPECT_TRUE([editor_ isDescendantOf:field_]);
- EXPECT_EQ([editor_ delegate], field_);
- EXPECT_EQ([editor_ observer], [field_ observer]);
-}
-
-// Test drawing, mostly to ensure nothing leaks or crashes.
-TEST_F(AutocompleteTextFieldEditorTest, Display) {
- [field_ display];
- [editor_ display];
-}
-
-// Test that -paste: is correctly delegated to the observer.
-TEST_F(AutocompleteTextFieldEditorObserverTest, Paste) {
- EXPECT_CALL(field_observer_, OnPaste());
- [editor_ paste:nil];
-}
-
-// Test that -copy: is correctly delegated to the observer.
-TEST_F(AutocompleteTextFieldEditorObserverTest, Copy) {
- EXPECT_CALL(field_observer_, CanCopy())
- .WillOnce(Return(true));
- EXPECT_CALL(field_observer_, CopyToPasteboard(A<NSPasteboard*>()))
- .Times(1);
- [editor_ copy:nil];
-}
-
-// Test that -cut: is correctly delegated to the observer and clears
-// the text field.
-TEST_F(AutocompleteTextFieldEditorObserverTest, Cut) {
- // Sets a string in the field.
- NSString* test_string = @"astring";
- EXPECT_CALL(field_observer_, OnDidBeginEditing());
- EXPECT_CALL(field_observer_, OnDidChange());
- EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(A<NSRange>()))
- .WillRepeatedly(ReturnArg<0>());
- [editor_ setString:test_string];
- [editor_ selectAll:nil];
-
- // Calls cut.
- EXPECT_CALL(field_observer_, CanCopy())
- .WillOnce(Return(true));
- EXPECT_CALL(field_observer_, CopyToPasteboard(A<NSPasteboard*>()))
- .Times(1);
- [editor_ cut:nil];
-
- // Check if the field is cleared.
- ASSERT_EQ([[editor_ textStorage] length], 0U);
-}
-
-// Test that -pasteAndGo: is correctly delegated to the observer.
-TEST_F(AutocompleteTextFieldEditorObserverTest, PasteAndGo) {
- EXPECT_CALL(field_observer_, OnPasteAndGo());
- [editor_ pasteAndGo:nil];
-}
-
-// Test that the menu is constructed correctly when CanPasteAndGo().
-TEST_F(AutocompleteTextFieldEditorObserverTest, CanPasteAndGoMenu) {
- EXPECT_CALL(field_observer_, CanPasteAndGo())
- .WillOnce(Return(true));
- EXPECT_CALL(field_observer_, GetPasteActionStringId())
- .WillOnce(Return(IDS_PASTE_AND_GO));
-
- NSMenu* menu = [editor_ menuForEvent:nil];
- NSArray* items = [menu itemArray];
- ASSERT_EQ([items count], 6U);
- // TODO(shess): Check the titles, too?
- NSUInteger i = 0; // Use an index to make future changes easier.
- EXPECT_EQ([[items objectAtIndex:i++] action], @selector(cut:));
- EXPECT_EQ([[items objectAtIndex:i++] action], @selector(copy:));
- EXPECT_EQ([[items objectAtIndex:i++] action], @selector(paste:));
- EXPECT_EQ([[items objectAtIndex:i++] action], @selector(pasteAndGo:));
- EXPECT_TRUE([[items objectAtIndex:i++] isSeparatorItem]);
-
- EXPECT_EQ([[items objectAtIndex:i] action], @selector(commandDispatch:));
- EXPECT_EQ([[items objectAtIndex:i] tag], IDC_EDIT_SEARCH_ENGINES);
- i++;
-}
-
-// Test that the menu is constructed correctly when !CanPasteAndGo().
-TEST_F(AutocompleteTextFieldEditorObserverTest, CannotPasteAndGoMenu) {
- EXPECT_CALL(field_observer_, CanPasteAndGo())
- .WillOnce(Return(false));
-
- NSMenu* menu = [editor_ menuForEvent:nil];
- NSArray* items = [menu itemArray];
- ASSERT_EQ([items count], 5U);
- // TODO(shess): Check the titles, too?
- NSUInteger i = 0; // Use an index to make future changes easier.
- EXPECT_EQ([[items objectAtIndex:i++] action], @selector(cut:));
- EXPECT_EQ([[items objectAtIndex:i++] action], @selector(copy:));
- EXPECT_EQ([[items objectAtIndex:i++] action], @selector(paste:));
- EXPECT_TRUE([[items objectAtIndex:i++] isSeparatorItem]);
-
- EXPECT_EQ([[items objectAtIndex:i] action], @selector(commandDispatch:));
- EXPECT_EQ([[items objectAtIndex:i] tag], IDC_EDIT_SEARCH_ENGINES);
- i++;
-}
-
-// Test that the menu is constructed correctly when field isn't
-// editable.
-TEST_F(AutocompleteTextFieldEditorObserverTest, CanPasteAndGoMenuNotEditable) {
- [field_ setEditable:NO];
- [editor_ setEditable:NO];
-
- // Never call these when not editable.
- EXPECT_CALL(field_observer_, CanPasteAndGo())
- .Times(0);
- EXPECT_CALL(field_observer_, GetPasteActionStringId())
- .Times(0);
-
- NSMenu* menu = [editor_ menuForEvent:nil];
- NSArray* items = [menu itemArray];
- ASSERT_EQ([items count], 3U);
- // TODO(shess): Check the titles, too?
- NSUInteger i = 0; // Use an index to make future changes easier.
- EXPECT_EQ([[items objectAtIndex:i++] action], @selector(cut:));
- EXPECT_EQ([[items objectAtIndex:i++] action], @selector(copy:));
- EXPECT_EQ([[items objectAtIndex:i++] action], @selector(paste:));
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/location_bar/autocomplete_text_field_unittest.mm b/chrome/browser/cocoa/location_bar/autocomplete_text_field_unittest.mm
deleted file mode 100644
index 17fdfc0..0000000
--- a/chrome/browser/cocoa/location_bar/autocomplete_text_field_unittest.mm
+++ /dev/null
@@ -1,792 +0,0 @@
-// 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 "app/resource_bundle.h"
-#import "base/cocoa_protocols_mac.h"
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/location_bar/autocomplete_text_field.h"
-#import "chrome/browser/cocoa/location_bar/autocomplete_text_field_cell.h"
-#import "chrome/browser/cocoa/location_bar/autocomplete_text_field_editor.h"
-#import "chrome/browser/cocoa/location_bar/autocomplete_text_field_unittest_helper.h"
-#import "chrome/browser/cocoa/location_bar/location_bar_decoration.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "grit/theme_resources.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-using ::testing::A;
-using ::testing::InSequence;
-using ::testing::Return;
-using ::testing::ReturnArg;
-using ::testing::StrictMock;
-using ::testing::_;
-
-namespace {
-
-class MockDecoration : public LocationBarDecoration {
- public:
- virtual CGFloat GetWidthForSpace(CGFloat width) { return 20.0; }
-
- virtual void DrawInFrame(NSRect frame, NSView* control_view) { ; }
- MOCK_METHOD0(AcceptsMousePress, bool());
- MOCK_METHOD1(OnMousePressed, bool(NSRect frame));
- MOCK_METHOD0(GetMenu, NSMenu*());
-};
-
-// Mock up an incrementing event number.
-NSUInteger eventNumber = 0;
-
-// Create an event of the indicated |type| at |point| within |view|.
-// TODO(shess): Would be nice to have a MockApplication which provided
-// nifty accessors to create these things and inject them. It could
-// even provide functions for "Click and drag mouse from point A to
-// point B".
-NSEvent* Event(NSView* view, const NSPoint point, const NSEventType type,
- const NSUInteger clickCount) {
- NSWindow* window([view window]);
- const NSPoint locationInWindow([view convertPoint:point toView:nil]);
- const NSPoint location([window convertBaseToScreen:locationInWindow]);
- return [NSEvent mouseEventWithType:type
- location:location
- modifierFlags:0
- timestamp:0
- windowNumber:[window windowNumber]
- context:nil
- eventNumber:eventNumber++
- clickCount:clickCount
- pressure:0.0];
-}
-NSEvent* Event(NSView* view, const NSPoint point, const NSEventType type) {
- return Event(view, point, type, 1);
-}
-
-// Width of the field so that we don't have to ask |field_| for it all
-// the time.
-static const CGFloat kWidth(300.0);
-
-class AutocompleteTextFieldTest : public CocoaTest {
- public:
- AutocompleteTextFieldTest() {
- // Make sure this is wide enough to play games with the cell
- // decorations.
- NSRect frame = NSMakeRect(0, 0, kWidth, 30);
- scoped_nsobject<AutocompleteTextField> field(
- [[AutocompleteTextField alloc] initWithFrame:frame]);
- field_ = field.get();
- [field_ setStringValue:@"Test test"];
- [[test_window() contentView] addSubview:field_];
-
- AutocompleteTextFieldCell* cell = [field_ cell];
- [cell clearDecorations];
-
- mock_left_decoration_.SetVisible(false);
- [cell addLeftDecoration:&mock_left_decoration_];
-
- mock_right_decoration_.SetVisible(false);
- [cell addRightDecoration:&mock_right_decoration_];
-
- window_delegate_.reset(
- [[AutocompleteTextFieldWindowTestDelegate alloc] init]);
- [test_window() setDelegate:window_delegate_.get()];
- }
-
- NSEvent* KeyDownEventWithFlags(NSUInteger flags) {
- return [NSEvent keyEventWithType:NSKeyDown
- location:NSZeroPoint
- modifierFlags:flags
- timestamp:0.0
- windowNumber:[test_window() windowNumber]
- context:nil
- characters:@"a"
- charactersIgnoringModifiers:@"a"
- isARepeat:NO
- keyCode:'a'];
- }
-
- // Helper to return the field-editor frame being used w/in |field_|.
- NSRect EditorFrame() {
- EXPECT_TRUE([field_ currentEditor]);
- EXPECT_EQ([[field_ subviews] count], 1U);
- if ([[field_ subviews] count] > 0) {
- return [[[field_ subviews] objectAtIndex:0] frame];
- } else {
- // Return something which won't work so the caller can soldier
- // on.
- return NSZeroRect;
- }
- }
-
- AutocompleteTextField* field_;
- MockDecoration mock_left_decoration_;
- MockDecoration mock_right_decoration_;
- scoped_nsobject<AutocompleteTextFieldWindowTestDelegate> window_delegate_;
-};
-
-TEST_VIEW(AutocompleteTextFieldTest, field_);
-
-// Base class for testing AutocompleteTextFieldObserver messages.
-class AutocompleteTextFieldObserverTest : public AutocompleteTextFieldTest {
- public:
- virtual void SetUp() {
- AutocompleteTextFieldTest::SetUp();
- [field_ setObserver:&field_observer_];
- }
-
- virtual void TearDown() {
- // Clear the observer so that we don't show output for
- // uninteresting messages to the mock (for instance, if |field_| has
- // focus at the end of the test).
- [field_ setObserver:NULL];
-
- AutocompleteTextFieldTest::TearDown();
- }
-
- StrictMock<MockAutocompleteTextFieldObserver> field_observer_;
-};
-
-// Test that we have the right cell class.
-TEST_F(AutocompleteTextFieldTest, CellClass) {
- EXPECT_TRUE([[field_ cell] isKindOfClass:[AutocompleteTextFieldCell class]]);
-}
-
-// Test that becoming first responder sets things up correctly.
-TEST_F(AutocompleteTextFieldTest, FirstResponder) {
- EXPECT_EQ(nil, [field_ currentEditor]);
- EXPECT_EQ([[field_ subviews] count], 0U);
- [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
- EXPECT_FALSE(nil == [field_ currentEditor]);
- EXPECT_EQ([[field_ subviews] count], 1U);
- EXPECT_TRUE([[field_ currentEditor] isDescendantOf:field_]);
-
- // Check that the window delegate is providing the right editor.
- Class c = [AutocompleteTextFieldEditor class];
- EXPECT_TRUE([[field_ currentEditor] isKindOfClass:c]);
-}
-
-TEST_F(AutocompleteTextFieldTest, AvailableDecorationWidth) {
- // A fudge factor to account for how much space the border takes up.
- // The test shouldn't be too dependent on the field's internals, but
- // it also shouldn't let deranged cases fall through the cracks
- // (like nothing available with no text, or everything available
- // with some text).
- const CGFloat kBorderWidth = 20.0;
-
- // With no contents, almost the entire width is available for
- // decorations.
- [field_ setStringValue:@""];
- CGFloat availableWidth = [field_ availableDecorationWidth];
- EXPECT_LE(availableWidth, kWidth);
- EXPECT_GT(availableWidth, kWidth - kBorderWidth);
-
- // With minor contents, most of the remaining width is available for
- // decorations.
- NSDictionary* attributes =
- [NSDictionary dictionaryWithObject:[field_ font]
- forKey:NSFontAttributeName];
- NSString* string = @"Hello world";
- const NSSize size([string sizeWithAttributes:attributes]);
- [field_ setStringValue:string];
- availableWidth = [field_ availableDecorationWidth];
- EXPECT_LE(availableWidth, kWidth - size.width);
- EXPECT_GT(availableWidth, kWidth - size.width - kBorderWidth);
-
- // With huge contents, nothing at all is left for decorations.
- string = @"A long string which is surely wider than field_ can hold.";
- [field_ setStringValue:string];
- availableWidth = [field_ availableDecorationWidth];
- EXPECT_LT(availableWidth, 0.0);
-}
-
-// Test drawing, mostly to ensure nothing leaks or crashes.
-TEST_F(AutocompleteTextFieldTest, Display) {
- [field_ display];
-
- // Test focussed drawing.
- [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
- [field_ display];
- [test_window() clearPretendKeyWindowAndFirstResponder];
-}
-
-TEST_F(AutocompleteTextFieldObserverTest, FlagsChanged) {
- InSequence dummy; // Call mock in exactly the order specified.
-
- // Test without Control key down, but some other modifier down.
- EXPECT_CALL(field_observer_, OnControlKeyChanged(false));
- [field_ flagsChanged:KeyDownEventWithFlags(NSShiftKeyMask)];
-
- // Test with Control key down.
- EXPECT_CALL(field_observer_, OnControlKeyChanged(true));
- [field_ flagsChanged:KeyDownEventWithFlags(NSControlKeyMask)];
-}
-
-// This test is here rather than in the editor's tests because the
-// field catches -flagsChanged: because it's on the responder chain,
-// the field editor doesn't implement it.
-TEST_F(AutocompleteTextFieldObserverTest, FieldEditorFlagsChanged) {
- // Many of these methods try to change the selection.
- EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(A<NSRange>()))
- .WillRepeatedly(ReturnArg<0>());
-
- InSequence dummy; // Call mock in exactly the order specified.
- EXPECT_CALL(field_observer_, OnSetFocus(false));
- [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
- NSResponder* firstResponder = [[field_ window] firstResponder];
- EXPECT_EQ(firstResponder, [field_ currentEditor]);
-
- // Test without Control key down, but some other modifier down.
- EXPECT_CALL(field_observer_, OnControlKeyChanged(false));
- [firstResponder flagsChanged:KeyDownEventWithFlags(NSShiftKeyMask)];
-
- // Test with Control key down.
- EXPECT_CALL(field_observer_, OnControlKeyChanged(true));
- [firstResponder flagsChanged:KeyDownEventWithFlags(NSControlKeyMask)];
-}
-
-// Frame size changes are propagated to |observer_|.
-TEST_F(AutocompleteTextFieldObserverTest, FrameChanged) {
- EXPECT_CALL(field_observer_, OnFrameChanged());
- NSRect frame = [field_ frame];
- frame.size.width += 10.0;
- [field_ setFrame:frame];
-}
-
-// Test that the field editor gets the same bounds when focus is
-// delivered by the standard focusing machinery, or by
-// -resetFieldEditorFrameIfNeeded.
-TEST_F(AutocompleteTextFieldTest, ResetFieldEditorBase) {
- // Capture the editor frame resulting from the standard focus
- // machinery.
- [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
- const NSRect baseEditorFrame = EditorFrame();
-
- // A decoration should result in a strictly smaller editor frame.
- mock_left_decoration_.SetVisible(true);
- [field_ resetFieldEditorFrameIfNeeded];
- EXPECT_FALSE(NSEqualRects(baseEditorFrame, EditorFrame()));
- EXPECT_TRUE(NSContainsRect(baseEditorFrame, EditorFrame()));
-
- // Removing the decoration and using -resetFieldEditorFrameIfNeeded
- // should result in the same frame as the standard focus machinery.
- mock_left_decoration_.SetVisible(false);
- [field_ resetFieldEditorFrameIfNeeded];
- EXPECT_TRUE(NSEqualRects(baseEditorFrame, EditorFrame()));
-}
-
-// Test that the field editor gets the same bounds when focus is
-// delivered by the standard focusing machinery, or by
-// -resetFieldEditorFrameIfNeeded, this time with a decoration
-// pre-loaded.
-TEST_F(AutocompleteTextFieldTest, ResetFieldEditorWithDecoration) {
- AutocompleteTextFieldCell* cell = [field_ cell];
-
- // Make sure decoration isn't already visible, then make it visible.
- EXPECT_TRUE(NSIsEmptyRect([cell frameForDecoration:&mock_left_decoration_
- inFrame:[field_ bounds]]));
- mock_left_decoration_.SetVisible(true);
- EXPECT_FALSE(NSIsEmptyRect([cell frameForDecoration:&mock_left_decoration_
- inFrame:[field_ bounds]]));
-
- // Capture the editor frame resulting from the standard focus
- // machinery.
-
- [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
- const NSRect baseEditorFrame = EditorFrame();
-
- // When the decoration is not visible the frame should be strictly larger.
- mock_left_decoration_.SetVisible(false);
- EXPECT_TRUE(NSIsEmptyRect([cell frameForDecoration:&mock_left_decoration_
- inFrame:[field_ bounds]]));
- [field_ resetFieldEditorFrameIfNeeded];
- EXPECT_FALSE(NSEqualRects(baseEditorFrame, EditorFrame()));
- EXPECT_TRUE(NSContainsRect(EditorFrame(), baseEditorFrame));
-
- // When the decoration is visible, -resetFieldEditorFrameIfNeeded
- // should result in the same frame as the standard focus machinery.
- mock_left_decoration_.SetVisible(true);
- EXPECT_FALSE(NSIsEmptyRect([cell frameForDecoration:&mock_left_decoration_
- inFrame:[field_ bounds]]));
-
- [field_ resetFieldEditorFrameIfNeeded];
- EXPECT_TRUE(NSEqualRects(baseEditorFrame, EditorFrame()));
-}
-
-// Test that resetting the field editor bounds does not cause untoward
-// messages to the field's observer.
-TEST_F(AutocompleteTextFieldObserverTest, ResetFieldEditorContinuesEditing) {
- // Many of these methods try to change the selection.
- EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(A<NSRange>()))
- .WillRepeatedly(ReturnArg<0>());
-
- EXPECT_CALL(field_observer_, OnSetFocus(false));
- // Becoming first responder doesn't begin editing.
- [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
- const NSRect baseEditorFrame = EditorFrame();
- NSTextView* editor = static_cast<NSTextView*>([field_ currentEditor]);
- EXPECT_TRUE(nil != editor);
-
- // This should begin editing and indicate a change.
- EXPECT_CALL(field_observer_, OnDidBeginEditing());
- EXPECT_CALL(field_observer_, OnDidChange());
- [editor shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:@""];
- [editor didChangeText];
-
- // No messages to |field_observer_| when the frame actually changes.
- mock_left_decoration_.SetVisible(true);
- [field_ resetFieldEditorFrameIfNeeded];
- EXPECT_FALSE(NSEqualRects(baseEditorFrame, EditorFrame()));
-}
-
-// Clicking in a right-hand decoration which does not handle the mouse
-// puts the caret rightmost.
-TEST_F(AutocompleteTextFieldTest, ClickRightDecorationPutsCaretRightmost) {
- // Decoration does not handle the mouse event, so the cell should
- // process it. Called at least once.
- EXPECT_CALL(mock_right_decoration_, AcceptsMousePress())
- .WillOnce(Return(false))
- .WillRepeatedly(Return(false));
-
- // Set the decoration before becoming responder.
- EXPECT_FALSE([field_ currentEditor]);
- mock_right_decoration_.SetVisible(true);
-
- // Make first responder should select all.
- [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
- EXPECT_TRUE([field_ currentEditor]);
- const NSRange allRange = NSMakeRange(0, [[field_ stringValue] length]);
- EXPECT_TRUE(NSEqualRanges(allRange, [[field_ currentEditor] selectedRange]));
-
- // Generate a click on the decoration.
- AutocompleteTextFieldCell* cell = [field_ cell];
- const NSRect bounds = [field_ bounds];
- const NSRect iconFrame =
- [cell frameForDecoration:&mock_right_decoration_ inFrame:bounds];
- const NSPoint point = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame));
- NSEvent* downEvent = Event(field_, point, NSLeftMouseDown);
- NSEvent* upEvent = Event(field_, point, NSLeftMouseUp);
- [NSApp postEvent:upEvent atStart:YES];
- [field_ mouseDown:downEvent];
-
- // Selection should be a right-hand-side caret.
- EXPECT_TRUE(NSEqualRanges(NSMakeRange([[field_ stringValue] length], 0),
- [[field_ currentEditor] selectedRange]));
-}
-
-// Clicking in a left-side decoration which doesn't handle the event
-// puts the selection in the leftmost position.
-TEST_F(AutocompleteTextFieldTest, ClickLeftDecorationPutsCaretLeftmost) {
- // Decoration does not handle the mouse event, so the cell should
- // process it. Called at least once.
- EXPECT_CALL(mock_left_decoration_, AcceptsMousePress())
- .WillOnce(Return(false))
- .WillRepeatedly(Return(false));
-
- // Set the decoration before becoming responder.
- EXPECT_FALSE([field_ currentEditor]);
- mock_left_decoration_.SetVisible(true);
-
- // Make first responder should select all.
- [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
- EXPECT_TRUE([field_ currentEditor]);
- const NSRange allRange = NSMakeRange(0, [[field_ stringValue] length]);
- EXPECT_TRUE(NSEqualRanges(allRange, [[field_ currentEditor] selectedRange]));
-
- // Generate a click on the decoration.
- AutocompleteTextFieldCell* cell = [field_ cell];
- const NSRect bounds = [field_ bounds];
- const NSRect iconFrame =
- [cell frameForDecoration:&mock_left_decoration_ inFrame:bounds];
- const NSPoint point = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame));
- NSEvent* downEvent = Event(field_, point, NSLeftMouseDown);
- NSEvent* upEvent = Event(field_, point, NSLeftMouseUp);
- [NSApp postEvent:upEvent atStart:YES];
- [field_ mouseDown:downEvent];
-
- // Selection should be a left-hand-side caret.
- EXPECT_TRUE(NSEqualRanges(NSMakeRange(0, 0),
- [[field_ currentEditor] selectedRange]));
-}
-
-// Clicks not in the text area or the cell's decorations fall through
-// to the editor.
-TEST_F(AutocompleteTextFieldTest, ClickBorderSelectsAll) {
- // Can't rely on the window machinery to make us first responder,
- // here.
- [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
- EXPECT_TRUE([field_ currentEditor]);
-
- const NSPoint point(NSMakePoint(20.0, 1.0));
- NSEvent* downEvent(Event(field_, point, NSLeftMouseDown));
- NSEvent* upEvent(Event(field_, point, NSLeftMouseUp));
- [NSApp postEvent:upEvent atStart:YES];
- [field_ mouseDown:downEvent];
-
- // Clicking in the narrow border area around a Cocoa NSTextField
- // does a select-all. Regardless of whether this is a good call, it
- // works as a test that things get passed down to the editor.
- const NSRange selectedRange([[field_ currentEditor] selectedRange]);
- EXPECT_EQ(selectedRange.location, 0U);
- EXPECT_EQ(selectedRange.length, [[field_ stringValue] length]);
-}
-
-// Single-click with no drag should setup a field editor and
-// select all.
-TEST_F(AutocompleteTextFieldTest, ClickSelectsAll) {
- EXPECT_FALSE([field_ currentEditor]);
-
- const NSPoint point = NSMakePoint(20.0, NSMidY([field_ bounds]));
- NSEvent* downEvent(Event(field_, point, NSLeftMouseDown));
- NSEvent* upEvent(Event(field_, point, NSLeftMouseUp));
- [NSApp postEvent:upEvent atStart:YES];
- [field_ mouseDown:downEvent];
- EXPECT_TRUE([field_ currentEditor]);
- const NSRange selectedRange([[field_ currentEditor] selectedRange]);
- EXPECT_EQ(selectedRange.location, 0U);
- EXPECT_EQ(selectedRange.length, [[field_ stringValue] length]);
-}
-
-// Click-drag selects text, not select all.
-TEST_F(AutocompleteTextFieldTest, ClickDragSelectsText) {
- EXPECT_FALSE([field_ currentEditor]);
-
- NSEvent* downEvent(Event(field_, NSMakePoint(20.0, 5.0), NSLeftMouseDown));
- NSEvent* upEvent(Event(field_, NSMakePoint(0.0, 5.0), NSLeftMouseUp));
- [NSApp postEvent:upEvent atStart:YES];
- [field_ mouseDown:downEvent];
- EXPECT_TRUE([field_ currentEditor]);
-
- // Expect this to have selected a prefix of the content. Mostly
- // just don't want the select-all behavior.
- const NSRange selectedRange([[field_ currentEditor] selectedRange]);
- EXPECT_EQ(selectedRange.location, 0U);
- EXPECT_LT(selectedRange.length, [[field_ stringValue] length]);
-}
-
-// TODO(shess): Test that click/pause/click allows cursor placement.
-// In this case the first click goes to the field, but the second
-// click goes to the field editor, so the current testing pattern
-// can't work. What really needs to happen is to push through the
-// NSWindow event machinery so that we can say "two independent clicks
-// at the same location have the right effect". Once that is done, it
-// might make sense to revise the other tests to use the same
-// machinery.
-
-// Double-click selects word, not select all.
-TEST_F(AutocompleteTextFieldTest, DoubleClickSelectsWord) {
- EXPECT_FALSE([field_ currentEditor]);
-
- const NSPoint point = NSMakePoint(20.0, NSMidY([field_ bounds]));
- NSEvent* downEvent(Event(field_, point, NSLeftMouseDown, 1));
- NSEvent* upEvent(Event(field_, point, NSLeftMouseUp, 1));
- NSEvent* downEvent2(Event(field_, point, NSLeftMouseDown, 2));
- NSEvent* upEvent2(Event(field_, point, NSLeftMouseUp, 2));
- [NSApp postEvent:upEvent atStart:YES];
- [field_ mouseDown:downEvent];
- [NSApp postEvent:upEvent2 atStart:YES];
- [field_ mouseDown:downEvent2];
- EXPECT_TRUE([field_ currentEditor]);
-
- // Selected the first word.
- const NSRange selectedRange([[field_ currentEditor] selectedRange]);
- const NSRange spaceRange([[field_ stringValue] rangeOfString:@" "]);
- EXPECT_GT(spaceRange.location, 0U);
- EXPECT_LT(spaceRange.length, [[field_ stringValue] length]);
- EXPECT_EQ(selectedRange.location, 0U);
- EXPECT_EQ(selectedRange.length, spaceRange.location);
-}
-
-TEST_F(AutocompleteTextFieldTest, TripleClickSelectsAll) {
- EXPECT_FALSE([field_ currentEditor]);
-
- const NSPoint point(NSMakePoint(20.0, 5.0));
- NSEvent* downEvent(Event(field_, point, NSLeftMouseDown, 1));
- NSEvent* upEvent(Event(field_, point, NSLeftMouseUp, 1));
- NSEvent* downEvent2(Event(field_, point, NSLeftMouseDown, 2));
- NSEvent* upEvent2(Event(field_, point, NSLeftMouseUp, 2));
- NSEvent* downEvent3(Event(field_, point, NSLeftMouseDown, 3));
- NSEvent* upEvent3(Event(field_, point, NSLeftMouseUp, 3));
- [NSApp postEvent:upEvent atStart:YES];
- [field_ mouseDown:downEvent];
- [NSApp postEvent:upEvent2 atStart:YES];
- [field_ mouseDown:downEvent2];
- [NSApp postEvent:upEvent3 atStart:YES];
- [field_ mouseDown:downEvent3];
- EXPECT_TRUE([field_ currentEditor]);
-
- // Selected the first word.
- const NSRange selectedRange([[field_ currentEditor] selectedRange]);
- EXPECT_EQ(selectedRange.location, 0U);
- EXPECT_EQ(selectedRange.length, [[field_ stringValue] length]);
-}
-
-// Clicking a decoration should call decoration's OnMousePressed.
-TEST_F(AutocompleteTextFieldTest, LeftDecorationMouseDown) {
- // At this point, not focussed.
- EXPECT_FALSE([field_ currentEditor]);
-
- mock_left_decoration_.SetVisible(true);
- EXPECT_CALL(mock_left_decoration_, AcceptsMousePress())
- .WillRepeatedly(Return(true));
-
- AutocompleteTextFieldCell* cell = [field_ cell];
- const NSRect iconFrame =
- [cell frameForDecoration:&mock_left_decoration_ inFrame:[field_ bounds]];
- const NSPoint location = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame));
- NSEvent* downEvent = Event(field_, location, NSLeftMouseDown, 1);
- NSEvent* upEvent = Event(field_, location, NSLeftMouseUp, 1);
-
- // Since decorations can be dragged, the mouse-press is sent on
- // mouse-up.
- [NSApp postEvent:upEvent atStart:YES];
-
- EXPECT_CALL(mock_left_decoration_, OnMousePressed(_))
- .WillOnce(Return(true));
- [field_ mouseDown:downEvent];
-
- // Focus the field and test that handled clicks don't affect selection.
- [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
- EXPECT_TRUE([field_ currentEditor]);
- const NSRange allRange = NSMakeRange(0, [[field_ stringValue] length]);
- EXPECT_TRUE(NSEqualRanges(allRange, [[field_ currentEditor] selectedRange]));
-
- // Generate another click on the decoration.
- downEvent = Event(field_, location, NSLeftMouseDown, 1);
- upEvent = Event(field_, location, NSLeftMouseUp, 1);
- [NSApp postEvent:upEvent atStart:YES];
- EXPECT_CALL(mock_left_decoration_, OnMousePressed(_))
- .WillOnce(Return(true));
- [field_ mouseDown:downEvent];
-
- // The selection should not have changed.
- EXPECT_TRUE(NSEqualRanges(allRange, [[field_ currentEditor] selectedRange]));
-
- // TODO(shess): Test that mouse drags are initiated if the next
- // event is a drag, or if the mouse-up takes too long to arrive.
- // IDEA: mock decoration to return a pasteboard which a mock
- // AutocompleteTextField notes in -dragImage:*.
-}
-
-// Clicking a decoration should call decoration's OnMousePressed.
-TEST_F(AutocompleteTextFieldTest, RightDecorationMouseDown) {
- // At this point, not focussed.
- EXPECT_FALSE([field_ currentEditor]);
-
- mock_right_decoration_.SetVisible(true);
- EXPECT_CALL(mock_right_decoration_, AcceptsMousePress())
- .WillRepeatedly(Return(true));
-
- AutocompleteTextFieldCell* cell = [field_ cell];
- const NSRect bounds = [field_ bounds];
- const NSRect iconFrame =
- [cell frameForDecoration:&mock_right_decoration_ inFrame:bounds];
- const NSPoint location = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame));
- NSEvent* downEvent = Event(field_, location, NSLeftMouseDown, 1);
- NSEvent* upEvent = Event(field_, location, NSLeftMouseUp, 1);
-
- // Since decorations can be dragged, the mouse-press is sent on
- // mouse-up.
- [NSApp postEvent:upEvent atStart:YES];
-
- EXPECT_CALL(mock_right_decoration_, OnMousePressed(_))
- .WillOnce(Return(true));
- [field_ mouseDown:downEvent];
-}
-
-// Test that page action menus are properly returned.
-// TODO(shess): Really, this should test that things are forwarded to
-// the cell, and the cell tests should test that the right things are
-// selected. It's easier to mock the event here, though. This code's
-// event-mockers might be worth promoting to |test_event_utils.h| or
-// |cocoa_test_helper.h|.
-TEST_F(AutocompleteTextFieldTest, DecorationMenu) {
- AutocompleteTextFieldCell* cell = [field_ cell];
- const NSRect bounds([field_ bounds]);
-
- const CGFloat edge = NSHeight(bounds) - 4.0;
- const NSSize size = NSMakeSize(edge, edge);
- scoped_nsobject<NSImage> image([[NSImage alloc] initWithSize:size]);
-
- scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@"Menu"]);
-
- mock_left_decoration_.SetVisible(true);
- mock_right_decoration_.SetVisible(true);
-
- // The item with a menu returns it.
- NSRect actionFrame = [cell frameForDecoration:&mock_right_decoration_
- inFrame:bounds];
- NSPoint location = NSMakePoint(NSMidX(actionFrame), NSMidY(actionFrame));
- NSEvent* event = Event(field_, location, NSRightMouseDown, 1);
-
- // Check that the decoration is called, and the field returns the
- // menu.
- EXPECT_CALL(mock_right_decoration_, GetMenu())
- .WillOnce(Return(menu.get()));
- NSMenu *decorationMenu = [field_ decorationMenuForEvent:event];
- EXPECT_EQ(decorationMenu, menu);
-
- // The item without a menu returns nil.
- EXPECT_CALL(mock_left_decoration_, GetMenu())
- .WillOnce(Return(static_cast<NSMenu*>(nil)));
- actionFrame = [cell frameForDecoration:&mock_left_decoration_
- inFrame:bounds];
- location = NSMakePoint(NSMidX(actionFrame), NSMidY(actionFrame));
- event = Event(field_, location, NSRightMouseDown, 1);
- EXPECT_FALSE([field_ decorationMenuForEvent:event]);
-
- // Something not in an action returns nil.
- location = NSMakePoint(NSMidX(bounds), NSMidY(bounds));
- event = Event(field_, location, NSRightMouseDown, 1);
- EXPECT_FALSE([field_ decorationMenuForEvent:event]);
-}
-
-// Verify that -setAttributedStringValue: works as expected when
-// focussed or when not focussed. Our code mostly depends on about
-// whether -stringValue works right.
-TEST_F(AutocompleteTextFieldTest, SetAttributedStringBaseline) {
- EXPECT_EQ(nil, [field_ currentEditor]);
-
- // So that we can set rich text.
- [field_ setAllowsEditingTextAttributes:YES];
-
- // Set an attribute different from the field's default so we can
- // tell we got the same string out as we put in.
- NSFont* font = [NSFont fontWithDescriptor:[[field_ font] fontDescriptor]
- size:[[field_ font] pointSize] + 2];
- NSDictionary* attributes =
- [NSDictionary dictionaryWithObject:font
- forKey:NSFontAttributeName];
- NSString* const kString = @"This is a test";
- scoped_nsobject<NSAttributedString> attributedString(
- [[NSAttributedString alloc] initWithString:kString
- attributes:attributes]);
-
- // Check that what we get back looks like what we put in.
- EXPECT_NSNE(kString, [field_ stringValue]);
- [field_ setAttributedStringValue:attributedString];
- EXPECT_TRUE([[field_ attributedStringValue]
- isEqualToAttributedString:attributedString]);
- EXPECT_NSEQ(kString, [field_ stringValue]);
-
- // Try that again with focus.
- [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
-
- EXPECT_TRUE([field_ currentEditor]);
-
- // Check that what we get back looks like what we put in.
- [field_ setStringValue:@""];
- EXPECT_NSNE(kString, [field_ stringValue]);
- [field_ setAttributedStringValue:attributedString];
- EXPECT_TRUE([[field_ attributedStringValue]
- isEqualToAttributedString:attributedString]);
- EXPECT_NSEQ(kString, [field_ stringValue]);
-}
-
-// -setAttributedStringValue: shouldn't reset the undo state if things
-// are being editted.
-TEST_F(AutocompleteTextFieldTest, SetAttributedStringUndo) {
- NSColor* redColor = [NSColor redColor];
- NSDictionary* attributes =
- [NSDictionary dictionaryWithObject:redColor
- forKey:NSForegroundColorAttributeName];
- NSString* const kString = @"This is a test";
- scoped_nsobject<NSAttributedString> attributedString(
- [[NSAttributedString alloc] initWithString:kString
- attributes:attributes]);
- [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
- EXPECT_TRUE([field_ currentEditor]);
- NSTextView* editor = static_cast<NSTextView*>([field_ currentEditor]);
- NSUndoManager* undoManager = [editor undoManager];
- EXPECT_TRUE(undoManager);
-
- // Nothing to undo, yet.
- EXPECT_FALSE([undoManager canUndo]);
-
- // Starting an editing action creates an undoable item.
- [editor shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:@""];
- [editor didChangeText];
- EXPECT_TRUE([undoManager canUndo]);
-
- // -setStringValue: resets the editor's undo chain.
- [field_ setStringValue:kString];
- EXPECT_FALSE([undoManager canUndo]);
-
- // Verify that -setAttributedStringValue: does not reset the
- // editor's undo chain.
- [field_ setStringValue:@""];
- [editor shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:@""];
- [editor didChangeText];
- EXPECT_TRUE([undoManager canUndo]);
- [field_ setAttributedStringValue:attributedString];
- EXPECT_TRUE([undoManager canUndo]);
-
- // Verify that calling -clearUndoChain clears the undo chain.
- [field_ clearUndoChain];
- EXPECT_FALSE([undoManager canUndo]);
-}
-
-TEST_F(AutocompleteTextFieldTest, EditorGetsCorrectUndoManager) {
- [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
-
- NSTextView* editor = static_cast<NSTextView*>([field_ currentEditor]);
- EXPECT_TRUE(editor);
- EXPECT_EQ([field_ undoManagerForTextView:editor], [editor undoManager]);
-}
-
-TEST_F(AutocompleteTextFieldObserverTest, SendsEditingMessages) {
- // Many of these methods try to change the selection.
- EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(A<NSRange>()))
- .WillRepeatedly(ReturnArg<0>());
-
- EXPECT_CALL(field_observer_, OnSetFocus(false));
- // Becoming first responder doesn't begin editing.
- [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
- NSTextView* editor = static_cast<NSTextView*>([field_ currentEditor]);
- EXPECT_TRUE(nil != editor);
-
- // This should begin editing and indicate a change.
- EXPECT_CALL(field_observer_, OnDidBeginEditing());
- EXPECT_CALL(field_observer_, OnDidChange());
- [editor shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:@""];
- [editor didChangeText];
-
- // Further changes don't send the begin message.
- EXPECT_CALL(field_observer_, OnDidChange());
- [editor shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:@""];
- [editor didChangeText];
-
- // -doCommandBySelector: should forward to observer via |field_|.
- // TODO(shess): Test with a fake arrow-key event?
- const SEL cmd = @selector(moveDown:);
- EXPECT_CALL(field_observer_, OnDoCommandBySelector(cmd))
- .WillOnce(Return(true));
- [editor doCommandBySelector:cmd];
-
- // Finished with the changes.
- EXPECT_CALL(field_observer_, OnKillFocus());
- EXPECT_CALL(field_observer_, OnDidEndEditing());
- [test_window() clearPretendKeyWindowAndFirstResponder];
-}
-
-// Test that the resign-key notification is forwarded right, and that
-// the notification is registered and unregistered when the view moves
-// in and out of the window.
-// TODO(shess): Should this test the key window for realz? That would
-// be really annoying to whoever is running the tests.
-TEST_F(AutocompleteTextFieldObserverTest, ClosePopupOnResignKey) {
- EXPECT_CALL(field_observer_, ClosePopup());
- [test_window() resignKeyWindow];
-
- scoped_nsobject<AutocompleteTextField> pin([field_ retain]);
- [field_ removeFromSuperview];
- [test_window() resignKeyWindow];
-
- [[test_window() contentView] addSubview:field_];
- EXPECT_CALL(field_observer_, ClosePopup());
- [test_window() resignKeyWindow];
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/location_bar/autocomplete_text_field_unittest_helper.h b/chrome/browser/cocoa/location_bar/autocomplete_text_field_unittest_helper.h
deleted file mode 100644
index 6db113a..0000000
--- a/chrome/browser/cocoa/location_bar/autocomplete_text_field_unittest_helper.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_AUTOCOMPLETE_TEXT_FIELD_UNITTEST_HELPER_H_
-#define CHROME_BROWSER_COCOA_AUTOCOMPLETE_TEXT_FIELD_UNITTEST_HELPER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/cocoa_protocols_mac.h"
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/location_bar/autocomplete_text_field.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-@class AutocompleteTextFieldEditor;
-
-// Return the right field editor for AutocompleteTextField instance.
-
-@interface AutocompleteTextFieldWindowTestDelegate :
- NSObject<NSWindowDelegate> {
- scoped_nsobject<AutocompleteTextFieldEditor> editor_;
-}
-- (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)anObject;
-@end
-
-namespace {
-
-// Allow monitoring calls into AutocompleteTextField's observer.
-// Being in a .h file with an anonymous namespace is strange, but this
-// is here so the mock interface doesn't have to change in multiple
-// places.
-
-// Any method you add here needs a unit test. You knew that.
-
-class MockAutocompleteTextFieldObserver : public AutocompleteTextFieldObserver {
- public:
- MOCK_METHOD1(SelectionRangeForProposedRange, NSRange(NSRange range));
- MOCK_METHOD1(OnControlKeyChanged, void(bool pressed));
- MOCK_METHOD0(CanCopy, bool());
- MOCK_METHOD1(CopyToPasteboard, void(NSPasteboard* pboard));
- MOCK_METHOD0(OnPaste, void());
- MOCK_METHOD0(CanPasteAndGo, bool());
- MOCK_METHOD0(GetPasteActionStringId, int());
- MOCK_METHOD0(OnPasteAndGo, void());
- MOCK_METHOD0(OnFrameChanged, void());
- MOCK_METHOD0(ClosePopup, void());
- MOCK_METHOD0(OnDidBeginEditing, void());
- MOCK_METHOD0(OnDidChange, void());
- MOCK_METHOD0(OnDidEndEditing, void());
- MOCK_METHOD1(OnDoCommandBySelector, bool(SEL cmd));
- MOCK_METHOD1(OnSetFocus, void(bool control_down));
- MOCK_METHOD0(OnKillFocus, void());
-};
-
-} // namespace
-
-#endif // CHROME_BROWSER_COCOA_AUTOCOMPLETE_TEXT_FIELD_UNITTEST_HELPER_H_
diff --git a/chrome/browser/cocoa/location_bar/autocomplete_text_field_unittest_helper.mm b/chrome/browser/cocoa/location_bar/autocomplete_text_field_unittest_helper.mm
deleted file mode 100644
index e170ecd..0000000
--- a/chrome/browser/cocoa/location_bar/autocomplete_text_field_unittest_helper.mm
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/location_bar/autocomplete_text_field_unittest_helper.h"
-
-#import "chrome/browser/cocoa/location_bar/autocomplete_text_field.h"
-#import "chrome/browser/cocoa/location_bar/autocomplete_text_field_editor.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-@implementation AutocompleteTextFieldWindowTestDelegate
-
-- (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)anObject {
- id editor = nil;
- if ([anObject isKindOfClass:[AutocompleteTextField class]]) {
- if (editor_ == nil) {
- editor_.reset([[AutocompleteTextFieldEditor alloc] init]);
- }
- EXPECT_TRUE(editor_ != nil);
-
- // This needs to be called every time, otherwise notifications
- // aren't sent correctly.
- [editor_ setFieldEditor:YES];
- editor = editor_.get();
- }
- return editor;
-}
-
-@end
diff --git a/chrome/browser/cocoa/location_bar/bubble_decoration.h b/chrome/browser/cocoa/location_bar/bubble_decoration.h
deleted file mode 100644
index 8be1aa7..0000000
--- a/chrome/browser/cocoa/location_bar/bubble_decoration.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_LOCATION_BAR_BUBBLE_DECORATION_H_
-#define CHROME_BROWSER_COCOA_LOCATION_BAR_BUBBLE_DECORATION_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/gtest_prod_util.h"
-#include "base/scoped_nsobject.h"
-#include "chrome/browser/cocoa/location_bar/location_bar_decoration.h"
-
-// Draws an outlined rounded rect, with an optional image to the left
-// and an optional text label to the right.
-
-class BubbleDecoration : public LocationBarDecoration {
- public:
- // |font| will be used when drawing the label, and cannot be |nil|.
- BubbleDecoration(NSFont* font);
- ~BubbleDecoration();
-
- // Setup the drawing parameters.
- NSImage* GetImage();
- void SetImage(NSImage* image);
- void SetLabel(NSString* label);
- void SetColors(NSColor* border_color,
- NSColor* background_color,
- NSColor* text_color);
-
- // Implement |LocationBarDecoration|.
- virtual void DrawInFrame(NSRect frame, NSView* control_view);
- virtual CGFloat GetWidthForSpace(CGFloat width);
-
- protected:
- // Helper returning bubble width for the given |image| and |label|
- // assuming |font_| (for sizing text). Arguments can be nil.
- CGFloat GetWidthForImageAndLabel(NSImage* image, NSString* label);
-
- // Helper to return where the image is drawn, for subclasses to drag
- // from. |frame| is the decoration's frame in the containing cell.
- NSRect GetImageRectInFrame(NSRect frame);
-
- private:
- friend class SelectedKeywordDecorationTest;
- FRIEND_TEST_ALL_PREFIXES(SelectedKeywordDecorationTest,
- UsesPartialKeywordIfNarrow);
-
- // Contains font and color attribute for drawing |label_|.
- scoped_nsobject<NSDictionary> attributes_;
-
- // Image drawn in the left side of the bubble.
- scoped_nsobject<NSImage> image_;
-
- // Label to draw to right of image. Can be |nil|.
- scoped_nsobject<NSString> label_;
-
- // Colors used to draw the bubble, should be set by the subclass
- // constructor.
- scoped_nsobject<NSColor> background_color_;
- scoped_nsobject<NSColor> border_color_;
-
- DISALLOW_COPY_AND_ASSIGN(BubbleDecoration);
-};
-
-#endif // CHROME_BROWSER_COCOA_LOCATION_BAR_BUBBLE_DECORATION_H_
diff --git a/chrome/browser/cocoa/location_bar/bubble_decoration.mm b/chrome/browser/cocoa/location_bar/bubble_decoration.mm
deleted file mode 100644
index 79570a5..0000000
--- a/chrome/browser/cocoa/location_bar/bubble_decoration.mm
+++ /dev/null
@@ -1,158 +0,0 @@
-// 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.
-
-#include <cmath>
-
-#import "chrome/browser/cocoa/location_bar/bubble_decoration.h"
-
-#include "base/logging.h"
-#import "chrome/browser/cocoa/image_utils.h"
-
-namespace {
-
-// Padding between the icon/label and bubble edges.
-const CGFloat kBubblePadding = 3.0;
-
-// The image needs to be in the same position as for the location
-// icon, which implies that the bubble's padding in the Omnibox needs
-// to differ from the location icon's. Indeed, that's how the views
-// implementation handles the problem. This draws the bubble edge a
-// little bit further left, which is easier but no less hacky.
-const CGFloat kLeftSideOverdraw = 2.0;
-
-// Omnibox corner radius is |4.0|, this needs to look tight WRT that.
-const CGFloat kBubbleCornerRadius = 2.0;
-
-// How far to inset the bubble from the top and bottom of the drawing
-// frame.
-// TODO(shess): Would be nicer to have the drawing code factor out the
-// space outside the border, and perhaps the border. Then this could
-// reflect the single pixel space w/in that.
-const CGFloat kBubbleYInset = 4.0;
-
-} // namespace
-
-BubbleDecoration::BubbleDecoration(NSFont* font) {
- DCHECK(font);
- if (font) {
- NSDictionary* attributes =
- [NSDictionary dictionaryWithObject:font
- forKey:NSFontAttributeName];
- attributes_.reset([attributes retain]);
- }
-}
-
-BubbleDecoration::~BubbleDecoration() {
-}
-
-CGFloat BubbleDecoration::GetWidthForImageAndLabel(NSImage* image,
- NSString* label) {
- if (!image && !label)
- return kOmittedWidth;
-
- const CGFloat image_width = image ? [image size].width : 0.0;
- if (!label)
- return kBubblePadding + image_width;
-
- // The bubble needs to take up an integral number of pixels.
- // Generally -sizeWithAttributes: seems to overestimate rather than
- // underestimate, so floor() seems to work better.
- const CGFloat label_width =
- std::floor([label sizeWithAttributes:attributes_].width);
- return kBubblePadding + image_width + label_width;
-}
-
-NSRect BubbleDecoration::GetImageRectInFrame(NSRect frame) {
- NSRect imageRect = NSInsetRect(frame, 0.0, kBubbleYInset);
- if (image_) {
- // Center the image vertically.
- const NSSize imageSize = [image_ size];
- imageRect.origin.y +=
- std::floor((NSHeight(frame) - imageSize.height) / 2.0);
- imageRect.size = imageSize;
- }
- return imageRect;
-}
-
-CGFloat BubbleDecoration::GetWidthForSpace(CGFloat width) {
- const CGFloat all_width = GetWidthForImageAndLabel(image_, label_);
- if (all_width <= width)
- return all_width;
-
- const CGFloat image_width = GetWidthForImageAndLabel(image_, nil);
- if (image_width <= width)
- return image_width;
-
- return kOmittedWidth;
-}
-
-void BubbleDecoration::DrawInFrame(NSRect frame, NSView* control_view) {
- const NSRect decorationFrame = NSInsetRect(frame, 0.0, kBubbleYInset);
-
- // The inset is to put the border down the middle of the pixel.
- NSRect bubbleFrame = NSInsetRect(decorationFrame, 0.5, 0.5);
- bubbleFrame.origin.x -= kLeftSideOverdraw;
- bubbleFrame.size.width += kLeftSideOverdraw;
- NSBezierPath* path =
- [NSBezierPath bezierPathWithRoundedRect:bubbleFrame
- xRadius:kBubbleCornerRadius
- yRadius:kBubbleCornerRadius];
-
- [background_color_ setFill];
- [path fill];
-
- [border_color_ setStroke];
- [path setLineWidth:1.0];
- [path stroke];
-
- NSRect imageRect = decorationFrame;
- if (image_) {
- // Center the image vertically.
- const NSSize imageSize = [image_ size];
- imageRect.origin.y +=
- std::floor((NSHeight(decorationFrame) - imageSize.height) / 2.0);
- imageRect.size = imageSize;
- [image_ drawInRect:imageRect
- fromRect:NSZeroRect // Entire image
- operation:NSCompositeSourceOver
- fraction:1.0
- neverFlipped:YES];
- } else {
- imageRect.size = NSZeroSize;
- }
-
- if (label_) {
- NSRect textRect = decorationFrame;
- textRect.origin.x = NSMaxX(imageRect);
- textRect.size.width = NSMaxX(decorationFrame) - NSMinX(textRect);
- [label_ drawInRect:textRect withAttributes:attributes_];
- }
-}
-
-NSImage* BubbleDecoration::GetImage() {
- return image_;
-}
-
-void BubbleDecoration::SetImage(NSImage* image) {
- image_.reset([image retain]);
-}
-
-void BubbleDecoration::SetLabel(NSString* label) {
- // If the initializer was called with |nil|, then the code cannot
- // process a label.
- DCHECK(attributes_);
- if (attributes_)
- label_.reset([label copy]);
-}
-
-void BubbleDecoration::SetColors(NSColor* border_color,
- NSColor* background_color,
- NSColor* text_color) {
- border_color_.reset([border_color retain]);
- background_color_.reset([background_color retain]);
-
- scoped_nsobject<NSMutableDictionary> attributes([attributes_ mutableCopy]);
- [attributes setObject:text_color forKey:NSForegroundColorAttributeName];
- attributes_.reset([attributes copy]);
-}
diff --git a/chrome/browser/cocoa/location_bar/content_setting_decoration.h b/chrome/browser/cocoa/location_bar/content_setting_decoration.h
deleted file mode 100644
index 7e8904b..0000000
--- a/chrome/browser/cocoa/location_bar/content_setting_decoration.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_LOCATION_BAR_CONTENT_SETTING_DECORATION_H_
-#define CHROME_BROWSER_COCOA_LOCATION_BAR_CONTENT_SETTING_DECORATION_H_
-#pragma once
-
-#include "base/scoped_ptr.h"
-#import "chrome/browser/cocoa/location_bar/image_decoration.h"
-#include "chrome/common/content_settings_types.h"
-
-// ContentSettingDecoration is used to display the content settings
-// images on the current page.
-
-class ContentSettingImageModel;
-class LocationBarViewMac;
-class Profile;
-class TabContents;
-
-class ContentSettingDecoration : public ImageDecoration {
- public:
- ContentSettingDecoration(ContentSettingsType settings_type,
- LocationBarViewMac* owner,
- Profile* profile);
- virtual ~ContentSettingDecoration();
-
- // Updates the image and visibility state based on the supplied TabContents.
- // Returns true if the decoration's visible state changed.
- bool UpdateFromTabContents(TabContents* tab_contents);
-
- // Overridden from |LocationBarDecoration|
- virtual bool AcceptsMousePress() { return true; }
- virtual bool OnMousePressed(NSRect frame);
- virtual NSString* GetToolTip();
-
- private:
- // Helper to get where the bubble point should land. Similar to
- // |PageActionDecoration| or |StarDecoration| (|LocationBarViewMac|
- // calls those).
- NSPoint GetBubblePointInFrame(NSRect frame);
-
- void SetToolTip(NSString* tooltip);
-
- scoped_ptr<ContentSettingImageModel> content_setting_image_model_;
-
- LocationBarViewMac* owner_; // weak
- Profile* profile_; // weak
-
- scoped_nsobject<NSString> tooltip_;
-
- DISALLOW_COPY_AND_ASSIGN(ContentSettingDecoration);
-};
-
-#endif // CHROME_BROWSER_COCOA_LOCATION_BAR_CONTENT_SETTING_DECORATION_H_
diff --git a/chrome/browser/cocoa/location_bar/content_setting_decoration.mm b/chrome/browser/cocoa/location_bar/content_setting_decoration.mm
deleted file mode 100644
index 358669f..0000000
--- a/chrome/browser/cocoa/location_bar/content_setting_decoration.mm
+++ /dev/null
@@ -1,109 +0,0 @@
-// 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 "chrome/browser/cocoa/location_bar/content_setting_decoration.h"
-
-#include "app/resource_bundle.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_list.h"
-#import "chrome/browser/cocoa/content_setting_bubble_cocoa.h"
-#import "chrome/browser/cocoa/location_bar/location_bar_view_mac.h"
-#include "chrome/browser/content_setting_image_model.h"
-#include "chrome/browser/content_setting_bubble_model.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/pref_names.h"
-#include "net/base/net_util.h"
-
-namespace {
-
-// How far to offset up from the bottom of the view to get the top
-// border of the popup 2px below the bottom of the Omnibox.
-const CGFloat kPopupPointYOffset = 2.0;
-
-} // namespace
-
-ContentSettingDecoration::ContentSettingDecoration(
- ContentSettingsType settings_type,
- LocationBarViewMac* owner,
- Profile* profile)
- : content_setting_image_model_(
- ContentSettingImageModel::CreateContentSettingImageModel(
- settings_type)),
- owner_(owner),
- profile_(profile) {
-}
-
-ContentSettingDecoration::~ContentSettingDecoration() {
-}
-
-bool ContentSettingDecoration::UpdateFromTabContents(
- TabContents* tab_contents) {
- bool was_visible = IsVisible();
- int old_icon = content_setting_image_model_->get_icon();
- content_setting_image_model_->UpdateFromTabContents(tab_contents);
- SetVisible(content_setting_image_model_->is_visible());
- bool decoration_changed = was_visible != IsVisible() ||
- old_icon != content_setting_image_model_->get_icon();
- if (IsVisible()) {
- // TODO(thakis): We should use pdfs for these icons on OSX.
- // http://crbug.com/35847
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- SetImage(rb.GetNativeImageNamed(content_setting_image_model_->get_icon()));
- SetToolTip(base::SysUTF8ToNSString(
- content_setting_image_model_->get_tooltip()));
- }
- return decoration_changed;
-}
-
-NSPoint ContentSettingDecoration::GetBubblePointInFrame(NSRect frame) {
- const NSRect draw_frame = GetDrawRectInFrame(frame);
- return NSMakePoint(NSMidX(draw_frame),
- NSMaxY(draw_frame) - kPopupPointYOffset);
-}
-
-bool ContentSettingDecoration::OnMousePressed(NSRect frame) {
- // Get host. This should be shared on linux/win/osx medium-term.
- TabContents* tabContents =
- BrowserList::GetLastActive()->GetSelectedTabContents();
- if (!tabContents)
- return true;
-
- GURL url = tabContents->GetURL();
- std::wstring displayHost;
- net::AppendFormattedHost(
- url,
- UTF8ToWide(profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)),
- &displayHost, NULL, NULL);
-
- // Find point for bubble's arrow in screen coordinates.
- // TODO(shess): |owner_| is only being used to fetch |field|.
- // Consider passing in |control_view|. Or refactoring to be
- // consistent with other decorations (which don't currently bring up
- // their bubble directly).
- AutocompleteTextField* field = owner_->GetAutocompleteTextField();
- NSPoint anchor = GetBubblePointInFrame(frame);
- anchor = [field convertPoint:anchor toView:nil];
- anchor = [[field window] convertBaseToScreen:anchor];
-
- // Open bubble.
- ContentSettingBubbleModel* model =
- ContentSettingBubbleModel::CreateContentSettingBubbleModel(
- tabContents, profile_,
- content_setting_image_model_->get_content_settings_type());
- [ContentSettingBubbleController showForModel:model
- parentWindow:[field window]
- anchoredAt:anchor];
- return true;
-}
-
-NSString* ContentSettingDecoration::GetToolTip() {
- return tooltip_.get();
-}
-
-void ContentSettingDecoration::SetToolTip(NSString* tooltip) {
- tooltip_.reset([tooltip retain]);
-}
diff --git a/chrome/browser/cocoa/location_bar/ev_bubble_decoration.h b/chrome/browser/cocoa/location_bar/ev_bubble_decoration.h
deleted file mode 100644
index bbb29fc..0000000
--- a/chrome/browser/cocoa/location_bar/ev_bubble_decoration.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_LOCATION_BAR_EV_BUBBLE_DECORATION_H_
-#define CHROME_BROWSER_COCOA_LOCATION_BAR_EV_BUBBLE_DECORATION_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "chrome/browser/cocoa/location_bar/bubble_decoration.h"
-
-// Draws the "Extended Validation SSL" bubble. This will be a lock
-// icon plus a label from the certification, and will replace the
-// location icon for URLs which have an EV cert. The |location_icon|
-// is used to fulfill drag-related calls.
-
-// TODO(shess): Refactor to pull the |location_icon| functionality out
-// into a distinct class like views |ClickHandler|.
-// http://crbug.com/48866
-
-class LocationIconDecoration;
-
-class EVBubbleDecoration : public BubbleDecoration {
- public:
- EVBubbleDecoration(LocationIconDecoration* location_icon, NSFont* font);
-
- // |GetWidthForSpace()| will set |full_label| as the label, if it
- // fits, else it will set an elided version.
- void SetFullLabel(NSString* full_label);
-
- // Get the point where the page info bubble should point within the
- // decoration's frame, in the cell's coordinates.
- NSPoint GetBubblePointInFrame(NSRect frame);
-
- // Implement |LocationBarDecoration|.
- virtual CGFloat GetWidthForSpace(CGFloat width);
- virtual bool IsDraggable();
- virtual NSPasteboard* GetDragPasteboard();
- virtual NSImage* GetDragImage();
- virtual NSRect GetDragImageFrame(NSRect frame) {
- return GetImageRectInFrame(frame);
- }
- virtual bool OnMousePressed(NSRect frame);
- virtual bool AcceptsMousePress() { return true; }
-
- private:
- // Keeps a reference to the font for use when eliding.
- scoped_nsobject<NSFont> font_;
-
- // The real label. BubbleDecoration's label may be elided.
- scoped_nsobject<NSString> full_label_;
-
- LocationIconDecoration* location_icon_; // weak, owned by location bar.
-
- DISALLOW_COPY_AND_ASSIGN(EVBubbleDecoration);
-};
-
-#endif // CHROME_BROWSER_COCOA_LOCATION_BAR_EV_BUBBLE_DECORATION_H_
diff --git a/chrome/browser/cocoa/location_bar/ev_bubble_decoration.mm b/chrome/browser/cocoa/location_bar/ev_bubble_decoration.mm
deleted file mode 100644
index 40220e4..0000000
--- a/chrome/browser/cocoa/location_bar/ev_bubble_decoration.mm
+++ /dev/null
@@ -1,117 +0,0 @@
-// 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 "chrome/browser/cocoa/location_bar/ev_bubble_decoration.h"
-
-#include "app/text_elider.h"
-#import "base/logging.h"
-#include "base/sys_string_conversions.h"
-#import "chrome/browser/cocoa/image_utils.h"
-#import "chrome/browser/cocoa/location_bar/location_icon_decoration.h"
-#include "gfx/font.h"
-
-namespace {
-
-// TODO(shess): In general, decorations that don't fit in the
-// available space are omitted. This one never goes to omitted, it
-// sticks at 150px, which AFAICT follows the Windows code. Since the
-// Layout() code doesn't take this into account, it's possible the
-// control could end up with display artifacts, though things still
-// work (and don't crash).
-// http://crbug.com/49822
-
-// Minimum acceptable width for the ev bubble.
-const CGFloat kMinElidedBubbleWidth = 150.0;
-
-// Maximum amount of available space to make the bubble, subject to
-// |kMinElidedBubbleWidth|.
-const float kMaxBubbleFraction = 0.5;
-
-// The info-bubble point should look like it points to the bottom of the lock
-// icon. Determined with Pixie.app.
-const CGFloat kPageInfoBubblePointYOffset = 6.0;
-
-// TODO(shess): This is ugly, find a better way. Using it right now
-// so that I can crib from gtk and still be able to see that I'm using
-// the same values easily.
-NSColor* ColorWithRGBBytes(int rr, int gg, int bb) {
- DCHECK_LE(rr, 255);
- DCHECK_LE(bb, 255);
- DCHECK_LE(gg, 255);
- return [NSColor colorWithCalibratedRed:static_cast<float>(rr)/255.0
- green:static_cast<float>(gg)/255.0
- blue:static_cast<float>(bb)/255.0
- alpha:1.0];
-}
-
-} // namespace
-
-EVBubbleDecoration::EVBubbleDecoration(
- LocationIconDecoration* location_icon,
- NSFont* font)
- : BubbleDecoration(font),
- font_([font retain]),
- location_icon_(location_icon) {
- // Color tuples stolen from location_bar_view_gtk.cc.
- NSColor* border_color = ColorWithRGBBytes(0x90, 0xc3, 0x90);
- NSColor* background_color = ColorWithRGBBytes(0xef, 0xfc, 0xef);
- NSColor* text_color = ColorWithRGBBytes(0x07, 0x95, 0x00);
- SetColors(border_color, background_color, text_color);
-}
-
-void EVBubbleDecoration::SetFullLabel(NSString* label) {
- full_label_.reset([label retain]);
- SetLabel(full_label_);
-}
-
-NSPoint EVBubbleDecoration::GetBubblePointInFrame(NSRect frame) {
- NSRect image_rect = GetImageRectInFrame(frame);
- return NSMakePoint(NSMidX(image_rect),
- NSMaxY(image_rect) - kPageInfoBubblePointYOffset);
-}
-
-CGFloat EVBubbleDecoration::GetWidthForSpace(CGFloat width) {
- // Limit with to not take up too much of the available width, but
- // also don't let it shrink too much.
- width = std::max(width * kMaxBubbleFraction, kMinElidedBubbleWidth);
-
- // Use the full label if it fits.
- NSImage* image = GetImage();
- const CGFloat all_width = GetWidthForImageAndLabel(image, full_label_);
- if (all_width <= width) {
- SetLabel(full_label_);
- return all_width;
- }
-
- // Width left for laying out the label.
- const CGFloat width_left = width - GetWidthForImageAndLabel(image, @"");
-
- // Middle-elide the label to fit |width_left|. This leaves the
- // prefix and the trailing country code in place.
- gfx::Font font(base::SysNSStringToWide([font_ fontName]),
- [font_ pointSize]);
- NSString* elided_label = base::SysUTF16ToNSString(
- ElideText(base::SysNSStringToUTF16(full_label_), font, width_left, true));
-
- // Use the elided label.
- SetLabel(elided_label);
- return GetWidthForImageAndLabel(image, elided_label);
-}
-
-// Pass mouse operations through to location icon.
-bool EVBubbleDecoration::IsDraggable() {
- return location_icon_->IsDraggable();
-}
-
-NSPasteboard* EVBubbleDecoration::GetDragPasteboard() {
- return location_icon_->GetDragPasteboard();
-}
-
-NSImage* EVBubbleDecoration::GetDragImage() {
- return location_icon_->GetDragImage();
-}
-
-bool EVBubbleDecoration::OnMousePressed(NSRect frame) {
- return location_icon_->OnMousePressed(frame);
-}
diff --git a/chrome/browser/cocoa/location_bar/ev_bubble_decoration_unittest.mm b/chrome/browser/cocoa/location_bar/ev_bubble_decoration_unittest.mm
deleted file mode 100644
index 69825ab..0000000
--- a/chrome/browser/cocoa/location_bar/ev_bubble_decoration_unittest.mm
+++ /dev/null
@@ -1,55 +0,0 @@
-// 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>
-
-#import "chrome/browser/cocoa/location_bar/ev_bubble_decoration.h"
-
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-class EVBubbleDecorationTest : public CocoaTest {
- public:
- EVBubbleDecorationTest()
- : decoration_(NULL, [NSFont userFontOfSize:12]) {
- }
-
- EVBubbleDecoration decoration_;
-};
-
-// Test that the decoration gets smaller when there's not enough space
-// to fit, within bounds.
-TEST_F(EVBubbleDecorationTest, MiddleElide) {
- NSString* kLongString = @"A very long string with spaces";
- const CGFloat kWide = 1000.0; // Wide enough to fit everything.
- const CGFloat kNarrow = 10.0; // Too narrow for anything.
- const CGFloat kMinimumWidth = 100.0; // Never should get this small.
-
- const NSSize kImageSize = NSMakeSize(20.0, 20.0);
- scoped_nsobject<NSImage> image([[NSImage alloc] initWithSize:kImageSize]);
-
- decoration_.SetImage(image);
- decoration_.SetFullLabel(kLongString);
-
- // Lots of space, decoration not omitted.
- EXPECT_NE(decoration_.GetWidthForSpace(kWide),
- LocationBarDecoration::kOmittedWidth);
-
- // If the available space is of the same magnitude as the required
- // space, the decoration doesn't eat it all up.
- const CGFloat long_width = decoration_.GetWidthForSpace(kWide);
- EXPECT_NE(decoration_.GetWidthForSpace(long_width + 20.0),
- LocationBarDecoration::kOmittedWidth);
- EXPECT_LT(decoration_.GetWidthForSpace(long_width + 20.0), long_width);
-
- // If there is very little space, the decoration is still relatively
- // big.
- EXPECT_NE(decoration_.GetWidthForSpace(kNarrow),
- LocationBarDecoration::kOmittedWidth);
- EXPECT_GT(decoration_.GetWidthForSpace(kNarrow), kMinimumWidth);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/location_bar/image_decoration.h b/chrome/browser/cocoa/location_bar/image_decoration.h
deleted file mode 100644
index 9324554..0000000
--- a/chrome/browser/cocoa/location_bar/image_decoration.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_LOCATION_BAR_IMAGE_DECORATION_H_
-#define CHROME_BROWSER_COCOA_LOCATION_BAR_IMAGE_DECORATION_H_
-#pragma once
-
-#import "base/scoped_nsobject.h"
-#include "chrome/browser/cocoa/location_bar/location_bar_decoration.h"
-
-// |LocationBarDecoration| which sizes and draws itself according to
-// an |NSImage|.
-
-class ImageDecoration : public LocationBarDecoration {
- public:
- ImageDecoration();
- virtual ~ImageDecoration();
-
- NSImage* GetImage();
- void SetImage(NSImage* image);
-
- // Returns the part of |frame| the image is drawn in.
- NSRect GetDrawRectInFrame(NSRect frame);
-
- // Implement |LocationBarDecoration|.
- virtual CGFloat GetWidthForSpace(CGFloat width);
- virtual void DrawInFrame(NSRect frame, NSView* control_view);
-
- private:
- scoped_nsobject<NSImage> image_;
-
- DISALLOW_COPY_AND_ASSIGN(ImageDecoration);
-};
-
-#endif // CHROME_BROWSER_COCOA_LOCATION_BAR_IMAGE_DECORATION_H_
diff --git a/chrome/browser/cocoa/location_bar/image_decoration.mm b/chrome/browser/cocoa/location_bar/image_decoration.mm
deleted file mode 100644
index 980d98d..0000000
--- a/chrome/browser/cocoa/location_bar/image_decoration.mm
+++ /dev/null
@@ -1,54 +0,0 @@
-// 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.
-
-#include <cmath>
-
-#import "chrome/browser/cocoa/location_bar/image_decoration.h"
-
-#import "chrome/browser/cocoa/image_utils.h"
-
-ImageDecoration::ImageDecoration() {
-}
-
-ImageDecoration::~ImageDecoration() {
-}
-
-NSImage* ImageDecoration::GetImage() {
- return image_;
-}
-
-void ImageDecoration::SetImage(NSImage* image) {
- image_.reset([image retain]);
-}
-
-NSRect ImageDecoration::GetDrawRectInFrame(NSRect frame) {
- NSImage* image = GetImage();
- if (!image)
- return frame;
-
- // Center the image within the frame.
- const CGFloat delta_height = NSHeight(frame) - [image size].height;
- const CGFloat y_inset = std::floor(delta_height / 2.0);
- const CGFloat delta_width = NSWidth(frame) - [image size].width;
- const CGFloat x_inset = std::floor(delta_width / 2.0);
- return NSInsetRect(frame, x_inset, y_inset);
-}
-
-CGFloat ImageDecoration::GetWidthForSpace(CGFloat width) {
- NSImage* image = GetImage();
- if (image) {
- const CGFloat image_width = [image size].width;
- if (image_width <= width)
- return image_width;
- }
- return kOmittedWidth;
-}
-
-void ImageDecoration::DrawInFrame(NSRect frame, NSView* control_view) {
- [GetImage() drawInRect:GetDrawRectInFrame(frame)
- fromRect:NSZeroRect // Entire image
- operation:NSCompositeSourceOver
- fraction:1.0
- neverFlipped:YES];
-}
diff --git a/chrome/browser/cocoa/location_bar/image_decoration_unittest.mm b/chrome/browser/cocoa/location_bar/image_decoration_unittest.mm
deleted file mode 100644
index 29040e0..0000000
--- a/chrome/browser/cocoa/location_bar/image_decoration_unittest.mm
+++ /dev/null
@@ -1,55 +0,0 @@
-// 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>
-
-#import "chrome/browser/cocoa/location_bar/image_decoration.h"
-
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-class ImageDecorationTest : public CocoaTest {
- public:
- ImageDecoration decoration_;
-};
-
-TEST_F(ImageDecorationTest, SetGetImage) {
- EXPECT_FALSE(decoration_.GetImage());
-
- const NSSize kImageSize = NSMakeSize(20.0, 20.0);
- scoped_nsobject<NSImage> image([[NSImage alloc] initWithSize:kImageSize]);
-
- decoration_.SetImage(image);
- EXPECT_EQ(decoration_.GetImage(), image);
-
- decoration_.SetImage(nil);
- EXPECT_FALSE(decoration_.GetImage());
-}
-
-TEST_F(ImageDecorationTest, GetWidthForSpace) {
- const CGFloat kWide = 100.0;
- const CGFloat kNarrow = 10.0;
-
- // Decoration with no image is omitted.
- EXPECT_EQ(decoration_.GetWidthForSpace(kWide),
- LocationBarDecoration::kOmittedWidth);
-
- const NSSize kImageSize = NSMakeSize(20.0, 20.0);
- scoped_nsobject<NSImage> image([[NSImage alloc] initWithSize:kImageSize]);
-
- // Decoration takes up the space of the image.
- decoration_.SetImage(image);
- EXPECT_EQ(decoration_.GetWidthForSpace(kWide), kImageSize.width);
-
- // If the image doesn't fit, decoration is omitted.
- EXPECT_EQ(decoration_.GetWidthForSpace(kNarrow),
- LocationBarDecoration::kOmittedWidth);
-}
-
-// TODO(shess): It would be nice to test mouse clicks and dragging,
-// but those are hard because they require a real |owner|.
-
-} // namespace
diff --git a/chrome/browser/cocoa/location_bar/instant_opt_in_controller.h b/chrome/browser/cocoa/location_bar/instant_opt_in_controller.h
deleted file mode 100644
index bf53b17..0000000
--- a/chrome/browser/cocoa/location_bar/instant_opt_in_controller.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_LOCATION_BAR_INSTANT_OPT_IN_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_LOCATION_BAR_INSTANT_OPT_IN_CONTROLLER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-class Profile;
-
-// This delegate receives callbacks from the InstantOptInController when the OK
-// and Cancel buttons are pushed.
-class InstantOptInControllerDelegate {
- public:
- virtual void UserPressedOptIn(bool opt_in) = 0;
-
- protected:
- virtual ~InstantOptInControllerDelegate() {}
-};
-
-// Manages an instant opt-in view, which is part of the omnibox popup.
-@interface InstantOptInController : NSViewController {
- @private
- InstantOptInControllerDelegate* delegate_; // weak
-
- // Needed in order to localize text and resize to fit.
- IBOutlet NSButton* okButton_;
- IBOutlet NSButton* cancelButton_;
- IBOutlet NSTextField* label_;
-}
-
-// Designated initializer.
-- (id)initWithDelegate:(InstantOptInControllerDelegate*)delegate;
-
-// Button actions.
-- (IBAction)ok:(id)sender;
-- (IBAction)cancel:(id)sender;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_LOCATION_BAR_INSTANT_OPT_IN_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/location_bar/instant_opt_in_controller.mm b/chrome/browser/cocoa/location_bar/instant_opt_in_controller.mm
deleted file mode 100644
index 181dc44..0000000
--- a/chrome/browser/cocoa/location_bar/instant_opt_in_controller.mm
+++ /dev/null
@@ -1,31 +0,0 @@
-// 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 "chrome/browser/cocoa/location_bar/instant_opt_in_controller.h"
-
-#include "base/mac_util.h"
-
-@implementation InstantOptInController
-
-- (id)initWithDelegate:(InstantOptInControllerDelegate*)delegate {
- if ((self = [super initWithNibName:@"InstantOptIn"
- bundle:mac_util::MainAppBundle()])) {
- delegate_ = delegate;
- }
- return self;
-}
-
-- (void)awakeFromNib {
- // TODO(rohitrao): Translate and resize strings.
-}
-
-- (IBAction)ok:(id)sender {
- delegate_->UserPressedOptIn(true);
-}
-
-- (IBAction)cancel:(id)sender {
- delegate_->UserPressedOptIn(false);
-}
-
-@end
diff --git a/chrome/browser/cocoa/location_bar/instant_opt_in_controller_unittest.mm b/chrome/browser/cocoa/location_bar/instant_opt_in_controller_unittest.mm
deleted file mode 100644
index 7c3e115..0000000
--- a/chrome/browser/cocoa/location_bar/instant_opt_in_controller_unittest.mm
+++ /dev/null
@@ -1,62 +0,0 @@
-// 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.
-
-#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/location_bar/instant_opt_in_controller.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-@interface InstantOptInController (ExposedForTesting)
-- (NSButton*)okButton;
-- (NSButton*)cancelButton;
-@end
-
-@implementation InstantOptInController (ExposedForTesting)
-- (NSButton*)okButton {
- return okButton_;
-}
-
-- (NSButton*)cancelButton {
- return cancelButton_;
-}
-@end
-
-
-namespace {
-
-class MockDelegate : public InstantOptInControllerDelegate {
- public:
- MOCK_METHOD1(UserPressedOptIn, void(bool opt_in));
-};
-
-class InstantOptInControllerTest : public CocoaTest {
- public:
- void SetUp() {
- CocoaTest::SetUp();
-
- controller_.reset(
- [[InstantOptInController alloc] initWithDelegate:&delegate_]);
-
- NSView* parent = [test_window() contentView];
- [parent addSubview:[controller_ view]];
- }
-
- MockDelegate delegate_;
- scoped_nsobject<InstantOptInController> controller_;
-};
-
-TEST_F(InstantOptInControllerTest, OkButtonCallback) {
- EXPECT_CALL(delegate_, UserPressedOptIn(true));
- [[controller_ okButton] performClick:nil];
-}
-
-TEST_F(InstantOptInControllerTest, CancelButtonCallback) {
- EXPECT_CALL(delegate_, UserPressedOptIn(false));
- [[controller_ cancelButton] performClick:nil];
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/location_bar/instant_opt_in_view.h b/chrome/browser/cocoa/location_bar/instant_opt_in_view.h
deleted file mode 100644
index 9e8c722..0000000
--- a/chrome/browser/cocoa/location_bar/instant_opt_in_view.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_LOCATION_BAR_INSTANT_OPT_IN_VIEW_H_
-#define CHROME_BROWSER_COCOA_LOCATION_BAR_INSTANT_OPT_IN_VIEW_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-// The instant opt in view that is embedded in the omnibox. Draws rounded
-// bottom corners and a horizontal gray line at the top.
-@interface InstantOptInView : NSView
-@end
-
-#endif // CHROME_BROWSER_COCOA_LOCATION_BAR_INSTANT_OPT_IN_VIEW_H_
diff --git a/chrome/browser/cocoa/location_bar/instant_opt_in_view.mm b/chrome/browser/cocoa/location_bar/instant_opt_in_view.mm
deleted file mode 100644
index 4b5e9ac..0000000
--- a/chrome/browser/cocoa/location_bar/instant_opt_in_view.mm
+++ /dev/null
@@ -1,54 +0,0 @@
-// 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.
-
-#include <algorithm>
-
-#import "chrome/browser/cocoa/location_bar/instant_opt_in_view.h"
-#import "third_party/GTM/AppKit/GTMNSBezierPath+RoundRect.h"
-
-namespace {
-// How to round off the popup's corners. Goal is to match star and go
-// buttons.
-const CGFloat kPopupRoundingRadius = 3.5;
-
-// How far from the top of the view to place the horizontal line.
-const CGFloat kHorizontalLineTopOffset = 2;
-
-// How far from the sides to inset the horizontal line.
-const CGFloat kHorizontalLineInset = 2;
-}
-
-@implementation InstantOptInView
-
-- (void)drawRect:(NSRect)rect {
- // Round off the bottom corners only.
- NSBezierPath* path =
- [NSBezierPath gtm_bezierPathWithRoundRect:[self bounds]
- topLeftCornerRadius:0
- topRightCornerRadius:0
- bottomLeftCornerRadius:kPopupRoundingRadius
- bottomRightCornerRadius:kPopupRoundingRadius];
-
- [NSGraphicsContext saveGraphicsState];
- [path addClip];
-
- // Background is white.
- [[NSColor whiteColor] set];
- NSRectFill(rect);
-
- // Draw a horizontal line 2 px down from the top of the view, inset at the
- // sides by 2 px.
- CGFloat lineY = NSMaxY([self bounds]) - kHorizontalLineTopOffset;
- CGFloat minX = std::min(NSMinX([self bounds]) + kHorizontalLineInset,
- NSMaxX([self bounds]));
- CGFloat maxX = std::max(NSMaxX([self bounds]) - kHorizontalLineInset,
- NSMinX([self bounds]));
-
- [[NSColor lightGrayColor] set];
- NSRectFill(NSMakeRect(minX, lineY, maxX - minX, 1));
-
- [NSGraphicsContext restoreGraphicsState];
-}
-
-@end
diff --git a/chrome/browser/cocoa/location_bar/instant_opt_in_view_unittest.mm b/chrome/browser/cocoa/location_bar/instant_opt_in_view_unittest.mm
deleted file mode 100644
index a8e60e9..0000000
--- a/chrome/browser/cocoa/location_bar/instant_opt_in_view_unittest.mm
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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 "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/location_bar/instant_opt_in_view.h"
-
-namespace {
-
-class InstantOptInViewTest : public CocoaTest {
- public:
- InstantOptInViewTest() {
- NSRect content_frame = [[test_window() contentView] frame];
- scoped_nsobject<InstantOptInView> view(
- [[InstantOptInView alloc] initWithFrame:content_frame]);
- view_ = view.get();
- [[test_window() contentView] addSubview:view_];
- }
-
- InstantOptInView* view_; // Weak. Owned by the view hierarchy.
-};
-
-// Tests display, add/remove.
-TEST_VIEW(InstantOptInViewTest, view_);
-
-} // namespace
diff --git a/chrome/browser/cocoa/location_bar/keyword_hint_decoration.h b/chrome/browser/cocoa/location_bar/keyword_hint_decoration.h
deleted file mode 100644
index d5972a7..0000000
--- a/chrome/browser/cocoa/location_bar/keyword_hint_decoration.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_LOCATION_BAR_KEYWORD_HINT_DECORATION_H_
-#define CHROME_BROWSER_COCOA_LOCATION_BAR_KEYWORD_HINT_DECORATION_H_
-#pragma once
-
-#include <string>
-
-#import "chrome/browser/cocoa/location_bar/location_bar_decoration.h"
-
-#import "base/scoped_nsobject.h"
-
-// Draws the keyword hint, "Press [tab] to search <site>".
-
-class KeywordHintDecoration : public LocationBarDecoration {
- public:
- KeywordHintDecoration(NSFont* font);
- virtual ~KeywordHintDecoration();
-
- // Calculates the message to display and where to place the [tab]
- // image.
- void SetKeyword(const std::wstring& keyword, bool is_extension_keyword);
-
- // Implement |LocationBarDecoration|.
- virtual void DrawInFrame(NSRect frame, NSView* control_view);
- virtual CGFloat GetWidthForSpace(CGFloat width);
-
- private:
- // Fetch and cache the [tab] image.
- NSImage* GetHintImage();
-
- // Attributes for drawing the hint string, such as font and color.
- scoped_nsobject<NSDictionary> attributes_;
-
- // Cache for the [tab] image.
- scoped_nsobject<NSImage> hint_image_;
-
- // The text to display to the left and right of the hint image.
- scoped_nsobject<NSString> hint_prefix_;
- scoped_nsobject<NSString> hint_suffix_;
-
- DISALLOW_COPY_AND_ASSIGN(KeywordHintDecoration);
-};
-
-#endif // CHROME_BROWSER_COCOA_LOCATION_BAR_KEYWORD_HINT_DECORATION_H_
diff --git a/chrome/browser/cocoa/location_bar/keyword_hint_decoration.mm b/chrome/browser/cocoa/location_bar/keyword_hint_decoration.mm
deleted file mode 100644
index 885b3dd..0000000
--- a/chrome/browser/cocoa/location_bar/keyword_hint_decoration.mm
+++ /dev/null
@@ -1,160 +0,0 @@
-// 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.
-
-#include <cmath>
-
-#import "chrome/browser/cocoa/location_bar/keyword_hint_decoration.h"
-
-#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
-#include "base/logging.h"
-#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
-#import "chrome/browser/cocoa/image_utils.h"
-#include "grit/theme_resources.h"
-#include "grit/generated_resources.h"
-#include "skia/ext/skia_utils_mac.h"
-
-namespace {
-
-// How far to inset the hint text area from sides.
-const CGFloat kHintTextYInset = 4.0;
-
-// How far to inset the hint image from sides. Lines baseline of text
-// in image with baseline of prefix and suffix.
-const CGFloat kHintImageYInset = 4.0;
-
-// Extra padding right and left of the image.
-const CGFloat kHintImagePadding = 1.0;
-
-// Maxmimum of the available space to allow the hint to take over.
-// Should leave enough so that the user has space to edit things.
-const CGFloat kHintAvailableRatio = 2.0 / 3.0;
-
-// Helper to convert |s| to an |NSString|, trimming whitespace at
-// ends.
-NSString* TrimAndConvert(const std::wstring& s) {
- std::wstring output;
- TrimWhitespace(s, TRIM_ALL, &output);
- return base::SysWideToNSString(output);
-}
-
-} // namespace
-
-KeywordHintDecoration::KeywordHintDecoration(NSFont* font) {
- NSColor* text_color = [NSColor lightGrayColor];
- NSDictionary* attributes =
- [NSDictionary dictionaryWithObjectsAndKeys:
- font, NSFontAttributeName,
- text_color, NSForegroundColorAttributeName,
- nil];
- attributes_.reset([attributes retain]);
-}
-
-KeywordHintDecoration::~KeywordHintDecoration() {
-}
-
-NSImage* KeywordHintDecoration::GetHintImage() {
- if (!hint_image_) {
- SkBitmap* skiaBitmap = ResourceBundle::GetSharedInstance().
- GetBitmapNamed(IDR_LOCATION_BAR_KEYWORD_HINT_TAB);
- if (skiaBitmap)
- hint_image_.reset([gfx::SkBitmapToNSImage(*skiaBitmap) retain]);
- }
- return hint_image_;
-}
-
-void KeywordHintDecoration::SetKeyword(const std::wstring& short_name,
- bool is_extension_keyword) {
- // KEYWORD_HINT is a message like "Press [tab] to search <site>".
- // [tab] is a parameter to be replaced by an image. "<site>" is
- // derived from |short_name|.
- std::vector<size_t> content_param_offsets;
- int message_id = is_extension_keyword ?
- IDS_OMNIBOX_EXTENSION_KEYWORD_HINT : IDS_OMNIBOX_KEYWORD_HINT;
- const std::wstring keyword_hint(
- l10n_util::GetStringF(message_id,
- std::wstring(), short_name,
- &content_param_offsets));
-
- // Should always be 2 offsets, see the comment in
- // location_bar_view.cc after IDS_OMNIBOX_KEYWORD_HINT fetch.
- DCHECK_EQ(content_param_offsets.size(), 2U);
-
- // Where to put the [tab] image.
- const size_t split = content_param_offsets.front();
-
- // Trim the spaces from the edges (there is space in the image) and
- // convert to |NSString|.
- hint_prefix_.reset([TrimAndConvert(keyword_hint.substr(0, split)) retain]);
- hint_suffix_.reset([TrimAndConvert(keyword_hint.substr(split)) retain]);
-}
-
-CGFloat KeywordHintDecoration::GetWidthForSpace(CGFloat width) {
- NSImage* image = GetHintImage();
- const CGFloat image_width = image ? [image size].width : 0.0;
-
- // AFAICT, on Windows the choices are "everything" if it fits, then
- // "image only" if it fits.
-
- // Entirely too small to fit, omit.
- if (width < image_width)
- return kOmittedWidth;
-
- // Show the full hint if it won't take up too much space. The image
- // needs to be placed at a pixel boundary, round the text widths so
- // that any partially-drawn pixels don't look too close (or too
- // far).
- CGFloat full_width =
- std::floor([hint_prefix_ sizeWithAttributes:attributes_].width + 0.5) +
- kHintImagePadding + image_width + kHintImagePadding +
- std::floor([hint_suffix_ sizeWithAttributes:attributes_].width + 0.5);
- if (full_width <= width * kHintAvailableRatio)
- return full_width;
-
- return image_width;
-}
-
-void KeywordHintDecoration::DrawInFrame(NSRect frame, NSView* control_view) {
- NSImage* image = GetHintImage();
- const CGFloat image_width = image ? [image size].width : 0.0;
-
- const bool draw_full = NSWidth(frame) > image_width;
-
- if (draw_full) {
- NSRect prefix_rect = NSInsetRect(frame, 0.0, kHintTextYInset);
- const CGFloat prefix_width =
- [hint_prefix_ sizeWithAttributes:attributes_].width;
- DCHECK_GE(NSWidth(prefix_rect), prefix_width);
- [hint_prefix_ drawInRect:prefix_rect withAttributes:attributes_];
-
- // The image should be drawn at a pixel boundary, round the prefix
- // so that partial pixels aren't oddly close (or distant).
- frame.origin.x += std::floor(prefix_width + 0.5) + kHintImagePadding;
- frame.size.width -= std::floor(prefix_width + 0.5) + kHintImagePadding;
- }
-
- NSRect image_rect = NSInsetRect(frame, 0.0, kHintImageYInset);
- image_rect.size = [image size];
- [image drawInRect:image_rect
- fromRect:NSZeroRect // Entire image
- operation:NSCompositeSourceOver
- fraction:1.0
- neverFlipped:YES];
- frame.origin.x += NSWidth(image_rect);
- frame.size.width -= NSWidth(image_rect);
-
- if (draw_full) {
- NSRect suffix_rect = NSInsetRect(frame, 0.0, kHintTextYInset);
- const CGFloat suffix_width =
- [hint_suffix_ sizeWithAttributes:attributes_].width;
-
- // Right-justify the text within the remaining space, so it
- // doesn't get too close to the image relative to a following
- // decoration.
- suffix_rect.origin.x = NSMaxX(suffix_rect) - suffix_width;
- DCHECK_GE(NSWidth(suffix_rect), suffix_width);
- [hint_suffix_ drawInRect:suffix_rect withAttributes:attributes_];
- }
-}
diff --git a/chrome/browser/cocoa/location_bar/keyword_hint_decoration_unittest.mm b/chrome/browser/cocoa/location_bar/keyword_hint_decoration_unittest.mm
deleted file mode 100644
index 1ee8c8e..0000000
--- a/chrome/browser/cocoa/location_bar/keyword_hint_decoration_unittest.mm
+++ /dev/null
@@ -1,57 +0,0 @@
-// 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>
-
-#import "chrome/browser/cocoa/location_bar/keyword_hint_decoration.h"
-
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-class KeywordHintDecorationTest : public CocoaTest {
- public:
- KeywordHintDecorationTest()
- : decoration_(NULL) {
- }
-
- KeywordHintDecoration decoration_;
-};
-
-TEST_F(KeywordHintDecorationTest, GetWidthForSpace) {
- decoration_.SetVisible(true);
- decoration_.SetKeyword(std::wstring(L"Google"), false);
-
- const CGFloat kVeryWide = 1000.0;
- const CGFloat kFairlyWide = 100.0; // Estimate for full hint space.
- const CGFloat kEditingSpace = 50.0;
-
- // Wider than the [tab] image when we have lots of space.
- EXPECT_NE(decoration_.GetWidthForSpace(kVeryWide),
- LocationBarDecoration::kOmittedWidth);
- EXPECT_GE(decoration_.GetWidthForSpace(kVeryWide), kFairlyWide);
-
- // When there's not enough space for the text, trims to something
- // narrower.
- const CGFloat full_width = decoration_.GetWidthForSpace(kVeryWide);
- const CGFloat not_wide_enough = full_width - 10.0;
- EXPECT_NE(decoration_.GetWidthForSpace(not_wide_enough),
- LocationBarDecoration::kOmittedWidth);
- EXPECT_LT(decoration_.GetWidthForSpace(not_wide_enough), full_width);
-
- // Even trims when there's enough space for everything, but it would
- // eat "too much".
- EXPECT_NE(decoration_.GetWidthForSpace(full_width + kEditingSpace),
- LocationBarDecoration::kOmittedWidth);
- EXPECT_LT(decoration_.GetWidthForSpace(full_width + kEditingSpace),
- full_width);
-
- // Omitted when not wide enough to fit even the image.
- const CGFloat image_width = decoration_.GetWidthForSpace(not_wide_enough);
- EXPECT_EQ(decoration_.GetWidthForSpace(image_width - 1.0),
- LocationBarDecoration::kOmittedWidth);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/location_bar/location_bar_decoration.h b/chrome/browser/cocoa/location_bar/location_bar_decoration.h
deleted file mode 100644
index 58b6f92..0000000
--- a/chrome/browser/cocoa/location_bar/location_bar_decoration.h
+++ /dev/null
@@ -1,89 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_LOCATION_BAR_LOCATION_BAR_DECORATION_H_
-#define CHROME_BROWSER_COCOA_LOCATION_BAR_LOCATION_BAR_DECORATION_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/basictypes.h"
-
-// Base class for decorations at the left and right of the location
-// bar. For instance, the location icon.
-
-// |LocationBarDecoration| and subclasses should approximately
-// parallel the classes provided under views/location_bar/. The term
-// "decoration" is used because "view" has strong connotations in
-// Cocoa, and while these are view-like, they aren't views at all.
-// Decorations are more like Cocoa cells, except implemented in C++ to
-// allow more similarity to the other platform implementations.
-
-class LocationBarDecoration {
- public:
- LocationBarDecoration()
- : visible_(false) {
- }
- virtual ~LocationBarDecoration() {}
-
- // Determines whether the decoration is visible.
- virtual bool IsVisible() const {
- return visible_;
- }
- virtual void SetVisible(bool visible) {
- visible_ = visible;
- }
-
- // Decorations can change their size to fit the available space.
- // Returns the width the decoration will use in the space allotted,
- // or |kOmittedWidth| if it should be omitted.
- virtual CGFloat GetWidthForSpace(CGFloat width);
-
- // Draw the decoration in the frame provided. The frame will be
- // generated from an earlier call to |GetWidthForSpace()|.
- virtual void DrawInFrame(NSRect frame, NSView* control_view);
-
- // Returns the tooltip for this decoration, return |nil| for no tooltip.
- virtual NSString* GetToolTip() { return nil; }
-
- // Decorations which do not accept mouse events are treated like the
- // field's background for purposes of selecting text. When such
- // decorations are adjacent to the text area, they will show the
- // I-beam cursor. Decorations which do accept mouse events will get
- // an arrow cursor when the mouse is over them.
- virtual bool AcceptsMousePress() { return false; }
-
- // Determine if the item can act as a drag source.
- virtual bool IsDraggable() { return false; }
-
- // The image to drag.
- virtual NSImage* GetDragImage() { return nil; }
-
- // Return the place within the decoration's frame where the
- // |GetDragImage()| comes from. This is used to make sure the image
- // appears correctly under the mouse while dragging. |frame|
- // matches the frame passed to |DrawInFrame()|.
- virtual NSRect GetDragImageFrame(NSRect frame) { return NSZeroRect; }
-
- // The pasteboard to drag.
- virtual NSPasteboard* GetDragPasteboard() { return nil; }
-
- // Called on mouse down. Return |false| to indicate that the press
- // was not processed and should be handled by the cell.
- virtual bool OnMousePressed(NSRect frame) { return false; }
-
- // Called to get the right-click menu, return |nil| for no menu.
- virtual NSMenu* GetMenu() { return nil; }
-
- // Width returned by |GetWidthForSpace()| when the item should be
- // omitted for this width;
- static const CGFloat kOmittedWidth;
-
- private:
- bool visible_;
-
- DISALLOW_COPY_AND_ASSIGN(LocationBarDecoration);
-};
-
-#endif // CHROME_BROWSER_COCOA_LOCATION_BAR_LOCATION_BAR_DECORATION_H_
diff --git a/chrome/browser/cocoa/location_bar/location_bar_decoration.mm b/chrome/browser/cocoa/location_bar/location_bar_decoration.mm
deleted file mode 100644
index 6d69740..0000000
--- a/chrome/browser/cocoa/location_bar/location_bar_decoration.mm
+++ /dev/null
@@ -1,18 +0,0 @@
-// 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 "chrome/browser/cocoa/location_bar/location_bar_decoration.h"
-
-#include "base/logging.h"
-
-const CGFloat LocationBarDecoration::kOmittedWidth = 0.0;
-
-CGFloat LocationBarDecoration::GetWidthForSpace(CGFloat width) {
- NOTREACHED();
- return kOmittedWidth;
-}
-
-void LocationBarDecoration::DrawInFrame(NSRect frame, NSView* control_view) {
- NOTREACHED();
-}
diff --git a/chrome/browser/cocoa/location_bar/location_bar_view_mac.h b/chrome/browser/cocoa/location_bar/location_bar_view_mac.h
deleted file mode 100644
index 91993f6..0000000
--- a/chrome/browser/cocoa/location_bar/location_bar_view_mac.h
+++ /dev/null
@@ -1,237 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_LOCATION_BAR_VIEW_MAC_H_
-#define CHROME_BROWSER_COCOA_LOCATION_BAR_VIEW_MAC_H_
-#pragma once
-
-#include <string>
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-#include "base/scoped_vector.h"
-#include "chrome/browser/autocomplete/autocomplete_edit.h"
-#include "chrome/browser/autocomplete/autocomplete_edit_view_mac.h"
-#include "chrome/browser/extensions/image_loading_tracker.h"
-#include "chrome/browser/first_run/first_run.h"
-#include "chrome/browser/location_bar.h"
-#include "chrome/browser/toolbar_model.h"
-#include "chrome/common/content_settings_types.h"
-
-@class AutocompleteTextField;
-class CommandUpdater;
-class ContentSettingDecoration;
-class ContentSettingImageModel;
-class EVBubbleDecoration;
-@class ExtensionPopupController;
-class KeywordHintDecoration;
-class LocationIconDecoration;
-class PageActionDecoration;
-class Profile;
-class SelectedKeywordDecoration;
-class SkBitmap;
-class StarDecoration;
-class ToolbarModel;
-
-// A C++ bridge class that represents the location bar UI element to
-// the portable code. Wires up an AutocompleteEditViewMac instance to
-// the location bar text field, which handles most of the work.
-
-class LocationBarViewMac : public AutocompleteEditController,
- public LocationBar,
- public LocationBarTesting,
- public NotificationObserver {
- public:
- LocationBarViewMac(AutocompleteTextField* field,
- CommandUpdater* command_updater,
- ToolbarModel* toolbar_model,
- Profile* profile,
- Browser* browser);
- virtual ~LocationBarViewMac();
-
- // Overridden from LocationBar:
- virtual void ShowFirstRunBubble(FirstRun::BubbleType bubble_type);
- virtual void SetSuggestedText(const string16& text);
- virtual std::wstring GetInputString() const;
- virtual WindowOpenDisposition GetWindowOpenDisposition() const;
- virtual PageTransition::Type GetPageTransition() const;
- virtual void AcceptInput();
- virtual void FocusLocation(bool select_all);
- virtual void FocusSearch();
- virtual void UpdateContentSettingsIcons();
- virtual void UpdatePageActions();
- virtual void InvalidatePageActions();
- virtual void SaveStateToContents(TabContents* contents);
- virtual void Revert();
- virtual const AutocompleteEditView* location_entry() const {
- return edit_view_.get();
- }
- virtual AutocompleteEditView* location_entry() {
- return edit_view_.get();
- }
- virtual LocationBarTesting* GetLocationBarForTesting() { return this; }
-
- // Overridden from LocationBarTesting:
- virtual int PageActionCount();
- virtual int PageActionVisibleCount();
- virtual ExtensionAction* GetPageAction(size_t index);
- virtual ExtensionAction* GetVisiblePageAction(size_t index);
- virtual void TestPageActionPressed(size_t index);
-
- // Set/Get the editable state of the field.
- void SetEditable(bool editable);
- bool IsEditable();
-
- // Set the starred state of the bookmark star.
- void SetStarred(bool starred);
-
- // Get the point on the star for the bookmark bubble to aim at.
- NSPoint GetBookmarkBubblePoint() const;
-
- // Get the point in the security icon at which the page info bubble aims.
- NSPoint GetPageInfoBubblePoint() const;
-
- // Get the point in the omnibox at which the first run bubble aims.
- NSPoint GetFirstRunBubblePoint() const;
-
- // Updates the location bar. Resets the bar's permanent text and
- // security style, and if |should_restore_state| is true, restores
- // saved state from the tab (for tab switching).
- void Update(const TabContents* tab, bool should_restore_state);
-
- // Layout the various decorations which live in the field.
- void Layout();
-
- // Returns the current TabContents.
- TabContents* GetTabContents() const;
-
- // Sets preview_enabled_ for the PageActionImageView associated with this
- // |page_action|. If |preview_enabled|, the location bar will display the
- // PageAction icon even if it has not been activated by the extension.
- // This is used by the ExtensionInstalledBubble to preview what the icon
- // will look like for the user upon installation of the extension.
- void SetPreviewEnabledPageAction(ExtensionAction* page_action,
- bool preview_enabled);
-
- // Return |page_action|'s info-bubble point in window coordinates.
- // This function should always be called with a visible page action.
- // If |page_action| is not a page action or not visible, NOTREACHED()
- // is called and this function returns |NSZeroPoint|.
- NSPoint GetPageActionBubblePoint(ExtensionAction* page_action);
-
- // Get the blocked-popup content setting's frame in window
- // coordinates. Used by the blocked-popup animation. Returns
- // |NSZeroRect| if the relevant content setting decoration is not
- // visible.
- NSRect GetBlockedPopupRect() const;
-
- // AutocompleteEditController implementation.
- virtual void OnAutocompleteWillClosePopup();
- virtual void OnAutocompleteLosingFocus(gfx::NativeView unused);
- virtual void OnAutocompleteWillAccept();
- virtual bool OnCommitSuggestedText(const std::wstring& typed_text);
- virtual void OnSetSuggestedSearchText(const string16& suggested_text);
- virtual void OnPopupBoundsChanged(const gfx::Rect& bounds);
- virtual void OnAutocompleteAccept(const GURL& url,
- WindowOpenDisposition disposition,
- PageTransition::Type transition,
- const GURL& alternate_nav_url);
- virtual void OnChanged();
- virtual void OnSelectionBoundsChanged();
- virtual void OnInputInProgress(bool in_progress);
- virtual void OnKillFocus();
- virtual void OnSetFocus();
- virtual SkBitmap GetFavIcon() const;
- virtual std::wstring GetTitle() const;
-
- NSImage* GetKeywordImage(const std::wstring& keyword);
-
- AutocompleteTextField* GetAutocompleteTextField() { return field_; }
-
-
- // Overridden from NotificationObserver.
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- private:
- // Posts |notification| to the default notification center.
- void PostNotification(NSString* notification);
-
- // Return the decoration for |page_action|.
- PageActionDecoration* GetPageActionDecoration(ExtensionAction* page_action);
-
- // Clear the page-action decorations.
- void DeletePageActionDecorations();
-
- // Re-generate the page-action decorations from the profile's
- // extension service.
- void RefreshPageActionDecorations();
-
- // Updates visibility of the content settings icons based on the current
- // tab contents state.
- bool RefreshContentSettingsDecorations();
-
- void ShowFirstRunBubbleInternal(FirstRun::BubbleType bubble_type);
-
- scoped_ptr<AutocompleteEditViewMac> edit_view_;
-
- CommandUpdater* command_updater_; // Weak, owned by Browser.
-
- AutocompleteTextField* field_; // owned by tab controller
-
- // When we get an OnAutocompleteAccept notification from the autocomplete
- // edit, we save the input string so we can give it back to the browser on
- // the LocationBar interface via GetInputString().
- std::wstring location_input_;
-
- // The user's desired disposition for how their input should be opened.
- WindowOpenDisposition disposition_;
-
- // A decoration that shows an icon to the left of the address.
- scoped_ptr<LocationIconDecoration> location_icon_decoration_;
-
- // A decoration that shows the keyword-search bubble on the left.
- scoped_ptr<SelectedKeywordDecoration> selected_keyword_decoration_;
-
- // A decoration that shows a lock icon and ev-cert label in a bubble
- // on the left.
- scoped_ptr<EVBubbleDecoration> ev_bubble_decoration_;
-
- // Bookmark star right of page actions.
- scoped_ptr<StarDecoration> star_decoration_;
-
- // Any installed Page Actions.
- ScopedVector<PageActionDecoration> page_action_decorations_;
-
- // The content blocked decorations.
- ScopedVector<ContentSettingDecoration> content_setting_decorations_;
-
- // Keyword hint decoration displayed on the right-hand side.
- scoped_ptr<KeywordHintDecoration> keyword_hint_decoration_;
-
- Profile* profile_;
-
- Browser* browser_;
-
- ToolbarModel* toolbar_model_; // Weak, owned by Browser.
-
- // Whether or not to update the instant preview.
- bool update_instant_;
-
- // The transition type to use for the navigation.
- PageTransition::Type transition_;
-
- // Used to register for notifications received by NotificationObserver.
- NotificationRegistrar registrar_;
-
- // Used to schedule a task for the first run info bubble.
- ScopedRunnableMethodFactory<LocationBarViewMac> first_run_bubble_;
-
- DISALLOW_COPY_AND_ASSIGN(LocationBarViewMac);
-};
-
-#endif // CHROME_BROWSER_COCOA_LOCATION_BAR_VIEW_MAC_H_
diff --git a/chrome/browser/cocoa/location_bar/location_bar_view_mac.mm b/chrome/browser/cocoa/location_bar/location_bar_view_mac.mm
deleted file mode 100644
index bac6ff5..0000000
--- a/chrome/browser/cocoa/location_bar/location_bar_view_mac.mm
+++ /dev/null
@@ -1,692 +0,0 @@
-// 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 "chrome/browser/cocoa/location_bar/location_bar_view_mac.h"
-
-#include "app/l10n_util_mac.h"
-#include "app/resource_bundle.h"
-#include "base/nsimage_cache_mac.h"
-#include "base/stl_util-inl.h"
-#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/alternate_nav_url_fetcher.h"
-#import "chrome/browser/app_controller_mac.h"
-#import "chrome/browser/autocomplete/autocomplete_edit_view_mac.h"
-#import "chrome/browser/autocomplete/autocomplete_popup_model.h"
-#include "chrome/browser/browser_list.h"
-#import "chrome/browser/cocoa/content_setting_bubble_cocoa.h"
-#include "chrome/browser/cocoa/event_utils.h"
-#import "chrome/browser/cocoa/extensions/extension_action_context_menu.h"
-#import "chrome/browser/cocoa/extensions/extension_popup_controller.h"
-#import "chrome/browser/cocoa/first_run_bubble_controller.h"
-#import "chrome/browser/cocoa/location_bar/autocomplete_text_field.h"
-#import "chrome/browser/cocoa/location_bar/autocomplete_text_field_cell.h"
-#import "chrome/browser/cocoa/location_bar/content_setting_decoration.h"
-#import "chrome/browser/cocoa/location_bar/ev_bubble_decoration.h"
-#import "chrome/browser/cocoa/location_bar/keyword_hint_decoration.h"
-#import "chrome/browser/cocoa/location_bar/location_icon_decoration.h"
-#import "chrome/browser/cocoa/location_bar/page_action_decoration.h"
-#import "chrome/browser/cocoa/location_bar/selected_keyword_decoration.h"
-#import "chrome/browser/cocoa/location_bar/star_decoration.h"
-#include "chrome/browser/command_updater.h"
-#include "chrome/browser/content_setting_image_model.h"
-#include "chrome/browser/content_setting_bubble_model.h"
-#include "chrome/browser/defaults.h"
-#include "chrome/browser/extensions/extension_browser_event_router.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/extensions/extension_tabs_module.h"
-#include "chrome/browser/instant/instant_controller.h"
-#include "chrome/browser/location_bar_util.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_model.h"
-#include "chrome/browser/tab_contents/navigation_entry.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_action.h"
-#include "chrome/common/extensions/extension_resource.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/pref_names.h"
-#include "net/base/net_util.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#include "skia/ext/skia_utils_mac.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-namespace {
-
-// Vertical space between the bottom edge of the location_bar and the first run
-// bubble arrow point.
-const static int kFirstRunBubbleYOffset = 1;
-
-}
-
-// TODO(shess): This code is mostly copied from the gtk
-// implementation. Make sure it's all appropriate and flesh it out.
-
-LocationBarViewMac::LocationBarViewMac(
- AutocompleteTextField* field,
- CommandUpdater* command_updater,
- ToolbarModel* toolbar_model,
- Profile* profile,
- Browser* browser)
- : edit_view_(new AutocompleteEditViewMac(this, toolbar_model, profile,
- command_updater, field)),
- command_updater_(command_updater),
- field_(field),
- disposition_(CURRENT_TAB),
- location_icon_decoration_(new LocationIconDecoration(this)),
- selected_keyword_decoration_(
- new SelectedKeywordDecoration(
- AutocompleteEditViewMac::GetFieldFont())),
- ev_bubble_decoration_(
- new EVBubbleDecoration(location_icon_decoration_.get(),
- AutocompleteEditViewMac::GetFieldFont())),
- star_decoration_(new StarDecoration(command_updater)),
- keyword_hint_decoration_(
- new KeywordHintDecoration(AutocompleteEditViewMac::GetFieldFont())),
- profile_(profile),
- browser_(browser),
- toolbar_model_(toolbar_model),
- update_instant_(true),
- transition_(PageTransition::TYPED),
- first_run_bubble_(this) {
- for (size_t i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
- DCHECK_EQ(i, content_setting_decorations_.size());
- ContentSettingsType type = static_cast<ContentSettingsType>(i);
- content_setting_decorations_.push_back(
- new ContentSettingDecoration(type, this, profile_));
- }
-
- registrar_.Add(this,
- NotificationType::EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED,
- NotificationService::AllSources());
-}
-
-LocationBarViewMac::~LocationBarViewMac() {
- // Disconnect from cell in case it outlives us.
- [[field_ cell] clearDecorations];
-}
-
-void LocationBarViewMac::ShowFirstRunBubble(FirstRun::BubbleType bubble_type) {
- // We need the browser window to be shown before we can show the bubble, but
- // we get called before that's happened.
- Task* task = first_run_bubble_.NewRunnableMethod(
- &LocationBarViewMac::ShowFirstRunBubbleInternal, bubble_type);
- MessageLoop::current()->PostTask(FROM_HERE, task);
-}
-
-void LocationBarViewMac::ShowFirstRunBubbleInternal(
- FirstRun::BubbleType bubble_type) {
- if (!field_ || ![field_ window])
- return;
-
- // The first run bubble's left edge should line up with the left edge of the
- // omnibox. This is different from other bubbles, which line up at a point
- // set by their top arrow. Because the BaseBubbleController adjusts the
- // window origin left to account for the arrow spacing, the first run bubble
- // moves the window origin right by this spacing, so that the
- // BaseBubbleController will move it back to the correct position.
- const NSPoint kOffset = NSMakePoint(
- info_bubble::kBubbleArrowXOffset + info_bubble::kBubbleArrowWidth/2.0,
- kFirstRunBubbleYOffset);
- [FirstRunBubbleController showForView:field_ offset:kOffset profile:profile_];
-}
-
-std::wstring LocationBarViewMac::GetInputString() const {
- return location_input_;
-}
-
-void LocationBarViewMac::SetSuggestedText(const string16& text) {
- edit_view_->SetSuggestText(
- edit_view_->model()->UseVerbatimInstant() ? string16() : text);
-}
-
-WindowOpenDisposition LocationBarViewMac::GetWindowOpenDisposition() const {
- return disposition_;
-}
-
-PageTransition::Type LocationBarViewMac::GetPageTransition() const {
- return transition_;
-}
-
-void LocationBarViewMac::AcceptInput() {
- WindowOpenDisposition disposition =
- event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
- edit_view_->model()->AcceptInput(disposition, false);
-}
-
-void LocationBarViewMac::FocusLocation(bool select_all) {
- edit_view_->FocusLocation(select_all);
-}
-
-void LocationBarViewMac::FocusSearch() {
- edit_view_->SetForcedQuery();
-}
-
-void LocationBarViewMac::UpdateContentSettingsIcons() {
- if (RefreshContentSettingsDecorations()) {
- [field_ updateCursorAndToolTipRects];
- [field_ setNeedsDisplay:YES];
- }
-}
-
-void LocationBarViewMac::UpdatePageActions() {
- size_t count_before = page_action_decorations_.size();
- RefreshPageActionDecorations();
- Layout();
- if (page_action_decorations_.size() != count_before) {
- NotificationService::current()->Notify(
- NotificationType::EXTENSION_PAGE_ACTION_COUNT_CHANGED,
- Source<LocationBar>(this),
- NotificationService::NoDetails());
- }
-}
-
-void LocationBarViewMac::InvalidatePageActions() {
- size_t count_before = page_action_decorations_.size();
- DeletePageActionDecorations();
- Layout();
- if (page_action_decorations_.size() != count_before) {
- NotificationService::current()->Notify(
- NotificationType::EXTENSION_PAGE_ACTION_COUNT_CHANGED,
- Source<LocationBar>(this),
- NotificationService::NoDetails());
- }
-}
-
-void LocationBarViewMac::SaveStateToContents(TabContents* contents) {
- // TODO(shess): Why SaveStateToContents vs SaveStateToTab?
- edit_view_->SaveStateToTab(contents);
-}
-
-void LocationBarViewMac::Update(const TabContents* contents,
- bool should_restore_state) {
- bool star_enabled = browser_defaults::bookmarks_enabled &&
- [field_ isEditable] && !toolbar_model_->input_in_progress();
- command_updater_->UpdateCommandEnabled(IDC_BOOKMARK_PAGE, star_enabled);
- star_decoration_->SetVisible(star_enabled);
- RefreshPageActionDecorations();
- RefreshContentSettingsDecorations();
- // AutocompleteEditView restores state if the tab is non-NULL.
- edit_view_->Update(should_restore_state ? contents : NULL);
- OnChanged();
-}
-
-void LocationBarViewMac::OnAutocompleteWillClosePopup() {
- if (!update_instant_)
- return;
-
- InstantController* controller = browser_->instant();
- if (controller && !controller->commit_on_mouse_up())
- controller->DestroyPreviewContents();
- SetSuggestedText(string16());
-}
-
-void LocationBarViewMac::OnAutocompleteLosingFocus(gfx::NativeView unused) {
- SetSuggestedText(string16());
-
- InstantController* instant = browser_->instant();
- if (!instant)
- return;
-
- // If |IsMouseDownFromActivate()| returns false, the RenderWidgetHostView did
- // not receive a mouseDown event. Therefore, we should destroy the preview.
- // Otherwise, the RWHV was clicked, so we commit the preview.
- if (!instant->is_displayable() || !instant->GetPreviewContents() ||
- !instant->IsMouseDownFromActivate()) {
- instant->DestroyPreviewContents();
- } else if (instant->IsShowingInstant()) {
- instant->SetCommitOnMouseUp();
- } else {
- instant->CommitCurrentPreview(INSTANT_COMMIT_FOCUS_LOST);
- }
-}
-
-void LocationBarViewMac::OnAutocompleteWillAccept() {
- update_instant_ = false;
-}
-
-bool LocationBarViewMac::OnCommitSuggestedText(const std::wstring& typed_text) {
- return edit_view_->CommitSuggestText();
-}
-
-void LocationBarViewMac::OnSetSuggestedSearchText(
- const string16& suggested_text) {
- SetSuggestedText(suggested_text);
-}
-
-void LocationBarViewMac::OnPopupBoundsChanged(const gfx::Rect& bounds) {
- InstantController* instant = browser_->instant();
- if (instant)
- instant->SetOmniboxBounds(bounds);
-}
-
-void LocationBarViewMac::OnAutocompleteAccept(const GURL& url,
- WindowOpenDisposition disposition,
- PageTransition::Type transition,
- const GURL& alternate_nav_url) {
- // WARNING: don't add an early return here. The calls after the if must
- // happen.
- if (url.is_valid()) {
- location_input_ = UTF8ToWide(url.spec());
- disposition_ = disposition;
- transition_ = transition;
-
- if (command_updater_) {
- if (!alternate_nav_url.is_valid()) {
- command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL);
- } else {
- AlternateNavURLFetcher* fetcher =
- new AlternateNavURLFetcher(alternate_nav_url);
- // The AlternateNavURLFetcher will listen for the pending navigation
- // notification that will be issued as a result of the "open URL." It
- // will automatically install itself into that navigation controller.
- command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL);
- if (fetcher->state() == AlternateNavURLFetcher::NOT_STARTED) {
- // I'm not sure this should be reachable, but I'm not also sure enough
- // that it shouldn't to stick in a NOTREACHED(). In any case, this is
- // harmless.
- delete fetcher;
- } else {
- // The navigation controller will delete the fetcher.
- }
- }
- }
- }
-
- if (browser_->instant())
- browser_->instant()->DestroyPreviewContents();
-
- update_instant_ = true;
-}
-
-void LocationBarViewMac::OnChanged() {
- // Update the location-bar icon.
- const int resource_id = edit_view_->GetIcon();
- NSImage* image = AutocompleteEditViewMac::ImageForResource(resource_id);
- location_icon_decoration_->SetImage(image);
- ev_bubble_decoration_->SetImage(image);
- Layout();
-
- InstantController* instant = browser_->instant();
- string16 suggested_text;
- if (update_instant_ && instant && GetTabContents()) {
- if (edit_view_->model()->user_input_in_progress() &&
- edit_view_->model()->popup_model()->IsOpen()) {
- instant->Update
- (browser_->GetSelectedTabContentsWrapper(),
- edit_view_->model()->CurrentMatch(),
- WideToUTF16(edit_view_->GetText()),
- edit_view_->model()->UseVerbatimInstant(),
- &suggested_text);
- if (!instant->MightSupportInstant()) {
- edit_view_->model()->FinalizeInstantQuery(std::wstring(),
- std::wstring());
- }
- } else {
- instant->DestroyPreviewContents();
- edit_view_->model()->FinalizeInstantQuery(std::wstring(),
- std::wstring());
- }
- }
-
- SetSuggestedText(suggested_text);
-}
-
-void LocationBarViewMac::OnSelectionBoundsChanged() {
- NOTIMPLEMENTED();
-}
-
-void LocationBarViewMac::OnInputInProgress(bool in_progress) {
- toolbar_model_->set_input_in_progress(in_progress);
- Update(NULL, false);
-}
-
-void LocationBarViewMac::OnSetFocus() {
- // Update the keyword and search hint states.
- OnChanged();
-}
-
-void LocationBarViewMac::OnKillFocus() {
- // Do nothing.
-}
-
-SkBitmap LocationBarViewMac::GetFavIcon() const {
- NOTIMPLEMENTED();
- return SkBitmap();
-}
-
-std::wstring LocationBarViewMac::GetTitle() const {
- NOTIMPLEMENTED();
- return std::wstring();
-}
-
-void LocationBarViewMac::Revert() {
- edit_view_->RevertAll();
-}
-
-// TODO(pamg): Change all these, here and for other platforms, to size_t.
-int LocationBarViewMac::PageActionCount() {
- return static_cast<int>(page_action_decorations_.size());
-}
-
-int LocationBarViewMac::PageActionVisibleCount() {
- int result = 0;
- for (size_t i = 0; i < page_action_decorations_.size(); ++i) {
- if (page_action_decorations_[i]->IsVisible())
- ++result;
- }
- return result;
-}
-
-TabContents* LocationBarViewMac::GetTabContents() const {
- return browser_->GetSelectedTabContents();
-}
-
-PageActionDecoration* LocationBarViewMac::GetPageActionDecoration(
- ExtensionAction* page_action) {
- DCHECK(page_action);
- for (size_t i = 0; i < page_action_decorations_.size(); ++i) {
- if (page_action_decorations_[i]->page_action() == page_action)
- return page_action_decorations_[i];
- }
- // If |page_action| is the browser action of an extension, no element in
- // |page_action_decorations_| will match.
- NOTREACHED();
- return NULL;
-}
-
-void LocationBarViewMac::SetPreviewEnabledPageAction(
- ExtensionAction* page_action, bool preview_enabled) {
- DCHECK(page_action);
- TabContents* contents = GetTabContents();
- if (!contents)
- return;
- RefreshPageActionDecorations();
- Layout();
-
- PageActionDecoration* decoration = GetPageActionDecoration(page_action);
- DCHECK(decoration);
- if (!decoration)
- return;
-
- decoration->set_preview_enabled(preview_enabled);
- decoration->UpdateVisibility(contents,
- GURL(WideToUTF8(toolbar_model_->GetText())));
-}
-
-NSPoint LocationBarViewMac::GetPageActionBubblePoint(
- ExtensionAction* page_action) {
- PageActionDecoration* decoration = GetPageActionDecoration(page_action);
- if (!decoration)
- return NSZeroPoint;
-
- AutocompleteTextFieldCell* cell = [field_ cell];
- NSRect frame = [cell frameForDecoration:decoration inFrame:[field_ bounds]];
- DCHECK(!NSIsEmptyRect(frame));
- if (NSIsEmptyRect(frame))
- return NSZeroPoint;
-
- NSPoint bubble_point = decoration->GetBubblePointInFrame(frame);
- return [field_ convertPoint:bubble_point toView:nil];
-}
-
-NSRect LocationBarViewMac::GetBlockedPopupRect() const {
- const size_t kPopupIndex = CONTENT_SETTINGS_TYPE_POPUPS;
- const LocationBarDecoration* decoration =
- content_setting_decorations_[kPopupIndex];
- if (!decoration || !decoration->IsVisible())
- return NSZeroRect;
-
- AutocompleteTextFieldCell* cell = [field_ cell];
- const NSRect frame = [cell frameForDecoration:decoration
- inFrame:[field_ bounds]];
- return [field_ convertRect:frame toView:nil];
-}
-
-ExtensionAction* LocationBarViewMac::GetPageAction(size_t index) {
- if (index < page_action_decorations_.size())
- return page_action_decorations_[index]->page_action();
- NOTREACHED();
- return NULL;
-}
-
-ExtensionAction* LocationBarViewMac::GetVisiblePageAction(size_t index) {
- size_t current = 0;
- for (size_t i = 0; i < page_action_decorations_.size(); ++i) {
- if (page_action_decorations_[i]->IsVisible()) {
- if (current == index)
- return page_action_decorations_[i]->page_action();
-
- ++current;
- }
- }
-
- NOTREACHED();
- return NULL;
-}
-
-void LocationBarViewMac::TestPageActionPressed(size_t index) {
- DCHECK_LT(index, page_action_decorations_.size());
- if (index < page_action_decorations_.size())
- page_action_decorations_[index]->OnMousePressed(NSZeroRect);
-}
-
-void LocationBarViewMac::SetEditable(bool editable) {
- [field_ setEditable:editable ? YES : NO];
- star_decoration_->SetVisible(browser_defaults::bookmarks_enabled &&
- editable && !toolbar_model_->input_in_progress());
- UpdatePageActions();
- Layout();
-}
-
-bool LocationBarViewMac::IsEditable() {
- return [field_ isEditable] ? true : false;
-}
-
-void LocationBarViewMac::SetStarred(bool starred) {
- star_decoration_->SetStarred(starred);
-
- // TODO(shess): The field-editor frame and cursor rects should not
- // change, here.
- [field_ updateCursorAndToolTipRects];
- [field_ resetFieldEditorFrameIfNeeded];
- [field_ setNeedsDisplay:YES];
-}
-
-NSPoint LocationBarViewMac::GetBookmarkBubblePoint() const {
- AutocompleteTextFieldCell* cell = [field_ cell];
- const NSRect frame = [cell frameForDecoration:star_decoration_.get()
- inFrame:[field_ bounds]];
- const NSPoint point = star_decoration_->GetBubblePointInFrame(frame);
- return [field_ convertPoint:point toView:nil];
-}
-
-NSPoint LocationBarViewMac::GetPageInfoBubblePoint() const {
- AutocompleteTextFieldCell* cell = [field_ cell];
- if (ev_bubble_decoration_->IsVisible()) {
- const NSRect frame = [cell frameForDecoration:ev_bubble_decoration_.get()
- inFrame:[field_ bounds]];
- const NSPoint point = ev_bubble_decoration_->GetBubblePointInFrame(frame);
- return [field_ convertPoint:point toView:nil];
- } else {
- const NSRect frame =
- [cell frameForDecoration:location_icon_decoration_.get()
- inFrame:[field_ bounds]];
- const NSPoint point =
- location_icon_decoration_->GetBubblePointInFrame(frame);
- return [field_ convertPoint:point toView:nil];
- }
-}
-
-NSImage* LocationBarViewMac::GetKeywordImage(const std::wstring& keyword) {
- const TemplateURL* template_url =
- profile_->GetTemplateURLModel()->GetTemplateURLForKeyword(keyword);
- if (template_url && template_url->IsExtensionKeyword()) {
- const SkBitmap& bitmap = profile_->GetExtensionsService()->
- GetOmniboxIcon(template_url->GetExtensionId());
- return gfx::SkBitmapToNSImage(bitmap);
- }
-
- return AutocompleteEditViewMac::ImageForResource(IDR_OMNIBOX_SEARCH);
-}
-
-void LocationBarViewMac::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- switch (type.value) {
- case NotificationType::EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED: {
- TabContents* contents = GetTabContents();
- if (Details<TabContents>(contents) != details)
- return;
-
- [field_ updateCursorAndToolTipRects];
- [field_ setNeedsDisplay:YES];
- break;
- }
- default:
- NOTREACHED() << "Unexpected notification";
- break;
- }
-}
-
-void LocationBarViewMac::PostNotification(NSString* notification) {
- [[NSNotificationCenter defaultCenter] postNotificationName:notification
- object:[NSValue valueWithPointer:this]];
-}
-
-bool LocationBarViewMac::RefreshContentSettingsDecorations() {
- const bool input_in_progress = toolbar_model_->input_in_progress();
- TabContents* tab_contents =
- input_in_progress ? NULL : browser_->GetSelectedTabContents();
- bool icons_updated = false;
- for (size_t i = 0; i < content_setting_decorations_.size(); ++i) {
- icons_updated |=
- content_setting_decorations_[i]->UpdateFromTabContents(tab_contents);
- }
- return icons_updated;
-}
-
-void LocationBarViewMac::DeletePageActionDecorations() {
- // TODO(shess): Deleting these decorations could result in the cell
- // refering to them before things are laid out again. Meanwhile, at
- // least fail safe.
- [[field_ cell] clearDecorations];
-
- page_action_decorations_.reset();
-}
-
-void LocationBarViewMac::RefreshPageActionDecorations() {
- if (!IsEditable()) {
- DeletePageActionDecorations();
- return;
- }
-
- ExtensionsService* service = profile_->GetExtensionsService();
- if (!service)
- return;
-
- std::vector<ExtensionAction*> page_actions;
- for (size_t i = 0; i < service->extensions()->size(); ++i) {
- if (service->extensions()->at(i)->page_action())
- page_actions.push_back(service->extensions()->at(i)->page_action());
- }
-
- // On startup we sometimes haven't loaded any extensions. This makes sure
- // we catch up when the extensions (and any Page Actions) load.
- if (page_actions.size() != page_action_decorations_.size()) {
- DeletePageActionDecorations(); // Delete the old views (if any).
-
- for (size_t i = 0; i < page_actions.size(); ++i) {
- page_action_decorations_.push_back(
- new PageActionDecoration(this, profile_, page_actions[i]));
- }
- }
-
- if (page_action_decorations_.empty())
- return;
-
- TabContents* contents = GetTabContents();
- if (!contents)
- return;
-
- GURL url = GURL(WideToUTF8(toolbar_model_->GetText()));
- for (size_t i = 0; i < page_action_decorations_.size(); ++i) {
- page_action_decorations_[i]->UpdateVisibility(
- toolbar_model_->input_in_progress() ? NULL : contents, url);
- }
-}
-
-// TODO(shess): This function should over time grow to closely match
-// the views Layout() function.
-void LocationBarViewMac::Layout() {
- AutocompleteTextFieldCell* cell = [field_ cell];
-
- // Reset the left-hand decorations.
- // TODO(shess): Shortly, this code will live somewhere else, like in
- // the constructor. I am still wrestling with how best to deal with
- // right-hand decorations, which are not a static set.
- [cell clearDecorations];
- [cell addLeftDecoration:location_icon_decoration_.get()];
- [cell addLeftDecoration:selected_keyword_decoration_.get()];
- [cell addLeftDecoration:ev_bubble_decoration_.get()];
- [cell addRightDecoration:star_decoration_.get()];
-
- // Note that display order is right to left.
- for (size_t i = 0; i < page_action_decorations_.size(); ++i) {
- [cell addRightDecoration:page_action_decorations_[i]];
- }
- for (size_t i = 0; i < content_setting_decorations_.size(); ++i) {
- [cell addRightDecoration:content_setting_decorations_[i]];
- }
-
- [cell addRightDecoration:keyword_hint_decoration_.get()];
-
- // By default only the location icon is visible.
- location_icon_decoration_->SetVisible(true);
- selected_keyword_decoration_->SetVisible(false);
- ev_bubble_decoration_->SetVisible(false);
- keyword_hint_decoration_->SetVisible(false);
-
- // Get the keyword to use for keyword-search and hinting.
- const std::wstring keyword(edit_view_->model()->keyword());
- std::wstring short_name;
- bool is_extension_keyword = false;
- if (!keyword.empty()) {
- short_name = profile_->GetTemplateURLModel()->
- GetKeywordShortName(keyword, &is_extension_keyword);
- }
-
- const bool is_keyword_hint = edit_view_->model()->is_keyword_hint();
-
- if (!keyword.empty() && !is_keyword_hint) {
- // Switch from location icon to keyword mode.
- location_icon_decoration_->SetVisible(false);
- selected_keyword_decoration_->SetVisible(true);
- selected_keyword_decoration_->SetKeyword(short_name, is_extension_keyword);
- selected_keyword_decoration_->SetImage(GetKeywordImage(keyword));
- } else if (toolbar_model_->GetSecurityLevel() == ToolbarModel::EV_SECURE) {
- // Switch from location icon to show the EV bubble instead.
- location_icon_decoration_->SetVisible(false);
- ev_bubble_decoration_->SetVisible(true);
-
- std::wstring label(toolbar_model_->GetEVCertName());
- ev_bubble_decoration_->SetFullLabel(base::SysWideToNSString(label));
- } else if (!keyword.empty() && is_keyword_hint) {
- keyword_hint_decoration_->SetKeyword(short_name, is_extension_keyword);
- keyword_hint_decoration_->SetVisible(true);
- }
-
- // These need to change anytime the layout changes.
- // TODO(shess): Anytime the field editor might have changed, the
- // cursor rects almost certainly should have changed. The tooltips
- // might change even when the rects don't change.
- [field_ resetFieldEditorFrameIfNeeded];
- [field_ updateCursorAndToolTipRects];
-
- [field_ setNeedsDisplay:YES];
-}
diff --git a/chrome/browser/cocoa/location_bar/location_icon_decoration.h b/chrome/browser/cocoa/location_bar/location_icon_decoration.h
deleted file mode 100644
index 4cba72f..0000000
--- a/chrome/browser/cocoa/location_bar/location_icon_decoration.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_LOCATION_BAR_LOCATION_ICON_DECORATION_H_
-#define CHROME_BROWSER_COCOA_LOCATION_BAR_LOCATION_ICON_DECORATION_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "chrome/browser/cocoa/location_bar/image_decoration.h"
-
-class LocationBarViewMac;
-
-// LocationIconDecoration is used to display an icon to the left of
-// the address.
-
-class LocationIconDecoration : public ImageDecoration {
- public:
- explicit LocationIconDecoration(LocationBarViewMac* owner);
- virtual ~LocationIconDecoration();
-
- // Allow dragging the current URL.
- virtual bool IsDraggable();
- virtual NSPasteboard* GetDragPasteboard();
- virtual NSImage* GetDragImage() { return GetImage(); }
- virtual NSRect GetDragImageFrame(NSRect frame) {
- return GetDrawRectInFrame(frame);
- }
-
- // Get the point where the page info bubble should point within the
- // decoration's frame, in the |owner_|'s coordinates.
- NSPoint GetBubblePointInFrame(NSRect frame);
-
- // Show the page info panel on click.
- virtual bool OnMousePressed(NSRect frame);
- virtual bool AcceptsMousePress() { return true; }
-
- private:
- // The location bar view that owns us.
- LocationBarViewMac* owner_;
-
- DISALLOW_COPY_AND_ASSIGN(LocationIconDecoration);
-};
-
-#endif // CHROME_BROWSER_COCOA_LOCATION_BAR_LOCATION_ICON_DECORATION_H_
diff --git a/chrome/browser/cocoa/location_bar/location_icon_decoration.mm b/chrome/browser/cocoa/location_bar/location_icon_decoration.mm
deleted file mode 100644
index 9649789..0000000
--- a/chrome/browser/cocoa/location_bar/location_icon_decoration.mm
+++ /dev/null
@@ -1,72 +0,0 @@
-// 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.
-
-#include <cmath>
-
-#import "chrome/browser/cocoa/location_bar/location_icon_decoration.h"
-
-#include "base/sys_string_conversions.h"
-#import "chrome/browser/cocoa/location_bar/location_bar_view_mac.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#import "third_party/mozilla/NSPasteboard+Utils.h"
-
-// The info-bubble point should look like it points to the bottom of the lock
-// icon. Determined with Pixie.app.
-const CGFloat kBubblePointYOffset = 2.0;
-
-LocationIconDecoration::LocationIconDecoration(LocationBarViewMac* owner)
- : owner_(owner) {
-}
-LocationIconDecoration::~LocationIconDecoration() {
-}
-
-bool LocationIconDecoration::IsDraggable() {
- // Without a tab it will be impossible to get the information needed
- // to perform a drag.
- if (!owner_->GetTabContents())
- return false;
-
- // Do not drag if the user has been editing the location bar, or the
- // location bar is at the NTP.
- if (owner_->location_entry()->IsEditingOrEmpty())
- return false;
-
- return true;
-}
-
-NSPasteboard* LocationIconDecoration::GetDragPasteboard() {
- TabContents* tab = owner_->GetTabContents();
- DCHECK(tab); // See |IsDraggable()|.
-
- NSString* url = base::SysUTF8ToNSString(tab->GetURL().spec());
- NSString* title = base::SysUTF16ToNSString(tab->GetTitle());
-
- NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
- [pboard declareURLPasteboardWithAdditionalTypes:[NSArray array]
- owner:nil];
- [pboard setDataForURL:url title:title];
- return pboard;
-}
-
-NSPoint LocationIconDecoration::GetBubblePointInFrame(NSRect frame) {
- const NSRect draw_frame = GetDrawRectInFrame(frame);
- return NSMakePoint(NSMidX(draw_frame),
- NSMaxY(draw_frame) - kBubblePointYOffset);
-}
-
-bool LocationIconDecoration::OnMousePressed(NSRect frame) {
- // Do not show page info if the user has been editing the location
- // bar, or the location bar is at the NTP.
- if (owner_->location_entry()->IsEditingOrEmpty())
- return true;
-
- TabContents* tab = owner_->GetTabContents();
- NavigationEntry* nav_entry = tab->controller().GetActiveEntry();
- if (!nav_entry) {
- NOTREACHED();
- return true;
- }
- tab->ShowPageInfo(nav_entry->url(), nav_entry->ssl(), true);
- return true;
-}
diff --git a/chrome/browser/cocoa/location_bar/omnibox_popup_view.h b/chrome/browser/cocoa/location_bar/omnibox_popup_view.h
deleted file mode 100644
index 938e635..0000000
--- a/chrome/browser/cocoa/location_bar/omnibox_popup_view.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_LOCATION_BAR_OMNIBOX_POPUP_VIEW_H_
-#define CHROME_BROWSER_COCOA_LOCATION_BAR_OMNIBOX_POPUP_VIEW_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-// The content view for the omnibox popup. Supports up to two subviews (the
-// AutocompleteMatrix containing autocomplete results and (optionally) an
-// InstantOptInView.
-@interface OmniboxPopupView : NSView
-@end
-
-#endif // CHROME_BROWSER_COCOA_LOCATION_BAR_OMNIBOX_POPUP_VIEW_H_
diff --git a/chrome/browser/cocoa/location_bar/omnibox_popup_view.mm b/chrome/browser/cocoa/location_bar/omnibox_popup_view.mm
deleted file mode 100644
index b8319ec..0000000
--- a/chrome/browser/cocoa/location_bar/omnibox_popup_view.mm
+++ /dev/null
@@ -1,43 +0,0 @@
-// 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 "chrome/browser/cocoa/location_bar/omnibox_popup_view.h"
-
-#include "base/logging.h"
-
-@implementation OmniboxPopupView
-
-// If there is only one subview, it is sized to fill all available space. If
-// there are two subviews, the second subview is placed at the bottom of the
-// view, and the first subview is sized to fill all remaining space.
-- (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize {
- NSArray* subviews = [self subviews];
- if ([subviews count] == 0)
- return;
-
- DCHECK_LE([subviews count], 2U);
-
- NSRect availableSpace = [self bounds];
-
- if ([subviews count] >= 2) {
- NSView* instantView = [subviews objectAtIndex:1];
- CGFloat height = NSHeight([instantView frame]);
- NSRect instantFrame = availableSpace;
- instantFrame.size.height = height;
-
- availableSpace.origin.y = height;
- availableSpace.size.height -= height;
- [instantView setFrame:instantFrame];
- }
-
- if ([subviews count] >= 1) {
- NSView* matrixView = [subviews objectAtIndex:0];
- if (NSHeight(availableSpace) < 0)
- availableSpace.size.height = 0;
-
- [matrixView setFrame:availableSpace];
- }
-}
-
-@end
diff --git a/chrome/browser/cocoa/location_bar/omnibox_popup_view_unittest.mm b/chrome/browser/cocoa/location_bar/omnibox_popup_view_unittest.mm
deleted file mode 100644
index 1bbb6ee..0000000
--- a/chrome/browser/cocoa/location_bar/omnibox_popup_view_unittest.mm
+++ /dev/null
@@ -1,68 +0,0 @@
-// 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 "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/location_bar/omnibox_popup_view.h"
-
-namespace {
-
-class OmniboxPopupViewTest : public CocoaTest {
- public:
- OmniboxPopupViewTest() {
- NSRect content_frame = [[test_window() contentView] frame];
- scoped_nsobject<OmniboxPopupView> view(
- [[OmniboxPopupView alloc] initWithFrame:content_frame]);
- view_ = view.get();
- [[test_window() contentView] addSubview:view_];
- }
-
- OmniboxPopupView* view_; // Weak. Owned by the view hierarchy.
-};
-
-// Tests display, add/remove.
-TEST_VIEW(OmniboxPopupViewTest, view_);
-
-// A single subview should completely fill the popup view.
-TEST_F(OmniboxPopupViewTest, ResizeWithOneSubview) {
- scoped_nsobject<NSView> subview1([[NSView alloc] initWithFrame:NSZeroRect]);
-
- // Adding the subview should not change its frame.
- [view_ addSubview:subview1];
- EXPECT_TRUE(NSEqualRects(NSZeroRect, [subview1 frame]));
-
- // Resizing the popup view should also resize the subview.
- [view_ setFrame:NSMakeRect(0, 0, 100, 100)];
- EXPECT_TRUE(NSEqualRects([view_ bounds], [subview1 frame]));
-}
-
-TEST_F(OmniboxPopupViewTest, ResizeWithTwoSubviews) {
- const CGFloat height = 50;
- NSRect initial = NSMakeRect(0, 0, 100, height);
-
- scoped_nsobject<NSView> subview1([[NSView alloc] initWithFrame:NSZeroRect]);
- scoped_nsobject<NSView> subview2([[NSView alloc] initWithFrame:initial]);
- [view_ addSubview:subview1];
- [view_ addSubview:subview2];
-
- // Resize the popup view to be much larger than height. |subview2|'s height
- // should stay the same, and |subview1| should resize to fill all available
- // space.
- [view_ setFrame:NSMakeRect(0, 0, 300, 4 * height)];
- EXPECT_EQ(NSWidth([view_ frame]), NSWidth([subview1 frame]));
- EXPECT_EQ(NSWidth([view_ frame]), NSWidth([subview2 frame]));
- EXPECT_EQ(height, NSHeight([subview2 frame]));
- EXPECT_EQ(NSHeight([view_ frame]),
- NSHeight([subview1 frame]) + NSHeight([subview2 frame]));
-
- // Now resize the popup view to be smaller than height. |subview2|'s height
- // should stay the same, and |subview1|'s height should be zero, not negative.
- [view_ setFrame:NSMakeRect(0, 0, 300, height - 10)];
- EXPECT_EQ(NSWidth([view_ frame]), NSWidth([subview1 frame]));
- EXPECT_EQ(NSWidth([view_ frame]), NSWidth([subview2 frame]));
- EXPECT_EQ(0, NSHeight([subview1 frame]));
- EXPECT_EQ(height, NSHeight([subview2 frame]));
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/location_bar/page_action_decoration.h b/chrome/browser/cocoa/location_bar/page_action_decoration.h
deleted file mode 100644
index 2608912..0000000
--- a/chrome/browser/cocoa/location_bar/page_action_decoration.h
+++ /dev/null
@@ -1,120 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_LOCATION_BAR_PAGE_ACTION_DECORATION_H_
-#define CHROME_BROWSER_COCOA_LOCATION_BAR_PAGE_ACTION_DECORATION_H_
-#pragma once
-
-#import "chrome/browser/cocoa/location_bar/image_decoration.h"
-
-#include "chrome/browser/extensions/image_loading_tracker.h"
-#include "googleurl/src/gurl.h"
-
-class ExtensionAction;
-@class ExtensionActionContextMenu;
-class LocationBarViewMac;
-class Profile;
-class TabContents;
-
-// PageActionDecoration is used to display the icon for a given Page
-// Action and notify the extension when the icon is clicked.
-
-class PageActionDecoration : public ImageDecoration,
- public ImageLoadingTracker::Observer,
- public NotificationObserver {
- public:
- PageActionDecoration(LocationBarViewMac* owner,
- Profile* profile,
- ExtensionAction* page_action);
- virtual ~PageActionDecoration();
-
- ExtensionAction* page_action() { return page_action_; }
- int current_tab_id() { return current_tab_id_; }
- void set_preview_enabled(bool enabled) { preview_enabled_ = enabled; }
- bool preview_enabled() const { return preview_enabled_; }
-
- // Overridden from |ImageLoadingTracker::Observer|.
- virtual void OnImageLoaded(
- SkBitmap* image, ExtensionResource resource, int index);
-
- // Called to notify the Page Action that it should determine whether
- // to be visible or hidden. |contents| is the TabContents that is
- // active, |url| is the current page URL.
- void UpdateVisibility(TabContents* contents, const GURL& url);
-
- // Sets the tooltip for this Page Action image.
- void SetToolTip(NSString* tooltip);
- void SetToolTip(std::string tooltip);
-
- // Get the point where extension info bubbles should point within
- // the given decoration frame.
- NSPoint GetBubblePointInFrame(NSRect frame);
-
- // Overridden from |LocationBarDecoration|
- virtual CGFloat GetWidthForSpace(CGFloat width);
- virtual bool AcceptsMousePress() { return true; }
- virtual bool OnMousePressed(NSRect frame);
- virtual NSString* GetToolTip();
- virtual NSMenu* GetMenu();
-
- protected:
- // For unit testing only.
- PageActionDecoration() : owner_(NULL),
- profile_(NULL),
- page_action_(NULL),
- tracker_(this),
- current_tab_id_(-1),
- preview_enabled_(false) {}
-
- private:
- // Overridden from NotificationObserver:
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- // The location bar view that owns us.
- LocationBarViewMac* owner_;
-
- // The current profile (not owned by us).
- Profile* profile_;
-
- // The Page Action that this view represents. The Page Action is not
- // owned by us, it resides in the extension of this particular
- // profile.
- ExtensionAction* page_action_;
-
- // A cache of images the Page Actions might need to show, mapped by
- // path.
- typedef std::map<std::string, SkBitmap> PageActionMap;
- PageActionMap page_action_icons_;
-
- // The object that is waiting for the image loading to complete
- // asynchronously.
- ImageLoadingTracker tracker_;
-
- // The tab id we are currently showing the icon for.
- int current_tab_id_;
-
- // The URL we are currently showing the icon for.
- GURL current_url_;
-
- // The string to show for a tooltip.
- scoped_nsobject<NSString> tooltip_;
-
- // The context menu for the Page Action.
- scoped_nsobject<ExtensionActionContextMenu> menu_;
-
- // This is used for post-install visual feedback. The page_action
- // icon is briefly shown even if it hasn't been enabled by its
- // extension.
- bool preview_enabled_;
-
- // Used to register for notifications received by
- // NotificationObserver.
- NotificationRegistrar registrar_;
-
- DISALLOW_COPY_AND_ASSIGN(PageActionDecoration);
-};
-
-#endif // CHROME_BROWSER_COCOA_LOCATION_BAR_PAGE_ACTION_DECORATION_H_
diff --git a/chrome/browser/cocoa/location_bar/page_action_decoration.mm b/chrome/browser/cocoa/location_bar/page_action_decoration.mm
deleted file mode 100644
index 79636b2..0000000
--- a/chrome/browser/cocoa/location_bar/page_action_decoration.mm
+++ /dev/null
@@ -1,251 +0,0 @@
-// 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.
-
-#include <cmath>
-
-#import "chrome/browser/cocoa/location_bar/page_action_decoration.h"
-
-#include "base/sys_string_conversions.h"
-#import "chrome/browser/cocoa/extensions/extension_action_context_menu.h"
-#import "chrome/browser/cocoa/extensions/extension_popup_controller.h"
-#import "chrome/browser/cocoa/location_bar/location_bar_view_mac.h"
-#include "chrome/browser/extensions/extension_browser_event_router.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/extensions/extension_action.h"
-#include "chrome/common/extensions/extension_resource.h"
-#include "skia/ext/skia_utils_mac.h"
-
-namespace {
-
-// Distance to offset the bubble pointer from the bottom of the max
-// icon area of the decoration. This makes the popup's upper border
-// 2px away from the omnibox's lower border (matches omnibox popup
-// upper border).
-const CGFloat kBubblePointYOffset = 2.0;
-
-} // namespace
-
-PageActionDecoration::PageActionDecoration(
- LocationBarViewMac* owner,
- Profile* profile,
- ExtensionAction* page_action)
- : owner_(NULL),
- profile_(profile),
- page_action_(page_action),
- tracker_(this),
- current_tab_id_(-1),
- preview_enabled_(false) {
- DCHECK(profile);
- const Extension* extension = profile->GetExtensionsService()->
- GetExtensionById(page_action->extension_id(), false);
- DCHECK(extension);
-
- // Load all the icons declared in the manifest. This is the contents of the
- // icons array, plus the default_icon property, if any.
- std::vector<std::string> icon_paths(*page_action->icon_paths());
- if (!page_action_->default_icon_path().empty())
- icon_paths.push_back(page_action_->default_icon_path());
-
- for (std::vector<std::string>::iterator iter = icon_paths.begin();
- iter != icon_paths.end(); ++iter) {
- tracker_.LoadImage(extension, extension->GetResource(*iter),
- gfx::Size(Extension::kPageActionIconMaxSize,
- Extension::kPageActionIconMaxSize),
- ImageLoadingTracker::DONT_CACHE);
- }
-
- registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE,
- Source<Profile>(profile_));
-
- // We set the owner last of all so that we can determine whether we are in
- // the process of initializing this class or not.
- owner_ = owner;
-}
-
-PageActionDecoration::~PageActionDecoration() {}
-
-// Always |kPageActionIconMaxSize| wide. |ImageDecoration| draws the
-// image centered.
-CGFloat PageActionDecoration::GetWidthForSpace(CGFloat width) {
- return Extension::kPageActionIconMaxSize;
-}
-
-// Either notify listeners or show a popup depending on the Page
-// Action.
-bool PageActionDecoration::OnMousePressed(NSRect frame) {
- if (current_tab_id_ < 0) {
- NOTREACHED() << "No current tab.";
- // We don't want other code to try and handle this click. Returning true
- // prevents this by indicating that we handled it.
- return true;
- }
-
- if (page_action_->HasPopup(current_tab_id_)) {
- // Anchor popup at the bottom center of the page action icon.
- AutocompleteTextField* field = owner_->GetAutocompleteTextField();
- NSPoint anchor = GetBubblePointInFrame(frame);
- anchor = [field convertPoint:anchor toView:nil];
-
- const GURL popup_url(page_action_->GetPopupUrl(current_tab_id_));
- [ExtensionPopupController showURL:popup_url
- inBrowser:BrowserList::GetLastActive()
- anchoredAt:anchor
- arrowLocation:info_bubble::kTopRight
- devMode:NO];
- } else {
- ExtensionBrowserEventRouter::GetInstance()->PageActionExecuted(
- profile_, page_action_->extension_id(), page_action_->id(),
- current_tab_id_, current_url_.spec(),
- 1);
- }
- return true;
-}
-
-void PageActionDecoration::OnImageLoaded(
- SkBitmap* image, ExtensionResource resource, int index) {
- // We loaded icons()->size() icons, plus one extra if the Page Action had
- // a default icon.
- int total_icons = static_cast<int>(page_action_->icon_paths()->size());
- if (!page_action_->default_icon_path().empty())
- total_icons++;
- DCHECK(index < total_icons);
-
- // Map the index of the loaded image back to its name. If we ever get an
- // index greater than the number of icons, it must be the default icon.
- if (image) {
- if (index < static_cast<int>(page_action_->icon_paths()->size()))
- page_action_icons_[page_action_->icon_paths()->at(index)] = *image;
- else
- page_action_icons_[page_action_->default_icon_path()] = *image;
- }
-
- // If we have no owner, that means this class is still being constructed and
- // we should not UpdatePageActions, since it leads to the PageActions being
- // destroyed again and new ones recreated (causing an infinite loop).
- if (owner_)
- owner_->UpdatePageActions();
-}
-
-void PageActionDecoration::UpdateVisibility(TabContents* contents,
- const GURL& url) {
- // Save this off so we can pass it back to the extension when the action gets
- // executed. See PageActionDecoration::OnMousePressed.
- current_tab_id_ = contents ? ExtensionTabUtil::GetTabId(contents) : -1;
- current_url_ = url;
-
- bool visible = contents &&
- (preview_enabled_ || page_action_->GetIsVisible(current_tab_id_));
- if (visible) {
- SetToolTip(page_action_->GetTitle(current_tab_id_));
-
- // Set the image.
- // It can come from three places. In descending order of priority:
- // - The developer can set it dynamically by path or bitmap. It will be in
- // page_action_->GetIcon().
- // - The developer can set it dynamically by index. It will be in
- // page_action_->GetIconIndex().
- // - It can be set in the manifest by path. It will be in page_action_->
- // default_icon_path().
-
- // First look for a dynamically set bitmap.
- SkBitmap skia_icon = page_action_->GetIcon(current_tab_id_);
- if (skia_icon.isNull()) {
- int icon_index = page_action_->GetIconIndex(current_tab_id_);
- std::string icon_path = (icon_index < 0) ?
- page_action_->default_icon_path() :
- page_action_->icon_paths()->at(icon_index);
- if (!icon_path.empty()) {
- PageActionMap::iterator iter = page_action_icons_.find(icon_path);
- if (iter != page_action_icons_.end())
- skia_icon = iter->second;
- }
- }
- if (!skia_icon.isNull()) {
- SetImage(gfx::SkBitmapToNSImage(skia_icon));
- } else if (!GetImage()) {
- // During install the action can be displayed before the icons
- // have come in. Rather than deal with this in multiple places,
- // provide a placeholder image. This will be replaced when an
- // icon comes in.
- const NSSize default_size = NSMakeSize(Extension::kPageActionIconMaxSize,
- Extension::kPageActionIconMaxSize);
- SetImage([[NSImage alloc] initWithSize:default_size]);
- }
- }
-
- if (IsVisible() != visible) {
- SetVisible(visible);
- NotificationService::current()->Notify(
- NotificationType::EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED,
- Source<ExtensionAction>(page_action_),
- Details<TabContents>(contents));
- }
-}
-
-void PageActionDecoration::SetToolTip(NSString* tooltip) {
- tooltip_.reset([tooltip retain]);
-}
-
-void PageActionDecoration::SetToolTip(std::string tooltip) {
- SetToolTip(tooltip.empty() ? nil : base::SysUTF8ToNSString(tooltip));
-}
-
-NSString* PageActionDecoration::GetToolTip() {
- return tooltip_.get();
-}
-
-NSPoint PageActionDecoration::GetBubblePointInFrame(NSRect frame) {
- // This is similar to |ImageDecoration::GetDrawRectInFrame()|,
- // except that code centers the image, which can differ in size
- // between actions. This centers the maximum image size, so the
- // point will consistently be at the same y position. x position is
- // easier (the middle of the centered image is the middle of the
- // frame).
- const CGFloat delta_height =
- NSHeight(frame) - Extension::kPageActionIconMaxSize;
- const CGFloat bottom_inset = std::ceil(delta_height / 2.0);
-
- // Return a point just below the bottom of the maximal drawing area.
- return NSMakePoint(NSMidX(frame),
- NSMaxY(frame) - bottom_inset + kBubblePointYOffset);
-}
-
-NSMenu* PageActionDecoration::GetMenu() {
- if (!profile_)
- return nil;
- ExtensionsService* service = profile_->GetExtensionsService();
- if (!service)
- return nil;
- const Extension* extension = service->GetExtensionById(
- page_action_->extension_id(), false);
- DCHECK(extension);
- if (!extension)
- return nil;
- menu_.reset([[ExtensionActionContextMenu alloc]
- initWithExtension:extension
- profile:profile_
- extensionAction:page_action_]);
-
- return menu_.get();
-}
-
-void PageActionDecoration::Observe(
- NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- switch (type.value) {
- case NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE: {
- ExtensionPopupController* popup = [ExtensionPopupController popup];
- if (popup && ![popup isClosing])
- [popup close];
-
- break;
- }
- default:
- NOTREACHED() << "Unexpected notification";
- break;
- }
-}
diff --git a/chrome/browser/cocoa/location_bar/selected_keyword_decoration.h b/chrome/browser/cocoa/location_bar/selected_keyword_decoration.h
deleted file mode 100644
index e2df50a..0000000
--- a/chrome/browser/cocoa/location_bar/selected_keyword_decoration.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_LOCATION_BAR_SELECTED_KEYWORD_DECORATION_H_
-#define CHROME_BROWSER_COCOA_LOCATION_BAR_SELECTED_KEYWORD_DECORATION_H_
-#pragma once
-
-#include <string>
-
-#import <Cocoa/Cocoa.h>
-
-#include "chrome/browser/cocoa/location_bar/bubble_decoration.h"
-
-class SelectedKeywordDecoration : public BubbleDecoration {
- public:
- SelectedKeywordDecoration(NSFont* font);
-
- // Calculates appropriate full and partial label strings based on
- // inputs.
- void SetKeyword(const std::wstring& keyword, bool is_extension_keyword);
-
- // Determines what combination of labels and image will best fit
- // within |width|, makes those current for |BubbleDecoration|, and
- // return the resulting width.
- virtual CGFloat GetWidthForSpace(CGFloat width);
-
- void SetImage(NSImage* image);
-
- private:
- friend class SelectedKeywordDecorationTest;
- FRIEND_TEST_ALL_PREFIXES(SelectedKeywordDecorationTest,
- UsesPartialKeywordIfNarrow);
-
- scoped_nsobject<NSImage> search_image_;
- scoped_nsobject<NSString> full_string_;
- scoped_nsobject<NSString> partial_string_;
-
- DISALLOW_COPY_AND_ASSIGN(SelectedKeywordDecoration);
-};
-
-#endif // CHROME_BROWSER_COCOA_LOCATION_BAR_SELECTED_KEYWORD_DECORATION_H_
diff --git a/chrome/browser/cocoa/location_bar/selected_keyword_decoration.mm b/chrome/browser/cocoa/location_bar/selected_keyword_decoration.mm
deleted file mode 100644
index 9d18bcb..0000000
--- a/chrome/browser/cocoa/location_bar/selected_keyword_decoration.mm
+++ /dev/null
@@ -1,73 +0,0 @@
-// 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 "chrome/browser/cocoa/location_bar/selected_keyword_decoration.h"
-
-#include "app/l10n_util_mac.h"
-#include "base/utf_string_conversions.h"
-#import "chrome/browser/autocomplete/autocomplete_edit_view_mac.h"
-#import "chrome/browser/cocoa/image_utils.h"
-#include "chrome/browser/location_bar_util.h"
-#include "grit/theme_resources.h"
-#include "grit/generated_resources.h"
-
-SelectedKeywordDecoration::SelectedKeywordDecoration(NSFont* font)
- : BubbleDecoration(font) {
- search_image_.reset([AutocompleteEditViewMac::ImageForResource(
- IDR_KEYWORD_SEARCH_MAGNIFIER) retain]);
-
- // Matches the color of the highlighted line in the popup.
- NSColor* background_color = [NSColor selectedControlColor];
-
- // Match focus ring's inner color.
- NSColor* border_color =
- [[NSColor keyboardFocusIndicatorColor] colorWithAlphaComponent:0.5];
- SetColors(border_color, background_color, [NSColor blackColor]);
-}
-
-CGFloat SelectedKeywordDecoration::GetWidthForSpace(CGFloat width) {
- const CGFloat full_width =
- GetWidthForImageAndLabel(search_image_, full_string_);
- if (full_width <= width) {
- BubbleDecoration::SetImage(search_image_);
- SetLabel(full_string_);
- return full_width;
- }
-
- BubbleDecoration::SetImage(nil);
- const CGFloat no_image_width = GetWidthForImageAndLabel(nil, full_string_);
- if (no_image_width <= width || !partial_string_) {
- SetLabel(full_string_);
- return no_image_width;
- }
-
- SetLabel(partial_string_);
- return GetWidthForImageAndLabel(nil, partial_string_);
-}
-
-void SelectedKeywordDecoration::SetKeyword(const std::wstring& short_name,
- bool is_extension_keyword) {
- const std::wstring min_name(
- location_bar_util::CalculateMinString(short_name));
- const int message_id = is_extension_keyword ?
- IDS_OMNIBOX_EXTENSION_KEYWORD_TEXT : IDS_OMNIBOX_KEYWORD_TEXT;
-
- // The text will be like "Search <name>:". "<name>" is a parameter
- // derived from |short_name|.
- full_string_.reset(
- [l10n_util::GetNSStringF(message_id, WideToUTF16(short_name)) copy]);
-
- if (min_name.empty()) {
- partial_string_.reset();
- } else {
- partial_string_.reset(
- [l10n_util::GetNSStringF(message_id, WideToUTF16(min_name)) copy]);
- }
-}
-
-void SelectedKeywordDecoration::SetImage(NSImage* image) {
- if (image != search_image_)
- search_image_.reset([image retain]);
- BubbleDecoration::SetImage(image);
-}
diff --git a/chrome/browser/cocoa/location_bar/selected_keyword_decoration_unittest.mm b/chrome/browser/cocoa/location_bar/selected_keyword_decoration_unittest.mm
deleted file mode 100644
index 6a7907a..0000000
--- a/chrome/browser/cocoa/location_bar/selected_keyword_decoration_unittest.mm
+++ /dev/null
@@ -1,65 +0,0 @@
-// 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>
-
-#import "chrome/browser/cocoa/location_bar/selected_keyword_decoration.h"
-
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-
-namespace {
-
-// A wide width which should fit everything.
-const CGFloat kWidth(300.0);
-
-// A narrow width for tests which test things that don't fit.
-const CGFloat kNarrowWidth(5.0);
-
-} // namespace
-
-class SelectedKeywordDecorationTest : public CocoaTest {
- public:
- SelectedKeywordDecorationTest()
- : decoration_([NSFont userFontOfSize:12]) {
- }
-
- SelectedKeywordDecoration decoration_;
-};
-
-// Test that the cell correctly chooses the partial keyword if there's
-// not enough room.
-TEST_F(SelectedKeywordDecorationTest, UsesPartialKeywordIfNarrow) {
-
- const std::wstring kKeyword(L"Engine");
- NSString* const kFullString = @"Search Engine:";
- NSString* const kPartialString = @"Search En\u2026:"; // ellipses
-
- decoration_.SetKeyword(kKeyword, false);
-
- // Wide width chooses the full string and image.
- const CGFloat all_width = decoration_.GetWidthForSpace(kWidth);
- EXPECT_TRUE(decoration_.image_);
- EXPECT_NSEQ(kFullString, decoration_.label_);
-
- // If not enough space to include the image, uses exactly the full
- // string.
- const CGFloat full_width = decoration_.GetWidthForSpace(all_width - 5.0);
- EXPECT_LT(full_width, all_width);
- EXPECT_FALSE(decoration_.image_);
- EXPECT_NSEQ(kFullString, decoration_.label_);
-
- // Narrow width chooses the partial string.
- const CGFloat partial_width = decoration_.GetWidthForSpace(kNarrowWidth);
- EXPECT_LT(partial_width, full_width);
- EXPECT_FALSE(decoration_.image_);
- EXPECT_NSEQ(kPartialString, decoration_.label_);
-
- // Narrow doesn't choose partial string if there is not one.
- decoration_.partial_string_.reset();
- decoration_.GetWidthForSpace(kNarrowWidth);
- EXPECT_FALSE(decoration_.image_);
- EXPECT_NSEQ(kFullString, decoration_.label_);
-}
diff --git a/chrome/browser/cocoa/location_bar/star_decoration.h b/chrome/browser/cocoa/location_bar/star_decoration.h
deleted file mode 100644
index 7e02e2c..0000000
--- a/chrome/browser/cocoa/location_bar/star_decoration.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_LOCATION_BAR_STAR_DECORATION_H_
-#define CHROME_BROWSER_COCOA_LOCATION_BAR_STAR_DECORATION_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "chrome/browser/cocoa/location_bar/image_decoration.h"
-
-class CommandUpdater;
-
-// Star icon on the right side of the field.
-
-class StarDecoration : public ImageDecoration {
- public:
- explicit StarDecoration(CommandUpdater* command_updater);
- virtual ~StarDecoration();
-
- // Sets the image and tooltip based on |starred|.
- void SetStarred(bool starred);
-
- // Get the point where the bookmark bubble should point within the
- // decoration's frame.
- NSPoint GetBubblePointInFrame(NSRect frame);
-
- // Implement |LocationBarDecoration|.
- virtual bool AcceptsMousePress() { return true; }
- virtual bool OnMousePressed(NSRect frame);
- virtual NSString* GetToolTip();
-
- private:
- // For bringing up bookmark bar.
- CommandUpdater* command_updater_; // Weak, owned by Browser.
-
- // The string to show for a tooltip.
- scoped_nsobject<NSString> tooltip_;
-
- DISALLOW_COPY_AND_ASSIGN(StarDecoration);
-};
-
-#endif // CHROME_BROWSER_COCOA_LOCATION_BAR_STAR_DECORATION_H_
diff --git a/chrome/browser/cocoa/location_bar/star_decoration.mm b/chrome/browser/cocoa/location_bar/star_decoration.mm
deleted file mode 100644
index 0d91929..0000000
--- a/chrome/browser/cocoa/location_bar/star_decoration.mm
+++ /dev/null
@@ -1,53 +0,0 @@
-// 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 "chrome/browser/cocoa/location_bar/star_decoration.h"
-
-#include "app/l10n_util_mac.h"
-#include "chrome/app/chrome_command_ids.h"
-#import "chrome/browser/autocomplete/autocomplete_edit_view_mac.h"
-#include "chrome/browser/command_updater.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-
-namespace {
-
-// The info-bubble point should look like it points to the point
-// between the star's lower tips. The popup should be where the
-// Omnibox popup ends up (2px below field). Determined via Pixie.app
-// magnification.
-const CGFloat kStarPointYOffset = 2.0;
-
-} // namespace
-
-StarDecoration::StarDecoration(CommandUpdater* command_updater)
- : command_updater_(command_updater) {
- SetVisible(true);
- SetStarred(false);
-}
-
-StarDecoration::~StarDecoration() {
-}
-
-void StarDecoration::SetStarred(bool starred) {
- const int image_id = starred ? IDR_STAR_LIT : IDR_STAR;
- const int tip_id = starred ? IDS_TOOLTIP_STARRED : IDS_TOOLTIP_STAR;
- SetImage(AutocompleteEditViewMac::ImageForResource(image_id));
- tooltip_.reset([l10n_util::GetNSStringWithFixup(tip_id) retain]);
-}
-
-NSPoint StarDecoration::GetBubblePointInFrame(NSRect frame) {
- const NSRect draw_frame = GetDrawRectInFrame(frame);
- return NSMakePoint(NSMidX(draw_frame),
- NSMaxY(draw_frame) - kStarPointYOffset);
-}
-
-bool StarDecoration::OnMousePressed(NSRect frame) {
- command_updater_->ExecuteCommand(IDC_BOOKMARK_PAGE);
- return true;
-}
-
-NSString* StarDecoration::GetToolTip() {
- return tooltip_.get();
-}
diff --git a/chrome/browser/cocoa/menu_button.h b/chrome/browser/cocoa/menu_button.h
deleted file mode 100644
index 7e8392a..0000000
--- a/chrome/browser/cocoa/menu_button.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_MENU_BUTTON_H_
-#define CHROME_BROWSER_COCOA_MENU_BUTTON_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_nsobject.h"
-
-// This a button which displays a user-provided menu "attached" below it upon
-// being clicked or dragged (or clicked and held). It expects a
-// |ClickHoldButtonCell| as cell.
-@interface MenuButton : NSButton {
- @private
- IBOutlet NSMenu* attachedMenu_;
- scoped_nsobject<NSPopUpButtonCell> popUpCell_;
-}
-
-// The menu to display. Note that it should have no (i.e., a blank) title and
-// that the 0-th entry should be blank (and won't be displayed). (This is
-// because we use a pulldown list, for which Cocoa uses the 0-th item as "title"
-// in the button. This might change if we ever switch to a pop-up. Our direct
-// use of the given NSMenu object means that the one can set and use NSMenu's
-// delegate as usual.)
-@property(assign, nonatomic) NSMenu* attachedMenu;
-
-@end // @interface MenuButton
-
-#endif // CHROME_BROWSER_COCOA_MENU_BUTTON_H_
diff --git a/chrome/browser/cocoa/menu_button.mm b/chrome/browser/cocoa/menu_button.mm
deleted file mode 100644
index f94646f..0000000
--- a/chrome/browser/cocoa/menu_button.mm
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/menu_button.h"
-
-#include "base/logging.h"
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/clickhold_button_cell.h"
-
-@interface MenuButton (Private)
-
-- (void)resetToDefaults;
-- (void)showMenu:(BOOL)isDragging;
-- (void)clickShowMenu:(id)sender;
-- (void)dragShowMenu:(id)sender;
-
-@end // @interface MenuButton (Private)
-
-@implementation MenuButton
-
-// Overrides:
-
-+ (Class)cellClass {
- return [ClickHoldButtonCell class];
-}
-
-- (id)init {
- if ((self = [super init]))
- [self resetToDefaults];
- return self;
-}
-
-- (id)initWithCoder:(NSCoder*)decoder {
- if ((self = [super initWithCoder:decoder]))
- [self resetToDefaults];
- return self;
-}
-
-- (id)initWithFrame:(NSRect)frameRect {
- if ((self = [super initWithFrame:frameRect]))
- [self resetToDefaults];
- return self;
-}
-
-// Accessors and mutators:
-
-@synthesize attachedMenu = attachedMenu_;
-
-@end // @implementation MenuButton
-
-@implementation MenuButton (Private)
-
-// Reset various settings of the button and its associated |ClickHoldButtonCell|
-// to the standard state which provides reasonable defaults.
-- (void)resetToDefaults {
- ClickHoldButtonCell* cell = [self cell];
- DCHECK([cell isKindOfClass:[ClickHoldButtonCell class]]);
- [cell setEnableClickHold:YES];
- [cell setClickHoldTimeout:0.0]; // Make menu trigger immediately.
- [cell setAction:@selector(clickShowMenu:)];
- [cell setTarget:self];
- [cell setClickHoldAction:@selector(dragShowMenu:)];
- [cell setClickHoldTarget:self];
-}
-
-// Actually show the menu (in the correct location). |isDragging| indicates
-// whether the mouse button is still down or not.
-- (void)showMenu:(BOOL)isDragging {
- if (![self attachedMenu]) {
- LOG(WARNING) << "No menu available.";
- if (isDragging) {
- // If we're dragging, wait for mouse up.
- [NSApp nextEventMatchingMask:NSLeftMouseUpMask
- untilDate:[NSDate distantFuture]
- inMode:NSEventTrackingRunLoopMode
- dequeue:YES];
- }
- return;
- }
-
- // TODO(viettrungluu): Remove silly fudge factors (same ones as in
- // delayedmenu_button.mm).
- NSRect frame = [self convertRect:[self frame]
- fromView:[self superview]];
- frame.origin.x -= 2.0;
- frame.size.height += 10.0;
-
- // Make our pop-up button cell and set things up. This is, as of 10.5, the
- // official Apple-recommended hack. Later, perhaps |-[NSMenu
- // popUpMenuPositioningItem:atLocation:inView:]| may be a better option.
- // However, using a pulldown has the benefit that Cocoa automatically places
- // the menu correctly even when we're at the edge of the screen (including
- // "dragging upwards" when the button is close to the bottom of the screen).
- // A |scoped_nsobject| local variable cannot be used here because
- // Accessibility on 10.5 grabs the NSPopUpButtonCell without retaining it, and
- // uses it later. (This is fixed in 10.6.)
- if (!popUpCell_.get()) {
- popUpCell_.reset([[NSPopUpButtonCell alloc] initTextCell:@""
- pullsDown:YES]);
- }
- DCHECK(popUpCell_.get());
- [popUpCell_ setMenu:[self attachedMenu]];
- [popUpCell_ selectItem:nil];
- [popUpCell_ attachPopUpWithFrame:frame
- inView:self];
- [popUpCell_ performClickWithFrame:frame
- inView:self];
-}
-
-// Called when the button is clicked and released. (Shouldn't happen with
-// timeout of 0, though there may be some strange pointing devices out there.)
-- (void)clickShowMenu:(id)sender {
- [self showMenu:NO];
-}
-
-// Called when the button is clicked and dragged/held.
-- (void)dragShowMenu:(id)sender {
- [self showMenu:YES];
-}
-
-@end // @implementation MenuButton (Private)
diff --git a/chrome/browser/cocoa/menu_button_unittest.mm b/chrome/browser/cocoa/menu_button_unittest.mm
deleted file mode 100644
index 6b7ba2b..0000000
--- a/chrome/browser/cocoa/menu_button_unittest.mm
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (c) 2009 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/scoped_nsobject.h"
-#import "chrome/browser/cocoa/clickhold_button_cell.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/menu_button.h"
-
-namespace {
-
-class MenuButtonTest : public CocoaTest {
- public:
- MenuButtonTest() {
- NSRect frame = NSMakeRect(0, 0, 50, 30);
- scoped_nsobject<MenuButton> button(
- [[MenuButton alloc] initWithFrame:frame]);
- button_ = button.get();
- scoped_nsobject<ClickHoldButtonCell> cell(
- [[ClickHoldButtonCell alloc] initTextCell:@"Testing"]);
- [button_ setCell:cell.get()];
- [[test_window() contentView] addSubview:button_];
- }
-
- MenuButton* button_;
-};
-
-TEST_VIEW(MenuButtonTest, button_);
-
-// Test assigning a menu, again mostly to ensure nothing leaks or crashes.
-TEST_F(MenuButtonTest, MenuAssign) {
- scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@""]);
- ASSERT_TRUE(menu.get());
-
- [menu insertItemWithTitle:@"" action:nil keyEquivalent:@"" atIndex:0];
- [menu insertItemWithTitle:@"foo" action:nil keyEquivalent:@"" atIndex:1];
- [menu insertItemWithTitle:@"bar" action:nil keyEquivalent:@"" atIndex:2];
- [menu insertItemWithTitle:@"baz" action:nil keyEquivalent:@"" atIndex:3];
-
- [button_ setAttachedMenu:menu];
- EXPECT_TRUE([button_ attachedMenu]);
-
- // TODO(viettrungluu): Display the menu. (The tough part is closing the menu,
- // not opening it!)
-
- // Since |button_| doesn't retain menu, we should probably unset it here.
- [button_ setAttachedMenu:nil];
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/menu_controller.h b/chrome/browser/cocoa/menu_controller.h
deleted file mode 100644
index c47af7f..0000000
--- a/chrome/browser/cocoa/menu_controller.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_MENU_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_MENU_CONTROLLER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_nsobject.h"
-
-namespace menus {
-class MenuModel;
-}
-
-// A controller for the cross-platform menu model. The menu that's created
-// has the tag and represented object set for each menu item. The object is a
-// NSValue holding a pointer to the model for that level of the menu (to
-// allow for hierarchical menus). The tag is the index into that model for
-// that particular item. It is important that the model outlives this object
-// as it only maintains weak references.
-@interface MenuController : NSObject {
- @protected
- menus::MenuModel* model_; // weak
- scoped_nsobject<NSMenu> menu_;
- BOOL useWithPopUpButtonCell_; // If YES, 0th item is blank
-}
-
-@property (nonatomic, assign) menus::MenuModel* model;
-// Note that changing this will have no effect if you use
-// |-initWithModel:useWithPopUpButtonCell:| or after the first call to |-menu|.
-@property (nonatomic) BOOL useWithPopUpButtonCell;
-
-// NIB-based initializer. This does not create a menu. Clients can set the
-// properties of the object and the menu will be created upon the first call to
-// |-menu|. Note that the menu will be immutable after creation.
-- (id)init;
-
-// Builds a NSMenu from the pre-built model (must not be nil). Changes made
-// to the contents of the model after calling this will not be noticed. If
-// the menu will be displayed by a NSPopUpButtonCell, it needs to be of a
-// slightly different form (0th item is empty). Note this attribute of the menu
-// cannot be changed after it has been created.
-- (id)initWithModel:(menus::MenuModel*)model
- useWithPopUpButtonCell:(BOOL)useWithCell;
-
-// Access to the constructed menu if the complex initializer was used. If the
-// default initializer was used, then this will create the menu on first call.
-- (NSMenu*)menu;
-
-@end
-
-// Exposed only for unit testing, do not call directly.
-@interface MenuController (PrivateExposedForTesting)
-- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item;
-@end
-
-// Protected methods that subclassers can override.
-@interface MenuController (Protected)
-- (void)addItemToMenu:(NSMenu*)menu
- atIndex:(NSInteger)index
- fromModel:(menus::MenuModel*)model
- modelIndex:(int)modelIndex;
-@end
-
-#endif // CHROME_BROWSER_COCOA_MENU_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/menu_controller.mm b/chrome/browser/cocoa/menu_controller.mm
deleted file mode 100644
index 4e0aa16..0000000
--- a/chrome/browser/cocoa/menu_controller.mm
+++ /dev/null
@@ -1,185 +0,0 @@
-// 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 "chrome/browser/cocoa/menu_controller.h"
-
-#include "app/l10n_util_mac.h"
-#include "app/menus/accelerator_cocoa.h"
-#include "app/menus/simple_menu_model.h"
-#include "base/logging.h"
-#include "base/sys_string_conversions.h"
-#include "skia/ext/skia_utils_mac.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-@interface MenuController (Private)
-- (NSMenu*)menuFromModel:(menus::MenuModel*)model;
-- (void)addSeparatorToMenu:(NSMenu*)menu
- atIndex:(int)index;
-@end
-
-@implementation MenuController
-
-@synthesize model = model_;
-@synthesize useWithPopUpButtonCell = useWithPopUpButtonCell_;
-
-- (id)init {
- self = [super init];
- return self;
-}
-
-- (id)initWithModel:(menus::MenuModel*)model
- useWithPopUpButtonCell:(BOOL)useWithCell {
- if ((self = [super init])) {
- model_ = model;
- useWithPopUpButtonCell_ = useWithCell;
- [self menu];
- }
- return self;
-}
-
-- (void)dealloc {
- model_ = NULL;
- [super dealloc];
-}
-
-// Creates a NSMenu from the given model. If the model has submenus, this can
-// be invoked recursively.
-- (NSMenu*)menuFromModel:(menus::MenuModel*)model {
- NSMenu* menu = [[[NSMenu alloc] initWithTitle:@""] autorelease];
-
- // The indices may not always start at zero (the windows system menu is one
- // example where this is used) so just make sure we can handle it.
- // SimpleMenuModel currently always starts at 0.
- int firstItemIndex = model->GetFirstItemIndex(menu);
- DCHECK(firstItemIndex == 0);
- const int count = model->GetItemCount();
- for (int index = firstItemIndex; index < firstItemIndex + count; index++) {
- int modelIndex = index - firstItemIndex;
- if (model->GetTypeAt(modelIndex) == menus::MenuModel::TYPE_SEPARATOR) {
- [self addSeparatorToMenu:menu atIndex:index];
- } else {
- [self addItemToMenu:menu atIndex:index fromModel:model
- modelIndex:modelIndex];
- }
- }
-
- return menu;
-}
-
-// Adds a separator item at the given index. As the separator doesn't need
-// anything from the model, this method doesn't need the model index as the
-// other method below does.
-- (void)addSeparatorToMenu:(NSMenu*)menu
- atIndex:(int)index {
- NSMenuItem* separator = [NSMenuItem separatorItem];
- [menu insertItem:separator atIndex:index];
-}
-
-// Adds an item or a hierarchical menu to the item at the |index|,
-// associated with the entry in the model indentifed by |modelIndex|.
-- (void)addItemToMenu:(NSMenu*)menu
- atIndex:(NSInteger)index
- fromModel:(menus::MenuModel*)model
- modelIndex:(int)modelIndex {
- NSString* label =
- l10n_util::FixUpWindowsStyleLabel(model->GetLabelAt(modelIndex));
- scoped_nsobject<NSMenuItem> item(
- [[NSMenuItem alloc] initWithTitle:label
- action:@selector(itemSelected:)
- keyEquivalent:@""]);
-
- // If the menu item has an icon, set it.
- SkBitmap skiaIcon;
- if (model->GetIconAt(modelIndex, &skiaIcon) && !skiaIcon.isNull()) {
- NSImage* icon = gfx::SkBitmapToNSImage(skiaIcon);
- if (icon) {
- [item setImage:icon];
- }
- }
-
- menus::MenuModel::ItemType type = model->GetTypeAt(modelIndex);
- if (type == menus::MenuModel::TYPE_SUBMENU) {
- // Recursively build a submenu from the sub-model at this index.
- [item setTarget:nil];
- [item setAction:nil];
- menus::MenuModel* submenuModel = model->GetSubmenuModelAt(modelIndex);
- NSMenu* submenu =
- [self menuFromModel:(menus::SimpleMenuModel*)submenuModel];
- [item setSubmenu:submenu];
- } else {
- // The MenuModel works on indexes so we can't just set the command id as the
- // tag like we do in other menus. Also set the represented object to be
- // the model so hierarchical menus check the correct index in the correct
- // model. Setting the target to |self| allows this class to participate
- // in validation of the menu items.
- [item setTag:modelIndex];
- [item setTarget:self];
- NSValue* modelObject = [NSValue valueWithPointer:model];
- [item setRepresentedObject:modelObject]; // Retains |modelObject|.
- menus::AcceleratorCocoa accelerator;
- if (model->GetAcceleratorAt(modelIndex, &accelerator)) {
- [item setKeyEquivalent:accelerator.characters()];
- [item setKeyEquivalentModifierMask:accelerator.modifiers()];
- }
- }
- [menu insertItem:item atIndex:index];
-}
-
-// Called before the menu is to be displayed to update the state (enabled,
-// radio, etc) of each item in the menu. Also will update the title if
-// the item is marked as "dynamic".
-- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
- SEL action = [item action];
- if (action != @selector(itemSelected:))
- return NO;
-
- NSInteger modelIndex = [item tag];
- menus::MenuModel* model =
- static_cast<menus::MenuModel*>(
- [[(id)item representedObject] pointerValue]);
- DCHECK(model);
- if (model) {
- BOOL checked = model->IsItemCheckedAt(modelIndex);
- DCHECK([(id)item isKindOfClass:[NSMenuItem class]]);
- [(id)item setState:(checked ? NSOnState : NSOffState)];
- [(id)item setHidden:(!model->IsVisibleAt(modelIndex))];
- if (model->IsLabelDynamicAt(modelIndex)) {
- NSString* label =
- l10n_util::FixUpWindowsStyleLabel(model->GetLabelAt(modelIndex));
- [(id)item setTitle:label];
- }
- return model->IsEnabledAt(modelIndex);
- }
- return NO;
-}
-
-// Called when the user chooses a particular menu item. |sender| is the menu
-// item chosen.
-- (void)itemSelected:(id)sender {
- NSInteger modelIndex = [sender tag];
- menus::MenuModel* model =
- static_cast<menus::MenuModel*>(
- [[sender representedObject] pointerValue]);
- DCHECK(model);
- if (model)
- model->ActivatedAt(modelIndex);
-}
-
-- (NSMenu*)menu {
- if (!menu_ && model_) {
- menu_.reset([[self menuFromModel:model_] retain]);
- // If this is to be used with a NSPopUpButtonCell, add an item at the 0th
- // position that's empty. Doing it after the menu has been constructed won't
- // complicate creation logic, and since the tags are model indexes, they
- // are unaffected by the extra item.
- if (useWithPopUpButtonCell_) {
- scoped_nsobject<NSMenuItem> blankItem(
- [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]);
- [menu_ insertItem:blankItem atIndex:0];
- }
- }
- return menu_.get();
-}
-
-@end
diff --git a/chrome/browser/cocoa/menu_controller_unittest.mm b/chrome/browser/cocoa/menu_controller_unittest.mm
deleted file mode 100644
index 448fa80..0000000
--- a/chrome/browser/cocoa/menu_controller_unittest.mm
+++ /dev/null
@@ -1,197 +0,0 @@
-// 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 "app/menus/simple_menu_model.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/cocoa/menu_controller.h"
-#include "grit/generated_resources.h"
-
-class MenuControllerTest : public CocoaTest {
-};
-
-// A menu delegate that counts the number of times certain things are called
-// to make sure things are hooked up properly.
-class Delegate : public menus::SimpleMenuModel::Delegate {
- public:
- Delegate() : execute_count_(0), enable_count_(0) { }
-
- virtual bool IsCommandIdChecked(int command_id) const { return false; }
- virtual bool IsCommandIdEnabled(int command_id) const {
- ++enable_count_;
- return true;
- }
- virtual bool GetAcceleratorForCommandId(
- int command_id,
- menus::Accelerator* accelerator) { return false; }
- virtual void ExecuteCommand(int command_id) { ++execute_count_; }
-
- int execute_count_;
- mutable int enable_count_;
-};
-
-TEST_F(MenuControllerTest, EmptyMenu) {
- Delegate delegate;
- menus::SimpleMenuModel model(&delegate);
- scoped_nsobject<MenuController> menu(
- [[MenuController alloc] initWithModel:&model useWithPopUpButtonCell:NO]);
- EXPECT_EQ([[menu menu] numberOfItems], 0);
-}
-
-TEST_F(MenuControllerTest, BasicCreation) {
- Delegate delegate;
- menus::SimpleMenuModel model(&delegate);
- model.AddItem(1, ASCIIToUTF16("one"));
- model.AddItem(2, ASCIIToUTF16("two"));
- model.AddItem(3, ASCIIToUTF16("three"));
- model.AddSeparator();
- model.AddItem(4, ASCIIToUTF16("four"));
- model.AddItem(5, ASCIIToUTF16("five"));
-
- scoped_nsobject<MenuController> menu(
- [[MenuController alloc] initWithModel:&model useWithPopUpButtonCell:NO]);
- EXPECT_EQ([[menu menu] numberOfItems], 6);
-
- // Check the title, tag, and represented object are correct for a random
- // element.
- NSMenuItem* itemTwo = [[menu menu] itemAtIndex:2];
- NSString* title = [itemTwo title];
- EXPECT_EQ(ASCIIToUTF16("three"), base::SysNSStringToUTF16(title));
- EXPECT_EQ([itemTwo tag], 2);
- EXPECT_EQ([[itemTwo representedObject] pointerValue], &model);
-
- EXPECT_TRUE([[[menu menu] itemAtIndex:3] isSeparatorItem]);
-}
-
-TEST_F(MenuControllerTest, Submenus) {
- Delegate delegate;
- menus::SimpleMenuModel model(&delegate);
- model.AddItem(1, ASCIIToUTF16("one"));
- menus::SimpleMenuModel submodel(&delegate);
- submodel.AddItem(2, ASCIIToUTF16("sub-one"));
- submodel.AddItem(3, ASCIIToUTF16("sub-two"));
- submodel.AddItem(4, ASCIIToUTF16("sub-three"));
- model.AddSubMenuWithStringId(5, IDS_ZOOM_MENU, &submodel);
- model.AddItem(6, ASCIIToUTF16("three"));
-
- scoped_nsobject<MenuController> menu(
- [[MenuController alloc] initWithModel:&model useWithPopUpButtonCell:NO]);
- EXPECT_EQ([[menu menu] numberOfItems], 3);
-
- // Inspect the submenu to ensure it has correct properties.
- NSMenu* submenu = [[[menu menu] itemAtIndex:1] submenu];
- EXPECT_TRUE(submenu);
- EXPECT_EQ([submenu numberOfItems], 3);
-
- // Inspect one of the items to make sure it has the correct model as its
- // represented object and the proper tag.
- NSMenuItem* submenuItem = [submenu itemAtIndex:1];
- NSString* title = [submenuItem title];
- EXPECT_EQ(ASCIIToUTF16("sub-two"), base::SysNSStringToUTF16(title));
- EXPECT_EQ([submenuItem tag], 1);
- EXPECT_EQ([[submenuItem representedObject] pointerValue], &submodel);
-
- // Make sure the item after the submenu is correct and its represented
- // object is back to the top model.
- NSMenuItem* item = [[menu menu] itemAtIndex:2];
- title = [item title];
- EXPECT_EQ(ASCIIToUTF16("three"), base::SysNSStringToUTF16(title));
- EXPECT_EQ([item tag], 2);
- EXPECT_EQ([[item representedObject] pointerValue], &model);
-}
-
-TEST_F(MenuControllerTest, EmptySubmenu) {
- Delegate delegate;
- menus::SimpleMenuModel model(&delegate);
- model.AddItem(1, ASCIIToUTF16("one"));
- menus::SimpleMenuModel submodel(&delegate);
- model.AddSubMenuWithStringId(2, IDS_ZOOM_MENU, &submodel);
-
- scoped_nsobject<MenuController> menu(
- [[MenuController alloc] initWithModel:&model useWithPopUpButtonCell:NO]);
- EXPECT_EQ([[menu menu] numberOfItems], 2);
-}
-
-TEST_F(MenuControllerTest, PopUpButton) {
- Delegate delegate;
- menus::SimpleMenuModel model(&delegate);
- model.AddItem(1, ASCIIToUTF16("one"));
- model.AddItem(2, ASCIIToUTF16("two"));
- model.AddItem(3, ASCIIToUTF16("three"));
-
- // Menu should have an extra item inserted at position 0 that has an empty
- // title.
- scoped_nsobject<MenuController> menu(
- [[MenuController alloc] initWithModel:&model useWithPopUpButtonCell:YES]);
- EXPECT_EQ([[menu menu] numberOfItems], 4);
- EXPECT_EQ(base::SysNSStringToUTF16([[[menu menu] itemAtIndex:0] title]),
- string16());
-
- // Make sure the tags are still correct (the index no longer matches the tag).
- NSMenuItem* itemTwo = [[menu menu] itemAtIndex:2];
- EXPECT_EQ([itemTwo tag], 1);
-}
-
-TEST_F(MenuControllerTest, Execute) {
- Delegate delegate;
- menus::SimpleMenuModel model(&delegate);
- model.AddItem(1, ASCIIToUTF16("one"));
- scoped_nsobject<MenuController> menu(
- [[MenuController alloc] initWithModel:&model useWithPopUpButtonCell:NO]);
- EXPECT_EQ([[menu menu] numberOfItems], 1);
-
- // Fake selecting the menu item, we expect the delegate to be told to execute
- // a command.
- NSMenuItem* item = [[menu menu] itemAtIndex:0];
- [[item target] performSelector:[item action] withObject:item];
- EXPECT_EQ(delegate.execute_count_, 1);
-}
-
-void Validate(MenuController* controller, NSMenu* menu) {
- for (int i = 0; i < [menu numberOfItems]; ++i) {
- NSMenuItem* item = [menu itemAtIndex:i];
- [controller validateUserInterfaceItem:item];
- if ([item hasSubmenu])
- Validate(controller, [item submenu]);
- }
-}
-
-TEST_F(MenuControllerTest, Validate) {
- Delegate delegate;
- menus::SimpleMenuModel model(&delegate);
- model.AddItem(1, ASCIIToUTF16("one"));
- model.AddItem(2, ASCIIToUTF16("two"));
- menus::SimpleMenuModel submodel(&delegate);
- submodel.AddItem(2, ASCIIToUTF16("sub-one"));
- model.AddSubMenuWithStringId(3, IDS_ZOOM_MENU, &submodel);
-
- scoped_nsobject<MenuController> menu(
- [[MenuController alloc] initWithModel:&model useWithPopUpButtonCell:NO]);
- EXPECT_EQ([[menu menu] numberOfItems], 3);
-
- Validate(menu.get(), [menu menu]);
-}
-
-TEST_F(MenuControllerTest, DefaultInitializer) {
- Delegate delegate;
- menus::SimpleMenuModel model(&delegate);
- model.AddItem(1, ASCIIToUTF16("one"));
- model.AddItem(2, ASCIIToUTF16("two"));
- model.AddItem(3, ASCIIToUTF16("three"));
-
- scoped_nsobject<MenuController> menu([[MenuController alloc] init]);
- EXPECT_FALSE([menu menu]);
-
- [menu setModel:&model];
- [menu setUseWithPopUpButtonCell:NO];
- EXPECT_TRUE([menu menu]);
- EXPECT_EQ(3, [[menu menu] numberOfItems]);
-
- // Check immutability.
- model.AddItem(4, ASCIIToUTF16("four"));
- EXPECT_EQ(3, [[menu menu] numberOfItems]);
-}
diff --git a/chrome/browser/cocoa/menu_tracked_button.h b/chrome/browser/cocoa/menu_tracked_button.h
deleted file mode 100644
index 84ed154..0000000
--- a/chrome/browser/cocoa/menu_tracked_button.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_MENU_TRACKED_BUTTON_H_
-#define CHROME_BROWSER_COCOA_MENU_TRACKED_BUTTON_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-// A MenuTrackedButton is meant to be used whenever a button is placed inside
-// the custom view of an NSMenuItem. If the user opens the menu in a non-sticky
-// fashion (i.e. clicks, holds, and drags) and then releases the mouse over
-// a MenuTrackedButton, it will |-performClick:| itself.
-//
-// To create the hover state effects, there are two code paths. When the menu
-// is opened sticky, a tracking rect produces mouse entered/exit events that
-// allow for setting the cell's highlight property. When in a drag cycle,
-// however, the only event received is |-mouseDragged:|. Therefore, a
-// delayed selector is scheduled to poll the mouse location after each drag
-// event. This checks if the user is still over the button after the drag
-// events stop being sent, indicating either the user is hovering without
-// movement or that the mouse is no longer over the receiver.
-@interface MenuTrackedButton : NSButton {
- @private
- // If the button received a |-mouseEntered:| event. This short-circuits the
- // custom drag tracking logic.
- BOOL didEnter_;
-
- // Whether or not the user is in a click-drag-release event sequence. If so
- // and this receives a |-mouseUp:|, then this will click itself.
- BOOL tracking_;
-
- // In order to get hover effects when the menu is sticky-opened, a tracking
- // rect needs to be installed on the button.
- NSTrackingRectTag trackingTag_;
-}
-
-@property (nonatomic, readonly, getter=isTracking) BOOL tracking;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_MENU_TRACKED_BUTTON_H_
diff --git a/chrome/browser/cocoa/menu_tracked_button.mm b/chrome/browser/cocoa/menu_tracked_button.mm
deleted file mode 100644
index 247417d..0000000
--- a/chrome/browser/cocoa/menu_tracked_button.mm
+++ /dev/null
@@ -1,118 +0,0 @@
-// 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 "chrome/browser/cocoa/menu_tracked_button.h"
-
-#include <cmath>
-
-@interface MenuTrackedButton (Private)
-- (void)doHighlight:(BOOL)highlight;
-- (void)checkMouseInRect;
-- (NSRect)insetBounds;
-- (BOOL)shouldHighlightOnHover;
-@end
-
-@implementation MenuTrackedButton
-
-@synthesize tracking = tracking_;
-
-- (void)updateTrackingAreas {
- [super updateTrackingAreas];
- [self removeTrackingRect:trackingTag_];
- trackingTag_ = [self addTrackingRect:NSInsetRect([self bounds], 1, 1)
- owner:self
- userData:NULL
- assumeInside:NO];
-}
-
-- (void)viewDidMoveToWindow {
- [self updateTrackingAreas];
- [self doHighlight:NO];
-}
-
-- (void)mouseEntered:(NSEvent*)theEvent {
- if (!tracking_) {
- didEnter_ = YES;
- }
- [self doHighlight:YES];
- [super mouseEntered:theEvent];
-}
-
-- (void)mouseExited:(NSEvent*)theEvent {
- didEnter_ = NO;
- tracking_ = NO;
- [self doHighlight:NO];
- [super mouseExited:theEvent];
-}
-
-- (void)mouseDragged:(NSEvent*)theEvent {
- tracking_ = !didEnter_;
-
- NSPoint point = [self convertPoint:[theEvent locationInWindow] fromView:nil];
- BOOL highlight = NSPointInRect(point, [self insetBounds]);
- [self doHighlight:highlight];
-
- // If tracking in non-sticky mode, poll the mouse cursor to see if it is still
- // over the button and thus needs to be highlighted. The delay is the
- // smallest that still produces the effect while minimizing jank. Smaller
- // values make the selector fire too close to immediately/now for the mouse to
- // have moved off the receiver, and larger values produce lag.
- if (tracking_ && [self shouldHighlightOnHover]) {
- [self performSelector:@selector(checkMouseInRect)
- withObject:nil
- afterDelay:0.05
- inModes:[NSArray arrayWithObject:NSEventTrackingRunLoopMode]];
- }
- [super mouseDragged:theEvent];
-}
-
-- (void)mouseUp:(NSEvent*)theEvent {
- [self doHighlight:NO];
- if (!tracking_) {
- return [super mouseUp:theEvent];
- }
- [self performClick:self];
- tracking_ = NO;
-}
-
-- (void)doHighlight:(BOOL)highlight {
- if (![self shouldHighlightOnHover]) {
- return;
- }
- [[self cell] setHighlighted:highlight];
- [self setNeedsDisplay];
-}
-
-// Checks if the user's current mouse location is over this button. If it is,
-// the user is merely hovering here. If it is not, then disable the highlight.
-// If the menu is opened in non-sticky mode, the button does not receive enter/
-// exit mouse events and thus polling is necessary.
-- (void)checkMouseInRect {
- NSPoint point = [NSEvent mouseLocation];
- point = [[self window] convertScreenToBase:point];
- point = [self convertPoint:point fromView:nil];
- if (!NSPointInRect(point, [self insetBounds])) {
- [self doHighlight:NO];
- }
-}
-
-// Returns the bounds of the receiver slightly inset to avoid highlighting both
-// buttons in a pair that overlap.
-- (NSRect)insetBounds {
- return NSInsetRect([self bounds], 2, 1);
-}
-
-- (BOOL)shouldHighlightOnHover {
- // Apple does not define NSAppKitVersionNumber10_5 when using the 10.5 SDK.
- // The Internets have come up with this solution.
- #ifndef NSAppKitVersionNumber10_5
- #define NSAppKitVersionNumber10_5 949
- #endif
-
- // There's a cell drawing bug in 10.5 that was fixed on 10.6. Hover states
- // look terrible due to this, so disable highlighting on 10.5.
- return std::floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5;
-}
-
-@end
diff --git a/chrome/browser/cocoa/menu_tracked_button_unittest.mm b/chrome/browser/cocoa/menu_tracked_button_unittest.mm
deleted file mode 100644
index b900db6..0000000
--- a/chrome/browser/cocoa/menu_tracked_button_unittest.mm
+++ /dev/null
@@ -1,117 +0,0 @@
-// 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 "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/menu_tracked_button.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-// This test does not test what you'd think it does. Testing around event
-// tracking run loops is probably not worh the effort when the size of the
-// helper MakeEvent() is larger than the class being tested. If we ever figure
-// out a good way to test event tracking, this should be revisited.
-
-@interface MenuTrackedButtonTestReceiver : NSObject {
- @public
- BOOL didThat_;
-}
-- (void)doThat:(id)sender;
-@end
-@implementation MenuTrackedButtonTestReceiver
-- (void)doThat:(id)sender {
- didThat_ = YES;
-}
-@end
-
-
-class MenuTrackedButtonTest : public CocoaTest {
- public:
- MenuTrackedButtonTest() : event_number_(0) {}
-
- void SetUp() {
- listener_.reset([[MenuTrackedButtonTestReceiver alloc] init]);
- button_.reset(
- [[MenuTrackedButton alloc] initWithFrame:NSMakeRect(10, 10, 50, 50)]);
- [[test_window() contentView] addSubview:button()];
- [button_ setTarget:listener()];
- [button_ setAction:@selector(doThat:)];
- }
-
- // Creates an event of |type|, with |location| in test_window()'s coordinates.
- NSEvent* MakeEvent(NSEventType type, NSPoint location) {
- NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
- location = [test_window() convertBaseToScreen:location];
- if (type == NSMouseEntered || type == NSMouseExited) {
- return [NSEvent enterExitEventWithType:type
- location:location
- modifierFlags:0
- timestamp:now
- windowNumber:[test_window() windowNumber]
- context:nil
- eventNumber:event_number_++
- trackingNumber:0
- userData:nil];
- } else {
- return [NSEvent mouseEventWithType:type
- location:location
- modifierFlags:0
- timestamp:now
- windowNumber:[test_window() windowNumber]
- context:nil
- eventNumber:event_number_++
- clickCount:1
- pressure:1.0];
- }
- }
-
- MenuTrackedButtonTestReceiver* listener() { return listener_.get(); }
- NSButton* button() { return button_.get(); }
-
- scoped_nsobject<MenuTrackedButtonTestReceiver> listener_;
- scoped_nsobject<MenuTrackedButton> button_;
- NSInteger event_number_;
-};
-
-// User mouses over and then off.
-TEST_F(MenuTrackedButtonTest, DISABLED_EnterExit) {
- [NSApp postEvent:MakeEvent(NSMouseEntered, NSMakePoint(11, 11)) atStart:YES];
- [NSApp postEvent:MakeEvent(NSMouseExited, NSMakePoint(9, 9)) atStart:YES];
- EXPECT_FALSE(listener()->didThat_);
-}
-
-// User mouses over, clicks, drags, and exits.
-TEST_F(MenuTrackedButtonTest, DISABLED_EnterDragExit) {
- [NSApp postEvent:MakeEvent(NSMouseEntered, NSMakePoint(11, 11)) atStart:YES];
- [NSApp postEvent:MakeEvent(NSLeftMouseDown, NSMakePoint(12, 12)) atStart:YES];
- [NSApp postEvent:MakeEvent(NSLeftMouseDragged, NSMakePoint(13, 11))
- atStart:YES];
- [NSApp postEvent:MakeEvent(NSLeftMouseDragged, NSMakePoint(13, 10))
- atStart:YES];
- [NSApp postEvent:MakeEvent(NSMouseExited, NSMakePoint(13, 9)) atStart:YES];
- EXPECT_FALSE(listener()->didThat_);
-}
-
-// User mouses over, clicks, drags, and releases.
-TEST_F(MenuTrackedButtonTest, DISABLED_EnterDragUp) {
- [NSApp postEvent:MakeEvent(NSMouseEntered, NSMakePoint(11, 11)) atStart:YES];
- [NSApp postEvent:MakeEvent(NSLeftMouseDown, NSMakePoint(12, 12)) atStart:YES];
- [NSApp postEvent:MakeEvent(NSLeftMouseDragged, NSMakePoint(13, 13))
- atStart:YES];
- [NSApp postEvent:MakeEvent(NSLeftMouseUp, NSMakePoint(14, 14)) atStart:YES];
- EXPECT_TRUE(listener()->didThat_);
-}
-
-// User drags in and releases.
-TEST_F(MenuTrackedButtonTest, DISABLED_DragUp) {
- [NSApp postEvent:MakeEvent(NSLeftMouseDragged, NSMakePoint(11, 11))
- atStart:YES];
- [NSApp postEvent:MakeEvent(NSLeftMouseDragged, NSMakePoint(12, 12))
- atStart:YES];
- [NSApp postEvent:MakeEvent(NSLeftMouseUp, NSMakePoint(13, 13))
- atStart:YES];
- EXPECT_TRUE(listener()->didThat_);
-}
diff --git a/chrome/browser/cocoa/menu_tracked_root_view.h b/chrome/browser/cocoa/menu_tracked_root_view.h
deleted file mode 100644
index 6d4bffa..0000000
--- a/chrome/browser/cocoa/menu_tracked_root_view.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_MENU_TRACKED_ROOT_VIEW_H_
-#define CHROME_BROWSER_COCOA_MENU_TRACKED_ROOT_VIEW_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-// An instance of MenuTrackedRootView should be the root of the view hierarchy
-// of the custom view of NSMenuItems. If the user opens the menu in a non-
-// sticky fashion (i.e. clicks, holds, and drags) and then releases the mouse
-// over the menu item, it will cancel tracking on the |[menuItem_ menu]|.
-@interface MenuTrackedRootView : NSView {
- @private
- // The menu item whose custom view's root view is an instance of this class.
- NSMenuItem* menuItem_; // weak
-}
-
-@property (assign, nonatomic) NSMenuItem* menuItem;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_MENU_TRACKED_ROOT_VIEW_H_
diff --git a/chrome/browser/cocoa/menu_tracked_root_view.mm b/chrome/browser/cocoa/menu_tracked_root_view.mm
deleted file mode 100644
index ef3c246..0000000
--- a/chrome/browser/cocoa/menu_tracked_root_view.mm
+++ /dev/null
@@ -1,15 +0,0 @@
-// 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 "chrome/browser/cocoa/menu_tracked_root_view.h"
-
-@implementation MenuTrackedRootView
-
-@synthesize menuItem = menuItem_;
-
-- (void)mouseUp:(NSEvent*)theEvent {
- [[menuItem_ menu] cancelTracking];
-}
-
-@end
diff --git a/chrome/browser/cocoa/menu_tracked_root_view_unittest.mm b/chrome/browser/cocoa/menu_tracked_root_view_unittest.mm
deleted file mode 100644
index f2e5f2c..0000000
--- a/chrome/browser/cocoa/menu_tracked_root_view_unittest.mm
+++ /dev/null
@@ -1,45 +0,0 @@
-// 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 "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/menu_tracked_root_view.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-#import "third_party/ocmock/OCMock/OCMock.h"
-
-class MenuTrackedRootViewTest : public CocoaTest {
- public:
- void SetUp() {
- CocoaTest::SetUp();
- view_.reset([[MenuTrackedRootView alloc] init]);
- }
-
- scoped_nsobject<MenuTrackedRootView> view_;
-};
-
-TEST_F(MenuTrackedRootViewTest, MouseUp) {
- id menu = [OCMockObject mockForClass:[NSMenu class]];
- [[menu expect] cancelTracking];
-
- id menuItem = [OCMockObject mockForClass:[NSMenuItem class]];
- [[[menuItem stub] andReturn:menu] menu];
-
- [view_ setMenuItem:menuItem];
- NSEvent* event = [NSEvent mouseEventWithType:NSLeftMouseUp
- location:NSMakePoint(42, 42)
- modifierFlags:0
- timestamp:0
- windowNumber:[test_window() windowNumber]
- context:nil
- eventNumber:1
- clickCount:1
- pressure:1.0];
- [view_ mouseUp:event];
-
- [menu verify];
- [menuItem verify];
-}
diff --git a/chrome/browser/cocoa/multi_key_equivalent_button.h b/chrome/browser/cocoa/multi_key_equivalent_button.h
deleted file mode 100644
index 5342a21..0000000
--- a/chrome/browser/cocoa/multi_key_equivalent_button.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_MULTI_KEY_EQUIVALENT_BUTTON_H_
-#define CHROME_BROWSER_COCOA_MULTI_KEY_EQUIVALENT_BUTTON_H_
-#pragma once
-
-#import <AppKit/AppKit.h>
-
-#include <vector>
-
-struct KeyEquivalentAndModifierMask {
- public:
- KeyEquivalentAndModifierMask() : charCode(nil), mask(0) {}
- NSString* charCode;
- NSUInteger mask;
-};
-
-// MultiKeyEquivalentButton is an NSButton subclass that is capable of
-// responding to additional key equivalents. It will respond to the ordinary
-// NSButton key equivalent set by -setKeyEquivalent: and
-// -setKeyEquivalentModifierMask:, and it will also respond to any additional
-// equivalents provided to it in a KeyEquivalentAndModifierMask structure
-// passed to -addKeyEquivalent:.
-
-@interface MultiKeyEquivalentButton : NSButton {
- @private
- std::vector<KeyEquivalentAndModifierMask> extraKeys_;
-}
-
-- (void)addKeyEquivalent:(KeyEquivalentAndModifierMask)key;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_MULTI_KEY_EQUIVALENT_BUTTON_H_
diff --git a/chrome/browser/cocoa/multi_key_equivalent_button.mm b/chrome/browser/cocoa/multi_key_equivalent_button.mm
deleted file mode 100644
index fc10160..0000000
--- a/chrome/browser/cocoa/multi_key_equivalent_button.mm
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/multi_key_equivalent_button.h"
-
-@implementation MultiKeyEquivalentButton
-
-- (void)addKeyEquivalent:(KeyEquivalentAndModifierMask)key {
- extraKeys_.push_back(key);
-}
-
-- (BOOL)performKeyEquivalent:(NSEvent*)event {
- NSWindow* modalWindow = [NSApp modalWindow];
- NSWindow* window = [self window];
-
- if ([self isEnabled] &&
- (!modalWindow || modalWindow == window || [window worksWhenModal])) {
- for (size_t index = 0; index < extraKeys_.size(); ++index) {
- KeyEquivalentAndModifierMask key = extraKeys_[index];
- if (key.charCode &&
- [key.charCode isEqualToString:[event charactersIgnoringModifiers]] &&
- ([event modifierFlags] & key.mask) == key.mask) {
- [self performClick:self];
- return YES;
- }
- }
- }
-
- return [super performKeyEquivalent:event];
-}
-
-@end
diff --git a/chrome/browser/cocoa/new_tab_button.h b/chrome/browser/cocoa/new_tab_button.h
deleted file mode 100644
index 7315ec0..0000000
--- a/chrome/browser/cocoa/new_tab_button.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_NEW_TAB_BUTTON
-#define CHROME_BROWSER_COCOA_NEW_TAB_BUTTON
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_nsobject.h"
-
-// Overrides hit-test behavior to only accept clicks inside the image of the
-// button, not just inside the bounding box. This could be abstracted to general
-// use, but no other buttons are so irregularly shaped with respect to their
-// bounding box.
-
-@interface NewTabButton : NSButton {
- @private
- scoped_nsobject<NSBezierPath> imagePath_;
-}
-
-// Returns YES if the given point is over the button. |point| is in the
-// superview's coordinate system.
-- (BOOL)pointIsOverButton:(NSPoint)point;
-@end
-
-#endif // CHROME_BROWSER_COCOA_NEW_TAB_BUTTON
diff --git a/chrome/browser/cocoa/new_tab_button.mm b/chrome/browser/cocoa/new_tab_button.mm
deleted file mode 100644
index bc92485..0000000
--- a/chrome/browser/cocoa/new_tab_button.mm
+++ /dev/null
@@ -1,42 +0,0 @@
-// 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 "chrome/browser/cocoa/new_tab_button.h"
-
-@implementation NewTabButton
-
-// Approximate the shape. It doesn't need to be perfect. This will need to be
-// updated if the size or shape of the icon ever changes.
-// TODO(pinkerton): use a click mask image instead of hard-coding points.
-- (NSBezierPath*)pathForButton {
- if (imagePath_.get())
- return imagePath_.get();
-
- // Cache the path as it doesn't change (the coordinates are local to this
- // view). There's not much point making constants for these, as they are
- // custom.
- imagePath_.reset([[NSBezierPath bezierPath] retain]);
- [imagePath_ moveToPoint:NSMakePoint(9, 7)];
- [imagePath_ lineToPoint:NSMakePoint(26, 7)];
- [imagePath_ lineToPoint:NSMakePoint(33, 23)];
- [imagePath_ lineToPoint:NSMakePoint(14, 23)];
- [imagePath_ lineToPoint:NSMakePoint(9, 7)];
- return imagePath_;
-}
-
-- (BOOL)pointIsOverButton:(NSPoint)point {
- NSPoint localPoint = [self convertPoint:point fromView:[self superview]];
- NSBezierPath* buttonPath = [self pathForButton];
- return [buttonPath containsPoint:localPoint];
-}
-
-// Override to only accept clicks within the bounds of the defined path, not
-// the entire bounding box. |aPoint| is in the superview's coordinate system.
-- (NSView*)hitTest:(NSPoint)aPoint {
- if ([self pointIsOverButton:aPoint])
- return [super hitTest:aPoint];
- return nil;
-}
-
-@end
diff --git a/chrome/browser/cocoa/notifications/balloon_controller.h b/chrome/browser/cocoa/notifications/balloon_controller.h
deleted file mode 100644
index 03f8e4f..0000000
--- a/chrome/browser/cocoa/notifications/balloon_controller.h
+++ /dev/null
@@ -1,98 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_NOTIFICATIONS_BALLOON_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_NOTIFICATIONS_BALLOON_CONTROLLER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/cocoa_protocols_mac.h"
-#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-
-class Balloon;
-@class BalloonContentViewCocoa;
-@class BalloonShelfViewCocoa;
-class BalloonViewHost;
-@class HoverImageButton;
-@class MenuController;
-class NotificationOptionsMenuModel;
-
-// The Balloon controller creates the view elements to display a
-// notification balloon, resize it if the HTML contents of that
-// balloon change, and move it when the collection of balloons is
-// modified.
-@interface BalloonController : NSWindowController<NSWindowDelegate> {
- @private
- // The balloon which represents the contents of this view. Weak pointer
- // owned by the browser's NotificationUIManager.
- Balloon* balloon_;
-
- // The view that contains the contents of the notification
- IBOutlet BalloonContentViewCocoa* htmlContainer_;
-
- // The view that contains the controls of the notification
- IBOutlet BalloonShelfViewCocoa* shelf_;
-
- // The close button.
- IBOutlet NSButton* closeButton_;
-
- // Tracking region for the close button.
- int closeButtonTrackingTag_;
-
- // The origin label.
- IBOutlet NSTextField* originLabel_;
-
- // The options menu that appears when "options" is pressed.
- IBOutlet HoverImageButton* optionsButton_;
- scoped_ptr<NotificationOptionsMenuModel> menuModel_;
- scoped_nsobject<MenuController> menuController_;
-
- // The host for the renderer of the HTML contents.
- scoped_ptr<BalloonViewHost> htmlContents_;
-
- // The psn of the front application process.
- ProcessSerialNumber frontProcessNum_;
-}
-
-// Initialize with a balloon object containing the notification data.
-- (id)initWithBalloon:(Balloon*)balloon;
-
-// Callback function for the close button.
-- (IBAction)closeButtonPressed:(id)sender;
-
-// Callback function for the options button.
-- (IBAction)optionsButtonPressed:(id)sender;
-
-// Callback function for the "revoke" option in the menu.
-- (IBAction)permissionRevoked:(id)sender;
-
-// Closes the balloon. Can be called by the bridge or by the close
-// button handler.
-- (void)closeBalloon:(bool)byUser;
-
-// Update the contents of the balloon to match the notification.
-- (void)updateContents;
-
-// Repositions the view to match the position and size of the balloon.
-// Called by the bridge when the size changes.
-- (void)repositionToBalloon;
-
-// The current size of the view, possibly subject to an animation completing.
-- (int)desiredTotalWidth;
-- (int)desiredTotalHeight;
-
-// The BalloonHost
-- (BalloonViewHost*)getHost;
-
-// Handle the event if it is for the balloon.
-- (BOOL)handleEvent:(NSEvent*)event;
-@end
-
-@interface BalloonController (UnitTesting)
-- (void)initializeHost;
-@end
-
-#endif // CHROME_BROWSER_COCOA_NOTIFICATIONS_BALLOON_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/notifications/balloon_controller.mm b/chrome/browser/cocoa/notifications/balloon_controller.mm
deleted file mode 100644
index 048888c..0000000
--- a/chrome/browser/cocoa/notifications/balloon_controller.mm
+++ /dev/null
@@ -1,241 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/notifications/balloon_controller.h"
-
-#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
-#import "base/cocoa_protocols_mac.h"
-#include "base/mac_util.h"
-#include "base/nsimage_cache_mac.h"
-#import "base/scoped_nsobject.h"
-#include "base/utf_string_conversions.h"
-#import "chrome/browser/cocoa/hover_image_button.h"
-#import "chrome/browser/cocoa/menu_controller.h"
-#import "chrome/browser/cocoa/notifications/balloon_view.h"
-#include "chrome/browser/cocoa/notifications/balloon_view_host_mac.h"
-#include "chrome/browser/notifications/balloon.h"
-#include "chrome/browser/notifications/desktop_notification_service.h"
-#include "chrome/browser/notifications/notification.h"
-#include "chrome/browser/notifications/notification_options_menu_model.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/renderer_host/render_view_host.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-
-namespace {
-
-// Margin, in pixels, between the notification frame and the contents
-// of the notification.
-const int kTopMargin = 1;
-const int kBottomMargin = 2;
-const int kLeftMargin = 2;
-const int kRightMargin = 2;
-
-} // namespace
-
-@interface BalloonController (Private)
-- (void)updateTrackingRect;
-@end
-
-@implementation BalloonController
-
-- (id)initWithBalloon:(Balloon*)balloon {
- NSString* nibpath =
- [mac_util::MainAppBundle() pathForResource:@"Notification"
- ofType:@"nib"];
- if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
- balloon_ = balloon;
- [self initializeHost];
- menuModel_.reset(new NotificationOptionsMenuModel(balloon));
- menuController_.reset([[MenuController alloc] initWithModel:menuModel_.get()
- useWithPopUpButtonCell:NO]);
- }
- return self;
-}
-
-- (void)awakeFromNib {
- DCHECK([self window]);
- DCHECK_EQ(self, [[self window] delegate]);
-
- NSImage* image = nsimage_cache::ImageNamed(@"balloon_wrench.pdf");
- [optionsButton_ setDefaultImage:image];
- [optionsButton_ setDefaultOpacity:0.6];
- [optionsButton_ setHoverImage:image];
- [optionsButton_ setHoverOpacity:0.9];
- [optionsButton_ setPressedImage:image];
- [optionsButton_ setPressedOpacity:1.0];
- [[optionsButton_ cell] setHighlightsBy:NSNoCellMask];
-
- NSString* sourceLabelText = l10n_util::GetNSStringF(
- IDS_NOTIFICATION_BALLOON_SOURCE_LABEL,
- balloon_->notification().display_source());
- [originLabel_ setStringValue:sourceLabelText];
-
- // This condition is false in unit tests which have no RVH.
- if (htmlContents_.get()) {
- gfx::NativeView contents = htmlContents_->native_view();
- [contents setFrame:NSMakeRect(kLeftMargin, kTopMargin, 0, 0)];
- [[htmlContainer_ superview] addSubview:contents
- positioned:NSWindowBelow
- relativeTo:nil];
- }
-
- // Use the standard close button for a utility window.
- closeButton_ = [NSWindow standardWindowButton:NSWindowCloseButton
- forStyleMask:NSUtilityWindowMask];
- NSRect frame = [closeButton_ frame];
- [closeButton_ setFrame:NSMakeRect(6, 1, frame.size.width, frame.size.height)];
- [closeButton_ setTarget:self];
- [closeButton_ setAction:@selector(closeButtonPressed:)];
- [shelf_ addSubview:closeButton_];
- [self updateTrackingRect];
-
- // Set the initial position without animating (the balloon should not
- // yet be visible).
- DCHECK(![[self window] isVisible]);
- NSRect balloon_frame = NSMakeRect(balloon_->GetPosition().x(),
- balloon_->GetPosition().y(),
- [self desiredTotalWidth],
- [self desiredTotalHeight]);
- [[self window] setFrame:balloon_frame
- display:NO];
-}
-
-- (void)updateTrackingRect {
- if (closeButtonTrackingTag_)
- [shelf_ removeTrackingRect:closeButtonTrackingTag_];
-
- closeButtonTrackingTag_ = [shelf_ addTrackingRect:[closeButton_ frame]
- owner:self
- userData:nil
- assumeInside:NO];
-}
-
-- (BOOL)handleEvent:(NSEvent*)event {
- BOOL eventHandled = NO;
- if ([event type] == NSLeftMouseDown) {
- NSPoint mouse = [shelf_ convertPoint:[event locationInWindow]
- fromView:nil];
- if (NSPointInRect(mouse, [closeButton_ frame])) {
- [closeButton_ mouseDown:event];
-
- // Bring back the front process that is deactivated when we click the
- // close button.
- if (frontProcessNum_.highLongOfPSN || frontProcessNum_.lowLongOfPSN) {
- SetFrontProcessWithOptions(&frontProcessNum_,
- kSetFrontProcessFrontWindowOnly);
- frontProcessNum_.highLongOfPSN = 0;
- frontProcessNum_.lowLongOfPSN = 0;
- }
-
- eventHandled = YES;
- } else if (NSPointInRect(mouse, [optionsButton_ frame])) {
- [optionsButton_ mouseDown:event];
- eventHandled = YES;
- }
- }
- return eventHandled;
-}
-
-- (void) mouseEntered:(NSEvent*)event {
- [[closeButton_ cell] setHighlighted:YES];
-
- // Remember the current front process so that we can bring it back later.
- if (!frontProcessNum_.highLongOfPSN && !frontProcessNum_.lowLongOfPSN)
- GetFrontProcess(&frontProcessNum_);
-}
-
-- (void) mouseExited:(NSEvent*)event {
- [[closeButton_ cell] setHighlighted:NO];
-
- frontProcessNum_.highLongOfPSN = 0;
- frontProcessNum_.lowLongOfPSN = 0;
-}
-
-- (IBAction)optionsButtonPressed:(id)sender {
- [NSMenu popUpContextMenu:[menuController_ menu]
- withEvent:[NSApp currentEvent]
- forView:optionsButton_];
-}
-
-- (IBAction)permissionRevoked:(id)sender {
- DesktopNotificationService* service =
- balloon_->profile()->GetDesktopNotificationService();
- service->DenyPermission(balloon_->notification().origin_url());
-}
-
-- (IBAction)closeButtonPressed:(id)sender {
- [self closeBalloon:YES];
- [self close];
-}
-
-- (void)close {
- if (closeButtonTrackingTag_)
- [shelf_ removeTrackingRect:closeButtonTrackingTag_];
-
- [super close];
-}
-
-- (void)closeBalloon:(bool)byUser {
- if (!balloon_)
- return;
- [self close];
- if (htmlContents_.get())
- htmlContents_->Shutdown();
- if (balloon_)
- balloon_->OnClose(byUser);
- balloon_ = NULL;
-}
-
-- (void)updateContents {
- DCHECK(htmlContents_.get()) << "BalloonView::Update called before Show";
- if (htmlContents_->render_view_host())
- htmlContents_->render_view_host()->NavigateToURL(
- balloon_->notification().content_url());
-}
-
-- (void)repositionToBalloon {
- DCHECK(balloon_);
- int x = balloon_->GetPosition().x();
- int y = balloon_->GetPosition().y();
- int w = [self desiredTotalWidth];
- int h = [self desiredTotalHeight];
-
- if (htmlContents_.get())
- htmlContents_->UpdateActualSize(balloon_->content_size());
-
- [[[self window] animator] setFrame:NSMakeRect(x, y, w, h)
- display:YES];
-}
-
-// Returns the total width the view should be to accommodate the balloon.
-- (int)desiredTotalWidth {
- return (balloon_ ? balloon_->content_size().width() : 0) +
- kLeftMargin + kRightMargin;
-}
-
-// Returns the total height the view should be to accommodate the balloon.
-- (int)desiredTotalHeight {
- return (balloon_ ? balloon_->content_size().height() : 0) +
- kTopMargin + kBottomMargin + [shelf_ frame].size.height;
-}
-
-// Returns the BalloonHost {
-- (BalloonViewHost*) getHost {
- return htmlContents_.get();
-}
-
-// Initializes the renderer host showing the HTML contents.
-- (void)initializeHost {
- htmlContents_.reset(new BalloonViewHost(balloon_));
- htmlContents_->Init();
-}
-
-// NSWindowDelegate notification.
-- (void)windowWillClose:(NSNotification*)notif {
- [self autorelease];
-}
-
-@end
diff --git a/chrome/browser/cocoa/notifications/balloon_controller_unittest.mm b/chrome/browser/cocoa/notifications/balloon_controller_unittest.mm
deleted file mode 100644
index 436fe31..0000000
--- a/chrome/browser/cocoa/notifications/balloon_controller_unittest.mm
+++ /dev/null
@@ -1,113 +0,0 @@
-// 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.
-
-#include "base/scoped_nsobject.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/cocoa/notifications/balloon_controller.h"
-#include "chrome/browser/notifications/balloon.h"
-#include "chrome/browser/notifications/balloon_collection.h"
-#include "chrome/browser/notifications/notification.h"
-#include "chrome/browser/renderer_host/test/test_render_view_host.h"
-#include "chrome/test/testing_profile.h"
-#import "third_party/ocmock/OCMock/OCMock.h"
-
-// Subclass balloon controller and mock out the initialization of the RVH.
-@interface TestBalloonController : BalloonController {
-}
-- (void)initializeHost;
-@end
-
-@implementation TestBalloonController
-- (void)initializeHost {}
-@end
-
-namespace {
-
-// Use a dummy balloon collection for testing.
-class MockBalloonCollection : public BalloonCollection {
- virtual void Add(const Notification& notification,
- Profile* profile) {}
- virtual bool RemoveById(const std::string& id) { return false; }
- virtual bool RemoveBySourceOrigin(const GURL& origin) { return false; }
- virtual void RemoveAll() {}
- virtual bool HasSpace() const { return true; }
- virtual void ResizeBalloon(Balloon* balloon, const gfx::Size& size) {};
- virtual void DisplayChanged() {}
- virtual void OnBalloonClosed(Balloon* source) {};
- virtual const Balloons& GetActiveBalloons() {
- NOTREACHED();
- return balloons_;
- }
- private:
- Balloons balloons_;
-};
-
-class BalloonControllerTest : public RenderViewHostTestHarness {
- public:
- BalloonControllerTest() :
- ui_thread_(BrowserThread::UI, MessageLoop::current()),
- io_thread_(BrowserThread::IO, MessageLoop::current()) {
- }
-
- virtual void SetUp() {
- RenderViewHostTestHarness::SetUp();
- CocoaTest::BootstrapCocoa();
- profile_.reset(new TestingProfile());
- profile_->CreateRequestContext();
- browser_.reset(new Browser(Browser::TYPE_NORMAL, profile_.get()));
- collection_.reset(new MockBalloonCollection());
- }
-
- virtual void TearDown() {
- MessageLoop::current()->RunAllPending();
- RenderViewHostTestHarness::TearDown();
- }
-
- protected:
- BrowserThread ui_thread_;
- BrowserThread io_thread_;
- scoped_ptr<TestingProfile> profile_;
- scoped_ptr<Browser> browser_;
- scoped_ptr<BalloonCollection> collection_;
-};
-
-TEST_F(BalloonControllerTest, ShowAndCloseTest) {
- Notification n(GURL("http://www.google.com"), GURL("http://www.google.com"),
- ASCIIToUTF16("http://www.google.com"), string16(),
- new NotificationObjectProxy(-1, -1, -1, false));
- scoped_ptr<Balloon> balloon(
- new Balloon(n, profile_.get(), collection_.get()));
- balloon->SetPosition(gfx::Point(1, 1), false);
- balloon->set_content_size(gfx::Size(100, 100));
-
- BalloonController* controller =
- [[TestBalloonController alloc] initWithBalloon:balloon.get()];
-
- [controller showWindow:nil];
- [controller closeBalloon:YES];
-}
-
-TEST_F(BalloonControllerTest, SizesTest) {
- Notification n(GURL("http://www.google.com"), GURL("http://www.google.com"),
- ASCIIToUTF16("http://www.google.com"), string16(),
- new NotificationObjectProxy(-1, -1, -1, false));
- scoped_ptr<Balloon> balloon(
- new Balloon(n, profile_.get(), collection_.get()));
- balloon->SetPosition(gfx::Point(1, 1), false);
- balloon->set_content_size(gfx::Size(100, 100));
-
- BalloonController* controller =
- [[TestBalloonController alloc] initWithBalloon:balloon.get()];
-
- [controller showWindow:nil];
-
- EXPECT_TRUE([controller desiredTotalWidth] > 100);
- EXPECT_TRUE([controller desiredTotalHeight] > 100);
-
- [controller closeBalloon:YES];
-}
-
-}
diff --git a/chrome/browser/cocoa/notifications/balloon_view.h b/chrome/browser/cocoa/notifications/balloon_view.h
deleted file mode 100644
index 819df68..0000000
--- a/chrome/browser/cocoa/notifications/balloon_view.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_NOTIFICATIONS_BALLOON_VIEW_H_
-#define CHROME_BROWSER_COCOA_NOTIFICATIONS_BALLOON_VIEW_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-@interface BalloonWindow : NSWindow {
-}
-@end
-
-// This view class draws a frame around the HTML contents of a
-// notification balloon.
-@interface BalloonContentViewCocoa : NSView {
-}
-@end
-
-// This view class draws the shelf of a notification balloon,
-// containing the controls.
-@interface BalloonShelfViewCocoa : NSView {
-}
-@end
-
-
-#endif // CHROME_BROWSER_COCOA_NOTIFICATIONS_BALLOON_VIEW_H_
diff --git a/chrome/browser/cocoa/notifications/balloon_view.mm b/chrome/browser/cocoa/notifications/balloon_view.mm
deleted file mode 100644
index 0c2e83e..0000000
--- a/chrome/browser/cocoa/notifications/balloon_view.mm
+++ /dev/null
@@ -1,84 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/notifications/balloon_view.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/basictypes.h"
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/notifications/balloon_controller.h"
-#import "third_party/GTM/AppKit/GTMNSBezierPath+RoundRect.h"
-
-namespace {
-
-const int kRoundedCornerSize = 6;
-
-} // namespace
-
-@implementation BalloonWindow
-- (id)initWithContentRect:(NSRect)contentRect
- styleMask:(unsigned int)aStyle
- backing:(NSBackingStoreType)bufferingType
- defer:(BOOL)flag {
- self = [super initWithContentRect:contentRect
- styleMask:NSBorderlessWindowMask
- backing:NSBackingStoreBuffered
- defer:NO];
- if (self) {
- [self setLevel:NSStatusWindowLevel];
- [self setOpaque:NO];
- [self setBackgroundColor:[NSColor clearColor]];
- }
- return self;
-}
-
-- (BOOL)canBecomeMainWindow {
- return NO;
-}
-
-- (void)sendEvent:(NSEvent*)event {
- // We do not want to bring chrome window to foreground when we click on close
- // or option button. To do this, we have to intercept the event.
- BalloonController* delegate =
- static_cast<BalloonController*>([self delegate]);
- if (![delegate handleEvent:event]) {
- [super sendEvent:event];
- }
-}
-@end
-
-@implementation BalloonShelfViewCocoa
-- (void)drawRect:(NSRect)rect {
- NSBezierPath* path =
- [NSBezierPath gtm_bezierPathWithRoundRect:[self bounds]
- topLeftCornerRadius:kRoundedCornerSize
- topRightCornerRadius:kRoundedCornerSize
- bottomLeftCornerRadius:0.0
- bottomRightCornerRadius:0.0];
-
- [[NSColor colorWithCalibratedWhite:0.957 alpha:1.0] set];
- [path fill];
-
- [[NSColor colorWithCalibratedWhite:0.8 alpha:1.0] set];
- NSPoint origin = [self bounds].origin;
- [NSBezierPath strokeLineFromPoint:origin
- toPoint:NSMakePoint(origin.x + NSWidth([self bounds]), origin.y)];
-}
-@end
-
-@implementation BalloonContentViewCocoa
-- (void)drawRect:(NSRect)rect {
- rect = NSInsetRect([self bounds], 0.5, 0.5);
- NSBezierPath* path =
- [NSBezierPath gtm_bezierPathWithRoundRect:rect
- topLeftCornerRadius:0.0
- topRightCornerRadius:0.0
- bottomLeftCornerRadius:kRoundedCornerSize
- bottomRightCornerRadius:kRoundedCornerSize];
- [[NSColor whiteColor] set];
- [path setLineWidth:3];
- [path stroke];
-}
-@end
diff --git a/chrome/browser/cocoa/notifications/balloon_view_bridge.h b/chrome/browser/cocoa/notifications/balloon_view_bridge.h
deleted file mode 100644
index 985fcde..0000000
--- a/chrome/browser/cocoa/notifications/balloon_view_bridge.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_NOTIFICATIONS_BALLOON_VIEW_BRIDGE_H_
-#define CHROME_BROWSER_COCOA_NOTIFICATIONS_BALLOON_VIEW_BRIDGE_H_
-#pragma once
-
-#include "chrome/browser/notifications/balloon.h"
-
-@class BalloonController;
-class BalloonHost;
-namespace gfx {
-class Size;
-}
-
-// Bridges from the cross-platform BalloonView interface to the Cocoa
-// controller which will draw the view on screen.
-class BalloonViewBridge : public BalloonView {
- public:
- BalloonViewBridge();
- ~BalloonViewBridge();
-
- // BalloonView interface.
- virtual void Show(Balloon* balloon);
- virtual void Update();
- virtual void RepositionToBalloon();
- virtual void Close(bool by_user);
- virtual gfx::Size GetSize() const;
- virtual BalloonHost* GetHost() const;
-
- private:
- // Weak pointer to the balloon controller which manages the UI.
- // This object cleans itself up when its windows close.
- BalloonController* controller_;
-
- DISALLOW_COPY_AND_ASSIGN(BalloonViewBridge);
-};
-
-#endif // CHROME_BROWSER_COCOA_NOTIFICATIONS_BALLOON_VIEW_BRIDGE_H_
diff --git a/chrome/browser/cocoa/notifications/balloon_view_bridge.mm b/chrome/browser/cocoa/notifications/balloon_view_bridge.mm
deleted file mode 100644
index c0b8b1f..0000000
--- a/chrome/browser/cocoa/notifications/balloon_view_bridge.mm
+++ /dev/null
@@ -1,48 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/notifications/balloon_view_bridge.h"
-
-#include "chrome/browser/cocoa/notifications/balloon_controller.h"
-#import "chrome/browser/cocoa/notifications/balloon_view_host_mac.h"
-#include "gfx/size.h"
-
-#import <Cocoa/Cocoa.h>
-
-BalloonViewBridge::BalloonViewBridge() :
- controller_(NULL) {
-}
-
-BalloonViewBridge::~BalloonViewBridge() {
-}
-
-void BalloonViewBridge::Close(bool by_user) {
- [controller_ closeBalloon:by_user];
-}
-
-gfx::Size BalloonViewBridge::GetSize() const {
- if (controller_)
- return gfx::Size([controller_ desiredTotalWidth],
- [controller_ desiredTotalHeight]);
- else
- return gfx::Size();
-}
-
-void BalloonViewBridge::RepositionToBalloon() {
- [controller_ repositionToBalloon];
-}
-
-void BalloonViewBridge::Show(Balloon* balloon) {
- controller_ = [[BalloonController alloc] initWithBalloon:balloon];
- [controller_ setShouldCascadeWindows:NO];
- [controller_ showWindow:nil];
-}
-
-BalloonHost* BalloonViewBridge::GetHost() const {
- return [controller_ getHost];
-}
-
-void BalloonViewBridge::Update() {
- [controller_ updateContents];
-}
diff --git a/chrome/browser/cocoa/notifications/balloon_view_host_mac.h b/chrome/browser/cocoa/notifications/balloon_view_host_mac.h
deleted file mode 100644
index 3ef85b2..0000000
--- a/chrome/browser/cocoa/notifications/balloon_view_host_mac.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_NOTIFICATIONS_BALLOON_VIEW_HOST_MAC_H_
-#define CHROME_BROWSER_COCOA_NOTIFICATIONS_BALLOON_VIEW_HOST_MAC_H_
-#pragma once
-
-#include "chrome/browser/notifications/balloon_host.h"
-
-class RenderWidgetHostView;
-class RenderWidgetHostViewMac;
-
-// BalloonViewHost class is a delegate to the renderer host for the HTML
-// notification. When initialized it creates a new RenderViewHost and loads
-// the contents of the toast into it. It also handles links within the toast,
-// loading them into a new tab.
-class BalloonViewHost : public BalloonHost {
- public:
- explicit BalloonViewHost(Balloon* balloon);
-
- ~BalloonViewHost();
-
- // Changes the size of the balloon.
- void UpdateActualSize(const gfx::Size& new_size);
-
- // Accessors.
- gfx::NativeView native_view() const;
-
- protected:
- virtual void InitRenderWidgetHostView();
- virtual RenderWidgetHostView* render_widget_host_view() const;
-
- private:
- // The Mac-specific widget host view. This is owned by its native view,
- // which this class frees in its destructor.
- RenderWidgetHostViewMac* render_widget_host_view_;
-
- DISALLOW_COPY_AND_ASSIGN(BalloonViewHost);
-};
-
-#endif // CHROME_BROWSER_COCOA_NOTIFICATIONS_BALLOON_VIEW_HOST_MAC_H_
diff --git a/chrome/browser/cocoa/notifications/balloon_view_host_mac.mm b/chrome/browser/cocoa/notifications/balloon_view_host_mac.mm
deleted file mode 100644
index 67b75b3..0000000
--- a/chrome/browser/cocoa/notifications/balloon_view_host_mac.mm
+++ /dev/null
@@ -1,39 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/notifications/balloon_view_host_mac.h"
-
-#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/renderer_host/render_widget_host_view_mac.h"
-
-BalloonViewHost::BalloonViewHost(Balloon* balloon)
- : BalloonHost(balloon) {
-}
-
-BalloonViewHost::~BalloonViewHost() {
- Shutdown();
-}
-
-void BalloonViewHost::UpdateActualSize(const gfx::Size& new_size) {
- NSView* view = render_widget_host_view_->native_view();
- NSRect frame = [view frame];
- frame.size.width = new_size.width();
- frame.size.height = new_size.height();
-
- [view setFrame:frame];
- [view setNeedsDisplay:YES];
-}
-
-gfx::NativeView BalloonViewHost::native_view() const {
- return render_widget_host_view_->native_view();
-}
-
-void BalloonViewHost::InitRenderWidgetHostView() {
- DCHECK(render_view_host_);
- render_widget_host_view_ = new RenderWidgetHostViewMac(render_view_host_);
-}
-
-RenderWidgetHostView* BalloonViewHost::render_widget_host_view() const {
- return render_widget_host_view_;
-}
diff --git a/chrome/browser/cocoa/nsimage_cache_unittest.mm b/chrome/browser/cocoa/nsimage_cache_unittest.mm
deleted file mode 100644
index 7f2e2fb..0000000
--- a/chrome/browser/cocoa/nsimage_cache_unittest.mm
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) 2009 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 "base/file_path.h"
-#include "base/mac_util.h"
-#include "base/nsimage_cache_mac.h"
-#include "base/path_service.h"
-#include "chrome/common/chrome_constants.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-// This tests nsimage_cache, which lives in base/. The unit test is in
-// chrome/ because it depends on having a built-up Chrome present.
-
-namespace {
-
-class NSImageCacheTest : public PlatformTest {
- public:
- NSImageCacheTest() {
- // Look in the framework bundle for resources.
- FilePath path;
- PathService::Get(base::DIR_EXE, &path);
- path = path.Append(chrome::kFrameworkName);
- mac_util::SetOverrideAppBundlePath(path);
- }
- virtual ~NSImageCacheTest() {
- mac_util::SetOverrideAppBundle(nil);
- }
-};
-
-TEST_F(NSImageCacheTest, LookupFound) {
- EXPECT_TRUE(nsimage_cache::ImageNamed(@"back_Template.pdf") != nil)
- << "Failed to find the toolbar image?";
-}
-
-TEST_F(NSImageCacheTest, LookupCached) {
- EXPECT_EQ(nsimage_cache::ImageNamed(@"back_Template.pdf"),
- nsimage_cache::ImageNamed(@"back_Template.pdf"))
- << "Didn't get the same NSImage back?";
-}
-
-TEST_F(NSImageCacheTest, LookupMiss) {
- EXPECT_TRUE(nsimage_cache::ImageNamed(@"should_not.exist") == nil)
- << "There shouldn't be an image with this name?";
-}
-
-TEST_F(NSImageCacheTest, LookupFoundAndClear) {
- NSImage *first = nsimage_cache::ImageNamed(@"back_Template.pdf");
- // Hang on to the first image so that the second one doesn't get allocated
- // in the same location by (bad) luck.
- [[first retain] autorelease];
- EXPECT_TRUE(first != nil)
- << "Failed to find the toolbar image?";
- nsimage_cache::Clear();
- NSImage *second = nsimage_cache::ImageNamed(@"back_Template.pdf");
- EXPECT_TRUE(second != nil)
- << "Failed to find the toolbar image...again?";
- EXPECT_NE(second, first)
- << "how'd we get the same image after a cache clear?";
-}
-
-TEST_F(NSImageCacheTest, AutoTemplating) {
- NSImage *templateImage = nsimage_cache::ImageNamed(@"back_Template.pdf");
- EXPECT_TRUE([templateImage isTemplate] == YES)
- << "Image ending in 'Template' should be marked as being a template";
- NSImage *nonTemplateImage = nsimage_cache::ImageNamed(@"aliasCursor.png");
- EXPECT_FALSE([nonTemplateImage isTemplate] == YES)
- << "Image not ending in 'Template' should not be marked as being a "
- "template";
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/nsmenuitem_additions.h b/chrome/browser/cocoa/nsmenuitem_additions.h
deleted file mode 100644
index 5a647fa..0000000
--- a/chrome/browser/cocoa/nsmenuitem_additions.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_NSMENUITEM_ADDITIONS_H_
-#define CHROME_BROWSER_COCOA_NSMENUITEM_ADDITIONS_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-@interface NSMenuItem(ChromeAdditions)
-
-// Returns true exactly if the menu item would fire if it would be put into
-// a menu and then |menu performKeyEquivalent:event| was called.
-- (BOOL)cr_firesForKeyEvent:(NSEvent*)event;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_NSMENUITEM_ADDITIONS_H_
diff --git a/chrome/browser/cocoa/nsmenuitem_additions.mm b/chrome/browser/cocoa/nsmenuitem_additions.mm
deleted file mode 100644
index fcd448c..0000000
--- a/chrome/browser/cocoa/nsmenuitem_additions.mm
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/nsmenuitem_additions.h"
-
-#include <Carbon/Carbon.h>
-
-#include "base/logging.h"
-
-@implementation NSMenuItem(ChromeAdditions)
-
-- (BOOL)cr_firesForKeyEvent:(NSEvent*)event {
- DCHECK([event type] == NSKeyDown);
- if (![self isEnabled])
- return NO;
-
- // In System Preferences->Keyboard->Keyboard Shortcuts, it is possible to add
- // arbitrary keyboard shortcuts to applications. It is not documented how this
- // works in detail, but |NSMenuItem| has a method |userKeyEquivalent| that
- // sounds related.
- // However, it looks like |userKeyEquivalent| is equal to |keyEquivalent| when
- // a user shortcut is set in system preferences, i.e. Cocoa automatically
- // sets/overwrites |keyEquivalent| as well. Hence, this method can ignore
- // |userKeyEquivalent| and check |keyEquivalent| only.
-
- // Menu item key equivalents are nearly all stored without modifiers. The
- // exception is shift, which is included in the key and not in the modifiers
- // for printable characters (but not for stuff like arrow keys etc).
- NSString* eventString = [event charactersIgnoringModifiers];
- NSUInteger eventModifiers =
- [event modifierFlags] & NSDeviceIndependentModifierFlagsMask;
-
- if ([eventString length] == 0 || [[self keyEquivalent] length] == 0)
- return NO;
-
- // Turns out esc never fires unless cmd or ctrl is down.
- if ([event keyCode] == kVK_Escape &&
- (eventModifiers & (NSControlKeyMask | NSCommandKeyMask)) == 0)
- return NO;
-
- // From the |NSMenuItem setKeyEquivalent:| documentation:
- //
- // If you want to specify the Backspace key as the key equivalent for a menu
- // item, use a single character string with NSBackspaceCharacter (defined in
- // NSText.h as 0x08) and for the Forward Delete key, use NSDeleteCharacter
- // (defined in NSText.h as 0x7F). Note that these are not the same characters
- // you get from an NSEvent key-down event when pressing those keys.
- if ([[self keyEquivalent] characterAtIndex:0] == NSBackspaceCharacter
- && [eventString characterAtIndex:0] == NSDeleteCharacter) {
- unichar chr = NSBackspaceCharacter;
- eventString = [NSString stringWithCharacters:&chr length:1];
-
- // Make sure "shift" is not removed from modifiers below.
- eventModifiers |= NSFunctionKeyMask;
- }
- if ([[self keyEquivalent] characterAtIndex:0] == NSDeleteCharacter &&
- [eventString characterAtIndex:0] == NSDeleteFunctionKey) {
- unichar chr = NSDeleteCharacter;
- eventString = [NSString stringWithCharacters:&chr length:1];
-
- // Make sure "shift" is not removed from modifiers below.
- eventModifiers |= NSFunctionKeyMask;
- }
-
- // cmd-opt-a gives some weird char as characters and "a" as
- // charactersWithoutModifiers with an US layout, but an "a" as characters and
- // a weird char as "charactersWithoutModifiers" with a cyrillic layout. Oh,
- // Cocoa! Instead of getting the current layout from Text Input Services,
- // and then requesting the kTISPropertyUnicodeKeyLayoutData and looking in
- // there, let's try a pragmatic hack.
- if ([eventString characterAtIndex:0] > 0x7f &&
- [[event characters] length] > 0 &&
- [[event characters] characterAtIndex:0] <= 0x7f)
- eventString = [event characters];
-
- // When both |characters| and |charactersIgnoringModifiers| are ascii, we
- // want to use |characters| if it's a character and
- // |charactersIgnoringModifiers| else (on dvorak, cmd-shift-z should fire
- // "cmd-:" instead of "cmd-;", but on dvorak-qwerty, cmd-shift-z should fire
- // cmd-shift-z instead of cmd-:).
- if ([eventString characterAtIndex:0] <= 0x7f &&
- [[event characters] length] > 0 &&
- [[event characters] characterAtIndex:0] <= 0x7f &&
- isalpha([[event characters] characterAtIndex:0]))
- eventString = [event characters];
-
- // Clear shift key for printable characters.
- if ((eventModifiers & (NSNumericPadKeyMask | NSFunctionKeyMask)) == 0 &&
- [[self keyEquivalent] characterAtIndex:0] != '\r')
- eventModifiers &= ~NSShiftKeyMask;
-
- // Clear all non-interesting modifiers
- eventModifiers &= NSCommandKeyMask |
- NSControlKeyMask |
- NSAlternateKeyMask |
- NSShiftKeyMask;
-
- return [eventString isEqualToString:[self keyEquivalent]]
- && eventModifiers == [self keyEquivalentModifierMask];
-}
-
-@end
diff --git a/chrome/browser/cocoa/nsmenuitem_additions_unittest.mm b/chrome/browser/cocoa/nsmenuitem_additions_unittest.mm
deleted file mode 100644
index 869cade..0000000
--- a/chrome/browser/cocoa/nsmenuitem_additions_unittest.mm
+++ /dev/null
@@ -1,351 +0,0 @@
-// 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 "chrome/browser/cocoa/nsmenuitem_additions.h"
-
-#include <Carbon/Carbon.h>
-
-#include <ostream>
-
-#include "base/scoped_nsobject.h"
-#include "base/sys_string_conversions.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-NSEvent* KeyEvent(const NSUInteger modifierFlags,
- NSString* chars,
- NSString* charsNoMods,
- const NSUInteger keyCode) {
- return [NSEvent keyEventWithType:NSKeyDown
- location:NSZeroPoint
- modifierFlags:modifierFlags
- timestamp:0.0
- windowNumber:0
- context:nil
- characters:chars
- charactersIgnoringModifiers:charsNoMods
- isARepeat:NO
- keyCode:keyCode];
-}
-
-NSMenuItem* MenuItem(NSString* equiv, NSUInteger mask) {
- NSMenuItem* item = [[[NSMenuItem alloc] initWithTitle:@""
- action:NULL
- keyEquivalent:@""] autorelease];
- [item setKeyEquivalent:equiv];
- [item setKeyEquivalentModifierMask:mask];
- return item;
-}
-
-std::ostream& operator<<(std::ostream& out, NSObject* obj) {
- return out << base::SysNSStringToUTF8([obj description]);
-}
-
-std::ostream& operator<<(std::ostream& out, NSMenuItem* item) {
- return out << "NSMenuItem " << base::SysNSStringToUTF8([item keyEquivalent]);
-}
-
-void ExpectKeyFiresItemEq(bool result, NSEvent* key, NSMenuItem* item,
- bool compareCocoa) {
- EXPECT_EQ(result, [item cr_firesForKeyEvent:key]) << key << '\n' << item;
-
- // Make sure that Cocoa does in fact agree with our expectations. However,
- // in some cases cocoa behaves weirdly (if you create e.g. a new event that
- // contains all fields of the event that you get when hitting cmd-a with a
- // russion keyboard layout, the copy won't fire a menu item that has cmd-a as
- // key equivalent, even though the original event would) and isn't a good
- // oracle function.
- if (compareCocoa) {
- scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@"Menu!"]);
- [menu setAutoenablesItems:NO];
- EXPECT_FALSE([menu performKeyEquivalent:key]);
- [menu addItem:item];
- EXPECT_EQ(result, [menu performKeyEquivalent:key]) << key << '\n' << item;
- }
-}
-
-void ExpectKeyFiresItem(
- NSEvent* key, NSMenuItem* item, bool compareCocoa = true) {
- ExpectKeyFiresItemEq(true, key, item, compareCocoa);
-}
-
-void ExpectKeyDoesntFireItem(
- NSEvent* key, NSMenuItem* item, bool compareCocoa = true) {
- ExpectKeyFiresItemEq(false, key, item, compareCocoa);
-}
-
-TEST(NSMenuItemAdditionsTest, TestFiresForKeyEvent) {
- // These test cases were built by writing a small test app that has a
- // MainMenu.xib with a given key equivalent set in Interface Builder and a
- // some code that prints both the key equivalent that fires a menu item and
- // the menu item's key equivalent and modifier masks. I then pasted those
- // below. This was done with a US layout, unless otherwise noted. In the
- // comments, "z" always means the physical "z" key on a US layout no matter
- // what character that key produces.
-
- NSMenuItem* item;
- NSEvent* key;
- unichar ch;
- NSString* s;
-
- // Sanity
- item = MenuItem(@"", 0);
- EXPECT_TRUE([item isEnabled]);
-
- // a
- key = KeyEvent(0x100, @"a", @"a", 0);
- item = MenuItem(@"a", 0);
- ExpectKeyFiresItem(key, item);
- ExpectKeyDoesntFireItem(KeyEvent(0x20102, @"A", @"A", 0), item);
-
- // Disabled menu item
- key = KeyEvent(0x100, @"a", @"a", 0);
- item = MenuItem(@"a", 0);
- [item setEnabled:NO];
- ExpectKeyDoesntFireItem(key, item, false);
-
- // shift-a
- key = KeyEvent(0x20102, @"A", @"A", 0);
- item = MenuItem(@"A", 0);
- ExpectKeyFiresItem(key, item);
- ExpectKeyDoesntFireItem(KeyEvent(0x100, @"a", @"a", 0), item);
-
- // cmd-opt-shift-a
- key = KeyEvent(0x1a012a, @"\u00c5", @"A", 0);
- item = MenuItem(@"A", 0x180000);
- ExpectKeyFiresItem(key, item);
-
- // cmd-opt-a
- key = KeyEvent(0x18012a, @"\u00e5", @"a", 0);
- item = MenuItem(@"a", 0x180000);
- ExpectKeyFiresItem(key, item);
-
- // cmd-=
- key = KeyEvent(0x100110, @"=", @"=", 0x18);
- item = MenuItem(@"=", 0x100000);
- ExpectKeyFiresItem(key, item);
-
- // cmd-shift-=
- key = KeyEvent(0x12010a, @"=", @"+", 0x18);
- item = MenuItem(@"+", 0x100000);
- ExpectKeyFiresItem(key, item);
-
- // Turns out Cocoa fires "+ 100108 + 18" if you hit cmd-= and the menu only
- // has a cmd-+ shortcut. But that's transparent for |cr_firesForKeyEvent:|.
-
- // ctrl-3
- key = KeyEvent(0x40101, @"3", @"3", 0x14);
- item = MenuItem(@"3", 0x40000);
- ExpectKeyFiresItem(key, item);
-
- // return
- key = KeyEvent(0, @"\r", @"\r", 0x24);
- item = MenuItem(@"\r", 0);
- ExpectKeyFiresItem(key, item);
-
- // shift-return
- key = KeyEvent(0x20102, @"\r", @"\r", 0x24);
- item = MenuItem(@"\r", 0x20000);
- ExpectKeyFiresItem(key, item);
-
- // shift-left
- ch = NSLeftArrowFunctionKey;
- s = [NSString stringWithCharacters:&ch length:1];
- key = KeyEvent(0xa20102, s, s, 0x7b);
- item = MenuItem(s, 0x20000);
- ExpectKeyFiresItem(key, item);
-
- // shift-f1 (with a layout that needs the fn key down for f1)
- ch = NSF1FunctionKey;
- s = [NSString stringWithCharacters:&ch length:1];
- key = KeyEvent(0x820102, s, s, 0x7a);
- item = MenuItem(s, 0x20000);
- ExpectKeyFiresItem(key, item);
-
- // esc
- // Turns out this doesn't fire.
- key = KeyEvent(0x100, @"\e", @"\e", 0x35);
- item = MenuItem(@"\e", 0);
- ExpectKeyDoesntFireItem(key,item, false);
-
- // shift-esc
- // Turns out this doesn't fire.
- key = KeyEvent(0x20102, @"\e", @"\e", 0x35);
- item = MenuItem(@"\e", 0x20000);
- ExpectKeyDoesntFireItem(key,item, false);
-
- // cmd-esc
- key = KeyEvent(0x100108, @"\e", @"\e", 0x35);
- item = MenuItem(@"\e", 0x100000);
- ExpectKeyFiresItem(key, item);
-
- // ctrl-esc
- key = KeyEvent(0x40101, @"\e", @"\e", 0x35);
- item = MenuItem(@"\e", 0x40000);
- ExpectKeyFiresItem(key, item);
-
- // delete ("backspace")
- key = KeyEvent(0x100, @"\x7f", @"\x7f", 0x33);
- item = MenuItem(@"\x08", 0);
- ExpectKeyFiresItem(key, item, false);
-
- // shift-delete
- key = KeyEvent(0x20102, @"\x7f", @"\x7f", 0x33);
- item = MenuItem(@"\x08", 0x20000);
- ExpectKeyFiresItem(key, item, false);
-
- // forwarddelete (fn-delete / fn-backspace)
- ch = NSDeleteFunctionKey;
- s = [NSString stringWithCharacters:&ch length:1];
- key = KeyEvent(0x800100, s, s, 0x75);
- item = MenuItem(@"\x7f", 0);
- ExpectKeyFiresItem(key, item, false);
-
- // shift-forwarddelete (shift-fn-delete / shift-fn-backspace)
- ch = NSDeleteFunctionKey;
- s = [NSString stringWithCharacters:&ch length:1];
- key = KeyEvent(0x820102, s, s, 0x75);
- item = MenuItem(@"\x7f", 0x20000);
- ExpectKeyFiresItem(key, item, false);
-
- // fn-left
- ch = NSHomeFunctionKey;
- s = [NSString stringWithCharacters:&ch length:1];
- key = KeyEvent(0x800100, s, s, 0x73);
- item = MenuItem(s, 0);
- ExpectKeyFiresItem(key, item);
-
- // cmd-left
- ch = NSLeftArrowFunctionKey;
- s = [NSString stringWithCharacters:&ch length:1];
- key = KeyEvent(0xb00108, s, s, 0x7b);
- item = MenuItem(s, 0x100000);
- ExpectKeyFiresItem(key, item);
-
- // Hitting the "a" key with a russian keyboard layout -- does not fire
- // a menu item that has "a" as key equiv.
- key = KeyEvent(0x100, @"\u0444", @"\u0444", 0);
- item = MenuItem(@"a", 0);
- ExpectKeyDoesntFireItem(key,item);
-
- // cmd-a on a russion layout -- fires for a menu item with cmd-a as key equiv.
- key = KeyEvent(0x100108, @"a", @"\u0444", 0);
- item = MenuItem(@"a", 0x100000);
- ExpectKeyFiresItem(key, item, false);
-
- // cmd-z on US layout
- key = KeyEvent(0x100108, @"z", @"z", 6);
- item = MenuItem(@"z", 0x100000);
- ExpectKeyFiresItem(key, item);
-
- // cmd-y on german layout (has same keycode as cmd-z on us layout, shouldn't
- // fire).
- key = KeyEvent(0x100108, @"y", @"y", 6);
- item = MenuItem(@"z", 0x100000);
- ExpectKeyDoesntFireItem(key,item);
-
- // cmd-z on german layout
- key = KeyEvent(0x100108, @"z", @"z", 0x10);
- item = MenuItem(@"z", 0x100000);
- ExpectKeyFiresItem(key, item);
-
- // fn-return (== enter)
- key = KeyEvent(0x800100, @"\x3", @"\x3", 0x4c);
- item = MenuItem(@"\r", 0);
- ExpectKeyDoesntFireItem(key,item);
-
- // cmd-z on dvorak layout (so that the key produces ';')
- key = KeyEvent(0x100108, @";", @";", 6);
- ExpectKeyDoesntFireItem(key, MenuItem(@"z", 0x100000));
- ExpectKeyFiresItem(key, MenuItem(@";", 0x100000));
-
- // cmd-z on dvorak qwerty layout (so that the key produces ';', but 'z' if
- // cmd is down)
- key = KeyEvent(0x100108, @"z", @";", 6);
- ExpectKeyFiresItem(key, MenuItem(@"z", 0x100000), false);
- ExpectKeyDoesntFireItem(key, MenuItem(@";", 0x100000), false);
-
- // cmd-shift-z on dvorak layout (so that we get a ':')
- key = KeyEvent(0x12010a, @";", @":", 6);
- ExpectKeyFiresItem(key, MenuItem(@":", 0x100000));
- ExpectKeyDoesntFireItem(key, MenuItem(@";", 0x100000));
-
- // cmd-s with a serbian layout (just "s" produces something that looks a lot
- // like "c" in some fonts, but is actually \u0441. cmd-s activates a menu item
- // with key equivalent "s", not "c")
- key = KeyEvent(0x100108, @"s", @"\u0441", 1);
- ExpectKeyFiresItem(key, MenuItem(@"s", 0x100000), false);
- ExpectKeyDoesntFireItem(key, MenuItem(@"c", 0x100000));
-}
-
-NSString* keyCodeToCharacter(NSUInteger keyCode,
- EventModifiers modifiers,
- TISInputSourceRef layout) {
- CFDataRef uchr = (CFDataRef)TISGetInputSourceProperty(
- layout, kTISPropertyUnicodeKeyLayoutData);
- UCKeyboardLayout* keyLayout = (UCKeyboardLayout*)CFDataGetBytePtr(uchr);
-
- UInt32 deadKeyState = 0;
- OSStatus err = noErr;
- UniCharCount maxStringLength = 4, actualStringLength;
- UniChar unicodeString[4];
- err = UCKeyTranslate(keyLayout,
- (UInt16)keyCode,
- kUCKeyActionDown,
- modifiers,
- LMGetKbdType(),
- kUCKeyTranslateNoDeadKeysBit,
- &deadKeyState,
- maxStringLength,
- &actualStringLength,
- unicodeString);
- assert(err == noErr);
-
- CFStringRef temp = CFStringCreateWithCharacters(
- kCFAllocatorDefault, unicodeString, 1);
- return [(NSString*)temp autorelease];
-}
-
-TEST(NSMenuItemAdditionsTest, TestMOnDifferentLayouts) {
- // There's one key -- "m" -- that has the same keycode on most keyboard
- // layouts. This function tests a menu item with cmd-m as key equivalent
- // can be fired on all layouts.
- NSMenuItem* item = MenuItem(@"m", 0x100000);
-
- NSDictionary* filter = [NSDictionary
- dictionaryWithObject:(NSString*)kTISTypeKeyboardLayout
- forKey:(NSString*)kTISPropertyInputSourceType];
-
- // Docs say that including all layouts instead of just the active ones is
- // slow, but there's no way around that.
- NSArray* list = (NSArray*)TISCreateInputSourceList(
- (CFDictionaryRef)filter, true);
- for (id layout in list) {
- TISInputSourceRef ref = (TISInputSourceRef)layout;
-
- NSUInteger keyCode = 0x2e; // "m" on a US layout and most other layouts.
-
- // On a few layouts, "m" has a different key code.
- NSString* layoutId = (NSString*)TISGetInputSourceProperty(
- ref, kTISPropertyInputSourceID);
- if ([layoutId isEqualToString:@"com.apple.keylayout.Belgian"] ||
- [layoutId isEqualToString:@"com.apple.keylayout.French"] ||
- [layoutId isEqualToString:@"com.apple.keylayout.French-numerical"] ||
- [layoutId isEqualToString:@"com.apple.keylayout.Italian"]) {
- keyCode = 0x29;
- } else if ([layoutId isEqualToString:@"com.apple.keylayout.Turkish"]) {
- keyCode = 0x28;
- } else if ([layoutId isEqualToString:@"com.apple.keylayout.Dvorak-Left"]) {
- keyCode = 0x16;
- } else if ([layoutId isEqualToString:@"com.apple.keylayout.Dvorak-Right"]) {
- keyCode = 0x1a;
- }
-
- EventModifiers modifiers = cmdKey >> 8;
- NSString* chars = keyCodeToCharacter(keyCode, modifiers, ref);
- NSString* charsIgnoringMods = keyCodeToCharacter(keyCode, 0, ref);
- NSEvent* key = KeyEvent(0x100000, chars, charsIgnoringMods, keyCode);
- ExpectKeyFiresItem(key, item, false);
- }
- CFRelease(list);
-}
diff --git a/chrome/browser/cocoa/nswindow_additions.h b/chrome/browser/cocoa/nswindow_additions.h
deleted file mode 100644
index 69ed983..0000000
--- a/chrome/browser/cocoa/nswindow_additions.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_NSWINDOW_ADDITIONS_H_
-#define CHROME_BROWSER_COCOA_NSWINDOW_ADDITIONS_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-// ID of a Space. Starts at 1.
-typedef int CGSWorkspaceID;
-
-@interface NSWindow(ChromeAdditions)
-
-// Gets the Space that the window is currently on. YES on success, NO on
-// failure.
-- (BOOL)cr_workspace:(CGSWorkspaceID*)outWorkspace;
-
-// Moves the window to the given Space. YES on success, NO on failure.
-- (BOOL)cr_moveToWorkspace:(CGSWorkspaceID)workspace;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_NSWINDOW_ADDITIONS_H_
diff --git a/chrome/browser/cocoa/nswindow_additions.mm b/chrome/browser/cocoa/nswindow_additions.mm
deleted file mode 100644
index 40da38f..0000000
--- a/chrome/browser/cocoa/nswindow_additions.mm
+++ /dev/null
@@ -1,104 +0,0 @@
-// 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 "chrome/browser/cocoa/nswindow_additions.h"
-
-#include <dlfcn.h>
-
-#include "base/logging.h"
-
-typedef void* CGSConnectionID;
-typedef int CGSWindowID;
-typedef int CGSError;
-typedef int CGSWorkspaceID;
-
-// These are private APIs we look up at run time.
-typedef CGSConnectionID (*CGSDefaultConnectionFunc)(void);
-typedef CGSError (*CGSGetWindowWorkspaceFunc)(const CGSConnectionID cid,
- CGSWindowID wid,
- CGSWorkspaceID* workspace);
-typedef CGSError (*CGSMoveWorkspaceWindowListFunc)(const CGSConnectionID cid,
- CGSWindowID* wids,
- int count,
- CGSWorkspaceID workspace);
-
-static CGSDefaultConnectionFunc sCGSDefaultConnection;
-static CGSGetWindowWorkspaceFunc sCGSGetWindowWorkspace;
-static CGSMoveWorkspaceWindowListFunc sCGSMoveWorkspaceWindowList;
-
-@implementation NSWindow(ChromeAdditions)
-
-// Looks up private Spaces APIs using dlsym.
-- (BOOL)cr_initializeWorkspaceAPIs {
- static BOOL shouldInitialize = YES;
- if (shouldInitialize) {
- shouldInitialize = NO;
-
- NSBundle* coreGraphicsBundle =
- [NSBundle bundleWithIdentifier:@"com.apple.CoreGraphics"];
- NSString* coreGraphicsPath = [[coreGraphicsBundle bundlePath]
- stringByAppendingPathComponent:@"CoreGraphics"];
- void* coreGraphicsLibrary = dlopen([coreGraphicsPath UTF8String],
- RTLD_GLOBAL | RTLD_LAZY);
-
- if (coreGraphicsLibrary) {
- sCGSDefaultConnection =
- (CGSDefaultConnectionFunc)dlsym(coreGraphicsLibrary,
- "_CGSDefaultConnection");
- if (!sCGSDefaultConnection) {
- LOG(ERROR) << "Failed to lookup _CGSDefaultConnection API" << dlerror();
- }
- sCGSGetWindowWorkspace =
- (CGSGetWindowWorkspaceFunc)dlsym(coreGraphicsLibrary,
- "CGSGetWindowWorkspace");
- if (!sCGSGetWindowWorkspace) {
- LOG(ERROR) << "Failed to lookup CGSGetWindowWorkspace API" << dlerror();
- }
- sCGSMoveWorkspaceWindowList =
- (CGSMoveWorkspaceWindowListFunc)dlsym(coreGraphicsLibrary,
- "CGSMoveWorkspaceWindowList");
- if (!sCGSMoveWorkspaceWindowList) {
- LOG(ERROR) << "Failed to lookup CGSMoveWorkspaceWindowList API"
- << dlerror();
- }
- } else {
- LOG(ERROR) << "Failed to load CoreGraphics lib" << dlerror();
- }
- }
-
- return sCGSDefaultConnection != NULL &&
- sCGSGetWindowWorkspace != NULL &&
- sCGSMoveWorkspaceWindowList != NULL;
-}
-
-- (BOOL)cr_workspace:(CGSWorkspaceID*)outWorkspace {
- if (![self cr_initializeWorkspaceAPIs]) {
- return NO;
- }
-
- // If this ASSERT fails then consider using CGSDefaultConnectionForThread()
- // instead of CGSDefaultConnection().
- DCHECK([NSThread isMainThread]);
- CGSConnectionID cid = sCGSDefaultConnection();
- CGSWindowID wid = [self windowNumber];
- CGSError err = sCGSGetWindowWorkspace(cid, wid, outWorkspace);
- return err == 0;
-}
-
-- (BOOL)cr_moveToWorkspace:(CGSWorkspaceID)workspace {
- if (![self cr_initializeWorkspaceAPIs]) {
- return NO;
- }
-
- // If this ASSERT fails then consider using CGSDefaultConnectionForThread()
- // instead of CGSDefaultConnection().
- DCHECK([NSThread isMainThread]);
- CGSConnectionID cid = sCGSDefaultConnection();
- CGSWindowID wid = [self windowNumber];
- // CGSSetWorkspaceForWindow doesn't seem to work for some reason.
- CGSError err = sCGSMoveWorkspaceWindowList(cid, &wid, 1, workspace);
- return err == 0;
-}
-
-@end
diff --git a/chrome/browser/cocoa/objc_method_swizzle.h b/chrome/browser/cocoa/objc_method_swizzle.h
deleted file mode 100644
index 368b33c..0000000
--- a/chrome/browser/cocoa/objc_method_swizzle.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_OBJC_METHOD_SWIZZLE_H_
-#define CHROME_BROWSER_COCOA_OBJC_METHOD_SWIZZLE_H_
-#pragma once
-
-#import <objc/objc-class.h>
-
-// You should think twice every single time you use anything from this
-// namespace.
-namespace ObjcEvilDoers {
-
-// This is similar to class_getInstanceMethod(), except that it
-// returns NULL if |aClass| does not directly implement |aSelector|.
-Method GetImplementedInstanceMethod(Class aClass, SEL aSelector);
-
-// Exchanges the implementation of |originalSelector| and
-// |alternateSelector| within |aClass|. Both selectors must be
-// implemented directly by |aClass|, not inherited. The IMP returned
-// is for |originalSelector| (for purposes of forwarding).
-IMP SwizzleImplementedInstanceMethods(
- Class aClass, const SEL originalSelector, const SEL alternateSelector);
-
-} // namespace ObjcEvilDoers
-
-#endif // CHROME_BROWSER_COCOA_OBJC_METHOD_SWIZZLE_H_
diff --git a/chrome/browser/cocoa/objc_method_swizzle.mm b/chrome/browser/cocoa/objc_method_swizzle.mm
deleted file mode 100644
index 433bc66..0000000
--- a/chrome/browser/cocoa/objc_method_swizzle.mm
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/objc_method_swizzle.h"
-
-#import "base/logging.h"
-#import "base/scoped_nsobject.h"
-#import "chrome/app/breakpad_mac.h"
-
-namespace ObjcEvilDoers {
-
-Method GetImplementedInstanceMethod(Class aClass, SEL aSelector) {
- Method method = NULL;
- unsigned int methodCount = 0;
- Method* methodList = class_copyMethodList(aClass, &methodCount);
- if (methodList) {
- for (unsigned int i = 0; i < methodCount; ++i) {
- if (method_getName(methodList[i]) == aSelector) {
- method = methodList[i];
- break;
- }
- }
- free(methodList);
- }
- return method;
-}
-
-IMP SwizzleImplementedInstanceMethods(
- Class aClass, const SEL originalSelector, const SEL alternateSelector) {
- // The methods must both be implemented by the target class, not
- // inherited from a superclass.
- Method original = GetImplementedInstanceMethod(aClass, originalSelector);
- Method alternate = GetImplementedInstanceMethod(aClass, alternateSelector);
- DCHECK(original);
- DCHECK(alternate);
- if (!original || !alternate) {
- return NULL;
- }
-
- // The argument and return types must match exactly.
- const char* originalTypes = method_getTypeEncoding(original);
- const char* alternateTypes = method_getTypeEncoding(alternate);
- DCHECK(originalTypes);
- DCHECK(alternateTypes);
- DCHECK(0 == strcmp(originalTypes, alternateTypes));
- if (!originalTypes || !alternateTypes ||
- strcmp(originalTypes, alternateTypes)) {
- return NULL;
- }
-
- IMP ret = method_getImplementation(original);
- if (ret) {
- method_exchangeImplementations(original, alternate);
- }
- return ret;
-}
-
-} // namespace ObjcEvilDoers
diff --git a/chrome/browser/cocoa/objc_method_swizzle_unittest.mm b/chrome/browser/cocoa/objc_method_swizzle_unittest.mm
deleted file mode 100644
index 09aee70..0000000
--- a/chrome/browser/cocoa/objc_method_swizzle_unittest.mm
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/objc_method_swizzle.h"
-
-#include "base/scoped_nsobject.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-@interface ObjcMethodSwizzleTest : NSObject
-- (id)self;
-
-- (NSInteger)one;
-- (NSInteger)two;
-@end
-
-@implementation ObjcMethodSwizzleTest : NSObject
-- (id)self {
- return [super self];
-}
-
-- (NSInteger)one {
- return 1;
-}
-- (NSInteger)two {
- return 2;
-}
-@end
-
-@interface ObjcMethodSwizzleTest (ObjcMethodSwizzleTestCategory)
-- (NSUInteger)hash;
-@end
-
-@implementation ObjcMethodSwizzleTest (ObjcMethodSwizzleTestCategory)
-- (NSUInteger)hash {
- return [super hash];
-}
-@end
-
-namespace ObjcEvilDoers {
-
-TEST(ObjcMethodSwizzleTest, GetImplementedInstanceMethod) {
- EXPECT_EQ(class_getInstanceMethod([NSObject class], @selector(dealloc)),
- GetImplementedInstanceMethod([NSObject class], @selector(dealloc)));
- EXPECT_EQ(class_getInstanceMethod([NSObject class], @selector(self)),
- GetImplementedInstanceMethod([NSObject class], @selector(self)));
- EXPECT_EQ(class_getInstanceMethod([NSObject class], @selector(hash)),
- GetImplementedInstanceMethod([NSObject class], @selector(hash)));
-
- Class testClass = [ObjcMethodSwizzleTest class];
- EXPECT_EQ(class_getInstanceMethod(testClass, @selector(self)),
- GetImplementedInstanceMethod(testClass, @selector(self)));
- EXPECT_NE(class_getInstanceMethod([NSObject class], @selector(self)),
- class_getInstanceMethod(testClass, @selector(self)));
-
- EXPECT_TRUE(class_getInstanceMethod(testClass, @selector(dealloc)));
- EXPECT_FALSE(GetImplementedInstanceMethod(testClass, @selector(dealloc)));
-}
-
-TEST(ObjcMethodSwizzleTest, SwizzleImplementedInstanceMethods) {
- scoped_nsobject<ObjcMethodSwizzleTest> object(
- [[ObjcMethodSwizzleTest alloc] init]);
- EXPECT_EQ([object one], 1);
- EXPECT_EQ([object two], 2);
-
- Class testClass = [object class];
- SwizzleImplementedInstanceMethods(testClass, @selector(one), @selector(two));
- EXPECT_EQ([object one], 2);
- EXPECT_EQ([object two], 1);
-
- SwizzleImplementedInstanceMethods(testClass, @selector(one), @selector(two));
- EXPECT_EQ([object one], 1);
- EXPECT_EQ([object two], 2);
-}
-
-} // namespace ObjcEvilDoers
diff --git a/chrome/browser/cocoa/objc_zombie.h b/chrome/browser/cocoa/objc_zombie.h
deleted file mode 100644
index 0d33ef1..0000000
--- a/chrome/browser/cocoa/objc_zombie.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_NSOBJECT_ZOMBIE_H_
-#define CHROME_BROWSER_COCOA_NSOBJECT_ZOMBIE_H_
-#pragma once
-
-#import <Foundation/Foundation.h>
-
-// You should think twice every single time you use anything from this
-// namespace.
-namespace ObjcEvilDoers {
-
-// Enable zombie object debugging. This implements a variant of Apple's
-// NSZombieEnabled which can help expose use-after-free errors where messages
-// are sent to freed Objective-C objects in production builds.
-//
-// Returns NO if it fails to enable.
-//
-// When |zombieAllObjects| is YES, all objects inheriting from
-// NSObject become zombies on -dealloc. If NO, -shouldBecomeCrZombie
-// is queried to determine whether to make the object a zombie.
-//
-// |zombieCount| controls how many zombies to store before freeing the
-// oldest. Set to 0 to free objects immediately after making them
-// zombies.
-BOOL ZombieEnable(BOOL zombieAllObjects, size_t zombieCount);
-
-// Disable zombies.
-void ZombieDisable();
-
-} // namespace ObjcEvilDoers
-
-@interface NSObject (CrZombie)
-- (BOOL)shouldBecomeCrZombie;
-@end
-
-#endif // CHROME_BROWSER_COCOA_NSOBJECT_ZOMBIE_H_
diff --git a/chrome/browser/cocoa/objc_zombie.mm b/chrome/browser/cocoa/objc_zombie.mm
deleted file mode 100644
index 8a6d766..0000000
--- a/chrome/browser/cocoa/objc_zombie.mm
+++ /dev/null
@@ -1,414 +0,0 @@
-// 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 "chrome/browser/cocoa/objc_zombie.h"
-
-#include <dlfcn.h>
-#include <mach-o/dyld.h>
-#include <mach-o/nlist.h>
-
-#import <objc/objc-class.h>
-
-#include "base/lock.h"
-#include "base/logging.h"
-#import "chrome/app/breakpad_mac.h"
-#import "chrome/browser/cocoa/objc_method_swizzle.h"
-
-// Deallocated objects are re-classed as |CrZombie|. No superclass
-// because then the class would have to override many/most of the
-// inherited methods (|NSObject| is like a category magnet!).
-@interface CrZombie {
- Class isa;
-}
-@end
-
-// Objects with enough space are made into "fat" zombies, which
-// directly remember which class they were until reallocated.
-@interface CrFatZombie : CrZombie {
- @public
- Class wasa;
-}
-@end
-
-namespace {
-
-// |object_cxxDestruct()| is an Objective-C runtime function which
-// traverses the object's class tree for ".cxxdestruct" methods which
-// are run to call C++ destructors as part of |-dealloc|. The
-// function is not public, so must be looked up using nlist.
-typedef void DestructFn(id obj);
-DestructFn* g_object_cxxDestruct = NULL;
-
-// The original implementation for |-[NSObject dealloc]|.
-IMP g_originalDeallocIMP = NULL;
-
-// Classes which freed objects become. |g_fatZombieSize| is the
-// minimum object size which can be made into a fat zombie (which can
-// remember which class it was before free, even after falling off the
-// treadmill).
-Class g_zombieClass = Nil; // cached [CrZombie class]
-Class g_fatZombieClass = Nil; // cached [CrFatZombie class]
-size_t g_fatZombieSize = 0;
-
-// Whether to zombie all freed objects, or only those which return YES
-// from |-shouldBecomeCrZombie|.
-BOOL g_zombieAllObjects = NO;
-
-// Protects |g_zombieCount|, |g_zombieIndex|, and |g_zombies|.
-Lock lock_;
-
-// How many zombies to keep before freeing, and the current head of
-// the circular buffer.
-size_t g_zombieCount = 0;
-size_t g_zombieIndex = 0;
-
-typedef struct {
- id object; // The zombied object.
- Class wasa; // Value of |object->isa| before we replaced it.
-} ZombieRecord;
-
-ZombieRecord* g_zombies = NULL;
-
-// Lookup the private |object_cxxDestruct| function and return a
-// pointer to it. Returns |NULL| on failure.
-DestructFn* LookupObjectCxxDestruct() {
-#if ARCH_CPU_64_BITS
- // TODO(shess): Port to 64-bit. I believe using struct nlist_64
- // will suffice. http://crbug.com/44021 .
- NOTIMPLEMENTED();
- return NULL;
-#endif
-
- struct nlist nl[3];
- bzero(&nl, sizeof(nl));
-
- nl[0].n_un.n_name = (char*)"_object_cxxDestruct";
-
- // My ability to calculate the base for offsets is apparently poor.
- // Use |class_addIvar| as a known reference point.
- nl[1].n_un.n_name = (char*)"_class_addIvar";
-
- if (nlist("/usr/lib/libobjc.dylib", nl) < 0 ||
- nl[0].n_type == N_UNDF || nl[1].n_type == N_UNDF)
- return NULL;
-
- return (DestructFn*)((char*)&class_addIvar - nl[1].n_value + nl[0].n_value);
-}
-
-// Replacement |-dealloc| which turns objects into zombies and places
-// them into |g_zombies| to be freed later.
-void ZombieDealloc(id self, SEL _cmd) {
- // This code should only be called when it is implementing |-dealloc|.
- DCHECK_EQ(_cmd, @selector(dealloc));
-
- // Use the original |-dealloc| if the object doesn't wish to be
- // zombied.
- if (!g_zombieAllObjects && ![self shouldBecomeCrZombie]) {
- g_originalDeallocIMP(self, _cmd);
- return;
- }
-
- // Use the original |-dealloc| if |object_cxxDestruct| was never
- // initialized, because otherwise C++ destructors won't be called.
- // This case should be impossible, but doing it wrong would cause
- // terrible problems.
- DCHECK(g_object_cxxDestruct);
- if (!g_object_cxxDestruct) {
- g_originalDeallocIMP(self, _cmd);
- return;
- }
-
- Class wasa = object_getClass(self);
- const size_t size = class_getInstanceSize(wasa);
-
- // Destroy the instance by calling C++ destructors and clearing it
- // to something unlikely to work well if someone references it.
- (*g_object_cxxDestruct)(self);
- memset(self, '!', size);
-
- // If the instance is big enough, make it into a fat zombie and have
- // it remember the old |isa|. Otherwise make it a regular zombie.
- // Setting |isa| rather than using |object_setClass()| because that
- // function is implemented with a memory barrier. The runtime's
- // |_internal_object_dispose()| (in objc-class.m) does this, so it
- // should be safe (messaging free'd objects shouldn't be expected to
- // be thread-safe in the first place).
- if (size >= g_fatZombieSize) {
- self->isa = g_fatZombieClass;
- static_cast<CrFatZombie*>(self)->wasa = wasa;
- } else {
- self->isa = g_zombieClass;
- }
-
- // The new record to swap into |g_zombies|. If |g_zombieCount| is
- // zero, then |self| will be freed immediately.
- ZombieRecord zombieToFree = {self, wasa};
-
- // Don't involve the lock when creating zombies without a treadmill.
- if (g_zombieCount > 0) {
- AutoLock pin(lock_);
-
- // Check the count again in a thread-safe manner.
- if (g_zombieCount > 0) {
- // Put the current object on the treadmill and keep the previous
- // occupant.
- std::swap(zombieToFree, g_zombies[g_zombieIndex]);
-
- // Bump the index forward.
- g_zombieIndex = (g_zombieIndex + 1) % g_zombieCount;
- }
- }
-
- // Do the free out here to prevent any chance of deadlock.
- if (zombieToFree.object)
- free(zombieToFree.object);
-}
-
-// Attempt to determine the original class of zombie |object|.
-Class ZombieWasa(id object) {
- // Fat zombies can hold onto their |wasa| past the point where the
- // object was actually freed. Note that to arrive here at all,
- // |object|'s memory must still be accessible.
- if (object_getClass(object) == g_fatZombieClass)
- return static_cast<CrFatZombie*>(object)->wasa;
-
- // For instances which weren't big enough to store |wasa|, check if
- // the object is still on the treadmill.
- AutoLock pin(lock_);
- for (size_t i=0; i < g_zombieCount; ++i) {
- if (g_zombies[i].object == object)
- return g_zombies[i].wasa;
- }
-
- return Nil;
-}
-
-// Log a message to a freed object. |wasa| is the object's original
-// class. |aSelector| is the selector which the calling code was
-// attempting to send. |viaSelector| is the selector of the
-// dispatch-related method which is being invoked to send |aSelector|
-// (for instance, -respondsToSelector:).
-void ZombieObjectCrash(id object, SEL aSelector, SEL viaSelector) {
- Class wasa = ZombieWasa(object);
- const char* wasaName = (wasa ? class_getName(wasa) : "<unknown>");
- NSString* aString =
- [NSString stringWithFormat:@"Zombie <%s: %p> received -%s",
- wasaName, object, sel_getName(aSelector)];
- if (viaSelector != NULL) {
- const char* viaName = sel_getName(viaSelector);
- aString = [aString stringByAppendingFormat:@" (via -%s)", viaName];
- }
-
- // Set a value for breakpad to report, then crash.
- SetCrashKeyValue(@"zombie", aString);
- LOG(ERROR) << [aString UTF8String];
-
- // This is how about:crash is implemented. Using instead of
- // |DebugUtil::BreakDebugger()| or |LOG(FATAL)| to make the top of
- // stack more immediately obvious in crash dumps.
- int* zero = NULL;
- *zero = 0;
-}
-
-// Initialize our globals, returning YES on success.
-BOOL ZombieInit() {
- static BOOL initialized = NO;
- if (initialized)
- return YES;
-
- Class rootClass = [NSObject class];
-
- g_object_cxxDestruct = LookupObjectCxxDestruct();
- g_originalDeallocIMP =
- class_getMethodImplementation(rootClass, @selector(dealloc));
- // objc_getClass() so CrZombie doesn't need +class.
- g_zombieClass = objc_getClass("CrZombie");
- g_fatZombieClass = objc_getClass("CrFatZombie");
- g_fatZombieSize = class_getInstanceSize(g_fatZombieClass);
-
- if (!g_object_cxxDestruct || !g_originalDeallocIMP ||
- !g_zombieClass || !g_fatZombieClass)
- return NO;
-
- initialized = YES;
- return YES;
-}
-
-} // namespace
-
-@implementation CrZombie
-
-// The Objective-C runtime needs to be able to call this successfully.
-+ (void)initialize {
-}
-
-// Any method not explicitly defined will end up here, forcing a
-// crash.
-- (id)forwardingTargetForSelector:(SEL)aSelector {
- ZombieObjectCrash(self, aSelector, NULL);
- return nil;
-}
-
-// Override a few methods often used for dynamic dispatch to log the
-// message the caller is attempting to send, rather than the utility
-// method being used to send it.
-- (BOOL)respondsToSelector:(SEL)aSelector {
- ZombieObjectCrash(self, aSelector, _cmd);
- return NO;
-}
-
-- (id)performSelector:(SEL)aSelector {
- ZombieObjectCrash(self, aSelector, _cmd);
- return nil;
-}
-
-- (id)performSelector:(SEL)aSelector withObject:(id)anObject {
- ZombieObjectCrash(self, aSelector, _cmd);
- return nil;
-}
-
-- (id)performSelector:(SEL)aSelector
- withObject:(id)anObject
- withObject:(id)anotherObject {
- ZombieObjectCrash(self, aSelector, _cmd);
- return nil;
-}
-
-- (void)performSelector:(SEL)aSelector
- withObject:(id)anArgument
- afterDelay:(NSTimeInterval)delay {
- ZombieObjectCrash(self, aSelector, _cmd);
-}
-
-@end
-
-@implementation CrFatZombie
-
-// This implementation intentionally left empty.
-
-@end
-
-@implementation NSObject (CrZombie)
-
-- (BOOL)shouldBecomeCrZombie {
- return NO;
-}
-
-@end
-
-namespace ObjcEvilDoers {
-
-BOOL ZombieEnable(BOOL zombieAllObjects,
- size_t zombieCount) {
- // Only allow enable/disable on the main thread, just to keep things
- // simple.
- CHECK([NSThread isMainThread]);
-
- if (!ZombieInit())
- return NO;
-
- g_zombieAllObjects = zombieAllObjects;
-
- // Replace the implementation of -[NSObject dealloc].
- Method m = class_getInstanceMethod([NSObject class], @selector(dealloc));
- if (!m)
- return NO;
-
- const IMP prevDeallocIMP = method_setImplementation(m, (IMP)ZombieDealloc);
- DCHECK(prevDeallocIMP == g_originalDeallocIMP ||
- prevDeallocIMP == (IMP)ZombieDealloc);
-
- // Grab the current set of zombies. This is thread-safe because
- // only the main thread can change these.
- const size_t oldCount = g_zombieCount;
- ZombieRecord* oldZombies = g_zombies;
-
- {
- AutoLock pin(lock_);
-
- // Save the old index in case zombies need to be transferred.
- size_t oldIndex = g_zombieIndex;
-
- // Create the new zombie treadmill, disabling zombies in case of
- // failure.
- g_zombieIndex = 0;
- g_zombieCount = zombieCount;
- g_zombies = NULL;
- if (g_zombieCount) {
- g_zombies =
- static_cast<ZombieRecord*>(calloc(g_zombieCount, sizeof(*g_zombies)));
- if (!g_zombies) {
- NOTREACHED();
- g_zombies = oldZombies;
- g_zombieCount = oldCount;
- g_zombieIndex = oldIndex;
- ZombieDisable();
- return NO;
- }
- }
-
- // If the count is changing, allow some of the zombies to continue
- // shambling forward.
- const size_t sharedCount = std::min(oldCount, zombieCount);
- if (sharedCount) {
- // Get index of the first shared zombie.
- oldIndex = (oldIndex + oldCount - sharedCount) % oldCount;
-
- for (; g_zombieIndex < sharedCount; ++ g_zombieIndex) {
- DCHECK_LT(g_zombieIndex, g_zombieCount);
- DCHECK_LT(oldIndex, oldCount);
- std::swap(g_zombies[g_zombieIndex], oldZombies[oldIndex]);
- oldIndex = (oldIndex + 1) % oldCount;
- }
- g_zombieIndex %= g_zombieCount;
- }
- }
-
- // Free the old treadmill and any remaining zombies.
- if (oldZombies) {
- for (size_t i = 0; i < oldCount; ++i) {
- if (oldZombies[i].object)
- free(oldZombies[i].object);
- }
- free(oldZombies);
- }
-
- return YES;
-}
-
-void ZombieDisable() {
- // Only allow enable/disable on the main thread, just to keep things
- // simple.
- CHECK([NSThread isMainThread]);
-
- // |ZombieInit()| was never called.
- if (!g_originalDeallocIMP)
- return;
-
- // Put back the original implementation of -[NSObject dealloc].
- Method m = class_getInstanceMethod([NSObject class], @selector(dealloc));
- CHECK(m);
- method_setImplementation(m, g_originalDeallocIMP);
-
- // Can safely grab this because it only happens on the main thread.
- const size_t oldCount = g_zombieCount;
- ZombieRecord* oldZombies = g_zombies;
-
- {
- AutoLock pin(lock_); // In case any |-dealloc| are in-progress.
- g_zombieCount = 0;
- g_zombies = NULL;
- }
-
- // Free any remaining zombies.
- if (oldZombies) {
- for (size_t i = 0; i < oldCount; ++i) {
- if (oldZombies[i].object)
- free(oldZombies[i].object);
- }
- free(oldZombies);
- }
-}
-
-} // namespace ObjcEvilDoers
diff --git a/chrome/browser/cocoa/page_info_bubble_controller.h b/chrome/browser/cocoa/page_info_bubble_controller.h
deleted file mode 100644
index 4f02216..0000000
--- a/chrome/browser/cocoa/page_info_bubble_controller.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// 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 "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-#import "chrome/browser/cocoa/base_bubble_controller.h"
-#include "chrome/browser/page_info_model.h"
-
-// This NSWindowController subclass manages the InfoBubbleWindow and view that
-// are displayed when the user clicks the security lock icon.
-@interface PageInfoBubbleController : BaseBubbleController {
- @private
- // The model that generates the content displayed by the controller.
- scoped_ptr<PageInfoModel> model_;
-
- // Thin bridge that pushes model-changed notifications from C++ to Cocoa.
- scoped_ptr<PageInfoModel::PageInfoModelObserver> bridge_;
-
- // The certificate ID for the page, 0 if the page is not over HTTPS.
- int certID_;
-}
-
-@property (nonatomic, assign) int certID;
-
-// Designated initializer. The new instance will take ownership of |model| and
-// |bridge|. There should be a 1:1 mapping of models to bridges. The
-// controller will release itself when the bubble is closed.
-- (id)initWithPageInfoModel:(PageInfoModel*)model
- modelObserver:(PageInfoModel::PageInfoModelObserver*)bridge
- parentWindow:(NSWindow*)parentWindow;
-
-// Shows the certificate display window. Note that this will implicitly close
-// the bubble because the certificate window will become key. The certificate
-// information attaches itself as a sheet to the |parentWindow|.
-- (IBAction)showCertWindow:(id)sender;
-
-// Opens the help center link that explains the contents of the page info.
-- (IBAction)showHelpPage:(id)sender;
-
-@end
-
-@interface PageInfoBubbleController (ExposedForUnitTesting)
-- (void)performLayout;
-@end
diff --git a/chrome/browser/cocoa/page_info_bubble_controller.mm b/chrome/browser/cocoa/page_info_bubble_controller.mm
deleted file mode 100644
index 6c0ed77..0000000
--- a/chrome/browser/cocoa/page_info_bubble_controller.mm
+++ /dev/null
@@ -1,461 +0,0 @@
-// 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 "chrome/browser/cocoa/page_info_bubble_controller.h"
-
-#include "app/l10n_util.h"
-#include "app/l10n_util_mac.h"
-#include "base/message_loop.h"
-#include "base/sys_string_conversions.h"
-#include "base/task.h"
-#include "chrome/browser/browser_list.h"
-#include "chrome/browser/cert_store.h"
-#include "chrome/browser/certificate_viewer.h"
-#import "chrome/browser/cocoa/browser_window_controller.h"
-#import "chrome/browser/cocoa/hyperlink_button_cell.h"
-#import "chrome/browser/cocoa/info_bubble_view.h"
-#import "chrome/browser/cocoa/info_bubble_window.h"
-#import "chrome/browser/cocoa/location_bar/location_bar_view_mac.h"
-#include "chrome/browser/google/google_util.h"
-#include "chrome/browser/profile.h"
-#include "chrome/common/url_constants.h"
-#include "grit/generated_resources.h"
-#include "grit/locale_settings.h"
-#include "net/base/cert_status_flags.h"
-#include "net/base/x509_certificate.h"
-#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-
-@interface PageInfoBubbleController (Private)
-- (PageInfoModel*)model;
-- (NSButton*)certificateButtonWithFrame:(NSRect)frame;
-- (void)configureTextFieldAsLabel:(NSTextField*)textField;
-- (CGFloat)addHeadlineViewForInfo:(const PageInfoModel::SectionInfo&)info
- toSubviews:(NSMutableArray*)subviews
- atPoint:(NSPoint)point;
-- (CGFloat)addDescriptionViewForInfo:(const PageInfoModel::SectionInfo&)info
- toSubviews:(NSMutableArray*)subviews
- atPoint:(NSPoint)point;
-- (CGFloat)addCertificateButtonToSubviews:(NSMutableArray*)subviews
- atOffset:(CGFloat)offset;
-- (void)addImageViewForInfo:(const PageInfoModel::SectionInfo&)info
- toSubviews:(NSMutableArray*)subviews
- atOffset:(CGFloat)offset;
-- (CGFloat)addHelpButtonToSubviews:(NSMutableArray*)subviews
- atOffset:(CGFloat)offset;
-- (CGFloat)addSeparatorToSubviews:(NSMutableArray*)subviews
- atOffset:(CGFloat)offset;
-- (NSPoint)anchorPointForWindowWithHeight:(CGFloat)bubbleHeight
- parentWindow:(NSWindow*)parent;
-@end
-
-// This simple NSView subclass is used as the single subview of the page info
-// bubble's window's contentView. Drawing is flipped so that layout of the
-// sections is easier. Apple recommends flipping the coordinate origin when
-// doing a lot of text layout because it's more natural.
-@interface PageInfoContentView : NSView {
-}
-@end
-@implementation PageInfoContentView
-- (BOOL)isFlipped {
- return YES;
-}
-@end
-
-namespace {
-
-// The width of the window, in view coordinates. The height will be determined
-// by the content.
-const NSInteger kWindowWidth = 380;
-
-// Spacing in between sections.
-const NSInteger kVerticalSpacing = 10;
-
-// Padding along on the X-axis between the window frame and content.
-const NSInteger kFramePadding = 10;
-
-// Spacing between the optional headline and description text views.
-const NSInteger kHeadlineSpacing = 2;
-
-// Spacing between the image and the text.
-const NSInteger kImageSpacing = 10;
-
-// Square size of the image.
-const CGFloat kImageSize = 30;
-
-// The X position of the text fields. Variants for with and without an image.
-const CGFloat kTextXPositionNoImage = kFramePadding;
-const CGFloat kTextXPosition = kTextXPositionNoImage + kImageSize +
- kImageSpacing;
-
-// Width of the text fields.
-const CGFloat kTextWidth = kWindowWidth - (kImageSize + kImageSpacing +
- kFramePadding * 2);
-
-// Bridge that listens for change notifications from the model.
-class PageInfoModelBubbleBridge : public PageInfoModel::PageInfoModelObserver {
- public:
- PageInfoModelBubbleBridge()
- : controller_(nil),
- ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)) {
- }
-
- // PageInfoModelObserver implementation.
- virtual void ModelChanged() {
- // Check to see if a layout has already been scheduled.
- if (!task_factory_.empty())
- return;
-
- // Delay performing layout by a second so that all the animations from
- // InfoBubbleWindow and origin updates from BaseBubbleController finish, so
- // that we don't all race trying to change the frame's origin.
- //
- // Using ScopedRunnableMethodFactory is superior here to |-performSelector:|
- // because it will not retain its target; if the child outlives its parent,
- // zombies get left behind (http://crbug.com/59619). This will also cancel
- // the scheduled Tasks if the controller (and thus this bridge) get
- // destroyed before the message can be delivered.
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- task_factory_.NewRunnableMethod(
- &PageInfoModelBubbleBridge::PerformLayout),
- 1000 /* milliseconds */);
- }
-
- // Sets the controller.
- void set_controller(PageInfoBubbleController* controller) {
- controller_ = controller;
- }
-
- private:
- void PerformLayout() {
- [controller_ performLayout];
- }
-
- PageInfoBubbleController* controller_; // weak
-
- // Factory that vends RunnableMethod tasks for scheduling layout.
- ScopedRunnableMethodFactory<PageInfoModelBubbleBridge> task_factory_;
-};
-
-} // namespace
-
-namespace browser {
-
-void ShowPageInfoBubble(gfx::NativeWindow parent,
- Profile* profile,
- const GURL& url,
- const NavigationEntry::SSLStatus& ssl,
- bool show_history) {
- PageInfoModelBubbleBridge* bridge = new PageInfoModelBubbleBridge();
- PageInfoModel* model =
- new PageInfoModel(profile, url, ssl, show_history, bridge);
- PageInfoBubbleController* controller =
- [[PageInfoBubbleController alloc] initWithPageInfoModel:model
- modelObserver:bridge
- parentWindow:parent];
- bridge->set_controller(controller);
- [controller setCertID:ssl.cert_id()];
- [controller showWindow:nil];
-}
-
-} // namespace browser
-
-@implementation PageInfoBubbleController
-
-@synthesize certID = certID_;
-
-- (id)initWithPageInfoModel:(PageInfoModel*)model
- modelObserver:(PageInfoModel::PageInfoModelObserver*)bridge
- parentWindow:(NSWindow*)parentWindow {
- // Use an arbitrary height because it will be changed by the bridge.
- NSRect contentRect = NSMakeRect(0, 0, kWindowWidth, 0);
- // Create an empty window into which content is placed.
- scoped_nsobject<InfoBubbleWindow> window(
- [[InfoBubbleWindow alloc] initWithContentRect:contentRect
- styleMask:NSBorderlessWindowMask
- backing:NSBackingStoreBuffered
- defer:NO]);
-
- if ((self = [super initWithWindow:window.get()
- parentWindow:parentWindow
- anchoredAt:NSZeroPoint])) {
- model_.reset(model);
- bridge_.reset(bridge);
- [[self bubble] setArrowLocation:info_bubble::kTopLeft];
- [self performLayout];
- }
- return self;
-}
-
-- (PageInfoModel*)model {
- return model_.get();
-}
-
-- (IBAction)showCertWindow:(id)sender {
- DCHECK(certID_ != 0);
- ShowCertificateViewerByID([self parentWindow], certID_);
-}
-
-- (IBAction)showHelpPage:(id)sender {
- GURL url = google_util::AppendGoogleLocaleParam(
- GURL(chrome::kPageInfoHelpCenterURL));
- Browser* browser = BrowserList::GetLastActive();
- browser->OpenURL(url, GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
-}
-
-// This will create the subviews for the page info window. The general layout
-// is 2 or 3 boxed and titled sections, each of which has a status image to
-// provide visual feedback and a description that explains it. The description
-// text is usually only 1 or 2 lines, but can be much longer. At the bottom of
-// the window is a button to view the SSL certificate, which is disabled if
-// not using HTTPS.
-- (void)performLayout {
- // |offset| is the Y position that should be drawn at next.
- CGFloat offset = kFramePadding + info_bubble::kBubbleArrowHeight;
-
- // Keep the new subviews in an array that gets replaced at the end.
- NSMutableArray* subviews = [NSMutableArray array];
-
- // The subviews will be attached to the PageInfoContentView, which has a
- // flipped origin. This allows the code to build top-to-bottom.
- const int sectionCount = model_->GetSectionCount();
- for (int i = 0; i < sectionCount; ++i) {
- PageInfoModel::SectionInfo info = model_->GetSectionInfo(i);
-
- // Only certain sections have images. This affects the X position.
- BOOL hasImage = model_->GetIconImage(info.icon_id) != nil;
- CGFloat xPosition = (hasImage ? kTextXPosition : kTextXPositionNoImage);
-
- // Insert the image subview for sections that are appropriate.
- CGFloat imageBaseline = offset + kImageSize;
- if (hasImage) {
- [self addImageViewForInfo:info toSubviews:subviews atOffset:offset];
- }
-
- // Add the title.
- if (!info.headline.empty()) {
- offset += [self addHeadlineViewForInfo:info
- toSubviews:subviews
- atPoint:NSMakePoint(xPosition, offset)];
- offset += kHeadlineSpacing;
- }
-
- // Create the description of the state.
- offset += [self addDescriptionViewForInfo:info
- toSubviews:subviews
- atPoint:NSMakePoint(xPosition, offset)];
-
- if (info.type == PageInfoModel::SECTION_INFO_IDENTITY && certID_) {
- offset += kVerticalSpacing;
- offset += [self addCertificateButtonToSubviews:subviews atOffset:offset];
- }
-
- // If at this point the description and optional headline and button are
- // not as tall as the image, adjust the offset by the difference.
- CGFloat imageBaselineDelta = imageBaseline - offset;
- if (imageBaselineDelta > 0)
- offset += imageBaselineDelta;
-
- // Add the separators.
- offset += kVerticalSpacing;
- offset += [self addSeparatorToSubviews:subviews atOffset:offset];
- }
-
- // The last item at the bottom of the window is the help center link.
- offset += [self addHelpButtonToSubviews:subviews atOffset:offset];
- offset += kVerticalSpacing;
-
- // Create the dummy view that uses flipped coordinates.
- NSRect contentFrame = NSMakeRect(0, 0, kWindowWidth, offset);
- scoped_nsobject<PageInfoContentView> contentView(
- [[PageInfoContentView alloc] initWithFrame:contentFrame]);
- [contentView setSubviews:subviews];
-
- // Replace the window's content.
- [[[self window] contentView] setSubviews:
- [NSArray arrayWithObject:contentView]];
-
- NSRect windowFrame = NSMakeRect(0, 0, kWindowWidth, offset);
- windowFrame.size = [[[self window] contentView] convertSize:windowFrame.size
- toView:nil];
- // Adjust the origin by the difference in height.
- windowFrame.origin = [[self window] frame].origin;
- windowFrame.origin.y -= NSHeight(windowFrame) -
- NSHeight([[self window] frame]);
-
- // Resize the window. Only animate if the window is visible, otherwise it
- // could be "growing" while it's opening, looking awkward.
- [[self window] setFrame:windowFrame
- display:YES
- animate:[[self window] isVisible]];
-
- NSPoint anchorPoint =
- [self anchorPointForWindowWithHeight:NSHeight(windowFrame)
- parentWindow:[self parentWindow]];
- [self setAnchorPoint:anchorPoint];
-}
-
-// Creates the button with a given |frame| that, when clicked, will show the
-// SSL certificate information.
-- (NSButton*)certificateButtonWithFrame:(NSRect)frame {
- NSButton* certButton = [[[NSButton alloc] initWithFrame:frame] autorelease];
- [certButton setTitle:
- l10n_util::GetNSStringWithFixup(IDS_PAGEINFO_CERT_INFO_BUTTON)];
- [certButton setButtonType:NSMomentaryPushInButton];
- [certButton setBezelStyle:NSRoundRectBezelStyle];
- [certButton setTarget:self];
- [certButton setAction:@selector(showCertWindow:)];
- [[certButton cell] setControlSize:NSSmallControlSize];
- NSFont* font = [NSFont systemFontOfSize:
- [NSFont systemFontSizeForControlSize:NSSmallControlSize]];
- [[certButton cell] setFont:font];
- return certButton;
-}
-
-// Sets proprties on the given |field| to act as the title or description labels
-// in the bubble.
-- (void)configureTextFieldAsLabel:(NSTextField*)textField {
- [textField setEditable:NO];
- [textField setDrawsBackground:NO];
- [textField setBezeled:NO];
-}
-
-// Adds the title text field at the given x,y position, and returns the y
-// position for the next element.
-- (CGFloat)addHeadlineViewForInfo:(const PageInfoModel::SectionInfo&)info
- toSubviews:(NSMutableArray*)subviews
- atPoint:(NSPoint)point {
- NSRect frame = NSMakeRect(point.x, point.y, kTextWidth, kImageSpacing);
- scoped_nsobject<NSTextField> textField(
- [[NSTextField alloc] initWithFrame:frame]);
- [self configureTextFieldAsLabel:textField.get()];
- [textField setStringValue:base::SysUTF16ToNSString(info.headline)];
- NSFont* font = [NSFont boldSystemFontOfSize:[NSFont smallSystemFontSize]];
- [textField setFont:font];
- frame.size.height +=
- [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:
- textField];
- [textField setFrame:frame];
- [subviews addObject:textField.get()];
- return NSHeight(frame);
-}
-
-// Adds the description text field at the given x,y position, and returns the y
-// position for the next element.
-- (CGFloat)addDescriptionViewForInfo:(const PageInfoModel::SectionInfo&)info
- toSubviews:(NSMutableArray*)subviews
- atPoint:(NSPoint)point {
- NSRect frame = NSMakeRect(point.x, point.y, kTextWidth, kImageSize);
- scoped_nsobject<NSTextField> textField(
- [[NSTextField alloc] initWithFrame:frame]);
- [self configureTextFieldAsLabel:textField.get()];
- [textField setStringValue:base::SysUTF16ToNSString(info.description)];
- [textField setFont:[NSFont labelFontOfSize:[NSFont smallSystemFontSize]]];
-
- // If the text is oversized, resize the text field.
- frame.size.height +=
- [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:
- textField];
- [subviews addObject:textField.get()];
- return NSHeight(frame);
-}
-
-// Adds the certificate button at a pre-determined x position and the given y.
-// Returns the y position for the next element.
-- (CGFloat)addCertificateButtonToSubviews:(NSMutableArray*)subviews
- atOffset:(CGFloat)offset {
- // The certificate button should only be added if there is SSL information.
- DCHECK(certID_);
-
- // Create the certificate button. The frame will be fixed up by GTM, so
- // use arbitrary values.
- NSRect frame = NSMakeRect(kTextXPosition, offset, 100, 14);
- NSButton* certButton = [self certificateButtonWithFrame:frame];
- [subviews addObject:certButton];
- [GTMUILocalizerAndLayoutTweaker sizeToFitView:certButton];
-
- // By default, assume that we don't have certificate information to show.
- scoped_refptr<net::X509Certificate> cert;
- CertStore::GetSharedInstance()->RetrieveCert(certID_, &cert);
-
- // Don't bother showing certificates if there isn't one. Gears runs
- // with no OS root certificate.
- if (!cert.get() || !cert->os_cert_handle()) {
- // This should only ever happen in unit tests.
- [certButton setEnabled:NO];
- }
-
- return NSHeight([certButton frame]);
-}
-
-// Adds the state image at a pre-determined x position and the given y. This
-// does not affect the next Y position because the image is placed next to
-// a text field that is larger and accounts for the image's size.
-- (void)addImageViewForInfo:(const PageInfoModel::SectionInfo&)info
- toSubviews:(NSMutableArray*)subviews
- atOffset:(CGFloat)offset {
- NSRect frame = NSMakeRect(kFramePadding, offset, kImageSize,
- kImageSize);
- scoped_nsobject<NSImageView> imageView(
- [[NSImageView alloc] initWithFrame:frame]);
- [imageView setImageFrameStyle:NSImageFrameNone];
- [imageView setImage:model_->GetIconImage(info.icon_id)];
- [subviews addObject:imageView.get()];
-}
-
-// Adds the help center button that explains the icons. Returns the y position
-// delta for the next offset.
-- (CGFloat)addHelpButtonToSubviews:(NSMutableArray*)subviews
- atOffset:(CGFloat)offset {
- NSRect frame = NSMakeRect(kFramePadding, offset, 100, 10);
- scoped_nsobject<NSButton> button([[NSButton alloc] initWithFrame:frame]);
- NSString* string =
- l10n_util::GetNSStringWithFixup(IDS_PAGE_INFO_HELP_CENTER_LINK);
- scoped_nsobject<HyperlinkButtonCell> cell(
- [[HyperlinkButtonCell alloc] initTextCell:string]);
- [cell setControlSize:NSSmallControlSize];
- [button setCell:cell.get()];
- [button setButtonType:NSMomentaryPushInButton];
- [button setBezelStyle:NSRegularSquareBezelStyle];
- [button setTarget:self];
- [button setAction:@selector(showHelpPage:)];
- [subviews addObject:button.get()];
-
- // Call size-to-fit to fixup for the localized string.
- [GTMUILocalizerAndLayoutTweaker sizeToFitView:button.get()];
- return NSHeight([button frame]);
-}
-
-// Adds a 1px separator between sections. Returns the y position delta for the
-// next offset.
-- (CGFloat)addSeparatorToSubviews:(NSMutableArray*)subviews
- atOffset:(CGFloat)offset {
- const CGFloat kSpacerHeight = 1.0;
- NSRect frame = NSMakeRect(kFramePadding, offset,
- kWindowWidth - 2 * kFramePadding, kSpacerHeight);
- scoped_nsobject<NSBox> spacer([[NSBox alloc] initWithFrame:frame]);
- [spacer setBoxType:NSBoxSeparator];
- [spacer setBorderType:NSLineBorder];
- [spacer setAlphaValue:0.2];
- [subviews addObject:spacer.get()];
- return kVerticalSpacing + kSpacerHeight;
-}
-
-// Takes in the bubble's height and the parent window, which should be a
-// BrowserWindow, and gets the proper anchor point for the bubble. The returned
-// point is in screen coordinates.
-- (NSPoint)anchorPointForWindowWithHeight:(CGFloat)bubbleHeight
- parentWindow:(NSWindow*)parent {
- BrowserWindowController* controller = [parent windowController];
- NSPoint origin = NSZeroPoint;
- if ([controller isKindOfClass:[BrowserWindowController class]]) {
- LocationBarViewMac* locationBar = [controller locationBarBridge];
- if (locationBar) {
- NSPoint bubblePoint = locationBar->GetPageInfoBubblePoint();
- origin = [parent convertBaseToScreen:bubblePoint];
- }
- }
- return origin;
-}
-
-@end
diff --git a/chrome/browser/cocoa/page_info_bubble_controller_unittest.mm b/chrome/browser/cocoa/page_info_bubble_controller_unittest.mm
deleted file mode 100644
index 3354577..0000000
--- a/chrome/browser/cocoa/page_info_bubble_controller_unittest.mm
+++ /dev/null
@@ -1,210 +0,0 @@
-// 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.
-
-#include "app/l10n_util.h"
-#include "base/scoped_nsobject.h"
-#include "base/string_util.h"
-#include "base/string_number_conversions.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#import "chrome/browser/cocoa/hyperlink_button_cell.h"
-#import "chrome/browser/cocoa/page_info_bubble_controller.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/page_info_model.h"
-#include "grit/generated_resources.h"
-
-namespace {
-
-class FakeModel : public PageInfoModel {
- public:
- FakeModel() : PageInfoModel() {}
-
- void AddSection(SectionStateIcon icon_id,
- const string16& headline,
- const string16& description,
- SectionInfoType type) {
- sections_.push_back(SectionInfo(
- icon_id, headline, description, type));
- }
-};
-
-class FakeBridge : public PageInfoModel::PageInfoModelObserver {
- public:
- void ModelChanged() {}
-};
-
-class PageInfoBubbleControllerTest : public CocoaTest {
- public:
- PageInfoBubbleControllerTest() {
- controller_ = nil;
- model_ = new FakeModel();
- }
-
- virtual void TearDown() {
- [controller_ close];
- CocoaTest::TearDown();
- }
-
- void CreateBubble() {
- // The controller cleans up after itself when the window closes.
- controller_ =
- [[PageInfoBubbleController alloc] initWithPageInfoModel:model_
- modelObserver:NULL
- parentWindow:test_window()];
- window_ = [controller_ window];
- [controller_ showWindow:nil];
- }
-
- // Checks the controller's window for the requisite subviews in the given
- // numbers.
- void CheckWindow(int text_count,
- int image_count,
- int spacer_count,
- int button_count) {
- // All windows have the help center link and a spacer for it.
- int link_count = 1;
- ++spacer_count;
-
- // The window's only immediate child is an invisible view that has a flipped
- // coordinate origin. It is into this that all views get placed.
- NSArray* windowSubviews = [[window_ contentView] subviews];
- EXPECT_EQ(1U, [windowSubviews count]);
- NSArray* subviews = [[windowSubviews lastObject] subviews];
-
- for (NSView* view in subviews) {
- if ([view isKindOfClass:[NSTextField class]]) {
- --text_count;
- } else if ([view isKindOfClass:[NSImageView class]]) {
- --image_count;
- } else if ([view isKindOfClass:[NSBox class]]) {
- --spacer_count;
- } else if ([view isKindOfClass:[NSButton class]]) {
- NSButton* button = static_cast<NSButton*>(view);
- // Every window should have a single link button to the help page.
- if ([[button cell] isKindOfClass:[HyperlinkButtonCell class]]) {
- --link_count;
- CheckButton(button, @selector(showHelpPage:));
- } else {
- --button_count;
- CheckButton(button, @selector(showCertWindow:));
- }
- } else {
- ADD_FAILURE() << "Unknown subview: " << [[view description] UTF8String];
- }
- }
- EXPECT_EQ(0, text_count);
- EXPECT_EQ(0, image_count);
- EXPECT_EQ(0, spacer_count);
- EXPECT_EQ(0, button_count);
- EXPECT_EQ(0, link_count);
- EXPECT_EQ([window_ delegate], controller_);
- }
-
- // Checks that a button is hooked up correctly.
- void CheckButton(NSButton* button, SEL action) {
- EXPECT_EQ(action, [button action]);
- EXPECT_EQ(controller_, [button target]);
- EXPECT_TRUE([button stringValue]);
- }
-
- BrowserTestHelper helper_;
-
- PageInfoBubbleController* controller_; // Weak, owns self.
- FakeModel* model_; // Weak, owned by controller.
- NSWindow* window_; // Weak, owned by controller.
-};
-
-
-TEST_F(PageInfoBubbleControllerTest, NoHistoryNoSecurity) {
- model_->AddSection(PageInfoModel::ICON_STATE_ERROR,
- string16(),
- l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY),
- PageInfoModel::SECTION_INFO_IDENTITY);
- model_->AddSection(PageInfoModel::ICON_STATE_ERROR,
- string16(),
- l10n_util::GetStringFUTF16(
- IDS_PAGE_INFO_SECURITY_TAB_NOT_ENCRYPTED_CONNECTION_TEXT,
- ASCIIToUTF16("google.com")),
- PageInfoModel::SECTION_INFO_CONNECTION);
-
- CreateBubble();
- CheckWindow(/*text=*/2, /*image=*/2, /*spacer=*/1, /*button=*/0);
-}
-
-
-TEST_F(PageInfoBubbleControllerTest, HistoryNoSecurity) {
- model_->AddSection(PageInfoModel::ICON_STATE_ERROR,
- string16(),
- l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY),
- PageInfoModel::SECTION_INFO_IDENTITY);
- model_->AddSection(PageInfoModel::ICON_STATE_ERROR,
- string16(),
- l10n_util::GetStringFUTF16(
- IDS_PAGE_INFO_SECURITY_TAB_NOT_ENCRYPTED_CONNECTION_TEXT,
- ASCIIToUTF16("google.com")),
- PageInfoModel::SECTION_INFO_CONNECTION);
-
- // In practice, the history information comes later because it's queried
- // asynchronously, so replicate the double-build here.
- CreateBubble();
-
- model_->AddSection(PageInfoModel::ICON_STATE_ERROR,
- l10n_util::GetStringUTF16(IDS_PAGE_INFO_SITE_INFO_TITLE),
- l10n_util::GetStringUTF16(
- IDS_PAGE_INFO_SECURITY_TAB_FIRST_VISITED_TODAY),
- PageInfoModel::SECTION_INFO_FIRST_VISIT);
-
- [controller_ performLayout];
-
- CheckWindow(/*text=*/4, /*image=*/3, /*spacer=*/2, /*button=*/0);
-}
-
-
-TEST_F(PageInfoBubbleControllerTest, NoHistoryMixedSecurity) {
- model_->AddSection(PageInfoModel::ICON_STATE_OK,
- string16(),
- l10n_util::GetStringFUTF16(
- IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY,
- ASCIIToUTF16("Goat Security Systems")),
- PageInfoModel::SECTION_INFO_IDENTITY);
-
- // This string is super long and the text should overflow the default clip
- // region (kImageSize).
- string16 description = l10n_util::GetStringFUTF16(
- IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_SENTENCE_LINK,
- l10n_util::GetStringFUTF16(
- IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_CONNECTION_TEXT,
- ASCIIToUTF16("chrome.google.com"),
- base::IntToString16(1024)),
- l10n_util::GetStringUTF16(
- IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_INSECURE_CONTENT_WARNING));
-
- model_->AddSection(PageInfoModel::ICON_STATE_OK,
- string16(),
- description,
- PageInfoModel::SECTION_INFO_CONNECTION);
-
-
- CreateBubble();
- [controller_ setCertID:1];
- [controller_ performLayout];
-
- CheckWindow(/*text=*/2, /*image=*/2, /*spacer=*/1, /*button=*/1);
-
- // Look for the over-sized box.
- NSString* targetDesc = base::SysUTF16ToNSString(description);
- NSArray* subviews = [[window_ contentView] subviews];
- for (NSView* subview in subviews) {
- if ([subview isKindOfClass:[NSTextField class]]) {
- NSTextField* desc = static_cast<NSTextField*>(subview);
- if ([[desc stringValue] isEqualToString:targetDesc]) {
- // Typical box frame is ~55px, make sure this is extra large.
- EXPECT_LT(75, NSHeight([desc frame]));
- }
- }
- }
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/preferences_window_controller.h b/chrome/browser/cocoa/preferences_window_controller.h
deleted file mode 100644
index cfec955..0000000
--- a/chrome/browser/cocoa/preferences_window_controller.h
+++ /dev/null
@@ -1,241 +0,0 @@
-// 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 "base/scoped_ptr.h"
-#include "base/scoped_nsobject.h"
-#include "chrome/browser/options_window.h"
-#include "chrome/browser/prefs/pref_member.h"
-#include "chrome/browser/prefs/pref_set_observer.h"
-#include "chrome/browser/prefs/pref_change_registrar.h"
-
-namespace PreferencesWindowControllerInternal {
-class PrefObserverBridge;
-class ManagedPrefsBannerState;
-}
-
-@class CustomHomePagesModel;
-@class FontLanguageSettingsController;
-class PrefService;
-class Profile;
-class ProfileSyncService;
-@class SearchEngineListModel;
-@class VerticalGradientView;
-@class WindowSizeAutosaver;
-
-// A window controller that handles the preferences window. The bulk of the
-// work is handled via Cocoa Bindings and getter/setter methods that wrap
-// cross-platform PrefMember objects. When prefs change in the back-end
-// (that is, outside of this UI), our observer receives a notification and can
-// tickle the KVO to update the UI so we are always in sync. The bindings are
-// specified in the nib file. Preferences are persisted into the back-end
-// as they are changed in the UI, and are thus immediately available even while
-// the window is still open. When the window closes, a notification is sent
-// via the system NotificationCenter. This can be used as a signal to
-// release this controller, as it's likely the client wants to enforce there
-// only being one (we don't do that internally as it makes it very difficult
-// to unit test).
-@interface PreferencesWindowController : NSWindowController {
- @private
- Profile* profile_; // weak ref
- OptionsPage initialPage_;
- PrefService* prefs_; // weak ref - Obtained from profile_ for convenience.
- // weak ref - Also obtained from profile_ for convenience. May be NULL.
- ProfileSyncService* syncService_;
- scoped_ptr<PreferencesWindowControllerInternal::PrefObserverBridge>
- observer_; // Watches for pref changes.
- PrefChangeRegistrar registrar_; // Manages pref change observer registration.
- scoped_nsobject<WindowSizeAutosaver> sizeSaver_;
- NSView* currentPrefsView_; // weak ref - current prefs page view.
- scoped_ptr<PreferencesWindowControllerInternal::ManagedPrefsBannerState>
- bannerState_;
- BOOL managedPrefsBannerVisible_;
-
- IBOutlet NSToolbar* toolbar_;
- IBOutlet VerticalGradientView* managedPrefsBannerView_;
- IBOutlet NSImageView* managedPrefsBannerWarningImage_;
-
- // The views we'll rotate through
- IBOutlet NSView* basicsView_;
- IBOutlet NSView* personalStuffView_;
- IBOutlet NSView* underTheHoodView_;
- // The last page the user was on when they opened the Options window.
- IntegerPrefMember lastSelectedPage_;
-
- // The groups of the Basics view for layout fixup.
- IBOutlet NSArray* basicsGroupStartup_;
- IBOutlet NSArray* basicsGroupHomePage_;
- IBOutlet NSArray* basicsGroupToolbar_;
- IBOutlet NSArray* basicsGroupSearchEngine_;
- IBOutlet NSArray* basicsGroupDefaultBrowser_;
-
- // The groups of the Personal Stuff view for layout fixup.
- IBOutlet NSArray* personalStuffGroupSync_;
- IBOutlet NSArray* personalStuffGroupPasswords_;
- IBOutlet NSArray* personalStuffGroupAutofill_;
- IBOutlet NSArray* personalStuffGroupBrowserData_;
- IBOutlet NSArray* personalStuffGroupThemes_;
-
- // Having two animations around is bad (they fight), so just use one.
- scoped_nsobject<NSViewAnimation> animation_;
-
- IBOutlet NSArrayController* customPagesArrayController_;
-
- // Basics panel
- IntegerPrefMember restoreOnStartup_;
- scoped_nsobject<CustomHomePagesModel> customPagesSource_;
- BooleanPrefMember newTabPageIsHomePage_;
- StringPrefMember homepage_;
- BooleanPrefMember showHomeButton_;
- BooleanPrefMember instantEnabled_;
- IBOutlet NSButton* instantCheckbox_;
- IBOutlet NSTextField* instantExperiment_;
- scoped_nsobject<SearchEngineListModel> searchEngineModel_;
- // Used when creating a new home page url to make the new cell editable.
- BOOL pendingSelectForEdit_;
- BOOL restoreButtonsEnabled_;
- BOOL restoreURLsEnabled_;
- BOOL showHomeButtonEnabled_;
- BOOL defaultSearchEngineEnabled_;
-
- // User Data panel
- BooleanPrefMember askSavePasswords_;
- BooleanPrefMember autoFillEnabled_;
- IBOutlet NSButton* autoFillSettingsButton_;
- IBOutlet NSButton* syncButton_;
- IBOutlet NSButton* syncCustomizeButton_;
- IBOutlet NSTextField* syncStatus_;
- IBOutlet NSButton* syncLink_;
- IBOutlet NSButton* privacyDashboardLink_;
- scoped_nsobject<NSColor> syncStatusNoErrorBackgroundColor_;
- scoped_nsobject<NSColor> syncLinkNoErrorBackgroundColor_;
- scoped_nsobject<NSColor> syncErrorBackgroundColor_;
- BOOL passwordManagerChoiceEnabled_;
- BOOL passwordManagerButtonEnabled_;
- BOOL autoFillSettingsButtonEnabled_;
-
- // Under the hood panel
- IBOutlet NSView* underTheHoodContentView_;
- IBOutlet NSScrollView* underTheHoodScroller_;
- IBOutlet NSButton* contentSettingsButton_;
- IBOutlet NSButton* clearDataButton_;
- BooleanPrefMember alternateErrorPages_;
- BooleanPrefMember useSuggest_;
- BooleanPrefMember dnsPrefetch_;
- BooleanPrefMember safeBrowsing_;
- BooleanPrefMember metricsReporting_;
- IBOutlet NSPathControl* downloadLocationControl_;
- IBOutlet NSButton* downloadLocationButton_;
- StringPrefMember defaultDownloadLocation_;
- BooleanPrefMember askForSaveLocation_;
- IBOutlet NSButton* resetFileHandlersButton_;
- StringPrefMember autoOpenFiles_;
- BooleanPrefMember translateEnabled_;
- BooleanPrefMember tabsToLinks_;
- FontLanguageSettingsController* fontLanguageSettings_;
- StringPrefMember currentTheme_;
- IBOutlet NSButton* enableLoggingCheckbox_;
- scoped_ptr<PrefSetObserver> proxyPrefs_;
- BOOL showAlternateErrorPagesEnabled_;
- BOOL useSuggestEnabled_;
- BOOL dnsPrefetchEnabled_;
- BOOL safeBrowsingEnabled_;
- BOOL metricsReportingEnabled_;
- BOOL proxiesConfigureButtonEnabled_;
-}
-
-// Designated initializer. |profile| should not be NULL.
-- (id)initWithProfile:(Profile*)profile initialPage:(OptionsPage)initialPage;
-
-// Show the preferences window.
-- (void)showPreferences:(id)sender;
-
-// Switch to the given preference page.
-- (void)switchToPage:(OptionsPage)page animate:(BOOL)animate;
-
-// Enables or disables the restoreOnStartup elements
-- (void) setEnabledStateOfRestoreOnStartup;
-
-// IBAction methods for responding to user actions.
-
-// Basics panel
-- (IBAction)addHomepage:(id)sender;
-- (IBAction)removeSelectedHomepages:(id)sender;
-- (IBAction)useCurrentPagesAsHomepage:(id)sender;
-- (IBAction)manageSearchEngines:(id)sender;
-- (IBAction)toggleInstant:(id)sender;
-- (IBAction)learnMoreAboutInstant:(id)sender;
-- (IBAction)makeDefaultBrowser:(id)sender;
-
-// User Data panel
-- (IBAction)doSyncAction:(id)sender;
-- (IBAction)doSyncCustomize:(id)sender;
-- (IBAction)doSyncReauthentication:(id)sender;
-- (IBAction)showPrivacyDashboard:(id)sender;
-- (IBAction)showSavedPasswords:(id)sender;
-- (IBAction)showAutoFillSettings:(id)sender;
-- (IBAction)importData:(id)sender;
-- (IBAction)resetThemeToDefault:(id)sender;
-- (IBAction)themesGallery:(id)sender;
-
-// Under the hood
-- (IBAction)showContentSettings:(id)sender;
-- (IBAction)clearData:(id)sender;
-- (IBAction)privacyLearnMore:(id)sender;
-- (IBAction)browseDownloadLocation:(id)sender;
-- (IBAction)resetAutoOpenFiles:(id)sender;
-- (IBAction)changeFontAndLanguageSettings:(id)sender;
-- (IBAction)openProxyPreferences:(id)sender;
-- (IBAction)showCertificates:(id)sender;
-- (IBAction)resetToDefaults:(id)sender;
-
-// When a toolbar button is clicked
-- (IBAction)toolbarButtonSelected:(id)sender;
-
-// Usable from cocoa bindings to hook up the custom home pages table.
-@property (nonatomic, readonly) CustomHomePagesModel* customPagesSource;
-
-// Properties for the enabled state of various UI elements. Keep these ordered
-// by occurrence on the dialog.
-@property (nonatomic) BOOL restoreButtonsEnabled;
-@property (nonatomic) BOOL restoreURLsEnabled;
-@property (nonatomic) BOOL showHomeButtonEnabled;
-@property (nonatomic) BOOL defaultSearchEngineEnabled;
-@property (nonatomic) BOOL passwordManagerChoiceEnabled;
-@property (nonatomic) BOOL passwordManagerButtonEnabled;
-@property (nonatomic) BOOL autoFillSettingsButtonEnabled;
-@property (nonatomic) BOOL showAlternateErrorPagesEnabled;
-@property (nonatomic) BOOL useSuggestEnabled;
-@property (nonatomic) BOOL dnsPrefetchEnabled;
-@property (nonatomic) BOOL safeBrowsingEnabled;
-@property (nonatomic) BOOL metricsReportingEnabled;
-@property (nonatomic) BOOL proxiesConfigureButtonEnabled;
-@end
-
-@interface PreferencesWindowController(Testing)
-
-- (IntegerPrefMember*)lastSelectedPage;
-- (NSToolbar*)toolbar;
-- (NSView*)basicsView;
-- (NSView*)personalStuffView;
-- (NSView*)underTheHoodView;
-
-// Converts the given OptionsPage value (which may be OPTIONS_PAGE_DEFAULT)
-// into a concrete OptionsPage value.
-- (OptionsPage)normalizePage:(OptionsPage)page;
-
-// Returns the toolbar item corresponding to the given page. Should be
-// called only after awakeFromNib is.
-- (NSToolbarItem*)getToolbarItemForPage:(OptionsPage)page;
-
-// Returns the (normalized) page corresponding to the given toolbar item.
-// Should be called only after awakeFromNib is.
-- (OptionsPage)getPageForToolbarItem:(NSToolbarItem*)toolbarItem;
-
-// Returns the view corresponding to the given page. Should be called
-// only after awakeFromNib is.
-- (NSView*)getPrefsViewForPage:(OptionsPage)page;
-
-@end
diff --git a/chrome/browser/cocoa/preferences_window_controller.mm b/chrome/browser/cocoa/preferences_window_controller.mm
deleted file mode 100644
index b3d4205..0000000
--- a/chrome/browser/cocoa/preferences_window_controller.mm
+++ /dev/null
@@ -1,2184 +0,0 @@
-// 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 "chrome/browser/cocoa/preferences_window_controller.h"
-
-#include <algorithm>
-
-#include "app/l10n_util.h"
-#include "app/l10n_util_mac.h"
-#include "app/resource_bundle.h"
-#include "base/logging.h"
-#include "base/mac_util.h"
-#include "base/mac/scoped_aedesc.h"
-#include "base/string16.h"
-#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/autofill/autofill_dialog.h"
-#include "chrome/browser/autofill/autofill_type.h"
-#include "chrome/browser/autofill/personal_data_manager.h"
-#include "chrome/browser/browser_process.h"
-#import "chrome/browser/cocoa/clear_browsing_data_controller.h"
-#import "chrome/browser/cocoa/content_settings_dialog_controller.h"
-#import "chrome/browser/cocoa/custom_home_pages_model.h"
-#import "chrome/browser/cocoa/font_language_settings_controller.h"
-#import "chrome/browser/cocoa/import_settings_dialog.h"
-#import "chrome/browser/cocoa/keyword_editor_cocoa_controller.h"
-#import "chrome/browser/cocoa/l10n_util.h"
-#import "chrome/browser/cocoa/search_engine_list_model.h"
-#import "chrome/browser/cocoa/vertical_gradient_view.h"
-#import "chrome/browser/cocoa/window_size_autosaver.h"
-#include "chrome/browser/download/download_manager.h"
-#include "chrome/browser/download/download_prefs.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/google/google_util.h"
-#include "chrome/browser/instant/instant_confirm_dialog.h"
-#include "chrome/browser/instant/instant_controller.h"
-#include "chrome/browser/metrics/metrics_service.h"
-#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/net/url_fixer_upper.h"
-#include "chrome/browser/options_util.h"
-#include "chrome/browser/options_window.h"
-#include "chrome/browser/policy/managed_prefs_banner_base.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/prefs/session_startup_pref.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/safe_browsing/safe_browsing_service.h"
-#include "chrome/browser/shell_integration.h"
-#include "chrome/browser/show_options_url.h"
-#include "chrome/browser/sync/profile_sync_service.h"
-#include "chrome/browser/sync/sync_ui_util.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_list.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/notification_details.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_type.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/url_constants.h"
-#include "chrome/installer/util/google_update_settings.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-#include "grit/locale_settings.h"
-#include "grit/theme_resources.h"
-#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
-#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-
-namespace {
-
-// Colors for the managed preferences warning banner.
-static const double kBannerGradientColorTop[3] =
- {255.0 / 255.0, 242.0 / 255.0, 183.0 / 255.0};
-static const double kBannerGradientColorBottom[3] =
- {250.0 / 255.0, 230.0 / 255.0, 145.0 / 255.0};
-static const double kBannerStrokeColor = 135.0 / 255.0;
-
-// Tag id for retrieval via viewWithTag in NSView (from IB).
-static const uint32 kBasicsStartupPageTableTag = 1000;
-
-bool IsNewTabUIURLString(const GURL& url) {
- return url == GURL(chrome::kChromeUINewTabURL);
-}
-
-// Helper that sizes two buttons to fit in a row keeping their spacing, returns
-// the total horizontal size change.
-CGFloat SizeToFitButtonPair(NSButton* leftButton, NSButton* rightButton) {
- CGFloat widthShift = 0.0;
-
- NSSize delta = [GTMUILocalizerAndLayoutTweaker sizeToFitView:leftButton];
- DCHECK_EQ(delta.height, 0.0) << "Height changes unsupported";
- widthShift += delta.width;
-
- if (widthShift != 0.0) {
- NSPoint origin = [rightButton frame].origin;
- origin.x += widthShift;
- [rightButton setFrameOrigin:origin];
- }
- delta = [GTMUILocalizerAndLayoutTweaker sizeToFitView:rightButton];
- DCHECK_EQ(delta.height, 0.0) << "Height changes unsupported";
- widthShift += delta.width;
-
- return widthShift;
-}
-
-// The different behaviors for the "pref group" auto sizing.
-enum AutoSizeGroupBehavior {
- kAutoSizeGroupBehaviorVerticalToFit,
- kAutoSizeGroupBehaviorVerticalFirstToFit,
- kAutoSizeGroupBehaviorHorizontalToFit,
- kAutoSizeGroupBehaviorHorizontalFirstGrows,
- kAutoSizeGroupBehaviorFirstTwoAsRowVerticalToFit
-};
-
-// Helper to tweak the layout of the "pref groups" and also ripple any height
-// changes from one group to the next groups' origins.
-// |views| is an ordered list of views with first being the label for the
-// group and the rest being top down or left to right ordering of the views.
-// The label is assumed to already be the same height as all the views it is
-// next too.
-CGFloat AutoSizeGroup(NSArray* views, AutoSizeGroupBehavior behavior,
- CGFloat verticalShift) {
- DCHECK_GE([views count], 2U) << "Should be at least a label and a control";
- NSTextField* label = [views objectAtIndex:0];
- DCHECK([label isKindOfClass:[NSTextField class]])
- << "First view should be the label for the group";
-
- // Auto size the label to see if we need more vertical space for its localized
- // string.
- CGFloat labelHeightChange =
- [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:label];
-
- CGFloat localVerticalShift = 0.0;
- switch (behavior) {
- case kAutoSizeGroupBehaviorVerticalToFit: {
- // Walk bottom up doing the sizing and moves.
- for (NSUInteger index = [views count] - 1; index > 0; --index) {
- NSView* view = [views objectAtIndex:index];
- NSSize delta = cocoa_l10n_util::WrapOrSizeToFit(view);
- DCHECK_GE(delta.height, 0.0) << "Should NOT shrink in height";
- if (localVerticalShift) {
- NSPoint origin = [view frame].origin;
- origin.y += localVerticalShift;
- [view setFrameOrigin:origin];
- }
- localVerticalShift += delta.height;
- }
- break;
- }
- case kAutoSizeGroupBehaviorVerticalFirstToFit: {
- // Just size the top one.
- NSView* view = [views objectAtIndex:1];
- NSSize delta = cocoa_l10n_util::WrapOrSizeToFit(view);
- DCHECK_GE(delta.height, 0.0) << "Should NOT shrink in height";
- localVerticalShift += delta.height;
- break;
- }
- case kAutoSizeGroupBehaviorHorizontalToFit: {
- // Walk left to right doing the sizing and moves.
- // NOTE: Don't worry about vertical, assume it always fits.
- CGFloat horizontalShift = 0.0;
- NSUInteger count = [views count];
- for (NSUInteger index = 1; index < count; ++index) {
- NSView* view = [views objectAtIndex:index];
- NSSize delta = cocoa_l10n_util::WrapOrSizeToFit(view);
- DCHECK_GE(delta.height, 0.0) << "Should NOT shrink in height";
- if (horizontalShift) {
- NSPoint origin = [view frame].origin;
- origin.x += horizontalShift;
- [view setFrameOrigin:origin];
- }
- horizontalShift += delta.width;
- }
- break;
- }
- case kAutoSizeGroupBehaviorHorizontalFirstGrows: {
- // Walk right to left doing the sizing and moves, then apply the space
- // collected into the first.
- // NOTE: Don't worry about vertical, assume it always all fits.
- CGFloat horizontalShift = 0.0;
- for (NSUInteger index = [views count] - 1; index > 1; --index) {
- NSView* view = [views objectAtIndex:index];
- NSSize delta = cocoa_l10n_util::WrapOrSizeToFit(view);
- DCHECK_GE(delta.height, 0.0) << "Should NOT shrink in height";
- horizontalShift -= delta.width;
- NSPoint origin = [view frame].origin;
- origin.x += horizontalShift;
- [view setFrameOrigin:origin];
- }
- if (horizontalShift) {
- NSView* view = [views objectAtIndex:1];
- NSSize delta = NSMakeSize(horizontalShift, 0.0);
- [GTMUILocalizerAndLayoutTweaker
- resizeViewWithoutAutoResizingSubViews:view
- delta:delta];
- }
- break;
- }
- case kAutoSizeGroupBehaviorFirstTwoAsRowVerticalToFit: {
- // Start out like kAutoSizeGroupBehaviorVerticalToFit but don't do
- // the first two. Then handle the two as a row, but apply any
- // vertical shift.
- // All but the first two (in the row); walk bottom up.
- for (NSUInteger index = [views count] - 1; index > 2; --index) {
- NSView* view = [views objectAtIndex:index];
- NSSize delta = cocoa_l10n_util::WrapOrSizeToFit(view);
- DCHECK_GE(delta.height, 0.0) << "Should NOT shrink in height";
- if (localVerticalShift) {
- NSPoint origin = [view frame].origin;
- origin.y += localVerticalShift;
- [view setFrameOrigin:origin];
- }
- localVerticalShift += delta.height;
- }
- // Deal with the two for the horizontal row. Size the second one.
- CGFloat horizontalShift = 0.0;
- NSView* view = [views objectAtIndex:2];
- NSSize delta = cocoa_l10n_util::WrapOrSizeToFit(view);
- DCHECK_GE(delta.height, 0.0) << "Should NOT shrink in height";
- horizontalShift -= delta.width;
- NSPoint origin = [view frame].origin;
- origin.x += horizontalShift;
- if (localVerticalShift) {
- origin.y += localVerticalShift;
- }
- [view setFrameOrigin:origin];
- // Now expand the first item in the row to consume the space opened up.
- view = [views objectAtIndex:1];
- if (horizontalShift) {
- NSSize delta = NSMakeSize(horizontalShift, 0.0);
- [GTMUILocalizerAndLayoutTweaker
- resizeViewWithoutAutoResizingSubViews:view
- delta:delta];
- }
- // And move it up by any amount needed from the previous items.
- if (localVerticalShift) {
- NSPoint origin = [view frame].origin;
- origin.y += localVerticalShift;
- [view setFrameOrigin:origin];
- }
- break;
- }
- default:
- NOTREACHED();
- break;
- }
-
- // If the label grew more then the views, the other views get an extra shift.
- // Otherwise, move the label to its top is aligned with the other views.
- CGFloat nonLabelShift = 0.0;
- if (labelHeightChange > localVerticalShift) {
- // Since the lable is taller, centering the other views looks best, just
- // shift the views by 1/2 of the size difference.
- nonLabelShift = (labelHeightChange - localVerticalShift) / 2.0;
- } else {
- NSPoint origin = [label frame].origin;
- origin.y += localVerticalShift - labelHeightChange;
- [label setFrameOrigin:origin];
- }
-
- // Apply the input shift requested along with any the shift from label being
- // taller then the rest of the group.
- for (NSView* view in views) {
- NSPoint origin = [view frame].origin;
- origin.y += verticalShift;
- if (view != label) {
- origin.y += nonLabelShift;
- }
- [view setFrameOrigin:origin];
- }
-
- // Return how much the group grew.
- return localVerticalShift + nonLabelShift;
-}
-
-// Helper to remove a view and move everything above it down to take over the
-// space.
-void RemoveViewFromView(NSView* view, NSView* toRemove) {
- // Sort bottom up so we can spin over what is above it.
- NSArray* views =
- [[view subviews] sortedArrayUsingFunction:cocoa_l10n_util::CompareFrameY
- context:NULL];
-
- // Find where |toRemove| was.
- NSUInteger index = [views indexOfObject:toRemove];
- DCHECK_NE(index, NSNotFound);
- NSUInteger count = [views count];
- CGFloat shrinkHeight = 0;
- if (index < (count - 1)) {
- // If we're not the topmost control, the amount to shift is the bottom of
- // |toRemove| to the bottom of the view above it.
- CGFloat shiftDown =
- NSMinY([[views objectAtIndex:index + 1] frame]) -
- NSMinY([toRemove frame]);
-
- // Now cycle over the views above it moving them down.
- for (++index; index < count; ++index) {
- NSView* view = [views objectAtIndex:index];
- NSPoint origin = [view frame].origin;
- origin.y -= shiftDown;
- [view setFrameOrigin:origin];
- }
-
- shrinkHeight = shiftDown;
- } else if (index > 0) {
- // If we're the topmost control, there's nothing to shift but we want to
- // shrink until the top edge of the second-topmost control, unless it is
- // actually higher than the topmost control (since we're sorting by the
- // bottom edge).
- shrinkHeight = std::max(0.f,
- NSMaxY([toRemove frame]) -
- NSMaxY([[views objectAtIndex:index - 1] frame]));
- }
- // If we only have one control, don't do any resizing (for now).
-
- // Remove |toRemove|.
- [toRemove removeFromSuperview];
-
- [GTMUILocalizerAndLayoutTweaker
- resizeViewWithoutAutoResizingSubViews:view
- delta:NSMakeSize(0, -shrinkHeight)];
-}
-
-// Simply removes all the views in |toRemove|.
-void RemoveGroupFromView(NSView* view, NSArray* toRemove) {
- for (NSView* viewToRemove in toRemove) {
- RemoveViewFromView(view, viewToRemove);
- }
-}
-
-// Helper to tweak the layout of the "Under the Hood" content by autosizing all
-// the views and moving things up vertically. Special case the two controls for
-// download location as they are horizontal, and should fill the row. Special
-// case "Content Settings" and "Clear browsing data" as they are horizontal as
-// well.
-CGFloat AutoSizeUnderTheHoodContent(NSView* view,
- NSPathControl* downloadLocationControl,
- NSButton* downloadLocationButton) {
- CGFloat verticalShift = 0.0;
-
- // Loop bottom up through the views sizing and shifting.
- NSArray* views =
- [[view subviews] sortedArrayUsingFunction:cocoa_l10n_util::CompareFrameY
- context:NULL];
- for (NSView* view in views) {
- NSSize delta = cocoa_l10n_util::WrapOrSizeToFit(view);
- DCHECK_GE(delta.height, 0.0) << "Should NOT shrink in height";
- if (verticalShift) {
- NSPoint origin = [view frame].origin;
- origin.y += verticalShift;
- [view setFrameOrigin:origin];
- }
- verticalShift += delta.height;
-
- // The Download Location controls go in a row with the button aligned to the
- // right edge and the path control using all the rest of the space.
- if (view == downloadLocationButton) {
- NSPoint origin = [downloadLocationButton frame].origin;
- origin.x -= delta.width;
- [downloadLocationButton setFrameOrigin:origin];
- NSSize controlSize = [downloadLocationControl frame].size;
- controlSize.width -= delta.width;
- [downloadLocationControl setFrameSize:controlSize];
- }
- }
-
- return verticalShift;
-}
-
-} // namespace
-
-//-------------------------------------------------------------------------
-
-@interface PreferencesWindowController(Private)
-// Callback when preferences are changed. |prefName| is the name of the
-// pref that has changed.
-- (void)prefChanged:(std::string*)prefName;
-// Callback when sync state has changed. syncService_ needs to be
-// queried to find out what happened.
-- (void)syncStateChanged;
-// Record the user performed a certain action and save the preferences.
-- (void)recordUserAction:(const UserMetricsAction&) action;
-- (void)registerPrefObservers;
-- (void)configureInstant;
-
-// KVC setter methods.
-- (void)setNewTabPageIsHomePageIndex:(NSInteger)val;
-- (void)setHomepageURL:(NSString*)urlString;
-- (void)setRestoreOnStartupIndex:(NSInteger)type;
-- (void)setShowHomeButton:(BOOL)value;
-- (void)setPasswordManagerEnabledIndex:(NSInteger)value;
-- (void)setIsUsingDefaultTheme:(BOOL)value;
-- (void)setShowAlternateErrorPages:(BOOL)value;
-- (void)setUseSuggest:(BOOL)value;
-- (void)setDnsPrefetch:(BOOL)value;
-- (void)setSafeBrowsing:(BOOL)value;
-- (void)setMetricsReporting:(BOOL)value;
-- (void)setAskForSaveLocation:(BOOL)value;
-- (void)setFileHandlerUIEnabled:(BOOL)value;
-- (void)setTranslateEnabled:(BOOL)value;
-- (void)setTabsToLinks:(BOOL)value;
-- (void)displayPreferenceViewForPage:(OptionsPage)page
- animate:(BOOL)animate;
-- (void)resetSubViews;
-- (void)initBannerStateForPage:(OptionsPage)page;
-
-// KVC getter methods.
-- (BOOL)fileHandlerUIEnabled;
-@end
-
-namespace PreferencesWindowControllerInternal {
-
-// A C++ class registered for changes in preferences. Bridges the
-// notification back to the PWC.
-class PrefObserverBridge : public NotificationObserver,
- public ProfileSyncServiceObserver {
- public:
- PrefObserverBridge(PreferencesWindowController* controller)
- : controller_(controller) {}
-
- virtual ~PrefObserverBridge() {}
-
- // Overridden from NotificationObserver:
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- if (type == NotificationType::PREF_CHANGED)
- [controller_ prefChanged:Details<std::string>(details).ptr()];
- }
-
- // Overridden from ProfileSyncServiceObserver.
- virtual void OnStateChanged() {
- [controller_ syncStateChanged];
- }
-
- private:
- PreferencesWindowController* controller_; // weak, owns us
-};
-
-// Tracks state for a managed prefs banner and triggers UI updates through the
-// PreferencesWindowController as appropriate.
-class ManagedPrefsBannerState : public policy::ManagedPrefsBannerBase {
- public:
- virtual ~ManagedPrefsBannerState() { }
-
- explicit ManagedPrefsBannerState(PreferencesWindowController* controller,
- OptionsPage page,
- PrefService* local_state,
- PrefService* prefs)
- : policy::ManagedPrefsBannerBase(local_state, prefs, page),
- controller_(controller),
- page_(page) { }
-
- BOOL IsVisible() {
- return DetermineVisibility();
- }
-
- protected:
- // Overridden from ManagedPrefsBannerBase.
- virtual void OnUpdateVisibility() {
- [controller_ switchToPage:page_ animate:YES];
- }
-
- private:
- PreferencesWindowController* controller_; // weak, owns us
- OptionsPage page_; // current options page
-};
-
-} // namespace PreferencesWindowControllerInternal
-
-@implementation PreferencesWindowController
-
-@synthesize restoreButtonsEnabled = restoreButtonsEnabled_;
-@synthesize restoreURLsEnabled = restoreURLsEnabled_;
-@synthesize showHomeButtonEnabled = showHomeButtonEnabled_;
-@synthesize defaultSearchEngineEnabled = defaultSearchEngineEnabled_;
-@synthesize passwordManagerChoiceEnabled = passwordManagerChoiceEnabled_;
-@synthesize passwordManagerButtonEnabled = passwordManagerButtonEnabled_;
-@synthesize autoFillSettingsButtonEnabled = autoFillSettingsButtonEnabled_;
-@synthesize showAlternateErrorPagesEnabled = showAlternateErrorPagesEnabled_;
-@synthesize useSuggestEnabled = useSuggestEnabled_;
-@synthesize dnsPrefetchEnabled = dnsPrefetchEnabled_;
-@synthesize safeBrowsingEnabled = safeBrowsingEnabled_;
-@synthesize metricsReportingEnabled = metricsReportingEnabled_;
-@synthesize proxiesConfigureButtonEnabled = proxiesConfigureButtonEnabled_;
-
-- (id)initWithProfile:(Profile*)profile initialPage:(OptionsPage)initialPage {
- DCHECK(profile);
- // Use initWithWindowNibPath:: instead of initWithWindowNibName: so we
- // can override it in a unit test.
- NSString* nibPath = [mac_util::MainAppBundle()
- pathForResource:@"Preferences"
- ofType:@"nib"];
- if ((self = [super initWithWindowNibPath:nibPath owner:self])) {
- profile_ = profile->GetOriginalProfile();
- initialPage_ = initialPage;
- prefs_ = profile->GetPrefs();
- DCHECK(prefs_);
- observer_.reset(
- new PreferencesWindowControllerInternal::PrefObserverBridge(self));
-
- // Set up the model for the custom home page table. The KVO observation
- // tells us when the number of items in the array changes. The normal
- // observation tells us when one of the URLs of an item changes.
- customPagesSource_.reset([[CustomHomePagesModel alloc]
- initWithProfile:profile_]);
- const SessionStartupPref startupPref =
- SessionStartupPref::GetStartupPref(prefs_);
- [customPagesSource_ setURLs:startupPref.urls];
-
- // Set up the model for the default search popup. Register for notifications
- // about when the model changes so we can update the selection in the view.
- searchEngineModel_.reset(
- [[SearchEngineListModel alloc]
- initWithModel:profile->GetTemplateURLModel()]);
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(searchEngineModelChanged:)
- name:kSearchEngineListModelChangedNotification
- object:searchEngineModel_.get()];
-
- // This needs to be done before awakeFromNib: because the bindings set up
- // in the nib rely on it.
- [self registerPrefObservers];
-
- // Use one animation so we can stop it if the user clicks quickly, and
- // start the new animation.
- animation_.reset([[NSViewAnimation alloc] init]);
- // Make this the delegate so it can remove the old view at the end of the
- // animation (once it is faded out).
- [animation_ setDelegate:self];
- [animation_ setAnimationBlockingMode:NSAnimationNonblocking];
-
- // TODO(akalin): handle incognito profiles? The windows version of this
- // (in chrome/browser/views/options/content_page_view.cc) just does what
- // we do below.
- syncService_ = profile_->GetProfileSyncService();
-
- // TODO(akalin): This color is taken from kSyncLabelErrorBgColor in
- // content_page_view.cc. Either decomp that color out into a
- // function/variable that is referenced by both this file and
- // content_page_view.cc, or maybe pick a more suitable color.
- syncErrorBackgroundColor_.reset(
- [[NSColor colorWithDeviceRed:0xff/255.0
- green:0x9a/255.0
- blue:0x9a/255.0
- alpha:1.0] retain]);
-
- // Disable the |autoFillSettingsButton_| if we have no
- // |personalDataManager|.
- PersonalDataManager* personalDataManager =
- profile_->GetPersonalDataManager();
- [autoFillSettingsButton_ setHidden:(personalDataManager == NULL)];
- bool autofill_disabled_by_policy =
- autoFillEnabled_.IsManaged() && !autoFillEnabled_.GetValue();
- [self setAutoFillSettingsButtonEnabled:!autofill_disabled_by_policy];
- [self setPasswordManagerChoiceEnabled:!askSavePasswords_.IsManaged()];
- [self setPasswordManagerButtonEnabled:
- !askSavePasswords_.IsManaged() || askSavePasswords_.GetValue()];
-
- // Initialize the enabled state of the elements on the general tab.
- [self setShowHomeButtonEnabled:!showHomeButton_.IsManaged()];
- [self setEnabledStateOfRestoreOnStartup];
- [self setDefaultSearchEngineEnabled:![searchEngineModel_ isDefaultManaged]];
-
- // Initialize UI state for the advanced page.
- [self setShowAlternateErrorPagesEnabled:!alternateErrorPages_.IsManaged()];
- [self setUseSuggestEnabled:!useSuggest_.IsManaged()];
- [self setDnsPrefetchEnabled:!dnsPrefetch_.IsManaged()];
- [self setSafeBrowsingEnabled:!safeBrowsing_.IsManaged()];
- [self setMetricsReportingEnabled:!metricsReporting_.IsManaged()];
- proxyPrefs_.reset(
- PrefSetObserver::CreateProxyPrefSetObserver(prefs_, observer_.get()));
- [self setProxiesConfigureButtonEnabled:!proxyPrefs_->IsManaged()];
- }
- return self;
-}
-
-- (void)awakeFromNib {
-
- // Validate some assumptions in debug builds.
-
- // "Basics", "Personal Stuff", and "Under the Hood" views should be the same
- // width. They should be the same width so they are laid out to look as good
- // as possible at that width with controls just having to wrap if their text
- // is too long.
- DCHECK_EQ(NSWidth([basicsView_ frame]), NSWidth([personalStuffView_ frame]))
- << "Basics and Personal Stuff should be the same widths";
- DCHECK_EQ(NSWidth([basicsView_ frame]), NSWidth([underTheHoodView_ frame]))
- << "Basics and Under the Hood should be the same widths";
- // "Under the Hood" content should always be skinnier than the scroller it
- // goes into (we resize it).
- DCHECK_LE(NSWidth([underTheHoodContentView_ frame]),
- [underTheHoodScroller_ contentSize].width)
- << "The Under the Hood content should be narrower than the content "
- "of the scroller it goes into";
-
-#if !defined(GOOGLE_CHROME_BUILD)
- // "Enable logging" (breakpad and stats) is only in Google Chrome builds,
- // remove the checkbox and slide everything above it down.
- RemoveViewFromView(underTheHoodContentView_, enableLoggingCheckbox_);
-#endif // !defined(GOOGLE_CHROME_BUILD)
-
- // There are four problem children within the groups:
- // Basics - Default Browser
- // Personal Stuff - Sync
- // Personal Stuff - Themes
- // Personal Stuff - Browser Data
- // These four have buttons that with some localizations are wider then the
- // view. So the four get manually laid out before doing the general work so
- // the views/window can be made wide enough to fit them. The layout in the
- // general pass is a noop for these buttons (since they are already sized).
-
- // Size the default browser button.
- const NSUInteger kDefaultBrowserGroupCount = 3;
- const NSUInteger kDefaultBrowserButtonIndex = 1;
- DCHECK_EQ([basicsGroupDefaultBrowser_ count], kDefaultBrowserGroupCount)
- << "Expected only two items in Default Browser group";
- NSButton* defaultBrowserButton =
- [basicsGroupDefaultBrowser_ objectAtIndex:kDefaultBrowserButtonIndex];
- NSSize defaultBrowserChange =
- [GTMUILocalizerAndLayoutTweaker sizeToFitView:defaultBrowserButton];
- DCHECK_EQ(defaultBrowserChange.height, 0.0)
- << "Button should have been right height in nib";
-
- [self configureInstant];
-
- // Size the sync row.
- CGFloat syncRowChange = SizeToFitButtonPair(syncButton_,
- syncCustomizeButton_);
-
- // Size the themes row.
- const NSUInteger kThemeGroupCount = 3;
- const NSUInteger kThemeResetButtonIndex = 1;
- const NSUInteger kThemeThemesButtonIndex = 2;
- DCHECK_EQ([personalStuffGroupThemes_ count], kThemeGroupCount)
- << "Expected only two items in Themes group";
- CGFloat themeRowChange = SizeToFitButtonPair(
- [personalStuffGroupThemes_ objectAtIndex:kThemeResetButtonIndex],
- [personalStuffGroupThemes_ objectAtIndex:kThemeThemesButtonIndex]);
-
- // Size the Privacy and Clear buttons that make a row in Under the Hood.
- CGFloat privacyRowChange = SizeToFitButtonPair(contentSettingsButton_,
- clearDataButton_);
- // Under the Hood view is narrower (then the other panes) in the nib, subtract
- // out the amount it was already going to grow to match the other panes when
- // calculating how much the row needs things to grow.
- privacyRowChange -=
- ([underTheHoodScroller_ contentSize].width -
- NSWidth([underTheHoodContentView_ frame]));
-
- // Find the most any row changed in size.
- CGFloat maxWidthChange = std::max(defaultBrowserChange.width, syncRowChange);
- maxWidthChange = std::max(maxWidthChange, themeRowChange);
- maxWidthChange = std::max(maxWidthChange, privacyRowChange);
-
- // If any grew wider, make the views wider. If they all shrank, they fit the
- // existing view widths, so no change is needed//.
- if (maxWidthChange > 0.0) {
- NSSize viewSize = [basicsView_ frame].size;
- viewSize.width += maxWidthChange;
- [basicsView_ setFrameSize:viewSize];
- viewSize = [personalStuffView_ frame].size;
- viewSize.width += maxWidthChange;
- [personalStuffView_ setFrameSize:viewSize];
- }
-
- // Now that we have the width needed for Basics and Personal Stuff, lay out
- // those pages bottom up making sure the strings fit and moving things up as
- // needed.
-
- CGFloat newWidth = NSWidth([basicsView_ frame]);
- CGFloat verticalShift = 0.0;
- verticalShift += AutoSizeGroup(basicsGroupDefaultBrowser_,
- kAutoSizeGroupBehaviorVerticalFirstToFit,
- verticalShift);
- // TODO(rsesek/rohitrao): This is ugly, when the instant experiement is no
- // longer displayed, please remove this code, the NSTextField and IBOutlet
- // needed.
- DCHECK(instantExperiment_ != nil);
- if (verticalShift) {
- // If the default browser moved things up, move the experiment field up
- // also, it is not in the SearchEngine group due to its position on screen.
- NSPoint origin = [instantExperiment_ frame].origin;
- origin.y += verticalShift;
- [instantExperiment_ setFrameOrigin:origin];
- }
- // End TODO
- verticalShift += AutoSizeGroup(basicsGroupSearchEngine_,
- kAutoSizeGroupBehaviorFirstTwoAsRowVerticalToFit,
- verticalShift);
- verticalShift += AutoSizeGroup(basicsGroupToolbar_,
- kAutoSizeGroupBehaviorVerticalToFit,
- verticalShift);
- verticalShift += AutoSizeGroup(basicsGroupHomePage_,
- kAutoSizeGroupBehaviorVerticalToFit,
- verticalShift);
- verticalShift += AutoSizeGroup(basicsGroupStartup_,
- kAutoSizeGroupBehaviorVerticalFirstToFit,
- verticalShift);
- [GTMUILocalizerAndLayoutTweaker
- resizeViewWithoutAutoResizingSubViews:basicsView_
- delta:NSMakeSize(0.0, verticalShift)];
-
- verticalShift = 0.0;
- verticalShift += AutoSizeGroup(personalStuffGroupThemes_,
- kAutoSizeGroupBehaviorHorizontalToFit,
- verticalShift);
- verticalShift += AutoSizeGroup(personalStuffGroupBrowserData_,
- kAutoSizeGroupBehaviorVerticalToFit,
- verticalShift);
- verticalShift += AutoSizeGroup(personalStuffGroupAutofill_,
- kAutoSizeGroupBehaviorVerticalToFit,
- verticalShift);
- verticalShift += AutoSizeGroup(personalStuffGroupPasswords_,
- kAutoSizeGroupBehaviorVerticalToFit,
- verticalShift);
- // TODO(akalin): Here we rely on the initial contents of the sync
- // group's text field/link field to be large enough to hold all
- // possible messages so that we don't have to re-layout when sync
- // state changes. This isn't perfect, since e.g. some sync messages
- // use the user's e-mail address (which may be really long), and the
- // link field is usually not shown (leaving a big empty space).
- // Rethink sync preferences UI for Mac.
- verticalShift += AutoSizeGroup(personalStuffGroupSync_,
- kAutoSizeGroupBehaviorVerticalToFit,
- verticalShift);
- [GTMUILocalizerAndLayoutTweaker
- resizeViewWithoutAutoResizingSubViews:personalStuffView_
- delta:NSMakeSize(0.0, verticalShift)];
-
- if (syncService_) {
- syncService_->AddObserver(observer_.get());
- // Update the controls according to the initial state.
- [self syncStateChanged];
- } else {
- // If sync is disabled we don't want to show the sync controls at all.
- RemoveGroupFromView(personalStuffView_, personalStuffGroupSync_);
- }
-
- // Make the window as wide as the views.
- NSWindow* prefsWindow = [self window];
- NSView* prefsContentView = [prefsWindow contentView];
- NSRect frame = [prefsContentView convertRect:[prefsWindow frame]
- fromView:nil];
- frame.size.width = newWidth;
- frame = [prefsContentView convertRect:frame toView:nil];
- [prefsWindow setFrame:frame display:NO];
-
- // The Under the Hood prefs is a scroller, it shouldn't get any border, so it
- // gets resized to be as wide as the window ended up.
- NSSize underTheHoodSize = [underTheHoodView_ frame].size;
- underTheHoodSize.width = newWidth;
- [underTheHoodView_ setFrameSize:underTheHoodSize];
-
- // Widen the Under the Hood content so things can rewrap to the full width.
- NSSize underTheHoodContentSize = [underTheHoodContentView_ frame].size;
- underTheHoodContentSize.width = [underTheHoodScroller_ contentSize].width;
- [underTheHoodContentView_ setFrameSize:underTheHoodContentSize];
-
- // Now that Under the Hood is the right width, auto-size to the new width to
- // get the final height.
- verticalShift = AutoSizeUnderTheHoodContent(underTheHoodContentView_,
- downloadLocationControl_,
- downloadLocationButton_);
- [GTMUILocalizerAndLayoutTweaker
- resizeViewWithoutAutoResizingSubViews:underTheHoodContentView_
- delta:NSMakeSize(0.0, verticalShift)];
- underTheHoodContentSize = [underTheHoodContentView_ frame].size;
-
- // Put the Under the Hood content view into the scroller and scroll it to the
- // top.
- [underTheHoodScroller_ setDocumentView:underTheHoodContentView_];
- [underTheHoodContentView_ scrollPoint:
- NSMakePoint(0, underTheHoodContentSize.height)];
-
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- NSImage* alertIcon = rb.GetNativeImageNamed(IDR_WARNING);
- DCHECK(alertIcon);
- [managedPrefsBannerWarningImage_ setImage:alertIcon];
-
- [self initBannerStateForPage:initialPage_];
- [self switchToPage:initialPage_ animate:NO];
-
- // Save/restore position based on prefs.
- if (g_browser_process && g_browser_process->local_state()) {
- sizeSaver_.reset([[WindowSizeAutosaver alloc]
- initWithWindow:[self window]
- prefService:g_browser_process->local_state()
- path:prefs::kPreferencesWindowPlacement]);
- }
-
- // Initialize the banner gradient and stroke color.
- NSColor* bannerStartingColor =
- [NSColor colorWithCalibratedRed:kBannerGradientColorTop[0]
- green:kBannerGradientColorTop[1]
- blue:kBannerGradientColorTop[2]
- alpha:1.0];
- NSColor* bannerEndingColor =
- [NSColor colorWithCalibratedRed:kBannerGradientColorBottom[0]
- green:kBannerGradientColorBottom[1]
- blue:kBannerGradientColorBottom[2]
- alpha:1.0];
- scoped_nsobject<NSGradient> bannerGradient(
- [[NSGradient alloc] initWithStartingColor:bannerStartingColor
- endingColor:bannerEndingColor]);
- [managedPrefsBannerView_ setGradient:bannerGradient];
-
- NSColor* bannerStrokeColor =
- [NSColor colorWithCalibratedWhite:kBannerStrokeColor
- alpha:1.0];
- [managedPrefsBannerView_ setStrokeColor:bannerStrokeColor];
-
- // Set accessibility related attributes.
- NSTableView* tableView = [basicsView_ viewWithTag:kBasicsStartupPageTableTag];
- NSString* description =
- l10n_util::GetNSStringWithFixup(IDS_OPTIONS_STARTUP_SHOW_PAGES);
- [tableView accessibilitySetOverrideValue:description
- forAttribute:NSAccessibilityDescriptionAttribute];
-}
-
-- (void)dealloc {
- if (syncService_) {
- syncService_->RemoveObserver(observer_.get());
- }
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [animation_ setDelegate:nil];
- [animation_ stopAnimation];
- [super dealloc];
-}
-
-// Xcode 3.1.x version of Interface Builder doesn't do a lot for editing
-// toolbars in XIB. So the toolbar's delegate is set to the controller so it
-// can tell the toolbar what items are selectable.
-- (NSArray*)toolbarSelectableItemIdentifiers:(NSToolbar*)toolbar {
- DCHECK(toolbar == toolbar_);
- return [[toolbar_ items] valueForKey:@"itemIdentifier"];
-}
-
-// Register our interest in the preferences we're displaying so if anything
-// else in the UI changes them we will be updated.
-- (void)registerPrefObservers {
- if (!prefs_) return;
-
- // Basics panel
- registrar_.Init(prefs_);
- registrar_.Add(prefs::kURLsToRestoreOnStartup, observer_.get());
- restoreOnStartup_.Init(prefs::kRestoreOnStartup, prefs_, observer_.get());
- newTabPageIsHomePage_.Init(prefs::kHomePageIsNewTabPage,
- prefs_, observer_.get());
- homepage_.Init(prefs::kHomePage, prefs_, observer_.get());
- showHomeButton_.Init(prefs::kShowHomeButton, prefs_, observer_.get());
- instantEnabled_.Init(prefs::kInstantEnabled, prefs_, observer_.get());
-
- // Personal Stuff panel
- askSavePasswords_.Init(prefs::kPasswordManagerEnabled,
- prefs_, observer_.get());
- autoFillEnabled_.Init(prefs::kAutoFillEnabled, prefs_, observer_.get());
- currentTheme_.Init(prefs::kCurrentThemeID, prefs_, observer_.get());
-
- // Under the hood panel
- alternateErrorPages_.Init(prefs::kAlternateErrorPagesEnabled,
- prefs_, observer_.get());
- useSuggest_.Init(prefs::kSearchSuggestEnabled, prefs_, observer_.get());
- dnsPrefetch_.Init(prefs::kDnsPrefetchingEnabled, prefs_, observer_.get());
- safeBrowsing_.Init(prefs::kSafeBrowsingEnabled, prefs_, observer_.get());
- autoOpenFiles_.Init(
- prefs::kDownloadExtensionsToOpen, prefs_, observer_.get());
- translateEnabled_.Init(prefs::kEnableTranslate, prefs_, observer_.get());
- tabsToLinks_.Init(prefs::kWebkitTabsToLinks, prefs_, observer_.get());
-
- // During unit tests, there is no local state object, so we fall back to
- // the prefs object (where we've explicitly registered this pref so we
- // know it's there).
- PrefService* local = g_browser_process->local_state();
- if (!local)
- local = prefs_;
- metricsReporting_.Init(prefs::kMetricsReportingEnabled,
- local, observer_.get());
- defaultDownloadLocation_.Init(prefs::kDownloadDefaultDirectory, prefs_,
- observer_.get());
- askForSaveLocation_.Init(prefs::kPromptForDownload, prefs_, observer_.get());
-
- // We don't need to observe changes in this value.
- lastSelectedPage_.Init(prefs::kOptionsWindowLastTabIndex, local, NULL);
-}
-
-// Called when the window wants to be closed.
-- (BOOL)windowShouldClose:(id)sender {
- // Stop any animation and clear the delegate to avoid stale pointers.
- [animation_ setDelegate:nil];
- [animation_ stopAnimation];
-
- return YES;
-}
-
-// Called when the user hits the escape key. Closes the window.
-- (void)cancel:(id)sender {
- [[self window] performClose:self];
-}
-
-// Record the user performed a certain action and save the preferences.
-- (void)recordUserAction:(const UserMetricsAction &)action {
- UserMetrics::RecordAction(action, profile_);
- if (prefs_)
- prefs_->ScheduleSavePersistentPrefs();
-}
-
-// Returns the set of keys that |key| depends on for its value so it can be
-// re-computed when any of those change as well.
-+ (NSSet*)keyPathsForValuesAffectingValueForKey:(NSString*)key {
- NSSet* paths = [super keyPathsForValuesAffectingValueForKey:key];
- if ([key isEqualToString:@"isHomepageURLEnabled"]) {
- paths = [paths setByAddingObject:@"newTabPageIsHomePageIndex"];
- paths = [paths setByAddingObject:@"homepageURL"];
- } else if ([key isEqualToString:@"restoreURLsEnabled"]) {
- paths = [paths setByAddingObject:@"restoreOnStartupIndex"];
- } else if ([key isEqualToString:@"isHomepageChoiceEnabled"]) {
- paths = [paths setByAddingObject:@"newTabPageIsHomePageIndex"];
- paths = [paths setByAddingObject:@"homepageURL"];
- } else if ([key isEqualToString:@"newTabPageIsHomePageIndex"]) {
- paths = [paths setByAddingObject:@"homepageURL"];
- } else if ([key isEqualToString:@"hompageURL"]) {
- paths = [paths setByAddingObject:@"newTabPageIsHomePageIndex"];
- } else if ([key isEqualToString:@"isDefaultBrowser"]) {
- paths = [paths setByAddingObject:@"defaultBrowser"];
- } else if ([key isEqualToString:@"defaultBrowserTextColor"]) {
- paths = [paths setByAddingObject:@"defaultBrowser"];
- } else if ([key isEqualToString:@"defaultBrowserText"]) {
- paths = [paths setByAddingObject:@"defaultBrowser"];
- }
- return paths;
-}
-
-// Launch the Keychain Access app.
-- (void)launchKeychainAccess {
- NSString* const kKeychainBundleId = @"com.apple.keychainaccess";
- [[NSWorkspace sharedWorkspace]
- launchAppWithBundleIdentifier:kKeychainBundleId
- options:0L
- additionalEventParamDescriptor:nil
- launchIdentifier:nil];
-}
-
-//-------------------------------------------------------------------------
-// Basics panel
-
-// Sets the home page preferences for kNewTabPageIsHomePage and kHomePage. If a
-// blank or null-host URL is passed in we revert to using NewTab page
-// as the Home page. Note: using SetValue() causes the observers not to fire,
-// which is actually a good thing as we could end up in a state where setting
-// the homepage to an empty url would automatically reset the prefs back to
-// using the NTP, so we'd be never be able to change it.
-- (void)setHomepage:(const GURL&)homepage {
- if (IsNewTabUIURLString(homepage)) {
- newTabPageIsHomePage_.SetValueIfNotManaged(true);
- homepage_.SetValueIfNotManaged(std::string());
- } else if (!homepage.is_valid()) {
- newTabPageIsHomePage_.SetValueIfNotManaged(true);
- if (!homepage.has_host())
- homepage_.SetValueIfNotManaged(std::string());
- } else {
- homepage_.SetValueIfNotManaged(homepage.spec());
- }
-}
-
-// Callback when preferences are changed by someone modifying the prefs backend
-// externally. |prefName| is the name of the pref that has changed. Unlike on
-// Windows, we don't need to use this method for initializing, that's handled by
-// Cocoa Bindings.
-// Handles prefs for the "Basics" panel.
-- (void)basicsPrefChanged:(std::string*)prefName {
- if (*prefName == prefs::kRestoreOnStartup) {
- const SessionStartupPref startupPref =
- SessionStartupPref::GetStartupPref(prefs_);
- [self setRestoreOnStartupIndex:startupPref.type];
- [self setEnabledStateOfRestoreOnStartup];
- } else if (*prefName == prefs::kURLsToRestoreOnStartup) {
- [customPagesSource_ reloadURLs];
- [self setEnabledStateOfRestoreOnStartup];
- } else if (*prefName == prefs::kHomePageIsNewTabPage) {
- NSInteger useNewTabPage = newTabPageIsHomePage_.GetValue() ? 0 : 1;
- [self setNewTabPageIsHomePageIndex:useNewTabPage];
- } else if (*prefName == prefs::kHomePage) {
- NSString* value = base::SysUTF8ToNSString(homepage_.GetValue());
- [self setHomepageURL:value];
- } else if (*prefName == prefs::kShowHomeButton) {
- [self setShowHomeButton:showHomeButton_.GetValue() ? YES : NO];
- [self setShowHomeButtonEnabled:!showHomeButton_.IsManaged()];
- } else if (*prefName == prefs::kInstantEnabled) {
- [self configureInstant];
- }
-}
-
-// Returns the index of the selected cell in the "on startup" matrix based
-// on the "restore on startup" pref. The ordering of the cells is in the
-// same order as the pref.
-- (NSInteger)restoreOnStartupIndex {
- const SessionStartupPref pref = SessionStartupPref::GetStartupPref(prefs_);
- return pref.type;
-}
-
-// A helper function that takes the startup session type, grabs the URLs to
-// restore, and saves it all in prefs.
-- (void)saveSessionStartupWithType:(SessionStartupPref::Type)type {
- SessionStartupPref pref;
- pref.type = type;
- pref.urls = [customPagesSource_.get() URLs];
- SessionStartupPref::SetStartupPref(prefs_, pref);
-}
-
-// Sets the pref based on the index of the selected cell in the matrix and
-// marks the appropriate user metric.
-- (void)setRestoreOnStartupIndex:(NSInteger)type {
- SessionStartupPref::Type startupType =
- static_cast<SessionStartupPref::Type>(type);
- switch (startupType) {
- case SessionStartupPref::DEFAULT:
- [self recordUserAction:UserMetricsAction("Options_Startup_Homepage")];
- break;
- case SessionStartupPref::LAST:
- [self recordUserAction:UserMetricsAction("Options_Startup_LastSession")];
- break;
- case SessionStartupPref::URLS:
- [self recordUserAction:UserMetricsAction("Options_Startup_Custom")];
- break;
- default:
- NOTREACHED();
- }
- [self saveSessionStartupWithType:startupType];
-}
-
-// Enables or disables the restoreOnStartup elements
-- (void) setEnabledStateOfRestoreOnStartup {
- const SessionStartupPref startupPref =
- SessionStartupPref::GetStartupPref(prefs_);
- [self setRestoreButtonsEnabled:!SessionStartupPref::TypeIsManaged(prefs_)];
- [self setRestoreURLsEnabled:!SessionStartupPref::URLsAreManaged(prefs_) &&
- [self restoreOnStartupIndex] == SessionStartupPref::URLS];
-}
-
-// Getter for the |customPagesSource| property for bindings.
-- (CustomHomePagesModel*)customPagesSource {
- return customPagesSource_.get();
-}
-
-// Called when the selection in the table changes. If a flag is set indicating
-// that we're waiting for a special select message, edit the cell. Otherwise
-// just ignore it, we don't normally care.
-- (void)tableViewSelectionDidChange:(NSNotification*)aNotification {
- if (pendingSelectForEdit_) {
- NSTableView* table = [aNotification object];
- NSUInteger selectedRow = [table selectedRow];
- [table editColumn:0 row:selectedRow withEvent:nil select:YES];
- pendingSelectForEdit_ = NO;
- }
-}
-
-// Called when the user hits the (+) button for adding a new homepage to the
-// list. This will also attempt to make the new item editable so the user can
-// just start typing.
-- (IBAction)addHomepage:(id)sender {
- [customPagesArrayController_ add:sender];
-
- // When the new item is added to the model, the array controller will select
- // it. We'll watch for that notification (because we are the table view's
- // delegate) and then make the cell editable. Note that this can't be
- // accomplished simply by subclassing the array controller's add method (I
- // did try). The update of the table is asynchronous with the controller
- // updating the model.
- pendingSelectForEdit_ = YES;
-}
-
-// Called when the user hits the (-) button for removing the selected items in
-// the homepage table. The controller does all the work.
-- (IBAction)removeSelectedHomepages:(id)sender {
- [customPagesArrayController_ remove:sender];
-}
-
-// Add all entries for all open browsers with our profile.
-- (IBAction)useCurrentPagesAsHomepage:(id)sender {
- std::vector<GURL> urls;
- for (BrowserList::const_iterator browserIter = BrowserList::begin();
- browserIter != BrowserList::end(); ++browserIter) {
- Browser* browser = *browserIter;
- if (browser->profile() != profile_)
- continue; // Only want entries for open profile.
-
- for (int tabIndex = 0; tabIndex < browser->tab_count(); ++tabIndex) {
- TabContents* tab = browser->GetTabContentsAt(tabIndex);
- if (tab->ShouldDisplayURL()) {
- const GURL url = browser->GetTabContentsAt(tabIndex)->GetURL();
- if (!url.is_empty())
- urls.push_back(url);
- }
- }
- }
- [customPagesSource_ setURLs:urls];
-}
-
-enum { kHomepageNewTabPage, kHomepageURL };
-
-// Here's a table describing the desired characteristics of the homepage choice
-// radio value, it's enabled state and the URL field enabled state. They depend
-// on the values of the managed bits for homepage (m_hp) and
-// homepageIsNewTabPage (m_ntp) preferences, as well as the value of the
-// homepageIsNewTabPage preference (ntp) and whether the homepage preference
-// is equal to the new tab page URL (hpisntp).
-//
-// m_hp m_ntp ntp hpisntp | choice value | choice enabled | URL field enabled
-// --------------------------------------------------------------------------
-// 0 0 0 0 | homepage | 1 | 1
-// 0 0 0 1 | new tab page | 1 | 0
-// 0 0 1 0 | new tab page | 1 | 0
-// 0 0 1 1 | new tab page | 1 | 0
-// 0 1 0 0 | homepage | 0 | 1
-// 0 1 0 1 | homepage | 0 | 1
-// 0 1 1 0 | new tab page | 0 | 0
-// 0 1 1 1 | new tab page | 0 | 0
-// 1 0 0 0 | homepage | 1 | 0
-// 1 0 0 1 | new tab page | 0 | 0
-// 1 0 1 0 | new tab page | 1 | 0
-// 1 0 1 1 | new tab page | 0 | 0
-// 1 1 0 0 | homepage | 0 | 0
-// 1 1 0 1 | new tab page | 0 | 0
-// 1 1 1 0 | new tab page | 0 | 0
-// 1 1 1 1 | new tab page | 0 | 0
-//
-// thus, we have:
-//
-// choice value is new tab page === ntp || (hpisntp && (m_hp || !m_ntp))
-// choice enabled === !m_ntp && !(m_hp && hpisntp)
-// URL field enabled === !ntp && !mhp && !(hpisntp && !m_ntp)
-//
-// which also make sense if you think about them.
-
-// Checks whether the homepage URL refers to the new tab page.
-- (BOOL)isHomepageNewTabUIURL {
- return IsNewTabUIURLString(GURL(homepage_.GetValue().c_str()));
-}
-
-// Returns the index of the selected cell in the "home page" marix based on
-// the "new tab is home page" pref. Sadly, the ordering is reversed from the
-// pref value.
-- (NSInteger)newTabPageIsHomePageIndex {
- return newTabPageIsHomePage_.GetValue() ||
- ([self isHomepageNewTabUIURL] &&
- (homepage_.IsManaged() || !newTabPageIsHomePage_.IsManaged())) ?
- kHomepageNewTabPage : kHomepageURL;
-}
-
-// Sets the pref based on the given index into the matrix and marks the
-// appropriate user metric.
-- (void)setNewTabPageIsHomePageIndex:(NSInteger)index {
- bool useNewTabPage = index == kHomepageNewTabPage ? true : false;
- if (useNewTabPage) {
- [self recordUserAction:UserMetricsAction("Options_Homepage_UseNewTab")];
- } else {
- [self recordUserAction:UserMetricsAction("Options_Homepage_UseURL")];
- if ([self isHomepageNewTabUIURL])
- homepage_.SetValueIfNotManaged(std::string());
- }
- newTabPageIsHomePage_.SetValueIfNotManaged(useNewTabPage);
-}
-
-// Check whether the new tab and URL homepage radios should be enabled, i.e. if
-// the corresponding preference is not managed through configuration policy.
-- (BOOL)isHomepageChoiceEnabled {
- return !newTabPageIsHomePage_.IsManaged() &&
- !(homepage_.IsManaged() && [self isHomepageNewTabUIURL]);
-}
-
-// Returns whether or not the homepage URL text field should be enabled
-// based on if the new tab page is the home page.
-- (BOOL)isHomepageURLEnabled {
- return !newTabPageIsHomePage_.GetValue() && !homepage_.IsManaged() &&
- !([self isHomepageNewTabUIURL] && !newTabPageIsHomePage_.IsManaged());
-}
-
-// Returns the homepage URL.
-- (NSString*)homepageURL {
- NSString* value = base::SysUTF8ToNSString(homepage_.GetValue());
- return [self isHomepageNewTabUIURL] ? nil : value;
-}
-
-// Sets the homepage URL to |urlString| with some fixing up.
-- (void)setHomepageURL:(NSString*)urlString {
- // If the text field contains a valid URL, sync it to prefs. We run it
- // through the fixer upper to allow input like "google.com" to be converted
- // to something valid ("http://google.com").
- std::string unfixedURL = urlString ? base::SysNSStringToUTF8(urlString) :
- chrome::kChromeUINewTabURL;
- [self setHomepage:URLFixerUpper::FixupURL(unfixedURL, std::string())];
-}
-
-// Returns whether the home button should be checked based on the preference.
-- (BOOL)showHomeButton {
- return showHomeButton_.GetValue() ? YES : NO;
-}
-
-// Sets the backend pref for whether or not the home button should be displayed
-// based on |value|.
-- (void)setShowHomeButton:(BOOL)value {
- if (value)
- [self recordUserAction:UserMetricsAction(
- "Options_Homepage_ShowHomeButton")];
- else
- [self recordUserAction:UserMetricsAction(
- "Options_Homepage_HideHomeButton")];
- showHomeButton_.SetValueIfNotManaged(value ? true : false);
-}
-
-// Getter for the |searchEngineModel| property for bindings.
-- (id)searchEngineModel {
- return searchEngineModel_.get();
-}
-
-// Bindings for the search engine popup. We not binding directly to the model
-// in order to siphon off the setter so we can record the metric. If we're
-// doing it with one, might as well do it with both.
-- (NSUInteger)searchEngineSelectedIndex {
- return [searchEngineModel_ defaultIndex];
-}
-
-- (void)setSearchEngineSelectedIndex:(NSUInteger)index {
- [self recordUserAction:UserMetricsAction("Options_SearchEngineChanged")];
- [searchEngineModel_ setDefaultIndex:index];
-}
-
-// Called when the search engine model changes. Update the selection in the
-// popup by tickling the bindings with the new value.
-- (void)searchEngineModelChanged:(NSNotification*)notify {
- [self setSearchEngineSelectedIndex:[self searchEngineSelectedIndex]];
- [self setDefaultSearchEngineEnabled:![searchEngineModel_ isDefaultManaged]];
-
-}
-
-- (IBAction)manageSearchEngines:(id)sender {
- [KeywordEditorCocoaController showKeywordEditor:profile_];
-}
-
-- (IBAction)toggleInstant:(id)sender {
- if (instantEnabled_.GetValue()) {
- InstantController::Disable(profile_);
- } else {
- [instantCheckbox_ setState:NSOffState];
- browser::ShowInstantConfirmDialogIfNecessary([self window], profile_);
- }
-}
-
-// Sets the state of the Instant checkbox and adds the type information to the
-// label.
-- (void)configureInstant {
- bool enabled = instantEnabled_.GetValue();
- NSInteger state = enabled ? NSOnState : NSOffState;
- [instantCheckbox_ setState:state];
-
- [instantExperiment_ setStringValue:@""];
-}
-
-- (IBAction)learnMoreAboutInstant:(id)sender {
- browser::ShowOptionsURL(profile_, browser::InstantLearnMoreURL());
-}
-
-// Called when the user clicks the button to make Chromium the default
-// browser. Registers http and https.
-- (IBAction)makeDefaultBrowser:(id)sender {
- [self willChangeValueForKey:@"defaultBrowser"];
-
- ShellIntegration::SetAsDefaultBrowser();
- [self recordUserAction:UserMetricsAction("Options_SetAsDefaultBrowser")];
- // If the user made Chrome the default browser, then he/she arguably wants
- // to be notified when that changes.
- prefs_->SetBoolean(prefs::kCheckDefaultBrowser, true);
-
- // Tickle KVO so that the UI updates.
- [self didChangeValueForKey:@"defaultBrowser"];
-}
-
-// Returns the Chromium default browser state.
-- (ShellIntegration::DefaultBrowserState)isDefaultBrowser {
- return ShellIntegration::IsDefaultBrowser();
-}
-
-// Returns the text color of the "chromium is your default browser" text (green
-// for yes, red for no).
-- (NSColor*)defaultBrowserTextColor {
- ShellIntegration::DefaultBrowserState state = [self isDefaultBrowser];
- return (state == ShellIntegration::IS_DEFAULT_BROWSER) ?
- [NSColor colorWithCalibratedRed:0.0 green:135.0/255.0 blue:0 alpha:1.0] :
- [NSColor colorWithCalibratedRed:135.0/255.0 green:0 blue:0 alpha:1.0];
-}
-
-// Returns the text for the "chromium is your default browser" string dependent
-// on if Chromium actually is or not.
-- (NSString*)defaultBrowserText {
- ShellIntegration::DefaultBrowserState state = [self isDefaultBrowser];
- int stringId;
- if (state == ShellIntegration::IS_DEFAULT_BROWSER)
- stringId = IDS_OPTIONS_DEFAULTBROWSER_DEFAULT;
- else if (state == ShellIntegration::NOT_DEFAULT_BROWSER)
- stringId = IDS_OPTIONS_DEFAULTBROWSER_NOTDEFAULT;
- else
- stringId = IDS_OPTIONS_DEFAULTBROWSER_UNKNOWN;
- string16 text =
- l10n_util::GetStringFUTF16(stringId,
- l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
- return base::SysUTF16ToNSString(text);
-}
-
-//-------------------------------------------------------------------------
-// User Data panel
-
-// Since passwords and forms are radio groups, 'enabled' is index 0 and
-// 'disabled' is index 1. Yay.
-const int kEnabledIndex = 0;
-const int kDisabledIndex = 1;
-
-// Callback when preferences are changed. |prefName| is the name of the pref
-// that has changed. Unlike on Windows, we don't need to use this method for
-// initializing, that's handled by Cocoa Bindings.
-// Handles prefs for the "Personal Stuff" panel.
-- (void)userDataPrefChanged:(std::string*)prefName {
- if (*prefName == prefs::kPasswordManagerEnabled) {
- [self setPasswordManagerEnabledIndex:askSavePasswords_.GetValue() ?
- kEnabledIndex : kDisabledIndex];
- [self setPasswordManagerChoiceEnabled:!askSavePasswords_.IsManaged()];
- [self setPasswordManagerButtonEnabled:
- !askSavePasswords_.IsManaged() || askSavePasswords_.GetValue()];
- }
- if (*prefName == prefs::kAutoFillEnabled) {
- bool autofill_disabled_by_policy =
- autoFillEnabled_.IsManaged() && !autoFillEnabled_.GetValue();
- [self setAutoFillSettingsButtonEnabled:!autofill_disabled_by_policy];
- }
- if (*prefName == prefs::kCurrentThemeID) {
- [self setIsUsingDefaultTheme:currentTheme_.GetValue().length() == 0];
- }
-}
-
-// Called to launch the Keychain Access app to show the user's stored
-// passwords.
-- (IBAction)showSavedPasswords:(id)sender {
- [self recordUserAction:UserMetricsAction("Options_ShowPasswordsExceptions")];
- [self launchKeychainAccess];
-}
-
-// Called to show the Auto Fill Settings dialog.
-- (IBAction)showAutoFillSettings:(id)sender {
- [self recordUserAction:UserMetricsAction("Options_ShowAutoFillSettings")];
-
- PersonalDataManager* personalDataManager = profile_->GetPersonalDataManager();
- if (!personalDataManager) {
- // Should not reach here because button is disabled when
- // |personalDataManager| is NULL.
- NOTREACHED();
- return;
- }
-
- ShowAutoFillDialog(NULL, personalDataManager, profile_);
-}
-
-// Called to import data from other browsers (Safari, Firefox, etc).
-- (IBAction)importData:(id)sender {
- UserMetrics::RecordAction(UserMetricsAction("Import_ShowDlg"), profile_);
- [ImportSettingsDialogController showImportSettingsDialogForProfile:profile_];
-}
-
-- (IBAction)resetThemeToDefault:(id)sender {
- [self recordUserAction:UserMetricsAction("Options_ThemesReset")];
- profile_->ClearTheme();
-}
-
-- (IBAction)themesGallery:(id)sender {
- [self recordUserAction:UserMetricsAction("Options_ThemesGallery")];
- Browser* browser = BrowserList::GetLastActive();
-
- if (!browser || !browser->GetSelectedTabContents())
- browser = Browser::Create(profile_);
- browser->OpenThemeGalleryTabAndActivate();
-}
-
-// Called when the "stop syncing" confirmation dialog started by
-// doSyncAction is finished. Stop syncing only If the user clicked
-// OK.
-- (void)stopSyncAlertDidEnd:(NSAlert*)alert
- returnCode:(int)returnCode
- contextInfo:(void*)contextInfo {
- DCHECK(syncService_ && !syncService_->IsManaged());
- if (returnCode == NSAlertFirstButtonReturn) {
- syncService_->DisableForUser();
- ProfileSyncService::SyncEvent(ProfileSyncService::STOP_FROM_OPTIONS);
- }
-}
-
-// Called when the user clicks the multi-purpose sync button in the
-// "Personal Stuff" pane.
-- (IBAction)doSyncAction:(id)sender {
- DCHECK(syncService_ && !syncService_->IsManaged());
- if (syncService_->HasSyncSetupCompleted()) {
- // If sync setup has completed that means the sync button was a
- // "stop syncing" button. Bring up a confirmation dialog before
- // actually stopping syncing (see stopSyncAlertDidEnd).
- scoped_nsobject<NSAlert> alert([[NSAlert alloc] init]);
- [alert addButtonWithTitle:l10n_util::GetNSStringWithFixup(
- IDS_SYNC_STOP_SYNCING_CONFIRM_BUTTON_LABEL)];
- [alert addButtonWithTitle:l10n_util::GetNSStringWithFixup(
- IDS_CANCEL)];
- [alert setMessageText:l10n_util::GetNSStringWithFixup(
- IDS_SYNC_STOP_SYNCING_DIALOG_TITLE)];
- [alert setInformativeText:l10n_util::GetNSStringFWithFixup(
- IDS_SYNC_STOP_SYNCING_EXPLANATION_LABEL,
- l10n_util::GetStringUTF16(IDS_PRODUCT_NAME))];
- [alert setAlertStyle:NSWarningAlertStyle];
- const SEL kEndSelector =
- @selector(stopSyncAlertDidEnd:returnCode:contextInfo:);
- [alert beginSheetModalForWindow:[self window]
- modalDelegate:self
- didEndSelector:kEndSelector
- contextInfo:NULL];
- } else {
- // Otherwise, the sync button was a "sync my bookmarks" button.
- // Kick off the sync setup process.
- syncService_->ShowLoginDialog(NULL);
- ProfileSyncService::SyncEvent(ProfileSyncService::START_FROM_OPTIONS);
- }
-}
-
-// Called when the user clicks on the link to the privacy dashboard.
-- (IBAction)showPrivacyDashboard:(id)sender {
- Browser* browser = BrowserList::GetLastActive();
-
- if (!browser || !browser->GetSelectedTabContents())
- browser = Browser::Create(profile_);
- browser->OpenPrivacyDashboardTabAndActivate();
-}
-
-// Called when the user clicks the "Customize Sync" button in the
-// "Personal Stuff" pane. Spawns a dialog-modal sheet that cleans
-// itself up on close.
-- (IBAction)doSyncCustomize:(id)sender {
- syncService_->ShowConfigure(NULL);
-}
-
-- (IBAction)doSyncReauthentication:(id)sender {
- DCHECK(syncService_ && !syncService_->IsManaged());
- syncService_->ShowLoginDialog(NULL);
-}
-
-- (void)setPasswordManagerEnabledIndex:(NSInteger)value {
- if (value == kEnabledIndex)
- [self recordUserAction:UserMetricsAction(
- "Options_PasswordManager_Enable")];
- else
- [self recordUserAction:UserMetricsAction(
- "Options_PasswordManager_Disable")];
- askSavePasswords_.SetValueIfNotManaged(value == kEnabledIndex ? true : false);
-}
-
-- (NSInteger)passwordManagerEnabledIndex {
- return askSavePasswords_.GetValue() ? kEnabledIndex : kDisabledIndex;
-}
-
-- (void)setIsUsingDefaultTheme:(BOOL)value {
- if (value)
- [self recordUserAction:UserMetricsAction(
- "Options_IsUsingDefaultTheme_Enable")];
- else
- [self recordUserAction:UserMetricsAction(
- "Options_IsUsingDefaultTheme_Disable")];
-}
-
-- (BOOL)isUsingDefaultTheme {
- return currentTheme_.GetValue().length() == 0;
-}
-
-//-------------------------------------------------------------------------
-// Under the hood panel
-
-// Callback when preferences are changed. |prefName| is the name of the pref
-// that has changed. Unlike on Windows, we don't need to use this method for
-// initializing, that's handled by Cocoa Bindings.
-// Handles prefs for the "Under the hood" panel.
-- (void)underHoodPrefChanged:(std::string*)prefName {
- if (*prefName == prefs::kAlternateErrorPagesEnabled) {
- [self setShowAlternateErrorPages:
- alternateErrorPages_.GetValue() ? YES : NO];
- [self setShowAlternateErrorPagesEnabled:!alternateErrorPages_.IsManaged()];
- }
- else if (*prefName == prefs::kSearchSuggestEnabled) {
- [self setUseSuggest:useSuggest_.GetValue() ? YES : NO];
- [self setUseSuggestEnabled:!useSuggest_.IsManaged()];
- }
- else if (*prefName == prefs::kDnsPrefetchingEnabled) {
- [self setDnsPrefetch:dnsPrefetch_.GetValue() ? YES : NO];
- [self setDnsPrefetchEnabled:!dnsPrefetch_.IsManaged()];
- }
- else if (*prefName == prefs::kSafeBrowsingEnabled) {
- [self setSafeBrowsing:safeBrowsing_.GetValue() ? YES : NO];
- [self setSafeBrowsingEnabled:!safeBrowsing_.IsManaged()];
- }
- else if (*prefName == prefs::kMetricsReportingEnabled) {
- [self setMetricsReporting:metricsReporting_.GetValue() ? YES : NO];
- [self setMetricsReportingEnabled:!metricsReporting_.IsManaged()];
- }
- else if (*prefName == prefs::kDownloadDefaultDirectory) {
- // Poke KVO.
- [self willChangeValueForKey:@"defaultDownloadLocation"];
- [self didChangeValueForKey:@"defaultDownloadLocation"];
- }
- else if (*prefName == prefs::kPromptForDownload) {
- [self setAskForSaveLocation:askForSaveLocation_.GetValue() ? YES : NO];
- }
- else if (*prefName == prefs::kEnableTranslate) {
- [self setTranslateEnabled:translateEnabled_.GetValue() ? YES : NO];
- }
- else if (*prefName == prefs::kWebkitTabsToLinks) {
- [self setTabsToLinks:tabsToLinks_.GetValue() ? YES : NO];
- }
- else if (*prefName == prefs::kDownloadExtensionsToOpen) {
- // Poke KVC.
- [self setFileHandlerUIEnabled:[self fileHandlerUIEnabled]];
- }
- else if (proxyPrefs_->IsObserved(*prefName)) {
- [self setProxiesConfigureButtonEnabled:!proxyPrefs_->IsManaged()];
- }
-}
-
-// Set the new download path and notify the UI via KVO.
-- (void)downloadPathPanelDidEnd:(NSOpenPanel*)panel
- code:(NSInteger)returnCode
- context:(void*)context {
- if (returnCode == NSOKButton) {
- [self recordUserAction:UserMetricsAction("Options_SetDownloadDirectory")];
- NSURL* path = [[panel URLs] lastObject]; // We only allow 1 item.
- [self willChangeValueForKey:@"defaultDownloadLocation"];
- defaultDownloadLocation_.SetValue(base::SysNSStringToUTF8([path path]));
- [self didChangeValueForKey:@"defaultDownloadLocation"];
- }
-}
-
-// Bring up an open panel to allow the user to set a new downloads location.
-- (void)browseDownloadLocation:(id)sender {
- NSOpenPanel* panel = [NSOpenPanel openPanel];
- [panel setAllowsMultipleSelection:NO];
- [panel setCanChooseFiles:NO];
- [panel setCanChooseDirectories:YES];
- NSString* path = base::SysUTF8ToNSString(defaultDownloadLocation_.GetValue());
- [panel beginSheetForDirectory:path
- file:nil
- types:nil
- modalForWindow:[self window]
- modalDelegate:self
- didEndSelector:@selector(downloadPathPanelDidEnd:code:context:)
- contextInfo:NULL];
-}
-
-// Called to clear user's browsing data. This puts up an application-modal
-// dialog to guide the user through clearing the data.
-- (IBAction)clearData:(id)sender {
- [ClearBrowsingDataController
- showClearBrowsingDialogForProfile:profile_];
-}
-
-// Opens the "Content Settings" dialog.
-- (IBAction)showContentSettings:(id)sender {
- [ContentSettingsDialogController
- showContentSettingsForType:CONTENT_SETTINGS_TYPE_DEFAULT
- profile:profile_];
-}
-
-- (IBAction)privacyLearnMore:(id)sender {
- GURL url = google_util::AppendGoogleLocaleParam(
- GURL(chrome::kPrivacyLearnMoreURL));
- // We open a new browser window so the Options dialog doesn't get lost
- // behind other windows.
- browser::ShowOptionsURL(profile_, url);
-}
-
-- (IBAction)resetAutoOpenFiles:(id)sender {
- profile_->GetDownloadManager()->download_prefs()->ResetAutoOpen();
- [self recordUserAction:UserMetricsAction("Options_ResetAutoOpenFiles")];
-}
-
-- (IBAction)openProxyPreferences:(id)sender {
- NSArray* itemsToOpen = [NSArray arrayWithObject:[NSURL fileURLWithPath:
- @"/System/Library/PreferencePanes/Network.prefPane"]];
-
- const char* proxyPrefCommand = "Proxies";
- base::mac::ScopedAEDesc<> openParams;
- OSStatus status = AECreateDesc('ptru',
- proxyPrefCommand,
- strlen(proxyPrefCommand),
- openParams.OutPointer());
- LOG_IF(ERROR, status != noErr) << "Failed to create open params: " << status;
-
- LSLaunchURLSpec launchSpec = { 0 };
- launchSpec.itemURLs = (CFArrayRef)itemsToOpen;
- launchSpec.passThruParams = openParams;
- launchSpec.launchFlags = kLSLaunchAsync | kLSLaunchDontAddToRecents;
- LSOpenFromURLSpec(&launchSpec, NULL);
-}
-
-// Returns whether the alternate error page checkbox should be checked based
-// on the preference.
-- (BOOL)showAlternateErrorPages {
- return alternateErrorPages_.GetValue() ? YES : NO;
-}
-
-// Sets the backend pref for whether or not the alternate error page checkbox
-// should be displayed based on |value|.
-- (void)setShowAlternateErrorPages:(BOOL)value {
- if (value)
- [self recordUserAction:UserMetricsAction(
- "Options_LinkDoctorCheckbox_Enable")];
- else
- [self recordUserAction:UserMetricsAction(
- "Options_LinkDoctorCheckbox_Disable")];
- alternateErrorPages_.SetValueIfNotManaged(value ? true : false);
-}
-
-// Returns whether the suggest checkbox should be checked based on the
-// preference.
-- (BOOL)useSuggest {
- return useSuggest_.GetValue() ? YES : NO;
-}
-
-// Sets the backend pref for whether or not the suggest checkbox should be
-// displayed based on |value|.
-- (void)setUseSuggest:(BOOL)value {
- if (value)
- [self recordUserAction:UserMetricsAction(
- "Options_UseSuggestCheckbox_Enable")];
- else
- [self recordUserAction:UserMetricsAction(
- "Options_UseSuggestCheckbox_Disable")];
- useSuggest_.SetValueIfNotManaged(value ? true : false);
-}
-
-// Returns whether the DNS prefetch checkbox should be checked based on the
-// preference.
-- (BOOL)dnsPrefetch {
- return dnsPrefetch_.GetValue() ? YES : NO;
-}
-
-// Sets the backend pref for whether or not the DNS prefetch checkbox should be
-// displayed based on |value|.
-- (void)setDnsPrefetch:(BOOL)value {
- if (value)
- [self recordUserAction:UserMetricsAction(
- "Options_DnsPrefetchCheckbox_Enable")];
- else
- [self recordUserAction:UserMetricsAction(
- "Options_DnsPrefetchCheckbox_Disable")];
- dnsPrefetch_.SetValueIfNotManaged(value ? true : false);
-}
-
-// Returns whether the safe browsing checkbox should be checked based on the
-// preference.
-- (BOOL)safeBrowsing {
- return safeBrowsing_.GetValue() ? YES : NO;
-}
-
-// Sets the backend pref for whether or not the safe browsing checkbox should be
-// displayed based on |value|.
-- (void)setSafeBrowsing:(BOOL)value {
- if (value)
- [self recordUserAction:UserMetricsAction(
- "Options_SafeBrowsingCheckbox_Enable")];
- else
- [self recordUserAction:UserMetricsAction(
- "Options_SafeBrowsingCheckbox_Disable")];
- safeBrowsing_.SetValueIfNotManaged(value ? true : false);
- SafeBrowsingService* safeBrowsingService =
- g_browser_process->resource_dispatcher_host()->safe_browsing_service();
- MessageLoop::current()->PostTask(
- FROM_HERE,
- NewRunnableMethod(safeBrowsingService,
- &SafeBrowsingService::OnEnable,
- safeBrowsing_.GetValue()));
-}
-
-// Returns whether the metrics reporting checkbox should be checked based on the
-// preference.
-- (BOOL)metricsReporting {
- return metricsReporting_.GetValue() ? YES : NO;
-}
-
-// Sets the backend pref for whether or not the metrics reporting checkbox
-// should be displayed based on |value|.
-- (void)setMetricsReporting:(BOOL)value {
- if (value)
- [self recordUserAction:UserMetricsAction(
- "Options_MetricsReportingCheckbox_Enable")];
- else
- [self recordUserAction:UserMetricsAction(
- "Options_MetricsReportingCheckbox_Disable")];
-
- // TODO(pinkerton): windows shows a dialog here telling the user they need to
- // restart for this to take effect. http://crbug.com/34653
- metricsReporting_.SetValueIfNotManaged(value ? true : false);
-
- bool enabled = metricsReporting_.GetValue();
- GoogleUpdateSettings::SetCollectStatsConsent(enabled);
- bool update_pref = GoogleUpdateSettings::GetCollectStatsConsent();
- if (enabled != update_pref) {
- DVLOG(1) << "GENERAL SECTION: Unable to set crash report status to "
- << enabled;
- }
- // Only change the pref if GoogleUpdateSettings::GetCollectStatsConsent
- // succeeds.
- enabled = update_pref;
-
- MetricsService* metrics = g_browser_process->metrics_service();
- DCHECK(metrics);
- if (metrics) {
- metrics->SetUserPermitsUpload(enabled);
- if (enabled)
- metrics->Start();
- else
- metrics->Stop();
- }
-}
-
-- (NSURL*)defaultDownloadLocation {
- NSString* pathString =
- base::SysUTF8ToNSString(defaultDownloadLocation_.GetValue());
- return [NSURL fileURLWithPath:pathString];
-}
-
-- (BOOL)askForSaveLocation {
- return askForSaveLocation_.GetValue();
-}
-
-- (void)setAskForSaveLocation:(BOOL)value {
- if (value) {
- [self recordUserAction:UserMetricsAction(
- "Options_AskForSaveLocation_Enable")];
- } else {
- [self recordUserAction:UserMetricsAction(
- "Options_AskForSaveLocation_Disable")];
- }
- askForSaveLocation_.SetValue(value);
-}
-
-- (BOOL)fileHandlerUIEnabled {
- if (!profile_->GetDownloadManager()) // Not set in unit tests.
- return NO;
- return profile_->GetDownloadManager()->download_prefs()->IsAutoOpenUsed();
-}
-
-- (void)setFileHandlerUIEnabled:(BOOL)value {
- [resetFileHandlersButton_ setEnabled:value];
-}
-
-- (BOOL)translateEnabled {
- return translateEnabled_.GetValue();
-}
-
-- (void)setTranslateEnabled:(BOOL)value {
- if (value) {
- [self recordUserAction:UserMetricsAction("Options_Translate_Enable")];
- } else {
- [self recordUserAction:UserMetricsAction("Options_Translate_Disable")];
- }
- translateEnabled_.SetValue(value);
-}
-
-- (BOOL)tabsToLinks {
- return tabsToLinks_.GetValue();
-}
-
-- (void)setTabsToLinks:(BOOL)value {
- if (value) {
- [self recordUserAction:UserMetricsAction("Options_TabsToLinks_Enable")];
- } else {
- [self recordUserAction:UserMetricsAction("Options_TabsToLinks_Disable")];
- }
- tabsToLinks_.SetValue(value);
-}
-
-- (void)fontAndLanguageEndSheet:(NSWindow*)sheet
- returnCode:(NSInteger)returnCode
- contextInfo:(void*)context {
- [sheet close];
- [sheet orderOut:self];
- fontLanguageSettings_ = nil;
-}
-
-- (IBAction)changeFontAndLanguageSettings:(id)sender {
- // Intentionally leak the controller as it will clean itself up when the
- // sheet closes.
- fontLanguageSettings_ =
- [[FontLanguageSettingsController alloc] initWithProfile:profile_];
- [NSApp beginSheet:[fontLanguageSettings_ window]
- modalForWindow:[self window]
- modalDelegate:self
- didEndSelector:@selector(fontAndLanguageEndSheet:returnCode:contextInfo:)
- contextInfo:nil];
-}
-
-// Called to launch the Keychain Access app to show the user's stored
-// certificates. Note there's no way to script the app to auto-select the
-// certificates.
-- (IBAction)showCertificates:(id)sender {
- [self recordUserAction:UserMetricsAction("Options_ManagerCerts")];
- [self launchKeychainAccess];
-}
-
-- (IBAction)resetToDefaults:(id)sender {
- // The alert will clean itself up in the did-end selector.
- NSAlert* alert = [[NSAlert alloc] init];
- [alert setMessageText:l10n_util::GetNSString(IDS_OPTIONS_RESET_MESSAGE)];
- NSButton* resetButton = [alert addButtonWithTitle:
- l10n_util::GetNSString(IDS_OPTIONS_RESET_OKLABEL)];
- [resetButton setKeyEquivalent:@""];
- NSButton* cancelButton = [alert addButtonWithTitle:
- l10n_util::GetNSString(IDS_OPTIONS_RESET_CANCELLABEL)];
- [cancelButton setKeyEquivalent:@"\r"];
-
- [alert beginSheetModalForWindow:[self window]
- modalDelegate:self
- didEndSelector:@selector(resetToDefaults:returned:context:)
- contextInfo:nil];
-}
-
-- (void)resetToDefaults:(NSAlert*)alert
- returned:(NSInteger)code
- context:(void*)context {
- if (code == NSAlertFirstButtonReturn) {
- OptionsUtil::ResetToDefaults(profile_);
- }
- [alert autorelease];
-}
-
-//-------------------------------------------------------------------------
-
-// Callback when preferences are changed. |prefName| is the name of the
-// pref that has changed and should not be NULL.
-- (void)prefChanged:(std::string*)prefName {
- DCHECK(prefName);
- if (!prefName) return;
- [self basicsPrefChanged:prefName];
- [self userDataPrefChanged:prefName];
- [self underHoodPrefChanged:prefName];
-}
-
-// Callback when sync service state has changed.
-//
-// TODO(akalin): Decomp this out since a lot of it is copied from the
-// Windows version.
-// TODO(akalin): Change the background of the status label/link on error.
-- (void)syncStateChanged {
- DCHECK(syncService_);
-
- string16 statusLabel, linkLabel;
- sync_ui_util::MessageType status =
- sync_ui_util::GetStatusLabels(syncService_, &statusLabel, &linkLabel);
- bool managed = syncService_->IsManaged();
-
- [syncButton_ setEnabled:!syncService_->WizardIsVisible()];
- NSString* buttonLabel;
- if (syncService_->HasSyncSetupCompleted()) {
- buttonLabel = l10n_util::GetNSStringWithFixup(
- IDS_SYNC_STOP_SYNCING_BUTTON_LABEL);
- [syncCustomizeButton_ setHidden:false];
- } else if (syncService_->SetupInProgress()) {
- buttonLabel = l10n_util::GetNSStringWithFixup(
- IDS_SYNC_NTP_SETUP_IN_PROGRESS);
- [syncCustomizeButton_ setHidden:true];
- } else {
- buttonLabel = l10n_util::GetNSStringWithFixup(
- IDS_SYNC_START_SYNC_BUTTON_LABEL);
- [syncCustomizeButton_ setHidden:true];
- }
- [syncCustomizeButton_ setEnabled:!managed];
- [syncButton_ setTitle:buttonLabel];
- [syncButton_ setEnabled:!managed];
-
- [syncStatus_ setStringValue:base::SysUTF16ToNSString(statusLabel)];
- [syncLink_ setHidden:linkLabel.empty()];
- [syncLink_ setTitle:base::SysUTF16ToNSString(linkLabel)];
- [syncLink_ setEnabled:!managed];
-
- NSButtonCell* syncLinkCell = static_cast<NSButtonCell*>([syncLink_ cell]);
- if (!syncStatusNoErrorBackgroundColor_) {
- DCHECK(!syncLinkNoErrorBackgroundColor_);
- // We assume that the sync controls start off in a non-error
- // state.
- syncStatusNoErrorBackgroundColor_.reset(
- [[syncStatus_ backgroundColor] retain]);
- syncLinkNoErrorBackgroundColor_.reset(
- [[syncLinkCell backgroundColor] retain]);
- }
- if (status == sync_ui_util::SYNC_ERROR) {
- [syncStatus_ setBackgroundColor:syncErrorBackgroundColor_];
- [syncLinkCell setBackgroundColor:syncErrorBackgroundColor_];
- } else {
- [syncStatus_ setBackgroundColor:syncStatusNoErrorBackgroundColor_];
- [syncLinkCell setBackgroundColor:syncLinkNoErrorBackgroundColor_];
- }
-}
-
-// Show the preferences window.
-- (IBAction)showPreferences:(id)sender {
- [self showWindow:sender];
-}
-
-- (IBAction)toolbarButtonSelected:(id)sender {
- DCHECK([sender isKindOfClass:[NSToolbarItem class]]);
- OptionsPage page = [self getPageForToolbarItem:sender];
- [self displayPreferenceViewForPage:page animate:YES];
-}
-
-// Helper to update the window to display a preferences view for a page.
-- (void)displayPreferenceViewForPage:(OptionsPage)page
- animate:(BOOL)animate {
- NSWindow* prefsWindow = [self window];
-
- // Needs to go *after* the call to [self window], which triggers
- // awakeFromNib if necessary.
- NSView* prefsView = [self getPrefsViewForPage:page];
- NSView* contentView = [prefsWindow contentView];
-
- // Make sure we aren't being told to display the same thing again.
- if (currentPrefsView_ == prefsView &&
- managedPrefsBannerVisible_ == bannerState_->IsVisible()) {
- return;
- }
-
- // Remember new options page as current page.
- if (page != OPTIONS_PAGE_DEFAULT)
- lastSelectedPage_.SetValue(page);
-
- // Stop any running animation, and reset the subviews to the new state. We
- // re-add any views we need for animation later.
- [animation_ stopAnimation];
- NSView* oldPrefsView = currentPrefsView_;
- currentPrefsView_ = prefsView;
- [self resetSubViews];
-
- // Update the banner state.
- [self initBannerStateForPage:page];
- BOOL showBanner = bannerState_->IsVisible();
-
- // Update the window title.
- NSToolbarItem* toolbarItem = [self getToolbarItemForPage:page];
- [prefsWindow setTitle:[toolbarItem label]];
-
- // Calculate new frames for the subviews.
- NSRect prefsViewFrame = [prefsView frame];
- NSRect contentViewFrame = [contentView frame];
- NSRect bannerViewFrame = [managedPrefsBannerView_ frame];
-
- // Determine what height the managed prefs banner will use.
- CGFloat bannerViewHeight = showBanner ? NSHeight(bannerViewFrame) : 0.0;
-
- if (animate) {
- // NSViewAnimation doesn't seem to honor subview resizing as it animates the
- // Window's frame. So instead of trying to get the top in the right place,
- // just set the origin where it should be at the end, and let the fade/size
- // slide things into the right spot.
- prefsViewFrame.origin.y = 0.0;
- } else {
- // The prefView is anchored to the top of its parent, so set its origin so
- // that the top is where it should be. When the window's frame is set, the
- // origin will be adjusted to keep it in the right spot.
- prefsViewFrame.origin.y = NSHeight(contentViewFrame) -
- NSHeight(prefsViewFrame) - bannerViewHeight;
- }
- bannerViewFrame.origin.y = NSHeight(prefsViewFrame);
- bannerViewFrame.size.width = NSWidth(contentViewFrame);
- [prefsView setFrame:prefsViewFrame];
-
- // Figure out the size of the window.
- NSRect windowFrame = [contentView convertRect:[prefsWindow frame]
- fromView:nil];
- CGFloat titleToolbarHeight =
- NSHeight(windowFrame) - NSHeight(contentViewFrame);
- windowFrame.size.height =
- NSHeight(prefsViewFrame) + titleToolbarHeight + bannerViewHeight;
- DCHECK_GE(NSWidth(windowFrame), NSWidth(prefsViewFrame))
- << "Initial width set wasn't wide enough.";
- windowFrame = [contentView convertRect:windowFrame toView:nil];
- windowFrame.origin.y = NSMaxY([prefsWindow frame]) - NSHeight(windowFrame);
-
- // Now change the size.
- if (animate) {
- NSMutableArray* animations = [NSMutableArray arrayWithCapacity:4];
- if (oldPrefsView != prefsView) {
- // Fade between prefs views if they change.
- [contentView addSubview:oldPrefsView
- positioned:NSWindowBelow
- relativeTo:nil];
- [animations addObject:
- [NSDictionary dictionaryWithObjectsAndKeys:
- oldPrefsView, NSViewAnimationTargetKey,
- NSViewAnimationFadeOutEffect, NSViewAnimationEffectKey,
- nil]];
- [animations addObject:
- [NSDictionary dictionaryWithObjectsAndKeys:
- prefsView, NSViewAnimationTargetKey,
- NSViewAnimationFadeInEffect, NSViewAnimationEffectKey,
- nil]];
- } else {
- // Make sure the prefs pane ends up in the right position in case we
- // manipulate the banner.
- [animations addObject:
- [NSDictionary dictionaryWithObjectsAndKeys:
- prefsView, NSViewAnimationTargetKey,
- [NSValue valueWithRect:prefsViewFrame],
- NSViewAnimationEndFrameKey,
- nil]];
- }
- if (showBanner != managedPrefsBannerVisible_) {
- // Slide the warning banner in or out of view.
- [animations addObject:
- [NSDictionary dictionaryWithObjectsAndKeys:
- managedPrefsBannerView_, NSViewAnimationTargetKey,
- [NSValue valueWithRect:bannerViewFrame],
- NSViewAnimationEndFrameKey,
- nil]];
- }
- // Window resize animation.
- [animations addObject:
- [NSDictionary dictionaryWithObjectsAndKeys:
- prefsWindow, NSViewAnimationTargetKey,
- [NSValue valueWithRect:windowFrame], NSViewAnimationEndFrameKey,
- nil]];
- [animation_ setViewAnimations:animations];
- // The default duration is 0.5s, which actually feels slow in here, so speed
- // it up a bit.
- [animation_ gtm_setDuration:0.2
- eventMask:NSLeftMouseUpMask];
- [animation_ startAnimation];
- } else {
- // If not animating, odds are we don't want to display either (because it
- // is initial window setup).
- [prefsWindow setFrame:windowFrame display:NO];
- [managedPrefsBannerView_ setFrame:bannerViewFrame];
- }
-
- managedPrefsBannerVisible_ = showBanner;
-}
-
-- (void)resetSubViews {
- // Reset subviews to current prefs view and banner, remove any views that
- // might have been left over from previous state or animation.
- NSArray* subviews = [NSArray arrayWithObjects:
- currentPrefsView_, managedPrefsBannerView_, nil];
- [[[self window] contentView] setSubviews:subviews];
- [[self window] setInitialFirstResponder:currentPrefsView_];
-}
-
-- (void)animationDidEnd:(NSAnimation*)animation {
- DCHECK_EQ(animation_.get(), animation);
- // Animation finished, reset subviews to current prefs view and the banner.
- [self resetSubViews];
-}
-
-// Reinitializes the banner state tracker object to watch for managed bits of
-// preferences relevant to the given options |page|.
-- (void)initBannerStateForPage:(OptionsPage)page {
- page = [self normalizePage:page];
-
- // During unit tests, there is no local state object, so we fall back to
- // the prefs object (where we've explicitly registered this pref so we
- // know it's there).
- PrefService* local = g_browser_process->local_state();
- if (!local)
- local = prefs_;
- bannerState_.reset(
- new PreferencesWindowControllerInternal::ManagedPrefsBannerState(
- self, page, local, prefs_));
-}
-
-- (void)switchToPage:(OptionsPage)page animate:(BOOL)animate {
- [self displayPreferenceViewForPage:page animate:animate];
- NSToolbarItem* toolbarItem = [self getToolbarItemForPage:page];
- [toolbar_ setSelectedItemIdentifier:[toolbarItem itemIdentifier]];
-}
-
-// Called when the window is being closed. Send out a notification that the user
-// is done editing preferences. Make sure there are no pending field editors
-// by clearing the first responder.
-- (void)windowWillClose:(NSNotification*)notification {
- // Setting the first responder to the window ends any in-progress field
- // editor. This will update the model appropriately so there's nothing left
- // to do.
- if (![[self window] makeFirstResponder:[self window]]) {
- // We've hit a recalcitrant field editor, force it to go away.
- [[self window] endEditingFor:nil];
- }
- [self autorelease];
-}
-
-- (void)controlTextDidEndEditing:(NSNotification*)notification {
- [customPagesSource_ validateURLs];
-}
-
-@end
-
-@implementation PreferencesWindowController(Testing)
-
-- (IntegerPrefMember*)lastSelectedPage {
- return &lastSelectedPage_;
-}
-
-- (NSToolbar*)toolbar {
- return toolbar_;
-}
-
-- (NSView*)basicsView {
- return basicsView_;
-}
-
-- (NSView*)personalStuffView {
- return personalStuffView_;
-}
-
-- (NSView*)underTheHoodView {
- return underTheHoodView_;
-}
-
-- (OptionsPage)normalizePage:(OptionsPage)page {
- if (page == OPTIONS_PAGE_DEFAULT) {
- // Get the last visited page from local state.
- page = static_cast<OptionsPage>(lastSelectedPage_.GetValue());
- if (page == OPTIONS_PAGE_DEFAULT) {
- page = OPTIONS_PAGE_GENERAL;
- }
- }
- return page;
-}
-
-- (NSToolbarItem*)getToolbarItemForPage:(OptionsPage)page {
- NSUInteger pageIndex = (NSUInteger)[self normalizePage:page];
- NSArray* items = [toolbar_ items];
- NSUInteger itemCount = [items count];
- DCHECK_GE(pageIndex, 0U);
- if (pageIndex >= itemCount) {
- NOTIMPLEMENTED();
- pageIndex = 0;
- }
- DCHECK_GT(itemCount, 0U);
- return [items objectAtIndex:pageIndex];
-}
-
-- (OptionsPage)getPageForToolbarItem:(NSToolbarItem*)toolbarItem {
- // Tags are set in the nib file.
- switch ([toolbarItem tag]) {
- case 0: // Basics
- return OPTIONS_PAGE_GENERAL;
- case 1: // Personal Stuff
- return OPTIONS_PAGE_CONTENT;
- case 2: // Under the Hood
- return OPTIONS_PAGE_ADVANCED;
- default:
- NOTIMPLEMENTED();
- return OPTIONS_PAGE_GENERAL;
- }
-}
-
-- (NSView*)getPrefsViewForPage:(OptionsPage)page {
- // The views will be NULL if this is mistakenly called before awakeFromNib.
- DCHECK(basicsView_);
- DCHECK(personalStuffView_);
- DCHECK(underTheHoodView_);
- page = [self normalizePage:page];
- switch (page) {
- case OPTIONS_PAGE_GENERAL:
- return basicsView_;
- case OPTIONS_PAGE_CONTENT:
- return personalStuffView_;
- case OPTIONS_PAGE_ADVANCED:
- return underTheHoodView_;
- case OPTIONS_PAGE_DEFAULT:
- case OPTIONS_PAGE_COUNT:
- LOG(DFATAL) << "Invalid page value " << page;
- }
- return basicsView_;
-}
-
-@end
diff --git a/chrome/browser/cocoa/preferences_window_controller_unittest.mm b/chrome/browser/cocoa/preferences_window_controller_unittest.mm
deleted file mode 100644
index c22a581..0000000
--- a/chrome/browser/cocoa/preferences_window_controller_unittest.mm
+++ /dev/null
@@ -1,240 +0,0 @@
-// Copyright (c) 2009 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>
-
-#import "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/preferences_window_controller.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/custom_home_pages_model.h"
-#include "chrome/browser/options_window.h"
-#include "chrome/common/pref_names.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-// Helper Objective-C object that sets a BOOL when we get a particular
-// callback from the prefs window.
-@interface PrefsClosedObserver : NSObject {
- @public
- BOOL gotNotification_;
-}
-- (void)prefsWindowClosed:(NSNotification*)notify;
-@end
-
-@implementation PrefsClosedObserver
-- (void)prefsWindowClosed:(NSNotification*)notify {
- gotNotification_ = YES;
-}
-@end
-
-namespace {
-
-class PrefsControllerTest : public CocoaTest {
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
- // The metrics reporting pref is registerd on the local state object in
- // real builds, but we don't have one of those for unit tests. Register
- // it on prefs so we'll find it when we go looking.
- PrefService* prefs = browser_helper_.profile()->GetPrefs();
- prefs->RegisterBooleanPref(prefs::kMetricsReportingEnabled, false);
-
- pref_controller_ = [[PreferencesWindowController alloc]
- initWithProfile:browser_helper_.profile()
- initialPage:OPTIONS_PAGE_DEFAULT];
- EXPECT_TRUE(pref_controller_);
- }
-
- virtual void TearDown() {
- [pref_controller_ close];
- CocoaTest::TearDown();
- }
-
- BrowserTestHelper browser_helper_;
- PreferencesWindowController* pref_controller_;
-};
-
-// Test showing the preferences window and making sure it's visible, then
-// making sure we get the notification when it's closed.
-TEST_F(PrefsControllerTest, ShowAndClose) {
- [pref_controller_ showPreferences:nil];
- EXPECT_TRUE([[pref_controller_ window] isVisible]);
-
- scoped_nsobject<PrefsClosedObserver> observer(
- [[PrefsClosedObserver alloc] init]);
- NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
- [defaultCenter addObserver:observer.get()
- selector:@selector(prefsWindowClosed:)
- name:NSWindowWillCloseNotification
- object:[pref_controller_ window]];
- [[pref_controller_ window] performClose:observer];
- EXPECT_TRUE(observer.get()->gotNotification_);
- [defaultCenter removeObserver:observer.get()];
-
- // Prevent pref_controller_ from being closed again in TearDown()
- pref_controller_ = nil;
-}
-
-TEST_F(PrefsControllerTest, ValidateCustomHomePagesTable) {
- // First, insert two valid URLs into the CustomHomePagesModel.
- GURL url1("http://www.google.com/");
- GURL url2("http://maps.google.com/");
- std::vector<GURL> urls;
- urls.push_back(url1);
- urls.push_back(url2);
- [[pref_controller_ customPagesSource] setURLs:urls];
- EXPECT_EQ(2U, [[pref_controller_ customPagesSource] countOfCustomHomePages]);
-
- // Now insert a bad (empty) URL into the model.
- [[pref_controller_ customPagesSource] setURLStringEmptyAt:1];
-
- // Send a notification to simulate the end of editing on a cell in the table
- // which should trigger validation.
- [pref_controller_ controlTextDidEndEditing:[NSNotification
- notificationWithName:NSControlTextDidEndEditingNotification
- object:nil]];
- EXPECT_EQ(1U, [[pref_controller_ customPagesSource] countOfCustomHomePages]);
-}
-
-TEST_F(PrefsControllerTest, NormalizePage) {
- EXPECT_EQ(OPTIONS_PAGE_GENERAL,
- [pref_controller_ normalizePage:OPTIONS_PAGE_GENERAL]);
- EXPECT_EQ(OPTIONS_PAGE_CONTENT,
- [pref_controller_ normalizePage:OPTIONS_PAGE_CONTENT]);
- EXPECT_EQ(OPTIONS_PAGE_ADVANCED,
- [pref_controller_ normalizePage:OPTIONS_PAGE_ADVANCED]);
-
- [pref_controller_ lastSelectedPage]->SetValue(OPTIONS_PAGE_ADVANCED);
- EXPECT_EQ(OPTIONS_PAGE_ADVANCED,
- [pref_controller_ normalizePage:OPTIONS_PAGE_DEFAULT]);
-
- [pref_controller_ lastSelectedPage]->SetValue(OPTIONS_PAGE_DEFAULT);
- EXPECT_EQ(OPTIONS_PAGE_GENERAL,
- [pref_controller_ normalizePage:OPTIONS_PAGE_DEFAULT]);
-}
-
-TEST_F(PrefsControllerTest, GetToolbarItemForPage) {
- // Trigger awakeFromNib.
- [pref_controller_ window];
-
- NSArray* toolbarItems = [[pref_controller_ toolbar] items];
- EXPECT_EQ([toolbarItems objectAtIndex:0],
- [pref_controller_ getToolbarItemForPage:OPTIONS_PAGE_GENERAL]);
- EXPECT_EQ([toolbarItems objectAtIndex:1],
- [pref_controller_ getToolbarItemForPage:OPTIONS_PAGE_CONTENT]);
- EXPECT_EQ([toolbarItems objectAtIndex:2],
- [pref_controller_ getToolbarItemForPage:OPTIONS_PAGE_ADVANCED]);
-
- [pref_controller_ lastSelectedPage]->SetValue(OPTIONS_PAGE_ADVANCED);
- EXPECT_EQ([toolbarItems objectAtIndex:2],
- [pref_controller_ getToolbarItemForPage:OPTIONS_PAGE_DEFAULT]);
-
- // Out-of-range argument.
- EXPECT_EQ([toolbarItems objectAtIndex:0],
- [pref_controller_ getToolbarItemForPage:OPTIONS_PAGE_COUNT]);
-}
-
-TEST_F(PrefsControllerTest, GetPageForToolbarItem) {
- scoped_nsobject<NSToolbarItem> toolbarItem(
- [[NSToolbarItem alloc] initWithItemIdentifier:@""]);
- [toolbarItem setTag:0];
- EXPECT_EQ(OPTIONS_PAGE_GENERAL,
- [pref_controller_ getPageForToolbarItem:toolbarItem]);
- [toolbarItem setTag:1];
- EXPECT_EQ(OPTIONS_PAGE_CONTENT,
- [pref_controller_ getPageForToolbarItem:toolbarItem]);
- [toolbarItem setTag:2];
- EXPECT_EQ(OPTIONS_PAGE_ADVANCED,
- [pref_controller_ getPageForToolbarItem:toolbarItem]);
-
- // Out-of-range argument.
- [toolbarItem setTag:3];
- EXPECT_EQ(OPTIONS_PAGE_GENERAL,
- [pref_controller_ getPageForToolbarItem:toolbarItem]);
-}
-
-TEST_F(PrefsControllerTest, GetPrefsViewForPage) {
- // Trigger awakeFromNib.
- [pref_controller_ window];
-
- EXPECT_EQ([pref_controller_ basicsView],
- [pref_controller_ getPrefsViewForPage:OPTIONS_PAGE_GENERAL]);
- EXPECT_EQ([pref_controller_ personalStuffView],
- [pref_controller_ getPrefsViewForPage:OPTIONS_PAGE_CONTENT]);
- EXPECT_EQ([pref_controller_ underTheHoodView],
- [pref_controller_ getPrefsViewForPage:OPTIONS_PAGE_ADVANCED]);
-
- [pref_controller_ lastSelectedPage]->SetValue(OPTIONS_PAGE_ADVANCED);
- EXPECT_EQ([pref_controller_ underTheHoodView],
- [pref_controller_ getPrefsViewForPage:OPTIONS_PAGE_DEFAULT]);
-}
-
-TEST_F(PrefsControllerTest, SwitchToPage) {
- // Trigger awakeFromNib.
- NSWindow* window = [pref_controller_ window];
-
- NSView* contentView = [window contentView];
- NSView* basicsView = [pref_controller_ basicsView];
- NSView* personalStuffView = [pref_controller_ personalStuffView];
- NSView* underTheHoodView = [pref_controller_ underTheHoodView];
- NSToolbar* toolbar = [pref_controller_ toolbar];
- NSToolbarItem* basicsToolbarItem =
- [pref_controller_ getToolbarItemForPage:OPTIONS_PAGE_GENERAL];
- NSToolbarItem* personalStuffToolbarItem =
- [pref_controller_ getToolbarItemForPage:OPTIONS_PAGE_CONTENT];
- NSToolbarItem* underTheHoodToolbarItem =
- [pref_controller_ getToolbarItemForPage:OPTIONS_PAGE_ADVANCED];
- NSString* basicsIdentifier = [basicsToolbarItem itemIdentifier];
- NSString* personalStuffIdentifier = [personalStuffToolbarItem itemIdentifier];
- NSString* underTheHoodIdentifier = [underTheHoodToolbarItem itemIdentifier];
- IntegerPrefMember* lastSelectedPage = [pref_controller_ lastSelectedPage];
-
- // Test without animation.
-
- [pref_controller_ switchToPage:OPTIONS_PAGE_GENERAL animate:NO];
- EXPECT_TRUE([basicsView isDescendantOf:contentView]);
- EXPECT_FALSE([personalStuffView isDescendantOf:contentView]);
- EXPECT_FALSE([underTheHoodView isDescendantOf:contentView]);
- EXPECT_NSEQ(basicsIdentifier, [toolbar selectedItemIdentifier]);
- EXPECT_EQ(OPTIONS_PAGE_GENERAL, lastSelectedPage->GetValue());
- EXPECT_NSEQ([basicsToolbarItem label], [window title]);
-
- [pref_controller_ switchToPage:OPTIONS_PAGE_CONTENT animate:NO];
- EXPECT_FALSE([basicsView isDescendantOf:contentView]);
- EXPECT_TRUE([personalStuffView isDescendantOf:contentView]);
- EXPECT_FALSE([underTheHoodView isDescendantOf:contentView]);
- EXPECT_NSEQ([toolbar selectedItemIdentifier], personalStuffIdentifier);
- EXPECT_EQ(OPTIONS_PAGE_CONTENT, lastSelectedPage->GetValue());
- EXPECT_NSEQ([personalStuffToolbarItem label], [window title]);
-
- [pref_controller_ switchToPage:OPTIONS_PAGE_ADVANCED animate:NO];
- EXPECT_FALSE([basicsView isDescendantOf:contentView]);
- EXPECT_FALSE([personalStuffView isDescendantOf:contentView]);
- EXPECT_TRUE([underTheHoodView isDescendantOf:contentView]);
- EXPECT_NSEQ([toolbar selectedItemIdentifier], underTheHoodIdentifier);
- EXPECT_EQ(OPTIONS_PAGE_ADVANCED, lastSelectedPage->GetValue());
- EXPECT_NSEQ([underTheHoodToolbarItem label], [window title]);
-
- // Test OPTIONS_PAGE_DEFAULT.
-
- lastSelectedPage->SetValue(OPTIONS_PAGE_CONTENT);
- [pref_controller_ switchToPage:OPTIONS_PAGE_DEFAULT animate:NO];
- EXPECT_FALSE([basicsView isDescendantOf:contentView]);
- EXPECT_TRUE([personalStuffView isDescendantOf:contentView]);
- EXPECT_FALSE([underTheHoodView isDescendantOf:contentView]);
- EXPECT_NSEQ(personalStuffIdentifier, [toolbar selectedItemIdentifier]);
- EXPECT_EQ(OPTIONS_PAGE_CONTENT, lastSelectedPage->GetValue());
- EXPECT_NSEQ([personalStuffToolbarItem label], [window title]);
-
- // TODO(akalin): Figure out how to test animation; we'll need everything
- // to stick around until the animation finishes.
-}
-
-// TODO(akalin): Figure out how to test sync controls.
-// TODO(akalin): Figure out how to test that sync controls are not shown
-// when there isn't a sync service.
-
-} // namespace
diff --git a/chrome/browser/cocoa/previewable_contents_controller.h b/chrome/browser/cocoa/previewable_contents_controller.h
deleted file mode 100644
index c4cc84e..0000000
--- a/chrome/browser/cocoa/previewable_contents_controller.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_PREVIEWABLE_CONTENTS_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_PREVIEWABLE_CONTENTS_CONTROLLER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-class TabContents;
-
-// PreviewableContentsController manages the display of up to two tab contents
-// views. It is primarily for use with Instant results. This class supports
-// the notion of an "active" view vs. a "preview" tab contents view.
-//
-// The "active" view is a container view that can be retrieved using
-// |-activeContainer|. Its contents are meant to be managed by an external
-// class.
-//
-// The "preview" can be set using |-showPreview:| and |-hidePreview|. When a
-// preview is set, the active view is hidden (but stays in the view hierarchy).
-// When the preview is removed, the active view is reshown.
-@interface PreviewableContentsController : NSViewController {
- @private
- // Container view for the "active" contents.
- IBOutlet NSView* activeContainer_;
-
- // The preview TabContents. Will be NULL if no preview is currently showing.
- TabContents* previewContents_; // weak
-}
-
-@property(readonly, nonatomic) NSView* activeContainer;
-
-// Sets the current preview and installs its TabContentsView into the view
-// hierarchy. Hides the active view. |preview| must not be NULL.
-- (void)showPreview:(TabContents*)preview;
-
-// Closes the current preview and shows the active view.
-- (void)hidePreview;
-
-// Returns YES if the preview contents is currently showing.
-- (BOOL)isShowingPreview;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_PREVIEWABLE_CONTENTS_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/previewable_contents_controller.mm b/chrome/browser/cocoa/previewable_contents_controller.mm
deleted file mode 100644
index 8ce042d..0000000
--- a/chrome/browser/cocoa/previewable_contents_controller.mm
+++ /dev/null
@@ -1,52 +0,0 @@
-// 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 "chrome/browser/cocoa/previewable_contents_controller.h"
-
-#include "base/logging.h"
-#include "base/mac_util.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-
-@implementation PreviewableContentsController
-
-@synthesize activeContainer = activeContainer_;
-
-- (id)init {
- if ((self = [super initWithNibName:@"PreviewableContents"
- bundle:mac_util::MainAppBundle()])) {
- }
- return self;
-}
-
-- (void)showPreview:(TabContents*)preview {
- DCHECK(preview);
-
- // Remove any old preview contents before showing the new one.
- if (previewContents_)
- [previewContents_->GetNativeView() removeFromSuperview];
-
- previewContents_ = preview;
- NSView* previewView = previewContents_->GetNativeView();
- [previewView setFrame:[[self view] bounds]];
-
- // Hide the active container and add the preview contents.
- [activeContainer_ setHidden:YES];
- [[self view] addSubview:previewView];
-}
-
-- (void)hidePreview {
- DCHECK(previewContents_);
-
- // Remove the preview contents and reshow the active container.
- [previewContents_->GetNativeView() removeFromSuperview];
- [activeContainer_ setHidden:NO];
-
- previewContents_ = nil;
-}
-
-- (BOOL)isShowingPreview {
- return previewContents_ != nil;
-}
-
-@end
diff --git a/chrome/browser/cocoa/previewable_contents_controller_unittest.mm b/chrome/browser/cocoa/previewable_contents_controller_unittest.mm
deleted file mode 100644
index 85e5c09..0000000
--- a/chrome/browser/cocoa/previewable_contents_controller_unittest.mm
+++ /dev/null
@@ -1,34 +0,0 @@
-// 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>
-
-#import "base/scoped_nsobject.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/previewable_contents_controller.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-namespace {
-
-class PreviewableContentsControllerTest : public CocoaTest {
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
- controller_.reset([[PreviewableContentsController alloc] init]);
- [[test_window() contentView] addSubview:[controller_ view]];
- }
-
- scoped_nsobject<PreviewableContentsController> controller_;
-};
-
-TEST_VIEW(PreviewableContentsControllerTest, [controller_ view])
-
-// TODO(rohitrao): Test showing and hiding the preview. This may require
-// changing the interface to take in a TabContentsView* instead of a
-// TabContents*.
-
-} // namespace
-
diff --git a/chrome/browser/cocoa/reload_button.h b/chrome/browser/cocoa/reload_button.h
deleted file mode 100644
index 6432943..0000000
--- a/chrome/browser/cocoa/reload_button.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_RELOAD_BUTTON_H_
-#define CHROME_BROWSER_COCOA_RELOAD_BUTTON_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/scoped_nsobject.h"
-
-// NSButton subclass which defers certain state changes when the mouse
-// is hovering over it.
-
-@interface ReloadButton : NSButton {
- @private
- // Tracks whether the mouse is hovering for purposes of not making
- // unexpected state changes.
- BOOL isMouseInside_;
- scoped_nsobject<NSTrackingArea> trackingArea_;
-
- // Timer used when setting reload mode while the mouse is hovered.
- scoped_nsobject<NSTimer> pendingReloadTimer_;
-}
-
-// Returns YES if the mouse is currently inside the bounds.
-- (BOOL)isMouseInside;
-
-// Update the tag, and the image and tooltip to match. If |anInt|
-// matches the current tag, no action is taken. |anInt| must be
-// either |IDC_STOP| or |IDC_RELOAD|.
-- (void)updateTag:(NSInteger)anInt;
-
-// Update the button to be a reload button or stop button depending on
-// |isLoading|. If |force|, always sets the indicated mode. If
-// |!force|, and the mouse is over the button, defer the transition
-// from stop button to reload button until the mouse has left the
-// button, or until |pendingReloadTimer_| fires. This prevents an
-// inadvertent click _just_ as the state changes.
-- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force;
-
-@end
-
-@interface ReloadButton (PrivateTestingMethods)
-+ (void)setPendingReloadTimeout:(NSTimeInterval)seconds;
-- (NSTrackingArea*)trackingArea;
-@end
-
-#endif // CHROME_BROWSER_COCOA_RELOAD_BUTTON_H_
diff --git a/chrome/browser/cocoa/reload_button.mm b/chrome/browser/cocoa/reload_button.mm
deleted file mode 100644
index 56cb3d7..0000000
--- a/chrome/browser/cocoa/reload_button.mm
+++ /dev/null
@@ -1,168 +0,0 @@
-// 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 "chrome/browser/cocoa/reload_button.h"
-
-#include "app/l10n_util.h"
-#include "app/l10n_util_mac.h"
-#include "base/nsimage_cache_mac.h"
-#include "chrome/app/chrome_command_ids.h"
-#import "chrome/browser/cocoa/gradient_button_cell.h"
-#import "chrome/browser/cocoa/view_id_util.h"
-#include "grit/generated_resources.h"
-
-namespace {
-
-NSString* const kReloadImageName = @"reload_Template.pdf";
-NSString* const kStopImageName = @"stop_Template.pdf";
-
-// Constant matches Windows.
-NSTimeInterval kPendingReloadTimeout = 1.35;
-
-} // namespace
-
-@implementation ReloadButton
-
-- (void)dealloc {
- if (trackingArea_) {
- [self removeTrackingArea:trackingArea_];
- trackingArea_.reset();
- }
- [super dealloc];
-}
-
-- (void)updateTrackingAreas {
- // If the mouse is hovering when the tracking area is updated, the
- // control could end up locked into inappropriate behavior for
- // awhile, so unwind state.
- if (isMouseInside_)
- [self mouseExited:nil];
-
- if (trackingArea_) {
- [self removeTrackingArea:trackingArea_];
- trackingArea_.reset();
- }
- trackingArea_.reset([[NSTrackingArea alloc]
- initWithRect:[self bounds]
- options:(NSTrackingMouseEnteredAndExited |
- NSTrackingActiveInActiveApp)
- owner:self
- userInfo:nil]);
- [self addTrackingArea:trackingArea_];
-}
-
-- (void)awakeFromNib {
- [self updateTrackingAreas];
-
- // Don't allow multi-clicks, because the user probably wouldn't ever
- // want to stop+reload or reload+stop.
- [self setIgnoresMultiClick:YES];
-}
-
-- (void)updateTag:(NSInteger)anInt {
- if ([self tag] == anInt)
- return;
-
- // Forcibly remove any stale tooltip which is being displayed.
- [self removeAllToolTips];
-
- [self setTag:anInt];
- if (anInt == IDC_RELOAD) {
- [self setImage:nsimage_cache::ImageNamed(kReloadImageName)];
- [self setToolTip:l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_RELOAD)];
- } else if (anInt == IDC_STOP) {
- [self setImage:nsimage_cache::ImageNamed(kStopImageName)];
- [self setToolTip:l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_STOP)];
- } else {
- NOTREACHED();
- }
-}
-
-- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force {
- // Can always transition to stop mode. Only transition to reload
- // mode if forced or if the mouse isn't hovering. Otherwise, note
- // that reload mode is desired and disable the button.
- if (isLoading) {
- pendingReloadTimer_.reset();
- [self updateTag:IDC_STOP];
- [self setEnabled:YES];
- } else if (force || ![self isMouseInside]) {
- pendingReloadTimer_.reset();
- [self updateTag:IDC_RELOAD];
-
- // This button's cell may not have received a mouseExited event, and
- // therefore it could still think that the mouse is inside the button. Make
- // sure the cell's sense of mouse-inside matches the local sense, to prevent
- // drawing artifacts.
- id cell = [self cell];
- if ([cell respondsToSelector:@selector(setMouseInside:animate:)])
- [cell setMouseInside:[self isMouseInside] animate:NO];
- [self setEnabled:YES];
- } else if ([self tag] == IDC_STOP && !pendingReloadTimer_) {
- [self setEnabled:NO];
- pendingReloadTimer_.reset(
- [[NSTimer scheduledTimerWithTimeInterval:kPendingReloadTimeout
- target:self
- selector:@selector(forceReloadState)
- userInfo:nil
- repeats:NO] retain]);
- }
-}
-
-- (void)forceReloadState {
- [self setIsLoading:NO force:YES];
-}
-
-- (BOOL)sendAction:(SEL)theAction to:(id)theTarget {
- if ([self tag] == IDC_STOP) {
- // When the timer is started, the button is disabled, so this
- // should not be possible.
- DCHECK(!pendingReloadTimer_.get());
-
- // When the stop is processed, immediately change to reload mode,
- // even though the IPC still has to bounce off the renderer and
- // back before the regular |-setIsLoaded:force:| will be called.
- // [This is how views and gtk do it.]
- const BOOL ret = [super sendAction:theAction to:theTarget];
- if (ret)
- [self forceReloadState];
- return ret;
- }
-
- return [super sendAction:theAction to:theTarget];
-}
-
-- (void)mouseEntered:(NSEvent*)theEvent {
- isMouseInside_ = YES;
-}
-
-- (void)mouseExited:(NSEvent*)theEvent {
- isMouseInside_ = NO;
-
- // Reload mode was requested during the hover.
- if (pendingReloadTimer_)
- [self forceReloadState];
-}
-
-- (BOOL)isMouseInside {
- return isMouseInside_;
-}
-
-- (ViewID)viewID {
- return VIEW_ID_RELOAD_BUTTON;
-}
-
-@end // ReloadButton
-
-@implementation ReloadButton (Testing)
-
-+ (void)setPendingReloadTimeout:(NSTimeInterval)seconds {
- kPendingReloadTimeout = seconds;
-}
-
-- (NSTrackingArea*)trackingArea {
- return trackingArea_;
-}
-
-@end
diff --git a/chrome/browser/cocoa/reload_button_unittest.mm b/chrome/browser/cocoa/reload_button_unittest.mm
deleted file mode 100644
index 617503f..0000000
--- a/chrome/browser/cocoa/reload_button_unittest.mm
+++ /dev/null
@@ -1,259 +0,0 @@
-// 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>
-
-#import "chrome/browser/cocoa/reload_button.h"
-
-#include "base/scoped_nsobject.h"
-#include "chrome/app/chrome_command_ids.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/test_event_utils.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-#import "third_party/ocmock/OCMock/OCMock.h"
-
-@protocol TargetActionMock <NSObject>
-- (void)anAction:(id)sender;
-@end
-
-namespace {
-
-class ReloadButtonTest : public CocoaTest {
- public:
- ReloadButtonTest() {
- NSRect frame = NSMakeRect(0, 0, 20, 20);
- scoped_nsobject<ReloadButton> button(
- [[ReloadButton alloc] initWithFrame:frame]);
- button_ = button.get();
-
- // Set things up so unit tests have a reliable baseline.
- [button_ setTag:IDC_RELOAD];
- [button_ awakeFromNib];
-
- [[test_window() contentView] addSubview:button_];
- }
-
- ReloadButton* button_;
-};
-
-TEST_VIEW(ReloadButtonTest, button_)
-
-// Test that mouse-tracking is setup and does the right thing.
-TEST_F(ReloadButtonTest, IsMouseInside) {
- EXPECT_TRUE([[button_ trackingAreas] containsObject:[button_ trackingArea]]);
-
- EXPECT_FALSE([button_ isMouseInside]);
- [button_ mouseEntered:nil];
- EXPECT_TRUE([button_ isMouseInside]);
- [button_ mouseExited:nil];
-}
-
-// Verify that multiple clicks do not result in multiple messages to
-// the target.
-TEST_F(ReloadButtonTest, IgnoredMultiClick) {
- id mock_target = [OCMockObject mockForProtocol:@protocol(TargetActionMock)];
- [button_ setTarget:mock_target];
- [button_ setAction:@selector(anAction:)];
-
- // Expect the action once.
- [[mock_target expect] anAction:button_];
-
- const std::pair<NSEvent*,NSEvent*> click_one =
- test_event_utils::MouseClickInView(button_, 1);
- const std::pair<NSEvent*,NSEvent*> click_two =
- test_event_utils::MouseClickInView(button_, 2);
- [NSApp postEvent:click_one.second atStart:YES];
- [button_ mouseDown:click_one.first];
- [NSApp postEvent:click_two.second atStart:YES];
- [button_ mouseDown:click_two.first];
-
- [button_ setTarget:nil];
-}
-
-TEST_F(ReloadButtonTest, UpdateTag) {
- [button_ setTag:IDC_STOP];
-
- [button_ updateTag:IDC_RELOAD];
- EXPECT_EQ(IDC_RELOAD, [button_ tag]);
- NSImage* reloadImage = [button_ image];
- NSString* const reloadToolTip = [button_ toolTip];
-
- [button_ updateTag:IDC_STOP];
- EXPECT_EQ(IDC_STOP, [button_ tag]);
- NSImage* stopImage = [button_ image];
- NSString* const stopToolTip = [button_ toolTip];
- EXPECT_NSNE(reloadImage, stopImage);
- EXPECT_NSNE(reloadToolTip, stopToolTip);
-
- [button_ updateTag:IDC_RELOAD];
- EXPECT_EQ(IDC_RELOAD, [button_ tag]);
- EXPECT_NSEQ(reloadImage, [button_ image]);
- EXPECT_NSEQ(reloadToolTip, [button_ toolTip]);
-}
-
-// Test that when forcing the mode, it takes effect immediately,
-// regardless of whether the mouse is hovering.
-TEST_F(ReloadButtonTest, SetIsLoadingForce) {
- EXPECT_FALSE([button_ isMouseInside]);
- EXPECT_EQ(IDC_RELOAD, [button_ tag]);
-
- // Changes to stop immediately.
- [button_ setIsLoading:YES force:YES];
- EXPECT_EQ(IDC_STOP, [button_ tag]);
-
- // Changes to reload immediately.
- [button_ setIsLoading:NO force:YES];
- EXPECT_EQ(IDC_RELOAD, [button_ tag]);
-
- // Changes to stop immediately when the mouse is hovered, and
- // doesn't change when the mouse exits.
- [button_ mouseEntered:nil];
- EXPECT_TRUE([button_ isMouseInside]);
- [button_ setIsLoading:YES force:YES];
- EXPECT_EQ(IDC_STOP, [button_ tag]);
- [button_ mouseExited:nil];
- EXPECT_FALSE([button_ isMouseInside]);
- EXPECT_EQ(IDC_STOP, [button_ tag]);
-
- // Changes to reload immediately when the mouse is hovered, and
- // doesn't change when the mouse exits.
- [button_ mouseEntered:nil];
- EXPECT_TRUE([button_ isMouseInside]);
- [button_ setIsLoading:NO force:YES];
- EXPECT_EQ(IDC_RELOAD, [button_ tag]);
- [button_ mouseExited:nil];
- EXPECT_FALSE([button_ isMouseInside]);
- EXPECT_EQ(IDC_RELOAD, [button_ tag]);
-}
-
-// Test that without force, stop mode is set immediately, but reload
-// is affected by the hover status.
-TEST_F(ReloadButtonTest, SetIsLoadingNoForceUnHover) {
- EXPECT_FALSE([button_ isMouseInside]);
- EXPECT_EQ(IDC_RELOAD, [button_ tag]);
-
- // Changes to stop immediately when the mouse is not hovering.
- [button_ setIsLoading:YES force:NO];
- EXPECT_EQ(IDC_STOP, [button_ tag]);
-
- // Changes to reload immediately when the mouse is not hovering.
- [button_ setIsLoading:NO force:NO];
- EXPECT_EQ(IDC_RELOAD, [button_ tag]);
-
- // Changes to stop immediately when the mouse is hovered, and
- // doesn't change when the mouse exits.
- [button_ mouseEntered:nil];
- EXPECT_TRUE([button_ isMouseInside]);
- [button_ setIsLoading:YES force:NO];
- EXPECT_EQ(IDC_STOP, [button_ tag]);
- [button_ mouseExited:nil];
- EXPECT_FALSE([button_ isMouseInside]);
- EXPECT_EQ(IDC_STOP, [button_ tag]);
-
- // Does not change to reload immediately when the mouse is hovered,
- // changes when the mouse exits.
- [button_ mouseEntered:nil];
- EXPECT_TRUE([button_ isMouseInside]);
- [button_ setIsLoading:NO force:NO];
- EXPECT_EQ(IDC_STOP, [button_ tag]);
- [button_ mouseExited:nil];
- EXPECT_FALSE([button_ isMouseInside]);
- EXPECT_EQ(IDC_RELOAD, [button_ tag]);
-}
-
-// Test that without force, stop mode is set immediately, and reload
-// will be set after a timeout.
-// TODO(shess): Reenable, http://crbug.com/61485
-TEST_F(ReloadButtonTest, DISABLED_SetIsLoadingNoForceTimeout) {
- // When the event loop first spins, some delayed tracking-area setup
- // is done, which causes -mouseExited: to be called. Spin it at
- // least once, and dequeue any pending events.
- // TODO(shess): It would be more reasonable to have an MockNSTimer
- // factory for the class to use, which this code could fire
- // directly.
- while ([NSApp nextEventMatchingMask:NSAnyEventMask
- untilDate:nil
- inMode:NSDefaultRunLoopMode
- dequeue:YES]) {
- }
-
- const NSTimeInterval kShortTimeout = 0.1;
- [ReloadButton setPendingReloadTimeout:kShortTimeout];
-
- EXPECT_FALSE([button_ isMouseInside]);
- EXPECT_EQ(IDC_RELOAD, [button_ tag]);
-
- // Move the mouse into the button and press it.
- [button_ mouseEntered:nil];
- EXPECT_TRUE([button_ isMouseInside]);
- [button_ setIsLoading:YES force:NO];
- EXPECT_EQ(IDC_STOP, [button_ tag]);
-
- // Does not change to reload immediately when the mouse is hovered.
- EXPECT_TRUE([button_ isMouseInside]);
- [button_ setIsLoading:NO force:NO];
- EXPECT_TRUE([button_ isMouseInside]);
- EXPECT_EQ(IDC_STOP, [button_ tag]);
- EXPECT_TRUE([button_ isMouseInside]);
-
- // Spin event loop until the timeout passes.
- NSDate* pastTimeout = [NSDate dateWithTimeIntervalSinceNow:2 * kShortTimeout];
- [NSApp nextEventMatchingMask:NSAnyEventMask
- untilDate:pastTimeout
- inMode:NSDefaultRunLoopMode
- dequeue:NO];
-
- // Mouse is still hovered, button is in reload mode. If the mouse
- // is no longer hovered, see comment at top of function.
- EXPECT_TRUE([button_ isMouseInside]);
- EXPECT_EQ(IDC_RELOAD, [button_ tag]);
-}
-
-// Test that pressing stop after reload mode has been requested
-// doesn't forward the stop message.
-TEST_F(ReloadButtonTest, StopAfterReloadSet) {
- id mock_target = [OCMockObject mockForProtocol:@protocol(TargetActionMock)];
- [button_ setTarget:mock_target];
- [button_ setAction:@selector(anAction:)];
-
- EXPECT_FALSE([button_ isMouseInside]);
-
- // Get to stop mode.
- [button_ setIsLoading:YES force:YES];
- EXPECT_EQ(IDC_STOP, [button_ tag]);
- EXPECT_TRUE([button_ isEnabled]);
-
- // Expect the action once.
- [[mock_target expect] anAction:button_];
-
- // Clicking in stop mode should send the action and transition to
- // reload mode.
- const std::pair<NSEvent*,NSEvent*> click =
- test_event_utils::MouseClickInView(button_, 1);
- [NSApp postEvent:click.second atStart:YES];
- [button_ mouseDown:click.first];
- EXPECT_EQ(IDC_RELOAD, [button_ tag]);
- EXPECT_TRUE([button_ isEnabled]);
-
- // Get back to stop mode.
- [button_ setIsLoading:YES force:YES];
- EXPECT_EQ(IDC_STOP, [button_ tag]);
- EXPECT_TRUE([button_ isEnabled]);
-
- // If hover prevented reload mode immediately taking effect, clicks should do
- // nothing, because the button should be disabled.
- [button_ mouseEntered:nil];
- EXPECT_TRUE([button_ isMouseInside]);
- [button_ setIsLoading:NO force:NO];
- EXPECT_EQ(IDC_STOP, [button_ tag]);
- EXPECT_FALSE([button_ isEnabled]);
- [NSApp postEvent:click.second atStart:YES];
- [button_ mouseDown:click.first];
- EXPECT_EQ(IDC_STOP, [button_ tag]);
-
- [button_ setTarget:nil];
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/repost_form_warning_mac.h b/chrome/browser/cocoa/repost_form_warning_mac.h
deleted file mode 100644
index 25f3f3e..0000000
--- a/chrome/browser/cocoa/repost_form_warning_mac.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_REPOST_FORM_WARNING_MAC_H_
-#define CHROME_BROWSER_COCOA_REPOST_FORM_WARNING_MAC_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_ptr.h"
-#include "chrome/browser/cocoa/constrained_window_mac.h"
-
-class RepostFormWarningController;
-
-// Displays a dialog that warns the user that they are about to resubmit
-// a form. To show the dialog, call the |Create| method. It will open the
-// dialog and then delete itself when the user dismisses the dialog.
-class RepostFormWarningMac : public ConstrainedDialogDelegate {
- public:
- // Convenience method that creates a new |RepostFormWarningController| and
- // then a new |RepostFormWarningMac| from that.
- static RepostFormWarningMac* Create(NSWindow* parent,
- TabContents* tab_contents);
-
- RepostFormWarningMac(NSWindow* parent,
- RepostFormWarningController* controller);
-
- // ConstrainedWindowDelegateMacSystemSheet methods:
- virtual void DeleteDelegate();
-
- private:
- virtual ~RepostFormWarningMac();
-
- scoped_ptr<RepostFormWarningController> controller_;
-
- DISALLOW_COPY_AND_ASSIGN(RepostFormWarningMac);
-};
-
-#endif // CHROME_BROWSER_COCOA_REPOST_FORM_WARNING_MAC_H_
diff --git a/chrome/browser/cocoa/repost_form_warning_mac.mm b/chrome/browser/cocoa/repost_form_warning_mac.mm
deleted file mode 100644
index e8876c7..0000000
--- a/chrome/browser/cocoa/repost_form_warning_mac.mm
+++ /dev/null
@@ -1,82 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/repost_form_warning_mac.h"
-
-#include "app/l10n_util_mac.h"
-#include "base/scoped_nsobject.h"
-#include "chrome/browser/repost_form_warning_controller.h"
-#include "grit/generated_resources.h"
-
-// The delegate of the NSAlert used to display the dialog. Forwards the alert's
-// completion event to the C++ class |RepostFormWarningController|.
-@interface RepostDelegate : NSObject {
- RepostFormWarningController* warning_; // weak
-}
-- (id)initWithWarning:(RepostFormWarningController*)warning;
-- (void)alertDidEnd:(NSAlert*)alert
- returnCode:(int)returnCode
- contextInfo:(void*)contextInfo;
-@end
-
-@implementation RepostDelegate
-- (id)initWithWarning:(RepostFormWarningController*)warning {
- if ((self = [super init])) {
- warning_ = warning;
- }
- return self;
-}
-
-- (void)alertDidEnd:(NSAlert*)alert
- returnCode:(int)returnCode
- contextInfo:(void*)contextInfo {
- if (returnCode == NSAlertFirstButtonReturn) {
- warning_->Continue();
- } else {
- warning_->Cancel();
- }
-}
-@end
-
-RepostFormWarningMac* RepostFormWarningMac::Create(NSWindow* parent,
- TabContents* tab_contents) {
- return new RepostFormWarningMac(
- parent,
- new RepostFormWarningController(tab_contents));
-}
-
-RepostFormWarningMac::RepostFormWarningMac(
- NSWindow* parent,
- RepostFormWarningController* controller)
- : ConstrainedWindowMacDelegateSystemSheet(
- [[[RepostDelegate alloc] initWithWarning:controller]
- autorelease],
- @selector(alertDidEnd:returnCode:contextInfo:)),
- controller_(controller) {
- scoped_nsobject<NSAlert> alert([[NSAlert alloc] init]);
- [alert setMessageText:
- l10n_util::GetNSStringWithFixup(IDS_HTTP_POST_WARNING_TITLE)];
- [alert setInformativeText:
- l10n_util::GetNSStringWithFixup(IDS_HTTP_POST_WARNING)];
- [alert addButtonWithTitle:
- l10n_util::GetNSStringWithFixup(IDS_HTTP_POST_WARNING_RESEND)];
- [alert addButtonWithTitle:
- l10n_util::GetNSStringWithFixup(IDS_CANCEL)];
-
- set_sheet(alert);
-
- controller->Show(this);
-}
-
-RepostFormWarningMac::~RepostFormWarningMac() {
- NSWindow* window = [(NSAlert*)sheet() window];
- if (window && is_sheet_open()) {
- [NSApp endSheet:window
- returnCode:NSAlertSecondButtonReturn];
- }
-}
-
-void RepostFormWarningMac::DeleteDelegate() {
- delete this;
-}
diff --git a/chrome/browser/cocoa/restart_browser.h b/chrome/browser/cocoa/restart_browser.h
deleted file mode 100644
index 73d6562..0000000
--- a/chrome/browser/cocoa/restart_browser.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_RESTART_BROWSER_H_
-#define CHROME_BROWSER_COCOA_RESTART_BROWSER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-// This is a functional match for chrome/browser/views/restart_message_box
-// so any code that needs to ask for a browser restart has something like what
-// the Windows code has.
-namespace restart_browser {
-
-// Puts up an alert telling the user to restart their browser. The alert
-// will be hung off |parent| or global otherise.
-void RequestRestart(NSWindow* parent);
-
-} // namespace restart_browser
-
-#endif // CHROME_BROWSER_COCOA_RESTART_BROWSER_H_
diff --git a/chrome/browser/cocoa/restart_browser.mm b/chrome/browser/cocoa/restart_browser.mm
deleted file mode 100644
index db1dc16..0000000
--- a/chrome/browser/cocoa/restart_browser.mm
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/restart_browser.h"
-
-#include "app/l10n_util.h"
-#include "app/l10n_util_mac.h"
-#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/common/pref_names.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-#include "grit/app_strings.h"
-
-// Helper to clean up after the notification that the alert was dismissed.
-@interface RestartHelper : NSObject {
- @private
- NSAlert* alert_;
-}
-- (NSAlert*)alert;
-- (void)alertDidEnd:(NSAlert*)alert
- returnCode:(int)returnCode
- contextInfo:(void*)contextInfo;
-@end
-
-@implementation RestartHelper
-
-- (NSAlert*)alert {
- alert_ = [[NSAlert alloc] init];
- return alert_;
-}
-
-- (void)dealloc {
- [alert_ release];
- [super dealloc];
-}
-
-- (void)alertDidEnd:(NSAlert*)alert
- returnCode:(int)returnCode
- contextInfo:(void*)contextInfo {
- if (returnCode == NSAlertFirstButtonReturn) {
- // Nothing to do. User will restart later.
- } else if (returnCode == NSAlertSecondButtonReturn) {
- // Set the flag to restore state after the restart.
- PrefService* pref_service = g_browser_process->local_state();
- pref_service->SetBoolean(prefs::kRestartLastSessionOnShutdown, true);
- BrowserList::CloseAllBrowsersAndExit();
- } else {
- NOTREACHED();
- }
- [self autorelease];
-}
-
-@end
-
-namespace restart_browser {
-
-void RequestRestart(NSWindow* parent) {
- NSString* title =
- l10n_util::GetNSStringFWithFixup(IDS_PLEASE_RESTART_BROWSER,
- l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
- NSString* text =
- l10n_util::GetNSStringFWithFixup(IDS_UPDATE_RECOMMENDED,
- l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
- NSString* notNowButtin = l10n_util::GetNSStringWithFixup(IDS_NOT_NOW);
- NSString* restartButton =
- l10n_util::GetNSStringWithFixup(IDS_RESTART_AND_UPDATE);
-
- RestartHelper* helper = [[RestartHelper alloc] init];
-
- NSAlert* alert = [helper alert];
- [alert setAlertStyle:NSInformationalAlertStyle];
- [alert setMessageText:title];
- [alert setInformativeText:text];
- [alert addButtonWithTitle:notNowButtin];
- [alert addButtonWithTitle:restartButton];
-
- [alert beginSheetModalForWindow:parent
- modalDelegate:helper
- didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
- contextInfo:nil];
-}
-
-} // namespace restart_browser
diff --git a/chrome/browser/cocoa/rwhvm_editcommand_helper.h b/chrome/browser/cocoa/rwhvm_editcommand_helper.h
deleted file mode 100644
index 706f8a0..0000000
--- a/chrome/browser/cocoa/rwhvm_editcommand_helper.h
+++ /dev/null
@@ -1,72 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_RWHVM_EDITCOMMAND_HELPER_H_
-#define CHROME_BROWSER_COCOA_RWHVM_EDITCOMMAND_HELPER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/basictypes.h"
-#include "base/hash_tables.h"
-#include "base/gtest_prod_util.h"
-#include "chrome/browser/renderer_host/render_widget_host_view_mac.h"
-
-// RenderWidgetHostViewMacEditCommandHelper is the real name of this class
-// but that's too long, so we use a shorter version.
-//
-// This class mimics the behavior of WebKit's WebView class in a way that makes
-// sense for Chrome.
-//
-// WebCore has the concept of "core commands", basically named actions such as
-// "Select All" and "Move Cursor Left". The commands are executed using their
-// string value by WebCore.
-//
-// This class is responsible for 2 things:
-// 1. Provide an abstraction to determine the enabled/disabled state of menu
-// items that correspond to edit commands.
-// 2. Hook up a bunch of objc selectors to the RenderWidgetHostViewCocoa object.
-// (note that this is not a misspelling of RenderWidgetHostViewMac, it's in
-// fact a distinct object) When these selectors are called, the relevant
-// edit command is executed in WebCore.
-class RWHVMEditCommandHelper {
- FRIEND_TEST_ALL_PREFIXES(RWHVMEditCommandHelperTest,
- TestAddEditingSelectorsToClass);
- FRIEND_TEST_ALL_PREFIXES(RWHVMEditCommandHelperTest,
- TestEditingCommandDelivery);
-
- public:
- RWHVMEditCommandHelper();
-
- // Adds editing selectors to the objc class using the objc runtime APIs.
- // Each selector is connected to a single c method which forwards the message
- // to WebCore's ExecuteEditCommand() function.
- // This method is idempotent.
- // The class passed in must conform to the RenderWidgetHostViewMacOwner
- // protocol.
- void AddEditingSelectorsToClass(Class klass);
-
- // Is a given menu item currently enabled?
- // SEL - the objc selector currently associated with an NSMenuItem.
- // owner - An object we can retrieve a RenderWidgetHostViewMac from to
- // determine the command states.
- bool IsMenuItemEnabled(SEL item_action,
- id<RenderWidgetHostViewMacOwner> owner);
-
- // Converts an editing selector into a command name that can be sent to
- // webkit.
- static NSString* CommandNameForSelector(SEL selector);
-
- protected:
- // Gets a list of all the selectors that AddEditingSelectorsToClass adds to
- // the aforementioned class.
- // returns an array of NSStrings WITHOUT the trailing ':'s.
- NSArray* GetEditSelectorNames();
-
- private:
- base::hash_set<std::string> edit_command_set_;
- DISALLOW_COPY_AND_ASSIGN(RWHVMEditCommandHelper);
-};
-
-#endif // CHROME_BROWSER_COCOA_RWHVM_EDITCOMMAND_HELPER_H_
diff --git a/chrome/browser/cocoa/rwhvm_editcommand_helper.mm b/chrome/browser/cocoa/rwhvm_editcommand_helper.mm
deleted file mode 100644
index 3665984..0000000
--- a/chrome/browser/cocoa/rwhvm_editcommand_helper.mm
+++ /dev/null
@@ -1,227 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/rwhvm_editcommand_helper.h"
-
-#import <objc/runtime.h>
-
-#include "chrome/browser/renderer_host/render_widget_host.h"
-#import "chrome/browser/renderer_host/render_widget_host_view_mac.h"
-
-namespace {
-// The names of all the objc selectors w/o ':'s added to an object by
-// AddEditingSelectorsToClass().
-//
-// This needs to be kept in Sync with WEB_COMMAND list in the WebKit tree at:
-// WebKit/mac/WebView/WebHTMLView.mm .
-const char* kEditCommands[] = {
- "alignCenter",
- "alignJustified",
- "alignLeft",
- "alignRight",
- "copy",
- "cut",
- "delete",
- "deleteBackward",
- "deleteBackwardByDecomposingPreviousCharacter",
- "deleteForward",
- "deleteToBeginningOfLine",
- "deleteToBeginningOfParagraph",
- "deleteToEndOfLine",
- "deleteToEndOfParagraph",
- "deleteToMark",
- "deleteWordBackward",
- "deleteWordForward",
- "ignoreSpelling",
- "indent",
- "insertBacktab",
- "insertLineBreak",
- "insertNewline",
- "insertNewlineIgnoringFieldEditor",
- "insertParagraphSeparator",
- "insertTab",
- "insertTabIgnoringFieldEditor",
- "makeTextWritingDirectionLeftToRight",
- "makeTextWritingDirectionNatural",
- "makeTextWritingDirectionRightToLeft",
- "moveBackward",
- "moveBackwardAndModifySelection",
- "moveDown",
- "moveDownAndModifySelection",
- "moveForward",
- "moveForwardAndModifySelection",
- "moveLeft",
- "moveLeftAndModifySelection",
- "moveParagraphBackwardAndModifySelection",
- "moveParagraphForwardAndModifySelection",
- "moveRight",
- "moveRightAndModifySelection",
- "moveToBeginningOfDocument",
- "moveToBeginningOfDocumentAndModifySelection",
- "moveToBeginningOfLine",
- "moveToBeginningOfLineAndModifySelection",
- "moveToBeginningOfParagraph",
- "moveToBeginningOfParagraphAndModifySelection",
- "moveToBeginningOfSentence",
- "moveToBeginningOfSentenceAndModifySelection",
- "moveToEndOfDocument",
- "moveToEndOfDocumentAndModifySelection",
- "moveToEndOfLine",
- "moveToEndOfLineAndModifySelection",
- "moveToEndOfParagraph",
- "moveToEndOfParagraphAndModifySelection",
- "moveToEndOfSentence",
- "moveToEndOfSentenceAndModifySelection",
- "moveUp",
- "moveUpAndModifySelection",
- "moveWordBackward",
- "moveWordBackwardAndModifySelection",
- "moveWordForward",
- "moveWordForwardAndModifySelection",
- "moveWordLeft",
- "moveWordLeftAndModifySelection",
- "moveWordRight",
- "moveWordRightAndModifySelection",
- "outdent",
- "pageDown",
- "pageDownAndModifySelection",
- "pageUp",
- "pageUpAndModifySelection",
- "selectAll",
- "selectLine",
- "selectParagraph",
- "selectSentence",
- "selectToMark",
- "selectWord",
- "setMark",
- "showGuessPanel",
- "subscript",
- "superscript",
- "swapWithMark",
- "transpose",
- "underline",
- "unscript",
- "yank",
- "yankAndSelect"};
-
-
-// This function is installed via the objc runtime as the implementation of all
-// the various editing selectors.
-// The objc runtime hookup occurs in
-// RWHVMEditCommandHelper::AddEditingSelectorsToClass().
-//
-// self - the object we're attached to; it must implement the
-// RenderWidgetHostViewMacOwner protocol.
-// _cmd - the selector that fired.
-// sender - the id of the object that sent the message.
-//
-// The selector is translated into an edit comand and then forwarded down the
-// pipeline to WebCore.
-// The route the message takes is:
-// RenderWidgetHostViewMac -> RenderViewHost ->
-// | IPC | ->
-// RenderView -> currently focused WebFrame.
-// The WebFrame is in the Chrome glue layer and forwards the message to WebCore.
-void EditCommandImp(id self, SEL _cmd, id sender) {
- // Make sure |self| is the right type.
- DCHECK([self conformsToProtocol:@protocol(RenderWidgetHostViewMacOwner)]);
-
- // SEL -> command name string.
- NSString* command_name_ns =
- RWHVMEditCommandHelper::CommandNameForSelector(_cmd);
- std::string edit_command([command_name_ns UTF8String]);
-
- // Forward the edit command string down the pipeline.
- RenderWidgetHostViewMac* rwhv = [(id<RenderWidgetHostViewMacOwner>)self
- renderWidgetHostViewMac];
- DCHECK(rwhv);
-
- // The second parameter is the core command value which isn't used here.
- rwhv->GetRenderWidgetHost()->ForwardEditCommand(edit_command, "");
-}
-
-} // namespace
-
-// Maps an objc-selector to a core command name.
-//
-// Returns the core command name (which is the selector name with the trailing
-// ':' stripped in most cases).
-//
-// Adapted from a function by the same name in
-// WebKit/mac/WebView/WebHTMLView.mm .
-// Capitalized names are returned from this function, but that's simply
-// matching WebHTMLView.mm.
-NSString* RWHVMEditCommandHelper::CommandNameForSelector(SEL selector) {
- if (selector == @selector(insertParagraphSeparator:) ||
- selector == @selector(insertNewlineIgnoringFieldEditor:))
- return @"InsertNewline";
- if (selector == @selector(insertTabIgnoringFieldEditor:))
- return @"InsertTab";
- if (selector == @selector(pageDown:))
- return @"MovePageDown";
- if (selector == @selector(pageDownAndModifySelection:))
- return @"MovePageDownAndModifySelection";
- if (selector == @selector(pageUp:))
- return @"MovePageUp";
- if (selector == @selector(pageUpAndModifySelection:))
- return @"MovePageUpAndModifySelection";
-
- // Remove the trailing colon.
- NSString* selector_str = NSStringFromSelector(selector);
- int selector_len = [selector_str length];
- return [selector_str substringToIndex:selector_len - 1];
-}
-
-RWHVMEditCommandHelper::RWHVMEditCommandHelper() {
- for (size_t i = 0; i < arraysize(kEditCommands); ++i) {
- edit_command_set_.insert(kEditCommands[i]);
- }
-}
-
-// Dynamically adds Selectors to the aformentioned class.
-void RWHVMEditCommandHelper::AddEditingSelectorsToClass(Class klass) {
- for (size_t i = 0; i < arraysize(kEditCommands); ++i) {
- // Append trailing ':' to command name to get selector name.
- NSString* sel_str = [NSString stringWithFormat: @"%s:", kEditCommands[i]];
-
- SEL edit_selector = NSSelectorFromString(sel_str);
- // May want to use @encode() for the last parameter to this method.
- // If class_addMethod fails we assume that all the editing selectors where
- // added to the class.
- // If a certain class already implements a method then class_addMethod
- // returns NO, which we can safely ignore.
- class_addMethod(klass, edit_selector, (IMP)EditCommandImp, "v@:@");
- }
-}
-
-bool RWHVMEditCommandHelper::IsMenuItemEnabled(SEL item_action,
- id<RenderWidgetHostViewMacOwner> owner) {
- const char* selector_name = sel_getName(item_action);
- // TODO(jeremy): The final form of this function will check state
- // associated with the Browser.
-
- // For now just mark all edit commands as enabled.
- NSString* selector_name_ns = [NSString stringWithUTF8String:selector_name];
-
- // Remove trailing ':'
- size_t str_len = [selector_name_ns length];
- selector_name_ns = [selector_name_ns substringToIndex:str_len - 1];
- std::string edit_command_name([selector_name_ns UTF8String]);
-
- // search for presence in set and return.
- bool ret = edit_command_set_.find(edit_command_name) !=
- edit_command_set_.end();
- return ret;
-}
-
-NSArray* RWHVMEditCommandHelper::GetEditSelectorNames() {
- size_t num_edit_commands = arraysize(kEditCommands);
- NSMutableArray* ret = [NSMutableArray arrayWithCapacity:num_edit_commands];
-
- for (size_t i = 0; i < num_edit_commands; ++i) {
- [ret addObject:[NSString stringWithUTF8String:kEditCommands[i]]];
- }
-
- return ret;
-}
diff --git a/chrome/browser/cocoa/rwhvm_editcommand_helper_unittest.mm b/chrome/browser/cocoa/rwhvm_editcommand_helper_unittest.mm
deleted file mode 100644
index 4fd5452..0000000
--- a/chrome/browser/cocoa/rwhvm_editcommand_helper_unittest.mm
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/rwhvm_editcommand_helper.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include "chrome/browser/renderer_host/mock_render_process_host.h"
-#include "chrome/browser/renderer_host/render_widget_host.h"
-#include "chrome/test/testing_profile.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-class RWHVMEditCommandHelperTest : public PlatformTest {
-};
-
-// Bare bones obj-c class for testing purposes.
-@interface RWHVMEditCommandHelperTestClass : NSObject
-@end
-
-@implementation RWHVMEditCommandHelperTestClass
-@end
-
-// Class that owns a RenderWidgetHostViewMac.
-@interface RenderWidgetHostViewMacOwner :
- NSObject<RenderWidgetHostViewMacOwner> {
- RenderWidgetHostViewMac* rwhvm_;
-}
-
-- (id) initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)rwhvm;
-@end
-
-@implementation RenderWidgetHostViewMacOwner
-
-- (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)rwhvm {
- if ((self = [super init])) {
- rwhvm_ = rwhvm;
- }
- return self;
-}
-
-- (RenderWidgetHostViewMac*)renderWidgetHostViewMac {
- return rwhvm_;
-}
-
-@end
-
-
-namespace {
- // Returns true if all the edit command names in the array are present
- // in test_obj.
- // edit_commands is a list of NSStrings, selector names are formed by
- // appending a trailing ':' to the string.
- bool CheckObjectRespondsToEditCommands(NSArray* edit_commands, id test_obj) {
- for (NSString* edit_command_name in edit_commands) {
- NSString* sel_str = [edit_command_name stringByAppendingString:@":"];
- if (![test_obj respondsToSelector:NSSelectorFromString(sel_str)]) {
- return false;
- }
- }
-
- return true;
- }
-} // namespace
-
-// Create a Mock RenderWidget
-class MockRenderWidgetHostEditCommandCounter : public RenderWidgetHost {
- public:
- MockRenderWidgetHostEditCommandCounter(RenderProcessHost* process,
- int routing_id) :
- RenderWidgetHost(process, routing_id) {}
-
- MOCK_METHOD2(ForwardEditCommand, void(const std::string&,
- const std::string&));
-};
-
-
-// Tests that editing commands make it through the pipeline all the way to
-// RenderWidgetHost.
-TEST_F(RWHVMEditCommandHelperTest, TestEditingCommandDelivery) {
- RWHVMEditCommandHelper helper;
- NSArray* edit_command_strings = helper.GetEditSelectorNames();
-
- // Set up a mock render widget and set expectations.
- MessageLoopForUI message_loop;
- TestingProfile profile;
- MockRenderProcessHost mock_process(&profile);
- MockRenderWidgetHostEditCommandCounter mock_render_widget(&mock_process, 0);
-
- size_t num_edit_commands = [edit_command_strings count];
- EXPECT_CALL(mock_render_widget,
- ForwardEditCommand(testing::_, testing::_)).Times(num_edit_commands);
-
-// TODO(jeremy): Figure this out and reenable this test.
-// For some bizarre reason this code doesn't work, running the code in the
-// debugger confirms that the function is called with the correct parameters
-// however gmock appears not to be able to match up parameters correctly.
-// Disable for now till we can figure this out.
-#if 0
- // Tell Mock object that we expect to recieve each edit command once.
- std::string empty_str;
- for (NSString* edit_command_name in edit_command_strings) {
- std::string command([edit_command_name UTF8String]);
- EXPECT_CALL(mock_render_widget,
- ForwardEditCommand(command, empty_str)).Times(1);
- }
-#endif // 0
-
- // RenderWidgetHostViewMac self destructs (RenderWidgetHostViewMacCocoa
- // takes ownership) so no need to delete it ourselves.
- RenderWidgetHostViewMac* rwhvm = new RenderWidgetHostViewMac(
- &mock_render_widget);
-
- RenderWidgetHostViewMacOwner* rwhwvm_owner =
- [[[RenderWidgetHostViewMacOwner alloc]
- initWithRenderWidgetHostViewMac:rwhvm] autorelease];
-
- helper.AddEditingSelectorsToClass([rwhwvm_owner class]);
-
- for (NSString* edit_command_name in edit_command_strings) {
- NSString* sel_str = [edit_command_name stringByAppendingString:@":"];
- [rwhwvm_owner performSelector:NSSelectorFromString(sel_str) withObject:nil];
- }
-}
-
-// Test RWHVMEditCommandHelper::AddEditingSelectorsToClass
-TEST_F(RWHVMEditCommandHelperTest, TestAddEditingSelectorsToClass) {
- RWHVMEditCommandHelper helper;
- NSArray* edit_command_strings = helper.GetEditSelectorNames();
- ASSERT_GT([edit_command_strings count], 0U);
-
- // Create a class instance and add methods to the class.
- RWHVMEditCommandHelperTestClass* test_obj =
- [[[RWHVMEditCommandHelperTestClass alloc] init] autorelease];
-
- // Check that edit commands aren't already attached to the object.
- ASSERT_FALSE(CheckObjectRespondsToEditCommands(edit_command_strings,
- test_obj));
-
- helper.AddEditingSelectorsToClass([test_obj class]);
-
- // Check that all edit commands where added.
- ASSERT_TRUE(CheckObjectRespondsToEditCommands(edit_command_strings,
- test_obj));
-
- // AddEditingSelectorsToClass() should be idempotent.
- helper.AddEditingSelectorsToClass([test_obj class]);
-
- // Check that all edit commands are still there.
- ASSERT_TRUE(CheckObjectRespondsToEditCommands(edit_command_strings,
- test_obj));
-}
-
-// Test RWHVMEditCommandHelper::IsMenuItemEnabled.
-TEST_F(RWHVMEditCommandHelperTest, TestMenuItemEnabling) {
- RWHVMEditCommandHelper helper;
- RenderWidgetHostViewMacOwner* rwhvm_owner =
- [[[RenderWidgetHostViewMacOwner alloc] init] autorelease];
-
- // The select all menu should always be enabled.
- SEL select_all = NSSelectorFromString(@"selectAll:");
- ASSERT_TRUE(helper.IsMenuItemEnabled(select_all, rwhvm_owner));
-
- // Random selectors should be enabled by the function.
- SEL garbage_selector = NSSelectorFromString(@"randomGarbageSelector:");
- ASSERT_FALSE(helper.IsMenuItemEnabled(garbage_selector, rwhvm_owner));
-
- // TODO(jeremy): Currently IsMenuItemEnabled just returns true for all edit
- // selectors. Once we go past that we should do more extensive testing here.
-}
diff --git a/chrome/browser/cocoa/sad_tab_controller.h b/chrome/browser/cocoa/sad_tab_controller.h
deleted file mode 100644
index b348710..0000000
--- a/chrome/browser/cocoa/sad_tab_controller.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_SAD_TAB_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_SAD_TAB_CONTROLLER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-class TabContents;
-
-// A controller class that manages the SadTabView (aka "Aw Snap" or crash page).
-@interface SadTabController : NSViewController {
- @private
- TabContents* tabContents_; // Weak reference.
-}
-
-// Designated initializer is initWithTabContents.
-- (id)initWithTabContents:(TabContents*)someTabContents
- superview:(NSView*)superview;
-
-// This action just calls the NSApp sendAction to get it into the standard
-// Cocoa action processing.
-- (IBAction)openLearnMoreAboutCrashLink:(id)sender;
-
-// Returns a weak reference to the TabContents whose TabContentsView created
-// this SadTabController.
-- (TabContents*)tabContents;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_SAD_TAB_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/sad_tab_controller.mm b/chrome/browser/cocoa/sad_tab_controller.mm
deleted file mode 100644
index c0c832a..0000000
--- a/chrome/browser/cocoa/sad_tab_controller.mm
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/sad_tab_controller.h"
-
-#include "base/mac_util.h"
-#import "chrome/browser/cocoa/sad_tab_view.h"
-
-@implementation SadTabController
-
-- (id)initWithTabContents:(TabContents*)someTabContents
- superview:(NSView*)superview {
- if ((self = [super initWithNibName:@"SadTab"
- bundle:mac_util::MainAppBundle()])) {
- tabContents_ = someTabContents;
-
- NSView* view = [self view];
- [superview addSubview:view];
- [view setFrame:[superview bounds]];
- }
-
- return self;
-}
-
-- (void)awakeFromNib {
- // If tab_contents_ is nil, ask view to remove link.
- if (!tabContents_) {
- SadTabView* sad_view = static_cast<SadTabView*>([self view]);
- [sad_view removeLinkButton];
- }
-}
-
-- (void)dealloc {
- [[self view] removeFromSuperview];
- [super dealloc];
-}
-
-- (TabContents*)tabContents {
- return tabContents_;
-}
-
-- (void)openLearnMoreAboutCrashLink:(id)sender {
- // Send the action up through the responder chain.
- [NSApp sendAction:@selector(openLearnMoreAboutCrashLink:) to:nil from:self];
-}
-
-@end
diff --git a/chrome/browser/cocoa/sad_tab_controller_unittest.mm b/chrome/browser/cocoa/sad_tab_controller_unittest.mm
deleted file mode 100644
index 7797397..0000000
--- a/chrome/browser/cocoa/sad_tab_controller_unittest.mm
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright (c) 2009 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/debug/debugger.h"
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/sad_tab_controller.h"
-#import "chrome/browser/cocoa/sad_tab_view.h"
-#include "chrome/browser/renderer_host/test/test_render_view_host.h"
-#include "chrome/browser/tab_contents/test_tab_contents.h"
-#include "chrome/test/testing_profile.h"
-
-@interface SadTabView (ExposedForTesting)
-// Implementation is below.
-- (NSButton*)linkButton;
-@end
-
-@implementation SadTabView (ExposedForTesting)
-- (NSButton*)linkButton {
- return linkButton_;
-}
-@end
-
-namespace {
-
-class SadTabControllerTest : public RenderViewHostTestHarness {
- public:
- SadTabControllerTest() : test_window_(nil) {
- link_clicked_ = false;
- }
-
- virtual void SetUp() {
- RenderViewHostTestHarness::SetUp();
- // Inherting from RenderViewHostTestHarness means we can't inherit from
- // from CocoaTest, so do a bootstrap and create test window.
- CocoaTest::BootstrapCocoa();
- test_window_ = [[CocoaTestHelperWindow alloc] init];
- if (base::debug::BeingDebugged()) {
- [test_window_ orderFront:nil];
- } else {
- [test_window_ orderBack:nil];
- }
- }
-
- virtual void TearDown() {
- [test_window_ close];
- test_window_ = nil;
- RenderViewHostTestHarness::TearDown();
- }
-
- // Creates the controller and adds its view to contents, caller has ownership.
- SadTabController* CreateController() {
- NSView* contentView = [test_window_ contentView];
- SadTabController* controller =
- [[SadTabController alloc] initWithTabContents:contents()
- superview:contentView];
- EXPECT_TRUE(controller);
- NSView* view = [controller view];
- EXPECT_TRUE(view);
-
- return controller;
- }
-
- NSButton* GetLinkButton(SadTabController* controller) {
- SadTabView* view = static_cast<SadTabView*>([controller view]);
- return ([view linkButton]);
- }
-
- static bool link_clicked_;
- CocoaTestHelperWindow* test_window_;
-};
-
-// static
-bool SadTabControllerTest::link_clicked_;
-
-TEST_F(SadTabControllerTest, WithTabContents) {
- scoped_nsobject<SadTabController> controller(CreateController());
- EXPECT_TRUE(controller);
- NSButton* link = GetLinkButton(controller);
- EXPECT_TRUE(link);
-}
-
-TEST_F(SadTabControllerTest, WithoutTabContents) {
- contents_.reset();
- scoped_nsobject<SadTabController> controller(CreateController());
- EXPECT_TRUE(controller);
- NSButton* link = GetLinkButton(controller);
- EXPECT_FALSE(link);
-}
-
-TEST_F(SadTabControllerTest, ClickOnLink) {
- scoped_nsobject<SadTabController> controller(CreateController());
- NSButton* link = GetLinkButton(controller);
- EXPECT_TRUE(link);
- EXPECT_FALSE(link_clicked_);
- [link performClick:link];
- EXPECT_TRUE(link_clicked_);
-}
-
-} // namespace
-
-@implementation NSApplication (SadTabControllerUnitTest)
-// Add handler for the openLearnMoreAboutCrashLink: action to NSApp for testing
-// purposes. Normally this would be sent up the responder tree correctly, but
-// since tests run in the background, key window and main window are never set
-// on NSApplication. Adding it to NSApplication directly removes the need for
-// worrying about what the current window with focus is.
-- (void)openLearnMoreAboutCrashLink:(id)sender {
- SadTabControllerTest::link_clicked_ = true;
-}
-
-@end
diff --git a/chrome/browser/cocoa/sad_tab_view.h b/chrome/browser/cocoa/sad_tab_view.h
deleted file mode 100644
index 7713c72..0000000
--- a/chrome/browser/cocoa/sad_tab_view.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_SAD_TAB_VIEW_H_
-#define CHROME_BROWSER_COCOA_SAD_TAB_VIEW_H_
-#pragma once
-
-#include "base/scoped_nsobject.h"
-#include "chrome/browser/cocoa/base_view.h"
-
-#import <Cocoa/Cocoa.h>
-
-@class HyperlinkButtonCell;
-
-// A view that displays the "sad tab" (aka crash page).
-@interface SadTabView : BaseView {
- @private
- IBOutlet NSImageView* image_;
- IBOutlet NSTextField* title_;
- IBOutlet NSTextField* message_;
- IBOutlet NSButton* linkButton_;
- IBOutlet HyperlinkButtonCell* linkCell_;
-
- scoped_nsobject<NSColor> backgroundColor_;
- NSSize messageSize_;
-}
-
-// Designated initializer is -initWithFrame: .
-
-// Called by SadTabController to remove link button.
-- (void)removeLinkButton;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_SAD_TAB_VIEW_H_
diff --git a/chrome/browser/cocoa/sad_tab_view.mm b/chrome/browser/cocoa/sad_tab_view.mm
deleted file mode 100644
index 7b86200..0000000
--- a/chrome/browser/cocoa/sad_tab_view.mm
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/sad_tab_view.h"
-
-#include "app/resource_bundle.h"
-#include "base/logging.h"
-#import "chrome/browser/cocoa/hyperlink_button_cell.h"
-#include "grit/theme_resources.h"
-#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-
-// Offset above vertical middle of page where contents of page start.
-static const CGFloat kSadTabOffset = -64;
-// Padding between icon and title.
-static const CGFloat kIconTitleSpacing = 20;
-// Padding between title and message.
-static const CGFloat kTitleMessageSpacing = 15;
-// Padding between message and link.
-static const CGFloat kMessageLinkSpacing = 15;
-// Paddings on left and right of page.
-static const CGFloat kTabHorzMargin = 13;
-
-@implementation SadTabView
-
-- (void)awakeFromNib {
- // Load resource for image and set it.
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- NSImage* image = rb.GetNativeImageNamed(IDR_SAD_TAB);
- DCHECK(image);
- [image_ setImage:image];
-
- // Set font for title.
- NSFont* titleFont = [NSFont boldSystemFontOfSize:[NSFont systemFontSize]];
- [title_ setFont:titleFont];
-
- // Set font for message.
- NSFont* messageFont = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
- [message_ setFont:messageFont];
-
- // If necessary, set font and color for link.
- if (linkButton_) {
- [linkButton_ setFont:messageFont];
- [linkCell_ setTextColor:[NSColor whiteColor]];
- }
-
- // Initialize background color.
- NSColor* backgroundColor = [[NSColor colorWithCalibratedRed:(35.0f/255.0f)
- green:(48.0f/255.0f)
- blue:(64.0f/255.0f)
- alpha:1.0] retain];
- backgroundColor_.reset(backgroundColor);
-}
-
-- (void)drawRect:(NSRect)dirtyRect {
- // Paint background.
- [backgroundColor_ set];
- NSRectFill(dirtyRect);
-}
-
-- (void)resizeSubviewsWithOldSize:(NSSize)oldSize {
- NSRect newBounds = [self bounds];
- CGFloat maxWidth = NSWidth(newBounds) - (kTabHorzMargin * 2);
- BOOL callSizeToFit = (messageSize_.width == 0);
-
- // Set new frame origin for image.
- NSRect iconFrame = [image_ frame];
- CGFloat iconX = (maxWidth - NSWidth(iconFrame)) / 2;
- CGFloat iconY =
- MIN(((NSHeight(newBounds) - NSHeight(iconFrame)) / 2) - kSadTabOffset,
- NSHeight(newBounds) - NSHeight(iconFrame));
- iconX = floor(iconX);
- iconY = floor(iconY);
- [image_ setFrameOrigin:NSMakePoint(iconX, iconY)];
-
- // Set new frame origin for title.
- if (callSizeToFit)
- [title_ sizeToFit];
- NSRect titleFrame = [title_ frame];
- CGFloat titleX = (maxWidth - NSWidth(titleFrame)) / 2;
- CGFloat titleY = iconY - kIconTitleSpacing - NSHeight(titleFrame);
- [title_ setFrameOrigin:NSMakePoint(titleX, titleY)];
-
- // Set new frame for message, wrapping or unwrapping the text if necessary.
- if (callSizeToFit) {
- [message_ sizeToFit];
- messageSize_ = [message_ frame].size;
- }
- NSRect messageFrame = [message_ frame];
- if (messageSize_.width > maxWidth) { // Need to wrap message.
- [message_ setFrameSize:NSMakeSize(maxWidth, messageSize_.height)];
- CGFloat heightChange =
- [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:message_];
- messageFrame.size.width = maxWidth;
- messageFrame.size.height = messageSize_.height + heightChange;
- messageFrame.origin.x = kTabHorzMargin;
- } else {
- if (!callSizeToFit) {
- [message_ sizeToFit];
- messageFrame = [message_ frame];
- }
- messageFrame.origin.x = (maxWidth - NSWidth(messageFrame)) / 2;
- }
- messageFrame.origin.y =
- titleY - kTitleMessageSpacing - NSHeight(messageFrame);
- [message_ setFrame:messageFrame];
-
- if (linkButton_) {
- if (callSizeToFit)
- [linkButton_ sizeToFit];
- // Set new frame origin for link.
- NSRect linkFrame = [linkButton_ frame];
- CGFloat linkX = (maxWidth - NSWidth(linkFrame)) / 2;
- CGFloat linkY =
- NSMinY(messageFrame) - kMessageLinkSpacing - NSHeight(linkFrame);
- [linkButton_ setFrameOrigin:NSMakePoint(linkX, linkY)];
- }
-}
-
-- (void)removeLinkButton {
- if (linkButton_) {
- [linkButton_ removeFromSuperview];
- linkButton_ = nil;
- }
-}
-
-@end
diff --git a/chrome/browser/cocoa/sad_tab_view_unittest.mm b/chrome/browser/cocoa/sad_tab_view_unittest.mm
deleted file mode 100644
index 7daddd3..0000000
--- a/chrome/browser/cocoa/sad_tab_view_unittest.mm
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/sad_tab_view.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-
-namespace {
-
-class SadTabViewTest : public CocoaTest {
- public:
- SadTabViewTest() {
- NSRect content_frame = [[test_window() contentView] frame];
- scoped_nsobject<SadTabView> view([[SadTabView alloc]
- initWithFrame:content_frame]);
- view_ = view.get();
- [[test_window() contentView] addSubview:view_];
- }
-
- SadTabView* view_; // Weak. Owned by the view hierarchy.
-};
-
-TEST_VIEW(SadTabViewTest, view_);
-
-} // namespace
diff --git a/chrome/browser/cocoa/scoped_authorizationref.h b/chrome/browser/cocoa/scoped_authorizationref.h
deleted file mode 100644
index 3ffa18b..0000000
--- a/chrome/browser/cocoa/scoped_authorizationref.h
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_SCOPED_AUTHORIZATIONREF_H_
-#define CHROME_BROWSER_COCOA_SCOPED_AUTHORIZATIONREF_H_
-#pragma once
-
-#include <Security/Authorization.h>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-
-// scoped_AuthorizationRef maintains ownership of an AuthorizationRef. It is
-// patterned after the scoped_ptr interface.
-
-class scoped_AuthorizationRef {
- public:
- explicit scoped_AuthorizationRef(AuthorizationRef authorization = NULL)
- : authorization_(authorization) {
- }
-
- ~scoped_AuthorizationRef() {
- if (authorization_) {
- AuthorizationFree(authorization_, kAuthorizationFlagDestroyRights);
- }
- }
-
- void reset(AuthorizationRef authorization = NULL) {
- if (authorization_ != authorization) {
- if (authorization_) {
- AuthorizationFree(authorization_, kAuthorizationFlagDestroyRights);
- }
- authorization_ = authorization;
- }
- }
-
- bool operator==(AuthorizationRef that) const {
- return authorization_ == that;
- }
-
- bool operator!=(AuthorizationRef that) const {
- return authorization_ != that;
- }
-
- operator AuthorizationRef() const {
- return authorization_;
- }
-
- AuthorizationRef* operator&() {
- return &authorization_;
- }
-
- AuthorizationRef get() const {
- return authorization_;
- }
-
- void swap(scoped_AuthorizationRef& that) {
- AuthorizationRef temp = that.authorization_;
- that.authorization_ = authorization_;
- authorization_ = temp;
- }
-
- // scoped_AuthorizationRef::release() is like scoped_ptr<>::release. It is
- // NOT a wrapper for AuthorizationFree(). To force a
- // scoped_AuthorizationRef object to call AuthorizationFree(), use
- // scoped_AuthorizaitonRef::reset().
- AuthorizationRef release() WARN_UNUSED_RESULT {
- AuthorizationRef temp = authorization_;
- authorization_ = NULL;
- return temp;
- }
-
- private:
- AuthorizationRef authorization_;
-
- DISALLOW_COPY_AND_ASSIGN(scoped_AuthorizationRef);
-};
-
-#endif // CHROME_BROWSER_COCOA_SCOPED_AUTHORIZATIONREF_H_
diff --git a/chrome/browser/cocoa/search_engine_dialog_controller.mm b/chrome/browser/cocoa/search_engine_dialog_controller.mm
deleted file mode 100644
index 0888050..0000000
--- a/chrome/browser/cocoa/search_engine_dialog_controller.mm
+++ /dev/null
@@ -1,285 +0,0 @@
-// 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 "chrome/browser/cocoa/search_engine_dialog_controller.h"
-
-#include <algorithm>
-
-#include "app/l10n_util_mac.h"
-#include "app/resource_bundle.h"
-#include "base/mac_util.h"
-#include "base/nsimage_cache_mac.h"
-#include "base/sys_string_conversions.h"
-#include "base/time.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_model.h"
-#include "chrome/browser/search_engines/template_url_model_observer.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-
-// Horizontal spacing between search engine choices.
-const int kSearchEngineSpacing = 20;
-
-// Vertical spacing between the search engine logo and the button underneath.
-const int kLogoButtonSpacing = 10;
-
-// Width of a label used in place of a logo.
-const int kLogoLabelWidth = 170;
-
-// Height of a label used in place of a logo.
-const int kLogoLabelHeight = 25;
-
-@interface SearchEngineDialogController (Private)
-- (void)onTemplateURLModelChanged;
-- (void)buildSearchEngineView;
-- (NSView*)viewForSearchEngine:(const TemplateURL*)engine
- atIndex:(size_t)index;
-- (IBAction)searchEngineSelected:(id)sender;
-@end
-
-class SearchEngineDialogControllerBridge :
- public base::RefCounted<SearchEngineDialogControllerBridge>,
- public TemplateURLModelObserver {
- public:
- SearchEngineDialogControllerBridge(SearchEngineDialogController* controller);
-
- // TemplateURLModelObserver
- virtual void OnTemplateURLModelChanged();
-
- private:
- SearchEngineDialogController* controller_;
-};
-
-SearchEngineDialogControllerBridge::SearchEngineDialogControllerBridge(
- SearchEngineDialogController* controller) : controller_(controller) {
-}
-
-void SearchEngineDialogControllerBridge::OnTemplateURLModelChanged() {
- [controller_ onTemplateURLModelChanged];
- MessageLoop::current()->QuitNow();
-}
-
-@implementation SearchEngineDialogController
-
-@synthesize profile = profile_;
-@synthesize randomize = randomize_;
-
-- (id)init {
- NSString* nibpath =
- [mac_util::MainAppBundle() pathForResource:@"SearchEngineDialog"
- ofType:@"nib"];
- self = [super initWithWindowNibPath:nibpath owner:self];
- if (self != nil) {
- bridge_ = new SearchEngineDialogControllerBridge(self);
- }
- return self;
-}
-
-- (void)dealloc {
- [super dealloc];
-}
-
-- (IBAction)showWindow:(id)sender {
- searchEnginesModel_ = profile_->GetTemplateURLModel();
- searchEnginesModel_->AddObserver(bridge_.get());
-
- if (searchEnginesModel_->loaded()) {
- MessageLoop::current()->PostTask(
- FROM_HERE,
- NewRunnableMethod(
- bridge_.get(),
- &SearchEngineDialogControllerBridge::OnTemplateURLModelChanged));
- } else {
- searchEnginesModel_->Load();
- }
- MessageLoop::current()->Run();
-}
-
-- (void)onTemplateURLModelChanged {
- searchEnginesModel_->RemoveObserver(bridge_.get());
-
- // Add the search engines in the search_engines_model_ to the buttons list.
- // The first three will always be from prepopulated data.
- std::vector<const TemplateURL*> templateUrls =
- searchEnginesModel_->GetTemplateURLs();
-
- // If we have fewer than two search engines, end the search engine dialog
- // immediately, leaving the imported default search engine setting intact.
- if (templateUrls.size() < 2) {
- return;
- }
-
- NSWindow* win = [self window];
-
- [win setBackgroundColor:[NSColor whiteColor]];
-
- NSImage* headerImage = ResourceBundle::GetSharedInstance().
- GetNativeImageNamed(IDR_SEARCH_ENGINE_DIALOG_TOP);
- [headerImageView_ setImage:headerImage];
-
- // Is the user's default search engine included in the first three
- // prepopulated set? If not, we need to expand the dialog to include a fourth
- // engine.
- const TemplateURL* defaultSearchEngine =
- searchEnginesModel_->GetDefaultSearchProvider();
-
- std::vector<const TemplateURL*>::iterator engineIter =
- templateUrls.begin();
- for (int i = 0; engineIter != templateUrls.end(); ++i, ++engineIter) {
- if (i < 3) {
- choices_.push_back(*engineIter);
- } else {
- if (*engineIter == defaultSearchEngine)
- choices_.push_back(*engineIter);
- }
- }
-
- // Randomize the order of the logos if the option has been set.
- if (randomize_) {
- int seed = static_cast<int>(base::Time::Now().ToInternalValue());
- srand(seed);
- std::random_shuffle(choices_.begin(), choices_.end());
- }
-
- [self buildSearchEngineView];
-
- // Display the dialog.
- NSInteger choice = [NSApp runModalForWindow:win];
- searchEnginesModel_->SetDefaultSearchProvider(choices_.at(choice));
-}
-
-- (void)buildSearchEngineView {
- scoped_nsobject<NSMutableArray> searchEngineViews
- ([[NSMutableArray alloc] init]);
-
- for (size_t i = 0; i < choices_.size(); ++i)
- [searchEngineViews addObject:[self viewForSearchEngine:choices_.at(i)
- atIndex:i]];
-
- NSSize newOverallSize = NSZeroSize;
- for (NSView* view in searchEngineViews.get()) {
- NSRect engineFrame = [view frame];
- engineFrame.origin = NSMakePoint(newOverallSize.width, 0);
- [searchEngineView_ addSubview:view];
- [view setFrame:engineFrame];
- newOverallSize = NSMakeSize(
- newOverallSize.width + NSWidth(engineFrame) + kSearchEngineSpacing,
- std::max(newOverallSize.height, NSHeight(engineFrame)));
- }
- newOverallSize.width -= kSearchEngineSpacing;
-
- // Resize the window to fit (and because it's bound on all sides it will
- // resize the search engine view).
- NSSize currentOverallSize = [searchEngineView_ bounds].size;
- NSSize deltaSize = NSMakeSize(
- newOverallSize.width - currentOverallSize.width,
- newOverallSize.height - currentOverallSize.height);
- NSSize windowDeltaSize = [searchEngineView_ convertSize:deltaSize toView:nil];
- NSRect windowFrame = [[self window] frame];
- windowFrame.size.width += windowDeltaSize.width;
- windowFrame.size.height += windowDeltaSize.height;
- [[self window] setFrame:windowFrame display:NO];
-}
-
-- (NSView*)viewForSearchEngine:(const TemplateURL*)engine
- atIndex:(size_t)index {
- bool useImages = false;
-#if defined(GOOGLE_CHROME_BUILD)
- useImages = true;
-#endif
-
- // Make the engine identifier.
- NSView* engineIdentifier = nil; // either the logo or the text label
-
- int logoId = engine->logo_id();
- if (useImages && logoId > 0) {
- NSImage* logoImage =
- ResourceBundle::GetSharedInstance().GetNativeImageNamed(logoId);
- NSRect logoBounds = NSZeroRect;
- logoBounds.size = [logoImage size];
- NSImageView* logoView =
- [[[NSImageView alloc] initWithFrame:logoBounds] autorelease];
- [logoView setImage:logoImage];
- [logoView setEditable:NO];
-
- // Tooltip text provides accessibility.
- [logoView setToolTip:base::SysWideToNSString(engine->short_name())];
- engineIdentifier = logoView;
- } else {
- // No logo -- we must show a text label.
- NSRect labelBounds = NSMakeRect(0, 0, kLogoLabelWidth, kLogoLabelHeight);
- NSTextField* labelField =
- [[[NSTextField alloc] initWithFrame:labelBounds] autorelease];
- [labelField setBezeled:NO];
- [labelField setEditable:NO];
- [labelField setSelectable:NO];
-
- scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
- [[NSMutableParagraphStyle alloc] init]);
- [paragraphStyle setAlignment:NSCenterTextAlignment];
- NSDictionary* attrs = [NSDictionary dictionaryWithObjectsAndKeys:
- [NSFont boldSystemFontOfSize:13], NSFontAttributeName,
- paragraphStyle.get(), NSParagraphStyleAttributeName,
- nil];
-
- NSString* value = base::SysWideToNSString(engine->short_name());
- scoped_nsobject<NSAttributedString> attrValue(
- [[NSAttributedString alloc] initWithString:value
- attributes:attrs]);
-
- [labelField setAttributedStringValue:attrValue.get()];
-
- engineIdentifier = labelField;
- }
-
- // Make the "Choose" button.
- scoped_nsobject<NSButton> chooseButton(
- [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 34)]);
- [chooseButton setBezelStyle:NSRoundedBezelStyle];
- [[chooseButton cell] setFont:[NSFont systemFontOfSize:
- [NSFont systemFontSizeForControlSize:NSRegularControlSize]]];
- [chooseButton setTitle:l10n_util::GetNSStringWithFixup(IDS_FR_SEARCH_CHOOSE)];
- [GTMUILocalizerAndLayoutTweaker sizeToFitView:chooseButton.get()];
- [chooseButton setTag:index];
- [chooseButton setTarget:self];
- [chooseButton setAction:@selector(searchEngineSelected:)];
-
- // Put 'em together.
- NSRect engineIdentifierFrame = [engineIdentifier frame];
- NSRect chooseButtonFrame = [chooseButton frame];
-
- NSRect containingViewFrame = NSZeroRect;
- containingViewFrame.size.width += engineIdentifierFrame.size.width;
- containingViewFrame.size.height += engineIdentifierFrame.size.height;
- containingViewFrame.size.height += kLogoButtonSpacing;
- containingViewFrame.size.height += chooseButtonFrame.size.height;
-
- NSView* containingView =
- [[[NSView alloc] initWithFrame:containingViewFrame] autorelease];
-
- [containingView addSubview:engineIdentifier];
- engineIdentifierFrame.origin.y =
- chooseButtonFrame.size.height + kLogoButtonSpacing;
- [engineIdentifier setFrame:engineIdentifierFrame];
-
- [containingView addSubview:chooseButton];
- chooseButtonFrame.origin.x =
- int((containingViewFrame.size.width - chooseButtonFrame.size.width) / 2);
- [chooseButton setFrame:chooseButtonFrame];
-
- return containingView;
-}
-
-- (NSFont*)mainLabelFont {
- return [NSFont boldSystemFontOfSize:13];
-}
-
-- (IBAction)searchEngineSelected:(id)sender {
- [[self window] close];
- [NSApp stopModalWithCode:[sender tag]];
-}
-
-@end
diff --git a/chrome/browser/cocoa/search_engine_list_model.h b/chrome/browser/cocoa/search_engine_list_model.h
deleted file mode 100644
index 386a793..0000000
--- a/chrome/browser/cocoa/search_engine_list_model.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_SEARCH_ENGINE_LIST_MODEL_H_
-#define CHROME_BROWSER_COCOA_SEARCH_ENGINE_LIST_MODEL_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-
-class TemplateURLModel;
-class SearchEngineObserver;
-
-// The model for the "default search engine" combobox in preferences. Bridges
-// between the cross-platform TemplateURLModel and Cocoa while watching for
-// changes to the cross-platform model.
-
-@interface SearchEngineListModel : NSObject {
- @private
- TemplateURLModel* model_; // weak, owned by Profile
- scoped_ptr<SearchEngineObserver> observer_; // watches for model changes
- scoped_nsobject<NSArray> engines_;
-}
-
-// Initialize with the given template model.
-- (id)initWithModel:(TemplateURLModel*)model;
-
-// Returns an array of NSString's corresponding to the user-visible names of the
-// search engines.
-- (NSArray*)searchEngines;
-
-// The index into |-searchEngines| of the current default search engine. If
-// there is no default search engine, the value is -1. The setter changes the
-// back-end preference.
-- (NSInteger)defaultIndex;
-- (void)setDefaultIndex:(NSInteger)index;
-// Return TRUE if the default is managed via policy.
-- (BOOL)isDefaultManaged;
-@end
-
-// Broadcast when the cross-platform model changes. This can be used to update
-// any view state that may rely on the position of items in the list.
-extern NSString* const kSearchEngineListModelChangedNotification;
-
-#endif // CHROME_BROWSER_COCOA_SEARCH_ENGINE_LIST_MODEL_H_
diff --git a/chrome/browser/cocoa/search_engine_list_model.mm b/chrome/browser/cocoa/search_engine_list_model.mm
deleted file mode 100644
index a4ac0fa..0000000
--- a/chrome/browser/cocoa/search_engine_list_model.mm
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/search_engine_list_model.h"
-
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_model.h"
-#include "chrome/browser/search_engines/template_url_model_observer.h"
-
-NSString* const kSearchEngineListModelChangedNotification =
- @"kSearchEngineListModelChangedNotification";
-
-@interface SearchEngineListModel(Private)
-- (void)buildEngineList;
-@end
-
-// C++ bridge from TemplateURLModel to our Obj-C model. When it's told about
-// model changes, notifies us to rebuild the list.
-class SearchEngineObserver : public TemplateURLModelObserver {
- public:
- SearchEngineObserver(SearchEngineListModel* notify)
- : notify_(notify) { }
- virtual ~SearchEngineObserver() { };
-
- private:
- // TemplateURLModelObserver methods.
- virtual void OnTemplateURLModelChanged() { [notify_ buildEngineList]; }
-
- SearchEngineListModel* notify_; // weak, owns us
-};
-
-@implementation SearchEngineListModel
-
-// The windows code allows for a NULL |model| and checks for it throughout
-// the code, though I'm not sure why. We follow suit.
-- (id)initWithModel:(TemplateURLModel*)model {
- if ((self = [super init])) {
- model_ = model;
- if (model_) {
- observer_.reset(new SearchEngineObserver(self));
- model_->Load();
- model_->AddObserver(observer_.get());
- [self buildEngineList];
- }
- }
- return self;
-}
-
-- (void)dealloc {
- if (model_)
- model_->RemoveObserver(observer_.get());
- [super dealloc];
-}
-
-// Returns an array of NSString's corresponding to the user-visible names of the
-// search engines.
-- (NSArray*)searchEngines {
- return engines_.get();
-}
-
-- (void)setSearchEngines:(NSArray*)engines {
- engines_.reset([engines retain]);
-
- // Tell anyone who's listening that something has changed so they need to
- // adjust the UI.
- [[NSNotificationCenter defaultCenter]
- postNotificationName:kSearchEngineListModelChangedNotification
- object:nil];
-}
-
-// Walks the model and builds an array of NSStrings to display to the user.
-// Assumes there is a non-NULL model.
-- (void)buildEngineList {
- scoped_nsobject<NSMutableArray> engines([[NSMutableArray alloc] init]);
-
- typedef std::vector<const TemplateURL*> TemplateURLs;
- TemplateURLs modelURLs = model_->GetTemplateURLs();
- for (size_t i = 0; i < modelURLs.size(); ++i) {
- if (modelURLs[i]->ShowInDefaultList())
- [engines addObject:base::SysWideToNSString(modelURLs[i]->short_name())];
- }
-
- [self setSearchEngines:engines.get()];
-}
-
-// The index into |-searchEngines| of the current default search engine.
-// -1 if there is no default.
-- (NSInteger)defaultIndex {
- if (!model_) return -1;
-
- NSInteger index = 0;
- const TemplateURL* defaultSearchProvider = model_->GetDefaultSearchProvider();
- if (defaultSearchProvider) {
- typedef std::vector<const TemplateURL*> TemplateURLs;
- TemplateURLs urls = model_->GetTemplateURLs();
- for (std::vector<const TemplateURL*>::iterator it = urls.begin();
- it != urls.end(); ++it) {
- const TemplateURL* url = *it;
- // Skip all the URLs not shown on the default list.
- if (!url->ShowInDefaultList())
- continue;
- if (url->id() == defaultSearchProvider->id())
- return index;
- ++index;
- }
- }
- return -1;
-}
-
-- (void)setDefaultIndex:(NSInteger)index {
- if (model_) {
- typedef std::vector<const TemplateURL*> TemplateURLs;
- TemplateURLs urls = model_->GetTemplateURLs();
- for (std::vector<const TemplateURL*>::iterator it = urls.begin();
- it != urls.end(); ++it) {
- const TemplateURL* url = *it;
- // Skip all the URLs not shown on the default list.
- if (!url->ShowInDefaultList())
- continue;
- if (0 == index) {
- model_->SetDefaultSearchProvider(url);
- return;
- }
- --index;
- }
- DCHECK(false);
- }
-}
-
-// Return TRUE if the default is managed via policy.
-- (BOOL)isDefaultManaged {
- return model_->is_default_search_managed();
-}
-@end
diff --git a/chrome/browser/cocoa/search_engine_list_model_unittest.mm b/chrome/browser/cocoa/search_engine_list_model_unittest.mm
deleted file mode 100644
index 5626aea..0000000
--- a/chrome/browser/cocoa/search_engine_list_model_unittest.mm
+++ /dev/null
@@ -1,152 +0,0 @@
-// Copyright (c) 2009 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/scoped_nsobject.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/search_engine_list_model.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_model.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-// A helper for NSNotifications. Makes a note that it's been called back.
-@interface SearchEngineListHelper : NSObject {
- @public
- BOOL sawNotification_;
-}
-@end
-
-@implementation SearchEngineListHelper
-- (void)entryChanged:(NSNotification*)notify {
- sawNotification_ = YES;
-}
-@end
-
-class SearchEngineListModelTest : public PlatformTest {
- public:
- SearchEngineListModelTest() {
- // Build a fake set of template urls.
- template_model_.reset(new TemplateURLModel(helper_.profile()));
- TemplateURL* t_url = new TemplateURL();
- t_url->SetURL("http://www.google.com/?q={searchTerms}", 0, 0);
- t_url->set_keyword(L"keyword");
- t_url->set_short_name(L"google");
- t_url->set_show_in_default_list(true);
- template_model_->Add(t_url);
- t_url = new TemplateURL();
- t_url->SetURL("http://www.google2.com/?q={searchTerms}", 0, 0);
- t_url->set_keyword(L"keyword2");
- t_url->set_short_name(L"google2");
- t_url->set_show_in_default_list(true);
- template_model_->Add(t_url);
- EXPECT_EQ(template_model_->GetTemplateURLs().size(), 2U);
-
- model_.reset([[SearchEngineListModel alloc]
- initWithModel:template_model_.get()]);
- notification_helper_.reset([[SearchEngineListHelper alloc] init]);
- [[NSNotificationCenter defaultCenter]
- addObserver:notification_helper_.get()
- selector:@selector(entryChanged:)
- name:kSearchEngineListModelChangedNotification
- object:nil];
- }
- ~SearchEngineListModelTest() {
- [[NSNotificationCenter defaultCenter]
- removeObserver:notification_helper_.get()];
- }
-
- BrowserTestHelper helper_;
- scoped_ptr<TemplateURLModel> template_model_;
- scoped_nsobject<SearchEngineListModel> model_;
- scoped_nsobject<SearchEngineListHelper> notification_helper_;
-};
-
-TEST_F(SearchEngineListModelTest, Init) {
- scoped_nsobject<SearchEngineListModel> model(
- [[SearchEngineListModel alloc] initWithModel:template_model_.get()]);
-}
-
-TEST_F(SearchEngineListModelTest, Engines) {
- NSArray* engines = [model_ searchEngines];
- EXPECT_EQ([engines count], 2U);
-}
-
-TEST_F(SearchEngineListModelTest, Default) {
- EXPECT_EQ([model_ defaultIndex], -1);
-
- [model_ setDefaultIndex:1];
- EXPECT_EQ([model_ defaultIndex], 1);
-
- // Add two more URLs, neither of which are shown in the default list.
- TemplateURL* t_url = new TemplateURL();
- t_url->SetURL("http://www.google3.com/?q={searchTerms}", 0, 0);
- t_url->set_keyword(L"keyword3");
- t_url->set_short_name(L"google3 not eligible");
- t_url->set_show_in_default_list(false);
- template_model_->Add(t_url);
- t_url = new TemplateURL();
- t_url->SetURL("http://www.google4.com/?q={searchTerms}", 0, 0);
- t_url->set_keyword(L"keyword4");
- t_url->set_short_name(L"google4");
- t_url->set_show_in_default_list(false);
- template_model_->Add(t_url);
-
- // Still should only have 2 engines and not these newly added ones.
- EXPECT_EQ([[model_ searchEngines] count], 2U);
-
- // Since keyword3 is not in the default list, the 2nd index in the default
- // keyword list should be keyword4. Test for http://crbug.com/21898.
- template_model_->SetDefaultSearchProvider(t_url);
- EXPECT_EQ([[model_ searchEngines] count], 3U);
- EXPECT_EQ([model_ defaultIndex], 2);
-
- NSString* defaultString = [[model_ searchEngines] objectAtIndex:2];
- EXPECT_NSEQ(@"google4", defaultString);
-}
-
-TEST_F(SearchEngineListModelTest, DefaultChosenFromUI) {
- EXPECT_EQ([model_ defaultIndex], -1);
-
- [model_ setDefaultIndex:1];
- EXPECT_EQ([model_ defaultIndex], 1);
-
- // Add two more URLs, the first one not shown in the default list.
- TemplateURL* t_url = new TemplateURL();
- t_url->SetURL("http://www.google3.com/?q={searchTerms}", 0, 0);
- t_url->set_keyword(L"keyword3");
- t_url->set_short_name(L"google3 not eligible");
- t_url->set_show_in_default_list(false);
- template_model_->Add(t_url);
- t_url = new TemplateURL();
- t_url->SetURL("http://www.google4.com/?q={searchTerms}", 0, 0);
- t_url->set_keyword(L"keyword4");
- t_url->set_short_name(L"google4");
- t_url->set_show_in_default_list(true);
- template_model_->Add(t_url);
-
- // We should have 3 engines.
- EXPECT_EQ([[model_ searchEngines] count], 3U);
-
- // Simulate the UI setting the default to the third entry.
- [model_ setDefaultIndex:2];
- EXPECT_EQ([model_ defaultIndex], 2);
-
- // The default search provider should be google4.
- EXPECT_EQ(template_model_->GetDefaultSearchProvider(), t_url);
-}
-
-// Make sure that when the back-end model changes that we get a notification.
-TEST_F(SearchEngineListModelTest, Notification) {
- // Add one more item to force a notification.
- TemplateURL* t_url = new TemplateURL();
- t_url->SetURL("http://www.google3.com/foo/bar", 0, 0);
- t_url->set_keyword(L"keyword3");
- t_url->set_short_name(L"google3");
- t_url->set_show_in_default_list(true);
- template_model_->Add(t_url);
-
- EXPECT_TRUE(notification_helper_.get()->sawNotification_);
-}
diff --git a/chrome/browser/cocoa/shell_dialogs_mac.mm b/chrome/browser/cocoa/shell_dialogs_mac.mm
deleted file mode 100644
index 8dcaebe..0000000
--- a/chrome/browser/cocoa/shell_dialogs_mac.mm
+++ /dev/null
@@ -1,417 +0,0 @@
-// 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.
-
-#include "chrome/browser/shell_dialogs.h"
-
-#import <Cocoa/Cocoa.h>
-#include <CoreServices/CoreServices.h>
-
-#include <map>
-#include <set>
-#include <vector>
-
-#include "app/l10n_util_mac.h"
-#import "base/cocoa_protocols_mac.h"
-#include "base/file_util.h"
-#include "base/logging.h"
-#include "base/mac_util.h"
-#include "base/mac/scoped_cftyperef.h"
-#import "base/scoped_nsobject.h"
-#include "base/sys_string_conversions.h"
-#include "base/thread_restrictions.h"
-#include "grit/generated_resources.h"
-
-static const int kFileTypePopupTag = 1234;
-
-class SelectFileDialogImpl;
-
-// A bridge class to act as the modal delegate to the save/open sheet and send
-// the results to the C++ class.
-@interface SelectFileDialogBridge : NSObject<NSOpenSavePanelDelegate> {
- @private
- SelectFileDialogImpl* selectFileDialogImpl_; // WEAK; owns us
-}
-
-- (id)initWithSelectFileDialogImpl:(SelectFileDialogImpl*)s;
-- (void)endedPanel:(NSSavePanel*)panel
- withReturn:(int)returnCode
- context:(void *)context;
-
-// NSSavePanel delegate method
-- (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename;
-
-@end
-
-// Implementation of SelectFileDialog that shows Cocoa dialogs for choosing a
-// file or folder.
-class SelectFileDialogImpl : public SelectFileDialog {
- public:
- explicit SelectFileDialogImpl(Listener* listener);
- virtual ~SelectFileDialogImpl();
-
- // BaseShellDialog implementation.
- virtual bool IsRunning(gfx::NativeWindow parent_window) const;
- virtual void ListenerDestroyed();
-
- // SelectFileDialog implementation.
- // |params| is user data we pass back via the Listener interface.
- virtual void SelectFile(Type type,
- const string16& title,
- const FilePath& default_path,
- const FileTypeInfo* file_types,
- int file_type_index,
- const FilePath::StringType& default_extension,
- gfx::NativeWindow owning_window,
- void* params);
-
- // Callback from ObjC bridge.
- void FileWasSelected(NSSavePanel* dialog,
- NSWindow* parent_window,
- bool was_cancelled,
- bool is_multi,
- const std::vector<FilePath>& files,
- int index);
-
- bool ShouldEnableFilename(NSSavePanel* dialog, NSString* filename);
-
- struct SheetContext {
- Type type;
- NSWindow* owning_window;
- };
-
- private:
- // Gets the accessory view for the save dialog.
- NSView* GetAccessoryView(const FileTypeInfo* file_types,
- int file_type_index);
-
- // The listener to be notified of selection completion.
- Listener* listener_;
-
- // The bridge for results from Cocoa to return to us.
- scoped_nsobject<SelectFileDialogBridge> bridge_;
-
- // A map from file dialogs to the |params| user data associated with them.
- std::map<NSSavePanel*, void*> params_map_;
-
- // The set of all parent windows for which we are currently running dialogs.
- std::set<NSWindow*> parents_;
-
- // A map from file dialogs to their types.
- std::map<NSSavePanel*, Type> type_map_;
-
- DISALLOW_COPY_AND_ASSIGN(SelectFileDialogImpl);
-};
-
-// static
-SelectFileDialog* SelectFileDialog::Create(Listener* listener) {
- return new SelectFileDialogImpl(listener);
-}
-
-SelectFileDialogImpl::SelectFileDialogImpl(Listener* listener)
- : listener_(listener),
- bridge_([[SelectFileDialogBridge alloc]
- initWithSelectFileDialogImpl:this]) {
-}
-
-SelectFileDialogImpl::~SelectFileDialogImpl() {
- // Walk through the open dialogs and close them all. Use a temporary vector
- // to hold the pointers, since we can't delete from the map as we're iterating
- // through it.
- std::vector<NSSavePanel*> panels;
- for (std::map<NSSavePanel*, void*>::iterator it = params_map_.begin();
- it != params_map_.end(); ++it) {
- panels.push_back(it->first);
- }
-
- for (std::vector<NSSavePanel*>::iterator it = panels.begin();
- it != panels.end(); ++it) {
- [(*it) cancel:nil];
- }
-}
-
-bool SelectFileDialogImpl::IsRunning(gfx::NativeWindow parent_window) const {
- return parents_.find(parent_window) != parents_.end();
-}
-
-void SelectFileDialogImpl::ListenerDestroyed() {
- listener_ = NULL;
-}
-
-void SelectFileDialogImpl::SelectFile(
- Type type,
- const string16& title,
- const FilePath& default_path,
- const FileTypeInfo* file_types,
- int file_type_index,
- const FilePath::StringType& default_extension,
- gfx::NativeWindow owning_window,
- void* params) {
- DCHECK(type == SELECT_FOLDER ||
- type == SELECT_OPEN_FILE ||
- type == SELECT_OPEN_MULTI_FILE ||
- type == SELECT_SAVEAS_FILE);
- parents_.insert(owning_window);
-
- // Note: we need to retain the dialog as owning_window can be null.
- // (see http://crbug.com/29213)
- NSSavePanel* dialog;
- if (type == SELECT_SAVEAS_FILE)
- dialog = [[NSSavePanel savePanel] retain];
- else
- dialog = [[NSOpenPanel openPanel] retain];
-
- if (!title.empty())
- [dialog setTitle:base::SysUTF16ToNSString(title)];
-
- NSString* default_dir = nil;
- NSString* default_filename = nil;
- if (!default_path.empty()) {
- // The file dialog is going to do a ton of stats anyway. Not much
- // point in eliminating this one.
- base::ThreadRestrictions::ScopedAllowIO allow_io;
- if (file_util::DirectoryExists(default_path)) {
- default_dir = base::SysUTF8ToNSString(default_path.value());
- } else {
- default_dir = base::SysUTF8ToNSString(default_path.DirName().value());
- default_filename =
- base::SysUTF8ToNSString(default_path.BaseName().value());
- }
- }
-
- NSMutableArray* allowed_file_types = nil;
- if (file_types) {
- if (!file_types->extensions.empty()) {
- allowed_file_types = [NSMutableArray array];
- for (size_t i=0; i < file_types->extensions.size(); ++i) {
- const std::vector<FilePath::StringType>& ext_list =
- file_types->extensions[i];
- for (size_t j=0; j < ext_list.size(); ++j) {
- [allowed_file_types addObject:base::SysUTF8ToNSString(ext_list[j])];
- }
- }
- }
- if (type == SELECT_SAVEAS_FILE)
- [dialog setAllowedFileTypes:allowed_file_types];
- // else we'll pass it in when we run the open panel
-
- if (file_types->include_all_files)
- [dialog setAllowsOtherFileTypes:YES];
-
- if (!file_types->extension_description_overrides.empty()) {
- NSView* accessory_view = GetAccessoryView(file_types, file_type_index);
- [dialog setAccessoryView:accessory_view];
- }
- } else {
- // If no type info is specified, anything goes.
- [dialog setAllowsOtherFileTypes:YES];
- }
-
- if (!default_extension.empty())
- [dialog setRequiredFileType:base::SysUTF8ToNSString(default_extension)];
-
- params_map_[dialog] = params;
- type_map_[dialog] = type;
-
- SheetContext* context = new SheetContext;
-
- // |context| should never be NULL, but we are seeing indications otherwise.
- // |This CHECK is here to confirm if we are actually getting NULL
- // ||context|s. http://crbug.com/58959
- CHECK(context);
- context->type = type;
- context->owning_window = owning_window;
-
- if (type == SELECT_SAVEAS_FILE) {
- [dialog beginSheetForDirectory:default_dir
- file:default_filename
- modalForWindow:owning_window
- modalDelegate:bridge_.get()
- didEndSelector:@selector(endedPanel:withReturn:context:)
- contextInfo:context];
- } else {
- NSOpenPanel* open_dialog = (NSOpenPanel*)dialog;
-
- if (type == SELECT_OPEN_MULTI_FILE)
- [open_dialog setAllowsMultipleSelection:YES];
- else
- [open_dialog setAllowsMultipleSelection:NO];
-
- if (type == SELECT_FOLDER) {
- [open_dialog setCanChooseFiles:NO];
- [open_dialog setCanChooseDirectories:YES];
- [open_dialog setCanCreateDirectories:YES];
- NSString *prompt = l10n_util::GetNSString(IDS_SELECT_FOLDER_BUTTON_TITLE);
- [open_dialog setPrompt:prompt];
- } else {
- [open_dialog setCanChooseFiles:YES];
- [open_dialog setCanChooseDirectories:NO];
- }
-
- [open_dialog setDelegate:bridge_.get()];
- [open_dialog beginSheetForDirectory:default_dir
- file:default_filename
- types:allowed_file_types
- modalForWindow:owning_window
- modalDelegate:bridge_.get()
- didEndSelector:@selector(endedPanel:withReturn:context:)
- contextInfo:context];
- }
-}
-
-void SelectFileDialogImpl::FileWasSelected(NSSavePanel* dialog,
- NSWindow* parent_window,
- bool was_cancelled,
- bool is_multi,
- const std::vector<FilePath>& files,
- int index) {
- void* params = params_map_[dialog];
- params_map_.erase(dialog);
- parents_.erase(parent_window);
- type_map_.erase(dialog);
-
- if (!listener_)
- return;
-
- if (was_cancelled) {
- listener_->FileSelectionCanceled(params);
- } else {
- if (is_multi) {
- listener_->MultiFilesSelected(files, params);
- } else {
- listener_->FileSelected(files[0], index, params);
- }
- }
-}
-
-NSView* SelectFileDialogImpl::GetAccessoryView(const FileTypeInfo* file_types,
- int file_type_index) {
- DCHECK(file_types);
- scoped_nsobject<NSNib> nib (
- [[NSNib alloc] initWithNibNamed:@"SaveAccessoryView"
- bundle:mac_util::MainAppBundle()]);
- if (!nib)
- return nil;
-
- NSArray* objects;
- BOOL success = [nib instantiateNibWithOwner:nil
- topLevelObjects:&objects];
- if (!success)
- return nil;
- [objects makeObjectsPerformSelector:@selector(release)];
-
- // This is a one-object nib, but IB insists on creating a second object, the
- // NSApplication. I don't know why.
- size_t view_index = 0;
- while (view_index < [objects count] &&
- ![[objects objectAtIndex:view_index] isKindOfClass:[NSView class]])
- ++view_index;
- DCHECK(view_index < [objects count]);
- NSView* accessory_view = [objects objectAtIndex:view_index];
-
- NSPopUpButton* popup = [accessory_view viewWithTag:kFileTypePopupTag];
- DCHECK(popup);
-
- size_t type_count = file_types->extensions.size();
- for (size_t type = 0; type<type_count; ++type) {
- NSString* type_description;
- if (type < file_types->extension_description_overrides.size()) {
- type_description = base::SysUTF16ToNSString(
- file_types->extension_description_overrides[type]);
- } else {
- const std::vector<FilePath::StringType>& ext_list =
- file_types->extensions[type];
- DCHECK(!ext_list.empty());
- NSString* type_extension = base::SysUTF8ToNSString(ext_list[0]);
- base::mac::ScopedCFTypeRef<CFStringRef> uti(
- UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension,
- (CFStringRef)type_extension,
- NULL));
- base::mac::ScopedCFTypeRef<CFStringRef> description(
- UTTypeCopyDescription(uti.get()));
-
- type_description =
- [NSString stringWithString:(NSString*)description.get()];
- }
- [popup addItemWithTitle:type_description];
- }
-
- [popup selectItemAtIndex:file_type_index-1]; // 1-based
- return accessory_view;
-}
-
-bool SelectFileDialogImpl::ShouldEnableFilename(NSSavePanel* dialog,
- NSString* filename) {
- // If this is a single open file dialog, disable selecting packages.
- if (type_map_[dialog] != SELECT_OPEN_FILE)
- return true;
-
- return ![[NSWorkspace sharedWorkspace] isFilePackageAtPath:filename];
-}
-
-@implementation SelectFileDialogBridge
-
-- (id)initWithSelectFileDialogImpl:(SelectFileDialogImpl*)s {
- self = [super init];
- if (self != nil) {
- selectFileDialogImpl_ = s;
- }
- return self;
-}
-
-- (void)endedPanel:(NSSavePanel*)panel
- withReturn:(int)returnCode
- context:(void *)context {
- // |context| should never be NULL, but we are seeing indications otherwise.
- // |This CHECK is here to confirm if we are actually getting NULL
- // ||context|s. http://crbug.com/58959
- CHECK(context);
-
- int index = 0;
- SelectFileDialogImpl::SheetContext* context_struct =
- (SelectFileDialogImpl::SheetContext*)context;
-
- SelectFileDialog::Type type = context_struct->type;
- NSWindow* parentWindow = context_struct->owning_window;
- delete context_struct;
-
- bool isMulti = type == SelectFileDialog::SELECT_OPEN_MULTI_FILE;
-
- std::vector<FilePath> paths;
- bool did_cancel = returnCode == NSCancelButton;
- if (!did_cancel) {
- if (type == SelectFileDialog::SELECT_SAVEAS_FILE) {
- paths.push_back(FilePath(base::SysNSStringToUTF8([panel filename])));
-
- NSView* accessoryView = [panel accessoryView];
- if (accessoryView) {
- NSPopUpButton* popup = [accessoryView viewWithTag:kFileTypePopupTag];
- if (popup) {
- // File type indexes are 1-based.
- index = [popup indexOfSelectedItem] + 1;
- }
- } else {
- index = 1;
- }
- } else {
- CHECK([panel isKindOfClass:[NSOpenPanel class]]);
- NSArray* filenames = [static_cast<NSOpenPanel*>(panel) filenames];
- for (NSString* filename in filenames)
- paths.push_back(FilePath(base::SysNSStringToUTF8(filename)));
- }
- }
-
- selectFileDialogImpl_->FileWasSelected(panel,
- parentWindow,
- did_cancel,
- isMulti,
- paths,
- index);
- [panel release];
-}
-
-- (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename {
- return selectFileDialogImpl_->ShouldEnableFilename(sender, filename);
-}
-
-@end
diff --git a/chrome/browser/cocoa/side_tab_strip_controller.h b/chrome/browser/cocoa/side_tab_strip_controller.h
deleted file mode 100644
index 1961842..0000000
--- a/chrome/browser/cocoa/side_tab_strip_controller.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// 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>
-
-#import "chrome/browser/cocoa/tab_strip_controller.h"
-
-// A controller for the tab strip when side tabs are enabled.
-//
-// TODO(pinkerton): I'm expecting there are more things here that need
-// overriding rather than just tweaking a couple of settings, so I'm creating
-// a full-blown subclass. Clearly, very little is actually necessary at this
-// point for it to work.
-
-@interface SideTabStripController : TabStripController {
-}
-
-@end
diff --git a/chrome/browser/cocoa/side_tab_strip_controller.mm b/chrome/browser/cocoa/side_tab_strip_controller.mm
deleted file mode 100644
index 9ff73d1..0000000
--- a/chrome/browser/cocoa/side_tab_strip_controller.mm
+++ /dev/null
@@ -1,33 +0,0 @@
-// 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 "chrome/browser/cocoa/side_tab_strip_controller.h"
-
-@implementation SideTabStripController
-
-// TODO(pinkerton): Still need to figure out several things:
-// - new tab button placement and layout
-// - animating tabs in and out
-// - being able to drop a tab elsewhere besides the 1st position
-// - how to load a different tab view nib for each tab.
-
-- (id)initWithView:(TabStripView*)view
- switchView:(NSView*)switchView
- browser:(Browser*)browser
- delegate:(id<TabStripControllerDelegate>)delegate {
- self = [super initWithView:view
- switchView:switchView
- browser:browser
- delegate:delegate];
- if (self) {
- // Side tabs have no indent since they are not sharing space with the
- // window controls.
- [self setIndentForControls:0.0];
- verticalLayout_ = YES;
- }
- return self;
-}
-
-@end
-
diff --git a/chrome/browser/cocoa/side_tab_strip_view.h b/chrome/browser/cocoa/side_tab_strip_view.h
deleted file mode 100644
index b4b4629..0000000
--- a/chrome/browser/cocoa/side_tab_strip_view.h
+++ /dev/null
@@ -1,15 +0,0 @@
-// 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>
-
-#import "chrome/browser/cocoa/tab_strip_view.h"
-
-// A class that handles drawing the background of the tab strip when side tabs
-// are enabled.
-
-@interface SideTabStripView : TabStripView {
-}
-
-@end
diff --git a/chrome/browser/cocoa/side_tab_strip_view.mm b/chrome/browser/cocoa/side_tab_strip_view.mm
deleted file mode 100644
index b7bebe0..0000000
--- a/chrome/browser/cocoa/side_tab_strip_view.mm
+++ /dev/null
@@ -1,43 +0,0 @@
-// 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 "chrome/browser/cocoa/side_tab_strip_view.h"
-
-#include "base/scoped_nsobject.h"
-#import "third_party/GTM/AppKit/GTMNSColor+Luminance.h"
-
-@implementation SideTabStripView
-
-- (void)drawBorder:(NSRect)bounds {
- // Draw a border on the right side.
- NSRect borderRect, contentRect;
- NSDivideRect(bounds, &borderRect, &contentRect, 1, NSMaxXEdge);
- [[NSColor colorWithCalibratedWhite:0.0 alpha:0.2] set];
- NSRectFillUsingOperation(borderRect, NSCompositeSourceOver);
-}
-
-// Override to prevent double-clicks from minimizing the window. The side
-// tab strip doesn't have that behavior (since it's in the window content
-// area).
-- (BOOL)doubleClickMinimizesWindow {
- return NO;
-}
-
-- (void)drawRect:(NSRect)rect {
- // BOOL isKey = [[self window] isKeyWindow];
- NSColor* aColor =
- [NSColor colorWithCalibratedRed:0.506 green:0.660 blue:0.985 alpha:1.000];
- NSColor* bColor =
- [NSColor colorWithCalibratedRed:0.099 green:0.140 blue:0.254 alpha:1.000];
- scoped_nsobject<NSGradient> gradient(
- [[NSGradient alloc] initWithStartingColor:aColor endingColor:bColor]);
-
- NSRect gradientRect = [self bounds];
- [gradient drawInRect:gradientRect angle:270.0];
-
- // Draw borders and any drop feedback.
- [super drawRect:rect];
-}
-
-@end
diff --git a/chrome/browser/cocoa/side_tab_strip_view_unittest.mm b/chrome/browser/cocoa/side_tab_strip_view_unittest.mm
deleted file mode 100644
index 79acebf..0000000
--- a/chrome/browser/cocoa/side_tab_strip_view_unittest.mm
+++ /dev/null
@@ -1,30 +0,0 @@
-// 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 "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/side_tab_strip_view.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-namespace {
-
-class SideTabStripViewTest : public CocoaTest {
- public:
- SideTabStripViewTest() {
- NSRect frame = NSMakeRect(0, 0, 100, 30);
- scoped_nsobject<SideTabStripView> view(
- [[SideTabStripView alloc] initWithFrame:frame]);
- view_ = view.get();
- [[test_window() contentView] addSubview:view_];
- }
-
- SideTabStripView* view_;
-};
-
-TEST_VIEW(SideTabStripViewTest, view_)
-
-} // namespace
diff --git a/chrome/browser/cocoa/sidebar_controller.h b/chrome/browser/cocoa/sidebar_controller.h
deleted file mode 100644
index 00c272a..0000000
--- a/chrome/browser/cocoa/sidebar_controller.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_SIDEBAR_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_SIDEBAR_CONTROLLER_H_
-#pragma once
-
-#import <Foundation/Foundation.h>
-
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/tab_contents_controller.h"
-
-@class NSSplitView;
-@class NSView;
-
-class TabContents;
-
-// A class that handles updates of the sidebar view within a browser window.
-// It swaps in the relevant sidebar contents for a given TabContents or removes
-// the vew, if there's no sidebar contents to show.
-@interface SidebarController : NSObject {
- @private
- // A view hosting sidebar contents.
- scoped_nsobject<NSSplitView> splitView_;
-
- // Manages currently displayed sidebar contents.
- scoped_nsobject<TabContentsController> contentsController_;
-}
-
-- (id)initWithDelegate:(id<TabContentsControllerDelegate>)delegate;
-
-// This controller's view.
-- (NSSplitView*)view;
-
-// The compiler seems to have trouble handling a function named "view" that
-// returns an NSSplitView, so provide a differently-named method.
-- (NSSplitView*)splitView;
-
-// Depending on |contents|'s state, decides whether the sidebar
-// should be shown or hidden and adjusts its width (|delegate_| handles
-// the actual resize).
-- (void)updateSidebarForTabContents:(TabContents*)contents;
-
-// Call when the sidebar view is properly sized and the render widget host view
-// should be put into the view hierarchy.
-- (void)ensureContentsVisible;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_SIDEBAR_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/sidebar_controller.mm b/chrome/browser/cocoa/sidebar_controller.mm
deleted file mode 100644
index d4dbe86..0000000
--- a/chrome/browser/cocoa/sidebar_controller.mm
+++ /dev/null
@@ -1,179 +0,0 @@
-// 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 "chrome/browser/cocoa/sidebar_controller.h"
-
-#include <algorithm>
-
-#include <Cocoa/Cocoa.h>
-
-#include "chrome/browser/browser_process.h"
-#import "chrome/browser/cocoa/view_id_util.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/sidebar/sidebar_manager.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/common/pref_names.h"
-
-namespace {
-
-// By default sidebar width is 1/7th of the current page content width.
-const CGFloat kDefaultSidebarWidthRatio = 1.0 / 7;
-
-// Never make the web part of the tab contents smaller than this (needed if the
-// window is only a few pixels wide).
-const int kMinWebWidth = 50;
-
-} // end namespace
-
-
-@interface SidebarController (Private)
-- (void)showSidebarContents:(TabContents*)sidebarContents;
-- (void)resizeSidebarToNewWidth:(CGFloat)width;
-@end
-
-
-@implementation SidebarController
-
-- (id)initWithDelegate:(id<TabContentsControllerDelegate>)delegate {
- if ((self = [super init])) {
- splitView_.reset([[NSSplitView alloc] initWithFrame:NSZeroRect]);
- [splitView_ setDividerStyle:NSSplitViewDividerStyleThin];
- [splitView_ setVertical:YES];
- [splitView_ setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
- [splitView_ setDelegate:self];
-
- contentsController_.reset(
- [[TabContentsController alloc] initWithContents:NULL
- delegate:delegate]);
- }
- return self;
-}
-
-- (void)dealloc {
- [splitView_ setDelegate:nil];
- [super dealloc];
-}
-
-- (NSSplitView*)view {
- return splitView_.get();
-}
-
-- (NSSplitView*)splitView {
- return splitView_.get();
-}
-
-- (void)updateSidebarForTabContents:(TabContents*)contents {
- // Get the active sidebar content.
- if (SidebarManager::GetInstance() == NULL) // Happens in tests.
- return;
-
- TabContents* sidebarContents = NULL;
- if (contents && SidebarManager::IsSidebarAllowed()) {
- SidebarContainer* activeSidebar =
- SidebarManager::GetInstance()->GetActiveSidebarContainerFor(contents);
- if (activeSidebar)
- sidebarContents = activeSidebar->sidebar_contents();
- }
-
- TabContents* oldSidebarContents = [contentsController_ tabContents];
- if (oldSidebarContents == sidebarContents)
- return;
-
- // Adjust sidebar view.
- [self showSidebarContents:sidebarContents];
-
- // Notify extensions.
- SidebarManager::GetInstance()->NotifyStateChanges(
- oldSidebarContents, sidebarContents);
-}
-
-- (void)ensureContentsVisible {
- [contentsController_ ensureContentsVisible];
-}
-
-- (void)showSidebarContents:(TabContents*)sidebarContents {
- [contentsController_ ensureContentsSizeDoesNotChange];
-
- NSArray* subviews = [splitView_ subviews];
- if (sidebarContents) {
- DCHECK_GE([subviews count], 1u);
-
- // Native view is a TabContentsViewCocoa object, whose ViewID was
- // set to VIEW_ID_TAB_CONTAINER initially, so change it to
- // VIEW_ID_SIDE_BAR_CONTAINER here.
- view_id_util::SetID(
- sidebarContents->GetNativeView(), VIEW_ID_SIDE_BAR_CONTAINER);
-
- CGFloat sidebarWidth = 0;
- if ([subviews count] == 1) {
- // Load the default split offset.
- sidebarWidth = g_browser_process->local_state()->GetInteger(
- prefs::kExtensionSidebarWidth);
- if (sidebarWidth < 0) {
- // Initial load, set to default value.
- sidebarWidth =
- NSWidth([splitView_ frame]) * kDefaultSidebarWidthRatio;
- }
- [splitView_ addSubview:[contentsController_ view]];
- } else {
- DCHECK_EQ([subviews count], 2u);
- sidebarWidth = NSWidth([[subviews objectAtIndex:1] frame]);
- }
-
- // Make sure |sidebarWidth| isn't too large or too small.
- sidebarWidth = std::min(sidebarWidth,
- NSWidth([splitView_ frame]) - kMinWebWidth);
- DCHECK_GE(sidebarWidth, 0) << "kMinWebWidth needs to be smaller than "
- << "smallest available tab contents space.";
- sidebarWidth = std::max(static_cast<CGFloat>(0), sidebarWidth);
-
- [self resizeSidebarToNewWidth:sidebarWidth];
- } else {
- if ([subviews count] > 1) {
- NSView* oldSidebarContentsView = [subviews objectAtIndex:1];
- // Store split offset when hiding sidebar window only.
- int sidebarWidth = NSWidth([oldSidebarContentsView frame]);
- g_browser_process->local_state()->SetInteger(
- prefs::kExtensionSidebarWidth, sidebarWidth);
- [oldSidebarContentsView removeFromSuperview];
- [splitView_ adjustSubviews];
- }
- }
-
- [contentsController_ changeTabContents:sidebarContents];
-}
-
-- (void)resizeSidebarToNewWidth:(CGFloat)width {
- NSArray* subviews = [splitView_ subviews];
-
- // It seems as if |-setPosition:ofDividerAtIndex:| should do what's needed,
- // but I can't figure out how to use it. Manually resize web and sidebar.
- // TODO(alekseys): either make setPosition:ofDividerAtIndex: work or to add a
- // category on NSSplitView to handle manual resizing.
- NSView* sidebarView = [subviews objectAtIndex:1];
- NSRect sidebarFrame = [sidebarView frame];
- sidebarFrame.size.width = width;
- [sidebarView setFrame:sidebarFrame];
-
- NSView* webView = [subviews objectAtIndex:0];
- NSRect webFrame = [webView frame];
- webFrame.size.width =
- NSWidth([splitView_ frame]) - ([splitView_ dividerThickness] + width);
- [webView setFrame:webFrame];
-
- [splitView_ adjustSubviews];
-}
-
-// NSSplitViewDelegate protocol.
-- (BOOL)splitView:(NSSplitView *)splitView
- shouldAdjustSizeOfSubview:(NSView *)subview {
- // Return NO for the sidebar view to indicate that it should not be resized
- // automatically. The sidebar keeps the width set by the user.
- if ([[splitView_ subviews] indexOfObject:subview] == 1)
- return NO;
- return YES;
-}
-
-@end
diff --git a/chrome/browser/cocoa/simple_content_exceptions_window_controller.h b/chrome/browser/cocoa/simple_content_exceptions_window_controller.h
deleted file mode 100644
index 0e29f68..0000000
--- a/chrome/browser/cocoa/simple_content_exceptions_window_controller.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// 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 "base/cocoa_protocols_mac.h"
-#include "base/scoped_ptr.h"
-#import "chrome/browser/cocoa/table_model_array_controller.h"
-#include "chrome/browser/remove_rows_table_model.h"
-
-class RemoveRowsObserverBridge;
-
-// Controller for the geolocation exception dialog.
-@interface SimpleContentExceptionsWindowController : NSWindowController
- <NSWindowDelegate> {
- @private
- IBOutlet NSTableView* tableView_;
- IBOutlet NSButton* removeButton_;
- IBOutlet NSButton* removeAllButton_;
- IBOutlet NSButton* doneButton_;
- IBOutlet TableModelArrayController* arrayController_;
-
- scoped_ptr<RemoveRowsTableModel> model_;
-}
-
-// Shows or makes frontmost the exceptions window.
-// Changes made by the user in the window are persisted in |model|.
-// Takes ownership of |model|.
-+ (id)controllerWithTableModel:(RemoveRowsTableModel*)model;
-
-// Sets the minimum width of the sheet and resizes it if necessary.
-- (void)setMinWidth:(CGFloat)minWidth;
-
-- (void)attachSheetTo:(NSWindow*)window;
-- (IBAction)closeSheet:(id)sender;
-
-@end
diff --git a/chrome/browser/cocoa/simple_content_exceptions_window_controller.mm b/chrome/browser/cocoa/simple_content_exceptions_window_controller.mm
deleted file mode 100644
index e61efa8..0000000
--- a/chrome/browser/cocoa/simple_content_exceptions_window_controller.mm
+++ /dev/null
@@ -1,125 +0,0 @@
-// 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 "chrome/browser/cocoa/simple_content_exceptions_window_controller.h"
-
-#include "app/l10n_util_mac.h"
-#include "app/table_model_observer.h"
-#include "base/logging.h"
-#import "base/mac_util.h"
-#import "base/scoped_nsobject.h"
-#include "base/sys_string_conversions.h"
-#include "grit/generated_resources.h"
-#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-
-@interface SimpleContentExceptionsWindowController (Private)
-- (id)initWithTableModel:(RemoveRowsTableModel*)model;
-@end
-
-namespace {
-
-const CGFloat kButtonBarHeight = 35.0;
-
-SimpleContentExceptionsWindowController* g_exceptionWindow = nil;
-
-} // namespace
-
-@implementation SimpleContentExceptionsWindowController
-
-+ (id)controllerWithTableModel:(RemoveRowsTableModel*)model {
- if (!g_exceptionWindow) {
- g_exceptionWindow = [[SimpleContentExceptionsWindowController alloc]
- initWithTableModel:model];
- }
- return g_exceptionWindow;
-}
-
-- (id)initWithTableModel:(RemoveRowsTableModel*)model {
- NSString* nibpath = [mac_util::MainAppBundle()
- pathForResource:@"SimpleContentExceptionsWindow"
- ofType:@"nib"];
- if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
- model_.reset(model);
-
- // TODO(thakis): autoremember window rect.
- // TODO(thakis): sorting support.
- }
- return self;
-}
-
-- (void)awakeFromNib {
- DCHECK([self window]);
- DCHECK_EQ(self, [[self window] delegate]);
- DCHECK(tableView_);
- DCHECK(arrayController_);
-
- CGFloat minWidth = [[removeButton_ superview] bounds].size.width +
- [[doneButton_ superview] bounds].size.width;
- [[self window] setMinSize:NSMakeSize(minWidth,
- [[self window] minSize].height)];
- NSDictionary* columns = [NSDictionary dictionaryWithObjectsAndKeys:
- [NSNumber numberWithInt:IDS_EXCEPTIONS_HOSTNAME_HEADER], @"hostname",
- [NSNumber numberWithInt:IDS_EXCEPTIONS_ACTION_HEADER], @"action",
- nil];
- [arrayController_ bindToTableModel:model_.get()
- withColumns:columns
- groupTitleColumn:@"hostname"];
-}
-
-- (void)setMinWidth:(CGFloat)minWidth {
- NSWindow* window = [self window];
- [window setMinSize:NSMakeSize(minWidth, [window minSize].height)];
- if ([window frame].size.width < minWidth) {
- NSRect frame = [window frame];
- frame.size.width = minWidth;
- [window setFrame:frame display:NO];
- }
-}
-
-- (void)windowWillClose:(NSNotification*)notification {
- g_exceptionWindow = nil;
- [self autorelease];
-}
-
-// Let esc close the window.
-- (void)cancel:(id)sender {
- [self closeSheet:self];
-}
-
-- (void)keyDown:(NSEvent*)event {
- NSString* chars = [event charactersIgnoringModifiers];
- if ([chars length] == 1) {
- switch ([chars characterAtIndex:0]) {
- case NSDeleteCharacter:
- case NSDeleteFunctionKey:
- // Delete deletes.
- if ([[tableView_ selectedRowIndexes] count] > 0)
- [arrayController_ remove:event];
- return;
- }
- }
- [super keyDown:event];
-}
-
-- (void)attachSheetTo:(NSWindow*)window {
- [NSApp beginSheet:[self window]
- modalForWindow:window
- modalDelegate:self
- didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
- contextInfo:nil];
-}
-
-- (void)sheetDidEnd:(NSWindow*)sheet
- returnCode:(NSInteger)returnCode
- contextInfo:(void*)context {
- [sheet close];
- [sheet orderOut:self];
-}
-
-- (IBAction)closeSheet:(id)sender {
- [NSApp endSheet:[self window]];
-}
-
-
-@end
diff --git a/chrome/browser/cocoa/simple_content_exceptions_window_controller_unittest.mm b/chrome/browser/cocoa/simple_content_exceptions_window_controller_unittest.mm
deleted file mode 100644
index 05b025c..0000000
--- a/chrome/browser/cocoa/simple_content_exceptions_window_controller_unittest.mm
+++ /dev/null
@@ -1,94 +0,0 @@
-// 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 "chrome/browser/cocoa/simple_content_exceptions_window_controller.h"
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/scoped_nsobject.h"
-#include "base/ref_counted.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/geolocation/geolocation_exceptions_table_model.h"
-#include "chrome/browser/host_content_settings_map.h"
-#include "chrome/browser/plugin_exceptions_table_model.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-@interface SimpleContentExceptionsWindowController (Testing)
-
-@property(readonly, nonatomic) TableModelArrayController* arrayController;
-
-@end
-
-@implementation SimpleContentExceptionsWindowController (Testing)
-
-- (TableModelArrayController*)arrayController {
- return arrayController_;
-}
-
-@end
-
-
-namespace {
-
-class SimpleContentExceptionsWindowControllerTest : public CocoaTest {
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
- TestingProfile* profile = browser_helper_.profile();
- geolocation_settings_ = new GeolocationContentSettingsMap(profile);
- content_settings_ = new HostContentSettingsMap(profile);
- }
-
- SimpleContentExceptionsWindowController* GetController() {
- GeolocationExceptionsTableModel* model = // Freed by window controller.
- new GeolocationExceptionsTableModel(geolocation_settings_.get());
- id controller = [SimpleContentExceptionsWindowController
- controllerWithTableModel:model];
- [controller showWindow:nil];
- return controller;
- }
-
- void ClickRemoveAll(SimpleContentExceptionsWindowController* controller) {
- [controller.arrayController removeAll:nil];
- }
-
- protected:
- BrowserTestHelper browser_helper_;
- scoped_refptr<GeolocationContentSettingsMap> geolocation_settings_;
- scoped_refptr<HostContentSettingsMap> content_settings_;
-};
-
-TEST_F(SimpleContentExceptionsWindowControllerTest, Construction) {
- GeolocationExceptionsTableModel* model = // Freed by window controller.
- new GeolocationExceptionsTableModel(geolocation_settings_.get());
- SimpleContentExceptionsWindowController* controller =
- [SimpleContentExceptionsWindowController controllerWithTableModel:model];
- [controller showWindow:nil];
- [controller close]; // Should autorelease.
-}
-
-TEST_F(SimpleContentExceptionsWindowControllerTest, ShowPluginExceptions) {
- PluginExceptionsTableModel* model = // Freed by window controller.
- new PluginExceptionsTableModel(content_settings_.get(), NULL);
- SimpleContentExceptionsWindowController* controller =
- [SimpleContentExceptionsWindowController controllerWithTableModel:model];
- [controller showWindow:nil];
- [controller close]; // Should autorelease.
-}
-
-TEST_F(SimpleContentExceptionsWindowControllerTest, AddExistingEditAdd) {
- geolocation_settings_->SetContentSetting(
- GURL("http://myhost"), GURL(), CONTENT_SETTING_BLOCK);
-
- SimpleContentExceptionsWindowController* controller = GetController();
- ClickRemoveAll(controller);
-
- [controller close];
-
- EXPECT_EQ(0u, geolocation_settings_->GetAllOriginsSettings().size());
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/speech_input_window_controller.h b/chrome/browser/cocoa/speech_input_window_controller.h
deleted file mode 100644
index 11000c2..0000000
--- a/chrome/browser/cocoa/speech_input_window_controller.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_SPEECH_INPUT_WINDOW_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_SPEECH_INPUT_WINDOW_CONTROLLER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "chrome/browser/cocoa/base_bubble_controller.h"
-#include "chrome/browser/speech/speech_input_bubble.h"
-
-// Controller for the speech input bubble window. This bubble window gets
-// displayed when the user starts speech input in a html input element.
-@interface SpeechInputWindowController : BaseBubbleController {
- @private
- SpeechInputBubble::Delegate* delegate_; // weak.
-
- // References below are weak, being obtained from the nib.
- IBOutlet NSImageView* iconImage_;
- IBOutlet NSTextField* instructionLabel_;
- IBOutlet NSButton* cancelButton_;
- IBOutlet NSButton* tryAgainButton_;
-}
-
-// Initialize the window. |anchoredAt| is in screen coordinates.
-- (id)initWithParentWindow:(NSWindow*)parentWindow
- delegate:(SpeechInputBubbleDelegate*)delegate
- anchoredAt:(NSPoint)anchoredAt;
-
-// Handler for the cancel button.
-- (IBAction)cancel:(id)sender;
-
-// Handler for the try again button.
-- (IBAction)tryAgain:(id)sender;
-
-// Updates the UI with data related to the given display mode.
-- (void)updateLayout:(SpeechInputBubbleBase::DisplayMode)mode
- messageText:(const string16&)messageText;
-
-// Makes the speech input bubble visible on screen.
-- (void)show;
-
-// Hides the speech input bubble away from screen. This does NOT release the
-// controller and the window.
-- (void)hide;
-
-// Sets the image to be displayed in the bubble's status ImageView. A future
-// call to updateLayout may change the image.
-// TODO(satish): Clean that up and move it into the platform independent
-// SpeechInputBubbleBase class.
-- (void)setImage:(NSImage*)image;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_SPEECH_INPUT_WINDOW_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/speech_input_window_controller.mm b/chrome/browser/cocoa/speech_input_window_controller.mm
deleted file mode 100644
index 005f37a..0000000
--- a/chrome/browser/cocoa/speech_input_window_controller.mm
+++ /dev/null
@@ -1,188 +0,0 @@
-// 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 "speech_input_window_controller.h"
-
-#include "app/l10n_util_mac.h"
-#include "app/resource_bundle.h"
-#include "base/logging.h"
-#include "base/mac_util.h"
-#include "base/sys_string_conversions.h"
-
-#include "chrome/browser/cocoa/info_bubble_view.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#import "skia/ext/skia_utils_mac.h"
-#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-
-const int kBubbleControlVerticalSpacing = 10; // Space between controls.
-const int kBubbleHorizontalMargin = 5; // Space on either sides of controls.
-
-@interface SpeechInputWindowController (Private)
-- (NSSize)calculateContentSize;
-- (void)layout:(NSSize)size;
-@end
-
-@implementation SpeechInputWindowController
-
-- (id)initWithParentWindow:(NSWindow*)parentWindow
- delegate:(SpeechInputBubbleDelegate*)delegate
- anchoredAt:(NSPoint)anchoredAt {
- anchoredAt.y += info_bubble::kBubbleArrowHeight / 2.0;
- if ((self = [super initWithWindowNibPath:@"SpeechInputBubble"
- parentWindow:parentWindow
- anchoredAt:anchoredAt])) {
- DCHECK(delegate);
- delegate_ = delegate;
-
- [self showWindow:nil];
- }
- return self;
-}
-
-- (void)awakeFromNib {
- [super awakeFromNib];
-
- NSWindow* window = [self window];
- [[self bubble] setArrowLocation:info_bubble::kTopLeft];
-
- NSSize newSize = [self calculateContentSize];
- [[self bubble] setFrameSize:newSize];
- NSSize windowDelta = NSMakeSize(
- newSize.width - NSWidth([[window contentView] bounds]),
- newSize.height - NSHeight([[window contentView] bounds]));
- windowDelta = [[window contentView] convertSize:windowDelta toView:nil];
- NSRect newFrame = [window frame];
- newFrame.size.width += windowDelta.width;
- newFrame.size.height += windowDelta.height;
- [window setFrame:newFrame display:NO];
-
- [self layout:newSize]; // Layout all the child controls.
-}
-
-- (IBAction)cancel:(id)sender {
- delegate_->InfoBubbleButtonClicked(SpeechInputBubble::BUTTON_CANCEL);
-}
-
-- (IBAction)tryAgain:(id)sender {
- delegate_->InfoBubbleButtonClicked(SpeechInputBubble::BUTTON_TRY_AGAIN);
-}
-
-// Calculate the window dimensions to reflect the sum height and max width of
-// all controls, with appropriate spacing between and around them. The returned
-// size is in view coordinates.
-- (NSSize)calculateContentSize {
- [GTMUILocalizerAndLayoutTweaker sizeToFitView:cancelButton_];
- [GTMUILocalizerAndLayoutTweaker sizeToFitView:tryAgainButton_];
- NSSize cancelSize = [cancelButton_ bounds].size;
- NSSize tryAgainSize = [tryAgainButton_ bounds].size;
- int newHeight = cancelSize.height + kBubbleControlVerticalSpacing;
- int newWidth = cancelSize.width + tryAgainSize.width;
-
- if (![iconImage_ isHidden]) {
- NSImage* icon = ResourceBundle::GetSharedInstance().GetNativeImageNamed(
- IDR_SPEECH_INPUT_MIC_EMPTY);
- NSSize size = [icon size];
- newHeight += size.height + kBubbleControlVerticalSpacing;
- if (newWidth < size.width)
- newWidth = size.width;
- } else {
- newHeight += kBubbleControlVerticalSpacing;
- }
-
- [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:
- instructionLabel_];
- NSSize size = [instructionLabel_ bounds].size;
- newHeight += size.height;
- if (newWidth < size.width)
- newWidth = size.width;
-
- return NSMakeSize(newWidth + 2 * kBubbleHorizontalMargin,
- newHeight + 2 * kBubbleControlVerticalSpacing);
-}
-
-// Position the controls within the given content area bounds.
-- (void)layout:(NSSize)size {
- int y = kBubbleControlVerticalSpacing;
-
- NSRect cancelRect = [cancelButton_ bounds];
-
- if ([tryAgainButton_ isHidden]) {
- cancelRect.origin.x = (size.width - NSWidth(cancelRect)) / 2;
- } else {
- NSRect tryAgainRect = [tryAgainButton_ bounds];
- cancelRect.origin.x = (size.width - NSWidth(cancelRect) -
- NSWidth(tryAgainRect)) / 2;
- tryAgainRect.origin.x = cancelRect.origin.x + NSWidth(cancelRect);
- tryAgainRect.origin.y = y;
- [tryAgainButton_ setFrame:tryAgainRect];
- }
- cancelRect.origin.y = y;
- [cancelButton_ setFrame:cancelRect];
-
- y += NSHeight(cancelRect) + kBubbleControlVerticalSpacing;
-
- NSRect rect;
- if (![iconImage_ isHidden]) {
- rect = [iconImage_ bounds];
- rect.origin.x = (size.width - NSWidth(rect)) / 2;
- rect.origin.y = y;
- [iconImage_ setFrame:rect];
- y += rect.size.height + kBubbleControlVerticalSpacing;
- }
-
- rect = [instructionLabel_ bounds];
- rect.origin.x = (size.width - NSWidth(rect)) / 2;
- rect.origin.y = y;
- [instructionLabel_ setFrame:rect];
-}
-
-- (void)updateLayout:(SpeechInputBubbleBase::DisplayMode)mode
- messageText:(const string16&)messageText {
- // Get the right set of controls to be visible.
- if (mode == SpeechInputBubbleBase::DISPLAY_MODE_MESSAGE) {
- [instructionLabel_ setStringValue:base::SysUTF16ToNSString(messageText)];
- [iconImage_ setHidden:YES];
- [tryAgainButton_ setHidden:NO];
- } else {
- if (mode == SpeechInputBubbleBase::DISPLAY_MODE_RECORDING) {
- [instructionLabel_ setStringValue:l10n_util::GetNSString(
- IDS_SPEECH_INPUT_BUBBLE_HEADING)];
- NSImage* icon = ResourceBundle::GetSharedInstance().GetNativeImageNamed(
- IDR_SPEECH_INPUT_MIC_EMPTY);
- [iconImage_ setImage:icon];
- } else {
- [instructionLabel_ setStringValue:l10n_util::GetNSString(
- IDS_SPEECH_INPUT_BUBBLE_WORKING)];
- }
- [iconImage_ setHidden:NO];
- [iconImage_ setNeedsDisplay:YES];
- [tryAgainButton_ setHidden:YES];
- }
-
- NSSize newSize = [self calculateContentSize];
- NSRect rect = [[self bubble] frame];
- rect.origin.y -= newSize.height - rect.size.height;
- rect.size = newSize;
- [[self bubble] setFrame:rect];
- [self layout:newSize];
-}
-
-- (void)windowWillClose:(NSNotification*)notification {
- delegate_->InfoBubbleFocusChanged();
-}
-
-- (void)show {
- [self showWindow:nil];
-}
-
-- (void)hide {
- [[self window] orderOut:nil];
-}
-
-- (void)setImage:(NSImage*)image {
- [iconImage_ setImage:image];
-}
-
-@end // implementation SpeechInputWindowController
diff --git a/chrome/browser/cocoa/ssl_client_certificate_selector.mm b/chrome/browser/cocoa/ssl_client_certificate_selector.mm
deleted file mode 100644
index c72e00f..0000000
--- a/chrome/browser/cocoa/ssl_client_certificate_selector.mm
+++ /dev/null
@@ -1,195 +0,0 @@
-// 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.
-
-#include "chrome/browser/ssl_client_certificate_selector.h"
-
-#import <SecurityInterface/SFChooseIdentityPanel.h>
-
-#include <vector>
-
-#import "app/l10n_util_mac.h"
-#include "base/logging.h"
-#include "base/ref_counted.h"
-#import "base/scoped_nsobject.h"
-#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_thread.h"
-#import "chrome/browser/cocoa/constrained_window_mac.h"
-#include "chrome/browser/ssl/ssl_client_auth_handler.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "grit/generated_resources.h"
-#include "net/base/x509_certificate.h"
-
-namespace {
-
-class ConstrainedSFChooseIdentityPanel
- : public ConstrainedWindowMacDelegateSystemSheet {
- public:
- ConstrainedSFChooseIdentityPanel(SFChooseIdentityPanel* panel,
- id delegate, SEL didEndSelector,
- NSArray* identities, NSString* message)
- : ConstrainedWindowMacDelegateSystemSheet(delegate, didEndSelector),
- identities_([identities retain]),
- message_([message retain]) {
- set_sheet(panel);
- }
-
- virtual ~ConstrainedSFChooseIdentityPanel() {
- // As required by ConstrainedWindowMacDelegate, close the sheet if
- // it's still open.
- if (is_sheet_open()) {
- [NSApp endSheet:sheet()
- returnCode:NSFileHandlingPanelCancelButton];
- }
- }
-
- // ConstrainedWindowMacDelegateSystemSheet implementation:
- virtual void DeleteDelegate() {
- delete this;
- }
-
- // SFChooseIdentityPanel's beginSheetForWindow: method has more arguments
- // than the usual one. Also pass the panel through contextInfo argument
- // because the callback has the wrong signature.
- virtual NSArray* GetSheetParameters(id delegate, SEL didEndSelector) {
- return [NSArray arrayWithObjects:
- [NSNull null], // window, must be [NSNull null]
- delegate,
- [NSValue valueWithPointer:didEndSelector],
- [NSValue valueWithPointer:sheet()],
- identities_.get(),
- message_.get(),
- nil];
- }
-
- private:
- scoped_nsobject<NSArray> identities_;
- scoped_nsobject<NSString> message_;
- DISALLOW_COPY_AND_ASSIGN(ConstrainedSFChooseIdentityPanel);
-};
-
-} // namespace
-
-@interface SSLClientCertificateSelectorCocoa : NSObject {
- @private
- // The handler to report back to.
- scoped_refptr<SSLClientAuthHandler> handler_;
- // The certificate request we serve.
- scoped_refptr<net::SSLCertRequestInfo> certRequestInfo_;
- // The list of identities offered to the user.
- scoped_nsobject<NSMutableArray> identities_;
- // The corresponding list of certificates.
- std::vector<scoped_refptr<net::X509Certificate> > certificates_;
- // The currently open dialog.
- ConstrainedWindow* window_;
-}
-
-- (id)initWithHandler:(SSLClientAuthHandler*)handler
- certRequestInfo:(net::SSLCertRequestInfo*)certRequestInfo;
-- (void)displayDialog:(TabContents*)parent;
-@end
-
-namespace browser {
-
-void ShowSSLClientCertificateSelector(
- TabContents* parent,
- net::SSLCertRequestInfo* cert_request_info,
- SSLClientAuthHandler* delegate) {
- // TODO(davidben): Implement a tab-modal dialog.
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- SSLClientCertificateSelectorCocoa* selector =
- [[[SSLClientCertificateSelectorCocoa alloc]
- initWithHandler:delegate
- certRequestInfo:cert_request_info] autorelease];
- [selector displayDialog:parent];
-}
-
-} // namespace browser
-
-@implementation SSLClientCertificateSelectorCocoa
-
-- (id)initWithHandler:(SSLClientAuthHandler*)handler
- certRequestInfo:(net::SSLCertRequestInfo*)certRequestInfo {
- DCHECK(handler);
- DCHECK(certRequestInfo);
- if ((self = [super init])) {
- handler_ = handler;
- certRequestInfo_ = certRequestInfo;
- window_ = NULL;
- }
- return self;
-}
-
-- (void)sheetDidEnd:(NSWindow*)parent
- returnCode:(NSInteger)returnCode
- context:(void*)context {
- DCHECK(context);
- SFChooseIdentityPanel* panel = static_cast<SFChooseIdentityPanel*>(context);
-
- net::X509Certificate* cert = NULL;
- if (returnCode == NSFileHandlingPanelOKButton) {
- NSUInteger index = [identities_ indexOfObject:(id)[panel identity]];
- if (index != NSNotFound)
- cert = certificates_[index];
- else
- NOTREACHED();
- }
-
- // Finally, tell the backend which identity (or none) the user selected.
- handler_->CertificateSelected(cert);
- // Close the constrained window.
- DCHECK(window_);
- window_->CloseConstrainedWindow();
-
- // Now that the panel has closed, release it. Note that the autorelease is
- // needed. After this callback returns, the panel is still accessed, so a
- // normal release crashes.
- [panel autorelease];
-}
-
-- (void)displayDialog:(TabContents*)parent {
- DCHECK(!window_);
- // Create an array of CFIdentityRefs for the certificates:
- size_t numCerts = certRequestInfo_->client_certs.size();
- identities_.reset([[NSMutableArray alloc] initWithCapacity:numCerts]);
- for (size_t i = 0; i < numCerts; ++i) {
- SecCertificateRef cert;
- cert = certRequestInfo_->client_certs[i]->os_cert_handle();
- SecIdentityRef identity;
- if (SecIdentityCreateWithCertificate(NULL, cert, &identity) == noErr) {
- [identities_ addObject:(id)identity];
- CFRelease(identity);
- certificates_.push_back(certRequestInfo_->client_certs[i]);
- }
- }
-
- // Get the message to display:
- NSString* title = l10n_util::GetNSString(IDS_CLIENT_CERT_DIALOG_TITLE);
- NSString* message = l10n_util::GetNSStringF(
- IDS_CLIENT_CERT_DIALOG_TEXT,
- ASCIIToUTF16(certRequestInfo_->host_and_port));
-
- // Create and set up a system choose-identity panel.
- SFChooseIdentityPanel* panel = [[SFChooseIdentityPanel alloc] init];
- [panel setInformativeText:message];
- [panel setDefaultButtonTitle:l10n_util::GetNSString(IDS_OK)];
- [panel setAlternateButtonTitle:l10n_util::GetNSString(IDS_CANCEL)];
- SecPolicyRef sslPolicy;
- if (net::X509Certificate::CreateSSLClientPolicy(&sslPolicy) == noErr) {
- [panel setPolicies:(id)sslPolicy];
- CFRelease(sslPolicy);
- }
-
- window_ =
- parent->CreateConstrainedDialog(new ConstrainedSFChooseIdentityPanel(
- panel, self,
- @selector(sheetDidEnd:returnCode:context:),
- identities_, title));
- // Note: SFChooseIdentityPanel does not take a reference to itself while the
- // sheet is open. Don't release the ownership claim until the sheet has ended
- // in |-sheetDidEnd:returnCode:context:|.
-}
-
-@end
diff --git a/chrome/browser/cocoa/status_bubble_mac.h b/chrome/browser/cocoa/status_bubble_mac.h
deleted file mode 100644
index de331d4..0000000
--- a/chrome/browser/cocoa/status_bubble_mac.h
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_STATUS_BUBBLE_MAC_H_
-#define CHROME_BROWSER_COCOA_STATUS_BUBBLE_MAC_H_
-#pragma once
-
-#include <string>
-
-#import <Cocoa/Cocoa.h>
-#import <QuartzCore/QuartzCore.h>
-
-#include "base/string16.h"
-#include "base/task.h"
-#include "chrome/browser/status_bubble.h"
-#include "googleurl/src/gurl.h"
-
-class GURL;
-class StatusBubbleMacTest;
-
-class StatusBubbleMac : public StatusBubble {
- public:
- // The various states that a status bubble may be in. Public for delegate
- // access (for testing).
- enum StatusBubbleState {
- kBubbleHidden, // Fully hidden
- kBubbleShowingTimer, // Waiting to fade in
- kBubbleShowingFadeIn, // In a fade-in transition
- kBubbleShown, // Fully visible
- kBubbleHidingTimer, // Waiting to fade out
- kBubbleHidingFadeOut // In a fade-out transition
- };
-
- StatusBubbleMac(NSWindow* parent, id delegate);
- virtual ~StatusBubbleMac();
-
- // StatusBubble implementation.
- virtual void SetStatus(const string16& status);
- virtual void SetURL(const GURL& url, const string16& languages);
- virtual void Hide();
- virtual void MouseMoved(const gfx::Point& location, bool left_content);
- virtual void UpdateDownloadShelfVisibility(bool visible);
-
- // Mac-specific method: Update the size and position of the status bubble to
- // match the parent window. Safe to call even when the status bubble does not
- // exist.
- void UpdateSizeAndPosition();
-
- // Mac-specific method: Change the parent window of the status bubble. Safe to
- // call even when the status bubble does not exist.
- void SwitchParentWindow(NSWindow* parent);
-
- // Delegate method called when a fade-in or fade-out transition has
- // completed. This is public so that it may be visible to the CAAnimation
- // delegate, which is an Objective-C object.
- void AnimationDidStop(CAAnimation* animation, bool finished);
-
- // Expand the bubble to fit a URL too long for the standard bubble size.
- void ExpandBubble();
-
- private:
- friend class StatusBubbleMacTest;
-
- // Setter for state_. Use this instead of writing to state_ directly so
- // that state changes can be observed by unit tests.
- void SetState(StatusBubbleState state);
-
- // Sets the bubble text for SetStatus and SetURL.
- void SetText(const string16& text, bool is_url);
-
- // Construct the window/widget if it does not already exist. (Safe to call if
- // it does.)
- void Create();
-
- // Attaches the status bubble window to its parent window. Safe to call even
- // when already attached.
- void Attach();
-
- // Detaches the status bubble window from its parent window.
- void Detach();
-
- // Is the status bubble attached to the browser window? It should be attached
- // when shown and during any fades, but should be detached when hidden.
- bool is_attached() { return [window_ parentWindow] != nil; }
-
- // Begins fading the status bubble window in or out depending on the value
- // of |show|. This must be called from the appropriate fade state,
- // kBubbleShowingFadeIn or kBubbleHidingFadeOut, or from the appropriate
- // fully-shown/hidden state, kBubbleShown or kBubbleHidden. This may be
- // called at any point during a fade-in or fade-out; it is even possible to
- // reverse a transition before it has completed.
- void Fade(bool show);
-
- // One-shot timer operations to manage the delays associated with the
- // kBubbleShowingTimer and kBubbleHidingTimer states. StartTimer and
- // TimerFired must be called from one of these states. StartTimer may be
- // called while the timer is still running; in that case, the timer will be
- // reset. CancelTimer may be called from any state.
- void StartTimer(int64 time_ms);
- void CancelTimer();
- void TimerFired();
-
- // Begin the process of showing or hiding the status bubble. These may be
- // called from any state, and will take the appropriate action to initiate
- // any state changes that may be needed.
- void StartShowing();
- void StartHiding();
-
- // Cancel the expansion timer.
- void CancelExpandTimer();
-
- // The timer factory used for show and hide delay timers.
- ScopedRunnableMethodFactory<StatusBubbleMac> timer_factory_;
-
- // The timer factory used for the expansion delay timer.
- ScopedRunnableMethodFactory<StatusBubbleMac> expand_timer_factory_;
-
- // Calculate the appropriate frame for the status bubble window. If
- // |expanded_width|, use entire width of parent frame.
- NSRect CalculateWindowFrame(bool expanded_width);
-
- // The window we attach ourselves to.
- NSWindow* parent_; // WEAK
-
- // The object that we query about our vertical offset for positioning.
- id delegate_; // WEAK
-
- // The window we own.
- NSWindow* window_;
-
- // The status text we want to display when there are no URLs to display.
- NSString* status_text_;
-
- // The url we want to display when there is no status text to display.
- NSString* url_text_;
-
- // The status bubble's current state. Do not write to this field directly;
- // use SetState().
- StatusBubbleState state_;
-
- // True if operations are to be performed immediately rather than waiting
- // for delays and transitions. Normally false, this should only be set to
- // true for testing.
- bool immediate_;
-
- // True if the status bubble has been expanded. If the bubble is in the
- // expanded state and encounters a new URL, change size immediately,
- // with no hover delay.
- bool is_expanded_;
-
- // The original, non-elided URL.
- GURL url_;
-
- // Needs to be passed to ElideURL if the original URL string is wider than
- // the standard bubble width.
- string16 languages_;
-
- DISALLOW_COPY_AND_ASSIGN(StatusBubbleMac);
-};
-
-// Delegate interface
-@interface NSObject(StatusBubbleDelegate)
-// Called to query the delegate about the frame StatusBubble should position
-// itself in. Frame is returned in the parent window coordinates.
-- (NSRect)statusBubbleBaseFrame;
-
-// Called from SetState to notify the delegate of state changes.
-- (void)statusBubbleWillEnterState:(StatusBubbleMac::StatusBubbleState)state;
-@end
-
-#endif // CHROME_BROWSER_COCOA_STATUS_BUBBLE_MAC_H_
diff --git a/chrome/browser/cocoa/status_bubble_mac.mm b/chrome/browser/cocoa/status_bubble_mac.mm
deleted file mode 100644
index 58da593..0000000
--- a/chrome/browser/cocoa/status_bubble_mac.mm
+++ /dev/null
@@ -1,705 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/status_bubble_mac.h"
-
-#include <limits>
-
-#include "app/text_elider.h"
-#include "base/compiler_specific.h"
-#include "base/message_loop.h"
-#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#import "chrome/browser/cocoa/bubble_view.h"
-#include "gfx/point.h"
-#include "net/base/net_util.h"
-#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
-#import "third_party/GTM/AppKit/GTMNSBezierPath+RoundRect.h"
-#import "third_party/GTM/AppKit/GTMNSColor+Luminance.h"
-
-namespace {
-
-const int kWindowHeight = 18;
-
-// The width of the bubble in relation to the width of the parent window.
-const CGFloat kWindowWidthPercent = 1.0 / 3.0;
-
-// How close the mouse can get to the infobubble before it starts sliding
-// off-screen.
-const int kMousePadding = 20;
-
-const int kTextPadding = 3;
-
-// The animation key used for fade-in and fade-out transitions.
-NSString* const kFadeAnimationKey = @"alphaValue";
-
-// The status bubble's maximum opacity, when fully faded in.
-const CGFloat kBubbleOpacity = 1.0;
-
-// Delay before showing or hiding the bubble after a SetStatus or SetURL call.
-const int64 kShowDelayMilliseconds = 80;
-const int64 kHideDelayMilliseconds = 250;
-
-// How long each fade should last.
-const NSTimeInterval kShowFadeInDurationSeconds = 0.120;
-const NSTimeInterval kHideFadeOutDurationSeconds = 0.200;
-
-// The minimum representable time interval. This can be used as the value
-// passed to +[NSAnimationContext setDuration:] to stop an in-progress
-// animation as quickly as possible.
-const NSTimeInterval kMinimumTimeInterval =
- std::numeric_limits<NSTimeInterval>::min();
-
-// How quickly the status bubble should expand, in seconds.
-const CGFloat kExpansionDuration = 0.125;
-
-} // namespace
-
-@interface StatusBubbleAnimationDelegate : NSObject {
- @private
- StatusBubbleMac* statusBubble_; // weak; owns us indirectly
-}
-
-- (id)initWithStatusBubble:(StatusBubbleMac*)statusBubble;
-
-// Invalidates this object so that no further calls will be made to
-// statusBubble_. This should be called when statusBubble_ is released, to
-// prevent attempts to call into the released object.
-- (void)invalidate;
-
-// CAAnimation delegate method
-- (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)finished;
-@end
-
-@implementation StatusBubbleAnimationDelegate
-
-- (id)initWithStatusBubble:(StatusBubbleMac*)statusBubble {
- if ((self = [super init])) {
- statusBubble_ = statusBubble;
- }
-
- return self;
-}
-
-- (void)invalidate {
- statusBubble_ = NULL;
-}
-
-- (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)finished {
- if (statusBubble_)
- statusBubble_->AnimationDidStop(animation, finished ? true : false);
-}
-
-@end
-
-StatusBubbleMac::StatusBubbleMac(NSWindow* parent, id delegate)
- : ALLOW_THIS_IN_INITIALIZER_LIST(timer_factory_(this)),
- ALLOW_THIS_IN_INITIALIZER_LIST(expand_timer_factory_(this)),
- parent_(parent),
- delegate_(delegate),
- window_(nil),
- status_text_(nil),
- url_text_(nil),
- state_(kBubbleHidden),
- immediate_(false),
- is_expanded_(false) {
-}
-
-StatusBubbleMac::~StatusBubbleMac() {
- Hide();
-
- if (window_) {
- [[[window_ animationForKey:kFadeAnimationKey] delegate] invalidate];
- Detach();
- [window_ release];
- window_ = nil;
- }
-}
-
-void StatusBubbleMac::SetStatus(const string16& status) {
- Create();
-
- SetText(status, false);
-}
-
-void StatusBubbleMac::SetURL(const GURL& url, const string16& languages) {
- url_ = url;
- languages_ = languages;
-
- Create();
-
- NSRect frame = [window_ frame];
-
- // Reset frame size when bubble is hidden.
- if (state_ == kBubbleHidden) {
- is_expanded_ = false;
- frame.size.width = NSWidth(CalculateWindowFrame(/*expand=*/false));
- [window_ setFrame:frame display:NO];
- }
-
- int text_width = static_cast<int>(NSWidth(frame) -
- kBubbleViewTextPositionX -
- kTextPadding);
-
- // Scale from view to window coordinates before eliding URL string.
- NSSize scaled_width = NSMakeSize(text_width, 0);
- scaled_width = [[parent_ contentView] convertSize:scaled_width fromView:nil];
- text_width = static_cast<int>(scaled_width.width);
- NSFont* font = [[window_ contentView] font];
- gfx::Font font_chr(base::SysNSStringToWide([font fontName]),
- [font pointSize]);
-
- string16 original_url_text = net::FormatUrl(url, UTF16ToUTF8(languages));
- string16 status = gfx::ElideUrl(url, font_chr, text_width,
- UTF16ToWideHack(languages));
-
- SetText(status, true);
-
- // In testing, don't use animation. When ExpandBubble is tested, it is
- // called explicitly.
- if (immediate_)
- return;
- else
- CancelExpandTimer();
-
- // If the bubble has been expanded, the user has already hovered over a link
- // to trigger the expanded state. Don't wait to change the bubble in this
- // case -- immediately expand or contract to fit the URL.
- if (is_expanded_ && !url.is_empty()) {
- ExpandBubble();
- } else if (original_url_text.length() > status.length()) {
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- expand_timer_factory_.NewRunnableMethod(
- &StatusBubbleMac::ExpandBubble), kExpandHoverDelay);
- }
-}
-
-void StatusBubbleMac::SetText(const string16& text, bool is_url) {
- // The status bubble allows the status and URL strings to be set
- // independently. Whichever was set non-empty most recently will be the
- // value displayed. When both are empty, the status bubble hides.
-
- NSString* text_ns = base::SysUTF16ToNSString(text);
-
- NSString** main;
- NSString** backup;
-
- if (is_url) {
- main = &url_text_;
- backup = &status_text_;
- } else {
- main = &status_text_;
- backup = &url_text_;
- }
-
- // Don't return from this function early. It's important to make sure that
- // all calls to StartShowing and StartHiding are made, so that all delays
- // are observed properly. Specifically, if the state is currently
- // kBubbleShowingTimer, the timer will need to be restarted even if
- // [text_ns isEqualToString:*main] is true.
-
- [*main autorelease];
- *main = [text_ns retain];
-
- bool show = true;
- if ([*main length] > 0)
- [[window_ contentView] setContent:*main];
- else if ([*backup length] > 0)
- [[window_ contentView] setContent:*backup];
- else
- show = false;
-
- if (show)
- StartShowing();
- else
- StartHiding();
-}
-
-void StatusBubbleMac::Hide() {
- CancelTimer();
- CancelExpandTimer();
- is_expanded_ = false;
-
- bool fade_out = false;
- if (state_ == kBubbleHidingFadeOut || state_ == kBubbleShowingFadeIn) {
- SetState(kBubbleHidingFadeOut);
-
- if (!immediate_) {
- // An animation is in progress. Cancel it by starting a new animation.
- // Use kMinimumTimeInterval to set the opacity as rapidly as possible.
- fade_out = true;
- [NSAnimationContext beginGrouping];
- [[NSAnimationContext currentContext] setDuration:kMinimumTimeInterval];
- [[window_ animator] setAlphaValue:0.0];
- [NSAnimationContext endGrouping];
- }
- }
-
- if (!fade_out) {
- // No animation is in progress, so the opacity can be set directly.
- [window_ setAlphaValue:0.0];
- SetState(kBubbleHidden);
- }
-
- // Stop any width animation and reset the bubble size.
- if (!immediate_) {
- [NSAnimationContext beginGrouping];
- [[NSAnimationContext currentContext] setDuration:kMinimumTimeInterval];
- [[window_ animator] setFrame:CalculateWindowFrame(/*expand=*/false)
- display:NO];
- [NSAnimationContext endGrouping];
- } else {
- [window_ setFrame:CalculateWindowFrame(/*expand=*/false) display:NO];
- }
-
- [status_text_ release];
- status_text_ = nil;
- [url_text_ release];
- url_text_ = nil;
-}
-
-void StatusBubbleMac::MouseMoved(
- const gfx::Point& location, bool left_content) {
- if (left_content)
- return;
-
- if (!window_)
- return;
-
- // TODO(thakis): Use 'location' here instead of NSEvent.
- NSPoint cursor_location = [NSEvent mouseLocation];
- --cursor_location.y; // docs say the y coord starts at 1 not 0; don't ask why
-
- // Bubble's base frame in |parent_| coordinates.
- NSRect baseFrame;
- if ([delegate_ respondsToSelector:@selector(statusBubbleBaseFrame)])
- baseFrame = [delegate_ statusBubbleBaseFrame];
- else
- baseFrame = [[parent_ contentView] frame];
-
- // Get the normal position of the frame.
- NSRect window_frame = [window_ frame];
- window_frame.origin = [parent_ convertBaseToScreen:baseFrame.origin];
-
- // Get the cursor position relative to the popup.
- cursor_location.x -= NSMaxX(window_frame);
- cursor_location.y -= NSMaxY(window_frame);
-
-
- // If the mouse is in a position where we think it would move the
- // status bubble, figure out where and how the bubble should be moved.
- if (cursor_location.y < kMousePadding &&
- cursor_location.x < kMousePadding) {
- int offset = kMousePadding - cursor_location.y;
-
- // Make the movement non-linear.
- offset = offset * offset / kMousePadding;
-
- // When the mouse is entering from the right, we want the offset to be
- // scaled by how horizontally far away the cursor is from the bubble.
- if (cursor_location.x > 0) {
- offset = offset * ((kMousePadding - cursor_location.x) / kMousePadding);
- }
-
- bool isOnScreen = true;
- NSScreen* screen = [window_ screen];
- if (screen &&
- NSMinY([screen visibleFrame]) > NSMinY(window_frame) - offset) {
- isOnScreen = false;
- }
-
- // If something is shown below tab contents (devtools, download shelf etc.),
- // adjust the position to sit on top of it.
- bool isAnyShelfVisible = NSMinY(baseFrame) > 0;
-
- if (isOnScreen && !isAnyShelfVisible) {
- // Cap the offset and change the visual presentation of the bubble
- // depending on where it ends up (so that rounded corners square off
- // and mate to the edges of the tab content).
- if (offset >= NSHeight(window_frame)) {
- offset = NSHeight(window_frame);
- [[window_ contentView] setCornerFlags:
- kRoundedBottomLeftCorner | kRoundedBottomRightCorner];
- } else if (offset > 0) {
- [[window_ contentView] setCornerFlags:
- kRoundedTopRightCorner | kRoundedBottomLeftCorner |
- kRoundedBottomRightCorner];
- } else {
- [[window_ contentView] setCornerFlags:kRoundedTopRightCorner];
- }
- window_frame.origin.y -= offset;
- } else {
- // Cannot move the bubble down without obscuring other content.
- // Move it to the right instead.
- [[window_ contentView] setCornerFlags:kRoundedTopLeftCorner];
-
- // Subtract border width + bubble width.
- window_frame.origin.x += NSWidth(baseFrame) - NSWidth(window_frame);
- }
- } else {
- [[window_ contentView] setCornerFlags:kRoundedTopRightCorner];
- }
-
- [window_ setFrame:window_frame display:YES];
-}
-
-void StatusBubbleMac::UpdateDownloadShelfVisibility(bool visible) {
-}
-
-void StatusBubbleMac::Create() {
- if (window_)
- return;
-
- // TODO(avi):fix this for RTL
- NSRect window_rect = CalculateWindowFrame(/*expand=*/false);
- // initWithContentRect has origin in screen coords and size in scaled window
- // coordinates.
- window_rect.size =
- [[parent_ contentView] convertSize:window_rect.size fromView:nil];
- window_ = [[NSWindow alloc] initWithContentRect:window_rect
- styleMask:NSBorderlessWindowMask
- backing:NSBackingStoreBuffered
- defer:YES];
- [window_ setMovableByWindowBackground:NO];
- [window_ setBackgroundColor:[NSColor clearColor]];
- [window_ setLevel:NSNormalWindowLevel];
- [window_ setOpaque:NO];
- [window_ setHasShadow:NO];
-
- // We do not need to worry about the bubble outliving |parent_| because our
- // teardown sequence in BWC guarantees that |parent_| outlives the status
- // bubble and that the StatusBubble is torn down completely prior to the
- // window going away.
- scoped_nsobject<BubbleView> view(
- [[BubbleView alloc] initWithFrame:NSZeroRect themeProvider:parent_]);
- [window_ setContentView:view];
-
- [window_ setAlphaValue:0.0];
-
- // Set a delegate for the fade-in and fade-out transitions to be notified
- // when fades are complete. The ownership model is for window_ to own
- // animation_dictionary, which owns animation, which owns
- // animation_delegate.
- CAAnimation* animation = [[window_ animationForKey:kFadeAnimationKey] copy];
- [animation autorelease];
- StatusBubbleAnimationDelegate* animation_delegate =
- [[StatusBubbleAnimationDelegate alloc] initWithStatusBubble:this];
- [animation_delegate autorelease];
- [animation setDelegate:animation_delegate];
- NSMutableDictionary* animation_dictionary =
- [NSMutableDictionary dictionaryWithDictionary:[window_ animations]];
- [animation_dictionary setObject:animation forKey:kFadeAnimationKey];
- [window_ setAnimations:animation_dictionary];
-
- // Don't |Attach()| since we don't know the appropriate state; let the
- // |SetState()| call do that.
-
- [view setCornerFlags:kRoundedTopRightCorner];
- MouseMoved(gfx::Point(), false);
-}
-
-void StatusBubbleMac::Attach() {
- // This method may be called several times during the process of creating or
- // showing a status bubble to attach the bubble to its parent window.
- if (!is_attached()) {
- [parent_ addChildWindow:window_ ordered:NSWindowAbove];
- UpdateSizeAndPosition();
- }
-}
-
-void StatusBubbleMac::Detach() {
- // This method may be called several times in the process of hiding or
- // destroying a status bubble.
- if (is_attached()) {
- // Magic setFrame: See crbug.com/58506, and codereview.chromium.org/3573014
- [window_ setFrame:CalculateWindowFrame(/*expand=*/false) display:NO];
- [parent_ removeChildWindow:window_]; // See crbug.com/28107 ...
- [window_ orderOut:nil]; // ... and crbug.com/29054.
- }
-}
-
-void StatusBubbleMac::AnimationDidStop(CAAnimation* animation, bool finished) {
- DCHECK([NSThread isMainThread]);
- DCHECK(state_ == kBubbleShowingFadeIn || state_ == kBubbleHidingFadeOut);
- DCHECK(is_attached());
-
- if (finished) {
- // Because of the mechanism used to interrupt animations, this is never
- // actually called with finished set to false. If animations ever become
- // directly interruptible, the check will ensure that state_ remains
- // properly synchronized.
- if (state_ == kBubbleShowingFadeIn) {
- DCHECK_EQ([[window_ animator] alphaValue], kBubbleOpacity);
- SetState(kBubbleShown);
- } else {
- DCHECK_EQ([[window_ animator] alphaValue], 0.0);
- SetState(kBubbleHidden);
- }
- }
-}
-
-void StatusBubbleMac::SetState(StatusBubbleState state) {
- // We must be hidden or attached, but not both.
- DCHECK((state_ == kBubbleHidden) ^ is_attached());
-
- if (state == state_)
- return;
-
- if (state == kBubbleHidden)
- Detach();
- else
- Attach();
-
- if ([delegate_ respondsToSelector:@selector(statusBubbleWillEnterState:)])
- [delegate_ statusBubbleWillEnterState:state];
-
- state_ = state;
-}
-
-void StatusBubbleMac::Fade(bool show) {
- DCHECK([NSThread isMainThread]);
-
- StatusBubbleState fade_state = kBubbleShowingFadeIn;
- StatusBubbleState target_state = kBubbleShown;
- NSTimeInterval full_duration = kShowFadeInDurationSeconds;
- CGFloat opacity = kBubbleOpacity;
-
- if (!show) {
- fade_state = kBubbleHidingFadeOut;
- target_state = kBubbleHidden;
- full_duration = kHideFadeOutDurationSeconds;
- opacity = 0.0;
- }
-
- DCHECK(state_ == fade_state || state_ == target_state);
-
- if (state_ == target_state)
- return;
-
- if (immediate_) {
- [window_ setAlphaValue:opacity];
- SetState(target_state);
- return;
- }
-
- // If an incomplete transition has left the opacity somewhere between 0 and
- // kBubbleOpacity, the fade rate is kept constant by shortening the duration.
- NSTimeInterval duration =
- full_duration *
- fabs(opacity - [[window_ animator] alphaValue]) / kBubbleOpacity;
-
- // 0.0 will not cancel an in-progress animation.
- if (duration == 0.0)
- duration = kMinimumTimeInterval;
-
- // This will cancel an in-progress transition and replace it with this fade.
- [NSAnimationContext beginGrouping];
- // Don't use the GTM additon for the "Steve" slowdown because this can happen
- // async from user actions and the effects could be a surprise.
- [[NSAnimationContext currentContext] setDuration:duration];
- [[window_ animator] setAlphaValue:opacity];
- [NSAnimationContext endGrouping];
-}
-
-void StatusBubbleMac::StartTimer(int64 delay_ms) {
- DCHECK([NSThread isMainThread]);
- DCHECK(state_ == kBubbleShowingTimer || state_ == kBubbleHidingTimer);
-
- if (immediate_) {
- TimerFired();
- return;
- }
-
- // There can only be one running timer.
- CancelTimer();
-
- MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- timer_factory_.NewRunnableMethod(&StatusBubbleMac::TimerFired),
- delay_ms);
-}
-
-void StatusBubbleMac::CancelTimer() {
- DCHECK([NSThread isMainThread]);
-
- if (!timer_factory_.empty())
- timer_factory_.RevokeAll();
-}
-
-void StatusBubbleMac::TimerFired() {
- DCHECK(state_ == kBubbleShowingTimer || state_ == kBubbleHidingTimer);
- DCHECK([NSThread isMainThread]);
-
- if (state_ == kBubbleShowingTimer) {
- SetState(kBubbleShowingFadeIn);
- Fade(true);
- } else {
- SetState(kBubbleHidingFadeOut);
- Fade(false);
- }
-}
-
-void StatusBubbleMac::StartShowing() {
- // Note that |SetState()| will |Attach()| or |Detach()| as required.
-
- if (state_ == kBubbleHidden) {
- // Arrange to begin fading in after a delay.
- SetState(kBubbleShowingTimer);
- StartTimer(kShowDelayMilliseconds);
- } else if (state_ == kBubbleHidingFadeOut) {
- // Cancel the fade-out in progress and replace it with a fade in.
- SetState(kBubbleShowingFadeIn);
- Fade(true);
- } else if (state_ == kBubbleHidingTimer) {
- // The bubble was already shown but was waiting to begin fading out. It's
- // given a stay of execution.
- SetState(kBubbleShown);
- CancelTimer();
- } else if (state_ == kBubbleShowingTimer) {
- // The timer was already running but nothing was showing yet. Reaching
- // this point means that there is a new request to show something. Start
- // over again by resetting the timer, effectively invalidating the earlier
- // request.
- StartTimer(kShowDelayMilliseconds);
- }
-
- // If the state is kBubbleShown or kBubbleShowingFadeIn, leave everything
- // alone.
-}
-
-void StatusBubbleMac::StartHiding() {
- if (state_ == kBubbleShown) {
- // Arrange to begin fading out after a delay.
- SetState(kBubbleHidingTimer);
- StartTimer(kHideDelayMilliseconds);
- } else if (state_ == kBubbleShowingFadeIn) {
- // Cancel the fade-in in progress and replace it with a fade out.
- SetState(kBubbleHidingFadeOut);
- Fade(false);
- } else if (state_ == kBubbleShowingTimer) {
- // The bubble was already hidden but was waiting to begin fading in. Too
- // bad, it won't get the opportunity now.
- SetState(kBubbleHidden);
- CancelTimer();
- }
-
- // If the state is kBubbleHidden, kBubbleHidingFadeOut, or
- // kBubbleHidingTimer, leave everything alone. The timer is not reset as
- // with kBubbleShowingTimer in StartShowing() because a subsequent request
- // to hide something while one is already in flight does not invalidate the
- // earlier request.
-}
-
-void StatusBubbleMac::CancelExpandTimer() {
- DCHECK([NSThread isMainThread]);
- expand_timer_factory_.RevokeAll();
-}
-
-void StatusBubbleMac::ExpandBubble() {
- // Calculate the width available for expanded and standard bubbles.
- NSRect window_frame = CalculateWindowFrame(/*expand=*/true);
- CGFloat max_bubble_width = NSWidth(window_frame);
- CGFloat standard_bubble_width =
- NSWidth(CalculateWindowFrame(/*expand=*/false));
-
- // Generate the URL string that fits in the expanded bubble.
- NSFont* font = [[window_ contentView] font];
- gfx::Font font_chr(base::SysNSStringToWide([font fontName]),
- [font pointSize]);
- string16 expanded_url = gfx::ElideUrl(url_, font_chr,
- max_bubble_width, UTF16ToWideHack(languages_));
-
- // Scale width from gfx::Font in view coordinates to window coordinates.
- int required_width_for_string =
- font_chr.GetStringWidth(UTF16ToWide(expanded_url)) +
- kTextPadding * 2 + kBubbleViewTextPositionX;
- NSSize scaled_width = NSMakeSize(required_width_for_string, 0);
- scaled_width = [[parent_ contentView] convertSize:scaled_width toView:nil];
- required_width_for_string = scaled_width.width;
-
- // The expanded width must be at least as wide as the standard width, but no
- // wider than the maximum width for its parent frame.
- int expanded_bubble_width =
- std::max(standard_bubble_width,
- std::min(max_bubble_width,
- static_cast<CGFloat>(required_width_for_string)));
-
- SetText(expanded_url, true);
- is_expanded_ = true;
- window_frame.size.width = expanded_bubble_width;
-
- // In testing, don't do any animation.
- if (immediate_) {
- [window_ setFrame:window_frame display:YES];
- return;
- }
-
- NSRect actual_window_frame = [window_ frame];
- // Adjust status bubble origin if bubble was moved to the right.
- // TODO(alekseys): fix for RTL.
- if (NSMinX(actual_window_frame) > NSMinX(window_frame)) {
- actual_window_frame.origin.x =
- NSMaxX(actual_window_frame) - NSWidth(window_frame);
- }
- actual_window_frame.size.width = NSWidth(window_frame);
-
- // Do not expand if it's going to cover mouse location.
- if (NSPointInRect([NSEvent mouseLocation], actual_window_frame))
- return;
-
- [NSAnimationContext beginGrouping];
- [[NSAnimationContext currentContext] setDuration:kExpansionDuration];
- [[window_ animator] setFrame:actual_window_frame display:YES];
- [NSAnimationContext endGrouping];
-}
-
-void StatusBubbleMac::UpdateSizeAndPosition() {
- if (!window_)
- return;
-
- [window_ setFrame:CalculateWindowFrame(/*expand=*/false) display:YES];
-}
-
-void StatusBubbleMac::SwitchParentWindow(NSWindow* parent) {
- DCHECK(parent);
-
- // If not attached, just update our member variable and position.
- if (!is_attached()) {
- parent_ = parent;
- [[window_ contentView] setThemeProvider:parent];
- UpdateSizeAndPosition();
- return;
- }
-
- Detach();
- parent_ = parent;
- [[window_ contentView] setThemeProvider:parent];
- Attach();
- UpdateSizeAndPosition();
-}
-
-NSRect StatusBubbleMac::CalculateWindowFrame(bool expanded_width) {
- DCHECK(parent_);
-
- NSRect screenRect;
- if ([delegate_ respondsToSelector:@selector(statusBubbleBaseFrame)]) {
- screenRect = [delegate_ statusBubbleBaseFrame];
- screenRect.origin = [parent_ convertBaseToScreen:screenRect.origin];
- } else {
- screenRect = [parent_ frame];
- }
-
- NSSize size = NSMakeSize(0, kWindowHeight);
- size = [[parent_ contentView] convertSize:size toView:nil];
-
- if (expanded_width) {
- size.width = screenRect.size.width;
- } else {
- size.width = kWindowWidthPercent * screenRect.size.width;
- }
-
- screenRect.size = size;
- return screenRect;
-}
diff --git a/chrome/browser/cocoa/status_bubble_mac_unittest.mm b/chrome/browser/cocoa/status_bubble_mac_unittest.mm
deleted file mode 100644
index 771dff5..0000000
--- a/chrome/browser/cocoa/status_bubble_mac_unittest.mm
+++ /dev/null
@@ -1,584 +0,0 @@
-// 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.
-
-#include <Cocoa/Cocoa.h>
-
-#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-#include "base/utf_string_conversions.h"
-#import "chrome/browser/cocoa/bubble_view.h"
-#import "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/status_bubble_mac.h"
-#include "googleurl/src/gurl.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-// The test delegate records all of the status bubble object's state
-// transitions.
-@interface StatusBubbleMacTestDelegate : NSObject {
- @private
- NSWindow* window_; // Weak.
- NSPoint baseFrameOffset_;
- std::vector<StatusBubbleMac::StatusBubbleState> states_;
-}
-- (id)initWithWindow:(NSWindow*)window;
-- (void)forceBaseFrameOffset:(NSPoint)baseFrameOffset;
-- (NSRect)statusBubbleBaseFrame;
-- (void)statusBubbleWillEnterState:(StatusBubbleMac::StatusBubbleState)state;
-@end
-@implementation StatusBubbleMacTestDelegate
-- (id)initWithWindow:(NSWindow*)window {
- if ((self = [super init])) {
- window_ = window;
- baseFrameOffset_ = NSMakePoint(0, 0);
- }
- return self;
-}
-- (void)forceBaseFrameOffset:(NSPoint)baseFrameOffset {
- baseFrameOffset_ = baseFrameOffset;
-}
-- (NSRect)statusBubbleBaseFrame {
- NSView* contentView = [window_ contentView];
- NSRect baseFrame = [contentView convertRect:[contentView frame] toView:nil];
- if (baseFrameOffset_.x > 0 || baseFrameOffset_.y > 0) {
- baseFrame = NSOffsetRect(baseFrame, baseFrameOffset_.x, baseFrameOffset_.y);
- baseFrame.size.width -= baseFrameOffset_.x;
- baseFrame.size.height -= baseFrameOffset_.y;
- }
- return baseFrame;
-}
-- (void)statusBubbleWillEnterState:(StatusBubbleMac::StatusBubbleState)state {
- states_.push_back(state);
-}
-- (std::vector<StatusBubbleMac::StatusBubbleState>*)states {
- return &states_;
-}
-@end
-
-// This class implements, for testing purposes, a subclass of |StatusBubbleMac|
-// whose |MouseMoved()| method does nothing. (Ideally, we'd have a way of
-// controlling the "mouse" location, but the current implementation of
-// |StatusBubbleMac| uses |[NSEvent mouseLocation]| directly.) Without this,
-// tests can be flaky since results may depend on the mouse location.
-class StatusBubbleMacIgnoreMouseMoved : public StatusBubbleMac {
- public:
- StatusBubbleMacIgnoreMouseMoved(NSWindow* parent, id delegate)
- : StatusBubbleMac(parent, delegate) {}
-
- virtual void MouseMoved(const gfx::Point& location, bool left_content) {}
-};
-
-class StatusBubbleMacTest : public CocoaTest {
- public:
- virtual void SetUp() {
- CocoaTest::SetUp();
- NSWindow* window = test_window();
- EXPECT_TRUE(window);
- delegate_.reset(
- [[StatusBubbleMacTestDelegate alloc] initWithWindow: window]);
- EXPECT_TRUE(delegate_.get());
- bubble_ = new StatusBubbleMacIgnoreMouseMoved(window, delegate_);
- EXPECT_TRUE(bubble_);
-
- // Turn off delays and transitions for test mode. This doesn't just speed
- // things along, it's actually required to get StatusBubbleMac to behave
- // synchronously, because the tests here don't know how to wait for
- // results. This allows these tests to be much more complete with a
- // minimal loss of coverage and without any heinous rearchitecting.
- bubble_->immediate_ = true;
-
- EXPECT_FALSE(bubble_->window_); // lazily creates window
- }
-
- virtual void TearDown() {
- // Not using a scoped_ptr because bubble must be deleted before calling
- // TearDown to get rid of bubble's window.
- delete bubble_;
- CocoaTest::TearDown();
- }
-
- bool IsVisible() {
- if (![bubble_->window_ isVisible])
- return false;
- return [bubble_->window_ alphaValue] > 0.0;
- }
- NSString* GetText() {
- return bubble_->status_text_;
- }
- NSString* GetURLText() {
- return bubble_->url_text_;
- }
- NSString* GetBubbleViewText() {
- BubbleView* bubbleView = [bubble_->window_ contentView];
- return [bubbleView content];
- }
- NSWindow* GetWindow() {
- return bubble_->window_;
- }
- NSWindow* GetParent() {
- return bubble_->parent_;
- }
- StatusBubbleMac::StatusBubbleState GetState() {
- return bubble_->state_;
- }
- void SetState(StatusBubbleMac::StatusBubbleState state) {
- bubble_->SetState(state);
- }
- std::vector<StatusBubbleMac::StatusBubbleState>* States() {
- return [delegate_ states];
- }
- StatusBubbleMac::StatusBubbleState StateAt(int index) {
- return (*States())[index];
- }
- BrowserTestHelper browser_helper_;
- scoped_nsobject<StatusBubbleMacTestDelegate> delegate_;
- StatusBubbleMac* bubble_; // Strong.
-};
-
-TEST_F(StatusBubbleMacTest, SetStatus) {
- bubble_->SetStatus(string16());
- bubble_->SetStatus(UTF8ToUTF16("This is a test"));
- EXPECT_NSEQ(@"This is a test", GetText());
- EXPECT_TRUE(IsVisible());
-
- // Set the status to the exact same thing again
- bubble_->SetStatus(UTF8ToUTF16("This is a test"));
- EXPECT_NSEQ(@"This is a test", GetText());
-
- // Hide it
- bubble_->SetStatus(string16());
- EXPECT_FALSE(IsVisible());
-}
-
-TEST_F(StatusBubbleMacTest, SetURL) {
- bubble_->SetURL(GURL(), string16());
- EXPECT_FALSE(IsVisible());
- bubble_->SetURL(GURL("bad url"), string16());
- EXPECT_FALSE(IsVisible());
- bubble_->SetURL(GURL("http://"), string16());
- EXPECT_TRUE(IsVisible());
- EXPECT_NSEQ(@"http:", GetURLText());
- bubble_->SetURL(GURL("about:blank"), string16());
- EXPECT_TRUE(IsVisible());
- EXPECT_NSEQ(@"about:blank", GetURLText());
- bubble_->SetURL(GURL("foopy://"), string16());
- EXPECT_TRUE(IsVisible());
- EXPECT_NSEQ(@"foopy://", GetURLText());
- bubble_->SetURL(GURL("http://www.cnn.com"), string16());
- EXPECT_TRUE(IsVisible());
- EXPECT_NSEQ(@"www.cnn.com", GetURLText());
-}
-
-// Test hiding bubble that's already hidden.
-TEST_F(StatusBubbleMacTest, Hides) {
- bubble_->SetStatus(UTF8ToUTF16("Showing"));
- EXPECT_TRUE(IsVisible());
- bubble_->Hide();
- EXPECT_FALSE(IsVisible());
- bubble_->Hide();
- EXPECT_FALSE(IsVisible());
-}
-
-// Test the "main"/"backup" behavior in StatusBubbleMac::SetText().
-TEST_F(StatusBubbleMacTest, SetStatusAndURL) {
- EXPECT_FALSE(IsVisible());
- bubble_->SetStatus(UTF8ToUTF16("Status"));
- EXPECT_TRUE(IsVisible());
- EXPECT_NSEQ(@"Status", GetBubbleViewText());
- bubble_->SetURL(GURL("http://www.nytimes.com"), string16());
- EXPECT_TRUE(IsVisible());
- EXPECT_NSEQ(@"www.nytimes.com", GetBubbleViewText());
- bubble_->SetURL(GURL(), string16());
- EXPECT_TRUE(IsVisible());
- EXPECT_NSEQ(@"Status", GetBubbleViewText());
- bubble_->SetStatus(string16());
- EXPECT_FALSE(IsVisible());
- bubble_->SetURL(GURL("http://www.nytimes.com"), string16());
- EXPECT_TRUE(IsVisible());
- EXPECT_NSEQ(@"www.nytimes.com", GetBubbleViewText());
- bubble_->SetStatus(UTF8ToUTF16("Status"));
- EXPECT_TRUE(IsVisible());
- EXPECT_NSEQ(@"Status", GetBubbleViewText());
- bubble_->SetStatus(string16());
- EXPECT_TRUE(IsVisible());
- EXPECT_NSEQ(@"www.nytimes.com", GetBubbleViewText());
- bubble_->SetURL(GURL(), string16());
- EXPECT_FALSE(IsVisible());
-}
-
-// Test that the status bubble goes through the correct delay and fade states.
-// The delay and fade duration are simulated and not actually experienced
-// during the test because StatusBubbleMacTest sets immediate_ mode.
-TEST_F(StatusBubbleMacTest, StateTransitions) {
- // First, some sanity
-
- EXPECT_FALSE(IsVisible());
- EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
-
- States()->clear();
- EXPECT_TRUE(States()->empty());
-
- bubble_->SetStatus(string16());
- EXPECT_FALSE(IsVisible());
- EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
- EXPECT_TRUE(States()->empty()); // no change from initial kBubbleHidden state
-
- // Next, a few ordinary cases
-
- // Test StartShowing from kBubbleHidden
- bubble_->SetStatus(UTF8ToUTF16("Status"));
- EXPECT_TRUE(IsVisible());
- // Check GetState before checking States to make sure that all state
- // transitions have been flushed to States.
- EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState());
- EXPECT_EQ(3u, States()->size());
- EXPECT_EQ(StatusBubbleMac::kBubbleShowingTimer, StateAt(0));
- EXPECT_EQ(StatusBubbleMac::kBubbleShowingFadeIn, StateAt(1));
- EXPECT_EQ(StatusBubbleMac::kBubbleShown, StateAt(2));
-
- // Test StartShowing from kBubbleShown with the same message
- States()->clear();
- bubble_->SetStatus(UTF8ToUTF16("Status"));
- EXPECT_TRUE(IsVisible());
- EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState());
- EXPECT_TRUE(States()->empty());
-
- // Test StartShowing from kBubbleShown with a different message
- bubble_->SetStatus(UTF8ToUTF16("New Status"));
- EXPECT_TRUE(IsVisible());
- EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState());
- EXPECT_TRUE(States()->empty());
-
- // Test StartHiding from kBubbleShown
- bubble_->SetStatus(string16());
- EXPECT_FALSE(IsVisible());
- // Check GetState before checking States to make sure that all state
- // transitions have been flushed to States.
- EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
- EXPECT_EQ(3u, States()->size());
- EXPECT_EQ(StatusBubbleMac::kBubbleHidingTimer, StateAt(0));
- EXPECT_EQ(StatusBubbleMac::kBubbleHidingFadeOut, StateAt(1));
- EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(2));
-
- // Test StartHiding from kBubbleHidden
- States()->clear();
- bubble_->SetStatus(string16());
- EXPECT_FALSE(IsVisible());
- EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
- EXPECT_TRUE(States()->empty());
-
- // Now, the edge cases
-
- // Test StartShowing from kBubbleShowingTimer
- bubble_->SetStatus(UTF8ToUTF16("Status"));
- SetState(StatusBubbleMac::kBubbleShowingTimer);
- [GetWindow() setAlphaValue:0.0];
- States()->clear();
- EXPECT_TRUE(States()->empty());
- bubble_->SetStatus(UTF8ToUTF16("Status"));
- EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState());
- EXPECT_EQ(2u, States()->size());
- EXPECT_EQ(StatusBubbleMac::kBubbleShowingFadeIn, StateAt(0));
- EXPECT_EQ(StatusBubbleMac::kBubbleShown, StateAt(1));
-
- // Test StartShowing from kBubbleShowingFadeIn
- bubble_->SetStatus(UTF8ToUTF16("Status"));
- SetState(StatusBubbleMac::kBubbleShowingFadeIn);
- [GetWindow() setAlphaValue:0.5];
- States()->clear();
- EXPECT_TRUE(States()->empty());
- bubble_->SetStatus(UTF8ToUTF16("Status"));
- // The actual state values can't be tested in immediate_ mode because
- // the window wasn't actually fading in. Without immediate_ mode,
- // expect kBubbleShown.
- bubble_->SetStatus(string16()); // Go back to a deterministic state.
-
- // Test StartShowing from kBubbleHidingTimer
- bubble_->SetStatus(string16());
- SetState(StatusBubbleMac::kBubbleHidingTimer);
- [GetWindow() setAlphaValue:1.0];
- States()->clear();
- EXPECT_TRUE(States()->empty());
- bubble_->SetStatus(UTF8ToUTF16("Status"));
- EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState());
- EXPECT_EQ(1u, States()->size());
- EXPECT_EQ(StatusBubbleMac::kBubbleShown, StateAt(0));
-
- // Test StartShowing from kBubbleHidingFadeOut
- bubble_->SetStatus(string16());
- SetState(StatusBubbleMac::kBubbleHidingFadeOut);
- [GetWindow() setAlphaValue:0.5];
- States()->clear();
- EXPECT_TRUE(States()->empty());
- bubble_->SetStatus(UTF8ToUTF16("Status"));
- EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState());
- EXPECT_EQ(2u, States()->size());
- EXPECT_EQ(StatusBubbleMac::kBubbleShowingFadeIn, StateAt(0));
- EXPECT_EQ(StatusBubbleMac::kBubbleShown, StateAt(1));
-
- // Test StartHiding from kBubbleShowingTimer
- bubble_->SetStatus(UTF8ToUTF16("Status"));
- SetState(StatusBubbleMac::kBubbleShowingTimer);
- [GetWindow() setAlphaValue:0.0];
- States()->clear();
- EXPECT_TRUE(States()->empty());
- bubble_->SetStatus(string16());
- EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
- EXPECT_EQ(1u, States()->size());
- EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0));
-
- // Test StartHiding from kBubbleShowingFadeIn
- bubble_->SetStatus(UTF8ToUTF16("Status"));
- SetState(StatusBubbleMac::kBubbleShowingFadeIn);
- [GetWindow() setAlphaValue:0.5];
- States()->clear();
- EXPECT_TRUE(States()->empty());
- bubble_->SetStatus(string16());
- EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
- EXPECT_EQ(2u, States()->size());
- EXPECT_EQ(StatusBubbleMac::kBubbleHidingFadeOut, StateAt(0));
- EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(1));
-
- // Test StartHiding from kBubbleHidingTimer
- bubble_->SetStatus(string16());
- SetState(StatusBubbleMac::kBubbleHidingTimer);
- [GetWindow() setAlphaValue:1.0];
- States()->clear();
- EXPECT_TRUE(States()->empty());
- bubble_->SetStatus(string16());
- // The actual state values can't be tested in immediate_ mode because
- // the timer wasn't actually running. Without immediate_ mode, expect
- // kBubbleHidingFadeOut and kBubbleHidden.
- // Go back to a deterministic state.
- bubble_->SetStatus(UTF8ToUTF16("Status"));
-
- // Test StartHiding from kBubbleHidingFadeOut
- bubble_->SetStatus(string16());
- SetState(StatusBubbleMac::kBubbleHidingFadeOut);
- [GetWindow() setAlphaValue:0.5];
- States()->clear();
- EXPECT_TRUE(States()->empty());
- bubble_->SetStatus(string16());
- // The actual state values can't be tested in immediate_ mode because
- // the window wasn't actually fading out. Without immediate_ mode, expect
- // kBubbleHidden.
- // Go back to a deterministic state.
- bubble_->SetStatus(UTF8ToUTF16("Status"));
-
- // Test Hide from kBubbleHidden
- bubble_->SetStatus(string16());
- EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
- States()->clear();
- EXPECT_TRUE(States()->empty());
- bubble_->Hide();
- EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
- EXPECT_TRUE(States()->empty());
-
- // Test Hide from kBubbleShowingTimer
- bubble_->SetStatus(UTF8ToUTF16("Status"));
- SetState(StatusBubbleMac::kBubbleShowingTimer);
- [GetWindow() setAlphaValue:0.0];
- States()->clear();
- EXPECT_TRUE(States()->empty());
- bubble_->Hide();
- EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
- EXPECT_EQ(1u, States()->size());
- EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0));
-
- // Test Hide from kBubbleShowingFadeIn
- bubble_->SetStatus(UTF8ToUTF16("Status"));
- SetState(StatusBubbleMac::kBubbleShowingFadeIn);
- [GetWindow() setAlphaValue:0.5];
- States()->clear();
- EXPECT_TRUE(States()->empty());
- bubble_->Hide();
- EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
- EXPECT_EQ(2u, States()->size());
- EXPECT_EQ(StatusBubbleMac::kBubbleHidingFadeOut, StateAt(0));
- EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(1));
-
- // Test Hide from kBubbleShown
- bubble_->SetStatus(UTF8ToUTF16("Status"));
- States()->clear();
- EXPECT_TRUE(States()->empty());
- bubble_->Hide();
- EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
- EXPECT_EQ(1u, States()->size());
- EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0));
-
- // Test Hide from kBubbleHidingTimer
- bubble_->SetStatus(UTF8ToUTF16("Status"));
- SetState(StatusBubbleMac::kBubbleHidingTimer);
- States()->clear();
- EXPECT_TRUE(States()->empty());
- bubble_->Hide();
- EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
- EXPECT_EQ(1u, States()->size());
- EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0));
-
- // Test Hide from kBubbleHidingFadeOut
- bubble_->SetStatus(UTF8ToUTF16("Status"));
- SetState(StatusBubbleMac::kBubbleHidingFadeOut);
- [GetWindow() setAlphaValue:0.5];
- States()->clear();
- EXPECT_TRUE(States()->empty());
- bubble_->Hide();
- EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
- EXPECT_EQ(1u, States()->size());
- EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0));
-}
-
-TEST_F(StatusBubbleMacTest, Delete) {
- NSWindow* window = test_window();
- // Create and delete immediately.
- StatusBubbleMac* bubble = new StatusBubbleMac(window, nil);
- delete bubble;
-
- // Create then delete while visible.
- bubble = new StatusBubbleMac(window, nil);
- bubble->SetStatus(UTF8ToUTF16("showing"));
- delete bubble;
-}
-
-TEST_F(StatusBubbleMacTest, UpdateSizeAndPosition) {
- // Test |UpdateSizeAndPosition()| when status bubble does not exist (shouldn't
- // crash; shouldn't create window).
- EXPECT_FALSE(GetWindow());
- bubble_->UpdateSizeAndPosition();
- EXPECT_FALSE(GetWindow());
-
- // Create a status bubble (with contents) and call resize (without actually
- // resizing); the frame size shouldn't change.
- bubble_->SetStatus(UTF8ToUTF16("UpdateSizeAndPosition test"));
- ASSERT_TRUE(GetWindow());
- NSRect rect_before = [GetWindow() frame];
- bubble_->UpdateSizeAndPosition();
- NSRect rect_after = [GetWindow() frame];
- EXPECT_TRUE(NSEqualRects(rect_before, rect_after));
-
- // Move the window and call resize; only the origin should change.
- NSWindow* window = test_window();
- ASSERT_TRUE(window);
- NSRect frame = [window frame];
- rect_before = [GetWindow() frame];
- frame.origin.x += 10.0; // (fairly arbitrary nonzero value)
- frame.origin.y += 10.0; // (fairly arbitrary nonzero value)
- [window setFrame:frame display:YES];
- bubble_->UpdateSizeAndPosition();
- rect_after = [GetWindow() frame];
- EXPECT_NE(rect_before.origin.x, rect_after.origin.x);
- EXPECT_NE(rect_before.origin.y, rect_after.origin.y);
- EXPECT_EQ(rect_before.size.width, rect_after.size.width);
- EXPECT_EQ(rect_before.size.height, rect_after.size.height);
-
- // Resize the window (without moving). The origin shouldn't change. The width
- // should change (in the current implementation), but not the height.
- frame = [window frame];
- rect_before = [GetWindow() frame];
- frame.size.width += 50.0; // (fairly arbitrary nonzero value)
- frame.size.height += 50.0; // (fairly arbitrary nonzero value)
- [window setFrame:frame display:YES];
- bubble_->UpdateSizeAndPosition();
- rect_after = [GetWindow() frame];
- EXPECT_EQ(rect_before.origin.x, rect_after.origin.x);
- EXPECT_EQ(rect_before.origin.y, rect_after.origin.y);
- EXPECT_NE(rect_before.size.width, rect_after.size.width);
- EXPECT_EQ(rect_before.size.height, rect_after.size.height);
-}
-
-TEST_F(StatusBubbleMacTest, MovingWindowUpdatesPosition) {
- NSWindow* window = test_window();
-
- // Show the bubble and make sure it has the same origin as |window|.
- bubble_->SetStatus(UTF8ToUTF16("Showing"));
- NSWindow* child = GetWindow();
- EXPECT_TRUE(NSEqualPoints([window frame].origin, [child frame].origin));
-
- // Hide the bubble, move the window, and show it again.
- bubble_->Hide();
- NSRect frame = [window frame];
- frame.origin.x += 50;
- [window setFrame:frame display:YES];
- bubble_->SetStatus(UTF8ToUTF16("Reshowing"));
-
- // The bubble should reattach in the correct location.
- child = GetWindow();
- EXPECT_TRUE(NSEqualPoints([window frame].origin, [child frame].origin));
-}
-
-TEST_F(StatusBubbleMacTest, StatuBubbleRespectsBaseFrameLimits) {
- NSWindow* window = test_window();
-
- // Show the bubble and make sure it has the same origin as |window|.
- bubble_->SetStatus(UTF8ToUTF16("Showing"));
- NSWindow* child = GetWindow();
- EXPECT_TRUE(NSEqualPoints([window frame].origin, [child frame].origin));
-
- // Hide the bubble, change base frame offset, and show it again.
- bubble_->Hide();
-
- NSPoint baseFrameOffset = NSMakePoint(0, [window frame].size.height / 3);
- EXPECT_GT(baseFrameOffset.y, 0);
- [delegate_ forceBaseFrameOffset:baseFrameOffset];
-
- bubble_->SetStatus(UTF8ToUTF16("Reshowing"));
-
- // The bubble should reattach in the correct location.
- child = GetWindow();
- NSPoint expectedOrigin = [window frame].origin;
- expectedOrigin.x += baseFrameOffset.x;
- expectedOrigin.y += baseFrameOffset.y;
- EXPECT_TRUE(NSEqualPoints(expectedOrigin, [child frame].origin));
-}
-
-TEST_F(StatusBubbleMacTest, ExpandBubble) {
- NSWindow* window = test_window();
- ASSERT_TRUE(window);
- NSRect window_frame = [window frame];
- window_frame.size.width = 600.0;
- [window setFrame:window_frame display:YES];
-
- // Check basic expansion
- bubble_->SetStatus(UTF8ToUTF16("Showing"));
- EXPECT_TRUE(IsVisible());
- bubble_->SetURL(GURL("http://www.battersbox.com/peter_paul_and_mary.html"),
- string16());
- EXPECT_TRUE([GetURLText() hasSuffix:@"\u2026"]);
- bubble_->ExpandBubble();
- EXPECT_TRUE(IsVisible());
- EXPECT_NSEQ(@"www.battersbox.com/peter_paul_and_mary.html", GetURLText());
- bubble_->Hide();
-
- // Make sure bubble resets after hide.
- bubble_->SetStatus(UTF8ToUTF16("Showing"));
- bubble_->SetURL(GURL("http://www.snickersnee.com/pioneer_fishstix.html"),
- string16());
- EXPECT_TRUE([GetURLText() hasSuffix:@"\u2026"]);
- // ...and that it expands again properly.
- bubble_->ExpandBubble();
- EXPECT_NSEQ(@"www.snickersnee.com/pioneer_fishstix.html", GetURLText());
- // ...again, again!
- bubble_->SetURL(GURL("http://www.battersbox.com/peter_paul_and_mary.html"),
- string16());
- bubble_->ExpandBubble();
- EXPECT_NSEQ(@"www.battersbox.com/peter_paul_and_mary.html", GetURLText());
- bubble_->Hide();
-
- window_frame = [window frame];
- window_frame.size.width = 300.0;
- [window setFrame:window_frame display:YES];
-
- // Very long URL's will be cut off even in the expanded state.
- bubble_->SetStatus(UTF8ToUTF16("Showing"));
- const char veryLongUrl[] =
- "http://www.diewahrscheinlichlaengstepralinederwelt.com/duuuuplo.html";
- bubble_->SetURL(GURL(veryLongUrl), string16());
- EXPECT_TRUE([GetURLText() hasSuffix:@"\u2026"]);
- bubble_->ExpandBubble();
- EXPECT_TRUE([GetURLText() hasSuffix:@"\u2026"]);
-}
-
-
diff --git a/chrome/browser/cocoa/status_icons/status_icon_mac.h b/chrome/browser/cocoa/status_icons/status_icon_mac.h
deleted file mode 100644
index 78a2283..0000000
--- a/chrome/browser/cocoa/status_icons/status_icon_mac.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_STATUS_ICONS_STATUS_ICON_MAC_H_
-#define CHROME_BROWSER_COCOA_STATUS_ICONS_STATUS_ICON_MAC_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_nsobject.h"
-#include "base/string16.h"
-#include "chrome/browser/status_icons/status_icon.h"
-
-class SkBitmap;
-@class NSStatusItem;
-@class StatusItemController;
-
-class StatusIconMac : public StatusIcon {
- public:
- StatusIconMac();
- virtual ~StatusIconMac();
-
- // Overridden from StatusIcon
- virtual void SetImage(const SkBitmap& image);
- virtual void SetPressedImage(const SkBitmap& image);
- virtual void SetToolTip(const string16& tool_tip);
-
- protected:
- // Overridden from StatusIcon.
- virtual void UpdatePlatformContextMenu(menus::MenuModel* menu);
-
- private:
- // Getter for item_ that allows lazy initialization.
- NSStatusItem* item();
- scoped_nsobject<NSStatusItem> item_;
-
- scoped_nsobject<StatusItemController> controller_;
-
- DISALLOW_COPY_AND_ASSIGN(StatusIconMac);
-};
-
-
-#endif // CHROME_BROWSER_COCOA_STATUS_ICONS_STATUS_ICON_MAC_H_
diff --git a/chrome/browser/cocoa/status_icons/status_icon_mac.mm b/chrome/browser/cocoa/status_icons/status_icon_mac.mm
deleted file mode 100644
index 6b79b45..0000000
--- a/chrome/browser/cocoa/status_icons/status_icon_mac.mm
+++ /dev/null
@@ -1,82 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/status_icons/status_icon_mac.h"
-
-#include "base/logging.h"
-#include "base/sys_string_conversions.h"
-#include "skia/ext/skia_utils_mac.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-@interface StatusItemController : NSObject {
- StatusIconMac* statusIcon_; // weak
-}
-- initWithIcon:(StatusIconMac*)icon;
-- (void)handleClick:(id)sender;
-
-@end // @interface StatusItemController
-
-@implementation StatusItemController
-
-- (id)initWithIcon:(StatusIconMac*)icon {
- statusIcon_ = icon;
- return self;
-}
-
-- (void)handleClick:(id)sender {
- // Pass along the click notification to our owner.
- DCHECK(statusIcon_);
- statusIcon_->DispatchClickEvent();
-}
-
-@end
-
-StatusIconMac::StatusIconMac()
- : item_(NULL) {
- controller_.reset([[StatusItemController alloc] initWithIcon:this]);
-}
-
-StatusIconMac::~StatusIconMac() {
- // Remove the status item from the status bar.
- if (item_)
- [[NSStatusBar systemStatusBar] removeStatusItem:item_];
-}
-
-NSStatusItem* StatusIconMac::item() {
- if (!item_.get()) {
- // Create a new status item.
- item_.reset([[[NSStatusBar systemStatusBar]
- statusItemWithLength:NSSquareStatusItemLength] retain]);
- [item_ setEnabled:YES];
- [item_ setTarget:controller_];
- [item_ setAction:@selector(handleClick:)];
- [item_ setHighlightMode:YES];
- }
- return item_.get();
-}
-
-void StatusIconMac::SetImage(const SkBitmap& bitmap) {
- if (!bitmap.isNull()) {
- NSImage* image = gfx::SkBitmapToNSImage(bitmap);
- if (image)
- [item() setImage:image];
- }
-}
-
-void StatusIconMac::SetPressedImage(const SkBitmap& bitmap) {
- if (!bitmap.isNull()) {
- NSImage* image = gfx::SkBitmapToNSImage(bitmap);
- if (image)
- [item() setAlternateImage:image];
- }
-}
-
-void StatusIconMac::SetToolTip(const string16& tool_tip) {
- [item() setToolTip:base::SysUTF16ToNSString(tool_tip)];
-}
-
-void StatusIconMac::UpdatePlatformContextMenu(menus::MenuModel* menu) {
- // TODO(atwilson): Add support for context menus for Mac when actually needed
- // (not yet used by anything) - http://crbug.com/37375.
-}
diff --git a/chrome/browser/cocoa/status_icons/status_icon_mac_unittest.mm b/chrome/browser/cocoa/status_icons/status_icon_mac_unittest.mm
deleted file mode 100644
index 39246ab..0000000
--- a/chrome/browser/cocoa/status_icons/status_icon_mac_unittest.mm
+++ /dev/null
@@ -1,30 +0,0 @@
-// 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.
-
-#include "app/resource_bundle.h"
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/cocoa/status_icons/status_icon_mac.h"
-#include "grit/browser_resources.h"
-#include "grit/theme_resources.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-class SkBitmap;
-
-class StatusIconMacTest : public CocoaTest {
-};
-
-TEST_F(StatusIconMacTest, Create) {
- // Create an icon, set the tool tip, then shut it down (checks for leaks).
- scoped_ptr<StatusIcon> icon(new StatusIconMac());
- SkBitmap* bitmap = ResourceBundle::GetSharedInstance().GetBitmapNamed(
- IDR_STATUS_TRAY_ICON);
- icon->SetImage(*bitmap);
- SkBitmap* pressed = ResourceBundle::GetSharedInstance().GetBitmapNamed(
- IDR_STATUS_TRAY_ICON_PRESSED);
- icon->SetPressedImage(*pressed);
- icon->SetToolTip(ASCIIToUTF16("tool tip"));
-}
diff --git a/chrome/browser/cocoa/status_icons/status_tray_mac.h b/chrome/browser/cocoa/status_icons/status_tray_mac.h
deleted file mode 100644
index 3552db4..0000000
--- a/chrome/browser/cocoa/status_icons/status_tray_mac.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_STATUS_ICONS_STATUS_TRAY_MAC_H_
-#define CHROME_BROWSER_COCOA_STATUS_ICONS_STATUS_TRAY_MAC_H_
-#pragma once
-
-#include "chrome/browser/status_icons/status_tray.h"
-
-class StatusTrayMac : public StatusTray {
- public:
- StatusTrayMac();
-
- protected:
- // Factory method for creating a status icon.
- virtual StatusIcon* CreatePlatformStatusIcon();
-
- private:
- DISALLOW_COPY_AND_ASSIGN(StatusTrayMac);
-};
-
-#endif // CHROME_BROWSER_COCOA_STATUS_ICONS_STATUS_TRAY_MAC_H_
-
diff --git a/chrome/browser/cocoa/status_icons/status_tray_mac.mm b/chrome/browser/cocoa/status_icons/status_tray_mac.mm
deleted file mode 100644
index d4e176f..0000000
--- a/chrome/browser/cocoa/status_icons/status_tray_mac.mm
+++ /dev/null
@@ -1,18 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/status_icons/status_tray_mac.h"
-
-#include "chrome/browser/cocoa/status_icons/status_icon_mac.h"
-
-StatusTray* StatusTray::Create() {
- return new StatusTrayMac();
-}
-
-StatusTrayMac::StatusTrayMac() {
-}
-
-StatusIcon* StatusTrayMac::CreatePlatformStatusIcon() {
- return new StatusIconMac();
-}
diff --git a/chrome/browser/cocoa/styled_text_field.mm b/chrome/browser/cocoa/styled_text_field.mm
deleted file mode 100644
index 8703575..0000000
--- a/chrome/browser/cocoa/styled_text_field.mm
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/styled_text_field.h"
-
-#include "base/logging.h"
-#import "chrome/browser/cocoa/styled_text_field_cell.h"
-
-@implementation StyledTextField
-
-- (StyledTextFieldCell*)styledTextFieldCell {
- DCHECK([[self cell] isKindOfClass:[StyledTextFieldCell class]]);
- return static_cast<StyledTextFieldCell*>([self cell]);
-}
-
-// Cocoa text fields are edited by placing an NSTextView as subview,
-// positioned by the cell's -editWithFrame:inView:... method. Using
-// the standard -makeFirstResponder: machinery to reposition the field
-// editor results in resetting the field editor's editing state, which
-// AutocompleteEditViewMac monitors. This causes problems because
-// editing can require the field editor to be repositioned, which
-// could disrupt editing. This code repositions the subview directly,
-// which causes no editing-state changes.
-- (void)resetFieldEditorFrameIfNeeded {
- // No action if not editing.
- NSText* editor = [self currentEditor];
- if (!editor) {
- return;
- }
-
- // When editing, we should have exactly one subview, which is a
- // clipview containing the editor (for purposes of scrolling).
- NSArray* subviews = [self subviews];
- DCHECK_EQ([subviews count], 1U);
- DCHECK([editor isDescendantOf:self]);
- if ([subviews count] == 0) {
- return;
- }
-
- // If the frame is already right, don't make any visible changes.
- StyledTextFieldCell* cell = [self styledTextFieldCell];
- const NSRect frame([cell drawingRectForBounds:[self bounds]]);
- NSView* subview = [subviews objectAtIndex:0];
- if (NSEqualRects(frame, [subview frame])) {
- return;
- }
-
- [subview setFrame:frame];
-
- // Make sure the selection remains visible.
- [editor scrollRangeToVisible:[editor selectedRange]];
-}
-
-- (CGFloat)availableDecorationWidth {
- NSAttributedString* as = [self attributedStringValue];
- const NSSize size([as size]);
- const NSRect bounds([self bounds]);
- return NSWidth(bounds) - size.width;
-}
-@end
diff --git a/chrome/browser/cocoa/styled_text_field_cell.h b/chrome/browser/cocoa/styled_text_field_cell.h
deleted file mode 100644
index 5e8e286..0000000
--- a/chrome/browser/cocoa/styled_text_field_cell.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_STYLED_TEXT_FIELD_CELL_H_
-#define CHROME_BROWSER_COCOA_STYLED_TEXT_FIELD_CELL_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-typedef enum {
- StyledTextFieldCellRoundedAll = 0,
- StyledTextFieldCellRoundedLeft = 1
-} StyledTextFieldCellRoundedFlags;
-
-// StyledTextFieldCell customizes the look of the standard Cocoa text field.
-// The border and focus ring are modified, as is the font baseline. Subclasses
-// can override |drawInteriorWithFrame:inView:| to provide custom drawing for
-// decorations, but they must make sure to call the superclass' implementation
-// with a modified frame after performing any custom drawing.
-
-@interface StyledTextFieldCell : NSTextFieldCell {
-}
-
-@end
-
-// Methods intended to be overridden by subclasses, not part of the public API
-// and should not be called outside of subclasses.
-@interface StyledTextFieldCell (ProtectedMethods)
-
-// Return the portion of the cell to show the text cursor over. The default
-// implementation returns the full |cellFrame|. Subclasses should override this
-// method if they add any decorations.
-- (NSRect)textCursorFrameForFrame:(NSRect)cellFrame;
-
-// Return the portion of the cell to use for text display. This corresponds to
-// the frame with our added decorations sliced off. The default implementation
-// returns the full |cellFrame|, as by default there are no decorations.
-// Subclasses should override this method if they add any decorations.
-- (NSRect)textFrameForFrame:(NSRect)cellFrame;
-
-// Baseline adjust for the text in this cell. Defaults to 0. Subclasses should
-// override as needed.
-- (CGFloat)baselineAdjust;
-
-// Radius of the corners of the field. Defaults to square corners (0.0).
-- (CGFloat)cornerRadius;
-
-// Which corners of the field to round. Defaults to RoundedAll.
-- (StyledTextFieldCellRoundedFlags)roundedFlags;
-
-// Returns YES if a light themed bezel should be drawn under the text field.
-// Default implementation returns NO.
-- (BOOL)shouldDrawBezel;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_STYLED_TEXT_FIELD_CELL_H_
diff --git a/chrome/browser/cocoa/styled_text_field_cell.mm b/chrome/browser/cocoa/styled_text_field_cell.mm
deleted file mode 100644
index 96a6c9f..0000000
--- a/chrome/browser/cocoa/styled_text_field_cell.mm
+++ /dev/null
@@ -1,217 +0,0 @@
-// 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 "chrome/browser/cocoa/styled_text_field_cell.h"
-
-#include "app/resource_bundle.h"
-#include "base/logging.h"
-#import "chrome/browser/cocoa/themed_window.h"
-#include "chrome/browser/themes/browser_theme_provider.h"
-#include "gfx/font.h"
-#include "grit/theme_resources.h"
-#import "third_party/GTM/AppKit/GTMNSBezierPath+RoundRect.h"
-
-namespace {
-
-NSBezierPath* RectPathWithInset(StyledTextFieldCellRoundedFlags roundedFlags,
- const NSRect frame,
- const CGFloat inset,
- const CGFloat outerRadius) {
- NSRect insetFrame = NSInsetRect(frame, inset, inset);
-
- if (outerRadius > 0.0) {
- CGFloat leftRadius = outerRadius - inset;
- CGFloat rightRadius =
- (roundedFlags == StyledTextFieldCellRoundedLeft) ? 0 : leftRadius;
-
- return [NSBezierPath gtm_bezierPathWithRoundRect:insetFrame
- topLeftCornerRadius:leftRadius
- topRightCornerRadius:rightRadius
- bottomLeftCornerRadius:leftRadius
- bottomRightCornerRadius:rightRadius];
- } else {
- return [NSBezierPath bezierPathWithRect:insetFrame];
- }
-}
-
-// Similar to |NSRectFill()|, additionally sets |color| as the fill
-// color. |outerRadius| greater than 0.0 uses rounded corners, with
-// inset backed out of the radius.
-void FillRectWithInset(StyledTextFieldCellRoundedFlags roundedFlags,
- const NSRect frame,
- const CGFloat inset,
- const CGFloat outerRadius,
- NSColor* color) {
- NSBezierPath* path =
- RectPathWithInset(roundedFlags, frame, inset, outerRadius);
- [color setFill];
- [path fill];
-}
-
-// Similar to |NSFrameRectWithWidth()|, additionally sets |color| as
-// the stroke color (as opposed to the fill color). |outerRadius|
-// greater than 0.0 uses rounded corners, with inset backed out of the
-// radius.
-void FrameRectWithInset(StyledTextFieldCellRoundedFlags roundedFlags,
- const NSRect frame,
- const CGFloat inset,
- const CGFloat outerRadius,
- const CGFloat lineWidth,
- NSColor* color) {
- const CGFloat finalInset = inset + (lineWidth / 2.0);
- NSBezierPath* path =
- RectPathWithInset(roundedFlags, frame, finalInset, outerRadius);
- [color setStroke];
- [path setLineWidth:lineWidth];
- [path stroke];
-}
-
-// TODO(shess): Maybe we need a |cocoa_util.h|?
-class ScopedSaveGraphicsState {
- public:
- ScopedSaveGraphicsState()
- : context_([NSGraphicsContext currentContext]) {
- [context_ saveGraphicsState];
- }
- explicit ScopedSaveGraphicsState(NSGraphicsContext* context)
- : context_(context) {
- [context_ saveGraphicsState];
- }
- ~ScopedSaveGraphicsState() {
- [context_ restoreGraphicsState];
- }
-
-private:
- NSGraphicsContext* context_;
-};
-
-} // namespace
-
-@implementation StyledTextFieldCell
-
-- (CGFloat)baselineAdjust {
- return 0.0;
-}
-
-- (CGFloat)cornerRadius {
- return 0.0;
-}
-
-- (StyledTextFieldCellRoundedFlags)roundedFlags {
- return StyledTextFieldCellRoundedAll;
-}
-
-- (BOOL)shouldDrawBezel {
- return NO;
-}
-
-// Returns the same value as textCursorFrameForFrame, but does not call it
-// directly to avoid potential infinite loops.
-- (NSRect)textFrameForFrame:(NSRect)cellFrame {
- return NSInsetRect(cellFrame, 0, [self baselineAdjust]);
-}
-
-// Returns the same value as textFrameForFrame, but does not call it directly to
-// avoid potential infinite loops.
-- (NSRect)textCursorFrameForFrame:(NSRect)cellFrame {
- return NSInsetRect(cellFrame, 0, [self baselineAdjust]);
-}
-
-// Override to show the I-beam cursor only in the area given by
-// |textCursorFrameForFrame:|.
-- (void)resetCursorRect:(NSRect)cellFrame inView:(NSView *)controlView {
- [super resetCursorRect:[self textCursorFrameForFrame:cellFrame]
- inView:controlView];
-}
-
-// For NSTextFieldCell this is the area within the borders. For our
-// purposes, we count the info decorations as being part of the
-// border.
-- (NSRect)drawingRectForBounds:(NSRect)theRect {
- return [super drawingRectForBounds:[self textFrameForFrame:theRect]];
-}
-
-// TODO(shess): This code is manually drawing the cell's border area,
-// but otherwise the cell assumes -setBordered:YES for purposes of
-// calculating things like the editing area. This is probably
-// incorrect. I know that this affects -drawingRectForBounds:.
-- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
- DCHECK([controlView isFlipped]);
- StyledTextFieldCellRoundedFlags roundedFlags = [self roundedFlags];
-
- // TODO(shess): This inset is also reflected by |kFieldVisualInset|
- // in autocomplete_popup_view_mac.mm.
- const NSRect frame = NSInsetRect(cellFrame, 0, 1);
- const CGFloat radius = [self cornerRadius];
-
- // Paint button background image if there is one (otherwise the border won't
- // look right).
- BrowserThemeProvider* themeProvider =
- static_cast<BrowserThemeProvider*>([[controlView window] themeProvider]);
- if (themeProvider) {
- NSColor* backgroundImageColor =
- themeProvider->GetNSImageColorNamed(IDR_THEME_BUTTON_BACKGROUND, false);
- if (backgroundImageColor) {
- // Set the phase to match window.
- NSRect trueRect = [controlView convertRect:cellFrame toView:nil];
- NSPoint midPoint = NSMakePoint(NSMinX(trueRect), NSMaxY(trueRect));
- [[NSGraphicsContext currentContext] setPatternPhase:midPoint];
-
- // NOTE(shess): This seems like it should be using a 0.0 inset,
- // but AFAICT using a 0.5 inset is important in mixing the
- // toolbar background and the omnibox background.
- FillRectWithInset(roundedFlags, frame, 0.5, radius, backgroundImageColor);
- }
-
- // Draw the outer stroke (over the background).
- BOOL active = [[controlView window] isMainWindow];
- NSColor* strokeColor = themeProvider->GetNSColor(
- active ? BrowserThemeProvider::COLOR_TOOLBAR_BUTTON_STROKE :
- BrowserThemeProvider::COLOR_TOOLBAR_BUTTON_STROKE_INACTIVE,
- true);
- FrameRectWithInset(roundedFlags, frame, 0.0, radius, 1.0, strokeColor);
- }
-
- // Fill interior with background color.
- FillRectWithInset(roundedFlags, frame, 1.0, radius, [self backgroundColor]);
-
- // Draw the shadow. For the rounded-rect case, the shadow needs to
- // slightly turn in at the corners. |shadowFrame| is at the same
- // midline as the inner border line on the top and left, but at the
- // outer border line on the bottom and right. The clipping change
- // will clip the bottom and right edges (and corner).
- {
- ScopedSaveGraphicsState state;
- [RectPathWithInset(roundedFlags, frame, 1.0, radius) addClip];
- const NSRect shadowFrame = NSOffsetRect(frame, 0.5, 0.5);
- NSColor* shadowShade = [NSColor colorWithCalibratedWhite:0.0 alpha:0.05];
- FrameRectWithInset(roundedFlags, shadowFrame, 0.5, radius - 0.5,
- 1.0, shadowShade);
- }
-
- // Draw optional bezel below bottom stroke.
- if ([self shouldDrawBezel] && themeProvider &&
- themeProvider->UsingDefaultTheme()) {
-
- [themeProvider->GetNSColor(
- BrowserThemeProvider::COLOR_TOOLBAR_BEZEL, true) set];
- NSRect bezelRect = NSMakeRect(cellFrame.origin.x,
- NSMaxY(cellFrame) - 0.5,
- NSWidth(cellFrame),
- 1.0);
- bezelRect = NSInsetRect(bezelRect, radius - 0.5, 0.0);
- NSRectFill(bezelRect);
- }
-
- // Draw the focus ring if needed.
- if ([self showsFirstResponder]) {
- NSColor* color =
- [[NSColor keyboardFocusIndicatorColor] colorWithAlphaComponent:0.5];
- FrameRectWithInset(roundedFlags, frame, 0.0, radius, 2.0, color);
- }
-
- [self drawInteriorWithFrame:cellFrame inView:controlView];
-}
-
-@end
diff --git a/chrome/browser/cocoa/styled_text_field_cell_unittest.mm b/chrome/browser/cocoa/styled_text_field_cell_unittest.mm
deleted file mode 100644
index 8ee6c46..0000000
--- a/chrome/browser/cocoa/styled_text_field_cell_unittest.mm
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright (c) 2009 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 "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/styled_text_field_cell.h"
-#import "chrome/browser/cocoa/styled_text_field_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-namespace {
-
-// Width of the field so that we don't have to ask |field_| for it all
-// the time.
-const CGFloat kWidth(300.0);
-
-class StyledTextFieldCellTest : public CocoaTest {
- public:
- StyledTextFieldCellTest() {
- // Make sure this is wide enough to play games with the cell
- // decorations.
- const NSRect frame = NSMakeRect(0, 0, kWidth, 30);
-
- scoped_nsobject<StyledTextFieldTestCell> cell(
- [[StyledTextFieldTestCell alloc] initTextCell:@"Testing"]);
- cell_ = cell.get();
- [cell_ setEditable:YES];
- [cell_ setBordered:YES];
-
- scoped_nsobject<NSTextField> view(
- [[NSTextField alloc] initWithFrame:frame]);
- view_ = view.get();
- [view_ setCell:cell_];
-
- [[test_window() contentView] addSubview:view_];
- }
-
- NSTextField* view_;
- StyledTextFieldTestCell* cell_;
-};
-
-// Basic view tests (AddRemove, Display).
-TEST_VIEW(StyledTextFieldCellTest, view_);
-
-// Test drawing, mostly to ensure nothing leaks or crashes.
-TEST_F(StyledTextFieldCellTest, FocusedDisplay) {
- [view_ display];
-
- // Test focused drawing.
- [test_window() makePretendKeyWindowAndSetFirstResponder:view_];
- [view_ display];
- [test_window() clearPretendKeyWindowAndFirstResponder];
-
- // Test display of various cell configurations.
- [cell_ setLeftMargin:5];
- [view_ display];
-
- [cell_ setRightMargin:15];
- [view_ display];
-}
-
-// The editor frame should be slightly inset from the text frame.
-TEST_F(StyledTextFieldCellTest, DrawingRectForBounds) {
- const NSRect bounds = [view_ bounds];
- NSRect textFrame = [cell_ textFrameForFrame:bounds];
- NSRect drawingRect = [cell_ drawingRectForBounds:bounds];
-
- EXPECT_FALSE(NSIsEmptyRect(drawingRect));
- EXPECT_TRUE(NSContainsRect(textFrame, NSInsetRect(drawingRect, 1, 1)));
-
- [cell_ setLeftMargin:10];
- textFrame = [cell_ textFrameForFrame:bounds];
- drawingRect = [cell_ drawingRectForBounds:bounds];
- EXPECT_FALSE(NSIsEmptyRect(drawingRect));
- EXPECT_TRUE(NSContainsRect(textFrame, NSInsetRect(drawingRect, 1, 1)));
-
- [cell_ setRightMargin:20];
- textFrame = [cell_ textFrameForFrame:bounds];
- drawingRect = [cell_ drawingRectForBounds:bounds];
- EXPECT_FALSE(NSIsEmptyRect(drawingRect));
- EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect));
-
- [cell_ setLeftMargin:0];
- textFrame = [cell_ textFrameForFrame:bounds];
- drawingRect = [cell_ drawingRectForBounds:bounds];
- EXPECT_FALSE(NSIsEmptyRect(drawingRect));
- EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect));
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/styled_text_field_test_helper.h b/chrome/browser/cocoa/styled_text_field_test_helper.h
deleted file mode 100644
index d4b356e..0000000
--- a/chrome/browser/cocoa/styled_text_field_test_helper.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2009 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>
-#import "chrome/browser/cocoa/styled_text_field_cell.h"
-
-// Subclass of StyledTextFieldCell that allows you to slice off sections on the
-// left and right of the cell.
-@interface StyledTextFieldTestCell : StyledTextFieldCell {
- CGFloat leftMargin_;
- CGFloat rightMargin_;
-}
-@property (nonatomic, assign) CGFloat leftMargin;
-@property (nonatomic, assign) CGFloat rightMargin;
-@end
diff --git a/chrome/browser/cocoa/styled_text_field_test_helper.mm b/chrome/browser/cocoa/styled_text_field_test_helper.mm
deleted file mode 100644
index fcae06a..0000000
--- a/chrome/browser/cocoa/styled_text_field_test_helper.mm
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) 2009 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>
-#import "chrome/browser/cocoa/styled_text_field_test_helper.h"
-
-@implementation StyledTextFieldTestCell
-@synthesize leftMargin = leftMargin_;
-@synthesize rightMargin = rightMargin_;
-
-- (NSRect)textFrameForFrame:(NSRect)frame {
- NSRect textFrame = [super textFrameForFrame:frame];
- textFrame.origin.x += leftMargin_;
- textFrame.size.width -= (leftMargin_ + rightMargin_);
- return textFrame;
-}
-@end
diff --git a/chrome/browser/cocoa/styled_text_field_unittest.mm b/chrome/browser/cocoa/styled_text_field_unittest.mm
deleted file mode 100644
index 000e77a..0000000
--- a/chrome/browser/cocoa/styled_text_field_unittest.mm
+++ /dev/null
@@ -1,198 +0,0 @@
-// Copyright (c) 2009 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>
-
-#import "base/cocoa_protocols_mac.h"
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/styled_text_field.h"
-#import "chrome/browser/cocoa/styled_text_field_cell.h"
-#import "chrome/browser/cocoa/styled_text_field_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "third_party/ocmock/OCMock/OCMock.h"
-
-namespace {
-
-// Width of the field so that we don't have to ask |field_| for it all
-// the time.
-static const CGFloat kWidth(300.0);
-
-class StyledTextFieldTest : public CocoaTest {
- public:
- StyledTextFieldTest() {
- // Make sure this is wide enough to play games with the cell
- // decorations.
- NSRect frame = NSMakeRect(0, 0, kWidth, 30);
-
- scoped_nsobject<StyledTextFieldTestCell> cell(
- [[StyledTextFieldTestCell alloc] initTextCell:@"Testing"]);
- cell_ = cell.get();
- [cell_ setEditable:YES];
- [cell_ setBordered:YES];
-
- scoped_nsobject<StyledTextField> field(
- [[StyledTextField alloc] initWithFrame:frame]);
- field_ = field.get();
- [field_ setCell:cell_];
-
- [[test_window() contentView] addSubview:field_];
- }
-
- // Helper to return the field-editor frame being used w/in |field_|.
- NSRect EditorFrame() {
- EXPECT_TRUE([field_ currentEditor]);
- EXPECT_EQ([[field_ subviews] count], 1U);
- if ([[field_ subviews] count] > 0) {
- return [[[field_ subviews] objectAtIndex:0] frame];
- } else {
- // Return something which won't work so the caller can soldier
- // on.
- return NSZeroRect;
- }
- }
-
- StyledTextField* field_;
- StyledTextFieldTestCell* cell_;
-};
-
-// Basic view tests (AddRemove, Display).
-TEST_VIEW(StyledTextFieldTest, field_);
-
-// Test that we get the same cell from -cell and
-// -styledTextFieldCell.
-TEST_F(StyledTextFieldTest, Cell) {
- StyledTextFieldCell* cell = [field_ styledTextFieldCell];
- EXPECT_EQ(cell, [field_ cell]);
- EXPECT_TRUE(cell != nil);
-}
-
-// Test that becoming first responder sets things up correctly.
-TEST_F(StyledTextFieldTest, FirstResponder) {
- EXPECT_EQ(nil, [field_ currentEditor]);
- EXPECT_EQ([[field_ subviews] count], 0U);
- [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
- EXPECT_FALSE(nil == [field_ currentEditor]);
- EXPECT_EQ([[field_ subviews] count], 1U);
- EXPECT_TRUE([[field_ currentEditor] isDescendantOf:field_]);
-}
-
-TEST_F(StyledTextFieldTest, AvailableDecorationWidth) {
- // A fudge factor to account for how much space the border takes up.
- // The test shouldn't be too dependent on the field's internals, but
- // it also shouldn't let deranged cases fall through the cracks
- // (like nothing available with no text, or everything available
- // with some text).
- const CGFloat kBorderWidth = 20.0;
-
- // With no contents, almost the entire width is available for
- // decorations.
- [field_ setStringValue:@""];
- CGFloat availableWidth = [field_ availableDecorationWidth];
- EXPECT_LE(availableWidth, kWidth);
- EXPECT_GT(availableWidth, kWidth - kBorderWidth);
-
- // With minor contents, most of the remaining width is available for
- // decorations.
- NSDictionary* attributes =
- [NSDictionary dictionaryWithObject:[field_ font]
- forKey:NSFontAttributeName];
- NSString* string = @"Hello world";
- const NSSize size([string sizeWithAttributes:attributes]);
- [field_ setStringValue:string];
- availableWidth = [field_ availableDecorationWidth];
- EXPECT_LE(availableWidth, kWidth - size.width);
- EXPECT_GT(availableWidth, kWidth - size.width - kBorderWidth);
-
- // With huge contents, nothing at all is left for decorations.
- string = @"A long string which is surely wider than field_ can hold.";
- [field_ setStringValue:string];
- availableWidth = [field_ availableDecorationWidth];
- EXPECT_LT(availableWidth, 0.0);
-}
-
-// Test drawing, mostly to ensure nothing leaks or crashes.
-TEST_F(StyledTextFieldTest, Display) {
- [field_ display];
-
- // Test focused drawing.
- [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
- [field_ display];
-}
-
-// Test that the field editor gets the same bounds when focus is delivered by
-// the standard focusing machinery, or by -resetFieldEditorFrameIfNeeded.
-TEST_F(StyledTextFieldTest, ResetFieldEditorBase) {
- // Capture the editor frame resulting from the standard focus machinery.
- [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
- const NSRect baseEditorFrame(EditorFrame());
-
- // Setting a hint should result in a strictly smaller editor frame.
- EXPECT_EQ(0, [cell_ leftMargin]);
- EXPECT_EQ(0, [cell_ rightMargin]);
- [cell_ setLeftMargin:10];
- [field_ resetFieldEditorFrameIfNeeded];
- EXPECT_FALSE(NSEqualRects(baseEditorFrame, EditorFrame()));
- EXPECT_TRUE(NSContainsRect(baseEditorFrame, EditorFrame()));
-
- // Resetting the margin and using -resetFieldEditorFrameIfNeeded should result
- // in the same frame as the standard focus machinery.
- [cell_ setLeftMargin:0];
- [field_ resetFieldEditorFrameIfNeeded];
- EXPECT_TRUE(NSEqualRects(baseEditorFrame, EditorFrame()));
-}
-
-// Test that the field editor gets the same bounds when focus is delivered by
-// the standard focusing machinery, or by -resetFieldEditorFrameIfNeeded.
-TEST_F(StyledTextFieldTest, ResetFieldEditorLeftMargin) {
- const CGFloat kLeftMargin = 20;
-
- // Start the cell off with a non-zero left margin.
- [cell_ setLeftMargin:kLeftMargin];
- [cell_ setRightMargin:0];
-
- // Capture the editor frame resulting from the standard focus machinery.
- [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
- const NSRect baseEditorFrame(EditorFrame());
-
- // Clearing the margin should result in a strictly larger editor frame.
- [cell_ setLeftMargin:0];
- [field_ resetFieldEditorFrameIfNeeded];
- EXPECT_FALSE(NSEqualRects(baseEditorFrame, EditorFrame()));
- EXPECT_TRUE(NSContainsRect(EditorFrame(), baseEditorFrame));
-
- // Setting the same margin and using -resetFieldEditorFrameIfNeeded should
- // result in the same frame as the standard focus machinery.
- [cell_ setLeftMargin:kLeftMargin];
- [field_ resetFieldEditorFrameIfNeeded];
- EXPECT_TRUE(NSEqualRects(baseEditorFrame, EditorFrame()));
-}
-
-// Test that the field editor gets the same bounds when focus is delivered by
-// the standard focusing machinery, or by -resetFieldEditorFrameIfNeeded.
-TEST_F(StyledTextFieldTest, ResetFieldEditorRightMargin) {
- const CGFloat kRightMargin = 20;
-
- // Start the cell off with a non-zero right margin.
- [cell_ setLeftMargin:0];
- [cell_ setRightMargin:kRightMargin];
-
- // Capture the editor frame resulting from the standard focus machinery.
- [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
- const NSRect baseEditorFrame(EditorFrame());
-
- // Clearing the margin should result in a strictly larger editor frame.
- [cell_ setRightMargin:0];
- [field_ resetFieldEditorFrameIfNeeded];
- EXPECT_FALSE(NSEqualRects(baseEditorFrame, EditorFrame()));
- EXPECT_TRUE(NSContainsRect(EditorFrame(), baseEditorFrame));
-
- // Setting the same margin and using -resetFieldEditorFrameIfNeeded should
- // result in the same frame as the standard focus machinery.
- [cell_ setRightMargin:kRightMargin];
- [field_ resetFieldEditorFrameIfNeeded];
- EXPECT_TRUE(NSEqualRects(baseEditorFrame, EditorFrame()));
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/tab_contents_controller.h b/chrome/browser/cocoa/tab_contents_controller.h
deleted file mode 100644
index 46a1ca5..0000000
--- a/chrome/browser/cocoa/tab_contents_controller.h
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_TAB_CONTENTS_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_TAB_CONTENTS_CONTROLLER_H_
-#pragma once
-
-#include <Cocoa/Cocoa.h>
-
-#include "base/scoped_ptr.h"
-
-class TabContents;
-class TabContentsNotificationBridge;
-@class TabContentsController;
-
-// The interface for the tab contents view controller's delegate.
-
-@protocol TabContentsControllerDelegate
-
-// Tells the delegate when the tab contents view's frame is about to change.
-- (void)tabContentsViewFrameWillChange:(TabContentsController*)source
- frameRect:(NSRect)frameRect;
-
-@end
-
-// A class that controls the TabContents view. It manages displaying the
-// native view for a given TabContents.
-// Note that just creating the class does not display the view. We defer
-// inserting it until the box is the correct size to avoid multiple resize
-// messages to the renderer. You must call |-ensureContentsVisible| to display
-// the render widget host view.
-
-@interface TabContentsController : NSViewController {
- @private
- TabContents* contents_; // weak
- // Delegate to be notified about size changes.
- id<TabContentsControllerDelegate> delegate_; // weak
- scoped_ptr<TabContentsNotificationBridge> tabContentsBridge_;
-}
-@property(readonly, nonatomic) TabContents* tabContents;
-
-- (id)initWithContents:(TabContents*)contents
- delegate:(id<TabContentsControllerDelegate>)delegate;
-
-// Call when the tab contents is about to be replaced with the currently
-// selected tab contents to do not trigger unnecessary content relayout.
-- (void)ensureContentsSizeDoesNotChange;
-
-// Call when the tab view is properly sized and the render widget host view
-// should be put into the view hierarchy.
-- (void)ensureContentsVisible;
-
-// Call to change the underlying tab contents object. View is not changed,
-// call |-ensureContentsVisible| to display the |newContents|'s render widget
-// host view.
-- (void)changeTabContents:(TabContents*)newContents;
-
-// Called when the tab contents is the currently selected tab and is about to be
-// removed from the view hierarchy.
-- (void)willBecomeUnselectedTab;
-
-// Called when the tab contents is about to be put into the view hierarchy as
-// the selected tab. Handles things such as ensuring the toolbar is correctly
-// enabled.
-- (void)willBecomeSelectedTab;
-
-// Called when the tab contents is updated in some non-descript way (the
-// notification from the model isn't specific). |updatedContents| could reflect
-// an entirely new tab contents object.
-- (void)tabDidChange:(TabContents*)updatedContents;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_TAB_CONTENTS_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/tab_contents_controller.mm b/chrome/browser/cocoa/tab_contents_controller.mm
deleted file mode 100644
index 4a5cd43..0000000
--- a/chrome/browser/cocoa/tab_contents_controller.mm
+++ /dev/null
@@ -1,212 +0,0 @@
-// 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 "chrome/browser/cocoa/tab_contents_controller.h"
-
-#include "base/mac_util.h"
-#include "base/scoped_nsobject.h"
-#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/renderer_host/render_widget_host_view.h"
-#include "chrome/browser/tab_contents/navigation_controller.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/notification_details.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_source.h"
-#include "chrome/common/notification_type.h"
-
-
-@interface TabContentsController(Private)
-// Forwards frame update to |delegate_| (ResizeNotificationView calls it).
-- (void)tabContentsViewFrameWillChange:(NSRect)frameRect;
-// Notification from TabContents (forwarded by TabContentsNotificationBridge).
-- (void)tabContentsRenderViewHostChanged:(RenderViewHost*)oldHost
- newHost:(RenderViewHost*)newHost;
-@end
-
-
-// A supporting C++ bridge object to register for TabContents notifications.
-
-class TabContentsNotificationBridge : public NotificationObserver {
- public:
- explicit TabContentsNotificationBridge(TabContentsController* controller);
-
- // Overriden from NotificationObserver.
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
- // Register for |contents|'s notifications, remove all prior registrations.
- void ChangeTabContents(TabContents* contents);
- private:
- NotificationRegistrar registrar_;
- TabContentsController* controller_; // weak, owns us
-};
-
-TabContentsNotificationBridge::TabContentsNotificationBridge(
- TabContentsController* controller)
- : controller_(controller) {
-}
-
-void TabContentsNotificationBridge::Observe(
- NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- if (type == NotificationType::RENDER_VIEW_HOST_CHANGED) {
- RenderViewHostSwitchedDetails* switched_details =
- Details<RenderViewHostSwitchedDetails>(details).ptr();
- [controller_ tabContentsRenderViewHostChanged:switched_details->old_host
- newHost:switched_details->new_host];
- } else {
- NOTREACHED();
- }
-}
-
-void TabContentsNotificationBridge::ChangeTabContents(TabContents* contents) {
- registrar_.RemoveAll();
- if (contents) {
- registrar_.Add(this,
- NotificationType::RENDER_VIEW_HOST_CHANGED,
- Source<NavigationController>(&contents->controller()));
- }
-}
-
-
-// A custom view that notifies |controller| that view's frame is changing.
-
-@interface ResizeNotificationView : NSView {
- TabContentsController* controller_;
-}
-- (id)initWithController:(TabContentsController*)controller;
-@end
-
-@implementation ResizeNotificationView
-
-- (id)initWithController:(TabContentsController*)controller {
- if ((self = [super initWithFrame:NSZeroRect])) {
- controller_ = controller;
- }
- return self;
-}
-
-- (void)setFrame:(NSRect)frameRect {
- [controller_ tabContentsViewFrameWillChange:frameRect];
- [super setFrame:frameRect];
-}
-
-@end
-
-
-@implementation TabContentsController
-@synthesize tabContents = contents_;
-
-- (id)initWithContents:(TabContents*)contents
- delegate:(id<TabContentsControllerDelegate>)delegate {
- if ((self = [super initWithNibName:nil bundle:nil])) {
- contents_ = contents;
- delegate_ = delegate;
- tabContentsBridge_.reset(new TabContentsNotificationBridge(self));
- tabContentsBridge_->ChangeTabContents(contents);
- }
- return self;
-}
-
-- (void)dealloc {
- // make sure our contents have been removed from the window
- [[self view] removeFromSuperview];
- [super dealloc];
-}
-
-- (void)loadView {
- scoped_nsobject<ResizeNotificationView> view(
- [[ResizeNotificationView alloc] initWithController:self]);
- [view setAutoresizingMask:NSViewHeightSizable|NSViewWidthSizable];
- [self setView:view];
-}
-
-- (void)ensureContentsSizeDoesNotChange {
- if (contents_) {
- NSView* contentsContainer = [self view];
- NSArray* subviews = [contentsContainer subviews];
- if ([subviews count] > 0)
- [contents_->GetNativeView() setAutoresizingMask:NSViewNotSizable];
- }
-}
-
-// Call when the tab view is properly sized and the render widget host view
-// should be put into the view hierarchy.
-- (void)ensureContentsVisible {
- if (!contents_)
- return;
- NSView* contentsContainer = [self view];
- NSArray* subviews = [contentsContainer subviews];
- NSView* contentsNativeView = contents_->GetNativeView();
-
- NSRect contentsNativeViewFrame = [contentsContainer frame];
- contentsNativeViewFrame.origin = NSZeroPoint;
-
- [delegate_ tabContentsViewFrameWillChange:self
- frameRect:contentsNativeViewFrame];
-
- // Native view is resized to the actual size before it becomes visible
- // to avoid flickering.
- [contentsNativeView setFrame:contentsNativeViewFrame];
- if ([subviews count] == 0) {
- [contentsContainer addSubview:contentsNativeView];
- } else if ([subviews objectAtIndex:0] != contentsNativeView) {
- [contentsContainer replaceSubview:[subviews objectAtIndex:0]
- with:contentsNativeView];
- }
- // Restore autoresizing properties possibly stripped by
- // ensureContentsSizeDoesNotChange call.
- [contentsNativeView setAutoresizingMask:NSViewWidthSizable|
- NSViewHeightSizable];
-}
-
-- (void)changeTabContents:(TabContents*)newContents {
- contents_ = newContents;
- tabContentsBridge_->ChangeTabContents(contents_);
-}
-
-- (void)tabContentsViewFrameWillChange:(NSRect)frameRect {
- [delegate_ tabContentsViewFrameWillChange:self frameRect:frameRect];
-}
-
-- (void)tabContentsRenderViewHostChanged:(RenderViewHost*)oldHost
- newHost:(RenderViewHost*)newHost {
- if (oldHost && newHost && oldHost->view() && newHost->view()) {
- newHost->view()->set_reserved_contents_rect(
- oldHost->view()->reserved_contents_rect());
- } else {
- [delegate_ tabContentsViewFrameWillChange:self
- frameRect:[[self view] frame]];
- }
-}
-
-- (void)willBecomeUnselectedTab {
- // The RWHV is ripped out of the view hierarchy on tab switches, so it never
- // formally resigns first responder status. Handle this by explicitly sending
- // a Blur() message to the renderer, but only if the RWHV currently has focus.
- RenderViewHost* rvh = [self tabContents]->render_view_host();
- if (rvh && rvh->view() && rvh->view()->HasFocus())
- rvh->Blur();
-}
-
-- (void)willBecomeSelectedTab {
- // Do not explicitly call Focus() here, as the RWHV may not actually have
- // focus (for example, if the omnibox has focus instead). The TabContents
- // logic will restore focus to the appropriate view.
-}
-
-- (void)tabDidChange:(TabContents*)updatedContents {
- // Calling setContentView: here removes any first responder status
- // the view may have, so avoid changing the view hierarchy unless
- // the view is different.
- if ([self tabContents] != updatedContents) {
- [self changeTabContents:updatedContents];
- if ([self tabContents])
- [self ensureContentsVisible];
- }
-}
-
-@end
diff --git a/chrome/browser/cocoa/tab_controller.h b/chrome/browser/cocoa/tab_controller.h
deleted file mode 100644
index 5a032ba..0000000
--- a/chrome/browser/cocoa/tab_controller.h
+++ /dev/null
@@ -1,113 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_TAB_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_TAB_CONTROLLER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-#import "chrome/browser/cocoa/hover_close_button.h"
-#include "chrome/browser/tab_menu_model.h"
-
-// The loading/waiting state of the tab.
-enum TabLoadingState {
- kTabDone,
- kTabLoading,
- kTabWaiting,
- kTabCrashed,
-};
-
-@class MenuController;
-namespace TabControllerInternal {
-class MenuDelegate;
-}
-@class TabView;
-@protocol TabControllerTarget;
-
-// A class that manages a single tab in the tab strip. Set its target/action
-// to be sent a message when the tab is selected by the user clicking. Setting
-// the |loading| property to YES visually indicates that this tab is currently
-// loading content via a spinner.
-//
-// The tab has the notion of an "icon view" which can be used to display
-// identifying characteristics such as a favicon, or since it's a full-fledged
-// view, something with state and animation such as a throbber for illustrating
-// progress. The default in the nib is an image view so nothing special is
-// required if that's all you need.
-
-@interface TabController : NSViewController {
- @private
- IBOutlet NSView* iconView_;
- IBOutlet NSTextField* titleView_;
- IBOutlet HoverCloseButton* closeButton_;
-
- NSRect originalIconFrame_; // frame of iconView_ as loaded from nib
- BOOL isIconShowing_; // last state of iconView_ in updateVisibility
-
- BOOL app_;
- BOOL mini_;
- BOOL pinned_;
- BOOL selected_;
- TabLoadingState loadingState_;
- CGFloat iconTitleXOffset_; // between left edges of icon and title
- CGFloat titleCloseWidthOffset_; // between right edges of icon and close btn.
- id<TabControllerTarget> target_; // weak, where actions are sent
- SEL action_; // selector sent when tab is selected by clicking
- scoped_ptr<TabMenuModel> contextMenuModel_;
- scoped_ptr<TabControllerInternal::MenuDelegate> contextMenuDelegate_;
- scoped_nsobject<MenuController> contextMenuController_;
-}
-
-@property(assign, nonatomic) TabLoadingState loadingState;
-
-@property(assign, nonatomic) SEL action;
-@property(assign, nonatomic) BOOL app;
-@property(assign, nonatomic) BOOL mini;
-@property(assign, nonatomic) BOOL pinned;
-@property(assign, nonatomic) BOOL selected;
-@property(assign, nonatomic) id target;
-
-// Minimum and maximum allowable tab width. The minimum width does not show
-// the icon or the close button. The selected tab always has at least a close
-// button so it has a different minimum width.
-+ (CGFloat)minTabWidth;
-+ (CGFloat)maxTabWidth;
-+ (CGFloat)minSelectedTabWidth;
-+ (CGFloat)miniTabWidth;
-+ (CGFloat)appTabWidth;
-
-// The view associated with this controller, pre-casted as a TabView
-- (TabView*)tabView;
-
-// Closes the associated TabView by relaying the message to |target_| to
-// perform the close.
-- (IBAction)closeTab:(id)sender;
-
-// Replace the current icon view with the given view. |iconView| will be
-// resized to the size of the current icon view.
-- (void)setIconView:(NSView*)iconView;
-- (NSView*)iconView;
-
-// Called by the tabs to determine whether we are in rapid (tab) closure mode.
-// In this mode, we handle clicks slightly differently due to animation.
-// Ideally, tabs would know about their own animation and wouldn't need this.
-- (BOOL)inRapidClosureMode;
-
-// Updates the visibility of certain subviews, such as the icon and close
-// button, based on criteria such as the tab's selected state and its current
-// width.
-- (void)updateVisibility;
-
-// Update the title color to match the tabs current state.
-- (void)updateTitleColor;
-@end
-
-@interface TabController(TestingAPI)
-- (NSString*)toolTip;
-- (int)iconCapacity;
-- (BOOL)shouldShowIcon;
-- (BOOL)shouldShowCloseButton;
-@end // TabController(TestingAPI)
-
-#endif // CHROME_BROWSER_COCOA_TAB_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/tab_controller.mm b/chrome/browser/cocoa/tab_controller.mm
deleted file mode 100644
index 6c607ad..0000000
--- a/chrome/browser/cocoa/tab_controller.mm
+++ /dev/null
@@ -1,313 +0,0 @@
-// 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.
-
-#include "app/l10n_util_mac.h"
-#include "base/mac_util.h"
-#import "chrome/browser/cocoa/menu_controller.h"
-#import "chrome/browser/cocoa/tab_controller.h"
-#import "chrome/browser/cocoa/tab_controller_target.h"
-#import "chrome/browser/cocoa/tab_view.h"
-#import "chrome/browser/cocoa/themed_window.h"
-#import "chrome/browser/themes/browser_theme_provider.h"
-#import "chrome/common/extensions/extension.h"
-#include "grit/generated_resources.h"
-
-@implementation TabController
-
-@synthesize action = action_;
-@synthesize app = app_;
-@synthesize loadingState = loadingState_;
-@synthesize mini = mini_;
-@synthesize pinned = pinned_;
-@synthesize target = target_;
-
-namespace TabControllerInternal {
-
-// A C++ delegate that handles enabling/disabling menu items and handling when
-// a menu command is chosen. Also fixes up the menu item label for "pin/unpin
-// tab".
-class MenuDelegate : public menus::SimpleMenuModel::Delegate {
- public:
- explicit MenuDelegate(id<TabControllerTarget> target, TabController* owner)
- : target_(target),
- owner_(owner) {}
-
- // Overridden from menus::SimpleMenuModel::Delegate
- virtual bool IsCommandIdChecked(int command_id) const { return false; }
- virtual bool IsCommandIdEnabled(int command_id) const {
- TabStripModel::ContextMenuCommand command =
- static_cast<TabStripModel::ContextMenuCommand>(command_id);
- return [target_ isCommandEnabled:command forController:owner_];
- }
- virtual bool GetAcceleratorForCommandId(
- int command_id,
- menus::Accelerator* accelerator) { return false; }
- virtual void ExecuteCommand(int command_id) {
- TabStripModel::ContextMenuCommand command =
- static_cast<TabStripModel::ContextMenuCommand>(command_id);
- [target_ commandDispatch:command forController:owner_];
- }
-
- private:
- id<TabControllerTarget> target_; // weak
- TabController* owner_; // weak, owns me
-};
-
-} // TabControllerInternal namespace
-
-// The min widths match the windows values and are sums of left + right
-// padding, of which we have no comparable constants (we draw using paths, not
-// images). The selected tab width includes the close button width.
-+ (CGFloat)minTabWidth { return 31; }
-+ (CGFloat)minSelectedTabWidth { return 46; }
-+ (CGFloat)maxTabWidth { return 220; }
-+ (CGFloat)miniTabWidth { return 53; }
-+ (CGFloat)appTabWidth { return 66; }
-
-- (TabView*)tabView {
- return static_cast<TabView*>([self view]);
-}
-
-- (id)init {
- self = [super initWithNibName:@"TabView" bundle:mac_util::MainAppBundle()];
- if (self != nil) {
- isIconShowing_ = YES;
- NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
- [defaultCenter addObserver:self
- selector:@selector(viewResized:)
- name:NSViewFrameDidChangeNotification
- object:[self view]];
- [defaultCenter addObserver:self
- selector:@selector(themeChangedNotification:)
- name:kBrowserThemeDidChangeNotification
- object:nil];
- }
- return self;
-}
-
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [[self tabView] setController:nil];
- [super dealloc];
-}
-
-// The internals of |-setSelected:| but doesn't check if we're already set
-// to |selected|. Pass the selection change to the subviews that need it and
-// mark ourselves as needing a redraw.
-- (void)internalSetSelected:(BOOL)selected {
- selected_ = selected;
- TabView* tabView = static_cast<TabView*>([self view]);
- DCHECK([tabView isKindOfClass:[TabView class]]);
- [tabView setState:selected];
- [tabView cancelAlert];
- [self updateVisibility];
- [self updateTitleColor];
-}
-
-// Called when the tab's nib is done loading and all outlets are hooked up.
-- (void)awakeFromNib {
- // Remember the icon's frame, so that if the icon is ever removed, a new
- // one can later replace it in the proper location.
- originalIconFrame_ = [iconView_ frame];
-
- // When the icon is removed, the title expands to the left to fill the space
- // left by the icon. When the close button is removed, the title expands to
- // the right to fill its space. These are the amounts to expand and contract
- // titleView_ under those conditions.
- NSRect titleFrame = [titleView_ frame];
- iconTitleXOffset_ = NSMinX(titleFrame) - NSMinX(originalIconFrame_);
- titleCloseWidthOffset_ = NSMaxX([closeButton_ frame]) - NSMaxX(titleFrame);
-
- [self internalSetSelected:selected_];
-}
-
-// Called when Cocoa wants to display the context menu. Lazily instantiate
-// the menu based off of the cross-platform model. Re-create the menu and
-// model every time to get the correct labels and enabling.
-- (NSMenu*)menu {
- contextMenuDelegate_.reset(
- new TabControllerInternal::MenuDelegate(target_, self));
- contextMenuModel_.reset(new TabMenuModel(contextMenuDelegate_.get(),
- [self pinned]));
- contextMenuController_.reset(
- [[MenuController alloc] initWithModel:contextMenuModel_.get()
- useWithPopUpButtonCell:NO]);
- return [contextMenuController_ menu];
-}
-
-- (IBAction)closeTab:(id)sender {
- if ([[self target] respondsToSelector:@selector(closeTab:)]) {
- [[self target] performSelector:@selector(closeTab:)
- withObject:[self view]];
- }
-}
-
-- (void)setTitle:(NSString*)title {
- [[self view] setToolTip:title];
- if ([self mini] && ![self selected]) {
- TabView* tabView = static_cast<TabView*>([self view]);
- DCHECK([tabView isKindOfClass:[TabView class]]);
- [tabView startAlert];
- }
- [super setTitle:title];
-}
-
-- (void)setSelected:(BOOL)selected {
- if (selected_ != selected)
- [self internalSetSelected:selected];
-}
-
-- (BOOL)selected {
- return selected_;
-}
-
-- (void)setIconView:(NSView*)iconView {
- [iconView_ removeFromSuperview];
- iconView_ = iconView;
- if ([self app]) {
- NSRect appIconFrame = [iconView frame];
- appIconFrame.origin = originalIconFrame_.origin;
- // Center the icon.
- appIconFrame.origin.x = ([TabController appTabWidth] -
- NSWidth(appIconFrame)) / 2.0;
- [iconView setFrame:appIconFrame];
- } else {
- [iconView_ setFrame:originalIconFrame_];
- }
- // Ensure that the icon is suppressed if no icon is set or if the tab is too
- // narrow to display one.
- [self updateVisibility];
-
- if (iconView_)
- [[self view] addSubview:iconView_];
-}
-
-- (NSView*)iconView {
- return iconView_;
-}
-
-- (NSString*)toolTip {
- return [[self view] toolTip];
-}
-
-// Return a rough approximation of the number of icons we could fit in the
-// tab. We never actually do this, but it's a helpful guide for determining
-// how much space we have available.
-- (int)iconCapacity {
- CGFloat width = NSMaxX([closeButton_ frame]) - NSMinX(originalIconFrame_);
- CGFloat iconWidth = NSWidth(originalIconFrame_);
-
- return width / iconWidth;
-}
-
-// Returns YES if we should show the icon. When tabs get too small, we clip
-// the favicon before the close button for selected tabs, and prefer the
-// favicon for unselected tabs. The icon can also be suppressed more directly
-// by clearing iconView_.
-- (BOOL)shouldShowIcon {
- if (!iconView_)
- return NO;
-
- if ([self mini])
- return YES;
-
- int iconCapacity = [self iconCapacity];
- if ([self selected])
- return iconCapacity >= 2;
- return iconCapacity >= 1;
-}
-
-// Returns YES if we should be showing the close button. The selected tab
-// always shows the close button.
-- (BOOL)shouldShowCloseButton {
- if ([self mini])
- return NO;
- return ([self selected] || [self iconCapacity] >= 3);
-}
-
-- (void)updateVisibility {
- // iconView_ may have been replaced or it may be nil, so [iconView_ isHidden]
- // won't work. Instead, the state of the icon is tracked separately in
- // isIconShowing_.
- BOOL oldShowIcon = isIconShowing_ ? YES : NO;
- BOOL newShowIcon = [self shouldShowIcon] ? YES : NO;
-
- [iconView_ setHidden:newShowIcon ? NO : YES];
- isIconShowing_ = newShowIcon;
-
- // If the tab is a mini-tab, hide the title.
- [titleView_ setHidden:[self mini]];
-
- BOOL oldShowCloseButton = [closeButton_ isHidden] ? NO : YES;
- BOOL newShowCloseButton = [self shouldShowCloseButton] ? YES : NO;
-
- [closeButton_ setHidden:newShowCloseButton ? NO : YES];
-
- // Adjust the title view based on changes to the icon's and close button's
- // visibility.
- NSRect titleFrame = [titleView_ frame];
-
- if (oldShowIcon != newShowIcon) {
- // Adjust the left edge of the title view according to the presence or
- // absence of the icon view.
-
- if (newShowIcon) {
- titleFrame.origin.x += iconTitleXOffset_;
- titleFrame.size.width -= iconTitleXOffset_;
- } else {
- titleFrame.origin.x -= iconTitleXOffset_;
- titleFrame.size.width += iconTitleXOffset_;
- }
- }
-
- if (oldShowCloseButton != newShowCloseButton) {
- // Adjust the right edge of the title view according to the presence or
- // absence of the close button.
- if (newShowCloseButton)
- titleFrame.size.width -= titleCloseWidthOffset_;
- else
- titleFrame.size.width += titleCloseWidthOffset_;
- }
-
- [titleView_ setFrame:titleFrame];
-}
-
-- (void)updateTitleColor {
- NSColor* titleColor = nil;
- ThemeProvider* theme = [[[self view] window] themeProvider];
- if (theme && ![self selected]) {
- titleColor =
- theme->GetNSColor(BrowserThemeProvider::COLOR_BACKGROUND_TAB_TEXT,
- true);
- }
- // Default to the selected text color unless told otherwise.
- if (theme && !titleColor) {
- titleColor = theme->GetNSColor(BrowserThemeProvider::COLOR_TAB_TEXT,
- true);
- }
- [titleView_ setTextColor:titleColor ? titleColor : [NSColor textColor]];
-}
-
-// Called when our view is resized. If it gets too small, start by hiding
-// the close button and only show it if tab is selected. Eventually, hide the
-// icon as well. We know that this is for our view because we only registered
-// for notifications from our specific view.
-- (void)viewResized:(NSNotification*)info {
- [self updateVisibility];
-}
-
-- (void)themeChangedNotification:(NSNotification*)notification {
- [self updateTitleColor];
-}
-
-// Called by the tabs to determine whether we are in rapid (tab) closure mode.
-- (BOOL)inRapidClosureMode {
- if ([[self target] respondsToSelector:@selector(inRapidClosureMode)]) {
- return [[self target] performSelector:@selector(inRapidClosureMode)] ?
- YES : NO;
- }
- return NO;
-}
-
-@end
diff --git a/chrome/browser/cocoa/tab_controller_target.h b/chrome/browser/cocoa/tab_controller_target.h
deleted file mode 100644
index 4e27b69..0000000
--- a/chrome/browser/cocoa/tab_controller_target.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_TAB_CONTROLLER_TARGET_H_
-#define CHROME_BROWSER_COCOA_TAB_CONTROLLER_TARGET_H_
-#pragma once
-
-#include "chrome/browser/tabs/tab_strip_model.h"
-
-@class TabController;
-
-// A protocol to be implemented by a TabController's target.
-@protocol TabControllerTarget
-- (void)selectTab:(id)sender;
-- (void)closeTab:(id)sender;
-
-// Dispatch context menu commands for the given tab controller.
-- (void)commandDispatch:(TabStripModel::ContextMenuCommand)command
- forController:(TabController*)controller;
-// Returns YES if the specificed command should be enabled for the given
-// controller.
-- (BOOL)isCommandEnabled:(TabStripModel::ContextMenuCommand)command
- forController:(TabController*)controller;
-@end
-
-#endif // CHROME_BROWSER_COCOA_TAB_CONTROLLER_TARGET_H_
diff --git a/chrome/browser/cocoa/tab_controller_unittest.mm b/chrome/browser/cocoa/tab_controller_unittest.mm
deleted file mode 100644
index 51f453e..0000000
--- a/chrome/browser/cocoa/tab_controller_unittest.mm
+++ /dev/null
@@ -1,268 +0,0 @@
-// Copyright (c) 2009 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>
-
-#import "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/tab_controller.h"
-#import "chrome/browser/cocoa/tab_controller_target.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-// Implements the target interface for the tab, which gets sent messages when
-// the tab is clicked on by the user and when its close box is clicked.
-@interface TabControllerTestTarget : NSObject<TabControllerTarget> {
- @private
- bool selected_;
- bool closed_;
-}
-- (bool)selected;
-- (bool)closed;
-@end
-
-@implementation TabControllerTestTarget
-- (bool)selected {
- return selected_;
-}
-- (bool)closed {
- return closed_;
-}
-- (void)selectTab:(id)sender {
- selected_ = true;
-}
-- (void)closeTab:(id)sender {
- closed_ = true;
-}
-- (void)mouseTimer:(NSTimer*)timer {
- // Fire the mouseUp to break the TabView drag loop.
- NSEvent* current = [NSApp currentEvent];
- NSWindow* window = [timer userInfo];
- NSEvent* up = [NSEvent mouseEventWithType:NSLeftMouseUp
- location:[current locationInWindow]
- modifierFlags:0
- timestamp:[current timestamp]
- windowNumber:[window windowNumber]
- context:nil
- eventNumber:0
- clickCount:1
- pressure:1.0];
- [window postEvent:up atStart:YES];
-}
-- (void)commandDispatch:(TabStripModel::ContextMenuCommand)command
- forController:(TabController*)controller {
-}
-- (BOOL)isCommandEnabled:(TabStripModel::ContextMenuCommand)command
- forController:(TabController*)controller {
- return NO;
-}
-@end
-
-namespace {
-
-// The dragging code in TabView makes heavy use of autorelease pools so
-// inherit from CocoaTest to have one created for us.
-class TabControllerTest : public CocoaTest {
- public:
- TabControllerTest() { }
-};
-
-// Tests creating the controller, sticking it in a window, and removing it.
-TEST_F(TabControllerTest, Creation) {
- NSWindow* window = test_window();
- scoped_nsobject<TabController> controller([[TabController alloc] init]);
- [[window contentView] addSubview:[controller view]];
- EXPECT_TRUE([controller tabView]);
- EXPECT_EQ([[controller view] window], window);
- [[controller view] display]; // Test drawing to ensure nothing leaks/crashes.
- [[controller view] removeFromSuperview];
-}
-
-// Tests sending it a close message and ensuring that the target/action get
-// called. Mimics the user clicking on the close button in the tab.
-TEST_F(TabControllerTest, Close) {
- NSWindow* window = test_window();
- scoped_nsobject<TabController> controller([[TabController alloc] init]);
- [[window contentView] addSubview:[controller view]];
-
- scoped_nsobject<TabControllerTestTarget> target(
- [[TabControllerTestTarget alloc] init]);
- EXPECT_FALSE([target closed]);
- [controller setTarget:target];
- EXPECT_EQ(target.get(), [controller target]);
-
- [controller closeTab:nil];
- EXPECT_TRUE([target closed]);
-
- [[controller view] removeFromSuperview];
-}
-
-// Tests setting the |selected| property via code.
-TEST_F(TabControllerTest, APISelection) {
- NSWindow* window = test_window();
- scoped_nsobject<TabController> controller([[TabController alloc] init]);
- [[window contentView] addSubview:[controller view]];
-
- EXPECT_FALSE([controller selected]);
- [controller setSelected:YES];
- EXPECT_TRUE([controller selected]);
-
- [[controller view] removeFromSuperview];
-}
-
-// Tests that setting the title of a tab sets the tooltip as well.
-TEST_F(TabControllerTest, ToolTip) {
- NSWindow* window = test_window();
-
- scoped_nsobject<TabController> controller([[TabController alloc] init]);
- [[window contentView] addSubview:[controller view]];
-
- EXPECT_TRUE([[controller toolTip] length] == 0);
- NSString *tooltip_string = @"Some text to use as a tab title";
- [controller setTitle:tooltip_string];
- EXPECT_NSEQ(tooltip_string, [controller toolTip]);
-}
-
-// Tests setting the |loading| property via code.
-TEST_F(TabControllerTest, Loading) {
- NSWindow* window = test_window();
- scoped_nsobject<TabController> controller([[TabController alloc] init]);
- [[window contentView] addSubview:[controller view]];
-
- EXPECT_EQ(kTabDone, [controller loadingState]);
- [controller setLoadingState:kTabWaiting];
- EXPECT_EQ(kTabWaiting, [controller loadingState]);
- [controller setLoadingState:kTabLoading];
- EXPECT_EQ(kTabLoading, [controller loadingState]);
- [controller setLoadingState:kTabDone];
- EXPECT_EQ(kTabDone, [controller loadingState]);
-
- [[controller view] removeFromSuperview];
-}
-
-// Tests selecting the tab with the mouse click and ensuring the target/action
-// get called.
-TEST_F(TabControllerTest, UserSelection) {
- NSWindow* window = test_window();
-
- // Create a tab at a known location in the window that we can click on
- // to activate selection.
- scoped_nsobject<TabController> controller([[TabController alloc] init]);
- [[window contentView] addSubview:[controller view]];
- NSRect frame = [[controller view] frame];
- frame.size.width = [TabController minTabWidth];
- frame.origin = NSMakePoint(0, 0);
- [[controller view] setFrame:frame];
-
- // Set the target and action.
- scoped_nsobject<TabControllerTestTarget> target(
- [[TabControllerTestTarget alloc] init]);
- EXPECT_FALSE([target selected]);
- [controller setTarget:target];
- [controller setAction:@selector(selectTab:)];
- EXPECT_EQ(target.get(), [controller target]);
- EXPECT_EQ(@selector(selectTab:), [controller action]);
-
- // In order to track a click, we have to fake a mouse down and a mouse
- // up, but the down goes into a tight drag loop. To break the loop, we have
- // to fire a timer that sends a mouse up event while the "drag" is ongoing.
- [NSTimer scheduledTimerWithTimeInterval:0.1
- target:target.get()
- selector:@selector(mouseTimer:)
- userInfo:window
- repeats:NO];
- NSEvent* current = [NSApp currentEvent];
- NSPoint click_point = NSMakePoint(frame.size.width / 2,
- frame.size.height / 2);
- NSEvent* down = [NSEvent mouseEventWithType:NSLeftMouseDown
- location:click_point
- modifierFlags:0
- timestamp:[current timestamp]
- windowNumber:[window windowNumber]
- context:nil
- eventNumber:0
- clickCount:1
- pressure:1.0];
- [[controller view] mouseDown:down];
-
- // Check our target was told the tab got selected.
- EXPECT_TRUE([target selected]);
-
- [[controller view] removeFromSuperview];
-}
-
-TEST_F(TabControllerTest, IconCapacity) {
- NSWindow* window = test_window();
- scoped_nsobject<TabController> controller([[TabController alloc] init]);
- [[window contentView] addSubview:[controller view]];
- int cap = [controller iconCapacity];
- EXPECT_GE(cap, 1);
-
- NSRect frame = [[controller view] frame];
- frame.size.width += 500;
- [[controller view] setFrame:frame];
- int newcap = [controller iconCapacity];
- EXPECT_GT(newcap, cap);
-}
-
-TEST_F(TabControllerTest, ShouldShowIcon) {
- NSWindow* window = test_window();
- scoped_nsobject<TabController> controller([[TabController alloc] init]);
- [[window contentView] addSubview:[controller view]];
- int cap = [controller iconCapacity];
- EXPECT_GT(cap, 0);
-
- // Tab is minimum width, both icon and close box should be hidden.
- NSRect frame = [[controller view] frame];
- frame.size.width = [TabController minTabWidth];
- [[controller view] setFrame:frame];
- EXPECT_FALSE([controller shouldShowIcon]);
- EXPECT_FALSE([controller shouldShowCloseButton]);
-
- // Setting the icon when tab is at min width should not show icon (bug 18359).
- scoped_nsobject<NSView> newIcon(
- [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 16, 16)]);
- [controller setIconView:newIcon.get()];
- EXPECT_TRUE([newIcon isHidden]);
-
- // Tab is at selected minimum width. Since it's selected, the close box
- // should be visible.
- [controller setSelected:YES];
- frame = [[controller view] frame];
- frame.size.width = [TabController minSelectedTabWidth];
- [[controller view] setFrame:frame];
- EXPECT_FALSE([controller shouldShowIcon]);
- EXPECT_TRUE([newIcon isHidden]);
- EXPECT_TRUE([controller shouldShowCloseButton]);
-
- // Test expanding the tab to max width and ensure the icon and close box
- // get put back, even when de-selected.
- frame.size.width = [TabController maxTabWidth];
- [[controller view] setFrame:frame];
- EXPECT_TRUE([controller shouldShowIcon]);
- EXPECT_FALSE([newIcon isHidden]);
- EXPECT_TRUE([controller shouldShowCloseButton]);
- [controller setSelected:NO];
- EXPECT_TRUE([controller shouldShowIcon]);
- EXPECT_TRUE([controller shouldShowCloseButton]);
-
- cap = [controller iconCapacity];
- EXPECT_GT(cap, 0);
-}
-
-TEST_F(TabControllerTest, Menu) {
- NSWindow* window = test_window();
- scoped_nsobject<TabController> controller([[TabController alloc] init]);
- [[window contentView] addSubview:[controller view]];
- int cap = [controller iconCapacity];
- EXPECT_GT(cap, 0);
-
- // Asking the view for its menu should yield a valid menu.
- NSMenu* menu = [[controller view] menu];
- EXPECT_TRUE(menu);
- EXPECT_GT([menu numberOfItems], 0);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/tab_strip_controller.h b/chrome/browser/cocoa/tab_strip_controller.h
deleted file mode 100644
index bc3210c..0000000
--- a/chrome/browser/cocoa/tab_strip_controller.h
+++ /dev/null
@@ -1,259 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_TAB_STRIP_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_TAB_STRIP_CONTROLLER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-#import "chrome/browser/cocoa/tab_contents_controller.h"
-#import "chrome/browser/cocoa/tab_controller_target.h"
-#import "chrome/browser/cocoa/url_drop_target.h"
-#import "third_party/GTM/AppKit/GTMWindowSheetController.h"
-
-@class NewTabButton;
-@class TabContentsController;
-@class TabView;
-@class TabStripView;
-
-class Browser;
-class ConstrainedWindowMac;
-class TabStripModelObserverBridge;
-class TabStripModel;
-class TabContents;
-class ToolbarModel;
-
-// The interface for the tab strip controller's delegate.
-// Delegating TabStripModelObserverBridge's events (in lieu of directly
-// subscribing to TabStripModelObserverBridge events, as TabStripController
-// does) is necessary to guarantee a proper order of subviews layout updates,
-// otherwise it might trigger unnesessary content relayout, UI flickering etc.
-@protocol TabStripControllerDelegate
-
-// Stripped down version of TabStripModelObserverBridge:selectTabWithContents.
-- (void)onSelectTabWithContents:(TabContents*)contents;
-
-// Stripped down version of TabStripModelObserverBridge:tabReplacedWithContents.
-- (void)onReplaceTabWithContents:(TabContents*)contents;
-
-// Stripped down version of TabStripModelObserverBridge:tabChangedWithContents.
-- (void)onSelectedTabChange:(TabStripModelObserver::TabChangeType)change;
-
-// Stripped down version of TabStripModelObserverBridge:tabDetachedWithContents.
-- (void)onTabDetachedWithContents:(TabContents*)contents;
-
-@end
-
-// A class that handles managing the tab strip in a browser window. It uses
-// a supporting C++ bridge object to register for notifications from the
-// TabStripModel. The Obj-C part of this class handles drag and drop and all
-// the other Cocoa-y aspects.
-//
-// For a full description of the design, see
-// http://www.chromium.org/developers/design-documents/tab-strip-mac
-@interface TabStripController :
- NSObject<TabControllerTarget,
- URLDropTargetController,
- GTMWindowSheetControllerDelegate,
- TabContentsControllerDelegate> {
- @protected
- // YES if tabs are to be laid out vertically instead of horizontally.
- BOOL verticalLayout_;
-
- @private
- scoped_nsobject<TabStripView> tabStripView_;
- NSView* switchView_; // weak
- scoped_nsobject<NSView> dragBlockingView_; // avoid bad window server drags
- NewTabButton* newTabButton_; // weak, obtained from the nib.
-
- // Tracks the newTabButton_ for rollovers.
- scoped_nsobject<NSTrackingArea> newTabTrackingArea_;
- scoped_ptr<TabStripModelObserverBridge> bridge_;
- Browser* browser_; // weak
- TabStripModel* tabStripModel_; // weak
- // Delegate that is informed about tab state changes.
- id<TabStripControllerDelegate> delegate_; // weak
-
- // YES if the new tab button is currently displaying the hover image (if the
- // mouse is currently over the button).
- BOOL newTabButtonShowingHoverImage_;
-
- // Access to the TabContentsControllers (which own the parent view
- // for the toolbar and associated tab contents) given an index. Call
- // |indexFromModelIndex:| to convert a |tabStripModel_| index to a
- // |tabContentsArray_| index. Do NOT assume that the indices of
- // |tabStripModel_| and this array are identical, this is e.g. not true while
- // tabs are animating closed (closed tabs are removed from |tabStripModel_|
- // immediately, but from |tabContentsArray_| only after their close animation
- // has completed).
- scoped_nsobject<NSMutableArray> tabContentsArray_;
- // An array of TabControllers which manage the actual tab views. See note
- // above |tabContentsArray_|. |tabContentsArray_| and |tabArray_| always
- // contain objects belonging to the same tabs at the same indices.
- scoped_nsobject<NSMutableArray> tabArray_;
-
- // Set of TabControllers that are currently animating closed.
- scoped_nsobject<NSMutableSet> closingControllers_;
-
- // These values are only used during a drag, and override tab positioning.
- TabView* placeholderTab_; // weak. Tab being dragged
- NSRect placeholderFrame_; // Frame to use
- CGFloat placeholderStretchiness_; // Vertical force shown by streching tab.
- NSRect droppedTabFrame_; // Initial frame of a dropped tab, for animation.
- // Frame targets for all the current views.
- // target frames are used because repeated requests to [NSView animator].
- // aren't coalesced, so we store frames to avoid redundant calls.
- scoped_nsobject<NSMutableDictionary> targetFrames_;
- NSRect newTabTargetFrame_;
- // If YES, do not show the new tab button during layout.
- BOOL forceNewTabButtonHidden_;
- // YES if we've successfully completed the initial layout. When this is
- // NO, we probably don't want to do any animation because we're just coming
- // into being.
- BOOL initialLayoutComplete_;
-
- // Width available for resizing the tabs (doesn't include the new tab
- // button). Used to restrict the available width when closing many tabs at
- // once to prevent them from resizing to fit the full width. If the entire
- // width should be used, this will have a value of |kUseFullAvailableWidth|.
- float availableResizeWidth_;
- // A tracking area that's the size of the tab strip used to be notified
- // when the mouse moves in the tab strip
- scoped_nsobject<NSTrackingArea> trackingArea_;
- TabView* hoveredTab_; // weak. Tab that the mouse is hovering over
-
- // Array of subviews which are permanent (and which should never be removed),
- // such as the new-tab button, but *not* the tabs themselves.
- scoped_nsobject<NSMutableArray> permanentSubviews_;
-
- // The default favicon, so we can use one copy for all buttons.
- scoped_nsobject<NSImage> defaultFavIcon_;
-
- // The amount by which to indent the tabs on the left (to make room for the
- // red/yellow/green buttons).
- CGFloat indentForControls_;
-
- // Manages per-tab sheets.
- scoped_nsobject<GTMWindowSheetController> sheetController_;
-
- // Is the mouse currently inside the strip;
- BOOL mouseInside_;
-}
-
-@property(nonatomic) CGFloat indentForControls;
-
-// Initialize the controller with a view and browser that contains
-// everything else we'll need. |switchView| is the view whose contents get
-// "switched" every time the user switches tabs. The children of this view
-// will be released, so if you want them to stay around, make sure
-// you have retained them.
-// |delegate| is the one listening to filtered TabStripModelObserverBridge's
-// events (see TabStripControllerDelegate for more details).
-- (id)initWithView:(TabStripView*)view
- switchView:(NSView*)switchView
- browser:(Browser*)browser
- delegate:(id<TabStripControllerDelegate>)delegate;
-
-// Return the view for the currently selected tab.
-- (NSView*)selectedTabView;
-
-// Set the frame of the selected tab, also updates the internal frame dict.
-- (void)setFrameOfSelectedTab:(NSRect)frame;
-
-// Move the given tab at index |from| in this window to the location of the
-// current placeholder.
-- (void)moveTabFromIndex:(NSInteger)from;
-
-// Drop a given TabContents at the location of the current placeholder. If there
-// is no placeholder, it will go at the end. Used when dragging from another
-// window when we don't have access to the TabContents as part of our strip.
-// |frame| is in the coordinate system of the tab strip view and represents
-// where the user dropped the new tab so it can be animated into its correct
-// location when the tab is added to the model. If the tab was pinned in its
-// previous window, setting |pinned| to YES will propagate that state to the
-// new window. Mini-tabs are either app or pinned tabs; the app state is stored
-// by the |contents|, but the |pinned| state is the caller's responsibility.
-- (void)dropTabContents:(TabContentsWrapper*)contents
- withFrame:(NSRect)frame
- asPinnedTab:(BOOL)pinned;
-
-// Returns the index of the subview |view|. Returns -1 if not present. Takes
-// closing tabs into account such that this index will correctly match the tab
-// model. If |view| is in the process of closing, returns -1, as closing tabs
-// are no longer in the model.
-- (NSInteger)modelIndexForTabView:(NSView*)view;
-
-// Return the view at a given index.
-- (NSView*)viewAtIndex:(NSUInteger)index;
-
-// Return the number of tab views in the tab strip. It's same as number of tabs
-// in the model, except when a tab is closing, which will be counted in views
-// count, but no longer in the model.
-- (NSUInteger)viewsCount;
-
-// Set the placeholder for a dragged tab, allowing the |frame| and |strechiness|
-// to be specified. This causes this tab to be rendered in an arbitrary position
-- (void)insertPlaceholderForTab:(TabView*)tab
- frame:(NSRect)frame
- yStretchiness:(CGFloat)yStretchiness;
-
-// Returns whether or not |tab| can still be fully seen in the tab strip or if
-// its current position would cause it be obscured by things such as the edge
-// of the window or the window decorations. Returns YES only if the entire tab
-// is visible.
-- (BOOL)isTabFullyVisible:(TabView*)tab;
-
-// Show or hide the new tab button. The button is hidden immediately, but
-// waits until the next call to |-layoutTabs| to show it again.
-- (void)showNewTabButton:(BOOL)show;
-
-// Force the tabs to rearrange themselves to reflect the current model.
-- (void)layoutTabs;
-
-// Are we in rapid (tab) closure mode? I.e., is a full layout deferred (while
-// the user closes tabs)? Needed to overcome missing clicks during rapid tab
-// closure.
-- (BOOL)inRapidClosureMode;
-
-// Returns YES if the user is allowed to drag tabs on the strip at this moment.
-// For example, this returns NO if there are any pending tab close animtations.
-- (BOOL)tabDraggingAllowed;
-
-// Default height for tabs.
-+ (CGFloat)defaultTabHeight;
-
-// Default indentation for tabs (see |indentForControls_|).
-+ (CGFloat)defaultIndentForControls;
-
-// Returns the (lazily created) window sheet controller of this window. Used
-// for the per-tab sheets.
-- (GTMWindowSheetController*)sheetController;
-
-// Destroys the window sheet controller of this window, if it exists. The sheet
-// controller can be recreated by a subsequent call to |-sheetController|. Must
-// not be called if any sheets are currently open.
-// TODO(viettrungluu): This is temporary code needed to allow sheets to work
-// (read: not crash) in fullscreen mode. Once GTMWindowSheetController is
-// modified to support moving sheets between windows, this code can go away.
-// http://crbug.com/19093.
-- (void)destroySheetController;
-
-// Returns the currently active TabContentsController.
-- (TabContentsController*)activeTabContentsController;
-
- // See comments in browser_window_controller.h for documentation about these
- // functions.
-- (void)attachConstrainedWindow:(ConstrainedWindowMac*)window;
-- (void)removeConstrainedWindow:(ConstrainedWindowMac*)window;
-
-@end
-
-// Notification sent when the number of tabs changes. The object will be this
-// controller.
-extern NSString* const kTabStripNumberOfTabsChanged;
-
-#endif // CHROME_BROWSER_COCOA_TAB_STRIP_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/tab_strip_controller.mm b/chrome/browser/cocoa/tab_strip_controller.mm
deleted file mode 100644
index 8adf673..0000000
--- a/chrome/browser/cocoa/tab_strip_controller.mm
+++ /dev/null
@@ -1,1879 +0,0 @@
-// 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 "chrome/browser/cocoa/tab_strip_controller.h"
-
-#import <QuartzCore/QuartzCore.h>
-
-#include <limits>
-#include <string>
-
-#include "app/l10n_util.h"
-#include "app/resource_bundle.h"
-#include "base/mac_util.h"
-#include "base/nsimage_cache_mac.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/find_bar.h"
-#include "chrome/browser/find_bar_controller.h"
-#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/profile.h"
-#import "chrome/browser/cocoa/browser_window_controller.h"
-#import "chrome/browser/cocoa/constrained_window_mac.h"
-#import "chrome/browser/cocoa/new_tab_button.h"
-#import "chrome/browser/cocoa/tab_strip_view.h"
-#import "chrome/browser/cocoa/tab_contents_controller.h"
-#import "chrome/browser/cocoa/tab_controller.h"
-#import "chrome/browser/cocoa/tab_strip_model_observer_bridge.h"
-#import "chrome/browser/cocoa/tab_view.h"
-#import "chrome/browser/cocoa/throbber_view.h"
-#include "chrome/browser/debugger/devtools_window.h"
-#include "chrome/browser/net/url_fixer_upper.h"
-#include "chrome/browser/sidebar/sidebar_container.h"
-#include "chrome/browser/sidebar/sidebar_manager.h"
-#include "chrome/browser/tab_contents/navigation_controller.h"
-#include "chrome/browser/tab_contents/navigation_entry.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents/tab_contents_view.h"
-#include "chrome/browser/tab_contents_wrapper.h"
-#include "chrome/browser/tabs/tab_strip_model.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_navigator.h"
-#include "grit/app_resources.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#include "skia/ext/skia_utils_mac.h"
-#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
-
-NSString* const kTabStripNumberOfTabsChanged = @"kTabStripNumberOfTabsChanged";
-
-namespace {
-
-// The images names used for different states of the new tab button.
-NSString* const kNewTabHoverImage = @"newtab_h.pdf";
-NSString* const kNewTabImage = @"newtab.pdf";
-NSString* const kNewTabPressedImage = @"newtab_p.pdf";
-
-// A value to indicate tab layout should use the full available width of the
-// view.
-const CGFloat kUseFullAvailableWidth = -1.0;
-
-// The amount by which tabs overlap.
-const CGFloat kTabOverlap = 20.0;
-
-// The width and height for a tab's icon.
-const CGFloat kIconWidthAndHeight = 16.0;
-
-// The amount by which the new tab button is offset (from the tabs).
-const CGFloat kNewTabButtonOffset = 8.0;
-
-// The amount by which to shrink the tab strip (on the right) when the
-// incognito badge is present.
-const CGFloat kIncognitoBadgeTabStripShrink = 18;
-
-// Time (in seconds) in which tabs animate to their final position.
-const NSTimeInterval kAnimationDuration = 0.125;
-
-// Helper class for doing NSAnimationContext calls that takes a bool to disable
-// all the work. Useful for code that wants to conditionally animate.
-class ScopedNSAnimationContextGroup {
- public:
- explicit ScopedNSAnimationContextGroup(bool animate)
- : animate_(animate) {
- if (animate_) {
- [NSAnimationContext beginGrouping];
- }
- }
-
- ~ScopedNSAnimationContextGroup() {
- if (animate_) {
- [NSAnimationContext endGrouping];
- }
- }
-
- void SetCurrentContextDuration(NSTimeInterval duration) {
- if (animate_) {
- [[NSAnimationContext currentContext] gtm_setDuration:duration
- eventMask:NSLeftMouseUpMask];
- }
- }
-
- void SetCurrentContextShortestDuration() {
- if (animate_) {
- // The minimum representable time interval. This used to stop an
- // in-progress animation as quickly as possible.
- const NSTimeInterval kMinimumTimeInterval =
- std::numeric_limits<NSTimeInterval>::min();
- // Directly set the duration to be short, avoiding the Steve slowmotion
- // ettect the gtm_setDuration: provides.
- [[NSAnimationContext currentContext] setDuration:kMinimumTimeInterval];
- }
- }
-
-private:
- bool animate_;
- DISALLOW_COPY_AND_ASSIGN(ScopedNSAnimationContextGroup);
-};
-
-} // namespace
-
-@interface TabStripController (Private)
-- (void)installTrackingArea;
-- (void)addSubviewToPermanentList:(NSView*)aView;
-- (void)regenerateSubviewList;
-- (NSInteger)indexForContentsView:(NSView*)view;
-- (void)updateFavIconForContents:(TabContents*)contents
- atIndex:(NSInteger)modelIndex;
-- (void)layoutTabsWithAnimation:(BOOL)animate
- regenerateSubviews:(BOOL)doUpdate;
-- (void)animationDidStopForController:(TabController*)controller
- finished:(BOOL)finished;
-- (NSInteger)indexFromModelIndex:(NSInteger)index;
-- (NSInteger)numberOfOpenTabs;
-- (NSInteger)numberOfOpenMiniTabs;
-- (NSInteger)numberOfOpenNonMiniTabs;
-- (void)mouseMoved:(NSEvent*)event;
-- (void)setTabTrackingAreasEnabled:(BOOL)enabled;
-- (void)droppingURLsAt:(NSPoint)point
- givesIndex:(NSInteger*)index
- disposition:(WindowOpenDisposition*)disposition;
-- (void)setNewTabButtonHoverState:(BOOL)showHover;
-@end
-
-// A simple view class that prevents the Window Server from dragging the area
-// behind tabs. Sometimes core animation confuses it. Unfortunately, it can also
-// falsely pick up clicks during rapid tab closure, so we have to account for
-// that.
-@interface TabStripControllerDragBlockingView : NSView {
- TabStripController* controller_; // weak; owns us
-}
-
-- (id)initWithFrame:(NSRect)frameRect
- controller:(TabStripController*)controller;
-@end
-
-@implementation TabStripControllerDragBlockingView
-- (BOOL)mouseDownCanMoveWindow {return NO;}
-- (void)drawRect:(NSRect)rect {}
-
-- (id)initWithFrame:(NSRect)frameRect
- controller:(TabStripController*)controller {
- if ((self = [super initWithFrame:frameRect]))
- controller_ = controller;
- return self;
-}
-
-// In "rapid tab closure" mode (i.e., the user is clicking close tab buttons in
-// rapid succession), the animations confuse Cocoa's hit testing (which appears
-// to use cached results, among other tricks), so this view can somehow end up
-// getting a mouse down event. Thus we do an explicit hit test during rapid tab
-// closure, and if we find that we got a mouse down we shouldn't have, we send
-// it off to the appropriate view.
-- (void)mouseDown:(NSEvent*)event {
- if ([controller_ inRapidClosureMode]) {
- NSView* superview = [self superview];
- NSPoint hitLocation =
- [[superview superview] convertPoint:[event locationInWindow]
- fromView:nil];
- NSView* hitView = [superview hitTest:hitLocation];
- if (hitView != self) {
- [hitView mouseDown:event];
- return;
- }
- }
- [super mouseDown:event];
-}
-@end
-
-#pragma mark -
-
-// A delegate, owned by the CAAnimation system, that is alerted when the
-// animation to close a tab is completed. Calls back to the given tab strip
-// to let it know that |controller_| is ready to be removed from the model.
-// Since we only maintain weak references, the tab strip must call -invalidate:
-// to prevent the use of dangling pointers.
-@interface TabCloseAnimationDelegate : NSObject {
- @private
- TabStripController* strip_; // weak; owns us indirectly
- TabController* controller_; // weak
-}
-
-// Will tell |strip| when the animation for |controller|'s view has completed.
-// These should not be nil, and will not be retained.
-- (id)initWithTabStrip:(TabStripController*)strip
- tabController:(TabController*)controller;
-
-// Invalidates this object so that no further calls will be made to
-// |strip_|. This should be called when |strip_| is released, to
-// prevent attempts to call into the released object.
-- (void)invalidate;
-
-// CAAnimation delegate method
-- (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)finished;
-
-@end
-
-@implementation TabCloseAnimationDelegate
-
-- (id)initWithTabStrip:(TabStripController*)strip
- tabController:(TabController*)controller {
- if ((self == [super init])) {
- DCHECK(strip && controller);
- strip_ = strip;
- controller_ = controller;
- }
- return self;
-}
-
-- (void)invalidate {
- strip_ = nil;
- controller_ = nil;
-}
-
-- (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)finished {
- [strip_ animationDidStopForController:controller_ finished:finished];
-}
-
-@end
-
-#pragma mark -
-
-// In general, there is a one-to-one correspondence between TabControllers,
-// TabViews, TabContentsControllers, and the TabContents in the TabStripModel.
-// In the steady-state, the indices line up so an index coming from the model
-// is directly mapped to the same index in the parallel arrays holding our
-// views and controllers. This is also true when new tabs are created (even
-// though there is a small period of animation) because the tab is present
-// in the model while the TabView is animating into place. As a result, nothing
-// special need be done to handle "new tab" animation.
-//
-// This all goes out the window with the "close tab" animation. The animation
-// kicks off in |-tabDetachedWithContents:atIndex:| with the notification that
-// the tab has been removed from the model. The simplest solution at this
-// point would be to remove the views and controllers as well, however once
-// the TabView is removed from the view list, the tab z-order code takes care of
-// removing it from the tab strip and we'll get no animation. That means if
-// there is to be any visible animation, the TabView needs to stay around until
-// its animation is complete. In order to maintain consistency among the
-// internal parallel arrays, this means all structures are kept around until
-// the animation completes. At this point, though, the model and our internal
-// structures are out of sync: the indices no longer line up. As a result,
-// there is a concept of a "model index" which represents an index valid in
-// the TabStripModel. During steady-state, the "model index" is just the same
-// index as our parallel arrays (as above), but during tab close animations,
-// it is different, offset by the number of tabs preceding the index which
-// are undergoing tab closing animation. As a result, the caller needs to be
-// careful to use the available conversion routines when accessing the internal
-// parallel arrays (e.g., -indexFromModelIndex:). Care also needs to be taken
-// during tab layout to ignore closing tabs in the total width calculations and
-// in individual tab positioning (to avoid moving them right back to where they
-// were).
-//
-// In order to prevent actions being taken on tabs which are closing, the tab
-// itself gets marked as such so it no longer will send back its select action
-// or allow itself to be dragged. In addition, drags on the tab strip as a
-// whole are disabled while there are tabs closing.
-
-@implementation TabStripController
-
-@synthesize indentForControls = indentForControls_;
-
-- (id)initWithView:(TabStripView*)view
- switchView:(NSView*)switchView
- browser:(Browser*)browser
- delegate:(id<TabStripControllerDelegate>)delegate {
- DCHECK(view && switchView && browser && delegate);
- if ((self = [super init])) {
- tabStripView_.reset([view retain]);
- switchView_ = switchView;
- browser_ = browser;
- tabStripModel_ = browser_->tabstrip_model();
- delegate_ = delegate;
- bridge_.reset(new TabStripModelObserverBridge(tabStripModel_, self));
- tabContentsArray_.reset([[NSMutableArray alloc] init]);
- tabArray_.reset([[NSMutableArray alloc] init]);
-
- // Important note: any non-tab subviews not added to |permanentSubviews_|
- // (see |-addSubviewToPermanentList:|) will be wiped out.
- permanentSubviews_.reset([[NSMutableArray alloc] init]);
-
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- defaultFavIcon_.reset([rb.GetNativeImageNamed(IDR_DEFAULT_FAVICON) retain]);
-
- [self setIndentForControls:[[self class] defaultIndentForControls]];
-
- // TODO(viettrungluu): WTF? "For some reason, if the view is present in the
- // nib a priori, it draws correctly. If we create it in code and add it to
- // the tab view, it draws with all sorts of crazy artifacts."
- newTabButton_ = [view newTabButton];
- [self addSubviewToPermanentList:newTabButton_];
- [newTabButton_ setTarget:nil];
- [newTabButton_ setAction:@selector(commandDispatch:)];
- [newTabButton_ setTag:IDC_NEW_TAB];
- // Set the images from code because Cocoa fails to find them in our sub
- // bundle during tests.
- [newTabButton_ setImage:nsimage_cache::ImageNamed(kNewTabImage)];
- [newTabButton_
- setAlternateImage:nsimage_cache::ImageNamed(kNewTabPressedImage)];
- newTabButtonShowingHoverImage_ = NO;
- newTabTrackingArea_.reset(
- [[NSTrackingArea alloc] initWithRect:[newTabButton_ bounds]
- options:(NSTrackingMouseEnteredAndExited |
- NSTrackingActiveAlways)
- owner:self
- userInfo:nil]);
- [newTabButton_ addTrackingArea:newTabTrackingArea_.get()];
- targetFrames_.reset([[NSMutableDictionary alloc] init]);
-
- dragBlockingView_.reset(
- [[TabStripControllerDragBlockingView alloc] initWithFrame:NSZeroRect
- controller:self]);
- [self addSubviewToPermanentList:dragBlockingView_];
-
- newTabTargetFrame_ = NSMakeRect(0, 0, 0, 0);
- availableResizeWidth_ = kUseFullAvailableWidth;
-
- closingControllers_.reset([[NSMutableSet alloc] init]);
-
- // Install the permanent subviews.
- [self regenerateSubviewList];
-
- // Watch for notifications that the tab strip view has changed size so
- // we can tell it to layout for the new size.
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(tabViewFrameChanged:)
- name:NSViewFrameDidChangeNotification
- object:tabStripView_];
-
- trackingArea_.reset([[NSTrackingArea alloc]
- initWithRect:NSZeroRect // Ignored by NSTrackingInVisibleRect
- options:NSTrackingMouseEnteredAndExited |
- NSTrackingMouseMoved |
- NSTrackingActiveAlways |
- NSTrackingInVisibleRect
- owner:self
- userInfo:nil]);
- [tabStripView_ addTrackingArea:trackingArea_.get()];
-
- // Check to see if the mouse is currently in our bounds so we can
- // enable the tracking areas. Otherwise we won't get hover states
- // or tab gradients if we load the window up under the mouse.
- NSPoint mouseLoc = [[view window] mouseLocationOutsideOfEventStream];
- mouseLoc = [view convertPoint:mouseLoc fromView:nil];
- if (NSPointInRect(mouseLoc, [view bounds])) {
- [self setTabTrackingAreasEnabled:YES];
- mouseInside_ = YES;
- }
-
- // Set accessibility descriptions. http://openradar.appspot.com/7496255
- NSString* description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_NEWTAB);
- [[newTabButton_ cell]
- accessibilitySetOverrideValue:description
- forAttribute:NSAccessibilityDescriptionAttribute];
-
- // Controller may have been (re-)created by switching layout modes, which
- // means the tab model is already fully formed with tabs. Need to walk the
- // list and create the UI for each.
- const int existingTabCount = tabStripModel_->count();
- const TabContentsWrapper* selection =
- tabStripModel_->GetSelectedTabContents();
- for (int i = 0; i < existingTabCount; ++i) {
- TabContentsWrapper* currentContents = tabStripModel_->GetTabContentsAt(i);
- [self insertTabWithContents:currentContents
- atIndex:i
- inForeground:NO];
- if (selection == currentContents) {
- // Must manually force a selection since the model won't send
- // selection messages in this scenario.
- [self selectTabWithContents:currentContents
- previousContents:NULL
- atIndex:i
- userGesture:NO];
- }
- }
- // Don't lay out the tabs until after the controller has been fully
- // constructed. The |verticalLayout_| flag has not been initialized by
- // subclasses at this point, which would cause layout to potentially use
- // the wrong mode.
- if (existingTabCount) {
- [self performSelectorOnMainThread:@selector(layoutTabs)
- withObject:nil
- waitUntilDone:NO];
- }
- }
- return self;
-}
-
-- (void)dealloc {
- if (trackingArea_.get())
- [tabStripView_ removeTrackingArea:trackingArea_.get()];
-
- [newTabButton_ removeTrackingArea:newTabTrackingArea_.get()];
- // Invalidate all closing animations so they don't call back to us after
- // we're gone.
- for (TabController* controller in closingControllers_.get()) {
- NSView* view = [controller view];
- [[[view animationForKey:@"frameOrigin"] delegate] invalidate];
- }
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [super dealloc];
-}
-
-+ (CGFloat)defaultTabHeight {
- return 25.0;
-}
-
-+ (CGFloat)defaultIndentForControls {
- // Default indentation leaves enough room so tabs don't overlap with the
- // window controls.
- return 64.0;
-}
-
-// Finds the TabContentsController associated with the given index into the tab
-// model and swaps out the sole child of the contentArea to display its
-// contents.
-- (void)swapInTabAtIndex:(NSInteger)modelIndex {
- DCHECK(modelIndex >= 0 && modelIndex < tabStripModel_->count());
- NSInteger index = [self indexFromModelIndex:modelIndex];
- TabContentsController* controller = [tabContentsArray_ objectAtIndex:index];
-
- // Resize the new view to fit the window. Calling |view| may lazily
- // instantiate the TabContentsController from the nib. Until we call
- // |-ensureContentsVisible|, the controller doesn't install the RWHVMac into
- // the view hierarchy. This is in order to avoid sending the renderer a
- // spurious default size loaded from the nib during the call to |-view|.
- NSView* newView = [controller view];
-
- // Turns content autoresizing off, so removing and inserting views won't
- // trigger unnecessary content relayout.
- [controller ensureContentsSizeDoesNotChange];
-
- // Remove the old view from the view hierarchy. We know there's only one
- // child of |switchView_| because we're the one who put it there. There
- // may not be any children in the case of a tab that's been closed, in
- // which case there's no swapping going on.
- NSArray* subviews = [switchView_ subviews];
- if ([subviews count]) {
- NSView* oldView = [subviews objectAtIndex:0];
- // Set newView frame to the oldVew frame to prevent NSSplitView hosting
- // sidebar and tab content from resizing sidebar's content view.
- // ensureContentsVisible (see below) sets content size and autoresizing
- // properties.
- [newView setFrame:[oldView frame]];
- [switchView_ replaceSubview:oldView with:newView];
- } else {
- [newView setFrame:[switchView_ bounds]];
- [switchView_ addSubview:newView];
- }
-
- // New content is in place, delegate should adjust itself accordingly.
- [delegate_ onSelectTabWithContents:[controller tabContents]];
-
- // It also restores content autoresizing properties.
- [controller ensureContentsVisible];
-
- // Make sure the new tabs's sheets are visible (necessary when a background
- // tab opened a sheet while it was in the background and now becomes active).
- TabContentsWrapper* newTab = tabStripModel_->GetTabContentsAt(modelIndex);
- DCHECK(newTab);
- if (newTab) {
- TabContents::ConstrainedWindowList::iterator it, end;
- end = newTab->tab_contents()->constrained_window_end();
- NSWindowController* controller = [[newView window] windowController];
- DCHECK([controller isKindOfClass:[BrowserWindowController class]]);
-
- for (it = newTab->tab_contents()->constrained_window_begin();
- it != end;
- ++it) {
- ConstrainedWindow* constrainedWindow = *it;
- static_cast<ConstrainedWindowMac*>(constrainedWindow)->Realize(
- static_cast<BrowserWindowController*>(controller));
- }
- }
-
- // Tell per-tab sheet manager about currently selected tab.
- if (sheetController_.get()) {
- [sheetController_ setActiveView:newView];
- }
-}
-
-// Create a new tab view and set its cell correctly so it draws the way we want
-// it to. It will be sized and positioned by |-layoutTabs| so there's no need to
-// set the frame here. This also creates the view as hidden, it will be
-// shown during layout.
-- (TabController*)newTab {
- TabController* controller = [[[TabController alloc] init] autorelease];
- [controller setTarget:self];
- [controller setAction:@selector(selectTab:)];
- [[controller view] setHidden:YES];
-
- return controller;
-}
-
-// (Private) Returns the number of open tabs in the tab strip. This is the
-// number of TabControllers we know about (as there's a 1-to-1 mapping from
-// these controllers to a tab) less the number of closing tabs.
-- (NSInteger)numberOfOpenTabs {
- return static_cast<NSInteger>(tabStripModel_->count());
-}
-
-// (Private) Returns the number of open, mini-tabs.
-- (NSInteger)numberOfOpenMiniTabs {
- // Ask the model for the number of mini tabs. Note that tabs which are in
- // the process of closing (i.e., whose controllers are in
- // |closingControllers_|) have already been removed from the model.
- return tabStripModel_->IndexOfFirstNonMiniTab();
-}
-
-// (Private) Returns the number of open, non-mini tabs.
-- (NSInteger)numberOfOpenNonMiniTabs {
- NSInteger number = [self numberOfOpenTabs] - [self numberOfOpenMiniTabs];
- DCHECK_GE(number, 0);
- return number;
-}
-
-// Given an index into the tab model, returns the index into the tab controller
-// or tab contents controller array accounting for tabs that are currently
-// closing. For example, if there are two tabs in the process of closing before
-// |index|, this returns |index| + 2. If there are no closing tabs, this will
-// return |index|.
-- (NSInteger)indexFromModelIndex:(NSInteger)index {
- DCHECK(index >= 0);
- if (index < 0)
- return index;
-
- NSInteger i = 0;
- for (TabController* controller in tabArray_.get()) {
- if ([closingControllers_ containsObject:controller]) {
- DCHECK([(TabView*)[controller view] isClosing]);
- ++index;
- }
- if (i == index) // No need to check anything after, it has no effect.
- break;
- ++i;
- }
- return index;
-}
-
-
-// Returns the index of the subview |view|. Returns -1 if not present. Takes
-// closing tabs into account such that this index will correctly match the tab
-// model. If |view| is in the process of closing, returns -1, as closing tabs
-// are no longer in the model.
-- (NSInteger)modelIndexForTabView:(NSView*)view {
- NSInteger index = 0;
- for (TabController* current in tabArray_.get()) {
- // If |current| is closing, skip it.
- if ([closingControllers_ containsObject:current])
- continue;
- else if ([current view] == view)
- return index;
- ++index;
- }
- return -1;
-}
-
-// Returns the index of the contents subview |view|. Returns -1 if not present.
-// Takes closing tabs into account such that this index will correctly match the
-// tab model. If |view| is in the process of closing, returns -1, as closing
-// tabs are no longer in the model.
-- (NSInteger)modelIndexForContentsView:(NSView*)view {
- NSInteger index = 0;
- NSInteger i = 0;
- for (TabContentsController* current in tabContentsArray_.get()) {
- // If the TabController corresponding to |current| is closing, skip it.
- TabController* controller = [tabArray_ objectAtIndex:i];
- if ([closingControllers_ containsObject:controller]) {
- ++i;
- continue;
- } else if ([current view] == view) {
- return index;
- }
- ++index;
- ++i;
- }
- return -1;
-}
-
-
-// Returns the view at the given index, using the array of TabControllers to
-// get the associated view. Returns nil if out of range.
-- (NSView*)viewAtIndex:(NSUInteger)index {
- if (index >= [tabArray_ count])
- return NULL;
- return [[tabArray_ objectAtIndex:index] view];
-}
-
-- (NSUInteger)viewsCount {
- return [tabArray_ count];
-}
-
-// Called when the user clicks a tab. Tell the model the selection has changed,
-// which feeds back into us via a notification.
-- (void)selectTab:(id)sender {
- DCHECK([sender isKindOfClass:[NSView class]]);
- int index = [self modelIndexForTabView:sender];
- if (tabStripModel_->ContainsIndex(index))
- tabStripModel_->SelectTabContentsAt(index, true);
-}
-
-// Called when the user closes a tab. Asks the model to close the tab. |sender|
-// is the TabView that is potentially going away.
-- (void)closeTab:(id)sender {
- DCHECK([sender isKindOfClass:[TabView class]]);
- if ([hoveredTab_ isEqual:sender]) {
- hoveredTab_ = nil;
- }
-
- NSInteger index = [self modelIndexForTabView:sender];
- if (!tabStripModel_->ContainsIndex(index))
- return;
-
- TabContentsWrapper* contents = tabStripModel_->GetTabContentsAt(index);
- if (contents)
- UserMetrics::RecordAction(UserMetricsAction("CloseTab_Mouse"),
- contents->tab_contents()->profile());
- const NSInteger numberOfOpenTabs = [self numberOfOpenTabs];
- if (numberOfOpenTabs > 1) {
- bool isClosingLastTab = index == numberOfOpenTabs - 1;
- if (!isClosingLastTab) {
- // Limit the width available for laying out tabs so that tabs are not
- // resized until a later time (when the mouse leaves the tab strip).
- // However, if the tab being closed is a pinned tab, break out of
- // rapid-closure mode since the mouse is almost guaranteed not to be over
- // the closebox of the adjacent tab (due to the difference in widths).
- // TODO(pinkerton): re-visit when handling tab overflow.
- // http://crbug.com/188
- if (tabStripModel_->IsTabPinned(index)) {
- availableResizeWidth_ = kUseFullAvailableWidth;
- } else {
- NSView* penultimateTab = [self viewAtIndex:numberOfOpenTabs - 2];
- availableResizeWidth_ = NSMaxX([penultimateTab frame]);
- }
- } else {
- // If the rightmost tab is closed, change the available width so that
- // another tab's close button lands below the cursor (assuming the tabs
- // are currently below their maximum width and can grow).
- NSView* lastTab = [self viewAtIndex:numberOfOpenTabs - 1];
- availableResizeWidth_ = NSMaxX([lastTab frame]);
- }
- tabStripModel_->CloseTabContentsAt(
- index,
- TabStripModel::CLOSE_USER_GESTURE |
- TabStripModel::CLOSE_CREATE_HISTORICAL_TAB);
- } else {
- // Use the standard window close if this is the last tab
- // this prevents the tab from being removed from the model until after
- // the window dissapears
- [[tabStripView_ window] performClose:nil];
- }
-}
-
-// Dispatch context menu commands for the given tab controller.
-- (void)commandDispatch:(TabStripModel::ContextMenuCommand)command
- forController:(TabController*)controller {
- int index = [self modelIndexForTabView:[controller view]];
- if (tabStripModel_->ContainsIndex(index))
- tabStripModel_->ExecuteContextMenuCommand(index, command);
-}
-
-// Returns YES if the specificed command should be enabled for the given
-// controller.
-- (BOOL)isCommandEnabled:(TabStripModel::ContextMenuCommand)command
- forController:(TabController*)controller {
- int index = [self modelIndexForTabView:[controller view]];
- if (!tabStripModel_->ContainsIndex(index))
- return NO;
- return tabStripModel_->IsContextMenuCommandEnabled(index, command) ? YES : NO;
-}
-
-- (void)insertPlaceholderForTab:(TabView*)tab
- frame:(NSRect)frame
- yStretchiness:(CGFloat)yStretchiness {
- placeholderTab_ = tab;
- placeholderFrame_ = frame;
- placeholderStretchiness_ = yStretchiness;
- [self layoutTabsWithAnimation:initialLayoutComplete_ regenerateSubviews:NO];
-}
-
-- (BOOL)isTabFullyVisible:(TabView*)tab {
- NSRect frame = [tab frame];
- return NSMinX(frame) >= [self indentForControls] &&
- NSMaxX(frame) <= NSMaxX([tabStripView_ frame]);
-}
-
-- (void)showNewTabButton:(BOOL)show {
- forceNewTabButtonHidden_ = show ? NO : YES;
- if (forceNewTabButtonHidden_)
- [newTabButton_ setHidden:YES];
-}
-
-// Lay out all tabs in the order of their TabContentsControllers, which matches
-// the ordering in the TabStripModel. This call isn't that expensive, though
-// it is O(n) in the number of tabs. Tabs will animate to their new position
-// if the window is visible and |animate| is YES.
-// TODO(pinkerton): Note this doesn't do too well when the number of min-sized
-// tabs would cause an overflow. http://crbug.com/188
-- (void)layoutTabsWithAnimation:(BOOL)animate
- regenerateSubviews:(BOOL)doUpdate {
- DCHECK([NSThread isMainThread]);
- if (![tabArray_ count])
- return;
-
- const CGFloat kMaxTabWidth = [TabController maxTabWidth];
- const CGFloat kMinTabWidth = [TabController minTabWidth];
- const CGFloat kMinSelectedTabWidth = [TabController minSelectedTabWidth];
- const CGFloat kMiniTabWidth = [TabController miniTabWidth];
- const CGFloat kAppTabWidth = [TabController appTabWidth];
-
- NSRect enclosingRect = NSZeroRect;
- ScopedNSAnimationContextGroup mainAnimationGroup(animate);
- mainAnimationGroup.SetCurrentContextDuration(kAnimationDuration);
-
- // Update the current subviews and their z-order if requested.
- if (doUpdate)
- [self regenerateSubviewList];
-
- // Compute the base width of tabs given how much room we're allowed. Note that
- // mini-tabs have a fixed width. We may not be able to use the entire width
- // if the user is quickly closing tabs. This may be negative, but that's okay
- // (taken care of by |MAX()| when calculating tab sizes).
- CGFloat availableSpace = 0;
- if (verticalLayout_) {
- availableSpace = NSHeight([tabStripView_ bounds]);
- } else {
- if ([self inRapidClosureMode]) {
- availableSpace = availableResizeWidth_;
- } else {
- availableSpace = NSWidth([tabStripView_ frame]);
- // Account for the new tab button and the incognito badge.
- availableSpace -= NSWidth([newTabButton_ frame]) + kNewTabButtonOffset;
- if (browser_->profile()->IsOffTheRecord())
- availableSpace -= kIncognitoBadgeTabStripShrink;
- }
- availableSpace -= [self indentForControls];
- }
-
- // This may be negative, but that's okay (taken care of by |MAX()| when
- // calculating tab sizes). "mini" tabs in horizontal mode just get a special
- // section, they don't change size.
- CGFloat availableSpaceForNonMini = availableSpace;
- if (!verticalLayout_) {
- availableSpaceForNonMini -=
- [self numberOfOpenMiniTabs] * (kMiniTabWidth - kTabOverlap);
- }
-
- // Initialize |nonMiniTabWidth| in case there aren't any non-mini-tabs; this
- // value shouldn't actually be used.
- CGFloat nonMiniTabWidth = kMaxTabWidth;
- const NSInteger numberOfOpenNonMiniTabs = [self numberOfOpenNonMiniTabs];
- if (!verticalLayout_ && numberOfOpenNonMiniTabs) {
- // Find the width of a non-mini-tab. This only applies to horizontal
- // mode. Add in the amount we "get back" from the tabs overlapping.
- availableSpaceForNonMini += (numberOfOpenNonMiniTabs - 1) * kTabOverlap;
-
- // Divide up the space between the non-mini-tabs.
- nonMiniTabWidth = availableSpaceForNonMini / numberOfOpenNonMiniTabs;
-
- // Clamp the width between the max and min.
- nonMiniTabWidth = MAX(MIN(nonMiniTabWidth, kMaxTabWidth), kMinTabWidth);
- }
-
- BOOL visible = [[tabStripView_ window] isVisible];
-
- CGFloat offset = [self indentForControls];
- NSUInteger i = 0;
- bool hasPlaceholderGap = false;
- for (TabController* tab in tabArray_.get()) {
- // Ignore a tab that is going through a close animation.
- if ([closingControllers_ containsObject:tab])
- continue;
-
- BOOL isPlaceholder = [[tab view] isEqual:placeholderTab_];
- NSRect tabFrame = [[tab view] frame];
- tabFrame.size.height = [[self class] defaultTabHeight] + 1;
- if (verticalLayout_) {
- tabFrame.origin.y = availableSpace - tabFrame.size.height - offset;
- tabFrame.origin.x = 0;
- } else {
- tabFrame.origin.y = 0;
- tabFrame.origin.x = offset;
- }
- // If the tab is hidden, we consider it a new tab. We make it visible
- // and animate it in.
- BOOL newTab = [[tab view] isHidden];
- if (newTab) {
- [[tab view] setHidden:NO];
- }
-
- if (isPlaceholder) {
- // Move the current tab to the correct location instantly.
- // We need a duration or else it doesn't cancel an inflight animation.
- ScopedNSAnimationContextGroup localAnimationGroup(animate);
- localAnimationGroup.SetCurrentContextShortestDuration();
- if (verticalLayout_)
- tabFrame.origin.y = availableSpace - tabFrame.size.height - offset;
- else
- tabFrame.origin.x = placeholderFrame_.origin.x;
- // TODO(alcor): reenable this
- //tabFrame.size.height += 10.0 * placeholderStretchiness_;
- id target = animate ? [[tab view] animator] : [tab view];
- [target setFrame:tabFrame];
-
- // Store the frame by identifier to aviod redundant calls to animator.
- NSValue* identifier = [NSValue valueWithPointer:[tab view]];
- [targetFrames_ setObject:[NSValue valueWithRect:tabFrame]
- forKey:identifier];
- continue;
- }
-
- if (placeholderTab_ && !hasPlaceholderGap) {
- const CGFloat placeholderMin =
- verticalLayout_ ? NSMinY(placeholderFrame_) :
- NSMinX(placeholderFrame_);
- if (verticalLayout_) {
- if (NSMidY(tabFrame) > placeholderMin) {
- hasPlaceholderGap = true;
- offset += NSHeight(placeholderFrame_);
- tabFrame.origin.y = availableSpace - tabFrame.size.height - offset;
- }
- } else {
- // If the left edge is to the left of the placeholder's left, but the
- // mid is to the right of it slide over to make space for it.
- if (NSMidX(tabFrame) > placeholderMin) {
- hasPlaceholderGap = true;
- offset += NSWidth(placeholderFrame_);
- offset -= kTabOverlap;
- tabFrame.origin.x = offset;
- }
- }
- }
-
- // Set the width. Selected tabs are slightly wider when things get really
- // small and thus we enforce a different minimum width.
- tabFrame.size.width = [tab mini] ?
- ([tab app] ? kAppTabWidth : kMiniTabWidth) : nonMiniTabWidth;
- if ([tab selected])
- tabFrame.size.width = MAX(tabFrame.size.width, kMinSelectedTabWidth);
-
- // Animate a new tab in by putting it below the horizon unless told to put
- // it in a specific location (i.e., from a drop).
- // TODO(pinkerton): figure out vertical tab animations.
- if (newTab && visible && animate) {
- if (NSEqualRects(droppedTabFrame_, NSZeroRect)) {
- [[tab view] setFrame:NSOffsetRect(tabFrame, 0, -NSHeight(tabFrame))];
- } else {
- [[tab view] setFrame:droppedTabFrame_];
- droppedTabFrame_ = NSZeroRect;
- }
- }
-
- // Check the frame by identifier to avoid redundant calls to animator.
- id frameTarget = visible && animate ? [[tab view] animator] : [tab view];
- NSValue* identifier = [NSValue valueWithPointer:[tab view]];
- NSValue* oldTargetValue = [targetFrames_ objectForKey:identifier];
- if (!oldTargetValue ||
- !NSEqualRects([oldTargetValue rectValue], tabFrame)) {
- [frameTarget setFrame:tabFrame];
- [targetFrames_ setObject:[NSValue valueWithRect:tabFrame]
- forKey:identifier];
- }
-
- enclosingRect = NSUnionRect(tabFrame, enclosingRect);
-
- if (verticalLayout_) {
- offset += NSHeight(tabFrame);
- } else {
- offset += NSWidth(tabFrame);
- offset -= kTabOverlap;
- }
- i++;
- }
-
- // Hide the new tab button if we're explicitly told to. It may already
- // be hidden, doing it again doesn't hurt. Otherwise position it
- // appropriately, showing it if necessary.
- if (forceNewTabButtonHidden_) {
- [newTabButton_ setHidden:YES];
- } else {
- NSRect newTabNewFrame = [newTabButton_ frame];
- // We've already ensured there's enough space for the new tab button
- // so we don't have to check it against the available space. We do need
- // to make sure we put it after any placeholder.
- newTabNewFrame.origin = NSMakePoint(offset, 0);
- newTabNewFrame.origin.x = MAX(newTabNewFrame.origin.x,
- NSMaxX(placeholderFrame_)) +
- kNewTabButtonOffset;
- if ([tabContentsArray_ count])
- [newTabButton_ setHidden:NO];
-
- if (!NSEqualRects(newTabTargetFrame_, newTabNewFrame)) {
- // Set the new tab button image correctly based on where the cursor is.
- NSWindow* window = [tabStripView_ window];
- NSPoint currentMouse = [window mouseLocationOutsideOfEventStream];
- currentMouse = [tabStripView_ convertPoint:currentMouse fromView:nil];
-
- BOOL shouldShowHover = [newTabButton_ pointIsOverButton:currentMouse];
- [self setNewTabButtonHoverState:shouldShowHover];
-
- // Move the new tab button into place. We want to animate the new tab
- // button if it's moving to the left (closing a tab), but not when it's
- // moving to the right (inserting a new tab). If moving right, we need
- // to use a very small duration to make sure we cancel any in-flight
- // animation to the left.
- if (visible && animate) {
- ScopedNSAnimationContextGroup localAnimationGroup(true);
- BOOL movingLeft = NSMinX(newTabNewFrame) < NSMinX(newTabTargetFrame_);
- if (!movingLeft) {
- localAnimationGroup.SetCurrentContextShortestDuration();
- }
- [[newTabButton_ animator] setFrame:newTabNewFrame];
- newTabTargetFrame_ = newTabNewFrame;
- } else {
- [newTabButton_ setFrame:newTabNewFrame];
- newTabTargetFrame_ = newTabNewFrame;
- }
- }
- }
-
- [dragBlockingView_ setFrame:enclosingRect];
-
- // Mark that we've successfully completed layout of at least one tab.
- initialLayoutComplete_ = YES;
-}
-
-// When we're told to layout from the public API we usually want to animate,
-// except when it's the first time.
-- (void)layoutTabs {
- [self layoutTabsWithAnimation:initialLayoutComplete_ regenerateSubviews:YES];
-}
-
-// Handles setting the title of the tab based on the given |contents|. Uses
-// a canned string if |contents| is NULL.
-- (void)setTabTitle:(NSViewController*)tab withContents:(TabContents*)contents {
- NSString* titleString = nil;
- if (contents)
- titleString = base::SysUTF16ToNSString(contents->GetTitle());
- if (![titleString length]) {
- titleString = l10n_util::GetNSString(IDS_BROWSER_WINDOW_MAC_TAB_UNTITLED);
- }
- [tab setTitle:titleString];
-}
-
-// Called when a notification is received from the model to insert a new tab
-// at |modelIndex|.
-- (void)insertTabWithContents:(TabContentsWrapper*)contents
- atIndex:(NSInteger)modelIndex
- inForeground:(bool)inForeground {
- DCHECK(contents);
- DCHECK(modelIndex == TabStripModel::kNoTab ||
- tabStripModel_->ContainsIndex(modelIndex));
-
- // Take closing tabs into account.
- NSInteger index = [self indexFromModelIndex:modelIndex];
-
- // Make a new tab. Load the contents of this tab from the nib and associate
- // the new controller with |contents| so it can be looked up later.
- scoped_nsobject<TabContentsController> contentsController(
- [[TabContentsController alloc] initWithContents:contents->tab_contents()
- delegate:self]);
- [tabContentsArray_ insertObject:contentsController atIndex:index];
-
- // Make a new tab and add it to the strip. Keep track of its controller.
- TabController* newController = [self newTab];
- [newController setMini:tabStripModel_->IsMiniTab(modelIndex)];
- [newController setPinned:tabStripModel_->IsTabPinned(modelIndex)];
- [newController setApp:tabStripModel_->IsAppTab(modelIndex)];
- [tabArray_ insertObject:newController atIndex:index];
- NSView* newView = [newController view];
-
- // Set the originating frame to just below the strip so that it animates
- // upwards as it's being initially layed out. Oddly, this works while doing
- // something similar in |-layoutTabs| confuses the window server.
- [newView setFrame:NSOffsetRect([newView frame],
- 0, -[[self class] defaultTabHeight])];
-
- [self setTabTitle:newController withContents:contents->tab_contents()];
-
- // If a tab is being inserted, we can again use the entire tab strip width
- // for layout.
- availableResizeWidth_ = kUseFullAvailableWidth;
-
- // We don't need to call |-layoutTabs| if the tab will be in the foreground
- // because it will get called when the new tab is selected by the tab model.
- // Whenever |-layoutTabs| is called, it'll also add the new subview.
- if (!inForeground) {
- [self layoutTabs];
- }
-
- // During normal loading, we won't yet have a favicon and we'll get
- // subsequent state change notifications to show the throbber, but when we're
- // dragging a tab out into a new window, we have to put the tab's favicon
- // into the right state up front as we won't be told to do it from anywhere
- // else.
- [self updateFavIconForContents:contents->tab_contents() atIndex:modelIndex];
-
- // Send a broadcast that the number of tabs have changed.
- [[NSNotificationCenter defaultCenter]
- postNotificationName:kTabStripNumberOfTabsChanged
- object:self];
-}
-
-// Called when a notification is received from the model to select a particular
-// tab. Swaps in the toolbar and content area associated with |newContents|.
-- (void)selectTabWithContents:(TabContentsWrapper*)newContents
- previousContents:(TabContentsWrapper*)oldContents
- atIndex:(NSInteger)modelIndex
- userGesture:(bool)wasUserGesture {
- // Take closing tabs into account.
- NSInteger index = [self indexFromModelIndex:modelIndex];
-
- if (oldContents) {
- int oldModelIndex =
- browser_->GetIndexOfController(&(oldContents->controller()));
- if (oldModelIndex != -1) { // When closing a tab, the old tab may be gone.
- NSInteger oldIndex = [self indexFromModelIndex:oldModelIndex];
- TabContentsController* oldController =
- [tabContentsArray_ objectAtIndex:oldIndex];
- [oldController willBecomeUnselectedTab];
- oldContents->view()->StoreFocus();
- oldContents->tab_contents()->WasHidden();
- }
- }
-
- // De-select all other tabs and select the new tab.
- int i = 0;
- for (TabController* current in tabArray_.get()) {
- [current setSelected:(i == index) ? YES : NO];
- ++i;
- }
-
- // Tell the new tab contents it is about to become the selected tab. Here it
- // can do things like make sure the toolbar is up to date.
- TabContentsController* newController =
- [tabContentsArray_ objectAtIndex:index];
- [newController willBecomeSelectedTab];
-
- // Relayout for new tabs and to let the selected tab grow to be larger in
- // size than surrounding tabs if the user has many. This also raises the
- // selected tab to the top.
- [self layoutTabs];
-
- // Swap in the contents for the new tab.
- [self swapInTabAtIndex:modelIndex];
-
- if (newContents) {
- newContents->tab_contents()->DidBecomeSelected();
- newContents->view()->RestoreFocus();
-
- if (newContents->tab_contents()->find_ui_active())
- browser_->GetFindBarController()->find_bar()->SetFocusAndSelection();
- }
-}
-
-- (void)tabReplacedWithContents:(TabContentsWrapper*)newContents
- previousContents:(TabContentsWrapper*)oldContents
- atIndex:(NSInteger)modelIndex {
- NSInteger index = [self indexFromModelIndex:modelIndex];
- TabContentsController* oldController =
- [tabContentsArray_ objectAtIndex:index];
- DCHECK_EQ(oldContents->tab_contents(), [oldController tabContents]);
-
- // Simply create a new TabContentsController for |newContents| and place it
- // into the array, replacing |oldContents|. A TabSelectedAt notification will
- // follow, at which point we will install the new view.
- scoped_nsobject<TabContentsController> newController(
- [[TabContentsController alloc]
- initWithContents:newContents->tab_contents()
- delegate:self]);
-
- // Bye bye, |oldController|.
- [tabContentsArray_ replaceObjectAtIndex:index withObject:newController];
-
- [delegate_ onReplaceTabWithContents:newContents->tab_contents()];
-
- // Fake a tab changed notification to force tab titles and favicons to update.
- [self tabChangedWithContents:newContents
- atIndex:modelIndex
- changeType:TabStripModelObserver::ALL];
-}
-
-// Remove all knowledge about this tab and its associated controller, and remove
-// the view from the strip.
-- (void)removeTab:(TabController*)controller {
- NSUInteger index = [tabArray_ indexOfObject:controller];
-
- // Release the tab contents controller so those views get destroyed. This
- // will remove all the tab content Cocoa views from the hierarchy. A
- // subsequent "select tab" notification will follow from the model. To
- // tell us what to swap in in its absence.
- [tabContentsArray_ removeObjectAtIndex:index];
-
- // Remove the view from the tab strip.
- NSView* tab = [controller view];
- [tab removeFromSuperview];
-
- // Remove ourself as an observer.
- [[NSNotificationCenter defaultCenter]
- removeObserver:self
- name:NSViewDidUpdateTrackingAreasNotification
- object:tab];
-
- // Clear the tab controller's target.
- // TODO(viettrungluu): [crbug.com/23829] Find a better way to handle the tab
- // controller's target.
- [controller setTarget:nil];
-
- if ([hoveredTab_ isEqual:tab])
- hoveredTab_ = nil;
-
- NSValue* identifier = [NSValue valueWithPointer:tab];
- [targetFrames_ removeObjectForKey:identifier];
-
- // Once we're totally done with the tab, delete its controller
- [tabArray_ removeObjectAtIndex:index];
-}
-
-// Called by the CAAnimation delegate when the tab completes the closing
-// animation.
-- (void)animationDidStopForController:(TabController*)controller
- finished:(BOOL)finished {
- [closingControllers_ removeObject:controller];
- [self removeTab:controller];
-}
-
-// Save off which TabController is closing and tell its view's animator
-// where to move the tab to. Registers a delegate to call back when the
-// animation is complete in order to remove the tab from the model.
-- (void)startClosingTabWithAnimation:(TabController*)closingTab {
- DCHECK([NSThread isMainThread]);
- // Save off the controller into the set of animating tabs. This alerts
- // the layout method to not do anything with it and allows us to correctly
- // calculate offsets when working with indices into the model.
- [closingControllers_ addObject:closingTab];
-
- // Mark the tab as closing. This prevents it from generating any drags or
- // selections while it's animating closed.
- [(TabView*)[closingTab view] setClosing:YES];
-
- // Register delegate (owned by the animation system).
- NSView* tabView = [closingTab view];
- CAAnimation* animation = [[tabView animationForKey:@"frameOrigin"] copy];
- [animation autorelease];
- scoped_nsobject<TabCloseAnimationDelegate> delegate(
- [[TabCloseAnimationDelegate alloc] initWithTabStrip:self
- tabController:closingTab]);
- [animation setDelegate:delegate.get()]; // Retains delegate.
- NSMutableDictionary* animationDictionary =
- [NSMutableDictionary dictionaryWithDictionary:[tabView animations]];
- [animationDictionary setObject:animation forKey:@"frameOrigin"];
- [tabView setAnimations:animationDictionary];
-
- // Periscope down! Animate the tab.
- NSRect newFrame = [tabView frame];
- newFrame = NSOffsetRect(newFrame, 0, -newFrame.size.height);
- ScopedNSAnimationContextGroup animationGroup(true);
- animationGroup.SetCurrentContextDuration(kAnimationDuration);
- [[tabView animator] setFrame:newFrame];
-}
-
-// Called when a notification is received from the model that the given tab
-// has gone away. Start an animation then force a layout to put everything
-// in motion.
-- (void)tabDetachedWithContents:(TabContentsWrapper*)contents
- atIndex:(NSInteger)modelIndex {
- // Take closing tabs into account.
- NSInteger index = [self indexFromModelIndex:modelIndex];
-
- TabController* tab = [tabArray_ objectAtIndex:index];
- if (tabStripModel_->count() > 0) {
- [self startClosingTabWithAnimation:tab];
- [self layoutTabs];
- } else {
- [self removeTab:tab];
- }
-
- // Send a broadcast that the number of tabs have changed.
- [[NSNotificationCenter defaultCenter]
- postNotificationName:kTabStripNumberOfTabsChanged
- object:self];
-
- [delegate_ onTabDetachedWithContents:contents->tab_contents()];
-}
-
-// A helper routine for creating an NSImageView to hold the fav icon or app icon
-// for |contents|.
-- (NSImageView*)iconImageViewForContents:(TabContents*)contents {
- BOOL isApp = contents->is_app();
- NSImage* image = nil;
- if (isApp) {
- SkBitmap* icon = contents->GetExtensionAppIcon();
- if (icon)
- image = gfx::SkBitmapToNSImage(*icon);
- } else {
- image = gfx::SkBitmapToNSImage(contents->GetFavIcon());
- }
-
- // Either we don't have a valid favicon or there was some issue converting it
- // from an SkBitmap. Either way, just show the default.
- if (!image)
- image = defaultFavIcon_.get();
- NSRect frame = NSMakeRect(0, 0, kIconWidthAndHeight, kIconWidthAndHeight);
- NSImageView* view = [[[NSImageView alloc] initWithFrame:frame] autorelease];
- [view setImage:image];
- return view;
-}
-
-// Updates the current loading state, replacing the icon view with a favicon,
-// a throbber, the default icon, or nothing at all.
-- (void)updateFavIconForContents:(TabContents*)contents
- atIndex:(NSInteger)modelIndex {
- if (!contents)
- return;
-
- static NSImage* throbberWaitingImage =
- [ResourceBundle::GetSharedInstance().GetNativeImageNamed(
- IDR_THROBBER_WAITING) retain];
- static NSImage* throbberLoadingImage =
- [ResourceBundle::GetSharedInstance().GetNativeImageNamed(IDR_THROBBER)
- retain];
- static NSImage* sadFaviconImage =
- [ResourceBundle::GetSharedInstance().GetNativeImageNamed(IDR_SAD_FAVICON)
- retain];
-
- // Take closing tabs into account.
- NSInteger index = [self indexFromModelIndex:modelIndex];
- TabController* tabController = [tabArray_ objectAtIndex:index];
-
- bool oldHasIcon = [tabController iconView] != nil;
- bool newHasIcon = contents->ShouldDisplayFavIcon() ||
- tabStripModel_->IsMiniTab(modelIndex); // Always show icon if mini.
-
- TabLoadingState oldState = [tabController loadingState];
- TabLoadingState newState = kTabDone;
- NSImage* throbberImage = nil;
- if (contents->is_crashed()) {
- newState = kTabCrashed;
- newHasIcon = true;
- } else if (contents->waiting_for_response()) {
- newState = kTabWaiting;
- throbberImage = throbberWaitingImage;
- } else if (contents->is_loading()) {
- newState = kTabLoading;
- throbberImage = throbberLoadingImage;
- }
-
- if (oldState != newState)
- [tabController setLoadingState:newState];
-
- // While loading, this function is called repeatedly with the same state.
- // To avoid expensive unnecessary view manipulation, only make changes when
- // the state is actually changing. When loading is complete (kTabDone),
- // every call to this function is significant.
- if (newState == kTabDone || oldState != newState ||
- oldHasIcon != newHasIcon) {
- NSView* iconView = nil;
- if (newHasIcon) {
- if (newState == kTabDone) {
- iconView = [self iconImageViewForContents:contents];
- } else if (newState == kTabCrashed) {
- NSImage* oldImage = [[self iconImageViewForContents:contents] image];
- NSRect frame =
- NSMakeRect(0, 0, kIconWidthAndHeight, kIconWidthAndHeight);
- iconView = [ThrobberView toastThrobberViewWithFrame:frame
- beforeImage:oldImage
- afterImage:sadFaviconImage];
- } else {
- NSRect frame =
- NSMakeRect(0, 0, kIconWidthAndHeight, kIconWidthAndHeight);
- iconView = [ThrobberView filmstripThrobberViewWithFrame:frame
- image:throbberImage];
- }
- }
-
- [tabController setIconView:iconView];
- }
-}
-
-// Called when a notification is received from the model that the given tab
-// has been updated. |loading| will be YES when we only want to update the
-// throbber state, not anything else about the (partially) loading tab.
-- (void)tabChangedWithContents:(TabContentsWrapper*)contents
- atIndex:(NSInteger)modelIndex
- changeType:(TabStripModelObserver::TabChangeType)change {
- // Take closing tabs into account.
- NSInteger index = [self indexFromModelIndex:modelIndex];
-
- if (modelIndex == tabStripModel_->selected_index())
- [delegate_ onSelectedTabChange:change];
-
- if (change == TabStripModelObserver::TITLE_NOT_LOADING) {
- // TODO(sky): make this work.
- // We'll receive another notification of the change asynchronously.
- return;
- }
-
- TabController* tabController = [tabArray_ objectAtIndex:index];
-
- if (change != TabStripModelObserver::LOADING_ONLY)
- [self setTabTitle:tabController withContents:contents->tab_contents()];
-
- [self updateFavIconForContents:contents->tab_contents() atIndex:modelIndex];
-
- TabContentsController* updatedController =
- [tabContentsArray_ objectAtIndex:index];
- [updatedController tabDidChange:contents->tab_contents()];
-}
-
-// Called when a tab is moved (usually by drag&drop). Keep our parallel arrays
-// in sync with the tab strip model. It can also be pinned/unpinned
-// simultaneously, so we need to take care of that.
-- (void)tabMovedWithContents:(TabContentsWrapper*)contents
- fromIndex:(NSInteger)modelFrom
- toIndex:(NSInteger)modelTo {
- // Take closing tabs into account.
- NSInteger from = [self indexFromModelIndex:modelFrom];
- NSInteger to = [self indexFromModelIndex:modelTo];
-
- scoped_nsobject<TabContentsController> movedTabContentsController(
- [[tabContentsArray_ objectAtIndex:from] retain]);
- [tabContentsArray_ removeObjectAtIndex:from];
- [tabContentsArray_ insertObject:movedTabContentsController.get()
- atIndex:to];
- scoped_nsobject<TabController> movedTabController(
- [[tabArray_ objectAtIndex:from] retain]);
- DCHECK([movedTabController isKindOfClass:[TabController class]]);
- [tabArray_ removeObjectAtIndex:from];
- [tabArray_ insertObject:movedTabController.get() atIndex:to];
-
- // The tab moved, which means that the mini-tab state may have changed.
- if (tabStripModel_->IsMiniTab(modelTo) != [movedTabController mini])
- [self tabMiniStateChangedWithContents:contents atIndex:modelTo];
-
- [self layoutTabs];
-}
-
-// Called when a tab is pinned or unpinned without moving.
-- (void)tabMiniStateChangedWithContents:(TabContentsWrapper*)contents
- atIndex:(NSInteger)modelIndex {
- // Take closing tabs into account.
- NSInteger index = [self indexFromModelIndex:modelIndex];
-
- TabController* tabController = [tabArray_ objectAtIndex:index];
- DCHECK([tabController isKindOfClass:[TabController class]]);
-
- // Don't do anything if the change was already picked up by the move event.
- if (tabStripModel_->IsMiniTab(modelIndex) == [tabController mini])
- return;
-
- [tabController setMini:tabStripModel_->IsMiniTab(modelIndex)];
- [tabController setPinned:tabStripModel_->IsTabPinned(modelIndex)];
- [tabController setApp:tabStripModel_->IsAppTab(modelIndex)];
- [self updateFavIconForContents:contents->tab_contents() atIndex:modelIndex];
- // If the tab is being restored and it's pinned, the mini state is set after
- // the tab has already been rendered, so re-layout the tabstrip. In all other
- // cases, the state is set before the tab is rendered so this isn't needed.
- [self layoutTabs];
-}
-
-- (void)setFrameOfSelectedTab:(NSRect)frame {
- NSView* view = [self selectedTabView];
- NSValue* identifier = [NSValue valueWithPointer:view];
- [targetFrames_ setObject:[NSValue valueWithRect:frame]
- forKey:identifier];
- [view setFrame:frame];
-}
-
-- (NSView*)selectedTabView {
- int selectedIndex = tabStripModel_->selected_index();
- // Take closing tabs into account. They can't ever be selected.
- selectedIndex = [self indexFromModelIndex:selectedIndex];
- return [self viewAtIndex:selectedIndex];
-}
-
-// Find the model index based on the x coordinate of the placeholder. If there
-// is no placeholder, this returns the end of the tab strip. Closing tabs are
-// not considered in computing the index.
-- (int)indexOfPlaceholder {
- double placeholderX = placeholderFrame_.origin.x;
- int index = 0;
- int location = 0;
- // Use |tabArray_| here instead of the tab strip count in order to get the
- // correct index when there are closing tabs to the left of the placeholder.
- const int count = [tabArray_ count];
- while (index < count) {
- // Ignore closing tabs for simplicity. The only drawback of this is that
- // if the placeholder is placed right before one or several contiguous
- // currently closing tabs, the associated TabController will start at the
- // end of the closing tabs.
- if ([closingControllers_ containsObject:[tabArray_ objectAtIndex:index]]) {
- index++;
- continue;
- }
- NSView* curr = [self viewAtIndex:index];
- // The placeholder tab works by changing the frame of the tab being dragged
- // to be the bounds of the placeholder, so we need to skip it while we're
- // iterating, otherwise we'll end up off by one. Note This only effects
- // dragging to the right, not to the left.
- if (curr == placeholderTab_) {
- index++;
- continue;
- }
- if (placeholderX <= NSMinX([curr frame]))
- break;
- index++;
- location++;
- }
- return location;
-}
-
-// Move the given tab at index |from| in this window to the location of the
-// current placeholder.
-- (void)moveTabFromIndex:(NSInteger)from {
- int toIndex = [self indexOfPlaceholder];
- tabStripModel_->MoveTabContentsAt(from, toIndex, true);
-}
-
-// Drop a given TabContents at the location of the current placeholder. If there
-// is no placeholder, it will go at the end. Used when dragging from another
-// window when we don't have access to the TabContents as part of our strip.
-// |frame| is in the coordinate system of the tab strip view and represents
-// where the user dropped the new tab so it can be animated into its correct
-// location when the tab is added to the model. If the tab was pinned in its
-// previous window, setting |pinned| to YES will propagate that state to the
-// new window. Mini-tabs are either app or pinned tabs; the app state is stored
-// by the |contents|, but the |pinned| state is the caller's responsibility.
-- (void)dropTabContents:(TabContentsWrapper*)contents
- withFrame:(NSRect)frame
- asPinnedTab:(BOOL)pinned {
- int modelIndex = [self indexOfPlaceholder];
-
- // Mark that the new tab being created should start at |frame|. It will be
- // reset as soon as the tab has been positioned.
- droppedTabFrame_ = frame;
-
- // Insert it into this tab strip. We want it in the foreground and to not
- // inherit the current tab's group.
- tabStripModel_->InsertTabContentsAt(
- modelIndex, contents,
- TabStripModel::ADD_SELECTED | (pinned ? TabStripModel::ADD_PINNED : 0));
-}
-
-// Called when the tab strip view changes size. As we only registered for
-// changes on our view, we know it's only for our view. Layout w/out
-// animations since they are blocked by the resize nested runloop. We need
-// the views to adjust immediately. Neither the tabs nor their z-order are
-// changed, so we don't need to update the subviews.
-- (void)tabViewFrameChanged:(NSNotification*)info {
- [self layoutTabsWithAnimation:NO regenerateSubviews:NO];
-}
-
-// Called when the tracking areas for any given tab are updated. This allows
-// the individual tabs to update their hover states correctly.
-// Only generates the event if the cursor is in the tab strip.
-- (void)tabUpdateTracking:(NSNotification*)notification {
- DCHECK([[notification object] isKindOfClass:[TabView class]]);
- DCHECK(mouseInside_);
- NSWindow* window = [tabStripView_ window];
- NSPoint location = [window mouseLocationOutsideOfEventStream];
- if (NSPointInRect(location, [tabStripView_ frame])) {
- NSEvent* mouseEvent = [NSEvent mouseEventWithType:NSMouseMoved
- location:location
- modifierFlags:0
- timestamp:0
- windowNumber:[window windowNumber]
- context:nil
- eventNumber:0
- clickCount:0
- pressure:0];
- [self mouseMoved:mouseEvent];
- }
-}
-
-- (BOOL)inRapidClosureMode {
- return availableResizeWidth_ != kUseFullAvailableWidth;
-}
-
-// Disable tab dragging when there are any pending animations.
-- (BOOL)tabDraggingAllowed {
- return [closingControllers_ count] == 0;
-}
-
-- (void)mouseMoved:(NSEvent*)event {
- // Use hit test to figure out what view we are hovering over.
- NSView* targetView = [tabStripView_ hitTest:[event locationInWindow]];
-
- // Set the new tab button hover state iff the mouse is over the button.
- BOOL shouldShowHoverImage = [targetView isKindOfClass:[NewTabButton class]];
- [self setNewTabButtonHoverState:shouldShowHoverImage];
-
- TabView* tabView = (TabView*)targetView;
- if (![tabView isKindOfClass:[TabView class]]) {
- if ([[tabView superview] isKindOfClass:[TabView class]]) {
- tabView = (TabView*)[targetView superview];
- } else {
- tabView = nil;
- }
- }
-
- if (hoveredTab_ != tabView) {
- [hoveredTab_ mouseExited:nil]; // We don't pass event because moved events
- [tabView mouseEntered:nil]; // don't have valid tracking areas
- hoveredTab_ = tabView;
- } else {
- [hoveredTab_ mouseMoved:event];
- }
-}
-
-- (void)mouseEntered:(NSEvent*)event {
- NSTrackingArea* area = [event trackingArea];
- if ([area isEqual:trackingArea_]) {
- mouseInside_ = YES;
- [self setTabTrackingAreasEnabled:YES];
- [self mouseMoved:event];
- }
-}
-
-// Called when the tracking area is in effect which means we're tracking to
-// see if the user leaves the tab strip with their mouse. When they do,
-// reset layout to use all available width.
-- (void)mouseExited:(NSEvent*)event {
- NSTrackingArea* area = [event trackingArea];
- if ([area isEqual:trackingArea_]) {
- mouseInside_ = NO;
- [self setTabTrackingAreasEnabled:NO];
- availableResizeWidth_ = kUseFullAvailableWidth;
- [hoveredTab_ mouseExited:event];
- hoveredTab_ = nil;
- [self layoutTabs];
- } else if ([area isEqual:newTabTrackingArea_]) {
- // If the mouse is moved quickly enough, it is possible for the mouse to
- // leave the tabstrip without sending any mouseMoved: messages at all.
- // Since this would result in the new tab button incorrectly staying in the
- // hover state, disable the hover image on every mouse exit.
- [self setNewTabButtonHoverState:NO];
- }
-}
-
-// Enable/Disable the tracking areas for the tabs. They are only enabled
-// when the mouse is in the tabstrip.
-- (void)setTabTrackingAreasEnabled:(BOOL)enabled {
- NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
- for (TabController* controller in tabArray_.get()) {
- TabView* tabView = [controller tabView];
- if (enabled) {
- // Set self up to observe tabs so hover states will be correct.
- [defaultCenter addObserver:self
- selector:@selector(tabUpdateTracking:)
- name:NSViewDidUpdateTrackingAreasNotification
- object:tabView];
- } else {
- [defaultCenter removeObserver:self
- name:NSViewDidUpdateTrackingAreasNotification
- object:tabView];
- }
- [tabView setTrackingEnabled:enabled];
- }
-}
-
-// Sets the new tab button's image based on the current hover state. Does
-// nothing if the hover state is already correct.
-- (void)setNewTabButtonHoverState:(BOOL)shouldShowHover {
- if (shouldShowHover && !newTabButtonShowingHoverImage_) {
- newTabButtonShowingHoverImage_ = YES;
- [newTabButton_ setImage:nsimage_cache::ImageNamed(kNewTabHoverImage)];
- } else if (!shouldShowHover && newTabButtonShowingHoverImage_) {
- newTabButtonShowingHoverImage_ = NO;
- [newTabButton_ setImage:nsimage_cache::ImageNamed(kNewTabImage)];
- }
-}
-
-// Adds the given subview to (the end of) the list of permanent subviews
-// (specified from bottom up). These subviews will always be below the
-// transitory subviews (tabs). |-regenerateSubviewList| must be called to
-// effectuate the addition.
-- (void)addSubviewToPermanentList:(NSView*)aView {
- if (aView)
- [permanentSubviews_ addObject:aView];
-}
-
-// Update the subviews, keeping the permanent ones (or, more correctly, putting
-// in the ones listed in permanentSubviews_), and putting in the current tabs in
-// the correct z-order. Any current subviews which is neither in the permanent
-// list nor a (current) tab will be removed. So if you add such a subview, you
-// should call |-addSubviewToPermanentList:| (or better yet, call that and then
-// |-regenerateSubviewList| to actually add it).
-- (void)regenerateSubviewList {
- // Remove self as an observer from all the old tabs before a new set of
- // potentially different tabs is put in place.
- [self setTabTrackingAreasEnabled:NO];
-
- // Subviews to put in (in bottom-to-top order), beginning with the permanent
- // ones.
- NSMutableArray* subviews = [NSMutableArray arrayWithArray:permanentSubviews_];
-
- NSView* selectedTabView = nil;
- // Go through tabs in reverse order, since |subviews| is bottom-to-top.
- for (TabController* tab in [tabArray_ reverseObjectEnumerator]) {
- NSView* tabView = [tab view];
- if ([tab selected]) {
- DCHECK(!selectedTabView);
- selectedTabView = tabView;
- } else {
- [subviews addObject:tabView];
- }
- }
- if (selectedTabView) {
- [subviews addObject:selectedTabView];
- }
- [tabStripView_ setSubviews:subviews];
- [self setTabTrackingAreasEnabled:mouseInside_];
-}
-
-// Get the index and disposition for a potential URL(s) drop given a point (in
-// the |TabStripView|'s coordinates). It considers only the x-coordinate of the
-// given point. If it's in the "middle" of a tab, it drops on that tab. If it's
-// to the left, it inserts to the left, and similarly for the right.
-- (void)droppingURLsAt:(NSPoint)point
- givesIndex:(NSInteger*)index
- disposition:(WindowOpenDisposition*)disposition {
- // Proportion of the tab which is considered the "middle" (and causes things
- // to drop on that tab).
- const double kMiddleProportion = 0.5;
- const double kLRProportion = (1.0 - kMiddleProportion) / 2.0;
-
- DCHECK(index && disposition);
- NSInteger i = 0;
- for (TabController* tab in tabArray_.get()) {
- NSView* view = [tab view];
- DCHECK([view isKindOfClass:[TabView class]]);
-
- // Recall that |-[NSView frame]| is in its superview's coordinates, so a
- // |TabView|'s frame is in the coordinates of the |TabStripView| (which
- // matches the coordinate system of |point|).
- NSRect frame = [view frame];
-
- // Modify the frame to make it "unoverlapped".
- frame.origin.x += kTabOverlap / 2.0;
- frame.size.width -= kTabOverlap;
- if (frame.size.width < 1.0)
- frame.size.width = 1.0; // try to avoid complete failure
-
- // Drop in a new tab to the left of tab |i|?
- if (point.x < (frame.origin.x + kLRProportion * frame.size.width)) {
- *index = i;
- *disposition = NEW_FOREGROUND_TAB;
- return;
- }
-
- // Drop on tab |i|?
- if (point.x <= (frame.origin.x +
- (1.0 - kLRProportion) * frame.size.width)) {
- *index = i;
- *disposition = CURRENT_TAB;
- return;
- }
-
- // (Dropping in a new tab to the right of tab |i| will be taken care of in
- // the next iteration.)
- i++;
- }
-
- // If we've made it here, we want to append a new tab to the end.
- *index = -1;
- *disposition = NEW_FOREGROUND_TAB;
-}
-
-// (URLDropTargetController protocol)
-- (void)dropURLs:(NSArray*)urls inView:(NSView*)view at:(NSPoint)point {
- DCHECK_EQ(view, tabStripView_.get());
-
- if ([urls count] < 1) {
- NOTREACHED();
- return;
- }
-
- //TODO(viettrungluu): dropping multiple URLs.
- if ([urls count] > 1)
- NOTIMPLEMENTED();
-
- // Get the first URL and fix it up.
- GURL url(URLFixerUpper::FixupURL(
- base::SysNSStringToUTF8([urls objectAtIndex:0]), std::string()));
-
- // Get the index and disposition.
- NSInteger index;
- WindowOpenDisposition disposition;
- [self droppingURLsAt:point
- givesIndex:&index
- disposition:&disposition];
-
- // Either insert a new tab or open in a current tab.
- switch (disposition) {
- case NEW_FOREGROUND_TAB: {
- UserMetrics::RecordAction(UserMetricsAction("Tab_DropURLBetweenTabs"),
- browser_->profile());
- browser::NavigateParams params(browser_, url, PageTransition::TYPED);
- params.disposition = disposition;
- params.tabstrip_index = index;
- params.tabstrip_add_types =
- TabStripModel::ADD_SELECTED | TabStripModel::ADD_FORCE_INDEX;
- browser::Navigate(&params);
- break;
- }
- case CURRENT_TAB:
- UserMetrics::RecordAction(UserMetricsAction("Tab_DropURLOnTab"),
- browser_->profile());
- tabStripModel_->GetTabContentsAt(index)
- ->tab_contents()->OpenURL(url, GURL(), CURRENT_TAB,
- PageTransition::TYPED);
- tabStripModel_->SelectTabContentsAt(index, true);
- break;
- default:
- NOTIMPLEMENTED();
- }
-}
-
-// (URLDropTargetController protocol)
-- (void)indicateDropURLsInView:(NSView*)view at:(NSPoint)point {
- DCHECK_EQ(view, tabStripView_.get());
-
- // The minimum y-coordinate at which one should consider place the arrow.
- const CGFloat arrowBaseY = 25;
-
- NSInteger index;
- WindowOpenDisposition disposition;
- [self droppingURLsAt:point
- givesIndex:&index
- disposition:&disposition];
-
- NSPoint arrowPos = NSMakePoint(0, arrowBaseY);
- if (index == -1) {
- // Append a tab at the end.
- DCHECK(disposition == NEW_FOREGROUND_TAB);
- NSInteger lastIndex = [tabArray_ count] - 1;
- NSRect overRect = [[[tabArray_ objectAtIndex:lastIndex] view] frame];
- arrowPos.x = overRect.origin.x + overRect.size.width - kTabOverlap / 2.0;
- } else {
- NSRect overRect = [[[tabArray_ objectAtIndex:index] view] frame];
- switch (disposition) {
- case NEW_FOREGROUND_TAB:
- // Insert tab (to the left of the given tab).
- arrowPos.x = overRect.origin.x + kTabOverlap / 2.0;
- break;
- case CURRENT_TAB:
- // Overwrite the given tab.
- arrowPos.x = overRect.origin.x + overRect.size.width / 2.0;
- break;
- default:
- NOTREACHED();
- }
- }
-
- [tabStripView_ setDropArrowPosition:arrowPos];
- [tabStripView_ setDropArrowShown:YES];
- [tabStripView_ setNeedsDisplay:YES];
-}
-
-// (URLDropTargetController protocol)
-- (void)hideDropURLsIndicatorInView:(NSView*)view {
- DCHECK_EQ(view, tabStripView_.get());
-
- if ([tabStripView_ dropArrowShown]) {
- [tabStripView_ setDropArrowShown:NO];
- [tabStripView_ setNeedsDisplay:YES];
- }
-}
-
-- (GTMWindowSheetController*)sheetController {
- if (!sheetController_.get())
- sheetController_.reset([[GTMWindowSheetController alloc]
- initWithWindow:[switchView_ window] delegate:self]);
- return sheetController_.get();
-}
-
-- (void)destroySheetController {
- // Make sure there are no open sheets.
- DCHECK_EQ(0U, [[sheetController_ viewsWithAttachedSheets] count]);
- sheetController_.reset();
-}
-
-// TabContentsControllerDelegate protocol.
-- (void)tabContentsViewFrameWillChange:(TabContentsController*)source
- frameRect:(NSRect)frameRect {
- id<TabContentsControllerDelegate> controller =
- [[switchView_ window] windowController];
- [controller tabContentsViewFrameWillChange:source frameRect:frameRect];
-}
-
-- (TabContentsController*)activeTabContentsController {
- int modelIndex = tabStripModel_->selected_index();
- if (modelIndex < 0)
- return nil;
- NSInteger index = [self indexFromModelIndex:modelIndex];
- if (index < 0 ||
- index >= (NSInteger)[tabContentsArray_ count])
- return nil;
- return [tabContentsArray_ objectAtIndex:index];
-}
-
-- (void)gtm_systemRequestsVisibilityForView:(NSView*)view {
- // This implementation is required by GTMWindowSheetController.
-
- // Raise window...
- [[switchView_ window] makeKeyAndOrderFront:self];
-
- // ...and raise a tab with a sheet.
- NSInteger index = [self modelIndexForContentsView:view];
- DCHECK(index >= 0);
- if (index >= 0)
- tabStripModel_->SelectTabContentsAt(index, false /* not a user gesture */);
-}
-
-- (void)attachConstrainedWindow:(ConstrainedWindowMac*)window {
- // TODO(thakis, avi): Figure out how to make this work when tabs are dragged
- // out or if fullscreen mode is toggled.
-
- // View hierarchy of the contents view:
- // NSView -- switchView, same for all tabs
- // +- NSView -- TabContentsController's view
- // +- TabContentsViewCocoa
- // Changing it? Do not forget to modify removeConstrainedWindow too.
- // We use the TabContentsController's view in |swapInTabAtIndex|, so we have
- // to pass it to the sheet controller here.
- NSView* tabContentsView = [window->owner()->GetNativeView() superview];
- window->delegate()->RunSheet([self sheetController], tabContentsView);
-
- // TODO(avi, thakis): GTMWindowSheetController has no api to move tabsheets
- // between windows. Until then, we have to prevent having to move a tabsheet
- // between windows, e.g. no tearing off of tabs.
- NSInteger modelIndex = [self modelIndexForContentsView:tabContentsView];
- NSInteger index = [self indexFromModelIndex:modelIndex];
- BrowserWindowController* controller =
- (BrowserWindowController*)[[switchView_ window] windowController];
- DCHECK(controller != nil);
- DCHECK(index >= 0);
- if (index >= 0) {
- [controller setTab:[self viewAtIndex:index] isDraggable:NO];
- }
-}
-
-- (void)removeConstrainedWindow:(ConstrainedWindowMac*)window {
- NSView* tabContentsView = [window->owner()->GetNativeView() superview];
-
- // TODO(avi, thakis): GTMWindowSheetController has no api to move tabsheets
- // between windows. Until then, we have to prevent having to move a tabsheet
- // between windows, e.g. no tearing off of tabs.
- NSInteger modelIndex = [self modelIndexForContentsView:tabContentsView];
- NSInteger index = [self indexFromModelIndex:modelIndex];
- BrowserWindowController* controller =
- (BrowserWindowController*)[[switchView_ window] windowController];
- DCHECK(index >= 0);
- if (index >= 0) {
- [controller setTab:[self viewAtIndex:index] isDraggable:YES];
- }
-}
-
-@end
diff --git a/chrome/browser/cocoa/tab_strip_controller_unittest.mm b/chrome/browser/cocoa/tab_strip_controller_unittest.mm
deleted file mode 100644
index 7cfde56..0000000
--- a/chrome/browser/cocoa/tab_strip_controller_unittest.mm
+++ /dev/null
@@ -1,177 +0,0 @@
-// 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>
-
-#import "chrome/browser/browser_window.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/new_tab_button.h"
-#import "chrome/browser/cocoa/tab_strip_controller.h"
-#import "chrome/browser/cocoa/tab_strip_view.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
-#include "chrome/browser/renderer_host/site_instance.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-@interface TestTabStripControllerDelegate :
- NSObject<TabStripControllerDelegate> {
-}
-@end
-
-@implementation TestTabStripControllerDelegate
-- (void)onSelectTabWithContents:(TabContents*)contents {
-}
-- (void)onReplaceTabWithContents:(TabContents*)contents {
-}
-- (void)onSelectedTabChange:(TabStripModelObserver::TabChangeType)change {
-}
-- (void)onTabDetachedWithContents:(TabContents*)contents {
-}
-@end
-
-namespace {
-
-// Stub model delegate
-class TestTabStripDelegate : public TabStripModelDelegate {
- public:
- virtual TabContentsWrapper* AddBlankTab(bool foreground) {
- return NULL;
- }
- virtual TabContentsWrapper* AddBlankTabAt(int index, bool foreground) {
- return NULL;
- }
- virtual Browser* CreateNewStripWithContents(TabContentsWrapper* contents,
- const gfx::Rect& window_bounds,
- const DockInfo& dock_info,
- bool maximize) {
- return NULL;
- }
- virtual void ContinueDraggingDetachedTab(TabContentsWrapper* contents,
- const gfx::Rect& window_bounds,
- const gfx::Rect& tab_bounds) {
- }
- virtual int GetDragActions() const {
- return 0;
- }
- virtual TabContentsWrapper* CreateTabContentsForURL(
- const GURL& url,
- const GURL& referrer,
- Profile* profile,
- PageTransition::Type transition,
- bool defer_load,
- SiteInstance* instance) const {
- return NULL;
- }
- virtual bool CanDuplicateContentsAt(int index) { return true; }
- virtual void DuplicateContentsAt(int index) { }
- virtual void CloseFrameAfterDragSession() { }
- virtual void CreateHistoricalTab(TabContentsWrapper* contents) { }
- virtual bool RunUnloadListenerBeforeClosing(TabContentsWrapper* contents) {
- return true;
- }
- virtual bool CanRestoreTab() {
- return true;
- }
- virtual void RestoreTab() {}
-
- virtual bool CanCloseContentsAt(int index) { return true; }
-
- virtual bool CanBookmarkAllTabs() const { return false; }
-
- virtual bool CanCloseTab() const { return true; }
-
- virtual void BookmarkAllTabs() {}
-
- virtual bool UseVerticalTabs() const { return false; }
-
- virtual void ToggleUseVerticalTabs() {}
-
- virtual bool LargeIconsPermitted() const { return true; }
-};
-
-class TabStripControllerTest : public CocoaTest {
- public:
- TabStripControllerTest() {
- Browser* browser = browser_helper_.browser();
- BrowserWindow* browser_window = browser_helper_.CreateBrowserWindow();
- NSWindow* window = browser_window->GetNativeHandle();
- NSView* parent = [window contentView];
- NSRect content_frame = [parent frame];
-
- // Create the "switch view" (view that gets changed out when a tab
- // switches).
- NSRect switch_frame = NSMakeRect(0, 0, content_frame.size.width, 500);
- scoped_nsobject<NSView> switch_view(
- [[NSView alloc] initWithFrame:switch_frame]);
- [parent addSubview:switch_view.get()];
-
- // Create the tab strip view. It's expected to have a child button in it
- // already as the "new tab" button so create that too.
- NSRect strip_frame = NSMakeRect(0, NSMaxY(switch_frame),
- content_frame.size.width, 30);
- scoped_nsobject<TabStripView> tab_strip(
- [[TabStripView alloc] initWithFrame:strip_frame]);
- [parent addSubview:tab_strip.get()];
- NSRect button_frame = NSMakeRect(0, 0, 15, 15);
- scoped_nsobject<NewTabButton> new_tab_button(
- [[NewTabButton alloc] initWithFrame:button_frame]);
- [tab_strip addSubview:new_tab_button.get()];
- [tab_strip setNewTabButton:new_tab_button.get()];
-
- delegate_.reset(new TestTabStripDelegate());
- model_ = browser->tabstrip_model();
- controller_delegate_.reset([TestTabStripControllerDelegate alloc]);
- controller_.reset([[TabStripController alloc]
- initWithView:static_cast<TabStripView*>(tab_strip.get())
- switchView:switch_view.get()
- browser:browser
- delegate:controller_delegate_.get()]);
- }
-
- virtual void TearDown() {
- browser_helper_.CloseBrowserWindow();
- // The call to CocoaTest::TearDown() deletes the Browser and TabStripModel
- // objects, so we first have to delete the controller, which refers to them.
- controller_.reset(nil);
- model_ = NULL;
- CocoaTest::TearDown();
- }
-
- BrowserTestHelper browser_helper_;
- scoped_ptr<TestTabStripDelegate> delegate_;
- TabStripModel* model_;
- scoped_nsobject<TestTabStripControllerDelegate> controller_delegate_;
- scoped_nsobject<TabStripController> controller_;
-};
-
-// Test adding and removing tabs and making sure that views get added to
-// the tab strip.
-TEST_F(TabStripControllerTest, AddRemoveTabs) {
- EXPECT_TRUE(model_->empty());
- SiteInstance* instance =
- SiteInstance::CreateSiteInstance(browser_helper_.profile());
- TabContentsWrapper* tab_contents =
- Browser::TabContentsFactory(browser_helper_.profile(), instance,
- MSG_ROUTING_NONE, NULL, NULL);
- model_->AppendTabContents(tab_contents, true);
- EXPECT_EQ(model_->count(), 1);
-}
-
-TEST_F(TabStripControllerTest, SelectTab) {
- // TODO(pinkerton): Implement http://crbug.com/10899
-}
-
-TEST_F(TabStripControllerTest, RearrangeTabs) {
- // TODO(pinkerton): Implement http://crbug.com/10899
-}
-
-// Test that changing the number of tabs broadcasts a
-// kTabStripNumberOfTabsChanged notifiction.
-TEST_F(TabStripControllerTest, Notifications) {
- // TODO(pinkerton): Implement http://crbug.com/10899
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/tab_strip_model_observer_bridge.h b/chrome/browser/cocoa/tab_strip_model_observer_bridge.h
deleted file mode 100644
index fa9d1d7..0000000
--- a/chrome/browser/cocoa/tab_strip_model_observer_bridge.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_TAB_STRIP_MODEL_OBSERVER_BRIDGE_H_
-#define CHROME_BROWSER_COCOA_TAB_STRIP_MODEL_OBSERVER_BRIDGE_H_
-#pragma once
-
-#import <Foundation/Foundation.h>
-
-#include "chrome/browser/tabs/tab_strip_model_observer.h"
-
-class TabContentsWrapper;
-class TabStripModel;
-
-// A C++ bridge class to handle receiving notifications from the C++ tab strip
-// model. When the caller allocates a bridge, it automatically registers for
-// notifications from |model| and passes messages to |controller| via the
-// informal protocol below. The owner of this object is responsible for deleting
-// it (and thus unhooking notifications) before |controller| is destroyed.
-class TabStripModelObserverBridge : public TabStripModelObserver {
- public:
- TabStripModelObserverBridge(TabStripModel* model, id controller);
- virtual ~TabStripModelObserverBridge();
-
- // Overridden from TabStripModelObserver
- virtual void TabInsertedAt(TabContentsWrapper* contents,
- int index,
- bool foreground);
- virtual void TabClosingAt(TabStripModel* tab_strip_model,
- TabContentsWrapper* contents,
- int index);
- virtual void TabDetachedAt(TabContentsWrapper* contents, int index);
- virtual void TabSelectedAt(TabContentsWrapper* old_contents,
- TabContentsWrapper* new_contents,
- int index,
- bool user_gesture);
- virtual void TabMoved(TabContentsWrapper* contents,
- int from_index,
- int to_index);
- virtual void TabChangedAt(TabContentsWrapper* contents, int index,
- TabChangeType change_type);
- virtual void TabReplacedAt(TabContentsWrapper* old_contents,
- TabContentsWrapper* new_contents,
- int index);
- virtual void TabMiniStateChanged(TabContentsWrapper* contents, int index);
- virtual void TabStripEmpty();
- virtual void TabStripModelDeleted();
-
- private:
- id controller_; // weak, owns me
- TabStripModel* model_; // weak, owned by Browser
-};
-
-// A collection of methods which can be selectively implemented by any
-// Cocoa object to receive updates about changes to a tab strip model. It is
-// ok to not implement them, the calling code checks before calling.
-@interface NSObject(TabStripModelBridge)
-- (void)insertTabWithContents:(TabContentsWrapper*)contents
- atIndex:(NSInteger)index
- inForeground:(bool)inForeground;
-- (void)tabClosingWithContents:(TabContentsWrapper*)contents
- atIndex:(NSInteger)index;
-- (void)tabDetachedWithContents:(TabContentsWrapper*)contents
- atIndex:(NSInteger)index;
-- (void)selectTabWithContents:(TabContentsWrapper*)newContents
- previousContents:(TabContentsWrapper*)oldContents
- atIndex:(NSInteger)index
- userGesture:(bool)wasUserGesture;
-- (void)tabMovedWithContents:(TabContentsWrapper*)contents
- fromIndex:(NSInteger)from
- toIndex:(NSInteger)to;
-- (void)tabChangedWithContents:(TabContentsWrapper*)contents
- atIndex:(NSInteger)index
- changeType:(TabStripModelObserver::TabChangeType)change;
-- (void)tabReplacedWithContents:(TabContentsWrapper*)newContents
- previousContents:(TabContentsWrapper*)oldContents
- atIndex:(NSInteger)index;
-- (void)tabMiniStateChangedWithContents:(TabContentsWrapper*)contents
- atIndex:(NSInteger)index;
-- (void)tabStripEmpty;
-- (void)tabStripModelDeleted;
-@end
-
-#endif // CHROME_BROWSER_COCOA_TAB_STRIP_MODEL_OBSERVER_BRIDGE_H_
diff --git a/chrome/browser/cocoa/tab_strip_model_observer_bridge.mm b/chrome/browser/cocoa/tab_strip_model_observer_bridge.mm
deleted file mode 100644
index 7aad635..0000000
--- a/chrome/browser/cocoa/tab_strip_model_observer_bridge.mm
+++ /dev/null
@@ -1,118 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/tab_strip_model_observer_bridge.h"
-
-#include "chrome/browser/tabs/tab_strip_model.h"
-
-TabStripModelObserverBridge::TabStripModelObserverBridge(TabStripModel* model,
- id controller)
- : controller_(controller), model_(model) {
- DCHECK(model && controller);
- // Register to be a listener on the model so we can get updates and tell
- // |controller_| about them in the future.
- model_->AddObserver(this);
-}
-
-TabStripModelObserverBridge::~TabStripModelObserverBridge() {
- // Remove ourselves from receiving notifications.
- model_->RemoveObserver(this);
-}
-
-void TabStripModelObserverBridge::TabInsertedAt(TabContentsWrapper* contents,
- int index,
- bool foreground) {
- if ([controller_ respondsToSelector:
- @selector(insertTabWithContents:atIndex:inForeground:)]) {
- [controller_ insertTabWithContents:contents
- atIndex:index
- inForeground:foreground];
- }
-}
-
-void TabStripModelObserverBridge::TabClosingAt(TabStripModel* tab_strip_model,
- TabContentsWrapper* contents,
- int index) {
- if ([controller_ respondsToSelector:
- @selector(tabClosingWithContents:atIndex:)]) {
- [controller_ tabClosingWithContents:contents atIndex:index];
- }
-}
-
-void TabStripModelObserverBridge::TabDetachedAt(TabContentsWrapper* contents,
- int index) {
- if ([controller_ respondsToSelector:
- @selector(tabDetachedWithContents:atIndex:)]) {
- [controller_ tabDetachedWithContents:contents atIndex:index];
- }
-}
-
-void TabStripModelObserverBridge::TabSelectedAt(
- TabContentsWrapper* old_contents,
- TabContentsWrapper* new_contents,
- int index,
- bool user_gesture) {
- if ([controller_ respondsToSelector:
- @selector(selectTabWithContents:previousContents:atIndex:
- userGesture:)]) {
- [controller_ selectTabWithContents:new_contents
- previousContents:old_contents
- atIndex:index
- userGesture:user_gesture];
- }
-}
-
-void TabStripModelObserverBridge::TabMoved(TabContentsWrapper* contents,
- int from_index,
- int to_index) {
- if ([controller_ respondsToSelector:
- @selector(tabMovedWithContents:fromIndex:toIndex:)]) {
- [controller_ tabMovedWithContents:contents
- fromIndex:from_index
- toIndex:to_index];
- }
-}
-
-void TabStripModelObserverBridge::TabChangedAt(TabContentsWrapper* contents,
- int index,
- TabChangeType change_type) {
- if ([controller_ respondsToSelector:
- @selector(tabChangedWithContents:atIndex:changeType:)]) {
- [controller_ tabChangedWithContents:contents
- atIndex:index
- changeType:change_type];
- }
-}
-
-void TabStripModelObserverBridge::TabReplacedAt(
- TabContentsWrapper* old_contents,
- TabContentsWrapper* new_contents,
- int index) {
- if ([controller_ respondsToSelector:
- @selector(tabReplacedWithContents:previousContents:atIndex:)]) {
- [controller_ tabReplacedWithContents:new_contents
- previousContents:old_contents
- atIndex:index];
- } else {
- TabChangedAt(new_contents, index, ALL);
- }
-}
-
-void TabStripModelObserverBridge::TabMiniStateChanged(
- TabContentsWrapper* contents, int index) {
- if ([controller_ respondsToSelector:
- @selector(tabMiniStateChangedWithContents:atIndex:)]) {
- [controller_ tabMiniStateChangedWithContents:contents atIndex:index];
- }
-}
-
-void TabStripModelObserverBridge::TabStripEmpty() {
- if ([controller_ respondsToSelector:@selector(tabStripEmpty)])
- [controller_ tabStripEmpty];
-}
-
-void TabStripModelObserverBridge::TabStripModelDeleted() {
- if ([controller_ respondsToSelector:@selector(tabStripModelDeleted)])
- [controller_ tabStripModelDeleted];
-}
diff --git a/chrome/browser/cocoa/tab_strip_view.h b/chrome/browser/cocoa/tab_strip_view.h
deleted file mode 100644
index 55214da..0000000
--- a/chrome/browser/cocoa/tab_strip_view.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_TAB_STRIP_VIEW_H_
-#define CHROME_BROWSER_COCOA_TAB_STRIP_VIEW_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/url_drop_target.h"
-
-@class NewTabButton;
-
-// A view class that handles rendering the tab strip and drops of URLS with
-// a positioning locator for drop feedback.
-
-@interface TabStripView : NSView<URLDropTarget> {
- @private
- NSTimeInterval lastMouseUp_;
-
- // Handles being a drag-and-drop target.
- scoped_nsobject<URLDropTargetHandler> dropHandler_;
-
- // Weak; the following come from the nib.
- NewTabButton* newTabButton_;
-
- // Whether the drop-indicator arrow is shown, and if it is, the coordinate of
- // its tip.
- BOOL dropArrowShown_;
- NSPoint dropArrowPosition_;
-}
-
-@property(assign, nonatomic) IBOutlet NewTabButton* newTabButton;
-@property(assign, nonatomic) BOOL dropArrowShown;
-@property(assign, nonatomic) NSPoint dropArrowPosition;
-
-@end
-
-// Protected methods subclasses can override to alter behavior. Clients should
-// not call these directly.
-@interface TabStripView(Protected)
-- (void)drawBottomBorder:(NSRect)bounds;
-- (BOOL)doubleClickMinimizesWindow;
-@end
-
-#endif // CHROME_BROWSER_COCOA_TAB_STRIP_VIEW_H_
diff --git a/chrome/browser/cocoa/tab_strip_view.mm b/chrome/browser/cocoa/tab_strip_view.mm
deleted file mode 100644
index 1e0daf8..0000000
--- a/chrome/browser/cocoa/tab_strip_view.mm
+++ /dev/null
@@ -1,211 +0,0 @@
-// 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 "chrome/browser/cocoa/tab_strip_view.h"
-
-#include "base/logging.h"
-#include "base/mac_util.h"
-#import "chrome/browser/cocoa/browser_window_controller.h"
-#import "chrome/browser/cocoa/tab_strip_controller.h"
-#import "chrome/browser/cocoa/view_id_util.h"
-#include "chrome/browser/themes/browser_theme_provider.h"
-
-@implementation TabStripView
-
-@synthesize newTabButton = newTabButton_;
-@synthesize dropArrowShown = dropArrowShown_;
-@synthesize dropArrowPosition = dropArrowPosition_;
-
-- (id)initWithFrame:(NSRect)frame {
- self = [super initWithFrame:frame];
- if (self) {
- // Set lastMouseUp_ = -1000.0 so that timestamp-lastMouseUp_ is big unless
- // lastMouseUp_ has been reset.
- lastMouseUp_ = -1000.0;
-
- // Register to be an URL drop target.
- dropHandler_.reset([[URLDropTargetHandler alloc] initWithView:self]);
- }
- return self;
-}
-
-// Draw bottom border (a dark border and light highlight). Each tab is
-// responsible for mimicking this bottom border, unless it's the selected
-// tab.
-- (void)drawBorder:(NSRect)bounds {
- NSRect borderRect, contentRect;
-
- borderRect = bounds;
- borderRect.origin.y = 1;
- borderRect.size.height = 1;
- [[NSColor colorWithCalibratedWhite:0.0 alpha:0.2] set];
- NSRectFillUsingOperation(borderRect, NSCompositeSourceOver);
- NSDivideRect(bounds, &borderRect, &contentRect, 1, NSMinYEdge);
-
- BrowserThemeProvider* themeProvider =
- static_cast<BrowserThemeProvider*>([[self window] themeProvider]);
- if (!themeProvider)
- return;
-
- NSColor* bezelColor = themeProvider->GetNSColor(
- themeProvider->UsingDefaultTheme() ?
- BrowserThemeProvider::COLOR_TOOLBAR_BEZEL :
- BrowserThemeProvider::COLOR_TOOLBAR, true);
- [bezelColor set];
- NSRectFill(borderRect);
- NSRectFillUsingOperation(borderRect, NSCompositeSourceOver);
-}
-
-- (void)drawRect:(NSRect)rect {
- NSRect boundsRect = [self bounds];
-
- [self drawBorder:boundsRect];
-
- // Draw drop-indicator arrow (if appropriate).
- // TODO(viettrungluu): this is all a stop-gap measure.
- if ([self dropArrowShown]) {
- // Programmer art: an arrow parametrized by many knobs. Note that the arrow
- // points downwards (so understand "width" and "height" accordingly).
-
- // How many (pixels) to inset on the top/bottom.
- const CGFloat kArrowTopInset = 1.5;
- const CGFloat kArrowBottomInset = 1;
-
- // What proportion of the vertical space is dedicated to the arrow tip,
- // i.e., (arrow tip height)/(amount of vertical space).
- const CGFloat kArrowTipProportion = 0.5;
-
- // This is a slope, i.e., (arrow tip height)/(0.5 * arrow tip width).
- const CGFloat kArrowTipSlope = 1.2;
-
- // What proportion of the arrow tip width is the stem, i.e., (stem
- // width)/(arrow tip width).
- const CGFloat kArrowStemProportion = 0.33;
-
- NSPoint arrowTipPos = [self dropArrowPosition];
- arrowTipPos.y += kArrowBottomInset; // Inset on the bottom.
-
- // Height we have to work with (insetting on the top).
- CGFloat availableHeight =
- NSMaxY(boundsRect) - arrowTipPos.y - kArrowTopInset;
- DCHECK(availableHeight >= 5);
-
- // Based on the knobs above, calculate actual dimensions which we'll need
- // for drawing.
- CGFloat arrowTipHeight = kArrowTipProportion * availableHeight;
- CGFloat arrowTipWidth = 2 * arrowTipHeight / kArrowTipSlope;
- CGFloat arrowStemHeight = availableHeight - arrowTipHeight;
- CGFloat arrowStemWidth = kArrowStemProportion * arrowTipWidth;
- CGFloat arrowStemInset = (arrowTipWidth - arrowStemWidth) / 2;
-
- // The line width is arbitrary, but our path really should be mitered.
- NSBezierPath* arrow = [NSBezierPath bezierPath];
- [arrow setLineJoinStyle:NSMiterLineJoinStyle];
- [arrow setLineWidth:1];
-
- // Define the arrow's shape! We start from the tip and go clockwise.
- [arrow moveToPoint:arrowTipPos];
- [arrow relativeLineToPoint:NSMakePoint(-arrowTipWidth / 2, arrowTipHeight)];
- [arrow relativeLineToPoint:NSMakePoint(arrowStemInset, 0)];
- [arrow relativeLineToPoint:NSMakePoint(0, arrowStemHeight)];
- [arrow relativeLineToPoint:NSMakePoint(arrowStemWidth, 0)];
- [arrow relativeLineToPoint:NSMakePoint(0, -arrowStemHeight)];
- [arrow relativeLineToPoint:NSMakePoint(arrowStemInset, 0)];
- [arrow closePath];
-
- // Draw and fill the arrow.
- [[NSColor colorWithCalibratedWhite:0 alpha:0.67] set];
- [arrow stroke];
- [[NSColor colorWithCalibratedWhite:1 alpha:0.67] setFill];
- [arrow fill];
- }
-}
-
-// YES if a double-click in the background of the tab strip minimizes the
-// window.
-- (BOOL)doubleClickMinimizesWindow {
- return YES;
-}
-
-// We accept first mouse so clicks onto close/zoom/miniaturize buttons and
-// title bar double-clicks are properly detected even when the window is in the
-// background.
-- (BOOL)acceptsFirstMouse:(NSEvent*)event {
- return YES;
-}
-
-// Trap double-clicks and make them miniaturize the browser window.
-- (void)mouseUp:(NSEvent*)event {
- // Bail early if double-clicks are disabled.
- if (![self doubleClickMinimizesWindow]) {
- [super mouseUp:event];
- return;
- }
-
- NSInteger clickCount = [event clickCount];
- NSTimeInterval timestamp = [event timestamp];
-
- // Double-clicks on Zoom/Close/Mininiaturize buttons shouldn't cause
- // miniaturization. For those, we miss the first click but get the second
- // (with clickCount == 2!). We thus check that we got a first click shortly
- // before (measured up-to-up) a double-click. Cocoa doesn't have a documented
- // way of getting the proper interval (= (double-click-threshold) +
- // (drag-threshold); the former is Carbon GetDblTime()/60.0 or
- // com.apple.mouse.doubleClickThreshold [undocumented]). So we hard-code
- // "short" as 0.8 seconds. (Measuring up-to-up isn't enough to properly
- // detect double-clicks, but we're actually using Cocoa for that.)
- if (clickCount == 2 && (timestamp - lastMouseUp_) < 0.8) {
- if (mac_util::ShouldWindowsMiniaturizeOnDoubleClick())
- [[self window] performMiniaturize:self];
- } else {
- [super mouseUp:event];
- }
-
- // If clickCount is 0, the drag threshold was passed.
- lastMouseUp_ = (clickCount == 1) ? timestamp : -1000.0;
-}
-
-// (URLDropTarget protocol)
-- (id<URLDropTargetController>)urlDropController {
- BrowserWindowController* windowController = [[self window] windowController];
- DCHECK([windowController isKindOfClass:[BrowserWindowController class]]);
- return [windowController tabStripController];
-}
-
-// (URLDropTarget protocol)
-- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
- return [dropHandler_ draggingEntered:sender];
-}
-
-// (URLDropTarget protocol)
-- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender {
- return [dropHandler_ draggingUpdated:sender];
-}
-
-// (URLDropTarget protocol)
-- (void)draggingExited:(id<NSDraggingInfo>)sender {
- return [dropHandler_ draggingExited:sender];
-}
-
-// (URLDropTarget protocol)
-- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
- return [dropHandler_ performDragOperation:sender];
-}
-
-- (BOOL)accessibilityIsIgnored {
- return NO;
-}
-
-- (id)accessibilityAttributeValue:(NSString*)attribute {
- if ([attribute isEqual:NSAccessibilityRoleAttribute])
- return NSAccessibilityGroupRole;
-
- return [super accessibilityAttributeValue:attribute];
-}
-
-- (ViewID)viewID {
- return VIEW_ID_TAB_STRIP;
-}
-
-@end
diff --git a/chrome/browser/cocoa/tab_strip_view_unittest.mm b/chrome/browser/cocoa/tab_strip_view_unittest.mm
deleted file mode 100644
index 635d3c2..0000000
--- a/chrome/browser/cocoa/tab_strip_view_unittest.mm
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2009 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 "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/tab_strip_view.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-namespace {
-
-class TabStripViewTest : public CocoaTest {
- public:
- TabStripViewTest() {
- NSRect frame = NSMakeRect(0, 0, 100, 30);
- scoped_nsobject<TabStripView> view(
- [[TabStripView alloc] initWithFrame:frame]);
- view_ = view.get();
- [[test_window() contentView] addSubview:view_];
- }
-
- TabStripView* view_;
-};
-
-TEST_VIEW(TabStripViewTest, view_)
-
-} // namespace
diff --git a/chrome/browser/cocoa/tab_view.h b/chrome/browser/cocoa/tab_view.h
deleted file mode 100644
index 73c6334..0000000
--- a/chrome/browser/cocoa/tab_view.h
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_TAB_VIEW_H_
-#define CHROME_BROWSER_COCOA_TAB_VIEW_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-#include <ApplicationServices/ApplicationServices.h>
-
-#include <map>
-
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/background_gradient_view.h"
-#import "chrome/browser/cocoa/hover_close_button.h"
-
-namespace tabs {
-
-// Nomenclature:
-// Tabs _glow_ under two different circumstances, when they are _hovered_ (by
-// the mouse) and when they are _alerted_ (to show that the tab's title has
-// changed).
-
-// The state of alerting (to show a title change on an unselected, pinned tab).
-// This is more complicated than a simple on/off since we want to allow the
-// alert glow to go through a full rise-hold-fall cycle to avoid flickering (or
-// always holding).
-enum AlertState {
- kAlertNone = 0, // Obj-C initializes to this.
- kAlertRising,
- kAlertHolding,
- kAlertFalling
-};
-
-} // namespace tabs
-
-@class TabController, TabWindowController;
-
-// A view that handles the event tracking (clicking and dragging) for a tab
-// on the tab strip. Relies on an associated TabController to provide a
-// target/action for selecting the tab.
-
-@interface TabView : BackgroundGradientView {
- @private
- IBOutlet TabController* controller_;
- // TODO(rohitrao): Add this button to a CoreAnimation layer so we can fade it
- // in and out on mouseovers.
- IBOutlet HoverCloseButton* closeButton_;
-
- // See awakeFromNib for purpose.
- scoped_nsobject<HoverCloseButton> closeButtonRetainer_;
-
- BOOL closing_;
-
- // Tracking area for close button mouseover images.
- scoped_nsobject<NSTrackingArea> closeTrackingArea_;
-
- BOOL isMouseInside_; // Is the mouse hovering over?
- tabs::AlertState alertState_;
-
- CGFloat hoverAlpha_; // How strong the hover glow is.
- NSTimeInterval hoverHoldEndTime_; // When the hover glow will begin dimming.
-
- CGFloat alertAlpha_; // How strong the alert glow is.
- NSTimeInterval alertHoldEndTime_; // When the hover glow will begin dimming.
-
- NSTimeInterval lastGlowUpdate_; // Time either glow was last updated.
-
- NSPoint hoverPoint_; // Current location of hover in view coords.
-
- // All following variables are valid for the duration of a drag.
- // These are released on mouseUp:
- BOOL moveWindowOnDrag_; // Set if the only tab of a window is dragged.
- BOOL tabWasDragged_; // Has the tab been dragged?
- BOOL draggingWithinTabStrip_; // Did drag stay in the current tab strip?
- BOOL chromeIsVisible_;
-
- NSTimeInterval tearTime_; // Time since tear happened
- NSPoint tearOrigin_; // Origin of the tear rect
- NSPoint dragOrigin_; // Origin point of the drag
- // TODO(alcor): these references may need to be strong to avoid crashes
- // due to JS closing windows
- TabWindowController* sourceController_; // weak. controller starting the drag
- NSWindow* sourceWindow_; // weak. The window starting the drag
- NSRect sourceWindowFrame_;
- NSRect sourceTabFrame_;
-
- TabWindowController* draggedController_; // weak. Controller being dragged.
- NSWindow* dragWindow_; // weak. The window being dragged
- NSWindow* dragOverlay_; // weak. The overlay being dragged
- // Cache workspace IDs per-drag because computing them on 10.5 with
- // CGWindowListCreateDescriptionFromArray is expensive.
- // resetDragControllers clears this cache.
- //
- // TODO(davidben): When 10.5 becomes unsupported, remove this.
- std::map<CGWindowID, int> workspaceIDCache_;
-
- TabWindowController* targetController_; // weak. Controller being targeted
- NSCellStateValue state_;
-}
-
-@property(assign, nonatomic) NSCellStateValue state;
-@property(assign, nonatomic) CGFloat hoverAlpha;
-@property(assign, nonatomic) CGFloat alertAlpha;
-
-// Determines if the tab is in the process of animating closed. It may still
-// be visible on-screen, but should not respond to/initiate any events. Upon
-// setting to NO, clears the target/action of the close button to prevent
-// clicks inside it from sending messages.
-@property(assign, nonatomic, getter=isClosing) BOOL closing;
-
-// Enables/Disables tracking regions for the tab.
-- (void)setTrackingEnabled:(BOOL)enabled;
-
-// Begin showing an "alert" glow (shown to call attention to an unselected
-// pinned tab whose title changed).
-- (void)startAlert;
-
-// Stop showing the "alert" glow; this won't immediately wipe out any glow, but
-// will make it fade away.
-- (void)cancelAlert;
-
-@end
-
-// The TabController |controller_| is not the only owner of this view. If the
-// controller is released before this view, then we could be hanging onto a
-// garbage pointer. To prevent this, the TabController uses this interface to
-// clear the |controller_| pointer when it is dying.
-@interface TabView (TabControllerInterface)
-- (void)setController:(TabController*)controller;
-@end
-
-#endif // CHROME_BROWSER_COCOA_TAB_VIEW_H_
diff --git a/chrome/browser/cocoa/tab_view.mm b/chrome/browser/cocoa/tab_view.mm
deleted file mode 100644
index 1550d7e..0000000
--- a/chrome/browser/cocoa/tab_view.mm
+++ /dev/null
@@ -1,1057 +0,0 @@
-// 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 "chrome/browser/cocoa/tab_view.h"
-
-#include "base/logging.h"
-#import "base/mac_util.h"
-#include "base/mac/scoped_cftyperef.h"
-#include "base/nsimage_cache_mac.h"
-#include "chrome/browser/accessibility/browser_accessibility_state.h"
-#import "chrome/browser/cocoa/tab_controller.h"
-#import "chrome/browser/cocoa/tab_window_controller.h"
-#import "chrome/browser/cocoa/themed_window.h"
-#import "chrome/browser/cocoa/view_id_util.h"
-#include "chrome/browser/themes/browser_theme_provider.h"
-#include "grit/theme_resources.h"
-
-namespace {
-
-// Constants for inset and control points for tab shape.
-const CGFloat kInsetMultiplier = 2.0/3.0;
-const CGFloat kControlPoint1Multiplier = 1.0/3.0;
-const CGFloat kControlPoint2Multiplier = 3.0/8.0;
-
-// The amount of time in seconds during which each type of glow increases, holds
-// steady, and decreases, respectively.
-const NSTimeInterval kHoverShowDuration = 0.2;
-const NSTimeInterval kHoverHoldDuration = 0.02;
-const NSTimeInterval kHoverHideDuration = 0.4;
-const NSTimeInterval kAlertShowDuration = 0.4;
-const NSTimeInterval kAlertHoldDuration = 0.4;
-const NSTimeInterval kAlertHideDuration = 0.4;
-
-// The default time interval in seconds between glow updates (when
-// increasing/decreasing).
-const NSTimeInterval kGlowUpdateInterval = 0.025;
-
-const CGFloat kTearDistance = 36.0;
-const NSTimeInterval kTearDuration = 0.333;
-
-// This is used to judge whether the mouse has moved during rapid closure; if it
-// has moved less than the threshold, we want to close the tab.
-const CGFloat kRapidCloseDist = 2.5;
-
-} // namespace
-
-@interface TabView(Private)
-
-- (void)resetLastGlowUpdateTime;
-- (NSTimeInterval)timeElapsedSinceLastGlowUpdate;
-- (void)adjustGlowValue;
-// TODO(davidben): When we stop supporting 10.5, this can be removed.
-- (int)getWorkspaceID:(NSWindow*)window useCache:(BOOL)useCache;
-- (NSBezierPath*)bezierPathForRect:(NSRect)rect;
-
-@end // TabView(Private)
-
-@implementation TabView
-
-@synthesize state = state_;
-@synthesize hoverAlpha = hoverAlpha_;
-@synthesize alertAlpha = alertAlpha_;
-@synthesize closing = closing_;
-
-- (id)initWithFrame:(NSRect)frame {
- self = [super initWithFrame:frame];
- if (self) {
- [self setShowsDivider:NO];
- // TODO(alcor): register for theming
- }
- return self;
-}
-
-- (void)awakeFromNib {
- [self setShowsDivider:NO];
-
- // It is desirable for us to remove the close button from the cocoa hierarchy,
- // so that VoiceOver does not encounter it.
- // TODO(dtseng): crbug.com/59978.
- // Retain in case we remove it from its superview.
- closeButtonRetainer_.reset([closeButton_ retain]);
- if (Singleton<BrowserAccessibilityState>::get()->IsAccessibleBrowser()) {
- // The superview gives up ownership of the closeButton here.
- [closeButton_ removeFromSuperview];
- }
-}
-
-- (void)dealloc {
- // Cancel any delayed requests that may still be pending (drags or hover).
- [NSObject cancelPreviousPerformRequestsWithTarget:self];
- [super dealloc];
-}
-
-// Called to obtain the context menu for when the user hits the right mouse
-// button (or control-clicks). (Note that -rightMouseDown: is *not* called for
-// control-click.)
-- (NSMenu*)menu {
- if ([self isClosing])
- return nil;
-
- // Sheets, being window-modal, should block contextual menus. For some reason
- // they do not. Disallow them ourselves.
- if ([[self window] attachedSheet])
- return nil;
-
- return [controller_ menu];
-}
-
-// Overridden so that mouse clicks come to this view (the parent of the
-// hierarchy) first. We want to handle clicks and drags in this class and
-// leave the background button for display purposes only.
-- (BOOL)acceptsFirstMouse:(NSEvent*)theEvent {
- return YES;
-}
-
-- (void)mouseEntered:(NSEvent*)theEvent {
- isMouseInside_ = YES;
- [self resetLastGlowUpdateTime];
- [self adjustGlowValue];
-}
-
-- (void)mouseMoved:(NSEvent*)theEvent {
- hoverPoint_ = [self convertPoint:[theEvent locationInWindow]
- fromView:nil];
- [self setNeedsDisplay:YES];
-}
-
-- (void)mouseExited:(NSEvent*)theEvent {
- isMouseInside_ = NO;
- hoverHoldEndTime_ =
- [NSDate timeIntervalSinceReferenceDate] + kHoverHoldDuration;
- [self resetLastGlowUpdateTime];
- [self adjustGlowValue];
-}
-
-- (void)setTrackingEnabled:(BOOL)enabled {
- [closeButton_ setTrackingEnabled:enabled];
-}
-
-// Determines which view a click in our frame actually hit. It's either this
-// view or our child close button.
-- (NSView*)hitTest:(NSPoint)aPoint {
- NSPoint viewPoint = [self convertPoint:aPoint fromView:[self superview]];
- NSRect frame = [self frame];
-
- // Reduce the width of the hit rect slightly to remove the overlap
- // between adjacent tabs. The drawing code in TabCell has the top
- // corners of the tab inset by height*2/3, so we inset by half of
- // that here. This doesn't completely eliminate the overlap, but it
- // works well enough.
- NSRect hitRect = NSInsetRect(frame, frame.size.height / 3.0f, 0);
- if (![closeButton_ isHidden])
- if (NSPointInRect(viewPoint, [closeButton_ frame])) return closeButton_;
- if (NSPointInRect(aPoint, hitRect)) return self;
- return nil;
-}
-
-// Returns |YES| if this tab can be torn away into a new window.
-- (BOOL)canBeDragged {
- if ([self isClosing])
- return NO;
- NSWindowController* controller = [sourceWindow_ windowController];
- if ([controller isKindOfClass:[TabWindowController class]]) {
- TabWindowController* realController =
- static_cast<TabWindowController*>(controller);
- return [realController isTabDraggable:self];
- }
- return YES;
-}
-
-// Returns an array of controllers that could be a drop target, ordered front to
-// back. It has to be of the appropriate class, and visible (obviously). Note
-// that the window cannot be a target for itself.
-- (NSArray*)dropTargetsForController:(TabWindowController*)dragController {
- NSMutableArray* targets = [NSMutableArray array];
- NSWindow* dragWindow = [dragController window];
- for (NSWindow* window in [NSApp orderedWindows]) {
- if (window == dragWindow) continue;
- if (![window isVisible]) continue;
- // Skip windows on the wrong space.
- if ([window respondsToSelector:@selector(isOnActiveSpace)]) {
- if (![window performSelector:@selector(isOnActiveSpace)])
- continue;
- } else {
- // TODO(davidben): When we stop supporting 10.5, this can be
- // removed.
- //
- // We don't cache the workspace of |dragWindow| because it may
- // move around spaces.
- if ([self getWorkspaceID:dragWindow useCache:NO] !=
- [self getWorkspaceID:window useCache:YES])
- continue;
- }
- NSWindowController* controller = [window windowController];
- if ([controller isKindOfClass:[TabWindowController class]]) {
- TabWindowController* realController =
- static_cast<TabWindowController*>(controller);
- if ([realController canReceiveFrom:dragController])
- [targets addObject:controller];
- }
- }
- return targets;
-}
-
-// Call to clear out transient weak references we hold during drags.
-- (void)resetDragControllers {
- draggedController_ = nil;
- dragWindow_ = nil;
- dragOverlay_ = nil;
- sourceController_ = nil;
- sourceWindow_ = nil;
- targetController_ = nil;
- workspaceIDCache_.clear();
-}
-
-// Sets whether the window background should be visible or invisible when
-// dragging a tab. The background should be invisible when the mouse is over a
-// potential drop target for the tab (the tab strip). It should be visible when
-// there's no drop target so the window looks more fully realized and ready to
-// become a stand-alone window.
-- (void)setWindowBackgroundVisibility:(BOOL)shouldBeVisible {
- if (chromeIsVisible_ == shouldBeVisible)
- return;
-
- // There appears to be a race-condition in CoreAnimation where if we use
- // animators to set the alpha values, we can't guarantee that we cancel them.
- // This has the side effect of sometimes leaving the dragged window
- // translucent or invisible. As a result, don't animate the alpha change.
- [[draggedController_ overlayWindow] setAlphaValue:1.0];
- if (targetController_) {
- [dragWindow_ setAlphaValue:0.0];
- [[draggedController_ overlayWindow] setHasShadow:YES];
- [[targetController_ window] makeMainWindow];
- } else {
- [dragWindow_ setAlphaValue:0.5];
- [[draggedController_ overlayWindow] setHasShadow:NO];
- [[draggedController_ window] makeMainWindow];
- }
- chromeIsVisible_ = shouldBeVisible;
-}
-
-// Handle clicks and drags in this button. We get here because we have
-// overridden acceptsFirstMouse: and the click is within our bounds.
-- (void)mouseDown:(NSEvent*)theEvent {
- if ([self isClosing])
- return;
-
- NSPoint downLocation = [theEvent locationInWindow];
-
- // Record the state of the close button here, because selecting the tab will
- // unhide it.
- BOOL closeButtonActive = [closeButton_ isHidden] ? NO : YES;
-
- // During the tab closure animation (in particular, during rapid tab closure),
- // we may get incorrectly hit with a mouse down. If it should have gone to the
- // close button, we send it there -- it should then track the mouse, so we
- // don't have to worry about mouse ups.
- if (closeButtonActive && [controller_ inRapidClosureMode]) {
- NSPoint hitLocation = [[self superview] convertPoint:downLocation
- fromView:nil];
- if ([self hitTest:hitLocation] == closeButton_) {
- [closeButton_ mouseDown:theEvent];
- return;
- }
- }
-
- // Fire the action to select the tab.
- if ([[controller_ target] respondsToSelector:[controller_ action]])
- [[controller_ target] performSelector:[controller_ action]
- withObject:self];
-
- [self resetDragControllers];
-
- // Resolve overlay back to original window.
- sourceWindow_ = [self window];
- if ([sourceWindow_ isKindOfClass:[NSPanel class]]) {
- sourceWindow_ = [sourceWindow_ parentWindow];
- }
-
- sourceWindowFrame_ = [sourceWindow_ frame];
- sourceTabFrame_ = [self frame];
- sourceController_ = [sourceWindow_ windowController];
- tabWasDragged_ = NO;
- tearTime_ = 0.0;
- draggingWithinTabStrip_ = YES;
- chromeIsVisible_ = NO;
-
- // If there's more than one potential window to be a drop target, we want to
- // treat a drag of a tab just like dragging around a tab that's already
- // detached. Note that unit tests might have |-numberOfTabs| reporting zero
- // since the model won't be fully hooked up. We need to be prepared for that
- // and not send them into the "magnetic" codepath.
- NSArray* targets = [self dropTargetsForController:sourceController_];
- moveWindowOnDrag_ =
- ([sourceController_ numberOfTabs] < 2 && ![targets count]) ||
- ![self canBeDragged] ||
- ![sourceController_ tabDraggingAllowed];
- // If we are dragging a tab, a window with a single tab should immediately
- // snap off and not drag within the tab strip.
- if (!moveWindowOnDrag_)
- draggingWithinTabStrip_ = [sourceController_ numberOfTabs] > 1;
-
- dragOrigin_ = [NSEvent mouseLocation];
-
- // If the tab gets torn off, the tab controller will be removed from the tab
- // strip and then deallocated. This will also result in *us* being
- // deallocated. Both these are bad, so we prevent this by retaining the
- // controller.
- scoped_nsobject<TabController> controller([controller_ retain]);
-
- // Because we move views between windows, we need to handle the event loop
- // ourselves. Ideally we should use the standard event loop.
- while (1) {
- theEvent =
- [NSApp nextEventMatchingMask:NSLeftMouseUpMask | NSLeftMouseDraggedMask
- untilDate:[NSDate distantFuture]
- inMode:NSDefaultRunLoopMode dequeue:YES];
- NSEventType type = [theEvent type];
- if (type == NSLeftMouseDragged) {
- [self mouseDragged:theEvent];
- } else if (type == NSLeftMouseUp) {
- NSPoint upLocation = [theEvent locationInWindow];
- CGFloat dx = upLocation.x - downLocation.x;
- CGFloat dy = upLocation.y - downLocation.y;
-
- // During rapid tab closure (mashing tab close buttons), we may get hit
- // with a mouse down. As long as the mouse up is over the close button,
- // and the mouse hasn't moved too much, we close the tab.
- if (closeButtonActive &&
- (dx*dx + dy*dy) <= kRapidCloseDist*kRapidCloseDist &&
- [controller inRapidClosureMode]) {
- NSPoint hitLocation =
- [[self superview] convertPoint:[theEvent locationInWindow]
- fromView:nil];
- if ([self hitTest:hitLocation] == closeButton_) {
- [controller closeTab:self];
- break;
- }
- }
-
- [self mouseUp:theEvent];
- break;
- } else {
- // TODO(viettrungluu): [crbug.com/23830] We can receive right-mouse-ups
- // (and maybe even others?) for reasons I don't understand. So we
- // explicitly check for both events we're expecting, and log others. We
- // should figure out what's going on.
- LOG(WARNING) << "Spurious event received of type " << type << ".";
- }
- }
-}
-
-- (void)mouseDragged:(NSEvent*)theEvent {
- // Special-case this to keep the logic below simpler.
- if (moveWindowOnDrag_) {
- if ([sourceController_ windowMovementAllowed]) {
- NSPoint thisPoint = [NSEvent mouseLocation];
- NSPoint origin = sourceWindowFrame_.origin;
- origin.x += (thisPoint.x - dragOrigin_.x);
- origin.y += (thisPoint.y - dragOrigin_.y);
- [sourceWindow_ setFrameOrigin:NSMakePoint(origin.x, origin.y)];
- } // else do nothing.
- return;
- }
-
- // First, go through the magnetic drag cycle. We break out of this if
- // "stretchiness" ever exceeds a set amount.
- tabWasDragged_ = YES;
-
- if (draggingWithinTabStrip_) {
- NSPoint thisPoint = [NSEvent mouseLocation];
- CGFloat stretchiness = thisPoint.y - dragOrigin_.y;
- stretchiness = copysign(sqrtf(fabs(stretchiness))/sqrtf(kTearDistance),
- stretchiness) / 2.0;
- CGFloat offset = thisPoint.x - dragOrigin_.x;
- if (fabsf(offset) > 100) stretchiness = 0;
- [sourceController_ insertPlaceholderForTab:self
- frame:NSOffsetRect(sourceTabFrame_,
- offset, 0)
- yStretchiness:stretchiness];
- // Check that we haven't pulled the tab too far to start a drag. This
- // can include either pulling it too far down, or off the side of the tab
- // strip that would cause it to no longer be fully visible.
- BOOL stillVisible = [sourceController_ isTabFullyVisible:self];
- CGFloat tearForce = fabs(thisPoint.y - dragOrigin_.y);
- if ([sourceController_ tabTearingAllowed] &&
- (tearForce > kTearDistance || !stillVisible)) {
- draggingWithinTabStrip_ = NO;
- // When you finally leave the strip, we treat that as the origin.
- dragOrigin_.x = thisPoint.x;
- } else {
- // Still dragging within the tab strip, wait for the next drag event.
- return;
- }
- }
-
- // Do not start dragging until the user has "torn" the tab off by
- // moving more than 3 pixels.
- NSDate* targetDwellDate = nil; // The date this target was first chosen.
-
- NSPoint thisPoint = [NSEvent mouseLocation];
-
- // Iterate over possible targets checking for the one the mouse is in.
- // If the tab is just in the frame, bring the window forward to make it
- // easier to drop something there. If it's in the tab strip, set the new
- // target so that it pops into that window. We can't cache this because we
- // need the z-order to be correct.
- NSArray* targets = [self dropTargetsForController:draggedController_];
- TabWindowController* newTarget = nil;
- for (TabWindowController* target in targets) {
- NSRect windowFrame = [[target window] frame];
- if (NSPointInRect(thisPoint, windowFrame)) {
- [[target window] orderFront:self];
- NSRect tabStripFrame = [[target tabStripView] frame];
- tabStripFrame.origin = [[target window]
- convertBaseToScreen:tabStripFrame.origin];
- if (NSPointInRect(thisPoint, tabStripFrame)) {
- newTarget = target;
- }
- break;
- }
- }
-
- // If we're now targeting a new window, re-layout the tabs in the old
- // target and reset how long we've been hovering over this new one.
- if (targetController_ != newTarget) {
- targetDwellDate = [NSDate date];
- [targetController_ removePlaceholder];
- targetController_ = newTarget;
- if (!newTarget) {
- tearTime_ = [NSDate timeIntervalSinceReferenceDate];
- tearOrigin_ = [dragWindow_ frame].origin;
- }
- }
-
- // Create or identify the dragged controller.
- if (!draggedController_) {
- // Get rid of any placeholder remaining in the original source window.
- [sourceController_ removePlaceholder];
-
- // Detach from the current window and put it in a new window. If there are
- // no more tabs remaining after detaching, the source window is about to
- // go away (it's been autoreleased) so we need to ensure we don't reference
- // it any more. In that case the new controller becomes our source
- // controller.
- draggedController_ = [sourceController_ detachTabToNewWindow:self];
- dragWindow_ = [draggedController_ window];
- [dragWindow_ setAlphaValue:0.0];
- if (![sourceController_ hasLiveTabs]) {
- sourceController_ = draggedController_;
- sourceWindow_ = dragWindow_;
- }
-
- // If dragging the tab only moves the current window, do not show overlay
- // so that sheets stay on top of the window.
- // Bring the target window to the front and make sure it has a border.
- [dragWindow_ setLevel:NSFloatingWindowLevel];
- [dragWindow_ setHasShadow:YES];
- [dragWindow_ orderFront:nil];
- [dragWindow_ makeMainWindow];
- [draggedController_ showOverlay];
- dragOverlay_ = [draggedController_ overlayWindow];
- // Force the new tab button to be hidden. We'll reset it on mouse up.
- [draggedController_ showNewTabButton:NO];
- tearTime_ = [NSDate timeIntervalSinceReferenceDate];
- tearOrigin_ = sourceWindowFrame_.origin;
- }
-
- // TODO(pinkerton): http://crbug.com/25682 demonstrates a way to get here by
- // some weird circumstance that doesn't first go through mouseDown:. We
- // really shouldn't go any farther.
- if (!draggedController_ || !sourceController_)
- return;
-
- // When the user first tears off the window, we want slide the window to
- // the current mouse location (to reduce the jarring appearance). We do this
- // by calling ourselves back with additional mouseDragged calls (not actual
- // events). |tearProgress| is a normalized measure of how far through this
- // tear "animation" (of length kTearDuration) we are and has values [0..1].
- // We use sqrt() so the animation is non-linear (slow down near the end
- // point).
- NSTimeInterval tearProgress =
- [NSDate timeIntervalSinceReferenceDate] - tearTime_;
- tearProgress /= kTearDuration; // Normalize.
- tearProgress = sqrtf(MAX(MIN(tearProgress, 1.0), 0.0));
-
- // Move the dragged window to the right place on the screen.
- NSPoint origin = sourceWindowFrame_.origin;
- origin.x += (thisPoint.x - dragOrigin_.x);
- origin.y += (thisPoint.y - dragOrigin_.y);
-
- if (tearProgress < 1) {
- // If the tear animation is not complete, call back to ourself with the
- // same event to animate even if the mouse isn't moving. We need to make
- // sure these get cancelled in mouseUp:.
- [NSObject cancelPreviousPerformRequestsWithTarget:self];
- [self performSelector:@selector(mouseDragged:)
- withObject:theEvent
- afterDelay:1.0f/30.0f];
-
- // Set the current window origin based on how far we've progressed through
- // the tear animation.
- origin.x = (1 - tearProgress) * tearOrigin_.x + tearProgress * origin.x;
- origin.y = (1 - tearProgress) * tearOrigin_.y + tearProgress * origin.y;
- }
-
- if (targetController_) {
- // In order to "snap" two windows of different sizes together at their
- // toolbar, we can't just use the origin of the target frame. We also have
- // to take into consideration the difference in height.
- NSRect targetFrame = [[targetController_ window] frame];
- NSRect sourceFrame = [dragWindow_ frame];
- origin.y = NSMinY(targetFrame) +
- (NSHeight(targetFrame) - NSHeight(sourceFrame));
- }
- [dragWindow_ setFrameOrigin:NSMakePoint(origin.x, origin.y)];
-
- // If we're not hovering over any window, make the window fully
- // opaque. Otherwise, find where the tab might be dropped and insert
- // a placeholder so it appears like it's part of that window.
- if (targetController_) {
- if (![[targetController_ window] isKeyWindow]) {
- // && ([targetDwellDate timeIntervalSinceNow] < -REQUIRED_DWELL)) {
- [[targetController_ window] orderFront:nil];
- targetDwellDate = nil;
- }
-
- // Compute where placeholder should go and insert it into the
- // destination tab strip.
- TabView* draggedTabView = (TabView*)[draggedController_ selectedTabView];
- NSRect tabFrame = [draggedTabView frame];
- tabFrame.origin = [dragWindow_ convertBaseToScreen:tabFrame.origin];
- tabFrame.origin = [[targetController_ window]
- convertScreenToBase:tabFrame.origin];
- tabFrame = [[targetController_ tabStripView]
- convertRect:tabFrame fromView:nil];
- [targetController_ insertPlaceholderForTab:self
- frame:tabFrame
- yStretchiness:0];
- [targetController_ layoutTabs];
- } else {
- [dragWindow_ makeKeyAndOrderFront:nil];
- }
-
- // Adjust the visibility of the window background. If there is a drop target,
- // we want to hide the window background so the tab stands out for
- // positioning. If not, we want to show it so it looks like a new window will
- // be realized.
- BOOL chromeShouldBeVisible = targetController_ == nil;
- [self setWindowBackgroundVisibility:chromeShouldBeVisible];
-}
-
-- (void)mouseUp:(NSEvent*)theEvent {
- // The drag/click is done. If the user dragged the mouse, finalize the drag
- // and clean up.
-
- // Special-case this to keep the logic below simpler.
- if (moveWindowOnDrag_)
- return;
-
- // Cancel any delayed -mouseDragged: requests that may still be pending.
- [NSObject cancelPreviousPerformRequestsWithTarget:self];
-
- // TODO(pinkerton): http://crbug.com/25682 demonstrates a way to get here by
- // some weird circumstance that doesn't first go through mouseDown:. We
- // really shouldn't go any farther.
- if (!sourceController_)
- return;
-
- // We are now free to re-display the new tab button in the window we're
- // dragging. It will show when the next call to -layoutTabs (which happens
- // indrectly by several of the calls below, such as removing the placeholder).
- [draggedController_ showNewTabButton:YES];
-
- if (draggingWithinTabStrip_) {
- if (tabWasDragged_) {
- // Move tab to new location.
- DCHECK([sourceController_ numberOfTabs]);
- TabWindowController* dropController = sourceController_;
- [dropController moveTabView:[dropController selectedTabView]
- fromController:nil];
- }
- } else if (targetController_) {
- // Move between windows. If |targetController_| is nil, we're not dropping
- // into any existing window.
- NSView* draggedTabView = [draggedController_ selectedTabView];
- [targetController_ moveTabView:draggedTabView
- fromController:draggedController_];
- // Force redraw to avoid flashes of old content before returning to event
- // loop.
- [[targetController_ window] display];
- [targetController_ showWindow:nil];
- [draggedController_ removeOverlay];
- } else {
- // Only move the window around on screen. Make sure it's set back to
- // normal state (fully opaque, has shadow, has key, etc).
- [draggedController_ removeOverlay];
- // Don't want to re-show the window if it was closed during the drag.
- if ([dragWindow_ isVisible]) {
- [dragWindow_ setAlphaValue:1.0];
- [dragOverlay_ setHasShadow:NO];
- [dragWindow_ setHasShadow:YES];
- [dragWindow_ makeKeyAndOrderFront:nil];
- }
- [[draggedController_ window] setLevel:NSNormalWindowLevel];
- [draggedController_ removePlaceholder];
- }
- [sourceController_ removePlaceholder];
- chromeIsVisible_ = YES;
-
- [self resetDragControllers];
-}
-
-- (void)otherMouseUp:(NSEvent*)theEvent {
- if ([self isClosing])
- return;
-
- // Support middle-click-to-close.
- if ([theEvent buttonNumber] == 2) {
- // |-hitTest:| takes a location in the superview's coordinates.
- NSPoint upLocation =
- [[self superview] convertPoint:[theEvent locationInWindow]
- fromView:nil];
- // If the mouse up occurred in our view or over the close button, then
- // close.
- if ([self hitTest:upLocation])
- [controller_ closeTab:self];
- }
-}
-
-- (void)drawRect:(NSRect)dirtyRect {
- NSGraphicsContext* context = [NSGraphicsContext currentContext];
- [context saveGraphicsState];
-
- BrowserThemeProvider* themeProvider =
- static_cast<BrowserThemeProvider*>([[self window] themeProvider]);
- [context setPatternPhase:[[self window] themePatternPhase]];
-
- NSRect rect = [self bounds];
- NSBezierPath* path = [self bezierPathForRect:rect];
-
- BOOL selected = [self state];
- // Don't draw the window/tab bar background when selected, since the tab
- // background overlay drawn over it (see below) will be fully opaque.
- BOOL hasBackgroundImage = NO;
- if (!selected) {
- // ThemeProvider::HasCustomImage is true only if the theme provides the
- // image. However, even if the theme doesn't provide a tab background, the
- // theme machinery will make one if given a frame image. See
- // BrowserThemePack::GenerateTabBackgroundImages for details.
- hasBackgroundImage = themeProvider &&
- (themeProvider->HasCustomImage(IDR_THEME_TAB_BACKGROUND) ||
- themeProvider->HasCustomImage(IDR_THEME_FRAME));
-
- NSColor* backgroundImageColor = hasBackgroundImage ?
- themeProvider->GetNSImageColorNamed(IDR_THEME_TAB_BACKGROUND, true) :
- nil;
-
- if (backgroundImageColor) {
- [backgroundImageColor set];
- [path fill];
- } else {
- // Use the window's background color rather than |[NSColor
- // windowBackgroundColor]|, which gets confused by the fullscreen window.
- // (The result is the same for normal, non-fullscreen windows.)
- [[[self window] backgroundColor] set];
- [path fill];
- [[NSColor colorWithCalibratedWhite:1.0 alpha:0.3] set];
- [path fill];
- }
- }
-
- [context saveGraphicsState];
- [path addClip];
-
- // Use the same overlay for the selected state and for hover and alert glows;
- // for the selected state, it's fully opaque.
- CGFloat hoverAlpha = [self hoverAlpha];
- CGFloat alertAlpha = [self alertAlpha];
- if (selected || hoverAlpha > 0 || alertAlpha > 0) {
- // Draw the selected background / glow overlay.
- [context saveGraphicsState];
- CGContextRef cgContext = static_cast<CGContextRef>([context graphicsPort]);
- CGContextBeginTransparencyLayer(cgContext, 0);
- if (!selected) {
- // The alert glow overlay is like the selected state but at most at most
- // 80% opaque. The hover glow brings up the overlay's opacity at most 50%.
- CGFloat backgroundAlpha = 0.8 * alertAlpha;
- backgroundAlpha += (1 - backgroundAlpha) * 0.5 * hoverAlpha;
- CGContextSetAlpha(cgContext, backgroundAlpha);
- }
- [path addClip];
- [context saveGraphicsState];
- [super drawBackground];
- [context restoreGraphicsState];
-
- // Draw a mouse hover gradient for the default themes.
- if (!selected && hoverAlpha > 0) {
- if (themeProvider && !hasBackgroundImage) {
- scoped_nsobject<NSGradient> glow([NSGradient alloc]);
- [glow initWithStartingColor:[NSColor colorWithCalibratedWhite:1.0
- alpha:1.0 * hoverAlpha]
- endingColor:[NSColor colorWithCalibratedWhite:1.0
- alpha:0.0]];
-
- NSPoint point = hoverPoint_;
- point.y = NSHeight(rect);
- [glow drawFromCenter:point
- radius:0.0
- toCenter:point
- radius:NSWidth(rect) / 3.0
- options:NSGradientDrawsBeforeStartingLocation];
-
- [glow drawInBezierPath:path relativeCenterPosition:hoverPoint_];
- }
- }
-
- CGContextEndTransparencyLayer(cgContext);
- [context restoreGraphicsState];
- }
-
- BOOL active = [[self window] isKeyWindow] || [[self window] isMainWindow];
- CGFloat borderAlpha = selected ? (active ? 0.3 : 0.2) : 0.2;
- NSColor* borderColor = [NSColor colorWithDeviceWhite:0.0 alpha:borderAlpha];
- NSColor* highlightColor = themeProvider ? themeProvider->GetNSColor(
- themeProvider->UsingDefaultTheme() ?
- BrowserThemeProvider::COLOR_TOOLBAR_BEZEL :
- BrowserThemeProvider::COLOR_TOOLBAR, true) : nil;
-
- // Draw the top inner highlight within the currently selected tab if using
- // the default theme.
- if (selected && themeProvider && themeProvider->UsingDefaultTheme()) {
- NSAffineTransform* highlightTransform = [NSAffineTransform transform];
- [highlightTransform translateXBy:1.0 yBy:-1.0];
- scoped_nsobject<NSBezierPath> highlightPath([path copy]);
- [highlightPath transformUsingAffineTransform:highlightTransform];
- [highlightColor setStroke];
- [highlightPath setLineWidth:1.0];
- [highlightPath stroke];
- highlightTransform = [NSAffineTransform transform];
- [highlightTransform translateXBy:-2.0 yBy:0.0];
- [highlightPath transformUsingAffineTransform:highlightTransform];
- [highlightPath stroke];
- }
-
- [context restoreGraphicsState];
-
- // Draw the top stroke.
- [context saveGraphicsState];
- [borderColor set];
- [path setLineWidth:1.0];
- [path stroke];
- [context restoreGraphicsState];
-
- // Mimic the tab strip's bottom border, which consists of a dark border
- // and light highlight.
- if (!selected) {
- [path addClip];
- NSRect borderRect = rect;
- borderRect.origin.y = 1;
- borderRect.size.height = 1;
- [borderColor set];
- NSRectFillUsingOperation(borderRect, NSCompositeSourceOver);
-
- borderRect.origin.y = 0;
- [highlightColor set];
- NSRectFillUsingOperation(borderRect, NSCompositeSourceOver);
- }
-
- [context restoreGraphicsState];
-}
-
-- (void)viewDidMoveToWindow {
- [super viewDidMoveToWindow];
- if ([self window]) {
- [controller_ updateTitleColor];
- }
-}
-
-- (void)setClosing:(BOOL)closing {
- closing_ = closing; // Safe because the property is nonatomic.
- // When closing, ensure clicks to the close button go nowhere.
- if (closing) {
- [closeButton_ setTarget:nil];
- [closeButton_ setAction:nil];
- }
-}
-
-- (void)startAlert {
- // Do not start a new alert while already alerting or while in a decay cycle.
- if (alertState_ == tabs::kAlertNone) {
- alertState_ = tabs::kAlertRising;
- [self resetLastGlowUpdateTime];
- [self adjustGlowValue];
- }
-}
-
-- (void)cancelAlert {
- if (alertState_ != tabs::kAlertNone) {
- alertState_ = tabs::kAlertFalling;
- alertHoldEndTime_ =
- [NSDate timeIntervalSinceReferenceDate] + kGlowUpdateInterval;
- [self resetLastGlowUpdateTime];
- [self adjustGlowValue];
- }
-}
-
-- (BOOL)accessibilityIsIgnored {
- return NO;
-}
-
-- (NSArray*)accessibilityActionNames {
- NSArray* parentActions = [super accessibilityActionNames];
-
- return [parentActions arrayByAddingObject:NSAccessibilityPressAction];
-}
-
-- (NSArray*)accessibilityAttributeNames {
- NSMutableArray* attributes =
- [[super accessibilityAttributeNames] mutableCopy];
- [attributes addObject:NSAccessibilityTitleAttribute];
- [attributes addObject:NSAccessibilityEnabledAttribute];
-
- return attributes;
-}
-
-- (BOOL)accessibilityIsAttributeSettable:(NSString*)attribute {
- if ([attribute isEqual:NSAccessibilityTitleAttribute])
- return NO;
-
- if ([attribute isEqual:NSAccessibilityEnabledAttribute])
- return NO;
-
- return [super accessibilityIsAttributeSettable:attribute];
-}
-
-- (id)accessibilityAttributeValue:(NSString*)attribute {
- if ([attribute isEqual:NSAccessibilityRoleAttribute])
- return NSAccessibilityButtonRole;
-
- if ([attribute isEqual:NSAccessibilityTitleAttribute])
- return [controller_ title];
-
- if ([attribute isEqual:NSAccessibilityEnabledAttribute])
- return [NSNumber numberWithBool:YES];
-
- if ([attribute isEqual:NSAccessibilityChildrenAttribute]) {
- // The subviews (icon and text) are clutter; filter out everything but
- // useful controls.
- NSArray* children = [super accessibilityAttributeValue:attribute];
- NSMutableArray* okChildren = [NSMutableArray array];
- for (id child in children) {
- if ([child isKindOfClass:[NSButtonCell class]])
- [okChildren addObject:child];
- }
-
- return okChildren;
- }
-
- return [super accessibilityAttributeValue:attribute];
-}
-
-- (ViewID)viewID {
- return VIEW_ID_TAB;
-}
-
-@end // @implementation TabView
-
-@implementation TabView (TabControllerInterface)
-
-- (void)setController:(TabController*)controller {
- controller_ = controller;
-}
-
-@end // @implementation TabView (TabControllerInterface)
-
-@implementation TabView(Private)
-
-- (void)resetLastGlowUpdateTime {
- lastGlowUpdate_ = [NSDate timeIntervalSinceReferenceDate];
-}
-
-- (NSTimeInterval)timeElapsedSinceLastGlowUpdate {
- return [NSDate timeIntervalSinceReferenceDate] - lastGlowUpdate_;
-}
-
-- (void)adjustGlowValue {
- // A time interval long enough to represent no update.
- const NSTimeInterval kNoUpdate = 1000000;
-
- // Time until next update for either glow.
- NSTimeInterval nextUpdate = kNoUpdate;
-
- NSTimeInterval elapsed = [self timeElapsedSinceLastGlowUpdate];
- NSTimeInterval currentTime = [NSDate timeIntervalSinceReferenceDate];
-
- // TODO(viettrungluu): <http://crbug.com/30617> -- split off the stuff below
- // into a pure function and add a unit test.
-
- CGFloat hoverAlpha = [self hoverAlpha];
- if (isMouseInside_) {
- // Increase hover glow until it's 1.
- if (hoverAlpha < 1) {
- hoverAlpha = MIN(hoverAlpha + elapsed / kHoverShowDuration, 1);
- [self setHoverAlpha:hoverAlpha];
- nextUpdate = MIN(kGlowUpdateInterval, nextUpdate);
- } // Else already 1 (no update needed).
- } else {
- if (currentTime >= hoverHoldEndTime_) {
- // No longer holding, so decrease hover glow until it's 0.
- if (hoverAlpha > 0) {
- hoverAlpha = MAX(hoverAlpha - elapsed / kHoverHideDuration, 0);
- [self setHoverAlpha:hoverAlpha];
- nextUpdate = MIN(kGlowUpdateInterval, nextUpdate);
- } // Else already 0 (no update needed).
- } else {
- // Schedule update for end of hold time.
- nextUpdate = MIN(hoverHoldEndTime_ - currentTime, nextUpdate);
- }
- }
-
- CGFloat alertAlpha = [self alertAlpha];
- if (alertState_ == tabs::kAlertRising) {
- // Increase alert glow until it's 1 ...
- alertAlpha = MIN(alertAlpha + elapsed / kAlertShowDuration, 1);
- [self setAlertAlpha:alertAlpha];
-
- // ... and having reached 1, switch to holding.
- if (alertAlpha >= 1) {
- alertState_ = tabs::kAlertHolding;
- alertHoldEndTime_ = currentTime + kAlertHoldDuration;
- nextUpdate = MIN(kAlertHoldDuration, nextUpdate);
- } else {
- nextUpdate = MIN(kGlowUpdateInterval, nextUpdate);
- }
- } else if (alertState_ != tabs::kAlertNone) {
- if (alertAlpha > 0) {
- if (currentTime >= alertHoldEndTime_) {
- // Stop holding, then decrease alert glow (until it's 0).
- if (alertState_ == tabs::kAlertHolding) {
- alertState_ = tabs::kAlertFalling;
- nextUpdate = MIN(kGlowUpdateInterval, nextUpdate);
- } else {
- DCHECK_EQ(tabs::kAlertFalling, alertState_);
- alertAlpha = MAX(alertAlpha - elapsed / kAlertHideDuration, 0);
- [self setAlertAlpha:alertAlpha];
- nextUpdate = MIN(kGlowUpdateInterval, nextUpdate);
- }
- } else {
- // Schedule update for end of hold time.
- nextUpdate = MIN(alertHoldEndTime_ - currentTime, nextUpdate);
- }
- } else {
- // Done the alert decay cycle.
- alertState_ = tabs::kAlertNone;
- }
- }
-
- if (nextUpdate < kNoUpdate)
- [self performSelector:_cmd withObject:nil afterDelay:nextUpdate];
-
- [self resetLastGlowUpdateTime];
- [self setNeedsDisplay:YES];
-}
-
-// Returns the workspace id of |window|. If |useCache|, then lookup
-// and remember the value in |workspaceIDCache_| until the end of the
-// current drag.
-- (int)getWorkspaceID:(NSWindow*)window useCache:(BOOL)useCache {
- CGWindowID windowID = [window windowNumber];
- if (useCache) {
- std::map<CGWindowID, int>::iterator iter =
- workspaceIDCache_.find(windowID);
- if (iter != workspaceIDCache_.end())
- return iter->second;
- }
-
- int workspace = -1;
- // It's possible to query in bulk, but probably not necessary.
- base::mac::ScopedCFTypeRef<CFArrayRef> windowIDs(CFArrayCreate(
- NULL, reinterpret_cast<const void **>(&windowID), 1, NULL));
- base::mac::ScopedCFTypeRef<CFArrayRef> descriptions(
- CGWindowListCreateDescriptionFromArray(windowIDs));
- DCHECK(CFArrayGetCount(descriptions.get()) <= 1);
- if (CFArrayGetCount(descriptions.get()) > 0) {
- CFDictionaryRef dict = static_cast<CFDictionaryRef>(
- CFArrayGetValueAtIndex(descriptions.get(), 0));
- DCHECK(CFGetTypeID(dict) == CFDictionaryGetTypeID());
-
- // Sanity check the ID.
- CFNumberRef otherIDRef = (CFNumberRef)mac_util::GetValueFromDictionary(
- dict, kCGWindowNumber, CFNumberGetTypeID());
- CGWindowID otherID;
- if (otherIDRef &&
- CFNumberGetValue(otherIDRef, kCGWindowIDCFNumberType, &otherID) &&
- otherID == windowID) {
- // And then get the workspace.
- CFNumberRef workspaceRef = (CFNumberRef)mac_util::GetValueFromDictionary(
- dict, kCGWindowWorkspace, CFNumberGetTypeID());
- if (!workspaceRef ||
- !CFNumberGetValue(workspaceRef, kCFNumberIntType, &workspace)) {
- workspace = -1;
- }
- } else {
- NOTREACHED();
- }
- }
- if (useCache) {
- workspaceIDCache_[windowID] = workspace;
- }
- return workspace;
-}
-
-// Returns the bezier path used to draw the tab given the bounds to draw it in.
-- (NSBezierPath*)bezierPathForRect:(NSRect)rect {
- // Outset by 0.5 in order to draw on pixels rather than on borders (which
- // would cause blurry pixels). Subtract 1px of height to compensate, otherwise
- // clipping will occur.
- rect = NSInsetRect(rect, -0.5, -0.5);
- rect.size.height -= 1.0;
-
- NSPoint bottomLeft = NSMakePoint(NSMinX(rect), NSMinY(rect) + 2);
- NSPoint bottomRight = NSMakePoint(NSMaxX(rect), NSMinY(rect) + 2);
- NSPoint topRight =
- NSMakePoint(NSMaxX(rect) - kInsetMultiplier * NSHeight(rect),
- NSMaxY(rect));
- NSPoint topLeft =
- NSMakePoint(NSMinX(rect) + kInsetMultiplier * NSHeight(rect),
- NSMaxY(rect));
-
- CGFloat baseControlPointOutset = NSHeight(rect) * kControlPoint1Multiplier;
- CGFloat bottomControlPointInset = NSHeight(rect) * kControlPoint2Multiplier;
-
- // Outset many of these values by 1 to cause the fill to bleed outside the
- // clip area.
- NSBezierPath* path = [NSBezierPath bezierPath];
- [path moveToPoint:NSMakePoint(bottomLeft.x - 1, bottomLeft.y - 2)];
- [path lineToPoint:NSMakePoint(bottomLeft.x - 1, bottomLeft.y)];
- [path lineToPoint:bottomLeft];
- [path curveToPoint:topLeft
- controlPoint1:NSMakePoint(bottomLeft.x + baseControlPointOutset,
- bottomLeft.y)
- controlPoint2:NSMakePoint(topLeft.x - bottomControlPointInset,
- topLeft.y)];
- [path lineToPoint:topRight];
- [path curveToPoint:bottomRight
- controlPoint1:NSMakePoint(topRight.x + bottomControlPointInset,
- topRight.y)
- controlPoint2:NSMakePoint(bottomRight.x - baseControlPointOutset,
- bottomRight.y)];
- [path lineToPoint:NSMakePoint(bottomRight.x + 1, bottomRight.y)];
- [path lineToPoint:NSMakePoint(bottomRight.x + 1, bottomRight.y - 2)];
- return path;
-}
-
-@end // @implementation TabView(Private)
diff --git a/chrome/browser/cocoa/tab_view_picker_table.h b/chrome/browser/cocoa/tab_view_picker_table.h
deleted file mode 100644
index 75d943f..0000000
--- a/chrome/browser/cocoa/tab_view_picker_table.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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>
-
-#import "base/cocoa_protocols_mac.h"
-#include "base/scoped_nsobject.h"
-
-// TabViewPickerTable is an NSOutlineView that can be used to switch between the
-// NSTabViewItems of an NSTabView. To use this, just create a
-// TabViewPickerTable in Interface Builder and connect the |tabView_| outlet
-// to an NSTabView. Now the table is automatically populated with the tab labels
-// of the tab view, clicking the table updates the tab view, and switching
-// tab view items updates the selection of the table.
-@interface TabViewPickerTable : NSOutlineView <NSTabViewDelegate,
- NSOutlineViewDelegate,
- NSOutlineViewDataSource> {
- @public
- IBOutlet NSTabView* tabView_; // Visible for testing.
-
- @private
- id oldTabViewDelegate_;
-
- // Shown above all the tab names. May be |nil|.
- scoped_nsobject<NSString> heading_;
-}
-@property (nonatomic, copy) NSString* heading;
-@end
diff --git a/chrome/browser/cocoa/tab_view_picker_table_unittest.mm b/chrome/browser/cocoa/tab_view_picker_table_unittest.mm
deleted file mode 100644
index 3055844..0000000
--- a/chrome/browser/cocoa/tab_view_picker_table_unittest.mm
+++ /dev/null
@@ -1,138 +0,0 @@
-// 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>
-
-#import "chrome/browser/cocoa/tab_view_picker_table.h"
-
-#import "base/cocoa_protocols_mac.h"
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-@interface TabViewPickerTableTestPing : NSObject <NSTabViewDelegate> {
- @public
- BOOL didSelectItemCalled_;
-}
-@end
-
-@implementation TabViewPickerTableTestPing
-- (void) tabView:(NSTabView*)tabView
- didSelectTabViewItem:(NSTabViewItem*)tabViewItem {
- didSelectItemCalled_ = YES;
-}
-@end
-
-namespace {
-
-class TabViewPickerTableTest : public CocoaTest {
- public:
- TabViewPickerTableTest() {
- // Initialize picker table.
- NSRect frame = NSMakeRect(0, 0, 30, 50);
- scoped_nsobject<TabViewPickerTable> view(
- [[TabViewPickerTable alloc] initWithFrame:frame]);
- view_ = view.get();
- [view_ setAllowsEmptySelection:NO];
- [view_ setAllowsMultipleSelection:NO];
- [view_ addTableColumn:
- [[[NSTableColumn alloc] initWithIdentifier:nil] autorelease]];
- [[test_window() contentView] addSubview:view_];
-
- // Initialize source tab view, with delegate.
- frame = NSMakeRect(30, 0, 50, 50);
- scoped_nsobject<NSTabView> tabView(
- [[NSTabView alloc] initWithFrame:frame]);
- tabView_ = tabView.get();
-
- scoped_nsobject<NSTabViewItem> item1(
- [[NSTabViewItem alloc] initWithIdentifier:nil]);
- [item1 setLabel:@"label 1"];
- [tabView_ addTabViewItem:item1];
-
- scoped_nsobject<NSTabViewItem> item2(
- [[NSTabViewItem alloc] initWithIdentifier:nil]);
- [item2 setLabel:@"label 2"];
- [tabView_ addTabViewItem:item2];
-
- [tabView_ selectTabViewItemAtIndex:1];
- [[test_window() contentView] addSubview:tabView_];
-
- ping_.reset([TabViewPickerTableTestPing new]);
- [tabView_ setDelegate:ping_.get()];
-
- // Simulate nib loading.
- view_->tabView_ = tabView_;
- [view_ awakeFromNib];
- }
-
- TabViewPickerTable* view_;
- NSTabView* tabView_;
- scoped_nsobject<TabViewPickerTableTestPing> ping_;
-};
-
-TEST_VIEW(TabViewPickerTableTest, view_)
-
-TEST_F(TabViewPickerTableTest, TestInitialSelectionCorrect) {
- EXPECT_EQ(1, [view_ selectedRow]);
-}
-
-TEST_F(TabViewPickerTableTest, TestSelectionUpdates) {
- [tabView_ selectTabViewItemAtIndex:0];
- EXPECT_EQ(0, [view_ selectedRow]);
-
- [tabView_ selectTabViewItemAtIndex:1];
- EXPECT_EQ(1, [view_ selectedRow]);
-}
-
-TEST_F(TabViewPickerTableTest, TestDelegateStillWorks) {
- EXPECT_FALSE(ping_.get()->didSelectItemCalled_);
- [tabView_ selectTabViewItemAtIndex:0];
- EXPECT_TRUE(ping_.get()->didSelectItemCalled_);
-}
-
-TEST_F(TabViewPickerTableTest, RowsCorrect) {
- EXPECT_EQ(2, [view_ numberOfRows]);
- EXPECT_EQ(2,
- [[view_ dataSource] outlineView:view_ numberOfChildrenOfItem:nil]);
-
- id item;
- item = [[view_ dataSource] outlineView:view_ child:0 ofItem:nil];
- EXPECT_NSEQ(@"label 1",
- [[view_ dataSource] outlineView:view_
- objectValueForTableColumn:nil // ignored
- byItem:item]);
- item = [[view_ dataSource] outlineView:view_ child:1 ofItem:nil];
- EXPECT_NSEQ(@"label 2",
- [[view_ dataSource] outlineView:view_
- objectValueForTableColumn:nil // ignored
- byItem:item]);
-}
-
-TEST_F(TabViewPickerTableTest, TestListUpdatesTabView) {
- [view_ selectRowIndexes:[NSIndexSet indexSetWithIndex:0]
- byExtendingSelection:NO];
- EXPECT_EQ(0, [view_ selectedRow]); // sanity
- EXPECT_EQ(0, [tabView_ indexOfTabViewItem:[tabView_ selectedTabViewItem]]);
-}
-
-TEST_F(TabViewPickerTableTest, TestWithHeadingNotEmpty) {
- [view_ setHeading:@"disregard this"];
-
- EXPECT_EQ(2, [view_ selectedRow]);
-
- [tabView_ selectTabViewItemAtIndex:0];
- EXPECT_EQ(1, [view_ selectedRow]);
- [tabView_ selectTabViewItemAtIndex:1];
- EXPECT_EQ(2, [view_ selectedRow]);
-
- [view_ selectRowIndexes:[NSIndexSet indexSetWithIndex:1]
- byExtendingSelection:NO];
- EXPECT_EQ(1, [view_ selectedRow]); // sanity
- EXPECT_EQ(0, [tabView_ indexOfTabViewItem:[tabView_ selectedTabViewItem]]);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/tab_view_unittest.mm b/chrome/browser/cocoa/tab_view_unittest.mm
deleted file mode 100644
index 99ad415..0000000
--- a/chrome/browser/cocoa/tab_view_unittest.mm
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright (c) 2009 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 "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/tab_view.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-namespace {
-
-class TabViewTest : public CocoaTest {
- public:
- TabViewTest() {
- NSRect frame = NSMakeRect(0, 0, 50, 30);
- scoped_nsobject<TabView> view([[TabView alloc] initWithFrame:frame]);
- view_ = view.get();
- [[test_window() contentView] addSubview:view_];
- }
-
- TabView* view_;
-};
-
-TEST_VIEW(TabViewTest, view_)
-
-// Test drawing, mostly to ensure nothing leaks or crashes.
-TEST_F(TabViewTest, Display) {
- for (int i = 0; i < 5; i++) {
- for (int j = 0; j < 5; j++) {
- [view_ setHoverAlpha:i*0.2];
- [view_ setAlertAlpha:j*0.2];
- [view_ display];
- }
- }
-}
-
-// Test it doesn't crash when asked for its menu with no TabController set.
-TEST_F(TabViewTest, Menu) {
- EXPECT_FALSE([view_ menu]);
-}
-
-TEST_F(TabViewTest, Glow) {
- // TODO(viettrungluu): Figure out how to test this, which is timing-sensitive
- // and which moreover uses |-performSelector:withObject:afterDelay:|.
-
- // Call |-startAlert|/|-cancelAlert| and make sure it doesn't crash.
- for (int i = 0; i < 5; i++) {
- [view_ startAlert];
- [view_ cancelAlert];
- }
- [view_ startAlert];
- [view_ startAlert];
- [view_ cancelAlert];
- [view_ cancelAlert];
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/tab_window_controller.h b/chrome/browser/cocoa/tab_window_controller.h
deleted file mode 100644
index b501548..0000000
--- a/chrome/browser/cocoa/tab_window_controller.h
+++ /dev/null
@@ -1,177 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_TAB_WINDOW_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_TAB_WINDOW_CONTROLLER_H_
-#pragma once
-
-// A class acting as the Objective-C window controller for a window that has
-// tabs which can be dragged around. Tabs can be re-arranged within the same
-// window or dragged into other TabWindowController windows. This class doesn't
-// know anything about the actual tab implementation or model, as that is fairly
-// application-specific. It only provides an API to be overridden by subclasses
-// to fill in the details.
-//
-// This assumes that there will be a view in the nib, connected to
-// |tabContentArea_|, that indicates the content that it switched when switching
-// between tabs. It needs to be a regular NSView, not something like an NSBox
-// because the TabStripController makes certain assumptions about how it can
-// swap out subviews.
-//
-// The tab strip can exist in different orientations and window locations,
-// depending on the return value of -usesVerticalTabs. If NO (the default),
-// the tab strip is placed outside the window's content area, overlapping the
-// title area and window controls and will be stretched to fill the width
-// of the window. If YES, the tab strip is vertical and lives within the
-// window's content area. It will be stretched to fill the window's height.
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/cocoa_protocols_mac.h"
-#include "base/scoped_nsobject.h"
-
-@class FastResizeView;
-@class FocusTracker;
-@class TabStripView;
-@class TabView;
-
-@interface TabWindowController : NSWindowController<NSWindowDelegate> {
- @private
- IBOutlet FastResizeView* tabContentArea_;
- // TODO(pinkerton): Figure out a better way to initialize one or the other
- // w/out needing both to be in the nib.
- IBOutlet TabStripView* topTabStripView_;
- IBOutlet TabStripView* sideTabStripView_;
- NSWindow* overlayWindow_; // Used during dragging for window opacity tricks
- NSView* cachedContentView_; // Used during dragging for identifying which
- // view is the proper content area in the overlay
- // (weak)
- scoped_nsobject<FocusTracker> focusBeforeOverlay_;
- scoped_nsobject<NSMutableSet> lockedTabs_;
- BOOL closeDeferred_; // If YES, call performClose: in removeOverlay:.
- // Difference between height of window content area and height of the
- // |tabContentArea_|. Calculated when the window is loaded from the nib and
- // cached in order to restore the delta when switching tab modes.
- CGFloat contentAreaHeightDelta_;
-}
-@property(readonly, nonatomic) TabStripView* tabStripView;
-@property(readonly, nonatomic) FastResizeView* tabContentArea;
-
-// Used during tab dragging to turn on/off the overlay window when a tab
-// is torn off. If -deferPerformClose (below) is used, -removeOverlay will
-// cause the controller to be autoreleased before returning.
-- (void)showOverlay;
-- (void)removeOverlay;
-- (NSWindow*)overlayWindow;
-
-// Returns YES if it is ok to constrain the window's frame to fit the screen.
-- (BOOL)shouldConstrainFrameRect;
-
-// A collection of methods, stubbed out in this base class, that provide
-// the implementation of tab dragging based on whatever model is most
-// appropriate.
-
-// Layout the tabs based on the current ordering of the model.
-- (void)layoutTabs;
-
-// Creates a new window by pulling the given tab out and placing it in
-// the new window. Returns the controller for the new window. The size of the
-// new window will be the same size as this window.
-- (TabWindowController*)detachTabToNewWindow:(TabView*)tabView;
-
-// Make room in the tab strip for |tab| at the given x coordinate. Will hide the
-// new tab button while there's a placeholder. Subclasses need to call the
-// superclass implementation.
-- (void)insertPlaceholderForTab:(TabView*)tab
- frame:(NSRect)frame
- yStretchiness:(CGFloat)yStretchiness;
-
-// Removes the placeholder installed by |-insertPlaceholderForTab:atLocation:|
-// and restores the new tab button. Subclasses need to call the superclass
-// implementation.
-- (void)removePlaceholder;
-
-// The follow return YES if tab dragging/tab tearing (off the tab strip)/window
-// movement is currently allowed. Any number of things can choose to disable it,
-// such as pending animations. The default implementations always return YES.
-// Subclasses should override as appropriate.
-- (BOOL)tabDraggingAllowed;
-- (BOOL)tabTearingAllowed;
-- (BOOL)windowMovementAllowed;
-
-// Show or hide the new tab button. The button is hidden immediately, but
-// waits until the next call to |-layoutTabs| to show it again.
-- (void)showNewTabButton:(BOOL)show;
-
-// Returns whether or not |tab| can still be fully seen in the tab strip or if
-// its current position would cause it be obscured by things such as the edge
-// of the window or the window decorations. Returns YES only if the entire tab
-// is visible. The default implementation always returns YES.
-- (BOOL)isTabFullyVisible:(TabView*)tab;
-
-// Called to check if the receiver can receive dragged tabs from
-// source. Return YES if so. The default implementation returns NO.
-- (BOOL)canReceiveFrom:(TabWindowController*)source;
-
-// Move a given tab view to the location of the current placeholder. If there is
-// no placeholder, it will go at the end. |controller| is the window controller
-// of a tab being dropped from a different window. It will be nil if the drag is
-// within the window, otherwise the tab is removed from that window before being
-// placed into this one. The implementation will call |-removePlaceholder| since
-// the drag is now complete. This also calls |-layoutTabs| internally so
-// clients do not need to call it again.
-- (void)moveTabView:(NSView*)view
- fromController:(TabWindowController*)controller;
-
-// Number of tabs in the tab strip. Useful, for example, to know if we're
-// dragging the only tab in the window. This includes pinned tabs (both live
-// and not).
-- (NSInteger)numberOfTabs;
-
-// YES if there are tabs in the tab strip which have content, allowing for
-// the notion of tabs in the tab strip that are placeholders but currently have
-// no content.
-- (BOOL)hasLiveTabs;
-
-// Return the view of the selected tab.
-- (NSView *)selectedTabView;
-
-// The title of the selected tab.
-- (NSString*)selectedTabTitle;
-
-// Called to check whether or not this controller's window has a tab strip (YES
-// if it does, NO otherwise). The default implementation returns YES.
-- (BOOL)hasTabStrip;
-
-// Returns YES if the tab strip lives in the window content area alongside the
-// tab contents. Returns NO if the tab strip is outside the window content
-// area, along the top of the window.
-- (BOOL)useVerticalTabs;
-
-// Get/set whether a particular tab is draggable between windows.
-- (BOOL)isTabDraggable:(NSView*)tabView;
-- (void)setTab:(NSView*)tabView isDraggable:(BOOL)draggable;
-
-// Tell the window that it needs to call performClose: as soon as the current
-// drag is complete. This prevents a window (and its overlay) from going away
-// during a drag.
-- (void)deferPerformClose;
-
-@end
-
-@interface TabWindowController(ProtectedMethods)
-// Tells the tab strip to forget about this tab in preparation for it being
-// put into a different tab strip, such as during a drop on another window.
-- (void)detachTabView:(NSView*)view;
-
-// Toggles from one display mode of the tab strip to another. Will automatically
-// call -layoutSubviews to reposition other content.
-- (void)toggleTabStripDisplayMode;
-
-// Called when the size of the window content area has changed. Override to
-// position specific views. Base class implementation does nothing.
-- (void)layoutSubviews;
-@end
-
-#endif // CHROME_BROWSER_COCOA_TAB_WINDOW_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/tab_window_controller.mm b/chrome/browser/cocoa/tab_window_controller.mm
deleted file mode 100644
index 4e886eb..0000000
--- a/chrome/browser/cocoa/tab_window_controller.mm
+++ /dev/null
@@ -1,351 +0,0 @@
-// 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 "chrome/browser/cocoa/tab_window_controller.h"
-
-#include "app/theme_provider.h"
-#include "base/logging.h"
-#import "chrome/browser/cocoa/focus_tracker.h"
-#import "chrome/browser/cocoa/tab_strip_view.h"
-#import "chrome/browser/cocoa/themed_window.h"
-
-@interface TabWindowController(PRIVATE)
-- (void)setUseOverlay:(BOOL)useOverlay;
-@end
-
-@interface TabWindowOverlayWindow : NSWindow
-@end
-
-@implementation TabWindowOverlayWindow
-
-- (ThemeProvider*)themeProvider {
- if ([self parentWindow])
- return [[[self parentWindow] windowController] themeProvider];
- return NULL;
-}
-
-- (ThemedWindowStyle)themedWindowStyle {
- if ([self parentWindow])
- return [[[self parentWindow] windowController] themedWindowStyle];
- return NO;
-}
-
-- (NSPoint)themePatternPhase {
- if ([self parentWindow])
- return [[[self parentWindow] windowController] themePatternPhase];
- return NSZeroPoint;
-}
-
-@end
-
-@implementation TabWindowController
-@synthesize tabContentArea = tabContentArea_;
-
-- (id)initWithWindow:(NSWindow*)window {
- if ((self = [super initWithWindow:window]) != nil) {
- lockedTabs_.reset([[NSMutableSet alloc] initWithCapacity:10]);
- }
- return self;
-}
-
-// Add the side tab strip to the left side of the window's content area,
-// making it fill the full height of the content area.
-- (void)addSideTabStripToWindow {
- NSView* contentView = [[self window] contentView];
- NSRect contentFrame = [contentView frame];
- NSRect sideStripFrame =
- NSMakeRect(0, 0,
- NSWidth([sideTabStripView_ frame]),
- NSHeight(contentFrame));
- [sideTabStripView_ setFrame:sideStripFrame];
- [contentView addSubview:sideTabStripView_];
-}
-
-// Add the top tab strop to the window, above the content box and add it to the
-// view hierarchy as a sibling of the content view so it can overlap with the
-// window frame.
-- (void)addTopTabStripToWindow {
- NSRect contentFrame = [tabContentArea_ frame];
- NSRect tabFrame =
- NSMakeRect(0, NSMaxY(contentFrame),
- NSWidth(contentFrame),
- NSHeight([topTabStripView_ frame]));
- [topTabStripView_ setFrame:tabFrame];
- NSView* contentParent = [[[self window] contentView] superview];
- [contentParent addSubview:topTabStripView_];
-}
-
-- (void)windowDidLoad {
- // Cache the difference in height between the window content area and the
- // tab content area.
- NSRect tabFrame = [tabContentArea_ frame];
- NSRect contentFrame = [[[self window] contentView] frame];
- contentAreaHeightDelta_ = NSHeight(contentFrame) - NSHeight(tabFrame);
-
- if ([self hasTabStrip]) {
- if ([self useVerticalTabs]) {
- // No top tabstrip so remove the tabContentArea offset.
- tabFrame.size.height = contentFrame.size.height;
- [tabContentArea_ setFrame:tabFrame];
- [self addSideTabStripToWindow];
- } else {
- [self addTopTabStripToWindow];
- }
- } else {
- // No top tabstrip so remove the tabContentArea offset.
- tabFrame.size.height = contentFrame.size.height;
- [tabContentArea_ setFrame:tabFrame];
- }
-}
-
-// Toggles from one display mode of the tab strip to another. Will automatically
-// call -layoutSubviews to reposition other content.
-- (void)toggleTabStripDisplayMode {
- // Adjust the size of the tab contents to either use more or less space,
- // depending on the direction of the toggle. This needs to be done prior to
- // adding back in the top tab strip as its position is based off the MaxY
- // of the tab content area.
- BOOL useVertical = [self useVerticalTabs];
- NSRect tabContentsFrame = [tabContentArea_ frame];
- tabContentsFrame.size.height += useVertical ?
- contentAreaHeightDelta_ : -contentAreaHeightDelta_;
- [tabContentArea_ setFrame:tabContentsFrame];
-
- if (useVertical) {
- // Remove the top tab strip and add the sidebar in.
- [topTabStripView_ removeFromSuperview];
- [self addSideTabStripToWindow];
- } else {
- // Remove the side tab strip and add the top tab strip as a sibling of the
- // window's content area.
- [sideTabStripView_ removeFromSuperview];
- NSRect tabContentsFrame = [tabContentArea_ frame];
- tabContentsFrame.size.height -= contentAreaHeightDelta_;
- [tabContentArea_ setFrame:tabContentsFrame];
- [self addTopTabStripToWindow];
- }
-
- [self layoutSubviews];
-}
-
-// Return the appropriate tab strip based on whether or not side tabs are
-// enabled.
-- (TabStripView*)tabStripView {
- if ([self useVerticalTabs])
- return sideTabStripView_;
- return topTabStripView_;
-}
-
-- (void)removeOverlay {
- [self setUseOverlay:NO];
- if (closeDeferred_) {
- // See comment in BrowserWindowCocoa::Close() about orderOut:.
- [[self window] orderOut:self];
- [[self window] performClose:self]; // Autoreleases the controller.
- }
-}
-
-- (void)showOverlay {
- [self setUseOverlay:YES];
-}
-
-// if |useOverlay| is true, we're moving views into the overlay's content
-// area. If false, we're moving out of the overlay back into the window's
-// content.
-- (void)moveViewsBetweenWindowAndOverlay:(BOOL)useOverlay {
- if (useOverlay) {
- [[[overlayWindow_ contentView] superview] addSubview:[self tabStripView]];
- // Add the original window's content view as a subview of the overlay
- // window's content view. We cannot simply use setContentView: here because
- // the overlay window has a different content size (due to it being
- // borderless).
- [[overlayWindow_ contentView] addSubview:cachedContentView_];
- } else {
- [[self window] setContentView:cachedContentView_];
- // The TabStripView always needs to be in front of the window's content
- // view and therefore it should always be added after the content view is
- // set.
- [[[[self window] contentView] superview] addSubview:[self tabStripView]];
- [[[[self window] contentView] superview] updateTrackingAreas];
- }
-}
-
-// If |useOverlay| is YES, creates a new overlay window and puts the tab strip
-// and the content area inside of it. This allows it to have a different opacity
-// from the title bar. If NO, returns everything to the previous state and
-// destroys the overlay window until it's needed again. The tab strip and window
-// contents are returned to the original window.
-- (void)setUseOverlay:(BOOL)useOverlay {
- [NSObject cancelPreviousPerformRequestsWithTarget:self
- selector:@selector(removeOverlay)
- object:nil];
- NSWindow* window = [self window];
- if (useOverlay && !overlayWindow_) {
- DCHECK(!cachedContentView_);
- overlayWindow_ = [[TabWindowOverlayWindow alloc]
- initWithContentRect:[window frame]
- styleMask:NSBorderlessWindowMask
- backing:NSBackingStoreBuffered
- defer:YES];
- [overlayWindow_ setTitle:@"overlay"];
- [overlayWindow_ setBackgroundColor:[NSColor clearColor]];
- [overlayWindow_ setOpaque:NO];
- [overlayWindow_ setDelegate:self];
- cachedContentView_ = [window contentView];
- [window addChildWindow:overlayWindow_ ordered:NSWindowAbove];
- // Sets explictly nil to the responder and then restores it.
- // Leaving the first responder non-null here
- // causes [RenderWidgethostViewCocoa resignFirstResponder] and
- // following RenderWidgetHost::Blur(), which results unexpected
- // focus lost.
- focusBeforeOverlay_.reset([[FocusTracker alloc] initWithWindow:window]);
- [window makeFirstResponder:nil];
- [self moveViewsBetweenWindowAndOverlay:useOverlay];
- [overlayWindow_ orderFront:nil];
- } else if (!useOverlay && overlayWindow_) {
- DCHECK(cachedContentView_);
- [window setContentView:cachedContentView_];
- [self moveViewsBetweenWindowAndOverlay:useOverlay];
- [focusBeforeOverlay_ restoreFocusInWindow:window];
- focusBeforeOverlay_.reset(nil);
- [window display];
- [window removeChildWindow:overlayWindow_];
- [overlayWindow_ orderOut:nil];
- [overlayWindow_ release];
- overlayWindow_ = nil;
- cachedContentView_ = nil;
- } else {
- NOTREACHED();
- }
-}
-
-- (NSWindow*)overlayWindow {
- return overlayWindow_;
-}
-
-- (BOOL)shouldConstrainFrameRect {
- // If we currently have an overlay window, do not attempt to change the
- // window's size, as our overlay window doesn't know how to resize properly.
- return overlayWindow_ == nil;
-}
-
-- (BOOL)canReceiveFrom:(TabWindowController*)source {
- // subclass must implement
- NOTIMPLEMENTED();
- return NO;
-}
-
-- (void)moveTabView:(NSView*)view
- fromController:(TabWindowController*)dragController {
- NOTIMPLEMENTED();
-}
-
-- (NSView*)selectedTabView {
- NOTIMPLEMENTED();
- return nil;
-}
-
-- (void)layoutTabs {
- // subclass must implement
- NOTIMPLEMENTED();
-}
-
-- (TabWindowController*)detachTabToNewWindow:(TabView*)tabView {
- // subclass must implement
- NOTIMPLEMENTED();
- return NULL;
-}
-
-- (void)insertPlaceholderForTab:(TabView*)tab
- frame:(NSRect)frame
- yStretchiness:(CGFloat)yStretchiness {
- [self showNewTabButton:NO];
-}
-
-- (void)removePlaceholder {
- [self showNewTabButton:YES];
-}
-
-- (BOOL)tabDraggingAllowed {
- return YES;
-}
-
-- (BOOL)tabTearingAllowed {
- return YES;
-}
-
-- (BOOL)windowMovementAllowed {
- return YES;
-}
-
-- (BOOL)isTabFullyVisible:(TabView*)tab {
- // Subclasses should implement this, but it's not necessary.
- return YES;
-}
-
-- (void)showNewTabButton:(BOOL)show {
- // subclass must implement
- NOTIMPLEMENTED();
-}
-
-- (void)detachTabView:(NSView*)view {
- // subclass must implement
- NOTIMPLEMENTED();
-}
-
-- (NSInteger)numberOfTabs {
- // subclass must implement
- NOTIMPLEMENTED();
- return 0;
-}
-
-- (BOOL)hasLiveTabs {
- // subclass must implement
- NOTIMPLEMENTED();
- return NO;
-}
-
-- (NSString*)selectedTabTitle {
- // subclass must implement
- NOTIMPLEMENTED();
- return @"";
-}
-
-- (BOOL)hasTabStrip {
- // Subclasses should implement this.
- NOTIMPLEMENTED();
- return YES;
-}
-
-- (BOOL)useVerticalTabs {
- // Subclasses should implement this.
- NOTIMPLEMENTED();
- return NO;
-}
-
-- (BOOL)isTabDraggable:(NSView*)tabView {
- return ![lockedTabs_ containsObject:tabView];
-}
-
-- (void)setTab:(NSView*)tabView isDraggable:(BOOL)draggable {
- if (draggable)
- [lockedTabs_ removeObject:tabView];
- else
- [lockedTabs_ addObject:tabView];
-}
-
-// Tell the window that it needs to call performClose: as soon as the current
-// drag is complete. This prevents a window (and its overlay) from going away
-// during a drag.
-- (void)deferPerformClose {
- closeDeferred_ = YES;
-}
-
-// Called when the size of the window content area has changed. Override to
-// position specific views. Base class implementation does nothing.
-- (void)layoutSubviews {
- NOTIMPLEMENTED();
-}
-
-@end
diff --git a/chrome/browser/cocoa/table_model_array_controller.h b/chrome/browser/cocoa/table_model_array_controller.h
deleted file mode 100644
index a357986..0000000
--- a/chrome/browser/cocoa/table_model_array_controller.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_TABLE_MODEL_ARRAY_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_TABLE_MODEL_ARRAY_CONTROLLER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "app/table_model_observer.h"
-#include "base/cocoa_protocols_mac.h"
-#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-
-class RemoveRowsObserverBridge;
-class RemoveRowsTableModel;
-@class TableModelArrayController;
-
-// This class functions as an adapter from a RemoveRowsTableModel to a Cocoa
-// NSArrayController, to be used with bindings.
-// It maps the CanRemoveRows method to its canRemove property, and exposes
-// RemoveRows and RemoveAll as actions (remove: and removeAll:).
-// If the table model has groups, these are inserted into the list of arranged
-// objects as group rows.
-// The designated initializer is the same as for NSArrayController,
-// initWithContent:, but usually this class is instantiated from a nib file.
-// Clicking on a group row selects all rows belonging to that group, like it
-// does in a Windows table_view.
-// In order to show group rows, this class must be the delegate of the
-// NSTableView.
-@interface TableModelArrayController : NSArrayController<NSTableViewDelegate> {
- @private
- RemoveRowsTableModel* model_; // weak
- scoped_ptr<RemoveRowsObserverBridge> tableObserver_;
- scoped_nsobject<NSDictionary> columns_;
- scoped_nsobject<NSString> groupTitle_;
-}
-
-// Bind this controller to the given model.
-// |columns| is a dictionary mapping table column bindings to NSNumbers
-// containing the column identifier in the TableModel.
-// |groupTitleColumn| is the column in the table that should display the group
-// title for a group row, usually the first column. If the model doesn't have
-// groups, it can be nil.
-- (void)bindToTableModel:(RemoveRowsTableModel*)model
- withColumns:(NSDictionary*)columns
- groupTitleColumn:(NSString*)groupTitleColumn;
-
-- (IBAction)removeAll:(id)sender;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_TABLE_MODEL_ARRAY_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/table_model_array_controller.mm b/chrome/browser/cocoa/table_model_array_controller.mm
deleted file mode 100644
index fa2e570..0000000
--- a/chrome/browser/cocoa/table_model_array_controller.mm
+++ /dev/null
@@ -1,246 +0,0 @@
-// 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 "chrome/browser/cocoa/table_model_array_controller.h"
-
-#include "app/table_model.h"
-#include "base/logging.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/remove_rows_table_model.h"
-
-@interface TableModelArrayController (PrivateMethods)
-
-- (NSUInteger)offsetForGroupID:(int)groupID;
-- (NSUInteger)offsetForGroupID:(int)groupID startingOffset:(NSUInteger)offset;
-- (NSIndexSet*)controllerRowsForModelRowsInRange:(NSRange)range;
-- (void)setModelRows:(RemoveRowsTableModel::Rows*)modelRows
- fromControllerRows:(NSIndexSet*)rows;
-- (void)modelDidChange;
-- (void)modelDidAddItemsInRange:(NSRange)range;
-- (void)modelDidRemoveItemsInRange:(NSRange)range;
-- (NSDictionary*)columnValuesForRow:(NSInteger)row;
-
-@end
-
-// Observer for a RemoveRowsTableModel.
-class RemoveRowsObserverBridge : public TableModelObserver {
- public:
- RemoveRowsObserverBridge(TableModelArrayController* controller)
- : controller_(controller) {}
- virtual ~RemoveRowsObserverBridge() {}
-
- // TableModelObserver methods
- virtual void OnModelChanged();
- virtual void OnItemsChanged(int start, int length);
- virtual void OnItemsAdded(int start, int length);
- virtual void OnItemsRemoved(int start, int length);
-
- private:
- TableModelArrayController* controller_; // weak
-};
-
-void RemoveRowsObserverBridge::OnModelChanged() {
- [controller_ modelDidChange];
-}
-
-void RemoveRowsObserverBridge::OnItemsChanged(int start, int length) {
- OnItemsRemoved(start, length);
- OnItemsAdded(start, length);
-}
-
-void RemoveRowsObserverBridge::OnItemsAdded(int start, int length) {
- [controller_ modelDidAddItemsInRange:NSMakeRange(start, length)];
-}
-
-void RemoveRowsObserverBridge::OnItemsRemoved(int start, int length) {
- [controller_ modelDidRemoveItemsInRange:NSMakeRange(start, length)];
-}
-
-@implementation TableModelArrayController
-
-static NSString* const kIsGroupRow = @"_is_group_row";
-static NSString* const kGroupID = @"_group_id";
-
-- (void)bindToTableModel:(RemoveRowsTableModel*)model
- withColumns:(NSDictionary*)columns
- groupTitleColumn:(NSString*)groupTitleColumn {
- model_ = model;
- tableObserver_.reset(new RemoveRowsObserverBridge(self));
- columns_.reset([columns copy]);
- groupTitle_.reset([groupTitleColumn copy]);
- model_->SetObserver(tableObserver_.get());
- [self modelDidChange];
-}
-
-- (void)modelDidChange {
- NSIndexSet* indexes = [NSIndexSet indexSetWithIndexesInRange:
- NSMakeRange(0, [[self arrangedObjects] count])];
- [self removeObjectsAtArrangedObjectIndexes:indexes];
- if (model_->HasGroups()) {
- const TableModel::Groups& groups = model_->GetGroups();
- DCHECK(groupTitle_.get());
- for (TableModel::Groups::const_iterator it = groups.begin();
- it != groups.end(); ++it) {
- NSDictionary* group = [NSDictionary dictionaryWithObjectsAndKeys:
- base::SysWideToNSString(it->title), groupTitle_.get(),
- [NSNumber numberWithBool:YES], kIsGroupRow,
- nil];
- [self addObject:group];
- }
- }
- [self modelDidAddItemsInRange:NSMakeRange(0, model_->RowCount())];
-}
-
-- (NSUInteger)offsetForGroupID:(int)groupID startingOffset:(NSUInteger)offset {
- const TableModel::Groups& groups = model_->GetGroups();
- DCHECK_GT(offset, 0u);
- for (NSUInteger i = offset - 1; i < groups.size(); ++i) {
- if (groups[i].id == groupID)
- return i + 1;
- }
- NOTREACHED();
- return NSNotFound;
-}
-
-- (NSUInteger)offsetForGroupID:(int)groupID {
- return [self offsetForGroupID:groupID startingOffset:1];
-}
-
-- (int)groupIDForControllerRow:(NSUInteger)row {
- NSDictionary* values = [[self arrangedObjects] objectAtIndex:row];
- return [[values objectForKey:kGroupID] intValue];
-}
-
-- (void)setModelRows:(RemoveRowsTableModel::Rows*)modelRows
- fromControllerRows:(NSIndexSet*)rows {
- if ([rows count] == 0)
- return;
-
- if (!model_->HasGroups()) {
- for (NSUInteger i = [rows firstIndex];
- i != NSNotFound;
- i = [rows indexGreaterThanIndex:i]) {
- modelRows->insert(i);
- }
- return;
- }
-
- NSUInteger offset = 1;
- for (NSUInteger i = [rows firstIndex];
- i != NSNotFound;
- i = [rows indexGreaterThanIndex:i]) {
- int group = [self groupIDForControllerRow:i];
- offset = [self offsetForGroupID:group startingOffset:offset];
- modelRows->insert(i - offset);
- }
-}
-
-- (NSIndexSet*)controllerRowsForModelRowsInRange:(NSRange)range {
- if (!model_->HasGroups())
- return [NSIndexSet indexSetWithIndexesInRange:range];
- NSMutableIndexSet* indexes = [NSMutableIndexSet indexSet];
- NSUInteger offset = 1;
- for (NSUInteger i = range.location; i < NSMaxRange(range); ++i) {
- int group = model_->GetGroupID(i);
- offset = [self offsetForGroupID:group startingOffset:offset];
- [indexes addIndex:i + offset];
- }
- return indexes;
-}
-
-- (void)modelDidAddItemsInRange:(NSRange)range {
- NSMutableArray* rows = [NSMutableArray arrayWithCapacity:range.length];
- for (NSUInteger i=range.location; i<NSMaxRange(range); ++i)
- [rows addObject:[self columnValuesForRow:i]];
- [self insertObjects:rows
- atArrangedObjectIndexes:[self controllerRowsForModelRowsInRange:range]];
-}
-
-- (void)modelDidRemoveItemsInRange:(NSRange)range {
- NSMutableIndexSet* indexes =
- [NSMutableIndexSet indexSetWithIndexesInRange:range];
- if (model_->HasGroups()) {
- // When this method is called, the model has already removed items, so
- // accessing items in the model from |range.location| on may not be possible
- // anymore. Therefore we use the item right before that, if it exists.
- NSUInteger offset = 0;
- if (range.location > 0) {
- int last_group = model_->GetGroupID(range.location - 1);
- offset = [self offsetForGroupID:last_group];
- }
- [indexes shiftIndexesStartingAtIndex:0 by:offset];
- for (NSUInteger row = range.location + offset;
- row < NSMaxRange(range) + offset;
- ++row) {
- if ([self tableView:nil isGroupRow:row]) {
- // Skip over group rows.
- [indexes shiftIndexesStartingAtIndex:row by:1];
- offset++;
- }
- }
- }
- [self removeObjectsAtArrangedObjectIndexes:indexes];
-}
-
-- (NSDictionary*)columnValuesForRow:(NSInteger)row {
- NSMutableDictionary* dict = [NSMutableDictionary dictionary];
- if (model_->HasGroups()) {
- [dict setObject:[NSNumber numberWithInt:model_->GetGroupID(row)]
- forKey:kGroupID];
- }
- for (NSString* identifier in columns_.get()) {
- int column_id = [[columns_ objectForKey:identifier] intValue];
- std::wstring text = model_->GetText(row, column_id);
- [dict setObject:base::SysWideToNSString(text) forKey:identifier];
- }
- return dict;
-}
-
-// Overridden from NSArrayController -----------------------------------------
-
-- (BOOL)canRemove {
- if (!model_)
- return NO;
- RemoveRowsTableModel::Rows rows;
- [self setModelRows:&rows fromControllerRows:[self selectionIndexes]];
- return model_->CanRemoveRows(rows);
-}
-
-- (IBAction)remove:(id)sender {
- RemoveRowsTableModel::Rows rows;
- [self setModelRows:&rows fromControllerRows:[self selectionIndexes]];
- model_->RemoveRows(rows);
-}
-
-// Table View Delegate --------------------------------------------------------
-
-- (BOOL)tableView:(NSTableView*)tv isGroupRow:(NSInteger)row {
- NSDictionary* values = [[self arrangedObjects] objectAtIndex:row];
- return [[values objectForKey:kIsGroupRow] boolValue];
-}
-
-- (NSIndexSet*)tableView:(NSTableView*)tableView
- selectionIndexesForProposedSelection:(NSIndexSet*)proposedIndexes {
- NSMutableIndexSet* indexes = [proposedIndexes mutableCopy];
- for (NSUInteger i = [proposedIndexes firstIndex];
- i != NSNotFound;
- i = [proposedIndexes indexGreaterThanIndex:i]) {
- if ([self tableView:tableView isGroupRow:i]) {
- [indexes removeIndex:i];
- NSUInteger row = i + 1;
- while (row < [[self arrangedObjects] count] &&
- ![self tableView:tableView isGroupRow:row])
- [indexes addIndex:row++];
- }
- }
- return indexes;
-}
-
-// Actions --------------------------------------------------------------------
-
-- (IBAction)removeAll:(id)sender {
- model_->RemoveAll();
-}
-
-@end
diff --git a/chrome/browser/cocoa/table_model_array_controller_unittest.mm b/chrome/browser/cocoa/table_model_array_controller_unittest.mm
deleted file mode 100644
index f8bff40..0000000
--- a/chrome/browser/cocoa/table_model_array_controller_unittest.mm
+++ /dev/null
@@ -1,172 +0,0 @@
-// 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 "chrome/browser/cocoa/table_model_array_controller.h"
-
-#include "base/auto_reset.h"
-#include "base/command_line.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/mock_plugin_exceptions_table_model.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/test/testing_profile.h"
-#include "grit/generated_resources.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/gtest_mac.h"
-#include "webkit/glue/plugins/plugin_list.h"
-#include "webkit/glue/plugins/webplugininfo.h"
-
-namespace {
-
-class TableModelArrayControllerTest : public CocoaTest {
- public:
- TableModelArrayControllerTest()
- : command_line_(CommandLine::ForCurrentProcess(),
- *CommandLine::ForCurrentProcess()) {}
-
- virtual void SetUp() {
- CocoaTest::SetUp();
-
- CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kEnableResourceContentSettings);
-
- TestingProfile* profile = browser_helper_.profile();
- HostContentSettingsMap* map = profile->GetHostContentSettingsMap();
-
- HostContentSettingsMap::Pattern example_com("[*.]example.com");
- HostContentSettingsMap::Pattern moose_org("[*.]moose.org");
- map->SetContentSetting(example_com,
- CONTENT_SETTINGS_TYPE_PLUGINS,
- "a-foo",
- CONTENT_SETTING_ALLOW);
- map->SetContentSetting(moose_org,
- CONTENT_SETTINGS_TYPE_PLUGINS,
- "b-bar",
- CONTENT_SETTING_BLOCK);
- map->SetContentSetting(example_com,
- CONTENT_SETTINGS_TYPE_PLUGINS,
- "b-bar",
- CONTENT_SETTING_ALLOW);
-
- model_.reset(new MockPluginExceptionsTableModel(map, NULL));
-
- NPAPI::PluginList::PluginMap plugins;
- WebPluginInfo foo_plugin;
- foo_plugin.path = FilePath(FILE_PATH_LITERAL("a-foo"));
- foo_plugin.name = ASCIIToUTF16("FooPlugin");
- foo_plugin.enabled = true;
- PluginGroup* foo_group = PluginGroup::FromWebPluginInfo(foo_plugin);
- plugins[foo_group->identifier()] = linked_ptr<PluginGroup>(foo_group);
- WebPluginInfo bar_plugin;
- bar_plugin.path = FilePath(FILE_PATH_LITERAL("b-bar"));
- bar_plugin.name = ASCIIToUTF16("BarPlugin");
- bar_plugin.enabled = true;
- PluginGroup* bar_group = PluginGroup::FromWebPluginInfo(bar_plugin);
- plugins[bar_group->identifier()] = linked_ptr<PluginGroup>(bar_group);
- WebPluginInfo blurp_plugin;
- blurp_plugin.path = FilePath(FILE_PATH_LITERAL("c-blurp"));
- blurp_plugin.name = ASCIIToUTF16("BlurpPlugin");
- blurp_plugin.enabled = true;
- PluginGroup* blurp_group = PluginGroup::FromWebPluginInfo(blurp_plugin);
- plugins[blurp_group->identifier()] = linked_ptr<PluginGroup>(blurp_group);
-
- model_->set_plugins(plugins);
- model_->LoadSettings();
-
- id content = [NSMutableArray array];
- controller_.reset(
- [[TableModelArrayController alloc] initWithContent:content]);
- NSDictionary* columns = [NSDictionary dictionaryWithObjectsAndKeys:
- [NSNumber numberWithInt:IDS_EXCEPTIONS_HOSTNAME_HEADER], @"title",
- [NSNumber numberWithInt:IDS_EXCEPTIONS_ACTION_HEADER], @"action",
- nil];
- [controller_.get() bindToTableModel:model_.get()
- withColumns:columns
- groupTitleColumn:@"title"];
- }
-
- protected:
- BrowserTestHelper browser_helper_;
- scoped_ptr<MockPluginExceptionsTableModel> model_;
- scoped_nsobject<TableModelArrayController> controller_;
-
- private:
- AutoReset<CommandLine> command_line_;
-};
-
-TEST_F(TableModelArrayControllerTest, CheckTitles) {
- NSArray* titles = [[controller_.get() arrangedObjects] valueForKey:@"title"];
- EXPECT_NSEQ(@"(\n"
- @" FooPlugin,\n"
- @" \"[*.]example.com\",\n"
- @" BarPlugin,\n"
- @" \"[*.]example.com\",\n"
- @" \"[*.]moose.org\"\n"
- @")",
- [titles description]);
-}
-
-TEST_F(TableModelArrayControllerTest, RemoveRows) {
- NSArrayController* controller = controller_.get();
- [controller setSelectionIndex:1];
- [controller remove:nil];
- NSArray* titles = [[controller arrangedObjects] valueForKey:@"title"];
- EXPECT_NSEQ(@"(\n"
- @" BarPlugin,\n"
- @" \"[*.]example.com\",\n"
- @" \"[*.]moose.org\"\n"
- @")",
- [titles description]);
-
- [controller setSelectionIndex:2];
- [controller remove:nil];
- titles = [[controller arrangedObjects] valueForKey:@"title"];
- EXPECT_NSEQ(@"(\n"
- @" BarPlugin,\n"
- @" \"[*.]example.com\"\n"
- @")",
- [titles description]);
-}
-
-TEST_F(TableModelArrayControllerTest, RemoveAll) {
- [controller_.get() removeAll:nil];
- EXPECT_EQ(0u, [[controller_.get() arrangedObjects] count]);
-}
-
-TEST_F(TableModelArrayControllerTest, AddException) {
- TestingProfile* profile = browser_helper_.profile();
- HostContentSettingsMap* map = profile->GetHostContentSettingsMap();
- HostContentSettingsMap::Pattern example_com("[*.]example.com");
- map->SetContentSetting(example_com,
- CONTENT_SETTINGS_TYPE_PLUGINS,
- "c-blurp",
- CONTENT_SETTING_BLOCK);
-
- NSArrayController* controller = controller_.get();
- NSArray* titles = [[controller arrangedObjects] valueForKey:@"title"];
- EXPECT_NSEQ(@"(\n"
- @" FooPlugin,\n"
- @" \"[*.]example.com\",\n"
- @" BarPlugin,\n"
- @" \"[*.]example.com\",\n"
- @" \"[*.]moose.org\",\n"
- @" BlurpPlugin,\n"
- @" \"[*.]example.com\"\n"
- @")",
- [titles description]);
- NSMutableIndexSet* indexes = [NSMutableIndexSet indexSetWithIndex:1];
- [indexes addIndex:6];
- [controller setSelectionIndexes:indexes];
- [controller remove:nil];
- titles = [[controller arrangedObjects] valueForKey:@"title"];
- EXPECT_NSEQ(@"(\n"
- @" BarPlugin,\n"
- @" \"[*.]example.com\",\n"
- @" \"[*.]moose.org\"\n"
- @")",
- [titles description]);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/table_row_nsimage_cache.h b/chrome/browser/cocoa/table_row_nsimage_cache.h
deleted file mode 100644
index 84dbb69..0000000
--- a/chrome/browser/cocoa/table_row_nsimage_cache.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_TABLE_ROW_NSIMAGE_CACHE_H_
-#define CHROME_BROWSER_COCOA_TABLE_ROW_NSIMAGE_CACHE_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_nsobject.h"
-
-class SkBitmap;
-
-// There are several dialogs that display tabular data with one SkBitmap
-// per row. This class converts these SkBitmaps to NSImages on demand, and
-// caches the results.
-class TableRowNSImageCache {
- public:
- // Interface this cache expects for its table model.
- class Table {
- public:
- // Returns the number of rows in the table.
- virtual int RowCount() const = 0;
-
- // Returns the icon of the |row|th row.
- virtual SkBitmap GetIcon(int row) const = 0;
-
- protected:
- virtual ~Table() {}
- };
-
- // |model| must outlive the cache.
- explicit TableRowNSImageCache(Table* model);
-
- // Lazily converts the image at the given row and caches it in |icon_images_|.
- NSImage* GetImageForRow(int row);
-
- // Call these functions every time the table changes, to update the cache.
- void OnModelChanged();
- void OnItemsChanged(int start, int length);
- void OnItemsAdded(int start, int length);
- void OnItemsRemoved(int start, int length);
-
- private:
- // The table model we query for row count and icons.
- Table* model_; // weak
-
- // Stores strong NSImage refs for icons. If an entry is NULL, it will be
- // created in GetImageForRow().
- scoped_nsobject<NSPointerArray> icon_images_;
-};
-
-#endif // CHROME_BROWSER_COCOA_TABLE_ROW_NSIMAGE_CACHE_H_
-
diff --git a/chrome/browser/cocoa/table_row_nsimage_cache.mm b/chrome/browser/cocoa/table_row_nsimage_cache.mm
deleted file mode 100644
index ed10af7..0000000
--- a/chrome/browser/cocoa/table_row_nsimage_cache.mm
+++ /dev/null
@@ -1,79 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/table_row_nsimage_cache.h"
-
-#include "base/logging.h"
-#include "skia/ext/skia_utils_mac.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-TableRowNSImageCache::TableRowNSImageCache(Table* model)
- : model_(model),
- icon_images_([[NSPointerArray alloc] initWithOptions:
- NSPointerFunctionsStrongMemory |
- NSPointerFunctionsObjectPersonality]) {
- int count = model_->RowCount();
- [icon_images_ setCount:count];
-}
-
-void TableRowNSImageCache::OnModelChanged() {
- int count = model_->RowCount();
- [icon_images_ setCount:0];
- [icon_images_ setCount:count];
-}
-
-void TableRowNSImageCache::OnItemsChanged(int start, int length) {
- DCHECK_LE(start + length, static_cast<int>([icon_images_ count]));
- for (int i = start; i < (start + length); ++i) {
- [icon_images_ replacePointerAtIndex:i withPointer:NULL];
- }
- DCHECK_EQ(model_->RowCount(),
- static_cast<int>([icon_images_ count]));
-}
-
-void TableRowNSImageCache::OnItemsAdded(int start, int length) {
- DCHECK_LE(start, static_cast<int>([icon_images_ count]));
-
- // -[NSPointerArray insertPointer:atIndex:] throws if index == count.
- // Instead expand the array with NULLs.
- if (start == static_cast<int>([icon_images_ count])) {
- [icon_images_ setCount:start + length];
- } else {
- for (int i = 0; i < length; ++i) {
- [icon_images_ insertPointer:NULL atIndex:start]; // Values slide up.
- }
- }
- DCHECK_EQ(model_->RowCount(),
- static_cast<int>([icon_images_ count]));
-}
-
-void TableRowNSImageCache::OnItemsRemoved(int start, int length) {
- DCHECK_LE(start + length, static_cast<int>([icon_images_ count]));
- for (int i = 0; i < length; ++i) {
- [icon_images_ removePointerAtIndex:start]; // Values slide down.
- }
- DCHECK_EQ(model_->RowCount(),
- static_cast<int>([icon_images_ count]));
-}
-
-NSImage* TableRowNSImageCache::GetImageForRow(int row) {
- DCHECK_EQ(model_->RowCount(),
- static_cast<int>([icon_images_ count]));
- DCHECK_GE(row, 0);
- DCHECK_LT(row, static_cast<int>([icon_images_ count]));
- NSImage* image = static_cast<NSImage*>([icon_images_ pointerAtIndex:row]);
- if (!image) {
- const SkBitmap bitmap_icon =
- model_->GetIcon(row);
- // This means GetIcon() will get called until it returns a non-empty bitmap.
- // Empty bitmaps are intentionally not cached.
- if (!bitmap_icon.isNull()) {
- image = gfx::SkBitmapToNSImage(bitmap_icon);
- DCHECK(image);
- [icon_images_ replacePointerAtIndex:row withPointer:image];
- }
- }
- return image;
-}
-
diff --git a/chrome/browser/cocoa/table_row_nsimage_cache_unittest.mm b/chrome/browser/cocoa/table_row_nsimage_cache_unittest.mm
deleted file mode 100644
index 1cc8471..0000000
--- a/chrome/browser/cocoa/table_row_nsimage_cache_unittest.mm
+++ /dev/null
@@ -1,200 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/table_row_nsimage_cache.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-namespace {
-
-class TestTable : public TableRowNSImageCache::Table {
- public:
-
- std::vector<SkBitmap>* rows() {
- return &rows_;
- }
-
- // TableRowNSImageCache::Table overrides.
- virtual int RowCount() const {
- return rows_.size();
- }
- virtual SkBitmap GetIcon(int index) const {
- return rows_[index];
- }
-
- private:
- std::vector<SkBitmap> rows_;
-};
-
-SkBitmap MakeImage(int width, int height) {
- SkBitmap image;
- image.setConfig(SkBitmap::kARGB_8888_Config, width, height);
- EXPECT_TRUE(image.allocPixels());
- image.eraseRGB(255, 0, 0);
- return image;
-}
-
-// Define this as a macro so that the original variable names can be used in
-// test output.
-#define COMPARE_SK_NS_IMG_SIZES(skia, cocoa) \
- EXPECT_EQ(skia.width(), [cocoa size].width); \
- EXPECT_EQ(skia.height(), [cocoa size].height);
-
-TEST(TableRowNSImageCacheTest, ModelChanged) {
- TestTable table;
- std::vector<SkBitmap>* rows = table.rows();
- rows->push_back(MakeImage(10, 10));
- rows->push_back(MakeImage(20, 20));
- rows->push_back(MakeImage(30, 30));
- TableRowNSImageCache cache(&table);
-
- NSImage* image0 = cache.GetImageForRow(0);
- NSImage* image1 = cache.GetImageForRow(1);
- NSImage* image2 = cache.GetImageForRow(2);
-
- COMPARE_SK_NS_IMG_SIZES(rows->at(0), image0);
- COMPARE_SK_NS_IMG_SIZES(rows->at(1), image1);
- COMPARE_SK_NS_IMG_SIZES(rows->at(2), image2);
-
- rows->clear();
-
- rows->push_back(MakeImage(15, 15));
- rows->push_back(MakeImage(25, 25));
- rows->push_back(MakeImage(35, 35));
- rows->push_back(MakeImage(45, 45));
-
- // Invalidate the entire model.
- cache.OnModelChanged();
-
- EXPECT_NE(image0, cache.GetImageForRow(0));
- image0 = cache.GetImageForRow(0);
-
- EXPECT_NE(image1, cache.GetImageForRow(1));
- image1 = cache.GetImageForRow(1);
-
- EXPECT_NE(image2, cache.GetImageForRow(2));
- image2 = cache.GetImageForRow(2);
-
- NSImage* image3 = cache.GetImageForRow(3);
-
- COMPARE_SK_NS_IMG_SIZES(rows->at(0), image0);
- COMPARE_SK_NS_IMG_SIZES(rows->at(1), image1);
- COMPARE_SK_NS_IMG_SIZES(rows->at(2), image2);
- COMPARE_SK_NS_IMG_SIZES(rows->at(3), image3);
-}
-
-
-TEST(TableRowNSImageCacheTest, ItemsChanged) {
- TestTable table;
- std::vector<SkBitmap>* rows = table.rows();
- rows->push_back(MakeImage(10, 10));
- rows->push_back(MakeImage(20, 20));
- rows->push_back(MakeImage(30, 30));
- TableRowNSImageCache cache(&table);
-
- NSImage* image0 = cache.GetImageForRow(0);
- NSImage* image1 = cache.GetImageForRow(1);
- NSImage* image2 = cache.GetImageForRow(2);
-
- COMPARE_SK_NS_IMG_SIZES(rows->at(0), image0);
- COMPARE_SK_NS_IMG_SIZES(rows->at(1), image1);
- COMPARE_SK_NS_IMG_SIZES(rows->at(2), image2);
-
- // Update the middle image.
- (*rows)[1] = MakeImage(25, 25);
- cache.OnItemsChanged(/* start=*/1, /* count=*/1);
-
- // Make sure the other items remained the same.
- EXPECT_EQ(image0, cache.GetImageForRow(0));
- EXPECT_EQ(image2, cache.GetImageForRow(2));
-
- image1 = cache.GetImageForRow(1);
- COMPARE_SK_NS_IMG_SIZES(rows->at(1), image1);
-
- // Update more than one image.
- (*rows)[0] = MakeImage(15, 15);
- (*rows)[1] = MakeImage(27, 27);
- EXPECT_EQ(3U, rows->size());
- cache.OnItemsChanged(0, 2);
-
- image0 = cache.GetImageForRow(0);
- image1 = cache.GetImageForRow(1);
-
- COMPARE_SK_NS_IMG_SIZES(rows->at(0), image0);
- COMPARE_SK_NS_IMG_SIZES(rows->at(1), image1);
-}
-
-
-TEST(TableRowNSImageCacheTest, ItemsAdded) {
- TestTable table;
- std::vector<SkBitmap>* rows = table.rows();
- rows->push_back(MakeImage(10, 10));
- rows->push_back(MakeImage(20, 20));
- TableRowNSImageCache cache(&table);
-
- NSImage* image0 = cache.GetImageForRow(0);
- NSImage* image1 = cache.GetImageForRow(1);
-
- COMPARE_SK_NS_IMG_SIZES(rows->at(0), image0);
- COMPARE_SK_NS_IMG_SIZES(rows->at(1), image1);
-
- // Add an item to the end.
- rows->push_back(MakeImage(30, 30));
- cache.OnItemsAdded(2, 1);
-
- // Make sure image 1 stayed the same.
- EXPECT_EQ(image1, cache.GetImageForRow(1));
- COMPARE_SK_NS_IMG_SIZES(rows->at(1), image1);
-
- // Check that image 2 got added correctly.
- NSImage* image2 = cache.GetImageForRow(2);
- COMPARE_SK_NS_IMG_SIZES(rows->at(2), image2);
-
- // Add two items to the begging.
- rows->insert(rows->begin(), MakeImage(7, 7));
- rows->insert(rows->begin(), MakeImage(3, 3));
- cache.OnItemsAdded(0, 2);
-
- NSImage* image00 = cache.GetImageForRow(0);
- NSImage* image01 = cache.GetImageForRow(1);
-
- COMPARE_SK_NS_IMG_SIZES(rows->at(0), image00);
- COMPARE_SK_NS_IMG_SIZES(rows->at(1), image01);
-}
-
-
-TEST(TableRowNSImageCacheTest, ItemsRemoved) {
- TestTable table;
- std::vector<SkBitmap>* rows = table.rows();
- rows->push_back(MakeImage(10, 10));
- rows->push_back(MakeImage(20, 20));
- rows->push_back(MakeImage(30, 30));
- rows->push_back(MakeImage(40, 40));
- rows->push_back(MakeImage(50, 50));
- TableRowNSImageCache cache(&table);
-
- NSImage* image0 = cache.GetImageForRow(0);
- NSImage* image1 = cache.GetImageForRow(1);
- NSImage* image2 = cache.GetImageForRow(2);
- NSImage* image3 = cache.GetImageForRow(3);
- NSImage* image4 = cache.GetImageForRow(4);
-
- COMPARE_SK_NS_IMG_SIZES(rows->at(0), image0);
- COMPARE_SK_NS_IMG_SIZES(rows->at(1), image1);
- COMPARE_SK_NS_IMG_SIZES(rows->at(2), image2);
- COMPARE_SK_NS_IMG_SIZES(rows->at(3), image3);
- COMPARE_SK_NS_IMG_SIZES(rows->at(4), image4);
-
- rows->erase(rows->begin() + 1, rows->begin() + 4); // [20x20, 50x50)
- cache.OnItemsRemoved(1, 3);
-
- image0 = cache.GetImageForRow(0);
- image1 = cache.GetImageForRow(1);
-
- COMPARE_SK_NS_IMG_SIZES(rows->at(0), image0);
- COMPARE_SK_NS_IMG_SIZES(rows->at(1), image1);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/tabpose_window.h b/chrome/browser/cocoa/tabpose_window.h
deleted file mode 100644
index 7728367..0000000
--- a/chrome/browser/cocoa/tabpose_window.h
+++ /dev/null
@@ -1,94 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_TABPOSE_WINDOW_H_
-#define CHROME_BROWSER_COCOA_TABPOSE_WINDOW_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/scoped_cftyperef.h"
-
-#include "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-#include "base/scoped_vector.h"
-
-namespace tabpose {
-
-class Tile;
-class TileSet;
-
-}
-
-namespace tabpose {
-
-enum WindowState {
- kFadingIn,
- kFadedIn,
- kFadingOut,
-};
-
-} // namespace tabpose
-
-class TabStripModel;
-class TabStripModelObserverBridge;
-
-// A TabposeWindow shows an overview of open tabs and lets the user select a new
-// active tab. The window blocks clicks on the tab strip and the download
-// shelf. Every open browser window has its own overlay, and they are
-// independent of each other.
-@interface TabposeWindow : NSWindow {
- @private
- tabpose::WindowState state_;
-
- // The root layer added to the content view. Covers the whole window.
- CALayer* rootLayer_; // weak
-
- // The layer showing the background layer. Covers the whole visible area.
- CALayer* bgLayer_; // weak
-
- // The layer drawn behind the currently selected tile.
- CALayer* selectionHighlight_; // weak
-
- // Colors used by the layers.
- base::mac::ScopedCFTypeRef<CGColorRef> gray_;
- base::mac::ScopedCFTypeRef<CGColorRef> darkBlue_;
-
- TabStripModel* tabStripModel_; // weak
-
- // Stores all preview layers. The order in here matches the order in
- // the tabstrip model.
- scoped_nsobject<NSMutableArray> allThumbnailLayers_;
-
- scoped_nsobject<NSMutableArray> allFaviconLayers_;
- scoped_nsobject<NSMutableArray> allTitleLayers_;
-
- // Manages the state of all layers.
- scoped_ptr<tabpose::TileSet> tileSet_;
-
- // The rectangle of the window that contains all layers. This is the
- // rectangle occupied by |bgLayer_|.
- NSRect containingRect_;
-
- // Informs us of added/removed/updated tabs.
- scoped_ptr<TabStripModelObserverBridge> tabStripModelObserverBridge_;
-}
-
-// Shows a TabposeWindow on top of |parent|, with |rect| being the active area.
-// If |slomo| is YES, then the appearance animation is shown in slow motion.
-// The window blocks all keyboard and mouse events and releases itself when
-// closed.
-+ (id)openTabposeFor:(NSWindow*)parent
- rect:(NSRect)rect
- slomo:(BOOL)slomo
- tabStripModel:(TabStripModel*)tabStripModel;
-@end
-
-@interface TabposeWindow (TestingAPI)
-- (void)selectTileAtIndexWithoutAnimation:(int)newIndex;
-- (NSUInteger)thumbnailLayerCount;
-- (int)selectedIndex;
-@end
-
-#endif // CHROME_BROWSER_COCOA_TABPOSE_WINDOW_H_
diff --git a/chrome/browser/cocoa/tabpose_window.mm b/chrome/browser/cocoa/tabpose_window.mm
deleted file mode 100644
index 07385ca..0000000
--- a/chrome/browser/cocoa/tabpose_window.mm
+++ /dev/null
@@ -1,1437 +0,0 @@
-// 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 "chrome/browser/cocoa/tabpose_window.h"
-
-#import <QuartzCore/QuartzCore.h>
-
-#include "app/resource_bundle.h"
-#include "base/mac_util.h"
-#include "base/mac/scoped_cftyperef.h"
-#include "base/scoped_callback_factory.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/browser_process.h"
-#import "chrome/browser/cocoa/bookmarks/bookmark_bar_constants.h"
-#import "chrome/browser/cocoa/browser_window_controller.h"
-#import "chrome/browser/cocoa/tab_strip_controller.h"
-#import "chrome/browser/cocoa/tab_strip_model_observer_bridge.h"
-#import "chrome/browser/debugger/devtools_window.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/renderer_host/backing_store_mac.h"
-#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/renderer_host/render_widget_host_view_mac.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
-#include "chrome/browser/tab_contents/thumbnail_generator.h"
-#include "chrome/browser/tab_contents_wrapper.h"
-#include "chrome/common/pref_names.h"
-#include "grit/app_resources.h"
-#include "skia/ext/skia_utils_mac.h"
-#include "third_party/skia/include/utils/mac/SkCGUtils.h"
-
-const int kTopGradientHeight = 15;
-
-NSString* const kAnimationIdKey = @"AnimationId";
-NSString* const kAnimationIdFadeIn = @"FadeIn";
-NSString* const kAnimationIdFadeOut = @"FadeOut";
-
-const CGFloat kDefaultAnimationDuration = 0.25; // In seconds.
-const CGFloat kSlomoFactor = 4;
-const CGFloat kObserverChangeAnimationDuration = 0.75; // In seconds.
-
-// CAGradientLayer is 10.6-only -- roll our own.
-@interface DarkGradientLayer : CALayer
-- (void)drawInContext:(CGContextRef)context;
-@end
-
-@implementation DarkGradientLayer
-- (void)drawInContext:(CGContextRef)context {
- base::mac::ScopedCFTypeRef<CGColorSpaceRef> grayColorSpace(
- CGColorSpaceCreateWithName(kCGColorSpaceGenericGray));
- CGFloat grays[] = { 0.277, 1.0, 0.39, 1.0 };
- CGFloat locations[] = { 0, 1 };
- base::mac::ScopedCFTypeRef<CGGradientRef> gradient(
- CGGradientCreateWithColorComponents(
- grayColorSpace.get(), grays, locations, arraysize(locations)));
- CGPoint topLeft = CGPointMake(0.0, kTopGradientHeight);
- CGContextDrawLinearGradient(context, gradient.get(), topLeft, CGPointZero, 0);
-}
-@end
-
-namespace tabpose {
-class ThumbnailLoader;
-}
-
-// A CALayer that draws a thumbnail for a TabContents object. The layer tries
-// to draw the TabContents's backing store directly if possible, and requests
-// a thumbnail bitmap from the TabContents's renderer process if not.
-@interface ThumbnailLayer : CALayer {
- // The TabContents the thumbnail is for.
- TabContents* contents_; // weak
-
- // The size the thumbnail is drawn at when zoomed in.
- NSSize fullSize_;
-
- // Used to load a thumbnail, if required.
- scoped_refptr<tabpose::ThumbnailLoader> loader_;
-
- // If the backing store couldn't be used and a thumbnail was returned from a
- // renderer process, it's stored in |thumbnail_|.
- base::mac::ScopedCFTypeRef<CGImageRef> thumbnail_;
-
- // True if the layer already sent a thumbnail request to a renderer.
- BOOL didSendLoad_;
-}
-- (id)initWithTabContents:(TabContents*)contents fullSize:(NSSize)fullSize;
-- (void)drawInContext:(CGContextRef)context;
-- (void)setThumbnail:(const SkBitmap&)bitmap;
-@end
-
-namespace tabpose {
-
-// ThumbnailLoader talks to the renderer process to load a thumbnail of a given
-// RenderWidgetHost, and sends the thumbnail back to a ThumbnailLayer once it
-// comes back from the renderer.
-class ThumbnailLoader : public base::RefCountedThreadSafe<ThumbnailLoader> {
- public:
- ThumbnailLoader(gfx::Size size, RenderWidgetHost* rwh, ThumbnailLayer* layer)
- : size_(size), rwh_(rwh), layer_(layer), factory_(this) {}
-
- // Starts the fetch.
- void LoadThumbnail();
-
- private:
- friend class base::RefCountedThreadSafe<ThumbnailLoader>;
- ~ThumbnailLoader() {
- ResetPaintingObserver();
- }
-
- void DidReceiveBitmap(const SkBitmap& bitmap) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- ResetPaintingObserver();
- [layer_ setThumbnail:bitmap];
- }
-
- void ResetPaintingObserver() {
- if (rwh_->painting_observer() != NULL) {
- DCHECK(rwh_->painting_observer() ==
- g_browser_process->GetThumbnailGenerator());
- rwh_->set_painting_observer(NULL);
- }
- }
-
- gfx::Size size_;
- RenderWidgetHost* rwh_; // weak
- ThumbnailLayer* layer_; // weak, owns us
- base::ScopedCallbackFactory<ThumbnailLoader> factory_;
-
- DISALLOW_COPY_AND_ASSIGN(ThumbnailLoader);
-};
-
-void ThumbnailLoader::LoadThumbnail() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- ThumbnailGenerator* generator = g_browser_process->GetThumbnailGenerator();
- if (!generator) // In unit tests.
- return;
-
- // As mentioned in ThumbnailLayer's -drawInContext:, it's sufficient to have
- // thumbnails at the zoomed-out pixel size for all but the thumbnail the user
- // clicks on in the end. But we don't don't which thumbnail that will be, so
- // keep it simple and request full thumbnails for everything.
- // TODO(thakis): Request smaller thumbnails for users with many tabs.
- gfx::Size page_size(size_); // Logical size the renderer renders at.
- gfx::Size pixel_size(size_); // Physical pixel size the image is rendered at.
-
- DCHECK(rwh_->painting_observer() == NULL ||
- rwh_->painting_observer() == generator);
- rwh_->set_painting_observer(generator);
-
- // Will send an IPC to the renderer on the IO thread.
- generator->AskForSnapshot(
- rwh_,
- /*prefer_backing_store=*/false,
- factory_.NewCallback(&ThumbnailLoader::DidReceiveBitmap),
- page_size,
- pixel_size);
-}
-
-} // namespace tabpose
-
-@implementation ThumbnailLayer
-
-- (id)initWithTabContents:(TabContents*)contents fullSize:(NSSize)fullSize {
- CHECK(contents);
- if ((self = [super init])) {
- contents_ = contents;
- fullSize_ = fullSize;
- }
- return self;
-}
-
-- (void)setTabContents:(TabContents*)contents {
- contents_ = contents;
-}
-
-- (void)setThumbnail:(const SkBitmap&)bitmap {
- // SkCreateCGImageRef() holds on to |bitmaps|'s memory, so this doesn't
- // create a copy.
- thumbnail_.reset(SkCreateCGImageRef(bitmap));
- loader_ = NULL;
- [self setNeedsDisplay];
-}
-
-- (int)topOffset {
- int topOffset = 0;
-
- // Medium term, we want to show thumbs of the actual info bar views, which
- // means I need to create InfoBarControllers here. At that point, we can get
- // the height from that controller. Until then, hardcode. :-/
- const int kInfoBarHeight = 31;
- topOffset += contents_->infobar_delegate_count() * kInfoBarHeight;
-
- bool always_show_bookmark_bar =
- contents_->profile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar);
- bool has_detached_bookmark_bar =
- contents_->ShouldShowBookmarkBar() && !always_show_bookmark_bar;
- if (has_detached_bookmark_bar)
- topOffset += bookmarks::kNTPBookmarkBarHeight;
-
- return topOffset;
-}
-
-- (int)bottomOffset {
- int bottomOffset = 0;
- TabContents* devToolsContents =
- DevToolsWindow::GetDevToolsContents(contents_);
- if (devToolsContents && devToolsContents->render_view_host() &&
- devToolsContents->render_view_host()->view()) {
- // The devtool's size might not be up-to-date, but since its height doesn't
- // change on window resize, and since most users don't use devtools, this is
- // good enough.
- bottomOffset +=
- devToolsContents->render_view_host()->view()->GetViewBounds().height();
- bottomOffset += 1; // :-( Divider line between web contents and devtools.
- }
- return bottomOffset;
-}
-
-- (void)drawBackingStore:(BackingStoreMac*)backing_store
- inRect:(CGRect)destRect
- context:(CGContextRef)context {
- // TODO(thakis): Add a sublayer for each accelerated surface in the rwhv.
- // Until then, accelerated layers (CoreAnimation NPAPI plugins, compositor)
- // won't show up in tabpose.
- if (backing_store->cg_layer()) {
- CGContextDrawLayerInRect(context, destRect, backing_store->cg_layer());
- } else {
- base::mac::ScopedCFTypeRef<CGImageRef> image(
- CGBitmapContextCreateImage(backing_store->cg_bitmap()));
- CGContextDrawImage(context, destRect, image);
- }
-}
-
-- (void)drawInContext:(CGContextRef)context {
- RenderWidgetHost* rwh = contents_->render_view_host();
- // NULL if renderer crashed.
- RenderWidgetHostView* rwhv = rwh ? rwh->view() : NULL;
- if (!rwhv) {
- // TODO(thakis): Maybe draw a sad tab layer?
- [super drawInContext:context];
- return;
- }
-
- // The size of the TabContent's RenderWidgetHost might not fit to the
- // current browser window at all, for example if the window was resized while
- // this TabContents object was not an active tab.
- // Compute the required size ourselves. Leave room for eventual infobars and
- // a detached bookmarks bar on the top, and for the devtools on the bottom.
- // Download shelf is not included in the |fullSize| rect, so no need to
- // correct for it here.
- // TODO(thakis): This is not resolution-independent.
- int topOffset = [self topOffset];
- int bottomOffset = [self bottomOffset];
- gfx::Size desiredThumbSize(fullSize_.width,
- fullSize_.height - topOffset - bottomOffset);
-
- // We need to ask the renderer for a thumbnail if
- // a) there's no backing store or
- // b) the backing store's size doesn't match our required size and
- // c) we didn't already send a thumbnail request to the renderer.
- BackingStoreMac* backing_store =
- (BackingStoreMac*)rwh->GetBackingStore(/*force_create=*/false);
- bool draw_backing_store =
- backing_store && backing_store->size() == desiredThumbSize;
-
- // Next weirdness: The destination rect. If the layer is |fullSize_| big, the
- // destination rect is (0, bottomOffset), (fullSize_.width, topOffset). But we
- // might be amidst an animation, so interpolate that rect.
- CGRect destRect = [self bounds];
- CGFloat scale = destRect.size.width / fullSize_.width;
- destRect.origin.y += bottomOffset * scale;
- destRect.size.height -= (bottomOffset + topOffset) * scale;
-
- // TODO(thakis): Draw infobars, detached bookmark bar as well.
-
- // If we haven't already, sent a thumbnail request to the renderer.
- if (!draw_backing_store && !didSendLoad_) {
- // Either the tab was never visible, or its backing store got evicted, or
- // the size of the backing store is wrong.
-
- // We only need a thumbnail the size of the zoomed-out layer for all
- // layers except the one the user clicks on. But since we can't know which
- // layer that is, request full-resolution layers for all tabs. This is
- // simple and seems to work in practice.
- loader_ = new tabpose::ThumbnailLoader(desiredThumbSize, rwh, self);
- loader_->LoadThumbnail();
- didSendLoad_ = YES;
-
- // Fill with bg color.
- [super drawInContext:context];
- }
-
- if (draw_backing_store) {
- // Backing store 'cache' hit!
- [self drawBackingStore:backing_store inRect:destRect context:context];
- } else if (thumbnail_) {
- // No cache hit, but the renderer returned a thumbnail to us.
- CGContextDrawImage(context, destRect, thumbnail_.get());
- }
-}
-
-@end
-
-namespace {
-
-class ScopedCAActionDisabler {
- public:
- ScopedCAActionDisabler() {
- [CATransaction begin];
- [CATransaction setValue:[NSNumber numberWithBool:YES]
- forKey:kCATransactionDisableActions];
- }
-
- ~ScopedCAActionDisabler() {
- [CATransaction commit];
- }
-};
-
-class ScopedCAActionSetDuration {
- public:
- explicit ScopedCAActionSetDuration(CGFloat duration) {
- [CATransaction begin];
- [CATransaction setValue:[NSNumber numberWithFloat:duration]
- forKey:kCATransactionAnimationDuration];
- }
-
- ~ScopedCAActionSetDuration() {
- [CATransaction commit];
- }
-};
-
-} // namespace
-
-// Given the number |n| of tiles with a desired aspect ratio of |a| and a
-// desired distance |dx|, |dy| between tiles, returns how many tiles fit
-// vertically into a rectangle with the dimensions |w_c|, |h_c|. This returns
-// an exact solution, which is usually a fractional number.
-static float FitNRectsWithAspectIntoBoundingSizeWithConstantPadding(
- int n, double a, int w_c, int h_c, int dx, int dy) {
- // We want to have the small rects have the same aspect ratio a as a full
- // tab. Let w, h be the size of a small rect, and w_c, h_c the size of the
- // container. dx, dy are the distances between small rects in x, y direction.
-
- // Geometry yields:
- // w_c = nx * (w + dx) - dx <=> w = (w_c + d_x) / nx - d_x
- // h_c = ny * (h + dy) - dy <=> h = (h_c + d_y) / ny - d_t
- // Plugging this into
- // a := tab_width / tab_height = w / h
- // yields
- // a = ((w_c - (nx - 1)*d_x)*ny) / (nx*(h_c - (ny - 1)*d_y))
- // Plugging in nx = n/ny and pen and paper (or wolfram alpha:
- // http://www.wolframalpha.com/input/?i=(-sqrt((d+n-a+f+n)^2-4+(a+f%2Ba+h)+(-d+n-n+w))%2Ba+f+n-d+n)/(2+a+(f%2Bh)) , (solution for nx)
- // http://www.wolframalpha.com/input/?i=+(-sqrt((a+f+n-d+n)^2-4+(d%2Bw)+(-a+f+n-a+h+n))-a+f+n%2Bd+n)/(2+(d%2Bw)) , (solution for ny)
- // ) gives us nx and ny (but the wrong root -- s/-sqrt(FOO)/sqrt(FOO)/.
-
- // This function returns ny.
- return (sqrt(pow(n * (a * dy - dx), 2) +
- 4 * n * a * (dx + w_c) * (dy + h_c)) -
- n * (a * dy - dx))
- /
- (2 * (dx + w_c));
-}
-
-namespace tabpose {
-
-// A tile is what is shown for a single tab in tabpose mode. It consists of a
-// title, favicon, thumbnail image, and pre- and postanimation rects.
-class Tile {
- public:
- Tile() {}
-
- // Returns the rectangle this thumbnail is at at the beginning of the zoom-in
- // animation. |tile| is the rectangle that's covering the whole tab area when
- // the animation starts.
- NSRect GetStartRectRelativeTo(const Tile& tile) const;
- NSRect thumb_rect() const { return thumb_rect_; }
-
- NSRect favicon_rect() const { return favicon_rect_; }
- SkBitmap favicon() const;
-
- // This changes |title_rect| and |favicon_rect| such that the favicon is on
- // the font's baseline and that the minimum distance between thumb rect and
- // favicon and title rects doesn't change.
- // The view code
- // 1. queries desired font size by calling |title_font_size()|
- // 2. loads that font
- // 3. calls |set_font_metrics()| which updates the title rect
- // 4. receives the title rect and puts the title on it with the font from 2.
- void set_font_metrics(CGFloat ascender, CGFloat descender);
- CGFloat title_font_size() const { return title_font_size_; }
-
- NSRect title_rect() const { return title_rect_; }
-
- // Returns an unelided title. The view logic is responsible for eliding.
- const string16& title() const { return contents_->GetTitle(); }
-
- TabContents* tab_contents() const { return contents_; }
- void set_tab_contents(TabContents* new_contents) { contents_ = new_contents; }
-
- private:
- friend class TileSet;
-
- // The thumb rect includes infobars, detached thumbnail bar, web contents,
- // and devtools.
- NSRect thumb_rect_;
- NSRect start_thumb_rect_;
-
- NSRect favicon_rect_;
-
- CGFloat title_font_size_;
- NSRect title_rect_;
-
- TabContents* contents_; // weak
-
- DISALLOW_COPY_AND_ASSIGN(Tile);
-};
-
-NSRect Tile::GetStartRectRelativeTo(const Tile& tile) const {
- NSRect rect = start_thumb_rect_;
- rect.origin.x -= tile.start_thumb_rect_.origin.x;
- rect.origin.y -= tile.start_thumb_rect_.origin.y;
- return rect;
-}
-
-SkBitmap Tile::favicon() const {
- if (contents_->is_app()) {
- SkBitmap* icon = contents_->GetExtensionAppIcon();
- if (icon)
- return *icon;
- }
- return contents_->GetFavIcon();
-}
-
-// Changes |title_rect| and |favicon_rect| such that the favicon is on the
-// font's baseline and that the minimum distance between thumb rect and
-// favicon and title rects doesn't change.
-void Tile::set_font_metrics(CGFloat ascender, CGFloat descender) {
- title_rect_.origin.y -= ascender + descender - NSHeight(title_rect_);
- title_rect_.size.height = ascender + descender;
-
- if (NSHeight(favicon_rect_) < ascender) {
- // Move favicon down.
- favicon_rect_.origin.y = title_rect_.origin.y + descender;
- } else {
- // Move title down.
- title_rect_.origin.y = favicon_rect_.origin.y - descender;
- }
-}
-
-// A tileset is responsible for owning and laying out all |Tile|s shown in a
-// tabpose window.
-class TileSet {
- public:
- TileSet() {}
-
- // Fills in |tiles_|.
- void Build(TabStripModel* source_model);
-
- // Computes coordinates for |tiles_|.
- void Layout(NSRect containing_rect);
-
- int selected_index() const { return selected_index_; }
- void set_selected_index(int index);
-
- const Tile& selected_tile() const { return *tiles_[selected_index()]; }
- Tile& tile_at(int index) { return *tiles_[index]; }
- const Tile& tile_at(int index) const { return *tiles_[index]; }
-
- // These return which index needs to be selected when the user presses
- // up, down, left, or right respectively.
- int up_index() const;
- int down_index() const;
- int left_index() const;
- int right_index() const;
-
- // These return which index needs to be selected on tab / shift-tab.
- int next_index() const;
- int previous_index() const;
-
- // Inserts a new Tile object containing |contents| at |index|. Does no
- // relayout.
- void InsertTileAt(int index, TabContents* contents);
-
- // Removes the Tile object at |index|. Does no relayout.
- void RemoveTileAt(int index);
-
- // Moves the Tile object at |from_index| to |to_index|. Since this doesn't
- // change the number of tiles, relayout can be done just by swapping the
- // tile rectangles in the index interval [from_index, to_index], so this does
- // layout.
- void MoveTileFromTo(int from_index, int to_index);
-
- private:
- int count_x() const {
- return ceilf(tiles_.size() / static_cast<float>(count_y_));
- }
- int count_y() const {
- return count_y_;
- }
- int last_row_count_x() const {
- return tiles_.size() - count_x() * (count_y() - 1);
- }
- int tiles_in_row(int row) const {
- return row != count_y() - 1 ? count_x() : last_row_count_x();
- }
- void index_to_tile_xy(int index, int* tile_x, int* tile_y) const {
- *tile_x = index % count_x();
- *tile_y = index / count_x();
- }
- int tile_xy_to_index(int tile_x, int tile_y) const {
- return tile_y * count_x() + tile_x;
- }
-
- ScopedVector<Tile> tiles_;
- int selected_index_;
- int count_y_;
-
- DISALLOW_COPY_AND_ASSIGN(TileSet);
-};
-
-void TileSet::Build(TabStripModel* source_model) {
- selected_index_ = source_model->selected_index();
- tiles_.resize(source_model->count());
- for (size_t i = 0; i < tiles_.size(); ++i) {
- tiles_[i] = new Tile;
- tiles_[i]->contents_ = source_model->GetTabContentsAt(i)->tab_contents();
- }
-}
-
-void TileSet::Layout(NSRect containing_rect) {
- int tile_count = tiles_.size();
- if (tile_count == 0) // Happens e.g. during test shutdown.
- return;
-
- // Room around the tiles insde of |containing_rect|.
- const int kSmallPaddingTop = 30;
- const int kSmallPaddingLeft = 30;
- const int kSmallPaddingRight = 30;
- const int kSmallPaddingBottom = 30;
-
- // Favicon / title area.
- const int kThumbTitlePaddingY = 6;
- const int kFaviconSize = 16;
- const int kTitleHeight = 14; // Font size.
- const int kTitleExtraHeight = kThumbTitlePaddingY + kTitleHeight;
- const int kFaviconExtraHeight = kThumbTitlePaddingY + kFaviconSize;
- const int kFaviconTitleDistanceX = 6;
- const int kFooterExtraHeight =
- std::max(kFaviconExtraHeight, kTitleExtraHeight);
-
- // Room between the tiles.
- const int kSmallPaddingX = 15;
- const int kSmallPaddingY = kFooterExtraHeight;
-
- // Aspect ratio of the containing rect.
- CGFloat aspect = NSWidth(containing_rect) / NSHeight(containing_rect);
-
- // Room left in container after the outer padding is removed.
- double container_width =
- NSWidth(containing_rect) - kSmallPaddingLeft - kSmallPaddingRight;
- double container_height =
- NSHeight(containing_rect) - kSmallPaddingTop - kSmallPaddingBottom;
-
- // The tricky part is figuring out the size of a tab thumbnail, or since the
- // size of the containing rect is known, the number of tiles in x and y
- // direction.
- // Given are the size of the containing rect, and the number of thumbnails
- // that need to fit into that rect. The aspect ratio of the thumbnails needs
- // to be the same as that of |containing_rect|, else they will look distorted.
- // The thumbnails need to be distributed such that
- // |count_x * count_y >= tile_count|, and such that wasted space is minimized.
- // See the comments in
- // |FitNRectsWithAspectIntoBoundingSizeWithConstantPadding()| for a more
- // detailed discussion.
- // TODO(thakis): It might be good enough to choose |count_x| and |count_y|
- // such that count_x / count_y is roughly equal to |aspect|?
- double fny = FitNRectsWithAspectIntoBoundingSizeWithConstantPadding(
- tile_count, aspect,
- container_width, container_height - kFooterExtraHeight,
- kSmallPaddingX, kSmallPaddingY + kFooterExtraHeight);
- count_y_ = roundf(fny);
-
- // Now that |count_x()| and |count_y_| are known, it's straightforward to
- // compute thumbnail width/height. See comment in
- // |FitNRectsWithAspectIntoBoundingSizeWithConstantPadding| for the derivation
- // of these two formulas.
- int small_width =
- floor((container_width + kSmallPaddingX) / static_cast<float>(count_x()) -
- kSmallPaddingX);
- int small_height =
- floor((container_height + kSmallPaddingY) / static_cast<float>(count_y_) -
- (kSmallPaddingY + kFooterExtraHeight));
-
- // |small_width / small_height| has only roughly an aspect ratio of |aspect|.
- // Shrink the thumbnail rect to make the aspect ratio fit exactly, and add
- // the extra space won by shrinking to the outer padding.
- int smallExtraPaddingLeft = 0;
- int smallExtraPaddingTop = 0;
- if (aspect > small_width/static_cast<float>(small_height)) {
- small_height = small_width / aspect;
- CGFloat all_tiles_height =
- (small_height + kSmallPaddingY + kFooterExtraHeight) * count_y() -
- (kSmallPaddingY + kFooterExtraHeight);
- smallExtraPaddingTop = (container_height - all_tiles_height)/2;
- } else {
- small_width = small_height * aspect;
- CGFloat all_tiles_width =
- (small_width + kSmallPaddingX) * count_x() - kSmallPaddingX;
- smallExtraPaddingLeft = (container_width - all_tiles_width)/2;
- }
-
- // Compute inter-tile padding in the zoomed-out view.
- CGFloat scale_small_to_big =
- NSWidth(containing_rect) / static_cast<float>(small_width);
- CGFloat big_padding_x = kSmallPaddingX * scale_small_to_big;
- CGFloat big_padding_y =
- (kSmallPaddingY + kFooterExtraHeight) * scale_small_to_big;
-
- // Now all dimensions are known. Lay out all tiles on a regular grid:
- // X X X X
- // X X X X
- // X X
- for (int row = 0, i = 0; i < tile_count; ++row) {
- for (int col = 0; col < count_x() && i < tile_count; ++col, ++i) {
- // Compute the smalled, zoomed-out thumbnail rect.
- tiles_[i]->thumb_rect_.size = NSMakeSize(small_width, small_height);
-
- int small_x = col * (small_width + kSmallPaddingX) +
- kSmallPaddingLeft + smallExtraPaddingLeft;
- int small_y = row * (small_height + kSmallPaddingY + kFooterExtraHeight) +
- kSmallPaddingTop + smallExtraPaddingTop;
-
- tiles_[i]->thumb_rect_.origin = NSMakePoint(
- small_x, NSHeight(containing_rect) - small_y - small_height);
-
- tiles_[i]->favicon_rect_.size = NSMakeSize(kFaviconSize, kFaviconSize);
- tiles_[i]->favicon_rect_.origin = NSMakePoint(
- small_x,
- NSHeight(containing_rect) -
- (small_y + small_height + kFaviconExtraHeight));
-
- // Align lower left corner of title rect with lower left corner of favicon
- // for now. The final position is computed later by
- // |Tile::set_font_metrics()|.
- tiles_[i]->title_font_size_ = kTitleHeight;
- tiles_[i]->title_rect_.origin = NSMakePoint(
- NSMaxX(tiles_[i]->favicon_rect()) + kFaviconTitleDistanceX,
- NSMinY(tiles_[i]->favicon_rect()));
- tiles_[i]->title_rect_.size = NSMakeSize(
- small_width -
- NSWidth(tiles_[i]->favicon_rect()) - kFaviconTitleDistanceX,
- kTitleHeight);
-
- // Compute the big, pre-zoom thumbnail rect.
- tiles_[i]->start_thumb_rect_.size = containing_rect.size;
-
- int big_x = col * (NSWidth(containing_rect) + big_padding_x);
- int big_y = row * (NSHeight(containing_rect) + big_padding_y);
- tiles_[i]->start_thumb_rect_.origin = NSMakePoint(big_x, -big_y);
- }
- }
-
- // Go through last row and center it:
- // X X X X
- // X X X X
- // X X
- int last_row_empty_tiles_x = count_x() - last_row_count_x();
- CGFloat small_last_row_shift_x =
- last_row_empty_tiles_x * (small_width + kSmallPaddingX) / 2;
- CGFloat big_last_row_shift_x =
- last_row_empty_tiles_x * (NSWidth(containing_rect) + big_padding_x) / 2;
- for (int i = tile_count - last_row_count_x(); i < tile_count; ++i) {
- tiles_[i]->thumb_rect_.origin.x += small_last_row_shift_x;
- tiles_[i]->start_thumb_rect_.origin.x += big_last_row_shift_x;
- tiles_[i]->favicon_rect_.origin.x += small_last_row_shift_x;
- tiles_[i]->title_rect_.origin.x += small_last_row_shift_x;
- }
-}
-
-void TileSet::set_selected_index(int index) {
- CHECK_GE(index, 0);
- CHECK_LT(index, static_cast<int>(tiles_.size()));
- selected_index_ = index;
-}
-
-// Given a |value| in [0, from_scale), map it into [0, to_scale) such that:
-// * [0, from_scale) ends up in the middle of [0, to_scale) if the latter is
-// a bigger range
-// * The middle of [0, from_scale) is mapped to [0, to_scale), and the parts
-// of the former that don't fit are mapped to 0 and to_scale - respectively
-// if the former is a bigger range.
-static int rescale(int value, int from_scale, int to_scale) {
- int left = (to_scale - from_scale) / 2;
- int result = value + left;
- if (result < 0)
- return 0;
- if (result >= to_scale)
- return to_scale - 1;
- return result;
-}
-
-int TileSet::up_index() const {
- int tile_x, tile_y;
- index_to_tile_xy(selected_index(), &tile_x, &tile_y);
- tile_y -= 1;
- if (tile_y == count_y() - 2) {
- // Transition from last row to second-to-last row.
- tile_x = rescale(tile_x, last_row_count_x(), count_x());
- } else if (tile_y < 0) {
- // Transition from first row to last row.
- tile_x = rescale(tile_x, count_x(), last_row_count_x());
- tile_y = count_y() - 1;
- }
- return tile_xy_to_index(tile_x, tile_y);
-}
-
-int TileSet::down_index() const {
- int tile_x, tile_y;
- index_to_tile_xy(selected_index(), &tile_x, &tile_y);
- tile_y += 1;
- if (tile_y == count_y() - 1) {
- // Transition from second-to-last row to last row.
- tile_x = rescale(tile_x, count_x(), last_row_count_x());
- } else if (tile_y >= count_y()) {
- // Transition from last row to first row.
- tile_x = rescale(tile_x, last_row_count_x(), count_x());
- tile_y = 0;
- }
- return tile_xy_to_index(tile_x, tile_y);
-}
-
-int TileSet::left_index() const {
- int tile_x, tile_y;
- index_to_tile_xy(selected_index(), &tile_x, &tile_y);
- tile_x -= 1;
- if (tile_x < 0)
- tile_x = tiles_in_row(tile_y) - 1;
- return tile_xy_to_index(tile_x, tile_y);
-}
-
-int TileSet::right_index() const {
- int tile_x, tile_y;
- index_to_tile_xy(selected_index(), &tile_x, &tile_y);
- tile_x += 1;
- if (tile_x >= tiles_in_row(tile_y))
- tile_x = 0;
- return tile_xy_to_index(tile_x, tile_y);
-}
-
-int TileSet::next_index() const {
- int new_index = selected_index() + 1;
- if (new_index >= static_cast<int>(tiles_.size()))
- new_index = 0;
- return new_index;
-}
-
-int TileSet::previous_index() const {
- int new_index = selected_index() - 1;
- if (new_index < 0)
- new_index = tiles_.size() - 1;
- return new_index;
-}
-
-void TileSet::InsertTileAt(int index, TabContents* contents) {
- tiles_.insert(tiles_.begin() + index, new Tile);
- tiles_[index]->contents_ = contents;
-}
-
-void TileSet::RemoveTileAt(int index) {
- tiles_.erase(tiles_.begin() + index);
-}
-
-// Moves the Tile object at |from_index| to |to_index|. Also updates rectangles
-// so that the tiles stay in a left-to-right, top-to-bottom layout when walked
-// in sequential order.
-void TileSet::MoveTileFromTo(int from_index, int to_index) {
- NSRect thumb = tiles_[from_index]->thumb_rect_;
- NSRect start_thumb = tiles_[from_index]->start_thumb_rect_;
- NSRect favicon = tiles_[from_index]->favicon_rect_;
- NSRect title = tiles_[from_index]->title_rect_;
-
- scoped_ptr<Tile> tile(tiles_[from_index]);
- tiles_.weak_erase(tiles_.begin() + from_index);
- tiles_.insert(tiles_.begin() + to_index, tile.release());
-
- int step = from_index < to_index ? -1 : 1;
- for (int i = to_index; (i - from_index) * step < 0; i += step) {
- tiles_[i]->thumb_rect_ = tiles_[i + step]->thumb_rect_;
- tiles_[i]->start_thumb_rect_ = tiles_[i + step]->start_thumb_rect_;
- tiles_[i]->favicon_rect_ = tiles_[i + step]->favicon_rect_;
- tiles_[i]->title_rect_ = tiles_[i + step]->title_rect_;
- }
- tiles_[from_index]->thumb_rect_ = thumb;
- tiles_[from_index]->start_thumb_rect_ = start_thumb;
- tiles_[from_index]->favicon_rect_ = favicon;
- tiles_[from_index]->title_rect_ = title;
-}
-
-} // namespace tabpose
-
-void AnimateCALayerFrameFromTo(
- CALayer* layer, const NSRect& from, const NSRect& to,
- NSTimeInterval duration, id boundsAnimationDelegate) {
- // http://developer.apple.com/mac/library/qa/qa2008/qa1620.html
- CABasicAnimation* animation;
-
- animation = [CABasicAnimation animationWithKeyPath:@"bounds"];
- animation.fromValue = [NSValue valueWithRect:from];
- animation.toValue = [NSValue valueWithRect:to];
- animation.duration = duration;
- animation.timingFunction =
- [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
- animation.delegate = boundsAnimationDelegate;
-
- // Update the layer's bounds so the layer doesn't snap back when the animation
- // completes.
- layer.bounds = NSRectToCGRect(to);
-
- // Add the animation, overriding the implicit animation.
- [layer addAnimation:animation forKey:@"bounds"];
-
- // Prepare the animation from the current position to the new position.
- NSPoint opoint = from.origin;
- NSPoint point = to.origin;
-
- // Adapt to anchorPoint.
- opoint.x += NSWidth(from) * layer.anchorPoint.x;
- opoint.y += NSHeight(from) * layer.anchorPoint.y;
- point.x += NSWidth(to) * layer.anchorPoint.x;
- point.y += NSHeight(to) * layer.anchorPoint.y;
-
- animation = [CABasicAnimation animationWithKeyPath:@"position"];
- animation.fromValue = [NSValue valueWithPoint:opoint];
- animation.toValue = [NSValue valueWithPoint:point];
- animation.duration = duration;
- animation.timingFunction =
- [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
-
- // Update the layer's position so that the layer doesn't snap back when the
- // animation completes.
- layer.position = NSPointToCGPoint(point);
-
- // Add the animation, overriding the implicit animation.
- [layer addAnimation:animation forKey:@"position"];
-}
-
-@interface TabposeWindow (Private)
-- (id)initForWindow:(NSWindow*)parent
- rect:(NSRect)rect
- slomo:(BOOL)slomo
- tabStripModel:(TabStripModel*)tabStripModel;
-- (void)setUpLayersInSlomo:(BOOL)slomo;
-- (void)fadeAway:(BOOL)slomo;
-- (void)selectTileAtIndex:(int)newIndex;
-@end
-
-@implementation TabposeWindow
-
-+ (id)openTabposeFor:(NSWindow*)parent
- rect:(NSRect)rect
- slomo:(BOOL)slomo
- tabStripModel:(TabStripModel*)tabStripModel {
- // Releases itself when closed.
- return [[TabposeWindow alloc]
- initForWindow:parent rect:rect slomo:slomo tabStripModel:tabStripModel];
-}
-
-- (id)initForWindow:(NSWindow*)parent
- rect:(NSRect)rect
- slomo:(BOOL)slomo
- tabStripModel:(TabStripModel*)tabStripModel {
- NSRect frame = [parent frame];
- if ((self = [super initWithContentRect:frame
- styleMask:NSBorderlessWindowMask
- backing:NSBackingStoreBuffered
- defer:NO])) {
- containingRect_ = rect;
- tabStripModel_ = tabStripModel;
- state_ = tabpose::kFadingIn;
- tileSet_.reset(new tabpose::TileSet);
- tabStripModelObserverBridge_.reset(
- new TabStripModelObserverBridge(tabStripModel_, self));
- [self setReleasedWhenClosed:YES];
- [self setOpaque:NO];
- [self setBackgroundColor:[NSColor clearColor]];
- [self setUpLayersInSlomo:slomo];
- [self setAcceptsMouseMovedEvents:YES];
- [parent addChildWindow:self ordered:NSWindowAbove];
- [self makeKeyAndOrderFront:self];
- }
- return self;
-}
-
-- (CALayer*)selectedLayer {
- return [allThumbnailLayers_ objectAtIndex:tileSet_->selected_index()];
-}
-
-- (void)selectTileAtIndex:(int)newIndex {
- const tabpose::Tile& tile = tileSet_->tile_at(newIndex);
- selectionHighlight_.frame =
- NSRectToCGRect(NSInsetRect(tile.thumb_rect(), -5, -5));
- tileSet_->set_selected_index(newIndex);
-}
-
-- (void)selectTileAtIndexWithoutAnimation:(int)newIndex {
- ScopedCAActionDisabler disabler;
- [self selectTileAtIndex:newIndex];
-}
-
-- (void)addLayersForTile:(tabpose::Tile&)tile
- showZoom:(BOOL)showZoom
- slomo:(BOOL)slomo
- animationDelegate:(id)animationDelegate {
- scoped_nsobject<CALayer> layer([[ThumbnailLayer alloc]
- initWithTabContents:tile.tab_contents()
- fullSize:tile.GetStartRectRelativeTo(
- tileSet_->selected_tile()).size]);
- [layer setNeedsDisplay];
-
- // Background color as placeholder for now.
- layer.get().backgroundColor = CGColorGetConstantColor(kCGColorWhite);
- if (showZoom) {
- AnimateCALayerFrameFromTo(
- layer,
- tile.GetStartRectRelativeTo(tileSet_->selected_tile()),
- tile.thumb_rect(),
- kDefaultAnimationDuration * (slomo ? kSlomoFactor : 1),
- animationDelegate);
- } else {
- layer.get().frame = NSRectToCGRect(tile.thumb_rect());
- }
-
- layer.get().shadowRadius = 10;
- layer.get().shadowOffset = CGSizeMake(0, -10);
- if (state_ == tabpose::kFadedIn)
- layer.get().shadowOpacity = 0.5;
-
- [bgLayer_ addSublayer:layer];
- [allThumbnailLayers_ addObject:layer];
-
- // Favicon and title.
- NSFont* font = [NSFont systemFontOfSize:tile.title_font_size()];
- tile.set_font_metrics([font ascender], -[font descender]);
-
- NSImage* nsFavicon = gfx::SkBitmapToNSImage(tile.favicon());
- // Either we don't have a valid favicon or there was some issue converting
- // it from an SkBitmap. Either way, just show the default.
- if (!nsFavicon) {
- NSImage* defaultFavIcon =
- ResourceBundle::GetSharedInstance().GetNativeImageNamed(
- IDR_DEFAULT_FAVICON);
- nsFavicon = defaultFavIcon;
- }
- base::mac::ScopedCFTypeRef<CGImageRef> favicon(
- mac_util::CopyNSImageToCGImage(nsFavicon));
-
- CALayer* faviconLayer = [CALayer layer];
- faviconLayer.frame = NSRectToCGRect(tile.favicon_rect());
- faviconLayer.contents = (id)favicon.get();
- faviconLayer.zPosition = 1; // On top of the thumb shadow.
- if (state_ == tabpose::kFadingIn)
- faviconLayer.hidden = YES;
- [bgLayer_ addSublayer:faviconLayer];
- [allFaviconLayers_ addObject:faviconLayer];
-
- CATextLayer* titleLayer = [CATextLayer layer];
- titleLayer.frame = NSRectToCGRect(tile.title_rect());
- titleLayer.string = base::SysUTF16ToNSString(tile.title());
- titleLayer.fontSize = [font pointSize];
- titleLayer.truncationMode = kCATruncationEnd;
- titleLayer.font = font;
- titleLayer.zPosition = 1; // On top of the thumb shadow.
- if (state_ == tabpose::kFadingIn)
- titleLayer.hidden = YES;
- [bgLayer_ addSublayer:titleLayer];
- [allTitleLayers_ addObject:titleLayer];
-}
-
-- (void)setUpLayersInSlomo:(BOOL)slomo {
- // Root layer -- covers whole window.
- rootLayer_ = [CALayer layer];
-
- // In a block so that the layers don't fade in.
- {
- ScopedCAActionDisabler disabler;
- // Background layer -- the visible part of the window.
- gray_.reset(CGColorCreateGenericGray(0.39, 1.0));
- bgLayer_ = [CALayer layer];
- bgLayer_.backgroundColor = gray_;
- bgLayer_.frame = NSRectToCGRect(containingRect_);
- bgLayer_.masksToBounds = YES;
- [rootLayer_ addSublayer:bgLayer_];
-
- // Selection highlight layer.
- darkBlue_.reset(CGColorCreateGenericRGB(0.25, 0.34, 0.86, 1.0));
- selectionHighlight_ = [CALayer layer];
- selectionHighlight_.backgroundColor = darkBlue_;
- selectionHighlight_.cornerRadius = 5.0;
- selectionHighlight_.zPosition = -1; // Behind other layers.
- selectionHighlight_.hidden = YES;
- [bgLayer_ addSublayer:selectionHighlight_];
-
- // Top gradient.
- CALayer* gradientLayer = [DarkGradientLayer layer];
- gradientLayer.frame = CGRectMake(
- 0,
- NSHeight(containingRect_) - kTopGradientHeight,
- NSWidth(containingRect_),
- kTopGradientHeight);
- [gradientLayer setNeedsDisplay]; // Draw once.
- [bgLayer_ addSublayer:gradientLayer];
- }
-
- // Layers for the tab thumbnails.
- tileSet_->Build(tabStripModel_);
- tileSet_->Layout(containingRect_);
- allThumbnailLayers_.reset(
- [[NSMutableArray alloc] initWithCapacity:tabStripModel_->count()]);
- allFaviconLayers_.reset(
- [[NSMutableArray alloc] initWithCapacity:tabStripModel_->count()]);
- allTitleLayers_.reset(
- [[NSMutableArray alloc] initWithCapacity:tabStripModel_->count()]);
-
- for (int i = 0; i < tabStripModel_->count(); ++i) {
- // Add a delegate to one of the animations to get a notification once the
- // animations are done.
- [self addLayersForTile:tileSet_->tile_at(i)
- showZoom:YES
- slomo:slomo
- animationDelegate:i == tileSet_->selected_index() ? self : nil];
- if (i == tileSet_->selected_index()) {
- CALayer* layer = [allThumbnailLayers_ objectAtIndex:i];
- CAAnimation* animation = [layer animationForKey:@"bounds"];
- DCHECK(animation);
- [animation setValue:kAnimationIdFadeIn forKey:kAnimationIdKey];
- }
- }
- [self selectTileAtIndexWithoutAnimation:tileSet_->selected_index()];
-
- // Needs to happen after all layers have been added to |rootLayer_|, else
- // there's a one frame flash of grey at the beginning of the animation
- // (|bgLayer_| showing through with none of its children visible yet).
- [[self contentView] setLayer:rootLayer_];
- [[self contentView] setWantsLayer:YES];
-}
-
-- (BOOL)canBecomeKeyWindow {
- return YES;
-}
-
-// Handle key events that should be executed repeatedly while the key is down.
-- (void)keyDown:(NSEvent*)event {
- if (state_ == tabpose::kFadingOut)
- return;
- NSString* characters = [event characters];
- if ([characters length] < 1)
- return;
-
- unichar character = [characters characterAtIndex:0];
- int newIndex = -1;
- switch (character) {
- case NSUpArrowFunctionKey:
- newIndex = tileSet_->up_index();
- break;
- case NSDownArrowFunctionKey:
- newIndex = tileSet_->down_index();
- break;
- case NSLeftArrowFunctionKey:
- newIndex = tileSet_->left_index();
- break;
- case NSRightArrowFunctionKey:
- newIndex = tileSet_->right_index();
- break;
- case NSTabCharacter:
- newIndex = tileSet_->next_index();
- break;
- case NSBackTabCharacter:
- newIndex = tileSet_->previous_index();
- break;
- }
- if (newIndex != -1)
- [self selectTileAtIndexWithoutAnimation:newIndex];
-}
-
-// Handle keyboard events that should be executed once when the key is released.
-- (void)keyUp:(NSEvent*)event {
- if (state_ == tabpose::kFadingOut)
- return;
- NSString* characters = [event characters];
- if ([characters length] < 1)
- return;
-
- unichar character = [characters characterAtIndex:0];
- switch (character) {
- case NSEnterCharacter:
- case NSNewlineCharacter:
- case NSCarriageReturnCharacter:
- case ' ':
- [self fadeAway:([event modifierFlags] & NSShiftKeyMask) != 0];
- break;
- case '\e': // Escape
- tileSet_->set_selected_index(tabStripModel_->selected_index());
- [self fadeAway:([event modifierFlags] & NSShiftKeyMask) != 0];
- break;
- }
-}
-
-// Handle keyboard events that contain cmd or ctrl.
-- (BOOL)performKeyEquivalent:(NSEvent*)event {
- if (state_ == tabpose::kFadingOut)
- return NO;
- NSString* characters = [event characters];
- if ([characters length] < 1)
- return NO;
- unichar character = [characters characterAtIndex:0];
- if ([event modifierFlags] & NSCommandKeyMask) {
- if (character >= '1' && character <= '9') {
- int index =
- character == '9' ? tabStripModel_->count() - 1 : character - '1';
- if (index < tabStripModel_->count()) {
- tileSet_->set_selected_index(index);
- [self fadeAway:([event modifierFlags] & NSShiftKeyMask) != 0];
- return YES;
- }
- }
- }
- return NO;
-}
-
--(void)selectTileFromMouseEvent:(NSEvent*)event {
- int newIndex = -1;
- CGPoint p = NSPointToCGPoint([event locationInWindow]);
- for (NSUInteger i = 0; i < [allThumbnailLayers_ count]; ++i) {
- CALayer* layer = [allThumbnailLayers_ objectAtIndex:i];
- CGPoint lp = [layer convertPoint:p fromLayer:rootLayer_];
- if ([static_cast<CALayer*>([layer presentationLayer]) containsPoint:lp])
- newIndex = i;
- }
- if (newIndex >= 0)
- [self selectTileAtIndexWithoutAnimation:newIndex];
-}
-
-- (void)mouseMoved:(NSEvent*)event {
- [self selectTileFromMouseEvent:event];
-}
-
-- (void)mouseDown:(NSEvent*)event {
- // Just in case the user clicked without ever moving the mouse.
- [self selectTileFromMouseEvent:event];
-
- [self fadeAway:([event modifierFlags] & NSShiftKeyMask) != 0];
-}
-
-- (void)swipeWithEvent:(NSEvent*)event {
- if (abs([event deltaY]) > 0.5) // Swipe up or down.
- [self fadeAway:([event modifierFlags] & NSShiftKeyMask) != 0];
-}
-
-- (void)close {
- // Prevent parent window from disappearing.
- [[self parentWindow] removeChildWindow:self];
-
- // We're dealloc'd in an autorelease pool – by then the observer registry
- // might be dead, so explicitly reset the observer now.
- tabStripModelObserverBridge_.reset();
-
- [super close];
-}
-
-- (void)commandDispatch:(id)sender {
- if ([sender tag] == IDC_TABPOSE)
- [self fadeAway:NO];
-}
-
-- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
- // Disable all browser-related menu items except the tab overview toggle.
- SEL action = [item action];
- NSInteger tag = [item tag];
- return action == @selector(commandDispatch:) && tag == IDC_TABPOSE;
-}
-
-- (void)fadeAway:(BOOL)slomo {
- if (state_ == tabpose::kFadingOut)
- return;
-
- state_ = tabpose::kFadingOut;
- [self setAcceptsMouseMovedEvents:NO];
-
- // Select chosen tab.
- if (tileSet_->selected_index() < tabStripModel_->count()) {
- tabStripModel_->SelectTabContentsAt(tileSet_->selected_index(),
- /*user_gesture=*/true);
- } else {
- DCHECK_EQ(tileSet_->selected_index(), 0);
- }
-
- {
- ScopedCAActionDisabler disableCAActions;
-
- // Move the selected layer on top of all other layers.
- [self selectedLayer].zPosition = 1;
-
- selectionHighlight_.hidden = YES;
- for (CALayer* layer in allFaviconLayers_.get())
- layer.hidden = YES;
- for (CALayer* layer in allTitleLayers_.get())
- layer.hidden = YES;
-
- // Running animations with shadows is slow, so turn shadows off before
- // running the exit animation.
- for (CALayer* layer in allThumbnailLayers_.get())
- layer.shadowOpacity = 0.0;
- }
-
- // Animate layers out, all in one transaction.
- CGFloat duration =
- 1.3 * kDefaultAnimationDuration * (slomo ? kSlomoFactor : 1);
- ScopedCAActionSetDuration durationSetter(duration);
- for (NSUInteger i = 0; i < [allThumbnailLayers_ count]; ++i) {
- CALayer* layer = [allThumbnailLayers_ objectAtIndex:i];
- // |start_thumb_rect_| was relative to the initial index, now this needs to
- // be relative to |selectedIndex_| (whose start rect was relative to
- // the initial index, too).
- CGRect newFrame = NSRectToCGRect(
- tileSet_->tile_at(i).GetStartRectRelativeTo(tileSet_->selected_tile()));
-
- // Add a delegate to one of the implicit animations to get a notification
- // once the animations are done.
- if (static_cast<int>(i) == tileSet_->selected_index()) {
- CAAnimation* animation = [CAAnimation animation];
- animation.delegate = self;
- [animation setValue:kAnimationIdFadeOut forKey:kAnimationIdKey];
- [layer addAnimation:animation forKey:@"frame"];
- }
-
- layer.frame = newFrame;
-
- if (static_cast<int>(i) == tileSet_->selected_index()) {
- // Redraw layer at big resolution, so that zoom-in isn't blocky.
- [layer setNeedsDisplay];
- }
- }
-}
-
-- (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)finished {
- NSString* animationId = [animation valueForKey:kAnimationIdKey];
- if ([animationId isEqualToString:kAnimationIdFadeIn]) {
- if (finished && state_ == tabpose::kFadingIn) {
- // If the user clicks while the fade in animation is still running,
- // |state_| is already kFadingOut. In that case, don't do anything.
- state_ = tabpose::kFadedIn;
-
- selectionHighlight_.hidden = NO;
- for (CALayer* layer in allFaviconLayers_.get())
- layer.hidden = NO;
- for (CALayer* layer in allTitleLayers_.get())
- layer.hidden = NO;
-
- // Running animations with shadows is slow, so turn shadows on only after
- // the animation is done.
- ScopedCAActionDisabler disableCAActions;
- for (CALayer* layer in allThumbnailLayers_.get())
- layer.shadowOpacity = 0.5;
- }
- } else if ([animationId isEqualToString:kAnimationIdFadeOut]) {
- DCHECK_EQ(tabpose::kFadingOut, state_);
- [self close];
- }
-}
-
-- (NSUInteger)thumbnailLayerCount {
- return [allThumbnailLayers_ count];
-}
-
-- (int)selectedIndex {
- return tileSet_->selected_index();
-}
-
-#pragma mark TabStripModelBridge
-
-- (void)refreshLayerFramesAtIndex:(int)i {
- const tabpose::Tile& tile = tileSet_->tile_at(i);
-
- CALayer* faviconLayer = [allFaviconLayers_ objectAtIndex:i];
- faviconLayer.frame = NSRectToCGRect(tile.favicon_rect());
- CALayer* titleLayer = [allTitleLayers_ objectAtIndex:i];
- titleLayer.frame = NSRectToCGRect(tile.title_rect());
- CALayer* thumbLayer = [allThumbnailLayers_ objectAtIndex:i];
- thumbLayer.frame = NSRectToCGRect(tile.thumb_rect());
-}
-
-- (void)insertTabWithContents:(TabContentsWrapper*)contents
- atIndex:(NSInteger)index
- inForeground:(bool)inForeground {
- // This happens if you cmd-click a link and then immediately open tabpose
- // on a slowish machine.
- ScopedCAActionSetDuration durationSetter(kObserverChangeAnimationDuration);
-
- // Insert new layer and relayout.
- tileSet_->InsertTileAt(index, contents->tab_contents());
- tileSet_->Layout(containingRect_);
- [self addLayersForTile:tileSet_->tile_at(index)
- showZoom:NO
- slomo:NO
- animationDelegate:nil];
-
- // Update old layers.
- DCHECK_EQ(tabStripModel_->count(),
- static_cast<int>([allThumbnailLayers_ count]));
- DCHECK_EQ(tabStripModel_->count(),
- static_cast<int>([allTitleLayers_ count]));
- DCHECK_EQ(tabStripModel_->count(),
- static_cast<int>([allFaviconLayers_ count]));
-
- for (int i = 0; i < tabStripModel_->count(); ++i) {
- if (i == index) // The new layer.
- continue;
- [self refreshLayerFramesAtIndex:i];
- }
-
- // Update selection.
- int selectedIndex = tileSet_->selected_index();
- if (selectedIndex >= index)
- selectedIndex++;
- [self selectTileAtIndex:selectedIndex];
-}
-
-- (void)tabClosingWithContents:(TabContentsWrapper*)contents
- atIndex:(NSInteger)index {
- // We will also get a -tabDetachedWithContents:atIndex: notification for
- // closing tabs, so do nothing here.
-}
-
-- (void)tabDetachedWithContents:(TabContentsWrapper*)contents
- atIndex:(NSInteger)index {
- ScopedCAActionSetDuration durationSetter(kObserverChangeAnimationDuration);
-
- // Remove layer and relayout.
- tileSet_->RemoveTileAt(index);
- tileSet_->Layout(containingRect_);
-
- [[allThumbnailLayers_ objectAtIndex:index] removeFromSuperlayer];
- [allThumbnailLayers_ removeObjectAtIndex:index];
- [[allTitleLayers_ objectAtIndex:index] removeFromSuperlayer];
- [allTitleLayers_ removeObjectAtIndex:index];
- [[allFaviconLayers_ objectAtIndex:index] removeFromSuperlayer];
- [allFaviconLayers_ removeObjectAtIndex:index];
-
- // Update old layers.
- DCHECK_EQ(tabStripModel_->count(),
- static_cast<int>([allThumbnailLayers_ count]));
- DCHECK_EQ(tabStripModel_->count(),
- static_cast<int>([allTitleLayers_ count]));
- DCHECK_EQ(tabStripModel_->count(),
- static_cast<int>([allFaviconLayers_ count]));
-
- if (tabStripModel_->count() == 0)
- [self close];
-
- for (int i = 0; i < tabStripModel_->count(); ++i)
- [self refreshLayerFramesAtIndex:i];
-
- // Update selection.
- int selectedIndex = tileSet_->selected_index();
- if (selectedIndex >= index)
- selectedIndex--;
- if (selectedIndex >= 0)
- [self selectTileAtIndex:selectedIndex];
-}
-
-- (void)tabMovedWithContents:(TabContentsWrapper*)contents
- fromIndex:(NSInteger)from
- toIndex:(NSInteger)to {
- ScopedCAActionSetDuration durationSetter(kObserverChangeAnimationDuration);
-
- // Move tile from |from| to |to|.
- tileSet_->MoveTileFromTo(from, to);
-
- // Move corresponding layers from |from| to |to|.
- scoped_nsobject<CALayer> thumbLayer(
- [[allThumbnailLayers_ objectAtIndex:from] retain]);
- [allThumbnailLayers_ removeObjectAtIndex:from];
- [allThumbnailLayers_ insertObject:thumbLayer.get() atIndex:to];
- scoped_nsobject<CALayer> faviconLayer(
- [[allFaviconLayers_ objectAtIndex:from] retain]);
- [allFaviconLayers_ removeObjectAtIndex:from];
- [allFaviconLayers_ insertObject:faviconLayer.get() atIndex:to];
- scoped_nsobject<CALayer> titleLayer(
- [[allTitleLayers_ objectAtIndex:from] retain]);
- [allTitleLayers_ removeObjectAtIndex:from];
- [allTitleLayers_ insertObject:titleLayer.get() atIndex:to];
-
- // Update frames of the layers.
- for (int i = std::min(from, to); i <= std::max(from, to); ++i)
- [self refreshLayerFramesAtIndex:i];
-
- // Update selection.
- int selectedIndex = tileSet_->selected_index();
- if (from == selectedIndex)
- selectedIndex = to;
- else if (from < selectedIndex && selectedIndex <= to)
- selectedIndex--;
- else if (to <= selectedIndex && selectedIndex < from)
- selectedIndex++;
- [self selectTileAtIndex:selectedIndex];
-}
-
-- (void)tabChangedWithContents:(TabContentsWrapper*)contents
- atIndex:(NSInteger)index
- changeType:(TabStripModelObserver::TabChangeType)change {
- // Tell the window to update text, title, and thumb layers at |index| to get
- // their data from |contents|. |contents| can be different from the old
- // contents at that index!
- // While a tab is loading, this is unfortunately called quite often for
- // both the "loading" and the "all" change types, so we don't really want to
- // send thumb requests to the corresponding renderer when this is called.
- // For now, just make sure that we don't hold on to an invalid TabContents
- // object.
- tabpose::Tile& tile = tileSet_->tile_at(index);
- if (contents->tab_contents() == tile.tab_contents()) {
- // TODO(thakis): Install a timer to send a thumb request/update title/update
- // favicon after 20ms or so, and reset the timer every time this is called
- // to make sure we get an updated thumb, without requesting them all over.
- return;
- }
-
- tile.set_tab_contents(contents->tab_contents());
- ThumbnailLayer* thumbLayer = [allThumbnailLayers_ objectAtIndex:index];
- [thumbLayer setTabContents:contents->tab_contents()];
-}
-
-- (void)tabStripModelDeleted {
- [self close];
-}
-
-@end
diff --git a/chrome/browser/cocoa/tabpose_window_unittest.mm b/chrome/browser/cocoa/tabpose_window_unittest.mm
deleted file mode 100644
index 4874b30..0000000
--- a/chrome/browser/cocoa/tabpose_window_unittest.mm
+++ /dev/null
@@ -1,119 +0,0 @@
-// 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 "chrome/browser/cocoa/tabpose_window.h"
-
-#import "chrome/browser/browser_window.h"
-#import "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/renderer_host/site_instance.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
-#include "chrome/browser/tabs/tab_strip_model.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-class TabposeWindowTest : public CocoaTest {
- public:
- TabposeWindowTest() {
- site_instance_ =
- SiteInstance::CreateSiteInstance(browser_helper_.profile());
- }
-
- void AppendTabToStrip() {
- TabContentsWrapper* tab_contents = Browser::TabContentsFactory(
- browser_helper_.profile(), site_instance_, MSG_ROUTING_NONE,
- NULL, NULL);
- browser_helper_.browser()->tabstrip_model()->AppendTabContents(
- tab_contents, /*foreground=*/true);
- }
-
- BrowserTestHelper browser_helper_;
- scoped_refptr<SiteInstance> site_instance_;
-};
-
-// Check that this doesn't leak.
-TEST_F(TabposeWindowTest, TestShow) {
- BrowserWindow* browser_window = browser_helper_.CreateBrowserWindow();
- NSWindow* parent = browser_window->GetNativeHandle();
-
- [parent orderFront:nil];
- EXPECT_TRUE([parent isVisible]);
-
- // Add a few tabs to the tab strip model.
- for (int i = 0; i < 3; ++i)
- AppendTabToStrip();
-
- base::mac::ScopedNSAutoreleasePool pool;
- TabposeWindow* window =
- [TabposeWindow openTabposeFor:parent
- rect:NSMakeRect(10, 20, 250, 160)
- slomo:NO
- tabStripModel:browser_helper_.browser()->tabstrip_model()];
-
- // Should release the window.
- [window mouseDown:nil];
-
- browser_helper_.CloseBrowserWindow();
-}
-
-TEST_F(TabposeWindowTest, TestModelObserver) {
- BrowserWindow* browser_window = browser_helper_.CreateBrowserWindow();
- NSWindow* parent = browser_window->GetNativeHandle();
- [parent orderFront:nil];
-
- // Add a few tabs to the tab strip model.
- for (int i = 0; i < 3; ++i)
- AppendTabToStrip();
-
- base::mac::ScopedNSAutoreleasePool pool;
- TabposeWindow* window =
- [TabposeWindow openTabposeFor:parent
- rect:NSMakeRect(10, 20, 250, 160)
- slomo:NO
- tabStripModel:browser_helper_.browser()->tabstrip_model()];
-
- // Exercise all the model change events.
- TabStripModel* model = browser_helper_.browser()->tabstrip_model();
- DCHECK_EQ([window thumbnailLayerCount], 3u);
- DCHECK_EQ([window selectedIndex], 2);
-
- model->MoveTabContentsAt(0, 2, /*select_after_move=*/false);
- DCHECK_EQ([window thumbnailLayerCount], 3u);
- DCHECK_EQ([window selectedIndex], 1);
-
- model->MoveTabContentsAt(2, 0, /*select_after_move=*/false);
- DCHECK_EQ([window thumbnailLayerCount], 3u);
- DCHECK_EQ([window selectedIndex], 2);
-
- [window selectTileAtIndexWithoutAnimation:0];
- DCHECK_EQ([window selectedIndex], 0);
-
- model->MoveTabContentsAt(0, 2, /*select_after_move=*/false);
- DCHECK_EQ([window selectedIndex], 2);
-
- model->MoveTabContentsAt(2, 0, /*select_after_move=*/false);
- DCHECK_EQ([window selectedIndex], 0);
-
- delete model->DetachTabContentsAt(0);
- DCHECK_EQ([window thumbnailLayerCount], 2u);
- DCHECK_EQ([window selectedIndex], 0);
-
- AppendTabToStrip();
- DCHECK_EQ([window thumbnailLayerCount], 3u);
- DCHECK_EQ([window selectedIndex], 0);
-
- model->CloseTabContentsAt(0, TabStripModel::CLOSE_NONE);
- DCHECK_EQ([window thumbnailLayerCount], 2u);
- DCHECK_EQ([window selectedIndex], 0);
-
- [window selectTileAtIndexWithoutAnimation:1];
- model->CloseTabContentsAt(0, TabStripModel::CLOSE_NONE);
- DCHECK_EQ([window thumbnailLayerCount], 1u);
- DCHECK_EQ([window selectedIndex], 0);
-
- // Should release the window.
- [window mouseDown:nil];
-
- browser_helper_.CloseBrowserWindow();
-}
diff --git a/chrome/browser/cocoa/task_helpers.h b/chrome/browser/cocoa/task_helpers.h
deleted file mode 100644
index ecc40f3..0000000
--- a/chrome/browser/cocoa/task_helpers.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_TASK_HELPERS_H_
-#define CHROME_BROWSER_COCOA_TASK_HELPERS_H_
-#pragma once
-
-class Task;
-
-namespace tracked_objects {
-class Location;
-} // namespace tracked_objects
-
-namespace cocoa_utils {
-
-// This can be used in place of BrowserThread::PostTask(BrowserThread::UI, ...).
-// The purpose of this function is to be able to execute Task work alongside
-// native work when a MessageLoop is blocked by a nested run loop. This function
-// will run the Task in both NSEventTrackingRunLoopMode and NSDefaultRunLoopMode
-// for the purpose of executing work while a menu is open. See
-// http://crbug.com/48679 for the full rationale.
-bool PostTaskInEventTrackingRunLoopMode(
- const tracked_objects::Location& from_here,
- Task* task);
-
-} // namespace cocoa_utils
-
-#endif // CHROME_BROWSER_COCOA_TASK_HELPERS_H_
diff --git a/chrome/browser/cocoa/task_helpers.mm b/chrome/browser/cocoa/task_helpers.mm
deleted file mode 100644
index 7cc458b..0000000
--- a/chrome/browser/cocoa/task_helpers.mm
+++ /dev/null
@@ -1,57 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/task_helpers.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_ptr.h"
-#include "base/task.h"
-
-// This is a wrapper for running Task objects from within a native run loop.
-// This can run specific tasks in that nested loop. This owns the task and will
-// delete it and itself when done.
-@interface NativeTaskRunner : NSObject {
- @private
- scoped_ptr<Task> task_;
-}
-- (id)initWithTask:(Task*)task;
-- (void)runTask;
-@end
-
-@implementation NativeTaskRunner
-- (id)initWithTask:(Task*)task {
- if ((self = [super init])) {
- task_.reset(task);
- }
- return self;
-}
-
-- (void)runTask {
- task_->Run();
- [self autorelease];
-}
-@end
-
-namespace cocoa_utils {
-
-bool PostTaskInEventTrackingRunLoopMode(
- const tracked_objects::Location& from_here,
- Task* task) {
- // This deletes itself and the task after the task runs.
- NativeTaskRunner* runner = [[NativeTaskRunner alloc] initWithTask:task];
-
- // Schedule the selector in multiple modes in case this was called while a
- // menu was not running.
- NSArray* modes = [NSArray arrayWithObjects:NSEventTrackingRunLoopMode,
- NSDefaultRunLoopMode,
- nil];
- [runner performSelectorOnMainThread:@selector(runTask)
- withObject:nil
- waitUntilDone:NO
- modes:modes];
- return true;
-}
-
-} // namespace cocoa_utils
diff --git a/chrome/browser/cocoa/task_manager_mac.h b/chrome/browser/cocoa/task_manager_mac.h
deleted file mode 100644
index 0c6feac..0000000
--- a/chrome/browser/cocoa/task_manager_mac.h
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_TASK_MANAGER_MAC_H_
-#define CHROME_BROWSER_COCOA_TASK_MANAGER_MAC_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-#include <vector>
-
-#include "base/cocoa_protocols_mac.h"
-#include "base/scoped_nsobject.h"
-#include "chrome/browser/cocoa/table_row_nsimage_cache.h"
-#include "chrome/browser/task_manager/task_manager.h"
-
-@class WindowSizeAutosaver;
-class SkBitmap;
-class TaskManagerMac;
-
-// This class is responsible for loading the task manager window and for
-// managing it.
-@interface TaskManagerWindowController :
- NSWindowController<NSTableViewDataSource,
- NSTableViewDelegate> {
- @private
- IBOutlet NSTableView* tableView_;
- IBOutlet NSButton* endProcessButton_;
- TaskManagerMac* taskManagerObserver_; // weak
- TaskManager* taskManager_; // weak
- TaskManagerModel* model_; // weak
-
- scoped_nsobject<WindowSizeAutosaver> size_saver_;
-
- // These contain a permutation of [0..|model_->ResourceCount() - 1|]. Used to
- // implement sorting.
- std::vector<int> viewToModelMap_;
- std::vector<int> modelToViewMap_;
-
- // Descriptor of the current sort column.
- scoped_nsobject<NSSortDescriptor> currentSortDescriptor_;
-}
-
-// Creates and shows the task manager's window.
-- (id)initWithTaskManagerObserver:(TaskManagerMac*)taskManagerObserver;
-
-// Refreshes all data in the task manager table.
-- (void)reloadData;
-
-// Callback for "Stats for nerds" link.
-- (IBAction)statsLinkClicked:(id)sender;
-
-// Callback for "End process" button.
-- (IBAction)killSelectedProcesses:(id)sender;
-
-// Callback for double clicks on the table.
-- (void)selectDoubleClickedTab:(id)sender;
-@end
-
-@interface TaskManagerWindowController (TestingAPI)
-- (NSTableView*)tableView;
-@end
-
-// This class listens to task changed events sent by chrome.
-class TaskManagerMac : public TaskManagerModelObserver,
- public TableRowNSImageCache::Table {
- public:
- TaskManagerMac(TaskManager* task_manager);
- virtual ~TaskManagerMac();
-
- // TaskManagerModelObserver
- virtual void OnModelChanged();
- virtual void OnItemsChanged(int start, int length);
- virtual void OnItemsAdded(int start, int length);
- virtual void OnItemsRemoved(int start, int length);
-
- // Called by the cocoa window controller when its window closes and the
- // controller destroyed itself. Informs the model to stop updating.
- void WindowWasClosed();
-
- // TableRowNSImageCache::Table
- virtual int RowCount() const;
- virtual SkBitmap GetIcon(int r) const;
-
- // Creates the task manager if it doesn't exist; otherwise, it activates the
- // existing task manager window.
- static void Show();
-
- // Returns the TaskManager observed by |this|.
- TaskManager* task_manager() { return task_manager_; }
-
- // Lazily converts the image at the given row and caches it in |icon_cache_|.
- NSImage* GetImageForRow(int row);
-
- // Returns the cocoa object. Used for testing.
- TaskManagerWindowController* cocoa_controller() { return window_controller_; }
- private:
- // The task manager.
- TaskManager* const task_manager_; // weak
-
- // Our model.
- TaskManagerModel* const model_; // weak
-
- // Controller of our window, destroys itself when the task manager window
- // is closed.
- TaskManagerWindowController* window_controller_; // weak
-
- // Caches favicons for all rows. Needs to be initalized after |model_|.
- TableRowNSImageCache icon_cache_;
-
- // An open task manager window. There can only be one open at a time. This
- // is reset to NULL when the window is closed.
- static TaskManagerMac* instance_;
-
- DISALLOW_COPY_AND_ASSIGN(TaskManagerMac);
-};
-
-#endif // CHROME_BROWSER_COCOA_TASK_MANAGER_MAC_H_
diff --git a/chrome/browser/cocoa/task_manager_mac.mm b/chrome/browser/cocoa/task_manager_mac.mm
deleted file mode 100644
index 65241d2..0000000
--- a/chrome/browser/cocoa/task_manager_mac.mm
+++ /dev/null
@@ -1,582 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/task_manager_mac.h"
-
-#include <algorithm>
-#include <vector>
-
-#include "app/l10n_util_mac.h"
-#include "base/mac_util.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/browser_process.h"
-#import "chrome/browser/cocoa/window_size_autosaver.h"
-#include "chrome/common/pref_names.h"
-#include "grit/generated_resources.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-namespace {
-
-// Width of "a" and most other letters/digits in "small" table views.
-const int kCharWidth = 6;
-
-// Some of the strings below have spaces at the end or are missing letters, to
-// make the columns look nicer, and to take potentially longer localized strings
-// into account.
-const struct ColumnWidth {
- int columnId;
- int minWidth;
- int maxWidth; // If this is -1, 1.5*minColumWidth is used as max width.
-} columnWidths[] = {
- // Note that arraysize includes the trailing \0. That's intended.
- { IDS_TASK_MANAGER_PAGE_COLUMN, 120, 600 },
- { IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN,
- arraysize("800 MiB") * kCharWidth, -1 },
- { IDS_TASK_MANAGER_SHARED_MEM_COLUMN,
- arraysize("800 MiB") * kCharWidth, -1 },
- { IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN,
- arraysize("800 MiB") * kCharWidth, -1 },
- { IDS_TASK_MANAGER_CPU_COLUMN,
- arraysize("99.9") * kCharWidth, -1 },
- { IDS_TASK_MANAGER_NET_COLUMN,
- arraysize("150 kiB/s") * kCharWidth, -1 },
- { IDS_TASK_MANAGER_PROCESS_ID_COLUMN,
- arraysize("73099 ") * kCharWidth, -1 },
- { IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN,
- arraysize("2000.0K (2000.0 live)") * kCharWidth, -1 },
- { IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN,
- arraysize("2000.0K (2000.0 live)") * kCharWidth, -1 },
- { IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN,
- arraysize("2000.0K (2000.0 live)") * kCharWidth, -1 },
- { IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN,
- arraysize("800 kB") * kCharWidth, -1 },
- { IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN,
- arraysize("2000.0K (2000.0 live)") * kCharWidth, -1 },
- { IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN,
- arraysize("15 ") * kCharWidth, -1 },
-};
-
-class SortHelper {
- public:
- SortHelper(TaskManagerModel* model, NSSortDescriptor* column)
- : sort_column_([[column key] intValue]),
- ascending_([column ascending]),
- model_(model) {}
-
- bool operator()(int a, int b) {
- std::pair<int, int> group_range1 = model_->GetGroupRangeForResource(a);
- std::pair<int, int> group_range2 = model_->GetGroupRangeForResource(b);
- if (group_range1 == group_range2) {
- // The two rows are in the same group, sort so that items in the same
- // group always appear in the same order. |ascending_| is intentionally
- // ignored.
- return a < b;
- }
- // Sort by the first entry of each of the groups.
- int cmp_result = model_->CompareValues(
- group_range1.first, group_range2.first, sort_column_);
- if (!ascending_)
- cmp_result = -cmp_result;
- return cmp_result < 0;
- }
- private:
- int sort_column_;
- bool ascending_;
- TaskManagerModel* model_; // weak;
-};
-
-} // namespace
-
-@interface TaskManagerWindowController (Private)
-- (NSTableColumn*)addColumnWithId:(int)columnId visible:(BOOL)isVisible;
-- (void)setUpTableColumns;
-- (void)setUpTableHeaderContextMenu;
-- (void)toggleColumn:(id)sender;
-- (void)adjustSelectionAndEndProcessButton;
-- (void)deselectRows;
-@end
-
-////////////////////////////////////////////////////////////////////////////////
-// TaskManagerWindowController implementation:
-
-@implementation TaskManagerWindowController
-
-- (id)initWithTaskManagerObserver:(TaskManagerMac*)taskManagerObserver {
- NSString* nibpath = [mac_util::MainAppBundle()
- pathForResource:@"TaskManager"
- ofType:@"nib"];
- if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
- taskManagerObserver_ = taskManagerObserver;
- taskManager_ = taskManagerObserver_->task_manager();
- model_ = taskManager_->model();
-
- if (g_browser_process && g_browser_process->local_state()) {
- size_saver_.reset([[WindowSizeAutosaver alloc]
- initWithWindow:[self window]
- prefService:g_browser_process->local_state()
- path:prefs::kTaskManagerWindowPlacement]);
- }
- [self showWindow:self];
- }
- return self;
-}
-
-- (void)sortShuffleArray {
- viewToModelMap_.resize(model_->ResourceCount());
- for (size_t i = 0; i < viewToModelMap_.size(); ++i)
- viewToModelMap_[i] = i;
-
- std::sort(viewToModelMap_.begin(), viewToModelMap_.end(),
- SortHelper(model_, currentSortDescriptor_.get()));
-
- modelToViewMap_.resize(viewToModelMap_.size());
- for (size_t i = 0; i < viewToModelMap_.size(); ++i)
- modelToViewMap_[viewToModelMap_[i]] = i;
-}
-
-- (void)reloadData {
- // Store old view indices, and the model indices they map to.
- NSIndexSet* viewSelection = [tableView_ selectedRowIndexes];
- std::vector<int> modelSelection;
- for (NSUInteger i = [viewSelection lastIndex];
- i != NSNotFound;
- i = [viewSelection indexLessThanIndex:i]) {
- modelSelection.push_back(viewToModelMap_[i]);
- }
-
- // Sort.
- [self sortShuffleArray];
-
- // Use the model indices to get the new view indices of the selection, and
- // set selection to that. This assumes that no rows were added or removed
- // (in that case, the selection is cleared before -reloadData is called).
- if (modelSelection.size() > 0)
- DCHECK_EQ([tableView_ numberOfRows], model_->ResourceCount());
- NSMutableIndexSet* indexSet = [NSMutableIndexSet indexSet];
- for (size_t i = 0; i < modelSelection.size(); ++i)
- [indexSet addIndex:modelToViewMap_[modelSelection[i]]];
- [tableView_ selectRowIndexes:indexSet byExtendingSelection:NO];
-
- [tableView_ reloadData];
- [self adjustSelectionAndEndProcessButton];
-}
-
-- (IBAction)statsLinkClicked:(id)sender {
- TaskManager::GetInstance()->OpenAboutMemory();
-}
-
-- (IBAction)killSelectedProcesses:(id)sender {
- NSIndexSet* selection = [tableView_ selectedRowIndexes];
- for (NSUInteger i = [selection lastIndex];
- i != NSNotFound;
- i = [selection indexLessThanIndex:i]) {
- taskManager_->KillProcess(viewToModelMap_[i]);
- }
-}
-
-- (void)selectDoubleClickedTab:(id)sender {
- NSInteger row = [tableView_ clickedRow];
- if (row < 0)
- return; // Happens e.g. if the table header is double-clicked.
- taskManager_->ActivateProcess(viewToModelMap_[row]);
-}
-
-- (NSTableView*)tableView {
- return tableView_;
-}
-
-- (void)awakeFromNib {
- [self setUpTableColumns];
- [self setUpTableHeaderContextMenu];
- [self adjustSelectionAndEndProcessButton];
-
- [tableView_ setDoubleAction:@selector(selectDoubleClickedTab:)];
- [tableView_ sizeToFit];
-}
-
-- (void)dealloc {
- [tableView_ setDelegate:nil];
- [tableView_ setDataSource:nil];
- [super dealloc];
-}
-
-// Adds a column which has the given string id as title. |isVisible| specifies
-// if the column is initially visible.
-- (NSTableColumn*)addColumnWithId:(int)columnId visible:(BOOL)isVisible {
- scoped_nsobject<NSTableColumn> column([[NSTableColumn alloc]
- initWithIdentifier:[NSNumber numberWithInt:columnId]]);
-
- NSTextAlignment textAlignment = columnId == IDS_TASK_MANAGER_PAGE_COLUMN ?
- NSLeftTextAlignment : NSRightTextAlignment;
-
- [[column.get() headerCell]
- setStringValue:l10n_util::GetNSStringWithFixup(columnId)];
- [[column.get() headerCell] setAlignment:textAlignment];
- [[column.get() dataCell] setAlignment:textAlignment];
-
- NSFont* font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
- [[column.get() dataCell] setFont:font];
-
- [column.get() setHidden:!isVisible];
- [column.get() setEditable:NO];
-
- // The page column should by default be sorted ascending.
- BOOL ascending = columnId == IDS_TASK_MANAGER_PAGE_COLUMN;
-
- scoped_nsobject<NSSortDescriptor> sortDescriptor([[NSSortDescriptor alloc]
- initWithKey:[NSString stringWithFormat:@"%d", columnId]
- ascending:ascending]);
- [column.get() setSortDescriptorPrototype:sortDescriptor.get()];
-
- // Default values, only used in release builds if nobody notices the DCHECK
- // during development when adding new columns.
- int minWidth = 200, maxWidth = 400;
-
- size_t i;
- for (i = 0; i < arraysize(columnWidths); ++i) {
- if (columnWidths[i].columnId == columnId) {
- minWidth = columnWidths[i].minWidth;
- maxWidth = columnWidths[i].maxWidth;
- if (maxWidth < 0)
- maxWidth = 3 * minWidth / 2; // *1.5 for ints.
- break;
- }
- }
- DCHECK(i < arraysize(columnWidths)) << "Could not find " << columnId;
- [column.get() setMinWidth:minWidth];
- [column.get() setMaxWidth:maxWidth];
- [column.get() setResizingMask:NSTableColumnAutoresizingMask |
- NSTableColumnUserResizingMask];
-
- [tableView_ addTableColumn:column.get()];
- return column.get(); // Now retained by |tableView_|.
-}
-
-// Adds all the task manager's columns to the table.
-- (void)setUpTableColumns {
- for (NSTableColumn* column in [tableView_ tableColumns])
- [tableView_ removeTableColumn:column];
- NSTableColumn* nameColumn = [self addColumnWithId:IDS_TASK_MANAGER_PAGE_COLUMN
- visible:YES];
- // |nameColumn| displays an icon for every row -- this is done by an
- // NSButtonCell.
- scoped_nsobject<NSButtonCell> nameCell(
- [[NSButtonCell alloc] initTextCell:@""]);
- [nameCell.get() setImagePosition:NSImageLeft];
- [nameCell.get() setButtonType:NSSwitchButton];
- [nameCell.get() setAlignment:[[nameColumn dataCell] alignment]];
- [nameCell.get() setFont:[[nameColumn dataCell] font]];
- [nameColumn setDataCell:nameCell.get()];
-
- // Initially, sort on the tab name.
- [tableView_ setSortDescriptors:
- [NSArray arrayWithObject:[nameColumn sortDescriptorPrototype]]];
-
- [self addColumnWithId:IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN visible:YES];
- [self addColumnWithId:IDS_TASK_MANAGER_SHARED_MEM_COLUMN visible:NO];
- [self addColumnWithId:IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN visible:NO];
- [self addColumnWithId:IDS_TASK_MANAGER_CPU_COLUMN visible:YES];
- [self addColumnWithId:IDS_TASK_MANAGER_NET_COLUMN visible:YES];
- [self addColumnWithId:IDS_TASK_MANAGER_PROCESS_ID_COLUMN visible:NO];
- [self addColumnWithId:IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN
- visible:NO];
- [self addColumnWithId:IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN
- visible:NO];
- [self addColumnWithId:IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN visible:NO];
- [self addColumnWithId:IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN visible:NO];
- [self addColumnWithId:IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN
- visible:NO];
- [self addColumnWithId:IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN visible:NO];
-}
-
-// Creates a context menu for the table header that allows the user to toggle
-// which columns should be shown and which should be hidden (like e.g.
-// Task Manager.app's table header context menu).
-- (void)setUpTableHeaderContextMenu {
- scoped_nsobject<NSMenu> contextMenu(
- [[NSMenu alloc] initWithTitle:@"Task Manager context menu"]);
- for (NSTableColumn* column in [tableView_ tableColumns]) {
- NSMenuItem* item = [contextMenu.get()
- addItemWithTitle:[[column headerCell] stringValue]
- action:@selector(toggleColumn:)
- keyEquivalent:@""];
- [item setTarget:self];
- [item setRepresentedObject:column];
- [item setState:[column isHidden] ? NSOffState : NSOnState];
- }
- [[tableView_ headerView] setMenu:contextMenu.get()];
-}
-
-// Callback for the table header context menu. Toggles visibility of the table
-// column associated with the clicked menu item.
-- (void)toggleColumn:(id)item {
- DCHECK([item isKindOfClass:[NSMenuItem class]]);
- if (![item isKindOfClass:[NSMenuItem class]])
- return;
-
- NSTableColumn* column = [item representedObject];
- DCHECK(column);
- NSInteger oldState = [item state];
- NSInteger newState = oldState == NSOnState ? NSOffState : NSOnState;
- [column setHidden:newState == NSOffState];
- [item setState:newState];
- [tableView_ sizeToFit];
- [tableView_ setNeedsDisplay];
-}
-
-// This function appropriately sets the enabled states on the table's editing
-// buttons.
-- (void)adjustSelectionAndEndProcessButton {
- bool selectionContainsBrowserProcess = false;
-
- // If a row is selected, make sure that all rows belonging to the same process
- // are selected as well. Also, check if the selection contains the browser
- // process.
- NSIndexSet* selection = [tableView_ selectedRowIndexes];
- for (NSUInteger i = [selection lastIndex];
- i != NSNotFound;
- i = [selection indexLessThanIndex:i]) {
- int modelIndex = viewToModelMap_[i];
- if (taskManager_->IsBrowserProcess(modelIndex))
- selectionContainsBrowserProcess = true;
-
- std::pair<int, int> rangePair =
- model_->GetGroupRangeForResource(modelIndex);
- NSMutableIndexSet* indexSet = [NSMutableIndexSet indexSet];
- for (int j = 0; j < rangePair.second; ++j)
- [indexSet addIndex:modelToViewMap_[rangePair.first + j]];
- [tableView_ selectRowIndexes:indexSet byExtendingSelection:YES];
- }
-
- bool enabled = [selection count] > 0 && !selectionContainsBrowserProcess;
- [endProcessButton_ setEnabled:enabled];
-}
-
-- (void)deselectRows {
- [tableView_ deselectAll:self];
-}
-
-// Table view delegate method.
-- (void)tableViewSelectionIsChanging:(NSNotification*)aNotification {
- [self adjustSelectionAndEndProcessButton];
-}
-
-- (void)windowWillClose:(NSNotification*)notification {
- if (taskManagerObserver_) {
- taskManagerObserver_->WindowWasClosed();
- taskManagerObserver_ = nil;
- }
- [self autorelease];
-}
-
-@end
-
-@implementation TaskManagerWindowController (NSTableDataSource)
-
-- (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView {
- DCHECK(tableView == tableView_ || tableView_ == nil);
- return model_->ResourceCount();
-}
-
-- (NSString*)modelTextForRow:(int)row column:(int)columnId {
- DCHECK_LT(static_cast<size_t>(row), viewToModelMap_.size());
- row = viewToModelMap_[row];
- switch (columnId) {
- case IDS_TASK_MANAGER_PAGE_COLUMN: // Process
- return base::SysUTF16ToNSString(model_->GetResourceTitle(row));
-
- case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN: // Memory
- if (!model_->IsResourceFirstInGroup(row))
- return @"";
- return base::SysUTF16ToNSString(model_->GetResourcePrivateMemory(row));
-
- case IDS_TASK_MANAGER_SHARED_MEM_COLUMN: // Memory
- if (!model_->IsResourceFirstInGroup(row))
- return @"";
- return base::SysUTF16ToNSString(model_->GetResourceSharedMemory(row));
-
- case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN: // Memory
- if (!model_->IsResourceFirstInGroup(row))
- return @"";
- return base::SysUTF16ToNSString(model_->GetResourcePhysicalMemory(row));
-
- case IDS_TASK_MANAGER_CPU_COLUMN: // CPU
- if (!model_->IsResourceFirstInGroup(row))
- return @"";
- return base::SysUTF16ToNSString(model_->GetResourceCPUUsage(row));
-
- case IDS_TASK_MANAGER_NET_COLUMN: // Net
- return base::SysUTF16ToNSString(model_->GetResourceNetworkUsage(row));
-
- case IDS_TASK_MANAGER_PROCESS_ID_COLUMN: // Process ID
- if (!model_->IsResourceFirstInGroup(row))
- return @"";
- return base::SysUTF16ToNSString(model_->GetResourceProcessId(row));
-
- case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN: // WebCore image cache
- if (!model_->IsResourceFirstInGroup(row))
- return @"";
- return base::SysUTF16ToNSString(
- model_->GetResourceWebCoreImageCacheSize(row));
-
- case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN: // WebCore script cache
- if (!model_->IsResourceFirstInGroup(row))
- return @"";
- return base::SysUTF16ToNSString(
- model_->GetResourceWebCoreScriptsCacheSize(row));
-
- case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN: // WebCore CSS cache
- if (!model_->IsResourceFirstInGroup(row))
- return @"";
- return base::SysUTF16ToNSString(
- model_->GetResourceWebCoreCSSCacheSize(row));
-
- case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN:
- if (!model_->IsResourceFirstInGroup(row))
- return @"";
- return base::SysUTF16ToNSString(
- model_->GetResourceSqliteMemoryUsed(row));
-
- case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN:
- if (!model_->IsResourceFirstInGroup(row))
- return @"";
- return base::SysUTF16ToNSString(
- model_->GetResourceV8MemoryAllocatedSize(row));
-
- case IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN: // Goats Teleported!
- return base::SysUTF16ToNSString(model_->GetResourceGoatsTeleported(row));
-
- default:
- NOTREACHED();
- return @"";
- }
-}
-
-- (id)tableView:(NSTableView*)tableView
- objectValueForTableColumn:(NSTableColumn*)tableColumn
- row:(NSInteger)rowIndex {
- // NSButtonCells expect an on/off state as objectValue. Their title is set
- // in |tableView:dataCellForTableColumn:row:| below.
- if ([[tableColumn identifier] intValue] == IDS_TASK_MANAGER_PAGE_COLUMN) {
- return [NSNumber numberWithInt:NSOffState];
- }
-
- return [self modelTextForRow:rowIndex
- column:[[tableColumn identifier] intValue]];
-}
-
-- (NSCell*)tableView:(NSTableView*)tableView
- dataCellForTableColumn:(NSTableColumn*)tableColumn
- row:(NSInteger)rowIndex {
- NSCell* cell = [tableColumn dataCellForRow:rowIndex];
-
- // Set the favicon and title for the task in the name column.
- if ([[tableColumn identifier] intValue] == IDS_TASK_MANAGER_PAGE_COLUMN) {
- DCHECK([cell isKindOfClass:[NSButtonCell class]]);
- NSButtonCell* buttonCell = static_cast<NSButtonCell*>(cell);
- NSString* title = [self modelTextForRow:rowIndex
- column:[[tableColumn identifier] intValue]];
- [buttonCell setTitle:title];
- [buttonCell setImage:
- taskManagerObserver_->GetImageForRow(viewToModelMap_[rowIndex])];
- [buttonCell setRefusesFirstResponder:YES]; // Don't push in like a button.
- [buttonCell setHighlightsBy:NSNoCellMask];
- }
-
- return cell;
-}
-
-- (void) tableView:(NSTableView*)tableView
- sortDescriptorsDidChange:(NSArray*)oldDescriptors {
- NSArray* newDescriptors = [tableView sortDescriptors];
- if ([newDescriptors count] < 1)
- return;
-
- currentSortDescriptor_.reset([[newDescriptors objectAtIndex:0] retain]);
- [self reloadData]; // Sorts.
-}
-
-@end
-
-////////////////////////////////////////////////////////////////////////////////
-// TaskManagerMac implementation:
-
-TaskManagerMac::TaskManagerMac(TaskManager* task_manager)
- : task_manager_(task_manager),
- model_(task_manager->model()),
- icon_cache_(this) {
- window_controller_ =
- [[TaskManagerWindowController alloc] initWithTaskManagerObserver:this];
- model_->AddObserver(this);
-}
-
-// static
-TaskManagerMac* TaskManagerMac::instance_ = NULL;
-
-TaskManagerMac::~TaskManagerMac() {
- if (this == instance_) {
- // Do not do this when running in unit tests: |StartUpdating()| never got
- // called in that case.
- task_manager_->OnWindowClosed();
- }
- model_->RemoveObserver(this);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// TaskManagerMac, TaskManagerModelObserver implementation:
-
-void TaskManagerMac::OnModelChanged() {
- icon_cache_.OnModelChanged();
- [window_controller_ deselectRows];
- [window_controller_ reloadData];
-}
-
-void TaskManagerMac::OnItemsChanged(int start, int length) {
- icon_cache_.OnItemsChanged(start, length);
- [window_controller_ reloadData];
-}
-
-void TaskManagerMac::OnItemsAdded(int start, int length) {
- icon_cache_.OnItemsAdded(start, length);
- [window_controller_ deselectRows];
- [window_controller_ reloadData];
-}
-
-void TaskManagerMac::OnItemsRemoved(int start, int length) {
- icon_cache_.OnItemsRemoved(start, length);
- [window_controller_ deselectRows];
- [window_controller_ reloadData];
-}
-
-NSImage* TaskManagerMac::GetImageForRow(int row) {
- return icon_cache_.GetImageForRow(row);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// TaskManagerMac, public:
-
-void TaskManagerMac::WindowWasClosed() {
- delete this;
- instance_ = NULL;
-}
-
-int TaskManagerMac::RowCount() const {
- return model_->ResourceCount();
-}
-
-SkBitmap TaskManagerMac::GetIcon(int r) const {
- return model_->GetResourceIcon(r);
-}
-
-// static
-void TaskManagerMac::Show() {
- if (instance_) {
- // If there's a Task manager window open already, just activate it.
- [[instance_->window_controller_ window]
- makeKeyAndOrderFront:instance_->window_controller_];
- } else {
- instance_ = new TaskManagerMac(TaskManager::GetInstance());
- instance_->model_->StartUpdating();
- }
-}
diff --git a/chrome/browser/cocoa/task_manager_mac_unittest.mm b/chrome/browser/cocoa/task_manager_mac_unittest.mm
deleted file mode 100644
index c82928b..0000000
--- a/chrome/browser/cocoa/task_manager_mac_unittest.mm
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (c) 2009 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 "base/scoped_nsobject.h"
-#include "base/utf_string_conversions.h"
-#import "chrome/browser/cocoa/task_manager_mac.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "grit/generated_resources.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-namespace {
-
-class TestResource : public TaskManager::Resource {
- public:
- TestResource(const string16& title, pid_t pid) : title_(title), pid_(pid) {}
- virtual std::wstring GetTitle() const { return UTF16ToWide(title_); }
- virtual SkBitmap GetIcon() const { return SkBitmap(); }
- virtual base::ProcessHandle GetProcess() const { return pid_; }
- virtual Type GetType() const { return RENDERER; }
- virtual bool SupportNetworkUsage() const { return false; }
- virtual void SetSupportNetworkUsage() { NOTREACHED(); }
- virtual void Refresh() {}
- string16 title_;
- pid_t pid_;
-};
-
-} // namespace
-
-class TaskManagerWindowControllerTest : public CocoaTest {
-};
-
-// Test creation, to ensure nothing leaks or crashes.
-TEST_F(TaskManagerWindowControllerTest, Init) {
- TaskManager task_manager;
- TaskManagerMac* bridge(new TaskManagerMac(&task_manager));
- TaskManagerWindowController* controller = bridge->cocoa_controller();
-
- // Releases the controller, which in turn deletes |bridge|.
- [controller close];
-}
-
-TEST_F(TaskManagerWindowControllerTest, Sort) {
- TaskManager task_manager;
-
- TestResource resource1(UTF8ToUTF16("zzz"), 1);
- TestResource resource2(UTF8ToUTF16("zzb"), 2);
- TestResource resource3(UTF8ToUTF16("zza"), 2);
-
- task_manager.AddResource(&resource1);
- task_manager.AddResource(&resource2);
- task_manager.AddResource(&resource3); // Will be in the same group as 2.
-
- TaskManagerMac* bridge(new TaskManagerMac(&task_manager));
- TaskManagerWindowController* controller = bridge->cocoa_controller();
- NSTableView* table = [controller tableView];
- ASSERT_EQ(3, [controller numberOfRowsInTableView:table]);
-
- // Test that table is sorted on title.
- NSTableColumn* title_column = [table tableColumnWithIdentifier:
- [NSNumber numberWithInt:IDS_TASK_MANAGER_PAGE_COLUMN]];
- NSCell* cell;
- cell = [controller tableView:table dataCellForTableColumn:title_column row:0];
- EXPECT_NSEQ(@"zzb", [cell title]);
- cell = [controller tableView:table dataCellForTableColumn:title_column row:1];
- EXPECT_NSEQ(@"zza", [cell title]);
- cell = [controller tableView:table dataCellForTableColumn:title_column row:2];
- EXPECT_NSEQ(@"zzz", [cell title]);
-
- // Releases the controller, which in turn deletes |bridge|.
- [controller close];
-
- task_manager.RemoveResource(&resource1);
- task_manager.RemoveResource(&resource2);
- task_manager.RemoveResource(&resource3);
-}
-
-TEST_F(TaskManagerWindowControllerTest, SelectionAdaptsToSorting) {
- TaskManager task_manager;
-
- TestResource resource1(UTF8ToUTF16("yyy"), 1);
- TestResource resource2(UTF8ToUTF16("aaa"), 2);
-
- task_manager.AddResource(&resource1);
- task_manager.AddResource(&resource2);
-
- TaskManagerMac* bridge(new TaskManagerMac(&task_manager));
- TaskManagerWindowController* controller = bridge->cocoa_controller();
- NSTableView* table = [controller tableView];
- ASSERT_EQ(2, [controller numberOfRowsInTableView:table]);
-
- // Select row 0 in the table (corresponds to row 1 in the model).
- [table selectRowIndexes:[NSIndexSet indexSetWithIndex:0]
- byExtendingSelection:NO];
-
- // Change the name of resource2 so that it becomes row 1 in the table.
- resource2.title_ = UTF8ToUTF16("zzz");
- bridge->OnItemsChanged(1, 1);
-
- // Check that the selection has moved to row 1.
- NSIndexSet* selection = [table selectedRowIndexes];
- ASSERT_EQ(1u, [selection count]);
- EXPECT_EQ(1u, [selection firstIndex]);
-
- // Releases the controller, which in turn deletes |bridge|.
- [controller close];
-
- task_manager.RemoveResource(&resource1);
- task_manager.RemoveResource(&resource2);
-}
diff --git a/chrome/browser/cocoa/test_event_utils.h b/chrome/browser/cocoa/test_event_utils.h
deleted file mode 100644
index aeda255..0000000
--- a/chrome/browser/cocoa/test_event_utils.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_TEST_EVENT_UTILS_H_
-#define CHROME_BROWSER_COCOA_TEST_EVENT_UTILS_H_
-#pragma once
-
-#include <utility>
-
-#import <objc/objc-class.h>
-
-#include "base/basictypes.h"
-
-// Within a given scope, replace the selector |selector| on |target| with that
-// from |source|.
-class ScopedClassSwizzler {
- public:
- ScopedClassSwizzler(Class target, Class source, SEL selector);
- ~ScopedClassSwizzler();
-
- private:
- Method old_selector_impl_;
- Method new_selector_impl_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedClassSwizzler);
-};
-
-namespace test_event_utils {
-
-// Create synthetic mouse events for testing. Currently these are very
-// basic, flesh out as needed. Points are all in window coordinates;
-// where the window is not specified, coordinate system is undefined
-// (but will be repeated when the event is queried).
-NSEvent* MakeMouseEvent(NSEventType type, NSUInteger modifiers);
-NSEvent* MouseEventAtPoint(NSPoint point, NSEventType type,
- NSUInteger modifiers);
-NSEvent* LeftMouseDownAtPoint(NSPoint point);
-NSEvent* LeftMouseDownAtPointInWindow(NSPoint point, NSWindow* window);
-
-// Return a mouse down and an up event with the given |clickCount| at
-// |view|'s midpoint.
-std::pair<NSEvent*, NSEvent*> MouseClickInView(NSView* view,
- NSUInteger clickCount);
-
-} // namespace test_event_utils
-
-#endif // CHROME_BROWSER_COCOA_TEST_EVENT_UTILS_H_
diff --git a/chrome/browser/cocoa/test_event_utils.mm b/chrome/browser/cocoa/test_event_utils.mm
deleted file mode 100644
index 8016111..0000000
--- a/chrome/browser/cocoa/test_event_utils.mm
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/test_event_utils.h"
-
-ScopedClassSwizzler::ScopedClassSwizzler(Class target, Class source,
- SEL selector) {
- old_selector_impl_ = class_getInstanceMethod(target, selector);
- new_selector_impl_ = class_getInstanceMethod(source, selector);
- method_exchangeImplementations(old_selector_impl_, new_selector_impl_);
-}
-
-ScopedClassSwizzler::~ScopedClassSwizzler() {
- method_exchangeImplementations(old_selector_impl_, new_selector_impl_);
-}
-
-namespace test_event_utils {
-
-NSEvent* MouseEventAtPoint(NSPoint point, NSEventType type,
- NSUInteger modifiers) {
- if (type == NSOtherMouseUp) {
- // To synthesize middle clicks we need to create a CGEvent with the
- // "center" button flags so that our resulting NSEvent will have the
- // appropriate buttonNumber field. NSEvent provides no way to create a
- // mouse event with a buttonNumber directly.
- CGPoint location = { point.x, point.y };
- CGEventRef cg_event = CGEventCreateMouseEvent(NULL, kCGEventOtherMouseUp,
- location,
- kCGMouseButtonCenter);
- NSEvent* event = [NSEvent eventWithCGEvent:cg_event];
- CFRelease(cg_event);
- return event;
- }
- return [NSEvent mouseEventWithType:type
- location:point
- modifierFlags:modifiers
- timestamp:0
- windowNumber:0
- context:nil
- eventNumber:0
- clickCount:1
- pressure:1.0];
-}
-
-NSEvent* MakeMouseEvent(NSEventType type, NSUInteger modifiers) {
- return MouseEventAtPoint(NSMakePoint(0, 0), type, modifiers);
-}
-
-static NSEvent* MouseEventAtPointInWindow(NSPoint point,
- NSEventType type,
- NSWindow* window,
- NSUInteger clickCount) {
- return [NSEvent mouseEventWithType:type
- location:point
- modifierFlags:0
- timestamp:0
- windowNumber:[window windowNumber]
- context:nil
- eventNumber:0
- clickCount:clickCount
- pressure:1.0];
-}
-
-NSEvent* LeftMouseDownAtPointInWindow(NSPoint point, NSWindow* window) {
- return MouseEventAtPointInWindow(point, NSLeftMouseDown, window, 1);
-}
-
-NSEvent* LeftMouseDownAtPoint(NSPoint point) {
- return LeftMouseDownAtPointInWindow(point, nil);
-}
-
-std::pair<NSEvent*,NSEvent*> MouseClickInView(NSView* view,
- NSUInteger clickCount) {
- const NSRect bounds = [view convertRect:[view bounds] toView:nil];
- const NSPoint mid_point = NSMakePoint(NSMidX(bounds), NSMidY(bounds));
- NSEvent* down = MouseEventAtPointInWindow(mid_point, NSLeftMouseDown,
- [view window], clickCount);
- NSEvent* up = MouseEventAtPointInWindow(mid_point, NSLeftMouseUp,
- [view window], clickCount);
- return std::make_pair(down, up);
-}
-
-} // namespace test_event_utils
diff --git a/chrome/browser/cocoa/theme_install_bubble_view.h b/chrome/browser/cocoa/theme_install_bubble_view.h
deleted file mode 100644
index f8208df..0000000
--- a/chrome/browser/cocoa/theme_install_bubble_view.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// 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.
-
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
-
-@class NSWindow;
-@class ThemeInstallBubbleViewCocoa;
-
-// ThemeInstallBubbleView is a view that provides a "Loading..." bubble in the
-// center of a browser window for use when an extension or theme is loaded.
-// (The Browser class only calls it to install itself into the currently active
-// browser window.) If an extension is being applied, the bubble goes away
-// immediately. If a theme is being applied, it disappears when the theme has
-// been loaded. The purpose of this bubble is to warn the user that the browser
-// may be unresponsive while the theme is being installed.
-//
-// Edge case: note that if one installs a theme in one window and then switches
-// rapidly to another window to install a theme there as well (in the short time
-// between install begin and theme caching seizing the UI thread), the loading
-// bubble will only appear over the first window, as there is only ever one
-// instance of the bubble.
-class ThemeInstallBubbleView : public NotificationObserver {
- public:
- ~ThemeInstallBubbleView();
-
- // NotificationObserver
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- // Show the loading bubble.
- static void Show(NSWindow* window);
-
- private:
- explicit ThemeInstallBubbleView(NSWindow* window);
-
- // The one copy of the loading bubble.
- static ThemeInstallBubbleView* view_;
-
- // A scoped container for notification registries.
- NotificationRegistrar registrar_;
-
- // Shut down the popup and remove our notifications.
- void Close();
-
- // The actual Cocoa view implementing the bubble.
- ThemeInstallBubbleViewCocoa* cocoa_view_;
-
- // Multiple loads can be started at once. Only show one bubble, and keep
- // track of number of loads happening. Close bubble when num_loads < 1.
- int num_loads_extant_;
-
- DISALLOW_COPY_AND_ASSIGN(ThemeInstallBubbleView);
-};
diff --git a/chrome/browser/cocoa/theme_install_bubble_view.mm b/chrome/browser/cocoa/theme_install_bubble_view.mm
deleted file mode 100644
index 82c0e49..0000000
--- a/chrome/browser/cocoa/theme_install_bubble_view.mm
+++ /dev/null
@@ -1,186 +0,0 @@
-// Copyright (c) 2009 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>
-
-#import "chrome/browser/cocoa/theme_install_bubble_view.h"
-
-#include "app/l10n_util_mac.h"
-#include "base/scoped_nsobject.h"
-#include "grit/generated_resources.h"
-
-namespace {
-
-// The alpha of the bubble.
-static const float kBubbleAlpha = 0.75;
-
-// The roundedness of the edges of our bubble.
-static const int kBubbleCornerRadius = 4;
-
-// Padding around text in popup box.
-static const int kTextHorizPadding = 90;
-static const int kTextVertPadding = 45;
-
-// Point size of the text in the box.
-static const int kLoadingTextSize = 24;
-
-}
-
-// static
-ThemeInstallBubbleView* ThemeInstallBubbleView::view_ = NULL;
-
-// The Cocoa view to draw a gray rounded rect with "Loading..." in it.
-@interface ThemeInstallBubbleViewCocoa : NSView {
- @private
- scoped_nsobject<NSAttributedString> message_;
-
- NSRect grayRect_;
- NSRect textRect_;
-}
-
-- (id)init;
-
-// The size of the gray rect that will be drawn.
-- (NSSize)preferredSize;
-// Forces size calculations of where everything will be drawn.
-- (void)layout;
-
-@end
-
-ThemeInstallBubbleView::ThemeInstallBubbleView(NSWindow* window)
- : cocoa_view_([[ThemeInstallBubbleViewCocoa alloc] init]),
- num_loads_extant_(1) {
- DCHECK(window);
-
- NSView* parent_view = [window contentView];
- NSRect parent_bounds = [parent_view bounds];
- if (parent_bounds.size.height < [cocoa_view_ preferredSize].height)
- Close();
-
- // Close when theme has been installed.
- registrar_.Add(
- this,
- NotificationType::BROWSER_THEME_CHANGED,
- NotificationService::AllSources());
-
- // Close when we are installing an extension, not a theme.
- registrar_.Add(
- this,
- NotificationType::NO_THEME_DETECTED,
- NotificationService::AllSources());
- registrar_.Add(
- this,
- NotificationType::EXTENSION_INSTALLED,
- NotificationService::AllSources());
- registrar_.Add(
- this,
- NotificationType::EXTENSION_INSTALL_ERROR,
- NotificationService::AllSources());
-
- // Don't let the bubble overlap the confirm dialog.
- registrar_.Add(
- this,
- NotificationType::EXTENSION_WILL_SHOW_CONFIRM_DIALOG,
- NotificationService::AllSources());
-
- // Add the view.
- [cocoa_view_ setFrame:parent_bounds];
- [cocoa_view_ setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
- [parent_view addSubview:cocoa_view_
- positioned:NSWindowAbove
- relativeTo:nil];
- [cocoa_view_ layout];
-}
-
-ThemeInstallBubbleView::~ThemeInstallBubbleView() {
- // Need to delete self; the real work happens in Close().
-}
-
-void ThemeInstallBubbleView::Close() {
- --num_loads_extant_;
- if (num_loads_extant_ < 1) {
- registrar_.RemoveAll();
- if (cocoa_view_ && [cocoa_view_ superview]) {
- [cocoa_view_ removeFromSuperview];
- [cocoa_view_ release];
- }
- view_ = NULL;
- delete this;
- // this is deleted; nothing more!
- }
-}
-
-void ThemeInstallBubbleView::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- Close();
-}
-
-// static
-void ThemeInstallBubbleView::Show(NSWindow* window) {
- if (view_)
- ++view_->num_loads_extant_;
- else
- view_ = new ThemeInstallBubbleView(window);
-}
-
-@implementation ThemeInstallBubbleViewCocoa
-
-- (id)init {
- self = [super initWithFrame:NSZeroRect];
- if (self) {
- NSString* loadingString =
- l10n_util::GetNSStringWithFixup(IDS_THEME_LOADING_TITLE);
- NSFont* loadingFont = [NSFont systemFontOfSize:kLoadingTextSize];
- NSColor* textColor = [NSColor whiteColor];
- NSDictionary* loadingAttrs = [NSDictionary dictionaryWithObjectsAndKeys:
- loadingFont, NSFontAttributeName,
- textColor, NSForegroundColorAttributeName,
- nil];
- message_.reset([[NSAttributedString alloc] initWithString:loadingString
- attributes:loadingAttrs]);
-
- // TODO(avi): find a white-on-black spinner
- }
- return self;
-}
-
-- (NSSize)preferredSize {
- NSSize size = [message_.get() size];
- size.width += kTextHorizPadding;
- size.height += kTextVertPadding;
- return size;
-}
-
-// Update the layout to keep the view centered when the window is resized.
-- (void)resizeWithOldSuperviewSize:(NSSize)oldBoundsSize {
- [super resizeWithOldSuperviewSize:oldBoundsSize];
- [self layout];
-}
-
-- (void)layout {
- NSRect bounds = [self bounds];
-
- grayRect_.size = [self preferredSize];
- grayRect_.origin.x = (bounds.size.width - grayRect_.size.width) / 2;
- grayRect_.origin.y = bounds.size.height / 2;
-
- textRect_.size = [message_.get() size];
- textRect_.origin.x = (bounds.size.width - [message_.get() size].width) / 2;
- textRect_.origin.y = (bounds.size.height + kTextVertPadding) / 2;
-}
-
-- (void)drawRect:(NSRect)dirtyRect {
- [[NSColor clearColor] set];
- NSRectFillUsingOperation([self bounds], NSCompositeSourceOver);
-
- [[[NSColor blackColor] colorWithAlphaComponent:kBubbleAlpha] set];
- [[NSBezierPath bezierPathWithRoundedRect:grayRect_
- xRadius:kBubbleCornerRadius
- yRadius:kBubbleCornerRadius] fill];
-
- [message_.get() drawInRect:textRect_];
-}
-
-@end
diff --git a/chrome/browser/cocoa/themed_window.h b/chrome/browser/cocoa/themed_window.h
deleted file mode 100644
index 1e6d5fb..0000000
--- a/chrome/browser/cocoa/themed_window.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_THEMED_WINDOW_H_
-#define CHROME_BROWSER_COCOA_THEMED_WINDOW_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-class ThemeProvider;
-
-// Bit flags; mix-and-match as necessary.
-enum {
- THEMED_NORMAL = 0,
- THEMED_INCOGNITO = 1 << 0,
- THEMED_POPUP = 1 << 1,
- THEMED_DEVTOOLS = 1 << 2
-};
-typedef NSUInteger ThemedWindowStyle;
-
-// Implemented by windows that support theming.
-
-@interface NSWindow (ThemeProvider)
-- (ThemeProvider*)themeProvider;
-- (ThemedWindowStyle)themedWindowStyle;
-- (NSPoint)themePatternPhase;
-@end
-
-#endif // CHROME_BROWSER_COCOA_THEMED_WINDOW_H_
diff --git a/chrome/browser/cocoa/themed_window.mm b/chrome/browser/cocoa/themed_window.mm
deleted file mode 100644
index bde4057..0000000
--- a/chrome/browser/cocoa/themed_window.mm
+++ /dev/null
@@ -1,23 +0,0 @@
-// 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 "chrome/browser/cocoa/themed_window.h"
-
-// Default implementations; used mostly for tests so that the hosting windows
-// don't needs to know about the theming machinery.
-@implementation NSWindow (ThemeProvider)
-
-- (ThemeProvider*)themeProvider {
- return NULL;
-}
-
-- (ThemedWindowStyle)themedWindowStyle {
- return THEMED_NORMAL;
-}
-
-- (NSPoint)themePatternPhase {
- return NSZeroPoint;
-}
-
-@end
diff --git a/chrome/browser/cocoa/throbber_view.h b/chrome/browser/cocoa/throbber_view.h
deleted file mode 100644
index c9b7802..0000000
--- a/chrome/browser/cocoa/throbber_view.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_THROBBER_VIEW_H_
-#define CHROME_BROWSER_COCOA_THROBBER_VIEW_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_nsobject.h"
-
-@protocol ThrobberDataDelegate;
-
-// A class that knows how to draw an animated state to indicate progress.
-// Creating the class starts the animation, destroying it stops it. There are
-// two types:
-//
-// - Filmstrip: Draws via a sequence of frames in an image. There is no state
-// where the class is frozen on an image and not animating. The image needs to
-// be made of squares such that the height divides evenly into the width.
-//
-// - Toast: Draws an image animating down to the bottom and then another image
-// animating up from the bottom. Stops once the animation is complete.
-
-@interface ThrobberView : NSView {
- @private
- id<ThrobberDataDelegate> dataDelegate_;
-}
-
-// Creates a filmstrip view with |frame| and image |image|.
-+ (id)filmstripThrobberViewWithFrame:(NSRect)frame
- image:(NSImage*)image;
-
-// Creates a toast view with |frame| and specified images.
-+ (id)toastThrobberViewWithFrame:(NSRect)frame
- beforeImage:(NSImage*)beforeImage
- afterImage:(NSImage*)afterImage;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_THROBBER_VIEW_H_
diff --git a/chrome/browser/cocoa/throbber_view.mm b/chrome/browser/cocoa/throbber_view.mm
deleted file mode 100644
index 5a50034..0000000
--- a/chrome/browser/cocoa/throbber_view.mm
+++ /dev/null
@@ -1,372 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/throbber_view.h"
-
-#include <set>
-
-#include "base/logging.h"
-
-static const float kAnimationIntervalSeconds = 0.03; // 30ms, same as windows
-
-@interface ThrobberView(PrivateMethods)
-- (id)initWithFrame:(NSRect)frame delegate:(id<ThrobberDataDelegate>)delegate;
-- (void)maintainTimer;
-- (void)animate;
-@end
-
-@protocol ThrobberDataDelegate <NSObject>
-// Is the current frame the last frame of the animation?
-- (BOOL)animationIsComplete;
-
-// Draw the current frame into the current graphics context.
-- (void)drawFrameInRect:(NSRect)rect;
-
-// Update the frame counter.
-- (void)advanceFrame;
-@end
-
-@interface ThrobberFilmstripDelegate : NSObject
- <ThrobberDataDelegate> {
- scoped_nsobject<NSImage> image_;
- unsigned int numFrames_; // Number of frames in this animation.
- unsigned int animationFrame_; // Current frame of the animation,
- // [0..numFrames_)
-}
-
-- (id)initWithImage:(NSImage*)image;
-
-@end
-
-@implementation ThrobberFilmstripDelegate
-
-- (id)initWithImage:(NSImage*)image {
- if ((self = [super init])) {
- // Reset the animation counter so there's no chance we are off the end.
- animationFrame_ = 0;
-
- // Ensure that the height divides evenly into the width. Cache the
- // number of frames in the animation for later.
- NSSize imageSize = [image size];
- DCHECK(imageSize.height && imageSize.width);
- if (!imageSize.height)
- return nil;
- DCHECK((int)imageSize.width % (int)imageSize.height == 0);
- numFrames_ = (int)imageSize.width / (int)imageSize.height;
- DCHECK(numFrames_);
- image_.reset([image retain]);
- }
- return self;
-}
-
-- (BOOL)animationIsComplete {
- return NO;
-}
-
-- (void)drawFrameInRect:(NSRect)rect {
- float imageDimension = [image_ size].height;
- float xOffset = animationFrame_ * imageDimension;
- NSRect sourceImageRect =
- NSMakeRect(xOffset, 0, imageDimension, imageDimension);
- [image_ drawInRect:rect
- fromRect:sourceImageRect
- operation:NSCompositeSourceOver
- fraction:1.0];
-}
-
-- (void)advanceFrame {
- animationFrame_ = ++animationFrame_ % numFrames_;
-}
-
-@end
-
-@interface ThrobberToastDelegate : NSObject
- <ThrobberDataDelegate> {
- scoped_nsobject<NSImage> image1_;
- scoped_nsobject<NSImage> image2_;
- NSSize image1Size_;
- NSSize image2Size_;
- int animationFrame_; // Current frame of the animation,
-}
-
-- (id)initWithImage1:(NSImage*)image1 image2:(NSImage*)image2;
-
-@end
-
-@implementation ThrobberToastDelegate
-
-- (id)initWithImage1:(NSImage*)image1 image2:(NSImage*)image2 {
- if ((self = [super init])) {
- image1_.reset([image1 retain]);
- image2_.reset([image2 retain]);
- image1Size_ = [image1 size];
- image2Size_ = [image2 size];
- animationFrame_ = 0;
- }
- return self;
-}
-
-- (BOOL)animationIsComplete {
- if (animationFrame_ >= image1Size_.height + image2Size_.height)
- return YES;
-
- return NO;
-}
-
-// From [0..image1Height) we draw image1, at image1Height we draw nothing, and
-// from [image1Height+1..image1Hight+image2Height] we draw the second image.
-- (void)drawFrameInRect:(NSRect)rect {
- NSImage* image = nil;
- NSSize srcSize;
- NSRect destRect;
-
- if (animationFrame_ < image1Size_.height) {
- image = image1_.get();
- srcSize = image1Size_;
- destRect = NSMakeRect(0, -animationFrame_,
- image1Size_.width, image1Size_.height);
- } else if (animationFrame_ == image1Size_.height) {
- // nothing; intermediate blank frame
- } else {
- image = image2_.get();
- srcSize = image2Size_;
- destRect = NSMakeRect(0, animationFrame_ -
- (image1Size_.height + image2Size_.height),
- image2Size_.width, image2Size_.height);
- }
-
- if (image) {
- NSRect sourceImageRect =
- NSMakeRect(0, 0, srcSize.width, srcSize.height);
- [image drawInRect:destRect
- fromRect:sourceImageRect
- operation:NSCompositeSourceOver
- fraction:1.0];
- }
-}
-
-- (void)advanceFrame {
- ++animationFrame_;
-}
-
-@end
-
-typedef std::set<ThrobberView*> ThrobberSet;
-
-// ThrobberTimer manages the animation of a set of ThrobberViews. It allows
-// a single timer instance to be shared among as many ThrobberViews as needed.
-@interface ThrobberTimer : NSObject {
- @private
- // A set of weak references to each ThrobberView that should be notified
- // whenever the timer fires.
- ThrobberSet throbbers_;
-
- // Weak reference to the timer that calls back to this object. The timer
- // retains this object.
- NSTimer* timer_;
-
- // Whether the timer is actively running. To avoid timer construction
- // and destruction overhead, the timer is not invalidated when it is not
- // needed, but its next-fire date is set to [NSDate distantFuture].
- // It is not possible to determine whether the timer has been suspended by
- // comparing its fireDate to [NSDate distantFuture], though, so a separate
- // variable is used to track this state.
- BOOL timerRunning_;
-
- // The thread that created this object. Used to validate that ThrobberViews
- // are only added and removed on the same thread that the fire action will
- // be performed on.
- NSThread* validThread_;
-}
-
-// Returns a shared ThrobberTimer. Everyone is expected to use the same
-// instance.
-+ (ThrobberTimer*)sharedThrobberTimer;
-
-// Invalidates the timer, which will cause it to remove itself from the run
-// loop. This causes the timer to be released, and it should then release
-// this object.
-- (void)invalidate;
-
-// Adds or removes ThrobberView objects from the throbbers_ set.
-- (void)addThrobber:(ThrobberView*)throbber;
-- (void)removeThrobber:(ThrobberView*)throbber;
-@end
-
-@interface ThrobberTimer(PrivateMethods)
-// Starts or stops the timer as needed as ThrobberViews are added and removed
-// from the throbbers_ set.
-- (void)maintainTimer;
-
-// Calls animate on each ThrobberView in the throbbers_ set.
-- (void)fire:(NSTimer*)timer;
-@end
-
-@implementation ThrobberTimer
-- (id)init {
- if ((self = [super init])) {
- // Start out with a timer that fires at the appropriate interval, but
- // prevent it from firing by setting its next-fire date to the distant
- // future. Once a ThrobberView is added, the timer will be allowed to
- // start firing.
- timer_ = [NSTimer scheduledTimerWithTimeInterval:kAnimationIntervalSeconds
- target:self
- selector:@selector(fire:)
- userInfo:nil
- repeats:YES];
- [timer_ setFireDate:[NSDate distantFuture]];
- timerRunning_ = NO;
-
- validThread_ = [NSThread currentThread];
- }
- return self;
-}
-
-+ (ThrobberTimer*)sharedThrobberTimer {
- // Leaked. That's OK, it's scoped to the lifetime of the application.
- static ThrobberTimer* sharedInstance = [[ThrobberTimer alloc] init];
- return sharedInstance;
-}
-
-- (void)invalidate {
- [timer_ invalidate];
-}
-
-- (void)addThrobber:(ThrobberView*)throbber {
- DCHECK([NSThread currentThread] == validThread_);
- throbbers_.insert(throbber);
- [self maintainTimer];
-}
-
-- (void)removeThrobber:(ThrobberView*)throbber {
- DCHECK([NSThread currentThread] == validThread_);
- throbbers_.erase(throbber);
- [self maintainTimer];
-}
-
-- (void)maintainTimer {
- BOOL oldRunning = timerRunning_;
- BOOL newRunning = throbbers_.empty() ? NO : YES;
-
- if (oldRunning == newRunning)
- return;
-
- // To start the timer, set its next-fire date to an appropriate interval from
- // now. To suspend the timer, set its next-fire date to a preposterous time
- // in the future.
- NSDate* fireDate;
- if (newRunning)
- fireDate = [NSDate dateWithTimeIntervalSinceNow:kAnimationIntervalSeconds];
- else
- fireDate = [NSDate distantFuture];
-
- [timer_ setFireDate:fireDate];
- timerRunning_ = newRunning;
-}
-
-- (void)fire:(NSTimer*)timer {
- // The call to [throbber animate] may result in the ThrobberView calling
- // removeThrobber: if it decides it's done animating. That would invalidate
- // the iterator, making it impossible to correctly get to the next element
- // in the set. To prevent that from happening, a second iterator is used
- // and incremented before calling [throbber animate].
- ThrobberSet::const_iterator current = throbbers_.begin();
- ThrobberSet::const_iterator next = current;
- while (current != throbbers_.end()) {
- ++next;
- ThrobberView* throbber = *current;
- [throbber animate];
- current = next;
- }
-}
-@end
-
-@implementation ThrobberView
-
-+ (id)filmstripThrobberViewWithFrame:(NSRect)frame
- image:(NSImage*)image {
- ThrobberFilmstripDelegate* delegate =
- [[[ThrobberFilmstripDelegate alloc] initWithImage:image] autorelease];
- if (!delegate)
- return nil;
-
- return [[[ThrobberView alloc] initWithFrame:frame
- delegate:delegate] autorelease];
-}
-
-+ (id)toastThrobberViewWithFrame:(NSRect)frame
- beforeImage:(NSImage*)beforeImage
- afterImage:(NSImage*)afterImage {
- ThrobberToastDelegate* delegate =
- [[[ThrobberToastDelegate alloc] initWithImage1:beforeImage
- image2:afterImage] autorelease];
- if (!delegate)
- return nil;
-
- return [[[ThrobberView alloc] initWithFrame:frame
- delegate:delegate] autorelease];
-}
-
-- (id)initWithFrame:(NSRect)frame delegate:(id<ThrobberDataDelegate>)delegate {
- if ((self = [super initWithFrame:frame])) {
- dataDelegate_ = [delegate retain];
- }
- return self;
-}
-
-- (void)dealloc {
- [dataDelegate_ release];
- [[ThrobberTimer sharedThrobberTimer] removeThrobber:self];
-
- [super dealloc];
-}
-
-// Manages this ThrobberView's membership in the shared throbber timer set on
-// the basis of its visibility and whether its animation needs to continue
-// running.
-- (void)maintainTimer {
- ThrobberTimer* throbberTimer = [ThrobberTimer sharedThrobberTimer];
-
- if ([self window] && ![self isHidden] && ![dataDelegate_ animationIsComplete])
- [throbberTimer addThrobber:self];
- else
- [throbberTimer removeThrobber:self];
-}
-
-// A ThrobberView added to a window may need to begin animating; a ThrobberView
-// removed from a window should stop.
-- (void)viewDidMoveToWindow {
- [self maintainTimer];
- [super viewDidMoveToWindow];
-}
-
-// A hidden ThrobberView should stop animating.
-- (void)viewDidHide {
- [self maintainTimer];
- [super viewDidHide];
-}
-
-// A visible ThrobberView may need to start animating.
-- (void)viewDidUnhide {
- [self maintainTimer];
- [super viewDidUnhide];
-}
-
-// Called when the timer fires. Advance the frame, dirty the display, and remove
-// the throbber if it's no longer needed.
-- (void)animate {
- [dataDelegate_ advanceFrame];
- [self setNeedsDisplay:YES];
-
- if ([dataDelegate_ animationIsComplete]) {
- [[ThrobberTimer sharedThrobberTimer] removeThrobber:self];
- }
-}
-
-// Overridden to draw the appropriate frame in the image strip.
-- (void)drawRect:(NSRect)rect {
- [dataDelegate_ drawFrameInRect:[self bounds]];
-}
-
-@end
diff --git a/chrome/browser/cocoa/throbber_view_unittest.mm b/chrome/browser/cocoa/throbber_view_unittest.mm
deleted file mode 100644
index 26a027d..0000000
--- a/chrome/browser/cocoa/throbber_view_unittest.mm
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) 2009 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 "app/resource_bundle.h"
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/throbber_view.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-#include "grit/app_resources.h"
-
-namespace {
-
-class ThrobberViewTest : public CocoaTest {
- public:
- ThrobberViewTest() {
- NSRect frame = NSMakeRect(10, 10, 16, 16);
- NSImage* image =
- ResourceBundle::GetSharedInstance().GetNativeImageNamed(IDR_THROBBER);
- view_ = [ThrobberView filmstripThrobberViewWithFrame:frame image:image];
- [[test_window() contentView] addSubview:view_];
- }
-
- ThrobberView* view_;
-};
-
-TEST_VIEW(ThrobberViewTest, view_)
-
-} // namespace
diff --git a/chrome/browser/cocoa/toolbar_controller.h b/chrome/browser/cocoa/toolbar_controller.h
deleted file mode 100644
index 9e0c2bc..0000000
--- a/chrome/browser/cocoa/toolbar_controller.h
+++ /dev/null
@@ -1,189 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_TOOLBAR_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_TOOLBAR_CONTROLLER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_ptr.h"
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/command_observer_bridge.h"
-#import "chrome/browser/cocoa/delayedmenu_button.h"
-#import "chrome/browser/cocoa/url_drop_target.h"
-#import "chrome/browser/cocoa/view_resizer.h"
-#include "chrome/browser/prefs/pref_member.h"
-
-@class AutocompleteTextField;
-@class AutocompleteTextFieldEditor;
-@class BrowserActionsContainerView;
-@class BackForwardMenuController;
-class Browser;
-@class BrowserActionsController;
-class CommandUpdater;
-@class DelayedMenuButton;
-class LocationBar;
-class LocationBarViewMac;
-@class MenuButton;
-namespace ToolbarControllerInternal {
-class NotificationBridge;
-class WrenchAcceleratorDelegate;
-} // namespace ToolbarControllerInternal
-class Profile;
-@class ReloadButton;
-class TabContents;
-class ToolbarModel;
-@class WrenchMenuController;
-class WrenchMenuModel;
-
-// A controller for the toolbar in the browser window. Manages
-// updating the state for location bar and back/fwd/reload/go buttons.
-// Manages the bookmark bar and its position in the window relative to
-// the web content view.
-
-@interface ToolbarController : NSViewController<CommandObserverProtocol,
- URLDropTargetController> {
- @protected
- // The ordering is important for unit tests. If new items are added or the
- // ordering is changed, make sure to update |-toolbarViews| and the
- // corresponding enum in the unit tests.
- IBOutlet DelayedMenuButton* backButton_;
- IBOutlet DelayedMenuButton* forwardButton_;
- IBOutlet ReloadButton* reloadButton_;
- IBOutlet NSButton* homeButton_;
- IBOutlet MenuButton* wrenchButton_;
- IBOutlet AutocompleteTextField* locationBar_;
- IBOutlet BrowserActionsContainerView* browserActionsContainerView_;
- IBOutlet WrenchMenuController* wrenchMenuController_;
-
- @private
- ToolbarModel* toolbarModel_; // weak, one per window
- CommandUpdater* commands_; // weak, one per window
- Profile* profile_; // weak, one per window
- Browser* browser_; // weak, one per window
- scoped_ptr<CommandObserverBridge> commandObserver_;
- scoped_ptr<LocationBarViewMac> locationBarView_;
- scoped_nsobject<AutocompleteTextFieldEditor> autocompleteTextFieldEditor_;
- id<ViewResizer> resizeDelegate_; // weak
- scoped_nsobject<BackForwardMenuController> backMenuController_;
- scoped_nsobject<BackForwardMenuController> forwardMenuController_;
- scoped_nsobject<BrowserActionsController> browserActionsController_;
-
- // Lazily-instantiated model and delegate for the menu on the
- // wrench button. Once visible, it will be non-null, but will not
- // reaped when the menu is hidden once it is initially shown.
- scoped_ptr<ToolbarControllerInternal::WrenchAcceleratorDelegate>
- acceleratorDelegate_;
- scoped_ptr<WrenchMenuModel> wrenchMenuModel_;
-
- // Used for monitoring the optional toolbar button prefs.
- scoped_ptr<ToolbarControllerInternal::NotificationBridge> notificationBridge_;
- BooleanPrefMember showHomeButton_;
- BooleanPrefMember showPageOptionButtons_;
- BOOL hasToolbar_; // If NO, we may have only the location bar.
- BOOL hasLocationBar_; // If |hasToolbar_| is YES, this must also be YES.
- BOOL locationBarAtMinSize_; // If the location bar is at the minimum size.
-
- // We have an extra retain in the locationBar_.
- // See comments in awakeFromNib for more info.
- scoped_nsobject<AutocompleteTextField> locationBarRetainer_;
-
- // Tracking area for mouse enter/exit/moved in the toolbar.
- scoped_nsobject<NSTrackingArea> trackingArea_;
-
- // We retain/release the hover button since interaction with the
- // button may make it go away (e.g. delete menu option over a
- // bookmark button). Thus this variable is not weak. The
- // hoveredButton_ is required to have an NSCell that responds to
- // setMouseInside:animate:.
- NSButton* hoveredButton_;
-}
-
-// Initialize the toolbar and register for command updates. The profile is
-// needed for initializing the location bar. The browser is needed for
-// initializing the back/forward menus.
-- (id)initWithModel:(ToolbarModel*)model
- commands:(CommandUpdater*)commands
- profile:(Profile*)profile
- browser:(Browser*)browser
- resizeDelegate:(id<ViewResizer>)resizeDelegate;
-
-// Get the C++ bridge object representing the location bar for this tab.
-- (LocationBarViewMac*)locationBarBridge;
-
-// Called by the Window delegate so we can provide a custom field editor if
-// needed.
-// Note that this may be called for objects unrelated to the toolbar.
-// returns nil if we don't want to override the custom field editor for |obj|.
-- (id)customFieldEditorForObject:(id)obj;
-
-// Make the location bar the first responder, if possible.
-- (void)focusLocationBar:(BOOL)selectAll;
-
-// Updates the toolbar (and transitively the location bar) with the states of
-// the specified |tab|. If |shouldRestore| is true, we're switching
-// (back?) to this tab and should restore any previous location bar state
-// (such as user editing) as well.
-- (void)updateToolbarWithContents:(TabContents*)tabForRestoring
- shouldRestoreState:(BOOL)shouldRestore;
-
-// Sets whether or not the current page in the frontmost tab is bookmarked.
-- (void)setStarredState:(BOOL)isStarred;
-
-// Called to update the loading state. Handles updating the go/stop
-// button state. |force| is set if the update is due to changing
-// tabs, as opposed to the page-load finishing. See comment in
-// reload_button.h.
-- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force;
-
-// Allow turning off the toolbar (but we may keep the location bar without a
-// surrounding toolbar). If |toolbar| is YES, the value of |hasLocationBar| is
-// ignored. This changes the behavior of other methods, like |-view|.
-- (void)setHasToolbar:(BOOL)toolbar hasLocationBar:(BOOL)locBar;
-
-// Point on the star icon for the bookmark bubble to be - in the
-// associated window's coordinate system.
-- (NSPoint)bookmarkBubblePoint;
-
-// Returns the desired toolbar height for the given compression factor.
-- (CGFloat)desiredHeightForCompression:(CGFloat)compressByHeight;
-
-// Set the opacity of the divider (the line at the bottom) *if* we have a
-// |ToolbarView| (0 means don't show it); no-op otherwise.
-- (void)setDividerOpacity:(CGFloat)opacity;
-
-// Create and add the Browser Action buttons to the toolbar view.
-- (void)createBrowserActionButtons;
-
-// Return the BrowserActionsController for this toolbar.
-- (BrowserActionsController*)browserActionsController;
-
-@end
-
-// A set of private methods used by subclasses. Do not call these directly
-// unless a subclass of ToolbarController.
-@interface ToolbarController(ProtectedMethods)
-// Designated initializer which takes a nib name in order to allow subclasses
-// to load a different nib file.
-- (id)initWithModel:(ToolbarModel*)model
- commands:(CommandUpdater*)commands
- profile:(Profile*)profile
- browser:(Browser*)browser
- resizeDelegate:(id<ViewResizer>)resizeDelegate
- nibFileNamed:(NSString*)nibName;
-@end
-
-// A set of private methods used by tests, in the absence of "friends" in ObjC.
-@interface ToolbarController(PrivateTestMethods)
-// Returns an array of views in the order of the outlets above.
-- (NSArray*)toolbarViews;
-- (void)showOptionalHomeButton;
-- (void)installWrenchMenu;
-- (WrenchMenuController*)wrenchMenuController;
-// Return a hover button for the current event.
-- (NSButton*)hoverButtonForEvent:(NSEvent*)theEvent;
-@end
-
-#endif // CHROME_BROWSER_COCOA_TOOLBAR_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/toolbar_controller.mm b/chrome/browser/cocoa/toolbar_controller.mm
deleted file mode 100644
index 3d87363..0000000
--- a/chrome/browser/cocoa/toolbar_controller.mm
+++ /dev/null
@@ -1,753 +0,0 @@
-// 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 "chrome/browser/cocoa/toolbar_controller.h"
-
-#include <algorithm>
-
-#include "app/l10n_util.h"
-#include "app/l10n_util_mac.h"
-#include "app/menus/accelerator_cocoa.h"
-#include "app/menus/menu_model.h"
-#include "base/mac_util.h"
-#include "base/nsimage_cache_mac.h"
-#include "base/singleton.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/autocomplete/autocomplete_edit_view.h"
-#import "chrome/browser/cocoa/accelerators_cocoa.h"
-#import "chrome/browser/cocoa/back_forward_menu_controller.h"
-#import "chrome/browser/cocoa/background_gradient_view.h"
-#import "chrome/browser/cocoa/encoding_menu_controller_delegate_mac.h"
-#import "chrome/browser/cocoa/extensions/browser_action_button.h"
-#import "chrome/browser/cocoa/extensions/browser_actions_container_view.h"
-#import "chrome/browser/cocoa/extensions/browser_actions_controller.h"
-#import "chrome/browser/cocoa/gradient_button_cell.h"
-#import "chrome/browser/cocoa/location_bar/autocomplete_text_field_editor.h"
-#import "chrome/browser/cocoa/location_bar/location_bar_view_mac.h"
-#import "chrome/browser/cocoa/menu_button.h"
-#import "chrome/browser/cocoa/menu_controller.h"
-#import "chrome/browser/cocoa/reload_button.h"
-#import "chrome/browser/cocoa/toolbar_view.h"
-#import "chrome/browser/cocoa/view_id_util.h"
-#import "chrome/browser/cocoa/wrench_menu_controller.h"
-#include "chrome/browser/net/url_fixer_upper.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/search_engines/template_url_model.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/themes/browser_theme_provider.h"
-#include "chrome/browser/toolbar_model.h"
-#include "chrome/browser/upgrade_detector.h"
-#include "chrome/browser/wrench_menu_model.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/common/notification_details.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/notification_type.h"
-#include "chrome/common/pref_names.h"
-#include "gfx/rect.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-
-namespace {
-
-// Names of images in the bundle for buttons.
-NSString* const kBackButtonImageName = @"back_Template.pdf";
-NSString* const kForwardButtonImageName = @"forward_Template.pdf";
-NSString* const kReloadButtonReloadImageName = @"reload_Template.pdf";
-NSString* const kReloadButtonStopImageName = @"stop_Template.pdf";
-NSString* const kHomeButtonImageName = @"home_Template.pdf";
-NSString* const kWrenchButtonImageName = @"tools_Template.pdf";
-
-// Height of the toolbar in pixels when the bookmark bar is closed.
-const CGFloat kBaseToolbarHeight = 35.0;
-
-// The minimum width of the location bar in pixels.
-const CGFloat kMinimumLocationBarWidth = 100.0;
-
-// The duration of any animation that occurs within the toolbar in seconds.
-const CGFloat kAnimationDuration = 0.2;
-
-// The amount of left padding that the wrench menu should have.
-const CGFloat kWrenchMenuLeftPadding = 3.0;
-
-} // namespace
-
-@interface ToolbarController(Private)
-- (void)addAccessibilityDescriptions;
-- (void)initCommandStatus:(CommandUpdater*)commands;
-- (void)prefChanged:(std::string*)prefName;
-- (BackgroundGradientView*)backgroundGradientView;
-- (void)toolbarFrameChanged;
-- (void)pinLocationBarToLeftOfBrowserActionsContainerAndAnimate:(BOOL)animate;
-- (void)maintainMinimumLocationBarWidth;
-- (void)adjustBrowserActionsContainerForNewWindow:(NSNotification*)notification;
-- (void)browserActionsContainerDragged:(NSNotification*)notification;
-- (void)browserActionsContainerDragFinished:(NSNotification*)notification;
-- (void)browserActionsVisibilityChanged:(NSNotification*)notification;
-- (void)adjustLocationSizeBy:(CGFloat)dX animate:(BOOL)animate;
-- (void)badgeWrenchMenu;
-@end
-
-namespace ToolbarControllerInternal {
-
-// A C++ delegate that handles the accelerators in the wrench menu.
-class WrenchAcceleratorDelegate : public menus::AcceleratorProvider {
- public:
- virtual bool GetAcceleratorForCommandId(int command_id,
- menus::Accelerator* accelerator_generic) {
- // Downcast so that when the copy constructor is invoked below, the key
- // string gets copied, too.
- menus::AcceleratorCocoa* out_accelerator =
- static_cast<menus::AcceleratorCocoa*>(accelerator_generic);
- AcceleratorsCocoa* keymap = Singleton<AcceleratorsCocoa>::get();
- const menus::AcceleratorCocoa* accelerator =
- keymap->GetAcceleratorForCommand(command_id);
- if (accelerator) {
- *out_accelerator = *accelerator;
- return true;
- }
- return false;
- }
-};
-
-// A class registered for C++ notifications. This is used to detect changes in
-// preferences and upgrade available notifications. Bridges the notification
-// back to the ToolbarController.
-class NotificationBridge : public NotificationObserver {
- public:
- explicit NotificationBridge(ToolbarController* controller)
- : controller_(controller) {
- registrar_.Add(this, NotificationType::UPGRADE_RECOMMENDED,
- NotificationService::AllSources());
- }
-
- // Overridden from NotificationObserver:
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- if (type == NotificationType::PREF_CHANGED)
- [controller_ prefChanged:Details<std::string>(details).ptr()];
- else if (type == NotificationType::UPGRADE_RECOMMENDED)
- [controller_ badgeWrenchMenu];
- }
-
- private:
- ToolbarController* controller_; // weak, owns us
-
- NotificationRegistrar registrar_;
-};
-
-} // namespace ToolbarControllerInternal
-
-@implementation ToolbarController
-
-- (id)initWithModel:(ToolbarModel*)model
- commands:(CommandUpdater*)commands
- profile:(Profile*)profile
- browser:(Browser*)browser
- resizeDelegate:(id<ViewResizer>)resizeDelegate
- nibFileNamed:(NSString*)nibName {
- DCHECK(model && commands && profile && [nibName length]);
- if ((self = [super initWithNibName:nibName
- bundle:mac_util::MainAppBundle()])) {
- toolbarModel_ = model;
- commands_ = commands;
- profile_ = profile;
- browser_ = browser;
- resizeDelegate_ = resizeDelegate;
- hasToolbar_ = YES;
- hasLocationBar_ = YES;
-
- // Register for notifications about state changes for the toolbar buttons
- commandObserver_.reset(new CommandObserverBridge(self, commands));
- commandObserver_->ObserveCommand(IDC_BACK);
- commandObserver_->ObserveCommand(IDC_FORWARD);
- commandObserver_->ObserveCommand(IDC_RELOAD);
- commandObserver_->ObserveCommand(IDC_HOME);
- commandObserver_->ObserveCommand(IDC_BOOKMARK_PAGE);
- }
- return self;
-}
-
-- (id)initWithModel:(ToolbarModel*)model
- commands:(CommandUpdater*)commands
- profile:(Profile*)profile
- browser:(Browser*)browser
- resizeDelegate:(id<ViewResizer>)resizeDelegate {
- if ((self = [self initWithModel:model
- commands:commands
- profile:profile
- browser:browser
- resizeDelegate:resizeDelegate
- nibFileNamed:@"Toolbar"])) {
- }
- return self;
-}
-
-
-- (void)dealloc {
- // Unset ViewIDs of toolbar elements.
- // ViewIDs of |toolbarView|, |reloadButton_|, |locationBar_| and
- // |browserActionsContainerView_| are handled by themselves.
- view_id_util::UnsetID(backButton_);
- view_id_util::UnsetID(forwardButton_);
- view_id_util::UnsetID(homeButton_);
- view_id_util::UnsetID(wrenchButton_);
-
- // Make sure any code in the base class which assumes [self view] is
- // the "parent" view continues to work.
- hasToolbar_ = YES;
- hasLocationBar_ = YES;
-
- [[NSNotificationCenter defaultCenter] removeObserver:self];
-
- if (trackingArea_.get())
- [[self view] removeTrackingArea:trackingArea_.get()];
- [super dealloc];
-}
-
-// Called after the view is done loading and the outlets have been hooked up.
-// Now we can hook up bridges that rely on UI objects such as the location
-// bar and button state.
-- (void)awakeFromNib {
- // A bug in AppKit (<rdar://7298597>, <http://openradar.me/7298597>) causes
- // images loaded directly from nibs in a framework to not get their "template"
- // flags set properly. Thus, despite the images being set on the buttons in
- // the xib, we must set them in code.
- [backButton_ setImage:nsimage_cache::ImageNamed(kBackButtonImageName)];
- [forwardButton_ setImage:nsimage_cache::ImageNamed(kForwardButtonImageName)];
- [reloadButton_
- setImage:nsimage_cache::ImageNamed(kReloadButtonReloadImageName)];
- [homeButton_ setImage:nsimage_cache::ImageNamed(kHomeButtonImageName)];
- [wrenchButton_ setImage:nsimage_cache::ImageNamed(kWrenchButtonImageName)];
-
- if (Singleton<UpgradeDetector>::get()->notify_upgrade())
- [self badgeWrenchMenu];
-
- [backButton_ setShowsBorderOnlyWhileMouseInside:YES];
- [forwardButton_ setShowsBorderOnlyWhileMouseInside:YES];
- [reloadButton_ setShowsBorderOnlyWhileMouseInside:YES];
- [homeButton_ setShowsBorderOnlyWhileMouseInside:YES];
- [wrenchButton_ setShowsBorderOnlyWhileMouseInside:YES];
-
- [self initCommandStatus:commands_];
- locationBarView_.reset(new LocationBarViewMac(locationBar_,
- commands_, toolbarModel_,
- profile_, browser_));
- [locationBar_ setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]];
- // Register pref observers for the optional home and page/options buttons
- // and then add them to the toolbar based on those prefs.
- notificationBridge_.reset(
- new ToolbarControllerInternal::NotificationBridge(self));
- PrefService* prefs = profile_->GetPrefs();
- showHomeButton_.Init(prefs::kShowHomeButton, prefs,
- notificationBridge_.get());
- showPageOptionButtons_.Init(prefs::kShowPageOptionsButtons, prefs,
- notificationBridge_.get());
- [self showOptionalHomeButton];
- [self installWrenchMenu];
-
- // Create the controllers for the back/forward menus.
- backMenuController_.reset([[BackForwardMenuController alloc]
- initWithBrowser:browser_
- modelType:BACK_FORWARD_MENU_TYPE_BACK
- button:backButton_]);
- forwardMenuController_.reset([[BackForwardMenuController alloc]
- initWithBrowser:browser_
- modelType:BACK_FORWARD_MENU_TYPE_FORWARD
- button:forwardButton_]);
-
- // For a popup window, the toolbar is really just a location bar
- // (see override for [ToolbarController view], below). When going
- // fullscreen, we remove the toolbar controller's view from the view
- // hierarchy. Calling [locationBar_ removeFromSuperview] when going
- // fullscreen causes it to get released, making us unhappy
- // (http://crbug.com/18551). We avoid the problem by incrementing
- // the retain count of the location bar; use of the scoped object
- // helps us remember to release it.
- locationBarRetainer_.reset([locationBar_ retain]);
- trackingArea_.reset(
- [[NSTrackingArea alloc] initWithRect:NSZeroRect // Ignored
- options:NSTrackingMouseMoved |
- NSTrackingInVisibleRect |
- NSTrackingMouseEnteredAndExited |
- NSTrackingActiveAlways
- owner:self
- userInfo:nil]);
- NSView* toolbarView = [self view];
- [toolbarView addTrackingArea:trackingArea_.get()];
-
- // If the user has any Browser Actions installed, the container view for them
- // may have to be resized depending on the width of the toolbar frame.
- [toolbarView setPostsFrameChangedNotifications:YES];
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(toolbarFrameChanged)
- name:NSViewFrameDidChangeNotification
- object:toolbarView];
-
- // Set ViewIDs for toolbar elements which don't have their dedicated class.
- // ViewIDs of |toolbarView|, |reloadButton_|, |locationBar_| and
- // |browserActionsContainerView_| are handled by themselves.
- view_id_util::SetID(backButton_, VIEW_ID_BACK_BUTTON);
- view_id_util::SetID(forwardButton_, VIEW_ID_FORWARD_BUTTON);
- view_id_util::SetID(homeButton_, VIEW_ID_HOME_BUTTON);
- view_id_util::SetID(wrenchButton_, VIEW_ID_APP_MENU);
-
- [self addAccessibilityDescriptions];
-}
-
-- (void)addAccessibilityDescriptions {
- // Set accessibility descriptions. http://openradar.appspot.com/7496255
- NSString* description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_BACK);
- [[backButton_ cell]
- accessibilitySetOverrideValue:description
- forAttribute:NSAccessibilityDescriptionAttribute];
- description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_FORWARD);
- [[forwardButton_ cell]
- accessibilitySetOverrideValue:description
- forAttribute:NSAccessibilityDescriptionAttribute];
- description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_RELOAD);
- [[reloadButton_ cell]
- accessibilitySetOverrideValue:description
- forAttribute:NSAccessibilityDescriptionAttribute];
- description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_HOME);
- [[homeButton_ cell]
- accessibilitySetOverrideValue:description
- forAttribute:NSAccessibilityDescriptionAttribute];
- description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_LOCATION);
- [[locationBar_ cell]
- accessibilitySetOverrideValue:description
- forAttribute:NSAccessibilityDescriptionAttribute];
- description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_APP);
- [[wrenchButton_ cell]
- accessibilitySetOverrideValue:description
- forAttribute:NSAccessibilityDescriptionAttribute];
-}
-
-- (void)mouseExited:(NSEvent*)theEvent {
- [[hoveredButton_ cell] setMouseInside:NO animate:YES];
- [hoveredButton_ release];
- hoveredButton_ = nil;
-}
-
-- (NSButton*)hoverButtonForEvent:(NSEvent*)theEvent {
- NSButton* targetView = (NSButton*)[[self view]
- hitTest:[theEvent locationInWindow]];
-
- // Only interpret the view as a hoverButton_ if it's both button and has a
- // button cell that cares. GradientButtonCell derived cells care.
- if (([targetView isKindOfClass:[NSButton class]]) &&
- ([[targetView cell]
- respondsToSelector:@selector(setMouseInside:animate:)]))
- return targetView;
- return nil;
-}
-
-- (void)mouseMoved:(NSEvent*)theEvent {
- NSButton* targetView = [self hoverButtonForEvent:theEvent];
- if (hoveredButton_ != targetView) {
- [[hoveredButton_ cell] setMouseInside:NO animate:YES];
- [[targetView cell] setMouseInside:YES animate:YES];
- [hoveredButton_ release];
- hoveredButton_ = [targetView retain];
- }
-}
-
-- (void)mouseEntered:(NSEvent*)event {
- [self mouseMoved:event];
-}
-
-- (LocationBarViewMac*)locationBarBridge {
- return locationBarView_.get();
-}
-
-- (void)focusLocationBar:(BOOL)selectAll {
- if (locationBarView_.get())
- locationBarView_->FocusLocation(selectAll ? true : false);
-}
-
-// Called when the state for a command changes to |enabled|. Update the
-// corresponding UI element.
-- (void)enabledStateChangedForCommand:(NSInteger)command enabled:(BOOL)enabled {
- NSButton* button = nil;
- switch (command) {
- case IDC_BACK:
- button = backButton_;
- break;
- case IDC_FORWARD:
- button = forwardButton_;
- break;
- case IDC_HOME:
- button = homeButton_;
- break;
- }
- [button setEnabled:enabled];
-}
-
-// Init the enabled state of the buttons on the toolbar to match the state in
-// the controller.
-- (void)initCommandStatus:(CommandUpdater*)commands {
- [backButton_ setEnabled:commands->IsCommandEnabled(IDC_BACK) ? YES : NO];
- [forwardButton_
- setEnabled:commands->IsCommandEnabled(IDC_FORWARD) ? YES : NO];
- [reloadButton_ setEnabled:YES];
- [homeButton_ setEnabled:commands->IsCommandEnabled(IDC_HOME) ? YES : NO];
-}
-
-- (void)updateToolbarWithContents:(TabContents*)tab
- shouldRestoreState:(BOOL)shouldRestore {
- locationBarView_->Update(tab, shouldRestore ? true : false);
-
- [locationBar_ updateCursorAndToolTipRects];
-
- if (browserActionsController_.get()) {
- [browserActionsController_ update];
- }
-}
-
-- (void)setStarredState:(BOOL)isStarred {
- locationBarView_->SetStarred(isStarred ? true : false);
-}
-
-- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force {
- [reloadButton_ setIsLoading:isLoading force:force];
-}
-
-- (void)setHasToolbar:(BOOL)toolbar hasLocationBar:(BOOL)locBar {
- [self view]; // Force nib loading.
-
- hasToolbar_ = toolbar;
-
- // If there's a toolbar, there must be a location bar.
- DCHECK((toolbar && locBar) || !toolbar);
- hasLocationBar_ = toolbar ? YES : locBar;
-
- // Decide whether to hide/show based on whether there's a location bar.
- [[self view] setHidden:!hasLocationBar_];
-
- // Make location bar not editable when in a pop-up.
- locationBarView_->SetEditable(toolbar);
-}
-
-- (NSView*)view {
- if (hasToolbar_)
- return [super view];
- return locationBar_;
-}
-
-// (Private) Returns the backdrop to the toolbar.
-- (BackgroundGradientView*)backgroundGradientView {
- // We really do mean |[super view]|; see our override of |-view|.
- DCHECK([[super view] isKindOfClass:[BackgroundGradientView class]]);
- return (BackgroundGradientView*)[super view];
-}
-
-- (id)customFieldEditorForObject:(id)obj {
- if (obj == locationBar_) {
- // Lazilly construct Field editor, Cocoa UI code always runs on the
- // same thread, so there shoudn't be a race condition here.
- if (autocompleteTextFieldEditor_.get() == nil) {
- autocompleteTextFieldEditor_.reset(
- [[AutocompleteTextFieldEditor alloc] init]);
- }
-
- // This needs to be called every time, otherwise notifications
- // aren't sent correctly.
- DCHECK(autocompleteTextFieldEditor_.get());
- [autocompleteTextFieldEditor_.get() setFieldEditor:YES];
- return autocompleteTextFieldEditor_.get();
- }
- return nil;
-}
-
-// Returns an array of views in the order of the outlets above.
-- (NSArray*)toolbarViews {
- return [NSArray arrayWithObjects:backButton_, forwardButton_, reloadButton_,
- homeButton_, wrenchButton_, locationBar_,
- browserActionsContainerView_, nil];
-}
-
-// Moves |rect| to the right by |delta|, keeping the right side fixed by
-// shrinking the width to compensate. Passing a negative value for |deltaX|
-// moves to the left and increases the width.
-- (NSRect)adjustRect:(NSRect)rect byAmount:(CGFloat)deltaX {
- NSRect frame = NSOffsetRect(rect, deltaX, 0);
- frame.size.width -= deltaX;
- return frame;
-}
-
-// Show or hide the home button based on the pref.
-- (void)showOptionalHomeButton {
- // Ignore this message if only showing the URL bar.
- if (!hasToolbar_)
- return;
- BOOL hide = showHomeButton_.GetValue() ? NO : YES;
- if (hide == [homeButton_ isHidden])
- return; // Nothing to do, view state matches pref state.
-
- // Always shift the text field by the width of the home button minus one pixel
- // since the frame edges of each button are right on top of each other. When
- // hiding the button, reverse the direction of the movement (to the left).
- CGFloat moveX = [homeButton_ frame].size.width - 1.0;
- if (hide)
- moveX *= -1; // Reverse the direction of the move.
-
- [locationBar_ setFrame:[self adjustRect:[locationBar_ frame]
- byAmount:moveX]];
- [homeButton_ setHidden:hide];
-}
-
-// Install the menu wrench buttons. Calling this repeatedly is inexpensive so it
-// can be done every time the buttons are shown.
-- (void)installWrenchMenu {
- if (wrenchMenuModel_.get())
- return;
- acceleratorDelegate_.reset(
- new ToolbarControllerInternal::WrenchAcceleratorDelegate());
-
- wrenchMenuModel_.reset(new WrenchMenuModel(
- acceleratorDelegate_.get(), browser_));
- [wrenchMenuController_ setModel:wrenchMenuModel_.get()];
- [wrenchMenuController_ setUseWithPopUpButtonCell:YES];
- [wrenchButton_ setAttachedMenu:[wrenchMenuController_ menu]];
-}
-
-- (WrenchMenuController*)wrenchMenuController {
- return wrenchMenuController_;
-}
-
-- (void)badgeWrenchMenu {
- // In the Windows version, the ball doesn't actually pulsate, and is always
- // drawn with the inactive image. Why? (We follow suit, though not on the
- // weird positioning they do that overlaps the button border.)
- NSImage* badge = nsimage_cache::ImageNamed(@"upgrade_dot.pdf");
- NSImage* wrenchImage = nsimage_cache::ImageNamed(kWrenchButtonImageName);
- NSSize wrenchImageSize = [wrenchImage size];
-
- scoped_nsobject<NSImage> overlayImage(
- [[NSImage alloc] initWithSize:wrenchImageSize]);
-
- [overlayImage lockFocus];
- [badge drawAtPoint:NSZeroPoint
- fromRect:NSZeroRect
- operation:NSCompositeSourceOver
- fraction:1.0];
- [overlayImage unlockFocus];
-
- [[wrenchButton_ cell] setOverlayImage:overlayImage];
-}
-
-- (void)prefChanged:(std::string*)prefName {
- if (!prefName) return;
- if (*prefName == prefs::kShowHomeButton) {
- [self showOptionalHomeButton];
- }
-}
-
-- (void)createBrowserActionButtons {
- if (!browserActionsController_.get()) {
- browserActionsController_.reset([[BrowserActionsController alloc]
- initWithBrowser:browser_
- containerView:browserActionsContainerView_]);
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(browserActionsContainerDragged:)
- name:kBrowserActionGrippyDraggingNotification
- object:browserActionsController_];
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(browserActionsContainerDragFinished:)
- name:kBrowserActionGrippyDragFinishedNotification
- object:browserActionsController_];
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(browserActionsVisibilityChanged:)
- name:kBrowserActionVisibilityChangedNotification
- object:browserActionsController_];
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(adjustBrowserActionsContainerForNewWindow:)
- name:NSWindowDidBecomeKeyNotification
- object:[[self view] window]];
- }
- CGFloat containerWidth = [browserActionsContainerView_ isHidden] ? 0.0 :
- NSWidth([browserActionsContainerView_ frame]);
- if (containerWidth > 0.0)
- [self adjustLocationSizeBy:(containerWidth * -1) animate:NO];
-}
-
-- (void)adjustBrowserActionsContainerForNewWindow:
- (NSNotification*)notification {
- [self toolbarFrameChanged];
- [[NSNotificationCenter defaultCenter]
- removeObserver:self
- name:NSWindowDidBecomeKeyNotification
- object:[[self view] window]];
-}
-
-- (void)browserActionsContainerDragged:(NSNotification*)notification {
- CGFloat locationBarWidth = NSWidth([locationBar_ frame]);
- locationBarAtMinSize_ = locationBarWidth <= kMinimumLocationBarWidth;
- [browserActionsContainerView_ setCanDragLeft:!locationBarAtMinSize_];
- [browserActionsContainerView_ setGrippyPinned:locationBarAtMinSize_];
- [self adjustLocationSizeBy:
- [browserActionsContainerView_ resizeDeltaX] animate:NO];
-}
-
-- (void)browserActionsContainerDragFinished:(NSNotification*)notification {
- [browserActionsController_ resizeContainerAndAnimate:YES];
- [self pinLocationBarToLeftOfBrowserActionsContainerAndAnimate:YES];
-}
-
-- (void)browserActionsVisibilityChanged:(NSNotification*)notification {
- [self pinLocationBarToLeftOfBrowserActionsContainerAndAnimate:NO];
-}
-
-- (void)pinLocationBarToLeftOfBrowserActionsContainerAndAnimate:(BOOL)animate {
- CGFloat locationBarXPos = NSMaxX([locationBar_ frame]);
- CGFloat leftDistance;
-
- if ([browserActionsContainerView_ isHidden]) {
- CGFloat edgeXPos = [wrenchButton_ frame].origin.x;
- leftDistance = edgeXPos - locationBarXPos - kWrenchMenuLeftPadding;
- } else {
- NSRect containerFrame = animate ?
- [browserActionsContainerView_ animationEndFrame] :
- [browserActionsContainerView_ frame];
-
- leftDistance = containerFrame.origin.x - locationBarXPos;
- }
- if (leftDistance != 0.0)
- [self adjustLocationSizeBy:leftDistance animate:animate];
-}
-
-- (void)maintainMinimumLocationBarWidth {
- CGFloat locationBarWidth = NSWidth([locationBar_ frame]);
- locationBarAtMinSize_ = locationBarWidth <= kMinimumLocationBarWidth;
- if (locationBarAtMinSize_) {
- CGFloat dX = kMinimumLocationBarWidth - locationBarWidth;
- [self adjustLocationSizeBy:dX animate:NO];
- }
-}
-
-- (void)toolbarFrameChanged {
- // Do nothing if the frame changes but no Browser Action Controller is
- // present.
- if (!browserActionsController_.get())
- return;
-
- [self maintainMinimumLocationBarWidth];
-
- if (locationBarAtMinSize_) {
- // Once the grippy is pinned, leave it until it is explicity un-pinned.
- [browserActionsContainerView_ setGrippyPinned:YES];
- NSRect containerFrame = [browserActionsContainerView_ frame];
- // Determine how much the container needs to move in case it's overlapping
- // with the location bar.
- CGFloat dX = NSMaxX([locationBar_ frame]) - containerFrame.origin.x;
- containerFrame = NSOffsetRect(containerFrame, dX, 0);
- containerFrame.size.width -= dX;
- [browserActionsContainerView_ setFrame:containerFrame];
- } else if (!locationBarAtMinSize_ &&
- [browserActionsContainerView_ grippyPinned]) {
- // Expand out the container until it hits the saved size, then unpin the
- // grippy.
- // Add 0.1 pixel so that it doesn't hit the minimum width codepath above.
- CGFloat dX = NSWidth([locationBar_ frame]) -
- (kMinimumLocationBarWidth + 0.1);
- NSRect containerFrame = [browserActionsContainerView_ frame];
- containerFrame = NSOffsetRect(containerFrame, -dX, 0);
- containerFrame.size.width += dX;
- CGFloat savedContainerWidth = [browserActionsController_ savedWidth];
- if (NSWidth(containerFrame) >= savedContainerWidth) {
- containerFrame = NSOffsetRect(containerFrame,
- NSWidth(containerFrame) - savedContainerWidth, 0);
- containerFrame.size.width = savedContainerWidth;
- [browserActionsContainerView_ setGrippyPinned:NO];
- }
- [browserActionsContainerView_ setFrame:containerFrame];
- [self pinLocationBarToLeftOfBrowserActionsContainerAndAnimate:NO];
- }
-}
-
-- (void)adjustLocationSizeBy:(CGFloat)dX animate:(BOOL)animate {
- // Ensure that the location bar is in its proper place.
- NSRect locationFrame = [locationBar_ frame];
- locationFrame.size.width += dX;
-
- if (!animate) {
- [locationBar_ setFrame:locationFrame];
- return;
- }
-
- [NSAnimationContext beginGrouping];
- [[NSAnimationContext currentContext] setDuration:kAnimationDuration];
- [[locationBar_ animator] setFrame:locationFrame];
- [NSAnimationContext endGrouping];
-}
-
-- (NSPoint)bookmarkBubblePoint {
- return locationBarView_->GetBookmarkBubblePoint();
-}
-
-- (CGFloat)desiredHeightForCompression:(CGFloat)compressByHeight {
- // With no toolbar, just ignore the compression.
- return hasToolbar_ ? kBaseToolbarHeight - compressByHeight :
- NSHeight([locationBar_ frame]);
-}
-
-- (void)setDividerOpacity:(CGFloat)opacity {
- BackgroundGradientView* view = [self backgroundGradientView];
- [view setShowsDivider:(opacity > 0 ? YES : NO)];
-
- // We may not have a toolbar view (e.g., popup windows only have a location
- // bar).
- if ([view isKindOfClass:[ToolbarView class]]) {
- ToolbarView* toolbarView = (ToolbarView*)view;
- [toolbarView setDividerOpacity:opacity];
- }
-}
-
-- (BrowserActionsController*)browserActionsController {
- return browserActionsController_.get();
-}
-
-// (URLDropTargetController protocol)
-- (void)dropURLs:(NSArray*)urls inView:(NSView*)view at:(NSPoint)point {
- // TODO(viettrungluu): This code is more or less copied from the code in
- // |TabStripController|. I'll refactor this soon to make it common and expand
- // its capabilities (e.g., allow text DnD).
- if ([urls count] < 1) {
- NOTREACHED();
- return;
- }
-
- // TODO(viettrungluu): dropping multiple URLs?
- if ([urls count] > 1)
- NOTIMPLEMENTED();
-
- // Get the first URL and fix it up.
- GURL url(URLFixerUpper::FixupURL(
- base::SysNSStringToUTF8([urls objectAtIndex:0]), std::string()));
-
- browser_->GetSelectedTabContents()->OpenURL(url, GURL(), CURRENT_TAB,
- PageTransition::TYPED);
-}
-
-// (URLDropTargetController protocol)
-- (void)indicateDropURLsInView:(NSView*)view at:(NSPoint)point {
- // Do nothing.
-}
-
-// (URLDropTargetController protocol)
-- (void)hideDropURLsIndicatorInView:(NSView*)view {
- // Do nothing.
-}
-
-@end
diff --git a/chrome/browser/cocoa/toolbar_controller_unittest.mm b/chrome/browser/cocoa/toolbar_controller_unittest.mm
deleted file mode 100644
index 43fbafb..0000000
--- a/chrome/browser/cocoa/toolbar_controller_unittest.mm
+++ /dev/null
@@ -1,237 +0,0 @@
-// 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>
-
-#import "base/scoped_nsobject.h"
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/gradient_button_cell.h"
-#import "chrome/browser/cocoa/toolbar_controller.h"
-#import "chrome/browser/cocoa/view_resizer_pong.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/common/pref_names.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-// An NSView that fakes out hitTest:.
-@interface HitView : NSView {
- id hitTestReturn_;
-}
-@end
-
-@implementation HitView
-
-- (void)setHitTestReturn:(id)rtn {
- hitTestReturn_ = rtn;
-}
-
-- (NSView *)hitTest:(NSPoint)aPoint {
- return hitTestReturn_;
-}
-
-@end
-
-
-namespace {
-
-class ToolbarControllerTest : public CocoaTest {
- public:
-
- // Indexes that match the ordering returned by the private ToolbarController
- // |-toolbarViews| method.
- enum {
- kBackIndex, kForwardIndex, kReloadIndex, kHomeIndex,
- kWrenchIndex, kLocationIndex, kBrowserActionContainerViewIndex
- };
-
- ToolbarControllerTest() {
- Browser* browser = helper_.browser();
- CommandUpdater* updater = browser->command_updater();
- // The default state for the commands is true, set a couple to false to
- // ensure they get picked up correct on initialization
- updater->UpdateCommandEnabled(IDC_BACK, false);
- updater->UpdateCommandEnabled(IDC_FORWARD, false);
- resizeDelegate_.reset([[ViewResizerPong alloc] init]);
- bar_.reset(
- [[ToolbarController alloc] initWithModel:browser->toolbar_model()
- commands:browser->command_updater()
- profile:helper_.profile()
- browser:browser
- resizeDelegate:resizeDelegate_.get()]);
- EXPECT_TRUE([bar_ view]);
- NSView* parent = [test_window() contentView];
- [parent addSubview:[bar_ view]];
- }
-
- // Make sure the enabled state of the view is the same as the corresponding
- // command in the updater. The views are in the declaration order of outlets.
- void CompareState(CommandUpdater* updater, NSArray* views) {
- EXPECT_EQ(updater->IsCommandEnabled(IDC_BACK),
- [[views objectAtIndex:kBackIndex] isEnabled] ? true : false);
- EXPECT_EQ(updater->IsCommandEnabled(IDC_FORWARD),
- [[views objectAtIndex:kForwardIndex] isEnabled] ? true : false);
- EXPECT_EQ(updater->IsCommandEnabled(IDC_RELOAD),
- [[views objectAtIndex:kReloadIndex] isEnabled] ? true : false);
- EXPECT_EQ(updater->IsCommandEnabled(IDC_HOME),
- [[views objectAtIndex:kHomeIndex] isEnabled] ? true : false);
- }
-
- BrowserTestHelper helper_;
- scoped_nsobject<ViewResizerPong> resizeDelegate_;
- scoped_nsobject<ToolbarController> bar_;
-};
-
-TEST_VIEW(ToolbarControllerTest, [bar_ view])
-
-// Test the initial state that everything is sync'd up
-TEST_F(ToolbarControllerTest, InitialState) {
- CommandUpdater* updater = helper_.browser()->command_updater();
- CompareState(updater, [bar_ toolbarViews]);
-}
-
-// Make sure a "titlebar only" toolbar with location bar works.
-TEST_F(ToolbarControllerTest, TitlebarOnly) {
- NSView* view = [bar_ view];
-
- [bar_ setHasToolbar:NO hasLocationBar:YES];
- EXPECT_NE(view, [bar_ view]);
-
- // Simulate a popup going fullscreen and back by performing the reparenting
- // that happens during fullscreen transitions
- NSView* superview = [view superview];
- [view removeFromSuperview];
- [superview addSubview:view];
-
- [bar_ setHasToolbar:YES hasLocationBar:YES];
- EXPECT_EQ(view, [bar_ view]);
-
- // Leave it off to make sure that's fine
- [bar_ setHasToolbar:NO hasLocationBar:YES];
-}
-
-// Make sure it works in the completely undecorated case.
-TEST_F(ToolbarControllerTest, NoLocationBar) {
- NSView* view = [bar_ view];
-
- [bar_ setHasToolbar:NO hasLocationBar:NO];
- EXPECT_NE(view, [bar_ view]);
- EXPECT_TRUE([[bar_ view] isHidden]);
-
- // Simulate a popup going fullscreen and back by performing the reparenting
- // that happens during fullscreen transitions
- NSView* superview = [view superview];
- [view removeFromSuperview];
- [superview addSubview:view];
-}
-
-// Make some changes to the enabled state of a few of the buttons and ensure
-// that we're still in sync.
-TEST_F(ToolbarControllerTest, UpdateEnabledState) {
- CommandUpdater* updater = helper_.browser()->command_updater();
- EXPECT_FALSE(updater->IsCommandEnabled(IDC_BACK));
- EXPECT_FALSE(updater->IsCommandEnabled(IDC_FORWARD));
- updater->UpdateCommandEnabled(IDC_BACK, true);
- updater->UpdateCommandEnabled(IDC_FORWARD, true);
- CompareState(updater, [bar_ toolbarViews]);
-}
-
-// Focus the location bar and make sure that it's the first responder.
-TEST_F(ToolbarControllerTest, FocusLocation) {
- NSWindow* window = test_window();
- [window makeFirstResponder:[window contentView]];
- EXPECT_EQ([window firstResponder], [window contentView]);
- [bar_ focusLocationBar:YES];
- EXPECT_NE([window firstResponder], [window contentView]);
- NSView* locationBar = [[bar_ toolbarViews] objectAtIndex:kLocationIndex];
- EXPECT_EQ([window firstResponder], [(id)locationBar currentEditor]);
-}
-
-TEST_F(ToolbarControllerTest, LoadingState) {
- // In its initial state, the reload button has a tag of
- // IDC_RELOAD. When loading, it should be IDC_STOP.
- NSButton* reload = [[bar_ toolbarViews] objectAtIndex:kReloadIndex];
- EXPECT_EQ([reload tag], IDC_RELOAD);
- [bar_ setIsLoading:YES force:YES];
- EXPECT_EQ([reload tag], IDC_STOP);
- [bar_ setIsLoading:NO force:YES];
- EXPECT_EQ([reload tag], IDC_RELOAD);
-}
-
-// Check that toggling the state of the home button changes the visible
-// state of the home button and moves the other items accordingly.
-TEST_F(ToolbarControllerTest, ToggleHome) {
- PrefService* prefs = helper_.profile()->GetPrefs();
- bool showHome = prefs->GetBoolean(prefs::kShowHomeButton);
- NSView* homeButton = [[bar_ toolbarViews] objectAtIndex:kHomeIndex];
- EXPECT_EQ(showHome, ![homeButton isHidden]);
-
- NSView* locationBar = [[bar_ toolbarViews] objectAtIndex:kLocationIndex];
- NSRect originalLocationBarFrame = [locationBar frame];
-
- // Toggle the pref and make sure the button changed state and the other
- // views moved.
- prefs->SetBoolean(prefs::kShowHomeButton, !showHome);
- EXPECT_EQ(showHome, [homeButton isHidden]);
- EXPECT_NE(NSMinX(originalLocationBarFrame), NSMinX([locationBar frame]));
- EXPECT_NE(NSWidth(originalLocationBarFrame), NSWidth([locationBar frame]));
-}
-
-// Ensure that we don't toggle the buttons when we have a strip marked as not
-// having the full toolbar. Also ensure that the location bar doesn't change
-// size.
-TEST_F(ToolbarControllerTest, DontToggleWhenNoToolbar) {
- [bar_ setHasToolbar:NO hasLocationBar:YES];
- NSView* homeButton = [[bar_ toolbarViews] objectAtIndex:kHomeIndex];
- NSView* locationBar = [[bar_ toolbarViews] objectAtIndex:kLocationIndex];
- NSRect locationBarFrame = [locationBar frame];
- EXPECT_EQ([homeButton isHidden], YES);
- [bar_ showOptionalHomeButton];
- EXPECT_EQ([homeButton isHidden], YES);
- NSRect newLocationBarFrame = [locationBar frame];
- EXPECT_TRUE(NSEqualRects(locationBarFrame, newLocationBarFrame));
- newLocationBarFrame = [locationBar frame];
- EXPECT_TRUE(NSEqualRects(locationBarFrame, newLocationBarFrame));
-}
-
-TEST_F(ToolbarControllerTest, BookmarkBubblePoint) {
- const NSPoint starPoint = [bar_ bookmarkBubblePoint];
- const NSRect barFrame =
- [[bar_ view] convertRect:[[bar_ view] bounds] toView:nil];
-
- // Make sure the star is completely inside the location bar.
- EXPECT_TRUE(NSPointInRect(starPoint, barFrame));
-}
-
-TEST_F(ToolbarControllerTest, HoverButtonForEvent) {
- scoped_nsobject<HitView> view([[HitView alloc]
- initWithFrame:NSMakeRect(0,0,100,100)]);
- [bar_ setView:view];
- NSEvent* event = [NSEvent mouseEventWithType:NSMouseMoved
- location:NSMakePoint(10,10)
- modifierFlags:0
- timestamp:0
- windowNumber:0
- context:nil
- eventNumber:0
- clickCount:0
- pressure:0.0];
-
- // NOT a match.
- [view setHitTestReturn:bar_.get()];
- EXPECT_FALSE([bar_ hoverButtonForEvent:event]);
-
- // Not yet...
- scoped_nsobject<NSButton> button([[NSButton alloc] init]);
- [view setHitTestReturn:button];
- EXPECT_FALSE([bar_ hoverButtonForEvent:event]);
-
- // Now!
- scoped_nsobject<GradientButtonCell> cell([[GradientButtonCell alloc] init]);
- [button setCell:cell.get()];
- EXPECT_TRUE([bar_ hoverButtonForEvent:nil]);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/toolbar_view.h b/chrome/browser/cocoa/toolbar_view.h
deleted file mode 100644
index b620606..0000000
--- a/chrome/browser/cocoa/toolbar_view.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_TOOLBAR_VIEW_H_
-#define CHROME_BROWSER_COCOA_TOOLBAR_VIEW_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-#import "chrome/browser/cocoa/background_gradient_view.h"
-
-// A view that handles any special rendering of the toolbar bar. At
-// this time it only draws a gradient. Future changes (e.g. themes)
-// may require new functionality here.
-
-@interface ToolbarView : BackgroundGradientView {
- @private
- // The opacity of the divider line (at the bottom of the toolbar); used when
- // the detached bookmark bar is morphing to the normal bar and vice versa.
- CGFloat dividerOpacity_;
-}
-
-@property(assign, nonatomic) CGFloat dividerOpacity;
-@end
-
-#endif // CHROME_BROWSER_COCOA_TOOLBAR_VIEW_H_
diff --git a/chrome/browser/cocoa/toolbar_view.mm b/chrome/browser/cocoa/toolbar_view.mm
deleted file mode 100644
index 012e5d8..0000000
--- a/chrome/browser/cocoa/toolbar_view.mm
+++ /dev/null
@@ -1,47 +0,0 @@
- // Copyright (c) 2009 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 "chrome/browser/cocoa/toolbar_view.h"
-
-#import "chrome/browser/cocoa/themed_window.h"
-#import "chrome/browser/cocoa/view_id_util.h"
-
-@implementation ToolbarView
-
-@synthesize dividerOpacity = dividerOpacity_;
-
-// Prevent mouse down events from moving the parent window around.
-- (BOOL)mouseDownCanMoveWindow {
- return NO;
-}
-
-- (void)drawRect:(NSRect)rect {
- // The toolbar's background pattern is phased relative to the
- // tab strip view's background pattern.
- NSPoint phase = [[self window] themePatternPhase];
- [[NSGraphicsContext currentContext] setPatternPhase:phase];
- [self drawBackground];
-}
-
-// Override of |-[BackgroundGradientView strokeColor]|; make it respect opacity.
-- (NSColor*)strokeColor {
- return [[super strokeColor] colorWithAlphaComponent:[self dividerOpacity]];
-}
-
-- (BOOL)accessibilityIsIgnored {
- return NO;
-}
-
-- (id)accessibilityAttributeValue:(NSString*)attribute {
- if ([attribute isEqual:NSAccessibilityRoleAttribute])
- return NSAccessibilityToolbarRole;
-
- return [super accessibilityAttributeValue:attribute];
-}
-
-- (ViewID)viewID {
- return VIEW_ID_TOOLBAR;
-}
-
-@end
diff --git a/chrome/browser/cocoa/toolbar_view_unittest.mm b/chrome/browser/cocoa/toolbar_view_unittest.mm
deleted file mode 100644
index 2026cad..0000000
--- a/chrome/browser/cocoa/toolbar_view_unittest.mm
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2009 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/scoped_nsobject.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/toolbar_view.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-namespace {
-
-class ToolbarViewTest : public CocoaTest {
-};
-
-// This class only needs to do one thing: prevent mouse down events from moving
-// the parent window around.
-TEST_F(ToolbarViewTest, CanDragWindow) {
- scoped_nsobject<ToolbarView> view([[ToolbarView alloc] init]);
- EXPECT_FALSE([view mouseDownCanMoveWindow]);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/translate/after_translate_infobar_controller.h b/chrome/browser/cocoa/translate/after_translate_infobar_controller.h
deleted file mode 100644
index ba946c9..0000000
--- a/chrome/browser/cocoa/translate/after_translate_infobar_controller.h
+++ /dev/null
@@ -1,11 +0,0 @@
-// 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 "chrome/browser/cocoa/translate/translate_infobar_base.h"
-
-@interface AfterTranslateInfobarController : TranslateInfoBarControllerBase {
- bool swappedLanugageButtons_;
-}
-
-@end
diff --git a/chrome/browser/cocoa/translate/after_translate_infobar_controller.mm b/chrome/browser/cocoa/translate/after_translate_infobar_controller.mm
deleted file mode 100644
index 7e01146..0000000
--- a/chrome/browser/cocoa/translate/after_translate_infobar_controller.mm
+++ /dev/null
@@ -1,60 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/translate/after_translate_infobar_controller.h"
-#include "base/sys_string_conversions.h"
-
-using TranslateInfoBarUtilities::MoveControl;
-using TranslateInfoBarUtilities::VerifyControlOrderAndSpacing;
-
-@implementation AfterTranslateInfobarController
-
-- (void)loadLabelText {
- std::vector<string16> strings;
- TranslateInfoBarDelegate::GetAfterTranslateStrings(
- &strings, &swappedLanugageButtons_);
- DCHECK(strings.size() == 3U);
- NSString* string1 = base::SysUTF16ToNSString(strings[0]);
- NSString* string2 = base::SysUTF16ToNSString(strings[1]);
- NSString* string3 = base::SysUTF16ToNSString(strings[2]);
-
- [label1_ setStringValue:string1];
- [label2_ setStringValue:string2];
- [label3_ setStringValue:string3];
-}
-
-- (void)layout {
- [self removeOkCancelButtons];
- [optionsPopUp_ setHidden:NO];
- NSView* firstPopup = fromLanguagePopUp_;
- NSView* lastPopup = toLanguagePopUp_;
- if (swappedLanugageButtons_) {
- firstPopup = toLanguagePopUp_;
- lastPopup = fromLanguagePopUp_;
- }
- NSView* lastControl = lastPopup;
-
- MoveControl(label1_, firstPopup, spaceBetweenControls_ / 2, true);
- MoveControl(firstPopup, label2_, spaceBetweenControls_ / 2, true);
- MoveControl(label2_, lastPopup, spaceBetweenControls_ / 2, true);
- MoveControl(lastPopup, label3_, 0, true);
- lastControl = label3_;
-
- MoveControl(lastControl, showOriginalButton_, spaceBetweenControls_ * 2,
- true);
-}
-
-- (NSArray*)visibleControls {
- return [NSArray arrayWithObjects:label1_.get(), fromLanguagePopUp_.get(),
- label2_.get(), toLanguagePopUp_.get(), label3_.get(),
- showOriginalButton_.get(), nil];
-}
-
-- (bool)verifyLayout {
- if ([optionsPopUp_ isHidden])
- return false;
- return [super verifyLayout];
-}
-
-@end
diff --git a/chrome/browser/cocoa/translate/before_translate_infobar_controller.h b/chrome/browser/cocoa/translate/before_translate_infobar_controller.h
deleted file mode 100644
index ff54daa..0000000
--- a/chrome/browser/cocoa/translate/before_translate_infobar_controller.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// 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 "chrome/browser/cocoa/translate/translate_infobar_base.h"
-
-@interface BeforeTranslateInfobarController : TranslateInfoBarControllerBase {
- scoped_nsobject<NSButton> alwaysTranslateButton_;
- scoped_nsobject<NSButton> neverTranslateButton_;
-}
-
-// Creates and initializes the alwaysTranslate and neverTranslate buttons.
-- (void)initializeExtraControls;
-
-@end
-
-@interface BeforeTranslateInfobarController (TestingAPI)
-
-- (NSButton*)alwaysTranslateButton;
-- (NSButton*)neverTranslateButton;
-
-@end
-
diff --git a/chrome/browser/cocoa/translate/before_translate_infobar_controller.mm b/chrome/browser/cocoa/translate/before_translate_infobar_controller.mm
deleted file mode 100644
index baa0eef..0000000
--- a/chrome/browser/cocoa/translate/before_translate_infobar_controller.mm
+++ /dev/null
@@ -1,123 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/translate/before_translate_infobar_controller.h"
-
-#include "app/l10n_util.h"
-#include "base/sys_string_conversions.h"
-#include "grit/generated_resources.h"
-
-using TranslateInfoBarUtilities::MoveControl;
-using TranslateInfoBarUtilities::VerifyControlOrderAndSpacing;
-
-namespace {
-
-NSButton* CreateNSButtonWithResourceIDAndParameter(
- int resourceId, const string16& param) {
- string16 title = l10n_util::GetStringFUTF16(resourceId, param);
- NSButton* button = [[NSButton alloc] init];
- [button setTitle:base::SysUTF16ToNSString(title)];
- [button setBezelStyle:NSTexturedRoundedBezelStyle];
- return button;
-}
-
-} // namespace
-
-@implementation BeforeTranslateInfobarController
-
-- (id) initWithDelegate:(InfoBarDelegate *)delegate {
- if ((self = [super initWithDelegate:delegate])) {
- [self initializeExtraControls];
- }
- return self;
-}
-
-- (void)initializeExtraControls {
- TranslateInfoBarDelegate* delegate = [self delegate];
- const string16& language = delegate->GetLanguageDisplayableNameAt(
- delegate->original_language_index());
- neverTranslateButton_.reset(
- CreateNSButtonWithResourceIDAndParameter(
- IDS_TRANSLATE_INFOBAR_NEVER_TRANSLATE, language));
- [neverTranslateButton_ setTarget:self];
- [neverTranslateButton_ setAction:@selector(neverTranslate:)];
-
- alwaysTranslateButton_.reset(
- CreateNSButtonWithResourceIDAndParameter(
- IDS_TRANSLATE_INFOBAR_ALWAYS_TRANSLATE, language));
- [alwaysTranslateButton_ setTarget:self];
- [alwaysTranslateButton_ setAction:@selector(alwaysTranslate:)];
-}
-
-- (void)layout {
- MoveControl(label1_, fromLanguagePopUp_, spaceBetweenControls_ / 2, true);
- MoveControl(fromLanguagePopUp_, label2_, spaceBetweenControls_, true);
- MoveControl(label2_, okButton_, spaceBetweenControls_, true);
- MoveControl(okButton_, cancelButton_, spaceBetweenControls_, true);
- NSView* lastControl = cancelButton_;
- if (neverTranslateButton_.get()) {
- MoveControl(lastControl, neverTranslateButton_.get(),
- spaceBetweenControls_, true);
- lastControl = neverTranslateButton_.get();
- }
- if (alwaysTranslateButton_.get()) {
- MoveControl(lastControl, alwaysTranslateButton_.get(),
- spaceBetweenControls_, true);
- }
-}
-
-- (void)loadLabelText {
- size_t offset = 0;
- string16 text =
- l10n_util::GetStringFUTF16(IDS_TRANSLATE_INFOBAR_BEFORE_MESSAGE,
- string16(), &offset);
- NSString* string1 = base::SysUTF16ToNSString(text.substr(0, offset));
- NSString* string2 = base::SysUTF16ToNSString(text.substr(offset));
- [label1_ setStringValue:string1];
- [label2_ setStringValue:string2];
- [label3_ setStringValue:@""];
-}
-
-- (NSArray*)visibleControls {
- NSMutableArray* visibleControls = [NSMutableArray arrayWithObjects:
- label1_.get(), fromLanguagePopUp_.get(), label2_.get(),
- okButton_, cancelButton_, nil];
-
- if ([self delegate]->ShouldShowNeverTranslateButton())
- [visibleControls addObject:neverTranslateButton_.get()];
-
- if ([self delegate]->ShouldShowAlwaysTranslateButton())
- [visibleControls addObject:alwaysTranslateButton_.get()];
-
- return visibleControls;
-}
-
-// This is called when the "Never Translate [language]" button is pressed.
-- (void)neverTranslate:(id)sender {
- [self delegate]->NeverTranslatePageLanguage();
-}
-
-// This is called when the "Always Translate [language]" button is pressed.
-- (void)alwaysTranslate:(id)sender {
- [self delegate]->AlwaysTranslatePageLanguage();
-}
-
-- (bool)verifyLayout {
- if ([optionsPopUp_ isHidden])
- return false;
- return [super verifyLayout];
-}
-
-@end
-
-@implementation BeforeTranslateInfobarController (TestingAPI)
-
-- (NSButton*)alwaysTranslateButton {
- return alwaysTranslateButton_.get();
-}
-- (NSButton*)neverTranslateButton {
- return neverTranslateButton_.get();
-}
-
-@end
diff --git a/chrome/browser/cocoa/translate/translate_infobar_base.h b/chrome/browser/cocoa/translate/translate_infobar_base.h
deleted file mode 100644
index b23250f..0000000
--- a/chrome/browser/cocoa/translate/translate_infobar_base.h
+++ /dev/null
@@ -1,163 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_TRANSLATE_INFOBAR_BASE_H_
-#define CHROME_BROWSER_COCOA_TRANSLATE_INFOBAR_BASE_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-#import "chrome/browser/cocoa/infobar_controller.h"
-
-#import "base/cocoa_protocols_mac.h"
-#import "base/scoped_nsobject.h"
-#include "base/scoped_ptr.h"
-#include "chrome/browser/translate/languages_menu_model.h"
-#include "chrome/browser/translate/options_menu_model.h"
-#include "chrome/browser/translate/translate_infobar_delegate.h"
-#include "chrome/common/translate_errors.h"
-
-class TranslateInfoBarMenuModel;
-
-#pragma mark TranslateInfoBarUtilities helper functions.
-namespace TranslateInfoBarUtilities {
-
-// Move the |toMove| view |spacing| pixels before/after the |anchor| view.
-// |after| signifies the side of |anchor| on which to place |toMove|.
-void MoveControl(NSView* anchor, NSView* toMove, int spacing, bool after);
-
-// Vertically center |toMove| in its container.
-void VerticallyCenterView(NSView *toMove);
-// Check that the control |before| is ordered visually before the |after|
-// control.
-// Also, check that there is space between them.
-bool VerifyControlOrderAndSpacing(id before, id after);
-
-// Creates a label control in the style we need for the translate infobar's
-// labels within |bounds|.
-NSTextField* CreateLabel(NSRect bounds);
-
-// Adds an item with the specified properties to |menu|.
-void AddMenuItem(NSMenu *menu, id target, SEL selector, NSString* title,
- int tag, bool enabled, bool checked);
-
-} // namespace
-
-// The base class for the three translate infobars. This class does all of the
-// heavy UI lifting, while deferring to the subclass to tell it what views
-// should be shown and where. Subclasses need to implement:
-// - (void)layout;
-// - (void)loadLabelText;
-// - (void)visibleControls;
-// - (bool)verifyLayout; // For testing.
-@interface TranslateInfoBarControllerBase : InfoBarController<NSMenuDelegate> {
- @protected
- scoped_nsobject<NSTextField> label1_;
- scoped_nsobject<NSTextField> label2_;
- scoped_nsobject<NSTextField> label3_;
- scoped_nsobject<NSPopUpButton> fromLanguagePopUp_;
- scoped_nsobject<NSPopUpButton> toLanguagePopUp_;
- scoped_nsobject<NSPopUpButton> optionsPopUp_;
- scoped_nsobject<NSButton> showOriginalButton_;
- // This is the button used in the translate message infobar. It can either be
- // a "Try Again" button, or a "Show Original" button in the case that the
- // page was translated from an unknown language.
- scoped_nsobject<NSButton> translateMessageButton_;
-
- // In the current locale, are the "from" and "to" language popup menu
- // flipped from what they'd appear in English.
- bool swappedLanguagePlaceholders_;
-
- // Space between controls in pixels - read from the NIB.
- CGFloat spaceBetweenControls_;
-
- scoped_ptr<LanguagesMenuModel> originalLanguageMenuModel_;
- scoped_ptr<LanguagesMenuModel> targetLanguageMenuModel_;
- scoped_ptr<OptionsMenuModel> optionsMenuModel_;
-}
-
-// Returns the delegate as a TranslateInfoBarDelegate.
-- (TranslateInfoBarDelegate*)delegate;
-
-// Called when the "Show Original" button is pressed.
-- (IBAction)showOriginal:(id)sender;
-
-@end
-
-@interface TranslateInfoBarControllerBase (ProtectedAPI)
-
-// Resizes or hides the options button based on how much space is available
-// so that it doesn't overlap other buttons.
-// lastView is the rightmost view, the first one that the options button
-// would overlap with.
-- (void)adjustOptionsButtonSizeAndVisibilityForView:(NSView*)lastView;
-
-// Move all the currently visible views into the correct place for the
-// current mode.
-// Must be implemented by the subclass.
-- (void)layout;
-
-// Loads the text for the 3 labels. There is only one message, but since
-// it has controls separating parts of it, it is separated into 3 separate
-// labels.
-// Must be implemented by the subclass.
-- (void)loadLabelText;
-
-// Returns the controls that are visible in the subclasses infobar. The
-// default implementation returns an empty array. The controls should
-// be returned in the order they are displayed, otherwise the layout test
-// will fail.
-// Must be implemented by the subclass.
-- (NSArray*)visibleControls;
-
-// Shows the array of controls provided by the subclass.
-- (void)showVisibleControls:(NSArray*)visibleControls;
-
-// Hides the OK and Cancel buttons.
-- (void)removeOkCancelButtons;
-
-// Called when the source or target language selection changes in a menu.
-// |newLanguageIdx| is the index of the newly selected item in the appropriate
-// menu.
-- (void)sourceLanguageModified:(NSInteger)newLanguageIdx;
-- (void)targetLanguageModified:(NSInteger)newLanguageIdx;
-
-// Called when an item in one of the toolbar's language or options
-// menus is selected.
-- (void)languageMenuChanged:(id)item;
-- (void)optionsMenuChanged:(id)item;
-
-// Teardown and rebuild the options menu. When the infobar is small, the
-// options menu is shrunk to just a drop down arrow, so the title needs
-// to be empty.
-- (void)rebuildOptionsMenu:(BOOL)hideTitle;
-
-// Whether or not this infobar should show the options popup.
-- (BOOL)shouldShowOptionsPopUp;
-
-@end // TranslateInfoBarControllerBase (ProtectedAPI)
-
-#pragma mark TestingAPI
-
-@interface TranslateInfoBarControllerBase (TestingAPI)
-
-// All the controls used in any of the translate states.
-// This is used for verifying layout and for setting the
-// correct styles on each button.
-- (NSArray*)allControls;
-
-// Verifies that the layout of the infobar is correct.
-// Must be implmented by the subclass.
-- (bool)verifyLayout;
-
-// Returns the underlying options menu.
-- (NSMenu*)optionsMenu;
-
-// Returns |translateMessageButton_|, see declaration of member
-// variable for a full description.
-- (NSButton*)translateMessageButton;
-
-@end // TranslateInfoBarControllerBase (TestingAPI)
-
-
-#endif // CHROME_BROWSER_COCOA_TRANSLATE_INFOBAR_BASE_H_
diff --git a/chrome/browser/cocoa/translate/translate_infobar_base.mm b/chrome/browser/cocoa/translate/translate_infobar_base.mm
deleted file mode 100644
index 48ce514..0000000
--- a/chrome/browser/cocoa/translate/translate_infobar_base.mm
+++ /dev/null
@@ -1,642 +0,0 @@
-// 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>
-#import "chrome/browser/cocoa/translate/translate_infobar_base.h"
-
-#include "app/l10n_util.h"
-#include "base/logging.h"
-#include "base/mac_util.h"
-#include "base/metrics/histogram.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/app/chrome_command_ids.h"
-#import "chrome/browser/cocoa/hover_close_button.h"
-#include "chrome/browser/cocoa/infobar.h"
-#import "chrome/browser/cocoa/infobar_controller.h"
-#import "chrome/browser/cocoa/infobar_gradient_view.h"
-#include "chrome/browser/cocoa/translate/after_translate_infobar_controller.h"
-#import "chrome/browser/cocoa/translate/before_translate_infobar_controller.h"
-#include "chrome/browser/cocoa/translate/translate_message_infobar_controller.h"
-#include "chrome/browser/translate/translate_infobar_delegate.h"
-#include "grit/generated_resources.h"
-#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-
-using TranslateInfoBarUtilities::MoveControl;
-using TranslateInfoBarUtilities::VerticallyCenterView;
-using TranslateInfoBarUtilities::VerifyControlOrderAndSpacing;
-using TranslateInfoBarUtilities::CreateLabel;
-using TranslateInfoBarUtilities::AddMenuItem;
-
-#pragma mark TranslateInfoBarUtilities helper functions.
-
-namespace TranslateInfoBarUtilities {
-
-// Move the |toMove| view |spacing| pixels before/after the |anchor| view.
-// |after| signifies the side of |anchor| on which to place |toMove|.
-void MoveControl(NSView* anchor, NSView* toMove, int spacing, bool after) {
- NSRect anchorFrame = [anchor frame];
- NSRect toMoveFrame = [toMove frame];
-
- // At the time of this writing, OS X doesn't natively support BiDi UIs, but
- // it doesn't hurt to be forward looking.
- bool toRight = after;
-
- if (toRight) {
- toMoveFrame.origin.x = NSMaxX(anchorFrame) + spacing;
- } else {
- // Place toMove to theleft of anchor.
- toMoveFrame.origin.x = NSMinX(anchorFrame) -
- spacing - NSWidth(toMoveFrame);
- }
- [toMove setFrame:toMoveFrame];
-}
-
-// Check that the control |before| is ordered visually before the |after|
-// control.
-// Also, check that there is space between them.
-bool VerifyControlOrderAndSpacing(id before, id after) {
- NSRect beforeFrame = [before frame];
- NSRect afterFrame = [after frame];
- return NSMinX(afterFrame) >= NSMaxX(beforeFrame);
-}
-
-// Vertically center |toMove| in its container.
-void VerticallyCenterView(NSView *toMove) {
- NSRect superViewFrame = [[toMove superview] frame];
- NSRect viewFrame = [toMove frame];
- viewFrame.origin.y =
- floor((NSHeight(superViewFrame) - NSHeight(viewFrame))/2.0);
- [toMove setFrame:viewFrame];
-}
-
-// Creates a label control in the style we need for the translate infobar's
-// labels within |bounds|.
-NSTextField* CreateLabel(NSRect bounds) {
- NSTextField* ret = [[NSTextField alloc] initWithFrame:bounds];
- [ret setEditable:NO];
- [ret setDrawsBackground:NO];
- [ret setBordered:NO];
- return ret;
-}
-
-// Adds an item with the specified properties to |menu|.
-void AddMenuItem(NSMenu *menu, id target, SEL selector, NSString* title,
- int tag, bool enabled, bool checked) {
- if (tag == -1) {
- [menu addItem:[NSMenuItem separatorItem]];
- } else {
- NSMenuItem* item = [[[NSMenuItem alloc]
- initWithTitle:title
- action:selector
- keyEquivalent:@""] autorelease];
- [item setTag:tag];
- [menu addItem:item];
- [item setTarget:target];
- if (checked)
- [item setState:NSOnState];
- if (!enabled)
- [item setEnabled:NO];
- }
-}
-
-} // namespace TranslateInfoBarUtilities
-
-// TranslateInfoBarDelegate views specific method:
-InfoBar* TranslateInfoBarDelegate::CreateInfoBar() {
- TranslateInfoBarControllerBase* infobar_controller = NULL;
- switch (type_) {
- case BEFORE_TRANSLATE:
- infobar_controller =
- [[BeforeTranslateInfobarController alloc] initWithDelegate:this];
- break;
- case AFTER_TRANSLATE:
- infobar_controller =
- [[AfterTranslateInfobarController alloc] initWithDelegate:this];
- break;
- case TRANSLATING:
- case TRANSLATION_ERROR:
- infobar_controller =
- [[TranslateMessageInfobarController alloc] initWithDelegate:this];
- break;
- default:
- NOTREACHED();
- }
- return new InfoBar(infobar_controller);
-}
-
-@implementation TranslateInfoBarControllerBase (FrameChangeObserver)
-
-// Triggered when the frame changes. This will figure out what size and
-// visibility the options popup should be.
-- (void)didChangeFrame:(NSNotification*)notification {
- [self adjustOptionsButtonSizeAndVisibilityForView:
- [[self visibleControls] lastObject]];
-}
-
-@end
-
-
-@interface TranslateInfoBarControllerBase (Private)
-
-// Removes all controls so that layout can add in only the controls
-// required.
-- (void)clearAllControls;
-
-// Create all the various controls we need for the toolbar.
-- (void)constructViews;
-
-// Reloads text for all labels for the current state.
-- (void)loadLabelText:(TranslateErrors::Type)error;
-
-// Set the infobar background gradient.
-- (void)setInfoBarGradientColor;
-
-// Main function to update the toolbar graphic state and data model after
-// the state has changed.
-// Controls are moved around as needed and visibility changed to match the
-// current state.
-- (void)updateState;
-
-// Called when the source or target language selection changes in a menu.
-// |newLanguageIdx| is the index of the newly selected item in the appropriate
-// menu.
-- (void)sourceLanguageModified:(NSInteger)newLanguageIdx;
-- (void)targetLanguageModified:(NSInteger)newLanguageIdx;
-
-// Completely rebuild "from" and "to" language menus from the data model.
-- (void)populateLanguageMenus;
-
-@end
-
-#pragma mark TranslateInfoBarController class
-
-@implementation TranslateInfoBarControllerBase
-
-- (id)initWithDelegate:(InfoBarDelegate*)delegate {
- if ((self = [super initWithDelegate:delegate])) {
- originalLanguageMenuModel_.reset(
- new LanguagesMenuModel([self delegate],
- LanguagesMenuModel::ORIGINAL));
-
- targetLanguageMenuModel_.reset(
- new LanguagesMenuModel([self delegate],
- LanguagesMenuModel::TARGET));
- }
- return self;
-}
-
-- (TranslateInfoBarDelegate*)delegate {
- return reinterpret_cast<TranslateInfoBarDelegate*>(delegate_);
-}
-
-- (void)constructViews {
- // Using a zero or very large frame causes GTMUILocalizerAndLayoutTweaker
- // to not resize the view properly so we take the bounds of the first label
- // which is contained in the nib.
- NSRect bogusFrame = [label_ frame];
- label1_.reset(CreateLabel(bogusFrame));
- label2_.reset(CreateLabel(bogusFrame));
- label3_.reset(CreateLabel(bogusFrame));
-
- optionsPopUp_.reset([[NSPopUpButton alloc] initWithFrame:bogusFrame
- pullsDown:YES]);
- fromLanguagePopUp_.reset([[NSPopUpButton alloc] initWithFrame:bogusFrame
- pullsDown:NO]);
- toLanguagePopUp_.reset([[NSPopUpButton alloc] initWithFrame:bogusFrame
- pullsDown:NO]);
- showOriginalButton_.reset([[NSButton alloc] init]);
- translateMessageButton_.reset([[NSButton alloc] init]);
-}
-
-- (void)sourceLanguageModified:(NSInteger)newLanguageIdx {
- DCHECK_GT(newLanguageIdx, -1);
- if (newLanguageIdx == [self delegate]->original_language_index())
- return;
- [self delegate]->SetOriginalLanguage(newLanguageIdx);
- int commandId = IDC_TRANSLATE_ORIGINAL_LANGUAGE_BASE + newLanguageIdx;
- int newMenuIdx = [fromLanguagePopUp_ indexOfItemWithTag:commandId];
- [fromLanguagePopUp_ selectItemAtIndex:newMenuIdx];
-}
-
-- (void)targetLanguageModified:(NSInteger)newLanguageIdx {
- DCHECK_GT(newLanguageIdx, -1);
- if (newLanguageIdx == [self delegate]->target_language_index())
- return;
- [self delegate]->SetTargetLanguage(newLanguageIdx);
- int commandId = IDC_TRANSLATE_TARGET_LANGUAGE_BASE + newLanguageIdx;
- int newMenuIdx = [toLanguagePopUp_ indexOfItemWithTag:commandId];
- [toLanguagePopUp_ selectItemAtIndex:newMenuIdx];
-}
-
-- (void)loadLabelText {
- // Do nothing by default, should be implemented by subclasses.
-}
-
-- (void)updateState {
- [self loadLabelText];
- [self clearAllControls];
- [self showVisibleControls:[self visibleControls]];
- [optionsPopUp_ setHidden:![self shouldShowOptionsPopUp]];
- [self layout];
- [self adjustOptionsButtonSizeAndVisibilityForView:
- [[self visibleControls] lastObject]];
-}
-
-- (void)setInfoBarGradientColor {
- NSColor* startingColor = [NSColor colorWithCalibratedWhite:0.93 alpha:1.0];
- NSColor* endingColor = [NSColor colorWithCalibratedWhite:0.85 alpha:1.0];
- NSGradient* translateInfoBarGradient =
- [[[NSGradient alloc] initWithStartingColor:startingColor
- endingColor:endingColor] autorelease];
-
- [infoBarView_ setGradient:translateInfoBarGradient];
- [infoBarView_
- setStrokeColor:[NSColor colorWithCalibratedWhite:0.75 alpha:1.0]];
-}
-
-- (void)removeOkCancelButtons {
- // Removing okButton_ & cancelButton_ from the view may cause them
- // to be released and since we can still access them from other areas
- // in the code later, we need them to be nil when this happens.
- [okButton_ removeFromSuperview];
- okButton_ = nil;
- [cancelButton_ removeFromSuperview];
- cancelButton_ = nil;
-}
-
-- (void)clearAllControls {
- // Step 1: remove all controls from the infobar so we have a clean slate.
- NSArray *allControls = [self allControls];
-
- for (NSControl* control in allControls) {
- if ([control superview])
- [control removeFromSuperview];
- }
-}
-
-- (void)showVisibleControls:(NSArray*)visibleControls {
- NSRect optionsFrame = [optionsPopUp_ frame];
- for (NSControl* control in visibleControls) {
- [GTMUILocalizerAndLayoutTweaker sizeToFitView:control];
- [control setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin |
- NSViewMaxYMargin];
-
- // Need to check if a view is already attached since |label1_| is always
- // parented and we don't want to add it again.
- if (![control superview])
- [infoBarView_ addSubview:control];
-
- if ([control isKindOfClass:[NSButton class]])
- VerticallyCenterView(control);
-
- // Make "from" and "to" language popup menus the same size as the options
- // menu.
- // We don't autosize since some languages names are really long causing
- // the toolbar to overflow.
- if ([control isKindOfClass:[NSPopUpButton class]])
- [control setFrame:optionsFrame];
- }
-}
-
-- (void)layout {
-
-}
-
-- (NSArray*)visibleControls {
- return [NSArray array];
-}
-
-- (void)rebuildOptionsMenu:(BOOL)hideTitle {
- if (![self shouldShowOptionsPopUp])
- return;
-
- // The options model doesn't know how to handle state transitions, so rebuild
- // it each time through here.
- optionsMenuModel_.reset(
- new OptionsMenuModel([self delegate]));
-
- [optionsPopUp_ removeAllItems];
- // Set title.
- NSString* optionsLabel = hideTitle ? @"" :
- l10n_util::GetNSString(IDS_TRANSLATE_INFOBAR_OPTIONS);
- [optionsPopUp_ addItemWithTitle:optionsLabel];
-
- // Populate options menu.
- NSMenu* optionsMenu = [optionsPopUp_ menu];
- [optionsMenu setAutoenablesItems:NO];
- for (int i = 0; i < optionsMenuModel_->GetItemCount(); ++i) {
- NSString* title = base::SysUTF16ToNSString(
- optionsMenuModel_->GetLabelAt(i));
- int cmd = optionsMenuModel_->GetCommandIdAt(i);
- bool checked = optionsMenuModel_->IsItemCheckedAt(i);
- bool enabled = optionsMenuModel_->IsEnabledAt(i);
- AddMenuItem(optionsMenu,
- self,
- @selector(optionsMenuChanged:),
- title,
- cmd,
- enabled,
- checked);
- }
-}
-
-- (BOOL)shouldShowOptionsPopUp {
- return YES;
-}
-
-- (void)populateLanguageMenus {
- NSMenu* originalLanguageMenu = [fromLanguagePopUp_ menu];
- [originalLanguageMenu setAutoenablesItems:NO];
- int selectedMenuIndex = 0;
- int selectedLangIndex = [self delegate]->original_language_index();
- for (int i = 0; i < originalLanguageMenuModel_->GetItemCount(); ++i) {
- NSString* title = base::SysUTF16ToNSString(
- originalLanguageMenuModel_->GetLabelAt(i));
- int cmd = originalLanguageMenuModel_->GetCommandIdAt(i);
- bool checked = (cmd == selectedLangIndex);
- if (checked)
- selectedMenuIndex = i;
- bool enabled = originalLanguageMenuModel_->IsEnabledAt(i);
- cmd += IDC_TRANSLATE_ORIGINAL_LANGUAGE_BASE;
- AddMenuItem(originalLanguageMenu,
- self,
- @selector(languageMenuChanged:),
- title,
- cmd,
- enabled,
- checked);
- }
- [fromLanguagePopUp_ selectItemAtIndex:selectedMenuIndex];
-
- NSMenu* targetLanguageMenu = [toLanguagePopUp_ menu];
- [targetLanguageMenu setAutoenablesItems:NO];
- selectedLangIndex = [self delegate]->target_language_index();
- for (int i = 0; i < targetLanguageMenuModel_->GetItemCount(); ++i) {
- NSString* title = base::SysUTF16ToNSString(
- targetLanguageMenuModel_->GetLabelAt(i));
- int cmd = targetLanguageMenuModel_->GetCommandIdAt(i);
- bool checked = (cmd == selectedLangIndex);
- if (checked)
- selectedMenuIndex = i;
- bool enabled = targetLanguageMenuModel_->IsEnabledAt(i);
- cmd += IDC_TRANSLATE_TARGET_LANGUAGE_BASE;
- AddMenuItem(targetLanguageMenu,
- self,
- @selector(languageMenuChanged:),
- title,
- cmd,
- enabled,
- checked);
- }
- [toLanguagePopUp_ selectItemAtIndex:selectedMenuIndex];
-}
-
-- (void)addAdditionalControls {
- using l10n_util::GetNSString;
- using l10n_util::GetNSStringWithFixup;
-
- // Get layout information from the NIB.
- NSRect okButtonFrame = [okButton_ frame];
- NSRect cancelButtonFrame = [cancelButton_ frame];
- spaceBetweenControls_ = NSMinX(cancelButtonFrame) - NSMaxX(okButtonFrame);
-
- // Set infobar background color.
- [self setInfoBarGradientColor];
-
- // Instantiate additional controls.
- [self constructViews];
-
- // Set ourselves as the delegate for the options menu so we can populate it
- // dynamically.
- [[optionsPopUp_ menu] setDelegate:self];
-
- // Replace label_ with label1_ so we get a consistent look between all the
- // labels we display in the translate view.
- [[label_ superview] replaceSubview:label_ with:label1_.get()];
- label_.reset(); // Now released.
-
- // Populate contextual menus.
- [self rebuildOptionsMenu:NO];
- [self populateLanguageMenus];
-
- // Set OK & Cancel text.
- [okButton_ setTitle:GetNSStringWithFixup(IDS_TRANSLATE_INFOBAR_ACCEPT)];
- [cancelButton_ setTitle:GetNSStringWithFixup(IDS_TRANSLATE_INFOBAR_DENY)];
-
- // Set up "Show original" and "Try again" buttons.
- [showOriginalButton_ setFrame:okButtonFrame];
-
- // Set each of the buttons and popups to the NSTexturedRoundedBezelStyle
- // (metal-looking) style.
- NSArray* allControls = [self allControls];
- for (NSControl* control in allControls) {
- if (![control isKindOfClass:[NSButton class]])
- continue;
- NSButton* button = (NSButton*)control;
- [button setBezelStyle:NSTexturedRoundedBezelStyle];
- if ([button isKindOfClass:[NSPopUpButton class]]) {
- [[button cell] setArrowPosition:NSPopUpArrowAtBottom];
- }
- }
- // The options button is handled differently than the rest as it floats
- // to the right.
- [optionsPopUp_ setBezelStyle:NSTexturedRoundedBezelStyle];
- [[optionsPopUp_ cell] setArrowPosition:NSPopUpArrowAtBottom];
-
- [showOriginalButton_ setTarget:self];
- [showOriginalButton_ setAction:@selector(showOriginal:)];
- [translateMessageButton_ setTarget:self];
- [translateMessageButton_ setAction:@selector(messageButtonPressed:)];
-
- [showOriginalButton_
- setTitle:GetNSStringWithFixup(IDS_TRANSLATE_INFOBAR_REVERT)];
-
- // Add and configure controls that are visible in all modes.
- [optionsPopUp_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin |
- NSViewMaxYMargin];
- // Add "options" popup z-ordered below all other controls so when we
- // resize the toolbar it doesn't hide them.
- [infoBarView_ addSubview:optionsPopUp_
- positioned:NSWindowBelow
- relativeTo:nil];
- [GTMUILocalizerAndLayoutTweaker sizeToFitView:optionsPopUp_];
- MoveControl(closeButton_, optionsPopUp_, spaceBetweenControls_, false);
- VerticallyCenterView(optionsPopUp_);
-
- [infoBarView_ setPostsFrameChangedNotifications:YES];
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(didChangeFrame:)
- name:NSViewFrameDidChangeNotification
- object:infoBarView_];
- // Show and place GUI elements.
- [self updateState];
-}
-
-- (void)adjustOptionsButtonSizeAndVisibilityForView:(NSView*)lastView {
- [optionsPopUp_ setHidden:NO];
- [self rebuildOptionsMenu:NO];
- [[optionsPopUp_ cell] setArrowPosition:NSPopUpArrowAtBottom];
- [optionsPopUp_ sizeToFit];
-
- MoveControl(closeButton_, optionsPopUp_, spaceBetweenControls_, false);
- if (!VerifyControlOrderAndSpacing(lastView, optionsPopUp_)) {
- [self rebuildOptionsMenu:YES];
- NSRect oldFrame = [optionsPopUp_ frame];
- oldFrame.size.width = NSHeight(oldFrame);
- [optionsPopUp_ setFrame:oldFrame];
- [[optionsPopUp_ cell] setArrowPosition:NSPopUpArrowAtCenter];
- MoveControl(closeButton_, optionsPopUp_, spaceBetweenControls_, false);
- if (!VerifyControlOrderAndSpacing(lastView, optionsPopUp_)) {
- [optionsPopUp_ setHidden:YES];
- }
- }
-}
-
-// Called when "Translate" button is clicked.
-- (IBAction)ok:(id)sender {
- TranslateInfoBarDelegate* delegate = [self delegate];
- TranslateInfoBarDelegate::Type state = delegate->type();
- DCHECK(state == TranslateInfoBarDelegate::BEFORE_TRANSLATE ||
- state == TranslateInfoBarDelegate::TRANSLATION_ERROR);
- delegate->Translate();
- UMA_HISTOGRAM_COUNTS("Translate.Translate", 1);
-}
-
-// Called when someone clicks on the "Nope" button.
-- (IBAction)cancel:(id)sender {
- DCHECK(
- [self delegate]->type() == TranslateInfoBarDelegate::BEFORE_TRANSLATE);
- [self delegate]->TranslationDeclined();
- UMA_HISTOGRAM_COUNTS("Translate.DeclineTranslate", 1);
- [super dismiss:nil];
-}
-
-- (void)messageButtonPressed:(id)sender {
- [self delegate]->MessageInfoBarButtonPressed();
-}
-
-- (IBAction)showOriginal:(id)sender {
- [self delegate]->RevertTranslation();
-}
-
-// Called when any of the language drop down menus are changed.
-- (void)languageMenuChanged:(id)item {
- if ([item respondsToSelector:@selector(tag)]) {
- int cmd = [item tag];
- if (cmd >= IDC_TRANSLATE_TARGET_LANGUAGE_BASE) {
- cmd -= IDC_TRANSLATE_TARGET_LANGUAGE_BASE;
- [self targetLanguageModified:cmd];
- return;
- } else if (cmd >= IDC_TRANSLATE_ORIGINAL_LANGUAGE_BASE) {
- cmd -= IDC_TRANSLATE_ORIGINAL_LANGUAGE_BASE;
- [self sourceLanguageModified:cmd];
- return;
- }
- }
- NOTREACHED() << "Language menu was changed with a bad language ID";
-}
-
-// Called when the options menu is changed.
-- (void)optionsMenuChanged:(id)item {
- if ([item respondsToSelector:@selector(tag)]) {
- int cmd = [item tag];
- // Danger Will Robinson! : This call can release the infobar (e.g. invoking
- // "About Translate" can open a new tab).
- // Do not access member variables after this line!
- optionsMenuModel_->ExecuteCommand(cmd);
- } else {
- NOTREACHED();
- }
-}
-
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [super dealloc];
-}
-
-#pragma mark NSMenuDelegate
-
-// Invoked by virtue of us being set as the delegate for the options menu.
-- (void)menuNeedsUpdate:(NSMenu *)menu {
- [self adjustOptionsButtonSizeAndVisibilityForView:
- [[self visibleControls] lastObject]];
-}
-
-@end
-
-@implementation TranslateInfoBarControllerBase (TestingAPI)
-
-- (NSArray*)allControls {
- return [NSArray arrayWithObjects:label1_.get(),fromLanguagePopUp_.get(),
- label2_.get(), toLanguagePopUp_.get(), label3_.get(), okButton_,
- cancelButton_, showOriginalButton_.get(), translateMessageButton_.get(),
- nil];
-}
-
-- (NSMenu*)optionsMenu {
- return [optionsPopUp_ menu];
-}
-
-- (NSButton*)translateMessageButton {
- return translateMessageButton_.get();
-}
-
-- (bool)verifyLayout {
- // All the controls available to translate infobars, except the options popup.
- // The options popup is shown/hidden instead of actually removed. This gets
- // checked in the subclasses.
- NSArray* allControls = [self allControls];
- NSArray* visibleControls = [self visibleControls];
-
- // Step 1: Make sure control visibility is what we expect.
- for (NSUInteger i = 0; i < [allControls count]; ++i) {
- id control = [allControls objectAtIndex:i];
- bool hasSuperView = [control superview];
- bool expectedVisibility = [visibleControls containsObject:control];
-
- if (expectedVisibility != hasSuperView) {
- NSString *title = @"";
- if ([control isKindOfClass:[NSPopUpButton class]]) {
- title = [[[control menu] itemAtIndex:0] title];
- }
-
- LOG(ERROR) <<
- "State: " << [self description] <<
- " Control @" << i << (hasSuperView ? " has" : " doesn't have") <<
- " a superview" << [[control description] UTF8String] <<
- " Title=" << [title UTF8String];
- return false;
- }
- }
-
- // Step 2: Check that controls are ordered correctly with no overlap.
- id previousControl = nil;
- for (NSUInteger i = 0; i < [visibleControls count]; ++i) {
- id control = [visibleControls objectAtIndex:i];
- // The options pop up doesn't lay out like the rest of the controls as
- // it floats to the right. It has some known issues shown in
- // http://crbug.com/47941.
- if (control == optionsPopUp_.get())
- continue;
- if (previousControl &&
- !VerifyControlOrderAndSpacing(previousControl, control)) {
- NSString *title = @"";
- if ([control isKindOfClass:[NSPopUpButton class]]) {
- title = [[[control menu] itemAtIndex:0] title];
- }
- LOG(ERROR) <<
- "State: " << [self description] <<
- " Control @" << i << " not ordered correctly: " <<
- [[control description] UTF8String] <<[title UTF8String];
- return false;
- }
- previousControl = control;
- }
-
- return true;
-}
-
-@end // TranslateInfoBarControllerBase (TestingAPI)
-
diff --git a/chrome/browser/cocoa/translate/translate_infobar_unittest.mm b/chrome/browser/cocoa/translate/translate_infobar_unittest.mm
deleted file mode 100644
index fbe85b0..0000000
--- a/chrome/browser/cocoa/translate/translate_infobar_unittest.mm
+++ /dev/null
@@ -1,254 +0,0 @@
-// Copyright (c) 2009 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>
-
-#import "base/scoped_nsobject.h"
-#import "base/string_util.h"
-#include "base/utf_string_conversions.h"
-#import "chrome/app/chrome_command_ids.h" // For translate menu command ids.
-#import "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/infobar.h"
-#import "chrome/browser/cocoa/translate/translate_infobar_base.h"
-#import "chrome/browser/cocoa/translate/before_translate_infobar_controller.h"
-#import "chrome/browser/renderer_host/site_instance.h"
-#import "chrome/browser/tab_contents/tab_contents.h"
-#import "chrome/browser/translate/translate_infobar_delegate.h"
-#import "testing/gmock/include/gmock/gmock.h"
-#import "testing/gtest/include/gtest/gtest.h"
-#import "testing/platform_test.h"
-
-namespace {
-
-// All states the translate toolbar can assume.
-TranslateInfoBarDelegate::Type kTranslateToolbarStates[] = {
- TranslateInfoBarDelegate::BEFORE_TRANSLATE,
- TranslateInfoBarDelegate::AFTER_TRANSLATE,
- TranslateInfoBarDelegate::TRANSLATING,
- TranslateInfoBarDelegate::TRANSLATION_ERROR
-};
-
-class MockTranslateInfoBarDelegate : public TranslateInfoBarDelegate {
- public:
- MockTranslateInfoBarDelegate(TranslateInfoBarDelegate::Type type,
- TranslateErrors::Type error,
- TabContents* contents)
- : TranslateInfoBarDelegate(type, error, contents, "en", "es"){
- // Start out in the "Before Translate" state.
- type_ = type;
-
- }
-
- virtual string16 GetDisplayNameForLocale(const std::string& language_code) {
- return ASCIIToUTF16("Foo");
- }
-
- virtual bool IsLanguageBlacklisted() {
- return false;
- }
-
- virtual bool IsSiteBlacklisted() {
- return false;
- }
-
- virtual bool ShouldAlwaysTranslate() {
- return false;
- }
-
- MOCK_METHOD0(Translate, void());
- MOCK_METHOD0(RevertTranslation, void());
- MOCK_METHOD0(TranslationDeclined, void());
- MOCK_METHOD0(ToggleLanguageBlacklist, void());
- MOCK_METHOD0(ToggleSiteBlacklist, void());
- MOCK_METHOD0(ToggleAlwaysTranslate, void());
-};
-
-class TranslationInfoBarTest : public CocoaTest {
- public:
- BrowserTestHelper browser_helper_;
- scoped_ptr<TabContents> tab_contents;
- scoped_ptr<MockTranslateInfoBarDelegate> infobar_delegate;
- scoped_nsobject<TranslateInfoBarControllerBase> infobar_controller;
-
- public:
- // Each test gets a single Mock translate delegate for the lifetime of
- // the test.
- virtual void SetUp() {
- CocoaTest::SetUp();
- tab_contents.reset(
- new TabContents(browser_helper_.profile(),
- NULL,
- MSG_ROUTING_NONE,
- NULL,
- NULL));
- CreateInfoBar();
- }
-
- void CreateInfoBar() {
- CreateInfoBar(TranslateInfoBarDelegate::BEFORE_TRANSLATE);
- }
-
- void CreateInfoBar(TranslateInfoBarDelegate::Type type) {
- TranslateErrors::Type error = TranslateErrors::NONE;
- if (type == TranslateInfoBarDelegate::TRANSLATION_ERROR)
- error = TranslateErrors::NETWORK;
- infobar_delegate.reset(
- new MockTranslateInfoBarDelegate(type, error, tab_contents.get()));
- [[infobar_controller view] removeFromSuperview];
- scoped_ptr<InfoBar> infobar(infobar_delegate->CreateInfoBar());
- infobar_controller.reset(
- reinterpret_cast<TranslateInfoBarControllerBase*>(
- infobar->controller()));
- // We need to set the window to be wide so that the options button
- // doesn't overlap the other buttons.
- [test_window() setContentSize:NSMakeSize(2000, 500)];
- [[infobar_controller view] setFrame:NSMakeRect(0, 0, 2000, 500)];
- [[test_window() contentView] addSubview:[infobar_controller view]];
- }
-};
-
-// Check that we can instantiate a Translate Infobar correctly.
-TEST_F(TranslationInfoBarTest, Instantiate) {
- CreateInfoBar();
- ASSERT_TRUE(infobar_controller.get());
-}
-
-// Check that clicking the Translate button calls Translate().
-TEST_F(TranslationInfoBarTest, TranslateCalledOnButtonPress) {
- CreateInfoBar();
-
- EXPECT_CALL(*infobar_delegate, Translate()).Times(1);
- [infobar_controller ok:nil];
-}
-
-// Check that clicking the "Retry" button calls Translate() when we're
-// in the error mode - http://crbug.com/41315 .
-TEST_F(TranslationInfoBarTest, TranslateCalledInErrorMode) {
- CreateInfoBar(TranslateInfoBarDelegate::TRANSLATION_ERROR);
-
- EXPECT_CALL(*infobar_delegate, Translate()).Times(1);
-
- [infobar_controller ok:nil];
-}
-
-// Check that clicking the "Show Original button calls RevertTranslation().
-TEST_F(TranslationInfoBarTest, RevertCalledOnButtonPress) {
- CreateInfoBar();
-
- EXPECT_CALL(*infobar_delegate, RevertTranslation()).Times(1);
- [infobar_controller showOriginal:nil];
-}
-
-// Check that items in the options menu are hooked up correctly.
-TEST_F(TranslationInfoBarTest, OptionsMenuItemsHookedUp) {
- EXPECT_CALL(*infobar_delegate, Translate())
- .Times(0);
-
- [infobar_controller rebuildOptionsMenu:NO];
- NSMenu* optionsMenu = [infobar_controller optionsMenu];
- NSArray* optionsMenuItems = [optionsMenu itemArray];
-
- EXPECT_EQ(7U, [optionsMenuItems count]);
-
- // First item is the options menu button's title, so there's no need to test
- // that the target on that is setup correctly.
- for (NSUInteger i = 1; i < [optionsMenuItems count]; ++i) {
- NSMenuItem* item = [optionsMenuItems objectAtIndex:i];
- if (![item isSeparatorItem])
- EXPECT_EQ([item target], infobar_controller.get());
- }
- NSMenuItem* alwaysTranslateLanguateItem = [optionsMenuItems objectAtIndex:1];
- NSMenuItem* neverTranslateLanguateItem = [optionsMenuItems objectAtIndex:2];
- NSMenuItem* neverTranslateSiteItem = [optionsMenuItems objectAtIndex:3];
- // Separator at 4.
- NSMenuItem* reportBadLanguageItem = [optionsMenuItems objectAtIndex:5];
- NSMenuItem* aboutTranslateItem = [optionsMenuItems objectAtIndex:6];
-
- {
- EXPECT_CALL(*infobar_delegate, ToggleAlwaysTranslate())
- .Times(1);
- [infobar_controller optionsMenuChanged:alwaysTranslateLanguateItem];
- }
-
- {
- EXPECT_CALL(*infobar_delegate, ToggleLanguageBlacklist())
- .Times(1);
- [infobar_controller optionsMenuChanged:neverTranslateLanguateItem];
- }
-
- {
- EXPECT_CALL(*infobar_delegate, ToggleSiteBlacklist())
- .Times(1);
- [infobar_controller optionsMenuChanged:neverTranslateSiteItem];
- }
-
- {
- // Can't mock these effectively, so just check that the tag is set
- // correctly.
- EXPECT_EQ(IDC_TRANSLATE_REPORT_BAD_LANGUAGE_DETECTION,
- [reportBadLanguageItem tag]);
- EXPECT_EQ(IDC_TRANSLATE_OPTIONS_ABOUT, [aboutTranslateItem tag]);
- }
-}
-
-// Check that selecting a new item from the "Source Language" popup in "before
-// translate" mode doesn't trigger a translation or change state.
-// http://crbug.com/36666
-TEST_F(TranslationInfoBarTest, Bug36666) {
- EXPECT_CALL(*infobar_delegate, Translate())
- .Times(0);
-
- CreateInfoBar();
- int arbitrary_index = 2;
- [infobar_controller sourceLanguageModified:arbitrary_index];
- EXPECT_CALL(*infobar_delegate, Translate())
- .Times(0);
-}
-
-// Check that the infobar lays itself out correctly when instantiated in
-// each of the states.
-// http://crbug.com/36895
-TEST_F(TranslationInfoBarTest, Bug36895) {
- EXPECT_CALL(*infobar_delegate, Translate())
- .Times(0);
-
- for (size_t i = 0; i < arraysize(kTranslateToolbarStates); ++i) {
- CreateInfoBar(kTranslateToolbarStates[i]);
- EXPECT_TRUE(
- [infobar_controller verifyLayout]) << "Layout wrong, for state #" << i;
- }
-}
-
-// Verify that the infobar shows the "Always translate this language" button
-// after doing 3 translations.
-TEST_F(TranslationInfoBarTest, TriggerShowAlwaysTranslateButton) {
- TranslatePrefs translate_prefs(browser_helper_.profile()->GetPrefs());
- translate_prefs.ResetTranslationAcceptedCount("en");
- for (int i = 0; i < 4; ++i) {
- translate_prefs.IncrementTranslationAcceptedCount("en");
- }
- CreateInfoBar(TranslateInfoBarDelegate::BEFORE_TRANSLATE);
- BeforeTranslateInfobarController* controller =
- (BeforeTranslateInfobarController*)infobar_controller.get();
- EXPECT_TRUE([[controller alwaysTranslateButton] superview] != nil);
- EXPECT_TRUE([[controller neverTranslateButton] superview] == nil);
-}
-
-// Verify that the infobar shows the "Never translate this language" button
-// after denying 3 translations.
-TEST_F(TranslationInfoBarTest, TriggerShowNeverTranslateButton) {
- TranslatePrefs translate_prefs(browser_helper_.profile()->GetPrefs());
- translate_prefs.ResetTranslationDeniedCount("en");
- for (int i = 0; i < 4; ++i) {
- translate_prefs.IncrementTranslationDeniedCount("en");
- }
- CreateInfoBar(TranslateInfoBarDelegate::BEFORE_TRANSLATE);
- BeforeTranslateInfobarController* controller =
- (BeforeTranslateInfobarController*)infobar_controller.get();
- EXPECT_TRUE([[controller alwaysTranslateButton] superview] == nil);
- EXPECT_TRUE([[controller neverTranslateButton] superview] != nil);
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/translate/translate_message_infobar_controller.h b/chrome/browser/cocoa/translate/translate_message_infobar_controller.h
deleted file mode 100644
index 985bf2a..0000000
--- a/chrome/browser/cocoa/translate/translate_message_infobar_controller.h
+++ /dev/null
@@ -1,10 +0,0 @@
-// 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 "chrome/browser/cocoa/translate/translate_infobar_base.h"
-
-@interface TranslateMessageInfobarController : TranslateInfoBarControllerBase {
-}
-
-@end
diff --git a/chrome/browser/cocoa/translate/translate_message_infobar_controller.mm b/chrome/browser/cocoa/translate/translate_message_infobar_controller.mm
deleted file mode 100644
index 1146fdc..0000000
--- a/chrome/browser/cocoa/translate/translate_message_infobar_controller.mm
+++ /dev/null
@@ -1,53 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/translate/translate_message_infobar_controller.h"
-
-#include "base/sys_string_conversions.h"
-
-using TranslateInfoBarUtilities::MoveControl;
-
-@implementation TranslateMessageInfobarController
-
-- (void)layout {
- [self removeOkCancelButtons];
- MoveControl(label1_, translateMessageButton_, spaceBetweenControls_ * 2, true);
- TranslateInfoBarDelegate* delegate = [self delegate];
- if ([self delegate]->ShouldShowMessageInfoBarButton()) {
- string16 buttonText = delegate->GetMessageInfoBarButtonText();
- [translateMessageButton_ setTitle:base::SysUTF16ToNSString(buttonText)];
- [translateMessageButton_ sizeToFit];
- }
-}
-
-- (void)adjustOptionsButtonSizeAndVisibilityForView:(NSView*)lastView {
- // Do nothing, but stop the options button from showing up.
-}
-
-- (NSArray*)visibleControls {
- NSMutableArray* visibleControls =
- [NSMutableArray arrayWithObjects:label1_.get(), nil];
- if ([self delegate]->ShouldShowMessageInfoBarButton())
- [visibleControls addObject:translateMessageButton_];
- return visibleControls;
-}
-
-- (void)loadLabelText {
- TranslateInfoBarDelegate* delegate = [self delegate];
- string16 messageText = delegate->GetMessageInfoBarText();
- NSString* string1 = base::SysUTF16ToNSString(messageText);
- [label1_ setStringValue:string1];
-}
-
-- (bool)verifyLayout {
- if (![optionsPopUp_ isHidden])
- return false;
- return [super verifyLayout];
-}
-
-- (BOOL)shouldShowOptionsPopUp {
- return NO;
-}
-
-@end
diff --git a/chrome/browser/cocoa/ui_localizer.h b/chrome/browser/cocoa/ui_localizer.h
deleted file mode 100644
index 1ac9f0a..0000000
--- a/chrome/browser/cocoa/ui_localizer.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_UI_LOCALIZER_H_
-#define CHROME_BROWSER_COCOA_UI_LOCALIZER_H_
-#pragma once
-
-#import "third_party/GTM/AppKit/GTMUILocalizer.h"
-
-@class NSString;
-
-// A base class for generated localizers.
-//
-// To use this, include your xib file in the list generate_localizer scans (see
-// chrome.gyp). Then add an instance of ChromeUILocalizer to the xib.
-// Connect the owner_ outlet of the instance to the "File's Owner" of the xib.
-// It expects the owner_ outlet to be an instance or subclass of
-// NSWindowController or NSViewController. It will then localize any items in
-// the NSWindowController's window and subviews, or the NSViewController's view
-// and subviews, when awakeFromNib is called on the instance. You can
-// optionally hook up otherObjectToLocalize_ and yetAnotherObjectToLocalize_ and
-// those will also be localized. Strings in the xib that you want localized must
-// start with ^IDS. The value must be a valid resource constant.
-// Things that will be localized are:
-// - Titles and altTitles (for menus, buttons, windows, menuitems, -tabViewItem)
-// - -stringValue (for labels)
-// - tooltips
-// - accessibility help
-// - accessibility descriptions
-// - menus
-@interface ChromeUILocalizer : GTMUILocalizer
-@end
-
-#endif // CHROME_BROWSER_COCOA_UI_LOCALIZER_H_
diff --git a/chrome/browser/cocoa/ui_localizer.mm b/chrome/browser/cocoa/ui_localizer.mm
deleted file mode 100644
index d085353..0000000
--- a/chrome/browser/cocoa/ui_localizer.mm
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/ui_localizer.h"
-
-#import <Foundation/Foundation.h>
-
-#include <stdlib.h>
-#include "app/l10n_util.h"
-#include "app/l10n_util_mac.h"
-#include "base/sys_string_conversions.h"
-#include "base/logging.h"
-#include "grit/app_strings.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-
-struct UILocalizerResourceMap {
- const char* const name;
- unsigned int label_id;
- unsigned int label_arg_id;
-};
-
-
-namespace {
-
-// Utility function for bsearch on a ResourceMap table
-int ResourceMapCompare(const void* utf8Void,
- const void* resourceMapVoid) {
- const char* utf8_key = reinterpret_cast<const char*>(utf8Void);
- const UILocalizerResourceMap* res_map =
- reinterpret_cast<const UILocalizerResourceMap*> (resourceMapVoid);
- return strcmp(utf8_key, res_map->name);
-}
-
-} // namespace
-
-@interface GTMUILocalizer (PrivateAdditions)
-- (void)localizedObjects;
-@end
-
-@implementation GTMUILocalizer (PrivateAdditions)
-- (void)localizedObjects {
- // The ivars are private, so this method lets us trigger the localization
- // from -[ChromeUILocalizer awakeFromNib].
- [self localizeObject:owner_ recursively:YES];
- [self localizeObject:otherObjectToLocalize_ recursively:YES];
- [self localizeObject:yetAnotherObjectToLocalize_ recursively:YES];
-}
- @end
-
-@implementation ChromeUILocalizer
-
-- (void)awakeFromNib {
- // The GTM base is bundle based, since don't need the bundle, use this
- // override to bypass the bundle lookup and directly do the localization
- // calls.
- [self localizedObjects];
-}
-
-- (NSString *)localizedStringForString:(NSString *)string {
-
- // Include the table here so it is a local static. This header provides
- // kUIResources and kUIResourcesSize.
-#include "ui_localizer_table.h"
-
- // Look up the string for the resource id to fetch.
- const char* utf8_key = [string UTF8String];
- if (utf8_key) {
- const void* valVoid = bsearch(utf8_key,
- kUIResources,
- kUIResourcesSize,
- sizeof(UILocalizerResourceMap),
- ResourceMapCompare);
- const UILocalizerResourceMap* val =
- reinterpret_cast<const UILocalizerResourceMap*>(valVoid);
- if (val) {
- // Do we need to build the string, or just fetch it?
- if (val->label_arg_id != 0) {
- const string16 label_arg(l10n_util::GetStringUTF16(val->label_arg_id));
- return l10n_util::GetNSStringFWithFixup(val->label_id,
- label_arg);
- }
-
- return l10n_util::GetNSStringWithFixup(val->label_id);
- }
-
- // Sanity check, there shouldn't be any strings with this id that aren't
- // in our map.
- DLOG_IF(WARNING, [string hasPrefix:@"^ID"]) << "Key '" << utf8_key
- << "' wasn't in the resource map?";
- }
-
- // If we didn't find anything, this string doesn't need localizing.
- return nil;
-}
-
-@end
diff --git a/chrome/browser/cocoa/url_drop_target.h b/chrome/browser/cocoa/url_drop_target.h
deleted file mode 100644
index f362b8a..0000000
--- a/chrome/browser/cocoa/url_drop_target.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_URL_DROP_TARGET_H_
-#define CHROME_BROWSER_COCOA_URL_DROP_TARGET_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-@protocol URLDropTarget;
-@protocol URLDropTargetController;
-
-// Object which coordinates the dropping of URLs on a given view, sending data
-// and updates to a controller.
-@interface URLDropTargetHandler : NSObject {
- @private
- NSView<URLDropTarget>* view_; // weak
-}
-
-// Returns an array of drag types that can be handled.
-+ (NSArray*)handledDragTypes;
-
-// Initialize the given view, which must implement the |URLDropTarget| (below),
-// to accept drops of URLs.
-- (id)initWithView:(NSView<URLDropTarget>*)view;
-
-// The owner view should implement the following methods by calling the
-// |URLDropTargetHandler|'s version, and leave the others to the default
-// implementation provided by |NSView|/|NSWindow|.
-- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender;
-- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender;
-- (void)draggingExited:(id<NSDraggingInfo>)sender;
-- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender;
-
-@end // @interface URLDropTargetHandler
-
-// Protocol which views that are URL drop targets and use |URLDropTargetHandler|
-// must implement.
-@protocol URLDropTarget
-
-// Returns the controller which handles the drop.
-- (id<URLDropTargetController>)urlDropController;
-
-// The following, which come from |NSDraggingDestination|, must be implemented
-// by calling the |URLDropTargetHandler|'s implementations.
-- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender;
-- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender;
-- (void)draggingExited:(id<NSDraggingInfo>)sender;
-- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender;
-
-@end // @protocol URLDropTarget
-
-// Protocol for the controller which handles the actual drop data/drop updates.
-@protocol URLDropTargetController
-
-// The given URLs (an |NSArray| of |NSString|s) were dropped in the given view
-// at the given point (in that view's coordinates).
-- (void)dropURLs:(NSArray*)urls inView:(NSView*)view at:(NSPoint)point;
-
-// Dragging is in progress over the owner view (at the given point, in view
-// coordinates) and any indicator of location -- e.g., an arrow -- should be
-// updated/shown.
-- (void)indicateDropURLsInView:(NSView*)view at:(NSPoint)point;
-
-// Dragging is over, and any indicator should be hidden.
-- (void)hideDropURLsIndicatorInView:(NSView*)view;
-
-@end // @protocol URLDropTargetController
-
-#endif // CHROME_BROWSER_COCOA_URL_DROP_TARGET_H_
diff --git a/chrome/browser/cocoa/url_drop_target.mm b/chrome/browser/cocoa/url_drop_target.mm
deleted file mode 100644
index 5c648b8..0000000
--- a/chrome/browser/cocoa/url_drop_target.mm
+++ /dev/null
@@ -1,98 +0,0 @@
-// 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 "chrome/browser/cocoa/url_drop_target.h"
-
-#include "base/basictypes.h"
-#import "third_party/mozilla/NSPasteboard+Utils.h"
-
-@interface URLDropTargetHandler(Private)
-
-// Gets the appropriate drag operation given the |NSDraggingInfo|.
-- (NSDragOperation)getDragOperation:(id<NSDraggingInfo>)sender;
-
-// Tell the window controller to hide the drop indicator.
-- (void)hideIndicator;
-
-@end // @interface URLDropTargetHandler(Private)
-
-@implementation URLDropTargetHandler
-
-+ (NSArray*)handledDragTypes {
- return [NSArray arrayWithObjects:kWebURLsWithTitlesPboardType,
- NSURLPboardType,
- NSStringPboardType,
- NSFilenamesPboardType,
- nil];
-}
-
-- (id)initWithView:(NSView<URLDropTarget>*)view {
- if ((self = [super init])) {
- view_ = view;
- [view_ registerForDraggedTypes:[URLDropTargetHandler handledDragTypes]];
- }
- return self;
-}
-
-// The following four methods implement parts of the |NSDraggingDestination|
-// protocol, which the owner should "forward" to its |URLDropTargetHandler|
-// (us).
-
-- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
- return [self getDragOperation:sender];
-}
-
-- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender {
- NSDragOperation dragOp = [self getDragOperation:sender];
- if (dragOp == NSDragOperationCopy) {
- // Just tell the window controller to update the indicator.
- NSPoint hoverPoint = [view_ convertPoint:[sender draggingLocation]
- fromView:nil];
- [[view_ urlDropController] indicateDropURLsInView:view_ at:hoverPoint];
- }
- return dragOp;
-}
-
-- (void)draggingExited:(id<NSDraggingInfo>)sender {
- [self hideIndicator];
-}
-
-- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
- [self hideIndicator];
-
- NSPasteboard* pboard = [sender draggingPasteboard];
- if ([pboard containsURLData]) {
- NSArray* urls = nil;
- NSArray* titles; // discarded
- [pboard getURLs:&urls andTitles:&titles convertingFilenames:YES];
-
- if ([urls count]) {
- // Tell the window controller about the dropped URL(s).
- NSPoint dropPoint =
- [view_ convertPoint:[sender draggingLocation] fromView:nil];
- [[view_ urlDropController] dropURLs:urls inView:view_ at:dropPoint];
- return YES;
- }
- }
-
- return NO;
-}
-
-@end // @implementation URLDropTargetHandler
-
-@implementation URLDropTargetHandler(Private)
-
-- (NSDragOperation)getDragOperation:(id<NSDraggingInfo>)sender {
- if (![[sender draggingPasteboard] containsURLData])
- return NSDragOperationNone;
-
- // Only allow the copy operation.
- return [sender draggingSourceOperationMask] & NSDragOperationCopy;
-}
-
-- (void)hideIndicator {
- [[view_ urlDropController] hideDropURLsIndicatorInView:view_];
-}
-
-@end // @implementation URLDropTargetHandler(Private)
diff --git a/chrome/browser/cocoa/vertical_gradient_view.h b/chrome/browser/cocoa/vertical_gradient_view.h
deleted file mode 100644
index 299209f..0000000
--- a/chrome/browser/cocoa/vertical_gradient_view.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_VERTICAL_GRADIENT_VIEW_H_
-#define CHROME_BROWSER_COCOA_VERTICAL_GRADIENT_VIEW_H_
-#pragma once
-
-#include "base/scoped_nsobject.h"
-
-#import <Cocoa/Cocoa.h>
-
-// Draws a vertical background gradient with a bottom stroke. The gradient and
-// stroke colors can be defined by calling |setGradient| and |setStrokeColor|,
-// respectively. Alternatively, you may override the |gradient| and
-// |strokeColor| accessors in order to provide colors dynamically. If the
-// gradient or color is |nil|, the respective element will not be drawn.
-@interface VerticalGradientView : NSView {
- @private
- // The gradient to draw.
- scoped_nsobject<NSGradient> gradient_;
- // Color for bottom stroke.
- scoped_nsobject<NSColor> strokeColor_;
-}
-
-// Gets and sets the gradient to paint as background.
-- (NSGradient*)gradient;
-- (void)setGradient:(NSGradient*)gradient;
-
-// Gets and sets the color of the stroke drawn at the bottom of the view.
-- (NSColor*)strokeColor;
-- (void)setStrokeColor:(NSColor*)gradient;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_VERTICAL_GRADIENT_VIEW_H_
diff --git a/chrome/browser/cocoa/vertical_gradient_view.mm b/chrome/browser/cocoa/vertical_gradient_view.mm
deleted file mode 100644
index 701053d..0000000
--- a/chrome/browser/cocoa/vertical_gradient_view.mm
+++ /dev/null
@@ -1,39 +0,0 @@
-// 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.
-
-#include "chrome/browser/cocoa/vertical_gradient_view.h"
-
-@implementation VerticalGradientView
-
-- (NSGradient*)gradient {
- return gradient_;
-}
-
-- (void)setGradient:(NSGradient*)gradient {
- gradient_.reset([gradient retain]);
-}
-
-- (NSColor*)strokeColor {
- return strokeColor_;
-}
-
-- (void)setStrokeColor:(NSColor*)strokeColor {
- strokeColor_.reset([strokeColor retain]);
-}
-
-- (void)drawRect:(NSRect)rect {
- // Draw gradient.
- [[self gradient] drawInRect:[self bounds] angle:270];
-
- // Draw bottom stroke.
- NSColor* strokeColor = [self strokeColor];
- if (strokeColor) {
- [[self strokeColor] set];
- NSRect borderRect, contentRect;
- NSDivideRect([self bounds], &borderRect, &contentRect, 1, NSMinYEdge);
- NSRectFillUsingOperation(borderRect, NSCompositeSourceOver);
- }
-}
-
-@end
diff --git a/chrome/browser/cocoa/vertical_gradient_view_unittest.mm b/chrome/browser/cocoa/vertical_gradient_view_unittest.mm
deleted file mode 100644
index 2e4e0a7..0000000
--- a/chrome/browser/cocoa/vertical_gradient_view_unittest.mm
+++ /dev/null
@@ -1,27 +0,0 @@
-// 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.
-
-#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/vertical_gradient_view.h"
-
-namespace {
-
-class VerticalGradientViewTest : public CocoaTest {
- public:
- VerticalGradientViewTest() {
- NSRect frame = NSMakeRect(0, 0, 50, 27);
- scoped_nsobject<VerticalGradientView> view(
- [[VerticalGradientView alloc] initWithFrame:frame]);
- view_ = view.get();
- [[test_window() contentView] addSubview:view_];
- }
-
- VerticalGradientView* view_;
-};
-
-TEST_VIEW(VerticalGradientViewTest, view_);
-
-} // namespace
-
diff --git a/chrome/browser/cocoa/view_id_util.h b/chrome/browser/cocoa/view_id_util.h
deleted file mode 100644
index e2b0291..0000000
--- a/chrome/browser/cocoa/view_id_util.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_VIEW_ID_UTIL_H_
-#define CHROME_BROWSER_COCOA_VIEW_ID_UTIL_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "gfx/native_widget_types.h"
-#include "chrome/browser/view_ids.h"
-
-// ViewIDs are a system that indexes important views in the browser window by a
-// ViewID identifier (integer). This is a useful compatibility for finding a
-// view object in cross-platform tests. See BrowserFocusTest.* for an example
-// of how ViewIDs are used.
-
-// For views with fixed ViewIDs, we add a -viewID method to them to return their
-// ViewIDs directly. But for views with changeable ViewIDs, as NSView itself
-// doesn't provide a facility to store its ViewID, to avoid modifying each
-// individual classes for adding ViewID support, we use an internal map to store
-// ViewIDs of each view and provide some utility functions for NSView to
-// set/unset the ViewID and lookup a view with a specified ViewID.
-
-namespace view_id_util {
-
-// Associates the given ViewID with the view. It shall be called upon the view's
-// initialization.
-void SetID(NSView* view, ViewID viewID);
-
-// Removes the association between the view and its ViewID. It shall be called
-// just before the view's destruction.
-void UnsetID(NSView* view);
-
-// Returns the view with a specific ViewID in a window, or nil if no view in the
-// window has that ViewID.
-NSView* GetView(NSWindow* window, ViewID viewID);
-
-} // namespace view_id_util
-
-
-@interface NSView (ViewID)
-
-// Returns the ViewID associated to the receiver. The default implementation
-// looks up the view's ViewID in the internal view to ViewID map. A subclass may
-// override this method to return its fixed ViewID.
-- (ViewID)viewID;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_VIEW_ID_UTIL_H_
diff --git a/chrome/browser/cocoa/view_id_util.mm b/chrome/browser/cocoa/view_id_util.mm
deleted file mode 100644
index cf61e9c..0000000
--- a/chrome/browser/cocoa/view_id_util.mm
+++ /dev/null
@@ -1,87 +0,0 @@
-// 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 "chrome/browser/cocoa/view_id_util.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include <map>
-#include <utility>
-
-#include "base/logging.h"
-#include "base/singleton.h"
-#import "chrome/browser/cocoa/browser_window_controller.h"
-#import "chrome/browser/cocoa/tab_strip_controller.h"
-
-namespace {
-
-// TODO(suzhe): After migrating to Mac OS X 10.6, we may use Objective-C's new
-// "Associative References" feature to attach the ViewID to the view directly
-// rather than using a separated map.
-typedef std::map<NSView*, ViewID> ViewIDMap;
-
-// Returns the view's nearest descendant (including itself) with a specific
-// ViewID, or nil if no subview has that ViewID.
-NSView* FindViewWithID(NSView* view, ViewID viewID) {
- if ([view viewID] == viewID)
- return view;
-
- for (NSView* subview in [view subviews]) {
- NSView* result = FindViewWithID(subview, viewID);
- if (result != nil)
- return result;
- }
- return nil;
-}
-
-} // anonymous namespace
-
-namespace view_id_util {
-
-void SetID(NSView* view, ViewID viewID) {
- DCHECK(view);
- DCHECK(viewID != VIEW_ID_NONE);
- // We handle VIEW_ID_TAB_0 to VIEW_ID_TAB_LAST in GetView() function directly.
- DCHECK(!((viewID >= VIEW_ID_TAB_0) && (viewID <= VIEW_ID_TAB_LAST)));
- (*Singleton<ViewIDMap>::get())[view] = viewID;
-}
-
-void UnsetID(NSView* view) {
- DCHECK(view);
- Singleton<ViewIDMap>::get()->erase(view);
-}
-
-NSView* GetView(NSWindow* window, ViewID viewID) {
- DCHECK(viewID != VIEW_ID_NONE);
- DCHECK(window);
-
- // As tabs can be created, destroyed or rearranged dynamically, we handle them
- // here specially.
- if (viewID >= VIEW_ID_TAB_0 && viewID <= VIEW_ID_TAB_LAST) {
- BrowserWindowController* windowController = [window windowController];
- DCHECK([windowController isKindOfClass:[BrowserWindowController class]]);
- TabStripController* tabStripController =
- [windowController tabStripController];
- DCHECK(tabStripController);
- NSUInteger count = [tabStripController viewsCount];
- DCHECK(count);
- NSUInteger index =
- (viewID == VIEW_ID_TAB_LAST ? count - 1 : viewID - VIEW_ID_TAB_0);
- return index < count ? [tabStripController viewAtIndex:index] : nil;
- }
-
- return FindViewWithID([[window contentView] superview], viewID);
-}
-
-} // namespace view_id_util
-
-@implementation NSView (ViewID)
-
-- (ViewID)viewID {
- ViewIDMap* map = Singleton<ViewIDMap>::get();
- ViewIDMap::const_iterator iter = map->find(self);
- return iter != map->end() ? iter->second : VIEW_ID_NONE;
-}
-
-@end
diff --git a/chrome/browser/cocoa/view_id_util_browsertest.mm b/chrome/browser/cocoa/view_id_util_browsertest.mm
deleted file mode 100644
index 1742b26..0000000
--- a/chrome/browser/cocoa/view_id_util_browsertest.mm
+++ /dev/null
@@ -1,118 +0,0 @@
-// 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.
-
-#include "base/basictypes.h"
-#include "base/command_line.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#include "chrome/browser/cocoa/view_id_util.h"
-#include "chrome/browser/download/download_shelf.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/sidebar/sidebar_manager.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/url_constants.h"
-#include "chrome/test/in_process_browser_test.h"
-#include "chrome/test/ui_test_utils.h"
-
-// Basic sanity check of ViewID use on the mac.
-class ViewIDTest : public InProcessBrowserTest {
- public:
- ViewIDTest() : root_window_(nil) {
- CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kEnableExperimentalExtensionApis);
- }
-
- void CheckViewID(ViewID view_id, bool should_have) {
- if (!root_window_)
- root_window_ = browser()->window()->GetNativeHandle();
-
- ASSERT_TRUE(root_window_);
- NSView* view = view_id_util::GetView(root_window_, view_id);
- EXPECT_EQ(should_have, !!view) << " Failed id=" << view_id;
- }
-
- void DoTest() {
- // Make sure FindBar is created to test
- // VIEW_ID_FIND_IN_PAGE_TEXT_FIELD and VIEW_ID_FIND_IN_PAGE.
- browser()->ShowFindBar();
-
- // Make sure sidebar is created to test VIEW_ID_SIDE_BAR_CONTAINER.
- const char sidebar_content_id[] = "test_content_id";
- SidebarManager::GetInstance()->ShowSidebar(
- browser()->GetSelectedTabContents(), sidebar_content_id);
- SidebarManager::GetInstance()->ExpandSidebar(
- browser()->GetSelectedTabContents(), sidebar_content_id);
-
- // Make sure docked devtools is created to test VIEW_ID_DEV_TOOLS_DOCKED
- browser()->profile()->GetPrefs()->SetBoolean(prefs::kDevToolsOpenDocked,
- true);
- browser()->ToggleDevToolsWindow(DEVTOOLS_TOGGLE_ACTION_INSPECT);
-
- // Make sure download shelf is created to test VIEW_ID_DOWNLOAD_SHELF
- browser()->window()->GetDownloadShelf()->Show();
-
- // Create a bookmark to test VIEW_ID_BOOKMARK_BAR_ELEMENT
- BookmarkModel* bookmark_model = browser()->profile()->GetBookmarkModel();
- if (bookmark_model) {
- if (!bookmark_model->IsLoaded())
- ui_test_utils::WaitForBookmarkModelToLoad(bookmark_model);
-
- bookmark_model->SetURLStarred(GURL(chrome::kAboutBlankURL),
- UTF8ToUTF16("about"), true);
- }
-
- for (int i = VIEW_ID_TOOLBAR; i < VIEW_ID_PREDEFINED_COUNT; ++i) {
- // Mac implementation does not support following ids yet.
- if (i == VIEW_ID_STAR_BUTTON ||
- i == VIEW_ID_AUTOCOMPLETE ||
- i == VIEW_ID_CONTENTS_SPLIT ||
- i == VIEW_ID_SIDE_BAR_SPLIT ||
- i == VIEW_ID_FEEDBACK_BUTTON) {
- continue;
- }
-
- CheckViewID(static_cast<ViewID>(i), true);
- }
-
- CheckViewID(VIEW_ID_TAB, true);
- CheckViewID(VIEW_ID_TAB_STRIP, true);
- CheckViewID(VIEW_ID_PREDEFINED_COUNT, false);
- }
-
- private:
- NSWindow* root_window_;
-};
-
-IN_PROC_BROWSER_TEST_F(ViewIDTest, Basic) {
- ASSERT_NO_FATAL_FAILURE(DoTest());
-}
-
-IN_PROC_BROWSER_TEST_F(ViewIDTest, Fullscreen) {
- browser()->window()->SetFullscreen(true);
- ASSERT_NO_FATAL_FAILURE(DoTest());
-}
-
-IN_PROC_BROWSER_TEST_F(ViewIDTest, Tab) {
- CheckViewID(VIEW_ID_TAB_0, true);
- CheckViewID(VIEW_ID_TAB_LAST, true);
-
- // Open 9 new tabs.
- for (int i = 1; i <= 9; ++i) {
- CheckViewID(static_cast<ViewID>(VIEW_ID_TAB_0 + i), false);
- browser()->OpenURL(GURL(chrome::kAboutBlankURL), GURL(),
- NEW_BACKGROUND_TAB, PageTransition::TYPED);
- CheckViewID(static_cast<ViewID>(VIEW_ID_TAB_0 + i), true);
- // VIEW_ID_TAB_LAST should always be available.
- CheckViewID(VIEW_ID_TAB_LAST, true);
- }
-
- // Open the 11th tab.
- browser()->OpenURL(GURL(chrome::kAboutBlankURL), GURL(),
- NEW_BACKGROUND_TAB, PageTransition::TYPED);
- CheckViewID(VIEW_ID_TAB_LAST, true);
-}
diff --git a/chrome/browser/cocoa/view_resizer.h b/chrome/browser/cocoa/view_resizer.h
deleted file mode 100644
index 645e9dd..0000000
--- a/chrome/browser/cocoa/view_resizer.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_VIEW_RESIZER_H_
-#define CHROME_BROWSER_COCOA_VIEW_RESIZER_H_
-#pragma once
-
-#include "chrome/browser/tabs/tab_strip_model.h"
-
-#import <Cocoa/Cocoa.h>
-
-// Defines a protocol that allows controllers to delegate resizing their views
-// to their parents. When a controller needs to change a view's height, rather
-// than resizing it directly, it sends a message to its parent asking the parent
-// to perform the resize. This allows the parent to do any re-layout that may
-// become necessary due to the resize.
-@protocol ViewResizer <NSObject>
-- (void)resizeView:(NSView*)view newHeight:(CGFloat)height;
-
-@optional
-// Optional method called when an animation is beginning or ending. Resize
-// delegates can implement this method if they need to modify their behavior
-// while an animation is running.
-- (void)setAnimationInProgress:(BOOL)inProgress;
-@end
-
-#endif // CHROME_BROWSER_COCOA_VIEW_RESIZER_H_
diff --git a/chrome/browser/cocoa/view_resizer_pong.h b/chrome/browser/cocoa/view_resizer_pong.h
deleted file mode 100644
index de7193b..0000000
--- a/chrome/browser/cocoa/view_resizer_pong.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_VIEW_RESIZER_PONG_H_
-#define CHROME_BROWSER_COCOA_VIEW_RESIZER_PONG_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#import "chrome/browser/cocoa/view_resizer.h"
-
-@interface ViewResizerPong : NSObject<ViewResizer> {
- @private
- CGFloat height_;
-}
-@property (nonatomic) CGFloat height;
-
-- (void)resizeView:(NSView*)view newHeight:(CGFloat)height;
-@end
-
-#endif // CHROME_BROWSER_COCOA_VIEW_RESIZER_PONG_H_
diff --git a/chrome/browser/cocoa/view_resizer_pong.mm b/chrome/browser/cocoa/view_resizer_pong.mm
deleted file mode 100644
index c5263a8..0000000
--- a/chrome/browser/cocoa/view_resizer_pong.mm
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2009 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>
-
-#import "chrome/browser/cocoa/view_resizer_pong.h"
-
-@implementation ViewResizerPong
-
-@synthesize height = height_;
-
-- (void)resizeView:(NSView*)view newHeight:(CGFloat)height {
- [self setHeight:height];
-
- // Set the view's height and width, in case it uses that as important state.
- [view setFrame:NSMakeRect(100, 50,
- NSWidth([[view superview] frame]) - 50, height)];
-}
-@end
diff --git a/chrome/browser/cocoa/web_contents_drag_source.h b/chrome/browser/cocoa/web_contents_drag_source.h
deleted file mode 100644
index 1b8baaa..0000000
--- a/chrome/browser/cocoa/web_contents_drag_source.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_WEB_CONTENTS_DRAG_SOURCE_H_
-#define CHROME_BROWSER_COCOA_WEB_CONTENTS_DRAG_SOURCE_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/scoped_nsobject.h"
-#include "chrome/browser/bookmarks/bookmark_node_data.h"
-
-@class TabContentsViewCocoa;
-
-// A class that handles tracking and event processing for a drag and drop
-// originating from the content area. Subclasses should implement
-// fillClipboard and dragImage.
-@interface WebContentsDragSource : NSObject {
- @private
- // Our tab. Weak reference (owns or co-owns us).
- TabContentsViewCocoa* contentsView_;
-
- // Our pasteboard.
- scoped_nsobject<NSPasteboard> pasteboard_;
-
- // A mask of the allowed drag operations.
- NSDragOperation dragOperationMask_;
-}
-
-// Initialize a DragDataSource object for a drag (originating on the given
-// contentsView and with the given dropData and pboard). Fill the pasteboard
-// with data types appropriate for dropData.
-- (id)initWithContentsView:(TabContentsViewCocoa*)contentsView
- pasteboard:(NSPasteboard*)pboard
- dragOperationMask:(NSDragOperation)dragOperationMask;
-
-// Creates the drag image. Implemented by the subclass.
-- (NSImage*)dragImage;
-
-// Put the data being dragged onto the pasteboard. Implemented by the
-// subclass.
-- (void)fillPasteboard;
-
-// Returns a mask of the allowed drag operations.
-- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal;
-
-// Start the drag (on the originally provided contentsView); can do this right
-// after -initWithContentsView:....
-- (void)startDrag;
-
-// End the drag and clear the pasteboard; hook up to
-// -draggedImage:endedAt:operation:.
-- (void)endDragAt:(NSPoint)screenPoint
- operation:(NSDragOperation)operation;
-
-// Drag moved; hook up to -draggedImage:movedTo:.
-- (void)moveDragTo:(NSPoint)screenPoint;
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_WEB_CONTENTS_DRAG_SOURCE_H_
diff --git a/chrome/browser/cocoa/web_contents_drag_source.mm b/chrome/browser/cocoa/web_contents_drag_source.mm
deleted file mode 100644
index 8d74a88..0000000
--- a/chrome/browser/cocoa/web_contents_drag_source.mm
+++ /dev/null
@@ -1,130 +0,0 @@
-// 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 "chrome/browser/cocoa/web_contents_drag_source.h"
-
-#include "base/nsimage_cache_mac.h"
-#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents/tab_contents_view_mac.h"
-
-namespace {
-
-// Make a drag image from the drop data.
-// TODO(feldstein): Make this work
-NSImage* MakeDragImage() {
- // TODO(feldstein): Just a stub for now. Make it do something (see, e.g.,
- // WebKit/WebKit/mac/Misc/WebNSViewExtras.m: |-_web_DragImageForElement:...|).
-
- // Default to returning a generic image.
- return nsimage_cache::ImageNamed(@"nav.pdf");
-}
-
-// Flips screen and point coordinates over the y axis to work with webkit
-// coordinate systems.
-void FlipPointCoordinates(NSPoint& screenPoint,
- NSPoint& localPoint,
- NSView* view) {
- NSRect viewFrame = [view frame];
- localPoint.y = NSHeight(viewFrame) - localPoint.y;
- // Flip |screenPoint|.
- NSRect screenFrame = [[[view window] screen] frame];
- screenPoint.y = NSHeight(screenFrame) - screenPoint.y;
-}
-
-} // namespace
-
-
-@implementation WebContentsDragSource
-
-- (id)initWithContentsView:(TabContentsViewCocoa*)contentsView
- pasteboard:(NSPasteboard*)pboard
- dragOperationMask:(NSDragOperation)dragOperationMask {
- if ((self = [super init])) {
- contentsView_ = contentsView;
- DCHECK(contentsView_);
-
- pasteboard_.reset([pboard retain]);
- DCHECK(pasteboard_.get());
-
- dragOperationMask_ = dragOperationMask;
- }
-
- return self;
-}
-
-- (NSImage*)dragImage {
- return MakeDragImage();
-}
-
-- (void)fillPasteboard {
- NOTIMPLEMENTED() << "Subclasses should implement fillPasteboard";
-}
-
-- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal {
- return dragOperationMask_;
-}
-
-- (void)startDrag {
- [self fillPasteboard];
- NSEvent* currentEvent = [NSApp currentEvent];
-
- // Synthesize an event for dragging, since we can't be sure that
- // [NSApp currentEvent] will return a valid dragging event.
- NSWindow* window = [contentsView_ window];
- NSPoint position = [window mouseLocationOutsideOfEventStream];
- NSTimeInterval eventTime = [currentEvent timestamp];
- NSEvent* dragEvent = [NSEvent mouseEventWithType:NSLeftMouseDragged
- location:position
- modifierFlags:NSLeftMouseDraggedMask
- timestamp:eventTime
- windowNumber:[window windowNumber]
- context:nil
- eventNumber:0
- clickCount:1
- pressure:1.0];
- [window dragImage:[self dragImage]
- at:position
- offset:NSZeroSize
- event:dragEvent
- pasteboard:pasteboard_
- source:self
- slideBack:YES];
-}
-
-- (void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint
- operation:(NSDragOperation)operation {
-}
-
-- (void)endDragAt:(NSPoint)screenPoint
- operation:(NSDragOperation)operation {
- RenderViewHost* rvh = [contentsView_ tabContents]->render_view_host();
- if (rvh) {
- rvh->DragSourceSystemDragEnded();
-
- NSPoint localPoint = [contentsView_ convertPoint:screenPoint fromView: nil];
- FlipPointCoordinates(screenPoint, localPoint, contentsView_);
- rvh->DragSourceEndedAt(localPoint.x, localPoint.y,
- screenPoint.x, screenPoint.y,
- static_cast<WebKit::WebDragOperation>(operation));
- }
-
- // Make sure the pasteboard owner isn't us.
- [pasteboard_ declareTypes:[NSArray array] owner:nil];
-}
-
-- (void)moveDragTo:(NSPoint)screenPoint {
- RenderViewHost* rvh = [contentsView_ tabContents]->render_view_host();
- if (rvh) {
- NSPoint localPoint = [contentsView_ convertPoint:screenPoint fromView:nil];
- FlipPointCoordinates(screenPoint, localPoint, contentsView_);
- rvh->DragSourceMovedTo(localPoint.x, localPoint.y,
- screenPoint.x, screenPoint.y);
- }
-}
-
-@end // @implementation WebContentsDragSource
-
diff --git a/chrome/browser/cocoa/web_drag_source.mm b/chrome/browser/cocoa/web_drag_source.mm
deleted file mode 100644
index 95ab0d1..0000000
--- a/chrome/browser/cocoa/web_drag_source.mm
+++ /dev/null
@@ -1,412 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/cocoa/web_drag_source.h"
-
-#include "base/file_path.h"
-#include "base/nsimage_cache_mac.h"
-#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
-#include "base/task.h"
-#include "base/thread.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/download/download_manager.h"
-#include "chrome/browser/download/download_util.h"
-#include "chrome/browser/download/drag_download_file.h"
-#include "chrome/browser/download/drag_download_util.h"
-#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents/tab_contents_view_mac.h"
-#include "net/base/file_stream.h"
-#include "net/base/net_util.h"
-#import "third_party/mozilla/NSPasteboard+Utils.h"
-#include "webkit/glue/webdropdata.h"
-
-using base::SysNSStringToUTF8;
-using base::SysUTF8ToNSString;
-using base::SysUTF16ToNSString;
-using net::FileStream;
-
-
-namespace {
-
-// An unofficial standard pasteboard title type to be provided alongside the
-// |NSURLPboardType|.
-NSString* const kNSURLTitlePboardType = @"public.url-name";
-
-// Returns a filename appropriate for the drop data
-// TODO(viettrungluu): Refactor to make it common across platforms,
-// and move it somewhere sensible.
-FilePath GetFileNameFromDragData(const WebDropData& drop_data) {
- // Images without ALT text will only have a file extension so we need to
- // synthesize one from the provided extension and URL.
- FilePath file_name([SysUTF16ToNSString(drop_data.file_description_filename)
- fileSystemRepresentation]);
- file_name = file_name.BaseName().RemoveExtension();
-
- if (file_name.empty()) {
- // Retrieve the name from the URL.
- file_name = net::GetSuggestedFilename(drop_data.url, "", "", FilePath());
- }
-
- file_name = file_name.ReplaceExtension([SysUTF16ToNSString(
- drop_data.file_extension) fileSystemRepresentation]);
-
- return file_name;
-}
-
-// This class's sole task is to write out data for a promised file; the caller
-// is responsible for opening the file.
-class PromiseWriterTask : public Task {
- public:
- // Assumes ownership of file_stream.
- PromiseWriterTask(const WebDropData& drop_data,
- FileStream* file_stream);
- virtual ~PromiseWriterTask();
- virtual void Run();
-
- private:
- WebDropData drop_data_;
-
- // This class takes ownership of file_stream_ and will close and delete it.
- scoped_ptr<FileStream> file_stream_;
-};
-
-// Takes the drop data and an open file stream (which it takes ownership of and
-// will close and delete).
-PromiseWriterTask::PromiseWriterTask(const WebDropData& drop_data,
- FileStream* file_stream) :
- drop_data_(drop_data) {
- file_stream_.reset(file_stream);
- DCHECK(file_stream_.get());
-}
-
-PromiseWriterTask::~PromiseWriterTask() {
- DCHECK(file_stream_.get());
- if (file_stream_.get())
- file_stream_->Close();
-}
-
-void PromiseWriterTask::Run() {
- CHECK(file_stream_.get());
- file_stream_->Write(drop_data_.file_contents.data(),
- drop_data_.file_contents.length(),
- NULL);
-
- // Let our destructor take care of business.
-}
-
-} // namespace
-
-
-@interface WebDragSource(Private)
-
-- (void)fillPasteboard;
-- (NSImage*)dragImage;
-
-@end // @interface WebDragSource(Private)
-
-
-@implementation WebDragSource
-
-- (id)initWithContentsView:(TabContentsViewCocoa*)contentsView
- dropData:(const WebDropData*)dropData
- image:(NSImage*)image
- offset:(NSPoint)offset
- pasteboard:(NSPasteboard*)pboard
- dragOperationMask:(NSDragOperation)dragOperationMask {
- if ((self = [super init])) {
- contentsView_ = contentsView;
- DCHECK(contentsView_);
-
- dropData_.reset(new WebDropData(*dropData));
- DCHECK(dropData_.get());
-
- dragImage_.reset([image retain]);
- imageOffset_ = offset;
-
- pasteboard_.reset([pboard retain]);
- DCHECK(pasteboard_.get());
-
- dragOperationMask_ = dragOperationMask;
-
- [self fillPasteboard];
- }
-
- return self;
-}
-
-- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal {
- return dragOperationMask_;
-}
-
-- (void)lazyWriteToPasteboard:(NSPasteboard*)pboard forType:(NSString*)type {
- // NSHTMLPboardType requires the character set to be declared. Otherwise, it
- // assumes US-ASCII. Awesome.
- static const string16 kHtmlHeader =
- ASCIIToUTF16("<meta http-equiv=\"Content-Type\" "
- "content=\"text/html;charset=UTF-8\">");
-
- // Be extra paranoid; avoid crashing.
- if (!dropData_.get()) {
- NOTREACHED() << "No drag-and-drop data available for lazy write.";
- return;
- }
-
- // HTML.
- if ([type isEqualToString:NSHTMLPboardType]) {
- DCHECK(!dropData_->text_html.empty());
- // See comment on |kHtmlHeader| above.
- [pboard setString:SysUTF16ToNSString(kHtmlHeader + dropData_->text_html)
- forType:NSHTMLPboardType];
-
- // URL.
- } else if ([type isEqualToString:NSURLPboardType]) {
- DCHECK(dropData_->url.is_valid());
- NSURL* url = [NSURL URLWithString:SysUTF8ToNSString(dropData_->url.spec())];
- [url writeToPasteboard:pboard];
-
- // URL title.
- } else if ([type isEqualToString:kNSURLTitlePboardType]) {
- [pboard setString:SysUTF16ToNSString(dropData_->url_title)
- forType:kNSURLTitlePboardType];
-
- // File contents.
- } else if ([type isEqualToString:NSFileContentsPboardType] ||
- [type isEqualToString:NSCreateFileContentsPboardType(
- SysUTF16ToNSString(dropData_->file_extension))]) {
- // TODO(viettrungluu: find something which is known to accept
- // NSFileContentsPboardType to check that this actually works!
- scoped_nsobject<NSFileWrapper> file_wrapper(
- [[NSFileWrapper alloc] initRegularFileWithContents:[NSData
- dataWithBytes:dropData_->file_contents.data()
- length:dropData_->file_contents.length()]]);
- [file_wrapper setPreferredFilename:SysUTF8ToNSString(
- GetFileNameFromDragData(*dropData_).value())];
- [pboard writeFileWrapper:file_wrapper];
-
- // TIFF.
- } else if ([type isEqualToString:NSTIFFPboardType]) {
- // TODO(viettrungluu): This is a bit odd since we rely on Cocoa to render
- // our image into a TIFF. This is also suboptimal since this is all done
- // synchronously. I'm not sure there's much we can easily do about it.
- scoped_nsobject<NSImage> image(
- [[NSImage alloc] initWithData:[NSData
- dataWithBytes:dropData_->file_contents.data()
- length:dropData_->file_contents.length()]]);
- [pboard setData:[image TIFFRepresentation] forType:NSTIFFPboardType];
-
- // Plain text.
- } else if ([type isEqualToString:NSStringPboardType]) {
- DCHECK(!dropData_->plain_text.empty());
- [pboard setString:SysUTF16ToNSString(dropData_->plain_text)
- forType:NSStringPboardType];
-
- // Oops!
- } else {
- NOTREACHED() << "Asked for a drag pasteboard type we didn't offer.";
- }
-}
-
-- (NSPoint)convertScreenPoint:(NSPoint)screenPoint {
- DCHECK([contentsView_ window]);
- NSPoint basePoint = [[contentsView_ window] convertScreenToBase:screenPoint];
- return [contentsView_ convertPoint:basePoint fromView:nil];
-}
-
-- (void)startDrag {
- NSEvent* currentEvent = [NSApp currentEvent];
-
- // Synthesize an event for dragging, since we can't be sure that
- // [NSApp currentEvent] will return a valid dragging event.
- NSWindow* window = [contentsView_ window];
- NSPoint position = [window mouseLocationOutsideOfEventStream];
- NSTimeInterval eventTime = [currentEvent timestamp];
- NSEvent* dragEvent = [NSEvent mouseEventWithType:NSLeftMouseDragged
- location:position
- modifierFlags:NSLeftMouseDraggedMask
- timestamp:eventTime
- windowNumber:[window windowNumber]
- context:nil
- eventNumber:0
- clickCount:1
- pressure:1.0];
-
- if (dragImage_) {
- position.x -= imageOffset_.x;
- // Deal with Cocoa's flipped coordinate system.
- position.y -= [dragImage_.get() size].height - imageOffset_.y;
- }
- // Per kwebster, offset arg is ignored, see -_web_DragImageForElement: in
- // third_party/WebKit/WebKit/mac/Misc/WebNSViewExtras.m.
- [window dragImage:[self dragImage]
- at:position
- offset:NSZeroSize
- event:dragEvent
- pasteboard:pasteboard_
- source:contentsView_
- slideBack:YES];
-}
-
-- (void)endDragAt:(NSPoint)screenPoint
- operation:(NSDragOperation)operation {
- RenderViewHost* rvh = [contentsView_ tabContents]->render_view_host();
- if (rvh) {
- rvh->DragSourceSystemDragEnded();
-
- // Convert |screenPoint| to view coordinates and flip it.
- NSPoint localPoint = [self convertScreenPoint:screenPoint];
- NSRect viewFrame = [contentsView_ frame];
- localPoint.y = viewFrame.size.height - localPoint.y;
- // Flip |screenPoint|.
- NSRect screenFrame = [[[contentsView_ window] screen] frame];
- screenPoint.y = screenFrame.size.height - screenPoint.y;
-
- rvh->DragSourceEndedAt(localPoint.x, localPoint.y,
- screenPoint.x, screenPoint.y,
- static_cast<WebKit::WebDragOperation>(operation));
- }
-
- // Make sure the pasteboard owner isn't us.
- [pasteboard_ declareTypes:[NSArray array] owner:nil];
-}
-
-- (void)moveDragTo:(NSPoint)screenPoint {
- RenderViewHost* rvh = [contentsView_ tabContents]->render_view_host();
- if (rvh) {
- // Convert |screenPoint| to view coordinates and flip it.
- NSPoint localPoint = [self convertScreenPoint:screenPoint];
- NSRect viewFrame = [contentsView_ frame];
- localPoint.y = viewFrame.size.height - localPoint.y;
- // Flip |screenPoint|.
- NSRect screenFrame = [[[contentsView_ window] screen] frame];
- screenPoint.y = screenFrame.size.height - screenPoint.y;
-
- rvh->DragSourceMovedTo(localPoint.x, localPoint.y,
- screenPoint.x, screenPoint.y);
- }
-}
-
-- (NSString*)dragPromisedFileTo:(NSString*)path {
- // Be extra paranoid; avoid crashing.
- if (!dropData_.get()) {
- NOTREACHED() << "No drag-and-drop data available for promised file.";
- return nil;
- }
-
- FilePath fileName = downloadFileName_.empty() ?
- GetFileNameFromDragData(*dropData_) : downloadFileName_;
- FilePath filePath(SysNSStringToUTF8(path));
- filePath = filePath.Append(fileName);
- FileStream* fileStream =
- drag_download_util::CreateFileStreamForDrop(&filePath);
- if (!fileStream)
- return nil;
-
- if (downloadURL_.is_valid()) {
- TabContents* tabContents = [contentsView_ tabContents];
- scoped_refptr<DragDownloadFile> dragFileDownloader(new DragDownloadFile(
- filePath,
- linked_ptr<net::FileStream>(fileStream),
- downloadURL_,
- tabContents->GetURL(),
- tabContents->encoding(),
- tabContents));
-
- // The finalizer will take care of closing and deletion.
- dragFileDownloader->Start(
- new drag_download_util::PromiseFileFinalizer(dragFileDownloader));
- } else {
- // The writer will take care of closing and deletion.
- g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE,
- new PromiseWriterTask(*dropData_, fileStream));
- }
-
- // Once we've created the file, we should return the file name.
- return SysUTF8ToNSString(filePath.BaseName().value());
-}
-
-@end // @implementation WebDragSource
-
-
-@implementation WebDragSource (Private)
-
-- (void)fillPasteboard {
- DCHECK(pasteboard_.get());
-
- [pasteboard_ declareTypes:[NSArray array] owner:contentsView_];
-
- // HTML.
- if (!dropData_->text_html.empty())
- [pasteboard_ addTypes:[NSArray arrayWithObject:NSHTMLPboardType]
- owner:contentsView_];
-
- // URL (and title).
- if (dropData_->url.is_valid())
- [pasteboard_ addTypes:[NSArray arrayWithObjects:NSURLPboardType,
- kNSURLTitlePboardType, nil]
- owner:contentsView_];
-
- // File.
- if (!dropData_->file_contents.empty() ||
- !dropData_->download_metadata.empty()) {
- NSString* fileExtension = 0;
-
- if (dropData_->download_metadata.empty()) {
- // |dropData_->file_extension| comes with the '.', which we must strip.
- fileExtension = (dropData_->file_extension.length() > 0) ?
- SysUTF16ToNSString(dropData_->file_extension.substr(1)) : @"";
- } else {
- string16 mimeType;
- FilePath fileName;
- if (drag_download_util::ParseDownloadMetadata(
- dropData_->download_metadata,
- &mimeType,
- &fileName,
- &downloadURL_)) {
- std::string contentDisposition =
- "attachment; filename=" + fileName.value();
- download_util::GenerateFileName(downloadURL_,
- contentDisposition,
- std::string(),
- UTF16ToUTF8(mimeType),
- &downloadFileName_);
- fileExtension = SysUTF8ToNSString(downloadFileName_.Extension());
- }
- }
-
- if (fileExtension) {
- // File contents (with and without specific type), file (HFS) promise,
- // TIFF.
- // TODO(viettrungluu): others?
- [pasteboard_ addTypes:[NSArray arrayWithObjects:
- NSFileContentsPboardType,
- NSCreateFileContentsPboardType(fileExtension),
- NSFilesPromisePboardType,
- NSTIFFPboardType,
- nil]
- owner:contentsView_];
-
- // For the file promise, we need to specify the extension.
- [pasteboard_ setPropertyList:[NSArray arrayWithObject:fileExtension]
- forType:NSFilesPromisePboardType];
- }
- }
-
- // Plain text.
- if (!dropData_->plain_text.empty())
- [pasteboard_ addTypes:[NSArray arrayWithObject:NSStringPboardType]
- owner:contentsView_];
-}
-
-- (NSImage*)dragImage {
- if (dragImage_)
- return dragImage_;
-
- // Default to returning a generic image.
- return nsimage_cache::ImageNamed(@"nav.pdf");
-}
-
-@end // @implementation WebDragSource (Private)
diff --git a/chrome/browser/cocoa/web_drop_target.mm b/chrome/browser/cocoa/web_drop_target.mm
deleted file mode 100644
index fdc8bcc..0000000
--- a/chrome/browser/cocoa/web_drop_target.mm
+++ /dev/null
@@ -1,283 +0,0 @@
-// 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 "chrome/browser/cocoa/web_drop_target.h"
-
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/bookmarks/bookmark_node_data.h"
-#include "chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.h"
-#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#import "third_party/mozilla/NSPasteboard+Utils.h"
-#include "webkit/glue/webdropdata.h"
-#include "webkit/glue/window_open_disposition.h"
-
-using WebKit::WebDragOperationsMask;
-
-@implementation WebDropTarget
-
-// |contents| is the TabContents representing this tab, used to communicate
-// drag&drop messages to WebCore and handle navigation on a successful drop
-// (if necessary).
-- (id)initWithTabContents:(TabContents*)contents {
- if ((self = [super init])) {
- tabContents_ = contents;
- }
- return self;
-}
-
-// Call to set whether or not we should allow the drop. Takes effect the
-// next time |-draggingUpdated:| is called.
-- (void)setCurrentOperation: (NSDragOperation)operation {
- current_operation_ = operation;
-}
-
-// Given a point in window coordinates and a view in that window, return a
-// flipped point in the coordinate system of |view|.
-- (NSPoint)flipWindowPointToView:(const NSPoint&)windowPoint
- view:(NSView*)view {
- DCHECK(view);
- NSPoint viewPoint = [view convertPoint:windowPoint fromView:nil];
- NSRect viewFrame = [view frame];
- viewPoint.y = viewFrame.size.height - viewPoint.y;
- return viewPoint;
-}
-
-// Given a point in window coordinates and a view in that window, return a
-// flipped point in screen coordinates.
-- (NSPoint)flipWindowPointToScreen:(const NSPoint&)windowPoint
- view:(NSView*)view {
- DCHECK(view);
- NSPoint screenPoint = [[view window] convertBaseToScreen:windowPoint];
- NSScreen* screen = [[view window] screen];
- NSRect screenFrame = [screen frame];
- screenPoint.y = screenFrame.size.height - screenPoint.y;
- return screenPoint;
-}
-
-// Return YES if the drop site only allows drops that would navigate. If this
-// is the case, we don't want to pass messages to the renderer because there's
-// really no point (i.e., there's nothing that cares about the mouse position or
-// entering and exiting). One example is an interstitial page (e.g., safe
-// browsing warning).
-- (BOOL)onlyAllowsNavigation {
- return tabContents_->showing_interstitial_page();
-}
-
-// Messages to send during the tracking of a drag, ususally upon recieving
-// calls from the view system. Communicates the drag messages to WebCore.
-
-- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info
- view:(NSView*)view {
- // Save off the RVH so we can tell if it changes during a drag. If it does,
- // we need to send a new enter message in draggingUpdated:.
- currentRVH_ = tabContents_->render_view_host();
-
- if ([self onlyAllowsNavigation]) {
- if ([[info draggingPasteboard] containsURLData])
- return NSDragOperationCopy;
- return NSDragOperationNone;
- }
-
- // If the tab is showing the boomark manager, send BookmarkDrag events
- RenderViewHostDelegate::BookmarkDrag* dragDelegate =
- tabContents_->GetBookmarkDragDelegate();
- BookmarkNodeData dragData;
- if(dragDelegate && dragData.ReadFromDragClipboard())
- dragDelegate->OnDragEnter(dragData);
-
- // Fill out a WebDropData from pasteboard.
- WebDropData data;
- [self populateWebDropData:&data fromPasteboard:[info draggingPasteboard]];
-
- // Create the appropriate mouse locations for WebCore. The draggingLocation
- // is in window coordinates. Both need to be flipped.
- NSPoint windowPoint = [info draggingLocation];
- NSPoint viewPoint = [self flipWindowPointToView:windowPoint view:view];
- NSPoint screenPoint = [self flipWindowPointToScreen:windowPoint view:view];
- NSDragOperation mask = [info draggingSourceOperationMask];
- tabContents_->render_view_host()->DragTargetDragEnter(data,
- gfx::Point(viewPoint.x, viewPoint.y),
- gfx::Point(screenPoint.x, screenPoint.y),
- static_cast<WebDragOperationsMask>(mask));
-
- // We won't know the true operation (whether the drag is allowed) until we
- // hear back from the renderer. For now, be optimistic:
- current_operation_ = NSDragOperationCopy;
- return current_operation_;
-}
-
-- (void)draggingExited:(id<NSDraggingInfo>)info {
- DCHECK(currentRVH_);
- if (currentRVH_ != tabContents_->render_view_host())
- return;
-
- // Nothing to do in the interstitial case.
-
- tabContents_->render_view_host()->DragTargetDragLeave();
-}
-
-- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)info
- view:(NSView*)view {
- DCHECK(currentRVH_);
- if (currentRVH_ != tabContents_->render_view_host())
- [self draggingEntered:info view:view];
-
- if ([self onlyAllowsNavigation]) {
- if ([[info draggingPasteboard] containsURLData])
- return NSDragOperationCopy;
- return NSDragOperationNone;
- }
-
- // Create the appropriate mouse locations for WebCore. The draggingLocation
- // is in window coordinates.
- NSPoint windowPoint = [info draggingLocation];
- NSPoint viewPoint = [self flipWindowPointToView:windowPoint view:view];
- NSPoint screenPoint = [self flipWindowPointToScreen:windowPoint view:view];
- NSDragOperation mask = [info draggingSourceOperationMask];
- tabContents_->render_view_host()->DragTargetDragOver(
- gfx::Point(viewPoint.x, viewPoint.y),
- gfx::Point(screenPoint.x, screenPoint.y),
- static_cast<WebDragOperationsMask>(mask));
-
- // If the tab is showing the boomark manager, send BookmarkDrag events
- RenderViewHostDelegate::BookmarkDrag* dragDelegate =
- tabContents_->GetBookmarkDragDelegate();
- BookmarkNodeData dragData;
- if(dragDelegate && dragData.ReadFromDragClipboard())
- dragDelegate->OnDragOver(dragData);
- return current_operation_;
-}
-
-- (BOOL)performDragOperation:(id<NSDraggingInfo>)info
- view:(NSView*)view {
- if (currentRVH_ != tabContents_->render_view_host())
- [self draggingEntered:info view:view];
-
- // Check if we only allow navigation and navigate to a url on the pasteboard.
- if ([self onlyAllowsNavigation]) {
- NSPasteboard* pboard = [info draggingPasteboard];
- if ([pboard containsURLData]) {
- GURL url;
- [self populateURL:&url
- andTitle:NULL
- fromPasteboard:pboard
- convertingFilenames:YES];
- tabContents_->OpenURL(url, GURL(), CURRENT_TAB,
- PageTransition::AUTO_BOOKMARK);
- return YES;
- }
- return NO;
- }
-
- // If the tab is showing the boomark manager, send BookmarkDrag events
- RenderViewHostDelegate::BookmarkDrag* dragDelegate =
- tabContents_->GetBookmarkDragDelegate();
- BookmarkNodeData dragData;
- if(dragDelegate && dragData.ReadFromDragClipboard())
- dragDelegate->OnDrop(dragData);
-
- currentRVH_ = NULL;
-
- // Create the appropriate mouse locations for WebCore. The draggingLocation
- // is in window coordinates. Both need to be flipped.
- NSPoint windowPoint = [info draggingLocation];
- NSPoint viewPoint = [self flipWindowPointToView:windowPoint view:view];
- NSPoint screenPoint = [self flipWindowPointToScreen:windowPoint view:view];
- tabContents_->render_view_host()->DragTargetDrop(
- gfx::Point(viewPoint.x, viewPoint.y),
- gfx::Point(screenPoint.x, screenPoint.y));
-
- return YES;
-}
-
-// Populate the |url| and |title| with URL data in |pboard|. There may be more
-// than one, but we only handle dropping the first. |url| must not be |NULL|;
-// |title| is an optional parameter. Returns |YES| if URL data was obtained from
-// the pasteboard, |NO| otherwise. If |convertFilenames| is |YES|, the function
-// will also attempt to convert filenames in |pboard| to file URLs.
-- (BOOL)populateURL:(GURL*)url
- andTitle:(string16*)title
- fromPasteboard:(NSPasteboard*)pboard
- convertingFilenames:(BOOL)convertFilenames {
- DCHECK(url);
- DCHECK(title);
-
- // Bail out early if there's no URL data.
- if (![pboard containsURLData])
- return NO;
-
- // |-getURLs:andTitles:convertingFilenames:| will already validate URIs so we
- // don't need to again. The arrays returned are both of NSString's.
- NSArray* urls = nil;
- NSArray* titles = nil;
- [pboard getURLs:&urls andTitles:&titles convertingFilenames:convertFilenames];
- DCHECK_EQ([urls count], [titles count]);
- // It's possible that no URLs were actually provided!
- if (![urls count])
- return NO;
- NSString* urlString = [urls objectAtIndex:0];
- if ([urlString length]) {
- // Check again just to make sure to not assign NULL into a std::string,
- // which throws an exception.
- const char* utf8Url = [urlString UTF8String];
- if (utf8Url) {
- *url = GURL(utf8Url);
- // Extra paranoia check.
- if (title && [titles count])
- *title = base::SysNSStringToUTF16([titles objectAtIndex:0]);
- }
- }
- return YES;
-}
-
-// Given |data|, which should not be nil, fill it in using the contents of the
-// given pasteboard.
-- (void)populateWebDropData:(WebDropData*)data
- fromPasteboard:(NSPasteboard*)pboard {
- DCHECK(data);
- DCHECK(pboard);
- NSArray* types = [pboard types];
-
- // Get URL if possible. To avoid exposing file system paths to web content,
- // filenames in the drag are not converted to file URLs.
- [self populateURL:&data->url
- andTitle:&data->url_title
- fromPasteboard:pboard
- convertingFilenames:NO];
-
- // Get plain text.
- if ([types containsObject:NSStringPboardType]) {
- data->plain_text =
- base::SysNSStringToUTF16([pboard stringForType:NSStringPboardType]);
- }
-
- // Get HTML. If there's no HTML, try RTF.
- if ([types containsObject:NSHTMLPboardType]) {
- data->text_html =
- base::SysNSStringToUTF16([pboard stringForType:NSHTMLPboardType]);
- } else if ([types containsObject:NSRTFPboardType]) {
- NSString* html = [pboard htmlFromRtf];
- data->text_html = base::SysNSStringToUTF16(html);
- }
-
- // 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 isDir = NO;
- BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:filename
- isDirectory:&isDir];
- if (exists && !isDir)
- data->filenames.push_back(base::SysNSStringToUTF16(filename));
- }
- }
- }
-
- // TODO(pinkerton): Get file contents. http://crbug.com/34661
-}
-
-@end
diff --git a/chrome/browser/cocoa/web_drop_target_unittest.mm b/chrome/browser/cocoa/web_drop_target_unittest.mm
deleted file mode 100644
index 2bd7085..0000000
--- a/chrome/browser/cocoa/web_drop_target_unittest.mm
+++ /dev/null
@@ -1,166 +0,0 @@
-// 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.
-
-#include "base/mac/scoped_nsautorelease_pool.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/web_drop_target.h"
-#include "chrome/browser/renderer_host/test/test_render_view_host.h"
-#include "chrome/browser/tab_contents/test_tab_contents.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "third_party/mozilla/NSPasteboard+Utils.h"
-#include "webkit/glue/webdropdata.h"
-
-class WebDropTargetTest : public RenderViewHostTestHarness {
- public:
- virtual void SetUp() {
- RenderViewHostTestHarness::SetUp();
- CocoaTest::BootstrapCocoa();
- drop_target_.reset([[WebDropTarget alloc] initWithTabContents:contents()]);
- }
-
- void PutURLOnPasteboard(NSString* urlString, NSPasteboard* pboard) {
- [pboard declareTypes:[NSArray arrayWithObject:NSURLPboardType]
- owner:nil];
- NSURL* url = [NSURL URLWithString:urlString];
- EXPECT_TRUE(url);
- [url writeToPasteboard:pboard];
- }
-
- void PutCoreURLAndTitleOnPasteboard(NSString* urlString, NSString* title,
- NSPasteboard* pboard) {
- [pboard
- declareTypes:[NSArray arrayWithObjects:kCorePasteboardFlavorType_url,
- kCorePasteboardFlavorType_urln,
- nil]
- owner:nil];
- [pboard setString:urlString
- forType:kCorePasteboardFlavorType_url];
- [pboard setString:title
- forType:kCorePasteboardFlavorType_urln];
- }
-
- base::mac::ScopedNSAutoreleasePool pool_;
- scoped_nsobject<WebDropTarget> drop_target_;
-};
-
-// Make sure nothing leaks.
-TEST_F(WebDropTargetTest, Init) {
- EXPECT_TRUE(drop_target_);
-}
-
-// Test flipping of coordinates given a point in window coordinates.
-TEST_F(WebDropTargetTest, Flip) {
- NSPoint windowPoint = NSZeroPoint;
- scoped_nsobject<NSWindow> window([[CocoaTestHelperWindow alloc] init]);
- NSPoint viewPoint =
- [drop_target_ flipWindowPointToView:windowPoint
- view:[window contentView]];
- NSPoint screenPoint =
- [drop_target_ flipWindowPointToScreen:windowPoint
- view:[window contentView]];
- EXPECT_EQ(0, viewPoint.x);
- EXPECT_EQ(600, viewPoint.y);
- EXPECT_EQ(0, screenPoint.x);
- // We can't put a value on the screen size since everyone will have a
- // different one.
- EXPECT_NE(0, screenPoint.y);
-}
-
-TEST_F(WebDropTargetTest, URL) {
- NSPasteboard* pboard = nil;
- NSString* url = nil;
- NSString* title = nil;
- GURL result_url;
- string16 result_title;
-
- // Put a URL on the pasteboard and check it.
- pboard = [NSPasteboard pasteboardWithUniqueName];
- url = @"http://www.google.com/";
- PutURLOnPasteboard(url, pboard);
- EXPECT_TRUE([drop_target_ populateURL:&result_url
- andTitle:&result_title
- fromPasteboard:pboard
- convertingFilenames:NO]);
- EXPECT_EQ(base::SysNSStringToUTF8(url), result_url.spec());
- [pboard releaseGlobally];
-
- // Put a 'url ' and 'urln' on the pasteboard and check it.
- pboard = [NSPasteboard pasteboardWithUniqueName];
- url = @"http://www.google.com/";
- title = @"Title of Awesomeness!",
- PutCoreURLAndTitleOnPasteboard(url, title, pboard);
- EXPECT_TRUE([drop_target_ populateURL:&result_url
- andTitle:&result_title
- fromPasteboard:pboard
- convertingFilenames:NO]);
- EXPECT_EQ(base::SysNSStringToUTF8(url), result_url.spec());
- EXPECT_EQ(base::SysNSStringToUTF16(title), result_title);
- [pboard releaseGlobally];
-
- // Also check that it passes file:// via 'url '/'urln' properly.
- pboard = [NSPasteboard pasteboardWithUniqueName];
- url = @"file:///tmp/dont_delete_me.txt";
- title = @"very important";
- PutCoreURLAndTitleOnPasteboard(url, title, pboard);
- EXPECT_TRUE([drop_target_ populateURL:&result_url
- andTitle:&result_title
- fromPasteboard:pboard
- convertingFilenames:NO]);
- EXPECT_EQ(base::SysNSStringToUTF8(url), result_url.spec());
- EXPECT_EQ(base::SysNSStringToUTF16(title), result_title);
- [pboard releaseGlobally];
-
- // And javascript:.
- pboard = [NSPasteboard pasteboardWithUniqueName];
- url = @"javascript:open('http://www.youtube.com/')";
- title = @"kill some time";
- PutCoreURLAndTitleOnPasteboard(url, title, pboard);
- EXPECT_TRUE([drop_target_ populateURL:&result_url
- andTitle:&result_title
- fromPasteboard:pboard
- convertingFilenames:NO]);
- EXPECT_EQ(base::SysNSStringToUTF8(url), result_url.spec());
- EXPECT_EQ(base::SysNSStringToUTF16(title), result_title);
- [pboard releaseGlobally];
-
- pboard = [NSPasteboard pasteboardWithUniqueName];
- url = @"/bin/sh";
- [pboard declareTypes:[NSArray arrayWithObject:NSFilenamesPboardType]
- owner:nil];
- [pboard setPropertyList:[NSArray arrayWithObject:url]
- forType:NSFilenamesPboardType];
- EXPECT_FALSE([drop_target_ populateURL:&result_url
- andTitle:&result_title
- fromPasteboard:pboard
- convertingFilenames:NO]);
- EXPECT_TRUE([drop_target_ populateURL:&result_url
- andTitle:&result_title
- fromPasteboard:pboard
- convertingFilenames:YES]);
- EXPECT_EQ("file://localhost/bin/sh", result_url.spec());
- EXPECT_EQ("sh", UTF16ToUTF8(result_title));
- [pboard releaseGlobally];
-}
-
-TEST_F(WebDropTargetTest, Data) {
- WebDropData data;
- NSPasteboard* pboard = [NSPasteboard pasteboardWithUniqueName];
-
- PutURLOnPasteboard(@"http://www.google.com", pboard);
- [pboard addTypes:[NSArray arrayWithObjects:NSHTMLPboardType,
- NSStringPboardType, nil]
- owner:nil];
- NSString* htmlString = @"<html><body><b>hi there</b></body></html>";
- NSString* textString = @"hi there";
- [pboard setString:htmlString forType:NSHTMLPboardType];
- [pboard setString:textString forType:NSStringPboardType];
- [drop_target_ populateWebDropData:&data fromPasteboard:pboard];
- EXPECT_EQ(data.url.spec(), "http://www.google.com/");
- EXPECT_EQ(base::SysNSStringToUTF16(textString), data.plain_text);
- EXPECT_EQ(base::SysNSStringToUTF16(htmlString), data.text_html);
-
- [pboard releaseGlobally];
-}
diff --git a/chrome/browser/cocoa/window_size_autosaver.h b/chrome/browser/cocoa/window_size_autosaver.h
deleted file mode 100644
index 6556e58..0000000
--- a/chrome/browser/cocoa/window_size_autosaver.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_WINDOW_SIZE_AUTOSAVER_H_
-#define CHROME_BROWSER_COCOA_WINDOW_SIZE_AUTOSAVER_H_
-#pragma once
-
-class PrefService;
-@class NSWindow;
-
-// WindowSizeAutosaver is a helper class that makes it easy to let windows
-// autoremember their position or position and size in a PrefService object.
-// To use this, add a |scoped_nsobject<WindowSizeAutosaver>| to your window
-// controller and initialize it in the window controller's init method, passing
-// a window and an autosave name. The autosaver will register for "window moved"
-// and "window resized" notifications and write the current window state to the
-// prefs service every time they fire. The window's size is automatically
-// restored when the autosaver's |initWithWindow:...| method is called.
-//
-// Note: Your xib file should have "Visible at launch" UNCHECKED, so that the
-// initial repositioning is not visible.
-@interface WindowSizeAutosaver : NSObject {
- NSWindow* window_; // weak
- PrefService* prefService_; // weak
- const char* path_;
-}
-
-- (id)initWithWindow:(NSWindow*)window
- prefService:(PrefService*)prefs
- path:(const char*)path;
-@end
-
-#endif // CHROME_BROWSER_COCOA_WINDOW_SIZE_AUTOSAVER_H_
-
diff --git a/chrome/browser/cocoa/window_size_autosaver.mm b/chrome/browser/cocoa/window_size_autosaver.mm
deleted file mode 100644
index c93525e..0000000
--- a/chrome/browser/cocoa/window_size_autosaver.mm
+++ /dev/null
@@ -1,108 +0,0 @@
-// 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>
-
-#import "chrome/browser/cocoa/window_size_autosaver.h"
-
-#include "chrome/browser/prefs/pref_service.h"
-
-// If the window width stored in the prefs is smaller than this, the size is
-// not restored but instead cleared from the profile -- to protect users from
-// accidentally making their windows very small and then not finding them again.
-const int kMinWindowWidth = 101;
-
-// Minimum restored window height, see |kMinWindowWidth|.
-const int kMinWindowHeight = 17;
-
-@interface WindowSizeAutosaver (Private)
-- (void)save:(NSNotification*)notification;
-- (void)restore;
-@end
-
-@implementation WindowSizeAutosaver
-
-- (id)initWithWindow:(NSWindow*)window
- prefService:(PrefService*)prefs
- path:(const char*)path {
- if ((self = [super init])) {
- window_ = window;
- prefService_ = prefs;
- path_ = path;
-
- [self restore];
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(save:)
- name:NSWindowDidMoveNotification
- object:window_];
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(save:)
- name:NSWindowDidResizeNotification
- object:window_];
- }
- return self;
-}
-
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [super dealloc];
-}
-
-- (void)save:(NSNotification*)notification {
- DictionaryValue* windowPrefs = prefService_->GetMutableDictionary(path_);
- NSRect frame = [window_ frame];
- if ([window_ styleMask] & NSResizableWindowMask) {
- // Save the origin of the window.
- windowPrefs->SetInteger("left", NSMinX(frame));
- windowPrefs->SetInteger("right", NSMaxX(frame));
- // windows's and linux's profiles have top < bottom due to having their
- // screen origin in the upper left, while cocoa's is in the lower left. To
- // keep the top < bottom invariant, store top in bottom and vice versa.
- windowPrefs->SetInteger("top", NSMinY(frame));
- windowPrefs->SetInteger("bottom", NSMaxY(frame));
- } else {
- // Save the origin of the window.
- windowPrefs->SetInteger("x", frame.origin.x);
- windowPrefs->SetInteger("y", frame.origin.y);
- }
-}
-
-- (void)restore {
- // Get the positioning information.
- DictionaryValue* windowPrefs = prefService_->GetMutableDictionary(path_);
- if ([window_ styleMask] & NSResizableWindowMask) {
- int x1, x2, y1, y2;
- if (!windowPrefs->GetInteger("left", &x1) ||
- !windowPrefs->GetInteger("right", &x2) ||
- !windowPrefs->GetInteger("top", &y1) ||
- !windowPrefs->GetInteger("bottom", &y2)) {
- return;
- }
- if (x2 - x1 < kMinWindowWidth || y2 - y1 < kMinWindowHeight) {
- // Windows should never be very small.
- windowPrefs->Remove("left", NULL);
- windowPrefs->Remove("right", NULL);
- windowPrefs->Remove("top", NULL);
- windowPrefs->Remove("bottom", NULL);
- } else {
- [window_ setFrame:NSMakeRect(x1, y1, x2 - x1, y2 - y1) display:YES];
-
- // Make sure the window is on-screen.
- [window_ cascadeTopLeftFromPoint:NSZeroPoint];
- }
- } else {
- int x, y;
- if (!windowPrefs->GetInteger("x", &x) ||
- !windowPrefs->GetInteger("y", &y))
- return; // Nothing stored.
- // Turn the origin (lower-left) into an upper-left window point.
- NSPoint upperLeft = NSMakePoint(x, y + NSHeight([window_ frame]));
- [window_ cascadeTopLeftFromPoint:upperLeft];
- }
-}
-
-@end
-
diff --git a/chrome/browser/cocoa/window_size_autosaver_unittest.mm b/chrome/browser/cocoa/window_size_autosaver_unittest.mm
deleted file mode 100644
index b220ea0..0000000
--- a/chrome/browser/cocoa/window_size_autosaver_unittest.mm
+++ /dev/null
@@ -1,201 +0,0 @@
-// Copyright (c) 2009 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>
-
-#import "chrome/browser/cocoa/window_size_autosaver.h"
-
-#include "base/scoped_nsobject.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-namespace {
-
-class WindowSizeAutosaverTest : public CocoaTest {
- virtual void SetUp() {
- CocoaTest::SetUp();
- path_ = "WindowSizeAutosaverTest";
- window_ =
- [[NSWindow alloc] initWithContentRect:NSMakeRect(100, 101, 150, 151)
- styleMask:NSTitledWindowMask|
- NSResizableWindowMask
- backing:NSBackingStoreBuffered
- defer:NO];
- browser_helper_.profile()->GetPrefs()->RegisterDictionaryPref(path_);
- }
-
- virtual void TearDown() {
- [window_ close];
- CocoaTest::TearDown();
- }
-
- public:
- BrowserTestHelper browser_helper_;
- NSWindow* window_;
- const char* path_;
-};
-
-TEST_F(WindowSizeAutosaverTest, RestoresAndSavesPos) {
- PrefService* pref = browser_helper_.profile()->GetPrefs();
- ASSERT_TRUE(pref != NULL);
-
- // Check to make sure there is no existing pref for window placement.
- ASSERT_TRUE(pref->GetDictionary(path_) == NULL);
-
- // Replace the window with one that doesn't have resize controls.
- [window_ close];
- window_ =
- [[NSWindow alloc] initWithContentRect:NSMakeRect(100, 101, 150, 151)
- styleMask:NSTitledWindowMask
- backing:NSBackingStoreBuffered
- defer:NO];
-
- // Ask the window to save its position, then check that a preference
- // exists. We're technically passing in a pointer to the user prefs
- // and not the local state prefs, but a PrefService* is a
- // PrefService*, and this is a unittest.
-
- {
- NSRect frame = [window_ frame];
- // Empty state, shouldn't restore:
- scoped_nsobject<WindowSizeAutosaver> sizeSaver([[WindowSizeAutosaver alloc]
- initWithWindow:window_
- prefService:pref
- path:path_]);
- EXPECT_EQ(NSMinX(frame), NSMinX([window_ frame]));
- EXPECT_EQ(NSMinY(frame), NSMinY([window_ frame]));
- EXPECT_EQ(NSWidth(frame), NSWidth([window_ frame]));
- EXPECT_EQ(NSHeight(frame), NSHeight([window_ frame]));
-
- // Move and resize window, should store position but not size.
- [window_ setFrame:NSMakeRect(300, 310, 250, 252) display:NO];
- }
-
- // Another window movement -- shouldn't be recorded.
- [window_ setFrame:NSMakeRect(400, 420, 160, 162) display:NO];
-
- {
- // Should restore last stored position, but not size.
- scoped_nsobject<WindowSizeAutosaver> sizeSaver([[WindowSizeAutosaver alloc]
- initWithWindow:window_
- prefService:pref
- path:path_]);
- EXPECT_EQ(300, NSMinX([window_ frame]));
- EXPECT_EQ(310, NSMinY([window_ frame]));
- EXPECT_EQ(160, NSWidth([window_ frame]));
- EXPECT_EQ(162, NSHeight([window_ frame]));
- }
-
- // ...and it should be in the profile, too.
- EXPECT_TRUE(pref->GetDictionary(path_) != NULL);
- int x, y;
- DictionaryValue* windowPref = pref->GetMutableDictionary(path_);
- EXPECT_FALSE(windowPref->GetInteger("left", &x));
- EXPECT_FALSE(windowPref->GetInteger("right", &x));
- EXPECT_FALSE(windowPref->GetInteger("top", &x));
- EXPECT_FALSE(windowPref->GetInteger("bottom", &x));
- ASSERT_TRUE(windowPref->GetInteger("x", &x));
- ASSERT_TRUE(windowPref->GetInteger("y", &y));
- EXPECT_EQ(300, x);
- EXPECT_EQ(310, y);
-}
-
-TEST_F(WindowSizeAutosaverTest, RestoresAndSavesRect) {
- PrefService* pref = browser_helper_.profile()->GetPrefs();
- ASSERT_TRUE(pref != NULL);
-
- // Check to make sure there is no existing pref for window placement.
- ASSERT_TRUE(pref->GetDictionary(path_) == NULL);
-
- // Ask the window to save its position, then check that a preference
- // exists. We're technically passing in a pointer to the user prefs
- // and not the local state prefs, but a PrefService* is a
- // PrefService*, and this is a unittest.
-
- {
- NSRect frame = [window_ frame];
- // Empty state, shouldn't restore:
- scoped_nsobject<WindowSizeAutosaver> sizeSaver([[WindowSizeAutosaver alloc]
- initWithWindow:window_
- prefService:pref
- path:path_]);
- EXPECT_EQ(NSMinX(frame), NSMinX([window_ frame]));
- EXPECT_EQ(NSMinY(frame), NSMinY([window_ frame]));
- EXPECT_EQ(NSWidth(frame), NSWidth([window_ frame]));
- EXPECT_EQ(NSHeight(frame), NSHeight([window_ frame]));
-
- // Move and resize window, should store
- [window_ setFrame:NSMakeRect(300, 310, 250, 252) display:NO];
- }
-
- // Another window movement -- shouldn't be recorded.
- [window_ setFrame:NSMakeRect(400, 420, 160, 162) display:NO];
-
- {
- // Should restore last stored size
- scoped_nsobject<WindowSizeAutosaver> sizeSaver([[WindowSizeAutosaver alloc]
- initWithWindow:window_
- prefService:pref
- path:path_]);
- EXPECT_EQ(300, NSMinX([window_ frame]));
- EXPECT_EQ(310, NSMinY([window_ frame]));
- EXPECT_EQ(250, NSWidth([window_ frame]));
- EXPECT_EQ(252, NSHeight([window_ frame]));
- }
-
- // ...and it should be in the profile, too.
- EXPECT_TRUE(pref->GetDictionary(path_) != NULL);
- int x1, y1, x2, y2;
- DictionaryValue* windowPref = pref->GetMutableDictionary(path_);
- EXPECT_FALSE(windowPref->GetInteger("x", &x1));
- EXPECT_FALSE(windowPref->GetInteger("y", &x1));
- ASSERT_TRUE(windowPref->GetInteger("left", &x1));
- ASSERT_TRUE(windowPref->GetInteger("right", &x2));
- ASSERT_TRUE(windowPref->GetInteger("top", &y1));
- ASSERT_TRUE(windowPref->GetInteger("bottom", &y2));
- EXPECT_EQ(300, x1);
- EXPECT_EQ(310, y1);
- EXPECT_EQ(300 + 250, x2);
- EXPECT_EQ(310 + 252, y2);
-}
-
-// http://crbug.com/39625
-TEST_F(WindowSizeAutosaverTest, DoesNotRestoreButClearsEmptyRect) {
- PrefService* pref = browser_helper_.profile()->GetPrefs();
- ASSERT_TRUE(pref != NULL);
-
- DictionaryValue* windowPref = pref->GetMutableDictionary(path_);
- windowPref->SetInteger("left", 50);
- windowPref->SetInteger("right", 50);
- windowPref->SetInteger("top", 60);
- windowPref->SetInteger("bottom", 60);
-
- {
- // Window rect shouldn't change...
- NSRect frame = [window_ frame];
- scoped_nsobject<WindowSizeAutosaver> sizeSaver([[WindowSizeAutosaver alloc]
- initWithWindow:window_
- prefService:pref
- path:path_]);
- EXPECT_EQ(NSMinX(frame), NSMinX([window_ frame]));
- EXPECT_EQ(NSMinY(frame), NSMinY([window_ frame]));
- EXPECT_EQ(NSWidth(frame), NSWidth([window_ frame]));
- EXPECT_EQ(NSHeight(frame), NSHeight([window_ frame]));
- }
-
- // ...and it should be gone from the profile, too.
- EXPECT_TRUE(pref->GetDictionary(path_) != NULL);
- int x1, y1, x2, y2;
- EXPECT_FALSE(windowPref->GetInteger("x", &x1));
- EXPECT_FALSE(windowPref->GetInteger("y", &x1));
- ASSERT_FALSE(windowPref->GetInteger("left", &x1));
- ASSERT_FALSE(windowPref->GetInteger("right", &x2));
- ASSERT_FALSE(windowPref->GetInteger("top", &y1));
- ASSERT_FALSE(windowPref->GetInteger("bottom", &y2));
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/wrench_menu_button_cell.h b/chrome/browser/cocoa/wrench_menu_button_cell.h
deleted file mode 100644
index 1ce73a8..0000000
--- a/chrome/browser/cocoa/wrench_menu_button_cell.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_WRENCH_MENU_BUTTON_CELL_H_
-#define CHROME_BROWSER_COCOA_WRENCH_MENU_BUTTON_CELL_H_
-
-#import <Cocoa/Cocoa.h>
-
-// The WrenchMenuButtonCell overrides drawing the background gradient to use
-// the same colors as NSSmallSquareBezelStyle but as a smooth gradient, rather
-// than two blocks of colors. This also uses the blue menu highlight color for
-// the pressed state.
-@interface WrenchMenuButtonCell : NSButtonCell {
-}
-
-@end
-
-#endif // CHROME_BROWSER_COCOA_WRENCH_MENU_BUTTON_CELL_H_
diff --git a/chrome/browser/cocoa/wrench_menu_button_cell.mm b/chrome/browser/cocoa/wrench_menu_button_cell.mm
deleted file mode 100644
index 70e0e6f..0000000
--- a/chrome/browser/cocoa/wrench_menu_button_cell.mm
+++ /dev/null
@@ -1,48 +0,0 @@
-// 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 "chrome/browser/cocoa/wrench_menu_button_cell.h"
-
-#include "base/scoped_nsobject.h"
-
-@implementation WrenchMenuButtonCell
-
-- (void)drawBezelWithFrame:(NSRect)frame inView:(NSView*)controlView {
- [NSGraphicsContext saveGraphicsState];
-
- // Inset the rect to match the appearance of the layout of interface builder.
- // The bounding rect of buttons is actually larger than the display rect shown
- // there.
- frame = NSInsetRect(frame, 0.0, 1.0);
-
- // Stroking the rect gives a weak stroke. Filling and insetting gives a
- // strong, un-anti-aliased border.
- [[NSColor colorWithDeviceWhite:0.663 alpha:1.0] set];
- NSRectFill(frame);
- frame = NSInsetRect(frame, 1.0, 1.0);
-
- // The default state should be a subtle gray gradient.
- if (![self isHighlighted]) {
- NSColor* end = [NSColor colorWithDeviceWhite:0.922 alpha:1.0];
- scoped_nsobject<NSGradient> gradient(
- [[NSGradient alloc] initWithStartingColor:[NSColor whiteColor]
- endingColor:end]);
- [gradient drawInRect:frame angle:90.0];
- } else {
- // |+selectedMenuItemColor| appears to be a gradient, so just filling the
- // rect with that color produces the desired effect.
- [[NSColor selectedMenuItemColor] set];
- NSRectFill(frame);
- }
-
- [NSGraphicsContext restoreGraphicsState];
-}
-
-- (NSBackgroundStyle)interiorBackgroundStyle {
- if ([self isHighlighted])
- return NSBackgroundStyleDark;
- return [super interiorBackgroundStyle];
-}
-
-@end
diff --git a/chrome/browser/cocoa/wrench_menu_button_cell_unittest.mm b/chrome/browser/cocoa/wrench_menu_button_cell_unittest.mm
deleted file mode 100644
index b24ad50..0000000
--- a/chrome/browser/cocoa/wrench_menu_button_cell_unittest.mm
+++ /dev/null
@@ -1,51 +0,0 @@
-// 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.
-
-#include "base/scoped_nsobject.h"
-#include "chrome/app/chrome_command_ids.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/wrench_menu_button_cell.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-@interface TestWrenchMenuButton : NSButton
-@end
-@implementation TestWrenchMenuButton
-+ (Class)cellClass {
- return [WrenchMenuButtonCell class];
-}
-@end
-
-namespace {
-
-class WrenchMenuButtonCellTest : public CocoaTest {
- public:
- void SetUp() {
- CocoaTest::SetUp();
-
- NSRect frame = NSMakeRect(10, 10, 50, 19);
- button_.reset([[TestWrenchMenuButton alloc] initWithFrame:frame]);
- [button_ setBezelStyle:NSSmallSquareBezelStyle];
- [[button_ cell] setControlSize:NSSmallControlSize];
- [button_ setTitle:@"Allays"];
- [button_ setButtonType:NSMomentaryPushInButton];
- }
-
- scoped_nsobject<NSButton> button_;
-};
-
-TEST_F(WrenchMenuButtonCellTest, Draw) {
- ASSERT_TRUE(button_.get());
- [[test_window() contentView] addSubview:button_.get()];
- [button_ setNeedsDisplay:YES];
-}
-
-TEST_F(WrenchMenuButtonCellTest, DrawHighlight) {
- ASSERT_TRUE(button_.get());
- [[test_window() contentView] addSubview:button_.get()];
- [button_ highlight:YES];
- [button_ setNeedsDisplay:YES];
-}
-
-} // namespace
diff --git a/chrome/browser/cocoa/wrench_menu_controller.h b/chrome/browser/cocoa/wrench_menu_controller.h
deleted file mode 100644
index bbfa995..0000000
--- a/chrome/browser/cocoa/wrench_menu_controller.h
+++ /dev/null
@@ -1,72 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_COCOA_WRENCH_MENU_CONTROLLER_H_
-#define CHROME_BROWSER_COCOA_WRENCH_MENU_CONTROLLER_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/cocoa_protocols_mac.h"
-#include "base/scoped_ptr.h"
-#import "chrome/browser/cocoa/menu_controller.h"
-
-@class MenuTrackedRootView;
-@class ToolbarController;
-class WrenchMenuModel;
-
-namespace WrenchMenuControllerInternal {
-class ZoomLevelObserver;
-} // namespace WrenchMenuControllerInternal
-
-// The Wrench menu has a creative layout, with buttons in menu items. There is
-// a cross-platform model for this special menu, but on the Mac it's easier to
-// get spacing and alignment precisely right using a NIB. To do that, we
-// subclass the generic MenuController implementation and special-case the two
-// items that require specific layout and load them from the NIB.
-//
-// This object is instantiated in Toolbar.xib and is configured by the
-// ToolbarController.
-@interface WrenchMenuController : MenuController<NSMenuDelegate> {
- IBOutlet MenuTrackedRootView* editItem_;
- IBOutlet NSButton* editCut_;
- IBOutlet NSButton* editCopy_;
- IBOutlet NSButton* editPaste_;
-
- IBOutlet MenuTrackedRootView* zoomItem_;
- IBOutlet NSButton* zoomPlus_;
- IBOutlet NSButton* zoomDisplay_;
- IBOutlet NSButton* zoomMinus_;
- IBOutlet NSButton* zoomFullScreen_;
-
- scoped_ptr<WrenchMenuControllerInternal::ZoomLevelObserver> observer_;
-}
-
-// Designated initializer; called within the NIB.
-- (id)init;
-
-// Used to dispatch commands from the Wrench menu. The custom items within the
-// menu cannot be hooked up directly to First Responder because the window in
-// which the controls reside is not the BrowserWindowController, but a
-// NSCarbonMenuWindow; this screws up the typical |-commandDispatch:| system.
-- (IBAction)dispatchWrenchMenuCommand:(id)sender;
-
-// Returns the weak reference to the WrenchMenuModel.
-- (WrenchMenuModel*)wrenchMenuModel;
-
-@end
-
-////////////////////////////////////////////////////////////////////////////////
-
-@interface WrenchMenuController (UnitTesting)
-// |-dispatchWrenchMenuCommand:| calls this after it has determined the tag of
-// the sender. The default implementation executes the command on the outermost
-// run loop using |-performSelector...withDelay:|. This is not desirable in
-// unit tests because it's hard to test around run loops in a deterministic
-// manner. To avoid those headaches, tests should provide an alternative
-// implementation.
-- (void)dispatchCommandInternal:(NSInteger)tag;
-@end
-
-#endif // CHROME_BROWSER_COCOA_WRENCH_MENU_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/wrench_menu_controller.mm b/chrome/browser/cocoa/wrench_menu_controller.mm
deleted file mode 100644
index d07e05f..0000000
--- a/chrome/browser/cocoa/wrench_menu_controller.mm
+++ /dev/null
@@ -1,213 +0,0 @@
-// 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 "chrome/browser/cocoa/wrench_menu_controller.h"
-
-#include "app/l10n_util.h"
-#include "app/menus/menu_model.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/app/chrome_command_ids.h"
-#import "chrome/browser/cocoa/menu_tracked_root_view.h"
-#import "chrome/browser/cocoa/toolbar_controller.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/wrench_menu_model.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/notification_source.h"
-#include "chrome/common/notification_type.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-
-@interface WrenchMenuController (Private)
-- (void)adjustPositioning;
-- (void)performCommandDispatch:(NSNumber*)tag;
-- (NSButton*)zoomDisplay;
-@end
-
-namespace WrenchMenuControllerInternal {
-
-class ZoomLevelObserver : public NotificationObserver {
- public:
- explicit ZoomLevelObserver(WrenchMenuController* controller)
- : controller_(controller) {
- registrar_.Add(this, NotificationType::ZOOM_LEVEL_CHANGED,
- NotificationService::AllSources());
- }
-
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- DCHECK_EQ(type.value, NotificationType::ZOOM_LEVEL_CHANGED);
- WrenchMenuModel* wrenchMenuModel = [controller_ wrenchMenuModel];
- wrenchMenuModel->UpdateZoomControls();
- const string16 level =
- wrenchMenuModel->GetLabelForCommandId(IDC_ZOOM_PERCENT_DISPLAY);
- [[controller_ zoomDisplay] setTitle:SysUTF16ToNSString(level)];
- }
-
- private:
- NotificationRegistrar registrar_;
- WrenchMenuController* controller_; // Weak; owns this.
-};
-
-} // namespace WrenchMenuControllerInternal
-
-@implementation WrenchMenuController
-
-- (id)init {
- if ((self = [super init])) {
- observer_.reset(new WrenchMenuControllerInternal::ZoomLevelObserver(self));
- }
- return self;
-}
-
-- (void)addItemToMenu:(NSMenu*)menu
- atIndex:(NSInteger)index
- fromModel:(menus::MenuModel*)model
- modelIndex:(int)modelIndex {
- // Non-button item types should be built as normal items.
- menus::MenuModel::ItemType type = model->GetTypeAt(modelIndex);
- if (type != menus::MenuModel::TYPE_BUTTON_ITEM) {
- [super addItemToMenu:menu
- atIndex:index
- fromModel:model
- modelIndex:modelIndex];
- return;
- }
-
- // Handle the special-cased menu items.
- int command_id = model->GetCommandIdAt(modelIndex);
- scoped_nsobject<NSMenuItem> customItem(
- [[NSMenuItem alloc] initWithTitle:@""
- action:nil
- keyEquivalent:@""]);
- switch (command_id) {
- case IDC_EDIT_MENU:
- DCHECK(editItem_);
- [customItem setView:editItem_];
- [editItem_ setMenuItem:customItem];
- break;
- case IDC_ZOOM_MENU:
- DCHECK(zoomItem_);
- [customItem setView:zoomItem_];
- [zoomItem_ setMenuItem:customItem];
- break;
- default:
- NOTREACHED();
- break;
- }
- [self adjustPositioning];
- [menu insertItem:customItem.get() atIndex:index];
-}
-
-- (NSMenu*)menu {
- NSMenu* menu = [super menu];
- if (![menu delegate]) {
- [menu setDelegate:self];
- }
- return menu;
-}
-
-- (void)menuWillOpen:(NSMenu*)menu {
- NSString* title = base::SysUTF16ToNSString(
- [self wrenchMenuModel]->GetLabelForCommandId(IDC_ZOOM_PERCENT_DISPLAY));
- [[zoomItem_ viewWithTag:IDC_ZOOM_PERCENT_DISPLAY] setTitle:title];
-
- NSImage* icon = [self wrenchMenuModel]->browser()->window()->IsFullscreen() ?
- [NSImage imageNamed:NSImageNameExitFullScreenTemplate] :
- [NSImage imageNamed:NSImageNameEnterFullScreenTemplate];
- [zoomFullScreen_ setImage:icon];
-}
-
-// Used to dispatch commands from the Wrench menu. The custom items within the
-// menu cannot be hooked up directly to First Responder because the window in
-// which the controls reside is not the BrowserWindowController, but a
-// NSCarbonMenuWindow; this screws up the typical |-commandDispatch:| system.
-- (IBAction)dispatchWrenchMenuCommand:(id)sender {
- NSInteger tag = [sender tag];
- if (sender == zoomPlus_ || sender == zoomMinus_) {
- // Do a direct dispatch rather than scheduling on the outermost run loop,
- // which would not get hit until after the menu had closed.
- [self performCommandDispatch:[NSNumber numberWithInt:tag]];
-
- // The zoom buttons should not close the menu if opened sticky.
- if ([sender respondsToSelector:@selector(isTracking)] &&
- [sender performSelector:@selector(isTracking)]) {
- [menu_ cancelTracking];
- }
- } else {
- // The custom views within the Wrench menu are abnormal and keep the menu
- // open after a target-action. Close the menu manually.
- [menu_ cancelTracking];
- [self dispatchCommandInternal:tag];
- }
-}
-
-- (void)dispatchCommandInternal:(NSInteger)tag {
- // Executing certain commands from the nested run loop of the menu can lead
- // to wonky behavior (e.g. http://crbug.com/49716). To avoid this, schedule
- // the dispatch on the outermost run loop.
- [self performSelector:@selector(performCommandDispatch:)
- withObject:[NSNumber numberWithInt:tag]
- afterDelay:0.0];
-}
-
-// Used to perform the actual dispatch on the outermost runloop.
-- (void)performCommandDispatch:(NSNumber*)tag {
- [self wrenchMenuModel]->ExecuteCommand([tag intValue]);
-}
-
-- (WrenchMenuModel*)wrenchMenuModel {
- return static_cast<WrenchMenuModel*>(model_);
-}
-
-// Fit the localized strings into the Cut/Copy/Paste control, then resize the
-// whole menu item accordingly.
-- (void)adjustPositioning {
- const CGFloat kButtonPadding = 12;
- CGFloat delta = 0;
-
- // Go through the three buttons from right-to-left, adjusting the size to fit
- // the localized strings while keeping them all aligned on their horizontal
- // edges.
- const size_t kAdjustViewCount = 3;
- NSButton* views[kAdjustViewCount] = { editPaste_, editCopy_, editCut_ };
- for (size_t i = 0; i < kAdjustViewCount; ++i) {
- NSButton* button = views[i];
- CGFloat originalWidth = NSWidth([button frame]);
-
- // Do not let |-sizeToFit| change the height of the button.
- NSSize size = [button frame].size;
- [button sizeToFit];
- size.width = [button frame].size.width + kButtonPadding;
- [button setFrameSize:size];
-
- CGFloat newWidth = size.width;
- delta += newWidth - originalWidth;
-
- NSRect frame = [button frame];
- frame.origin.x -= delta;
- [button setFrame:frame];
- }
-
- // Resize the menu item by the total amound the buttons changed so that the
- // spacing between the buttons and the title remains the same.
- NSRect itemFrame = [editItem_ frame];
- itemFrame.size.width += delta;
- [editItem_ setFrame:itemFrame];
-
- // Also resize the superview of the buttons, which is an NSView used to slide
- // when the item title is too big and GTM resizes it.
- NSRect parentFrame = [[editCut_ superview] frame];
- parentFrame.size.width += delta;
- parentFrame.origin.x -= delta;
- [[editCut_ superview] setFrame:parentFrame];
-}
-
-- (NSButton*)zoomDisplay {
- return zoomDisplay_;
-}
-
-@end // @implementation WrenchMenuController
diff --git a/chrome/browser/cocoa/wrench_menu_controller_unittest.mm b/chrome/browser/cocoa/wrench_menu_controller_unittest.mm
deleted file mode 100644
index 1018666..0000000
--- a/chrome/browser/cocoa/wrench_menu_controller_unittest.mm
+++ /dev/null
@@ -1,84 +0,0 @@
-// 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.
-
-#include "base/scoped_nsobject.h"
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#import "chrome/browser/cocoa/toolbar_controller.h"
-#import "chrome/browser/cocoa/wrench_menu_controller.h"
-#import "chrome/browser/cocoa/view_resizer_pong.h"
-#include "chrome/browser/wrench_menu_model.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-// Override to avoid dealing with run loops in the testing environment.
-@implementation WrenchMenuController (UnitTesting)
-- (void)dispatchCommandInternal:(NSInteger)tag {
- [self wrenchMenuModel]->ExecuteCommand(tag);
-}
-@end
-
-
-namespace {
-
-class MockWrenchMenuModel : public WrenchMenuModel {
- public:
- MockWrenchMenuModel() : WrenchMenuModel() {}
- ~MockWrenchMenuModel() {
- // This dirty, ugly hack gets around a bug in the test. In
- // ~WrenchMenuModel(), there's a call to TabstripModel::RemoveObserver(this)
- // which mysteriously leads to this crash: http://crbug.com/49206 . It
- // seems that the vector of observers is getting hosed somewhere between
- // |-[ToolbarController dealloc]| and ~MockWrenchMenuModel(). This line
- // short-circuits the parent destructor to avoid this crash.
- tabstrip_model_ = NULL;
- }
- MOCK_METHOD1(ExecuteCommand, void(int command_id));
-};
-
-class WrenchMenuControllerTest : public CocoaTest {
- public:
- void SetUp() {
- Browser* browser = helper_.browser();
- resize_delegate_.reset([[ViewResizerPong alloc] init]);
- toolbar_controller_.reset(
- [[ToolbarController alloc] initWithModel:browser->toolbar_model()
- commands:browser->command_updater()
- profile:helper_.profile()
- browser:browser
- resizeDelegate:resize_delegate_.get()]);
- EXPECT_TRUE([toolbar_controller_ view]);
- NSView* parent = [test_window() contentView];
- [parent addSubview:[toolbar_controller_ view]];
- }
-
- WrenchMenuController* controller() {
- return [toolbar_controller_ wrenchMenuController];
- }
-
- BrowserTestHelper helper_;
- scoped_nsobject<ViewResizerPong> resize_delegate_;
- MockWrenchMenuModel fake_model_;
- scoped_nsobject<ToolbarController> toolbar_controller_;
-};
-
-TEST_F(WrenchMenuControllerTest, Initialized) {
- EXPECT_TRUE([controller() menu]);
- EXPECT_GE([[controller() menu] numberOfItems], 5);
-}
-
-TEST_F(WrenchMenuControllerTest, DispatchSimple) {
- scoped_nsobject<NSButton> button([[NSButton alloc] init]);
- [button setTag:IDC_ZOOM_PLUS];
-
- // Set fake model to test dispatching.
- EXPECT_CALL(fake_model_, ExecuteCommand(IDC_ZOOM_PLUS));
- [controller() setModel:&fake_model_];
-
- [controller() dispatchWrenchMenuCommand:button.get()];
-}
-
-} // namespace
diff --git a/chrome/browser/content_exceptions_table_model.cc b/chrome/browser/content_exceptions_table_model.cc
index 84e8c2d..ee92157 100644
--- a/chrome/browser/content_exceptions_table_model.cc
+++ b/chrome/browser/content_exceptions_table_model.cc
@@ -7,7 +7,7 @@
#include "app/l10n_util.h"
#include "app/table_model_observer.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/host_content_settings_map.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "grit/generated_resources.h"
ContentExceptionsTableModel::ContentExceptionsTableModel(
@@ -30,7 +30,7 @@ ContentExceptionsTableModel::ContentExceptionsTableModel(
ContentExceptionsTableModel::~ContentExceptionsTableModel() {}
void ContentExceptionsTableModel::AddException(
- const HostContentSettingsMap::Pattern& original_pattern,
+ const ContentSettingsPattern& original_pattern,
ContentSetting setting,
bool is_off_the_record) {
DCHECK(!is_off_the_record || off_the_record_map_);
@@ -38,7 +38,7 @@ void ContentExceptionsTableModel::AddException(
int insert_position =
is_off_the_record ? RowCount() : static_cast<int>(entries_.size());
- const HostContentSettingsMap::Pattern pattern(
+ const ContentSettingsPattern pattern(
original_pattern.CanonicalizePattern());
entries(is_off_the_record).push_back(
@@ -77,14 +77,14 @@ void ContentExceptionsTableModel::RemoveAll() {
}
int ContentExceptionsTableModel::IndexOfExceptionByPattern(
- const HostContentSettingsMap::Pattern& original_pattern,
+ const ContentSettingsPattern& original_pattern,
bool is_off_the_record) {
DCHECK(!is_off_the_record || off_the_record_map_);
int offset =
is_off_the_record ? static_cast<int>(entries_.size()) : 0;
- const HostContentSettingsMap::Pattern pattern(
+ const ContentSettingsPattern pattern(
original_pattern.CanonicalizePattern());
// This is called on every key type in the editor. Move to a map if we end up
diff --git a/chrome/browser/content_exceptions_table_model.h b/chrome/browser/content_exceptions_table_model.h
index 245522e..e01250b 100644
--- a/chrome/browser/content_exceptions_table_model.h
+++ b/chrome/browser/content_exceptions_table_model.h
@@ -12,7 +12,7 @@
#include "base/ref_counted.h"
#include "chrome/common/content_settings.h"
#include "chrome/common/content_settings_types.h"
-#include "chrome/browser/host_content_settings_map.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
class ContentExceptionsTableModel : public TableModel {
public:
@@ -37,7 +37,7 @@ class ContentExceptionsTableModel : public TableModel {
}
// Adds a new exception on the map and table model.
- void AddException(const HostContentSettingsMap::Pattern& pattern,
+ void AddException(const ContentSettingsPattern& pattern,
ContentSetting setting,
bool is_off_the_record);
@@ -49,7 +49,7 @@ class ContentExceptionsTableModel : public TableModel {
// Returns the index of the specified exception given a host, or -1 if there
// is no exception for the specified host.
- int IndexOfExceptionByPattern(const HostContentSettingsMap::Pattern& pattern,
+ int IndexOfExceptionByPattern(const ContentSettingsPattern& pattern,
bool is_off_the_record);
// TableModel overrides:
diff --git a/chrome/browser/content_exceptions_table_model_unittest.cc b/chrome/browser/content_exceptions_table_model_unittest.cc
index f467d07..3c3d26d 100644
--- a/chrome/browser/content_exceptions_table_model_unittest.cc
+++ b/chrome/browser/content_exceptions_table_model_unittest.cc
@@ -27,7 +27,7 @@ TEST_F(ContentExceptionsTableModelTest, Incognito) {
otr_profile->GetHostContentSettingsMap(),
CONTENT_SETTINGS_TYPE_COOKIES);
delete otr_profile;
- model.AddException(HostContentSettingsMap::Pattern("example.com"),
+ model.AddException(ContentSettingsPattern("example.com"),
CONTENT_SETTING_BLOCK, true);
}
diff --git a/chrome/browser/content_setting_bubble_model.cc b/chrome/browser/content_setting_bubble_model.cc
index f7e89d4..71889d8 100644
--- a/chrome/browser/content_setting_bubble_model.cc
+++ b/chrome/browser/content_setting_bubble_model.cc
@@ -8,11 +8,11 @@
#include "base/command_line.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/blocked_content_container.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
-#include "chrome/browser/host_content_settings_map.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
@@ -25,8 +25,9 @@
class ContentSettingTitleAndLinkModel : public ContentSettingBubbleModel {
public:
- ContentSettingTitleAndLinkModel(TabContents* tab_contents, Profile* profile,
- ContentSettingsType content_type)
+ ContentSettingTitleAndLinkModel(TabContents* tab_contents,
+ Profile* profile,
+ ContentSettingsType content_type)
: ContentSettingBubbleModel(tab_contents, profile, content_type) {
// Notifications do not have a bubble.
DCHECK_NE(content_type, CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
@@ -118,52 +119,45 @@ class ContentSettingTitleAndLinkModel : public ContentSettingBubbleModel {
}
};
-class ContentSettingTitleLinkAndInfoModel
+class ContentSettingTitleLinkAndCustomModel
: public ContentSettingTitleAndLinkModel {
public:
- ContentSettingTitleLinkAndInfoModel(TabContents* tab_contents,
- Profile* profile,
- ContentSettingsType content_type)
+ ContentSettingTitleLinkAndCustomModel(TabContents* tab_contents,
+ Profile* profile,
+ ContentSettingsType content_type)
: ContentSettingTitleAndLinkModel(tab_contents, profile, content_type) {
- SetInfoLink();
+ SetCustomLink();
}
private:
- void SetInfoLink() {
- static const int kInfoIDs[] = {
+ void SetCustomLink() {
+ static const int kCustomIDs[] = {
IDS_BLOCKED_COOKIES_INFO,
- 0, // Images do not have an info link.
- 0, // Javascript doesn't have an info link.
- 0, // Plugins do not have an info link.
- 0, // Popups do not have an info link.
- 0, // Geolocation does not have an info link.
+ 0, // Images do not have a custom link.
+ 0, // Javascript doesn't have a custom link.
+ IDS_BLOCKED_PLUGINS_LOAD_ALL,
+ 0, // Popups do not have a custom link.
+ 0, // Geolocation custom links are set within that class.
0, // Notifications do not have a bubble.
};
- COMPILE_ASSERT(arraysize(kInfoIDs) == CONTENT_SETTINGS_NUM_TYPES,
+ COMPILE_ASSERT(arraysize(kCustomIDs) == CONTENT_SETTINGS_NUM_TYPES,
Need_a_setting_for_every_content_settings_type);
- if (kInfoIDs[content_type()])
- set_info_link(l10n_util::GetStringUTF8(kInfoIDs[content_type()]));
+ if (kCustomIDs[content_type()])
+ set_custom_link(l10n_util::GetStringUTF8(kCustomIDs[content_type()]));
}
- virtual void OnInfoLinkClicked() {
- DCHECK(content_type() == CONTENT_SETTINGS_TYPE_COOKIES);
- if (tab_contents()) {
- NotificationService::current()->Notify(
- NotificationType::COLLECTED_COOKIES_SHOWN,
- Source<TabSpecificContentSettings>(
- tab_contents()->GetTabSpecificContentSettings()),
- NotificationService::NoDetails());
- tab_contents()->delegate()->ShowCollectedCookiesDialog(tab_contents());
- }
- }
+ virtual void OnCustomLinkClicked() {}
};
-class ContentSettingSingleRadioGroup : public ContentSettingTitleAndLinkModel {
+class ContentSettingSingleRadioGroup
+ : public ContentSettingTitleLinkAndCustomModel {
public:
- ContentSettingSingleRadioGroup(TabContents* tab_contents, Profile* profile,
- ContentSettingsType content_type)
- : ContentSettingTitleAndLinkModel(tab_contents, profile, content_type),
+ ContentSettingSingleRadioGroup(TabContents* tab_contents,
+ Profile* profile,
+ ContentSettingsType content_type)
+ : ContentSettingTitleLinkAndCustomModel(tab_contents, profile,
+ content_type),
block_setting_(CONTENT_SETTING_BLOCK) {
SetRadioGroup();
}
@@ -286,37 +280,58 @@ class ContentSettingSingleRadioGroup : public ContentSettingTitleAndLinkModel {
}
};
+class ContentSettingCookiesBubbleModel
+ : public ContentSettingTitleLinkAndCustomModel {
+ public:
+ ContentSettingCookiesBubbleModel(TabContents* tab_contents,
+ Profile* profile,
+ ContentSettingsType content_type)
+ : ContentSettingTitleLinkAndCustomModel(tab_contents, profile,
+ content_type) {
+ DCHECK_EQ(CONTENT_SETTINGS_TYPE_COOKIES, content_type);
+ set_custom_link_enabled(true);
+ }
+
+ private:
+ virtual void OnCustomLinkClicked() OVERRIDE {
+ if (tab_contents()) {
+ NotificationService::current()->Notify(
+ NotificationType::COLLECTED_COOKIES_SHOWN,
+ Source<TabSpecificContentSettings>(
+ tab_contents()->GetTabSpecificContentSettings()),
+ NotificationService::NoDetails());
+ tab_contents()->delegate()->ShowCollectedCookiesDialog(tab_contents());
+ }
+ }
+};
+
class ContentSettingPluginBubbleModel : public ContentSettingSingleRadioGroup {
public:
- ContentSettingPluginBubbleModel(TabContents* tab_contents, Profile* profile,
+ ContentSettingPluginBubbleModel(TabContents* tab_contents,
+ Profile* profile,
ContentSettingsType content_type)
: ContentSettingSingleRadioGroup(tab_contents, profile, content_type) {
DCHECK_EQ(content_type, CONTENT_SETTINGS_TYPE_PLUGINS);
- SetLoadPluginsLinkTitle();
+ set_custom_link_enabled(tab_contents && tab_contents->
+ GetTabSpecificContentSettings()->load_plugins_link_enabled());
}
private:
- void SetLoadPluginsLinkTitle() {
- set_load_plugins_link_title(
- l10n_util::GetStringUTF8(IDS_BLOCKED_PLUGINS_LOAD_ALL));
- }
-
- virtual void OnLoadPluginsLinkClicked() {
+ virtual void OnCustomLinkClicked() OVERRIDE {
UserMetrics::RecordAction(UserMetricsAction("ClickToPlay_LoadAll_Bubble"));
- if (tab_contents()) {
- tab_contents()->render_view_host()->LoadBlockedPlugins();
- }
- set_load_plugins_link_enabled(false);
- TabSpecificContentSettings* settings =
- tab_contents()->GetTabSpecificContentSettings();
- settings->set_load_plugins_link_enabled(false);
+ DCHECK(tab_contents());
+ tab_contents()->render_view_host()->LoadBlockedPlugins();
+ set_custom_link_enabled(false);
+ tab_contents()->GetTabSpecificContentSettings()->
+ set_load_plugins_link_enabled(false);
}
};
class ContentSettingPopupBubbleModel : public ContentSettingSingleRadioGroup {
public:
- ContentSettingPopupBubbleModel(TabContents* tab_contents, Profile* profile,
- ContentSettingsType content_type)
+ ContentSettingPopupBubbleModel(TabContents* tab_contents,
+ Profile* profile,
+ ContentSettingsType content_type)
: ContentSettingSingleRadioGroup(tab_contents, profile, content_type) {
SetPopups();
}
@@ -361,7 +376,7 @@ class ContentSettingDomainListBubbleModel
: ContentSettingTitleAndLinkModel(tab_contents, profile, content_type) {
DCHECK_EQ(CONTENT_SETTINGS_TYPE_GEOLOCATION, content_type) <<
"SetDomains currently only supports geolocation content type";
- SetDomainsAndClearLink();
+ SetDomainsAndCustomLink();
}
private:
@@ -373,7 +388,7 @@ class ContentSettingDomainListBubbleModel
add_domain_list(domain_list);
}
}
- void SetDomainsAndClearLink() {
+ void SetDomainsAndCustomLink() {
TabSpecificContentSettings* content_settings =
tab_contents()->GetTabSpecificContentSettings();
const GeolocationSettingsState& settings =
@@ -390,21 +405,16 @@ class ContentSettingDomainListBubbleModel
IDS_GEOLOCATION_BUBBLE_SECTION_DENIED);
if (tab_state_flags & GeolocationSettingsState::TABSTATE_HAS_EXCEPTION) {
- set_clear_link(
- l10n_util::GetStringUTF8(IDS_GEOLOCATION_BUBBLE_CLEAR_LINK));
+ set_custom_link(l10n_util::GetStringUTF8(
+ IDS_GEOLOCATION_BUBBLE_CLEAR_LINK));
+ set_custom_link_enabled(true);
} else if (tab_state_flags &
GeolocationSettingsState::TABSTATE_HAS_CHANGED) {
- // It is a slight abuse of the domain list field to use it for the reload
- // hint, but works fine for now. TODO(joth): If we need to style it
- // differently, consider adding an explicit field, or generalize the
- // domain list to be a flat list of style formatted lines.
- DomainList reload_section;
- reload_section.title = l10n_util::GetStringUTF8(
- IDS_GEOLOCATION_BUBBLE_REQUIRE_RELOAD_TO_CLEAR);
- add_domain_list(reload_section);
+ set_custom_link(l10n_util::GetStringUTF8(
+ IDS_GEOLOCATION_BUBBLE_REQUIRE_RELOAD_TO_CLEAR));
}
}
- virtual void OnClearLinkClicked() {
+ virtual void OnCustomLinkClicked() OVERRIDE {
if (!tab_contents())
return;
// Reset this embedder's entry to default for each of the requesting
@@ -431,8 +441,8 @@ ContentSettingBubbleModel*
Profile* profile,
ContentSettingsType content_type) {
if (content_type == CONTENT_SETTINGS_TYPE_COOKIES) {
- return new ContentSettingTitleLinkAndInfoModel(tab_contents, profile,
- content_type);
+ return new ContentSettingCookiesBubbleModel(tab_contents, profile,
+ content_type);
}
if (content_type == CONTENT_SETTINGS_TYPE_POPUPS) {
return new ContentSettingPopupBubbleModel(tab_contents, profile,
@@ -451,17 +461,12 @@ ContentSettingBubbleModel*
}
ContentSettingBubbleModel::ContentSettingBubbleModel(
- TabContents* tab_contents, Profile* profile,
+ TabContents* tab_contents,
+ Profile* profile,
ContentSettingsType content_type)
- : tab_contents_(tab_contents), profile_(profile),
+ : tab_contents_(tab_contents),
+ profile_(profile),
content_type_(content_type) {
- if (tab_contents) {
- TabSpecificContentSettings* settings =
- tab_contents->GetTabSpecificContentSettings();
- set_load_plugins_link_enabled(settings->load_plugins_link_enabled());
- } else {
- set_load_plugins_link_enabled(true);
- }
registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
Source<TabContents>(tab_contents));
}
@@ -478,7 +483,7 @@ ContentSettingBubbleModel::DomainList::DomainList() {}
ContentSettingBubbleModel::DomainList::~DomainList() {}
ContentSettingBubbleModel::BubbleContent::BubbleContent()
- : load_plugins_link_enabled(false) {
+ : custom_link_enabled(false) {
}
ContentSettingBubbleModel::BubbleContent::~BubbleContent() {}
diff --git a/chrome/browser/content_setting_bubble_model.h b/chrome/browser/content_setting_bubble_model.h
index 49af1b2..f1b53c6 100644
--- a/chrome/browser/content_setting_bubble_model.h
+++ b/chrome/browser/content_setting_bubble_model.h
@@ -68,11 +68,9 @@ class ContentSettingBubbleModel : public NotificationObserver {
RadioGroup radio_group;
std::vector<DomainList> domain_lists;
std::set<std::string> resource_identifiers;
+ std::string custom_link;
+ bool custom_link_enabled;
std::string manage_link;
- std::string clear_link;
- std::string info_link;
- std::string load_plugins_link_title;
- bool load_plugins_link_enabled;
private:
DISALLOW_COPY_AND_ASSIGN(BubbleContent);
@@ -87,10 +85,8 @@ class ContentSettingBubbleModel : public NotificationObserver {
virtual void OnRadioClicked(int radio_index) {}
virtual void OnPopupClicked(int index) {}
+ virtual void OnCustomLinkClicked() {}
virtual void OnManageLinkClicked() {}
- virtual void OnClearLinkClicked() {}
- virtual void OnInfoLinkClicked() {}
- virtual void OnLoadPluginsLinkClicked() {}
protected:
ContentSettingBubbleModel(TabContents* tab_contents, Profile* profile,
@@ -109,20 +105,14 @@ class ContentSettingBubbleModel : public NotificationObserver {
void add_domain_list(const DomainList& domain_list) {
bubble_content_.domain_lists.push_back(domain_list);
}
- void set_manage_link(const std::string& link) {
- bubble_content_.manage_link = link;
- }
- void set_clear_link(const std::string& link) {
- bubble_content_.clear_link = link;
+ void set_custom_link(const std::string& link) {
+ bubble_content_.custom_link = link;
}
- void set_info_link(const std::string& link) {
- bubble_content_.info_link = link;
+ void set_custom_link_enabled(bool enabled) {
+ bubble_content_.custom_link_enabled = enabled;
}
- void set_load_plugins_link_title(const std::string& title) {
- bubble_content_.load_plugins_link_title = title;
- }
- void set_load_plugins_link_enabled(bool enabled) {
- bubble_content_.load_plugins_link_enabled = enabled;
+ void set_manage_link(const std::string& link) {
+ bubble_content_.manage_link = link;
}
void AddBlockedResource(const std::string& resource_identifier);
diff --git a/chrome/browser/content_setting_bubble_model_unittest.cc b/chrome/browser/content_setting_bubble_model_unittest.cc
index d9590e0..d2eebde 100644
--- a/chrome/browser/content_setting_bubble_model_unittest.cc
+++ b/chrome/browser/content_setting_bubble_model_unittest.cc
@@ -7,8 +7,8 @@
#include "base/auto_reset.h"
#include "base/command_line.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/host_content_settings_map.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
#include "chrome/browser/renderer_host/test/test_render_view_host.h"
#include "chrome/browser/tab_contents/test_tab_contents.h"
@@ -30,21 +30,14 @@ class ContentSettingBubbleModelTest : public RenderViewHostTestHarness {
contents(), profile_.get(), CONTENT_SETTINGS_TYPE_GEOLOCATION));
const ContentSettingBubbleModel::BubbleContent& bubble_content =
content_setting_bubble_model->bubble_content();
- EXPECT_EQ(0U, bubble_content.radio_group.radio_items.size());
- EXPECT_EQ(0U, bubble_content.popup_items.size());
- // The reload hint is currently implemented as a tacked on domain title, so
- // account for this.
- if (expect_reload_hint)
- ++expected_domains;
+ EXPECT_TRUE(bubble_content.title.empty());
+ EXPECT_TRUE(bubble_content.radio_group.radio_items.empty());
+ EXPECT_TRUE(bubble_content.popup_items.empty());
EXPECT_EQ(expected_domains, bubble_content.domain_lists.size());
- if (expect_clear_link)
- EXPECT_NE(std::string(), bubble_content.clear_link);
- else
- EXPECT_EQ(std::string(), bubble_content.clear_link);
- EXPECT_NE(std::string(), bubble_content.manage_link);
- EXPECT_EQ(std::string(), bubble_content.info_link);
- EXPECT_EQ(std::string(), bubble_content.title);
- EXPECT_EQ(std::string(), bubble_content.load_plugins_link_title);
+ EXPECT_NE(expect_clear_link || expect_reload_hint,
+ bubble_content.custom_link.empty());
+ EXPECT_EQ(expect_clear_link, bubble_content.custom_link_enabled);
+ EXPECT_FALSE(bubble_content.manage_link.empty());
}
BrowserThread ui_thread_;
@@ -61,12 +54,11 @@ TEST_F(ContentSettingBubbleModelTest, ImageRadios) {
contents(), profile_.get(), CONTENT_SETTINGS_TYPE_IMAGES));
const ContentSettingBubbleModel::BubbleContent& bubble_content =
content_setting_bubble_model->bubble_content();
+ EXPECT_FALSE(bubble_content.title.empty());
EXPECT_EQ(2U, bubble_content.radio_group.radio_items.size());
EXPECT_EQ(0, bubble_content.radio_group.default_item);
- EXPECT_NE(std::string(), bubble_content.manage_link);
- EXPECT_EQ(std::string(), bubble_content.info_link);
- EXPECT_NE(std::string(), bubble_content.title);
- EXPECT_EQ(std::string(), bubble_content.load_plugins_link_title);
+ EXPECT_TRUE(bubble_content.custom_link.empty());
+ EXPECT_FALSE(bubble_content.manage_link.empty());
}
TEST_F(ContentSettingBubbleModelTest, Cookies) {
@@ -80,11 +72,11 @@ TEST_F(ContentSettingBubbleModelTest, Cookies) {
contents(), profile_.get(), CONTENT_SETTINGS_TYPE_COOKIES));
const ContentSettingBubbleModel::BubbleContent& bubble_content =
content_setting_bubble_model->bubble_content();
- EXPECT_EQ(0U, bubble_content.radio_group.radio_items.size());
- EXPECT_NE(std::string(), bubble_content.manage_link);
- EXPECT_NE(std::string(), bubble_content.info_link);
- EXPECT_NE(std::string(), bubble_content.title);
- EXPECT_EQ(std::string(), bubble_content.load_plugins_link_title);
+ EXPECT_FALSE(bubble_content.title.empty());
+ EXPECT_TRUE(bubble_content.radio_group.radio_items.empty());
+ EXPECT_FALSE(bubble_content.custom_link.empty());
+ EXPECT_TRUE(bubble_content.custom_link_enabled);
+ EXPECT_FALSE(bubble_content.manage_link.empty());
}
TEST_F(ContentSettingBubbleModelTest, Plugins) {
@@ -98,11 +90,11 @@ TEST_F(ContentSettingBubbleModelTest, Plugins) {
contents(), profile_.get(), CONTENT_SETTINGS_TYPE_PLUGINS));
const ContentSettingBubbleModel::BubbleContent& bubble_content =
content_setting_bubble_model->bubble_content();
+ EXPECT_FALSE(bubble_content.title.empty());
EXPECT_EQ(2U, bubble_content.radio_group.radio_items.size());
- EXPECT_NE(std::string(), bubble_content.manage_link);
- EXPECT_EQ(std::string(), bubble_content.info_link);
- EXPECT_NE(std::string(), bubble_content.title);
- EXPECT_NE(std::string(), bubble_content.load_plugins_link_title);
+ EXPECT_FALSE(bubble_content.custom_link.empty());
+ EXPECT_TRUE(bubble_content.custom_link_enabled);
+ EXPECT_FALSE(bubble_content.manage_link.empty());
}
TEST_F(ContentSettingBubbleModelTest, MultiplePlugins) {
diff --git a/chrome/browser/content_setting_image_model.cc b/chrome/browser/content_setting_image_model.cc
index f392ec4..4aeea3a 100644
--- a/chrome/browser/content_setting_image_model.cc
+++ b/chrome/browser/content_setting_image_model.cc
@@ -6,8 +6,8 @@
#include "app/l10n_util.h"
#include "base/command_line.h"
-#include "chrome/browser/host_content_settings_map.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_switches.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/content_setting_image_model_unittest.cc b/chrome/browser/content_setting_image_model_unittest.cc
index f84f22d..fc7989d 100644
--- a/chrome/browser/content_setting_image_model_unittest.cc
+++ b/chrome/browser/content_setting_image_model_unittest.cc
@@ -5,8 +5,8 @@
#include "chrome/browser/content_setting_image_model.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/host_content_settings_map.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/test/test_render_view_host.h"
#include "chrome/browser/tab_contents/test_tab_contents.h"
#include "chrome/test/testing_profile.h"
@@ -59,7 +59,7 @@ TEST_F(ContentSettingImageModelTest, CookieAccessed) {
EXPECT_EQ(std::string(), content_setting_image_model->get_tooltip());
net::CookieOptions options;
- content_settings->OnCookieAccessed(
+ content_settings->OnCookieChanged(
GURL("http://google.com"), "A=B", options, false);
content_setting_image_model->UpdateFromTabContents(&tab_contents);
EXPECT_TRUE(content_setting_image_model->is_visible());
diff --git a/chrome/browser/content_settings/content_settings_details.h b/chrome/browser/content_settings/content_settings_details.h
new file mode 100644
index 0000000..51c5431
--- /dev/null
+++ b/chrome/browser/content_settings/content_settings_details.h
@@ -0,0 +1,56 @@
+// 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.
+
+// The details send with notifications about content setting changes.
+
+#ifndef CHROME_BROWSER_CONTENT_SETTINGS_CONTENT_SETTINGS_DETAILS_H_
+#define CHROME_BROWSER_CONTENT_SETTINGS_CONTENT_SETTINGS_DETAILS_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "chrome/browser/content_settings/content_settings_pattern.h"
+#include "chrome/common/content_settings.h"
+
+// Details for the CONTENT_SETTINGS_CHANGED notification. This is sent when
+// content settings change for at least one host. If settings change for more
+// than one pattern in one user interaction, this will usually send a single
+// notification with update_all() returning true instead of one notification
+// for each pattern.
+class ContentSettingsDetails {
+ public:
+ // Update the setting that matches this pattern/content type/resource.
+ ContentSettingsDetails(const ContentSettingsPattern& pattern,
+ ContentSettingsType type,
+ const std::string& resource_identifier)
+ : pattern_(pattern),
+ type_(type),
+ resource_identifier_(resource_identifier) {}
+
+ // The pattern whose settings have changed.
+ const ContentSettingsPattern& pattern() const { return pattern_; }
+
+ // True if all settings should be updated for the given type.
+ bool update_all() const { return pattern_.AsString().empty(); }
+
+ // The type of the pattern whose settings have changed.
+ ContentSettingsType type() const { return type_; }
+
+ // The resource identifier for the settings type that has changed.
+ const std::string& resource_identifier() const {
+ return resource_identifier_;
+ }
+
+ // True if all types should be updated. If update_all() is false, this will
+ // be false as well (although the reverse does not hold true).
+ bool update_all_types() const {
+ return CONTENT_SETTINGS_TYPE_DEFAULT == type_;
+ }
+
+ private:
+ ContentSettingsPattern pattern_;
+ ContentSettingsType type_;
+ std::string resource_identifier_;
+};
+
+#endif // CHROME_BROWSER_CONTENT_SETTINGS_CONTENT_SETTINGS_DETAILS_H_
diff --git a/chrome/browser/content_settings/content_settings_pattern.cc b/chrome/browser/content_settings/content_settings_pattern.cc
new file mode 100644
index 0000000..ba93ff4
--- /dev/null
+++ b/chrome/browser/content_settings/content_settings_pattern.cc
@@ -0,0 +1,87 @@
+// 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.
+
+#include "chrome/browser/content_settings/content_settings_pattern.h"
+
+#include "base/string_util.h"
+#include "net/base/net_util.h"
+#include "googleurl/src/gurl.h"
+#include "googleurl/src/url_canon.h"
+
+// The version of the pattern format implemented. Version 1 includes the
+// following patterns:
+// - [*.]domain.tld (matches domain.tld and all sub-domains)
+// - host (matches an exact hostname)
+// - a.b.c.d (matches an exact IPv4 ip)
+// - [a:b:c:d:e:f:g:h] (matches an exact IPv6 ip)
+// - file:///tmp/test.html (a complete URL without a host)
+// Version 2 adds a resource identifier for plugins.
+// TODO(jochen): update once this feature is no longer behind a flag.
+const int ContentSettingsPattern::kContentSettingsPatternVersion = 1;
+const char* ContentSettingsPattern::kDomainWildcard = "[*.]";
+const size_t ContentSettingsPattern::kDomainWildcardLength = 4;
+
+// static
+ContentSettingsPattern ContentSettingsPattern::FromURL(
+ const GURL& url) {
+ return ContentSettingsPattern(!url.has_host() || url.HostIsIPAddress() ?
+ net::GetHostOrSpecFromURL(url) :
+ std::string(kDomainWildcard) + url.host());
+}
+
+// static
+ContentSettingsPattern ContentSettingsPattern::FromURLNoWildcard(
+ const GURL& url) {
+ return ContentSettingsPattern(net::GetHostOrSpecFromURL(url));
+}
+
+bool ContentSettingsPattern::IsValid() const {
+ if (pattern_.empty())
+ return false;
+
+ const std::string host(pattern_.length() > kDomainWildcardLength &&
+ StartsWithASCII(pattern_, kDomainWildcard, false) ?
+ pattern_.substr(kDomainWildcardLength) :
+ pattern_);
+ url_canon::CanonHostInfo host_info;
+ return host.find('*') == std::string::npos &&
+ !net::CanonicalizeHost(host, &host_info).empty();
+}
+
+bool ContentSettingsPattern::Matches(const GURL& url) const {
+ if (!IsValid())
+ return false;
+
+ const std::string host(net::GetHostOrSpecFromURL(url));
+ if (pattern_.length() < kDomainWildcardLength ||
+ !StartsWithASCII(pattern_, kDomainWildcard, false))
+ return pattern_ == host;
+
+ const size_t match =
+ host.rfind(pattern_.substr(kDomainWildcardLength));
+
+ return (match != std::string::npos) &&
+ (match == 0 || host[match - 1] == '.') &&
+ (match + pattern_.length() - kDomainWildcardLength == host.length());
+}
+
+std::string ContentSettingsPattern::CanonicalizePattern() const {
+ if (!IsValid()) {
+ return "";
+ }
+
+ bool starts_with_wildcard = pattern_.length() > kDomainWildcardLength &&
+ StartsWithASCII(pattern_, kDomainWildcard, false);
+
+ const std::string host(starts_with_wildcard ?
+ pattern_.substr(kDomainWildcardLength) : pattern_);
+
+ std::string canonicalized_pattern =
+ starts_with_wildcard ? kDomainWildcard : "";
+
+ url_canon::CanonHostInfo host_info;
+ canonicalized_pattern += net::CanonicalizeHost(host, &host_info);
+
+ return canonicalized_pattern;
+}
diff --git a/chrome/browser/content_settings/content_settings_pattern.h b/chrome/browser/content_settings/content_settings_pattern.h
new file mode 100644
index 0000000..330042f
--- /dev/null
+++ b/chrome/browser/content_settings/content_settings_pattern.h
@@ -0,0 +1,72 @@
+// 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.
+
+// Patterns used in content setting rules.
+
+#ifndef CHROME_BROWSER_CONTENT_SETTINGS_CONTENT_SETTINGS_PATTERN_H_
+#define CHROME_BROWSER_CONTENT_SETTINGS_CONTENT_SETTINGS_PATTERN_H_
+#pragma once
+
+#include <string>
+
+class GURL;
+
+// A pattern used in content setting rules. See |IsValid| for a description of
+// possible patterns.
+class ContentSettingsPattern {
+ public:
+ // Returns a pattern that matches the host of this URL and all subdomains.
+ static ContentSettingsPattern FromURL(const GURL& url);
+
+ // Returns a pattern that matches exactly this URL.
+ static ContentSettingsPattern FromURLNoWildcard(const GURL& url);
+
+ ContentSettingsPattern() {}
+
+ explicit ContentSettingsPattern(const std::string& pattern)
+ : pattern_(pattern) {}
+
+ // True if this is a valid pattern. Valid patterns are
+ // - [*.]domain.tld (matches domain.tld and all sub-domains)
+ // - host (matches an exact hostname)
+ // - a.b.c.d (matches an exact IPv4 ip)
+ // - [a:b:c:d:e:f:g:h] (matches an exact IPv6 ip)
+ // TODO(jochen): should also return true for a complete URL without a host.
+ bool IsValid() const;
+
+ // True if |url| matches this pattern.
+ bool Matches(const GURL& url) const;
+
+ // Returns a std::string representation of this pattern.
+ const std::string& AsString() const { return pattern_; }
+
+ bool operator==(const ContentSettingsPattern& other) const {
+ return pattern_ == other.pattern_;
+ }
+
+ // Canonicalizes the pattern so that it's ASCII only, either
+ // in original (if it was already ASCII) or punycode form.
+ std::string CanonicalizePattern() const;
+
+ // The version of the pattern format implemented.
+ static const int kContentSettingsPatternVersion;
+
+ // The format of a domain wildcard.
+ static const char* kDomainWildcard;
+
+ // The length of kDomainWildcard (without the trailing '\0').
+ static const size_t kDomainWildcardLength;
+
+ private:
+ std::string pattern_;
+};
+
+// Stream operator so ContentSettingsPattern can be used in assertion
+// statements.
+inline std::ostream& operator<<(
+ std::ostream& out, const ContentSettingsPattern& pattern) {
+ return out << pattern.AsString();
+}
+
+#endif // CHROME_BROWSER_CONTENT_SETTINGS_CONTENT_SETTINGS_PATTERN_H_
diff --git a/chrome/browser/content_settings/content_settings_pattern_unittest.cc b/chrome/browser/content_settings/content_settings_pattern_unittest.cc
new file mode 100644
index 0000000..88b42dc
--- /dev/null
+++ b/chrome/browser/content_settings/content_settings_pattern_unittest.cc
@@ -0,0 +1,69 @@
+// 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.
+
+#include "chrome/browser/content_settings/content_settings_pattern.h"
+
+#include "googleurl/src/gurl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+TEST(ContentSettingsPatternTest, PatternSupport) {
+ EXPECT_TRUE(ContentSettingsPattern("[*.]example.com").IsValid());
+ EXPECT_TRUE(ContentSettingsPattern("example.com").IsValid());
+ EXPECT_TRUE(ContentSettingsPattern("192.168.0.1").IsValid());
+ EXPECT_TRUE(ContentSettingsPattern("[::1]").IsValid());
+ EXPECT_FALSE(ContentSettingsPattern("*example.com").IsValid());
+ EXPECT_FALSE(ContentSettingsPattern("example.*").IsValid());
+ EXPECT_FALSE(ContentSettingsPattern("http://example.com").IsValid());
+
+ EXPECT_TRUE(ContentSettingsPattern("[*.]example.com").Matches(
+ GURL("http://example.com/")));
+ EXPECT_TRUE(ContentSettingsPattern("[*.]example.com").Matches(
+ GURL("http://www.example.com/")));
+ EXPECT_TRUE(ContentSettingsPattern("www.example.com").Matches(
+ GURL("http://www.example.com/")));
+ EXPECT_FALSE(ContentSettingsPattern("").Matches(
+ GURL("http://www.example.com/")));
+ EXPECT_FALSE(ContentSettingsPattern("[*.]example.com").Matches(
+ GURL("http://example.org/")));
+ EXPECT_FALSE(ContentSettingsPattern("example.com").Matches(
+ GURL("http://example.org/")));
+}
+
+TEST(ContentSettingsPatternTest, CanonicalizePattern) {
+ // Basic patterns.
+ EXPECT_STREQ("[*.]ikea.com", ContentSettingsPattern("[*.]ikea.com")
+ .CanonicalizePattern().c_str());
+ EXPECT_STREQ("example.com", ContentSettingsPattern("example.com")
+ .CanonicalizePattern().c_str());
+ EXPECT_STREQ("192.168.1.1", ContentSettingsPattern("192.168.1.1")
+ .CanonicalizePattern().c_str());
+ EXPECT_STREQ("[::1]", ContentSettingsPattern("[::1]")
+ .CanonicalizePattern().c_str());
+ // IsValid returns false for file:/// patterns.
+ EXPECT_STREQ("", ContentSettingsPattern(
+ "file:///temp/file.html").CanonicalizePattern().c_str());
+
+ // UTF-8 patterns.
+ EXPECT_STREQ("[*.]xn--ira-ppa.com", ContentSettingsPattern(
+ "[*.]\xC4\x87ira.com").CanonicalizePattern().c_str());
+ EXPECT_STREQ("xn--ira-ppa.com", ContentSettingsPattern(
+ "\xC4\x87ira.com").CanonicalizePattern().c_str());
+ // IsValid returns false for file:/// patterns.
+ EXPECT_STREQ("", ContentSettingsPattern(
+ "file:///\xC4\x87ira.html").CanonicalizePattern().c_str());
+
+ // Invalid patterns.
+ EXPECT_STREQ("", ContentSettingsPattern(
+ "*example.com").CanonicalizePattern().c_str());
+ EXPECT_STREQ("", ContentSettingsPattern(
+ "example.*").CanonicalizePattern().c_str());
+ EXPECT_STREQ("", ContentSettingsPattern(
+ "*\xC4\x87ira.com").CanonicalizePattern().c_str());
+ EXPECT_STREQ("", ContentSettingsPattern(
+ "\xC4\x87ira.*").CanonicalizePattern().c_str());
+}
+
+} // namespace
diff --git a/chrome/browser/content_settings/content_settings_provider.h b/chrome/browser/content_settings/content_settings_provider.h
new file mode 100644
index 0000000..2754bfc
--- /dev/null
+++ b/chrome/browser/content_settings/content_settings_provider.h
@@ -0,0 +1,42 @@
+// 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.
+
+// Interface for objects providing content setting rules.
+
+#ifndef CHROME_BROWSER_CONTENT_SETTINGS_CONTENT_SETTINGS_PROVIDER_H_
+#define CHROME_BROWSER_CONTENT_SETTINGS_CONTENT_SETTINGS_PROVIDER_H_
+#pragma once
+
+#include "chrome/common/content_settings.h"
+
+class ContentSettingsProviderInterface {
+ public:
+ virtual ~ContentSettingsProviderInterface() {}
+
+ // True if this provider can provide a default setting for the |content_type|.
+ virtual bool CanProvideDefaultSetting(
+ ContentSettingsType content_type) const = 0;
+
+ // Returns the default content setting this provider has for the given
+ // |content_type|, or CONTENT_SETTING_DEFAULT if nothing be provided for this
+ // type.
+ virtual ContentSetting ProvideDefaultSetting(
+ ContentSettingsType content_type) const = 0;
+
+ // Notifies the provider that the host content settings map would like to
+ // update the default setting for the given |content_type|. The provider may
+ // ignore this.
+ virtual void UpdateDefaultSetting(ContentSettingsType content_type,
+ ContentSetting setting) = 0;
+
+ // Resets the state of the provider to the default.
+ virtual void ResetToDefaults() = 0;
+
+ // True if the default setting for the |content_type| is policy managed, i.e.,
+ // there shouldn't be any UI shown to modify this setting.
+ virtual bool DefaultSettingIsManaged(
+ ContentSettingsType content_type) const = 0;
+};
+
+#endif // CHROME_BROWSER_CONTENT_SETTINGS_CONTENT_SETTINGS_PROVIDER_H_
diff --git a/chrome/browser/content_settings/content_settings_provider_unittest.cc b/chrome/browser/content_settings/content_settings_provider_unittest.cc
new file mode 100644
index 0000000..bb625ef
--- /dev/null
+++ b/chrome/browser/content_settings/content_settings_provider_unittest.cc
@@ -0,0 +1,26 @@
+// 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.
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "chrome/browser/content_settings/mock_content_settings_provider.h"
+
+TEST(ContentSettingsProviderTest, Mock) {
+ MockContentSettingsProvider provider(CONTENT_SETTINGS_TYPE_COOKIES,
+ CONTENT_SETTING_ALLOW,
+ false,
+ true);
+ EXPECT_TRUE(provider.CanProvideDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES));
+ EXPECT_FALSE(provider.CanProvideDefaultSetting(CONTENT_SETTINGS_TYPE_POPUPS));
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ provider.ProvideDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES));
+ EXPECT_EQ(CONTENT_SETTING_DEFAULT,
+ provider.ProvideDefaultSetting(CONTENT_SETTINGS_TYPE_POPUPS));
+ EXPECT_FALSE(provider.DefaultSettingIsManaged(CONTENT_SETTINGS_TYPE_COOKIES));
+ EXPECT_FALSE(provider.DefaultSettingIsManaged(CONTENT_SETTINGS_TYPE_POPUPS));
+ provider.UpdateDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES,
+ CONTENT_SETTING_BLOCK);
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ provider.ProvideDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES));
+}
diff --git a/chrome/browser/content_settings/host_content_settings_map.cc b/chrome/browser/content_settings/host_content_settings_map.cc
new file mode 100644
index 0000000..7de7a80
--- /dev/null
+++ b/chrome/browser/content_settings/host_content_settings_map.cc
@@ -0,0 +1,977 @@
+// 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.
+
+#include "chrome/browser/content_settings/host_content_settings_map.h"
+
+#include "base/command_line.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/content_settings/content_settings_details.h"
+#include "chrome/browser/content_settings/policy_content_settings_provider.h"
+#include "chrome/browser/content_settings/pref_content_settings_provider.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/prefs/scoped_pref_update.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/net_util.h"
+#include "net/base/static_cookie_policy.h"
+
+namespace {
+
+// The preference keys where resource identifiers are stored for
+// ContentSettingsType values that support resource identifiers.
+const char* kResourceTypeNames[CONTENT_SETTINGS_NUM_TYPES] = {
+ NULL,
+ NULL,
+ NULL,
+ "per_plugin",
+ NULL,
+ NULL, // Not used for Geolocation
+ NULL, // Not used for Notifications
+};
+
+// The names of the ContentSettingsType values, for use with dictionary prefs.
+const char* kTypeNames[CONTENT_SETTINGS_NUM_TYPES] = {
+ "cookies",
+ "images",
+ "javascript",
+ "plugins",
+ "popups",
+ NULL, // Not used for Geolocation
+ NULL, // Not used for Notifications
+};
+
+// True if a given content settings type requires additional resource
+// identifiers.
+const bool kRequiresResourceIdentifier[CONTENT_SETTINGS_NUM_TYPES] = {
+ false, // CONTENT_SETTINGS_TYPE_COOKIES
+ false, // CONTENT_SETTINGS_TYPE_IMAGES
+ false, // CONTENT_SETTINGS_TYPE_JAVASCRIPT
+ true, // CONTENT_SETTINGS_TYPE_PLUGINS
+ false, // CONTENT_SETTINGS_TYPE_POPUPS
+ false, // Not used for Geolocation
+ false, // Not used for Notifications
+};
+
+// Returns true if we should allow all content types for this URL. This is
+// true for various internal objects like chrome:// URLs, so UI and other
+// things users think of as "not webpages" don't break.
+static bool ShouldAllowAllContent(const GURL& url) {
+ return url.SchemeIs(chrome::kChromeDevToolsScheme) ||
+ url.SchemeIs(chrome::kChromeInternalScheme) ||
+ url.SchemeIs(chrome::kChromeUIScheme) ||
+ url.SchemeIs(chrome::kExtensionScheme) ||
+ url.SchemeIs(chrome::kGearsScheme) ||
+ url.SchemeIs(chrome::kUserScriptScheme);
+}
+
+// Map ASK for the plugins content type to BLOCK if click-to-play is
+// not enabled.
+ContentSetting ClickToPlayFixup(ContentSettingsType content_type,
+ ContentSetting setting) {
+ if (setting == CONTENT_SETTING_ASK &&
+ content_type == CONTENT_SETTINGS_TYPE_PLUGINS &&
+ !CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableClickToPlay)) {
+ return CONTENT_SETTING_BLOCK;
+ }
+ return setting;
+}
+
+typedef std::vector<linked_ptr<ContentSettingsProviderInterface> >::iterator
+ provider_iterator;
+typedef
+ std::vector<linked_ptr<ContentSettingsProviderInterface> >::const_iterator
+ const_provider_iterator;
+
+} // namespace
+
+
+struct HostContentSettingsMap::ExtendedContentSettings {
+ ContentSettings content_settings;
+ ResourceContentSettings content_settings_for_resources;
+};
+
+HostContentSettingsMap::HostContentSettingsMap(Profile* profile)
+ : profile_(profile),
+ is_off_the_record_(profile_->IsOffTheRecord()),
+ updating_preferences_(false),
+ block_third_party_cookies_(false),
+ is_block_third_party_cookies_managed_(false) {
+ // The order in which the content settings providers are created is critical,
+ // as providers that are further down in the list (i.e. added later) override
+ // providers further up.
+ content_settings_providers_.push_back(
+ linked_ptr<ContentSettingsProviderInterface>(
+ new PrefContentSettingsProvider(profile)));
+ content_settings_providers_.push_back(
+ linked_ptr<ContentSettingsProviderInterface>(
+ new PolicyContentSettingsProvider(profile)));
+
+ PrefService* prefs = profile_->GetPrefs();
+
+ MigrateObsoleteCookiePref(prefs);
+
+ MigrateObsoletePopupsPref(prefs);
+
+ MigrateObsoletePerhostPref(prefs);
+
+ // Read misc. global settings.
+ block_third_party_cookies_ =
+ prefs->GetBoolean(prefs::kBlockThirdPartyCookies);
+ is_block_third_party_cookies_managed_ =
+ prefs->IsManagedPreference(prefs::kBlockThirdPartyCookies);
+ block_nonsandboxed_plugins_ =
+ prefs->GetBoolean(prefs::kBlockNonsandboxedPlugins);
+
+ // Verify preferences version.
+ if (!prefs->HasPrefPath(prefs::kContentSettingsVersion)) {
+ prefs->SetInteger(prefs::kContentSettingsVersion,
+ ContentSettingsPattern::kContentSettingsPatternVersion);
+ }
+ if (prefs->GetInteger(prefs::kContentSettingsVersion) >
+ ContentSettingsPattern::kContentSettingsPatternVersion) {
+ LOG(ERROR) << "Unknown content settings version in preferences.";
+ return;
+ }
+
+ // Read exceptions.
+ ReadExceptions(false);
+
+ pref_change_registrar_.Init(prefs);
+ pref_change_registrar_.Add(prefs::kContentSettingsPatterns, this);
+ pref_change_registrar_.Add(prefs::kBlockThirdPartyCookies, this);
+ pref_change_registrar_.Add(prefs::kBlockNonsandboxedPlugins, this);
+ notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED,
+ Source<Profile>(profile_));
+}
+
+// static
+void HostContentSettingsMap::RegisterUserPrefs(PrefService* prefs) {
+ prefs->RegisterIntegerPref(prefs::kContentSettingsVersion,
+ ContentSettingsPattern::kContentSettingsPatternVersion);
+ prefs->RegisterDictionaryPref(prefs::kContentSettingsPatterns);
+ prefs->RegisterBooleanPref(prefs::kBlockThirdPartyCookies, false);
+ prefs->RegisterBooleanPref(prefs::kBlockNonsandboxedPlugins, false);
+ prefs->RegisterIntegerPref(prefs::kContentSettingsWindowLastTabIndex, 0);
+
+ // Obsolete prefs, for migration:
+ prefs->RegisterIntegerPref(prefs::kCookieBehavior,
+ net::StaticCookiePolicy::ALLOW_ALL_COOKIES);
+ prefs->RegisterListPref(prefs::kPopupWhitelistedHosts);
+ prefs->RegisterDictionaryPref(prefs::kPerHostContentSettings);
+}
+
+ContentSetting HostContentSettingsMap::GetDefaultContentSetting(
+ ContentSettingsType content_type) const {
+ ContentSetting setting = CONTENT_SETTING_DEFAULT;
+ for (const_provider_iterator provider = content_settings_providers_.begin();
+ provider != content_settings_providers_.end(); ++provider) {
+ if (!(*provider)->CanProvideDefaultSetting(content_type))
+ continue;
+ ContentSetting provided_setting =
+ (*provider)->ProvideDefaultSetting(content_type);
+ if (provided_setting != CONTENT_SETTING_DEFAULT)
+ setting = provided_setting;
+ }
+ // The method GetDefaultContentSetting always has to return an explicit
+ // value that is to be used as default. We here rely on the
+ // PrefContentSettingProvider to always provide a value.
+ CHECK_NE(CONTENT_SETTING_DEFAULT, setting);
+ return setting;
+}
+
+ContentSetting HostContentSettingsMap::GetContentSetting(
+ const GURL& url,
+ ContentSettingsType content_type,
+ const std::string& resource_identifier) const {
+ ContentSetting setting = GetNonDefaultContentSetting(url,
+ content_type,
+ resource_identifier);
+ if (setting == CONTENT_SETTING_DEFAULT ||
+ IsDefaultContentSettingManaged(content_type)) {
+ return GetDefaultContentSetting(content_type);
+ }
+ return setting;
+}
+
+ContentSetting HostContentSettingsMap::GetNonDefaultContentSetting(
+ const GURL& url,
+ ContentSettingsType content_type,
+ const std::string& resource_identifier) const {
+ if (ShouldAllowAllContent(url))
+ return CONTENT_SETTING_ALLOW;
+
+ if (!RequiresResourceIdentifier(content_type))
+ return GetNonDefaultContentSettings(url).settings[content_type];
+
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableResourceContentSettings)) {
+ DCHECK(!resource_identifier.empty());
+ }
+
+ // Host content settings are ignored if the default_content_setting is
+ // managed.
+ if (IsDefaultContentSettingManaged(content_type)) {
+ return GetDefaultContentSetting(content_type);
+ }
+
+ AutoLock auto_lock(lock_);
+
+ const std::string host(net::GetHostOrSpecFromURL(url));
+ ContentSettingsTypeResourceIdentifierPair
+ requested_setting(content_type, resource_identifier);
+
+ // Check for exact matches first.
+ HostContentSettings::const_iterator i(host_content_settings_.find(host));
+ if (i != host_content_settings_.end() &&
+ i->second.content_settings_for_resources.find(requested_setting) !=
+ i->second.content_settings_for_resources.end()) {
+ return i->second.content_settings_for_resources.find(
+ requested_setting)->second;
+ }
+
+ // If this map is not for an off-the-record profile, these searches will never
+ // match. The additional off-the-record exceptions always overwrite the
+ // regular ones.
+ i = off_the_record_settings_.find(host);
+ if (i != off_the_record_settings_.end() &&
+ i->second.content_settings_for_resources.find(requested_setting) !=
+ i->second.content_settings_for_resources.end()) {
+ return i->second.content_settings_for_resources.find(
+ requested_setting)->second;
+ }
+
+ // Match patterns starting with the most concrete pattern match.
+ for (std::string key =
+ std::string(ContentSettingsPattern::kDomainWildcard) + host; ; ) {
+ HostContentSettings::const_iterator i(off_the_record_settings_.find(key));
+ if (i != off_the_record_settings_.end() &&
+ i->second.content_settings_for_resources.find(requested_setting) !=
+ i->second.content_settings_for_resources.end()) {
+ return i->second.content_settings_for_resources.find(
+ requested_setting)->second;
+ }
+
+ i = host_content_settings_.find(key);
+ if (i != host_content_settings_.end() &&
+ i->second.content_settings_for_resources.find(requested_setting) !=
+ i->second.content_settings_for_resources.end()) {
+ return i->second.content_settings_for_resources.find(
+ requested_setting)->second;
+ }
+
+ const size_t next_dot =
+ key.find('.', ContentSettingsPattern::kDomainWildcardLength);
+ if (next_dot == std::string::npos)
+ break;
+ key.erase(ContentSettingsPattern::kDomainWildcardLength,
+ next_dot - ContentSettingsPattern::kDomainWildcardLength + 1);
+ }
+
+ return CONTENT_SETTING_DEFAULT;
+}
+
+ContentSettings HostContentSettingsMap::GetContentSettings(
+ const GURL& url) const {
+ ContentSettings output = GetNonDefaultContentSettings(url);
+
+ // If we require a resource identifier, set the content settings to default,
+ // otherwise make the defaults explicit.
+ for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j) {
+ if (RequiresResourceIdentifier(ContentSettingsType(j))) {
+ output.settings[j] = CONTENT_SETTING_DEFAULT;
+ } else {
+ // A managed default content setting has the highest priority and hence
+ // will overwrite any previously set value.
+ if ((output.settings[j] == CONTENT_SETTING_DEFAULT) ||
+ IsDefaultContentSettingManaged(ContentSettingsType(j))) {
+ output.settings[j] = GetDefaultContentSetting(ContentSettingsType(j));
+ }
+ }
+ }
+ return output;
+}
+
+ContentSettings HostContentSettingsMap::GetNonDefaultContentSettings(
+ const GURL& url) const {
+ if (ShouldAllowAllContent(url))
+ return ContentSettings(CONTENT_SETTING_ALLOW);
+
+ AutoLock auto_lock(lock_);
+
+ const std::string host(net::GetHostOrSpecFromURL(url));
+ ContentSettings output;
+ for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j)
+ output.settings[j] = CONTENT_SETTING_DEFAULT;
+
+ // Check for exact matches first.
+ HostContentSettings::const_iterator i(host_content_settings_.find(host));
+ if (i != host_content_settings_.end())
+ output = i->second.content_settings;
+
+ // If this map is not for an off-the-record profile, these searches will never
+ // match. The additional off-the-record exceptions always overwrite the
+ // regular ones.
+ i = off_the_record_settings_.find(host);
+ if (i != off_the_record_settings_.end()) {
+ for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j)
+ if (i->second.content_settings.settings[j] != CONTENT_SETTING_DEFAULT)
+ output.settings[j] = i->second.content_settings.settings[j];
+ }
+
+ // Match patterns starting with the most concrete pattern match.
+ for (std::string key =
+ std::string(ContentSettingsPattern::kDomainWildcard) + host; ; ) {
+ HostContentSettings::const_iterator i(off_the_record_settings_.find(key));
+ if (i != off_the_record_settings_.end()) {
+ for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j) {
+ if (output.settings[j] == CONTENT_SETTING_DEFAULT)
+ output.settings[j] = i->second.content_settings.settings[j];
+ }
+ }
+ i = host_content_settings_.find(key);
+ if (i != host_content_settings_.end()) {
+ for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j) {
+ if (output.settings[j] == CONTENT_SETTING_DEFAULT)
+ output.settings[j] = i->second.content_settings.settings[j];
+ }
+ }
+ const size_t next_dot =
+ key.find('.', ContentSettingsPattern::kDomainWildcardLength);
+ if (next_dot == std::string::npos)
+ break;
+ key.erase(ContentSettingsPattern::kDomainWildcardLength,
+ next_dot - ContentSettingsPattern::kDomainWildcardLength + 1);
+ }
+
+ return output;
+}
+
+void HostContentSettingsMap::GetSettingsForOneType(
+ ContentSettingsType content_type,
+ const std::string& resource_identifier,
+ SettingsForOneType* settings) const {
+ DCHECK(RequiresResourceIdentifier(content_type) !=
+ resource_identifier.empty());
+ DCHECK(settings);
+ settings->clear();
+
+ const HostContentSettings* map_to_return =
+ is_off_the_record_ ? &off_the_record_settings_ : &host_content_settings_;
+ ContentSettingsTypeResourceIdentifierPair
+ requested_setting(content_type, resource_identifier);
+
+ AutoLock auto_lock(lock_);
+ for (HostContentSettings::const_iterator i(map_to_return->begin());
+ i != map_to_return->end(); ++i) {
+ ContentSetting setting;
+ if (RequiresResourceIdentifier(content_type)) {
+ if (i->second.content_settings_for_resources.find(requested_setting) !=
+ i->second.content_settings_for_resources.end())
+ setting = i->second.content_settings_for_resources.find(
+ requested_setting)->second;
+ else
+ setting = CONTENT_SETTING_DEFAULT;
+ } else {
+ setting = i->second.content_settings.settings[content_type];
+ }
+ if (setting != CONTENT_SETTING_DEFAULT) {
+ // Use of push_back() relies on the map iterator traversing in order of
+ // ascending keys.
+ settings->push_back(
+ std::make_pair(ContentSettingsPattern(i->first), setting));
+ }
+ }
+}
+
+void HostContentSettingsMap::SetDefaultContentSetting(
+ ContentSettingsType content_type,
+ ContentSetting setting) {
+ DCHECK(kTypeNames[content_type] != NULL); // Don't call this for Geolocation.
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(content_type != CONTENT_SETTINGS_TYPE_PLUGINS ||
+ setting != CONTENT_SETTING_ASK ||
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableClickToPlay));
+
+ // The default settings may not be directly modified for OTR sessions.
+ // Instead, they are synced to the main profile's setting.
+ if (is_off_the_record_) {
+ NOTREACHED();
+ return;
+ }
+
+ for (provider_iterator provider = content_settings_providers_.begin();
+ provider != content_settings_providers_.end(); ++provider) {
+ (*provider)->UpdateDefaultSetting(content_type, setting);
+ }
+}
+
+void HostContentSettingsMap::SetContentSetting(
+ const ContentSettingsPattern& original_pattern,
+ ContentSettingsType content_type,
+ const std::string& resource_identifier,
+ ContentSetting setting) {
+ DCHECK(kTypeNames[content_type] != NULL); // Don't call this for Geolocation.
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_NE(RequiresResourceIdentifier(content_type),
+ resource_identifier.empty());
+ DCHECK(content_type != CONTENT_SETTINGS_TYPE_PLUGINS ||
+ setting != CONTENT_SETTING_ASK ||
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableClickToPlay));
+
+ const ContentSettingsPattern pattern(original_pattern.CanonicalizePattern());
+
+ bool early_exit = false;
+ std::string pattern_str(pattern.AsString());
+ PrefService* prefs = NULL;
+ DictionaryValue* all_settings_dictionary = NULL;
+ HostContentSettings* map_to_modify = &off_the_record_settings_;
+ if (!is_off_the_record_) {
+ prefs = profile_->GetPrefs();
+ all_settings_dictionary =
+ prefs->GetMutableDictionary(prefs::kContentSettingsPatterns);
+ map_to_modify = &host_content_settings_;
+ }
+
+ {
+ AutoLock auto_lock(lock_);
+ if (!map_to_modify->count(pattern_str))
+ (*map_to_modify)[pattern_str].content_settings = ContentSettings();
+ HostContentSettings::iterator
+ i(map_to_modify->find(pattern_str));
+ ContentSettings& settings = i->second.content_settings;
+ if (RequiresResourceIdentifier(content_type)) {
+ settings.settings[content_type] = CONTENT_SETTING_DEFAULT;
+ if (setting != CONTENT_SETTING_DEFAULT) {
+ i->second.content_settings_for_resources[
+ ContentSettingsTypeResourceIdentifierPair(content_type,
+ resource_identifier)] = setting;
+ } else {
+ i->second.content_settings_for_resources.erase(
+ ContentSettingsTypeResourceIdentifierPair(content_type,
+ resource_identifier));
+ }
+ } else {
+ settings.settings[content_type] = setting;
+ }
+ if (AllDefault(i->second)) {
+ map_to_modify->erase(i);
+ if (all_settings_dictionary)
+ all_settings_dictionary->RemoveWithoutPathExpansion(pattern_str, NULL);
+
+ // We can't just return because |NotifyObservers()| needs to be called,
+ // without |lock_| being held.
+ early_exit = true;
+ }
+ }
+
+ if (!early_exit && all_settings_dictionary) {
+ DictionaryValue* host_settings_dictionary = NULL;
+ bool found = all_settings_dictionary->GetDictionaryWithoutPathExpansion(
+ pattern_str, &host_settings_dictionary);
+ if (!found) {
+ host_settings_dictionary = new DictionaryValue;
+ all_settings_dictionary->SetWithoutPathExpansion(
+ pattern_str, host_settings_dictionary);
+ DCHECK_NE(setting, CONTENT_SETTING_DEFAULT);
+ }
+ if (RequiresResourceIdentifier(content_type)) {
+ std::string dictionary_path(kResourceTypeNames[content_type]);
+ DictionaryValue* resource_dictionary = NULL;
+ found = host_settings_dictionary->GetDictionary(
+ dictionary_path, &resource_dictionary);
+ if (!found) {
+ resource_dictionary = new DictionaryValue;
+ host_settings_dictionary->Set(dictionary_path, resource_dictionary);
+ }
+ if (setting == CONTENT_SETTING_DEFAULT) {
+ resource_dictionary->RemoveWithoutPathExpansion(resource_identifier,
+ NULL);
+ } else {
+ resource_dictionary->SetWithoutPathExpansion(
+ resource_identifier, Value::CreateIntegerValue(setting));
+ }
+ } else {
+ std::string dictionary_path(kTypeNames[content_type]);
+ if (setting == CONTENT_SETTING_DEFAULT) {
+ host_settings_dictionary->RemoveWithoutPathExpansion(dictionary_path,
+ NULL);
+ } else {
+ host_settings_dictionary->SetWithoutPathExpansion(
+ dictionary_path, Value::CreateIntegerValue(setting));
+ }
+ }
+ }
+
+ updating_preferences_ = true;
+ if (!is_off_the_record_)
+ ScopedPrefUpdate update(prefs, prefs::kContentSettingsPatterns);
+ updating_preferences_ = false;
+
+ NotifyObservers(ContentSettingsDetails(pattern, content_type, ""));
+}
+
+void HostContentSettingsMap::AddExceptionForURL(
+ const GURL& url,
+ ContentSettingsType content_type,
+ const std::string& resource_identifier,
+ ContentSetting setting) {
+ // Make sure there is no entry that would override the pattern we are about
+ // to insert for exactly this URL.
+ SetContentSetting(ContentSettingsPattern::FromURLNoWildcard(url),
+ content_type,
+ resource_identifier,
+ CONTENT_SETTING_DEFAULT);
+ SetContentSetting(ContentSettingsPattern::FromURL(url),
+ content_type,
+ resource_identifier,
+ setting);
+}
+
+void HostContentSettingsMap::ClearSettingsForOneType(
+ ContentSettingsType content_type) {
+ DCHECK(kTypeNames[content_type] != NULL); // Don't call this for Geolocation.
+
+ PrefService* prefs = NULL;
+ DictionaryValue* all_settings_dictionary = NULL;
+ HostContentSettings* map_to_modify = &off_the_record_settings_;
+
+ if (!is_off_the_record_) {
+ prefs = profile_->GetPrefs();
+ all_settings_dictionary =
+ prefs->GetMutableDictionary(prefs::kContentSettingsPatterns);
+ map_to_modify = &host_content_settings_;
+ }
+
+ {
+ AutoLock auto_lock(lock_);
+ for (HostContentSettings::iterator i(map_to_modify->begin());
+ i != map_to_modify->end(); ) {
+ if (RequiresResourceIdentifier(content_type) ||
+ i->second.content_settings.settings[content_type] !=
+ CONTENT_SETTING_DEFAULT) {
+ if (RequiresResourceIdentifier(content_type))
+ i->second.content_settings_for_resources.clear();
+ i->second.content_settings.settings[content_type] =
+ CONTENT_SETTING_DEFAULT;
+ std::string host(i->first);
+ if (AllDefault(i->second)) {
+ if (all_settings_dictionary)
+ all_settings_dictionary->
+ RemoveWithoutPathExpansion(host, NULL);
+ map_to_modify->erase(i++);
+ } else if (all_settings_dictionary) {
+ DictionaryValue* host_settings_dictionary;
+ bool found =
+ all_settings_dictionary->GetDictionaryWithoutPathExpansion(
+ host, &host_settings_dictionary);
+ DCHECK(found);
+ host_settings_dictionary->RemoveWithoutPathExpansion(
+ kTypeNames[content_type], NULL);
+ ++i;
+ }
+ } else {
+ ++i;
+ }
+ }
+ }
+
+ updating_preferences_ = true;
+ if (!is_off_the_record_)
+ ScopedPrefUpdate update(prefs, prefs::kContentSettingsPatterns);
+ updating_preferences_ = false;
+
+ NotifyObservers(
+ ContentSettingsDetails(ContentSettingsPattern(), content_type, ""));
+}
+
+bool HostContentSettingsMap::RequiresResourceIdentifier(
+ ContentSettingsType content_type) const {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableResourceContentSettings)) {
+ return kRequiresResourceIdentifier[content_type];
+ } else {
+ return false;
+ }
+}
+
+void HostContentSettingsMap::SetBlockThirdPartyCookies(bool block) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // This setting may not be directly modified for OTR sessions. Instead, it
+ // is synced to the main profile's setting.
+ if (is_off_the_record_) {
+ NOTREACHED();
+ return;
+ }
+
+ PrefService* prefs = profile_->GetPrefs();
+ // If the preference block-third-party-cookies is managed then do not allow to
+ // change it.
+ if (prefs->IsManagedPreference(prefs::kBlockThirdPartyCookies)) {
+ NOTREACHED();
+ return;
+ }
+
+ {
+ AutoLock auto_lock(lock_);
+ block_third_party_cookies_ = block;
+ }
+
+ if (block)
+ prefs->SetBoolean(prefs::kBlockThirdPartyCookies, true);
+ else
+ prefs->ClearPref(prefs::kBlockThirdPartyCookies);
+}
+
+void HostContentSettingsMap::SetBlockNonsandboxedPlugins(bool block) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // This setting may not be directly modified for OTR sessions. Instead, it
+ // is synced to the main profile's setting.
+ if (is_off_the_record_) {
+ NOTREACHED();
+ return;
+ }
+
+ {
+ AutoLock auto_lock(lock_);
+ block_nonsandboxed_plugins_ = block;
+ }
+
+
+ PrefService* prefs = profile_->GetPrefs();
+ if (block) {
+ UserMetrics::RecordAction(
+ UserMetricsAction("BlockNonsandboxedPlugins_Enable"));
+ prefs->SetBoolean(prefs::kBlockNonsandboxedPlugins, true);
+ } else {
+ UserMetrics::RecordAction(
+ UserMetricsAction("BlockNonsandboxedPlugins_Disable"));
+ prefs->ClearPref(prefs::kBlockNonsandboxedPlugins);
+ }
+}
+
+void HostContentSettingsMap::ResetToDefaults() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ {
+ AutoLock auto_lock(lock_);
+ for (provider_iterator provider = content_settings_providers_.begin();
+ provider != content_settings_providers_.end(); ++provider) {
+ (*provider)->ResetToDefaults();
+ }
+ host_content_settings_.clear();
+ off_the_record_settings_.clear();
+ // Don't reset block third party cookies if they are managed.
+ if (!IsBlockThirdPartyCookiesManaged())
+ block_third_party_cookies_ = false;
+ block_nonsandboxed_plugins_ = false;
+ }
+
+ if (!is_off_the_record_) {
+ PrefService* prefs = profile_->GetPrefs();
+ updating_preferences_ = true;
+ prefs->ClearPref(prefs::kContentSettingsPatterns);
+ // If the block third party cookies preference is managed we still must
+ // clear it in order to restore the default value for later when the
+ // preference is not managed anymore.
+ prefs->ClearPref(prefs::kBlockThirdPartyCookies);
+ prefs->ClearPref(prefs::kBlockNonsandboxedPlugins);
+ updating_preferences_ = false;
+ NotifyObservers(ContentSettingsDetails(ContentSettingsPattern(),
+ CONTENT_SETTINGS_TYPE_DEFAULT,
+ ""));
+ }
+}
+
+void HostContentSettingsMap::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (type == NotificationType::PREF_CHANGED) {
+ DCHECK_EQ(profile_->GetPrefs(), Source<PrefService>(source).ptr());
+ if (updating_preferences_)
+ return;
+
+ std::string* name = Details<std::string>(details).ptr();
+ if (*name == prefs::kContentSettingsPatterns) {
+ ReadExceptions(true);
+ } else if (*name == prefs::kBlockThirdPartyCookies) {
+ AutoLock auto_lock(lock_);
+ block_third_party_cookies_ = profile_->GetPrefs()->GetBoolean(
+ prefs::kBlockThirdPartyCookies);
+ is_block_third_party_cookies_managed_ =
+ profile_->GetPrefs()->IsManagedPreference(
+ prefs::kBlockThirdPartyCookies);
+ } else if (*name == prefs::kBlockNonsandboxedPlugins) {
+ AutoLock auto_lock(lock_);
+ block_nonsandboxed_plugins_ = profile_->GetPrefs()->GetBoolean(
+ prefs::kBlockNonsandboxedPlugins);
+ } else {
+ NOTREACHED() << "Unexpected preference observed";
+ return;
+ }
+
+ if (!is_off_the_record_) {
+ NotifyObservers(ContentSettingsDetails(ContentSettingsPattern(),
+ CONTENT_SETTINGS_TYPE_DEFAULT,
+ ""));
+ }
+ } else if (type == NotificationType::PROFILE_DESTROYED) {
+ DCHECK_EQ(profile_, Source<Profile>(source).ptr());
+ UnregisterObservers();
+ } else {
+ NOTREACHED() << "Unexpected notification";
+ }
+}
+
+HostContentSettingsMap::~HostContentSettingsMap() {
+ UnregisterObservers();
+}
+
+void HostContentSettingsMap::GetSettingsFromDictionary(
+ const DictionaryValue* dictionary,
+ ContentSettings* settings) {
+ for (DictionaryValue::key_iterator i(dictionary->begin_keys());
+ i != dictionary->end_keys(); ++i) {
+ const std::string& content_type(*i);
+ for (size_t type = 0; type < arraysize(kTypeNames); ++type) {
+ if ((kTypeNames[type] != NULL) && (kTypeNames[type] == content_type)) {
+ int setting = CONTENT_SETTING_DEFAULT;
+ bool found = dictionary->GetIntegerWithoutPathExpansion(content_type,
+ &setting);
+ DCHECK(found);
+ settings->settings[type] = IntToContentSetting(setting);
+ break;
+ }
+ }
+ }
+ // Migrate obsolete cookie prompt mode.
+ if (settings->settings[CONTENT_SETTINGS_TYPE_COOKIES] ==
+ CONTENT_SETTING_ASK)
+ settings->settings[CONTENT_SETTINGS_TYPE_COOKIES] = CONTENT_SETTING_BLOCK;
+
+ settings->settings[CONTENT_SETTINGS_TYPE_PLUGINS] =
+ ClickToPlayFixup(CONTENT_SETTINGS_TYPE_PLUGINS,
+ settings->settings[CONTENT_SETTINGS_TYPE_PLUGINS]);
+}
+
+void HostContentSettingsMap::GetResourceSettingsFromDictionary(
+ const DictionaryValue* dictionary,
+ ResourceContentSettings* settings) {
+ for (DictionaryValue::key_iterator i(dictionary->begin_keys());
+ i != dictionary->end_keys(); ++i) {
+ const std::string& content_type(*i);
+ for (size_t type = 0; type < arraysize(kResourceTypeNames); ++type) {
+ if ((kResourceTypeNames[type] != NULL) &&
+ (kResourceTypeNames[type] == content_type)) {
+ DictionaryValue* resource_dictionary = NULL;
+ bool found = dictionary->GetDictionary(content_type,
+ &resource_dictionary);
+ DCHECK(found);
+ for (DictionaryValue::key_iterator j(resource_dictionary->begin_keys());
+ j != resource_dictionary->end_keys(); ++j) {
+ const std::string& resource_identifier(*j);
+ int setting = CONTENT_SETTING_DEFAULT;
+ bool found = resource_dictionary->GetIntegerWithoutPathExpansion(
+ resource_identifier, &setting);
+ DCHECK(found);
+ (*settings)[ContentSettingsTypeResourceIdentifierPair(
+ ContentSettingsType(type), resource_identifier)] =
+ ClickToPlayFixup(ContentSettingsType(type),
+ ContentSetting(setting));
+ }
+
+ break;
+ }
+ }
+ }
+}
+
+bool HostContentSettingsMap::AllDefault(
+ const ExtendedContentSettings& settings) const {
+ for (size_t i = 0; i < arraysize(settings.content_settings.settings); ++i) {
+ if (settings.content_settings.settings[i] != CONTENT_SETTING_DEFAULT)
+ return false;
+ }
+ return settings.content_settings_for_resources.empty();
+}
+
+bool HostContentSettingsMap::IsDefaultContentSettingManaged(
+ ContentSettingsType content_type) const {
+ for (const_provider_iterator provider = content_settings_providers_.begin();
+ provider != content_settings_providers_.end(); ++provider) {
+ if ((*provider)->DefaultSettingIsManaged(content_type))
+ return true;
+ }
+ return false;
+}
+
+void HostContentSettingsMap::ReadExceptions(bool overwrite) {
+ AutoLock lock(lock_);
+
+ PrefService* prefs = profile_->GetPrefs();
+ DictionaryValue* all_settings_dictionary =
+ prefs->GetMutableDictionary(prefs::kContentSettingsPatterns);
+
+ if (overwrite)
+ host_content_settings_.clear();
+
+ // Careful: The returned value could be NULL if the pref has never been set.
+ if (all_settings_dictionary != NULL) {
+ // Convert all Unicode patterns into punycode form, then read.
+ CanonicalizeContentSettingsExceptions(all_settings_dictionary);
+
+ for (DictionaryValue::key_iterator i(all_settings_dictionary->begin_keys());
+ i != all_settings_dictionary->end_keys(); ++i) {
+ const std::string& pattern(*i);
+ if (!ContentSettingsPattern(pattern).IsValid())
+ LOG(WARNING) << "Invalid pattern stored in content settings";
+ DictionaryValue* pattern_settings_dictionary = NULL;
+ bool found = all_settings_dictionary->GetDictionaryWithoutPathExpansion(
+ pattern, &pattern_settings_dictionary);
+ DCHECK(found);
+ ContentSettings settings;
+ GetSettingsFromDictionary(pattern_settings_dictionary, &settings);
+ host_content_settings_[pattern].content_settings = settings;
+ GetResourceSettingsFromDictionary(
+ pattern_settings_dictionary,
+ &host_content_settings_[pattern].content_settings_for_resources);
+ }
+ }
+}
+
+void HostContentSettingsMap::NotifyObservers(
+ const ContentSettingsDetails& details) {
+ NotificationService::current()->Notify(
+ NotificationType::CONTENT_SETTINGS_CHANGED,
+ Source<HostContentSettingsMap>(this),
+ Details<const ContentSettingsDetails>(&details));
+}
+
+void HostContentSettingsMap::UnregisterObservers() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!profile_)
+ return;
+ pref_change_registrar_.RemoveAll();
+ notification_registrar_.Remove(this, NotificationType::PROFILE_DESTROYED,
+ Source<Profile>(profile_));
+ profile_ = NULL;
+}
+
+void HostContentSettingsMap::MigrateObsoleteCookiePref(PrefService* prefs) {
+ if (prefs->HasPrefPath(prefs::kCookieBehavior)) {
+ int cookie_behavior = prefs->GetInteger(prefs::kCookieBehavior);
+ prefs->ClearPref(prefs::kCookieBehavior);
+ if (!prefs->HasPrefPath(prefs::kDefaultContentSettings)) {
+ SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_COOKIES,
+ (cookie_behavior == net::StaticCookiePolicy::BLOCK_ALL_COOKIES) ?
+ CONTENT_SETTING_BLOCK : CONTENT_SETTING_ALLOW);
+ }
+ if (!prefs->HasPrefPath(prefs::kBlockThirdPartyCookies)) {
+ SetBlockThirdPartyCookies(cookie_behavior ==
+ net::StaticCookiePolicy::BLOCK_THIRD_PARTY_COOKIES);
+ }
+ }
+}
+
+void HostContentSettingsMap::MigrateObsoletePopupsPref(PrefService* prefs) {
+ if (prefs->HasPrefPath(prefs::kPopupWhitelistedHosts)) {
+ const ListValue* whitelist_pref =
+ prefs->GetList(prefs::kPopupWhitelistedHosts);
+ for (ListValue::const_iterator i(whitelist_pref->begin());
+ i != whitelist_pref->end(); ++i) {
+ std::string host;
+ (*i)->GetAsString(&host);
+ SetContentSetting(ContentSettingsPattern(host),
+ CONTENT_SETTINGS_TYPE_POPUPS,
+ "",
+ CONTENT_SETTING_ALLOW);
+ }
+ prefs->ClearPref(prefs::kPopupWhitelistedHosts);
+ }
+}
+
+void HostContentSettingsMap::MigrateObsoletePerhostPref(PrefService* prefs) {
+ if (prefs->HasPrefPath(prefs::kPerHostContentSettings)) {
+ const DictionaryValue* all_settings_dictionary =
+ prefs->GetDictionary(prefs::kPerHostContentSettings);
+ for (DictionaryValue::key_iterator i(all_settings_dictionary->begin_keys());
+ i != all_settings_dictionary->end_keys(); ++i) {
+ const std::string& host(*i);
+ ContentSettingsPattern pattern(
+ std::string(ContentSettingsPattern::kDomainWildcard) + host);
+ DictionaryValue* host_settings_dictionary = NULL;
+ bool found = all_settings_dictionary->GetDictionaryWithoutPathExpansion(
+ host, &host_settings_dictionary);
+ DCHECK(found);
+ ContentSettings settings;
+ GetSettingsFromDictionary(host_settings_dictionary, &settings);
+ for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j) {
+ if (settings.settings[j] != CONTENT_SETTING_DEFAULT &&
+ !RequiresResourceIdentifier(ContentSettingsType(j)))
+ SetContentSetting(
+ pattern, ContentSettingsType(j), "", settings.settings[j]);
+ }
+ }
+ prefs->ClearPref(prefs::kPerHostContentSettings);
+ }
+}
+
+void HostContentSettingsMap::CanonicalizeContentSettingsExceptions(
+ DictionaryValue* all_settings_dictionary) {
+ DCHECK(all_settings_dictionary);
+
+ std::vector<std::string> remove_items;
+ std::vector<std::pair<std::string, std::string> > move_items;
+ for (DictionaryValue::key_iterator i(all_settings_dictionary->begin_keys());
+ i != all_settings_dictionary->end_keys(); ++i) {
+ const std::string& pattern(*i);
+ const std::string canonicalized_pattern =
+ ContentSettingsPattern(pattern).CanonicalizePattern();
+
+ if (canonicalized_pattern.empty() || canonicalized_pattern == pattern)
+ continue;
+
+ // Clear old pattern if prefs already have canonicalized pattern.
+ DictionaryValue* new_pattern_settings_dictionary = NULL;
+ if (all_settings_dictionary->GetDictionaryWithoutPathExpansion(
+ canonicalized_pattern, &new_pattern_settings_dictionary)) {
+ remove_items.push_back(pattern);
+ continue;
+ }
+
+ // Move old pattern to canonicalized pattern.
+ DictionaryValue* old_pattern_settings_dictionary = NULL;
+ if (all_settings_dictionary->GetDictionaryWithoutPathExpansion(
+ pattern, &old_pattern_settings_dictionary)) {
+ move_items.push_back(std::make_pair(pattern, canonicalized_pattern));
+ }
+ }
+
+ for (size_t i = 0; i < remove_items.size(); ++i) {
+ all_settings_dictionary->RemoveWithoutPathExpansion(remove_items[i], NULL);
+ }
+
+ for (size_t i = 0; i < move_items.size(); ++i) {
+ Value* pattern_settings_dictionary = NULL;
+ all_settings_dictionary->RemoveWithoutPathExpansion(
+ move_items[i].first, &pattern_settings_dictionary);
+ all_settings_dictionary->SetWithoutPathExpansion(
+ move_items[i].second, pattern_settings_dictionary);
+ }
+}
diff --git a/chrome/browser/content_settings/host_content_settings_map.h b/chrome/browser/content_settings/host_content_settings_map.h
new file mode 100644
index 0000000..915d974
--- /dev/null
+++ b/chrome/browser/content_settings/host_content_settings_map.h
@@ -0,0 +1,254 @@
+// 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.
+
+// Maps hostnames to custom content settings. Written on the UI thread and read
+// on any thread. One instance per profile.
+
+#ifndef CHROME_BROWSER_CONTENT_SETTINGS_HOST_CONTENT_SETTINGS_MAP_H_
+#define CHROME_BROWSER_CONTENT_SETTINGS_HOST_CONTENT_SETTINGS_MAP_H_
+#pragma once
+
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/linked_ptr.h"
+#include "base/lock.h"
+#include "base/ref_counted.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/content_settings/content_settings_pattern.h"
+#include "chrome/browser/prefs/pref_change_registrar.h"
+#include "chrome/common/content_settings.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+
+class ContentSettingsDetails;
+class ContentSettingsProviderInterface;
+class DictionaryValue;
+class GURL;
+class PrefService;
+class Profile;
+
+class HostContentSettingsMap
+ : public NotificationObserver,
+ public base::RefCountedThreadSafe<HostContentSettingsMap,
+ BrowserThread::DeleteOnUIThread> {
+ public:
+ typedef std::pair<ContentSettingsPattern, ContentSetting> PatternSettingPair;
+ typedef std::vector<PatternSettingPair> SettingsForOneType;
+
+ explicit HostContentSettingsMap(Profile* profile);
+ ~HostContentSettingsMap();
+
+ static void RegisterUserPrefs(PrefService* prefs);
+
+ // Returns the default setting for a particular content type.
+ //
+ // This may be called on any thread.
+ ContentSetting GetDefaultContentSetting(
+ ContentSettingsType content_type) const;
+
+ // Returns a single ContentSetting which applies to a given URL. Note that
+ // certain internal schemes are whitelisted. For ContentSettingsTypes that
+ // require an resource identifier to be specified, the |resource_identifier|
+ // must be non-empty.
+ //
+ // This may be called on any thread.
+ ContentSetting GetContentSetting(
+ const GURL& url,
+ ContentSettingsType content_type,
+ const std::string& resource_identifier) const;
+
+ // Returns a single ContentSetting which applies to a given URL or
+ // CONTENT_SETTING_DEFAULT, if no exception applies. Note that certain
+ // internal schemes are whitelisted. For ContentSettingsTypes that require an
+ // resource identifier to be specified, the |resource_identifier| must be
+ // non-empty.
+ //
+ // This may be called on any thread.
+ ContentSetting GetNonDefaultContentSetting(
+ const GURL& url,
+ ContentSettingsType content_type,
+ const std::string& resource_identifier) const;
+
+ // Returns all ContentSettings which apply to a given URL. For content
+ // setting types that require an additional resource identifier, the default
+ // content setting is returned.
+ //
+ // This may be called on any thread.
+ ContentSettings GetContentSettings(const GURL& url) const;
+
+ // Returns all non-default ContentSettings which apply to a given URL. For
+ // content setting types that require an additional resource identifier,
+ // CONTENT_SETTING_DEFAULT is returned.
+ //
+ // This may be called on any thread.
+ ContentSettings GetNonDefaultContentSettings(const GURL& url) const;
+
+ // For a given content type, returns all patterns with a non-default setting,
+ // mapped to their actual settings, in lexicographical order. |settings|
+ // must be a non-NULL outparam. If this map was created for the
+ // off-the-record profile, it will only return those settings differing from
+ // the main map. For ContentSettingsTypes that require an resource identifier
+ // to be specified, the |resource_identifier| must be non-empty.
+ //
+ // This may be called on any thread.
+ void GetSettingsForOneType(ContentSettingsType content_type,
+ const std::string& resource_identifier,
+ SettingsForOneType* settings) const;
+
+ // Sets the default setting for a particular content type. This method must
+ // not be invoked on an off-the-record map.
+ //
+ // This should only be called on the UI thread.
+ void SetDefaultContentSetting(ContentSettingsType content_type,
+ ContentSetting setting);
+
+ // Sets the blocking setting for a particular pattern and content type.
+ // Setting the value to CONTENT_SETTING_DEFAULT causes the default setting
+ // for that type to be used when loading pages matching this pattern. For
+ // ContentSettingsTypes that require an resource identifier to be specified,
+ // the |resource_identifier| must be non-empty.
+ //
+ // This should only be called on the UI thread.
+ void SetContentSetting(const ContentSettingsPattern& pattern,
+ ContentSettingsType content_type,
+ const std::string& resource_identifier,
+ ContentSetting setting);
+
+ // Convenience method to add a content setting for a given URL, making sure
+ // that there is no setting overriding it. For ContentSettingsTypes that
+ // require an resource identifier to be specified, the |resource_identifier|
+ // must be non-empty.
+ //
+ // This should only be called on the UI thread.
+ void AddExceptionForURL(const GURL& url,
+ ContentSettingsType content_type,
+ const std::string& resource_identifier,
+ ContentSetting setting);
+
+ // Clears all host-specific settings for one content type.
+ //
+ // This should only be called on the UI thread.
+ void ClearSettingsForOneType(ContentSettingsType content_type);
+
+ // Whether the |content_type| requires an additional resource identifier for
+ // accessing content settings.
+ bool RequiresResourceIdentifier(ContentSettingsType content_type) const;
+
+ // This setting trumps any host-specific settings.
+ bool BlockThirdPartyCookies() const { return block_third_party_cookies_; }
+ bool IsBlockThirdPartyCookiesManaged() const {
+ return is_block_third_party_cookies_managed_;
+ }
+
+ // Sets whether we block all third-party cookies. This method must not be
+ // invoked on an off-the-record map.
+ //
+ // This should only be called on the UI thread.
+ void SetBlockThirdPartyCookies(bool block);
+
+ bool GetBlockNonsandboxedPlugins() const {
+ return block_nonsandboxed_plugins_;
+ }
+
+ void SetBlockNonsandboxedPlugins(bool block);
+
+ // Resets all settings levels.
+ //
+ // This should only be called on the UI thread.
+ void ResetToDefaults();
+
+ // Returns true if the default setting for the |content_type| is managed.
+ bool IsDefaultContentSettingManaged(ContentSettingsType content_type) const;
+
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ private:
+ friend class base::RefCountedThreadSafe<HostContentSettingsMap>;
+
+ typedef std::pair<ContentSettingsType, std::string>
+ ContentSettingsTypeResourceIdentifierPair;
+ typedef std::map<ContentSettingsTypeResourceIdentifierPair, ContentSetting>
+ ResourceContentSettings;
+
+ struct ExtendedContentSettings;
+ typedef std::map<std::string, ExtendedContentSettings> HostContentSettings;
+
+ // Sets the fields of |settings| based on the values in |dictionary|.
+ void GetSettingsFromDictionary(const DictionaryValue* dictionary,
+ ContentSettings* settings);
+
+ // Populates |settings| based on the values in |dictionary|.
+ void GetResourceSettingsFromDictionary(const DictionaryValue* dictionary,
+ ResourceContentSettings* settings);
+
+ // Returns true if |settings| consists entirely of CONTENT_SETTING_DEFAULT.
+ bool AllDefault(const ExtendedContentSettings& settings) const;
+
+ // Reads the host exceptions from the prefereces service. If |overwrite| is
+ // true and the preference is missing, the local copy will be cleared as well.
+ void ReadExceptions(bool overwrite);
+
+ // Informs observers that content settings have changed. Make sure that
+ // |lock_| is not held when calling this, as listeners will usually call one
+ // of the GetSettings functions in response, which would then lead to a
+ // mutex deadlock.
+ void NotifyObservers(const ContentSettingsDetails& details);
+
+ void UnregisterObservers();
+
+ // Various migration methods (old cookie, popup and per-host data gets
+ // migrated to the new format).
+ void MigrateObsoleteCookiePref(PrefService* prefs);
+ void MigrateObsoletePopupsPref(PrefService* prefs);
+ void MigrateObsoletePerhostPref(PrefService* prefs);
+
+ // Converts all exceptions that have non-canonicalized pattern into
+ // canonicalized pattern. If such pattern already exists, we just remove the
+ // old exception.
+ void CanonicalizeContentSettingsExceptions(DictionaryValue* settings);
+
+ // The profile we're associated with.
+ Profile* profile_;
+
+ NotificationRegistrar notification_registrar_;
+ PrefChangeRegistrar pref_change_registrar_;
+
+ // Whether this settings map is for an OTR session.
+ bool is_off_the_record_;
+
+ // Whether we are currently updating preferences, this is used to ignore
+ // notifications from the preferences service that we triggered ourself.
+ bool updating_preferences_;
+
+ // Content setting providers.
+ std::vector<linked_ptr<ContentSettingsProviderInterface> >
+ content_settings_providers_;
+
+ // Used around accesses to the following objects to guarantee thread safety.
+ mutable Lock lock_;
+
+ // Copies of the pref data, so that we can read it on threads other than the
+ // UI thread.
+ HostContentSettings host_content_settings_;
+
+ // Differences to the preference-stored host content settings for
+ // off-the-record settings.
+ HostContentSettings off_the_record_settings_;
+
+ // Misc global settings.
+ bool block_third_party_cookies_;
+ bool is_block_third_party_cookies_managed_;
+ bool block_nonsandboxed_plugins_;
+
+ DISALLOW_COPY_AND_ASSIGN(HostContentSettingsMap);
+};
+
+#endif // CHROME_BROWSER_CONTENT_SETTINGS_HOST_CONTENT_SETTINGS_MAP_H_
diff --git a/chrome/browser/content_settings/host_content_settings_map_unittest.cc b/chrome/browser/content_settings/host_content_settings_map_unittest.cc
new file mode 100644
index 0000000..e7540e2
--- /dev/null
+++ b/chrome/browser/content_settings/host_content_settings_map_unittest.cc
@@ -0,0 +1,854 @@
+// 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.
+
+#include "chrome/browser/content_settings/host_content_settings_map_unittest.h"
+
+#include "base/auto_reset.h"
+#include "base/command_line.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "chrome/browser/content_settings/content_settings_details.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/test/testing_pref_service.h"
+#include "chrome/test/testing_profile.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/static_cookie_policy.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+
+namespace {
+
+bool SettingsEqual(const ContentSettings& settings1,
+ const ContentSettings& settings2) {
+ for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
+ if (settings1.settings[i] != settings2.settings[i])
+ return false;
+ }
+ return true;
+}
+
+class HostContentSettingsMapTest : public testing::Test {
+ public:
+ HostContentSettingsMapTest() : ui_thread_(BrowserThread::UI, &message_loop_) {
+ }
+
+ protected:
+ MessageLoop message_loop_;
+ BrowserThread ui_thread_;
+};
+
+TEST_F(HostContentSettingsMapTest, DefaultValues) {
+ TestingProfile profile;
+ HostContentSettingsMap* host_content_settings_map =
+ profile.GetHostContentSettingsMap();
+
+ // Check setting defaults.
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_JAVASCRIPT));
+ host_content_settings_map->SetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_IMAGES, CONTENT_SETTING_BLOCK);
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_IMAGES));
+ EXPECT_EQ(CONTENT_SETTING_ALLOW, host_content_settings_map->GetContentSetting(
+ GURL(chrome::kChromeUINewTabURL),
+ CONTENT_SETTINGS_TYPE_IMAGES, ""));
+ {
+ // Click-to-play needs to be enabled to set the content setting to ASK.
+ CommandLine* cmd = CommandLine::ForCurrentProcess();
+ AutoReset<CommandLine> auto_reset(cmd, *cmd);
+ cmd->AppendSwitch(switches::kEnableClickToPlay);
+
+ host_content_settings_map->SetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_PLUGINS, CONTENT_SETTING_ASK);
+ EXPECT_EQ(CONTENT_SETTING_ASK,
+ host_content_settings_map->GetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_PLUGINS));
+ }
+ host_content_settings_map->SetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_POPUPS, CONTENT_SETTING_ALLOW);
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_POPUPS));
+ host_content_settings_map->ResetToDefaults();
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_PLUGINS));
+
+ // Check returning individual settings.
+ GURL host("http://example.com/");
+ ContentSettingsPattern pattern("[*.]example.com");
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_IMAGES, ""));
+ host_content_settings_map->SetContentSetting(pattern,
+ CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_DEFAULT);
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_IMAGES, ""));
+ host_content_settings_map->SetContentSetting(pattern,
+ CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_IMAGES, ""));
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_PLUGINS, ""));
+
+ // Check returning all settings for a host.
+ ContentSettings desired_settings;
+ desired_settings.settings[CONTENT_SETTINGS_TYPE_COOKIES] =
+ CONTENT_SETTING_ALLOW;
+ host_content_settings_map->SetContentSetting(pattern,
+ CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_DEFAULT);
+ desired_settings.settings[CONTENT_SETTINGS_TYPE_IMAGES] =
+ CONTENT_SETTING_ALLOW;
+ host_content_settings_map->SetContentSetting(pattern,
+ CONTENT_SETTINGS_TYPE_JAVASCRIPT, "", CONTENT_SETTING_BLOCK);
+ desired_settings.settings[CONTENT_SETTINGS_TYPE_JAVASCRIPT] =
+ CONTENT_SETTING_BLOCK;
+ host_content_settings_map->SetContentSetting(pattern,
+ CONTENT_SETTINGS_TYPE_PLUGINS, "", CONTENT_SETTING_ALLOW);
+ desired_settings.settings[CONTENT_SETTINGS_TYPE_PLUGINS] =
+ CONTENT_SETTING_ALLOW;
+ desired_settings.settings[CONTENT_SETTINGS_TYPE_POPUPS] =
+ CONTENT_SETTING_BLOCK;
+ desired_settings.settings[CONTENT_SETTINGS_TYPE_GEOLOCATION] =
+ CONTENT_SETTING_ASK;
+ desired_settings.settings[CONTENT_SETTINGS_TYPE_NOTIFICATIONS] =
+ CONTENT_SETTING_ASK;
+ ContentSettings settings =
+ host_content_settings_map->GetContentSettings(host);
+ EXPECT_TRUE(SettingsEqual(desired_settings, settings));
+
+ // Check returning all hosts for a setting.
+ ContentSettingsPattern pattern2("[*.]example.org");
+ host_content_settings_map->SetContentSetting(pattern2,
+ CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
+ host_content_settings_map->SetContentSetting(pattern2,
+ CONTENT_SETTINGS_TYPE_PLUGINS, "", CONTENT_SETTING_BLOCK);
+ HostContentSettingsMap::SettingsForOneType host_settings;
+ host_content_settings_map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_IMAGES,
+ "",
+ &host_settings);
+ EXPECT_EQ(1U, host_settings.size());
+ host_content_settings_map->GetSettingsForOneType(
+ CONTENT_SETTINGS_TYPE_PLUGINS, "", &host_settings);
+ EXPECT_EQ(2U, host_settings.size());
+ host_content_settings_map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_POPUPS,
+ "",
+ &host_settings);
+ EXPECT_EQ(0U, host_settings.size());
+ host_content_settings_map->ResetToDefaults();
+ host_content_settings_map->GetSettingsForOneType(
+ CONTENT_SETTINGS_TYPE_PLUGINS, "", &host_settings);
+ EXPECT_EQ(0U, host_settings.size());
+
+ // Check clearing one type.
+ ContentSettingsPattern pattern3("[*.]example.net");
+ host_content_settings_map->SetContentSetting(pattern,
+ CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
+ host_content_settings_map->SetContentSetting(pattern2,
+ CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
+ host_content_settings_map->SetContentSetting(pattern2,
+ CONTENT_SETTINGS_TYPE_PLUGINS, "", CONTENT_SETTING_BLOCK);
+ host_content_settings_map->SetContentSetting(pattern3,
+ CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
+ host_content_settings_map->ClearSettingsForOneType(
+ CONTENT_SETTINGS_TYPE_IMAGES);
+ host_content_settings_map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_IMAGES,
+ "",
+ &host_settings);
+ EXPECT_EQ(0U, host_settings.size());
+ host_content_settings_map->GetSettingsForOneType(
+ CONTENT_SETTINGS_TYPE_PLUGINS, "", &host_settings);
+ EXPECT_EQ(1U, host_settings.size());
+}
+
+TEST_F(HostContentSettingsMapTest, Patterns) {
+ TestingProfile profile;
+ HostContentSettingsMap* host_content_settings_map =
+ profile.GetHostContentSettingsMap();
+
+ GURL host1("http://example.com/");
+ GURL host2("http://www.example.com/");
+ GURL host3("http://example.org/");
+ ContentSettingsPattern pattern1("[*.]example.com");
+ ContentSettingsPattern pattern2("example.org");
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetContentSetting(
+ host1, CONTENT_SETTINGS_TYPE_IMAGES, ""));
+ host_content_settings_map->SetContentSetting(pattern1,
+ CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetContentSetting(
+ host1, CONTENT_SETTINGS_TYPE_IMAGES, ""));
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetContentSetting(
+ host2, CONTENT_SETTINGS_TYPE_IMAGES, ""));
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetContentSetting(
+ host3, CONTENT_SETTINGS_TYPE_IMAGES, ""));
+ host_content_settings_map->SetContentSetting(pattern2,
+ CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetContentSetting(
+ host3, CONTENT_SETTINGS_TYPE_IMAGES, ""));
+}
+
+TEST_F(HostContentSettingsMapTest, Observer) {
+ TestingProfile profile;
+ HostContentSettingsMap* host_content_settings_map =
+ profile.GetHostContentSettingsMap();
+ StubSettingsObserver observer;
+
+ ContentSettingsPattern pattern("[*.]example.com");
+ host_content_settings_map->SetContentSetting(pattern,
+ CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_ALLOW);
+ EXPECT_EQ(host_content_settings_map, observer.last_notifier);
+ EXPECT_EQ(pattern, observer.last_pattern);
+ EXPECT_FALSE(observer.last_update_all);
+ EXPECT_FALSE(observer.last_update_all_types);
+ EXPECT_EQ(1, observer.counter);
+
+ host_content_settings_map->ClearSettingsForOneType(
+ CONTENT_SETTINGS_TYPE_IMAGES);
+ EXPECT_EQ(host_content_settings_map, observer.last_notifier);
+ EXPECT_TRUE(observer.last_update_all);
+ EXPECT_FALSE(observer.last_update_all_types);
+ EXPECT_EQ(2, observer.counter);
+
+ host_content_settings_map->ResetToDefaults();
+ EXPECT_EQ(host_content_settings_map, observer.last_notifier);
+ EXPECT_TRUE(observer.last_update_all);
+ EXPECT_TRUE(observer.last_update_all_types);
+ EXPECT_EQ(3, observer.counter);
+
+ host_content_settings_map->SetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_IMAGES, CONTENT_SETTING_BLOCK);
+ EXPECT_EQ(host_content_settings_map, observer.last_notifier);
+ EXPECT_TRUE(observer.last_update_all);
+ EXPECT_FALSE(observer.last_update_all_types);
+ EXPECT_EQ(4, observer.counter);
+}
+
+TEST_F(HostContentSettingsMapTest, ObserveDefaultPref) {
+ TestingProfile profile;
+ HostContentSettingsMap* host_content_settings_map =
+ profile.GetHostContentSettingsMap();
+
+ PrefService* prefs = profile.GetPrefs();
+
+ // Make a copy of the default pref value so we can reset it later.
+ scoped_ptr<Value> default_value(prefs->FindPreference(
+ prefs::kDefaultContentSettings)->GetValue()->DeepCopy());
+
+ GURL host("http://example.com");
+
+ host_content_settings_map->SetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_BLOCK);
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_COOKIES, ""));
+
+ // Make a copy of the pref's new value so we can reset it later.
+ scoped_ptr<Value> new_value(prefs->FindPreference(
+ prefs::kDefaultContentSettings)->GetValue()->DeepCopy());
+
+ // Clearing the backing pref should also clear the internal cache.
+ prefs->Set(prefs::kDefaultContentSettings, *default_value);
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_COOKIES, ""));
+
+ // Reseting the pref to its previous value should update the cache.
+ prefs->Set(prefs::kDefaultContentSettings, *new_value);
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_COOKIES, ""));
+}
+
+TEST_F(HostContentSettingsMapTest, ObserveExceptionPref) {
+ TestingProfile profile;
+ HostContentSettingsMap* host_content_settings_map =
+ profile.GetHostContentSettingsMap();
+
+ PrefService* prefs = profile.GetPrefs();
+
+ // Make a copy of the default pref value so we can reset it later.
+ scoped_ptr<Value> default_value(prefs->FindPreference(
+ prefs::kContentSettingsPatterns)->GetValue()->DeepCopy());
+
+ ContentSettingsPattern pattern("[*.]example.com");
+ GURL host("http://example.com");
+
+ host_content_settings_map->SetContentSetting(pattern,
+ CONTENT_SETTINGS_TYPE_COOKIES, "", CONTENT_SETTING_BLOCK);
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_COOKIES, ""));
+
+ // Make a copy of the pref's new value so we can reset it later.
+ scoped_ptr<Value> new_value(prefs->FindPreference(
+ prefs::kContentSettingsPatterns)->GetValue()->DeepCopy());
+
+ // Clearing the backing pref should also clear the internal cache.
+ prefs->Set(prefs::kContentSettingsPatterns, *default_value);
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_COOKIES, ""));
+
+ // Reseting the pref to its previous value should update the cache.
+ prefs->Set(prefs::kContentSettingsPatterns, *new_value);
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_COOKIES, ""));
+}
+
+TEST_F(HostContentSettingsMapTest, HostTrimEndingDotCheck) {
+ TestingProfile profile;
+ HostContentSettingsMap* host_content_settings_map =
+ profile.GetHostContentSettingsMap();
+
+ ContentSettingsPattern pattern("[*.]example.com");
+ GURL host_ending_with_dot("http://example.com./");
+
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetContentSetting(
+ host_ending_with_dot, CONTENT_SETTINGS_TYPE_IMAGES, ""));
+ host_content_settings_map->SetContentSetting(pattern,
+ CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_DEFAULT);
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetContentSetting(
+ host_ending_with_dot, CONTENT_SETTINGS_TYPE_IMAGES, ""));
+ host_content_settings_map->SetContentSetting(pattern,
+ CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetContentSetting(
+ host_ending_with_dot, CONTENT_SETTINGS_TYPE_IMAGES, ""));
+
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetContentSetting(
+ host_ending_with_dot, CONTENT_SETTINGS_TYPE_COOKIES, ""));
+ host_content_settings_map->SetContentSetting(pattern,
+ CONTENT_SETTINGS_TYPE_COOKIES, "", CONTENT_SETTING_DEFAULT);
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetContentSetting(
+ host_ending_with_dot, CONTENT_SETTINGS_TYPE_COOKIES, ""));
+ host_content_settings_map->SetContentSetting(pattern,
+ CONTENT_SETTINGS_TYPE_COOKIES, "", CONTENT_SETTING_BLOCK);
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetContentSetting(
+ host_ending_with_dot, CONTENT_SETTINGS_TYPE_COOKIES, ""));
+
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetContentSetting(
+ host_ending_with_dot, CONTENT_SETTINGS_TYPE_JAVASCRIPT, ""));
+ host_content_settings_map->SetContentSetting(pattern,
+ CONTENT_SETTINGS_TYPE_JAVASCRIPT, "", CONTENT_SETTING_DEFAULT);
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetContentSetting(
+ host_ending_with_dot, CONTENT_SETTINGS_TYPE_JAVASCRIPT, ""));
+ host_content_settings_map->SetContentSetting(pattern,
+ CONTENT_SETTINGS_TYPE_JAVASCRIPT, "", CONTENT_SETTING_BLOCK);
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetContentSetting(
+ host_ending_with_dot, CONTENT_SETTINGS_TYPE_JAVASCRIPT, ""));
+
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetContentSetting(
+ host_ending_with_dot, CONTENT_SETTINGS_TYPE_PLUGINS, ""));
+ host_content_settings_map->SetContentSetting(pattern,
+ CONTENT_SETTINGS_TYPE_PLUGINS, "", CONTENT_SETTING_DEFAULT);
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetContentSetting(
+ host_ending_with_dot, CONTENT_SETTINGS_TYPE_PLUGINS, ""));
+ host_content_settings_map->SetContentSetting(pattern,
+ CONTENT_SETTINGS_TYPE_PLUGINS, "", CONTENT_SETTING_BLOCK);
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetContentSetting(
+ host_ending_with_dot, CONTENT_SETTINGS_TYPE_PLUGINS, ""));
+
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetContentSetting(
+ host_ending_with_dot, CONTENT_SETTINGS_TYPE_POPUPS, ""));
+ host_content_settings_map->SetContentSetting(pattern,
+ CONTENT_SETTINGS_TYPE_POPUPS, "", CONTENT_SETTING_DEFAULT);
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetContentSetting(
+ host_ending_with_dot, CONTENT_SETTINGS_TYPE_POPUPS, ""));
+ host_content_settings_map->SetContentSetting(pattern,
+ CONTENT_SETTINGS_TYPE_POPUPS, "", CONTENT_SETTING_ALLOW);
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetContentSetting(
+ host_ending_with_dot, CONTENT_SETTINGS_TYPE_POPUPS, ""));
+}
+
+TEST_F(HostContentSettingsMapTest, NestedSettings) {
+ TestingProfile profile;
+ HostContentSettingsMap* host_content_settings_map =
+ profile.GetHostContentSettingsMap();
+
+ GURL host("http://a.b.example.com/");
+ ContentSettingsPattern pattern1("[*.]example.com");
+ ContentSettingsPattern pattern2("[*.]b.example.com");
+ ContentSettingsPattern pattern3("a.b.example.com");
+
+ host_content_settings_map->SetContentSetting(pattern1,
+ CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
+ host_content_settings_map->SetContentSetting(pattern2,
+ CONTENT_SETTINGS_TYPE_COOKIES, "", CONTENT_SETTING_BLOCK);
+ host_content_settings_map->SetContentSetting(pattern3,
+ CONTENT_SETTINGS_TYPE_PLUGINS, "", CONTENT_SETTING_BLOCK);
+ host_content_settings_map->SetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_JAVASCRIPT, CONTENT_SETTING_BLOCK);
+
+ ContentSettings desired_settings;
+ desired_settings.settings[CONTENT_SETTINGS_TYPE_COOKIES] =
+ CONTENT_SETTING_BLOCK;
+ desired_settings.settings[CONTENT_SETTINGS_TYPE_IMAGES] =
+ CONTENT_SETTING_BLOCK;
+ desired_settings.settings[CONTENT_SETTINGS_TYPE_JAVASCRIPT] =
+ CONTENT_SETTING_BLOCK;
+ desired_settings.settings[CONTENT_SETTINGS_TYPE_PLUGINS] =
+ CONTENT_SETTING_BLOCK;
+ desired_settings.settings[CONTENT_SETTINGS_TYPE_POPUPS] =
+ CONTENT_SETTING_BLOCK;
+ desired_settings.settings[CONTENT_SETTINGS_TYPE_GEOLOCATION] =
+ CONTENT_SETTING_ASK;
+ desired_settings.settings[CONTENT_SETTINGS_TYPE_NOTIFICATIONS] =
+ CONTENT_SETTING_ASK;
+ ContentSettings settings =
+ host_content_settings_map->GetContentSettings(host);
+ EXPECT_TRUE(SettingsEqual(desired_settings, settings));
+ EXPECT_EQ(desired_settings.settings[CONTENT_SETTINGS_TYPE_COOKIES],
+ settings.settings[CONTENT_SETTINGS_TYPE_COOKIES]);
+ EXPECT_EQ(desired_settings.settings[CONTENT_SETTINGS_TYPE_IMAGES],
+ settings.settings[CONTENT_SETTINGS_TYPE_IMAGES]);
+ EXPECT_EQ(desired_settings.settings[CONTENT_SETTINGS_TYPE_PLUGINS],
+ settings.settings[CONTENT_SETTINGS_TYPE_PLUGINS]);
+ EXPECT_EQ(desired_settings.settings[CONTENT_SETTINGS_TYPE_POPUPS],
+ settings.settings[CONTENT_SETTINGS_TYPE_POPUPS]);
+ EXPECT_EQ(desired_settings.settings[CONTENT_SETTINGS_TYPE_GEOLOCATION],
+ settings.settings[CONTENT_SETTINGS_TYPE_GEOLOCATION]);
+ EXPECT_EQ(desired_settings.settings[CONTENT_SETTINGS_TYPE_COOKIES],
+ settings.settings[CONTENT_SETTINGS_TYPE_COOKIES]);
+}
+
+TEST_F(HostContentSettingsMapTest, OffTheRecord) {
+ TestingProfile profile;
+ HostContentSettingsMap* host_content_settings_map =
+ profile.GetHostContentSettingsMap();
+ profile.set_off_the_record(true);
+ scoped_refptr<HostContentSettingsMap> otr_map(
+ new HostContentSettingsMap(&profile));
+ profile.set_off_the_record(false);
+
+ GURL host("http://example.com/");
+ ContentSettingsPattern pattern("[*.]example.com");
+
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_IMAGES, ""));
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ otr_map->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_IMAGES, ""));
+
+ // Changing content settings on the main map should also affect the
+ // off-the-record map.
+ host_content_settings_map->SetContentSetting(pattern,
+ CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_IMAGES, ""));
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ otr_map->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_IMAGES, ""));
+
+ // Changing content settings on the off-the-record map should NOT affect the
+ // main map.
+ otr_map->SetContentSetting(pattern,
+ CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_ALLOW);
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_IMAGES, ""));
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ otr_map->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_IMAGES, ""));
+}
+
+TEST_F(HostContentSettingsMapTest, MigrateObsoletePrefs) {
+ // This feature is currently behind a flag.
+ CommandLine* cmd = CommandLine::ForCurrentProcess();
+ AutoReset<CommandLine> auto_reset(cmd, *cmd);
+ cmd->AppendSwitch(switches::kEnableResourceContentSettings);
+
+ TestingProfile profile;
+ PrefService* prefs = profile.GetPrefs();
+
+ // Set obsolete data.
+ prefs->SetInteger(prefs::kCookieBehavior,
+ net::StaticCookiePolicy::BLOCK_ALL_COOKIES);
+
+ ListValue popup_hosts;
+ popup_hosts.Append(new StringValue("[*.]example.com"));
+ prefs->Set(prefs::kPopupWhitelistedHosts, popup_hosts);
+
+ HostContentSettingsMap* host_content_settings_map =
+ profile.GetHostContentSettingsMap();
+
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_COOKIES));
+
+ GURL host("http://example.com");
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_POPUPS, ""));
+}
+
+// For a single Unicode encoded pattern, check if it gets converted to punycode
+// and old pattern gets deleted.
+TEST_F(HostContentSettingsMapTest, CanonicalizeExceptionsUnicodeOnly) {
+ TestingProfile profile;
+ PrefService* prefs = profile.GetPrefs();
+
+ // Set utf-8 data.
+ DictionaryValue* all_settings_dictionary =
+ prefs->GetMutableDictionary(prefs::kContentSettingsPatterns);
+ ASSERT_TRUE(NULL != all_settings_dictionary);
+
+ DictionaryValue* dummy_payload = new DictionaryValue;
+ dummy_payload->SetInteger("images", CONTENT_SETTING_ALLOW);
+ all_settings_dictionary->SetWithoutPathExpansion("[*.]\xC4\x87ira.com",
+ dummy_payload);
+
+ profile.GetHostContentSettingsMap();
+
+ DictionaryValue* result = NULL;
+ EXPECT_FALSE(all_settings_dictionary->GetDictionaryWithoutPathExpansion(
+ "[*.]\xC4\x87ira.com", &result));
+ EXPECT_TRUE(all_settings_dictionary->GetDictionaryWithoutPathExpansion(
+ "[*.]xn--ira-ppa.com", &result));
+}
+
+// If both Unicode and its punycode pattern exist, make sure we don't touch the
+// settings for the punycode, and that Unicode pattern gets deleted.
+TEST_F(HostContentSettingsMapTest, CanonicalizeExceptionsUnicodeAndPunycode) {
+ // This feature is currently behind a flag.
+ CommandLine* cmd = CommandLine::ForCurrentProcess();
+ AutoReset<CommandLine> auto_reset(cmd, *cmd);
+ cmd->AppendSwitch(switches::kEnableResourceContentSettings);
+
+ TestingProfile profile;
+
+ scoped_ptr<Value> value(base::JSONReader::Read(
+ "{\"[*.]\\xC4\\x87ira.com\":{\"per_plugin\":{\"pluginx\":2}}}", false));
+ profile.GetPrefs()->Set(prefs::kContentSettingsPatterns, *value);
+
+ // Set punycode equivalent, with different setting.
+ scoped_ptr<Value> puny_value(base::JSONReader::Read(
+ "{\"[*.]xn--ira-ppa.com\":{\"per_plugin\":{\"pluginy\":2}}}", false));
+ profile.GetPrefs()->Set(prefs::kContentSettingsPatterns, *puny_value);
+
+ // Initialize the content map.
+ profile.GetHostContentSettingsMap();
+
+ const DictionaryValue* content_setting_prefs =
+ profile.GetPrefs()->GetDictionary(prefs::kContentSettingsPatterns);
+ std::string prefs_as_json;
+ base::JSONWriter::Write(content_setting_prefs, false, &prefs_as_json);
+ EXPECT_STREQ("{\"[*.]xn--ira-ppa.com\":{\"per_plugin\":{\"pluginy\":2}}}",
+ prefs_as_json.c_str());
+}
+
+TEST_F(HostContentSettingsMapTest, NonDefaultSettings) {
+ TestingProfile profile;
+ HostContentSettingsMap* host_content_settings_map =
+ profile.GetHostContentSettingsMap();
+
+ GURL host("http://example.com/");
+ ContentSettingsPattern pattern("[*.]example.com");
+
+ ContentSettings desired_settings(CONTENT_SETTING_DEFAULT);
+ ContentSettings settings =
+ host_content_settings_map->GetNonDefaultContentSettings(host);
+ EXPECT_TRUE(SettingsEqual(desired_settings, settings));
+
+ host_content_settings_map->SetContentSetting(pattern,
+ CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
+ desired_settings.settings[CONTENT_SETTINGS_TYPE_IMAGES] =
+ CONTENT_SETTING_BLOCK;
+ settings =
+ host_content_settings_map->GetNonDefaultContentSettings(host);
+ EXPECT_TRUE(SettingsEqual(desired_settings, settings));
+}
+
+TEST_F(HostContentSettingsMapTest, ResourceIdentifier) {
+ // This feature is currently behind a flag.
+ CommandLine* cmd = CommandLine::ForCurrentProcess();
+ AutoReset<CommandLine> auto_reset(cmd, *cmd);
+ cmd->AppendSwitch(switches::kEnableResourceContentSettings);
+
+ TestingProfile profile;
+ HostContentSettingsMap* host_content_settings_map =
+ profile.GetHostContentSettingsMap();
+
+ GURL host("http://example.com/");
+ ContentSettingsPattern pattern("[*.]example.com");
+ std::string resource1("someplugin");
+ std::string resource2("otherplugin");
+
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_PLUGINS, resource1));
+ host_content_settings_map->SetContentSetting(pattern,
+ CONTENT_SETTINGS_TYPE_PLUGINS, resource1, CONTENT_SETTING_BLOCK);
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_PLUGINS, resource1));
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_PLUGINS, resource2));
+}
+
+TEST_F(HostContentSettingsMapTest, ResourceIdentifierPrefs) {
+ // This feature is currently behind a flag.
+ CommandLine* cmd = CommandLine::ForCurrentProcess();
+ AutoReset<CommandLine> auto_reset(cmd, *cmd);
+ cmd->AppendSwitch(switches::kEnableResourceContentSettings);
+
+ TestingProfile profile;
+ scoped_ptr<Value> value(base::JSONReader::Read(
+ "{\"[*.]example.com\":{\"per_plugin\":{\"someplugin\":2}}}", false));
+ profile.GetPrefs()->Set(prefs::kContentSettingsPatterns, *value);
+ HostContentSettingsMap* host_content_settings_map =
+ profile.GetHostContentSettingsMap();
+
+ GURL host("http://example.com/");
+ ContentSettingsPattern pattern("[*.]example.com");
+ std::string resource1("someplugin");
+ std::string resource2("otherplugin");
+
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_PLUGINS, resource1));
+
+ host_content_settings_map->SetContentSetting(pattern,
+ CONTENT_SETTINGS_TYPE_PLUGINS, resource1, CONTENT_SETTING_DEFAULT);
+
+ const DictionaryValue* content_setting_prefs =
+ profile.GetPrefs()->GetDictionary(prefs::kContentSettingsPatterns);
+ std::string prefs_as_json;
+ base::JSONWriter::Write(content_setting_prefs, false, &prefs_as_json);
+ EXPECT_STREQ("{}", prefs_as_json.c_str());
+
+ host_content_settings_map->SetContentSetting(pattern,
+ CONTENT_SETTINGS_TYPE_PLUGINS, resource2, CONTENT_SETTING_BLOCK);
+
+ content_setting_prefs =
+ profile.GetPrefs()->GetDictionary(prefs::kContentSettingsPatterns);
+ base::JSONWriter::Write(content_setting_prefs, false, &prefs_as_json);
+ EXPECT_STREQ("{\"[*.]example.com\":{\"per_plugin\":{\"otherplugin\":2}}}",
+ prefs_as_json.c_str());
+}
+
+// If a default-content-setting is managed, the managed value should be used
+// instead of the default value.
+TEST_F(HostContentSettingsMapTest, ManagedDefaultContentSetting) {
+ TestingProfile profile;
+ HostContentSettingsMap* host_content_settings_map =
+ profile.GetHostContentSettingsMap();
+ TestingPrefService* prefs = profile.GetTestingPrefService();
+
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_JAVASCRIPT));
+
+ // Set managed-default-content-setting through the coresponding preferences.
+ prefs->SetManagedPref(prefs::kManagedDefaultJavaScriptSetting,
+ Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_JAVASCRIPT));
+
+ // Remove managed-default-content-settings-preferences.
+ prefs->RemoveManagedPref(prefs::kManagedDefaultJavaScriptSetting);
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_JAVASCRIPT));
+
+ // Set preference to manage the default-content-setting for Plugins.
+ prefs->SetManagedPref(prefs::kManagedDefaultPluginsSetting,
+ Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_PLUGINS));
+
+ // Remove the preference to manage the default-content-setting for Plugins.
+ prefs->RemoveManagedPref(prefs::kManagedDefaultPluginsSetting);
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_PLUGINS));
+}
+
+TEST_F(HostContentSettingsMapTest,
+ GetNonDefaultContentSettingsIfTypeManaged) {
+ TestingProfile profile;
+ HostContentSettingsMap* host_content_settings_map =
+ profile.GetHostContentSettingsMap();
+ TestingPrefService* prefs = profile.GetTestingPrefService();
+
+ // Set pattern for JavaScript setting.
+ ContentSettingsPattern pattern("[*.]example.com");
+ host_content_settings_map->SetContentSetting(pattern,
+ CONTENT_SETTINGS_TYPE_JAVASCRIPT, "", CONTENT_SETTING_BLOCK);
+
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_JAVASCRIPT));
+
+ GURL host("http://example.com/");
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_JAVASCRIPT, ""));
+
+ // Set managed-default-content-setting for content-settings-type JavaScript.
+ prefs->SetManagedPref(prefs::kManagedDefaultJavaScriptSetting,
+ Value::CreateIntegerValue(CONTENT_SETTING_ALLOW));
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_JAVASCRIPT, ""));
+}
+
+// Managed default content setting should have higher priority
+// than user defined patterns.
+TEST_F(HostContentSettingsMapTest,
+ ManagedDefaultContentSettingIgnoreUserPattern) {
+ TestingProfile profile;
+ HostContentSettingsMap* host_content_settings_map =
+ profile.GetHostContentSettingsMap();
+ TestingPrefService* prefs = profile.GetTestingPrefService();
+
+ // Block all JavaScript.
+ host_content_settings_map->SetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_JAVASCRIPT, CONTENT_SETTING_BLOCK);
+
+ // Set an exception to allow "[*.]example.com"
+ ContentSettingsPattern pattern("[*.]example.com");
+ host_content_settings_map->SetContentSetting(pattern,
+ CONTENT_SETTINGS_TYPE_JAVASCRIPT, "", CONTENT_SETTING_ALLOW);
+
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_JAVASCRIPT));
+ GURL host("http://example.com/");
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_JAVASCRIPT, ""));
+
+ // Set managed-default-content-settings-preferences.
+ prefs->SetManagedPref(prefs::kManagedDefaultJavaScriptSetting,
+ Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_JAVASCRIPT, ""));
+
+ // Remove managed-default-content-settings-preferences.
+ prefs->RemoveManagedPref(prefs::kManagedDefaultJavaScriptSetting);
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_JAVASCRIPT, ""));
+}
+
+// If a default-content-setting is set to managed setting, the user defined
+// setting should be preserved.
+TEST_F(HostContentSettingsMapTest, OverwrittenDefaultContentSetting) {
+ TestingProfile profile;
+ HostContentSettingsMap* host_content_settings_map =
+ profile.GetHostContentSettingsMap();
+ TestingPrefService* prefs = profile.GetTestingPrefService();
+
+ // Set user defined default-content-setting for Cookies.
+ host_content_settings_map->SetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_BLOCK);
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_COOKIES));
+
+ // Set preference to manage the default-content-setting for Cookies.
+ prefs->SetManagedPref(prefs::kManagedDefaultCookiesSetting,
+ Value::CreateIntegerValue(CONTENT_SETTING_ALLOW));
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_COOKIES));
+
+ // Remove the preference to manage the default-content-setting for Cookies.
+ prefs->RemoveManagedPref(prefs::kManagedDefaultCookiesSetting);
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_COOKIES));
+}
+
+// If a setting for a default-content-setting-type is set while the type is
+// managed, then the new setting should be preserved and used after the
+// default-content-setting-type is not managed anymore.
+TEST_F(HostContentSettingsMapTest, SettingDefaultContentSettingsWhenManaged) {
+ TestingProfile profile;
+ HostContentSettingsMap* host_content_settings_map =
+ profile.GetHostContentSettingsMap();
+ TestingPrefService* prefs = profile.GetTestingPrefService();
+
+ prefs->SetManagedPref(prefs::kManagedDefaultPluginsSetting,
+ Value::CreateIntegerValue(CONTENT_SETTING_ALLOW));
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_PLUGINS));
+
+ host_content_settings_map->SetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_PLUGINS, CONTENT_SETTING_BLOCK);
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ host_content_settings_map->GetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_PLUGINS));
+
+ prefs->RemoveManagedPref(prefs::kManagedDefaultPluginsSetting);
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ host_content_settings_map->GetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_PLUGINS));
+}
+
+TEST_F(HostContentSettingsMapTest, ResetToDefaultsWhenManaged) {
+ TestingProfile profile;
+ HostContentSettingsMap* host_content_settings_map =
+ profile.GetHostContentSettingsMap();
+ TestingPrefService* prefs = profile.GetTestingPrefService();
+
+ prefs->SetManagedPref(prefs::kBlockThirdPartyCookies,
+ Value::CreateBooleanValue(true));
+ prefs->SetUserPref(prefs::kBlockThirdPartyCookies,
+ Value::CreateBooleanValue(true));
+
+ EXPECT_TRUE(host_content_settings_map->IsBlockThirdPartyCookiesManaged());
+ EXPECT_TRUE(host_content_settings_map->BlockThirdPartyCookies());
+
+ // Reset to the default value (false).
+ host_content_settings_map->ResetToDefaults();
+ // Since the preference BlockThirdPartyCookies is managed the
+ // HostContentSettingsMap should still return the managed value which is true.
+ EXPECT_TRUE(host_content_settings_map->IsBlockThirdPartyCookiesManaged());
+ EXPECT_TRUE(host_content_settings_map->BlockThirdPartyCookies());
+
+ // After unsetting the managed value for the preference BlockThirdPartyCookies
+ // the default value should be returned now.
+ prefs->RemoveManagedPref(prefs::kBlockThirdPartyCookies);
+ EXPECT_FALSE(host_content_settings_map->IsBlockThirdPartyCookiesManaged());
+ EXPECT_FALSE(host_content_settings_map->BlockThirdPartyCookies());
+}
+
+} // namespace
diff --git a/chrome/browser/content_settings/host_content_settings_map_unittest.h b/chrome/browser/content_settings/host_content_settings_map_unittest.h
new file mode 100644
index 0000000..ba56ab4
--- /dev/null
+++ b/chrome/browser/content_settings/host_content_settings_map_unittest.h
@@ -0,0 +1,49 @@
+// 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.
+
+#ifndef CHROME_BROWSER_CONTENT_SETTINGS_HOST_CONTENT_SETTINGS_MAP_UNITTEST_H_
+#define CHROME_BROWSER_CONTENT_SETTINGS_HOST_CONTENT_SETTINGS_MAP_UNITTEST_H_
+#pragma once
+
+#include "chrome/browser/content_settings/content_settings_details.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
+#include "chrome/common/notification_service.h"
+#include "googleurl/src/gurl.h"
+
+class HostContentSettingsMap;
+
+class StubSettingsObserver : public NotificationObserver {
+ public:
+ StubSettingsObserver() : last_notifier(NULL), counter(0) {
+ registrar_.Add(this, NotificationType::CONTENT_SETTINGS_CHANGED,
+ NotificationService::AllSources());
+ }
+
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ ++counter;
+ Source<HostContentSettingsMap> content_settings(source);
+ Details<ContentSettingsDetails> settings_details(details);
+ last_notifier = content_settings.ptr();
+ last_pattern = settings_details.ptr()->pattern();
+ last_update_all = settings_details.ptr()->update_all();
+ last_update_all_types = settings_details.ptr()->update_all_types();
+ last_type = settings_details.ptr()->type();
+ // This checks that calling a Get function from an observer doesn't
+ // deadlock.
+ last_notifier->GetContentSettings(GURL("http://random-hostname.com/"));
+ }
+
+ HostContentSettingsMap* last_notifier;
+ ContentSettingsPattern last_pattern;
+ bool last_update_all;
+ bool last_update_all_types;
+ int counter;
+ ContentSettingsType last_type;
+
+ private:
+ NotificationRegistrar registrar_;
+};
+#endif // CHROME_BROWSER_CONTENT_SETTINGS_HOST_CONTENT_SETTINGS_MAP_UNITTEST_H_
diff --git a/chrome/browser/content_settings/mock_content_settings_provider.cc b/chrome/browser/content_settings/mock_content_settings_provider.cc
new file mode 100644
index 0000000..ee3e845
--- /dev/null
+++ b/chrome/browser/content_settings/mock_content_settings_provider.cc
@@ -0,0 +1,44 @@
+// 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.
+
+#include "chrome/browser/content_settings/mock_content_settings_provider.h"
+
+MockContentSettingsProvider::MockContentSettingsProvider(
+ ContentSettingsType content_type,
+ ContentSetting setting,
+ bool is_managed,
+ bool can_override)
+ : content_type_(content_type),
+ setting_(setting),
+ is_managed_(is_managed),
+ can_override_(can_override) {
+}
+
+MockContentSettingsProvider::~MockContentSettingsProvider() {
+}
+
+bool MockContentSettingsProvider::CanProvideDefaultSetting(
+ ContentSettingsType content_type) const {
+ return content_type == content_type_;
+}
+
+ContentSetting MockContentSettingsProvider::ProvideDefaultSetting(
+ ContentSettingsType content_type) const {
+ return content_type == content_type_ ? setting_ : CONTENT_SETTING_DEFAULT;
+}
+
+void MockContentSettingsProvider::UpdateDefaultSetting(
+ ContentSettingsType content_type,
+ ContentSetting setting) {
+ if (can_override_ && content_type == content_type_)
+ setting_ = setting;
+}
+
+bool MockContentSettingsProvider::DefaultSettingIsManaged(
+ ContentSettingsType content_type) const {
+ return content_type == content_type_ && is_managed_;
+}
+
+void MockContentSettingsProvider::ResetToDefaults() {
+}
diff --git a/chrome/browser/content_settings/mock_content_settings_provider.h b/chrome/browser/content_settings/mock_content_settings_provider.h
new file mode 100644
index 0000000..113a8ae
--- /dev/null
+++ b/chrome/browser/content_settings/mock_content_settings_provider.h
@@ -0,0 +1,40 @@
+// 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.
+
+#ifndef CHROME_BROWSER_CONTENT_SETTINGS_MOCK_CONTENT_SETTINGS_PROVIDER_H_
+#define CHROME_BROWSER_CONTENT_SETTINGS_MOCK_CONTENT_SETTINGS_PROVIDER_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "chrome/browser/content_settings/content_settings_provider.h"
+
+class MockContentSettingsProvider : public ContentSettingsProviderInterface {
+ public:
+ // Create a content settings provider that provides a given setting for a
+ // given type.
+ MockContentSettingsProvider(ContentSettingsType content_type,
+ ContentSetting setting,
+ bool is_managed,
+ bool can_override);
+ virtual ~MockContentSettingsProvider();
+
+ // ContentSettingsProviderInterface implementation.
+ virtual bool CanProvideDefaultSetting(ContentSettingsType content_type) const;
+ virtual ContentSetting ProvideDefaultSetting(
+ ContentSettingsType content_type) const;
+ virtual void UpdateDefaultSetting(ContentSettingsType content_type,
+ ContentSetting setting);
+ virtual void ResetToDefaults();
+ virtual bool DefaultSettingIsManaged(ContentSettingsType content_type) const;
+
+ private:
+ ContentSettingsType content_type_;
+ ContentSetting setting_;
+ bool is_managed_;
+ bool can_override_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockContentSettingsProvider);
+};
+
+#endif // CHROME_BROWSER_CONTENT_SETTINGS_MOCK_CONTENT_SETTINGS_PROVIDER_H_
diff --git a/chrome/browser/content_settings/policy_content_settings_provider.cc b/chrome/browser/content_settings/policy_content_settings_provider.cc
new file mode 100644
index 0000000..5bc8e9f
--- /dev/null
+++ b/chrome/browser/content_settings/policy_content_settings_provider.cc
@@ -0,0 +1,204 @@
+// 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.
+
+#include "chrome/browser/content_settings/policy_content_settings_provider.h"
+
+#include "base/command_line.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/content_settings/content_settings_details.h"
+#include "chrome/browser/content_settings/content_settings_pattern.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/prefs/scoped_pref_update.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/pref_names.h"
+
+namespace {
+
+// Base pref path of the prefs that contain the managed default content
+// settings values.
+const std::string kManagedSettings =
+ "profile.managed_default_content_settings";
+
+// The preferences used to manage ContentSettingsTypes.
+const char* kPrefToManageType[CONTENT_SETTINGS_NUM_TYPES] = {
+ prefs::kManagedDefaultCookiesSetting,
+ prefs::kManagedDefaultImagesSetting,
+ prefs::kManagedDefaultJavaScriptSetting,
+ prefs::kManagedDefaultPluginsSetting,
+ prefs::kManagedDefaultPopupsSetting,
+ NULL, // Not used for Geolocation
+ NULL, // Not used for Notifications
+};
+
+} // namespace
+
+PolicyContentSettingsProvider::PolicyContentSettingsProvider(Profile* profile)
+ : profile_(profile),
+ is_off_the_record_(profile_->IsOffTheRecord()) {
+ PrefService* prefs = profile->GetPrefs();
+
+ // Read global defaults.
+ DCHECK_EQ(arraysize(kPrefToManageType),
+ static_cast<size_t>(CONTENT_SETTINGS_NUM_TYPES));
+ ReadManagedDefaultSettings();
+
+ pref_change_registrar_.Init(prefs);
+ // The following preferences are only used to indicate if a
+ // default-content-setting is managed and to hold the managed default-setting
+ // value. If the value for any of the following perferences is set then the
+ // corresponding default-content-setting is managed. These preferences exist
+ // in parallel to the preference default-content-settings. If a
+ // default-content-settings-type is managed any user defined excpetions
+ // (patterns) for this type are ignored.
+ pref_change_registrar_.Add(prefs::kManagedDefaultCookiesSetting, this);
+ pref_change_registrar_.Add(prefs::kManagedDefaultImagesSetting, this);
+ pref_change_registrar_.Add(prefs::kManagedDefaultJavaScriptSetting, this);
+ pref_change_registrar_.Add(prefs::kManagedDefaultPluginsSetting, this);
+ pref_change_registrar_.Add(prefs::kManagedDefaultPopupsSetting, this);
+ notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED,
+ Source<Profile>(profile_));
+}
+
+PolicyContentSettingsProvider::~PolicyContentSettingsProvider() {
+ UnregisterObservers();
+}
+
+bool PolicyContentSettingsProvider::CanProvideDefaultSetting(
+ ContentSettingsType content_type) const {
+ AutoLock lock(lock_);
+ if (managed_default_content_settings_.settings[content_type] !=
+ CONTENT_SETTING_DEFAULT) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+ContentSetting PolicyContentSettingsProvider::ProvideDefaultSetting(
+ ContentSettingsType content_type) const {
+ AutoLock auto_lock(lock_);
+ return managed_default_content_settings_.settings[content_type];
+}
+
+void PolicyContentSettingsProvider::UpdateDefaultSetting(
+ ContentSettingsType content_type,
+ ContentSetting setting) {
+}
+
+bool PolicyContentSettingsProvider::DefaultSettingIsManaged(
+ ContentSettingsType content_type) const {
+ AutoLock lock(lock_);
+ if (managed_default_content_settings_.settings[content_type] !=
+ CONTENT_SETTING_DEFAULT) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void PolicyContentSettingsProvider::ResetToDefaults() {
+}
+
+void PolicyContentSettingsProvider::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (type == NotificationType::PREF_CHANGED) {
+ DCHECK_EQ(profile_->GetPrefs(), Source<PrefService>(source).ptr());
+ std::string* name = Details<std::string>(details).ptr();
+ if (*name == prefs::kManagedDefaultCookiesSetting) {
+ UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES);
+ } else if (*name == prefs::kManagedDefaultImagesSetting) {
+ UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_IMAGES);
+ } else if (*name == prefs::kManagedDefaultJavaScriptSetting) {
+ UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_JAVASCRIPT);
+ } else if (*name == prefs::kManagedDefaultPluginsSetting) {
+ UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_PLUGINS);
+ } else if (*name == prefs::kManagedDefaultPopupsSetting) {
+ UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_POPUPS);
+ } else {
+ NOTREACHED() << "Unexpected preference observed";
+ return;
+ }
+
+ if (!is_off_the_record_) {
+ NotifyObservers(ContentSettingsDetails(
+ ContentSettingsPattern(), CONTENT_SETTINGS_TYPE_DEFAULT, ""));
+ }
+ } else if (type == NotificationType::PROFILE_DESTROYED) {
+ DCHECK_EQ(profile_, Source<Profile>(source).ptr());
+ UnregisterObservers();
+ } else {
+ NOTREACHED() << "Unexpected notification";
+ }
+}
+
+void PolicyContentSettingsProvider::UnregisterObservers() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!profile_)
+ return;
+ pref_change_registrar_.RemoveAll();
+ notification_registrar_.Remove(this, NotificationType::PROFILE_DESTROYED,
+ Source<Profile>(profile_));
+ profile_ = NULL;
+}
+
+
+void PolicyContentSettingsProvider::NotifyObservers(
+ const ContentSettingsDetails& details) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (profile_ == NULL)
+ return;
+ NotificationService::current()->Notify(
+ NotificationType::CONTENT_SETTINGS_CHANGED,
+ Source<HostContentSettingsMap>(profile_->GetHostContentSettingsMap()),
+ Details<const ContentSettingsDetails>(&details));
+}
+
+void PolicyContentSettingsProvider::ReadManagedDefaultSettings() {
+ for (size_t type = 0; type < arraysize(kPrefToManageType); ++type) {
+ if (kPrefToManageType[type] == NULL) {
+ // TODO(markusheintz): Handle Geolocation and notification separately.
+ continue;
+ }
+ UpdateManagedDefaultSetting(ContentSettingsType(type));
+ }
+}
+
+void PolicyContentSettingsProvider::UpdateManagedDefaultSetting(
+ ContentSettingsType type) {
+ // If a pref to manage a default-content-setting was not set (NOTICE:
+ // "HasPrefPath" returns false if no value was set for a registered pref) then
+ // the default value of the preference is used. The default value of a
+ // preference to manage a default-content-settings is
+ // CONTENT_SETTING_DEFAULT. This indicates that no managed value is set. If a
+ // pref was set, than it MUST be managed.
+ PrefService* prefs = profile_->GetPrefs();
+ DCHECK(!prefs->HasPrefPath(kPrefToManageType[type]) ||
+ prefs->IsManagedPreference(kPrefToManageType[type]));
+ AutoLock auto_lock(lock_);
+ managed_default_content_settings_.settings[type] = IntToContentSetting(
+ prefs->GetInteger(kPrefToManageType[type]));
+}
+
+// static
+void PolicyContentSettingsProvider::RegisterUserPrefs(PrefService* prefs) {
+ // Preferences for default content setting policies. A policy is not set of
+ // the corresponding preferences below is set to CONTENT_SETTING_DEFAULT.
+ prefs->RegisterIntegerPref(prefs::kManagedDefaultCookiesSetting,
+ CONTENT_SETTING_DEFAULT);
+ prefs->RegisterIntegerPref(prefs::kManagedDefaultImagesSetting,
+ CONTENT_SETTING_DEFAULT);
+ prefs->RegisterIntegerPref(prefs::kManagedDefaultJavaScriptSetting,
+ CONTENT_SETTING_DEFAULT);
+ prefs->RegisterIntegerPref(prefs::kManagedDefaultPluginsSetting,
+ CONTENT_SETTING_DEFAULT);
+ prefs->RegisterIntegerPref(prefs::kManagedDefaultPopupsSetting,
+ CONTENT_SETTING_DEFAULT);
+}
diff --git a/chrome/browser/content_settings/policy_content_settings_provider.h b/chrome/browser/content_settings/policy_content_settings_provider.h
new file mode 100644
index 0000000..1844234
--- /dev/null
+++ b/chrome/browser/content_settings/policy_content_settings_provider.h
@@ -0,0 +1,78 @@
+// 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.
+
+#ifndef CHROME_BROWSER_CONTENT_SETTINGS_POLICY_CONTENT_SETTINGS_PROVIDER_H_
+#define CHROME_BROWSER_CONTENT_SETTINGS_POLICY_CONTENT_SETTINGS_PROVIDER_H_
+#pragma once
+
+// A content settings provider that takes its settings out of policies.
+
+#include "base/basictypes.h"
+#include "base/lock.h"
+#include "chrome/browser/content_settings/content_settings_provider.h"
+#include "chrome/browser/prefs/pref_change_registrar.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+
+class ContentSettingsDetails;
+class DictionaryValue;
+class PrefService;
+class Profile;
+
+class PolicyContentSettingsProvider : public ContentSettingsProviderInterface,
+ public NotificationObserver {
+ public:
+ explicit PolicyContentSettingsProvider(Profile* profile);
+ virtual ~PolicyContentSettingsProvider();
+
+ // ContentSettingsProviderInterface implementation.
+ virtual bool CanProvideDefaultSetting(ContentSettingsType content_type) const;
+ virtual ContentSetting ProvideDefaultSetting(
+ ContentSettingsType content_type) const;
+ virtual void UpdateDefaultSetting(ContentSettingsType content_type,
+ ContentSetting setting);
+ virtual void ResetToDefaults();
+ virtual bool DefaultSettingIsManaged(ContentSettingsType content_type) const;
+
+ static void RegisterUserPrefs(PrefService* prefs);
+
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ private:
+ // Informs observers that content settings have changed. Make sure that
+ // |lock_| is not held when calling this, as listeners will usually call one
+ // of the GetSettings functions in response, which would then lead to a
+ // mutex deadlock.
+ void NotifyObservers(const ContentSettingsDetails& details);
+
+ void UnregisterObservers();
+
+ // Reads the policy managed default settings.
+ void ReadManagedDefaultSettings();
+
+ // Reads the policy controlled default settings for a specific content type.
+ void UpdateManagedDefaultSetting(ContentSettingsType content_type);
+
+ // Copies of the pref data, so that we can read it on the IO thread.
+ ContentSettings managed_default_content_settings_;
+
+ Profile* profile_;
+
+ // Whether this settings map is for an OTR session.
+ bool is_off_the_record_;
+
+ // Used around accesses to the managed_default_content_settings_ object to
+ // guarantee thread safety.
+ mutable Lock lock_;
+
+ PrefChangeRegistrar pref_change_registrar_;
+ NotificationRegistrar notification_registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(PolicyContentSettingsProvider);
+};
+
+#endif // CHROME_BROWSER_CONTENT_SETTINGS_POLICY_CONTENT_SETTINGS_PROVIDER_H_
diff --git a/chrome/browser/content_settings/policy_content_settings_provider_unittest.cc b/chrome/browser/content_settings/policy_content_settings_provider_unittest.cc
new file mode 100644
index 0000000..9c639ab
--- /dev/null
+++ b/chrome/browser/content_settings/policy_content_settings_provider_unittest.cc
@@ -0,0 +1,88 @@
+// 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.
+
+#include "chrome/browser/content_settings/policy_content_settings_provider.h"
+
+#include "chrome/browser/content_settings/host_content_settings_map_unittest.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/test/testing_pref_service.h"
+#include "chrome/test/testing_profile.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+
+namespace {
+
+class PolicyContentSettingsProviderTest : public testing::Test {
+ public:
+ PolicyContentSettingsProviderTest()
+ : ui_thread_(BrowserThread::UI, &message_loop_) {
+ }
+
+ protected:
+ MessageLoop message_loop_;
+ BrowserThread ui_thread_;
+};
+
+TEST_F(PolicyContentSettingsProviderTest, DefaultValues) {
+ TestingProfile profile;
+ PolicyContentSettingsProvider provider(&profile);
+ TestingPrefService* prefs = profile.GetTestingPrefService();
+
+ // By default, policies should be off.
+ ASSERT_FALSE(
+ provider.CanProvideDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES));
+ ASSERT_FALSE(
+ provider.DefaultSettingIsManaged(CONTENT_SETTINGS_TYPE_COOKIES));
+
+ // Set managed-default-content-setting through the coresponding preferences.
+ prefs->SetManagedPref(prefs::kManagedDefaultCookiesSetting,
+ Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
+ ASSERT_TRUE(
+ provider.CanProvideDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES));
+ ASSERT_TRUE(
+ provider.DefaultSettingIsManaged(CONTENT_SETTINGS_TYPE_COOKIES));
+ ASSERT_EQ(CONTENT_SETTING_BLOCK,
+ provider.ProvideDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES));
+
+ // Remove managed-default-content-settings-preferences.
+ prefs->RemoveManagedPref(prefs::kManagedDefaultCookiesSetting);
+ ASSERT_FALSE(
+ provider.CanProvideDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES));
+ ASSERT_FALSE(
+ provider.DefaultSettingIsManaged(CONTENT_SETTINGS_TYPE_COOKIES));
+}
+
+// When a default-content-setting is set to a managed setting a
+// CONTENT_SETTINGS_CHANGED notification should be fired. The same should happen
+// if the managed setting is removed.
+TEST_F(PolicyContentSettingsProviderTest, ObserveManagedSettingsChange) {
+ TestingProfile profile;
+ StubSettingsObserver observer;
+ // Make sure the content settings map exists.
+ profile.GetHostContentSettingsMap();
+ TestingPrefService* prefs = profile.GetTestingPrefService();
+
+ // Set the managed default-content-setting.
+ prefs->SetManagedPref(prefs::kManagedDefaultImagesSetting,
+ Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
+ EXPECT_EQ(profile.GetHostContentSettingsMap(), observer.last_notifier);
+ EXPECT_EQ(ContentSettingsPattern(), observer.last_pattern);
+ EXPECT_EQ(CONTENT_SETTINGS_TYPE_DEFAULT, observer.last_type);
+ EXPECT_TRUE(observer.last_update_all);
+ EXPECT_TRUE(observer.last_update_all_types);
+ EXPECT_EQ(1, observer.counter);
+
+ // Remove the managed default-content-setting.
+ prefs->RemoveManagedPref(prefs::kManagedDefaultImagesSetting);
+ EXPECT_EQ(profile.GetHostContentSettingsMap(), observer.last_notifier);
+ EXPECT_EQ(CONTENT_SETTINGS_TYPE_DEFAULT, observer.last_type);
+ EXPECT_EQ(ContentSettingsPattern(), observer.last_pattern);
+ EXPECT_TRUE(observer.last_update_all);
+ EXPECT_TRUE(observer.last_update_all_types);
+ EXPECT_EQ(2, observer.counter);
+}
+
+} // namespace
diff --git a/chrome/browser/content_settings/pref_content_settings_provider.cc b/chrome/browser/content_settings/pref_content_settings_provider.cc
new file mode 100644
index 0000000..01ac055
--- /dev/null
+++ b/chrome/browser/content_settings/pref_content_settings_provider.cc
@@ -0,0 +1,263 @@
+// 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.
+
+#include "chrome/browser/content_settings/pref_content_settings_provider.h"
+
+#include "base/command_line.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/content_settings/content_settings_details.h"
+#include "chrome/browser/content_settings/content_settings_pattern.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/prefs/scoped_pref_update.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/pref_names.h"
+
+namespace {
+
+// The default setting for each content type.
+const ContentSetting kDefaultSettings[CONTENT_SETTINGS_NUM_TYPES] = {
+ CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_COOKIES
+ CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_IMAGES
+ CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_JAVASCRIPT
+ CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_PLUGINS
+ CONTENT_SETTING_BLOCK, // CONTENT_SETTINGS_TYPE_POPUPS
+ CONTENT_SETTING_ASK, // Not used for Geolocation
+ CONTENT_SETTING_ASK, // Not used for Notifications
+};
+
+// The names of the ContentSettingsType values, for use with dictionary prefs.
+const char* kTypeNames[CONTENT_SETTINGS_NUM_TYPES] = {
+ "cookies",
+ "images",
+ "javascript",
+ "plugins",
+ "popups",
+ NULL, // Not used for Geolocation
+ NULL, // Not used for Notifications
+};
+
+
+// Map ASK for the plugins content type to BLOCK if click-to-play is
+// not enabled.
+ContentSetting ClickToPlayFixup(ContentSettingsType content_type,
+ ContentSetting setting) {
+ if (setting == CONTENT_SETTING_ASK &&
+ content_type == CONTENT_SETTINGS_TYPE_PLUGINS &&
+ !CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableClickToPlay)) {
+ return CONTENT_SETTING_BLOCK;
+ }
+ return setting;
+}
+
+} // namespace
+
+PrefContentSettingsProvider::PrefContentSettingsProvider(Profile* profile)
+ : profile_(profile),
+ is_off_the_record_(profile_->IsOffTheRecord()),
+ updating_preferences_(false) {
+ PrefService* prefs = profile->GetPrefs();
+
+ // Read global defaults.
+ DCHECK_EQ(arraysize(kTypeNames),
+ static_cast<size_t>(CONTENT_SETTINGS_NUM_TYPES));
+ ReadDefaultSettings(true);
+
+ pref_change_registrar_.Init(prefs);
+ pref_change_registrar_.Add(prefs::kDefaultContentSettings, this);
+ notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED,
+ Source<Profile>(profile_));
+}
+
+PrefContentSettingsProvider::~PrefContentSettingsProvider() {
+ UnregisterObservers();
+}
+
+bool PrefContentSettingsProvider::CanProvideDefaultSetting(
+ ContentSettingsType content_type) const {
+ return true;
+}
+
+ContentSetting PrefContentSettingsProvider::ProvideDefaultSetting(
+ ContentSettingsType content_type) const {
+ AutoLock lock(lock_);
+ return default_content_settings_.settings[content_type];
+}
+
+void PrefContentSettingsProvider::UpdateDefaultSetting(
+ ContentSettingsType content_type,
+ ContentSetting setting) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(kTypeNames[content_type] != NULL); // Don't call this for Geolocation.
+ DCHECK(content_type != CONTENT_SETTINGS_TYPE_PLUGINS ||
+ setting != CONTENT_SETTING_ASK ||
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableClickToPlay));
+
+ // The default settings may not be directly modified for OTR sessions.
+ // Instead, they are synced to the main profile's setting.
+ if (is_off_the_record_)
+ return;
+
+ PrefService* prefs = profile_->GetPrefs();
+
+ DictionaryValue* default_settings_dictionary =
+ prefs->GetMutableDictionary(prefs::kDefaultContentSettings);
+ std::string dictionary_path(kTypeNames[content_type]);
+ updating_preferences_ = true;
+ {
+ AutoLock lock(lock_);
+ ScopedPrefUpdate update(prefs, prefs::kDefaultContentSettings);
+ if ((setting == CONTENT_SETTING_DEFAULT) ||
+ (setting == kDefaultSettings[content_type])) {
+ default_content_settings_.settings[content_type] =
+ kDefaultSettings[content_type];
+ default_settings_dictionary->RemoveWithoutPathExpansion(dictionary_path,
+ NULL);
+ } else {
+ default_content_settings_.settings[content_type] = setting;
+ default_settings_dictionary->SetWithoutPathExpansion(
+ dictionary_path, Value::CreateIntegerValue(setting));
+ }
+ }
+ updating_preferences_ = false;
+
+ NotifyObservers(
+ ContentSettingsDetails(ContentSettingsPattern(), content_type, ""));
+}
+
+bool PrefContentSettingsProvider::DefaultSettingIsManaged(
+ ContentSettingsType content_type) const {
+ return false;
+}
+
+void PrefContentSettingsProvider::ResetToDefaults() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ AutoLock lock(lock_);
+ default_content_settings_ = ContentSettings();
+ ForceDefaultsToBeExplicit();
+
+ if (!is_off_the_record_) {
+ PrefService* prefs = profile_->GetPrefs();
+ updating_preferences_ = true;
+ prefs->ClearPref(prefs::kDefaultContentSettings);
+ updating_preferences_ = false;
+ }
+}
+
+void PrefContentSettingsProvider::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (type == NotificationType::PREF_CHANGED) {
+ DCHECK_EQ(profile_->GetPrefs(), Source<PrefService>(source).ptr());
+ if (updating_preferences_)
+ return;
+
+ std::string* name = Details<std::string>(details).ptr();
+ if (*name == prefs::kDefaultContentSettings) {
+ ReadDefaultSettings(true);
+ } else {
+ NOTREACHED() << "Unexpected preference observed";
+ return;
+ }
+
+ if (!is_off_the_record_) {
+ NotifyObservers(ContentSettingsDetails(
+ ContentSettingsPattern(), CONTENT_SETTINGS_TYPE_DEFAULT, ""));
+ }
+ } else if (type == NotificationType::PROFILE_DESTROYED) {
+ DCHECK_EQ(profile_, Source<Profile>(source).ptr());
+ UnregisterObservers();
+ } else {
+ NOTREACHED() << "Unexpected notification";
+ }
+}
+
+void PrefContentSettingsProvider::UnregisterObservers() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!profile_)
+ return;
+ pref_change_registrar_.RemoveAll();
+ notification_registrar_.Remove(this, NotificationType::PROFILE_DESTROYED,
+ Source<Profile>(profile_));
+ profile_ = NULL;
+}
+
+void PrefContentSettingsProvider::ReadDefaultSettings(bool overwrite) {
+ PrefService* prefs = profile_->GetPrefs();
+ const DictionaryValue* default_settings_dictionary =
+ prefs->GetDictionary(prefs::kDefaultContentSettings);
+
+ AutoLock lock(lock_);
+
+ if (overwrite)
+ default_content_settings_ = ContentSettings();
+
+ // Careful: The returned value could be NULL if the pref has never been set.
+ if (default_settings_dictionary != NULL) {
+ GetSettingsFromDictionary(default_settings_dictionary,
+ &default_content_settings_);
+ }
+ ForceDefaultsToBeExplicit();
+}
+
+void PrefContentSettingsProvider::ForceDefaultsToBeExplicit() {
+ DCHECK_EQ(arraysize(kDefaultSettings),
+ static_cast<size_t>(CONTENT_SETTINGS_NUM_TYPES));
+
+ for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
+ if (default_content_settings_.settings[i] == CONTENT_SETTING_DEFAULT)
+ default_content_settings_.settings[i] = kDefaultSettings[i];
+ }
+}
+
+void PrefContentSettingsProvider::GetSettingsFromDictionary(
+ const DictionaryValue* dictionary,
+ ContentSettings* settings) {
+ for (DictionaryValue::key_iterator i(dictionary->begin_keys());
+ i != dictionary->end_keys(); ++i) {
+ const std::string& content_type(*i);
+ for (size_t type = 0; type < arraysize(kTypeNames); ++type) {
+ if ((kTypeNames[type] != NULL) && (kTypeNames[type] == content_type)) {
+ int setting = CONTENT_SETTING_DEFAULT;
+ bool found = dictionary->GetIntegerWithoutPathExpansion(content_type,
+ &setting);
+ DCHECK(found);
+ settings->settings[type] = IntToContentSetting(setting);
+ break;
+ }
+ }
+ }
+ // Migrate obsolete cookie prompt mode.
+ if (settings->settings[CONTENT_SETTINGS_TYPE_COOKIES] ==
+ CONTENT_SETTING_ASK)
+ settings->settings[CONTENT_SETTINGS_TYPE_COOKIES] = CONTENT_SETTING_BLOCK;
+
+ settings->settings[CONTENT_SETTINGS_TYPE_PLUGINS] =
+ ClickToPlayFixup(CONTENT_SETTINGS_TYPE_PLUGINS,
+ settings->settings[CONTENT_SETTINGS_TYPE_PLUGINS]);
+}
+
+void PrefContentSettingsProvider::NotifyObservers(
+ const ContentSettingsDetails& details) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (profile_ == NULL)
+ return;
+ NotificationService::current()->Notify(
+ NotificationType::CONTENT_SETTINGS_CHANGED,
+ Source<HostContentSettingsMap>(profile_->GetHostContentSettingsMap()),
+ Details<const ContentSettingsDetails>(&details));
+}
+
+
+// static
+void PrefContentSettingsProvider::RegisterUserPrefs(PrefService* prefs) {
+ prefs->RegisterDictionaryPref(prefs::kDefaultContentSettings);
+}
diff --git a/chrome/browser/content_settings/pref_content_settings_provider.h b/chrome/browser/content_settings/pref_content_settings_provider.h
new file mode 100644
index 0000000..178e903
--- /dev/null
+++ b/chrome/browser/content_settings/pref_content_settings_provider.h
@@ -0,0 +1,88 @@
+// 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.
+
+#ifndef CHROME_BROWSER_CONTENT_SETTINGS_PREF_CONTENT_SETTINGS_PROVIDER_H_
+#define CHROME_BROWSER_CONTENT_SETTINGS_PREF_CONTENT_SETTINGS_PROVIDER_H_
+#pragma once
+
+// A content settings provider that takes its settings out of the pref service.
+
+#include "base/basictypes.h"
+#include "base/lock.h"
+#include "chrome/browser/content_settings/content_settings_provider.h"
+#include "chrome/browser/prefs/pref_change_registrar.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+
+class ContentSettingsDetails;
+class DictionaryValue;
+class PrefService;
+class Profile;
+
+class PrefContentSettingsProvider : public ContentSettingsProviderInterface,
+ public NotificationObserver {
+ public:
+ explicit PrefContentSettingsProvider(Profile* profile);
+ virtual ~PrefContentSettingsProvider();
+
+ // ContentSettingsProviderInterface implementation.
+ virtual bool CanProvideDefaultSetting(ContentSettingsType content_type) const;
+ virtual ContentSetting ProvideDefaultSetting(
+ ContentSettingsType content_type) const;
+ virtual void UpdateDefaultSetting(ContentSettingsType content_type,
+ ContentSetting setting);
+ virtual void ResetToDefaults();
+ virtual bool DefaultSettingIsManaged(ContentSettingsType content_type) const;
+
+ static void RegisterUserPrefs(PrefService* prefs);
+
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ private:
+ // Informs observers that content settings have changed. Make sure that
+ // |lock_| is not held when calling this, as listeners will usually call one
+ // of the GetSettings functions in response, which would then lead to a
+ // mutex deadlock.
+ void NotifyObservers(const ContentSettingsDetails& details);
+
+ void UnregisterObservers();
+
+ // Sets the fields of |settings| based on the values in |dictionary|.
+ void GetSettingsFromDictionary(const DictionaryValue* dictionary,
+ ContentSettings* settings);
+
+ // Forces the default settings to be explicitly set instead of themselves
+ // being CONTENT_SETTING_DEFAULT.
+ void ForceDefaultsToBeExplicit();
+
+ // Reads the default settings from the preferences service. If |overwrite| is
+ // true and the preference is missing, the local copy will be cleared as well.
+ void ReadDefaultSettings(bool overwrite);
+
+ // Copies of the pref data, so that we can read it on the IO thread.
+ ContentSettings default_content_settings_;
+
+ Profile* profile_;
+
+ // Whether this settings map is for an OTR session.
+ bool is_off_the_record_;
+
+ // Used around accesses to the default_content_settings_ object to guarantee
+ // thread safety.
+ mutable Lock lock_;
+
+ PrefChangeRegistrar pref_change_registrar_;
+ NotificationRegistrar notification_registrar_;
+
+ // Whether we are currently updating preferences, this is used to ignore
+ // notifications from the preferences service that we triggered ourself.
+ bool updating_preferences_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrefContentSettingsProvider);
+};
+
+#endif // CHROME_BROWSER_CONTENT_SETTINGS_PREF_CONTENT_SETTINGS_PROVIDER_H_
diff --git a/chrome/browser/content_settings/pref_content_settings_provider_unittest.cc b/chrome/browser/content_settings/pref_content_settings_provider_unittest.cc
new file mode 100644
index 0000000..f4289f3
--- /dev/null
+++ b/chrome/browser/content_settings/pref_content_settings_provider_unittest.cc
@@ -0,0 +1,124 @@
+// 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.
+
+#include "chrome/browser/content_settings/pref_content_settings_provider.h"
+
+#include "chrome/browser/content_settings/host_content_settings_map_unittest.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/test/testing_pref_service.h"
+#include "chrome/test/testing_profile.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+
+namespace {
+
+class PrefContentSettingsProviderTest : public testing::Test {
+ public:
+ PrefContentSettingsProviderTest()
+ : ui_thread_(BrowserThread::UI, &message_loop_) {
+ }
+
+ protected:
+ MessageLoop message_loop_;
+ BrowserThread ui_thread_;
+};
+
+TEST_F(PrefContentSettingsProviderTest, DefaultValues) {
+ TestingProfile profile;
+ PrefContentSettingsProvider provider(&profile);
+
+ ASSERT_TRUE(
+ provider.CanProvideDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES));
+ ASSERT_FALSE(
+ provider.DefaultSettingIsManaged(CONTENT_SETTINGS_TYPE_COOKIES));
+
+ // Check setting defaults.
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ provider.ProvideDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES));
+ provider.UpdateDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES,
+ CONTENT_SETTING_BLOCK);
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ provider.ProvideDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES));
+ provider.ResetToDefaults();
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ provider.ProvideDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES));
+}
+
+TEST_F(PrefContentSettingsProviderTest, Observer) {
+ TestingProfile profile;
+ PrefContentSettingsProvider provider(&profile);
+ StubSettingsObserver observer;
+
+ provider.UpdateDefaultSetting(
+ CONTENT_SETTINGS_TYPE_IMAGES, CONTENT_SETTING_BLOCK);
+ EXPECT_EQ(profile.GetHostContentSettingsMap(), observer.last_notifier);
+ EXPECT_TRUE(observer.last_update_all);
+ EXPECT_FALSE(observer.last_update_all_types);
+ EXPECT_EQ(1, observer.counter);
+}
+
+TEST_F(PrefContentSettingsProviderTest, ObserveDefaultPref) {
+ TestingProfile profile;
+ PrefContentSettingsProvider provider(&profile);
+
+ PrefService* prefs = profile.GetPrefs();
+
+ // Make a copy of the default pref value so we can reset it later.
+ scoped_ptr<Value> default_value(prefs->FindPreference(
+ prefs::kDefaultContentSettings)->GetValue()->DeepCopy());
+
+ provider.UpdateDefaultSetting(
+ CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_BLOCK);
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ provider.ProvideDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES));
+
+ // Make a copy of the pref's new value so we can reset it later.
+ scoped_ptr<Value> new_value(prefs->FindPreference(
+ prefs::kDefaultContentSettings)->GetValue()->DeepCopy());
+
+ // Clearing the backing pref should also clear the internal cache.
+ prefs->Set(prefs::kDefaultContentSettings, *default_value);
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ provider.ProvideDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES));
+
+ // Reseting the pref to its previous value should update the cache.
+ prefs->Set(prefs::kDefaultContentSettings, *new_value);
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ provider.ProvideDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES));
+}
+
+TEST_F(PrefContentSettingsProviderTest, OffTheRecord) {
+ TestingProfile profile;
+ PrefContentSettingsProvider provider(&profile);
+
+ profile.set_off_the_record(true);
+ PrefContentSettingsProvider otr_provider(&profile);
+ profile.set_off_the_record(false);
+
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ provider.ProvideDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES));
+ EXPECT_EQ(CONTENT_SETTING_ALLOW,
+ otr_provider.ProvideDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES));
+
+ // Changing content settings on the main provider should also affect the
+ // off-the-record map.
+ provider.UpdateDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES,
+ CONTENT_SETTING_BLOCK);
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ provider.ProvideDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES));
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ otr_provider.ProvideDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES));
+
+ // Changing content settings on the off-the-record provider should be ignored.
+ otr_provider.UpdateDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES,
+ CONTENT_SETTING_ALLOW);
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ provider.ProvideDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES));
+ EXPECT_EQ(CONTENT_SETTING_BLOCK,
+ otr_provider.ProvideDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES));
+}
+
+} // namespace
diff --git a/chrome/browser/cookies_tree_model.cc b/chrome/browser/cookies_tree_model.cc
index 24e3c9a..78a873c 100644
--- a/chrome/browser/cookies_tree_model.cc
+++ b/chrome/browser/cookies_tree_model.cc
@@ -14,7 +14,7 @@
#include "base/linked_ptr.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/in_process_webkit/webkit_context.h"
#include "grit/app_resources.h"
#include "grit/generated_resources.h"
@@ -51,6 +51,8 @@ CookieTreeCookieNode::CookieTreeCookieNode(
cookie_(cookie) {
}
+CookieTreeCookieNode::~CookieTreeCookieNode() {}
+
void CookieTreeCookieNode::DeleteStoredObjects() {
// notify CookieMonster that we should delete this cookie
// We have stored a copy of all the cookies in the model, and our model is
@@ -62,6 +64,12 @@ void CookieTreeCookieNode::DeleteStoredObjects() {
GetModel()->cookie_monster_->DeleteCanonicalCookie(*cookie_);
}
+CookieTreeNode::DetailedInfo CookieTreeCookieNode::GetDetailedInfo() const {
+ return DetailedInfo(GetParent()->GetParent()->GetTitle(),
+ DetailedInfo::TYPE_COOKIE,
+ cookie_, NULL, NULL, NULL, NULL, NULL);
+}
+
namespace {
// comparison functor, for use in CookieTreeRootNode
class OriginNodeComparator {
@@ -136,6 +144,12 @@ void CookieTreeAppCacheNode::DeleteStoredObjects() {
appcache_info_->manifest_url);
}
+CookieTreeNode::DetailedInfo CookieTreeAppCacheNode::GetDetailedInfo() const {
+ return DetailedInfo(GetParent()->GetParent()->GetTitle(),
+ DetailedInfo::TYPE_APPCACHE,
+ NULL, NULL, NULL, NULL, appcache_info_, NULL);
+}
+
///////////////////////////////////////////////////////////////////////////////
// CookieTreeDatabaseNode, public:
@@ -147,11 +161,19 @@ CookieTreeDatabaseNode::CookieTreeDatabaseNode(
database_info_(database_info) {
}
+CookieTreeDatabaseNode::~CookieTreeDatabaseNode() {}
+
void CookieTreeDatabaseNode::DeleteStoredObjects() {
GetModel()->database_helper_->DeleteDatabase(
database_info_->origin_identifier, database_info_->database_name);
}
+CookieTreeNode::DetailedInfo CookieTreeDatabaseNode::GetDetailedInfo() const {
+ return DetailedInfo(GetParent()->GetParent()->GetTitle(),
+ DetailedInfo::TYPE_DATABASE,
+ NULL, database_info_, NULL, NULL, NULL, NULL);
+}
+
///////////////////////////////////////////////////////////////////////////////
// CookieTreeLocalStorageNode, public:
@@ -164,11 +186,20 @@ CookieTreeLocalStorageNode::CookieTreeLocalStorageNode(
local_storage_info_(local_storage_info) {
}
+CookieTreeLocalStorageNode::~CookieTreeLocalStorageNode() {}
+
void CookieTreeLocalStorageNode::DeleteStoredObjects() {
GetModel()->local_storage_helper_->DeleteLocalStorageFile(
local_storage_info_->file_path);
}
+CookieTreeNode::DetailedInfo
+CookieTreeLocalStorageNode::GetDetailedInfo() const {
+ return DetailedInfo(GetParent()->GetParent()->GetTitle(),
+ DetailedInfo::TYPE_LOCAL_STORAGE,
+ NULL, NULL, local_storage_info_, NULL, NULL, NULL);
+}
+
///////////////////////////////////////////////////////////////////////////////
// CookieTreeSessionStorageNode, public:
@@ -181,6 +212,15 @@ CookieTreeSessionStorageNode::CookieTreeSessionStorageNode(
session_storage_info_(session_storage_info) {
}
+CookieTreeSessionStorageNode::~CookieTreeSessionStorageNode() {}
+
+CookieTreeNode::DetailedInfo
+CookieTreeSessionStorageNode::GetDetailedInfo() const {
+ return DetailedInfo(GetParent()->GetParent()->GetTitle(),
+ DetailedInfo::TYPE_SESSION_STORAGE,
+ NULL, NULL, NULL, session_storage_info_, NULL, NULL);
+}
+
///////////////////////////////////////////////////////////////////////////////
// CookieTreeIndexedDBNode, public:
@@ -193,14 +233,28 @@ CookieTreeIndexedDBNode::CookieTreeIndexedDBNode(
indexed_db_info_(indexed_db_info) {
}
+CookieTreeIndexedDBNode::~CookieTreeIndexedDBNode() {}
+
void CookieTreeIndexedDBNode::DeleteStoredObjects() {
GetModel()->indexed_db_helper_->DeleteIndexedDBFile(
indexed_db_info_->file_path);
}
+CookieTreeNode::DetailedInfo CookieTreeIndexedDBNode::GetDetailedInfo() const {
+ return DetailedInfo(GetParent()->GetParent()->GetTitle(),
+ DetailedInfo::TYPE_INDEXED_DB,
+ NULL, NULL, NULL, NULL, NULL, indexed_db_info_);
+}
+
///////////////////////////////////////////////////////////////////////////////
// CookieTreeRootNode, public:
+CookieTreeRootNode::CookieTreeRootNode(CookiesTreeModel* model)
+ : model_(model) {
+}
+
+CookieTreeRootNode::~CookieTreeRootNode() {}
+
CookieTreeOriginNode* CookieTreeRootNode::GetOrCreateOriginNode(
const GURL& url) {
CookieTreeOriginNode origin_node(url);
@@ -224,6 +278,16 @@ CookieTreeOriginNode* CookieTreeRootNode::GetOrCreateOriginNode(
return retval;
}
+CookiesTreeModel* CookieTreeRootNode::GetModel() const {
+ return model_;
+}
+
+CookieTreeNode::DetailedInfo CookieTreeRootNode::GetDetailedInfo() const {
+ return DetailedInfo(string16(),
+ DetailedInfo::TYPE_ROOT,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+}
+
///////////////////////////////////////////////////////////////////////////////
// CookieTreeOriginNode, public:
@@ -322,6 +386,15 @@ CookieTreeCookiesNode::CookieTreeCookiesNode()
: CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_COOKIES)) {
}
+CookieTreeCookiesNode::~CookieTreeCookiesNode() {
+}
+
+CookieTreeNode::DetailedInfo CookieTreeCookiesNode::GetDetailedInfo() const {
+ return DetailedInfo(GetParent()->GetTitle(),
+ DetailedInfo::TYPE_COOKIES,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+}
+
///////////////////////////////////////////////////////////////////////////////
// CookieTreeAppCachesNode, public:
@@ -330,6 +403,14 @@ CookieTreeAppCachesNode::CookieTreeAppCachesNode()
IDS_COOKIES_APPLICATION_CACHES)) {
}
+CookieTreeAppCachesNode::~CookieTreeAppCachesNode() {}
+
+CookieTreeNode::DetailedInfo CookieTreeAppCachesNode::GetDetailedInfo() const {
+ return DetailedInfo(GetParent()->GetTitle(),
+ DetailedInfo::TYPE_APPCACHES,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+}
+
///////////////////////////////////////////////////////////////////////////////
// CookieTreeDatabasesNode, public:
@@ -337,6 +418,14 @@ CookieTreeDatabasesNode::CookieTreeDatabasesNode()
: CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_WEB_DATABASES)) {
}
+CookieTreeDatabasesNode::~CookieTreeDatabasesNode() {}
+
+CookieTreeNode::DetailedInfo CookieTreeDatabasesNode::GetDetailedInfo() const {
+ return DetailedInfo(GetParent()->GetTitle(),
+ DetailedInfo::TYPE_DATABASES,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+}
+
///////////////////////////////////////////////////////////////////////////////
// CookieTreeLocalStoragesNode, public:
@@ -344,6 +433,15 @@ CookieTreeLocalStoragesNode::CookieTreeLocalStoragesNode()
: CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_LOCAL_STORAGE)) {
}
+CookieTreeLocalStoragesNode::~CookieTreeLocalStoragesNode() {}
+
+CookieTreeNode::DetailedInfo
+CookieTreeLocalStoragesNode::GetDetailedInfo() const {
+ return DetailedInfo(GetParent()->GetTitle(),
+ DetailedInfo::TYPE_LOCAL_STORAGES,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+}
+
///////////////////////////////////////////////////////////////////////////////
// CookieTreeSessionStoragesNode, public:
@@ -351,6 +449,15 @@ CookieTreeSessionStoragesNode::CookieTreeSessionStoragesNode()
: CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_SESSION_STORAGE)) {
}
+CookieTreeSessionStoragesNode::~CookieTreeSessionStoragesNode() {}
+
+CookieTreeNode::DetailedInfo
+CookieTreeSessionStoragesNode::GetDetailedInfo() const {
+ return DetailedInfo(GetParent()->GetTitle(),
+ DetailedInfo::TYPE_SESSION_STORAGES,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+}
+
///////////////////////////////////////////////////////////////////////////////
// CookieTreeIndexedDBsNode, public:
@@ -358,6 +465,15 @@ CookieTreeIndexedDBsNode::CookieTreeIndexedDBsNode()
: CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_INDEXED_DB)) {
}
+CookieTreeIndexedDBsNode::~CookieTreeIndexedDBsNode() {}
+
+CookieTreeNode::DetailedInfo
+CookieTreeIndexedDBsNode::GetDetailedInfo() const {
+ return DetailedInfo(GetParent()->GetTitle(),
+ DetailedInfo::TYPE_INDEXED_DBS,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+}
+
///////////////////////////////////////////////////////////////////////////////
// CookieTreeNode, protected
diff --git a/chrome/browser/cookies_tree_model.h b/chrome/browser/cookies_tree_model.h
index 40b29b8..20b2a71 100644
--- a/chrome/browser/cookies_tree_model.h
+++ b/chrome/browser/cookies_tree_model.h
@@ -162,20 +162,16 @@ class CookieTreeNode : public TreeNode<CookieTreeNode> {
// The node at the root of the CookieTree that gets inserted into the view.
class CookieTreeRootNode : public CookieTreeNode {
public:
- explicit CookieTreeRootNode(CookiesTreeModel* model) : model_(model) {}
- virtual ~CookieTreeRootNode() {}
+ explicit CookieTreeRootNode(CookiesTreeModel* model);
+ virtual ~CookieTreeRootNode();
CookieTreeOriginNode* GetOrCreateOriginNode(const GURL& url);
// CookieTreeNode methods:
- virtual CookiesTreeModel* GetModel() const { return model_; }
- virtual DetailedInfo GetDetailedInfo() const {
- return DetailedInfo(string16(),
- DetailedInfo::TYPE_ROOT,
- NULL, NULL, NULL, NULL, NULL, NULL);
- }
- private:
+ virtual CookiesTreeModel* GetModel() const;
+ virtual DetailedInfo GetDetailedInfo() const;
+ private:
CookiesTreeModel* model_;
DISALLOW_COPY_AND_ASSIGN(CookieTreeRootNode);
@@ -236,15 +232,11 @@ class CookieTreeCookieNode : public CookieTreeNode {
// Does not take ownership of cookie, and cookie should remain valid at least
// as long as the CookieTreeCookieNode is valid.
explicit CookieTreeCookieNode(net::CookieMonster::CanonicalCookie* cookie);
- virtual ~CookieTreeCookieNode() {}
+ virtual ~CookieTreeCookieNode();
// CookieTreeNode methods:
virtual void DeleteStoredObjects();
- virtual DetailedInfo GetDetailedInfo() const {
- return DetailedInfo(GetParent()->GetParent()->GetTitle(),
- DetailedInfo::TYPE_COOKIE,
- cookie_, NULL, NULL, NULL, NULL, NULL);
- }
+ virtual DetailedInfo GetDetailedInfo() const;
private:
// Cookie_ is not owned by the node, and is expected to remain valid as long
@@ -257,13 +249,9 @@ class CookieTreeCookieNode : public CookieTreeNode {
class CookieTreeCookiesNode : public CookieTreeNode {
public:
CookieTreeCookiesNode();
- virtual ~CookieTreeCookiesNode() {}
+ virtual ~CookieTreeCookiesNode();
- virtual DetailedInfo GetDetailedInfo() const {
- return DetailedInfo(GetParent()->GetTitle(),
- DetailedInfo::TYPE_COOKIES,
- NULL, NULL, NULL, NULL, NULL, NULL);
- }
+ virtual DetailedInfo GetDetailedInfo() const;
void AddCookieNode(CookieTreeCookieNode* child) {
AddChildSortedByTitle(child);
@@ -285,11 +273,7 @@ class CookieTreeAppCacheNode : public CookieTreeNode {
virtual ~CookieTreeAppCacheNode() {}
virtual void DeleteStoredObjects();
- virtual DetailedInfo GetDetailedInfo() const {
- return DetailedInfo(GetParent()->GetParent()->GetTitle(),
- DetailedInfo::TYPE_APPCACHE,
- NULL, NULL, NULL, NULL, appcache_info_, NULL);
- }
+ virtual DetailedInfo GetDetailedInfo() const;
private:
const appcache::AppCacheInfo* appcache_info_;
@@ -299,13 +283,9 @@ class CookieTreeAppCacheNode : public CookieTreeNode {
class CookieTreeAppCachesNode : public CookieTreeNode {
public:
CookieTreeAppCachesNode();
- virtual ~CookieTreeAppCachesNode() {}
+ virtual ~CookieTreeAppCachesNode();
- virtual DetailedInfo GetDetailedInfo() const {
- return DetailedInfo(GetParent()->GetTitle(),
- DetailedInfo::TYPE_APPCACHES,
- NULL, NULL, NULL, NULL, NULL, NULL);
- }
+ virtual DetailedInfo GetDetailedInfo() const;
void AddAppCacheNode(CookieTreeAppCacheNode* child) {
AddChildSortedByTitle(child);
@@ -324,14 +304,10 @@ class CookieTreeDatabaseNode : public CookieTreeNode {
// valid at least as long as the CookieTreeDatabaseNode is valid.
explicit CookieTreeDatabaseNode(
BrowsingDataDatabaseHelper::DatabaseInfo* database_info);
- virtual ~CookieTreeDatabaseNode() {}
+ virtual ~CookieTreeDatabaseNode();
virtual void DeleteStoredObjects();
- virtual DetailedInfo GetDetailedInfo() const {
- return DetailedInfo(GetParent()->GetParent()->GetTitle(),
- DetailedInfo::TYPE_DATABASE,
- NULL, database_info_, NULL, NULL, NULL, NULL);
- }
+ virtual DetailedInfo GetDetailedInfo() const;
private:
// database_info_ is not owned by the node, and is expected to remain
@@ -344,13 +320,9 @@ class CookieTreeDatabaseNode : public CookieTreeNode {
class CookieTreeDatabasesNode : public CookieTreeNode {
public:
CookieTreeDatabasesNode();
- virtual ~CookieTreeDatabasesNode() {}
+ virtual ~CookieTreeDatabasesNode();
- virtual DetailedInfo GetDetailedInfo() const {
- return DetailedInfo(GetParent()->GetTitle(),
- DetailedInfo::TYPE_DATABASES,
- NULL, NULL, NULL, NULL, NULL, NULL);
- }
+ virtual DetailedInfo GetDetailedInfo() const;
void AddDatabaseNode(CookieTreeDatabaseNode* child) {
AddChildSortedByTitle(child);
@@ -369,15 +341,11 @@ class CookieTreeLocalStorageNode : public CookieTreeNode {
// valid.
explicit CookieTreeLocalStorageNode(
BrowsingDataLocalStorageHelper::LocalStorageInfo* local_storage_info);
- virtual ~CookieTreeLocalStorageNode() {}
+ virtual ~CookieTreeLocalStorageNode();
// CookieTreeNode methods:
virtual void DeleteStoredObjects();
- virtual DetailedInfo GetDetailedInfo() const {
- return DetailedInfo(GetParent()->GetParent()->GetTitle(),
- DetailedInfo::TYPE_LOCAL_STORAGE,
- NULL, NULL, local_storage_info_, NULL, NULL, NULL);
- }
+ virtual DetailedInfo GetDetailedInfo() const;
private:
// local_storage_info_ is not owned by the node, and is expected to remain
@@ -390,13 +358,9 @@ class CookieTreeLocalStorageNode : public CookieTreeNode {
class CookieTreeLocalStoragesNode : public CookieTreeNode {
public:
CookieTreeLocalStoragesNode();
- virtual ~CookieTreeLocalStoragesNode() {}
+ virtual ~CookieTreeLocalStoragesNode();
- virtual DetailedInfo GetDetailedInfo() const {
- return DetailedInfo(GetParent()->GetTitle(),
- DetailedInfo::TYPE_LOCAL_STORAGES,
- NULL, NULL, NULL, NULL, NULL, NULL);
- }
+ virtual DetailedInfo GetDetailedInfo() const;
void AddLocalStorageNode(CookieTreeLocalStorageNode* child) {
AddChildSortedByTitle(child);
@@ -416,14 +380,10 @@ class CookieTreeSessionStorageNode : public CookieTreeNode {
// is valid.
explicit CookieTreeSessionStorageNode(
BrowsingDataLocalStorageHelper::LocalStorageInfo* session_storage_info);
- virtual ~CookieTreeSessionStorageNode() {}
+ virtual ~CookieTreeSessionStorageNode();
// CookieTreeNode methods:
- virtual DetailedInfo GetDetailedInfo() const {
- return DetailedInfo(GetParent()->GetParent()->GetTitle(),
- DetailedInfo::TYPE_SESSION_STORAGE,
- NULL, NULL, NULL, session_storage_info_, NULL, NULL);
- }
+ virtual DetailedInfo GetDetailedInfo() const;
private:
// session_storage_info_ is not owned by the node, and is expected to remain
@@ -436,13 +396,9 @@ class CookieTreeSessionStorageNode : public CookieTreeNode {
class CookieTreeSessionStoragesNode : public CookieTreeNode {
public:
CookieTreeSessionStoragesNode();
- virtual ~CookieTreeSessionStoragesNode() {}
+ virtual ~CookieTreeSessionStoragesNode();
- virtual DetailedInfo GetDetailedInfo() const {
- return DetailedInfo(GetParent()->GetTitle(),
- DetailedInfo::TYPE_SESSION_STORAGES,
- NULL, NULL, NULL, NULL, NULL, NULL);
- }
+ virtual DetailedInfo GetDetailedInfo() const;
void AddSessionStorageNode(CookieTreeSessionStorageNode* child) {
AddChildSortedByTitle(child);
@@ -461,15 +417,11 @@ class CookieTreeIndexedDBNode : public CookieTreeNode {
// is valid.
explicit CookieTreeIndexedDBNode(
BrowsingDataIndexedDBHelper::IndexedDBInfo* indexed_db_info);
- virtual ~CookieTreeIndexedDBNode() {}
+ virtual ~CookieTreeIndexedDBNode();
// CookieTreeNode methods:
virtual void DeleteStoredObjects();
- virtual DetailedInfo GetDetailedInfo() const {
- return DetailedInfo(GetParent()->GetParent()->GetTitle(),
- DetailedInfo::TYPE_INDEXED_DB,
- NULL, NULL, NULL, NULL, NULL, indexed_db_info_);
- }
+ virtual DetailedInfo GetDetailedInfo() const;
private:
// indexed_db_info_ is not owned by the node, and is expected to remain
@@ -482,13 +434,9 @@ class CookieTreeIndexedDBNode : public CookieTreeNode {
class CookieTreeIndexedDBsNode : public CookieTreeNode {
public:
CookieTreeIndexedDBsNode();
- virtual ~CookieTreeIndexedDBsNode() {}
+ virtual ~CookieTreeIndexedDBsNode();
- virtual DetailedInfo GetDetailedInfo() const {
- return DetailedInfo(GetParent()->GetTitle(),
- DetailedInfo::TYPE_INDEXED_DBS,
- NULL, NULL, NULL, NULL, NULL, NULL);
- }
+ virtual DetailedInfo GetDetailedInfo() const;
void AddIndexedDBNode(CookieTreeIndexedDBNode* child) {
AddChildSortedByTitle(child);
@@ -555,7 +503,7 @@ class CookiesTreeModel : public TreeNodeModel<CookieTreeNode> {
COOKIE = 1,
DATABASE = 2
};
- typedef net::CookieMonster::CookieList CookieList;
+ typedef net::CookieList CookieList;
typedef std::vector<BrowsingDataDatabaseHelper::DatabaseInfo>
DatabaseInfoList;
typedef std::vector<BrowsingDataLocalStorageHelper::LocalStorageInfo>
diff --git a/chrome/browser/cookies_tree_model_unittest.cc b/chrome/browser/cookies_tree_model_unittest.cc
index 55888c1..8d03b2a 100644
--- a/chrome/browser/cookies_tree_model_unittest.cc
+++ b/chrome/browser/cookies_tree_model_unittest.cc
@@ -6,14 +6,13 @@
#include <string>
-#include "chrome/browser/host_content_settings_map.h"
+#include "chrome/browser/content_settings/host_content_settings_map_unittest.h"
#include "chrome/browser/mock_browsing_data_appcache_helper.h"
#include "chrome/browser/mock_browsing_data_database_helper.h"
#include "chrome/browser/mock_browsing_data_indexed_db_helper.h"
#include "chrome/browser/mock_browsing_data_local_storage_helper.h"
#include "chrome/common/net/url_request_context_getter.h"
#include "chrome/common/notification_details.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "chrome/test/testing_profile.h"
#include "net/url_request/url_request_context.h"
@@ -22,29 +21,6 @@
namespace {
-class StubSettingsObserver : public NotificationObserver {
- public:
- StubSettingsObserver() : counter(0) {
- registrar_.Add(this, NotificationType::CONTENT_SETTINGS_CHANGED,
- NotificationService::AllSources());
- }
-
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- ++counter;
- Details<HostContentSettingsMap::ContentSettingsDetails>
- settings_details(details);
- last_pattern = settings_details.ptr()->pattern();
- }
-
- HostContentSettingsMap::Pattern last_pattern;
- int counter;
-
- private:
- NotificationRegistrar registrar_;
-};
-
class CookiesTreeModelTest : public testing::Test {
public:
CookiesTreeModelTest() : ui_thread_(BrowserThread::UI, &message_loop_),
@@ -120,7 +96,7 @@ class CookiesTreeModelTest : public testing::Test {
// EXPECT_STREQ("Y,X", GetMonsterCookies(monster).c_str());
std::string GetMonsterCookies(net::CookieMonster* monster) {
std::vector<std::string> parts;
- net::CookieMonster::CookieList cookie_list = monster->GetAllCookies();
+ net::CookieList cookie_list = monster->GetAllCookies();
for (size_t i = 0; i < cookie_list.size(); ++i)
parts.push_back(cookie_list[i].Name());
return JoinString(parts, ',');
@@ -670,7 +646,7 @@ TEST_F(CookiesTreeModelTest, OriginOrdering) {
TEST_F(CookiesTreeModelTest, ContentSettings) {
GURL host("http://example.com/");
- HostContentSettingsMap::Pattern pattern("[*.]example.com");
+ ContentSettingsPattern pattern("[*.]example.com");
net::CookieMonster* monster = profile_->GetCookieMonster();
monster->SetCookie(host, "A=1");
diff --git a/chrome/browser/crash_handler_host_linux.cc b/chrome/browser/crash_handler_host_linux.cc
index a941cdd..196352a 100644
--- a/chrome/browser/crash_handler_host_linux.cc
+++ b/chrome/browser/crash_handler_host_linux.cc
@@ -19,6 +19,7 @@
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/rand_util.h"
+#include "base/singleton.h"
#include "base/string_util.h"
#include "base/task.h"
#include "base/thread.h"
@@ -118,20 +119,23 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
static const unsigned kCrashContextSize =
sizeof(ExceptionHandler::CrashContext);
+ const size_t kIovSize = 7;
struct msghdr msg = {0};
- struct iovec iov[6];
+ struct iovec iov[kIovSize];
char crash_context[kCrashContextSize];
char* guid = new char[kGuidSize + 1];
char* crash_url = new char[kMaxActiveURLSize + 1];
char* distro = new char[kDistroSize + 1];
char* tid_buf_addr = NULL;
int tid_fd = -1;
+ uint64_t uptime;
char control[kControlMsgSize];
const ssize_t expected_msg_size = sizeof(crash_context) +
kGuidSize + 1 +
kMaxActiveURLSize + 1 +
kDistroSize + 1 +
- sizeof(tid_buf_addr) + sizeof(tid_fd);
+ sizeof(tid_buf_addr) + sizeof(tid_fd) +
+ sizeof(uptime);
iov[0].iov_base = crash_context;
iov[0].iov_len = sizeof(crash_context);
@@ -145,8 +149,10 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
iov[4].iov_len = sizeof(tid_buf_addr);
iov[5].iov_base = &tid_fd;
iov[5].iov_len = sizeof(tid_fd);
+ iov[6].iov_base = &uptime;
+ iov[6].iov_len = sizeof(uptime);
msg.msg_iov = iov;
- msg.msg_iovlen = 6;
+ msg.msg_iovlen = kIovSize;
msg.msg_control = control;
msg.msg_controllen = kControlMsgSize;
@@ -328,6 +334,7 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
info->distro = distro;
info->upload = upload;
+ info->process_start_time = uptime;
uploader_thread_->message_loop()->PostTask(
FROM_HERE,
@@ -358,6 +365,11 @@ void PluginCrashHandlerHostLinux::SetProcessType() {
process_type_ = "plugin";
}
+// static
+PluginCrashHandlerHostLinux* PluginCrashHandlerHostLinux::GetInstance() {
+ return Singleton<PluginCrashHandlerHostLinux>::get();
+}
+
RendererCrashHandlerHostLinux::RendererCrashHandlerHostLinux() {
InitCrashUploaderThread();
}
@@ -368,3 +380,8 @@ RendererCrashHandlerHostLinux::~RendererCrashHandlerHostLinux() {
void RendererCrashHandlerHostLinux::SetProcessType() {
process_type_ = "renderer";
}
+
+// static
+RendererCrashHandlerHostLinux* RendererCrashHandlerHostLinux::GetInstance() {
+ return Singleton<RendererCrashHandlerHostLinux>::get();
+}
diff --git a/chrome/browser/crash_handler_host_linux.h b/chrome/browser/crash_handler_host_linux.h
index bc2214b..9ff5333 100644
--- a/chrome/browser/crash_handler_host_linux.h
+++ b/chrome/browser/crash_handler_host_linux.h
@@ -10,7 +10,8 @@
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
-#include "base/singleton.h"
+
+template <typename T> struct DefaultSingletonTraits;
namespace base {
class Thread;
@@ -79,6 +80,10 @@ class CrashHandlerHostLinux : public MessageLoopForIO::Watcher,
};
class PluginCrashHandlerHostLinux : public CrashHandlerHostLinux {
+ public:
+ // Returns the singleton instance.
+ static PluginCrashHandlerHostLinux* GetInstance();
+
private:
friend struct DefaultSingletonTraits<PluginCrashHandlerHostLinux>;
PluginCrashHandlerHostLinux();
@@ -92,6 +97,10 @@ class PluginCrashHandlerHostLinux : public CrashHandlerHostLinux {
};
class RendererCrashHandlerHostLinux : public CrashHandlerHostLinux {
+ public:
+ // Returns the singleton instance.
+ static RendererCrashHandlerHostLinux* GetInstance();
+
private:
friend struct DefaultSingletonTraits<RendererCrashHandlerHostLinux>;
RendererCrashHandlerHostLinux();
diff --git a/chrome/browser/crash_handler_host_linux_stub.cc b/chrome/browser/crash_handler_host_linux_stub.cc
index 6835bc2..157d772 100644
--- a/chrome/browser/crash_handler_host_linux_stub.cc
+++ b/chrome/browser/crash_handler_host_linux_stub.cc
@@ -7,6 +7,8 @@
#include "chrome/browser/crash_handler_host_linux.h"
+#include "base/singleton.h"
+
CrashHandlerHostLinux::CrashHandlerHostLinux()
: process_socket_(-1),
browser_socket_(-1) {
@@ -30,8 +32,18 @@ PluginCrashHandlerHostLinux::PluginCrashHandlerHostLinux() {
PluginCrashHandlerHostLinux::~PluginCrashHandlerHostLinux() {
}
+// static
+PluginCrashHandlerHostLinux* PluginCrashHandlerHostLinux::GetInstance() {
+ return Singleton<PluginCrashHandlerHostLinux>::get();
+}
+
RendererCrashHandlerHostLinux::RendererCrashHandlerHostLinux() {
}
RendererCrashHandlerHostLinux::~RendererCrashHandlerHostLinux() {
}
+
+// static
+RendererCrashHandlerHostLinux* RendererCrashHandlerHostLinux::GetInstance() {
+ return Singleton<RendererCrashHandlerHostLinux>::get();
+}
diff --git a/chrome/browser/crash_recovery_browsertest.cc b/chrome/browser/crash_recovery_browsertest.cc
index feaf61d..92b5393 100644
--- a/chrome/browser/crash_recovery_browsertest.cc
+++ b/chrome/browser/crash_recovery_browsertest.cc
@@ -4,7 +4,6 @@
#include "base/file_path.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/page_transition_types.h"
diff --git a/chrome/browser/cross_site_request_manager.cc b/chrome/browser/cross_site_request_manager.cc
index 4104398..d12e9a4 100644
--- a/chrome/browser/cross_site_request_manager.cc
+++ b/chrome/browser/cross_site_request_manager.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/cross_site_request_manager.h"
+#include "base/singleton.h"
+
bool CrossSiteRequestManager::HasPendingCrossSiteRequest(int renderer_id,
int render_view_id) {
AutoLock lock(lock_);
@@ -29,3 +31,8 @@ void CrossSiteRequestManager::SetHasPendingCrossSiteRequest(int renderer_id,
CrossSiteRequestManager::CrossSiteRequestManager() {}
CrossSiteRequestManager::~CrossSiteRequestManager() {}
+
+// static
+CrossSiteRequestManager* CrossSiteRequestManager::GetInstance() {
+ return Singleton<CrossSiteRequestManager>::get();
+}
diff --git a/chrome/browser/cross_site_request_manager.h b/chrome/browser/cross_site_request_manager.h
index 84d07e9..6c90b24 100644
--- a/chrome/browser/cross_site_request_manager.h
+++ b/chrome/browser/cross_site_request_manager.h
@@ -11,7 +11,8 @@
#include "base/basictypes.h"
#include "base/lock.h"
-#include "base/singleton.h"
+
+template <typename T> struct DefaultSingletonTraits;
// CrossSiteRequestManager is used to handle bookkeeping for cross-site
// requests and responses between the UI and IO threads. Such requests involve
@@ -22,6 +23,9 @@
//
class CrossSiteRequestManager {
public:
+ // Returns the singleton instance.
+ static CrossSiteRequestManager* GetInstance();
+
// Returns whether the RenderViewHost specified by the given IDs currently
// has a pending cross-site request. If so, we will have to delay the
// response until the previous RenderViewHost runs its onunload handler.
@@ -38,8 +42,6 @@ class CrossSiteRequestManager {
friend struct DefaultSingletonTraits<CrossSiteRequestManager>;
typedef std::set<std::pair<int, int> > RenderViewSet;
- // Obtain an instance of CrossSiteRequestManager via
- // Singleton<CrossSiteRequestManager>().
CrossSiteRequestManager();
~CrossSiteRequestManager();
diff --git a/chrome/browser/custom_home_pages_table_model.cc b/chrome/browser/custom_home_pages_table_model.cc
index 53fd565..f7c9a92 100644
--- a/chrome/browser/custom_home_pages_table_model.cc
+++ b/chrome/browser/custom_home_pages_table_model.cc
@@ -11,7 +11,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/pref_names.h"
diff --git a/chrome/browser/debugger/debugger_remote_service.cc b/chrome/browser/debugger/debugger_remote_service.cc
index 3d102d5..e2ea5f2 100644
--- a/chrome/browser/debugger/debugger_remote_service.cc
+++ b/chrome/browser/debugger/debugger_remote_service.cc
@@ -12,7 +12,6 @@
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/debugger/devtools_protocol_handler.h"
#include "chrome/browser/debugger/devtools_remote_message.h"
diff --git a/chrome/browser/debugger/devtools_client_host.cc b/chrome/browser/debugger/devtools_client_host.cc
new file mode 100644
index 0000000..f619bfb
--- /dev/null
+++ b/chrome/browser/debugger/devtools_client_host.cc
@@ -0,0 +1,16 @@
+// Copyright (c) 2009 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 "chrome/browser/debugger/devtools_client_host.h"
+
+DevToolsWindow* DevToolsClientHost::AsDevToolsWindow() {
+ return NULL;
+}
+
+void DevToolsClientHost::NotifyCloseListener() {
+ if (close_listener_) {
+ close_listener_->ClientHostClosing(this);
+ close_listener_ = NULL;
+ }
+}
diff --git a/chrome/browser/debugger/devtools_client_host.h b/chrome/browser/debugger/devtools_client_host.h
index e62237d..952f532 100644
--- a/chrome/browser/debugger/devtools_client_host.h
+++ b/chrome/browser/debugger/devtools_client_host.h
@@ -41,19 +41,14 @@ class DevToolsClientHost {
close_listener_ = listener;
}
- virtual DevToolsWindow* AsDevToolsWindow() { return NULL; }
+ virtual DevToolsWindow* AsDevToolsWindow();
protected:
DevToolsClientHost() : close_listener_(NULL) {}
// Should be called when the devtools client is going to die and this
// DevToolsClientHost should not be used anymore.
- void NotifyCloseListener() {
- if (close_listener_) {
- close_listener_->ClientHostClosing(this);
- close_listener_ = NULL;
- }
- }
+ void NotifyCloseListener();
private:
CloseListener* close_listener_;
diff --git a/chrome/browser/debugger/devtools_http_protocol_handler.cc b/chrome/browser/debugger/devtools_http_protocol_handler.cc
index 5327008..1aaf18b 100644
--- a/chrome/browser/debugger/devtools_http_protocol_handler.cc
+++ b/chrome/browser/debugger/devtools_http_protocol_handler.cc
@@ -14,11 +14,11 @@
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/debugger/devtools_client_host.h"
#include "chrome/browser/debugger/devtools_manager.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/tab_contents_wrapper.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/devtools_messages.h"
#include "chrome/common/net/url_request_context_getter.h"
#include "googleurl/src/gurl.h"
@@ -108,7 +108,8 @@ void DevToolsHttpProtocolHandler::OnHttpRequest(
}
// Proxy static files from chrome://devtools/*.
- URLRequest* request = new URLRequest(GURL("chrome:/" + info.path), this);
+ net::URLRequest* request = new net::URLRequest(
+ GURL("chrome:/" + info.path), this);
Bind(request, socket);
request->set_context(
Profile::GetDefaultRequestContext()->GetURLRequestContext());
@@ -144,9 +145,9 @@ void DevToolsHttpProtocolHandler::OnClose(HttpListenSocket* socket) {
SocketToRequestsMap::iterator it = socket_to_requests_io_.find(socket);
if (it != socket_to_requests_io_.end()) {
// Dispose delegating socket.
- for (std::set<URLRequest*>::iterator it2 = it->second.begin();
+ for (std::set<net::URLRequest*>::iterator it2 = it->second.begin();
it2 != it->second.end(); ++it2) {
- URLRequest* request = *it2;
+ net::URLRequest* request = *it2;
request->Cancel();
request_to_socket_io_.erase(request);
request_to_buffer_io_.erase(request);
@@ -155,15 +156,13 @@ void DevToolsHttpProtocolHandler::OnClose(HttpListenSocket* socket) {
socket_to_requests_io_.erase(socket);
}
- // This can't use make_scoped_refptr because |socket| is already deleted
- // when this runs -- http://crbug.com/59930
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
NewRunnableMethod(
this,
&DevToolsHttpProtocolHandler::OnCloseUI,
- socket));
+ make_scoped_refptr(socket)));
}
void DevToolsHttpProtocolHandler::OnHttpRequestUI(
@@ -264,16 +263,28 @@ void DevToolsHttpProtocolHandler::OnWebSocketMessageUI(
void DevToolsHttpProtocolHandler::OnCloseUI(HttpListenSocket* socket) {
SocketToClientHostMap::iterator it = socket_to_client_host_ui_.find(socket);
- if (it == socket_to_client_host_ui_.end())
- return;
- DevToolsClientHostImpl* client_host =
- static_cast<DevToolsClientHostImpl*>(it->second);
- client_host->NotifyCloseListener();
- delete client_host;
- socket_to_client_host_ui_.erase(socket);
+ if (it != socket_to_client_host_ui_.end()) {
+ DevToolsClientHostImpl* client_host =
+ static_cast<DevToolsClientHostImpl*>(it->second);
+ client_host->NotifyCloseListener();
+ delete client_host;
+ socket_to_client_host_ui_.erase(socket);
+ }
+
+ // We are holding last reference to scoped refptr 'socket' here.
+ // We can't exit method just like that since 'socket' is going to
+ // be destroyed on the UI thread then. Schedule no-op to IO thread
+ // so that socket is destroyed on IO instead.
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &DevToolsHttpProtocolHandler::ReleaseSocket,
+ make_scoped_refptr(socket)));
}
-void DevToolsHttpProtocolHandler::OnResponseStarted(URLRequest* request) {
+void DevToolsHttpProtocolHandler::OnResponseStarted(net::URLRequest* request) {
RequestToSocketMap::iterator it = request_to_socket_io_.find(request);
if (it == request_to_socket_io_.end())
return;
@@ -307,7 +318,7 @@ void DevToolsHttpProtocolHandler::OnResponseStarted(URLRequest* request) {
OnReadCompleted(request, bytes_read);
}
-void DevToolsHttpProtocolHandler::OnReadCompleted(URLRequest* request,
+void DevToolsHttpProtocolHandler::OnReadCompleted(net::URLRequest* request,
int bytes_read) {
RequestToSocketMap::iterator it = request_to_socket_io_.find(request);
if (it == request_to_socket_io_.end())
@@ -341,21 +352,21 @@ void DevToolsHttpProtocolHandler::Teardown() {
server_ = NULL;
}
-void DevToolsHttpProtocolHandler::Bind(URLRequest* request,
+void DevToolsHttpProtocolHandler::Bind(net::URLRequest* request,
HttpListenSocket* socket) {
request_to_socket_io_[request] = socket;
SocketToRequestsMap::iterator it = socket_to_requests_io_.find(socket);
if (it == socket_to_requests_io_.end()) {
- std::pair<HttpListenSocket*, std::set<URLRequest*> > value(
+ std::pair<HttpListenSocket*, std::set<net::URLRequest*> > value(
socket,
- std::set<URLRequest*>());
+ std::set<net::URLRequest*>());
it = socket_to_requests_io_.insert(value).first;
}
it->second.insert(request);
request_to_buffer_io_[request] = new net::IOBuffer(kBufferSize);
}
-void DevToolsHttpProtocolHandler::RequestCompleted(URLRequest* request) {
+void DevToolsHttpProtocolHandler::RequestCompleted(net::URLRequest* request) {
RequestToSocketMap::iterator it = request_to_socket_io_.find(request);
if (it == request_to_socket_io_.end())
return;
@@ -405,6 +416,11 @@ void DevToolsHttpProtocolHandler::AcceptWebSocket(
request));
}
+void DevToolsHttpProtocolHandler::ReleaseSocket(
+ HttpListenSocket* socket) {
+ // This in fact is scoped ref ptr. It'll get nuked on exit.
+}
+
TabContents* DevToolsHttpProtocolHandler::GetTabContents(int session_id) {
for (BrowserList::const_iterator it = BrowserList::begin(),
end = BrowserList::end(); it != end; ++it) {
diff --git a/chrome/browser/debugger/devtools_http_protocol_handler.h b/chrome/browser/debugger/devtools_http_protocol_handler.h
index 332fbaa..c5c485f 100644
--- a/chrome/browser/debugger/devtools_http_protocol_handler.h
+++ b/chrome/browser/debugger/devtools_http_protocol_handler.h
@@ -19,7 +19,7 @@ class TabContents;
class DevToolsHttpProtocolHandler
: public HttpListenSocket::Delegate,
- public URLRequest::Delegate,
+ public net::URLRequest::Delegate,
public base::RefCountedThreadSafe<DevToolsHttpProtocolHandler> {
public:
explicit DevToolsHttpProtocolHandler(int port);
@@ -51,14 +51,14 @@ class DevToolsHttpProtocolHandler
const std::string& data);
virtual void OnCloseUI(HttpListenSocket* socket);
- // URLRequest::Delegate implementation.
- virtual void OnResponseStarted(URLRequest* request);
- virtual void OnReadCompleted(URLRequest* request, int bytes_read);
+ // net::URLRequest::Delegate implementation.
+ virtual void OnResponseStarted(net::URLRequest* request);
+ virtual void OnReadCompleted(net::URLRequest* request, int bytes_read);
void Init();
void Teardown();
- void Bind(URLRequest* request, HttpListenSocket* socket);
- void RequestCompleted(URLRequest* request);
+ void Bind(net::URLRequest* request, HttpListenSocket* socket);
+ void RequestCompleted(net::URLRequest* request);
void Send200(HttpListenSocket* socket,
const std::string& data,
@@ -68,18 +68,19 @@ class DevToolsHttpProtocolHandler
const std::string& message);
void AcceptWebSocket(HttpListenSocket* socket,
const HttpServerRequestInfo& request);
+ void ReleaseSocket(HttpListenSocket* socket);
TabContents* GetTabContents(int session_id);
int port_;
scoped_refptr<HttpListenSocket> server_;
- typedef std::map<URLRequest*, HttpListenSocket*>
+ typedef std::map<net::URLRequest*, HttpListenSocket*>
RequestToSocketMap;
RequestToSocketMap request_to_socket_io_;
- typedef std::map<HttpListenSocket*, std::set<URLRequest*> >
+ typedef std::map<HttpListenSocket*, std::set<net::URLRequest*> >
SocketToRequestsMap;
SocketToRequestsMap socket_to_requests_io_;
- typedef std::map<URLRequest*, scoped_refptr<net::IOBuffer> >
+ typedef std::map<net::URLRequest*, scoped_refptr<net::IOBuffer> >
BuffersMap;
BuffersMap request_to_buffer_io_;
typedef std::map<HttpListenSocket*, DevToolsClientHost*>
diff --git a/chrome/browser/debugger/devtools_manager.cc b/chrome/browser/debugger/devtools_manager.cc
index 86d7e52..e8e69e1 100644
--- a/chrome/browser/debugger/devtools_manager.cc
+++ b/chrome/browser/debugger/devtools_manager.cc
@@ -16,10 +16,10 @@
#include "chrome/browser/debugger/devtools_window.h"
#include "chrome/browser/io_thread.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/site_instance.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "googleurl/src/gurl.h"
diff --git a/chrome/browser/debugger/devtools_netlog_observer.cc b/chrome/browser/debugger/devtools_netlog_observer.cc
index 35368a1..0c2bb3e 100644
--- a/chrome/browser/debugger/devtools_netlog_observer.cc
+++ b/chrome/browser/debugger/devtools_netlog_observer.cc
@@ -19,7 +19,7 @@ const size_t kMaxNumEntries = 1000;
DevToolsNetLogObserver* DevToolsNetLogObserver::instance_ = NULL;
DevToolsNetLogObserver::DevToolsNetLogObserver(ChromeNetLog* chrome_net_log)
- : ChromeNetLog::Observer(net::NetLog::LOG_ALL_BUT_BYTES),
+ : ChromeNetLog::ThreadSafeObserver(net::NetLog::LOG_ALL_BUT_BYTES),
chrome_net_log_(chrome_net_log) {
chrome_net_log_->AddObserver(this);
}
@@ -41,10 +41,14 @@ void DevToolsNetLogObserver::OnAddEntry(net::NetLog::EventType type,
const net::NetLog::Source& source,
net::NetLog::EventPhase phase,
net::NetLog::EventParameters* params) {
+ // The events that the Observer is interested in only occur on the IO thread.
+ if (!BrowserThread::CurrentlyOn(BrowserThread::IO))
+ return;
+
if (type == net::NetLog::TYPE_URL_REQUEST_START_JOB) {
if (phase != net::NetLog::PHASE_BEGIN)
return;
- int load_flags = static_cast<URLRequestStartEventParameters*>(params)->
+ int load_flags = static_cast<net::URLRequestStartEventParameters*>(params)->
load_flags();
if (!(load_flags & net::LOAD_REPORT_RAW_HEADERS))
return;
@@ -108,7 +112,7 @@ void DevToolsNetLogObserver::Attach(IOThread* io_thread) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DCHECK(!instance_);
- instance_ = new DevToolsNetLogObserver(io_thread->globals()->net_log.get());
+ instance_ = new DevToolsNetLogObserver(io_thread->net_log());
}
void DevToolsNetLogObserver::Detach() {
@@ -126,7 +130,7 @@ DevToolsNetLogObserver* DevToolsNetLogObserver::GetInstance() {
}
// static
-void DevToolsNetLogObserver::PopulateResponseInfo(URLRequest* request,
+void DevToolsNetLogObserver::PopulateResponseInfo(net::URLRequest* request,
ResourceResponse* response) {
if (!(request->load_flags() & net::LOAD_REPORT_RAW_HEADERS))
return;
diff --git a/chrome/browser/debugger/devtools_netlog_observer.h b/chrome/browser/debugger/devtools_netlog_observer.h
index 2fad712..d6ce2a4 100644
--- a/chrome/browser/debugger/devtools_netlog_observer.h
+++ b/chrome/browser/debugger/devtools_netlog_observer.h
@@ -21,11 +21,15 @@ struct ResourceResponse;
// DevToolsNetLogObserver watches the NetLog event stream and collects the
// stuff that may be of interest to DevTools. Currently, this only includes
// actual HTTP/SPDY headers sent and received over the network.
-class DevToolsNetLogObserver: public ChromeNetLog::Observer {
+//
+// As DevToolsNetLogObserver shares live data with objects that live on the
+// IO Thread, it must also reside on the IO Thread. Only OnAddEntry can be
+// called from other threads.
+class DevToolsNetLogObserver: public ChromeNetLog::ThreadSafeObserver {
typedef webkit_glue::ResourceDevToolsInfo ResourceInfo;
public:
- // Observer implementation:
+ // ThreadSafeObserver implementation:
virtual void OnAddEntry(net::NetLog::EventType type,
const base::TimeTicks& time,
const net::NetLog::Source& source,
diff --git a/chrome/browser/debugger/devtools_protocol_handler.cc b/chrome/browser/debugger/devtools_protocol_handler.cc
index 3d5300e..6e72ef0 100644
--- a/chrome/browser/debugger/devtools_protocol_handler.cc
+++ b/chrome/browser/debugger/devtools_protocol_handler.cc
@@ -9,7 +9,6 @@
#include "chrome/browser/debugger/inspectable_tab_proxy.h"
#include "chrome/browser/debugger/devtools_remote_message.h"
#include "chrome/browser/debugger/devtools_remote_listen_socket.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
DevToolsProtocolHandler::DevToolsProtocolHandler(int port)
: port_(port),
diff --git a/chrome/browser/debugger/devtools_remote_listen_socket.cc b/chrome/browser/debugger/devtools_remote_listen_socket.cc
index 8ea1821..3ac15ae 100644
--- a/chrome/browser/debugger/devtools_remote_listen_socket.cc
+++ b/chrome/browser/debugger/devtools_remote_listen_socket.cc
@@ -206,6 +206,10 @@ void DevToolsRemoteListenSocket::HandleMessage() {
}
}
+void DevToolsRemoteListenSocket::Listen() {
+ ListenSocket::Listen();
+}
+
void DevToolsRemoteListenSocket::Accept() {
SOCKET conn = ListenSocket::Accept(socket_);
if (conn != INVALID_SOCKET) {
diff --git a/chrome/browser/debugger/devtools_remote_listen_socket.h b/chrome/browser/debugger/devtools_remote_listen_socket.h
index 5497861..28c3f1f 100644
--- a/chrome/browser/debugger/devtools_remote_listen_socket.h
+++ b/chrome/browser/debugger/devtools_remote_listen_socket.h
@@ -26,7 +26,7 @@ class DevToolsRemoteListenSocket : public ListenSocket,
DevToolsRemoteListener* message_listener);
protected:
- virtual void Listen() { ListenSocket::Listen(); }
+ virtual void Listen();
virtual void Accept();
virtual void Close();
virtual void SendInternal(const char* bytes, int len);
diff --git a/chrome/browser/debugger/devtools_remote_service.cc b/chrome/browser/debugger/devtools_remote_service.cc
index d67174c..2c37917 100644
--- a/chrome/browser/debugger/devtools_remote_service.cc
+++ b/chrome/browser/debugger/devtools_remote_service.cc
@@ -2,15 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "chrome/browser/debugger/devtools_remote_service.h"
+
+#include <string>
+
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/scoped_ptr.h"
#include "base/values.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/debugger/devtools_protocol_handler.h"
#include "chrome/browser/debugger/devtools_remote_message.h"
-#include "chrome/browser/debugger/devtools_remote_service.h"
#include "chrome/browser/debugger/inspectable_tab_proxy.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
diff --git a/chrome/browser/debugger/devtools_sanity_unittest.cc b/chrome/browser/debugger/devtools_sanity_unittest.cc
index 05a0d0e..458be02 100644
--- a/chrome/browser/debugger/devtools_sanity_unittest.cc
+++ b/chrome/browser/debugger/devtools_sanity_unittest.cc
@@ -10,8 +10,8 @@
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/debugger/devtools_window.h"
#include "chrome/browser/extensions/extension_host.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
@@ -189,7 +189,7 @@ class DevToolsExtensionDebugTest : public DevToolsSanityTest,
private:
bool LoadExtensionFromPath(const FilePath& path) {
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
size_t num_before = service->extensions()->size();
{
NotificationRegistrar registrar;
@@ -273,9 +273,8 @@ IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, MAYBE_TestEnableResourcesTab) {
#define MAYBE_TestResourceContentLength TestResourceContentLength
#endif // defined(OS_LINUX)
-// Disabled because times out on builder: http://crbug.com/54592.
// Tests profiler panel.
-IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, DISABLED_TestProfilerTab) {
+IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestProfilerTab) {
RunTest("testProfilerTab", kJsPage);
}
diff --git a/chrome/browser/debugger/devtools_window.cc b/chrome/browser/debugger/devtools_window.cc
index b18703c..cb3295b 100644
--- a/chrome/browser/debugger/devtools_window.cc
+++ b/chrome/browser/debugger/devtools_window.cc
@@ -12,22 +12,23 @@
#include "chrome/browser/browser_window.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/debugger/devtools_window.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/in_process_webkit/session_storage_namespace.h"
#include "chrome/browser/load_notification_details.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/bindings_policy.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/url_constants.h"
@@ -274,9 +275,12 @@ void DevToolsWindow::AddDevToolsExtensionsToClient() {
CallClientFunction(L"WebInspector.setInspectedTabId", tabId);
}
ListValue results;
- const ExtensionsService* extension_service =
+ const ExtensionService* extension_service =
tab_contents_->tab_contents()->profile()->
- GetOriginalProfile()->GetExtensionsService();
+ GetOriginalProfile()->GetExtensionService();
+ if (!extension_service)
+ return;
+
const ExtensionList* extensions = extension_service->extensions();
for (ExtensionList::const_iterator extension = extensions->begin();
@@ -392,6 +396,10 @@ void DevToolsWindow::UpdateTheme() {
ExecuteJavascriptInWebFrame(L"", UTF8ToWide(command));
}
+bool DevToolsWindow::CanReloadContents(TabContents* source) const {
+ return false;
+}
+
bool DevToolsWindow::PreHandleKeyboardEvent(
const NativeWebKeyboardEvent& event, bool* is_keyboard_shortcut) {
if (docked_) {
diff --git a/chrome/browser/debugger/devtools_window.h b/chrome/browser/debugger/devtools_window.h
index a9ba40d..e7b9afc 100644
--- a/chrome/browser/debugger/devtools_window.h
+++ b/chrome/browser/debugger/devtools_window.h
@@ -14,7 +14,6 @@
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
namespace IPC {
class Message;
@@ -49,7 +48,7 @@ class DevToolsWindow
RenderViewHost* GetRenderViewHost();
TabContentsWrapper* tab_contents() { return tab_contents_; }
- Browser* browser() { return browser_; } // For tests.
+ Browser* browser() { return browser_; } // For tests.
bool is_docked() { return docked_; }
private:
@@ -88,7 +87,7 @@ class DevToolsWindow
virtual void LoadingStateChanged(TabContents* source) {}
virtual void CloseContents(TabContents* source) {}
virtual void MoveContents(TabContents* source, const gfx::Rect& pos) {}
- virtual bool CanReloadContents(TabContents* source) const { return false; }
+ virtual bool CanReloadContents(TabContents* source) const;
virtual void URLStarredChanged(TabContents* source, bool starred) {}
virtual void UpdateTargetURL(TabContents* source, const GURL& url) {}
virtual void ToolbarSizeChanged(TabContents* source, bool is_animating) {}
diff --git a/chrome/browser/debugger/extension_ports_remote_service.cc b/chrome/browser/debugger/extension_ports_remote_service.cc
index 3596187..6f4fbb9 100644
--- a/chrome/browser/debugger/extension_ports_remote_service.cc
+++ b/chrome/browser/debugger/extension_ports_remote_service.cc
@@ -19,11 +19,9 @@
#include "chrome/browser/debugger/devtools_protocol_handler.h"
#include "chrome/browser/debugger/devtools_remote_message.h"
#include "chrome/browser/debugger/inspectable_tab_proxy.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/devtools_messages.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/render_messages_params.h"
diff --git a/chrome/browser/debugger/inspectable_tab_proxy.cc b/chrome/browser/debugger/inspectable_tab_proxy.cc
index 5dd734f..9aa0622 100644
--- a/chrome/browser/debugger/inspectable_tab_proxy.cc
+++ b/chrome/browser/debugger/inspectable_tab_proxy.cc
@@ -11,9 +11,9 @@
#include "chrome/browser/debugger/devtools_client_host.h"
#include "chrome/browser/sessions/session_id.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/devtools_messages.h"
DevToolsClientHostImpl::DevToolsClientHostImpl(
diff --git a/chrome/browser/default_encoding_combo_model.cc b/chrome/browser/default_encoding_combo_model.cc
index f900713..67dc183 100644
--- a/chrome/browser/default_encoding_combo_model.cc
+++ b/chrome/browser/default_encoding_combo_model.cc
@@ -9,7 +9,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/prefs/pref_member.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
DefaultEncodingComboboxModel::DefaultEncodingComboboxModel() {
diff --git a/chrome/browser/device_orientation/data_fetcher.h b/chrome/browser/device_orientation/data_fetcher.h
index 1a599b7..2b57fa9 100644
--- a/chrome/browser/device_orientation/data_fetcher.h
+++ b/chrome/browser/device_orientation/data_fetcher.h
@@ -13,7 +13,6 @@ class DataFetcher {
public:
virtual ~DataFetcher() {}
virtual bool GetOrientation(Orientation*) = 0;
- virtual int MinSamplingIntervalMs() const { return 0; }
};
} // namespace device_orientation
diff --git a/chrome/browser/device_orientation/dispatcher_host.cc b/chrome/browser/device_orientation/dispatcher_host.cc
deleted file mode 100644
index 6bec33f..0000000
--- a/chrome/browser/device_orientation/dispatcher_host.cc
+++ /dev/null
@@ -1,112 +0,0 @@
-// 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.
-
-#include "chrome/browser/device_orientation/dispatcher_host.h"
-
-#include "base/scoped_ptr.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/device_orientation/orientation.h"
-#include "chrome/browser/device_orientation/provider.h"
-#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/renderer_host/render_view_host_notification_task.h"
-#include "chrome/common/render_messages.h"
-#include "chrome/common/render_messages_params.h"
-#include "ipc/ipc_message.h"
-
-namespace device_orientation {
-
-DispatcherHost::DispatcherHost(int process_id)
- : process_id_(process_id),
- observers_map_(),
- provider_(NULL) {
-}
-
-DispatcherHost::~DispatcherHost() {
-}
-
-class DispatcherHost::ObserverDelegate
- : public base::RefCounted<ObserverDelegate>, public Provider::Observer {
- public:
- // Create ObserverDelegate that observes provider and forwards updates to
- // render_view_id in process_id.
- // Will stop observing provider when destructed.
- ObserverDelegate(Provider* provider,
- int process_id,
- int render_view_id);
-
- // From Provider::Observer.
- virtual void OnOrientationUpdate(const Orientation& orientation);
-
- private:
- friend class base::RefCounted<ObserverDelegate>;
- virtual ~ObserverDelegate();
-
- scoped_refptr<Provider> provider_;
- int process_id_;
- int render_view_id_;
-
- DISALLOW_COPY_AND_ASSIGN(ObserverDelegate);
-};
-
-DispatcherHost::ObserverDelegate::ObserverDelegate(Provider* provider,
- int process_id,
- int render_view_id)
- : provider_(provider),
- process_id_(process_id),
- render_view_id_(render_view_id) {
- provider_->AddObserver(this);
-}
-
-DispatcherHost::ObserverDelegate::~ObserverDelegate() {
- provider_->RemoveObserver(this);
-}
-
-void DispatcherHost::ObserverDelegate::OnOrientationUpdate(
- const Orientation& orientation) {
- ViewMsg_DeviceOrientationUpdated_Params params;
- params.can_provide_alpha = orientation.can_provide_alpha_;
- params.alpha = orientation.alpha_;
- params.can_provide_beta = orientation.can_provide_beta_;
- params.beta = orientation.beta_;
- params.can_provide_gamma = orientation.can_provide_gamma_;
- params.gamma = orientation.gamma_;
-
- IPC::Message* message = new ViewMsg_DeviceOrientationUpdated(render_view_id_,
- params);
- CallRenderViewHost(process_id_, render_view_id_, &RenderViewHost::Send,
- message);
-}
-
-bool DispatcherHost::OnMessageReceived(const IPC::Message& msg,
- bool* msg_was_ok) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP_EX(DispatcherHost, msg, *msg_was_ok)
- IPC_MESSAGE_HANDLER(ViewHostMsg_DeviceOrientation_StartUpdating,
- OnStartUpdating)
- IPC_MESSAGE_HANDLER(ViewHostMsg_DeviceOrientation_StopUpdating,
- OnStopUpdating)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void DispatcherHost::OnStartUpdating(int render_view_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- if (!provider_)
- provider_ = Provider::GetInstance();
-
- observers_map_[render_view_id] = new ObserverDelegate(provider_,
- process_id_,
- render_view_id);
-}
-
-void DispatcherHost::OnStopUpdating(int render_view_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- observers_map_.erase(render_view_id);
-}
-
-} // namespace device_orientation
diff --git a/chrome/browser/device_orientation/dispatcher_host.h b/chrome/browser/device_orientation/dispatcher_host.h
deleted file mode 100644
index d30e820..0000000
--- a/chrome/browser/device_orientation/dispatcher_host.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_DEVICE_ORIENTATION_DISPATCHER_HOST_H_
-#define CHROME_BROWSER_DEVICE_ORIENTATION_DISPATCHER_HOST_H_
-
-#include <map>
-
-#include "base/ref_counted.h"
-#include "chrome/browser/device_orientation/provider.h"
-
-namespace IPC { class Message; }
-
-namespace device_orientation {
-
-class Orientation;
-
-class DispatcherHost : public base::RefCounted<DispatcherHost> {
- public:
- explicit DispatcherHost(int process_id);
- bool OnMessageReceived(const IPC::Message& msg, bool* msg_was_ok);
-
- private:
- virtual ~DispatcherHost();
- friend class base::RefCounted<DispatcherHost>;
-
- void OnStartUpdating(int render_view_id);
- void OnStopUpdating(int render_view_id);
-
- // Helper class that observes a Provider and forwards updates to a RenderView.
- class ObserverDelegate;
-
- int process_id_;
-
- // map from render_view_id to ObserverDelegate.
- std::map<int, scoped_refptr<ObserverDelegate> > observers_map_;
-
- scoped_refptr<Provider> provider_;
-
- DISALLOW_COPY_AND_ASSIGN(DispatcherHost);
-};
-
-} // namespace device_orientation
-
-#endif // CHROME_BROWSER_DEVICE_ORIENTATION_DISPATCHER_HOST_H_
diff --git a/chrome/browser/device_orientation/message_filter.cc b/chrome/browser/device_orientation/message_filter.cc
new file mode 100644
index 0000000..06f49cb
--- /dev/null
+++ b/chrome/browser/device_orientation/message_filter.cc
@@ -0,0 +1,106 @@
+// 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.
+
+#include "chrome/browser/device_orientation/message_filter.h"
+
+#include "base/scoped_ptr.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/device_orientation/orientation.h"
+#include "chrome/browser/device_orientation/provider.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/renderer_host/render_view_host_notification_task.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
+#include "ipc/ipc_message.h"
+
+namespace device_orientation {
+
+MessageFilter::MessageFilter() : provider_(NULL) {
+}
+
+MessageFilter::~MessageFilter() {
+}
+
+class MessageFilter::ObserverDelegate
+ : public base::RefCounted<ObserverDelegate>, public Provider::Observer {
+ public:
+ // Create ObserverDelegate that observes provider and forwards updates to
+ // render_view_id in process_id.
+ // Will stop observing provider when destructed.
+ ObserverDelegate(Provider* provider,
+ int render_view_id,
+ IPC::Message::Sender* sender);
+
+ // From Provider::Observer.
+ virtual void OnOrientationUpdate(const Orientation& orientation);
+
+ private:
+ friend class base::RefCounted<ObserverDelegate>;
+ virtual ~ObserverDelegate();
+
+ scoped_refptr<Provider> provider_;
+ int render_view_id_;
+ IPC::Message::Sender* sender_; // Weak pointer.
+
+ DISALLOW_COPY_AND_ASSIGN(ObserverDelegate);
+};
+
+MessageFilter::ObserverDelegate::ObserverDelegate(Provider* provider,
+ int render_view_id,
+ IPC::Message::Sender* sender)
+ : provider_(provider),
+ render_view_id_(render_view_id),
+ sender_(sender) {
+ provider_->AddObserver(this);
+}
+
+MessageFilter::ObserverDelegate::~ObserverDelegate() {
+ provider_->RemoveObserver(this);
+}
+
+void MessageFilter::ObserverDelegate::OnOrientationUpdate(
+ const Orientation& orientation) {
+ ViewMsg_DeviceOrientationUpdated_Params params;
+ params.can_provide_alpha = orientation.can_provide_alpha_;
+ params.alpha = orientation.alpha_;
+ params.can_provide_beta = orientation.can_provide_beta_;
+ params.beta = orientation.beta_;
+ params.can_provide_gamma = orientation.can_provide_gamma_;
+ params.gamma = orientation.gamma_;
+
+ sender_->Send(new ViewMsg_DeviceOrientationUpdated(render_view_id_, params));
+}
+
+bool MessageFilter::OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(MessageFilter, message, *message_was_ok)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DeviceOrientation_StartUpdating,
+ OnStartUpdating)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DeviceOrientation_StopUpdating,
+ OnStopUpdating)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void MessageFilter::OnStartUpdating(int render_view_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ if (!provider_)
+ provider_ = Provider::GetInstance();
+
+ observers_map_[render_view_id] = new ObserverDelegate(provider_,
+ render_view_id,
+ this);
+}
+
+void MessageFilter::OnStopUpdating(int render_view_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ observers_map_.erase(render_view_id);
+}
+
+} // namespace device_orientation
diff --git a/chrome/browser/device_orientation/message_filter.h b/chrome/browser/device_orientation/message_filter.h
new file mode 100644
index 0000000..468fe6f
--- /dev/null
+++ b/chrome/browser/device_orientation/message_filter.h
@@ -0,0 +1,44 @@
+// 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.
+
+#ifndef CHROME_BROWSER_DEVICE_ORIENTATION_MESSAGE_FILTER_H_
+#define CHROME_BROWSER_DEVICE_ORIENTATION_MESSAGE_FILTER_H_
+
+#include <map>
+
+#include "chrome/browser/browser_message_filter.h"
+#include "chrome/browser/device_orientation/provider.h"
+
+namespace device_orientation {
+
+class Orientation;
+
+class MessageFilter : public BrowserMessageFilter {
+ public:
+ MessageFilter();
+
+ // BrowserMessageFilter implementation.
+ virtual bool OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok);
+
+ private:
+ virtual ~MessageFilter();
+
+ void OnStartUpdating(int render_view_id);
+ void OnStopUpdating(int render_view_id);
+
+ // Helper class that observes a Provider and forwards updates to a RenderView.
+ class ObserverDelegate;
+
+ // map from render_view_id to ObserverDelegate.
+ std::map<int, scoped_refptr<ObserverDelegate> > observers_map_;
+
+ scoped_refptr<Provider> provider_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessageFilter);
+};
+
+} // namespace device_orientation
+
+#endif // CHROME_BROWSER_DEVICE_ORIENTATION_MESSAGE_FILTER_H_
diff --git a/chrome/browser/device_orientation/provider_impl.cc b/chrome/browser/device_orientation/provider_impl.cc
index e5e2397..dfe994a 100644
--- a/chrome/browser/device_orientation/provider_impl.cc
+++ b/chrome/browser/device_orientation/provider_impl.cc
@@ -7,8 +7,9 @@
#include <vector>
#include "base/logging.h"
+#include "base/message_loop.h"
#include "base/task.h"
-#include "chrome/browser/browser_thread.h"
+#include "base/thread.h"
#include "chrome/browser/device_orientation/orientation.h"
#include "chrome/browser/device_orientation/provider_impl.h"
@@ -150,6 +151,7 @@ void ProviderImpl::ScheduleDoPoll() {
}
namespace {
+
bool IsElementSignificantlyDifferent(bool can_provide_element1,
bool can_provide_element2,
double element1,
@@ -163,7 +165,7 @@ bool IsElementSignificantlyDifferent(bool can_provide_element1,
return true;
return false;
}
-} // namespace
+} // namespace
// Returns true if two orientations are considered different enough that
// observers should be notified of the new orientation.
@@ -187,12 +189,10 @@ int ProviderImpl::SamplingIntervalMs() const {
DCHECK(MessageLoop::current() == polling_thread_->message_loop());
DCHECK(data_fetcher_.get());
- int fetcher_interval = data_fetcher_->MinSamplingIntervalMs();
-
- if (fetcher_interval > kDesiredSamplingIntervalMs)
- return fetcher_interval;
- else
- return kDesiredSamplingIntervalMs;
+ // TODO(erg): There used to be unused code here, that called a default
+ // implementation on the DataFetcherInterface that was never defined. I'm
+ // removing unused methods from headers.
+ return kDesiredSamplingIntervalMs;
}
} // namespace device_orientation
diff --git a/chrome/browser/diagnostics/diagnostics_main.cc b/chrome/browser/diagnostics/diagnostics_main.cc
index bf88222..2f654c2 100644
--- a/chrome/browser/diagnostics/diagnostics_main.cc
+++ b/chrome/browser/diagnostics/diagnostics_main.cc
@@ -315,8 +315,8 @@ class TestController : public DiagnosticsModel::Observer {
// -(all) RegisterInvalidParamHandler()
// -(all) base::AtExitManager::AtExitManager()
// -(macOS) base::ScopedNSAutoreleasePool
-// -(posix) Singleton<base::GlobalDescriptors>::Set(kPrimaryIPCChannel)
-// -(linux) Singleton<base::GlobalDescriptors>::Set(kCrashDumpSignal)
+// -(posix) base::GlobalDescriptors::GetInstance()->Set(kPrimaryIPCChannel)
+// -(linux) base::GlobalDescriptors::GetInstance()->Set(kCrashDumpSignal)
// -(posix) setlocale(LC_ALL,..)
// -(all) CommandLine::Init();
diff --git a/chrome/browser/diagnostics/diagnostics_test.cc b/chrome/browser/diagnostics/diagnostics_test.cc
new file mode 100644
index 0000000..cd36c92
--- /dev/null
+++ b/chrome/browser/diagnostics/diagnostics_test.cc
@@ -0,0 +1,53 @@
+// 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.
+
+#include "chrome/browser/diagnostics/diagnostics_test.h"
+
+#include "base/file_path.h"
+#include "base/path_service.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_paths.h"
+
+DiagnosticTest::DiagnosticTest(const string16& title)
+ : title_(title), result_(DiagnosticsModel::TEST_NOT_RUN) {
+}
+
+DiagnosticTest::~DiagnosticTest() {
+}
+
+bool DiagnosticTest::Execute(DiagnosticsModel::Observer* observer,
+ DiagnosticsModel* model,
+ size_t index) {
+ result_ = DiagnosticsModel::TEST_RUNNING;
+ observer->OnProgress(index, 0, model);
+ bool keep_going = ExecuteImpl(observer);
+ observer->OnFinished(index, model);
+ return keep_going;
+}
+
+string16 DiagnosticTest::GetTitle() {
+ return title_;
+}
+
+DiagnosticsModel::TestResult DiagnosticTest::GetResult() {
+ return result_;
+}
+
+string16 DiagnosticTest::GetAdditionalInfo() {
+ return additional_info_;
+}
+
+void DiagnosticTest::RecordOutcome(const string16& additional_info,
+ DiagnosticsModel::TestResult result) {
+ additional_info_ = additional_info;
+ result_ = result;
+}
+
+// static
+FilePath DiagnosticTest::GetUserDefaultProfileDir() {
+ FilePath path;
+ if (!PathService::Get(chrome::DIR_USER_DATA, &path))
+ return FilePath();
+ return path.Append(FilePath::FromWStringHack(chrome::kNotSignedInProfile));
+}
diff --git a/chrome/browser/diagnostics/diagnostics_test.h b/chrome/browser/diagnostics/diagnostics_test.h
index 998a0d1..70d7eb7 100644
--- a/chrome/browser/diagnostics/diagnostics_test.h
+++ b/chrome/browser/diagnostics/diagnostics_test.h
@@ -6,12 +6,10 @@
#define CHROME_BROWSER_DIAGNOSTICS_DIAGNOSTICS_TEST_H_
#pragma once
-#include "base/file_path.h"
-#include "base/path_service.h"
#include "base/string16.h"
#include "chrome/browser/diagnostics/diagnostics_model.h"
-#include "chrome/common/chrome_constants.h"
-#include "chrome/common/chrome_paths.h"
+
+class FilePath;
// Represents a single diagnostic test and encapsulates the common
// functionality across platforms as well.
@@ -27,33 +25,20 @@ class DiagnosticTest : public DiagnosticsModel::TestInfo {
public:
// |title| is the human readable, localized string that says that
// the objective of the test is.
- explicit DiagnosticTest(const string16& title)
- : title_(title), result_(DiagnosticsModel::TEST_NOT_RUN) {}
+ explicit DiagnosticTest(const string16& title);
- virtual ~DiagnosticTest() {}
+ virtual ~DiagnosticTest();
// Runs the test. Returning false signals that no more tests should be run.
// The actual outcome of the test should be set using the RecordXX functions.
bool Execute(DiagnosticsModel::Observer* observer, DiagnosticsModel* model,
- size_t index) {
- result_ = DiagnosticsModel::TEST_RUNNING;
- observer->OnProgress(index, 0, model);
- bool keep_going = ExecuteImpl(observer);
- observer->OnFinished(index, model);
- return keep_going;
- }
+ size_t index);
- virtual string16 GetTitle() {
- return title_;
- }
+ virtual string16 GetTitle();
- virtual DiagnosticsModel::TestResult GetResult() {
- return result_;
- }
+ virtual DiagnosticsModel::TestResult GetResult();
- virtual string16 GetAdditionalInfo() {
- return additional_info_;
- }
+ virtual string16 GetAdditionalInfo();
void RecordStopFailure(const string16& additional_info) {
RecordOutcome(additional_info, DiagnosticsModel::TEST_FAIL_STOP);
@@ -68,17 +53,9 @@ class DiagnosticTest : public DiagnosticsModel::TestInfo {
}
void RecordOutcome(const string16& additional_info,
- DiagnosticsModel::TestResult result) {
- additional_info_ = additional_info;
- result_ = result;
- }
+ DiagnosticsModel::TestResult result);
- static FilePath GetUserDefaultProfileDir() {
- FilePath path;
- if (!PathService::Get(chrome::DIR_USER_DATA, &path))
- return FilePath();
- return path.Append(FilePath::FromWStringHack(chrome::kNotSignedInProfile));
- }
+ static FilePath GetUserDefaultProfileDir();
protected:
// The id needs to be overriden by derived classes and must uniquely
diff --git a/chrome/browser/diagnostics/recon_diagnostics.cc b/chrome/browser/diagnostics/recon_diagnostics.cc
index bda422b..f657fef 100644
--- a/chrome/browser/diagnostics/recon_diagnostics.cc
+++ b/chrome/browser/diagnostics/recon_diagnostics.cc
@@ -15,6 +15,7 @@
#include "base/path_service.h"
#include "chrome/browser/diagnostics/diagnostics_test.h"
#include "chrome/browser/platform_util.h"
+#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/json_value_serializer.h"
diff --git a/chrome/browser/dock_info.cc b/chrome/browser/dock_info.cc
deleted file mode 100644
index d52ddc9..0000000
--- a/chrome/browser/dock_info.cc
+++ /dev/null
@@ -1,268 +0,0 @@
-// 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.
-
-#include "chrome/browser/dock_info.h"
-
-#if defined(TOOLKIT_VIEWS)
-#include "chrome/browser/views/tabs/tab.h"
-#else
-#include "chrome/browser/gtk/tabs/tab_gtk.h"
-#endif
-
-namespace {
-
-// Distance in pixels between the hotspot and when the hint should be shown.
-const int kHotSpotDeltaX = 120;
-const int kHotSpotDeltaY = 120;
-
-// Size of the popup window.
-const int kPopupWidth = 70;
-const int kPopupHeight = 70;
-
-} // namespace
-
-// static
-DockInfo::Factory* DockInfo::factory_ = NULL;
-
-// static
-bool DockInfo::IsCloseToPoint(const gfx::Point& screen_loc,
- int x,
- int y,
- bool* in_enable_area) {
- int delta_x = abs(x - screen_loc.x());
- int delta_y = abs(y - screen_loc.y());
- *in_enable_area = (delta_x < kPopupWidth / 2 && delta_y < kPopupHeight / 2);
- return *in_enable_area || (delta_x < kHotSpotDeltaX &&
- delta_y < kHotSpotDeltaY);
-}
-
-// static
-bool DockInfo::IsCloseToMonitorPoint(const gfx::Point& screen_loc,
- int x,
- int y,
- DockInfo::Type type,
- bool* in_enable_area) {
- // Because the monitor relative positions are aligned with the edge of the
- // monitor these need to be handled differently.
- int delta_x = abs(x - screen_loc.x());
- int delta_y = abs(y - screen_loc.y());
-
- int enable_delta_x = kPopupWidth / 2;
- int enable_delta_y = kPopupHeight / 2;
- int hot_spot_delta_x = kHotSpotDeltaX;
- int hot_spot_delta_y = kHotSpotDeltaY;
-
- switch (type) {
- case DockInfo::LEFT_HALF:
- case DockInfo::RIGHT_HALF:
- enable_delta_x += enable_delta_x;
- hot_spot_delta_x += hot_spot_delta_x;
- break;
-
-
- case DockInfo::MAXIMIZE: {
- // Make the maximize height smaller than the tab height to avoid showing
- // the dock indicator when close to maximized browser.
-#if defined(TOOLKIT_VIEWS)
- hot_spot_delta_y = Tab::GetMinimumUnselectedSize().height() - 1;
-#else
- hot_spot_delta_y = TabGtk::GetMinimumUnselectedSize().height() - 1;
-#endif
- enable_delta_y = hot_spot_delta_y / 2;
- break;
- }
- case DockInfo::BOTTOM_HALF:
- enable_delta_y += enable_delta_y;
- hot_spot_delta_y += hot_spot_delta_y;
- break;
-
- default:
- NOTREACHED();
- return false;
- }
- *in_enable_area = (delta_x < enable_delta_x && delta_y < enable_delta_y);
- bool result = (*in_enable_area || (delta_x < hot_spot_delta_x &&
- delta_y < hot_spot_delta_y));
- if (type != DockInfo::MAXIMIZE)
- return result;
-
- // Make the hot spot/enable spot for maximized windows the whole top of the
- // monitor.
- int max_delta_y = abs(screen_loc.y() - y);
- *in_enable_area = (*in_enable_area || (max_delta_y < enable_delta_y));
- return *in_enable_area || (max_delta_y < hot_spot_delta_y);
-}
-
-// static
-int DockInfo::popup_width() {
- return kPopupWidth;
-}
-
-// static
-int DockInfo::popup_height() {
- return kPopupHeight;
-}
-
-bool DockInfo::IsValidForPoint(const gfx::Point& screen_point) {
- if (type_ == NONE)
- return false;
-
- if (window_) {
- return IsCloseToPoint(screen_point, hot_spot_.x(), hot_spot_.y(),
- &in_enable_area_);
- }
-
- return monitor_bounds_.Contains(screen_point) &&
- IsCloseToMonitorPoint(screen_point, hot_spot_.x(),
- hot_spot_.y(), type_, &in_enable_area_);
-}
-
-bool DockInfo::GetNewWindowBounds(gfx::Rect* new_window_bounds,
- bool* maximize_new_window) const {
- if (type_ == NONE || !in_enable_area_)
- return false;
-
- gfx::Rect window_bounds;
- if (window_ && !GetWindowBounds(&window_bounds))
- return false;
-
- int half_m_width = (monitor_bounds_.right() - monitor_bounds_.x()) / 2;
- int half_m_height = (monitor_bounds_.bottom() - monitor_bounds_.y()) / 2;
-
- *maximize_new_window = false;
-
- switch (type_) {
- case LEFT_OF_WINDOW:
- new_window_bounds->SetRect(monitor_bounds_.x(), window_bounds.y(),
- half_m_width, window_bounds.height());
- break;
-
- case RIGHT_OF_WINDOW:
- new_window_bounds->SetRect(monitor_bounds_.x() + half_m_width,
- window_bounds.y(), half_m_width,
- window_bounds.height());
- break;
-
- case TOP_OF_WINDOW:
- new_window_bounds->SetRect(window_bounds.x(), monitor_bounds_.y(),
- window_bounds.width(), half_m_height);
- break;
-
- case BOTTOM_OF_WINDOW:
- new_window_bounds->SetRect(window_bounds.x(),
- monitor_bounds_.y() + half_m_height,
- window_bounds.width(), half_m_height);
- break;
-
- case LEFT_HALF:
- new_window_bounds->SetRect(monitor_bounds_.x(), monitor_bounds_.y(),
- half_m_width, monitor_bounds_.height());
- break;
-
- case RIGHT_HALF:
- new_window_bounds->SetRect(monitor_bounds_.right() - half_m_width,
- monitor_bounds_.y(), half_m_width, monitor_bounds_.height());
- break;
-
- case BOTTOM_HALF:
- new_window_bounds->SetRect(monitor_bounds_.x(),
- monitor_bounds_.y() + half_m_height,
- monitor_bounds_.width(), half_m_height);
- break;
-
- case MAXIMIZE:
- *maximize_new_window = true;
- break;
-
- default:
- NOTREACHED();
- }
- return true;
-}
-
-void DockInfo::AdjustOtherWindowBounds() const {
- if (!in_enable_area_)
- return;
-
- gfx::Rect window_bounds;
- if (!window_ || !GetWindowBounds(&window_bounds))
- return;
-
- gfx::Rect other_window_bounds;
- int half_m_width = (monitor_bounds_.right() - monitor_bounds_.x()) / 2;
- int half_m_height = (monitor_bounds_.bottom() - monitor_bounds_.y()) / 2;
-
- switch (type_) {
- case LEFT_OF_WINDOW:
- other_window_bounds.SetRect(monitor_bounds_.x() + half_m_width,
- window_bounds.y(), half_m_width,
- window_bounds.height());
- break;
-
- case RIGHT_OF_WINDOW:
- other_window_bounds.SetRect(monitor_bounds_.x(), window_bounds.y(),
- half_m_width, window_bounds.height());
- break;
-
- case TOP_OF_WINDOW:
- other_window_bounds.SetRect(window_bounds.x(),
- monitor_bounds_.y() + half_m_height,
- window_bounds.width(), half_m_height);
- break;
-
- case BOTTOM_OF_WINDOW:
- other_window_bounds.SetRect(window_bounds.x(), monitor_bounds_.y(),
- window_bounds.width(), half_m_height);
- break;
-
- default:
- return;
- }
-
- SizeOtherWindowTo(other_window_bounds);
-}
-
-gfx::Rect DockInfo::GetPopupRect() const {
- int x = hot_spot_.x() - popup_width() / 2;
- int y = hot_spot_.y() - popup_height() / 2;
- switch (type_) {
- case LEFT_OF_WINDOW:
- case RIGHT_OF_WINDOW:
- case TOP_OF_WINDOW:
- case BOTTOM_OF_WINDOW: {
- // Constrain the popup to the monitor's bounds.
- gfx::Rect ideal_bounds(x, y, popup_width(), popup_height());
- ideal_bounds = ideal_bounds.AdjustToFit(monitor_bounds_);
- return ideal_bounds;
- }
- case DockInfo::MAXIMIZE:
- y += popup_height() / 2;
- break;
- case DockInfo::LEFT_HALF:
- x += popup_width() / 2;
- break;
- case DockInfo::RIGHT_HALF:
- x -= popup_width() / 2;
- break;
- case DockInfo::BOTTOM_HALF:
- y -= popup_height() / 2;
- break;
-
- default:
- NOTREACHED();
- }
- return gfx::Rect(x, y, popup_width(), popup_height());
-}
-
-bool DockInfo::CheckMonitorPoint(const gfx::Point& screen_loc,
- int x,
- int y,
- Type type) {
- if (IsCloseToMonitorPoint(screen_loc, x, y, type, &in_enable_area_)) {
- hot_spot_.SetPoint(x, y);
- type_ = type;
- return true;
- }
- return false;
-}
diff --git a/chrome/browser/dock_info.h b/chrome/browser/dock_info.h
deleted file mode 100644
index d0bf90c..0000000
--- a/chrome/browser/dock_info.h
+++ /dev/null
@@ -1,190 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_DOCK_INFO_H_
-#define CHROME_BROWSER_DOCK_INFO_H_
-#pragma once
-
-#include <set>
-
-#include "gfx/native_widget_types.h"
-#include "gfx/point.h"
-#include "gfx/rect.h"
-
-// DockInfo is used to do determine possible dock locations for a dragged
-// tab. To use DockInfo invoke GetDockInfoAtPoint. This returns a new
-// DockInfo whose type indicates the type of dock that should occur based
-// on the screen location. As the user drags the mouse around invoke
-// IsValidForPoint, this returns true if the DockInfo is still valid for the
-// new location. If the DockInfo is not valid, invoke GetDockInfoAtPoint to
-// get the new DockInfo. Use GetNewWindowBounds to get the position to place
-// the new window at.
-//
-// DockInfos are cheap and explicitly allow copy and assignment operators.
-class DockInfo {
- public:
- class Factory {
- public:
- virtual DockInfo GetDockInfoAtPoint(
- const gfx::Point& screen_point,
- const std::set<gfx::NativeView>& ignore) = 0;
-
- virtual gfx::NativeWindow GetLocalProcessWindowAtPoint(
- const gfx::Point& screen_point,
- const std::set<gfx::NativeView>& ignore) = 0;
-
- protected:
- virtual ~Factory() {}
- };
-
- // Possible dock positions.
- enum Type {
- // Indicates there is no valid dock position for the current location.
- NONE,
-
- // Indicates the new window should be positioned relative to the window
- // identified by window().
- LEFT_OF_WINDOW,
- RIGHT_OF_WINDOW,
- BOTTOM_OF_WINDOW,
- TOP_OF_WINDOW,
-
- // Indicates the window should be maximized on the monitor at hot_spot.
- MAXIMIZE,
-
- // Indicates the window should be docked to a specific side of the monitor.
- LEFT_HALF,
- RIGHT_HALF,
- BOTTOM_HALF
- };
-
- DockInfo() : type_(NONE), window_(NULL), in_enable_area_(false) {}
-
- // Returns true if |screen_loc| is close to the hotspot at |x|, |y|. If the
- // point is close enough to the hotspot true is returned and |in_enable_area|
- // is set appropriately.
- static bool IsCloseToPoint(const gfx::Point& screen_loc,
- int x,
- int y,
- bool* in_enable_area);
-
- // Variant of IsCloseToPoint used for monitor relative positions.
- static bool IsCloseToMonitorPoint(const gfx::Point& screen_loc,
- int x,
- int y,
- DockInfo::Type type,
- bool* in_enable_area);
-
- // Sets the factory.
- static void set_factory(Factory* factory) { factory_ = factory; }
-
- // Size of the popup window shown to indicate a valid dock location.
- static int popup_width();
- static int popup_height();
-
- // Returns the DockInfo for the specified point |screen_point|. |ignore|
- // contains the set of windows to ignore from consideration. This contains the
- // dragged window as well as any windows showing possible dock locations.
- //
- // If there is no docking position for the specified location the returned
- // DockInfo has a type of NONE.
- //
- // If a Factory has been set, the method of the same name is invoked on the
- // Factory to determine the DockInfo.
- static DockInfo GetDockInfoAtPoint(const gfx::Point& screen_point,
- const std::set<gfx::NativeView>& ignore);
-
- // Returns the top most window from the current process at |screen_point|.
- // See GetDockInfoAtPoint for a description of |ignore|. This returns NULL if
- // there is no window from the current process at |screen_point|, or another
- // window obscures the topmost window from our process at |screen_point|.
- //
- // If a Factory has been set, the method of the same name is invoked on the
- // Factory to determine the DockInfo.
- static gfx::NativeWindow GetLocalProcessWindowAtPoint(
- const gfx::Point& screen_point,
- const std::set<gfx::NativeView>& ignore);
-
- // Returns true if this DockInfo is valid for the specified point. This
- // resets in_enable_area based on the new location.
- bool IsValidForPoint(const gfx::Point& screen_point);
-
- // Returns the bounds for the new window in |new_window_bounds|. If the new
- // window is to be maximized, |maximize_new_window| is set to true.
- // This returns true if type is other than NONE or the mouse isn't in the
- // enable area, false otherwise.
- bool GetNewWindowBounds(gfx::Rect* new_window_bounds,
- bool* maximize_new_window) const;
-
- // Adjust the bounds of the other window during docking. Does nothing if type
- // is NONE, in_enable_are is false, or the type is not window relative.
- void AdjustOtherWindowBounds() const;
-
- // Type of docking to occur.
- void set_type(Type type) { type_ = type; }
- Type type() const { return type_; }
-
- // The window to dock too. Is null for dock types that are relative to the
- // monitor.
- void set_window(gfx::NativeWindow window) { window_ = window; }
- gfx::NativeWindow window() const { return window_; }
-
- // The location of the hotspot.
- void set_hot_spot(const gfx::Point& hot_spot) { hot_spot_ = hot_spot; }
- const gfx::Point& hot_spot() const { return hot_spot_; }
-
- // Bounds of the monitor.
- void set_monitor_bounds(const gfx::Rect& monitor_bounds) {
- monitor_bounds_ = monitor_bounds;
- }
- const gfx::Rect& monitor_bounds() const { return monitor_bounds_; }
-
- // Returns the bounds of the window to show the indicator for.
- gfx::Rect GetPopupRect() const;
-
- // Returns true if the drop should result in docking. DockInfo maintains two
- // states (as indicated by this boolean):
- // 1. The mouse is close enough to the hot spot such that a visual indicator
- // should be shown, but if the user releases the mouse docking shouldn't
- // result. This corresponds to a value of false for in_enable_area.
- // 2. The mouse is close enough to the hot spot such that releasing the mouse
- // should result in docking. This corresponds to a value of true for
- // in_enable_area.
- void set_in_enable_area(bool in_enable_area) {
- in_enable_area_ = in_enable_area;
- }
- bool in_enable_area() const { return in_enable_area_; }
-
- // Returns true if |other| is considered equal to this. Two DockInfos are
- // considered equal if they have the same type and same window.
- bool equals(const DockInfo& other) const {
- return type_ == other.type_ && window_ == other.window_ &&
- monitor_bounds_ == other.monitor_bounds_;
- }
-
- // If screen_loc is close enough to the hot spot given by |x| and |y|, the
- // type and hot_spot are set from the supplied parameters. This is used
- // internally, there is no need to invoke this otherwise.
- bool CheckMonitorPoint(const gfx::Point& screen_loc,
- int x,
- int y,
- Type type);
-
- private:
- // Returns the bounds of the window.
- bool GetWindowBounds(gfx::Rect* bounds) const;
- void SizeOtherWindowTo(const gfx::Rect& bounds) const;
-
- Type type_;
- gfx::NativeWindow window_;
- gfx::Point hot_spot_;
- gfx::Rect monitor_bounds_;
- bool in_enable_area_;
-
- // Factory that creates DockInfos. By default this is NULL, which gives the
- // default behavior.
- static Factory* factory_;
-};
-
-#endif // CHROME_BROWSER_DOCK_INFO_H_
diff --git a/chrome/browser/dock_info_gtk.cc b/chrome/browser/dock_info_gtk.cc
deleted file mode 100644
index 3b29395..0000000
--- a/chrome/browser/dock_info_gtk.cc
+++ /dev/null
@@ -1,219 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/dock_info.h"
-
-#include <gtk/gtk.h>
-
-#include "base/logging.h"
-#include "base/task.h"
-#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_window.h"
-#include "chrome/browser/gtk/browser_window_gtk.h"
-#include "chrome/browser/gtk/gtk_util.h"
-#include "gfx/native_widget_types.h"
-
-////////////////////////////////////////////////////////////////////////////////
-// BaseWindowFinder
-//
-// Base class used to locate a window. A subclass need only override
-// ShouldStopIterating to determine when iteration should stop.
-class BaseWindowFinder : public x11_util::EnumerateWindowsDelegate {
- public:
- explicit BaseWindowFinder(const std::set<GtkWidget*>& ignore) {
- std::set<GtkWidget*>::iterator iter;
- for (iter = ignore.begin(); iter != ignore.end(); iter++) {
- XID xid = x11_util::GetX11WindowFromGtkWidget(*iter);
- ignore_.insert(xid);
- }
- }
-
- virtual ~BaseWindowFinder() {}
-
- protected:
- // Returns true if |window| is in the ignore list.
- bool ShouldIgnoreWindow(XID window) {
- return (ignore_.find(window) != ignore_.end());
- }
-
- // Returns true if iteration should stop, false otherwise.
- virtual bool ShouldStopIterating(XID window) {
- return false;
- }
-
- private:
- std::set<XID> ignore_;
-
- DISALLOW_COPY_AND_ASSIGN(BaseWindowFinder);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// TopMostFinder
-//
-// Helper class to determine if a particular point of a window is not obscured
-// by another window.
-class TopMostFinder : public BaseWindowFinder {
- public:
- // Returns true if |window| is not obscured by another window at the
- // location |screen_loc|, not including the windows in |ignore|.
- static bool IsTopMostWindowAtPoint(XID window,
- const gfx::Point& screen_loc,
- const std::set<GtkWidget*>& ignore) {
- TopMostFinder finder(window, screen_loc, ignore);
- return finder.is_top_most_;
- }
-
- protected:
- virtual bool ShouldStopIterating(XID window) {
- if (BaseWindowFinder::ShouldIgnoreWindow(window))
- return false;
-
- if (window == target_) {
- // Window is topmost, stop iterating.
- is_top_most_ = true;
- return true;
- }
-
- if (!x11_util::IsWindowVisible(window)) {
- // The window isn't visible, keep iterating.
- return false;
- }
-
- gfx::Rect rect;
- if (x11_util::GetWindowRect(window, &rect) && rect.Contains(screen_loc_)) {
- // At this point we haven't found our target window, so this window is
- // higher in the z-order than the target window. If this window contains
- // the point, then we can stop the search now because this window is
- // obscuring the target window at this point.
- return true;
- }
-
- return false;
- }
-
- private:
- TopMostFinder(XID window,
- const gfx::Point& screen_loc,
- const std::set<GtkWidget*>& ignore)
- : BaseWindowFinder(ignore),
- target_(window),
- screen_loc_(screen_loc),
- is_top_most_(false) {
- gtk_util::EnumerateTopLevelWindows(this);
- }
-
- // The window we're looking for.
- XID target_;
-
- // Location of window to find.
- gfx::Point screen_loc_;
-
- // Is target_ the top most window? This is initially false but set to true
- // in ShouldStopIterating if target_ is passed in.
- bool is_top_most_;
-
- DISALLOW_COPY_AND_ASSIGN(TopMostFinder);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// LocalProcessWindowFinder
-//
-// Helper class to determine if a particular point of a window from our process
-// is not obscured by another window.
-class LocalProcessWindowFinder : public BaseWindowFinder {
- public:
- // Returns the XID from our process at screen_loc that is not obscured by
- // another window. Returns 0 otherwise.
- static XID GetProcessWindowAtPoint(const gfx::Point& screen_loc,
- const std::set<GtkWidget*>& ignore) {
- LocalProcessWindowFinder finder(screen_loc, ignore);
- if (finder.result_ &&
- TopMostFinder::IsTopMostWindowAtPoint(finder.result_, screen_loc,
- ignore)) {
- return finder.result_;
- }
- return 0;
- }
-
- protected:
- virtual bool ShouldStopIterating(XID window) {
- if (BaseWindowFinder::ShouldIgnoreWindow(window))
- return false;
-
- // Check if this window is in our process.
- if (!BrowserWindowGtk::GetBrowserWindowForXID(window))
- return false;
-
- if (!x11_util::IsWindowVisible(window))
- return false;
-
- gfx::Rect rect;
- if (x11_util::GetWindowRect(window, &rect) && rect.Contains(screen_loc_)) {
- result_ = window;
- return true;
- }
-
- return false;
- }
-
- private:
- LocalProcessWindowFinder(const gfx::Point& screen_loc,
- const std::set<GtkWidget*>& ignore)
- : BaseWindowFinder(ignore),
- screen_loc_(screen_loc),
- result_(0) {
- gtk_util::EnumerateTopLevelWindows(this);
- }
-
- // Position of the mouse.
- gfx::Point screen_loc_;
-
- // The resulting window. This is initially null but set to true in
- // ShouldStopIterating if an appropriate window is found.
- XID result_;
-
- DISALLOW_COPY_AND_ASSIGN(LocalProcessWindowFinder);
-};
-
-// static
-DockInfo DockInfo::GetDockInfoAtPoint(const gfx::Point& screen_point,
- const std::set<GtkWidget*>& ignore) {
- if (factory_)
- return factory_->GetDockInfoAtPoint(screen_point, ignore);
-
- NOTIMPLEMENTED();
- return DockInfo();
-}
-
-// static
-GtkWindow* DockInfo::GetLocalProcessWindowAtPoint(
- const gfx::Point& screen_point,
- const std::set<GtkWidget*>& ignore) {
- if (factory_)
- return factory_->GetLocalProcessWindowAtPoint(screen_point, ignore);
-
-#if defined(OS_CHROMEOS) || defined(TOOLKIT_VIEWS)
- return NULL;
-#else
- XID xid =
- LocalProcessWindowFinder::GetProcessWindowAtPoint(screen_point, ignore);
- return BrowserWindowGtk::GetBrowserWindowForXID(xid);
-#endif
-}
-
-bool DockInfo::GetWindowBounds(gfx::Rect* bounds) const {
- if (!window())
- return false;
-
- int x, y, w, h;
- gtk_window_get_position(window(), &x, &y);
- gtk_window_get_size(window(), &w, &h);
- bounds->SetRect(x, y, w, h);
- return true;
-}
-
-void DockInfo::SizeOtherWindowTo(const gfx::Rect& bounds) const {
- gtk_window_move(window(), bounds.x(), bounds.y());
- gtk_window_resize(window(), bounds.width(), bounds.height());
-}
diff --git a/chrome/browser/dock_info_mac.cc b/chrome/browser/dock_info_mac.cc
deleted file mode 100644
index 7c4113c..0000000
--- a/chrome/browser/dock_info_mac.cc
+++ /dev/null
@@ -1,15 +0,0 @@
-// 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.
-
-#include "chrome/browser/dock_info.h"
-
-bool DockInfo::GetNewWindowBounds(gfx::Rect* new_window_bounds,
- bool* maximize_new_window) const {
- // TODO(pinkerton): Implement DockInfo, http://crbug.com/9274.
- return true;
-}
-
-void DockInfo::AdjustOtherWindowBounds() const {
- // TODO(pinkerton): Implement DockInfo, http://crbug.com/9274.
-}
diff --git a/chrome/browser/dock_info_unittest.cc b/chrome/browser/dock_info_unittest.cc
deleted file mode 100644
index 1b6b3ef..0000000
--- a/chrome/browser/dock_info_unittest.cc
+++ /dev/null
@@ -1,191 +0,0 @@
-// 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.
-
-#include "base/basictypes.h"
-#include "chrome/browser/dock_info.h"
-#include "gfx/point.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-// Distance in pixels between the hotspot and when the hint should be shown.
-const int kHotSpotDeltaX = 120;
-const int kHotSpotDeltaY = 120;
-// Size of the popup window.
-const int kPopupWidth = 70;
-const int kPopupHeight = 70;
-} // namespace
-
-TEST(DockInfoTest, IsCloseToPoint) {
- bool in_enable_area;
- gfx::Point screen_loc[] = {
- gfx::Point(0, 0),
- gfx::Point(kPopupWidth/2 - 1, kPopupHeight/2 - 1),
- gfx::Point(kPopupWidth/2, kPopupHeight/2),
- gfx::Point(kHotSpotDeltaX - 1, kHotSpotDeltaY - 1),
- gfx::Point(kHotSpotDeltaX, kHotSpotDeltaY),
- gfx::Point(-kHotSpotDeltaX, -kHotSpotDeltaY)
- };
- gfx::Point hotspot[] = {
- gfx::Point(0, 0),
- gfx::Point(0, 0),
- gfx::Point(kPopupWidth, kPopupHeight),
- gfx::Point(0, 0),
- gfx::Point(2*kHotSpotDeltaX, 2*kHotSpotDeltaY),
- gfx::Point(0, 0)
- };
- bool expected_results[] = {
- true, true, true, true, false, false
- };
- bool expected_in_enable_area[] = {
- true, true, false, false, false, false
- };
-
- for (size_t i = 0; i < arraysize(expected_results); ++i) {
- bool result = DockInfo::IsCloseToPoint(
- screen_loc[i], hotspot[i].x(), hotspot[i].y(), &in_enable_area);
- EXPECT_EQ(expected_results[i], result);
- EXPECT_EQ(expected_in_enable_area[i], in_enable_area);
- }
-}
-
-TEST(DockInfoTest, IsCloseToMonitorPoint) {
- bool in_enable_area;
- gfx::Point screen_loc[] = {
- gfx::Point(0, 0),
- gfx::Point(kPopupWidth - 1, kPopupHeight/2 -1),
- gfx::Point(kPopupWidth, kPopupHeight/2 - 1),
- gfx::Point(kPopupWidth - 1, kPopupHeight),
- gfx::Point(2*kHotSpotDeltaX, kHotSpotDeltaY - 1),
- gfx::Point(2*kHotSpotDeltaX - 1, kHotSpotDeltaY),
- gfx::Point(2*kHotSpotDeltaX - 1, kHotSpotDeltaY),
- gfx::Point(0, 0),
- gfx::Point(kPopupWidth/2 - 1, kPopupHeight - 1),
- gfx::Point(kPopupWidth/2 - 1, kPopupHeight),
- gfx::Point(kPopupWidth/2, kPopupHeight - 1),
- gfx::Point(kHotSpotDeltaX - 1, 2*kHotSpotDeltaY),
- gfx::Point(kHotSpotDeltaX, 2*kHotSpotDeltaY - 1),
- };
- gfx::Point hotspot = gfx::Point(0, 0);
- DockInfo::Type type[] = {
- DockInfo::LEFT_HALF,
- DockInfo::LEFT_HALF,
- DockInfo::LEFT_HALF,
- DockInfo::LEFT_HALF,
- DockInfo::LEFT_HALF,
- DockInfo::LEFT_HALF,
- DockInfo::RIGHT_HALF,
- DockInfo::BOTTOM_HALF,
- DockInfo::BOTTOM_HALF,
- DockInfo::BOTTOM_HALF,
- DockInfo::BOTTOM_HALF,
- DockInfo::BOTTOM_HALF,
- DockInfo::BOTTOM_HALF,
- };
- bool expected_results[] = {
- true, true, true, true, false, false, false,
- true, true, true, true, false, false
- };
- bool expected_in_enable_area[] = {
- true, true, false, false, false, false, false,
- true, true, false, false, false, false
- };
-
- for (size_t i = 0; i < arraysize(expected_results); ++i) {
- bool result = DockInfo::IsCloseToMonitorPoint(
- screen_loc[i], hotspot.x(), hotspot.y(), type[i], &in_enable_area);
- EXPECT_EQ(expected_results[i], result);
- EXPECT_EQ(expected_in_enable_area[i], in_enable_area);
- }
-}
-
-TEST(DockInfoTest, IsValidForPoint) {
- DockInfo d;
- EXPECT_EQ(false, d.IsValidForPoint(gfx::Point(0, 0)));
- d.set_monitor_bounds(gfx::Rect(0, 0, kPopupWidth, kPopupHeight));
- d.set_hot_spot(gfx::Point(0, 0));
- d.set_type(DockInfo::LEFT_HALF);
-
- gfx::Point screen_point[] = {
- gfx::Point(0, 0),
- gfx::Point(kPopupWidth + 1, kPopupHeight + 1),
- gfx::Point(2 * kHotSpotDeltaX, kHotSpotDeltaY),
- };
-
- bool expected_result[] = {
- true, false, false
- };
-
- for (size_t i = 0; i < arraysize(expected_result); ++i) {
- EXPECT_EQ(expected_result[i], d.IsValidForPoint(screen_point[i]));
- }
-}
-
-TEST(DockInfoTest, equals) {
- DockInfo d;
- DockInfo dd;
- EXPECT_EQ(true, d.equals(dd));
- d.set_type(DockInfo::MAXIMIZE);
- EXPECT_EQ(false, d.equals(dd));
-}
-
-TEST(DockInfoTest, CheckMonitorPoint) {
- DockInfo d;
- gfx::Point screen_loc[] = {
- gfx::Point(0, 0),
- gfx::Point(2 * kHotSpotDeltaX, kHotSpotDeltaY),
- gfx::Point(2 * kHotSpotDeltaX, kHotSpotDeltaY),
- };
-
- DockInfo::Type type[] = {
- DockInfo::LEFT_HALF,
- DockInfo::RIGHT_HALF,
- DockInfo::MAXIMIZE
- };
-
- bool expected_result[] = {
- true, false, false
- };
-
- for (size_t i = 0; i < arraysize(expected_result); ++i) {
- bool result = d.CheckMonitorPoint(screen_loc[i], 0, 0, type[i]);
- EXPECT_EQ(result, expected_result[i]);
- if (result == true) {
- EXPECT_EQ(0, d.hot_spot().x());
- EXPECT_EQ(0, d.hot_spot().y());
- EXPECT_EQ(type[i], d.type());
- }
- }
-}
-
-TEST(DockInfoTest, GetPopupRect) {
- DockInfo d;
- d.set_hot_spot(gfx::Point(kPopupWidth, kPopupHeight));
- DockInfo::Type type[] = {
- DockInfo::MAXIMIZE,
- DockInfo::LEFT_HALF,
- DockInfo::RIGHT_HALF,
- DockInfo::BOTTOM_HALF,
- };
- int expected_x[] = {
- kPopupWidth/2,
- kPopupWidth,
- 0,
- kPopupWidth/2
- };
- int expected_y[] = {
- kPopupHeight,
- kPopupHeight/2,
- kPopupHeight/2,
- 0
- };
-
- for (size_t i = 0; i < arraysize(type); ++i) {
- d.set_type(type[i]);
- gfx::Rect result = d.GetPopupRect();
- EXPECT_EQ(expected_x[i], result.x());
- EXPECT_EQ(expected_y[i], result.y());
- EXPECT_EQ(kPopupWidth, result.width());
- EXPECT_EQ(kPopupHeight, result.height());
- }
-}
diff --git a/chrome/browser/dock_info_win.cc b/chrome/browser/dock_info_win.cc
deleted file mode 100644
index b6fd04f..0000000
--- a/chrome/browser/dock_info_win.cc
+++ /dev/null
@@ -1,326 +0,0 @@
-// 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.
-
-#include "chrome/browser/dock_info.h"
-
-#include "base/basictypes.h"
-#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_window.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/views/frame/browser_view.h"
-#include "chrome/browser/views/tabs/tab.h"
-
-namespace {
-
-// BaseWindowFinder -----------------------------------------------------------
-
-// Base class used to locate a window. This is intended to be used with the
-// various win32 functions that iterate over windows.
-//
-// A subclass need only override ShouldStopIterating to determine when
-// iteration should stop.
-class BaseWindowFinder {
- public:
- // Creates a BaseWindowFinder with the specified set of HWNDs to ignore.
- explicit BaseWindowFinder(const std::set<HWND>& ignore) : ignore_(ignore) {}
- virtual ~BaseWindowFinder() {}
-
- protected:
- // Returns true if iteration should stop, false if iteration should continue.
- virtual bool ShouldStopIterating(HWND window) = 0;
-
- static BOOL CALLBACK WindowCallbackProc(HWND hwnd, LPARAM lParam) {
- BaseWindowFinder* finder = reinterpret_cast<BaseWindowFinder*>(lParam);
- if (finder->ignore_.find(hwnd) != finder->ignore_.end())
- return TRUE;
-
- return finder->ShouldStopIterating(hwnd) ? FALSE : TRUE;
- }
-
- private:
- const std::set<HWND>& ignore_;
-
- DISALLOW_COPY_AND_ASSIGN(BaseWindowFinder);
-};
-
-// TopMostFinder --------------------------------------------------------------
-
-// Helper class to determine if a particular point of a window is not obscured
-// by another window.
-class TopMostFinder : public BaseWindowFinder {
- public:
- // Returns true if |window| is the topmost window at the location
- // |screen_loc|, not including the windows in |ignore|.
- static bool IsTopMostWindowAtPoint(HWND window,
- const gfx::Point& screen_loc,
- const std::set<HWND>& ignore) {
- TopMostFinder finder(window, screen_loc, ignore);
- return finder.is_top_most_;
- }
-
- virtual bool ShouldStopIterating(HWND hwnd) {
- if (hwnd == target_) {
- // Window is topmost, stop iterating.
- is_top_most_ = true;
- return true;
- }
-
- if (!IsWindowVisible(hwnd)) {
- // The window isn't visible, keep iterating.
- return false;
- }
-
- RECT r;
- if (!GetWindowRect(hwnd, &r) || !PtInRect(&r, screen_loc_.ToPOINT())) {
- // The window doesn't contain the point, keep iterating.
- return false;
- }
-
- LONG ex_styles = GetWindowLong(hwnd, GWL_EXSTYLE);
- if (ex_styles & WS_EX_TRANSPARENT || ex_styles & WS_EX_LAYERED) {
- // Mouse events fall through WS_EX_TRANSPARENT windows, so we ignore them.
- //
- // WS_EX_LAYERED is trickier. Apps like Switcher create a totally
- // transparent WS_EX_LAYERED window that is always on top. If we don't
- // ignore WS_EX_LAYERED windows and there are totally transparent
- // WS_EX_LAYERED windows then there are effectively holes on the screen
- // that the user can't reattach tabs to. So we ignore them. This is a bit
- // problematic in so far as WS_EX_LAYERED windows need not be totally
- // transparent in which case we treat chrome windows as not being obscured
- // when they really are, but this is better than not being able to
- // reattach tabs.
- return false;
- }
-
- // hwnd is at the point. Make sure the point is within the windows region.
- if (GetWindowRgn(hwnd, tmp_region_.Get()) == ERROR) {
- // There's no region on the window and the window contains the point. Stop
- // iterating.
- return true;
- }
-
- // The region is relative to the window's rect.
- BOOL is_point_in_region = PtInRegion(tmp_region_.Get(),
- screen_loc_.x() - r.left, screen_loc_.y() - r.top);
- tmp_region_ = CreateRectRgn(0, 0, 0, 0);
- // Stop iterating if the region contains the point.
- return !!is_point_in_region;
- }
-
- private:
- TopMostFinder(HWND window,
- const gfx::Point& screen_loc,
- const std::set<HWND>& ignore)
- : BaseWindowFinder(ignore),
- target_(window),
- screen_loc_(screen_loc),
- is_top_most_(false),
- tmp_region_(CreateRectRgn(0, 0, 0, 0)) {
- EnumWindows(WindowCallbackProc, reinterpret_cast<LPARAM>(this));
- }
-
- // The window we're looking for.
- HWND target_;
-
- // Location of window to find.
- gfx::Point screen_loc_;
-
- // Is target_ the top most window? This is initially false but set to true
- // in ShouldStopIterating if target_ is passed in.
- bool is_top_most_;
-
- ScopedRegion tmp_region_;
-
- DISALLOW_COPY_AND_ASSIGN(TopMostFinder);
-};
-
-// WindowFinder ---------------------------------------------------------------
-
-// Helper class to determine if a particular point contains a window from our
-// process.
-class LocalProcessWindowFinder : public BaseWindowFinder {
- public:
- // Returns the hwnd from our process at screen_loc that is not obscured by
- // another window. Returns NULL otherwise.
- static HWND GetProcessWindowAtPoint(const gfx::Point& screen_loc,
- const std::set<HWND>& ignore) {
- LocalProcessWindowFinder finder(screen_loc, ignore);
- if (finder.result_ &&
- TopMostFinder::IsTopMostWindowAtPoint(finder.result_, screen_loc,
- ignore)) {
- return finder.result_;
- }
- return NULL;
- }
-
- protected:
- virtual bool ShouldStopIterating(HWND hwnd) {
- RECT r;
- if (IsWindowVisible(hwnd) && GetWindowRect(hwnd, &r) &&
- PtInRect(&r, screen_loc_.ToPOINT())) {
- result_ = hwnd;
- return true;
- }
- return false;
- }
-
- private:
- LocalProcessWindowFinder(const gfx::Point& screen_loc,
- const std::set<HWND>& ignore)
- : BaseWindowFinder(ignore),
- screen_loc_(screen_loc),
- result_(NULL) {
- EnumThreadWindows(GetCurrentThreadId(), WindowCallbackProc,
- reinterpret_cast<LPARAM>(this));
- }
-
- // Position of the mouse.
- gfx::Point screen_loc_;
-
- // The resulting window. This is initially null but set to true in
- // ShouldStopIterating if an appropriate window is found.
- HWND result_;
-
- DISALLOW_COPY_AND_ASSIGN(LocalProcessWindowFinder);
-};
-
-// DockToWindowFinder ---------------------------------------------------------
-
-// Helper class for creating a DockInfo from a specified point.
-class DockToWindowFinder : public BaseWindowFinder {
- public:
- // Returns the DockInfo for the specified point. If there is no docking
- // position for the specified point the returned DockInfo has a type of NONE.
- static DockInfo GetDockInfoAtPoint(const gfx::Point& screen_loc,
- const std::set<HWND>& ignore) {
- DockToWindowFinder finder(screen_loc, ignore);
- if (!finder.result_.window() ||
- !TopMostFinder::IsTopMostWindowAtPoint(finder.result_.window(),
- finder.result_.hot_spot(),
- ignore)) {
- finder.result_.set_type(DockInfo::NONE);
- }
- return finder.result_;
- }
-
- protected:
- virtual bool ShouldStopIterating(HWND hwnd) {
- BrowserView* window = BrowserView::GetBrowserViewForNativeWindow(hwnd);
- RECT bounds;
- if (!window || !IsWindowVisible(hwnd) ||
- !GetWindowRect(hwnd, &bounds)) {
- return false;
- }
-
- // Check the three corners we allow docking to. We don't currently allow
- // docking to top of window as it conflicts with docking to the tab strip.
- if (CheckPoint(hwnd, bounds.left, (bounds.top + bounds.bottom) / 2,
- DockInfo::LEFT_OF_WINDOW) ||
- CheckPoint(hwnd, bounds.right - 1, (bounds.top + bounds.bottom) / 2,
- DockInfo::RIGHT_OF_WINDOW) ||
- CheckPoint(hwnd, (bounds.left + bounds.right) / 2, bounds.bottom - 1,
- DockInfo::BOTTOM_OF_WINDOW)) {
- return true;
- }
- return false;
- }
-
- private:
- DockToWindowFinder(const gfx::Point& screen_loc,
- const std::set<HWND>& ignore)
- : BaseWindowFinder(ignore),
- screen_loc_(screen_loc) {
- HMONITOR monitor = MonitorFromPoint(screen_loc.ToPOINT(),
- MONITOR_DEFAULTTONULL);
- MONITORINFO monitor_info = {0};
- monitor_info.cbSize = sizeof(MONITORINFO);
- if (monitor && GetMonitorInfo(monitor, &monitor_info)) {
- result_.set_monitor_bounds(gfx::Rect(monitor_info.rcWork));
- EnumThreadWindows(GetCurrentThreadId(), WindowCallbackProc,
- reinterpret_cast<LPARAM>(this));
- }
- }
-
- bool CheckPoint(HWND hwnd, int x, int y, DockInfo::Type type) {
- bool in_enable_area;
- if (DockInfo::IsCloseToPoint(screen_loc_, x, y, &in_enable_area)) {
- result_.set_in_enable_area(in_enable_area);
- result_.set_window(hwnd);
- result_.set_type(type);
- result_.set_hot_spot(gfx::Point(x, y));
- // Only show the hotspot if the monitor contains the bounds of the popup
- // window. Otherwise we end with a weird situation where the popup window
- // isn't completely visible.
- return result_.monitor_bounds().Contains(result_.GetPopupRect());
- }
- return false;
- }
-
- // The location to look for.
- gfx::Point screen_loc_;
-
- // The resulting DockInfo.
- DockInfo result_;
-
- DISALLOW_COPY_AND_ASSIGN(DockToWindowFinder);
-};
-
-} // namespace
-
-// DockInfo -------------------------------------------------------------------
-
-// static
-DockInfo DockInfo::GetDockInfoAtPoint(const gfx::Point& screen_point,
- const std::set<HWND>& ignore) {
- if (factory_)
- return factory_->GetDockInfoAtPoint(screen_point, ignore);
-
- // Try docking to a window first.
- DockInfo info = DockToWindowFinder::GetDockInfoAtPoint(screen_point, ignore);
- if (info.type() != DockInfo::NONE)
- return info;
-
- // No window relative positions. Try monitor relative positions.
- const gfx::Rect& m_bounds = info.monitor_bounds();
- int mid_x = m_bounds.x() + m_bounds.width() / 2;
- int mid_y = m_bounds.y() + m_bounds.height() / 2;
-
- bool result =
- info.CheckMonitorPoint(screen_point, mid_x, m_bounds.y(),
- DockInfo::MAXIMIZE) ||
- info.CheckMonitorPoint(screen_point, mid_x, m_bounds.bottom(),
- DockInfo::BOTTOM_HALF) ||
- info.CheckMonitorPoint(screen_point, m_bounds.x(), mid_y,
- DockInfo::LEFT_HALF) ||
- info.CheckMonitorPoint(screen_point, m_bounds.right(), mid_y,
- DockInfo::RIGHT_HALF);
-
- return info;
-}
-
-HWND DockInfo::GetLocalProcessWindowAtPoint(const gfx::Point& screen_point,
- const std::set<HWND>& ignore) {
- if (factory_)
- return factory_->GetLocalProcessWindowAtPoint(screen_point, ignore);
- return
- LocalProcessWindowFinder::GetProcessWindowAtPoint(screen_point, ignore);
-}
-
-bool DockInfo::GetWindowBounds(gfx::Rect* bounds) const {
- RECT window_rect;
- if (!window() || !GetWindowRect(window(), &window_rect))
- return false;
- *bounds = gfx::Rect(window_rect);
- return true;
-}
-
-void DockInfo::SizeOtherWindowTo(const gfx::Rect& bounds) const {
- if (IsZoomed(window())) {
- // We're docking relative to another window, we need to make sure the
- // window we're docking to isn't maximized.
- ShowWindow(window(), SW_RESTORE | SW_SHOWNA);
- }
- SetWindowPos(window(), HWND_TOP, bounds.x(), bounds.y(), bounds.width(),
- bounds.height(), SWP_NOACTIVATE | SWP_NOOWNERZORDER);
-}
diff --git a/chrome/browser/dom_ui/app_launcher_handler.cc b/chrome/browser/dom_ui/app_launcher_handler.cc
index e447da7..64d128a 100644
--- a/chrome/browser/dom_ui/app_launcher_handler.cc
+++ b/chrome/browser/dom_ui/app_launcher_handler.cc
@@ -12,12 +12,11 @@
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/app_launched_animation.h"
-#include "chrome/browser/dom_ui/shown_sections_handler.h"
#include "chrome/browser/extensions/default_apps.h"
#include "chrome/browser/extensions/extension_prefs.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/platform_util.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
@@ -74,10 +73,9 @@ bool IsPromoActive(const std::string& path) {
} // namespace
-AppLauncherHandler::AppLauncherHandler(ExtensionsService* extension_service)
+AppLauncherHandler::AppLauncherHandler(ExtensionService* extension_service)
: extensions_service_(extension_service),
- promo_active_(false),
- ignore_changes_(false) {
+ promo_active_(false) {
}
AppLauncherHandler::~AppLauncherHandler() {}
@@ -113,28 +111,16 @@ void AppLauncherHandler::CreateAppInfo(const Extension* extension,
}
// static
-bool AppLauncherHandler::HandlePing(Profile* profile, const std::string& path) {
- bool is_web_store_ping =
- path.find(kLaunchWebStorePingURL) != std::string::npos;
- bool is_app_launch_ping =
- path.find(kLaunchAppPingURL) != std::string::npos;
-
- // We get called for every URL in chrome://newtab/. Return false if it isn't
- // one we handle.
- if (!is_web_store_ping && !is_app_launch_ping)
- return false;
-
- bool is_promo_active = IsPromoActive(path);
-
- if (is_web_store_ping)
- RecordWebStoreLaunch(is_promo_active);
- else
- RecordAppLaunch(is_promo_active);
-
- if (is_promo_active)
- profile->GetExtensionsService()->default_apps()->SetPromoHidden();
+bool AppLauncherHandler::HandlePing(const std::string& path) {
+ if (path.find(kLaunchWebStorePingURL) != std::string::npos) {
+ RecordWebStoreLaunch(IsPromoActive(path));
+ return true;
+ } else if (path.find(kLaunchAppPingURL) != std::string::npos) {
+ RecordAppLaunch(IsPromoActive(path));
+ return true;
+ }
- return true;
+ return false;
}
DOMMessageHandler* AppLauncherHandler::Attach(DOMUI* dom_ui) {
@@ -160,9 +146,6 @@ void AppLauncherHandler::RegisterMessages() {
void AppLauncherHandler::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
- if (ignore_changes_)
- return;
-
switch (type.value) {
case NotificationType::EXTENSION_LOADED:
case NotificationType::EXTENSION_UNLOADED:
@@ -204,14 +187,26 @@ void AppLauncherHandler::FillAppDictionary(DictionaryValue* dictionary) {
dictionary->SetBoolean("disableCreateAppShortcut", true);
#endif
+#if defined(OS_CHROMEOS)
+ // Making shortcut does not make sense on ChromeOS because it does not have
+ // a desktop.
+ dictionary->SetBoolean("disableCreateAppShortcut", true);
+#endif
+
+ // We always show the launcher on Chrome OS. On Desktop Chrome, only show it
+ // if we've installed our default apps.
+#if defined(OS_CHROMEOS)
+ dictionary->SetBoolean("showLauncher", true);
+#else
dictionary->SetBoolean(
"showLauncher",
- extensions_service_->default_apps()->ShouldShowAppLauncher(
- extensions_service_->GetAppIds()));
+ extensions_service_->default_apps()->GetDefaultAppsInstalled());
+#endif
}
void AppLauncherHandler::HandleGetApps(const ListValue* args) {
DictionaryValue dictionary;
+ FillAppDictionary(&dictionary);
// Tell the client whether to show the promo for this view. We don't do this
// in the case of PREF_CHANGED because:
@@ -222,24 +217,15 @@ void AppLauncherHandler::HandleGetApps(const ListValue* args) {
// b) Conceptually, it doesn't really make sense to count a
// prefchange-triggered refresh as a promo 'view'.
DefaultApps* default_apps = extensions_service_->default_apps();
- bool promo_just_expired = false;
- if (default_apps->ShouldShowPromo(extensions_service_->GetAppIds(),
- &promo_just_expired)) {
+ if (default_apps->CheckShouldShowPromo(extensions_service_->GetAppIds())) {
dictionary.SetBoolean("showPromo", true);
+ default_apps->DidShowPromo();
promo_active_ = true;
} else {
- if (promo_just_expired) {
- ignore_changes_ = true;
- UninstallDefaultApps();
- ignore_changes_ = false;
- ShownSectionsHandler::SetShownSection(dom_ui_->GetProfile()->GetPrefs(),
- THUMB);
- }
dictionary.SetBoolean("showPromo", false);
promo_active_ = false;
}
- FillAppDictionary(&dictionary);
dom_ui_->CallJavascriptFunction(L"getAppsCallback", dictionary);
// First time we get here we set up the observer so that we can tell update
@@ -306,10 +292,8 @@ void AppLauncherHandler::HandleLaunchApp(const ListValue* args) {
if (new_contents != old_contents && browser->tab_count() > 1)
browser->CloseTabContents(old_contents);
- if (extension_id != extension_misc::kWebStoreAppId) {
+ if (extension_id != extension_misc::kWebStoreAppId)
RecordAppLaunch(promo_active_);
- extensions_service_->default_apps()->SetPromoHidden();
- }
}
void AppLauncherHandler::HandleSetLaunchType(const ListValue* args) {
@@ -351,14 +335,17 @@ void AppLauncherHandler::HandleHideAppsPromo(const ListValue* args) {
UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppsPromoHistogram,
extension_misc::PROMO_CLOSE,
extension_misc::PROMO_BUCKET_BOUNDARY);
+ DefaultApps* default_apps = extensions_service_->default_apps();
+ const ExtensionIdSet* app_ids = default_apps->GetDefaultApps();
+ DCHECK(*app_ids == extensions_service_->GetAppIds());
+
+ for (ExtensionIdSet::const_iterator iter = app_ids->begin();
+ iter != app_ids->end(); ++iter) {
+ if (extensions_service_->GetExtensionById(*iter, true))
+ extensions_service_->UninstallExtension(*iter, false);
+ }
- ShownSectionsHandler::SetShownSection(dom_ui_->GetProfile()->GetPrefs(),
- THUMB);
- ignore_changes_ = true;
- UninstallDefaultApps();
extensions_service_->default_apps()->SetPromoHidden();
- ignore_changes_ = false;
- HandleGetApps(NULL);
}
void AppLauncherHandler::HandleCreateAppShortcut(const ListValue* args) {
@@ -437,13 +424,3 @@ void AppLauncherHandler::AnimateAppIcon(const Extension* extension,
#endif
}
}
-
-void AppLauncherHandler::UninstallDefaultApps() {
- DefaultApps* default_apps = extensions_service_->default_apps();
- const ExtensionIdSet& app_ids = default_apps->default_apps();
- for (ExtensionIdSet::const_iterator iter = app_ids.begin();
- iter != app_ids.end(); ++iter) {
- if (extensions_service_->GetExtensionById(*iter, true))
- extensions_service_->UninstallExtension(*iter, false);
- }
-}
diff --git a/chrome/browser/dom_ui/app_launcher_handler.h b/chrome/browser/dom_ui/app_launcher_handler.h
index ac711c7..5f946d9 100644
--- a/chrome/browser/dom_ui/app_launcher_handler.h
+++ b/chrome/browser/dom_ui/app_launcher_handler.h
@@ -15,10 +15,9 @@
class Extension;
class ExtensionPrefs;
-class ExtensionsService;
+class ExtensionService;
class NotificationRegistrar;
class PrefChangeRegistrar;
-class Profile;
namespace gfx {
class Rect;
@@ -30,7 +29,7 @@ class AppLauncherHandler
public ExtensionInstallUI::Delegate,
public NotificationObserver {
public:
- explicit AppLauncherHandler(ExtensionsService* extension_service);
+ explicit AppLauncherHandler(ExtensionService* extension_service);
virtual ~AppLauncherHandler();
// Populate a dictionary with the information from an extension.
@@ -39,7 +38,7 @@ class AppLauncherHandler
DictionaryValue* value);
// Callback for pings related to launching apps on the NTP.
- static bool HandlePing(Profile* profile, const std::string& path);
+ static bool HandlePing(const std::string& path);
// DOMMessageHandler implementation.
virtual DOMMessageHandler* Attach(DOMUI* dom_ui);
@@ -92,11 +91,8 @@ class AppLauncherHandler
// Starts the animation of the app icon.
void AnimateAppIcon(const Extension* extension, const gfx::Rect& rect);
- // Helper that uninstalls all the default apps.
- void UninstallDefaultApps();
-
// The apps are represented in the extensions model.
- scoped_refptr<ExtensionsService> extensions_service_;
+ scoped_refptr<ExtensionService> extensions_service_;
// We monitor changes to the extension system so that we can reload the apps
// when necessary.
@@ -115,10 +111,6 @@ class AppLauncherHandler
// Whether the promo is currently being shown.
bool promo_active_;
- // When true, we ignore changes to the underlying data rather than immediately
- // refreshing. This is useful when making many batch updates to avoid flicker.
- bool ignore_changes_;
-
DISALLOW_COPY_AND_ASSIGN(AppLauncherHandler);
};
diff --git a/chrome/browser/dom_ui/bookmarks_ui.cc b/chrome/browser/dom_ui/bookmarks_ui.cc
index c824f67..1875d45 100644
--- a/chrome/browser/dom_ui/bookmarks_ui.cc
+++ b/chrome/browser/dom_ui/bookmarks_ui.cc
@@ -51,7 +51,7 @@ BookmarksUI::BookmarksUI(TabContents* contents) : DOMUI(contents) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(html_source)));
}
diff --git a/chrome/browser/dom_ui/bug_report_ui.cc b/chrome/browser/dom_ui/bug_report_ui.cc
index 5bcd846..4c92c73 100644
--- a/chrome/browser/dom_ui/bug_report_ui.cc
+++ b/chrome/browser/dom_ui/bug_report_ui.cc
@@ -30,7 +30,6 @@
#include "chrome/common/jstemplate_builder.h"
#include "chrome/common/url_constants.h"
#include "gfx/rect.h"
-#include "views/window/window.h"
#include "grit/browser_resources.h"
#include "grit/chromium_strings.h"
@@ -45,6 +44,10 @@
#include "app/win_util.h"
#endif
+#if defined(TOOLKIT_VIEWS)
+#include "views/window/window.h"
+#endif
+
#if defined(OS_CHROMEOS)
#include "base/file_util.h"
#include "base/path_service.h"
@@ -196,7 +199,6 @@ void ShowHtmlBugReportView(NSWindow* window, Browser* browser) {
if (feedback_tab_index >=0) {
// Do not refresh screenshot, do not create a new tab
browser->SelectTabContentsAt(feedback_tab_index, true);
- return;
}
// now for refreshing the last screenshot
@@ -513,7 +515,7 @@ void BugReportHandler::ClobberScreenshotsSource() {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(new DOMUIScreenshotSource(NULL))));
@@ -532,7 +534,7 @@ void BugReportHandler::SetupScreenshotsSource() {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(screenshot_source_)));
}
@@ -572,7 +574,7 @@ base::StringPiece BugReportHandler::Init() {
TabContents* target_tab = browser->GetTabContentsAt(index);
if (target_tab) {
target_tab_title_ = target_tab->GetTitle();
- target_tab_url_ = target_tab->controller().GetActiveEntry()->url().spec();
+ target_tab_url_ = target_tab->GetURL().spec();
}
// Setup the screenshot source after we've verified input is legit.
@@ -805,7 +807,7 @@ BugReportUI::BugReportUI(TabContents* tab) : HtmlDialogUI(tab) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(html_source)));
}
diff --git a/chrome/browser/dom_ui/chrome_url_data_manager.cc b/chrome/browser/dom_ui/chrome_url_data_manager.cc
index 11f0d88..42af812 100644
--- a/chrome/browser/dom_ui/chrome_url_data_manager.cc
+++ b/chrome/browser/dom_ui/chrome_url_data_manager.cc
@@ -18,7 +18,6 @@
#include "base/win/windows_version.h"
#endif
#include "chrome/browser/appcache/view_appcache_internals_job_factory.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/dom_ui/shared_resources_data_source.h"
#include "chrome/browser/net/chrome_url_request_context.h"
@@ -35,15 +34,15 @@
#include "net/url_request/url_request_file_job.h"
#include "net/url_request/url_request_job.h"
-// URLRequestChromeJob is a URLRequestJob that manages running chrome-internal
-// resource requests asynchronously.
+// URLRequestChromeJob is a net::URLRequestJob that manages running
+// chrome-internal resource requests asynchronously.
// It hands off URL requests to ChromeURLDataManager, which asynchronously
// calls back once the data is available.
class URLRequestChromeJob : public net::URLRequestJob {
public:
- explicit URLRequestChromeJob(URLRequest* request);
+ explicit URLRequestChromeJob(net::URLRequest* request);
- // URLRequestJob implementation.
+ // net::URLRequestJob implementation.
virtual void Start();
virtual void Kill();
virtual bool ReadRawData(net::IOBuffer* buf, int buf_size, int *bytes_read);
@@ -61,7 +60,7 @@ class URLRequestChromeJob : public net::URLRequestJob {
virtual ~URLRequestChromeJob();
// Helper for Start(), to let us start asynchronously.
- // (This pattern is shared by most URLRequestJob implementations.)
+ // (This pattern is shared by most net::URLRequestJob implementations.)
void StartAsync();
// Do the actual copy from data_ (the data we're serving) into |buf|.
@@ -83,10 +82,10 @@ class URLRequestChromeJob : public net::URLRequestJob {
DISALLOW_COPY_AND_ASSIGN(URLRequestChromeJob);
};
-// URLRequestChromeFileJob is a URLRequestJob that acts like a file:// URL
-class URLRequestChromeFileJob : public URLRequestFileJob {
+// URLRequestChromeFileJob is a net::URLRequestJob that acts like a file:// URL
+class URLRequestChromeFileJob : public net::URLRequestFileJob {
public:
- URLRequestChromeFileJob(URLRequest* request, const FilePath& path);
+ URLRequestChromeFileJob(net::URLRequest* request, const FilePath& path);
private:
virtual ~URLRequestChromeFileJob();
@@ -97,21 +96,21 @@ class URLRequestChromeFileJob : public URLRequestFileJob {
void RegisterURLRequestChromeJob() {
FilePath inspector_dir;
if (PathService::Get(chrome::DIR_INSPECTOR, &inspector_dir)) {
- Singleton<ChromeURLDataManager>()->AddFileSource(
+ ChromeURLDataManager::GetInstance()->AddFileSource(
chrome::kChromeUIDevToolsHost, inspector_dir);
}
SharedResourcesDataSource::Register();
- URLRequest::RegisterProtocolFactory(chrome::kChromeDevToolsScheme,
- &ChromeURLDataManager::Factory);
- URLRequest::RegisterProtocolFactory(chrome::kChromeUIScheme,
- &ChromeURLDataManager::Factory);
+ net::URLRequest::RegisterProtocolFactory(chrome::kChromeDevToolsScheme,
+ &ChromeURLDataManager::Factory);
+ net::URLRequest::RegisterProtocolFactory(chrome::kChromeUIScheme,
+ &ChromeURLDataManager::Factory);
}
void UnregisterURLRequestChromeJob() {
FilePath inspector_dir;
if (PathService::Get(chrome::DIR_INSPECTOR, &inspector_dir)) {
- Singleton<ChromeURLDataManager>()->RemoveFileSource(
+ ChromeURLDataManager::GetInstance()->RemoveFileSource(
chrome::kChromeUIDevToolsHost);
}
}
@@ -159,8 +158,8 @@ bool ChromeURLDataManager::URLToFilePath(const GURL& url,
URLToRequest(stripped_url, &source_name, &relative_path);
FileSourceMap::const_iterator i(
- Singleton<ChromeURLDataManager>()->file_sources_.find(source_name));
- if (i == Singleton<ChromeURLDataManager>()->file_sources_.end())
+ ChromeURLDataManager::GetInstance()->file_sources_.find(source_name));
+ if (i == ChromeURLDataManager::GetInstance()->file_sources_.end())
return false;
// Check that |relative_path| is not an absolute path (otherwise AppendASCII()
@@ -179,6 +178,11 @@ ChromeURLDataManager::ChromeURLDataManager() : next_request_id_(0) { }
ChromeURLDataManager::~ChromeURLDataManager() { }
+// static
+ChromeURLDataManager* ChromeURLDataManager::GetInstance() {
+ return Singleton<ChromeURLDataManager>::get();
+}
+
void ChromeURLDataManager::AddDataSource(scoped_refptr<DataSource> source) {
// TODO(jackson): A new data source with same name should not clobber the
// existing one.
@@ -264,7 +268,7 @@ void ChromeURLDataManager::RemoveRequest(URLRequestChromeJob* job) {
void ChromeURLDataManager::DataAvailable(
RequestID request_id,
scoped_refptr<RefCountedMemory> bytes) {
- // Forward this data on to the pending URLRequest, if it exists.
+ // Forward this data on to the pending net::URLRequest, if it exists.
PendingRequestMap::iterator i = pending_requests_.find(request_id);
if (i != pending_requests_.end()) {
// We acquire a reference to the job so that it doesn't disappear under the
@@ -288,7 +292,7 @@ void ChromeURLDataManager::DataSource::SendResponse(
RefCountedMemory* bytes) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(Singleton<ChromeURLDataManager>::get(),
+ NewRunnableMethod(ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::DataAvailable,
request_id, scoped_refptr<RefCountedMemory>(bytes)));
}
@@ -318,8 +322,8 @@ void ChromeURLDataManager::DataSource::SetFontAndTextDirection(
base::i18n::IsRTL() ? "rtl" : "ltr");
}
-URLRequestJob* ChromeURLDataManager::Factory(URLRequest* request,
- const std::string& scheme) {
+net::URLRequestJob* ChromeURLDataManager::Factory(net::URLRequest* request,
+ const std::string& scheme) {
// Try first with a file handler
FilePath path;
if (ChromeURLDataManager::URLToFilePath(request->url(), &path))
@@ -341,14 +345,14 @@ URLRequestJob* ChromeURLDataManager::Factory(URLRequest* request,
return new URLRequestChromeJob(request);
}
-URLRequestChromeJob::URLRequestChromeJob(URLRequest* request)
- : URLRequestJob(request),
+URLRequestChromeJob::URLRequestChromeJob(net::URLRequest* request)
+ : net::URLRequestJob(request),
data_offset_(0),
pending_buf_size_(0) {
}
URLRequestChromeJob::~URLRequestChromeJob() {
- CHECK(!Singleton<ChromeURLDataManager>()->HasPendingJob(this));
+ CHECK(!ChromeURLDataManager::GetInstance()->HasPendingJob(this));
}
void URLRequestChromeJob::Start() {
@@ -359,7 +363,7 @@ void URLRequestChromeJob::Start() {
}
void URLRequestChromeJob::Kill() {
- Singleton<ChromeURLDataManager>()->RemoveRequest(this);
+ ChromeURLDataManager::GetInstance()->RemoveRequest(this);
}
bool URLRequestChromeJob::GetMimeType(std::string* mime_type) const {
@@ -419,7 +423,8 @@ void URLRequestChromeJob::StartAsync() {
if (!request_)
return;
- if (Singleton<ChromeURLDataManager>()->StartRequest(request_->url(), this)) {
+ if (ChromeURLDataManager::GetInstance()->StartRequest(request_->url(),
+ this)) {
NotifyHeadersComplete();
} else {
NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED,
@@ -427,9 +432,9 @@ void URLRequestChromeJob::StartAsync() {
}
}
-URLRequestChromeFileJob::URLRequestChromeFileJob(URLRequest* request,
+URLRequestChromeFileJob::URLRequestChromeFileJob(net::URLRequest* request,
const FilePath& path)
- : URLRequestFileJob(request, path) {
+ : net::URLRequestFileJob(request, path) {
}
URLRequestChromeFileJob::~URLRequestChromeFileJob() { }
diff --git a/chrome/browser/dom_ui/chrome_url_data_manager.h b/chrome/browser/dom_ui/chrome_url_data_manager.h
index c6b6e76..709cdcb 100644
--- a/chrome/browser/dom_ui/chrome_url_data_manager.h
+++ b/chrome/browser/dom_ui/chrome_url_data_manager.h
@@ -9,6 +9,7 @@
#include <map>
#include <string>
+#include "base/singleton.h"
#include "base/task.h"
#include "base/ref_counted.h"
@@ -32,8 +33,8 @@ class URLRequestJob;
// it from the UI thread needs to go through an InvokeLater.
class ChromeURLDataManager {
public:
- ChromeURLDataManager();
- ~ChromeURLDataManager();
+ // Returns the singleton instance.
+ static ChromeURLDataManager* GetInstance();
typedef int RequestID;
@@ -122,6 +123,10 @@ class ChromeURLDataManager {
private:
friend class URLRequestChromeJob;
+ friend struct DefaultSingletonTraits<ChromeURLDataManager>;
+
+ ChromeURLDataManager();
+ ~ChromeURLDataManager();
// Parse a URL into the components used to resolve its request.
static void URLToRequest(const GURL& url,
diff --git a/chrome/browser/dom_ui/conflicts_ui.cc b/chrome/browser/dom_ui/conflicts_ui.cc
index 555430e..ed51f21 100644
--- a/chrome/browser/dom_ui/conflicts_ui.cc
+++ b/chrome/browser/dom_ui/conflicts_ui.cc
@@ -15,6 +15,8 @@
#include "base/values.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
#include "chrome/browser/enumerate_modules_model_win.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/jstemplate_builder.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
@@ -140,11 +142,11 @@ void ConflictsDOMHandler::HandleRequestModuleList(const ListValue* args) {
// This request is handled asynchronously. See Observe for when we reply back.
registrar_.Add(this, NotificationType::MODULE_LIST_ENUMERATED,
NotificationService::AllSources());
- EnumerateModulesModel::GetSingleton()->ScanNow();
+ EnumerateModulesModel::GetInstance()->ScanNow();
}
void ConflictsDOMHandler::SendModuleList() {
- EnumerateModulesModel* loaded_modules = EnumerateModulesModel::GetSingleton();
+ EnumerateModulesModel* loaded_modules = EnumerateModulesModel::GetInstance();
ListValue* list = loaded_modules->GetModuleList();
DictionaryValue results;
results.Set("moduleList", list);
@@ -192,6 +194,9 @@ void ConflictsDOMHandler::Observe(NotificationType type,
///////////////////////////////////////////////////////////////////////////////
ConflictsUI::ConflictsUI(TabContents* contents) : DOMUI(contents) {
+ UserMetrics::RecordAction(
+ UserMetricsAction("ViewAboutConflicts"), contents->profile());
+
AddMessageHandler((new ConflictsDOMHandler())->Attach(this));
ConflictsUIHTMLSource* html_source = new ConflictsUIHTMLSource();
@@ -199,9 +204,9 @@ ConflictsUI::ConflictsUI(TabContents* contents) : DOMUI(contents) {
// Set up the about:conflicts source.
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(Singleton<ChromeURLDataManager>::get(),
- &ChromeURLDataManager::AddDataSource,
- make_scoped_refptr(html_source)));
+ NewRunnableMethod(ChromeURLDataManager::GetInstance(),
+ &ChromeURLDataManager::AddDataSource,
+ make_scoped_refptr(html_source)));
}
// static
diff --git a/chrome/browser/dom_ui/constrained_html_ui.cc b/chrome/browser/dom_ui/constrained_html_ui.cc
index d15644c..75aeda1 100644
--- a/chrome/browser/dom_ui/constrained_html_ui.cc
+++ b/chrome/browser/dom_ui/constrained_html_ui.cc
@@ -4,12 +4,16 @@
#include "chrome/browser/dom_ui/constrained_html_ui.h"
-#include "base/singleton.h"
+#include "base/lazy_instance.h"
#include "chrome/browser/dom_ui/dom_ui_util.h"
#include "chrome/browser/dom_ui/html_dialog_ui.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/common/bindings_policy.h"
+static base::LazyInstance<PropertyAccessor<ConstrainedHtmlUIDelegate*> >
+ g_constrained_html_ui_property_accessor(base::LINKER_INITIALIZED);
+
ConstrainedHtmlUI::ConstrainedHtmlUI(TabContents* contents)
: DOMUI(contents) {
}
@@ -50,5 +54,5 @@ ConstrainedHtmlUIDelegate*
// static
PropertyAccessor<ConstrainedHtmlUIDelegate*>&
ConstrainedHtmlUI::GetPropertyAccessor() {
- return *Singleton<PropertyAccessor<ConstrainedHtmlUIDelegate*> >::get();
+ return g_constrained_html_ui_property_accessor.Get();
}
diff --git a/chrome/browser/dom_ui/constrained_html_ui.h b/chrome/browser/dom_ui/constrained_html_ui.h
index 8327c99..48b769f 100644
--- a/chrome/browser/dom_ui/constrained_html_ui.h
+++ b/chrome/browser/dom_ui/constrained_html_ui.h
@@ -10,7 +10,7 @@
#include "chrome/browser/dom_ui/dom_ui.h"
#include "chrome/browser/tab_contents/constrained_window.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/property_bag.h"
class HtmlDialogUIDelegate;
class Profile;
diff --git a/chrome/browser/dom_ui/constrained_html_ui_browsertest.cc b/chrome/browser/dom_ui/constrained_html_ui_browsertest.cc
index a1cd300..2862dbe 100644
--- a/chrome/browser/dom_ui/constrained_html_ui_browsertest.cc
+++ b/chrome/browser/dom_ui/constrained_html_ui_browsertest.cc
@@ -6,7 +6,6 @@
#include "base/file_path.h"
#include "base/message_loop.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/dom_ui/constrained_html_ui.h"
#include "chrome/browser/dom_ui/html_dialog_ui.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
diff --git a/chrome/browser/dom_ui/dom_ui.cc b/chrome/browser/dom_ui/dom_ui.cc
index 06c7d2d..fdefd38 100644
--- a/chrome/browser/dom_ui/dom_ui.cc
+++ b/chrome/browser/dom_ui/dom_ui.cc
@@ -10,7 +10,7 @@
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
diff --git a/chrome/browser/dom_ui/dom_ui_factory.cc b/chrome/browser/dom_ui/dom_ui_factory.cc
index 414f41f..6f7eaaf 100644
--- a/chrome/browser/dom_ui/dom_ui_factory.cc
+++ b/chrome/browser/dom_ui/dom_ui_factory.cc
@@ -6,18 +6,15 @@
#include "base/command_line.h"
#include "chrome/browser/about_flags.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/dom_ui/bookmarks_ui.h"
#include "chrome/browser/dom_ui/bug_report_ui.h"
#include "chrome/browser/dom_ui/constrained_html_ui.h"
#include "chrome/browser/dom_ui/downloads_ui.h"
#include "chrome/browser/dom_ui/devtools_ui.h"
+#include "chrome/browser/dom_ui/gpu_internals_ui.h"
#include "chrome/browser/dom_ui/history_ui.h"
#include "chrome/browser/dom_ui/history2_ui.h"
#include "chrome/browser/dom_ui/html_dialog_ui.h"
-#if defined(TOUCH_UI)
-#include "chrome/browser/dom_ui/keyboard_ui.h"
-#endif
#include "chrome/browser/dom_ui/flags_ui.h"
#include "chrome/browser/dom_ui/net_internals_ui.h"
#include "chrome/browser/dom_ui/new_tab_ui.h"
@@ -28,10 +25,10 @@
#include "chrome/browser/dom_ui/slideshow_ui.h"
#include "chrome/browser/dom_ui/textfields_ui.h"
#include "chrome/browser/extensions/extension_dom_ui.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extensions_ui.h"
#include "chrome/browser/printing/print_dialog_cloud.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension_constants.h"
@@ -51,6 +48,11 @@
#include "chrome/browser/dom_ui/mediaplayer_ui.h"
#endif
+#if defined(TOUCH_UI)
+#include "chrome/browser/dom_ui/keyboard_ui.h"
+#include "chrome/browser/chromeos/dom_ui/login/login_ui.h"
+#endif
+
#if defined(OS_WIN)
#include "chrome/browser/dom_ui/conflicts_ui.h"
#endif
@@ -73,7 +75,7 @@ template<>
DOMUI* NewDOMUI<ExtensionDOMUI>(TabContents* contents, const GURL& url) {
// Don't use a DOMUI for incognito tabs because we require extensions to run
// within a single process.
- ExtensionsService* service = contents->profile()->GetExtensionsService();
+ ExtensionService* service = contents->profile()->GetExtensionService();
if (service &&
service->ExtensionBindingsAllowed(url)) {
return new ExtensionDOMUI(contents, url);
@@ -94,7 +96,7 @@ static DOMUIFactoryFunction GetDOMUIFactoryFunction(Profile* profile,
if (url.host() == chrome::kChromeUIDialogHost)
return &NewDOMUI<ConstrainedHtmlUI>;
- ExtensionsService* service = profile->GetExtensionsService();
+ ExtensionService* service = profile->GetExtensionService();
if (service && service->ExtensionBindingsAllowed(url))
return &NewDOMUI<ExtensionDOMUI>;
@@ -156,6 +158,8 @@ static DOMUIFactoryFunction GetDOMUIFactoryFunction(Profile* profile,
if (url.host() == chrome::kChromeUIKeyboardHost)
return &NewDOMUI<KeyboardUI>;
#endif
+ if (url.host() == chrome::kChromeUIGpuInternalsHost)
+ return &NewDOMUI<GpuInternalsUI>;
if (url.host() == chrome::kChromeUINetInternalsHost)
return &NewDOMUI<NetInternalsUI>;
if (url.host() == chrome::kChromeUIPluginsHost)
@@ -207,6 +211,11 @@ static DOMUIFactoryFunction GetDOMUIFactoryFunction(Profile* profile,
return &NewDOMUI<PrintPreviewUI>;
}
}
+#endif // defined(OS_CHROMEOS)
+
+#if defined(OS_CHROMEOS) && defined(TOUCH_UI)
+ if (url.host() == chrome::kChromeUILoginHost)
+ return &NewDOMUI<chromeos::LoginUI>;
#endif
if (url.spec() == chrome::kChromeUIConstrainedHTMLTestURL)
diff --git a/chrome/browser/dom_ui/dom_ui_favicon_source.cc b/chrome/browser/dom_ui/dom_ui_favicon_source.cc
index de5adba..565d4ed 100644
--- a/chrome/browser/dom_ui/dom_ui_favicon_source.cc
+++ b/chrome/browser/dom_ui/dom_ui_favicon_source.cc
@@ -6,8 +6,7 @@
#include "app/resource_bundle.h"
#include "base/callback.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/url_constants.h"
#include "grit/app_resources.h"
diff --git a/chrome/browser/dom_ui/dom_ui_screenshot_source.cc b/chrome/browser/dom_ui/dom_ui_screenshot_source.cc
index db35499..110a52e 100644
--- a/chrome/browser/dom_ui/dom_ui_screenshot_source.cc
+++ b/chrome/browser/dom_ui/dom_ui_screenshot_source.cc
@@ -115,3 +115,9 @@ void DOMUIScreenshotSource::StartDataRequest(const std::string& path,
int request_id) {
SendResponse(request_id, new RefCountedBytes(GetScreenshot(path)));
}
+
+std::string DOMUIScreenshotSource::GetMimeType(const std::string&) const {
+ // We need to explicitly return a mime type, otherwise if the user tries to
+ // drag the image they get no extension.
+ return "image/png";
+}
diff --git a/chrome/browser/dom_ui/dom_ui_screenshot_source.h b/chrome/browser/dom_ui/dom_ui_screenshot_source.h
index 8cd8b2c..3a9aafc 100644
--- a/chrome/browser/dom_ui/dom_ui_screenshot_source.h
+++ b/chrome/browser/dom_ui/dom_ui_screenshot_source.h
@@ -27,11 +27,7 @@ class DOMUIScreenshotSource : public ChromeURLDataManager::DataSource {
bool is_off_the_record,
int request_id);
- virtual std::string GetMimeType(const std::string&) const {
- // We need to explicitly return a mime type, otherwise if the user tries to
- // drag the image they get no extension.
- return "image/png";
- }
+ virtual std::string GetMimeType(const std::string&) const;
std::vector<unsigned char> GetScreenshot(const std::string& path);
diff --git a/chrome/browser/dom_ui/dom_ui_theme_source.cc b/chrome/browser/dom_ui/dom_ui_theme_source.cc
index d15202a..cbddafd 100644
--- a/chrome/browser/dom_ui/dom_ui_theme_source.cc
+++ b/chrome/browser/dom_ui/dom_ui_theme_source.cc
@@ -10,7 +10,7 @@
#include "base/ref_counted_memory.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/dom_ui/ntp_resource_cache.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/resources_util.h"
#include "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/common/url_constants.h"
diff --git a/chrome/browser/dom_ui/dom_ui_theme_source_unittest.cc b/chrome/browser/dom_ui/dom_ui_theme_source_unittest.cc
index 2ce7bfc..fb7a0ad 100644
--- a/chrome/browser/dom_ui/dom_ui_theme_source_unittest.cc
+++ b/chrome/browser/dom_ui/dom_ui_theme_source_unittest.cc
@@ -5,7 +5,7 @@
#include "base/ref_counted_memory.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/dom_ui/dom_ui_theme_source.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/testing_profile.h"
diff --git a/chrome/browser/dom_ui/dom_ui_thumbnail_source.cc b/chrome/browser/dom_ui/dom_ui_thumbnail_source.cc
index 4ed9d4a..8b15821 100644
--- a/chrome/browser/dom_ui/dom_ui_thumbnail_source.cc
+++ b/chrome/browser/dom_ui/dom_ui_thumbnail_source.cc
@@ -6,9 +6,8 @@
#include "app/resource_bundle.h"
#include "base/callback.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/history/top_sites.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
#include "googleurl/src/gurl.h"
#include "grit/theme_resources.h"
diff --git a/chrome/browser/dom_ui/downloads_dom_handler.cc b/chrome/browser/dom_ui/downloads_dom_handler.cc
index 5617d2b..07ca6fc 100644
--- a/chrome/browser/dom_ui/downloads_dom_handler.cc
+++ b/chrome/browser/dom_ui/downloads_dom_handler.cc
@@ -4,6 +4,9 @@
#include "chrome/browser/dom_ui/downloads_dom_handler.h"
+#include <algorithm>
+#include <functional>
+
#include "base/basictypes.h"
#include "base/callback.h"
#include "base/singleton.h"
@@ -19,7 +22,6 @@
#include "chrome/browser/download/download_item.h"
#include "chrome/browser/download/download_util.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/jstemplate_builder.h"
#include "chrome/common/url_constants.h"
@@ -42,7 +44,7 @@ class DownloadItemSorter : public std::binary_function<DownloadItem*,
}
};
-} // namespace
+} // namespace
DownloadsDOMHandler::DownloadsDOMHandler(DownloadManager* dlm)
: search_text_(),
@@ -52,7 +54,7 @@ DownloadsDOMHandler::DownloadsDOMHandler(DownloadManager* dlm)
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(new FileIconSource())));
}
diff --git a/chrome/browser/dom_ui/downloads_ui.cc b/chrome/browser/dom_ui/downloads_ui.cc
index f59ba5c..9c033ea 100644
--- a/chrome/browser/dom_ui/downloads_ui.cc
+++ b/chrome/browser/dom_ui/downloads_ui.cc
@@ -15,7 +15,7 @@
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
#include "chrome/browser/dom_ui/downloads_dom_handler.h"
#include "chrome/browser/download/download_manager.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/jstemplate_builder.h"
#include "chrome/common/url_constants.h"
#include "grit/browser_resources.h"
@@ -136,9 +136,9 @@ DownloadsUI::DownloadsUI(TabContents* contents) : DOMUI(contents) {
// Set up the chrome://downloads/ source.
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(Singleton<ChromeURLDataManager>::get(),
- &ChromeURLDataManager::AddDataSource,
- make_scoped_refptr(html_source)));
+ NewRunnableMethod(ChromeURLDataManager::GetInstance(),
+ &ChromeURLDataManager::AddDataSource,
+ make_scoped_refptr(html_source)));
}
// static
diff --git a/chrome/browser/dom_ui/filebrowse_ui.cc b/chrome/browser/dom_ui/filebrowse_ui.cc
index 9e5a3d5..41ab3c2 100644
--- a/chrome/browser/dom_ui/filebrowse_ui.cc
+++ b/chrome/browser/dom_ui/filebrowse_ui.cc
@@ -29,7 +29,7 @@
#include "chrome/browser/download/download_util.h"
#include "chrome/browser/history/history_types.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h"
@@ -422,7 +422,7 @@ DOMMessageHandler* FilebrowseHandler::Attach(DOMUI* dom_ui) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(new DOMUIFavIconSource(dom_ui->GetProfile()))));
profile_ = dom_ui->GetProfile();
@@ -622,7 +622,7 @@ void FilebrowseHandler::PlayMediaFile(const ListValue* args) {
Browser* browser = Browser::GetBrowserForController(
&tab_contents_->controller(), NULL);
- MediaPlayer* mediaplayer = MediaPlayer::Get();
+ MediaPlayer* mediaplayer = MediaPlayer::GetInstance();
mediaplayer->ForcePlayMediaURL(gurl, browser);
#endif
}
@@ -634,7 +634,7 @@ void FilebrowseHandler::EnqueueMediaFile(const ListValue* args) {
Browser* browser = Browser::GetBrowserForController(
&tab_contents_->controller(), NULL);
- MediaPlayer* mediaplayer = MediaPlayer::Get();
+ MediaPlayer* mediaplayer = MediaPlayer::GetInstance();
mediaplayer->EnqueueMediaURL(gurl, browser);
#endif
}
@@ -823,7 +823,7 @@ void FilebrowseHandler::GetChildrenForPath(FilePath& path, bool is_refresh) {
#if defined(OS_CHROMEOS)
// Don't allow listing files in inaccessible dirs.
- if (URLRequestFileJob::AccessDisabled(path))
+ if (net::URLRequestFileJob::AccessDisabled(path))
return;
#endif // OS_CHROMEOS
@@ -971,7 +971,7 @@ void FilebrowseHandler::HandleDeleteFile(const ListValue* args) {
FilePath currentpath(path);
// Don't allow file deletion in inaccessible dirs.
- if (URLRequestFileJob::AccessDisabled(currentpath))
+ if (net::URLRequestFileJob::AccessDisabled(currentpath))
return;
for (unsigned int x = 0; x < active_download_items_.size(); x++) {
@@ -1008,7 +1008,7 @@ void FilebrowseHandler::HandleCopyFile(const ListValue* value) {
FilePath DestPath = FilePath(dest);
// Don't allow file copy to inaccessible dirs.
- if (URLRequestFileJob::AccessDisabled(DestPath))
+ if (net::URLRequestFileJob::AccessDisabled(DestPath))
return;
TaskProxy* task = new TaskProxy(AsWeakPtr(), SrcPath, DestPath);
@@ -1129,7 +1129,7 @@ FileBrowseUI::FileBrowseUI(TabContents* contents) : HtmlDialogUI(contents) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(html_source)));
}
diff --git a/chrome/browser/dom_ui/fileicon_source.cc b/chrome/browser/dom_ui/fileicon_source.cc
index 7572cdc..a720df8 100644
--- a/chrome/browser/dom_ui/fileicon_source.cc
+++ b/chrome/browser/dom_ui/fileicon_source.cc
@@ -59,6 +59,11 @@ void FileIconSource::StartDataRequest(const std::string& path,
}
}
+std::string FileIconSource::GetMimeType(const std::string&) const {
+ // Rely on image decoder inferring the correct type.
+ return std::string();
+}
+
void FileIconSource::OnFileIconDataAvailable(IconManager::Handle handle,
SkBitmap* icon) {
IconManager* im = g_browser_process->icon_manager();
diff --git a/chrome/browser/dom_ui/fileicon_source.h b/chrome/browser/dom_ui/fileicon_source.h
index b8e1d2f..1bcf060 100644
--- a/chrome/browser/dom_ui/fileicon_source.h
+++ b/chrome/browser/dom_ui/fileicon_source.h
@@ -26,10 +26,7 @@ class FileIconSource : public ChromeURLDataManager::DataSource {
bool is_off_the_record,
int request_id);
- virtual std::string GetMimeType(const std::string&) const {
- // Rely on image decoder inferring the correct type.
- return std::string();
- }
+ virtual std::string GetMimeType(const std::string&) const;
// Called when favicon data is available from the history backend.
void OnFileIconDataAvailable(
diff --git a/chrome/browser/dom_ui/flags_ui.cc b/chrome/browser/dom_ui/flags_ui.cc
index 7688579..76d4bdd 100644
--- a/chrome/browser/dom_ui/flags_ui.cc
+++ b/chrome/browser/dom_ui/flags_ui.cc
@@ -16,7 +16,7 @@
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/jstemplate_builder.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
@@ -183,9 +183,9 @@ FlagsUI::FlagsUI(TabContents* contents) : DOMUI(contents) {
// Set up the about:flags source.
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(Singleton<ChromeURLDataManager>::get(),
- &ChromeURLDataManager::AddDataSource,
- make_scoped_refptr(html_source)));
+ NewRunnableMethod(ChromeURLDataManager::GetInstance(),
+ &ChromeURLDataManager::AddDataSource,
+ make_scoped_refptr(html_source)));
}
// static
diff --git a/chrome/browser/dom_ui/foreign_session_handler.cc b/chrome/browser/dom_ui/foreign_session_handler.cc
index 4583234..21fc142 100644
--- a/chrome/browser/dom_ui/foreign_session_handler.cc
+++ b/chrome/browser/dom_ui/foreign_session_handler.cc
@@ -4,14 +4,16 @@
#include "chrome/browser/dom_ui/foreign_session_handler.h"
+#include <string>
+
#include "base/scoped_vector.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/dom_ui/value_helper.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_restore.h"
#include "chrome/browser/sessions/tab_restore_service.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/profile_sync_service.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_service.h"
@@ -105,7 +107,7 @@ void ForeignSessionHandler::OpenForeignSession(
ScopedVector<ForeignSession> session;
associator->AppendForeignSessionWithID(id, &session.get(), &trans);
- DCHECK(session.size() == 1);
+ DCHECK_EQ(1U, session.size());
std::vector<SessionWindow*> windows = (*session.begin())->windows;
SessionRestore::RestoreForeignSessionWindows(dom_ui_->GetProfile(), &windows);
}
diff --git a/chrome/browser/dom_ui/foreign_session_handler.h b/chrome/browser/dom_ui/foreign_session_handler.h
index 6532205..8532d10 100644
--- a/chrome/browser/dom_ui/foreign_session_handler.h
+++ b/chrome/browser/dom_ui/foreign_session_handler.h
@@ -30,8 +30,9 @@ class ForeignSessionHandler : public DOMMessageHandler,
void Init();
// Determines how ForeignSessionHandler will interact with the new tab page.
- void Observe(NotificationType type, const NotificationSource& source,
- const NotificationDetails& details);
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
// Returns a pointer to the current session model associator or NULL.
SessionModelAssociator* GetModelAssociator();
diff --git a/chrome/browser/dom_ui/gpu_internals_ui.cc b/chrome/browser/dom_ui/gpu_internals_ui.cc
new file mode 100644
index 0000000..9b93bfb
--- /dev/null
+++ b/chrome/browser/dom_ui/gpu_internals_ui.cc
@@ -0,0 +1,350 @@
+// 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.
+
+#include "chrome/browser/dom_ui/gpu_internals_ui.h"
+
+#include <algorithm>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/message_loop.h"
+#include "base/path_service.h"
+#include "base/singleton.h"
+#include "base/string_number_conversions.h"
+#include "base/string_piece.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
+#include "chrome/browser/gpu_process_host.h"
+#include "chrome/browser/gpu_process_host_ui_shim.h"
+#include "chrome/browser/io_thread.h"
+#include "chrome/browser/net/chrome_net_log.h"
+#include "chrome/browser/net/connection_tester.h"
+#include "chrome/browser/net/passive_log_collector.h"
+#include "chrome/browser/net/url_fixer_upper.h"
+#include "chrome/browser/platform_util.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_version_info.h"
+#include "chrome/common/jstemplate_builder.h"
+#include "chrome/common/net/url_request_context_getter.h"
+#include "chrome/common/url_constants.h"
+#include "grit/browser_resources.h"
+#include "grit/generated_resources.h"
+#include "net/base/escape.h"
+
+
+namespace {
+
+class GpuHTMLSource : public ChromeURLDataManager::DataSource {
+ public:
+ GpuHTMLSource();
+
+ // Called when the network layer has requested a resource underneath
+ // the path we registered.
+ virtual void StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id);
+ virtual std::string GetMimeType(const std::string&) const;
+
+ private:
+ ~GpuHTMLSource() {}
+ DISALLOW_COPY_AND_ASSIGN(GpuHTMLSource);
+};
+
+// This class receives javascript messages from the renderer.
+// Note that the DOMUI infrastructure runs on the UI thread, therefore all of
+// this class's methods are expected to run on the UI thread.
+class GpuMessageHandler
+ : public DOMMessageHandler,
+ public base::SupportsWeakPtr<GpuMessageHandler> {
+ public:
+ GpuMessageHandler();
+ virtual ~GpuMessageHandler();
+
+ // DOMMessageHandler implementation.
+ virtual DOMMessageHandler* Attach(DOMUI* dom_ui);
+ virtual void RegisterMessages();
+
+ // Mesages
+ void OnCallAsync(const ListValue* list);
+
+ // Submessages dispatched from OnCallAsync
+ Value* OnRequestGpuInfo(const ListValue* list);
+ Value* OnRequestClientInfo(const ListValue* list);
+
+ // Executes the javascript function |function_name| in the renderer, passing
+ // it the argument |value|.
+ void CallJavascriptFunction(const std::wstring& function_name,
+ const Value* value);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GpuMessageHandler);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// GpuHTMLSource
+//
+////////////////////////////////////////////////////////////////////////////////
+
+GpuHTMLSource::GpuHTMLSource()
+ : DataSource(chrome::kChromeUIGpuInternalsHost, MessageLoop::current()) {
+}
+
+void GpuHTMLSource::StartDataRequest(const std::string& path,
+ bool is_off_the_record,
+ int request_id) {
+ DictionaryValue localized_strings;
+ SetFontAndTextDirection(&localized_strings);
+
+ base::StringPiece gpu_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_GPU_INTERNALS_HTML));
+ std::string full_html(gpu_html.data(), gpu_html.size());
+ jstemplate_builder::AppendJsonHtml(&localized_strings, &full_html);
+ jstemplate_builder::AppendI18nTemplateSourceHtml(&full_html);
+ jstemplate_builder::AppendI18nTemplateProcessHtml(&full_html);
+ jstemplate_builder::AppendJsTemplateSourceHtml(&full_html);
+
+
+ scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
+ html_bytes->data.resize(full_html.size());
+ std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
+
+ SendResponse(request_id, html_bytes);
+}
+
+std::string GpuHTMLSource::GetMimeType(const std::string&) const {
+ return "text/html";
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// GpuMessageHandler
+//
+////////////////////////////////////////////////////////////////////////////////
+
+GpuMessageHandler::GpuMessageHandler() {
+}
+
+GpuMessageHandler::~GpuMessageHandler() {}
+
+DOMMessageHandler* GpuMessageHandler::Attach(DOMUI* dom_ui) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DOMMessageHandler* result = DOMMessageHandler::Attach(dom_ui);
+ return result;
+}
+
+/* BrowserBridge.callAsync prepends a requestID to these messages. */
+void GpuMessageHandler::RegisterMessages() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ dom_ui_->RegisterMessageCallback(
+ "callAsync",
+ NewCallback(this, &GpuMessageHandler::OnCallAsync));
+}
+
+void GpuMessageHandler::OnCallAsync(const ListValue* args) {
+ DCHECK_GE(args->GetSize(), static_cast<size_t>(2));
+ // unpack args into requestId, submessage and submessageArgs
+ bool ok;
+ Value* requestId;
+ ok = args->Get(0, &requestId);
+ DCHECK(ok);
+
+ std::string submessage;
+ ok = args->GetString(1, &submessage);
+ DCHECK(ok);
+
+ ListValue* submessageArgs = new ListValue();
+ for (size_t i = 2; i < args->GetSize(); ++i) {
+ Value* arg;
+ ok = args->Get(i, &arg);
+ DCHECK(ok);
+
+ Value* argCopy = arg->DeepCopy();
+ submessageArgs->Append(argCopy);
+ }
+
+ // call the submessage handler
+ Value* ret = NULL;
+ if (submessage == "requestGpuInfo") {
+ ret = OnRequestGpuInfo(submessageArgs);
+ } else if (submessage == "requestClientInfo") {
+ ret = OnRequestClientInfo(submessageArgs);
+ } else { // unrecognized submessage
+ NOTREACHED();
+ delete submessageArgs;
+ return;
+ }
+ delete submessageArgs;
+
+ // call BrowserBridge.onCallAsyncReply with result
+ if (ret) {
+ dom_ui_->CallJavascriptFunction(L"browserBridge.onCallAsyncReply",
+ *requestId,
+ *ret);
+ delete ret;
+ } else {
+ dom_ui_->CallJavascriptFunction(L"browserBridge.onCallAsyncReply",
+ *requestId);
+ }
+}
+
+Value* GpuMessageHandler::OnRequestClientInfo(const ListValue* list) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ DictionaryValue* dict = new DictionaryValue();
+
+ chrome::VersionInfo version_info;
+
+ if (!version_info.is_valid()) {
+ DLOG(ERROR) << "Unable to create chrome::VersionInfo";
+ } else {
+ // We have everything we need to send the right values.
+ dict->SetString("version", version_info.Version());
+ dict->SetString("cl", version_info.LastChange());
+ dict->SetString("version_mod",
+ platform_util::GetVersionStringModifier());
+ dict->SetString("official",
+ l10n_util::GetStringUTF16(
+ version_info.IsOfficialBuild() ?
+ IDS_ABOUT_VERSION_OFFICIAL
+ : IDS_ABOUT_VERSION_UNOFFICIAL));
+
+ dict->SetString("command_line",
+ CommandLine::ForCurrentProcess()->command_line_string());
+ }
+
+ return dict;
+}
+
+DictionaryValue* NewDescriptionValuePair(const std::string& desc,
+ const std::string& value) {
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetString("description", desc);
+ dict->SetString("value", value);
+ return dict;
+}
+
+DictionaryValue* NewDescriptionValuePair(const std::string& desc,
+ Value* value) {
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetString("description", desc);
+ dict->Set("value", value);
+ return dict;
+}
+
+#if defined(OS_WIN)
+// Output DxDiagNode tree as nested array of {description,value} pairs
+ListValue* DxDiagNodeToList(const DxDiagNode& node) {
+ ListValue* list = new ListValue();
+ for (std::map<std::string, std::string>::const_iterator it =
+ node.values.begin();
+ it != node.values.end();
+ ++it) {
+ list->Append(NewDescriptionValuePair(it->first, it->second));
+ }
+
+ for (std::map<std::string, DxDiagNode>::const_iterator it =
+ node.children.begin();
+ it != node.children.end();
+ ++it) {
+ ListValue* sublist = DxDiagNodeToList(it->second);
+ list->Append(NewDescriptionValuePair(it->first, sublist));
+ }
+ return list;
+}
+
+#endif // OS_WIN
+
+std::string VersionNumberToString(uint32 value) {
+ int hi = (value >> 8) & 0xff;
+ int low = value & 0xff;
+ return base::IntToString(hi) + "." + base::IntToString(low);
+}
+
+DictionaryValue* GpuInfoToDict(const GPUInfo& gpu_info) {
+ ListValue* basic_info = new ListValue();
+ basic_info->Append(NewDescriptionValuePair("Initialization time",
+ base::Int64ToString(gpu_info.initialization_time().InMilliseconds())));
+ basic_info->Append(NewDescriptionValuePair("Vendor Id",
+ base::StringPrintf("0x%04x", gpu_info.vendor_id())));
+ basic_info->Append(NewDescriptionValuePair("Device Id",
+ base::StringPrintf("0x%04x", gpu_info.device_id())));
+ basic_info->Append(NewDescriptionValuePair("Driver version",
+ WideToASCII(gpu_info.driver_version()).c_str()));
+ basic_info->Append(NewDescriptionValuePair("Pixel shader version",
+ VersionNumberToString(gpu_info.pixel_shader_version())));
+ basic_info->Append(NewDescriptionValuePair("Vertex shader version",
+ VersionNumberToString(gpu_info.vertex_shader_version())));
+ basic_info->Append(NewDescriptionValuePair("GL version",
+ VersionNumberToString(gpu_info.gl_version())));
+
+ DictionaryValue* info = new DictionaryValue();
+ info->Set("basic_info", basic_info);
+
+ if (gpu_info.progress() == GPUInfo::kPartial) {
+ info->SetString("progress", "partial");
+ } else {
+ info->SetString("progress", "complete");
+ }
+#if defined(OS_WIN)
+ if (gpu_info.progress() == GPUInfo::kComplete) {
+ ListValue* dx_info = DxDiagNodeToList(gpu_info.dx_diagnostics());
+ info->Set("diagnostics", dx_info);
+ }
+#endif
+
+ return info;
+}
+
+Value* GpuMessageHandler::OnRequestGpuInfo(const ListValue* list) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // Get GPU Info.
+ GPUInfo gpu_info = GpuProcessHostUIShim::GetInstance()->gpu_info();
+
+ std::string html;
+ if (gpu_info.progress() != GPUInfo::kComplete) {
+ GpuProcessHostUIShim::GetInstance()->CollectGraphicsInfoAsynchronously();
+ }
+
+ if (gpu_info.progress() != GPUInfo::kUninitialized) {
+ return GpuInfoToDict(gpu_info);
+ } else {
+ return NULL;
+ }
+}
+
+} // namespace
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// GpuInternalsUI
+//
+////////////////////////////////////////////////////////////////////////////////
+
+GpuInternalsUI::GpuInternalsUI(TabContents* contents) : DOMUI(contents) {
+ AddMessageHandler((new GpuMessageHandler())->Attach(this));
+
+ GpuHTMLSource* html_source = new GpuHTMLSource();
+
+ // Set up the chrome://gpu/ source.
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(
+ ChromeURLDataManager::GetInstance(),
+ &ChromeURLDataManager::AddDataSource,
+ make_scoped_refptr(html_source)));
+}
+
diff --git a/chrome/browser/dom_ui/gpu_internals_ui.h b/chrome/browser/dom_ui/gpu_internals_ui.h
new file mode 100644
index 0000000..8b45692
--- /dev/null
+++ b/chrome/browser/dom_ui/gpu_internals_ui.h
@@ -0,0 +1,20 @@
+// 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.
+
+#ifndef CHROME_BROWSER_DOM_UI_GPU_INTERNALS_UI_H_
+#define CHROME_BROWSER_DOM_UI_GPU_INTERNALS_UI_H_
+#pragma once
+
+#include "chrome/browser/dom_ui/dom_ui.h"
+
+class GpuInternalsUI : public DOMUI {
+ public:
+ explicit GpuInternalsUI(TabContents* contents);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GpuInternalsUI);
+};
+
+#endif // CHROME_BROWSER_DOM_UI_GPU_INTERNALS_UI_H_
+
diff --git a/chrome/browser/dom_ui/history2_ui.cc b/chrome/browser/dom_ui/history2_ui.cc
index 5b20af5..faf00cb 100644
--- a/chrome/browser/dom_ui/history2_ui.cc
+++ b/chrome/browser/dom_ui/history2_ui.cc
@@ -4,6 +4,9 @@
#include "chrome/browser/dom_ui/history2_ui.h"
+#include <algorithm>
+#include <set>
+
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/callback.h"
@@ -22,13 +25,13 @@
#include "chrome/browser/dom_ui/dom_ui_favicon_source.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/history/history_types.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/common/jstemplate_builder.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/time_format.h"
#include "chrome/common/url_constants.h"
#include "net/base/escape.h"
@@ -107,6 +110,10 @@ void HistoryUIHTMLSource2::StartDataRequest(const std::string& path,
SendResponse(request_id, html_bytes);
}
+std::string HistoryUIHTMLSource2::GetMimeType(const std::string&) const {
+ return "text/html";
+}
+
////////////////////////////////////////////////////////////////////////////////
//
// HistoryHandler
@@ -126,7 +133,7 @@ DOMMessageHandler* BrowsingHistoryHandler2::Attach(DOMUI* dom_ui) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(new DOMUIFavIconSource(dom_ui->GetProfile()))));
@@ -269,20 +276,19 @@ void BrowsingHistoryHandler2::QueryComplete(
string16 date_str = TimeFormat::RelativeDate(page.visit_time(),
&midnight_today);
if (date_str.empty()) {
- date_str =
- WideToUTF16Hack(base::TimeFormatFriendlyDate(page.visit_time()));
+ date_str = base::TimeFormatFriendlyDate(page.visit_time());
} else {
date_str = l10n_util::GetStringFUTF16(
IDS_HISTORY_DATE_WITH_RELATIVE_TIME,
date_str,
- WideToUTF16Hack(base::TimeFormatFriendlyDate(page.visit_time())));
+ base::TimeFormatFriendlyDate(page.visit_time()));
}
page_value->SetString("dateRelativeDay", date_str);
page_value->SetString("dateTimeOfDay",
- WideToUTF16Hack(base::TimeFormatTimeOfDay(page.visit_time())));
+ base::TimeFormatTimeOfDay(page.visit_time()));
} else {
page_value->SetString("dateShort",
- WideToUTF16Hack(base::TimeFormatShortDate(page.visit_time())));
+ base::TimeFormatShortDate(page.visit_time()));
page_value->SetString("snippet", page.snippet().text());
}
page_value->SetBoolean("starred",
@@ -398,7 +404,7 @@ HistoryUI2::HistoryUI2(TabContents* contents) : DOMUI(contents) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(html_source)));
}
diff --git a/chrome/browser/dom_ui/history2_ui.h b/chrome/browser/dom_ui/history2_ui.h
index b38650e..a9e1d26 100644
--- a/chrome/browser/dom_ui/history2_ui.h
+++ b/chrome/browser/dom_ui/history2_ui.h
@@ -30,9 +30,7 @@ class HistoryUIHTMLSource2 : public ChromeURLDataManager::DataSource {
bool is_off_the_record,
int request_id);
- virtual std::string GetMimeType(const std::string&) const {
- return "text/html";
- }
+ virtual std::string GetMimeType(const std::string&) const;
private:
~HistoryUIHTMLSource2() {}
diff --git a/chrome/browser/dom_ui/history_ui.cc b/chrome/browser/dom_ui/history_ui.cc
index 859a101..fa7c332 100644
--- a/chrome/browser/dom_ui/history_ui.cc
+++ b/chrome/browser/dom_ui/history_ui.cc
@@ -4,6 +4,9 @@
#include "chrome/browser/dom_ui/history_ui.h"
+#include <algorithm>
+#include <set>
+
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/callback.h"
@@ -22,13 +25,13 @@
#include "chrome/browser/dom_ui/dom_ui_favicon_source.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/history/history_types.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/common/jstemplate_builder.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/time_format.h"
#include "chrome/common/url_constants.h"
#include "net/base/escape.h"
@@ -107,6 +110,10 @@ void HistoryUIHTMLSource::StartDataRequest(const std::string& path,
SendResponse(request_id, html_bytes);
}
+std::string HistoryUIHTMLSource::GetMimeType(const std::string&) const {
+ return "text/html";
+}
+
////////////////////////////////////////////////////////////////////////////////
//
// HistoryHandler
@@ -126,7 +133,7 @@ DOMMessageHandler* BrowsingHistoryHandler::Attach(DOMUI* dom_ui) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(new DOMUIFavIconSource(dom_ui->GetProfile()))));
@@ -269,20 +276,19 @@ void BrowsingHistoryHandler::QueryComplete(
string16 date_str = TimeFormat::RelativeDate(page.visit_time(),
&midnight_today);
if (date_str.empty()) {
- date_str =
- WideToUTF16Hack(base::TimeFormatFriendlyDate(page.visit_time()));
+ date_str = base::TimeFormatFriendlyDate(page.visit_time());
} else {
date_str = l10n_util::GetStringFUTF16(
IDS_HISTORY_DATE_WITH_RELATIVE_TIME,
date_str,
- WideToUTF16Hack(base::TimeFormatFriendlyDate(page.visit_time())));
+ base::TimeFormatFriendlyDate(page.visit_time()));
}
page_value->SetString("dateRelativeDay", date_str);
page_value->SetString("dateTimeOfDay",
- WideToUTF16Hack(base::TimeFormatTimeOfDay(page.visit_time())));
+ base::TimeFormatTimeOfDay(page.visit_time()));
} else {
page_value->SetString("dateShort",
- WideToUTF16Hack(base::TimeFormatShortDate(page.visit_time())));
+ base::TimeFormatShortDate(page.visit_time()));
page_value->SetString("snippet", page.snippet().text());
}
page_value->SetBoolean("starred",
@@ -386,7 +392,7 @@ HistoryUI::HistoryUI(TabContents* contents) : DOMUI(contents) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(html_source)));
}
diff --git a/chrome/browser/dom_ui/history_ui.h b/chrome/browser/dom_ui/history_ui.h
index 8d33afe..f31a9d8 100644
--- a/chrome/browser/dom_ui/history_ui.h
+++ b/chrome/browser/dom_ui/history_ui.h
@@ -26,9 +26,7 @@ class HistoryUIHTMLSource : public ChromeURLDataManager::DataSource {
virtual void StartDataRequest(const std::string& path,
bool is_off_the_record,
int request_id);
- virtual std::string GetMimeType(const std::string&) const {
- return "text/html";
- }
+ virtual std::string GetMimeType(const std::string&) const;
private:
~HistoryUIHTMLSource() {}
diff --git a/chrome/browser/dom_ui/html_dialog_tab_contents_delegate.cc b/chrome/browser/dom_ui/html_dialog_tab_contents_delegate.cc
index 1ba3c5c..6f8d825 100644
--- a/chrome/browser/dom_ui/html_dialog_tab_contents_delegate.cc
+++ b/chrome/browser/dom_ui/html_dialog_tab_contents_delegate.cc
@@ -4,12 +4,12 @@
#include "chrome/browser/dom_ui/html_dialog_tab_contents_delegate.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_navigator.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
// Incognito profiles are not long-lived, so we always want to store a
// non-incognito profile.
diff --git a/chrome/browser/dom_ui/html_dialog_ui.cc b/chrome/browser/dom_ui/html_dialog_ui.cc
index ee9ce34..fbea1f6 100644
--- a/chrome/browser/dom_ui/html_dialog_ui.cc
+++ b/chrome/browser/dom_ui/html_dialog_ui.cc
@@ -5,13 +5,16 @@
#include "chrome/browser/dom_ui/html_dialog_ui.h"
#include "base/callback.h"
-#include "base/singleton.h"
+#include "base/lazy_instance.h"
#include "base/values.h"
#include "chrome/browser/dom_ui/dom_ui_util.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/common/bindings_policy.h"
+static base::LazyInstance<PropertyAccessor<HtmlDialogUIDelegate*> >
+ g_html_dialog_ui_property_accessor(base::LINKER_INITIALIZED);
+
HtmlDialogUI::HtmlDialogUI(TabContents* tab_contents) : DOMUI(tab_contents) {
}
@@ -28,7 +31,7 @@ HtmlDialogUI::~HtmlDialogUI() {
// static
PropertyAccessor<HtmlDialogUIDelegate*>& HtmlDialogUI::GetPropertyAccessor() {
- return *Singleton< PropertyAccessor<HtmlDialogUIDelegate*> >::get();
+ return g_html_dialog_ui_property_accessor.Get();
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/dom_ui/keyboard_ui.cc b/chrome/browser/dom_ui/keyboard_ui.cc
index 2b0f1ea..9fddd04 100644
--- a/chrome/browser/dom_ui/keyboard_ui.cc
+++ b/chrome/browser/dom_ui/keyboard_ui.cc
@@ -10,7 +10,6 @@
#include "base/string_piece.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
-#include "chrome/browser/profile.h"
#include "chrome/common/url_constants.h"
#include "grit/browser_resources.h"
@@ -23,7 +22,7 @@ KeyboardUI::KeyboardUI(TabContents* contents)
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(html_source)));
}
diff --git a/chrome/browser/dom_ui/mediaplayer_browsertest.cc b/chrome/browser/dom_ui/mediaplayer_browsertest.cc
index 896bf20..74cbc30 100644
--- a/chrome/browser/dom_ui/mediaplayer_browsertest.cc
+++ b/chrome/browser/dom_ui/mediaplayer_browsertest.cc
@@ -7,7 +7,6 @@
#include "base/utf_string_conversions.h"
#include "chrome/test/automation/dom_element_proxy.h"
#include "chrome/browser/dom_ui/mediaplayer_ui.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
@@ -70,7 +69,7 @@ IN_PROC_BROWSER_TEST_F(MediaPlayerBrowserTest, Popup) {
ui_test_utils::NavigateToURL(browser(),
GURL("chrome://downloads"));
- MediaPlayer* player = MediaPlayer::Get();
+ MediaPlayer* player = MediaPlayer::GetInstance();
// Check that its not currently visible
ASSERT_FALSE(IsPlayerVisible());
@@ -86,7 +85,7 @@ IN_PROC_BROWSER_TEST_F(MediaPlayerBrowserTest, PopupPlaylist) {
GURL("chrome://downloads"));
- MediaPlayer* player = MediaPlayer::Get();
+ MediaPlayer* player = MediaPlayer::GetInstance();
player->EnqueueMediaURL(GetMusicTestURL(), NULL);
diff --git a/chrome/browser/dom_ui/mediaplayer_ui.cc b/chrome/browser/dom_ui/mediaplayer_ui.cc
index 79d656f..85c53f6 100644
--- a/chrome/browser/dom_ui/mediaplayer_ui.cc
+++ b/chrome/browser/dom_ui/mediaplayer_ui.cc
@@ -23,7 +23,7 @@
#include "chrome/browser/download/download_util.h"
#include "chrome/browser/history/history_types.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h"
@@ -212,7 +212,7 @@ DOMMessageHandler* MediaplayerHandler::Attach(DOMUI* dom_ui) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(new DOMUIFavIconSource(dom_ui->GetProfile()))));
@@ -220,7 +220,7 @@ DOMMessageHandler* MediaplayerHandler::Attach(DOMUI* dom_ui) {
}
void MediaplayerHandler::Init(bool is_playlist, TabContents* contents) {
- MediaPlayer* player = MediaPlayer::Get();
+ MediaPlayer* player = MediaPlayer::GetInstance();
if (!is_playlist) {
player->SetNewHandler(this, contents);
} else {
@@ -258,7 +258,7 @@ void MediaplayerHandler::PlaybackMediaFile(const GURL& url) {
current_playlist_.clear();
current_playlist_.push_back(MediaplayerHandler::MediaUrl(url));
FirePlaylistChanged(url.spec(), true, 0);
- MediaPlayer::Get()->NotifyPlaylistChanged();
+ MediaPlayer::GetInstance()->NotifyPlaylistChanged();
}
const MediaplayerHandler::UrlVector& MediaplayerHandler::GetCurrentPlaylist() {
@@ -270,13 +270,13 @@ int MediaplayerHandler::GetCurrentPlaylistOffset() {
}
void MediaplayerHandler::HandleToggleFullscreen(const ListValue* args) {
- MediaPlayer::Get()->ToggleFullscreen();
+ MediaPlayer::GetInstance()->ToggleFullscreen();
}
void MediaplayerHandler::HandleSetCurrentPlaylistOffset(const ListValue* args) {
int id;
CHECK(ExtractIntegerValue(args, &id));
- MediaPlayer::Get()->SetPlaylistOffset(id);
+ MediaPlayer::GetInstance()->SetPlaylistOffset(id);
}
void MediaplayerHandler::FirePlaylistChanged(const std::string& path,
@@ -306,12 +306,12 @@ void MediaplayerHandler::SetCurrentPlaylist(
void MediaplayerHandler::EnqueueMediaFile(const GURL& url) {
current_playlist_.push_back(MediaplayerHandler::MediaUrl(url));
FirePlaylistChanged(url.spec(), false, current_offset_);
- MediaPlayer::Get()->NotifyPlaylistChanged();
+ MediaPlayer::GetInstance()->NotifyPlaylistChanged();
}
void MediaplayerHandler::HandleCurrentOffsetChanged(const ListValue* args) {
CHECK(ExtractIntegerValue(args, &current_offset_));
- MediaPlayer::Get()->NotifyPlaylistChanged();
+ MediaPlayer::GetInstance()->NotifyPlaylistChanged();
}
void MediaplayerHandler::HandlePlaybackError(const ListValue* args) {
@@ -335,11 +335,11 @@ void MediaplayerHandler::HandleGetCurrentPlaylist(const ListValue* args) {
}
void MediaplayerHandler::HandleTogglePlaylist(const ListValue* args) {
- MediaPlayer::Get()->TogglePlaylistWindowVisible();
+ MediaPlayer::GetInstance()->TogglePlaylistWindowVisible();
}
void MediaplayerHandler::HandleShowPlaylist(const ListValue* args) {
- MediaPlayer::Get()->ShowPlaylistWindow();
+ MediaPlayer::GetInstance()->ShowPlaylistWindow();
}
////////////////////////////////////////////////////////////////////////////////
@@ -355,6 +355,11 @@ DISABLE_RUNNABLE_METHOD_REFCOUNT(MediaPlayer);
MediaPlayer::~MediaPlayer() {
}
+// static
+MediaPlayer* MediaPlayer::GetInstance() {
+ return Singleton<MediaPlayer>::get();
+}
+
void MediaPlayer::EnqueueMediaURL(const GURL& url, Browser* creator) {
if (!Enabled()) {
return;
@@ -538,7 +543,7 @@ void MediaPlayer::PopupMediaPlayer(Browser* creator) {
mediaplayer_browser_->window()->Show();
}
-URLRequestJob* MediaPlayer::MaybeIntercept(URLRequest* request) {
+net::URLRequestJob* MediaPlayer::MaybeIntercept(net::URLRequest* request) {
// Don't attempt to intercept here as we want to wait until the mime
// type is fully determined.
return NULL;
@@ -552,8 +557,8 @@ static const char* const supported_mime_type_list[] = {
"audio/mp3"
};
-URLRequestJob* MediaPlayer::MaybeInterceptResponse(
- URLRequest* request) {
+net::URLRequestJob* MediaPlayer::MaybeInterceptResponse(
+ net::URLRequest* request) {
// Do not intercept this request if it is a download.
if (request->load_flags() & net::LOAD_IS_DOWNLOAD) {
return NULL;
@@ -610,7 +615,7 @@ MediaplayerUI::MediaplayerUI(TabContents* contents) : DOMUI(contents) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(html_source)));
}
diff --git a/chrome/browser/dom_ui/mediaplayer_ui.h b/chrome/browser/dom_ui/mediaplayer_ui.h
index 5c5b4bc..921190a 100644
--- a/chrome/browser/dom_ui/mediaplayer_ui.h
+++ b/chrome/browser/dom_ui/mediaplayer_ui.h
@@ -9,7 +9,6 @@
#include <set>
#include <vector>
-#include "base/singleton.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
#include "chrome/browser/dom_ui/dom_ui.h"
#include "chrome/common/notification_observer.h"
@@ -19,12 +18,13 @@
#include "net/base/directory_lister.h"
#include "net/url_request/url_request.h"
+template <typename T> struct DefaultSingletonTraits;
class GURL;
class MediaplayerHandler;
class Browser;
class MediaPlayer : public NotificationObserver,
- public URLRequest::Interceptor {
+ public net::URLRequest::Interceptor {
public:
~MediaPlayer();
@@ -74,13 +74,13 @@ class MediaPlayer : public NotificationObserver,
// Always returns NULL because we don't want to attempt a redirect
// before seeing the detected mime type of the request.
- // Implementation of URLRequest::Interceptor.
+ // Implementation of net::URLRequest::Interceptor.
virtual net::URLRequestJob* MaybeIntercept(net::URLRequest* request);
// Determines if the requested document can be viewed by the
- // MediaPlayer. If it can, returns a URLRequestJob that
+ // MediaPlayer. If it can, returns a net::URLRequestJob that
// redirects the browser to the view URL.
- // Implementation of URLRequest::Interceptor.
+ // Implementation of net::URLRequest::Interceptor.
virtual net::URLRequestJob* MaybeInterceptResponse(net::URLRequest* request);
// Used to detect when the mediaplayer is closed.
@@ -89,11 +89,11 @@ class MediaPlayer : public NotificationObserver,
const NotificationDetails& details);
// Getter for the singleton.
- static MediaPlayer* Get() {
- return Singleton<MediaPlayer>::get();
- }
+ static MediaPlayer* GetInstance();
private:
+ friend struct DefaultSingletonTraits<MediaPlayer>;
+
MediaPlayer();
// Popup the mediaplayer, this shows the browser, and sets up its
@@ -147,7 +147,6 @@ class MediaPlayer : public NotificationObserver,
// List of mimetypes that the mediaplayer should listen to. Used for
// interceptions of url GETs.
std::set<std::string> supported_mime_types_;
- friend struct DefaultSingletonTraits<MediaPlayer>;
DISALLOW_COPY_AND_ASSIGN(MediaPlayer);
};
diff --git a/chrome/browser/dom_ui/most_visited_handler.cc b/chrome/browser/dom_ui/most_visited_handler.cc
index 6ec3113..798a600 100644
--- a/chrome/browser/dom_ui/most_visited_handler.cc
+++ b/chrome/browser/dom_ui/most_visited_handler.cc
@@ -27,7 +27,7 @@
#include "chrome/browser/history/top_sites.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/notification_source.h"
@@ -75,7 +75,7 @@ DOMMessageHandler* MostVisitedHandler::Attach(DOMUI* dom_ui) {
new DOMUIThumbnailSource(dom_ui->GetProfile());
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(Singleton<ChromeURLDataManager>::get(),
+ NewRunnableMethod(ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(thumbnail_src)));
@@ -83,7 +83,7 @@ DOMMessageHandler* MostVisitedHandler::Attach(DOMUI* dom_ui) {
new DOMUIFavIconSource(dom_ui->GetProfile());
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(Singleton<ChromeURLDataManager>::get(),
+ NewRunnableMethod(ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(favicon_src)));
diff --git a/chrome/browser/dom_ui/net_internals_ui.cc b/chrome/browser/dom_ui/net_internals_ui.cc
index 90d2a09..0cea72a 100644
--- a/chrome/browser/dom_ui/net_internals_ui.cc
+++ b/chrome/browser/dom_ui/net_internals_ui.cc
@@ -29,9 +29,10 @@
#include "chrome/browser/net/passive_log_collector.h"
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/platform_util.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_version_info.h"
+#include "chrome/common/jstemplate_builder.h"
#include "chrome/common/net/url_request_context_getter.h"
#include "chrome/common/url_constants.h"
#include "grit/generated_resources.h"
@@ -151,14 +152,16 @@ class NetInternalsMessageHandler
DISALLOW_COPY_AND_ASSIGN(NetInternalsMessageHandler);
};
-// This class is the "real" message handler. With the exception of being
-// allocated and destroyed on the UI thread, its methods are expected to be
-// called from the IO thread.
+// This class is the "real" message handler. It is allocated and destroyed on
+// the UI thread. With the exception of OnAddEntry, OnDOMUIDeleted, and
+// CallJavascriptFunction, its methods are all expected to be called from the IO
+// thread. OnAddEntry and CallJavascriptFunction can be called from any thread,
+// and OnDOMUIDeleted can only be called from the UI thread.
class NetInternalsMessageHandler::IOThreadImpl
: public base::RefCountedThreadSafe<
NetInternalsMessageHandler::IOThreadImpl,
BrowserThread::DeleteOnUIThread>,
- public ChromeNetLog::Observer,
+ public ChromeNetLog::ThreadSafeObserver,
public ConnectionTester::Delegate {
public:
// Type for methods that can be used as MessageHandler callbacks.
@@ -186,12 +189,18 @@ class NetInternalsMessageHandler::IOThreadImpl
// IO thread.
void Detach();
+ // Sends all passive log entries in |passive_entries| to the Javascript
+ // handler, called on the IO thread.
+ void SendPassiveLogEntries(const ChromeNetLog::EntryList& passive_entries);
+
+ // Called when the DOMUI is deleted. Prevents calling Javascript functions
+ // afterwards. Called on UI thread.
+ void OnDOMUIDeleted();
+
//--------------------------------
// Javascript message handlers:
//--------------------------------
- // This message is called after the webpage's onloaded handler has fired.
- // it indicates that the renderer is ready to start receiving captured data.
void OnRendererReady(const ListValue* list);
void OnGetProxySettings(const ListValue* list);
@@ -201,7 +210,6 @@ class NetInternalsMessageHandler::IOThreadImpl
void OnGetHostResolverInfo(const ListValue* list);
void OnClearHostResolverCache(const ListValue* list);
void OnEnableIPv6(const ListValue* list);
- void OnGetPassiveLogEntries(const ListValue* list);
void OnStartConnectionTests(const ListValue* list);
void OnGetHttpCacheInfo(const ListValue* list);
void OnGetSocketPoolInfo(const ListValue* list);
@@ -212,7 +220,7 @@ class NetInternalsMessageHandler::IOThreadImpl
void OnSetLogLevel(const ListValue* list);
- // ChromeNetLog::Observer implementation:
+ // ChromeNetLog::ThreadSafeObserver implementation:
virtual void OnAddEntry(net::NetLog::EventType type,
const base::TimeTicks& time,
const net::NetLog::Source& source,
@@ -235,7 +243,8 @@ class NetInternalsMessageHandler::IOThreadImpl
void DispatchToMessageHandler(ListValue* arg, MessageHandler method);
// Helper that executes |function_name| in the attached renderer.
- // The function takes ownership of |arg|.
+ // The function takes ownership of |arg|. Note that this can be called from
+ // any thread.
void CallJavascriptFunction(const std::wstring& function_name,
Value* arg);
@@ -251,6 +260,14 @@ class NetInternalsMessageHandler::IOThreadImpl
// Helper that runs the suite of connection tests.
scoped_ptr<ConnectionTester> connection_tester_;
+ // True if the DOM UI has been deleted. This is used to prevent calling
+ // Javascript functions after the DOM UI is destroyed. On refresh, the
+ // messages can end up being sent to the refreshed page, causing duplicate
+ // or partial entries.
+ //
+ // This is only read and written to on the UI thread.
+ bool was_domui_deleted_;
+
// True if we have attached an observer to the NetLog already.
bool is_observing_log_;
friend class base::RefCountedThreadSafe<IOThreadImpl>;
@@ -303,6 +320,9 @@ NetInternalsHTMLSource::NetInternalsHTMLSource()
void NetInternalsHTMLSource::StartDataRequest(const std::string& path,
bool is_off_the_record,
int request_id) {
+ DictionaryValue localized_strings;
+ SetFontAndTextDirection(&localized_strings);
+
// The provided "path" may contain a fragment, or query section. We only
// care about the path itself, and will disregard anything else.
std::string filename =
@@ -313,13 +333,20 @@ void NetInternalsHTMLSource::StartDataRequest(const std::string& path,
// Note that users can type anything into the address bar, though, so we must
// handle arbitrary input.
if (filename.empty() || filename == "index.html") {
- scoped_refptr<RefCountedStaticMemory> bytes(
- ResourceBundle::GetSharedInstance().LoadDataResourceBytes(
+ base::StringPiece html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
IDR_NET_INTERNALS_INDEX_HTML));
- if (bytes && bytes->front()) {
- SendResponse(request_id, bytes);
- return;
- }
+ std::string full_html(html.data(), html.size());
+ jstemplate_builder::AppendJsonHtml(&localized_strings, &full_html);
+ jstemplate_builder::AppendI18nTemplateSourceHtml(&full_html);
+ jstemplate_builder::AppendI18nTemplateProcessHtml(&full_html);
+ jstemplate_builder::AppendJsTemplateSourceHtml(&full_html);
+
+ scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
+ html_bytes->data.resize(full_html.size());
+ std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
+ SendResponse(request_id, html_bytes);
+ return;
}
const std::string data_string("<p style='color:red'>Failed to read resource" +
@@ -344,6 +371,7 @@ NetInternalsMessageHandler::NetInternalsMessageHandler() {}
NetInternalsMessageHandler::~NetInternalsMessageHandler() {
if (proxy_) {
+ proxy_.get()->OnDOMUIDeleted();
// Notify the handler on the IO thread that the renderer is gone.
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
NewRunnableMethod(proxy_.get(), &IOThreadImpl::Detach));
@@ -386,9 +414,6 @@ void NetInternalsMessageHandler::RegisterMessages() {
"enableIPv6",
proxy_->CreateCallback(&IOThreadImpl::OnEnableIPv6));
dom_ui_->RegisterMessageCallback(
- "getPassiveLogEntries",
- proxy_->CreateCallback(&IOThreadImpl::OnGetPassiveLogEntries));
- dom_ui_->RegisterMessageCallback(
"startConnectionTests",
proxy_->CreateCallback(&IOThreadImpl::OnStartConnectionTests));
dom_ui_->RegisterMessageCallback(
@@ -432,10 +457,11 @@ NetInternalsMessageHandler::IOThreadImpl::IOThreadImpl(
const base::WeakPtr<NetInternalsMessageHandler>& handler,
IOThread* io_thread,
URLRequestContextGetter* context_getter)
- : Observer(net::NetLog::LOG_ALL_BUT_BYTES),
+ : ThreadSafeObserver(net::NetLog::LOG_ALL_BUT_BYTES),
handler_(handler),
io_thread_(io_thread),
context_getter_(context_getter),
+ was_domui_deleted_(false),
is_observing_log_(false) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}
@@ -455,21 +481,39 @@ void NetInternalsMessageHandler::IOThreadImpl::Detach() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
// Unregister with network stack to observe events.
if (is_observing_log_)
- io_thread_->globals()->net_log->RemoveObserver(this);
+ io_thread_->net_log()->RemoveObserver(this);
// Cancel any in-progress connection tests.
connection_tester_.reset();
}
+void NetInternalsMessageHandler::IOThreadImpl::SendPassiveLogEntries(
+ const ChromeNetLog::EntryList& passive_entries) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ ListValue* dict_list = new ListValue();
+ for (size_t i = 0; i < passive_entries.size(); ++i) {
+ const ChromeNetLog::Entry& e = passive_entries[i];
+ dict_list->Append(net::NetLog::EntryToDictionaryValue(e.type,
+ e.time,
+ e.source,
+ e.phase,
+ e.params,
+ false));
+ }
+
+ CallJavascriptFunction(L"g_browser.receivedPassiveLogEntries", dict_list);
+}
+
+void NetInternalsMessageHandler::IOThreadImpl::OnDOMUIDeleted() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ was_domui_deleted_ = true;
+}
+
void NetInternalsMessageHandler::IOThreadImpl::OnRendererReady(
const ListValue* list) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DCHECK(!is_observing_log_) << "notifyReady called twice";
- // Register with network stack to observe events.
- is_observing_log_ = true;
- io_thread_->globals()->net_log->AddObserver(this);
-
// Tell the javascript about the relationship between event type enums and
// their symbolic name.
{
@@ -617,7 +661,12 @@ void NetInternalsMessageHandler::IOThreadImpl::OnRendererReady(
base::Int64ToString(tick_to_unix_time_ms)));
}
- OnGetPassiveLogEntries(NULL);
+ // Register with network stack to observe events.
+ is_observing_log_ = true;
+ ChromeNetLog::EntryList entries;
+ io_thread_->net_log()->AddObserverAndGetAllPassivelyCapturedEvents(this,
+ &entries);
+ SendPassiveLogEntries(entries);
}
void NetInternalsMessageHandler::IOThreadImpl::OnGetProxySettings(
@@ -774,27 +823,6 @@ void NetInternalsMessageHandler::IOThreadImpl::OnEnableIPv6(
OnGetHostResolverInfo(NULL);
}
-void NetInternalsMessageHandler::IOThreadImpl::OnGetPassiveLogEntries(
- const ListValue* list) {
- ChromeNetLog* net_log = io_thread_->globals()->net_log.get();
-
- PassiveLogCollector::EntryList passive_entries;
- net_log->passive_collector()->GetAllCapturedEvents(&passive_entries);
-
- ListValue* dict_list = new ListValue();
- for (size_t i = 0; i < passive_entries.size(); ++i) {
- const PassiveLogCollector::Entry& e = passive_entries[i];
- dict_list->Append(net::NetLog::EntryToDictionaryValue(e.type,
- e.time,
- e.source,
- e.phase,
- e.params,
- false));
- }
-
- CallJavascriptFunction(L"g_browser.receivedPassiveLogEntries", dict_list);
-}
-
void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTests(
const ListValue* list) {
// |value| should be: [<URL to test>].
@@ -805,7 +833,8 @@ void NetInternalsMessageHandler::IOThreadImpl::OnStartConnectionTests(
// For example, turn "www.google.com" into "http://www.google.com".
GURL url(URLFixerUpper::FixupURL(UTF16ToUTF8(url_str), std::string()));
- connection_tester_.reset(new ConnectionTester(this, io_thread_));
+ connection_tester_.reset(new ConnectionTester(
+ this, io_thread_->globals()->proxy_script_fetcher_context.get()));
connection_tester_->RunAllTests(url);
}
@@ -911,17 +940,17 @@ void NetInternalsMessageHandler::IOThreadImpl::OnSetLogLevel(
DCHECK_GE(log_level, net::NetLog::LOG_ALL);
DCHECK_LE(log_level, net::NetLog::LOG_BASIC);
- set_log_level(static_cast<net::NetLog::LogLevel>(log_level));
+ SetLogLevel(static_cast<net::NetLog::LogLevel>(log_level));
}
+// Note that unlike other methods of IOThreadImpl, this function
+// can be called from ANY THREAD.
void NetInternalsMessageHandler::IOThreadImpl::OnAddEntry(
net::NetLog::EventType type,
const base::TimeTicks& time,
const net::NetLog::Source& source,
net::NetLog::EventPhase phase,
net::NetLog::EventParameters* params) {
- DCHECK(is_observing_log_);
-
CallJavascriptFunction(
L"g_browser.receivedLogEntry",
net::NetLog::EntryToDictionaryValue(type, time, source, phase, params,
@@ -967,11 +996,12 @@ void NetInternalsMessageHandler::IOThreadImpl::DispatchToMessageHandler(
delete arg;
}
+// Note that this can be called from ANY THREAD.
void NetInternalsMessageHandler::IOThreadImpl::CallJavascriptFunction(
const std::wstring& function_name,
Value* arg) {
if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
- if (handler_) {
+ if (handler_ && !was_domui_deleted_) {
// We check |handler_| in case it was deleted on the UI thread earlier
// while we were running on the IO thread.
handler_->CallJavascriptFunction(function_name, arg);
@@ -980,10 +1010,6 @@ void NetInternalsMessageHandler::IOThreadImpl::CallJavascriptFunction(
return;
}
- // Otherwise if we were called from the IO thread, bridge the request over to
- // the UI thread.
-
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (!BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
NewRunnableMethod(
@@ -1013,7 +1039,7 @@ NetInternalsUI::NetInternalsUI(TabContents* contents) : DOMUI(contents) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(html_source)));
}
diff --git a/chrome/browser/dom_ui/new_tab_page_sync_handler.cc b/chrome/browser/dom_ui/new_tab_page_sync_handler.cc
index d79ee91..c075793 100644
--- a/chrome/browser/dom_ui/new_tab_page_sync_handler.cc
+++ b/chrome/browser/dom_ui/new_tab_page_sync_handler.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/dom_ui/new_tab_page_sync_handler.h"
+#include <vector>
+
#include "app/l10n_util.h"
#include "base/callback.h"
#include "base/string_split.h"
@@ -12,9 +14,8 @@
#include "base/values.h"
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/pref_names.h"
#include "grit/browser_resources.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/dom_ui/new_tab_ui.cc b/chrome/browser/dom_ui/new_tab_ui.cc
index ffad4ee..c75bdf0 100644
--- a/chrome/browser/dom_ui/new_tab_ui.cc
+++ b/chrome/browser/dom_ui/new_tab_ui.cc
@@ -31,7 +31,7 @@
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/sessions/session_types.h"
#include "chrome/browser/sessions/tab_restore_service.h"
@@ -376,8 +376,8 @@ NewTabUI::NewTabUI(TabContents* contents)
AddMessageHandler((new MetricsHandler())->Attach(this));
if (GetProfile()->IsSyncAccessible())
AddMessageHandler((new NewTabPageSyncHandler())->Attach(this));
- ExtensionsService* service = GetProfile()->GetExtensionsService();
- // We might not have an ExtensionsService (on ChromeOS when not logged in
+ ExtensionService* service = GetProfile()->GetExtensionService();
+ // We might not have an ExtensionService (on ChromeOS when not logged in
// for example).
if (service)
AddMessageHandler((new AppLauncherHandler(service))->Attach(this));
@@ -395,7 +395,7 @@ NewTabUI::NewTabUI(TabContents* contents)
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(html_source)));
@@ -442,7 +442,7 @@ void NewTabUI::InitializeCSSCaches() {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(theme)));
}
@@ -605,7 +605,7 @@ void NewTabUI::NewTabHTMLSource::StartDataRequest(const std::string& path,
int request_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (AppLauncherHandler::HandlePing(profile_, path)) {
+ if (AppLauncherHandler::HandlePing(path)) {
return;
} else if (!path.empty() && path[0] != '#') {
// A path under new-tab was requested; it's likely a bad relative
diff --git a/chrome/browser/dom_ui/new_tab_ui.h b/chrome/browser/dom_ui/new_tab_ui.h
index abcd47a..40add03 100644
--- a/chrome/browser/dom_ui/new_tab_ui.h
+++ b/chrome/browser/dom_ui/new_tab_ui.h
@@ -89,9 +89,9 @@ class NewTabUI : public DOMUI,
private:
FRIEND_TEST_ALL_PREFIXES(NewTabUITest, UpdateUserPrefsVersion);
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
// Reset the CSS caches.
void InitializeCSSCaches();
diff --git a/chrome/browser/dom_ui/new_tab_ui_uitest.cc b/chrome/browser/dom_ui/new_tab_ui_uitest.cc
index f50e179..51d2b05 100644
--- a/chrome/browser/dom_ui/new_tab_ui_uitest.cc
+++ b/chrome/browser/dom_ui/new_tab_ui_uitest.cc
@@ -5,7 +5,6 @@
#include "chrome/test/ui/ui_test.h"
#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/dom_ui/new_tab_ui.h"
#include "chrome/browser/prefs/pref_value_store.h"
#include "chrome/browser/sync/signin_manager.h"
diff --git a/chrome/browser/dom_ui/ntp_login_handler.cc b/chrome/browser/dom_ui/ntp_login_handler.cc
index b250dd9..67939d0 100644
--- a/chrome/browser/dom_ui/ntp_login_handler.cc
+++ b/chrome/browser/dom_ui/ntp_login_handler.cc
@@ -10,7 +10,7 @@
#include "chrome/browser/dom_ui/dom_ui_util.h"
#include "chrome/browser/prefs/pref_notifier.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/sync_setup_flow.h"
#include "chrome/common/pref_names.h"
diff --git a/chrome/browser/dom_ui/ntp_resource_cache.cc b/chrome/browser/dom_ui/ntp_resource_cache.cc
index b478dcb..6c9edac 100644
--- a/chrome/browser/dom_ui/ntp_resource_cache.cc
+++ b/chrome/browser/dom_ui/ntp_resource_cache.cc
@@ -24,7 +24,7 @@
#include "chrome/browser/dom_ui/shown_sections_handler.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/browser/web_resource/web_resource_service.h"
#include "chrome/common/chrome_switches.h"
@@ -45,7 +45,7 @@
#if defined(OS_WIN) || defined(TOOLKIT_VIEWS)
#include "chrome/browser/views/bookmark_bar_view.h"
#elif defined(OS_MACOSX)
-#include "chrome/browser/cocoa/bookmarks/bookmark_bar_constants.h"
+#include "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h"
#elif defined(OS_POSIX)
#include "chrome/browser/gtk/bookmark_bar_gtk.h"
#endif
diff --git a/chrome/browser/dom_ui/options/about_page_handler.cc b/chrome/browser/dom_ui/options/about_page_handler.cc
index 02579bc..71f994f 100644
--- a/chrome/browser/dom_ui/options/about_page_handler.cc
+++ b/chrome/browser/dom_ui/options/about_page_handler.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/dom_ui/options/about_page_handler.h"
+#include <vector>
+
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/basictypes.h"
@@ -15,10 +17,8 @@
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/platform_util.h"
#include "chrome/common/chrome_version_info.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
#include "googleurl/src/gurl.h"
#include "grit/browser_resources.h"
@@ -86,7 +86,7 @@ const LocalizeEntry localize_table[] = {
{ "channel_warning_text", IDS_ABOUT_PAGE_CHANNEL_WARNING_TEXT },
{ "user_agent", IDS_ABOUT_VERSION_USER_AGENT },
{ "command_line", IDS_ABOUT_VERSION_COMMAND_LINE },
- { "aboutPage", IDS_ABOUT_PAGE_TITLE }
+ { "aboutPage", IDS_ABOUT }
};
void LocalizedStrings(DictionaryValue* localized_strings) {
diff --git a/chrome/browser/dom_ui/options/add_startup_page_handler.cc b/chrome/browser/dom_ui/options/add_startup_page_handler.cc
index 36d3cf7..e76da33 100644
--- a/chrome/browser/dom_ui/options/add_startup_page_handler.cc
+++ b/chrome/browser/dom_ui/options/add_startup_page_handler.cc
@@ -10,7 +10,7 @@
#include "base/values.h"
#include "chrome/browser/possible_url_model.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/dom_ui/options/advanced_options_handler.cc b/chrome/browser/dom_ui/options/advanced_options_handler.cc
index 9bbff48..9531d84 100644
--- a/chrome/browser/dom_ui/options/advanced_options_handler.cc
+++ b/chrome/browser/dom_ui/options/advanced_options_handler.cc
@@ -4,29 +4,31 @@
#include "chrome/browser/dom_ui/options/advanced_options_handler.h"
+#include <string>
+
#include "app/l10n_util.h"
#include "base/basictypes.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
-#include "chrome/browser/browser_process.h"
+#include "chrome/browser/dom_ui/options/dom_options_util.h"
#include "chrome/browser/dom_ui/options/options_managed_banner_handler.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/options_util.h"
-#include "chrome/browser/options_window.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h"
#include "chrome/browser/printing/cloud_print/cloud_print_setup_flow.h"
#include "chrome/browser/printing/cloud_print/cloud_print_url.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
+#include "chrome/browser/ui/options/options_util.h"
+#include "chrome/browser/ui/options/options_window.h"
#include "chrome/common/chrome_switches.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_details.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
@@ -35,6 +37,7 @@
#include "grit/locale_settings.h"
#if !defined(OS_CHROMEOS)
+#include "chrome/browser/browser_process.h"
#include "chrome/browser/dom_ui/options/advanced_options_utils.h"
#endif
@@ -65,8 +68,8 @@ void AdvancedOptionsHandler::GetLocalizedValues(
GURL(chrome::kPrivacyLearnMoreURL)).spec());
localized_strings->SetString("downloadLocationGroupName",
l10n_util::GetStringUTF16(IDS_OPTIONS_DOWNLOADLOCATION_GROUP_NAME));
- localized_strings->SetString("downloadLocationBrowseButton",
- l10n_util::GetStringUTF16(IDS_OPTIONS_DOWNLOADLOCATION_BROWSE_BUTTON));
+ localized_strings->SetString("downloadLocationChangeButton",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_DOWNLOADLOCATION_CHANGE_BUTTON));
localized_strings->SetString("downloadLocationBrowseTitle",
l10n_util::GetStringUTF16(IDS_OPTIONS_DOWNLOADLOCATION_BROWSE_TITLE));
localized_strings->SetString("downloadLocationBrowseWindowTitle",
@@ -76,18 +79,17 @@ void AdvancedOptionsHandler::GetLocalizedValues(
l10n_util::GetStringUTF16(
IDS_OPTIONS_DOWNLOADLOCATION_ASKFORSAVELOCATION));
localized_strings->SetString("autoOpenFileTypesInfo",
- l10n_util::GetStringUTF16(IDS_OPTIONS_AUTOOPENFILETYPES_INFO));
+ l10n_util::GetStringUTF16(IDS_OPTIONS_OPEN_FILE_TYPES_AUTOMATICALLY));
localized_strings->SetString("autoOpenFileTypesResetToDefault",
l10n_util::GetStringUTF16(IDS_OPTIONS_AUTOOPENFILETYPES_RESETTODEFAULT));
localized_strings->SetString("gearSettingsGroupName",
- l10n_util::GetStringUTF16(IDS_OPTIONS_GEARSSETTINGS_GROUP_NAME));
+ dom_options_util::StripColon(
+ l10n_util::GetStringUTF16(IDS_OPTIONS_GEARSSETTINGS_GROUP_NAME)));
localized_strings->SetString("gearSettingsConfigureGearsButton",
l10n_util::GetStringUTF16(
IDS_OPTIONS_GEARSSETTINGS_CONFIGUREGEARS_BUTTON));
localized_strings->SetString("translateEnableTranslate",
l10n_util::GetStringUTF16(IDS_OPTIONS_TRANSLATE_ENABLE_TRANSLATE));
- localized_strings->SetString("certificatesLabel",
- l10n_util::GetStringUTF16(IDS_OPTIONS_CERTIFICATES_LABEL));
localized_strings->SetString("certificatesManageButton",
l10n_util::GetStringUTF16(IDS_OPTIONS_CERTIFICATES_MANAGE_BUTTON));
localized_strings->SetString("proxiesLabel",
@@ -98,8 +100,6 @@ void AdvancedOptionsHandler::GetLocalizedValues(
l10n_util::GetStringUTF16(IDS_OPTIONS_SAFEBROWSING_ENABLEPROTECTION));
localized_strings->SetString("sslGroupDescription",
l10n_util::GetStringUTF16(IDS_OPTIONS_SSL_GROUP_DESCRIPTION));
- localized_strings->SetString("sslUseSSL2",
- l10n_util::GetStringUTF16(IDS_OPTIONS_SSL_USESSL2));
localized_strings->SetString("sslCheckRevocation",
l10n_util::GetStringUTF16(IDS_OPTIONS_SSL_CHECKREVOCATION));
localized_strings->SetString("sslUseSSL3",
@@ -122,19 +122,43 @@ void AdvancedOptionsHandler::GetLocalizedValues(
l10n_util::GetStringUTF16(IDS_OPTIONS_FONTSETTINGS_INFO));
localized_strings->SetString("defaultZoomLevelLabel",
l10n_util::GetStringUTF16(IDS_OPTIONS_DEFAULT_ZOOM_LEVEL_LABEL));
+ localized_strings->SetString("defaultFontSizeLabel",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_DEFAULT_FONT_SIZE_LABEL));
+ localized_strings->SetString("fontSizeLabelVerySmall",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_FONT_SIZE_LABEL_VERY_SMALL));
+ localized_strings->SetString("fontSizeLabelSmall",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_FONT_SIZE_LABEL_SMALL));
+ localized_strings->SetString("fontSizeLabelMedium",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_FONT_SIZE_LABEL_MEDIUM));
+ localized_strings->SetString("fontSizeLabelLarge",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_FONT_SIZE_LABEL_LARGE));
+ localized_strings->SetString("fontSizeLabelVeryLarge",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_FONT_SIZE_LABEL_VERY_LARGE));
+ localized_strings->SetString("fontSizeLabelCustom",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_FONT_SIZE_LABEL_CUSTOM));
localized_strings->SetString("fontSettingsCustomizeFontsButton",
l10n_util::GetStringUTF16(
IDS_OPTIONS_FONTSETTINGS_CUSTOMIZE_FONTS_BUTTON));
localized_strings->SetString("advancedSectionTitlePrivacy",
- l10n_util::GetStringUTF16(IDS_OPTIONS_ADVANCED_SECTION_TITLE_PRIVACY));
+ dom_options_util::StripColon(
+ l10n_util::GetStringUTF16(
+ IDS_OPTIONS_ADVANCED_SECTION_TITLE_PRIVACY)));
localized_strings->SetString("advancedSectionTitleContent",
- l10n_util::GetStringUTF16(IDS_OPTIONS_ADVANCED_SECTION_TITLE_CONTENT));
+ dom_options_util::StripColon(
+ l10n_util::GetStringUTF16(
+ IDS_OPTIONS_ADVANCED_SECTION_TITLE_CONTENT)));
localized_strings->SetString("advancedSectionTitleSecurity",
- l10n_util::GetStringUTF16(IDS_OPTIONS_ADVANCED_SECTION_TITLE_SECURITY));
+ dom_options_util::StripColon(
+ l10n_util::GetStringUTF16(
+ IDS_OPTIONS_ADVANCED_SECTION_TITLE_SECURITY)));
localized_strings->SetString("advancedSectionTitleNetwork",
- l10n_util::GetStringUTF16(IDS_OPTIONS_ADVANCED_SECTION_TITLE_NETWORK));
+ dom_options_util::StripColon(
+ l10n_util::GetStringUTF16(
+ IDS_OPTIONS_ADVANCED_SECTION_TITLE_NETWORK)));
localized_strings->SetString("advancedSectionTitleTranslate",
- l10n_util::GetStringUTF16(IDS_OPTIONS_ADVANCED_SECTION_TITLE_TRANSLATE));
+ dom_options_util::StripColon(
+ l10n_util::GetStringUTF16(
+ IDS_OPTIONS_ADVANCED_SECTION_TITLE_TRANSLATE)));
localized_strings->SetString("translateEnableTranslate",
l10n_util::GetStringUTF16(IDS_OPTIONS_TRANSLATE_ENABLE_TRANSLATE));
#if !defined(OS_CHROMEOS)
@@ -159,25 +183,18 @@ void AdvancedOptionsHandler::GetLocalizedValues(
#endif
localized_strings->SetString("enableLogging",
l10n_util::GetStringUTF16(IDS_OPTIONS_ENABLE_LOGGING));
- localized_strings->SetString("disableServices",
- l10n_util::GetStringUTF16(IDS_OPTIONS_DISABLE_SERVICES));
- localized_strings->SetString("optionsReset",
- l10n_util::GetStringUTF16(IDS_OPTIONS_RESET));
- localized_strings->SetString("optionsResetMessage",
- l10n_util::GetStringUTF16(IDS_OPTIONS_RESET_MESSAGE));
- localized_strings->SetString("optionsResetOkLabel",
- l10n_util::GetStringUTF16(IDS_OPTIONS_RESET_OKLABEL));
- localized_strings->SetString("optionsResetCancelLabel",
- l10n_util::GetStringUTF16(IDS_OPTIONS_RESET_CANCELLABEL));
- localized_strings->SetString("optionsRestartRequired",
- l10n_util::GetStringUTF16(IDS_OPTIONS_RESTART_REQUIRED));
+ localized_strings->SetString("improveBrowsingExperience",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_IMPROVE_BROWSING_EXPERIENCE));
+ localized_strings->SetString("disableWebServices",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_DISABLE_WEB_SERVICES));
}
void AdvancedOptionsHandler::Initialize() {
DCHECK(dom_ui_);
- SetupMetricsReportingCheckbox(false);
+ SetupMetricsReportingCheckbox();
SetupMetricsReportingSettingVisibility();
SetupDefaultZoomLevel();
+ SetupFontSizeLabel();
SetupDownloadLocationPath();
SetupAutoOpenFileTypesDisabledAttribute();
SetupProxySettingsSection();
@@ -213,6 +230,9 @@ DOMMessageHandler* AdvancedOptionsHandler::Attach(DOMUI* dom_ui) {
prefs, this);
auto_open_files_.Init(prefs::kDownloadExtensionsToOpen, prefs, this);
default_zoom_level_.Init(prefs::kDefaultZoomLevel, prefs, this);
+ default_font_size_.Init(prefs::kWebKitDefaultFontSize, prefs, this);
+ default_fixed_font_size_.Init(prefs::kWebKitDefaultFixedFontSize, prefs,
+ this);
proxy_prefs_.reset(
PrefSetObserver::CreateProxyPrefSetObserver(prefs, this));
@@ -229,11 +249,10 @@ void AdvancedOptionsHandler::RegisterMessages() {
dom_ui_->RegisterMessageCallback("autoOpenFileTypesAction",
NewCallback(this,
&AdvancedOptionsHandler::HandleAutoOpenButton));
- dom_ui_->RegisterMessageCallback("resetToDefaults",
- NewCallback(this,
- &AdvancedOptionsHandler::HandleResetToDefaults));
dom_ui_->RegisterMessageCallback("defaultZoomLevelAction",
NewCallback(this, &AdvancedOptionsHandler::HandleDefaultZoomLevel));
+ dom_ui_->RegisterMessageCallback("defaultFontSizeAction",
+ NewCallback(this, &AdvancedOptionsHandler::HandleDefaultFontSize));
#if !defined(OS_CHROMEOS)
dom_ui_->RegisterMessageCallback("metricsReportingCheckboxAction",
NewCallback(this,
@@ -266,9 +285,6 @@ void AdvancedOptionsHandler::RegisterMessages() {
dom_ui_->RegisterMessageCallback("checkRevocationCheckboxAction",
NewCallback(this,
&AdvancedOptionsHandler::HandleCheckRevocationCheckbox));
- dom_ui_->RegisterMessageCallback("useSSL2CheckboxAction",
- NewCallback(this,
- &AdvancedOptionsHandler::HandleUseSSL2Checkbox));
dom_ui_->RegisterMessageCallback("useSSL3CheckboxAction",
NewCallback(this,
&AdvancedOptionsHandler::HandleUseSSL3Checkbox));
@@ -297,6 +313,9 @@ void AdvancedOptionsHandler::Observe(NotificationType type,
if (cloud_print_proxy_ui_enabled_)
SetupCloudPrintProxySection();
#endif
+ } else if (*pref_name == prefs::kWebKitDefaultFontSize ||
+ *pref_name == prefs::kWebKitDefaultFixedFontSize) {
+ SetupFontSizeLabel();
}
}
}
@@ -334,10 +353,6 @@ void AdvancedOptionsHandler::HandleAutoOpenButton(const ListValue* args) {
manager->download_prefs()->ResetAutoOpen();
}
-void AdvancedOptionsHandler::HandleResetToDefaults(const ListValue* args) {
- OptionsUtil::ResetToDefaults(dom_ui_->GetProfile());
-}
-
void AdvancedOptionsHandler::HandleMetricsReportingCheckbox(
const ListValue* args) {
#if defined(GOOGLE_CHROME_BUILD) && !defined(OS_CHROMEOS)
@@ -349,9 +364,7 @@ void AdvancedOptionsHandler::HandleMetricsReportingCheckbox(
UserMetricsAction("Options_MetricsReportingCheckbox_Disable"));
bool is_enabled = OptionsUtil::ResolveMetricsReportingEnabled(enabled);
enable_metrics_recording_.SetValue(is_enabled);
-
- bool user_changed = (enabled == is_enabled);
- SetupMetricsReportingCheckbox(user_changed);
+ SetupMetricsReportingCheckbox();
#endif
}
@@ -363,6 +376,17 @@ void AdvancedOptionsHandler::HandleDefaultZoomLevel(const ListValue* args) {
}
}
+void AdvancedOptionsHandler::HandleDefaultFontSize(const ListValue* args) {
+ int font_size;
+ if (ExtractIntegerValue(args, &font_size)) {
+ if (font_size > 0) {
+ default_font_size_.SetValue(font_size);
+ default_fixed_font_size_.SetValue(font_size);
+ SetupFontSizeLabel();
+ }
+ }
+}
+
#if defined(OS_WIN)
void AdvancedOptionsHandler::HandleCheckRevocationCheckbox(
const ListValue* args) {
@@ -375,15 +399,6 @@ void AdvancedOptionsHandler::HandleCheckRevocationCheckbox(
net::SSLConfigServiceWin::SetRevCheckingEnabled(enabled);
}
-void AdvancedOptionsHandler::HandleUseSSL2Checkbox(const ListValue* args) {
- std::string checked_str = WideToUTF8(ExtractStringValue(args));
- bool enabled = (checked_str == "true");
- std::string metric =
- (enabled ? "Options_SSL2_Enable" : "Options_SSL2_Disable");
- UserMetricsRecordAction(UserMetricsAction(metric.c_str()));
- net::SSLConfigServiceWin::SetSSL2Enabled(enabled);
-}
-
void AdvancedOptionsHandler::HandleUseSSL3Checkbox(const ListValue* args) {
std::string checked_str = WideToUTF8(ExtractStringValue(args));
bool enabled = (checked_str == "true");
@@ -482,14 +497,13 @@ void AdvancedOptionsHandler::SetupCloudPrintProxySection() {
}
#endif
-void AdvancedOptionsHandler::SetupMetricsReportingCheckbox(bool user_changed) {
+void AdvancedOptionsHandler::SetupMetricsReportingCheckbox() {
#if defined(GOOGLE_CHROME_BUILD) && !defined(OS_CHROMEOS)
FundamentalValue checked(enable_metrics_recording_.GetValue());
FundamentalValue disabled(enable_metrics_recording_.IsManaged());
- FundamentalValue user_has_changed(user_changed);
dom_ui_->CallJavascriptFunction(
L"options.AdvancedOptions.SetMetricsReportingCheckboxState", checked,
- disabled, user_has_changed);
+ disabled);
#endif
}
@@ -512,6 +526,15 @@ void AdvancedOptionsHandler::SetupDefaultZoomLevel() {
L"options.AdvancedOptions.SetDefaultZoomLevel", value);
}
+void AdvancedOptionsHandler::SetupFontSizeLabel() {
+ // We're only interested in integer values, so convert to int.
+ FundamentalValue fixed_font_size(default_fixed_font_size_.GetValue());
+ FundamentalValue font_size(default_font_size_.GetValue());
+ dom_ui_->CallJavascriptFunction(
+ L"options.AdvancedOptions.SetFontSize", fixed_font_size,
+ font_size);
+}
+
void AdvancedOptionsHandler::SetupDownloadLocationPath() {
StringValue value(default_download_location_.GetValue().value());
dom_ui_->CallJavascriptFunction(
@@ -557,7 +580,6 @@ void AdvancedOptionsHandler::SetupProxySettingsSection() {
#if defined(OS_WIN)
void AdvancedOptionsHandler::SetupSSLConfigSettings() {
bool checkRevocationSetting = false;
- bool useSSL2Setting = false;
bool useSSL3Setting = false;
bool useTLS1Setting = false;
bool disabled = false;
@@ -565,7 +587,6 @@ void AdvancedOptionsHandler::SetupSSLConfigSettings() {
net::SSLConfig config;
if (net::SSLConfigServiceWin::GetSSLConfigNow(&config)) {
checkRevocationSetting = config.rev_checking_enabled;
- useSSL2Setting = config.ssl2_enabled;
useSSL3Setting = config.ssl3_enabled;
useTLS1Setting = config.tls1_enabled;
} else {
@@ -576,10 +597,6 @@ void AdvancedOptionsHandler::SetupSSLConfigSettings() {
dom_ui_->CallJavascriptFunction(
L"options.AdvancedOptions.SetCheckRevocationCheckboxState",
checkRevocationValue, disabledValue);
- FundamentalValue useSSL2Value(useSSL2Setting);
- dom_ui_->CallJavascriptFunction(
- L"options.AdvancedOptions.SetUseSSL2CheckboxState",
- useSSL2Value, disabledValue);
FundamentalValue useSSL3Value(useSSL3Setting);
dom_ui_->CallJavascriptFunction(
L"options.AdvancedOptions.SetUseSSL3CheckboxState",
diff --git a/chrome/browser/dom_ui/options/advanced_options_handler.h b/chrome/browser/dom_ui/options/advanced_options_handler.h
index 58e4df9..0de52ab 100644
--- a/chrome/browser/dom_ui/options/advanced_options_handler.h
+++ b/chrome/browser/dom_ui/options/advanced_options_handler.h
@@ -51,10 +51,6 @@ class AdvancedOptionsHandler
// remove all auto-open file-type settings.
void HandleAutoOpenButton(const ListValue* args);
- // Callback for the "resetToDefaults" message. This will ask the user if
- // they want to reset all options to their default values.
- void HandleResetToDefaults(const ListValue* args);
-
// Callback for the "metricsReportingCheckboxAction" message. This is called
// if the user toggles the metrics reporting checkbox.
void HandleMetricsReportingCheckbox(const ListValue* args);
@@ -64,15 +60,16 @@ class AdvancedOptionsHandler
// one item, the zoom level as a numeric value.
void HandleDefaultZoomLevel(const ListValue* args);
+ // Callback for the "defaultFontSizeAction" message. This is called if the
+ // user changes the default font size. |args| is an array that contains
+ // one item, the font size as a numeric value.
+ void HandleDefaultFontSize(const ListValue* args);
+
#if defined(OS_WIN)
// Callback for the "Check SSL Revocation" checkbox. This is needed so we
// can support manual handling on Windows.
void HandleCheckRevocationCheckbox(const ListValue* args);
- // Callback for the "Use SSL2" checkbox. This is needed so we can support
- // manual handling on Windows.
- void HandleUseSSL2Checkbox(const ListValue* args);
-
// Callback for the "Use SSL3" checkbox. This is needed so we can support
// manual handling on Windows.
void HandleUseSSL3Checkbox(const ListValue* args);
@@ -119,12 +116,13 @@ class AdvancedOptionsHandler
#endif
// Setup the checked state for the metrics reporting checkbox.
- void SetupMetricsReportingCheckbox(bool user_changed);
+ void SetupMetricsReportingCheckbox();
// Setup the visibility for the metrics reporting setting.
void SetupMetricsReportingSettingVisibility();
void SetupDefaultZoomLevel();
+ void SetupFontSizeLabel();
// Setup the download path based on user preferences.
void SetupDownloadLocationPath();
@@ -151,6 +149,8 @@ class AdvancedOptionsHandler
FilePathPrefMember default_download_location_;
StringPrefMember auto_open_files_;
RealPrefMember default_zoom_level_;
+ IntegerPrefMember default_font_size_;
+ IntegerPrefMember default_fixed_font_size_;
scoped_ptr<PrefSetObserver> proxy_prefs_;
scoped_ptr<OptionsManagedBannerHandler> banner_handler_;
diff --git a/chrome/browser/dom_ui/options/autofill_options_handler.cc b/chrome/browser/dom_ui/options/autofill_options_handler.cc
index b3cd3ce..1e09fd2 100644
--- a/chrome/browser/dom_ui/options/autofill_options_handler.cc
+++ b/chrome/browser/dom_ui/options/autofill_options_handler.cc
@@ -13,8 +13,8 @@
#include "base/values.h"
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/credit_card.h"
-#include "chrome/browser/guid.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/guid.h"
#include "grit/generated_resources.h"
AutoFillOptionsHandler::AutoFillOptionsHandler()
@@ -34,20 +34,14 @@ void AutoFillOptionsHandler::GetLocalizedValues(
localized_strings->SetString("autoFillOptionsTitle",
l10n_util::GetStringUTF16(IDS_AUTOFILL_OPTIONS_TITLE));
- localized_strings->SetString("autoFillEnabled",
- l10n_util::GetStringUTF16(IDS_OPTIONS_AUTOFILL_ENABLE));
- localized_strings->SetString("addressesHeader",
+ localized_strings->SetString("autoFillAddresses",
l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESSES_GROUP_NAME));
- localized_strings->SetString("creditCardsHeader",
+ localized_strings->SetString("autoFillCreditCards",
l10n_util::GetStringUTF16(IDS_AUTOFILL_CREDITCARDS_GROUP_NAME));
- localized_strings->SetString("addAddressButton",
+ localized_strings->SetString("autoFillAddAddress",
l10n_util::GetStringUTF16(IDS_AUTOFILL_ADD_ADDRESS_BUTTON));
- localized_strings->SetString("addCreditCardButton",
+ localized_strings->SetString("autoFillAddCreditCard",
l10n_util::GetStringUTF16(IDS_AUTOFILL_ADD_CREDITCARD_BUTTON));
- localized_strings->SetString("editButton",
- l10n_util::GetStringUTF16(IDS_AUTOFILL_EDIT_BUTTON));
- localized_strings->SetString("deleteButton",
- l10n_util::GetStringUTF16(IDS_AUTOFILL_DELETE_BUTTON));
localized_strings->SetString("helpButton",
l10n_util::GetStringUTF16(IDS_AUTOFILL_HELP_LABEL));
localized_strings->SetString("addAddressTitle",
@@ -64,8 +58,7 @@ void AutoFillOptionsHandler::GetLocalizedValues(
}
void AutoFillOptionsHandler::Initialize() {
- personal_data_ =
- dom_ui_->GetProfile()->GetOriginalProfile()->GetPersonalDataManager();
+ personal_data_ = dom_ui_->GetProfile()->GetPersonalDataManager();
personal_data_->SetObserver(this);
LoadAutoFillData();
@@ -73,28 +66,17 @@ void AutoFillOptionsHandler::Initialize() {
void AutoFillOptionsHandler::RegisterMessages() {
dom_ui_->RegisterMessageCallback(
- "updateAddress",
- NewCallback(this, &AutoFillOptionsHandler::UpdateAddress));
-
- dom_ui_->RegisterMessageCallback(
- "editAddress",
- NewCallback(this, &AutoFillOptionsHandler::EditAddress));
-
+ "removeAutoFillProfile",
+ NewCallback(this, &AutoFillOptionsHandler::RemoveAutoFillProfile));
dom_ui_->RegisterMessageCallback(
- "removeAddress",
- NewCallback(this, &AutoFillOptionsHandler::RemoveAddress));
-
+ "loadProfileEditor",
+ NewCallback(this, &AutoFillOptionsHandler::LoadProfileEditor));
dom_ui_->RegisterMessageCallback(
- "updateCreditCard",
- NewCallback(this, &AutoFillOptionsHandler::UpdateCreditCard));
-
- dom_ui_->RegisterMessageCallback(
- "editCreditCard",
- NewCallback(this, &AutoFillOptionsHandler::EditCreditCard));
-
+ "setAddress",
+ NewCallback(this, &AutoFillOptionsHandler::SetAddress));
dom_ui_->RegisterMessageCallback(
- "removeCreditCard",
- NewCallback(this, &AutoFillOptionsHandler::RemoveCreditCard));
+ "setCreditCard",
+ NewCallback(this, &AutoFillOptionsHandler::SetCreditCard));
}
/////////////////////////////////////////////////////////////////////////////
@@ -157,30 +139,68 @@ void AutoFillOptionsHandler::LoadAutoFillData() {
for (std::vector<AutoFillProfile*>::const_iterator i =
personal_data_->web_profiles().begin();
i != personal_data_->web_profiles().end(); ++i) {
- DictionaryValue* address = new DictionaryValue();
- address->SetString("label", (*i)->Label());
- address->SetString("guid", (*i)->guid());
- addresses.Append(address);
+ ListValue* entry = new ListValue();
+ entry->Append(new StringValue((*i)->guid()));
+ entry->Append(new StringValue((*i)->Label()));
+ addresses.Append(entry);
}
- dom_ui_->CallJavascriptFunction(L"AutoFillOptions.updateAddresses",
+ dom_ui_->CallJavascriptFunction(L"AutoFillOptions.setAddressList",
addresses);
ListValue credit_cards;
for (std::vector<CreditCard*>::const_iterator i =
personal_data_->credit_cards().begin();
i != personal_data_->credit_cards().end(); ++i) {
- DictionaryValue* credit_card = new DictionaryValue();
- credit_card->SetString("label", (*i)->PreviewSummary());
- credit_card->SetString("guid", (*i)->guid());
- credit_cards.Append(credit_card);
+ ListValue* entry = new ListValue();
+ entry->Append(new StringValue((*i)->guid()));
+ entry->Append(new StringValue((*i)->PreviewSummary()));
+ credit_cards.Append(entry);
}
- dom_ui_->CallJavascriptFunction(L"AutoFillOptions.updateCreditCards",
+ dom_ui_->CallJavascriptFunction(L"AutoFillOptions.setCreditCardList",
credit_cards);
}
-void AutoFillOptionsHandler::UpdateAddress(const ListValue* args) {
+void AutoFillOptionsHandler::RemoveAutoFillProfile(const ListValue* args) {
+ DCHECK(personal_data_->IsDataLoaded());
+
+ std::string guid;
+ if (!args->GetString(0, &guid)) {
+ NOTREACHED();
+ return;
+ }
+
+ // |guid| is the GUID of either an address or a credit card. Try to load the
+ // corresponding address. If it exists, then remove that address; otherwise,
+ // the GUID identifies a credit card, so remove the credit card.
+ // TODO(jhawkins): Make RemoveProfile return true/false depending on whether
+ // the profile was removed or not.
+ if (personal_data_->GetProfileByGUID(guid) != NULL)
+ personal_data_->RemoveProfile(guid);
+ else
+ personal_data_->RemoveCreditCard(guid);
+}
+
+void AutoFillOptionsHandler::LoadProfileEditor(const ListValue* args) {
+ DCHECK(personal_data_->IsDataLoaded());
+
+ std::string guid;
+ if (!args->GetString(0, &guid)) {
+ NOTREACHED();
+ return;
+ }
+
+ // |guid| is the GUID of either an address or a credit card. Try to load the
+ // corresponding address. If it exists, then edit that address; otherwise, the
+ // GUID identifies a credit card, so load the credit card editor.
+ if (personal_data_->GetProfileByGUID(guid) != NULL)
+ EditAddress(guid);
+ else
+ EditCreditCard(guid);
+}
+
+void AutoFillOptionsHandler::SetAddress(const ListValue* args) {
if (!personal_data_->IsDataLoaded())
return;
@@ -224,7 +244,7 @@ void AutoFillOptionsHandler::UpdateAddress(const ListValue* args) {
}
}
-void AutoFillOptionsHandler::EditAddress(const ListValue* args) {
+void AutoFillOptionsHandler::SetCreditCard(const ListValue* args) {
if (!personal_data_->IsDataLoaded())
return;
@@ -234,6 +254,29 @@ void AutoFillOptionsHandler::EditAddress(const ListValue* args) {
return;
}
+ CreditCard credit_card(guid);
+
+ string16 value;
+ if (args->GetString(1, &value))
+ credit_card.SetInfo(AutoFillType(CREDIT_CARD_NAME), value);
+ if (args->GetString(2, &value))
+ credit_card.SetInfo(AutoFillType(CREDIT_CARD_NUMBER), value);
+ if (args->GetString(3, &value))
+ credit_card.SetInfo(AutoFillType(CREDIT_CARD_EXP_MONTH), value);
+ if (args->GetString(4, &value))
+ credit_card.SetInfo(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), value);
+
+ if (!guid::IsValidGUID(credit_card.guid())) {
+ credit_card.set_guid(guid::GenerateGUID());
+ personal_data_->AddCreditCard(credit_card);
+ } else {
+ personal_data_->UpdateCreditCard(credit_card);
+ }
+}
+
+void AutoFillOptionsHandler::EditAddress(const std::string& guid) {
+ DCHECK(personal_data_->IsDataLoaded());
+
AutoFillProfile* profile = personal_data_->GetProfileByGUID(guid);
if (!profile) {
NOTREACHED();
@@ -275,62 +318,10 @@ void AutoFillOptionsHandler::EditAddress(const ListValue* args) {
addressList);
}
-void AutoFillOptionsHandler::RemoveAddress(const ListValue* args) {
- if (!personal_data_->IsDataLoaded())
- return;
-
- std::string guid;
- if (!args->GetString(0, &guid)) {
- NOTREACHED();
- return;
- }
-
- personal_data_->RemoveProfile(guid);
-}
-
-void AutoFillOptionsHandler::UpdateCreditCard(const ListValue* args) {
- if (!personal_data_->IsDataLoaded())
- return;
-
- std::string guid;
- if (!args->GetString(0, &guid)) {
- NOTREACHED();
- return;
- }
-
- CreditCard credit_card(guid);
-
- string16 value;
- if (args->GetString(1, &value))
- credit_card.SetInfo(AutoFillType(CREDIT_CARD_NAME), value);
- if (args->GetString(2, &value))
- credit_card.SetInfo(AutoFillType(CREDIT_CARD_NUMBER), value);
- if (args->GetString(3, &value))
- credit_card.SetInfo(AutoFillType(CREDIT_CARD_EXP_MONTH), value);
- if (args->GetString(4, &value))
- credit_card.SetInfo(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), value);
-
- if (!guid::IsValidGUID(credit_card.guid())) {
- credit_card.set_guid(guid::GenerateGUID());
- personal_data_->AddCreditCard(credit_card);
- } else {
- personal_data_->UpdateCreditCard(credit_card);
- }
-
-}
-
-void AutoFillOptionsHandler::EditCreditCard(const ListValue* args) {
- if (!personal_data_->IsDataLoaded())
- return;
-
- std::string guid;
- if (!args->GetString(0, &guid)) {
- NOTREACHED();
- return;
- }
+void AutoFillOptionsHandler::EditCreditCard(const std::string& guid) {
+ DCHECK(personal_data_->IsDataLoaded());
CreditCard* credit_card = personal_data_->GetCreditCardByGUID(guid);
-
if (!credit_card) {
NOTREACHED();
return;
@@ -358,16 +349,3 @@ void AutoFillOptionsHandler::EditCreditCard(const ListValue* args) {
dom_ui_->CallJavascriptFunction(L"AutoFillOptions.editCreditCard",
credit_card_list);
}
-
-void AutoFillOptionsHandler::RemoveCreditCard(const ListValue* args) {
- if (!personal_data_->IsDataLoaded())
- return;
-
- std::string guid;
- if (!args->GetString(0, &guid)) {
- NOTREACHED();
- return;
- }
-
- personal_data_->RemoveCreditCard(guid);
-}
diff --git a/chrome/browser/dom_ui/options/autofill_options_handler.h b/chrome/browser/dom_ui/options/autofill_options_handler.h
index e932047..eff357a 100644
--- a/chrome/browser/dom_ui/options/autofill_options_handler.h
+++ b/chrome/browser/dom_ui/options/autofill_options_handler.h
@@ -5,9 +5,14 @@
#ifndef CHROME_BROWSER_DOM_UI_OPTIONS_AUTOFILL_OPTIONS_HANDLER_H_
#define CHROME_BROWSER_DOM_UI_OPTIONS_AUTOFILL_OPTIONS_HANDLER_H_
+#include <string>
+
#include "chrome/browser/autofill/personal_data_manager.h"
#include "chrome/browser/dom_ui/options/options_ui.h"
+class DictionaryValue;
+class ListValue;
+
class AutoFillOptionsHandler : public OptionsPageUIHandler,
public PersonalDataManager::Observer {
public:
@@ -31,38 +36,38 @@ class AutoFillOptionsHandler : public OptionsPageUIHandler,
// Loads AutoFill addresses and credit cards using the PersonalDataManager.
void LoadAutoFillData();
- // Adds or updates an address, depending on the unique ID of the address. If
- // the unique ID is 0, a new address is added to the WebDatabase; otherwise,
- // the address with the matching ID is updated. Called from DOMUI.
- // |args| - an array containing the unique ID of the address followed by the
+ // Removes either an address or a credit card, depending on the type of the
+ // profile.
+ // |args| - A string, the GUID of the profile to remove.
+ void RemoveAutoFillProfile(const ListValue* args);
+
+ // Requests profile data for a specific profile. Calls into DOMUI with the
+ // loaded profile data to open the appropriate editor, depending on the type
+ // of the profile.
+ // |args| - A string, the GUID of the profile to load.
+ void LoadProfileEditor(const ListValue* args);
+
+ // Adds or updates an address, depending on the GUID of the profile. If the
+ // GUID is empty, a new address is added to the WebDatabase; otherwise, the
+ // address with the matching GUID is updated. Called from DOMUI.
+ // |args| - an array containing the GUID of the address followed by the
// address data.
- void UpdateAddress(const ListValue* args);
+ void SetAddress(const ListValue* args);
+
+ // Adds or updates a credit card, depending on the GUID of the profile. If the
+ // GUID is empty, a new credit card is added to the WebDatabase; otherwise,
+ // the credit card with the matching GUID is updated. Called from DOMUI.
+ // |args| - an array containing the GUID of the credit card followed by the
+ // credit card data.
+ void SetCreditCard(const ListValue* args);
// Loads the data from an address and sends this data back to the DOMUI to
- // show in the address editor. Called from DOMUI.
- // |args| - an integer, the unique ID of the address to edit.
- void EditAddress(const ListValue* args);
-
- // Removes an address from the WebDatabase. Called from DOMUI.
- // |args| - an integer, the unique ID of the address to remove.
- void RemoveAddress(const ListValue* args);
-
- // Adds or updates a credit card, depending on the unique ID of the credit
- // card. If the unique ID is 0, a new credit card is added to the WebDatabase;
- // otherwise, the credit card with the matching ID is updated. Called from
- // DOMUI.
- // |args| - an array containing the unique ID of the credit card followed by
- // the credit card data.
- void UpdateCreditCard(const ListValue* args);
+ // show in the address editor. |guid| is the GUID of the profile to load.
+ void EditAddress(const std::string& guid);
// Loads the data from a credit card and sends this data back to the DOMUI to
- // show in the credit card editor. Called from DOMUI.
- // |args| - an integer, the unique ID of the credit card to edit.
- void EditCreditCard(const ListValue* args);
-
- // Removes a credit card from the WebDatabase. Called from DOMUI.
- // |args| - an integer, the unique ID of the credit card to remove.
- void RemoveCreditCard(const ListValue* args);
+ // show in the credit card editor. |guid| is the GUID of the profile to load.
+ void EditCreditCard(const std::string& guid);
// The personal data manager, used to load AutoFill profiles and credit cards.
// Unowned pointer, may not be NULL.
diff --git a/chrome/browser/dom_ui/options/browser_options_handler.cc b/chrome/browser/dom_ui/options/browser_options_handler.cc
index a6775f7..863b461 100644
--- a/chrome/browser/dom_ui/options/browser_options_handler.cc
+++ b/chrome/browser/dom_ui/options/browser_options_handler.cc
@@ -14,15 +14,16 @@
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/custom_home_pages_table_model.h"
#include "chrome/browser/dom_ui/dom_ui_favicon_source.h"
+#include "chrome/browser/dom_ui/options/dom_options_util.h"
#include "chrome/browser/dom_ui/options/options_managed_banner_handler.h"
#include "chrome/browser/instant/instant_confirm_dialog.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/net/url_fixer_upper.h"
-#include "chrome/browser/options_window.h"
#include "chrome/browser/prefs/session_startup_pref.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/ui/options/options_window.h"
#include "chrome/installer/util/browser_distribution.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
@@ -45,33 +46,35 @@ void BrowserOptionsHandler::GetLocalizedValues(
DictionaryValue* localized_strings) {
DCHECK(localized_strings);
localized_strings->SetString("startupGroupName",
- l10n_util::GetStringUTF16(IDS_OPTIONS_STARTUP_GROUP_NAME));
+ dom_options_util::StripColon(
+ l10n_util::GetStringUTF16(IDS_OPTIONS_STARTUP_GROUP_NAME)));
localized_strings->SetString("startupShowDefaultAndNewTab",
l10n_util::GetStringUTF16(IDS_OPTIONS_STARTUP_SHOW_DEFAULT_AND_NEWTAB));
localized_strings->SetString("startupShowLastSession",
l10n_util::GetStringUTF16(IDS_OPTIONS_STARTUP_SHOW_LAST_SESSION));
localized_strings->SetString("startupShowPages",
l10n_util::GetStringUTF16(IDS_OPTIONS_STARTUP_SHOW_PAGES));
- localized_strings->SetString("startupAddButton",
- l10n_util::GetStringUTF16(IDS_OPTIONS_STARTUP_ADD_BUTTON));
- localized_strings->SetString("startupRemoveButton",
- l10n_util::GetStringUTF16(IDS_OPTIONS_STARTUP_REMOVE_BUTTON));
+ localized_strings->SetString("startupShowManyPages",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_STARTUP_SHOW_MANY_PAGES));
localized_strings->SetString("startupUseCurrent",
l10n_util::GetStringUTF16(IDS_OPTIONS_STARTUP_USE_CURRENT));
localized_strings->SetString("homepageGroupName",
- l10n_util::GetStringUTF16(IDS_OPTIONS_HOMEPAGE_GROUP_NAME));
+ dom_options_util::StripColon(
+ l10n_util::GetStringUTF16(IDS_OPTIONS_HOMEPAGE_GROUP_NAME)));
localized_strings->SetString("homepageUseNewTab",
l10n_util::GetStringUTF16(IDS_OPTIONS_HOMEPAGE_USE_NEWTAB));
localized_strings->SetString("homepageUseURL",
l10n_util::GetStringUTF16(IDS_OPTIONS_HOMEPAGE_USE_URL));
localized_strings->SetString("toolbarGroupName",
- l10n_util::GetStringUTF16(IDS_OPTIONS_TOOLBAR_GROUP_NAME));
+ dom_options_util::StripColon(
+ l10n_util::GetStringUTF16(IDS_OPTIONS_TOOLBAR_GROUP_NAME)));
localized_strings->SetString("toolbarShowHomeButton",
l10n_util::GetStringUTF16(IDS_OPTIONS_TOOLBAR_SHOW_HOME_BUTTON));
localized_strings->SetString("defaultSearchGroupName",
- l10n_util::GetStringUTF16(IDS_OPTIONS_DEFAULTSEARCH_GROUP_NAME));
- localized_strings->SetString("defaultSearchManageEnginesLink",
- l10n_util::GetStringUTF16(IDS_OPTIONS_DEFAULTSEARCH_MANAGE_ENGINES_LINK));
+ dom_options_util::StripColon(
+ l10n_util::GetStringUTF16(IDS_OPTIONS_DEFAULTSEARCH_GROUP_NAME)));
+ localized_strings->SetString("defaultSearchManageEngines",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_DEFAULTSEARCH_MANAGE_ENGINES));
localized_strings->SetString("instantName",
l10n_util::GetStringUTF16(IDS_INSTANT_PREF));
localized_strings->SetString("instantWarningText",
@@ -83,7 +86,8 @@ void BrowserOptionsHandler::GetLocalizedValues(
localized_strings->SetString("instantConfirmMessage",
l10n_util::GetStringUTF16(IDS_INSTANT_OPT_IN_MESSAGE));
localized_strings->SetString("defaultBrowserGroupName",
- l10n_util::GetStringUTF16(IDS_OPTIONS_DEFAULTBROWSER_GROUP_NAME));
+ dom_options_util::StripColon(
+ l10n_util::GetStringUTF16(IDS_OPTIONS_DEFAULTBROWSER_GROUP_NAME)));
localized_strings->SetString("defaultBrowserUnknown",
l10n_util::GetStringFUTF16(IDS_OPTIONS_DEFAULTBROWSER_UNKNOWN,
l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
@@ -115,7 +119,7 @@ void BrowserOptionsHandler::Initialize() {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(new DOMUIFavIconSource(dom_ui_->GetProfile()))));
diff --git a/chrome/browser/dom_ui/options/certificate_manager_handler.cc b/chrome/browser/dom_ui/options/certificate_manager_handler.cc
index b5d684a..480fcb4 100644
--- a/chrome/browser/dom_ui/options/certificate_manager_handler.cc
+++ b/chrome/browser/dom_ui/options/certificate_manager_handler.cc
@@ -457,9 +457,9 @@ void CertificateManagerHandler::GetCATrust(const ListValue* args) {
void CertificateManagerHandler::EditCATrust(const ListValue* args) {
net::X509Certificate* cert = CallbackArgsToCert(args);
bool fail = !cert;
- bool trust_ssl;
- bool trust_email;
- bool trust_obj_sign;
+ bool trust_ssl = false;
+ bool trust_email = false;
+ bool trust_obj_sign = false;
fail |= !CallbackArgsToBool(args, 1, &trust_ssl);
fail |= !CallbackArgsToBool(args, 2, &trust_email);
fail |= !CallbackArgsToBool(args, 3, &trust_obj_sign);
@@ -533,10 +533,10 @@ void CertificateManagerHandler::ExportPersonalPasswordSelected(
password_,
&output);
if (!num_exported) {
+ dom_ui_->CallJavascriptFunction(L"CertificateRestoreOverlay.dismiss");
ShowError(
l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_EXPORT_ERROR_TITLE),
l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
- dom_ui_->CallJavascriptFunction(L"CertificateRestoreOverlay.dismiss");
ImportExportCleanup();
return;
}
diff --git a/chrome/browser/dom_ui/options/clear_browser_data_handler.cc b/chrome/browser/dom_ui/options/clear_browser_data_handler.cc
index 9cf4838..21f2121 100644
--- a/chrome/browser/dom_ui/options/clear_browser_data_handler.cc
+++ b/chrome/browser/dom_ui/options/clear_browser_data_handler.cc
@@ -9,7 +9,7 @@
#include "base/string16.h"
#include "base/values.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/dom_ui/options/content_settings_handler.cc b/chrome/browser/dom_ui/options/content_settings_handler.cc
index 77e0abf..d1bccf8 100644
--- a/chrome/browser/dom_ui/options/content_settings_handler.cc
+++ b/chrome/browser/dom_ui/options/content_settings_handler.cc
@@ -10,10 +10,11 @@
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/browser_list.h"
+#include "chrome/browser/content_settings/content_settings_details.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
-#include "chrome/browser/host_content_settings_map.h"
#include "chrome/browser/notifications/desktop_notification_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/content_settings_helper.h"
#include "chrome/common/notification_service.h"
@@ -24,8 +25,6 @@
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
-typedef HostContentSettingsMap::ContentSettingsDetails ContentSettingsDetails;
-
namespace {
const char* kDisplayPattern = "displayPattern";
@@ -112,7 +111,7 @@ std::string GeolocationExceptionToString(const GURL& origin,
// in a HostContentSettingsMap-controlled exceptions table (e.g., cookies).
// Ownership of the pointer is passed to the caller.
DictionaryValue* GetExceptionForPage(
- const HostContentSettingsMap::Pattern pattern,
+ const ContentSettingsPattern pattern,
ContentSetting setting) {
DictionaryValue* exception = new DictionaryValue();
exception->Set(
@@ -199,12 +198,16 @@ void ContentSettingsHandler::GetLocalizedValues(
l10n_util::GetStringUTF16(IDS_EXCEPTIONS_OTR_LABEL));
localized_strings->SetString("examplePattern",
l10n_util::GetStringUTF16(IDS_EXCEPTIONS_PATTERN_EXAMPLE));
+ localized_strings->SetString("addNewExceptionInstructions",
+ l10n_util::GetStringUTF16(IDS_EXCEPTIONS_ADD_NEW_INSTRUCTIONS));
+ localized_strings->SetString("manage_exceptions",
+ l10n_util::GetStringUTF16(IDS_EXCEPTIONS_MANAGE));
// Cookies filter.
localized_strings->SetString("cookies_tab_label",
l10n_util::GetStringUTF16(IDS_COOKIES_TAB_LABEL));
- localized_strings->SetString("cookies_modify",
- l10n_util::GetStringUTF16(IDS_MODIFY_COOKIE_STORING_LABEL));
+ localized_strings->SetString("cookies_header",
+ l10n_util::GetStringUTF16(IDS_COOKIES_HEADER));
localized_strings->SetString("cookies_allow",
l10n_util::GetStringUTF16(IDS_COOKIES_ALLOW_RADIO));
localized_strings->SetString("cookies_ask",
@@ -225,8 +228,8 @@ void ContentSettingsHandler::GetLocalizedValues(
// Image filter.
localized_strings->SetString("images_tab_label",
l10n_util::GetStringUTF16(IDS_IMAGES_TAB_LABEL));
- localized_strings->SetString("images_setting",
- l10n_util::GetStringUTF16(IDS_IMAGES_SETTING_LABEL));
+ localized_strings->SetString("images_header",
+ l10n_util::GetStringUTF16(IDS_IMAGES_HEADER));
localized_strings->SetString("images_allow",
l10n_util::GetStringUTF16(IDS_IMAGES_LOAD_RADIO));
localized_strings->SetString("images_block",
@@ -235,8 +238,8 @@ void ContentSettingsHandler::GetLocalizedValues(
// JavaScript filter.
localized_strings->SetString("javascript_tab_label",
l10n_util::GetStringUTF16(IDS_JAVASCRIPT_TAB_LABEL));
- localized_strings->SetString("javascript_setting",
- l10n_util::GetStringUTF16(IDS_JS_SETTING_LABEL));
+ localized_strings->SetString("javascript_header",
+ l10n_util::GetStringUTF16(IDS_JAVASCRIPT_HEADER));
localized_strings->SetString("javascript_allow",
l10n_util::GetStringUTF16(IDS_JS_ALLOW_RADIO));
localized_strings->SetString("javascript_block",
@@ -245,8 +248,8 @@ void ContentSettingsHandler::GetLocalizedValues(
// Plug-ins filter.
localized_strings->SetString("plugins_tab_label",
l10n_util::GetStringUTF16(IDS_PLUGIN_TAB_LABEL));
- localized_strings->SetString("plugins_setting",
- l10n_util::GetStringUTF16(IDS_PLUGIN_SETTING_LABEL));
+ localized_strings->SetString("plugins_header",
+ l10n_util::GetStringUTF16(IDS_PLUGIN_HEADER));
localized_strings->SetString("plugins_ask",
l10n_util::GetStringUTF16(IDS_PLUGIN_ASK_RADIO));
localized_strings->SetString("plugins_allow",
@@ -259,12 +262,11 @@ void ContentSettingsHandler::GetLocalizedValues(
CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableClickToPlay));
-
// Pop-ups filter.
localized_strings->SetString("popups_tab_label",
l10n_util::GetStringUTF16(IDS_POPUP_TAB_LABEL));
- localized_strings->SetString("popups_setting",
- l10n_util::GetStringUTF16(IDS_POPUP_SETTING_LABEL));
+ localized_strings->SetString("popups_header",
+ l10n_util::GetStringUTF16(IDS_POPUP_HEADER));
localized_strings->SetString("popups_allow",
l10n_util::GetStringUTF16(IDS_POPUP_ALLOW_RADIO));
localized_strings->SetString("popups_block",
@@ -273,8 +275,8 @@ void ContentSettingsHandler::GetLocalizedValues(
// Location filter.
localized_strings->SetString("location_tab_label",
l10n_util::GetStringUTF16(IDS_GEOLOCATION_TAB_LABEL));
- localized_strings->SetString("location_setting",
- l10n_util::GetStringUTF16(IDS_GEOLOCATION_SETTING_LABEL));
+ localized_strings->SetString("location_header",
+ l10n_util::GetStringUTF16(IDS_GEOLOCATION_HEADER));
localized_strings->SetString("location_allow",
l10n_util::GetStringUTF16(IDS_GEOLOCATION_ALLOW_RADIO));
localized_strings->SetString("location_ask",
@@ -285,8 +287,8 @@ void ContentSettingsHandler::GetLocalizedValues(
// Notifications filter.
localized_strings->SetString("notifications_tab_label",
l10n_util::GetStringUTF16(IDS_NOTIFICATIONS_TAB_LABEL));
- localized_strings->SetString("notifications_setting",
- l10n_util::GetStringUTF16(IDS_NOTIFICATIONS_SETTING_LABEL));
+ localized_strings->SetString("notifications_header",
+ l10n_util::GetStringUTF16(IDS_NOTIFICATIONS_HEADER));
localized_strings->SetString("notifications_allow",
l10n_util::GetStringUTF16(IDS_NOTIFICATIONS_ALLOW_RADIO));
localized_strings->SetString("notifications_ask",
@@ -312,7 +314,7 @@ void ContentSettingsHandler::Initialize() {
UpdateAllExceptionsViewsFromModel();
notification_registrar_.Add(
this, NotificationType::CONTENT_SETTINGS_CHANGED,
- Source<const HostContentSettingsMap>(settings_map));
+ NotificationService::AllSources());
notification_registrar_.Add(
this, NotificationType::DESKTOP_NOTIFICATION_DEFAULT_CHANGED,
NotificationService::AllSources());
@@ -332,8 +334,10 @@ void ContentSettingsHandler::Observe(NotificationType type,
switch (type.value) {
case NotificationType::PROFILE_DESTROYED: {
Profile* profile = static_cast<Source<Profile> >(source).ptr();
- if (profile->IsOffTheRecord())
- dom_ui_->CallJavascriptFunction(L"ContentSettings.OTRProfileDestroyed");
+ if (profile->IsOffTheRecord()) {
+ dom_ui_->CallJavascriptFunction(
+ L"ContentSettingsExceptionsArea.OTRProfileDestroyed");
+ }
break;
}
@@ -344,7 +348,7 @@ void ContentSettingsHandler::Observe(NotificationType type,
case NotificationType::CONTENT_SETTINGS_CHANGED: {
const ContentSettingsDetails* settings_details =
- static_cast<Details<const ContentSettingsDetails> >(details).ptr();
+ Details<const ContentSettingsDetails>(details).ptr();
// TODO(estade): we pretend update_all() is always true.
if (settings_details->update_all_types())
@@ -381,8 +385,10 @@ void ContentSettingsHandler::Observe(NotificationType type,
void ContentSettingsHandler::UpdateSettingDefaultFromModel(
ContentSettingsType type) {
DictionaryValue filter_settings;
- filter_settings.SetString(ContentSettingsTypeToGroupName(type),
- GetSettingDefaultFromModel(type));
+ filter_settings.SetString(ContentSettingsTypeToGroupName(type) + ".value",
+ GetSettingDefaultFromModel(type));
+ filter_settings.SetBoolean(ContentSettingsTypeToGroupName(type) + ".managed",
+ GetDefaultSettingManagedFromModel(type));
dom_ui_->CallJavascriptFunction(
L"ContentSettings.setContentFilterSettingsValue", filter_settings);
@@ -404,6 +410,19 @@ std::string ContentSettingsHandler::GetSettingDefaultFromModel(
return ContentSettingToString(default_setting);
}
+bool ContentSettingsHandler::GetDefaultSettingManagedFromModel(
+ ContentSettingsType type) {
+ if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
+ return dom_ui_->GetProfile()->
+ GetGeolocationContentSettingsMap()->IsDefaultContentSettingManaged();
+ } else if (type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
+ return dom_ui_->GetProfile()->
+ GetDesktopNotificationService()->IsDefaultContentSettingManaged();
+ } else {
+ return GetContentSettingsMap()->IsDefaultContentSettingManaged(type);
+ }
+}
+
void ContentSettingsHandler::UpdateAllExceptionsViewsFromModel() {
for (int type = CONTENT_SETTINGS_TYPE_DEFAULT + 1;
type < CONTENT_SETTINGS_NUM_TYPES; ++type) {
@@ -553,9 +572,9 @@ void ContentSettingsHandler::RegisterMessages() {
dom_ui_->RegisterMessageCallback("setAllowThirdPartyCookies",
NewCallback(this,
&ContentSettingsHandler::SetAllowThirdPartyCookies));
- dom_ui_->RegisterMessageCallback("removeExceptions",
+ dom_ui_->RegisterMessageCallback("removeException",
NewCallback(this,
- &ContentSettingsHandler::RemoveExceptions));
+ &ContentSettingsHandler::RemoveException));
dom_ui_->RegisterMessageCallback("setException",
NewCallback(this,
&ContentSettingsHandler::SetException));
@@ -596,62 +615,60 @@ void ContentSettingsHandler::SetAllowThirdPartyCookies(const ListValue* args) {
GetContentSettingsMap()->SetBlockThirdPartyCookies(allow == L"true");
}
-void ContentSettingsHandler::RemoveExceptions(const ListValue* args) {
+void ContentSettingsHandler::RemoveException(const ListValue* args) {
size_t arg_i = 0;
std::string type_string;
CHECK(args->GetString(arg_i++, &type_string));
ContentSettingsType type = ContentSettingsTypeFromGroupName(type_string);
- while (arg_i < args->GetSize()) {
- if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
- std::string origin;
- std::string embedding_origin;
- bool rv = args->GetString(arg_i++, &origin);
- DCHECK(rv);
- rv = args->GetString(arg_i++, &embedding_origin);
- DCHECK(rv);
-
- dom_ui_->GetProfile()->GetGeolocationContentSettingsMap()->
- SetContentSetting(GURL(origin),
- GURL(embedding_origin),
- CONTENT_SETTING_DEFAULT);
- } else if (type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
- std::string origin;
- std::string setting;
- bool rv = args->GetString(arg_i++, &origin);
- DCHECK(rv);
- rv = args->GetString(arg_i++, &setting);
- DCHECK(rv);
- ContentSetting content_setting = ContentSettingFromString(setting);
- if (content_setting == CONTENT_SETTING_ALLOW) {
- dom_ui_->GetProfile()->GetDesktopNotificationService()->
- ResetAllowedOrigin(GURL(origin));
- } else {
- DCHECK_EQ(content_setting, CONTENT_SETTING_BLOCK);
- dom_ui_->GetProfile()->GetDesktopNotificationService()->
- ResetBlockedOrigin(GURL(origin));
- }
+ if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
+ std::string origin;
+ std::string embedding_origin;
+ bool rv = args->GetString(arg_i++, &origin);
+ DCHECK(rv);
+ rv = args->GetString(arg_i++, &embedding_origin);
+ DCHECK(rv);
+
+ dom_ui_->GetProfile()->GetGeolocationContentSettingsMap()->
+ SetContentSetting(GURL(origin),
+ GURL(embedding_origin),
+ CONTENT_SETTING_DEFAULT);
+ } else if (type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
+ std::string origin;
+ std::string setting;
+ bool rv = args->GetString(arg_i++, &origin);
+ DCHECK(rv);
+ rv = args->GetString(arg_i++, &setting);
+ DCHECK(rv);
+ ContentSetting content_setting = ContentSettingFromString(setting);
+ if (content_setting == CONTENT_SETTING_ALLOW) {
+ dom_ui_->GetProfile()->GetDesktopNotificationService()->
+ ResetAllowedOrigin(GURL(origin));
} else {
- std::string mode;
- bool rv = args->GetString(arg_i++, &mode);
- DCHECK(rv);
-
- std::string pattern;
- rv = args->GetString(arg_i++, &pattern);
- DCHECK(rv);
-
- HostContentSettingsMap* settings_map =
- mode == "normal" ? GetContentSettingsMap() :
- GetOTRContentSettingsMap();
- // The settings map could be null if the mode was OTR but the OTR profile
- // got destroyed before we received this message.
- if (settings_map) {
- settings_map->SetContentSetting(
- HostContentSettingsMap::Pattern(pattern),
- ContentSettingsTypeFromGroupName(type_string),
- "",
- CONTENT_SETTING_DEFAULT);
- }
+ DCHECK_EQ(content_setting, CONTENT_SETTING_BLOCK);
+ dom_ui_->GetProfile()->GetDesktopNotificationService()->
+ ResetBlockedOrigin(GURL(origin));
+ }
+ } else {
+ std::string mode;
+ bool rv = args->GetString(arg_i++, &mode);
+ DCHECK(rv);
+
+ std::string pattern;
+ rv = args->GetString(arg_i++, &pattern);
+ DCHECK(rv);
+
+ HostContentSettingsMap* settings_map =
+ mode == "normal" ? GetContentSettingsMap() :
+ GetOTRContentSettingsMap();
+ // The settings map could be null if the mode was OTR but the OTR profile
+ // got destroyed before we received this message.
+ if (settings_map) {
+ settings_map->SetContentSetting(
+ ContentSettingsPattern(pattern),
+ ContentSettingsTypeFromGroupName(type_string),
+ "",
+ CONTENT_SETTING_DEFAULT);
}
}
}
@@ -683,11 +700,10 @@ void ContentSettingsHandler::SetException(const ListValue* args) {
if (!settings_map)
return;
- settings_map->
- SetContentSetting(HostContentSettingsMap::Pattern(pattern),
- type,
- "",
- ContentSettingFromString(setting));
+ settings_map->SetContentSetting(ContentSettingsPattern(pattern),
+ type,
+ "",
+ ContentSettingFromString(setting));
}
void ContentSettingsHandler::CheckExceptionPatternValidity(
@@ -700,7 +716,7 @@ void ContentSettingsHandler::CheckExceptionPatternValidity(
std::string pattern_string;
CHECK(args->GetString(arg_i++, &pattern_string));
- HostContentSettingsMap::Pattern pattern(pattern_string);
+ ContentSettingsPattern pattern(pattern_string);
scoped_ptr<Value> mode_value(Value::CreateStringValue(mode_string));
scoped_ptr<Value> pattern_value(Value::CreateStringValue(pattern_string));
diff --git a/chrome/browser/dom_ui/options/content_settings_handler.h b/chrome/browser/dom_ui/options/content_settings_handler.h
index e18de26..1542539 100644
--- a/chrome/browser/dom_ui/options/content_settings_handler.h
+++ b/chrome/browser/dom_ui/options/content_settings_handler.h
@@ -65,10 +65,10 @@ class ContentSettingsHandler : public OptionsPageUIHandler {
// chosen.
void SetContentFilter(const ListValue* args);
- // Removes the given rows from the table. The first entry in |args| is the
- // content type, and the rest of the arguments describe individual exceptions
+ // Removes the given row from the table. The first entry in |args| is the
+ // content type, and the rest of the arguments depend on the content type
// to be removed.
- void RemoveExceptions(const ListValue* args);
+ void RemoveException(const ListValue* args);
// Changes the value of an exception. Called after the user is done editing an
// exception.
@@ -96,6 +96,10 @@ class ContentSettingsHandler : public OptionsPageUIHandler {
// Gets the default setting in string form.
std::string GetSettingDefaultFromModel(ContentSettingsType type);
+ // Returns true if the default setting for the given content settings type
+ // |type| is managed.
+ bool GetDefaultSettingManagedFromModel(ContentSettingsType type);
+
// Member variables ---------------------------------------------------------
NotificationRegistrar notification_registrar_;
diff --git a/chrome/browser/dom_ui/options/cookies_view_handler.cc b/chrome/browser/dom_ui/options/cookies_view_handler.cc
index f1eee91..5cfeb7a 100644
--- a/chrome/browser/dom_ui/options/cookies_view_handler.cc
+++ b/chrome/browser/dom_ui/options/cookies_view_handler.cc
@@ -15,7 +15,7 @@
#include "chrome/browser/browsing_data_database_helper.h"
#include "chrome/browser/browsing_data_indexed_db_helper.h"
#include "chrome/browser/browsing_data_local_storage_helper.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "grit/generated_resources.h"
#include "net/base/cookie_monster.h"
@@ -85,9 +85,9 @@ void GetCookieTreeNodeDictionary(const CookieTreeNode& node,
dict->SetString(kKeySendFor, cookie.IsSecure() ?
l10n_util::GetStringUTF8(IDS_COOKIES_COOKIE_SENDFOR_SECURE) :
l10n_util::GetStringUTF8(IDS_COOKIES_COOKIE_SENDFOR_ANY));
- dict->SetString(kKeyCreated, WideToUTF8(
+ dict->SetString(kKeyCreated, UTF16ToUTF8(
base::TimeFormatFriendlyDateAndTime(cookie.CreationDate())));
- dict->SetString(kKeyExpires, cookie.DoesExpire() ? WideToUTF8(
+ dict->SetString(kKeyExpires, cookie.DoesExpire() ? UTF16ToUTF8(
base::TimeFormatFriendlyDateAndTime(cookie.ExpiryDate())) :
l10n_util::GetStringUTF8(IDS_COOKIES_COOKIE_EXPIRES_SESSION));
@@ -108,7 +108,7 @@ void GetCookieTreeNodeDictionary(const CookieTreeNode& node,
FormatBytes(database_info.size,
GetByteDisplayUnits(database_info.size),
true));
- dict->SetString(kKeyModified, WideToUTF8(
+ dict->SetString(kKeyModified, UTF16ToUTF8(
base::TimeFormatFriendlyDateAndTime(database_info.last_modified)));
break;
@@ -125,7 +125,7 @@ void GetCookieTreeNodeDictionary(const CookieTreeNode& node,
FormatBytes(local_storage_info.size,
GetByteDisplayUnits(local_storage_info.size),
true));
- dict->SetString(kKeyModified, WideToUTF8(
+ dict->SetString(kKeyModified, UTF16ToUTF8(
base::TimeFormatFriendlyDateAndTime(
local_storage_info.last_modified)));
@@ -143,9 +143,9 @@ void GetCookieTreeNodeDictionary(const CookieTreeNode& node,
FormatBytes(appcache_info.size,
GetByteDisplayUnits(appcache_info.size),
true));
- dict->SetString(kKeyCreated, WideToUTF8(
+ dict->SetString(kKeyCreated, UTF16ToUTF8(
base::TimeFormatFriendlyDateAndTime(appcache_info.creation_time)));
- dict->SetString(kKeyAccessed, WideToUTF8(
+ dict->SetString(kKeyAccessed, UTF16ToUTF8(
base::TimeFormatFriendlyDateAndTime(appcache_info.last_access_time)));
break;
@@ -162,7 +162,7 @@ void GetCookieTreeNodeDictionary(const CookieTreeNode& node,
FormatBytes(indexed_db_info.size,
GetByteDisplayUnits(indexed_db_info.size),
true));
- dict->SetString(kKeyModified, WideToUTF8(
+ dict->SetString(kKeyModified, UTF16ToUTF8(
base::TimeFormatFriendlyDateAndTime(indexed_db_info.last_modified)));
break;
diff --git a/chrome/browser/dom_ui/options/core_options_handler.cc b/chrome/browser/dom_ui/options/core_options_handler.cc
index 951b7d8..ab8a6d4 100644
--- a/chrome/browser/dom_ui/options/core_options_handler.cc
+++ b/chrome/browser/dom_ui/options/core_options_handler.cc
@@ -12,8 +12,8 @@
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/notification_details.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/url_constants.h"
#include "googleurl/src/gurl.h"
@@ -367,4 +367,3 @@ void CoreOptionsHandler::NotifyPrefChanged(const std::string* pref_name) {
}
}
}
-
diff --git a/chrome/browser/dom_ui/options/dom_options_util.cc b/chrome/browser/dom_ui/options/dom_options_util.cc
new file mode 100644
index 0000000..f528a47
--- /dev/null
+++ b/chrome/browser/dom_ui/options/dom_options_util.cc
@@ -0,0 +1,18 @@
+// 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.
+
+#include "chrome/browser/dom_ui/options/dom_options_util.h"
+
+#include "base/string_util.h"
+
+namespace dom_options_util {
+
+string16 StripColon(const string16& str) {
+ const string16::value_type kColon[] = {':',0};
+ string16 result;
+ RemoveChars(str, kColon, &result);
+ return result;
+}
+
+} // namespace dom_options_util
diff --git a/chrome/browser/dom_ui/options/dom_options_util.h b/chrome/browser/dom_ui/options/dom_options_util.h
new file mode 100644
index 0000000..9cbac39
--- /dev/null
+++ b/chrome/browser/dom_ui/options/dom_options_util.h
@@ -0,0 +1,21 @@
+// 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.
+
+#ifndef CHROME_BROWSER_DOM_UI_OPTIONS_DOM_OPTIONS_UTIL_H_
+#define CHROME_BROWSER_DOM_UI_OPTIONS_DOM_OPTIONS_UTIL_H_
+#pragma once
+
+#include "base/string16.h"
+
+namespace dom_options_util {
+
+// Strips the trailing colon from a string. Used to remove the colon from
+// section titles on platforms that append it.
+// TODO(jhawkins): Remove this once the platform-specific options dialogs are
+// removed.
+string16 StripColon(const string16& str);
+
+} // namespace options_util
+
+#endif // CHROME_BROWSER_DOM_UI_OPTIONS_DOM_OPTIONS_UTIL_H_
diff --git a/chrome/browser/dom_ui/options/font_settings_handler.cc b/chrome/browser/dom_ui/options/font_settings_handler.cc
index ce0c31e..64eef14 100644
--- a/chrome/browser/dom_ui/options/font_settings_handler.cc
+++ b/chrome/browser/dom_ui/options/font_settings_handler.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/dom_ui/options/font_settings_handler.h"
+#include <string>
+
#include "app/l10n_util.h"
#include "base/basictypes.h"
#include "base/string_number_conversions.h"
@@ -12,8 +14,8 @@
#include "chrome/browser/character_encoding.h"
#include "chrome/browser/dom_ui/options/font_settings_utils.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/notification_details.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "grit/chromium_strings.h"
diff --git a/chrome/browser/dom_ui/options/import_data_handler.cc b/chrome/browser/dom_ui/options/import_data_handler.cc
index fe60703..85fd571 100644
--- a/chrome/browser/dom_ui/options/import_data_handler.cc
+++ b/chrome/browser/dom_ui/options/import_data_handler.cc
@@ -15,7 +15,7 @@
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "chrome/browser/importer/importer_data_types.h"
@@ -31,65 +31,31 @@ ImportDataHandler::~ImportDataHandler() {
void ImportDataHandler::GetLocalizedValues(
DictionaryValue* localized_strings) {
DCHECK(localized_strings);
- localized_strings->SetString("import_data_title",
+ localized_strings->SetString("importDataTitle",
l10n_util::GetStringUTF16(IDS_IMPORT_SETTINGS_TITLE));
- localized_strings->SetString("import_from_label",
+ localized_strings->SetString("importFromLabel",
l10n_util::GetStringUTF16(IDS_IMPORT_FROM_LABEL));
- localized_strings->SetString("import_commit",
- l10n_util::GetStringUTF16(IDS_IMPORT_COMMIT));
- localized_strings->SetString("import_description",
+ localized_strings->SetString("importLoading",
+ l10n_util::GetStringUTF16(IDS_IMPORT_LOADING_PROFILES));
+ localized_strings->SetString("importDescription",
l10n_util::GetStringUTF16(IDS_IMPORT_ITEMS_LABEL));
- localized_strings->SetString("import_favorites",
+ localized_strings->SetString("importHistory",
+ l10n_util::GetStringUTF16(IDS_IMPORT_HISTORY_CHKBOX));
+ localized_strings->SetString("importFavorites",
l10n_util::GetStringUTF16(IDS_IMPORT_FAVORITES_CHKBOX));
- localized_strings->SetString("import_search",
+ localized_strings->SetString("importSearch",
l10n_util::GetStringUTF16(IDS_IMPORT_SEARCH_ENGINES_CHKBOX));
- localized_strings->SetString("import_passwords",
+ localized_strings->SetString("importPasswords",
l10n_util::GetStringUTF16(IDS_IMPORT_PASSWORDS_CHKBOX));
- localized_strings->SetString("import_history",
- l10n_util::GetStringUTF16(IDS_IMPORT_HISTORY_CHKBOX));
- localized_strings->SetString("no_profile_found",
+ localized_strings->SetString("importCommit",
+ l10n_util::GetStringUTF16(IDS_IMPORT_COMMIT));
+ localized_strings->SetString("noProfileFound",
l10n_util::GetStringUTF16(IDS_IMPORT_NO_PROFILE_FOUND));
}
void ImportDataHandler::Initialize() {
- importer_list_.reset(new ImporterList);
-
- // The ImporterHost object creates an ImporterList, which calls PathExists
- // one or more times. Because we are currently in the UI thread, this will
- // trigger a DCHECK due to IO being done on the UI thread. For now we will
- // supress the DCHECK. See the following bug for more detail:
- // http://crbug.com/60825
- base::ThreadRestrictions::ScopedAllowIO allow_io;
- importer_list_->DetectSourceProfiles();
- int profiles_count = importer_list_->GetAvailableProfileCount();
-
- ListValue browser_profiles;
- if (profiles_count > 0) {
- for (int i = 0; i < profiles_count; i++) {
- const importer::ProfileInfo& source_profile =
- importer_list_->GetSourceProfileInfoAt(i);
- string16 browser_name = WideToUTF16Hack(source_profile.description);
- uint16 browser_services = source_profile.services_supported;
-
- DictionaryValue* browser_profile = new DictionaryValue();
- browser_profile->SetString("name", browser_name);
- browser_profile->SetInteger("index", i);
- browser_profile->SetBoolean("history",
- (browser_services & importer::HISTORY) != 0);
- browser_profile->SetBoolean("favorites",
- (browser_services & importer::FAVORITES) != 0);
- browser_profile->SetBoolean("passwords",
- (browser_services & importer::PASSWORDS) != 0);
- browser_profile->SetBoolean("search",
- (browser_services & importer::SEARCH_ENGINES) != 0);
-
- browser_profiles.Append(browser_profile);
- }
- }
-
- dom_ui_->CallJavascriptFunction(
- L"options.ImportDataOverlay.updateSupportedBrowsers",
- browser_profiles);
+ importer_list_ = new ImporterList;
+ importer_list_->DetectSourceProfiles(this);
}
void ImportDataHandler::RegisterMessages() {
@@ -131,21 +97,14 @@ void ImportDataHandler::ImportData(const ListValue* args) {
dom_ui_->CallJavascriptFunction(
L"ImportDataOverlay.setImportingState", state);
- // The ImporterHost object creates an ImporterList, which calls PathExists
- // one or more times. Because we are currently in the UI thread, this will
- // trigger a DCHECK due to IO being done on the UI thread. For now we will
- // supress the DCHECK. See the following bug for more detail:
- // http://crbug.com/60825
- base::ThreadRestrictions::ScopedAllowIO allow_io;
-
// TODO(csilv): Out-of-process import has only been qualified on MacOS X,
// so we will only use it on that platform since it is required. Remove this
// conditional logic once oop import is qualified for Linux/Windows.
// http://crbug.com/22142
#if defined(OS_MACOSX)
- importer_host_ = new ExternalProcessImporterHost;
+ importer_host_ = new ExternalProcessImporterHost(this);
#else
- importer_host_ = new ImporterHost;
+ importer_host_ = new ImporterHost(this);
#endif
importer_host_->SetObserver(this);
Profile* profile = dom_ui_->GetProfile();
@@ -175,3 +134,32 @@ void ImportDataHandler::ImportEnded() {
dom_ui_->CallJavascriptFunction(L"ImportDataOverlay.dismiss");
}
+
+void ImportDataHandler::SourceProfilesLoaded() {
+ ListValue browser_profiles;
+ int profiles_count = importer_list_->GetAvailableProfileCount();
+ for (int i = 0; i < profiles_count; i++) {
+ const importer::ProfileInfo& source_profile =
+ importer_list_->GetSourceProfileInfoAt(i);
+ string16 browser_name = WideToUTF16Hack(source_profile.description);
+ uint16 browser_services = source_profile.services_supported;
+
+ DictionaryValue* browser_profile = new DictionaryValue();
+ browser_profile->SetString("name", browser_name);
+ browser_profile->SetInteger("index", i);
+ browser_profile->SetBoolean("history",
+ (browser_services & importer::HISTORY) != 0);
+ browser_profile->SetBoolean("favorites",
+ (browser_services & importer::FAVORITES) != 0);
+ browser_profile->SetBoolean("passwords",
+ (browser_services & importer::PASSWORDS) != 0);
+ browser_profile->SetBoolean("search",
+ (browser_services & importer::SEARCH_ENGINES) != 0);
+
+ browser_profiles.Append(browser_profile);
+ }
+
+ dom_ui_->CallJavascriptFunction(
+ L"options.ImportDataOverlay.updateSupportedBrowsers",
+ browser_profiles);
+}
diff --git a/chrome/browser/dom_ui/options/import_data_handler.h b/chrome/browser/dom_ui/options/import_data_handler.h
index 1c7b872..8f4ed61 100644
--- a/chrome/browser/dom_ui/options/import_data_handler.h
+++ b/chrome/browser/dom_ui/options/import_data_handler.h
@@ -5,12 +5,14 @@
#ifndef CHROME_BROWSER_DOM_UI_OPTIONS_IMPORT_DATA_HANDLER_H_
#define CHROME_BROWSER_DOM_UI_OPTIONS_IMPORT_DATA_HANDLER_H_
+#include "base/ref_counted.h"
#include "chrome/browser/dom_ui/options/options_ui.h"
#include "chrome/browser/importer/importer.h"
// Chrome personal stuff import data overlay UI handler.
class ImportDataHandler : public OptionsPageUIHandler,
- public ImporterHost::Observer {
+ public ImporterHost::Observer,
+ public ImporterList::Observer {
public:
ImportDataHandler();
virtual ~ImportDataHandler();
@@ -25,13 +27,16 @@ class ImportDataHandler : public OptionsPageUIHandler,
private:
void ImportData(const ListValue* args);
- // ImporterHost observer implementation.
+ // ImporterHost::Observer implementation.
virtual void ImportStarted();
virtual void ImportItemStarted(importer::ImportItem item);
virtual void ImportItemEnded(importer::ImportItem item);
virtual void ImportEnded();
- scoped_ptr<ImporterList> importer_list_;
+ // ImporterList::Observer implementation.
+ virtual void SourceProfilesLoaded();
+
+ scoped_refptr<ImporterList> importer_list_;
// If non-null it means importing is in progress. ImporterHost takes care
// of deleting itself when done import.
diff --git a/chrome/browser/dom_ui/options/options_managed_banner_handler.cc b/chrome/browser/dom_ui/options/options_managed_banner_handler.cc
index 7be5bf9..5f01e4f 100644
--- a/chrome/browser/dom_ui/options/options_managed_banner_handler.cc
+++ b/chrome/browser/dom_ui/options/options_managed_banner_handler.cc
@@ -7,7 +7,7 @@
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/dom_ui/dom_ui.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
OptionsManagedBannerHandler::OptionsManagedBannerHandler(
DOMUI* dom_ui, const string16& page_name, OptionsPage page)
diff --git a/chrome/browser/dom_ui/options/options_managed_banner_handler.h b/chrome/browser/dom_ui/options/options_managed_banner_handler.h
index 6c63484..9cfc5e9 100644
--- a/chrome/browser/dom_ui/options/options_managed_banner_handler.h
+++ b/chrome/browser/dom_ui/options/options_managed_banner_handler.h
@@ -8,7 +8,7 @@
#include "base/string16.h"
#include "chrome/browser/policy/managed_prefs_banner_base.h"
-#include "chrome/browser/options_window.h"
+#include "chrome/browser/ui/options/options_window.h"
class DOMUI;
diff --git a/chrome/browser/dom_ui/options/options_ui.cc b/chrome/browser/dom_ui/options/options_ui.cc
index 2b250e7..867b4fb 100644
--- a/chrome/browser/dom_ui/options/options_ui.cc
+++ b/chrome/browser/dom_ui/options/options_ui.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/dom_ui/options/options_ui.h"
#include <algorithm>
+#include <vector>
#include "app/resource_bundle.h"
#include "base/callback.h"
@@ -29,19 +30,19 @@
#include "chrome/browser/dom_ui/options/core_options_handler.h"
#include "chrome/browser/dom_ui/options/font_settings_handler.h"
#include "chrome/browser/dom_ui/options/import_data_handler.h"
-#include "chrome/browser/dom_ui/options/passwords_exceptions_handler.h"
+#include "chrome/browser/dom_ui/options/password_manager_handler.h"
#include "chrome/browser/dom_ui/options/personal_options_handler.h"
#include "chrome/browser/dom_ui/options/search_engine_manager_handler.h"
+#include "chrome/browser/dom_ui/options/startup_page_manager_handler.h"
#include "chrome/browser/dom_ui/options/stop_syncing_handler.h"
#include "chrome/browser/dom_ui/options/sync_options_handler.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
#include "chrome/common/jstemplate_builder.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/time_format.h"
#include "chrome/common/url_constants.h"
@@ -121,6 +122,10 @@ OptionsPageUIHandler::OptionsPageUIHandler() {
OptionsPageUIHandler::~OptionsPageUIHandler() {
}
+bool OptionsPageUIHandler::IsEnabled() {
+ return true;
+}
+
void OptionsPageUIHandler::UserMetricsRecordAction(
const UserMetricsAction& action) {
UserMetrics::RecordAction(action, dom_ui_->GetProfile());
@@ -150,9 +155,10 @@ OptionsUI::OptionsUI(TabContents* contents) : DOMUI(contents) {
AddOptionsPageUIHandler(localized_strings, new ContentSettingsHandler());
AddOptionsPageUIHandler(localized_strings, new CookiesViewHandler());
AddOptionsPageUIHandler(localized_strings, new FontSettingsHandler());
- AddOptionsPageUIHandler(localized_strings, new PasswordsExceptionsHandler());
+ AddOptionsPageUIHandler(localized_strings, new PasswordManagerHandler());
AddOptionsPageUIHandler(localized_strings, new PersonalOptionsHandler());
AddOptionsPageUIHandler(localized_strings, new SearchEngineManagerHandler());
+ AddOptionsPageUIHandler(localized_strings, new StartupPageManagerHandler());
AddOptionsPageUIHandler(localized_strings, new ImportDataHandler());
AddOptionsPageUIHandler(localized_strings, new StopSyncingHandler());
AddOptionsPageUIHandler(localized_strings, new SyncOptionsHandler());
@@ -192,7 +198,7 @@ OptionsUI::OptionsUI(TabContents* contents) : DOMUI(contents) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(html_source)));
@@ -201,7 +207,7 @@ OptionsUI::OptionsUI(TabContents* contents) : DOMUI(contents) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(theme)));
}
diff --git a/chrome/browser/dom_ui/options/options_ui.h b/chrome/browser/dom_ui/options/options_ui.h
index fbc55e6..ad1007d 100644
--- a/chrome/browser/dom_ui/options/options_ui.h
+++ b/chrome/browser/dom_ui/options/options_ui.h
@@ -47,7 +47,7 @@ class OptionsPageUIHandler : public DOMMessageHandler,
virtual ~OptionsPageUIHandler();
// Is this handler enabled?
- virtual bool IsEnabled() { return true; }
+ virtual bool IsEnabled();
// Collects localized strings for options page.
virtual void GetLocalizedValues(DictionaryValue* localized_strings) = 0;
@@ -81,8 +81,8 @@ class OptionsUI : public DOMUI {
virtual ~OptionsUI();
static RefCountedMemory* GetFaviconResourceBytes();
- void RenderViewCreated(RenderViewHost* render_view_host);
- void DidBecomeActiveForReusedRenderView();
+ virtual void RenderViewCreated(RenderViewHost* render_view_host);
+ virtual void DidBecomeActiveForReusedRenderView();
void InitializeHandlers();
diff --git a/chrome/browser/dom_ui/options/password_manager_handler.cc b/chrome/browser/dom_ui/options/password_manager_handler.cc
new file mode 100644
index 0000000..6076bc7
--- /dev/null
+++ b/chrome/browser/dom_ui/options/password_manager_handler.cc
@@ -0,0 +1,190 @@
+// 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.
+
+#include "chrome/browser/dom_ui/options/password_manager_handler.h"
+
+#include "app/l10n_util.h"
+#include "base/callback.h"
+#include "base/stl_util-inl.h"
+#include "base/string_number_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "net/base/net_util.h"
+
+PasswordManagerHandler::PasswordManagerHandler()
+ : ALLOW_THIS_IN_INITIALIZER_LIST(populater_(this)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(exception_populater_(this)) {
+}
+
+PasswordManagerHandler::~PasswordManagerHandler() {
+}
+
+void PasswordManagerHandler::GetLocalizedValues(
+ DictionaryValue* localized_strings) {
+ DCHECK(localized_strings);
+
+ localized_strings->SetString("passwordsTitle",
+ l10n_util::GetStringUTF16(IDS_PASSWORDS_EXCEPTIONS_WINDOW_TITLE));
+ localized_strings->SetString("savedPasswordsTitle",
+ l10n_util::GetStringUTF16(IDS_PASSWORDS_SHOW_PASSWORDS_TAB_TITLE));
+ localized_strings->SetString("passwordExceptionsTitle",
+ l10n_util::GetStringUTF16(IDS_PASSWORDS_EXCEPTIONS_TAB_TITLE));
+ localized_strings->SetString("passwordsSiteColumn",
+ l10n_util::GetStringUTF16(IDS_PASSWORDS_PAGE_VIEW_SITE_COLUMN));
+ localized_strings->SetString("passwordsUsernameColumn",
+ l10n_util::GetStringUTF16(IDS_PASSWORDS_PAGE_VIEW_USERNAME_COLUMN));
+ localized_strings->SetString("passwordsRemoveButton",
+ l10n_util::GetStringUTF16(IDS_PASSWORDS_PAGE_VIEW_REMOVE_BUTTON));
+ localized_strings->SetString("passwordsRemoveAllButton",
+ l10n_util::GetStringUTF16(IDS_PASSWORDS_PAGE_VIEW_REMOVE_ALL_BUTTON));
+ localized_strings->SetString("passwordsShowButton",
+ l10n_util::GetStringUTF16(IDS_PASSWORDS_PAGE_VIEW_SHOW_BUTTON));
+ localized_strings->SetString("passwordsHideButton",
+ l10n_util::GetStringUTF16(IDS_PASSWORDS_PAGE_VIEW_HIDE_BUTTON));
+ localized_strings->SetString("passwordsRemoveAllTitle",
+ l10n_util::GetStringUTF16(
+ IDS_PASSWORDS_PAGE_VIEW_CAPTION_DELETE_ALL_PASSWORDS));
+ localized_strings->SetString("passwordsRemoveAllWarning",
+ l10n_util::GetStringUTF16(
+ IDS_PASSWORDS_PAGE_VIEW_TEXT_DELETE_ALL_PASSWORDS));
+}
+
+void PasswordManagerHandler::Initialize() {
+ // We should not cache dom_ui_->GetProfile(). See crosbug.com/6304.
+}
+
+void PasswordManagerHandler::RegisterMessages() {
+ DCHECK(dom_ui_);
+
+ dom_ui_->RegisterMessageCallback("updatePasswordLists",
+ NewCallback(this, &PasswordManagerHandler::UpdatePasswordLists));
+ dom_ui_->RegisterMessageCallback("removeSavedPassword",
+ NewCallback(this, &PasswordManagerHandler::RemoveSavedPassword));
+ dom_ui_->RegisterMessageCallback("removePasswordException",
+ NewCallback(this, &PasswordManagerHandler::RemovePasswordException));
+ dom_ui_->RegisterMessageCallback("removeAllSavedPasswords",
+ NewCallback(this, &PasswordManagerHandler::RemoveAllSavedPasswords));
+ dom_ui_->RegisterMessageCallback("removeAllPasswordExceptions", NewCallback(
+ this, &PasswordManagerHandler::RemoveAllPasswordExceptions));
+}
+
+PasswordStore* PasswordManagerHandler::GetPasswordStore() {
+ return dom_ui_->GetProfile()->GetPasswordStore(Profile::EXPLICIT_ACCESS);
+}
+
+void PasswordManagerHandler::UpdatePasswordLists(const ListValue* args) {
+ languages_ =
+ dom_ui_->GetProfile()->GetPrefs()->GetString(prefs::kAcceptLanguages);
+ populater_.Populate();
+ exception_populater_.Populate();
+}
+
+void PasswordManagerHandler::RemoveSavedPassword(const ListValue* args) {
+ std::string string_value = WideToUTF8(ExtractStringValue(args));
+ int index;
+ base::StringToInt(string_value, &index);
+
+ GetPasswordStore()->RemoveLogin(*password_list_[index]);
+ delete password_list_[index];
+ password_list_.erase(password_list_.begin() + index);
+ SetPasswordList();
+}
+
+void PasswordManagerHandler::RemovePasswordException(
+ const ListValue* args) {
+ std::string string_value = WideToUTF8(ExtractStringValue(args));
+ int index;
+ base::StringToInt(string_value, &index);
+
+ GetPasswordStore()->RemoveLogin(*password_exception_list_[index]);
+ delete password_exception_list_[index];
+ password_exception_list_.erase(password_exception_list_.begin() + index);
+ SetPasswordExceptionList();
+}
+
+void PasswordManagerHandler::RemoveAllSavedPasswords(
+ const ListValue* args) {
+ PasswordStore* store = GetPasswordStore();
+ for (size_t i = 0; i < password_list_.size(); ++i)
+ store->RemoveLogin(*password_list_[i]);
+ STLDeleteElements(&password_list_);
+ SetPasswordList();
+}
+
+void PasswordManagerHandler::RemoveAllPasswordExceptions(
+ const ListValue* args) {
+ PasswordStore* store = GetPasswordStore();
+ for (size_t i = 0; i < password_exception_list_.size(); ++i)
+ store->RemoveLogin(*password_exception_list_[i]);
+ STLDeleteElements(&password_exception_list_);
+ SetPasswordExceptionList();
+}
+
+void PasswordManagerHandler::SetPasswordList() {
+ ListValue entries;
+ for (size_t i = 0; i < password_list_.size(); ++i) {
+ ListValue* entry = new ListValue();
+ entry->Append(new StringValue(net::FormatUrl(password_list_[i]->origin,
+ languages_)));
+ entry->Append(new StringValue(password_list_[i]->username_value));
+ entry->Append(new StringValue(password_list_[i]->password_value));
+ entries.Append(entry);
+ }
+
+ dom_ui_->CallJavascriptFunction(
+ L"PasswordManager.setSavedPasswordsList", entries);
+}
+
+void PasswordManagerHandler::SetPasswordExceptionList() {
+ ListValue entries;
+ for (size_t i = 0; i < password_exception_list_.size(); ++i) {
+ entries.Append(new StringValue(
+ net::FormatUrl(password_exception_list_[i]->origin, languages_)));
+ }
+
+ dom_ui_->CallJavascriptFunction(
+ L"PasswordManager.setPasswordExceptionsList", entries);
+}
+
+void PasswordManagerHandler::PasswordListPopulater::Populate() {
+ DCHECK(!pending_login_query_);
+ PasswordStore* store = page_->GetPasswordStore();
+ if (store != NULL)
+ pending_login_query_ = store->GetAutofillableLogins(this);
+ else
+ LOG(ERROR) << "No password store! Cannot display passwords.";
+}
+
+void PasswordManagerHandler::PasswordListPopulater::
+ OnPasswordStoreRequestDone(int handle,
+ const std::vector<webkit_glue::PasswordForm*>& result) {
+ DCHECK_EQ(pending_login_query_, handle);
+ pending_login_query_ = 0;
+ page_->password_list_ = result;
+ page_->SetPasswordList();
+}
+
+void PasswordManagerHandler::PasswordExceptionListPopulater::Populate() {
+ DCHECK(!pending_login_query_);
+ PasswordStore* store = page_->GetPasswordStore();
+ if (store != NULL)
+ pending_login_query_ = store->GetBlacklistLogins(this);
+ else
+ LOG(ERROR) << "No password store! Cannot display exceptions.";
+}
+
+void PasswordManagerHandler::PasswordExceptionListPopulater::
+ OnPasswordStoreRequestDone(int handle,
+ const std::vector<webkit_glue::PasswordForm*>& result) {
+ DCHECK_EQ(pending_login_query_, handle);
+ pending_login_query_ = 0;
+ page_->password_exception_list_ = result;
+ page_->SetPasswordExceptionList();
+}
diff --git a/chrome/browser/dom_ui/options/password_manager_handler.h b/chrome/browser/dom_ui/options/password_manager_handler.h
new file mode 100644
index 0000000..5cd3080
--- /dev/null
+++ b/chrome/browser/dom_ui/options/password_manager_handler.h
@@ -0,0 +1,119 @@
+// 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.
+
+#ifndef CHROME_BROWSER_DOM_UI_OPTIONS_PASSWORD_MANAGER_HANDLER_H_
+#define CHROME_BROWSER_DOM_UI_OPTIONS_PASSWORD_MANAGER_HANDLER_H_
+
+#include <string>
+#include <vector>
+
+#include "chrome/browser/dom_ui/options/options_ui.h"
+#include "chrome/browser/password_manager/password_store.h"
+
+class PasswordManagerHandler : public OptionsPageUIHandler {
+ public:
+ PasswordManagerHandler();
+ virtual ~PasswordManagerHandler();
+
+ // OptionsUIHandler implementation.
+ virtual void GetLocalizedValues(DictionaryValue* localized_strings);
+
+ virtual void Initialize();
+
+ virtual void RegisterMessages();
+
+ private:
+ // The password store associated with the currently active profile.
+ PasswordStore* GetPasswordStore();
+
+ // Called when the JS PasswordManager object is initialized.
+ void UpdatePasswordLists(const ListValue* args);
+
+ // Remove an entry.
+ // @param value the entry index to be removed.
+ void RemoveSavedPassword(const ListValue* args);
+
+ // Remove an password exception.
+ // @param value the entry index to be removed.
+ void RemovePasswordException(const ListValue* args);
+
+ // Remove all saved passwords
+ void RemoveAllSavedPasswords(const ListValue* args);
+
+ // Remove All password exceptions
+ void RemoveAllPasswordExceptions(const ListValue* args);
+
+ // Get password value for the selected entry.
+ // @param value the selected entry index.
+ void ShowSelectedPassword(const ListValue* args);
+
+ // Sets the password and exception list contents to the given data.
+ // We take ownership of the PasswordForms in the vector.
+ void SetPasswordList();
+ void SetPasswordExceptionList();
+
+ // A short class to mediate requests to the password store.
+ class ListPopulater : public PasswordStoreConsumer {
+ public:
+ explicit ListPopulater(PasswordManagerHandler* page)
+ : page_(page),
+ pending_login_query_(0) {
+ }
+
+ // Send a query to the password store to populate a list.
+ virtual void Populate() = 0;
+
+ // Send the password store's reply back to the handler.
+ virtual void OnPasswordStoreRequestDone(
+ int handle, const std::vector<webkit_glue::PasswordForm*>& result) = 0;
+
+ protected:
+ PasswordManagerHandler* page_;
+ int pending_login_query_;
+ };
+
+ // A short class to mediate requests to the password store for passwordlist.
+ class PasswordListPopulater : public ListPopulater {
+ public:
+ explicit PasswordListPopulater(PasswordManagerHandler* page)
+ : ListPopulater(page) {
+ }
+
+ // Send a query to the password store to populate a password list.
+ virtual void Populate();
+
+ // Send the password store's reply back to the handler.
+ virtual void OnPasswordStoreRequestDone(
+ int handle, const std::vector<webkit_glue::PasswordForm*>& result);
+ };
+
+ // A short class to mediate requests to the password store for exceptions.
+ class PasswordExceptionListPopulater : public ListPopulater {
+ public:
+ explicit PasswordExceptionListPopulater(
+ PasswordManagerHandler* page) : ListPopulater(page) {
+ }
+
+ // Send a query to the password store to populate a passwordException list.
+ virtual void Populate();
+
+ // Send the password store's reply back to the handler.
+ virtual void OnPasswordStoreRequestDone(
+ int handle, const std::vector<webkit_glue::PasswordForm*>& result);
+ };
+
+ // Password store consumer for populating the password list and exceptions.
+ PasswordListPopulater populater_;
+ PasswordExceptionListPopulater exception_populater_;
+
+ std::vector<webkit_glue::PasswordForm*> password_list_;
+ std::vector<webkit_glue::PasswordForm*> password_exception_list_;
+
+ // User's pref
+ std::string languages_;
+
+ DISALLOW_COPY_AND_ASSIGN(PasswordManagerHandler);
+};
+
+#endif // CHROME_BROWSER_DOM_UI_OPTIONS_PASSWORD_MANAGER_HANDLER_H_
diff --git a/chrome/browser/dom_ui/options/passwords_exceptions_handler.cc b/chrome/browser/dom_ui/options/passwords_exceptions_handler.cc
deleted file mode 100644
index 39f77ca..0000000
--- a/chrome/browser/dom_ui/options/passwords_exceptions_handler.cc
+++ /dev/null
@@ -1,201 +0,0 @@
-// 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.
-
-#include "chrome/browser/dom_ui/options/passwords_exceptions_handler.h"
-
-#include "app/l10n_util.h"
-#include "base/callback.h"
-#include "base/stl_util-inl.h"
-#include "base/string_number_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "base/values.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/url_constants.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-#include "net/base/net_util.h"
-
-PasswordsExceptionsHandler::PasswordsExceptionsHandler()
- : ALLOW_THIS_IN_INITIALIZER_LIST(populater_(this)),
- ALLOW_THIS_IN_INITIALIZER_LIST(exception_populater_(this)) {
-}
-
-PasswordsExceptionsHandler::~PasswordsExceptionsHandler() {
-}
-
-void PasswordsExceptionsHandler::GetLocalizedValues(
- DictionaryValue* localized_strings) {
- DCHECK(localized_strings);
-
- localized_strings->SetString("savedPasswordsExceptionsTitle",
- l10n_util::GetStringUTF16(IDS_PASSWORDS_EXCEPTIONS_WINDOW_TITLE));
- localized_strings->SetString("passwordsTabTitle",
- l10n_util::GetStringUTF16(IDS_PASSWORDS_SHOW_PASSWORDS_TAB_TITLE));
- localized_strings->SetString("passwordExceptionsTabTitle",
- l10n_util::GetStringUTF16(IDS_PASSWORDS_EXCEPTIONS_TAB_TITLE));
- localized_strings->SetString("passwordsSiteColumn",
- l10n_util::GetStringUTF16(IDS_PASSWORDS_PAGE_VIEW_SITE_COLUMN));
- localized_strings->SetString("passwordsUsernameColumn",
- l10n_util::GetStringUTF16(IDS_PASSWORDS_PAGE_VIEW_USERNAME_COLUMN));
- localized_strings->SetString("passwordsRemoveButton",
- l10n_util::GetStringUTF16(IDS_PASSWORDS_PAGE_VIEW_REMOVE_BUTTON));
- localized_strings->SetString("passwordsRemoveAllButton",
- l10n_util::GetStringUTF16(IDS_PASSWORDS_PAGE_VIEW_REMOVE_ALL_BUTTON));
- localized_strings->SetString("passwordsShowButton",
- l10n_util::GetStringUTF16(IDS_PASSWORDS_PAGE_VIEW_SHOW_BUTTON));
- localized_strings->SetString("passwordsHideButton",
- l10n_util::GetStringUTF16(IDS_PASSWORDS_PAGE_VIEW_HIDE_BUTTON));
- localized_strings->SetString("passwordsRemoveAllTitle",
- l10n_util::GetStringUTF16(
- IDS_PASSWORDS_PAGE_VIEW_CAPTION_DELETE_ALL_PASSWORDS));
- localized_strings->SetString("passwordsRemoveAllWarning",
- l10n_util::GetStringUTF16(
- IDS_PASSWORDS_PAGE_VIEW_TEXT_DELETE_ALL_PASSWORDS));
-}
-
-void PasswordsExceptionsHandler::Initialize() {
- // We should not cache dom_ui_->GetProfile(). See crosbug.com/6304.
-}
-
-void PasswordsExceptionsHandler::RegisterMessages() {
- DCHECK(dom_ui_);
-
- dom_ui_->RegisterMessageCallback("loadLists",
- NewCallback(this, &PasswordsExceptionsHandler::LoadLists));
- dom_ui_->RegisterMessageCallback("removeSavedPassword",
- NewCallback(this, &PasswordsExceptionsHandler::RemoveSavedPassword));
- dom_ui_->RegisterMessageCallback("removePasswordException",
- NewCallback(this, &PasswordsExceptionsHandler::RemovePasswordException));
- dom_ui_->RegisterMessageCallback("removeAllSavedPasswords",
- NewCallback(this, &PasswordsExceptionsHandler::RemoveAllSavedPasswords));
- dom_ui_->RegisterMessageCallback("removeAllPasswordExceptions", NewCallback(
- this, &PasswordsExceptionsHandler::RemoveAllPasswordExceptions));
- dom_ui_->RegisterMessageCallback("showSelectedPassword",
- NewCallback(this, &PasswordsExceptionsHandler::ShowSelectedPassword));
-}
-
-PasswordStore* PasswordsExceptionsHandler::GetPasswordStore() {
- return dom_ui_->GetProfile()->GetPasswordStore(Profile::EXPLICIT_ACCESS);
-}
-
-void PasswordsExceptionsHandler::LoadLists(const ListValue* args) {
- languages_ =
- dom_ui_->GetProfile()->GetPrefs()->GetString(prefs::kAcceptLanguages);
- populater_.Populate();
- exception_populater_.Populate();
-}
-
-void PasswordsExceptionsHandler::RemoveSavedPassword(const ListValue* args) {
- std::string string_value = WideToUTF8(ExtractStringValue(args));
- int index;
- base::StringToInt(string_value, &index);
-
- GetPasswordStore()->RemoveLogin(*password_list_[index]);
- delete password_list_[index];
- password_list_.erase(password_list_.begin() + index);
- SetPasswordList();
-}
-
-void PasswordsExceptionsHandler::RemovePasswordException(
- const ListValue* args) {
- std::string string_value = WideToUTF8(ExtractStringValue(args));
- int index;
- base::StringToInt(string_value, &index);
-
- GetPasswordStore()->RemoveLogin(*password_exception_list_[index]);
- delete password_exception_list_[index];
- password_exception_list_.erase(password_exception_list_.begin() + index);
- SetPasswordExceptionList();
-}
-
-void PasswordsExceptionsHandler::RemoveAllSavedPasswords(
- const ListValue* args) {
- PasswordStore* store = GetPasswordStore();
- for (size_t i = 0; i < password_list_.size(); ++i)
- store->RemoveLogin(*password_list_[i]);
- STLDeleteElements(&password_list_);
- SetPasswordList();
-}
-
-void PasswordsExceptionsHandler::RemoveAllPasswordExceptions(
- const ListValue* args) {
- PasswordStore* store = GetPasswordStore();
- for (size_t i = 0; i < password_exception_list_.size(); ++i)
- store->RemoveLogin(*password_exception_list_[i]);
- STLDeleteElements(&password_exception_list_);
- SetPasswordExceptionList();
-}
-
-void PasswordsExceptionsHandler::ShowSelectedPassword(const ListValue* args) {
- std::string string_value = WideToUTF8(ExtractStringValue(args));
- int index;
- base::StringToInt(string_value, &index);
-
- std::string pass = UTF16ToUTF8(password_list_[index]->password_value);
- scoped_ptr<Value> password_string(Value::CreateStringValue(pass));
- dom_ui_->CallJavascriptFunction(
- L"PasswordsExceptions.selectedPasswordCallback", *password_string.get());
-}
-
-void PasswordsExceptionsHandler::SetPasswordList() {
- ListValue entries;
- for (size_t i = 0; i < password_list_.size(); ++i) {
- ListValue* entry = new ListValue();
- entry->Append(new StringValue(net::FormatUrl(password_list_[i]->origin,
- languages_)));
- entry->Append(new StringValue(password_list_[i]->username_value));
- entries.Append(entry);
- }
-
- dom_ui_->CallJavascriptFunction(
- L"PasswordsExceptions.setSavedPasswordsList", entries);
-}
-
-void PasswordsExceptionsHandler::SetPasswordExceptionList() {
- ListValue entries;
- for (size_t i = 0; i < password_exception_list_.size(); ++i) {
- entries.Append(new StringValue(
- net::FormatUrl(password_exception_list_[i]->origin, languages_)));
- }
-
- dom_ui_->CallJavascriptFunction(
- L"PasswordsExceptions.setPasswordExceptionsList", entries);
-}
-
-void PasswordsExceptionsHandler::PasswordListPopulater::Populate() {
- DCHECK(!pending_login_query_);
- PasswordStore* store = page_->GetPasswordStore();
- if (store != NULL)
- pending_login_query_ = store->GetAutofillableLogins(this);
- else
- LOG(ERROR) << "No password store! Cannot display passwords.";
-}
-
-void PasswordsExceptionsHandler::PasswordListPopulater::
- OnPasswordStoreRequestDone(int handle,
- const std::vector<webkit_glue::PasswordForm*>& result) {
- DCHECK_EQ(pending_login_query_, handle);
- pending_login_query_ = 0;
- page_->password_list_ = result;
- page_->SetPasswordList();
-}
-
-void PasswordsExceptionsHandler::PasswordExceptionListPopulater::Populate() {
- DCHECK(!pending_login_query_);
- PasswordStore* store = page_->GetPasswordStore();
- if (store != NULL)
- pending_login_query_ = store->GetBlacklistLogins(this);
- else
- LOG(ERROR) << "No password store! Cannot display exceptions.";
-}
-
-void PasswordsExceptionsHandler::PasswordExceptionListPopulater::
- OnPasswordStoreRequestDone(int handle,
- const std::vector<webkit_glue::PasswordForm*>& result) {
- DCHECK_EQ(pending_login_query_, handle);
- pending_login_query_ = 0;
- page_->password_exception_list_ = result;
- page_->SetPasswordExceptionList();
-}
diff --git a/chrome/browser/dom_ui/options/passwords_exceptions_handler.h b/chrome/browser/dom_ui/options/passwords_exceptions_handler.h
deleted file mode 100644
index a63ab77..0000000
--- a/chrome/browser/dom_ui/options/passwords_exceptions_handler.h
+++ /dev/null
@@ -1,117 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_DOM_UI_OPTIONS_PASSWORDS_EXCEPTIONS_HANDLER_H_
-#define CHROME_BROWSER_DOM_UI_OPTIONS_PASSWORDS_EXCEPTIONS_HANDLER_H_
-
-#include "chrome/browser/dom_ui/options/options_ui.h"
-#include "chrome/browser/password_manager/password_store.h"
-#include "chrome/browser/profile.h"
-
-class PasswordsExceptionsHandler : public OptionsPageUIHandler {
- public:
- PasswordsExceptionsHandler();
- virtual ~PasswordsExceptionsHandler();
-
- // OptionsUIHandler implementation.
- virtual void GetLocalizedValues(DictionaryValue* localized_strings);
-
- virtual void Initialize();
-
- virtual void RegisterMessages();
-
- private:
- // The password store associated with the currently active profile.
- PasswordStore* GetPasswordStore();
-
- // Fired when user clicks 'show saved passwords' button in personal page.
- void LoadLists(const ListValue* args);
-
- // Remove an entry.
- // @param value the entry index to be removed.
- void RemoveSavedPassword(const ListValue* args);
-
- // Remove an password exception.
- // @param value the entry index to be removed.
- void RemovePasswordException(const ListValue* args);
-
- // Remove all saved passwords
- void RemoveAllSavedPasswords(const ListValue* args);
-
- // Remove All password exceptions
- void RemoveAllPasswordExceptions(const ListValue* args);
-
- // Get password value for the selected entry.
- // @param value the selected entry index.
- void ShowSelectedPassword(const ListValue* args);
-
- // Sets the password and exception list contents to the given data.
- // We take ownership of the PasswordForms in the vector.
- void SetPasswordList();
- void SetPasswordExceptionList();
-
- // A short class to mediate requests to the password store.
- class ListPopulater : public PasswordStoreConsumer {
- public:
- explicit ListPopulater(PasswordsExceptionsHandler* page)
- : page_(page),
- pending_login_query_(0) {
- }
-
- // Send a query to the password store to populate a list.
- virtual void Populate() = 0;
-
- // Send the password store's reply back to the handler.
- virtual void OnPasswordStoreRequestDone(
- int handle, const std::vector<webkit_glue::PasswordForm*>& result) = 0;
-
- protected:
- PasswordsExceptionsHandler* page_;
- int pending_login_query_;
- };
-
- // A short class to mediate requests to the password store for passwordlist.
- class PasswordListPopulater : public ListPopulater {
- public:
- explicit PasswordListPopulater(PasswordsExceptionsHandler* page)
- : ListPopulater(page) {
- }
-
- // Send a query to the password store to populate a password list.
- virtual void Populate();
-
- // Send the password store's reply back to the handler.
- virtual void OnPasswordStoreRequestDone(
- int handle, const std::vector<webkit_glue::PasswordForm*>& result);
- };
-
- // A short class to mediate requests to the password store for exceptions.
- class PasswordExceptionListPopulater : public ListPopulater {
- public:
- explicit PasswordExceptionListPopulater(
- PasswordsExceptionsHandler* page) : ListPopulater(page) {
- }
-
- // Send a query to the password store to populate a passwordException list.
- virtual void Populate();
-
- // Send the password store's reply back to the handler.
- virtual void OnPasswordStoreRequestDone(
- int handle, const std::vector<webkit_glue::PasswordForm*>& result);
- };
-
- // Password store consumer for populating the password list and exceptions.
- PasswordListPopulater populater_;
- PasswordExceptionListPopulater exception_populater_;
-
- std::vector<webkit_glue::PasswordForm*> password_list_;
- std::vector<webkit_glue::PasswordForm*> password_exception_list_;
-
- // User's pref
- std::string languages_;
-
- DISALLOW_COPY_AND_ASSIGN(PasswordsExceptionsHandler);
-};
-
-#endif // CHROME_BROWSER_DOM_UI_OPTIONS_PASSWORDS_EXCEPTIONS_HANDLER_H_
diff --git a/chrome/browser/dom_ui/options/personal_options_handler.cc b/chrome/browser/dom_ui/options/personal_options_handler.cc
index 8ef7524..bc14c1f 100644
--- a/chrome/browser/dom_ui/options/personal_options_handler.cc
+++ b/chrome/browser/dom_ui/options/personal_options_handler.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/dom_ui/options/personal_options_handler.h"
+#include <string>
+
#include "app/l10n_util.h"
#include "base/basictypes.h"
#include "base/callback.h"
@@ -13,21 +15,15 @@
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_process.h"
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/login/user_manager.h"
-#endif
+#include "chrome/browser/dom_ui/options/dom_options_util.h"
#include "chrome/browser/dom_ui/options/options_managed_banner_handler.h"
-#if defined(TOOLKIT_GTK)
-#include "chrome/browser/gtk/gtk_theme_provider.h"
-#endif // defined(TOOLKIT_GTK)
-#include "chrome/browser/options_page_base.h"
-#include "chrome/browser/options_window.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/sync_ui_util.h"
#include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/ui/options/options_page_base.h"
+#include "chrome/browser/ui/options/options_window.h"
#include "chrome/common/net/gaia/google_service_auth_error.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/chrome_paths.h"
@@ -37,6 +33,13 @@
#include "grit/locale_settings.h"
#include "grit/theme_resources.h"
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/login/user_manager.h"
+#endif // defined(OS_CHROMEOS)
+#if defined(TOOLKIT_GTK)
+#include "chrome/browser/gtk/gtk_theme_provider.h"
+#endif // defined(TOOLKIT_GTK)
+
PersonalOptionsHandler::PersonalOptionsHandler() {
}
@@ -52,12 +55,14 @@ void PersonalOptionsHandler::GetLocalizedValues(
DCHECK(localized_strings);
localized_strings->SetString("syncSection",
- l10n_util::GetStringUTF16(IDS_SYNC_OPTIONS_GROUP_NAME));
+ dom_options_util::StripColon(
+ l10n_util::GetStringUTF16(IDS_SYNC_OPTIONS_GROUP_NAME)));
localized_strings->SetString("privacyDashboardLink",
l10n_util::GetStringUTF16(IDS_SYNC_PRIVACY_DASHBOARD_LINK_LABEL));
localized_strings->SetString("passwords",
- l10n_util::GetStringUTF16(IDS_OPTIONS_PASSWORDS_GROUP_NAME));
+ dom_options_util::StripColon(
+ l10n_util::GetStringUTF16(IDS_OPTIONS_PASSWORDS_GROUP_NAME)));
localized_strings->SetString("passwordsAskToSave",
l10n_util::GetStringUTF16(IDS_OPTIONS_PASSWORDS_ASKTOSAVE));
localized_strings->SetString("passwordsNeverSave",
@@ -66,12 +71,16 @@ void PersonalOptionsHandler::GetLocalizedValues(
l10n_util::GetStringUTF16(IDS_OPTIONS_PASSWORDS_MANAGE_PASSWORDS));
localized_strings->SetString("autofill",
- l10n_util::GetStringUTF16(IDS_AUTOFILL_SETTING_WINDOWS_GROUP_NAME));
- localized_strings->SetString("autofillOptions",
- l10n_util::GetStringUTF16(IDS_AUTOFILL_OPTIONS));
+ dom_options_util::StripColon(
+ l10n_util::GetStringUTF16(IDS_AUTOFILL_SETTING_WINDOWS_GROUP_NAME)));
+ localized_strings->SetString("autoFillEnabled",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_AUTOFILL_ENABLE));
+ localized_strings->SetString("manageAutofillSettings",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_MANAGE_AUTOFILL_SETTINGS));
localized_strings->SetString("browsingData",
- l10n_util::GetStringUTF16(IDS_OPTIONS_BROWSING_DATA_GROUP_NAME));
+ dom_options_util::StripColon(
+ l10n_util::GetStringUTF16(IDS_OPTIONS_BROWSING_DATA_GROUP_NAME)));
localized_strings->SetString("importData",
l10n_util::GetStringUTF16(IDS_OPTIONS_IMPORT_DATA_BUTTON));
@@ -82,7 +91,8 @@ void PersonalOptionsHandler::GetLocalizedValues(
#if defined(TOOLKIT_GTK)
localized_strings->SetString("appearance",
- l10n_util::GetStringUTF16(IDS_APPEARANCE_GROUP_NAME));
+ dom_options_util::StripColon(
+ l10n_util::GetStringUTF16(IDS_APPEARANCE_GROUP_NAME)));
localized_strings->SetString("themesGTKButton",
l10n_util::GetStringUTF16(IDS_THEMES_GTK_BUTTON));
localized_strings->SetString("themesSetClassic",
@@ -93,10 +103,27 @@ void PersonalOptionsHandler::GetLocalizedValues(
l10n_util::GetStringUTF16(IDS_HIDE_WINDOW_DECORATIONS_RADIO));
#else
localized_strings->SetString("themes",
- l10n_util::GetStringUTF16(IDS_THEMES_GROUP_NAME));
+ dom_options_util::StripColon(
+ l10n_util::GetStringUTF16(IDS_THEMES_GROUP_NAME)));
localized_strings->SetString("themesReset",
l10n_util::GetStringUTF16(IDS_THEMES_RESET_BUTTON));
#endif
+
+ // Sync select control.
+ ListValue* sync_select_list = new ListValue;
+ ListValue* datatypes = new ListValue;
+ datatypes->Append(Value::CreateBooleanValue(false));
+ datatypes->Append(
+ Value::CreateStringValue(
+ l10n_util::GetStringUTF8(IDS_SYNC_OPTIONS_SELECT_DATATYPES)));
+ sync_select_list->Append(datatypes);
+ ListValue* everything = new ListValue;
+ everything->Append(Value::CreateBooleanValue(true));
+ everything->Append(
+ Value::CreateStringValue(
+ l10n_util::GetStringUTF8(IDS_SYNC_OPTIONS_SELECT_EVERYTHING)));
+ sync_select_list->Append(everything);
+ localized_strings->Set("syncSelectList", sync_select_list);
}
void PersonalOptionsHandler::RegisterMessages() {
@@ -178,21 +205,6 @@ void PersonalOptionsHandler::OnStateChanged() {
dom_ui_->CallJavascriptFunction(L"PersonalOptions.setStartStopButtonLabel",
*label);
- visible.reset(Value::CreateBooleanValue(
- sync_setup_completed && !status_has_error));
- dom_ui_->CallJavascriptFunction(L"PersonalOptions.setCustomizeButtonVisible",
- *visible);
-
- enabled.reset(Value::CreateBooleanValue(!managed));
- dom_ui_->CallJavascriptFunction(L"PersonalOptions.setCustomizeButtonEnabled",
- *enabled);
-
- string16 customize_button_label =
- l10n_util::GetStringUTF16(IDS_SYNC_CUSTOMIZE_BUTTON_LABEL);
- label.reset(Value::CreateStringValue(customize_button_label));
- dom_ui_->CallJavascriptFunction(L"PersonalOptions.setCustomizeButtonLabel",
- *label);
-
#if !defined(OS_CHROMEOS)
label.reset(Value::CreateStringValue(link_label));
dom_ui_->CallJavascriptFunction(L"PersonalOptions.setSyncActionLinkLabel",
diff --git a/chrome/browser/dom_ui/options/search_engine_manager_handler.cc b/chrome/browser/dom_ui/options/search_engine_manager_handler.cc
index d3a407a..25ce098 100644
--- a/chrome/browser/dom_ui/options/search_engine_manager_handler.cc
+++ b/chrome/browser/dom_ui/options/search_engine_manager_handler.cc
@@ -9,7 +9,7 @@
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/keyword_editor_controller.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
@@ -56,8 +56,6 @@ void SearchEngineManagerHandler::GetLocalizedValues(
l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_EDITOR_KEYWORD_COLUMN));
localized_strings->SetString("addSearchEngineButton",
l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_EDITOR_NEW_BUTTON));
- localized_strings->SetString("removeSearchEngineButton",
- l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_EDITOR_REMOVE_BUTTON));
localized_strings->SetString("editSearchEngineButton",
l10n_util::GetStringUTF16(IDS_SEARCH_ENGINES_EDITOR_EDIT_BUTTON));
localized_strings->SetString("makeDefaultSearchEngineButton",
@@ -234,6 +232,7 @@ void SearchEngineManagerHandler::EditSearchEngine(const ListValue* args) {
engine_details.SetString("keyword", WideToUTF16Hack(edit_url->keyword()));
engine_details.SetString("url",
WideToUTF16Hack(edit_url->url()->DisplayURL()));
+ engine_details.SetBoolean("urlLocked", edit_url->prepopulate_id() > 0);
dom_ui_->CallJavascriptFunction(L"EditSearchEngineOverlay.setEditDetails",
engine_details);
}
diff --git a/chrome/browser/dom_ui/options/startup_page_manager_handler.cc b/chrome/browser/dom_ui/options/startup_page_manager_handler.cc
new file mode 100644
index 0000000..aabae28
--- /dev/null
+++ b/chrome/browser/dom_ui/options/startup_page_manager_handler.cc
@@ -0,0 +1,28 @@
+// 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.
+
+#include "chrome/browser/dom_ui/options/startup_page_manager_handler.h"
+
+#include "app/l10n_util.h"
+#include "base/values.h"
+#include "grit/generated_resources.h"
+#include "grit/locale_settings.h"
+
+StartupPageManagerHandler::StartupPageManagerHandler() {
+}
+
+StartupPageManagerHandler::~StartupPageManagerHandler() {
+}
+
+void StartupPageManagerHandler::GetLocalizedValues(
+ DictionaryValue* localized_strings) {
+ DCHECK(localized_strings);
+
+ localized_strings->SetString("startupAddButton",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_STARTUP_ADD_BUTTON));
+ localized_strings->SetString("startupPageManagerPage",
+ l10n_util::GetStringUTF16(IDS_STARTUP_PAGE_SUBPAGE_TITLE));
+ localized_strings->SetString("startupManagePages",
+ l10n_util::GetStringUTF16(IDS_OPTIONS_STARTUP_MANAGE_BUTTON));
+}
diff --git a/chrome/browser/dom_ui/options/startup_page_manager_handler.h b/chrome/browser/dom_ui/options/startup_page_manager_handler.h
new file mode 100644
index 0000000..440e887
--- /dev/null
+++ b/chrome/browser/dom_ui/options/startup_page_manager_handler.h
@@ -0,0 +1,23 @@
+// 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.
+
+#ifndef CHROME_BROWSER_DOM_UI_OPTIONS_STARTUP_PAGE_MANAGER_HANDLER_H_
+#define CHROME_BROWSER_DOM_UI_OPTIONS_STARTUP_PAGE_MANAGER_HANDLER_H_
+
+#include "chrome/browser/dom_ui/options/options_ui.h"
+
+class StartupPageManagerHandler : public OptionsPageUIHandler {
+ public:
+ StartupPageManagerHandler();
+ virtual ~StartupPageManagerHandler();
+
+ // OptionsUIHandler implementation.
+ virtual void GetLocalizedValues(DictionaryValue* localized_strings);
+
+ private:
+
+ DISALLOW_COPY_AND_ASSIGN(StartupPageManagerHandler);
+};
+
+#endif // CHROME_BROWSER_DOM_UI_OPTIONS_STARTUP_PAGE_MANAGER_HANDLER_H_
diff --git a/chrome/browser/dom_ui/options/stop_syncing_handler.cc b/chrome/browser/dom_ui/options/stop_syncing_handler.cc
index ceab2d8..833c88e 100644
--- a/chrome/browser/dom_ui/options/stop_syncing_handler.cc
+++ b/chrome/browser/dom_ui/options/stop_syncing_handler.cc
@@ -11,8 +11,8 @@
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "chrome/browser/sync/profile_sync_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
StopSyncingHandler::StopSyncingHandler() {
}
diff --git a/chrome/browser/dom_ui/options/sync_options_handler.cc b/chrome/browser/dom_ui/options/sync_options_handler.cc
index de6c5bf..e67050c 100644
--- a/chrome/browser/dom_ui/options/sync_options_handler.cc
+++ b/chrome/browser/dom_ui/options/sync_options_handler.cc
@@ -11,6 +11,7 @@
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/sync_setup_flow.h"
#include "chrome/common/notification_service.h"
@@ -66,7 +67,8 @@ void SyncOptionsHandler::Initialize() {
DictionaryValue args;
SyncSetupFlow::GetArgsForConfigure(service, &args);
- dom_ui_->CallJavascriptFunction(L"SyncOptions.setRegisteredDataTypes", args);
+ dom_ui_->CallJavascriptFunction(
+ L"PersonalOptions.setRegisteredDataTypes", args);
}
void SyncOptionsHandler::RegisterMessages() {
diff --git a/chrome/browser/dom_ui/options/sync_options_handler.h b/chrome/browser/dom_ui/options/sync_options_handler.h
index e7d8904..79bf46d 100644
--- a/chrome/browser/dom_ui/options/sync_options_handler.h
+++ b/chrome/browser/dom_ui/options/sync_options_handler.h
@@ -9,6 +9,7 @@
#include "chrome/browser/dom_ui/options/options_ui.h"
// Chrome sync options page UI handler.
+// TODO(jhawkins): Move the meat of this class to PersonalOptionsHandler.
class SyncOptionsHandler : public OptionsPageUIHandler {
public:
SyncOptionsHandler();
diff --git a/chrome/browser/dom_ui/plugins_ui.cc b/chrome/browser/dom_ui/plugins_ui.cc
index 1834332..aaf59f1 100644
--- a/chrome/browser/dom_ui/plugins_ui.cc
+++ b/chrome/browser/dom_ui/plugins_ui.cc
@@ -19,7 +19,7 @@
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
#include "chrome/browser/plugin_updater.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
@@ -32,7 +32,7 @@
#include "grit/browser_resources.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
-#include "webkit/glue/plugins/plugin_list.h"
+#include "webkit/plugins/npapi/plugin_list.h"
namespace {
@@ -214,7 +214,7 @@ void PluginsDOMHandler::HandleEnablePluginMessage(const ListValue* args) {
return;
bool enable = enable_str == "true";
- PluginUpdater* plugin_updater = PluginUpdater::GetPluginUpdater();
+ PluginUpdater* plugin_updater = PluginUpdater::GetInstance();
if (is_group_str == "true") {
string16 group_name;
if (!args->GetString(0, &group_name))
@@ -223,14 +223,13 @@ void PluginsDOMHandler::HandleEnablePluginMessage(const ListValue* args) {
plugin_updater->EnablePluginGroup(enable, group_name);
if (enable) {
// See http://crbug.com/50105 for background.
- string16 reader8 = ASCIIToUTF16(PluginGroup::kAdobeReader8GroupName);
- string16 reader9 = ASCIIToUTF16(PluginGroup::kAdobeReader9GroupName);
+ string16 adobereader = ASCIIToUTF16(
+ webkit::npapi::PluginGroup::kAdobeReaderGroupName);
string16 internalpdf = ASCIIToUTF16(PepperPluginRegistry::kPDFPluginName);
- if (group_name == reader8 || group_name == reader9) {
+ if (group_name == adobereader) {
plugin_updater->EnablePluginGroup(false, internalpdf);
} else if (group_name == internalpdf) {
- plugin_updater->EnablePluginGroup(false, reader8);
- plugin_updater->EnablePluginGroup(false, reader9);
+ plugin_updater->EnablePluginGroup(false, adobereader);
}
}
} else {
@@ -264,7 +263,7 @@ void PluginsDOMHandler::Observe(NotificationType type,
void PluginsDOMHandler::LoadPluginsOnFileThread(ListWrapper* wrapper,
Task* task) {
- wrapper->list = PluginUpdater::GetPluginUpdater()->GetPluginGroupsData();
+ wrapper->list = PluginUpdater::GetInstance()->GetPluginGroupsData();
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, task);
BrowserThread::PostTask(
BrowserThread::UI,
@@ -316,9 +315,9 @@ PluginsUI::PluginsUI(TabContents* contents) : DOMUI(contents) {
// Set up the chrome://plugins/ source.
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(Singleton<ChromeURLDataManager>::get(),
- &ChromeURLDataManager::AddDataSource,
- make_scoped_refptr(html_source)));
+ NewRunnableMethod(ChromeURLDataManager::GetInstance(),
+ &ChromeURLDataManager::AddDataSource,
+ make_scoped_refptr(html_source)));
}
diff --git a/chrome/browser/dom_ui/print_preview_handler.cc b/chrome/browser/dom_ui/print_preview_handler.cc
index 9248a8a..cee9be4 100644
--- a/chrome/browser/dom_ui/print_preview_handler.cc
+++ b/chrome/browser/dom_ui/print_preview_handler.cc
@@ -15,10 +15,18 @@ PrintPreviewHandler::~PrintPreviewHandler() {
}
void PrintPreviewHandler::RegisterMessages() {
+ dom_ui_->RegisterMessageCallback("getPreview",
+ NewCallback(this, &PrintPreviewHandler::HandleGetPreview));
dom_ui_->RegisterMessageCallback("getPrinters",
NewCallback(this, &PrintPreviewHandler::HandleGetPrinters));
}
+void PrintPreviewHandler::HandleGetPreview(const ListValue*) {
+ // TODO(thestig) Hook this up properly when PDF generation works.
+ StringValue dummy_url("chrome://print/dummy.pdf");
+ dom_ui_->CallJavascriptFunction(L"createPDFPlugin", dummy_url);
+}
+
void PrintPreviewHandler::HandleGetPrinters(const ListValue*) {
ListValue printers;
diff --git a/chrome/browser/dom_ui/print_preview_handler.h b/chrome/browser/dom_ui/print_preview_handler.h
index edcb8e6..b5d454d 100644
--- a/chrome/browser/dom_ui/print_preview_handler.h
+++ b/chrome/browser/dom_ui/print_preview_handler.h
@@ -25,6 +25,9 @@ class PrintPreviewHandler : public DOMMessageHandler,
virtual void RegisterMessages();
private:
+ // Get the PDF preview and refresh the PDF plugin. |args| is unused.
+ void HandleGetPreview(const ListValue* args);
+
// Get the list of printers and send it to the DOM UI. |args| is unused.
void HandleGetPrinters(const ListValue* args);
diff --git a/chrome/browser/dom_ui/print_preview_ui.cc b/chrome/browser/dom_ui/print_preview_ui.cc
index 9b95f86..f0f7656 100644
--- a/chrome/browser/dom_ui/print_preview_ui.cc
+++ b/chrome/browser/dom_ui/print_preview_ui.cc
@@ -29,6 +29,10 @@ namespace {
void SetLocalizedStrings(DictionaryValue* localized_strings) {
localized_strings->SetString(std::string("title"),
l10n_util::GetStringUTF8(IDS_PRINT_PREVIEW_TITLE));
+ localized_strings->SetString(std::string("loading"),
+ l10n_util::GetStringUTF8(IDS_PRINT_PREVIEW_LOADING));
+ localized_strings->SetString(std::string("noPlugin"),
+ l10n_util::GetStringUTF8(IDS_PRINT_PREVIEW_NO_PLUGIN));
localized_strings->SetString(std::string("noPrinter"),
l10n_util::GetStringUTF8(IDS_PRINT_PREVIEW_NO_PRINTER));
@@ -86,25 +90,39 @@ PrintPreviewUIHTMLSource::~PrintPreviewUIHTMLSource() {}
void PrintPreviewUIHTMLSource::StartDataRequest(const std::string& path,
bool is_off_the_record,
int request_id) {
- DictionaryValue localized_strings;
- SetLocalizedStrings(&localized_strings);
- SetFontAndTextDirection(&localized_strings);
-
- static const base::StringPiece print_html(
- ResourceBundle::GetSharedInstance().GetRawDataResource(
- IDR_PRINT_PREVIEW_HTML));
- const std::string full_html = jstemplate_builder::GetI18nTemplateHtml(
- print_html, &localized_strings);
-
- scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
- html_bytes->data.resize(full_html.size());
- std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
-
- SendResponse(request_id, html_bytes);
+ // Print Preview Index page.
+ if (path.empty()) {
+ DictionaryValue localized_strings;
+ SetLocalizedStrings(&localized_strings);
+ SetFontAndTextDirection(&localized_strings);
+
+ static const base::StringPiece print_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_PRINT_PREVIEW_HTML));
+ const std::string full_html = jstemplate_builder::GetI18nTemplateHtml(
+ print_html, &localized_strings);
+
+ scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
+ html_bytes->data.resize(full_html.size());
+ std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
+
+ SendResponse(request_id, html_bytes);
+ return;
+ }
+
+ // Print Preview data.
+ NOTIMPLEMENTED() << "No PDF for you";
+ scoped_refptr<RefCountedBytes> data_bytes(new RefCountedBytes);
+ SendResponse(request_id, data_bytes);
}
-std::string PrintPreviewUIHTMLSource::GetMimeType(const std::string&) const {
- return "text/html";
+std::string PrintPreviewUIHTMLSource::GetMimeType(
+ const std::string& path) const {
+ // Print Preview Index page.
+ if (path.empty())
+ return "text/html";
+ // Print Preview data.
+ return "application/pdf";
}
////////////////////////////////////////////////////////////////////////////////
@@ -122,7 +140,7 @@ PrintPreviewUI::PrintPreviewUI(TabContents* contents) : DOMUI(contents) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(new PrintPreviewUIHTMLSource())));
}
diff --git a/chrome/browser/dom_ui/print_preview_ui_uitest.cc b/chrome/browser/dom_ui/print_preview_ui_uitest.cc
index f09cda5..4be0a28 100644
--- a/chrome/browser/dom_ui/print_preview_ui_uitest.cc
+++ b/chrome/browser/dom_ui/print_preview_ui_uitest.cc
@@ -5,6 +5,7 @@
#include "app/l10n_util.h"
#include "base/string16.h"
#include "base/utf_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/automation/browser_proxy.h"
@@ -46,4 +47,30 @@ TEST_F(PrintPreviewUITest, LoadPrintPreviewByURL) {
AssertIsPrintPage(tab);
}
+TEST_F(PrintPreviewUITest, PrintCommandDisabled) {
+ scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
+ ASSERT_TRUE(browser.get());
+
+ // Go to the about:blank page.
+ NavigateToURL(GURL(chrome::kAboutBlankURL));
+
+ // Make sure there is 1 tab and print is enabled. Create print preview tab.
+ int tab_count;
+ ASSERT_TRUE(browser->GetTabCount(&tab_count));
+ ASSERT_EQ(1, tab_count);
+ bool enabled;
+ ASSERT_TRUE(browser->IsMenuCommandEnabled(IDC_PRINT, &enabled));
+ ASSERT_TRUE(enabled);
+ ASSERT_TRUE(browser->RunCommand(IDC_PRINT));
+
+ // Make sure there are 2 tabs and print is disabled.
+ ASSERT_TRUE(browser->GetTabCount(&tab_count));
+ ASSERT_EQ(2, tab_count);
+ scoped_refptr<TabProxy> tab = browser->GetActiveTab();
+ ASSERT_TRUE(tab.get());
+ AssertIsPrintPage(tab);
+ ASSERT_TRUE(browser->IsMenuCommandEnabled(IDC_PRINT, &enabled));
+ ASSERT_FALSE(enabled);
+}
+
} // namespace
diff --git a/chrome/browser/dom_ui/remoting_ui.cc b/chrome/browser/dom_ui/remoting_ui.cc
index 90ceb52..0bdb717 100644
--- a/chrome/browser/dom_ui/remoting_ui.cc
+++ b/chrome/browser/dom_ui/remoting_ui.cc
@@ -66,9 +66,9 @@ RemotingUI::RemotingUI(TabContents* contents) : DOMUI(contents) {
// Set up the chrome://remoting source.
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(Singleton<ChromeURLDataManager>::get(),
- &ChromeURLDataManager::AddDataSource,
- make_scoped_refptr(html_source)));
+ NewRunnableMethod(ChromeURLDataManager::GetInstance(),
+ &ChromeURLDataManager::AddDataSource,
+ make_scoped_refptr(html_source)));
}
diff --git a/chrome/browser/dom_ui/shared_resources_data_source.cc b/chrome/browser/dom_ui/shared_resources_data_source.cc
index 2c51470..6ff8343 100644
--- a/chrome/browser/dom_ui/shared_resources_data_source.cc
+++ b/chrome/browser/dom_ui/shared_resources_data_source.cc
@@ -4,10 +4,11 @@
#include "chrome/browser/dom_ui/shared_resources_data_source.h"
+#include <string>
+
#include "app/resource_bundle.h"
#include "base/singleton.h"
#include "base/thread_restrictions.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
#include "chrome/browser/io_thread.h"
@@ -56,7 +57,7 @@ void SharedResourcesDataSource::Register() {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(source)));
}
@@ -89,4 +90,3 @@ std::string SharedResourcesDataSource::GetMimeType(
net::GetMimeTypeFromFile(FilePath().AppendASCII(path), &mime_type);
return mime_type;
}
-
diff --git a/chrome/browser/dom_ui/shown_sections_handler.cc b/chrome/browser/dom_ui/shown_sections_handler.cc
index 5682ca6..6a2e3ca 100644
--- a/chrome/browser/dom_ui/shown_sections_handler.cc
+++ b/chrome/browser/dom_ui/shown_sections_handler.cc
@@ -10,7 +10,7 @@
#include "base/values.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_details.h"
@@ -47,15 +47,6 @@ int ShownSectionsHandler::GetShownSections(PrefService* prefs) {
return prefs->GetInteger(prefs::kNTPShownSections);
}
-// static
-void ShownSectionsHandler::SetShownSection(PrefService* prefs,
- Section section) {
- int shown_sections = GetShownSections(prefs);
- shown_sections &= ~ALL_SECTIONS_MASK;
- shown_sections |= section;
- prefs->SetInteger(prefs::kNTPShownSections, shown_sections);
-}
-
ShownSectionsHandler::ShownSectionsHandler(PrefService* pref_service)
: pref_service_(pref_service) {
pref_registrar_.Init(pref_service);
@@ -115,6 +106,12 @@ void ShownSectionsHandler::RegisterUserPrefs(PrefService* pref_service) {
void ShownSectionsHandler::MigrateUserPrefs(PrefService* pref_service,
int old_pref_version,
int new_pref_version) {
+ // Nothing to migrate for default kNTPShownSections value.
+ const PrefService::Preference* shown_sections_pref =
+ pref_service->FindPreference(prefs::kNTPShownSections);
+ if (shown_sections_pref->IsDefaultValue())
+ return;
+
bool changed = false;
int shown_sections = pref_service->GetInteger(prefs::kNTPShownSections);
diff --git a/chrome/browser/dom_ui/shown_sections_handler.h b/chrome/browser/dom_ui/shown_sections_handler.h
index 41c7da8..ad227b4 100644
--- a/chrome/browser/dom_ui/shown_sections_handler.h
+++ b/chrome/browser/dom_ui/shown_sections_handler.h
@@ -43,10 +43,6 @@ class ShownSectionsHandler : public DOMMessageHandler,
// Helper to get the current shown sections.
static int GetShownSections(PrefService* pref_service);
- // Expands |section|, collapsing any previously expanded section. This is the
- // same thing that happens if a user clicks on |section|.
- static void SetShownSection(PrefService* prefs, Section section);
-
// DOMMessageHandler implementation.
virtual void RegisterMessages();
diff --git a/chrome/browser/dom_ui/shown_sections_handler_unittest.cc b/chrome/browser/dom_ui/shown_sections_handler_unittest.cc
index 9e9278e..7ca5631 100644
--- a/chrome/browser/dom_ui/shown_sections_handler_unittest.cc
+++ b/chrome/browser/dom_ui/shown_sections_handler_unittest.cc
@@ -5,7 +5,6 @@
#include "chrome/browser/dom_ui/shown_sections_handler.h"
#include "base/scoped_ptr.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/prefs/pref_value_store.h"
#include "chrome/common/json_pref_store.h"
#include "chrome/common/pref_names.h"
@@ -23,7 +22,7 @@ int MigratePrefValue(PrefService* prefs, int starting_value) {
return prefs->GetInteger(prefs::kNTPShownSections);
}
-}
+} // namespace
TEST_F(ShownSectionsHandlerTest, MigrateUserPrefs) {
scoped_ptr<PrefService> pref(new TestingPrefService);
diff --git a/chrome/browser/dom_ui/slideshow_ui.cc b/chrome/browser/dom_ui/slideshow_ui.cc
index 277ea21..da8a807 100644
--- a/chrome/browser/dom_ui/slideshow_ui.cc
+++ b/chrome/browser/dom_ui/slideshow_ui.cc
@@ -20,7 +20,7 @@
#include "chrome/browser/dom_ui/dom_ui_favicon_source.h"
#include "chrome/browser/history/history_types.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/jstemplate_builder.h"
@@ -153,7 +153,7 @@ DOMMessageHandler* SlideshowHandler::Attach(DOMUI* dom_ui) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(new DOMUIFavIconSource(dom_ui->GetProfile()))));
profile_ = dom_ui->GetProfile();
@@ -288,7 +288,7 @@ SlideshowUI::SlideshowUI(TabContents* contents) : DOMUI(contents) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(html_source)));
}
diff --git a/chrome/browser/dom_ui/textfields_ui.cc b/chrome/browser/dom_ui/textfields_ui.cc
index db4fb0c..a74f10d 100644
--- a/chrome/browser/dom_ui/textfields_ui.cc
+++ b/chrome/browser/dom_ui/textfields_ui.cc
@@ -70,7 +70,7 @@ TextfieldsUI::TextfieldsUI(TabContents* contents) : DOMUI(contents) {
// Set up the chrome://textfields/ source.
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(Singleton<ChromeURLDataManager>::get(),
- &ChromeURLDataManager::AddDataSource,
- make_scoped_refptr(html_source)));
+ NewRunnableMethod(ChromeURLDataManager::GetInstance(),
+ &ChromeURLDataManager::AddDataSource,
+ make_scoped_refptr(html_source)));
}
diff --git a/chrome/browser/dom_ui/tips_handler.cc b/chrome/browser/dom_ui/tips_handler.cc
index 6d1d863..411da1f 100644
--- a/chrome/browser/dom_ui/tips_handler.cc
+++ b/chrome/browser/dom_ui/tips_handler.cc
@@ -10,7 +10,7 @@
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/dom_ui/tips_handler.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/web_resource/web_resource_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/web_resource/web_resource_unpacker.h"
diff --git a/chrome/browser/download/base_file.cc b/chrome/browser/download/base_file.cc
index 2d89159..7d84670 100644
--- a/chrome/browser/download/base_file.cc
+++ b/chrome/browser/download/base_file.cc
@@ -15,7 +15,7 @@
#if defined(OS_WIN)
#include "chrome/common/win_safe_util.h"
#elif defined(OS_MACOSX)
-#include "chrome/browser/cocoa/file_metadata.h"
+#include "chrome/browser/ui/cocoa/file_metadata.h"
#endif
BaseFile::BaseFile(const FilePath& full_path,
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc
index 2997346..6f0d998 100644
--- a/chrome/browser/download/download_browsertest.cc
+++ b/chrome/browser/download/download_browsertest.cc
@@ -14,11 +14,9 @@
#include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/net/url_request_mock_http_job.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/chrome_paths.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
@@ -122,7 +120,7 @@ class DownloadsObserver : public DownloadManager::Observer,
std::set<DownloadItem*>::const_iterator
finished_it(finished_downloads_.find(*it));
- std::set<DownloadItem*>::const_iterator
+ std::set<DownloadItem*>::iterator
observed_it(downloads_observed_.find(*it));
// If it isn't finished and we're aren't observing it, start.
diff --git a/chrome/browser/download/download_exe.cc b/chrome/browser/download/download_exe.cc
deleted file mode 100644
index 8111f5d..0000000
--- a/chrome/browser/download/download_exe.cc
+++ /dev/null
@@ -1,241 +0,0 @@
-// 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.
-
-#include <set>
-#include <string>
-
-#include "chrome/browser/download/download_util.h"
-
-#include "base/string_util.h"
-#include "net/base/mime_util.h"
-#include "net/base/net_util.h"
-
-namespace download_util {
-
-// For file extensions taken from mozilla:
-
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (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.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla Communicator client code, released
- * March 31, 1998.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998-1999
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Doug Turner <dougt@netscape.com>
- * Dean Tessman <dean_tessman@hotmail.com>
- * Brodie Thiesfield <brofield@jellycan.com>
- * Jungshik Shin <jshin@i18nl10n.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-static const char* const g_executables[] = {
- "class",
- "htm",
- "html",
- "jar",
- "pdf",
- "pdfxml",
- "mars",
- "fdf",
- "xfdf",
- "xdp",
- "xfd",
- "pl",
- "py",
- "rb",
- "shtm",
- "shtml",
- "svg",
- "swf",
- "xht",
- "xhtm",
- "xhtml",
- "xml",
- "xsl",
- "xslt",
-#if defined(OS_WIN)
- "ad",
- "ade",
- "adp",
- "app",
- "application",
- "asp",
- "asx",
- "bas",
- "bat",
- "chm",
- "cmd",
- "com",
- "cpl",
- "crt",
- "dll",
- "exe",
- "fxp",
- "hlp",
- "hta",
- "htt",
- "inf",
- "ins",
- "isp",
- "js",
- "jse",
- "lnk",
- "mad",
- "maf",
- "mag",
- "mam",
- "maq",
- "mar",
- "mas",
- "mat",
- "mau",
- "mav",
- "maw",
- "mda",
- "mdb",
- "mde",
- "mdt",
- "mdw",
- "mdz",
- "mht",
- "mhtml",
- "msc",
- "msh",
- "mshxml",
- "msi",
- "msp",
- "mst",
- "ocx",
- "ops",
- "pcd",
- "pif",
- "plg",
- "prf",
- "prg",
- "pst",
- "reg",
- "scf",
- "scr",
- "sct",
- "shb",
- "shs",
- "url",
- "vb",
- "vbe",
- "vbs",
- "vsd",
- "vsmacros",
- "vss",
- "vst",
- "vsw",
- "ws",
- "wsc",
- "wsf",
- "wsh",
- "xbap",
-#elif defined(OS_MACOSX)
- // TODO(thakis): Figure out what makes sense here -- crbug.com/19096
- "app",
- "dmg",
-#elif defined(OS_POSIX)
- // TODO(estade): lengthen this list.
- "bash",
- "csh",
- "deb",
- "exe",
- "ksh",
- "rpm",
- "sh",
- "tcsh",
-#endif
-};
-
-bool IsExecutableFile(const FilePath& path) {
- return IsExecutableExtension(path.Extension());
-}
-
-bool IsExecutableExtension(const FilePath::StringType& extension) {
- if (extension.empty())
- return false;
- if (!IsStringASCII(extension))
- return false;
-#if defined(OS_WIN)
- std::string ascii_extension = WideToASCII(extension);
-#elif defined(OS_POSIX)
- std::string ascii_extension = extension;
-#endif
-
- // Strip out leading dot if it's still there
- if (ascii_extension[0] == FilePath::kExtensionSeparator)
- ascii_extension.erase(0, 1);
-
- for (size_t i = 0; i < arraysize(g_executables); ++i) {
- if (LowerCaseEqualsASCII(ascii_extension, g_executables[i]))
- return true;
- }
- return false;
-}
-
-static const char* kExecutableWhiteList[] = {
- // JavaScript is just as powerful as EXE.
- "text/javascript",
- "text/javascript;version=*",
- "text/html",
- // Registry files can cause critical changes to the MS OS behavior.
- // Addition of this mimetype also addresses bug 7337.
- "text/x-registry",
- "text/x-sh",
- // Some sites use binary/octet-stream to mean application/octet-stream.
- // See http://code.google.com/p/chromium/issues/detail?id=1573
- "binary/octet-stream"
-};
-
-static const char* kExecutableBlackList[] = {
- // These application types are not executable.
- "application/*+xml",
- "application/xml"
-};
-
-bool IsExecutableMimeType(const std::string& mime_type) {
- for (size_t i = 0; i < arraysize(kExecutableWhiteList); ++i) {
- if (net::MatchesMimeType(kExecutableWhiteList[i], mime_type))
- return true;
- }
- for (size_t i = 0; i < arraysize(kExecutableBlackList); ++i) {
- if (net::MatchesMimeType(kExecutableBlackList[i], mime_type))
- return false;
- }
- // We consider only other application types to be executable.
- return net::MatchesMimeType("application/*", mime_type);
-}
-
-
-} // namespace download_util
diff --git a/chrome/browser/download/download_extensions.cc b/chrome/browser/download/download_extensions.cc
new file mode 100644
index 0000000..52aa565
--- /dev/null
+++ b/chrome/browser/download/download_extensions.cc
@@ -0,0 +1,258 @@
+// 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.
+
+#include <set>
+#include <string>
+
+#include "chrome/browser/download/download_extensions.h"
+
+#include "base/string_util.h"
+#include "net/base/mime_util.h"
+#include "net/base/net_util.h"
+
+namespace download_util {
+
+// For file extensions taken from mozilla:
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Doug Turner <dougt@netscape.com>
+ * Dean Tessman <dean_tessman@hotmail.com>
+ * Brodie Thiesfield <brofield@jellycan.com>
+ * Jungshik Shin <jshin@i18nl10n.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+static const struct Executables {
+ const char* extension;
+ DownloadDangerLevel level;
+} g_executables[] = {
+ { "class", Dangerous },
+ { "htm", AllowOnUserGesture },
+ { "html", AllowOnUserGesture },
+ { "jar", Dangerous },
+ { "jnlp", Dangerous },
+ { "pdf", AllowOnUserGesture },
+ { "pdfxml", AllowOnUserGesture },
+ { "mars", AllowOnUserGesture },
+ { "fdf", AllowOnUserGesture },
+ { "xfdf", AllowOnUserGesture },
+ { "xdp", AllowOnUserGesture },
+ { "xfd", AllowOnUserGesture },
+ { "pl", AllowOnUserGesture },
+ { "py", AllowOnUserGesture },
+ { "rb", AllowOnUserGesture },
+ { "shtm", AllowOnUserGesture },
+ { "shtml", AllowOnUserGesture },
+ { "svg", AllowOnUserGesture },
+ { "swf", AllowOnUserGesture },
+ { "xht", AllowOnUserGesture },
+ { "xhtm", AllowOnUserGesture },
+ { "xhtml", AllowOnUserGesture },
+ { "xml", AllowOnUserGesture },
+ { "xsl", AllowOnUserGesture },
+ { "xslt", AllowOnUserGesture },
+#if defined(OS_WIN)
+ { "ad", AllowOnUserGesture },
+ { "ade", AllowOnUserGesture },
+ { "adp", AllowOnUserGesture },
+ { "app", AllowOnUserGesture },
+ { "application", AllowOnUserGesture },
+ { "asp", AllowOnUserGesture },
+ { "asx", AllowOnUserGesture },
+ { "bas", AllowOnUserGesture },
+ { "bat", AllowOnUserGesture },
+ { "chi", AllowOnUserGesture },
+ { "chm", AllowOnUserGesture },
+ { "cmd", AllowOnUserGesture },
+ { "com", AllowOnUserGesture },
+ { "cpl", AllowOnUserGesture },
+ { "crt", AllowOnUserGesture },
+ { "dll", Dangerous },
+ { "drv", Dangerous },
+ { "exe", AllowOnUserGesture },
+ { "fxp", AllowOnUserGesture },
+ { "hlp", AllowOnUserGesture },
+ { "hta", AllowOnUserGesture },
+ { "htt", AllowOnUserGesture },
+ { "inf", AllowOnUserGesture },
+ { "ins", AllowOnUserGesture },
+ { "isp", AllowOnUserGesture },
+ { "js", AllowOnUserGesture },
+ { "jse", AllowOnUserGesture },
+ { "lnk", AllowOnUserGesture },
+ { "mad", AllowOnUserGesture },
+ { "maf", AllowOnUserGesture },
+ { "mag", AllowOnUserGesture },
+ { "mam", AllowOnUserGesture },
+ { "maq", AllowOnUserGesture },
+ { "mar", AllowOnUserGesture },
+ { "mas", AllowOnUserGesture },
+ { "mat", AllowOnUserGesture },
+ { "mau", AllowOnUserGesture },
+ { "mav", AllowOnUserGesture },
+ { "maw", AllowOnUserGesture },
+ { "mda", AllowOnUserGesture },
+ { "mdb", AllowOnUserGesture },
+ { "mde", AllowOnUserGesture },
+ { "mdt", AllowOnUserGesture },
+ { "mdw", AllowOnUserGesture },
+ { "mdz", AllowOnUserGesture },
+ { "mht", AllowOnUserGesture },
+ { "mhtml", AllowOnUserGesture },
+ { "mmc", AllowOnUserGesture },
+ { "msc", AllowOnUserGesture },
+ { "msh", AllowOnUserGesture },
+ { "mshxml", AllowOnUserGesture },
+ { "msi", AllowOnUserGesture },
+ { "msp", AllowOnUserGesture },
+ { "mst", AllowOnUserGesture },
+ { "ocx", AllowOnUserGesture },
+ { "ops", AllowOnUserGesture },
+ { "pcd", AllowOnUserGesture },
+ { "pif", AllowOnUserGesture },
+ { "plg", AllowOnUserGesture },
+ { "prf", AllowOnUserGesture },
+ { "prg", AllowOnUserGesture },
+ { "pst", AllowOnUserGesture },
+ { "reg", AllowOnUserGesture },
+ { "scf", AllowOnUserGesture },
+ { "scr", AllowOnUserGesture },
+ { "sct", AllowOnUserGesture },
+ { "shb", AllowOnUserGesture },
+ { "shs", AllowOnUserGesture },
+ { "sys", Dangerous },
+ { "url", AllowOnUserGesture },
+ { "vb", AllowOnUserGesture },
+ { "vbe", AllowOnUserGesture },
+ { "vbs", AllowOnUserGesture },
+ { "vsd", AllowOnUserGesture },
+ { "vsmacros", AllowOnUserGesture },
+ { "vss", AllowOnUserGesture },
+ { "vst", AllowOnUserGesture },
+ { "vsw", AllowOnUserGesture },
+ { "ws", AllowOnUserGesture },
+ { "wsc", AllowOnUserGesture },
+ { "wsf", AllowOnUserGesture },
+ { "wsh", AllowOnUserGesture },
+ { "xbap", Dangerous },
+#elif defined(OS_MACOSX)
+ // TODO(thakis): Figure out what makes sense here -- crbug.com/19096
+ { "app", AllowOnUserGesture },
+ { "dmg", AllowOnUserGesture },
+#elif defined(OS_POSIX)
+ // TODO(estade): lengthen this list.
+ { "bash", AllowOnUserGesture },
+ { "csh", AllowOnUserGesture },
+ { "deb", AllowOnUserGesture },
+ { "exe", AllowOnUserGesture },
+ { "ksh", AllowOnUserGesture },
+ { "rpm", AllowOnUserGesture },
+ { "sh", AllowOnUserGesture },
+ { "tcsh", AllowOnUserGesture },
+#endif
+};
+
+DownloadDangerLevel GetFileDangerLevel(const FilePath& path) {
+ return GetFileExtensionDangerLevel(path.Extension());
+}
+
+DownloadDangerLevel GetFileExtensionDangerLevel(
+ const FilePath::StringType& extension) {
+ if (extension.empty())
+ return NotDangerous;
+ if (!IsStringASCII(extension))
+ return NotDangerous;
+#if defined(OS_WIN)
+ std::string ascii_extension = WideToASCII(extension);
+#elif defined(OS_POSIX)
+ std::string ascii_extension = extension;
+#endif
+
+ // Strip out leading dot if it's still there
+ if (ascii_extension[0] == FilePath::kExtensionSeparator)
+ ascii_extension.erase(0, 1);
+
+ for (size_t i = 0; i < arraysize(g_executables); ++i) {
+ if (LowerCaseEqualsASCII(ascii_extension, g_executables[i].extension))
+ return g_executables[i].level;
+ }
+ return NotDangerous;
+}
+
+bool IsFileExtensionSafe(const FilePath::StringType& extension) {
+ return GetFileExtensionDangerLevel(extension) == NotDangerous;
+}
+
+bool IsFileSafe(const FilePath& path) {
+ return GetFileDangerLevel(path) == NotDangerous;
+}
+
+static const char* kExecutableWhiteList[] = {
+ // JavaScript is just as powerful as EXE.
+ "text/javascript",
+ "text/javascript;version=*",
+ "text/html",
+ // Registry files can cause critical changes to the MS OS behavior.
+ // Addition of this mimetype also addresses bug 7337.
+ "text/x-registry",
+ "text/x-sh",
+ // Some sites use binary/octet-stream to mean application/octet-stream.
+ // See http://code.google.com/p/chromium/issues/detail?id=1573
+ "binary/octet-stream"
+};
+
+static const char* kExecutableBlackList[] = {
+ // These application types are not executable.
+ "application/*+xml",
+ "application/xml"
+};
+
+bool IsExecutableMimeType(const std::string& mime_type) {
+ for (size_t i = 0; i < arraysize(kExecutableWhiteList); ++i) {
+ if (net::MatchesMimeType(kExecutableWhiteList[i], mime_type))
+ return true;
+ }
+ for (size_t i = 0; i < arraysize(kExecutableBlackList); ++i) {
+ if (net::MatchesMimeType(kExecutableBlackList[i], mime_type))
+ return false;
+ }
+ // We consider only other application types to be executable.
+ return net::MatchesMimeType("application/*", mime_type);
+}
+
+
+} // namespace download_util
diff --git a/chrome/browser/download/download_extensions.h b/chrome/browser/download/download_extensions.h
new file mode 100644
index 0000000..3a7c557
--- /dev/null
+++ b/chrome/browser/download/download_extensions.h
@@ -0,0 +1,39 @@
+// 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.
+
+#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_EXTENSIONS_H_
+#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_EXTENSIONS_H_
+#pragma once
+
+#include <string>
+
+#include "base/file_path.h"
+
+namespace download_util {
+
+enum DownloadDangerLevel {
+ NotDangerous,
+ AllowOnUserGesture,
+ Dangerous
+};
+
+// Determine the download danger level of a file.
+DownloadDangerLevel GetFileDangerLevel(const FilePath& path);
+
+// Determine the download danger level using a file extension.
+DownloadDangerLevel GetFileExtensionDangerLevel(
+ const FilePath::StringType& extension);
+
+// True if the download danger level of the file is NotDangerous.
+bool IsFileSafe(const FilePath& path);
+
+// True if the download danger level of the extension is NotDangerous.
+bool IsFileExtensionSafe(const FilePath::StringType& extension);
+
+// Tests if we think the server means for this mime_type to be executable.
+bool IsExecutableMimeType(const std::string& mime_type);
+
+} // namespace download_util
+
+#endif // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_EXTENSIONS_H_
diff --git a/chrome/browser/download/download_file_manager.cc b/chrome/browser/download/download_file_manager.cc
index e33003a..035714e 100644
--- a/chrome/browser/download/download_file_manager.cc
+++ b/chrome/browser/download/download_file_manager.cc
@@ -16,7 +16,7 @@
#include "chrome/browser/history/download_create_info.h"
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/browser/platform_util.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "chrome/browser/tab_contents/tab_contents.h"
@@ -27,7 +27,7 @@
#include "app/win_util.h"
#include "chrome/common/win_safe_util.h"
#elif defined(OS_MACOSX)
-#include "chrome/browser/cocoa/file_metadata.h"
+#include "chrome/browser/ui/cocoa/file_metadata.h"
#endif
namespace {
@@ -176,6 +176,8 @@ void DownloadFileManager::StartDownload(DownloadCreateInfo* info) {
return;
}
+ manager->CreateDownloadItem(info);
+
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
NewRunnableMethod(this, &DownloadFileManager::CreateDownloadFile,
info, make_scoped_refptr(manager)));
diff --git a/chrome/browser/download/download_history.cc b/chrome/browser/download/download_history.cc
index dd945c5..388ffd3 100644
--- a/chrome/browser/download/download_history.cc
+++ b/chrome/browser/download/download_history.cc
@@ -8,7 +8,7 @@
#include "chrome/browser/history/download_create_info.h"
#include "chrome/browser/history/history_marshaling.h"
#include "chrome/browser/download/download_item.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
// Our download table ID starts at 1, so we use 0 to represent a download that
// has started, but has not yet had its data persisted in the table. We use fake
diff --git a/chrome/browser/download/download_item.cc b/chrome/browser/download/download_item.cc
index 8cd733e..f6bee14 100644
--- a/chrome/browser/download/download_item.cc
+++ b/chrome/browser/download/download_item.cc
@@ -7,12 +7,14 @@
#include "app/l10n_util.h"
#include "base/basictypes.h"
#include "base/file_util.h"
+#include "base/format_macros.h"
#include "base/logging.h"
#include "base/stringprintf.h"
#include "base/timer.h"
#include "base/utf_string_conversions.h"
#include "net/base/net_util.h"
#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/download/download_extensions.h"
#include "chrome/browser/download/download_file_manager.h"
#include "chrome/browser/download/download_history.h"
#include "chrome/browser/download/download_manager.h"
@@ -21,7 +23,7 @@
#include "chrome/browser/history/download_create_info.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/pref_names.h"
@@ -196,7 +198,7 @@ void DownloadItem::NotifyObserversDownloadFileCompleted() {
bool DownloadItem::CanOpenDownload() {
return !Extension::IsExtension(target_name_) &&
- !download_util::IsExecutableFile(target_name_);
+ download_util::IsFileSafe(target_name_);
}
bool DownloadItem::ShouldOpenFileBasedOnExtension() {
@@ -373,6 +375,9 @@ int DownloadItem::PercentComplete() const {
}
void DownloadItem::Rename(const FilePath& full_path) {
+ VLOG(20) << " " << __FUNCTION__ << "()"
+ << " full_path = " << full_path.value()
+ << DebugString(true);
DCHECK(!full_path.empty());
full_path_ = full_path;
}
@@ -403,14 +408,17 @@ void DownloadItem::OnSafeDownloadFinished(DownloadFileManager* file_manager) {
BrowserThread::FILE, FROM_HERE,
NewRunnableMethod(
file_manager, &DownloadFileManager::OnFinalDownloadName,
- id(), GetTargetFilePath(), false, download_manager_));
+ id(), GetTargetFilePath(), false,
+ make_scoped_refptr(download_manager_)));
return;
}
- download_manager_->DownloadFinished(this);
+ Finished();
}
void DownloadItem::OnDownloadRenamedToFinalName(const FilePath& full_path) {
+ VLOG(20) << " " << __FUNCTION__ << "()"
+ << " full_path = " << full_path.value();
bool needed_rename = NeedsRename();
Rename(full_path);
@@ -419,7 +427,7 @@ void DownloadItem::OnDownloadRenamedToFinalName(const FilePath& full_path) {
if (needed_rename && safety_state() == SAFE) {
// This was called from OnSafeDownloadFinished; continue to call
// DownloadFinished.
- download_manager_->DownloadFinished(this);
+ Finished();
}
}
@@ -451,6 +459,36 @@ bool DownloadItem::MatchesQuery(const string16& query) const {
return false;
}
+void DownloadItem::SetFileCheckResults(const FilePath& path,
+ bool is_dangerous,
+ int path_uniquifier,
+ bool prompt,
+ bool is_extension_install,
+ const FilePath& original_name) {
+ VLOG(20) << " " << __FUNCTION__ << "()"
+ << " path = \"" << path.value() << "\""
+ << " is_dangerous = " << is_dangerous
+ << " path_uniquifier = " << path_uniquifier
+ << " prompt = " << prompt
+ << " is_extension_install = " << is_extension_install
+ << " path = \"" << path.value() << "\""
+ << " original_name = \"" << original_name.value() << "\""
+ << " " << DebugString(true);
+ // Make sure the initial file name is set only once.
+ DCHECK(full_path_.empty());
+ DCHECK(!path.empty());
+
+ full_path_ = path;
+ safety_state_ = is_dangerous ? DANGEROUS : SAFE;
+ path_uniquifier_ = path_uniquifier;
+ save_as_ = prompt;
+ is_extension_install_ = is_extension_install;
+ target_name_ = original_name;
+
+ if (target_name_.value().empty())
+ target_name_ = full_path_.BaseName();
+}
+
FilePath DownloadItem::GetTargetFilePath() const {
return full_path_.DirName().Append(target_name_);
}
@@ -475,24 +513,41 @@ void DownloadItem::Init(bool start_timer) {
target_name_ = full_path_.BaseName();
if (start_timer)
StartProgressTimer();
+ VLOG(20) << " " << __FUNCTION__ << "() " << DebugString(true);
}
std::string DownloadItem::DebugString(bool verbose) const {
std::string description =
- base::StringPrintf("{ url = \"%s\"", url().spec().c_str());
+ base::StringPrintf("{ id_ = %d"
+ " state = %s",
+ id_,
+ DebugDownloadStateString(state()));
if (verbose) {
description += base::StringPrintf(
- " target_name_ = " "\"%s\""
- " full_path = " "\"%s\""
- " safety_state = " "%s",
+ " db_handle = %" PRId64
+ " total_bytes = %" PRId64
+ " is_paused = " "%c"
+ " is_extension_install = " "%c"
+ " is_otr = " "%c"
+ " safety_state = " "%s"
+ " url = " "\"%s\""
+ " target_name_ = \"%" PRFilePath "\""
+ " full_path = \"%" PRFilePath "\"",
+ db_handle(),
+ total_bytes(),
+ is_paused() ? 'T' : 'F',
+ is_extension_install() ? 'T' : 'F',
+ is_otr() ? 'T' : 'F',
+ DebugSafetyStateString(safety_state()),
+ url().spec().c_str(),
target_name_.value().c_str(),
- full_path().value().c_str(),
- DebugSafetyStateString(safety_state()));
+ full_path().value().c_str());
+ } else {
+ description += base::StringPrintf(" url = \"%s\"", url().spec().c_str());
}
- description += base::StringPrintf(" state = %s }",
- DebugDownloadStateString(state()));
+ description += " }";
return description;
}
diff --git a/chrome/browser/download/download_item.h b/chrome/browser/download/download_item.h
index 4f963fb..788ea98 100644
--- a/chrome/browser/download/download_item.h
+++ b/chrome/browser/download/download_item.h
@@ -150,6 +150,16 @@ class DownloadItem {
// total size).
int PercentComplete() const;
+ // Update the fields that may have changed in DownloadCreateInfo as a
+ // result of analyzing the file and figuring out its type, location, etc.
+ // May only be called once.
+ void SetFileCheckResults(const FilePath& path,
+ bool is_dangerous,
+ int path_uniquifier,
+ bool prompt,
+ bool is_extension_install,
+ const FilePath& original_name);
+
// Update the download's path, the actual file is renamed on the download
// thread.
void Rename(const FilePath& full_path);
diff --git a/chrome/browser/download/download_manager.cc b/chrome/browser/download/download_manager.cc
index 746dbed..da878b0 100644
--- a/chrome/browser/download/download_manager.cc
+++ b/chrome/browser/download/download_manager.cc
@@ -20,25 +20,26 @@
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/download/download_extensions.h"
#include "chrome/browser/download/download_file_manager.h"
#include "chrome/browser/download/download_history.h"
#include "chrome/browser/download/download_item.h"
#include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/download/download_status_updater.h"
#include "chrome/browser/download/download_util.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/history/download_create_info.h"
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/browser/platform_util.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_paths.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "googleurl/src/gurl.h"
@@ -79,56 +80,49 @@ void DownloadManager::Shutdown() {
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
NewRunnableMethod(file_manager_,
&DownloadFileManager::OnDownloadManagerShutdown,
- this));
+ make_scoped_refptr(this)));
}
- // 'in_progress_' may contain DownloadItems that have not finished the start
- // complete (from the history service) and thus aren't in downloads_.
- DownloadMap::iterator it = in_progress_.begin();
- std::set<DownloadItem*> to_remove;
- for (; it != in_progress_.end(); ++it) {
- DownloadItem* download = it->second;
- if (download->safety_state() == DownloadItem::DANGEROUS) {
- // Forget about any download that the user did not approve.
- // Note that we cannot call download->Remove() this would invalidate our
- // iterator.
- to_remove.insert(download);
- continue;
- }
- DCHECK_EQ(DownloadItem::IN_PROGRESS, download->state());
- download->Cancel(false);
- download_history_->UpdateEntry(download);
- if (download->db_handle() == DownloadHistory::kUninitializedHandle) {
- // An invalid handle means that 'download' does not yet exist in
- // 'downloads_', so we have to delete it here.
- delete download;
+ AssertContainersConsistent();
+
+ // Go through all downloads in downloads_. Dangerous ones we need to
+ // remove on disk, and in progress ones we need to cancel.
+ for (DownloadSet::iterator it = downloads_.begin(); it != downloads_.end();) {
+ DownloadItem* download = *it;
+
+ // Save iterator from potential erases in this set done by called code.
+ // Iterators after an erasure point are still valid for lists and
+ // associative containers such as sets.
+ it++;
+
+ if (download->safety_state() == DownloadItem::DANGEROUS &&
+ (download->state() == DownloadItem::IN_PROGRESS ||
+ download->state() == DownloadItem::COMPLETE)) {
+ // The user hasn't accepted it, so we need to remove it
+ // from the disk. This may or may not result in it being
+ // removed from the DownloadManager queues and deleted
+ // (specifically, DownloadManager::RemoveDownload only
+ // removes and deletes it if it's known to the history service)
+ // so the only thing we know after calling this function is that
+ // the download was deleted if-and-only-if it was removed
+ // from all queues.
+ download->Remove(true);
+ } else if (download->state() == DownloadItem::IN_PROGRESS) {
+ download->Cancel(false);
+ download_history_->UpdateEntry(download);
}
}
- // 'dangerous_finished_' contains all complete downloads that have not been
- // approved. They should be removed.
- it = dangerous_finished_.begin();
- for (; it != dangerous_finished_.end(); ++it)
- to_remove.insert(it->second);
-
- // Remove the dangerous download that are not approved.
- for (std::set<DownloadItem*>::const_iterator rm_it = to_remove.begin();
- rm_it != to_remove.end(); ++rm_it) {
- DownloadItem* download = *rm_it;
- int64 handle = download->db_handle();
- download->Remove(true);
- // Same as above, delete the download if it is not in 'downloads_' (as the
- // Remove() call above won't have deleted it).
- if (handle == DownloadHistory::kUninitializedHandle)
- delete download;
- }
- to_remove.clear();
+ // At this point, all dangerous downloads have had their files removed
+ // and all in progress downloads have been cancelled. We can now delete
+ // anything left.
+ STLDeleteElements(&downloads_);
+ // And clear all non-owning containers.
in_progress_.clear();
- dangerous_finished_.clear();
- STLDeleteValues(&downloads_);
- STLDeleteContainerPointers(save_page_downloads_.begin(),
- save_page_downloads_.end());
+#if !defined(NDEBUG)
+ save_page_as_downloads_.clear();
+#endif
file_manager_ = NULL;
@@ -148,8 +142,8 @@ void DownloadManager::GetTemporaryDownloads(
const FilePath& dir_path, std::vector<DownloadItem*>* result) {
DCHECK(result);
- for (DownloadMap::iterator it = downloads_.begin();
- it != downloads_.end(); ++it) {
+ for (DownloadMap::iterator it = history_downloads_.begin();
+ it != history_downloads_.end(); ++it) {
if (it->second->is_temporary() &&
it->second->full_path().DirName() == dir_path)
result->push_back(it->second);
@@ -160,8 +154,8 @@ void DownloadManager::GetAllDownloads(
const FilePath& dir_path, std::vector<DownloadItem*>* result) {
DCHECK(result);
- for (DownloadMap::iterator it = downloads_.begin();
- it != downloads_.end(); ++it) {
+ for (DownloadMap::iterator it = history_downloads_.begin();
+ it != history_downloads_.end(); ++it) {
if (!it->second->is_temporary() &&
(dir_path.empty() || it->second->full_path().DirName() == dir_path))
result->push_back(it->second);
@@ -172,8 +166,8 @@ void DownloadManager::GetCurrentDownloads(
const FilePath& dir_path, std::vector<DownloadItem*>* result) {
DCHECK(result);
- for (DownloadMap::iterator it = downloads_.begin();
- it != downloads_.end(); ++it) {
+ for (DownloadMap::iterator it = history_downloads_.begin();
+ it != history_downloads_.end(); ++it) {
if (!it->second->is_temporary() &&
(it->second->state() == DownloadItem::IN_PROGRESS ||
it->second->safety_state() == DownloadItem::DANGEROUS) &&
@@ -186,7 +180,6 @@ void DownloadManager::GetCurrentDownloads(
if (original_profile != profile_)
original_profile->GetDownloadManager()->GetCurrentDownloads(dir_path,
result);
-
}
void DownloadManager::SearchDownloads(const string16& query,
@@ -195,8 +188,8 @@ void DownloadManager::SearchDownloads(const string16& query,
string16 query_lower(l10n_util::ToLower(query));
- for (DownloadMap::iterator it = downloads_.begin();
- it != downloads_.end(); ++it) {
+ for (DownloadMap::iterator it = history_downloads_.begin();
+ it != history_downloads_.end(); ++it) {
DownloadItem* download_item = it->second;
if (download_item->is_temporary() || download_item->is_extension_install())
@@ -251,9 +244,10 @@ bool DownloadManager::Init(Profile* profile) {
// create a download item and store it in our download map, and inform the
// history system of a new download. Since this method can be called while the
// history service thread is still reading the persistent state, we do not
-// insert the new DownloadItem into 'downloads_' or inform our observers at this
-// point. OnCreateDatabaseEntryComplete() handles that finalization of the the
-// download creation as a callback from the history thread.
+// insert the new DownloadItem into 'history_downloads_' or inform our
+// observers at this point. OnCreateDatabaseEntryComplete() handles that
+// finalization of the the download creation as a callback from the
+// history thread.
void DownloadManager::StartDownload(DownloadCreateInfo* info) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(info);
@@ -288,7 +282,7 @@ void DownloadManager::StartDownload(DownloadCreateInfo* info) {
// Determine the proper path for a download, by either one of the following:
// 1) using the default download directory.
// 2) prompting the user.
- if (info->prompt_user_for_save_location && !last_download_path_.empty()){
+ if (info->prompt_user_for_save_location && !last_download_path_.empty()) {
info->suggested_path = last_download_path_;
} else {
info->suggested_path = download_prefs_->download_path();
@@ -423,28 +417,58 @@ void DownloadManager::OnPathExistenceAvailable(DownloadCreateInfo* info) {
FOR_EACH_OBSERVER(Observer, observers_, SelectFileDialogDisplayed());
} else {
// No prompting for download, just continue with the suggested name.
- CreateDownloadItem(info, info->suggested_path);
+ AttachDownloadItem(info, info->suggested_path);
}
}
-void DownloadManager::CreateDownloadItem(DownloadCreateInfo* info,
+void DownloadManager::CreateDownloadItem(DownloadCreateInfo* info) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ DownloadItem* download = new DownloadItem(this, *info,
+ profile_->IsOffTheRecord());
+ DCHECK(!ContainsKey(in_progress_, info->download_id));
+ downloads_.insert(download);
+}
+
+void DownloadManager::AttachDownloadItem(DownloadCreateInfo* info,
const FilePath& target_path) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
scoped_ptr<DownloadCreateInfo> infop(info);
info->path = target_path;
- DownloadItem* download = new DownloadItem(this, *info,
- profile_->IsOffTheRecord());
+ // NOTE(ahendrickson) We will be adding a new map |active_downloads_|, into
+ // which we will be adding the download as soon as it's created. This will
+ // make this loop unnecessary.
+ // Eventually |active_downloads_| will replace |in_progress_|, but we don't
+ // want to change the semantics yet.
DCHECK(!ContainsKey(in_progress_, info->download_id));
+ DownloadItem* download = NULL;
+ for (std::set<DownloadItem*>::iterator i = downloads_.begin();
+ i != downloads_.end(); ++i) {
+ DownloadItem* item = (*i);
+ if (item && (item->id() == info->download_id)) {
+ download = item;
+ break;
+ }
+ }
+ DCHECK(download != NULL);
+ download->SetFileCheckResults(info->path,
+ info->is_dangerous,
+ info->path_uniquifier,
+ info->prompt_user_for_save_location,
+ info->is_extension_install,
+ info->original_name);
in_progress_[info->download_id] = download;
bool download_finished = ContainsKey(pending_finished_downloads_,
info->download_id);
VLOG(20) << __FUNCTION__ << "()"
+ << " target_path = \"" << target_path.value() << "\""
<< " download_finished = " << download_finished
- << " info = " << info->DebugString();
+ << " info = " << info->DebugString()
+ << " download = " << download->DebugString(true);
if (download_finished || info->is_dangerous) {
// The download has already finished or the download is not safe.
@@ -454,7 +478,8 @@ void DownloadManager::CreateDownloadItem(DownloadCreateInfo* info,
BrowserThread::FILE, FROM_HERE,
NewRunnableMethod(
file_manager_, &DownloadFileManager::OnFinalDownloadName,
- download->id(), target_path, !info->is_dangerous, this));
+ download->id(), target_path, !info->is_dangerous,
+ make_scoped_refptr(this)));
} else {
// The download hasn't finished and it is a safe download. We need to
// rename it to its intermediate '.crdownload' path.
@@ -463,7 +488,7 @@ void DownloadManager::CreateDownloadItem(DownloadCreateInfo* info,
BrowserThread::FILE, FROM_HERE,
NewRunnableMethod(
file_manager_, &DownloadFileManager::OnIntermediateDownloadName,
- download->id(), download_path, this));
+ download->id(), download_path, make_scoped_refptr(this)));
download->Rename(download_path);
}
@@ -537,7 +562,6 @@ void DownloadManager::OnAllDataSaved(int32 download_id, int64 size) {
// anything. When the user notifies us, it will trigger a call to
// ProceedWithFinishedDangerousDownload.
if (download->safety_state() == DownloadItem::DANGEROUS) {
- dangerous_finished_[download_id] = download;
return;
}
@@ -567,18 +591,6 @@ void DownloadManager::DownloadRenamedToFinalName(int download_id,
item->OnDownloadRenamedToFinalName(full_path);
}
-void DownloadManager::DownloadFinished(DownloadItem* download) {
- VLOG(20) << __FUNCTION__ << "()"
- << " download = " << download->DebugString(true);
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // If this was a dangerous download, it has now been approved and must be
- // removed from dangerous_finished_ so it does not get deleted on shutdown.
- dangerous_finished_.erase(download->id());
-
- download->Finished();
-}
-
// Called on the file thread. Renames the downloaded file to its original name.
void DownloadManager::ProceedWithFinishedDangerousDownload(
int64 download_handle,
@@ -617,8 +629,8 @@ void DownloadManager::DangerousDownloadRenamed(int64 download_handle,
<< " success = " << success
<< " new_path = \"" << new_path.value() << "\""
<< " new_path_uniquifier = " << new_path_uniquifier;
- DownloadMap::iterator it = downloads_.find(download_handle);
- if (it == downloads_.end()) {
+ DownloadMap::iterator it = history_downloads_.find(download_handle);
+ if (it == history_downloads_.end()) {
NOTREACHED();
return;
}
@@ -633,7 +645,7 @@ void DownloadManager::DangerousDownloadRenamed(int64 download_handle,
}
// Continue the download finished sequence.
- DownloadFinished(download);
+ download->Finished();
}
void DownloadManager::DownloadCancelled(int32 download_id) {
@@ -714,8 +726,8 @@ void DownloadManager::PauseDownloadRequest(ResourceDispatcherHost* rdh,
}
void DownloadManager::RemoveDownload(int64 download_handle) {
- DownloadMap::iterator it = downloads_.find(download_handle);
- if (it == downloads_.end())
+ DownloadMap::iterator it = history_downloads_.find(download_handle);
+ if (it == history_downloads_.end())
return;
// Make history update.
@@ -723,10 +735,9 @@ void DownloadManager::RemoveDownload(int64 download_handle) {
download_history_->RemoveEntry(download);
// Remove from our tables and delete.
- downloads_.erase(it);
- it = dangerous_finished_.find(download->id());
- if (it != dangerous_finished_.end())
- dangerous_finished_.erase(it);
+ history_downloads_.erase(it);
+ int downloads_count = downloads_.erase(download);
+ DCHECK_EQ(1, downloads_count);
// Tell observers to refresh their views.
NotifyModelChanged();
@@ -738,9 +749,11 @@ int DownloadManager::RemoveDownloadsBetween(const base::Time remove_begin,
const base::Time remove_end) {
download_history_->RemoveEntriesBetween(remove_begin, remove_end);
- DownloadMap::iterator it = downloads_.begin();
+ // All downloads visible to the user will be in the history,
+ // so scan that map.
+ DownloadMap::iterator it = history_downloads_.begin();
std::vector<DownloadItem*> pending_deletes;
- while (it != downloads_.end()) {
+ while (it != history_downloads_.end()) {
DownloadItem* download = it->second;
DownloadItem::DownloadState state = download->state();
if (download->start_time() >= remove_begin &&
@@ -748,13 +761,9 @@ int DownloadManager::RemoveDownloadsBetween(const base::Time remove_begin,
(state == DownloadItem::COMPLETE ||
state == DownloadItem::CANCELLED)) {
// Remove from the map and move to the next in the list.
- downloads_.erase(it++);
+ history_downloads_.erase(it++);
// Also remove it from any completed dangerous downloads.
- DownloadMap::iterator dit = dangerous_finished_.find(download->id());
- if (dit != dangerous_finished_.end())
- dangerous_finished_.erase(dit);
-
pending_deletes.push_back(download);
continue;
@@ -763,12 +772,22 @@ int DownloadManager::RemoveDownloadsBetween(const base::Time remove_begin,
++it;
}
+ // If we aren't deleting anything, we're done.
+ if (pending_deletes.empty())
+ return 0;
+
+ // Remove the chosen downloads from the main owning container.
+ for (std::vector<DownloadItem*>::iterator it = pending_deletes.begin();
+ it != pending_deletes.end(); it++) {
+ downloads_.erase(*it);
+ }
+
// Tell observers to refresh their views.
+ NotifyModelChanged();
+
+ // Delete the download items themselves.
int num_deleted = static_cast<int>(pending_deletes.size());
- if (num_deleted > 0)
- NotifyModelChanged();
- // Delete the download items after updating the observers.
STLDeleteContainerPointers(pending_deletes.begin(), pending_deletes.end());
pending_deletes.clear();
@@ -790,7 +809,10 @@ int DownloadManager::RemoveAllDownloads() {
}
void DownloadManager::SavePageAsDownloadStarted(DownloadItem* download_item) {
- save_page_downloads_.push_back(download_item);
+#if !defined(NDEBUG)
+ save_page_as_downloads_.insert(download_item);
+#endif
+ downloads_.insert(download_item);
}
// Initiate a download of a specific URL. We send the request to the
@@ -836,7 +858,7 @@ bool DownloadManager::ShouldOpenFileBasedOnExtension(
FilePath::StringType extension = path.Extension();
if (extension.empty())
return false;
- if (download_util::IsExecutableExtension(extension))
+ if (!download_util::IsFileExtensionSafe(extension))
return false;
if (Extension::IsExtension(path))
return false;
@@ -884,7 +906,7 @@ void DownloadManager::FileSelected(const FilePath& path,
DownloadCreateInfo* info = reinterpret_cast<DownloadCreateInfo*>(params);
if (info->prompt_user_for_save_location)
last_download_path_ = path.DirName();
- CreateDownloadItem(info, path);
+ AttachDownloadItem(info, path);
}
void DownloadManager::FileSelectionCanceled(void* params) {
@@ -922,8 +944,9 @@ void DownloadManager::OnQueryDownloadEntriesComplete(
std::vector<DownloadCreateInfo>* entries) {
for (size_t i = 0; i < entries->size(); ++i) {
DownloadItem* download = new DownloadItem(this, entries->at(i));
- DCHECK(!ContainsKey(downloads_, download->db_handle()));
- downloads_[download->db_handle()] = download;
+ DCHECK(!ContainsKey(history_downloads_, download->db_handle()));
+ downloads_.insert(download);
+ history_downloads_[download->db_handle()] = download;
VLOG(20) << __FUNCTION__ << "()" << i << ">"
<< " download = " << download->DebugString(true);
}
@@ -932,7 +955,7 @@ void DownloadManager::OnQueryDownloadEntriesComplete(
// Once the new DownloadItem's creation info has been committed to the history
// service, we associate the DownloadItem with the db handle, update our
-// 'downloads_' map and inform observers.
+// 'history_downloads_' map and inform observers.
void DownloadManager::OnCreateDownloadEntryComplete(
DownloadCreateInfo info,
int64 db_handle) {
@@ -956,8 +979,9 @@ void DownloadManager::OnCreateDownloadEntryComplete(
download->set_db_handle(db_handle);
// Insert into our full map.
- DCHECK(downloads_.find(download->db_handle()) == downloads_.end());
- downloads_[download->db_handle()] = download;
+ DCHECK(history_downloads_.find(download->db_handle()) ==
+ history_downloads_.end());
+ history_downloads_[download->db_handle()] = download;
// Show in the appropropriate browser UI.
ShowDownloadInBrowser(info, download);
@@ -1009,8 +1033,8 @@ void DownloadManager::NotifyModelChanged() {
}
DownloadItem* DownloadManager::GetDownloadItem(int id) {
- for (DownloadMap::iterator it = downloads_.begin();
- it != downloads_.end(); ++it) {
+ for (DownloadMap::iterator it = history_downloads_.begin();
+ it != history_downloads_.end(); ++it) {
DownloadItem* item = it->second;
if (item->id() == id)
return item;
@@ -1018,6 +1042,51 @@ DownloadItem* DownloadManager::GetDownloadItem(int id) {
return NULL;
}
+// Confirm that everything in all maps is also in |downloads_|, and that
+// everything in |downloads_| is also in some other map.
+void DownloadManager::AssertContainersConsistent() const {
+#if !defined(NDEBUG)
+ // Turn everything into sets.
+ DownloadSet in_progress_set, history_set;
+ const DownloadMap* input_maps[] = {&in_progress_, &history_downloads_};
+ DownloadSet* local_sets[] = {&in_progress_set, &history_set};
+ DCHECK_EQ(ARRAYSIZE_UNSAFE(input_maps), ARRAYSIZE_UNSAFE(local_sets));
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(input_maps); i++) {
+ for (DownloadMap::const_iterator it = input_maps[i]->begin();
+ it != input_maps[i]->end(); it++) {
+ local_sets[i]->insert(&*it->second);
+ }
+ }
+
+ // Check if each set is fully present in downloads, and create a union.
+ const DownloadSet* all_sets[] = {&in_progress_set, &history_set,
+ &save_page_as_downloads_};
+ DownloadSet downloads_union;
+ for (int i = 0; i < static_cast<int>(ARRAYSIZE_UNSAFE(all_sets)); i++) {
+ DownloadSet remainder;
+ std::insert_iterator<DownloadSet> insert_it(remainder, remainder.begin());
+ std::set_difference(all_sets[i]->begin(), all_sets[i]->end(),
+ downloads_.begin(), downloads_.end(),
+ insert_it);
+ DCHECK(remainder.empty());
+ std::insert_iterator<DownloadSet>
+ insert_union(downloads_union, downloads_union.end());
+ std::set_union(downloads_union.begin(), downloads_union.end(),
+ all_sets[i]->begin(), all_sets[i]->end(),
+ insert_union);
+ }
+
+ // Is everything in downloads_ present in one of the other sets?
+ DownloadSet remainder;
+ std::insert_iterator<DownloadSet>
+ insert_remainder(remainder, remainder.begin());
+ std::set_difference(downloads_.begin(), downloads_.end(),
+ downloads_union.begin(), downloads_union.end(),
+ insert_remainder);
+ DCHECK(remainder.empty());
+#endif
+}
+
// DownloadManager::OtherDownloadManagerObserver implementation ----------------
DownloadManager::OtherDownloadManagerObserver::OtherDownloadManagerObserver(
diff --git a/chrome/browser/download/download_manager.h b/chrome/browser/download/download_manager.h
index e5f08bf..4f5ebcf 100644
--- a/chrome/browser/download/download_manager.h
+++ b/chrome/browser/download/download_manager.h
@@ -189,6 +189,9 @@ class DownloadManager
DownloadPrefs* download_prefs() { return download_prefs_.get(); }
+ // Creates the download item. Must be called on the UI thread.
+ void CreateDownloadItem(DownloadCreateInfo* info);
+
// Clears the last download path, used to initialize "save as" dialogs.
void ClearLastDownloadPath();
@@ -208,13 +211,6 @@ class DownloadManager
// Called when the user has validated the download of a dangerous file.
void DangerousDownloadValidated(DownloadItem* download);
- // Performs the last steps required when a download has been completed.
- // It is necessary to break down the flow when a download is finished as
- // dangerous downloads are downloaded to temporary files that need to be
- // renamed on the file thread first.
- // Invoked on the UI thread.
- void DownloadFinished(DownloadItem* download);
-
private:
// This class is used to let an incognito DownloadManager observe changes to
// a normal DownloadManager, to propagate ModelChanged() calls from the parent
@@ -256,7 +252,7 @@ class DownloadManager
// Called back after a target path for the file to be downloaded to has been
// determined, either automatically based on the suggested file name, or by
// the user in a Save As dialog box.
- void CreateDownloadItem(DownloadCreateInfo* info,
+ void AttachDownloadItem(DownloadCreateInfo* info,
const FilePath& target_path);
// Download cancel helper function.
@@ -296,38 +292,49 @@ class DownloadManager
DownloadItem* GetDownloadItem(int id);
- // 'downloads_' is map of all downloads in this profile. The key is the handle
- // returned by the history system, which is unique across sessions. This map
- // owns all the DownloadItems once they have been created in the history
- // system.
+ // Debugging routine to confirm relationship between below
+ // containers; no-op if NDEBUG.
+ void AssertContainersConsistent() const;
+
+ // |downloads_| is the owning set for all downloads known to the
+ // DownloadManager. This includes downloads started by the user in
+ // this session, downloads initialized from the history system, and
+ // "save page as" downloads. All other DownloadItem containers in
+ // the DownloadManager are maps; they do not own the DownloadItems.
+ // Note that this is the only place (with any functional implications;
+ // see save_page_as_downloads_ below) that "save page as" downloads are
+ // kept, as the DownloadManager's only job is to hold onto those
+ // until destruction.
+ //
+ // |history_downloads_| is map of all downloads in this profile. The key
+ // is the handle returned by the history system, which is unique
+ // across sessions.
//
- // 'in_progress_' is a map of all downloads that are in progress and that have
+ // |in_progress_| is a map of all downloads that are in progress and that have
// not yet received a valid history handle. The key is the ID assigned by the
- // ResourceDispatcherHost, which is unique for the current session. This map
- // does not own the DownloadItems.
+ // ResourceDispatcherHost, which is unique for the current session.
//
- // 'dangerous_finished_' is a map of dangerous download that have finished
- // but were not yet approved by the user. Similarly to in_progress_, the key
- // is the ID assigned by the ResourceDispatcherHost and the map does not own
- // the DownloadItems. It is used on shutdown to delete completed downloads
- // that have not been approved.
+ // |save_page_as_downloads_| (if defined) is a collection of all the
+ // downloads the "save page as" system has given to us to hold onto
+ // until we are destroyed. It is only used for debugging.
//
// When a download is created through a user action, the corresponding
- // DownloadItem* is placed in 'in_progress_' and remains there until it has
+ // DownloadItem* is placed in |in_progress_| and remains there until it has
// received a valid handle from the history system. Once it has a valid
- // handle, the DownloadItem* is placed in the 'downloads_' map. When the
- // download is complete, it is removed from 'in_progress_'. Downloads from
- // past sessions read from a persisted state from the history system are
- // placed directly into 'downloads_' since they have valid handles in the
- // history system.
+ // handle, the DownloadItem* is placed in the |history_downloads_|
+ // map. When the download is complete, it is removed from
+ // |in_progress_|. Downloads from past sessions read from a
+ // persisted state from the history system are placed directly into
+ // |history_downloads_| since they have valid handles in the history system.
+ typedef std::set<DownloadItem*> DownloadSet;
typedef base::hash_map<int64, DownloadItem*> DownloadMap;
- DownloadMap downloads_;
- DownloadMap in_progress_;
- DownloadMap dangerous_finished_;
- // Collection of all save-page-as downloads in this profile.
- // It owns the DownloadItems.
- std::vector<DownloadItem*> save_page_downloads_;
+ DownloadSet downloads_;
+ DownloadMap history_downloads_;
+ DownloadMap in_progress_;
+#if !defined(NDEBUG)
+ DownloadSet save_page_as_downloads_;
+#endif
// True if the download manager has been initialized and requires a shutdown.
bool shutdown_needed_;
diff --git a/chrome/browser/download/download_manager_unittest.cc b/chrome/browser/download/download_manager_unittest.cc
index fdb088d..210788d 100644
--- a/chrome/browser/download/download_manager_unittest.cc
+++ b/chrome/browser/download/download_manager_unittest.cc
@@ -247,6 +247,8 @@ TEST_F(DownloadManagerTest, DownloadRenameTest) {
if (kDownloadRenameCases[i].will_delete_crdownload)
EXPECT_CALL(*download, DeleteCrDownload()).Times(1);
+ download_manager_->CreateDownloadItem(info);
+
if (kDownloadRenameCases[i].finish_before_rename) {
download_manager_->OnAllDataSaved(i, 1024);
download_manager_->FileSelected(new_path, i, info);
diff --git a/chrome/browser/download/download_prefs.cc b/chrome/browser/download/download_prefs.cc
index 8673e0a..b4f9ddc 100644
--- a/chrome/browser/download/download_prefs.cc
+++ b/chrome/browser/download/download_prefs.cc
@@ -9,6 +9,8 @@
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
#include "base/utf_string_conversions.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/download/download_extensions.h"
#include "chrome/browser/download/download_util.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/pref_names.h"
@@ -30,7 +32,7 @@ DownloadPrefs::DownloadPrefs(PrefService* prefs) : prefs_(prefs) {
#elif defined(OS_WIN)
FilePath path(UTF8ToWide(extensions[i]));
#endif
- if (!extensions[i].empty() && !download_util::IsExecutableFile(path))
+ if (!extensions[i].empty() && download_util::IsFileSafe(path))
auto_open_.insert(path.value());
}
}
@@ -87,7 +89,7 @@ bool DownloadPrefs::EnableAutoOpenBasedOnExtension(const FilePath& file_name) {
return false;
DCHECK(extension[0] == FilePath::kExtensionSeparator);
extension.erase(0, 1);
- if (download_util::IsExecutableExtension(extension))
+ if (!download_util::IsFileExtensionSafe(extension))
return false;
auto_open_.insert(extension);
diff --git a/chrome/browser/download/download_request_limiter.cc b/chrome/browser/download/download_request_limiter.cc
index 89d7697..fae07c9 100644
--- a/chrome/browser/download/download_request_limiter.cc
+++ b/chrome/browser/download/download_request_limiter.cc
@@ -12,7 +12,7 @@
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
// TabDownloadState ------------------------------------------------------------
diff --git a/chrome/browser/download/download_request_limiter.h b/chrome/browser/download/download_request_limiter.h
index 4a685e3..f27438c 100644
--- a/chrome/browser/download/download_request_limiter.h
+++ b/chrome/browser/download/download_request_limiter.h
@@ -131,9 +131,9 @@ class DownloadRequestLimiter
private:
// NotificationObserver method.
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
// Notifies the callbacks as to whether the download is allowed or not.
// Updates status_ appropriately.
diff --git a/chrome/browser/download/download_shelf.cc b/chrome/browser/download/download_shelf.cc
index 8d11e9a..3380789 100644
--- a/chrome/browser/download/download_shelf.cc
+++ b/chrome/browser/download/download_shelf.cc
@@ -27,6 +27,10 @@ DownloadShelfContextMenu::DownloadShelfContextMenu(
DownloadShelfContextMenu::~DownloadShelfContextMenu() {
}
+DownloadItem* DownloadShelfContextMenu::download() const {
+ return download_;
+}
+
bool DownloadShelfContextMenu::IsCommandIdChecked(int command_id) const {
switch (command_id) {
case OPEN_WHEN_COMPLETE:
@@ -110,7 +114,7 @@ bool DownloadShelfContextMenu::GetAcceleratorForCommandId(
return false;
}
-bool DownloadShelfContextMenu::IsLabelForCommandIdDynamic(
+bool DownloadShelfContextMenu::IsItemForCommandIdDynamic(
int command_id) const {
return command_id == TOGGLE_PAUSE;
}
diff --git a/chrome/browser/download/download_shelf.h b/chrome/browser/download/download_shelf.h
index b6ee780..ab565fa 100644
--- a/chrome/browser/download/download_shelf.h
+++ b/chrome/browser/download/download_shelf.h
@@ -48,7 +48,7 @@ class DownloadShelfContextMenu : public menus::SimpleMenuModel::Delegate {
public:
virtual ~DownloadShelfContextMenu();
- virtual DownloadItem* download() const { return download_; }
+ virtual DownloadItem* download() const;
enum ContextMenuCommands {
SHOW_IN_FOLDER = 1, // Open a file explorer window with the item selected.
@@ -73,7 +73,7 @@ class DownloadShelfContextMenu : public menus::SimpleMenuModel::Delegate {
virtual void ExecuteCommand(int command_id);
virtual bool GetAcceleratorForCommandId(int command_id,
menus::Accelerator* accelerator);
- virtual bool IsLabelForCommandIdDynamic(int command_id) const;
+ virtual bool IsItemForCommandIdDynamic(int command_id) const;
virtual string16 GetLabelForCommandId(int command_id) const;
// A model to control the cancel behavior.
diff --git a/chrome/browser/download/download_uitest.cc b/chrome/browser/download/download_uitest.cc
index c92ef6d..aed2f6c 100644
--- a/chrome/browser/download/download_uitest.cc
+++ b/chrome/browser/download/download_uitest.cc
@@ -121,7 +121,7 @@ class DownloadTest : public UITest {
// Download a file with non-viewable content, verify that the
// download tab opened and the file exists.
// All download tests are flaky on all platforms, http://crbug.com/35275,
-// http://crbug.com/48913 and especially http://crbug.com/50060.
+// http://crbug.com/48913.
// Additionally, there is Windows-specific flake, http://crbug.com/20809.
TEST_F(DownloadTest, DISABLED_DownloadMimeType) {
FilePath file(FILE_PATH_LITERAL("download-test1.lib"));
@@ -143,7 +143,7 @@ TEST_F(DownloadTest, DISABLED_DownloadMimeType) {
// Access a file with a viewable mime-type, verify that a download
// did not initiate.
// All download tests are flaky on all platforms, http://crbug.com/35275,
-// http://crbug.com/48913 and especially http://crbug.com/50060.
+// http://crbug.com/48913.
// Additionally, there is Windows-specific flake, http://crbug.com/20809.
TEST_F(DownloadTest, FLAKY_NoDownload) {
FilePath file(FILE_PATH_LITERAL("download-test2.html"));
@@ -169,7 +169,7 @@ TEST_F(DownloadTest, FLAKY_NoDownload) {
// download tab opened and the file exists as the filename specified in the
// header. This also ensures we properly handle empty file downloads.
// All download tests are flaky on all platforms, http://crbug.com/35275,
-// http://crbug.com/48913 and especially http://crbug.com/50060.
+// http://crbug.com/48913.
// Additionally, there is Windows-specific flake, http://crbug.com/20809.
TEST_F(DownloadTest, DISABLED_ContentDisposition) {
FilePath file(FILE_PATH_LITERAL("download-test3.gif"));
@@ -192,7 +192,7 @@ TEST_F(DownloadTest, DISABLED_ContentDisposition) {
// and checking that the shelf is closed.
// See bug http://crbug.com/26325
// All download tests are flaky on all platforms, http://crbug.com/35275,
-// http://crbug.com/48913 and especially http://crbug.com/50060.
+// http://crbug.com/48913.
// Additionally, there is Windows-specific flake, http://crbug.com/20809.
TEST_F(DownloadTest, DISABLED_PerWindowShelf) {
FilePath file(FILE_PATH_LITERAL("download-test3.gif"));
@@ -235,7 +235,7 @@ TEST_F(DownloadTest, DISABLED_PerWindowShelf) {
// in the middle until the server receives a second request for
// "download-finish. At that time, the download will finish.
// All download tests are flaky on all platforms, http://crbug.com/35275,
-// http://crbug.com/48913 and especially http://crbug.com/50060.
+// http://crbug.com/48913.
// Additionally, there is Windows-specific flake, http://crbug.com/20809.
TEST_F(DownloadTest, FLAKY_UnknownSize) {
GURL url(URLRequestSlowDownloadJob::kUnknownSizeUrl);
@@ -247,7 +247,7 @@ TEST_F(DownloadTest, FLAKY_UnknownSize) {
}
// All download tests are flaky on all platforms, http://crbug.com/35275,
-// http://crbug.com/48913 and especially http://crbug.com/50060.
+// http://crbug.com/48913.
// Additionally, there is Windows-specific flake, http://crbug.com/20809.
TEST_F(DownloadTest, FLAKY_KnownSize) {
GURL url(URLRequestSlowDownloadJob::kKnownSizeUrl);
@@ -261,7 +261,7 @@ TEST_F(DownloadTest, FLAKY_KnownSize) {
// Test that when downloading an item in Incognito mode, we don't crash when
// closing the last Incognito window (http://crbug.com/13983).
// All download tests are flaky on all platforms, http://crbug.com/35275,
-// http://crbug.com/48913 and especially http://crbug.com/50060.
+// http://crbug.com/48913.
// Additionally, there is Windows-specific flake, http://crbug.com/20809.
TEST_F(DownloadTest, DISABLED_IncognitoDownload) {
// Open a regular window and sanity check default values for window / tab
@@ -310,7 +310,7 @@ TEST_F(DownloadTest, DISABLED_IncognitoDownload) {
// All of the following tests are disabled, see http://crbug.com/43066
// All download tests are flaky on all platforms, http://crbug.com/35275,
-// http://crbug.com/48913 and especially http://crbug.com/50060.
+// http://crbug.com/48913.
// Additionally, there is Windows-specific flake, http://crbug.com/20809.
TEST_F(DownloadTest, FLAKY_DontCloseNewTab1) {
scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
@@ -332,7 +332,7 @@ TEST_F(DownloadTest, FLAKY_DontCloseNewTab1) {
}
// All download tests are flaky on all platforms, http://crbug.com/35275,
-// http://crbug.com/48913 and especially http://crbug.com/50060.
+// http://crbug.com/48913.
// Additionally, there is Windows-specific flake, http://crbug.com/20809.
TEST_F(DownloadTest, FLAKY_CloseNewTab1) {
scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
@@ -359,7 +359,7 @@ TEST_F(DownloadTest, FLAKY_CloseNewTab1) {
// Disabled, see http://crbug.com/43066
// All download tests are flaky on all platforms, http://crbug.com/35275,
-// http://crbug.com/48913 and especially http://crbug.com/50060.
+// http://crbug.com/48913.
// Additionally, there is Windows-specific flake, http://crbug.com/20809.
TEST_F(DownloadTest, FLAKY_DontCloseNewTab2) {
scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
@@ -387,7 +387,7 @@ TEST_F(DownloadTest, FLAKY_DontCloseNewTab2) {
// Flaky, see http://crbug.com/43066
// All download tests are flaky on all platforms, http://crbug.com/35275,
-// http://crbug.com/48913 and especially http://crbug.com/50060.
+// http://crbug.com/48913.
// Additionally, there is Windows-specific flake, http://crbug.com/20809.
TEST_F(DownloadTest, FLAKY_DontCloseNewTab3) {
scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
@@ -418,7 +418,7 @@ TEST_F(DownloadTest, FLAKY_DontCloseNewTab3) {
// Flaky, see http://crbug.com/43066
// All download tests are flaky on all platforms, http://crbug.com/35275,
-// http://crbug.com/48913 and especially http://crbug.com/50060.
+// http://crbug.com/48913.
// Additionally, there is Windows-specific flake, http://crbug.com/20809.
TEST_F(DownloadTest, FLAKY_CloseNewTab2) {
scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
@@ -446,7 +446,7 @@ TEST_F(DownloadTest, FLAKY_CloseNewTab2) {
// Flaky, see http://crbug.com/43066
// All download tests are flaky on all platforms, http://crbug.com/35275,
-// http://crbug.com/48913 and especially http://crbug.com/50060.
+// http://crbug.com/48913.
// Additionally, there is Windows-specific flake, http://crbug.com/20809.
TEST_F(DownloadTest, FLAKY_CloseNewTab3) {
scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
@@ -474,7 +474,7 @@ TEST_F(DownloadTest, FLAKY_CloseNewTab3) {
}
// All download tests are flaky on all platforms, http://crbug.com/35275,
-// http://crbug.com/48913 and especially http://crbug.com/50060.
+// http://crbug.com/48913.
// Additionally, there is Windows-specific flake, http://crbug.com/20809.
TEST_F(DownloadTest, DISABLED_DontCloseNewWindow) {
scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
@@ -498,9 +498,8 @@ TEST_F(DownloadTest, DISABLED_DontCloseNewWindow) {
}
// Regression test for http://crbug.com/44454
-// See also http://crbug.com/50060.
// All download tests are flaky on all platforms, http://crbug.com/35275,
-// http://crbug.com/48913 and especially http://crbug.com/50060.
+// http://crbug.com/48913.
// Additionally, there is Windows-specific flake, http://crbug.com/20809.
TEST_F(DownloadTest, DISABLED_NewWindow) {
scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
diff --git a/chrome/browser/download/download_util.cc b/chrome/browser/download/download_util.cc
index 082845c..c7babd3 100644
--- a/chrome/browser/download/download_util.cc
+++ b/chrome/browser/download/download_util.cc
@@ -16,8 +16,8 @@
#include "base/file_util.h"
#include "base/i18n/rtl.h"
#include "base/i18n/time_formatting.h"
+#include "base/lazy_instance.h"
#include "base/path_service.h"
-#include "base/singleton.h"
#include "base/string16.h"
#include "base/string_number_conversions.h"
#include "base/stringprintf.h"
@@ -26,18 +26,17 @@
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "base/win/windows_version.h"
-#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/download/download_extensions.h"
#include "chrome/browser/download/download_item.h"
#include "chrome/browser/download/download_item_model.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/extensions/crx_installer.h"
#include "chrome/browser/extensions/extension_install_ui.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/history/download_create_info.h"
#include "chrome/browser/net/chrome_url_request_context.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"
@@ -109,12 +108,15 @@ class DefaultDownloadDirectory {
}
}
}
- friend struct DefaultSingletonTraits<DefaultDownloadDirectory>;
+ friend struct base::DefaultLazyInstanceTraits<DefaultDownloadDirectory>;
FilePath path_;
};
+static base::LazyInstance<DefaultDownloadDirectory>
+ g_default_download_directory(base::LINKER_INITIALIZED);
+
const FilePath& GetDefaultDownloadDirectory() {
- return Singleton<DefaultDownloadDirectory>::get()->path();
+ return g_default_download_directory.Get().path();
}
bool CreateTemporaryFileForDownload(FilePath* temp_file) {
@@ -230,7 +232,7 @@ void OpenChromeExtension(Profile* profile,
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(download_item.is_extension_install());
- ExtensionsService* service = profile->GetExtensionsService();
+ ExtensionService* service = profile->GetExtensionService();
CHECK(service);
NotificationService* nservice = NotificationService::current();
GURL nonconst_download_url = download_item.url();
@@ -437,7 +439,7 @@ void DragDownload(const DownloadItem* download,
if (icon) {
drag_utils::CreateDragImageForFile(
- download->GetFileNameToReportUser().value(), icon, &data);
+ download->GetFileNameToReportUser(), icon, &data);
}
const FilePath full_path = download->full_path();
@@ -487,7 +489,7 @@ DictionaryValue* CreateDownloadItemValue(DownloadItem* download, int id) {
file_value->SetString("since_string",
TimeFormat::RelativeDate(download->start_time(), NULL));
file_value->SetString("date_string",
- WideToUTF16Hack(base::TimeFormatShortDate(download->start_time())));
+ base::TimeFormatShortDate(download->start_time()));
file_value->SetInteger("id", id);
file_value->SetString("file_path",
WideToUTF16Hack(download->GetTargetFilePath().ToWStringHack()));
@@ -699,7 +701,7 @@ void DeleteUniqueDownloadFile(const FilePath& path, int index) {
file_util::Delete(new_path, false);
}
-}
+} // namespace
void EraseUniqueDownloadFiles(const FilePath& path) {
FilePath cr_path = GetCrDownloadPath(path);
@@ -721,18 +723,22 @@ FilePath GetCrDownloadPath(const FilePath& suggested_path) {
// TODO(erikkay,phajdan.jr): This is apparently not being exercised in tests.
bool IsDangerous(DownloadCreateInfo* info, Profile* profile) {
- // Downloads can be marked as dangerous for two reasons:
- // a) They have a dangerous-looking filename
- // b) They are an extension that is not from the gallery
- if (IsExecutableFile(info->suggested_path.BaseName())) {
+ DownloadDangerLevel danger_level = GetFileDangerLevel(
+ info->suggested_path.BaseName());
+
+ if (danger_level == Dangerous) {
+ return true;
+ } else if (danger_level == AllowOnUserGesture && !info->has_user_gesture) {
return true;
} else if (info->is_extension_install) {
- ExtensionsService* service = profile->GetExtensionsService();
+ ExtensionService* service = profile->GetExtensionService();
if (!service ||
!service->IsDownloadFromGallery(info->url, info->referrer_url)) {
+ // Extensions that are not from the gallery are considered dangerous.
return true;
}
}
+
return false;
}
diff --git a/chrome/browser/download/download_util.h b/chrome/browser/download/download_util.h
index 0224a26..0a0bd90 100644
--- a/chrome/browser/download/download_util.h
+++ b/chrome/browser/download/download_util.h
@@ -150,17 +150,6 @@ void DragDownload(const DownloadItem* download,
SkBitmap* icon,
gfx::NativeView view);
-// Executable file support -----------------------------------------------------
-
-// Tests if a file is considered executable, based on its type.
-bool IsExecutableFile(const FilePath& path);
-
-// Determine if the specified extension is an executable extension.
-bool IsExecutableExtension(const FilePath::StringType& extension);
-
-// Tests if we think the server means for this mime_type to be executable.
-bool IsExecutableMimeType(const std::string& mime_type);
-
// Helpers ---------------------------------------------------------------------
// Creates a representation of a download in a format that the downloads
diff --git a/chrome/browser/download/drag_download_file.cc b/chrome/browser/download/drag_download_file.cc
index 709c735..3426ef7 100644
--- a/chrome/browser/download/drag_download_file.cc
+++ b/chrome/browser/download/drag_download_file.cc
@@ -9,7 +9,7 @@
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/download/download_file.h"
#include "chrome/browser/download/download_item.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "net/base/file_stream.h"
diff --git a/chrome/browser/download/save_package.cc b/chrome/browser/download/save_package.cc
index ba608e4..7bda1bb 100644
--- a/chrome/browser/download/save_package.cc
+++ b/chrome/browser/download/save_package.cc
@@ -32,7 +32,7 @@
#include "chrome/browser/platform_util.h"
#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
diff --git a/chrome/browser/download/save_package.h b/chrome/browser/download/save_package.h
index e7080a8..ddfc172 100644
--- a/chrome/browser/download/save_package.h
+++ b/chrome/browser/download/save_package.h
@@ -256,7 +256,7 @@ class SavePackage : public base::RefCountedThreadSafe<SavePackage>,
SavedItemMap saved_success_items_;
// The request context which provides application-specific context for
- // URLRequest instances.
+ // net::URLRequest instances.
scoped_refptr<URLRequestContextGetter> request_context_getter_;
// Non-owning pointer for handling file writing on the file thread.
diff --git a/chrome/browser/encoding_menu_controller.cc b/chrome/browser/encoding_menu_controller.cc
deleted file mode 100644
index 7d3a89e..0000000
--- a/chrome/browser/encoding_menu_controller.cc
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/encoding_menu_controller.h"
-
-#include "app/l10n_util.h"
-#include "base/i18n/rtl.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/character_encoding.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/common/pref_names.h"
-#include "grit/generated_resources.h"
-
-const int EncodingMenuController::kValidEncodingIds[] = {
- IDC_ENCODING_UTF8,
- IDC_ENCODING_UTF16LE,
- IDC_ENCODING_ISO88591,
- IDC_ENCODING_WINDOWS1252,
- IDC_ENCODING_GBK,
- IDC_ENCODING_GB18030,
- IDC_ENCODING_BIG5,
- IDC_ENCODING_BIG5HKSCS,
- IDC_ENCODING_KOREAN,
- IDC_ENCODING_SHIFTJIS,
- IDC_ENCODING_ISO2022JP,
- IDC_ENCODING_EUCJP,
- IDC_ENCODING_THAI,
- IDC_ENCODING_ISO885915,
- IDC_ENCODING_MACINTOSH,
- IDC_ENCODING_ISO88592,
- IDC_ENCODING_WINDOWS1250,
- IDC_ENCODING_ISO88595,
- IDC_ENCODING_WINDOWS1251,
- IDC_ENCODING_KOI8R,
- IDC_ENCODING_KOI8U,
- IDC_ENCODING_ISO88597,
- IDC_ENCODING_WINDOWS1253,
- IDC_ENCODING_ISO88594,
- IDC_ENCODING_ISO885913,
- IDC_ENCODING_WINDOWS1257,
- IDC_ENCODING_ISO88593,
- IDC_ENCODING_ISO885910,
- IDC_ENCODING_ISO885914,
- IDC_ENCODING_ISO885916,
- IDC_ENCODING_WINDOWS1254,
- IDC_ENCODING_ISO88596,
- IDC_ENCODING_WINDOWS1256,
- IDC_ENCODING_ISO88598,
- IDC_ENCODING_WINDOWS1255,
- IDC_ENCODING_WINDOWS1258,
- IDC_ENCODING_ISO88598I,
-};
-
-bool EncodingMenuController::DoesCommandBelongToEncodingMenu(int id) {
- if (id == IDC_ENCODING_AUTO_DETECT) {
- return true;
- }
-
- for (size_t i = 0; i < arraysize(kValidEncodingIds); ++i) {
- if (id == kValidEncodingIds[i]) {
- return true;
- }
- }
-
- return false;
-}
-
-const int* EncodingMenuController::ValidGUIEncodingIDs() {
- return kValidEncodingIds;
-}
-
-int EncodingMenuController::NumValidGUIEncodingIDs() {
- return arraysize(kValidEncodingIds);
-}
-
-bool EncodingMenuController::IsItemChecked(
- Profile* browser_profile,
- const std::string& current_tab_encoding,
- int item_id) {
- if (!DoesCommandBelongToEncodingMenu(item_id))
- return false;
-
- std::string encoding = current_tab_encoding;
- if (encoding.empty())
- encoding = browser_profile->GetPrefs()->GetString(prefs::kDefaultCharset);
-
- if (item_id == IDC_ENCODING_AUTO_DETECT) {
- return browser_profile->GetPrefs()->GetBoolean(
- prefs::kWebKitUsesUniversalDetector);
- }
-
- if (!encoding.empty()) {
- return encoding ==
- CharacterEncoding::GetCanonicalEncodingNameByCommandId(item_id);
- }
-
- return false;
-}
-
-void EncodingMenuController::GetEncodingMenuItems(Profile* profile,
- EncodingMenuItemList* menuItems) {
-
- DCHECK(menuItems);
- EncodingMenuItem separator(0, string16());
-
- menuItems->clear();
- menuItems->push_back(
- EncodingMenuItem(IDC_ENCODING_AUTO_DETECT,
- l10n_util::GetStringUTF16(IDS_ENCODING_AUTO_DETECT)));
- menuItems->push_back(separator);
-
- // Create current display encoding list.
- const std::vector<CharacterEncoding::EncodingInfo>* encodings;
-
- // Build the list of encoding ids : It is made of the
- // locale-dependent short list, the cache of recently selected
- // encodings and other encodings.
- encodings = CharacterEncoding::GetCurrentDisplayEncodings(
- g_browser_process->GetApplicationLocale(),
- profile->GetPrefs()->GetString(prefs::kStaticEncodings),
- profile->GetPrefs()->GetString(prefs::kRecentlySelectedEncoding));
- DCHECK(encodings);
- DCHECK(!encodings->empty());
-
- // Build up output list for menu.
- std::vector<CharacterEncoding::EncodingInfo>::const_iterator it;
- for (it = encodings->begin(); it != encodings->end(); ++it) {
- if (it->encoding_id) {
- std::wstring encoding = it->encoding_display_name;
- base::i18n::AdjustStringForLocaleDirection(&encoding);
- menuItems->push_back(EncodingMenuItem(it->encoding_id,
- WideToUTF16(encoding)));
- } else {
- menuItems->push_back(separator);
- }
- }
-}
diff --git a/chrome/browser/encoding_menu_controller.h b/chrome/browser/encoding_menu_controller.h
deleted file mode 100644
index fc907f8..0000000
--- a/chrome/browser/encoding_menu_controller.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_ENCODING_MENU_CONTROLLER_H_
-#define CHROME_BROWSER_ENCODING_MENU_CONTROLLER_H_
-#pragma once
-
-#include <utility>
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h" // For DISALLOW_COPY_AND_ASSIGN
-#include "base/gtest_prod_util.h"
-#include "base/string16.h"
-
-class Profile;
-
-// Cross-platform logic needed for the encoding menu.
-// For now, we don't need to track state so all methods are static.
-class EncodingMenuController {
- FRIEND_TEST_ALL_PREFIXES(EncodingMenuControllerTest, EncodingIDsBelongTest);
- FRIEND_TEST_ALL_PREFIXES(EncodingMenuControllerTest, IsItemChecked);
-
- public:
- typedef std::pair<int, string16> EncodingMenuItem;
- typedef std::vector<EncodingMenuItem> EncodingMenuItemList;
-
- public:
- EncodingMenuController() {}
-
- // Given a command ID, does this command belong to the encoding menu?
- bool DoesCommandBelongToEncodingMenu(int id);
-
- // Returns true if the given encoding menu item (specified by item_id)
- // is checked. Note that this header is included from objc, where the name
- // "id" is reserved.
- bool IsItemChecked(Profile* browser_profile,
- const std::string& current_tab_encoding,
- int item_id);
-
- // Fills in a list of menu items in the order they should appear in the menu.
- // Items whose ids are 0 are separators.
- void GetEncodingMenuItems(Profile* profile,
- EncodingMenuItemList* menuItems);
-
- private:
- // List of all valid encoding GUI IDs.
- static const int kValidEncodingIds[];
- const int* ValidGUIEncodingIDs();
- int NumValidGUIEncodingIDs();
-
- DISALLOW_COPY_AND_ASSIGN(EncodingMenuController);
-};
-
-#endif // CHROME_BROWSER_ENCODING_MENU_CONTROLLER_H_
diff --git a/chrome/browser/encoding_menu_controller_unittest.cc b/chrome/browser/encoding_menu_controller_unittest.cc
deleted file mode 100644
index ab8b6b5..0000000
--- a/chrome/browser/encoding_menu_controller_unittest.cc
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/encoding_menu_controller.h"
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/test/testing_profile.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-
-class EncodingMenuControllerTest : public testing::Test {
-};
-
-TEST_F(EncodingMenuControllerTest, EncodingIDsBelongTest) {
- EncodingMenuController controller;
-
- // Check some bogus ids to make sure they're never valid.
- ASSERT_FALSE(controller.DoesCommandBelongToEncodingMenu(0));
- ASSERT_FALSE(controller.DoesCommandBelongToEncodingMenu(-1));
-
- int num_valid_encoding_ids = controller.NumValidGUIEncodingIDs();
- const int* valid_encodings = controller.ValidGUIEncodingIDs();
- ASSERT_TRUE(controller.DoesCommandBelongToEncodingMenu(
- IDC_ENCODING_AUTO_DETECT));
- // Check that all valid encodings are accepted.
- for (int i = 0; i < num_valid_encoding_ids; ++i) {
- ASSERT_TRUE(controller.DoesCommandBelongToEncodingMenu(valid_encodings[i]));
- }
-
- // This test asserts that we haven't added a new valid ID without including it
- // in the kValidEncodingIds test list above.
- // The premise is that new encodings will be added directly after the current
- // ones so we'll catch such cases.
- int one_past_largest_id = valid_encodings[num_valid_encoding_ids - 1] + 1;
- ASSERT_FALSE(controller.DoesCommandBelongToEncodingMenu(one_past_largest_id));
-}
-
-TEST_F(EncodingMenuControllerTest, ListEncodingMenuItems) {
- typedef EncodingMenuController::EncodingMenuItemList EncodingMenuItemList;
- EncodingMenuController controller;
-
- EncodingMenuItemList english_items;
- TestingProfile profile_en;
-
- controller.GetEncodingMenuItems(&profile_en, &english_items);
-
- // Make sure there are items in the lists.
- ASSERT_TRUE(english_items.size() > 0);
- // Make sure that autodetect is the first item on both menus
- ASSERT_EQ(english_items[0].first, IDC_ENCODING_AUTO_DETECT);
-}
-
-TEST_F(EncodingMenuControllerTest, IsItemChecked) {
- TestingProfile profile_en;
- std::string encoding("UTF-8");
-
- // Check that enabling and disabling autodetect works.
- bool autodetect_enabed[] = {true, false};
- PrefService* prefs = profile_en.GetPrefs();
- EncodingMenuController controller;
- for (size_t i = 0; i < arraysize(autodetect_enabed); ++i) {
- bool enabled = autodetect_enabed[i];
- prefs->SetBoolean(prefs::kWebKitUsesUniversalDetector, enabled);
- ASSERT_TRUE(controller.IsItemChecked(&profile_en,
- encoding,
- IDC_ENCODING_AUTO_DETECT) == enabled);
- }
-
- // Check all valid encodings, make sure only one is enabled when autodetection
- // is turned off.
- prefs->SetBoolean(prefs::kWebKitUsesUniversalDetector, false);
- bool encoding_is_enabled = false;
- size_t num_valid_encoding_ids = controller.NumValidGUIEncodingIDs();
- const int* valid_encodings = controller.ValidGUIEncodingIDs();
- for (size_t i = 0; i < num_valid_encoding_ids; ++i) {
- bool on = controller.IsItemChecked(&profile_en,
- encoding,
- valid_encodings[i]);
- // Only one item in the encoding menu can be selected at a time.
- ASSERT_FALSE(on && encoding_is_enabled);
- encoding_is_enabled |= on;
- }
-
- // Make sure at least one encoding is enabled.
- ASSERT_TRUE(encoding_is_enabled);
-}
diff --git a/chrome/browser/enumerate_modules_model_win.cc b/chrome/browser/enumerate_modules_model_win.cc
index 9523580..83dc535 100644
--- a/chrome/browser/enumerate_modules_model_win.cc
+++ b/chrome/browser/enumerate_modules_model_win.cc
@@ -266,7 +266,7 @@ ModuleEnumerator::ModuleStatus ModuleEnumerator::Match(
// We have a name match against the blacklist (and possibly location match
// also), so check version.
scoped_ptr<Version> module_version(
- Version::GetVersionFromString(module.version));
+ Version::GetVersionFromString(UTF16ToASCII(module.version)));
scoped_ptr<Version> version_min(
Version::GetVersionFromString(blacklisted.version_from));
scoped_ptr<Version> version_max(
@@ -677,6 +677,11 @@ string16 ModuleEnumerator::GetSubjectNameFromDigitalSignature(
// ----------------------------------------------------------------------------
+// static
+EnumerateModulesModel* EnumerateModulesModel::GetInstance() {
+ return Singleton<EnumerateModulesModel>::get();
+}
+
void EnumerateModulesModel::ScanNow() {
if (scanning_)
return; // A scan is already in progress.
diff --git a/chrome/browser/enumerate_modules_model_win.h b/chrome/browser/enumerate_modules_model_win.h
index c7ed505..1f524c8 100644
--- a/chrome/browser/enumerate_modules_model_win.h
+++ b/chrome/browser/enumerate_modules_model_win.h
@@ -221,9 +221,7 @@ class ModuleEnumerator : public base::RefCountedThreadSafe<ModuleEnumerator> {
// notification.
class EnumerateModulesModel {
public:
- static EnumerateModulesModel* GetSingleton() {
- return Singleton<EnumerateModulesModel>::get();
- }
+ static EnumerateModulesModel* GetInstance();
// Returns the number of suspected bad modules found in the last scan.
// Returns 0 if no scan has taken place yet.
diff --git a/chrome/browser/extensions/alert_apitest.cc b/chrome/browser/extensions/alert_apitest.cc
index 292e1bd..10b310b 100644
--- a/chrome/browser/extensions/alert_apitest.cc
+++ b/chrome/browser/extensions/alert_apitest.cc
@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/app_modal_dialog.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/ui_test_utils.h"
diff --git a/chrome/browser/extensions/all_urls_apitest.cc b/chrome/browser/extensions/all_urls_apitest.cc
index e0e2a4a..522610e 100644
--- a/chrome/browser/extensions/all_urls_apitest.cc
+++ b/chrome/browser/extensions/all_urls_apitest.cc
@@ -3,9 +3,9 @@
// found in the LICENSE file.
#include "chrome/browser/extensions/extension_apitest.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_test_message_listener.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/test/ui_test_utils.h"
@@ -44,7 +44,7 @@ IN_PROC_BROWSER_TEST_F(AllUrlsApiTest, WhitelistedExtension) {
// Then load extensions.
Checkpoint("LoadExtension1", start_time);
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
const size_t size_before = service->extensions()->size();
ASSERT_TRUE(LoadExtension(extension_dir1));
Checkpoint("LoadExtension2", start_time);
@@ -123,7 +123,7 @@ IN_PROC_BROWSER_TEST_F(AllUrlsApiTest, DISABLED_RegularExtensions) {
FilePath extension_dir2 = test_data_dir_.AppendASCII("all_urls")
.AppendASCII("execute_script");
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
const size_t size_before = service->extensions()->size();
ASSERT_TRUE(LoadExtension(extension_dir1));
ASSERT_TRUE(LoadExtension(extension_dir2));
diff --git a/chrome/browser/extensions/app_process_apitest.cc b/chrome/browser/extensions/app_process_apitest.cc
index 1d1b707..dece83c 100644
--- a/chrome/browser/extensions/app_process_apitest.cc
+++ b/chrome/browser/extensions/app_process_apitest.cc
@@ -7,7 +7,7 @@
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_process_manager.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
@@ -84,7 +84,8 @@ IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_AppProcess) {
// The app under test acts on URLs whose host is "localhost",
// so the URLs we navigate to must have host "localhost".
GURL::Replacements replace_host;
- replace_host.SetHostStr("localhost");
+ std::string host_str("localhost"); // must stay in scope with replace_host
+ replace_host.SetHostStr(host_str);
base_url = base_url.ReplaceComponents(replace_host);
browser()->NewTab();
diff --git a/chrome/browser/extensions/autoupdate_interceptor.cc b/chrome/browser/extensions/autoupdate_interceptor.cc
index ef0091f..e919189 100644
--- a/chrome/browser/extensions/autoupdate_interceptor.cc
+++ b/chrome/browser/extensions/autoupdate_interceptor.cc
@@ -15,7 +15,7 @@
// code relies on.
class AutoUpdateTestRequestJob : public URLRequestTestJob {
public:
- AutoUpdateTestRequestJob(URLRequest* request,
+ AutoUpdateTestRequestJob(net::URLRequest* request,
const std::string& response_data) : URLRequestTestJob(
request, URLRequestTestJob::test_headers(), response_data, true) {}
virtual int GetResponseCode() const { return 200; }
@@ -26,15 +26,15 @@ class AutoUpdateTestRequestJob : public URLRequestTestJob {
AutoUpdateInterceptor::AutoUpdateInterceptor() {
- URLRequest::RegisterRequestInterceptor(this);
+ net::URLRequest::RegisterRequestInterceptor(this);
}
AutoUpdateInterceptor::~AutoUpdateInterceptor() {
- URLRequest::UnregisterRequestInterceptor(this);
+ net::URLRequest::UnregisterRequestInterceptor(this);
}
-
-URLRequestJob* AutoUpdateInterceptor::MaybeIntercept(URLRequest* request) {
+net::URLRequestJob* AutoUpdateInterceptor::MaybeIntercept(
+ net::URLRequest* request) {
EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (request->url().scheme() != "http" ||
request->url().host() != "localhost") {
diff --git a/chrome/browser/extensions/autoupdate_interceptor.h b/chrome/browser/extensions/autoupdate_interceptor.h
index 219941a..a2e0891 100644
--- a/chrome/browser/extensions/autoupdate_interceptor.h
+++ b/chrome/browser/extensions/autoupdate_interceptor.h
@@ -15,7 +15,7 @@
// This url request interceptor lets us respond to localhost http request urls
// with the contents of files on disk for use in tests.
class AutoUpdateInterceptor
- : public URLRequest::Interceptor,
+ : public net::URLRequest::Interceptor,
public base::RefCountedThreadSafe<AutoUpdateInterceptor> {
public:
AutoUpdateInterceptor();
diff --git a/chrome/browser/extensions/browser_action_apitest.cc b/chrome/browser/extensions/browser_action_apitest.cc
index 59e56ca..8c413e4 100644
--- a/chrome/browser/extensions/browser_action_apitest.cc
+++ b/chrome/browser/extensions/browser_action_apitest.cc
@@ -13,8 +13,8 @@
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_browser_event_router.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_switches.h"
@@ -286,7 +286,7 @@ IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, IncognitoBasic) {
// Now enable the extension in incognito mode, and test that the browser
// action shows up. Note that we don't update the existing window at the
// moment, so we just create a new one.
- browser()->profile()->GetExtensionsService()->extension_prefs()->
+ browser()->profile()->GetExtensionService()->extension_prefs()->
SetIsIncognitoEnabled(extension->id(), true);
incognito_browser->CloseWindow();
@@ -299,7 +299,7 @@ IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, IncognitoBasic) {
}
IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, IncognitoDragging) {
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
// The tooltips for each respective browser action.
const char kTooltipA[] = "Make this page red";
diff --git a/chrome/browser/extensions/browser_action_test_util_mac.mm b/chrome/browser/extensions/browser_action_test_util_mac.mm
index bc46a88..3b6dcc6 100644
--- a/chrome/browser/extensions/browser_action_test_util_mac.mm
+++ b/chrome/browser/extensions/browser_action_test_util_mac.mm
@@ -5,13 +5,13 @@
#include "browser_action_test_util.h"
#include "base/sys_string_conversions.h"
-#import "chrome/browser/cocoa/browser_window_cocoa.h"
-#import "chrome/browser/cocoa/browser_window_controller.h"
-#import "chrome/browser/cocoa/extensions/browser_actions_controller.h"
-#import "chrome/browser/cocoa/extensions/extension_popup_controller.h"
-#import "chrome/browser/cocoa/info_bubble_window.h"
-#import "chrome/browser/cocoa/toolbar_controller.h"
#include "chrome/browser/ui/browser.h"
+#import "chrome/browser/ui/cocoa/browser_window_cocoa.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "chrome/browser/ui/cocoa/extensions/browser_actions_controller.h"
+#import "chrome/browser/ui/cocoa/extensions/extension_popup_controller.h"
+#import "chrome/browser/ui/cocoa/info_bubble_window.h"
+#import "chrome/browser/ui/cocoa/toolbar_controller.h"
#include "gfx/rect.h"
#include "gfx/size.h"
diff --git a/chrome/browser/extensions/content_script_extension_process_apitest.cc b/chrome/browser/extensions/content_script_extension_process_apitest.cc
index f6748de..100e77b 100644
--- a/chrome/browser/extensions/content_script_extension_process_apitest.cc
+++ b/chrome/browser/extensions/content_script_extension_process_apitest.cc
@@ -3,8 +3,7 @@
// found in the LICENSE file.
#include "chrome/browser/extensions/extension_apitest.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/test/ui_test_utils.h"
diff --git a/chrome/browser/extensions/convert_user_script.cc b/chrome/browser/extensions/convert_user_script.cc
index 89caec4..bcb0f5a 100644
--- a/chrome/browser/extensions/convert_user_script.cc
+++ b/chrome/browser/extensions/convert_user_script.cc
@@ -34,6 +34,11 @@ scoped_refptr<Extension> ConvertUserScriptToExtension(
return NULL;
}
+ if (!IsStringUTF8(content)) {
+ *error = "User script must be UTF8 encoded.";
+ return NULL;
+ }
+
UserScript script;
if (!UserScriptMaster::ScriptReloader::ParseMetadataHeader(content,
&script)) {
diff --git a/chrome/browser/extensions/convert_user_script_unittest.cc b/chrome/browser/extensions/convert_user_script_unittest.cc
index a0e1b8b..e9c73cb 100644
--- a/chrome/browser/extensions/convert_user_script_unittest.cc
+++ b/chrome/browser/extensions/convert_user_script_unittest.cc
@@ -92,3 +92,18 @@ TEST(ExtensionFromUserScript, NoMetdata) {
// Cleanup
file_util::Delete(extension->path(), true);
}
+
+TEST(ExtensionFromUserScript, NotUTF8) {
+ FilePath test_file;
+
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_file));
+ test_file = test_file.AppendASCII("extensions")
+ .AppendASCII("user_script_not_utf8.user.js");
+
+ std::string error;
+ scoped_refptr<Extension> extension(ConvertUserScriptToExtension(
+ test_file, GURL("http://www.google.com/foo/bar.user.js?monkey"), &error));
+
+ ASSERT_FALSE(extension.get());
+ EXPECT_EQ("User script must be UTF8 encoded.", error);
+}
diff --git a/chrome/browser/extensions/convert_web_app.cc b/chrome/browser/extensions/convert_web_app.cc
index 11303ff..e1c8c92 100644
--- a/chrome/browser/extensions/convert_web_app.cc
+++ b/chrome/browser/extensions/convert_web_app.cc
@@ -101,6 +101,9 @@ scoped_refptr<Extension> ConvertWebAppToExtension(
root->SetString(keys::kDescription, UTF16ToUTF8(web_app.description));
root->SetString(keys::kLaunchWebURL, web_app.app_url.spec());
+ if (!web_app.launch_container.empty())
+ root->SetString(keys::kLaunchContainer, web_app.launch_container);
+
// Add the icons.
DictionaryValue* icons = new DictionaryValue();
root->Set(keys::kIcons, icons);
diff --git a/chrome/browser/extensions/convert_web_app_browsertest.cc b/chrome/browser/extensions/convert_web_app_browsertest.cc
index a6cdb19..bb2ea24 100644
--- a/chrome/browser/extensions/convert_web_app_browsertest.cc
+++ b/chrome/browser/extensions/convert_web_app_browsertest.cc
@@ -4,9 +4,9 @@
#include <string>
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_details.h"
@@ -47,7 +47,7 @@ class ExtensionFromWebAppTest
IN_PROC_BROWSER_TEST_F(ExtensionFromWebAppTest, Basic) {
ASSERT_TRUE(test_server()->Start());
- browser()->profile()->GetExtensionsService()->set_show_extensions_prompts(
+ browser()->profile()->GetExtensionService()->set_show_extensions_prompts(
false);
NotificationRegistrar registrar;
@@ -65,4 +65,22 @@ IN_PROC_BROWSER_TEST_F(ExtensionFromWebAppTest, Basic) {
EXPECT_TRUE(installed_extension_);
EXPECT_TRUE(installed_extension_->is_hosted_app());
+ EXPECT_EQ("Test application", installed_extension_->name());
+ EXPECT_EQ("the description is", installed_extension_->description());
+ EXPECT_EQ(extension_misc::LAUNCH_PANEL,
+ installed_extension_->launch_container());
+
+ ASSERT_EQ(2u, installed_extension_->api_permissions().size());
+ EXPECT_TRUE(installed_extension_->api_permissions().find("geolocation") !=
+ installed_extension_->api_permissions().end());
+ EXPECT_TRUE(installed_extension_->api_permissions().find("notifications") !=
+ installed_extension_->api_permissions().end());
+
+ ASSERT_EQ(3u, installed_extension_->icons().map().size());
+ EXPECT_EQ("icons/16.png", installed_extension_->icons().Get(
+ 16, ExtensionIconSet::MATCH_EXACTLY));
+ EXPECT_EQ("icons/48.png", installed_extension_->icons().Get(
+ 48, ExtensionIconSet::MATCH_EXACTLY));
+ EXPECT_EQ("icons/128.png", installed_extension_->icons().Get(
+ 128, ExtensionIconSet::MATCH_EXACTLY));
}
diff --git a/chrome/browser/extensions/crashed_extension_infobar.cc b/chrome/browser/extensions/crashed_extension_infobar.cc
index 053b4b4..fbed6e6 100644
--- a/chrome/browser/extensions/crashed_extension_infobar.cc
+++ b/chrome/browser/extensions/crashed_extension_infobar.cc
@@ -7,7 +7,7 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/common/extensions/extension.h"
#include "grit/browser_resources.h"
#include "grit/generated_resources.h"
@@ -15,7 +15,7 @@
CrashedExtensionInfoBarDelegate::CrashedExtensionInfoBarDelegate(
TabContents* tab_contents,
- ExtensionsService* extensions_service,
+ ExtensionService* extensions_service,
const Extension* extension)
: ConfirmInfoBarDelegate(tab_contents),
extensions_service_(extensions_service),
@@ -30,6 +30,11 @@ AsCrashedExtensionInfoBarDelegate() {
return this;
}
+bool CrashedExtensionInfoBarDelegate::ShouldExpire(
+ const NavigationController::LoadCommittedDetails& details) const {
+ return false;
+}
+
string16 CrashedExtensionInfoBarDelegate::GetMessageText() const {
return l10n_util::GetStringFUTF16(IDS_EXTENSION_CRASHED_INFOBAR_MESSAGE,
UTF8ToUTF16(extension_name_));
diff --git a/chrome/browser/extensions/crashed_extension_infobar.h b/chrome/browser/extensions/crashed_extension_infobar.h
index 1508ae5..201e606 100644
--- a/chrome/browser/extensions/crashed_extension_infobar.h
+++ b/chrome/browser/extensions/crashed_extension_infobar.h
@@ -12,7 +12,7 @@
#include "chrome/browser/tab_contents/infobar_delegate.h"
class Extension;
-class ExtensionsService;
+class ExtensionService;
class SkBitmap;
// This infobar will be displayed when an extension process crashes. It allows
@@ -21,15 +21,17 @@ class CrashedExtensionInfoBarDelegate : public ConfirmInfoBarDelegate {
public:
// |tab_contents| should point to the TabContents the infobar will be added
// to. |extension| should be the crashed extension, and |extensions_service|
- // the ExtensionsService which manages that extension.
+ // the ExtensionService which manages that extension.
CrashedExtensionInfoBarDelegate(TabContents* tab_contents,
- ExtensionsService* extensions_service,
+ ExtensionService* extensions_service,
const Extension* extension);
const std::string extension_id() { return extension_id_; }
// InfoBarDelegate
virtual CrashedExtensionInfoBarDelegate* AsCrashedExtensionInfoBarDelegate();
+ virtual bool ShouldExpire(
+ const NavigationController::LoadCommittedDetails& details) const;
// ConfirmInfoBarDelegate
virtual string16 GetMessageText() const;
@@ -41,7 +43,7 @@ class CrashedExtensionInfoBarDelegate : public ConfirmInfoBarDelegate {
virtual bool Accept();
private:
- ExtensionsService* extensions_service_;
+ ExtensionService* extensions_service_;
const std::string extension_id_;
const std::string extension_name_;
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index 8441baa..f6708c5 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -9,9 +9,9 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/file_util.h"
+#include "base/lazy_instance.h"
#include "base/path_service.h"
#include "base/scoped_temp_dir.h"
-#include "base/singleton.h"
#include "base/stl_util-inl.h"
#include "base/stringprintf.h"
#include "base/time.h"
@@ -23,9 +23,8 @@
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/extensions/convert_user_script.h"
#include "chrome/browser/extensions/convert_web_app.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_error_reporter.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/shell_integration.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/common/chrome_paths.h"
@@ -51,25 +50,28 @@ struct WhitelistedInstallData {
std::set<std::string> ids;
};
+static base::LazyInstance<WhitelistedInstallData>
+ g_whitelisted_install_data(base::LINKER_INITIALIZED);
+
} // namespace
// static
void CrxInstaller::SetWhitelistedInstallId(const std::string& id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- Singleton<WhitelistedInstallData>::get()->ids.insert(id);
+ g_whitelisted_install_data.Get().ids.insert(id);
}
// static
bool CrxInstaller::IsIdWhitelisted(const std::string& id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- std::set<std::string>& ids = Singleton<WhitelistedInstallData>::get()->ids;
+ std::set<std::string>& ids = g_whitelisted_install_data.Get().ids;
return ContainsKey(ids, id);
}
// static
bool CrxInstaller::ClearWhitelistedInstallId(const std::string& id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- std::set<std::string>& ids = Singleton<WhitelistedInstallData>::get()->ids;
+ std::set<std::string>& ids = g_whitelisted_install_data.Get().ids;
if (ContainsKey(ids, id)) {
ids.erase(id);
return true;
@@ -77,7 +79,7 @@ bool CrxInstaller::ClearWhitelistedInstallId(const std::string& id) {
return false;
}
-CrxInstaller::CrxInstaller(ExtensionsService* frontend,
+CrxInstaller::CrxInstaller(ExtensionService* frontend,
ExtensionInstallUI* client)
: install_directory_(frontend->install_directory()),
install_source_(Extension::INTERNAL),
@@ -308,8 +310,7 @@ void CrxInstaller::ConfirmInstall() {
GURL overlapping_url;
const Extension* overlapping_extension =
frontend_->GetExtensionByOverlappingWebExtent(extension_->web_extent());
- if (overlapping_extension &&
- overlapping_extension->id() != extension_->id()) {
+ if (overlapping_extension) {
ReportFailureFromUIThread(l10n_util::GetStringFUTF8(
IDS_EXTENSION_OVERLAPPING_WEB_EXTENT,
UTF8ToUTF16(overlapping_extension->name())));
diff --git a/chrome/browser/extensions/crx_installer.h b/chrome/browser/extensions/crx_installer.h
index c22a4a9..4a6aa28 100644
--- a/chrome/browser/extensions/crx_installer.h
+++ b/chrome/browser/extensions/crx_installer.h
@@ -15,7 +15,7 @@
#include "chrome/common/extensions/extension.h"
#include "chrome/common/web_apps.h"
-class ExtensionsService;
+class ExtensionService;
class SkBitmap;
// This class installs a crx file into a profile.
@@ -65,7 +65,7 @@ class CrxInstaller
// frontend->install_directory() then registered with |frontend|. Any install
// UI will be displayed using |client|. Pass NULL for |client| for silent
// install.
- CrxInstaller(ExtensionsService* frontend,
+ CrxInstaller(ExtensionService* frontend,
ExtensionInstallUI* client);
// Install the crx in |source_file|.
@@ -182,7 +182,7 @@ class CrxInstaller
bool create_app_shortcut_;
// The extension we're installing. We own this and either pass it off to
- // ExtensionsService on success, or delete it on failure.
+ // ExtensionService on success, or delete it on failure.
scoped_refptr<const Extension> extension_;
// If non-empty, contains the current version of the extension we're
@@ -197,7 +197,7 @@ class CrxInstaller
FilePath temp_dir_;
// The frontend we will report results back to.
- scoped_refptr<ExtensionsService> frontend_;
+ scoped_refptr<ExtensionService> frontend_;
// The client we will work with to do the installation. This can be NULL, in
// which case the install is silent.
diff --git a/chrome/browser/extensions/crx_installer_browsertest.cc b/chrome/browser/extensions/crx_installer_browsertest.cc
index f49c577..e1a412f 100644
--- a/chrome/browser/extensions/crx_installer_browsertest.cc
+++ b/chrome/browser/extensions/crx_installer_browsertest.cc
@@ -5,8 +5,8 @@
#include "chrome/browser/extensions/crx_installer.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/extensions/extension_install_ui.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/ui_test_utils.h"
@@ -48,7 +48,7 @@ class ExtensionCrxInstallerTest : public ExtensionBrowserTest {
// happened or not.
bool DidWhitelistInstallPrompt(const std::string& crx_relpath,
const std::string& id) {
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
MockInstallUI* mock_install_ui = new MockInstallUI(browser()->profile());
scoped_refptr<CrxInstaller> installer(
diff --git a/chrome/browser/extensions/default_apps.cc b/chrome/browser/extensions/default_apps.cc
index cee5c32..a9e305f 100644
--- a/chrome/browser/extensions/default_apps.cc
+++ b/chrome/browser/extensions/default_apps.cc
@@ -18,146 +18,89 @@ void DefaultApps::RegisterUserPrefs(PrefService* prefs) {
prefs->RegisterIntegerPref(prefs::kAppsPromoCounter, 0);
}
-DefaultApps::DefaultApps(PrefService* prefs,
- const std::string& application_locale)
- : prefs_(prefs), application_locale_(application_locale) {
+DefaultApps::DefaultApps(PrefService* prefs)
+ : prefs_(prefs) {
+#if !defined(OS_CHROMEOS)
// Poppit, Entanglement
ids_.insert("mcbkbpnkkkipelfledbfocopglifcfmi");
ids_.insert("aciahcmjmecflokailenpkdchphgkefd");
+#endif // OS_CHROMEOS
}
DefaultApps::~DefaultApps() {}
-const ExtensionIdSet& DefaultApps::default_apps() const {
- return ids_;
-}
-
-bool DefaultApps::DefaultAppSupported() {
- // On Chrome OS the default apps are installed via a different mechanism.
-#if defined(OS_CHROMEOS)
- return false;
-#else
- return DefaultAppsSupportedForLanguage();
-#endif
+const ExtensionIdSet* DefaultApps::GetAppsToInstall() const {
+ if (GetDefaultAppsInstalled())
+ return NULL;
+ else
+ return &ids_;
}
-bool DefaultApps::DefaultAppsSupportedForLanguage() {
- return application_locale_ == "en-US";
+const ExtensionIdSet* DefaultApps::GetDefaultApps() const {
+ return &ids_;
}
-bool DefaultApps::ShouldInstallDefaultApps(
- const ExtensionIdSet& installed_ids) {
- if (!DefaultAppSupported())
- return false;
-
- if (GetDefaultAppsInstalled())
- return false;
-
- // If there are any non-default apps installed, we should never try to install
- // the default apps again, even if the non-default apps are later removed.
- if (NonDefaultAppIsInstalled(installed_ids)) {
+void DefaultApps::DidInstallApp(const ExtensionIdSet& installed_ids) {
+ // If all the default apps have been installed, stop trying to install them.
+ // Note that we use std::includes here instead of == because apps might have
+ // been manually installed while the the default apps were installing and we
+ // wouldn't want to keep trying to install them in that case.
+ if (!GetDefaultAppsInstalled() &&
+ std::includes(installed_ids.begin(), installed_ids.end(),
+ ids_.begin(), ids_.end())) {
SetDefaultAppsInstalled(true);
- return false;
}
-
- return true;
}
-bool DefaultApps::ShouldShowAppLauncher(const ExtensionIdSet& installed_ids) {
- // On Chrome OS the default apps are installed via a separate mechanism that
- // is always enabled. Therefore we always show the launcher.
-#if defined(OS_CHROME)
- return true;
-#else
- // The app store only supports en-us at the moment, so we don't show the apps
- // section by default for users in other locales. But we do show it if a user
- // from a non-supported locale somehow installs an app (eg by navigating
- // directly to the store).
- if (!DefaultAppsSupportedForLanguage())
- return !installed_ids.empty();
-
- // For supported locales, we need to wait for all the default apps to be
- // installed before showing the apps section. We also show it if any
- // non-default app is installed (eg because the user installed the app in a
- // previous version of Chrome).
- if (GetDefaultAppsInstalled() || NonDefaultAppIsInstalled(installed_ids))
- return true;
- else
- return false;
+bool DefaultApps::CheckShouldShowPromo(const ExtensionIdSet& installed_ids) {
+#if defined(OS_CHROMEOS)
+ // Don't show the promo at all on Chrome OS.
+ return false;
#endif
-}
-
-bool DefaultApps::ShouldShowPromo(const ExtensionIdSet& installed_ids,
- bool* just_expired) {
- *just_expired = false;
-
if (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kForceAppsPromoVisible)) {
return true;
}
- if (!DefaultAppSupported())
- return false;
-
- if (!GetDefaultAppsInstalled())
- return false;
-
- int promo_counter = GetPromoCounter();
- if (promo_counter <= kAppsPromoCounterMax) {
+ if (GetDefaultAppsInstalled() && GetPromoCounter() < kAppsPromoCounterMax) {
// If we have the exact set of default apps, show the promo. If we don't
// have the exact set of default apps, this means that the user manually
- // installed or uninstalled one. The promo doesn't make sense if it shows
- // apps the user manually installed, so expire it immediately in that
- // situation.
- if (ids_ != installed_ids) {
- SetPromoHidden();
- return false;
- }
-
- if (promo_counter == kAppsPromoCounterMax) {
- *just_expired = true;
- UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppsPromoHistogram,
- extension_misc::PROMO_EXPIRE,
- extension_misc::PROMO_BUCKET_BOUNDARY);
- SetPromoCounter(++promo_counter);
- return false;
- } else {
- UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppsPromoHistogram,
- extension_misc::PROMO_SEEN,
- extension_misc::PROMO_BUCKET_BOUNDARY);
- SetPromoCounter(++promo_counter);
+ // installed one. The promo doesn't make sense if it shows apps the user
+ // manually installed, so expire it immediately in that situation.
+ if (installed_ids == ids_)
return true;
- }
+ else
+ SetPromoHidden();
}
return false;
}
-void DefaultApps::DidInstallApp(const ExtensionIdSet& installed_ids) {
- // If all the default apps have been installed, stop trying to install them.
- // Note that we use std::includes here instead of == because apps might have
- // been manually installed while the the default apps were installing and we
- // wouldn't want to keep trying to install them in that case.
- if (!GetDefaultAppsInstalled() &&
- std::includes(installed_ids.begin(), installed_ids.end(),
- ids_.begin(), ids_.end())) {
- SetDefaultAppsInstalled(true);
+void DefaultApps::DidShowPromo() {
+ if (!GetDefaultAppsInstalled()) {
+ NOTREACHED() << "Should not show promo until default apps are installed.";
+ return;
}
-}
-bool DefaultApps::NonDefaultAppIsInstalled(
- const ExtensionIdSet& installed_ids) const {
- for (ExtensionIdSet::const_iterator iter = installed_ids.begin();
- iter != installed_ids.end(); ++iter) {
- if (ids_.find(*iter) == ids_.end())
- return true;
+ int promo_counter = GetPromoCounter();
+ if (promo_counter == kAppsPromoCounterMax) {
+ NOTREACHED() << "Promo has already been shown the maximum number of times.";
+ return;
}
- return false;
+ if (promo_counter < kAppsPromoCounterMax) {
+ if (promo_counter + 1 == kAppsPromoCounterMax)
+ UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppsPromoHistogram,
+ extension_misc::PROMO_EXPIRE,
+ extension_misc::PROMO_BUCKET_BOUNDARY);
+ SetPromoCounter(++promo_counter);
+ } else {
+ SetPromoHidden();
+ }
}
void DefaultApps::SetPromoHidden() {
- SetPromoCounter(kAppsPromoCounterMax + 1);
+ SetPromoCounter(kAppsPromoCounterMax);
}
int DefaultApps::GetPromoCounter() const {
diff --git a/chrome/browser/extensions/default_apps.h b/chrome/browser/extensions/default_apps.h
index 2ff8801..b03f6ec 100644
--- a/chrome/browser/extensions/default_apps.h
+++ b/chrome/browser/extensions/default_apps.h
@@ -13,60 +13,65 @@
class PrefService;
-// Encapsulates business logic for:
-// - Whether to install default apps on Chrome startup
-// - Whether to show the app launcher
-// - Whether to show the apps promo in the launcher
+// Manages the installation of the set of default apps into Chrome, and the
+// promotion of those apps in the launcher.
+//
+// It implements the following rules:
+//
+// - Only install default apps once per-profile.
+// - Don't install default apps if any apps are already installed.
+// - Do not start showing the promo until all default apps have been installed.
+// - Do not show the promo if it has been hidden by the user.
+// - Do not show promo after one app has been manually installed or uninstalled.
+// - Do not show promo if the set of installed apps is different than the set of
+// default apps.
+// - Only show promo a certain amount of times.
+//
+// The promo can also be forced on with --force-apps-promo-visible.
class DefaultApps {
public:
- // The maximum number of times to show the apps promo. The promo counter
- // actually goes up to this number + 1 because we need to differentiate
- // between the first time we overflow and subsequent times.
+ // The maximum number of times to show the apps promo.
static const int kAppsPromoCounterMax;
// Register our preferences.
static void RegisterUserPrefs(PrefService* prefs);
- explicit DefaultApps(PrefService* prefs,
- const std::string& application_locale);
+ explicit DefaultApps(PrefService* prefs);
~DefaultApps();
- // Gets the set of default apps.
- const ExtensionIdSet& default_apps() const;
+ // Gets the list of default apps that should be installed. Can return NULL if
+ // no apps need to be installed.
+ const ExtensionIdSet* GetAppsToInstall() const;
- // Returns true if the default apps should be installed.
- bool ShouldInstallDefaultApps(const ExtensionIdSet& installed_ids);
+ // Gets the list of default apps.
+ const ExtensionIdSet* GetDefaultApps() const;
- // Returns true if the app launcher in the NTP should be shown.
- bool ShouldShowAppLauncher(const ExtensionIdSet& installed_ids);
+ // Returns true if the default apps have been installed. False otherwise.
+ bool GetDefaultAppsInstalled() const;
+
+ // Should be called after each app is installed. Once installed_ids contains
+ // all the default apps, GetAppsToInstall() will start returning NULL.
+ void DidInstallApp(const ExtensionIdSet& installed_ids);
// Returns true if the apps promo should be displayed in the launcher.
//
// NOTE: If the default apps have been installed, but |installed_ids| is
// different than GetDefaultApps(), this will permanently expire the promo.
- bool ShouldShowPromo(const ExtensionIdSet& installed_ids, bool* just_expired);
+ bool CheckShouldShowPromo(const ExtensionIdSet& installed_ids);
- // Should be called after each app is installed. Once installed_ids contains
- // all the default apps, GetAppsToInstall() will start returning NULL.
- void DidInstallApp(const ExtensionIdSet& installed_ids);
+ // Should be called after each time the promo is installed.
+ void DidShowPromo();
// Force the promo to be hidden.
void SetPromoHidden();
private:
- FRIEND_TEST_ALL_PREFIXES(ExtensionDefaultApps, HappyPath);
- FRIEND_TEST_ALL_PREFIXES(ExtensionDefaultApps, UnsupportedLocale);
+ FRIEND_TEST_ALL_PREFIXES(ExtensionDefaultApps, Basics);
FRIEND_TEST_ALL_PREFIXES(ExtensionDefaultApps, HidePromo);
FRIEND_TEST_ALL_PREFIXES(ExtensionDefaultApps, InstallingAnAppHidesPromo);
FRIEND_TEST_ALL_PREFIXES(ExtensionDefaultApps,
ManualAppInstalledWhileInstallingDefaultApps);
- bool DefaultAppSupported();
- bool DefaultAppsSupportedForLanguage();
-
- bool NonDefaultAppIsInstalled(const ExtensionIdSet& installed_ids) const;
-
- bool GetDefaultAppsInstalled() const;
void SetDefaultAppsInstalled(bool val);
int GetPromoCounter() const;
@@ -75,9 +80,6 @@ class DefaultApps {
// Our permanent state is stored in this PrefService instance.
PrefService* prefs_;
- // The locale the browser is currently in.
- std::string application_locale_;
-
// The set of default extensions. Initialized to a static list in the
// constructor.
ExtensionIdSet ids_;
diff --git a/chrome/browser/extensions/default_apps_unittest.cc b/chrome/browser/extensions/default_apps_unittest.cc
index 316568d..4fa9bc2 100644
--- a/chrome/browser/extensions/default_apps_unittest.cc
+++ b/chrome/browser/extensions/default_apps_unittest.cc
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/logging.h"
#include "chrome/browser/extensions/default_apps.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/test/testing_pref_service.h"
@@ -11,180 +10,94 @@
// TODO(dpolukhin): On Chrome OS all apps are installed via external extensions,
// and the web store promo is never shown.
#if !defined(OS_CHROMEOS)
-TEST(ExtensionDefaultApps, HappyPath) {
+TEST(ExtensionDefaultApps, Basics) {
TestingPrefService pref_service;
DefaultApps::RegisterUserPrefs(&pref_service);
- DefaultApps default_apps(&pref_service, "en-US");
+ DefaultApps default_apps(&pref_service);
- const ExtensionIdSet& default_app_ids = default_apps.default_apps();
+ ExtensionIdSet default_app_ids = *default_apps.GetAppsToInstall();
ASSERT_GT(default_app_ids.size(), 0u);
EXPECT_FALSE(default_apps.GetDefaultAppsInstalled());
EXPECT_EQ(0, default_apps.GetPromoCounter());
-
- // If no apps are installed, the default apps should be installed.
- ExtensionIdSet installed_app_ids;
- EXPECT_TRUE(default_apps.ShouldInstallDefaultApps(installed_app_ids));
-
- // The launcher should not be shown until the default apps have been
- // installed.
- EXPECT_FALSE(default_apps.ShouldShowAppLauncher(installed_app_ids));
+ EXPECT_EQ(default_app_ids, *default_apps.GetDefaultApps());
// The promo should not be shown until the default apps have been installed.
- bool promo_just_expired = false;
- EXPECT_FALSE(default_apps.ShouldShowPromo(installed_app_ids,
- &promo_just_expired));
- EXPECT_FALSE(promo_just_expired);
+ ExtensionIdSet installed_app_ids;
+ EXPECT_FALSE(default_apps.CheckShouldShowPromo(installed_app_ids));
// Simulate installing the apps one by one and notifying default_apps after
// each intallation. Nothing should change until we have installed all the
// default apps.
- for (size_t i = 0; i < default_app_ids.size() - 1; ++i) {
- ExtensionIdSet::const_iterator iter = default_app_ids.begin();
- for (size_t j = 0; j <= i; ++j)
- ++iter;
- installed_app_ids.insert(*iter);
- default_apps.DidInstallApp(installed_app_ids);
+ ExtensionIdSet extension_id_sets[] = {
+ default_app_ids,
+ default_app_ids,
+ default_app_ids
+ };
+ extension_id_sets[0].clear();
+ extension_id_sets[1].erase(extension_id_sets[1].begin());
+ extension_id_sets[2].erase(extension_id_sets[2].begin(),
+ ++extension_id_sets[2].begin());
+ for (size_t i = 0; i < arraysize(extension_id_sets); ++i) {
+ default_apps.DidInstallApp(extension_id_sets[i]);
+ EXPECT_TRUE(default_app_ids == *default_apps.GetAppsToInstall());
EXPECT_FALSE(default_apps.GetDefaultAppsInstalled());
- EXPECT_TRUE(default_apps.ShouldInstallDefaultApps(installed_app_ids));
- EXPECT_FALSE(default_apps.ShouldShowAppLauncher(installed_app_ids));
- EXPECT_FALSE(default_apps.ShouldShowPromo(installed_app_ids,
- &promo_just_expired));
- EXPECT_FALSE(promo_just_expired);
+ EXPECT_FALSE(default_apps.CheckShouldShowPromo(extension_id_sets[i]));
}
// Simulate all the default apps being installed. Now we should stop getting
// default apps to install.
- installed_app_ids = default_app_ids;
- default_apps.DidInstallApp(installed_app_ids);
+ default_apps.DidInstallApp(default_app_ids);
+ EXPECT_EQ(NULL, default_apps.GetAppsToInstall());
EXPECT_TRUE(default_apps.GetDefaultAppsInstalled());
- EXPECT_FALSE(default_apps.ShouldInstallDefaultApps(installed_app_ids));
- // And the promo and launcher should become available.
- EXPECT_TRUE(default_apps.ShouldShowAppLauncher(installed_app_ids));
- EXPECT_TRUE(default_apps.ShouldShowPromo(installed_app_ids,
- &promo_just_expired));
- EXPECT_FALSE(promo_just_expired);
+ // And the promo should become available.
+ EXPECT_TRUE(default_apps.CheckShouldShowPromo(default_app_ids));
// The promo should be available up to the max allowed times, then stop.
- // We start counting at 1 because of the call to ShouldShowPromo() above.
- for (int i = 1; i < DefaultApps::kAppsPromoCounterMax; ++i) {
- EXPECT_TRUE(default_apps.ShouldShowPromo(installed_app_ids,
- &promo_just_expired));
- EXPECT_FALSE(promo_just_expired);
+ for (int i = 0; i < DefaultApps::kAppsPromoCounterMax; ++i) {
+ EXPECT_TRUE(default_apps.CheckShouldShowPromo(default_app_ids));
+ default_apps.DidShowPromo();
EXPECT_EQ(i + 1, default_apps.GetPromoCounter());
}
-
- // The first time, should_show_promo should flip to true, then back to false.
- EXPECT_FALSE(default_apps.ShouldShowPromo(installed_app_ids,
- &promo_just_expired));
- EXPECT_TRUE(promo_just_expired);
- EXPECT_EQ(DefaultApps::kAppsPromoCounterMax + 1,
- default_apps.GetPromoCounter());
-
- // Even if all the apps are subsequently removed, the apps section should
- // remain.
- installed_app_ids.clear();
- EXPECT_FALSE(default_apps.ShouldInstallDefaultApps(installed_app_ids));
- EXPECT_TRUE(default_apps.ShouldShowAppLauncher(installed_app_ids));
- EXPECT_FALSE(default_apps.ShouldShowPromo(installed_app_ids,
- &promo_just_expired));
- EXPECT_FALSE(promo_just_expired);
- EXPECT_EQ(DefaultApps::kAppsPromoCounterMax + 1,
- default_apps.GetPromoCounter());
-}
-
-TEST(ExtensionDefaultApps, UnsupportedLocale) {
- TestingPrefService pref_service;
- DefaultApps::RegisterUserPrefs(&pref_service);
- DefaultApps default_apps(&pref_service, "fr");
-
- const ExtensionIdSet& default_app_ids = default_apps.default_apps();
- EXPECT_GT(default_app_ids.size(), 0u);
-
- // Since the store only supports en-US at the moment, we don't install default
- // apps or promote the store.
- ExtensionIdSet installed_ids;
- EXPECT_FALSE(default_apps.ShouldInstallDefaultApps(installed_ids));
- EXPECT_FALSE(default_apps.ShouldShowAppLauncher(installed_ids));
-
- bool promo_just_expired = false;
- EXPECT_FALSE(default_apps.ShouldShowPromo(installed_ids,
- &promo_just_expired));
- EXPECT_FALSE(promo_just_expired);
-
- // If the user installs an app manually, then we show the apps section, but
- // no promotion or default apps.
- installed_ids.insert(*(default_app_ids.begin()));
- EXPECT_FALSE(default_apps.ShouldInstallDefaultApps(installed_ids));
- EXPECT_TRUE(default_apps.ShouldShowAppLauncher(installed_ids));
- EXPECT_FALSE(default_apps.ShouldShowPromo(installed_ids,
- &promo_just_expired));
- EXPECT_FALSE(promo_just_expired);
-
- // Even if the user installs the exact set of default apps, we don't show the
- // promo.
- installed_ids = default_app_ids;
- EXPECT_FALSE(default_apps.ShouldInstallDefaultApps(installed_ids));
- EXPECT_TRUE(default_apps.ShouldShowAppLauncher(installed_ids));
- EXPECT_FALSE(default_apps.ShouldShowPromo(installed_ids,
- &promo_just_expired));
- EXPECT_FALSE(promo_just_expired);
-
- // If the user uninstalls the apps again, we go back to not showing the
- // apps section.
- installed_ids.clear();
- EXPECT_FALSE(default_apps.ShouldInstallDefaultApps(installed_ids));
- EXPECT_FALSE(default_apps.ShouldShowAppLauncher(installed_ids));
- EXPECT_FALSE(default_apps.ShouldShowPromo(installed_ids,
- &promo_just_expired));
- EXPECT_FALSE(promo_just_expired);
+ EXPECT_FALSE(default_apps.CheckShouldShowPromo(default_app_ids));
+ EXPECT_EQ(DefaultApps::kAppsPromoCounterMax, default_apps.GetPromoCounter());
}
TEST(ExtensionDefaultApps, HidePromo) {
TestingPrefService pref_service;
DefaultApps::RegisterUserPrefs(&pref_service);
- DefaultApps default_apps(&pref_service, "en-US");
+ DefaultApps default_apps(&pref_service);
- const ExtensionIdSet& default_app_ids = default_apps.default_apps();
+ ExtensionIdSet default_app_ids = *default_apps.GetAppsToInstall();
default_apps.DidInstallApp(default_app_ids);
- bool promo_just_expired = false;
- EXPECT_TRUE(default_apps.ShouldShowPromo(default_app_ids,
- &promo_just_expired));
- EXPECT_FALSE(promo_just_expired);
+ EXPECT_TRUE(default_apps.CheckShouldShowPromo(default_app_ids));
+ default_apps.DidShowPromo();
EXPECT_EQ(1, default_apps.GetPromoCounter());
default_apps.SetPromoHidden();
- EXPECT_FALSE(default_apps.ShouldShowPromo(default_app_ids,
- &promo_just_expired));
- EXPECT_FALSE(promo_just_expired);
- EXPECT_EQ(DefaultApps::kAppsPromoCounterMax + 1,
- default_apps.GetPromoCounter());
+ EXPECT_FALSE(default_apps.CheckShouldShowPromo(default_app_ids));
+ EXPECT_EQ(DefaultApps::kAppsPromoCounterMax, default_apps.GetPromoCounter());
}
TEST(ExtensionDefaultApps, InstallingAnAppHidesPromo) {
TestingPrefService pref_service;
DefaultApps::RegisterUserPrefs(&pref_service);
- DefaultApps default_apps(&pref_service, "en-US");
+ DefaultApps default_apps(&pref_service);
- const ExtensionIdSet& default_app_ids = default_apps.default_apps();
+ ExtensionIdSet default_app_ids = *default_apps.GetAppsToInstall();
ExtensionIdSet installed_app_ids = default_app_ids;
default_apps.DidInstallApp(installed_app_ids);
- bool promo_just_expired = false;
- EXPECT_TRUE(default_apps.ShouldShowPromo(installed_app_ids,
- &promo_just_expired));
- EXPECT_FALSE(promo_just_expired);
+ EXPECT_TRUE(default_apps.CheckShouldShowPromo(installed_app_ids));
+ default_apps.DidShowPromo();
EXPECT_EQ(1, default_apps.GetPromoCounter());
// Now simulate a new extension being installed. This should cause the promo
// to be hidden.
installed_app_ids.insert("foo");
- EXPECT_FALSE(default_apps.ShouldShowPromo(installed_app_ids,
- &promo_just_expired));
- EXPECT_FALSE(promo_just_expired);
- EXPECT_EQ(DefaultApps::kAppsPromoCounterMax + 1,
- default_apps.GetPromoCounter());
+ EXPECT_FALSE(default_apps.CheckShouldShowPromo(installed_app_ids));
+ EXPECT_EQ(DefaultApps::kAppsPromoCounterMax, default_apps.GetPromoCounter());
}
TEST(ExtensionDefaultApps, ManualAppInstalledWhileInstallingDefaultApps) {
@@ -198,39 +111,27 @@ TEST(ExtensionDefaultApps, ManualAppInstalledWhileInstallingDefaultApps) {
// the default ones.
TestingPrefService pref_service;
DefaultApps::RegisterUserPrefs(&pref_service);
- DefaultApps default_apps(&pref_service, "en-US");
+ DefaultApps default_apps(&pref_service);
// Simulate an app getting installed before the complete set of default apps.
- // This should stop the default apps from trying to be installed. The launcher
- // should also immediately show up.
+ // This shouldn't affect us installing default apps. We should keep trying.
ExtensionIdSet installed_ids;
installed_ids.insert("foo");
- EXPECT_FALSE(default_apps.ShouldInstallDefaultApps(installed_ids));
+ default_apps.DidInstallApp(installed_ids);
+ EXPECT_FALSE(default_apps.GetDefaultAppsInstalled());
+ EXPECT_TRUE(default_apps.GetAppsToInstall());
+
+ // Now add all the default apps in addition to the extra app. We should stop
+ // trying to install default apps.
+ installed_ids = *default_apps.GetAppsToInstall();
+ installed_ids.insert("foo");
+ default_apps.DidInstallApp(installed_ids);
EXPECT_TRUE(default_apps.GetDefaultAppsInstalled());
- EXPECT_TRUE(default_apps.ShouldShowAppLauncher(installed_ids));
+ EXPECT_FALSE(default_apps.GetAppsToInstall());
// The promo shouldn't turn on though, because it would look weird with the
// user's extra, manually installed extensions.
- bool promo_just_expired = false;
- EXPECT_FALSE(default_apps.ShouldShowPromo(installed_ids,
- &promo_just_expired));
- EXPECT_FALSE(promo_just_expired);
- EXPECT_EQ(DefaultApps::kAppsPromoCounterMax + 1,
- default_apps.GetPromoCounter());
-
- // Going back to a subset of the default apps shouldn't allow the default app
- // install to continue.
- installed_ids.clear();
- EXPECT_FALSE(default_apps.ShouldInstallDefaultApps(installed_ids));
- EXPECT_TRUE(default_apps.GetDefaultAppsInstalled());
- EXPECT_TRUE(default_apps.ShouldShowAppLauncher(installed_ids));
- EXPECT_FALSE(default_apps.ShouldShowPromo(installed_ids,
- &promo_just_expired));
- EXPECT_FALSE(promo_just_expired);
-
- // Going to the exact set of default apps shouldn't show the promo.
- EXPECT_FALSE(default_apps.ShouldShowPromo(default_apps.default_apps(),
- &promo_just_expired));
- EXPECT_FALSE(promo_just_expired);
+ EXPECT_FALSE(default_apps.CheckShouldShowPromo(installed_ids));
+ EXPECT_EQ(DefaultApps::kAppsPromoCounterMax, default_apps.GetPromoCounter());
}
#endif // OS_CHROMEOS
diff --git a/chrome/browser/extensions/execute_code_in_tab_function.cc b/chrome/browser/extensions/execute_code_in_tab_function.cc
index 1659af3..b3bfee0 100644
--- a/chrome/browser/extensions/execute_code_in_tab_function.cc
+++ b/chrome/browser/extensions/execute_code_in_tab_function.cc
@@ -9,12 +9,12 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
#include "chrome/browser/extensions/extension_tabs_module_constants.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/file_reader.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_error_utils.h"
diff --git a/chrome/browser/extensions/extension_accessibility_api.cc b/chrome/browser/extensions/extension_accessibility_api.cc
index 3dd0345..fa0ee0e 100644
--- a/chrome/browser/extensions/extension_accessibility_api.cc
+++ b/chrome/browser/extensions/extension_accessibility_api.cc
@@ -14,8 +14,8 @@
#include "chrome/browser/extensions/extension_accessibility_api_constants.h"
#include "chrome/browser/extensions/extension_event_router.h"
#include "chrome/browser/extensions/extension_function_dispatcher.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_service.h"
diff --git a/chrome/browser/extensions/extension_apitest.cc b/chrome/browser/extensions/extension_apitest.cc
index f65d8eb..dbb47cd 100644
--- a/chrome/browser/extensions/extension_apitest.cc
+++ b/chrome/browser/extensions/extension_apitest.cc
@@ -7,8 +7,8 @@
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "chrome/browser/extensions/extension_test_api.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/test/ui_test_utils.h"
@@ -143,7 +143,7 @@ bool ExtensionApiTest::RunExtensionTestImpl(const char* extension_name,
DCHECK(!std::string(extension_name).empty()) <<
"Relative page_url given with no extension_name";
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
const Extension* extension =
service->GetExtensionById(last_loaded_extension_id_, false);
if (!extension)
@@ -166,7 +166,7 @@ bool ExtensionApiTest::RunExtensionTestImpl(const char* extension_name,
// Test that exactly one extension loaded.
const Extension* ExtensionApiTest::GetSingleLoadedExtension() {
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
int found_extension_index = -1;
for (size_t i = 0; i < service->extensions()->size(); ++i) {
diff --git a/chrome/browser/extensions/extension_apitest.h b/chrome/browser/extensions/extension_apitest.h
index b2079a6..4f76d28 100644
--- a/chrome/browser/extensions/extension_apitest.h
+++ b/chrome/browser/extensions/extension_apitest.h
@@ -11,7 +11,6 @@
#include "base/values.h"
#include "chrome/browser/extensions/extension_browsertest.h"
-#include "chrome/common/notification_service.h"
class Extension;
diff --git a/chrome/browser/extensions/extension_bookmark_manager_api.cc b/chrome/browser/extensions/extension_bookmark_manager_api.cc
index cc38ad1..67963b2 100644
--- a/chrome/browser/extensions/extension_bookmark_manager_api.cc
+++ b/chrome/browser/extensions/extension_bookmark_manager_api.cc
@@ -18,7 +18,7 @@
#include "chrome/browser/extensions/extension_bookmarks_module_constants.h"
#include "chrome/browser/extensions/extension_dom_ui.h"
#include "chrome/browser/extensions/extension_event_router.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/extensions/extension_bookmarks_module.cc b/chrome/browser/extensions/extension_bookmarks_module.cc
index f805a1e..180a5bb 100644
--- a/chrome/browser/extensions/extension_bookmarks_module.cc
+++ b/chrome/browser/extensions/extension_bookmarks_module.cc
@@ -22,7 +22,7 @@
#include "chrome/browser/importer/importer.h"
#include "chrome/browser/importer/importer_data_types.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
@@ -75,7 +75,7 @@ void BookmarksFunction::Observe(NotificationType type,
}
// static
-ExtensionBookmarkEventRouter* ExtensionBookmarkEventRouter::GetSingleton() {
+ExtensionBookmarkEventRouter* ExtensionBookmarkEventRouter::GetInstance() {
return Singleton<ExtensionBookmarkEventRouter>::get();
}
diff --git a/chrome/browser/extensions/extension_bookmarks_module.h b/chrome/browser/extensions/extension_bookmarks_module.h
index e8e91a1..21b9ad8 100644
--- a/chrome/browser/extensions/extension_bookmarks_module.h
+++ b/chrome/browser/extensions/extension_bookmarks_module.h
@@ -21,7 +21,7 @@
// the extension system.
class ExtensionBookmarkEventRouter : public BookmarkModelObserver {
public:
- static ExtensionBookmarkEventRouter* GetSingleton();
+ static ExtensionBookmarkEventRouter* GetInstance();
virtual ~ExtensionBookmarkEventRouter();
// Call this for each model to observe. Safe to call multiple times per
@@ -179,8 +179,9 @@ class BookmarksIOFunction : public BookmarksFunction,
// Overridden from SelectFileDialog::Listener:
virtual void FileSelected(const FilePath& path, int index, void* params) = 0;
- void MultiFilesSelected(const std::vector<FilePath>& files, void* params);
- void FileSelectionCanceled(void* params);
+ virtual void MultiFilesSelected(const std::vector<FilePath>& files,
+ void* params);
+ virtual void FileSelectionCanceled(void* params);
void SelectFile(SelectFileDialog::Type type);
protected:
@@ -190,8 +191,8 @@ class BookmarksIOFunction : public BookmarksFunction,
class ImportBookmarksFunction : public BookmarksIOFunction {
public:
// Override BookmarkManagerIOFunction.
- bool RunImpl();
- void FileSelected(const FilePath& path, int index, void* params);
+ virtual bool RunImpl();
+ virtual void FileSelected(const FilePath& path, int index, void* params);
private:
DECLARE_EXTENSION_FUNCTION_NAME("bookmarks.import");
@@ -200,8 +201,8 @@ class ImportBookmarksFunction : public BookmarksIOFunction {
class ExportBookmarksFunction : public BookmarksIOFunction {
public:
// Override BookmarkManagerIOFunction.
- bool RunImpl();
- void FileSelected(const FilePath& path, int index, void* params);
+ virtual bool RunImpl();
+ virtual void FileSelected(const FilePath& path, int index, void* params);
private:
DECLARE_EXTENSION_FUNCTION_NAME("bookmarks.export");
diff --git a/chrome/browser/extensions/extension_browser_event_router.cc b/chrome/browser/extensions/extension_browser_event_router.cc
index b49c1a9..6df9ede 100644
--- a/chrome/browser/extensions/extension_browser_event_router.cc
+++ b/chrome/browser/extensions/extension_browser_event_router.cc
@@ -10,13 +10,12 @@
#include "chrome/browser/extensions/extension_event_router.h"
#include "chrome/browser/extensions/extension_page_actions_module_constants.h"
#include "chrome/browser/extensions/extension_tabs_module_constants.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_service.h"
diff --git a/chrome/browser/extensions/extension_browser_event_router.h b/chrome/browser/extensions/extension_browser_event_router.h
index e951290..cdf2efe 100644
--- a/chrome/browser/extensions/extension_browser_event_router.h
+++ b/chrome/browser/extensions/extension_browser_event_router.h
@@ -92,9 +92,9 @@ class ExtensionBrowserEventRouter : public TabStripModelObserver,
Browser* browser);
// NotificationObserver.
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
private:
// "Synthetic" event. Called from TabInsertedAt if new tab is detected.
void TabCreatedAt(TabContents* contents, int index, bool foreground);
diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc
index ae90a66..8178848 100644
--- a/chrome/browser/extensions/extension_browsertest.cc
+++ b/chrome/browser/extensions/extension_browsertest.cc
@@ -15,10 +15,10 @@
#include "chrome/browser/extensions/extension_error_reporter.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_install_ui.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/location_bar.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/omnibox/location_bar.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_registrar.h"
@@ -46,7 +46,7 @@ void ExtensionBrowserTest::SetUpCommandLine(CommandLine* command_line) {
#if defined(OS_CHROMEOS)
// This makes sure that we create the Default profile first, with no
- // ExtensionsService and then the real profile with one, as we do when
+ // ExtensionService and then the real profile with one, as we do when
// running on chromeos.
command_line->AppendSwitchASCII(switches::kLoginUser,
"TestUser@gmail.com");
@@ -57,7 +57,7 @@ void ExtensionBrowserTest::SetUpCommandLine(CommandLine* command_line) {
bool ExtensionBrowserTest::LoadExtensionImpl(const FilePath& path,
bool incognito_enabled) {
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
{
NotificationRegistrar registrar;
registrar.Add(this, NotificationType::EXTENSION_LOADED,
@@ -124,7 +124,7 @@ bool ExtensionBrowserTest::InstallOrUpdateExtension(const std::string& id,
const FilePath& path,
InstallUIType ui_type,
int expected_change) {
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
service->set_show_extensions_prompts(false);
size_t num_before = service->extensions()->size();
@@ -174,7 +174,7 @@ bool ExtensionBrowserTest::InstallOrUpdateExtension(const std::string& id,
}
void ExtensionBrowserTest::ReloadExtension(const std::string& extension_id) {
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
service->ReloadExtension(extension_id);
ui_test_utils::RegisterAndWait(this,
NotificationType::EXTENSION_LOADED,
@@ -182,22 +182,22 @@ void ExtensionBrowserTest::ReloadExtension(const std::string& extension_id) {
}
void ExtensionBrowserTest::UnloadExtension(const std::string& extension_id) {
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
- service->UnloadExtension(extension_id);
+ ExtensionService* service = browser()->profile()->GetExtensionService();
+ service->UnloadExtension(extension_id, UnloadedExtensionInfo::DISABLE);
}
void ExtensionBrowserTest::UninstallExtension(const std::string& extension_id) {
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
service->UninstallExtension(extension_id, false);
}
void ExtensionBrowserTest::DisableExtension(const std::string& extension_id) {
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
service->DisableExtension(extension_id);
}
void ExtensionBrowserTest::EnableExtension(const std::string& extension_id) {
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
service->EnableExtension(extension_id);
}
@@ -272,7 +272,7 @@ void ExtensionBrowserTest::WaitForExtensionLoad() {
bool ExtensionBrowserTest::WaitForExtensionCrash(
const std::string& extension_id) {
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
if (!service->GetExtensionById(extension_id, true)) {
// The extension is already unloaded, presumably due to a crash.
diff --git a/chrome/browser/extensions/extension_browsertests_misc.cc b/chrome/browser/extensions/extension_browsertests_misc.cc
index 4787fc5..df03580 100644
--- a/chrome/browser/extensions/extension_browsertests_misc.cc
+++ b/chrome/browser/extensions/extension_browsertests_misc.cc
@@ -13,18 +13,17 @@
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_updater.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/extension_action.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/ui_test_utils.h"
#include "net/base/mock_host_resolver.h"
@@ -173,6 +172,23 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, TabContents) {
EXPECT_TRUE(result);
}
+// Tests that GPU-related WebKit preferences are set for extension background
+// pages. See http://crbug.com/64512.
+IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, WebKitPrefsBackgroundPage) {
+ ASSERT_TRUE(LoadExtension(
+ test_data_dir_.AppendASCII("good").AppendASCII("Extensions")
+ .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
+ .AppendASCII("1.0.0.0")));
+
+ ExtensionProcessManager* manager =
+ browser()->profile()->GetExtensionProcessManager();
+ ExtensionHost* host = FindHostWithPath(manager, "/backgroundpage.html", 1);
+ WebPreferences prefs = host->GetWebkitPrefs();
+ ASSERT_FALSE(prefs.experimental_webgl_enabled);
+ ASSERT_FALSE(prefs.accelerated_compositing_enabled);
+ ASSERT_FALSE(prefs.accelerated_2d_canvas_enabled);
+}
+
// Tests that we can load page actions in the Omnibox.
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, PageAction) {
ASSERT_TRUE(test_server()->Start());
@@ -252,7 +268,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, UnloadPageAction) {
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, PageActionRefreshCrash) {
base::TimeTicks start_time = base::TimeTicks::Now();
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
size_t size_before = service->extensions()->size();
@@ -321,7 +337,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, RSSMultiRelLink) {
// Tests that tooltips of a browser action icon can be specified using UTF8.
// See http://crbug.com/25349.
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, TitleLocalizationBrowserAction) {
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
const size_t size_before = service->extensions()->size();
FilePath extension_path(test_data_dir_.AppendASCII("browsertest")
.AppendASCII("title_localized"));
@@ -344,7 +360,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, TitleLocalizationBrowserAction) {
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, TitleLocalizationPageAction) {
ASSERT_TRUE(test_server()->Start());
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
const size_t size_before = service->extensions()->size();
FilePath extension_path(test_data_dir_.AppendASCII("browsertest")
@@ -443,7 +459,7 @@ void NavigateToFeedAndValidate(net::TestServer* server,
// TODO(finnur): Implement this is a non-flaky way.
}
- ExtensionsService* service = browser->profile()->GetExtensionsService();
+ ExtensionService* service = browser->profile()->GetExtensionService();
const Extension* extension = service->extensions()->back();
std::string id = extension->id();
@@ -745,7 +761,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, MAYBE_PluginLoadUnload) {
tab->render_view_host(), L"", L"testPluginWorks()", &result));
EXPECT_FALSE(result);
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
const size_t size_before = service->extensions()->size();
ASSERT_TRUE(LoadExtension(extension_dir));
EXPECT_EQ(size_before + 1, service->extensions()->size());
@@ -797,7 +813,7 @@ static const wchar_t* jscript_click_option_button =
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, DISABLED_OptionsPage) {
// Install an extension with an options page.
ASSERT_TRUE(InstallExtension(test_data_dir_.AppendASCII("options.crx"), 1));
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
const ExtensionList* extensions = service->extensions();
ASSERT_EQ(1u, extensions->size());
const Extension* extension = extensions->at(0);
diff --git a/chrome/browser/extensions/extension_clipboard_api.cc b/chrome/browser/extensions/extension_clipboard_api.cc
index f80be6b..8cde22f 100644
--- a/chrome/browser/extensions/extension_clipboard_api.cc
+++ b/chrome/browser/extensions/extension_clipboard_api.cc
@@ -9,7 +9,7 @@
#include "chrome/browser/extensions/extension_tabs_module.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/extensions/extension_error_utils.h"
namespace {
diff --git a/chrome/browser/extensions/extension_context_menu_api.cc b/chrome/browser/extensions/extension_context_menu_api.cc
index a004b97..78f4f03 100644
--- a/chrome/browser/extensions/extension_context_menu_api.cc
+++ b/chrome/browser/extensions/extension_context_menu_api.cc
@@ -9,8 +9,8 @@
#include "base/values.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/extension_error_utils.h"
const char kCheckedKey[] = "checked";
@@ -213,7 +213,7 @@ bool CreateContextMenuFunction::RunImpl() {
return false;
ExtensionMenuManager* menu_manager =
- profile()->GetExtensionsService()->menu_manager();
+ profile()->GetExtensionService()->menu_manager();
ExtensionMenuItem::ContextList contexts(ExtensionMenuItem::PAGE);
if (!ParseContexts(*properties, kContextsKey, &contexts))
@@ -268,7 +268,7 @@ bool UpdateContextMenuFunction::RunImpl() {
ExtensionMenuItem::Id item_id(profile(), extension_id(), 0);
EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &item_id.uid));
- ExtensionsService* service = profile()->GetExtensionsService();
+ ExtensionService* service = profile()->GetExtensionService();
ExtensionMenuManager* manager = service->menu_manager();
ExtensionMenuItem* item = manager->GetItemById(item_id);
if (!item || item->extension_id() != extension_id()) {
@@ -282,7 +282,7 @@ bool UpdateContextMenuFunction::RunImpl() {
EXTENSION_FUNCTION_VALIDATE(properties != NULL);
ExtensionMenuManager* menu_manager =
- profile()->GetExtensionsService()->menu_manager();
+ profile()->GetExtensionService()->menu_manager();
// Type.
ExtensionMenuItem::Type type;
@@ -334,7 +334,7 @@ bool UpdateContextMenuFunction::RunImpl() {
bool RemoveContextMenuFunction::RunImpl() {
ExtensionMenuItem::Id id(profile(), extension_id(), 0);
EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &id.uid));
- ExtensionsService* service = profile()->GetExtensionsService();
+ ExtensionService* service = profile()->GetExtensionService();
ExtensionMenuManager* manager = service->menu_manager();
ExtensionMenuItem* item = manager->GetItemById(id);
@@ -349,7 +349,7 @@ bool RemoveContextMenuFunction::RunImpl() {
}
bool RemoveAllContextMenusFunction::RunImpl() {
- ExtensionsService* service = profile()->GetExtensionsService();
+ ExtensionService* service = profile()->GetExtensionService();
ExtensionMenuManager* manager = service->menu_manager();
manager->RemoveAllContextItems(extension_id());
return true;
diff --git a/chrome/browser/extensions/extension_context_menu_browsertest.cc b/chrome/browser/extensions/extension_context_menu_browsertest.cc
index 2397aa7..fe893f9 100644
--- a/chrome/browser/extensions/extension_context_menu_browsertest.cc
+++ b/chrome/browser/extensions/extension_context_menu_browsertest.cc
@@ -3,12 +3,13 @@
// found in the LICENSE file.
#include "app/menus/menu_model.h"
+#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/extensions/extension_test_message_listener.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/render_view_context_menu.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
@@ -145,14 +146,14 @@ class ExtensionContextMenuBrowserTest : public ExtensionBrowserTest {
// Shortcut to return the current ExtensionMenuManager.
ExtensionMenuManager* menu_manager() {
- return browser()->profile()->GetExtensionsService()->menu_manager();
+ return browser()->profile()->GetExtensionService()->menu_manager();
}
// Returns a pointer to the currently loaded extension with |name|, or null
// if not found.
const Extension* GetExtensionNamed(std::string name) {
const ExtensionList* extensions =
- browser()->profile()->GetExtensionsService()->extensions();
+ browser()->profile()->GetExtensionService()->extensions();
ExtensionList::const_iterator i;
for (i = extensions->begin(); i != extensions->end(); ++i) {
if ((*i)->name() == name) {
diff --git a/chrome/browser/extensions/extension_context_menu_model.cc b/chrome/browser/extensions/extension_context_menu_model.cc
index 047af99..70d4189 100644
--- a/chrome/browser/extensions/extension_context_menu_model.cc
+++ b/chrome/browser/extensions/extension_context_menu_model.cc
@@ -5,11 +5,10 @@
#include "chrome/browser/extensions/extension_context_menu_model.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/extensions/extension_action.h"
#include "chrome/common/extensions/extension_constants.h"
@@ -118,12 +117,12 @@ void ExtensionContextMenuModel::ExecuteCommand(int command_id) {
browser_);
break;
case HIDE: {
- ExtensionsService* extension_service = profile_->GetExtensionsService();
+ ExtensionService* extension_service = profile_->GetExtensionService();
extension_service->SetBrowserActionVisibility(extension, false);
break;
}
case DISABLE: {
- ExtensionsService* extension_service = profile_->GetExtensionsService();
+ ExtensionService* extension_service = profile_->GetExtensionService();
extension_service->DisableExtension(extension_id_);
break;
}
@@ -150,7 +149,7 @@ void ExtensionContextMenuModel::ExecuteCommand(int command_id) {
void ExtensionContextMenuModel::InstallUIProceed() {
if (GetExtension())
- profile_->GetExtensionsService()->UninstallExtension(extension_id_, false);
+ profile_->GetExtensionService()->UninstallExtension(extension_id_, false);
Release();
}
@@ -160,6 +159,6 @@ void ExtensionContextMenuModel::InstallUIAbort() {
}
const Extension* ExtensionContextMenuModel::GetExtension() const {
- ExtensionsService* extension_service = profile_->GetExtensionsService();
+ ExtensionService* extension_service = profile_->GetExtensionService();
return extension_service->GetExtensionById(extension_id_, false);
}
diff --git a/chrome/browser/extensions/extension_cookies_api.cc b/chrome/browser/extensions/extension_cookies_api.cc
index e66c4b3..0f61602 100644
--- a/chrome/browser/extensions/extension_cookies_api.cc
+++ b/chrome/browser/extensions/extension_cookies_api.cc
@@ -14,7 +14,7 @@
#include "chrome/browser/extensions/extension_cookies_api_constants.h"
#include "chrome/browser/extensions/extension_cookies_helpers.h"
#include "chrome/browser/extensions/extension_event_router.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_error_utils.h"
#include "chrome/common/net/url_request_context_getter.h"
@@ -191,7 +191,7 @@ void GetCookieFunction::GetCookieOnIOThread() {
void GetCookieFunction::RespondOnUIThread() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- net::CookieMonster::CookieList::iterator it;
+ net::CookieList::iterator it;
for (it = cookie_list_.begin(); it != cookie_list_.end(); ++it) {
// Return the first matching cookie. Relies on the fact that the
// CookieMonster returns them in canonical order (longest path, then
@@ -425,7 +425,7 @@ bool GetAllCookieStoresFunction::RunImpl() {
scoped_ptr<ListValue> original_tab_ids(new ListValue());
Profile* incognito_profile = NULL;
scoped_ptr<ListValue> incognito_tab_ids;
- if (include_incognito()) {
+ if (include_incognito() && profile()->HasOffTheRecordProfile()) {
incognito_profile = profile()->GetOffTheRecordProfile();
if (incognito_profile)
incognito_tab_ids.reset(new ListValue());
diff --git a/chrome/browser/extensions/extension_cookies_api.h b/chrome/browser/extensions/extension_cookies_api.h
index 50b922b..dc81731 100644
--- a/chrome/browser/extensions/extension_cookies_api.h
+++ b/chrome/browser/extensions/extension_cookies_api.h
@@ -106,7 +106,7 @@ class GetCookieFunction : public CookiesFunction {
GURL url_;
std::string store_id_;
scoped_refptr<URLRequestContextGetter> store_context_;
- net::CookieMonster::CookieList cookie_list_;
+ net::CookieList cookie_list_;
};
// Implements the cookies.getAll() extension function.
@@ -125,7 +125,7 @@ class GetAllCookiesFunction : public CookiesFunction {
GURL url_;
std::string store_id_;
scoped_refptr<URLRequestContextGetter> store_context_;
- net::CookieMonster::CookieList cookie_list_;
+ net::CookieList cookie_list_;
};
// Implements the cookies.set() extension function.
diff --git a/chrome/browser/extensions/extension_cookies_helpers.cc b/chrome/browser/extensions/extension_cookies_helpers.cc
index a140c8e..42e2fae 100644
--- a/chrome/browser/extensions/extension_cookies_helpers.cc
+++ b/chrome/browser/extensions/extension_cookies_helpers.cc
@@ -10,10 +10,10 @@
#include "base/values.h"
#include "chrome/browser/extensions/extension_cookies_api_constants.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tabs/tab_strip_model.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/url_constants.h"
#include "googleurl/src/gurl.h"
@@ -30,7 +30,8 @@ Profile* ChooseProfileFromStoreId(const std::string& store_id,
bool include_incognito) {
DCHECK(profile);
bool allow_original = !profile->IsOffTheRecord();
- bool allow_incognito = profile->IsOffTheRecord() || include_incognito;
+ bool allow_incognito = profile->IsOffTheRecord() ||
+ (include_incognito && profile->HasOffTheRecordProfile());
if (store_id == kOriginalProfileStoreId && allow_original)
return profile->GetOriginalProfile();
if (store_id == kOffTheRecordProfileStoreId && allow_incognito)
@@ -75,7 +76,7 @@ DictionaryValue* CreateCookieStoreValue(Profile* profile,
return result;
}
-net::CookieMonster::CookieList GetCookieListFromStore(
+net::CookieList GetCookieListFromStore(
net::CookieStore* cookie_store, const GURL& url) {
DCHECK(cookie_store);
net::CookieMonster* monster = cookie_store->GetCookieMonster();
@@ -97,12 +98,12 @@ GURL GetURLFromCanonicalCookie(
}
void AppendMatchingCookiesToList(
- const net::CookieMonster::CookieList& all_cookies,
+ const net::CookieList& all_cookies,
const std::string& store_id,
const GURL& url, const DictionaryValue* details,
const Extension* extension,
ListValue* match_list) {
- net::CookieMonster::CookieList::const_iterator it;
+ net::CookieList::const_iterator it;
for (it = all_cookies.begin(); it != all_cookies.end(); ++it) {
// Ignore any cookie whose domain doesn't match the extension's
// host permissions.
diff --git a/chrome/browser/extensions/extension_cookies_helpers.h b/chrome/browser/extensions/extension_cookies_helpers.h
index 7bb33d2..18bbf8d 100644
--- a/chrome/browser/extensions/extension_cookies_helpers.h
+++ b/chrome/browser/extensions/extension_cookies_helpers.h
@@ -49,7 +49,7 @@ DictionaryValue* CreateCookieStoreValue(Profile* profile,
// Retrieves all cookies from the given cookie store corresponding to the given
// URL. If the URL is empty, all cookies in the cookie store are retrieved.
// This can only be called on the IO thread.
-net::CookieMonster::CookieList GetCookieListFromStore(
+net::CookieList GetCookieListFromStore(
net::CookieStore* cookie_store, const GURL& url);
// Constructs a URL from a cookie's information for use in checking
@@ -63,7 +63,7 @@ GURL GetURLFromCanonicalCookie(
// match list all the cookies that both match the given URL and cookie details
// and are allowed by extension host permissions.
void AppendMatchingCookiesToList(
- const net::CookieMonster::CookieList& all_cookies,
+ const net::CookieList& all_cookies,
const std::string& store_id,
const GURL& url, const DictionaryValue* details,
const Extension* extension,
diff --git a/chrome/browser/extensions/extension_cookies_unittest.cc b/chrome/browser/extensions/extension_cookies_unittest.cc
index 6665052..2aa34a3 100644
--- a/chrome/browser/extensions/extension_cookies_unittest.cc
+++ b/chrome/browser/extensions/extension_cookies_unittest.cc
@@ -42,6 +42,10 @@ class OtrTestingProfile : public TestingProfile {
return linked_profile_;
}
+ virtual bool HasOffTheRecordProfile() {
+ return (!IsOffTheRecord() && linked_profile_);
+ }
+
static void LinkProfiles(OtrTestingProfile* profile1,
OtrTestingProfile* profile2) {
profile1->set_linked_profile(profile2);
diff --git a/chrome/browser/extensions/extension_crash_recovery_browsertest.cc b/chrome/browser/extensions/extension_crash_recovery_browsertest.cc
index 898de6b..cb489a1 100644
--- a/chrome/browser/extensions/extension_crash_recovery_browsertest.cc
+++ b/chrome/browser/extensions/extension_crash_recovery_browsertest.cc
@@ -7,19 +7,21 @@
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_process_manager.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/common/result_codes.h"
#include "chrome/test/ui_test_utils.h"
class ExtensionCrashRecoveryTest : public ExtensionBrowserTest {
protected:
- ExtensionsService* GetExtensionsService() {
- return browser()->profile()->GetExtensionsService();
+ ExtensionService* GetExtensionService() {
+ return browser()->profile()->GetExtensionService();
}
ExtensionProcessManager* GetExtensionProcessManager() {
@@ -50,9 +52,9 @@ class ExtensionCrashRecoveryTest : public ExtensionBrowserTest {
}
void CrashExtension(size_t index) {
- ASSERT_LT(index, GetExtensionsService()->extensions()->size());
+ ASSERT_LT(index, GetExtensionService()->extensions()->size());
const Extension* extension =
- GetExtensionsService()->extensions()->at(index);
+ GetExtensionService()->extensions()->at(index);
ASSERT_TRUE(extension);
std::string extension_id(extension->id());
ExtensionHost* extension_host =
@@ -61,17 +63,16 @@ class ExtensionCrashRecoveryTest : public ExtensionBrowserTest {
RenderProcessHost* extension_rph =
extension_host->render_view_host()->process();
- base::KillProcess(extension_rph->GetHandle(),
- base::PROCESS_END_KILLED_BY_USER, false);
+ base::KillProcess(extension_rph->GetHandle(), ResultCodes::KILLED, false);
ASSERT_TRUE(WaitForExtensionCrash(extension_id));
ASSERT_FALSE(
GetExtensionProcessManager()->GetBackgroundHostForExtension(extension));
}
void CheckExtensionConsistency(size_t index) {
- ASSERT_LT(index, GetExtensionsService()->extensions()->size());
+ ASSERT_LT(index, GetExtensionService()->extensions()->size());
const Extension* extension =
- GetExtensionsService()->extensions()->at(index);
+ GetExtensionService()->extensions()->at(index);
ASSERT_TRUE(extension);
ExtensionHost* extension_host =
GetExtensionProcessManager()->GetBackgroundHostForExtension(extension);
@@ -84,21 +85,21 @@ class ExtensionCrashRecoveryTest : public ExtensionBrowserTest {
void LoadTestExtension() {
ExtensionBrowserTest::SetUpInProcessBrowserTestFixture();
- const size_t size_before = GetExtensionsService()->extensions()->size();
+ const size_t size_before = GetExtensionService()->extensions()->size();
ASSERT_TRUE(LoadExtension(
test_data_dir_.AppendASCII("common").AppendASCII("background_page")));
- const Extension* extension = GetExtensionsService()->extensions()->back();
+ const Extension* extension = GetExtensionService()->extensions()->back();
ASSERT_TRUE(extension);
first_extension_id_ = extension->id();
CheckExtensionConsistency(size_before);
}
void LoadSecondExtension() {
- int offset = GetExtensionsService()->extensions()->size();
+ int offset = GetExtensionService()->extensions()->size();
ASSERT_TRUE(LoadExtension(
test_data_dir_.AppendASCII("install").AppendASCII("install")));
const Extension* extension =
- GetExtensionsService()->extensions()->at(offset);
+ GetExtensionService()->extensions()->at(offset);
ASSERT_TRUE(extension);
second_extension_id_ = extension->id();
CheckExtensionConsistency(offset);
@@ -109,10 +110,10 @@ class ExtensionCrashRecoveryTest : public ExtensionBrowserTest {
};
IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, Basic) {
- const size_t size_before = GetExtensionsService()->extensions()->size();
+ const size_t size_before = GetExtensionService()->extensions()->size();
LoadTestExtension();
CrashExtension(size_before);
- ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size());
+ ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
AcceptCrashedExtensionInfobar(0);
SCOPED_TRACE("after clicking the infobar");
@@ -120,10 +121,10 @@ IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, Basic) {
}
IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, CloseAndReload) {
- const size_t size_before = GetExtensionsService()->extensions()->size();
+ const size_t size_before = GetExtensionService()->extensions()->size();
LoadTestExtension();
CrashExtension(size_before);
- ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size());
+ ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
CancelCrashedExtensionInfobar(0);
ReloadExtension(first_extension_id_);
@@ -132,10 +133,10 @@ IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, CloseAndReload) {
}
IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, ReloadIndependently) {
- const size_t size_before = GetExtensionsService()->extensions()->size();
+ const size_t size_before = GetExtensionService()->extensions()->size();
LoadTestExtension();
CrashExtension(size_before);
- ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size());
+ ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
ReloadExtension(first_extension_id_);
@@ -150,22 +151,148 @@ IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, ReloadIndependently) {
ASSERT_EQ(0, current_tab->infobar_delegate_count());
}
+IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest,
+ ReloadIndependentlyChangeTabs) {
+ const size_t size_before = GetExtensionService()->extensions()->size();
+ LoadTestExtension();
+ CrashExtension(size_before);
+ ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
+
+ TabContents* original_tab = browser()->GetSelectedTabContents();
+ ASSERT_TRUE(original_tab);
+ ASSERT_EQ(1, original_tab->infobar_delegate_count());
+
+ // Open a new tab so the info bar will not be in the current tab.
+ browser()->NewTab();
+ TabContents* new_current_tab = browser()->GetSelectedTabContents();
+ ASSERT_TRUE(new_current_tab);
+ ASSERT_NE(new_current_tab, original_tab);
+ ASSERT_EQ(0, new_current_tab->infobar_delegate_count());
+
+ ReloadExtension(first_extension_id_);
+
+ SCOPED_TRACE("after reloading");
+ CheckExtensionConsistency(size_before);
+
+ // The infobar should automatically hide after the extension is successfully
+ // reloaded.
+ ASSERT_EQ(0, original_tab->infobar_delegate_count());
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest,
+ ReloadIndependentlyNavigatePage) {
+ const size_t size_before = GetExtensionService()->extensions()->size();
+ LoadTestExtension();
+ CrashExtension(size_before);
+ ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
+
+ TabContents* current_tab = browser()->GetSelectedTabContents();
+ ASSERT_TRUE(current_tab);
+ ASSERT_EQ(1, current_tab->infobar_delegate_count());
+
+ // Navigate to another page.
+ ui_test_utils::NavigateToURL(browser(),
+ ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
+ FilePath(FILE_PATH_LITERAL("title1.html"))));
+ ASSERT_EQ(1, current_tab->infobar_delegate_count());
+
+ ReloadExtension(first_extension_id_);
+
+ SCOPED_TRACE("after reloading");
+ CheckExtensionConsistency(size_before);
+
+ // The infobar should automatically hide after the extension is successfully
+ // reloaded.
+ ASSERT_EQ(0, current_tab->infobar_delegate_count());
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest,
+ ReloadIndependentlyTwoInfoBars) {
+ const size_t size_before = GetExtensionService()->extensions()->size();
+ LoadTestExtension();
+
+ // Open a new window so that there will be an info bar in each.
+ Browser* browser2 = CreateBrowser(browser()->profile());
+
+ CrashExtension(size_before);
+ ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
+
+ TabContents* current_tab = browser()->GetSelectedTabContents();
+ ASSERT_TRUE(current_tab);
+ ASSERT_EQ(1, current_tab->infobar_delegate_count());
+
+ TabContents* current_tab2 = browser2->GetSelectedTabContents();
+ ASSERT_TRUE(current_tab2);
+ ASSERT_EQ(1, current_tab2->infobar_delegate_count());
+
+ ReloadExtension(first_extension_id_);
+
+ SCOPED_TRACE("after reloading");
+ CheckExtensionConsistency(size_before);
+
+ // Both infobars should automatically hide after the extension is successfully
+ // reloaded.
+ ASSERT_EQ(0, current_tab->infobar_delegate_count());
+ ASSERT_EQ(0, current_tab2->infobar_delegate_count());
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest,
+ ReloadIndependentlyTwoInfoBarsSameBrowser) {
+ const size_t size_before = GetExtensionService()->extensions()->size();
+ LoadTestExtension();
+
+ // Open a new window so that there will be an info bar in each.
+ Browser* browser2 = CreateBrowser(browser()->profile());
+
+ CrashExtension(size_before);
+ ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
+
+ TabContents* current_tab = browser()->GetSelectedTabContents();
+ ASSERT_TRUE(current_tab);
+ ASSERT_EQ(1, current_tab->infobar_delegate_count());
+
+ TabContents* current_tab2 = browser2->GetSelectedTabContents();
+ ASSERT_TRUE(current_tab2);
+ ASSERT_EQ(1, current_tab2->infobar_delegate_count());
+
+ // Move second window into first browser so there will be multiple tabs
+ // with the info bar for the same extension in one browser.
+ TabContentsWrapper* contents =
+ browser2->tabstrip_model()->DetachTabContentsAt(0);
+ browser()->tabstrip_model()->AppendTabContents(contents, true);
+ current_tab2 = browser()->GetSelectedTabContents();
+ ASSERT_EQ(1, current_tab2->infobar_delegate_count());
+ ASSERT_NE(current_tab2, current_tab);
+
+ ReloadExtension(first_extension_id_);
+
+ SCOPED_TRACE("after reloading");
+ CheckExtensionConsistency(size_before);
+
+ // Both infobars should automatically hide after the extension is successfully
+ // reloaded.
+ ASSERT_EQ(0, current_tab2->infobar_delegate_count());
+ browser()->SelectPreviousTab();
+ ASSERT_EQ(current_tab, browser()->GetSelectedTabContents());
+ ASSERT_EQ(0, current_tab->infobar_delegate_count());
+}
+
// Make sure that when we don't do anything about the crashed extension
// and close the browser, it doesn't crash. The browser is closed implicitly
// at the end of each browser test.
IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, ShutdownWhileCrashed) {
- const size_t size_before = GetExtensionsService()->extensions()->size();
+ const size_t size_before = GetExtensionService()->extensions()->size();
LoadTestExtension();
CrashExtension(size_before);
- ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size());
+ ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
}
IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, TwoExtensionsCrashFirst) {
- const size_t size_before = GetExtensionsService()->extensions()->size();
+ const size_t size_before = GetExtensionService()->extensions()->size();
LoadTestExtension();
LoadSecondExtension();
CrashExtension(size_before);
- ASSERT_EQ(size_before + 1, GetExtensionsService()->extensions()->size());
+ ASSERT_EQ(size_before + 1, GetExtensionService()->extensions()->size());
AcceptCrashedExtensionInfobar(0);
SCOPED_TRACE("after clicking the infobar");
@@ -174,11 +301,11 @@ IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, TwoExtensionsCrashFirst) {
}
IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, TwoExtensionsCrashSecond) {
- const size_t size_before = GetExtensionsService()->extensions()->size();
+ const size_t size_before = GetExtensionService()->extensions()->size();
LoadTestExtension();
LoadSecondExtension();
CrashExtension(size_before + 1);
- ASSERT_EQ(size_before + 1, GetExtensionsService()->extensions()->size());
+ ASSERT_EQ(size_before + 1, GetExtensionService()->extensions()->size());
AcceptCrashedExtensionInfobar(0);
SCOPED_TRACE("after clicking the infobar");
@@ -188,13 +315,13 @@ IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, TwoExtensionsCrashSecond) {
IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest,
TwoExtensionsCrashBothAtOnce) {
- const size_t size_before = GetExtensionsService()->extensions()->size();
+ const size_t size_before = GetExtensionService()->extensions()->size();
LoadTestExtension();
LoadSecondExtension();
CrashExtension(size_before);
- ASSERT_EQ(size_before + 1, GetExtensionsService()->extensions()->size());
+ ASSERT_EQ(size_before + 1, GetExtensionService()->extensions()->size());
CrashExtension(size_before);
- ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size());
+ ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
{
SCOPED_TRACE("first infobar");
@@ -211,13 +338,13 @@ IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest,
}
IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, TwoExtensionsOneByOne) {
- const size_t size_before = GetExtensionsService()->extensions()->size();
+ const size_t size_before = GetExtensionService()->extensions()->size();
LoadTestExtension();
CrashExtension(size_before);
- ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size());
+ ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
LoadSecondExtension();
CrashExtension(size_before);
- ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size());
+ ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
{
SCOPED_TRACE("first infobar");
@@ -238,42 +365,42 @@ IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, TwoExtensionsOneByOne) {
// at the end of each browser test.
IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest,
TwoExtensionsShutdownWhileCrashed) {
- const size_t size_before = GetExtensionsService()->extensions()->size();
+ const size_t size_before = GetExtensionService()->extensions()->size();
LoadTestExtension();
CrashExtension(size_before);
- ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size());
+ ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
LoadSecondExtension();
CrashExtension(size_before);
- ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size());
+ ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
}
IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest,
TwoExtensionsIgnoreFirst) {
- const size_t size_before = GetExtensionsService()->extensions()->size();
+ const size_t size_before = GetExtensionService()->extensions()->size();
LoadTestExtension();
LoadSecondExtension();
CrashExtension(size_before);
- ASSERT_EQ(size_before + 1, GetExtensionsService()->extensions()->size());
+ ASSERT_EQ(size_before + 1, GetExtensionService()->extensions()->size());
CrashExtension(size_before);
- ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size());
+ ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
CancelCrashedExtensionInfobar(0);
AcceptCrashedExtensionInfobar(1);
SCOPED_TRACE("infobars done");
- ASSERT_EQ(size_before + 1, GetExtensionsService()->extensions()->size());
+ ASSERT_EQ(size_before + 1, GetExtensionService()->extensions()->size());
CheckExtensionConsistency(size_before);
}
IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest,
TwoExtensionsReloadIndependently) {
- const size_t size_before = GetExtensionsService()->extensions()->size();
+ const size_t size_before = GetExtensionService()->extensions()->size();
LoadTestExtension();
LoadSecondExtension();
CrashExtension(size_before);
- ASSERT_EQ(size_before + 1, GetExtensionsService()->extensions()->size());
+ ASSERT_EQ(size_before + 1, GetExtensionService()->extensions()->size());
CrashExtension(size_before);
- ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size());
+ ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
{
SCOPED_TRACE("first: reload");
diff --git a/chrome/browser/extensions/extension_data_deleter.cc b/chrome/browser/extensions/extension_data_deleter.cc
index 14ea9a2..f98ac86 100644
--- a/chrome/browser/extensions/extension_data_deleter.cc
+++ b/chrome/browser/extensions/extension_data_deleter.cc
@@ -5,13 +5,14 @@
#include "chrome/browser/extensions/extension_data_deleter.h"
#include "chrome/browser/in_process_webkit/webkit_context.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/net/url_request_context_getter.h"
#include "net/base/cookie_monster.h"
#include "net/base/net_errors.h"
#include "webkit/database/database_util.h"
#include "webkit/database/database_tracker.h"
+#include "webkit/fileapi/sandboxed_file_system_context.h"
ExtensionDataDeleter::ExtensionDataDeleter(Profile* profile,
const GURL& extension_url) {
@@ -19,6 +20,7 @@ ExtensionDataDeleter::ExtensionDataDeleter(Profile* profile,
webkit_context_ = profile->GetWebKitContext();
database_tracker_ = profile->GetDatabaseTracker();
extension_request_context_ = profile->GetRequestContextForExtensions();
+ file_system_context_ = profile->GetFileSystemContext();
extension_url_ = extension_url;
origin_id_ =
webkit_database::DatabaseUtil::GetOriginIdentifier(extension_url_);
@@ -48,6 +50,11 @@ void ExtensionDataDeleter::StartDeleting() {
BrowserThread::FILE, FROM_HERE,
NewRunnableMethod(
this, &ExtensionDataDeleter::DeleteDatabaseOnFileThread));
+
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(
+ this, &ExtensionDataDeleter::DeleteFileSystemOnFileThread));
}
void ExtensionDataDeleter::DeleteCookiesOnIOThread() {
@@ -74,3 +81,8 @@ void ExtensionDataDeleter::DeleteIndexedDBOnWebkitThread() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
webkit_context_->indexed_db_context()->DeleteIndexedDBForOrigin(origin_id_);
}
+
+void ExtensionDataDeleter::DeleteFileSystemOnFileThread() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ file_system_context_->DeleteDataForOriginOnFileThread(extension_url_);
+}
diff --git a/chrome/browser/extensions/extension_data_deleter.h b/chrome/browser/extensions/extension_data_deleter.h
index 0a535fe..960f06f 100644
--- a/chrome/browser/extensions/extension_data_deleter.h
+++ b/chrome/browser/extensions/extension_data_deleter.h
@@ -15,13 +15,17 @@ namespace webkit_database {
class DatabaseTracker;
}
+namespace fileapi {
+class SandboxedFileSystemContext;
+}
+
class Profile;
class URLRequestContextGetter;
class WebKitContext;
// A helper class that takes care of removing local storage, databases and
// cookies for a given extension. This is used by
-// ExtensionsService::ClearExtensionData() upon uninstalling an extension.
+// ExtensionService::ClearExtensionData() upon uninstalling an extension.
class ExtensionDataDeleter
: public base::RefCountedThreadSafe<ExtensionDataDeleter,
BrowserThread::DeleteOnUIThread> {
@@ -52,6 +56,10 @@ class ExtensionDataDeleter
// webkit thread.
void DeleteIndexedDBOnWebkitThread();
+ // Deletes filesystem files for the extension. May only be called on the
+ // file thread.
+ void DeleteFileSystemOnFileThread();
+
// The database context for deleting the database.
scoped_refptr<webkit_database::DatabaseTracker> database_tracker_;
@@ -67,6 +75,8 @@ class ExtensionDataDeleter
// Webkit context for accessing the DOM storage helper.
scoped_refptr<WebKitContext> webkit_context_;
+ scoped_refptr<fileapi::SandboxedFileSystemContext> file_system_context_;
+
DISALLOW_COPY_AND_ASSIGN(ExtensionDataDeleter);
};
diff --git a/chrome/browser/extensions/extension_devtools_bridge.cc b/chrome/browser/extensions/extension_devtools_bridge.cc
index 3a8f525..8394ad0 100644
--- a/chrome/browser/extensions/extension_devtools_bridge.cc
+++ b/chrome/browser/extensions/extension_devtools_bridge.cc
@@ -12,9 +12,9 @@
#include "chrome/browser/extensions/extension_devtools_manager.h"
#include "chrome/browser/extensions/extension_event_router.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/devtools_messages.h"
ExtensionDevToolsBridge::ExtensionDevToolsBridge(int tab_id,
diff --git a/chrome/browser/extensions/extension_devtools_browsertests.cc b/chrome/browser/extensions/extension_devtools_browsertests.cc
index cc61b3d..c29a4ca 100644
--- a/chrome/browser/extensions/extension_devtools_browsertests.cc
+++ b/chrome/browser/extensions/extension_devtools_browsertests.cc
@@ -11,9 +11,9 @@
#include "chrome/browser/extensions/extension_error_reporter.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_process_manager.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/tab_contents/tab_contents.h"
@@ -21,7 +21,6 @@
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/devtools_messages.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/ui_test_utils.h"
#include "net/base/net_util.h"
diff --git a/chrome/browser/extensions/extension_disabled_infobar_delegate.cc b/chrome/browser/extensions/extension_disabled_infobar_delegate.cc
index 354fea9..28e0709 100644
--- a/chrome/browser/extensions/extension_disabled_infobar_delegate.cc
+++ b/chrome/browser/extensions/extension_disabled_infobar_delegate.cc
@@ -8,16 +8,16 @@
#include "app/l10n_util.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/extensions/extension_install_ui.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/browser_list.h"
#include "chrome/common/extensions/extension_file_util.h"
#include "chrome/common/extensions/extension_resource.h"
+#include "chrome/common/notification_details.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
#include "grit/generated_resources.h"
class ExtensionDisabledDialogDelegate
@@ -25,7 +25,7 @@ class ExtensionDisabledDialogDelegate
public base::RefCountedThreadSafe<ExtensionDisabledDialogDelegate> {
public:
ExtensionDisabledDialogDelegate(Profile* profile,
- ExtensionsService* service,
+ ExtensionService* service,
const Extension* extension)
: service_(service), extension_(extension) {
AddRef(); // Balanced in Proceed or Abort.
@@ -52,7 +52,7 @@ class ExtensionDisabledDialogDelegate
// The UI for showing the install dialog when enabling.
scoped_ptr<ExtensionInstallUI> install_ui_;
- ExtensionsService* service_;
+ ExtensionService* service_;
const Extension* extension_;
};
@@ -61,7 +61,7 @@ class ExtensionDisabledInfobarDelegate
public NotificationObserver {
public:
ExtensionDisabledInfobarDelegate(TabContents* tab_contents,
- ExtensionsService* service,
+ ExtensionService* service,
const Extension* extension)
: ConfirmInfoBarDelegate(tab_contents),
tab_contents_(tab_contents),
@@ -70,7 +70,7 @@ class ExtensionDisabledInfobarDelegate
// The user might re-enable the extension in other ways, so watch for that.
registrar_.Add(this, NotificationType::EXTENSION_LOADED,
Source<Profile>(service->profile()));
- registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED,
+ registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
Source<Profile>(service->profile()));
}
virtual ~ExtensionDisabledInfobarDelegate() {
@@ -106,27 +106,34 @@ class ExtensionDisabledInfobarDelegate
const NotificationDetails& details) {
// TODO(mpcomplete): RemoveInfoBar doesn't seem to always result in us
// getting deleted.
+ const Extension* extension = NULL;
switch (type.value) {
case NotificationType::EXTENSION_LOADED:
- case NotificationType::EXTENSION_UNLOADED_DISABLED: {
- const Extension* extension = Details<const Extension>(details).ptr();
- if (extension == extension_)
- tab_contents_->RemoveInfoBar(this);
+ extension = Details<const Extension>(details).ptr();
+ break;
+ case NotificationType::EXTENSION_UNLOADED: {
+ UnloadedExtensionInfo* info =
+ Details<UnloadedExtensionInfo>(details).ptr();
+ if (info->reason == UnloadedExtensionInfo::DISABLE)
+ extension = info->extension;
break;
}
default:
NOTREACHED();
+ return;
}
+ if (extension == extension_)
+ tab_contents_->RemoveInfoBar(this);
}
private:
NotificationRegistrar registrar_;
TabContents* tab_contents_;
- ExtensionsService* service_;
+ ExtensionService* service_;
const Extension* extension_;
};
-void ShowExtensionDisabledUI(ExtensionsService* service, Profile* profile,
+void ShowExtensionDisabledUI(ExtensionService* service, Profile* profile,
const Extension* extension) {
Browser* browser = BrowserList::GetLastActiveWithProfile(profile);
if (!browser)
@@ -140,7 +147,7 @@ void ShowExtensionDisabledUI(ExtensionsService* service, Profile* profile,
tab_contents, service, extension));
}
-void ShowExtensionDisabledDialog(ExtensionsService* service, Profile* profile,
+void ShowExtensionDisabledDialog(ExtensionService* service, Profile* profile,
const Extension* extension) {
// This object manages its own lifetime.
new ExtensionDisabledDialogDelegate(profile, service, extension);
diff --git a/chrome/browser/extensions/extension_disabled_infobar_delegate.h b/chrome/browser/extensions/extension_disabled_infobar_delegate.h
index 430e652..665b0eb 100644
--- a/chrome/browser/extensions/extension_disabled_infobar_delegate.h
+++ b/chrome/browser/extensions/extension_disabled_infobar_delegate.h
@@ -7,16 +7,16 @@
#pragma once
class Extension;
-class ExtensionsService;
+class ExtensionService;
class Profile;
// Shows UI to inform the user that an extension was disabled after upgrading
// to higher permissions.
-void ShowExtensionDisabledUI(ExtensionsService* service, Profile* profile,
+void ShowExtensionDisabledUI(ExtensionService* service, Profile* profile,
const Extension* extension);
// Shows the extension install dialog.
-void ShowExtensionDisabledDialog(ExtensionsService* service, Profile* profile,
+void ShowExtensionDisabledDialog(ExtensionService* service, Profile* profile,
const Extension* extension);
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_DISABLED_INFOBAR_DELEGATE_H_
diff --git a/chrome/browser/extensions/extension_dom_ui.cc b/chrome/browser/extensions/extension_dom_ui.cc
index faaa74b..97889d7 100644
--- a/chrome/browser/extensions/extension_dom_ui.cc
+++ b/chrome/browser/extensions/extension_dom_ui.cc
@@ -5,17 +5,17 @@
#include "chrome/browser/extensions/extension_dom_ui.h"
#include <set>
+#include <vector>
#include "net/base/file_stream.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/extensions/extension_bookmark_manager_api.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/image_loading_tracker.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
@@ -64,7 +64,7 @@ class ExtensionDOMUIImageLoadingTracker : public ImageLoadingTracker::Observer {
extension_(NULL) {
// Even when the extensions service is enabled by default, it's still
// disabled in incognito mode.
- ExtensionsService* service = profile->GetExtensionsService();
+ ExtensionService* service = profile->GetExtensionService();
if (service)
extension_ = service->GetExtensionByURL(page_url);
}
@@ -125,7 +125,7 @@ const char ExtensionDOMUI::kExtensionURLOverrides[] =
ExtensionDOMUI::ExtensionDOMUI(TabContents* tab_contents, const GURL& url)
: DOMUI(tab_contents),
url_(url) {
- ExtensionsService* service = tab_contents->profile()->GetExtensionsService();
+ ExtensionService* service = tab_contents->profile()->GetExtensionService();
const Extension* extension = service->GetExtensionByURL(url);
if (!extension)
extension = service->GetExtensionByWebExtent(url);
@@ -242,7 +242,7 @@ bool ExtensionDOMUI::HandleChromeURLOverride(GURL* url, Profile* profile) {
if (!overrides || !overrides->GetList(page, &url_list))
return false;
- ExtensionsService* service = profile->GetExtensionsService();
+ ExtensionService* service = profile->GetExtensionService();
size_t i = 0;
while (i < url_list->GetSize()) {
diff --git a/chrome/browser/extensions/extension_event_router.cc b/chrome/browser/extensions/extension_event_router.cc
index 4fc48e3..0b4f799 100644
--- a/chrome/browser/extensions/extension_event_router.cc
+++ b/chrome/browser/extensions/extension_event_router.cc
@@ -10,8 +10,8 @@
#include "chrome/browser/extensions/extension_processes_api.h"
#include "chrome/browser/extensions/extension_processes_api_constants.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_service.h"
@@ -56,7 +56,7 @@ struct ExtensionEventRouter::EventListener {
bool ExtensionEventRouter::CanCrossIncognito(Profile* profile,
const std::string& extension_id) {
const Extension* extension =
- profile->GetExtensionsService()->GetExtensionById(extension_id, false);
+ profile->GetExtensionService()->GetExtensionById(extension_id, false);
return CanCrossIncognito(profile, extension);
}
@@ -66,7 +66,7 @@ bool ExtensionEventRouter::CanCrossIncognito(Profile* profile,
// We allow the extension to see events and data from another profile iff it
// uses "spanning" behavior and it has incognito access. "split" mode
// extensions only see events for a matching profile.
- return (profile->GetExtensionsService()->IsIncognitoEnabled(extension) &&
+ return (profile->GetExtensionService()->IsIncognitoEnabled(extension) &&
!extension->incognito_split_mode());
}
@@ -168,7 +168,7 @@ void ExtensionEventRouter::DispatchEventImpl(
return;
std::set<EventListener>& listeners = it->second;
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
// Send the event only to renderers that are listening for it.
for (std::set<EventListener>::iterator listener = listeners.begin();
diff --git a/chrome/browser/extensions/extension_fileapi_apitest.cc b/chrome/browser/extensions/extension_fileapi_apitest.cc
new file mode 100644
index 0000000..782a600
--- /dev/null
+++ b/chrome/browser/extensions/extension_fileapi_apitest.cc
@@ -0,0 +1,9 @@
+// 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.
+
+#include "chrome/browser/extensions/extension_apitest.h"
+
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, FileAPI) {
+ ASSERT_TRUE(RunExtensionTest("fileapi")) << message_;
+}
diff --git a/chrome/browser/extensions/extension_function.cc b/chrome/browser/extensions/extension_function.cc
index 88a6c9e..054c882 100644
--- a/chrome/browser/extensions/extension_function.cc
+++ b/chrome/browser/extensions/extension_function.cc
@@ -7,8 +7,8 @@
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "chrome/browser/extensions/extension_function_dispatcher.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
ExtensionFunction::ExtensionFunction()
: request_id_(-1),
@@ -22,7 +22,7 @@ ExtensionFunction::~ExtensionFunction() {
}
const Extension* ExtensionFunction::GetExtension() {
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
DCHECK(service);
return service->GetExtensionById(extension_id_, false);
}
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index 7c86ed7..3c98cf3 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -50,10 +50,12 @@
#include "chrome/browser/extensions/extension_tts_api.h"
#include "chrome/browser/extensions/extension_webstore_private_api.h"
#include "chrome/browser/extensions/extensions_quota_service.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/common/notification_service.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/render_messages_params.h"
#include "chrome/common/result_codes.h"
@@ -75,7 +77,7 @@ ExtensionFunction* NewExtensionFunction() {
// create instances of them.
class FactoryRegistry {
public:
- static FactoryRegistry* instance();
+ static FactoryRegistry* GetInstance();
FactoryRegistry() { ResetFunctions(); }
// Resets all functions to their default values.
@@ -102,7 +104,7 @@ class FactoryRegistry {
FactoryMap factories_;
};
-FactoryRegistry* FactoryRegistry::instance() {
+FactoryRegistry* FactoryRegistry::GetInstance() {
return Singleton<FactoryRegistry>::get();
}
@@ -239,6 +241,7 @@ void FactoryRegistry::ResetFunctions() {
RegisterFunction<ExtensionTtsSpeakFunction>();
RegisterFunction<ExtensionTtsStopSpeakingFunction>();
RegisterFunction<ExtensionTtsIsSpeakingFunction>();
+ RegisterFunction<ExtensionTtsSpeakCompletedFunction>();
// Clipboard.
RegisterFunction<ExecuteCopyClipboardFunction>();
@@ -325,24 +328,24 @@ ExtensionFunction* FactoryRegistry::NewFunction(const std::string& name) {
void ExtensionFunctionDispatcher::GetAllFunctionNames(
std::vector<std::string>* names) {
- FactoryRegistry::instance()->GetAllNames(names);
+ FactoryRegistry::GetInstance()->GetAllNames(names);
}
bool ExtensionFunctionDispatcher::OverrideFunction(
const std::string& name, ExtensionFunctionFactory factory) {
- return FactoryRegistry::instance()->OverrideFunction(name, factory);
+ return FactoryRegistry::GetInstance()->OverrideFunction(name, factory);
}
void ExtensionFunctionDispatcher::ResetFunctions() {
- FactoryRegistry::instance()->ResetFunctions();
+ FactoryRegistry::GetInstance()->ResetFunctions();
}
ExtensionFunctionDispatcher* ExtensionFunctionDispatcher::Create(
RenderViewHost* render_view_host,
Delegate* delegate,
const GURL& url) {
- ExtensionsService* service =
- render_view_host->process()->profile()->GetExtensionsService();
+ ExtensionService* service =
+ render_view_host->process()->profile()->GetExtensionService();
DCHECK(service);
if (!service->ExtensionBindingsAllowed(url))
@@ -387,7 +390,7 @@ ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(
DOMUIFavIconSource* favicon_source = new DOMUIFavIconSource(profile_);
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(Singleton<ChromeURLDataManager>::get(),
+ NewRunnableMethod(ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(favicon_source)));
}
@@ -444,7 +447,7 @@ Browser* ExtensionFunctionDispatcher::GetCurrentBrowser(
void ExtensionFunctionDispatcher::HandleRequest(
const ViewHostMsg_DomMessage_Params& params) {
scoped_refptr<ExtensionFunction> function(
- FactoryRegistry::instance()->NewFunction(params.name));
+ FactoryRegistry::GetInstance()->NewFunction(params.name));
function->set_dispatcher_peer(peer_);
function->set_profile(profile_);
function->set_extension_id(extension_id());
@@ -453,7 +456,7 @@ void ExtensionFunctionDispatcher::HandleRequest(
function->set_request_id(params.request_id);
function->set_has_callback(params.has_callback);
function->set_user_gesture(params.user_gesture);
- ExtensionsService* service = profile()->GetExtensionsService();
+ ExtensionService* service = profile()->GetExtensionService();
DCHECK(service);
const Extension* extension = service->GetExtensionById(extension_id(), false);
DCHECK(extension);
@@ -493,6 +496,7 @@ void ExtensionFunctionDispatcher::HandleBadMessage(ExtensionFunction* api) {
CHECK(false);
} else {
NOTREACHED();
+ UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_EFD"));
base::KillProcess(render_view_host_->process()->GetHandle(),
ResultCodes::KILLED_BAD_MESSAGE, false);
}
diff --git a/chrome/browser/extensions/extension_history_api.cc b/chrome/browser/extensions/extension_history_api.cc
index 6c07488..5ff98e3 100644
--- a/chrome/browser/extensions/extension_history_api.cc
+++ b/chrome/browser/extensions/extension_history_api.cc
@@ -14,7 +14,7 @@
#include "chrome/browser/extensions/extension_history_api_constants.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/history/history_types.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/notification_service.h"
diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc
index 4aea841..1d60390 100644
--- a/chrome/browser/extensions/extension_host.cc
+++ b/chrome/browser/extensions/extension_host.cc
@@ -21,12 +21,11 @@
#include "chrome/browser/dom_ui/dom_ui_factory.h"
#include "chrome/browser/extensions/extension_message_service.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/file_select_helper.h"
-#include "chrome/browser/message_box_handler.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
@@ -37,6 +36,7 @@
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/ui/app_modal_dialogs/message_box_handler.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/bindings_policy.h"
#include "chrome/common/extensions/extension.h"
@@ -66,7 +66,7 @@ bool ExtensionHost::enable_dom_automation_ = false;
// ExtensionHosts, to avoid blocking the UI.
class ExtensionHost::ProcessCreationQueue {
public:
- static ProcessCreationQueue* get() {
+ static ProcessCreationQueue* GetInstance() {
return Singleton<ProcessCreationQueue>::get();
}
@@ -155,7 +155,7 @@ ExtensionHost::~ExtensionHost() {
NotificationType::EXTENSION_HOST_DESTROYED,
Source<Profile>(profile_),
Details<ExtensionHost>(this));
- ProcessCreationQueue::get()->Remove(this);
+ ProcessCreationQueue::GetInstance()->Remove(this);
render_view_host_->Shutdown(); // deletes render_view_host
}
@@ -177,6 +177,10 @@ void ExtensionHost::CreateView(Browser* browser) {
#endif
}
+TabContents* ExtensionHost::associated_tab_contents() const {
+ return associated_tab_contents_;
+}
+
RenderProcessHost* ExtensionHost::render_process_host() const {
return render_view_host_->process();
}
@@ -197,7 +201,7 @@ void ExtensionHost::CreateRenderViewSoon(RenderWidgetHostView* host_view) {
// to defer.
CreateRenderViewNow();
} else {
- ProcessCreationQueue::get()->CreateSoon(this);
+ ProcessCreationQueue::GetInstance()->CreateSoon(this);
}
}
@@ -206,7 +210,7 @@ void ExtensionHost::CreateRenderViewNow() {
NavigateToURL(url_);
DCHECK(IsRenderViewLive());
if (is_background_page())
- profile_->GetExtensionsService()->DidCreateRenderViewForBackgroundPage(
+ profile_->GetExtensionService()->DidCreateRenderViewForBackgroundPage(
this);
}
@@ -231,7 +235,7 @@ void ExtensionHost::NavigateToURL(const GURL& url) {
url_ = url;
if (!is_background_page() &&
- !profile_->GetExtensionsService()->IsBackgroundPageReady(extension_)) {
+ !profile_->GetExtensionService()->IsBackgroundPageReady(extension_)) {
// Make sure the background page loads before any others.
registrar_.Add(this, NotificationType::EXTENSION_BACKGROUND_PAGE_READY,
Source<Extension>(extension_));
@@ -246,7 +250,7 @@ void ExtensionHost::Observe(NotificationType type,
const NotificationDetails& details) {
switch (type.value) {
case NotificationType::EXTENSION_BACKGROUND_PAGE_READY:
- DCHECK(profile_->GetExtensionsService()->
+ DCHECK(profile_->GetExtensionService()->
IsBackgroundPageReady(extension_));
NavigateToURL(url_);
break;
@@ -261,7 +265,7 @@ void ExtensionHost::Observe(NotificationType type,
// sent. NULL it out so that dirty pointer issues don't arise in cases
// when multiple ExtensionHost objects pointing to the same Extension are
// present.
- if (extension_ == Details<const Extension>(details).ptr())
+ if (extension_ == Details<UnloadedExtensionInfo>(details)->extension)
extension_ = NULL;
break;
default:
@@ -284,7 +288,9 @@ void ExtensionHost::ClearInspectorSettings() {
RenderViewHostDelegateHelper::ClearInspectorSettings(profile());
}
-void ExtensionHost::RenderViewGone(RenderViewHost* render_view_host) {
+void ExtensionHost::RenderViewGone(RenderViewHost* render_view_host,
+ base::TerminationStatus status,
+ int error_code) {
// During browser shutdown, we may use sudden termination on an extension
// process, so it is expected to lose our connection to the render view.
// Do nothing.
@@ -391,7 +397,7 @@ void ExtensionHost::DocumentAvailableInMainFrame(RenderViewHost* rvh) {
document_element_available_ = true;
if (is_background_page()) {
- profile_->GetExtensionsService()->SetBackgroundPageReady(extension_);
+ profile_->GetExtensionService()->SetBackgroundPageReady(extension_);
} else {
switch (extension_host_type_) {
case ViewType::EXTENSION_INFOBAR:
@@ -444,6 +450,14 @@ gfx::NativeWindow ExtensionHost::GetMessageBoxRootWindow() {
return NULL;
}
+TabContents* ExtensionHost::AsTabContents() {
+ return NULL;
+}
+
+ExtensionHost* ExtensionHost::AsExtensionHost() {
+ return this;
+}
+
void ExtensionHost::OnMessageBoxClosed(IPC::Message* reply_msg,
bool success,
const std::wstring& prompt) {
@@ -487,6 +501,14 @@ WebPreferences ExtensionHost::GetWebkitPrefs() {
extension_host_type_ == ViewType::EXTENSION_INFOBAR)
webkit_prefs.allow_scripts_to_close_windows = true;
+ // Disable anything that requires the GPU process for background pages.
+ // See http://crbug.com/64512 and http://crbug.com/64841.
+ if (extension_host_type_ == ViewType::EXTENSION_BACKGROUND_PAGE) {
+ webkit_prefs.experimental_webgl_enabled = false;
+ webkit_prefs.accelerated_compositing_enabled = false;
+ webkit_prefs.accelerated_2d_canvas_enabled = false;
+ }
+
// TODO(dcheng): incorporate this setting into kClipboardPermission check.
webkit_prefs.javascript_can_access_clipboard = true;
@@ -734,6 +756,10 @@ ViewType::Type ExtensionHost::GetRenderViewType() const {
return extension_host_type_;
}
+const GURL& ExtensionHost::GetURL() const {
+ return url_;
+}
+
void ExtensionHost::RenderViewCreated(RenderViewHost* render_view_host) {
if (view_.get())
view_->RenderViewCreated();
diff --git a/chrome/browser/extensions/extension_host.h b/chrome/browser/extensions/extension_host.h
index d121145..801bdab 100644
--- a/chrome/browser/extensions/extension_host.h
+++ b/chrome/browser/extensions/extension_host.h
@@ -12,13 +12,13 @@
#include "base/perftimer.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/extensions/extension_function_dispatcher.h"
-#include "chrome/browser/js_modal_dialog.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
#include "chrome/browser/tab_contents/render_view_host_delegate_helper.h"
+#include "chrome/browser/ui/app_modal_dialogs/js_modal_dialog.h"
#if defined(TOOLKIT_VIEWS)
#include "chrome/browser/views/extensions/extension_view.h"
#elif defined(OS_MACOSX)
-#include "chrome/browser/cocoa/extension_view_mac.h"
+#include "chrome/browser/ui/cocoa/extension_view_mac.h"
#elif defined(TOOLKIT_GTK)
#include "chrome/browser/gtk/extension_view_gtk.h"
#endif
@@ -83,9 +83,7 @@ class ExtensionHost : public RenderViewHostDelegate,
ViewType::Type extension_host_type() const { return extension_host_type_; }
// ExtensionFunctionDispatcher::Delegate
- virtual TabContents* associated_tab_contents() const {
- return associated_tab_contents_;
- }
+ virtual TabContents* associated_tab_contents() const;
void set_associated_tab_contents(TabContents* associated_tab_contents) {
associated_tab_contents_ = associated_tab_contents;
}
@@ -109,12 +107,14 @@ class ExtensionHost : public RenderViewHostDelegate,
void DisableScrollbarsForSmallWindows(const gfx::Size& size_limit);
// RenderViewHostDelegate::View implementation.
- virtual const GURL& GetURL() const { return url_; }
+ virtual const GURL& GetURL() const;
virtual void RenderViewCreated(RenderViewHost* render_view_host);
virtual ViewType::Type GetRenderViewType() const;
virtual FileSelect* GetFileSelectDelegate();
virtual int GetBrowserWindowID() const;
- virtual void RenderViewGone(RenderViewHost* render_view_host);
+ virtual void RenderViewGone(RenderViewHost* render_view_host,
+ base::TerminationStatus status,
+ int error_code);
virtual void DidNavigate(RenderViewHost* render_view_host,
const ViewHostMsg_FrameNavigate_Params& params);
virtual void DidStopLoading();
@@ -192,8 +192,8 @@ class ExtensionHost : public RenderViewHostDelegate,
const std::wstring& prompt);
virtual void SetSuppressMessageBoxes(bool suppress_message_boxes) {}
virtual gfx::NativeWindow GetMessageBoxRootWindow();
- virtual TabContents* AsTabContents() { return NULL; }
- virtual ExtensionHost* AsExtensionHost() { return this; }
+ virtual TabContents* AsTabContents();
+ virtual ExtensionHost* AsExtensionHost();
protected:
// Internal functions used to support the CreateNewWidget() method. If a
diff --git a/chrome/browser/extensions/extension_host_mac.mm b/chrome/browser/extensions/extension_host_mac.mm
index d6de067..67bc851 100644
--- a/chrome/browser/extensions/extension_host_mac.mm
+++ b/chrome/browser/extensions/extension_host_mac.mm
@@ -4,10 +4,10 @@
#include "chrome/browser/extensions/extension_host_mac.h"
-#import "chrome/browser/cocoa/chrome_event_processing_window.h"
-#import "chrome/browser/cocoa/extensions/extension_popup_controller.h"
-#import "chrome/browser/cocoa/info_bubble_window.h"
#include "chrome/browser/renderer_host/render_widget_host_view_mac.h"
+#import "chrome/browser/ui/cocoa/chrome_event_processing_window.h"
+#import "chrome/browser/ui/cocoa/extensions/extension_popup_controller.h"
+#import "chrome/browser/ui/cocoa/info_bubble_window.h"
#include "chrome/common/native_web_keyboard_event.h"
ExtensionHostMac::~ExtensionHostMac() {
diff --git a/chrome/browser/extensions/extension_i18n_api.cc b/chrome/browser/extensions/extension_i18n_api.cc
index 40964a7..def4380 100644
--- a/chrome/browser/extensions/extension_i18n_api.cc
+++ b/chrome/browser/extensions/extension_i18n_api.cc
@@ -7,7 +7,7 @@
#include "base/string_piece.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
// Errors.
diff --git a/chrome/browser/extensions/extension_idle_api.cc b/chrome/browser/extensions/extension_idle_api.cc
index 76144a4..b43e6c8 100644
--- a/chrome/browser/extensions/extension_idle_api.cc
+++ b/chrome/browser/extensions/extension_idle_api.cc
@@ -17,11 +17,11 @@
#include "chrome/browser/extensions/extension_event_router.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_idle_api_constants.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/extensions/extension.h"
-#include "chrome/common/notification_service.h"
namespace keys = extension_idle_api_constants;
diff --git a/chrome/browser/extensions/extension_idle_api.h b/chrome/browser/extensions/extension_idle_api.h
index d6e0c89..9f40481 100644
--- a/chrome/browser/extensions/extension_idle_api.h
+++ b/chrome/browser/extensions/extension_idle_api.h
@@ -7,9 +7,10 @@
#pragma once
#include "chrome/browser/idle.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/extensions/extension_function.h"
+class Profile;
+
// Event router class for events related to the idle API.
class ExtensionIdleEventRouter {
public:
diff --git a/chrome/browser/extensions/extension_incognito_apitest.cc b/chrome/browser/extensions/extension_incognito_apitest.cc
index 52ee7c3..315ac99 100644
--- a/chrome/browser/extensions/extension_incognito_apitest.cc
+++ b/chrome/browser/extensions/extension_incognito_apitest.cc
@@ -6,10 +6,10 @@
#include "chrome/browser/browser_window.h"
#include "chrome/browser/extensions/browser_action_test_util.h"
#include "chrome/browser/extensions/extension_apitest.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_test_message_listener.h"
#include "chrome/browser/extensions/user_script_master.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_switches.h"
@@ -86,8 +86,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, IncognitoYesScript) {
// accidentially create and incognito profile.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DontCreateIncognitoProfile) {
ASSERT_FALSE(browser()->profile()->HasOffTheRecordProfile());
- ASSERT_TRUE(
- RunExtensionTestIncognito("incognito/enumerate_tabs")) << message_;
+ ASSERT_TRUE(RunExtensionTestIncognito(
+ "incognito/dont_create_profile")) << message_;
ASSERT_FALSE(browser()->profile()->HasOffTheRecordProfile());
}
diff --git a/chrome/browser/extensions/extension_infobar_apitest.cc b/chrome/browser/extensions/extension_infobar_apitest.cc
index 5932185..0ca70c8 100644
--- a/chrome/browser/extensions/extension_infobar_apitest.cc
+++ b/chrome/browser/extensions/extension_infobar_apitest.cc
@@ -6,7 +6,7 @@
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/common/chrome_switches.h"
-#if defined(TOOLKIT_VIEWS)
+#if defined(OS_WIN)
#define MAYBE_Infobars Infobars
#else
// Need to finish port to Linux. See http://crbug.com/39916 for details.
diff --git a/chrome/browser/extensions/extension_infobar_delegate.cc b/chrome/browser/extensions/extension_infobar_delegate.cc
index 3f9b861..140a82f 100644
--- a/chrome/browser/extensions/extension_infobar_delegate.cc
+++ b/chrome/browser/extensions/extension_infobar_delegate.cc
@@ -6,9 +6,10 @@
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_process_manager.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"
@@ -38,6 +39,10 @@ ExtensionInfoBarDelegate::~ExtensionInfoBarDelegate() {
observer_->OnDelegateDeleted();
}
+void ExtensionInfoBarDelegate::InfoBarDismissed() {
+ closing_ = true;
+}
+
bool ExtensionInfoBarDelegate::EqualsDelegate(InfoBarDelegate* delegate) const {
ExtensionInfoBarDelegate* extension_delegate =
delegate->AsExtensionInfoBarDelegate();
@@ -78,7 +83,8 @@ void ExtensionInfoBarDelegate::Observe(NotificationType type,
break;
}
case NotificationType::EXTENSION_UNLOADED: {
- const Extension* extension = Details<const Extension>(details).ptr();
+ const Extension* extension =
+ Details<UnloadedExtensionInfo>(details)->extension;
if (extension_ == extension)
tab_contents_->RemoveInfoBar(this);
break;
diff --git a/chrome/browser/extensions/extension_infobar_delegate.h b/chrome/browser/extensions/extension_infobar_delegate.h
index e929fee..f286a11 100644
--- a/chrome/browser/extensions/extension_infobar_delegate.h
+++ b/chrome/browser/extensions/extension_infobar_delegate.h
@@ -37,7 +37,7 @@ class ExtensionInfoBarDelegate : public InfoBarDelegate,
void set_observer(DelegateObserver* observer) { observer_ = observer; }
// Overridden from InfoBarDelegate:
- virtual void InfoBarDismissed() { closing_ = true; }
+ virtual void InfoBarDismissed();
virtual bool EqualsDelegate(InfoBarDelegate* delegate) const;
virtual void InfoBarClosed();
virtual InfoBar* CreateInfoBar();
diff --git a/chrome/browser/extensions/extension_infobar_module.cc b/chrome/browser/extensions/extension_infobar_module.cc
index 21d94ae..707630c 100644
--- a/chrome/browser/extensions/extension_infobar_module.cc
+++ b/chrome/browser/extensions/extension_infobar_module.cc
@@ -14,8 +14,8 @@
#include "chrome/browser/extensions/extension_tabs_module_constants.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_error_utils.h"
#include "chrome/common/url_constants.h"
diff --git a/chrome/browser/extensions/extension_input_api.cc b/chrome/browser/extensions/extension_input_api.cc
index 850a344..cc5cb43 100644
--- a/chrome/browser/extensions/extension_input_api.cc
+++ b/chrome/browser/extensions/extension_input_api.cc
@@ -11,7 +11,6 @@
#include "chrome/browser/browser_window.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/views/frame/browser_view.h"
#include "chrome/common/native_web_keyboard_event.h"
diff --git a/chrome/browser/extensions/extension_install_ui.cc b/chrome/browser/extensions/extension_install_ui.cc
index aca3de6..391a54c 100644
--- a/chrome/browser/extensions/extension_install_ui.cc
+++ b/chrome/browser/extensions/extension_install_ui.cc
@@ -10,6 +10,7 @@
#include "app/resource_bundle.h"
#include "base/command_line.h"
#include "base/file_util.h"
+#include "base/i18n/rtl.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
@@ -17,7 +18,7 @@
#include "chrome/browser/browser_window.h"
#include "chrome/browser/extensions/theme_installed_infobar_delegate.h"
#include "chrome/browser/platform_util.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/common/chrome_switches.h"
@@ -33,7 +34,7 @@
#include "grit/theme_resources.h"
#if defined(OS_MACOSX)
-#include "chrome/browser/cocoa/extension_installed_bubble_bridge.h"
+#include "chrome/browser/ui/cocoa/extension_installed_bubble_bridge.h"
#endif
#if defined(TOOLKIT_VIEWS)
@@ -76,22 +77,7 @@ ExtensionInstallUI::ExtensionInstallUI(Profile* profile)
extension_(NULL),
delegate_(NULL),
prompt_type_(NUM_PROMPT_TYPES),
- ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)) {
- // Remember the current theme in case the user presses undo.
- if (profile_) {
- const Extension* previous_theme = profile_->GetTheme();
- if (previous_theme)
- previous_theme_id_ = previous_theme->id();
-#if defined(TOOLKIT_GTK)
- // On Linux, we also need to take the user's system settings into account
- // to undo theme installation.
- previous_use_system_theme_ =
- GtkThemeProvider::GetFrom(profile_)->UseGtkTheme();
-#else
- DCHECK(!previous_use_system_theme_);
-#endif
- }
-}
+ ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)) {}
ExtensionInstallUI::~ExtensionInstallUI() {
}
@@ -106,6 +92,20 @@ void ExtensionInstallUI::ConfirmInstall(Delegate* delegate,
// immediately installed, and then we show an infobar (see OnInstallSuccess)
// to allow the user to revert if they don't like it.
if (extension->is_theme()) {
+ // Remember the current theme in case the user pressed undo.
+ const Extension* previous_theme = profile_->GetTheme();
+ if (previous_theme)
+ previous_theme_id_ = previous_theme->id();
+
+#if defined(TOOLKIT_GTK)
+ // On Linux, we also need to take the user's system settings into account
+ // to undo theme installation.
+ previous_use_system_theme_ =
+ GtkThemeProvider::GetFrom(profile_)->UseGtkTheme();
+#else
+ DCHECK(!previous_use_system_theme_);
+#endif
+
delegate->InstallUIProceed();
return;
}
@@ -296,9 +296,11 @@ void ExtensionInstallUI::ShowGenericExtensionInstalledInfoBar(
if (!tab_contents)
return;
+ string16 extension_name = UTF8ToUTF16(new_extension->name());
+ base::i18n::AdjustStringForLocaleDirection(&extension_name);
string16 msg =
l10n_util::GetStringFUTF16(IDS_EXTENSION_INSTALLED_HEADING,
- UTF8ToUTF16(new_extension->name())) +
+ extension_name) +
UTF8ToUTF16(" ") +
l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALLED_MANAGE_INFO_MAC);
InfoBarDelegate* delegate = new SimpleAlertInfoBarDelegate(
diff --git a/chrome/browser/extensions/extension_install_ui_browsertest.cc b/chrome/browser/extensions/extension_install_ui_browsertest.cc
index 818c414..6866325 100644
--- a/chrome/browser/extensions/extension_install_ui_browsertest.cc
+++ b/chrome/browser/extensions/extension_install_ui_browsertest.cc
@@ -3,9 +3,9 @@
// found in the LICENSE file.
#include "chrome/browser/extensions/extension_browsertest.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/theme_installed_infobar_delegate.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/ui_test_utils.h"
diff --git a/chrome/browser/extensions/extension_management_api.cc b/chrome/browser/extensions/extension_management_api.cc
index bcb12c6..50117c4 100644
--- a/chrome/browser/extensions/extension_management_api.cc
+++ b/chrome/browser/extensions/extension_management_api.cc
@@ -13,9 +13,9 @@
#include "base/string_util.h"
#include "chrome/browser/extensions/extension_event_names.h"
#include "chrome/browser/extensions/extension_event_router.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_updater.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_error_utils.h"
@@ -47,8 +47,8 @@ const char kNoExtensionError[] = "No extension with id *";
const char kNotAnAppError[] = "Extension * is not an App";
}
-ExtensionsService* ExtensionManagementFunction::service() {
- return profile()->GetExtensionsService();
+ExtensionService* ExtensionManagementFunction::service() {
+ return profile()->GetExtensionService();
}
static DictionaryValue* CreateExtensionInfo(const Extension& extension,
@@ -267,9 +267,14 @@ void ExtensionManagementEventRouter::Observe(
Details<UninstalledExtensionInfo>(details).ptr()->extension_id;
args.Append(Value::CreateStringValue(extension_id));
} else {
- const Extension* extension = Details<const Extension>(details).ptr();
+ const Extension* extension = NULL;
+ if (event_name == events::kOnExtensionDisabled) {
+ extension = Details<UnloadedExtensionInfo>(details)->extension;
+ } else {
+ extension = Details<const Extension>(details).ptr();
+ }
CHECK(extension);
- ExtensionsService* service = profile->GetExtensionsService();
+ ExtensionService* service = profile->GetExtensionService();
bool enabled = service->GetExtensionById(extension->id(), false) != NULL;
args.Append(CreateExtensionInfo(*extension, enabled));
}
diff --git a/chrome/browser/extensions/extension_management_api.h b/chrome/browser/extensions/extension_management_api.h
index 864741f..5349955 100644
--- a/chrome/browser/extensions/extension_management_api.h
+++ b/chrome/browser/extensions/extension_management_api.h
@@ -11,11 +11,11 @@
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-class ExtensionsService;
+class ExtensionService;
class ExtensionManagementFunction : public SyncExtensionFunction {
protected:
- ExtensionsService* service();
+ ExtensionService* service();
};
class GetAllExtensionsFunction : public ExtensionManagementFunction {
diff --git a/chrome/browser/extensions/extension_management_apitest.cc b/chrome/browser/extensions/extension_management_apitest.cc
index bdbb057..9883f5d 100644
--- a/chrome/browser/extensions/extension_management_apitest.cc
+++ b/chrome/browser/extensions/extension_management_apitest.cc
@@ -3,8 +3,8 @@
// found in the LICENSE file.
#include "chrome/browser/extensions/extension_apitest.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
class ExtensionManagementApiTest : public ExtensionApiTest {
@@ -19,7 +19,7 @@ class ExtensionManagementApiTest : public ExtensionApiTest {
ASSERT_TRUE(LoadExtension(basedir.AppendASCII("permissions")));
// Load 2 disabled items.
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
ASSERT_TRUE(LoadExtension(basedir.AppendASCII("disabled_extension")));
service->DisableExtension(last_loaded_extension_id_);
ASSERT_TRUE(LoadExtension(basedir.AppendASCII("disabled_app")));
diff --git a/chrome/browser/extensions/extension_management_browsertest.cc b/chrome/browser/extensions/extension_management_browsertest.cc
index 6120c73..a1eb2f6 100644
--- a/chrome/browser/extensions/extension_management_browsertest.cc
+++ b/chrome/browser/extensions/extension_management_browsertest.cc
@@ -6,11 +6,12 @@
#include "chrome/browser/extensions/autoupdate_interceptor.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/extensions/extension_host.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_test_message_listener.h"
#include "chrome/browser/extensions/extension_updater.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/prefs/scoped_pref_update.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/pref_names.h"
@@ -56,7 +57,7 @@ class ExtensionManagementTest : public ExtensionBrowserTest {
// to the second version requiring increased permissions. Returns whether
// the operation was completed successfully.
bool InstallAndUpdateIncreasingPermissionsExtension() {
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
size_t size_before = service->extensions()->size();
// Install the initial version, which should happen just fine.
@@ -81,7 +82,7 @@ class ExtensionManagementTest : public ExtensionBrowserTest {
// Tests that installing the same version overwrites.
IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, InstallSameVersion) {
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
const size_t size_before = service->extensions()->size();
ASSERT_TRUE(InstallExtension(
test_data_dir_.AppendASCII("install/install.crx"), 1));
@@ -99,7 +100,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, InstallSameVersion) {
}
IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, InstallOlderVersion) {
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
const size_t size_before = service->extensions()->size();
ASSERT_TRUE(InstallExtension(
test_data_dir_.AppendASCII("install/install.crx"), 1));
@@ -110,7 +111,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, InstallOlderVersion) {
}
IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, InstallThenCancel) {
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
const size_t size_before = service->extensions()->size();
ASSERT_TRUE(InstallExtension(
test_data_dir_.AppendASCII("install/install.crx"), 1));
@@ -137,7 +138,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, Incognito) {
// Tests the process of updating an extension to one that requires higher
// permissions.
IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, UpdatePermissions) {
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
ASSERT_TRUE(InstallAndUpdateIncreasingPermissionsExtension());
const size_t size_before = service->extensions()->size();
@@ -149,7 +150,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, UpdatePermissions) {
// Tests that we can uninstall a disabled extension.
IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, UninstallDisabled) {
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
ASSERT_TRUE(InstallAndUpdateIncreasingPermissionsExtension());
const size_t size_before = service->extensions()->size();
@@ -163,7 +164,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, UninstallDisabled) {
IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, DisableEnable) {
ExtensionProcessManager* manager = browser()->profile()->
GetExtensionProcessManager();
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
const size_t size_before = service->extensions()->size();
// Load an extension, expect the background page to be available.
@@ -206,7 +207,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, AutoUpdate) {
// Install version 1 of the extension.
ExtensionTestMessageListener listener1("v1 installed", false);
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
const size_t size_before = service->extensions()->size();
ASSERT_TRUE(service->disabled_extensions()->empty());
ASSERT_TRUE(InstallExtension(basedir.AppendASCII("v1.crx"), 1));
@@ -252,7 +253,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, AutoUpdate) {
// See http://crbug.com/57378 for flakiness details.
IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, ExternalUrlUpdate) {
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
const char* kExtensionId = "ogjcoiohnmldgjemafoockdghcjciccf";
// We don't want autoupdate blacklist checks.
service->updater()->set_blacklist_checks_enabled(false);
@@ -272,7 +273,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, ExternalUrlUpdate) {
ASSERT_TRUE(service->disabled_extensions()->empty());
// The code that reads external_extensions.json uses this method to inform
- // the ExtensionsService of an extension to download. Using the real code
+ // the ExtensionService of an extension to download. Using the real code
// is race-prone, because instantating the ExtensionService starts a read
// of external_extensions.json before this test function starts.
service->AddPendingExtensionFromExternalUpdateUrl(
@@ -292,31 +293,39 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, ExternalUrlUpdate) {
UninstallExtension(kExtensionId);
- std::set<std::string> killed_ids;
- service->extension_prefs()->GetKilledExtensionIds(&killed_ids);
- EXPECT_TRUE(killed_ids.end() != killed_ids.find(kExtensionId))
+ ExtensionPrefs* extension_prefs = service->extension_prefs();
+ EXPECT_TRUE(extension_prefs->IsExtensionKilled(kExtensionId))
<< "Uninstalling should set kill bit on externaly installed extension.";
+ // Try to install the extension again from an external source. It should fail
+ // because of the killbit.
+ service->AddPendingExtensionFromExternalUpdateUrl(
+ kExtensionId, GURL("http://localhost/autoupdate/manifest"),
+ Extension::EXTERNAL_PREF_DOWNLOAD);
+ const PendingExtensionMap& pending_extensions =
+ service->pending_extensions();
+ EXPECT_TRUE(
+ pending_extensions.find(kExtensionId) == pending_extensions.end())
+ << "External reinstall of a killed extension shouldn't work.";
+ EXPECT_TRUE(extension_prefs->IsExtensionKilled(kExtensionId))
+ << "External reinstall of a killed extension should leave it killed.";
+
// Installing from non-external source.
ASSERT_TRUE(InstallExtension(basedir.AppendASCII("v2.crx"), 1));
- killed_ids.clear();
- service->extension_prefs()->GetKilledExtensionIds(&killed_ids);
- EXPECT_TRUE(killed_ids.end() == killed_ids.find(kExtensionId))
+ EXPECT_FALSE(extension_prefs->IsExtensionKilled(kExtensionId))
<< "Reinstalling should clear the kill bit.";
// Uninstalling from a non-external source should not set the kill bit.
UninstallExtension(kExtensionId);
- killed_ids.clear();
- service->extension_prefs()->GetKilledExtensionIds(&killed_ids);
- EXPECT_TRUE(killed_ids.end() == killed_ids.find(kExtensionId))
+ EXPECT_FALSE(extension_prefs->IsExtensionKilled(kExtensionId))
<< "Uninstalling non-external extension should not set kill bit.";
}
// See http://crbug.com/57378 for flakiness details.
IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, ExternalPolicyRefresh) {
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
const char* kExtensionId = "ogjcoiohnmldgjemafoockdghcjciccf";
// We don't want autoupdate blacklist checks.
service->updater()->set_blacklist_checks_enabled(false);
@@ -335,15 +344,17 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, ExternalPolicyRefresh) {
const size_t size_before = service->extensions()->size();
ASSERT_TRUE(service->disabled_extensions()->empty());
- // Set the policy as a user preference and fire notification observers.
PrefService* prefs = browser()->profile()->GetPrefs();
- ListValue* forcelist =
- prefs->GetMutableList(prefs::kExtensionInstallForceList);
- ASSERT_TRUE(forcelist->empty());
- forcelist->Append(Value::CreateStringValue(
- "ogjcoiohnmldgjemafoockdghcjciccf;"
- "http://localhost/autoupdate/manifest"));
- prefs->pref_notifier()->FireObservers(prefs::kExtensionInstallForceList);
+ {
+ // Set the policy as a user preference and fire notification observers.
+ ScopedPrefUpdate pref_update(prefs, prefs::kExtensionInstallForceList);
+ ListValue* forcelist =
+ prefs->GetMutableList(prefs::kExtensionInstallForceList);
+ ASSERT_TRUE(forcelist->empty());
+ forcelist->Append(Value::CreateStringValue(
+ "ogjcoiohnmldgjemafoockdghcjciccf;"
+ "http://localhost/autoupdate/manifest"));
+ }
// Check if the extension got installed.
ASSERT_TRUE(WaitForExtensionInstall());
@@ -356,5 +367,4 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, ExternalPolicyRefresh) {
// Check that emptying the list doesn't cause any trouble.
prefs->ClearPref(prefs::kExtensionInstallForceList);
- prefs->pref_notifier()->FireObservers(prefs::kExtensionInstallForceList);
}
diff --git a/chrome/browser/extensions/extension_menu_manager.cc b/chrome/browser/extensions/extension_menu_manager.cc
index eae74f6..0d3c891 100644
--- a/chrome/browser/extensions/extension_menu_manager.cc
+++ b/chrome/browser/extensions/extension_menu_manager.cc
@@ -15,8 +15,9 @@
#include "base/json/json_writer.h"
#include "chrome/browser/extensions/extension_event_router.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/extension.h"
+#include "chrome/common/notification_service.h"
#include "gfx/favicon_size.h"
#include "webkit/glue/context_menu.h"
@@ -73,10 +74,8 @@ string16 ExtensionMenuItem::TitleWithReplacement(
// put "%s" in titles that won't get substituted.
ReplaceSubstringsAfterOffset(&result, 0, ASCIIToUTF16("%s"), selection);
- if (result.length() > max_length) {
- result = WideToUTF16(l10n_util::TruncateString(UTF16ToWideHack(result),
- max_length));
- }
+ if (result.length() > max_length)
+ result = l10n_util::TruncateString(result, max_length);
return result;
}
@@ -412,8 +411,7 @@ void ExtensionMenuManager::ExecuteCommand(
AddURLProperty(properties, "frameUrl", params.frame_url);
if (params.selection_text.length() > 0)
- properties->SetString("selectionText",
- WideToUTF16Hack(params.selection_text));
+ properties->SetString("selectionText", params.selection_text);
properties->SetBoolean("editable", params.is_editable);
@@ -455,7 +453,8 @@ void ExtensionMenuManager::Observe(NotificationType type,
NOTREACHED();
return;
}
- const Extension* extension = Details<const Extension>(details).ptr();
+ const Extension* extension =
+ Details<UnloadedExtensionInfo>(details)->extension;
if (ContainsKey(context_items_, extension->id())) {
RemoveAllContextItems(extension->id());
}
diff --git a/chrome/browser/extensions/extension_menu_manager_unittest.cc b/chrome/browser/extensions/extension_menu_manager_unittest.cc
index cbd9a52..ca844cc 100644
--- a/chrome/browser/extensions/extension_menu_manager_unittest.cc
+++ b/chrome/browser/extensions/extension_menu_manager_unittest.cc
@@ -8,6 +8,7 @@
#include "base/path_service.h"
#include "base/scoped_temp_dir.h"
#include "base/scoped_vector.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/extensions/extension_event_router.h"
@@ -321,9 +322,10 @@ TEST_F(ExtensionMenuManagerTest, ExtensionUnloadRemovesMenuItems) {
// Notify that the extension was unloaded, and make sure the right item is
// gone.
+ UnloadedExtensionInfo details(extension1, UnloadedExtensionInfo::DISABLE);
notifier->Notify(NotificationType::EXTENSION_UNLOADED,
Source<Profile>(NULL),
- Details<const Extension>(extension1));
+ Details<UnloadedExtensionInfo>(&details));
ASSERT_EQ(NULL, manager_.MenuItems(extension1->id()));
ASSERT_EQ(1u, manager_.MenuItems(extension2->id())->size());
ASSERT_TRUE(manager_.GetItemById(id1) == NULL);
@@ -419,7 +421,7 @@ TEST_F(ExtensionMenuManagerTest, ExecuteCommand) {
params.media_type = WebKit::WebContextMenuData::MediaTypeImage;
params.src_url = GURL("http://foo.bar/image.png");
params.page_url = GURL("http://foo.bar");
- params.selection_text = L"Hello World";
+ params.selection_text = ASCIIToUTF16("Hello World");
params.is_editable = false;
Extension* extension = AddExtension("test");
@@ -471,8 +473,9 @@ TEST_F(ExtensionMenuManagerTest, ExecuteCommand) {
ASSERT_TRUE(info->GetString("pageUrl", &tmp));
ASSERT_EQ(params.page_url.spec(), tmp);
- ASSERT_TRUE(info->GetString("selectionText", &tmp));
- ASSERT_EQ(WideToUTF8(params.selection_text), tmp);
+ string16 tmp16;
+ ASSERT_TRUE(info->GetString("selectionText", &tmp16));
+ ASSERT_EQ(params.selection_text, tmp16);
bool bool_tmp = true;
ASSERT_TRUE(info->GetBoolean("editable", &bool_tmp));
diff --git a/chrome/browser/extensions/extension_message_service.cc b/chrome/browser/extensions/extension_message_service.cc
index 67c6e71..c72c9d8 100644
--- a/chrome/browser/extensions/extension_message_service.cc
+++ b/chrome/browser/extensions/extension_message_service.cc
@@ -11,12 +11,12 @@
#include "chrome/browser/child_process_security_policy.h"
#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_util.h"
-#include "chrome/browser/tab_contents_wrapper.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/render_messages.h"
diff --git a/chrome/browser/extensions/extension_message_service.h b/chrome/browser/extensions/extension_message_service.h
index 9135a1c..30c771d 100644
--- a/chrome/browser/extensions/extension_message_service.h
+++ b/chrome/browser/extensions/extension_message_service.h
@@ -134,9 +134,9 @@ class ExtensionMessageService
bool notify_other_port);
// NotificationObserver interface.
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
// An IPC sender that might be in our list of channels has closed.
void OnSenderClosed(IPC::Message::Sender* sender);
diff --git a/chrome/browser/extensions/extension_messages_apitest.cc b/chrome/browser/extensions/extension_messages_apitest.cc
index 760a627..24291a5 100644
--- a/chrome/browser/extensions/extension_messages_apitest.cc
+++ b/chrome/browser/extensions/extension_messages_apitest.cc
@@ -4,8 +4,9 @@
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_event_router.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_service.h"
#include "googleurl/src/gurl.h"
namespace {
diff --git a/chrome/browser/extensions/extension_metrics_apitest.cc b/chrome/browser/extensions/extension_metrics_apitest.cc
index c9464d2..81875b6 100644
--- a/chrome/browser/extensions/extension_metrics_apitest.cc
+++ b/chrome/browser/extensions/extension_metrics_apitest.cc
@@ -5,11 +5,11 @@
#include <map>
#include "base/metrics/histogram.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_service.h"
namespace {
diff --git a/chrome/browser/extensions/extension_module.cc b/chrome/browser/extensions/extension_module.cc
index 84c3789..1ef27a9 100644
--- a/chrome/browser/extensions/extension_module.cc
+++ b/chrome/browser/extensions/extension_module.cc
@@ -7,11 +7,11 @@
#include <string>
#include "chrome/browser/extensions/extension_prefs.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
ExtensionPrefs* SetUpdateUrlDataFunction::extension_prefs() {
- return profile()->GetExtensionsService()->extension_prefs();
+ return profile()->GetExtensionService()->extension_prefs();
}
bool SetUpdateUrlDataFunction::RunImpl() {
diff --git a/chrome/browser/extensions/extension_omnibox_api.cc b/chrome/browser/extensions/extension_omnibox_api.cc
index 605374b..4981c98 100644
--- a/chrome/browser/extensions/extension_omnibox_api.cc
+++ b/chrome/browser/extensions/extension_omnibox_api.cc
@@ -5,13 +5,13 @@
#include "chrome/browser/extensions/extension_omnibox_api.h"
#include "base/json/json_writer.h"
-#include "base/singleton.h"
+#include "base/lazy_instance.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/extensions/extension_event_router.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/common/notification_service.h"
@@ -36,8 +36,11 @@ const char kDescriptionStylesType[] = "type";
const char kDescriptionStylesOffset[] = "offset";
const char kDescriptionStylesLength[] = "length";
+static base::LazyInstance<PropertyAccessor<ExtensionOmniboxSuggestion> >
+ g_extension_omnibox_suggestion_property_accessor(base::LINKER_INITIALIZED);
+
PropertyAccessor<ExtensionOmniboxSuggestion>& GetPropertyAccessor() {
- return *Singleton< PropertyAccessor<ExtensionOmniboxSuggestion> >::get();
+ return g_extension_omnibox_suggestion_property_accessor.Get();
}
// Returns the suggestion object set by the extension via the
@@ -45,11 +48,11 @@ PropertyAccessor<ExtensionOmniboxSuggestion>& GetPropertyAccessor() {
const ExtensionOmniboxSuggestion* GetDefaultSuggestionForExtension(
Profile* profile, const std::string& extension_id) {
const Extension* extension =
- profile->GetExtensionsService()->GetExtensionById(extension_id, false);
+ profile->GetExtensionService()->GetExtensionById(extension_id, false);
if (!extension)
return NULL;
return GetPropertyAccessor().GetProperty(
- profile->GetExtensionsService()->GetPropertyBag(extension));
+ profile->GetExtensionService()->GetPropertyBag(extension));
}
}; // namespace
@@ -161,7 +164,7 @@ bool OmniboxSetDefaultSuggestionFunction::RunImpl() {
// Store the suggestion in the extension's runtime data.
GetPropertyAccessor().SetProperty(
- profile_->GetExtensionsService()->GetPropertyBag(GetExtension()),
+ profile_->GetExtensionService()->GetPropertyBag(GetExtension()),
suggestion);
NotificationService::current()->Notify(
diff --git a/chrome/browser/extensions/extension_omnibox_apitest.cc b/chrome/browser/extensions/extension_omnibox_apitest.cc
index 854662d..0eba9be 100644
--- a/chrome/browser/extensions/extension_omnibox_apitest.cc
+++ b/chrome/browser/extensions/extension_omnibox_apitest.cc
@@ -12,11 +12,11 @@
#include "chrome/browser/autocomplete/autocomplete_popup_model.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/extensions/extension_apitest.h"
-#include "chrome/browser/location_bar.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/omnibox/location_bar.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/url_constants.h"
diff --git a/chrome/browser/extensions/extension_override_apitest.cc b/chrome/browser/extensions/extension_override_apitest.cc
index 3f0c801..4fd73f4 100644
--- a/chrome/browser/extensions/extension_override_apitest.cc
+++ b/chrome/browser/extensions/extension_override_apitest.cc
@@ -5,9 +5,9 @@
#include "chrome/browser/browser_list.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_dom_ui.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/url_constants.h"
@@ -115,7 +115,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionOverrideTest, ShouldNotCreateDuplicateEntries) {
for (size_t i = 0; i < 3; ++i) {
ExtensionDOMUI::RegisterChromeURLOverrides(
browser()->profile(),
- browser()->profile()->GetExtensionsService()->extensions()->back()->
+ browser()->profile()->GetExtensionService()->extensions()->back()->
GetChromeURLOverrides());
}
@@ -161,7 +161,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionOverrideTest, OverrideKeyboard) {
// Unload the failing version. We should be back to passing now.
const ExtensionList *extensions =
- browser()->profile()->GetExtensionsService()->extensions();
+ browser()->profile()->GetExtensionService()->extensions();
UnloadExtension((*extensions->rbegin())->id());
{
ResultCatcher catcher;
diff --git a/chrome/browser/extensions/extension_page_actions_module.cc b/chrome/browser/extensions/extension_page_actions_module.cc
index c9dc2a3..0e26d60 100644
--- a/chrome/browser/extensions/extension_page_actions_module.cc
+++ b/chrome/browser/extensions/extension_page_actions_module.cc
@@ -8,12 +8,12 @@
#include "chrome/browser/browser_list.h"
#include "chrome/browser/extensions/extension_page_actions_module_constants.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_action.h"
#include "chrome/common/extensions/extension_error_utils.h"
diff --git a/chrome/browser/extensions/extension_popup_api.cc b/chrome/browser/extensions/extension_popup_api.cc
index 2af847e..25d3657 100644
--- a/chrome/browser/extensions/extension_popup_api.cc
+++ b/chrome/browser/extensions/extension_popup_api.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/extensions/extension_popup_api.h"
+#include <string>
+
#include "base/json/json_writer.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
@@ -11,14 +13,13 @@
#include "chrome/browser/extensions/extension_dom_ui.h"
#include "chrome/browser/extensions/extension_event_router.h"
#include "chrome/browser/extensions/extension_host.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/window_sizer.h"
+#include "chrome/browser/ui/window_sizer.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_service.h"
diff --git a/chrome/browser/extensions/extension_pref_store.cc b/chrome/browser/extensions/extension_pref_store.cc
index 27719ed..b3aba44 100644
--- a/chrome/browser/extensions/extension_pref_store.cc
+++ b/chrome/browser/extensions/extension_pref_store.cc
@@ -4,196 +4,25 @@
#include "chrome/browser/extensions/extension_pref_store.h"
-#include "base/logging.h"
-#include "base/values.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/notification_service.h"
-
-ExtensionPrefStore::ExtensionPrefStore(Profile* profile,
- PrefNotifier::PrefStoreType type)
- : prefs_(new DictionaryValue()),
- profile_(profile),
- type_(type) {
- RegisterObservers();
+ExtensionPrefStore::ExtensionPrefStore()
+ : initialization_complete_(false) {
}
-ExtensionPrefStore::~ExtensionPrefStore() {
- STLDeleteElements(&extension_stack_);
- notification_registrar_.RemoveAll();
+void ExtensionPrefStore::SetExtensionPref(const std::string& key,
+ Value* value) {
+ SetValue(key, value);
}
-void ExtensionPrefStore::InstallExtensionPref(const Extension* extension,
- const char* new_pref_path,
- Value* new_pref_value) {
- ExtensionStack::iterator i;
- for (i = extension_stack_.begin(); i != extension_stack_.end(); ++i) {
- if ((*i)->extension == extension)
- break;
- }
-
- // If this extension is not already in the stack, add it. Otherwise, update
- // or add the value of this preference, but don't change the extension's
- // position in the stack. We store the extension even if this preference
- // isn't registered with our PrefService, so that the ordering of extensions
- // is consistent among all local-state and user ExtensionPrefStores.
- PrefService* pref_service = GetPrefService();
- // The pref_service may be NULL in unit testing.
- bool is_registered_pref = (pref_service == NULL ||
- pref_service->FindPreference(new_pref_path) != NULL);
- PrefValueMap* pref_values;
- if (i == extension_stack_.end()) {
- pref_values = new PrefValueMap();
- if (is_registered_pref)
- (*pref_values)[new_pref_path] = new_pref_value;
-
- ExtensionPrefs* extension_prefs = new ExtensionPrefs(extension,
- pref_values);
- extension_stack_.push_front(extension_prefs);
- } else if (is_registered_pref) {
- pref_values = (*i)->pref_values;
- delete (*pref_values)[new_pref_path];
- (*pref_values)[new_pref_path] = new_pref_value;
- }
-
- // Apply the preference to our local |prefs_| store.
- UpdateOnePref(new_pref_path);
+void ExtensionPrefStore::RemoveExtensionPref(const std::string& key) {
+ RemoveValue(key);
}
-void ExtensionPrefStore::UninstallExtension(const Extension* extension) {
- // Remove this extension from the stack.
- for (ExtensionStack::iterator i = extension_stack_.begin();
- i != extension_stack_.end(); ++i) {
- if ((*i)->extension == extension) {
- scoped_ptr<ExtensionPrefs> to_be_deleted(*i);
- extension_stack_.erase(i);
- UpdatePrefs(to_be_deleted->pref_values);
- return;
- }
- }
+void ExtensionPrefStore::OnInitializationCompleted() {
+ DCHECK(!initialization_complete_);
+ initialization_complete_ = true;
+ NotifyInitializationCompleted();
}
-void ExtensionPrefStore::GetExtensionIDs(std::vector<std::string>* result) {
- for (ExtensionStack::iterator i = extension_stack_.begin();
- i != extension_stack_.end(); ++i) {
- (*result).push_back((*i)->extension->id());
- }
-}
-
-// This could be sped up by keeping track of which extension currently controls
-// a given preference, among other optimizations. But probably fewer than 10
-// installed extensions will be trying to control any preferences, so stick
-// with this simpler algorithm until it causes a problem.
-void ExtensionPrefStore::UpdateOnePref(const char* path) {
- PrefService* pref_service = GetPrefService();
-
- // There are at least two PrefServices, one for local state and one for
- // user prefs. (See browser_main.cc.) Different preferences are registered
- // in each; if this one doesn't have the desired pref registered, we ignore
- // it and let the other one handle it.
- // The pref_service may be NULL in unit testing.
- if (pref_service && !pref_service->FindPreference(path))
- return;
-
- // Save the old value before removing it from the local cache.
- Value* my_old_value_ptr = NULL;
- prefs_->Get(path, &my_old_value_ptr);
- scoped_ptr<Value> my_old_value;
- if (my_old_value_ptr)
- my_old_value.reset(my_old_value_ptr->DeepCopy());
-
- // DictionaryValue::Set complains if a key is overwritten with the same
- // value, so remove it first.
- prefs_->Remove(path, NULL);
-
- // Find the first extension that wants to set this pref and use its value.
- Value* my_new_value = NULL;
- for (ExtensionStack::iterator ext_iter = extension_stack_.begin();
- ext_iter != extension_stack_.end(); ++ext_iter) {
- PrefValueMap::iterator value_iter = (*ext_iter)->pref_values->find(path);
- if (value_iter != (*ext_iter)->pref_values->end()) {
- prefs_->Set(path, (*value_iter).second->DeepCopy());
- my_new_value = (*value_iter).second;
- break;
- }
- }
-
- if (pref_service) {
- bool value_changed = true;
- if (!my_old_value.get() && !my_new_value) {
- value_changed = false;
- } else if (my_old_value.get() &&
- my_new_value &&
- my_old_value->Equals(my_new_value)) {
- value_changed = false;
- }
-
- if (value_changed)
- pref_service->pref_notifier()->OnPreferenceSet(path, type_);
- }
-}
-
-void ExtensionPrefStore::UpdatePrefs(const PrefValueMap* pref_values) {
- if (!pref_values)
- return;
-
- for (PrefValueMap::const_iterator i = pref_values->begin();
- i != pref_values->end(); ++i) {
- UpdateOnePref(i->first);
- }
-}
-
-PrefService* ExtensionPrefStore::GetPrefService() {
- if (profile_)
- return profile_->GetPrefs();
- return g_browser_process->local_state();
-}
-
-void ExtensionPrefStore::RegisterObservers() {
- notification_registrar_.Add(this,
- NotificationType::EXTENSION_PREF_CHANGED,
- NotificationService::AllSources());
-
- notification_registrar_.Add(this,
- NotificationType::EXTENSION_UNLOADED,
- NotificationService::AllSources());
-}
-
-void ExtensionPrefStore::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- switch (type.value) {
- case NotificationType::EXTENSION_PREF_CHANGED: {
- Profile* extension_profile = Source<Profile>(source).ptr();
- // The ExtensionPrefStore for the local state watches all profiles.
- if (!profile_ || profile_ == extension_profile) {
- ExtensionPrefStore::ExtensionPrefDetails* data =
- Details<ExtensionPrefStore::ExtensionPrefDetails>(details).ptr();
- InstallExtensionPref(data->first, data->second.first,
- data->second.second);
- }
- break;
- }
- case NotificationType::EXTENSION_UNLOADED: {
- Profile* extension_profile = Source<Profile>(source).ptr();
- const Extension* extension = Details<const Extension>(details).ptr();
- // The ExtensionPrefStore for the local state watches all profiles.
- if (profile_ == NULL || profile_ == extension_profile)
- UninstallExtension(extension);
- break;
- }
- default: {
- NOTREACHED();
- }
- }
-}
-
-ExtensionPrefStore::ExtensionPrefs::ExtensionPrefs(const Extension* extension,
- PrefValueMap* values) : extension(extension), pref_values(values) {}
-
-ExtensionPrefStore::ExtensionPrefs::~ExtensionPrefs() {
- STLDeleteValues(pref_values);
- delete pref_values;
+bool ExtensionPrefStore::IsInitializationComplete() const {
+ return initialization_complete_;
}
diff --git a/chrome/browser/extensions/extension_pref_store.h b/chrome/browser/extensions/extension_pref_store.h
index f176758..f2db809 100644
--- a/chrome/browser/extensions/extension_pref_store.h
+++ b/chrome/browser/extensions/extension_pref_store.h
@@ -6,119 +6,31 @@
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_PREF_STORE_H_
#pragma once
-#include <list>
-#include <map>
-#include <string>
-#include <utility>
-#include <vector>
+#include "chrome/browser/prefs/value_map_pref_store.h"
-#include "base/basictypes.h"
-#include "base/scoped_ptr.h"
-#include "base/stl_util-inl.h"
-#include "chrome/browser/prefs/pref_notifier.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
-#include "chrome/common/pref_store.h"
-
-class DictionaryValue;
-class Extension;
-class PrefService;
-class Profile;
-class Value;
-
-// This PrefStore keeps track of preferences set by extensions: for example,
-// proxy settings. A stack of relevant extensions is stored in order of
-// their addition to this PrefStore. For each preference, the last-added
-// enabled extension that tries to set it overrules any others.
-class ExtensionPrefStore : public PrefStore,
- public NotificationObserver {
+// A PrefStore implementation that holds preferences set by extensions.
+class ExtensionPrefStore : public ValueMapPrefStore {
public:
- // Maps preference paths to their values.
- typedef std::map<const char*, Value*> PrefValueMap;
-
- // The type passed as Details for an EXTENSION_PREF_CHANGED notification.
- // The nested pairs are <extension, <pref_path, pref_value> >. This is here,
- // rather than in (say) notification_type.h, to keep the dependency on
- // std::pair out of the many places that include notification_type.h.
- typedef std::pair<const Extension*, std::pair<const char*, Value*> >
- ExtensionPrefDetails;
-
- ExtensionPrefStore(Profile* profile, PrefNotifier::PrefStoreType type);
- virtual ~ExtensionPrefStore();
-
- // Begins tracking the preference and value an extension wishes to set. This
- // must be called each time an extension API tries to set a preference.
- // The ExtensionPrefStore will take ownership of the |pref_value|.
- virtual void InstallExtensionPref(const Extension* extension,
- const char* pref_path,
- Value* pref_value);
+ ExtensionPrefStore();
+ virtual ~ExtensionPrefStore() {}
- // Removes an extension and all its preference settings from this PrefStore.
- // This must be called when an extension is uninstalled or disabled.
- virtual void UninstallExtension(const Extension* extension);
+ // Set an extension preference |value| for |key|. Takes ownership of |value|.
+ void SetExtensionPref(const std::string& key, Value* value);
- // PrefStore methods:
- virtual DictionaryValue* prefs() const { return prefs_.get(); }
+ // Remove the extension preference value for |key|.
+ void RemoveExtensionPref(const std::string& key);
- virtual PrefReadError ReadPrefs() { return PREF_READ_ERROR_NONE; }
-
- protected:
- // Returns a vector of the extension IDs in the extension_stack_.
- // This should only be accessed by subclasses for unit-testing.
- void GetExtensionIDs(std::vector<std::string>* result);
-
- // Returns the applicable pref service from the profile (if we have one) or
- // the browser's local state. This should only be accessed or overridden by
- // subclasses for unit-testing.
- virtual PrefService* GetPrefService();
+ // Tell the store it's now fully initialized.
+ void OnInitializationCompleted();
private:
- // Associates an extension with the prefs it sets. Owns the pref values.
- struct ExtensionPrefs {
- ExtensionPrefs(const Extension* extension, PrefValueMap* values);
- ~ExtensionPrefs();
-
- const Extension* extension;
- PrefValueMap* pref_values;
- };
-
- // A pseudo-stack of extensions and their preferences. Extensions are always
- // added to the head, but may be removed from the middle.
- typedef std::list<ExtensionPrefs*> ExtensionStack;
+ // PrefStore overrides:
+ virtual bool IsInitializationComplete() const;
- // Applies the highest-priority extension's setting for the given preference
- // path to the |prefs_| store, or clears the setting there if no extensions
- // wish to control it.
- void UpdateOnePref(const char* path);
-
- // Updates each preference in the key set of the |pref_values| map.
- void UpdatePrefs(const PrefValueMap* pref_values);
-
- // Registers this as an observer for relevant notifications.
- void RegisterObservers();
-
- // Responds to observed notifications.
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- // A cache of the highest-priority values for each preference that any
- // extension is controlling, for quick read access. Owns the stored values.
- scoped_ptr<DictionaryValue> prefs_;
-
- ExtensionStack extension_stack_;
-
- NotificationRegistrar notification_registrar_;
-
- // Weak reference to the profile whose extensions we're interested in. May be
- // NULL (for the local-state preferences), in which case we watch all
- // extensions.
- Profile* profile_;
-
- // My PrefStore type, assigned by the PrefValueStore.
- PrefNotifier::PrefStoreType type_;
+ bool initialization_complete_;
DISALLOW_COPY_AND_ASSIGN(ExtensionPrefStore);
};
+
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_PREF_STORE_H_
diff --git a/chrome/browser/extensions/extension_pref_store_unittest.cc b/chrome/browser/extensions/extension_pref_store_unittest.cc
deleted file mode 100644
index 580dd3e..0000000
--- a/chrome/browser/extensions/extension_pref_store_unittest.cc
+++ /dev/null
@@ -1,369 +0,0 @@
-// 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.
-
-#include <string>
-#include <vector>
-
-#include "base/scoped_ptr.h"
-#include "base/scoped_temp_dir.h"
-#include "base/values.h"
-#include "chrome/browser/extensions/extension_pref_store.h"
-#include "chrome/browser/prefs/default_pref_store.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/prefs/pref_value_store.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/test/testing_pref_service.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace keys = extension_manifest_keys;
-
-namespace {
-
-class TestExtensionPrefStore : public ExtensionPrefStore {
- public:
- TestExtensionPrefStore()
- : ExtensionPrefStore(NULL, PrefNotifier::EXTENSION_STORE),
- ext1(NULL),
- ext2(NULL),
- ext3(NULL),
- pref_service_(NULL) {
- // Can't use ASSERT_TRUE here because a constructor can't return a value.
- if (!temp_dir_.CreateUniqueTempDir()) {
- ADD_FAILURE() << "Failed to create temp dir";
- return;
- }
- DictionaryValue simple_dict;
- std::string error;
-
- simple_dict.SetString(keys::kVersion, "1.0.0.0");
- simple_dict.SetString(keys::kName, "unused");
-
- ext1_scoped_ = Extension::Create(
- temp_dir_.path().AppendASCII("ext1"), Extension::INVALID,
- simple_dict, false, &error);
- ext2_scoped_ = Extension::Create(
- temp_dir_.path().AppendASCII("ext2"), Extension::INVALID,
- simple_dict, false, &error);
- ext3_scoped_ = Extension::Create(
- temp_dir_.path().AppendASCII("ext3"), Extension::INVALID,
- simple_dict, false, &error);
-
- ext1 = ext1_scoped_.get();
- ext2 = ext2_scoped_.get();
- ext3 = ext3_scoped_.get();
- }
-
- typedef std::vector<std::string> ExtensionIDs;
- void GetExtensionIDList(ExtensionIDs* result) {
- GetExtensionIDs(result);
- }
-
- void SetPrefService(PrefService* pref_service) {
- pref_service_ = pref_service;
- }
-
- // Overridden from ExtensionPrefStore.
- virtual PrefService* GetPrefService() {
- return pref_service_;
- }
-
- // Weak references, for convenience.
- Extension* ext1;
- Extension* ext2;
- Extension* ext3;
-
- private:
- ScopedTempDir temp_dir_;
-
- scoped_refptr<Extension> ext1_scoped_;
- scoped_refptr<Extension> ext2_scoped_;
- scoped_refptr<Extension> ext3_scoped_;
-
- // Weak reference.
- PrefService* pref_service_;
-};
-
-// Mock PrefNotifier that allows the notifications to be tracked.
-class MockPrefNotifier : public PrefNotifier {
- public:
- MockPrefNotifier(PrefService* service, PrefValueStore* value_store)
- : PrefNotifier(service, value_store) {}
-
- virtual ~MockPrefNotifier() {}
-
- MOCK_METHOD1(FireObservers, void(const char* path));
-};
-
-// Mock PrefService that allows the PrefNotifier to be injected.
-class MockPrefService : public PrefService {
- public:
- explicit MockPrefService(PrefValueStore* pref_value_store)
- : PrefService(pref_value_store) {
- }
-
- void SetPrefNotifier(MockPrefNotifier* notifier) {
- pref_notifier_.reset(notifier);
- }
-};
-
-// Use constants to avoid confusing std::map with hard-coded strings.
-const char kPref1[] = "path1.subpath";
-const char kPref2[] = "path2";
-const char kPref3[] = "path3";
-const char kPref4[] = "path4";
-
-} // namespace
-
-TEST(ExtensionPrefStoreTest, InstallOneExtension) {
- TestExtensionPrefStore eps;
- ASSERT_TRUE(eps.ext1 != NULL);
- eps.InstallExtensionPref(eps.ext1, kPref1, Value::CreateStringValue("val1"));
-
- TestExtensionPrefStore::ExtensionIDs ids;
- eps.GetExtensionIDList(&ids);
- EXPECT_EQ(1u, ids.size());
- EXPECT_EQ(eps.ext1->id(), ids[0]);
-
- DictionaryValue* prefs = eps.prefs();
- ASSERT_EQ(1u, prefs->size());
- std::string actual;
- ASSERT_TRUE(prefs->GetString(kPref1, &actual));
- EXPECT_EQ("val1", actual);
-}
-
-// Make sure the last-installed extension wins.
-TEST(ExtensionPrefStoreTest, InstallMultipleExtensions) {
- TestExtensionPrefStore eps;
- ASSERT_TRUE(eps.ext1 != NULL);
- eps.InstallExtensionPref(eps.ext1, kPref1, Value::CreateStringValue("val1"));
- eps.InstallExtensionPref(eps.ext2, kPref1, Value::CreateStringValue("val2"));
- eps.InstallExtensionPref(eps.ext3, kPref1, Value::CreateStringValue("val3"));
-
- TestExtensionPrefStore::ExtensionIDs ids;
- eps.GetExtensionIDList(&ids);
- EXPECT_EQ(3u, ids.size());
- EXPECT_EQ(eps.ext3->id(), ids[0]);
- EXPECT_EQ(eps.ext2->id(), ids[1]);
- EXPECT_EQ(eps.ext1->id(), ids[2]);
-
- DictionaryValue* prefs = eps.prefs();
- ASSERT_EQ(1u, prefs->size());
- std::string actual;
- ASSERT_TRUE(prefs->GetString(kPref1, &actual));
- EXPECT_EQ("val3", actual);
-}
-
-// Make sure the last-installed extension wins for each preference.
-TEST(ExtensionPrefStoreTest, InstallOverwrittenExtensions) {
- TestExtensionPrefStore eps;
- ASSERT_TRUE(eps.ext1 != NULL);
- eps.InstallExtensionPref(eps.ext1, kPref1, Value::CreateStringValue("val1"));
- eps.InstallExtensionPref(eps.ext2, kPref1, Value::CreateStringValue("val2"));
- eps.InstallExtensionPref(eps.ext3, kPref1, Value::CreateStringValue("val3"));
-
- eps.InstallExtensionPref(eps.ext1, kPref2, Value::CreateStringValue("val4"));
- eps.InstallExtensionPref(eps.ext2, kPref2, Value::CreateStringValue("val5"));
-
- eps.InstallExtensionPref(eps.ext1, kPref1, Value::CreateStringValue("val6"));
- eps.InstallExtensionPref(eps.ext1, kPref2, Value::CreateStringValue("val7"));
- eps.InstallExtensionPref(eps.ext1, kPref3, Value::CreateStringValue("val8"));
-
- TestExtensionPrefStore::ExtensionIDs ids;
- eps.GetExtensionIDList(&ids);
- EXPECT_EQ(3u, ids.size());
- EXPECT_EQ(eps.ext3->id(), ids[0]);
- EXPECT_EQ(eps.ext2->id(), ids[1]);
- EXPECT_EQ(eps.ext1->id(), ids[2]);
-
- DictionaryValue* prefs = eps.prefs();
- ASSERT_EQ(3u, prefs->size());
- std::string actual;
- EXPECT_TRUE(prefs->GetString(kPref1, &actual));
- EXPECT_EQ("val3", actual);
- EXPECT_TRUE(prefs->GetString(kPref2, &actual));
- EXPECT_EQ("val5", actual);
- EXPECT_TRUE(prefs->GetString(kPref3, &actual));
- EXPECT_EQ("val8", actual);
-}
-
-// Make sure the last-installed extension wins even if other extensions set
-// the same or different preferences later.
-TEST(ExtensionPrefStoreTest, InstallInterleavedExtensions) {
- TestExtensionPrefStore eps;
- ASSERT_TRUE(eps.ext1 != NULL);
- eps.InstallExtensionPref(eps.ext1, kPref1, Value::CreateStringValue("val1"));
- eps.InstallExtensionPref(eps.ext2, kPref2, Value::CreateStringValue("val2"));
- eps.InstallExtensionPref(eps.ext3, kPref3, Value::CreateStringValue("val3"));
-
- eps.InstallExtensionPref(eps.ext3, kPref3, Value::CreateStringValue("val4"));
- eps.InstallExtensionPref(eps.ext2, kPref3, Value::CreateStringValue("val5"));
- eps.InstallExtensionPref(eps.ext1, kPref3, Value::CreateStringValue("val6"));
-
- eps.InstallExtensionPref(eps.ext3, kPref1, Value::CreateStringValue("val7"));
-
- TestExtensionPrefStore::ExtensionIDs ids;
- eps.GetExtensionIDList(&ids);
- EXPECT_EQ(3u, ids.size());
- EXPECT_EQ(eps.ext3->id(), ids[0]);
- EXPECT_EQ(eps.ext2->id(), ids[1]);
- EXPECT_EQ(eps.ext1->id(), ids[2]);
-
- DictionaryValue* prefs = eps.prefs();
- ASSERT_EQ(3u, prefs->size());
- std::string actual;
- EXPECT_TRUE(prefs->GetString(kPref1, &actual));
- EXPECT_EQ("val7", actual);
- EXPECT_TRUE(prefs->GetString(kPref2, &actual));
- EXPECT_EQ("val2", actual);
- EXPECT_TRUE(prefs->GetString(kPref3, &actual));
- EXPECT_EQ("val4", actual);
-}
-
-TEST(ExtensionPrefStoreTest, UninstallOnlyExtension) {
- TestExtensionPrefStore eps;
- ASSERT_TRUE(eps.ext1 != NULL);
- eps.InstallExtensionPref(eps.ext1, kPref1, Value::CreateStringValue("val1"));
- eps.InstallExtensionPref(eps.ext1, kPref2, Value::CreateStringValue("val2"));
-
- // No need to check the state here; the Install* tests cover that.
- eps.UninstallExtension(eps.ext1);
-
- TestExtensionPrefStore::ExtensionIDs ids;
- eps.GetExtensionIDList(&ids);
- EXPECT_EQ(0u, ids.size());
-
- DictionaryValue* prefs = eps.prefs();
- std::string actual;
- // "path1.name" has been removed, but an empty "path1" dictionary is still
- // present.
- ASSERT_EQ(1u, prefs->size());
- EXPECT_FALSE(prefs->GetString(kPref1, &actual));
- EXPECT_FALSE(prefs->GetString(kPref2, &actual));
-}
-
-// Tests uninstalling an extension that wasn't winning for any preferences.
-TEST(ExtensionPrefStoreTest, UninstallIrrelevantExtension) {
- TestExtensionPrefStore eps;
- ASSERT_TRUE(eps.ext1 != NULL);
- eps.InstallExtensionPref(eps.ext1, kPref1, Value::CreateStringValue("val1"));
- eps.InstallExtensionPref(eps.ext2, kPref1, Value::CreateStringValue("val2"));
-
- eps.InstallExtensionPref(eps.ext1, kPref2, Value::CreateStringValue("val3"));
- eps.InstallExtensionPref(eps.ext2, kPref2, Value::CreateStringValue("val4"));
-
- eps.UninstallExtension(eps.ext1);
-
- TestExtensionPrefStore::ExtensionIDs ids;
- eps.GetExtensionIDList(&ids);
- EXPECT_EQ(1u, ids.size());
- EXPECT_EQ(eps.ext2->id(), ids[0]);
-
- DictionaryValue* prefs = eps.prefs();
- ASSERT_EQ(2u, prefs->size());
- std::string actual;
- EXPECT_TRUE(prefs->GetString(kPref1, &actual));
- EXPECT_EQ("val2", actual);
- EXPECT_TRUE(prefs->GetString(kPref2, &actual));
- EXPECT_EQ("val4", actual);
-}
-
-// Tests uninstalling an extension that was winning for all preferences.
-TEST(ExtensionPrefStoreTest, UninstallExtensionFromTop) {
- TestExtensionPrefStore eps;
- ASSERT_TRUE(eps.ext1 != NULL);
- eps.InstallExtensionPref(eps.ext1, kPref1, Value::CreateStringValue("val1"));
- eps.InstallExtensionPref(eps.ext2, kPref1, Value::CreateStringValue("val2"));
- eps.InstallExtensionPref(eps.ext3, kPref1, Value::CreateStringValue("val3"));
-
- eps.InstallExtensionPref(eps.ext1, kPref2, Value::CreateStringValue("val4"));
- eps.InstallExtensionPref(eps.ext3, kPref2, Value::CreateStringValue("val5"));
-
- eps.UninstallExtension(eps.ext3);
-
- TestExtensionPrefStore::ExtensionIDs ids;
- eps.GetExtensionIDList(&ids);
- EXPECT_EQ(2u, ids.size());
- EXPECT_EQ(eps.ext2->id(), ids[0]);
- EXPECT_EQ(eps.ext1->id(), ids[1]);
-
- DictionaryValue* prefs = eps.prefs();
- ASSERT_EQ(2u, prefs->size());
- std::string actual;
- EXPECT_TRUE(prefs->GetString(kPref1, &actual));
- EXPECT_EQ("val2", actual);
- EXPECT_TRUE(prefs->GetString(kPref2, &actual));
- EXPECT_EQ("val4", actual);
-}
-
-// Tests uninstalling an extension that was winning for only some preferences.
-TEST(ExtensionPrefStoreTest, UninstallExtensionFromMiddle) {
- TestExtensionPrefStore eps;
- ASSERT_TRUE(eps.ext1 != NULL);
- eps.InstallExtensionPref(eps.ext1, kPref1, Value::CreateStringValue("val1"));
- eps.InstallExtensionPref(eps.ext2, kPref1, Value::CreateStringValue("val2"));
- eps.InstallExtensionPref(eps.ext3, kPref1, Value::CreateStringValue("val3"));
-
- eps.InstallExtensionPref(eps.ext1, kPref2, Value::CreateStringValue("val4"));
- eps.InstallExtensionPref(eps.ext2, kPref2, Value::CreateStringValue("val5"));
-
- eps.InstallExtensionPref(eps.ext1, kPref3, Value::CreateStringValue("val6"));
-
- eps.InstallExtensionPref(eps.ext2, kPref4, Value::CreateStringValue("val7"));
-
- eps.UninstallExtension(eps.ext2);
-
- TestExtensionPrefStore::ExtensionIDs ids;
- eps.GetExtensionIDList(&ids);
- EXPECT_EQ(2u, ids.size());
- EXPECT_EQ(eps.ext3->id(), ids[0]);
- EXPECT_EQ(eps.ext1->id(), ids[1]);
-
- DictionaryValue* prefs = eps.prefs();
- ASSERT_EQ(3u, prefs->size());
- std::string actual;
- EXPECT_TRUE(prefs->GetString(kPref1, &actual));
- EXPECT_EQ("val3", actual);
- EXPECT_TRUE(prefs->GetString(kPref2, &actual));
- EXPECT_EQ("val4", actual);
- EXPECT_TRUE(prefs->GetString(kPref3, &actual));
- EXPECT_EQ("val6", actual);
- EXPECT_FALSE(prefs->GetString(kPref4, &actual));
-}
-
-TEST(ExtensionPrefStoreTest, NotifyWhenNeeded) {
- using testing::Mock;
-
- TestExtensionPrefStore* eps = new TestExtensionPrefStore;
- DefaultPrefStore* dps = new DefaultPrefStore;
- ASSERT_TRUE(eps->ext1 != NULL);
-
- // The PrefValueStore takes ownership of the PrefStores; in this case, that's
- // only an ExtensionPrefStore. Likewise, the PrefService takes ownership of
- // the PrefValueStore and PrefNotifier.
- PrefValueStore* value_store = new TestingPrefService::TestingPrefValueStore(
- NULL, NULL, eps, NULL, NULL, NULL, dps);
- scoped_ptr<MockPrefService> pref_service(new MockPrefService(value_store));
- MockPrefNotifier* pref_notifier = new MockPrefNotifier(pref_service.get(),
- value_store);
- pref_service->SetPrefNotifier(pref_notifier);
-
- eps->SetPrefService(pref_service.get());
- pref_service->RegisterStringPref(kPref1, std::string());
-
- EXPECT_CALL(*pref_notifier, FireObservers(kPref1));
- eps->InstallExtensionPref(eps->ext1, kPref1,
- Value::CreateStringValue("https://www.chromium.org"));
- Mock::VerifyAndClearExpectations(pref_notifier);
-
- EXPECT_CALL(*pref_notifier, FireObservers(kPref1)).Times(0);
- eps->InstallExtensionPref(eps->ext1, kPref1,
- Value::CreateStringValue("https://www.chromium.org"));
- Mock::VerifyAndClearExpectations(pref_notifier);
-
- EXPECT_CALL(*pref_notifier, FireObservers(kPref1)).Times(2);
- eps->InstallExtensionPref(eps->ext1, kPref1,
- Value::CreateStringValue("chrome://newtab"));
- eps->UninstallExtension(eps->ext1);
-}
diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc
index 0cc2ec5..1f128ab 100644
--- a/chrome/browser/extensions/extension_prefs.cc
+++ b/chrome/browser/extensions/extension_prefs.cc
@@ -7,6 +7,8 @@
#include "base/string_util.h"
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
+#include "chrome/browser/extensions/extension_pref_store.h"
+#include "chrome/browser/prefs/pref_notifier.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/url_pattern.h"
#include "chrome/common/notification_service.h"
@@ -91,6 +93,12 @@ const char kPrefGrantedPermissionsAPI[] = "granted_permissions.api";
const char kPrefGrantedPermissionsHost[] = "granted_permissions.host";
const char kPrefGrantedPermissionsAll[] = "granted_permissions.full";
+// A preference that indicates when an extension was installed.
+const char kPrefInstallTime[] = "install_time";
+
+// A preference that contains any extension-controlled preferences.
+const char kPrefPreferences[] = "preferences";
+
} // namespace
////////////////////////////////////////////////////////////////////////////////
@@ -133,14 +141,19 @@ static void ExtentToStringSet(const ExtensionExtent& host_extent,
} // namespace
-ExtensionPrefs::ExtensionPrefs(PrefService* prefs, const FilePath& root_dir)
+ExtensionPrefs::ExtensionPrefs(PrefService* prefs,
+ const FilePath& root_dir,
+ ExtensionPrefStore* pref_store)
: prefs_(prefs),
- install_directory_(root_dir) {
+ install_directory_(root_dir),
+ pref_store_(pref_store) {
// TODO(asargent) - Remove this in a couple of months. (See comment above
// CleanupBadExtensionKeys).
- CleanupBadExtensionKeys(prefs);
+ CleanupBadExtensionKeys(prefs_);
MakePathsRelative();
+
+ InitPrefStore();
}
ExtensionPrefs::~ExtensionPrefs() {}
@@ -325,7 +338,9 @@ void ExtensionPrefs::AddToExtensionPrefStringSet(
void ExtensionPrefs::SavePrefsAndNotify() {
prefs_->ScheduleSavePersistentPrefs();
- prefs_->pref_notifier()->OnUserPreferenceSet(kExtensionsPref);
+ // TODO(mnissler, danno): Don't use pref_notifier() here, but tell the
+ // PrefService by some other means that we changed the pref value.
+ prefs_->pref_notifier()->OnPreferenceChanged(kExtensionsPref);
}
bool ExtensionPrefs::IsBlacklistBitSet(DictionaryValue* ext) {
@@ -622,36 +637,17 @@ void ExtensionPrefs::SetLaunchType(const std::string& extension_id,
SavePrefsAndNotify();
}
-void ExtensionPrefs::GetKilledExtensionIds(std::set<std::string>* killed_ids) {
- const DictionaryValue* dict = prefs_->GetDictionary(kExtensionsPref);
- if (!dict || dict->empty())
- return;
-
- for (DictionaryValue::key_iterator i = dict->begin_keys();
- i != dict->end_keys(); ++i) {
- const std::string& key_name(*i);
- if (!Extension::IdIsValid(key_name)) {
- LOG(WARNING) << "Invalid external extension ID encountered: " << key_name;
- continue;
- }
-
- DictionaryValue* extension;
- if (!dict->GetDictionary(key_name, &extension)) {
- NOTREACHED();
- continue;
- }
-
- // Check to see if the extension has been killed.
- int state;
- if (extension->GetInteger(kPrefState, &state) &&
- state == static_cast<int>(Extension::KILLBIT)) {
- killed_ids->insert(StringToLowerASCII(key_name));
- }
- }
+bool ExtensionPrefs::IsExtensionKilled(const std::string& id) {
+ DictionaryValue* extension = GetExtensionPref(id);
+ if (!extension)
+ return false;
+ int state = 0;
+ return extension->GetInteger(kPrefState, &state) &&
+ state == static_cast<int>(Extension::KILLBIT);
}
std::vector<std::string> ExtensionPrefs::GetToolbarOrder() {
- std::vector<std::string> extension_ids;
+ ExtensionPrefs::ExtensionIdSet extension_ids;
const ListValue* toolbar_order = prefs_->GetList(kExtensionToolbar);
if (toolbar_order) {
for (size_t i = 0; i < toolbar_order->GetSize(); ++i) {
@@ -678,12 +674,18 @@ void ExtensionPrefs::OnExtensionInstalled(
const Extension* extension, Extension::State initial_state,
bool initial_incognito_enabled) {
const std::string& id = extension->id();
+ const base::Time install_time = GetCurrentTime();
UpdateExtensionPref(id, kPrefState,
Value::CreateIntegerValue(initial_state));
UpdateExtensionPref(id, kPrefIncognitoEnabled,
Value::CreateBooleanValue(initial_incognito_enabled));
UpdateExtensionPref(id, kPrefLocation,
Value::CreateIntegerValue(extension->location()));
+ UpdateExtensionPref(id, kPrefInstallTime,
+ Value::CreateStringValue(
+ base::Int64ToString(install_time.ToInternalValue())));
+ UpdateExtensionPref(id, kPrefPreferences, new DictionaryValue());
+
FilePath::StringType path = MakePathRelative(install_directory_,
extension->path(), NULL);
UpdateExtensionPref(id, kPrefPath, Value::CreateStringValue(path));
@@ -701,6 +703,9 @@ void ExtensionPrefs::OnExtensionInstalled(
void ExtensionPrefs::OnExtensionUninstalled(const std::string& extension_id,
const Extension::Location& location,
bool external_uninstall) {
+ PrefKeySet pref_keys;
+ GetExtensionControlledPrefKeys(extension_id, &pref_keys);
+
// For external extensions, we save a preference reminding ourself not to try
// and install the extension anymore (except when |external_uninstall| is
// true, which signifies that the registry key was deleted or the pref file
@@ -712,10 +717,12 @@ void ExtensionPrefs::OnExtensionUninstalled(const std::string& extension_id,
} else {
DeleteExtensionPrefs(extension_id);
}
+
+ UpdatePrefStore(pref_keys);
}
Extension::State ExtensionPrefs::GetExtensionState(
- const std::string& extension_id) {
+ const std::string& extension_id) const {
DictionaryValue* extension = GetExtensionPref(extension_id);
// If the extension doesn't have a pref, it's a --load-extension.
@@ -736,6 +743,11 @@ void ExtensionPrefs::SetExtensionState(const Extension* extension,
Extension::State state) {
UpdateExtensionPref(extension->id(), kPrefState,
Value::CreateIntegerValue(state));
+
+ PrefKeySet pref_keys;
+ GetExtensionControlledPrefKeys(extension->id(), &pref_keys);
+ UpdatePrefStore(pref_keys);
+
SavePrefsAndNotify();
}
@@ -841,6 +853,18 @@ DictionaryValue* ExtensionPrefs::GetExtensionPref(
return extension;
}
+DictionaryValue* ExtensionPrefs::GetExtensionControlledPrefs(
+ const std::string& extension_id) const {
+ DictionaryValue* extension = GetExtensionPref(extension_id);
+ if (!extension) {
+ NOTREACHED();
+ return NULL;
+ }
+ DictionaryValue* preferences = NULL;
+ extension->GetDictionary(kPrefPreferences, &preferences);
+ return preferences;
+}
+
// Helper function for GetInstalledExtensionsInfo.
static ExtensionInfo* GetInstalledExtensionInfoImpl(
DictionaryValue* extension_data,
@@ -1100,6 +1124,175 @@ std::string ExtensionPrefs::GetUpdateUrlData(const std::string& extension_id) {
return data;
}
+base::Time ExtensionPrefs::GetCurrentTime() const {
+ return base::Time::Now();
+}
+
+base::Time ExtensionPrefs::GetInstallTime(
+ const std::string& extension_id) const {
+ const DictionaryValue* extension = GetExtensionPref(extension_id);
+ if (!extension) {
+ NOTREACHED();
+ return base::Time();
+ }
+ std::string install_time_str("0");
+ extension->GetString(kPrefInstallTime, &install_time_str);
+ int64 install_time_i64 = 0;
+ base::StringToInt64(install_time_str, &install_time_i64);
+ LOG_IF(ERROR, install_time_i64 == 0)
+ << "Error parsing installation time of an extension.";
+ return base::Time::FromInternalValue(install_time_i64);
+}
+
+void ExtensionPrefs::GetEnabledExtensions(ExtensionIdSet* out) const {
+ CHECK(out);
+ const DictionaryValue* extensions =
+ pref_service()->GetDictionary(kExtensionsPref);
+
+ for (DictionaryValue::key_iterator ext_id = extensions->begin_keys();
+ ext_id != extensions->end_keys(); ++ext_id) {
+ if (GetExtensionState(*ext_id) != Extension::ENABLED)
+ continue;
+ out->push_back(*ext_id);
+ }
+}
+
+void ExtensionPrefs::FixMissingPrefs(const ExtensionIdSet& extension_ids) {
+ // Fix old entries that did not get an installation time entry when they
+ // were installed or don't have a preferences field.
+ bool persist_required = false;
+ for (ExtensionIdSet::const_iterator ext_id = extension_ids.begin();
+ ext_id != extension_ids.end(); ++ext_id) {
+ DictionaryValue* extension = GetExtensionPref(*ext_id);
+ CHECK(extension);
+
+ if (GetInstallTime(*ext_id) == base::Time()) {
+ const base::Time install_time = GetCurrentTime();
+ extension->Set(kPrefInstallTime,
+ Value::CreateStringValue(
+ base::Int64ToString(install_time.ToInternalValue())));
+ persist_required = true;
+ }
+ }
+ if (persist_required)
+ SavePrefsAndNotify();
+}
+
+void ExtensionPrefs::InitPrefStore() {
+ // When this is called, the PrefService is initialized and provides access
+ // to the user preferences stored in a JSON file.
+ ExtensionIdSet extension_ids;
+ GetEnabledExtensions(&extension_ids);
+ FixMissingPrefs(extension_ids);
+
+ // Collect the unique extension controlled preference keys of all extensions.
+ PrefKeySet ext_controlled_prefs;
+ for (ExtensionIdSet::iterator ext_id = extension_ids.begin();
+ ext_id != extension_ids.end(); ++ext_id) {
+ GetExtensionControlledPrefKeys(*ext_id, &ext_controlled_prefs);
+ }
+
+ // Store winning preference for each extension controlled preference.
+ UpdatePrefStore(ext_controlled_prefs);
+ pref_store_->OnInitializationCompleted();
+}
+
+const Value* ExtensionPrefs::GetWinningExtensionControlledPrefValue(
+ const std::string& key) const {
+ Value *winner = NULL;
+ base::Time winners_install_time = base::Time();
+
+ ExtensionIdSet extension_ids;
+ GetEnabledExtensions(&extension_ids);
+ for (ExtensionIdSet::iterator ext_id = extension_ids.begin();
+ ext_id != extension_ids.end(); ++ext_id) {
+ base::Time extension_install_time = GetInstallTime(*ext_id);
+
+ // We do not need to consider extensions that were installed before the
+ // most recent extension found that provides the requested preference.
+ if (extension_install_time < winners_install_time)
+ continue;
+
+ DictionaryValue* preferences = GetExtensionControlledPrefs(*ext_id);
+ Value *value = NULL;
+ if (preferences && preferences->GetWithoutPathExpansion(key, &value)) {
+ // This extension is more recent than the last one providing this pref.
+ winner = value;
+ winners_install_time = extension_install_time;
+ }
+ }
+
+ return winner;
+}
+
+void ExtensionPrefs::UpdatePrefStore(
+ const ExtensionPrefs::PrefKeySet& pref_keys) {
+ for (PrefKeySet::const_iterator i = pref_keys.begin();
+ i != pref_keys.end(); ++i) {
+ UpdatePrefStore(*i);
+ }
+}
+
+void ExtensionPrefs::UpdatePrefStore(const std::string& pref_key) {
+ if (pref_store_ == NULL)
+ return;
+ const Value* winning_pref_value =
+ GetWinningExtensionControlledPrefValue(pref_key);
+
+ if (winning_pref_value)
+ pref_store_->SetExtensionPref(pref_key, winning_pref_value->DeepCopy());
+ else
+ pref_store_->RemoveExtensionPref(pref_key);
+}
+
+void ExtensionPrefs::SetExtensionControlledPref(const std::string& extension_id,
+ const std::string& pref_key,
+ Value* value) {
+ scoped_ptr<Value> scoped_value(value);
+ DCHECK(pref_service()->FindPreference(pref_key.c_str()))
+ << "Extension controlled preference key " << pref_key
+ << " not registered.";
+ DictionaryValue* extension_preferences =
+ GetExtensionControlledPrefs(extension_id);
+
+ if (extension_preferences == NULL) { // May be pruned when writing to disk.
+ DictionaryValue* extension = GetExtensionPref(extension_id);
+ if (extension == NULL) {
+ LOG(ERROR) << "Extension preference for " << extension_id << " undefined";
+ return;
+ }
+ extension_preferences = new DictionaryValue;
+ extension->Set(kPrefPreferences, extension_preferences);
+ }
+
+ Value* oldValue = NULL;
+ extension_preferences->GetWithoutPathExpansion(pref_key, &oldValue);
+ bool modified = !Value::Equals(oldValue, scoped_value.get());
+ if (!modified)
+ return;
+
+ if (scoped_value.get() == NULL)
+ extension_preferences->RemoveWithoutPathExpansion(pref_key, NULL);
+ else
+ extension_preferences->SetWithoutPathExpansion(pref_key,
+ scoped_value.release());
+ pref_service()->ScheduleSavePersistentPrefs();
+
+ UpdatePrefStore(pref_key);
+}
+
+void ExtensionPrefs::GetExtensionControlledPrefKeys(
+ const std::string& extension_id, PrefKeySet *out) const {
+ DCHECK(out != NULL);
+ DictionaryValue* ext_prefs = GetExtensionControlledPrefs(extension_id);
+ if (ext_prefs) {
+ for (DictionaryValue::key_iterator i = ext_prefs->begin_keys();
+ i != ext_prefs->end_keys(); ++i) {
+ out->insert(*i);
+ }
+ }
+}
+
// static
void ExtensionPrefs::RegisterUserPrefs(PrefService* prefs) {
prefs->RegisterDictionaryPref(kExtensionsPref);
diff --git a/chrome/browser/extensions/extension_prefs.h b/chrome/browser/extensions/extension_prefs.h
index 6245eda..8c8be82 100644
--- a/chrome/browser/extensions/extension_prefs.h
+++ b/chrome/browser/extensions/extension_prefs.h
@@ -16,9 +16,23 @@
#include "chrome/common/extensions/extension.h"
#include "googleurl/src/gurl.h"
+class ExtensionPrefStore;
+
// Class for managing global and per-extension preferences.
-// This class is instantiated by ExtensionsService, so it should be accessed
-// from there.
+//
+// This class distinguishes the following kinds of preferences:
+// - global preferences:
+// internal state for the extension system in general, not associated
+// with an individual extension, such as lastUpdateTime.
+// - per-extension preferences:
+// meta-preferences describing properties of the extension like
+// installation time, whether the extension is enabled, etc.
+// - extension controlled preferences:
+// browser preferences that an extension controls. For example, an
+// extension could use the proxy API to specify the browser's proxy
+// preference. Extension-controlled preferences are stored in
+// PrefValueStore::extension_prefs(), which this class populates and
+// maintains as the underlying extensions change.
class ExtensionPrefs {
public:
// Key name for a preference that keeps track of per-extension settings. This
@@ -28,6 +42,12 @@ class ExtensionPrefs {
typedef std::vector<linked_ptr<ExtensionInfo> > ExtensionsInfo;
+ // Vector containing identifiers for preferences.
+ typedef std::set<std::string> PrefKeySet;
+
+ // Vector containing identifiers for extensions.
+ typedef std::vector<std::string> ExtensionIdSet;
+
// This enum is used for the launch type the user wants to use for an
// application.
// Do not remove items or re-order this enum as it is used in preferences
@@ -39,7 +59,9 @@ class ExtensionPrefs {
LAUNCH_WINDOW
};
- explicit ExtensionPrefs(PrefService* prefs, const FilePath& root_dir_);
+ explicit ExtensionPrefs(PrefService* prefs,
+ const FilePath& root_dir,
+ ExtensionPrefStore* extension_pref_store);
~ExtensionPrefs();
// Returns a copy of the Extensions prefs.
@@ -47,8 +69,9 @@ class ExtensionPrefs {
// aware of the internal structure of the preferences.
DictionaryValue* CopyCurrentExtensions();
- // Populate |killed_ids| with extension ids that have been killed.
- void GetKilledExtensionIds(std::set<std::string>* killed_ids);
+ // Returns true if the specified extension has an entry in prefs
+ // and its killbit is on.
+ bool IsExtensionKilled(const std::string& id);
// Get the order that toolstrip URLs appear in the shelf.
typedef std::vector<GURL> URLList;
@@ -74,11 +97,14 @@ class ExtensionPrefs {
bool external_uninstall);
// Returns the state (enabled/disabled) of the given extension.
- Extension::State GetExtensionState(const std::string& extension_id);
+ Extension::State GetExtensionState(const std::string& extension_id) const;
// Called to change the extension's state when it is enabled/disabled.
void SetExtensionState(const Extension* extension, Extension::State);
+ // Returns all installed and enabled extensions
+ void GetEnabledExtensions(ExtensionIdSet* out) const;
+
// Getter and setter for browser action visibility.
bool GetBrowserActionVisibility(const Extension* extension);
void SetBrowserActionVisibility(const Extension* extension, bool visible);
@@ -232,11 +258,23 @@ class ExtensionPrefs {
const std::string& data);
std::string GetUpdateUrlData(const std::string& extension_id);
+ // Sets a preference value that is controlled by the extension. In other
+ // words, this is not a pref value *about* the extension but something
+ // global the extension wants to override.
+ void SetExtensionControlledPref(const std::string& extension_id,
+ const std::string& pref_key,
+ Value* value);
+
static void RegisterUserPrefs(PrefService* prefs);
// The underlying PrefService.
PrefService* pref_service() const { return prefs_; }
+ protected:
+ // For unit testing. Enables injecting an artificial clock that is used
+ // to query the current time, when an extension is installed.
+ virtual base::Time GetCurrentTime() const;
+
private:
// Converts absolute paths in the pref to paths relative to the
// install_directory_.
@@ -296,6 +334,11 @@ class ExtensionPrefs {
// Same as above, but returns NULL if it doesn't exist.
DictionaryValue* GetExtensionPref(const std::string& id) const;
+ // Returns the dictionary of preferences controlled by the specified extension
+ // or NULL if unknown. All entries in the dictionary contain non-expanded
+ // paths.
+ DictionaryValue* GetExtensionControlledPrefs(const std::string& id) const;
+
// Serializes the data and schedules a persistent save via the |PrefService|.
// Additionally fires a PREF_CHANGED notification with the top-level
// |kExtensionsPref| path set.
@@ -313,12 +356,44 @@ class ExtensionPrefs {
base::Time LastPingDayImpl(const DictionaryValue* dictionary) const;
void SetLastPingDayImpl(const base::Time& time, DictionaryValue* dictionary);
+ // Helper method to acquire the installation time of an extension.
+ base::Time GetInstallTime(const std::string& extension_id) const;
+
+ // Fix missing preference entries in the extensions that are were introduced
+ // in a later Chrome version.
+ void FixMissingPrefs(const ExtensionIdSet& extension_ids);
+
+ // Installs the persistent extension preferences into |prefs_|'s extension
+ // pref store.
+ void InitPrefStore();
+
+ // Returns the extension controlled preference value of the extension that was
+ // installed most recently.
+ const Value* GetWinningExtensionControlledPrefValue(
+ const std::string& key) const;
+
+ // Executes UpdatePrefStore for all |pref_keys|.
+ void UpdatePrefStore(const PrefKeySet& pref_keys);
+
+ // Finds the most recently installed extension that defines a preference
+ // for |pref_key|, then stores its value in the PrefValueStore's extension
+ // pref store and sends notifications to observers in case the value changed.
+ void UpdatePrefStore(const std::string& pref_key);
+
+ // Retrieves a list of preference keys that the specified extension
+ // intends to manage. Keys are always appended, |out| is not cleared.
+ void GetExtensionControlledPrefKeys(const std::string& extension_id,
+ PrefKeySet *out) const;
+
// The pref service specific to this set of extension prefs.
PrefService* prefs_;
// Base extensions install directory.
FilePath install_directory_;
+ // Used to manipulate extension preferences.
+ ExtensionPrefStore* pref_store_;
+
// The URLs of all of the toolstrips.
URLList shelf_order_;
diff --git a/chrome/browser/extensions/extension_prefs_unittest.cc b/chrome/browser/extensions/extension_prefs_unittest.cc
index d6dcc23..6b59740 100644
--- a/chrome/browser/extensions/extension_prefs_unittest.cc
+++ b/chrome/browser/extensions/extension_prefs_unittest.cc
@@ -8,17 +8,31 @@
#include "base/stl_util-inl.h"
#include "base/string_number_conversions.h"
#include "base/stringprintf.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/extensions/extension_prefs.h"
#include "chrome/browser/extensions/test_extension_prefs.h"
+#include "chrome/browser/prefs/pref_change_registrar.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_observer_mock.h"
+#include "chrome/common/notification_source.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::Time;
using base::TimeDelta;
+const char kPref1[] = "path1.subpath";
+const char kPref2[] = "path2";
+const char kPref3[] = "path3";
+const char kPref4[] = "path4";
+
+// Default values in case an extension pref value is not overridden.
+const char kDefaultPref1[] = "default pref 1";
+const char kDefaultPref2[] = "default pref 2";
+const char kDefaultPref3[] = "default pref 3";
+const char kDefaultPref4[] = "default pref 4";
+
static void AddPattern(ExtensionExtent* extent, const std::string& pattern) {
int schemes = URLPattern::SCHEME_ALL;
extent->AddPattern(URLPattern(schemes, pattern));
@@ -55,7 +69,11 @@ class ExtensionPrefsTest : public testing::Test {
// things don't break after any ExtensionPrefs startup work.
virtual void Verify() = 0;
+ // This function is called to Register preference default values.
+ virtual void RegisterPreferences() {}
+
virtual void SetUp() {
+ RegisterPreferences();
Initialize();
}
@@ -64,6 +82,7 @@ class ExtensionPrefsTest : public testing::Test {
// Reset ExtensionPrefs, and re-verify.
prefs_.RecreateExtensionPrefs();
+ RegisterPreferences();
Verify();
}
@@ -527,3 +546,349 @@ class ExtensionPrefsAppLaunchIndex : public ExtensionPrefsTest {
scoped_refptr<Extension> extension_;
};
TEST_F(ExtensionPrefsAppLaunchIndex, ExtensionPrefsAppLaunchIndex) {}
+
+namespace keys = extension_manifest_keys;
+
+class ExtensionPrefsPreferencesBase : public ExtensionPrefsTest {
+ public:
+ ExtensionPrefsPreferencesBase()
+ : ExtensionPrefsTest(),
+ ext1_(NULL),
+ ext2_(NULL),
+ ext3_(NULL),
+ installed() {
+ DictionaryValue simple_dict;
+ std::string error;
+
+ simple_dict.SetString(keys::kVersion, "1.0.0.0");
+ simple_dict.SetString(keys::kName, "unused");
+
+ ext1_scoped_ = Extension::Create(
+ prefs_.temp_dir().AppendASCII("ext1_"), Extension::INVALID,
+ simple_dict, false, &error);
+ ext2_scoped_ = Extension::Create(
+ prefs_.temp_dir().AppendASCII("ext2_"), Extension::INVALID,
+ simple_dict, false, &error);
+ ext3_scoped_ = Extension::Create(
+ prefs_.temp_dir().AppendASCII("ext3_"), Extension::INVALID,
+ simple_dict, false, &error);
+
+ ext1_ = ext1_scoped_.get();
+ ext2_ = ext2_scoped_.get();
+ ext3_ = ext3_scoped_.get();
+
+ for (size_t i = 0; i < arraysize(installed); ++i)
+ installed[i] = false;
+ }
+
+ void RegisterPreferences() {
+ prefs()->pref_service()->RegisterStringPref(kPref1, kDefaultPref1);
+ prefs()->pref_service()->RegisterStringPref(kPref2, kDefaultPref2);
+ prefs()->pref_service()->RegisterStringPref(kPref3, kDefaultPref3);
+ prefs()->pref_service()->RegisterStringPref(kPref4, kDefaultPref4);
+ }
+
+ void InstallExtControlledPref(Extension *ext,
+ const std::string& key,
+ Value* val) {
+ // Install extension the first time a preference is set for it.
+ Extension* extensions[] = {ext1_, ext2_, ext3_};
+ for (int i = 0; i < 3; ++i) {
+ if (ext == extensions[i] && !installed[i]) {
+ prefs()->OnExtensionInstalled(ext, Extension::ENABLED, true);
+ installed[i] = true;
+ break;
+ }
+ }
+
+ prefs()->SetExtensionControlledPref(ext->id(), key, val);
+ }
+
+ void UninstallExtension(const std::string& extension_id) {
+ prefs()->OnExtensionUninstalled(extension_id, Extension::INTERNAL, false);
+ }
+
+ // Weak references, for convenience.
+ Extension* ext1_;
+ Extension* ext2_;
+ Extension* ext3_;
+
+ // Flags indicating whether each of the extensions has been installed, yet.
+ bool installed[3];
+
+ private:
+ scoped_refptr<Extension> ext1_scoped_;
+ scoped_refptr<Extension> ext2_scoped_;
+ scoped_refptr<Extension> ext3_scoped_;
+};
+
+class ExtensionPrefsInstallOneExtension
+ : public ExtensionPrefsPreferencesBase {
+ virtual void Initialize() {
+ InstallExtControlledPref(ext1_, kPref1, Value::CreateStringValue("val1"));
+ }
+ virtual void Verify() {
+ std::string actual = prefs()->pref_service()->GetString(kPref1);
+ EXPECT_EQ("val1", actual);
+ }
+};
+TEST_F(ExtensionPrefsInstallOneExtension, ExtensionPrefsInstallOneExtension) {}
+
+// Make sure the last-installed extension wins for each preference.
+class ExtensionPrefsInstallOverwrittenExtensions
+ : public ExtensionPrefsPreferencesBase {
+ virtual void Initialize() {
+ InstallExtControlledPref(ext1_, kPref1, Value::CreateStringValue("val1"));
+ InstallExtControlledPref(ext2_, kPref1, Value::CreateStringValue("val2"));
+ InstallExtControlledPref(ext3_, kPref1, Value::CreateStringValue("val3"));
+
+ InstallExtControlledPref(ext1_, kPref2, Value::CreateStringValue("val4"));
+ InstallExtControlledPref(ext2_, kPref2, Value::CreateStringValue("val5"));
+
+ InstallExtControlledPref(ext1_, kPref1, Value::CreateStringValue("val6"));
+ InstallExtControlledPref(ext1_, kPref2, Value::CreateStringValue("val7"));
+ InstallExtControlledPref(ext1_, kPref3, Value::CreateStringValue("val8"));
+ }
+ virtual void Verify() {
+ std::string actual;
+ actual = prefs()->pref_service()->GetString(kPref1);
+ EXPECT_EQ("val3", actual);
+ actual = prefs()->pref_service()->GetString(kPref2);
+ EXPECT_EQ("val5", actual);
+ actual = prefs()->pref_service()->GetString(kPref3);
+ EXPECT_EQ("val8", actual);
+ }
+};
+TEST_F(ExtensionPrefsInstallOverwrittenExtensions,
+ ExtensionPrefsInstallOverwrittenExtensions) {}
+
+// Make sure the last-installed extension wins even if other extensions set
+// the same or different preferences later.
+class ExtensionPrefsInstallInterleavedExtensions
+ : public ExtensionPrefsPreferencesBase {
+ virtual void Initialize() {
+ InstallExtControlledPref(ext1_, kPref1, Value::CreateStringValue("val1"));
+ InstallExtControlledPref(ext2_, kPref2, Value::CreateStringValue("val2"));
+ InstallExtControlledPref(ext3_, kPref3, Value::CreateStringValue("val3"));
+
+ InstallExtControlledPref(ext3_, kPref3, Value::CreateStringValue("val4"));
+ InstallExtControlledPref(ext2_, kPref3, Value::CreateStringValue("val5"));
+ InstallExtControlledPref(ext1_, kPref3, Value::CreateStringValue("val6"));
+
+ InstallExtControlledPref(ext3_, kPref1, Value::CreateStringValue("val7"));
+ }
+ virtual void Verify() {
+ std::string actual;
+ actual = prefs()->pref_service()->GetString(kPref1);
+ EXPECT_EQ("val7", actual);
+ actual = prefs()->pref_service()->GetString(kPref2);
+ EXPECT_EQ("val2", actual);
+ actual = prefs()->pref_service()->GetString(kPref3);
+ EXPECT_EQ("val4", actual);
+ }
+};
+TEST_F(ExtensionPrefsInstallInterleavedExtensions,
+ ExtensionPrefsInstallInterleavedExtensions) {}
+
+class ExtensionPrefsUninstallOnlyExtension
+ : public ExtensionPrefsPreferencesBase {
+ virtual void Initialize() {
+ InstallExtControlledPref(ext1_, kPref1, Value::CreateStringValue("val1"));
+ InstallExtControlledPref(ext1_, kPref2, Value::CreateStringValue("val2"));
+
+ UninstallExtension(ext1_->id());
+ }
+ virtual void Verify() {
+ std::string actual;
+ actual = prefs()->pref_service()->GetString(kPref1);
+ EXPECT_EQ(kDefaultPref1, actual);
+ actual = prefs()->pref_service()->GetString(kPref2);
+ EXPECT_EQ(kDefaultPref2, actual);
+ }
+};
+TEST_F(ExtensionPrefsUninstallOnlyExtension,
+ ExtensionPrefsUninstallOnlyExtension) {}
+
+// Tests uninstalling an extension that wasn't winning for any preferences.
+class ExtensionPrefsUninstallIrrelevantExtension
+ : public ExtensionPrefsPreferencesBase {
+ virtual void Initialize() {
+ InstallExtControlledPref(ext1_, kPref1, Value::CreateStringValue("val1"));
+ InstallExtControlledPref(ext2_, kPref1, Value::CreateStringValue("val2"));
+
+ InstallExtControlledPref(ext1_, kPref2, Value::CreateStringValue("val3"));
+ InstallExtControlledPref(ext2_, kPref2, Value::CreateStringValue("val4"));
+
+ UninstallExtension(ext1_->id());
+ }
+ virtual void Verify() {
+ std::string actual;
+ actual = prefs()->pref_service()->GetString(kPref1);
+ EXPECT_EQ("val2", actual);
+ actual = prefs()->pref_service()->GetString(kPref2);
+ EXPECT_EQ("val4", actual);
+ }
+};
+TEST_F(ExtensionPrefsUninstallIrrelevantExtension,
+ ExtensionPrefsUninstallIrrelevantExtension) {}
+
+// Tests uninstalling an extension that was winning for all preferences.
+class ExtensionPrefsUninstallExtensionFromTop
+ : public ExtensionPrefsPreferencesBase {
+ virtual void Initialize() {
+ InstallExtControlledPref(ext1_, kPref1, Value::CreateStringValue("val1"));
+ InstallExtControlledPref(ext2_, kPref1, Value::CreateStringValue("val2"));
+ InstallExtControlledPref(ext3_, kPref1, Value::CreateStringValue("val3"));
+
+ InstallExtControlledPref(ext1_, kPref2, Value::CreateStringValue("val4"));
+ InstallExtControlledPref(ext3_, kPref2, Value::CreateStringValue("val5"));
+
+ UninstallExtension(ext3_->id());
+ }
+ virtual void Verify() {
+ std::string actual;
+ actual = prefs()->pref_service()->GetString(kPref1);
+ EXPECT_EQ("val2", actual);
+ actual = prefs()->pref_service()->GetString(kPref2);
+ EXPECT_EQ("val4", actual);
+ }
+};
+TEST_F(ExtensionPrefsUninstallExtensionFromTop,
+ ExtensionPrefsUninstallExtensionFromTop) {}
+
+// Tests uninstalling an extension that was winning for only some preferences.
+class ExtensionPrefsUninstallExtensionFromMiddle
+ : public ExtensionPrefsPreferencesBase {
+ virtual void Initialize() {
+ InstallExtControlledPref(ext1_, kPref1, Value::CreateStringValue("val1"));
+ InstallExtControlledPref(ext2_, kPref1, Value::CreateStringValue("val2"));
+ InstallExtControlledPref(ext3_, kPref1, Value::CreateStringValue("val3"));
+
+ InstallExtControlledPref(ext1_, kPref2, Value::CreateStringValue("val4"));
+ InstallExtControlledPref(ext2_, kPref2, Value::CreateStringValue("val5"));
+
+ InstallExtControlledPref(ext1_, kPref3, Value::CreateStringValue("val6"));
+
+ InstallExtControlledPref(ext2_, kPref4, Value::CreateStringValue("val7"));
+
+ UninstallExtension(ext2_->id());
+ }
+ virtual void Verify() {
+ std::string actual;
+ actual = prefs()->pref_service()->GetString(kPref1);
+ EXPECT_EQ("val3", actual);
+ actual = prefs()->pref_service()->GetString(kPref2);
+ EXPECT_EQ("val4", actual);
+ actual = prefs()->pref_service()->GetString(kPref3);
+ EXPECT_EQ("val6", actual);
+ actual = prefs()->pref_service()->GetString(kPref4);
+ EXPECT_EQ(kDefaultPref4, actual);
+ }
+};
+TEST_F(ExtensionPrefsUninstallExtensionFromMiddle,
+ ExtensionPrefsUninstallExtensionFromMiddle) {}
+
+// Tests triggering of notifications to registered observers
+class ExtensionPrefsNotifyWhenNeeded
+ : public ExtensionPrefsPreferencesBase {
+ virtual void Initialize() {
+ using testing::_;
+ using testing::Mock;
+ using testing::StrEq;
+
+ scoped_ptr<NotificationObserverMock> observer(
+ new NotificationObserverMock());
+ PrefChangeRegistrar registrar;
+ registrar.Init(prefs()->pref_service());
+ registrar.Add(kPref1, observer.get());
+
+ EXPECT_CALL(*observer, Observe(_, _, _));
+ InstallExtControlledPref(ext1_, kPref1,
+ Value::CreateStringValue("https://www.chromium.org"));
+ Mock::VerifyAndClearExpectations(observer.get());
+
+ EXPECT_CALL(*observer, Observe(_, _, _)).Times(0);
+ InstallExtControlledPref(ext1_, kPref1,
+ Value::CreateStringValue("https://www.chromium.org"));
+ Mock::VerifyAndClearExpectations(observer.get());
+
+ EXPECT_CALL(*observer, Observe(_, _, _)).Times(2);
+ InstallExtControlledPref(ext1_, kPref1,
+ Value::CreateStringValue("chrome://newtab"));
+
+ UninstallExtension(ext1_->id());
+ registrar.Remove(kPref1, observer.get());
+ }
+ virtual void Verify() {
+ std::string actual = prefs()->pref_service()->GetString(kPref1);
+ EXPECT_EQ(kDefaultPref1, actual);
+ }
+};
+TEST_F(ExtensionPrefsNotifyWhenNeeded,
+ ExtensionPrefsNotifyWhenNeeded) {}
+
+// Tests disabling an extension
+class ExtensionPrefsDisableExt
+ : public ExtensionPrefsPreferencesBase {
+ virtual void Initialize() {
+ InstallExtControlledPref(ext1_, kPref1, Value::CreateStringValue("val1"));
+ std::string actual = prefs()->pref_service()->GetString(kPref1);
+ EXPECT_EQ("val1", actual);
+ prefs()->SetExtensionState(ext1_, Extension::DISABLED);
+ }
+ virtual void Verify() {
+ std::string actual = prefs()->pref_service()->GetString(kPref1);
+ EXPECT_EQ(kDefaultPref1, actual);
+ }
+};
+TEST_F(ExtensionPrefsDisableExt, ExtensionPrefsDisableExt) {}
+
+// Tests disabling and reenabling an extension
+class ExtensionPrefsReenableExt
+ : public ExtensionPrefsPreferencesBase {
+ virtual void Initialize() {
+ InstallExtControlledPref(ext1_, kPref1, Value::CreateStringValue("val1"));
+ prefs()->SetExtensionState(ext1_, Extension::DISABLED);
+ prefs()->SetExtensionState(ext1_, Extension::ENABLED);
+ }
+ virtual void Verify() {
+ std::string actual = prefs()->pref_service()->GetString(kPref1);
+ EXPECT_EQ("val1", actual);
+ }
+};
+TEST_F(ExtensionPrefsDisableExt, ExtensionPrefsReenableExt) {}
+
+// Mock class to test whether objects are deleted correctly.
+class MockStringValue : public StringValue {
+ public:
+ explicit MockStringValue(const std::string& in_value)
+ : StringValue(in_value) {
+ }
+ virtual ~MockStringValue() {
+ Die();
+ }
+ MOCK_METHOD0(Die, void());
+};
+
+class ExtensionPrefsSetExtensionControlledPref
+ : public ExtensionPrefsPreferencesBase {
+ public:
+ virtual void Initialize() {
+ MockStringValue* v1 = new MockStringValue("https://www.chromium.org");
+ MockStringValue* v2 = new MockStringValue("https://www.chromium.org");
+ // Ownership is taken, value shall not be deleted.
+ EXPECT_CALL(*v1, Die()).Times(0);
+ InstallExtControlledPref(ext1_, kPref1, v1);
+ testing::Mock::VerifyAndClearExpectations(v1);
+ // Make sure there is no memory leak and both values are deleted.
+ EXPECT_CALL(*v2, Die()).Times(1);
+ EXPECT_CALL(*v1, Die()).Times(1);
+ InstallExtControlledPref(ext1_, kPref1, v2);
+ prefs_.RecreateExtensionPrefs();
+ }
+
+ virtual void Verify() {
+ }
+};
+TEST_F(ExtensionPrefsSetExtensionControlledPref,
+ ExtensionPrefsSetExtensionControlledPref) {}
diff --git a/chrome/browser/extensions/extension_process_manager.cc b/chrome/browser/extensions/extension_process_manager.cc
index c273033..03e868d 100644
--- a/chrome/browser/extensions/extension_process_manager.cc
+++ b/chrome/browser/extensions/extension_process_manager.cc
@@ -10,8 +10,8 @@
#include "chrome/browser/extensions/extension_host_mac.h"
#endif
#include "chrome/browser/extensions/extension_host.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
@@ -135,8 +135,8 @@ ExtensionHost* ExtensionProcessManager::CreateView(const GURL& url,
ViewType::Type view_type) {
// A NULL browser may only be given for pop-up views.
DCHECK(browser || (!browser && view_type == ViewType::EXTENSION_POPUP));
- ExtensionsService* service =
- browsing_instance_->profile()->GetExtensionsService();
+ ExtensionService* service =
+ browsing_instance_->profile()->GetExtensionService();
if (service) {
const Extension* extension = service->GetExtensionByURL(url);
if (extension)
@@ -226,8 +226,8 @@ void ExtensionProcessManager::RegisterExtensionProcess(
DCHECK(it == process_ids_.end());
process_ids_[extension_id] = process_id;
- ExtensionsService* extension_service =
- browsing_instance_->profile()->GetExtensionsService();
+ ExtensionService* extension_service =
+ browsing_instance_->profile()->GetExtensionService();
std::vector<std::string> page_action_ids;
const Extension* extension =
@@ -281,13 +281,13 @@ void ExtensionProcessManager::Observe(NotificationType type,
switch (type.value) {
case NotificationType::EXTENSIONS_READY: {
CreateBackgroundHosts(this,
- Source<Profile>(source).ptr()->GetExtensionsService()->extensions());
+ Source<Profile>(source).ptr()->GetExtensionService()->extensions());
break;
}
case NotificationType::EXTENSION_LOADED: {
- ExtensionsService* service =
- Source<Profile>(source).ptr()->GetExtensionsService();
+ ExtensionService* service =
+ Source<Profile>(source).ptr()->GetExtensionService();
if (service->is_ready()) {
const Extension* extension = Details<const Extension>(details).ptr();
::CreateBackgroundHost(this, extension);
@@ -296,7 +296,8 @@ void ExtensionProcessManager::Observe(NotificationType type,
}
case NotificationType::EXTENSION_UNLOADED: {
- const Extension* extension = Details<const Extension>(details).ptr();
+ const Extension* extension =
+ Details<UnloadedExtensionInfo>(details)->extension;
for (ExtensionHostSet::iterator iter = background_hosts_.begin();
iter != background_hosts_.end(); ++iter) {
ExtensionHost* host = *iter;
@@ -427,8 +428,8 @@ RenderProcessHost* IncognitoExtensionProcessManager::GetExtensionProcess(
const Extension* IncognitoExtensionProcessManager::GetExtensionOrAppByURL(
const GURL& url) {
- ExtensionsService* service =
- browsing_instance_->profile()->GetExtensionsService();
+ ExtensionService* service =
+ browsing_instance_->profile()->GetExtensionService();
if (!service)
return NULL;
return (url.SchemeIs(chrome::kExtensionScheme)) ?
@@ -437,8 +438,8 @@ const Extension* IncognitoExtensionProcessManager::GetExtensionOrAppByURL(
bool IncognitoExtensionProcessManager::IsIncognitoEnabled(
const Extension* extension) {
- ExtensionsService* service =
- browsing_instance_->profile()->GetExtensionsService();
+ ExtensionService* service =
+ browsing_instance_->profile()->GetExtensionService();
return service && service->IsIncognitoEnabled(extension);
}
@@ -456,8 +457,8 @@ void IncognitoExtensionProcessManager::Observe(
// On Chrome OS, a login screen is implemented as a browser.
// This browser has no extension service. In this case,
// service will be NULL.
- ExtensionsService* service =
- browsing_instance_->profile()->GetExtensionsService();
+ ExtensionService* service =
+ browsing_instance_->profile()->GetExtensionService();
if (service && service->is_ready())
CreateBackgroundHosts(this, service->extensions());
}
diff --git a/chrome/browser/extensions/extension_processes_api.cc b/chrome/browser/extensions/extension_processes_api.cc
index 99b72e8..5edc2f0 100644
--- a/chrome/browser/extensions/extension_processes_api.cc
+++ b/chrome/browser/extensions/extension_processes_api.cc
@@ -16,13 +16,12 @@
#include "chrome/browser/extensions/extension_processes_api_constants.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
#include "chrome/browser/extensions/extension_tabs_module_constants.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/task_manager/task_manager.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/extensions/extension_error_utils.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
namespace keys = extension_processes_api_constants;
diff --git a/chrome/browser/extensions/extension_protocols.cc b/chrome/browser/extensions/extension_protocols.cc
index edf937b..e95f18d 100644
--- a/chrome/browser/extensions/extension_protocols.cc
+++ b/chrome/browser/extensions/extension_protocols.cc
@@ -32,15 +32,15 @@
namespace {
-class URLRequestResourceBundleJob : public URLRequestSimpleJob {
+class URLRequestResourceBundleJob : public net::URLRequestSimpleJob {
public:
- explicit URLRequestResourceBundleJob(URLRequest* request,
+ explicit URLRequestResourceBundleJob(net::URLRequest* request,
const FilePath& filename, int resource_id)
- : URLRequestSimpleJob(request),
+ : net::URLRequestSimpleJob(request),
filename_(filename),
resource_id_(resource_id) { }
- // URLRequestSimpleJob method.
+ // Overridden from URLRequestSimpleJob:
virtual bool GetData(std::string* mime_type,
std::string* charset,
std::string* data) const {
@@ -67,7 +67,7 @@ class URLRequestResourceBundleJob : public URLRequestSimpleJob {
};
// Returns true if an chrome-extension:// resource should be allowed to load.
-bool AllowExtensionResourceLoad(URLRequest* request,
+bool AllowExtensionResourceLoad(net::URLRequest* request,
ChromeURLRequestContext* context,
const std::string& scheme) {
const ResourceDispatcherHostRequestInfo* info =
@@ -142,16 +142,17 @@ bool AllowExtensionResourceLoad(URLRequest* request,
} // namespace
-// Factory registered with URLRequest to create URLRequestJobs for extension://
-// URLs.
-static URLRequestJob* CreateExtensionURLRequestJob(URLRequest* request,
- const std::string& scheme) {
+// Factory registered with net::URLRequest to create URLRequestJobs for
+// extension:// URLs.
+static net::URLRequestJob* CreateExtensionURLRequestJob(
+ net::URLRequest* request,
+ const std::string& scheme) {
ChromeURLRequestContext* context =
static_cast<ChromeURLRequestContext*>(request->context());
// TODO(mpcomplete): better error code.
if (!AllowExtensionResourceLoad(request, context, scheme))
- return new URLRequestErrorJob(request, net::ERR_ADDRESS_UNREACHABLE);
+ return new net::URLRequestErrorJob(request, net::ERR_ADDRESS_UNREACHABLE);
// chrome-extension://extension-id/resource/path.js
const std::string& extension_id = request->url().host();
@@ -198,13 +199,14 @@ static URLRequestJob* CreateExtensionURLRequestJob(URLRequest* request,
base::ThreadRestrictions::ScopedAllowIO allow_io;
resource_file_path = resource.GetFilePath();
}
- return new URLRequestFileJob(request, resource_file_path);
+ return new net::URLRequestFileJob(request, resource_file_path);
}
-// Factory registered with URLRequest to create URLRequestJobs for
+// Factory registered with net::URLRequest to create URLRequestJobs for
// chrome-user-script:/ URLs.
-static URLRequestJob* CreateUserScriptURLRequestJob(URLRequest* request,
- const std::string& scheme) {
+static net::URLRequestJob* CreateUserScriptURLRequestJob(
+ net::URLRequest* request,
+ const std::string& scheme) {
ChromeURLRequestContext* context =
static_cast<ChromeURLRequestContext*>(request->context());
@@ -214,12 +216,12 @@ static URLRequestJob* CreateUserScriptURLRequestJob(URLRequest* request,
ExtensionResource resource(request->url().host(), directory_path,
extension_file_util::ExtensionURLToRelativeFilePath(request->url()));
- return new URLRequestFileJob(request, resource.GetFilePath());
+ return new net::URLRequestFileJob(request, resource.GetFilePath());
}
void RegisterExtensionProtocols() {
- URLRequest::RegisterProtocolFactory(chrome::kExtensionScheme,
- &CreateExtensionURLRequestJob);
- URLRequest::RegisterProtocolFactory(chrome::kUserScriptScheme,
- &CreateUserScriptURLRequestJob);
+ net::URLRequest::RegisterProtocolFactory(chrome::kExtensionScheme,
+ &CreateExtensionURLRequestJob);
+ net::URLRequest::RegisterProtocolFactory(chrome::kUserScriptScheme,
+ &CreateUserScriptURLRequestJob);
}
diff --git a/chrome/browser/extensions/extension_proxy_api.cc b/chrome/browser/extensions/extension_proxy_api.cc
index 030b711..d71c055 100644
--- a/chrome/browser/extensions/extension_proxy_api.cc
+++ b/chrome/browser/extensions/extension_proxy_api.cc
@@ -7,8 +7,9 @@
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/values.h"
-#include "chrome/browser/extensions/extension_pref_store.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/browser/prefs/proxy_prefs.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/common/pref_names.h"
namespace {
@@ -53,8 +54,8 @@ bool UseCustomProxySettingsFunction::RunImpl() {
DictionaryValue* proxy_config;
EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &proxy_config));
- bool auto_detect = false;
- proxy_config->GetBoolean("autoDetect", &auto_detect);
+ std::string proxy_mode;
+ proxy_config->GetString("mode", &proxy_mode);
DictionaryValue* pac_dict = NULL;
proxy_config->GetDictionary("pacScript", &pac_dict);
@@ -62,7 +63,9 @@ bool UseCustomProxySettingsFunction::RunImpl() {
DictionaryValue* proxy_rules = NULL;
proxy_config->GetDictionary("rules", &proxy_rules);
- return ApplyAutoDetect(auto_detect) &&
+ // TODO(battre,gfeher): Make sure all the preferences get always
+ // overwritten.
+ return ApplyMode(proxy_mode) &&
ApplyPacScript(pac_dict) &&
ApplyProxyRules(proxy_rules);
}
@@ -75,13 +78,19 @@ bool UseCustomProxySettingsFunction::GetProxyServer(
return true;
}
-bool UseCustomProxySettingsFunction::ApplyAutoDetect(bool auto_detect) {
- // We take control of the auto-detect preference even if none was specified,
- // so that all proxy preferences are controlled by the same extension (if not
- // by a higher-priority source).
- SendNotification(prefs::kProxyAutoDetect,
- Value::CreateBooleanValue(auto_detect));
- return true;
+bool UseCustomProxySettingsFunction::ApplyMode(const std::string& mode) {
+ // We take control of the mode preference even if none was specified, so that
+ // all proxy preferences are controlled by the same extension (if not by a
+ // higher-priority source).
+ bool result = true;
+ ProxyPrefs::ProxyMode mode_enum;
+ if (!ProxyPrefs::StringToProxyMode(mode, &mode_enum)) {
+ mode_enum = ProxyPrefs::MODE_SYSTEM;
+ LOG(WARNING) << "Invalid mode for proxy settings: " << mode;
+ result = false;
+ }
+ ApplyPreference(prefs::kProxyMode, Value::CreateIntegerValue(mode_enum));
+ return result;
}
bool UseCustomProxySettingsFunction::ApplyPacScript(DictionaryValue* pac_dict) {
@@ -92,14 +101,16 @@ bool UseCustomProxySettingsFunction::ApplyPacScript(DictionaryValue* pac_dict) {
// We take control of the PAC preference even if none was specified, so that
// all proxy preferences are controlled by the same extension (if not by a
// higher-priority source).
- SendNotification(prefs::kProxyPacUrl, Value::CreateStringValue(pac_url));
+ ApplyPreference(prefs::kProxyPacUrl, Value::CreateStringValue(pac_url));
return true;
}
bool UseCustomProxySettingsFunction::ApplyProxyRules(
DictionaryValue* proxy_rules) {
- if (!proxy_rules)
+ if (!proxy_rules) {
+ ApplyPreference(prefs::kProxyServer, Value::CreateStringValue(""));
return true;
+ }
// Local data into which the parameters will be parsed. has_proxy describes
// whether a setting was found for the scheme; proxy_dict holds the
@@ -153,17 +164,12 @@ bool UseCustomProxySettingsFunction::ApplyProxyRules(
}
}
- SendNotification(prefs::kProxyServer, Value::CreateStringValue(proxy_pref));
+ ApplyPreference(prefs::kProxyServer, Value::CreateStringValue(proxy_pref));
return true;
}
-void UseCustomProxySettingsFunction::SendNotification(const char* pref_path,
- Value* pref_value) {
- ExtensionPrefStore::ExtensionPrefDetails details =
- std::make_pair(GetExtension(), std::make_pair(pref_path, pref_value));
-
- NotificationService::current()->Notify(
- NotificationType::EXTENSION_PREF_CHANGED,
- Source<Profile>(profile_),
- Details<ExtensionPrefStore::ExtensionPrefDetails>(&details));
+void UseCustomProxySettingsFunction::ApplyPreference(const char* pref_path,
+ Value* pref_value) {
+ profile()->GetExtensionService()->extension_prefs()
+ ->SetExtensionControlledPref(extension_id(), pref_path, pref_value);
}
diff --git a/chrome/browser/extensions/extension_proxy_api.h b/chrome/browser/extensions/extension_proxy_api.h
index 95be304..d645c44 100644
--- a/chrome/browser/extensions/extension_proxy_api.h
+++ b/chrome/browser/extensions/extension_proxy_api.h
@@ -33,14 +33,12 @@ class UseCustomProxySettingsFunction : public SyncExtensionFunction {
bool GetProxyServer(const DictionaryValue* dict, ProxyServer* proxy_server);
- bool ApplyAutoDetect(bool auto_detect);
+ bool ApplyMode(const std::string& mode);
bool ApplyPacScript(DictionaryValue* pac_dict);
bool ApplyProxyRules(DictionaryValue* proxy_rules);
- // Sends a notification that the given pref would like to change to the
- // indicated pref_value. This is mainly useful so the ExtensionPrefStore can
- // apply the requested change.
- void SendNotification(const char* pref_path, Value* pref_value);
+ // Takes ownership of |pref_value|.
+ void ApplyPreference(const char* pref_path, Value* pref_value);
};
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_PROXY_API_H_
diff --git a/chrome/browser/extensions/extension_proxy_apitest.cc b/chrome/browser/extensions/extension_proxy_apitest.cc
index 7f83407..5537f32 100644
--- a/chrome/browser/extensions/extension_proxy_apitest.cc
+++ b/chrome/browser/extensions/extension_proxy_apitest.cc
@@ -4,13 +4,46 @@
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/prefs/proxy_prefs.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/pref_names.h"
-// Tests auto-detect and PAC proxy settings.
+// Tests direct connection settings.
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProxyDirectSettings) {
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableExperimentalExtensionApis);
+
+ ASSERT_TRUE(RunExtensionTest("proxy/direct")) << message_;
+ const Extension* extension = GetSingleLoadedExtension();
+ ASSERT_TRUE(extension);
+
+ PrefService* pref_service = browser()->profile()->GetPrefs();
+
+ const PrefService::Preference* pref =
+ pref_service->FindPreference(prefs::kProxyMode);
+ ASSERT_TRUE(pref != NULL);
+ ASSERT_TRUE(pref->IsExtensionControlled());
+ int mode = pref_service->GetInteger(prefs::kProxyMode);
+ EXPECT_EQ(ProxyPrefs::MODE_DIRECT, mode);
+
+ // Other proxy prefs should also be set, so they're all controlled from one
+ // place.
+ pref = pref_service->FindPreference(prefs::kProxyPacUrl);
+ ASSERT_TRUE(pref != NULL);
+ EXPECT_TRUE(pref->IsExtensionControlled());
+ EXPECT_EQ("", pref_service->GetString(prefs::kProxyPacUrl));
+
+ // No manual proxy prefs were set.
+ pref = pref_service->FindPreference(prefs::kProxyServer);
+ ASSERT_TRUE(pref != NULL);
+ EXPECT_TRUE(pref->IsExtensionControlled());
+ EXPECT_EQ("", pref_service->GetString(prefs::kProxyServer));
+}
+
+// Tests auto-detect settings.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProxyAutoSettings) {
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableExperimentalExtensionApis);
@@ -22,11 +55,37 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProxyAutoSettings) {
PrefService* pref_service = browser()->profile()->GetPrefs();
const PrefService::Preference* pref =
- pref_service->FindPreference(prefs::kProxyAutoDetect);
+ pref_service->FindPreference(prefs::kProxyMode);
+ ASSERT_TRUE(pref != NULL);
+ ASSERT_TRUE(pref->IsExtensionControlled());
+ int mode = pref_service->GetInteger(prefs::kProxyMode);
+ EXPECT_EQ(ProxyPrefs::MODE_AUTO_DETECT, mode);
+
+ // Other proxy prefs should also be set, so they're all controlled from one
+ // place.
+ pref = pref_service->FindPreference(prefs::kProxyPacUrl);
+ ASSERT_TRUE(pref != NULL);
+ EXPECT_TRUE(pref->IsExtensionControlled());
+ EXPECT_EQ("", pref_service->GetString(prefs::kProxyPacUrl));
+}
+
+// Tests PAC proxy settings.
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProxyPacScript) {
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableExperimentalExtensionApis);
+
+ ASSERT_TRUE(RunExtensionTest("proxy/pac")) << message_;
+ const Extension* extension = GetSingleLoadedExtension();
+ ASSERT_TRUE(extension);
+
+ PrefService* pref_service = browser()->profile()->GetPrefs();
+
+ const PrefService::Preference* pref =
+ pref_service->FindPreference(prefs::kProxyMode);
ASSERT_TRUE(pref != NULL);
ASSERT_TRUE(pref->IsExtensionControlled());
- bool auto_detect = pref_service->GetBoolean(prefs::kProxyAutoDetect);
- EXPECT_TRUE(auto_detect);
+ int mode = pref_service->GetInteger(prefs::kProxyMode);
+ EXPECT_EQ(ProxyPrefs::MODE_PAC_SCRIPT, mode);
pref = pref_service->FindPreference(prefs::kProxyPacUrl);
ASSERT_TRUE(pref != NULL);
@@ -37,11 +96,12 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProxyAutoSettings) {
// No manual proxy prefs were set.
pref = pref_service->FindPreference(prefs::kProxyServer);
ASSERT_TRUE(pref != NULL);
- EXPECT_TRUE(pref->IsDefaultValue());
+ EXPECT_TRUE(pref->IsExtensionControlled());
+ EXPECT_EQ("", pref_service->GetString(prefs::kProxyServer));
}
// Tests setting a single proxy to cover all schemes.
-IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProxyManualSingle) {
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProxyFixedSingle) {
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableExperimentalExtensionApis);
@@ -64,19 +124,53 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProxyManualSingle) {
// Other proxy prefs should also be set, so they're all controlled from one
// place.
- pref = pref_service->FindPreference(prefs::kProxyAutoDetect);
+ pref = pref_service->FindPreference(prefs::kProxyMode);
+ ASSERT_TRUE(pref != NULL);
+ EXPECT_TRUE(pref->IsExtensionControlled());
+ EXPECT_EQ(ProxyPrefs::MODE_FIXED_SERVERS,
+ pref_service->GetInteger(prefs::kProxyMode));
+
+ pref = pref_service->FindPreference(prefs::kProxyPacUrl);
ASSERT_TRUE(pref != NULL);
EXPECT_TRUE(pref->IsExtensionControlled());
- EXPECT_FALSE(pref_service->GetBoolean(prefs::kProxyAutoDetect));
+ EXPECT_EQ("", pref_service->GetString(prefs::kProxyPacUrl));
+}
+
+// Tests setting to use the system's proxy settings.
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProxySystem) {
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableExperimentalExtensionApis);
+
+ ASSERT_TRUE(RunExtensionTest("proxy/system")) << message_;
+ const Extension* extension = GetSingleLoadedExtension();
+ ASSERT_TRUE(extension);
+
+ PrefService* pref_service = browser()->profile()->GetPrefs();
+
+ // There should be no values superseding the extension-set proxy in this test.
+ const PrefService::Preference* pref =
+ pref_service->FindPreference(prefs::kProxyMode);
+ ASSERT_TRUE(pref != NULL);
+ ASSERT_TRUE(pref->IsExtensionControlled());
+ int proxy_server_mode = pref_service->GetInteger(prefs::kProxyMode);
+ EXPECT_EQ(ProxyPrefs::MODE_SYSTEM, proxy_server_mode);
+ // Other proxy prefs should also be set, so they're all controlled from one
+ // place.
pref = pref_service->FindPreference(prefs::kProxyPacUrl);
ASSERT_TRUE(pref != NULL);
EXPECT_TRUE(pref->IsExtensionControlled());
EXPECT_EQ("", pref_service->GetString(prefs::kProxyPacUrl));
+
+ // No manual proxy prefs were set.
+ pref = pref_service->FindPreference(prefs::kProxyServer);
+ ASSERT_TRUE(pref != NULL);
+ EXPECT_TRUE(pref->IsExtensionControlled());
+ EXPECT_EQ("", pref_service->GetString(prefs::kProxyServer));
}
// Tests setting separate proxies for each scheme.
-IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProxyManualIndividual) {
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProxyFixedIndividual) {
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableExperimentalExtensionApis);
@@ -100,10 +194,11 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProxyManualIndividual) {
// Other proxy prefs should also be set, so they're all controlled from one
// place.
- pref = pref_service->FindPreference(prefs::kProxyAutoDetect);
+ pref = pref_service->FindPreference(prefs::kProxyMode);
ASSERT_TRUE(pref != NULL);
EXPECT_TRUE(pref->IsExtensionControlled());
- EXPECT_FALSE(pref_service->GetBoolean(prefs::kProxyAutoDetect));
+ EXPECT_EQ(ProxyPrefs::MODE_FIXED_SERVERS,
+ pref_service->GetInteger(prefs::kProxyMode));
pref = pref_service->FindPreference(prefs::kProxyPacUrl);
ASSERT_TRUE(pref != NULL);
diff --git a/chrome/browser/extensions/extension_rlz_apitest.cc b/chrome/browser/extensions/extension_rlz_apitest.cc
index 10bfba6..efb275a 100644
--- a/chrome/browser/extensions/extension_rlz_apitest.cc
+++ b/chrome/browser/extensions/extension_rlz_apitest.cc
@@ -5,7 +5,6 @@
#include <map>
#include "base/win/registry.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extension_function.h"
#include "chrome/browser/extensions/extension_function_dispatcher.h"
#include "chrome/browser/extensions/extension_apitest.h"
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
new file mode 100644
index 0000000..bb24e1e
--- /dev/null
+++ b/chrome/browser/extensions/extension_service.cc
@@ -0,0 +1,2074 @@
+// 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.
+
+#include "chrome/browser/extensions/extension_service.h"
+
+#include <algorithm>
+
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/metrics/histogram.h"
+#include "base/stl_util-inl.h"
+#include "base/string16.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "base/thread_restrictions.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "base/values_util.h"
+#include "base/version.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/debugger/devtools_manager.h"
+#include "chrome/browser/dom_ui/shown_sections_handler.h"
+#include "chrome/browser/extensions/crx_installer.h"
+#include "chrome/browser/extensions/default_apps.h"
+#include "chrome/browser/extensions/extension_accessibility_api.h"
+#include "chrome/browser/extensions/extension_bookmarks_module.h"
+#include "chrome/browser/extensions/extension_browser_event_router.h"
+#include "chrome/browser/extensions/extension_cookies_api.h"
+#include "chrome/browser/extensions/extension_data_deleter.h"
+#include "chrome/browser/extensions/extension_dom_ui.h"
+#include "chrome/browser/extensions/extension_error_reporter.h"
+#include "chrome/browser/extensions/extension_history_api.h"
+#include "chrome/browser/extensions/extension_host.h"
+#include "chrome/browser/extensions/extension_management_api.h"
+#include "chrome/browser/extensions/extension_process_manager.h"
+#include "chrome/browser/extensions/extension_processes_api.h"
+#include "chrome/browser/extensions/extension_updater.h"
+#include "chrome/browser/extensions/extension_webnavigation_api.h"
+#include "chrome/browser/extensions/external_extension_provider.h"
+#include "chrome/browser/extensions/external_policy_extension_provider.h"
+#include "chrome/browser/extensions/external_pref_extension_provider.h"
+#include "chrome/browser/net/chrome_url_request_context.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/common/child_process_logging.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/extensions/extension_error_utils.h"
+#include "chrome/common/extensions/extension_file_util.h"
+#include "chrome/common/extensions/extension_l10n_util.h"
+#include "chrome/common/extensions/extension_resource.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
+#include "chrome/common/json_value_serializer.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/registry_controlled_domain.h"
+#include "webkit/database/database_tracker.h"
+#include "webkit/database/database_util.h"
+
+#if defined(OS_WIN)
+#include "chrome/browser/extensions/external_registry_extension_provider_win.h"
+#endif
+
+using base::Time;
+
+namespace errors = extension_manifest_errors;
+
+namespace {
+
+#if defined(OS_LINUX)
+static const int kOmniboxIconPaddingLeft = 2;
+static const int kOmniboxIconPaddingRight = 2;
+#elif defined(OS_MACOSX)
+static const int kOmniboxIconPaddingLeft = 0;
+static const int kOmniboxIconPaddingRight = 2;
+#else
+static const int kOmniboxIconPaddingLeft = 0;
+static const int kOmniboxIconPaddingRight = 0;
+#endif
+
+// The following enumeration is used in histograms matching
+// Extensions.ManifestReload* . Values may be added, as long
+// as existing values are not changed.
+enum ManifestReloadReason {
+ NOT_NEEDED = 0, // Reload not needed.
+ UNPACKED_DIR, // Unpacked directory
+ NEEDS_RELOCALIZATION, // The local has changed since we read this extension.
+ NUM_MANIFEST_RELOAD_REASONS
+};
+
+ManifestReloadReason ShouldReloadExtensionManifest(const ExtensionInfo& info) {
+ // Always reload manifests of unpacked extensions, because they can change
+ // on disk independent of the manifest in our prefs.
+ if (info.extension_location == Extension::LOAD)
+ return UNPACKED_DIR;
+
+ // Reload the manifest if it needs to be relocalized.
+ if (extension_l10n_util::ShouldRelocalizeManifest(info))
+ return NEEDS_RELOCALIZATION;
+
+ return NOT_NEEDED;
+}
+
+void GetExplicitOriginsInExtent(const Extension* extension,
+ std::vector<GURL>* origins) {
+ typedef std::vector<URLPattern> PatternList;
+ std::set<GURL> set;
+ const PatternList& patterns = extension->web_extent().patterns();
+ for (PatternList::const_iterator pattern = patterns.begin();
+ pattern != patterns.end(); ++pattern) {
+ if (pattern->match_subdomains() || pattern->match_all_urls())
+ continue;
+ // Wildcard URL schemes won't parse into a valid GURL, so explicit schemes
+ // must be used.
+ PatternList explicit_patterns = pattern->ConvertToExplicitSchemes();
+ for (PatternList::const_iterator explicit_p = explicit_patterns.begin();
+ explicit_p != explicit_patterns.end(); ++explicit_p) {
+ GURL origin = GURL(explicit_p->GetAsString()).GetOrigin();
+ if (origin.is_valid()) {
+ set.insert(origin);
+ } else {
+ NOTREACHED();
+ }
+ }
+ }
+
+ for (std::set<GURL>::const_iterator unique = set.begin();
+ unique != set.end(); ++unique) {
+ origins->push_back(*unique);
+ }
+}
+
+} // namespace
+
+PendingExtensionInfo::PendingExtensionInfo(
+ const GURL& update_url,
+ ShouldInstallExtensionPredicate should_install_extension,
+ bool is_from_sync,
+ bool install_silently,
+ bool enable_on_install,
+ bool enable_incognito_on_install,
+ Extension::Location location)
+ : update_url(update_url),
+ should_install_extension(should_install_extension),
+ is_from_sync(is_from_sync),
+ install_silently(install_silently),
+ enable_on_install(enable_on_install),
+ enable_incognito_on_install(enable_incognito_on_install),
+ install_source(location) {}
+
+PendingExtensionInfo::PendingExtensionInfo()
+ : update_url(),
+ should_install_extension(NULL),
+ is_from_sync(true),
+ install_silently(false),
+ enable_on_install(false),
+ enable_incognito_on_install(false),
+ install_source(Extension::INVALID) {}
+
+
+ExtensionService::ExtensionRuntimeData::ExtensionRuntimeData()
+ : background_page_ready(false),
+ being_upgraded(false) {
+}
+
+ExtensionService::ExtensionRuntimeData::~ExtensionRuntimeData() {
+}
+
+// ExtensionService.
+
+const char* ExtensionService::kInstallDirectoryName = "Extensions";
+const char* ExtensionService::kCurrentVersionFileName = "Current Version";
+
+// Implements IO for the ExtensionService.
+
+class ExtensionServiceBackend
+ : public base::RefCountedThreadSafe<ExtensionServiceBackend>,
+ public ExternalExtensionProvider::Visitor {
+ public:
+ // |install_directory| is a path where to look for extensions to load.
+ ExtensionServiceBackend(PrefService* prefs,
+ const FilePath& install_directory);
+
+ // Loads a single extension from |path| where |path| is the top directory of
+ // a specific extension where its manifest file lives.
+ // Errors are reported through ExtensionErrorReporter. On success,
+ // OnExtensionLoaded() is called.
+ // TODO(erikkay): It might be useful to be able to load a packed extension
+ // (presumably into memory) without installing it.
+ void LoadSingleExtension(const FilePath &path,
+ scoped_refptr<ExtensionService> frontend);
+
+ // Check externally updated extensions for updates and install if necessary.
+ // Errors are reported through ExtensionErrorReporter. Succcess is not
+ // reported.
+ void CheckForExternalUpdates(scoped_refptr<ExtensionService> frontend);
+
+ // For the extension in |version_path| with |id|, check to see if it's an
+ // externally managed extension. If so, tell the frontend to uninstall it.
+ void CheckExternalUninstall(scoped_refptr<ExtensionService> frontend,
+ const std::string& id);
+
+ // Clear all ExternalExtensionProviders.
+ void ClearProvidersForTesting();
+
+ // Adds an ExternalExtensionProvider for the service to use during testing.
+ // Takes ownership of |test_provider|.
+ void AddProviderForTesting(ExternalExtensionProvider* test_provider);
+
+ // ExternalExtensionProvider::Visitor implementation.
+ virtual void OnExternalExtensionFileFound(const std::string& id,
+ const Version* version,
+ const FilePath& path,
+ Extension::Location location);
+
+ virtual void OnExternalExtensionUpdateUrlFound(const std::string& id,
+ const GURL& update_url,
+ Extension::Location location);
+
+ virtual void UpdateExternalPolicyExtensionProvider(
+ scoped_refptr<RefCountedList> forcelist);
+
+ private:
+ friend class base::RefCountedThreadSafe<ExtensionServiceBackend>;
+
+ virtual ~ExtensionServiceBackend();
+
+ // Finish installing the extension in |crx_path| after it has been unpacked to
+ // |unpacked_path|. If |expected_id| is not empty, it's verified against the
+ // extension's manifest before installation. If |silent| is true, there will
+ // be no install confirmation dialog. |from_gallery| indicates whether the
+ // crx was installed from our gallery, which results in different UI.
+ //
+ // Note: We take ownership of |extension|.
+ void OnExtensionUnpacked(const FilePath& crx_path,
+ const FilePath& unpacked_path,
+ const Extension* extension,
+ const std::string expected_id);
+
+ // Notify the frontend that there was an error loading an extension.
+ void ReportExtensionLoadError(const FilePath& extension_path,
+ const std::string& error);
+
+ // This is a naked pointer which is set by each entry point.
+ // The entry point is responsible for ensuring lifetime.
+ ExtensionService* frontend_;
+
+ // The top-level extensions directory being installed to.
+ FilePath install_directory_;
+
+ // Whether errors result in noisy alerts.
+ bool alert_on_error_;
+
+ // A collection of external extension providers. Each provider reads
+ // a source of external extension information. Examples include the
+ // windows registry and external_extensions.json.
+ typedef std::vector<linked_ptr<ExternalExtensionProvider> >
+ ProviderCollection;
+ ProviderCollection external_extension_providers_;
+ linked_ptr<ExternalPolicyExtensionProvider>
+ external_policy_extension_provider_;
+
+ // Set to true by OnExternalExtensionUpdateUrlFound() when an external
+ // extension URL is found. Used in CheckForExternalUpdates() to see
+ // if an update check is needed to install pending extensions.
+ bool external_extension_added_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionServiceBackend);
+};
+
+ExtensionServiceBackend::ExtensionServiceBackend(
+ PrefService* prefs,
+ const FilePath& install_directory)
+ : frontend_(NULL),
+ install_directory_(install_directory),
+ alert_on_error_(false),
+ external_extension_added_(false) {
+ // TODO(aa): This ends up doing blocking IO on the UI thread because it reads
+ // pref data in the ctor and that is called on the UI thread. Would be better
+ // to re-read data each time we list external extensions, anyway.
+ external_extension_providers_.push_back(
+ linked_ptr<ExternalExtensionProvider>(
+ new ExternalPrefExtensionProvider()));
+#if defined(OS_WIN)
+ external_extension_providers_.push_back(
+ linked_ptr<ExternalExtensionProvider>(
+ new ExternalRegistryExtensionProvider()));
+#endif
+ // The policy-controlled extension provider is also stored in a member
+ // variable so that UpdateExternalPolicyExtensionProvider can access it and
+ // update its extension list later.
+ external_policy_extension_provider_.reset(
+ new ExternalPolicyExtensionProvider(
+ prefs->GetList(prefs::kExtensionInstallForceList)));
+ external_extension_providers_.push_back(external_policy_extension_provider_);
+}
+
+ExtensionServiceBackend::~ExtensionServiceBackend() {
+}
+
+void ExtensionServiceBackend::LoadSingleExtension(
+ const FilePath& path_in, scoped_refptr<ExtensionService> frontend) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+ frontend_ = frontend;
+
+ // Explicit UI loads are always noisy.
+ alert_on_error_ = true;
+
+ FilePath extension_path = path_in;
+ file_util::AbsolutePath(&extension_path);
+
+ std::string error;
+ scoped_refptr<const Extension> extension(extension_file_util::LoadExtension(
+ extension_path,
+ Extension::LOAD,
+ false, // Don't require id
+ &error));
+
+ if (!extension) {
+ ReportExtensionLoadError(extension_path, error);
+ return;
+ }
+
+ // Report this as an installed extension so that it gets remembered in the
+ // prefs.
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(frontend_,
+ &ExtensionService::OnExtensionInstalled,
+ extension));
+}
+
+void ExtensionServiceBackend::ReportExtensionLoadError(
+ const FilePath& extension_path, const std::string &error) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ frontend_,
+ &ExtensionService::ReportExtensionLoadError, extension_path,
+ error, NotificationType::EXTENSION_INSTALL_ERROR, alert_on_error_));
+}
+
+// Some extensions will autoupdate themselves externally from Chrome. These
+// are typically part of some larger client application package. To support
+// these, the extension will register its location in the the preferences file
+// (and also, on Windows, in the registry) and this code will periodically
+// check that location for a .crx file, which it will then install locally if
+// a new version is available.
+void ExtensionServiceBackend::CheckForExternalUpdates(
+ scoped_refptr<ExtensionService> frontend) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+ // Note that this installation is intentionally silent (since it didn't
+ // go through the front-end). Extensions that are registered in this
+ // way are effectively considered 'pre-bundled', and so implicitly
+ // trusted. In general, if something has HKLM or filesystem access,
+ // they could install an extension manually themselves anyway.
+ alert_on_error_ = false;
+ frontend_ = frontend;
+ external_extension_added_ = false;
+
+ // Ask each external extension provider to give us a call back for each
+ // extension they know about. See OnExternalExtension(File|UpdateUrl)Found.
+ ProviderCollection::const_iterator i;
+ for (i = external_extension_providers_.begin();
+ i != external_extension_providers_.end(); ++i) {
+ ExternalExtensionProvider* provider = i->get();
+ provider->VisitRegisteredExtension(this);
+ }
+
+ if (external_extension_added_ && frontend->updater()) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ frontend->updater(), &ExtensionUpdater::CheckNow));
+ }
+}
+
+void ExtensionServiceBackend::CheckExternalUninstall(
+ scoped_refptr<ExtensionService> frontend, const std::string& id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+ // Check if the providers know about this extension.
+ ProviderCollection::const_iterator i;
+ for (i = external_extension_providers_.begin();
+ i != external_extension_providers_.end(); ++i) {
+ if (i->get()->HasExtension(id))
+ return; // Yup, known extension, don't uninstall.
+ }
+
+ // This is an external extension that we don't have registered. Uninstall.
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ frontend.get(), &ExtensionService::UninstallExtension, id, true));
+}
+
+void ExtensionServiceBackend::UpdateExternalPolicyExtensionProvider(
+ scoped_refptr<RefCountedList> forcelist) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ external_policy_extension_provider_->SetPreferences(forcelist->Get());
+}
+
+void ExtensionServiceBackend::ClearProvidersForTesting() {
+ external_extension_providers_.clear();
+}
+
+void ExtensionServiceBackend::AddProviderForTesting(
+ ExternalExtensionProvider* test_provider) {
+ DCHECK(test_provider);
+ external_extension_providers_.push_back(
+ linked_ptr<ExternalExtensionProvider>(test_provider));
+}
+
+void ExtensionServiceBackend::OnExternalExtensionFileFound(
+ const std::string& id, const Version* version, const FilePath& path,
+ Extension::Location location) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+ DCHECK(version);
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ frontend_, &ExtensionService::OnExternalExtensionFileFound, id,
+ version->GetString(), path, location));
+}
+
+void ExtensionServiceBackend::OnExternalExtensionUpdateUrlFound(
+ const std::string& id,
+ const GURL& update_url,
+ Extension::Location location) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+ if (frontend_->GetExtensionById(id, true)) {
+ // Already installed. Do not change the update URL that the extension set.
+ return;
+ }
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ frontend_,
+ &ExtensionService::AddPendingExtensionFromExternalUpdateUrl,
+ id, update_url, location));
+ external_extension_added_ |= true;
+}
+
+bool ExtensionService::IsDownloadFromGallery(const GURL& download_url,
+ const GURL& referrer_url) {
+ // Special-case the themes mini-gallery.
+ // TODO(erikkay) When that gallery goes away, remove this code.
+ if (IsDownloadFromMiniGallery(download_url) &&
+ StartsWithASCII(referrer_url.spec(),
+ extension_urls::kMiniGalleryBrowsePrefix, false)) {
+ return true;
+ }
+
+ const Extension* download_extension = GetExtensionByWebExtent(download_url);
+ const Extension* referrer_extension = GetExtensionByWebExtent(referrer_url);
+ const Extension* webstore_app = GetWebStoreApp();
+
+ bool referrer_valid = (referrer_extension == webstore_app);
+ bool download_valid = (download_extension == webstore_app);
+
+ // If the command-line gallery URL is set, then be a bit more lenient.
+ GURL store_url =
+ GURL(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kAppsGalleryURL));
+ if (!store_url.is_empty()) {
+ std::string store_tld =
+ net::RegistryControlledDomainService::GetDomainAndRegistry(store_url);
+ if (!referrer_valid) {
+ std::string referrer_tld =
+ net::RegistryControlledDomainService::GetDomainAndRegistry(
+ referrer_url);
+ // The referrer gets stripped when transitioning from https to http,
+ // or when hitting an unknown test cert and that commonly happens in
+ // testing environments. Given this, we allow an empty referrer when
+ // the command-line flag is set.
+ // Otherwise, the TLD must match the TLD of the command-line url.
+ referrer_valid = referrer_url.is_empty() || (referrer_tld == store_tld);
+ }
+
+ if (!download_valid) {
+ std::string download_tld =
+ net::RegistryControlledDomainService::GetDomainAndRegistry(
+ GURL(download_url));
+
+ // Otherwise, the TLD must match the TLD of the command-line url.
+ download_valid = (download_tld == store_tld);
+ }
+ }
+
+ return (referrer_valid && download_valid);
+}
+
+bool ExtensionService::IsDownloadFromMiniGallery(const GURL& download_url) {
+ return StartsWithASCII(download_url.spec(),
+ extension_urls::kMiniGalleryDownloadPrefix,
+ false); // case_sensitive
+}
+
+bool ExtensionService::IsInstalledApp(const GURL& url) {
+ // Check for hosted app.
+ if (GetExtensionByWebExtent(url) != NULL)
+ return true;
+
+ // Check for packaged app.
+ const Extension* extension = GetExtensionByURL(url);
+ return extension != NULL && extension->is_app();
+}
+
+// static
+bool ExtensionService::UninstallExtensionHelper(
+ ExtensionService* extensions_service,
+ const std::string& extension_id) {
+ DCHECK(extensions_service);
+
+ // We can't call UninstallExtension with an invalid extension ID, so check it
+ // first.
+ if (extensions_service->GetExtensionById(extension_id, true)) {
+ extensions_service->UninstallExtension(extension_id, false);
+ } else {
+ LOG(WARNING) << "Attempted uninstallation of non-existent extension with "
+ << "id: " << extension_id;
+ return false;
+ }
+
+ return true;
+}
+
+ExtensionService::ExtensionService(Profile* profile,
+ const CommandLine* command_line,
+ const FilePath& install_directory,
+ ExtensionPrefs* extension_prefs,
+ bool autoupdate_enabled)
+ : profile_(profile),
+ extension_prefs_(extension_prefs),
+ install_directory_(install_directory),
+ extensions_enabled_(true),
+ show_extensions_prompts_(true),
+ ready_(false),
+ ALLOW_THIS_IN_INITIALIZER_LIST(toolbar_model_(this)),
+ default_apps_(profile->GetPrefs()),
+ event_routers_initialized_(false) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // Figure out if extension installation should be enabled.
+ if (command_line->HasSwitch(switches::kDisableExtensions)) {
+ extensions_enabled_ = false;
+ } else if (profile->GetPrefs()->GetBoolean(prefs::kDisableExtensions)) {
+ extensions_enabled_ = false;
+ }
+
+ registrar_.Add(this, NotificationType::EXTENSION_PROCESS_TERMINATED,
+ NotificationService::AllSources());
+ pref_change_registrar_.Init(profile->GetPrefs());
+ pref_change_registrar_.Add(prefs::kExtensionInstallAllowList, this);
+ pref_change_registrar_.Add(prefs::kExtensionInstallDenyList, this);
+ pref_change_registrar_.Add(prefs::kExtensionInstallForceList, this);
+
+ // Set up the ExtensionUpdater
+ if (autoupdate_enabled) {
+ int update_frequency = kDefaultUpdateFrequencySeconds;
+ if (command_line->HasSwitch(switches::kExtensionsUpdateFrequency)) {
+ base::StringToInt(command_line->GetSwitchValueASCII(
+ switches::kExtensionsUpdateFrequency),
+ &update_frequency);
+ }
+ updater_ = new ExtensionUpdater(this,
+ profile->GetPrefs(),
+ update_frequency);
+ }
+
+ backend_ = new ExtensionServiceBackend(profile->GetPrefs(),
+ install_directory_);
+
+ // Use monochrome icons for Omnibox icons.
+ omnibox_popup_icon_manager_.set_monochrome(true);
+ omnibox_icon_manager_.set_monochrome(true);
+ omnibox_icon_manager_.set_padding(gfx::Insets(0, kOmniboxIconPaddingLeft,
+ 0, kOmniboxIconPaddingRight));
+}
+
+const ExtensionList* ExtensionService::extensions() const {
+ return &extensions_;
+}
+
+const ExtensionList* ExtensionService::disabled_extensions() const {
+ return &disabled_extensions_;
+}
+
+const PendingExtensionMap& ExtensionService::pending_extensions() const {
+ return pending_extensions_;
+}
+
+bool ExtensionService::HasInstalledExtensions() {
+ return !(extensions_.empty() && disabled_extensions_.empty());
+}
+
+ExtensionService::~ExtensionService() {
+ DCHECK(!profile_); // Profile should have told us it's going away.
+ UnloadAllExtensions();
+ if (updater_.get()) {
+ updater_->Stop();
+ }
+}
+
+void ExtensionService::InitEventRouters() {
+ if (event_routers_initialized_)
+ return;
+
+ ExtensionHistoryEventRouter::GetInstance()->ObserveProfile(profile_);
+ ExtensionAccessibilityEventRouter::GetInstance()->ObserveProfile(profile_);
+ ExtensionBrowserEventRouter::GetInstance()->Init(profile_);
+ ExtensionBookmarkEventRouter::GetInstance()->Observe(
+ profile_->GetBookmarkModel());
+ ExtensionCookiesEventRouter::GetInstance()->Init();
+ ExtensionManagementEventRouter::GetInstance()->Init();
+ ExtensionProcessesEventRouter::GetInstance()->ObserveProfile(profile_);
+ ExtensionWebNavigationEventRouter::GetInstance()->Init();
+ event_routers_initialized_ = true;
+}
+
+const Extension* ExtensionService::GetExtensionById(const std::string& id,
+ bool include_disabled) {
+ return GetExtensionByIdInternal(id, true, include_disabled);
+}
+
+void ExtensionService::Init() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ DCHECK(!ready_); // Can't redo init.
+ DCHECK_EQ(extensions_.size(), 0u);
+
+ // Hack: we need to ensure the ResourceDispatcherHost is ready before we load
+ // the first extension, because its members listen for loaded notifications.
+ g_browser_process->resource_dispatcher_host();
+
+ LoadAllExtensions();
+
+ // TODO(erikkay) this should probably be deferred to a future point
+ // rather than running immediately at startup.
+ CheckForExternalUpdates();
+
+ // TODO(erikkay) this should probably be deferred as well.
+ GarbageCollectExtensions();
+}
+
+void ExtensionService::InstallExtension(const FilePath& extension_path) {
+ scoped_refptr<CrxInstaller> installer(
+ new CrxInstaller(this, // frontend
+ NULL)); // no client (silent install)
+ installer->InstallCrx(extension_path);
+}
+
+namespace {
+ // TODO(akalin): Put this somewhere where both crx_installer.cc and
+ // this file can use it.
+ void DeleteFileHelper(const FilePath& path, bool recursive) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ file_util::Delete(path, recursive);
+ }
+} // namespace
+
+void ExtensionService::UpdateExtension(const std::string& id,
+ const FilePath& extension_path,
+ const GURL& download_url) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ PendingExtensionMap::const_iterator it = pending_extensions_.find(id);
+ bool is_pending_extension = (it != pending_extensions_.end());
+
+ const Extension* extension = GetExtensionByIdInternal(id, true, true);
+ if (!is_pending_extension && !extension) {
+ LOG(WARNING) << "Will not update extension " << id
+ << " because it is not installed or pending";
+ // Delete extension_path since we're not creating a CrxInstaller
+ // that would do it for us.
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableFunction(&DeleteFileHelper, extension_path, false));
+ return;
+ }
+
+ // We want a silent install only for non-pending extensions and
+ // pending extensions that have install_silently set.
+ ExtensionInstallUI* client =
+ (!is_pending_extension || it->second.install_silently) ?
+ NULL : new ExtensionInstallUI(profile_);
+
+ scoped_refptr<CrxInstaller> installer(
+ new CrxInstaller(this, // frontend
+ client));
+ installer->set_expected_id(id);
+ if (is_pending_extension)
+ installer->set_install_source(it->second.install_source);
+ else if (extension)
+ installer->set_install_source(extension->location());
+ installer->set_delete_source(true);
+ installer->set_original_url(download_url);
+ installer->InstallCrx(extension_path);
+}
+
+void ExtensionService::AddPendingExtensionFromSync(
+ const std::string& id, const GURL& update_url,
+ ShouldInstallExtensionPredicate should_install_extension,
+ bool install_silently, bool enable_on_install,
+ bool enable_incognito_on_install) {
+ if (GetExtensionByIdInternal(id, true, true)) {
+ LOG(DFATAL) << "Trying to add pending extension " << id
+ << " which already exists";
+ return;
+ }
+
+ AddPendingExtensionInternal(id, update_url, should_install_extension, true,
+ install_silently, enable_on_install,
+ enable_incognito_on_install,
+ Extension::INTERNAL);
+}
+
+namespace {
+
+bool AlwaysInstall(const Extension& extension) {
+ return true;
+}
+
+} // namespace
+
+void ExtensionService::AddPendingExtensionFromExternalUpdateUrl(
+ const std::string& id, const GURL& update_url,
+ Extension::Location location) {
+ const bool kIsFromSync = false;
+ const bool kInstallSilently = true;
+ const bool kEnableOnInstall = true;
+ const bool kEnableIncognitoOnInstall = false;
+ if (extension_prefs_->IsExtensionKilled(id))
+ return;
+
+ if (GetExtensionByIdInternal(id, true, true)) {
+ LOG(DFATAL) << "Trying to add extension " << id
+ << " by external update, but it is already installed.";
+ return;
+ }
+
+ AddPendingExtensionInternal(id, update_url, &AlwaysInstall,
+ kIsFromSync, kInstallSilently,
+ kEnableOnInstall, kEnableIncognitoOnInstall,
+ location);
+}
+
+namespace {
+
+bool IsApp(const Extension& extension) {
+ return extension.is_app();
+}
+
+} // namespace
+
+// TODO(akalin): Change DefaultAppList to DefaultExtensionList and
+// remove the IsApp() check.
+
+void ExtensionService::AddPendingExtensionFromDefaultAppList(
+ const std::string& id) {
+ const bool kIsFromSync = false;
+ const bool kInstallSilently = true;
+ const bool kEnableOnInstall = true;
+ const bool kEnableIncognitoOnInstall = true;
+
+ // This can legitimately happen if the user manually installed one of the
+ // default apps before this code ran.
+ if (GetExtensionByIdInternal(id, true, true))
+ return;
+
+ AddPendingExtensionInternal(id, GURL(), &IsApp,
+ kIsFromSync, kInstallSilently,
+ kEnableOnInstall, kEnableIncognitoOnInstall,
+ Extension::INTERNAL);
+}
+
+void ExtensionService::AddPendingExtensionInternal(
+ const std::string& id, const GURL& update_url,
+ ShouldInstallExtensionPredicate should_install_extension,
+ bool is_from_sync, bool install_silently,
+ bool enable_on_install, bool enable_incognito_on_install,
+ Extension::Location install_source) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // If a non-sync update is pending, a sync request should not
+ // overwrite it. This is important for external extensions.
+ // If an external extension download is pending, and the user has
+ // the extension in their sync profile, the install should set the
+ // type to be external. An external extension should not be
+ // rejected if it fails the safty checks for a syncable extension.
+ // TODO(skerner): Work out other potential overlapping conditions.
+ // (crbug.com/61000)
+ PendingExtensionMap::iterator it = pending_extensions_.find(id);
+ if (it != pending_extensions_.end()) {
+ VLOG(1) << "Extension id " << id
+ << " was entered for update more than once."
+ << " old is_from_sync = " << it->second.is_from_sync
+ << " new is_from_sync = " << is_from_sync;
+ if (!it->second.is_from_sync && is_from_sync)
+ return;
+ }
+
+ pending_extensions_[id] =
+ PendingExtensionInfo(update_url, should_install_extension,
+ is_from_sync, install_silently, enable_on_install,
+ enable_incognito_on_install, install_source);
+}
+
+void ExtensionService::ReloadExtension(const std::string& extension_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ FilePath path;
+ const Extension* current_extension = GetExtensionById(extension_id, false);
+
+ // Disable the extension if it's loaded. It might not be loaded if it crashed.
+ if (current_extension) {
+ // If the extension has an inspector open for its background page, detach
+ // the inspector and hang onto a cookie for it, so that we can reattach
+ // later.
+ ExtensionProcessManager* manager = profile_->GetExtensionProcessManager();
+ ExtensionHost* host = manager->GetBackgroundHostForExtension(
+ current_extension);
+ if (host) {
+ // Look for an open inspector for the background page.
+ int devtools_cookie = DevToolsManager::GetInstance()->DetachClientHost(
+ host->render_view_host());
+ if (devtools_cookie >= 0)
+ orphaned_dev_tools_[extension_id] = devtools_cookie;
+ }
+
+ path = current_extension->path();
+ DisableExtension(extension_id);
+ disabled_extension_paths_[extension_id] = path;
+ } else {
+ path = unloaded_extension_paths_[extension_id];
+ }
+
+ // Check the installed extensions to see if what we're reloading was already
+ // installed.
+ scoped_ptr<ExtensionInfo> installed_extension(
+ extension_prefs_->GetInstalledExtensionInfo(extension_id));
+ if (installed_extension.get() &&
+ installed_extension->extension_manifest.get()) {
+ LoadInstalledExtension(*installed_extension, false);
+ } else {
+ // We should always be able to remember the extension's path. If it's not in
+ // the map, someone failed to update |unloaded_extension_paths_|.
+ CHECK(!path.empty());
+ LoadExtension(path);
+ }
+}
+
+void ExtensionService::UninstallExtension(const std::string& extension_id,
+ bool external_uninstall) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ const Extension* extension =
+ GetExtensionByIdInternal(extension_id, true, true);
+
+ // Callers should not send us nonexistent extensions.
+ CHECK(extension);
+
+ // Get hold of information we need after unloading, since the extension
+ // pointer will be invalid then.
+ GURL extension_url(extension->url());
+ Extension::Location location(extension->location());
+ UninstalledExtensionInfo uninstalled_extension_info(*extension);
+
+ UMA_HISTOGRAM_ENUMERATION("Extensions.UninstallType",
+ extension->GetType(), 100);
+
+ // Also copy the extension identifier since the reference might have been
+ // obtained via Extension::id().
+ std::string extension_id_copy(extension_id);
+
+ if (profile_->GetTemplateURLModel())
+ profile_->GetTemplateURLModel()->UnregisterExtensionKeyword(extension);
+
+ // Unload before doing more cleanup to ensure that nothing is hanging on to
+ // any of these resources.
+ UnloadExtension(extension_id, UnloadedExtensionInfo::UNINSTALL);
+
+ extension_prefs_->OnExtensionUninstalled(extension_id_copy, location,
+ external_uninstall);
+
+ // Tell the backend to start deleting installed extensions on the file thread.
+ if (Extension::LOAD != location) {
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableFunction(
+ &extension_file_util::UninstallExtension,
+ install_directory_,
+ extension_id_copy));
+ }
+
+ ClearExtensionData(extension_url);
+
+ // Notify interested parties that we've uninstalled this extension.
+ NotificationService::current()->Notify(
+ NotificationType::EXTENSION_UNINSTALLED,
+ Source<Profile>(profile_),
+ Details<UninstalledExtensionInfo>(&uninstalled_extension_info));
+}
+
+void ExtensionService::ClearExtensionData(const GURL& extension_url) {
+ scoped_refptr<ExtensionDataDeleter> deleter(
+ new ExtensionDataDeleter(profile_, extension_url));
+ deleter->StartDeleting();
+}
+
+void ExtensionService::EnableExtension(const std::string& extension_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ const Extension* extension =
+ GetExtensionByIdInternal(extension_id, false, true);
+ if (!extension)
+ return;
+
+ extension_prefs_->SetExtensionState(extension, Extension::ENABLED);
+
+ // Move it over to the enabled list.
+ extensions_.push_back(make_scoped_refptr(extension));
+ ExtensionList::iterator iter = std::find(disabled_extensions_.begin(),
+ disabled_extensions_.end(),
+ extension);
+ disabled_extensions_.erase(iter);
+
+ // Make sure any browser action contained within it is not hidden.
+ extension_prefs_->SetBrowserActionVisibility(extension, true);
+
+ ExtensionDOMUI::RegisterChromeURLOverrides(profile_,
+ extension->GetChromeURLOverrides());
+
+ NotifyExtensionLoaded(extension);
+ UpdateActiveExtensionsInCrashReporter();
+}
+
+void ExtensionService::DisableExtension(const std::string& extension_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ const Extension* extension =
+ GetExtensionByIdInternal(extension_id, true, false);
+ // The extension may have been disabled already.
+ if (!extension)
+ return;
+
+ extension_prefs_->SetExtensionState(extension, Extension::DISABLED);
+
+ // Move it over to the disabled list.
+ disabled_extensions_.push_back(make_scoped_refptr(extension));
+ ExtensionList::iterator iter = std::find(extensions_.begin(),
+ extensions_.end(),
+ extension);
+ extensions_.erase(iter);
+
+ ExtensionDOMUI::UnregisterChromeURLOverrides(profile_,
+ extension->GetChromeURLOverrides());
+
+ NotifyExtensionUnloaded(extension, UnloadedExtensionInfo::DISABLE);
+ UpdateActiveExtensionsInCrashReporter();
+}
+
+void ExtensionService::GrantPermissions(const Extension* extension) {
+ CHECK(extension);
+
+ // We only maintain the granted permissions prefs for INTERNAL extensions.
+ CHECK(extension->location() == Extension::INTERNAL);
+
+ ExtensionExtent effective_hosts = extension->GetEffectiveHostPermissions();
+ extension_prefs_->AddGrantedPermissions(extension->id(),
+ extension->HasFullPermissions(),
+ extension->api_permissions(),
+ effective_hosts);
+}
+
+void ExtensionService::GrantPermissionsAndEnableExtension(
+ const Extension* extension) {
+ CHECK(extension);
+ GrantPermissions(extension);
+ extension_prefs_->SetDidExtensionEscalatePermissions(extension, false);
+ EnableExtension(extension->id());
+}
+
+void ExtensionService::LoadExtension(const FilePath& extension_path) {
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(
+ backend_.get(),
+ &ExtensionServiceBackend::LoadSingleExtension,
+ extension_path, scoped_refptr<ExtensionService>(this)));
+}
+
+void ExtensionService::LoadComponentExtensions() {
+ for (RegisteredComponentExtensions::iterator it =
+ component_extension_manifests_.begin();
+ it != component_extension_manifests_.end(); ++it) {
+ JSONStringValueSerializer serializer(it->manifest);
+ scoped_ptr<Value> manifest(serializer.Deserialize(NULL, NULL));
+ if (!manifest.get()) {
+ DLOG(ERROR) << "Failed to parse manifest for extension";
+ continue;
+ }
+
+ std::string error;
+ scoped_refptr<const Extension> extension(Extension::Create(
+ it->root_directory,
+ Extension::COMPONENT,
+ *static_cast<DictionaryValue*>(manifest.get()),
+ true, // require key
+ &error));
+ if (!extension.get()) {
+ NOTREACHED() << error;
+ return;
+ }
+
+ OnExtensionLoaded(extension);
+ }
+}
+
+void ExtensionService::LoadAllExtensions() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ base::TimeTicks start_time = base::TimeTicks::Now();
+
+ // Load any component extensions.
+ LoadComponentExtensions();
+
+ // Load the previously installed extensions.
+ scoped_ptr<ExtensionPrefs::ExtensionsInfo> extensions_info(
+ extension_prefs_->GetInstalledExtensionsInfo());
+
+ std::vector<int> reload_reason_counts(NUM_MANIFEST_RELOAD_REASONS, 0);
+ bool should_write_prefs = false;
+
+ for (size_t i = 0; i < extensions_info->size(); ++i) {
+ ExtensionInfo* info = extensions_info->at(i).get();
+
+ ManifestReloadReason reload_reason = ShouldReloadExtensionManifest(*info);
+ ++reload_reason_counts[reload_reason];
+ UMA_HISTOGRAM_ENUMERATION("Extensions.ManifestReloadEnumValue",
+ reload_reason, 100);
+
+ if (reload_reason != NOT_NEEDED) {
+ // Reloading and extension reads files from disk. We do this on the
+ // UI thread because reloads should be very rare, and the complexity
+ // added by delaying the time when the extensions service knows about
+ // all extensions is significant. See crbug.com/37548 for details.
+ // |allow_io| disables tests that file operations run on the file
+ // thread.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+ std::string error;
+ scoped_refptr<const Extension> extension(
+ extension_file_util::LoadExtension(
+ info->extension_path, info->extension_location, false, &error));
+
+ if (extension.get()) {
+ extensions_info->at(i)->extension_manifest.reset(
+ static_cast<DictionaryValue*>(
+ extension->manifest_value()->DeepCopy()));
+ should_write_prefs = true;
+ }
+ }
+ }
+
+ for (size_t i = 0; i < extensions_info->size(); ++i) {
+ LoadInstalledExtension(*extensions_info->at(i), should_write_prefs);
+ }
+
+ OnLoadedInstalledExtensions();
+
+ // The histograms Extensions.ManifestReload* allow us to validate
+ // the assumption that reloading manifest is a rare event.
+ UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNotNeeded",
+ reload_reason_counts[NOT_NEEDED]);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadUnpackedDir",
+ reload_reason_counts[UNPACKED_DIR]);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNeedsRelocalization",
+ reload_reason_counts[NEEDS_RELOCALIZATION]);
+
+ UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAll", extensions_.size());
+ UMA_HISTOGRAM_COUNTS_100("Extensions.Disabled", disabled_extensions_.size());
+
+ UMA_HISTOGRAM_TIMES("Extensions.LoadAllTime",
+ base::TimeTicks::Now() - start_time);
+
+ int app_count = 0;
+ int hosted_app_count = 0;
+ int packaged_app_count = 0;
+ int user_script_count = 0;
+ int extension_count = 0;
+ int theme_count = 0;
+ int external_count = 0;
+ int page_action_count = 0;
+ int browser_action_count = 0;
+ ExtensionList::iterator ex;
+ for (ex = extensions_.begin(); ex != extensions_.end(); ++ex) {
+ Extension::Location location = (*ex)->location();
+ Extension::Type type = (*ex)->GetType();
+ if ((*ex)->is_app()) {
+ UMA_HISTOGRAM_ENUMERATION("Extensions.AppLocation",
+ location, 100);
+ } else if (type == Extension::TYPE_EXTENSION) {
+ UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionLocation",
+ location, 100);
+ }
+
+ // Don't count component extensions, since they are only extensions as an
+ // implementation detail.
+ if (location == Extension::COMPONENT)
+ continue;
+
+ // Don't count unpacked extensions, since they're a developer-specific
+ // feature.
+ if (location == Extension::LOAD)
+ continue;
+
+ // Using an enumeration shows us the total installed ratio across all users.
+ // Using the totals per user at each startup tells us the distribution of
+ // usage for each user (e.g. 40% of users have at least one app installed).
+ UMA_HISTOGRAM_ENUMERATION("Extensions.LoadType", type, 100);
+ switch (type) {
+ case Extension::TYPE_THEME:
+ ++theme_count;
+ break;
+ case Extension::TYPE_USER_SCRIPT:
+ ++user_script_count;
+ break;
+ case Extension::TYPE_HOSTED_APP:
+ ++app_count;
+ ++hosted_app_count;
+ break;
+ case Extension::TYPE_PACKAGED_APP:
+ ++app_count;
+ ++packaged_app_count;
+ break;
+ case Extension::TYPE_EXTENSION:
+ default:
+ ++extension_count;
+ break;
+ }
+ if (Extension::IsExternalLocation(location))
+ ++external_count;
+ if ((*ex)->page_action() != NULL)
+ ++page_action_count;
+ if ((*ex)->browser_action() != NULL)
+ ++browser_action_count;
+ }
+ UMA_HISTOGRAM_COUNTS_100("Extensions.LoadApp", app_count);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.LoadHostedApp", hosted_app_count);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPackagedApp", packaged_app_count);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtension", extension_count);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.LoadUserScript", user_script_count);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.LoadTheme", theme_count);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExternal", external_count);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPageAction", page_action_count);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.LoadBrowserAction",
+ browser_action_count);
+}
+
+void ExtensionService::LoadInstalledExtension(const ExtensionInfo& info,
+ bool write_to_prefs) {
+ std::string error;
+ scoped_refptr<const Extension> extension(NULL);
+ if (!extension_prefs_->IsExtensionAllowedByPolicy(info.extension_id)) {
+ error = errors::kDisabledByPolicy;
+ } else if (info.extension_manifest.get()) {
+ bool require_key = info.extension_location != Extension::LOAD;
+ extension = Extension::Create(
+ info.extension_path, info.extension_location, *info.extension_manifest,
+ require_key, &error);
+ } else {
+ error = errors::kManifestUnreadable;
+ }
+
+ if (!extension) {
+ ReportExtensionLoadError(info.extension_path,
+ error,
+ NotificationType::EXTENSION_INSTALL_ERROR,
+ false);
+ return;
+ }
+
+ if (write_to_prefs)
+ extension_prefs_->UpdateManifest(extension);
+
+ OnExtensionLoaded(extension);
+
+ if (Extension::IsExternalLocation(info.extension_location)) {
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(
+ backend_.get(),
+ &ExtensionServiceBackend::CheckExternalUninstall,
+ scoped_refptr<ExtensionService>(this),
+ info.extension_id));
+ }
+}
+
+void ExtensionService::NotifyExtensionLoaded(const Extension* extension) {
+ // The ChromeURLRequestContexts 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.
+ if (profile_) {
+ profile_->RegisterExtensionWithRequestContexts(extension);
+
+ // Check if this permission requires unlimited storage quota
+ if (extension->HasApiPermission(Extension::kUnlimitedStoragePermission))
+ GrantUnlimitedStorage(extension);
+
+ // If the extension is an app, protect its local storage from
+ // "Clear browsing data."
+ if (extension->is_app())
+ GrantProtectedStorage(extension);
+ }
+
+ NotificationService::current()->Notify(
+ NotificationType::EXTENSION_LOADED,
+ Source<Profile>(profile_),
+ Details<const Extension>(extension));
+}
+
+void ExtensionService::NotifyExtensionUnloaded(
+ const Extension* extension, UnloadedExtensionInfo::Reason reason) {
+ UnloadedExtensionInfo details(extension, reason);
+ NotificationService::current()->Notify(
+ NotificationType::EXTENSION_UNLOADED,
+ Source<Profile>(profile_),
+ Details<UnloadedExtensionInfo>(&details));
+
+ if (profile_) {
+ profile_->UnregisterExtensionWithRequestContexts(extension);
+
+ // Check if this permission required unlimited storage quota, reset its
+ // in-memory quota.
+ if (extension->HasApiPermission(Extension::kUnlimitedStoragePermission))
+ RevokeUnlimitedStorage(extension);
+
+ // If this is an app, then stop protecting its storage so it can be deleted.
+ if (extension->is_app())
+ RevokeProtectedStorage(extension);
+ }
+}
+
+void ExtensionService::GrantProtectedStorage(const Extension* extension) {
+ DCHECK(extension->is_app()) << "Only Apps are allowed protected storage.";
+ std::vector<GURL> origins;
+ GetExplicitOriginsInExtent(extension, &origins);
+ for (size_t i = 0; i < origins.size(); ++i)
+ ++protected_storage_map_[origins[i]];
+}
+
+void ExtensionService::RevokeProtectedStorage(const Extension* extension) {
+ DCHECK(extension->is_app()) << "Attempting to revoke protected storage from "
+ << " a non-app extension.";
+ std::vector<GURL> origins;
+ GetExplicitOriginsInExtent(extension, &origins);
+ for (size_t i = 0; i < origins.size(); ++i) {
+ const GURL& origin = origins[i];
+ DCHECK(protected_storage_map_[origin] > 0);
+ if (--protected_storage_map_[origin] <= 0)
+ protected_storage_map_.erase(origin);
+ }
+}
+
+void ExtensionService::GrantUnlimitedStorage(const Extension* extension) {
+ DCHECK(extension->HasApiPermission(Extension::kUnlimitedStoragePermission));
+ std::vector<GURL> origins;
+ GetExplicitOriginsInExtent(extension, &origins);
+ origins.push_back(extension->url());
+
+ for (size_t i = 0; i < origins.size(); ++i) {
+ const GURL& origin = origins[i];
+ if (++unlimited_storage_map_[origin] == 1) {
+ string16 origin_identifier =
+ webkit_database::DatabaseUtil::GetOriginIdentifier(origin);
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(
+ profile_->GetDatabaseTracker(),
+ &webkit_database::DatabaseTracker::SetOriginQuotaInMemory,
+ origin_identifier,
+ kint64max));
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(
+ profile_->GetAppCacheService(),
+ &ChromeAppCacheService::SetOriginQuotaInMemory,
+ origin,
+ kint64max));
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(
+ profile_->GetFileSystemContext(),
+ &fileapi::SandboxedFileSystemContext::SetOriginQuotaUnlimited,
+ origin));
+ }
+ }
+}
+
+void ExtensionService::RevokeUnlimitedStorage(const Extension* extension) {
+ DCHECK(extension->HasApiPermission(Extension::kUnlimitedStoragePermission));
+ std::vector<GURL> origins;
+ GetExplicitOriginsInExtent(extension, &origins);
+ origins.push_back(extension->url());
+
+ for (size_t i = 0; i < origins.size(); ++i) {
+ const GURL& origin = origins[i];
+ DCHECK(unlimited_storage_map_[origin] > 0);
+ if (--unlimited_storage_map_[origin] == 0) {
+ unlimited_storage_map_.erase(origin);
+ string16 origin_identifier =
+ webkit_database::DatabaseUtil::GetOriginIdentifier(origin);
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(
+ profile_->GetDatabaseTracker(),
+ &webkit_database::DatabaseTracker::ResetOriginQuotaInMemory,
+ origin_identifier));
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(
+ profile_->GetAppCacheService(),
+ &ChromeAppCacheService::ResetOriginQuotaInMemory,
+ origin));
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(
+ profile_->GetFileSystemContext(),
+ &fileapi::SandboxedFileSystemContext::ResetOriginQuotaUnlimited,
+ origin));
+ }
+ }
+}
+
+void ExtensionService::UpdateExtensionBlacklist(
+ const std::vector<std::string>& blacklist) {
+ // Use this set to indicate if an extension in the blacklist has been used.
+ std::set<std::string> blacklist_set;
+ for (unsigned int i = 0; i < blacklist.size(); ++i) {
+ if (Extension::IdIsValid(blacklist[i])) {
+ blacklist_set.insert(blacklist[i]);
+ }
+ }
+ extension_prefs_->UpdateBlacklist(blacklist_set);
+ std::vector<std::string> to_be_removed;
+ // Loop current extensions, unload installed extensions.
+ for (ExtensionList::const_iterator iter = extensions_.begin();
+ iter != extensions_.end(); ++iter) {
+ const Extension* extension = (*iter);
+ if (blacklist_set.find(extension->id()) != blacklist_set.end()) {
+ to_be_removed.push_back(extension->id());
+ }
+ }
+
+ // UnloadExtension will change the extensions_ list. So, we should
+ // call it outside the iterator loop.
+ for (unsigned int i = 0; i < to_be_removed.size(); ++i) {
+ UnloadExtension(to_be_removed[i], UnloadedExtensionInfo::DISABLE);
+ }
+}
+
+void ExtensionService::DestroyingProfile() {
+ pref_change_registrar_.RemoveAll();
+ profile_ = NULL;
+ toolbar_model_.DestroyingProfile();
+}
+
+ExtensionPrefs* ExtensionService::extension_prefs() {
+ return extension_prefs_;
+}
+
+void ExtensionService::CheckAdminBlacklist() {
+ std::vector<std::string> to_be_removed;
+ // Loop through extensions list, unload installed extensions.
+ for (ExtensionList::const_iterator iter = extensions_.begin();
+ iter != extensions_.end(); ++iter) {
+ const Extension* extension = (*iter);
+ if (!extension_prefs_->IsExtensionAllowedByPolicy(extension->id()))
+ to_be_removed.push_back(extension->id());
+ }
+
+ // UnloadExtension will change the extensions_ list. So, we should
+ // call it outside the iterator loop.
+ for (unsigned int i = 0; i < to_be_removed.size(); ++i)
+ UnloadExtension(to_be_removed[i], UnloadedExtensionInfo::DISABLE);
+}
+
+bool ExtensionService::IsIncognitoEnabled(const Extension* extension) {
+ // If this is a component extension we always allow it to work in incognito
+ // mode.
+ if (extension->location() == Extension::COMPONENT)
+ return true;
+
+ // Check the prefs.
+ return extension_prefs_->IsIncognitoEnabled(extension->id());
+}
+
+void ExtensionService::SetIsIncognitoEnabled(const Extension* extension,
+ bool enabled) {
+ extension_prefs_->SetIsIncognitoEnabled(extension->id(), enabled);
+
+ // Broadcast unloaded and loaded events to update browser state. Only bother
+ // if the extension is actually enabled, since there is no UI otherwise.
+ bool is_enabled = std::find(extensions_.begin(), extensions_.end(),
+ extension) != extensions_.end();
+ if (is_enabled) {
+ NotifyExtensionUnloaded(extension, UnloadedExtensionInfo::DISABLE);
+ NotifyExtensionLoaded(extension);
+ }
+}
+
+bool ExtensionService::CanCrossIncognito(const Extension* extension) {
+ // We allow the extension to see events and data from another profile iff it
+ // uses "spanning" behavior and it has incognito access. "split" mode
+ // extensions only see events for a matching profile.
+ return IsIncognitoEnabled(extension) && !extension->incognito_split_mode();
+}
+
+bool ExtensionService::AllowFileAccess(const Extension* extension) {
+ return (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableExtensionsFileAccessCheck) ||
+ extension_prefs_->AllowFileAccess(extension->id()));
+}
+
+void ExtensionService::SetAllowFileAccess(const Extension* extension,
+ bool allow) {
+ extension_prefs_->SetAllowFileAccess(extension->id(), allow);
+ NotificationService::current()->Notify(
+ NotificationType::EXTENSION_USER_SCRIPTS_UPDATED,
+ Source<Profile>(profile_),
+ Details<const Extension>(extension));
+}
+
+bool ExtensionService::GetBrowserActionVisibility(const Extension* extension) {
+ return extension_prefs_->GetBrowserActionVisibility(extension);
+}
+
+void ExtensionService::SetBrowserActionVisibility(const Extension* extension,
+ bool visible) {
+ extension_prefs_->SetBrowserActionVisibility(extension, visible);
+}
+
+void ExtensionService::CheckForExternalUpdates() {
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(
+ backend_.get(), &ExtensionServiceBackend::CheckForExternalUpdates,
+ scoped_refptr<ExtensionService>(this)));
+}
+
+void ExtensionService::UpdateExternalPolicyExtensionProvider() {
+ const ListValue* list_pref =
+ profile_->GetPrefs()->GetList(prefs::kExtensionInstallForceList);
+ ListValue* list_copy = NULL;
+ if (list_pref)
+ list_copy = static_cast<ListValue*>(list_pref->DeepCopy());
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(
+ backend_.get(),
+ &ExtensionServiceBackend::UpdateExternalPolicyExtensionProvider,
+ scoped_refptr<RefCountedList>(
+ new RefCountedList(list_copy))));
+}
+
+void ExtensionService::UnloadExtension(
+ const std::string& extension_id,
+ UnloadedExtensionInfo::Reason reason) {
+ // Make sure the extension gets deleted after we return from this function.
+ scoped_refptr<const Extension> extension(
+ GetExtensionByIdInternal(extension_id, true, true));
+
+ // This method can be called via PostTask, so the extension may have been
+ // unloaded by the time this runs.
+ if (!extension)
+ return;
+
+ // Keep information about the extension so that we can reload it later
+ // even if it's not permanently installed.
+ unloaded_extension_paths_[extension->id()] = extension->path();
+
+ // Clean up if the extension is meant to be enabled after a reload.
+ disabled_extension_paths_.erase(extension->id());
+
+ // Clean up runtime data.
+ extension_runtime_data_.erase(extension_id);
+
+ ExtensionDOMUI::UnregisterChromeURLOverrides(profile_,
+ extension->GetChromeURLOverrides());
+
+ ExtensionList::iterator iter = std::find(disabled_extensions_.begin(),
+ disabled_extensions_.end(),
+ extension.get());
+ if (iter != disabled_extensions_.end()) {
+ UnloadedExtensionInfo details(extension, reason);
+ details.already_disabled = true;
+ disabled_extensions_.erase(iter);
+ NotificationService::current()->Notify(
+ NotificationType::EXTENSION_UNLOADED,
+ Source<Profile>(profile_),
+ Details<UnloadedExtensionInfo>(&details));
+ return;
+ }
+
+ iter = std::find(extensions_.begin(), extensions_.end(), extension.get());
+
+ // Remove the extension from our list.
+ extensions_.erase(iter);
+
+ NotifyExtensionUnloaded(extension.get(), reason);
+ UpdateActiveExtensionsInCrashReporter();
+}
+
+void ExtensionService::UnloadAllExtensions() {
+ extensions_.clear();
+ disabled_extensions_.clear();
+ extension_runtime_data_.clear();
+
+ // TODO(erikkay) should there be a notification for this? We can't use
+ // EXTENSION_UNLOADED since that implies that the extension has been disabled
+ // or uninstalled, and UnloadAll is just part of shutdown.
+}
+
+void ExtensionService::ReloadExtensions() {
+ UnloadAllExtensions();
+ LoadAllExtensions();
+}
+
+void ExtensionService::GarbageCollectExtensions() {
+ if (extension_prefs_->pref_service()->ReadOnly())
+ return;
+
+ scoped_ptr<ExtensionPrefs::ExtensionsInfo> info(
+ extension_prefs_->GetInstalledExtensionsInfo());
+
+ std::map<std::string, FilePath> extension_paths;
+ for (size_t i = 0; i < info->size(); ++i)
+ extension_paths[info->at(i)->extension_id] = info->at(i)->extension_path;
+
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableFunction(
+ &extension_file_util::GarbageCollectExtensions, install_directory_,
+ extension_paths));
+
+ // Also garbage-collect themes. We check |profile_| to be
+ // defensive; in the future, we may call GarbageCollectExtensions()
+ // from somewhere other than Init() (e.g., in a timer).
+ if (profile_) {
+ profile_->GetThemeProvider()->RemoveUnusedThemes();
+ }
+}
+
+void ExtensionService::OnLoadedInstalledExtensions() {
+ if (updater_.get()) {
+ updater_->Start();
+ }
+
+ ready_ = true;
+ NotificationService::current()->Notify(
+ NotificationType::EXTENSIONS_READY,
+ Source<Profile>(profile_),
+ NotificationService::NoDetails());
+}
+
+void ExtensionService::OnExtensionLoaded(const Extension* extension) {
+ // Ensure extension is deleted unless we transfer ownership.
+ scoped_refptr<const Extension> scoped_extension(extension);
+
+ // The extension is now loaded, remove its data from unloaded extension map.
+ unloaded_extension_paths_.erase(extension->id());
+
+ // If the extension was disabled for a reload, then enable it.
+ if (disabled_extension_paths_.erase(extension->id()) > 0)
+ EnableExtension(extension->id());
+
+ // TODO(jstritar): We may be able to get rid of this branch by overriding the
+ // default extension state to DISABLED when the --disable-extensions flag
+ // is set (http://crbug.com/29067).
+ if (!extensions_enabled() &&
+ !extension->is_theme() &&
+ extension->location() != Extension::COMPONENT &&
+ !Extension::IsExternalLocation(extension->location()))
+ return;
+
+ // Check if the extension's privileges have changed and disable the
+ // extension if necessary.
+ DisableIfPrivilegeIncrease(extension);
+
+ switch (extension_prefs_->GetExtensionState(extension->id())) {
+ case Extension::ENABLED:
+ extensions_.push_back(scoped_extension);
+
+ NotifyExtensionLoaded(extension);
+
+ ExtensionDOMUI::RegisterChromeURLOverrides(
+ profile_, extension->GetChromeURLOverrides());
+ break;
+ case Extension::DISABLED:
+ disabled_extensions_.push_back(scoped_extension);
+ NotificationService::current()->Notify(
+ NotificationType::EXTENSION_UPDATE_DISABLED,
+ Source<Profile>(profile_),
+ Details<const Extension>(extension));
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+
+ SetBeingUpgraded(extension, false);
+
+ UpdateActiveExtensionsInCrashReporter();
+
+ if (profile_->GetTemplateURLModel())
+ profile_->GetTemplateURLModel()->RegisterExtensionKeyword(extension);
+
+ // Load the icon for omnibox-enabled extensions so it will be ready to display
+ // in the URL bar.
+ if (!extension->omnibox_keyword().empty()) {
+ omnibox_popup_icon_manager_.LoadIcon(extension);
+ omnibox_icon_manager_.LoadIcon(extension);
+ }
+}
+
+void ExtensionService::DisableIfPrivilegeIncrease(const Extension* extension) {
+ // We keep track of all permissions the user has granted each extension.
+ // This allows extensions to gracefully support backwards compatibility
+ // by including unknown permissions in their manifests. When the user
+ // installs the extension, only the recognized permissions are recorded.
+ // When the unknown permissions become recognized (e.g., through browser
+ // upgrade), we can prompt the user to accept these new permissions.
+ // Extensions can also silently upgrade to less permissions, and then
+ // silently upgrade to a version that adds these permissions back.
+ //
+ // For example, pretend that Chrome 10 includes a permission "omnibox"
+ // for an API that adds suggestions to the omnibox. An extension can
+ // maintain backwards compatibility while still having "omnibox" in the
+ // manifest. If a user installs the extension on Chrome 9, the browser
+ // will record the permissions it recognized, not including "omnibox."
+ // When upgrading to Chrome 10, "omnibox" will be recognized and Chrome
+ // will disable the extension and prompt the user to approve the increase
+ // in privileges. The extension could then release a new version that
+ // removes the "omnibox" permission. When the user upgrades, Chrome will
+ // still remember that "omnibox" had been granted, so that if the
+ // extension once again includes "omnibox" in an upgrade, the extension
+ // can upgrade without requiring this user's approval.
+ const Extension* old = GetExtensionByIdInternal(extension->id(),
+ true, true);
+ bool granted_full_access;
+ std::set<std::string> granted_apis;
+ ExtensionExtent granted_extent;
+
+ bool is_extension_upgrade = old != NULL;
+ bool is_privilege_increase = false;
+
+ // We only record the granted permissions for INTERNAL extensions, since
+ // they can't silently increase privileges.
+ if (extension->location() == Extension::INTERNAL) {
+ // Add all the recognized permissions if the granted permissions list
+ // hasn't been initialized yet.
+ if (!extension_prefs_->GetGrantedPermissions(extension->id(),
+ &granted_full_access,
+ &granted_apis,
+ &granted_extent)) {
+ GrantPermissions(extension);
+ CHECK(extension_prefs_->GetGrantedPermissions(extension->id(),
+ &granted_full_access,
+ &granted_apis,
+ &granted_extent));
+ }
+
+ // Here, we check if an extension's privileges have increased in a manner
+ // that requires the user's approval. This could occur because the browser
+ // upgraded and recognized additional privileges, or an extension upgrades
+ // to a version that requires additional privileges.
+ is_privilege_increase = Extension::IsPrivilegeIncrease(
+ granted_full_access, granted_apis, granted_extent, extension);
+ }
+
+ if (is_extension_upgrade) {
+ // Other than for unpacked extensions, CrxInstaller should have guaranteed
+ // that we aren't downgrading.
+ if (extension->location() != Extension::LOAD)
+ CHECK(extension->version()->CompareTo(*(old->version())) >= 0);
+
+ // Extensions get upgraded if the privileges are allowed to increase or
+ // the privileges haven't increased.
+ if (!is_privilege_increase) {
+ SetBeingUpgraded(old, true);
+ SetBeingUpgraded(extension, true);
+ }
+
+ // To upgrade an extension in place, unload the old one and
+ // then load the new one.
+ UnloadExtension(old->id(), UnloadedExtensionInfo::UPDATE);
+ old = NULL;
+ }
+
+ // Extension has changed permissions significantly. Disable it. A
+ // notification should be sent by the caller.
+ if (is_privilege_increase) {
+ extension_prefs_->SetExtensionState(extension, Extension::DISABLED);
+ extension_prefs_->SetDidExtensionEscalatePermissions(extension, true);
+ }
+}
+
+void ExtensionService::UpdateActiveExtensionsInCrashReporter() {
+ std::set<std::string> extension_ids;
+ for (size_t i = 0; i < extensions_.size(); ++i) {
+ if (!extensions_[i]->is_theme() &&
+ extensions_[i]->location() != Extension::COMPONENT)
+ extension_ids.insert(extensions_[i]->id());
+ }
+
+ child_process_logging::SetActiveExtensions(extension_ids);
+}
+
+void ExtensionService::OnExtensionInstalled(const Extension* extension) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // Ensure extension is deleted unless we transfer ownership.
+ scoped_refptr<const Extension> scoped_extension(extension);
+ Extension::State initial_state = Extension::DISABLED;
+ bool initial_enable_incognito = false;
+ PendingExtensionMap::iterator it =
+ pending_extensions_.find(extension->id());
+ if (it != pending_extensions_.end()) {
+ PendingExtensionInfo pending_extension_info = it->second;
+ pending_extensions_.erase(it);
+ it = pending_extensions_.end();
+
+ if (!pending_extension_info.should_install_extension(*extension)) {
+ LOG(WARNING)
+ << "should_install_extension ("
+ << pending_extension_info.should_install_extension
+ << ") returned false for " << extension->id()
+ << " of type " << extension->GetType()
+ << " and update URL " << extension->update_url().spec()
+ << "; not installing";
+ // Delete the extension directory since we're not going to
+ // load it.
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableFunction(&DeleteFileHelper, extension->path(), true));
+ return;
+ }
+
+ if (extension->is_theme()) {
+ DCHECK(pending_extension_info.enable_on_install);
+ initial_state = Extension::ENABLED;
+ DCHECK(!pending_extension_info.enable_incognito_on_install);
+ initial_enable_incognito = false;
+ } else {
+ initial_state =
+ pending_extension_info.enable_on_install ?
+ Extension::ENABLED : Extension::DISABLED;
+ initial_enable_incognito =
+ pending_extension_info.enable_incognito_on_install;
+ }
+ } else {
+ // Make sure we preserve enabled/disabled states.
+ Extension::State existing_state =
+ extension_prefs_->GetExtensionState(extension->id());
+ initial_state =
+ (existing_state == Extension::DISABLED) ?
+ Extension::DISABLED : Extension::ENABLED;
+ initial_enable_incognito =
+ extension_prefs_->IsIncognitoEnabled(extension->id());
+ }
+
+ UMA_HISTOGRAM_ENUMERATION("Extensions.InstallType",
+ extension->GetType(), 100);
+ ShownSectionsHandler::OnExtensionInstalled(profile_->GetPrefs(), extension);
+ extension_prefs_->OnExtensionInstalled(
+ extension, initial_state, initial_enable_incognito);
+
+ // Unpacked extensions start off with file access since they are a developer
+ // feature.
+ if (extension->location() == Extension::LOAD)
+ extension_prefs_->SetAllowFileAccess(extension->id(), true);
+
+ // If the extension is a theme, tell the profile (and therefore ThemeProvider)
+ // to apply it.
+ if (extension->is_theme()) {
+ NotificationService::current()->Notify(
+ NotificationType::THEME_INSTALLED,
+ Source<Profile>(profile_),
+ Details<const Extension>(extension));
+ } else {
+ NotificationService::current()->Notify(
+ NotificationType::EXTENSION_INSTALLED,
+ Source<Profile>(profile_),
+ Details<const Extension>(extension));
+ }
+
+ if (extension->is_app()) {
+ ExtensionIdSet installed_ids = GetAppIds();
+ installed_ids.insert(extension->id());
+ default_apps_.DidInstallApp(installed_ids);
+ }
+
+ // Transfer ownership of |extension| to OnExtensionLoaded.
+ OnExtensionLoaded(scoped_extension);
+}
+
+const Extension* ExtensionService::GetExtensionByIdInternal(
+ const std::string& id, bool include_enabled, bool include_disabled) {
+ std::string lowercase_id = StringToLowerASCII(id);
+ if (include_enabled) {
+ for (ExtensionList::const_iterator iter = extensions_.begin();
+ iter != extensions_.end(); ++iter) {
+ if ((*iter)->id() == lowercase_id)
+ return *iter;
+ }
+ }
+ if (include_disabled) {
+ for (ExtensionList::const_iterator iter = disabled_extensions_.begin();
+ iter != disabled_extensions_.end(); ++iter) {
+ if ((*iter)->id() == lowercase_id)
+ return *iter;
+ }
+ }
+ return NULL;
+}
+
+const Extension* ExtensionService::GetWebStoreApp() {
+ return GetExtensionById(extension_misc::kWebStoreAppId, false);
+}
+
+const Extension* ExtensionService::GetExtensionByURL(const GURL& url) {
+ return url.scheme() != chrome::kExtensionScheme ? NULL :
+ GetExtensionById(url.host(), false);
+}
+
+const Extension* ExtensionService::GetExtensionByWebExtent(const GURL& url) {
+ for (size_t i = 0; i < extensions_.size(); ++i) {
+ if (extensions_[i]->web_extent().ContainsURL(url))
+ return extensions_[i];
+ }
+ return NULL;
+}
+
+bool ExtensionService::ExtensionBindingsAllowed(const GURL& url) {
+ // Allow bindings for all packaged extension.
+ if (GetExtensionByURL(url))
+ return true;
+
+ // Allow bindings for all component, hosted apps.
+ const Extension* extension = GetExtensionByWebExtent(url);
+ return (extension && extension->location() == Extension::COMPONENT);
+}
+
+const Extension* ExtensionService::GetExtensionByOverlappingWebExtent(
+ const ExtensionExtent& extent) {
+ for (size_t i = 0; i < extensions_.size(); ++i) {
+ if (extensions_[i]->web_extent().OverlapsWith(extent))
+ return extensions_[i];
+ }
+
+ return NULL;
+}
+
+const SkBitmap& ExtensionService::GetOmniboxIcon(
+ const std::string& extension_id) {
+ return omnibox_icon_manager_.GetIcon(extension_id);
+}
+
+const SkBitmap& ExtensionService::GetOmniboxPopupIcon(
+ const std::string& extension_id) {
+ return omnibox_popup_icon_manager_.GetIcon(extension_id);
+}
+
+void ExtensionService::ClearProvidersForTesting() {
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(
+ backend_.get(), &ExtensionServiceBackend::ClearProvidersForTesting));
+}
+
+void ExtensionService::AddProviderForTesting(
+ ExternalExtensionProvider* test_provider) {
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(
+ backend_.get(), &ExtensionServiceBackend::AddProviderForTesting,
+ test_provider));
+}
+
+void ExtensionService::OnExternalExtensionFileFound(
+ const std::string& id,
+ const std::string& version,
+ const FilePath& path,
+ Extension::Location location) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (extension_prefs_->IsExtensionKilled(id))
+ return;
+
+ // Before even bothering to unpack, check and see if we already have this
+ // version. This is important because these extensions are going to get
+ // installed on every startup.
+ const Extension* existing = GetExtensionById(id, true);
+ scoped_ptr<Version> other(Version::GetVersionFromString(version));
+ if (existing) {
+ switch (existing->version()->CompareTo(*other)) {
+ case -1: // existing version is older, we should upgrade
+ break;
+ case 0: // existing version is same, do nothing
+ return;
+ case 1: // existing version is newer, uh-oh
+ LOG(WARNING) << "Found external version of extension " << id
+ << "that is older than current version. Current version "
+ << "is: " << existing->VersionString() << ". New version "
+ << "is: " << version << ". Keeping current version.";
+ return;
+ }
+ }
+
+ GURL update_url = GURL();
+ bool is_from_sync = false;
+ bool install_silently = true;
+ bool enable_on_install = true;
+ bool enable_incognito_on_install = false;
+ pending_extensions_[id] = PendingExtensionInfo(
+ update_url,
+ &AlwaysInstall,
+ is_from_sync,
+ install_silently,
+ enable_on_install,
+ enable_incognito_on_install,
+ location);
+
+ scoped_refptr<CrxInstaller> installer(
+ new CrxInstaller(this, // frontend
+ NULL)); // no client (silent install)
+ installer->set_install_source(location);
+ installer->set_expected_id(id);
+ installer->InstallCrx(path);
+}
+
+void ExtensionService::ReportExtensionLoadError(
+ const FilePath& extension_path,
+ const std::string &error,
+ NotificationType type,
+ bool be_noisy) {
+ NotificationService* service = NotificationService::current();
+ service->Notify(type,
+ Source<Profile>(profile_),
+ Details<const std::string>(&error));
+
+ // TODO(port): note that this isn't guaranteed to work properly on Linux.
+ std::string path_str = WideToUTF8(extension_path.ToWStringHack());
+ std::string message = base::StringPrintf(
+ "Could not load extension from '%s'. %s",
+ path_str.c_str(), error.c_str());
+ ExtensionErrorReporter::GetInstance()->ReportError(message, be_noisy);
+}
+
+void ExtensionService::DidCreateRenderViewForBackgroundPage(
+ ExtensionHost* host) {
+ OrphanedDevTools::iterator iter =
+ orphaned_dev_tools_.find(host->extension()->id());
+ if (iter == orphaned_dev_tools_.end())
+ return;
+
+ DevToolsManager::GetInstance()->AttachClientHost(
+ iter->second, host->render_view_host());
+ orphaned_dev_tools_.erase(iter);
+}
+
+void ExtensionService::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ switch (type.value) {
+ case NotificationType::EXTENSION_PROCESS_TERMINATED: {
+ if (profile_ != Source<Profile>(source).ptr()->GetOriginalProfile())
+ break;
+
+ ExtensionHost* host = Details<ExtensionHost>(details).ptr();
+
+ // Unload the entire extension. We want it to be in a consistent state:
+ // either fully working or not loaded at all, but never half-crashed.
+ // We do it in a PostTask so that other handlers of this notification will
+ // still have access to the Extension and ExtensionHost.
+ MessageLoop::current()->PostTask(FROM_HERE,
+ NewRunnableMethod(this,
+ &ExtensionService::UnloadExtension,
+ host->extension()->id(),
+ UnloadedExtensionInfo::DISABLE));
+ break;
+ }
+
+ case NotificationType::PREF_CHANGED: {
+ std::string* pref_name = Details<std::string>(details).ptr();
+ if (*pref_name == prefs::kExtensionInstallAllowList ||
+ *pref_name == prefs::kExtensionInstallDenyList) {
+ CheckAdminBlacklist();
+ } else if (*pref_name == prefs::kExtensionInstallForceList) {
+ UpdateExternalPolicyExtensionProvider();
+ CheckForExternalUpdates();
+ // TODO(gfeher): Also check for external extensions that can be
+ // uninstalled because they were removed from the pref.
+ // (crbug.com/63667)
+ } else {
+ NOTREACHED() << "Unexpected preference name.";
+ }
+ break;
+ }
+
+ default:
+ NOTREACHED() << "Unexpected notification type.";
+ }
+}
+
+bool ExtensionService::HasApps() const {
+ return !GetAppIds().empty();
+}
+
+ExtensionIdSet ExtensionService::GetAppIds() const {
+ ExtensionIdSet result;
+ for (ExtensionList::const_iterator it = extensions_.begin();
+ it != extensions_.end(); ++it) {
+ if ((*it)->is_app() && (*it)->location() != Extension::COMPONENT)
+ result.insert((*it)->id());
+ }
+
+ return result;
+}
+
+bool ExtensionService::IsBackgroundPageReady(const Extension* extension) {
+ return (extension->background_url().is_empty() ||
+ extension_runtime_data_[extension->id()].background_page_ready);
+}
+
+void ExtensionService::SetBackgroundPageReady(const Extension* extension) {
+ DCHECK(!extension->background_url().is_empty());
+ extension_runtime_data_[extension->id()].background_page_ready = true;
+ NotificationService::current()->Notify(
+ NotificationType::EXTENSION_BACKGROUND_PAGE_READY,
+ Source<const Extension>(extension),
+ NotificationService::NoDetails());
+}
+
+bool ExtensionService::IsBeingUpgraded(const Extension* extension) {
+ return extension_runtime_data_[extension->id()].being_upgraded;
+}
+
+void ExtensionService::SetBeingUpgraded(const Extension* extension,
+ bool value) {
+ extension_runtime_data_[extension->id()].being_upgraded = value;
+}
+
+PropertyBag* ExtensionService::GetPropertyBag(const Extension* extension) {
+ return &extension_runtime_data_[extension->id()].property_bag;
+}
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
new file mode 100644
index 0000000..9e4206c
--- /dev/null
+++ b/chrome/browser/extensions/extension_service.h
@@ -0,0 +1,601 @@
+// 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.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_SERVICE_H_
+#define CHROME_BROWSER_EXTENSIONS_EXTENSION_SERVICE_H_
+#pragma once
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/file_path.h"
+#include "base/gtest_prod_util.h"
+#include "base/linked_ptr.h"
+#include "base/ref_counted.h"
+#include "base/task.h"
+#include "base/time.h"
+#include "base/tuple.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/extensions/default_apps.h"
+#include "chrome/browser/extensions/extension_icon_manager.h"
+#include "chrome/browser/extensions/extension_menu_manager.h"
+#include "chrome/browser/extensions/extension_prefs.h"
+#include "chrome/browser/extensions/extension_process_manager.h"
+#include "chrome/browser/extensions/extension_toolbar_model.h"
+#include "chrome/browser/extensions/extensions_quota_service.h"
+#include "chrome/browser/extensions/external_extension_provider.h"
+#include "chrome/browser/extensions/sandboxed_extension_unpacker.h"
+#include "chrome/browser/prefs/pref_change_registrar.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/property_bag.h"
+
+class ExtensionServiceBackend;
+class ExtensionToolbarModel;
+class ExtensionUpdater;
+class GURL;
+class Profile;
+class Version;
+
+typedef bool (*ShouldInstallExtensionPredicate)(const Extension&);
+
+// A pending extension is an extension that hasn't been installed yet
+// and is intended to be installed in the next auto-update cycle. The
+// update URL of a pending extension may be blank, in which case a
+// default one is assumed.
+struct PendingExtensionInfo {
+ PendingExtensionInfo(
+ const GURL& update_url,
+ ShouldInstallExtensionPredicate should_install_extension,
+ bool is_from_sync,
+ bool install_silently,
+ bool enable_on_install,
+ bool enable_incognito_on_install,
+ Extension::Location install_source);
+
+ PendingExtensionInfo();
+
+ GURL update_url;
+ // When the extension is about to be installed, this function is
+ // called. If this function returns true, the install proceeds. If
+ // this function returns false, the install is aborted.
+ ShouldInstallExtensionPredicate should_install_extension;
+ bool is_from_sync; // This update check was initiated from sync.
+ bool install_silently;
+ bool enable_on_install;
+ bool enable_incognito_on_install;
+ Extension::Location install_source;
+};
+
+// A PendingExtensionMap is a map from IDs of pending extensions to
+// their info.
+typedef std::map<std::string, PendingExtensionInfo> PendingExtensionMap;
+
+// This is an interface class to encapsulate the dependencies that
+// ExtensionUpdater has on ExtensionService. This allows easy mocking.
+class ExtensionUpdateService {
+ public:
+ virtual ~ExtensionUpdateService() {}
+ virtual const ExtensionList* extensions() const = 0;
+ virtual const PendingExtensionMap& pending_extensions() const = 0;
+ virtual void UpdateExtension(const std::string& id, const FilePath& path,
+ const GURL& download_url) = 0;
+ virtual const Extension* GetExtensionById(const std::string& id,
+ bool include_disabled) = 0;
+ virtual void UpdateExtensionBlacklist(
+ const std::vector<std::string>& blacklist) = 0;
+ virtual void CheckAdminBlacklist() = 0;
+ virtual bool HasInstalledExtensions() = 0;
+
+ virtual ExtensionPrefs* extension_prefs() = 0;
+};
+
+// Manages installed and running Chromium extensions.
+class ExtensionService
+ : public base::RefCountedThreadSafe<ExtensionService,
+ BrowserThread::DeleteOnUIThread>,
+ public ExtensionUpdateService,
+ public NotificationObserver {
+ public:
+ // Information about a registered component extension.
+ struct ComponentExtensionInfo {
+ ComponentExtensionInfo(const std::string& manifest,
+ const FilePath& root_directory)
+ : manifest(manifest),
+ root_directory(root_directory) {
+ }
+
+ // The extension's manifest. This is required for component extensions so
+ // that ExtensionService doesn't need to go to disk to load them.
+ std::string manifest;
+
+ // Directory where the extension is stored.
+ FilePath root_directory;
+ };
+
+ // The name of the directory inside the profile where extensions are
+ // installed to.
+ static const char* kInstallDirectoryName;
+
+ // If auto-updates are turned on, default to running every 5 hours.
+ static const int kDefaultUpdateFrequencySeconds = 60 * 60 * 5;
+
+ // The name of the file that the current active version number is stored in.
+ static const char* kCurrentVersionFileName;
+
+ // Determine if a given extension download should be treated as if it came
+ // from the gallery. Note that this is requires *both* that the download_url
+ // match and that the download was referred from a gallery page.
+ bool IsDownloadFromGallery(const GURL& download_url,
+ const GURL& referrer_url);
+
+ // Determine if the downloaded extension came from the theme mini-gallery,
+ // Used to test if we need to show the "Loading" dialog for themes.
+ static bool IsDownloadFromMiniGallery(const GURL& download_url);
+
+ // Returns whether the URL is from either a hosted or packaged app.
+ bool IsInstalledApp(const GURL& url);
+
+ // Attempts to uninstall an extension from a given ExtensionService. Returns
+ // true iff the target extension exists.
+ static bool UninstallExtensionHelper(ExtensionService* extensions_service,
+ const std::string& extension_id);
+
+ // Constructor stores pointers to |profile| and |extension_prefs| but
+ // ownership remains at caller.
+ ExtensionService(Profile* profile,
+ const CommandLine* command_line,
+ const FilePath& install_directory,
+ ExtensionPrefs* extension_prefs,
+ bool autoupdate_enabled);
+
+ // Gets the list of currently installed extensions.
+ virtual const ExtensionList* extensions() const;
+ virtual const ExtensionList* disabled_extensions() const;
+
+ // Gets the set of pending extensions.
+ virtual const PendingExtensionMap& pending_extensions() const;
+
+ // Registers an extension to be loaded as a component extension.
+ void register_component_extension(const ComponentExtensionInfo& info) {
+ component_extension_manifests_.push_back(info);
+ }
+
+ // Returns true if any extensions are installed.
+ virtual bool HasInstalledExtensions();
+
+ const FilePath& install_directory() const { return install_directory_; }
+
+ DefaultApps* default_apps() { return &default_apps_; }
+
+ // Whether this extension can run in an incognito window.
+ bool IsIncognitoEnabled(const Extension* extension);
+ void SetIsIncognitoEnabled(const Extension* extension, bool enabled);
+
+ // Returns true if the given extension can see events and data from another
+ // sub-profile (incognito to original profile, or vice versa).
+ bool CanCrossIncognito(const Extension* extension);
+
+ // Whether this extension can inject scripts into pages with file URLs.
+ bool AllowFileAccess(const Extension* extension);
+ void SetAllowFileAccess(const Extension* extension, bool allow);
+
+ // Getter and setter for the Browser Action visibility in the toolbar.
+ bool GetBrowserActionVisibility(const Extension* extension);
+ void SetBrowserActionVisibility(const Extension* extension, bool visible);
+
+ // Whether the background page, if any, is ready. We don't load other
+ // components until then. If there is no background page, we consider it to
+ // be ready.
+ bool IsBackgroundPageReady(const Extension* extension);
+ void SetBackgroundPageReady(const Extension* extension);
+
+ // Getter and setter for the flag that specifies whether the extension is
+ // being upgraded.
+ bool IsBeingUpgraded(const Extension* extension);
+ void SetBeingUpgraded(const Extension* extension, bool value);
+
+ // Getter for the extension's runtime data PropertyBag.
+ PropertyBag* GetPropertyBag(const Extension* extension);
+
+ // Initialize and start all installed extensions.
+ void Init();
+
+ // Start up the extension event routers.
+ void InitEventRouters();
+
+ // Look up an extension by ID.
+ virtual const Extension* GetExtensionById(const std::string& id,
+ bool include_disabled);
+
+ // Install the extension file at |extension_path|. Will install as an
+ // update if an older version is already installed.
+ // For fresh installs, this method also causes the extension to be
+ // immediately loaded.
+ // TODO(aa): This method can be removed. It is only used by the unit tests,
+ // and they could use CrxInstaller directly instead.
+ void InstallExtension(const FilePath& extension_path);
+
+ // Updates a currently-installed extension with the contents from
+ // |extension_path|.
+ // TODO(aa): This method can be removed. ExtensionUpdater could use
+ // CrxInstaller directly instead.
+ virtual void UpdateExtension(const std::string& id,
+ const FilePath& extension_path,
+ const GURL& download_url);
+
+ // Adds an extension in a pending state; the extension with the
+ // given info will be installed on the next auto-update cycle.
+ //
+ // It is an error to call this with an already-installed extension
+ // (even a disabled one).
+ //
+ // TODO(akalin): Replace |install_silently| with a list of
+ // pre-enabled permissions.
+ void AddPendingExtensionFromSync(
+ const std::string& id, const GURL& update_url,
+ ShouldInstallExtensionPredicate should_install_extension,
+ bool install_silently, bool enable_on_install,
+ bool enable_incognito_on_install);
+
+ // Given an extension id and an update URL, schedule the extension
+ // to be fetched, installed, and activated.
+ void AddPendingExtensionFromExternalUpdateUrl(const std::string& id,
+ const GURL& update_url,
+ Extension::Location location);
+
+ // Like the above. Always installed silently, and defaults update url
+ // from extension id.
+ void AddPendingExtensionFromDefaultAppList(const std::string& id);
+
+ // Reloads the specified extension.
+ void ReloadExtension(const std::string& extension_id);
+
+ // Uninstalls the specified extension. Callers should only call this method
+ // with extensions that exist. |external_uninstall| is a magical parameter
+ // that is only used to send information to ExtensionPrefs, which external
+ // callers should never set to true.
+ // TODO(aa): Remove |external_uninstall| -- this information should be passed
+ // to ExtensionPrefs some other way.
+ void UninstallExtension(const std::string& extension_id,
+ bool external_uninstall);
+
+ // Enable or disable an extension. No action if the extension is already
+ // enabled/disabled.
+ void EnableExtension(const std::string& extension_id);
+ void DisableExtension(const std::string& extension_id);
+
+ // Updates the |extension|'s granted permissions lists to include all
+ // permissions in the |extension|'s manifest.
+ void GrantPermissions(const Extension* extension);
+
+ // Updates the |extension|'s granted permissions lists to include all
+ // permissions in the |extension|'s manifest and re-enables the
+ // extension.
+ void GrantPermissionsAndEnableExtension(const Extension* extension);
+
+ // Load the extension from the directory |extension_path|.
+ void LoadExtension(const FilePath& extension_path);
+
+ // Load any component extensions.
+ void LoadComponentExtensions();
+
+ // Load all known extensions (used by startup and testing code).
+ void LoadAllExtensions();
+
+ // Continues loading all know extensions. It can be called from
+ // LoadAllExtensions or from file thread if we had to relocalize manifest
+ // (write_to_prefs is true in that case).
+ void ContinueLoadAllExtensions(ExtensionPrefs::ExtensionsInfo* info,
+ base::TimeTicks start_time,
+ bool write_to_prefs);
+
+ // Check for updates (or potentially new extensions from external providers)
+ void CheckForExternalUpdates();
+
+ // Copies the list of force-installed extensions from the user PrefService
+ // to ExternalPolicyExtensionProvider.
+ void UpdateExternalPolicyExtensionProvider();
+
+ // Unload the specified extension.
+ void UnloadExtension(const std::string& extension_id,
+ UnloadedExtensionInfo::Reason reason);
+
+ // Unload all extensions. This is currently only called on shutdown, and
+ // does not send notifications.
+ void UnloadAllExtensions();
+
+ // Called only by testing.
+ void ReloadExtensions();
+
+ // Scan the extension directory and clean up the cruft.
+ void GarbageCollectExtensions();
+
+ // The App that represents the web store.
+ const Extension* GetWebStoreApp();
+
+ // Lookup an extension by |url|.
+ const Extension* GetExtensionByURL(const GURL& url);
+
+ // If there is an extension for the specified url it is returned. Otherwise
+ // returns the extension whose web extent contains |url|.
+ const Extension* GetExtensionByWebExtent(const GURL& url);
+
+ // Returns an extension that contains any URL that overlaps with the given
+ // extent, if one exists.
+ const Extension* GetExtensionByOverlappingWebExtent(
+ const ExtensionExtent& extent);
+
+ // Returns true if |url| should get extension api bindings and be permitted
+ // to make api calls. Note that this is independent of what extension
+ // permissions the given extension has been granted.
+ bool ExtensionBindingsAllowed(const GURL& url);
+
+ // Returns the icon to display in the omnibox for the given extension.
+ const SkBitmap& GetOmniboxIcon(const std::string& extension_id);
+
+ // Returns the icon to display in the omnibox popup window for the given
+ // extension.
+ const SkBitmap& GetOmniboxPopupIcon(const std::string& extension_id);
+
+ // Clear all ExternalExtensionProviders.
+ void ClearProvidersForTesting();
+
+ // Sets an ExternalExtensionProvider for the service to use during testing.
+ // Takes ownership of |test_provider|.
+ void AddProviderForTesting(ExternalExtensionProvider* test_provider);
+
+ // Called when the initial extensions load has completed.
+ virtual void OnLoadedInstalledExtensions();
+
+ // Called when an extension has been loaded.
+ void OnExtensionLoaded(const Extension* extension);
+
+ // Called by the backend when an extension has been installed.
+ void OnExtensionInstalled(const Extension* extension);
+
+ // Called by the backend when an external extension is found.
+ void OnExternalExtensionFileFound(const std::string& id,
+ const std::string& version,
+ const FilePath& path,
+ Extension::Location location);
+
+ // Checks if the privileges requested by |extension| have increased, and if
+ // so, disables the extension and prompts the user to approve the change.
+ void DisableIfPrivilegeIncrease(const Extension* extension);
+
+ // Go through each extensions in pref, unload blacklisted extensions
+ // and update the blacklist state in pref.
+ virtual void UpdateExtensionBlacklist(
+ const std::vector<std::string>& blacklist);
+
+ // Go through each extension and unload those that the network admin has
+ // put on the blacklist (not to be confused with the Google managed blacklist
+ // set of extensions.
+ virtual void CheckAdminBlacklist();
+
+ void set_extensions_enabled(bool enabled) { extensions_enabled_ = enabled; }
+ bool extensions_enabled() { return extensions_enabled_; }
+
+ void set_show_extensions_prompts(bool enabled) {
+ show_extensions_prompts_ = enabled;
+ }
+
+ bool show_extensions_prompts() {
+ return show_extensions_prompts_;
+ }
+
+ Profile* profile() { return profile_; }
+
+ // Profile calls this when it is being destroyed so that we know not to call
+ // it.
+ void DestroyingProfile();
+
+ virtual ExtensionPrefs* extension_prefs();
+
+ // Whether the extension service is ready.
+ // TODO(skerner): Get rid of this method. crbug.com/63756
+ bool is_ready() { return ready_; }
+
+ // Note that this may return NULL if autoupdate is not turned on.
+ ExtensionUpdater* updater() { return updater_.get(); }
+
+ ExtensionToolbarModel* toolbar_model() { return &toolbar_model_; }
+
+ ExtensionsQuotaService* quota_service() { return &quota_service_; }
+
+ ExtensionMenuManager* menu_manager() { return &menu_manager_; }
+
+ const std::map<GURL, int>& protected_storage_map() const {
+ return protected_storage_map_;
+ }
+
+ // Notify the frontend that there was an error loading an extension.
+ // This method is public because ExtensionServiceBackend can post to here.
+ void ReportExtensionLoadError(const FilePath& extension_path,
+ const std::string& error,
+ NotificationType type,
+ bool be_noisy);
+
+ // ExtensionHost of background page calls this method right after its render
+ // view has been created.
+ void DidCreateRenderViewForBackgroundPage(ExtensionHost* host);
+
+ // NotificationObserver
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // Whether there are any apps installed. Component apps are not included.
+ bool HasApps() const;
+
+ // Gets the set of loaded app ids. Component apps are not included.
+ ExtensionIdSet GetAppIds() const;
+
+ private:
+ friend class BrowserThread;
+ friend class DeleteTask<ExtensionService>;
+
+ // Contains Extension data that can change during the life of the process,
+ // but does not persist across restarts.
+ struct ExtensionRuntimeData {
+ // True if the background page is ready.
+ bool background_page_ready;
+
+ // True while the extension is being upgraded.
+ bool being_upgraded;
+
+ // Generic bag of runtime data that users can associate with extensions.
+ PropertyBag property_bag;
+
+ ExtensionRuntimeData();
+ ~ExtensionRuntimeData();
+ };
+ typedef std::map<std::string, ExtensionRuntimeData> ExtensionRuntimeDataMap;
+
+ virtual ~ExtensionService();
+
+ // Clear all persistent data that may have been stored by the extension.
+ void ClearExtensionData(const GURL& extension_url);
+
+ // Look up an extension by ID, optionally including either or both of enabled
+ // and disabled extensions.
+ const Extension* GetExtensionByIdInternal(const std::string& id,
+ bool include_enabled,
+ bool include_disabled);
+
+ // Like AddPendingExtension*() functions above, but assumes an
+ // extension with the same id is not already installed.
+ void AddPendingExtensionInternal(
+ const std::string& id, const GURL& update_url,
+ ShouldInstallExtensionPredicate should_install_extension,
+ bool is_from_sync, bool install_silently,
+ bool enable_on_install, bool enable_incognito_on_install,
+ Extension::Location install_source);
+
+ // Handles sending notification that |extension| was loaded.
+ void NotifyExtensionLoaded(const Extension* extension);
+
+ // Handles sending notification that |extension| was unloaded.
+ void NotifyExtensionUnloaded(const Extension* extension,
+ UnloadedExtensionInfo::Reason reason);
+
+ // Helper that updates the active extension list used for crash reporting.
+ void UpdateActiveExtensionsInCrashReporter();
+
+ // Helper method. Loads extension from prefs.
+ void LoadInstalledExtension(const ExtensionInfo& info, bool write_to_prefs);
+
+ // Helper methods to configure the storage services accordingly.
+ void GrantProtectedStorage(const Extension* extension);
+ void RevokeProtectedStorage(const Extension* extension);
+ void GrantUnlimitedStorage(const Extension* extension);
+ void RevokeUnlimitedStorage(const Extension* extension);
+
+ // The profile this ExtensionService is part of.
+ Profile* profile_;
+
+ // Preferences for the owning profile (weak reference).
+ ExtensionPrefs* extension_prefs_;
+
+ // The current list of installed extensions.
+ ExtensionList extensions_;
+
+ // The list of installed extensions that have been disabled.
+ ExtensionList disabled_extensions_;
+
+ // The set of pending extensions.
+ PendingExtensionMap pending_extensions_;
+
+ // The map of extension IDs to their runtime data.
+ ExtensionRuntimeDataMap extension_runtime_data_;
+
+ // The full path to the directory where extensions are installed.
+ FilePath install_directory_;
+
+ // Whether or not extensions are enabled.
+ bool extensions_enabled_;
+
+ // Whether to notify users when they attempt to install an extension.
+ bool show_extensions_prompts_;
+
+ // The backend that will do IO on behalf of this instance.
+ scoped_refptr<ExtensionServiceBackend> backend_;
+
+ // Used by dispatchers to limit API quota for individual extensions.
+ ExtensionsQuotaService quota_service_;
+
+ // Record that Init() has been called, and NotificationType::EXTENSIONS_READY
+ // has fired.
+ bool ready_;
+
+ // Our extension updater, if updates are turned on.
+ scoped_refptr<ExtensionUpdater> updater_;
+
+ // The model that tracks extensions with BrowserAction buttons.
+ ExtensionToolbarModel toolbar_model_;
+
+ // Map unloaded extensions' ids to their paths. When a temporarily loaded
+ // extension is unloaded, we lose the infomation about it and don't have
+ // any in the extension preferences file.
+ typedef std::map<std::string, FilePath> UnloadedExtensionPathMap;
+ UnloadedExtensionPathMap unloaded_extension_paths_;
+
+ // Map disabled extensions' ids to their paths. When a temporarily loaded
+ // extension is disabled before it is reloaded, keep track of the path so that
+ // it can be re-enabled upon a successful load.
+ typedef std::map<std::string, FilePath> DisabledExtensionPathMap;
+ DisabledExtensionPathMap disabled_extension_paths_;
+
+ // Map of inspector cookies that are detached, waiting for an extension to be
+ // reloaded.
+ typedef std::map<std::string, int> OrphanedDevTools;
+ OrphanedDevTools orphaned_dev_tools_;
+
+ NotificationRegistrar registrar_;
+ PrefChangeRegistrar pref_change_registrar_;
+
+ // Keeps track of menu items added by extensions.
+ ExtensionMenuManager menu_manager_;
+
+ // Keeps track of favicon-sized omnibox icons for extensions.
+ ExtensionIconManager omnibox_icon_manager_;
+ ExtensionIconManager omnibox_popup_icon_manager_;
+
+ // List of registered component extensions (see Extension::Location).
+ typedef std::vector<ComponentExtensionInfo> RegisteredComponentExtensions;
+ RegisteredComponentExtensions component_extension_manifests_;
+
+ // Collection of origins we've granted unlimited storage to. This is a
+ // map from origin to the number of extensions requiring unlimited
+ // storage within that origin.
+ typedef std::map<GURL, int> UnlimitedStorageMap;
+ UnlimitedStorageMap unlimited_storage_map_;
+
+ // Collection of origins whose storage is protected by "Clear browsing data."
+ // A map from origin to the number of Apps currently installed and therefore
+ // intrinsically protected.
+ typedef std::map<GURL, int> ProtectedStorageMap;
+ ProtectedStorageMap protected_storage_map_;
+
+ // Manages the installation of default apps and the promotion of them in the
+ // app launcher.
+ DefaultApps default_apps_;
+
+ // Flag to make sure event routers are only initialized once.
+ bool event_routers_initialized_;
+
+ FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest,
+ UpdatePendingExtensionAlreadyInstalled);
+ FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest,
+ InstallAppsWithUnlimtedStorage);
+ FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest,
+ InstallAppsAndCheckStorageProtection);
+ DISALLOW_COPY_AND_ASSIGN(ExtensionService);
+};
+
+#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_SERVICE_H_
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
new file mode 100644
index 0000000..7f052b6
--- /dev/null
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -0,0 +1,3264 @@
+// 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.
+
+#include "chrome/browser/extensions/extension_service_unittest.h"
+
+#include <algorithm>
+#include <set>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/json/json_reader.h"
+#include "base/message_loop.h"
+#include "base/path_service.h"
+#include "base/scoped_ptr.h"
+#include "base/stl_util-inl.h"
+#include "base/string16.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
+#include "base/task.h"
+#include "base/utf_string_conversions.h"
+#include "base/version.h"
+#include "chrome/browser/appcache/chrome_appcache_service.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/extensions/crx_installer.h"
+#include "chrome/browser/extensions/extension_creator.h"
+#include "chrome/browser/extensions/extension_error_reporter.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/external_extension_provider.h"
+#include "chrome/browser/extensions/external_pref_extension_provider.h"
+#include "chrome/browser/extensions/pack_extension_job.cc"
+#include "chrome/browser/file_system/browser_file_system_helper.h"
+#include "chrome/browser/in_process_webkit/dom_storage_context.h"
+#include "chrome/browser/in_process_webkit/webkit_context.h"
+#include "chrome/browser/prefs/browser_prefs.h"
+#include "chrome/browser/prefs/pref_service_mock_builder.h"
+#include "chrome/browser/prefs/scoped_pref_update.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/extensions/extension_resource.h"
+#include "chrome/common/extensions/url_pattern.h"
+#include "chrome/common/json_value_serializer.h"
+#include "chrome/common/net/url_request_context_getter.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/test/testing_profile.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/cookie_monster.h"
+#include "net/base/cookie_options.h"
+#include "net/url_request/url_request_context.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+#include "webkit/database/database_tracker.h"
+#include "webkit/database/database_util.h"
+
+namespace keys = extension_manifest_keys;
+
+namespace {
+
+// Extension ids used during testing.
+const char* const all_zero = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+const char* const zero_n_one = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab";
+const char* const good0 = "behllobkkfkfnphdnhnkndlbkcpglgmj";
+const char* const good1 = "hpiknbiabeeppbpihjehijgoemciehgk";
+const char* const good2 = "bjafgdebaacbbbecmhlhpofkepfkgcpa";
+const char* const good_crx = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
+const char* const page_action = "obcimlgaoabeegjmmpldobjndiealpln";
+const char* const theme_crx = "iamefpfkojoapidjnbafmgkgncegbkad";
+const char* const theme2_crx = "pjpgmfcmabopnnfonnhmdjglfpjjfkbf";
+const char* const permissions_crx = "eagpmdpfmaekmmcejjbmjoecnejeiiin";
+
+struct ExtensionsOrder {
+ bool operator()(const Extension* a, const Extension* b) {
+ return a->name() < b->name();
+ }
+};
+
+static std::vector<std::string> GetErrors() {
+ const std::vector<std::string>* errors =
+ ExtensionErrorReporter::GetInstance()->GetErrors();
+ std::vector<std::string> ret_val;
+
+ for (std::vector<std::string>::const_iterator iter = errors->begin();
+ iter != errors->end(); ++iter) {
+ if (iter->find(".svn") == std::string::npos) {
+ ret_val.push_back(*iter);
+ }
+ }
+
+ // The tests rely on the errors being in a certain order, which can vary
+ // depending on how filesystem iteration works.
+ std::stable_sort(ret_val.begin(), ret_val.end());
+
+ return ret_val;
+}
+
+static void AddPattern(ExtensionExtent* extent, const std::string& pattern) {
+ int schemes = URLPattern::SCHEME_ALL;
+ extent->AddPattern(URLPattern(schemes, pattern));
+}
+
+static void AssertEqualExtents(ExtensionExtent* extent1,
+ ExtensionExtent* extent2) {
+ std::vector<URLPattern> patterns1 = extent1->patterns();
+ std::vector<URLPattern> patterns2 = extent2->patterns();
+ std::set<std::string> strings1;
+ EXPECT_EQ(patterns1.size(), patterns2.size());
+
+ for (size_t i = 0; i < patterns1.size(); ++i)
+ strings1.insert(patterns1.at(i).GetAsString());
+
+ std::set<std::string> strings2;
+ for (size_t i = 0; i < patterns2.size(); ++i)
+ strings2.insert(patterns2.at(i).GetAsString());
+
+ EXPECT_EQ(strings1, strings2);
+}
+
+} // namespace
+
+class MockExtensionProvider : public ExternalExtensionProvider {
+ public:
+ explicit MockExtensionProvider(Extension::Location location)
+ : location_(location), visit_count_(0) {}
+ virtual ~MockExtensionProvider() {}
+
+ void UpdateOrAddExtension(const std::string& id,
+ const std::string& version,
+ const FilePath& path) {
+ extension_map_[id] = std::make_pair(version, path);
+ }
+
+ void RemoveExtension(const std::string& id) {
+ extension_map_.erase(id);
+ }
+
+ // ExternalExtensionProvider implementation:
+ virtual void VisitRegisteredExtension(Visitor* visitor) const {
+ visit_count_++;
+ for (DataMap::const_iterator i = extension_map_.begin();
+ i != extension_map_.end(); ++i) {
+ scoped_ptr<Version> version;
+ version.reset(Version::GetVersionFromString(i->second.first));
+
+ visitor->OnExternalExtensionFileFound(
+ i->first, version.get(), i->second.second, location_);
+ }
+ }
+
+ virtual bool HasExtension(const std::string& id) const {
+ return extension_map_.find(id) != extension_map_.end();
+ }
+
+ virtual bool GetExtensionDetails(const std::string& id,
+ Extension::Location* location,
+ scoped_ptr<Version>* version) const {
+ DataMap::const_iterator it = extension_map_.find(id);
+ if (it == extension_map_.end())
+ return false;
+
+ if (version)
+ version->reset(Version::GetVersionFromString(it->second.first));
+
+ if (location)
+ *location = location_;
+
+ return true;
+ }
+ int visit_count() const { return visit_count_; }
+ void set_visit_count(int visit_count) {
+ visit_count_ = visit_count;
+ }
+
+ private:
+ typedef std::map< std::string, std::pair<std::string, FilePath> > DataMap;
+ DataMap extension_map_;
+ Extension::Location location_;
+
+ // visit_count_ tracks the number of calls to VisitRegisteredExtension().
+ // Mutable because it must be incremented on each call to
+ // VisitRegisteredExtension(), which must be a const method to inherit
+ // from the class being mocked.
+ mutable int visit_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockExtensionProvider);
+};
+
+class MockProviderVisitor : public ExternalExtensionProvider::Visitor {
+ public:
+ MockProviderVisitor() : ids_found_(0) {
+ }
+
+ int Visit(const std::string& json_data) {
+ // Give the test json file to the provider for parsing.
+ provider_.reset(new ExternalPrefExtensionProvider());
+ provider_->SetPreferencesForTesting(json_data);
+
+ // We also parse the file into a dictionary to compare what we get back
+ // from the provider.
+ JSONStringValueSerializer serializer(json_data);
+ Value* json_value = serializer.Deserialize(NULL, NULL);
+
+ if (!json_value || !json_value->IsType(Value::TYPE_DICTIONARY)) {
+ NOTREACHED() << "Unable to deserialize json data";
+ return -1;
+ } else {
+ DictionaryValue* external_extensions =
+ static_cast<DictionaryValue*>(json_value);
+ prefs_.reset(external_extensions);
+ }
+
+ // Reset our counter.
+ ids_found_ = 0;
+ // Ask the provider to look up all extensions and return them.
+ provider_->VisitRegisteredExtension(this);
+
+ return ids_found_;
+ }
+
+ virtual void OnExternalExtensionFileFound(const std::string& id,
+ const Version* version,
+ const FilePath& path,
+ Extension::Location unused) {
+ ++ids_found_;
+ DictionaryValue* pref;
+ // This tests is to make sure that the provider only notifies us of the
+ // values we gave it. So if the id we doesn't exist in our internal
+ // dictionary then something is wrong.
+ EXPECT_TRUE(prefs_->GetDictionary(id, &pref))
+ << "Got back ID (" << id.c_str() << ") we weren't expecting";
+
+ if (pref) {
+ EXPECT_TRUE(provider_->HasExtension(id));
+
+ // Ask provider if the extension we got back is registered.
+ Extension::Location location = Extension::INVALID;
+ scoped_ptr<Version> v1;
+ FilePath crx_path;
+
+ EXPECT_TRUE(provider_->GetExtensionDetails(id, NULL, &v1));
+ EXPECT_STREQ(version->GetString().c_str(), v1->GetString().c_str());
+
+ scoped_ptr<Version> v2;
+ EXPECT_TRUE(provider_->GetExtensionDetails(id, &location, &v2));
+ EXPECT_STREQ(version->GetString().c_str(), v1->GetString().c_str());
+ EXPECT_STREQ(version->GetString().c_str(), v2->GetString().c_str());
+ EXPECT_EQ(Extension::EXTERNAL_PREF, location);
+
+ // Remove it so we won't count it ever again.
+ prefs_->Remove(id, NULL);
+ }
+ }
+
+ virtual void OnExternalExtensionUpdateUrlFound(
+ const std::string& id, const GURL& update_url,
+ Extension::Location location) {
+ ++ids_found_;
+ DictionaryValue* pref;
+ // This tests is to make sure that the provider only notifies us of the
+ // values we gave it. So if the id we doesn't exist in our internal
+ // dictionary then something is wrong.
+ EXPECT_TRUE(prefs_->GetDictionary(id, &pref))
+ << L"Got back ID (" << id.c_str() << ") we weren't expecting";
+ EXPECT_EQ(Extension::EXTERNAL_PREF_DOWNLOAD, location);
+
+ if (pref) {
+ EXPECT_TRUE(provider_->HasExtension(id));
+
+ // External extensions with update URLs do not have versions.
+ scoped_ptr<Version> v1;
+ Extension::Location location1 = Extension::INVALID;
+ EXPECT_TRUE(provider_->GetExtensionDetails(id, &location1, &v1));
+ EXPECT_FALSE(v1.get());
+ EXPECT_EQ(Extension::EXTERNAL_PREF_DOWNLOAD, location1);
+
+ // Remove it so we won't count it again.
+ prefs_->Remove(id, NULL);
+ }
+ }
+
+ private:
+ int ids_found_;
+
+ scoped_ptr<ExternalPrefExtensionProvider> provider_;
+ scoped_ptr<DictionaryValue> prefs_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockProviderVisitor);
+};
+
+class ExtensionTestingProfile : public TestingProfile {
+ public:
+ ExtensionTestingProfile() : service_(NULL) {
+ }
+
+ void set_extensions_service(ExtensionService* service) {
+ service_ = service;
+ }
+ virtual ExtensionService* GetExtensionService() { return service_; }
+
+ virtual ChromeAppCacheService* GetAppCacheService() {
+ if (!appcache_service_) {
+ appcache_service_ = new ChromeAppCacheService;
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(appcache_service_.get(),
+ &ChromeAppCacheService::InitializeOnIOThread,
+ GetPath(), IsOffTheRecord(),
+ make_scoped_refptr(GetHostContentSettingsMap())));
+ }
+ return appcache_service_;
+ }
+
+ virtual fileapi::SandboxedFileSystemContext* GetFileSystemContext() {
+ if (!file_system_context_)
+ file_system_context_ = CreateFileSystemContext(
+ GetPath(), IsOffTheRecord());
+ return file_system_context_;
+ }
+
+ private:
+ ExtensionService* service_;
+ scoped_refptr<ChromeAppCacheService> appcache_service_;
+ scoped_refptr<fileapi::SandboxedFileSystemContext> file_system_context_;
+};
+
+// Our message loop may be used in tests which require it to be an IO loop.
+ExtensionServiceTestBase::ExtensionServiceTestBase()
+ : total_successes_(0),
+ loop_(MessageLoop::TYPE_IO),
+ ui_thread_(BrowserThread::UI, &loop_),
+ db_thread_(BrowserThread::DB, &loop_),
+ webkit_thread_(BrowserThread::WEBKIT, &loop_),
+ file_thread_(BrowserThread::FILE, &loop_),
+ io_thread_(BrowserThread::IO, &loop_) {
+}
+
+ExtensionServiceTestBase::~ExtensionServiceTestBase() {
+ // Drop our reference to ExtensionService and TestingProfile, so that they
+ // can be destroyed while BrowserThreads and MessageLoop are still around
+ // (they are used in the destruction process).
+ service_ = NULL;
+ profile_.reset(NULL);
+ MessageLoop::current()->RunAllPending();
+}
+
+void ExtensionServiceTestBase::InitializeExtensionService(
+ const FilePath& pref_file, const FilePath& extensions_install_dir) {
+ ExtensionTestingProfile* profile = new ExtensionTestingProfile();
+ // Create a PrefService that only contains user defined preference values.
+ PrefService* prefs =
+ PrefServiceMockBuilder().WithUserFilePrefs(pref_file).Create();
+ Profile::RegisterUserPrefs(prefs);
+ browser::RegisterUserPrefs(prefs);
+ profile->SetPrefService(prefs);
+
+ profile_.reset(profile);
+
+ service_ = profile->CreateExtensionService(
+ CommandLine::ForCurrentProcess(),
+ extensions_install_dir);
+ service_->set_extensions_enabled(true);
+ service_->set_show_extensions_prompts(false);
+ profile->set_extensions_service(service_.get());
+
+ // When we start up, we want to make sure there is no external provider,
+ // since the ExtensionService on Windows will use the Registry as a default
+ // provider and if there is something already registered there then it will
+ // interfere with the tests. Those tests that need an external provider
+ // will register one specifically.
+ service_->ClearProvidersForTesting();
+
+ total_successes_ = 0;
+}
+
+void ExtensionServiceTestBase::InitializeInstalledExtensionService(
+ const FilePath& prefs_file, const FilePath& source_install_dir) {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ FilePath path_ = temp_dir_.path();
+ path_ = path_.Append(FILE_PATH_LITERAL("TestingExtensionsPath"));
+ file_util::Delete(path_, true);
+ file_util::CreateDirectory(path_);
+ FilePath temp_prefs = path_.Append(FILE_PATH_LITERAL("Preferences"));
+ file_util::CopyFile(prefs_file, temp_prefs);
+
+ extensions_install_dir_ = path_.Append(FILE_PATH_LITERAL("Extensions"));
+ file_util::Delete(extensions_install_dir_, true);
+ file_util::CopyDirectory(source_install_dir, extensions_install_dir_, true);
+
+ InitializeExtensionService(temp_prefs, extensions_install_dir_);
+}
+
+void ExtensionServiceTestBase::InitializeEmptyExtensionService() {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ FilePath path_ = temp_dir_.path();
+ path_ = path_.Append(FILE_PATH_LITERAL("TestingExtensionsPath"));
+ file_util::Delete(path_, true);
+ file_util::CreateDirectory(path_);
+ FilePath prefs_filename = path_
+ .Append(FILE_PATH_LITERAL("TestPreferences"));
+ extensions_install_dir_ = path_.Append(FILE_PATH_LITERAL("Extensions"));
+ file_util::Delete(extensions_install_dir_, true);
+ file_util::CreateDirectory(extensions_install_dir_);
+
+ InitializeExtensionService(prefs_filename, extensions_install_dir_);
+}
+
+// static
+void ExtensionServiceTestBase::SetUpTestCase() {
+ ExtensionErrorReporter::Init(false); // no noisy errors
+}
+
+void ExtensionServiceTestBase::SetUp() {
+ ExtensionErrorReporter::GetInstance()->ClearErrors();
+}
+
+class ExtensionServiceTest
+ : public ExtensionServiceTestBase, public NotificationObserver {
+ public:
+ ExtensionServiceTest() : installed_(NULL) {
+ registrar_.Add(this, NotificationType::EXTENSION_LOADED,
+ NotificationService::AllSources());
+ registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
+ NotificationService::AllSources());
+ registrar_.Add(this, NotificationType::EXTENSION_INSTALLED,
+ NotificationService::AllSources());
+ registrar_.Add(this, NotificationType::THEME_INSTALLED,
+ NotificationService::AllSources());
+ }
+
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ switch (type.value) {
+ case NotificationType::EXTENSION_LOADED: {
+ const Extension* extension = Details<const Extension>(details).ptr();
+ loaded_.push_back(make_scoped_refptr(extension));
+ // The tests rely on the errors being in a certain order, which can vary
+ // depending on how filesystem iteration works.
+ std::stable_sort(loaded_.begin(), loaded_.end(), ExtensionsOrder());
+ break;
+ }
+
+ case NotificationType::EXTENSION_UNLOADED: {
+ const Extension* e =
+ Details<UnloadedExtensionInfo>(details)->extension;
+ unloaded_id_ = e->id();
+ ExtensionList::iterator i =
+ std::find(loaded_.begin(), loaded_.end(), e);
+ // TODO(erikkay) fix so this can be an assert. Right now the tests
+ // are manually calling clear() on loaded_, so this isn't doable.
+ if (i == loaded_.end())
+ return;
+ loaded_.erase(i);
+ break;
+ }
+ case NotificationType::EXTENSION_INSTALLED:
+ case NotificationType::THEME_INSTALLED:
+ installed_ = Details<const Extension>(details).ptr();
+ break;
+
+ default:
+ DCHECK(false);
+ }
+ }
+
+ void AddMockExternalProvider(ExternalExtensionProvider* provider) {
+ service_->AddProviderForTesting(provider);
+ }
+
+ protected:
+ void TestExternalProvider(MockExtensionProvider* provider,
+ Extension::Location location);
+
+ void PackAndInstallExtension(const FilePath& dir_path,
+ const FilePath& pem_path,
+ bool should_succeed) {
+ FilePath crx_path;
+ ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &crx_path));
+ crx_path = crx_path.AppendASCII("temp.crx");
+
+ // Use the existing pem key, if provided.
+ FilePath pem_output_path;
+ if (pem_path.value().empty()) {
+ pem_output_path = crx_path.DirName().AppendASCII("temp.pem");
+ ASSERT_TRUE(file_util::Delete(pem_output_path, false));
+ } else {
+ ASSERT_TRUE(file_util::PathExists(pem_path));
+ }
+
+ ASSERT_TRUE(file_util::Delete(crx_path, false));
+
+ scoped_ptr<ExtensionCreator> creator(new ExtensionCreator());
+ ASSERT_TRUE(creator->Run(dir_path,
+ crx_path,
+ pem_path,
+ pem_output_path));
+
+ ASSERT_TRUE(file_util::PathExists(crx_path));
+
+ InstallExtension(crx_path, should_succeed);
+ }
+
+ void PackAndInstallExtension(const FilePath& dir_path,
+ bool should_succeed) {
+ PackAndInstallExtension(dir_path, FilePath(), should_succeed);
+ }
+
+ void InstallExtension(const FilePath& path,
+ bool should_succeed) {
+ ASSERT_TRUE(file_util::PathExists(path));
+ service_->InstallExtension(path);
+ loop_.RunAllPending();
+ std::vector<std::string> errors = GetErrors();
+ if (should_succeed) {
+ ++total_successes_;
+
+ EXPECT_TRUE(installed_) << path.value();
+
+ ASSERT_EQ(1u, loaded_.size()) << path.value();
+ EXPECT_EQ(0u, errors.size()) << path.value();
+ EXPECT_EQ(total_successes_, service_->extensions()->size()) <<
+ path.value();
+ EXPECT_TRUE(service_->GetExtensionById(loaded_[0]->id(), false)) <<
+ path.value();
+ for (std::vector<std::string>::iterator err = errors.begin();
+ err != errors.end(); ++err) {
+ LOG(ERROR) << *err;
+ }
+ } else {
+ EXPECT_FALSE(installed_) << path.value();
+ EXPECT_EQ(0u, loaded_.size()) << path.value();
+ EXPECT_EQ(1u, errors.size()) << path.value();
+ }
+
+ installed_ = NULL;
+ loaded_.clear();
+ ExtensionErrorReporter::GetInstance()->ClearErrors();
+ }
+
+ enum UpdateState {
+ FAILED_SILENTLY,
+ FAILED,
+ UPDATED,
+ INSTALLED,
+ ENABLED
+ };
+
+ void UpdateExtension(const std::string& id, const FilePath& in_path,
+ UpdateState expected_state) {
+ ASSERT_TRUE(file_util::PathExists(in_path));
+
+ // We need to copy this to a temporary location because Update() will delete
+ // it.
+ FilePath path = temp_dir_.path();
+ path = path.Append(in_path.BaseName());
+ ASSERT_TRUE(file_util::CopyFile(in_path, path));
+
+ int previous_enabled_extension_count =
+ service_->extensions()->size();
+ int previous_installed_extension_count =
+ previous_enabled_extension_count +
+ service_->disabled_extensions()->size();
+
+ service_->UpdateExtension(id, path, GURL());
+ loop_.RunAllPending();
+
+ std::vector<std::string> errors = GetErrors();
+ int error_count = errors.size();
+ int enabled_extension_count =
+ service_->extensions()->size();
+ int installed_extension_count =
+ enabled_extension_count + service_->disabled_extensions()->size();
+
+ int expected_error_count = (expected_state == FAILED) ? 1 : 0;
+ EXPECT_EQ(expected_error_count, error_count) << path.value();
+
+ if (expected_state <= FAILED) {
+ EXPECT_EQ(previous_enabled_extension_count,
+ enabled_extension_count);
+ EXPECT_EQ(previous_installed_extension_count,
+ installed_extension_count);
+ } else {
+ int expected_installed_extension_count =
+ (expected_state >= INSTALLED) ? 1 : 0;
+ int expected_enabled_extension_count =
+ (expected_state >= ENABLED) ? 1 : 0;
+ EXPECT_EQ(expected_installed_extension_count,
+ installed_extension_count);
+ EXPECT_EQ(expected_enabled_extension_count,
+ enabled_extension_count);
+ }
+
+ // Update() should delete the temporary input file.
+ EXPECT_FALSE(file_util::PathExists(path));
+ }
+
+ void ValidatePrefKeyCount(size_t count) {
+ DictionaryValue* dict =
+ profile_->GetPrefs()->GetMutableDictionary("extensions.settings");
+ ASSERT_TRUE(dict != NULL);
+ EXPECT_EQ(count, dict->size());
+ }
+
+ void ValidateBooleanPref(const std::string& extension_id,
+ const std::string& pref_path,
+ bool expected_val) {
+ std::string msg = " while checking: ";
+ msg += extension_id;
+ msg += " ";
+ msg += pref_path;
+ msg += " == ";
+ msg += expected_val ? "true" : "false";
+
+ PrefService* prefs = profile_->GetPrefs();
+ const DictionaryValue* dict =
+ prefs->GetDictionary("extensions.settings");
+ ASSERT_TRUE(dict != NULL) << msg;
+ DictionaryValue* pref = NULL;
+ ASSERT_TRUE(dict->GetDictionary(extension_id, &pref)) << msg;
+ EXPECT_TRUE(pref != NULL) << msg;
+ bool val;
+ ASSERT_TRUE(pref->GetBoolean(pref_path, &val)) << msg;
+ EXPECT_EQ(expected_val, val) << msg;
+ }
+
+ bool IsPrefExist(const std::string& extension_id,
+ const std::string& pref_path) {
+ const DictionaryValue* dict =
+ profile_->GetPrefs()->GetDictionary("extensions.settings");
+ if (dict == NULL) return false;
+ DictionaryValue* pref = NULL;
+ if (!dict->GetDictionary(extension_id, &pref)) {
+ return false;
+ }
+ if (pref == NULL) {
+ return false;
+ }
+ bool val;
+ if (!pref->GetBoolean(pref_path, &val)) {
+ return false;
+ }
+ return true;
+ }
+
+ void ValidateIntegerPref(const std::string& extension_id,
+ const std::string& pref_path,
+ int expected_val) {
+ std::string msg = " while checking: ";
+ msg += extension_id;
+ msg += " ";
+ msg += pref_path;
+ msg += " == ";
+ msg += base::IntToString(expected_val);
+
+ PrefService* prefs = profile_->GetPrefs();
+ const DictionaryValue* dict =
+ prefs->GetDictionary("extensions.settings");
+ ASSERT_TRUE(dict != NULL) << msg;
+ DictionaryValue* pref = NULL;
+ ASSERT_TRUE(dict->GetDictionary(extension_id, &pref)) << msg;
+ EXPECT_TRUE(pref != NULL) << msg;
+ int val;
+ ASSERT_TRUE(pref->GetInteger(pref_path, &val)) << msg;
+ EXPECT_EQ(expected_val, val) << msg;
+ }
+
+ void ValidateStringPref(const std::string& extension_id,
+ const std::string& pref_path,
+ const std::string& expected_val) {
+ std::string msg = " while checking: ";
+ msg += extension_id;
+ msg += ".manifest.";
+ msg += pref_path;
+ msg += " == ";
+ msg += expected_val;
+
+ const DictionaryValue* dict =
+ profile_->GetPrefs()->GetDictionary("extensions.settings");
+ ASSERT_TRUE(dict != NULL) << msg;
+ DictionaryValue* pref = NULL;
+ std::string manifest_path = extension_id + ".manifest";
+ ASSERT_TRUE(dict->GetDictionary(manifest_path, &pref)) << msg;
+ EXPECT_TRUE(pref != NULL) << msg;
+ std::string val;
+ ASSERT_TRUE(pref->GetString(pref_path, &val)) << msg;
+ EXPECT_EQ(expected_val, val) << msg;
+ }
+
+ void SetPref(const std::string& extension_id,
+ const std::string& pref_path,
+ Value* value,
+ const std::string& msg) {
+ const DictionaryValue* dict =
+ profile_->GetPrefs()->GetMutableDictionary("extensions.settings");
+ ASSERT_TRUE(dict != NULL) << msg;
+ DictionaryValue* pref = NULL;
+ ASSERT_TRUE(dict->GetDictionary(extension_id, &pref)) << msg;
+ EXPECT_TRUE(pref != NULL) << msg;
+ pref->Set(pref_path, value);
+ }
+
+ void SetPrefInteg(const std::string& extension_id,
+ const std::string& pref_path,
+ int value) {
+ std::string msg = " while setting: ";
+ msg += extension_id;
+ msg += " ";
+ msg += pref_path;
+ msg += " = ";
+ msg += base::IntToString(value);
+
+ SetPref(extension_id, pref_path, Value::CreateIntegerValue(value), msg);
+ }
+
+ void SetPrefBool(const std::string& extension_id,
+ const std::string& pref_path,
+ bool value) {
+ std::string msg = " while setting: ";
+ msg += extension_id + " " + pref_path;
+ msg += " = ";
+ msg += (value ? "true" : "false");
+
+ SetPref(extension_id, pref_path, Value::CreateBooleanValue(value), msg);
+ }
+
+ void ClearPref(const std::string& extension_id,
+ const std::string& pref_path) {
+ std::string msg = " while clearing: ";
+ msg += extension_id + " " + pref_path;
+
+ const DictionaryValue* dict =
+ profile_->GetPrefs()->GetMutableDictionary("extensions.settings");
+ ASSERT_TRUE(dict != NULL) << msg;
+ DictionaryValue* pref = NULL;
+ ASSERT_TRUE(dict->GetDictionary(extension_id, &pref)) << msg;
+ EXPECT_TRUE(pref != NULL) << msg;
+ pref->Remove(pref_path, NULL);
+ }
+
+ void SetPrefStringSet(const std::string& extension_id,
+ const std::string& pref_path,
+ const std::set<std::string>& value) {
+ std::string msg = " while setting: ";
+ msg += extension_id + " " + pref_path;
+
+ ListValue* list_value = new ListValue();
+ for (std::set<std::string>::const_iterator iter = value.begin();
+ iter != value.end(); ++iter)
+ list_value->Append(Value::CreateStringValue(*iter));
+
+ SetPref(extension_id, pref_path, list_value, msg);
+ }
+
+ protected:
+ ExtensionList loaded_;
+ std::string unloaded_id_;
+ const Extension* installed_;
+
+ private:
+ NotificationRegistrar registrar_;
+};
+
+FilePath NormalizeSeparators(const FilePath& path) {
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+ return path.NormalizeWindowsPathSeparators();
+#else
+ return path;
+#endif // FILE_PATH_USES_WIN_SEPARATORS
+}
+
+// Receives notifications from a PackExtensionJob, indicating either that
+// packing succeeded or that there was some error.
+class PackExtensionTestClient : public PackExtensionJob::Client {
+ public:
+ PackExtensionTestClient(const FilePath& expected_crx_path,
+ const FilePath& expected_private_key_path);
+ virtual void OnPackSuccess(const FilePath& crx_path,
+ const FilePath& private_key_path);
+ virtual void OnPackFailure(const std::string& error_message);
+
+ private:
+ const FilePath expected_crx_path_;
+ const FilePath expected_private_key_path_;
+ DISALLOW_COPY_AND_ASSIGN(PackExtensionTestClient);
+};
+
+PackExtensionTestClient::PackExtensionTestClient(
+ const FilePath& expected_crx_path,
+ const FilePath& expected_private_key_path)
+ : expected_crx_path_(expected_crx_path),
+ expected_private_key_path_(expected_private_key_path) {}
+
+// If packing succeeded, we make sure that the package names match our
+// expectations.
+void PackExtensionTestClient::OnPackSuccess(const FilePath& crx_path,
+ const FilePath& private_key_path) {
+ // We got the notification and processed it; we don't expect any further tasks
+ // to be posted to the current thread, so we should stop blocking and continue
+ // on with the rest of the test.
+ // This call to |Quit()| matches the call to |Run()| in the
+ // |PackPunctuatedExtension| test.
+ MessageLoop::current()->Quit();
+ EXPECT_EQ(expected_crx_path_.value(), crx_path.value());
+ EXPECT_EQ(expected_private_key_path_.value(), private_key_path.value());
+ ASSERT_TRUE(file_util::PathExists(private_key_path));
+}
+
+// The tests are designed so that we never expect to see a packing error.
+void PackExtensionTestClient::OnPackFailure(const std::string& error_message) {
+ FAIL() << "Packing should not fail.";
+}
+
+// Test loading good extensions from the profile directory.
+TEST_F(ExtensionServiceTest, LoadAllExtensionsFromDirectorySuccess) {
+ // Initialize the test dir with a good Preferences/extensions.
+ FilePath source_install_dir;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir));
+ source_install_dir = source_install_dir
+ .AppendASCII("extensions")
+ .AppendASCII("good")
+ .AppendASCII("Extensions");
+ FilePath pref_path = source_install_dir
+ .DirName()
+ .AppendASCII("Preferences");
+ InitializeInstalledExtensionService(pref_path, source_install_dir);
+
+ service_->Init();
+
+ // On Chrome OS, we disallow extensions with plugins. "good1" has plugins,
+ // so we need to edit it out here.
+ uint32 expected_num_extensions = 3u;
+#if defined(OS_CHROMEOS)
+ --expected_num_extensions;
+#endif
+ ASSERT_EQ(expected_num_extensions, loaded_.size());
+
+ EXPECT_EQ(std::string(good0), loaded_[0]->id());
+ EXPECT_EQ(std::string("My extension 1"),
+ loaded_[0]->name());
+ EXPECT_EQ(std::string("The first extension that I made."),
+ loaded_[0]->description());
+ EXPECT_EQ(Extension::INTERNAL, loaded_[0]->location());
+ EXPECT_TRUE(service_->GetExtensionById(loaded_[0]->id(), false));
+ EXPECT_EQ(expected_num_extensions, service_->extensions()->size());
+
+ ValidatePrefKeyCount(3);
+ ValidateIntegerPref(good0, "state", Extension::ENABLED);
+ ValidateIntegerPref(good0, "location", Extension::INTERNAL);
+ ValidateIntegerPref(good1, "state", Extension::ENABLED);
+ ValidateIntegerPref(good1, "location", Extension::INTERNAL);
+ ValidateIntegerPref(good2, "state", Extension::ENABLED);
+ ValidateIntegerPref(good2, "location", Extension::INTERNAL);
+
+ const Extension* extension = loaded_[0];
+ const UserScriptList& scripts = extension->content_scripts();
+ ASSERT_EQ(2u, scripts.size());
+ EXPECT_EQ(3u, scripts[0].url_patterns().size());
+ EXPECT_EQ("file://*",
+ scripts[0].url_patterns()[0].GetAsString());
+ EXPECT_EQ("http://*.google.com/*",
+ scripts[0].url_patterns()[1].GetAsString());
+ EXPECT_EQ("https://*.google.com/*",
+ scripts[0].url_patterns()[2].GetAsString());
+ EXPECT_EQ(2u, scripts[0].js_scripts().size());
+ ExtensionResource resource00(extension->id(),
+ scripts[0].js_scripts()[0].extension_root(),
+ scripts[0].js_scripts()[0].relative_path());
+ FilePath expected_path(extension->path().AppendASCII("script1.js"));
+ ASSERT_TRUE(file_util::AbsolutePath(&expected_path));
+ EXPECT_TRUE(resource00.ComparePathWithDefault(expected_path));
+ ExtensionResource resource01(extension->id(),
+ scripts[0].js_scripts()[1].extension_root(),
+ scripts[0].js_scripts()[1].relative_path());
+ expected_path = extension->path().AppendASCII("script2.js");
+ ASSERT_TRUE(file_util::AbsolutePath(&expected_path));
+ EXPECT_TRUE(resource01.ComparePathWithDefault(expected_path));
+ EXPECT_TRUE(extension->plugins().empty());
+ EXPECT_EQ(1u, scripts[1].url_patterns().size());
+ EXPECT_EQ("http://*.news.com/*", scripts[1].url_patterns()[0].GetAsString());
+ ExtensionResource resource10(extension->id(),
+ scripts[1].js_scripts()[0].extension_root(),
+ scripts[1].js_scripts()[0].relative_path());
+ expected_path =
+ extension->path().AppendASCII("js_files").AppendASCII("script3.js");
+ ASSERT_TRUE(file_util::AbsolutePath(&expected_path));
+ EXPECT_TRUE(resource10.ComparePathWithDefault(expected_path));
+ const std::vector<URLPattern> permissions = extension->host_permissions();
+ ASSERT_EQ(2u, permissions.size());
+ EXPECT_EQ("http://*.google.com/*", permissions[0].GetAsString());
+ EXPECT_EQ("https://*.google.com/*", permissions[1].GetAsString());
+
+#if !defined(OS_CHROMEOS)
+ EXPECT_EQ(std::string(good1), loaded_[1]->id());
+ EXPECT_EQ(std::string("My extension 2"), loaded_[1]->name());
+ EXPECT_EQ(std::string(""), loaded_[1]->description());
+ EXPECT_EQ(loaded_[1]->GetResourceURL("background.html"),
+ loaded_[1]->background_url());
+ EXPECT_EQ(0u, loaded_[1]->content_scripts().size());
+ EXPECT_EQ(2u, loaded_[1]->plugins().size());
+ EXPECT_EQ(loaded_[1]->path().AppendASCII("content_plugin.dll").value(),
+ loaded_[1]->plugins()[0].path.value());
+ EXPECT_TRUE(loaded_[1]->plugins()[0].is_public);
+ EXPECT_EQ(loaded_[1]->path().AppendASCII("extension_plugin.dll").value(),
+ loaded_[1]->plugins()[1].path.value());
+ EXPECT_FALSE(loaded_[1]->plugins()[1].is_public);
+ EXPECT_EQ(Extension::INTERNAL, loaded_[1]->location());
+#endif
+
+ int index = expected_num_extensions - 1;
+ EXPECT_EQ(std::string(good2), loaded_[index]->id());
+ EXPECT_EQ(std::string("My extension 3"), loaded_[index]->name());
+ EXPECT_EQ(std::string(""), loaded_[index]->description());
+ EXPECT_EQ(0u, loaded_[index]->content_scripts().size());
+ EXPECT_EQ(Extension::INTERNAL, loaded_[index]->location());
+};
+
+// Test loading bad extensions from the profile directory.
+TEST_F(ExtensionServiceTest, LoadAllExtensionsFromDirectoryFail) {
+ // Initialize the test dir with a bad Preferences/extensions.
+ FilePath source_install_dir;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir));
+ source_install_dir = source_install_dir
+ .AppendASCII("extensions")
+ .AppendASCII("bad")
+ .AppendASCII("Extensions");
+ FilePath pref_path = source_install_dir
+ .DirName()
+ .AppendASCII("Preferences");
+
+ InitializeInstalledExtensionService(pref_path, source_install_dir);
+
+ service_->Init();
+ loop_.RunAllPending();
+
+ ASSERT_EQ(4u, GetErrors().size());
+ ASSERT_EQ(0u, loaded_.size());
+
+ EXPECT_TRUE(MatchPattern(GetErrors()[0],
+ std::string("Could not load extension from '*'. ") +
+ extension_manifest_errors::kManifestUnreadable)) << GetErrors()[0];
+
+ EXPECT_TRUE(MatchPattern(GetErrors()[1],
+ std::string("Could not load extension from '*'. ") +
+ extension_manifest_errors::kManifestUnreadable)) << GetErrors()[1];
+
+ EXPECT_TRUE(MatchPattern(GetErrors()[2],
+ std::string("Could not load extension from '*'. ") +
+ extension_manifest_errors::kMissingFile)) << GetErrors()[2];
+
+ EXPECT_TRUE(MatchPattern(GetErrors()[3],
+ std::string("Could not load extension from '*'. ") +
+ extension_manifest_errors::kManifestUnreadable)) << GetErrors()[3];
+};
+
+// Test that partially deleted extensions are cleaned up during startup
+// Test loading bad extensions from the profile directory.
+TEST_F(ExtensionServiceTest, CleanupOnStartup) {
+ FilePath source_install_dir;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir));
+ source_install_dir = source_install_dir
+ .AppendASCII("extensions")
+ .AppendASCII("good")
+ .AppendASCII("Extensions");
+ FilePath pref_path = source_install_dir
+ .DirName()
+ .AppendASCII("Preferences");
+
+ InitializeInstalledExtensionService(pref_path, source_install_dir);
+
+ // Simulate that one of them got partially deleted by clearing its pref.
+ DictionaryValue* dict =
+ profile_->GetPrefs()->GetMutableDictionary("extensions.settings");
+ ASSERT_TRUE(dict != NULL);
+ dict->Remove("behllobkkfkfnphdnhnkndlbkcpglgmj", NULL);
+
+ service_->Init();
+ loop_.RunAllPending();
+
+ file_util::FileEnumerator dirs(extensions_install_dir_, false,
+ file_util::FileEnumerator::DIRECTORIES);
+ size_t count = 0;
+ while (!dirs.Next().empty())
+ count++;
+
+ // We should have only gotten two extensions now.
+ EXPECT_EQ(2u, count);
+
+ // And extension1 dir should now be toast.
+ FilePath extension_dir = extensions_install_dir_
+ .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj");
+ ASSERT_FALSE(file_util::PathExists(extension_dir));
+}
+
+// Test installing extensions. This test tries to install few extensions using
+// crx files. If you need to change those crx files, feel free to repackage
+// them, throw away the key used and change the id's above.
+TEST_F(ExtensionServiceTest, InstallExtension) {
+ InitializeEmptyExtensionService();
+
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+
+ // Extensions not enabled.
+ set_extensions_enabled(false);
+ FilePath path = extensions_path.AppendASCII("good.crx");
+ InstallExtension(path, false);
+ set_extensions_enabled(true);
+
+ ValidatePrefKeyCount(0);
+
+ // A simple extension that should install without error.
+ path = extensions_path.AppendASCII("good.crx");
+ InstallExtension(path, true);
+ // TODO(erikkay): verify the contents of the installed extension.
+
+ int pref_count = 0;
+ ValidatePrefKeyCount(++pref_count);
+ ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
+ ValidateIntegerPref(good_crx, "location", Extension::INTERNAL);
+
+ // An extension with page actions.
+ path = extensions_path.AppendASCII("page_action.crx");
+ InstallExtension(path, true);
+ ValidatePrefKeyCount(++pref_count);
+ ValidateIntegerPref(page_action, "state", Extension::ENABLED);
+ ValidateIntegerPref(page_action, "location", Extension::INTERNAL);
+
+ // Bad signature.
+ path = extensions_path.AppendASCII("bad_signature.crx");
+ InstallExtension(path, false);
+ ValidatePrefKeyCount(pref_count);
+
+ // 0-length extension file.
+ path = extensions_path.AppendASCII("not_an_extension.crx");
+ InstallExtension(path, false);
+ ValidatePrefKeyCount(pref_count);
+
+ // Bad magic number.
+ path = extensions_path.AppendASCII("bad_magic.crx");
+ InstallExtension(path, false);
+ ValidatePrefKeyCount(pref_count);
+
+ // Extensions cannot have folders or files that have underscores except in
+ // certain whitelisted cases (eg _locales). This is an example of a broader
+ // class of validation that we do to the directory structure of the extension.
+ // We did not used to handle this correctly for installation.
+ path = extensions_path.AppendASCII("bad_underscore.crx");
+ InstallExtension(path, false);
+ ValidatePrefKeyCount(pref_count);
+
+ // TODO(erikkay): add more tests for many of the failure cases.
+ // TODO(erikkay): add tests for upgrade cases.
+}
+
+// Test the handling of killed extensions.
+TEST_F(ExtensionServiceTest, KilledExtensions) {
+ InitializeEmptyExtensionService();
+
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+ FilePath path = extensions_path.AppendASCII("good.crx");
+ set_extensions_enabled(true);
+
+ // Install an external extension.
+ service_->OnExternalExtensionFileFound(good_crx, "1.0.0.0",
+ path, Extension::EXTERNAL_PREF);
+ loop_.RunAllPending();
+ ASSERT_TRUE(NULL != service_->GetExtensionById(good_crx, false));
+
+ // Uninstall it and check that its killbit gets set.
+ service_->UninstallExtension(good_crx, false);
+ loop_.RunAllPending();
+ ValidateIntegerPref(good_crx, "location", Extension::KILLBIT);
+
+ // Try to re-install it externally. This should fail because of the killbit.
+ service_->OnExternalExtensionFileFound(good_crx, "1.0.0.0",
+ path, Extension::EXTERNAL_PREF);
+ loop_.RunAllPending();
+ ASSERT_TRUE(NULL == service_->GetExtensionById(good_crx, false));
+ ValidateIntegerPref(good_crx, "location", Extension::KILLBIT);
+
+ // Repeat the same thing with a newer version of the extension.
+ path = extensions_path.AppendASCII("good2.crx");
+ service_->OnExternalExtensionFileFound(good_crx, "1.0.0.1",
+ path, Extension::EXTERNAL_PREF);
+ loop_.RunAllPending();
+ ASSERT_TRUE(NULL == service_->GetExtensionById(good_crx, false));
+ ValidateIntegerPref(good_crx, "location", Extension::KILLBIT);
+
+ // Try adding the same extension from an external update URL.
+ service_->AddPendingExtensionFromExternalUpdateUrl(
+ good_crx,
+ GURL("http:://fake.update/url"),
+ Extension::EXTERNAL_PREF_DOWNLOAD);
+ const PendingExtensionMap& pending_extensions =
+ service_->pending_extensions();
+ ASSERT_TRUE(pending_extensions.find(good_crx) == pending_extensions.end());
+}
+
+// Install a user script (they get converted automatically to an extension)
+TEST_F(ExtensionServiceTest, InstallUserScript) {
+ // The details of script conversion are tested elsewhere, this just tests
+ // integration with ExtensionService.
+ InitializeEmptyExtensionService();
+
+ FilePath path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
+ path = path.AppendASCII("extensions")
+ .AppendASCII("user_script_basic.user.js");
+
+ ASSERT_TRUE(file_util::PathExists(path));
+ scoped_refptr<CrxInstaller> installer(
+ new CrxInstaller(service_, NULL)); // silent install
+ installer->InstallUserScript(
+ path,
+ GURL("http://www.aaronboodman.com/scripts/user_script_basic.user.js"));
+
+ loop_.RunAllPending();
+ std::vector<std::string> errors = GetErrors();
+ EXPECT_TRUE(installed_) << "Nothing was installed.";
+ ASSERT_EQ(1u, loaded_.size()) << "Nothing was loaded.";
+ EXPECT_EQ(0u, errors.size()) << "There were errors: "
+ << JoinString(errors, ',');
+ EXPECT_TRUE(service_->GetExtensionById(loaded_[0]->id(), false)) <<
+ path.value();
+
+ installed_ = NULL;
+ loaded_.clear();
+ ExtensionErrorReporter::GetInstance()->ClearErrors();
+}
+
+// This tests that the granted permissions preferences are correctly set when
+// installing an extension.
+TEST_F(ExtensionServiceTest, GrantedPermissions) {
+ InitializeEmptyExtensionService();
+ FilePath path;
+ FilePath pem_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
+ path = path.AppendASCII("extensions")
+ .AppendASCII("permissions");
+
+ pem_path = path.AppendASCII("unknown.pem");
+ path = path.AppendASCII("unknown");
+
+ ASSERT_TRUE(file_util::PathExists(pem_path));
+ ASSERT_TRUE(file_util::PathExists(path));
+
+ ExtensionPrefs* prefs = service_->extension_prefs();
+
+ std::set<std::string> expected_api_perms;
+ std::set<std::string> known_api_perms;
+ bool full_access;
+ ExtensionExtent expected_host_perms;
+ ExtensionExtent known_host_perms;
+
+ // Make sure there aren't any granted permissions before the
+ // extension is installed.
+ EXPECT_FALSE(prefs->GetGrantedPermissions(
+ permissions_crx, &full_access, &known_api_perms, &known_host_perms));
+ EXPECT_TRUE(known_api_perms.empty());
+ EXPECT_TRUE(known_host_perms.is_empty());
+
+ PackAndInstallExtension(path, pem_path, true);
+
+ EXPECT_EQ(0u, GetErrors().size());
+ ASSERT_EQ(1u, service_->extensions()->size());
+ std::string extension_id = service_->extensions()->at(0)->id();
+ EXPECT_EQ(permissions_crx, extension_id);
+
+
+ // Verify that the valid API permissions have been recognized.
+ expected_api_perms.insert("tabs");
+
+ AddPattern(&expected_host_perms, "http://*.google.com/*");
+ AddPattern(&expected_host_perms, "https://*.google.com/*");
+ AddPattern(&expected_host_perms, "http://*.google.com.hk/*");
+ AddPattern(&expected_host_perms, "http://www.example.com/*");
+
+ EXPECT_TRUE(prefs->GetGrantedPermissions(extension_id,
+ &full_access,
+ &known_api_perms,
+ &known_host_perms));
+
+ EXPECT_EQ(expected_api_perms, known_api_perms);
+ EXPECT_FALSE(full_access);
+ AssertEqualExtents(&expected_host_perms, &known_host_perms);
+}
+
+#if !defined(OS_CHROMEOS)
+// Tests that the granted permissions full_access bit gets set correctly when
+// an extension contains an NPAPI plugin. Don't run this test on Chrome OS
+// since they don't support plugins.
+TEST_F(ExtensionServiceTest, GrantedFullAccessPermissions) {
+ InitializeEmptyExtensionService();
+
+ FilePath path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
+ path = path.AppendASCII("extensions")
+ .AppendASCII("good")
+ .AppendASCII("Extensions")
+ .AppendASCII(good1)
+ .AppendASCII("2");
+
+ ASSERT_TRUE(file_util::PathExists(path));
+
+ PackAndInstallExtension(path, true);
+
+ EXPECT_EQ(0u, GetErrors().size());
+ EXPECT_EQ(1u, service_->extensions()->size());
+ const Extension* extension = service_->extensions()->at(0);
+ std::string extension_id = extension->id();
+ ExtensionPrefs* prefs = service_->extension_prefs();
+
+ bool full_access;
+ std::set<std::string> api_permissions;
+ ExtensionExtent host_permissions;
+ EXPECT_TRUE(prefs->GetGrantedPermissions(
+ extension_id, &full_access, &api_permissions, &host_permissions));
+
+ EXPECT_TRUE(full_access);
+ EXPECT_TRUE(api_permissions.empty());
+ EXPECT_TRUE(host_permissions.is_empty());
+}
+#endif
+
+// Tests that the extension is disabled when permissions are missing from
+// the extension's granted permissions preferences. (This simulates updating
+// the browser to a version which recognizes more permissions).
+TEST_F(ExtensionServiceTest, GrantedAPIAndHostPermissions) {
+ InitializeEmptyExtensionService();
+
+ FilePath path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
+ path = path.AppendASCII("extensions")
+ .AppendASCII("permissions")
+ .AppendASCII("unknown");
+
+ ASSERT_TRUE(file_util::PathExists(path));
+
+ PackAndInstallExtension(path, true);
+
+ EXPECT_EQ(0u, GetErrors().size());
+ EXPECT_EQ(1u, service_->extensions()->size());
+ const Extension* extension = service_->extensions()->at(0);
+ std::string extension_id = extension->id();
+
+ ExtensionPrefs* prefs = service_->extension_prefs();
+
+ std::set<std::string> expected_api_permissions;
+ ExtensionExtent expected_host_permissions;
+
+ expected_api_permissions.insert("tabs");
+ AddPattern(&expected_host_permissions, "http://*.google.com/*");
+ AddPattern(&expected_host_permissions, "https://*.google.com/*");
+ AddPattern(&expected_host_permissions, "http://*.google.com.hk/*");
+ AddPattern(&expected_host_permissions, "http://www.example.com/*");
+
+ std::set<std::string> api_permissions;
+ std::set<std::string> host_permissions;
+
+ // Test that the extension is disabled when an API permission is missing from
+ // the extension's granted api permissions preference. (This simulates
+ // updating the browser to a version which recognizes a new API permission).
+ SetPrefStringSet(extension_id, "granted_permissions.api", api_permissions);
+
+ service_->ReloadExtensions();
+
+ EXPECT_EQ(1u, service_->disabled_extensions()->size());
+ extension = service_->disabled_extensions()->at(0);
+
+ ASSERT_TRUE(prefs->GetExtensionState(extension_id) == Extension::DISABLED);
+ ASSERT_TRUE(prefs->DidExtensionEscalatePermissions(extension_id));
+
+ // Now grant and re-enable the extension, making sure the prefs are updated.
+ service_->GrantPermissionsAndEnableExtension(extension);
+
+ ASSERT_TRUE(prefs->GetExtensionState(extension_id) == Extension::ENABLED);
+ ASSERT_FALSE(prefs->DidExtensionEscalatePermissions(extension_id));
+
+ std::set<std::string> current_api_permissions;
+ ExtensionExtent current_host_permissions;
+ bool current_full_access;
+
+ ASSERT_TRUE(prefs->GetGrantedPermissions(extension_id,
+ &current_full_access,
+ &current_api_permissions,
+ &current_host_permissions));
+
+ ASSERT_FALSE(current_full_access);
+ ASSERT_EQ(expected_api_permissions, current_api_permissions);
+ AssertEqualExtents(&expected_host_permissions, &current_host_permissions);
+
+ // Tests that the extension is disabled when a host permission is missing from
+ // the extension's granted host permissions preference. (This simulates
+ // updating the browser to a version which recognizes additional host
+ // permissions).
+ api_permissions.clear();
+ host_permissions.clear();
+ current_api_permissions.clear();
+ current_host_permissions.ClearPaths();
+
+ api_permissions.insert("tabs");
+ host_permissions.insert("http://*.google.com/*");
+ host_permissions.insert("https://*.google.com/*");
+ host_permissions.insert("http://*.google.com.hk/*");
+
+ SetPrefStringSet(extension_id, "granted_permissions.api", api_permissions);
+ SetPrefStringSet(extension_id, "granted_permissions.host", host_permissions);
+
+ service_->ReloadExtensions();
+
+ EXPECT_EQ(1u, service_->disabled_extensions()->size());
+ extension = service_->disabled_extensions()->at(0);
+
+ ASSERT_TRUE(prefs->GetExtensionState(extension_id) == Extension::DISABLED);
+ ASSERT_TRUE(prefs->DidExtensionEscalatePermissions(extension_id));
+
+ // Now grant and re-enable the extension, making sure the prefs are updated.
+ service_->GrantPermissionsAndEnableExtension(extension);
+
+ ASSERT_TRUE(prefs->GetExtensionState(extension_id) == Extension::ENABLED);
+ ASSERT_FALSE(prefs->DidExtensionEscalatePermissions(extension_id));
+
+ ASSERT_TRUE(prefs->GetGrantedPermissions(extension_id,
+ &current_full_access,
+ &current_api_permissions,
+ &current_host_permissions));
+
+ ASSERT_FALSE(current_full_access);
+ ASSERT_EQ(expected_api_permissions, current_api_permissions);
+ AssertEqualExtents(&expected_host_permissions, &current_host_permissions);
+
+ // Tests that the granted permissions preferences are initialized when
+ // migrating from the old pref schema.
+ current_api_permissions.clear();
+ current_host_permissions.ClearPaths();
+
+ ClearPref(extension_id, "granted_permissions");
+
+ service_->ReloadExtensions();
+
+ EXPECT_EQ(1u, service_->extensions()->size());
+ extension = service_->extensions()->at(0);
+
+ ASSERT_TRUE(prefs->GetExtensionState(extension_id) == Extension::ENABLED);
+ ASSERT_FALSE(prefs->DidExtensionEscalatePermissions(extension_id));
+
+ ASSERT_TRUE(prefs->GetGrantedPermissions(extension_id,
+ &current_full_access,
+ &current_api_permissions,
+ &current_host_permissions));
+
+ ASSERT_FALSE(current_full_access);
+ ASSERT_EQ(expected_api_permissions, current_api_permissions);
+ AssertEqualExtents(&expected_host_permissions, &current_host_permissions);
+}
+
+// Test Packaging and installing an extension.
+TEST_F(ExtensionServiceTest, PackExtension) {
+ InitializeEmptyExtensionService();
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+ FilePath input_directory = extensions_path
+ .AppendASCII("good")
+ .AppendASCII("Extensions")
+ .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
+ .AppendASCII("1.0.0.0");
+
+ ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ FilePath output_directory = temp_dir.path();
+
+ FilePath crx_path(output_directory.AppendASCII("ex1.crx"));
+ FilePath privkey_path(output_directory.AppendASCII("privkey.pem"));
+
+ scoped_ptr<ExtensionCreator> creator(new ExtensionCreator());
+ ASSERT_TRUE(creator->Run(input_directory, crx_path, FilePath(),
+ privkey_path));
+
+ ASSERT_TRUE(file_util::PathExists(privkey_path));
+ InstallExtension(crx_path, true);
+
+ // Try packing with invalid paths.
+ creator.reset(new ExtensionCreator());
+ ASSERT_FALSE(creator->Run(FilePath(), FilePath(), FilePath(), FilePath()));
+
+ // Try packing an empty directory. Should fail because an empty directory is
+ // not a valid extension.
+ ScopedTempDir temp_dir2;
+ ASSERT_TRUE(temp_dir2.CreateUniqueTempDir());
+ creator.reset(new ExtensionCreator());
+ ASSERT_FALSE(creator->Run(temp_dir2.path(), crx_path, privkey_path,
+ FilePath()));
+
+ // Try packing with an invalid manifest.
+ std::string invalid_manifest_content = "I am not a manifest.";
+ ASSERT_TRUE(file_util::WriteFile(
+ temp_dir2.path().Append(Extension::kManifestFilename),
+ invalid_manifest_content.c_str(), invalid_manifest_content.size()));
+ creator.reset(new ExtensionCreator());
+ ASSERT_FALSE(creator->Run(temp_dir2.path(), crx_path, privkey_path,
+ FilePath()));
+}
+
+// Test Packaging and installing an extension whose name contains punctuation.
+TEST_F(ExtensionServiceTest, PackPunctuatedExtension) {
+ InitializeEmptyExtensionService();
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+ FilePath input_directory = extensions_path
+ .AppendASCII("good")
+ .AppendASCII("Extensions")
+ .AppendASCII(good0)
+ .AppendASCII("1.0.0.0");
+
+ ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+ // Extension names containing punctuation, and the expected names for the
+ // packed extensions.
+ const FilePath punctuated_names[] = {
+ FilePath(FilePath::StringType(
+ FILE_PATH_LITERAL("this.extensions.name.has.periods"))),
+ FilePath(FilePath::StringType(
+ FILE_PATH_LITERAL(".thisextensionsnamestartswithaperiod"))),
+ NormalizeSeparators(FilePath(FilePath::StringType(
+ FILE_PATH_LITERAL("thisextensionhasaslashinitsname/")))),
+ };
+ const FilePath expected_crx_names[] = {
+ FilePath(FilePath::StringType(
+ FILE_PATH_LITERAL("this.extensions.name.has.periods.crx"))),
+ FilePath(FilePath::StringType(
+ FILE_PATH_LITERAL(".thisextensionsnamestartswithaperiod.crx"))),
+ FilePath(FilePath::StringType(
+ FILE_PATH_LITERAL("thisextensionhasaslashinitsname.crx"))),
+ };
+ const FilePath expected_private_key_names[] = {
+ FilePath(FilePath::StringType(
+ FILE_PATH_LITERAL("this.extensions.name.has.periods.pem"))),
+ FilePath(FilePath::StringType(
+ FILE_PATH_LITERAL(".thisextensionsnamestartswithaperiod.pem"))),
+ FilePath(FilePath::StringType(
+ FILE_PATH_LITERAL("thisextensionhasaslashinitsname.pem"))),
+ };
+
+ for (size_t i = 0; i < arraysize(punctuated_names); ++i) {
+ SCOPED_TRACE(punctuated_names[i].value().c_str());
+ FilePath output_dir = temp_dir.path().Append(punctuated_names[i]);
+
+ // Copy the extension into the output directory, as PackExtensionJob doesn't
+ // let us choose where to output the packed extension.
+ ASSERT_TRUE(file_util::CopyDirectory(input_directory, output_dir, true));
+
+ FilePath expected_crx_path = temp_dir.path().Append(expected_crx_names[i]);
+ FilePath expected_private_key_path =
+ temp_dir.path().Append(expected_private_key_names[i]);
+ PackExtensionTestClient pack_client(expected_crx_path,
+ expected_private_key_path);
+ scoped_refptr<PackExtensionJob> packer(new PackExtensionJob(&pack_client,
+ output_dir,
+ FilePath()));
+ packer->Start();
+
+ // The packer will post a notification task to the current thread's message
+ // loop when it is finished. We manually run the loop here so that we
+ // block and catch the notification; otherwise, the process would exit.
+ // This call to |Run()| is matched by a call to |Quit()| in the
+ // |PackExtensionTestClient|'s notification handling code.
+ MessageLoop::current()->Run();
+
+ if (HasFatalFailure())
+ return;
+
+ InstallExtension(expected_crx_path, true);
+ }
+}
+
+// Test Packaging and installing an extension using an openssl generated key.
+// The openssl is generated with the following:
+// > openssl genrsa -out privkey.pem 1024
+// > openssl pkcs8 -topk8 -nocrypt -in privkey.pem -out privkey_asn1.pem
+// The privkey.pem is a PrivateKey, and the pcks8 -topk8 creates a
+// PrivateKeyInfo ASN.1 structure, we our RSAPrivateKey expects.
+TEST_F(ExtensionServiceTest, PackExtensionOpenSSLKey) {
+ InitializeEmptyExtensionService();
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+ FilePath input_directory = extensions_path
+ .AppendASCII("good")
+ .AppendASCII("Extensions")
+ .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
+ .AppendASCII("1.0.0.0");
+ FilePath privkey_path(extensions_path.AppendASCII(
+ "openssl_privkey_asn1.pem"));
+ ASSERT_TRUE(file_util::PathExists(privkey_path));
+
+ ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ FilePath output_directory = temp_dir.path();
+
+ FilePath crx_path(output_directory.AppendASCII("ex1.crx"));
+
+ scoped_ptr<ExtensionCreator> creator(new ExtensionCreator());
+ ASSERT_TRUE(creator->Run(input_directory, crx_path, privkey_path,
+ FilePath()));
+
+ InstallExtension(crx_path, true);
+}
+
+TEST_F(ExtensionServiceTest, InstallTheme) {
+ InitializeEmptyExtensionService();
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+
+ // A theme.
+ FilePath path = extensions_path.AppendASCII("theme.crx");
+ InstallExtension(path, true);
+ int pref_count = 0;
+ ValidatePrefKeyCount(++pref_count);
+ ValidateIntegerPref(theme_crx, "state", Extension::ENABLED);
+ ValidateIntegerPref(theme_crx, "location", Extension::INTERNAL);
+
+ // A theme when extensions are disabled. Themes can be installed, even when
+ // extensions are disabled.
+ set_extensions_enabled(false);
+ path = extensions_path.AppendASCII("theme2.crx");
+ InstallExtension(path, true);
+ ValidatePrefKeyCount(++pref_count);
+ ValidateIntegerPref(theme2_crx, "state", Extension::ENABLED);
+ ValidateIntegerPref(theme2_crx, "location", Extension::INTERNAL);
+
+ // A theme with extension elements. Themes cannot have extension elements so
+ // this test should fail.
+ set_extensions_enabled(true);
+ path = extensions_path.AppendASCII("theme_with_extension.crx");
+ InstallExtension(path, false);
+ ValidatePrefKeyCount(pref_count);
+
+ // A theme with image resources missing (misspelt path).
+ path = extensions_path.AppendASCII("theme_missing_image.crx");
+ InstallExtension(path, false);
+ ValidatePrefKeyCount(pref_count);
+}
+
+TEST_F(ExtensionServiceTest, LoadLocalizedTheme) {
+ // Load.
+ InitializeEmptyExtensionService();
+ FilePath extension_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extension_path));
+ extension_path = extension_path
+ .AppendASCII("extensions")
+ .AppendASCII("theme_i18n");
+
+ service_->LoadExtension(extension_path);
+ loop_.RunAllPending();
+ EXPECT_EQ(0u, GetErrors().size());
+ ASSERT_EQ(1u, loaded_.size());
+ EXPECT_EQ(1u, service_->extensions()->size());
+ EXPECT_EQ("name", service_->extensions()->at(0)->name());
+ EXPECT_EQ("description", service_->extensions()->at(0)->description());
+}
+
+TEST_F(ExtensionServiceTest, InstallLocalizedTheme) {
+ InitializeEmptyExtensionService();
+ FilePath theme_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &theme_path));
+ theme_path = theme_path
+ .AppendASCII("extensions")
+ .AppendASCII("theme_i18n");
+
+ PackAndInstallExtension(theme_path, true);
+
+ EXPECT_EQ(0u, GetErrors().size());
+ EXPECT_EQ(1u, service_->extensions()->size());
+ EXPECT_EQ("name", service_->extensions()->at(0)->name());
+ EXPECT_EQ("description", service_->extensions()->at(0)->description());
+}
+
+TEST_F(ExtensionServiceTest, InstallApps) {
+ InitializeEmptyExtensionService();
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+
+ // An empty app.
+ PackAndInstallExtension(extensions_path.AppendASCII("app1"), true);
+ int pref_count = 0;
+ ValidatePrefKeyCount(++pref_count);
+ ASSERT_EQ(1u, service_->extensions()->size());
+ std::string id = service_->extensions()->at(0)->id();
+ ValidateIntegerPref(id, "state", Extension::ENABLED);
+ ValidateIntegerPref(id, "location", Extension::INTERNAL);
+
+ // Another app with non-overlapping extent. Should succeed.
+ PackAndInstallExtension(extensions_path.AppendASCII("app2"), true);
+ ValidatePrefKeyCount(++pref_count);
+
+ // A third app whose extent overlaps the first. Should fail.
+ PackAndInstallExtension(extensions_path.AppendASCII("app3"), false);
+ ValidatePrefKeyCount(pref_count);
+}
+
+TEST_F(ExtensionServiceTest, InstallAppsWithUnlimtedStorage) {
+ InitializeEmptyExtensionService();
+ EXPECT_TRUE(service_->extensions()->empty());
+ EXPECT_TRUE(service_->unlimited_storage_map_.empty());
+
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+ int pref_count = 0;
+ ChromeAppCacheService* appcache_service = profile_->GetAppCacheService();
+
+ // Install app1 with unlimited storage.
+ PackAndInstallExtension(extensions_path.AppendASCII("app1"), true);
+ ValidatePrefKeyCount(++pref_count);
+ ASSERT_EQ(1u, service_->extensions()->size());
+ const Extension* extension = service_->extensions()->at(0);
+ const std::string id1 = extension->id();
+ EXPECT_TRUE(extension->HasApiPermission(
+ Extension::kUnlimitedStoragePermission));
+ EXPECT_TRUE(extension->web_extent().ContainsURL(
+ extension->GetFullLaunchURL()));
+ const GURL origin1(extension->GetFullLaunchURL().GetOrigin());
+ EXPECT_EQ(kint64max,
+ appcache_service->storage()->GetOriginQuotaInMemory(origin1));
+ EXPECT_FALSE(service_->unlimited_storage_map_.empty());
+
+ // Install app2 from the same origin with unlimited storage.
+ PackAndInstallExtension(extensions_path.AppendASCII("app2"), true);
+ ValidatePrefKeyCount(++pref_count);
+ ASSERT_EQ(2u, service_->extensions()->size());
+ extension = service_->extensions()->at(1);
+ const std::string id2 = extension->id();
+ EXPECT_TRUE(extension->HasApiPermission(
+ Extension::kUnlimitedStoragePermission));
+ EXPECT_TRUE(extension->web_extent().ContainsURL(
+ extension->GetFullLaunchURL()));
+ const GURL origin2(extension->GetFullLaunchURL().GetOrigin());
+ EXPECT_EQ(origin1, origin2);
+ EXPECT_EQ(kint64max,
+ appcache_service->storage()->GetOriginQuotaInMemory(origin2));
+ EXPECT_FALSE(service_->unlimited_storage_map_.empty());
+
+ // Uninstall one of them, unlimited storage should still be granted
+ // to the origin.
+ service_->UninstallExtension(id1, false);
+ loop_.RunAllPending();
+ EXPECT_EQ(1u, service_->extensions()->size());
+ EXPECT_EQ(kint64max,
+ appcache_service->storage()->GetOriginQuotaInMemory(origin1));
+ EXPECT_FALSE(service_->unlimited_storage_map_.empty());
+
+ // Uninstall the other, unlimited storage should be revoked.
+ service_->UninstallExtension(id2, false);
+ loop_.RunAllPending();
+ EXPECT_EQ(0u, service_->extensions()->size());
+ EXPECT_EQ(-1L,
+ appcache_service->storage()->GetOriginQuotaInMemory(origin2));
+ EXPECT_TRUE(service_->unlimited_storage_map_.empty());
+}
+
+TEST_F(ExtensionServiceTest, InstallAppsAndCheckStorageProtection) {
+ InitializeEmptyExtensionService();
+ EXPECT_TRUE(service_->extensions()->empty());
+ EXPECT_TRUE(service_->protected_storage_map_.empty());
+
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+ int pref_count = 0;
+
+ PackAndInstallExtension(extensions_path.AppendASCII("app1"), true);
+ ValidatePrefKeyCount(++pref_count);
+ ASSERT_EQ(1u, service_->extensions()->size());
+ const Extension* extension = service_->extensions()->at(0);
+ EXPECT_TRUE(extension->is_app());
+ const std::string id1 = extension->id();
+ EXPECT_FALSE(service_->protected_storage_map_.empty());
+ const GURL origin1(extension->GetFullLaunchURL().GetOrigin());
+ ASSERT_EQ(1, service_->protected_storage_map_[origin1]);
+
+ // App 4 has a different origin (maps.google.com).
+ PackAndInstallExtension(extensions_path.AppendASCII("app4"), true);
+ ValidatePrefKeyCount(++pref_count);
+ ASSERT_EQ(2u, service_->extensions()->size());
+ extension = service_->extensions()->at(1);
+ const std::string id2 = extension->id();
+ EXPECT_FALSE(service_->protected_storage_map_.empty());
+ const GURL origin2(extension->GetFullLaunchURL().GetOrigin());
+ ASSERT_NE(origin1, origin2);
+ ASSERT_EQ(1, service_->protected_storage_map_[origin2]);
+
+ service_->UninstallExtension(id1, false);
+ loop_.RunAllPending();
+ EXPECT_EQ(1u, service_->extensions()->size());
+ EXPECT_FALSE(service_->protected_storage_map_.empty());
+
+ service_->UninstallExtension(id2, false);
+ loop_.RunAllPending();
+
+ EXPECT_TRUE(service_->extensions()->empty());
+ EXPECT_TRUE(service_->protected_storage_map_.empty());
+}
+
+// Test that when an extension version is reinstalled, nothing happens.
+TEST_F(ExtensionServiceTest, Reinstall) {
+ InitializeEmptyExtensionService();
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+
+ // A simple extension that should install without error.
+ FilePath path = extensions_path.AppendASCII("good.crx");
+ service_->InstallExtension(path);
+ loop_.RunAllPending();
+
+ ASSERT_TRUE(installed_);
+ ASSERT_EQ(1u, loaded_.size());
+ ASSERT_EQ(0u, GetErrors().size());
+ ValidatePrefKeyCount(1);
+ ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
+ ValidateIntegerPref(good_crx, "location", Extension::INTERNAL);
+
+ installed_ = NULL;
+ loaded_.clear();
+ ExtensionErrorReporter::GetInstance()->ClearErrors();
+
+ // Reinstall the same version, it should overwrite the previous one.
+ service_->InstallExtension(path);
+ loop_.RunAllPending();
+
+ ASSERT_TRUE(installed_);
+ ASSERT_EQ(1u, loaded_.size());
+ ASSERT_EQ(0u, GetErrors().size());
+ ValidatePrefKeyCount(1);
+ ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
+ ValidateIntegerPref(good_crx, "location", Extension::INTERNAL);
+}
+
+// Test upgrading a signed extension.
+TEST_F(ExtensionServiceTest, UpgradeSignedGood) {
+ InitializeEmptyExtensionService();
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+
+ FilePath path = extensions_path.AppendASCII("good.crx");
+ service_->InstallExtension(path);
+ loop_.RunAllPending();
+
+ ASSERT_TRUE(installed_);
+ ASSERT_EQ(1u, loaded_.size());
+ ASSERT_EQ("1.0.0.0", loaded_[0]->version()->GetString());
+ ASSERT_EQ(0u, GetErrors().size());
+
+ // Upgrade to version 2.0
+ path = extensions_path.AppendASCII("good2.crx");
+ service_->InstallExtension(path);
+ loop_.RunAllPending();
+
+ ASSERT_TRUE(installed_);
+ ASSERT_EQ(1u, loaded_.size());
+ ASSERT_EQ("1.0.0.1", loaded_[0]->version()->GetString());
+ ASSERT_EQ(0u, GetErrors().size());
+}
+
+// Test upgrading a signed extension with a bad signature.
+TEST_F(ExtensionServiceTest, UpgradeSignedBad) {
+ InitializeEmptyExtensionService();
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+
+ FilePath path = extensions_path.AppendASCII("good.crx");
+ service_->InstallExtension(path);
+ loop_.RunAllPending();
+
+ ASSERT_TRUE(installed_);
+ ASSERT_EQ(1u, loaded_.size());
+ ASSERT_EQ(0u, GetErrors().size());
+ installed_ = NULL;
+
+ // Try upgrading with a bad signature. This should fail during the unpack,
+ // because the key will not match the signature.
+ path = extensions_path.AppendASCII("good2_bad_signature.crx");
+ service_->InstallExtension(path);
+ loop_.RunAllPending();
+
+ ASSERT_FALSE(installed_);
+ ASSERT_EQ(1u, loaded_.size());
+ ASSERT_EQ(1u, GetErrors().size());
+}
+
+// Test a normal update via the UpdateExtension API
+TEST_F(ExtensionServiceTest, UpdateExtension) {
+ InitializeEmptyExtensionService();
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+
+ FilePath path = extensions_path.AppendASCII("good.crx");
+
+ InstallExtension(path, true);
+ const Extension* good = service_->extensions()->at(0);
+ ASSERT_EQ("1.0.0.0", good->VersionString());
+ ASSERT_EQ(good_crx, good->id());
+
+ path = extensions_path.AppendASCII("good2.crx");
+ UpdateExtension(good_crx, path, ENABLED);
+ ASSERT_EQ("1.0.0.1", loaded_[0]->version()->GetString());
+}
+
+// Test updating a not-already-installed extension - this should fail
+TEST_F(ExtensionServiceTest, UpdateNotInstalledExtension) {
+ InitializeEmptyExtensionService();
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+
+ FilePath path = extensions_path.AppendASCII("good.crx");
+ UpdateExtension(good_crx, path, UPDATED);
+ loop_.RunAllPending();
+
+ ASSERT_EQ(0u, service_->extensions()->size());
+ ASSERT_FALSE(installed_);
+ ASSERT_EQ(0u, loaded_.size());
+}
+
+// Makes sure you can't downgrade an extension via UpdateExtension
+TEST_F(ExtensionServiceTest, UpdateWillNotDowngrade) {
+ InitializeEmptyExtensionService();
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+
+ FilePath path = extensions_path.AppendASCII("good2.crx");
+
+ InstallExtension(path, true);
+ const Extension* good = service_->extensions()->at(0);
+ ASSERT_EQ("1.0.0.1", good->VersionString());
+ ASSERT_EQ(good_crx, good->id());
+
+ // Change path from good2.crx -> good.crx
+ path = extensions_path.AppendASCII("good.crx");
+ UpdateExtension(good_crx, path, FAILED);
+ ASSERT_EQ("1.0.0.1", service_->extensions()->at(0)->VersionString());
+}
+
+// Make sure calling update with an identical version does nothing
+TEST_F(ExtensionServiceTest, UpdateToSameVersionIsNoop) {
+ InitializeEmptyExtensionService();
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+
+ FilePath path = extensions_path.AppendASCII("good.crx");
+
+ InstallExtension(path, true);
+ const Extension* good = service_->extensions()->at(0);
+ ASSERT_EQ(good_crx, good->id());
+ UpdateExtension(good_crx, path, FAILED_SILENTLY);
+}
+
+// Tests that updating an extension does not clobber old state.
+TEST_F(ExtensionServiceTest, UpdateExtensionPreservesState) {
+ InitializeEmptyExtensionService();
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+
+ FilePath path = extensions_path.AppendASCII("good.crx");
+
+ InstallExtension(path, true);
+ const Extension* good = service_->extensions()->at(0);
+ ASSERT_EQ("1.0.0.0", good->VersionString());
+ ASSERT_EQ(good_crx, good->id());
+
+ // Disable it and allow it to run in incognito. These settings should carry
+ // over to the updated version.
+ service_->DisableExtension(good->id());
+ service_->SetIsIncognitoEnabled(good, true);
+
+ path = extensions_path.AppendASCII("good2.crx");
+ UpdateExtension(good_crx, path, INSTALLED);
+ ASSERT_EQ(1u, service_->disabled_extensions()->size());
+ const Extension* good2 = service_->disabled_extensions()->at(0);
+ ASSERT_EQ("1.0.0.1", good2->version()->GetString());
+ EXPECT_TRUE(service_->IsIncognitoEnabled(good2));
+}
+
+// Tests that updating preserves extension location.
+TEST_F(ExtensionServiceTest, UpdateExtensionPreservesLocation) {
+ InitializeEmptyExtensionService();
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+
+ FilePath path = extensions_path.AppendASCII("good.crx");
+
+ InstallExtension(path, true);
+ const Extension* good = service_->extensions()->at(0);
+
+ ASSERT_EQ("1.0.0.0", good->VersionString());
+ ASSERT_EQ(good_crx, good->id());
+
+ // Simulate non-internal location.
+ const_cast<Extension*>(good)->location_ = Extension::EXTERNAL_PREF;
+
+ path = extensions_path.AppendASCII("good2.crx");
+ UpdateExtension(good_crx, path, ENABLED);
+ const Extension* good2 = service_->extensions()->at(0);
+ ASSERT_EQ("1.0.0.1", good2->version()->GetString());
+ EXPECT_EQ(good2->location(), Extension::EXTERNAL_PREF);
+}
+
+// Makes sure that LOAD extension types can downgrade.
+TEST_F(ExtensionServiceTest, LoadExtensionsCanDowngrade) {
+ InitializeEmptyExtensionService();
+
+ ScopedTempDir temp;
+ ASSERT_TRUE(temp.CreateUniqueTempDir());
+
+ // We'll write the extension manifest dynamically to a temporary path
+ // to make it easier to change the version number.
+ FilePath extension_path = temp.path();
+ FilePath manifest_path = extension_path.Append(Extension::kManifestFilename);
+ ASSERT_FALSE(file_util::PathExists(manifest_path));
+
+ // Start with version 2.0.
+ DictionaryValue manifest;
+ manifest.SetString("version", "2.0");
+ manifest.SetString("name", "LOAD Downgrade Test");
+
+ JSONFileValueSerializer serializer(manifest_path);
+ ASSERT_TRUE(serializer.Serialize(manifest));
+
+ service_->LoadExtension(extension_path);
+ loop_.RunAllPending();
+
+ EXPECT_EQ(0u, GetErrors().size());
+ ASSERT_EQ(1u, loaded_.size());
+ EXPECT_EQ(Extension::LOAD, loaded_[0]->location());
+ EXPECT_EQ(1u, service_->extensions()->size());
+ EXPECT_EQ("2.0", loaded_[0]->VersionString());
+
+ // Now set the version number to 1.0, reload the extensions and verify that
+ // the downgrade was accepted.
+ manifest.SetString("version", "1.0");
+ ASSERT_TRUE(serializer.Serialize(manifest));
+
+ service_->LoadExtension(extension_path);
+ loop_.RunAllPending();
+
+ EXPECT_EQ(0u, GetErrors().size());
+ ASSERT_EQ(1u, loaded_.size());
+ EXPECT_EQ(Extension::LOAD, loaded_[0]->location());
+ EXPECT_EQ(1u, service_->extensions()->size());
+ EXPECT_EQ("1.0", loaded_[0]->VersionString());
+}
+
+namespace {
+
+bool IsExtension(const Extension& extension) {
+ return extension.GetType() == Extension::TYPE_EXTENSION;
+}
+
+} // namespace
+
+// Test adding a pending extension.
+TEST_F(ExtensionServiceTest, AddPendingExtensionFromSync) {
+ InitializeEmptyExtensionService();
+
+ const std::string kFakeId("fake-id");
+ const GURL kFakeUpdateURL("http:://fake.update/url");
+ const bool kFakeInstallSilently(true);
+ const Extension::State kFakeInitialState(Extension::ENABLED);
+ const bool kFakeInitialIncognitoEnabled(false);
+
+ service_->AddPendingExtensionFromSync(
+ kFakeId, kFakeUpdateURL, &IsExtension,
+ kFakeInstallSilently, kFakeInitialState, kFakeInitialIncognitoEnabled);
+ PendingExtensionMap::const_iterator it =
+ service_->pending_extensions().find(kFakeId);
+ ASSERT_TRUE(it != service_->pending_extensions().end());
+ EXPECT_EQ(kFakeUpdateURL, it->second.update_url);
+ EXPECT_EQ(&IsExtension, it->second.should_install_extension);
+ EXPECT_EQ(kFakeInstallSilently, it->second.install_silently);
+}
+
+namespace {
+const char kGoodId[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
+const char kGoodUpdateURL[] = "http://good.update/url";
+const bool kGoodIsFromSync = true;
+const bool kGoodInstallSilently = true;
+const Extension::State kGoodInitialState = Extension::DISABLED;
+const bool kGoodInitialIncognitoEnabled = true;
+} // namespace
+
+// Test updating a pending extension.
+TEST_F(ExtensionServiceTest, UpdatePendingExtension) {
+ InitializeEmptyExtensionService();
+ service_->AddPendingExtensionFromSync(
+ kGoodId, GURL(kGoodUpdateURL), &IsExtension,
+ kGoodInstallSilently, kGoodInitialState,
+ kGoodInitialIncognitoEnabled);
+ EXPECT_TRUE(ContainsKey(service_->pending_extensions(), kGoodId));
+
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+ FilePath path = extensions_path.AppendASCII("good.crx");
+ UpdateExtension(kGoodId, path, INSTALLED);
+
+ EXPECT_FALSE(ContainsKey(service_->pending_extensions(), kGoodId));
+
+ const Extension* extension = service_->GetExtensionById(kGoodId, true);
+ ASSERT_TRUE(extension);
+
+ bool enabled = service_->GetExtensionById(kGoodId, false);
+ EXPECT_EQ(kGoodInitialState == Extension::ENABLED, enabled);
+ EXPECT_EQ(kGoodInitialState,
+ service_->extension_prefs()->GetExtensionState(extension->id()));
+ EXPECT_EQ(kGoodInitialIncognitoEnabled,
+ service_->IsIncognitoEnabled(extension));
+}
+
+namespace {
+
+bool IsTheme(const Extension& extension) {
+ return extension.is_theme();
+}
+
+} // namespace
+
+// Test updating a pending theme.
+TEST_F(ExtensionServiceTest, UpdatePendingTheme) {
+ InitializeEmptyExtensionService();
+ service_->AddPendingExtensionFromSync(
+ theme_crx, GURL(), &IsTheme,
+ false, Extension::ENABLED, false);
+ EXPECT_TRUE(ContainsKey(service_->pending_extensions(), theme_crx));
+
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+ FilePath path = extensions_path.AppendASCII("theme.crx");
+ UpdateExtension(theme_crx, path, ENABLED);
+
+ EXPECT_FALSE(ContainsKey(service_->pending_extensions(), theme_crx));
+
+ const Extension* extension = service_->GetExtensionById(theme_crx, true);
+ ASSERT_TRUE(extension);
+
+ EXPECT_EQ(Extension::ENABLED,
+ service_->extension_prefs()->GetExtensionState(extension->id()));
+ EXPECT_FALSE(service_->IsIncognitoEnabled(extension));
+}
+
+// Test updating a pending CRX as if the source is an external extension
+// with an update URL. In this case we don't know if the CRX is a theme
+// or not.
+TEST_F(ExtensionServiceTest, UpdatePendingExternalCrx) {
+ InitializeEmptyExtensionService();
+ service_->AddPendingExtensionFromExternalUpdateUrl(
+ theme_crx, GURL(), Extension::EXTERNAL_PREF_DOWNLOAD);
+
+ EXPECT_TRUE(ContainsKey(service_->pending_extensions(), theme_crx));
+
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+ FilePath path = extensions_path.AppendASCII("theme.crx");
+ UpdateExtension(theme_crx, path, ENABLED);
+
+ EXPECT_FALSE(ContainsKey(service_->pending_extensions(), theme_crx));
+
+ const Extension* extension = service_->GetExtensionById(theme_crx, true);
+ ASSERT_TRUE(extension);
+
+ EXPECT_EQ(Extension::ENABLED,
+ service_->extension_prefs()->GetExtensionState(extension->id()));
+ EXPECT_FALSE(service_->IsIncognitoEnabled(extension));
+}
+
+// Test updating a pending CRX as if the source is an external extension
+// with an update URL. The external update should overwrite a sync update,
+// but a sync update should not overwrite a non-sync update.
+TEST_F(ExtensionServiceTest, UpdatePendingExternalCrxWinsOverSync) {
+ InitializeEmptyExtensionService();
+
+ // Add a crx to be installed from the update mechanism.
+ service_->AddPendingExtensionFromSync(
+ kGoodId, GURL(kGoodUpdateURL), &IsExtension,
+ kGoodInstallSilently, kGoodInitialState,
+ kGoodInitialIncognitoEnabled);
+
+ // Check that there is a pending crx, with is_from_sync set to true.
+ PendingExtensionMap::const_iterator it;
+ it = service_->pending_extensions().find(kGoodId);
+ ASSERT_TRUE(it != service_->pending_extensions().end());
+ EXPECT_TRUE(it->second.is_from_sync);
+
+ // Add a crx to be updated, with the same ID, from a non-sync source.
+ service_->AddPendingExtensionFromExternalUpdateUrl(
+ kGoodId, GURL(kGoodUpdateURL), Extension::EXTERNAL_PREF_DOWNLOAD);
+
+ // Check that there is a pending crx, with is_from_sync set to false.
+ it = service_->pending_extensions().find(kGoodId);
+ ASSERT_TRUE(it != service_->pending_extensions().end());
+ EXPECT_FALSE(it->second.is_from_sync);
+
+ // Add a crx to be installed from the update mechanism.
+ service_->AddPendingExtensionFromSync(
+ kGoodId, GURL(kGoodUpdateURL), &IsExtension,
+ kGoodInstallSilently, kGoodInitialState,
+ kGoodInitialIncognitoEnabled);
+
+ // Check that the external, non-sync update was not overridden.
+ it = service_->pending_extensions().find(kGoodId);
+ ASSERT_TRUE(it != service_->pending_extensions().end());
+ EXPECT_FALSE(it->second.is_from_sync);
+}
+
+// Updating a theme should fail if the updater is explicitly told that
+// the CRX is not a theme.
+TEST_F(ExtensionServiceTest, UpdatePendingCrxThemeMismatch) {
+ InitializeEmptyExtensionService();
+ service_->AddPendingExtensionFromSync(
+ theme_crx, GURL(), &IsExtension,
+ true, Extension::ENABLED, false);
+
+ EXPECT_TRUE(ContainsKey(service_->pending_extensions(), theme_crx));
+
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+ FilePath path = extensions_path.AppendASCII("theme.crx");
+ UpdateExtension(theme_crx, path, FAILED_SILENTLY);
+
+ EXPECT_FALSE(ContainsKey(service_->pending_extensions(), theme_crx));
+
+ const Extension* extension = service_->GetExtensionById(theme_crx, true);
+ ASSERT_FALSE(extension);
+}
+
+// TODO(akalin): Test updating a pending extension non-silently once
+// we can mock out ExtensionInstallUI and inject our version into
+// UpdateExtension().
+
+// Test updating a pending extension which fails the should-install test.
+TEST_F(ExtensionServiceTest, UpdatePendingExtensionFailedShouldInstallTest) {
+ InitializeEmptyExtensionService();
+ // Add pending extension with a flipped is_theme.
+ service_->AddPendingExtensionFromSync(
+ kGoodId, GURL(kGoodUpdateURL), &IsTheme,
+ kGoodInstallSilently, kGoodInitialState,
+ kGoodInitialIncognitoEnabled);
+ EXPECT_TRUE(ContainsKey(service_->pending_extensions(), kGoodId));
+
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+ FilePath path = extensions_path.AppendASCII("good.crx");
+ UpdateExtension(kGoodId, path, UPDATED);
+
+ // TODO(akalin): Figure out how to check that the extensions
+ // directory is cleaned up properly in OnExtensionInstalled().
+
+ EXPECT_FALSE(ContainsKey(service_->pending_extensions(), kGoodId));
+}
+
+// TODO(akalin): Figure out how to test that installs of pending
+// unsyncable extensions are blocked.
+
+// Test updating a pending extension for one that is not pending.
+TEST_F(ExtensionServiceTest, UpdatePendingExtensionNotPending) {
+ InitializeEmptyExtensionService();
+
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+ FilePath path = extensions_path.AppendASCII("good.crx");
+ UpdateExtension(kGoodId, path, UPDATED);
+
+ EXPECT_FALSE(ContainsKey(service_->pending_extensions(), kGoodId));
+}
+
+// Test updating a pending extension for one that is already
+// installed.
+TEST_F(ExtensionServiceTest, UpdatePendingExtensionAlreadyInstalled) {
+ InitializeEmptyExtensionService();
+
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+ FilePath path = extensions_path.AppendASCII("good.crx");
+ InstallExtension(path, true);
+ ASSERT_EQ(1u, service_->extensions()->size());
+ const Extension* good = service_->extensions()->at(0);
+
+ EXPECT_FALSE(good->is_theme());
+
+ // Use AddPendingExtensionInternal() as AddPendingExtension() would
+ // balk.
+ service_->AddPendingExtensionInternal(
+ good->id(), good->update_url(), &IsExtension,
+ kGoodIsFromSync, kGoodInstallSilently, kGoodInitialState,
+ kGoodInitialIncognitoEnabled, Extension::INTERNAL);
+ UpdateExtension(good->id(), path, INSTALLED);
+
+ EXPECT_FALSE(ContainsKey(service_->pending_extensions(), kGoodId));
+}
+
+// Test pref settings for blacklist and unblacklist extensions.
+TEST_F(ExtensionServiceTest, SetUnsetBlacklistInPrefs) {
+ InitializeEmptyExtensionService();
+ std::vector<std::string> blacklist;
+ blacklist.push_back(good0);
+ blacklist.push_back("invalid_id"); // an invalid id
+ blacklist.push_back(good1);
+ service_->UpdateExtensionBlacklist(blacklist);
+ // Make sure pref is updated
+ loop_.RunAllPending();
+
+ // blacklist is set for good0,1,2
+ ValidateBooleanPref(good0, "blacklist", true);
+ ValidateBooleanPref(good1, "blacklist", true);
+ // invalid_id should not be inserted to pref.
+ EXPECT_FALSE(IsPrefExist("invalid_id", "blacklist"));
+
+ // remove good1, add good2
+ blacklist.pop_back();
+ blacklist.push_back(good2);
+
+ service_->UpdateExtensionBlacklist(blacklist);
+ // only good0 and good1 should be set
+ ValidateBooleanPref(good0, "blacklist", true);
+ EXPECT_FALSE(IsPrefExist(good1, "blacklist"));
+ ValidateBooleanPref(good2, "blacklist", true);
+ EXPECT_FALSE(IsPrefExist("invalid_id", "blacklist"));
+}
+
+// Unload installed extension from blacklist.
+TEST_F(ExtensionServiceTest, UnloadBlacklistedExtension) {
+ InitializeEmptyExtensionService();
+ FilePath extensions_path;
+ EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+
+ FilePath path = extensions_path.AppendASCII("good.crx");
+
+ InstallExtension(path, true);
+ const Extension* good = service_->extensions()->at(0);
+ EXPECT_EQ(good_crx, good->id());
+ UpdateExtension(good_crx, path, FAILED_SILENTLY);
+
+ std::vector<std::string> blacklist;
+ blacklist.push_back(good_crx);
+ service_->UpdateExtensionBlacklist(blacklist);
+ // Make sure pref is updated
+ loop_.RunAllPending();
+
+ // Now, the good_crx is blacklisted.
+ ValidateBooleanPref(good_crx, "blacklist", true);
+ EXPECT_EQ(0u, service_->extensions()->size());
+
+ // Remove good_crx from blacklist
+ blacklist.pop_back();
+ service_->UpdateExtensionBlacklist(blacklist);
+ // Make sure pref is updated
+ loop_.RunAllPending();
+ // blacklist value should not be set for good_crx
+ EXPECT_FALSE(IsPrefExist(good_crx, "blacklist"));
+}
+
+// Unload installed extension from blacklist.
+TEST_F(ExtensionServiceTest, BlacklistedExtensionWillNotInstall) {
+ InitializeEmptyExtensionService();
+ std::vector<std::string> blacklist;
+ blacklist.push_back(good_crx);
+ service_->UpdateExtensionBlacklist(blacklist);
+ // Make sure pref is updated
+ loop_.RunAllPending();
+
+ // Now, the good_crx is blacklisted.
+ ValidateBooleanPref(good_crx, "blacklist", true);
+
+ // We can not install good_crx.
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+ FilePath path = extensions_path.AppendASCII("good.crx");
+ service_->InstallExtension(path);
+ loop_.RunAllPending();
+ EXPECT_EQ(0u, service_->extensions()->size());
+ ValidateBooleanPref(good_crx, "blacklist", true);
+}
+
+// Test loading extensions from the profile directory, except
+// blacklisted ones.
+TEST_F(ExtensionServiceTest, WillNotLoadBlacklistedExtensionsFromDirectory) {
+ // Initialize the test dir with a good Preferences/extensions.
+ FilePath source_install_dir;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir));
+ source_install_dir = source_install_dir
+ .AppendASCII("extensions")
+ .AppendASCII("good")
+ .AppendASCII("Extensions");
+ FilePath pref_path = source_install_dir
+ .DirName()
+ .AppendASCII("Preferences");
+ InitializeInstalledExtensionService(pref_path, source_install_dir);
+
+ // Blacklist good1.
+ std::vector<std::string> blacklist;
+ blacklist.push_back(good1);
+ service_->UpdateExtensionBlacklist(blacklist);
+ // Make sure pref is updated
+ loop_.RunAllPending();
+
+ ValidateBooleanPref(good1, "blacklist", true);
+
+ // Load extensions.
+ service_->Init();
+ loop_.RunAllPending();
+
+ std::vector<std::string> errors = GetErrors();
+ for (std::vector<std::string>::iterator err = errors.begin();
+ err != errors.end(); ++err) {
+ LOG(ERROR) << *err;
+ }
+ ASSERT_EQ(2u, loaded_.size());
+
+ EXPECT_NE(std::string(good1), loaded_[0]->id());
+ EXPECT_NE(std::string(good1), loaded_[1]->id());
+}
+
+#if defined(OS_CHROMEOS)
+// Test loading extensions from the profile directory, except
+// ones with a plugin.
+TEST_F(ExtensionServiceTest, WillNotLoadPluginExtensionsFromDirectory) {
+ // Initialize the test dir with a good Preferences/extensions.
+ FilePath source_install_dir;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir));
+ source_install_dir = source_install_dir
+ .AppendASCII("extensions")
+ .AppendASCII("good")
+ .AppendASCII("Extensions");
+ FilePath pref_path = source_install_dir
+ .DirName()
+ .AppendASCII("Preferences");
+ InitializeInstalledExtensionService(pref_path, source_install_dir);
+
+ // good1 contains a plugin.
+ // Load extensions.
+ service_->Init();
+ loop_.RunAllPending();
+
+ std::vector<std::string> errors = GetErrors();
+ for (std::vector<std::string>::iterator err = errors.begin();
+ err != errors.end(); ++err) {
+ LOG(ERROR) << *err;
+ }
+ ASSERT_EQ(2u, loaded_.size());
+
+ EXPECT_NE(std::string(good1), loaded_[0]->id());
+ EXPECT_NE(std::string(good1), loaded_[1]->id());
+}
+#endif
+
+// Will not install extension blacklisted by policy.
+TEST_F(ExtensionServiceTest, BlacklistedByPolicyWillNotInstall) {
+ InitializeEmptyExtensionService();
+
+ ListValue* whitelist =
+ profile_->GetPrefs()->GetMutableList(prefs::kExtensionInstallAllowList);
+ ListValue* blacklist =
+ profile_->GetPrefs()->GetMutableList(prefs::kExtensionInstallDenyList);
+ ASSERT_TRUE(whitelist != NULL && blacklist != NULL);
+
+ // Blacklist everything.
+ blacklist->Append(Value::CreateStringValue("*"));
+
+ // Blacklist prevents us from installing good_crx.
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+ FilePath path = extensions_path.AppendASCII("good.crx");
+ service_->InstallExtension(path);
+ loop_.RunAllPending();
+ EXPECT_EQ(0u, service_->extensions()->size());
+
+ // Now whitelist this particular extension.
+ whitelist->Append(Value::CreateStringValue(good_crx));
+
+ // Ensure we can now install good_crx.
+ service_->InstallExtension(path);
+ loop_.RunAllPending();
+ EXPECT_EQ(1u, service_->extensions()->size());
+}
+
+// Extension blacklisted by policy get unloaded after installing.
+TEST_F(ExtensionServiceTest, BlacklistedByPolicyRemovedIfRunning) {
+ InitializeEmptyExtensionService();
+
+ // Install good_crx.
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+ FilePath path = extensions_path.AppendASCII("good.crx");
+ service_->InstallExtension(path);
+ loop_.RunAllPending();
+ EXPECT_EQ(1u, service_->extensions()->size());
+
+ { // Scope for pref update notification.
+ PrefService* prefs = profile_->GetPrefs();
+ ScopedPrefUpdate pref_update(prefs, prefs::kExtensionInstallDenyList);
+ ListValue* blacklist =
+ prefs->GetMutableList(prefs::kExtensionInstallDenyList);
+ ASSERT_TRUE(blacklist != NULL);
+
+ // Blacklist this extension.
+ blacklist->Append(Value::CreateStringValue(good_crx));
+ prefs->ScheduleSavePersistentPrefs();
+ }
+
+ // Extension should not be running now.
+ loop_.RunAllPending();
+ EXPECT_EQ(0u, service_->extensions()->size());
+}
+
+// Tests disabling extensions
+TEST_F(ExtensionServiceTest, DisableExtension) {
+ InitializeEmptyExtensionService();
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+
+ // A simple extension that should install without error.
+ FilePath path = extensions_path.AppendASCII("good.crx");
+ InstallExtension(path, true);
+
+ const char* extension_id = good_crx;
+ EXPECT_FALSE(service_->extensions()->empty());
+ EXPECT_TRUE(service_->GetExtensionById(extension_id, true) != NULL);
+ EXPECT_TRUE(service_->GetExtensionById(extension_id, false) != NULL);
+ EXPECT_TRUE(service_->disabled_extensions()->empty());
+
+ // Disable it.
+ service_->DisableExtension(extension_id);
+
+ EXPECT_TRUE(service_->extensions()->empty());
+ EXPECT_TRUE(service_->GetExtensionById(extension_id, true) != NULL);
+ EXPECT_FALSE(service_->GetExtensionById(extension_id, false) != NULL);
+ EXPECT_FALSE(service_->disabled_extensions()->empty());
+}
+
+// Tests disabling all extensions (simulating --disable-extensions flag).
+TEST_F(ExtensionServiceTest, DisableAllExtensions) {
+ InitializeEmptyExtensionService();
+
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+
+ FilePath path = extensions_path.AppendASCII("good.crx");
+ InstallExtension(path, true);
+
+ EXPECT_EQ(1u, service_->extensions()->size());
+ EXPECT_EQ(0u, service_->disabled_extensions()->size());
+
+ // Disable extensions.
+ service_->set_extensions_enabled(false);
+ service_->ReloadExtensions();
+
+ // There shouldn't be extensions in either list.
+ EXPECT_EQ(0u, service_->extensions()->size());
+ EXPECT_EQ(0u, service_->disabled_extensions()->size());
+
+ // This shouldn't do anything when all extensions are disabled.
+ service_->EnableExtension(good_crx);
+ service_->ReloadExtensions();
+
+ // There still shouldn't be extensions in either list.
+ EXPECT_EQ(0u, service_->extensions()->size());
+ EXPECT_EQ(0u, service_->disabled_extensions()->size());
+
+ // And then re-enable the extensions.
+ service_->set_extensions_enabled(true);
+ service_->ReloadExtensions();
+
+ EXPECT_EQ(1u, service_->extensions()->size());
+ EXPECT_EQ(0u, service_->disabled_extensions()->size());
+}
+
+// Tests reloading extensions
+TEST_F(ExtensionServiceTest, ReloadExtensions) {
+ InitializeEmptyExtensionService();
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+
+ // Simple extension that should install without error.
+ FilePath path = extensions_path.AppendASCII("good.crx");
+ InstallExtension(path, true);
+ const char* extension_id = good_crx;
+ service_->DisableExtension(extension_id);
+
+ EXPECT_EQ(0u, service_->extensions()->size());
+ EXPECT_EQ(1u, service_->disabled_extensions()->size());
+
+ service_->ReloadExtensions();
+
+ // Extension counts shouldn't change.
+ EXPECT_EQ(0u, service_->extensions()->size());
+ EXPECT_EQ(1u, service_->disabled_extensions()->size());
+
+ service_->EnableExtension(extension_id);
+
+ EXPECT_EQ(1u, service_->extensions()->size());
+ EXPECT_EQ(0u, service_->disabled_extensions()->size());
+
+ // Need to clear |loaded_| manually before reloading as the
+ // EnableExtension() call above inserted into it and
+ // UnloadAllExtensions() doesn't send out notifications.
+ loaded_.clear();
+ service_->ReloadExtensions();
+
+ // Extension counts shouldn't change.
+ EXPECT_EQ(1u, service_->extensions()->size());
+ EXPECT_EQ(0u, service_->disabled_extensions()->size());
+}
+
+// Tests uninstalling normal extensions
+TEST_F(ExtensionServiceTest, UninstallExtension) {
+ InitializeEmptyExtensionService();
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+
+ // A simple extension that should install without error.
+ FilePath path = extensions_path.AppendASCII("good.crx");
+ InstallExtension(path, true);
+
+ // The directory should be there now.
+ const char* extension_id = good_crx;
+ FilePath extension_path = extensions_install_dir_.AppendASCII(extension_id);
+ EXPECT_TRUE(file_util::PathExists(extension_path));
+
+ ValidatePrefKeyCount(1);
+ ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
+ ValidateIntegerPref(good_crx, "location", Extension::INTERNAL);
+
+ // Uninstall it.
+ service_->UninstallExtension(extension_id, false);
+ total_successes_ = 0;
+
+ // We should get an unload notification.
+ ASSERT_TRUE(unloaded_id_.length());
+ EXPECT_EQ(extension_id, unloaded_id_);
+
+ ValidatePrefKeyCount(0);
+
+ // The extension should not be in the service anymore.
+ ASSERT_FALSE(service_->GetExtensionById(extension_id, false));
+ loop_.RunAllPending();
+
+ // The directory should be gone.
+ EXPECT_FALSE(file_util::PathExists(extension_path));
+}
+
+// Tests the uninstaller helper.
+TEST_F(ExtensionServiceTest, UninstallExtensionHelper) {
+ InitializeEmptyExtensionService();
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+
+ // A simple extension that should install without error.
+ FilePath path = extensions_path.AppendASCII("good.crx");
+ InstallExtension(path, true);
+
+ // The directory should be there now.
+ const char* extension_id = good_crx;
+ FilePath extension_path = extensions_install_dir_.AppendASCII(extension_id);
+ EXPECT_TRUE(file_util::PathExists(extension_path));
+
+ bool result = ExtensionService::UninstallExtensionHelper(service_,
+ extension_id);
+ total_successes_ = 0;
+
+ EXPECT_TRUE(result);
+
+ // We should get an unload notification.
+ ASSERT_TRUE(unloaded_id_.length());
+ EXPECT_EQ(extension_id, unloaded_id_);
+
+ ValidatePrefKeyCount(0);
+
+ // The extension should not be in the service anymore.
+ ASSERT_FALSE(service_->GetExtensionById(extension_id, false));
+ loop_.RunAllPending();
+
+ // The directory should be gone.
+ EXPECT_FALSE(file_util::PathExists(extension_path));
+
+ // Attempt to uninstall again. This should fail as we just removed the
+ // extension.
+ result = ExtensionService::UninstallExtensionHelper(service_, extension_id);
+ EXPECT_FALSE(result);
+}
+
+// Verifies extension state is removed upon uninstall
+TEST_F(ExtensionServiceTest, ClearExtensionData) {
+ InitializeEmptyExtensionService();
+
+ // Load a test extension.
+ FilePath path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
+ path = path.AppendASCII("extensions");
+ path = path.AppendASCII("good.crx");
+ InstallExtension(path, true);
+ const Extension* extension = service_->GetExtensionById(good_crx, false);
+ ASSERT_TRUE(extension);
+ GURL ext_url(extension->url());
+ string16 origin_id =
+ webkit_database::DatabaseUtil::GetOriginIdentifier(ext_url);
+
+ // Set a cookie for the extension.
+ net::CookieMonster* cookie_monster = profile_
+ ->GetRequestContextForExtensions()->GetCookieStore()->GetCookieMonster();
+ ASSERT_TRUE(cookie_monster);
+ net::CookieOptions options;
+ cookie_monster->SetCookieWithOptions(ext_url, "dummy=value", options);
+ net::CookieList list = cookie_monster->GetAllCookiesForURL(ext_url);
+ EXPECT_EQ(1U, list.size());
+
+ // Open a database.
+ webkit_database::DatabaseTracker* db_tracker = profile_->GetDatabaseTracker();
+ string16 db_name = UTF8ToUTF16("db");
+ string16 description = UTF8ToUTF16("db_description");
+ int64 size;
+ int64 available;
+ db_tracker->DatabaseOpened(origin_id, db_name, description, 1, &size,
+ &available);
+ db_tracker->DatabaseClosed(origin_id, db_name);
+ std::vector<webkit_database::OriginInfo> origins;
+ db_tracker->GetAllOriginsInfo(&origins);
+ EXPECT_EQ(1U, origins.size());
+ EXPECT_EQ(origin_id, origins[0].GetOrigin());
+
+ // Create local storage. We only simulate this by creating the backing file
+ // since webkit is not initialized.
+ DOMStorageContext* context =
+ profile_->GetWebKitContext()->dom_storage_context();
+ FilePath lso_path = context->GetLocalStorageFilePath(origin_id);
+ EXPECT_TRUE(file_util::CreateDirectory(lso_path.DirName()));
+ EXPECT_EQ(0, file_util::WriteFile(lso_path, NULL, 0));
+ EXPECT_TRUE(file_util::PathExists(lso_path));
+
+ // Create indexed db. Again, it is enough to only simulate this by creating
+ // the file on the disk.
+ IndexedDBContext* idb_context =
+ profile_->GetWebKitContext()->indexed_db_context();
+ FilePath idb_path = idb_context->GetIndexedDBFilePath(origin_id);
+ EXPECT_TRUE(file_util::CreateDirectory(idb_path.DirName()));
+ EXPECT_EQ(0, file_util::WriteFile(idb_path, NULL, 0));
+ EXPECT_TRUE(file_util::PathExists(idb_path));
+
+ // Uninstall the extension.
+ service_->UninstallExtension(good_crx, false);
+ loop_.RunAllPending();
+
+ // Check that the cookie is gone.
+ list = cookie_monster->GetAllCookiesForURL(ext_url);
+ EXPECT_EQ(0U, list.size());
+
+ // The database should have vanished as well.
+ origins.clear();
+ db_tracker->GetAllOriginsInfo(&origins);
+ EXPECT_EQ(0U, origins.size());
+
+ // Check that the LSO file has been removed.
+ EXPECT_FALSE(file_util::PathExists(lso_path));
+
+ // Check if the indexed db has disappeared too.
+ EXPECT_FALSE(file_util::PathExists(idb_path));
+}
+
+// Tests loading single extensions (like --load-extension)
+TEST_F(ExtensionServiceTest, LoadExtension) {
+ InitializeEmptyExtensionService();
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+
+ FilePath ext1 = extensions_path
+ .AppendASCII("good")
+ .AppendASCII("Extensions")
+ .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
+ .AppendASCII("1.0.0.0");
+ service_->LoadExtension(ext1);
+ loop_.RunAllPending();
+ EXPECT_EQ(0u, GetErrors().size());
+ ASSERT_EQ(1u, loaded_.size());
+ EXPECT_EQ(Extension::LOAD, loaded_[0]->location());
+ EXPECT_EQ(1u, service_->extensions()->size());
+
+ ValidatePrefKeyCount(1);
+
+ FilePath no_manifest = extensions_path
+ .AppendASCII("bad")
+ // .AppendASCII("Extensions")
+ .AppendASCII("cccccccccccccccccccccccccccccccc")
+ .AppendASCII("1");
+ service_->LoadExtension(no_manifest);
+ loop_.RunAllPending();
+ EXPECT_EQ(1u, GetErrors().size());
+ ASSERT_EQ(1u, loaded_.size());
+ EXPECT_EQ(1u, service_->extensions()->size());
+
+ // Test uninstall.
+ std::string id = loaded_[0]->id();
+ EXPECT_FALSE(unloaded_id_.length());
+ service_->UninstallExtension(id, false);
+ loop_.RunAllPending();
+ EXPECT_EQ(id, unloaded_id_);
+ ASSERT_EQ(0u, loaded_.size());
+ EXPECT_EQ(0u, service_->extensions()->size());
+}
+
+// Tests that we generate IDs when they are not specified in the manifest for
+// --load-extension.
+TEST_F(ExtensionServiceTest, GenerateID) {
+ InitializeEmptyExtensionService();
+
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions");
+
+ FilePath no_id_ext = extensions_path.AppendASCII("no_id");
+ service_->LoadExtension(no_id_ext);
+ loop_.RunAllPending();
+ EXPECT_EQ(0u, GetErrors().size());
+ ASSERT_EQ(1u, loaded_.size());
+ ASSERT_TRUE(Extension::IdIsValid(loaded_[0]->id()));
+ EXPECT_EQ(loaded_[0]->location(), Extension::LOAD);
+
+ ValidatePrefKeyCount(1);
+
+ std::string previous_id = loaded_[0]->id();
+
+ // If we reload the same path, we should get the same extension ID.
+ service_->LoadExtension(no_id_ext);
+ loop_.RunAllPending();
+ ASSERT_EQ(1u, loaded_.size());
+ ASSERT_EQ(previous_id, loaded_[0]->id());
+}
+
+void ExtensionServiceTest::TestExternalProvider(
+ MockExtensionProvider* provider, Extension::Location location) {
+ // Verify that starting with no providers loads no extensions.
+ service_->Init();
+ loop_.RunAllPending();
+ ASSERT_EQ(0u, loaded_.size());
+
+ provider->set_visit_count(0);
+
+ // Register a test extension externally using the mock registry provider.
+ FilePath source_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_path));
+ source_path = source_path.AppendASCII("extensions").AppendASCII("good.crx");
+
+ // Add the extension.
+ provider->UpdateOrAddExtension(good_crx, "1.0.0.0", source_path);
+
+ // Reloading extensions should find our externally registered extension
+ // and install it.
+ service_->CheckForExternalUpdates();
+ loop_.RunAllPending();
+
+ ASSERT_EQ(0u, GetErrors().size());
+ ASSERT_EQ(1u, loaded_.size());
+ ASSERT_EQ(location, loaded_[0]->location());
+ ASSERT_EQ("1.0.0.0", loaded_[0]->version()->GetString());
+ ValidatePrefKeyCount(1);
+ ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
+ ValidateIntegerPref(good_crx, "location", location);
+
+ // Reload extensions without changing anything. The extension should be
+ // loaded again.
+ loaded_.clear();
+ service_->ReloadExtensions();
+ loop_.RunAllPending();
+ ASSERT_EQ(0u, GetErrors().size());
+ ASSERT_EQ(1u, loaded_.size());
+ ValidatePrefKeyCount(1);
+ ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
+ ValidateIntegerPref(good_crx, "location", location);
+
+ // Now update the extension with a new version. We should get upgraded.
+ source_path = source_path.DirName().AppendASCII("good2.crx");
+ provider->UpdateOrAddExtension(good_crx, "1.0.0.1", source_path);
+
+ loaded_.clear();
+ service_->CheckForExternalUpdates();
+ loop_.RunAllPending();
+ ASSERT_EQ(0u, GetErrors().size());
+ ASSERT_EQ(1u, loaded_.size());
+ ASSERT_EQ("1.0.0.1", loaded_[0]->version()->GetString());
+ ValidatePrefKeyCount(1);
+ ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
+ ValidateIntegerPref(good_crx, "location", location);
+
+ // Uninstall the extension and reload. Nothing should happen because the
+ // preference should prevent us from reinstalling.
+ std::string id = loaded_[0]->id();
+ service_->UninstallExtension(id, false);
+ loop_.RunAllPending();
+
+ // The extension should also be gone from the install directory.
+ FilePath install_path = extensions_install_dir_.AppendASCII(id);
+ ASSERT_FALSE(file_util::PathExists(install_path));
+
+ loaded_.clear();
+ service_->CheckForExternalUpdates();
+ loop_.RunAllPending();
+ ASSERT_EQ(0u, loaded_.size());
+ ValidatePrefKeyCount(1);
+ ValidateIntegerPref(good_crx, "state", Extension::KILLBIT);
+ ValidateIntegerPref(good_crx, "location", location);
+
+ // Now clear the preference and reinstall.
+ SetPrefInteg(good_crx, "state", Extension::ENABLED);
+ profile_->GetPrefs()->ScheduleSavePersistentPrefs();
+
+ loaded_.clear();
+ service_->CheckForExternalUpdates();
+ loop_.RunAllPending();
+ ASSERT_EQ(1u, loaded_.size());
+ ValidatePrefKeyCount(1);
+ ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
+ ValidateIntegerPref(good_crx, "location", location);
+
+ // Now test an externally triggered uninstall (deleting the registry key or
+ // the pref entry).
+ provider->RemoveExtension(good_crx);
+
+ loaded_.clear();
+ service_->UnloadAllExtensions();
+ service_->LoadAllExtensions();
+ loop_.RunAllPending();
+ ASSERT_EQ(0u, loaded_.size());
+ ValidatePrefKeyCount(0);
+
+ // The extension should also be gone from the install directory.
+ ASSERT_FALSE(file_util::PathExists(install_path));
+
+ // Now test the case where user uninstalls and then the extension is removed
+ // from the external provider.
+
+ provider->UpdateOrAddExtension(good_crx, "1.0", source_path);
+ service_->CheckForExternalUpdates();
+ loop_.RunAllPending();
+
+ ASSERT_EQ(1u, loaded_.size());
+ ASSERT_EQ(0u, GetErrors().size());
+
+ // User uninstalls.
+ loaded_.clear();
+ service_->UninstallExtension(id, false);
+ loop_.RunAllPending();
+ ASSERT_EQ(0u, loaded_.size());
+
+ // Then remove the extension from the extension provider.
+ provider->RemoveExtension(good_crx);
+
+ // Should still be at 0.
+ loaded_.clear();
+ service_->LoadAllExtensions();
+ loop_.RunAllPending();
+ ASSERT_EQ(0u, loaded_.size());
+ ValidatePrefKeyCount(1);
+
+ EXPECT_EQ(5, provider->visit_count());
+}
+
+// Tests the external installation feature
+#if defined(OS_WIN)
+TEST_F(ExtensionServiceTest, ExternalInstallRegistry) {
+ // This should all work, even when normal extension installation is disabled.
+ InitializeEmptyExtensionService();
+ set_extensions_enabled(false);
+
+ // Now add providers. Extension system takes ownership of the objects.
+ MockExtensionProvider* reg_provider =
+ new MockExtensionProvider(Extension::EXTERNAL_REGISTRY);
+ AddMockExternalProvider(reg_provider);
+ TestExternalProvider(reg_provider, Extension::EXTERNAL_REGISTRY);
+}
+#endif
+
+TEST_F(ExtensionServiceTest, ExternalInstallPref) {
+ InitializeEmptyExtensionService();
+
+ // Now add providers. Extension system takes ownership of the objects.
+ MockExtensionProvider* pref_provider =
+ new MockExtensionProvider(Extension::EXTERNAL_PREF);
+
+ AddMockExternalProvider(pref_provider);
+ TestExternalProvider(pref_provider, Extension::EXTERNAL_PREF);
+}
+
+TEST_F(ExtensionServiceTest, ExternalInstallPrefUpdateUrl) {
+ // This should all work, even when normal extension installation is disabled.
+ InitializeEmptyExtensionService();
+ set_extensions_enabled(false);
+
+ // TODO(skerner): The mock provider is not a good model of a provider
+ // that works with update URLs, because it adds file and version info.
+ // Extend the mock to work with update URLs. This test checks the
+ // behavior that is common to all external extension visitors. The
+ // browser test ExtensionManagementTest.ExternalUrlUpdate tests that
+ // what the visitor does results in an extension being downloaded and
+ // installed.
+ MockExtensionProvider* pref_provider =
+ new MockExtensionProvider(Extension::EXTERNAL_PREF_DOWNLOAD);
+ AddMockExternalProvider(pref_provider);
+ TestExternalProvider(pref_provider, Extension::EXTERNAL_PREF_DOWNLOAD);
+}
+
+// Tests that external extensions get uninstalled when the external extension
+// providers can't account for them.
+TEST_F(ExtensionServiceTest, ExternalUninstall) {
+ // Start the extensions service with one external extension already installed.
+ FilePath source_install_dir;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir));
+ source_install_dir = source_install_dir
+ .AppendASCII("extensions")
+ .AppendASCII("good")
+ .AppendASCII("Extensions");
+ FilePath pref_path = source_install_dir
+ .DirName()
+ .AppendASCII("PreferencesExternal");
+
+ // This initializes the extensions service with no ExternalExtensionProviders.
+ InitializeInstalledExtensionService(pref_path, source_install_dir);
+ set_extensions_enabled(false);
+
+ service_->Init();
+ loop_.RunAllPending();
+
+ ASSERT_EQ(0u, GetErrors().size());
+ ASSERT_EQ(0u, loaded_.size());
+
+ // Verify that it's not the disabled extensions flag causing it not to load.
+ set_extensions_enabled(true);
+ service_->ReloadExtensions();
+ loop_.RunAllPending();
+
+ ASSERT_EQ(0u, GetErrors().size());
+ ASSERT_EQ(0u, loaded_.size());
+}
+
+TEST_F(ExtensionServiceTest, ExternalPrefProvider) {
+ InitializeEmptyExtensionService();
+ std::string json_data =
+ "{"
+ " \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\": {"
+ " \"external_crx\": \"RandomExtension.crx\","
+ " \"external_version\": \"1.0\""
+ " },"
+ " \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\": {"
+ " \"external_crx\": \"RandomExtension2.crx\","
+ " \"external_version\": \"2.0\""
+ " },"
+ " \"cccccccccccccccccccccccccccccccc\": {"
+ " \"external_update_url\": \"http:\\\\foo.com/update\""
+ " }"
+ "}";
+
+ MockProviderVisitor visitor;
+
+ // Simulate an external_extensions.json file that contains seven invalid
+ // extensions:
+ // - One that is missing the 'external_crx' key.
+ // - One that is missing the 'external_version' key.
+ // - One that is specifying .. in the path.
+ // - One that specifies both a file and update URL.
+ // - One that specifies no file or update URL.
+ // - One that has an update URL that is not well formed.
+ // - One that contains a malformed version.
+ // The final extension is valid, and we check that it is read to make sure
+ // failures don't stop valid records from being read.
+ json_data =
+ "{"
+ " \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\": {"
+ " \"external_version\": \"1.0\""
+ " },"
+ " \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\": {"
+ " \"external_crx\": \"RandomExtension.crx\""
+ " },"
+ " \"cccccccccccccccccccccccccccccccc\": {"
+ " \"external_crx\": \"..\\\\foo\\\\RandomExtension2.crx\","
+ " \"external_version\": \"2.0\""
+ " },"
+ " \"dddddddddddddddddddddddddddddddd\": {"
+ " \"external_crx\": \"RandomExtension2.crx\","
+ " \"external_version\": \"2.0\","
+ " \"external_update_url\": \"http:\\\\foo.com/update\""
+ " },"
+ " \"eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\": {"
+ " },"
+ " \"ffffffffffffffffffffffffffffffff\": {"
+ " \"external_update_url\": \"This string is not a valid URL\""
+ " },"
+ " \"gggggggggggggggggggggggggggggggg\": {"
+ " \"external_crx\": \"RandomExtension3.crx\","
+ " \"external_version\": \"This is not a valid version!\""
+ " },"
+ " \"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh\": {"
+ " \"external_crx\": \"RandomValidExtension.crx\","
+ " \"external_version\": \"1.0\""
+ " }"
+ "}";
+ EXPECT_EQ(1, visitor.Visit(json_data));
+}
+
+// Test loading good extensions from the profile directory.
+TEST_F(ExtensionServiceTest, LoadAndRelocalizeExtensions) {
+ // Initialize the test dir with a good Preferences/extensions.
+ FilePath source_install_dir;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir));
+ source_install_dir = source_install_dir
+ .AppendASCII("extensions")
+ .AppendASCII("l10n");
+ FilePath pref_path = source_install_dir.AppendASCII("Preferences");
+ InitializeInstalledExtensionService(pref_path, source_install_dir);
+
+ service_->Init();
+ loop_.RunAllPending();
+
+ ASSERT_EQ(3u, loaded_.size());
+
+ // This was equal to "sr" on load.
+ ValidateStringPref(loaded_[0]->id(), keys::kCurrentLocale, "en");
+
+ // These are untouched by re-localization.
+ ValidateStringPref(loaded_[1]->id(), keys::kCurrentLocale, "en");
+ EXPECT_FALSE(IsPrefExist(loaded_[1]->id(), keys::kCurrentLocale));
+
+ // This one starts with Serbian name, and gets re-localized into English.
+ EXPECT_EQ("My name is simple.", loaded_[0]->name());
+
+ // These are untouched by re-localization.
+ EXPECT_EQ("My name is simple.", loaded_[1]->name());
+ EXPECT_EQ("no l10n", loaded_[2]->name());
+}
+
+class ExtensionsReadyRecorder : public NotificationObserver {
+ public:
+ ExtensionsReadyRecorder() : ready_(false) {
+ registrar_.Add(this, NotificationType::EXTENSIONS_READY,
+ NotificationService::AllSources());
+ }
+
+ void set_ready(bool value) { ready_ = value; }
+ bool ready() { return ready_; }
+
+ private:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ switch (type.value) {
+ case NotificationType::EXTENSIONS_READY:
+ ready_ = true;
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+
+ NotificationRegistrar registrar_;
+ bool ready_;
+};
+
+// Test that we get enabled/disabled correctly for all the pref/command-line
+// combinations. We don't want to derive from the ExtensionServiceTest class
+// for this test, so we use ExtensionServiceTestSimple.
+//
+// Also tests that we always fire EXTENSIONS_READY, no matter whether we are
+// enabled or not.
+TEST(ExtensionServiceTestSimple, Enabledness) {
+ ExtensionsReadyRecorder recorder;
+ scoped_ptr<TestingProfile> profile(new TestingProfile());
+ MessageLoop loop;
+ BrowserThread ui_thread(BrowserThread::UI, &loop);
+ BrowserThread file_thread(BrowserThread::FILE, &loop);
+ scoped_ptr<CommandLine> command_line;
+ scoped_refptr<ExtensionService> service;
+ FilePath install_dir = profile->GetPath()
+ .AppendASCII(ExtensionService::kInstallDirectoryName);
+
+ // By default, we are enabled.
+ command_line.reset(new CommandLine(CommandLine::NO_PROGRAM));
+ service = profile->CreateExtensionService(command_line.get(),
+ install_dir);
+ EXPECT_TRUE(service->extensions_enabled());
+ service->Init();
+ loop.RunAllPending();
+ EXPECT_TRUE(recorder.ready());
+
+ // If either the command line or pref is set, we are disabled.
+ recorder.set_ready(false);
+ profile.reset(new TestingProfile());
+ command_line->AppendSwitch(switches::kDisableExtensions);
+ service = profile->CreateExtensionService(command_line.get(),
+ install_dir);
+ EXPECT_FALSE(service->extensions_enabled());
+ service->Init();
+ loop.RunAllPending();
+ EXPECT_TRUE(recorder.ready());
+
+ recorder.set_ready(false);
+ profile.reset(new TestingProfile());
+ profile->GetPrefs()->SetBoolean(prefs::kDisableExtensions, true);
+ service = profile->CreateExtensionService(command_line.get(),
+ install_dir);
+ EXPECT_FALSE(service->extensions_enabled());
+ service->Init();
+ loop.RunAllPending();
+ EXPECT_TRUE(recorder.ready());
+
+ recorder.set_ready(false);
+ profile.reset(new TestingProfile());
+ profile->GetPrefs()->SetBoolean(prefs::kDisableExtensions, true);
+ command_line.reset(new CommandLine(CommandLine::NO_PROGRAM));
+ service = profile->CreateExtensionService(command_line.get(),
+ install_dir);
+ EXPECT_FALSE(service->extensions_enabled());
+ service->Init();
+ loop.RunAllPending();
+ EXPECT_TRUE(recorder.ready());
+
+ // Explicitly delete all the resources used in this test.
+ profile.reset();
+ service = NULL;
+}
+
+// Test loading extensions that require limited and unlimited storage quotas.
+TEST_F(ExtensionServiceTest, StorageQuota) {
+ InitializeEmptyExtensionService();
+
+ FilePath extensions_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
+ extensions_path = extensions_path.AppendASCII("extensions")
+ .AppendASCII("storage_quota");
+
+ FilePath limited_quota_ext = extensions_path.AppendASCII("limited_quota")
+ .AppendASCII("1.0");
+
+ // The old permission name for unlimited quota was "unlimited_storage", but
+ // we changed it to "unlimitedStorage". This tests both versions.
+ FilePath unlimited_quota_ext = extensions_path.AppendASCII("unlimited_quota")
+ .AppendASCII("1.0");
+ FilePath unlimited_quota_ext2 = extensions_path.AppendASCII("unlimited_quota")
+ .AppendASCII("2.0");
+ service_->LoadExtension(limited_quota_ext);
+ service_->LoadExtension(unlimited_quota_ext);
+ service_->LoadExtension(unlimited_quota_ext2);
+ loop_.RunAllPending();
+
+ ASSERT_EQ(3u, loaded_.size());
+ EXPECT_TRUE(profile_.get());
+ EXPECT_FALSE(profile_->IsOffTheRecord());
+
+ // Open the database from each origin to make the tracker aware
+ // of the existence of these origins and to get their quotas.
+ int64 limited_quota = -1;
+ int64 unlimited_quota = -1;
+ string16 limited_quota_identifier =
+ webkit_database::DatabaseUtil::GetOriginIdentifier(loaded_[0]->url());
+ string16 unlimited_quota_identifier =
+ webkit_database::DatabaseUtil::GetOriginIdentifier(loaded_[1]->url());
+ string16 unlimited_quota_identifier2 =
+ webkit_database::DatabaseUtil::GetOriginIdentifier(loaded_[2]->url());
+ string16 db_name = UTF8ToUTF16("db");
+ string16 description = UTF8ToUTF16("db_description");
+ int64 database_size;
+ webkit_database::DatabaseTracker* db_tracker = profile_->GetDatabaseTracker();
+
+ // First check the normal limited quota extension.
+ db_tracker->DatabaseOpened(limited_quota_identifier, db_name, description,
+ 1, &database_size, &limited_quota);
+ db_tracker->DatabaseClosed(limited_quota_identifier, db_name);
+ EXPECT_EQ(profile_->GetDatabaseTracker()->GetDefaultQuota(), limited_quota);
+
+ // Now check the two unlimited quota ones.
+ db_tracker->DatabaseOpened(unlimited_quota_identifier, db_name, description,
+ 1, &database_size, &unlimited_quota);
+ db_tracker->DatabaseClosed(unlimited_quota_identifier, db_name);
+ EXPECT_EQ(kint64max, unlimited_quota);
+ db_tracker->DatabaseOpened(unlimited_quota_identifier2, db_name, description,
+ 1, &database_size, &unlimited_quota);
+ db_tracker->DatabaseClosed(unlimited_quota_identifier2, db_name);
+
+ EXPECT_EQ(kint64max, unlimited_quota);
+}
+
+// Tests ExtensionService::register_component_extension().
+TEST_F(ExtensionServiceTest, ComponentExtensions) {
+ InitializeEmptyExtensionService();
+
+ // Component extensions should work even when extensions are disabled.
+ set_extensions_enabled(false);
+
+ FilePath path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
+ path = path.AppendASCII("extensions")
+ .AppendASCII("good")
+ .AppendASCII("Extensions")
+ .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
+ .AppendASCII("1.0.0.0");
+
+ std::string manifest;
+ ASSERT_TRUE(file_util::ReadFileToString(
+ path.Append(Extension::kManifestFilename), &manifest));
+
+ service_->register_component_extension(
+ ExtensionService::ComponentExtensionInfo(manifest, path));
+ service_->Init();
+
+ // Note that we do not pump messages -- the extension should be loaded
+ // immediately.
+
+ EXPECT_EQ(0u, GetErrors().size());
+ ASSERT_EQ(1u, loaded_.size());
+ EXPECT_EQ(Extension::COMPONENT, loaded_[0]->location());
+ EXPECT_EQ(1u, service_->extensions()->size());
+
+ // Component extensions shouldn't get recourded in the prefs.
+ ValidatePrefKeyCount(0);
+
+ // Reload all extensions, and make sure it comes back.
+ std::string extension_id = service_->extensions()->at(0)->id();
+ loaded_.clear();
+ service_->ReloadExtensions();
+ ASSERT_EQ(1u, service_->extensions()->size());
+ EXPECT_EQ(extension_id, service_->extensions()->at(0)->id());
+}
diff --git a/chrome/browser/extensions/extension_service_unittest.h b/chrome/browser/extensions/extension_service_unittest.h
new file mode 100644
index 0000000..8ca7b28
--- /dev/null
+++ b/chrome/browser/extensions/extension_service_unittest.h
@@ -0,0 +1,53 @@
+// 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.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_SERVICE_UNITTEST_H_
+#define CHROME_BROWSER_EXTENSIONS_EXTENSION_SERVICE_UNITTEST_H_
+#pragma once
+
+#include "base/file_path.h"
+#include "base/message_loop.h"
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+#include "base/scoped_temp_dir.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class ExtensionServiceTestBase : public testing::Test {
+ public:
+ ExtensionServiceTestBase();
+ ~ExtensionServiceTestBase();
+
+ virtual void InitializeExtensionService(
+ const FilePath& pref_file, const FilePath& extensions_install_dir);
+
+ virtual void InitializeInstalledExtensionService(
+ const FilePath& prefs_file, const FilePath& source_install_dir);
+
+ virtual void InitializeEmptyExtensionService();
+
+ static void SetUpTestCase();
+
+ virtual void SetUp();
+
+ void set_extensions_enabled(bool enabled) {
+ service_->set_extensions_enabled(enabled);
+ }
+
+ protected:
+ ScopedTempDir temp_dir_;
+ scoped_ptr<Profile> profile_;
+ FilePath extensions_install_dir_;
+ scoped_refptr<ExtensionService> service_;
+ size_t total_successes_;
+ MessageLoop loop_;
+ BrowserThread ui_thread_;
+ BrowserThread db_thread_;
+ BrowserThread webkit_thread_;
+ BrowserThread file_thread_;
+ BrowserThread io_thread_;
+};
+
+#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_SERVICE_UNITTEST_H_
diff --git a/chrome/browser/extensions/extension_sidebar_api.cc b/chrome/browser/extensions/extension_sidebar_api.cc
index 5495a8e..bd32d5a 100644
--- a/chrome/browser/extensions/extension_sidebar_api.cc
+++ b/chrome/browser/extensions/extension_sidebar_api.cc
@@ -10,13 +10,13 @@
#include "base/string16.h"
#include "base/values.h"
#include "chrome/browser/extensions/extension_event_router.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sidebar/sidebar_container.h"
#include "chrome/browser/sidebar/sidebar_manager.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_error_utils.h"
diff --git a/chrome/browser/extensions/extension_startup_browsertest.cc b/chrome/browser/extensions/extension_startup_browsertest.cc
index 97cc84d..25bad91 100644
--- a/chrome/browser/extensions/extension_startup_browsertest.cc
+++ b/chrome/browser/extensions/extension_startup_browsertest.cc
@@ -8,9 +8,9 @@
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/path_service.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/user_script_master.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_paths.h"
@@ -18,7 +18,6 @@
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
@@ -85,7 +84,7 @@ class ExtensionStartupTestBase : public InProcessBrowserTest {
void WaitForServicesToStart(int num_expected_extensions,
bool expect_extensions_enabled) {
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
// Count the number of non-component extensions.
int found_extensions = 0;
@@ -168,7 +167,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionsStartupTest, Test) {
IN_PROC_BROWSER_TEST_F(ExtensionsStartupTest, MAYBE_NoFileAccess) {
WaitForServicesToStart(num_expected_extensions_, true);
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
for (size_t i = 0; i < service->extensions()->size(); ++i) {
if (service->extensions()->at(i)->location() == Extension::COMPONENT)
continue;
diff --git a/chrome/browser/extensions/extension_tabs_apitest.cc b/chrome/browser/extensions/extension_tabs_apitest.cc
index 6ec3e6c..b736777 100644
--- a/chrome/browser/extensions/extension_tabs_apitest.cc
+++ b/chrome/browser/extensions/extension_tabs_apitest.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/pref_names.h"
diff --git a/chrome/browser/extensions/extension_tabs_module.cc b/chrome/browser/extensions/extension_tabs_module.cc
index 169cfff..b58e07c 100644
--- a/chrome/browser/extensions/extension_tabs_module.cc
+++ b/chrome/browser/extensions/extension_tabs_module.cc
@@ -4,6 +4,9 @@
#include "chrome/browser/extensions/extension_tabs_module.h"
+#include <algorithm>
+#include <vector>
+
#include "base/base64.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
@@ -15,21 +18,22 @@
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_infobar_delegate.h"
#include "chrome/browser/extensions/extension_tabs_module_constants.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/backing_store.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_navigator.h"
-#include "chrome/browser/window_sizer.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "chrome/browser/ui/window_sizer.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_error_utils.h"
+#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
#include "gfx/codec/jpeg_codec.h"
#include "gfx/codec/png_codec.h"
@@ -310,6 +314,7 @@ bool GetAllWindowsFunction::RunImpl() {
bool CreateWindowFunction::RunImpl() {
DictionaryValue* args = NULL;
std::vector<GURL> urls;
+ TabContentsWrapper* contents = NULL;
if (HasOptionalArgument(0))
EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
@@ -349,6 +354,29 @@ bool CreateWindowFunction::RunImpl() {
}
}
+ // Look for optional tab id.
+ if (args) {
+ int tab_id;
+ if (args->HasKey(keys::kTabIdKey)) {
+ EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kTabIdKey, &tab_id));
+
+ // Find the tab and detach it from the original window.
+ Browser* source_browser = NULL;
+ TabStripModel* source_tab_strip = NULL;
+ int tab_index = -1;
+ if (!GetTabById(tab_id, profile(), include_incognito(),
+ &source_browser, &source_tab_strip, &contents,
+ &tab_index, &error_))
+ return false;
+ contents = source_tab_strip->DetachTabContentsAt(tab_index);
+ if (!contents) {
+ error_ = ExtensionErrorUtils::FormatErrorMessage(
+ keys::kTabNotFoundError, base::IntToString(tab_id));
+ return false;
+ }
+ }
+ }
+
// Try to position the new browser relative its originating browser window.
gfx::Rect window_bounds;
bool maximized;
@@ -428,8 +456,13 @@ bool CreateWindowFunction::RunImpl() {
Browser* new_window = Browser::CreateForType(window_type, window_profile);
for (std::vector<GURL>::iterator i = urls.begin(); i != urls.end(); ++i)
new_window->AddSelectedTabWithURL(*i, PageTransition::LINK);
- if (urls.size() == 0)
+ if (contents) {
+ TabStripModel* target_tab_strip = new_window->tabstrip_model();
+ target_tab_strip->InsertTabContentsAt(urls.size(), contents,
+ TabStripModel::ADD_NONE);
+ } else if (urls.size() == 0) {
new_window->NewTab();
+ }
new_window->SelectNumberedTab(0);
if (window_type & Browser::TYPE_POPUP)
new_window->window()->SetBounds(popup_bounds);
@@ -517,6 +550,13 @@ bool RemoveWindowFunction::RunImpl() {
if (!browser)
return false;
+ // Don't let the extension remove the window if the user is dragging tabs
+ // in that window.
+ if (!browser->IsTabStripEditable()) {
+ error_ = keys::kTabStripNotEditableError;
+ return false;
+ }
+
browser->CloseWindow();
return true;
@@ -815,8 +855,9 @@ bool MoveTabFunction::RunImpl() {
&tab_index, &error_))
return false;
- if (source_browser->type() != Browser::TYPE_NORMAL) {
- error_ = keys::kCanOnlyMoveTabsWithinNormalWindowsError;
+ // Don't let the extension move the tab if the user is dragging tabs.
+ if (!source_browser->IsTabStripEditable()) {
+ error_ = keys::kTabStripNotEditableError;
return false;
}
@@ -830,6 +871,11 @@ bool MoveTabFunction::RunImpl() {
if (!target_browser)
return false;
+ if (!target_browser->IsTabStripEditable()) {
+ error_ = keys::kTabStripNotEditableError;
+ return false;
+ }
+
if (target_browser->type() != Browser::TYPE_NORMAL) {
error_ = keys::kCanOnlyMoveTabsWithinNormalWindowsError;
return false;
@@ -889,6 +935,12 @@ bool RemoveTabFunction::RunImpl() {
&browser, NULL, &contents, NULL, &error_))
return false;
+ // Don't let the extension remove a tab if the user is dragging tabs around.
+ if (!browser->IsTabStripEditable()) {
+ error_ = keys::kTabStripNotEditableError;
+ return false;
+ }
+
// Close the tab in this convoluted way, since there's a chance that the tab
// is being dragged, or we're in some other nested event loop. This code path
// should ensure that the tab is safely closed under such circumstances,
diff --git a/chrome/browser/extensions/extension_tabs_module.h b/chrome/browser/extensions/extension_tabs_module.h
index 4307c90..7125867 100644
--- a/chrome/browser/extensions/extension_tabs_module.h
+++ b/chrome/browser/extensions/extension_tabs_module.h
@@ -9,7 +9,6 @@
#include <string>
#include "chrome/browser/extensions/extension_function.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
diff --git a/chrome/browser/extensions/extension_tabs_module_constants.cc b/chrome/browser/extensions/extension_tabs_module_constants.cc
index 6405783..6ea521f 100644
--- a/chrome/browser/extensions/extension_tabs_module_constants.cc
+++ b/chrome/browser/extensions/extension_tabs_module_constants.cc
@@ -58,6 +58,8 @@ const char kNoCurrentWindowError[] = "No current window";
const char kNoLastFocusedWindowError[] = "No last-focused window";
const char kWindowNotFoundError[] = "No window with id: *.";
const char kTabNotFoundError[] = "No tab with id: *.";
+const char kTabStripNotEditableError[] =
+ "Tabs cannot be edited right now (user may be dragging a tab).";
const char kNoSelectedTabError[] = "No selected tab";
const char kInvalidUrlError[] = "Invalid url: \"*\".";
const char kInternalVisibleTabCaptureError[] =
diff --git a/chrome/browser/extensions/extension_tabs_module_constants.h b/chrome/browser/extensions/extension_tabs_module_constants.h
index 89c1cd3..4ac09de 100644
--- a/chrome/browser/extensions/extension_tabs_module_constants.h
+++ b/chrome/browser/extensions/extension_tabs_module_constants.h
@@ -61,6 +61,7 @@ extern const char kNoCurrentWindowError[];
extern const char kNoLastFocusedWindowError[];
extern const char kWindowNotFoundError[];
extern const char kTabNotFoundError[];
+extern const char kTabStripNotEditableError[];
extern const char kNoSelectedTabError[];
extern const char kInvalidUrlError[];
extern const char kInternalVisibleTabCaptureError[];
diff --git a/chrome/browser/extensions/extension_test_api.cc b/chrome/browser/extensions/extension_test_api.cc
index eb50391..83800b0 100644
--- a/chrome/browser/extensions/extension_test_api.cc
+++ b/chrome/browser/extensions/extension_test_api.cc
@@ -6,9 +6,10 @@
#include <string>
-#include "chrome/browser/extensions/extensions_service.h"
+#include "base/singleton.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extensions_quota_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/notification_service.h"
@@ -55,7 +56,7 @@ bool ExtensionTestLogFunction::RunImpl() {
ExtensionTestQuotaResetFunction::~ExtensionTestQuotaResetFunction() {}
bool ExtensionTestQuotaResetFunction::RunImpl() {
- ExtensionsService* service = profile()->GetExtensionsService();
+ ExtensionService* service = profile()->GetExtensionService();
ExtensionsQuotaService* quota = service->quota_service();
quota->Purge();
quota->violators_.clear();
@@ -93,17 +94,23 @@ void ExtensionTestSendMessageFunction::Reply(const std::string& message) {
// static
void ExtensionTestGetConfigFunction::set_test_config_state(
DictionaryValue* value) {
- TestConfigState* test_config_state = Singleton<TestConfigState>::get();
+ TestConfigState* test_config_state = TestConfigState::GetInstance();
test_config_state->set_config_state(value);
}
ExtensionTestGetConfigFunction::TestConfigState::TestConfigState()
: config_state_(NULL) {}
+// static
+ExtensionTestGetConfigFunction::TestConfigState*
+ExtensionTestGetConfigFunction::TestConfigState::GetInstance() {
+ return Singleton<TestConfigState>::get();
+}
+
ExtensionTestGetConfigFunction::~ExtensionTestGetConfigFunction() {}
bool ExtensionTestGetConfigFunction::RunImpl() {
- TestConfigState* test_config_state = Singleton<TestConfigState>::get();
+ TestConfigState* test_config_state = TestConfigState::GetInstance();
if (!test_config_state->config_state()) {
error_ = kNoTestConfigDataError;
diff --git a/chrome/browser/extensions/extension_test_api.h b/chrome/browser/extensions/extension_test_api.h
index 27b55dc..1a0baa0 100644
--- a/chrome/browser/extensions/extension_test_api.h
+++ b/chrome/browser/extensions/extension_test_api.h
@@ -6,10 +6,11 @@
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_TEST_API_H_
#pragma once
-#include "base/singleton.h"
#include "base/values.h"
#include "chrome/browser/extensions/extension_function.h"
+template <typename T> struct DefaultSingletonTraits;
+
class ExtensionTestPassFunction : public SyncExtensionFunction {
~ExtensionTestPassFunction();
virtual bool RunImpl();
@@ -65,6 +66,8 @@ class ExtensionTestGetConfigFunction : public SyncExtensionFunction {
// state, owned by the test code.
class TestConfigState {
public:
+ static TestConfigState* GetInstance();
+
void set_config_state(DictionaryValue* config_state) {
config_state_ = config_state;
}
diff --git a/chrome/browser/extensions/extension_toolbar_model.cc b/chrome/browser/extensions/extension_toolbar_model.cc
index 973dba8..3979cbf 100644
--- a/chrome/browser/extensions/extension_toolbar_model.cc
+++ b/chrome/browser/extensions/extension_toolbar_model.cc
@@ -5,14 +5,14 @@
#include "chrome/browser/extensions/extension_toolbar_model.h"
#include "chrome/browser/extensions/extension_prefs.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
-ExtensionToolbarModel::ExtensionToolbarModel(ExtensionsService* service)
+ExtensionToolbarModel::ExtensionToolbarModel(ExtensionService* service)
: service_(service),
prefs_(service->profile()->GetPrefs()),
extensions_initialized_(false) {
@@ -22,8 +22,6 @@ ExtensionToolbarModel::ExtensionToolbarModel(ExtensionsService* service)
Source<Profile>(service_->profile()));
registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
Source<Profile>(service_->profile()));
- registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED,
- Source<Profile>(service_->profile()));
registrar_.Add(this, NotificationType::EXTENSIONS_READY,
Source<Profile>(service_->profile()));
registrar_.Add(this,
@@ -96,7 +94,12 @@ void ExtensionToolbarModel::Observe(NotificationType type,
if (!service_->is_ready())
return;
- const Extension* extension = Details<const Extension>(details).ptr();
+ const Extension* extension = NULL;
+ if (type == NotificationType::EXTENSION_UNLOADED) {
+ extension = Details<UnloadedExtensionInfo>(details)->extension;
+ } else {
+ extension = Details<const Extension>(details).ptr();
+ }
if (type == NotificationType::EXTENSION_LOADED) {
// We don't want to add the same extension twice. It may have already been
// added by EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED below, if the user
@@ -105,9 +108,9 @@ void ExtensionToolbarModel::Observe(NotificationType type,
if (toolitems_[i].get() == extension)
return; // Already exists.
}
- AddExtension(extension);
- } else if (type == NotificationType::EXTENSION_UNLOADED ||
- type == NotificationType::EXTENSION_UNLOADED_DISABLED) {
+ if (service_->GetBrowserActionVisibility(extension))
+ AddExtension(extension);
+ } else if (type == NotificationType::EXTENSION_UNLOADED) {
RemoveExtension(extension);
} else if (type ==
NotificationType::EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED) {
@@ -160,7 +163,7 @@ void ExtensionToolbarModel::RemoveExtension(const Extension* extension) {
}
// Combine the currently enabled extensions that have browser actions (which
-// we get from the ExtensionsService) with the ordering we get from the
+// we get from the ExtensionService) with the ordering we get from the
// pref service. For robustness we use a somewhat inefficient process:
// 1. Create a vector of extensions sorted by their pref values. This vector may
// have holes.
diff --git a/chrome/browser/extensions/extension_toolbar_model.h b/chrome/browser/extensions/extension_toolbar_model.h
index 37c3a08..f782c05 100644
--- a/chrome/browser/extensions/extension_toolbar_model.h
+++ b/chrome/browser/extensions/extension_toolbar_model.h
@@ -11,13 +11,13 @@
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-class ExtensionsService;
+class ExtensionService;
class PrefService;
// Model for the browser actions toolbar.
class ExtensionToolbarModel : public NotificationObserver {
public:
- explicit ExtensionToolbarModel(ExtensionsService* service);
+ explicit ExtensionToolbarModel(ExtensionService* service);
~ExtensionToolbarModel();
// Notifies the toolbar model that the Profile that suplied its
@@ -96,8 +96,8 @@ class ExtensionToolbarModel : public NotificationObserver {
void AddExtension(const Extension* extension);
void RemoveExtension(const Extension* extension);
- // Our ExtensionsService, guaranteed to outlive us.
- ExtensionsService* service_;
+ // Our ExtensionService, guaranteed to outlive us.
+ ExtensionService* service_;
PrefService* prefs_;
diff --git a/chrome/browser/extensions/extension_toolbar_model_browsertest.cc b/chrome/browser/extensions/extension_toolbar_model_browsertest.cc
index 755ac01..951f424 100644
--- a/chrome/browser/extensions/extension_toolbar_model_browsertest.cc
+++ b/chrome/browser/extensions/extension_toolbar_model_browsertest.cc
@@ -3,16 +3,16 @@
// found in the LICENSE file.
#include "chrome/browser/extensions/extension_browsertest.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_toolbar_model.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/in_process_browser_test.h"
// An InProcessBrowserTest for testing the ExtensionToolbarModel.
// TODO(erikkay) It's unfortunate that this needs to be an in-proc browser test.
-// It would be nice to refactor things so that ExtensionsService could run
+// It would be nice to refactor things so that ExtensionService could run
// without so much of the browser in place.
class ExtensionToolbarModelTest : public ExtensionBrowserTest,
public ExtensionToolbarModel::Observer {
@@ -27,7 +27,7 @@ class ExtensionToolbarModelTest : public ExtensionBrowserTest,
virtual Browser* CreateBrowser(Profile* profile) {
Browser* b = InProcessBrowserTest::CreateBrowser(profile);
- ExtensionsService* service = b->profile()->GetExtensionsService();
+ ExtensionService* service = b->profile()->GetExtensionService();
model_ = service->toolbar_model();
model_->AddObserver(this);
return b;
diff --git a/chrome/browser/extensions/extension_tts_api.cc b/chrome/browser/extensions/extension_tts_api.cc
index 1654b07..c618db3 100644
--- a/chrome/browser/extensions/extension_tts_api.cc
+++ b/chrome/browser/extensions/extension_tts_api.cc
@@ -2,22 +2,116 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/extensions/extension_tts_api.h"
-
#include <string>
+#include <vector>
#include "base/float_util.h"
+#include "base/json/json_writer.h"
#include "base/message_loop.h"
#include "base/values.h"
+#include "chrome/browser/extensions/extension_event_router.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_tts_api.h"
+#include "chrome/browser/profiles/profile.h"
namespace util = extension_tts_api_util;
namespace {
-const char kCrosLibraryNotLoadedError[] =
- "Cros shared library not loaded.";
+const char kSpeechInterruptedError[] = "Utterance interrupted.";
+const char kSpeechRemovedFromQueueError[] = "Utterance removed from queue.";
const int kSpeechCheckDelayIntervalMs = 100;
};
+namespace events {
+const char kOnSpeak[] = "experimental.tts.onSpeak";
+const char kOnStop[] = "experimental.tts.onStop";
+}; // namespace events
+
+//
+// ExtensionTtsPlatformImpl
+//
+
+std::string ExtensionTtsPlatformImpl::error() {
+ return error_;
+}
+
+void ExtensionTtsPlatformImpl::clear_error() {
+ error_ = std::string();
+}
+
+void ExtensionTtsPlatformImpl::set_error(const std::string& error) {
+ error_ = error;
+}
+
+//
+// Utterance
+//
+
+// static
+int Utterance::next_utterance_id_ = 0;
+
+Utterance::Utterance(Profile* profile,
+ const std::string& text,
+ DictionaryValue* options,
+ Task* completion_task)
+ : profile_(profile),
+ id_(next_utterance_id_++),
+ text_(text),
+ rate_(-1.0),
+ pitch_(-1.0),
+ volume_(-1.0),
+ can_enqueue_(false),
+ completion_task_(completion_task) {
+ if (!options) {
+ // Use all default options.
+ options_.reset(new DictionaryValue());
+ return;
+ }
+
+ options_.reset(options->DeepCopy());
+
+ if (options->HasKey(util::kVoiceNameKey))
+ options->GetString(util::kVoiceNameKey, &voice_name_);
+
+ if (options->HasKey(util::kLocaleKey))
+ options->GetString(util::kLocaleKey, &locale_);
+
+ if (options->HasKey(util::kGenderKey))
+ options->GetString(util::kGenderKey, &gender_);
+
+ if (util::ReadNumberByKey(options, util::kRateKey, &rate_)) {
+ if (!base::IsFinite(rate_) || rate_ < 0.0 || rate_ > 1.0)
+ rate_ = -1.0;
+ }
+
+ if (util::ReadNumberByKey(options, util::kPitchKey, &pitch_)) {
+ if (!base::IsFinite(pitch_) || pitch_ < 0.0 || pitch_ > 1.0)
+ pitch_ = -1.0;
+ }
+
+ if (util::ReadNumberByKey(options, util::kVolumeKey, &volume_)) {
+ if (!base::IsFinite(volume_) || volume_ < 0.0 || volume_ > 1.0)
+ volume_ = -1.0;
+ }
+
+ if (options->HasKey(util::kEnqueueKey))
+ options->GetBoolean(util::kEnqueueKey, &can_enqueue_);
+}
+
+Utterance::~Utterance() {
+ DCHECK_EQ(completion_task_, static_cast<Task *>(NULL));
+}
+
+void Utterance::FinishAndDestroy() {
+ completion_task_->Run();
+ completion_task_ = NULL;
+ delete this;
+}
+
+//
+// ExtensionTtsController
+//
+
// static
ExtensionTtsController* ExtensionTtsController::GetInstance() {
return Singleton<ExtensionTtsController>::get();
@@ -29,9 +123,13 @@ ExtensionTtsController::ExtensionTtsController()
platform_impl_(NULL) {
}
-void ExtensionTtsController::SpeakOrEnqueue(
- Utterance* utterance, bool can_enqueue) {
- if (IsSpeaking() && can_enqueue) {
+ExtensionTtsController::~ExtensionTtsController() {
+ FinishCurrentUtterance();
+ ClearUtteranceQueue();
+}
+
+void ExtensionTtsController::SpeakOrEnqueue(Utterance* utterance) {
+ if (IsSpeaking() && utterance->can_enqueue()) {
utterance_queue_.push(utterance);
} else {
Stop();
@@ -39,59 +137,167 @@ void ExtensionTtsController::SpeakOrEnqueue(
}
}
+std::string ExtensionTtsController::GetMatchingExtensionId(
+ Utterance* utterance) {
+ ExtensionService* service = utterance->profile()->GetExtensionService();
+ DCHECK(service);
+ ExtensionEventRouter* event_router =
+ utterance->profile()->GetExtensionEventRouter();
+ DCHECK(event_router);
+
+ const ExtensionList* extensions = service->extensions();
+ ExtensionList::const_iterator iter;
+ for (iter = extensions->begin(); iter != extensions->end(); ++iter) {
+ const Extension* extension = *iter;
+
+ if (!event_router->ExtensionHasEventListener(
+ extension->id(), events::kOnSpeak) ||
+ !event_router->ExtensionHasEventListener(
+ extension->id(), events::kOnStop)) {
+ continue;
+ }
+
+ const std::vector<Extension::TtsVoice>& tts_voices =
+ extension->tts_voices();
+ for (size_t i = 0; i < tts_voices.size(); ++i) {
+ const Extension::TtsVoice& voice = tts_voices[i];
+ if (!voice.voice_name.empty() &&
+ !utterance->voice_name().empty() &&
+ voice.voice_name != utterance->voice_name()) {
+ continue;
+ }
+ if (!voice.locale.empty() &&
+ !utterance->locale().empty() &&
+ voice.locale != utterance->locale()) {
+ continue;
+ }
+ if (!voice.gender.empty() &&
+ !utterance->gender().empty() &&
+ voice.gender != utterance->gender()) {
+ continue;
+ }
+
+ return extension->id();
+ }
+ }
+
+ return std::string();
+}
+
void ExtensionTtsController::SpeakNow(Utterance* utterance) {
+ std::string extension_id = GetMatchingExtensionId(utterance);
+ if (!extension_id.empty()) {
+ current_utterance_ = utterance;
+ utterance->set_extension_id(extension_id);
+
+ ListValue args;
+ args.Set(0, Value::CreateStringValue(utterance->text()));
+
+ // Pass through all options to the speech engine, except for
+ // "enqueue", which the speech engine doesn't need to handle.
+ DictionaryValue* options = static_cast<DictionaryValue*>(
+ utterance->options()->DeepCopy());
+ if (options->HasKey(util::kEnqueueKey))
+ options->Remove(util::kEnqueueKey, NULL);
+
+ args.Set(1, options);
+ args.Set(2, Value::CreateIntegerValue(utterance->id()));
+ std::string json_args;
+ base::JSONWriter::Write(&args, false, &json_args);
+
+ utterance->profile()->GetExtensionEventRouter()->DispatchEventToExtension(
+ extension_id,
+ events::kOnSpeak,
+ json_args,
+ utterance->profile(),
+ GURL());
+
+ return;
+ }
+
GetPlatformImpl()->clear_error();
bool success = GetPlatformImpl()->Speak(
- utterance->text,
- utterance->language,
- utterance->gender,
- utterance->rate,
- utterance->pitch,
- utterance->volume);
+ utterance->text(),
+ utterance->locale(),
+ utterance->gender(),
+ utterance->rate(),
+ utterance->pitch(),
+ utterance->volume());
if (!success) {
- utterance->error = GetPlatformImpl()->error();
- utterance->failure_task->Run();
- delete utterance->success_task;
- delete utterance;
+ utterance->set_error(GetPlatformImpl()->error());
+ utterance->FinishAndDestroy();
return;
}
current_utterance_ = utterance;
- // Post a task to check if this utterance has completed after a delay.
- MessageLoop::current()->PostDelayedTask(
- FROM_HERE, method_factory_.NewRunnableMethod(
- &ExtensionTtsController::CheckSpeechStatus),
- kSpeechCheckDelayIntervalMs);
+ // Check to see if it's still speaking; finish the utterance if not and
+ // start polling if so. Checking immediately helps to avoid flaky unit
+ // tests by forcing them to set expectations for IsSpeaking.
+ CheckSpeechStatus();
}
void ExtensionTtsController::Stop() {
- GetPlatformImpl()->clear_error();
- GetPlatformImpl()->StopSpeaking();
+ if (current_utterance_ && !current_utterance_->extension_id().empty()) {
+ current_utterance_->profile()->GetExtensionEventRouter()->
+ DispatchEventToExtension(
+ current_utterance_->extension_id(),
+ events::kOnStop,
+ "[]",
+ current_utterance_->profile(),
+ GURL());
+ } else {
+ GetPlatformImpl()->clear_error();
+ GetPlatformImpl()->StopSpeaking();
+ }
+ if (current_utterance_)
+ current_utterance_->set_error(kSpeechInterruptedError);
FinishCurrentUtterance();
ClearUtteranceQueue();
}
+void ExtensionTtsController::OnSpeechFinished(
+ int request_id, std::string error_message) {
+ // We may sometimes receive completion callbacks "late", after we've
+ // already finished the utterance (for example because another utterance
+ // interrupted or we got a call to Stop). It's also possible that a buggy
+ // extension has called this more than once. In either case it's safe to
+ // just ignore this call.
+ if (!current_utterance_ || request_id != current_utterance_->id())
+ return;
+
+ current_utterance_->set_error(error_message);
+ FinishCurrentUtterance();
+ SpeakNextUtterance();
+}
+
bool ExtensionTtsController::IsSpeaking() const {
return current_utterance_ != NULL;
}
void ExtensionTtsController::FinishCurrentUtterance() {
if (current_utterance_) {
- current_utterance_->success_task->Run();
- delete current_utterance_->failure_task;
- delete current_utterance_;
+ current_utterance_->FinishAndDestroy();
current_utterance_ = NULL;
}
}
+void ExtensionTtsController::SpeakNextUtterance() {
+ // Start speaking the next utterance in the queue. Keep trying in case
+ // one fails but there are still more in the queue to try.
+ while (!utterance_queue_.empty() && !current_utterance_) {
+ Utterance* utterance = utterance_queue_.front();
+ utterance_queue_.pop();
+ SpeakNow(utterance);
+ }
+}
+
void ExtensionTtsController::ClearUtteranceQueue() {
while (!utterance_queue_.empty()) {
Utterance* utterance = utterance_queue_.front();
utterance_queue_.pop();
- utterance->success_task->Run();
- delete utterance->failure_task;
- delete utterance;
+ utterance->set_error(kSpeechRemovedFromQueueError);
+ utterance->FinishAndDestroy();
}
}
@@ -99,21 +305,19 @@ void ExtensionTtsController::CheckSpeechStatus() {
if (!current_utterance_)
return;
+ if (!current_utterance_->extension_id().empty())
+ return;
+
if (GetPlatformImpl()->IsSpeaking() == false) {
FinishCurrentUtterance();
-
- // Start speaking the next utterance in the queue. Keep trying in case
- // one fails but there are still more in the queue to try.
- while (!utterance_queue_.empty() && !current_utterance_) {
- Utterance* utterance = utterance_queue_.front();
- utterance_queue_.pop();
- SpeakNow(utterance);
- }
+ SpeakNextUtterance();
}
// If we're still speaking something (either the prevoius utterance or
// a new utterance), keep calling this method after another delay.
- if (current_utterance_) {
+ // TODO(dmazzoni): get rid of this as soon as all platform implementations
+ // provide completion callbacks rather than only supporting polling.
+ if (current_utterance_ && current_utterance_->extension_id().empty()) {
MessageLoop::current()->PostDelayedTask(
FROM_HERE, method_factory_.NewRunnableMethod(
&ExtensionTtsController::CheckSpeechStatus),
@@ -137,67 +341,25 @@ ExtensionTtsPlatformImpl* ExtensionTtsController::GetPlatformImpl() {
//
bool ExtensionTtsSpeakFunction::RunImpl() {
- utterance_ = new ExtensionTtsController::Utterance();
- bool can_enqueue = false;
-
- DictionaryValue* speak_options = NULL;
- EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &utterance_->text));
-
- if (args_->GetDictionary(1, &speak_options)) {
- if (speak_options->HasKey(util::kLanguageNameKey)) {
- speak_options->GetString(util::kLanguageNameKey, &utterance_->language);
- }
-
- if (speak_options->HasKey(util::kGenderKey)) {
- speak_options->GetString(util::kGenderKey, &utterance_->gender);
- }
-
- if (speak_options->HasKey(util::kEnqueueKey)) {
- speak_options->GetBoolean(util::kEnqueueKey, &can_enqueue);
- }
-
- if (util::ReadNumberByKey(
- speak_options, util::kRateKey, &utterance_->rate)) {
- if (!base::IsFinite(utterance_->rate) ||
- utterance_->rate < 0.0 ||
- utterance_->rate > 1.0) {
- utterance_->rate = -1.0;
- }
- }
-
- if (util::ReadNumberByKey(
- speak_options, util::kPitchKey, &utterance_->pitch)) {
- if (!base::IsFinite(utterance_->pitch) ||
- utterance_->pitch < 0.0 ||
- utterance_->pitch > 1.0) {
- utterance_->pitch = -1.0;
- }
- }
-
- if (util::ReadNumberByKey(
- speak_options, util::kVolumeKey, &utterance_->volume)) {
- if (!base::IsFinite(utterance_->volume) ||
- utterance_->volume < 0.0 ||
- utterance_->volume > 1.0) {
- utterance_->volume = -1.0;
- }
- }
- }
+ std::string text;
+ EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &text));
+ DictionaryValue* options = NULL;
+ if (args_->GetSize() >= 2)
+ EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &options));
+ Task* completion_task = NewRunnableMethod(
+ this, &ExtensionTtsSpeakFunction::SpeechFinished);
+ utterance_ = new Utterance(profile(), text, options, completion_task);
AddRef(); // Balanced in SpeechFinished().
- utterance_->success_task = NewRunnableMethod(
- this, &ExtensionTtsSpeakFunction::SpeechFinished, true);
- utterance_->failure_task = NewRunnableMethod(
- this, &ExtensionTtsSpeakFunction::SpeechFinished, false);
- ExtensionTtsController::GetInstance()->SpeakOrEnqueue(
- utterance_, can_enqueue);
+ ExtensionTtsController::GetInstance()->SpeakOrEnqueue(utterance_);
return true;
}
-void ExtensionTtsSpeakFunction::SpeechFinished(bool success) {
- error_ = utterance_->error;
+void ExtensionTtsSpeakFunction::SpeechFinished() {
+ error_ = utterance_->error();
+ bool success = error_.empty();
SendResponse(success);
- Release(); // Balanced in Speak().
+ Release(); // Balanced in RunImpl().
}
bool ExtensionTtsStopSpeakingFunction::RunImpl() {
@@ -210,3 +372,15 @@ bool ExtensionTtsIsSpeakingFunction::RunImpl() {
ExtensionTtsController::GetInstance()->IsSpeaking()));
return true;
}
+
+bool ExtensionTtsSpeakCompletedFunction::RunImpl() {
+ int request_id;
+ std::string error_message;
+ EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &request_id));
+ if (args_->GetSize() >= 2)
+ EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &error_message));
+ ExtensionTtsController::GetInstance()->OnSpeechFinished(
+ request_id, error_message);
+
+ return true;
+}
diff --git a/chrome/browser/extensions/extension_tts_api.h b/chrome/browser/extensions/extension_tts_api.h
index 0eedcc2..9f7da37 100644
--- a/chrome/browser/extensions/extension_tts_api.h
+++ b/chrome/browser/extensions/extension_tts_api.h
@@ -6,6 +6,7 @@
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_TTS_API_H_
#include <queue>
+#include <string>
#include "base/singleton.h"
#include "base/task.h"
@@ -19,7 +20,7 @@ class ExtensionTtsPlatformImpl {
// Speak the given utterance with the given parameters if possible,
// and return true on success. Utterance will always be nonempty.
- // If the user does not specify the other values, language and gender
+ // If the user does not specify the other values, then locale and gender
// will be empty strings, and rate, pitch, and volume will be -1.0.
//
// The ExtensionTtsController will only try to speak one utterance at
@@ -28,7 +29,7 @@ class ExtensionTtsPlatformImpl {
// returns false before calling Speak again.
virtual bool Speak(
const std::string& utterance,
- const std::string& language,
+ const std::string& locale,
const std::string& gender,
double rate,
double pitch,
@@ -40,9 +41,9 @@ class ExtensionTtsPlatformImpl {
// Return true if the synthesis engine is currently speaking.
virtual bool IsSpeaking() = 0;
- virtual std::string error() { return error_; }
- virtual void clear_error() { error_ = std::string(); }
- virtual void set_error(const std::string& error) { error_ = error; }
+ virtual std::string error();
+ virtual void clear_error();
+ virtual void set_error(const std::string& error);
protected:
ExtensionTtsPlatformImpl() {}
@@ -53,51 +54,108 @@ class ExtensionTtsPlatformImpl {
DISALLOW_COPY_AND_ASSIGN(ExtensionTtsPlatformImpl);
};
+// One speech utterance.
+class Utterance {
+ public:
+ // Construct an utterance given a profile, the text to speak,
+ // the options passed to tts.speak, and a completion task to call
+ // when the utterance is done speaking.
+ Utterance(Profile* profile,
+ const std::string& text,
+ DictionaryValue* options,
+ Task* completion_task);
+ ~Utterance();
+
+ // Calls the completion task and then destroys itself.
+ void FinishAndDestroy();
+
+ void set_error(const std::string& error) { error_ = error; }
+ void set_extension_id(const std::string& extension_id) {
+ extension_id_ = extension_id;
+ }
+
+ // Accessors
+ Profile* profile() { return profile_; }
+ const std::string& extension_id() { return extension_id_; }
+ int id() { return id_; }
+ const std::string& text() { return text_; }
+ const Value* options() { return options_.get(); }
+ const std::string& voice_name() { return voice_name_; }
+ const std::string& locale() { return locale_; }
+ const std::string& gender() { return gender_; }
+ double rate() { return rate_; }
+ double pitch() { return pitch_; }
+ double volume() { return volume_; }
+ bool can_enqueue() { return can_enqueue_; }
+ const std::string& error() { return error_; }
+
+ private:
+ // The profile that initiated this utterance.
+ Profile* profile_;
+
+ // The extension ID of the extension providing TTS for this utterance, or
+ // empty if native TTS is being used.
+ std::string extension_id_;
+
+ // The unique ID of this utterance, used to associate callback functions
+ // with utterances.
+ int id_;
+
+ // The id of the next utterance, so we can associate requests with
+ // responses.
+ static int next_utterance_id_;
+
+ // The text to speak.
+ std::string text_;
+
+ // The full options arg passed to tts.speak, which may include fields
+ // other than the ones we explicitly parse, below.
+ scoped_ptr<Value> options_;
+
+ // The parsed options.
+ std::string voice_name_;
+ std::string locale_;
+ std::string gender_;
+ double rate_;
+ double pitch_;
+ double volume_;
+ bool can_enqueue_;
+
+ // The error string to pass to the completion task. Will be empty if
+ // no error occurred.
+ std::string error_;
+
+ // The method to call when this utterance has completed speaking.
+ Task* completion_task_;
+};
+
// Singleton class that manages text-to-speech.
class ExtensionTtsController {
public:
// Get the single instance of this class.
static ExtensionTtsController* GetInstance();
- struct Utterance {
- Utterance()
- : rate(-1.0),
- pitch(-1.0),
- volume(-1.0),
- success_task(NULL),
- failure_task(NULL) {
- }
-
- std::string text;
- std::string language;
- std::string gender;
- double rate;
- double pitch;
- double volume;
-
- Task* success_task;
- Task* failure_task;
-
- std::string error;
- };
-
// Returns true if we're currently speaking an utterance.
bool IsSpeaking() const;
- // Speak the given utterance. If |can_enqueue| is true and another
- // utterance is in progress, adds it to the end of the queue. Otherwise,
- // interrupts any current utterance and speaks this one immediately.
- void SpeakOrEnqueue(Utterance* utterance, bool can_enqueue);
+ // Speak the given utterance. If the utterance's can_enqueue flag is true
+ // and another utterance is in progress, adds it to the end of the queue.
+ // Otherwise, interrupts any current utterance and speaks this one
+ // immediately.
+ void SpeakOrEnqueue(Utterance* utterance);
// Stop all utterances and flush the queue.
void Stop();
+ // Called when an extension finishes speaking an utterance.
+ void OnSpeechFinished(int request_id, std::string error_message);
+
// For unit testing.
void SetPlatformImpl(ExtensionTtsPlatformImpl* platform_impl);
private:
ExtensionTtsController();
- virtual ~ExtensionTtsController() {}
+ virtual ~ExtensionTtsController();
// Get the platform TTS implementation (or injected mock).
ExtensionTtsPlatformImpl* GetPlatformImpl();
@@ -117,6 +175,14 @@ class ExtensionTtsController {
// Finalize and delete the current utterance.
void FinishCurrentUtterance();
+ // Start speaking the next utterance in the queue.
+ void SpeakNextUtterance();
+
+ // Return the id string of the first extension with tts_voices in its
+ // manifest that matches the speech parameters of this utterance,
+ // or the empty string if none is found.
+ std::string GetMatchingExtensionId(Utterance* utterance);
+
ScopedRunnableMethodFactory<ExtensionTtsController> method_factory_;
friend struct DefaultSingletonTraits<ExtensionTtsController>;
@@ -141,8 +207,8 @@ class ExtensionTtsSpeakFunction : public AsyncExtensionFunction {
private:
~ExtensionTtsSpeakFunction() {}
virtual bool RunImpl();
- void SpeechFinished(bool success);
- ExtensionTtsController::Utterance* utterance_;
+ void SpeechFinished();
+ Utterance* utterance_;
DECLARE_EXTENSION_FUNCTION_NAME("experimental.tts.speak")
};
@@ -160,4 +226,11 @@ class ExtensionTtsIsSpeakingFunction : public SyncExtensionFunction {
DECLARE_EXTENSION_FUNCTION_NAME("experimental.tts.isSpeaking")
};
+class ExtensionTtsSpeakCompletedFunction : public SyncExtensionFunction {
+ private:
+ ~ExtensionTtsSpeakCompletedFunction() {}
+ virtual bool RunImpl();
+ DECLARE_EXTENSION_FUNCTION_NAME("experimental.tts.speakCompleted")
+};
+
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_TTS_API_H_
diff --git a/chrome/browser/extensions/extension_tts_api_chromeos.cc b/chrome/browser/extensions/extension_tts_api_chromeos.cc
index a183612..4e6ce65 100644
--- a/chrome/browser/extensions/extension_tts_api_chromeos.cc
+++ b/chrome/browser/extensions/extension_tts_api_chromeos.cc
@@ -21,7 +21,7 @@ class ExtensionTtsPlatformImplChromeOs : public ExtensionTtsPlatformImpl {
public:
virtual bool Speak(
const std::string& utterance,
- const std::string& language,
+ const std::string& locale,
const std::string& gender,
double rate,
double pitch,
@@ -38,6 +38,10 @@ class ExtensionTtsPlatformImplChromeOs : public ExtensionTtsPlatformImpl {
ExtensionTtsPlatformImplChromeOs() {}
virtual ~ExtensionTtsPlatformImplChromeOs() {}
+ void AppendSpeakOption(std::string key,
+ std::string value,
+ std::string* options);
+
friend struct DefaultSingletonTraits<ExtensionTtsPlatformImplChromeOs>;
DISALLOW_COPY_AND_ASSIGN(ExtensionTtsPlatformImplChromeOs);
@@ -50,7 +54,7 @@ ExtensionTtsPlatformImpl* ExtensionTtsPlatformImpl::GetInstance() {
bool ExtensionTtsPlatformImplChromeOs::Speak(
const std::string& utterance,
- const std::string& language,
+ const std::string& locale,
const std::string& gender,
double rate,
double pitch,
@@ -63,31 +67,41 @@ bool ExtensionTtsPlatformImplChromeOs::Speak(
std::string options;
- if (!language.empty()) {
- util::AppendSpeakOption(
- std::string(util::kNameKey), language, &options);
+ if (!locale.empty()) {
+ AppendSpeakOption(
+ chromeos::SpeechSynthesisLibrary::kSpeechPropertyLocale,
+ locale,
+ &options);
}
if (!gender.empty()) {
- util::AppendSpeakOption(
- std::string(util::kGenderKey), gender, &options);
+ AppendSpeakOption(
+ chromeos::SpeechSynthesisLibrary::kSpeechPropertyGender,
+ gender,
+ &options);
}
if (rate >= 0.0) {
- util::AppendSpeakOption(
- std::string(util::kRateKey), DoubleToString(rate * 5), &options);
+ AppendSpeakOption(
+ chromeos::SpeechSynthesisLibrary::kSpeechPropertyRate,
+ DoubleToString(rate * 5),
+ &options);
}
if (pitch >= 0.0) {
// The TTS service allows a range of 0 to 2 for speech pitch.
- util::AppendSpeakOption(
- std::string(util::kPitchKey), DoubleToString(pitch * 2), &options);
+ AppendSpeakOption(
+ chromeos::SpeechSynthesisLibrary::kSpeechPropertyPitch,
+ DoubleToString(pitch * 2),
+ &options);
}
if (volume >= 0.0) {
// The TTS service allows a range of 0 to 5 for speech volume.
- util::AppendSpeakOption(
- std::string(util::kVolumeKey), DoubleToString(volume * 5), &options);
+ AppendSpeakOption(
+ chromeos::SpeechSynthesisLibrary::kSpeechPropertyVolume,
+ DoubleToString(volume * 5),
+ &options);
}
if (!options.empty()) {
@@ -118,6 +132,17 @@ bool ExtensionTtsPlatformImplChromeOs::IsSpeaking() {
return false;
}
+void ExtensionTtsPlatformImplChromeOs::AppendSpeakOption(
+ std::string key,
+ std::string value,
+ std::string* options) {
+ *options +=
+ key +
+ chromeos::SpeechSynthesisLibrary::kSpeechPropertyEquals +
+ value +
+ chromeos::SpeechSynthesisLibrary::kSpeechPropertyDelimiter;
+}
+
// static
ExtensionTtsPlatformImplChromeOs*
ExtensionTtsPlatformImplChromeOs::GetInstance() {
diff --git a/chrome/browser/extensions/extension_tts_api_util.cc b/chrome/browser/extensions/extension_tts_api_util.cc
index ac5d53b..b3ef18c 100644
--- a/chrome/browser/extensions/extension_tts_api_util.cc
+++ b/chrome/browser/extensions/extension_tts_api_util.cc
@@ -6,6 +6,14 @@
namespace extension_tts_api_util {
+const char kVoiceNameKey[] = "voiceName";
+const char kLocaleKey[] = "locale";
+const char kGenderKey[] = "gender";
+const char kRateKey[] = "rate";
+const char kPitchKey[] = "pitch";
+const char kVolumeKey[] = "volume";
+const char kEnqueueKey[] = "enqueue";
+
// Static.
bool ReadNumberByKey(DictionaryValue* dict,
const char* key,
@@ -28,11 +36,4 @@ bool ReadNumberByKey(DictionaryValue* dict,
return true;
}
-// Static.
-void AppendSpeakOption(std::string key,
- std::string value,
- std::string* options) {
- *options += key + kEqualStr + value + kDelimiter;
-}
-
} // namespace extension_tts_api_util.
diff --git a/chrome/browser/extensions/extension_tts_api_util.h b/chrome/browser/extensions/extension_tts_api_util.h
index cf0d702..9d13e75 100644
--- a/chrome/browser/extensions/extension_tts_api_util.h
+++ b/chrome/browser/extensions/extension_tts_api_util.h
@@ -11,23 +11,17 @@
namespace extension_tts_api_util {
-const char kNameKey[] = "name";
-const char kLanguageNameKey[] = "languageName";
-const char kGenderKey[] = "gender";
-const char kRateKey[] = "rate";
-const char kPitchKey[] = "pitch";
-const char kVolumeKey[] = "volume";
-const char kEnqueueKey[] = "enqueue";
-const char kEqualStr[] = "=";
-const char kDelimiter[] = ";";
+extern const char kVoiceNameKey[];
+extern const char kLocaleKey[];
+extern const char kGenderKey[];
+extern const char kRateKey[];
+extern const char kPitchKey[];
+extern const char kVolumeKey[];
+extern const char kEnqueueKey[];
bool ReadNumberByKey(DictionaryValue* dict,
const char* key,
double* ret_value);
-void AppendSpeakOption(std::string key,
- std::string value,
- std::string* options);
-
} // namespace extension_tts_api_util.
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_TTS_API_UTIL_H_
diff --git a/chrome/browser/extensions/extension_tts_apitest.cc b/chrome/browser/extensions/extension_tts_apitest.cc
index 6f37404..f7ed0d8 100644
--- a/chrome/browser/extensions/extension_tts_apitest.cc
+++ b/chrome/browser/extensions/extension_tts_apitest.cc
@@ -16,6 +16,7 @@
#include "chrome/browser/chromeos/cros/cros_mock.h"
#endif
+using ::testing::AnyNumber;
using ::testing::CreateFunctor;
using ::testing::DoAll;
using ::testing::InSequence;
@@ -28,7 +29,7 @@ class MockExtensionTtsPlatformImpl : public ExtensionTtsPlatformImpl {
public:
MOCK_METHOD6(Speak,
bool(const std::string& utterance,
- const std::string& language,
+ const std::string& locale,
const std::string& gender,
double rate,
double pitch,
@@ -83,11 +84,20 @@ IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakKeepsSpeakingTwice) {
}
IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakInterrupt) {
+ // One utterances starts speaking, and then a second interrupts.
InSequence s;
EXPECT_CALL(mock_platform_impl_, StopSpeaking())
.WillOnce(Return(true));
EXPECT_CALL(mock_platform_impl_, Speak("text 1", _, _, _, _, _))
.WillOnce(Return(true));
+
+ // Ensure that the first utterance keeps going until it's interrupted.
+ EXPECT_CALL(mock_platform_impl_, IsSpeaking())
+ .Times(AnyNumber())
+ .WillRepeatedly(Return(true));
+
+ // Expect the second utterance and allow it to continue for two calls to
+ // IsSpeaking and then finish successfully.
EXPECT_CALL(mock_platform_impl_, StopSpeaking())
.WillOnce(Return(true));
EXPECT_CALL(mock_platform_impl_, Speak("text 2", _, _, _, _, _))
@@ -107,6 +117,14 @@ IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakQueueInterrupt) {
.WillOnce(Return(true));
EXPECT_CALL(mock_platform_impl_, Speak("text 1", _, _, _, _, _))
.WillOnce(Return(true));
+
+ // Ensure that the first utterance keeps going until it's interrupted.
+ EXPECT_CALL(mock_platform_impl_, IsSpeaking())
+ .Times(AnyNumber())
+ .WillRepeatedly(Return(true));
+
+ // Expect the third utterance and allow it to continue for two calls to
+ // IsSpeaking and then finish successfully.
EXPECT_CALL(mock_platform_impl_, StopSpeaking())
.WillOnce(Return(true));
EXPECT_CALL(mock_platform_impl_, Speak("text 3", _, _, _, _, _))
@@ -145,12 +163,16 @@ IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakError) {
.WillOnce(Return(true));
EXPECT_CALL(mock_platform_impl_, IsSpeaking())
.WillOnce(Return(false));
+ EXPECT_CALL(mock_platform_impl_, StopSpeaking())
+ .WillOnce(Return(true));
EXPECT_CALL(mock_platform_impl_, Speak(_, _, _, _, _, _))
.WillOnce(DoAll(
InvokeWithoutArgs(
CreateFunctor(&mock_platform_impl_,
&MockExtensionTtsPlatformImpl::SetErrorToEpicFail)),
Return(false)));
+ EXPECT_CALL(mock_platform_impl_, StopSpeaking())
+ .WillOnce(Return(true));
EXPECT_CALL(mock_platform_impl_, Speak(_, _, _, _, _, _))
.WillOnce(Return(true));
EXPECT_CALL(mock_platform_impl_, IsSpeaking())
@@ -158,6 +180,25 @@ IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakError) {
ASSERT_TRUE(RunExtensionTest("tts/speak_error")) << message_;
}
+IN_PROC_BROWSER_TEST_F(TtsApiTest, Provide) {
+ EXPECT_CALL(mock_platform_impl_, StopSpeaking())
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(mock_platform_impl_, IsSpeaking())
+ .WillRepeatedly(Return(false));
+
+ {
+ InSequence s;
+ EXPECT_CALL(mock_platform_impl_, Speak("native speech", _, _, _, _, _))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_platform_impl_, Speak("native speech 2", _, _, _, _, _))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_platform_impl_, Speak("native speech 3", _, _, _, _, _))
+ .WillOnce(Return(true));
+ }
+
+ ASSERT_TRUE(RunExtensionTest("tts/provide")) << message_;
+}
+
#if defined(OS_CHROMEOS)
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, TtsChromeOs) {
CommandLine::ForCurrentProcess()->AppendSwitch(
diff --git a/chrome/browser/extensions/extension_uitest.cc b/chrome/browser/extensions/extension_uitest.cc
index bc25d75..845696e 100644
--- a/chrome/browser/extensions/extension_uitest.cc
+++ b/chrome/browser/extensions/extension_uitest.cc
@@ -126,15 +126,15 @@ TEST_F(ExtensionTestSimpleApiCall, FLAKY_RunTest) {
namespace keys = extension_automation_constants;
ASSERT_THAT(mock_, testing::NotNull());
- EXPECT_CALL(*mock_, OnDidNavigate(_, _)).Times(1);
- EXPECT_CALL(*mock_, OnNavigationStateChanged(_, _, _))
+ EXPECT_CALL(*mock_, OnDidNavigate(_)).Times(1);
+ EXPECT_CALL(*mock_, OnNavigationStateChanged(_, _))
.Times(testing::AnyNumber());
std::string message_received;
EXPECT_CALL(*mock_, OnForwardMessageToExternalHost(
- _, _, keys::kAutomationOrigin, keys::kAutomationRequestTarget))
+ _, keys::kAutomationOrigin, keys::kAutomationRequestTarget))
.WillOnce(DoAll(
- SaveArg<1>(&message_received),
+ SaveArg<0>(&message_received),
InvokeWithoutArgs(
CreateFunctor(&loop_, &TimedMessageLoopRunner::Quit))));
@@ -277,15 +277,15 @@ TEST_F(ExtensionTestRoundtripApiCall, FLAKY_RunTest) {
namespace keys = extension_automation_constants;
ASSERT_THAT(mock_, testing::NotNull());
- EXPECT_CALL(*mock_, OnDidNavigate(_, _)).Times(1);
- EXPECT_CALL(*mock_, OnNavigationStateChanged(_, _, _))
+ EXPECT_CALL(*mock_, OnDidNavigate(_)).Times(1);
+ EXPECT_CALL(*mock_, OnNavigationStateChanged(_, _))
.Times(testing::AnyNumber());
- EXPECT_CALL(*mock_, OnLoad(_, _)).Times(testing::AnyNumber());
+ EXPECT_CALL(*mock_, OnLoad(_)).Times(testing::AnyNumber());
EXPECT_CALL(*mock_, OnForwardMessageToExternalHost(
- _, _, keys::kAutomationOrigin, keys::kAutomationRequestTarget))
+ _, keys::kAutomationOrigin, keys::kAutomationRequestTarget))
.Times(2)
- .WillRepeatedly(WithArgs<1>(Invoke(
+ .WillRepeatedly(WithArgs<0>(Invoke(
CreateFunctor(this,
&ExtensionTestRoundtripApiCall::CheckAndSendResponse))));
@@ -465,14 +465,14 @@ TEST_F(ExtensionTestBrowserEvents, FLAKY_RunTest) {
namespace keys = extension_automation_constants;
ASSERT_THAT(mock_, testing::NotNull());
- EXPECT_CALL(*mock_, OnDidNavigate(_, _)).Times(1);
- EXPECT_CALL(*mock_, OnNavigationStateChanged(_, _, _))
+ EXPECT_CALL(*mock_, OnDidNavigate(_)).Times(1);
+ EXPECT_CALL(*mock_, OnNavigationStateChanged(_, _))
.Times(testing::AnyNumber());
- EXPECT_CALL(*mock_, OnLoad(_, _)).Times(testing::AnyNumber());
+ EXPECT_CALL(*mock_, OnLoad(_)).Times(testing::AnyNumber());
EXPECT_CALL(*mock_, OnForwardMessageToExternalHost(
- _, _, keys::kAutomationOrigin, _))
- .WillRepeatedly(WithArgs<1, 3>(Invoke(
+ _, keys::kAutomationOrigin, _))
+ .WillRepeatedly(WithArgs<0, 2>(Invoke(
CreateFunctor(this,
&ExtensionTestBrowserEvents::HandleMessageFromChrome))));
diff --git a/chrome/browser/extensions/extension_updater.cc b/chrome/browser/extensions/extension_updater.cc
index 15e26aa..63374ac 100644
--- a/chrome/browser/extensions/extension_updater.cc
+++ b/chrome/browser/extensions/extension_updater.cc
@@ -21,9 +21,9 @@
#include "base/version.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extension_error_reporter.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/utility_process_host.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/chrome_version_info.h"
@@ -190,8 +190,7 @@ void ManifestFetchesBuilder::AddExtension(const Extension& extension) {
AddExtensionData(extension.location(),
extension.id(),
*extension.version(),
- (extension.is_theme() ? PendingExtensionInfo::THEME
- : PendingExtensionInfo::EXTENSION),
+ extension.GetType(),
extension.update_url(), update_url_data);
}
@@ -204,17 +203,20 @@ void ManifestFetchesBuilder::AddPendingExtension(
scoped_ptr<Version> version(
Version::GetVersionFromString("0.0.0.0"));
- AddExtensionData(info.install_source, id, *version,
- info.expected_crx_type, info.update_url, "");
+ AddExtensionData(
+ info.install_source, id, *version,
+ Extension::TYPE_UNKNOWN, info.update_url, "");
}
void ManifestFetchesBuilder::ReportStats() const {
- UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckExtensions",
- url_stats_.google_url_count +
- url_stats_.other_url_count -
- url_stats_.theme_count);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckExtension",
+ url_stats_.extension_count);
UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckTheme",
url_stats_.theme_count);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckApp",
+ url_stats_.app_count);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckPending",
+ url_stats_.pending_count);
UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckGoogleUrl",
url_stats_.google_url_count);
UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateCheckOtherUrl",
@@ -239,7 +241,7 @@ void ManifestFetchesBuilder::AddExtensionData(
Extension::Location location,
const std::string& id,
const Version& version,
- PendingExtensionInfo::ExpectedCrxType crx_type,
+ Extension::Type extension_type,
GURL update_url,
const std::string& update_url_data) {
@@ -272,8 +274,21 @@ void ManifestFetchesBuilder::AddExtensionData(
url_stats_.other_url_count++;
}
- if (crx_type == PendingExtensionInfo::THEME) {
- url_stats_.theme_count++;
+ switch (extension_type) {
+ case Extension::TYPE_THEME:
+ ++url_stats_.theme_count;
+ break;
+ case Extension::TYPE_EXTENSION:
+ case Extension::TYPE_USER_SCRIPT:
+ ++url_stats_.extension_count;
+ break;
+ case Extension::TYPE_HOSTED_APP:
+ case Extension::TYPE_PACKAGED_APP:
+ ++url_stats_.app_count;
+ case Extension::TYPE_UNKNOWN:
+ default:
+ ++url_stats_.pending_count;
+ break;
}
DCHECK(!update_url.is_empty());
@@ -637,7 +652,7 @@ void ExtensionUpdater::OnCRXFetchComplete(const GURL& url,
ProcessBlacklist(data);
} else {
// Successfully fetched - now write crx to a file so we can have the
- // ExtensionsService install it.
+ // ExtensionService install it.
BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
NewRunnableMethod(
@@ -669,7 +684,7 @@ void ExtensionUpdater::OnCRXFileWritten(const std::string& id,
// This can be called after we've been stopped.
if (!alive_)
return;
- // The ExtensionsService is now responsible for cleaning up the temp file
+ // The ExtensionService is now responsible for cleaning up the temp file
// at |path|.
service_->UpdateExtension(id, path, download_url);
}
@@ -701,7 +716,7 @@ void ExtensionUpdater::TimerFired() {
// If the user has overridden the update frequency, don't bother reporting
// this.
- if (frequency_seconds_ == ExtensionsService::kDefaultUpdateFrequencySeconds) {
+ if (frequency_seconds_ == ExtensionService::kDefaultUpdateFrequencySeconds) {
Time last = Time::FromInternalValue(prefs_->GetInt64(
kLastExtensionsUpdateCheck));
if (last.ToInternalValue() != 0) {
@@ -734,7 +749,10 @@ void ExtensionUpdater::CheckNow() {
service_->pending_extensions();
for (PendingExtensionMap::const_iterator iter = pending_extensions.begin();
iter != pending_extensions.end(); ++iter) {
- fetches_builder.AddPendingExtension(iter->first, iter->second);
+ Extension::Location location = iter->second.install_source;
+ if (location != Extension::EXTERNAL_PREF &&
+ location != Extension::EXTERNAL_REGISTRY)
+ fetches_builder.AddPendingExtension(iter->first, iter->second);
}
fetches_builder.ReportStats();
diff --git a/chrome/browser/extensions/extension_updater.h b/chrome/browser/extensions/extension_updater.h
index 041dba0..d9e6a3e 100644
--- a/chrome/browser/extensions/extension_updater.h
+++ b/chrome/browser/extensions/extension_updater.h
@@ -19,7 +19,7 @@
#include "base/task.h"
#include "base/time.h"
#include "base/timer.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/common/extensions/update_manifest.h"
#include "chrome/common/net/url_fetcher.h"
#include "googleurl/src/gurl.h"
@@ -104,15 +104,19 @@ class ManifestFetchesBuilder {
: no_url_count(0),
google_url_count(0),
other_url_count(0),
- theme_count(0) {}
+ extension_count(0),
+ theme_count(0),
+ app_count(0),
+ pending_count(0) {}
- int no_url_count, google_url_count, other_url_count, theme_count;
+ int no_url_count, google_url_count, other_url_count;
+ int extension_count, theme_count, app_count, pending_count;
};
void AddExtensionData(Extension::Location location,
const std::string& id,
const Version& version,
- PendingExtensionInfo::ExpectedCrxType crx_type,
+ Extension::Type extension_type,
GURL update_url,
const std::string& update_url_data);
ExtensionUpdateService* service_;
diff --git a/chrome/browser/extensions/extension_updater_unittest.cc b/chrome/browser/extensions/extension_updater_unittest.cc
index b85d5d8..d501de6 100644
--- a/chrome/browser/extensions/extension_updater_unittest.cc
+++ b/chrome/browser/extensions/extension_updater_unittest.cc
@@ -16,7 +16,7 @@
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/extensions/extension_error_reporter.h"
#include "chrome/browser/extensions/extension_updater.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/test_extension_prefs.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/extensions/extension.h"
@@ -124,22 +124,34 @@ std::string GenerateId(std::string input) {
return result;
}
+bool ShouldInstallExtensionsOnly(const Extension& extension) {
+ return extension.GetType() == Extension::TYPE_EXTENSION;
+}
+
+bool ShouldInstallThemesOnly(const Extension& extension) {
+ return extension.is_theme();
+}
+
+bool ShouldAlwaysInstall(const Extension& extension) {
+ return true;
+}
+
// Creates test pending extensions and inserts them into list. The
// name and version are all based on their index.
void CreateTestPendingExtensions(int count, const GURL& update_url,
PendingExtensionMap* pending_extensions) {
- PendingExtensionInfo::ExpectedCrxType crx_type;
for (int i = 1; i <= count; i++) {
- crx_type = ((i % 2) ? PendingExtensionInfo::EXTENSION
- : PendingExtensionInfo::THEME);
+ ShouldInstallExtensionPredicate should_install_extension =
+ (i % 2 == 0) ? &ShouldInstallThemesOnly :
+ &ShouldInstallExtensionsOnly;
const bool kIsFromSync = true;
const bool kInstallSilently = true;
const Extension::State kInitialState = Extension::ENABLED;
const bool kInitialIncognitoEnabled = false;
std::string id = GenerateId(base::StringPrintf("extension%i", i));
(*pending_extensions)[id] =
- PendingExtensionInfo(update_url, crx_type, kIsFromSync,
- kInstallSilently, kInitialState,
+ PendingExtensionInfo(update_url, should_install_extension,
+ kIsFromSync, kInstallSilently, kInitialState,
kInitialIncognitoEnabled, Extension::INTERNAL);
}
}
@@ -636,15 +648,13 @@ class ExtensionUpdaterTest : public testing::Test {
updater->FetchUpdatedExtension(id, test_url, hash, version->GetString());
if (pending) {
- const PendingExtensionInfo::ExpectedCrxType kExpectedCrxType =
- PendingExtensionInfo::EXTENSION;
const bool kIsFromSync = true;
const bool kInstallSilently = true;
const Extension::State kInitialState = Extension::ENABLED;
const bool kInitialIncognitoEnabled = false;
PendingExtensionMap pending_extensions;
pending_extensions[id] =
- PendingExtensionInfo(test_url, kExpectedCrxType, kIsFromSync,
+ PendingExtensionInfo(test_url, &ShouldAlwaysInstall, kIsFromSync,
kInstallSilently, kInitialState,
kInitialIncognitoEnabled, Extension::INTERNAL);
service.set_pending_extensions(pending_extensions);
@@ -985,14 +995,14 @@ TEST(ExtensionUpdaterTest, TestManifestFetchesBuilderAddExtension) {
// Extensions with invalid update URLs should be rejected.
builder.AddPendingExtension(
GenerateId("foo"), PendingExtensionInfo(GURL("http:google.com:foo"),
- PendingExtensionInfo::EXTENSION,
+ &ShouldInstallExtensionsOnly,
false, false, true, false,
Extension::INTERNAL));
EXPECT_TRUE(builder.GetFetches().empty());
// Extensions with empty IDs should be rejected.
builder.AddPendingExtension(
- "", PendingExtensionInfo(GURL(), PendingExtensionInfo::EXTENSION,
+ "", PendingExtensionInfo(GURL(), &ShouldInstallExtensionsOnly,
false, false, true, false,
Extension::INTERNAL));
EXPECT_TRUE(builder.GetFetches().empty());
@@ -1004,7 +1014,7 @@ TEST(ExtensionUpdaterTest, TestManifestFetchesBuilderAddExtension) {
// filled in.
builder.AddPendingExtension(
GenerateId("foo"), PendingExtensionInfo(GURL(),
- PendingExtensionInfo::EXTENSION,
+ &ShouldInstallExtensionsOnly,
false, false, true, false,
Extension::INTERNAL));
std::vector<ManifestFetchData*> fetches = builder.GetFetches();
diff --git a/chrome/browser/extensions/extension_webglbackground_apitest.cc b/chrome/browser/extensions/extension_webglbackground_apitest.cc
new file mode 100644
index 0000000..9e7701c
--- /dev/null
+++ b/chrome/browser/extensions/extension_webglbackground_apitest.cc
@@ -0,0 +1,9 @@
+// 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.
+
+#include "chrome/browser/extensions/extension_apitest.h"
+
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebGLBackground) {
+ ASSERT_TRUE(RunExtensionTest("webglbackground")) << message_;
+}
diff --git a/chrome/browser/extensions/extension_webnavigation_api.cc b/chrome/browser/extensions/extension_webnavigation_api.cc
index 9a3e4ab..2e3a1ca 100644
--- a/chrome/browser/extensions/extension_webnavigation_api.cc
+++ b/chrome/browser/extensions/extension_webnavigation_api.cc
@@ -12,12 +12,11 @@
#include "chrome/browser/extensions/extension_event_router.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
#include "chrome/browser/extensions/extension_webnavigation_api_constants.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/provisional_load_details.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/notification_service.h"
-#include "chrome/common/url_constants.h"
#include "net/base/net_errors.h"
namespace keys = extension_webnavigation_api_constants;
@@ -37,34 +36,35 @@ double MilliSecondsFromTime(const base::Time& time) {
} // namespace
+
FrameNavigationState::FrameNavigationState() {
}
FrameNavigationState::~FrameNavigationState() {
}
-bool FrameNavigationState::CanSendEvents(long long frame_id) const {
+bool FrameNavigationState::CanSendEvents(int64 frame_id) const {
FrameIdToStateMap::const_iterator frame_state =
frame_state_map_.find(frame_id);
return frame_state != frame_state_map_.end() &&
!frame_state->second.error_occurred;
}
-void FrameNavigationState::TrackFrame(long long frame_id,
+void FrameNavigationState::TrackFrame(int64 frame_id,
const GURL& url,
bool is_main_frame,
+ bool is_error_page,
const TabContents* tab_contents) {
if (is_main_frame)
RemoveTabContentsState(tab_contents);
- tab_contents_map_.insert(
- TabContentsToFrameIdMap::value_type(tab_contents, frame_id));
+ tab_contents_map_.insert(std::make_pair(tab_contents, frame_id));
FrameState& frame_state = frame_state_map_[frame_id];
- frame_state.error_occurred = (url.spec() == chrome::kUnreachableWebDataURL);
+ frame_state.error_occurred = is_error_page;
frame_state.url = url;
frame_state.is_main_frame = is_main_frame;
}
-GURL FrameNavigationState::GetUrl(long long frame_id) const {
+GURL FrameNavigationState::GetUrl(int64 frame_id) const {
FrameIdToStateMap::const_iterator frame_state =
frame_state_map_.find(frame_id);
if (frame_state == frame_state_map_.end()) {
@@ -74,7 +74,7 @@ GURL FrameNavigationState::GetUrl(long long frame_id) const {
return frame_state->second.url;
}
-bool FrameNavigationState::IsMainFrame(long long frame_id) const {
+bool FrameNavigationState::IsMainFrame(int64 frame_id) const {
FrameIdToStateMap::const_iterator frame_state =
frame_state_map_.find(frame_id);
if (frame_state == frame_state_map_.end()) {
@@ -84,7 +84,7 @@ bool FrameNavigationState::IsMainFrame(long long frame_id) const {
return frame_state->second.is_main_frame;
}
-void FrameNavigationState::ErrorOccurredInFrame(long long frame_id) {
+void FrameNavigationState::ErrorOccurredInFrame(int64 frame_id) {
DCHECK(frame_state_map_.find(frame_id) != frame_state_map_.end());
frame_state_map_[frame_id].error_occurred = true;
}
@@ -93,7 +93,7 @@ void FrameNavigationState::RemoveTabContentsState(
const TabContents* tab_contents) {
typedef TabContentsToFrameIdMap::iterator FrameIdIterator;
std::pair<FrameIdIterator, FrameIdIterator> frame_ids =
- tab_contents_map_.equal_range(tab_contents);
+ tab_contents_map_.equal_range(tab_contents);
for (FrameIdIterator frame_id = frame_ids.first; frame_id != frame_ids.second;
++frame_id) {
frame_state_map_.erase(frame_id->second);
@@ -149,19 +149,18 @@ void ExtensionWebNavigationEventRouter::Observe(
case NotificationType::FRAME_DOM_CONTENT_LOADED:
FrameDomContentLoaded(
Source<NavigationController>(source).ptr(),
- *Details<long long>(details).ptr());
+ *Details<int64>(details).ptr());
break;
case NotificationType::FRAME_DID_FINISH_LOAD:
FrameDidFinishLoad(
Source<NavigationController>(source).ptr(),
- *Details<long long>(details).ptr());
+ *Details<int64>(details).ptr());
break;
case NotificationType::FAIL_PROVISIONAL_LOAD_WITH_ERROR:
FailProvisionalLoadWithError(
Source<NavigationController>(source).ptr(),
Details<ProvisionalLoadDetails>(details).ptr());
break;
-
case NotificationType::TAB_CONTENTS_DESTROYED:
navigation_state_.RemoveTabContentsState(
Source<TabContents>(source).ptr());
@@ -177,6 +176,7 @@ void ExtensionWebNavigationEventRouter::FrameProvisionalLoadStart(
navigation_state_.TrackFrame(details->frame_id(),
details->url(),
details->main_frame(),
+ details->is_error_page(),
controller->tab_contents());
if (!navigation_state_.CanSendEvents(details->frame_id()))
return;
@@ -184,8 +184,7 @@ void ExtensionWebNavigationEventRouter::FrameProvisionalLoadStart(
DictionaryValue* dict = new DictionaryValue();
dict->SetInteger(keys::kTabIdKey,
ExtensionTabUtil::GetTabId(controller->tab_contents()));
- dict->SetString(keys::kUrlKey,
- details->url().spec());
+ dict->SetString(keys::kUrlKey, details->url().spec());
dict->SetInteger(keys::kFrameIdKey, GetFrameId(details));
dict->SetInteger(keys::kRequestIdKey, 0);
dict->SetReal(keys::kTimeStampKey, MilliSecondsFromTime(base::Time::Now()));
@@ -205,8 +204,7 @@ void ExtensionWebNavigationEventRouter::FrameProvisionalLoadCommitted(
DictionaryValue* dict = new DictionaryValue();
dict->SetInteger(keys::kTabIdKey,
ExtensionTabUtil::GetTabId(controller->tab_contents()));
- dict->SetString(keys::kUrlKey,
- details->url().spec());
+ dict->SetString(keys::kUrlKey, details->url().spec());
dict->SetInteger(keys::kFrameIdKey, GetFrameId(details));
dict->SetString(keys::kTransitionTypeKey,
PageTransition::CoreTransitionString(
@@ -223,7 +221,8 @@ void ExtensionWebNavigationEventRouter::FrameProvisionalLoadCommitted(
}
void ExtensionWebNavigationEventRouter::FrameDomContentLoaded(
- NavigationController* controller, long long frame_id) {
+ NavigationController* controller,
+ int64 frame_id) {
if (!navigation_state_.CanSendEvents(frame_id))
return;
ListValue args;
@@ -231,8 +230,8 @@ void ExtensionWebNavigationEventRouter::FrameDomContentLoaded(
dict->SetInteger(keys::kTabIdKey,
ExtensionTabUtil::GetTabId(controller->tab_contents()));
dict->SetString(keys::kUrlKey, navigation_state_.GetUrl(frame_id).spec());
- dict->SetInteger(keys::kFrameIdKey, navigation_state_.IsMainFrame(frame_id) ?
- 0 : static_cast<int>(frame_id));
+ dict->SetInteger(keys::kFrameIdKey,
+ navigation_state_.IsMainFrame(frame_id) ? 0 : static_cast<int>(frame_id));
dict->SetReal(keys::kTimeStampKey, MilliSecondsFromTime(base::Time::Now()));
args.Append(dict);
@@ -242,7 +241,8 @@ void ExtensionWebNavigationEventRouter::FrameDomContentLoaded(
}
void ExtensionWebNavigationEventRouter::FrameDidFinishLoad(
- NavigationController* controller, long long frame_id) {
+ NavigationController* controller,
+ int64 frame_id) {
if (!navigation_state_.CanSendEvents(frame_id))
return;
ListValue args;
@@ -250,8 +250,8 @@ void ExtensionWebNavigationEventRouter::FrameDidFinishLoad(
dict->SetInteger(keys::kTabIdKey,
ExtensionTabUtil::GetTabId(controller->tab_contents()));
dict->SetString(keys::kUrlKey, navigation_state_.GetUrl(frame_id).spec());
- dict->SetInteger(keys::kFrameIdKey, navigation_state_.IsMainFrame(frame_id) ?
- 0 : static_cast<int>(frame_id));
+ dict->SetInteger(keys::kFrameIdKey,
+ navigation_state_.IsMainFrame(frame_id) ? 0 : static_cast<int>(frame_id));
dict->SetReal(keys::kTimeStampKey, MilliSecondsFromTime(base::Time::Now()));
args.Append(dict);
@@ -269,8 +269,7 @@ void ExtensionWebNavigationEventRouter::FailProvisionalLoadWithError(
DictionaryValue* dict = new DictionaryValue();
dict->SetInteger(keys::kTabIdKey,
ExtensionTabUtil::GetTabId(controller->tab_contents()));
- dict->SetString(keys::kUrlKey,
- details->url().spec());
+ dict->SetString(keys::kUrlKey, details->url().spec());
dict->SetInteger(keys::kFrameIdKey, GetFrameId(details));
dict->SetString(keys::kErrorKey,
std::string(net::ErrorToString(details->error_code())));
diff --git a/chrome/browser/extensions/extension_webnavigation_api.h b/chrome/browser/extensions/extension_webnavigation_api.h
index b595aca..0f5948e 100644
--- a/chrome/browser/extensions/extension_webnavigation_api.h
+++ b/chrome/browser/extensions/extension_webnavigation_api.h
@@ -22,43 +22,45 @@ class NavigationController;
class ProvisionalLoadDetails;
class TabContents;
-// Tracks which frames are in an error state, and no navigation events should
-// be sent for.
+// Tracks the navigation state of all frames currently known to the
+// webNavigation API. It is mainly used to track in which frames an error
+// occurred so no further events for this frame are being sent.
class FrameNavigationState {
public:
FrameNavigationState();
~FrameNavigationState();
// True if navigation events for the given frame can be sent.
- bool CanSendEvents(long long frame_id) const;
+ bool CanSendEvents(int64 frame_id) const;
// Starts to track a frame given by its |frame_id| showing the URL |url| in
// a |tab_contents|.
- void TrackFrame(long long frame_id,
+ void TrackFrame(int64 frame_id,
const GURL& url,
bool is_main_frame,
+ bool is_error_page,
const TabContents* tab_contents);
// Returns the URL corresponding to a tracked frame given by its |frame_id|.
- GURL GetUrl(long long frame_id) const;
+ GURL GetUrl(int64 frame_id) const;
// True if the frame given by its |frame_id| is the main frame of its tab.
- bool IsMainFrame(long long frame_id) const;
+ bool IsMainFrame(int64 frame_id) const;
// Marks a frame as in an error state.
- void ErrorOccurredInFrame(long long frame_id);
+ void ErrorOccurredInFrame(int64 frame_id);
// Removes state associated with this tab contents and all of its frames.
void RemoveTabContentsState(const TabContents* tab_contents);
private:
- typedef std::multimap<const TabContents*, long long> TabContentsToFrameIdMap;
+ typedef std::multimap<const TabContents*, int64> TabContentsToFrameIdMap;
struct FrameState {
bool error_occurred; // True if an error has occurred in this frame.
bool is_main_frame; // True if this is a main frame.
GURL url; // URL of this frame.
};
- typedef std::map<long long, FrameState> FrameIdToStateMap;
+ typedef std::map<int64, FrameState> FrameIdToStateMap;
// Tracks which frames belong to a given tab contents object.
TabContentsToFrameIdMap tab_contents_map_;
@@ -69,13 +71,16 @@ class FrameNavigationState {
DISALLOW_COPY_AND_ASSIGN(FrameNavigationState);
};
+
// Observes navigation notifications and routes them as events to the extension
// system.
class ExtensionWebNavigationEventRouter : public NotificationObserver {
public:
- // Single instance of the event router.
+ // Returns the singleton instance of the event router.
static ExtensionWebNavigationEventRouter* GetInstance();
+ // Invoked by the extensions service once the extension system is fully set
+ // up and can start dispatching events to extensions.
void Init();
private:
@@ -104,11 +109,11 @@ class ExtensionWebNavigationEventRouter : public NotificationObserver {
// Handler for the FRAME_DOM_CONTENT_LOADED event. The method takes the frame
// ID and constructs a suitable JSON formatted extension event from it.
void FrameDomContentLoaded(NavigationController* controller,
- long long frame_id);
+ int64 frame_id);
// Handler for the FRAME_DID_FINISH_LOAD event. The method takes the frame
// ID and constructs a suitable JSON formatted extension event from it.
- void FrameDidFinishLoad(NavigationController* controller, long long frame_id);
+ void FrameDidFinishLoad(NavigationController* controller, int64 frame_id);
// Handler for the FAIL_PROVISIONAL_LOAD_WITH_ERROR event. The method takes
// the details of such an event and constructs a suitable JSON formatted
@@ -116,7 +121,7 @@ class ExtensionWebNavigationEventRouter : public NotificationObserver {
void FailProvisionalLoadWithError(NavigationController* controller,
ProvisionalLoadDetails* details);
- // This method dispatches events to the extension message service.
+ // Dispatches events to the extension message service.
void DispatchEvent(Profile* context,
const char* event_name,
const std::string& json_args);
diff --git a/chrome/browser/extensions/extension_webnavigation_apitest.cc b/chrome/browser/extensions/extension_webnavigation_apitest.cc
index b27887b..8e833b0 100644
--- a/chrome/browser/extensions/extension_webnavigation_apitest.cc
+++ b/chrome/browser/extensions/extension_webnavigation_apitest.cc
@@ -6,6 +6,7 @@
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/common/chrome_switches.h"
+
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WebNavigation) {
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableExperimentalExtensionApis);
diff --git a/chrome/browser/extensions/extension_webnavigation_unittest.cc b/chrome/browser/extensions/extension_webnavigation_unittest.cc
index 5ac378e..cfeada0 100644
--- a/chrome/browser/extensions/extension_webnavigation_unittest.cc
+++ b/chrome/browser/extensions/extension_webnavigation_unittest.cc
@@ -8,13 +8,12 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "base/values.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/extensions/extension_webnavigation_api.h"
#include "chrome/browser/renderer_host/test/test_render_view_host.h"
#include "chrome/browser/tab_contents/test_tab_contents.h"
-#include "chrome/common/url_constants.h"
#include "chrome/test/testing_profile.h"
+
class FrameNavigationStateTest : public RenderViewHostTestHarness {
};
@@ -22,19 +21,19 @@ class FrameNavigationStateTest : public RenderViewHostTestHarness {
// goes away.
TEST_F(FrameNavigationStateTest, TrackFrame) {
FrameNavigationState navigation_state;
- const long long frame_id1 = 23;
- const long long frame_id2 = 42;
+ const int64 frame_id1 = 23;
+ const int64 frame_id2 = 42;
const GURL url1("http://www.google.com/");
const GURL url2("http://mail.google.com/");
// Create a main frame.
EXPECT_FALSE(navigation_state.CanSendEvents(frame_id1));
- navigation_state.TrackFrame(frame_id1, url1, true, contents());
+ navigation_state.TrackFrame(frame_id1, url1, true, false, contents());
EXPECT_TRUE(navigation_state.CanSendEvents(frame_id1));
// Add a sub frame.
EXPECT_FALSE(navigation_state.CanSendEvents(frame_id2));
- navigation_state.TrackFrame(frame_id2, url2, false, contents());
+ navigation_state.TrackFrame(frame_id2, url2, false, false, contents());
EXPECT_TRUE(navigation_state.CanSendEvents(frame_id2));
// Check frame state.
@@ -54,23 +53,22 @@ TEST_F(FrameNavigationStateTest, TrackFrame) {
// before a new navigation happened in this frame.
TEST_F(FrameNavigationStateTest, ErrorState) {
FrameNavigationState navigation_state;
- const long long frame_id = 42;
+ const int64 frame_id = 42;
const GURL url("http://www.google.com/");
- navigation_state.TrackFrame(frame_id, url, true, contents());
+ navigation_state.TrackFrame(frame_id, url, true, false, contents());
EXPECT_TRUE(navigation_state.CanSendEvents(frame_id));
// After an error occurred, no further events should be sent.
navigation_state.ErrorOccurredInFrame(frame_id);
EXPECT_FALSE(navigation_state.CanSendEvents(frame_id));
- // Navigations to the "unreachable web data" URL should be ignored.
- navigation_state.TrackFrame(
- frame_id, GURL(chrome::kUnreachableWebDataURL), true, contents());
+ // Navigations to a network error page should be ignored.
+ navigation_state.TrackFrame(frame_id, GURL(), true, true, contents());
EXPECT_FALSE(navigation_state.CanSendEvents(frame_id));
// However, when the frame navigates again, it should send events again.
- navigation_state.TrackFrame(frame_id, url, true, contents());
+ navigation_state.TrackFrame(frame_id, url, true, false, contents());
EXPECT_TRUE(navigation_state.CanSendEvents(frame_id));
}
@@ -78,12 +76,12 @@ TEST_F(FrameNavigationStateTest, ErrorState) {
// before a new navigation happened in this frame.
TEST_F(FrameNavigationStateTest, ErrorStateFrame) {
FrameNavigationState navigation_state;
- const long long frame_id1 = 23;
- const long long frame_id2 = 42;
+ const int64 frame_id1 = 23;
+ const int64 frame_id2 = 42;
const GURL url("http://www.google.com/");
- navigation_state.TrackFrame(frame_id1, url, true, contents());
- navigation_state.TrackFrame(frame_id2, url, false, contents());
+ navigation_state.TrackFrame(frame_id1, url, true, false, contents());
+ navigation_state.TrackFrame(frame_id2, url, false, false, contents());
EXPECT_TRUE(navigation_state.CanSendEvents(frame_id1));
EXPECT_TRUE(navigation_state.CanSendEvents(frame_id2));
@@ -92,14 +90,13 @@ TEST_F(FrameNavigationStateTest, ErrorStateFrame) {
EXPECT_TRUE(navigation_state.CanSendEvents(frame_id1));
EXPECT_FALSE(navigation_state.CanSendEvents(frame_id2));
- // Navigations to the "unreachable web data" URL should be ignored.
- navigation_state.TrackFrame(
- frame_id2, GURL(chrome::kUnreachableWebDataURL), false, contents());
+ // Navigations to a network error page should be ignored.
+ navigation_state.TrackFrame(frame_id2, GURL(), false, true, contents());
EXPECT_TRUE(navigation_state.CanSendEvents(frame_id1));
EXPECT_FALSE(navigation_state.CanSendEvents(frame_id2));
// However, when the frame navigates again, it should send events again.
- navigation_state.TrackFrame(frame_id2, url, false, contents());
+ navigation_state.TrackFrame(frame_id2, url, false, false, contents());
EXPECT_TRUE(navigation_state.CanSendEvents(frame_id1));
EXPECT_TRUE(navigation_state.CanSendEvents(frame_id2));
}
diff --git a/chrome/browser/extensions/extension_webstore_private_api.cc b/chrome/browser/extensions/extension_webstore_private_api.cc
index 468ae14..32b7c65 100644
--- a/chrome/browser/extensions/extension_webstore_private_api.cc
+++ b/chrome/browser/extensions/extension_webstore_private_api.cc
@@ -13,16 +13,17 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/crx_installer.h"
#include "chrome/browser/extensions/extension_prefs.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/net/gaia/token_service.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_error_utils.h"
#include "chrome/common/net/gaia/gaia_constants.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
@@ -58,7 +59,7 @@ BrowserSignin* GetBrowserSignin(Profile* profile) {
}
bool IsWebStoreURL(Profile* profile, const GURL& url) {
- ExtensionsService* service = profile->GetExtensionsService();
+ ExtensionService* service = profile->GetExtensionService();
const Extension* store = service->GetWebStoreApp();
if (!store) {
NOTREACHED();
@@ -185,7 +186,7 @@ bool GetBrowserLoginFunction::RunImpl() {
bool GetStoreLoginFunction::RunImpl() {
if (!IsWebStoreURL(profile_, source_url()))
return false;
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
ExtensionPrefs* prefs = service->extension_prefs();
std::string login;
if (prefs->GetWebStoreLogin(&login)) {
@@ -201,7 +202,7 @@ bool SetStoreLoginFunction::RunImpl() {
return false;
std::string login;
EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &login));
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
ExtensionPrefs* prefs = service->extension_prefs();
prefs->SetWebStoreLogin(login);
return true;
diff --git a/chrome/browser/extensions/extension_webstore_private_browsertest.cc b/chrome/browser/extensions/extension_webstore_private_browsertest.cc
index 01b8e45..3ed1383 100644
--- a/chrome/browser/extensions/extension_webstore_private_browsertest.cc
+++ b/chrome/browser/extensions/extension_webstore_private_browsertest.cc
@@ -10,7 +10,7 @@
#include "chrome/browser/extensions/extension_test_message_listener.h"
#include "chrome/browser/extensions/extension_webstore_private_api.h"
#include "chrome/browser/net/gaia/token_service.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_switches.h"
diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc
deleted file mode 100644
index 6842a84..0000000
--- a/chrome/browser/extensions/extensions_service.cc
+++ /dev/null
@@ -1,2067 +0,0 @@
-// 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.
-
-#include "chrome/browser/extensions/extensions_service.h"
-
-#include <algorithm>
-
-#include "base/basictypes.h"
-#include "base/command_line.h"
-#include "base/file_util.h"
-#include "base/metrics/histogram.h"
-#include "base/stl_util-inl.h"
-#include "base/string16.h"
-#include "base/string_number_conversions.h"
-#include "base/string_util.h"
-#include "base/stringprintf.h"
-#include "base/thread_restrictions.h"
-#include "base/time.h"
-#include "base/utf_string_conversions.h"
-#include "base/values.h"
-#include "base/values_util.h"
-#include "base/version.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/themes/browser_theme_provider.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/debugger/devtools_manager.h"
-#include "chrome/browser/dom_ui/shown_sections_handler.h"
-#include "chrome/browser/extensions/crx_installer.h"
-#include "chrome/browser/extensions/default_apps.h"
-#include "chrome/browser/extensions/extension_accessibility_api.h"
-#include "chrome/browser/extensions/extension_bookmarks_module.h"
-#include "chrome/browser/extensions/extension_browser_event_router.h"
-#include "chrome/browser/extensions/extension_cookies_api.h"
-#include "chrome/browser/extensions/extension_data_deleter.h"
-#include "chrome/browser/extensions/extension_dom_ui.h"
-#include "chrome/browser/extensions/extension_error_reporter.h"
-#include "chrome/browser/extensions/extension_history_api.h"
-#include "chrome/browser/extensions/extension_host.h"
-#include "chrome/browser/extensions/extension_management_api.h"
-#include "chrome/browser/extensions/extension_process_manager.h"
-#include "chrome/browser/extensions/extension_processes_api.h"
-#include "chrome/browser/extensions/extension_updater.h"
-#include "chrome/browser/extensions/extension_webnavigation_api.h"
-#include "chrome/browser/extensions/external_extension_provider.h"
-#include "chrome/browser/extensions/external_policy_extension_provider.h"
-#include "chrome/browser/extensions/external_pref_extension_provider.h"
-#include "chrome/browser/net/chrome_url_request_context.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/search_engines/template_url_model.h"
-#include "chrome/browser/sync/glue/extension_sync_traits.h"
-#include "chrome/browser/sync/glue/extension_util.h"
-#include "chrome/common/child_process_logging.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_constants.h"
-#include "chrome/common/extensions/extension_error_utils.h"
-#include "chrome/common/extensions/extension_file_util.h"
-#include "chrome/common/extensions/extension_l10n_util.h"
-#include "chrome/common/extensions/extension_resource.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/notification_type.h"
-#include "chrome/common/json_value_serializer.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/url_constants.h"
-#include "googleurl/src/gurl.h"
-#include "net/base/registry_controlled_domain.h"
-#include "webkit/database/database_tracker.h"
-#include "webkit/database/database_util.h"
-
-#if defined(OS_WIN)
-#include "chrome/browser/extensions/external_registry_extension_provider_win.h"
-#endif
-
-using base::Time;
-
-namespace errors = extension_manifest_errors;
-
-namespace {
-
-#if defined(OS_LINUX)
-static const int kOmniboxIconPaddingLeft = 2;
-static const int kOmniboxIconPaddingRight = 2;
-#elif defined(OS_MACOSX)
-static const int kOmniboxIconPaddingLeft = 0;
-static const int kOmniboxIconPaddingRight = 2;
-#else
-static const int kOmniboxIconPaddingLeft = 0;
-static const int kOmniboxIconPaddingRight = 0;
-#endif
-
-// The following enumeration is used in histograms matching
-// Extensions.ManifestReload* . Values may be added, as long
-// as existing values are not changed.
-enum ManifestReloadReason {
- NOT_NEEDED = 0, // Reload not needed.
- UNPACKED_DIR, // Unpacked directory
- NEEDS_RELOCALIZATION, // The local has changed since we read this extension.
- NUM_MANIFEST_RELOAD_REASONS
-};
-
-ManifestReloadReason ShouldReloadExtensionManifest(const ExtensionInfo& info) {
- // Always reload manifests of unpacked extensions, because they can change
- // on disk independent of the manifest in our prefs.
- if (info.extension_location == Extension::LOAD)
- return UNPACKED_DIR;
-
- // Reload the manifest if it needs to be relocalized.
- if (extension_l10n_util::ShouldRelocalizeManifest(info))
- return NEEDS_RELOCALIZATION;
-
- return NOT_NEEDED;
-}
-
-void GetExplicitOriginsInExtent(const Extension* extension,
- std::vector<GURL>* origins) {
- typedef std::vector<URLPattern> PatternList;
- std::set<GURL> set;
- const PatternList& patterns = extension->web_extent().patterns();
- for (PatternList::const_iterator pattern = patterns.begin();
- pattern != patterns.end(); ++pattern) {
- if (pattern->match_subdomains() || pattern->match_all_urls())
- continue;
- // Wildcard URL schemes won't parse into a valid GURL, so explicit schemes
- // must be used.
- PatternList explicit_patterns = pattern->ConvertToExplicitSchemes();
- for (PatternList::const_iterator explicit_p = explicit_patterns.begin();
- explicit_p != explicit_patterns.end(); ++explicit_p) {
- GURL origin = GURL(explicit_p->GetAsString()).GetOrigin();
- if (origin.is_valid()) {
- set.insert(origin);
- } else {
- NOTREACHED();
- }
- }
- }
-
- for (std::set<GURL>::const_iterator unique = set.begin();
- unique != set.end(); ++unique) {
- origins->push_back(*unique);
- }
-}
-
-} // namespace
-
-PendingExtensionInfo::PendingExtensionInfo(
- const GURL& update_url,
- PendingExtensionInfo::ExpectedCrxType expected_crx_type,
- bool is_from_sync,
- bool install_silently,
- bool enable_on_install,
- bool enable_incognito_on_install,
- Extension::Location location)
- : update_url(update_url),
- expected_crx_type(expected_crx_type),
- is_from_sync(is_from_sync),
- install_silently(install_silently),
- enable_on_install(enable_on_install),
- enable_incognito_on_install(enable_incognito_on_install),
- install_source(location) {}
-
-PendingExtensionInfo::PendingExtensionInfo()
- : update_url(),
- expected_crx_type(PendingExtensionInfo::UNKNOWN),
- is_from_sync(true),
- install_silently(false),
- enable_on_install(false),
- enable_incognito_on_install(false),
- install_source(Extension::INVALID) {}
-
-
-ExtensionsService::ExtensionRuntimeData::ExtensionRuntimeData()
- : background_page_ready(false),
- being_upgraded(false) {
-}
-
-ExtensionsService::ExtensionRuntimeData::~ExtensionRuntimeData() {
-}
-
-// ExtensionsService.
-
-const char* ExtensionsService::kInstallDirectoryName = "Extensions";
-const char* ExtensionsService::kCurrentVersionFileName = "Current Version";
-
-// Implements IO for the ExtensionsService.
-
-class ExtensionsServiceBackend
- : public base::RefCountedThreadSafe<ExtensionsServiceBackend>,
- public ExternalExtensionProvider::Visitor {
- public:
- // |install_directory| is a path where to look for extensions to load.
- ExtensionsServiceBackend(PrefService* prefs,
- const FilePath& install_directory);
-
- // Loads a single extension from |path| where |path| is the top directory of
- // a specific extension where its manifest file lives.
- // Errors are reported through ExtensionErrorReporter. On success,
- // OnExtensionLoaded() is called.
- // TODO(erikkay): It might be useful to be able to load a packed extension
- // (presumably into memory) without installing it.
- void LoadSingleExtension(const FilePath &path,
- scoped_refptr<ExtensionsService> frontend);
-
- // Check externally updated extensions for updates and install if necessary.
- // Errors are reported through ExtensionErrorReporter. Succcess is not
- // reported.
- void CheckForExternalUpdates(const std::set<std::string>& ids_to_ignore,
- scoped_refptr<ExtensionsService> frontend);
-
- // For the extension in |version_path| with |id|, check to see if it's an
- // externally managed extension. If so, tell the frontend to uninstall it.
- void CheckExternalUninstall(scoped_refptr<ExtensionsService> frontend,
- const std::string& id);
-
- // Clear all ExternalExtensionProviders.
- void ClearProvidersForTesting();
-
- // Adds an ExternalExtensionProvider for the service to use during testing.
- // Takes ownership of |test_provider|.
- void AddProviderForTesting(ExternalExtensionProvider* test_provider);
-
- // ExternalExtensionProvider::Visitor implementation.
- virtual void OnExternalExtensionFileFound(const std::string& id,
- const Version* version,
- const FilePath& path,
- Extension::Location location);
-
- virtual void OnExternalExtensionUpdateUrlFound(const std::string& id,
- const GURL& update_url,
- Extension::Location location);
-
- virtual void UpdateExternalPolicyExtensionProvider(
- scoped_refptr<RefCountedList> forcelist);
-
- private:
- friend class base::RefCountedThreadSafe<ExtensionsServiceBackend>;
-
- virtual ~ExtensionsServiceBackend();
-
- // Finish installing the extension in |crx_path| after it has been unpacked to
- // |unpacked_path|. If |expected_id| is not empty, it's verified against the
- // extension's manifest before installation. If |silent| is true, there will
- // be no install confirmation dialog. |from_gallery| indicates whether the
- // crx was installed from our gallery, which results in different UI.
- //
- // Note: We take ownership of |extension|.
- void OnExtensionUnpacked(const FilePath& crx_path,
- const FilePath& unpacked_path,
- const Extension* extension,
- const std::string expected_id);
-
- // Notify the frontend that there was an error loading an extension.
- void ReportExtensionLoadError(const FilePath& extension_path,
- const std::string& error);
-
- // This is a naked pointer which is set by each entry point.
- // The entry point is responsible for ensuring lifetime.
- ExtensionsService* frontend_;
-
- // The top-level extensions directory being installed to.
- FilePath install_directory_;
-
- // Whether errors result in noisy alerts.
- bool alert_on_error_;
-
- // A collection of external extension providers. Each provider reads
- // a source of external extension information. Examples include the
- // windows registry and external_extensions.json.
- typedef std::vector<linked_ptr<ExternalExtensionProvider> >
- ProviderCollection;
- ProviderCollection external_extension_providers_;
- linked_ptr<ExternalPolicyExtensionProvider>
- external_policy_extension_provider_;
-
- // Set to true by OnExternalExtensionUpdateUrlFound() when an external
- // extension URL is found. Used in CheckForExternalUpdates() to see
- // if an update check is needed to install pending extensions.
- bool external_extension_added_;
-
- DISALLOW_COPY_AND_ASSIGN(ExtensionsServiceBackend);
-};
-
-ExtensionsServiceBackend::ExtensionsServiceBackend(
- PrefService* prefs,
- const FilePath& install_directory)
- : frontend_(NULL),
- install_directory_(install_directory),
- alert_on_error_(false),
- external_extension_added_(false) {
- // TODO(aa): This ends up doing blocking IO on the UI thread because it reads
- // pref data in the ctor and that is called on the UI thread. Would be better
- // to re-read data each time we list external extensions, anyway.
- external_extension_providers_.push_back(
- linked_ptr<ExternalExtensionProvider>(
- new ExternalPrefExtensionProvider()));
-#if defined(OS_WIN)
- external_extension_providers_.push_back(
- linked_ptr<ExternalExtensionProvider>(
- new ExternalRegistryExtensionProvider()));
-#endif
- // The policy-controlled extension provider is also stored in a member
- // variable so that UpdateExternalPolicyExtensionProvider can access it and
- // update its extension list later.
- external_policy_extension_provider_.reset(
- new ExternalPolicyExtensionProvider());
- external_policy_extension_provider_->SetPreferences(
- prefs->GetList(prefs::kExtensionInstallForceList));
- external_extension_providers_.push_back(external_policy_extension_provider_);
-}
-
-ExtensionsServiceBackend::~ExtensionsServiceBackend() {
-}
-
-void ExtensionsServiceBackend::LoadSingleExtension(
- const FilePath& path_in, scoped_refptr<ExtensionsService> frontend) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- frontend_ = frontend;
-
- // Explicit UI loads are always noisy.
- alert_on_error_ = true;
-
- FilePath extension_path = path_in;
- file_util::AbsolutePath(&extension_path);
-
- std::string error;
- scoped_refptr<const Extension> extension(extension_file_util::LoadExtension(
- extension_path,
- Extension::LOAD,
- false, // Don't require id
- &error));
-
- if (!extension) {
- ReportExtensionLoadError(extension_path, error);
- return;
- }
-
- // Report this as an installed extension so that it gets remembered in the
- // prefs.
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(frontend_,
- &ExtensionsService::OnExtensionInstalled,
- extension));
-}
-
-void ExtensionsServiceBackend::ReportExtensionLoadError(
- const FilePath& extension_path, const std::string &error) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(
- frontend_,
- &ExtensionsService::ReportExtensionLoadError, extension_path,
- error, NotificationType::EXTENSION_INSTALL_ERROR, alert_on_error_));
-}
-
-// Some extensions will autoupdate themselves externally from Chrome. These
-// are typically part of some larger client application package. To support
-// these, the extension will register its location in the the preferences file
-// (and also, on Windows, in the registry) and this code will periodically
-// check that location for a .crx file, which it will then install locally if
-// a new version is available.
-void ExtensionsServiceBackend::CheckForExternalUpdates(
- const std::set<std::string>& ids_to_ignore,
- scoped_refptr<ExtensionsService> frontend) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- // Note that this installation is intentionally silent (since it didn't
- // go through the front-end). Extensions that are registered in this
- // way are effectively considered 'pre-bundled', and so implicitly
- // trusted. In general, if something has HKLM or filesystem access,
- // they could install an extension manually themselves anyway.
- alert_on_error_ = false;
- frontend_ = frontend;
- external_extension_added_ = false;
-
- // Ask each external extension provider to give us a call back for each
- // extension they know about. See OnExternalExtension(File|UpdateUrl)Found.
- ProviderCollection::const_iterator i;
- for (i = external_extension_providers_.begin();
- i != external_extension_providers_.end(); ++i) {
- ExternalExtensionProvider* provider = i->get();
- provider->VisitRegisteredExtension(this, ids_to_ignore);
- }
-
- if (external_extension_added_ && frontend->updater()) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(
- frontend->updater(), &ExtensionUpdater::CheckNow));
- }
-}
-
-void ExtensionsServiceBackend::CheckExternalUninstall(
- scoped_refptr<ExtensionsService> frontend, const std::string& id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- // Check if the providers know about this extension.
- ProviderCollection::const_iterator i;
- for (i = external_extension_providers_.begin();
- i != external_extension_providers_.end(); ++i) {
- if (i->get()->HasExtension(id))
- return; // Yup, known extension, don't uninstall.
- }
-
- // This is an external extension that we don't have registered. Uninstall.
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(
- frontend.get(), &ExtensionsService::UninstallExtension, id, true));
-}
-
-void ExtensionsServiceBackend::UpdateExternalPolicyExtensionProvider(
- scoped_refptr<RefCountedList> forcelist) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- external_policy_extension_provider_->SetPreferences(forcelist->Get());
-}
-
-void ExtensionsServiceBackend::ClearProvidersForTesting() {
- external_extension_providers_.clear();
-}
-
-void ExtensionsServiceBackend::AddProviderForTesting(
- ExternalExtensionProvider* test_provider) {
- DCHECK(test_provider);
- external_extension_providers_.push_back(
- linked_ptr<ExternalExtensionProvider>(test_provider));
-}
-
-void ExtensionsServiceBackend::OnExternalExtensionFileFound(
- const std::string& id, const Version* version, const FilePath& path,
- Extension::Location location) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- DCHECK(version);
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(
- frontend_, &ExtensionsService::OnExternalExtensionFileFound, id,
- version->GetString(), path, location));
-}
-
-void ExtensionsServiceBackend::OnExternalExtensionUpdateUrlFound(
- const std::string& id,
- const GURL& update_url,
- Extension::Location location) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- if (frontend_->GetExtensionById(id, true)) {
- // Already installed. Do not change the update URL that the extension set.
- return;
- }
-
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(
- frontend_,
- &ExtensionsService::AddPendingExtensionFromExternalUpdateUrl,
- id, update_url, location));
- external_extension_added_ |= true;
-}
-
-bool ExtensionsService::IsDownloadFromGallery(const GURL& download_url,
- const GURL& referrer_url) {
- // Special-case the themes mini-gallery.
- // TODO(erikkay) When that gallery goes away, remove this code.
- if (IsDownloadFromMiniGallery(download_url) &&
- StartsWithASCII(referrer_url.spec(),
- extension_urls::kMiniGalleryBrowsePrefix, false)) {
- return true;
- }
-
- const Extension* download_extension = GetExtensionByWebExtent(download_url);
- const Extension* referrer_extension = GetExtensionByWebExtent(referrer_url);
- const Extension* webstore_app = GetWebStoreApp();
-
- bool referrer_valid = (referrer_extension == webstore_app);
- bool download_valid = (download_extension == webstore_app);
-
- // If the command-line gallery URL is set, then be a bit more lenient.
- GURL store_url =
- GURL(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kAppsGalleryURL));
- if (!store_url.is_empty()) {
- std::string store_tld =
- net::RegistryControlledDomainService::GetDomainAndRegistry(store_url);
- if (!referrer_valid) {
- std::string referrer_tld =
- net::RegistryControlledDomainService::GetDomainAndRegistry(
- referrer_url);
- // The referrer gets stripped when transitioning from https to http,
- // or when hitting an unknown test cert and that commonly happens in
- // testing environments. Given this, we allow an empty referrer when
- // the command-line flag is set.
- // Otherwise, the TLD must match the TLD of the command-line url.
- referrer_valid = referrer_url.is_empty() || (referrer_tld == store_tld);
- }
-
- if (!download_valid) {
- std::string download_tld =
- net::RegistryControlledDomainService::GetDomainAndRegistry(
- GURL(download_url));
-
- // Otherwise, the TLD must match the TLD of the command-line url.
- download_valid = (download_tld == store_tld);
- }
- }
-
- return (referrer_valid && download_valid);
-}
-
-bool ExtensionsService::IsDownloadFromMiniGallery(const GURL& download_url) {
- return StartsWithASCII(download_url.spec(),
- extension_urls::kMiniGalleryDownloadPrefix,
- false); // case_sensitive
-}
-
-// static
-bool ExtensionsService::UninstallExtensionHelper(
- ExtensionsService* extensions_service,
- const std::string& extension_id) {
- DCHECK(extensions_service);
-
- // We can't call UninstallExtension with an invalid extension ID, so check it
- // first.
- if (extensions_service->GetExtensionById(extension_id, true)) {
- extensions_service->UninstallExtension(extension_id, false);
- } else {
- LOG(WARNING) << "Attempted uninstallation of non-existent extension with "
- << "id: " << extension_id;
- return false;
- }
-
- return true;
-}
-
-ExtensionsService::ExtensionsService(Profile* profile,
- const CommandLine* command_line,
- const FilePath& install_directory,
- bool autoupdate_enabled)
- : profile_(profile),
- extension_prefs_(new ExtensionPrefs(profile->GetPrefs(),
- install_directory)),
- install_directory_(install_directory),
- extensions_enabled_(true),
- show_extensions_prompts_(true),
- ready_(false),
- ALLOW_THIS_IN_INITIALIZER_LIST(toolbar_model_(this)),
- default_apps_(profile->GetPrefs(),
- g_browser_process->GetApplicationLocale()),
- event_routers_initialized_(false) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // Figure out if extension installation should be enabled.
- if (command_line->HasSwitch(switches::kDisableExtensions)) {
- extensions_enabled_ = false;
- } else if (profile->GetPrefs()->GetBoolean(prefs::kDisableExtensions)) {
- extensions_enabled_ = false;
- }
-
- registrar_.Add(this, NotificationType::EXTENSION_PROCESS_TERMINATED,
- NotificationService::AllSources());
- pref_change_registrar_.Init(profile->GetPrefs());
- pref_change_registrar_.Add(prefs::kExtensionInstallAllowList, this);
- pref_change_registrar_.Add(prefs::kExtensionInstallDenyList, this);
- pref_change_registrar_.Add(prefs::kExtensionInstallForceList, this);
-
- // Set up the ExtensionUpdater
- if (autoupdate_enabled) {
- int update_frequency = kDefaultUpdateFrequencySeconds;
- if (command_line->HasSwitch(switches::kExtensionsUpdateFrequency)) {
- base::StringToInt(command_line->GetSwitchValueASCII(
- switches::kExtensionsUpdateFrequency),
- &update_frequency);
- }
- updater_ = new ExtensionUpdater(this,
- profile->GetPrefs(),
- update_frequency);
- }
-
- backend_ = new ExtensionsServiceBackend(profile->GetPrefs(),
- install_directory_);
-
- // Use monochrome icons for Omnibox icons.
- omnibox_popup_icon_manager_.set_monochrome(true);
- omnibox_icon_manager_.set_monochrome(true);
- omnibox_icon_manager_.set_padding(gfx::Insets(0, kOmniboxIconPaddingLeft,
- 0, kOmniboxIconPaddingRight));
-}
-
-ExtensionsService::~ExtensionsService() {
- DCHECK(!profile_); // Profile should have told us it's going away.
- UnloadAllExtensions();
- if (updater_.get()) {
- updater_->Stop();
- }
-}
-
-void ExtensionsService::InitEventRouters() {
- if (event_routers_initialized_)
- return;
-
- ExtensionHistoryEventRouter::GetInstance()->ObserveProfile(profile_);
- ExtensionAccessibilityEventRouter::GetInstance()->ObserveProfile(profile_);
- ExtensionBrowserEventRouter::GetInstance()->Init(profile_);
- ExtensionBookmarkEventRouter::GetSingleton()->Observe(
- profile_->GetBookmarkModel());
- ExtensionCookiesEventRouter::GetInstance()->Init();
- ExtensionManagementEventRouter::GetInstance()->Init();
- ExtensionProcessesEventRouter::GetInstance()->ObserveProfile(profile_);
- ExtensionWebNavigationEventRouter::GetInstance()->Init();
- event_routers_initialized_ = true;
-}
-
-void ExtensionsService::Init() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- DCHECK(!ready_); // Can't redo init.
- DCHECK_EQ(extensions_.size(), 0u);
-
- // Hack: we need to ensure the ResourceDispatcherHost is ready before we load
- // the first extension, because its members listen for loaded notifications.
- g_browser_process->resource_dispatcher_host();
-
- LoadAllExtensions();
-
- // TODO(erikkay) this should probably be deferred to a future point
- // rather than running immediately at startup.
- CheckForExternalUpdates();
-
- // TODO(erikkay) this should probably be deferred as well.
- GarbageCollectExtensions();
-}
-
-void ExtensionsService::InstallExtension(const FilePath& extension_path) {
- scoped_refptr<CrxInstaller> installer(
- new CrxInstaller(this, // frontend
- NULL)); // no client (silent install)
- installer->InstallCrx(extension_path);
-}
-
-namespace {
- // TODO(akalin): Put this somewhere where both crx_installer.cc and
- // this file can use it.
- void DeleteFileHelper(const FilePath& path, bool recursive) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- file_util::Delete(path, recursive);
- }
-} // namespace
-
-void ExtensionsService::UpdateExtension(const std::string& id,
- const FilePath& extension_path,
- const GURL& download_url) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- PendingExtensionMap::const_iterator it = pending_extensions_.find(id);
- bool is_pending_extension = (it != pending_extensions_.end());
-
- const Extension* extension = GetExtensionByIdInternal(id, true, true);
- if (!is_pending_extension && !extension) {
- LOG(WARNING) << "Will not update extension " << id
- << " because it is not installed or pending";
- // Delete extension_path since we're not creating a CrxInstaller
- // that would do it for us.
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableFunction(&DeleteFileHelper, extension_path, false));
- return;
- }
-
- // We want a silent install only for non-pending extensions and
- // pending extensions that have install_silently set.
- ExtensionInstallUI* client =
- (!is_pending_extension || it->second.install_silently) ?
- NULL : new ExtensionInstallUI(profile_);
-
- scoped_refptr<CrxInstaller> installer(
- new CrxInstaller(this, // frontend
- client));
- installer->set_expected_id(id);
- if (is_pending_extension)
- installer->set_install_source(it->second.install_source);
- else if (extension)
- installer->set_install_source(extension->location());
- installer->set_delete_source(true);
- installer->set_original_url(download_url);
- installer->InstallCrx(extension_path);
-}
-
-void ExtensionsService::AddPendingExtensionFromSync(
- const std::string& id, const GURL& update_url,
- PendingExtensionInfo::ExpectedCrxType expected_crx_type,
- bool install_silently, bool enable_on_install,
- bool enable_incognito_on_install) {
- if (GetExtensionByIdInternal(id, true, true)) {
- LOG(DFATAL) << "Trying to add pending extension " << id
- << " which already exists";
- return;
- }
-
- AddPendingExtensionInternal(id, update_url, expected_crx_type, true,
- install_silently, enable_on_install,
- enable_incognito_on_install,
- Extension::INTERNAL);
-}
-
-void ExtensionsService::AddPendingExtensionFromExternalUpdateUrl(
- const std::string& id, const GURL& update_url,
- Extension::Location location) {
- // Add the extension to this list of extensions to update.
- const PendingExtensionInfo::ExpectedCrxType kExpectedCrxType =
- PendingExtensionInfo::UNKNOWN;
- const bool kIsFromSync = false;
- const bool kInstallSilently = true;
- const bool kEnableOnInstall = true;
- const bool kEnableIncognitoOnInstall = false;
-
- if (GetExtensionByIdInternal(id, true, true)) {
- LOG(DFATAL) << "Trying to add extension " << id
- << " by external update, but it is already installed.";
- return;
- }
-
- AddPendingExtensionInternal(id, update_url, kExpectedCrxType, kIsFromSync,
- kInstallSilently, kEnableOnInstall,
- kEnableIncognitoOnInstall,
- location);
-}
-
-void ExtensionsService::AddPendingExtensionFromDefaultAppList(
- const std::string& id) {
- // Add the extension to this list of extensions to update.
- const PendingExtensionInfo::ExpectedCrxType kExpectedCrxType =
- PendingExtensionInfo::APP;
- const bool kIsFromSync = false;
- const bool kInstallSilently = true;
- const bool kEnableOnInstall = true;
- const bool kEnableIncognitoOnInstall = true;
-
- // This can legitimately happen if the user manually installed one of the
- // default apps before this code ran.
- if (GetExtensionByIdInternal(id, true, true))
- return;
-
- AddPendingExtensionInternal(id, GURL(), kExpectedCrxType, kIsFromSync,
- kInstallSilently, kEnableOnInstall,
- kEnableIncognitoOnInstall,
- Extension::INTERNAL);
-}
-
-void ExtensionsService::AddPendingExtensionInternal(
- const std::string& id, const GURL& update_url,
- PendingExtensionInfo::ExpectedCrxType expected_crx_type,
- bool is_from_sync, bool install_silently,
- bool enable_on_install, bool enable_incognito_on_install,
- Extension::Location install_source) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // If a non-sync update is pending, a sync request should not
- // overwrite it. This is important for external extensions.
- // If an external extension download is pending, and the user has
- // the extension in their sync profile, the install should set the
- // type to be external. An external extension should not be
- // rejected if it fails the safty checks for a syncable extension.
- // TODO(skerner): Work out other potential overlapping conditions.
- // (crbug.com/61000)
- PendingExtensionMap::iterator it = pending_extensions_.find(id);
- if (it != pending_extensions_.end()) {
- VLOG(1) << "Extension id " << id
- << " was entered for update more than once."
- << " old is_from_sync = " << it->second.is_from_sync
- << " new is_from_sync = " << is_from_sync;
- if (!it->second.is_from_sync && is_from_sync)
- return;
- }
-
-
- pending_extensions_[id] =
- PendingExtensionInfo(update_url, expected_crx_type, is_from_sync,
- install_silently, enable_on_install,
- enable_incognito_on_install, install_source);
-}
-
-void ExtensionsService::ReloadExtension(const std::string& extension_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- FilePath path;
- const Extension* current_extension = GetExtensionById(extension_id, false);
-
- // Disable the extension if it's loaded. It might not be loaded if it crashed.
- if (current_extension) {
- // If the extension has an inspector open for its background page, detach
- // the inspector and hang onto a cookie for it, so that we can reattach
- // later.
- ExtensionProcessManager* manager = profile_->GetExtensionProcessManager();
- ExtensionHost* host = manager->GetBackgroundHostForExtension(
- current_extension);
- if (host) {
- // Look for an open inspector for the background page.
- int devtools_cookie = DevToolsManager::GetInstance()->DetachClientHost(
- host->render_view_host());
- if (devtools_cookie >= 0)
- orphaned_dev_tools_[extension_id] = devtools_cookie;
- }
-
- path = current_extension->path();
- DisableExtension(extension_id);
- disabled_extension_paths_[extension_id] = path;
- } else {
- path = unloaded_extension_paths_[extension_id];
- }
-
- // Check the installed extensions to see if what we're reloading was already
- // installed.
- scoped_ptr<ExtensionInfo> installed_extension(
- extension_prefs_->GetInstalledExtensionInfo(extension_id));
- if (installed_extension.get() &&
- installed_extension->extension_manifest.get()) {
- LoadInstalledExtension(*installed_extension, false);
- } else {
- // We should always be able to remember the extension's path. If it's not in
- // the map, someone failed to update |unloaded_extension_paths_|.
- CHECK(!path.empty());
- LoadExtension(path);
- }
-}
-
-void ExtensionsService::UninstallExtension(const std::string& extension_id,
- bool external_uninstall) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- const Extension* extension =
- GetExtensionByIdInternal(extension_id, true, true);
-
- // Callers should not send us nonexistent extensions.
- CHECK(extension);
-
- // Get hold of information we need after unloading, since the extension
- // pointer will be invalid then.
- GURL extension_url(extension->url());
- Extension::Location location(extension->location());
- UninstalledExtensionInfo uninstalled_extension_info(*extension);
-
- UMA_HISTOGRAM_ENUMERATION("Extensions.UninstallType",
- extension->GetHistogramType(), 100);
-
- // Also copy the extension identifier since the reference might have been
- // obtained via Extension::id().
- std::string extension_id_copy(extension_id);
-
- if (profile_->GetTemplateURLModel())
- profile_->GetTemplateURLModel()->UnregisterExtensionKeyword(extension);
-
- // Unload before doing more cleanup to ensure that nothing is hanging on to
- // any of these resources.
- UnloadExtension(extension_id);
-
- extension_prefs_->OnExtensionUninstalled(extension_id_copy, location,
- external_uninstall);
-
- // Tell the backend to start deleting installed extensions on the file thread.
- if (Extension::LOAD != location) {
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableFunction(
- &extension_file_util::UninstallExtension,
- install_directory_,
- extension_id_copy));
- }
-
- ClearExtensionData(extension_url);
-
- // Notify interested parties that we've uninstalled this extension.
- NotificationService::current()->Notify(
- NotificationType::EXTENSION_UNINSTALLED,
- Source<Profile>(profile_),
- Details<UninstalledExtensionInfo>(&uninstalled_extension_info));
-}
-
-void ExtensionsService::ClearExtensionData(const GURL& extension_url) {
- scoped_refptr<ExtensionDataDeleter> deleter(
- new ExtensionDataDeleter(profile_, extension_url));
- deleter->StartDeleting();
-}
-
-void ExtensionsService::EnableExtension(const std::string& extension_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- const Extension* extension =
- GetExtensionByIdInternal(extension_id, false, true);
- if (!extension)
- return;
-
- extension_prefs_->SetExtensionState(extension, Extension::ENABLED);
-
- // Move it over to the enabled list.
- extensions_.push_back(make_scoped_refptr(extension));
- ExtensionList::iterator iter = std::find(disabled_extensions_.begin(),
- disabled_extensions_.end(),
- extension);
- disabled_extensions_.erase(iter);
-
- // Make sure any browser action contained within it is not hidden.
- extension_prefs_->SetBrowserActionVisibility(extension, true);
-
- ExtensionDOMUI::RegisterChromeURLOverrides(profile_,
- extension->GetChromeURLOverrides());
-
- NotifyExtensionLoaded(extension);
- UpdateActiveExtensionsInCrashReporter();
-}
-
-void ExtensionsService::DisableExtension(const std::string& extension_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- const Extension* extension =
- GetExtensionByIdInternal(extension_id, true, false);
- // The extension may have been disabled already.
- if (!extension)
- return;
-
- extension_prefs_->SetExtensionState(extension, Extension::DISABLED);
-
- // Move it over to the disabled list.
- disabled_extensions_.push_back(make_scoped_refptr(extension));
- ExtensionList::iterator iter = std::find(extensions_.begin(),
- extensions_.end(),
- extension);
- extensions_.erase(iter);
-
- ExtensionDOMUI::UnregisterChromeURLOverrides(profile_,
- extension->GetChromeURLOverrides());
-
- NotifyExtensionUnloaded(extension);
- UpdateActiveExtensionsInCrashReporter();
-}
-
-void ExtensionsService::GrantPermissions(const Extension* extension) {
- CHECK(extension);
-
- // We only maintain the granted permissions prefs for INTERNAL extensions.
- CHECK(extension->location() == Extension::INTERNAL);
-
- ExtensionExtent effective_hosts = extension->GetEffectiveHostPermissions();
- extension_prefs_->AddGrantedPermissions(extension->id(),
- extension->HasFullPermissions(),
- extension->api_permissions(),
- effective_hosts);
-}
-
-void ExtensionsService::GrantPermissionsAndEnableExtension(
- const Extension* extension) {
- CHECK(extension);
- GrantPermissions(extension);
- extension_prefs_->SetDidExtensionEscalatePermissions(extension, false);
- EnableExtension(extension->id());
-}
-
-void ExtensionsService::LoadExtension(const FilePath& extension_path) {
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(
- backend_.get(),
- &ExtensionsServiceBackend::LoadSingleExtension,
- extension_path, scoped_refptr<ExtensionsService>(this)));
-}
-
-void ExtensionsService::LoadComponentExtensions() {
- for (RegisteredComponentExtensions::iterator it =
- component_extension_manifests_.begin();
- it != component_extension_manifests_.end(); ++it) {
- JSONStringValueSerializer serializer(it->manifest);
- scoped_ptr<Value> manifest(serializer.Deserialize(NULL, NULL));
- if (!manifest.get()) {
- DLOG(ERROR) << "Failed to parse manifest for extension";
- continue;
- }
-
- std::string error;
- scoped_refptr<const Extension> extension(Extension::Create(
- it->root_directory,
- Extension::COMPONENT,
- *static_cast<DictionaryValue*>(manifest.get()),
- true, // require key
- &error));
- if (!extension.get()) {
- NOTREACHED() << error;
- return;
- }
-
- OnExtensionLoaded(extension);
- }
-}
-
-void ExtensionsService::LoadAllExtensions() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- base::TimeTicks start_time = base::TimeTicks::Now();
-
- // Load any component extensions.
- LoadComponentExtensions();
-
- // Load the previously installed extensions.
- scoped_ptr<ExtensionPrefs::ExtensionsInfo> extensions_info(
- extension_prefs_->GetInstalledExtensionsInfo());
-
- std::vector<int> reload_reason_counts(NUM_MANIFEST_RELOAD_REASONS, 0);
- bool should_write_prefs = false;
-
- for (size_t i = 0; i < extensions_info->size(); ++i) {
- ExtensionInfo* info = extensions_info->at(i).get();
-
- ManifestReloadReason reload_reason = ShouldReloadExtensionManifest(*info);
- ++reload_reason_counts[reload_reason];
- UMA_HISTOGRAM_ENUMERATION("Extensions.ManifestReloadEnumValue",
- reload_reason, 100);
-
- if (reload_reason != NOT_NEEDED) {
- // Reloading and extension reads files from disk. We do this on the
- // UI thread because reloads should be very rare, and the complexity
- // added by delaying the time when the extensions service knows about
- // all extensions is significant. See crbug.com/37548 for details.
- // |allow_io| disables tests that file operations run on the file
- // thread.
- base::ThreadRestrictions::ScopedAllowIO allow_io;
-
- std::string error;
- scoped_refptr<const Extension> extension(
- extension_file_util::LoadExtension(
- info->extension_path, info->extension_location, false, &error));
-
- if (extension.get()) {
- extensions_info->at(i)->extension_manifest.reset(
- static_cast<DictionaryValue*>(
- extension->manifest_value()->DeepCopy()));
- should_write_prefs = true;
- }
- }
- }
-
- for (size_t i = 0; i < extensions_info->size(); ++i) {
- LoadInstalledExtension(*extensions_info->at(i), should_write_prefs);
- }
-
- OnLoadedInstalledExtensions();
-
- // The histograms Extensions.ManifestReload* allow us to validate
- // the assumption that reloading manifest is a rare event.
- UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNotNeeded",
- reload_reason_counts[NOT_NEEDED]);
- UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadUnpackedDir",
- reload_reason_counts[UNPACKED_DIR]);
- UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNeedsRelocalization",
- reload_reason_counts[NEEDS_RELOCALIZATION]);
-
- UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAll", extensions_.size());
- UMA_HISTOGRAM_COUNTS_100("Extensions.Disabled", disabled_extensions_.size());
-
- UMA_HISTOGRAM_TIMES("Extensions.LoadAllTime",
- base::TimeTicks::Now() - start_time);
-
- int app_count = 0;
- int hosted_app_count = 0;
- int packaged_app_count = 0;
- int user_script_count = 0;
- int extension_count = 0;
- int theme_count = 0;
- int external_count = 0;
- int page_action_count = 0;
- int browser_action_count = 0;
- ExtensionList::iterator ex;
- for (ex = extensions_.begin(); ex != extensions_.end(); ++ex) {
- Extension::Location location = (*ex)->location();
- Extension::HistogramType type = (*ex)->GetHistogramType();
- if ((*ex)->is_app()) {
- UMA_HISTOGRAM_ENUMERATION("Extensions.AppLocation",
- location, 100);
- } else if (type == Extension::TYPE_EXTENSION) {
- UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionLocation",
- location, 100);
- }
-
- // Don't count component extensions, since they are only extensions as an
- // implementation detail.
- if (location == Extension::COMPONENT)
- continue;
-
- // Don't count unpacked extensions, since they're a developer-specific
- // feature.
- if (location == Extension::LOAD)
- continue;
-
- // Using an enumeration shows us the total installed ratio across all users.
- // Using the totals per user at each startup tells us the distribution of
- // usage for each user (e.g. 40% of users have at least one app installed).
- UMA_HISTOGRAM_ENUMERATION("Extensions.LoadType", type, 100);
- switch (type) {
- case Extension::TYPE_THEME:
- ++theme_count;
- break;
- case Extension::TYPE_USER_SCRIPT:
- ++user_script_count;
- break;
- case Extension::TYPE_HOSTED_APP:
- ++app_count;
- ++hosted_app_count;
- break;
- case Extension::TYPE_PACKAGED_APP:
- ++app_count;
- ++packaged_app_count;
- break;
- case Extension::TYPE_EXTENSION:
- default:
- ++extension_count;
- break;
- }
- if (Extension::IsExternalLocation(location))
- ++external_count;
- if ((*ex)->page_action() != NULL)
- ++page_action_count;
- if ((*ex)->browser_action() != NULL)
- ++browser_action_count;
- }
- UMA_HISTOGRAM_COUNTS_100("Extensions.LoadApp", app_count);
- UMA_HISTOGRAM_COUNTS_100("Extensions.LoadHostedApp", hosted_app_count);
- UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPackagedApp", packaged_app_count);
- UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtension", extension_count);
- UMA_HISTOGRAM_COUNTS_100("Extensions.LoadUserScript", user_script_count);
- UMA_HISTOGRAM_COUNTS_100("Extensions.LoadTheme", theme_count);
- UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExternal", external_count);
- UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPageAction", page_action_count);
- UMA_HISTOGRAM_COUNTS_100("Extensions.LoadBrowserAction",
- browser_action_count);
-}
-
-void ExtensionsService::LoadInstalledExtension(const ExtensionInfo& info,
- bool write_to_prefs) {
- std::string error;
- scoped_refptr<const Extension> extension(NULL);
- if (!extension_prefs_->IsExtensionAllowedByPolicy(info.extension_id)) {
- error = errors::kDisabledByPolicy;
- } else if (info.extension_manifest.get()) {
- bool require_key = info.extension_location != Extension::LOAD;
- extension = Extension::Create(
- info.extension_path, info.extension_location, *info.extension_manifest,
- require_key, &error);
- } else {
- error = errors::kManifestUnreadable;
- }
-
- if (!extension) {
- ReportExtensionLoadError(info.extension_path,
- error,
- NotificationType::EXTENSION_INSTALL_ERROR,
- false);
- return;
- }
-
- if (write_to_prefs)
- extension_prefs_->UpdateManifest(extension);
-
- OnExtensionLoaded(extension);
-
- if (Extension::IsExternalLocation(info.extension_location)) {
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(
- backend_.get(),
- &ExtensionsServiceBackend::CheckExternalUninstall,
- scoped_refptr<ExtensionsService>(this),
- info.extension_id));
- }
-}
-
-void ExtensionsService::NotifyExtensionLoaded(const Extension* extension) {
- // The ChromeURLRequestContexts 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.
- if (profile_) {
- profile_->RegisterExtensionWithRequestContexts(extension);
-
- // Check if this permission requires unlimited storage quota
- if (extension->HasApiPermission(Extension::kUnlimitedStoragePermission))
- GrantUnlimitedStorage(extension);
-
- // If the extension is an app, protect its local storage from
- // "Clear browsing data."
- if (extension->is_app())
- GrantProtectedStorage(extension);
- }
-
- NotificationService::current()->Notify(
- NotificationType::EXTENSION_LOADED,
- Source<Profile>(profile_),
- Details<const Extension>(extension));
-}
-
-void ExtensionsService::NotifyExtensionUnloaded(const Extension* extension) {
- NotificationService::current()->Notify(
- NotificationType::EXTENSION_UNLOADED,
- Source<Profile>(profile_),
- Details<const Extension>(extension));
-
- if (profile_) {
- profile_->UnregisterExtensionWithRequestContexts(extension);
-
- // Check if this permission required unlimited storage quota, reset its
- // in-memory quota.
- if (extension->HasApiPermission(Extension::kUnlimitedStoragePermission))
- RevokeUnlimitedStorage(extension);
-
- // If this is an app, then stop protecting its storage so it can be deleted.
- if (extension->is_app())
- RevokeProtectedStorage(extension);
- }
-}
-
-void ExtensionsService::GrantProtectedStorage(const Extension* extension) {
- DCHECK(extension->is_app()) << "Only Apps are allowed protected storage.";
- std::vector<GURL> origins;
- GetExplicitOriginsInExtent(extension, &origins);
- for (size_t i = 0; i < origins.size(); ++i)
- ++protected_storage_map_[origins[i]];
-}
-
-void ExtensionsService::RevokeProtectedStorage(const Extension* extension) {
- DCHECK(extension->is_app()) << "Attempting to revoke protected storage from "
- << " a non-app extension.";
- std::vector<GURL> origins;
- GetExplicitOriginsInExtent(extension, &origins);
- for (size_t i = 0; i < origins.size(); ++i) {
- const GURL& origin = origins[i];
- DCHECK(protected_storage_map_[origin] > 0);
- if (--protected_storage_map_[origin] <= 0)
- protected_storage_map_.erase(origin);
- }
-}
-
-void ExtensionsService::GrantUnlimitedStorage(const Extension* extension) {
- DCHECK(extension->HasApiPermission(Extension::kUnlimitedStoragePermission));
- std::vector<GURL> origins;
- GetExplicitOriginsInExtent(extension, &origins);
- origins.push_back(extension->url());
-
- for (size_t i = 0; i < origins.size(); ++i) {
- const GURL& origin = origins[i];
- if (++unlimited_storage_map_[origin] == 1) {
- string16 origin_identifier =
- webkit_database::DatabaseUtil::GetOriginIdentifier(origin);
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(
- profile_->GetDatabaseTracker(),
- &webkit_database::DatabaseTracker::SetOriginQuotaInMemory,
- origin_identifier,
- kint64max));
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(
- profile_->GetAppCacheService(),
- &ChromeAppCacheService::SetOriginQuotaInMemory,
- origin,
- kint64max));
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(
- profile_->GetFileSystemContext(),
- &BrowserFileSystemContext::SetOriginQuotaUnlimited,
- origin));
- }
- }
-}
-
-void ExtensionsService::RevokeUnlimitedStorage(const Extension* extension) {
- DCHECK(extension->HasApiPermission(Extension::kUnlimitedStoragePermission));
- std::vector<GURL> origins;
- GetExplicitOriginsInExtent(extension, &origins);
- origins.push_back(extension->url());
-
- for (size_t i = 0; i < origins.size(); ++i) {
- const GURL& origin = origins[i];
- DCHECK(unlimited_storage_map_[origin] > 0);
- if (--unlimited_storage_map_[origin] == 0) {
- unlimited_storage_map_.erase(origin);
- string16 origin_identifier =
- webkit_database::DatabaseUtil::GetOriginIdentifier(origin);
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(
- profile_->GetDatabaseTracker(),
- &webkit_database::DatabaseTracker::ResetOriginQuotaInMemory,
- origin_identifier));
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(
- profile_->GetAppCacheService(),
- &ChromeAppCacheService::ResetOriginQuotaInMemory,
- origin));
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(
- profile_->GetFileSystemContext(),
- &BrowserFileSystemContext::ResetOriginQuotaUnlimited,
- origin));
- }
- }
-}
-
-void ExtensionsService::UpdateExtensionBlacklist(
- const std::vector<std::string>& blacklist) {
- // Use this set to indicate if an extension in the blacklist has been used.
- std::set<std::string> blacklist_set;
- for (unsigned int i = 0; i < blacklist.size(); ++i) {
- if (Extension::IdIsValid(blacklist[i])) {
- blacklist_set.insert(blacklist[i]);
- }
- }
- extension_prefs_->UpdateBlacklist(blacklist_set);
- std::vector<std::string> to_be_removed;
- // Loop current extensions, unload installed extensions.
- for (ExtensionList::const_iterator iter = extensions_.begin();
- iter != extensions_.end(); ++iter) {
- const Extension* extension = (*iter);
- if (blacklist_set.find(extension->id()) != blacklist_set.end()) {
- to_be_removed.push_back(extension->id());
- }
- }
-
- // UnloadExtension will change the extensions_ list. So, we should
- // call it outside the iterator loop.
- for (unsigned int i = 0; i < to_be_removed.size(); ++i) {
- UnloadExtension(to_be_removed[i]);
- }
-}
-
-void ExtensionsService::DestroyingProfile() {
- pref_change_registrar_.RemoveAll();
- profile_ = NULL;
- toolbar_model_.DestroyingProfile();
-}
-
-void ExtensionsService::CheckAdminBlacklist() {
- std::vector<std::string> to_be_removed;
- // Loop through extensions list, unload installed extensions.
- for (ExtensionList::const_iterator iter = extensions_.begin();
- iter != extensions_.end(); ++iter) {
- const Extension* extension = (*iter);
- if (!extension_prefs_->IsExtensionAllowedByPolicy(extension->id()))
- to_be_removed.push_back(extension->id());
- }
-
- // UnloadExtension will change the extensions_ list. So, we should
- // call it outside the iterator loop.
- for (unsigned int i = 0; i < to_be_removed.size(); ++i)
- UnloadExtension(to_be_removed[i]);
-}
-
-bool ExtensionsService::IsIncognitoEnabled(const Extension* extension) {
- // If this is a component extension we always allow it to work in incognito
- // mode.
- if (extension->location() == Extension::COMPONENT)
- return true;
-
- // Check the prefs.
- return extension_prefs_->IsIncognitoEnabled(extension->id());
-}
-
-void ExtensionsService::SetIsIncognitoEnabled(const Extension* extension,
- bool enabled) {
- extension_prefs_->SetIsIncognitoEnabled(extension->id(), enabled);
-
- // Broadcast unloaded and loaded events to update browser state. Only bother
- // if the extension is actually enabled, since there is no UI otherwise.
- bool is_enabled = std::find(extensions_.begin(), extensions_.end(),
- extension) != extensions_.end();
- if (is_enabled) {
- NotifyExtensionUnloaded(extension);
- NotifyExtensionLoaded(extension);
- }
-}
-
-bool ExtensionsService::CanCrossIncognito(const Extension* extension) {
- // We allow the extension to see events and data from another profile iff it
- // uses "spanning" behavior and it has incognito access. "split" mode
- // extensions only see events for a matching profile.
- return IsIncognitoEnabled(extension) && !extension->incognito_split_mode();
-}
-
-bool ExtensionsService::AllowFileAccess(const Extension* extension) {
- return (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableExtensionsFileAccessCheck) ||
- extension_prefs_->AllowFileAccess(extension->id()));
-}
-
-void ExtensionsService::SetAllowFileAccess(const Extension* extension,
- bool allow) {
- extension_prefs_->SetAllowFileAccess(extension->id(), allow);
- NotificationService::current()->Notify(
- NotificationType::EXTENSION_USER_SCRIPTS_UPDATED,
- Source<Profile>(profile_),
- Details<const Extension>(extension));
-}
-
-bool ExtensionsService::GetBrowserActionVisibility(const Extension* extension) {
- return extension_prefs_->GetBrowserActionVisibility(extension);
-}
-
-void ExtensionsService::SetBrowserActionVisibility(const Extension* extension,
- bool visible) {
- extension_prefs_->SetBrowserActionVisibility(extension, visible);
-}
-
-void ExtensionsService::CheckForExternalUpdates() {
- // This installs or updates externally provided extensions.
- // TODO(aa): Why pass this list into the provider, why not just filter it
- // later?
- std::set<std::string> killed_extensions;
- extension_prefs_->GetKilledExtensionIds(&killed_extensions);
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(
- backend_.get(), &ExtensionsServiceBackend::CheckForExternalUpdates,
- killed_extensions, scoped_refptr<ExtensionsService>(this)));
-}
-
-void ExtensionsService::UpdateExternalPolicyExtensionProvider() {
- const ListValue* list_pref =
- profile_->GetPrefs()->GetList(prefs::kExtensionInstallForceList);
- ListValue* list_copy = NULL;
- if (list_pref)
- list_copy = static_cast<ListValue*>(list_pref->DeepCopy());
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(
- backend_.get(),
- &ExtensionsServiceBackend::UpdateExternalPolicyExtensionProvider,
- scoped_refptr<RefCountedList>(
- new RefCountedList(list_copy))));
-}
-
-void ExtensionsService::UnloadExtension(const std::string& extension_id) {
- // Make sure the extension gets deleted after we return from this function.
- scoped_refptr<const Extension> extension(
- GetExtensionByIdInternal(extension_id, true, true));
-
- // This method can be called via PostTask, so the extension may have been
- // unloaded by the time this runs.
- if (!extension)
- return;
-
- // Keep information about the extension so that we can reload it later
- // even if it's not permanently installed.
- unloaded_extension_paths_[extension->id()] = extension->path();
-
- // Clean up if the extension is meant to be enabled after a reload.
- disabled_extension_paths_.erase(extension->id());
-
- // Clean up runtime data.
- extension_runtime_data_.erase(extension_id);
-
- ExtensionDOMUI::UnregisterChromeURLOverrides(profile_,
- extension->GetChromeURLOverrides());
-
- ExtensionList::iterator iter = std::find(disabled_extensions_.begin(),
- disabled_extensions_.end(),
- extension.get());
- if (iter != disabled_extensions_.end()) {
- disabled_extensions_.erase(iter);
- NotificationService::current()->Notify(
- NotificationType::EXTENSION_UNLOADED_DISABLED,
- Source<Profile>(profile_),
- Details<const Extension>(extension.get()));
- return;
- }
-
- iter = std::find(extensions_.begin(), extensions_.end(), extension.get());
-
- // Remove the extension from our list.
- extensions_.erase(iter);
-
- NotifyExtensionUnloaded(extension.get());
- UpdateActiveExtensionsInCrashReporter();
-}
-
-void ExtensionsService::UnloadAllExtensions() {
- extensions_.clear();
- disabled_extensions_.clear();
- extension_runtime_data_.clear();
-
- // TODO(erikkay) should there be a notification for this? We can't use
- // EXTENSION_UNLOADED since that implies that the extension has been disabled
- // or uninstalled, and UnloadAll is just part of shutdown.
-}
-
-void ExtensionsService::ReloadExtensions() {
- UnloadAllExtensions();
- LoadAllExtensions();
-}
-
-void ExtensionsService::GarbageCollectExtensions() {
- if (extension_prefs_->pref_service()->read_only())
- return;
-
- scoped_ptr<ExtensionPrefs::ExtensionsInfo> info(
- extension_prefs_->GetInstalledExtensionsInfo());
-
- std::map<std::string, FilePath> extension_paths;
- for (size_t i = 0; i < info->size(); ++i)
- extension_paths[info->at(i)->extension_id] = info->at(i)->extension_path;
-
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableFunction(
- &extension_file_util::GarbageCollectExtensions, install_directory_,
- extension_paths));
-
- // Also garbage-collect themes. We check |profile_| to be
- // defensive; in the future, we may call GarbageCollectExtensions()
- // from somewhere other than Init() (e.g., in a timer).
- if (profile_) {
- profile_->GetThemeProvider()->RemoveUnusedThemes();
- }
-}
-
-void ExtensionsService::OnLoadedInstalledExtensions() {
- if (updater_.get()) {
- updater_->Start();
- }
-
- ready_ = true;
- NotificationService::current()->Notify(
- NotificationType::EXTENSIONS_READY,
- Source<Profile>(profile_),
- NotificationService::NoDetails());
-}
-
-void ExtensionsService::OnExtensionLoaded(const Extension* extension) {
- // Ensure extension is deleted unless we transfer ownership.
- scoped_refptr<const Extension> scoped_extension(extension);
-
- // The extension is now loaded, remove its data from unloaded extension map.
- unloaded_extension_paths_.erase(extension->id());
-
- // If the extension was disabled for a reload, then enable it.
- if (disabled_extension_paths_.erase(extension->id()) > 0)
- EnableExtension(extension->id());
-
- // TODO(jstritar): We may be able to get rid of this branch by overriding the
- // default extension state to DISABLED when the --disable-extensions flag
- // is set (http://crbug.com/29067).
- if (!extensions_enabled() &&
- !extension->is_theme() &&
- extension->location() != Extension::COMPONENT &&
- !Extension::IsExternalLocation(extension->location()))
- return;
-
- // Check if the extension's privileges have changed and disable the
- // extension if necessary.
- DisableIfPrivilegeIncrease(extension);
-
- switch (extension_prefs_->GetExtensionState(extension->id())) {
- case Extension::ENABLED:
- extensions_.push_back(scoped_extension);
-
- NotifyExtensionLoaded(extension);
-
- ExtensionDOMUI::RegisterChromeURLOverrides(
- profile_, extension->GetChromeURLOverrides());
- break;
- case Extension::DISABLED:
- disabled_extensions_.push_back(scoped_extension);
- NotificationService::current()->Notify(
- NotificationType::EXTENSION_UPDATE_DISABLED,
- Source<Profile>(profile_),
- Details<const Extension>(extension));
- break;
- default:
- NOTREACHED();
- break;
- }
-
- SetBeingUpgraded(extension, false);
-
- UpdateActiveExtensionsInCrashReporter();
-
- if (profile_->GetTemplateURLModel())
- profile_->GetTemplateURLModel()->RegisterExtensionKeyword(extension);
-
- // Load the icon for omnibox-enabled extensions so it will be ready to display
- // in the URL bar.
- if (!extension->omnibox_keyword().empty()) {
- omnibox_popup_icon_manager_.LoadIcon(extension);
- omnibox_icon_manager_.LoadIcon(extension);
- }
-}
-
-void ExtensionsService::DisableIfPrivilegeIncrease(const Extension* extension) {
- // We keep track of all permissions the user has granted each extension.
- // This allows extensions to gracefully support backwards compatibility
- // by including unknown permissions in their manifests. When the user
- // installs the extension, only the recognized permissions are recorded.
- // When the unknown permissions become recognized (e.g., through browser
- // upgrade), we can prompt the user to accept these new permissions.
- // Extensions can also silently upgrade to less permissions, and then
- // silently upgrade to a version that adds these permissions back.
- //
- // For example, pretend that Chrome 10 includes a permission "omnibox"
- // for an API that adds suggestions to the omnibox. An extension can
- // maintain backwards compatibility while still having "omnibox" in the
- // manifest. If a user installs the extension on Chrome 9, the browser
- // will record the permissions it recognized, not including "omnibox."
- // When upgrading to Chrome 10, "omnibox" will be recognized and Chrome
- // will disable the extension and prompt the user to approve the increase
- // in privileges. The extension could then release a new version that
- // removes the "omnibox" permission. When the user upgrades, Chrome will
- // still remember that "omnibox" had been granted, so that if the
- // extension once again includes "omnibox" in an upgrade, the extension
- // can upgrade without requiring this user's approval.
- const Extension* old = GetExtensionByIdInternal(extension->id(),
- true, true);
- bool granted_full_access;
- std::set<std::string> granted_apis;
- ExtensionExtent granted_extent;
-
- bool is_extension_upgrade = old != NULL;
- bool is_privilege_increase = false;
-
- // We only record the granted permissions for INTERNAL extensions, since
- // they can't silently increase privileges.
- if (extension->location() == Extension::INTERNAL) {
- // Add all the recognized permissions if the granted permissions list
- // hasn't been initialized yet.
- if (!extension_prefs_->GetGrantedPermissions(extension->id(),
- &granted_full_access,
- &granted_apis,
- &granted_extent)) {
- GrantPermissions(extension);
- CHECK(extension_prefs_->GetGrantedPermissions(extension->id(),
- &granted_full_access,
- &granted_apis,
- &granted_extent));
- }
-
- // Here, we check if an extension's privileges have increased in a manner
- // that requires the user's approval. This could occur because the browser
- // upgraded and recognized additional privileges, or an extension upgrades
- // to a version that requires additional privileges.
- is_privilege_increase = Extension::IsPrivilegeIncrease(
- granted_full_access, granted_apis, granted_extent, extension);
- }
-
- if (is_extension_upgrade) {
- // CrxInstaller should have guaranteed that we aren't downgrading.
- CHECK(extension->version()->CompareTo(*(old->version())) >= 0);
-
- // Extensions get upgraded if the privileges are allowed to increase or
- // the privileges haven't increased.
- if (!is_privilege_increase) {
- SetBeingUpgraded(old, true);
- SetBeingUpgraded(extension, true);
- }
-
- // To upgrade an extension in place, unload the old one and
- // then load the new one.
- UnloadExtension(old->id());
- old = NULL;
- }
-
- // Extension has changed permissions significantly. Disable it. A
- // notification should be sent by the caller.
- if (is_privilege_increase) {
- extension_prefs_->SetExtensionState(extension, Extension::DISABLED);
- extension_prefs_->SetDidExtensionEscalatePermissions(extension, true);
- }
-}
-
-void ExtensionsService::UpdateActiveExtensionsInCrashReporter() {
- std::set<std::string> extension_ids;
- for (size_t i = 0; i < extensions_.size(); ++i) {
- if (!extensions_[i]->is_theme() &&
- extensions_[i]->location() != Extension::COMPONENT)
- extension_ids.insert(extensions_[i]->id());
- }
-
- child_process_logging::SetActiveExtensions(extension_ids);
-}
-
-void ExtensionsService::OnExtensionInstalled(const Extension* extension) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // Ensure extension is deleted unless we transfer ownership.
- scoped_refptr<const Extension> scoped_extension(extension);
- Extension::State initial_state = Extension::DISABLED;
- bool initial_enable_incognito = false;
- PendingExtensionMap::iterator it =
- pending_extensions_.find(extension->id());
- if (it != pending_extensions_.end()) {
- PendingExtensionInfo pending_extension_info = it->second;
- PendingExtensionInfo::ExpectedCrxType expected_crx_type =
- pending_extension_info.expected_crx_type;
- bool is_from_sync = pending_extension_info.is_from_sync;
- pending_extensions_.erase(it);
- it = pending_extensions_.end();
-
- // Set initial state from pending extension data.
- PendingExtensionInfo::ExpectedCrxType actual_crx_type =
- PendingExtensionInfo::EXTENSION;
- if (extension->is_app())
- actual_crx_type = PendingExtensionInfo::APP;
- else if (extension->is_theme())
- actual_crx_type = PendingExtensionInfo::THEME;
-
- if (expected_crx_type != PendingExtensionInfo::UNKNOWN &&
- expected_crx_type != actual_crx_type) {
- LOG(WARNING)
- << "Not installing pending extension " << extension->id()
- << " with is_theme = " << extension->is_theme();
- // Delete the extension directory since we're not going to
- // load it.
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableFunction(&DeleteFileHelper, extension->path(), true));
- return;
- }
-
- // If |extension| is not syncable, and was installed via sync, disallow
- // the instanation.
- //
- // Themes are always allowed. Because they contain no active code, they
- // are less of a risk than extensions.
- //
- // If |is_from_sync| is false, then the install was not initiated by sync,
- // and this check should pass. Extensions that were installed from an
- // update URL in external_extensions.json are an example. They are not
- // syncable, because the user did not make an explicit choice to install
- // them. However, they were installed through the update mechanism, so
- // control must pass into this function.
- //
- // TODO(akalin): When we do apps sync, we have to work with its
- // traits, too.
- const browser_sync::ExtensionSyncTraits extension_sync_traits =
- browser_sync::GetExtensionSyncTraits();
- const browser_sync::ExtensionSyncTraits app_sync_traits =
- browser_sync::GetAppSyncTraits();
- // If an extension is a theme, we bypass the valid/syncable check
- // as themes are harmless.
- if (!extension->is_theme() && is_from_sync &&
- !browser_sync::IsExtensionValidAndSyncable(
- *extension, extension_sync_traits.allowed_extension_types) &&
- !browser_sync::IsExtensionValidAndSyncable(
- *extension, app_sync_traits.allowed_extension_types)) {
- // We're an extension installed via sync that is unsyncable,
- // i.e. we may have been syncable previously. We block these
- // installs. We'll have to update the clause above if we decide
- // to sync other extension-like things, like apps or user
- // scripts.
- //
- // Note that this creates a small window where a user who tries
- // to download/install an extension that is simultaneously
- // installed via sync (and blocked) will find his download
- // blocked.
- //
- // TODO(akalin): Remove this check once we've put in UI to
- // approve synced extensions.
- LOG(WARNING)
- << "Not installing invalid or unsyncable extension "
- << extension->id();
- // Delete the extension directory since we're not going to
- // load it.
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableFunction(&DeleteFileHelper, extension->path(), true));
- return;
- }
- if (extension->is_theme()) {
- DCHECK(pending_extension_info.enable_on_install);
- initial_state = Extension::ENABLED;
- DCHECK(!pending_extension_info.enable_incognito_on_install);
- initial_enable_incognito = false;
- } else {
- initial_state =
- pending_extension_info.enable_on_install ?
- Extension::ENABLED : Extension::DISABLED;
- initial_enable_incognito =
- pending_extension_info.enable_incognito_on_install;
- }
- } else {
- // Make sure we preserve enabled/disabled states.
- Extension::State existing_state =
- extension_prefs_->GetExtensionState(extension->id());
- initial_state =
- (existing_state == Extension::DISABLED) ?
- Extension::DISABLED : Extension::ENABLED;
- initial_enable_incognito =
- extension_prefs_->IsIncognitoEnabled(extension->id());
- }
-
- UMA_HISTOGRAM_ENUMERATION("Extensions.InstallType",
- extension->GetHistogramType(), 100);
- ShownSectionsHandler::OnExtensionInstalled(profile_->GetPrefs(), extension);
- extension_prefs_->OnExtensionInstalled(
- extension, initial_state, initial_enable_incognito);
-
- // Unpacked extensions start off with file access since they are a developer
- // feature.
- if (extension->location() == Extension::LOAD)
- extension_prefs_->SetAllowFileAccess(extension->id(), true);
-
- // If the extension is a theme, tell the profile (and therefore ThemeProvider)
- // to apply it.
- if (extension->is_theme()) {
- NotificationService::current()->Notify(
- NotificationType::THEME_INSTALLED,
- Source<Profile>(profile_),
- Details<const Extension>(extension));
- } else {
- NotificationService::current()->Notify(
- NotificationType::EXTENSION_INSTALLED,
- Source<Profile>(profile_),
- Details<const Extension>(extension));
- }
-
- if (extension->is_app()) {
- ExtensionIdSet installed_ids = GetAppIds();
- installed_ids.insert(extension->id());
- default_apps_.DidInstallApp(installed_ids);
- }
-
- // Transfer ownership of |extension| to OnExtensionLoaded.
- OnExtensionLoaded(scoped_extension);
-}
-
-const Extension* ExtensionsService::GetExtensionByIdInternal(
- const std::string& id, bool include_enabled, bool include_disabled) {
- std::string lowercase_id = StringToLowerASCII(id);
- if (include_enabled) {
- for (ExtensionList::const_iterator iter = extensions_.begin();
- iter != extensions_.end(); ++iter) {
- if ((*iter)->id() == lowercase_id)
- return *iter;
- }
- }
- if (include_disabled) {
- for (ExtensionList::const_iterator iter = disabled_extensions_.begin();
- iter != disabled_extensions_.end(); ++iter) {
- if ((*iter)->id() == lowercase_id)
- return *iter;
- }
- }
- return NULL;
-}
-
-const Extension* ExtensionsService::GetWebStoreApp() {
- return GetExtensionById(extension_misc::kWebStoreAppId, false);
-}
-
-const Extension* ExtensionsService::GetExtensionByURL(const GURL& url) {
- return url.scheme() != chrome::kExtensionScheme ? NULL :
- GetExtensionById(url.host(), false);
-}
-
-const Extension* ExtensionsService::GetExtensionByWebExtent(const GURL& url) {
- for (size_t i = 0; i < extensions_.size(); ++i) {
- if (extensions_[i]->web_extent().ContainsURL(url))
- return extensions_[i];
- }
- return NULL;
-}
-
-bool ExtensionsService::ExtensionBindingsAllowed(const GURL& url) {
- // Allow bindings for all packaged extension.
- if (GetExtensionByURL(url))
- return true;
-
- // Allow bindings for all component, hosted apps.
- const Extension* extension = GetExtensionByWebExtent(url);
- return (extension && extension->location() == Extension::COMPONENT);
-}
-
-const Extension* ExtensionsService::GetExtensionByOverlappingWebExtent(
- const ExtensionExtent& extent) {
- for (size_t i = 0; i < extensions_.size(); ++i) {
- if (extensions_[i]->web_extent().OverlapsWith(extent))
- return extensions_[i];
- }
-
- return NULL;
-}
-
-const SkBitmap& ExtensionsService::GetOmniboxIcon(
- const std::string& extension_id) {
- return omnibox_icon_manager_.GetIcon(extension_id);
-}
-
-const SkBitmap& ExtensionsService::GetOmniboxPopupIcon(
- const std::string& extension_id) {
- return omnibox_popup_icon_manager_.GetIcon(extension_id);
-}
-
-void ExtensionsService::ClearProvidersForTesting() {
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(
- backend_.get(), &ExtensionsServiceBackend::ClearProvidersForTesting));
-}
-
-void ExtensionsService::AddProviderForTesting(
- ExternalExtensionProvider* test_provider) {
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(
- backend_.get(), &ExtensionsServiceBackend::AddProviderForTesting,
- test_provider));
-}
-
-void ExtensionsService::OnExternalExtensionFileFound(
- const std::string& id,
- const std::string& version,
- const FilePath& path,
- Extension::Location location) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // Before even bothering to unpack, check and see if we already have this
- // version. This is important because these extensions are going to get
- // installed on every startup.
- const Extension* existing = GetExtensionById(id, true);
- scoped_ptr<Version> other(Version::GetVersionFromString(version));
- if (existing) {
- switch (existing->version()->CompareTo(*other)) {
- case -1: // existing version is older, we should upgrade
- break;
- case 0: // existing version is same, do nothing
- return;
- case 1: // existing version is newer, uh-oh
- LOG(WARNING) << "Found external version of extension " << id
- << "that is older than current version. Current version "
- << "is: " << existing->VersionString() << ". New version "
- << "is: " << version << ". Keeping current version.";
- return;
- }
- }
-
- scoped_refptr<CrxInstaller> installer(
- new CrxInstaller(this, // frontend
- NULL)); // no client (silent install)
- installer->set_install_source(location);
- installer->set_expected_id(id);
- installer->InstallCrx(path);
-}
-
-void ExtensionsService::ReportExtensionLoadError(
- const FilePath& extension_path,
- const std::string &error,
- NotificationType type,
- bool be_noisy) {
- NotificationService* service = NotificationService::current();
- service->Notify(type,
- Source<Profile>(profile_),
- Details<const std::string>(&error));
-
- // TODO(port): note that this isn't guaranteed to work properly on Linux.
- std::string path_str = WideToUTF8(extension_path.ToWStringHack());
- std::string message = base::StringPrintf(
- "Could not load extension from '%s'. %s",
- path_str.c_str(), error.c_str());
- ExtensionErrorReporter::GetInstance()->ReportError(message, be_noisy);
-}
-
-void ExtensionsService::DidCreateRenderViewForBackgroundPage(
- ExtensionHost* host) {
- OrphanedDevTools::iterator iter =
- orphaned_dev_tools_.find(host->extension()->id());
- if (iter == orphaned_dev_tools_.end())
- return;
-
- DevToolsManager::GetInstance()->AttachClientHost(
- iter->second, host->render_view_host());
- orphaned_dev_tools_.erase(iter);
-}
-
-void ExtensionsService::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- switch (type.value) {
- case NotificationType::EXTENSION_PROCESS_TERMINATED: {
- if (profile_ != Source<Profile>(source).ptr()->GetOriginalProfile())
- break;
-
- ExtensionHost* host = Details<ExtensionHost>(details).ptr();
-
- // Unload the entire extension. We want it to be in a consistent state:
- // either fully working or not loaded at all, but never half-crashed.
- // We do it in a PostTask so that other handlers of this notification will
- // still have access to the Extension and ExtensionHost.
- MessageLoop::current()->PostTask(FROM_HERE,
- NewRunnableMethod(this, &ExtensionsService::UnloadExtension,
- host->extension()->id()));
- break;
- }
-
- case NotificationType::PREF_CHANGED: {
- std::string* pref_name = Details<std::string>(details).ptr();
- if (*pref_name == prefs::kExtensionInstallAllowList ||
- *pref_name == prefs::kExtensionInstallDenyList) {
- CheckAdminBlacklist();
- } else if (*pref_name == prefs::kExtensionInstallForceList) {
- UpdateExternalPolicyExtensionProvider();
- CheckForExternalUpdates();
- // TODO(gfeher): Also check for external extensions that can be
- // uninstalled because they were removed from the pref.
- // (crbug.com/63667)
- } else {
- NOTREACHED() << "Unexpected preference name.";
- }
- break;
- }
-
- default:
- NOTREACHED() << "Unexpected notification type.";
- }
-}
-
-bool ExtensionsService::HasApps() const {
- return !GetAppIds().empty();
-}
-
-ExtensionIdSet ExtensionsService::GetAppIds() const {
- ExtensionIdSet result;
- for (ExtensionList::const_iterator it = extensions_.begin();
- it != extensions_.end(); ++it) {
- if ((*it)->is_app() && (*it)->location() != Extension::COMPONENT)
- result.insert((*it)->id());
- }
-
- return result;
-}
-
-bool ExtensionsService::IsBackgroundPageReady(const Extension* extension) {
- return (extension->background_url().is_empty() ||
- extension_runtime_data_[extension->id()].background_page_ready);
-}
-
-void ExtensionsService::SetBackgroundPageReady(const Extension* extension) {
- DCHECK(!extension->background_url().is_empty());
- extension_runtime_data_[extension->id()].background_page_ready = true;
- NotificationService::current()->Notify(
- NotificationType::EXTENSION_BACKGROUND_PAGE_READY,
- Source<const Extension>(extension),
- NotificationService::NoDetails());
-}
-
-bool ExtensionsService::IsBeingUpgraded(const Extension* extension) {
- return extension_runtime_data_[extension->id()].being_upgraded;
-}
-
-void ExtensionsService::SetBeingUpgraded(const Extension* extension,
- bool value) {
- extension_runtime_data_[extension->id()].being_upgraded = value;
-}
-
-PropertyBag* ExtensionsService::GetPropertyBag(const Extension* extension) {
- return &extension_runtime_data_[extension->id()].property_bag;
-}
diff --git a/chrome/browser/extensions/extensions_service.h b/chrome/browser/extensions/extensions_service.h
deleted file mode 100644
index c831039..0000000
--- a/chrome/browser/extensions/extensions_service.h
+++ /dev/null
@@ -1,607 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSIONS_SERVICE_H_
-#define CHROME_BROWSER_EXTENSIONS_EXTENSIONS_SERVICE_H_
-#pragma once
-
-#include <map>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/command_line.h"
-#include "base/file_path.h"
-#include "base/gtest_prod_util.h"
-#include "base/linked_ptr.h"
-#include "base/ref_counted.h"
-#include "base/task.h"
-#include "base/time.h"
-#include "base/tuple.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/extensions/default_apps.h"
-#include "chrome/browser/extensions/extension_icon_manager.h"
-#include "chrome/browser/extensions/extension_menu_manager.h"
-#include "chrome/browser/extensions/extension_prefs.h"
-#include "chrome/browser/extensions/extension_process_manager.h"
-#include "chrome/browser/extensions/extension_toolbar_model.h"
-#include "chrome/browser/extensions/extensions_quota_service.h"
-#include "chrome/browser/extensions/external_extension_provider.h"
-#include "chrome/browser/extensions/sandboxed_extension_unpacker.h"
-#include "chrome/browser/prefs/pref_change_registrar.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/property_bag.h"
-
-class ExtensionsServiceBackend;
-class ExtensionToolbarModel;
-class ExtensionUpdater;
-class GURL;
-class PrefService;
-class Profile;
-class Version;
-
-// A pending extension is an extension that hasn't been installed yet
-// and is intended to be installed in the next auto-update cycle. The
-// update URL of a pending extension may be blank, in which case a
-// default one is assumed.
-struct PendingExtensionInfo {
- // TODO(skerner): Consider merging ExpectedCrxType with
- // browser_sync::ExtensionType.
- enum ExpectedCrxType {
- UNKNOWN, // Sometimes we don't know the type of a pending item. An
- // update URL from external_extensions.json is one such case.
- APP,
- THEME,
- EXTENSION
- };
-
- PendingExtensionInfo(const GURL& update_url,
- ExpectedCrxType expected_crx_type,
- bool is_from_sync,
- bool install_silently,
- bool enable_on_install,
- bool enable_incognito_on_install,
- Extension::Location install_source);
-
- PendingExtensionInfo();
-
- GURL update_url;
- ExpectedCrxType expected_crx_type;
- bool is_from_sync; // This update check was initiated from sync.
- bool install_silently;
- bool enable_on_install;
- bool enable_incognito_on_install;
- Extension::Location install_source;
-};
-
-// A PendingExtensionMap is a map from IDs of pending extensions to
-// their info.
-typedef std::map<std::string, PendingExtensionInfo> PendingExtensionMap;
-
-// This is an interface class to encapsulate the dependencies that
-// ExtensionUpdater has on ExtensionsService. This allows easy mocking.
-class ExtensionUpdateService {
- public:
- virtual ~ExtensionUpdateService() {}
- virtual const ExtensionList* extensions() const = 0;
- virtual const PendingExtensionMap& pending_extensions() const = 0;
- virtual void UpdateExtension(const std::string& id, const FilePath& path,
- const GURL& download_url) = 0;
- virtual const Extension* GetExtensionById(const std::string& id,
- bool include_disabled) = 0;
- virtual void UpdateExtensionBlacklist(
- const std::vector<std::string>& blacklist) = 0;
- virtual void CheckAdminBlacklist() = 0;
- virtual bool HasInstalledExtensions() = 0;
-
- virtual ExtensionPrefs* extension_prefs() = 0;
-};
-
-// Manages installed and running Chromium extensions.
-class ExtensionsService
- : public base::RefCountedThreadSafe<ExtensionsService,
- BrowserThread::DeleteOnUIThread>,
- public ExtensionUpdateService,
- public NotificationObserver {
- public:
- // Information about a registered component extension.
- struct ComponentExtensionInfo {
- ComponentExtensionInfo(const std::string& manifest,
- const FilePath& root_directory)
- : manifest(manifest),
- root_directory(root_directory) {
- }
-
- // The extension's manifest. This is required for component extensions so
- // that ExtensionsService doesn't need to go to disk to load them.
- std::string manifest;
-
- // Directory where the extension is stored.
- FilePath root_directory;
- };
-
- // The name of the directory inside the profile where extensions are
- // installed to.
- static const char* kInstallDirectoryName;
-
- // If auto-updates are turned on, default to running every 5 hours.
- static const int kDefaultUpdateFrequencySeconds = 60 * 60 * 5;
-
- // The name of the file that the current active version number is stored in.
- static const char* kCurrentVersionFileName;
-
- // Determine if a given extension download should be treated as if it came
- // from the gallery. Note that this is requires *both* that the download_url
- // match and that the download was referred from a gallery page.
- bool IsDownloadFromGallery(const GURL& download_url,
- const GURL& referrer_url);
-
- // Determine if the downloaded extension came from the theme mini-gallery,
- // Used to test if we need to show the "Loading" dialog for themes.
- static bool IsDownloadFromMiniGallery(const GURL& download_url);
-
- // Attempts to uninstall an extension from a given ExtensionService. Returns
- // true iff the target extension exists.
- static bool UninstallExtensionHelper(ExtensionsService* extensions_service,
- const std::string& extension_id);
-
- ExtensionsService(Profile* profile,
- const CommandLine* command_line,
- const FilePath& install_directory,
- bool autoupdate_enabled);
-
- // Gets the list of currently installed extensions.
- virtual const ExtensionList* extensions() const { return &extensions_; }
- virtual const ExtensionList* disabled_extensions() const {
- return &disabled_extensions_;
- }
-
- // Gets the set of pending extensions.
- virtual const PendingExtensionMap& pending_extensions() const {
- return pending_extensions_;
- }
-
- // Registers an extension to be loaded as a component extension.
- void register_component_extension(const ComponentExtensionInfo& info) {
- component_extension_manifests_.push_back(info);
- }
-
- // Returns true if any extensions are installed.
- virtual bool HasInstalledExtensions() {
- return !(extensions_.empty() && disabled_extensions_.empty());
- }
-
- const FilePath& install_directory() const { return install_directory_; }
-
- DefaultApps* default_apps() { return &default_apps_; }
-
- // Whether this extension can run in an incognito window.
- bool IsIncognitoEnabled(const Extension* extension);
- void SetIsIncognitoEnabled(const Extension* extension, bool enabled);
-
- // Returns true if the given extension can see events and data from another
- // sub-profile (incognito to original profile, or vice versa).
- bool CanCrossIncognito(const Extension* extension);
-
- // Whether this extension can inject scripts into pages with file URLs.
- bool AllowFileAccess(const Extension* extension);
- void SetAllowFileAccess(const Extension* extension, bool allow);
-
- // Getter and setter for the Browser Action visibility in the toolbar.
- bool GetBrowserActionVisibility(const Extension* extension);
- void SetBrowserActionVisibility(const Extension* extension, bool visible);
-
- // Whether the background page, if any, is ready. We don't load other
- // components until then. If there is no background page, we consider it to
- // be ready.
- bool IsBackgroundPageReady(const Extension* extension);
- void SetBackgroundPageReady(const Extension* extension);
-
- // Getter and setter for the flag that specifies whether the extension is
- // being upgraded.
- bool IsBeingUpgraded(const Extension* extension);
- void SetBeingUpgraded(const Extension* extension, bool value);
-
- // Getter for the extension's runtime data PropertyBag.
- PropertyBag* GetPropertyBag(const Extension* extension);
-
- // Initialize and start all installed extensions.
- void Init();
-
- // Start up the extension event routers.
- void InitEventRouters();
-
- // Look up an extension by ID.
- const Extension* GetExtensionById(const std::string& id,
- bool include_disabled) {
- return GetExtensionByIdInternal(id, true, include_disabled);
- }
-
- // Install the extension file at |extension_path|. Will install as an
- // update if an older version is already installed.
- // For fresh installs, this method also causes the extension to be
- // immediately loaded.
- // TODO(aa): This method can be removed. It is only used by the unit tests,
- // and they could use CrxInstaller directly instead.
- void InstallExtension(const FilePath& extension_path);
-
- // Updates a currently-installed extension with the contents from
- // |extension_path|.
- // TODO(aa): This method can be removed. ExtensionUpdater could use
- // CrxInstaller directly instead.
- virtual void UpdateExtension(const std::string& id,
- const FilePath& extension_path,
- const GURL& download_url);
-
- // Adds an extension in a pending state; the extension with the
- // given info will be installed on the next auto-update cycle.
- //
- // It is an error to call this with an already-installed extension
- // (even a disabled one).
- //
- // TODO(akalin): Replace |install_silently| with a list of
- // pre-enabled permissions.
- void AddPendingExtensionFromSync(
- const std::string& id, const GURL& update_url,
- const PendingExtensionInfo::ExpectedCrxType expected_crx_type,
- bool install_silently, bool enable_on_install,
- bool enable_incognito_on_install);
-
- // Given an extension id and an update URL, schedule the extension
- // to be fetched, installed, and activated.
- void AddPendingExtensionFromExternalUpdateUrl(const std::string& id,
- const GURL& update_url,
- Extension::Location location);
-
- // Like the above. Always installed silently, and defaults update url
- // from extension id.
- void AddPendingExtensionFromDefaultAppList(const std::string& id);
-
- // Reloads the specified extension.
- void ReloadExtension(const std::string& extension_id);
-
- // Uninstalls the specified extension. Callers should only call this method
- // with extensions that exist. |external_uninstall| is a magical parameter
- // that is only used to send information to ExtensionPrefs, which external
- // callers should never set to true.
- // TODO(aa): Remove |external_uninstall| -- this information should be passed
- // to ExtensionPrefs some other way.
- void UninstallExtension(const std::string& extension_id,
- bool external_uninstall);
-
- // Enable or disable an extension. No action if the extension is already
- // enabled/disabled.
- void EnableExtension(const std::string& extension_id);
- void DisableExtension(const std::string& extension_id);
-
- // Updates the |extension|'s granted permissions lists to include all
- // permissions in the |extension|'s manifest.
- void GrantPermissions(const Extension* extension);
-
- // Updates the |extension|'s granted permissions lists to include all
- // permissions in the |extension|'s manifest and re-enables the
- // extension.
- void GrantPermissionsAndEnableExtension(const Extension* extension);
-
- // Load the extension from the directory |extension_path|.
- void LoadExtension(const FilePath& extension_path);
-
- // Load any component extensions.
- void LoadComponentExtensions();
-
- // Load all known extensions (used by startup and testing code).
- void LoadAllExtensions();
-
- // Continues loading all know extensions. It can be called from
- // LoadAllExtensions or from file thread if we had to relocalize manifest
- // (write_to_prefs is true in that case).
- void ContinueLoadAllExtensions(ExtensionPrefs::ExtensionsInfo* info,
- base::TimeTicks start_time,
- bool write_to_prefs);
-
- // Check for updates (or potentially new extensions from external providers)
- void CheckForExternalUpdates();
-
- // Copies the list of force-installed extensions from the user PrefService
- // to ExternalPolicyExtensionProvider.
- void UpdateExternalPolicyExtensionProvider();
-
- // Unload the specified extension.
- void UnloadExtension(const std::string& extension_id);
-
- // Unload all extensions. This is currently only called on shutdown, and
- // does not send notifications.
- void UnloadAllExtensions();
-
- // Called only by testing.
- void ReloadExtensions();
-
- // Scan the extension directory and clean up the cruft.
- void GarbageCollectExtensions();
-
- // The App that represents the web store.
- const Extension* GetWebStoreApp();
-
- // Lookup an extension by |url|.
- const Extension* GetExtensionByURL(const GURL& url);
-
- // If there is an extension for the specified url it is returned. Otherwise
- // returns the extension whose web extent contains |url|.
- const Extension* GetExtensionByWebExtent(const GURL& url);
-
- // Returns an extension that contains any URL that overlaps with the given
- // extent, if one exists.
- const Extension* GetExtensionByOverlappingWebExtent(
- const ExtensionExtent& extent);
-
- // Returns true if |url| should get extension api bindings and be permitted
- // to make api calls. Note that this is independent of what extension
- // permissions the given extension has been granted.
- bool ExtensionBindingsAllowed(const GURL& url);
-
- // Returns the icon to display in the omnibox for the given extension.
- const SkBitmap& GetOmniboxIcon(const std::string& extension_id);
-
- // Returns the icon to display in the omnibox popup window for the given
- // extension.
- const SkBitmap& GetOmniboxPopupIcon(const std::string& extension_id);
-
- // Clear all ExternalExtensionProviders.
- void ClearProvidersForTesting();
-
- // Sets an ExternalExtensionProvider for the service to use during testing.
- // Takes ownership of |test_provider|.
- void AddProviderForTesting(ExternalExtensionProvider* test_provider);
-
- // Called when the initial extensions load has completed.
- virtual void OnLoadedInstalledExtensions();
-
- // Called when an extension has been loaded.
- void OnExtensionLoaded(const Extension* extension);
-
- // Called by the backend when an extension has been installed.
- void OnExtensionInstalled(const Extension* extension);
-
- // Called by the backend when an external extension is found.
- void OnExternalExtensionFileFound(const std::string& id,
- const std::string& version,
- const FilePath& path,
- Extension::Location location);
-
- // Checks if the privileges requested by |extension| have increased, and if
- // so, disables the extension and prompts the user to approve the change.
- void DisableIfPrivilegeIncrease(const Extension* extension);
-
- // Go through each extensions in pref, unload blacklisted extensions
- // and update the blacklist state in pref.
- virtual void UpdateExtensionBlacklist(
- const std::vector<std::string>& blacklist);
-
- // Go through each extension and unload those that the network admin has
- // put on the blacklist (not to be confused with the Google managed blacklist
- // set of extensions.
- virtual void CheckAdminBlacklist();
-
- void set_extensions_enabled(bool enabled) { extensions_enabled_ = enabled; }
- bool extensions_enabled() { return extensions_enabled_; }
-
- void set_show_extensions_prompts(bool enabled) {
- show_extensions_prompts_ = enabled;
- }
-
- bool show_extensions_prompts() {
- return show_extensions_prompts_;
- }
-
- Profile* profile() { return profile_; }
-
- // Profile calls this when it is being destroyed so that we know not to call
- // it.
- void DestroyingProfile();
-
- ExtensionPrefs* extension_prefs() { return extension_prefs_.get(); }
-
- // Whether the extension service is ready.
- // TODO(skerner): Get rid of this method. crbug.com/63756
- bool is_ready() { return ready_; }
-
- // Note that this may return NULL if autoupdate is not turned on.
- ExtensionUpdater* updater() { return updater_.get(); }
-
- ExtensionToolbarModel* toolbar_model() { return &toolbar_model_; }
-
- ExtensionsQuotaService* quota_service() { return &quota_service_; }
-
- ExtensionMenuManager* menu_manager() { return &menu_manager_; }
-
- const std::map<GURL, int>& protected_storage_map() const {
- return protected_storage_map_;
- }
-
- // Notify the frontend that there was an error loading an extension.
- // This method is public because ExtensionsServiceBackend can post to here.
- void ReportExtensionLoadError(const FilePath& extension_path,
- const std::string& error,
- NotificationType type,
- bool be_noisy);
-
- // ExtensionHost of background page calls this method right after its render
- // view has been created.
- void DidCreateRenderViewForBackgroundPage(ExtensionHost* host);
-
- // NotificationObserver
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- // Whether there are any apps installed. Component apps are not included.
- bool HasApps() const;
-
- // Gets the set of loaded app ids. Component apps are not included.
- ExtensionIdSet GetAppIds() const;
-
- private:
- friend class BrowserThread;
- friend class DeleteTask<ExtensionsService>;
-
- // Contains Extension data that can change during the life of the process,
- // but does not persist across restarts.
- struct ExtensionRuntimeData {
- // True if the background page is ready.
- bool background_page_ready;
-
- // True while the extension is being upgraded.
- bool being_upgraded;
-
- // Generic bag of runtime data that users can associate with extensions.
- PropertyBag property_bag;
-
- ExtensionRuntimeData();
- ~ExtensionRuntimeData();
- };
- typedef std::map<std::string, ExtensionRuntimeData> ExtensionRuntimeDataMap;
-
- virtual ~ExtensionsService();
-
- // Clear all persistent data that may have been stored by the extension.
- void ClearExtensionData(const GURL& extension_url);
-
- // Look up an extension by ID, optionally including either or both of enabled
- // and disabled extensions.
- const Extension* GetExtensionByIdInternal(const std::string& id,
- bool include_enabled,
- bool include_disabled);
-
- // Like AddPendingExtension() but assumes an extension with the same
- // id is not already installed.
- void AddPendingExtensionInternal(
- const std::string& id, const GURL& update_url,
- PendingExtensionInfo::ExpectedCrxType crx_type,
- bool is_from_sync, bool install_silently,
- bool enable_on_install, bool enable_incognito_on_install,
- Extension::Location install_source);
-
- // Handles sending notification that |extension| was loaded.
- void NotifyExtensionLoaded(const Extension* extension);
-
- // Handles sending notification that |extension| was unloaded.
- void NotifyExtensionUnloaded(const Extension* extension);
-
- // Helper that updates the active extension list used for crash reporting.
- void UpdateActiveExtensionsInCrashReporter();
-
- // Helper method. Loads extension from prefs.
- void LoadInstalledExtension(const ExtensionInfo& info, bool write_to_prefs);
-
- // Helper methods to configure the storage services accordingly.
- void GrantProtectedStorage(const Extension* extension);
- void RevokeProtectedStorage(const Extension* extension);
- void GrantUnlimitedStorage(const Extension* extension);
- void RevokeUnlimitedStorage(const Extension* extension);
-
- // The profile this ExtensionsService is part of.
- Profile* profile_;
-
- // Preferences for the owning profile.
- scoped_ptr<ExtensionPrefs> extension_prefs_;
-
- // The current list of installed extensions.
- ExtensionList extensions_;
-
- // The list of installed extensions that have been disabled.
- ExtensionList disabled_extensions_;
-
- // The set of pending extensions.
- PendingExtensionMap pending_extensions_;
-
- // The map of extension IDs to their runtime data.
- ExtensionRuntimeDataMap extension_runtime_data_;
-
- // The full path to the directory where extensions are installed.
- FilePath install_directory_;
-
- // Whether or not extensions are enabled.
- bool extensions_enabled_;
-
- // Whether to notify users when they attempt to install an extension.
- bool show_extensions_prompts_;
-
- // The backend that will do IO on behalf of this instance.
- scoped_refptr<ExtensionsServiceBackend> backend_;
-
- // Used by dispatchers to limit API quota for individual extensions.
- ExtensionsQuotaService quota_service_;
-
- // Record that Init() has been called, and NotificationType::EXTENSIONS_READY
- // has fired.
- bool ready_;
-
- // Our extension updater, if updates are turned on.
- scoped_refptr<ExtensionUpdater> updater_;
-
- // The model that tracks extensions with BrowserAction buttons.
- ExtensionToolbarModel toolbar_model_;
-
- // Map unloaded extensions' ids to their paths. When a temporarily loaded
- // extension is unloaded, we lose the infomation about it and don't have
- // any in the extension preferences file.
- typedef std::map<std::string, FilePath> UnloadedExtensionPathMap;
- UnloadedExtensionPathMap unloaded_extension_paths_;
-
- // Map disabled extensions' ids to their paths. When a temporarily loaded
- // extension is disabled before it is reloaded, keep track of the path so that
- // it can be re-enabled upon a successful load.
- typedef std::map<std::string, FilePath> DisabledExtensionPathMap;
- DisabledExtensionPathMap disabled_extension_paths_;
-
- // Map of inspector cookies that are detached, waiting for an extension to be
- // reloaded.
- typedef std::map<std::string, int> OrphanedDevTools;
- OrphanedDevTools orphaned_dev_tools_;
-
- NotificationRegistrar registrar_;
- PrefChangeRegistrar pref_change_registrar_;
-
- // Keeps track of menu items added by extensions.
- ExtensionMenuManager menu_manager_;
-
- // Keeps track of favicon-sized omnibox icons for extensions.
- ExtensionIconManager omnibox_icon_manager_;
- ExtensionIconManager omnibox_popup_icon_manager_;
-
- // List of registered component extensions (see Extension::Location).
- typedef std::vector<ComponentExtensionInfo> RegisteredComponentExtensions;
- RegisteredComponentExtensions component_extension_manifests_;
-
- // Collection of origins we've granted unlimited storage to. This is a
- // map from origin to the number of extensions requiring unlimited
- // storage within that origin.
- typedef std::map<GURL, int> UnlimitedStorageMap;
- UnlimitedStorageMap unlimited_storage_map_;
-
- // Collection of origins whose storage is protected by "Clear browsing data."
- // A map from origin to the number of Apps currently installed and therefore
- // intrinsically protected.
- typedef std::map<GURL, int> ProtectedStorageMap;
- ProtectedStorageMap protected_storage_map_;
-
- // Manages the installation of default apps and the promotion of them in the
- // app launcher.
- DefaultApps default_apps_;
-
- // Flag to make sure event routers are only initialized once.
- bool event_routers_initialized_;
-
- FRIEND_TEST_ALL_PREFIXES(ExtensionsServiceTest,
- UpdatePendingExtensionAlreadyInstalled);
- FRIEND_TEST_ALL_PREFIXES(ExtensionsServiceTest,
- InstallAppsWithUnlimtedStorage);
- FRIEND_TEST_ALL_PREFIXES(ExtensionsServiceTest,
- InstallAppsAndCheckStorageProtection);
- DISALLOW_COPY_AND_ASSIGN(ExtensionsService);
-};
-
-#endif // CHROME_BROWSER_EXTENSIONS_EXTENSIONS_SERVICE_H_
diff --git a/chrome/browser/extensions/extensions_service_unittest.cc b/chrome/browser/extensions/extensions_service_unittest.cc
deleted file mode 100644
index e6c4e3a..0000000
--- a/chrome/browser/extensions/extensions_service_unittest.cc
+++ /dev/null
@@ -1,3178 +0,0 @@
-// 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.
-
-#include "chrome/browser/extensions/extensions_service_unittest.h"
-
-#include <algorithm>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/command_line.h"
-#include "base/file_util.h"
-#include "base/json/json_reader.h"
-#include "base/message_loop.h"
-#include "base/path_service.h"
-#include "base/scoped_ptr.h"
-#include "base/stl_util-inl.h"
-#include "base/string16.h"
-#include "base/string_number_conversions.h"
-#include "base/string_util.h"
-#include "base/task.h"
-#include "base/utf_string_conversions.h"
-#include "base/version.h"
-#include "chrome/browser/appcache/chrome_appcache_service.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/file_system/browser_file_system_context.h"
-#include "chrome/browser/extensions/crx_installer.h"
-#include "chrome/browser/extensions/extension_creator.h"
-#include "chrome/browser/extensions/extension_error_reporter.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/extensions/external_extension_provider.h"
-#include "chrome/browser/extensions/external_pref_extension_provider.h"
-#include "chrome/browser/extensions/pack_extension_job.cc"
-#include "chrome/browser/in_process_webkit/dom_storage_context.h"
-#include "chrome/browser/in_process_webkit/webkit_context.h"
-#include "chrome/browser/prefs/browser_prefs.h"
-#include "chrome/browser/prefs/pref_value_store.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_constants.h"
-#include "chrome/common/extensions/extension_resource.h"
-#include "chrome/common/extensions/url_pattern.h"
-#include "chrome/common/json_value_serializer.h"
-#include "chrome/common/net/url_request_context_getter.h"
-#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/notification_type.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/url_constants.h"
-#include "chrome/test/testing_profile.h"
-#include "googleurl/src/gurl.h"
-#include "net/base/cookie_monster.h"
-#include "net/base/cookie_options.h"
-#include "net/url_request/url_request_context.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-#include "webkit/database/database_tracker.h"
-#include "webkit/database/database_util.h"
-
-namespace keys = extension_manifest_keys;
-
-namespace {
-
-// Extension ids used during testing.
-const char* const all_zero = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
-const char* const zero_n_one = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab";
-const char* const good0 = "behllobkkfkfnphdnhnkndlbkcpglgmj";
-const char* const good1 = "hpiknbiabeeppbpihjehijgoemciehgk";
-const char* const good2 = "bjafgdebaacbbbecmhlhpofkepfkgcpa";
-const char* const good_crx = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
-const char* const page_action = "obcimlgaoabeegjmmpldobjndiealpln";
-const char* const theme_crx = "iamefpfkojoapidjnbafmgkgncegbkad";
-const char* const theme2_crx = "pjpgmfcmabopnnfonnhmdjglfpjjfkbf";
-const char* const permissions_crx = "eagpmdpfmaekmmcejjbmjoecnejeiiin";
-
-struct ExtensionsOrder {
- bool operator()(const Extension* a, const Extension* b) {
- return a->name() < b->name();
- }
-};
-
-static std::vector<std::string> GetErrors() {
- const std::vector<std::string>* errors =
- ExtensionErrorReporter::GetInstance()->GetErrors();
- std::vector<std::string> ret_val;
-
- for (std::vector<std::string>::const_iterator iter = errors->begin();
- iter != errors->end(); ++iter) {
- if (iter->find(".svn") == std::string::npos) {
- ret_val.push_back(*iter);
- }
- }
-
- // The tests rely on the errors being in a certain order, which can vary
- // depending on how filesystem iteration works.
- std::stable_sort(ret_val.begin(), ret_val.end());
-
- return ret_val;
-}
-
-static void AddPattern(ExtensionExtent* extent, const std::string& pattern) {
- int schemes = URLPattern::SCHEME_ALL;
- extent->AddPattern(URLPattern(schemes, pattern));
-}
-
-static void AssertEqualExtents(ExtensionExtent* extent1,
- ExtensionExtent* extent2) {
- std::vector<URLPattern> patterns1 = extent1->patterns();
- std::vector<URLPattern> patterns2 = extent2->patterns();
- std::set<std::string> strings1;
- EXPECT_EQ(patterns1.size(), patterns2.size());
-
- for (size_t i = 0; i < patterns1.size(); ++i)
- strings1.insert(patterns1.at(i).GetAsString());
-
- std::set<std::string> strings2;
- for (size_t i = 0; i < patterns2.size(); ++i)
- strings2.insert(patterns2.at(i).GetAsString());
-
- EXPECT_EQ(strings1, strings2);
-}
-
-} // namespace
-
-class MockExtensionProvider : public ExternalExtensionProvider {
- public:
- explicit MockExtensionProvider(Extension::Location location)
- : location_(location), visit_count_(0) {}
- virtual ~MockExtensionProvider() {}
-
- void UpdateOrAddExtension(const std::string& id,
- const std::string& version,
- const FilePath& path) {
- extension_map_[id] = std::make_pair(version, path);
- }
-
- void RemoveExtension(const std::string& id) {
- extension_map_.erase(id);
- }
-
- // ExternalExtensionProvider implementation:
- virtual void VisitRegisteredExtension(
- Visitor* visitor, const std::set<std::string>& ids_to_ignore) const {
- visit_count_++;
- for (DataMap::const_iterator i = extension_map_.begin();
- i != extension_map_.end(); ++i) {
- if (ids_to_ignore.find(i->first) != ids_to_ignore.end())
- continue;
- scoped_ptr<Version> version;
- version.reset(Version::GetVersionFromString(i->second.first));
-
- visitor->OnExternalExtensionFileFound(
- i->first, version.get(), i->second.second, location_);
- }
- }
-
- virtual bool HasExtension(const std::string& id) const {
- return extension_map_.find(id) != extension_map_.end();
- }
-
- virtual bool GetExtensionDetails(const std::string& id,
- Extension::Location* location,
- scoped_ptr<Version>* version) const {
- DataMap::const_iterator it = extension_map_.find(id);
- if (it == extension_map_.end())
- return false;
-
- if (version)
- version->reset(Version::GetVersionFromString(it->second.first));
-
- if (location)
- *location = location_;
-
- return true;
- }
- int visit_count() const { return visit_count_; }
- void set_visit_count(int visit_count) {
- visit_count_ = visit_count;
- }
-
- private:
- typedef std::map< std::string, std::pair<std::string, FilePath> > DataMap;
- DataMap extension_map_;
- Extension::Location location_;
-
- // visit_count_ tracks the number of calls to VisitRegisteredExtension().
- // Mutable because it must be incremented on each call to
- // VisitRegisteredExtension(), which must be a const method to inherit
- // from the class being mocked.
- mutable int visit_count_;
-
- DISALLOW_COPY_AND_ASSIGN(MockExtensionProvider);
-};
-
-class MockProviderVisitor : public ExternalExtensionProvider::Visitor {
- public:
- MockProviderVisitor() : ids_found_(0) {
- }
-
- int Visit(const std::string& json_data,
- const std::set<std::string>& ignore_list) {
- // Give the test json file to the provider for parsing.
- provider_.reset(new ExternalPrefExtensionProvider());
- provider_->SetPreferencesForTesting(json_data);
-
- // We also parse the file into a dictionary to compare what we get back
- // from the provider.
- JSONStringValueSerializer serializer(json_data);
- Value* json_value = serializer.Deserialize(NULL, NULL);
-
- if (!json_value || !json_value->IsType(Value::TYPE_DICTIONARY)) {
- NOTREACHED() << "Unable to deserialize json data";
- return -1;
- } else {
- DictionaryValue* external_extensions =
- static_cast<DictionaryValue*>(json_value);
- prefs_.reset(external_extensions);
- }
-
- // Reset our counter.
- ids_found_ = 0;
- // Ask the provider to look up all extensions (and return the ones
- // found (that are not on the ignore list).
- provider_->VisitRegisteredExtension(this, ignore_list);
-
- return ids_found_;
- }
-
- virtual void OnExternalExtensionFileFound(const std::string& id,
- const Version* version,
- const FilePath& path,
- Extension::Location unused) {
- ++ids_found_;
- DictionaryValue* pref;
- // This tests is to make sure that the provider only notifies us of the
- // values we gave it. So if the id we doesn't exist in our internal
- // dictionary then something is wrong.
- EXPECT_TRUE(prefs_->GetDictionary(id, &pref))
- << "Got back ID (" << id.c_str() << ") we weren't expecting";
-
- if (pref) {
- EXPECT_TRUE(provider_->HasExtension(id));
-
- // Ask provider if the extension we got back is registered.
- Extension::Location location = Extension::INVALID;
- scoped_ptr<Version> v1;
- FilePath crx_path;
-
- EXPECT_TRUE(provider_->GetExtensionDetails(id, NULL, &v1));
- EXPECT_STREQ(version->GetString().c_str(), v1->GetString().c_str());
-
- scoped_ptr<Version> v2;
- EXPECT_TRUE(provider_->GetExtensionDetails(id, &location, &v2));
- EXPECT_STREQ(version->GetString().c_str(), v1->GetString().c_str());
- EXPECT_STREQ(version->GetString().c_str(), v2->GetString().c_str());
- EXPECT_EQ(Extension::EXTERNAL_PREF, location);
-
- // Remove it so we won't count it ever again.
- prefs_->Remove(id, NULL);
- }
- }
-
- virtual void OnExternalExtensionUpdateUrlFound(
- const std::string& id, const GURL& update_url,
- Extension::Location location) {
- ++ids_found_;
- DictionaryValue* pref;
- // This tests is to make sure that the provider only notifies us of the
- // values we gave it. So if the id we doesn't exist in our internal
- // dictionary then something is wrong.
- EXPECT_TRUE(prefs_->GetDictionary(id, &pref))
- << L"Got back ID (" << id.c_str() << ") we weren't expecting";
- EXPECT_EQ(Extension::EXTERNAL_PREF_DOWNLOAD, location);
-
- if (pref) {
- EXPECT_TRUE(provider_->HasExtension(id));
-
- // External extensions with update URLs do not have versions.
- scoped_ptr<Version> v1;
- Extension::Location location1 = Extension::INVALID;
- EXPECT_TRUE(provider_->GetExtensionDetails(id, &location1, &v1));
- EXPECT_FALSE(v1.get());
- EXPECT_EQ(Extension::EXTERNAL_PREF_DOWNLOAD, location1);
-
- // Remove it so we won't count it again.
- prefs_->Remove(id, NULL);
- }
- }
-
- private:
- int ids_found_;
-
- scoped_ptr<ExternalPrefExtensionProvider> provider_;
- scoped_ptr<DictionaryValue> prefs_;
-
- DISALLOW_COPY_AND_ASSIGN(MockProviderVisitor);
-};
-
-class ExtensionTestingProfile : public TestingProfile {
- public:
- ExtensionTestingProfile() : service_(NULL) {
- }
-
- void set_extensions_service(ExtensionsService* service) {
- service_ = service;
- }
- virtual ExtensionsService* GetExtensionsService() { return service_; }
-
- virtual ChromeAppCacheService* GetAppCacheService() {
- if (!appcache_service_) {
- appcache_service_ = new ChromeAppCacheService;
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(appcache_service_.get(),
- &ChromeAppCacheService::InitializeOnIOThread,
- GetPath(), IsOffTheRecord(),
- make_scoped_refptr(GetHostContentSettingsMap())));
- }
- return appcache_service_;
- }
-
- virtual BrowserFileSystemContext* GetFileSystemContext() {
- if (!browser_file_system_context_)
- browser_file_system_context_ = new BrowserFileSystemContext(
- GetPath(), IsOffTheRecord());
- return browser_file_system_context_;
- }
-
- private:
- ExtensionsService* service_;
- scoped_refptr<ChromeAppCacheService> appcache_service_;
- scoped_refptr<BrowserFileSystemContext> browser_file_system_context_;
-};
-
-// Our message loop may be used in tests which require it to be an IO loop.
-ExtensionsServiceTestBase::ExtensionsServiceTestBase()
- : total_successes_(0),
- loop_(MessageLoop::TYPE_IO),
- ui_thread_(BrowserThread::UI, &loop_),
- db_thread_(BrowserThread::DB, &loop_),
- webkit_thread_(BrowserThread::WEBKIT, &loop_),
- file_thread_(BrowserThread::FILE, &loop_),
- io_thread_(BrowserThread::IO, &loop_) {
-}
-
-ExtensionsServiceTestBase::~ExtensionsServiceTestBase() {
- // Drop our reference to ExtensionsService and TestingProfile, so that they
- // can be destroyed while BrowserThreads and MessageLoop are still around
- // (they are used in the destruction process).
- service_ = NULL;
- profile_.reset(NULL);
- MessageLoop::current()->RunAllPending();
-}
-
-void ExtensionsServiceTestBase::InitializeExtensionsService(
- const FilePath& pref_file, const FilePath& extensions_install_dir) {
- ExtensionTestingProfile* profile = new ExtensionTestingProfile();
- // Create a preference service that only contains user defined
- // preference values.
- PrefService* prefs = PrefService::CreateUserPrefService(pref_file);
- Profile::RegisterUserPrefs(prefs);
- browser::RegisterUserPrefs(prefs);
- profile->SetPrefService(prefs);
-
- profile_.reset(profile);
-
- service_ = profile->CreateExtensionsService(
- CommandLine::ForCurrentProcess(),
- extensions_install_dir);
- service_->set_extensions_enabled(true);
- service_->set_show_extensions_prompts(false);
- profile->set_extensions_service(service_.get());
-
- // When we start up, we want to make sure there is no external provider,
- // since the ExtensionService on Windows will use the Registry as a default
- // provider and if there is something already registered there then it will
- // interfere with the tests. Those tests that need an external provider
- // will register one specifically.
- service_->ClearProvidersForTesting();
-
- total_successes_ = 0;
-}
-
-void ExtensionsServiceTestBase::InitializeInstalledExtensionsService(
- const FilePath& prefs_file, const FilePath& source_install_dir) {
- ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- FilePath path_ = temp_dir_.path();
- path_ = path_.Append(FILE_PATH_LITERAL("TestingExtensionsPath"));
- file_util::Delete(path_, true);
- file_util::CreateDirectory(path_);
- FilePath temp_prefs = path_.Append(FILE_PATH_LITERAL("Preferences"));
- file_util::CopyFile(prefs_file, temp_prefs);
-
- extensions_install_dir_ = path_.Append(FILE_PATH_LITERAL("Extensions"));
- file_util::Delete(extensions_install_dir_, true);
- file_util::CopyDirectory(source_install_dir, extensions_install_dir_, true);
-
- InitializeExtensionsService(temp_prefs, extensions_install_dir_);
-}
-
-void ExtensionsServiceTestBase::InitializeEmptyExtensionsService() {
- ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- FilePath path_ = temp_dir_.path();
- path_ = path_.Append(FILE_PATH_LITERAL("TestingExtensionsPath"));
- file_util::Delete(path_, true);
- file_util::CreateDirectory(path_);
- FilePath prefs_filename = path_
- .Append(FILE_PATH_LITERAL("TestPreferences"));
- extensions_install_dir_ = path_.Append(FILE_PATH_LITERAL("Extensions"));
- file_util::Delete(extensions_install_dir_, true);
- file_util::CreateDirectory(extensions_install_dir_);
-
- InitializeExtensionsService(prefs_filename, extensions_install_dir_);
-}
-
-// static
-void ExtensionsServiceTestBase::SetUpTestCase() {
- ExtensionErrorReporter::Init(false); // no noisy errors
-}
-
-void ExtensionsServiceTestBase::SetUp() {
- ExtensionErrorReporter::GetInstance()->ClearErrors();
-}
-
-class ExtensionsServiceTest
- : public ExtensionsServiceTestBase, public NotificationObserver {
- public:
- ExtensionsServiceTest() : installed_(NULL) {
- registrar_.Add(this, NotificationType::EXTENSION_LOADED,
- NotificationService::AllSources());
- registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
- NotificationService::AllSources());
- registrar_.Add(this, NotificationType::EXTENSION_INSTALLED,
- NotificationService::AllSources());
- registrar_.Add(this, NotificationType::THEME_INSTALLED,
- NotificationService::AllSources());
- }
-
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- switch (type.value) {
- case NotificationType::EXTENSION_LOADED: {
- const Extension* extension = Details<const Extension>(details).ptr();
- loaded_.push_back(make_scoped_refptr(extension));
- // The tests rely on the errors being in a certain order, which can vary
- // depending on how filesystem iteration works.
- std::stable_sort(loaded_.begin(), loaded_.end(), ExtensionsOrder());
- break;
- }
-
- case NotificationType::EXTENSION_UNLOADED: {
- const Extension* e = Details<const Extension>(details).ptr();
- unloaded_id_ = e->id();
- ExtensionList::iterator i =
- std::find(loaded_.begin(), loaded_.end(), e);
- // TODO(erikkay) fix so this can be an assert. Right now the tests
- // are manually calling clear() on loaded_, so this isn't doable.
- if (i == loaded_.end())
- return;
- loaded_.erase(i);
- break;
- }
- case NotificationType::EXTENSION_INSTALLED:
- case NotificationType::THEME_INSTALLED:
- installed_ = Details<const Extension>(details).ptr();
- break;
-
- default:
- DCHECK(false);
- }
- }
-
- void AddMockExternalProvider(ExternalExtensionProvider* provider) {
- service_->AddProviderForTesting(provider);
- }
-
- protected:
- void TestExternalProvider(MockExtensionProvider* provider,
- Extension::Location location);
-
- void PackAndInstallExtension(const FilePath& dir_path,
- const FilePath& pem_path,
- bool should_succeed) {
- FilePath crx_path;
- ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &crx_path));
- crx_path = crx_path.AppendASCII("temp.crx");
-
- // Use the existing pem key, if provided.
- FilePath pem_output_path;
- if (pem_path.value().empty()) {
- pem_output_path = crx_path.DirName().AppendASCII("temp.pem");
- ASSERT_TRUE(file_util::Delete(pem_output_path, false));
- } else {
- ASSERT_TRUE(file_util::PathExists(pem_path));
- }
-
- ASSERT_TRUE(file_util::Delete(crx_path, false));
-
- scoped_ptr<ExtensionCreator> creator(new ExtensionCreator());
- ASSERT_TRUE(creator->Run(dir_path,
- crx_path,
- pem_path,
- pem_output_path));
-
- ASSERT_TRUE(file_util::PathExists(crx_path));
-
- InstallExtension(crx_path, should_succeed);
- }
-
- void PackAndInstallExtension(const FilePath& dir_path,
- bool should_succeed) {
- PackAndInstallExtension(dir_path, FilePath(), should_succeed);
- }
-
- void InstallExtension(const FilePath& path,
- bool should_succeed) {
- ASSERT_TRUE(file_util::PathExists(path));
- service_->InstallExtension(path);
- loop_.RunAllPending();
- std::vector<std::string> errors = GetErrors();
- if (should_succeed) {
- ++total_successes_;
-
- EXPECT_TRUE(installed_) << path.value();
-
- ASSERT_EQ(1u, loaded_.size()) << path.value();
- EXPECT_EQ(0u, errors.size()) << path.value();
- EXPECT_EQ(total_successes_, service_->extensions()->size()) <<
- path.value();
- EXPECT_TRUE(service_->GetExtensionById(loaded_[0]->id(), false)) <<
- path.value();
- for (std::vector<std::string>::iterator err = errors.begin();
- err != errors.end(); ++err) {
- LOG(ERROR) << *err;
- }
- } else {
- EXPECT_FALSE(installed_) << path.value();
- EXPECT_EQ(0u, loaded_.size()) << path.value();
- EXPECT_EQ(1u, errors.size()) << path.value();
- }
-
- installed_ = NULL;
- loaded_.clear();
- ExtensionErrorReporter::GetInstance()->ClearErrors();
- }
-
- enum UpdateState {
- FAILED_SILENTLY,
- FAILED,
- UPDATED,
- INSTALLED,
- ENABLED
- };
-
- void UpdateExtension(const std::string& id, const FilePath& in_path,
- UpdateState expected_state) {
- ASSERT_TRUE(file_util::PathExists(in_path));
-
- // We need to copy this to a temporary location because Update() will delete
- // it.
- FilePath path = temp_dir_.path();
- path = path.Append(in_path.BaseName());
- ASSERT_TRUE(file_util::CopyFile(in_path, path));
-
- int previous_enabled_extension_count =
- service_->extensions()->size();
- int previous_installed_extension_count =
- previous_enabled_extension_count +
- service_->disabled_extensions()->size();
-
- service_->UpdateExtension(id, path, GURL());
- loop_.RunAllPending();
-
- std::vector<std::string> errors = GetErrors();
- int error_count = errors.size();
- int enabled_extension_count =
- service_->extensions()->size();
- int installed_extension_count =
- enabled_extension_count + service_->disabled_extensions()->size();
-
- int expected_error_count = (expected_state == FAILED) ? 1 : 0;
- EXPECT_EQ(expected_error_count, error_count) << path.value();
-
- if (expected_state <= FAILED) {
- EXPECT_EQ(previous_enabled_extension_count,
- enabled_extension_count);
- EXPECT_EQ(previous_installed_extension_count,
- installed_extension_count);
- } else {
- int expected_installed_extension_count =
- (expected_state >= INSTALLED) ? 1 : 0;
- int expected_enabled_extension_count =
- (expected_state >= ENABLED) ? 1 : 0;
- EXPECT_EQ(expected_installed_extension_count,
- installed_extension_count);
- EXPECT_EQ(expected_enabled_extension_count,
- enabled_extension_count);
- }
-
- // Update() should delete the temporary input file.
- EXPECT_FALSE(file_util::PathExists(path));
- }
-
- void ValidatePrefKeyCount(size_t count) {
- DictionaryValue* dict =
- profile_->GetPrefs()->GetMutableDictionary("extensions.settings");
- ASSERT_TRUE(dict != NULL);
- EXPECT_EQ(count, dict->size());
- }
-
- void ValidateBooleanPref(const std::string& extension_id,
- const std::string& pref_path,
- bool expected_val) {
- std::string msg = " while checking: ";
- msg += extension_id;
- msg += " ";
- msg += pref_path;
- msg += " == ";
- msg += expected_val ? "true" : "false";
-
- PrefService* prefs = profile_->GetPrefs();
- const DictionaryValue* dict =
- prefs->GetDictionary("extensions.settings");
- ASSERT_TRUE(dict != NULL) << msg;
- DictionaryValue* pref = NULL;
- ASSERT_TRUE(dict->GetDictionary(extension_id, &pref)) << msg;
- EXPECT_TRUE(pref != NULL) << msg;
- bool val;
- ASSERT_TRUE(pref->GetBoolean(pref_path, &val)) << msg;
- EXPECT_EQ(expected_val, val) << msg;
- }
-
- bool IsPrefExist(const std::string& extension_id,
- const std::string& pref_path) {
- const DictionaryValue* dict =
- profile_->GetPrefs()->GetDictionary("extensions.settings");
- if (dict == NULL) return false;
- DictionaryValue* pref = NULL;
- if (!dict->GetDictionary(extension_id, &pref)) {
- return false;
- }
- if (pref == NULL) {
- return false;
- }
- bool val;
- if (!pref->GetBoolean(pref_path, &val)) {
- return false;
- }
- return true;
- }
-
- void ValidateIntegerPref(const std::string& extension_id,
- const std::string& pref_path,
- int expected_val) {
- std::string msg = " while checking: ";
- msg += extension_id;
- msg += " ";
- msg += pref_path;
- msg += " == ";
- msg += base::IntToString(expected_val);
-
- PrefService* prefs = profile_->GetPrefs();
- const DictionaryValue* dict =
- prefs->GetDictionary("extensions.settings");
- ASSERT_TRUE(dict != NULL) << msg;
- DictionaryValue* pref = NULL;
- ASSERT_TRUE(dict->GetDictionary(extension_id, &pref)) << msg;
- EXPECT_TRUE(pref != NULL) << msg;
- int val;
- ASSERT_TRUE(pref->GetInteger(pref_path, &val)) << msg;
- EXPECT_EQ(expected_val, val) << msg;
- }
-
- void ValidateStringPref(const std::string& extension_id,
- const std::string& pref_path,
- const std::string& expected_val) {
- std::string msg = " while checking: ";
- msg += extension_id;
- msg += ".manifest.";
- msg += pref_path;
- msg += " == ";
- msg += expected_val;
-
- const DictionaryValue* dict =
- profile_->GetPrefs()->GetDictionary("extensions.settings");
- ASSERT_TRUE(dict != NULL) << msg;
- DictionaryValue* pref = NULL;
- std::string manifest_path = extension_id + ".manifest";
- ASSERT_TRUE(dict->GetDictionary(manifest_path, &pref)) << msg;
- EXPECT_TRUE(pref != NULL) << msg;
- std::string val;
- ASSERT_TRUE(pref->GetString(pref_path, &val)) << msg;
- EXPECT_EQ(expected_val, val) << msg;
- }
-
- void SetPref(const std::string& extension_id,
- const std::string& pref_path,
- Value* value,
- const std::string& msg) {
- const DictionaryValue* dict =
- profile_->GetPrefs()->GetMutableDictionary("extensions.settings");
- ASSERT_TRUE(dict != NULL) << msg;
- DictionaryValue* pref = NULL;
- ASSERT_TRUE(dict->GetDictionary(extension_id, &pref)) << msg;
- EXPECT_TRUE(pref != NULL) << msg;
- pref->Set(pref_path, value);
- }
-
- void SetPrefInteg(const std::string& extension_id,
- const std::string& pref_path,
- int value) {
- std::string msg = " while setting: ";
- msg += extension_id;
- msg += " ";
- msg += pref_path;
- msg += " = ";
- msg += base::IntToString(value);
-
- SetPref(extension_id, pref_path, Value::CreateIntegerValue(value), msg);
- }
-
- void SetPrefBool(const std::string& extension_id,
- const std::string& pref_path,
- bool value) {
- std::string msg = " while setting: ";
- msg += extension_id + " " + pref_path;
- msg += " = ";
- msg += (value ? "true" : "false");
-
- SetPref(extension_id, pref_path, Value::CreateBooleanValue(value), msg);
- }
-
- void ClearPref(const std::string& extension_id,
- const std::string& pref_path) {
- std::string msg = " while clearing: ";
- msg += extension_id + " " + pref_path;
-
- const DictionaryValue* dict =
- profile_->GetPrefs()->GetMutableDictionary("extensions.settings");
- ASSERT_TRUE(dict != NULL) << msg;
- DictionaryValue* pref = NULL;
- ASSERT_TRUE(dict->GetDictionary(extension_id, &pref)) << msg;
- EXPECT_TRUE(pref != NULL) << msg;
- pref->Remove(pref_path, NULL);
- }
-
- void SetPrefStringSet(const std::string& extension_id,
- const std::string& pref_path,
- const std::set<std::string>& value) {
- std::string msg = " while setting: ";
- msg += extension_id + " " + pref_path;
-
- ListValue* list_value = new ListValue();
- for (std::set<std::string>::const_iterator iter = value.begin();
- iter != value.end(); ++iter)
- list_value->Append(Value::CreateStringValue(*iter));
-
- SetPref(extension_id, pref_path, list_value, msg);
- }
-
- protected:
- ExtensionList loaded_;
- std::string unloaded_id_;
- const Extension* installed_;
-
- private:
- NotificationRegistrar registrar_;
-};
-
-FilePath NormalizeSeparators(const FilePath& path) {
-#if defined(FILE_PATH_USES_WIN_SEPARATORS)
- return path.NormalizeWindowsPathSeparators();
-#else
- return path;
-#endif // FILE_PATH_USES_WIN_SEPARATORS
-}
-
-// Receives notifications from a PackExtensionJob, indicating either that
-// packing succeeded or that there was some error.
-class PackExtensionTestClient : public PackExtensionJob::Client {
- public:
- PackExtensionTestClient(const FilePath& expected_crx_path,
- const FilePath& expected_private_key_path);
- virtual void OnPackSuccess(const FilePath& crx_path,
- const FilePath& private_key_path);
- virtual void OnPackFailure(const std::string& error_message);
-
- private:
- const FilePath expected_crx_path_;
- const FilePath expected_private_key_path_;
- DISALLOW_COPY_AND_ASSIGN(PackExtensionTestClient);
-};
-
-PackExtensionTestClient::PackExtensionTestClient(
- const FilePath& expected_crx_path,
- const FilePath& expected_private_key_path)
- : expected_crx_path_(expected_crx_path),
- expected_private_key_path_(expected_private_key_path) {}
-
-// If packing succeeded, we make sure that the package names match our
-// expectations.
-void PackExtensionTestClient::OnPackSuccess(const FilePath& crx_path,
- const FilePath& private_key_path) {
- // We got the notification and processed it; we don't expect any further tasks
- // to be posted to the current thread, so we should stop blocking and continue
- // on with the rest of the test.
- // This call to |Quit()| matches the call to |Run()| in the
- // |PackPunctuatedExtension| test.
- MessageLoop::current()->Quit();
- EXPECT_EQ(expected_crx_path_.value(), crx_path.value());
- EXPECT_EQ(expected_private_key_path_.value(), private_key_path.value());
- ASSERT_TRUE(file_util::PathExists(private_key_path));
-}
-
-// The tests are designed so that we never expect to see a packing error.
-void PackExtensionTestClient::OnPackFailure(const std::string& error_message) {
- FAIL() << "Packing should not fail.";
-}
-
-// Test loading good extensions from the profile directory.
-TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectorySuccess) {
- // Initialize the test dir with a good Preferences/extensions.
- FilePath source_install_dir;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir));
- source_install_dir = source_install_dir
- .AppendASCII("extensions")
- .AppendASCII("good")
- .AppendASCII("Extensions");
- FilePath pref_path = source_install_dir
- .DirName()
- .AppendASCII("Preferences");
- InitializeInstalledExtensionsService(pref_path, source_install_dir);
-
- service_->Init();
-
- // On Chrome OS, we disallow extensions with plugins. "good1" has plugins,
- // so we need to edit it out here.
- uint32 expected_num_extensions = 3u;
-#if defined(OS_CHROMEOS)
- --expected_num_extensions;
-#endif
- ASSERT_EQ(expected_num_extensions, loaded_.size());
-
- EXPECT_EQ(std::string(good0), loaded_[0]->id());
- EXPECT_EQ(std::string("My extension 1"),
- loaded_[0]->name());
- EXPECT_EQ(std::string("The first extension that I made."),
- loaded_[0]->description());
- EXPECT_EQ(Extension::INTERNAL, loaded_[0]->location());
- EXPECT_TRUE(service_->GetExtensionById(loaded_[0]->id(), false));
- EXPECT_EQ(expected_num_extensions, service_->extensions()->size());
-
- ValidatePrefKeyCount(3);
- ValidateIntegerPref(good0, "state", Extension::ENABLED);
- ValidateIntegerPref(good0, "location", Extension::INTERNAL);
- ValidateIntegerPref(good1, "state", Extension::ENABLED);
- ValidateIntegerPref(good1, "location", Extension::INTERNAL);
- ValidateIntegerPref(good2, "state", Extension::ENABLED);
- ValidateIntegerPref(good2, "location", Extension::INTERNAL);
-
- const Extension* extension = loaded_[0];
- const UserScriptList& scripts = extension->content_scripts();
- ASSERT_EQ(2u, scripts.size());
- EXPECT_EQ(3u, scripts[0].url_patterns().size());
- EXPECT_EQ("file://*",
- scripts[0].url_patterns()[0].GetAsString());
- EXPECT_EQ("http://*.google.com/*",
- scripts[0].url_patterns()[1].GetAsString());
- EXPECT_EQ("https://*.google.com/*",
- scripts[0].url_patterns()[2].GetAsString());
- EXPECT_EQ(2u, scripts[0].js_scripts().size());
- ExtensionResource resource00(extension->id(),
- scripts[0].js_scripts()[0].extension_root(),
- scripts[0].js_scripts()[0].relative_path());
- FilePath expected_path(extension->path().AppendASCII("script1.js"));
- ASSERT_TRUE(file_util::AbsolutePath(&expected_path));
- EXPECT_TRUE(resource00.ComparePathWithDefault(expected_path));
- ExtensionResource resource01(extension->id(),
- scripts[0].js_scripts()[1].extension_root(),
- scripts[0].js_scripts()[1].relative_path());
- expected_path = extension->path().AppendASCII("script2.js");
- ASSERT_TRUE(file_util::AbsolutePath(&expected_path));
- EXPECT_TRUE(resource01.ComparePathWithDefault(expected_path));
- EXPECT_TRUE(extension->plugins().empty());
- EXPECT_EQ(1u, scripts[1].url_patterns().size());
- EXPECT_EQ("http://*.news.com/*", scripts[1].url_patterns()[0].GetAsString());
- ExtensionResource resource10(extension->id(),
- scripts[1].js_scripts()[0].extension_root(),
- scripts[1].js_scripts()[0].relative_path());
- expected_path =
- extension->path().AppendASCII("js_files").AppendASCII("script3.js");
- ASSERT_TRUE(file_util::AbsolutePath(&expected_path));
- EXPECT_TRUE(resource10.ComparePathWithDefault(expected_path));
- const std::vector<URLPattern> permissions = extension->host_permissions();
- ASSERT_EQ(2u, permissions.size());
- EXPECT_EQ("http://*.google.com/*", permissions[0].GetAsString());
- EXPECT_EQ("https://*.google.com/*", permissions[1].GetAsString());
-
-#if !defined(OS_CHROMEOS)
- EXPECT_EQ(std::string(good1), loaded_[1]->id());
- EXPECT_EQ(std::string("My extension 2"), loaded_[1]->name());
- EXPECT_EQ(std::string(""), loaded_[1]->description());
- EXPECT_EQ(loaded_[1]->GetResourceURL("background.html"),
- loaded_[1]->background_url());
- EXPECT_EQ(0u, loaded_[1]->content_scripts().size());
- EXPECT_EQ(2u, loaded_[1]->plugins().size());
- EXPECT_EQ(loaded_[1]->path().AppendASCII("content_plugin.dll").value(),
- loaded_[1]->plugins()[0].path.value());
- EXPECT_TRUE(loaded_[1]->plugins()[0].is_public);
- EXPECT_EQ(loaded_[1]->path().AppendASCII("extension_plugin.dll").value(),
- loaded_[1]->plugins()[1].path.value());
- EXPECT_FALSE(loaded_[1]->plugins()[1].is_public);
- EXPECT_EQ(Extension::INTERNAL, loaded_[1]->location());
-#endif
-
- int index = expected_num_extensions - 1;
- EXPECT_EQ(std::string(good2), loaded_[index]->id());
- EXPECT_EQ(std::string("My extension 3"), loaded_[index]->name());
- EXPECT_EQ(std::string(""), loaded_[index]->description());
- EXPECT_EQ(0u, loaded_[index]->content_scripts().size());
- EXPECT_EQ(Extension::INTERNAL, loaded_[index]->location());
-};
-
-// Test loading bad extensions from the profile directory.
-TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectoryFail) {
- // Initialize the test dir with a bad Preferences/extensions.
- FilePath source_install_dir;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir));
- source_install_dir = source_install_dir
- .AppendASCII("extensions")
- .AppendASCII("bad")
- .AppendASCII("Extensions");
- FilePath pref_path = source_install_dir
- .DirName()
- .AppendASCII("Preferences");
-
- InitializeInstalledExtensionsService(pref_path, source_install_dir);
-
- service_->Init();
- loop_.RunAllPending();
-
- ASSERT_EQ(4u, GetErrors().size());
- ASSERT_EQ(0u, loaded_.size());
-
- EXPECT_TRUE(MatchPattern(GetErrors()[0],
- std::string("Could not load extension from '*'. ") +
- extension_manifest_errors::kManifestUnreadable)) << GetErrors()[0];
-
- EXPECT_TRUE(MatchPattern(GetErrors()[1],
- std::string("Could not load extension from '*'. ") +
- extension_manifest_errors::kManifestUnreadable)) << GetErrors()[1];
-
- EXPECT_TRUE(MatchPattern(GetErrors()[2],
- std::string("Could not load extension from '*'. ") +
- extension_manifest_errors::kMissingFile)) << GetErrors()[2];
-
- EXPECT_TRUE(MatchPattern(GetErrors()[3],
- std::string("Could not load extension from '*'. ") +
- extension_manifest_errors::kManifestUnreadable)) << GetErrors()[3];
-};
-
-// Test that partially deleted extensions are cleaned up during startup
-// Test loading bad extensions from the profile directory.
-TEST_F(ExtensionsServiceTest, CleanupOnStartup) {
- FilePath source_install_dir;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir));
- source_install_dir = source_install_dir
- .AppendASCII("extensions")
- .AppendASCII("good")
- .AppendASCII("Extensions");
- FilePath pref_path = source_install_dir
- .DirName()
- .AppendASCII("Preferences");
-
- InitializeInstalledExtensionsService(pref_path, source_install_dir);
-
- // Simulate that one of them got partially deleted by clearing its pref.
- DictionaryValue* dict =
- profile_->GetPrefs()->GetMutableDictionary("extensions.settings");
- ASSERT_TRUE(dict != NULL);
- dict->Remove("behllobkkfkfnphdnhnkndlbkcpglgmj", NULL);
-
- service_->Init();
- loop_.RunAllPending();
-
- file_util::FileEnumerator dirs(extensions_install_dir_, false,
- file_util::FileEnumerator::DIRECTORIES);
- size_t count = 0;
- while (!dirs.Next().empty())
- count++;
-
- // We should have only gotten two extensions now.
- EXPECT_EQ(2u, count);
-
- // And extension1 dir should now be toast.
- FilePath extension_dir = extensions_install_dir_
- .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj");
- ASSERT_FALSE(file_util::PathExists(extension_dir));
-}
-
-// Test installing extensions. This test tries to install few extensions using
-// crx files. If you need to change those crx files, feel free to repackage
-// them, throw away the key used and change the id's above.
-TEST_F(ExtensionsServiceTest, InstallExtension) {
- InitializeEmptyExtensionsService();
-
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
-
- // Extensions not enabled.
- set_extensions_enabled(false);
- FilePath path = extensions_path.AppendASCII("good.crx");
- InstallExtension(path, false);
- set_extensions_enabled(true);
-
- ValidatePrefKeyCount(0);
-
- // A simple extension that should install without error.
- path = extensions_path.AppendASCII("good.crx");
- InstallExtension(path, true);
- // TODO(erikkay): verify the contents of the installed extension.
-
- int pref_count = 0;
- ValidatePrefKeyCount(++pref_count);
- ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
- ValidateIntegerPref(good_crx, "location", Extension::INTERNAL);
-
- // An extension with page actions.
- path = extensions_path.AppendASCII("page_action.crx");
- InstallExtension(path, true);
- ValidatePrefKeyCount(++pref_count);
- ValidateIntegerPref(page_action, "state", Extension::ENABLED);
- ValidateIntegerPref(page_action, "location", Extension::INTERNAL);
-
- // Bad signature.
- path = extensions_path.AppendASCII("bad_signature.crx");
- InstallExtension(path, false);
- ValidatePrefKeyCount(pref_count);
-
- // 0-length extension file.
- path = extensions_path.AppendASCII("not_an_extension.crx");
- InstallExtension(path, false);
- ValidatePrefKeyCount(pref_count);
-
- // Bad magic number.
- path = extensions_path.AppendASCII("bad_magic.crx");
- InstallExtension(path, false);
- ValidatePrefKeyCount(pref_count);
-
- // Extensions cannot have folders or files that have underscores except in
- // certain whitelisted cases (eg _locales). This is an example of a broader
- // class of validation that we do to the directory structure of the extension.
- // We did not used to handle this correctly for installation.
- path = extensions_path.AppendASCII("bad_underscore.crx");
- InstallExtension(path, false);
- ValidatePrefKeyCount(pref_count);
-
- // TODO(erikkay): add more tests for many of the failure cases.
- // TODO(erikkay): add tests for upgrade cases.
-}
-
-// Install a user script (they get converted automatically to an extension)
-TEST_F(ExtensionsServiceTest, InstallUserScript) {
- // The details of script conversion are tested elsewhere, this just tests
- // integration with ExtensionsService.
- InitializeEmptyExtensionsService();
-
- FilePath path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
- path = path.AppendASCII("extensions")
- .AppendASCII("user_script_basic.user.js");
-
- ASSERT_TRUE(file_util::PathExists(path));
- scoped_refptr<CrxInstaller> installer(
- new CrxInstaller(service_, NULL)); // silent install
- installer->InstallUserScript(
- path,
- GURL("http://www.aaronboodman.com/scripts/user_script_basic.user.js"));
-
- loop_.RunAllPending();
- std::vector<std::string> errors = GetErrors();
- EXPECT_TRUE(installed_) << "Nothing was installed.";
- ASSERT_EQ(1u, loaded_.size()) << "Nothing was loaded.";
- EXPECT_EQ(0u, errors.size()) << "There were errors: "
- << JoinString(errors, ',');
- EXPECT_TRUE(service_->GetExtensionById(loaded_[0]->id(), false)) <<
- path.value();
-
- installed_ = NULL;
- loaded_.clear();
- ExtensionErrorReporter::GetInstance()->ClearErrors();
-}
-
-// This tests that the granted permissions preferences are correctly set when
-// installing an extension.
-TEST_F(ExtensionsServiceTest, GrantedPermissions) {
- InitializeEmptyExtensionsService();
- FilePath path;
- FilePath pem_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
- path = path.AppendASCII("extensions")
- .AppendASCII("permissions");
-
- pem_path = path.AppendASCII("unknown.pem");
- path = path.AppendASCII("unknown");
-
- ASSERT_TRUE(file_util::PathExists(pem_path));
- ASSERT_TRUE(file_util::PathExists(path));
-
- ExtensionPrefs* prefs = service_->extension_prefs();
-
- std::set<std::string> expected_api_perms;
- std::set<std::string> known_api_perms;
- bool full_access;
- ExtensionExtent expected_host_perms;
- ExtensionExtent known_host_perms;
-
- // Make sure there aren't any granted permissions before the
- // extension is installed.
- EXPECT_FALSE(prefs->GetGrantedPermissions(
- permissions_crx, &full_access, &known_api_perms, &known_host_perms));
- EXPECT_TRUE(known_api_perms.empty());
- EXPECT_TRUE(known_host_perms.is_empty());
-
- PackAndInstallExtension(path, pem_path, true);
-
- EXPECT_EQ(0u, GetErrors().size());
- ASSERT_EQ(1u, service_->extensions()->size());
- std::string extension_id = service_->extensions()->at(0)->id();
- EXPECT_EQ(permissions_crx, extension_id);
-
-
- // Verify that the valid API permissions have been recognized.
- expected_api_perms.insert("tabs");
-
- AddPattern(&expected_host_perms, "http://*.google.com/*");
- AddPattern(&expected_host_perms, "https://*.google.com/*");
- AddPattern(&expected_host_perms, "http://*.google.com.hk/*");
- AddPattern(&expected_host_perms, "http://www.example.com/*");
-
- EXPECT_TRUE(prefs->GetGrantedPermissions(extension_id,
- &full_access,
- &known_api_perms,
- &known_host_perms));
-
- EXPECT_EQ(expected_api_perms, known_api_perms);
- EXPECT_FALSE(full_access);
- AssertEqualExtents(&expected_host_perms, &known_host_perms);
-}
-
-#if !defined(OS_CHROMEOS)
-// Tests that the granted permissions full_access bit gets set correctly when
-// an extension contains an NPAPI plugin. Don't run this test on Chrome OS
-// since they don't support plugins.
-TEST_F(ExtensionsServiceTest, GrantedFullAccessPermissions) {
- InitializeEmptyExtensionsService();
-
- FilePath path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
- path = path.AppendASCII("extensions")
- .AppendASCII("good")
- .AppendASCII("Extensions")
- .AppendASCII(good1)
- .AppendASCII("2");
-
- ASSERT_TRUE(file_util::PathExists(path));
-
- PackAndInstallExtension(path, true);
-
- EXPECT_EQ(0u, GetErrors().size());
- EXPECT_EQ(1u, service_->extensions()->size());
- const Extension* extension = service_->extensions()->at(0);
- std::string extension_id = extension->id();
- ExtensionPrefs* prefs = service_->extension_prefs();
-
- bool full_access;
- std::set<std::string> api_permissions;
- ExtensionExtent host_permissions;
- EXPECT_TRUE(prefs->GetGrantedPermissions(
- extension_id, &full_access, &api_permissions, &host_permissions));
-
- EXPECT_TRUE(full_access);
- EXPECT_TRUE(api_permissions.empty());
- EXPECT_TRUE(host_permissions.is_empty());
-}
-#endif
-
-// Tests that the extension is disabled when permissions are missing from
-// the extension's granted permissions preferences. (This simulates updating
-// the browser to a version which recognizes more permissions).
-TEST_F(ExtensionsServiceTest, GrantedAPIAndHostPermissions) {
- InitializeEmptyExtensionsService();
-
- FilePath path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
- path = path.AppendASCII("extensions")
- .AppendASCII("permissions")
- .AppendASCII("unknown");
-
- ASSERT_TRUE(file_util::PathExists(path));
-
- PackAndInstallExtension(path, true);
-
- EXPECT_EQ(0u, GetErrors().size());
- EXPECT_EQ(1u, service_->extensions()->size());
- const Extension* extension = service_->extensions()->at(0);
- std::string extension_id = extension->id();
-
- ExtensionPrefs* prefs = service_->extension_prefs();
-
- std::set<std::string> expected_api_permissions;
- ExtensionExtent expected_host_permissions;
-
- expected_api_permissions.insert("tabs");
- AddPattern(&expected_host_permissions, "http://*.google.com/*");
- AddPattern(&expected_host_permissions, "https://*.google.com/*");
- AddPattern(&expected_host_permissions, "http://*.google.com.hk/*");
- AddPattern(&expected_host_permissions, "http://www.example.com/*");
-
- std::set<std::string> api_permissions;
- std::set<std::string> host_permissions;
-
- // Test that the extension is disabled when an API permission is missing from
- // the extension's granted api permissions preference. (This simulates
- // updating the browser to a version which recognizes a new API permission).
- SetPrefStringSet(extension_id, "granted_permissions.api", api_permissions);
-
- service_->ReloadExtensions();
-
- EXPECT_EQ(1u, service_->disabled_extensions()->size());
- extension = service_->disabled_extensions()->at(0);
-
- ASSERT_TRUE(prefs->GetExtensionState(extension_id) == Extension::DISABLED);
- ASSERT_TRUE(prefs->DidExtensionEscalatePermissions(extension_id));
-
- // Now grant and re-enable the extension, making sure the prefs are updated.
- service_->GrantPermissionsAndEnableExtension(extension);
-
- ASSERT_TRUE(prefs->GetExtensionState(extension_id) == Extension::ENABLED);
- ASSERT_FALSE(prefs->DidExtensionEscalatePermissions(extension_id));
-
- std::set<std::string> current_api_permissions;
- ExtensionExtent current_host_permissions;
- bool current_full_access;
-
- ASSERT_TRUE(prefs->GetGrantedPermissions(extension_id,
- &current_full_access,
- &current_api_permissions,
- &current_host_permissions));
-
- ASSERT_FALSE(current_full_access);
- ASSERT_EQ(expected_api_permissions, current_api_permissions);
- AssertEqualExtents(&expected_host_permissions, &current_host_permissions);
-
- // Tests that the extension is disabled when a host permission is missing from
- // the extension's granted host permissions preference. (This simulates
- // updating the browser to a version which recognizes additional host
- // permissions).
- api_permissions.clear();
- host_permissions.clear();
- current_api_permissions.clear();
- current_host_permissions.ClearPaths();
-
- api_permissions.insert("tabs");
- host_permissions.insert("http://*.google.com/*");
- host_permissions.insert("https://*.google.com/*");
- host_permissions.insert("http://*.google.com.hk/*");
-
- SetPrefStringSet(extension_id, "granted_permissions.api", api_permissions);
- SetPrefStringSet(extension_id, "granted_permissions.host", host_permissions);
-
- service_->ReloadExtensions();
-
- EXPECT_EQ(1u, service_->disabled_extensions()->size());
- extension = service_->disabled_extensions()->at(0);
-
- ASSERT_TRUE(prefs->GetExtensionState(extension_id) == Extension::DISABLED);
- ASSERT_TRUE(prefs->DidExtensionEscalatePermissions(extension_id));
-
- // Now grant and re-enable the extension, making sure the prefs are updated.
- service_->GrantPermissionsAndEnableExtension(extension);
-
- ASSERT_TRUE(prefs->GetExtensionState(extension_id) == Extension::ENABLED);
- ASSERT_FALSE(prefs->DidExtensionEscalatePermissions(extension_id));
-
- ASSERT_TRUE(prefs->GetGrantedPermissions(extension_id,
- &current_full_access,
- &current_api_permissions,
- &current_host_permissions));
-
- ASSERT_FALSE(current_full_access);
- ASSERT_EQ(expected_api_permissions, current_api_permissions);
- AssertEqualExtents(&expected_host_permissions, &current_host_permissions);
-
- // Tests that the granted permissions preferences are initialized when
- // migrating from the old pref schema.
- current_api_permissions.clear();
- current_host_permissions.ClearPaths();
-
- ClearPref(extension_id, "granted_permissions");
-
- service_->ReloadExtensions();
-
- EXPECT_EQ(1u, service_->extensions()->size());
- extension = service_->extensions()->at(0);
-
- ASSERT_TRUE(prefs->GetExtensionState(extension_id) == Extension::ENABLED);
- ASSERT_FALSE(prefs->DidExtensionEscalatePermissions(extension_id));
-
- ASSERT_TRUE(prefs->GetGrantedPermissions(extension_id,
- &current_full_access,
- &current_api_permissions,
- &current_host_permissions));
-
- ASSERT_FALSE(current_full_access);
- ASSERT_EQ(expected_api_permissions, current_api_permissions);
- AssertEqualExtents(&expected_host_permissions, &current_host_permissions);
-}
-
-// Test Packaging and installing an extension.
-TEST_F(ExtensionsServiceTest, PackExtension) {
- InitializeEmptyExtensionsService();
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
- FilePath input_directory = extensions_path
- .AppendASCII("good")
- .AppendASCII("Extensions")
- .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
- .AppendASCII("1.0.0.0");
-
- ScopedTempDir temp_dir;
- ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
- FilePath output_directory = temp_dir.path();
-
- FilePath crx_path(output_directory.AppendASCII("ex1.crx"));
- FilePath privkey_path(output_directory.AppendASCII("privkey.pem"));
-
- scoped_ptr<ExtensionCreator> creator(new ExtensionCreator());
- ASSERT_TRUE(creator->Run(input_directory, crx_path, FilePath(),
- privkey_path));
-
- ASSERT_TRUE(file_util::PathExists(privkey_path));
- InstallExtension(crx_path, true);
-
- // Try packing with invalid paths.
- creator.reset(new ExtensionCreator());
- ASSERT_FALSE(creator->Run(FilePath(), FilePath(), FilePath(), FilePath()));
-
- // Try packing an empty directory. Should fail because an empty directory is
- // not a valid extension.
- ScopedTempDir temp_dir2;
- ASSERT_TRUE(temp_dir2.CreateUniqueTempDir());
- creator.reset(new ExtensionCreator());
- ASSERT_FALSE(creator->Run(temp_dir2.path(), crx_path, privkey_path,
- FilePath()));
-
- // Try packing with an invalid manifest.
- std::string invalid_manifest_content = "I am not a manifest.";
- ASSERT_TRUE(file_util::WriteFile(
- temp_dir2.path().Append(Extension::kManifestFilename),
- invalid_manifest_content.c_str(), invalid_manifest_content.size()));
- creator.reset(new ExtensionCreator());
- ASSERT_FALSE(creator->Run(temp_dir2.path(), crx_path, privkey_path,
- FilePath()));
-}
-
-// Test Packaging and installing an extension whose name contains punctuation.
-TEST_F(ExtensionsServiceTest, PackPunctuatedExtension) {
- InitializeEmptyExtensionsService();
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
- FilePath input_directory = extensions_path
- .AppendASCII("good")
- .AppendASCII("Extensions")
- .AppendASCII(good0)
- .AppendASCII("1.0.0.0");
-
- ScopedTempDir temp_dir;
- ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
-
- // Extension names containing punctuation, and the expected names for the
- // packed extensions.
- const FilePath punctuated_names[] = {
- FilePath(FilePath::StringType(
- FILE_PATH_LITERAL("this.extensions.name.has.periods"))),
- FilePath(FilePath::StringType(
- FILE_PATH_LITERAL(".thisextensionsnamestartswithaperiod"))),
- NormalizeSeparators(FilePath(FilePath::StringType(
- FILE_PATH_LITERAL("thisextensionhasaslashinitsname/")))),
- };
- const FilePath expected_crx_names[] = {
- FilePath(FilePath::StringType(
- FILE_PATH_LITERAL("this.extensions.name.has.periods.crx"))),
- FilePath(FilePath::StringType(
- FILE_PATH_LITERAL(".thisextensionsnamestartswithaperiod.crx"))),
- FilePath(FilePath::StringType(
- FILE_PATH_LITERAL("thisextensionhasaslashinitsname.crx"))),
- };
- const FilePath expected_private_key_names[] = {
- FilePath(FilePath::StringType(
- FILE_PATH_LITERAL("this.extensions.name.has.periods.pem"))),
- FilePath(FilePath::StringType(
- FILE_PATH_LITERAL(".thisextensionsnamestartswithaperiod.pem"))),
- FilePath(FilePath::StringType(
- FILE_PATH_LITERAL("thisextensionhasaslashinitsname.pem"))),
- };
-
- for (size_t i = 0; i < arraysize(punctuated_names); ++i) {
- SCOPED_TRACE(punctuated_names[i].value().c_str());
- FilePath output_dir = temp_dir.path().Append(punctuated_names[i]);
-
- // Copy the extension into the output directory, as PackExtensionJob doesn't
- // let us choose where to output the packed extension.
- ASSERT_TRUE(file_util::CopyDirectory(input_directory, output_dir, true));
-
- FilePath expected_crx_path = temp_dir.path().Append(expected_crx_names[i]);
- FilePath expected_private_key_path =
- temp_dir.path().Append(expected_private_key_names[i]);
- PackExtensionTestClient pack_client(expected_crx_path,
- expected_private_key_path);
- scoped_refptr<PackExtensionJob> packer(new PackExtensionJob(&pack_client,
- output_dir,
- FilePath()));
- packer->Start();
-
- // The packer will post a notification task to the current thread's message
- // loop when it is finished. We manually run the loop here so that we
- // block and catch the notification; otherwise, the process would exit.
- // This call to |Run()| is matched by a call to |Quit()| in the
- // |PackExtensionTestClient|'s notification handling code.
- MessageLoop::current()->Run();
-
- if (HasFatalFailure())
- return;
-
- InstallExtension(expected_crx_path, true);
- }
-}
-
-// Test Packaging and installing an extension using an openssl generated key.
-// The openssl is generated with the following:
-// > openssl genrsa -out privkey.pem 1024
-// > openssl pkcs8 -topk8 -nocrypt -in privkey.pem -out privkey_asn1.pem
-// The privkey.pem is a PrivateKey, and the pcks8 -topk8 creates a
-// PrivateKeyInfo ASN.1 structure, we our RSAPrivateKey expects.
-TEST_F(ExtensionsServiceTest, PackExtensionOpenSSLKey) {
- InitializeEmptyExtensionsService();
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
- FilePath input_directory = extensions_path
- .AppendASCII("good")
- .AppendASCII("Extensions")
- .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
- .AppendASCII("1.0.0.0");
- FilePath privkey_path(extensions_path.AppendASCII(
- "openssl_privkey_asn1.pem"));
- ASSERT_TRUE(file_util::PathExists(privkey_path));
-
- ScopedTempDir temp_dir;
- ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
- FilePath output_directory = temp_dir.path();
-
- FilePath crx_path(output_directory.AppendASCII("ex1.crx"));
-
- scoped_ptr<ExtensionCreator> creator(new ExtensionCreator());
- ASSERT_TRUE(creator->Run(input_directory, crx_path, privkey_path,
- FilePath()));
-
- InstallExtension(crx_path, true);
-}
-
-TEST_F(ExtensionsServiceTest, InstallTheme) {
- InitializeEmptyExtensionsService();
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
-
- // A theme.
- FilePath path = extensions_path.AppendASCII("theme.crx");
- InstallExtension(path, true);
- int pref_count = 0;
- ValidatePrefKeyCount(++pref_count);
- ValidateIntegerPref(theme_crx, "state", Extension::ENABLED);
- ValidateIntegerPref(theme_crx, "location", Extension::INTERNAL);
-
- // A theme when extensions are disabled. Themes can be installed, even when
- // extensions are disabled.
- set_extensions_enabled(false);
- path = extensions_path.AppendASCII("theme2.crx");
- InstallExtension(path, true);
- ValidatePrefKeyCount(++pref_count);
- ValidateIntegerPref(theme2_crx, "state", Extension::ENABLED);
- ValidateIntegerPref(theme2_crx, "location", Extension::INTERNAL);
-
- // A theme with extension elements. Themes cannot have extension elements so
- // this test should fail.
- set_extensions_enabled(true);
- path = extensions_path.AppendASCII("theme_with_extension.crx");
- InstallExtension(path, false);
- ValidatePrefKeyCount(pref_count);
-
- // A theme with image resources missing (misspelt path).
- path = extensions_path.AppendASCII("theme_missing_image.crx");
- InstallExtension(path, false);
- ValidatePrefKeyCount(pref_count);
-}
-
-TEST_F(ExtensionsServiceTest, LoadLocalizedTheme) {
- // Load.
- InitializeEmptyExtensionsService();
- FilePath extension_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extension_path));
- extension_path = extension_path
- .AppendASCII("extensions")
- .AppendASCII("theme_i18n");
-
- service_->LoadExtension(extension_path);
- loop_.RunAllPending();
- EXPECT_EQ(0u, GetErrors().size());
- ASSERT_EQ(1u, loaded_.size());
- EXPECT_EQ(1u, service_->extensions()->size());
- EXPECT_EQ("name", service_->extensions()->at(0)->name());
- EXPECT_EQ("description", service_->extensions()->at(0)->description());
-}
-
-TEST_F(ExtensionsServiceTest, InstallLocalizedTheme) {
- InitializeEmptyExtensionsService();
- FilePath theme_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &theme_path));
- theme_path = theme_path
- .AppendASCII("extensions")
- .AppendASCII("theme_i18n");
-
- PackAndInstallExtension(theme_path, true);
-
- EXPECT_EQ(0u, GetErrors().size());
- EXPECT_EQ(1u, service_->extensions()->size());
- EXPECT_EQ("name", service_->extensions()->at(0)->name());
- EXPECT_EQ("description", service_->extensions()->at(0)->description());
-}
-
-TEST_F(ExtensionsServiceTest, InstallApps) {
- InitializeEmptyExtensionsService();
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
-
- // An empty app.
- PackAndInstallExtension(extensions_path.AppendASCII("app1"), true);
- int pref_count = 0;
- ValidatePrefKeyCount(++pref_count);
- ASSERT_EQ(1u, service_->extensions()->size());
- std::string id = service_->extensions()->at(0)->id();
- ValidateIntegerPref(id, "state", Extension::ENABLED);
- ValidateIntegerPref(id, "location", Extension::INTERNAL);
-
- // Another app with non-overlapping extent. Should succeed.
- PackAndInstallExtension(extensions_path.AppendASCII("app2"), true);
- ValidatePrefKeyCount(++pref_count);
-
- // A third app whose extent overlaps the first. Should fail.
- PackAndInstallExtension(extensions_path.AppendASCII("app3"), false);
- ValidatePrefKeyCount(pref_count);
-}
-
-TEST_F(ExtensionsServiceTest, InstallAppsWithUnlimtedStorage) {
- InitializeEmptyExtensionsService();
- EXPECT_TRUE(service_->extensions()->empty());
- EXPECT_TRUE(service_->unlimited_storage_map_.empty());
-
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
- int pref_count = 0;
- ChromeAppCacheService* appcache_service = profile_->GetAppCacheService();
-
- // Install app1 with unlimited storage.
- PackAndInstallExtension(extensions_path.AppendASCII("app1"), true);
- ValidatePrefKeyCount(++pref_count);
- ASSERT_EQ(1u, service_->extensions()->size());
- const Extension* extension = service_->extensions()->at(0);
- const std::string id1 = extension->id();
- EXPECT_TRUE(extension->HasApiPermission(
- Extension::kUnlimitedStoragePermission));
- EXPECT_TRUE(extension->web_extent().ContainsURL(
- extension->GetFullLaunchURL()));
- const GURL origin1(extension->GetFullLaunchURL().GetOrigin());
- EXPECT_EQ(kint64max,
- appcache_service->storage()->GetOriginQuotaInMemory(origin1));
- EXPECT_FALSE(service_->unlimited_storage_map_.empty());
-
- // Install app2 from the same origin with unlimited storage.
- PackAndInstallExtension(extensions_path.AppendASCII("app2"), true);
- ValidatePrefKeyCount(++pref_count);
- ASSERT_EQ(2u, service_->extensions()->size());
- extension = service_->extensions()->at(1);
- const std::string id2 = extension->id();
- EXPECT_TRUE(extension->HasApiPermission(
- Extension::kUnlimitedStoragePermission));
- EXPECT_TRUE(extension->web_extent().ContainsURL(
- extension->GetFullLaunchURL()));
- const GURL origin2(extension->GetFullLaunchURL().GetOrigin());
- EXPECT_EQ(origin1, origin2);
- EXPECT_EQ(kint64max,
- appcache_service->storage()->GetOriginQuotaInMemory(origin2));
- EXPECT_FALSE(service_->unlimited_storage_map_.empty());
-
- // Uninstall one of them, unlimited storage should still be granted
- // to the origin.
- service_->UninstallExtension(id1, false);
- loop_.RunAllPending();
- EXPECT_EQ(1u, service_->extensions()->size());
- EXPECT_EQ(kint64max,
- appcache_service->storage()->GetOriginQuotaInMemory(origin1));
- EXPECT_FALSE(service_->unlimited_storage_map_.empty());
-
- // Uninstall the other, unlimited storage should be revoked.
- service_->UninstallExtension(id2, false);
- loop_.RunAllPending();
- EXPECT_EQ(0u, service_->extensions()->size());
- EXPECT_EQ(-1L,
- appcache_service->storage()->GetOriginQuotaInMemory(origin2));
- EXPECT_TRUE(service_->unlimited_storage_map_.empty());
-}
-
-TEST_F(ExtensionsServiceTest, InstallAppsAndCheckStorageProtection) {
- InitializeEmptyExtensionsService();
- EXPECT_TRUE(service_->extensions()->empty());
- EXPECT_TRUE(service_->protected_storage_map_.empty());
-
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
- int pref_count = 0;
-
- PackAndInstallExtension(extensions_path.AppendASCII("app1"), true);
- ValidatePrefKeyCount(++pref_count);
- ASSERT_EQ(1u, service_->extensions()->size());
- const Extension* extension = service_->extensions()->at(0);
- EXPECT_TRUE(extension->is_app());
- const std::string id1 = extension->id();
- EXPECT_FALSE(service_->protected_storage_map_.empty());
- const GURL origin1(extension->GetFullLaunchURL().GetOrigin());
- ASSERT_EQ(1, service_->protected_storage_map_[origin1]);
-
- // App 4 has a different origin (maps.google.com).
- PackAndInstallExtension(extensions_path.AppendASCII("app4"), true);
- ValidatePrefKeyCount(++pref_count);
- ASSERT_EQ(2u, service_->extensions()->size());
- extension = service_->extensions()->at(1);
- const std::string id2 = extension->id();
- EXPECT_FALSE(service_->protected_storage_map_.empty());
- const GURL origin2(extension->GetFullLaunchURL().GetOrigin());
- ASSERT_NE(origin1, origin2);
- ASSERT_EQ(1, service_->protected_storage_map_[origin2]);
-
- service_->UninstallExtension(id1, false);
- loop_.RunAllPending();
- EXPECT_EQ(1u, service_->extensions()->size());
- EXPECT_FALSE(service_->protected_storage_map_.empty());
-
- service_->UninstallExtension(id2, false);
- loop_.RunAllPending();
-
- EXPECT_TRUE(service_->extensions()->empty());
- EXPECT_TRUE(service_->protected_storage_map_.empty());
-}
-
-// Test that when an extension version is reinstalled, nothing happens.
-TEST_F(ExtensionsServiceTest, Reinstall) {
- InitializeEmptyExtensionsService();
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
-
- // A simple extension that should install without error.
- FilePath path = extensions_path.AppendASCII("good.crx");
- service_->InstallExtension(path);
- loop_.RunAllPending();
-
- ASSERT_TRUE(installed_);
- ASSERT_EQ(1u, loaded_.size());
- ASSERT_EQ(0u, GetErrors().size());
- ValidatePrefKeyCount(1);
- ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
- ValidateIntegerPref(good_crx, "location", Extension::INTERNAL);
-
- installed_ = NULL;
- loaded_.clear();
- ExtensionErrorReporter::GetInstance()->ClearErrors();
-
- // Reinstall the same version, it should overwrite the previous one.
- service_->InstallExtension(path);
- loop_.RunAllPending();
-
- ASSERT_TRUE(installed_);
- ASSERT_EQ(1u, loaded_.size());
- ASSERT_EQ(0u, GetErrors().size());
- ValidatePrefKeyCount(1);
- ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
- ValidateIntegerPref(good_crx, "location", Extension::INTERNAL);
-}
-
-// Test upgrading a signed extension.
-TEST_F(ExtensionsServiceTest, UpgradeSignedGood) {
- InitializeEmptyExtensionsService();
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
-
- FilePath path = extensions_path.AppendASCII("good.crx");
- service_->InstallExtension(path);
- loop_.RunAllPending();
-
- ASSERT_TRUE(installed_);
- ASSERT_EQ(1u, loaded_.size());
- ASSERT_EQ("1.0.0.0", loaded_[0]->version()->GetString());
- ASSERT_EQ(0u, GetErrors().size());
-
- // Upgrade to version 2.0
- path = extensions_path.AppendASCII("good2.crx");
- service_->InstallExtension(path);
- loop_.RunAllPending();
-
- ASSERT_TRUE(installed_);
- ASSERT_EQ(1u, loaded_.size());
- ASSERT_EQ("1.0.0.1", loaded_[0]->version()->GetString());
- ASSERT_EQ(0u, GetErrors().size());
-}
-
-// Test upgrading a signed extension with a bad signature.
-TEST_F(ExtensionsServiceTest, UpgradeSignedBad) {
- InitializeEmptyExtensionsService();
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
-
- FilePath path = extensions_path.AppendASCII("good.crx");
- service_->InstallExtension(path);
- loop_.RunAllPending();
-
- ASSERT_TRUE(installed_);
- ASSERT_EQ(1u, loaded_.size());
- ASSERT_EQ(0u, GetErrors().size());
- installed_ = NULL;
-
- // Try upgrading with a bad signature. This should fail during the unpack,
- // because the key will not match the signature.
- path = extensions_path.AppendASCII("good2_bad_signature.crx");
- service_->InstallExtension(path);
- loop_.RunAllPending();
-
- ASSERT_FALSE(installed_);
- ASSERT_EQ(1u, loaded_.size());
- ASSERT_EQ(1u, GetErrors().size());
-}
-
-// Test a normal update via the UpdateExtension API
-TEST_F(ExtensionsServiceTest, UpdateExtension) {
- InitializeEmptyExtensionsService();
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
-
- FilePath path = extensions_path.AppendASCII("good.crx");
-
- InstallExtension(path, true);
- const Extension* good = service_->extensions()->at(0);
- ASSERT_EQ("1.0.0.0", good->VersionString());
- ASSERT_EQ(good_crx, good->id());
-
- path = extensions_path.AppendASCII("good2.crx");
- UpdateExtension(good_crx, path, ENABLED);
- ASSERT_EQ("1.0.0.1", loaded_[0]->version()->GetString());
-}
-
-// Test updating a not-already-installed extension - this should fail
-TEST_F(ExtensionsServiceTest, UpdateNotInstalledExtension) {
- InitializeEmptyExtensionsService();
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
-
- FilePath path = extensions_path.AppendASCII("good.crx");
- UpdateExtension(good_crx, path, UPDATED);
- loop_.RunAllPending();
-
- ASSERT_EQ(0u, service_->extensions()->size());
- ASSERT_FALSE(installed_);
- ASSERT_EQ(0u, loaded_.size());
-}
-
-// Makes sure you can't downgrade an extension via UpdateExtension
-TEST_F(ExtensionsServiceTest, UpdateWillNotDowngrade) {
- InitializeEmptyExtensionsService();
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
-
- FilePath path = extensions_path.AppendASCII("good2.crx");
-
- InstallExtension(path, true);
- const Extension* good = service_->extensions()->at(0);
- ASSERT_EQ("1.0.0.1", good->VersionString());
- ASSERT_EQ(good_crx, good->id());
-
- // Change path from good2.crx -> good.crx
- path = extensions_path.AppendASCII("good.crx");
- UpdateExtension(good_crx, path, FAILED);
- ASSERT_EQ("1.0.0.1", service_->extensions()->at(0)->VersionString());
-}
-
-// Make sure calling update with an identical version does nothing
-TEST_F(ExtensionsServiceTest, UpdateToSameVersionIsNoop) {
- InitializeEmptyExtensionsService();
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
-
- FilePath path = extensions_path.AppendASCII("good.crx");
-
- InstallExtension(path, true);
- const Extension* good = service_->extensions()->at(0);
- ASSERT_EQ(good_crx, good->id());
- UpdateExtension(good_crx, path, FAILED_SILENTLY);
-}
-
-// Tests that updating an extension does not clobber old state.
-TEST_F(ExtensionsServiceTest, UpdateExtensionPreservesState) {
- InitializeEmptyExtensionsService();
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
-
- FilePath path = extensions_path.AppendASCII("good.crx");
-
- InstallExtension(path, true);
- const Extension* good = service_->extensions()->at(0);
- ASSERT_EQ("1.0.0.0", good->VersionString());
- ASSERT_EQ(good_crx, good->id());
-
- // Disable it and allow it to run in incognito. These settings should carry
- // over to the updated version.
- service_->DisableExtension(good->id());
- service_->SetIsIncognitoEnabled(good, true);
-
- path = extensions_path.AppendASCII("good2.crx");
- UpdateExtension(good_crx, path, INSTALLED);
- ASSERT_EQ(1u, service_->disabled_extensions()->size());
- const Extension* good2 = service_->disabled_extensions()->at(0);
- ASSERT_EQ("1.0.0.1", good2->version()->GetString());
- EXPECT_TRUE(service_->IsIncognitoEnabled(good2));
-}
-
-// Tests that updating preserves extension location.
-TEST_F(ExtensionsServiceTest, UpdateExtensionPreservesLocation) {
- InitializeEmptyExtensionsService();
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
-
- FilePath path = extensions_path.AppendASCII("good.crx");
-
- InstallExtension(path, true);
- const Extension* good = service_->extensions()->at(0);
-
- ASSERT_EQ("1.0.0.0", good->VersionString());
- ASSERT_EQ(good_crx, good->id());
-
- // Simulate non-internal location.
- const_cast<Extension*>(good)->location_ = Extension::EXTERNAL_PREF;
-
- path = extensions_path.AppendASCII("good2.crx");
- UpdateExtension(good_crx, path, ENABLED);
- const Extension* good2 = service_->extensions()->at(0);
- ASSERT_EQ("1.0.0.1", good2->version()->GetString());
- EXPECT_EQ(good2->location(), Extension::EXTERNAL_PREF);
-}
-
-// Test adding a pending extension.
-TEST_F(ExtensionsServiceTest, AddPendingExtension) {
- InitializeEmptyExtensionsService();
-
- const std::string kFakeId("fake-id");
- const GURL kFakeUpdateURL("http:://fake.update/url");
- const PendingExtensionInfo::ExpectedCrxType kFakeExpectedCrxType =
- PendingExtensionInfo::EXTENSION;
- const bool kFakeInstallSilently(true);
- const Extension::State kFakeInitialState(Extension::ENABLED);
- const bool kFakeInitialIncognitoEnabled(false);
-
- service_->AddPendingExtensionFromSync(
- kFakeId, kFakeUpdateURL, kFakeExpectedCrxType, kFakeInstallSilently,
- kFakeInitialState, kFakeInitialIncognitoEnabled);
- PendingExtensionMap::const_iterator it =
- service_->pending_extensions().find(kFakeId);
- ASSERT_TRUE(it != service_->pending_extensions().end());
- EXPECT_EQ(kFakeUpdateURL, it->second.update_url);
- EXPECT_EQ(kFakeExpectedCrxType, it->second.expected_crx_type);
- EXPECT_EQ(kFakeInstallSilently, it->second.install_silently);
-}
-
-namespace {
-const char kGoodId[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
-const char kGoodUpdateURL[] = "http://good.update/url";
-const PendingExtensionInfo::ExpectedCrxType kCrxTypeTheme =
- PendingExtensionInfo::THEME;
-const PendingExtensionInfo::ExpectedCrxType kCrxTypeExtension =
- PendingExtensionInfo::EXTENSION;
-const bool kGoodIsFromSync = true;
-const bool kGoodInstallSilently = true;
-const Extension::State kGoodInitialState = Extension::DISABLED;
-const bool kGoodInitialIncognitoEnabled = true;
-} // namespace
-
-// Test updating a pending extension.
-TEST_F(ExtensionsServiceTest, UpdatePendingExtension) {
- InitializeEmptyExtensionsService();
- service_->AddPendingExtensionFromSync(
- kGoodId, GURL(kGoodUpdateURL), kCrxTypeExtension,
- kGoodInstallSilently, kGoodInitialState,
- kGoodInitialIncognitoEnabled);
- EXPECT_TRUE(ContainsKey(service_->pending_extensions(), kGoodId));
-
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
- FilePath path = extensions_path.AppendASCII("good.crx");
- UpdateExtension(kGoodId, path, INSTALLED);
-
- EXPECT_FALSE(ContainsKey(service_->pending_extensions(), kGoodId));
-
- const Extension* extension = service_->GetExtensionById(kGoodId, true);
- ASSERT_TRUE(extension);
-
- bool enabled = service_->GetExtensionById(kGoodId, false);
- EXPECT_EQ(kGoodInitialState == Extension::ENABLED, enabled);
- EXPECT_EQ(kGoodInitialState,
- service_->extension_prefs()->GetExtensionState(extension->id()));
- EXPECT_EQ(kGoodInitialIncognitoEnabled,
- service_->IsIncognitoEnabled(extension));
-}
-
-// Test updating a pending theme.
-TEST_F(ExtensionsServiceTest, UpdatePendingTheme) {
- InitializeEmptyExtensionsService();
- service_->AddPendingExtensionFromSync(
- theme_crx, GURL(), PendingExtensionInfo::THEME,
- false, Extension::ENABLED, false);
- EXPECT_TRUE(ContainsKey(service_->pending_extensions(), theme_crx));
-
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
- FilePath path = extensions_path.AppendASCII("theme.crx");
- UpdateExtension(theme_crx, path, ENABLED);
-
- EXPECT_FALSE(ContainsKey(service_->pending_extensions(), theme_crx));
-
- const Extension* extension = service_->GetExtensionById(theme_crx, true);
- ASSERT_TRUE(extension);
-
- EXPECT_EQ(Extension::ENABLED,
- service_->extension_prefs()->GetExtensionState(extension->id()));
- EXPECT_FALSE(service_->IsIncognitoEnabled(extension));
-}
-
-// Test updating a pending CRX as if the source is an external extension
-// with an update URL. In this case we don't know if the CRX is a theme
-// or not.
-TEST_F(ExtensionsServiceTest, UpdatePendingExternalCrx) {
- InitializeEmptyExtensionsService();
- service_->AddPendingExtensionFromExternalUpdateUrl(
- theme_crx, GURL(), Extension::EXTERNAL_PREF_DOWNLOAD);
-
- EXPECT_TRUE(ContainsKey(service_->pending_extensions(), theme_crx));
-
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
- FilePath path = extensions_path.AppendASCII("theme.crx");
- UpdateExtension(theme_crx, path, ENABLED);
-
- EXPECT_FALSE(ContainsKey(service_->pending_extensions(), theme_crx));
-
- const Extension* extension = service_->GetExtensionById(theme_crx, true);
- ASSERT_TRUE(extension);
-
- EXPECT_EQ(Extension::ENABLED,
- service_->extension_prefs()->GetExtensionState(extension->id()));
- EXPECT_FALSE(service_->IsIncognitoEnabled(extension));
-}
-
-// Test updating a pending CRX as if the source is an external extension
-// with an update URL. The external update should overwrite a sync update,
-// but a sync update should not overwrite a non-sync update.
-TEST_F(ExtensionsServiceTest, UpdatePendingExternalCrxWinsOverSync) {
- InitializeEmptyExtensionsService();
-
- // Add a crx to be installed from the update mechanism.
- service_->AddPendingExtensionFromSync(
- kGoodId, GURL(kGoodUpdateURL), kCrxTypeExtension,
- kGoodInstallSilently, kGoodInitialState,
- kGoodInitialIncognitoEnabled);
-
- // Check that there is a pending crx, with is_from_sync set to true.
- PendingExtensionMap::const_iterator it;
- it = service_->pending_extensions().find(kGoodId);
- ASSERT_TRUE(it != service_->pending_extensions().end());
- EXPECT_TRUE(it->second.is_from_sync);
-
- // Add a crx to be updated, with the same ID, from a non-sync source.
- service_->AddPendingExtensionFromExternalUpdateUrl(
- kGoodId, GURL(kGoodUpdateURL), Extension::EXTERNAL_PREF_DOWNLOAD);
-
- // Check that there is a pending crx, with is_from_sync set to false.
- it = service_->pending_extensions().find(kGoodId);
- ASSERT_TRUE(it != service_->pending_extensions().end());
- EXPECT_FALSE(it->second.is_from_sync);
-
- // Add a crx to be installed from the update mechanism.
- service_->AddPendingExtensionFromSync(
- kGoodId, GURL(kGoodUpdateURL), kCrxTypeExtension,
- kGoodInstallSilently, kGoodInitialState,
- kGoodInitialIncognitoEnabled);
-
- // Check that the external, non-sync update was not overridden.
- it = service_->pending_extensions().find(kGoodId);
- ASSERT_TRUE(it != service_->pending_extensions().end());
- EXPECT_FALSE(it->second.is_from_sync);
-}
-
-// Updating a theme should fail if the updater is explicitly told that
-// the CRX is not a theme.
-TEST_F(ExtensionsServiceTest, UpdatePendingCrxThemeMismatch) {
- InitializeEmptyExtensionsService();
- service_->AddPendingExtensionFromSync(
- theme_crx, GURL(),
- PendingExtensionInfo::EXTENSION,
- true, Extension::ENABLED, false);
-
- EXPECT_TRUE(ContainsKey(service_->pending_extensions(), theme_crx));
-
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
- FilePath path = extensions_path.AppendASCII("theme.crx");
- UpdateExtension(theme_crx, path, FAILED_SILENTLY);
-
- EXPECT_FALSE(ContainsKey(service_->pending_extensions(), theme_crx));
-
- const Extension* extension = service_->GetExtensionById(theme_crx, true);
- ASSERT_FALSE(extension);
-}
-
-// TODO(akalin): Test updating a pending extension non-silently once
-// we can mock out ExtensionInstallUI and inject our version into
-// UpdateExtension().
-
-// Test updating a pending extension with wrong is_theme.
-TEST_F(ExtensionsServiceTest, UpdatePendingExtensionWrongIsTheme) {
- InitializeEmptyExtensionsService();
- // Add pending extension with a flipped is_theme.
- service_->AddPendingExtensionFromSync(
- kGoodId, GURL(kGoodUpdateURL),
- kCrxTypeTheme, kGoodInstallSilently, kGoodInitialState,
- kGoodInitialIncognitoEnabled);
- EXPECT_TRUE(ContainsKey(service_->pending_extensions(), kGoodId));
-
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
- FilePath path = extensions_path.AppendASCII("good.crx");
- UpdateExtension(kGoodId, path, UPDATED);
-
- // TODO(akalin): Figure out how to check that the extensions
- // directory is cleaned up properly in OnExtensionInstalled().
-
- EXPECT_FALSE(ContainsKey(service_->pending_extensions(), kGoodId));
-}
-
-// TODO(akalin): Figure out how to test that installs of pending
-// unsyncable extensions are blocked.
-
-// Test updating a pending extension for one that is not pending.
-TEST_F(ExtensionsServiceTest, UpdatePendingExtensionNotPending) {
- InitializeEmptyExtensionsService();
-
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
- FilePath path = extensions_path.AppendASCII("good.crx");
- UpdateExtension(kGoodId, path, UPDATED);
-
- EXPECT_FALSE(ContainsKey(service_->pending_extensions(), kGoodId));
-}
-
-// Test updating a pending extension for one that is already
-// installed.
-TEST_F(ExtensionsServiceTest, UpdatePendingExtensionAlreadyInstalled) {
- InitializeEmptyExtensionsService();
-
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
- FilePath path = extensions_path.AppendASCII("good.crx");
- InstallExtension(path, true);
- ASSERT_EQ(1u, service_->extensions()->size());
- const Extension* good = service_->extensions()->at(0);
-
- EXPECT_FALSE(good->is_theme());
-
- // Use AddPendingExtensionInternal() as AddPendingExtension() would
- // balk.
- service_->AddPendingExtensionInternal(
- good->id(), good->update_url(),
- PendingExtensionInfo::EXTENSION,
- kGoodIsFromSync, kGoodInstallSilently, kGoodInitialState,
- kGoodInitialIncognitoEnabled, Extension::INTERNAL);
- UpdateExtension(good->id(), path, INSTALLED);
-
- EXPECT_FALSE(ContainsKey(service_->pending_extensions(), kGoodId));
-}
-
-// Test pref settings for blacklist and unblacklist extensions.
-TEST_F(ExtensionsServiceTest, SetUnsetBlacklistInPrefs) {
- InitializeEmptyExtensionsService();
- std::vector<std::string> blacklist;
- blacklist.push_back(good0);
- blacklist.push_back("invalid_id"); // an invalid id
- blacklist.push_back(good1);
- service_->UpdateExtensionBlacklist(blacklist);
- // Make sure pref is updated
- loop_.RunAllPending();
-
- // blacklist is set for good0,1,2
- ValidateBooleanPref(good0, "blacklist", true);
- ValidateBooleanPref(good1, "blacklist", true);
- // invalid_id should not be inserted to pref.
- EXPECT_FALSE(IsPrefExist("invalid_id", "blacklist"));
-
- // remove good1, add good2
- blacklist.pop_back();
- blacklist.push_back(good2);
-
- service_->UpdateExtensionBlacklist(blacklist);
- // only good0 and good1 should be set
- ValidateBooleanPref(good0, "blacklist", true);
- EXPECT_FALSE(IsPrefExist(good1, "blacklist"));
- ValidateBooleanPref(good2, "blacklist", true);
- EXPECT_FALSE(IsPrefExist("invalid_id", "blacklist"));
-}
-
-// Unload installed extension from blacklist.
-TEST_F(ExtensionsServiceTest, UnloadBlacklistedExtension) {
- InitializeEmptyExtensionsService();
- FilePath extensions_path;
- EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
-
- FilePath path = extensions_path.AppendASCII("good.crx");
-
- InstallExtension(path, true);
- const Extension* good = service_->extensions()->at(0);
- EXPECT_EQ(good_crx, good->id());
- UpdateExtension(good_crx, path, FAILED_SILENTLY);
-
- std::vector<std::string> blacklist;
- blacklist.push_back(good_crx);
- service_->UpdateExtensionBlacklist(blacklist);
- // Make sure pref is updated
- loop_.RunAllPending();
-
- // Now, the good_crx is blacklisted.
- ValidateBooleanPref(good_crx, "blacklist", true);
- EXPECT_EQ(0u, service_->extensions()->size());
-
- // Remove good_crx from blacklist
- blacklist.pop_back();
- service_->UpdateExtensionBlacklist(blacklist);
- // Make sure pref is updated
- loop_.RunAllPending();
- // blacklist value should not be set for good_crx
- EXPECT_FALSE(IsPrefExist(good_crx, "blacklist"));
-}
-
-// Unload installed extension from blacklist.
-TEST_F(ExtensionsServiceTest, BlacklistedExtensionWillNotInstall) {
- InitializeEmptyExtensionsService();
- std::vector<std::string> blacklist;
- blacklist.push_back(good_crx);
- service_->UpdateExtensionBlacklist(blacklist);
- // Make sure pref is updated
- loop_.RunAllPending();
-
- // Now, the good_crx is blacklisted.
- ValidateBooleanPref(good_crx, "blacklist", true);
-
- // We can not install good_crx.
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
- FilePath path = extensions_path.AppendASCII("good.crx");
- service_->InstallExtension(path);
- loop_.RunAllPending();
- EXPECT_EQ(0u, service_->extensions()->size());
- ValidateBooleanPref(good_crx, "blacklist", true);
-}
-
-// Test loading extensions from the profile directory, except
-// blacklisted ones.
-TEST_F(ExtensionsServiceTest, WillNotLoadBlacklistedExtensionsFromDirectory) {
- // Initialize the test dir with a good Preferences/extensions.
- FilePath source_install_dir;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir));
- source_install_dir = source_install_dir
- .AppendASCII("extensions")
- .AppendASCII("good")
- .AppendASCII("Extensions");
- FilePath pref_path = source_install_dir
- .DirName()
- .AppendASCII("Preferences");
- InitializeInstalledExtensionsService(pref_path, source_install_dir);
-
- // Blacklist good1.
- std::vector<std::string> blacklist;
- blacklist.push_back(good1);
- service_->UpdateExtensionBlacklist(blacklist);
- // Make sure pref is updated
- loop_.RunAllPending();
-
- ValidateBooleanPref(good1, "blacklist", true);
-
- // Load extensions.
- service_->Init();
- loop_.RunAllPending();
-
- std::vector<std::string> errors = GetErrors();
- for (std::vector<std::string>::iterator err = errors.begin();
- err != errors.end(); ++err) {
- LOG(ERROR) << *err;
- }
- ASSERT_EQ(2u, loaded_.size());
-
- EXPECT_NE(std::string(good1), loaded_[0]->id());
- EXPECT_NE(std::string(good1), loaded_[1]->id());
-}
-
-#if defined(OS_CHROMEOS)
-// Test loading extensions from the profile directory, except
-// ones with a plugin.
-TEST_F(ExtensionsServiceTest, WillNotLoadPluginExtensionsFromDirectory) {
- // Initialize the test dir with a good Preferences/extensions.
- FilePath source_install_dir;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir));
- source_install_dir = source_install_dir
- .AppendASCII("extensions")
- .AppendASCII("good")
- .AppendASCII("Extensions");
- FilePath pref_path = source_install_dir
- .DirName()
- .AppendASCII("Preferences");
- InitializeInstalledExtensionsService(pref_path, source_install_dir);
-
- // good1 contains a plugin.
- // Load extensions.
- service_->Init();
- loop_.RunAllPending();
-
- std::vector<std::string> errors = GetErrors();
- for (std::vector<std::string>::iterator err = errors.begin();
- err != errors.end(); ++err) {
- LOG(ERROR) << *err;
- }
- ASSERT_EQ(2u, loaded_.size());
-
- EXPECT_NE(std::string(good1), loaded_[0]->id());
- EXPECT_NE(std::string(good1), loaded_[1]->id());
-}
-#endif
-
-// Will not install extension blacklisted by policy.
-TEST_F(ExtensionsServiceTest, BlacklistedByPolicyWillNotInstall) {
- InitializeEmptyExtensionsService();
-
- ListValue* whitelist =
- profile_->GetPrefs()->GetMutableList("extensions.install.allowlist");
- ListValue* blacklist =
- profile_->GetPrefs()->GetMutableList("extensions.install.denylist");
- ASSERT_TRUE(whitelist != NULL && blacklist != NULL);
-
- // Blacklist everything.
- blacklist->Append(Value::CreateStringValue("*"));
-
- // Blacklist prevents us from installing good_crx.
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
- FilePath path = extensions_path.AppendASCII("good.crx");
- service_->InstallExtension(path);
- loop_.RunAllPending();
- EXPECT_EQ(0u, service_->extensions()->size());
-
- // Now whitelist this particular extension.
- whitelist->Append(Value::CreateStringValue(good_crx));
-
- // Ensure we can now install good_crx.
- service_->InstallExtension(path);
- loop_.RunAllPending();
- EXPECT_EQ(1u, service_->extensions()->size());
-}
-
-// Extension blacklisted by policy get unloaded after installing.
-TEST_F(ExtensionsServiceTest, BlacklistedByPolicyRemovedIfRunning) {
- InitializeEmptyExtensionsService();
-
- // Install good_crx.
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
- FilePath path = extensions_path.AppendASCII("good.crx");
- service_->InstallExtension(path);
- loop_.RunAllPending();
- EXPECT_EQ(1u, service_->extensions()->size());
-
- PrefService* prefs = profile_->GetPrefs();
- ListValue* blacklist =
- prefs->GetMutableList("extensions.install.denylist");
- ASSERT_TRUE(blacklist != NULL);
-
- // Blacklist this extension.
- blacklist->Append(Value::CreateStringValue(good_crx));
- prefs->ScheduleSavePersistentPrefs();
-
- // Programmatically appending to the prefs doesn't seem to notify the
- // observers... :/
- prefs->pref_notifier()->FireObservers("extensions.install.denylist");
-
- // Extension should not be running now.
- loop_.RunAllPending();
- EXPECT_EQ(0u, service_->extensions()->size());
-}
-
-// Tests disabling extensions
-TEST_F(ExtensionsServiceTest, DisableExtension) {
- InitializeEmptyExtensionsService();
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
-
- // A simple extension that should install without error.
- FilePath path = extensions_path.AppendASCII("good.crx");
- InstallExtension(path, true);
-
- const char* extension_id = good_crx;
- EXPECT_FALSE(service_->extensions()->empty());
- EXPECT_TRUE(service_->GetExtensionById(extension_id, true) != NULL);
- EXPECT_TRUE(service_->GetExtensionById(extension_id, false) != NULL);
- EXPECT_TRUE(service_->disabled_extensions()->empty());
-
- // Disable it.
- service_->DisableExtension(extension_id);
-
- EXPECT_TRUE(service_->extensions()->empty());
- EXPECT_TRUE(service_->GetExtensionById(extension_id, true) != NULL);
- EXPECT_FALSE(service_->GetExtensionById(extension_id, false) != NULL);
- EXPECT_FALSE(service_->disabled_extensions()->empty());
-}
-
-// Tests disabling all extensions (simulating --disable-extensions flag).
-TEST_F(ExtensionsServiceTest, DisableAllExtensions) {
- InitializeEmptyExtensionsService();
-
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
-
- FilePath path = extensions_path.AppendASCII("good.crx");
- InstallExtension(path, true);
-
- EXPECT_EQ(1u, service_->extensions()->size());
- EXPECT_EQ(0u, service_->disabled_extensions()->size());
-
- // Disable extensions.
- service_->set_extensions_enabled(false);
- service_->ReloadExtensions();
-
- // There shouldn't be extensions in either list.
- EXPECT_EQ(0u, service_->extensions()->size());
- EXPECT_EQ(0u, service_->disabled_extensions()->size());
-
- // This shouldn't do anything when all extensions are disabled.
- service_->EnableExtension(good_crx);
- service_->ReloadExtensions();
-
- // There still shouldn't be extensions in either list.
- EXPECT_EQ(0u, service_->extensions()->size());
- EXPECT_EQ(0u, service_->disabled_extensions()->size());
-
- // And then re-enable the extensions.
- service_->set_extensions_enabled(true);
- service_->ReloadExtensions();
-
- EXPECT_EQ(1u, service_->extensions()->size());
- EXPECT_EQ(0u, service_->disabled_extensions()->size());
-}
-
-// Tests reloading extensions
-TEST_F(ExtensionsServiceTest, ReloadExtensions) {
- InitializeEmptyExtensionsService();
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
-
- // Simple extension that should install without error.
- FilePath path = extensions_path.AppendASCII("good.crx");
- InstallExtension(path, true);
- const char* extension_id = good_crx;
- service_->DisableExtension(extension_id);
-
- EXPECT_EQ(0u, service_->extensions()->size());
- EXPECT_EQ(1u, service_->disabled_extensions()->size());
-
- service_->ReloadExtensions();
-
- // Extension counts shouldn't change.
- EXPECT_EQ(0u, service_->extensions()->size());
- EXPECT_EQ(1u, service_->disabled_extensions()->size());
-
- service_->EnableExtension(extension_id);
-
- EXPECT_EQ(1u, service_->extensions()->size());
- EXPECT_EQ(0u, service_->disabled_extensions()->size());
-
- // Need to clear |loaded_| manually before reloading as the
- // EnableExtension() call above inserted into it and
- // UnloadAllExtensions() doesn't send out notifications.
- loaded_.clear();
- service_->ReloadExtensions();
-
- // Extension counts shouldn't change.
- EXPECT_EQ(1u, service_->extensions()->size());
- EXPECT_EQ(0u, service_->disabled_extensions()->size());
-}
-
-// Tests uninstalling normal extensions
-TEST_F(ExtensionsServiceTest, UninstallExtension) {
- InitializeEmptyExtensionsService();
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
-
- // A simple extension that should install without error.
- FilePath path = extensions_path.AppendASCII("good.crx");
- InstallExtension(path, true);
-
- // The directory should be there now.
- const char* extension_id = good_crx;
- FilePath extension_path = extensions_install_dir_.AppendASCII(extension_id);
- EXPECT_TRUE(file_util::PathExists(extension_path));
-
- ValidatePrefKeyCount(1);
- ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
- ValidateIntegerPref(good_crx, "location", Extension::INTERNAL);
-
- // Uninstall it.
- service_->UninstallExtension(extension_id, false);
- total_successes_ = 0;
-
- // We should get an unload notification.
- ASSERT_TRUE(unloaded_id_.length());
- EXPECT_EQ(extension_id, unloaded_id_);
-
- ValidatePrefKeyCount(0);
-
- // The extension should not be in the service anymore.
- ASSERT_FALSE(service_->GetExtensionById(extension_id, false));
- loop_.RunAllPending();
-
- // The directory should be gone.
- EXPECT_FALSE(file_util::PathExists(extension_path));
-}
-
-// Tests the uninstaller helper.
-TEST_F(ExtensionsServiceTest, UninstallExtensionHelper) {
- InitializeEmptyExtensionsService();
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
-
- // A simple extension that should install without error.
- FilePath path = extensions_path.AppendASCII("good.crx");
- InstallExtension(path, true);
-
- // The directory should be there now.
- const char* extension_id = good_crx;
- FilePath extension_path = extensions_install_dir_.AppendASCII(extension_id);
- EXPECT_TRUE(file_util::PathExists(extension_path));
-
- bool result = ExtensionsService::UninstallExtensionHelper(service_,
- extension_id);
- total_successes_ = 0;
-
- EXPECT_TRUE(result);
-
- // We should get an unload notification.
- ASSERT_TRUE(unloaded_id_.length());
- EXPECT_EQ(extension_id, unloaded_id_);
-
- ValidatePrefKeyCount(0);
-
- // The extension should not be in the service anymore.
- ASSERT_FALSE(service_->GetExtensionById(extension_id, false));
- loop_.RunAllPending();
-
- // The directory should be gone.
- EXPECT_FALSE(file_util::PathExists(extension_path));
-
- // Attempt to uninstall again. This should fail as we just removed the
- // extension.
- result = ExtensionsService::UninstallExtensionHelper(service_, extension_id);
- EXPECT_FALSE(result);
-}
-
-// Verifies extension state is removed upon uninstall
-TEST_F(ExtensionsServiceTest, ClearExtensionData) {
- InitializeEmptyExtensionsService();
-
- // Load a test extension.
- FilePath path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
- path = path.AppendASCII("extensions");
- path = path.AppendASCII("good.crx");
- InstallExtension(path, true);
- const Extension* extension = service_->GetExtensionById(good_crx, false);
- ASSERT_TRUE(extension);
- GURL ext_url(extension->url());
- string16 origin_id =
- webkit_database::DatabaseUtil::GetOriginIdentifier(ext_url);
-
- // Set a cookie for the extension.
- net::CookieMonster* cookie_monster = profile_
- ->GetRequestContextForExtensions()->GetCookieStore()->GetCookieMonster();
- ASSERT_TRUE(cookie_monster);
- net::CookieOptions options;
- cookie_monster->SetCookieWithOptions(ext_url, "dummy=value", options);
- net::CookieMonster::CookieList list =
- cookie_monster->GetAllCookiesForURL(ext_url);
- EXPECT_EQ(1U, list.size());
-
- // Open a database.
- webkit_database::DatabaseTracker* db_tracker = profile_->GetDatabaseTracker();
- string16 db_name = UTF8ToUTF16("db");
- string16 description = UTF8ToUTF16("db_description");
- int64 size;
- int64 available;
- db_tracker->DatabaseOpened(origin_id, db_name, description, 1, &size,
- &available);
- db_tracker->DatabaseClosed(origin_id, db_name);
- std::vector<webkit_database::OriginInfo> origins;
- db_tracker->GetAllOriginsInfo(&origins);
- EXPECT_EQ(1U, origins.size());
- EXPECT_EQ(origin_id, origins[0].GetOrigin());
-
- // Create local storage. We only simulate this by creating the backing file
- // since webkit is not initialized.
- DOMStorageContext* context =
- profile_->GetWebKitContext()->dom_storage_context();
- FilePath lso_path = context->GetLocalStorageFilePath(origin_id);
- EXPECT_TRUE(file_util::CreateDirectory(lso_path.DirName()));
- EXPECT_EQ(0, file_util::WriteFile(lso_path, NULL, 0));
- EXPECT_TRUE(file_util::PathExists(lso_path));
-
- // Create indexed db. Again, it is enough to only simulate this by creating
- // the file on the disk.
- IndexedDBContext* idb_context =
- profile_->GetWebKitContext()->indexed_db_context();
- FilePath idb_path = idb_context->GetIndexedDBFilePath(origin_id);
- EXPECT_TRUE(file_util::CreateDirectory(idb_path.DirName()));
- EXPECT_EQ(0, file_util::WriteFile(idb_path, NULL, 0));
- EXPECT_TRUE(file_util::PathExists(idb_path));
-
- // Uninstall the extension.
- service_->UninstallExtension(good_crx, false);
- loop_.RunAllPending();
-
- // Check that the cookie is gone.
- list = cookie_monster->GetAllCookiesForURL(ext_url);
- EXPECT_EQ(0U, list.size());
-
- // The database should have vanished as well.
- origins.clear();
- db_tracker->GetAllOriginsInfo(&origins);
- EXPECT_EQ(0U, origins.size());
-
- // Check that the LSO file has been removed.
- EXPECT_FALSE(file_util::PathExists(lso_path));
-
- // Check if the indexed db has disappeared too.
- EXPECT_FALSE(file_util::PathExists(idb_path));
-}
-
-// Tests loading single extensions (like --load-extension)
-TEST_F(ExtensionsServiceTest, LoadExtension) {
- InitializeEmptyExtensionsService();
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
-
- FilePath ext1 = extensions_path
- .AppendASCII("good")
- .AppendASCII("Extensions")
- .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
- .AppendASCII("1.0.0.0");
- service_->LoadExtension(ext1);
- loop_.RunAllPending();
- EXPECT_EQ(0u, GetErrors().size());
- ASSERT_EQ(1u, loaded_.size());
- EXPECT_EQ(Extension::LOAD, loaded_[0]->location());
- EXPECT_EQ(1u, service_->extensions()->size());
-
- ValidatePrefKeyCount(1);
-
- FilePath no_manifest = extensions_path
- .AppendASCII("bad")
- // .AppendASCII("Extensions")
- .AppendASCII("cccccccccccccccccccccccccccccccc")
- .AppendASCII("1");
- service_->LoadExtension(no_manifest);
- loop_.RunAllPending();
- EXPECT_EQ(1u, GetErrors().size());
- ASSERT_EQ(1u, loaded_.size());
- EXPECT_EQ(1u, service_->extensions()->size());
-
- // Test uninstall.
- std::string id = loaded_[0]->id();
- EXPECT_FALSE(unloaded_id_.length());
- service_->UninstallExtension(id, false);
- loop_.RunAllPending();
- EXPECT_EQ(id, unloaded_id_);
- ASSERT_EQ(0u, loaded_.size());
- EXPECT_EQ(0u, service_->extensions()->size());
-}
-
-// Tests that we generate IDs when they are not specified in the manifest for
-// --load-extension.
-TEST_F(ExtensionsServiceTest, GenerateID) {
- InitializeEmptyExtensionsService();
-
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions");
-
- FilePath no_id_ext = extensions_path.AppendASCII("no_id");
- service_->LoadExtension(no_id_ext);
- loop_.RunAllPending();
- EXPECT_EQ(0u, GetErrors().size());
- ASSERT_EQ(1u, loaded_.size());
- ASSERT_TRUE(Extension::IdIsValid(loaded_[0]->id()));
- EXPECT_EQ(loaded_[0]->location(), Extension::LOAD);
-
- ValidatePrefKeyCount(1);
-
- std::string previous_id = loaded_[0]->id();
-
- // If we reload the same path, we should get the same extension ID.
- service_->LoadExtension(no_id_ext);
- loop_.RunAllPending();
- ASSERT_EQ(1u, loaded_.size());
- ASSERT_EQ(previous_id, loaded_[0]->id());
-}
-
-void ExtensionsServiceTest::TestExternalProvider(
- MockExtensionProvider* provider, Extension::Location location) {
- // Verify that starting with no providers loads no extensions.
- service_->Init();
- loop_.RunAllPending();
- ASSERT_EQ(0u, loaded_.size());
-
- provider->set_visit_count(0);
-
- // Register a test extension externally using the mock registry provider.
- FilePath source_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_path));
- source_path = source_path.AppendASCII("extensions").AppendASCII("good.crx");
-
- // Add the extension.
- provider->UpdateOrAddExtension(good_crx, "1.0.0.0", source_path);
-
- // Reloading extensions should find our externally registered extension
- // and install it.
- service_->CheckForExternalUpdates();
- loop_.RunAllPending();
-
- ASSERT_EQ(0u, GetErrors().size());
- ASSERT_EQ(1u, loaded_.size());
- ASSERT_EQ(location, loaded_[0]->location());
- ASSERT_EQ("1.0.0.0", loaded_[0]->version()->GetString());
- ValidatePrefKeyCount(1);
- ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
- ValidateIntegerPref(good_crx, "location", location);
-
- // Reload extensions without changing anything. The extension should be
- // loaded again.
- loaded_.clear();
- service_->ReloadExtensions();
- loop_.RunAllPending();
- ASSERT_EQ(0u, GetErrors().size());
- ASSERT_EQ(1u, loaded_.size());
- ValidatePrefKeyCount(1);
- ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
- ValidateIntegerPref(good_crx, "location", location);
-
- // Now update the extension with a new version. We should get upgraded.
- source_path = source_path.DirName().AppendASCII("good2.crx");
- provider->UpdateOrAddExtension(good_crx, "1.0.0.1", source_path);
-
- loaded_.clear();
- service_->CheckForExternalUpdates();
- loop_.RunAllPending();
- ASSERT_EQ(0u, GetErrors().size());
- ASSERT_EQ(1u, loaded_.size());
- ASSERT_EQ("1.0.0.1", loaded_[0]->version()->GetString());
- ValidatePrefKeyCount(1);
- ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
- ValidateIntegerPref(good_crx, "location", location);
-
- // Uninstall the extension and reload. Nothing should happen because the
- // preference should prevent us from reinstalling.
- std::string id = loaded_[0]->id();
- service_->UninstallExtension(id, false);
- loop_.RunAllPending();
-
- // The extension should also be gone from the install directory.
- FilePath install_path = extensions_install_dir_.AppendASCII(id);
- ASSERT_FALSE(file_util::PathExists(install_path));
-
- loaded_.clear();
- service_->CheckForExternalUpdates();
- loop_.RunAllPending();
- ASSERT_EQ(0u, loaded_.size());
- ValidatePrefKeyCount(1);
- ValidateIntegerPref(good_crx, "state", Extension::KILLBIT);
- ValidateIntegerPref(good_crx, "location", location);
-
- // Now clear the preference and reinstall.
- SetPrefInteg(good_crx, "state", Extension::ENABLED);
- profile_->GetPrefs()->ScheduleSavePersistentPrefs();
-
- loaded_.clear();
- service_->CheckForExternalUpdates();
- loop_.RunAllPending();
- ASSERT_EQ(1u, loaded_.size());
- ValidatePrefKeyCount(1);
- ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
- ValidateIntegerPref(good_crx, "location", location);
-
- // Now test an externally triggered uninstall (deleting the registry key or
- // the pref entry).
- provider->RemoveExtension(good_crx);
-
- loaded_.clear();
- service_->UnloadAllExtensions();
- service_->LoadAllExtensions();
- loop_.RunAllPending();
- ASSERT_EQ(0u, loaded_.size());
- ValidatePrefKeyCount(0);
-
- // The extension should also be gone from the install directory.
- ASSERT_FALSE(file_util::PathExists(install_path));
-
- // Now test the case where user uninstalls and then the extension is removed
- // from the external provider.
-
- provider->UpdateOrAddExtension(good_crx, "1.0", source_path);
- service_->CheckForExternalUpdates();
- loop_.RunAllPending();
-
- ASSERT_EQ(1u, loaded_.size());
- ASSERT_EQ(0u, GetErrors().size());
-
- // User uninstalls.
- loaded_.clear();
- service_->UninstallExtension(id, false);
- loop_.RunAllPending();
- ASSERT_EQ(0u, loaded_.size());
-
- // Then remove the extension from the extension provider.
- provider->RemoveExtension(good_crx);
-
- // Should still be at 0.
- loaded_.clear();
- service_->LoadAllExtensions();
- loop_.RunAllPending();
- ASSERT_EQ(0u, loaded_.size());
- ValidatePrefKeyCount(1);
-
- EXPECT_EQ(5, provider->visit_count());
-}
-
-// Tests the external installation feature
-#if defined(OS_WIN)
-TEST_F(ExtensionsServiceTest, ExternalInstallRegistry) {
- // This should all work, even when normal extension installation is disabled.
- InitializeEmptyExtensionsService();
- set_extensions_enabled(false);
-
- // Now add providers. Extension system takes ownership of the objects.
- MockExtensionProvider* reg_provider =
- new MockExtensionProvider(Extension::EXTERNAL_REGISTRY);
- AddMockExternalProvider(reg_provider);
- TestExternalProvider(reg_provider, Extension::EXTERNAL_REGISTRY);
-}
-#endif
-
-TEST_F(ExtensionsServiceTest, ExternalInstallPref) {
- InitializeEmptyExtensionsService();
-
- // Now add providers. Extension system takes ownership of the objects.
- MockExtensionProvider* pref_provider =
- new MockExtensionProvider(Extension::EXTERNAL_PREF);
-
- AddMockExternalProvider(pref_provider);
- TestExternalProvider(pref_provider, Extension::EXTERNAL_PREF);
-}
-
-TEST_F(ExtensionsServiceTest, ExternalInstallPrefUpdateUrl) {
- // This should all work, even when normal extension installation is disabled.
- InitializeEmptyExtensionsService();
- set_extensions_enabled(false);
-
- // TODO(skerner): The mock provider is not a good model of a provider
- // that works with update URLs, because it adds file and version info.
- // Extend the mock to work with update URLs. This test checks the
- // behavior that is common to all external extension visitors. The
- // browser test ExtensionManagementTest.ExternalUrlUpdate tests that
- // what the visitor does results in an extension being downloaded and
- // installed.
- MockExtensionProvider* pref_provider =
- new MockExtensionProvider(Extension::EXTERNAL_PREF_DOWNLOAD);
- AddMockExternalProvider(pref_provider);
- TestExternalProvider(pref_provider, Extension::EXTERNAL_PREF_DOWNLOAD);
-}
-
-// Tests that external extensions get uninstalled when the external extension
-// providers can't account for them.
-TEST_F(ExtensionsServiceTest, ExternalUninstall) {
- // Start the extensions service with one external extension already installed.
- FilePath source_install_dir;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir));
- source_install_dir = source_install_dir
- .AppendASCII("extensions")
- .AppendASCII("good")
- .AppendASCII("Extensions");
- FilePath pref_path = source_install_dir
- .DirName()
- .AppendASCII("PreferencesExternal");
-
- // This initializes the extensions service with no ExternalExtensionProviders.
- InitializeInstalledExtensionsService(pref_path, source_install_dir);
- set_extensions_enabled(false);
-
- service_->Init();
- loop_.RunAllPending();
-
- ASSERT_EQ(0u, GetErrors().size());
- ASSERT_EQ(0u, loaded_.size());
-
- // Verify that it's not the disabled extensions flag causing it not to load.
- set_extensions_enabled(true);
- service_->ReloadExtensions();
- loop_.RunAllPending();
-
- ASSERT_EQ(0u, GetErrors().size());
- ASSERT_EQ(0u, loaded_.size());
-}
-
-TEST_F(ExtensionsServiceTest, ExternalPrefProvider) {
- InitializeEmptyExtensionsService();
- std::string json_data =
- "{"
- " \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\": {"
- " \"external_crx\": \"RandomExtension.crx\","
- " \"external_version\": \"1.0\""
- " },"
- " \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\": {"
- " \"external_crx\": \"RandomExtension2.crx\","
- " \"external_version\": \"2.0\""
- " },"
- " \"cccccccccccccccccccccccccccccccc\": {"
- " \"external_update_url\": \"http:\\\\foo.com/update\""
- " }"
- "}";
-
- MockProviderVisitor visitor;
- std::set<std::string> ignore_list;
- EXPECT_EQ(3, visitor.Visit(json_data, ignore_list));
- ignore_list.insert("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
- EXPECT_EQ(2, visitor.Visit(json_data, ignore_list));
- ignore_list.insert("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
- EXPECT_EQ(1, visitor.Visit(json_data, ignore_list));
- ignore_list.insert("cccccccccccccccccccccccccccccccc");
- EXPECT_EQ(0, visitor.Visit(json_data, ignore_list));
-
- // Simulate an external_extensions.json file that contains seven invalid
- // extensions:
- // - One that is missing the 'external_crx' key.
- // - One that is missing the 'external_version' key.
- // - One that is specifying .. in the path.
- // - One that specifies both a file and update URL.
- // - One that specifies no file or update URL.
- // - One that has an update URL that is not well formed.
- // - One that contains a malformed version.
- // The final extension is valid, and we check that it is read to make sure
- // failures don't stop valid records from being read.
- json_data =
- "{"
- " \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\": {"
- " \"external_version\": \"1.0\""
- " },"
- " \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\": {"
- " \"external_crx\": \"RandomExtension.crx\""
- " },"
- " \"cccccccccccccccccccccccccccccccc\": {"
- " \"external_crx\": \"..\\\\foo\\\\RandomExtension2.crx\","
- " \"external_version\": \"2.0\""
- " },"
- " \"dddddddddddddddddddddddddddddddd\": {"
- " \"external_crx\": \"RandomExtension2.crx\","
- " \"external_version\": \"2.0\","
- " \"external_update_url\": \"http:\\\\foo.com/update\""
- " },"
- " \"eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\": {"
- " },"
- " \"ffffffffffffffffffffffffffffffff\": {"
- " \"external_update_url\": \"This string is not a valid URL\""
- " },"
- " \"gggggggggggggggggggggggggggggggg\": {"
- " \"external_crx\": \"RandomExtension3.crx\","
- " \"external_version\": \"This is not a valid version!\""
- " },"
- " \"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh\": {"
- " \"external_crx\": \"RandomValidExtension.crx\","
- " \"external_version\": \"1.0\""
- " }"
- "}";
- ignore_list.clear();
- EXPECT_EQ(1, visitor.Visit(json_data, ignore_list));
-}
-
-// Test loading good extensions from the profile directory.
-TEST_F(ExtensionsServiceTest, LoadAndRelocalizeExtensions) {
- // Initialize the test dir with a good Preferences/extensions.
- FilePath source_install_dir;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir));
- source_install_dir = source_install_dir
- .AppendASCII("extensions")
- .AppendASCII("l10n");
- FilePath pref_path = source_install_dir.AppendASCII("Preferences");
- InitializeInstalledExtensionsService(pref_path, source_install_dir);
-
- service_->Init();
- loop_.RunAllPending();
-
- ASSERT_EQ(3u, loaded_.size());
-
- // This was equal to "sr" on load.
- ValidateStringPref(loaded_[0]->id(), keys::kCurrentLocale, "en");
-
- // These are untouched by re-localization.
- ValidateStringPref(loaded_[1]->id(), keys::kCurrentLocale, "en");
- EXPECT_FALSE(IsPrefExist(loaded_[1]->id(), keys::kCurrentLocale));
-
- // This one starts with Serbian name, and gets re-localized into English.
- EXPECT_EQ("My name is simple.", loaded_[0]->name());
-
- // These are untouched by re-localization.
- EXPECT_EQ("My name is simple.", loaded_[1]->name());
- EXPECT_EQ("no l10n", loaded_[2]->name());
-}
-
-class ExtensionsReadyRecorder : public NotificationObserver {
- public:
- ExtensionsReadyRecorder() : ready_(false) {
- registrar_.Add(this, NotificationType::EXTENSIONS_READY,
- NotificationService::AllSources());
- }
-
- void set_ready(bool value) { ready_ = value; }
- bool ready() { return ready_; }
-
- private:
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- switch (type.value) {
- case NotificationType::EXTENSIONS_READY:
- ready_ = true;
- break;
- default:
- NOTREACHED();
- }
- }
-
- NotificationRegistrar registrar_;
- bool ready_;
-};
-
-// Test that we get enabled/disabled correctly for all the pref/command-line
-// combinations. We don't want to derive from the ExtensionsServiceTest class
-// for this test, so we use ExtensionsServiceTestSimple.
-//
-// Also tests that we always fire EXTENSIONS_READY, no matter whether we are
-// enabled or not.
-TEST(ExtensionsServiceTestSimple, Enabledness) {
- ExtensionsReadyRecorder recorder;
- scoped_ptr<TestingProfile> profile(new TestingProfile());
- MessageLoop loop;
- BrowserThread ui_thread(BrowserThread::UI, &loop);
- BrowserThread file_thread(BrowserThread::FILE, &loop);
- scoped_ptr<CommandLine> command_line;
- scoped_refptr<ExtensionsService> service;
- FilePath install_dir = profile->GetPath()
- .AppendASCII(ExtensionsService::kInstallDirectoryName);
-
- // By default, we are enabled.
- command_line.reset(new CommandLine(CommandLine::NO_PROGRAM));
- service = profile->CreateExtensionsService(command_line.get(),
- install_dir);
- EXPECT_TRUE(service->extensions_enabled());
- service->Init();
- loop.RunAllPending();
- EXPECT_TRUE(recorder.ready());
-
- // If either the command line or pref is set, we are disabled.
- recorder.set_ready(false);
- profile.reset(new TestingProfile());
- command_line->AppendSwitch(switches::kDisableExtensions);
- service = profile->CreateExtensionsService(command_line.get(),
- install_dir);
- EXPECT_FALSE(service->extensions_enabled());
- service->Init();
- loop.RunAllPending();
- EXPECT_TRUE(recorder.ready());
-
- recorder.set_ready(false);
- profile.reset(new TestingProfile());
- profile->GetPrefs()->SetBoolean(prefs::kDisableExtensions, true);
- service = profile->CreateExtensionsService(command_line.get(),
- install_dir);
- EXPECT_FALSE(service->extensions_enabled());
- service->Init();
- loop.RunAllPending();
- EXPECT_TRUE(recorder.ready());
-
- recorder.set_ready(false);
- profile.reset(new TestingProfile());
- profile->GetPrefs()->SetBoolean(prefs::kDisableExtensions, true);
- command_line.reset(new CommandLine(CommandLine::NO_PROGRAM));
- service = profile->CreateExtensionsService(command_line.get(),
- install_dir);
- EXPECT_FALSE(service->extensions_enabled());
- service->Init();
- loop.RunAllPending();
- EXPECT_TRUE(recorder.ready());
-
- // Explicitly delete all the resources used in this test.
- profile.reset();
- service = NULL;
-}
-
-// Test loading extensions that require limited and unlimited storage quotas.
-TEST_F(ExtensionsServiceTest, StorageQuota) {
- InitializeEmptyExtensionsService();
-
- FilePath extensions_path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
- extensions_path = extensions_path.AppendASCII("extensions")
- .AppendASCII("storage_quota");
-
- FilePath limited_quota_ext = extensions_path.AppendASCII("limited_quota")
- .AppendASCII("1.0");
-
- // The old permission name for unlimited quota was "unlimited_storage", but
- // we changed it to "unlimitedStorage". This tests both versions.
- FilePath unlimited_quota_ext = extensions_path.AppendASCII("unlimited_quota")
- .AppendASCII("1.0");
- FilePath unlimited_quota_ext2 = extensions_path.AppendASCII("unlimited_quota")
- .AppendASCII("2.0");
- service_->LoadExtension(limited_quota_ext);
- service_->LoadExtension(unlimited_quota_ext);
- service_->LoadExtension(unlimited_quota_ext2);
- loop_.RunAllPending();
-
- ASSERT_EQ(3u, loaded_.size());
- EXPECT_TRUE(profile_.get());
- EXPECT_FALSE(profile_->IsOffTheRecord());
-
- // Open the database from each origin to make the tracker aware
- // of the existence of these origins and to get their quotas.
- int64 limited_quota = -1;
- int64 unlimited_quota = -1;
- string16 limited_quota_identifier =
- webkit_database::DatabaseUtil::GetOriginIdentifier(loaded_[0]->url());
- string16 unlimited_quota_identifier =
- webkit_database::DatabaseUtil::GetOriginIdentifier(loaded_[1]->url());
- string16 unlimited_quota_identifier2 =
- webkit_database::DatabaseUtil::GetOriginIdentifier(loaded_[2]->url());
- string16 db_name = UTF8ToUTF16("db");
- string16 description = UTF8ToUTF16("db_description");
- int64 database_size;
- webkit_database::DatabaseTracker* db_tracker = profile_->GetDatabaseTracker();
-
- // First check the normal limited quota extension.
- db_tracker->DatabaseOpened(limited_quota_identifier, db_name, description,
- 1, &database_size, &limited_quota);
- db_tracker->DatabaseClosed(limited_quota_identifier, db_name);
- EXPECT_EQ(profile_->GetDatabaseTracker()->GetDefaultQuota(), limited_quota);
-
- // Now check the two unlimited quota ones.
- db_tracker->DatabaseOpened(unlimited_quota_identifier, db_name, description,
- 1, &database_size, &unlimited_quota);
- db_tracker->DatabaseClosed(unlimited_quota_identifier, db_name);
- EXPECT_EQ(kint64max, unlimited_quota);
- db_tracker->DatabaseOpened(unlimited_quota_identifier2, db_name, description,
- 1, &database_size, &unlimited_quota);
- db_tracker->DatabaseClosed(unlimited_quota_identifier2, db_name);
-
- EXPECT_EQ(kint64max, unlimited_quota);
-}
-
-// Tests ExtensionsService::register_component_extension().
-TEST_F(ExtensionsServiceTest, ComponentExtensions) {
- InitializeEmptyExtensionsService();
-
- // Component extensions should work even when extensions are disabled.
- set_extensions_enabled(false);
-
- FilePath path;
- ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
- path = path.AppendASCII("extensions")
- .AppendASCII("good")
- .AppendASCII("Extensions")
- .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
- .AppendASCII("1.0.0.0");
-
- std::string manifest;
- ASSERT_TRUE(file_util::ReadFileToString(
- path.Append(Extension::kManifestFilename), &manifest));
-
- service_->register_component_extension(
- ExtensionsService::ComponentExtensionInfo(manifest, path));
- service_->Init();
-
- // Note that we do not pump messages -- the extension should be loaded
- // immediately.
-
- EXPECT_EQ(0u, GetErrors().size());
- ASSERT_EQ(1u, loaded_.size());
- EXPECT_EQ(Extension::COMPONENT, loaded_[0]->location());
- EXPECT_EQ(1u, service_->extensions()->size());
-
- // Component extensions shouldn't get recourded in the prefs.
- ValidatePrefKeyCount(0);
-
- // Reload all extensions, and make sure it comes back.
- std::string extension_id = service_->extensions()->at(0)->id();
- loaded_.clear();
- service_->ReloadExtensions();
- ASSERT_EQ(1u, service_->extensions()->size());
- EXPECT_EQ(extension_id, service_->extensions()->at(0)->id());
-}
diff --git a/chrome/browser/extensions/extensions_service_unittest.h b/chrome/browser/extensions/extensions_service_unittest.h
deleted file mode 100644
index f38cc34..0000000
--- a/chrome/browser/extensions/extensions_service_unittest.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSIONS_SERVICE_UNITTEST_H_
-#define CHROME_BROWSER_EXTENSIONS_EXTENSIONS_SERVICE_UNITTEST_H_
-#pragma once
-
-#include "base/file_path.h"
-#include "base/message_loop.h"
-#include "base/ref_counted.h"
-#include "base/scoped_ptr.h"
-#include "base/scoped_temp_dir.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-class ExtensionsServiceTestBase : public testing::Test {
- public:
- ExtensionsServiceTestBase();
- ~ExtensionsServiceTestBase();
-
- virtual void InitializeExtensionsService(
- const FilePath& pref_file, const FilePath& extensions_install_dir);
-
- virtual void InitializeInstalledExtensionsService(
- const FilePath& prefs_file, const FilePath& source_install_dir);
-
- virtual void InitializeEmptyExtensionsService();
-
- static void SetUpTestCase();
-
- virtual void SetUp();
-
- void set_extensions_enabled(bool enabled) {
- service_->set_extensions_enabled(enabled);
- }
-
- protected:
- ScopedTempDir temp_dir_;
- scoped_ptr<Profile> profile_;
- FilePath extensions_install_dir_;
- scoped_refptr<ExtensionsService> service_;
- size_t total_successes_;
- MessageLoop loop_;
- BrowserThread ui_thread_;
- BrowserThread db_thread_;
- BrowserThread webkit_thread_;
- BrowserThread file_thread_;
- BrowserThread io_thread_;
-};
-
-#endif // CHROME_BROWSER_EXTENSIONS_EXTENSIONS_SERVICE_UNITTEST_H_
diff --git a/chrome/browser/extensions/extensions_startup.cc b/chrome/browser/extensions/extensions_startup.cc
index 9faeac6..8e0b855 100644
--- a/chrome/browser/extensions/extensions_startup.cc
+++ b/chrome/browser/extensions/extensions_startup.cc
@@ -7,49 +7,31 @@
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/extensions/pack_extension_job.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"
#if defined(OS_WIN)
#include "app/win_util.h"
#endif
-namespace extensions_startup {
+ExtensionsStartupUtil::ExtensionsStartupUtil() : pack_job_succeeded_(false) {}
-class PackExtensionLogger : public PackExtensionJob::Client {
- public:
- PackExtensionLogger() : process_startup_(false) {}
- virtual void OnPackSuccess(const FilePath& crx_path,
- const FilePath& output_private_key_path);
- virtual void OnPackFailure(const std::string& error_message);
-
- private:
- // We need to track if this extension packing job was created on process
- // startup or not so we know if we should Quit() the message loop after
- // packaging the extension.
- bool process_startup_;
- void ShowPackExtensionMessage(const std::wstring& caption,
- const std::wstring& message);
-
- DISALLOW_COPY_AND_ASSIGN(PackExtensionLogger);
-};
-
-void PackExtensionLogger::OnPackSuccess(
+void ExtensionsStartupUtil::OnPackSuccess(
const FilePath& crx_path,
const FilePath& output_private_key_path) {
+ pack_job_succeeded_ = true;
ShowPackExtensionMessage(L"Extension Packaging Success",
PackExtensionJob::StandardSuccessMessage(
crx_path, output_private_key_path));
}
-void PackExtensionLogger::OnPackFailure(const std::string& error_message) {
+void ExtensionsStartupUtil::OnPackFailure(const std::string& error_message) {
ShowPackExtensionMessage(L"Extension Packaging Error",
UTF8ToWide(error_message));
}
-void PackExtensionLogger::ShowPackExtensionMessage(
+void ExtensionsStartupUtil::ShowPackExtensionMessage(
const std::wstring& caption,
const std::wstring& message) {
#if defined(OS_WIN)
@@ -62,62 +44,49 @@ void PackExtensionLogger::ShowPackExtensionMessage(
out_text.append("\n");
base::StringPrintf("%s", out_text.c_str());
#endif
-
- // We got the notification and processed it; we don't expect any further tasks
- // to be posted to the current thread, so we should stop blocking and exit.
- // This call to |Quit()| matches the call to |Run()| in
- // |ProcessCmdLineImpl()|.
- MessageLoop::current()->Quit();
}
-bool HandlePackExtension(const CommandLine& cmd_line) {
- if (cmd_line.HasSwitch(switches::kPackExtension)) {
- // Input Paths.
- FilePath src_dir = cmd_line.GetSwitchValuePath(
- switches::kPackExtension);
- FilePath private_key_path;
- if (cmd_line.HasSwitch(switches::kPackExtensionKey)) {
- private_key_path = cmd_line.GetSwitchValuePath(
- switches::kPackExtensionKey);
- }
-
- // Launch a job to perform the packing on the file thread.
- PackExtensionLogger pack_client;
- scoped_refptr<PackExtensionJob> pack_job(
- new PackExtensionJob(&pack_client, src_dir, private_key_path));
- pack_job->Start();
-
- // The job will post a notification task to the current thread's message
- // loop when it is finished. We manually run the loop here so that we
- // block and catch the notification. Otherwise, the process would exit;
- // in particular, this would mean that |pack_client| would be destroyed
- // and we wouldn't be able to report success or failure back to the user.
- // This call to |Run()| is matched by a call to |Quit()| in the
- // |PackExtensionLogger|'s notification handling code.
- MessageLoop::current()->Run();
+bool ExtensionsStartupUtil::PackExtension(const CommandLine& cmd_line) {
+ if (!cmd_line.HasSwitch(switches::kPackExtension))
+ return false;
- return true;
+ // Input Paths.
+ FilePath src_dir = cmd_line.GetSwitchValuePath(switches::kPackExtension);
+ FilePath private_key_path;
+ if (cmd_line.HasSwitch(switches::kPackExtensionKey)) {
+ private_key_path = cmd_line.GetSwitchValuePath(switches::kPackExtensionKey);
}
- return false;
+ // Launch a job to perform the packing on the file thread.
+ pack_job_ = new PackExtensionJob(this, src_dir, private_key_path);
+ pack_job_->set_asynchronous(false);
+ pack_job_->Start();
+
+ return pack_job_succeeded_;
}
-bool HandleUninstallExtension(const CommandLine& cmd_line, Profile* profile) {
+bool ExtensionsStartupUtil::UninstallExtension(const CommandLine& cmd_line,
+ Profile* profile) {
DCHECK(profile);
- if (cmd_line.HasSwitch(switches::kUninstallExtension)) {
- ExtensionsService* extensions_service = profile->GetExtensionsService();
- if (extensions_service) {
- std::string extension_id = cmd_line.GetSwitchValueASCII(
- switches::kUninstallExtension);
- if (ExtensionsService::UninstallExtensionHelper(extensions_service,
- extension_id)) {
- return true;
- }
- }
+ if (!cmd_line.HasSwitch(switches::kUninstallExtension))
+ return false;
+
+ ExtensionService* extension_service = profile->GetExtensionService();
+ if (!extension_service)
+ return false;
+
+ std::string extension_id = cmd_line.GetSwitchValueASCII(
+ switches::kUninstallExtension);
+ if (ExtensionService::UninstallExtensionHelper(extension_service,
+ extension_id)) {
+ return true;
}
return false;
}
-} // namespace extensions_startup
+ExtensionsStartupUtil::~ExtensionsStartupUtil() {
+ if (pack_job_.get())
+ pack_job_->ClearClient();
+}
diff --git a/chrome/browser/extensions/extensions_startup.h b/chrome/browser/extensions/extensions_startup.h
index 85622de..2dee7d3 100644
--- a/chrome/browser/extensions/extensions_startup.h
+++ b/chrome/browser/extensions/extensions_startup.h
@@ -6,19 +6,38 @@
#define CHROME_BROWSER_EXTENSIONS_EXTENSIONS_STARTUP_H_
#pragma once
+#include "base/scoped_ptr.h"
+#include "chrome/browser/extensions/pack_extension_job.h"
+
class CommandLine;
class Profile;
// Initialization helpers for various Extension startup actions.
-namespace extensions_startup {
-// Handle --pack-extension flag from the |cmd_line| by packing the specified
-// extension. Returns false if the pack job could not be started.
-bool HandlePackExtension(const CommandLine& cmd_line);
-
-// Handle --uninstall-extension flag from the |cmd_line| by uninstalling the
-// specified extension from |profile|. Returns false if the uninstall job
-// could not be started.
-bool HandleUninstallExtension(const CommandLine& cmd_line, Profile* profile);
-} // namespace extensions_startup
+class ExtensionsStartupUtil : public PackExtensionJob::Client {
+ public:
+ ExtensionsStartupUtil();
+ virtual ~ExtensionsStartupUtil();
+
+ virtual void OnPackSuccess(const FilePath& crx_path,
+ const FilePath& output_private_key_path);
+ virtual void OnPackFailure(const std::string& error_message);
+
+ // Handle --pack-extension flag from the |cmd_line| by packing the specified
+ // extension. Returns false if the pack job failed.
+ bool PackExtension(const CommandLine& cmd_line);
+
+ // Handle --uninstall-extension flag from the |cmd_line| by uninstalling the
+ // specified extension from |profile|. Returns false if the uninstall job
+ // could not be started.
+ bool UninstallExtension(const CommandLine& cmd_line, Profile* profile);
+
+ private:
+ void ShowPackExtensionMessage(const std::wstring& caption,
+ const std::wstring& message);
+ scoped_refptr<PackExtensionJob> pack_job_;
+ bool pack_job_succeeded_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionsStartupUtil);
+};
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSIONS_STARTUP_H_
diff --git a/chrome/browser/extensions/extensions_ui.cc b/chrome/browser/extensions/extensions_ui.cc
index 0078f0e..5d3a05d 100644
--- a/chrome/browser/extensions/extensions_ui.cc
+++ b/chrome/browser/extensions/extensions_ui.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/extensions/extensions_ui.h"
+#include <algorithm>
+
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/base64.h"
@@ -16,7 +18,6 @@
#include "base/thread.h"
#include "base/version.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/debugger/devtools_toggle_action.h"
#include "chrome/browser/extensions/crx_installer.h"
@@ -25,11 +26,11 @@
#include "chrome/browser/extensions/extension_function_dispatcher.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_message_service.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_updater.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
@@ -190,6 +191,9 @@ void ExtensionsUIHTMLSource::StartDataRequest(const std::string& path,
SendResponse(request_id, html_bytes);
}
+std::string ExtensionsUIHTMLSource::GetMimeType(const std::string&) const {
+ return "text/html";
+}
////////////////////////////////////////////////////////////////////////////////
//
@@ -289,7 +293,7 @@ void ExtensionsDOMHandler::IconLoader::ReportResultOnUIThread(
//
///////////////////////////////////////////////////////////////////////////////
-ExtensionsDOMHandler::ExtensionsDOMHandler(ExtensionsService* extension_service)
+ExtensionsDOMHandler::ExtensionsDOMHandler(ExtensionService* extension_service)
: extensions_service_(extension_service),
ignore_notifications_(false),
deleting_rvh_(NULL) {
@@ -387,8 +391,6 @@ void ExtensionsDOMHandler::OnIconsLoaded(DictionaryValue* json) {
NotificationService::AllSources());
registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
NotificationService::AllSources());
- registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED,
- NotificationService::AllSources());
registrar_.Add(this, NotificationType::EXTENSION_UPDATE_DISABLED,
NotificationService::AllSources());
registrar_.Add(this, NotificationType::EXTENSION_FUNCTION_DISPATCHER_CREATED,
@@ -675,6 +677,11 @@ void ExtensionsDOMHandler::FileSelected(const FilePath& path, int index,
dom_ui_->CallJavascriptFunction(L"window.handleFilePathSelected", results);
}
+void ExtensionsDOMHandler::MultiFilesSelected(
+ const std::vector<FilePath>& files, void* params) {
+ NOTREACHED();
+}
+
void ExtensionsDOMHandler::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
@@ -702,7 +709,6 @@ void ExtensionsDOMHandler::Observe(NotificationType type,
case NotificationType::EXTENSION_LOADED:
case NotificationType::EXTENSION_PROCESS_CREATED:
case NotificationType::EXTENSION_UNLOADED:
- case NotificationType::EXTENSION_UNLOADED_DISABLED:
case NotificationType::EXTENSION_UPDATE_DISABLED:
case NotificationType::EXTENSION_FUNCTION_DISPATCHER_CREATED:
case NotificationType::EXTENSION_FUNCTION_DISPATCHER_DESTROYED:
@@ -784,7 +790,7 @@ static bool ExtensionWantsFileAccess(const Extension* extension) {
// Static
DictionaryValue* ExtensionsDOMHandler::CreateExtensionDetailValue(
- ExtensionsService* service, const Extension* extension,
+ ExtensionService* service, const Extension* extension,
const std::vector<ExtensionPage>& pages, bool enabled) {
DictionaryValue* extension_data = new DictionaryValue();
@@ -929,8 +935,8 @@ ExtensionsDOMHandler::~ExtensionsDOMHandler() {
// ExtensionsDOMHandler, public: -----------------------------------------------
ExtensionsUI::ExtensionsUI(TabContents* contents) : DOMUI(contents) {
- ExtensionsService *exstension_service =
- GetProfile()->GetOriginalProfile()->GetExtensionsService();
+ ExtensionService *exstension_service =
+ GetProfile()->GetOriginalProfile()->GetExtensionService();
ExtensionsDOMHandler* handler = new ExtensionsDOMHandler(exstension_service);
AddMessageHandler(handler);
@@ -942,7 +948,7 @@ ExtensionsUI::ExtensionsUI(TabContents* contents) : DOMUI(contents) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(
- Singleton<ChromeURLDataManager>::get(),
+ ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(html_source)));
}
diff --git a/chrome/browser/extensions/extensions_ui.h b/chrome/browser/extensions/extensions_ui.h
index 54ec298..b7a9b69 100644
--- a/chrome/browser/extensions/extensions_ui.h
+++ b/chrome/browser/extensions/extensions_ui.h
@@ -22,7 +22,7 @@
class DictionaryValue;
class Extension;
-class ExtensionsService;
+class ExtensionService;
class FilePath;
class ListValue;
class PrefService;
@@ -51,9 +51,7 @@ class ExtensionsUIHTMLSource : public ChromeURLDataManager::DataSource {
virtual void StartDataRequest(const std::string& path,
bool is_off_the_record,
int request_id);
- virtual std::string GetMimeType(const std::string&) const {
- return "text/html";
- }
+ virtual std::string GetMimeType(const std::string&) const;
private:
~ExtensionsUIHTMLSource() {}
@@ -104,7 +102,7 @@ class ExtensionsDOMHandler
ExtensionsDOMHandler* handler_;
};
- explicit ExtensionsDOMHandler(ExtensionsService* extension_service);
+ explicit ExtensionsDOMHandler(ExtensionService* extension_service);
virtual ~ExtensionsDOMHandler();
// DOMMessageHandler implementation.
@@ -113,7 +111,7 @@ class ExtensionsDOMHandler
// Extension Detail JSON Struct for page. (static for ease of testing).
// Note: service can be NULL in unit tests.
static DictionaryValue* CreateExtensionDetailValue(
- ExtensionsService* service,
+ ExtensionService* service,
const Extension* extension,
const std::vector<ExtensionPage>& pages,
bool enabled);
@@ -190,9 +188,7 @@ class ExtensionsDOMHandler
virtual void FileSelected(const FilePath& path,
int index, void* params);
virtual void MultiFilesSelected(
- const std::vector<FilePath>& files, void* params) {
- NOTREACHED();
- }
+ const std::vector<FilePath>& files, void* params);
virtual void FileSelectionCanceled(void* params) {}
// NotificationObserver
@@ -227,7 +223,7 @@ class ExtensionsDOMHandler
ExtensionInstallUI* GetExtensionInstallUI();
// Our model.
- scoped_refptr<ExtensionsService> extensions_service_;
+ scoped_refptr<ExtensionService> extensions_service_;
// Used to pick the directory when loading an extension.
scoped_refptr<SelectFileDialog> load_extension_dialog_;
diff --git a/chrome/browser/extensions/external_extension_provider.h b/chrome/browser/extensions/external_extension_provider.h
index 1d040bd..5bcce1d 100644
--- a/chrome/browser/extensions/external_extension_provider.h
+++ b/chrome/browser/extensions/external_extension_provider.h
@@ -6,9 +6,6 @@
#define CHROME_BROWSER_EXTENSIONS_EXTERNAL_EXTENSION_PROVIDER_H_
#pragma once
-#include <set>
-#include <string>
-
#include "chrome/common/extensions/extension.h"
class FilePath;
@@ -44,8 +41,7 @@ class ExternalExtensionProvider {
// Enumerate registered extension, calling OnExternalExtensionFound on
// the |visitor| object for each registered extension found. |ids_to_ignore|
// contains a list of extension ids that should not result in a call back.
- virtual void VisitRegisteredExtension(
- Visitor* visitor, const std::set<std::string>& ids_to_ignore) const = 0;
+ virtual void VisitRegisteredExtension(Visitor* visitor) const = 0;
// Test if this provider has an extension with id |id| registered.
virtual bool HasExtension(const std::string& id) const = 0;
diff --git a/chrome/browser/extensions/external_policy_extension_provider.cc b/chrome/browser/extensions/external_policy_extension_provider.cc
index d482bb3..5e87379 100644
--- a/chrome/browser/extensions/external_policy_extension_provider.cc
+++ b/chrome/browser/extensions/external_policy_extension_provider.cc
@@ -4,8 +4,10 @@
#include "chrome/browser/extensions/external_policy_extension_provider.h"
+#include "base/logging.h"
#include "base/values.h"
#include "chrome/common/pref_names.h"
+#include "chrome/browser/browser_thread.h"
#include "chrome/browser/extensions/stateful_external_extension_provider.h"
#include "chrome/browser/prefs/pref_service.h"
@@ -29,16 +31,27 @@ bool CheckExtension(std::string id, std::string update_url) {
}
-ExternalPolicyExtensionProvider::ExternalPolicyExtensionProvider()
- : StatefulExternalExtensionProvider(Extension::INVALID,
- Extension::EXTERNAL_POLICY_DOWNLOAD) {
+ExternalPolicyExtensionProvider::ExternalPolicyExtensionProvider(
+ const ListValue* forcelist)
+ : StatefulExternalExtensionProvider(
+ Extension::INVALID,
+ Extension::EXTERNAL_POLICY_DOWNLOAD) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ ProcessPreferences(forcelist);
}
ExternalPolicyExtensionProvider::~ExternalPolicyExtensionProvider() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}
void ExternalPolicyExtensionProvider::SetPreferences(
const ListValue* forcelist) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ ProcessPreferences(forcelist);
+}
+
+void ExternalPolicyExtensionProvider::ProcessPreferences(
+ const ListValue* forcelist) {
DictionaryValue* result = new DictionaryValue();
if (forcelist != NULL) {
std::string extension_desc;
@@ -59,5 +72,5 @@ void ExternalPolicyExtensionProvider::SetPreferences(
}
}
}
- prefs_.reset(result);
+ set_prefs(result);
}
diff --git a/chrome/browser/extensions/external_policy_extension_provider.h b/chrome/browser/extensions/external_policy_extension_provider.h
index bb4cc7d..9c36960 100644
--- a/chrome/browser/extensions/external_policy_extension_provider.h
+++ b/chrome/browser/extensions/external_policy_extension_provider.h
@@ -14,11 +14,14 @@ class PrefService;
// A specialization of the ExternalExtensionProvider that uses
// prefs::kExtensionInstallForceList to look up which external extensions are
-// registered.
+// registered. The value of this preference is received via the constructor and
+// via |SetPreferences| in case of run-time updates.
+// Instances of this class are expected to be created and destroyed on the UI
+// thread and they are expecting public method calls from the FILE thread.
class ExternalPolicyExtensionProvider
: public StatefulExternalExtensionProvider {
public:
- explicit ExternalPolicyExtensionProvider();
+ explicit ExternalPolicyExtensionProvider(const ListValue* forcelist);
virtual ~ExternalPolicyExtensionProvider();
// Set the internal list of extensions based on |forcelist|.
@@ -28,6 +31,9 @@ class ExternalPolicyExtensionProvider
private:
friend class MockExternalPolicyExtensionProviderVisitor;
+ // Set the internal list of extensions based on |forcelist|.
+ // Does not take ownership of |forcelist|.
+ void ProcessPreferences(const ListValue* forcelist);
};
#endif // CHROME_BROWSER_EXTENSIONS_EXTERNAL_POLICY_EXTENSION_PROVIDER_H_
diff --git a/chrome/browser/extensions/external_policy_extension_provider_unittest.cc b/chrome/browser/extensions/external_policy_extension_provider_unittest.cc
index 4fb5117..cd5a3df 100644
--- a/chrome/browser/extensions/external_policy_extension_provider_unittest.cc
+++ b/chrome/browser/extensions/external_policy_extension_provider_unittest.cc
@@ -7,11 +7,26 @@
#include "base/logging.h"
#include "base/values.h"
#include "base/version.h"
+#include "chrome/browser/browser_thread.h"
#include "chrome/browser/extensions/external_policy_extension_provider.h"
#include "chrome/common/extensions/extension.h"
#include "testing/gtest/include/gtest/gtest.h"
class ExternalPolicyExtensionProviderTest : public testing::Test {
+ public:
+ ExternalPolicyExtensionProviderTest()
+ : loop_(MessageLoop::TYPE_IO),
+ ui_thread_(BrowserThread::UI, &loop_),
+ file_thread_(BrowserThread::FILE, &loop_) {
+ }
+
+ virtual ~ExternalPolicyExtensionProviderTest() {
+ }
+
+ private:
+ MessageLoop loop_;
+ BrowserThread ui_thread_;
+ BrowserThread file_thread_;
};
class MockExternalPolicyExtensionProviderVisitor
@@ -25,14 +40,12 @@ class MockExternalPolicyExtensionProviderVisitor
void Visit(ListValue* policy_forcelist,
ListValue* policy_validlist,
const std::set<std::string>& ignore_list) {
- provider_.reset(new ExternalPolicyExtensionProvider());
- // Give the list extensions to the provider.
- provider_->SetPreferences(policy_forcelist);
+ provider_.reset(new ExternalPolicyExtensionProvider(policy_forcelist));
// Extensions will be removed from this list as they visited,
// so it should be emptied by the end.
remaining_extensions = policy_validlist;
- provider_->VisitRegisteredExtension(this, ignore_list);
+ provider_->VisitRegisteredExtension(this);
EXPECT_EQ(0u, remaining_extensions->GetSize());
}
diff --git a/chrome/browser/extensions/external_pref_extension_provider.cc b/chrome/browser/extensions/external_pref_extension_provider.cc
index 7580388..7ea5f4a 100644
--- a/chrome/browser/extensions/external_pref_extension_provider.cc
+++ b/chrome/browser/extensions/external_pref_extension_provider.cc
@@ -9,12 +9,14 @@
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
+#include "chrome/browser/browser_thread.h"
#include "chrome/browser/extensions/stateful_external_extension_provider.h"
#include "chrome/common/json_value_serializer.h"
ExternalPrefExtensionProvider::ExternalPrefExtensionProvider()
: StatefulExternalExtensionProvider(Extension::EXTERNAL_PREF,
Extension::EXTERNAL_PREF_DOWNLOAD) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
FilePath json_file;
PathService::Get(app::DIR_EXTERNAL_EXTENSIONS, &json_file);
json_file = json_file.Append(FILE_PATH_LITERAL("external_extensions.json"));
@@ -23,11 +25,12 @@ ExternalPrefExtensionProvider::ExternalPrefExtensionProvider()
JSONFileValueSerializer serializer(json_file);
SetPreferences(&serializer);
} else {
- prefs_.reset(new DictionaryValue());
+ set_prefs(new DictionaryValue());
}
}
ExternalPrefExtensionProvider::~ExternalPrefExtensionProvider() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}
void ExternalPrefExtensionProvider::SetPreferencesForTesting(
@@ -50,5 +53,5 @@ void ExternalPrefExtensionProvider::SetPreferences(
dictionary.reset(static_cast<DictionaryValue*>(extensions));
}
}
- prefs_.reset(dictionary.release());
+ set_prefs(dictionary.release());
}
diff --git a/chrome/browser/extensions/external_pref_extension_provider.h b/chrome/browser/extensions/external_pref_extension_provider.h
index 8b9eb0b..b74be39 100644
--- a/chrome/browser/extensions/external_pref_extension_provider.h
+++ b/chrome/browser/extensions/external_pref_extension_provider.h
@@ -10,6 +10,8 @@
// A specialization of the ExternalExtensionProvider that uses a json file to
// look up which external extensions are registered.
+// Instances of this class are expected to be created and destroyed on the UI
+// thread and they are expecting public method calls from the FILE thread.
class ExternalPrefExtensionProvider : public StatefulExternalExtensionProvider {
public:
explicit ExternalPrefExtensionProvider();
diff --git a/chrome/browser/extensions/external_registry_extension_provider_win.cc b/chrome/browser/extensions/external_registry_extension_provider_win.cc
index 00bea09..16b107f 100644
--- a/chrome/browser/extensions/external_registry_extension_provider_win.cc
+++ b/chrome/browser/extensions/external_registry_extension_provider_win.cc
@@ -41,7 +41,7 @@ ExternalRegistryExtensionProvider::~ExternalRegistryExtensionProvider() {
}
void ExternalRegistryExtensionProvider::VisitRegisteredExtension(
- Visitor* visitor, const std::set<std::string>& ids_to_ignore) const {
+ Visitor* visitor) const {
base::win::RegistryKeyIterator iterator(
kRegRoot, ASCIIToWide(kRegistryExtensions).c_str());
while (iterator.Valid()) {
@@ -56,13 +56,10 @@ void ExternalRegistryExtensionProvider::VisitRegisteredExtension(
if (key.ReadValue(kRegistryExtensionVersion, &extension_version)) {
std::string id = WideToASCII(iterator.Name());
StringToLowerASCII(&id);
- if (ids_to_ignore.find(id) != ids_to_ignore.end()) {
- ++iterator;
- continue;
- }
scoped_ptr<Version> version;
- version.reset(Version::GetVersionFromString(extension_version));
+ version.reset(Version::GetVersionFromString(
+ WideToASCII(extension_version)));
if (!version.get()) {
LOG(ERROR) << "Invalid version value " << extension_version
<< " for key " << key_path;
@@ -107,8 +104,10 @@ bool ExternalRegistryExtensionProvider::GetExtensionDetails(
if (!key.ReadValue(kRegistryExtensionVersion, &extension_version))
return false;
- if (version)
- version->reset(Version::GetVersionFromString(extension_version));
+ if (version) {
+ version->reset(Version::GetVersionFromString(
+ WideToASCII(extension_version)));
+ }
if (location)
*location = Extension::EXTERNAL_REGISTRY;
diff --git a/chrome/browser/extensions/external_registry_extension_provider_win.h b/chrome/browser/extensions/external_registry_extension_provider_win.h
index bb60106..34899ae 100644
--- a/chrome/browser/extensions/external_registry_extension_provider_win.h
+++ b/chrome/browser/extensions/external_registry_extension_provider_win.h
@@ -6,9 +6,6 @@
#define CHROME_BROWSER_EXTENSIONS_EXTERNAL_REGISTRY_EXTENSION_PROVIDER_WIN_H_
#pragma once
-#include <set>
-#include <string>
-
#include "chrome/browser/extensions/external_extension_provider.h"
class Version;
@@ -21,8 +18,7 @@ class ExternalRegistryExtensionProvider : public ExternalExtensionProvider {
virtual ~ExternalRegistryExtensionProvider();
// ExternalExtensionProvider implementation:
- virtual void VisitRegisteredExtension(
- Visitor* visitor, const std::set<std::string>& ids_to_ignore) const;
+ virtual void VisitRegisteredExtension(Visitor* visitor) const;
virtual bool HasExtension(const std::string& id) const;
diff --git a/chrome/browser/extensions/fragment_navigation_apitest.cc b/chrome/browser/extensions/fragment_navigation_apitest.cc
index 68ca622..8d931a8 100644
--- a/chrome/browser/extensions/fragment_navigation_apitest.cc
+++ b/chrome/browser/extensions/fragment_navigation_apitest.cc
@@ -11,7 +11,9 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptFragmentNavigation) {
ASSERT_TRUE(RunExtensionTest(extension_name)) << message_;
}
-IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ExecuteScriptFragmentNavigation) {
+// Crashy, http://crbug.com/67774.
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest,
+ DISABLED_ExecuteScriptFragmentNavigation) {
ASSERT_TRUE(StartTestServer());
const char* extension_name = "executescript/fragment";
ASSERT_TRUE(RunExtensionTest(extension_name)) << message_;
diff --git a/chrome/browser/extensions/gtk_theme_installed_infobar_delegate.cc b/chrome/browser/extensions/gtk_theme_installed_infobar_delegate.cc
index d3fc1c0..cd2f123 100644
--- a/chrome/browser/extensions/gtk_theme_installed_infobar_delegate.cc
+++ b/chrome/browser/extensions/gtk_theme_installed_infobar_delegate.cc
@@ -4,7 +4,7 @@
#include "chrome/browser/extensions/gtk_theme_installed_infobar_delegate.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
GtkThemeInstalledInfoBarDelegate::GtkThemeInstalledInfoBarDelegate(
TabContents* tab_contents,
diff --git a/chrome/browser/extensions/image_loading_tracker.cc b/chrome/browser/extensions/image_loading_tracker.cc
index 496c3ad..873dcaa 100644
--- a/chrome/browser/extensions/image_loading_tracker.cc
+++ b/chrome/browser/extensions/image_loading_tracker.cc
@@ -123,8 +123,6 @@ ImageLoadingTracker::ImageLoadingTracker(Observer* observer)
next_id_(0) {
registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
NotificationService::AllSources());
- registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED,
- NotificationService::AllSources());
}
ImageLoadingTracker::~ImageLoadingTracker() {
@@ -184,10 +182,10 @@ void ImageLoadingTracker::OnImageLoaded(
void ImageLoadingTracker::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
- DCHECK(type == NotificationType::EXTENSION_UNLOADED ||
- type == NotificationType::EXTENSION_UNLOADED_DISABLED);
+ DCHECK(type == NotificationType::EXTENSION_UNLOADED);
- const Extension* extension = Details<const Extension>(details).ptr();
+ const Extension* extension =
+ Details<UnloadedExtensionInfo>(details)->extension;
// Remove all entries in the load_map_ referencing the extension. This ensures
// we don't attempt to cache the image when the load completes.
diff --git a/chrome/browser/extensions/image_loading_tracker_unittest.cc b/chrome/browser/extensions/image_loading_tracker_unittest.cc
index 57b5268..4c9734f 100644
--- a/chrome/browser/extensions/image_loading_tracker_unittest.cc
+++ b/chrome/browser/extensions/image_loading_tracker_unittest.cc
@@ -160,10 +160,12 @@ TEST_F(ImageLoadingTrackerTest, DeleteExtensionWhileWaitingForCache) {
EXPECT_EQ(0, image_loaded_count());
// Send out notification the extension was uninstalled.
+ UnloadedExtensionInfo details(extension.get(),
+ UnloadedExtensionInfo::UNINSTALL);
NotificationService::current()->Notify(
NotificationType::EXTENSION_UNLOADED,
NotificationService::AllSources(),
- Details<const Extension>(extension.get()));
+ Details<UnloadedExtensionInfo>(&details));
// Chuck the extension, that way if anyone tries to access it we should crash
// or get valgrind errors.
diff --git a/chrome/browser/extensions/notifications_apitest.cc b/chrome/browser/extensions/notifications_apitest.cc
index 6a80635..7e2a34d 100644
--- a/chrome/browser/extensions/notifications_apitest.cc
+++ b/chrome/browser/extensions/notifications_apitest.cc
@@ -5,17 +5,11 @@
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/notifications/desktop_notification_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
-// Fails and hoses bot, http://crbug.com/50060.
// Flaky, http://crbug.com/42314.
-#if defined(OS_MACOSX)
-#define MAYBE_Notifications DISABLED_Notifications
-#else
-#define MAYBE_Notifications FLAKY_Notifications
-#endif
-IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_Notifications) {
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, FLAKY_Notifications) {
#if defined(OS_LINUX) && defined(TOOLKIT_VIEWS)
// Notifications not supported on linux/views yet.
#else
diff --git a/chrome/browser/extensions/pack_extension_job.cc b/chrome/browser/extensions/pack_extension_job.cc
index 5f64025..327d7c4 100644
--- a/chrome/browser/extensions/pack_extension_job.cc
+++ b/chrome/browser/extensions/pack_extension_job.cc
@@ -15,15 +15,19 @@
PackExtensionJob::PackExtensionJob(Client* client,
const FilePath& root_directory,
const FilePath& key_file)
- : client_(client), key_file_(key_file) {
+ : client_(client), key_file_(key_file), asynchronous_(true) {
root_directory_ = root_directory.StripTrailingSeparators();
CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_));
}
void PackExtensionJob::Start() {
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(this, &PackExtensionJob::RunOnFileThread));
+ if (asynchronous_) {
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(this, &PackExtensionJob::Run));
+ } else {
+ Run();
+ }
}
void PackExtensionJob::ClearClient() {
@@ -32,7 +36,7 @@ void PackExtensionJob::ClearClient() {
PackExtensionJob::~PackExtensionJob() {}
-void PackExtensionJob::RunOnFileThread() {
+void PackExtensionJob::Run() {
crx_file_out_ = FilePath(root_directory_.value() +
chrome::kExtensionFileExtension);
@@ -44,16 +48,24 @@ void PackExtensionJob::RunOnFileThread() {
// returns. See bug 20734.
ExtensionCreator creator;
if (creator.Run(root_directory_, crx_file_out_, key_file_, key_file_out_)) {
- BrowserThread::PostTask(
- client_thread_id_, FROM_HERE,
- NewRunnableMethod(this,
- &PackExtensionJob::ReportSuccessOnClientThread));
+ if (asynchronous_) {
+ BrowserThread::PostTask(
+ client_thread_id_, FROM_HERE,
+ NewRunnableMethod(this,
+ &PackExtensionJob::ReportSuccessOnClientThread));
+ } else {
+ ReportSuccessOnClientThread();
+ }
} else {
- BrowserThread::PostTask(
- client_thread_id_, FROM_HERE,
- NewRunnableMethod(
- this, &PackExtensionJob::ReportFailureOnClientThread,
- creator.error_message()));
+ if (asynchronous_) {
+ BrowserThread::PostTask(
+ client_thread_id_, FROM_HERE,
+ NewRunnableMethod(
+ this, &PackExtensionJob::ReportFailureOnClientThread,
+ creator.error_message()));
+ } else {
+ ReportFailureOnClientThread(creator.error_message());
+ }
}
}
diff --git a/chrome/browser/extensions/pack_extension_job.h b/chrome/browser/extensions/pack_extension_job.h
index ecd3d68..e26687a 100644
--- a/chrome/browser/extensions/pack_extension_job.h
+++ b/chrome/browser/extensions/pack_extension_job.h
@@ -33,8 +33,7 @@ class PackExtensionJob : public base::RefCountedThreadSafe<PackExtensionJob> {
const FilePath& root_directory,
const FilePath& key_file);
- // Starts the packing thread job. See http://crbug.com/27944 for more details
- // on why this function is needed.
+ // Starts the packing job.
void Start();
// The client should call this when it is destroyed to prevent
@@ -45,12 +44,15 @@ class PackExtensionJob : public base::RefCountedThreadSafe<PackExtensionJob> {
static std::wstring StandardSuccessMessage(const FilePath& crx_file,
const FilePath& key_file);
+ void set_asynchronous(bool async) { asynchronous_ = async; }
+
private:
friend class base::RefCountedThreadSafe<PackExtensionJob>;
virtual ~PackExtensionJob();
- void RunOnFileThread();
+ // If |asynchronous_| is false, this is run on whichever thread calls it.
+ void Run();
void ReportSuccessOnClientThread();
void ReportFailureOnClientThread(const std::string& error);
@@ -60,6 +62,7 @@ class PackExtensionJob : public base::RefCountedThreadSafe<PackExtensionJob> {
FilePath key_file_;
FilePath crx_file_out_;
FilePath key_file_out_;
+ bool asynchronous_;
DISALLOW_COPY_AND_ASSIGN(PackExtensionJob);
};
diff --git a/chrome/browser/extensions/page_action_apitest.cc b/chrome/browser/extensions/page_action_apitest.cc
index dede04b..504f909 100644
--- a/chrome/browser/extensions/page_action_apitest.cc
+++ b/chrome/browser/extensions/page_action_apitest.cc
@@ -5,12 +5,12 @@
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_browser_event_router.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/location_bar.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/omnibox/location_bar.h"
#include "chrome/common/extensions/extension_action.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/test/ui_test_utils.h"
diff --git a/chrome/browser/extensions/sandboxed_extension_unpacker.cc b/chrome/browser/extensions/sandboxed_extension_unpacker.cc
index faf236b..9d7e45b 100644
--- a/chrome/browser/extensions/sandboxed_extension_unpacker.cc
+++ b/chrome/browser/extensions/sandboxed_extension_unpacker.cc
@@ -6,6 +6,7 @@
#include <set>
+#include "app/l10n_util.h"
#include "base/base64.h"
#include "base/crypto/signature_verifier.h"
#include "base/file_util.h"
@@ -15,7 +16,7 @@
#include "base/task.h"
#include "base/utf_string_conversions.h" // TODO(viettrungluu): delete me.
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
@@ -25,6 +26,7 @@
#include "chrome/common/extensions/extension_unpacker.h"
#include "chrome/common/json_value_serializer.h"
#include "gfx/codec/png_codec.h"
+#include "grit/generated_resources.h"
#include "third_party/skia/include/core/SkBitmap.h"
const char SandboxedExtensionUnpacker::kExtensionHeaderMagic[] = "Cr24";
@@ -46,7 +48,10 @@ void SandboxedExtensionUnpacker::Start() {
// Create a temporary directory to work in.
if (!temp_dir_.CreateUniqueTempDirUnderPath(temp_path_)) {
- ReportFailure("Could not create temporary directory.");
+ // Could not create temporary directory.
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
+ ASCIIToUTF16("COULD_NOT_CREATE_TEMP_DIRECTORY")));
return;
}
@@ -61,7 +66,10 @@ void SandboxedExtensionUnpacker::Start() {
// Copy the crx file into our working directory.
FilePath temp_crx_path = temp_dir_.path().Append(crx_path_.BaseName());
if (!file_util::CopyFile(crx_path_, temp_crx_path)) {
- ReportFailure("Failed to copy extension file to temporary directory.");
+ // Failed to copy extension file to temporary directory.
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
+ ASCIIToUTF16("FAILED_TO_COPY_EXTENSION_FILE_TO_TEMP_DIRECTORY")));
return;
}
@@ -81,21 +89,7 @@ void SandboxedExtensionUnpacker::Start() {
if (!file_util::NormalizeFilePath(temp_crx_path, &link_free_crx_path)) {
LOG(ERROR) << "Could not get the normalized path of "
<< temp_crx_path.value();
-#if defined (OS_WIN)
- // On windows, it is possible to mount a disk without the root of that
- // disk having a drive letter. The sandbox does not support this.
- // See crbug/49530 .
- ReportFailure(
- "Can not unpack extension. To safely unpack an extension, "
- "there must be a path to your profile directory that starts "
- "with a drive letter and does not contain a junction, mount "
- "point, or symlink. No such path exists for your profile.");
-#else
- ReportFailure(
- "Can not unpack extension. To safely unpack an extension, "
- "there must be a path to your profile directory that does "
- "not contain a symlink. No such path exists for your profile.");
-#endif
+ ReportFailure(l10n_util::GetStringUTF8(IDS_EXTENSION_UNPACK_FAILED));
return;
}
@@ -153,7 +147,9 @@ void SandboxedExtensionUnpacker::OnUnpackExtensionSucceeded(
if (!extension_l10n_util::LocalizeExtension(extension_root_,
final_manifest.get(),
&error)) {
- ReportFailure(error);
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_ERROR_MESSAGE,
+ ASCIIToUTF16(error)));
return;
}
@@ -178,21 +174,29 @@ void SandboxedExtensionUnpacker::OnUnpackExtensionFailed(
const std::string& error) {
DCHECK(BrowserThread::CurrentlyOn(thread_identifier_));
got_response_ = true;
- ReportFailure(error);
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_ERROR_MESSAGE,
+ ASCIIToUTF16(error)));
}
-void SandboxedExtensionUnpacker::OnProcessCrashed() {
+void SandboxedExtensionUnpacker::OnProcessCrashed(int exit_code) {
// Don't report crashes if they happen after we got a response.
if (got_response_)
return;
- ReportFailure("Utility process crashed while trying to install.");
+ // Utility process crashed while trying to install.
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
+ ASCIIToUTF16("UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL")));
}
bool SandboxedExtensionUnpacker::ValidateSignature() {
ScopedStdioHandle file(file_util::OpenFile(crx_path_, "rb"));
if (!file.get()) {
- ReportFailure("Could not open crx file for reading");
+ // Could not open crx file for reading
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_ERROR_CODE,
+ ASCIIToUTF16("CRX_FILE_NOT_READABLE")));
return false;
}
@@ -207,29 +211,47 @@ bool SandboxedExtensionUnpacker::ValidateSignature() {
len = fread(&header, 1, sizeof(ExtensionHeader),
file.get());
if (len < sizeof(ExtensionHeader)) {
- ReportFailure("Invalid crx header");
+ // Invalid crx header
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_ERROR_CODE,
+ ASCIIToUTF16("CRX_HEADER_INVALID")));
return false;
}
if (strncmp(kExtensionHeaderMagic, header.magic,
sizeof(header.magic))) {
- ReportFailure("Bad magic number");
+ // Bad magic number
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_ERROR_CODE,
+ ASCIIToUTF16("CRX_MAGIC_NUMBER_INVALID")));
return false;
}
if (header.version != kCurrentVersion) {
- ReportFailure("Bad version number");
+ // Bad version numer
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_ERROR_CODE,
+ ASCIIToUTF16("CRX_VERSION_NUMBER_INVALID")));
return false;
}
if (header.key_size > kMaxPublicKeySize ||
header.signature_size > kMaxSignatureSize) {
- ReportFailure("Excessively large key or signature");
+ // Excessively large key or signature
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_ERROR_CODE,
+ ASCIIToUTF16("CRX_EXCESSIVELY_LARGE_KEY_OR_SIGNATURE")));
return false;
}
if (header.key_size == 0) {
- ReportFailure("Key length is zero");
+ // Key length is zero
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_ERROR_CODE,
+ ASCIIToUTF16("CRX_ZERO_KEY_LENGTH")));
return false;
}
if (header.signature_size == 0) {
- ReportFailure("Signature length is zero");
+ // Signature length is zero
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_ERROR_CODE,
+ ASCIIToUTF16("CRX_ZERO_SIGNATURE_LENGTH")));
return false;
}
@@ -237,7 +259,10 @@ bool SandboxedExtensionUnpacker::ValidateSignature() {
key.resize(header.key_size);
len = fread(&key.front(), sizeof(uint8), header.key_size, file.get());
if (len < header.key_size) {
- ReportFailure("Invalid public key");
+ // Invalid public key
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_ERROR_CODE,
+ ASCIIToUTF16("CRX_PUBLIC_KEY_INVALID")));
return false;
}
@@ -246,7 +271,10 @@ bool SandboxedExtensionUnpacker::ValidateSignature() {
len = fread(&signature.front(), sizeof(uint8), header.signature_size,
file.get());
if (len < header.signature_size) {
- ReportFailure("Invalid signature");
+ // Invalid signature
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_ERROR_CODE,
+ ASCIIToUTF16("CRX_SIGNATURE_INVALID")));
return false;
}
@@ -257,9 +285,11 @@ bool SandboxedExtensionUnpacker::ValidateSignature() {
signature.size(),
&key.front(),
key.size())) {
- ReportFailure("Signature verification initialization failed. "
- "This is most likely caused by a public key in "
- "the wrong format (should encode algorithm).");
+ // Signature verification initialization failed. This is most likely
+ // caused by a public key in the wrong format (should encode algorithm).
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_ERROR_CODE,
+ ASCIIToUTF16("CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED")));
return false;
}
@@ -268,7 +298,10 @@ bool SandboxedExtensionUnpacker::ValidateSignature() {
verifier.VerifyUpdate(buf, len);
if (!verifier.VerifyFinal()) {
- ReportFailure("Signature verification failed");
+ // Signature verification failed
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_ERROR_CODE,
+ ASCIIToUTF16("CRX_SIGNATURE_VERIFICATION_FAILED")));
return false;
}
@@ -300,7 +333,10 @@ DictionaryValue* SandboxedExtensionUnpacker::RewriteManifestFile(
JSONStringValueSerializer serializer(&manifest_json);
serializer.set_pretty_print(true);
if (!serializer.Serialize(*final_manifest)) {
- ReportFailure("Error serializing manifest.json.");
+ // Error serializing manifest.json.
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
+ ASCIIToUTF16("ERROR_SERIALIZING_MANIFEST_JSON")));
return NULL;
}
@@ -308,7 +344,10 @@ DictionaryValue* SandboxedExtensionUnpacker::RewriteManifestFile(
extension_root_.Append(Extension::kManifestFilename);
if (!file_util::WriteFile(manifest_path,
manifest_json.data(), manifest_json.size())) {
- ReportFailure("Error saving manifest.json.");
+ // Error saving manifest.json.
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
+ ASCIIToUTF16("ERROR_SAVING_MANIFEST_JSON")));
return NULL;
}
@@ -318,7 +357,10 @@ DictionaryValue* SandboxedExtensionUnpacker::RewriteManifestFile(
bool SandboxedExtensionUnpacker::RewriteImageFiles() {
ExtensionUnpacker::DecodedImages images;
if (!ExtensionUnpacker::ReadImagesFromFile(temp_dir_.path(), &images)) {
- ReportFailure("Couldn't read image data from disk.");
+ // Couldn't read image data from disk.
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
+ ASCIIToUTF16("COULD_NOT_READ_IMAGE_DATA_FROM_DISK")));
return false;
}
@@ -327,7 +369,10 @@ bool SandboxedExtensionUnpacker::RewriteImageFiles() {
// originals are gone for good.
std::set<FilePath> image_paths = extension_->GetBrowserImages();
if (image_paths.size() != images.size()) {
- ReportFailure("Decoded images don't match what's in the manifest.");
+ // Decoded images don't match what's in the manifest.
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
+ ASCIIToUTF16("DECODED_IMAGES_DO_NOT_MATCH_THE_MANIFEST")));
return false;
}
@@ -335,11 +380,17 @@ bool SandboxedExtensionUnpacker::RewriteImageFiles() {
it != image_paths.end(); ++it) {
FilePath path = *it;
if (path.IsAbsolute() || path.ReferencesParent()) {
- ReportFailure("Invalid path for browser image.");
+ // Invalid path for browser image.
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
+ ASCIIToUTF16("INVALID_PATH_FOR_BROWSER_IMAGE")));
return false;
}
if (!file_util::Delete(extension_root_.Append(path), false)) {
- ReportFailure("Error removing old image file.");
+ // Error removing old image file.
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
+ ASCIIToUTF16("ERROR_REMOVING_OLD_IMAGE_FILE")));
return false;
}
}
@@ -349,7 +400,10 @@ bool SandboxedExtensionUnpacker::RewriteImageFiles() {
const SkBitmap& image = images[i].a;
FilePath path_suffix = images[i].b;
if (path_suffix.IsAbsolute() || path_suffix.ReferencesParent()) {
- ReportFailure("Invalid path for bitmap image.");
+ // Invalid path for bitmap image.
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
+ ASCIIToUTF16("INVALID_PATH_FOR_BITMAP_IMAGE")));
return false;
}
FilePath path = extension_root_.Append(path_suffix);
@@ -359,7 +413,10 @@ bool SandboxedExtensionUnpacker::RewriteImageFiles() {
// though they may originally be .jpg, etc. Figure something out.
// http://code.google.com/p/chromium/issues/detail?id=12459
if (!gfx::PNGCodec::EncodeBGRASkBitmap(image, false, &image_data)) {
- ReportFailure("Error re-encoding theme image.");
+ // Error re-encoding theme image.
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
+ ASCIIToUTF16("ERROR_RE_ENCODING_THEME_IMAGE")));
return false;
}
@@ -367,7 +424,10 @@ bool SandboxedExtensionUnpacker::RewriteImageFiles() {
// so we can be sure the directory exists.
const char* image_data_ptr = reinterpret_cast<const char*>(&image_data[0]);
if (!file_util::WriteFile(path, image_data_ptr, image_data.size())) {
- ReportFailure("Error saving theme image.");
+ // Error saving theme image.
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
+ ASCIIToUTF16("ERROR_SAVING_THEME_IMAGE")));
return false;
}
}
@@ -379,7 +439,10 @@ bool SandboxedExtensionUnpacker::RewriteCatalogFiles() {
DictionaryValue catalogs;
if (!ExtensionUnpacker::ReadMessageCatalogsFromFile(temp_dir_.path(),
&catalogs)) {
- ReportFailure("Could not read catalog data from disk.");
+ // Could not read catalog data from disk.
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
+ ASCIIToUTF16("COULD_NOT_READ_CATALOG_DATA_FROM_DISK")));
return false;
}
@@ -388,7 +451,10 @@ bool SandboxedExtensionUnpacker::RewriteCatalogFiles() {
key_it != catalogs.end_keys(); ++key_it) {
DictionaryValue* catalog;
if (!catalogs.GetDictionaryWithoutPathExpansion(*key_it, &catalog)) {
- ReportFailure("Invalid catalog data.");
+ // Invalid catalog data.
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
+ ASCIIToUTF16("INVALID_CATALOG_DATA")));
return false;
}
@@ -397,7 +463,10 @@ bool SandboxedExtensionUnpacker::RewriteCatalogFiles() {
FilePath relative_path = FilePath::FromWStringHack(UTF8ToWide(*key_it));
relative_path = relative_path.Append(Extension::kMessagesFilename);
if (relative_path.IsAbsolute() || relative_path.ReferencesParent()) {
- ReportFailure("Invalid path for catalog.");
+ // Invalid path for catalog.
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
+ ASCIIToUTF16("INVALID_PATH_FOR_CATALOG")));
return false;
}
FilePath path = extension_root_.Append(relative_path);
@@ -406,7 +475,10 @@ bool SandboxedExtensionUnpacker::RewriteCatalogFiles() {
JSONStringValueSerializer serializer(&catalog_json);
serializer.set_pretty_print(true);
if (!serializer.Serialize(*catalog)) {
- ReportFailure("Error serializing catalog.");
+ // Error serializing catalog.
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
+ ASCIIToUTF16("ERROR_SERIALIZING_CATALOG")));
return false;
}
@@ -415,7 +487,10 @@ bool SandboxedExtensionUnpacker::RewriteCatalogFiles() {
if (!file_util::WriteFile(path,
catalog_json.c_str(),
catalog_json.size())) {
- ReportFailure("Error saving catalog.");
+ // Error saving catalog.
+ ReportFailure(l10n_util::GetStringFUTF8(
+ IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
+ ASCIIToUTF16("ERROR_SAVING_CATALOG")));
return false;
}
}
diff --git a/chrome/browser/extensions/sandboxed_extension_unpacker.h b/chrome/browser/extensions/sandboxed_extension_unpacker.h
index 8438482..e47b26c 100644
--- a/chrome/browser/extensions/sandboxed_extension_unpacker.h
+++ b/chrome/browser/extensions/sandboxed_extension_unpacker.h
@@ -122,9 +122,9 @@ class SandboxedExtensionUnpacker : public UtilityProcessHost::Client {
void StartProcessOnIOThread(const FilePath& temp_crx_path);
// SandboxedExtensionUnpacker
- void OnUnpackExtensionSucceeded(const DictionaryValue& manifest);
- void OnUnpackExtensionFailed(const std::string& error_message);
- void OnProcessCrashed();
+ virtual void OnUnpackExtensionSucceeded(const DictionaryValue& manifest);
+ virtual void OnUnpackExtensionFailed(const std::string& error_message);
+ virtual void OnProcessCrashed(int exit_code);
void ReportFailure(const std::string& message);
void ReportSuccess();
diff --git a/chrome/browser/extensions/stateful_external_extension_provider.cc b/chrome/browser/extensions/stateful_external_extension_provider.cc
index 63899da..fd1a42a 100644
--- a/chrome/browser/extensions/stateful_external_extension_provider.cc
+++ b/chrome/browser/extensions/stateful_external_extension_provider.cc
@@ -10,6 +10,7 @@
#include "base/path_service.h"
#include "base/values.h"
#include "base/version.h"
+#include "chrome/browser/browser_thread.h"
namespace {
@@ -27,19 +28,20 @@ StatefulExternalExtensionProvider::StatefulExternalExtensionProvider(
Extension::Location download_location)
: crx_location_(crx_location),
download_location_(download_location) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}
StatefulExternalExtensionProvider::~StatefulExternalExtensionProvider() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}
void StatefulExternalExtensionProvider::VisitRegisteredExtension(
- Visitor* visitor, const std::set<std::string>& ids_to_ignore) const {
+ Visitor* visitor) const {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK(prefs_.get());
for (DictionaryValue::key_iterator i = prefs_->begin_keys();
i != prefs_->end_keys(); ++i) {
const std::string& extension_id = *i;
- if (ids_to_ignore.find(extension_id) != ids_to_ignore.end())
- continue;
-
DictionaryValue* extension;
if (!prefs_->GetDictionaryWithoutPathExpansion(extension_id, &extension))
continue;
@@ -123,12 +125,16 @@ void StatefulExternalExtensionProvider::VisitRegisteredExtension(
bool StatefulExternalExtensionProvider::HasExtension(
const std::string& id) const {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK(prefs_.get());
return prefs_->HasKey(id);
}
bool StatefulExternalExtensionProvider::GetExtensionDetails(
const std::string& id, Extension::Location* location,
scoped_ptr<Version>* version) const {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK(prefs_.get());
DictionaryValue* extension = NULL;
if (!prefs_->GetDictionary(id, &extension))
return false;
@@ -157,3 +163,7 @@ bool StatefulExternalExtensionProvider::GetExtensionDetails(
return true;
}
+
+void StatefulExternalExtensionProvider::set_prefs(DictionaryValue* prefs) {
+ prefs_.reset(prefs);
+}
diff --git a/chrome/browser/extensions/stateful_external_extension_provider.h b/chrome/browser/extensions/stateful_external_extension_provider.h
index 506873d..2fd481c 100644
--- a/chrome/browser/extensions/stateful_external_extension_provider.h
+++ b/chrome/browser/extensions/stateful_external_extension_provider.h
@@ -6,9 +6,6 @@
#define CHROME_BROWSER_EXTENSIONS_STATEFUL_EXTERNAL_EXTENSION_PROVIDER_H_
#pragma once
-#include <set>
-#include <string>
-
#include "chrome/browser/extensions/external_extension_provider.h"
class DictionaryValue;
@@ -23,6 +20,8 @@ class Version;
// This provider can provide external extensions from two sources: crx files
// and udpate URLs. The locations that the provider will report for these
// are specified at the constructor.
+// Instances of this class are expected to be created and destroyed on the UI
+// thread and they are expecting public method calls from the FILE thread.
class StatefulExternalExtensionProvider : public ExternalExtensionProvider {
public:
// Initialize the location for external extensions originating from crx
@@ -35,8 +34,7 @@ class StatefulExternalExtensionProvider : public ExternalExtensionProvider {
virtual ~StatefulExternalExtensionProvider();
// ExternalExtensionProvider implementation:
- virtual void VisitRegisteredExtension(
- Visitor* visitor, const std::set<std::string>& ids_to_ignore) const;
+ virtual void VisitRegisteredExtension(Visitor* visitor) const;
virtual bool HasExtension(const std::string& id) const;
@@ -50,6 +48,12 @@ class StatefulExternalExtensionProvider : public ExternalExtensionProvider {
// Location for external extensions that are provided by this provider from
// update URLs.
const Extension::Location download_location_;
+
+ // Stores the dictionary of external extensions internally. Takes ownership
+ // of |prefs|.
+ void set_prefs(DictionaryValue* prefs);
+
+ private:
// Dictionary of the external extensions that are provided by this provider.
scoped_ptr<DictionaryValue> prefs_;
};
diff --git a/chrome/browser/extensions/test_extension_prefs.cc b/chrome/browser/extensions/test_extension_prefs.cc
index 2cbb2d1..5b0ee7b 100644
--- a/chrome/browser/extensions/test_extension_prefs.cc
+++ b/chrome/browser/extensions/test_extension_prefs.cc
@@ -6,18 +6,46 @@
#include "base/file_util.h"
#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
#include "base/scoped_ptr.h"
#include "base/values.h"
#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/extensions/extension_pref_store.h"
#include "chrome/browser/extensions/extension_prefs.h"
#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/prefs/pref_service_mock_builder.h"
#include "chrome/browser/prefs/pref_value_store.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/json_pref_store.h"
#include "testing/gtest/include/gtest/gtest.h"
-TestExtensionPrefs::TestExtensionPrefs() {
+namespace {
+
+// Mock ExtensionPrefs class with artificial clock to guarantee that no two
+// extensions get the same installation time stamp and we can reliably
+// assert the installation order in the tests below.
+class MockExtensionPrefs : public ExtensionPrefs {
+ public:
+ MockExtensionPrefs(PrefService* prefs,
+ const FilePath& root_dir_,
+ ExtensionPrefStore* pref_store)
+ : ExtensionPrefs(prefs, root_dir_, pref_store),
+ currentTime(base::Time::Now()) {}
+ ~MockExtensionPrefs() {}
+
+ protected:
+ mutable base::Time currentTime;
+
+ virtual base::Time GetCurrentTime() const {
+ currentTime += base::TimeDelta::FromSeconds(10);
+ return currentTime;
+ }
+};
+
+} // namespace
+
+TestExtensionPrefs::TestExtensionPrefs() : pref_service_(NULL) {
EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
preferences_file_ = temp_dir_.path().AppendASCII("Preferences");
extensions_dir_ = temp_dir_.path().AppendASCII("Extensions");
@@ -29,6 +57,9 @@ TestExtensionPrefs::TestExtensionPrefs() {
TestExtensionPrefs::~TestExtensionPrefs() {}
void TestExtensionPrefs::RecreateExtensionPrefs() {
+ // We persist and reload the PrefService's PrefStores because this process
+ // deletes all empty dictionaries. The ExtensionPrefs implementation
+ // needs to be able to handle this situation.
if (pref_service_.get()) {
// The PrefService writes its persistent file on the file thread, so we
// need to wait for any pending I/O to complete before creating a new
@@ -39,10 +70,14 @@ void TestExtensionPrefs::RecreateExtensionPrefs() {
file_loop.RunAllPending();
}
- // Create a |PrefService| instance that contains only user defined values.
- pref_service_.reset(PrefService::CreateUserPrefService(preferences_file_));
+ ExtensionPrefStore* pref_store = new ExtensionPrefStore;
+ PrefServiceMockBuilder builder;
+ builder.WithUserFilePrefs(preferences_file_);
+ builder.WithExtensionPrefs(pref_store);
+ pref_service_.reset(builder.Create());
ExtensionPrefs::RegisterUserPrefs(pref_service_.get());
- prefs_.reset(new ExtensionPrefs(pref_service_.get(), temp_dir_.path()));
+ prefs_.reset(new MockExtensionPrefs(pref_service_.get(), temp_dir_.path(),
+ pref_store));
}
scoped_refptr<Extension> TestExtensionPrefs::AddExtension(std::string name) {
diff --git a/chrome/browser/extensions/test_extension_prefs.h b/chrome/browser/extensions/test_extension_prefs.h
index cb723b2..3220d7a 100644
--- a/chrome/browser/extensions/test_extension_prefs.h
+++ b/chrome/browser/extensions/test_extension_prefs.h
@@ -16,7 +16,6 @@ class DictionaryValue;
class ExtensionPrefs;
class PrefService;
-
// This is a test class intended to make it easier to work with ExtensionPrefs
// in tests.
class TestExtensionPrefs {
diff --git a/chrome/browser/extensions/theme_installed_infobar_delegate.cc b/chrome/browser/extensions/theme_installed_infobar_delegate.cc
index 088e732..5f47084 100644
--- a/chrome/browser/extensions/theme_installed_infobar_delegate.cc
+++ b/chrome/browser/extensions/theme_installed_infobar_delegate.cc
@@ -9,8 +9,8 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/common/extensions/extension.h"
@@ -75,7 +75,7 @@ string16 ThemeInstalledInfoBarDelegate::GetButtonLabel(
bool ThemeInstalledInfoBarDelegate::Cancel() {
if (!previous_theme_id_.empty()) {
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
if (service) {
const Extension* previous_theme =
service->GetExtensionById(previous_theme_id_, true);
diff --git a/chrome/browser/extensions/user_script_listener.cc b/chrome/browser/extensions/user_script_listener.cc
index c553b1f..43965f0 100644
--- a/chrome/browser/extensions/user_script_listener.cc
+++ b/chrome/browser/extensions/user_script_listener.cc
@@ -5,8 +5,8 @@
#include "chrome/browser/extensions/user_script_listener.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/global_request_id.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
#include "chrome/common/extensions/extension.h"
@@ -34,7 +34,7 @@ void UserScriptListener::ShutdownMainThread() {
}
bool UserScriptListener::ShouldDelayRequest(
- URLRequest* request,
+ net::URLRequest* request,
const ResourceDispatcherHostRequestInfo& request_info,
const GlobalRequestID& request_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
@@ -136,14 +136,14 @@ void UserScriptListener::Observe(NotificationType type,
case NotificationType::EXTENSION_UNLOADED: {
const Extension* unloaded_extension =
- Details<const Extension>(details).ptr();
+ Details<UnloadedExtensionInfo>(details)->extension;
if (unloaded_extension->content_scripts().empty())
return; // no patterns to delete for this extension.
// Clear all our patterns and reregister all the still-loaded extensions.
URLPatterns new_patterns;
- ExtensionsService* service =
- Source<Profile>(source).ptr()->GetExtensionsService();
+ ExtensionService* service =
+ Source<Profile>(source).ptr()->GetExtensionService();
for (ExtensionList::const_iterator it = service->extensions()->begin();
it != service->extensions()->end(); ++it) {
if (*it != unloaded_extension)
diff --git a/chrome/browser/extensions/user_script_listener_unittest.cc b/chrome/browser/extensions/user_script_listener_unittest.cc
index ec13f9f..cd40fd5 100644
--- a/chrome/browser/extensions/user_script_listener_unittest.cc
+++ b/chrome/browser/extensions/user_script_listener_unittest.cc
@@ -4,7 +4,7 @@
#include "base/message_loop.h"
#include "base/thread.h"
-#include "chrome/browser/extensions/extensions_service_unittest.h"
+#include "chrome/browser/extensions/extension_service_unittest.h"
#include "chrome/browser/extensions/user_script_listener.h"
#include "chrome/browser/renderer_host/global_request_id.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
@@ -90,35 +90,35 @@ ResourceDispatcherHostRequestInfo* CreateRequestInfo(int request_id) {
return new ResourceDispatcherHostRequestInfo(
new DummyResourceHandler(), ChildProcessInfo::RENDER_PROCESS, 0, 0,
request_id, "null", "null", ResourceType::MAIN_FRAME,
- 0, false, false, -1, -1);
+ 0, false, false, false, -1, -1);
}
-// A simple test URLRequestJob. We don't care what it does, only that whether it
-// starts and finishes.
+// A simple test net::URLRequestJob. We don't care what it does, only that
+// whether it starts and finishes.
class SimpleTestJob : public URLRequestTestJob {
public:
- explicit SimpleTestJob(URLRequest* request)
+ explicit SimpleTestJob(net::URLRequest* request)
: URLRequestTestJob(request, test_headers(), kTestData, true) {}
private:
~SimpleTestJob() {}
};
class UserScriptListenerTest
- : public ExtensionsServiceTestBase,
- public URLRequest::Interceptor {
+ : public ExtensionServiceTestBase,
+ public net::URLRequest::Interceptor {
public:
UserScriptListenerTest() {
- URLRequest::RegisterRequestInterceptor(this);
+ net::URLRequest::RegisterRequestInterceptor(this);
}
~UserScriptListenerTest() {
- URLRequest::UnregisterRequestInterceptor(this);
+ net::URLRequest::UnregisterRequestInterceptor(this);
}
virtual void SetUp() {
- ExtensionsServiceTestBase::SetUp();
+ ExtensionServiceTestBase::SetUp();
- InitializeEmptyExtensionsService();
+ InitializeEmptyExtensionService();
service_->Init();
MessageLoop::current()->RunAllPending();
@@ -135,13 +135,13 @@ class UserScriptListenerTest
MessageLoop::current()->RunAllPending();
}
- // URLRequest::Interceptor
- virtual URLRequestJob* MaybeIntercept(URLRequest* request) {
+ // net::URLRequest::Interceptor
+ virtual net::URLRequestJob* MaybeIntercept(net::URLRequest* request) {
return new SimpleTestJob(request);
}
protected:
- TestURLRequest* StartTestRequest(URLRequest::Delegate* delegate,
+ TestURLRequest* StartTestRequest(net::URLRequest::Delegate* delegate,
const std::string& url) {
TestURLRequest* request = new TestURLRequest(GURL(url), delegate);
scoped_ptr<ResourceDispatcherHostRequestInfo> rdh_info(
@@ -164,7 +164,8 @@ class UserScriptListenerTest
void UnloadTestExtension() {
ASSERT_FALSE(service_->extensions()->empty());
- service_->UnloadExtension(service_->extensions()->at(0)->id());
+ service_->UnloadExtension(service_->extensions()->at(0)->id(),
+ UnloadedExtensionInfo::DISABLE);
}
scoped_refptr<UserScriptListener> listener_;
diff --git a/chrome/browser/extensions/user_script_master.cc b/chrome/browser/extensions/user_script_master.cc
index 1712bb6..2af102e 100644
--- a/chrome/browser/extensions/user_script_master.cc
+++ b/chrome/browser/extensions/user_script_master.cc
@@ -15,9 +15,8 @@
#include "base/string_util.h"
#include "base/thread.h"
#include "base/version.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_resource.h"
#include "chrome/common/notification_service.h"
@@ -340,9 +339,9 @@ void UserScriptMaster::Observe(NotificationType type,
case NotificationType::EXTENSION_LOADED: {
// Add any content scripts inside the extension.
const Extension* extension = Details<const Extension>(details).ptr();
- bool incognito_enabled = profile_->GetExtensionsService()->
+ bool incognito_enabled = profile_->GetExtensionService()->
IsIncognitoEnabled(extension);
- bool allow_file_access = profile_->GetExtensionsService()->
+ bool allow_file_access = profile_->GetExtensionService()->
AllowFileAccess(extension);
const UserScriptList& scripts = extension->content_scripts();
for (UserScriptList::const_iterator iter = scripts.begin();
@@ -357,7 +356,8 @@ void UserScriptMaster::Observe(NotificationType type,
}
case NotificationType::EXTENSION_UNLOADED: {
// Remove any content scripts.
- const Extension* extension = Details<const Extension>(details).ptr();
+ const Extension* extension =
+ Details<UnloadedExtensionInfo>(details)->extension;
UserScriptList new_lone_scripts;
for (UserScriptList::iterator iter = lone_scripts_.begin();
iter != lone_scripts_.end(); ++iter) {
@@ -375,9 +375,9 @@ void UserScriptMaster::Observe(NotificationType type,
case NotificationType::EXTENSION_USER_SCRIPTS_UPDATED: {
const Extension* extension = Details<const Extension>(details).ptr();
UserScriptList new_lone_scripts;
- bool incognito_enabled = profile_->GetExtensionsService()->
+ bool incognito_enabled = profile_->GetExtensionService()->
IsIncognitoEnabled(extension);
- bool allow_file_access = profile_->GetExtensionsService()->
+ bool allow_file_access = profile_->GetExtensionService()->
AllowFileAccess(extension);
for (UserScriptList::iterator iter = lone_scripts_.begin();
iter != lone_scripts_.end(); ++iter) {
diff --git a/chrome/browser/extensions/window_open_apitest.cc b/chrome/browser/extensions/window_open_apitest.cc
index 7fe20b9..567ccc7 100644
--- a/chrome/browser/extensions/window_open_apitest.cc
+++ b/chrome/browser/extensions/window_open_apitest.cc
@@ -4,14 +4,14 @@
#include "base/command_line.h"
#include "chrome/browser/extensions/extension_apitest.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/ui_test_utils.h"
#include "net/base/mock_host_resolver.h"
-IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WindowOpen) {
+// Disabled, http://crbug.com/64899.
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_WindowOpen) {
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableExperimentalExtensionApis);
diff --git a/chrome/browser/external_tab_container_win.cc b/chrome/browser/external_tab_container_win.cc
index b7c6596..976d27d 100644
--- a/chrome/browser/external_tab_container_win.cc
+++ b/chrome/browser/external_tab_container_win.cc
@@ -11,6 +11,7 @@
#include "base/debug/trace_event.h"
#include "base/i18n/rtl.h"
#include "base/logging.h"
+#include "base/utf_string_conversions.h"
#include "base/win_util.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/app/chrome_dll_resource.h"
@@ -23,12 +24,13 @@
#include "chrome/browser/history/history_types.h"
#include "chrome/browser/load_notification_details.h"
#include "chrome/browser/page_info_window.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
#include "chrome/browser/tab_contents/provisional_load_details.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/views/browser_dialogs.h"
#include "chrome/browser/views/page_info_bubble_view.h"
#include "chrome/browser/views/tab_contents/render_view_context_menu_views.h"
#include "chrome/browser/views/tab_contents/tab_contents_container.h"
@@ -342,7 +344,7 @@ void ExternalTabContainer::OpenURLFromTab(TabContents* source,
case NEW_WINDOW:
case SAVE_TO_DISK:
if (automation_) {
- automation_->Send(new AutomationMsg_OpenURL(0, tab_handle_,
+ automation_->Send(new AutomationMsg_OpenURL(tab_handle_,
url, referrer,
disposition));
// TODO(ananta)
@@ -372,10 +374,10 @@ void ExternalTabContainer::OpenURLFromTab(TabContents* source,
void ExternalTabContainer::NavigationStateChanged(const TabContents* source,
unsigned changed_flags) {
if (automation_) {
- IPC::NavigationInfo nav_info;
+ NavigationInfo nav_info;
if (InitNavigationInfo(&nav_info, NavigationType::NAV_IGNORE, 0))
automation_->Send(new AutomationMsg_NavigationStateChanged(
- 0, tab_handle_, changed_flags, nav_info));
+ tab_handle_, changed_flags, nav_info));
}
}
@@ -430,14 +432,14 @@ void ExternalTabContainer::AddNewContents(TabContents* source,
uintptr_t cookie = reinterpret_cast<uintptr_t>(new_container.get());
pending_tabs_.Get()[cookie] = new_container;
new_container->set_pending(true);
- IPC::AttachExternalTabParams attach_params_;
+ AttachExternalTabParams attach_params_;
attach_params_.cookie = static_cast<uint64>(cookie);
attach_params_.dimensions = initial_pos;
attach_params_.user_gesture = user_gesture;
attach_params_.disposition = disposition;
attach_params_.profile_name = WideToUTF8(
tab_contents()->profile()->GetPath().DirName().BaseName().value());
- automation_->Send(new AutomationMsg_AttachExternalTab(0,
+ automation_->Send(new AutomationMsg_AttachExternalTab(
tab_handle_, attach_params_));
} else {
NOTREACHED();
@@ -477,7 +479,7 @@ void ExternalTabContainer::CloseContents(TabContents* source) {
automation_->Send(unload_reply_message_);
unload_reply_message_ = NULL;
} else {
- automation_->Send(new AutomationMsg_CloseExternalTab(0, tab_handle_));
+ automation_->Send(new AutomationMsg_CloseExternalTab(tab_handle_));
}
}
@@ -494,7 +496,7 @@ void ExternalTabContainer::UpdateTargetURL(TabContents* source,
if (automation_) {
std::wstring url_string = CA2W(url.spec().c_str());
automation_->Send(
- new AutomationMsg_UpdateTargetUrl(0, tab_handle_, url_string));
+ new AutomationMsg_UpdateTargetUrl(tab_handle_, url_string));
}
}
@@ -509,9 +511,8 @@ void ExternalTabContainer::ForwardMessageToExternalHost(
const std::string& message, const std::string& origin,
const std::string& target) {
if (automation_) {
- automation_->Send(
- new AutomationMsg_ForwardMessageToExternalHost(0, tab_handle_,
- message, origin, target));
+ automation_->Send(new AutomationMsg_ForwardMessageToExternalHost(
+ tab_handle_, message, origin, target));
}
}
@@ -525,7 +526,7 @@ gfx::NativeWindow ExternalTabContainer::GetFrameNativeWindow() {
bool ExternalTabContainer::TakeFocus(bool reverse) {
if (automation_) {
- automation_->Send(new AutomationMsg_TabbedOut(0, tab_handle_,
+ automation_->Send(new AutomationMsg_TabbedOut(tab_handle_,
win_util::IsShiftPressed()));
}
@@ -620,18 +621,18 @@ bool ExternalTabContainer::HandleContextMenu(const ContextMenuParams& params) {
POINT screen_pt = { params.x, params.y };
MapWindowPoints(GetNativeView(), HWND_DESKTOP, &screen_pt, 1);
- IPC::MiniContextMenuParams ipc_params;
- ipc_params.screen_x = screen_pt.x;
- ipc_params.screen_y = screen_pt.y;
- ipc_params.link_url = params.link_url;
- ipc_params.unfiltered_link_url = params.unfiltered_link_url;
- ipc_params.src_url = params.src_url;
- ipc_params.page_url = params.page_url;
- ipc_params.frame_url = params.frame_url;
+ MiniContextMenuParams ipc_params(
+ screen_pt.x,
+ screen_pt.y,
+ params.link_url,
+ params.unfiltered_link_url,
+ params.src_url,
+ params.page_url,
+ params.frame_url);
bool rtl = base::i18n::IsRTL();
automation_->Send(
- new AutomationMsg_ForwardContextMenuToExternalHost(0, tab_handle_,
+ new AutomationMsg_ForwardContextMenuToExternalHost(tab_handle_,
external_context_menu_->GetMenuHandle(),
rtl ? TPM_RIGHTALIGN : TPM_LEFTALIGN, ipc_params));
@@ -702,6 +703,11 @@ void ExternalTabContainer::BeforeUnloadFired(TabContents* tab,
}
}
+void ExternalTabContainer::ShowRepostFormWarningDialog(
+ TabContents* tab_contents) {
+ browser::ShowRepostFormWarningDialog(GetNativeView(), tab_contents);
+}
+
////////////////////////////////////////////////////////////////////////////////
// ExternalTabContainer, NotificationObserver implementation:
@@ -721,7 +727,7 @@ void ExternalTabContainer::Observe(NotificationType type,
if (load != NULL && PageTransition::IsMainFrame(load->origin())) {
TRACE_EVENT_END("ExternalTabContainer::Navigate", 0,
load->url().spec());
- automation_->Send(new AutomationMsg_TabLoaded(0, tab_handle_,
+ automation_->Send(new AutomationMsg_TabLoaded(tab_handle_,
load->url()));
}
break;
@@ -738,18 +744,18 @@ void ExternalTabContainer::Observe(NotificationType type,
if (commit->http_status_code >= kHttpClientErrorStart &&
commit->http_status_code <= kHttpServerErrorEnd) {
automation_->Send(new AutomationMsg_NavigationFailed(
- 0, tab_handle_, commit->http_status_code, commit->entry->url()));
+ tab_handle_, commit->http_status_code, commit->entry->url()));
ignore_next_load_notification_ = true;
} else {
- IPC::NavigationInfo navigation_info;
+ NavigationInfo navigation_info;
// When the previous entry index is invalid, it will be -1, which
// will still make the computation come out right (navigating to the
// 0th entry will be +1).
if (InitNavigationInfo(&navigation_info, commit->type,
commit->previous_entry_index -
tab_contents_->controller().last_committed_entry_index()))
- automation_->Send(new AutomationMsg_DidNavigate(0, tab_handle_,
+ automation_->Send(new AutomationMsg_DidNavigate(tab_handle_,
navigation_info));
}
break;
@@ -758,7 +764,7 @@ void ExternalTabContainer::Observe(NotificationType type,
const ProvisionalLoadDetails* load_details =
Details<ProvisionalLoadDetails>(details).ptr();
automation_->Send(new AutomationMsg_NavigationFailed(
- 0, tab_handle_, load_details->error_code(), load_details->url()));
+ tab_handle_, load_details->error_code(), load_details->url()));
ignore_next_load_notification_ = true;
break;
@@ -853,11 +859,11 @@ bool ExternalTabContainer::ProcessUnhandledKeyStroke(HWND window,
msg.message = message;
msg.wParam = wparam;
msg.lParam = lparam;
- automation_->Send(new AutomationMsg_HandleAccelerator(0, tab_handle_, msg));
+ automation_->Send(new AutomationMsg_HandleAccelerator(tab_handle_, msg));
return true;
}
-bool ExternalTabContainer::InitNavigationInfo(IPC::NavigationInfo* nav_info,
+bool ExternalTabContainer::InitNavigationInfo(NavigationInfo* nav_info,
NavigationType::Type nav_type,
int relative_offset) {
DCHECK(nav_info);
@@ -983,7 +989,7 @@ void ExternalTabContainer::Navigate(const GURL& url, const GURL& referrer) {
bool ExternalTabContainer::OnGoToEntryOffset(int offset) {
if (load_requests_via_automation_) {
automation_->Send(new AutomationMsg_RequestGoToHistoryEntryOffset(
- 0, tab_handle_, offset));
+ tab_handle_, offset));
return false;
}
diff --git a/chrome/browser/external_tab_container_win.h b/chrome/browser/external_tab_container_win.h
index cc0e35c..f08f364 100644
--- a/chrome/browser/external_tab_container_win.h
+++ b/chrome/browser/external_tab_container_win.h
@@ -29,15 +29,12 @@ class AutomationProvider;
class Profile;
class TabContentsContainer;
class RenderViewContextMenuViews;
+struct NavigationInfo;
namespace app {
class ViewProp;
}
-namespace IPC {
-struct NavigationInfo;
-}
-
// This class serves as the container window for an external tab.
// An external tab is a Chrome tab that is meant to displayed in an
// external process. This class provides the FocusManger needed by the
@@ -173,6 +170,8 @@ class ExternalTabContainer : public TabContentsDelegate,
bool proceed,
bool* proceed_to_fire_unload);
+ void ShowRepostFormWarningDialog(TabContents* tab_contents);
+
// Overriden from TabContentsDelegate::AutomationResourceRoutingDelegate
virtual void RegisterRenderViewHost(RenderViewHost* render_view_host);
virtual void UnregisterRenderViewHost(RenderViewHost* render_view_host);
@@ -223,7 +222,7 @@ class ExternalTabContainer : public TabContentsDelegate,
virtual void OnDestroy();
virtual void OnFinalMessage(HWND window);
- bool InitNavigationInfo(IPC::NavigationInfo* nav_info,
+ bool InitNavigationInfo(NavigationInfo* nav_info,
NavigationType::Type nav_type,
int relative_offset);
void Navigate(const GURL& url, const GURL& referrer);
diff --git a/chrome/browser/fav_icon_helper.cc b/chrome/browser/fav_icon_helper.cc
index a6d2e1b..544b4e8 100644
--- a/chrome/browser/fav_icon_helper.cc
+++ b/chrome/browser/fav_icon_helper.cc
@@ -10,7 +10,8 @@
#include "base/callback.h"
#include "base/ref_counted_memory.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
@@ -78,7 +79,7 @@ void FavIconHelper::SetFavIcon(
(image.width() == kFavIconSize && image.height() == kFavIconSize)
? image : ConvertToFavIconSize(image);
- if (GetFaviconService() && !profile()->IsOffTheRecord()) {
+ if (GetFaviconService() && ShouldSaveFavicon(url)) {
std::vector<unsigned char> image_data;
gfx::PNGCodec::EncodeBGRASkBitmap(sized_image, false, &image_data);
GetFaviconService()->SetFavicon(url, image_url, image_data);
@@ -296,3 +297,12 @@ SkBitmap FavIconHelper::ConvertToFavIconSize(const SkBitmap& image) {
}
return image;
}
+
+bool FavIconHelper::ShouldSaveFavicon(const GURL& url) {
+ if (!profile()->IsOffTheRecord())
+ return true;
+
+ // Otherwise store the favicon if the page is bookmarked.
+ BookmarkModel* bookmark_model = profile()->GetBookmarkModel();
+ return bookmark_model && bookmark_model->IsBookmarked(url);
+}
diff --git a/chrome/browser/fav_icon_helper.h b/chrome/browser/fav_icon_helper.h
index 8eb7f17..a64eba2 100644
--- a/chrome/browser/fav_icon_helper.h
+++ b/chrome/browser/fav_icon_helper.h
@@ -156,6 +156,9 @@ class FavIconHelper : public RenderViewHostDelegate::FavIcon {
// wide. Does nothing if the image is empty.
SkBitmap ConvertToFavIconSize(const SkBitmap& image);
+ // Returns true if the favicon should be saved.
+ bool ShouldSaveFavicon(const GURL& url);
+
// Hosting TabContents. We callback into this when done.
TabContents* tab_contents_;
diff --git a/chrome/browser/favicon_service.cc b/chrome/browser/favicon_service.cc
index f30381a..b476a41 100644
--- a/chrome/browser/favicon_service.cc
+++ b/chrome/browser/favicon_service.cc
@@ -4,11 +4,10 @@
#include "chrome/browser/favicon_service.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/dom_ui/dom_ui_factory.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/history/history_backend.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/url_constants.h"
FaviconService::FaviconService(Profile* profile) : profile_(profile) {
diff --git a/chrome/browser/file_path_watcher.cc b/chrome/browser/file_path_watcher.cc
deleted file mode 100644
index 19aff7a..0000000
--- a/chrome/browser/file_path_watcher.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// 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.
-
-// Cross platform methods for FilePathWatcher. See the various platform
-// specific implementaiton files, too.
-
-#include "chrome/browser/file_path_watcher.h"
-
-FilePathWatcher::~FilePathWatcher() {
- impl_->Cancel();
-}
-
-bool FilePathWatcher::Watch(const FilePath& path,
- Delegate* delegate) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- DCHECK(path.IsAbsolute());
- return impl_->Watch(path, delegate);
-}
diff --git a/chrome/browser/file_path_watcher.h b/chrome/browser/file_path_watcher.h
deleted file mode 100644
index 51d25cf..0000000
--- a/chrome/browser/file_path_watcher.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// 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.
-
-// This module provides a way to monitor a file or directory for changes.
-
-#ifndef CHROME_BROWSER_FILE_PATH_WATCHER_H_
-#define CHROME_BROWSER_FILE_PATH_WATCHER_H_
-#pragma once
-
-#include "base/basictypes.h"
-#include "base/file_path.h"
-#include "base/ref_counted.h"
-#include "chrome/browser/browser_thread.h"
-
-// This class lets you register interest in changes on a FilePath.
-// The delegate will get called whenever the file or directory referenced by the
-// FilePath is changed, including created or deleted. Due to limitations in the
-// underlying OS APIs, spurious notifications might occur that don't relate to
-// an actual change to the watch target.
-class FilePathWatcher {
- public:
- // Declares the callback client code implements to receive notifications. Note
- // that implementations of this interface should not keep a reference to the
- // corresponding FileWatcher object to prevent a reference cycle.
- class Delegate : public base::RefCountedThreadSafe<Delegate> {
- public:
- virtual ~Delegate() {}
- virtual void OnFilePathChanged(const FilePath& path) = 0;
- // Called when platform specific code detected an error. The watcher will
- // not call OnFilePathChanged for future changes.
- virtual void OnError() {}
- };
-
- FilePathWatcher();
- ~FilePathWatcher();
-
- // Register interest in any changes on |path|. OnPathChanged will be called
- // back for each change. Returns true on success.
- bool Watch(const FilePath& path, Delegate* delegate) WARN_UNUSED_RESULT;
-
- // Used internally to encapsulate different members on different platforms.
- class PlatformDelegate
- : public base::RefCountedThreadSafe<PlatformDelegate,
- BrowserThread::DeleteOnFileThread> {
- public:
- virtual ~PlatformDelegate() {}
-
- // Start watching for the given |path| and notify |delegate| about changes.
- virtual bool Watch(const FilePath& path, Delegate* delegate)
- WARN_UNUSED_RESULT = 0;
-
- // Stop watching. This is called from FilePathWatcher's dtor in order to
- // allow to shut down properly while the object is still alive.
- virtual void Cancel() {}
- };
-
- private:
- scoped_refptr<PlatformDelegate> impl_;
-
- DISALLOW_COPY_AND_ASSIGN(FilePathWatcher);
-};
-
-#endif // CHROME_BROWSER_FILE_PATH_WATCHER_H_
diff --git a/chrome/browser/file_path_watcher/file_path_watcher.cc b/chrome/browser/file_path_watcher/file_path_watcher.cc
new file mode 100644
index 0000000..c516172
--- /dev/null
+++ b/chrome/browser/file_path_watcher/file_path_watcher.cc
@@ -0,0 +1,19 @@
+// 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.
+
+// Cross platform methods for FilePathWatcher. See the various platform
+// specific implementation files, too.
+
+#include "chrome/browser/file_path_watcher/file_path_watcher.h"
+
+FilePathWatcher::~FilePathWatcher() {
+ impl_->Cancel();
+}
+
+bool FilePathWatcher::Watch(const FilePath& path,
+ Delegate* delegate) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK(path.IsAbsolute());
+ return impl_->Watch(path, delegate);
+}
diff --git a/chrome/browser/file_path_watcher/file_path_watcher.h b/chrome/browser/file_path_watcher/file_path_watcher.h
new file mode 100644
index 0000000..d80bfc1
--- /dev/null
+++ b/chrome/browser/file_path_watcher/file_path_watcher.h
@@ -0,0 +1,64 @@
+// 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.
+
+// This module provides a way to monitor a file or directory for changes.
+
+#ifndef CHROME_BROWSER_FILE_PATH_WATCHER_FILE_PATH_WATCHER_H_
+#define CHROME_BROWSER_FILE_PATH_WATCHER_FILE_PATH_WATCHER_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/ref_counted.h"
+#include "chrome/browser/browser_thread.h"
+
+// This class lets you register interest in changes on a FilePath.
+// The delegate will get called whenever the file or directory referenced by the
+// FilePath is changed, including created or deleted. Due to limitations in the
+// underlying OS APIs, spurious notifications might occur that don't relate to
+// an actual change to the watch target.
+class FilePathWatcher {
+ public:
+ // Declares the callback client code implements to receive notifications. Note
+ // that implementations of this interface should not keep a reference to the
+ // corresponding FileWatcher object to prevent a reference cycle.
+ class Delegate : public base::RefCountedThreadSafe<Delegate> {
+ public:
+ virtual ~Delegate() {}
+ virtual void OnFilePathChanged(const FilePath& path) = 0;
+ // Called when platform specific code detected an error. The watcher will
+ // not call OnFilePathChanged for future changes.
+ virtual void OnError() {}
+ };
+
+ FilePathWatcher();
+ ~FilePathWatcher();
+
+ // Register interest in any changes on |path|. OnPathChanged will be called
+ // back for each change. Returns true on success.
+ bool Watch(const FilePath& path, Delegate* delegate) WARN_UNUSED_RESULT;
+
+ // Used internally to encapsulate different members on different platforms.
+ class PlatformDelegate
+ : public base::RefCountedThreadSafe<PlatformDelegate,
+ BrowserThread::DeleteOnFileThread> {
+ public:
+ virtual ~PlatformDelegate() {}
+
+ // Start watching for the given |path| and notify |delegate| about changes.
+ virtual bool Watch(const FilePath& path, Delegate* delegate)
+ WARN_UNUSED_RESULT = 0;
+
+ // Stop watching. This is called from FilePathWatcher's dtor in order to
+ // allow to shut down properly while the object is still alive.
+ virtual void Cancel() {}
+ };
+
+ private:
+ scoped_refptr<PlatformDelegate> impl_;
+
+ DISALLOW_COPY_AND_ASSIGN(FilePathWatcher);
+};
+
+#endif // CHROME_BROWSER_FILE_PATH_WATCHER_FILE_PATH_WATCHER_H_
diff --git a/chrome/browser/file_path_watcher/file_path_watcher_browsertest.cc b/chrome/browser/file_path_watcher/file_path_watcher_browsertest.cc
new file mode 100644
index 0000000..9a8f29e
--- /dev/null
+++ b/chrome/browser/file_path_watcher/file_path_watcher_browsertest.cc
@@ -0,0 +1,455 @@
+// 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.
+
+#include "chrome/browser/file_path_watcher/file_path_watcher.h"
+
+#include <set>
+
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
+#include "base/path_service.h"
+#include "base/platform_thread.h"
+#include "base/scoped_temp_dir.h"
+#include "base/string_util.h"
+#include "base/stl_util-inl.h"
+#include "base/waitable_event.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_MACOSX)
+// TODO(mnissler): There are flakes on Mac (http://crbug.com/54822) at least for
+// FilePathWatcherTest.MultipleWatchersSingleFile.
+#define MAYBE(name) FLAKY_ ## name
+#else
+#define MAYBE(name) name
+#endif
+
+namespace {
+
+class TestDelegate;
+
+// Aggregates notifications from the test delegates and breaks the message loop
+// the test thread is waiting on once they all came in.
+class NotificationCollector
+ : public base::RefCountedThreadSafe<NotificationCollector> {
+ public:
+ NotificationCollector()
+ : loop_(base::MessageLoopProxy::CreateForCurrentThread()) {}
+
+ // Called from the file thread by the delegates.
+ void OnChange(TestDelegate* delegate) {
+ loop_->PostTask(FROM_HERE,
+ NewRunnableMethod(this,
+ &NotificationCollector::RecordChange,
+ make_scoped_refptr(delegate)));
+ }
+
+ void Register(TestDelegate* delegate) {
+ delegates_.insert(delegate);
+ }
+
+ void Reset() {
+ signaled_.clear();
+ }
+
+ private:
+ void RecordChange(TestDelegate* delegate) {
+ ASSERT_TRUE(loop_->BelongsToCurrentThread());
+ ASSERT_TRUE(delegates_.count(delegate));
+ signaled_.insert(delegate);
+
+ // Check whether all delegates have been signaled.
+ if (signaled_ == delegates_)
+ loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask());
+ }
+
+ // Set of registered delegates.
+ std::set<TestDelegate*> delegates_;
+
+ // Set of signaled delegates.
+ std::set<TestDelegate*> signaled_;
+
+ // The loop we should break after all delegates signaled.
+ scoped_refptr<base::MessageLoopProxy> loop_;
+};
+
+// A mock FilePathWatcher::Delegate for testing. I'd rather use gmock, but it's
+// not thread safe for setting expectations, so the test code couldn't safely
+// reset expectations while the file watcher is running. In order to allow this,
+// we keep simple thread safe status flags in TestDelegate.
+class TestDelegate : public FilePathWatcher::Delegate {
+ public:
+ // The message loop specified by |loop| will be quit if a notification is
+ // received while the delegate is |armed_|. Note that the testing code must
+ // guarantee |loop| outlives the file thread on which OnFilePathChanged runs.
+ explicit TestDelegate(NotificationCollector* collector)
+ : collector_(collector) {
+ collector_->Register(this);
+ }
+
+ virtual void OnFilePathChanged(const FilePath&) {
+ collector_->OnChange(this);
+ }
+
+ private:
+ scoped_refptr<NotificationCollector> collector_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestDelegate);
+};
+
+// A helper class for setting up watches on the file thread.
+class SetupWatchTask : public Task {
+ public:
+ SetupWatchTask(const FilePath& target,
+ FilePathWatcher* watcher,
+ FilePathWatcher::Delegate* delegate,
+ bool* result,
+ base::WaitableEvent* completion)
+ : target_(target),
+ watcher_(watcher),
+ delegate_(delegate),
+ result_(result),
+ completion_(completion) {}
+
+ void Run() {
+ *result_ = watcher_->Watch(target_, delegate_);
+ completion_->Signal();
+ }
+
+ private:
+ const FilePath target_;
+ FilePathWatcher* watcher_;
+ FilePathWatcher::Delegate* delegate_;
+ bool* result_;
+ base::WaitableEvent* completion_;
+
+ DISALLOW_COPY_AND_ASSIGN(SetupWatchTask);
+};
+
+class FilePathWatcherTest : public testing::Test {
+ public:
+ // Implementation of FilePathWatcher on Mac requires UI loop.
+ FilePathWatcherTest()
+ : loop_(MessageLoop::TYPE_UI),
+ ui_thread_(BrowserThread::UI, &loop_) {
+ }
+
+ protected:
+ virtual void SetUp() {
+ // Create a separate file thread in order to test proper thread usage.
+ file_thread_.reset(new BrowserThread(BrowserThread::FILE));
+ file_thread_->Start();
+ temp_dir_.reset(new ScopedTempDir);
+ ASSERT_TRUE(temp_dir_->CreateUniqueTempDir());
+ collector_ = new NotificationCollector();
+ }
+
+ virtual void TearDown() {
+ loop_.RunAllPending();
+ file_thread_.reset();
+ }
+
+ FilePath test_file() {
+ return temp_dir_->path().AppendASCII("FilePathWatcherTest");
+ }
+
+ // Write |content| to |file|. Returns true on success.
+ bool WriteFile(const FilePath& file, const std::string& content) {
+ int write_size = file_util::WriteFile(file, content.c_str(),
+ content.length());
+ return write_size == static_cast<int>(content.length());
+ }
+
+ void SetupWatch(const FilePath& target,
+ FilePathWatcher* watcher,
+ FilePathWatcher::Delegate* delegate) {
+ base::WaitableEvent completion(false, false);
+ bool result;
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ new SetupWatchTask(target, watcher, delegate, &result, &completion));
+ completion.Wait();
+ ASSERT_TRUE(result);
+ }
+
+ void WaitForEvents() {
+ collector_->Reset();
+ loop_.Run();
+ }
+
+ NotificationCollector* collector() { return collector_.get(); }
+
+ MessageLoop loop_;
+ BrowserThread ui_thread_;
+ scoped_ptr<BrowserThread> file_thread_;
+ scoped_ptr<ScopedTempDir> temp_dir_;
+ scoped_refptr<NotificationCollector> collector_;
+};
+
+// Basic test: Create the file and verify that we notice.
+TEST_F(FilePathWatcherTest, MAYBE(NewFile)) {
+ FilePathWatcher watcher;
+ scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+ SetupWatch(test_file(), &watcher, delegate.get());
+
+ ASSERT_TRUE(WriteFile(test_file(), "content"));
+ WaitForEvents();
+}
+
+// Verify that modifying the file is caught.
+TEST_F(FilePathWatcherTest, MAYBE(ModifiedFile)) {
+ ASSERT_TRUE(WriteFile(test_file(), "content"));
+
+ FilePathWatcher watcher;
+ scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+ SetupWatch(test_file(), &watcher, delegate.get());
+
+ // Now make sure we get notified if the file is modified.
+ ASSERT_TRUE(WriteFile(test_file(), "new content"));
+ WaitForEvents();
+}
+
+// Verify that moving the file into place is caught.
+TEST_F(FilePathWatcherTest, MAYBE(MovedFile)) {
+ FilePath source_file(temp_dir_->path().AppendASCII("source"));
+ ASSERT_TRUE(WriteFile(source_file, "content"));
+
+ FilePathWatcher watcher;
+ scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+ SetupWatch(test_file(), &watcher, delegate.get());
+
+ // Now make sure we get notified if the file is modified.
+ ASSERT_TRUE(file_util::Move(source_file, test_file()));
+ WaitForEvents();
+}
+
+TEST_F(FilePathWatcherTest, MAYBE(DeletedFile)) {
+ ASSERT_TRUE(WriteFile(test_file(), "content"));
+
+ FilePathWatcher watcher;
+ scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+ SetupWatch(test_file(), &watcher, delegate.get());
+
+ // Now make sure we get notified if the file is deleted.
+ file_util::Delete(test_file(), false);
+ WaitForEvents();
+}
+
+// Used by the DeleteDuringNotify test below.
+// Deletes the FilePathWatcher when it's notified.
+class Deleter : public FilePathWatcher::Delegate {
+ public:
+ Deleter(FilePathWatcher* watcher, MessageLoop* loop)
+ : watcher_(watcher),
+ loop_(loop) {
+ }
+
+ virtual void OnFilePathChanged(const FilePath& path) {
+ watcher_.reset(NULL);
+ loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask());
+ }
+
+ scoped_ptr<FilePathWatcher> watcher_;
+ MessageLoop* loop_;
+};
+
+// Verify that deleting a watcher during the callback doesn't crash.
+TEST_F(FilePathWatcherTest, DeleteDuringNotify) {
+ FilePathWatcher* watcher = new FilePathWatcher;
+ // Takes ownership of watcher.
+ scoped_refptr<Deleter> deleter(new Deleter(watcher, &loop_));
+ SetupWatch(test_file(), watcher, deleter.get());
+
+ ASSERT_TRUE(WriteFile(test_file(), "content"));
+ WaitForEvents();
+
+ // We win if we haven't crashed yet.
+ // Might as well double-check it got deleted, too.
+ ASSERT_TRUE(deleter->watcher_.get() == NULL);
+}
+
+// Verify that deleting the watcher works even if there is a pending
+// notification.
+TEST_F(FilePathWatcherTest, DestroyWithPendingNotification) {
+ scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+ FilePathWatcher* watcher = new FilePathWatcher;
+ SetupWatch(test_file(), watcher, delegate.get());
+ ASSERT_TRUE(WriteFile(test_file(), "content"));
+ BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, watcher);
+}
+
+TEST_F(FilePathWatcherTest, MAYBE(MultipleWatchersSingleFile)) {
+ FilePathWatcher watcher1, watcher2;
+ scoped_refptr<TestDelegate> delegate1(new TestDelegate(collector()));
+ scoped_refptr<TestDelegate> delegate2(new TestDelegate(collector()));
+ SetupWatch(test_file(), &watcher1, delegate1.get());
+ SetupWatch(test_file(), &watcher2, delegate2.get());
+
+ ASSERT_TRUE(WriteFile(test_file(), "content"));
+ WaitForEvents();
+}
+
+// Verify that watching a file whose parent directory doesn't exist yet works if
+// the directory and file are created eventually.
+TEST_F(FilePathWatcherTest, NonExistentDirectory) {
+ FilePathWatcher watcher;
+ FilePath dir(temp_dir_->path().AppendASCII("dir"));
+ FilePath file(dir.AppendASCII("file"));
+ scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+ SetupWatch(file, &watcher, delegate.get());
+
+ ASSERT_TRUE(file_util::CreateDirectory(dir));
+
+ ASSERT_TRUE(WriteFile(file, "content"));
+ VLOG(1) << "Waiting for file creation";
+ WaitForEvents();
+
+ ASSERT_TRUE(WriteFile(file, "content v2"));
+ VLOG(1) << "Waiting for file change";
+ WaitForEvents();
+
+ ASSERT_TRUE(file_util::Delete(file, false));
+ VLOG(1) << "Waiting for file deletion";
+ WaitForEvents();
+}
+
+// Exercises watch reconfiguration for the case that directories on the path
+// are rapidly created.
+TEST_F(FilePathWatcherTest, DirectoryChain) {
+ FilePath path(temp_dir_->path());
+ std::vector<std::string> dir_names;
+ for (int i = 0; i < 20; i++) {
+ std::string dir(StringPrintf("d%d", i));
+ dir_names.push_back(dir);
+ path = path.AppendASCII(dir);
+ }
+
+ FilePathWatcher watcher;
+ FilePath file(path.AppendASCII("file"));
+ scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+ SetupWatch(file, &watcher, delegate.get());
+
+ FilePath sub_path(temp_dir_->path());
+ for (std::vector<std::string>::const_iterator d(dir_names.begin());
+ d != dir_names.end(); ++d) {
+ sub_path = sub_path.AppendASCII(*d);
+ ASSERT_TRUE(file_util::CreateDirectory(sub_path));
+ }
+ ASSERT_TRUE(WriteFile(file, "content"));
+ VLOG(1) << "Waiting for file creation";
+ WaitForEvents();
+
+ ASSERT_TRUE(WriteFile(file, "content v2"));
+ VLOG(1) << "Waiting for file modification";
+ WaitForEvents();
+}
+
+TEST_F(FilePathWatcherTest, DisappearingDirectory) {
+ FilePathWatcher watcher;
+ FilePath dir(temp_dir_->path().AppendASCII("dir"));
+ FilePath file(dir.AppendASCII("file"));
+ ASSERT_TRUE(file_util::CreateDirectory(dir));
+ ASSERT_TRUE(WriteFile(file, "content"));
+ scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+ SetupWatch(file, &watcher, delegate.get());
+
+ ASSERT_TRUE(file_util::Delete(dir, true));
+ WaitForEvents();
+}
+
+// Tests that a file that is deleted and reappears is tracked correctly.
+TEST_F(FilePathWatcherTest, DeleteAndRecreate) {
+ ASSERT_TRUE(WriteFile(test_file(), "content"));
+ FilePathWatcher watcher;
+ scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+ SetupWatch(test_file(), &watcher, delegate.get());
+
+ ASSERT_TRUE(file_util::Delete(test_file(), false));
+ VLOG(1) << "Waiting for file deletion";
+ WaitForEvents();
+
+ ASSERT_TRUE(WriteFile(test_file(), "content"));
+ VLOG(1) << "Waiting for file creation";
+ WaitForEvents();
+}
+
+TEST_F(FilePathWatcherTest, WatchDirectory) {
+ FilePathWatcher watcher;
+ FilePath dir(temp_dir_->path().AppendASCII("dir"));
+ FilePath file1(dir.AppendASCII("file1"));
+ FilePath file2(dir.AppendASCII("file2"));
+ scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
+ SetupWatch(dir, &watcher, delegate.get());
+
+ ASSERT_TRUE(file_util::CreateDirectory(dir));
+ VLOG(1) << "Waiting for directory creation";
+ WaitForEvents();
+
+ ASSERT_TRUE(WriteFile(file1, "content"));
+ VLOG(1) << "Waiting for file1 creation";
+ WaitForEvents();
+
+ ASSERT_TRUE(WriteFile(file1, "content v2"));
+ VLOG(1) << "Waiting for file1 modification";
+ WaitForEvents();
+
+ ASSERT_TRUE(file_util::Delete(file1, false));
+ VLOG(1) << "Waiting for file1 deletion";
+ WaitForEvents();
+
+ ASSERT_TRUE(WriteFile(file2, "content"));
+ VLOG(1) << "Waiting for file2 creation";
+ WaitForEvents();
+}
+
+TEST_F(FilePathWatcherTest, MoveParent) {
+ FilePathWatcher file_watcher;
+ FilePathWatcher subdir_watcher;
+ FilePath dir(temp_dir_->path().AppendASCII("dir"));
+ FilePath dest(temp_dir_->path().AppendASCII("dest"));
+ FilePath subdir(dir.AppendASCII("subdir"));
+ FilePath file(subdir.AppendASCII("file"));
+ scoped_refptr<TestDelegate> file_delegate(new TestDelegate(collector()));
+ SetupWatch(file, &file_watcher, file_delegate.get());
+ scoped_refptr<TestDelegate> subdir_delegate(new TestDelegate(collector()));
+ SetupWatch(subdir, &subdir_watcher, subdir_delegate.get());
+
+ // Setup a directory hierarchy.
+ ASSERT_TRUE(file_util::CreateDirectory(subdir));
+ ASSERT_TRUE(WriteFile(file, "content"));
+ VLOG(1) << "Waiting for file creation";
+ WaitForEvents();
+
+ // Move the parent directory.
+ file_util::Move(dir, dest);
+ VLOG(1) << "Waiting for directory move";
+ WaitForEvents();
+}
+
+TEST_F(FilePathWatcherTest, MoveChild) {
+ FilePathWatcher file_watcher;
+ FilePathWatcher subdir_watcher;
+ FilePath source_dir(temp_dir_->path().AppendASCII("source"));
+ FilePath source_subdir(source_dir.AppendASCII("subdir"));
+ FilePath source_file(source_subdir.AppendASCII("file"));
+ FilePath dest_dir(temp_dir_->path().AppendASCII("dest"));
+ FilePath dest_subdir(dest_dir.AppendASCII("subdir"));
+ FilePath dest_file(dest_subdir.AppendASCII("file"));
+
+ // Setup a directory hierarchy.
+ ASSERT_TRUE(file_util::CreateDirectory(source_subdir));
+ ASSERT_TRUE(WriteFile(source_file, "content"));
+
+ scoped_refptr<TestDelegate> file_delegate(new TestDelegate(collector()));
+ SetupWatch(dest_file, &file_watcher, file_delegate.get());
+ scoped_refptr<TestDelegate> subdir_delegate(new TestDelegate(collector()));
+ SetupWatch(dest_subdir, &subdir_watcher, subdir_delegate.get());
+
+ // Move the directory into place, s.t. the watched file appears.
+ ASSERT_TRUE(file_util::Move(source_dir, dest_dir));
+ WaitForEvents();
+}
+
+} // namespace
diff --git a/chrome/browser/file_path_watcher/file_path_watcher_inotify.cc b/chrome/browser/file_path_watcher/file_path_watcher_inotify.cc
new file mode 100644
index 0000000..c65b22d
--- /dev/null
+++ b/chrome/browser/file_path_watcher/file_path_watcher_inotify.cc
@@ -0,0 +1,412 @@
+// 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.
+
+#include "chrome/browser/file_path_watcher/file_path_watcher.h"
+
+#include <errno.h>
+#include <string.h>
+#include <sys/inotify.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "base/eintr_wrapper.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/hash_tables.h"
+#include "base/lazy_instance.h"
+#include "base/lock.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/scoped_ptr.h"
+#include "base/task.h"
+#include "base/thread.h"
+
+namespace {
+
+class FilePathWatcherImpl;
+
+// Singleton to manage all inotify watches.
+// TODO(tony): It would be nice if this wasn't a singleton.
+// http://crbug.com/38174
+class InotifyReader {
+ public:
+ typedef int Watch; // Watch descriptor used by AddWatch and RemoveWatch.
+ static const Watch kInvalidWatch = -1;
+
+ // Watch directory |path| for changes. |watcher| will be notified on each
+ // change. Returns kInvalidWatch on failure.
+ Watch AddWatch(const FilePath& path, FilePathWatcherImpl* watcher);
+
+ // Remove |watch|. Returns true on success.
+ bool RemoveWatch(Watch watch, FilePathWatcherImpl* watcher);
+
+ // Callback for InotifyReaderTask.
+ void OnInotifyEvent(const inotify_event* event);
+
+ private:
+ friend struct ::base::DefaultLazyInstanceTraits<InotifyReader>;
+
+ typedef std::set<FilePathWatcherImpl*> WatcherSet;
+
+ InotifyReader();
+ ~InotifyReader();
+
+ // We keep track of which delegates want to be notified on which watches.
+ base::hash_map<Watch, WatcherSet> watchers_;
+
+ // Lock to protect watchers_.
+ Lock lock_;
+
+ // Separate thread on which we run blocking read for inotify events.
+ base::Thread thread_;
+
+ // File descriptor returned by inotify_init.
+ const int inotify_fd_;
+
+ // Use self-pipe trick to unblock select during shutdown.
+ int shutdown_pipe_[2];
+
+ // Flag set to true when startup was successful.
+ bool valid_;
+
+ DISALLOW_COPY_AND_ASSIGN(InotifyReader);
+};
+
+class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate {
+ public:
+ FilePathWatcherImpl();
+ virtual ~FilePathWatcherImpl() {}
+
+ // Called for each event coming from the watch. |fired_watch| identifies the
+ // watch that fired, |child| indicates what has changed, and is relative to
+ // the currently watched path for |fired_watch|. The flag |created| is true if
+ // the object appears, and |is_directory| is set when the event refers to a
+ // directory.
+ void OnFilePathChanged(InotifyReader::Watch fired_watch,
+ const FilePath::StringType& child,
+ bool created,
+ bool is_directory);
+
+ // Start watching |path| for changes and notify |delegate| on each change.
+ // Returns true if watch for |path| has been added successfully.
+ virtual bool Watch(const FilePath& path, FilePathWatcher::Delegate* delegate);
+
+ // Cancel the watch. This unregisters the instance with InotifyReader.
+ virtual void Cancel();
+
+ private:
+ // Inotify watches are installed for all directory components of |target_|. A
+ // WatchEntry instance holds the watch descriptor for a component and the
+ // subdirectory for that identifies the next component.
+ struct WatchEntry {
+ WatchEntry(InotifyReader::Watch watch, const FilePath::StringType& subdir)
+ : watch_(watch),
+ subdir_(subdir) {}
+
+ InotifyReader::Watch watch_;
+ FilePath::StringType subdir_;
+ };
+ typedef std::vector<WatchEntry> WatchVector;
+
+ // Reconfigure to watch for the most specific parent directory of |target_|
+ // that exists. Updates |watched_path_|. Returns true on success.
+ bool UpdateWatches() WARN_UNUSED_RESULT;
+
+ // Delegate to notify upon changes.
+ scoped_refptr<FilePathWatcher::Delegate> delegate_;
+
+ // The file or directory we're supposed to watch.
+ FilePath target_;
+
+ // The vector of watches and next component names for all path components,
+ // starting at the root directory. The last entry corresponds to the watch for
+ // |target_| and always stores an empty next component name in |subdir_|.
+ WatchVector watches_;
+
+ DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl);
+};
+
+class InotifyReaderTask : public Task {
+ public:
+ InotifyReaderTask(InotifyReader* reader, int inotify_fd, int shutdown_fd)
+ : reader_(reader),
+ inotify_fd_(inotify_fd),
+ shutdown_fd_(shutdown_fd) {
+ }
+
+ virtual void Run() {
+ while (true) {
+ fd_set rfds;
+ FD_ZERO(&rfds);
+ FD_SET(inotify_fd_, &rfds);
+ FD_SET(shutdown_fd_, &rfds);
+
+ // Wait until some inotify events are available.
+ int select_result =
+ HANDLE_EINTR(select(std::max(inotify_fd_, shutdown_fd_) + 1,
+ &rfds, NULL, NULL, NULL));
+ if (select_result < 0) {
+ DPLOG(WARNING) << "select failed";
+ return;
+ }
+
+ if (FD_ISSET(shutdown_fd_, &rfds))
+ return;
+
+ // Adjust buffer size to current event queue size.
+ int buffer_size;
+ int ioctl_result = HANDLE_EINTR(ioctl(inotify_fd_, FIONREAD,
+ &buffer_size));
+
+ if (ioctl_result != 0) {
+ DPLOG(WARNING) << "ioctl failed";
+ return;
+ }
+
+ std::vector<char> buffer(buffer_size);
+
+ ssize_t bytes_read = HANDLE_EINTR(read(inotify_fd_, &buffer[0],
+ buffer_size));
+
+ if (bytes_read < 0) {
+ DPLOG(WARNING) << "read from inotify fd failed";
+ return;
+ }
+
+ ssize_t i = 0;
+ while (i < bytes_read) {
+ inotify_event* event = reinterpret_cast<inotify_event*>(&buffer[i]);
+ size_t event_size = sizeof(inotify_event) + event->len;
+ DCHECK(i + event_size <= static_cast<size_t>(bytes_read));
+ reader_->OnInotifyEvent(event);
+ i += event_size;
+ }
+ }
+ }
+
+ private:
+ InotifyReader* reader_;
+ int inotify_fd_;
+ int shutdown_fd_;
+
+ DISALLOW_COPY_AND_ASSIGN(InotifyReaderTask);
+};
+
+static base::LazyInstance<InotifyReader> g_inotify_reader(
+ base::LINKER_INITIALIZED);
+
+InotifyReader::InotifyReader()
+ : thread_("inotify_reader"),
+ inotify_fd_(inotify_init()),
+ valid_(false) {
+ shutdown_pipe_[0] = -1;
+ shutdown_pipe_[1] = -1;
+ if (inotify_fd_ >= 0 && pipe(shutdown_pipe_) == 0 && thread_.Start()) {
+ thread_.message_loop()->PostTask(
+ FROM_HERE, new InotifyReaderTask(this, inotify_fd_, shutdown_pipe_[0]));
+ valid_ = true;
+ }
+}
+
+InotifyReader::~InotifyReader() {
+ if (valid_) {
+ // Write to the self-pipe so that the select call in InotifyReaderTask
+ // returns.
+ ssize_t ret = HANDLE_EINTR(write(shutdown_pipe_[1], "", 1));
+ DPCHECK(ret > 0);
+ DCHECK_EQ(ret, 1);
+ thread_.Stop();
+ }
+ if (inotify_fd_ >= 0)
+ close(inotify_fd_);
+ if (shutdown_pipe_[0] >= 0)
+ close(shutdown_pipe_[0]);
+ if (shutdown_pipe_[1] >= 0)
+ close(shutdown_pipe_[1]);
+}
+
+InotifyReader::Watch InotifyReader::AddWatch(
+ const FilePath& path, FilePathWatcherImpl* watcher) {
+ if (!valid_)
+ return kInvalidWatch;
+
+ AutoLock auto_lock(lock_);
+
+ Watch watch = inotify_add_watch(inotify_fd_, path.value().c_str(),
+ IN_CREATE | IN_DELETE |
+ IN_CLOSE_WRITE | IN_MOVE |
+ IN_ONLYDIR);
+
+ if (watch == kInvalidWatch)
+ return kInvalidWatch;
+
+ watchers_[watch].insert(watcher);
+
+ return watch;
+}
+
+bool InotifyReader::RemoveWatch(Watch watch,
+ FilePathWatcherImpl* watcher) {
+ if (!valid_)
+ return false;
+
+ AutoLock auto_lock(lock_);
+
+ watchers_[watch].erase(watcher);
+
+ if (watchers_[watch].empty()) {
+ watchers_.erase(watch);
+ return (inotify_rm_watch(inotify_fd_, watch) == 0);
+ }
+
+ return true;
+}
+
+void InotifyReader::OnInotifyEvent(const inotify_event* event) {
+ if (event->mask & IN_IGNORED)
+ return;
+
+ FilePath::StringType child(event->len ? event->name : FILE_PATH_LITERAL(""));
+ AutoLock auto_lock(lock_);
+
+ for (WatcherSet::iterator watcher = watchers_[event->wd].begin();
+ watcher != watchers_[event->wd].end();
+ ++watcher) {
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(*watcher,
+ &FilePathWatcherImpl::OnFilePathChanged,
+ event->wd,
+ child,
+ event->mask & (IN_CREATE | IN_MOVED_TO),
+ event->mask & IN_ISDIR));
+ }
+}
+
+FilePathWatcherImpl::FilePathWatcherImpl()
+ : delegate_(NULL) {
+}
+
+void FilePathWatcherImpl::OnFilePathChanged(InotifyReader::Watch fired_watch,
+ const FilePath::StringType& child,
+ bool created,
+ bool is_directory) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+ // Find the entry in |watches_| that corresponds to |fired_watch|.
+ WatchVector::const_iterator watch_entry(watches_.begin());
+ for ( ; watch_entry != watches_.end(); ++watch_entry) {
+ if (fired_watch == watch_entry->watch_)
+ break;
+ }
+
+ // If this notification is from a previous generation of watches or the watch
+ // has been cancelled (|watches_| is empty then), bail out.
+ if (watch_entry == watches_.end())
+ return;
+
+ // Check whether a path component of |target_| changed.
+ bool change_on_target_path = child.empty() || child == watch_entry->subdir_;
+
+ // Check whether the change references |target_| or a direct child.
+ DCHECK(watch_entry->subdir_.empty() || (watch_entry + 1) != watches_.end());
+ bool target_changed = watch_entry->subdir_.empty() ||
+ (watch_entry->subdir_ == child && (++watch_entry)->subdir_.empty());
+
+ // Update watches if a directory component of the |target_| path (dis)appears.
+ if (is_directory && change_on_target_path && !UpdateWatches()) {
+ delegate_->OnError();
+ return;
+ }
+
+ // Report the following events:
+ // - The target or a direct child of the target got changed (in case the
+ // watched path refers to a directory).
+ // - One of the parent directories got moved or deleted, since the target
+ // disappears in this case.
+ // - One of the parent directories appears. The event corresponding to the
+ // target appearing might have been missed in this case, so recheck.
+ if (target_changed ||
+ (change_on_target_path && !created) ||
+ (change_on_target_path && file_util::PathExists(target_))) {
+ delegate_->OnFilePathChanged(target_);
+ }
+}
+
+bool FilePathWatcherImpl::Watch(const FilePath& path,
+ FilePathWatcher::Delegate* delegate) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK(target_.empty());
+
+ delegate_ = delegate;
+ target_ = path;
+ std::vector<FilePath::StringType> comps;
+ target_.GetComponents(&comps);
+ DCHECK(!comps.empty());
+ for (std::vector<FilePath::StringType>::const_iterator comp(++comps.begin());
+ comp != comps.end(); ++comp) {
+ watches_.push_back(WatchEntry(InotifyReader::kInvalidWatch, *comp));
+ }
+ watches_.push_back(WatchEntry(InotifyReader::kInvalidWatch,
+ FilePath::StringType()));
+ return UpdateWatches();
+}
+
+void FilePathWatcherImpl::Cancel() {
+ // Switch to the file thread if necessary so we can access |watches_|.
+ if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(this, &FilePathWatcherImpl::Cancel));
+ return;
+ }
+
+ for (WatchVector::iterator watch_entry(watches_.begin());
+ watch_entry != watches_.end(); ++watch_entry) {
+ if (watch_entry->watch_ != InotifyReader::kInvalidWatch)
+ g_inotify_reader.Get().RemoveWatch(watch_entry->watch_, this);
+ }
+ watches_.clear();
+ delegate_ = NULL;
+ target_.clear();
+}
+
+bool FilePathWatcherImpl::UpdateWatches() {
+ // Ensure this runs on the file thread exclusively in order to avoid
+ // concurrency issues.
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+ // Walk the list of watches and update them as we go.
+ FilePath path(FILE_PATH_LITERAL("/"));
+ bool path_valid = true;
+ for (WatchVector::iterator watch_entry(watches_.begin());
+ watch_entry != watches_.end(); ++watch_entry) {
+ InotifyReader::Watch old_watch = watch_entry->watch_;
+ if (path_valid) {
+ watch_entry->watch_ = g_inotify_reader.Get().AddWatch(path, this);
+ if (watch_entry->watch_ == InotifyReader::kInvalidWatch) {
+ path_valid = false;
+ }
+ } else {
+ watch_entry->watch_ = InotifyReader::kInvalidWatch;
+ }
+ if (old_watch != InotifyReader::kInvalidWatch &&
+ old_watch != watch_entry->watch_) {
+ g_inotify_reader.Get().RemoveWatch(old_watch, this);
+ }
+ path = path.Append(watch_entry->subdir_);
+ }
+
+ return true;
+}
+
+} // namespace
+
+FilePathWatcher::FilePathWatcher() {
+ impl_ = new FilePathWatcherImpl();
+}
diff --git a/chrome/browser/file_path_watcher/file_path_watcher_mac.cc b/chrome/browser/file_path_watcher/file_path_watcher_mac.cc
new file mode 100644
index 0000000..86c5bb5
--- /dev/null
+++ b/chrome/browser/file_path_watcher/file_path_watcher_mac.cc
@@ -0,0 +1,233 @@
+// 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.
+
+#include "chrome/browser/file_path_watcher/file_path_watcher.h"
+
+#include <CoreServices/CoreServices.h>
+#include <set>
+
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/singleton.h"
+#include "base/time.h"
+
+namespace {
+
+// The latency parameter passed to FSEventsStreamCreate().
+const CFAbsoluteTime kEventLatencySeconds = 0.3;
+
+// Mac-specific file watcher implementation based on the FSEvents API.
+class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate {
+ public:
+ FilePathWatcherImpl();
+ virtual ~FilePathWatcherImpl() {}
+
+ // Called from the FSEvents callback whenever there is a change to the paths
+ void OnFilePathChanged();
+
+ // (Re-)Initialize the event stream to start reporting events from
+ // |start_event|.
+ void UpdateEventStream(FSEventStreamEventId start_event);
+
+ // FilePathWatcher::PlatformDelegate overrides.
+ virtual bool Watch(const FilePath& path, FilePathWatcher::Delegate* delegate);
+ virtual void Cancel();
+
+ private:
+ // Destroy the event stream.
+ void DestroyEventStream();
+
+ // Delegate to notify upon changes.
+ scoped_refptr<FilePathWatcher::Delegate> delegate_;
+
+ // Target path to watch (passed to delegate).
+ FilePath target_;
+
+ // Keep track of the last modified time of the file. We use nulltime
+ // to represent the file not existing.
+ base::Time last_modified_;
+
+ // The time at which we processed the first notification with the
+ // |last_modified_| time stamp.
+ base::Time first_notification_;
+
+ // Backend stream we receive event callbacks from (strong reference).
+ FSEventStreamRef fsevent_stream_;
+
+ // Used to detect early cancellation.
+ bool canceled_;
+
+ DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl);
+};
+
+// The callback passed to FSEventStreamCreate().
+void FSEventsCallback(ConstFSEventStreamRef stream,
+ void* event_watcher, size_t num_events,
+ void* event_paths, const FSEventStreamEventFlags flags[],
+ const FSEventStreamEventId event_ids[]) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ FilePathWatcherImpl* watcher =
+ reinterpret_cast<FilePathWatcherImpl*>(event_watcher);
+ bool root_changed = false;
+ FSEventStreamEventId root_change_at = FSEventStreamGetLatestEventId(stream);
+ for (size_t i = 0; i < num_events; i++) {
+ if (flags[i] & kFSEventStreamEventFlagRootChanged)
+ root_changed = true;
+ if (event_ids[i])
+ root_change_at = std::min(root_change_at, event_ids[i]);
+ }
+
+ // Reinitialize the event stream if we find changes to the root. This is
+ // necessary since FSEvents doesn't report any events for the subtree after
+ // the directory to be watched gets created.
+ if (root_changed) {
+ // Resetting the event stream from within the callback fails (FSEvents spews
+ // bad file descriptor errors), so post a task to do the reset.
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(watcher, &FilePathWatcherImpl::UpdateEventStream,
+ root_change_at));
+ }
+
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(watcher, &FilePathWatcherImpl::OnFilePathChanged));
+}
+
+// FilePathWatcherImpl implementation:
+
+FilePathWatcherImpl::FilePathWatcherImpl()
+ : fsevent_stream_(NULL),
+ canceled_(false) {
+}
+
+void FilePathWatcherImpl::OnFilePathChanged() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK(!target_.empty());
+
+ base::PlatformFileInfo file_info;
+ bool file_exists = file_util::GetFileInfo(target_, &file_info);
+ if (file_exists && (last_modified_.is_null() ||
+ last_modified_ != file_info.last_modified)) {
+ last_modified_ = file_info.last_modified;
+ first_notification_ = base::Time::Now();
+ delegate_->OnFilePathChanged(target_);
+ } else if (file_exists && !first_notification_.is_null()) {
+ // The target's last modification time is equal to what's on record. This
+ // means that either an unrelated event occurred, or the target changed
+ // again (file modification times only have a resolution of 1s). Comparing
+ // file modification times against the wall clock is not reliable to find
+ // out whether the change is recent, since this code might just run too
+ // late. Moreover, there's no guarantee that file modification time and wall
+ // clock times come from the same source.
+ //
+ // Instead, the time at which the first notification carrying the current
+ // |last_notified_| time stamp is recorded. Later notifications that find
+ // the same file modification time only need to be forwarded until wall
+ // clock has advanced one second from the initial notification. After that
+ // interval, client code is guaranteed to having seen the current revision
+ // of the file.
+ if (base::Time::Now() - first_notification_ >
+ base::TimeDelta::FromSeconds(1)) {
+ // Stop further notifications for this |last_modification_| time stamp.
+ first_notification_ = base::Time();
+ }
+ delegate_->OnFilePathChanged(target_);
+ } else if (!file_exists && !last_modified_.is_null()) {
+ last_modified_ = base::Time();
+ delegate_->OnFilePathChanged(target_);
+ }
+}
+
+bool FilePathWatcherImpl::Watch(const FilePath& path,
+ FilePathWatcher::Delegate* delegate) {
+ DCHECK(target_.value().empty());
+
+ target_ = path;
+ delegate_ = delegate;
+
+ FSEventStreamEventId start_event = FSEventsGetCurrentEventId();
+
+ base::PlatformFileInfo file_info;
+ if (file_util::GetFileInfo(target_, &file_info)) {
+ last_modified_ = file_info.last_modified;
+ first_notification_ = base::Time::Now();
+ }
+
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(this, &FilePathWatcherImpl::UpdateEventStream,
+ start_event));
+
+ return true;
+}
+
+void FilePathWatcherImpl::Cancel() {
+ // Switch to the UI thread if necessary, so we can tear down the event stream.
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(this, &FilePathWatcherImpl::Cancel));
+ return;
+ }
+
+ canceled_ = true;
+ if (fsevent_stream_)
+ DestroyEventStream();
+}
+
+void FilePathWatcherImpl::UpdateEventStream(FSEventStreamEventId start_event) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // It can happen that the watcher gets canceled while tasks that call this
+ // function are still in flight, so abort if this situation is detected.
+ if (canceled_)
+ return;
+
+ if (fsevent_stream_)
+ DestroyEventStream();
+
+ base::mac::ScopedCFTypeRef<CFStringRef> cf_path(CFStringCreateWithCString(
+ NULL, target_.value().c_str(), kCFStringEncodingMacHFS));
+ base::mac::ScopedCFTypeRef<CFStringRef> cf_dir_path(CFStringCreateWithCString(
+ NULL, target_.DirName().value().c_str(), kCFStringEncodingMacHFS));
+ CFStringRef paths_array[] = { cf_path.get(), cf_dir_path.get() };
+ base::mac::ScopedCFTypeRef<CFArrayRef> watched_paths(CFArrayCreate(
+ NULL, reinterpret_cast<const void**>(paths_array), arraysize(paths_array),
+ &kCFTypeArrayCallBacks));
+
+ FSEventStreamContext context;
+ context.version = 0;
+ context.info = this;
+ context.retain = NULL;
+ context.release = NULL;
+ context.copyDescription = NULL;
+
+ fsevent_stream_ = FSEventStreamCreate(NULL, &FSEventsCallback, &context,
+ watched_paths,
+ start_event,
+ kEventLatencySeconds,
+ kFSEventStreamCreateFlagWatchRoot);
+ FSEventStreamScheduleWithRunLoop(fsevent_stream_, CFRunLoopGetCurrent(),
+ kCFRunLoopDefaultMode);
+ if (!FSEventStreamStart(fsevent_stream_)) {
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(delegate_.get(),
+ &FilePathWatcher::Delegate::OnError));
+ }
+}
+
+void FilePathWatcherImpl::DestroyEventStream() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ FSEventStreamStop(fsevent_stream_);
+ FSEventStreamUnscheduleFromRunLoop(fsevent_stream_, CFRunLoopGetCurrent(),
+ kCFRunLoopDefaultMode);
+ FSEventStreamRelease(fsevent_stream_);
+ fsevent_stream_ = NULL;
+}
+
+} // namespace
+
+FilePathWatcher::FilePathWatcher() {
+ impl_ = new FilePathWatcherImpl();
+}
diff --git a/chrome/browser/file_path_watcher/file_path_watcher_stub.cc b/chrome/browser/file_path_watcher/file_path_watcher_stub.cc
new file mode 100644
index 0000000..6387715
--- /dev/null
+++ b/chrome/browser/file_path_watcher/file_path_watcher_stub.cc
@@ -0,0 +1,19 @@
+// 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.
+
+// This file exists for Unix systems which don't have the inotify headers, and
+// thus cannot build file_watcher_inotify.cc
+
+#include "chrome/browser/file_path_watcher/file_path_watcher.h"
+
+class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate {
+ public:
+ virtual bool Watch(const FilePath& path, FileWatcher::Delegate* delegate) {
+ return false;
+ }
+};
+
+FilePathWatcher::FilePathWatcher() {
+ impl_ = new FilePathWatcherImpl();
+}
diff --git a/chrome/browser/file_path_watcher/file_path_watcher_win.cc b/chrome/browser/file_path_watcher/file_path_watcher_win.cc
new file mode 100644
index 0000000..57294d4
--- /dev/null
+++ b/chrome/browser/file_path_watcher/file_path_watcher_win.cc
@@ -0,0 +1,244 @@
+// 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.
+
+#include "chrome/browser/file_path_watcher/file_path_watcher.h"
+
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/object_watcher.h"
+#include "base/ref_counted.h"
+#include "base/time.h"
+
+namespace {
+
+class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate,
+ public base::ObjectWatcher::Delegate {
+ public:
+ FilePathWatcherImpl() : delegate_(NULL), handle_(INVALID_HANDLE_VALUE) {}
+
+ virtual bool Watch(const FilePath& path, FilePathWatcher::Delegate* delegate);
+ virtual void Cancel();
+
+ // Callback from MessageLoopForIO.
+ virtual void OnObjectSignaled(HANDLE object);
+
+ private:
+ virtual ~FilePathWatcherImpl();
+
+ // Setup a watch handle for directory |dir|. Returns true if no fatal error
+ // occurs. |handle| will receive the handle value if |dir| is watchable,
+ // otherwise INVALID_HANDLE_VALUE.
+ static bool SetupWatchHandle(const FilePath& dir, HANDLE* handle)
+ WARN_UNUSED_RESULT;
+
+ // (Re-)Initialize the watch handle.
+ bool UpdateWatch() WARN_UNUSED_RESULT;
+
+ // Destroy the watch handle.
+ void DestroyWatch();
+
+ // Delegate to notify upon changes.
+ scoped_refptr<FilePathWatcher::Delegate> delegate_;
+
+ // Path we're supposed to watch (passed to delegate).
+ FilePath target_;
+
+ // Handle for FindFirstChangeNotification.
+ HANDLE handle_;
+
+ // ObjectWatcher to watch handle_ for events.
+ base::ObjectWatcher watcher_;
+
+ // Keep track of the last modified time of the file. We use nulltime
+ // to represent the file not existing.
+ base::Time last_modified_;
+
+ // The time at which we processed the first notification with the
+ // |last_modified_| time stamp.
+ base::Time first_notification_;
+
+ DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl);
+};
+
+bool FilePathWatcherImpl::Watch(const FilePath& path,
+ FilePathWatcher::Delegate* delegate) {
+ DCHECK(target_.value().empty()); // Can only watch one path.
+ delegate_ = delegate;
+ target_ = path;
+
+ if (!UpdateWatch())
+ return false;
+
+ watcher_.StartWatching(handle_, this);
+
+ return true;
+}
+
+void FilePathWatcherImpl::Cancel() {
+ // Switch to the file thread if necessary so we can stop |watcher_|.
+ if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(this, &FilePathWatcherImpl::Cancel));
+ return;
+ }
+
+ if (handle_ != INVALID_HANDLE_VALUE)
+ DestroyWatch();
+}
+
+void FilePathWatcherImpl::OnObjectSignaled(HANDLE object) {
+ DCHECK(object == handle_);
+ // Make sure we stay alive through the body of this function.
+ scoped_refptr<FilePathWatcherImpl> keep_alive(this);
+
+ if (!UpdateWatch()) {
+ delegate_->OnError();
+ return;
+ }
+
+ // Check whether the event applies to |target_| and notify the delegate.
+ base::PlatformFileInfo file_info;
+ bool file_exists = file_util::GetFileInfo(target_, &file_info);
+ if (file_exists && (last_modified_.is_null() ||
+ last_modified_ != file_info.last_modified)) {
+ last_modified_ = file_info.last_modified;
+ first_notification_ = base::Time::Now();
+ delegate_->OnFilePathChanged(target_);
+ } else if (file_exists && !first_notification_.is_null()) {
+ // The target's last modification time is equal to what's on record. This
+ // means that either an unrelated event occurred, or the target changed
+ // again (file modification times only have a resolution of 1s). Comparing
+ // file modification times against the wall clock is not reliable to find
+ // out whether the change is recent, since this code might just run too
+ // late. Moreover, there's no guarantee that file modification time and wall
+ // clock times come from the same source.
+ //
+ // Instead, the time at which the first notification carrying the current
+ // |last_notified_| time stamp is recorded. Later notifications that find
+ // the same file modification time only need to be forwarded until wall
+ // clock has advanced one second from the initial notification. After that
+ // interval, client code is guaranteed to having seen the current revision
+ // of the file.
+ if (base::Time::Now() - first_notification_ >
+ base::TimeDelta::FromSeconds(1)) {
+ // Stop further notifications for this |last_modification_| time stamp.
+ first_notification_ = base::Time();
+ }
+ delegate_->OnFilePathChanged(target_);
+ } else if (!file_exists && !last_modified_.is_null()) {
+ last_modified_ = base::Time();
+ delegate_->OnFilePathChanged(target_);
+ }
+
+ // The watch may have been cancelled by the callback.
+ if (handle_ != INVALID_HANDLE_VALUE)
+ watcher_.StartWatching(handle_, this);
+}
+
+FilePathWatcherImpl::~FilePathWatcherImpl() {
+ if (handle_ != INVALID_HANDLE_VALUE)
+ DestroyWatch();
+}
+
+// static
+bool FilePathWatcherImpl::SetupWatchHandle(const FilePath& dir,
+ HANDLE* handle) {
+ *handle = FindFirstChangeNotification(
+ dir.value().c_str(),
+ false, // Don't watch subtrees
+ FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_SIZE |
+ FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_DIR_NAME |
+ FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SECURITY);
+ if (*handle != INVALID_HANDLE_VALUE) {
+ // Make sure the handle we got points to an existing directory. It seems
+ // that windows sometimes hands out watches to direectories that are
+ // about to go away, but doesn't sent notifications if that happens.
+ if (!file_util::DirectoryExists(dir)) {
+ FindCloseChangeNotification(*handle);
+ *handle = INVALID_HANDLE_VALUE;
+ }
+ return true;
+ }
+
+ // If FindFirstChangeNotification failed because the target directory
+ // doesn't exist, access is denied (happens if the file is already gone but
+ // there are still handles open), or the target is not a directory, try the
+ // immediate parent directory instead.
+ DWORD error_code = GetLastError();
+ if (error_code != ERROR_FILE_NOT_FOUND &&
+ error_code != ERROR_PATH_NOT_FOUND &&
+ error_code != ERROR_ACCESS_DENIED &&
+ error_code != ERROR_SHARING_VIOLATION &&
+ error_code != ERROR_DIRECTORY) {
+ PLOG(ERROR) << "FindFirstChangeNotification failed for "
+ << dir.value();
+ return false;
+ }
+
+ return true;
+}
+
+bool FilePathWatcherImpl::UpdateWatch() {
+ if (handle_ != INVALID_HANDLE_VALUE)
+ DestroyWatch();
+
+ base::PlatformFileInfo file_info;
+ if (file_util::GetFileInfo(target_, &file_info)) {
+ last_modified_ = file_info.last_modified;
+ first_notification_ = base::Time::Now();
+ }
+
+ // Start at the target and walk up the directory chain until we succesfully
+ // create a watch handle in |handle_|. |child_dirs| keeps a stack of child
+ // directories stripped from target, in reverse order.
+ std::vector<FilePath> child_dirs;
+ FilePath watched_path(target_);
+ while (true) {
+ if (!SetupWatchHandle(watched_path, &handle_))
+ return false;
+
+ // Break if a valid handle is returned. Try the parent directory otherwise.
+ if (handle_ != INVALID_HANDLE_VALUE)
+ break;
+
+ // Abort if we hit the root directory.
+ child_dirs.push_back(watched_path.BaseName());
+ FilePath parent(watched_path.DirName());
+ if (parent == watched_path) {
+ LOG(ERROR) << "Reached the root directory";
+ return false;
+ }
+ watched_path = parent;
+ }
+
+ // At this point, handle_ is valid. However, the bottom-up search that the
+ // above code performs races against directory creation. So try to walk back
+ // down and see whether any children appeared in the mean time.
+ while (!child_dirs.empty()) {
+ watched_path = watched_path.Append(child_dirs.back());
+ child_dirs.pop_back();
+ HANDLE temp_handle = INVALID_HANDLE_VALUE;
+ if (!SetupWatchHandle(watched_path, &temp_handle))
+ return false;
+ if (temp_handle == INVALID_HANDLE_VALUE)
+ break;
+ FindCloseChangeNotification(handle_);
+ handle_ = temp_handle;
+ }
+
+ return true;
+}
+
+void FilePathWatcherImpl::DestroyWatch() {
+ watcher_.StopWatching();
+ FindCloseChangeNotification(handle_);
+ handle_ = INVALID_HANDLE_VALUE;
+}
+
+} // namespace
+
+FilePathWatcher::FilePathWatcher() {
+ impl_ = new FilePathWatcherImpl();
+}
diff --git a/chrome/browser/file_path_watcher_browsertest.cc b/chrome/browser/file_path_watcher_browsertest.cc
deleted file mode 100644
index a337ae3..0000000
--- a/chrome/browser/file_path_watcher_browsertest.cc
+++ /dev/null
@@ -1,455 +0,0 @@
-// 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.
-
-#include "chrome/browser/file_path_watcher.h"
-
-#include <set>
-
-#include "base/basictypes.h"
-#include "base/file_path.h"
-#include "base/file_util.h"
-#include "base/message_loop.h"
-#include "base/message_loop_proxy.h"
-#include "base/path_service.h"
-#include "base/platform_thread.h"
-#include "base/scoped_temp_dir.h"
-#include "base/string_util.h"
-#include "base/stl_util-inl.h"
-#include "base/waitable_event.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-#if defined(OS_MACOSX)
-// TODO(mnissler): There are flakes on Mac (http://crbug.com/54822) at least for
-// FilePathWatcherTest.MultipleWatchersSingleFile.
-#define MAYBE(name) FLAKY_ ## name
-#else
-#define MAYBE(name) name
-#endif
-
-namespace {
-
-class TestDelegate;
-
-// Aggregates notifications from the test delegates and breaks the message loop
-// the test thread is waiting on once they all came in.
-class NotificationCollector
- : public base::RefCountedThreadSafe<NotificationCollector> {
- public:
- NotificationCollector()
- : loop_(base::MessageLoopProxy::CreateForCurrentThread()) {}
-
- // Called from the file thread by the delegates.
- void OnChange(TestDelegate* delegate) {
- loop_->PostTask(FROM_HERE,
- NewRunnableMethod(this,
- &NotificationCollector::RecordChange,
- make_scoped_refptr(delegate)));
- }
-
- void Register(TestDelegate* delegate) {
- delegates_.insert(delegate);
- }
-
- void Reset() {
- signaled_.clear();
- }
-
- private:
- void RecordChange(TestDelegate* delegate) {
- ASSERT_TRUE(loop_->BelongsToCurrentThread());
- ASSERT_TRUE(delegates_.count(delegate));
- signaled_.insert(delegate);
-
- // Check whether all delegates have been signaled.
- if (signaled_ == delegates_)
- loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask());
- }
-
- // Set of registered delegates.
- std::set<TestDelegate*> delegates_;
-
- // Set of signaled delegates.
- std::set<TestDelegate*> signaled_;
-
- // The loop we should break after all delegates signaled.
- scoped_refptr<base::MessageLoopProxy> loop_;
-};
-
-// A mock FilePathWatcher::Delegate for testing. I'd rather use gmock, but it's
-// not thread safe for setting expectations, so the test code couldn't safely
-// reset expectations while the file watcher is running. In order to allow this,
-// we keep simple thread safe status flags in TestDelegate.
-class TestDelegate : public FilePathWatcher::Delegate {
- public:
- // The message loop specified by |loop| will be quit if a notification is
- // received while the delegate is |armed_|. Note that the testing code must
- // guarantee |loop| outlives the file thread on which OnFilePathChanged runs.
- explicit TestDelegate(NotificationCollector* collector)
- : collector_(collector) {
- collector_->Register(this);
- }
-
- virtual void OnFilePathChanged(const FilePath&) {
- collector_->OnChange(this);
- }
-
- private:
- scoped_refptr<NotificationCollector> collector_;
-
- DISALLOW_COPY_AND_ASSIGN(TestDelegate);
-};
-
-// A helper class for setting up watches on the file thread.
-class SetupWatchTask : public Task {
- public:
- SetupWatchTask(const FilePath& target,
- FilePathWatcher* watcher,
- FilePathWatcher::Delegate* delegate,
- bool* result,
- base::WaitableEvent* completion)
- : target_(target),
- watcher_(watcher),
- delegate_(delegate),
- result_(result),
- completion_(completion) {}
-
- void Run() {
- *result_ = watcher_->Watch(target_, delegate_);
- completion_->Signal();
- }
-
- private:
- const FilePath target_;
- FilePathWatcher* watcher_;
- FilePathWatcher::Delegate* delegate_;
- bool* result_;
- base::WaitableEvent* completion_;
-
- DISALLOW_COPY_AND_ASSIGN(SetupWatchTask);
-};
-
-class FilePathWatcherTest : public testing::Test {
- public:
- // Implementation of FilePathWatcher on Mac requires UI loop.
- FilePathWatcherTest()
- : loop_(MessageLoop::TYPE_UI),
- ui_thread_(BrowserThread::UI, &loop_) {
- }
-
- protected:
- virtual void SetUp() {
- // Create a separate file thread in order to test proper thread usage.
- file_thread_.reset(new BrowserThread(BrowserThread::FILE));
- file_thread_->Start();
- temp_dir_.reset(new ScopedTempDir);
- ASSERT_TRUE(temp_dir_->CreateUniqueTempDir());
- collector_ = new NotificationCollector();
- }
-
- virtual void TearDown() {
- loop_.RunAllPending();
- file_thread_.reset();
- }
-
- FilePath test_file() {
- return temp_dir_->path().AppendASCII("FilePathWatcherTest");
- }
-
- // Write |content| to |file|. Returns true on success.
- bool WriteFile(const FilePath& file, const std::string& content) {
- int write_size = file_util::WriteFile(file, content.c_str(),
- content.length());
- return write_size == static_cast<int>(content.length());
- }
-
- void SetupWatch(const FilePath& target,
- FilePathWatcher* watcher,
- FilePathWatcher::Delegate* delegate) {
- base::WaitableEvent completion(false, false);
- bool result;
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- new SetupWatchTask(target, watcher, delegate, &result, &completion));
- completion.Wait();
- ASSERT_TRUE(result);
- }
-
- void WaitForEvents() {
- collector_->Reset();
- loop_.Run();
- }
-
- NotificationCollector* collector() { return collector_.get(); }
-
- MessageLoop loop_;
- BrowserThread ui_thread_;
- scoped_ptr<BrowserThread> file_thread_;
- scoped_ptr<ScopedTempDir> temp_dir_;
- scoped_refptr<NotificationCollector> collector_;
-};
-
-// Basic test: Create the file and verify that we notice.
-TEST_F(FilePathWatcherTest, MAYBE(NewFile)) {
- FilePathWatcher watcher;
- scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
- SetupWatch(test_file(), &watcher, delegate.get());
-
- ASSERT_TRUE(WriteFile(test_file(), "content"));
- WaitForEvents();
-}
-
-// Verify that modifying the file is caught.
-TEST_F(FilePathWatcherTest, MAYBE(ModifiedFile)) {
- ASSERT_TRUE(WriteFile(test_file(), "content"));
-
- FilePathWatcher watcher;
- scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
- SetupWatch(test_file(), &watcher, delegate.get());
-
- // Now make sure we get notified if the file is modified.
- ASSERT_TRUE(WriteFile(test_file(), "new content"));
- WaitForEvents();
-}
-
-// Verify that moving the file into place is caught.
-TEST_F(FilePathWatcherTest, MAYBE(MovedFile)) {
- FilePath source_file(temp_dir_->path().AppendASCII("source"));
- ASSERT_TRUE(WriteFile(source_file, "content"));
-
- FilePathWatcher watcher;
- scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
- SetupWatch(test_file(), &watcher, delegate.get());
-
- // Now make sure we get notified if the file is modified.
- ASSERT_TRUE(file_util::Move(source_file, test_file()));
- WaitForEvents();
-}
-
-TEST_F(FilePathWatcherTest, MAYBE(DeletedFile)) {
- ASSERT_TRUE(WriteFile(test_file(), "content"));
-
- FilePathWatcher watcher;
- scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
- SetupWatch(test_file(), &watcher, delegate.get());
-
- // Now make sure we get notified if the file is deleted.
- file_util::Delete(test_file(), false);
- WaitForEvents();
-}
-
-// Used by the DeleteDuringNotify test below.
-// Deletes the FilePathWatcher when it's notified.
-class Deleter : public FilePathWatcher::Delegate {
- public:
- Deleter(FilePathWatcher* watcher, MessageLoop* loop)
- : watcher_(watcher),
- loop_(loop) {
- }
-
- virtual void OnFilePathChanged(const FilePath& path) {
- watcher_.reset(NULL);
- loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask());
- }
-
- scoped_ptr<FilePathWatcher> watcher_;
- MessageLoop* loop_;
-};
-
-// Verify that deleting a watcher during the callback doesn't crash.
-TEST_F(FilePathWatcherTest, DeleteDuringNotify) {
- FilePathWatcher* watcher = new FilePathWatcher;
- // Takes ownership of watcher.
- scoped_refptr<Deleter> deleter(new Deleter(watcher, &loop_));
- SetupWatch(test_file(), watcher, deleter.get());
-
- ASSERT_TRUE(WriteFile(test_file(), "content"));
- WaitForEvents();
-
- // We win if we haven't crashed yet.
- // Might as well double-check it got deleted, too.
- ASSERT_TRUE(deleter->watcher_.get() == NULL);
-}
-
-// Verify that deleting the watcher works even if there is a pending
-// notification.
-TEST_F(FilePathWatcherTest, DestroyWithPendingNotification) {
- scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
- FilePathWatcher* watcher = new FilePathWatcher;
- SetupWatch(test_file(), watcher, delegate.get());
- ASSERT_TRUE(WriteFile(test_file(), "content"));
- BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, watcher);
-}
-
-TEST_F(FilePathWatcherTest, MAYBE(MultipleWatchersSingleFile)) {
- FilePathWatcher watcher1, watcher2;
- scoped_refptr<TestDelegate> delegate1(new TestDelegate(collector()));
- scoped_refptr<TestDelegate> delegate2(new TestDelegate(collector()));
- SetupWatch(test_file(), &watcher1, delegate1.get());
- SetupWatch(test_file(), &watcher2, delegate2.get());
-
- ASSERT_TRUE(WriteFile(test_file(), "content"));
- WaitForEvents();
-}
-
-// Verify that watching a file whose parent directory doesn't exist yet works if
-// the directory and file are created eventually.
-TEST_F(FilePathWatcherTest, NonExistentDirectory) {
- FilePathWatcher watcher;
- FilePath dir(temp_dir_->path().AppendASCII("dir"));
- FilePath file(dir.AppendASCII("file"));
- scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
- SetupWatch(file, &watcher, delegate.get());
-
- ASSERT_TRUE(file_util::CreateDirectory(dir));
-
- ASSERT_TRUE(WriteFile(file, "content"));
- VLOG(1) << "Waiting for file creation";
- WaitForEvents();
-
- ASSERT_TRUE(WriteFile(file, "content v2"));
- VLOG(1) << "Waiting for file change";
- WaitForEvents();
-
- ASSERT_TRUE(file_util::Delete(file, false));
- VLOG(1) << "Waiting for file deletion";
- WaitForEvents();
-}
-
-// Exercises watch reconfiguration for the case that directories on the path
-// are rapidly created.
-TEST_F(FilePathWatcherTest, DirectoryChain) {
- FilePath path(temp_dir_->path());
- std::vector<std::string> dir_names;
- for (int i = 0; i < 20; i++) {
- std::string dir(StringPrintf("d%d", i));
- dir_names.push_back(dir);
- path = path.AppendASCII(dir);
- }
-
- FilePathWatcher watcher;
- FilePath file(path.AppendASCII("file"));
- scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
- SetupWatch(file, &watcher, delegate.get());
-
- FilePath sub_path(temp_dir_->path());
- for (std::vector<std::string>::const_iterator d(dir_names.begin());
- d != dir_names.end(); ++d) {
- sub_path = sub_path.AppendASCII(*d);
- ASSERT_TRUE(file_util::CreateDirectory(sub_path));
- }
- ASSERT_TRUE(WriteFile(file, "content"));
- VLOG(1) << "Waiting for file creation";
- WaitForEvents();
-
- ASSERT_TRUE(WriteFile(file, "content v2"));
- VLOG(1) << "Waiting for file modification";
- WaitForEvents();
-}
-
-TEST_F(FilePathWatcherTest, DisappearingDirectory) {
- FilePathWatcher watcher;
- FilePath dir(temp_dir_->path().AppendASCII("dir"));
- FilePath file(dir.AppendASCII("file"));
- ASSERT_TRUE(file_util::CreateDirectory(dir));
- ASSERT_TRUE(WriteFile(file, "content"));
- scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
- SetupWatch(file, &watcher, delegate.get());
-
- ASSERT_TRUE(file_util::Delete(dir, true));
- WaitForEvents();
-}
-
-// Tests that a file that is deleted and reappears is tracked correctly.
-TEST_F(FilePathWatcherTest, DeleteAndRecreate) {
- ASSERT_TRUE(WriteFile(test_file(), "content"));
- FilePathWatcher watcher;
- scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
- SetupWatch(test_file(), &watcher, delegate.get());
-
- ASSERT_TRUE(file_util::Delete(test_file(), false));
- VLOG(1) << "Waiting for file deletion";
- WaitForEvents();
-
- ASSERT_TRUE(WriteFile(test_file(), "content"));
- VLOG(1) << "Waiting for file creation";
- WaitForEvents();
-}
-
-TEST_F(FilePathWatcherTest, WatchDirectory) {
- FilePathWatcher watcher;
- FilePath dir(temp_dir_->path().AppendASCII("dir"));
- FilePath file1(dir.AppendASCII("file1"));
- FilePath file2(dir.AppendASCII("file2"));
- scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
- SetupWatch(dir, &watcher, delegate.get());
-
- ASSERT_TRUE(file_util::CreateDirectory(dir));
- VLOG(1) << "Waiting for directory creation";
- WaitForEvents();
-
- ASSERT_TRUE(WriteFile(file1, "content"));
- VLOG(1) << "Waiting for file1 creation";
- WaitForEvents();
-
- ASSERT_TRUE(WriteFile(file1, "content v2"));
- VLOG(1) << "Waiting for file1 modification";
- WaitForEvents();
-
- ASSERT_TRUE(file_util::Delete(file1, false));
- VLOG(1) << "Waiting for file1 deletion";
- WaitForEvents();
-
- ASSERT_TRUE(WriteFile(file2, "content"));
- VLOG(1) << "Waiting for file2 creation";
- WaitForEvents();
-}
-
-TEST_F(FilePathWatcherTest, MoveParent) {
- FilePathWatcher file_watcher;
- FilePathWatcher subdir_watcher;
- FilePath dir(temp_dir_->path().AppendASCII("dir"));
- FilePath dest(temp_dir_->path().AppendASCII("dest"));
- FilePath subdir(dir.AppendASCII("subdir"));
- FilePath file(subdir.AppendASCII("file"));
- scoped_refptr<TestDelegate> file_delegate(new TestDelegate(collector()));
- SetupWatch(file, &file_watcher, file_delegate.get());
- scoped_refptr<TestDelegate> subdir_delegate(new TestDelegate(collector()));
- SetupWatch(subdir, &subdir_watcher, subdir_delegate.get());
-
- // Setup a directory hierarchy.
- ASSERT_TRUE(file_util::CreateDirectory(subdir));
- ASSERT_TRUE(WriteFile(file, "content"));
- VLOG(1) << "Waiting for file creation";
- WaitForEvents();
-
- // Move the parent directory.
- file_util::Move(dir, dest);
- VLOG(1) << "Waiting for directory move";
- WaitForEvents();
-}
-
-TEST_F(FilePathWatcherTest, MoveChild) {
- FilePathWatcher file_watcher;
- FilePathWatcher subdir_watcher;
- FilePath source_dir(temp_dir_->path().AppendASCII("source"));
- FilePath source_subdir(source_dir.AppendASCII("subdir"));
- FilePath source_file(source_subdir.AppendASCII("file"));
- FilePath dest_dir(temp_dir_->path().AppendASCII("dest"));
- FilePath dest_subdir(dest_dir.AppendASCII("subdir"));
- FilePath dest_file(dest_subdir.AppendASCII("file"));
-
- // Setup a directory hierarchy.
- ASSERT_TRUE(file_util::CreateDirectory(source_subdir));
- ASSERT_TRUE(WriteFile(source_file, "content"));
-
- scoped_refptr<TestDelegate> file_delegate(new TestDelegate(collector()));
- SetupWatch(dest_file, &file_watcher, file_delegate.get());
- scoped_refptr<TestDelegate> subdir_delegate(new TestDelegate(collector()));
- SetupWatch(dest_subdir, &subdir_watcher, subdir_delegate.get());
-
- // Move the directory into place, s.t. the watched file appears.
- ASSERT_TRUE(file_util::Move(source_dir, dest_dir));
- WaitForEvents();
-}
-
-} // namespace
diff --git a/chrome/browser/file_path_watcher_inotify.cc b/chrome/browser/file_path_watcher_inotify.cc
deleted file mode 100644
index 591daba..0000000
--- a/chrome/browser/file_path_watcher_inotify.cc
+++ /dev/null
@@ -1,410 +0,0 @@
-// 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.
-
-#include "chrome/browser/file_path_watcher.h"
-
-#include <errno.h>
-#include <string.h>
-#include <sys/inotify.h>
-#include <sys/ioctl.h>
-#include <sys/select.h>
-#include <unistd.h>
-
-#include <algorithm>
-#include <set>
-#include <utility>
-#include <vector>
-
-#include "base/eintr_wrapper.h"
-#include "base/file_path.h"
-#include "base/file_util.h"
-#include "base/hash_tables.h"
-#include "base/lock.h"
-#include "base/logging.h"
-#include "base/message_loop.h"
-#include "base/scoped_ptr.h"
-#include "base/singleton.h"
-#include "base/task.h"
-#include "base/thread.h"
-
-namespace {
-
-class FilePathWatcherImpl;
-
-// Singleton to manage all inotify watches.
-// TODO(tony): It would be nice if this wasn't a singleton.
-// http://crbug.com/38174
-class InotifyReader {
- public:
- typedef int Watch; // Watch descriptor used by AddWatch and RemoveWatch.
- static const Watch kInvalidWatch = -1;
-
- // Watch directory |path| for changes. |watcher| will be notified on each
- // change. Returns kInvalidWatch on failure.
- Watch AddWatch(const FilePath& path, FilePathWatcherImpl* watcher);
-
- // Remove |watch|. Returns true on success.
- bool RemoveWatch(Watch watch, FilePathWatcherImpl* watcher);
-
- // Callback for InotifyReaderTask.
- void OnInotifyEvent(const inotify_event* event);
-
- private:
- friend struct DefaultSingletonTraits<InotifyReader>;
-
- typedef std::set<FilePathWatcherImpl*> WatcherSet;
-
- InotifyReader();
- ~InotifyReader();
-
- // We keep track of which delegates want to be notified on which watches.
- base::hash_map<Watch, WatcherSet> watchers_;
-
- // Lock to protect watchers_.
- Lock lock_;
-
- // Separate thread on which we run blocking read for inotify events.
- base::Thread thread_;
-
- // File descriptor returned by inotify_init.
- const int inotify_fd_;
-
- // Use self-pipe trick to unblock select during shutdown.
- int shutdown_pipe_[2];
-
- // Flag set to true when startup was successful.
- bool valid_;
-
- DISALLOW_COPY_AND_ASSIGN(InotifyReader);
-};
-
-class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate {
- public:
- FilePathWatcherImpl();
- virtual ~FilePathWatcherImpl() {}
-
- // Called for each event coming from the watch. |fired_watch| identifies the
- // watch that fired, |child| indicates what has changed, and is relative to
- // the currently watched path for |fired_watch|. The flag |created| is true if
- // the object appears, and |is_directory| is set when the event refers to a
- // directory.
- void OnFilePathChanged(InotifyReader::Watch fired_watch,
- const FilePath::StringType& child,
- bool created,
- bool is_directory);
-
- // Start watching |path| for changes and notify |delegate| on each change.
- // Returns true if watch for |path| has been added successfully.
- virtual bool Watch(const FilePath& path, FilePathWatcher::Delegate* delegate);
-
- // Cancel the watch. This unregisters the instance with InotifyReader.
- virtual void Cancel();
-
- private:
- // Inotify watches are installed for all directory components of |target_|. A
- // WatchEntry instance holds the watch descriptor for a component and the
- // subdirectory for that identifies the next component.
- struct WatchEntry {
- WatchEntry(InotifyReader::Watch watch, const FilePath::StringType& subdir)
- : watch_(watch),
- subdir_(subdir) {}
-
- InotifyReader::Watch watch_;
- FilePath::StringType subdir_;
- };
- typedef std::vector<WatchEntry> WatchVector;
-
- // Reconfigure to watch for the most specific parent directory of |target_|
- // that exists. Updates |watched_path_|. Returns true on success.
- bool UpdateWatches() WARN_UNUSED_RESULT;
-
- // Delegate to notify upon changes.
- scoped_refptr<FilePathWatcher::Delegate> delegate_;
-
- // The file or directory we're supposed to watch.
- FilePath target_;
-
- // The vector of watches and next component names for all path components,
- // starting at the root directory. The last entry corresponds to the watch for
- // |target_| and always stores an empty next component name in |subdir_|.
- WatchVector watches_;
-
- DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl);
-};
-
-class InotifyReaderTask : public Task {
- public:
- InotifyReaderTask(InotifyReader* reader, int inotify_fd, int shutdown_fd)
- : reader_(reader),
- inotify_fd_(inotify_fd),
- shutdown_fd_(shutdown_fd) {
- }
-
- virtual void Run() {
- while (true) {
- fd_set rfds;
- FD_ZERO(&rfds);
- FD_SET(inotify_fd_, &rfds);
- FD_SET(shutdown_fd_, &rfds);
-
- // Wait until some inotify events are available.
- int select_result =
- HANDLE_EINTR(select(std::max(inotify_fd_, shutdown_fd_) + 1,
- &rfds, NULL, NULL, NULL));
- if (select_result < 0) {
- DPLOG(WARNING) << "select failed";
- return;
- }
-
- if (FD_ISSET(shutdown_fd_, &rfds))
- return;
-
- // Adjust buffer size to current event queue size.
- int buffer_size;
- int ioctl_result = HANDLE_EINTR(ioctl(inotify_fd_, FIONREAD,
- &buffer_size));
-
- if (ioctl_result != 0) {
- DPLOG(WARNING) << "ioctl failed";
- return;
- }
-
- std::vector<char> buffer(buffer_size);
-
- ssize_t bytes_read = HANDLE_EINTR(read(inotify_fd_, &buffer[0],
- buffer_size));
-
- if (bytes_read < 0) {
- DPLOG(WARNING) << "read from inotify fd failed";
- return;
- }
-
- ssize_t i = 0;
- while (i < bytes_read) {
- inotify_event* event = reinterpret_cast<inotify_event*>(&buffer[i]);
- size_t event_size = sizeof(inotify_event) + event->len;
- DCHECK(i + event_size <= static_cast<size_t>(bytes_read));
- reader_->OnInotifyEvent(event);
- i += event_size;
- }
- }
- }
-
- private:
- InotifyReader* reader_;
- int inotify_fd_;
- int shutdown_fd_;
-
- DISALLOW_COPY_AND_ASSIGN(InotifyReaderTask);
-};
-
-InotifyReader::InotifyReader()
- : thread_("inotify_reader"),
- inotify_fd_(inotify_init()),
- valid_(false) {
- shutdown_pipe_[0] = -1;
- shutdown_pipe_[1] = -1;
- if (inotify_fd_ >= 0 && pipe(shutdown_pipe_) == 0 && thread_.Start()) {
- thread_.message_loop()->PostTask(
- FROM_HERE, new InotifyReaderTask(this, inotify_fd_, shutdown_pipe_[0]));
- valid_ = true;
- }
-}
-
-InotifyReader::~InotifyReader() {
- if (valid_) {
- // Write to the self-pipe so that the select call in InotifyReaderTask
- // returns.
- ssize_t ret = HANDLE_EINTR(write(shutdown_pipe_[1], "", 1));
- DPCHECK(ret > 0);
- DCHECK_EQ(ret, 1);
- thread_.Stop();
- }
- if (inotify_fd_ >= 0)
- close(inotify_fd_);
- if (shutdown_pipe_[0] >= 0)
- close(shutdown_pipe_[0]);
- if (shutdown_pipe_[1] >= 0)
- close(shutdown_pipe_[1]);
-}
-
-InotifyReader::Watch InotifyReader::AddWatch(
- const FilePath& path, FilePathWatcherImpl* watcher) {
- if (!valid_)
- return kInvalidWatch;
-
- AutoLock auto_lock(lock_);
-
- Watch watch = inotify_add_watch(inotify_fd_, path.value().c_str(),
- IN_CREATE | IN_DELETE |
- IN_CLOSE_WRITE | IN_MOVE |
- IN_ONLYDIR);
-
- if (watch == kInvalidWatch)
- return kInvalidWatch;
-
- watchers_[watch].insert(watcher);
-
- return watch;
-}
-
-bool InotifyReader::RemoveWatch(Watch watch,
- FilePathWatcherImpl* watcher) {
- if (!valid_)
- return false;
-
- AutoLock auto_lock(lock_);
-
- watchers_[watch].erase(watcher);
-
- if (watchers_[watch].empty()) {
- watchers_.erase(watch);
- return (inotify_rm_watch(inotify_fd_, watch) == 0);
- }
-
- return true;
-}
-
-void InotifyReader::OnInotifyEvent(const inotify_event* event) {
- if (event->mask & IN_IGNORED)
- return;
-
- FilePath::StringType child(event->len ? event->name : FILE_PATH_LITERAL(""));
- AutoLock auto_lock(lock_);
-
- for (WatcherSet::iterator watcher = watchers_[event->wd].begin();
- watcher != watchers_[event->wd].end();
- ++watcher) {
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(*watcher,
- &FilePathWatcherImpl::OnFilePathChanged,
- event->wd,
- child,
- event->mask & (IN_CREATE | IN_MOVED_TO),
- event->mask & IN_ISDIR));
- }
-}
-
-FilePathWatcherImpl::FilePathWatcherImpl()
- : delegate_(NULL) {
-}
-
-void FilePathWatcherImpl::OnFilePathChanged(InotifyReader::Watch fired_watch,
- const FilePath::StringType& child,
- bool created,
- bool is_directory) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- // Find the entry in |watches_| that corresponds to |fired_watch|.
- WatchVector::const_iterator watch_entry(watches_.begin());
- for ( ; watch_entry != watches_.end(); ++watch_entry) {
- if (fired_watch == watch_entry->watch_)
- break;
- }
-
- // If this notification is from a previous generation of watches or the watch
- // has been cancelled (|watches_| is empty then), bail out.
- if (watch_entry == watches_.end())
- return;
-
- // Check whether a path component of |target_| changed.
- bool change_on_target_path = child.empty() || child == watch_entry->subdir_;
-
- // Check whether the change references |target_| or a direct child.
- DCHECK(watch_entry->subdir_.empty() || (watch_entry + 1) != watches_.end());
- bool target_changed = watch_entry->subdir_.empty() ||
- (watch_entry->subdir_ == child && (++watch_entry)->subdir_.empty());
-
- // Update watches if a directory component of the |target_| path (dis)appears.
- if (is_directory && change_on_target_path && !UpdateWatches()) {
- delegate_->OnError();
- return;
- }
-
- // Report the following events:
- // - The target or a direct child of the target got changed (in case the
- // watched path refers to a directory).
- // - One of the parent directories got moved or deleted, since the target
- // disappears in this case.
- // - One of the parent directories appears. The event corresponding to the
- // target appearing might have been missed in this case, so recheck.
- if (target_changed ||
- (change_on_target_path && !created) ||
- (change_on_target_path && file_util::PathExists(target_))) {
- delegate_->OnFilePathChanged(target_);
- }
-}
-
-bool FilePathWatcherImpl::Watch(const FilePath& path,
- FilePathWatcher::Delegate* delegate) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- DCHECK(target_.empty());
-
- delegate_ = delegate;
- target_ = path;
- std::vector<FilePath::StringType> comps;
- target_.GetComponents(&comps);
- DCHECK(!comps.empty());
- for (std::vector<FilePath::StringType>::const_iterator comp(++comps.begin());
- comp != comps.end(); ++comp) {
- watches_.push_back(WatchEntry(InotifyReader::kInvalidWatch, *comp));
- }
- watches_.push_back(WatchEntry(InotifyReader::kInvalidWatch,
- FilePath::StringType()));
- return UpdateWatches();
-}
-
-void FilePathWatcherImpl::Cancel() {
- // Switch to the file thread if necessary so we can access |watches_|.
- if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(this, &FilePathWatcherImpl::Cancel));
- return;
- }
-
- for (WatchVector::iterator watch_entry(watches_.begin());
- watch_entry != watches_.end(); ++watch_entry) {
- if (watch_entry->watch_ != InotifyReader::kInvalidWatch)
- Singleton<InotifyReader>::get()->RemoveWatch(watch_entry->watch_, this);
- }
- watches_.clear();
- delegate_ = NULL;
- target_.clear();
-}
-
-bool FilePathWatcherImpl::UpdateWatches() {
- // Ensure this runs on the file thread exclusively in order to avoid
- // concurrency issues.
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- // Walk the list of watches and update them as we go.
- FilePath path(FILE_PATH_LITERAL("/"));
- bool path_valid = true;
- for (WatchVector::iterator watch_entry(watches_.begin());
- watch_entry != watches_.end(); ++watch_entry) {
- InotifyReader::Watch old_watch = watch_entry->watch_;
- if (path_valid) {
- watch_entry->watch_ =
- Singleton<InotifyReader>::get()->AddWatch(path, this);
- if (watch_entry->watch_ == InotifyReader::kInvalidWatch) {
- path_valid = false;
- }
- } else {
- watch_entry->watch_ = InotifyReader::kInvalidWatch;
- }
- if (old_watch != InotifyReader::kInvalidWatch &&
- old_watch != watch_entry->watch_) {
- Singleton<InotifyReader>::get()->RemoveWatch(old_watch, this);
- }
- path = path.Append(watch_entry->subdir_);
- }
-
- return true;
-}
-
-} // namespace
-
-FilePathWatcher::FilePathWatcher() {
- impl_ = new FilePathWatcherImpl();
-}
diff --git a/chrome/browser/file_path_watcher_mac.cc b/chrome/browser/file_path_watcher_mac.cc
deleted file mode 100644
index cc925a6..0000000
--- a/chrome/browser/file_path_watcher_mac.cc
+++ /dev/null
@@ -1,232 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/file_path_watcher.h"
-
-#include <CoreServices/CoreServices.h>
-#include <set>
-
-#include "base/file_path.h"
-#include "base/file_util.h"
-#include "base/logging.h"
-#include "base/mac/scoped_cftyperef.h"
-#include "base/singleton.h"
-#include "base/time.h"
-
-namespace {
-
-// The latency parameter passed to FSEventsStreamCreate().
-const CFAbsoluteTime kEventLatencySeconds = 0.3;
-
-// Mac-specific file watcher implementation based on the FSEvents API.
-class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate {
- public:
- FilePathWatcherImpl();
- virtual ~FilePathWatcherImpl() {}
-
- // Called from the FSEvents callback whenever there is a change to the paths
- void OnFilePathChanged();
-
- // (Re-)Initialize the event stream to start reporting events from
- // |start_event|.
- void UpdateEventStream(FSEventStreamEventId start_event);
-
- // FilePathWatcher::PlatformDelegate overrides.
- virtual bool Watch(const FilePath& path, FilePathWatcher::Delegate* delegate);
- virtual void Cancel();
-
- private:
- // Destroy the event stream.
- void DestroyEventStream();
-
- // Delegate to notify upon changes.
- scoped_refptr<FilePathWatcher::Delegate> delegate_;
-
- // Target path to watch (passed to delegate).
- FilePath target_;
-
- // Keep track of the last modified time of the file. We use nulltime
- // to represent the file not existing.
- base::Time last_modified_;
-
- // The time at which we processed the first notification with the
- // |last_modified_| time stamp.
- base::Time first_notification_;
-
- // Backend stream we receive event callbacks from (strong reference).
- FSEventStreamRef fsevent_stream_;
-
- // Used to detect early cancellation.
- bool canceled_;
-
- DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl);
-};
-
-// The callback passed to FSEventStreamCreate().
-void FSEventsCallback(ConstFSEventStreamRef stream,
- void* event_watcher, size_t num_events,
- void* event_paths, const FSEventStreamEventFlags flags[],
- const FSEventStreamEventId event_ids[]) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- FilePathWatcherImpl* watcher =
- reinterpret_cast<FilePathWatcherImpl*>(event_watcher);
- bool root_changed = false;
- FSEventStreamEventId root_change_at = FSEventStreamGetLatestEventId(stream);
- for (size_t i = 0; i < num_events; i++) {
- if (flags[i] & kFSEventStreamEventFlagRootChanged)
- root_changed = true;
- if (event_ids[i])
- root_change_at = std::min(root_change_at, event_ids[i]);
- }
-
- // Reinitialize the event stream if we find changes to the root. This is
- // necessary since FSEvents doesn't report any events for the subtree after
- // the directory to be watched gets created.
- if (root_changed) {
- // Resetting the event stream from within the callback fails (FSEvents spews
- // bad file descriptor errors), so post a task to do the reset.
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(watcher, &FilePathWatcherImpl::UpdateEventStream,
- root_change_at));
- }
-
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(watcher, &FilePathWatcherImpl::OnFilePathChanged));
-}
-
-// FilePathWatcherImpl implementation:
-
-FilePathWatcherImpl::FilePathWatcherImpl()
- : fsevent_stream_(NULL),
- canceled_(false) {
-}
-
-void FilePathWatcherImpl::OnFilePathChanged() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- DCHECK(!target_.empty());
-
- base::PlatformFileInfo file_info;
- bool file_exists = file_util::GetFileInfo(target_, &file_info);
- if (file_exists && (last_modified_.is_null() ||
- last_modified_ != file_info.last_modified)) {
- last_modified_ = file_info.last_modified;
- first_notification_ = base::Time::Now();
- delegate_->OnFilePathChanged(target_);
- } else if (file_exists && !first_notification_.is_null()) {
- // The target's last modification time is equal to what's on record. This
- // means that either an unrelated event occurred, or the target changed
- // again (file modification times only have a resolution of 1s). Comparing
- // file modification times against the wall clock is not reliable to find
- // out whether the change is recent, since this code might just run too
- // late. Moreover, there's no guarantee that file modification time and wall
- // clock times come from the same source.
- //
- // Instead, the time at which the first notification carrying the current
- // |last_notified_| time stamp is recorded. Later notifications that find
- // the same file modification time only need to be forwarded until wall
- // clock has advanced one second from the initial notification. After that
- // interval, client code is guaranteed to having seen the current revision
- // of the file.
- if (base::Time::Now() - first_notification_ >
- base::TimeDelta::FromSeconds(1)) {
- // Stop further notifications for this |last_modification_| time stamp.
- first_notification_ = base::Time();
- }
- delegate_->OnFilePathChanged(target_);
- } else if (!file_exists && !last_modified_.is_null()) {
- last_modified_ = base::Time();
- delegate_->OnFilePathChanged(target_);
- }
-}
-
-bool FilePathWatcherImpl::Watch(const FilePath& path,
- FilePathWatcher::Delegate* delegate) {
- DCHECK(target_.value().empty());
-
- target_ = path;
- delegate_ = delegate;
-
- FSEventStreamEventId start_event = FSEventsGetCurrentEventId();
-
- base::PlatformFileInfo file_info;
- if (file_util::GetFileInfo(target_, &file_info)) {
- last_modified_ = file_info.last_modified;
- first_notification_ = base::Time::Now();
- }
-
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(this, &FilePathWatcherImpl::UpdateEventStream,
- start_event));
-
- return true;
-}
-
-void FilePathWatcherImpl::Cancel() {
- // Switch to the UI thread if necessary, so we can tear down the event stream.
- if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(this, &FilePathWatcherImpl::Cancel));
- return;
- }
-
- canceled_ = true;
- if (fsevent_stream_)
- DestroyEventStream();
-}
-
-void FilePathWatcherImpl::UpdateEventStream(FSEventStreamEventId start_event) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // It can happen that the watcher gets canceled while tasks that call this
- // function are still in flight, so abort if this situation is detected.
- if (canceled_)
- return;
-
- if (fsevent_stream_)
- DestroyEventStream();
-
- base::mac::ScopedCFTypeRef<CFStringRef> cf_path(CFStringCreateWithCString(
- NULL, target_.value().c_str(), kCFStringEncodingMacHFS));
- base::mac::ScopedCFTypeRef<CFStringRef> cf_dir_path(CFStringCreateWithCString(
- NULL, target_.DirName().value().c_str(), kCFStringEncodingMacHFS));
- CFStringRef paths_array[] = { cf_path.get(), cf_dir_path.get() };
- base::mac::ScopedCFTypeRef<CFArrayRef> watched_paths(CFArrayCreate(
- NULL, reinterpret_cast<const void**>(paths_array), arraysize(paths_array),
- &kCFTypeArrayCallBacks));
-
- FSEventStreamContext context;
- context.version = 0;
- context.info = this;
- context.retain = NULL;
- context.release = NULL;
- context.copyDescription = NULL;
-
- fsevent_stream_ = FSEventStreamCreate(NULL, &FSEventsCallback, &context,
- watched_paths,
- start_event,
- kEventLatencySeconds,
- kFSEventStreamCreateFlagWatchRoot);
- FSEventStreamScheduleWithRunLoop(fsevent_stream_, CFRunLoopGetCurrent(),
- kCFRunLoopDefaultMode);
- if (!FSEventStreamStart(fsevent_stream_)) {
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(delegate_.get(),
- &FilePathWatcher::Delegate::OnError));
- }
-}
-
-void FilePathWatcherImpl::DestroyEventStream() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- FSEventStreamStop(fsevent_stream_);
- FSEventStreamInvalidate(fsevent_stream_);
- FSEventStreamRelease(fsevent_stream_);
- fsevent_stream_ = NULL;
-}
-
-} // namespace
-
-FilePathWatcher::FilePathWatcher() {
- impl_ = new FilePathWatcherImpl();
-}
diff --git a/chrome/browser/file_path_watcher_stub.cc b/chrome/browser/file_path_watcher_stub.cc
deleted file mode 100644
index 5112f48..0000000
--- a/chrome/browser/file_path_watcher_stub.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// 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.
-
-// This file exists for Unix systems which don't have the inotify headers, and
-// thus cannot build file_watcher_inotify.cc
-
-#include "chrome/browser/file_path_watcher.h"
-
-class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate {
- public:
- virtual bool Watch(const FilePath& path, FileWatcher::Delegate* delegate) {
- return false;
- }
-};
-
-FilePathWatcher::FilePathWatcher() {
- impl_ = new FilePathWatcherImpl();
-}
diff --git a/chrome/browser/file_path_watcher_win.cc b/chrome/browser/file_path_watcher_win.cc
deleted file mode 100644
index 7e1f4ec..0000000
--- a/chrome/browser/file_path_watcher_win.cc
+++ /dev/null
@@ -1,244 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/file_path_watcher.h"
-
-#include "base/file_path.h"
-#include "base/file_util.h"
-#include "base/logging.h"
-#include "base/object_watcher.h"
-#include "base/ref_counted.h"
-#include "base/time.h"
-
-namespace {
-
-class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate,
- public base::ObjectWatcher::Delegate {
- public:
- FilePathWatcherImpl() : delegate_(NULL), handle_(INVALID_HANDLE_VALUE) {}
-
- virtual bool Watch(const FilePath& path, FilePathWatcher::Delegate* delegate);
- virtual void Cancel();
-
- // Callback from MessageLoopForIO.
- virtual void OnObjectSignaled(HANDLE object);
-
- private:
- virtual ~FilePathWatcherImpl();
-
- // Setup a watch handle for directory |dir|. Returns true if no fatal error
- // occurs. |handle| will receive the handle value if |dir| is watchable,
- // otherwise INVALID_HANDLE_VALUE.
- static bool SetupWatchHandle(const FilePath& dir, HANDLE* handle)
- WARN_UNUSED_RESULT;
-
- // (Re-)Initialize the watch handle.
- bool UpdateWatch() WARN_UNUSED_RESULT;
-
- // Destroy the watch handle.
- void DestroyWatch();
-
- // Delegate to notify upon changes.
- scoped_refptr<FilePathWatcher::Delegate> delegate_;
-
- // Path we're supposed to watch (passed to delegate).
- FilePath target_;
-
- // Handle for FindFirstChangeNotification.
- HANDLE handle_;
-
- // ObjectWatcher to watch handle_ for events.
- base::ObjectWatcher watcher_;
-
- // Keep track of the last modified time of the file. We use nulltime
- // to represent the file not existing.
- base::Time last_modified_;
-
- // The time at which we processed the first notification with the
- // |last_modified_| time stamp.
- base::Time first_notification_;
-
- DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl);
-};
-
-bool FilePathWatcherImpl::Watch(const FilePath& path,
- FilePathWatcher::Delegate* delegate) {
- DCHECK(target_.value().empty()); // Can only watch one path.
- delegate_ = delegate;
- target_ = path;
-
- if (!UpdateWatch())
- return false;
-
- watcher_.StartWatching(handle_, this);
-
- return true;
-}
-
-void FilePathWatcherImpl::Cancel() {
- // Switch to the file thread if necessary so we can stop |watcher_|.
- if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(this, &FilePathWatcherImpl::Cancel));
- return;
- }
-
- if (handle_ != INVALID_HANDLE_VALUE)
- DestroyWatch();
-}
-
-void FilePathWatcherImpl::OnObjectSignaled(HANDLE object) {
- DCHECK(object == handle_);
- // Make sure we stay alive through the body of this function.
- scoped_refptr<FilePathWatcherImpl> keep_alive(this);
-
- if (!UpdateWatch()) {
- delegate_->OnError();
- return;
- }
-
- // Check whether the event applies to |target_| and notify the delegate.
- base::PlatformFileInfo file_info;
- bool file_exists = file_util::GetFileInfo(target_, &file_info);
- if (file_exists && (last_modified_.is_null() ||
- last_modified_ != file_info.last_modified)) {
- last_modified_ = file_info.last_modified;
- first_notification_ = base::Time::Now();
- delegate_->OnFilePathChanged(target_);
- } else if (file_exists && !first_notification_.is_null()) {
- // The target's last modification time is equal to what's on record. This
- // means that either an unrelated event occurred, or the target changed
- // again (file modification times only have a resolution of 1s). Comparing
- // file modification times against the wall clock is not reliable to find
- // out whether the change is recent, since this code might just run too
- // late. Moreover, there's no guarantee that file modification time and wall
- // clock times come from the same source.
- //
- // Instead, the time at which the first notification carrying the current
- // |last_notified_| time stamp is recorded. Later notifications that find
- // the same file modification time only need to be forwarded until wall
- // clock has advanced one second from the initial notification. After that
- // interval, client code is guaranteed to having seen the current revision
- // of the file.
- if (base::Time::Now() - first_notification_ >
- base::TimeDelta::FromSeconds(1)) {
- // Stop further notifications for this |last_modification_| time stamp.
- first_notification_ = base::Time();
- }
- delegate_->OnFilePathChanged(target_);
- } else if (!file_exists && !last_modified_.is_null()) {
- last_modified_ = base::Time();
- delegate_->OnFilePathChanged(target_);
- }
-
- // The watch may have been cancelled by the callback.
- if (handle_ != INVALID_HANDLE_VALUE)
- watcher_.StartWatching(handle_, this);
-}
-
-FilePathWatcherImpl::~FilePathWatcherImpl() {
- if (handle_ != INVALID_HANDLE_VALUE)
- DestroyWatch();
-}
-
-// static
-bool FilePathWatcherImpl::SetupWatchHandle(const FilePath& dir,
- HANDLE* handle) {
- *handle = FindFirstChangeNotification(
- dir.value().c_str(),
- false, // Don't watch subtrees
- FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_SIZE |
- FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_DIR_NAME |
- FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SECURITY);
- if (*handle != INVALID_HANDLE_VALUE) {
- // Make sure the handle we got points to an existing directory. It seems
- // that windows sometimes hands out watches to direectories that are
- // about to go away, but doesn't sent notifications if that happens.
- if (!file_util::DirectoryExists(dir)) {
- FindCloseChangeNotification(*handle);
- *handle = INVALID_HANDLE_VALUE;
- }
- return true;
- }
-
- // If FindFirstChangeNotification failed because the target directory
- // doesn't exist, access is denied (happens if the file is already gone but
- // there are still handles open), or the target is not a directory, try the
- // immediate parent directory instead.
- DWORD error_code = GetLastError();
- if (error_code != ERROR_FILE_NOT_FOUND &&
- error_code != ERROR_PATH_NOT_FOUND &&
- error_code != ERROR_ACCESS_DENIED &&
- error_code != ERROR_SHARING_VIOLATION &&
- error_code != ERROR_DIRECTORY) {
- PLOG(ERROR) << "FindFirstChangeNotification failed for "
- << dir.value();
- return false;
- }
-
- return true;
-}
-
-bool FilePathWatcherImpl::UpdateWatch() {
- if (handle_ != INVALID_HANDLE_VALUE)
- DestroyWatch();
-
- base::PlatformFileInfo file_info;
- if (file_util::GetFileInfo(target_, &file_info)) {
- last_modified_ = file_info.last_modified;
- first_notification_ = base::Time::Now();
- }
-
- // Start at the target and walk up the directory chain until we succesfully
- // create a watch handle in |handle_|. |child_dirs| keeps a stack of child
- // directories stripped from target, in reverse order.
- std::vector<FilePath> child_dirs;
- FilePath watched_path(target_);
- while (true) {
- if (!SetupWatchHandle(watched_path, &handle_))
- return false;
-
- // Break if a valid handle is returned. Try the parent directory otherwise.
- if (handle_ != INVALID_HANDLE_VALUE)
- break;
-
- // Abort if we hit the root directory.
- child_dirs.push_back(watched_path.BaseName());
- FilePath parent(watched_path.DirName());
- if (parent == watched_path) {
- LOG(ERROR) << "Reached the root directory";
- return false;
- }
- watched_path = parent;
- }
-
- // At this point, handle_ is valid. However, the bottom-up search that the
- // above code performs races against directory creation. So try to walk back
- // down and see whether any children appeared in the mean time.
- while (!child_dirs.empty()) {
- watched_path = watched_path.Append(child_dirs.back());
- child_dirs.pop_back();
- HANDLE temp_handle = INVALID_HANDLE_VALUE;
- if (!SetupWatchHandle(watched_path, &temp_handle))
- return false;
- if (temp_handle == INVALID_HANDLE_VALUE)
- break;
- FindCloseChangeNotification(handle_);
- handle_ = temp_handle;
- }
-
- return true;
-}
-
-void FilePathWatcherImpl::DestroyWatch() {
- watcher_.StopWatching();
- FindCloseChangeNotification(handle_);
- handle_ = INVALID_HANDLE_VALUE;
-}
-
-} // namespace
-
-FilePathWatcher::FilePathWatcher() {
- impl_ = new FilePathWatcherImpl();
-}
diff --git a/chrome/browser/file_select_helper.cc b/chrome/browser/file_select_helper.cc
index 3ef8ad3..1604b0d 100644
--- a/chrome/browser/file_select_helper.cc
+++ b/chrome/browser/file_select_helper.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/file_select_helper.h"
+#include <string>
+
#include "app/l10n_util.h"
#include "base/file_util.h"
#include "base/string_split.h"
@@ -11,12 +13,10 @@
#include "base/utf_string_conversions.h"
#include "net/base/mime_util.h"
#include "chrome/browser/platform_util.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/shell_dialogs.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_source.h"
#include "chrome/common/render_messages_params.h"
diff --git a/chrome/browser/file_system/browser_file_system_callback_dispatcher.cc b/chrome/browser/file_system/browser_file_system_callback_dispatcher.cc
deleted file mode 100644
index 810bf3f..0000000
--- a/chrome/browser/file_system/browser_file_system_callback_dispatcher.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-// 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.
-
-#include "chrome/browser/file_system/browser_file_system_callback_dispatcher.h"
-
-#include "chrome/browser/file_system/file_system_dispatcher_host.h"
-#include "chrome/common/render_messages.h"
-
-BrowserFileSystemCallbackDispatcher::BrowserFileSystemCallbackDispatcher(
- FileSystemDispatcherHost* dispatcher_host, int request_id)
- : dispatcher_host_(dispatcher_host),
- request_id_(request_id) {
- DCHECK(dispatcher_host_);
-}
-
-BrowserFileSystemCallbackDispatcher::~BrowserFileSystemCallbackDispatcher() {}
-
-void BrowserFileSystemCallbackDispatcher::DidSucceed() {
- dispatcher_host_->Send(new ViewMsg_FileSystem_DidSucceed(request_id_));
- dispatcher_host_->RemoveCompletedOperation(request_id_);
-}
-
-void BrowserFileSystemCallbackDispatcher::DidReadMetadata(
- const base::PlatformFileInfo& info) {
- dispatcher_host_->Send(new ViewMsg_FileSystem_DidReadMetadata(
- request_id_, info));
- dispatcher_host_->RemoveCompletedOperation(request_id_);
-}
-
-void BrowserFileSystemCallbackDispatcher::DidReadDirectory(
- const std::vector<base::FileUtilProxy::Entry>& entries, bool has_more) {
- dispatcher_host_->Send(new ViewMsg_FileSystem_DidReadDirectory(
- request_id_, entries, has_more));
- dispatcher_host_->RemoveCompletedOperation(request_id_);
-}
-
-void BrowserFileSystemCallbackDispatcher::DidOpenFileSystem(
- const std::string& name, const FilePath& path) {
- dispatcher_host_->Send(
- new ViewMsg_OpenFileSystemRequest_Complete(
- request_id_, !path.empty(), name, path));
- dispatcher_host_->RemoveCompletedOperation(request_id_);
-}
-
-void BrowserFileSystemCallbackDispatcher::DidFail(
- base::PlatformFileError error_code) {
- dispatcher_host_->Send(new ViewMsg_FileSystem_DidFail(
- request_id_, error_code));
- dispatcher_host_->RemoveCompletedOperation(request_id_);
-}
-
-void BrowserFileSystemCallbackDispatcher::DidWrite(
- int64 bytes,
- bool complete) {
- dispatcher_host_->Send(new ViewMsg_FileSystem_DidWrite(
- request_id_, bytes, complete));
- if (complete)
- dispatcher_host_->RemoveCompletedOperation(request_id_);
-}
diff --git a/chrome/browser/file_system/browser_file_system_callback_dispatcher.h b/chrome/browser/file_system/browser_file_system_callback_dispatcher.h
deleted file mode 100644
index 7e85b41..0000000
--- a/chrome/browser/file_system/browser_file_system_callback_dispatcher.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_FILE_SYSTEM_BROWSER_FILE_SYSTEM_CALLBACK_DISPATCHER_H_
-#define CHROME_BROWSER_FILE_SYSTEM_BROWSER_FILE_SYSTEM_CALLBACK_DISPATCHER_H_
-
-#include "webkit/fileapi/file_system_callback_dispatcher.h"
-
-class FileSystemDispatcherHost;
-
-class BrowserFileSystemCallbackDispatcher
- : public fileapi::FileSystemCallbackDispatcher {
- public:
- BrowserFileSystemCallbackDispatcher(FileSystemDispatcherHost* dispatcher_host,
- int request_id);
- virtual ~BrowserFileSystemCallbackDispatcher();
-
- // FileSystemCallbackDispatcher implementation.
- virtual void DidSucceed();
- virtual void DidReadMetadata(const base::PlatformFileInfo& file_info);
- virtual void DidReadDirectory(
- const std::vector<base::FileUtilProxy::Entry>& entries,
- bool has_more);
- virtual void DidOpenFileSystem(const std::string& name,
- const FilePath& root_path);
- virtual void DidFail(base::PlatformFileError error_code);
- virtual void DidWrite(int64 bytes, bool complete);
-
- private:
- scoped_refptr<FileSystemDispatcherHost> dispatcher_host_;
- int request_id_;
-};
-
-#endif // CHROME_BROWSER_FILE_SYSTEM_BROWSER_FILE_SYSTEM_CALLBACK_DISPATCHER_H_
diff --git a/chrome/browser/file_system/browser_file_system_context.cc b/chrome/browser/file_system/browser_file_system_context.cc
deleted file mode 100644
index bbc4806..0000000
--- a/chrome/browser/file_system/browser_file_system_context.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// 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.
-
-#include "chrome/browser/file_system/browser_file_system_context.h"
-
-#include "base/file_path.h"
-#include "base/command_line.h"
-#include "chrome/common/chrome_switches.h"
-#include "webkit/fileapi/file_system_quota_manager.h"
-
-BrowserFileSystemContext::BrowserFileSystemContext(
- const FilePath& profile_path, bool is_incognito)
- : fileapi::SandboxedFileSystemContext(
- BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
- profile_path,
- is_incognito,
- CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kAllowFileAccessFromFiles),
- CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kUnlimitedQuotaForFiles)) {
-}
-
-void BrowserFileSystemContext::SetOriginQuotaUnlimited(const GURL& url) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- quota_manager()->SetOriginQuotaUnlimited(url);
-}
-
-void BrowserFileSystemContext::ResetOriginQuotaUnlimited(const GURL& url) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- quota_manager()->ResetOriginQuotaUnlimited(url);
-}
-
-BrowserFileSystemContext::~BrowserFileSystemContext() {}
diff --git a/chrome/browser/file_system/browser_file_system_context.h b/chrome/browser/file_system/browser_file_system_context.h
deleted file mode 100644
index 8082179..0000000
--- a/chrome/browser/file_system/browser_file_system_context.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_FILE_SYSTEM_BROWSER_FILE_SYSTEM_CONTEXT_H_
-#define CHROME_BROWSER_FILE_SYSTEM_BROWSER_FILE_SYSTEM_CONTEXT_H_
-
-#include "base/ref_counted.h"
-#include "base/scoped_ptr.h"
-#include "chrome/browser/browser_thread.h"
-#include "webkit/fileapi/sandboxed_file_system_context.h"
-
-class FilePath;
-class GURL;
-
-// This is owned by profile and shared by all the FileSystemDispatcherHost
-// that shared by the same profile. This class is just a thin wrapper around
-// fileapi::SandboxedFileSystemContext.
-class BrowserFileSystemContext
- : public base::RefCountedThreadSafe<BrowserFileSystemContext,
- BrowserThread::DeleteOnIOThread>,
- public fileapi::SandboxedFileSystemContext {
- public:
- BrowserFileSystemContext(const FilePath& profile_path, bool is_incognito);
- virtual ~BrowserFileSystemContext();
-
- // Quota related methods.
- void SetOriginQuotaUnlimited(const GURL& url);
- void ResetOriginQuotaUnlimited(const GURL& url);
-
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(BrowserFileSystemContext);
-};
-
-#endif // CHROME_BROWSER_FILE_SYSTEM_BROWSER_FILE_SYSTEM_CONTEXT_H_
diff --git a/chrome/browser/file_system/browser_file_system_helper.cc b/chrome/browser/file_system/browser_file_system_helper.cc
new file mode 100644
index 0000000..2ce4f36
--- /dev/null
+++ b/chrome/browser/file_system/browser_file_system_helper.cc
@@ -0,0 +1,23 @@
+// 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.
+
+#include "chrome/browser/file_system/browser_file_system_helper.h"
+
+#include "base/file_path.h"
+#include "base/command_line.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/common/chrome_switches.h"
+
+scoped_refptr<fileapi::SandboxedFileSystemContext> CreateFileSystemContext(
+ const FilePath& profile_path, bool is_incognito) {
+ return new fileapi::SandboxedFileSystemContext(
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO),
+ profile_path,
+ is_incognito,
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kAllowFileAccessFromFiles),
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kUnlimitedQuotaForFiles));
+}
diff --git a/chrome/browser/file_system/browser_file_system_helper.h b/chrome/browser/file_system/browser_file_system_helper.h
new file mode 100644
index 0000000..56ec3e2
--- /dev/null
+++ b/chrome/browser/file_system/browser_file_system_helper.h
@@ -0,0 +1,17 @@
+// 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.
+
+#ifndef CHROME_BROWSER_FILE_SYSTEM_BROWSER_FILE_SYSTEM_HELPER_H_
+#define CHROME_BROWSER_FILE_SYSTEM_BROWSER_FILE_SYSTEM_HELPER_H_
+
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+#include "webkit/fileapi/sandboxed_file_system_context.h"
+
+// Convenient method that returns SandboxedFileSystemContext
+// constructed for the browser process.
+scoped_refptr<fileapi::SandboxedFileSystemContext> CreateFileSystemContext(
+ const FilePath& profile_path, bool is_incognito);
+
+#endif // CHROME_BROWSER_FILE_SYSTEM_BROWSER_FILE_SYSTEM_HELPER_H_
diff --git a/chrome/browser/file_system/file_system_dispatcher_host.cc b/chrome/browser/file_system/file_system_dispatcher_host.cc
index 12b4d19..98b14a5 100644
--- a/chrome/browser/file_system/file_system_dispatcher_host.cc
+++ b/chrome/browser/file_system/file_system_dispatcher_host.cc
@@ -4,61 +4,102 @@
#include "chrome/browser/file_system/file_system_dispatcher_host.h"
+#include <string>
+#include <vector>
+
#include "base/file_path.h"
#include "base/thread.h"
#include "base/time.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/file_system/browser_file_system_callback_dispatcher.h"
-#include "chrome/browser/file_system/browser_file_system_context.h"
-#include "chrome/browser/host_content_settings_map.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/net/chrome_url_request_context.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/browser_render_process_host.h"
#include "chrome/common/net/url_request_context_getter.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/render_messages_params.h"
#include "googleurl/src/gurl.h"
#include "net/url_request/url_request_context.h"
+#include "webkit/fileapi/file_system_callback_dispatcher.h"
#include "webkit/fileapi/file_system_operation.h"
#include "webkit/fileapi/file_system_path_manager.h"
#include "webkit/fileapi/file_system_quota_manager.h"
+#include "webkit/fileapi/sandboxed_file_system_context.h"
#include "webkit/fileapi/sandboxed_file_system_operation.h"
+using fileapi::FileSystemCallbackDispatcher;
using fileapi::FileSystemQuotaManager;
using fileapi::SandboxedFileSystemOperation;
-FileSystemDispatcherHost::FileSystemDispatcherHost(
- IPC::Message::Sender* sender, Profile* profile)
- : message_sender_(sender),
- process_handle_(0),
- shutdown_(false),
- context_(profile->GetFileSystemContext()),
+class BrowserFileSystemCallbackDispatcher
+ : public FileSystemCallbackDispatcher {
+ public:
+ BrowserFileSystemCallbackDispatcher(
+ FileSystemDispatcherHost* dispatcher_host, int request_id)
+ : dispatcher_host_(dispatcher_host),
+ request_id_(request_id) {
+ DCHECK(dispatcher_host_);
+ }
+
+ virtual ~BrowserFileSystemCallbackDispatcher() {
+ dispatcher_host_->UnregisterOperation(request_id_);
+ }
+
+ virtual void DidSucceed() {
+ dispatcher_host_->Send(new ViewMsg_FileSystem_DidSucceed(request_id_));
+ }
+
+ virtual void DidReadMetadata(const base::PlatformFileInfo& info) {
+ dispatcher_host_->Send(new ViewMsg_FileSystem_DidReadMetadata(
+ request_id_, info));
+ }
+
+ virtual void DidReadDirectory(
+ const std::vector<base::FileUtilProxy::Entry>& entries, bool has_more) {
+ dispatcher_host_->Send(new ViewMsg_FileSystem_DidReadDirectory(
+ request_id_, entries, has_more));
+ }
+
+ virtual void DidOpenFileSystem(const std::string& name,
+ const FilePath& path) {
+ dispatcher_host_->Send(
+ new ViewMsg_OpenFileSystemRequest_Complete(
+ request_id_, !path.empty(), name, path));
+ }
+
+ virtual void DidFail(base::PlatformFileError error_code) {
+ dispatcher_host_->Send(new ViewMsg_FileSystem_DidFail(
+ request_id_, error_code));
+ }
+
+ virtual void DidWrite(int64 bytes, bool complete) {
+ dispatcher_host_->Send(new ViewMsg_FileSystem_DidWrite(
+ request_id_, bytes, complete));
+ }
+
+ private:
+ scoped_refptr<FileSystemDispatcherHost> dispatcher_host_;
+ int request_id_;
+};
+
+FileSystemDispatcherHost::FileSystemDispatcherHost(Profile* profile)
+ : context_(profile->GetFileSystemContext()),
host_content_settings_map_(profile->GetHostContentSettingsMap()),
request_context_getter_(profile->GetRequestContext()) {
- DCHECK(message_sender_);
}
FileSystemDispatcherHost::FileSystemDispatcherHost(
- IPC::Message::Sender* sender, ChromeURLRequestContext* context)
- : message_sender_(sender),
- process_handle_(0),
- shutdown_(false),
- context_(context->browser_file_system_context()),
+ ChromeURLRequestContext* context)
+ : context_(context->file_system_context()),
host_content_settings_map_(context->host_content_settings_map()),
request_context_(context) {
- DCHECK(message_sender_);
}
FileSystemDispatcherHost::~FileSystemDispatcherHost() {
}
-void FileSystemDispatcherHost::Init(base::ProcessHandle process_handle) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK(!shutdown_);
- DCHECK(!process_handle_);
- DCHECK(process_handle);
- process_handle_ = process_handle;
+void FileSystemDispatcherHost::OnChannelConnected(int32 peer_pid) {
+ BrowserMessageFilter::OnChannelConnected(peer_pid);
+
if (request_context_getter_.get()) {
DCHECK(!request_context_.get());
request_context_ = request_context_getter_->GetURLRequestContext();
@@ -66,14 +107,8 @@ void FileSystemDispatcherHost::Init(base::ProcessHandle process_handle) {
DCHECK(request_context_.get());
}
-void FileSystemDispatcherHost::Shutdown() {
- message_sender_ = NULL;
- shutdown_ = true;
-}
-
bool FileSystemDispatcherHost::OnMessageReceived(
const IPC::Message& message, bool* message_was_ok) {
- DCHECK(!shutdown_);
*message_was_ok = true;
bool handled = true;
IPC_BEGIN_MESSAGE_MAP_EX(FileSystemDispatcherHost, message, *message_was_ok)
@@ -197,14 +232,6 @@ void FileSystemDispatcherHost::OnCancel(
}
}
-void FileSystemDispatcherHost::Send(IPC::Message* message) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (!shutdown_ && message_sender_)
- message_sender_->Send(message);
- else
- delete message;
-}
-
SandboxedFileSystemOperation* FileSystemDispatcherHost::GetNewOperation(
int request_id) {
BrowserFileSystemCallbackDispatcher* dispatcher =
@@ -212,12 +239,12 @@ SandboxedFileSystemOperation* FileSystemDispatcherHost::GetNewOperation(
SandboxedFileSystemOperation* operation = new SandboxedFileSystemOperation(
dispatcher,
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
- context_.get());
+ context_);
operations_.AddWithID(operation, request_id);
return operation;
}
-void FileSystemDispatcherHost::RemoveCompletedOperation(int request_id) {
+void FileSystemDispatcherHost::UnregisterOperation(int request_id) {
DCHECK(operations_.Lookup(request_id));
operations_.Remove(request_id);
}
diff --git a/chrome/browser/file_system/file_system_dispatcher_host.h b/chrome/browser/file_system/file_system_dispatcher_host.h
index 2cfe4f6..ab57d09 100644
--- a/chrome/browser/file_system/file_system_dispatcher_host.h
+++ b/chrome/browser/file_system/file_system_dispatcher_host.h
@@ -9,9 +9,7 @@
#include "base/basictypes.h"
#include "base/id_map.h"
-#include "base/process.h"
-#include "base/ref_counted.h"
-#include "ipc/ipc_message.h"
+#include "chrome/browser/browser_message_filter.h"
#include "webkit/fileapi/file_system_types.h"
namespace base {
@@ -19,34 +17,33 @@ class Time;
}
class ChromeURLRequestContext;
-class BrowserFileSystemContext;
class FilePath;
class GURL;
class HostContentSettingsMap;
class Profile;
class Receiver;
-class ResourceMessageFilter;
+class RenderMessageFilter;
class URLRequestContext;
class URLRequestContextGetter;
namespace fileapi {
+class SandboxedFileSystemContext;
class SandboxedFileSystemOperation;
}
-class FileSystemDispatcherHost
- : public base::RefCountedThreadSafe<FileSystemDispatcherHost> {
+class FileSystemDispatcherHost : public BrowserMessageFilter {
public:
// Used by the renderer.
- FileSystemDispatcherHost(IPC::Message::Sender* sender,
- Profile* profile);
+ explicit FileSystemDispatcherHost(Profile* profile);
// Used by the worker, since it has the context handy already.
- FileSystemDispatcherHost(IPC::Message::Sender* sender,
- ChromeURLRequestContext* context);
+ explicit FileSystemDispatcherHost(ChromeURLRequestContext* context);
~FileSystemDispatcherHost();
- void Init(base::ProcessHandle process_handle);
- void Shutdown();
- bool OnMessageReceived(const IPC::Message& message, bool* message_was_ok);
+ // BrowserMessageFilter implementation.
+ virtual void OnChannelConnected(int32 peer_pid);
+ virtual bool OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok);
+
void OnOpenFileSystem(int request_id,
const GURL& origin_url,
@@ -78,29 +75,19 @@ class FileSystemDispatcherHost
const base::Time& last_access_time,
const base::Time& last_modified_time);
void OnCancel(int request_id, int request_to_cancel);
- void Send(IPC::Message* message);
- void RemoveCompletedOperation(int request_id);
+ void UnregisterOperation(int request_id);
private:
// Creates a new SandboxedFileSystemOperation.
fileapi::SandboxedFileSystemOperation* GetNewOperation(int request_id);
- // The sender to be used for sending out IPC messages.
- IPC::Message::Sender* message_sender_;
-
- // The handle of this process.
- base::ProcessHandle process_handle_;
-
- bool shutdown_;
-
- scoped_refptr<BrowserFileSystemContext> context_;
+ scoped_refptr<fileapi::SandboxedFileSystemContext> context_;
// Used to look up permissions.
scoped_refptr<HostContentSettingsMap> host_content_settings_map_;
// Keeps ongoing file system operations.
- typedef IDMap<fileapi::SandboxedFileSystemOperation, IDMapOwnPointer>
- OperationsMap;
+ typedef IDMap<fileapi::SandboxedFileSystemOperation> OperationsMap;
OperationsMap operations_;
// This holds the URLRequestContextGetter until Init() can be called from the
diff --git a/chrome/browser/find_backend_unittest.cc b/chrome/browser/find_backend_unittest.cc
deleted file mode 100644
index ac8c5ce..0000000
--- a/chrome/browser/find_backend_unittest.cc
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright (c) 2009 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/string16.h"
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/find_bar_state.h"
-#include "chrome/browser/renderer_host/test/test_render_view_host.h"
-#include "chrome/browser/tab_contents/test_tab_contents.h"
-#include "chrome/common/url_constants.h"
-#include "chrome/test/testing_profile.h"
-
-typedef RenderViewHostTestHarness FindBackendTest;
-
-namespace {
-
-string16 FindPrepopulateText(TabContents* contents) {
- return FindBarState::GetLastPrepopulateText(contents->profile());
-}
-
-} // end namespace
-
-// This test takes two TabContents objects, searches in both of them and
-// tests the internal state for find_text and find_prepopulate_text.
-TEST_F(FindBackendTest, InternalState) {
- // Initial state for the TabContents is blank strings.
- EXPECT_EQ(string16(), FindPrepopulateText(contents()));
- EXPECT_EQ(string16(), contents()->find_text());
-
- // Get another TabContents object ready.
- TestTabContents contents2(profile_.get(), NULL);
-
- // No search has still been issued, strings should be blank.
- EXPECT_EQ(string16(), FindPrepopulateText(contents()));
- EXPECT_EQ(string16(), contents()->find_text());
- EXPECT_EQ(string16(), FindPrepopulateText(&contents2));
- EXPECT_EQ(string16(), contents2.find_text());
-
- string16 search_term1 = ASCIIToUTF16(" I had a 401K ");
- string16 search_term2 = ASCIIToUTF16(" but the economy ");
- string16 search_term3 = ASCIIToUTF16(" eated it. ");
-
- // Start searching in the first TabContents, searching forwards but not case
- // sensitive (as indicated by the last two params).
- contents()->StartFinding(search_term1, true, false);
-
- // Pre-populate string should always match between the two, but find_text
- // should not.
- EXPECT_EQ(search_term1, FindPrepopulateText(contents()));
- EXPECT_EQ(search_term1, contents()->find_text());
- EXPECT_EQ(search_term1, FindPrepopulateText(&contents2));
- EXPECT_EQ(string16(), contents2.find_text());
-
- // Now search in the other TabContents, searching forwards but not case
- // sensitive (as indicated by the last two params).
- contents2.StartFinding(search_term2, true, false);
-
- // Again, pre-populate string should always match between the two, but
- // find_text should not.
- EXPECT_EQ(search_term2, FindPrepopulateText(contents()));
- EXPECT_EQ(search_term1, contents()->find_text());
- EXPECT_EQ(search_term2, FindPrepopulateText(&contents2));
- EXPECT_EQ(search_term2, contents2.find_text());
-
- // Search again in the first TabContents, searching forwards but not case
- // sensitive (as indicated by the last two params).
- contents()->StartFinding(search_term3, true, false);
-
- // Once more, pre-populate string should always match between the two, but
- // find_text should not.
- EXPECT_EQ(search_term3, FindPrepopulateText(contents()));
- EXPECT_EQ(search_term3, contents()->find_text());
- EXPECT_EQ(search_term3, FindPrepopulateText(&contents2));
- EXPECT_EQ(search_term2, contents2.find_text());
-}
diff --git a/chrome/browser/find_bar.h b/chrome/browser/find_bar.h
deleted file mode 100644
index 041643f..0000000
--- a/chrome/browser/find_bar.h
+++ /dev/null
@@ -1,95 +0,0 @@
-// 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.
-//
-// This is an interface for the platform specific FindBar. It is responsible
-// for drawing the FindBar bar on the platform and is owned by the
-// FindBarController.
-
-#ifndef CHROME_BROWSER_FIND_BAR_H_
-#define CHROME_BROWSER_FIND_BAR_H_
-#pragma once
-
-#include "base/string16.h"
-#include "gfx/rect.h"
-
-class FindBarController;
-class FindBarTesting;
-class FindNotificationDetails;
-
-class FindBar {
- public:
- virtual ~FindBar() { }
-
- // Accessor and setter for the FindBarController.
- virtual FindBarController* GetFindBarController() const = 0;
- virtual void SetFindBarController(
- FindBarController* find_bar_controller) = 0;
-
- // Shows the find bar. Any previous search string will again be visible.
- // If |animate| is true, we try to slide the find bar in.
- virtual void Show(bool animate) = 0;
-
- // Hide the find bar. If |animate| is true, we try to slide the find bar
- // away.
- virtual void Hide(bool animate) = 0;
-
- // Restore the selected text in the find box and focus it.
- virtual void SetFocusAndSelection() = 0;
-
- // Clear the text in the find box.
- virtual void ClearResults(const FindNotificationDetails& results) = 0;
-
- // Stop the animation.
- virtual void StopAnimation() = 0;
-
- // If the find bar obscures the search results we need to move the window. To
- // do that we need to know what is selected on the page. We simply calculate
- // where it would be if we place it on the left of the selection and if it
- // doesn't fit on the screen we try the right side. The parameter
- // |selection_rect| is expected to have coordinates relative to the top of
- // the web page area. If |no_redraw| is true, the window will be moved without
- // redrawing siblings.
- virtual void MoveWindowIfNecessary(const gfx::Rect& selection_rect,
- bool no_redraw) = 0;
-
- // Set the text in the find box.
- virtual void SetFindText(const string16& find_text) = 0;
-
- // Updates the FindBar with the find result details contained within the
- // specified |result|.
- virtual void UpdateUIForFindResult(const FindNotificationDetails& result,
- const string16& find_text) = 0;
-
- // No match was found; play an audible alert.
- virtual void AudibleAlert() = 0;
-
- virtual bool IsFindBarVisible() = 0;
-
- // Upon dismissing the window, restore focus to the last focused view which is
- // not FindBarView or any of its children.
- virtual void RestoreSavedFocus() = 0;
-
- // Returns a pointer to the testing interface to the FindBar, or NULL
- // if there is none.
- virtual FindBarTesting* GetFindBarTesting() = 0;
-};
-
-class FindBarTesting {
- public:
- virtual ~FindBarTesting() { }
-
- // Computes the location of the find bar and whether it is fully visible in
- // its parent window. The return value indicates if the window is visible at
- // all. Both out arguments are optional.
- //
- // This is used for UI tests of the find bar. If the find bar is not currently
- // shown (return value of false), the out params will be {(0, 0), false}.
- virtual bool GetFindBarWindowInfo(gfx::Point* position,
- bool* fully_visible) = 0;
-
- // Gets the search string currently visible in the Find box.
- virtual string16 GetFindText() = 0;
-};
-
-#endif // CHROME_BROWSER_FIND_BAR_H_
diff --git a/chrome/browser/find_bar_controller.cc b/chrome/browser/find_bar_controller.cc
deleted file mode 100644
index da0daf3..0000000
--- a/chrome/browser/find_bar_controller.cc
+++ /dev/null
@@ -1,225 +0,0 @@
-// 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.
-
-#include "chrome/browser/find_bar_controller.h"
-
-#include "base/i18n/rtl.h"
-#include "build/build_config.h"
-#include "chrome/browser/find_bar.h"
-#include "chrome/browser/find_bar_state.h"
-#include "chrome/browser/tab_contents/navigation_entry.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "gfx/rect.h"
-
-// The minimum space between the FindInPage window and the search result.
-static const int kMinFindWndDistanceFromSelection = 5;
-
-FindBarController::FindBarController(FindBar* find_bar)
- : find_bar_(find_bar),
- tab_contents_(NULL),
- last_reported_matchcount_(0) {
-}
-
-FindBarController::~FindBarController() {
- DCHECK(!tab_contents_);
-}
-
-void FindBarController::Show() {
- // Only show the animation if we're not already showing a find bar for the
- // selected TabContents.
- if (!tab_contents_->find_ui_active()) {
- MaybeSetPrepopulateText();
-
- tab_contents_->set_find_ui_active(true);
- find_bar_->Show(true);
- }
- find_bar_->SetFocusAndSelection();
-}
-
-void FindBarController::EndFindSession(SelectionAction action) {
- find_bar_->Hide(true);
-
- // |tab_contents_| can be NULL for a number of reasons, for example when the
- // tab is closing. We must guard against that case. See issue 8030.
- if (tab_contents_) {
- // When we hide the window, we need to notify the renderer that we are done
- // for now, so that we can abort the scoping effort and clear all the
- // tickmarks and highlighting.
- tab_contents_->StopFinding(action);
-
- if (action != kKeepSelection)
- find_bar_->ClearResults(tab_contents_->find_result());
-
- // When we get dismissed we restore the focus to where it belongs.
- find_bar_->RestoreSavedFocus();
- }
-}
-
-void FindBarController::ChangeTabContents(TabContents* contents) {
- if (tab_contents_) {
- registrar_.RemoveAll();
- find_bar_->StopAnimation();
- }
-
- tab_contents_ = contents;
-
- // Hide any visible find window from the previous tab if NULL |tab_contents|
- // is passed in or if the find UI is not active in the new tab.
- if (find_bar_->IsFindBarVisible() &&
- (!tab_contents_ || !tab_contents_->find_ui_active())) {
- find_bar_->Hide(false);
- }
-
- if (!tab_contents_)
- return;
-
- registrar_.Add(this, NotificationType::FIND_RESULT_AVAILABLE,
- Source<TabContents>(tab_contents_));
- registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
- Source<NavigationController>(&tab_contents_->controller()));
-
- MaybeSetPrepopulateText();
-
- if (tab_contents_->find_ui_active()) {
- // A tab with a visible find bar just got selected and we need to show the
- // find bar but without animation since it was already animated into its
- // visible state. We also want to reset the window location so that
- // we don't surprise the user by popping up to the left for no apparent
- // reason.
- find_bar_->Show(false);
- }
-
- UpdateFindBarForCurrentResult();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// FindBarHost, NotificationObserver implementation:
-
-void FindBarController::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- if (type == NotificationType::FIND_RESULT_AVAILABLE) {
- // Don't update for notifications from TabContentses other than the one we
- // are actively tracking.
- if (Source<TabContents>(source).ptr() == tab_contents_) {
- UpdateFindBarForCurrentResult();
- if (tab_contents_->find_result().final_update() &&
- tab_contents_->find_result().number_of_matches() == 0) {
- const string16& last_search = tab_contents_->previous_find_text();
- const string16& current_search = tab_contents_->find_text();
- if (last_search.find(current_search) != 0)
- find_bar_->AudibleAlert();
- }
- }
- } else if (type == NotificationType::NAV_ENTRY_COMMITTED) {
- NavigationController* source_controller =
- Source<NavigationController>(source).ptr();
- if (source_controller == &tab_contents_->controller()) {
- NavigationController::LoadCommittedDetails* commit_details =
- Details<NavigationController::LoadCommittedDetails>(details).ptr();
- PageTransition::Type transition_type =
- commit_details->entry->transition_type();
- // We hide the FindInPage window when the user navigates away, except on
- // reload.
- if (find_bar_->IsFindBarVisible()) {
- if (PageTransition::StripQualifier(transition_type) !=
- PageTransition::RELOAD) {
- EndFindSession(kKeepSelection);
- } else {
- // On Reload we want to make sure FindNext is converted to a full Find
- // to make sure highlights for inactive matches are repainted.
- tab_contents_->set_find_op_aborted(true);
- }
- }
- }
- }
-}
-
-// static
-gfx::Rect FindBarController::GetLocationForFindbarView(
- gfx::Rect view_location,
- const gfx::Rect& dialog_bounds,
- const gfx::Rect& avoid_overlapping_rect) {
- if (base::i18n::IsRTL()) {
- int boundary = dialog_bounds.width() - view_location.width();
- view_location.set_x(std::min(view_location.x(), boundary));
- } else {
- view_location.set_x(std::max(view_location.x(), dialog_bounds.x()));
- }
-
- gfx::Rect new_pos = view_location;
-
- // If the selection rectangle intersects the current position on screen then
- // we try to move our dialog to the left (right for RTL) of the selection
- // rectangle.
- if (!avoid_overlapping_rect.IsEmpty() &&
- avoid_overlapping_rect.Intersects(new_pos)) {
- if (base::i18n::IsRTL()) {
- new_pos.set_x(avoid_overlapping_rect.x() +
- avoid_overlapping_rect.width() +
- (2 * kMinFindWndDistanceFromSelection));
-
- // If we moved it off-screen to the right, we won't move it at all.
- if (new_pos.x() + new_pos.width() > dialog_bounds.width())
- new_pos = view_location; // Reset.
- } else {
- new_pos.set_x(avoid_overlapping_rect.x() - new_pos.width() -
- kMinFindWndDistanceFromSelection);
-
- // If we moved it off-screen to the left, we won't move it at all.
- if (new_pos.x() < 0)
- new_pos = view_location; // Reset.
- }
- }
-
- return new_pos;
-}
-
-void FindBarController::UpdateFindBarForCurrentResult() {
- const FindNotificationDetails& find_result = tab_contents_->find_result();
-
- // Avoid bug 894389: When a new search starts (and finds something) it reports
- // an interim match count result of 1 before the scoping effort starts. This
- // is to provide feedback as early as possible that we will find something.
- // As you add letters to the search term, this creates a flashing effect when
- // we briefly show "1 of 1" matches because there is a slight delay until
- // the scoping effort starts updating the match count. We avoid this flash by
- // ignoring interim results of 1 if we already have a positive number.
- if (find_result.number_of_matches() > -1) {
- if (last_reported_matchcount_ > 0 &&
- find_result.number_of_matches() == 1 &&
- !find_result.final_update())
- return; // Don't let interim result override match count.
- last_reported_matchcount_ = find_result.number_of_matches();
- }
-
- find_bar_->UpdateUIForFindResult(find_result, tab_contents_->find_text());
-}
-
-void FindBarController::MaybeSetPrepopulateText() {
-#if !defined(OS_MACOSX)
- // Find out what we should show in the find text box. Usually, this will be
- // the last search in this tab, but if no search has been issued in this tab
- // we use the last search string (from any tab).
- string16 find_string = tab_contents_->find_text();
- if (find_string.empty())
- find_string = tab_contents_->previous_find_text();
- if (find_string.empty()) {
- find_string =
- FindBarState::GetLastPrepopulateText(tab_contents_->profile());
- }
-
- // Update the find bar with existing results and search text, regardless of
- // whether or not the find bar is visible, so that if it's subsequently
- // shown it is showing the right state for this tab. We update the find text
- // _first_ since the FindBarView checks its emptiness to see if it should
- // clear the result count display when there's nothing in the box.
- find_bar_->SetFindText(find_string);
-#else
- // Having a per-tab find_string is not compatible with OS X's find pasteboard,
- // so we always have the same find text in all find bars. This is done through
- // the find pasteboard mechanism, so don't set the text here.
-#endif
-}
diff --git a/chrome/browser/find_bar_controller.h b/chrome/browser/find_bar_controller.h
deleted file mode 100644
index 4d949a3..0000000
--- a/chrome/browser/find_bar_controller.h
+++ /dev/null
@@ -1,89 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_FIND_BAR_CONTROLLER_H_
-#define CHROME_BROWSER_FIND_BAR_CONTROLLER_H_
-#pragma once
-
-#include "base/basictypes.h"
-#include "base/scoped_ptr.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
-
-namespace gfx {
-class Rect;
-}
-
-class FindBar;
-class TabContents;
-
-class FindBarController : public NotificationObserver {
- public:
- // An enum listing the possible actions to take on a find-in-page selection.
- enum SelectionAction {
- kKeepSelection, // Translate the find selection into a normal selection.
- kClearSelection, // Clear the find selection.
- kActivateSelection // Focus and click the selected node (for links).
- };
-
- // FindBar takes ownership of |find_bar_view|.
- explicit FindBarController(FindBar* find_bar);
-
- virtual ~FindBarController();
-
- // Shows the find bar. Any previous search string will again be visible.
- void Show();
-
- // Ends the current session.
- void EndFindSession(SelectionAction action);
-
- // Accessor for the attached TabContents.
- TabContents* tab_contents() const { return tab_contents_; }
-
- // Changes the TabContents that this FindBar is attached to. This occurs when
- // the user switches tabs in the Browser window. |contents| can be NULL.
- void ChangeTabContents(TabContents* contents);
-
- // Overridden from NotificationObserver:
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- FindBar* find_bar() const { return find_bar_.get(); }
-
- // Reposition |view_location| such that it avoids |avoid_overlapping_rect|,
- // and return the new location.
- static gfx::Rect GetLocationForFindbarView(
- gfx::Rect view_location,
- const gfx::Rect& dialog_bounds,
- const gfx::Rect& avoid_overlapping_rect);
-
- private:
- // Sents an update to the find bar with the tab contents' current result. The
- // tab_contents_ must be non-NULL before this call. Theis handles
- // de-flickering in addition to just calling the update function.
- void UpdateFindBarForCurrentResult();
-
- // For Windows and Linux this function sets the prepopulate text for the
- // Find text box. The propopulate value is the last value the user searched
- // for in the current tab, or (if blank) the last value searched for in any
- // tab. Mac has a global value for search, so this function does nothing on
- // Mac.
- void MaybeSetPrepopulateText();
-
- NotificationRegistrar registrar_;
-
- scoped_ptr<FindBar> find_bar_;
-
- // The TabContents we are currently associated with. Can be NULL.
- TabContents* tab_contents_;
-
- // The last match count we reported to the user. This is used by
- // UpdateFindBarForCurrentResult to avoid flickering.
- int last_reported_matchcount_;
-
- DISALLOW_COPY_AND_ASSIGN(FindBarController);
-};
-
-#endif // CHROME_BROWSER_FIND_BAR_CONTROLLER_H_
diff --git a/chrome/browser/find_bar_host_browsertest.cc b/chrome/browser/find_bar_host_browsertest.cc
deleted file mode 100644
index eaf5b3b..0000000
--- a/chrome/browser/find_bar_host_browsertest.cc
+++ /dev/null
@@ -1,1070 +0,0 @@
-// 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.
-
-#include "app/keyboard_codes.h"
-#include "base/message_loop.h"
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/find_bar.h"
-#include "chrome/browser/find_bar_controller.h"
-#include "chrome/browser/find_notification_details.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents/tab_contents_view.h"
-#include "chrome/browser/tabs/tab_strip_model.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_navigator.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/test/in_process_browser_test.h"
-#include "chrome/test/ui_test_utils.h"
-#include "net/test/test_server.h"
-
-#if defined(TOOLKIT_VIEWS)
-#include "chrome/browser/views/find_bar_host.h"
-#include "views/focus/focus_manager.h"
-#elif defined(TOOLKIT_GTK)
-#include "chrome/browser/gtk/slide_animator_gtk.h"
-#elif defined(OS_MACOSX)
-#include "chrome/browser/cocoa/find_bar_bridge.h"
-#endif
-
-const std::string kSimplePage = "404_is_enough_for_us.html";
-const std::string kFramePage = "files/find_in_page/frames.html";
-const std::string kFrameData = "files/find_in_page/framedata_general.html";
-const std::string kUserSelectPage = "files/find_in_page/user-select.html";
-const std::string kCrashPage = "files/find_in_page/crash_1341577.html";
-const std::string kTooFewMatchesPage = "files/find_in_page/bug_1155639.html";
-const std::string kEndState = "files/find_in_page/end_state.html";
-const std::string kPrematureEnd = "files/find_in_page/premature_end.html";
-const std::string kMoveIfOver = "files/find_in_page/move_if_obscuring.html";
-const std::string kBitstackCrash = "files/find_in_page/crash_14491.html";
-const std::string kSelectChangesOrdinal =
- "files/find_in_page/select_changes_ordinal.html";
-const std::string kSimple = "files/find_in_page/simple.html";
-const std::string kLinkPage = "files/find_in_page/link.html";
-
-const bool kBack = false;
-const bool kFwd = true;
-
-const bool kIgnoreCase = false;
-const bool kCaseSensitive = true;
-
-const int kMoveIterations = 30;
-
-class FindInPageControllerTest : public InProcessBrowserTest {
- public:
- FindInPageControllerTest() {
- EnableDOMAutomation();
-
-#if defined(TOOLKIT_VIEWS)
- DropdownBarHost::disable_animations_during_testing_ = true;
-#elif defined(TOOLKIT_GTK)
- SlideAnimatorGtk::SetAnimationsForTesting(false);
-#elif defined(OS_MACOSX)
- FindBarBridge::disable_animations_during_testing_ = true;
-#endif
- }
-
- protected:
- bool GetFindBarWindowInfoForBrowser(
- Browser* browser, gfx::Point* position, bool* fully_visible) {
- FindBarTesting* find_bar =
- browser->GetFindBarController()->find_bar()->GetFindBarTesting();
- return find_bar->GetFindBarWindowInfo(position, fully_visible);
- }
-
- bool GetFindBarWindowInfo(gfx::Point* position, bool* fully_visible) {
- return GetFindBarWindowInfoForBrowser(browser(), position, fully_visible);
- }
-
- string16 GetFindBarTextForBrowser(Browser* browser) {
- FindBarTesting* find_bar =
- browser->GetFindBarController()->find_bar()->GetFindBarTesting();
- return find_bar->GetFindText();
- }
-
- string16 GetFindBarText() {
- return GetFindBarTextForBrowser(browser());
- }
-
- void EnsureFindBoxOpenForBrowser(Browser* browser) {
- browser->ShowFindBar();
- gfx::Point position;
- bool fully_visible = false;
- EXPECT_TRUE(GetFindBarWindowInfoForBrowser(
- browser, &position, &fully_visible));
- EXPECT_TRUE(fully_visible);
- }
-
- void EnsureFindBoxOpen() {
- EnsureFindBoxOpenForBrowser(browser());
- }
-};
-
-// Platform independent FindInPage that takes |const wchar_t*|
-// as an input.
-int FindInPageWchar(TabContents* tab,
- const wchar_t* search_str,
- bool forward,
- bool case_sensitive,
- int* ordinal) {
- return ui_test_utils::FindInPage(
- tab, WideToUTF16(std::wstring(search_str)),
- forward, case_sensitive, ordinal);
-}
-
-// This test loads a page with frames and starts FindInPage requests.
-IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindInPageFrames) {
- ASSERT_TRUE(test_server()->Start());
-
- // First we navigate to our frames page.
- GURL url = test_server()->GetURL(kFramePage);
- ui_test_utils::NavigateToURL(browser(), url);
-
- // Try incremental search (mimicking user typing in).
- int ordinal = 0;
- TabContents* tab = browser()->GetSelectedTabContents();
- EXPECT_EQ(18, FindInPageWchar(tab, L"g",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(1, ordinal);
- EXPECT_EQ(11, FindInPageWchar(tab, L"go",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(1, ordinal);
- EXPECT_EQ(04, FindInPageWchar(tab, L"goo",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(1, ordinal);
- EXPECT_EQ(03, FindInPageWchar(tab, L"goog",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(1, ordinal);
- EXPECT_EQ(02, FindInPageWchar(tab, L"googl",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(1, ordinal);
- EXPECT_EQ(01, FindInPageWchar(tab, L"google",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(1, ordinal);
- EXPECT_EQ(00, FindInPageWchar(tab, L"google!",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(0, ordinal);
-
- // Negative test (no matches should be found).
- EXPECT_EQ(0, FindInPageWchar(tab, L"Non-existing string",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(0, ordinal);
-
- // 'horse' only exists in the three right frames.
- EXPECT_EQ(3, FindInPageWchar(tab, L"horse",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(1, ordinal);
-
- // 'cat' only exists in the first frame.
- EXPECT_EQ(1, FindInPageWchar(tab, L"cat",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(1, ordinal);
-
- // Try searching again, should still come up with 1 match.
- EXPECT_EQ(1, FindInPageWchar(tab, L"cat",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(1, ordinal);
-
- // Try searching backwards, ignoring case, should still come up with 1 match.
- EXPECT_EQ(1, FindInPageWchar(tab, L"CAT",
- kBack, kIgnoreCase, &ordinal));
- EXPECT_EQ(1, ordinal);
-
- // Try case sensitive, should NOT find it.
- EXPECT_EQ(0, FindInPageWchar(tab, L"CAT",
- kFwd, kCaseSensitive, &ordinal));
- EXPECT_EQ(0, ordinal);
-
- // Try again case sensitive, but this time with right case.
- EXPECT_EQ(1, FindInPageWchar(tab, L"dog",
- kFwd, kCaseSensitive, &ordinal));
- EXPECT_EQ(1, ordinal);
-
- // Try non-Latin characters ('Hreggvidur' with 'eth' for 'd' in left frame).
- EXPECT_EQ(1, FindInPageWchar(tab, L"Hreggvi\u00F0ur",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(1, ordinal);
- EXPECT_EQ(1, FindInPageWchar(tab, L"Hreggvi\u00F0ur",
- kFwd, kCaseSensitive, &ordinal));
- EXPECT_EQ(1, ordinal);
- EXPECT_EQ(0, FindInPageWchar(tab, L"hreggvi\u00F0ur",
- kFwd, kCaseSensitive, &ordinal));
- EXPECT_EQ(0, ordinal);
-}
-
-// Specifying a prototype so that we can add the WARN_UNUSED_RESULT attribute.
-bool FocusedOnPage(TabContents* tab_contents, std::string* result)
- WARN_UNUSED_RESULT;
-
-bool FocusedOnPage(TabContents* tab_contents, std::string* result) {
- return ui_test_utils::ExecuteJavaScriptAndExtractString(
- tab_contents->render_view_host(),
- L"",
- L"window.domAutomationController.send(getFocusedElement());",
- result);
-}
-
-// This tests the FindInPage end-state, in other words: what is focused when you
-// close the Find box (ie. if you find within a link the link should be
-// focused).
-IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindInPageEndState) {
- ASSERT_TRUE(test_server()->Start());
-
- // First we navigate to our special focus tracking page.
- GURL url = test_server()->GetURL(kEndState);
- ui_test_utils::NavigateToURL(browser(), url);
-
- TabContents* tab_contents = browser()->GetSelectedTabContents();
- ASSERT_TRUE(NULL != tab_contents);
-
- // Verify that nothing has focus.
- std::string result;
- ASSERT_TRUE(FocusedOnPage(tab_contents, &result));
- ASSERT_STREQ("{nothing focused}", result.c_str());
-
- // Search for a text that exists within a link on the page.
- int ordinal = 0;
- EXPECT_EQ(1, FindInPageWchar(tab_contents, L"nk",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(1, ordinal);
-
- // End the find session, which should set focus to the link.
- tab_contents->StopFinding(FindBarController::kKeepSelection);
-
- // Verify that the link is focused.
- ASSERT_TRUE(FocusedOnPage(tab_contents, &result));
- EXPECT_STREQ("link1", result.c_str());
-
- // Search for a text that exists within a link on the page.
- EXPECT_EQ(1, FindInPageWchar(tab_contents, L"Google",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(1, ordinal);
-
- // Move the selection to link 1, after searching.
- ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString(
- tab_contents->render_view_host(),
- L"",
- L"window.domAutomationController.send(selectLink1());",
- &result));
-
- // End the find session.
- tab_contents->StopFinding(FindBarController::kKeepSelection);
-
- // Verify that link2 is not focused.
- ASSERT_TRUE(FocusedOnPage(tab_contents, &result));
- EXPECT_STREQ("", result.c_str());
-}
-
-// This test loads a single-frame page and makes sure the ordinal returned makes
-// sense as we FindNext over all the items.
-IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindInPageOrdinal) {
- ASSERT_TRUE(test_server()->Start());
-
- // First we navigate to our page.
- GURL url = test_server()->GetURL(kFrameData);
- ui_test_utils::NavigateToURL(browser(), url);
-
- // Search for 'o', which should make the first item active and return
- // '1 in 3' (1st ordinal of a total of 3 matches).
- TabContents* tab = browser()->GetSelectedTabContents();
- int ordinal = 0;
- EXPECT_EQ(3, FindInPageWchar(tab, L"o",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(1, ordinal);
- EXPECT_EQ(3, FindInPageWchar(tab, L"o",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(2, ordinal);
- EXPECT_EQ(3, FindInPageWchar(tab, L"o",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(3, ordinal);
- // Go back one match.
- EXPECT_EQ(3, FindInPageWchar(tab, L"o",
- kBack, kIgnoreCase, &ordinal));
- EXPECT_EQ(2, ordinal);
- EXPECT_EQ(3, FindInPageWchar(tab, L"o",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(3, ordinal);
- // This should wrap to the top.
- EXPECT_EQ(3, FindInPageWchar(tab, L"o",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(1, ordinal);
- // This should go back to the end.
- EXPECT_EQ(3, FindInPageWchar(tab, L"o",
- kBack, kIgnoreCase, &ordinal));
- EXPECT_EQ(3, ordinal);
-}
-
-// This tests that the ordinal is correctly adjusted after a selection
-IN_PROC_BROWSER_TEST_F(FindInPageControllerTest,
- SelectChangesOrdinal_Issue20883) {
- ASSERT_TRUE(test_server()->Start());
-
- // First we navigate to our test content.
- GURL url = test_server()->GetURL(kSelectChangesOrdinal);
- ui_test_utils::NavigateToURL(browser(), url);
-
- TabContents* tab_contents = browser()->GetSelectedTabContents();
- ASSERT_TRUE(NULL != tab_contents);
-
- // Search for a text that exists within a link on the page.
- TabContents* tab = browser()->GetSelectedTabContents();
- int ordinal = 0;
- EXPECT_EQ(4, FindInPageWchar(tab_contents,
- L"google",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(1, ordinal);
-
- // Move the selection to link 1, after searching.
- std::string result;
- ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString(
- tab_contents->render_view_host(),
- L"",
- L"window.domAutomationController.send(selectLink1());",
- &result));
-
- // Do a find-next after the selection. This should move forward
- // from there to the 3rd instance of 'google'.
- EXPECT_EQ(4, FindInPageWchar(tab,
- L"google",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(3, ordinal);
-
- // End the find session.
- tab_contents->StopFinding(FindBarController::kKeepSelection);
-}
-
-// This test loads a page with frames and makes sure the ordinal returned makes
-// sense.
-IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindInPageMultiFramesOrdinal) {
- ASSERT_TRUE(test_server()->Start());
-
- // First we navigate to our page.
- GURL url = test_server()->GetURL(kFramePage);
- ui_test_utils::NavigateToURL(browser(), url);
-
- // Search for 'a', which should make the first item active and return
- // '1 in 7' (1st ordinal of a total of 7 matches).
- TabContents* tab = browser()->GetSelectedTabContents();
- int ordinal = 0;
- EXPECT_EQ(7,
- FindInPageWchar(tab, L"a", kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(1, ordinal);
- EXPECT_EQ(7,
- FindInPageWchar(tab, L"a", kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(2, ordinal);
- EXPECT_EQ(7,
- FindInPageWchar(tab, L"a", kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(3, ordinal);
- EXPECT_EQ(7,
- FindInPageWchar(tab, L"a", kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(4, ordinal);
- // Go back one, which should go back one frame.
- EXPECT_EQ(7,
- FindInPageWchar(tab, L"a", kBack, kIgnoreCase, &ordinal));
- EXPECT_EQ(3, ordinal);
- EXPECT_EQ(7,
- FindInPageWchar(tab, L"a", kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(4, ordinal);
- EXPECT_EQ(7,
- FindInPageWchar(tab, L"a", kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(5, ordinal);
- EXPECT_EQ(7,
- FindInPageWchar(tab, L"a", kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(6, ordinal);
- EXPECT_EQ(7,
- FindInPageWchar(tab, L"a", kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(7, ordinal);
- // Now we should wrap back to frame 1.
- EXPECT_EQ(7,
- FindInPageWchar(tab, L"a", kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(1, ordinal);
- // Now we should wrap back to frame last frame.
- EXPECT_EQ(7,
- FindInPageWchar(tab, L"a", kBack, kIgnoreCase, &ordinal));
- EXPECT_EQ(7, ordinal);
-}
-
-// We could get ordinals out of whack when restarting search in subframes.
-// See http://crbug.com/5132.
-IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindInPage_Issue5132) {
- ASSERT_TRUE(test_server()->Start());
-
- // First we navigate to our page.
- GURL url = test_server()->GetURL(kFramePage);
- ui_test_utils::NavigateToURL(browser(), url);
-
- // Search for 'goa' three times (6 matches on page).
- int ordinal = 0;
- TabContents* tab = browser()->GetSelectedTabContents();
- EXPECT_EQ(6, FindInPageWchar(tab, L"goa",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(1, ordinal);
- EXPECT_EQ(6, FindInPageWchar(tab, L"goa",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(2, ordinal);
- EXPECT_EQ(6, FindInPageWchar(tab, L"goa",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(3, ordinal);
- // Add space to search (should result in no matches).
- EXPECT_EQ(0, FindInPageWchar(tab, L"goa ",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(0, ordinal);
- // Remove the space, should be back to '3 out of 6')
- EXPECT_EQ(6, FindInPageWchar(tab, L"goa",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(3, ordinal);
-}
-
-// Load a page with no selectable text and make sure we don't crash.
-IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindUnSelectableText) {
- ASSERT_TRUE(test_server()->Start());
-
- // First we navigate to our page.
- GURL url = test_server()->GetURL(kUserSelectPage);
- ui_test_utils::NavigateToURL(browser(), url);
-
- int ordinal = 0;
- TabContents* tab = browser()->GetSelectedTabContents();
- // The search string is present but doesn't qualify to be found
- EXPECT_EQ(0, FindInPageWchar(tab, L"text",
- kFwd, kIgnoreCase, &ordinal));
- // With zero results there should be no current selection.
- EXPECT_EQ(0, ordinal);
-}
-
-// Try to reproduce the crash seen in issue 1341577.
-IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindCrash_Issue1341577) {
- ASSERT_TRUE(test_server()->Start());
-
- // First we navigate to our page.
- GURL url = test_server()->GetURL(kCrashPage);
- ui_test_utils::NavigateToURL(browser(), url);
-
- // This would crash the tab. These must be the first two find requests issued
- // against the frame, otherwise an active frame pointer is set and it wont
- // produce the crash.
- // We used to check the return value and |ordinal|. With ICU 4.2, FiP does
- // not find a stand-alone dependent vowel sign of Indic scripts. So, the
- // exptected values are all 0. To make this test pass regardless of
- // ICU version, we just call FiP and see if there's any crash.
- // TODO(jungshik): According to a native Malayalam speaker, it's ok not
- // to find U+0D4C. Still need to investigate further this issue.
- int ordinal = 0;
- TabContents* tab = browser()->GetSelectedTabContents();
- FindInPageWchar(tab, L"\u0D4C", kFwd, kIgnoreCase, &ordinal);
- FindInPageWchar(tab, L"\u0D4C", kFwd, kIgnoreCase, &ordinal);
-
- // This should work fine.
- EXPECT_EQ(1, FindInPageWchar(tab, L"\u0D24\u0D46",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(1, ordinal);
- EXPECT_EQ(0, FindInPageWchar(tab, L"nostring",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(0, ordinal);
-}
-
-// Try to reproduce the crash seen in http://crbug.com/14491, where an assert
-// hits in the BitStack size comparison in WebKit.
-IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindCrash_Issue14491) {
- ASSERT_TRUE(test_server()->Start());
-
- // First we navigate to our page.
- GURL url = test_server()->GetURL(kBitstackCrash);
- ui_test_utils::NavigateToURL(browser(), url);
-
- // This used to crash the tab.
- int ordinal = 0;
- EXPECT_EQ(0, FindInPageWchar(browser()->GetSelectedTabContents(),
- L"s", kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(0, ordinal);
-}
-
-// Test to make sure Find does the right thing when restarting from a timeout.
-// We used to have a problem where we'd stop finding matches when all of the
-// following conditions were true:
-// 1) The page has a lot of text to search.
-// 2) The page contains more than one match.
-// 3) It takes longer than the time-slice given to each Find operation (100
-// ms) to find one or more of those matches (so Find times out and has to try
-// again from where it left off).
-IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindRestarts_Issue1155639) {
- ASSERT_TRUE(test_server()->Start());
-
- // First we navigate to our page.
- GURL url = test_server()->GetURL(kTooFewMatchesPage);
- ui_test_utils::NavigateToURL(browser(), url);
-
- // This string appears 5 times at the bottom of a long page. If Find restarts
- // properly after a timeout, it will find 5 matches, not just 1.
- int ordinal = 0;
- EXPECT_EQ(5, FindInPageWchar(browser()->GetSelectedTabContents(),
- L"008.xml",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(1, ordinal);
-}
-
-// This tests bug 11761: FindInPage terminates search prematurely.
-// This test is not expected to pass until bug 11761 is fixed.
-IN_PROC_BROWSER_TEST_F(FindInPageControllerTest,
- DISABLED_FindInPagePrematureEnd) {
- ASSERT_TRUE(test_server()->Start());
-
- // First we navigate to our special focus tracking page.
- GURL url = test_server()->GetURL(kPrematureEnd);
- ui_test_utils::NavigateToURL(browser(), url);
-
- TabContents* tab_contents = browser()->GetSelectedTabContents();
- ASSERT_TRUE(NULL != tab_contents);
-
- // Search for a text that exists within a link on the page.
- int ordinal = 0;
- EXPECT_EQ(2, FindInPageWchar(tab_contents, L"html ",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(1, ordinal);
-}
-
-IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindDisappearOnNavigate) {
- ASSERT_TRUE(test_server()->Start());
-
- // First we navigate to our special focus tracking page.
- GURL url = test_server()->GetURL(kSimplePage);
- GURL url2 = test_server()->GetURL(kFramePage);
- ui_test_utils::NavigateToURL(browser(), url);
-
- browser()->ShowFindBar();
-
- gfx::Point position;
- bool fully_visible = false;
-
- // Make sure it is open.
- EXPECT_TRUE(GetFindBarWindowInfo(&position, &fully_visible));
- EXPECT_TRUE(fully_visible);
-
- // Reload the tab and make sure Find window doesn't go away.
- browser()->Reload(CURRENT_TAB);
- ui_test_utils::WaitForNavigationInCurrentTab(browser());
-
- EXPECT_TRUE(GetFindBarWindowInfo(&position, &fully_visible));
- EXPECT_TRUE(fully_visible);
-
- // Navigate and make sure the Find window goes away.
- ui_test_utils::NavigateToURL(browser(), url2);
-
- EXPECT_TRUE(GetFindBarWindowInfo(&position, &fully_visible));
- EXPECT_FALSE(fully_visible);
-}
-
-#if defined(OS_MACOSX)
-// FindDisappearOnNewTabAndHistory is flaky, at least on Mac.
-// See http://crbug.com/43072
-#define FindDisappearOnNewTabAndHistory FLAKY_FindDisappearOnNewTabAndHistory
-#endif
-
-// Make sure Find box disappears when History/Downloads page is opened, and
-// when a New Tab is opened.
-IN_PROC_BROWSER_TEST_F(FindInPageControllerTest,
- FindDisappearOnNewTabAndHistory) {
- ASSERT_TRUE(test_server()->Start());
-
- // First we navigate to our special focus tracking page.
- GURL url = test_server()->GetURL(kSimplePage);
- ui_test_utils::NavigateToURL(browser(), url);
-
- browser()->ShowFindBar();
-
- gfx::Point position;
- bool fully_visible = false;
-
- // Make sure it is open.
- EXPECT_TRUE(GetFindBarWindowInfo(&position, &fully_visible));
- EXPECT_TRUE(fully_visible);
-
- // Open another tab (tab B).
- browser()->NewTab();
- ui_test_utils::NavigateToURL(browser(), url);
-
- // Make sure Find box is closed.
- EXPECT_TRUE(GetFindBarWindowInfo(&position, &fully_visible));
- EXPECT_FALSE(fully_visible);
-
- // Close tab B.
- browser()->CloseTab();
-
- // Make sure Find window appears again.
- EXPECT_TRUE(GetFindBarWindowInfo(&position, &fully_visible));
- EXPECT_TRUE(fully_visible);
-
- browser()->ShowHistoryTab();
-
- // Make sure Find box is closed.
- EXPECT_TRUE(GetFindBarWindowInfo(&position, &fully_visible));
- EXPECT_FALSE(fully_visible);
-}
-
-// TODO(rohitrao): The FindMovesWhenObscuring test does not pass on mac.
-// http://crbug.com/22036
-#if defined(OS_MACOSX)
-#define MAYBE_FindMovesWhenObscuring FAILS_FindMovesWhenObscuring
-#else
-#define MAYBE_FindMovesWhenObscuring FindMovesWhenObscuring
-#endif
-
-// Make sure Find box moves out of the way if it is obscuring the active match.
-IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, MAYBE_FindMovesWhenObscuring) {
- ASSERT_TRUE(test_server()->Start());
-
- GURL url = test_server()->GetURL(kMoveIfOver);
- ui_test_utils::NavigateToURL(browser(), url);
-
- browser()->ShowFindBar();
-
- // This is needed on GTK because the reposition operation is asynchronous.
- MessageLoop::current()->RunAllPending();
-
- gfx::Point start_position;
- gfx::Point position;
- bool fully_visible = false;
-
- // Make sure it is open.
- EXPECT_TRUE(GetFindBarWindowInfo(&start_position, &fully_visible));
- EXPECT_TRUE(fully_visible);
-
- // Search for 'Chromium' which the Find box is obscuring.
- int ordinal = 0;
- TabContents* tab = browser()->GetSelectedTabContents();
- int index = 0;
- for (; index < kMoveIterations; ++index) {
- EXPECT_EQ(kMoveIterations, FindInPageWchar(tab, L"Chromium",
- kFwd, kIgnoreCase, &ordinal));
-
- // Check the position.
- EXPECT_TRUE(GetFindBarWindowInfo(&position, &fully_visible));
- EXPECT_TRUE(fully_visible);
-
- // If the Find box has moved then we are done.
- if (position.x() != start_position.x())
- break;
- }
-
- // We should not have reached the end.
- ASSERT_GT(kMoveIterations, index);
-
- // Search for something guaranteed not to be obscured by the Find box.
- EXPECT_EQ(1, FindInPageWchar(tab, L"Done",
- kFwd, kIgnoreCase, &ordinal));
- // Check the position.
- EXPECT_TRUE(GetFindBarWindowInfo(&position, &fully_visible));
- EXPECT_TRUE(fully_visible);
-
- // Make sure Find box has moved back to its original location.
- EXPECT_EQ(position.x(), start_position.x());
-}
-
-#if defined(OS_MACOSX)
-// FindNextInNewTabUsesPrepopulate times-out, at least on Mac.
-// See http://crbug.com/43070
-#define FindNextInNewTabUsesPrepopulate DISABLED_FindNextInNewTabUsesPrepopulate
-#endif
-
-// Make sure F3 in a new tab works if Find has previous string to search for.
-IN_PROC_BROWSER_TEST_F(FindInPageControllerTest,
- FindNextInNewTabUsesPrepopulate) {
- ASSERT_TRUE(test_server()->Start());
-
- // First we navigate to any page.
- GURL url = test_server()->GetURL(kSimplePage);
- ui_test_utils::NavigateToURL(browser(), url);
-
- // Search for 'no_match'. No matches should be found.
- int ordinal = 0;
- TabContents* tab = browser()->GetSelectedTabContents();
- EXPECT_EQ(0, FindInPageWchar(tab, L"no_match",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(0, ordinal);
-
- // Open another tab (tab B).
- browser()->NewTab();
- ui_test_utils::NavigateToURL(browser(), url);
-
- // Simulate what happens when you press F3 for FindNext. We should get a
- // response here (a hang means search was aborted).
- EXPECT_EQ(0, ui_test_utils::FindInPage(tab, string16(),
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(0, ordinal);
-
- // Open another tab (tab C).
- browser()->NewTab();
- ui_test_utils::NavigateToURL(browser(), url);
-
- // Simulate what happens when you press F3 for FindNext. We should get a
- // response here (a hang means search was aborted).
- EXPECT_EQ(0, ui_test_utils::FindInPage(tab, string16(),
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(0, ordinal);
-}
-
-#if defined(TOOLKIT_VIEWS)
-// Make sure Find box grabs the Esc accelerator and restores it again.
-#if defined(OS_LINUX)
-// TODO(oshima): On Gtk/Linux, a focus out event is asynchronous and
-// hiding a find bar does not immediately update the target
-// accelerator. The last condition fails in most cases due to this
-// behavior. See http://crbug.com/26870.
-IN_PROC_BROWSER_TEST_F(FindInPageControllerTest,
- DISABLED_AcceleratorRestoring) {
-#else
- IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, AcceleratorRestoring) {
-#endif
- ASSERT_TRUE(test_server()->Start());
-
- // First we navigate to any page.
- GURL url = test_server()->GetURL(kSimplePage);
- ui_test_utils::NavigateToURL(browser(), url);
-
- views::FocusManager* focus_manager =
- views::FocusManager::GetFocusManagerForNativeWindow(
- browser()->window()->GetNativeHandle());
-
- // See where Escape is registered.
- views::Accelerator escape(app::VKEY_ESCAPE, false, false, false);
- views::AcceleratorTarget* old_target =
- focus_manager->GetCurrentTargetForAccelerator(escape);
- EXPECT_TRUE(old_target != NULL);
-
- browser()->ShowFindBar();
-
- // Our Find bar should be the new target.
- views::AcceleratorTarget* new_target =
- focus_manager->GetCurrentTargetForAccelerator(escape);
-
- EXPECT_TRUE(new_target != NULL);
- EXPECT_NE(new_target, old_target);
-
- // Close the Find box.
- browser()->GetFindBarController()->EndFindSession(
- FindBarController::kKeepSelection);
-
- // The accelerator for Escape should be back to what it was before.
- EXPECT_EQ(old_target,
- focus_manager->GetCurrentTargetForAccelerator(escape));
-}
-#endif // TOOLKIT_VIEWS
-
-// Make sure Find box does not become UI-inactive when no text is in the box as
-// we switch to a tab contents with an empty find string. See issue 13570.
-IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, StayActive) {
- ASSERT_TRUE(test_server()->Start());
-
- // First we navigate to any page.
- GURL url = test_server()->GetURL(kSimplePage);
- ui_test_utils::NavigateToURL(browser(), url);
-
- browser()->ShowFindBar();
-
- // Simulate a user clearing the search string. Ideally, we should be
- // simulating keypresses here for searching for something and pressing
- // backspace, but that's been proven flaky in the past, so we go straight to
- // tab_contents.
- TabContents* tab_contents = browser()->GetSelectedTabContents();
- // Stop the (non-existing) find operation, and clear the selection (which
- // signals the UI is still active).
- tab_contents->StopFinding(FindBarController::kClearSelection);
- // Make sure the Find UI flag hasn't been cleared, it must be so that the UI
- // still responds to browser window resizing.
- ASSERT_TRUE(tab_contents->find_ui_active());
-}
-
-// Make sure F3 works after you FindNext a couple of times and end the Find
-// session. See issue http://crbug.com/28306.
-IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, RestartSearchFromF3) {
- ASSERT_TRUE(test_server()->Start());
-
- // First we navigate to a simple page.
- GURL url = test_server()->GetURL(kSimple);
- ui_test_utils::NavigateToURL(browser(), url);
-
- // Search for 'page'. Should have 1 match.
- int ordinal = 0;
- TabContents* tab = browser()->GetSelectedTabContents();
- EXPECT_EQ(1, FindInPageWchar(tab, L"page", kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(1, ordinal);
-
- // Simulate what happens when you press F3 for FindNext. Still should show
- // one match. This cleared the pre-populate string at one point (see bug).
- EXPECT_EQ(1, ui_test_utils::FindInPage(tab, string16(),
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(1, ordinal);
-
- // End the Find session, thereby making the next F3 start afresh.
- browser()->GetFindBarController()->EndFindSession(
- FindBarController::kKeepSelection);
-
- // Simulate F3 while Find box is closed. Should have 1 match.
- EXPECT_EQ(1, FindInPageWchar(tab, L"", kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(1, ordinal);
-}
-
-// When re-opening the find bar with F3, the find bar should be re-populated
-// with the last search from the same tab rather than the last overall search.
-// http://crbug.com/30006
-IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, PreferPreviousSearch) {
- ASSERT_TRUE(test_server()->Start());
-
- // First we navigate to any page.
- GURL url = test_server()->GetURL(kSimplePage);
- ui_test_utils::NavigateToURL(browser(), url);
-
- // Find "Default".
- int ordinal = 0;
- TabContents* tab1 = browser()->GetSelectedTabContents();
- EXPECT_EQ(1, FindInPageWchar(tab1, L"Default", kFwd, kIgnoreCase, &ordinal));
-
- // Create a second tab.
- // For some reason we can't use AddSelectedTabWithURL here on ChromeOS. It
- // could be some delicate assumption about the tab starting off unselected or
- // something relating to user gesture.
- browser::NavigateParams params(browser(), url, PageTransition::TYPED);
- params.disposition = NEW_BACKGROUND_TAB;
- params.tabstrip_add_types = TabStripModel::ADD_NONE;
- browser::Navigate(&params);
- browser()->SelectTabContentsAt(1, false);
- TabContents* tab2 = browser()->GetSelectedTabContents();
- EXPECT_NE(tab1, tab2);
-
- // Find "given".
- FindInPageWchar(tab2, L"given", kFwd, kIgnoreCase, &ordinal);
-
- // Switch back to first tab.
- browser()->SelectTabContentsAt(0, false);
- browser()->GetFindBarController()->EndFindSession(
- FindBarController::kKeepSelection);
- // Simulate F3.
- ui_test_utils::FindInPage(tab1, string16(), kFwd, kIgnoreCase, &ordinal);
- EXPECT_EQ(tab1->find_text(), WideToUTF16(L"Default"));
-}
-
-// This tests that whenever you close and reopen the Find bar, it should show
-// the last search entered in that tab. http://crbug.com/40121.
-IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, PrepopulateSameTab) {
-#if defined(OS_MACOSX)
- // FindInPage on Mac doesn't use prepopulated values. Search there is global.
- return;
-#endif
-
- ASSERT_TRUE(test_server()->Start());
-
- // First we navigate to any page.
- GURL url = test_server()->GetURL(kSimple);
- ui_test_utils::NavigateToURL(browser(), url);
-
- // Search for the word "page".
- int ordinal = 0;
- TabContents* tab1 = browser()->GetSelectedTabContents();
- EXPECT_EQ(1, FindInPageWchar(tab1, L"page", kFwd, kIgnoreCase, &ordinal));
-
- // Open the Find box.
- EnsureFindBoxOpen();
-
- EXPECT_EQ(ASCIIToUTF16("page"), GetFindBarText());
-
- // Close the Find box.
- browser()->GetFindBarController()->EndFindSession(
- FindBarController::kKeepSelection);
-
- // Open the Find box again.
- EnsureFindBoxOpen();
-
- // After the Find box has been reopened, it should have been prepopulated with
- // the word "page" again.
- EXPECT_EQ(ASCIIToUTF16("page"), GetFindBarText());
-}
-
-// This tests that whenever you open Find in a new tab it should prepopulate
-// with a previous search term (in any tab), if a search has not been issued in
-// this tab before.
-IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, PrepopulateInNewTab) {
-#if defined(OS_MACOSX)
- // FindInPage on Mac doesn't use prepopulated values. Search there is global.
- return;
-#endif
-
- ASSERT_TRUE(test_server()->Start());
-
- // First we navigate to any page.
- GURL url = test_server()->GetURL(kSimple);
- ui_test_utils::NavigateToURL(browser(), url);
-
- // Search for the word "page".
- int ordinal = 0;
- TabContents* tab1 = browser()->GetSelectedTabContents();
- EXPECT_EQ(1, FindInPageWchar(tab1, L"page", kFwd, kIgnoreCase, &ordinal));
-
- // Now create a second tab and load the same page.
- browser()->AddSelectedTabWithURL(url, PageTransition::TYPED);
- TabContents* tab2 = browser()->GetSelectedTabContents();
- EXPECT_NE(tab1, tab2);
-
- // Open the Find box.
- EnsureFindBoxOpen();
-
- // The new tab should have "page" prepopulated, since that was the last search
- // in the first tab.
- EXPECT_EQ(ASCIIToUTF16("page"), GetFindBarText());
-}
-
-// This makes sure that we can search for A in tabA, then for B in tabB and
-// when we come back to tabA we should still see A (because that was the last
-// search in that tab).
-IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, PrepopulatePreserveLast) {
-#if defined(OS_MACOSX)
- // FindInPage on Mac doesn't use prepopulated values. Search there is global.
- return;
-#endif
-
- ASSERT_TRUE(test_server()->Start());
-
- // First we navigate to any page.
- GURL url = test_server()->GetURL(kSimple);
- ui_test_utils::NavigateToURL(browser(), url);
-
- // Search for the word "page".
- int ordinal = 0;
- TabContents* tab1 = browser()->GetSelectedTabContents();
- EXPECT_EQ(1, FindInPageWchar(tab1, L"page", kFwd, kIgnoreCase, &ordinal));
-
- // Open the Find box.
- EnsureFindBoxOpen();
-
- EXPECT_EQ(ASCIIToUTF16("page"), GetFindBarText());
-
- // Close the Find box.
- browser()->GetFindBarController()->EndFindSession(
- FindBarController::kKeepSelection);
-
- // Now create a second tab and load the same page.
- browser::NavigateParams params(browser(), url, PageTransition::TYPED);
- params.disposition = NEW_BACKGROUND_TAB;
- params.tabstrip_add_types = TabStripModel::ADD_NONE;
- browser::Navigate(&params);
- browser()->SelectTabContentsAt(1, false);
- TabContents* tab2 = browser()->GetSelectedTabContents();
- EXPECT_NE(tab1, tab2);
-
- // Search for the word "text".
- FindInPageWchar(tab2, L"text", kFwd, kIgnoreCase, &ordinal);
-
- // Go back to the first tab and make sure we have NOT switched the prepopulate
- // text to "text".
- browser()->SelectTabContentsAt(0, false);
-
- // Open the Find box.
- EnsureFindBoxOpen();
-
- // After the Find box has been reopened, it should have been prepopulated with
- // the word "page" again, since that was the last search in that tab.
- EXPECT_EQ(ASCIIToUTF16("page"), GetFindBarText());
-
- // Close the Find box.
- browser()->GetFindBarController()->EndFindSession(
- FindBarController::kKeepSelection);
-
- // Re-open the Find box.
- // This is a special case: previous search in TabContents used to get cleared
- // if you opened and closed the FindBox, which would cause the global
- // prepopulate value to show instead of last search in this tab.
- EnsureFindBoxOpen();
-
- // After the Find box has been reopened, it should have been prepopulated with
- // the word "page" again, since that was the last search in that tab.
- EXPECT_EQ(ASCIIToUTF16("page"), GetFindBarText());
-}
-
-// TODO(rohitrao): Searching in incognito tabs does not work in browser tests in
-// linux views. Investigate and fix. http://crbug.com/40948
-#if defined(OS_LINUX) && defined(TOOLKIT_VIEWS)
-#define MAYBE_NoIncognitoPrepopulate DISABLED_NoIncognitoPrepopulate
-#else
-#define MAYBE_NoIncognitoPrepopulate NoIncognitoPrepopulate
-#endif
-
-// This tests that search terms entered into an incognito find bar are not used
-// as prepopulate terms for non-incognito windows.
-IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, MAYBE_NoIncognitoPrepopulate) {
-#if defined(OS_MACOSX)
- // FindInPage on Mac doesn't use prepopulated values. Search there is global.
- return;
-#endif
-
- ASSERT_TRUE(test_server()->Start());
-
- // First we navigate to the "simple" test page.
- GURL url = test_server()->GetURL(kSimple);
- ui_test_utils::NavigateToURL(browser(), url);
-
- // Search for the word "page" in the normal browser tab.
- int ordinal = 0;
- TabContents* tab1 = browser()->GetSelectedTabContents();
- EXPECT_EQ(1, FindInPageWchar(tab1, L"page", kFwd, kIgnoreCase, &ordinal));
-
- // Open the Find box.
- EnsureFindBoxOpenForBrowser(browser());
- EXPECT_EQ(ASCIIToUTF16("page"), GetFindBarTextForBrowser(browser()));
-
- // Close the Find box.
- browser()->GetFindBarController()->EndFindSession(
- FindBarController::kKeepSelection);
-
- // Open a new incognito window and navigate to the same page.
- Profile* incognito_profile = browser()->profile()->GetOffTheRecordProfile();
- Browser* incognito_browser = Browser::Create(incognito_profile);
- incognito_browser->AddSelectedTabWithURL(url, PageTransition::START_PAGE);
- ui_test_utils::WaitForNavigation(
- &incognito_browser->GetSelectedTabContents()->controller());
- incognito_browser->window()->Show();
-
- // Open the find box and make sure that it is prepopulated with "page".
- EnsureFindBoxOpenForBrowser(incognito_browser);
- EXPECT_EQ(ASCIIToUTF16("page"), GetFindBarTextForBrowser(incognito_browser));
-
- // Search for the word "text" in the incognito tab.
- TabContents* incognito_tab = incognito_browser->GetSelectedTabContents();
- EXPECT_EQ(1, FindInPageWchar(incognito_tab, L"text",
- kFwd, kIgnoreCase, &ordinal));
- EXPECT_EQ(ASCIIToUTF16("text"), GetFindBarTextForBrowser(incognito_browser));
-
- // Close the Find box.
- incognito_browser->GetFindBarController()->EndFindSession(
- FindBarController::kKeepSelection);
-
- // Now open a new tab in the original (non-incognito) browser.
- browser()->AddSelectedTabWithURL(url, PageTransition::TYPED);
- TabContents* tab2 = browser()->GetSelectedTabContents();
- EXPECT_NE(tab1, tab2);
-
- // Open the Find box and make sure it is prepopulated with the search term
- // from the original browser, not the search term from the incognito window.
- EnsureFindBoxOpenForBrowser(browser());
- EXPECT_EQ(ASCIIToUTF16("page"), GetFindBarTextForBrowser(browser()));
-}
-
-// This makes sure that dismissing the find bar with kActivateSelection works.
-IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, ActivateLinkNavigatesPage) {
- ASSERT_TRUE(test_server()->Start());
-
- // First we navigate to our test content.
- GURL url = test_server()->GetURL(kLinkPage);
- ui_test_utils::NavigateToURL(browser(), url);
-
- TabContents* tab = browser()->GetSelectedTabContents();
- int ordinal = 0;
- FindInPageWchar(tab, L"link", kFwd, kIgnoreCase, &ordinal);
- EXPECT_EQ(ordinal, 1);
-
- // End the find session, click on the link.
- tab->StopFinding(FindBarController::kActivateSelection);
- EXPECT_TRUE(ui_test_utils::WaitForNavigationInCurrentTab(browser()));
-}
diff --git a/chrome/browser/find_bar_state.cc b/chrome/browser/find_bar_state.cc
deleted file mode 100644
index d33d104..0000000
--- a/chrome/browser/find_bar_state.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// 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.
-
-#include "chrome/browser/find_bar_state.h"
-#include "chrome/browser/profile.h"
-
-// static
-string16 FindBarState::GetLastPrepopulateText(Profile* p) {
- FindBarState* state = p->GetFindBarState();
- string16 text = state->last_prepopulate_text();
-
- if (text.empty() && p->IsOffTheRecord()) {
- // Fall back to the original profile.
- state = p->GetOriginalProfile()->GetFindBarState();
- text = state->last_prepopulate_text();
- }
-
- return text;
-}
diff --git a/chrome/browser/find_bar_state.h b/chrome/browser/find_bar_state.h
deleted file mode 100644
index 801779e..0000000
--- a/chrome/browser/find_bar_state.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// 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.
-
-// Stores per-profile state needed for find in page. This includes the most
-// recently searched for term.
-
-#ifndef CHROME_BROWSER_FIND_BAR_STATE_H_
-#define CHROME_BROWSER_FIND_BAR_STATE_H_
-#pragma once
-
-#include "base/basictypes.h"
-#include "base/string16.h"
-
-class Profile;
-
-class FindBarState {
- public:
- FindBarState() {}
- ~FindBarState() {}
-
- string16 last_prepopulate_text() const {
- return last_prepopulate_text_;
- }
-
- void set_last_prepopulate_text(const string16& text) {
- last_prepopulate_text_ = text;
- }
-
- // Retrieves the last prepopulate text for a given Profile. If the profile is
- // off the record and has an empty prepopulate text, falls back to the
- // prepopulate text from the normal profile.
- static string16 GetLastPrepopulateText(Profile* profile);
-
- private:
- string16 last_prepopulate_text_;
-
- DISALLOW_COPY_AND_ASSIGN(FindBarState);
-};
-
-#endif // CHROME_BROWSER_FIND_BAR_STATE_H_
diff --git a/chrome/browser/find_notification_details.h b/chrome/browser/find_notification_details.h
deleted file mode 100644
index ee5fc51..0000000
--- a/chrome/browser/find_notification_details.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_FIND_NOTIFICATION_DETAILS_H_
-#define CHROME_BROWSER_FIND_NOTIFICATION_DETAILS_H_
-#pragma once
-
-#include "base/basictypes.h"
-#include "gfx/rect.h"
-
-class FindNotificationDetails {
- public:
- FindNotificationDetails(int request_id,
- int number_of_matches,
- const gfx::Rect& selection_rect,
- int active_match_ordinal,
- bool final_update)
- : request_id_(request_id),
- number_of_matches_(number_of_matches),
- selection_rect_(selection_rect),
- active_match_ordinal_(active_match_ordinal),
- final_update_(final_update) {}
-
- FindNotificationDetails()
- : request_id_(0),
- number_of_matches_(-1),
- active_match_ordinal_(-1),
- final_update_(false) {}
-
- ~FindNotificationDetails() {}
-
- int request_id() const { return request_id_; }
-
- int number_of_matches() const { return number_of_matches_; }
-
- gfx::Rect selection_rect() const { return selection_rect_; }
-
- int active_match_ordinal() const { return active_match_ordinal_; }
-
- bool final_update() const { return final_update_; }
-
- private:
- int request_id_; // The find-in-page request whose results we're returning.
- int number_of_matches_; // How many matches were found.
- gfx::Rect selection_rect_; // Where selection occurred (screen coordinate).
- int active_match_ordinal_; // The ordinal of the currently selected match.
- bool final_update_; // Whether this is the last Find Result update.
-};
-
-#endif // CHROME_BROWSER_FIND_NOTIFICATION_DETAILS_H_
diff --git a/chrome/browser/first_run/first_run.cc b/chrome/browser/first_run/first_run.cc
index ce89af5..4235a8a 100644
--- a/chrome/browser/first_run/first_run.cc
+++ b/chrome/browser/first_run/first_run.cc
@@ -21,7 +21,7 @@
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/process_singleton.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/shell_integration.h"
#include "chrome/common/chrome_paths.h"
@@ -94,9 +94,9 @@ bool FirstRun::ProcessMasterPreferences(const FilePath& user_data_dir,
FilePath master_prefs;
if (!PathService::Get(base::DIR_EXE, &master_prefs))
return true;
- master_prefs = master_prefs.AppendASCII(installer_util::kDefaultMasterPrefs);
+ master_prefs = master_prefs.AppendASCII(installer::kDefaultMasterPrefs);
- installer_util::MasterPreferences prefs(master_prefs);
+ installer::MasterPreferences prefs(master_prefs);
if (!prefs.read_from_file())
return true;
@@ -107,14 +107,14 @@ bool FirstRun::ProcessMasterPreferences(const FilePath& user_data_dir,
#if defined(OS_WIN)
// RLZ is currently a Windows-only phenomenon. When it comes to the Mac/
// Linux, enable it here.
- if (!prefs.GetInt(installer_util::master_preferences::kDistroPingDelay,
+ if (!prefs.GetInt(installer::master_preferences::kDistroPingDelay,
&out_prefs->ping_delay)) {
// 90 seconds is the default that we want to use in case master
// preferences is missing, corrupt or ping_delay is missing.
out_prefs->ping_delay = 90;
}
- if (prefs.GetBool(installer_util::master_preferences::kRequireEula, &value) &&
+ if (prefs.GetBool(installer::master_preferences::kRequireEula, &value) &&
value) {
// Show the post-installation EULA. This is done by setup.exe and the
// result determines if we continue or not. We wait here until the user
@@ -125,16 +125,16 @@ bool FirstRun::ProcessMasterPreferences(const FilePath& user_data_dir,
FilePath inner_html;
if (WriteEULAtoTempFile(&inner_html)) {
int retcode = 0;
- if (!LaunchSetupWithParam(installer_util::switches::kShowEula,
+ if (!LaunchSetupWithParam(installer::switches::kShowEula,
inner_html.ToWStringHack(), &retcode) ||
- (retcode == installer_util::EULA_REJECTED)) {
+ (retcode == installer::EULA_REJECTED)) {
LOG(WARNING) << "EULA rejected. Fast exit.";
::ExitProcess(1);
}
- if (retcode == installer_util::EULA_ACCEPTED) {
+ if (retcode == installer::EULA_ACCEPTED) {
VLOG(1) << "EULA : no collection";
GoogleUpdateSettings::SetCollectStatsConsent(false);
- } else if (retcode == installer_util::EULA_ACCEPTED_OPT_IN) {
+ } else if (retcode == installer::EULA_ACCEPTED_OPT_IN) {
VLOG(1) << "EULA : collection consent";
GoogleUpdateSettings::SetCollectStatsConsent(true);
}
@@ -142,7 +142,7 @@ bool FirstRun::ProcessMasterPreferences(const FilePath& user_data_dir,
}
#endif
- if (prefs.GetBool(installer_util::master_preferences::kAltFirstRunBubble,
+ if (prefs.GetBool(installer::master_preferences::kAltFirstRunBubble,
&value) && value) {
FirstRun::SetOEMFirstRunBubblePref();
}
@@ -164,7 +164,7 @@ bool FirstRun::ProcessMasterPreferences(const FilePath& user_data_dir,
}
#endif
- if (prefs.GetBool(installer_util::master_preferences::kDistroImportSearchPref,
+ if (prefs.GetBool(installer::master_preferences::kDistroImportSearchPref,
&value)) {
if (value) {
out_prefs->do_import_items |= importer::SEARCH_ENGINES;
@@ -175,7 +175,7 @@ bool FirstRun::ProcessMasterPreferences(const FilePath& user_data_dir,
// Check to see if search engine logos should be randomized.
if (prefs.GetBool(
- installer_util::master_preferences::
+ installer::master_preferences::
kSearchEngineExperimentRandomizePref,
&value) && value) {
out_prefs->randomize_search_engine_experiment = true;
@@ -186,12 +186,12 @@ bool FirstRun::ProcessMasterPreferences(const FilePath& user_data_dir,
// user is guaranteed to see the bubble iff he or she has completed the first
// run process.
if (prefs.GetBool(
- installer_util::master_preferences::kDistroSuppressFirstRunBubble,
+ installer::master_preferences::kDistroSuppressFirstRunBubble,
&value) && value)
FirstRun::SetShowFirstRunBubblePref(false);
if (prefs.GetBool(
- installer_util::master_preferences::kDistroImportHistoryPref,
+ installer::master_preferences::kDistroImportHistoryPref,
&value)) {
if (value) {
out_prefs->do_import_items |= importer::HISTORY;
@@ -204,7 +204,7 @@ bool FirstRun::ProcessMasterPreferences(const FilePath& user_data_dir,
out_prefs->homepage_defined = prefs.GetString(prefs::kHomePage, &not_used);
if (prefs.GetBool(
- installer_util::master_preferences::kDistroImportHomePagePref,
+ installer::master_preferences::kDistroImportHomePagePref,
&value)) {
if (value) {
out_prefs->do_import_items |= importer::HOME_PAGE;
@@ -215,13 +215,13 @@ bool FirstRun::ProcessMasterPreferences(const FilePath& user_data_dir,
// Bookmarks are never imported unless specifically turned on.
if (prefs.GetBool(
- installer_util::master_preferences::kDistroImportBookmarksPref,
+ installer::master_preferences::kDistroImportBookmarksPref,
&value) && value) {
out_prefs->do_import_items |= importer::FAVORITES;
}
if (prefs.GetBool(
- installer_util::master_preferences::kMakeChromeDefaultForUser,
+ installer::master_preferences::kMakeChromeDefaultForUser,
&value) && value) {
out_prefs->make_chrome_default = true;
}
@@ -231,7 +231,7 @@ bool FirstRun::ProcessMasterPreferences(const FilePath& user_data_dir,
// Note we are skipping all other master preferences if skip-first-run-ui
// is *not* specified. (That is, we continue only if skipping first run ui.)
if (!prefs.GetBool(
- installer_util::master_preferences::kDistroSkipFirstRunPref,
+ installer::master_preferences::kDistroSkipFirstRunPref,
&value) || !value) {
return true;
}
@@ -248,14 +248,14 @@ bool FirstRun::ProcessMasterPreferences(const FilePath& user_data_dir,
if (!FirstRun::CreateSentinel())
return false;
- if (prefs.GetBool(installer_util::master_preferences::kDistroShowWelcomePage,
+ if (prefs.GetBool(installer::master_preferences::kDistroShowWelcomePage,
&value) && value) {
FirstRun::SetShowWelcomePagePref();
}
std::string import_bookmarks_path;
prefs.GetString(
- installer_util::master_preferences::kDistroImportBookmarksFromFilePref,
+ installer::master_preferences::kDistroImportBookmarksFromFilePref,
&import_bookmarks_path);
#if defined(OS_WIN)
@@ -302,7 +302,7 @@ bool FirstRun::ProcessMasterPreferences(const FilePath& user_data_dir,
#endif
if (prefs.GetBool(
- installer_util::master_preferences::kMakeChromeDefaultForUser,
+ installer::master_preferences::kMakeChromeDefaultForUser,
&value) && value) {
ShellIntegration::SetAsDefaultBrowser();
}
@@ -472,6 +472,20 @@ void Upgrade::RelaunchChromeBrowserWithNewCommandLineIfNeeded() {
}
#endif // (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
+FirstRunBrowserProcess::FirstRunBrowserProcess(const CommandLine& command_line)
+ : BrowserProcessImpl(command_line) {
+}
+
+FirstRunBrowserProcess::~FirstRunBrowserProcess() {}
+
+GoogleURLTracker* FirstRunBrowserProcess::google_url_tracker() {
+ return NULL;
+}
+
+IntranetRedirectDetector* FirstRunBrowserProcess::intranet_redirect_detector() {
+ return NULL;
+}
+
FirstRunImportObserver::FirstRunImportObserver()
: loop_running_(false), import_result_(ResultCodes::NORMAL_EXIT) {
}
diff --git a/chrome/browser/first_run/first_run.h b/chrome/browser/first_run/first_run.h
index c131756..415753f 100644
--- a/chrome/browser/first_run/first_run.h
+++ b/chrome/browser/first_run/first_run.h
@@ -282,15 +282,11 @@ class Upgrade {
// thread to fetch on).
class FirstRunBrowserProcess : public BrowserProcessImpl {
public:
- explicit FirstRunBrowserProcess(const CommandLine& command_line)
- : BrowserProcessImpl(command_line) {
- }
- virtual ~FirstRunBrowserProcess() { }
+ explicit FirstRunBrowserProcess(const CommandLine& command_line);
+ virtual ~FirstRunBrowserProcess();
- virtual GoogleURLTracker* google_url_tracker() { return NULL; }
- virtual IntranetRedirectDetector* intranet_redirect_detector() {
- return NULL;
- }
+ virtual GoogleURLTracker* google_url_tracker();
+ virtual IntranetRedirectDetector* intranet_redirect_detector();
private:
DISALLOW_COPY_AND_ASSIGN(FirstRunBrowserProcess);
diff --git a/chrome/browser/first_run/first_run_mac.mm b/chrome/browser/first_run/first_run_mac.mm
index b297d15..e4ec8df 100644
--- a/chrome/browser/first_run/first_run_mac.mm
+++ b/chrome/browser/first_run/first_run_mac.mm
@@ -6,12 +6,12 @@
#import "base/scoped_nsobject.h"
#import "chrome/app/breakpad_mac.h"
-#import "chrome/browser/cocoa/first_run_dialog.h"
-#import "chrome/browser/cocoa/search_engine_dialog_controller.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/shell_integration.h"
+#import "chrome/browser/ui/cocoa/first_run_dialog.h"
+#import "chrome/browser/ui/cocoa/search_engine_dialog_controller.h"
#include "chrome/common/pref_names.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/google_update_settings.h"
diff --git a/chrome/browser/first_run/first_run_win.cc b/chrome/browser/first_run/first_run_win.cc
index 35037d5..995dcb2 100644
--- a/chrome/browser/first_run/first_run_win.cc
+++ b/chrome/browser/first_run/first_run_win.cc
@@ -25,14 +25,15 @@
#include "base/utf_string_conversions.h"
#include "base/win/registry.h"
#include "base/win/windows_version.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_updater.h"
#include "chrome/browser/importer/importer.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/process_singleton.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/views/first_run_search_engine_view.h"
+#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
@@ -64,14 +65,7 @@ namespace {
bool GetNewerChromeFile(FilePath* path) {
if (!PathService::Get(base::DIR_EXE, path))
return false;
- *path = path->Append(installer_util::kChromeNewExe);
- return true;
-}
-
-bool GetBackupChromeFile(std::wstring* path) {
- if (!PathService::Get(base::DIR_EXE, path))
- return false;
- file_util::AppendToPath(path, installer_util::kChromeOldExe);
+ *path = path->Append(installer::kChromeNewExe);
return true;
}
@@ -89,7 +83,7 @@ bool InvokeGoogleUpdateForRename() {
DWORD exit_code;
::GetExitCodeProcess(handle, &exit_code);
::CloseHandle(handle);
- if (exit_code == installer_util::RENAME_SUCCESSFUL)
+ if (exit_code == installer::RENAME_SUCCESSFUL)
return true;
}
}
@@ -101,8 +95,8 @@ bool LaunchSetupWithParam(const std::string& param, const std::wstring& value,
FilePath exe_path;
if (!PathService::Get(base::DIR_MODULE, &exe_path))
return false;
- exe_path = exe_path.Append(installer_util::kInstallerDir);
- exe_path = exe_path.Append(installer_util::kSetupExe);
+ exe_path = exe_path.Append(installer::kInstallerDir);
+ exe_path = exe_path.Append(installer::kSetupExe);
base::ProcessHandle ph;
CommandLine cl(exe_path);
cl.AppendSwitchNative(param, value);
@@ -156,7 +150,7 @@ class FirstRunDelayedTasks : public NotificationObserver {
const NotificationDetails& details) {
// After processing the notification we always delete ourselves.
if (type.value == NotificationType::EXTENSIONS_READY)
- DoExtensionWork(Source<Profile>(source).ptr()->GetExtensionsService());
+ DoExtensionWork(Source<Profile>(source).ptr()->GetExtensionService());
delete this;
return;
}
@@ -168,7 +162,7 @@ class FirstRunDelayedTasks : public NotificationObserver {
// The extension work is to basically trigger an extension update check.
// If the extension specified in the master pref is older than the live
// extension it will get updated which is the same as get it installed.
- void DoExtensionWork(ExtensionsService* service) {
+ void DoExtensionWork(ExtensionService* service) {
if (!service)
return;
service->updater()->CheckNow();
@@ -186,8 +180,8 @@ bool FirstRun::LaunchSetupWithParam(const std::string& param,
FilePath exe_path;
if (!PathService::Get(base::DIR_MODULE, &exe_path))
return false;
- exe_path = exe_path.Append(installer_util::kInstallerDir);
- exe_path = exe_path.Append(installer_util::kSetupExe);
+ exe_path = exe_path.Append(installer::kInstallerDir);
+ exe_path = exe_path.Append(installer::kSetupExe);
base::ProcessHandle ph;
CommandLine cl(exe_path);
cl.AppendSwitchNative(param, value);
@@ -225,30 +219,32 @@ void FirstRun::DoDelayedInstallExtensions() {
CommandLine* Upgrade::new_command_line_ = NULL;
bool FirstRun::CreateChromeDesktopShortcut() {
- std::wstring chrome_exe;
+ FilePath chrome_exe;
if (!PathService::Get(base::FILE_EXE, &chrome_exe))
return false;
BrowserDistribution *dist = BrowserDistribution::GetDistribution();
if (!dist)
return false;
- return ShellUtil::CreateChromeDesktopShortcut(chrome_exe,
+ return ShellUtil::CreateChromeDesktopShortcut(dist, chrome_exe.value(),
dist->GetAppDescription(), ShellUtil::CURRENT_USER,
false, true); // create if doesn't exist.
}
bool FirstRun::CreateChromeQuickLaunchShortcut() {
- std::wstring chrome_exe;
+ FilePath chrome_exe;
if (!PathService::Get(base::FILE_EXE, &chrome_exe))
return false;
- return ShellUtil::CreateChromeQuickLaunchShortcut(chrome_exe,
+ BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+ return ShellUtil::CreateChromeQuickLaunchShortcut(dist, chrome_exe.value(),
ShellUtil::CURRENT_USER, // create only for current user.
true); // create if doesn't exist.
}
bool Upgrade::IsBrowserAlreadyRunning() {
static HANDLE handle = NULL;
- std::wstring exe;
- PathService::Get(base::FILE_EXE, &exe);
+ FilePath exe_path;
+ PathService::Get(base::FILE_EXE, &exe_path);
+ std::wstring exe = exe_path.value();
std::replace(exe.begin(), exe.end(), '\\', '!');
std::transform(exe.begin(), exe.end(), exe.begin(), tolower);
exe = L"Global\\" + exe;
@@ -261,8 +257,7 @@ bool Upgrade::IsBrowserAlreadyRunning() {
bool Upgrade::RelaunchChromeBrowser(const CommandLine& command_line) {
scoped_ptr<base::Environment> env(base::Environment::Create());
- env->UnSetVar(WideToUTF8(
- BrowserDistribution::GetDistribution()->GetEnvVersionKey()).c_str());
+ env->UnSetVar(chrome::kChromeVersionEnvVar);
return base::LaunchApp(command_line.command_line_string(),
false, false, NULL);
}
@@ -273,12 +268,13 @@ bool Upgrade::SwapNewChromeExeIfPresent() {
return false;
if (!file_util::PathExists(new_chrome_exe))
return false;
- std::wstring curr_chrome_exe;
- if (!PathService::Get(base::FILE_EXE, &curr_chrome_exe))
+ FilePath cur_chrome_exe;
+ if (!PathService::Get(base::FILE_EXE, &cur_chrome_exe))
return false;
// First try to rename exe by launching rename command ourselves.
- bool user_install = InstallUtil::IsPerUserInstall(curr_chrome_exe.c_str());
+ bool user_install =
+ InstallUtil::IsPerUserInstall(cur_chrome_exe.value().c_str());
HKEY reg_root = user_install ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
BrowserDistribution *dist = BrowserDistribution::GetDistribution();
base::win::RegKey key;
@@ -290,7 +286,7 @@ bool Upgrade::SwapNewChromeExeIfPresent() {
DWORD exit_code;
::GetExitCodeProcess(handle, &exit_code);
::CloseHandle(handle);
- if (exit_code == installer_util::RENAME_SUCCESSFUL)
+ if (exit_code == installer::RENAME_SUCCESSFUL)
return true;
}
}
diff --git a/chrome/browser/geolocation/geolocation_browsertest.cc b/chrome/browser/geolocation/geolocation_browsertest.cc
index bc9d719..2696850 100644
--- a/chrome/browser/geolocation/geolocation_browsertest.cc
+++ b/chrome/browser/geolocation/geolocation_browsertest.cc
@@ -7,13 +7,12 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/dom_operation_notification_details.h"
#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
#include "chrome/browser/geolocation/geolocation_settings_state.h"
#include "chrome/browser/geolocation/location_arbitrator.h"
#include "chrome/browser/geolocation/mock_location_provider.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"
@@ -34,7 +33,7 @@
// load and wait one single frame here by calling a javascript function.
class IFrameLoader : public NotificationObserver {
public:
- IFrameLoader(Browser* browser, int iframe_id, const GURL& url)
+ IFrameLoader(Browser* browser, int iframe_id, const GURL& url)
: navigation_completed_(false),
javascript_completed_(false) {
NavigationController* controller =
@@ -542,7 +541,8 @@ IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest,
EXPECT_EQ(num_infobars_before_cancel, num_infobars_after_cancel + 1);
}
-IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, InvalidUrlRequest) {
+// Disabled, http://crbug.com/66959.
+IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, DISABLED_InvalidUrlRequest) {
// Tests that an invalid URL (e.g. from a popup window) is rejected
// correctly. Also acts as a regression test for http://crbug.com/40478
html_for_tests_ = "files/geolocation/invalid_request_url.html";
@@ -552,7 +552,8 @@ IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, InvalidUrlRequest) {
CheckStringValueFromJavascriptForTab("1", "isAlive()", original_tab);
}
-IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, NoInfoBarBeforeStart) {
+// Crashy, http://crbug.com/66400.
+IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, DISABLED_NoInfoBarBeforeStart) {
// See http://crbug.com/42789
html_for_tests_ = "files/geolocation/iframes_different_origin.html";
ASSERT_TRUE(Initialize(INITIALIZATION_IFRAMES));
diff --git a/chrome/browser/geolocation/geolocation_content_settings_map.cc b/chrome/browser/geolocation/geolocation_content_settings_map.cc
index 31a0a21..5c67523 100644
--- a/chrome/browser/geolocation/geolocation_content_settings_map.cc
+++ b/chrome/browser/geolocation/geolocation_content_settings_map.cc
@@ -15,13 +15,18 @@
#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
+#include <string>
+
#include "base/string_piece.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/content_settings/content_settings_details.h"
+#include "chrome/browser/content_settings/content_settings_pattern.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prefs/scoped_pref_update.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
@@ -35,6 +40,11 @@ const ContentSetting
GeolocationContentSettingsMap::GeolocationContentSettingsMap(Profile* profile)
: profile_(profile) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ prefs_registrar_.Init(profile_->GetPrefs());
+ prefs_registrar_.Add(prefs::kGeolocationDefaultContentSetting, this);
+ prefs_registrar_.Add(prefs::kGeolocationContentSettings, this);
+ notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED,
+ Source<Profile>(profile_));
}
// static
@@ -46,6 +56,9 @@ void GeolocationContentSettingsMap::RegisterUserPrefs(PrefService* prefs) {
ContentSetting GeolocationContentSettingsMap::GetDefaultContentSetting() const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ // If the profile is destroyed (and set to NULL) return CONTENT_SETTING_BLOCK.
+ if (!profile_)
+ return CONTENT_SETTING_BLOCK;
const PrefService* prefs = profile_->GetPrefs();
const ContentSetting default_content_setting = IntToContentSetting(
prefs->GetInteger(prefs::kGeolocationDefaultContentSetting));
@@ -53,6 +66,15 @@ ContentSetting GeolocationContentSettingsMap::GetDefaultContentSetting() const {
kDefaultSetting : default_content_setting;
}
+bool GeolocationContentSettingsMap::IsDefaultContentSettingManaged() const {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ // If the profile is destroyed (and set to NULL) return true.
+ if (!profile_)
+ return true;
+ return profile_->GetPrefs()->IsManagedPreference(
+ prefs::kGeolocationDefaultContentSetting);
+}
+
ContentSetting GeolocationContentSettingsMap::GetContentSetting(
const GURL& requesting_url,
const GURL& embedding_url) const {
@@ -61,7 +83,9 @@ ContentSetting GeolocationContentSettingsMap::GetContentSetting(
GURL requesting_origin(requesting_url.GetOrigin());
GURL embedding_origin(embedding_url.GetOrigin());
DCHECK(requesting_origin.is_valid() && embedding_origin.is_valid());
-
+ // If the profile is destroyed (and set to NULL) return CONTENT_SETTING_BLOCK.
+ if (!profile_)
+ return CONTENT_SETTING_BLOCK;
const DictionaryValue* all_settings_dictionary =
profile_->GetPrefs()->GetDictionary(prefs::kGeolocationContentSettings);
// Careful: The returned value could be NULL if the pref has never been set.
@@ -114,6 +138,8 @@ GeolocationContentSettingsMap::AllOriginsSettings
void GeolocationContentSettingsMap::SetDefaultContentSetting(
ContentSetting setting) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!profile_)
+ return;
profile_->GetPrefs()->SetInteger(prefs::kGeolocationDefaultContentSetting,
setting == CONTENT_SETTING_DEFAULT ?
kDefaultSetting : setting);
@@ -130,6 +156,8 @@ void GeolocationContentSettingsMap::SetContentSetting(
GURL embedding_origin(embedding_url.GetOrigin());
DCHECK(requesting_origin.is_valid());
DCHECK(embedding_origin.is_valid() || embedding_url.is_empty());
+ if (!profile_)
+ return;
PrefService* prefs = profile_->GetPrefs();
DictionaryValue* all_settings_dictionary = prefs->GetMutableDictionary(
prefs::kGeolocationContentSettings);
@@ -161,13 +189,52 @@ void GeolocationContentSettingsMap::SetContentSetting(
void GeolocationContentSettingsMap::ResetToDefault() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
+ if (!profile_)
+ return;
PrefService* prefs = profile_->GetPrefs();
prefs->ClearPref(prefs::kGeolocationDefaultContentSetting);
prefs->ClearPref(prefs::kGeolocationContentSettings);
}
+void GeolocationContentSettingsMap::NotifyObservers(
+ const ContentSettingsDetails& details) {
+ NotificationService::current()->Notify(
+ NotificationType::GEOLOCATION_SETTINGS_CHANGED,
+ Source<GeolocationContentSettingsMap>(this),
+ Details<const ContentSettingsDetails>(&details));
+}
+
+void GeolocationContentSettingsMap::Observe(
+ NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NotificationType::PREF_CHANGED) {
+ const std::string& name = *Details<std::string>(details).ptr();
+ if (name == prefs::kGeolocationDefaultContentSetting) {
+ NotifyObservers(ContentSettingsDetails(
+ ContentSettingsPattern(),
+ CONTENT_SETTINGS_TYPE_DEFAULT,
+ ""));
+ }
+ } else if (NotificationType::PROFILE_DESTROYED == type) {
+ UnregisterObservers();
+ } else {
+ NOTREACHED();
+ }
+}
+
+void GeolocationContentSettingsMap::UnregisterObservers() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!profile_)
+ return;
+ prefs_registrar_.RemoveAll();
+ notification_registrar_.Remove(this, NotificationType::PROFILE_DESTROYED,
+ Source<Profile>(profile_));
+ profile_ = NULL;
+}
+
GeolocationContentSettingsMap::~GeolocationContentSettingsMap() {
+ UnregisterObservers();
}
// static
diff --git a/chrome/browser/geolocation/geolocation_content_settings_map.h b/chrome/browser/geolocation/geolocation_content_settings_map.h
index ae56044..74a74fa 100644
--- a/chrome/browser/geolocation/geolocation_content_settings_map.h
+++ b/chrome/browser/geolocation/geolocation_content_settings_map.h
@@ -17,21 +17,28 @@
#include "base/basictypes.h"
#include "base/ref_counted.h"
+#include "chrome/browser/prefs/pref_change_registrar.h"
#include "chrome/common/content_settings.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
#include "googleurl/src/gurl.h"
+class ContentSettingsDetails;
class DictionaryValue;
class PrefService;
class Profile;
class GeolocationContentSettingsMap
- : public base::RefCountedThreadSafe<GeolocationContentSettingsMap> {
+ : public base::RefCountedThreadSafe<GeolocationContentSettingsMap>,
+ public NotificationObserver {
public:
typedef std::map<GURL, ContentSetting> OneOriginSettings;
typedef std::map<GURL, OneOriginSettings> AllOriginsSettings;
explicit GeolocationContentSettingsMap(Profile* profile);
+ virtual ~GeolocationContentSettingsMap();
+
static void RegisterUserPrefs(PrefService* prefs);
// Returns the default setting.
@@ -39,6 +46,9 @@ class GeolocationContentSettingsMap
// This should only be called on the UI thread.
ContentSetting GetDefaultContentSetting() const;
+ // Returns true if the content setting is managed (set by a policy).
+ bool IsDefaultContentSettingManaged() const;
+
// Returns a single ContentSetting which applies to the given |requesting_url|
// when embedded in a top-level page from |embedding_url|. To determine the
// setting for a top-level page, as opposed to a frame embedded in a page,
@@ -80,13 +90,21 @@ class GeolocationContentSettingsMap
// This should only be called on the UI thread.
void ResetToDefault();
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
private:
friend class base::RefCountedThreadSafe<GeolocationContentSettingsMap>;
// The default setting.
static const ContentSetting kDefaultSetting;
- ~GeolocationContentSettingsMap();
+ // Sends a CONTENT_SETTINGS_CHANGED notification.
+ void NotifyObservers(const ContentSettingsDetails& details);
+
+ void UnregisterObservers();
// Sets the fields of |one_origin_settings| based on the values in
// |dictionary|.
@@ -97,6 +115,10 @@ class GeolocationContentSettingsMap
// The profile we're associated with.
Profile* profile_;
+ // Registrar to register for PREF_CHANGED notifications.
+ PrefChangeRegistrar prefs_registrar_;
+ NotificationRegistrar notification_registrar_;
+
DISALLOW_COPY_AND_ASSIGN(GeolocationContentSettingsMap);
};
diff --git a/chrome/browser/geolocation/geolocation_content_settings_map_unittest.cc b/chrome/browser/geolocation/geolocation_content_settings_map_unittest.cc
index 5148116..0177f0f 100644
--- a/chrome/browser/geolocation/geolocation_content_settings_map_unittest.cc
+++ b/chrome/browser/geolocation/geolocation_content_settings_map_unittest.cc
@@ -4,7 +4,12 @@
#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
+#include "base/message_loop.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/content_settings/content_settings_details.h"
#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -12,6 +17,41 @@
namespace {
+class StubSettingsObserver : public NotificationObserver {
+ public:
+ StubSettingsObserver() : last_notifier(NULL), counter(0) {
+ registrar_.Add(this, NotificationType::GEOLOCATION_SETTINGS_CHANGED,
+ NotificationService::AllSources());
+ }
+
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ ++counter;
+ Source<GeolocationContentSettingsMap> content_settings(source);
+ Details<ContentSettingsDetails> settings_details(details);
+ last_notifier = content_settings.ptr();
+ last_pattern = settings_details.ptr()->pattern();
+ last_update_all = settings_details.ptr()->update_all();
+ last_update_all_types = settings_details.ptr()->update_all_types();
+ last_type = settings_details.ptr()->type();
+ // This checks that calling a Get function from an observer doesn't
+ // deadlock.
+ last_notifier->GetContentSetting(GURL("http://random-hostname.com/"),
+ GURL("http://foo.random-hostname.com/"));
+ }
+
+ GeolocationContentSettingsMap* last_notifier;
+ ContentSettingsPattern last_pattern;
+ bool last_update_all;
+ bool last_update_all_types;
+ int counter;
+ ContentSettingsType last_type;
+
+ private:
+ NotificationRegistrar registrar_;
+};
+
class GeolocationContentSettingsMapTests : public testing::Test {
public:
GeolocationContentSettingsMapTests()
@@ -239,4 +279,32 @@ TEST_F(GeolocationContentSettingsMapTests, IgnoreInvalidURLsInPrefs) {
GURL("http://b/")));
}
+TEST_F(GeolocationContentSettingsMapTests, Observe) {
+ TestingProfile profile;
+ GeolocationContentSettingsMap* map =
+ profile.GetGeolocationContentSettingsMap();
+ StubSettingsObserver observer;
+
+ EXPECT_EQ(CONTENT_SETTING_ASK, map->GetDefaultContentSetting());
+
+ // Test if a CONTENT_SETTING_CHANGE notification is sent after the geolocation
+ // default content setting was changed through calling the
+ // SetDefaultContentSetting method.
+ map->SetDefaultContentSetting(CONTENT_SETTING_BLOCK);
+ EXPECT_EQ(map, observer.last_notifier);
+ EXPECT_EQ(CONTENT_SETTINGS_TYPE_DEFAULT, observer.last_type);
+ EXPECT_EQ(1, observer.counter);
+
+
+ // Test if a CONTENT_SETTING_CHANGE notification is sent after the preference
+ // GeolocationDefaultContentSetting was changed.
+ PrefService* prefs = profile.GetPrefs();
+ prefs->SetInteger(prefs::kGeolocationDefaultContentSetting,
+ CONTENT_SETTING_ALLOW);
+ EXPECT_EQ(2, observer.counter);
+ EXPECT_EQ(map, observer.last_notifier);
+ EXPECT_EQ(CONTENT_SETTINGS_TYPE_DEFAULT, observer.last_type);
+ EXPECT_EQ(CONTENT_SETTING_ALLOW, map->GetDefaultContentSetting());
+}
+
} // namespace
diff --git a/chrome/browser/geolocation/geolocation_dispatcher_host.cc b/chrome/browser/geolocation/geolocation_dispatcher_host.cc
new file mode 100644
index 0000000..4f4020b
--- /dev/null
+++ b/chrome/browser/geolocation/geolocation_dispatcher_host.cc
@@ -0,0 +1,245 @@
+// 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.
+
+#include "chrome/browser/geolocation/geolocation_dispatcher_host.h"
+
+#include <map>
+#include <set>
+#include <utility>
+
+#include "chrome/common/geoposition.h"
+#include "chrome/browser/geolocation/geolocation_permission_context.h"
+#include "chrome/browser/geolocation/geolocation_provider.h"
+#include "chrome/browser/renderer_host/render_message_filter.h"
+#include "chrome/browser/renderer_host/render_process_host.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/renderer_host/render_view_host_notification_task.h"
+#include "chrome/common/render_messages.h"
+#include "ipc/ipc_message.h"
+
+namespace {
+class GeolocationDispatcherHostImpl : public GeolocationDispatcherHost,
+ public GeolocationObserver {
+ public:
+ GeolocationDispatcherHostImpl(
+ int render_process_id,
+ GeolocationPermissionContext* geolocation_permission_context);
+
+ // GeolocationDispatcherHost
+ virtual bool OnMessageReceived(const IPC::Message& msg, bool* msg_was_ok);
+
+ // GeolocationObserver
+ virtual void OnLocationUpdate(const Geoposition& position);
+
+ private:
+ virtual ~GeolocationDispatcherHostImpl();
+
+ void OnRegisterDispatcher(int render_view_id);
+ void OnUnregisterDispatcher(int render_view_id);
+ void OnRequestPermission(
+ int render_view_id, int bridge_id, const GURL& requesting_frame);
+ void OnCancelPermissionRequest(
+ int render_view_id, int bridge_id, const GURL& requesting_frame);
+ void OnStartUpdating(
+ int render_view_id, int bridge_id, const GURL& requesting_frame,
+ bool enable_high_accuracy);
+ void OnStopUpdating(int render_view_id, int bridge_id);
+ void OnSuspend(int render_view_id, int bridge_id);
+ void OnResume(int render_view_id, int bridge_id);
+
+ // Updates the |location_arbitrator_| with the currently required update
+ // options, based on |bridge_update_options_|.
+ void RefreshGeolocationObserverOptions();
+
+ int render_process_id_;
+ scoped_refptr<GeolocationPermissionContext> geolocation_permission_context_;
+
+ // Iterated when sending location updates to renderer processes. The fan out
+ // to individual bridge IDs happens renderer side, in order to minimize
+ // context switches.
+ // Only used on the IO thread.
+ std::set<int> geolocation_renderer_ids_;
+ // Maps <renderer_id, bridge_id> to the location arbitrator update options
+ // that correspond to this particular bridge.
+ std::map<std::pair<int, int>, GeolocationObserverOptions>
+ bridge_update_options_;
+ // Only set whilst we are registered with the arbitrator.
+ GeolocationProvider* location_provider_;
+
+ DISALLOW_COPY_AND_ASSIGN(GeolocationDispatcherHostImpl);
+};
+
+GeolocationDispatcherHostImpl::GeolocationDispatcherHostImpl(
+ int render_process_id,
+ GeolocationPermissionContext* geolocation_permission_context)
+ : render_process_id_(render_process_id),
+ geolocation_permission_context_(geolocation_permission_context),
+ location_provider_(NULL) {
+ // This is initialized by ResourceMessageFilter. Do not add any non-trivial
+ // initialization here, defer to OnRegisterBridge which is triggered whenever
+ // a javascript geolocation object is actually initialized.
+}
+
+GeolocationDispatcherHostImpl::~GeolocationDispatcherHostImpl() {
+ if (location_provider_)
+ location_provider_->RemoveObserver(this);
+}
+
+bool GeolocationDispatcherHostImpl::OnMessageReceived(
+ const IPC::Message& msg, bool* msg_was_ok) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ *msg_was_ok = true;
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(GeolocationDispatcherHostImpl, msg, *msg_was_ok)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_Geolocation_RegisterDispatcher,
+ OnRegisterDispatcher)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_Geolocation_UnregisterDispatcher,
+ OnUnregisterDispatcher)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_Geolocation_CancelPermissionRequest,
+ OnCancelPermissionRequest)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_Geolocation_RequestPermission,
+ OnRequestPermission)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_Geolocation_StartUpdating,
+ OnStartUpdating)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_Geolocation_StopUpdating,
+ OnStopUpdating)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_Geolocation_Suspend,
+ OnSuspend)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_Geolocation_Resume,
+ OnResume)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void GeolocationDispatcherHostImpl::OnLocationUpdate(
+ const Geoposition& geoposition) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ for (std::set<int>::iterator it = geolocation_renderer_ids_.begin();
+ it != geolocation_renderer_ids_.end(); ++it) {
+ IPC::Message* message =
+ new ViewMsg_Geolocation_PositionUpdated(*it, geoposition);
+ CallRenderViewHost(render_process_id_, *it,
+ &RenderViewHost::Send, message);
+ }
+}
+
+void GeolocationDispatcherHostImpl::OnRegisterDispatcher(
+ int render_view_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_EQ(0u, geolocation_renderer_ids_.count(render_view_id));
+ geolocation_renderer_ids_.insert(render_view_id);
+}
+
+void GeolocationDispatcherHostImpl::OnUnregisterDispatcher(
+ int render_view_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_EQ(1u, geolocation_renderer_ids_.count(render_view_id));
+ geolocation_renderer_ids_.erase(render_view_id);
+}
+
+void GeolocationDispatcherHostImpl::OnRequestPermission(
+ int render_view_id,
+ int bridge_id,
+ const GURL& requesting_frame) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DVLOG(1) << __FUNCTION__ << " " << render_process_id_ << ":"
+ << render_view_id << ":" << bridge_id;
+ geolocation_permission_context_->RequestGeolocationPermission(
+ render_process_id_, render_view_id, bridge_id,
+ requesting_frame);
+}
+
+void GeolocationDispatcherHostImpl::OnCancelPermissionRequest(
+ int render_view_id,
+ int bridge_id,
+ const GURL& requesting_frame) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DVLOG(1) << __FUNCTION__ << " " << render_process_id_ << ":"
+ << render_view_id << ":" << bridge_id;
+ geolocation_permission_context_->CancelGeolocationPermissionRequest(
+ render_process_id_, render_view_id, bridge_id,
+ requesting_frame);
+}
+
+void GeolocationDispatcherHostImpl::OnStartUpdating(
+ int render_view_id,
+ int bridge_id,
+ const GURL& requesting_frame,
+ bool enable_high_accuracy) {
+#if defined(ENABLE_CLIENT_BASED_GEOLOCATION)
+ // StartUpdating() can be invoked as a result of high-accuracy mode
+ // being enabled / disabled. No need to register the dispatcher again.
+ if (!geolocation_renderer_ids_.count(render_view_id))
+ OnRegisterDispatcher(render_view_id);
+#endif
+ // WebKit sends the startupdating request before checking permissions, to
+ // optimize the no-location-available case and reduce latency in the success
+ // case (location lookup happens in parallel with the permission request).
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DVLOG(1) << __FUNCTION__ << " " << render_process_id_ << ":"
+ << render_view_id << ":" << bridge_id;
+ bridge_update_options_[std::make_pair(render_view_id, bridge_id)] =
+ GeolocationObserverOptions(enable_high_accuracy);
+ geolocation_permission_context_->StartUpdatingRequested(
+ render_process_id_, render_view_id, bridge_id,
+ requesting_frame);
+ RefreshGeolocationObserverOptions();
+}
+
+void GeolocationDispatcherHostImpl::OnStopUpdating(int render_view_id,
+ int bridge_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DVLOG(1) << __FUNCTION__ << " " << render_process_id_ << ":"
+ << render_view_id << ":" << bridge_id;
+ if (bridge_update_options_.erase(std::make_pair(render_view_id, bridge_id)))
+ RefreshGeolocationObserverOptions();
+ geolocation_permission_context_->StopUpdatingRequested(
+ render_process_id_, render_view_id, bridge_id);
+#if defined(ENABLE_CLIENT_BASED_GEOLOCATION)
+ OnUnregisterDispatcher(render_view_id);
+#endif
+}
+
+void GeolocationDispatcherHostImpl::OnSuspend(int render_view_id,
+ int bridge_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DVLOG(1) << __FUNCTION__ << " " << render_process_id_ << ":"
+ << render_view_id << ":" << bridge_id;
+ // TODO(bulach): connect this with GeolocationArbitrator.
+}
+
+void GeolocationDispatcherHostImpl::OnResume(int render_view_id,
+ int bridge_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DVLOG(1) << __FUNCTION__ << " " << render_process_id_ << ":"
+ << render_view_id << ":" << bridge_id;
+ // TODO(bulach): connect this with GeolocationArbitrator.
+}
+
+void GeolocationDispatcherHostImpl::RefreshGeolocationObserverOptions() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (bridge_update_options_.empty()) {
+ if (location_provider_) {
+ location_provider_->RemoveObserver(this);
+ location_provider_ = NULL;
+ }
+ } else {
+ if (!location_provider_)
+ location_provider_ = GeolocationProvider::GetInstance();
+ // Re-add to re-establish our options, in case they changed.
+ location_provider_->AddObserver(
+ this,
+ GeolocationObserverOptions::Collapse(bridge_update_options_));
+ }
+}
+} // namespace
+
+GeolocationDispatcherHost* GeolocationDispatcherHost::New(
+ int render_process_id,
+ GeolocationPermissionContext* geolocation_permission_context) {
+ return new GeolocationDispatcherHostImpl(
+ render_process_id,
+ geolocation_permission_context);
+}
diff --git a/chrome/browser/geolocation/geolocation_dispatcher_host.h b/chrome/browser/geolocation/geolocation_dispatcher_host.h
new file mode 100644
index 0000000..293cb33
--- /dev/null
+++ b/chrome/browser/geolocation/geolocation_dispatcher_host.h
@@ -0,0 +1,31 @@
+// 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.
+
+#ifndef CHROME_BROWSER_GEOLOCATION_GEOLOCATION_DISPATCHER_HOST_H_
+#define CHROME_BROWSER_GEOLOCATION_GEOLOCATION_DISPATCHER_HOST_H_
+#pragma once
+
+#include "chrome/browser/browser_message_filter.h"
+
+class GeolocationPermissionContext;
+
+// GeolocationDispatcherHost is a browser filter for Geolocation messages.
+// It's the complement of GeolocationDispatcher (owned by RenderView).
+
+class GeolocationDispatcherHost : public BrowserMessageFilter {
+ public:
+ static GeolocationDispatcherHost* New(
+ int render_process_id,
+ GeolocationPermissionContext* geolocation_permission_context);
+
+ virtual bool OnMessageReceived(const IPC::Message& msg, bool* msg_was_ok) = 0;
+
+ protected:
+ GeolocationDispatcherHost() {}
+ virtual ~GeolocationDispatcherHost() {}
+
+ DISALLOW_COPY_AND_ASSIGN(GeolocationDispatcherHost);
+};
+
+#endif // CHROME_BROWSER_GEOLOCATION_GEOLOCATION_DISPATCHER_HOST_H_
diff --git a/chrome/browser/geolocation/geolocation_dispatcher_host_old.cc b/chrome/browser/geolocation/geolocation_dispatcher_host_old.cc
deleted file mode 100644
index 0af76e0..0000000
--- a/chrome/browser/geolocation/geolocation_dispatcher_host_old.cc
+++ /dev/null
@@ -1,239 +0,0 @@
-// 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.
-
-#include "chrome/browser/geolocation/geolocation_dispatcher_host_old.h"
-
-#include <map>
-#include <set>
-#include <utility>
-
-#include "chrome/common/geoposition.h"
-#include "chrome/browser/geolocation/geolocation_permission_context.h"
-#include "chrome/browser/geolocation/geolocation_provider.h"
-#include "chrome/browser/renderer_host/render_process_host.h"
-#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/renderer_host/render_view_host_notification_task.h"
-#include "chrome/browser/renderer_host/resource_message_filter.h"
-#include "chrome/common/render_messages.h"
-#include "ipc/ipc_message.h"
-
-namespace {
-class GeolocationDispatcherHostOldImpl : public GeolocationDispatcherHostOld,
- public GeolocationObserver {
- public:
- GeolocationDispatcherHostOldImpl(
- int resource_message_filter_process_id,
- GeolocationPermissionContext* geolocation_permission_context);
-
- // GeolocationDispatcherHostOld
- // Called to possibly handle the incoming IPC message. Returns true if
- // handled. Called in the browser process.
- virtual bool OnMessageReceived(const IPC::Message& msg, bool* msg_was_ok);
-
- // GeolocationArbitrator::Delegate
- virtual void OnLocationUpdate(const Geoposition& position);
-
- private:
- friend class base::RefCountedThreadSafe<GeolocationDispatcherHostOldImpl>;
- virtual ~GeolocationDispatcherHostOldImpl();
-
- void OnRegisterDispatcher(int render_view_id);
- void OnUnregisterDispatcher(int render_view_id);
- void OnRequestPermission(
- int render_view_id, int bridge_id, const GURL& requesting_frame);
- void OnCancelPermissionRequest(
- int render_view_id, int bridge_id, const GURL& requesting_frame);
- void OnStartUpdating(
- int render_view_id, int bridge_id, const GURL& requesting_frame,
- bool enable_high_accuracy);
- void OnStopUpdating(int render_view_id, int bridge_id);
- void OnSuspend(int render_view_id, int bridge_id);
- void OnResume(int render_view_id, int bridge_id);
-
- // Updates the |location_arbitrator_| with the currently required update
- // options, based on |bridge_update_options_|.
- void RefreshGeolocationObserverOptions();
-
- int resource_message_filter_process_id_;
- scoped_refptr<GeolocationPermissionContext> geolocation_permission_context_;
-
- // Iterated when sending location updates to renderer processes. The fan out
- // to individual bridge IDs happens renderer side, in order to minimize
- // context switches.
- // Only used on the IO thread.
- std::set<int> geolocation_renderer_ids_;
- // Maps <renderer_id, bridge_id> to the location arbitrator update options
- // that correspond to this particular bridge.
- std::map<std::pair<int, int>, GeolocationObserverOptions>
- bridge_update_options_;
- // Only set whilst we are registered with the arbitrator.
- GeolocationProvider* location_provider_;
-
- DISALLOW_COPY_AND_ASSIGN(GeolocationDispatcherHostOldImpl);
-};
-
-GeolocationDispatcherHostOldImpl::GeolocationDispatcherHostOldImpl(
- int resource_message_filter_process_id,
- GeolocationPermissionContext* geolocation_permission_context)
- : resource_message_filter_process_id_(resource_message_filter_process_id),
- geolocation_permission_context_(geolocation_permission_context),
- location_provider_(NULL) {
- // This is initialized by ResourceMessageFilter. Do not add any non-trivial
- // initialization here, defer to OnRegisterBridge which is triggered whenever
- // a javascript geolocation object is actually initialized.
-}
-
-GeolocationDispatcherHostOldImpl::~GeolocationDispatcherHostOldImpl() {
- if (location_provider_)
- location_provider_->RemoveObserver(this);
-}
-
-bool GeolocationDispatcherHostOldImpl::OnMessageReceived(
- const IPC::Message& msg, bool* msg_was_ok) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- *msg_was_ok = true;
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP_EX(GeolocationDispatcherHostOldImpl, msg, *msg_was_ok)
- IPC_MESSAGE_HANDLER(ViewHostMsg_Geolocation_RegisterDispatcher,
- OnRegisterDispatcher)
- IPC_MESSAGE_HANDLER(ViewHostMsg_Geolocation_UnregisterDispatcher,
- OnUnregisterDispatcher)
- IPC_MESSAGE_HANDLER(ViewHostMsg_Geolocation_CancelPermissionRequest,
- OnCancelPermissionRequest)
- IPC_MESSAGE_HANDLER(ViewHostMsg_Geolocation_RequestPermission,
- OnRequestPermission)
- IPC_MESSAGE_HANDLER(ViewHostMsg_Geolocation_StartUpdating,
- OnStartUpdating)
- IPC_MESSAGE_HANDLER(ViewHostMsg_Geolocation_StopUpdating,
- OnStopUpdating)
- IPC_MESSAGE_HANDLER(ViewHostMsg_Geolocation_Suspend,
- OnSuspend)
- IPC_MESSAGE_HANDLER(ViewHostMsg_Geolocation_Resume,
- OnResume)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void GeolocationDispatcherHostOldImpl::OnLocationUpdate(
- const Geoposition& geoposition) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- for (std::set<int>::iterator it = geolocation_renderer_ids_.begin();
- it != geolocation_renderer_ids_.end(); ++it) {
- IPC::Message* message =
- new ViewMsg_Geolocation_PositionUpdated(*it, geoposition);
- CallRenderViewHost(resource_message_filter_process_id_, *it,
- &RenderViewHost::Send, message);
- }
-}
-
-void GeolocationDispatcherHostOldImpl::OnRegisterDispatcher(
- int render_view_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK_EQ(0u, geolocation_renderer_ids_.count(render_view_id));
- geolocation_renderer_ids_.insert(render_view_id);
-}
-
-void GeolocationDispatcherHostOldImpl::OnUnregisterDispatcher(
- int render_view_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK_EQ(1u, geolocation_renderer_ids_.count(render_view_id));
- geolocation_renderer_ids_.erase(render_view_id);
-}
-
-void GeolocationDispatcherHostOldImpl::OnRequestPermission(
- int render_view_id,
- int bridge_id,
- const GURL& requesting_frame) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DVLOG(1) << __FUNCTION__ << " " << resource_message_filter_process_id_ << ":"
- << render_view_id << ":" << bridge_id;
- geolocation_permission_context_->RequestGeolocationPermission(
- resource_message_filter_process_id_, render_view_id, bridge_id,
- requesting_frame);
-}
-
-void GeolocationDispatcherHostOldImpl::OnCancelPermissionRequest(
- int render_view_id,
- int bridge_id,
- const GURL& requesting_frame) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DVLOG(1) << __FUNCTION__ << " " << resource_message_filter_process_id_ << ":"
- << render_view_id << ":" << bridge_id;
- geolocation_permission_context_->CancelGeolocationPermissionRequest(
- resource_message_filter_process_id_, render_view_id, bridge_id,
- requesting_frame);
-}
-
-void GeolocationDispatcherHostOldImpl::OnStartUpdating(
- int render_view_id,
- int bridge_id,
- const GURL& requesting_frame,
- bool enable_high_accuracy) {
- // WebKit sends the startupdating request before checking permissions, to
- // optimize the no-location-available case and reduce latency in the success
- // case (location lookup happens in parallel with the permission request).
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DVLOG(1) << __FUNCTION__ << " " << resource_message_filter_process_id_ << ":"
- << render_view_id << ":" << bridge_id;
- bridge_update_options_[std::make_pair(render_view_id, bridge_id)] =
- GeolocationObserverOptions(enable_high_accuracy);
- geolocation_permission_context_->StartUpdatingRequested(
- resource_message_filter_process_id_, render_view_id, bridge_id,
- requesting_frame);
- RefreshGeolocationObserverOptions();
-}
-
-void GeolocationDispatcherHostOldImpl::OnStopUpdating(int render_view_id,
- int bridge_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DVLOG(1) << __FUNCTION__ << " " << resource_message_filter_process_id_ << ":"
- << render_view_id << ":" << bridge_id;
- if (bridge_update_options_.erase(std::make_pair(render_view_id, bridge_id)))
- RefreshGeolocationObserverOptions();
- geolocation_permission_context_->StopUpdatingRequested(
- resource_message_filter_process_id_, render_view_id, bridge_id);
-}
-
-void GeolocationDispatcherHostOldImpl::OnSuspend(int render_view_id,
- int bridge_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DVLOG(1) << __FUNCTION__ << " " << resource_message_filter_process_id_ << ":"
- << render_view_id << ":" << bridge_id;
- // TODO(bulach): connect this with GeolocationArbitrator.
-}
-
-void GeolocationDispatcherHostOldImpl::OnResume(int render_view_id,
- int bridge_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DVLOG(1) << __FUNCTION__ << " " << resource_message_filter_process_id_ << ":"
- << render_view_id << ":" << bridge_id;
- // TODO(bulach): connect this with GeolocationArbitrator.
-}
-
-void GeolocationDispatcherHostOldImpl::RefreshGeolocationObserverOptions() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (bridge_update_options_.empty()) {
- if (location_provider_) {
- location_provider_->RemoveObserver(this);
- location_provider_ = NULL;
- }
- } else {
- if (!location_provider_)
- location_provider_ = GeolocationProvider::GetInstance();
- // Re-add to re-establish our options, in case they changed.
- location_provider_->AddObserver(
- this,
- GeolocationObserverOptions::Collapse(bridge_update_options_));
- }
-}
-} // namespace
-
-GeolocationDispatcherHostOld* GeolocationDispatcherHostOld::New(
- int resource_message_filter_process_id,
- GeolocationPermissionContext* geolocation_permission_context) {
- return new GeolocationDispatcherHostOldImpl(
- resource_message_filter_process_id,
- geolocation_permission_context);
-}
diff --git a/chrome/browser/geolocation/geolocation_dispatcher_host_old.h b/chrome/browser/geolocation/geolocation_dispatcher_host_old.h
deleted file mode 100644
index 655049a..0000000
--- a/chrome/browser/geolocation/geolocation_dispatcher_host_old.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_GEOLOCATION_GEOLOCATION_DISPATCHER_HOST_OLD_H_
-#define CHROME_BROWSER_GEOLOCATION_GEOLOCATION_DISPATCHER_HOST_OLD_H_
-#pragma once
-
-#include "base/ref_counted.h"
-
-class GeolocationPermissionContext;
-namespace IPC { class Message; }
-
-// GeolocationDispatcherHostOld is a delegate for Geolocation messages used by
-// ResourceMessageFilter.
-// It's the complement of GeolocationDispatcher (owned by RenderView).
-
-// TODO(jknotten): Remove this class once the new client-based implementation is
-// checked in (see http://crbug.com/59908).
-class GeolocationDispatcherHostOld
- : public base::RefCountedThreadSafe<GeolocationDispatcherHostOld> {
- public:
- static GeolocationDispatcherHostOld* New(
- int resource_message_filter_process_id,
- GeolocationPermissionContext* geolocation_permission_context);
-
- // Called to possibly handle the incoming IPC message. Returns true if
- // handled. Called in the browser process.
- virtual bool OnMessageReceived(const IPC::Message& msg, bool* msg_was_ok) = 0;
-
- protected:
- friend class base::RefCountedThreadSafe<GeolocationDispatcherHostOld>;
- GeolocationDispatcherHostOld() {}
- virtual ~GeolocationDispatcherHostOld() {}
-
- DISALLOW_COPY_AND_ASSIGN(GeolocationDispatcherHostOld);
-};
-
-#endif // CHROME_BROWSER_GEOLOCATION_GEOLOCATION_DISPATCHER_HOST_OLD_H_
diff --git a/chrome/browser/geolocation/geolocation_permission_context.cc b/chrome/browser/geolocation/geolocation_permission_context.cc
index bf19218..1f8160d 100644
--- a/chrome/browser/geolocation/geolocation_permission_context.cc
+++ b/chrome/browser/geolocation/geolocation_permission_context.cc
@@ -8,13 +8,12 @@
#include "app/resource_bundle.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
-#include "chrome/browser/geolocation/geolocation_dispatcher_host_old.h"
#include "chrome/browser/geolocation/geolocation_provider.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_view_host_notification_task.h"
@@ -373,7 +372,7 @@ void GeolocationPermissionContext::RequestGeolocationPermission(
}
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- ExtensionsService* extensions = profile_->GetExtensionsService();
+ ExtensionService* extensions = profile_->GetExtensionService();
if (extensions) {
const Extension* ext = extensions->GetExtensionByURL(requesting_frame);
if (!ext)
@@ -440,6 +439,12 @@ void GeolocationPermissionContext::StartUpdatingRequested(
// Note we cannot store the arbitrator as a member as it is not thread safe.
GeolocationProvider* provider = GeolocationProvider::GetInstance();
+#if defined(ENABLE_CLIENT_BASED_GEOLOCATION)
+ // Client-based Geolocation uses a preemptive permission model, so permission
+ // ought to have been requested and granted before the controller requests
+ // the client to start updating.
+ DCHECK(provider->HasPermissionBeenGranted());
+#else
// WebKit will not request permission until it has received a valid
// location, but the google network location provider will not give a
// valid location until the user has granted permission. So we cut the Gordian
@@ -449,11 +454,14 @@ void GeolocationPermissionContext::StartUpdatingRequested(
RequestGeolocationPermission(render_process_id, render_view_id, bridge_id,
requesting_frame);
}
+#endif
}
void GeolocationPermissionContext::StopUpdatingRequested(
int render_process_id, int render_view_id, int bridge_id) {
+#if !defined(ENABLE_CLIENT_BASED_GEOLOCATION)
CancelPendingInfoBarRequest(render_process_id, render_view_id, bridge_id);
+#endif
}
void GeolocationPermissionContext::NotifyPermissionSet(
diff --git a/chrome/browser/geolocation/geolocation_permission_context.h b/chrome/browser/geolocation/geolocation_permission_context.h
index 432c9a2..c2a08e7 100644
--- a/chrome/browser/geolocation/geolocation_permission_context.h
+++ b/chrome/browser/geolocation/geolocation_permission_context.h
@@ -46,7 +46,7 @@ class GeolocationPermissionContext
// Called when a geolocation object wants to start receiving location updates.
// This also applies global policy around which location providers may be
- // enbaled at a given time (e.g. prior to the user agreeing to any geolocation
+ // enabled at a given time (e.g. prior to the user agreeing to any geolocation
// permission requests).
void StartUpdatingRequested(
int render_process_id, int render_view_id, int bridge_id,
diff --git a/chrome/browser/geolocation/geolocation_permission_context_unittest.cc b/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
index 6e40862..0fadbe7 100644
--- a/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
+++ b/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
@@ -290,7 +290,14 @@ TEST_F(GeolocationPermissionContextTests, CancelGeolocationPermissionRequest) {
requesting_frame_1, requesting_frame_0));
}
-TEST_F(GeolocationPermissionContextTests, StopUpdating) {
+// TODO(jknotten): Remove this test once we have completely
+// switched over to client-based geolocation.
+#if defined(ENABLE_CLIENT_BASED_GEOLOCATION)
+#define MAYBE_StopUpdating DISABLED_StopUpdating
+#else
+#define MAYBE_StopUpdating StopUpdating
+#endif
+TEST_F(GeolocationPermissionContextTests, MAYBE_StopUpdating) {
GURL requesting_frame("http://www.example.com/geolocation");
NavigateAndCommit(requesting_frame);
EXPECT_EQ(0, contents()->infobar_delegate_count());
diff --git a/chrome/browser/geolocation/geolocation_provider.cc b/chrome/browser/geolocation/geolocation_provider.cc
index 97e9049..3756af7 100644
--- a/chrome/browser/geolocation/geolocation_provider.cc
+++ b/chrome/browser/geolocation/geolocation_provider.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/geolocation/geolocation_provider.h"
#include "base/singleton.h"
+#include "base/thread_restrictions.h"
#include "chrome/browser/geolocation/location_arbitrator.h"
// This class is guaranteed to outlive its internal thread, so ref counting
@@ -47,6 +48,10 @@ bool GeolocationProvider::RemoveObserver(GeolocationObserver* observer) {
void GeolocationProvider::OnObserversChanged() {
DCHECK(OnClientThread());
if (observers_.empty()) {
+ // http://crbug.com/66077: This is a bug. The geolocation thread may
+ // transitively (via other threads it joins) block on long-running tasks /
+ // IO.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
Stop();
} else {
if (!IsRunning()) {
diff --git a/chrome/browser/geolocation/geolocation_settings_state.cc b/chrome/browser/geolocation/geolocation_settings_state.cc
index 5c7b784..cb9669c 100644
--- a/chrome/browser/geolocation/geolocation_settings_state.cc
+++ b/chrome/browser/geolocation/geolocation_settings_state.cc
@@ -8,7 +8,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/common/pref_names.h"
#include "net/base/net_util.h"
diff --git a/chrome/browser/geolocation/location_arbitrator.cc b/chrome/browser/geolocation/location_arbitrator.cc
index 5b5d08a..4ae6ee7 100644
--- a/chrome/browser/geolocation/location_arbitrator.cc
+++ b/chrome/browser/geolocation/location_arbitrator.cc
@@ -6,7 +6,7 @@
#include <map>
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
namespace {
const char* kDefaultNetworkProviderUrl = "https://www.google.com/loc/json";
diff --git a/chrome/browser/geolocation/mock_location_provider.cc b/chrome/browser/geolocation/mock_location_provider.cc
index 689ab9c..e3575f0 100644
--- a/chrome/browser/geolocation/mock_location_provider.cc
+++ b/chrome/browser/geolocation/mock_location_provider.cc
@@ -78,7 +78,9 @@ class AutoMockLocationProvider : public MockLocationProvider {
position_.accuracy = 3;
position_.latitude = 4.3;
position_.longitude = -7.8;
- position_.timestamp = base::Time::FromDoubleT(4567.8);
+ // Webkit compares the timestamp to wall clock time, so we need it to be
+ // contemporary.
+ position_.timestamp = base::Time::Now();
} else {
position_.error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE;
}
diff --git a/chrome/browser/geolocation/win7_location_api_unittest_win.cc b/chrome/browser/geolocation/win7_location_api_unittest_win.cc
index 3b86762..16d867c 100644
--- a/chrome/browser/geolocation/win7_location_api_unittest_win.cc
+++ b/chrome/browser/geolocation/win7_location_api_unittest_win.cc
@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <Objbase.h>
+
#include <algorithm>
#include <cmath>
-#include <Objbase.h>
#include "base/compiler_specific.h"
#include "base/logging.h"
@@ -13,7 +14,6 @@
#include "base/time.h"
#include "base/win_util.h"
#include "chrome/common/geoposition.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/geolocation/win7_location_api_win.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -25,12 +25,12 @@ using testing::Invoke;
using testing::Return;
class MockLatLongReport : public ILatLongReport {
-public:
+ public:
MockLatLongReport() : ref_count_(1) {
ON_CALL(*this, GetAltitude(_))
.WillByDefault(Invoke(this, &MockLatLongReport::GetAltitudeValid));
ON_CALL(*this, GetAltitudeError(_))
- .WillByDefault(Invoke(this,
+ .WillByDefault(Invoke(this,
&MockLatLongReport::GetAltitudeErrorValid));
ON_CALL(*this, GetErrorRadius(_))
.WillByDefault(Invoke(this, &MockLatLongReport::GetErrorRadiusValid));
@@ -38,7 +38,7 @@ public:
.WillByDefault(Invoke(this, &MockLatLongReport::GetLatitudeValid));
ON_CALL(*this, GetLongitude(_))
.WillByDefault(Invoke(this, &MockLatLongReport::GetLongitudeValid));
- ON_CALL(*this, GetValue(_,_))
+ ON_CALL(*this, GetValue(_, _))
.WillByDefault(Invoke(this, &MockLatLongReport::GetValueValid));
ON_CALL(*this, Release())
.WillByDefault(Invoke(this, &MockLatLongReport::ReleaseInternal));
@@ -120,7 +120,7 @@ public:
delete this;
return new_ref_count;
}
-
+
LONG ref_count_;
};
@@ -136,7 +136,7 @@ class MockReport : public ILocationReport {
ON_CALL(*this, AddRef())
.WillByDefault(Invoke(this, &MockReport::AddRefInternal));
}
-
+
// ILocationReport
MOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE,
GetSensorID,
@@ -160,7 +160,7 @@ class MockReport : public ILocationReport {
MockLatLongReport* mock_lat_long_report_;
-private:
+ private:
~MockReport() {
mock_lat_long_report_->Release();
}
@@ -242,10 +242,10 @@ class MockLocation : public ILocation {
MockReport* mock_report_;
private:
- ~MockLocation() {
+ ~MockLocation() {
mock_report_->Release();
}
-
+
HRESULT GetReportValid(REFIID report_type,
ILocationReport** location_report) {
*location_report = reinterpret_cast<ILocationReport*>(mock_report_);
@@ -288,7 +288,7 @@ class GeolocationApiWin7Tests : public testing::Test {
locator_->Release();
api_.reset();
}
- ~GeolocationApiWin7Tests(){
+ ~GeolocationApiWin7Tests() {
}
protected:
Win7LocationApi* CreateMock() {
diff --git a/chrome/browser/geolocation/win7_location_provider_unittest_win.cc b/chrome/browser/geolocation/win7_location_provider_unittest_win.cc
index 487f005..ababadd 100644
--- a/chrome/browser/geolocation/win7_location_provider_unittest_win.cc
+++ b/chrome/browser/geolocation/win7_location_provider_unittest_win.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/browser_thread.h"
+#include "base/message_loop.h"
#include "chrome/browser/geolocation/win7_location_provider_win.h"
#include "chrome/browser/geolocation/win7_location_api_win.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -49,10 +49,10 @@ class MockWin7LocationApi : public Win7LocationApi {
}
private:
- MockWin7LocationApi() : Win7LocationApi(NULL, NULL, NULL) {
+ MockWin7LocationApi() : Win7LocationApi(NULL, NULL, NULL) {
ON_CALL(*this, GetPosition(_))
.WillByDefault(Invoke(this,
- &MockWin7LocationApi::GetPositionValid));
+ &MockWin7LocationApi::GetPositionValid));
ON_CALL(*this, SetHighAccuracy(true))
.WillByDefault(Return(true));
ON_CALL(*this, SetHighAccuracy(false))
diff --git a/chrome/browser/google/google_update.cc b/chrome/browser/google/google_update.cc
index cb68832..fc7f324 100644
--- a/chrome/browser/google/google_update.cc
+++ b/chrome/browser/google/google_update.cc
@@ -7,6 +7,7 @@
#include <atlbase.h>
#include <atlcom.h>
+#include "base/file_path.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/scoped_comptr_win.h"
@@ -32,8 +33,13 @@ bool CanUpdateCurrentChrome(const std::wstring& chrome_exe_path) {
#if !defined(GOOGLE_CHROME_BUILD)
return false;
#else
- std::wstring user_exe_path = installer::GetChromeInstallPath(false);
- std::wstring machine_exe_path = installer::GetChromeInstallPath(true);
+ // TODO(tommi): Check if using the default distribution is always the right
+ // thing to do.
+ BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+ std::wstring user_exe_path =
+ installer::GetChromeInstallPath(false, dist).value();
+ std::wstring machine_exe_path =
+ installer::GetChromeInstallPath(true, dist).value();
std::transform(user_exe_path.begin(), user_exe_path.end(),
user_exe_path.begin(), tolower);
std::transform(machine_exe_path.begin(), machine_exe_path.end(),
@@ -226,16 +232,17 @@ bool GoogleUpdate::InitiateGoogleUpdateCheck(bool install_if_newer,
Window* window,
MessageLoop* main_loop) {
- std::wstring chrome_exe_path;
+ FilePath chrome_exe_path;
if (!PathService::Get(base::DIR_EXE, &chrome_exe_path)) {
NOTREACHED();
return false;
}
+ std::wstring chrome_exe = chrome_exe_path.value();
- std::transform(chrome_exe_path.begin(), chrome_exe_path.end(),
- chrome_exe_path.begin(), tolower);
+ std::transform(chrome_exe.begin(), chrome_exe.end(),
+ chrome_exe.begin(), tolower);
- if (!CanUpdateCurrentChrome(chrome_exe_path)) {
+ if (!CanUpdateCurrentChrome(chrome_exe)) {
main_loop->PostTask(FROM_HERE, NewRunnableMethod(this,
&GoogleUpdate::ReportResults, UPGRADE_ERROR,
CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY));
@@ -254,7 +261,7 @@ bool GoogleUpdate::InitiateGoogleUpdateCheck(bool install_if_newer,
ScopedComPtr<IGoogleUpdate> on_demand;
- if (InstallUtil::IsPerUserInstall(chrome_exe_path.c_str())) {
+ if (InstallUtil::IsPerUserInstall(chrome_exe.c_str())) {
hr = on_demand.CreateInstance(CLSID_OnDemandUserAppsClass);
} else {
// The Update operation needs Admin privileges for writing
diff --git a/chrome/browser/google/google_url_tracker.cc b/chrome/browser/google/google_url_tracker.cc
index e4f5edb..0070cfb 100644
--- a/chrome/browser/google/google_url_tracker.cc
+++ b/chrome/browser/google/google_url_tracker.cc
@@ -13,7 +13,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/tab_contents.h"
diff --git a/chrome/browser/google/google_url_tracker_unittest.cc b/chrome/browser/google/google_url_tracker_unittest.cc
index d9fe0c7..0892ee3 100644
--- a/chrome/browser/google/google_url_tracker_unittest.cc
+++ b/chrome/browser/google/google_url_tracker_unittest.cc
@@ -3,9 +3,12 @@
// found in the LICENSE file.
#include "chrome/browser/google/google_url_tracker.h"
+
#include "base/command_line.h"
+#include "base/message_loop.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/common/net/url_fetcher.h"
#include "chrome/common/net/url_request_context_getter.h"
diff --git a/chrome/browser/gpu.sb b/chrome/browser/gpu.sb
new file mode 100644
index 0000000..346bcfa
--- /dev/null
+++ b/chrome/browser/gpu.sb
@@ -0,0 +1,18 @@
+;;
+;; 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.
+;;
+
+; *** The contents of chrome/common/common.sb are implicitly included here. ***
+
+; The GPU process opens a shared memory file to communicate with the renderer.
+; This is backed by a file in /var/folders.
+; TODO(thakis): Let the browser allocated the pipe and hand the handles to
+; renderer and GPU process and remove this: http://crbug.com/65344
+(allow file-read* file-write* (regex "^/(private/)?(tmp|var)(/|$)"))
+
+; Allow communication between the GPU process and the UI server.
+(allow mach-lookup (global-name "com.apple.tsm.uiserver"))
+
+(allow file-read-metadata (literal "/"))
diff --git a/chrome/browser/gpu_blacklist.cc b/chrome/browser/gpu_blacklist.cc
index 6bb33c6..85063a8 100644
--- a/chrome/browser/gpu_blacklist.cc
+++ b/chrome/browser/gpu_blacklist.cc
@@ -7,6 +7,7 @@
#include "base/json/json_reader.h"
#include "base/logging.h"
#include "base/string_number_conversions.h"
+#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/sys_info.h"
#include "base/values.h"
@@ -102,6 +103,8 @@ GpuBlacklist::OsInfo::OsInfo(const std::string& os,
}
}
+GpuBlacklist::OsInfo::~OsInfo() {}
+
bool GpuBlacklist::OsInfo::Contains(OsType type,
const Version& version) const {
if (!IsValid())
@@ -214,6 +217,8 @@ GpuBlacklist::GpuBlacklistEntry::GetGpuBlacklistEntryFromValue(
return entry;
}
+GpuBlacklist::GpuBlacklistEntry::~GpuBlacklistEntry() {}
+
GpuBlacklist::GpuBlacklistEntry::GpuBlacklistEntry()
: vendor_id_(0),
device_id_(0) {
@@ -365,7 +370,7 @@ GpuFeatureFlags GpuBlacklist::DetermineGpuFeatureFlags(
if (gpu_info.progress() == GPUInfo::kUninitialized)
return flags;
scoped_ptr<Version> driver_version(
- Version::GetVersionFromString(gpu_info.driver_version()));
+ Version::GetVersionFromString(WideToASCII(gpu_info.driver_version())));
if (driver_version.get() == NULL)
return flags;
diff --git a/chrome/browser/gpu_blacklist.h b/chrome/browser/gpu_blacklist.h
index ee556b3..85c4145 100644
--- a/chrome/browser/gpu_blacklist.h
+++ b/chrome/browser/gpu_blacklist.h
@@ -116,6 +116,7 @@ class GpuBlacklist {
const std::string& version_op,
const std::string& version_string,
const std::string& version_string2);
+ ~OsInfo();
// Determines if a given os/version is included in the OsInfo set.
bool Contains(OsType type, const Version& version) const;
@@ -150,6 +151,8 @@ class GpuBlacklist {
// Returns the GpuFeatureFlags.
GpuFeatureFlags GetGpuFeatureFlags() const;
+ ~GpuBlacklistEntry();
+
private:
GpuBlacklistEntry();
diff --git a/chrome/browser/gpu_process_host.cc b/chrome/browser/gpu_process_host.cc
index 4c85ad0..9e374c4 100644
--- a/chrome/browser/gpu_process_host.cc
+++ b/chrome/browser/gpu_process_host.cc
@@ -10,13 +10,12 @@
#include "base/metrics/histogram.h"
#include "base/string_piece.h"
#include "base/thread.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/gpu_blacklist.h"
#include "chrome/browser/gpu_process_host_ui_shim.h"
+#include "chrome/browser/renderer_host/render_message_filter.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
-#include "chrome/browser/renderer_host/resource_message_filter.h"
#include "chrome/browser/tab_contents/render_view_host_delegate_helper.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/gpu_feature_flags.h"
@@ -29,25 +28,20 @@
#include "media/base/media_switches.h"
#if defined(OS_LINUX)
-#include <gdk/gdkwindow.h>
-#include <gdk/gdkx.h>
+// These two #includes need to come after render_messages.h.
+#include <gdk/gdkwindow.h> // NOLINT
+#include <gdk/gdkx.h> // NOLINT
#include "app/x11_util.h"
#include "gfx/gtk_native_view_id_manager.h"
#include "gfx/size.h"
-#endif
+#endif // defined(OS_LINUX)
namespace {
-enum GPUBlacklistTestResult {
- BLOCKED,
- ALLOWED,
- BLACKLIST_TEST_RESULT_MAX
-};
-
enum GPUProcessLifetimeEvent {
- LAUNCED,
- CRASHED,
- GPU_PROCESS_LIFETIME_EVENT_MAX
+ kLaunched,
+ kCrashed,
+ kGPUProcessLifetimeEvent_Max
};
// Tasks used by this file
@@ -58,7 +52,7 @@ class RouteOnUIThreadTask : public Task {
private:
void Run() {
- GpuProcessHostUIShim::Get()->OnMessageReceived(msg_);
+ GpuProcessHostUIShim::GetInstance()->OnMessageReceived(msg_);
}
IPC::Message msg_;
};
@@ -86,8 +80,7 @@ void RouteOnUIThread(const IPC::Message& message) {
GpuProcessHost::GpuProcessHost()
: BrowserChildProcessHost(GPU_PROCESS, NULL),
initialized_(false),
- initialized_successfully_(false),
- blacklist_result_recorded_(false) {
+ initialized_successfully_(false) {
DCHECK_EQ(sole_instance_, static_cast<GpuProcessHost*>(NULL));
}
@@ -139,17 +132,18 @@ bool GpuProcessHost::Send(IPC::Message* msg) {
return BrowserChildProcessHost::Send(msg);
}
-void GpuProcessHost::OnMessageReceived(const IPC::Message& message) {
+bool GpuProcessHost::OnMessageReceived(const IPC::Message& message) {
DCHECK(CalledOnValidThread());
if (message.routing_id() == MSG_ROUTING_CONTROL)
- OnControlMessageReceived(message);
- else
- RouteOnUIThread(message);
+ return OnControlMessageReceived(message);
+
+ RouteOnUIThread(message);
+ return true;
}
void GpuProcessHost::EstablishGpuChannel(int renderer_id,
- ResourceMessageFilter* filter) {
+ RenderMessageFilter* filter) {
DCHECK(CalledOnValidThread());
if (Send(new GpuMsg_EstablishChannel(renderer_id))) {
@@ -160,7 +154,7 @@ void GpuProcessHost::EstablishGpuChannel(int renderer_id,
}
void GpuProcessHost::Synchronize(IPC::Message* reply,
- ResourceMessageFilter* filter) {
+ RenderMessageFilter* filter) {
DCHECK(CalledOnValidThread());
if (Send(new GpuMsg_Synchronize())) {
@@ -170,7 +164,7 @@ void GpuProcessHost::Synchronize(IPC::Message* reply,
}
}
-GpuProcessHost::ChannelRequest::ChannelRequest(ResourceMessageFilter* filter)
+GpuProcessHost::ChannelRequest::ChannelRequest(RenderMessageFilter* filter)
: filter(filter) {
}
@@ -178,14 +172,14 @@ GpuProcessHost::ChannelRequest::~ChannelRequest() {}
GpuProcessHost::SynchronizationRequest::SynchronizationRequest(
IPC::Message* reply,
- ResourceMessageFilter* filter)
+ RenderMessageFilter* filter)
: reply(reply),
filter(filter) {
}
GpuProcessHost::SynchronizationRequest::~SynchronizationRequest() {}
-void GpuProcessHost::OnControlMessageReceived(const IPC::Message& message) {
+bool GpuProcessHost::OnControlMessageReceived(const IPC::Message& message) {
DCHECK(CalledOnValidThread());
IPC_BEGIN_MESSAGE_MAP(GpuProcessHost, message)
@@ -209,6 +203,8 @@ void GpuProcessHost::OnControlMessageReceived(const IPC::Message& message) {
// handle it.
IPC_MESSAGE_UNHANDLED(RouteOnUIThread(message))
IPC_END_MESSAGE_MAP()
+
+ return true;
}
void GpuProcessHost::OnChannelEstablished(
@@ -222,19 +218,11 @@ void GpuProcessHost::OnChannelEstablished(
const ChannelRequest& request = sent_requests_.front();
// Currently if any of the GPU features are blacklised, we don't establish a
// GPU channel.
- GPUBlacklistTestResult test_result;
if (gpu_feature_flags.flags() != 0) {
Send(new GpuMsg_CloseChannel(channel_handle));
SendEstablishChannelReply(IPC::ChannelHandle(), gpu_info, request.filter);
- test_result = BLOCKED;
} else {
SendEstablishChannelReply(channel_handle, gpu_info, request.filter);
- test_result = ALLOWED;
- }
- if (!blacklist_result_recorded_) {
- UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResults",
- test_result, BLACKLIST_TEST_RESULT_MAX);
- blacklist_result_recorded_ = true;
}
sent_requests_.pop();
}
@@ -257,7 +245,7 @@ void SendDelayedReply(IPC::Message* reply_msg) {
void GetViewXIDDispatcher(gfx::NativeViewId id, IPC::Message* reply_msg) {
XID xid;
- GtkNativeViewManager* manager = Singleton<GtkNativeViewManager>::get();
+ GtkNativeViewManager* manager = GtkNativeViewManager::GetInstance();
if (!manager->GetPermanentXIDForId(&xid, id)) {
DLOG(ERROR) << "Can't find XID for view id " << id;
xid = 0;
@@ -272,7 +260,7 @@ void GetViewXIDDispatcher(gfx::NativeViewId id, IPC::Message* reply_msg) {
}
void ReleaseXIDDispatcher(unsigned long xid) {
- GtkNativeViewManager* manager = Singleton<GtkNativeViewManager>::get();
+ GtkNativeViewManager* manager = GtkNativeViewManager::GetInstance();
manager->ReleasePermanentXID(xid);
}
@@ -475,7 +463,7 @@ void GpuProcessHost::OnGetCompositorHostWindow(
void GpuProcessHost::SendEstablishChannelReply(
const IPC::ChannelHandle& channel,
const GPUInfo& gpu_info,
- ResourceMessageFilter* filter) {
+ RenderMessageFilter* filter) {
ViewMsg_GpuChannelEstablished* message =
new ViewMsg_GpuChannelEstablished(channel, gpu_info);
// If the renderer process is performing synchronous initialization,
@@ -488,16 +476,10 @@ void GpuProcessHost::SendEstablishChannelReply(
// Sends the response for synchronization request to the renderer.
void GpuProcessHost::SendSynchronizationReply(
IPC::Message* reply,
- ResourceMessageFilter* filter) {
+ RenderMessageFilter* filter) {
filter->Send(reply);
}
-URLRequestContext* GpuProcessHost::GetRequestContext(
- uint32 request_id,
- const ViewHostMsg_Resource_Request& request_data) {
- return NULL;
-}
-
bool GpuProcessHost::CanShutdown() {
return true;
}
@@ -506,16 +488,16 @@ void GpuProcessHost::OnChildDied() {
// Located in OnChildDied because OnProcessCrashed suffers from a race
// condition on Linux. The GPU process will only die if it crashes.
UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLifetimeEvents",
- CRASHED, GPU_PROCESS_LIFETIME_EVENT_MAX);
+ kCrashed, kGPUProcessLifetimeEvent_Max);
BrowserChildProcessHost::OnChildDied();
}
-void GpuProcessHost::OnProcessCrashed() {
+void GpuProcessHost::OnProcessCrashed(int exit_code) {
if (++g_gpu_crash_count >= kGpuMaxCrashCount) {
// The gpu process is too unstable to use. Disable it for current session.
RenderViewHostDelegateHelper::set_gpu_enabled(false);
}
- BrowserChildProcessHost::OnProcessCrashed();
+ BrowserChildProcessHost::OnProcessCrashed(exit_code);
}
bool GpuProcessHost::CanLaunchGpuProcess() const {
@@ -543,8 +525,13 @@ bool GpuProcessHost::LaunchGpuProcess() {
switches::kDisableLogging,
switches::kEnableAcceleratedDecoding,
switches::kEnableLogging,
+#if defined(OS_MACOSX)
+ switches::kEnableSandboxLogging,
+#endif
switches::kGpuStartupDialog,
switches::kLoggingLevel,
+ switches::kNoGpuSandbox,
+ switches::kNoSandbox,
};
cmd_line->CopySwitchesFrom(browser_command_line, kSwitchNames,
arraysize(kSwitchNames));
@@ -563,7 +550,7 @@ bool GpuProcessHost::LaunchGpuProcess() {
cmd_line);
UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLifetimeEvents",
- LAUNCED, GPU_PROCESS_LIFETIME_EVENT_MAX);
+ kLaunched, kGPUProcessLifetimeEvent_Max);
return true;
}
diff --git a/chrome/browser/gpu_process_host.h b/chrome/browser/gpu_process_host.h
index 762b98f..14edf88 100644
--- a/chrome/browser/gpu_process_host.h
+++ b/chrome/browser/gpu_process_host.h
@@ -18,7 +18,7 @@ struct GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params;
struct GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params;
class GpuBlacklist;
class GPUInfo;
-class ResourceMessageFilter;
+class RenderMessageFilter;
namespace gfx {
class Size;
@@ -37,33 +37,30 @@ class GpuProcessHost : public BrowserChildProcessHost, public NonThreadSafe {
virtual bool Send(IPC::Message* msg);
// IPC::Channel::Listener implementation.
- virtual void OnMessageReceived(const IPC::Message& message);
+ virtual bool OnMessageReceived(const IPC::Message& message);
// Tells the GPU process to create a new channel for communication with a
// renderer. Will asynchronously send message to object with given routing id
// on completion.
- void EstablishGpuChannel(int renderer_id,
- ResourceMessageFilter* filter);
+ void EstablishGpuChannel(int renderer_id, RenderMessageFilter* filter);
// Sends a reply message later when the next GpuHostMsg_SynchronizeReply comes
// in.
- void Synchronize(IPC::Message* reply,
- ResourceMessageFilter* filter);
+ void Synchronize(IPC::Message* reply, RenderMessageFilter* filter);
private:
// Used to queue pending channel requests.
struct ChannelRequest {
- explicit ChannelRequest(ResourceMessageFilter* filter);
+ explicit ChannelRequest(RenderMessageFilter* filter);
~ChannelRequest();
// Used to send the reply message back to the renderer.
- scoped_refptr<ResourceMessageFilter> filter;
+ scoped_refptr<RenderMessageFilter> filter;
};
// Used to queue pending synchronization requests.
struct SynchronizationRequest {
- SynchronizationRequest(IPC::Message* reply,
- ResourceMessageFilter* filter);
+ SynchronizationRequest(IPC::Message* reply, RenderMessageFilter* filter);
~SynchronizationRequest();
// The delayed reply message which needs to be sent to the
@@ -71,7 +68,7 @@ class GpuProcessHost : public BrowserChildProcessHost, public NonThreadSafe {
IPC::Message* reply;
// Used to send the reply message back to the renderer.
- scoped_refptr<ResourceMessageFilter> filter;
+ scoped_refptr<RenderMessageFilter> filter;
};
GpuProcessHost();
@@ -80,7 +77,7 @@ class GpuProcessHost : public BrowserChildProcessHost, public NonThreadSafe {
bool EnsureInitialized();
bool Init();
- void OnControlMessageReceived(const IPC::Message& message);
+ bool OnControlMessageReceived(const IPC::Message& message);
// Message handlers.
void OnChannelEstablished(const IPC::ChannelHandle& channel_handle,
@@ -104,19 +101,14 @@ class GpuProcessHost : public BrowserChildProcessHost, public NonThreadSafe {
// Sends the response for establish channel request to the renderer.
void SendEstablishChannelReply(const IPC::ChannelHandle& channel,
const GPUInfo& gpu_info,
- ResourceMessageFilter* filter);
+ RenderMessageFilter* filter);
// Sends the response for synchronization request to the renderer.
void SendSynchronizationReply(IPC::Message* reply,
- ResourceMessageFilter* filter);
-
- // ResourceDispatcherHost::Receiver implementation:
- virtual URLRequestContext* GetRequestContext(
- uint32 request_id,
- const ViewHostMsg_Resource_Request& request_data);
+ RenderMessageFilter* filter);
virtual bool CanShutdown();
virtual void OnChildDied();
- virtual void OnProcessCrashed();
+ virtual void OnProcessCrashed(int exit_code);
bool CanLaunchGpuProcess() const;
bool LaunchGpuProcess();
@@ -126,8 +118,6 @@ class GpuProcessHost : public BrowserChildProcessHost, public NonThreadSafe {
bool initialized_;
bool initialized_successfully_;
- bool blacklist_result_recorded_;
-
scoped_ptr<GpuBlacklist> gpu_blacklist_;
// These are the channel requests that we have already sent to
diff --git a/chrome/browser/gpu_process_host_ui_shim.cc b/chrome/browser/gpu_process_host_ui_shim.cc
index d8257a8..87c7be2 100644
--- a/chrome/browser/gpu_process_host_ui_shim.cc
+++ b/chrome/browser/gpu_process_host_ui_shim.cc
@@ -34,7 +34,7 @@ GpuProcessHostUIShim::~GpuProcessHostUIShim() {
}
// static
-GpuProcessHostUIShim* GpuProcessHostUIShim::Get() {
+GpuProcessHostUIShim* GpuProcessHostUIShim::GetInstance() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
return Singleton<GpuProcessHostUIShim>::get();
}
@@ -63,13 +63,13 @@ void GpuProcessHostUIShim::RemoveRoute(int32 routing_id) {
router_.RemoveRoute(routing_id);
}
-void GpuProcessHostUIShim::OnMessageReceived(const IPC::Message& message) {
+bool GpuProcessHostUIShim::OnMessageReceived(const IPC::Message& message) {
DCHECK(CalledOnValidThread());
if (message.routing_id() == MSG_ROUTING_CONTROL)
- OnControlMessageReceived(message);
- else
- router_.RouteMessage(message);
+ return OnControlMessageReceived(message);
+
+ return router_.RouteMessage(message);
}
void GpuProcessHostUIShim::CollectGraphicsInfoAsynchronously() {
@@ -104,6 +104,10 @@ const GPUInfo& GpuProcessHostUIShim::gpu_info() const {
void GpuProcessHostUIShim::OnGraphicsInfoCollected(const GPUInfo& gpu_info) {
gpu_info_ = gpu_info;
child_process_logging::SetGpuInfo(gpu_info);
+
+ // Used only in testing.
+ if (gpu_info_collected_callback_.get())
+ gpu_info_collected_callback_->Run();
}
void GpuProcessHostUIShim::OnScheduleComposite(int renderer_id,
@@ -115,7 +119,8 @@ void GpuProcessHostUIShim::OnScheduleComposite(int renderer_id,
}
host->ScheduleComposite();
}
-void GpuProcessHostUIShim::OnControlMessageReceived(
+
+bool GpuProcessHostUIShim::OnControlMessageReceived(
const IPC::Message& message) {
DCHECK(CalledOnValidThread());
@@ -123,9 +128,10 @@ void GpuProcessHostUIShim::OnControlMessageReceived(
IPC_MESSAGE_HANDLER(GpuHostMsg_GraphicsInfoCollected,
OnGraphicsInfoCollected)
#if defined(OS_WIN)
- IPC_MESSAGE_HANDLER(GpuHostMsg_ScheduleComposite,
- OnScheduleComposite);
+ IPC_MESSAGE_HANDLER(GpuHostMsg_ScheduleComposite, OnScheduleComposite);
#endif
IPC_MESSAGE_UNHANDLED_ERROR()
IPC_END_MESSAGE_MAP()
+
+ return true;
}
diff --git a/chrome/browser/gpu_process_host_ui_shim.h b/chrome/browser/gpu_process_host_ui_shim.h
index eda33d2..f261093 100644
--- a/chrome/browser/gpu_process_host_ui_shim.h
+++ b/chrome/browser/gpu_process_host_ui_shim.h
@@ -11,7 +11,9 @@
// portion of this class, the GpuProcessHost, is responsible for
// shuttling messages between the browser and GPU processes.
+#include "base/callback.h"
#include "base/non_thread_safe.h"
+#include "base/scoped_ptr.h"
#include "base/singleton.h"
#include "chrome/common/gpu_info.h"
#include "chrome/common/message_router.h"
@@ -23,7 +25,7 @@ class GpuProcessHostUIShim : public IPC::Channel::Sender,
public NonThreadSafe {
public:
// Getter for the singleton. This will return NULL on failure.
- static GpuProcessHostUIShim* Get();
+ static GpuProcessHostUIShim* GetInstance();
int32 GetNextRoutingId();
@@ -34,7 +36,7 @@ class GpuProcessHostUIShim : public IPC::Channel::Sender,
// The GpuProcessHost causes this to be called on the UI thread to
// dispatch the incoming messages from the GPU process, which are
// actually received on the IO thread.
- virtual void OnMessageReceived(const IPC::Message& message);
+ virtual bool OnMessageReceived(const IPC::Message& message);
// See documentation on MessageRouter for AddRoute and RemoveRoute
void AddRoute(int32 routing_id, IPC::Channel::Listener* listener);
@@ -54,6 +56,13 @@ class GpuProcessHostUIShim : public IPC::Channel::Sender,
// Return all known information about the GPU.
const GPUInfo& gpu_info() const;
+ // Used only in testing. Sets a callback to invoke when GPU info is collected,
+ // regardless of whether it has been collected already or if it is partial
+ // or complete info. Set to NULL when the callback should no longer be called.
+ void set_gpu_info_collected_callback(Callback0::Type* callback) {
+ gpu_info_collected_callback_.reset(callback);
+ }
+
private:
friend struct DefaultSingletonTraits<GpuProcessHostUIShim>;
@@ -63,13 +72,17 @@ class GpuProcessHostUIShim : public IPC::Channel::Sender,
// Message handlers.
void OnGraphicsInfoCollected(const GPUInfo& gpu_info);
void OnScheduleComposite(int32 renderer_id, int32 render_view_id);
- void OnControlMessageReceived(const IPC::Message& message);
+ bool OnControlMessageReceived(const IPC::Message& message);
int last_routing_id_;
GPUInfo gpu_info_;
MessageRouter router_;
+
+ // Used only in testing. If set, the callback is invoked when the GPU info
+ // has been collected.
+ scoped_ptr<Callback0::Type> gpu_info_collected_callback_;
};
#endif // CHROME_BROWSER_GPU_PROCESS_HOST_UI_SHIM_H_
diff --git a/chrome/browser/gtk/about_chrome_dialog.cc b/chrome/browser/gtk/about_chrome_dialog.cc
index cf22f23..23fad57 100644
--- a/chrome/browser/gtk/about_chrome_dialog.cc
+++ b/chrome/browser/gtk/about_chrome_dialog.cc
@@ -18,7 +18,7 @@
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/platform_util.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/url_constants.h"
diff --git a/chrome/browser/gtk/accelerators_gtk.cc b/chrome/browser/gtk/accelerators_gtk.cc
index c0a2f73..5456b0d 100644
--- a/chrome/browser/gtk/accelerators_gtk.cc
+++ b/chrome/browser/gtk/accelerators_gtk.cc
@@ -8,6 +8,7 @@
#include <gdk/gdkkeysyms.h>
#include <X11/XF86keysym.h>
+#include "base/singleton.h"
#include "chrome/app/chrome_command_ids.h"
namespace {
@@ -190,6 +191,11 @@ AcceleratorsGtk::AcceleratorsGtk() {
AcceleratorsGtk::~AcceleratorsGtk() {}
+// static
+AcceleratorsGtk* AcceleratorsGtk::GetInstance() {
+ return Singleton<AcceleratorsGtk>::get();
+}
+
const menus::AcceleratorGtk* AcceleratorsGtk::GetPrimaryAcceleratorForCommand(
int command_id) {
base::hash_map<int, menus::AcceleratorGtk>::const_iterator iter =
diff --git a/chrome/browser/gtk/accelerators_gtk.h b/chrome/browser/gtk/accelerators_gtk.h
index 1ea7ce4..2e45700 100644
--- a/chrome/browser/gtk/accelerators_gtk.h
+++ b/chrome/browser/gtk/accelerators_gtk.h
@@ -9,15 +9,17 @@
#include "app/menus/accelerator_gtk.h"
#include "base/hash_tables.h"
+template <typename T> struct DefaultSingletonTraits;
+
class AcceleratorsGtk {
public:
- AcceleratorsGtk();
- ~AcceleratorsGtk();
-
typedef std::vector<std::pair<int, menus::AcceleratorGtk> >
AcceleratorGtkList;
typedef AcceleratorGtkList::const_iterator const_iterator;
+ // Returns the singleton instance.
+ static AcceleratorsGtk* GetInstance();
+
const_iterator const begin() {
return all_accelerators_.begin();
}
@@ -30,6 +32,11 @@ class AcceleratorsGtk {
const menus::AcceleratorGtk* GetPrimaryAcceleratorForCommand(int command_id);
private:
+ friend struct DefaultSingletonTraits<AcceleratorsGtk>;
+
+ AcceleratorsGtk();
+ ~AcceleratorsGtk();
+
base::hash_map<int, menus::AcceleratorGtk> primary_accelerators_;
AcceleratorGtkList all_accelerators_;
diff --git a/chrome/browser/gtk/accessibility_event_router_gtk.cc b/chrome/browser/gtk/accessibility_event_router_gtk.cc
index fade7eb..1248247 100644
--- a/chrome/browser/gtk/accessibility_event_router_gtk.cc
+++ b/chrome/browser/gtk/accessibility_event_router_gtk.cc
@@ -10,13 +10,13 @@
#include "base/stl_util-inl.h"
#include "chrome/browser/extensions/extension_accessibility_api.h"
#include "chrome/browser/gtk/gtk_chrome_link_button.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/notification_type.h"
-#include "views/controls/textfield/native_textfield_gtk.h"
#if defined(TOOLKIT_VIEWS)
#include "views/controls/textfield/gtk_views_textview.h"
#include "views/controls/textfield/gtk_views_entry.h"
+#include "views/controls/textfield/native_textfield_gtk.h"
#endif
namespace {
diff --git a/chrome/browser/gtk/accessible_widget_helper_gtk.cc b/chrome/browser/gtk/accessible_widget_helper_gtk.cc
index 6a25d94..029aca4 100644
--- a/chrome/browser/gtk/accessible_widget_helper_gtk.cc
+++ b/chrome/browser/gtk/accessible_widget_helper_gtk.cc
@@ -6,7 +6,7 @@
#include "app/l10n_util.h"
#include "chrome/browser/accessibility_events.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/notification_service.h"
AccessibleWidgetHelper::AccessibleWidgetHelper(
diff --git a/chrome/browser/gtk/back_forward_button_gtk.cc b/chrome/browser/gtk/back_forward_button_gtk.cc
index 669b9d7..29cf61c 100644
--- a/chrome/browser/gtk/back_forward_button_gtk.cc
+++ b/chrome/browser/gtk/back_forward_button_gtk.cc
@@ -9,12 +9,12 @@
#include "app/l10n_util.h"
#include "base/message_loop.h"
#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/back_forward_menu_model.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/gtk/menu_gtk.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/toolbar/back_forward_menu_model.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
diff --git a/chrome/browser/gtk/bookmark_bar_gtk.cc b/chrome/browser/gtk/bookmark_bar_gtk.cc
index 362dbd6..ab6c5a5 100644
--- a/chrome/browser/gtk/bookmark_bar_gtk.cc
+++ b/chrome/browser/gtk/bookmark_bar_gtk.cc
@@ -34,7 +34,7 @@
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/ntp_background_util.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/sync_ui_util.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
@@ -86,6 +86,7 @@ const double kTopBorderColor[] =
const int kDestTargetList[] = { gtk_dnd_util::CHROME_BOOKMARK_ITEM,
gtk_dnd_util::CHROME_NAMED_URL,
gtk_dnd_util::TEXT_URI_LIST,
+ gtk_dnd_util::NETSCAPE_URL,
gtk_dnd_util::TEXT_PLAIN, -1 };
// Acceptable drag actions for the bookmark bar drag destinations.
@@ -1271,6 +1272,12 @@ void BookmarkBarGtk::OnDragReceived(GtkWidget* widget,
break;
}
+ case gtk_dnd_util::NETSCAPE_URL: {
+ dnd_success = bookmark_utils::CreateNewBookmarkFromNetscapeURL(
+ selection_data, model_, dest_node, index);
+ break;
+ }
+
case gtk_dnd_util::TEXT_PLAIN: {
guchar* text = gtk_selection_data_get_text(selection_data);
if (!text)
diff --git a/chrome/browser/gtk/bookmark_bubble_gtk.cc b/chrome/browser/gtk/bookmark_bubble_gtk.cc
index 33cf4f5..ba0e198 100644
--- a/chrome/browser/gtk/bookmark_bubble_gtk.cc
+++ b/chrome/browser/gtk/bookmark_bubble_gtk.cc
@@ -22,7 +22,7 @@
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/gtk/info_bubble_gtk.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/notification_service.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/gtk/bookmark_editor_gtk.cc b/chrome/browser/gtk/bookmark_editor_gtk.cc
index 1ad5857..74558e1 100644
--- a/chrome/browser/gtk/bookmark_editor_gtk.cc
+++ b/chrome/browser/gtk/bookmark_editor_gtk.cc
@@ -20,7 +20,7 @@
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/net/url_fixer_upper.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "gfx/gtk_util.h"
#include "gfx/point.h"
#include "googleurl/src/gurl.h"
diff --git a/chrome/browser/gtk/bookmark_editor_gtk_unittest.cc b/chrome/browser/gtk/bookmark_editor_gtk_unittest.cc
index 6a12fb8..9a8c651 100644
--- a/chrome/browser/gtk/bookmark_editor_gtk_unittest.cc
+++ b/chrome/browser/gtk/bookmark_editor_gtk_unittest.cc
@@ -11,7 +11,7 @@
#include "chrome/browser/gtk/bookmark_editor_gtk.h"
#include "chrome/browser/gtk/bookmark_tree_model.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/gtk/bookmark_menu_controller_gtk.cc b/chrome/browser/gtk/bookmark_menu_controller_gtk.cc
index be7662f..21939c1 100644
--- a/chrome/browser/gtk/bookmark_menu_controller_gtk.cc
+++ b/chrome/browser/gtk/bookmark_menu_controller_gtk.cc
@@ -17,7 +17,7 @@
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/gtk/menu_gtk.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/page_navigator.h"
#include "gfx/gtk_util.h"
#include "grit/app_resources.h"
@@ -155,11 +155,10 @@ void BookmarkMenuController::BuildMenu(const BookmarkNode* parent,
// This breaks on word boundaries. Ideally we would break on character
// boundaries.
- std::string elided_name = WideToUTF8(
- l10n_util::TruncateString(UTF16ToWideHack(node->GetTitle()),
- kMaxChars));
+ string16 elided_name = l10n_util::TruncateString(node->GetTitle(),
+ kMaxChars);
GtkWidget* menu_item =
- gtk_image_menu_item_new_with_label(elided_name.c_str());
+ gtk_image_menu_item_new_with_label(UTF16ToUTF8(elided_name).c_str());
g_object_set_data(G_OBJECT(menu_item), "bookmark-node", AsVoid(node));
SetImageMenuItem(menu_item, node, profile_->GetBookmarkModel());
gtk_util::SetAlwaysShowImage(menu_item);
diff --git a/chrome/browser/gtk/bookmark_utils_gtk.cc b/chrome/browser/gtk/bookmark_utils_gtk.cc
index fa7505c..62acc14 100644
--- a/chrome/browser/gtk/bookmark_utils_gtk.cc
+++ b/chrome/browser/gtk/bookmark_utils_gtk.cc
@@ -17,7 +17,7 @@
#include "chrome/browser/gtk/gtk_chrome_button.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/gtk/gtk_util.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "gfx/canvas_skia_paint.h"
#include "gfx/font.h"
#include "gfx/gtk_util.h"
@@ -246,8 +246,8 @@ std::string BuildTooltipFor(const BookmarkNode* node) {
const std::string& url = node->GetURL().possibly_invalid_spec();
const std::string& title = UTF16ToUTF8(node->GetTitle());
- std::string truncated_url = WideToUTF8(l10n_util::TruncateString(
- UTF8ToWide(url), kMaxTooltipURLLength));
+ std::string truncated_url = UTF16ToUTF8(l10n_util::TruncateString(
+ UTF8ToUTF16(url), kMaxTooltipURLLength));
gchar* escaped_url_cstr = g_markup_escape_text(truncated_url.c_str(),
truncated_url.size());
std::string escaped_url(escaped_url_cstr);
@@ -257,8 +257,8 @@ std::string BuildTooltipFor(const BookmarkNode* node) {
if (url == title || title.empty()) {
return escaped_url;
} else {
- std::string truncated_title = WideToUTF8(l10n_util::TruncateString(
- UTF16ToWideHack(node->GetTitle()), kMaxTooltipTitleLength));
+ std::string truncated_title = UTF16ToUTF8(l10n_util::TruncateString(
+ node->GetTitle(), kMaxTooltipTitleLength));
gchar* escaped_title_cstr = g_markup_escape_text(truncated_title.c_str(),
truncated_title.size());
std::string escaped_title(escaped_title_cstr);
@@ -427,4 +427,15 @@ bool CreateNewBookmarksFromURIList(GtkSelectionData* selection_data,
return true;
}
+bool CreateNewBookmarkFromNetscapeURL(GtkSelectionData* selection_data,
+ BookmarkModel* model, const BookmarkNode* parent, int idx) {
+ GURL url;
+ string16 title;
+ if (!gtk_dnd_util::ExtractNetscapeURL(selection_data, &url, &title))
+ return false;
+
+ model->AddURL(parent, idx, title, url);
+ return true;
+}
+
} // namespace bookmark_utils
diff --git a/chrome/browser/gtk/bookmark_utils_gtk.h b/chrome/browser/gtk/bookmark_utils_gtk.h
index 0e666c7..1ebc627 100644
--- a/chrome/browser/gtk/bookmark_utils_gtk.h
+++ b/chrome/browser/gtk/bookmark_utils_gtk.h
@@ -98,6 +98,13 @@ bool CreateNewBookmarksFromURIList(
const BookmarkNode* parent,
int idx);
+// Add the "url\ntitle" combination into the model at the given position.
+bool CreateNewBookmarkFromNetscapeURL(
+ GtkSelectionData* selection_data,
+ BookmarkModel* model,
+ const BookmarkNode* parent,
+ int idx);
+
} // namespace bookmark_utils
#endif // CHROME_BROWSER_GTK_BOOKMARK_UTILS_GTK_H_
diff --git a/chrome/browser/gtk/browser_actions_toolbar_gtk.cc b/chrome/browser/gtk/browser_actions_toolbar_gtk.cc
index 9a493ac..9ed0106 100644
--- a/chrome/browser/gtk/browser_actions_toolbar_gtk.cc
+++ b/chrome/browser/gtk/browser_actions_toolbar_gtk.cc
@@ -10,7 +10,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/extensions/extension_browser_event_router.h"
#include "chrome/browser/extensions/extension_context_menu_model.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/image_loading_tracker.h"
#include "chrome/browser/gtk/cairo_cached_surface.h"
#include "chrome/browser/gtk/extension_popup_gtk.h"
@@ -21,7 +21,7 @@
#include "chrome/browser/gtk/hover_controller_gtk.h"
#include "chrome/browser/gtk/menu_gtk.h"
#include "chrome/browser/gtk/view_id_util.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/extensions/extension.h"
@@ -363,7 +363,7 @@ BrowserActionsToolbarGtk::BrowserActionsToolbarGtk(Browser* browser)
desired_width_(0),
start_width_(0),
method_factory_(this) {
- ExtensionsService* extension_service = profile_->GetExtensionsService();
+ ExtensionService* extension_service = profile_->GetExtensionService();
// The |extension_service| can be NULL in Incognito.
if (!extension_service)
return;
@@ -562,7 +562,7 @@ bool BrowserActionsToolbarGtk::ShouldDisplayBrowserAction(
const Extension* extension) {
// Only display incognito-enabled extensions while in incognito mode.
return (!profile_->IsOffTheRecord() ||
- profile_->GetExtensionsService()->IsIncognitoEnabled(extension));
+ profile_->GetExtensionService()->IsIncognitoEnabled(extension));
}
void BrowserActionsToolbarGtk::HidePopup() {
@@ -649,6 +649,20 @@ void BrowserActionsToolbarGtk::AnimationEnded(const Animation* animation) {
UpdateChevronVisibility();
}
+bool BrowserActionsToolbarGtk::IsCommandIdChecked(int command_id) const {
+ return false;
+}
+
+bool BrowserActionsToolbarGtk::IsCommandIdEnabled(int command_id) const {
+ return true;
+}
+
+bool BrowserActionsToolbarGtk::GetAcceleratorForCommandId(
+ int command_id,
+ menus::Accelerator* accelerator) {
+ return false;
+}
+
void BrowserActionsToolbarGtk::ExecuteCommand(int command_id) {
const Extension* extension = model_->GetExtensionByIndex(command_id);
ExtensionAction* browser_action = extension->browser_action();
diff --git a/chrome/browser/gtk/browser_actions_toolbar_gtk.h b/chrome/browser/gtk/browser_actions_toolbar_gtk.h
index ac80386..452a642 100644
--- a/chrome/browser/gtk/browser_actions_toolbar_gtk.h
+++ b/chrome/browser/gtk/browser_actions_toolbar_gtk.h
@@ -61,9 +61,9 @@ class BrowserActionsToolbarGtk : public ExtensionToolbarModel::Observer,
void Update();
// NotificationObserver implementation.
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
bool animating() {
return resize_animation_.is_animating();
@@ -117,13 +117,11 @@ class BrowserActionsToolbarGtk : public ExtensionToolbarModel::Observer,
// SimpleMenuModel::Delegate implementation.
// In our case, |command_id| is be the index into the model's extension list.
- virtual bool IsCommandIdChecked(int command_id) const { return false; }
- virtual bool IsCommandIdEnabled(int command_id) const { return true; }
+ virtual bool IsCommandIdChecked(int command_id) const;
+ virtual bool IsCommandIdEnabled(int command_id) const;
virtual bool GetAcceleratorForCommandId(
int command_id,
- menus::Accelerator* accelerator) {
- return false;
- }
+ menus::Accelerator* accelerator);
virtual void ExecuteCommand(int command_id);
// MenuGtk::Delegate implementation.
diff --git a/chrome/browser/gtk/browser_titlebar.cc b/chrome/browser/gtk/browser_titlebar.cc
index 71c8571..7af5a5e 100644
--- a/chrome/browser/gtk/browser_titlebar.cc
+++ b/chrome/browser/gtk/browser_titlebar.cc
@@ -18,7 +18,6 @@
#include "base/string_tokenizer.h"
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/encoding_menu_controller.h"
#include "chrome/browser/gtk/accelerators_gtk.h"
#include "chrome/browser/gtk/browser_window_gtk.h"
#include "chrome/browser/gtk/custom_button.h"
@@ -31,10 +30,11 @@
#include "chrome/browser/gtk/nine_box.h"
#include "chrome/browser/gtk/tabs/tab_strip_gtk.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/wrench_menu_model.h"
+#include "chrome/browser/ui/toolbar/encoding_menu_controller.h"
+#include "chrome/browser/ui/toolbar/wrench_menu_model.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "gfx/gtk_util.h"
@@ -307,7 +307,7 @@ void BrowserTitlebar::Init() {
#if defined(USE_GCONF)
// Either read the gconf database and register for updates (on GNOME), or use
// the default value (anywhere else).
- Singleton<GConfTitlebarListener>()->SetTitlebarButtons(this);
+ GConfTitlebarListener::GetInstance()->SetTitlebarButtons(this);
#else
BuildButtons(kDefaultButtonString);
#endif
@@ -373,7 +373,7 @@ void BrowserTitlebar::Init() {
BrowserTitlebar::~BrowserTitlebar() {
ActiveWindowWatcherX::RemoveObserver(this);
#if defined(USE_GCONF)
- Singleton<GConfTitlebarListener>()->RemoveObserver(this);
+ GConfTitlebarListener::GetInstance()->RemoveObserver(this);
#endif
}
@@ -849,7 +849,7 @@ void BrowserTitlebar::ExecuteCommand(int command_id) {
bool BrowserTitlebar::GetAcceleratorForCommandId(
int command_id, menus::Accelerator* accelerator) {
const menus::AcceleratorGtk* accelerator_gtk =
- Singleton<AcceleratorsGtk>()->GetPrimaryAcceleratorForCommand(
+ AcceleratorsGtk::GetInstance()->GetPrimaryAcceleratorForCommand(
command_id);
if (accelerator_gtk)
*accelerator = *accelerator_gtk;
diff --git a/chrome/browser/gtk/browser_toolbar_gtk.cc b/chrome/browser/gtk/browser_toolbar_gtk.cc
index bfcce1b..3af9c38 100644
--- a/chrome/browser/gtk/browser_toolbar_gtk.cc
+++ b/chrome/browser/gtk/browser_toolbar_gtk.cc
@@ -18,7 +18,7 @@
#include "base/path_service.h"
#include "base/singleton.h"
#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/encoding_menu_controller.h"
+#include "chrome/browser/background_page_tracker.h"
#include "chrome/browser/gtk/accelerators_gtk.h"
#include "chrome/browser/gtk/back_forward_button_gtk.h"
#include "chrome/browser/gtk/browser_actions_toolbar_gtk.h"
@@ -35,10 +35,11 @@
#include "chrome/browser/gtk/view_id_util.h"
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/toolbar/encoding_menu_controller.h"
#include "chrome/browser/upgrade_detector.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_details.h"
@@ -101,6 +102,9 @@ BrowserToolbarGtk::BrowserToolbarGtk(Browser* browser, BrowserWindowGtk* window)
registrar_.Add(this,
NotificationType::UPGRADE_RECOMMENDED,
NotificationService::AllSources());
+ registrar_.Add(this,
+ NotificationType::BACKGROUND_PAGE_TRACKER_CHANGED,
+ NotificationService::AllSources());
}
BrowserToolbarGtk::~BrowserToolbarGtk() {
@@ -311,16 +315,20 @@ void BrowserToolbarGtk::StoppedShowing() {
gtk_chrome_button_set_hover_state(
GTK_CHROME_BUTTON(wrench_menu_button_->widget()), 0.0);
wrench_menu_button_->UnsetPaintOverride();
+
+ // Stop showing the BG page badge when we close the wrench menu.
+ BackgroundPageTracker::GetInstance()->AcknowledgeBackgroundPages();
}
GtkIconSet* BrowserToolbarGtk::GetIconSetForId(int idr) {
return theme_provider_->GetIconSetForId(idr);
}
-// Always show images because we desire that the upgrade icon always show when
-// an upgrade is available regardless of the system setting.
+// Always show images because we desire that some icons always show
+// regardless of the system setting.
bool BrowserToolbarGtk::AlwaysShowIconForCmd(int command_id) const {
- return command_id == IDC_UPGRADE_DIALOG;
+ return command_id == IDC_UPGRADE_DIALOG ||
+ command_id == IDC_VIEW_BACKGROUND_PAGES;
}
// menus::AcceleratorProvider
@@ -329,7 +337,7 @@ bool BrowserToolbarGtk::GetAcceleratorForCommandId(
int id,
menus::Accelerator* accelerator) {
const menus::AcceleratorGtk* accelerator_gtk =
- Singleton<AcceleratorsGtk>()->GetPrimaryAcceleratorForCommand(id);
+ AcceleratorsGtk::GetInstance()->GetPrimaryAcceleratorForCommand(id);
if (accelerator_gtk)
*accelerator = *accelerator_gtk;
return !!accelerator_gtk;
@@ -375,7 +383,9 @@ void BrowserToolbarGtk::Observe(NotificationType type,
}
UpdateRoundedness();
- } else if (type == NotificationType::UPGRADE_RECOMMENDED) {
+ } else if (type == NotificationType::UPGRADE_RECOMMENDED ||
+ type == NotificationType::BACKGROUND_PAGE_TRACKER_CHANGED) {
+ // Redraw the wrench menu to update the badge.
gtk_widget_queue_draw(wrench_menu_button_->widget());
} else if (type == NotificationType::ZOOM_LEVEL_CHANGED) {
// If our zoom level changed, we need to tell the menu to update its state,
@@ -626,19 +636,23 @@ bool BrowserToolbarGtk::ShouldOnlyShowLocation() const {
gboolean BrowserToolbarGtk::OnWrenchMenuButtonExpose(GtkWidget* sender,
GdkEventExpose* expose) {
- if (!Singleton<UpgradeDetector>::get()->notify_upgrade())
+ const SkBitmap* badge = NULL;
+ if (UpgradeDetector::GetInstance()->notify_upgrade()) {
+ badge = theme_provider_->GetBitmapNamed(IDR_UPDATE_BADGE);
+ } else if (BackgroundPageTracker::GetInstance()->
+ GetUnacknowledgedBackgroundPageCount()) {
+ badge = theme_provider_->GetBitmapNamed(IDR_BACKGROUND_BADGE);
+ } else {
return FALSE;
-
- const SkBitmap& badge =
- *theme_provider_->GetBitmapNamed(IDR_UPDATE_BADGE);
+ }
// Draw the chrome app menu icon onto the canvas.
gfx::CanvasSkiaPaint canvas(expose, false);
int x_offset = base::i18n::IsRTL() ? 0 :
- sender->allocation.width - badge.width();
+ sender->allocation.width - badge->width();
int y_offset = 0;
canvas.DrawBitmapInt(
- badge,
+ *badge,
sender->allocation.x + x_offset,
sender->allocation.y + y_offset);
diff --git a/chrome/browser/gtk/browser_toolbar_gtk.h b/chrome/browser/gtk/browser_toolbar_gtk.h
index dbcc97d..431c573 100644
--- a/chrome/browser/gtk/browser_toolbar_gtk.h
+++ b/chrome/browser/gtk/browser_toolbar_gtk.h
@@ -20,7 +20,7 @@
#include "chrome/browser/gtk/menu_gtk.h"
#include "chrome/browser/gtk/owned_widget_gtk.h"
#include "chrome/browser/prefs/pref_member.h"
-#include "chrome/browser/wrench_menu_model.h"
+#include "chrome/browser/ui/toolbar/wrench_menu_model.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
@@ -98,9 +98,9 @@ class BrowserToolbarGtk : public CommandUpdater::CommandObserver,
menus::Accelerator* accelerator);
// NotificationObserver implementation.
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
Profile* profile() { return profile_; }
void SetProfile(Profile* profile);
diff --git a/chrome/browser/gtk/browser_window_gtk.cc b/chrome/browser/gtk/browser_window_gtk.cc
index c0b5f47..0728464 100644
--- a/chrome/browser/gtk/browser_window_gtk.cc
+++ b/chrome/browser/gtk/browser_window_gtk.cc
@@ -21,7 +21,6 @@
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/app_modal_dialog_queue.h"
#include "chrome/browser/autocomplete/autocomplete_edit_view.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/browser_list.h"
@@ -30,7 +29,6 @@
#include "chrome/browser/dom_ui/bug_report_ui.h"
#include "chrome/browser/download/download_item_model.h"
#include "chrome/browser/download/download_manager.h"
-#include "chrome/browser/find_bar_controller.h"
#include "chrome/browser/gtk/about_chrome_dialog.h"
#include "chrome/browser/gtk/accelerators_gtk.h"
#include "chrome/browser/gtk/bookmark_bar_gtk.h"
@@ -65,17 +63,19 @@
#include "chrome/browser/gtk/task_manager_gtk.h"
#include "chrome/browser/gtk/theme_install_bubble_view_gtk.h"
#include "chrome/browser/gtk/update_recommended_dialog.h"
-#include "chrome/browser/location_bar.h"
#include "chrome/browser/page_info_window.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h"
#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/window_sizer.h"
+#include "chrome/browser/ui/find_bar/find_bar_controller.h"
+#include "chrome/browser/ui/omnibox/location_bar.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "chrome/browser/ui/window_sizer.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/native_web_keyboard_event.h"
#include "chrome/common/notification_service.h"
@@ -285,26 +285,6 @@ GQuark GetBrowserWindowQuarkKey() {
return quark;
}
-// Checks if a reserved accelerator key should be processed immediately, rather
-// than being sent to the renderer first.
-bool ShouldExecuteReservedCommandImmediately(
- const NativeWebKeyboardEvent& event, int command_id) {
- // IDC_EXIT is now only bound to Ctrl+Shift+q, so we should always execute it
- // immediately.
- if (command_id == IDC_EXIT)
- return true;
-
- // Keys like Ctrl+w, Ctrl+n, etc. should always be sent to the renderer first,
- // otherwise some web apps or the Emacs key bindings may not work correctly.
- int vkey = event.windowsKeyCode;
- if ((vkey >= app::VKEY_0 && vkey <= app::VKEY_9) ||
- (vkey >= app::VKEY_A && vkey <= app::VKEY_Z))
- return false;
-
- // All other reserved accelerators should be processed immediately.
- return true;
-}
-
} // namespace
std::map<XID, GtkWindow*> BrowserWindowGtk::xid_map_;
@@ -663,7 +643,7 @@ void BrowserWindowGtk::Close() {
if (accel_group_) {
// Disconnecting the keys we connected to our accelerator group frees the
// closures allocated in ConnectAccelerators.
- AcceleratorsGtk* accelerators = Singleton<AcceleratorsGtk>().get();
+ AcceleratorsGtk* accelerators = AcceleratorsGtk::GetInstance();
for (AcceleratorsGtk::const_iterator iter = accelerators->begin();
iter != accelerators->end(); ++iter) {
gtk_accel_group_disconnect_key(accel_group_,
@@ -874,6 +854,11 @@ bool BrowserWindowGtk::IsBookmarkBarAnimating() const {
return false;
}
+bool BrowserWindowGtk::IsTabStripEditable() const {
+ return !tabstrip()->IsDragSessionActive() &&
+ !tabstrip()->IsActiveDropTarget();
+}
+
bool BrowserWindowGtk::IsToolbarVisible() const {
return IsToolbarSupported();
}
@@ -1052,11 +1037,9 @@ bool BrowserWindowGtk::PreHandleKeyboardEvent(
if (id == -1)
return false;
- if (browser_->IsReservedCommand(id) &&
- ShouldExecuteReservedCommandImmediately(event, id)) {
- // Executing the command may cause |this| object to be destroyed.
- return ExecuteBrowserCommand(id);
- }
+ // Executing the command may cause |this| object to be destroyed.
+ if (browser_->IsReservedCommand(id) && !event.match_edit_command)
+ return browser_->ExecuteCommandIfEnabled(id);
// The |event| is a keyboard shortcut.
DCHECK(is_keyboard_shortcut != NULL);
@@ -1081,7 +1064,7 @@ void BrowserWindowGtk::HandleKeyboardEvent(
// gtk_window_activate_key() takes care of it automatically.
int id = GetCustomCommandId(os_event);
if (id != -1)
- ExecuteBrowserCommand(id);
+ browser_->ExecuteCommandIfEnabled(id);
else
gtk_window_activate_key(window_, os_event);
}
@@ -1218,8 +1201,8 @@ void BrowserWindowGtk::ActiveWindowChanged(GdkWindow* active_window) {
if (is_active && changed) {
// If there's an app modal dialog (e.g., JS alert), try to redirect
// the user's attention to the window owning the dialog.
- if (Singleton<AppModalDialogQueue>()->HasActiveDialog()) {
- Singleton<AppModalDialogQueue>()->ActivateModalDialog();
+ if (AppModalDialogQueue::GetInstance()->HasActiveDialog()) {
+ AppModalDialogQueue::GetInstance()->ActivateModalDialog();
return;
}
}
@@ -1301,6 +1284,10 @@ void BrowserWindowGtk::DestroyBrowser() {
void BrowserWindowGtk::OnBoundsChanged(const gfx::Rect& bounds) {
GetLocationBar()->location_entry()->ClosePopup();
+ TabContents* tab_contents = GetDisplayedTabContents();
+ if (tab_contents)
+ tab_contents->WindowMoveOrResizeStarted();
+
if (bounds_.size() != bounds.size())
OnSizeChanged(bounds.width(), bounds.height());
@@ -1735,7 +1722,7 @@ void BrowserWindowGtk::ConnectAccelerators() {
accel_group_ = gtk_accel_group_new();
gtk_window_add_accel_group(window_, accel_group_);
- AcceleratorsGtk* accelerators = Singleton<AcceleratorsGtk>().get();
+ AcceleratorsGtk* accelerators = AcceleratorsGtk::GetInstance();
for (AcceleratorsGtk::const_iterator iter = accelerators->begin();
iter != accelerators->end(); ++iter) {
gtk_accel_group_connect(
@@ -1869,7 +1856,7 @@ gboolean BrowserWindowGtk::OnGtkAccelerator(GtkAccelGroup* accel_group,
BrowserWindowGtk* browser_window =
GetBrowserWindowForNativeWindow(GTK_WINDOW(acceleratable));
DCHECK(browser_window != NULL);
- return browser_window->ExecuteBrowserCommand(command_id);
+ return browser_window->browser()->ExecuteCommandIfEnabled(command_id);
}
// Let the focused widget have first crack at the key event so we don't
@@ -1886,7 +1873,7 @@ gboolean BrowserWindowGtk::OnKeyPress(GtkWidget* widget, GdkEventKey* event) {
if (command_id == -1)
command_id = GetPreHandleCommandId(event);
- if (command_id != -1 && ExecuteBrowserCommand(command_id))
+ if (command_id != -1 && browser_->ExecuteCommandIfEnabled(command_id))
return TRUE;
// Propagate the key event to child widget first, so we don't override their
@@ -2087,14 +2074,6 @@ gboolean BrowserWindowGtk::OnFocusOut(GtkWidget* widget,
return FALSE;
}
-bool BrowserWindowGtk::ExecuteBrowserCommand(int id) {
- if (browser_->command_updater()->IsCommandEnabled(id)) {
- browser_->ExecuteCommand(id);
- return true;
- }
- return false;
-}
-
void BrowserWindowGtk::ShowSupportedWindowFeatures() {
if (IsTabStripSupported())
tabstrip_->Show();
diff --git a/chrome/browser/gtk/browser_window_gtk.h b/chrome/browser/gtk/browser_window_gtk.h
index 3e6db38..069cfd5 100644
--- a/chrome/browser/gtk/browser_window_gtk.h
+++ b/chrome/browser/gtk/browser_window_gtk.h
@@ -84,6 +84,7 @@ class BrowserWindowGtk : public BrowserWindow,
virtual void RotatePaneFocus(bool forwards);
virtual bool IsBookmarkBarVisible() const;
virtual bool IsBookmarkBarAnimating() const;
+ virtual bool IsTabStripEditable() const;
virtual bool IsToolbarVisible() const;
virtual void ConfirmAddSearchProvider(const TemplateURL* template_url,
Profile* profile);
@@ -357,10 +358,6 @@ class BrowserWindowGtk : public BrowserWindow,
CHROMEGTK_CALLBACK_1(BrowserWindowGtk, gboolean, OnFocusOut,
GdkEventFocus*);
- // A small shim for browser_->ExecuteCommand.
- // Returns true if the command was executed.
- bool ExecuteBrowserCommand(int id);
-
// Callback for the loading animation(s) associated with this window.
void LoadingAnimationCallback();
diff --git a/chrome/browser/gtk/certificate_viewer.cc b/chrome/browser/gtk/certificate_viewer.cc
index 905eee3..a79507d 100644
--- a/chrome/browser/gtk/certificate_viewer.cc
+++ b/chrome/browser/gtk/certificate_viewer.cc
@@ -260,9 +260,9 @@ void CertificateViewer::InitGeneralPage() {
base::Time issued, expires;
std::string issued_str, expires_str;
if (x509_certificate_model::GetTimes(cert, &issued, &expires)) {
- issued_str = WideToUTF8(
+ issued_str = UTF16ToUTF8(
base::TimeFormatShortDateNumeric(issued));
- expires_str = WideToUTF8(
+ expires_str = UTF16ToUTF8(
base::TimeFormatShortDateNumeric(expires));
} else {
issued_str = alternative_text;
@@ -389,8 +389,8 @@ void CertificateViewer::FillTreeStoreWithCertFields(
base::Time issued, expires;
std::string issued_str, expires_str;
if (x509_certificate_model::GetTimes(cert, &issued, &expires)) {
- issued_str = WideToUTF8(base::TimeFormatShortDateAndTime(issued));
- expires_str = WideToUTF8(base::TimeFormatShortDateAndTime(expires));
+ issued_str = UTF16ToUTF8(base::TimeFormatShortDateAndTime(issued));
+ expires_str = UTF16ToUTF8(base::TimeFormatShortDateAndTime(expires));
}
gtk_tree_store_append(store, &iter, &validity_iter);
gtk_tree_store_set(
diff --git a/chrome/browser/gtk/clear_browsing_data_dialog_gtk.cc b/chrome/browser/gtk/clear_browsing_data_dialog_gtk.cc
index b5b2450..cae4b37 100644
--- a/chrome/browser/gtk/clear_browsing_data_dialog_gtk.cc
+++ b/chrome/browser/gtk/clear_browsing_data_dialog_gtk.cc
@@ -13,7 +13,7 @@
#include "chrome/browser/gtk/gtk_chrome_link_button.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/gtk/collected_cookies_gtk.cc b/chrome/browser/gtk/collected_cookies_gtk.cc
index 5823083..a64f19e 100644
--- a/chrome/browser/gtk/collected_cookies_gtk.cc
+++ b/chrome/browser/gtk/collected_cookies_gtk.cc
@@ -4,12 +4,14 @@
#include "chrome/browser/gtk/collected_cookies_gtk.h"
+#include <string>
+
#include "app/l10n_util.h"
#include "chrome/browser/cookies_tree_model.h"
#include "chrome/browser/gtk/gtk_util.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
#include "grit/generated_resources.h"
namespace {
diff --git a/chrome/browser/gtk/collected_cookies_gtk.h b/chrome/browser/gtk/collected_cookies_gtk.h
index be983c3..f4348b2 100644
--- a/chrome/browser/gtk/collected_cookies_gtk.h
+++ b/chrome/browser/gtk/collected_cookies_gtk.h
@@ -53,9 +53,9 @@ class CollectedCookiesGtk : public ConstrainedDialogDelegate,
ContentSetting setting);
// Notification Observer implementation.
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
// Callbacks.
CHROMEGTK_CALLBACK_2(CollectedCookiesGtk, void, OnTreeViewRowExpanded,
diff --git a/chrome/browser/gtk/constrained_html_delegate_gtk.cc b/chrome/browser/gtk/constrained_html_delegate_gtk.cc
index 350bf31..d55393f 100644
--- a/chrome/browser/gtk/constrained_html_delegate_gtk.cc
+++ b/chrome/browser/gtk/constrained_html_delegate_gtk.cc
@@ -11,7 +11,6 @@
#include "chrome/browser/gtk/tab_contents_container_gtk.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/notification_source.h"
#include "gfx/rect.h"
#include "ipc/ipc_message.h"
diff --git a/chrome/browser/gtk/content_setting_bubble_gtk.cc b/chrome/browser/gtk/content_setting_bubble_gtk.cc
index 657b82a..f8c36f0 100644
--- a/chrome/browser/gtk/content_setting_bubble_gtk.cc
+++ b/chrome/browser/gtk/content_setting_bubble_gtk.cc
@@ -4,26 +4,30 @@
#include "chrome/browser/gtk/content_setting_bubble_gtk.h"
+#include <set>
+#include <string>
+#include <vector>
+
#include "app/l10n_util.h"
#include "app/text_elider.h"
#include "base/i18n/rtl.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/blocked_content_container.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/content_setting_bubble_model.h"
#include "chrome/browser/gtk/gtk_chrome_link_button.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/gtk/options/content_settings_window_gtk.h"
-#include "chrome/browser/host_content_settings_map.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/content_settings.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"
#include "gfx/gtk_util.h"
#include "grit/app_resources.h"
#include "grit/generated_resources.h"
-#include "webkit/glue/plugins/plugin_list.h"
+#include "webkit/plugins/npapi/plugin_list.h"
namespace {
@@ -104,12 +108,9 @@ void ContentSettingBubbleGtk::BuildBubble() {
for (std::set<std::string>::const_iterator it = plugins.begin();
it != plugins.end(); ++it) {
- std::string name;
- NPAPI::PluginList::PluginMap groups;
- NPAPI::PluginList::Singleton()->GetPluginGroups(false, &groups);
- if (groups.find(*it) != groups.end())
- name = UTF16ToUTF8(groups[*it]->GetGroupName());
- else
+ std::string name = UTF16ToUTF8(
+ webkit::npapi::PluginList::Singleton()->GetPluginGroupName(*it));
+ if (name.empty())
name = *it;
GtkWidget* label = gtk_label_new(BuildElidedText(name).c_str());
@@ -191,10 +192,6 @@ void ContentSettingBubbleGtk::BuildBubble() {
// We can attach signal handlers now that all defaults are set.
g_signal_connect(*i, "toggled", G_CALLBACK(OnRadioToggledThunk), this);
}
- if (!radio_group_gtk_.empty()) {
- gtk_box_pack_start(GTK_BOX(bubble_content), gtk_hseparator_new(), FALSE,
- FALSE, 0);
- }
}
for (std::vector<ContentSettingBubbleModel::DomainList>::const_iterator i =
@@ -218,47 +215,25 @@ void ContentSettingBubbleGtk::BuildBubble() {
gtk_util::kControlSpacing);
}
- if (!content.clear_link.empty()) {
- GtkWidget* clear_link_box = gtk_hbox_new(FALSE, 0);
- GtkWidget* clear_link = gtk_chrome_link_button_new(
- content.clear_link.c_str());
- g_signal_connect(clear_link, "clicked", G_CALLBACK(OnClearLinkClickedThunk),
- this);
- gtk_box_pack_start(GTK_BOX(clear_link_box), clear_link, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(bubble_content), clear_link_box,
- FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(bubble_content), gtk_hseparator_new(),
- FALSE, FALSE, 0);
- }
-
- if (!content.info_link.empty()) {
- GtkWidget* info_link_box = gtk_hbox_new(FALSE, 0);
- GtkWidget* info_link = gtk_chrome_link_button_new(
- content.info_link.c_str());
- g_signal_connect(info_link, "clicked", G_CALLBACK(OnInfoLinkClickedThunk),
- this);
- gtk_box_pack_start(GTK_BOX(info_link_box), info_link, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(bubble_content), info_link_box,
- FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(bubble_content), gtk_hseparator_new(),
+ if (!content.custom_link.empty()) {
+ GtkWidget* custom_link_box = gtk_hbox_new(FALSE, 0);
+ GtkWidget* custom_link = NULL;
+ if (content.custom_link_enabled) {
+ custom_link = gtk_chrome_link_button_new(content.custom_link.c_str());
+ g_signal_connect(custom_link, "clicked",
+ G_CALLBACK(OnCustomLinkClickedThunk), this);
+ } else {
+ custom_link = gtk_label_new(content.custom_link.c_str());
+ gtk_misc_set_alignment(GTK_MISC(custom_link), 0, 0.5);
+ }
+ DCHECK(custom_link);
+ gtk_box_pack_start(GTK_BOX(custom_link_box), custom_link, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(bubble_content), custom_link_box,
FALSE, FALSE, 0);
}
- if (!content.load_plugins_link_title.empty()) {
- GtkWidget* load_plugins_link_box = gtk_hbox_new(FALSE, 0);
- GtkWidget* load_plugins_link = gtk_chrome_link_button_new(
- content.load_plugins_link_title.c_str());
- gtk_widget_set_sensitive(load_plugins_link,
- content.load_plugins_link_enabled);
- g_signal_connect(load_plugins_link, "clicked",
- G_CALLBACK(OnLoadPluginsLinkClickedThunk), this);
- gtk_box_pack_start(GTK_BOX(load_plugins_link_box), load_plugins_link,
- FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(bubble_content), load_plugins_link_box,
- FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(bubble_content), gtk_hseparator_new(),
- FALSE, FALSE, 0);
- }
+ gtk_box_pack_start(GTK_BOX(bubble_content), gtk_hseparator_new(),
+ FALSE, FALSE, 0);
GtkWidget* bottom_box = gtk_hbox_new(FALSE, 0);
@@ -330,22 +305,12 @@ void ContentSettingBubbleGtk::OnCloseButtonClicked(GtkWidget *button) {
Close();
}
-void ContentSettingBubbleGtk::OnManageLinkClicked(GtkWidget* button) {
- content_setting_bubble_model_->OnManageLinkClicked();
- Close();
-}
-
-void ContentSettingBubbleGtk::OnClearLinkClicked(GtkWidget* button) {
- content_setting_bubble_model_->OnClearLinkClicked();
+void ContentSettingBubbleGtk::OnCustomLinkClicked(GtkWidget* button) {
+ content_setting_bubble_model_->OnCustomLinkClicked();
Close();
}
-void ContentSettingBubbleGtk::OnInfoLinkClicked(GtkWidget* button) {
- content_setting_bubble_model_->OnInfoLinkClicked();
- Close();
-}
-
-void ContentSettingBubbleGtk::OnLoadPluginsLinkClicked(GtkWidget* button) {
- content_setting_bubble_model_->OnLoadPluginsLinkClicked();
+void ContentSettingBubbleGtk::OnManageLinkClicked(GtkWidget* button) {
+ content_setting_bubble_model_->OnManageLinkClicked();
Close();
}
diff --git a/chrome/browser/gtk/content_setting_bubble_gtk.h b/chrome/browser/gtk/content_setting_bubble_gtk.h
index 2fccd66..f003ab6 100644
--- a/chrome/browser/gtk/content_setting_bubble_gtk.h
+++ b/chrome/browser/gtk/content_setting_bubble_gtk.h
@@ -56,11 +56,9 @@ class ContentSettingBubbleGtk : public InfoBubbleGtkDelegate,
GdkEventButton*);
CHROMEGTK_CALLBACK_0(ContentSettingBubbleGtk, void, OnPopupLinkClicked);
CHROMEGTK_CALLBACK_0(ContentSettingBubbleGtk, void, OnRadioToggled);
- CHROMEGTK_CALLBACK_0(ContentSettingBubbleGtk, void, OnCloseButtonClicked);
+ CHROMEGTK_CALLBACK_0(ContentSettingBubbleGtk, void, OnCustomLinkClicked);
CHROMEGTK_CALLBACK_0(ContentSettingBubbleGtk, void, OnManageLinkClicked);
- CHROMEGTK_CALLBACK_0(ContentSettingBubbleGtk, void, OnClearLinkClicked);
- CHROMEGTK_CALLBACK_0(ContentSettingBubbleGtk, void, OnInfoLinkClicked);
- CHROMEGTK_CALLBACK_0(ContentSettingBubbleGtk, void, OnLoadPluginsLinkClicked);
+ CHROMEGTK_CALLBACK_0(ContentSettingBubbleGtk, void, OnCloseButtonClicked);
// We position the bubble near this widget.
GtkWidget* anchor_;
@@ -89,8 +87,6 @@ class ContentSettingBubbleGtk : public InfoBubbleGtkDelegate,
typedef std::vector<GtkWidget*> RadioGroupGtk;
RadioGroupGtk radio_group_gtk_;
-
- GtkWidget* load_plugins_link_;
};
#endif // CHROME_BROWSER_GTK_CONTENT_SETTING_BUBBLE_GTK_H_
diff --git a/chrome/browser/gtk/create_application_shortcuts_dialog_gtk.cc b/chrome/browser/gtk/create_application_shortcuts_dialog_gtk.cc
index 34ee5a7..2d6b44e 100644
--- a/chrome/browser/gtk/create_application_shortcuts_dialog_gtk.cc
+++ b/chrome/browser/gtk/create_application_shortcuts_dialog_gtk.cc
@@ -87,10 +87,7 @@ void CreateApplicationShortcutsDialogGtk::CreateDialogBox(GtkWindow* parent) {
GTK_RESPONSE_REJECT,
NULL);
gtk_widget_realize(create_dialog_);
- gtk_util::SetWindowSizeFromResources(GTK_WINDOW(create_dialog_),
- IDS_CREATE_SHORTCUTS_DIALOG_WIDTH_CHARS,
- -1, // height
- false); // resizable
+ gtk_window_set_resizable(GTK_WINDOW(create_dialog_), false);
gtk_util::AddButtonToDialog(create_dialog_,
l10n_util::GetStringUTF8(IDS_CREATE_SHORTCUTS_COMMIT).c_str(),
GTK_STOCK_APPLY, GTK_RESPONSE_ACCEPT);
@@ -117,11 +114,19 @@ void CreateApplicationShortcutsDialogGtk::CreateDialogBox(GtkWindow* parent) {
gtk_box_pack_start(GTK_BOX(hbox), description_label, FALSE, FALSE, 0);
gtk_label_set_line_wrap(GTK_LABEL(description_label), TRUE);
gtk_widget_realize(description_label);
- int label_height;
- gtk_util::GetWidgetSizeFromCharacters(description_label, -1,
- kDescriptionLabelHeightLines, NULL,
- &label_height);
- gtk_widget_set_size_request(description_label, -1, label_height);
+
+ // Set the size request on the label so it knows where to line wrap. The width
+ // is the desired size of the dialog less the space reserved for padding and
+ // the image.
+ int label_width, label_height;
+ gtk_util::GetWidgetSizeFromResources(
+ description_label,
+ IDS_CREATE_SHORTCUTS_DIALOG_WIDTH_CHARS, -1, &label_width, NULL);
+ label_width -= gtk_util::kControlSpacing * 3 +
+ gdk_pixbuf_get_width(favicon_pixbuf_);
+ gtk_util::GetWidgetSizeFromCharacters(
+ description_label, -1, kDescriptionLabelHeightLines, NULL, &label_height);
+ gtk_widget_set_size_request(description_label, label_width, label_height);
gtk_misc_set_alignment(GTK_MISC(description_label), 0, 0.5);
std::string description(UTF16ToUTF8(shortcut_info_.description));
std::string title(UTF16ToUTF8(shortcut_info_.title));
diff --git a/chrome/browser/gtk/dialogs_gtk.cc b/chrome/browser/gtk/dialogs_gtk.cc
index 8a95192..1814e92 100644
--- a/chrome/browser/gtk/dialogs_gtk.cc
+++ b/chrome/browser/gtk/dialogs_gtk.cc
@@ -16,7 +16,6 @@
#include "base/thread.h"
#include "base/thread_restrictions.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/shell_dialogs.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/gtk/download_in_progress_dialog_gtk.cc b/chrome/browser/gtk/download_in_progress_dialog_gtk.cc
index 3b039ca..0aa0455 100644
--- a/chrome/browser/gtk/download_in_progress_dialog_gtk.cc
+++ b/chrome/browser/gtk/download_in_progress_dialog_gtk.cc
@@ -11,7 +11,7 @@
#include "base/string16.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/gtk/gtk_util.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "grit/chromium_strings.h"
diff --git a/chrome/browser/gtk/download_shelf_gtk.cc b/chrome/browser/gtk/download_shelf_gtk.cc
index 3c47c38..d9b5109 100644
--- a/chrome/browser/gtk/download_shelf_gtk.cc
+++ b/chrome/browser/gtk/download_shelf_gtk.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/gtk/download_shelf_gtk.h"
+#include <string>
+
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "chrome/browser/download/download_item.h"
@@ -16,7 +18,6 @@
#include "chrome/browser/gtk/gtk_chrome_shrinkable_hbox.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/gtk/gtk_util.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/notification_service.h"
#include "gfx/gtk_util.h"
@@ -176,6 +177,10 @@ void DownloadShelfGtk::Close() {
browser_->UpdateDownloadShelfVisibility(false);
}
+Browser* DownloadShelfGtk::browser() const {
+ return browser_;
+}
+
void DownloadShelfGtk::Closed() {
// When the close animation is complete, remove all completed downloads.
size_t i = 0;
diff --git a/chrome/browser/gtk/download_shelf_gtk.h b/chrome/browser/gtk/download_shelf_gtk.h
index bd8ff0f..9c6cceb 100644
--- a/chrome/browser/gtk/download_shelf_gtk.h
+++ b/chrome/browser/gtk/download_shelf_gtk.h
@@ -40,7 +40,7 @@ class DownloadShelfGtk : public DownloadShelf,
virtual bool IsClosing() const;
virtual void Show();
virtual void Close();
- virtual Browser* browser() const { return browser_; }
+ virtual Browser* browser() const;
// SlideAnimatorGtk::Delegate implementation.
virtual void Closed();
diff --git a/chrome/browser/gtk/download_started_animation_gtk.cc b/chrome/browser/gtk/download_started_animation_gtk.cc
index 5343ac2..5015b80 100644
--- a/chrome/browser/gtk/download_started_animation_gtk.cc
+++ b/chrome/browser/gtk/download_started_animation_gtk.cc
@@ -11,7 +11,7 @@
#include "base/message_loop.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
#include "gfx/rect.h"
#include "grit/theme_resources.h"
diff --git a/chrome/browser/gtk/edit_search_engine_dialog.cc b/chrome/browser/gtk/edit_search_engine_dialog.cc
index 3c4c58a..a3fa339 100644
--- a/chrome/browser/gtk/edit_search_engine_dialog.cc
+++ b/chrome/browser/gtk/edit_search_engine_dialog.cc
@@ -14,7 +14,7 @@
#include "chrome/browser/gtk/accessible_widget_helper_gtk.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/net/url_fixer_upper.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/edit_search_engine_controller.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
diff --git a/chrome/browser/gtk/extension_installed_bubble_gtk.cc b/chrome/browser/gtk/extension_installed_bubble_gtk.cc
index adb2b7b..9ca5854 100644
--- a/chrome/browser/gtk/extension_installed_bubble_gtk.cc
+++ b/chrome/browser/gtk/extension_installed_bubble_gtk.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/gtk/extension_installed_bubble_gtk.h"
+#include <string>
+
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/i18n/rtl.h"
@@ -18,7 +20,8 @@
#include "chrome/browser/ui/browser.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_action.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"
#include "gfx/gtk_util.h"
#include "grit/generated_resources.h"
@@ -92,7 +95,8 @@ void ExtensionInstalledBubbleGtk::Observe(NotificationType type,
&ExtensionInstalledBubbleGtk::ShowInternal));
}
} else if (type == NotificationType::EXTENSION_UNLOADED) {
- const Extension* extension = Details<const Extension>(details).ptr();
+ const Extension* extension =
+ Details<UnloadedExtensionInfo>(details)->extension;
if (extension == extension_)
extension_ = NULL;
} else {
@@ -197,8 +201,10 @@ void ExtensionInstalledBubbleGtk::ShowInternal() {
// Heading label
GtkWidget* heading_label = gtk_label_new(NULL);
+ string16 extension_name = UTF8ToUTF16(extension_->name());
+ base::i18n::AdjustStringForLocaleDirection(&extension_name);
std::string heading_text = l10n_util::GetStringFUTF8(
- IDS_EXTENSION_INSTALLED_HEADING, UTF8ToUTF16(extension_->name()));
+ IDS_EXTENSION_INSTALLED_HEADING, extension_name);
char* markup = g_markup_printf_escaped("<span size=\"larger\">%s</span>",
heading_text.c_str());
gtk_label_set_markup(GTK_LABEL(heading_label), markup);
@@ -240,11 +246,6 @@ void ExtensionInstalledBubbleGtk::ShowInternal() {
close_button_.reset(CustomDrawButton::CloseButton(theme_provider));
g_signal_connect(close_button_->widget(), "clicked",
G_CALLBACK(OnButtonClick), this);
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- close_button_->SetBackground(
- theme_provider->GetColor(BrowserThemeProvider::COLOR_TAB_TEXT),
- rb.GetBitmapNamed(IDR_CLOSE_BAR),
- rb.GetBitmapNamed(IDR_CLOSE_BAR_MASK));
gtk_box_pack_start(GTK_BOX(close_column), close_button_->widget(),
FALSE, FALSE, 0);
diff --git a/chrome/browser/gtk/extension_popup_gtk.cc b/chrome/browser/gtk/extension_popup_gtk.cc
index e9ed014..f1faf37 100644
--- a/chrome/browser/gtk/extension_popup_gtk.cc
+++ b/chrome/browser/gtk/extension_popup_gtk.cc
@@ -6,18 +6,21 @@
#include <gtk/gtk.h>
+#include <algorithm>
+
#include "base/i18n/rtl.h"
#include "base/message_loop.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/debugger/devtools_manager.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view_gtk.h"
#include "chrome/browser/ui/browser.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
#include "googleurl/src/gurl.h"
ExtensionPopupGtk* ExtensionPopupGtk::current_extension_popup_ = NULL;
diff --git a/chrome/browser/gtk/external_protocol_dialog_gtk.cc b/chrome/browser/gtk/external_protocol_dialog_gtk.cc
index f59a26e..34c2f78 100644
--- a/chrome/browser/gtk/external_protocol_dialog_gtk.cc
+++ b/chrome/browser/gtk/external_protocol_dialog_gtk.cc
@@ -9,14 +9,13 @@
#include <string>
#include "app/l10n_util.h"
+#include "app/text_elider.h"
#include "base/metrics/histogram.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/external_protocol_handler.h"
#include "chrome/browser/gtk/gtk_util.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
@@ -64,9 +63,9 @@ ExternalProtocolDialogGtk::ExternalProtocolDialogGtk(const GURL& url)
const int kMaxCommandSize = 256;
std::wstring elided_url_without_scheme;
std::wstring elided_command;
- ElideString(ASCIIToWide(url.possibly_invalid_spec()),
+ gfx::ElideString(ASCIIToWide(url.possibly_invalid_spec()),
kMaxUrlWithoutSchemeSize, &elided_url_without_scheme);
- ElideString(ASCIIToWide(std::string("xdg-open ") + url.spec()),
+ gfx::ElideString(ASCIIToWide(std::string("xdg-open ") + url.spec()),
kMaxCommandSize, &elided_command);
std::string message_text = l10n_util::GetStringFUTF8(
diff --git a/chrome/browser/gtk/find_bar_gtk.cc b/chrome/browser/gtk/find_bar_gtk.cc
index aa3429f..ddd9955 100644
--- a/chrome/browser/gtk/find_bar_gtk.cc
+++ b/chrome/browser/gtk/find_bar_gtk.cc
@@ -16,8 +16,6 @@
#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/find_bar_controller.h"
-#include "chrome/browser/find_bar_state.h"
#include "chrome/browser/gtk/browser_window_gtk.h"
#include "chrome/browser/gtk/cairo_cached_surface.h"
#include "chrome/browser/gtk/custom_button.h"
@@ -29,10 +27,12 @@
#include "chrome/browser/gtk/tab_contents_container_gtk.h"
#include "chrome/browser/gtk/tabs/tab_strip_gtk.h"
#include "chrome/browser/gtk/view_id_util.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/find_bar/find_bar_controller.h"
+#include "chrome/browser/ui/find_bar/find_bar_state.h"
#include "chrome/common/native_web_keyboard_event.h"
#include "chrome/common/notification_service.h"
#include "grit/generated_resources.h"
@@ -557,6 +557,22 @@ string16 FindBarGtk::GetFindText() {
return UTF8ToUTF16(contents);
}
+string16 FindBarGtk::GetFindSelectedText() {
+ gint cursor_pos;
+ gint selection_bound;
+ g_object_get(G_OBJECT(text_entry_), "cursor-position", &cursor_pos,
+ NULL);
+ g_object_get(G_OBJECT(text_entry_), "selection-bound", &selection_bound,
+ NULL);
+ std::string contents(gtk_entry_get_text(GTK_ENTRY(text_entry_)));
+ return UTF8ToUTF16(contents.substr(cursor_pos, selection_bound));
+}
+
+string16 FindBarGtk::GetMatchCountText() {
+ std::string contents(gtk_label_get_text(GTK_LABEL(match_count_label_)));
+ return UTF8ToUTF16(contents);
+}
+
void FindBarGtk::FindEntryTextInContents(bool forward_search) {
TabContents* tab_contents = find_bar_controller_->tab_contents();
if (!tab_contents)
diff --git a/chrome/browser/gtk/find_bar_gtk.h b/chrome/browser/gtk/find_bar_gtk.h
index ee9c0e5..527644a 100644
--- a/chrome/browser/gtk/find_bar_gtk.h
+++ b/chrome/browser/gtk/find_bar_gtk.h
@@ -10,10 +10,10 @@
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
-#include "chrome/browser/find_bar.h"
#include "chrome/browser/gtk/focus_store_gtk.h"
#include "chrome/browser/gtk/owned_widget_gtk.h"
#include "chrome/browser/gtk/slide_animator_gtk.h"
+#include "chrome/browser/ui/find_bar/find_bar.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "gfx/point.h"
@@ -62,6 +62,8 @@ class FindBarGtk : public FindBar,
virtual bool GetFindBarWindowInfo(gfx::Point* position,
bool* fully_visible);
virtual string16 GetFindText();
+ virtual string16 GetFindSelectedText();
+ virtual string16 GetMatchCountText();
// Overridden from NotificationObserver:
virtual void Observe(NotificationType type,
diff --git a/chrome/browser/gtk/first_run_bubble.cc b/chrome/browser/gtk/first_run_bubble.cc
index 343f57b..119166b 100644
--- a/chrome/browser/gtk/first_run_bubble.cc
+++ b/chrome/browser/gtk/first_run_bubble.cc
@@ -48,6 +48,10 @@ void FirstRunBubble::InfoBubbleClosing(InfoBubbleGtk* info_bubble,
// TODO(port): Enable parent window
}
+bool FirstRunBubble::CloseOnEscape() {
+ return true;
+}
+
void FirstRunBubble::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
diff --git a/chrome/browser/gtk/first_run_bubble.h b/chrome/browser/gtk/first_run_bubble.h
index 211ae68..220c4f6 100644
--- a/chrome/browser/gtk/first_run_bubble.h
+++ b/chrome/browser/gtk/first_run_bubble.h
@@ -17,10 +17,11 @@
#include "base/basictypes.h"
#include "chrome/browser/first_run/first_run.h"
#include "chrome/browser/gtk/info_bubble_gtk.h"
-#include "chrome/browser/profile.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
+class Profile;
+
class FirstRunBubble : public InfoBubbleGtkDelegate,
public NotificationObserver {
public:
@@ -34,7 +35,7 @@ class FirstRunBubble : public InfoBubbleGtkDelegate,
// is about to be closed.
virtual void InfoBubbleClosing(InfoBubbleGtk* info_bubble,
bool closed_by_escape);
- virtual bool CloseOnEscape() { return true; }
+ virtual bool CloseOnEscape();
// Overridden from NotificationObserver:
virtual void Observe(NotificationType type,
diff --git a/chrome/browser/gtk/first_run_dialog.cc b/chrome/browser/gtk/first_run_dialog.cc
index 230fee3..b0f83fc 100644
--- a/chrome/browser/gtk/first_run_dialog.cc
+++ b/chrome/browser/gtk/first_run_dialog.cc
@@ -4,19 +4,20 @@
#include "chrome/browser/gtk/first_run_dialog.h"
+#include <string>
+#include <vector>
+
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/i18n/rtl.h"
#include "base/message_loop.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/gtk/gtk_chrome_link_button.h"
#include "chrome/browser/gtk/gtk_floating_container.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/platform_util.h"
-#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/process_singleton.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/shell_integration.h"
@@ -31,6 +32,11 @@
#include "chrome/app/breakpad_linux.h"
#endif
+#if defined(GOOGLE_CHROME_BUILD)
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/prefs/pref_service.h"
+#endif
+
namespace {
const gchar* kSearchEngineKey = "template-url-search-engine";
diff --git a/chrome/browser/gtk/gconf_titlebar_listener.cc b/chrome/browser/gtk/gconf_titlebar_listener.cc
index 237332f..ae89f1a 100644
--- a/chrome/browser/gtk/gconf_titlebar_listener.cc
+++ b/chrome/browser/gtk/gconf_titlebar_listener.cc
@@ -7,6 +7,7 @@
#include <gtk/gtk.h>
#include "base/scoped_ptr.h"
+#include "base/singleton.h"
#include "base/environment.h"
#include "base/nix/xdg_util.h"
#include "chrome/browser/gtk/browser_titlebar.h"
@@ -25,6 +26,11 @@ const char* kMetacityGeneral = "/apps/metacity/general";
// Public interface:
+// static
+GConfTitlebarListener* GConfTitlebarListener::GetInstance() {
+ return Singleton<GConfTitlebarListener>::get();
+}
+
void GConfTitlebarListener::SetTitlebarButtons(BrowserTitlebar* titlebar) {
if (client_) {
titlebar->BuildButtons(current_value_);
diff --git a/chrome/browser/gtk/gconf_titlebar_listener.h b/chrome/browser/gtk/gconf_titlebar_listener.h
index 19318eb..b96b759 100644
--- a/chrome/browser/gtk/gconf_titlebar_listener.h
+++ b/chrome/browser/gtk/gconf_titlebar_listener.h
@@ -13,9 +13,10 @@
#include <string>
#include "app/gtk_signal.h"
-#include "base/singleton.h"
+#include "base/basictypes.h"
class BrowserTitlebar;
+template <typename T> struct DefaultSingletonTraits;
// On GNOME desktops, subscribes to the gconf key which controlls button order.
// Everywhere else, SetTiltebarButtons() just calls back into BrowserTitlebar
@@ -24,6 +25,9 @@ class BrowserTitlebar;
// Meant to be used as a Singleton through base/singleton.h's interface.
class GConfTitlebarListener {
public:
+ // Returns the singleton instance.
+ static GConfTitlebarListener* GetInstance();
+
// Sets the current titlebar button order. On GNOME desktops, also subscribes
// to further notifications when this changes.
void SetTitlebarButtons(BrowserTitlebar* titlebar);
diff --git a/chrome/browser/gtk/gtk_chrome_cookie_view.cc b/chrome/browser/gtk/gtk_chrome_cookie_view.cc
index 07413f6..a0e3c62 100644
--- a/chrome/browser/gtk/gtk_chrome_cookie_view.cc
+++ b/chrome/browser/gtk/gtk_chrome_cookie_view.cc
@@ -474,11 +474,11 @@ void gtk_chrome_cookie_view_display_cookie(
gtk_entry_set_text(GTK_ENTRY(self->cookie_path_entry_),
cookie.Path().c_str());
gtk_entry_set_text(GTK_ENTRY(self->cookie_created_entry_),
- WideToUTF8(base::TimeFormatFriendlyDateAndTime(
+ UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime(
cookie.CreationDate())).c_str());
std::string expire_text = cookie.DoesExpire() ?
- WideToUTF8(base::TimeFormatFriendlyDateAndTime(cookie.ExpiryDate())) :
+ UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime(cookie.ExpiryDate())) :
l10n_util::GetStringUTF8(IDS_COOKIES_COOKIE_EXPIRES_SESSION);
if (self->cookie_expires_entry_) {
@@ -545,7 +545,7 @@ void gtk_chrome_cookie_view_display_database(
GetByteDisplayUnits(database_info.size),
true)).c_str());
gtk_entry_set_text(GTK_ENTRY(self->database_last_modified_entry_),
- WideToUTF8(base::TimeFormatFriendlyDateAndTime(
+ UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime(
database_info.last_modified)).c_str());
SetDatabaseDetailsSensitivity(self, TRUE);
}
@@ -565,7 +565,7 @@ void gtk_chrome_cookie_view_display_local_storage(
GetByteDisplayUnits(local_storage_info.size),
true)).c_str());
gtk_entry_set_text(GTK_ENTRY(self->local_storage_last_modified_entry_),
- WideToUTF8(base::TimeFormatFriendlyDateAndTime(
+ UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime(
local_storage_info.last_modified)).c_str());
SetLocalStorageDetailsSensitivity(self, TRUE);
}
@@ -584,10 +584,10 @@ void gtk_chrome_cookie_view_display_app_cache(
GetByteDisplayUnits(info.size),
true)).c_str());
gtk_entry_set_text(GTK_ENTRY(self->appcache_created_entry_),
- WideToUTF8(base::TimeFormatFriendlyDateAndTime(
+ UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime(
info.creation_time)).c_str());
gtk_entry_set_text(GTK_ENTRY(self->appcache_last_accessed_entry_),
- WideToUTF8(base::TimeFormatFriendlyDateAndTime(
+ UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime(
info.last_access_time)).c_str());
SetAppCacheDetailsSensitivity(self, TRUE);
}
@@ -606,7 +606,7 @@ void gtk_chrome_cookie_view_display_indexed_db(
GetByteDisplayUnits(indexed_db_info.size),
true)).c_str());
gtk_entry_set_text(GTK_ENTRY(self->indexed_db_last_modified_entry_),
- WideToUTF8(base::TimeFormatFriendlyDateAndTime(
+ UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime(
indexed_db_info.last_modified)).c_str());
SetLocalStorageDetailsSensitivity(self, TRUE);
}
diff --git a/chrome/browser/gtk/gtk_theme_provider.cc b/chrome/browser/gtk/gtk_theme_provider.cc
index a5cbfab..84c44b3 100644
--- a/chrome/browser/gtk/gtk_theme_provider.cc
+++ b/chrome/browser/gtk/gtk_theme_provider.cc
@@ -20,7 +20,7 @@
#include "chrome/browser/gtk/hover_controller_gtk.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_source.h"
diff --git a/chrome/browser/gtk/gtk_theme_provider_unittest.cc b/chrome/browser/gtk/gtk_theme_provider_unittest.cc
index 1836b80..e2a7272 100644
--- a/chrome/browser/gtk/gtk_theme_provider_unittest.cc
+++ b/chrome/browser/gtk/gtk_theme_provider_unittest.cc
@@ -6,7 +6,7 @@
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_profile.h"
#include "grit/theme_resources.h"
diff --git a/chrome/browser/gtk/gtk_util.cc b/chrome/browser/gtk/gtk_util.cc
index e65def3..bf7ba63 100644
--- a/chrome/browser/gtk/gtk_util.cc
+++ b/chrome/browser/gtk/gtk_util.cc
@@ -28,7 +28,7 @@
#include "chrome/browser/browser_window.h"
#include "chrome/browser/gtk/cairo_cached_surface.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/renderer_preferences.h"
@@ -773,12 +773,15 @@ void DrawTextEntryBackground(GtkWidget* offscreen_entry,
// above; this is a noop on themes that do).
gint xborder = our_style->xthickness;
gint yborder = our_style->ythickness;
- gtk_paint_flat_box(our_style, widget_to_draw_on->window,
- GTK_STATE_NORMAL, GTK_SHADOW_NONE, dirty_rec,
- widget_to_draw_on, "entry_bg",
- rec->x + xborder, rec->y + yborder,
- rec->width - 2 * xborder,
- rec->height - 2 * yborder);
+ gint width = rec->width - 2 * xborder;
+ gint height = rec->height - 2 * yborder;
+ if (width > 0 && height > 0) {
+ gtk_paint_flat_box(our_style, widget_to_draw_on->window,
+ GTK_STATE_NORMAL, GTK_SHADOW_NONE, dirty_rec,
+ widget_to_draw_on, "entry_bg",
+ rec->x + xborder, rec->y + yborder,
+ width, height);
+ }
gtk_style_detach(our_style);
g_object_unref(our_style);
diff --git a/chrome/browser/gtk/html_dialog_gtk.cc b/chrome/browser/gtk/html_dialog_gtk.cc
index 2568e83..d0d18b2 100644
--- a/chrome/browser/gtk/html_dialog_gtk.cc
+++ b/chrome/browser/gtk/html_dialog_gtk.cc
@@ -93,6 +93,10 @@ void HtmlDialogGtk::OnDialogClosed(const std::string& json_retval) {
delete this;
}
+bool HtmlDialogGtk::ShouldShowDialogTitle() const {
+ return true;
+}
+
////////////////////////////////////////////////////////////////////////////////
// TabContentsDelegate implementation:
diff --git a/chrome/browser/gtk/html_dialog_gtk.h b/chrome/browser/gtk/html_dialog_gtk.h
index aba28f2..6b4ddda 100644
--- a/chrome/browser/gtk/html_dialog_gtk.h
+++ b/chrome/browser/gtk/html_dialog_gtk.h
@@ -46,7 +46,7 @@ class HtmlDialogGtk : public HtmlDialogTabContentsDelegate,
virtual std::string GetDialogArgs() const;
virtual void OnDialogClosed(const std::string& json_retval);
virtual void OnCloseContents(TabContents* source, bool* out_close_dialog) { }
- virtual bool ShouldShowDialogTitle() const { return true; }
+ virtual bool ShouldShowDialogTitle() const;
// Overridden from TabContentsDelegate:
virtual void MoveContents(TabContents* source, const gfx::Rect& pos);
diff --git a/chrome/browser/gtk/import_dialog_gtk.cc b/chrome/browser/gtk/import_dialog_gtk.cc
index 786007c..d1f828a 100644
--- a/chrome/browser/gtk/import_dialog_gtk.cc
+++ b/chrome/browser/gtk/import_dialog_gtk.cc
@@ -44,7 +44,7 @@ ImportDialogGtk::ImportDialogGtk(GtkWindow* parent, Profile* profile,
int initial_state)
: parent_(parent),
profile_(profile),
- importer_host_(new ImporterHost()),
+ importer_host_(new ImporterHost(this)),
initial_state_(initial_state) {
// Build the dialog.
std::string dialog_name = l10n_util::GetStringUTF8(
@@ -65,10 +65,10 @@ ImportDialogGtk::ImportDialogGtk(GtkWindow* parent, Profile* profile,
// Add import button separately as we might need to disable it, if
// no supported browsers found.
- GtkWidget* import_button = gtk_util::AddButtonToDialog(dialog_,
+ import_button_ = gtk_util::AddButtonToDialog(dialog_,
l10n_util::GetStringUTF8(IDS_IMPORT_COMMIT).c_str(),
GTK_STOCK_APPLY, GTK_RESPONSE_ACCEPT);
- GTK_WIDGET_SET_FLAGS(import_button, GTK_CAN_DEFAULT);
+ GTK_WIDGET_SET_FLAGS(import_button_, GTK_CAN_DEFAULT);
gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_ACCEPT);
GtkWidget* content_area = GTK_DIALOG(dialog_)->vbox;
@@ -125,27 +125,14 @@ ImportDialogGtk::ImportDialogGtk(GtkWindow* parent, Profile* profile,
gtk_box_pack_start(GTK_BOX(content_area), vbox, FALSE, FALSE, 0);
- // Detect any supported browsers that we can import from and fill
- // up the combo box. If none found, disable all controls except cancel.
- int profiles_count = importer_host_->GetAvailableProfileCount();
- if (profiles_count > 0) {
- for (int i = 0; i < profiles_count; i++) {
- std::wstring profile = importer_host_->GetSourceProfileNameAt(i);
- gtk_combo_box_append_text(GTK_COMBO_BOX(combo_),
- WideToUTF8(profile).c_str());
- }
- gtk_widget_grab_focus(import_button);
- } else {
- gtk_combo_box_append_text(GTK_COMBO_BOX(combo_),
- l10n_util::GetStringUTF8(IDS_IMPORT_NO_PROFILE_FOUND).c_str());
- gtk_widget_set_sensitive(bookmarks_, FALSE);
- gtk_widget_set_sensitive(search_engines_, FALSE);
- gtk_widget_set_sensitive(passwords_, FALSE);
- gtk_widget_set_sensitive(history_, FALSE);
- gtk_widget_set_sensitive(import_button, FALSE);
- }
+ // Let the user know profiles are being loaded.
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combo_),
+ l10n_util::GetStringUTF8(IDS_IMPORT_LOADING_PROFILES).c_str());
gtk_combo_box_set_active(GTK_COMBO_BOX(combo_), 0);
+ // Disable controls until source profiles are loaded.
+ SetDialogControlsSensitive(false);
+
g_signal_connect(dialog_, "response",
G_CALLBACK(OnDialogResponseThunk), this);
@@ -160,6 +147,26 @@ ImportDialogGtk::ImportDialogGtk(GtkWindow* parent, Profile* profile,
ImportDialogGtk::~ImportDialogGtk() {
}
+void ImportDialogGtk::SourceProfilesLoaded() {
+ // Detect any supported browsers that we can import from and fill
+ // up the combo box. If none found, disable all controls except cancel.
+ int profiles_count = importer_host_->GetAvailableProfileCount();
+ SetDialogControlsSensitive(profiles_count != 0);
+ gtk_combo_box_remove_text(GTK_COMBO_BOX(combo_), 0);
+ if (profiles_count > 0) {
+ for (int i = 0; i < profiles_count; i++) {
+ std::wstring profile = importer_host_->GetSourceProfileNameAt(i);
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combo_),
+ WideToUTF8(profile).c_str());
+ }
+ gtk_widget_grab_focus(import_button_);
+ } else {
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combo_),
+ l10n_util::GetStringUTF8(IDS_IMPORT_NO_PROFILE_FOUND).c_str());
+ }
+ gtk_combo_box_set_active(GTK_COMBO_BOX(combo_), 0);
+}
+
void ImportDialogGtk::OnDialogResponse(GtkWidget* widget, int response) {
gtk_widget_hide_all(dialog_);
if (response == GTK_RESPONSE_ACCEPT) {
@@ -187,6 +194,14 @@ void ImportDialogGtk::UpdateDialogButtons() {
GetCheckedItems() != 0);
}
+void ImportDialogGtk::SetDialogControlsSensitive(bool sensitive) {
+ gtk_widget_set_sensitive(bookmarks_, sensitive);
+ gtk_widget_set_sensitive(search_engines_, sensitive);
+ gtk_widget_set_sensitive(passwords_, sensitive);
+ gtk_widget_set_sensitive(history_, sensitive);
+ gtk_widget_set_sensitive(import_button_, sensitive);
+}
+
uint16 ImportDialogGtk::GetCheckedItems() {
uint16 items = importer::NONE;
if (IsChecked(bookmarks_))
diff --git a/chrome/browser/gtk/import_dialog_gtk.h b/chrome/browser/gtk/import_dialog_gtk.h
index a1126b8..f52b845 100644
--- a/chrome/browser/gtk/import_dialog_gtk.h
+++ b/chrome/browser/gtk/import_dialog_gtk.h
@@ -12,14 +12,15 @@
class AccessibleWidgetHelper;
class Profile;
-class ImportDialogGtk : public ImportObserver {
+class ImportDialogGtk : public ImportObserver,
+ public ImporterList::Observer {
public:
// Displays the import box to import data from another browser into |profile|
// |initial_state| is a bitmask of ImportItems. Each checkbox for the bits in
// is checked.
static void Show(GtkWindow* parent, Profile* profile, int initial_state);
- // Overridden from ImportObserver:
+ // ImportObserver implementation.
virtual void ImportCanceled();
virtual void ImportComplete();
@@ -27,6 +28,9 @@ class ImportDialogGtk : public ImportObserver {
ImportDialogGtk(GtkWindow* parent, Profile* profile, int initial_state);
~ImportDialogGtk();
+ // ImporterList::Observer implementation.
+ virtual void SourceProfilesLoaded();
+
// Handler to respond to OK or Cancel responses from the dialog.
CHROMEGTK_CALLBACK_1(ImportDialogGtk, void, OnDialogResponse, int);
@@ -37,6 +41,10 @@ class ImportDialogGtk : public ImportObserver {
// checkboxes.
void UpdateDialogButtons();
+ // Sets the sensitivity of all controls on the dialog except the cancel
+ // button.
+ void SetDialogControlsSensitive(bool sensitive);
+
// Create a bitmask from the checkboxes of the dialog.
uint16 GetCheckedItems();
@@ -61,6 +69,9 @@ class ImportDialogGtk : public ImportObserver {
// History checkbox
GtkWidget* history_;
+ // Import button.
+ GtkWidget* import_button_;
+
// Our current profile
Profile* profile_;
diff --git a/chrome/browser/gtk/infobar_container_gtk.cc b/chrome/browser/gtk/infobar_container_gtk.cc
index b5c95e3..76ba36a 100644
--- a/chrome/browser/gtk/infobar_container_gtk.cc
+++ b/chrome/browser/gtk/infobar_container_gtk.cc
@@ -6,6 +6,8 @@
#include <gtk/gtk.h>
+#include <utility>
+
#include "base/command_line.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/gtk/browser_window_gtk.h"
@@ -16,7 +18,8 @@
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_switches.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
#include "third_party/skia/include/core/SkPaint.h"
namespace {
diff --git a/chrome/browser/gtk/instant_confirm_dialog_gtk.cc b/chrome/browser/gtk/instant_confirm_dialog_gtk.cc
index fcc95b6..1e7725c 100644
--- a/chrome/browser/gtk/instant_confirm_dialog_gtk.cc
+++ b/chrome/browser/gtk/instant_confirm_dialog_gtk.cc
@@ -11,8 +11,8 @@
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/instant/instant_confirm_dialog.h"
#include "chrome/browser/instant/instant_controller.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/show_options_url.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/options/show_options_url.h"
#include "googleurl/src/gurl.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/gtk/js_modal_dialog_gtk.cc b/chrome/browser/gtk/js_modal_dialog_gtk.cc
index b4a0953..27888d4 100644
--- a/chrome/browser/gtk/js_modal_dialog_gtk.cc
+++ b/chrome/browser/gtk/js_modal_dialog_gtk.cc
@@ -11,7 +11,7 @@
#include "base/logging.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/gtk/gtk_util.h"
-#include "chrome/browser/js_modal_dialog.h"
+#include "chrome/browser/ui/app_modal_dialogs/js_modal_dialog.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
@@ -135,8 +135,7 @@ JSModalDialogGtk::JSModalDialogGtk(JavaScriptAppModalDialog* dialog,
gtk_dialog_set_default_response(GTK_DIALOG(gtk_dialog_), GTK_RESPONSE_OK);
g_signal_connect(gtk_dialog_, "response",
- G_CALLBACK(JSModalDialogGtk::OnDialogResponse),
- reinterpret_cast<JSModalDialogGtk*>(this));
+ G_CALLBACK(OnDialogResponseThunk), this);
}
JSModalDialogGtk::~JSModalDialogGtk() {
@@ -174,32 +173,33 @@ void JSModalDialogGtk::ActivateAppModalDialog() {
void JSModalDialogGtk::CloseAppModalDialog() {
DCHECK(gtk_dialog_);
- HandleDialogResponse(GTK_DIALOG(gtk_dialog_), GTK_RESPONSE_DELETE_EVENT);
+ OnDialogResponse(gtk_dialog_, GTK_RESPONSE_DELETE_EVENT);
}
void JSModalDialogGtk::AcceptAppModalDialog() {
- HandleDialogResponse(GTK_DIALOG(gtk_dialog_), GTK_RESPONSE_OK);
+ OnDialogResponse(gtk_dialog_, GTK_RESPONSE_OK);
}
void JSModalDialogGtk::CancelAppModalDialog() {
- HandleDialogResponse(GTK_DIALOG(gtk_dialog_), GTK_RESPONSE_CANCEL);
+ OnDialogResponse(gtk_dialog_, GTK_RESPONSE_CANCEL);
}
////////////////////////////////////////////////////////////////////////////////
// JSModalDialogGtk, private:
-void JSModalDialogGtk::HandleDialogResponse(GtkDialog* dialog,
- gint response_id) {
+void JSModalDialogGtk::OnDialogResponse(GtkWidget* dialog,
+ int response_id) {
switch (response_id) {
case GTK_RESPONSE_OK:
// The first arg is the prompt text and the second is true if we want to
// suppress additional popups from the page.
- dialog_->OnAccept(GetPromptText(dialog), ShouldSuppressJSDialogs(dialog));
+ dialog_->OnAccept(GetPromptText(GTK_DIALOG(dialog)),
+ ShouldSuppressJSDialogs(GTK_DIALOG(dialog)));
break;
case GTK_RESPONSE_CANCEL:
case GTK_RESPONSE_DELETE_EVENT: // User hit the X on the dialog.
- dialog_->OnCancel(ShouldSuppressJSDialogs(dialog));
+ dialog_->OnCancel(ShouldSuppressJSDialogs(GTK_DIALOG(dialog)));
break;
default:
@@ -213,13 +213,6 @@ void JSModalDialogGtk::HandleDialogResponse(GtkDialog* dialog,
delete this;
}
-// static
-void JSModalDialogGtk::OnDialogResponse(GtkDialog* gtk_dialog,
- gint response_id,
- JSModalDialogGtk* dialog) {
- dialog->HandleDialogResponse(gtk_dialog, response_id);
-}
-
////////////////////////////////////////////////////////////////////////////////
// NativeAppModalDialog, public:
@@ -229,5 +222,3 @@ NativeAppModalDialog* NativeAppModalDialog::CreateNativeJavaScriptPrompt(
gfx::NativeWindow parent_window) {
return new JSModalDialogGtk(dialog, parent_window);
}
-
-
diff --git a/chrome/browser/gtk/js_modal_dialog_gtk.h b/chrome/browser/gtk/js_modal_dialog_gtk.h
index 18d573c..a6a132b 100644
--- a/chrome/browser/gtk/js_modal_dialog_gtk.h
+++ b/chrome/browser/gtk/js_modal_dialog_gtk.h
@@ -6,14 +6,14 @@
#define CHROME_BROWSER_GTK_JS_MODAL_DIALOG_GTK_H_
#pragma once
-#include <gtk/gtk.h>
-
#include "app/gtk_signal.h"
-#include "base/logging.h"
+#include "base/basictypes.h"
#include "base/scoped_ptr.h"
-#include "chrome/browser/native_app_modal_dialog.h"
+#include "chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h"
#include "gfx/native_widget_types.h"
+typedef struct _GtkWidget GtkWidget;
+
class JavaScriptAppModalDialog;
class JSModalDialogGtk : public NativeAppModalDialog {
@@ -31,9 +31,7 @@ class JSModalDialogGtk : public NativeAppModalDialog {
virtual void CancelAppModalDialog();
private:
- void HandleDialogResponse(GtkDialog* dialog, gint response_id);
- static void OnDialogResponse(GtkDialog* gtk_dialog, gint response_id,
- JSModalDialogGtk* dialog);
+ CHROMEGTK_CALLBACK_1(JSModalDialogGtk, void, OnDialogResponse, int);
scoped_ptr<JavaScriptAppModalDialog> dialog_;
GtkWidget* gtk_dialog_;
@@ -42,4 +40,3 @@ class JSModalDialogGtk : public NativeAppModalDialog {
};
#endif // CHROME_BROWSER_GTK_JS_MODAL_DIALOG_GTK_H_
-
diff --git a/chrome/browser/gtk/keyword_editor_view.cc b/chrome/browser/gtk/keyword_editor_view.cc
index 0753e28..c4b98da 100644
--- a/chrome/browser/gtk/keyword_editor_view.cc
+++ b/chrome/browser/gtk/keyword_editor_view.cc
@@ -14,7 +14,7 @@
#include "chrome/browser/gtk/gtk_tree.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/keyword_editor_controller.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
diff --git a/chrome/browser/gtk/location_bar_view_gtk.cc b/chrome/browser/gtk/location_bar_view_gtk.cc
index 002e9a6..c48f631 100644
--- a/chrome/browser/gtk/location_bar_view_gtk.cc
+++ b/chrome/browser/gtk/location_bar_view_gtk.cc
@@ -26,7 +26,7 @@
#include "chrome/browser/defaults.h"
#include "chrome/browser/extensions/extension_browser_event_router.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/gtk/bookmark_bubble_gtk.h"
#include "chrome/browser/gtk/bookmark_utils_gtk.h"
#include "chrome/browser/gtk/cairo_cached_surface.h"
@@ -39,12 +39,12 @@
#include "chrome/browser/gtk/rounded_window.h"
#include "chrome/browser/gtk/view_id_util.h"
#include "chrome/browser/instant/instant_controller.h"
-#include "chrome/browser/location_bar_util.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/omnibox/location_bar_util.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_action.h"
#include "chrome/common/extensions/extension_resource.h"
@@ -464,12 +464,7 @@ bool LocationBarViewGtk::OnCommitSuggestedText(
}
bool LocationBarViewGtk::AcceptCurrentInstantPreview() {
- InstantController* instant = browser_->instant();
- if (instant && instant->IsCurrent()) {
- instant->CommitCurrentPreview(INSTANT_COMMIT_PRESSED_ENTER);
- return true;
- }
- return false;
+ return InstantController::CommitIfCurrent(browser_->instant());
}
void LocationBarViewGtk::OnSetSuggestedSearchText(
@@ -680,7 +675,7 @@ void LocationBarViewGtk::UpdateContentSettingsIcons() {
void LocationBarViewGtk::UpdatePageActions() {
std::vector<ExtensionAction*> page_actions;
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
if (!service)
return;
@@ -756,6 +751,10 @@ LocationBarTesting* LocationBarViewGtk::GetLocationBarForTesting() {
return this;
}
+int LocationBarViewGtk::PageActionCount() {
+ return page_action_views_.size();
+}
+
int LocationBarViewGtk::PageActionVisibleCount() {
int count = 0;
gtk_container_foreach(GTK_CONTAINER(page_action_hbox_.get()),
@@ -991,7 +990,7 @@ void LocationBarViewGtk::SetKeywordLabel(const std::wstring& keyword) {
if (is_extension_keyword) {
const TemplateURL* template_url =
profile_->GetTemplateURLModel()->GetTemplateURLForKeyword(keyword);
- const SkBitmap& bitmap = profile_->GetExtensionsService()->
+ const SkBitmap& bitmap = profile_->GetExtensionService()->
GetOmniboxIcon(template_url->GetExtensionId());
GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&bitmap);
gtk_image_set_from_pixbuf(GTK_IMAGE(tab_to_search_magnifier_), pixbuf);
@@ -1344,7 +1343,7 @@ LocationBarViewGtk::PageActionViewGtk::PageActionViewGtk(
image_.Own(gtk_image_new());
gtk_container_add(GTK_CONTAINER(event_box_.get()), image_.get());
- const Extension* extension = profile->GetExtensionsService()->
+ const Extension* extension = profile->GetExtensionService()->
GetExtensionById(page_action->extension_id(), false);
DCHECK(extension);
@@ -1508,7 +1507,7 @@ gboolean LocationBarViewGtk::PageActionViewGtk::OnButtonPressed(
event->button.button);
}
} else {
- const Extension* extension = profile_->GetExtensionsService()->
+ const Extension* extension = profile_->GetExtensionService()->
GetExtensionById(page_action()->extension_id(), false);
context_menu_model_ =
diff --git a/chrome/browser/gtk/location_bar_view_gtk.h b/chrome/browser/gtk/location_bar_view_gtk.h
index bab0279..f1b1534 100644
--- a/chrome/browser/gtk/location_bar_view_gtk.h
+++ b/chrome/browser/gtk/location_bar_view_gtk.h
@@ -23,7 +23,7 @@
#include "chrome/browser/gtk/info_bubble_gtk.h"
#include "chrome/browser/gtk/menu_gtk.h"
#include "chrome/browser/gtk/owned_widget_gtk.h"
-#include "chrome/browser/location_bar.h"
+#include "chrome/browser/ui/omnibox/location_bar.h"
#include "chrome/common/content_settings_types.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
@@ -130,7 +130,7 @@ class LocationBarViewGtk : public AutocompleteEditController,
virtual LocationBarTesting* GetLocationBarForTesting();
// Implement the LocationBarTesting interface.
- virtual int PageActionCount() { return page_action_views_.size(); }
+ virtual int PageActionCount();
virtual int PageActionVisibleCount();
virtual ExtensionAction* GetPageAction(size_t index);
virtual ExtensionAction* GetVisiblePageAction(size_t index);
diff --git a/chrome/browser/gtk/menu_gtk.cc b/chrome/browser/gtk/menu_gtk.cc
index 5823f25..04450ef 100644
--- a/chrome/browser/gtk/menu_gtk.cc
+++ b/chrome/browser/gtk/menu_gtk.cc
@@ -121,7 +121,6 @@ GtkWidget* MenuGtk::Delegate::GetDefaultImageForCommandId(int command_id) {
case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB:
case IDC_CONTENT_CONTEXT_OPENAVNEWTAB:
- case IDC_CONTENT_CONTEXT_OPENFRAMENEWTAB:
stock = GTK_STOCK_NEW;
break;
@@ -132,6 +131,9 @@ GtkWidget* MenuGtk::Delegate::GetDefaultImageForCommandId(int command_id) {
case IDC_CONTENT_CONTEXT_SAVEIMAGEAS:
case IDC_CONTENT_CONTEXT_SAVEAVAS:
case IDC_CONTENT_CONTEXT_SAVELINKAS:
+ stock = GTK_STOCK_SAVE_AS;
+ break;
+
case IDC_SAVE_PAGE:
stock = GTK_STOCK_SAVE;
break;
@@ -157,6 +159,7 @@ GtkWidget* MenuGtk::Delegate::GetDefaultImageForCommandId(int command_id) {
break;
case IDC_CONTENT_CONTEXT_DELETE:
+ case IDC_BOOKMARK_BAR_REMOVE:
stock = GTK_STOCK_DELETE;
break;
@@ -243,6 +246,23 @@ GtkWidget* MenuGtk::Delegate::GetDefaultImageForCommandId(int command_id) {
stock = GTK_STOCK_PROPERTIES;
break;
+ case IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK:
+ stock = GTK_STOCK_ADD;
+ break;
+
+ case IDC_BOOKMARK_BAR_RENAME_FOLDER:
+ case IDC_BOOKMARK_BAR_EDIT:
+ stock = GTK_STOCK_EDIT;
+ break;
+
+ case IDC_BOOKMARK_BAR_NEW_FOLDER:
+ stock = GTK_STOCK_DIRECTORY;
+ break;
+
+ case IDC_BOOKMARK_BAR_OPEN_ALL:
+ stock = GTK_STOCK_OPEN;
+ break;
+
default:
stock = NULL;
}
@@ -724,7 +744,7 @@ void MenuGtk::SetButtonItemInfo(GtkWidget* button, gpointer userdata) {
int index = GPOINTER_TO_INT(g_object_get_data(
G_OBJECT(button), "button-model-id"));
- if (model->IsLabelDynamicAt(index)) {
+ if (model->IsItemDynamicAt(index)) {
std::string label =
gfx::ConvertAcceleratorsFromWindowsStyle(
UTF16ToUTF8(model->GetLabelAt(index)));
@@ -783,7 +803,8 @@ void MenuGtk::SetMenuItemInfo(GtkWidget* widget, gpointer userdata) {
if (model->IsVisibleAt(id)) {
// Update the menu item label if it is dynamic.
- if (model->IsLabelDynamicAt(id)) {
+ // TODO(atwilson): Update the icon as well (http://crbug.com/66508).
+ if (model->IsItemDynamicAt(id)) {
std::string label =
gfx::ConvertAcceleratorsFromWindowsStyle(
UTF16ToUTF8(model->GetLabelAt(id)));
diff --git a/chrome/browser/gtk/notifications/balloon_view_gtk.cc b/chrome/browser/gtk/notifications/balloon_view_gtk.cc
index 9161be5..bbca070 100644
--- a/chrome/browser/gtk/notifications/balloon_view_gtk.cc
+++ b/chrome/browser/gtk/notifications/balloon_view_gtk.cc
@@ -29,7 +29,7 @@
#include "chrome/browser/notifications/desktop_notification_service.h"
#include "chrome/browser/notifications/notification.h"
#include "chrome/browser/notifications/notification_options_menu_model.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/themes/browser_theme_provider.h"
@@ -126,6 +126,10 @@ gfx::Size BalloonViewImpl::GetSize() const {
return gfx::Size(GetDesiredTotalWidth(), GetDesiredTotalHeight());
}
+BalloonHost* BalloonViewImpl::GetHost() const {
+ return html_contents_.get();
+}
+
void BalloonViewImpl::DelayedClose(bool by_user) {
html_contents_->Shutdown();
if (frame_container_) {
diff --git a/chrome/browser/gtk/notifications/balloon_view_gtk.h b/chrome/browser/gtk/notifications/balloon_view_gtk.h
index dce5869..de95e71 100644
--- a/chrome/browser/gtk/notifications/balloon_view_gtk.h
+++ b/chrome/browser/gtk/notifications/balloon_view_gtk.h
@@ -46,7 +46,7 @@ class BalloonViewImpl : public BalloonView,
virtual void RepositionToBalloon();
virtual void Close(bool by_user);
virtual gfx::Size GetSize() const;
- virtual BalloonHost* GetHost() const { return html_contents_.get(); }
+ virtual BalloonHost* GetHost() const;
private:
// NotificationObserver interface.
diff --git a/chrome/browser/gtk/options/advanced_contents_gtk.cc b/chrome/browser/gtk/options/advanced_contents_gtk.cc
index c941aab..21fe182 100644
--- a/chrome/browser/gtk/options/advanced_contents_gtk.cc
+++ b/chrome/browser/gtk/options/advanced_contents_gtk.cc
@@ -33,14 +33,14 @@
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/gtk/options/content_settings_window_gtk.h"
#include "chrome/browser/gtk/options/options_layout_gtk.h"
-#include "chrome/browser/options_page_base.h"
-#include "chrome/browser/options_util.h"
#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/prefs/pref_set_observer.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
-#include "chrome/browser/show_options_url.h"
+#include "chrome/browser/ui/options/options_page_base.h"
+#include "chrome/browser/ui/options/options_util.h"
+#include "chrome/browser/ui/options/show_options_url.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
@@ -614,10 +614,6 @@ class PrivacySection : public OptionsPageBase {
// permission match the |reporting_enabled_checkbox_|.
void ResolveMetricsReportingEnabled();
- // Inform the user that the browser must be restarted for changes to take
- // effect.
- void ShowRestartMessageBox() const;
-
// The callback functions for the options widgets.
static void OnContentSettingsClicked(GtkButton* button,
PrivacySection* privacy_section);
@@ -871,8 +867,6 @@ void PrivacySection::OnLoggingChange(GtkWidget* widget,
reinterpret_cast<gpointer>(OnLoggingChange),
privacy_section);
privacy_section->ResolveMetricsReportingEnabled();
- if (enabled == gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
- privacy_section->ShowRestartMessageBox();
g_signal_handlers_unblock_by_func(widget,
reinterpret_cast<gpointer>(OnLoggingChange),
privacy_section);
@@ -939,22 +933,6 @@ void PrivacySection::ResolveMetricsReportingEnabled() {
#endif
}
-void PrivacySection::ShowRestartMessageBox() const {
- GtkWidget* dialog = gtk_message_dialog_new(
- GTK_WINDOW(gtk_widget_get_toplevel(page_)),
- static_cast<GtkDialogFlags>(GTK_DIALOG_MODAL),
- GTK_MESSAGE_INFO,
- GTK_BUTTONS_OK,
- "%s",
- l10n_util::GetStringUTF8(IDS_OPTIONS_RESTART_REQUIRED).c_str());
- gtk_util::ApplyMessageDialogQuirks(dialog);
- gtk_window_set_title(GTK_WINDOW(dialog),
- l10n_util::GetStringUTF8(IDS_PRODUCT_NAME).c_str());
- g_signal_connect_swapped(dialog, "response", G_CALLBACK(gtk_widget_destroy),
- dialog);
- gtk_util::ShowDialog(dialog);
-}
-
///////////////////////////////////////////////////////////////////////////////
// SecuritySection
@@ -976,8 +954,6 @@ class SecuritySection : public OptionsPageBase {
SecuritySection* section);
static void OnRevCheckingEnabledToggled(GtkToggleButton* togglebutton,
SecuritySection* section);
- static void OnSSL2EnabledToggled(GtkToggleButton* togglebutton,
- SecuritySection* section);
static void OnSSL3EnabledToggled(GtkToggleButton* togglebutton,
SecuritySection* section);
static void OnTLS1EnabledToggled(GtkToggleButton* togglebutton,
@@ -986,13 +962,11 @@ class SecuritySection : public OptionsPageBase {
// The widget containing the options for this section.
GtkWidget* page_;
GtkWidget* rev_checking_enabled_checkbox_;
- GtkWidget* ssl2_enabled_checkbox_;
GtkWidget* ssl3_enabled_checkbox_;
GtkWidget* tls1_enabled_checkbox_;
// SSLConfigService prefs.
BooleanPrefMember rev_checking_enabled_;
- BooleanPrefMember ssl2_enabled_;
BooleanPrefMember ssl3_enabled_;
BooleanPrefMember tls1_enabled_;
@@ -1041,10 +1015,6 @@ SecuritySection::SecuritySection(Profile* profile)
G_CALLBACK(OnRevCheckingEnabledToggled), this);
accessible_widget_helper_->SetWidgetName(
rev_checking_enabled_checkbox_, IDS_OPTIONS_SSL_CHECKREVOCATION);
- ssl2_enabled_checkbox_ = AddCheckButtonWithWrappedLabel(
- IDS_OPTIONS_SSL_USESSL2, page_, G_CALLBACK(OnSSL2EnabledToggled), this);
- accessible_widget_helper_->SetWidgetName(
- ssl2_enabled_checkbox_, IDS_OPTIONS_SSL_USESSL2);
ssl3_enabled_checkbox_ = AddCheckButtonWithWrappedLabel(
IDS_OPTIONS_SSL_USESSL3, page_, G_CALLBACK(OnSSL3EnabledToggled), this);
accessible_widget_helper_->SetWidgetName(
@@ -1056,7 +1026,6 @@ SecuritySection::SecuritySection(Profile* profile)
rev_checking_enabled_.Init(prefs::kCertRevocationCheckingEnabled,
profile->GetPrefs(), this);
- ssl2_enabled_.Init(prefs::kSSL2Enabled, profile->GetPrefs(), this);
ssl3_enabled_.Init(prefs::kSSL3Enabled, profile->GetPrefs(), this);
tls1_enabled_.Init(prefs::kTLS1Enabled, profile->GetPrefs(), this);
@@ -1070,10 +1039,6 @@ void SecuritySection::NotifyPrefChanged(const std::string* pref_name) {
GTK_TOGGLE_BUTTON(rev_checking_enabled_checkbox_),
rev_checking_enabled_.GetValue());
}
- if (!pref_name || *pref_name == prefs::kSSL2Enabled) {
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ssl2_enabled_checkbox_),
- ssl2_enabled_.GetValue());
- }
if (!pref_name || *pref_name == prefs::kSSL3Enabled) {
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ssl3_enabled_checkbox_),
ssl3_enabled_.GetValue());
@@ -1113,23 +1078,6 @@ void SecuritySection::OnRevCheckingEnabledToggled(GtkToggleButton* togglebutton,
}
// static
-void SecuritySection::OnSSL2EnabledToggled(GtkToggleButton* togglebutton,
- SecuritySection* section) {
- if (section->pref_changing_)
- return;
-
- bool enabled = gtk_toggle_button_get_active(togglebutton);
- if (enabled) {
- section->UserMetricsRecordAction(UserMetricsAction("Options_SSL2_Enable"),
- NULL);
- } else {
- section->UserMetricsRecordAction(UserMetricsAction("Options_SSL2_Disable"),
- NULL);
- }
- section->ssl2_enabled_.SetValue(enabled);
-}
-
-// static
void SecuritySection::OnSSL3EnabledToggled(GtkToggleButton* togglebutton,
SecuritySection* section) {
if (section->pref_changing_)
diff --git a/chrome/browser/gtk/options/advanced_page_gtk.cc b/chrome/browser/gtk/options/advanced_page_gtk.cc
index 8351322..1bab4b4 100644
--- a/chrome/browser/gtk/options/advanced_page_gtk.cc
+++ b/chrome/browser/gtk/options/advanced_page_gtk.cc
@@ -6,8 +6,8 @@
#include "app/l10n_util.h"
#include "chrome/browser/gtk/gtk_util.h"
-#include "chrome/browser/options_util.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/options/options_util.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/gtk/options/advanced_page_gtk.h b/chrome/browser/gtk/options/advanced_page_gtk.h
index 193a6d6..f1345c8 100644
--- a/chrome/browser/gtk/options/advanced_page_gtk.h
+++ b/chrome/browser/gtk/options/advanced_page_gtk.h
@@ -11,8 +11,8 @@
#include "app/gtk_signal.h"
#include "chrome/browser/gtk/options/advanced_contents_gtk.h"
#include "chrome/browser/gtk/options/managed_prefs_banner_gtk.h"
-#include "chrome/browser/options_page_base.h"
#include "chrome/browser/prefs/pref_member.h"
+#include "chrome/browser/ui/options/options_page_base.h"
class Profile;
diff --git a/chrome/browser/gtk/options/content_exception_editor.cc b/chrome/browser/gtk/options/content_exception_editor.cc
index e0dfc83..5f8aa69 100644
--- a/chrome/browser/gtk/options/content_exception_editor.cc
+++ b/chrome/browser/gtk/options/content_exception_editor.cc
@@ -9,8 +9,8 @@
#include "base/message_loop.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/content_exceptions_table_model.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/gtk/gtk_util.h"
-#include "chrome/browser/host_content_settings_map.h"
#include "grit/app_resources.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
@@ -21,7 +21,7 @@ ContentExceptionEditor::ContentExceptionEditor(
ContentExceptionsTableModel* model,
bool allow_off_the_record,
int index,
- const HostContentSettingsMap::Pattern& pattern,
+ const ContentSettingsPattern& pattern,
ContentSetting setting,
bool is_off_the_record)
: delegate_(delegate),
@@ -91,7 +91,7 @@ ContentExceptionEditor::ContentExceptionEditor(
}
bool ContentExceptionEditor::IsPatternValid(
- const HostContentSettingsMap::Pattern& pattern,
+ const ContentSettingsPattern& pattern,
bool is_off_the_record) const {
bool is_valid_pattern = pattern.IsValid() &&
(model_->IndexOfExceptionByPattern(pattern, is_off_the_record) == -1);
@@ -107,8 +107,7 @@ void ContentExceptionEditor::UpdateImage(GtkWidget* image, bool is_valid) {
}
void ContentExceptionEditor::OnEntryChanged(GtkWidget* entry) {
- HostContentSettingsMap::Pattern new_pattern(
- gtk_entry_get_text(GTK_ENTRY(entry)));
+ ContentSettingsPattern new_pattern(gtk_entry_get_text(GTK_ENTRY(entry)));
bool is_off_the_record =
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(otr_checkbox_));
bool is_valid = IsPatternValid(new_pattern, is_off_the_record);
@@ -120,8 +119,7 @@ void ContentExceptionEditor::OnEntryChanged(GtkWidget* entry) {
void ContentExceptionEditor::OnResponse(GtkWidget* sender, int response_id) {
if (response_id == GTK_RESPONSE_OK) {
// Notify our delegate to update everything.
- HostContentSettingsMap::Pattern new_pattern(
- gtk_entry_get_text(GTK_ENTRY(entry_)));
+ ContentSettingsPattern new_pattern(gtk_entry_get_text(GTK_ENTRY(entry_)));
ContentSetting setting = cb_model_.SettingForIndex(
gtk_combo_box_get_active(GTK_COMBO_BOX(action_combo_)));
bool is_off_the_record =
diff --git a/chrome/browser/gtk/options/content_exception_editor.h b/chrome/browser/gtk/options/content_exception_editor.h
index fed69c0..4ed5ad3 100644
--- a/chrome/browser/gtk/options/content_exception_editor.h
+++ b/chrome/browser/gtk/options/content_exception_editor.h
@@ -23,7 +23,7 @@ class ContentExceptionEditor {
public:
// Invoked when the user accepts the edit.
virtual void AcceptExceptionEdit(
- const HostContentSettingsMap::Pattern& pattern,
+ const ContentSettingsPattern& pattern,
ContentSetting setting,
bool is_off_the_record,
int index,
@@ -38,7 +38,7 @@ class ContentExceptionEditor {
ContentExceptionsTableModel* model,
bool allow_off_the_record,
int index,
- const HostContentSettingsMap::Pattern& pattern,
+ const ContentSettingsPattern& pattern,
ContentSetting setting,
bool is_off_the_record);
virtual ~ContentExceptionEditor() {}
@@ -47,7 +47,7 @@ class ContentExceptionEditor {
// Returns true if we're adding a new item.
bool is_new() const { return index_ == -1; }
- bool IsPatternValid(const HostContentSettingsMap::Pattern& pattern,
+ bool IsPatternValid(const ContentSettingsPattern& pattern,
bool is_off_the_record) const;
void UpdateImage(GtkWidget* image, bool is_valid);
@@ -65,7 +65,7 @@ class ContentExceptionEditor {
// Index of the item being edited. If -1, indicates this is a new entry.
const int index_;
- const HostContentSettingsMap::Pattern pattern_;
+ const ContentSettingsPattern pattern_;
const ContentSetting setting_;
// UI widgets.
diff --git a/chrome/browser/gtk/options/content_exceptions_window_gtk.cc b/chrome/browser/gtk/options/content_exceptions_window_gtk.cc
index 5c8cdfd..6a1fc88 100644
--- a/chrome/browser/gtk/options/content_exceptions_window_gtk.cc
+++ b/chrome/browser/gtk/options/content_exceptions_window_gtk.cc
@@ -199,7 +199,7 @@ void ContentExceptionsWindowGtk::SetColumnValues(int row, GtkTreeIter* iter) {
}
void ContentExceptionsWindowGtk::AcceptExceptionEdit(
- const HostContentSettingsMap::Pattern& pattern,
+ const ContentSettingsPattern& pattern,
ContentSetting setting,
bool is_off_the_record,
int index,
@@ -235,7 +235,7 @@ void ContentExceptionsWindowGtk::UpdateButtonState() {
void ContentExceptionsWindowGtk::Add(GtkWidget* widget) {
new ContentExceptionEditor(GTK_WINDOW(dialog_),
this, model_.get(), allow_off_the_record_, -1,
- HostContentSettingsMap::Pattern(),
+ ContentSettingsPattern(),
CONTENT_SETTING_BLOCK, false);
}
diff --git a/chrome/browser/gtk/options/content_exceptions_window_gtk.h b/chrome/browser/gtk/options/content_exceptions_window_gtk.h
index 4779833..0f70c90 100644
--- a/chrome/browser/gtk/options/content_exceptions_window_gtk.h
+++ b/chrome/browser/gtk/options/content_exceptions_window_gtk.h
@@ -37,7 +37,7 @@ class ContentExceptionsWindowGtk : public gtk_tree::TableAdapter::Delegate,
// ContentExceptionEditor::Delegate implementation:
virtual void AcceptExceptionEdit(
- const HostContentSettingsMap::Pattern& pattern,
+ const ContentSettingsPattern& pattern,
ContentSetting setting,
bool is_off_the_record,
int index,
diff --git a/chrome/browser/gtk/options/content_exceptions_window_gtk_unittest.cc b/chrome/browser/gtk/options/content_exceptions_window_gtk_unittest.cc
index 764e991..8af7c55 100644
--- a/chrome/browser/gtk/options/content_exceptions_window_gtk_unittest.cc
+++ b/chrome/browser/gtk/options/content_exceptions_window_gtk_unittest.cc
@@ -26,7 +26,7 @@ class ContentExceptionsWindowGtkUnittest : public testing::Test {
void AddException(const std::string& pattern, ContentSetting value) {
host_content_settings_map_->SetContentSetting(
- HostContentSettingsMap::Pattern(pattern),
+ ContentSettingsPattern(pattern),
CONTENT_SETTINGS_TYPE_JAVASCRIPT,
"",
value);
diff --git a/chrome/browser/gtk/options/content_filter_page_gtk.cc b/chrome/browser/gtk/options/content_filter_page_gtk.cc
index 21387a5..13aeb05 100644
--- a/chrome/browser/gtk/options/content_filter_page_gtk.cc
+++ b/chrome/browser/gtk/options/content_filter_page_gtk.cc
@@ -6,10 +6,12 @@
#include "app/l10n_util.h"
#include "base/command_line.h"
+#include "chrome/browser/content_settings/content_settings_details.h"
+#include "chrome/browser/content_settings/content_settings_pattern.h"
#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
#include "chrome/browser/geolocation/geolocation_exceptions_table_model.h"
#include "chrome/browser/plugin_exceptions_table_model.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/gtk/browser_window_gtk.h"
#include "chrome/browser/gtk/gtk_chrome_link_button.h"
@@ -18,8 +20,8 @@
#include "chrome/browser/gtk/options/simple_content_exceptions_window.h"
#include "chrome/browser/notifications/desktop_notification_service.h"
#include "chrome/browser/notifications/notification_exceptions_table_model.h"
-#include "chrome/browser/show_options_url.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/options/show_options_url.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_service.h"
@@ -156,6 +158,10 @@ GtkWidget* ContentFilterPageGtk::InitGroup() {
// aften content settings change.
registrar_.Add(this, NotificationType::CONTENT_SETTINGS_CHANGED,
NotificationService::AllSources());
+ registrar_.Add(this, NotificationType::DESKTOP_NOTIFICATION_DEFAULT_CHANGED,
+ NotificationService::AllSources());
+ registrar_.Add(this, NotificationType::GEOLOCATION_SETTINGS_CHANGED,
+ NotificationService::AllSources());
return vbox;
}
@@ -163,15 +169,24 @@ GtkWidget* ContentFilterPageGtk::InitGroup() {
void ContentFilterPageGtk::UpdateButtonsState() {
// Get default_setting.
ContentSetting default_setting;
+ // If the content setting is managed, sensitive is set to false and the radio
+ // buttons will be disabled.
+ bool sensitive = true;
if (content_type_ == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
default_setting = profile()->GetGeolocationContentSettingsMap()->
GetDefaultContentSetting();
+ sensitive = !profile()->GetGeolocationContentSettingsMap()->
+ IsDefaultContentSettingManaged();
} else if (content_type_ == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
default_setting = profile()->GetDesktopNotificationService()->
GetDefaultContentSetting();
+ sensitive = !profile()->GetDesktopNotificationService()->
+ IsDefaultContentSettingManaged();
} else {
default_setting = profile()->GetHostContentSettingsMap()->
GetDefaultContentSetting(content_type_);
+ sensitive = !profile()->GetHostContentSettingsMap()->
+ IsDefaultContentSettingManaged(content_type_);
}
// Set UI state.
if (default_setting == CONTENT_SETTING_ALLOW) {
@@ -185,8 +200,6 @@ void ContentFilterPageGtk::UpdateButtonsState() {
}
// Disable the UI if the default content setting is managed.
- bool sensitive = !profile()->GetHostContentSettingsMap()->
- IsDefaultContentSettingManaged(content_type_);
gtk_widget_set_sensitive(allow_radio_, sensitive);
gtk_widget_set_sensitive(block_radio_, sensitive);
if (ask_radio_)
@@ -275,17 +288,25 @@ void ContentFilterPageGtk::OnPluginsPageLinkClicked(GtkWidget* button) {
void ContentFilterPageGtk::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
-
if (type == NotificationType::CONTENT_SETTINGS_CHANGED) {
NotifyContentSettingsChanged(
- Details<HostContentSettingsMap::ContentSettingsDetails>(details).ptr());
+ Details<const ContentSettingsDetails>(details).ptr());
+ } else if (type == NotificationType::GEOLOCATION_SETTINGS_CHANGED) {
+ NotifyContentSettingsChanged(
+ Details<const ContentSettingsDetails>(details).ptr());
+ } else if (type == NotificationType::DESKTOP_NOTIFICATION_DEFAULT_CHANGED) {
+ ContentSettingsDetails content_settings_details(
+ ContentSettingsPattern(),
+ CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
+ "");
+ NotifyContentSettingsChanged(&content_settings_details);
} else {
OptionsPageBase::Observe(type, source, details);
}
}
void ContentFilterPageGtk::NotifyContentSettingsChanged(
- const HostContentSettingsMap::ContentSettingsDetails *details) {
+ const ContentSettingsDetails *details) {
if (details->type() == CONTENT_SETTINGS_TYPE_DEFAULT ||
details->type() == content_type_) {
ignore_toggle_ = true;
diff --git a/chrome/browser/gtk/options/content_filter_page_gtk.h b/chrome/browser/gtk/options/content_filter_page_gtk.h
index e3c2d6a..d5d3de2 100644
--- a/chrome/browser/gtk/options/content_filter_page_gtk.h
+++ b/chrome/browser/gtk/options/content_filter_page_gtk.h
@@ -9,12 +9,14 @@
#include <gtk/gtk.h>
#include "app/gtk_signal.h"
-#include "chrome/browser/options_page_base.h"
-#include "chrome/browser/host_content_settings_map.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
+#include "chrome/browser/ui/options/options_page_base.h"
#include "chrome/common/content_settings.h"
#include "chrome/common/content_settings_types.h"
#include "chrome/common/notification_registrar.h"
+class ContentSettingsDetails;
+
// A page in the content settings window. Used for everything but the Cookies
// page (which has a much more complex dialog). A |content_type| is passed into
// the constructor and the correct strings and settings are used.
@@ -38,7 +40,7 @@ class ContentFilterPageGtk : public OptionsPageBase {
virtual void UpdateButtonsState();
virtual void NotifyContentSettingsChanged(
- const HostContentSettingsMap::ContentSettingsDetails *details);
+ const ContentSettingsDetails* details);
// Builds the content of the dialog.
GtkWidget* InitGroup();
diff --git a/chrome/browser/gtk/options/content_page_gtk.cc b/chrome/browser/gtk/options/content_page_gtk.cc
index 5cfe3b7..0981456 100644
--- a/chrome/browser/gtk/options/content_page_gtk.cc
+++ b/chrome/browser/gtk/options/content_page_gtk.cc
@@ -18,6 +18,7 @@
#include "chrome/browser/gtk/options/passwords_exceptions_window_gtk.h"
#include "chrome/browser/importer/importer_data_types.h"
#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/sync_ui_util.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
diff --git a/chrome/browser/gtk/options/content_page_gtk.h b/chrome/browser/gtk/options/content_page_gtk.h
index 286e28c..eb840b9 100644
--- a/chrome/browser/gtk/options/content_page_gtk.h
+++ b/chrome/browser/gtk/options/content_page_gtk.h
@@ -8,13 +8,16 @@
#include <gtk/gtk.h>
+#include <string>
+
#include "app/gtk_signal.h"
#include "chrome/browser/autofill/personal_data_manager.h"
#include "chrome/browser/gtk/options/managed_prefs_banner_gtk.h"
-#include "chrome/browser/options_page_base.h"
#include "chrome/browser/prefs/pref_member.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/ui/options/options_page_base.h"
+
+class Profile;
class ContentPageGtk : public OptionsPageBase,
public ProfileSyncServiceObserver {
diff --git a/chrome/browser/gtk/options/content_settings_window_gtk.cc b/chrome/browser/gtk/options/content_settings_window_gtk.cc
index d890a2a..91b0019 100644
--- a/chrome/browser/gtk/options/content_settings_window_gtk.cc
+++ b/chrome/browser/gtk/options/content_settings_window_gtk.cc
@@ -9,18 +9,16 @@
#include "app/l10n_util.h"
#include "base/command_line.h"
#include "base/message_loop.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/gtk/accessible_widget_helper_gtk.h"
#include "chrome/browser/gtk/browser_window_gtk.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/gtk/gtk_tree.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/content_settings_types.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/gtk/options/cookie_filter_page_gtk.cc b/chrome/browser/gtk/options/cookie_filter_page_gtk.cc
index 66eac73..d2fa259 100644
--- a/chrome/browser/gtk/options/cookie_filter_page_gtk.cc
+++ b/chrome/browser/gtk/options/cookie_filter_page_gtk.cc
@@ -8,15 +8,15 @@
#include "base/auto_reset.h"
#include "base/command_line.h"
#include "chrome/browser/browsing_data_local_storage_helper.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/gtk/browser_window_gtk.h"
#include "chrome/browser/gtk/gtk_chrome_link_button.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/gtk/options/content_exceptions_window_gtk.h"
#include "chrome/browser/gtk/options/cookies_view.h"
-#include "chrome/browser/host_content_settings_map.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/show_options_url.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/options/show_options_url.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/gtk/options/cookie_filter_page_gtk.h b/chrome/browser/gtk/options/cookie_filter_page_gtk.h
index 37c0ce3..f07cbdb 100644
--- a/chrome/browser/gtk/options/cookie_filter_page_gtk.h
+++ b/chrome/browser/gtk/options/cookie_filter_page_gtk.h
@@ -11,9 +11,9 @@
#include <string>
#include "app/gtk_signal.h"
-#include "chrome/browser/host_content_settings_map.h"
-#include "chrome/browser/options_page_base.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/prefs/pref_member.h"
+#include "chrome/browser/ui/options/options_page_base.h"
class Profile;
diff --git a/chrome/browser/gtk/options/cookies_view.cc b/chrome/browser/gtk/options/cookies_view.cc
index 557b22a..9b4cedd 100644
--- a/chrome/browser/gtk/options/cookies_view.cc
+++ b/chrome/browser/gtk/options/cookies_view.cc
@@ -13,7 +13,7 @@
#include "base/string_util.h"
#include "chrome/browser/cookies_tree_model.h"
#include "chrome/browser/gtk/gtk_util.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "gfx/gtk_util.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
diff --git a/chrome/browser/gtk/options/cookies_view_unittest.cc b/chrome/browser/gtk/options/cookies_view_unittest.cc
index 0c78d7f..8087cf8 100644
--- a/chrome/browser/gtk/options/cookies_view_unittest.cc
+++ b/chrome/browser/gtk/options/cookies_view_unittest.cc
@@ -105,7 +105,7 @@ class CookiesViewTest : public testing::Test {
// EXPECT_STREQ("Y,X", GetMonsterCookies(monster).c_str());
std::string GetMonsterCookies(net::CookieMonster* monster) {
std::vector<std::string> parts;
- net::CookieMonster::CookieList cookie_list = monster->GetAllCookies();
+ net::CookieList cookie_list = monster->GetAllCookies();
for (size_t i = 0; i < cookie_list.size(); ++i)
parts.push_back(cookie_list[i].Name());
return JoinString(parts, ',');
diff --git a/chrome/browser/gtk/options/fonts_languages_window_gtk.cc b/chrome/browser/gtk/options/fonts_languages_window_gtk.cc
index ce046a9..e37cb1c 100644
--- a/chrome/browser/gtk/options/fonts_languages_window_gtk.cc
+++ b/chrome/browser/gtk/options/fonts_languages_window_gtk.cc
@@ -9,7 +9,7 @@
#include "app/l10n_util.h"
#include "base/message_loop.h"
#include "chrome/browser/gtk/gtk_util.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/gtk/options/fonts_page_gtk.h"
#include "chrome/browser/gtk/options/languages_page_gtk.h"
#include "grit/chromium_strings.h"
diff --git a/chrome/browser/gtk/options/fonts_page_gtk.cc b/chrome/browser/gtk/options/fonts_page_gtk.cc
index 555f098..a3c2d4e 100644
--- a/chrome/browser/gtk/options/fonts_page_gtk.cc
+++ b/chrome/browser/gtk/options/fonts_page_gtk.cc
@@ -4,14 +4,15 @@
#include "chrome/browser/gtk/options/fonts_page_gtk.h"
+#include <string>
+
#include "app/l10n_util.h"
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/default_encoding_combo_model.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/gtk/options/options_layout_gtk.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "gfx/font.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/gtk/options/fonts_page_gtk.h b/chrome/browser/gtk/options/fonts_page_gtk.h
index fc87863..3dbdf5a 100644
--- a/chrome/browser/gtk/options/fonts_page_gtk.h
+++ b/chrome/browser/gtk/options/fonts_page_gtk.h
@@ -14,8 +14,8 @@
#include "app/gtk_signal.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/character_encoding.h"
-#include "chrome/browser/options_page_base.h"
#include "chrome/browser/prefs/pref_member.h"
+#include "chrome/browser/ui/options/options_page_base.h"
class DefaultEncodingComboboxModel;
diff --git a/chrome/browser/gtk/options/general_page_gtk.cc b/chrome/browser/gtk/options/general_page_gtk.cc
index 70e88b0..61f806e 100644
--- a/chrome/browser/gtk/options/general_page_gtk.cc
+++ b/chrome/browser/gtk/options/general_page_gtk.cc
@@ -24,12 +24,11 @@
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prefs/session_startup_pref.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
-#include "chrome/browser/show_options_url.h"
+#include "chrome/browser/ui/options/show_options_url.h"
#include "chrome/common/chrome_switches.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "gfx/gtk_util.h"
diff --git a/chrome/browser/gtk/options/general_page_gtk.h b/chrome/browser/gtk/options/general_page_gtk.h
index 0050b2b..05dac88 100644
--- a/chrome/browser/gtk/options/general_page_gtk.h
+++ b/chrome/browser/gtk/options/general_page_gtk.h
@@ -13,11 +13,11 @@
#include "app/gtk_signal.h"
#include "chrome/browser/gtk/gtk_tree.h"
#include "chrome/browser/gtk/options/managed_prefs_banner_gtk.h"
-#include "chrome/browser/options_page_base.h"
#include "chrome/browser/prefs/pref_change_registrar.h"
#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/search_engines/template_url_model_observer.h"
#include "chrome/browser/shell_integration.h"
+#include "chrome/browser/ui/options/options_page_base.h"
#include "googleurl/src/gurl.h"
class AccessibleWidgetHelper;
diff --git a/chrome/browser/gtk/options/languages_page_gtk.cc b/chrome/browser/gtk/options/languages_page_gtk.cc
index eda179f..9bb8732 100644
--- a/chrome/browser/gtk/options/languages_page_gtk.cc
+++ b/chrome/browser/gtk/options/languages_page_gtk.cc
@@ -17,7 +17,7 @@
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/language_combobox_model.h"
#include "chrome/browser/language_order_table_model.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/spellcheck_common.h"
diff --git a/chrome/browser/gtk/options/languages_page_gtk.h b/chrome/browser/gtk/options/languages_page_gtk.h
index 81712be..5fb41bb 100644
--- a/chrome/browser/gtk/options/languages_page_gtk.h
+++ b/chrome/browser/gtk/options/languages_page_gtk.h
@@ -21,8 +21,8 @@
#include "base/gtest_prod_util.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/gtk/gtk_tree.h"
-#include "chrome/browser/options_page_base.h"
#include "chrome/browser/prefs/pref_member.h"
+#include "chrome/browser/ui/options/options_page_base.h"
class LanguageComboboxModel;
class LanguageOrderTableModel;
diff --git a/chrome/browser/gtk/options/languages_page_gtk_unittest.cc b/chrome/browser/gtk/options/languages_page_gtk_unittest.cc
index 453eea5..d861c35 100644
--- a/chrome/browser/gtk/options/languages_page_gtk_unittest.cc
+++ b/chrome/browser/gtk/options/languages_page_gtk_unittest.cc
@@ -6,6 +6,7 @@
#include <gtk/gtk.h>
+#include "base/message_loop.h"
#include "base/string_util.h"
#include "chrome/browser/language_combobox_model.h"
#include "chrome/browser/prefs/pref_service.h"
diff --git a/chrome/browser/gtk/options/options_window_gtk.cc b/chrome/browser/gtk/options/options_window_gtk.cc
index 8c7555c..c2e997e 100644
--- a/chrome/browser/gtk/options/options_window_gtk.cc
+++ b/chrome/browser/gtk/options/options_window_gtk.cc
@@ -2,17 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/options_window.h"
-
#include <gtk/gtk.h>
#include "app/l10n_util.h"
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/accessibility_events.h"
-#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_window.h"
#include "chrome/browser/gtk/accessible_widget_helper_gtk.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/gtk/options/advanced_page_gtk.h"
@@ -20,9 +16,11 @@
#include "chrome/browser/gtk/options/general_page_gtk.h"
#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/window_sizer.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/options/options_window.h"
+#include "chrome/browser/ui/window_sizer.h"
#include "chrome/common/pref_names.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/gtk/options/passwords_exceptions_page_gtk.cc b/chrome/browser/gtk/options/passwords_exceptions_page_gtk.cc
index d8f94b5..065d8f3 100644
--- a/chrome/browser/gtk/options/passwords_exceptions_page_gtk.cc
+++ b/chrome/browser/gtk/options/passwords_exceptions_page_gtk.cc
@@ -12,6 +12,7 @@
#include "chrome/browser/gtk/gtk_tree.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "gfx/gtk_util.h"
diff --git a/chrome/browser/gtk/options/passwords_exceptions_page_gtk.h b/chrome/browser/gtk/options/passwords_exceptions_page_gtk.h
index c25060a..0179501 100644
--- a/chrome/browser/gtk/options/passwords_exceptions_page_gtk.h
+++ b/chrome/browser/gtk/options/passwords_exceptions_page_gtk.h
@@ -12,7 +12,8 @@
#include "app/gtk_signal.h"
#include "chrome/browser/password_manager/password_store.h"
-#include "chrome/browser/profile.h"
+
+class Profile;
// A page in the show saved passwords dialog that lists what sites we never
// show passwords for, with controls for the user to add/remove sites from that
diff --git a/chrome/browser/gtk/options/passwords_exceptions_window_gtk.cc b/chrome/browser/gtk/options/passwords_exceptions_window_gtk.cc
index 33fa5b3..d516f58 100644
--- a/chrome/browser/gtk/options/passwords_exceptions_window_gtk.cc
+++ b/chrome/browser/gtk/options/passwords_exceptions_window_gtk.cc
@@ -10,13 +10,12 @@
#include "app/l10n_util.h"
#include "base/message_loop.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/gtk/accessible_widget_helper_gtk.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/gtk/options/passwords_exceptions_page_gtk.h"
#include "chrome/browser/gtk/options/passwords_page_gtk.h"
-#include "chrome/browser/options_window.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/options/options_window.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
diff --git a/chrome/browser/gtk/options/passwords_page_gtk.cc b/chrome/browser/gtk/options/passwords_page_gtk.cc
index 2051eb6..7a58f15 100644
--- a/chrome/browser/gtk/options/passwords_page_gtk.cc
+++ b/chrome/browser/gtk/options/passwords_page_gtk.cc
@@ -12,6 +12,7 @@
#include "chrome/browser/gtk/gtk_tree.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
diff --git a/chrome/browser/gtk/options/passwords_page_gtk.h b/chrome/browser/gtk/options/passwords_page_gtk.h
index 8d81689..d2f9ddf 100644
--- a/chrome/browser/gtk/options/passwords_page_gtk.h
+++ b/chrome/browser/gtk/options/passwords_page_gtk.h
@@ -8,14 +8,16 @@
#include <gtk/gtk.h>
+#include <string>
#include <vector>
#include "app/gtk_signal.h"
#include "chrome/browser/password_manager/password_store.h"
#include "chrome/browser/prefs/pref_member.h"
-#include "chrome/browser/profile.h"
#include "chrome/common/notification_observer.h"
+class Profile;
+
class PasswordsPageGtk : public NotificationObserver {
public:
explicit PasswordsPageGtk(Profile* profile);
@@ -38,9 +40,9 @@ class PasswordsPageGtk : public NotificationObserver {
void HidePassword();
// NotificationObserver implementation.
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
// Handles changes to the observed preferences and updates the UI.
void OnPrefChanged(const std::string& pref_name);
diff --git a/chrome/browser/gtk/options/url_picker_dialog_gtk.cc b/chrome/browser/gtk/options/url_picker_dialog_gtk.cc
index e9cef31..2d00873 100644
--- a/chrome/browser/gtk/options/url_picker_dialog_gtk.cc
+++ b/chrome/browser/gtk/options/url_picker_dialog_gtk.cc
@@ -14,7 +14,7 @@
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/possible_url_model.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "gfx/gtk_util.h"
#include "googleurl/src/gurl.h"
diff --git a/chrome/browser/gtk/overflow_button.cc b/chrome/browser/gtk/overflow_button.cc
index bd1e216..9397799 100644
--- a/chrome/browser/gtk/overflow_button.cc
+++ b/chrome/browser/gtk/overflow_button.cc
@@ -7,7 +7,7 @@
#include <gtk/gtk.h>
#include "app/resource_bundle.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
diff --git a/chrome/browser/gtk/overflow_button.h b/chrome/browser/gtk/overflow_button.h
index 647221e..66724f4 100644
--- a/chrome/browser/gtk/overflow_button.h
+++ b/chrome/browser/gtk/overflow_button.h
@@ -24,9 +24,9 @@ class OverflowButton : public NotificationObserver {
private:
// NotificationObserver implementation.
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
OwnedWidgetGtk widget_;
diff --git a/chrome/browser/gtk/reload_button_gtk.cc b/chrome/browser/gtk/reload_button_gtk.cc
index 6725dbb..9ee0e29 100644
--- a/chrome/browser/gtk/reload_button_gtk.cc
+++ b/chrome/browser/gtk/reload_button_gtk.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/gtk/reload_button_gtk.h"
+#include <algorithm>
+
#include "app/l10n_util.h"
#include "base/logging.h"
#include "chrome/app/chrome_command_ids.h"
@@ -12,7 +14,7 @@
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/gtk/location_bar_view_gtk.h"
#include "chrome/browser/ui/browser.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
diff --git a/chrome/browser/gtk/slide_animator_gtk.h b/chrome/browser/gtk/slide_animator_gtk.h
index dabdd70..8028367 100644
--- a/chrome/browser/gtk/slide_animator_gtk.h
+++ b/chrome/browser/gtk/slide_animator_gtk.h
@@ -83,8 +83,8 @@ class SlideAnimatorGtk : public AnimationDelegate {
bool IsAnimating();
// AnimationDelegate implementation.
- void AnimationProgressed(const Animation* animation);
- void AnimationEnded(const Animation* animation);
+ virtual void AnimationProgressed(const Animation* animation);
+ virtual void AnimationEnded(const Animation* animation);
// Used during testing; disable or enable animations (default is enabled).
static void SetAnimationsForTesting(bool enable);
diff --git a/chrome/browser/gtk/ssl_client_certificate_selector.cc b/chrome/browser/gtk/ssl_client_certificate_selector.cc
index 8e4077e..edf560a 100644
--- a/chrome/browser/gtk/ssl_client_certificate_selector.cc
+++ b/chrome/browser/gtk/ssl_client_certificate_selector.cc
@@ -246,7 +246,7 @@ std::string SSLClientCertificateSelector::FormatDetailsText(
rv += l10n_util::GetStringFUTF8(
IDS_CERT_SUBJECTNAME_FORMAT,
- UTF8ToUTF16(x509_certificate_model::GetSubjectName(cert)));;
+ UTF8ToUTF16(x509_certificate_model::GetSubjectName(cert)));
rv += "\n ";
rv += l10n_util::GetStringFUTF8(
@@ -256,10 +256,8 @@ std::string SSLClientCertificateSelector::FormatDetailsText(
base::Time issued, expires;
if (x509_certificate_model::GetTimes(cert, &issued, &expires)) {
- string16 issued_str = WideToUTF16(
- base::TimeFormatShortDateAndTime(issued));
- string16 expires_str = WideToUTF16(
- base::TimeFormatShortDateAndTime(expires));
+ string16 issued_str = base::TimeFormatShortDateAndTime(issued);
+ string16 expires_str = base::TimeFormatShortDateAndTime(expires);
rv += "\n ";
rv += l10n_util::GetStringFUTF8(IDS_CERT_VALIDITY_RANGE_FORMAT,
issued_str, expires_str);
diff --git a/chrome/browser/gtk/status_bubble_gtk.h b/chrome/browser/gtk/status_bubble_gtk.h
index b951b79..82253d4 100644
--- a/chrome/browser/gtk/status_bubble_gtk.h
+++ b/chrome/browser/gtk/status_bubble_gtk.h
@@ -15,7 +15,7 @@
#include "base/scoped_ptr.h"
#include "base/timer.h"
#include "chrome/browser/gtk/owned_widget_gtk.h"
-#include "chrome/browser/status_bubble.h"
+#include "chrome/browser/ui/status_bubble.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "gfx/point.h"
@@ -55,9 +55,9 @@ class StatusBubbleGtk : public StatusBubble,
virtual void UpdateDownloadShelfVisibility(bool visible);
// Overridden from NotificationObserver:
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
// Top of the widget hierarchy for a StatusBubble. This top level widget is
// guarenteed to have its gtk_widget_name set to "status-bubble" for
diff --git a/chrome/browser/gtk/tab_contents_container_gtk.cc b/chrome/browser/gtk/tab_contents_container_gtk.cc
index f74f90e..b189e81 100644
--- a/chrome/browser/gtk/tab_contents_container_gtk.cc
+++ b/chrome/browser/gtk/tab_contents_container_gtk.cc
@@ -4,13 +4,15 @@
#include "chrome/browser/gtk/tab_contents_container_gtk.h"
+#include <algorithm>
+
#include "base/i18n/rtl.h"
#include "chrome/browser/gtk/gtk_expanded_container.h"
#include "chrome/browser/gtk/gtk_floating_container.h"
#include "chrome/browser/gtk/status_bubble_gtk.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/renderer_host/render_widget_host_view_gtk.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
#include "gfx/native_widget_types.h"
TabContentsContainerGtk::TabContentsContainerGtk(StatusBubbleGtk* status_bubble)
@@ -152,7 +154,6 @@ void TabContentsContainerGtk::HideTabContents(TabContents* contents) {
gtk_widget_hide(widget);
contents->WasHidden();
-
}
void TabContentsContainerGtk::DetachTabContents(TabContents* tab_contents) {
diff --git a/chrome/browser/gtk/tabs/dragged_tab_controller_gtk.cc b/chrome/browser/gtk/tabs/dragged_tab_controller_gtk.cc
index 00546c6..a204b29 100644
--- a/chrome/browser/gtk/tabs/dragged_tab_controller_gtk.cc
+++ b/chrome/browser/gtk/tabs/dragged_tab_controller_gtk.cc
@@ -13,10 +13,10 @@
#include "chrome/browser/gtk/tabs/tab_strip_gtk.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "chrome/common/notification_source.h"
namespace {
@@ -409,6 +409,7 @@ void DraggedTabControllerGtk::Attach(TabStripGtk* attached_tabstrip,
}
DCHECK(tab); // We should now have a tab.
tab->SetVisible(false);
+ tab->set_dragging(true);
// TODO(jhawkins): Move the corresponding window to the front.
}
@@ -654,6 +655,7 @@ void DraggedTabControllerGtk::RevertDrag() {
ShowWindow();
source_tab_->SetVisible(true);
+ source_tab_->set_dragging(false);
}
bool DraggedTabControllerGtk::CompleteDrag() {
@@ -759,6 +761,7 @@ void DraggedTabControllerGtk::OnAnimateToBoundsComplete() {
TabGtk* tab = GetTabMatchingDraggedContents(attached_tabstrip_);
if (tab) {
tab->SetVisible(true);
+ tab->set_dragging(false);
// Paint the tab now, otherwise there may be slight flicker between the
// time the dragged tab window is destroyed and we paint.
tab->SchedulePaint();
diff --git a/chrome/browser/gtk/tabs/dragged_tab_controller_gtk.h b/chrome/browser/gtk/tabs/dragged_tab_controller_gtk.h
index 1802441..c421d69 100644
--- a/chrome/browser/gtk/tabs/dragged_tab_controller_gtk.h
+++ b/chrome/browser/gtk/tabs/dragged_tab_controller_gtk.h
@@ -13,8 +13,8 @@
#include "app/x11_util.h"
#include "base/scoped_ptr.h"
#include "base/timer.h"
-#include "chrome/browser/dock_info.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
+#include "chrome/browser/ui/tabs/dock_info.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
diff --git a/chrome/browser/gtk/tabs/dragged_tab_gtk.cc b/chrome/browser/gtk/tabs/dragged_tab_gtk.cc
index 9929f10..a1fda13 100644
--- a/chrome/browser/gtk/tabs/dragged_tab_gtk.cc
+++ b/chrome/browser/gtk/tabs/dragged_tab_gtk.cc
@@ -12,7 +12,7 @@
#include "base/i18n/rtl.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/gtk/tabs/tab_renderer_gtk.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/backing_store_x.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
diff --git a/chrome/browser/gtk/tabs/tab_gtk.cc b/chrome/browser/gtk/tabs/tab_gtk.cc
index b61c967..440084b 100644
--- a/chrome/browser/gtk/tabs/tab_gtk.cc
+++ b/chrome/browser/gtk/tabs/tab_gtk.cc
@@ -13,7 +13,7 @@
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/gtk/accelerators_gtk.h"
#include "chrome/browser/gtk/menu_gtk.h"
-#include "chrome/browser/tab_menu_model.h"
+#include "chrome/browser/ui/tabs/tab_menu_model.h"
#include "gfx/path.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
@@ -69,7 +69,7 @@ class TabGtk::ContextMenuController : public menus::SimpleMenuModel::Delegate,
&browser_command))
return false;
const menus::AcceleratorGtk* accelerator_gtk =
- Singleton<AcceleratorsGtk>()->GetPrimaryAcceleratorForCommand(
+ AcceleratorsGtk::GetInstance()->GetPrimaryAcceleratorForCommand(
browser_command);
if (accelerator_gtk)
*accelerator = *accelerator_gtk;
@@ -128,6 +128,7 @@ TabGtk::TabGtk(TabDelegate* delegate)
: TabRendererGtk(delegate->GetThemeProvider()),
delegate_(delegate),
closing_(false),
+ dragging_(false),
last_mouse_down_(NULL),
drag_widget_(NULL),
title_width_(0),
diff --git a/chrome/browser/gtk/tabs/tab_gtk.h b/chrome/browser/gtk/tabs/tab_gtk.h
index 586e306..804656e 100644
--- a/chrome/browser/gtk/tabs/tab_gtk.h
+++ b/chrome/browser/gtk/tabs/tab_gtk.h
@@ -94,6 +94,10 @@ class TabGtk : public TabRendererGtk,
void set_closing(bool closing) { closing_ = closing; }
bool closing() const { return closing_; }
+ // Used to set/check whether this Tab is being dragged.
+ void set_dragging(bool dragging) { dragging_ = dragging; }
+ bool dragging() const { return dragging_; }
+
// TabRendererGtk overrides:
virtual bool IsSelected() const;
virtual bool IsVisible() const;
@@ -164,6 +168,9 @@ class TabGtk : public TabRendererGtk,
// True if the tab is being animated closed.
bool closing_;
+ // True if the tab is being dragged.
+ bool dragging_;
+
// The context menu controller.
scoped_ptr<ContextMenuController> menu_controller_;
diff --git a/chrome/browser/gtk/tabs/tab_renderer_gtk.cc b/chrome/browser/gtk/tabs/tab_renderer_gtk.cc
index 5afd379..fc1f7c2 100644
--- a/chrome/browser/gtk/tabs/tab_renderer_gtk.cc
+++ b/chrome/browser/gtk/tabs/tab_renderer_gtk.cc
@@ -17,7 +17,7 @@
#include "chrome/browser/gtk/custom_button.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/gtk/gtk_util.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/notification_service.h"
diff --git a/chrome/browser/gtk/tabs/tab_strip_gtk.cc b/chrome/browser/gtk/tabs/tab_strip_gtk.cc
index 0960cec..4c307d8 100644
--- a/chrome/browser/gtk/tabs/tab_strip_gtk.cc
+++ b/chrome/browser/gtk/tabs/tab_strip_gtk.cc
@@ -12,19 +12,22 @@
#include "app/slide_animation.h"
#include "base/i18n/rtl.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autocomplete/autocomplete.h"
+#include "chrome/browser/autocomplete/autocomplete_classifier.h"
+#include "chrome/browser/autocomplete/autocomplete_match.h"
#include "chrome/browser/gtk/browser_window_gtk.h"
#include "chrome/browser/gtk/custom_button.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/gtk/tabs/dragged_tab_controller_gtk.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/tabs/tab_strip_model_delegate.h"
#include "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_navigator.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "gfx/gtk_util.h"
@@ -737,6 +740,7 @@ void TabStripGtk::Init() {
GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK));
static const int targets[] = { gtk_dnd_util::TEXT_URI_LIST,
gtk_dnd_util::NETSCAPE_URL,
+ gtk_dnd_util::TEXT_PLAIN,
-1 };
gtk_dnd_util::SetDestTargetList(tabstrip_.get(), targets);
@@ -777,6 +781,15 @@ void TabStripGtk::Hide() {
gtk_widget_hide(tabstrip_.get());
}
+bool TabStripGtk::IsActiveDropTarget() const {
+ for (int i = 0; i < GetTabCount(); ++i) {
+ TabGtk* tab = GetTabAt(i);
+ if (tab->dragging())
+ return true;
+ }
+ return false;
+}
+
void TabStripGtk::Layout() {
// Called from:
// - window resize
@@ -1603,7 +1616,7 @@ void TabStripGtk::SetDropIndex(int index, bool drop_before) {
drop_bounds.width(), drop_bounds.height());
}
-bool TabStripGtk::CompleteDrop(guchar* data) {
+bool TabStripGtk::CompleteDrop(guchar* data, bool is_plain_text) {
if (!drop_info_.get())
return false;
@@ -1613,8 +1626,17 @@ bool TabStripGtk::CompleteDrop(guchar* data) {
// Destroy the drop indicator.
drop_info_.reset();
- std::string url_string(reinterpret_cast<char*>(data));
- GURL url(url_string.substr(0, url_string.find_first_of('\n')));
+ GURL url;
+ if (is_plain_text) {
+ AutocompleteMatch match;
+ model_->profile()->GetAutocompleteClassifier()->Classify(
+ UTF8ToWide(reinterpret_cast<char*>(data)), std::wstring(), false,
+ &match, NULL);
+ url = match.destination_url;
+ } else {
+ std::string url_string(reinterpret_cast<char*>(data));
+ url = GURL(url_string.substr(0, url_string.find_first_of('\n')));
+ }
if (!url.is_valid())
return false;
@@ -1954,8 +1976,9 @@ gboolean TabStripGtk::OnDragDataReceived(GtkWidget* widget,
bool success = false;
if (info == gtk_dnd_util::TEXT_URI_LIST ||
- info == gtk_dnd_util::NETSCAPE_URL) {
- success = CompleteDrop(data->data);
+ info == gtk_dnd_util::NETSCAPE_URL ||
+ info == gtk_dnd_util::TEXT_PLAIN) {
+ success = CompleteDrop(data->data, info == gtk_dnd_util::TEXT_PLAIN);
}
gtk_drag_finish(context, success, success, time);
diff --git a/chrome/browser/gtk/tabs/tab_strip_gtk.h b/chrome/browser/gtk/tabs/tab_strip_gtk.h
index 0095ebe..20d9ee0 100644
--- a/chrome/browser/gtk/tabs/tab_strip_gtk.h
+++ b/chrome/browser/gtk/tabs/tab_strip_gtk.h
@@ -54,6 +54,9 @@ class TabStripGtk : public TabStripModelObserver,
// Returns true if there is an active drag session.
bool IsDragSessionActive() const { return drag_controller_.get() != NULL; }
+ // Returns true if a tab is being dragged into this tabstrip.
+ bool IsActiveDropTarget() const;
+
// Sets the bounds of the tabs.
void Layout();
@@ -363,7 +366,7 @@ class TabStripGtk : public TabStripModelObserver,
// Determines whether the data is acceptable by the tabstrip and opens a new
// tab with the data as URL if it is. Returns true if the drop was
// successful.
- bool CompleteDrop(guchar* data);
+ bool CompleteDrop(guchar* data, bool is_plain_text);
// Returns the image to use for indicating a drop on a tab. If is_down is
// true, this returns an arrow pointing down.
diff --git a/chrome/browser/gtk/task_manager_gtk.cc b/chrome/browser/gtk/task_manager_gtk.cc
index fcb9817..ccc5f73 100644
--- a/chrome/browser/gtk/task_manager_gtk.cc
+++ b/chrome/browser/gtk/task_manager_gtk.cc
@@ -476,10 +476,8 @@ void TaskManagerGtk::Init() {
CreateTaskManagerTreeview();
gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(treeview_), TRUE);
- g_signal_connect(treeview_, "button-press-event",
- G_CALLBACK(OnButtonPressEventThunk), this);
- gtk_widget_add_events(treeview_,
- GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
+ g_signal_connect(treeview_, "row-activated",
+ G_CALLBACK(OnRowActivatedThunk), this);
// |selection| is owned by |treeview_|.
GtkTreeSelection* selection = gtk_tree_view_get_selection(
@@ -780,25 +778,6 @@ void TaskManagerGtk::ShowContextMenu() {
}
#endif
-void TaskManagerGtk::ActivateFocusedTab() {
- GtkTreeSelection* selection = gtk_tree_view_get_selection(
- GTK_TREE_VIEW(treeview_));
-
- // If the user has just double clicked, only one item is selected.
- GtkTreeModel* model;
- GList* selected = gtk_tree_selection_get_selected_rows(selection, &model);
- if (selected) {
- GtkTreePath* path = gtk_tree_model_sort_convert_path_to_child_path(
- GTK_TREE_MODEL_SORT(process_list_sort_),
- reinterpret_cast<GtkTreePath*>(selected->data));
- int row = gtk_tree::GetRowNumForPath(path);
- gtk_tree_path_free(path);
- task_manager_->ActivateProcess(row);
- }
- g_list_foreach(selected, reinterpret_cast<GFunc>(gtk_tree_path_free), NULL);
- g_list_free(selected);
-}
-
void TaskManagerGtk::OnLinkActivated() {
task_manager_->OpenAboutMemory();
}
@@ -942,12 +921,14 @@ void TaskManagerGtk::OnSelectionChanged(GtkTreeSelection* selection) {
kTaskManagerResponseKill, sensitive);
}
-gboolean TaskManagerGtk::OnButtonPressEvent(GtkWidget* widget,
- GdkEventButton* event) {
- if (event->type == GDK_2BUTTON_PRESS)
- ActivateFocusedTab();
-
- return FALSE;
+void TaskManagerGtk::OnRowActivated(GtkWidget* widget,
+ GtkTreePath* path,
+ GtkTreeViewColumn* column) {
+ GtkTreePath* child_path = gtk_tree_model_sort_convert_path_to_child_path(
+ GTK_TREE_MODEL_SORT(process_list_sort_), path);
+ int row = gtk_tree::GetRowNumForPath(child_path);
+ gtk_tree_path_free(child_path);
+ task_manager_->ActivateProcess(row);
}
gboolean TaskManagerGtk::OnButtonReleaseEvent(GtkWidget* widget,
diff --git a/chrome/browser/gtk/task_manager_gtk.h b/chrome/browser/gtk/task_manager_gtk.h
index 75982e1..5aa5907 100644
--- a/chrome/browser/gtk/task_manager_gtk.h
+++ b/chrome/browser/gtk/task_manager_gtk.h
@@ -72,9 +72,6 @@ class TaskManagerGtk : public TaskManagerModelObserver {
void ShowContextMenu();
#endif
- // Activates the tab associated with the focused row.
- void ActivateFocusedTab();
-
// Opens about:memory in a new foreground tab.
void OnLinkActivated();
@@ -95,9 +92,10 @@ class TaskManagerGtk : public TaskManagerModelObserver {
CHROMEG_CALLBACK_0(TaskManagerGtk, void, OnSelectionChanged,
GtkTreeSelection*);
- // button-press-event handler that activates a process on double-click.
- CHROMEGTK_CALLBACK_1(TaskManagerGtk, gboolean, OnButtonPressEvent,
- GdkEventButton*);
+ // row-activated handler that foregrounds a process on activation (e.g.,
+ // double-click).
+ CHROMEGTK_CALLBACK_2(TaskManagerGtk, void, OnRowActivated,
+ GtkTreePath*, GtkTreeViewColumn*);
// button-release-event handler that opens the right-click context menu.
CHROMEGTK_CALLBACK_1(TaskManagerGtk, gboolean, OnButtonReleaseEvent,
diff --git a/chrome/browser/gtk/theme_install_bubble_view_gtk.cc b/chrome/browser/gtk/theme_install_bubble_view_gtk.cc
index 4708211..a08d393 100644
--- a/chrome/browser/gtk/theme_install_bubble_view_gtk.cc
+++ b/chrome/browser/gtk/theme_install_bubble_view_gtk.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// 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.
@@ -115,7 +115,7 @@ void ThemeInstallBubbleViewGtk::InitWidgets() {
if (composited) {
gtk_widget_set_app_paintable(widget_, TRUE);
g_signal_connect(widget_, "expose-event",
- G_CALLBACK(HandleExposeEventThunk), this);
+ G_CALLBACK(OnExposeThunk), this);
gtk_widget_realize(widget_);
} else {
gtk_widget_modify_bg(widget_, GTK_STATE_NORMAL, &gtk_util::kGdkBlack);
@@ -127,7 +127,7 @@ void ThemeInstallBubbleViewGtk::InitWidgets() {
MoveWindow();
g_signal_connect(widget_, "unmap-event",
- G_CALLBACK(&HandleParentUnmapThunk), this);
+ G_CALLBACK(OnUnmapEventThunk), this);
gtk_widget_show_all(widget_);
}
@@ -147,13 +147,13 @@ void ThemeInstallBubbleViewGtk::MoveWindow() {
gtk_window_move(GTK_WINDOW(widget_), x, y);
}
-gboolean ThemeInstallBubbleViewGtk::HandleParentUnmap() {
+gboolean ThemeInstallBubbleViewGtk::OnUnmapEvent(GtkWidget* widget) {
delete this;
return FALSE;
}
-gboolean ThemeInstallBubbleViewGtk::HandleExposeEvent(
- GdkEventExpose* event) {
+gboolean ThemeInstallBubbleViewGtk::OnExpose(GtkWidget* widget,
+ GdkEventExpose* event) {
cairo_t* cr = gdk_cairo_create(event->window);
gdk_cairo_rectangle(cr, &event->area);
cairo_clip(cr);
diff --git a/chrome/browser/gtk/theme_install_bubble_view_gtk.h b/chrome/browser/gtk/theme_install_bubble_view_gtk.h
index 17770a2..fe38690 100644
--- a/chrome/browser/gtk/theme_install_bubble_view_gtk.h
+++ b/chrome/browser/gtk/theme_install_bubble_view_gtk.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// 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.
@@ -8,6 +8,7 @@
#include <gtk/gtk.h>
+#include "app/gtk_signal.h"
#include "base/basictypes.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
@@ -35,23 +36,12 @@ class ThemeInstallBubbleViewGtk : public NotificationObserver {
void MoveWindow();
// Our parent is going down; self destruct.
- static gboolean HandleParentUnmapThunk(GtkWidget* widget,
- GdkEvent* event,
- gpointer user_data) {
- return reinterpret_cast<ThemeInstallBubbleViewGtk*>(user_data)->
- HandleParentUnmap();
- }
- gboolean HandleParentUnmap();
+ CHROMEGTK_CALLBACK_0(ThemeInstallBubbleViewGtk, gboolean, OnUnmapEvent);
// Draw the background. This is only signalled if we are using a compositing
// window manager, otherwise we just use ActAsRoundedWindow().
- static gboolean HandleExposeEventThunk(GtkWidget* widget,
- GdkEventExpose* event,
- gpointer user_data) {
- return reinterpret_cast<ThemeInstallBubbleViewGtk*>(user_data)->
- HandleExposeEvent(event);
- }
- gboolean HandleExposeEvent(GdkEventExpose* event);
+ CHROMEGTK_CALLBACK_1(ThemeInstallBubbleViewGtk, gboolean,
+ OnExpose, GdkEventExpose*);
GtkWidget* widget_;
diff --git a/chrome/browser/gtk/translate/after_translate_infobar_gtk.cc b/chrome/browser/gtk/translate/after_translate_infobar_gtk.cc
index 914f2ca..3f36ca6 100644
--- a/chrome/browser/gtk/translate/after_translate_infobar_gtk.cc
+++ b/chrome/browser/gtk/translate/after_translate_infobar_gtk.cc
@@ -64,6 +64,10 @@ void AfterTranslateInfoBar::Init() {
gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
}
+bool AfterTranslateInfoBar::ShowOptionsMenuButton() const {
+ return true;
+}
+
void AfterTranslateInfoBar::OnOriginalLanguageModified(GtkWidget* sender) {
int index = GetLanguageComboboxActiveId(GTK_COMBO_BOX(sender));
if (index == GetDelegate()->original_language_index())
diff --git a/chrome/browser/gtk/translate/after_translate_infobar_gtk.h b/chrome/browser/gtk/translate/after_translate_infobar_gtk.h
index bd870be..4f49ffd 100644
--- a/chrome/browser/gtk/translate/after_translate_infobar_gtk.h
+++ b/chrome/browser/gtk/translate/after_translate_infobar_gtk.h
@@ -20,7 +20,7 @@ class AfterTranslateInfoBar : public TranslateInfoBarBase {
virtual void Init();
protected:
- virtual bool ShowOptionsMenuButton() const { return true; }
+ virtual bool ShowOptionsMenuButton() const;
private:
CHROMEGTK_CALLBACK_0(AfterTranslateInfoBar, void, OnOriginalLanguageModified);
diff --git a/chrome/browser/gtk/translate/before_translate_infobar_gtk.cc b/chrome/browser/gtk/translate/before_translate_infobar_gtk.cc
index 75c668e..01a94ff 100644
--- a/chrome/browser/gtk/translate/before_translate_infobar_gtk.cc
+++ b/chrome/browser/gtk/translate/before_translate_infobar_gtk.cc
@@ -75,6 +75,10 @@ void BeforeTranslateInfoBar::Init() {
}
}
+bool BeforeTranslateInfoBar::ShowOptionsMenuButton() const {
+ return true;
+}
+
void BeforeTranslateInfoBar::OnLanguageModified(GtkWidget* sender) {
int index = GetLanguageComboboxActiveId(GTK_COMBO_BOX(sender));
if (index == GetDelegate()->original_language_index())
diff --git a/chrome/browser/gtk/translate/before_translate_infobar_gtk.h b/chrome/browser/gtk/translate/before_translate_infobar_gtk.h
index 1373247..e6ff5a9 100644
--- a/chrome/browser/gtk/translate/before_translate_infobar_gtk.h
+++ b/chrome/browser/gtk/translate/before_translate_infobar_gtk.h
@@ -19,7 +19,7 @@ class BeforeTranslateInfoBar : public TranslateInfoBarBase {
virtual void Init();
protected:
- virtual bool ShowOptionsMenuButton() const { return true; }
+ virtual bool ShowOptionsMenuButton() const;
private:
CHROMEGTK_CALLBACK_0(BeforeTranslateInfoBar, void, OnLanguageModified);
diff --git a/chrome/browser/gtk/translate/translate_infobar_base_gtk.cc b/chrome/browser/gtk/translate/translate_infobar_base_gtk.cc
index 530d215..5560662 100644
--- a/chrome/browser/gtk/translate/translate_infobar_base_gtk.cc
+++ b/chrome/browser/gtk/translate/translate_infobar_base_gtk.cc
@@ -124,6 +124,10 @@ void TranslateInfoBarBase::AnimationProgressed(const Animation* animation) {
gtk_widget_queue_draw(widget());
}
+bool TranslateInfoBarBase::ShowOptionsMenuButton() const {
+ return false;
+}
+
GtkWidget* TranslateInfoBarBase::CreateLabel(const std::string& text) {
GtkWidget* label = gtk_label_new(text.c_str());
gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &gtk_util::kGdkBlack);
diff --git a/chrome/browser/gtk/translate/translate_infobar_base_gtk.h b/chrome/browser/gtk/translate/translate_infobar_base_gtk.h
index 8b2303b..ae147ca 100644
--- a/chrome/browser/gtk/translate/translate_infobar_base_gtk.h
+++ b/chrome/browser/gtk/translate/translate_infobar_base_gtk.h
@@ -43,7 +43,7 @@ class TranslateInfoBarBase : public TranslateInfoBarView,
protected:
// Sub-classes that want to have the options menu button showing sould
// override and return true.
- virtual bool ShowOptionsMenuButton() const { return false; }
+ virtual bool ShowOptionsMenuButton() const;
// Creates a label with the appropriate font and color for the translate
// infobars.
diff --git a/chrome/browser/gtk/view_id_util.h b/chrome/browser/gtk/view_id_util.h
index c4833ad..0be817e 100644
--- a/chrome/browser/gtk/view_id_util.h
+++ b/chrome/browser/gtk/view_id_util.h
@@ -6,7 +6,7 @@
#define CHROME_BROWSER_GTK_VIEW_ID_UTIL_H_
#pragma once
-#include "chrome/browser/view_ids.h"
+#include "chrome/browser/ui/view_ids.h"
typedef struct _GtkWidget GtkWidget;
diff --git a/chrome/browser/guid.cc b/chrome/browser/guid.cc
deleted file mode 100644
index b8f46db..0000000
--- a/chrome/browser/guid.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// 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.
-
-#include "chrome/browser/guid.h"
-
-#include "base/rand_util.h"
-#include "base/stringprintf.h"
-
-namespace guid {
-
-bool IsValidGUID(const std::string& guid) {
- const size_t kGUIDLength = 36U;
- if (guid.length() != kGUIDLength)
- return false;
-
- std::string hexchars = "0123456789ABCDEF";
- for (uint32 i = 0; i < guid.length(); ++i) {
- char current = guid[i];
- if (i == 8 || i == 13 || i == 18 || i == 23) {
- if (current != '-')
- return false;
- } else {
- if (hexchars.find(current) == std::string::npos)
- return false;
- }
- }
-
- return true;
-}
-
-} // namespace guid
diff --git a/chrome/browser/guid.h b/chrome/browser/guid.h
deleted file mode 100644
index b5aa67d..0000000
--- a/chrome/browser/guid.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_GUID_H_
-#define CHROME_BROWSER_GUID_H_
-#pragma once
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "build/build_config.h"
-
-namespace guid {
-
-// Generate a 128-bit random GUID of the form: "%08X-%04X-%04X-%04X-%012llX".
-// If GUID generation fails an empty string is returned.
-// The POSIX implementation uses psuedo random number generation to create
-// the GUID. The Windows implementation uses system services.
-std::string GenerateGUID();
-
-// Returns true if the input string conforms to the GUID format.
-bool IsValidGUID(const std::string& guid);
-
-#if defined(OS_POSIX)
-// For unit testing purposes only. Do not use outside of tests.
-std::string RandomDataToGUIDString(const uint64 bytes[2]);
-#endif
-
-} // namespace guid
-
-#endif // CHROME_BROWSER_GUID_H_
diff --git a/chrome/browser/guid_posix.cc b/chrome/browser/guid_posix.cc
deleted file mode 100644
index 48d7198..0000000
--- a/chrome/browser/guid_posix.cc
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) 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.
-
-#include "chrome/browser/guid.h"
-
-#include "base/rand_util.h"
-#include "base/stringprintf.h"
-
-namespace guid {
-
-std::string GenerateGUID() {
- uint64 sixteen_bytes[2] = { base::RandUint64(), base::RandUint64() };
- return RandomDataToGUIDString(sixteen_bytes);
-}
-
-// TODO(cmasone): Once we're comfortable this works, migrate Windows code to
-// use this as well.
-std::string RandomDataToGUIDString(const uint64 bytes[2]) {
- return StringPrintf("%08X-%04X-%04X-%04X-%012llX",
- static_cast<unsigned int>(bytes[0] >> 32),
- static_cast<unsigned int>((bytes[0] >> 16) & 0x0000ffff),
- static_cast<unsigned int>(bytes[0] & 0x0000ffff),
- static_cast<unsigned int>(bytes[1] >> 48),
- bytes[1] & 0x0000ffffffffffffULL);
-}
-
-} // namespace guid
diff --git a/chrome/browser/guid_unittest.cc b/chrome/browser/guid_unittest.cc
deleted file mode 100644
index 1951ca1..0000000
--- a/chrome/browser/guid_unittest.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// 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.
-
-#include "chrome/browser/guid.h"
-
-#include <limits>
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-#if defined(OS_POSIX)
-TEST(GUIDTest, GUIDGeneratesAllZeroes) {
- uint64 bytes[] = { 0, 0 };
- std::string clientid = guid::RandomDataToGUIDString(bytes);
- EXPECT_EQ("00000000-0000-0000-0000-000000000000", clientid);
-}
-
-TEST(GUIDTest, GUIDGeneratesCorrectly) {
- uint64 bytes[] = { 0x0123456789ABCDEFULL, 0xFEDCBA9876543210ULL };
- std::string clientid = guid::RandomDataToGUIDString(bytes);
- EXPECT_EQ("01234567-89AB-CDEF-FEDC-BA9876543210", clientid);
-}
-#endif
-
-TEST(GUIDTest, GUIDCorrectlyFormatted) {
- const int kIterations = 10;
- for (int it = 0; it < kIterations; ++it) {
- std::string guid = guid::GenerateGUID();
- EXPECT_TRUE(guid::IsValidGUID(guid));
- }
-}
-
-TEST(GUIDTest, GUIDBasicUniqueness) {
- const int kIterations = 10;
- for (int it = 0; it < kIterations; ++it) {
- std::string guid1 = guid::GenerateGUID();
- std::string guid2 = guid::GenerateGUID();
- EXPECT_EQ(36U, guid1.length());
- EXPECT_EQ(36U, guid2.length());
- EXPECT_NE(guid1, guid2);
- }
-}
diff --git a/chrome/browser/guid_win.cc b/chrome/browser/guid_win.cc
deleted file mode 100644
index 115e806..0000000
--- a/chrome/browser/guid_win.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 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.
-
-#include "chrome/browser/guid.h"
-
-#include <stdlib.h>
-
-#include <objbase.h>
-#include <windows.h>
-
-#include "base/basictypes.h"
-#include "base/logging.h"
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-
-namespace guid {
-
-std::string GenerateGUID() {
- const int kGUIDSize = 39;
-
- GUID guid;
- HRESULT guid_result = CoCreateGuid(&guid);
- DCHECK(SUCCEEDED(guid_result));
- if (!SUCCEEDED(guid_result))
- return std::string();
-
- std::wstring guid_string;
- int result = StringFromGUID2(guid,
- WriteInto(&guid_string, kGUIDSize), kGUIDSize);
- DCHECK(result == kGUIDSize);
- if (result != kGUIDSize)
- return std::string();
-
- return WideToUTF8(guid_string.substr(1, guid_string.length() - 2));
-}
-
-} // namespace guid
diff --git a/chrome/browser/hang_monitor/hung_plugin_action.cc b/chrome/browser/hang_monitor/hung_plugin_action.cc
index 8399464..9b719ca 100644
--- a/chrome/browser/hang_monitor/hung_plugin_action.cc
+++ b/chrome/browser/hang_monitor/hung_plugin_action.cc
@@ -12,7 +12,7 @@
#include "chrome/browser/platform_util.h"
#include "chrome/common/logging_chrome.h"
#include "grit/generated_resources.h"
-#include "webkit/glue/plugins/webplugin_delegate_impl.h"
+#include "webkit/plugins/npapi/webplugin_delegate_impl.h"
HungPluginAction::HungPluginAction() : current_hung_plugin_window_(NULL) {
}
@@ -122,8 +122,8 @@ bool HungPluginAction::GetPluginName(HWND plugin_window,
// we have gone too far.
return false;
}
- if (WebPluginDelegateImpl::GetPluginNameFromWindow(window_to_check,
- plugin_name)) {
+ if (webkit::npapi::WebPluginDelegateImpl::GetPluginNameFromWindow(
+ window_to_check, plugin_name)) {
return true;
}
window_to_check = GetParent(window_to_check);
diff --git a/chrome/browser/history/download_create_info.cc b/chrome/browser/history/download_create_info.cc
index 67ffdc7..d1ea28e 100644
--- a/chrome/browser/history/download_create_info.cc
+++ b/chrome/browser/history/download_create_info.cc
@@ -15,7 +15,8 @@ DownloadCreateInfo::DownloadCreateInfo(const FilePath& path,
int64 received_bytes,
int64 total_bytes,
int32 state,
- int32 download_id)
+ int32 download_id,
+ bool has_user_gesture)
: path(path),
url(url),
path_uniquifier(0),
@@ -24,6 +25,7 @@ DownloadCreateInfo::DownloadCreateInfo(const FilePath& path,
total_bytes(total_bytes),
state(state),
download_id(download_id),
+ has_user_gesture(has_user_gesture),
child_id(-1),
render_view_id(-1),
request_id(-1),
@@ -39,6 +41,7 @@ DownloadCreateInfo::DownloadCreateInfo()
total_bytes(0),
state(-1),
download_id(-1),
+ has_user_gesture(false),
child_id(-1),
render_view_id(-1),
request_id(-1),
@@ -54,7 +57,7 @@ DownloadCreateInfo::~DownloadCreateInfo() {
std::string DownloadCreateInfo::DebugString() const {
return base::StringPrintf("{"
" url_ = \"%s\""
- " path = \"%s\""
+ " path = \"%" PRFilePath "\""
" received_bytes = %" PRId64
" total_bytes = %" PRId64
" child_id = %d"
diff --git a/chrome/browser/history/download_create_info.h b/chrome/browser/history/download_create_info.h
index b995b0b..49ac635 100644
--- a/chrome/browser/history/download_create_info.h
+++ b/chrome/browser/history/download_create_info.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// 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.
//
@@ -27,7 +27,8 @@ struct DownloadCreateInfo {
int64 received_bytes,
int64 total_bytes,
int32 state,
- int32 download_id);
+ int32 download_id,
+ bool has_user_gesture);
DownloadCreateInfo();
~DownloadCreateInfo();
@@ -46,6 +47,7 @@ struct DownloadCreateInfo {
int64 total_bytes;
int32 state;
int32 download_id;
+ bool has_user_gesture;
int child_id;
int render_view_id;
int request_id;
diff --git a/chrome/browser/history/expire_history_backend_unittest.cc b/chrome/browser/history/expire_history_backend_unittest.cc
index 3177dde..161a086 100644
--- a/chrome/browser/history/expire_history_backend_unittest.cc
+++ b/chrome/browser/history/expire_history_backend_unittest.cc
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <string>
+#include <utility>
+
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/file_path.h"
@@ -12,6 +15,7 @@
#include "base/string16.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/browser_thread.h"
#include "chrome/browser/history/archived_database.h"
#include "chrome/browser/history/expire_history_backend.h"
#include "chrome/browser/history/history_database.h"
@@ -19,7 +23,6 @@
#include "chrome/browser/history/text_database_manager.h"
#include "chrome/browser/history/thumbnail_database.h"
#include "chrome/browser/history/top_sites.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/thumbnail_score.h"
#include "chrome/test/testing_profile.h"
#include "chrome/tools/profiles/thumbnail-inl.h"
diff --git a/chrome/browser/history/history.cc b/chrome/browser/history/history.cc
index 53a5420..0736fc2 100644
--- a/chrome/browser/history/history.cc
+++ b/chrome/browser/history/history.cc
@@ -43,8 +43,8 @@
#include "chrome/browser/history/in_memory_history_backend.h"
#include "chrome/browser/history/top_sites.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/visitedlink_master.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/visitedlink/visitedlink_master.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
@@ -357,6 +357,14 @@ void HistoryService::AddPage(const history::HistoryAddPageArgs& add_page_args) {
add_page_args.Clone()));
}
+void HistoryService::AddPageNoVisitForBookmark(const GURL& url) {
+ if (!CanAddURL(url))
+ return;
+
+ ScheduleAndForget(PRIORITY_NORMAL,
+ &HistoryBackend::AddPageNoVisitForBookmark, url);
+}
+
void HistoryService::SetPageTitle(const GURL& url,
const string16& title) {
ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::SetPageTitle, url, title);
diff --git a/chrome/browser/history/history.h b/chrome/browser/history/history.h
index 3fe34ba..3e604e6 100644
--- a/chrome/browser/history/history.h
+++ b/chrome/browser/history/history.h
@@ -212,6 +212,11 @@ class HistoryService : public CancelableRequestProvider,
// All AddPage variants end up here.
void AddPage(const history::HistoryAddPageArgs& add_page_args);
+ // Adds an entry for the specified url without creating a visit. This should
+ // only be used when bookmarking a page, otherwise the row leaks in the
+ // history db (it never gets cleaned).
+ void AddPageNoVisitForBookmark(const GURL& url);
+
// Sets the title for the given page. The page should be in history. If it
// is not, this operation is ignored. This call will not update the full
// text index. The last title set when the page is indexed will be the
diff --git a/chrome/browser/history/history_backend.cc b/chrome/browser/history/history_backend.cc
index 0bf6045..cd0a40b 100644
--- a/chrome/browser/history/history_backend.cc
+++ b/chrome/browser/history/history_backend.cc
@@ -870,6 +870,23 @@ void HistoryBackend::SetPageTitle(const GURL& url,
ScheduleCommit();
}
+void HistoryBackend::AddPageNoVisitForBookmark(const GURL& url) {
+ if (!db_.get())
+ return;
+
+ URLRow url_info(url);
+ URLID url_id = db_->GetRowForURL(url, &url_info);
+ if (url_id) {
+ // URL is already known, nothing to do.
+ return;
+ }
+ url_info.set_last_visit(Time::Now());
+ // Mark the page hidden. If the user types it in, it'll unhide.
+ url_info.set_hidden(true);
+
+ db_->AddURL(url_info);
+}
+
void HistoryBackend::IterateURLs(HistoryService::URLEnumerator* iterator) {
if (db_.get()) {
HistoryDatabase::URLEnumerator e;
diff --git a/chrome/browser/history/history_backend.h b/chrome/browser/history/history_backend.h
index 54cbf29..4ce7aea 100644
--- a/chrome/browser/history/history_backend.h
+++ b/chrome/browser/history/history_backend.h
@@ -121,6 +121,7 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
void AddPage(scoped_refptr<HistoryAddPageArgs> request);
virtual void SetPageTitle(const GURL& url, const string16& title);
+ void AddPageNoVisitForBookmark(const GURL& url);
// Indexing ------------------------------------------------------------------
@@ -453,8 +454,8 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
// Schedules a broadcast of the given notification on the main thread. The
// details argument will have ownership taken by this function (it will be
// sent to the main thread and deleted there).
- void BroadcastNotifications(NotificationType type,
- HistoryDetails* details_deleted);
+ virtual void BroadcastNotifications(NotificationType type,
+ HistoryDetails* details_deleted);
// Deleting all history ------------------------------------------------------
diff --git a/chrome/browser/history/history_backend_unittest.cc b/chrome/browser/history/history_backend_unittest.cc
index ad16e9c..a3b2c86 100644
--- a/chrome/browser/history/history_backend_unittest.cc
+++ b/chrome/browser/history/history_backend_unittest.cc
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <set>
+#include <vector>
+
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/command_line.h"
@@ -19,7 +22,8 @@
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/thumbnail_score.h"
#include "chrome/tools/profiles/thumbnail-inl.h"
#include "gfx/codec/jpeg_codec.h"
diff --git a/chrome/browser/history/history_browsertest.cc b/chrome/browser/history/history_browsertest.cc
index d06aaf8..7075b16 100644
--- a/chrome/browser/history/history_browsertest.cc
+++ b/chrome/browser/history/history_browsertest.cc
@@ -4,9 +4,11 @@
#include <vector>
+#include "base/message_loop.h"
+#include "chrome/browser/browser_thread.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/in_process_browser_test.h"
@@ -108,7 +110,7 @@ class HistoryBrowserTest : public InProcessBrowserTest {
FROM_HERE,
NewRunnableMethod(history,
&HistoryService::ScheduleDBTask,
- task.get(),
+ task,
&request_consumer));
ui_test_utils::RunMessageLoop();
}
diff --git a/chrome/browser/history/history_publisher_win.cc b/chrome/browser/history/history_publisher_win.cc
index ec8525b..4aeb333 100644
--- a/chrome/browser/history/history_publisher_win.cc
+++ b/chrome/browser/history/history_publisher_win.cc
@@ -119,7 +119,7 @@ void HistoryPublisher::PublishDataToIndexers(const PageData& page_data)
}
// Send data to registered indexers.
- ScopedVariant time(var_time, VT_DATE);
+ base::win::ScopedVariant time(var_time, VT_DATE);
ScopedBstr url(ASCIIToWide(page_data.url.spec()).c_str());
ScopedBstr html(page_data.html);
ScopedBstr title(page_data.title);
@@ -127,7 +127,7 @@ void HistoryPublisher::PublishDataToIndexers(const PageData& page_data)
ScopedBstr format(page_data.thumbnail_format ?
ASCIIToWide(page_data.thumbnail_format).c_str() :
NULL);
- ScopedVariant psa(thumbnail_arr.m_psa);
+ base::win::ScopedVariant psa(thumbnail_arr.m_psa);
for (size_t i = 0; i < indexers_.size(); ++i) {
indexers_[i]->SendPageData(time, url, html, title, format, psa);
}
@@ -136,8 +136,10 @@ void HistoryPublisher::PublishDataToIndexers(const PageData& page_data)
void HistoryPublisher::DeleteUserHistoryBetween(const base::Time& begin_time,
const base::Time& end_time)
const {
- ScopedVariant var_begin_time(TimeToUTCVariantTime(begin_time), VT_DATE);
- ScopedVariant var_end_time(TimeToUTCVariantTime(end_time), VT_DATE);
+ base::win::ScopedVariant var_begin_time(TimeToUTCVariantTime(begin_time),
+ VT_DATE);
+ base::win::ScopedVariant var_end_time(TimeToUTCVariantTime(end_time),
+ VT_DATE);
for (size_t i = 0; i < indexers_.size(); ++i) {
indexers_[i]->DeleteUserHistoryBetween(var_begin_time, var_end_time);
}
diff --git a/chrome/browser/history/history_types.cc b/chrome/browser/history/history_types.cc
index eebe5a7..05d9a72 100644
--- a/chrome/browser/history/history_types.cc
+++ b/chrome/browser/history/history_types.cc
@@ -60,8 +60,8 @@ void URLRow::Swap(URLRow* other) {
void URLRow::Initialize() {
id_ = 0;
- visit_count_ = false;
- typed_count_ = false;
+ visit_count_ = 0;
+ typed_count_ = 0;
last_visit_ = Time();
hidden_ = false;
favicon_id_ = 0;
@@ -335,6 +335,12 @@ Images::Images() {}
Images::~Images() {}
+// TopSitesDelta --------------------------------------------------------------
+
+TopSitesDelta::TopSitesDelta() {}
+
+TopSitesDelta::~TopSitesDelta() {}
+
// HistoryAddPageArgs ---------------------------------------------------------
HistoryAddPageArgs::HistoryAddPageArgs(
@@ -366,7 +372,12 @@ HistoryAddPageArgs* HistoryAddPageArgs::Clone() const {
visit_source, did_replace_entry);
}
-MostVisitedThumbnails::MostVisitedThumbnails() {
-}
+ThumbnailMigration::ThumbnailMigration() {}
+
+ThumbnailMigration::~ThumbnailMigration() {}
+
+MostVisitedThumbnails::MostVisitedThumbnails() {}
+
+MostVisitedThumbnails::~MostVisitedThumbnails() {}
} // namespace history
diff --git a/chrome/browser/history/history_types.h b/chrome/browser/history/history_types.h
index 536064a..bc28dd1 100644
--- a/chrome/browser/history/history_types.h
+++ b/chrome/browser/history/history_types.h
@@ -610,6 +610,9 @@ struct MostVisitedURLWithRank {
typedef std::vector<MostVisitedURLWithRank> MostVisitedURLWithRankList;
struct TopSitesDelta {
+ TopSitesDelta();
+ ~TopSitesDelta();
+
MostVisitedURLList deleted;
MostVisitedURLWithRankList added;
MostVisitedURLWithRankList moved;
@@ -619,6 +622,9 @@ typedef std::map<GURL, scoped_refptr<RefCountedBytes> > URLToThumbnailMap;
// Used when migrating most visited thumbnails out of history and into topsites.
struct ThumbnailMigration {
+ ThumbnailMigration();
+ ~ThumbnailMigration();
+
MostVisitedURLList most_visited;
URLToThumbnailMap url_to_thumbnail_map;
};
@@ -629,6 +635,7 @@ class MostVisitedThumbnails
: public base::RefCountedThreadSafe<MostVisitedThumbnails> {
public:
MostVisitedThumbnails();
+ virtual ~MostVisitedThumbnails();
MostVisitedURLList most_visited;
URLToImagesMap url_to_images_map;
diff --git a/chrome/browser/history/history_unittest.cc b/chrome/browser/history/history_unittest.cc
index 1cc560e..e139cdd 100644
--- a/chrome/browser/history/history_unittest.cc
+++ b/chrome/browser/history/history_unittest.cc
@@ -18,7 +18,9 @@
// to run.
#include <time.h>
+
#include <algorithm>
+#include <string>
#include "app/sql/connection.h"
#include "app/sql/statement.h"
@@ -34,7 +36,6 @@
#include "base/string_util.h"
#include "base/task.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/download/download_item.h"
#include "chrome/browser/history/download_create_info.h"
#include "chrome/browser/history/history.h"
@@ -47,7 +48,8 @@
#include "chrome/browser/history/top_sites.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/thumbnail_score.h"
#include "chrome/tools/profiles/thumbnail-inl.h"
#include "gfx/codec/jpeg_codec.h"
@@ -198,7 +200,7 @@ class HistoryTest : public testing::Test {
int64 AddDownload(int32 state, const Time& time) {
DownloadCreateInfo download(FilePath(FILE_PATH_LITERAL("foo-path")),
- GURL("foo-url"), time, 0, 512, state, 0);
+ GURL("foo-url"), time, 0, 512, state, 0, false);
return db_->CreateDownload(download);
}
diff --git a/chrome/browser/history/in_memory_history_backend.cc b/chrome/browser/history/in_memory_history_backend.cc
index be82f58..978c8c4 100644
--- a/chrome/browser/history/in_memory_history_backend.cc
+++ b/chrome/browser/history/in_memory_history_backend.cc
@@ -4,6 +4,9 @@
#include "chrome/browser/history/in_memory_history_backend.h"
+#include <set>
+#include <vector>
+
#include "base/command_line.h"
#include "base/metrics/histogram.h"
#include "base/time.h"
@@ -14,9 +17,10 @@
#include "chrome/browser/history/in_memory_url_index.h"
#include "chrome/browser/history/url_database.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/pref_names.h"
namespace history {
diff --git a/chrome/browser/history/in_memory_url_index.cc b/chrome/browser/history/in_memory_url_index.cc
index 98c2acd..62a22e6 100644
--- a/chrome/browser/history/in_memory_url_index.cc
+++ b/chrome/browser/history/in_memory_url_index.cc
@@ -8,7 +8,7 @@
#include <limits>
#include "app/l10n_util.h"
-#include "base/i18n/word_iterator.h"
+#include "base/i18n/break_iterator.h"
#include "base/string_util.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
@@ -16,6 +16,7 @@
#include "chrome/browser/history/url_database.h"
#include "net/base/escape.h"
#include "net/base/net_util.h"
+#include "unicode/utypes.h" // for int32_t
using base::Time;
using base::TimeDelta;
@@ -233,11 +234,11 @@ InMemoryURLIndex::HistoryIDSet InMemoryURLIndex::HistoryIDsForTerm(
InMemoryURLIndex::String16Set InMemoryURLIndex::WordSetFromString16(
const string16& uni_string) {
String16Set words;
- WordIterator iter(&uni_string, WordIterator::BREAK_WORD);
+ base::BreakIterator iter(&uni_string, base::BreakIterator::BREAK_WORD);
if (iter.Init()) {
while (iter.Advance()) {
if (iter.IsWord())
- words.insert(iter.GetWord());
+ words.insert(iter.GetString());
}
}
return words;
diff --git a/chrome/browser/history/multipart_uitest.cc b/chrome/browser/history/multipart_uitest.cc
index 036cd96..34d7625 100644
--- a/chrome/browser/history/multipart_uitest.cc
+++ b/chrome/browser/history/multipart_uitest.cc
@@ -16,18 +16,11 @@ namespace {
class MultipartResponseUITest : public UITest {
};
-// http://crbug.com/50060
-#if defined(OS_MACOSX)
-#define MAYBE_SingleVisit DISABLED_SingleVisit
-#else
-#define MAYBE_SingleVisit SingleVisit
-#endif
-
#if defined(NDEBUG)
// http://code.google.com/p/chromium/issues/detail?id=37746
// Running this test only for release builds as it fails in debug test
// runs
-TEST_F(MultipartResponseUITest, MAYBE_SingleVisit) {
+TEST_F(MultipartResponseUITest, SingleVisit) {
// Make sure that visiting a multipart/x-mixed-replace site only
// creates one entry in the visits table.
net::TestServer test_server(net::TestServer::TYPE_HTTP,
diff --git a/chrome/browser/history/query_parser.cc b/chrome/browser/history/query_parser.cc
index e1afb86..12ecc29 100644
--- a/chrome/browser/history/query_parser.cc
+++ b/chrome/browser/history/query_parser.cc
@@ -7,7 +7,7 @@
#include <algorithm>
#include "app/l10n_util.h"
-#include "base/i18n/word_iterator.h"
+#include "base/i18n/break_iterator.h"
#include "base/logging.h"
#include "base/scoped_vector.h"
#include "base/string_util.h"
@@ -322,7 +322,7 @@ bool QueryParser::DoesQueryMatch(const string16& text,
bool QueryParser::ParseQueryImpl(const string16& query,
QueryNodeList* root) {
- WordIterator iter(&query, WordIterator::BREAK_WORD);
+ base::BreakIterator iter(&query, base::BreakIterator::BREAK_WORD);
// TODO(evanm): support a locale here
if (!iter.Init())
return false;
@@ -338,7 +338,7 @@ bool QueryParser::ParseQueryImpl(const string16& query,
// is not necessarily a word, but could also be a sequence of punctuation
// or whitespace.
if (iter.IsWord()) {
- string16 word = iter.GetWord();
+ string16 word = iter.GetString();
QueryNodeWord* word_node = new QueryNodeWord(word);
if (in_quotes)
@@ -365,7 +365,7 @@ bool QueryParser::ParseQueryImpl(const string16& query,
void QueryParser::ExtractQueryWords(const string16& text,
std::vector<QueryWord>* words) {
- WordIterator iter(&text, WordIterator::BREAK_WORD);
+ base::BreakIterator iter(&text, base::BreakIterator::BREAK_WORD);
// TODO(evanm): support a locale here
if (!iter.Init())
return;
@@ -375,7 +375,7 @@ void QueryParser::ExtractQueryWords(const string16& text,
// is not necessarily a word, but could also be a sequence of punctuation
// or whitespace.
if (iter.IsWord()) {
- string16 word = iter.GetWord();
+ string16 word = iter.GetString();
if (!word.empty()) {
words->push_back(QueryWord());
words->back().word = word;
diff --git a/chrome/browser/history/redirect_uitest.cc b/chrome/browser/history/redirect_uitest.cc
index 91b7317..1dbadcc 100644
--- a/chrome/browser/history/redirect_uitest.cc
+++ b/chrome/browser/history/redirect_uitest.cc
@@ -14,7 +14,7 @@
#include "base/string_util.h"
#include "base/string16.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/view_ids.h"
+#include "chrome/browser/ui/view_ids.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/automation/window_proxy.h"
diff --git a/chrome/browser/history/top_sites.cc b/chrome/browser/history/top_sites.cc
index 164dea3..dd3eee9 100644
--- a/chrome/browser/history/top_sites.cc
+++ b/chrome/browser/history/top_sites.cc
@@ -22,7 +22,7 @@
#include "chrome/browser/history/top_sites_backend.h"
#include "chrome/browser/history/top_sites_cache.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/common/chrome_switches.h"
diff --git a/chrome/browser/history/top_sites.h b/chrome/browser/history/top_sites.h
index 8992483..9eeb715 100644
--- a/chrome/browser/history/top_sites.h
+++ b/chrome/browser/history/top_sites.h
@@ -9,6 +9,7 @@
#include <list>
#include <set>
#include <string>
+#include <utility>
#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
@@ -17,12 +18,10 @@
#include "base/ref_counted_memory.h"
#include "base/time.h"
#include "base/timer.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/cancelable_request.h"
#include "chrome/browser/history/history_types.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/history/page_usage_data.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/thumbnail_score.h"
#include "googleurl/src/gurl.h"
diff --git a/chrome/browser/host_content_settings_map.cc b/chrome/browser/host_content_settings_map.cc
deleted file mode 100644
index 9371139..0000000
--- a/chrome/browser/host_content_settings_map.cc
+++ /dev/null
@@ -1,1169 +0,0 @@
-// 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.
-
-#include "chrome/browser/host_content_settings_map.h"
-
-#include "base/command_line.h"
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/prefs/scoped_pref_update.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/notification_source.h"
-#include "chrome/common/notification_type.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/url_constants.h"
-#include "googleurl/src/gurl.h"
-#include "googleurl/src/url_canon.h"
-#include "googleurl/src/url_parse.h"
-#include "net/base/dns_util.h"
-#include "net/base/net_util.h"
-#include "net/base/static_cookie_policy.h"
-
-namespace {
-// The version of the pattern format implemented. Version 1 includes the
-// following patterns:
-// - [*.]domain.tld (matches domain.tld and all sub-domains)
-// - host (matches an exact hostname)
-// - a.b.c.d (matches an exact IPv4 ip)
-// - [a:b:c:d:e:f:g:h] (matches an exact IPv6 ip)
-// - file:///tmp/test.html (a complete URL without a host)
-// Version 2 adds a resource identifier for plugins.
-// TODO(jochen): update once this feature is no longer behind a flag.
-const int kContentSettingsPatternVersion = 1;
-
-// The format of a domain wildcard.
-const char kDomainWildcard[] = "[*.]";
-
-// The length of kDomainWildcard (without the trailing '\0')
-const size_t kDomainWildcardLength = arraysize(kDomainWildcard) - 1;
-
-// Base pref path of the prefs that contain the managed default content
-// settings values.
-const std::string kManagedSettings =
- "profile.managed_default_content_settings";
-
-// The preference keys where resource identifiers are stored for
-// ContentSettingsType values that support resource identifiers.
-const char* kResourceTypeNames[CONTENT_SETTINGS_NUM_TYPES] = {
- NULL,
- NULL,
- NULL,
- "per_plugin",
- NULL,
- NULL, // Not used for Geolocation
- NULL, // Not used for Notifications
-};
-
-// The names of the ContentSettingsType values, for use with dictionary prefs.
-const char* kTypeNames[CONTENT_SETTINGS_NUM_TYPES] = {
- "cookies",
- "images",
- "javascript",
- "plugins",
- "popups",
- NULL, // Not used for Geolocation
- NULL, // Not used for Notifications
-};
-
-// The preferences used to manage ContentSettingsTypes.
-const char* kPrefToManageType[CONTENT_SETTINGS_NUM_TYPES] = {
- prefs::kManagedDefaultCookiesSetting,
- prefs::kManagedDefaultImagesSetting,
- prefs::kManagedDefaultJavaScriptSetting,
- prefs::kManagedDefaultPluginsSetting,
- prefs::kManagedDefaultPopupsSetting,
- NULL, // Not used for Geolocation
- NULL, // Not used for Notifications
-};
-
-// The default setting for each content type.
-const ContentSetting kDefaultSettings[CONTENT_SETTINGS_NUM_TYPES] = {
- CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_COOKIES
- CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_IMAGES
- CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_JAVASCRIPT
- CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_PLUGINS
- CONTENT_SETTING_BLOCK, // CONTENT_SETTINGS_TYPE_POPUPS
- CONTENT_SETTING_ASK, // Not used for Geolocation
- CONTENT_SETTING_ASK, // Not used for Notifications
-};
-
-// True if a given content settings type requires additional resource
-// identifiers.
-const bool kRequiresResourceIdentifier[CONTENT_SETTINGS_NUM_TYPES] = {
- false, // CONTENT_SETTINGS_TYPE_COOKIES
- false, // CONTENT_SETTINGS_TYPE_IMAGES
- false, // CONTENT_SETTINGS_TYPE_JAVASCRIPT
- true, // CONTENT_SETTINGS_TYPE_PLUGINS
- false, // CONTENT_SETTINGS_TYPE_POPUPS
- false, // Not used for Geolocation
- false, // Not used for Notifications
-};
-
-// Returns true if we should allow all content types for this URL. This is
-// true for various internal objects like chrome:// URLs, so UI and other
-// things users think of as "not webpages" don't break.
-static bool ShouldAllowAllContent(const GURL& url) {
- return url.SchemeIs(chrome::kChromeDevToolsScheme) ||
- url.SchemeIs(chrome::kChromeInternalScheme) ||
- url.SchemeIs(chrome::kChromeUIScheme) ||
- url.SchemeIs(chrome::kExtensionScheme) ||
- url.SchemeIs(chrome::kGearsScheme) ||
- url.SchemeIs(chrome::kUserScriptScheme);
-}
-
-// Map ASK for the plugins content type to BLOCK if click-to-play is
-// not enabled.
-ContentSetting ClickToPlayFixup(ContentSettingsType content_type,
- ContentSetting setting) {
- if (setting == CONTENT_SETTING_ASK &&
- content_type == CONTENT_SETTINGS_TYPE_PLUGINS &&
- !CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableClickToPlay)) {
- return CONTENT_SETTING_BLOCK;
- }
- return setting;
-}
-
-} // namespace
-
-
-struct HostContentSettingsMap::ExtendedContentSettings {
- ContentSettings content_settings;
- ResourceContentSettings content_settings_for_resources;
-};
-
-// static
-HostContentSettingsMap::Pattern HostContentSettingsMap::Pattern::FromURL(
- const GURL& url) {
- return Pattern(!url.has_host() || url.HostIsIPAddress() ?
- net::GetHostOrSpecFromURL(url) :
- std::string(kDomainWildcard) + url.host());
-}
-
-// static
-HostContentSettingsMap::Pattern
- HostContentSettingsMap::Pattern::FromURLNoWildcard(const GURL& url) {
- return Pattern(net::GetHostOrSpecFromURL(url));
-}
-
-bool HostContentSettingsMap::Pattern::IsValid() const {
- if (pattern_.empty())
- return false;
-
- const std::string host(pattern_.length() > kDomainWildcardLength &&
- StartsWithASCII(pattern_, kDomainWildcard, false) ?
- pattern_.substr(kDomainWildcardLength) :
- pattern_);
- url_canon::CanonHostInfo host_info;
- return host.find('*') == std::string::npos &&
- !net::CanonicalizeHost(host, &host_info).empty();
-}
-
-bool HostContentSettingsMap::Pattern::Matches(const GURL& url) const {
- if (!IsValid())
- return false;
-
- const std::string host(net::GetHostOrSpecFromURL(url));
- if (pattern_.length() < kDomainWildcardLength ||
- !StartsWithASCII(pattern_, kDomainWildcard, false))
- return pattern_ == host;
-
- const size_t match =
- host.rfind(pattern_.substr(kDomainWildcardLength));
-
- return (match != std::string::npos) &&
- (match == 0 || host[match - 1] == '.') &&
- (match + pattern_.length() - kDomainWildcardLength == host.length());
-}
-
-std::string HostContentSettingsMap::Pattern::CanonicalizePattern() const {
- if (!IsValid()) {
- return "";
- }
-
- bool starts_with_wildcard = pattern_.length() > kDomainWildcardLength &&
- StartsWithASCII(pattern_, kDomainWildcard, false);
-
- const std::string host(starts_with_wildcard ?
- pattern_.substr(kDomainWildcardLength) : pattern_);
-
- std::string canonicalized_pattern =
- starts_with_wildcard ? kDomainWildcard : "";
-
- url_canon::CanonHostInfo host_info;
- canonicalized_pattern += net::CanonicalizeHost(host, &host_info);
-
- return canonicalized_pattern;
-}
-
-HostContentSettingsMap::HostContentSettingsMap(Profile* profile)
- : profile_(profile),
- block_third_party_cookies_(false),
- is_block_third_party_cookies_managed_(false),
- is_off_the_record_(profile_->IsOffTheRecord()),
- updating_preferences_(false) {
- PrefService* prefs = profile_->GetPrefs();
-
- MigrateObsoleteCookiePref(prefs);
-
- MigrateObsoletePopupsPref(prefs);
-
- MigrateObsoletePerhostPref(prefs);
-
- // Read global defaults.
- DCHECK_EQ(arraysize(kTypeNames),
- static_cast<size_t>(CONTENT_SETTINGS_NUM_TYPES));
- ReadDefaultSettings(false);
-
- // Read misc. global settings.
- block_third_party_cookies_ =
- prefs->GetBoolean(prefs::kBlockThirdPartyCookies);
- is_block_third_party_cookies_managed_ =
- prefs->IsManagedPreference(prefs::kBlockThirdPartyCookies);
- block_nonsandboxed_plugins_ =
- prefs->GetBoolean(prefs::kBlockNonsandboxedPlugins);
-
- // Verify preferences version.
- if (!prefs->HasPrefPath(prefs::kContentSettingsVersion)) {
- prefs->SetInteger(prefs::kContentSettingsVersion,
- kContentSettingsPatternVersion);
- }
- if (prefs->GetInteger(prefs::kContentSettingsVersion) >
- kContentSettingsPatternVersion) {
- LOG(ERROR) << "Unknown content settings version in preferences.";
- return;
- }
-
- // Read exceptions.
- ReadExceptions(false);
-
- pref_change_registrar_.Init(prefs);
- pref_change_registrar_.Add(prefs::kDefaultContentSettings, this);
- pref_change_registrar_.Add(prefs::kContentSettingsPatterns, this);
- pref_change_registrar_.Add(prefs::kBlockThirdPartyCookies, this);
- pref_change_registrar_.Add(prefs::kBlockNonsandboxedPlugins, this);
- // The following preferences are only used to indicate if a
- // default-content-setting is managed and to hold the managed default-setting
- // value. If the value for any of the following perferences is set then the
- // corresponding default-content-setting is managed. These preferences exist
- // in parallel to the preference default-content-settings. If a
- // default-content-settings-type is managed any user defined excpetions
- // (patterns) for this type are ignored.
- pref_change_registrar_.Add(prefs::kManagedDefaultCookiesSetting, this);
- pref_change_registrar_.Add(prefs::kManagedDefaultImagesSetting, this);
- pref_change_registrar_.Add(prefs::kManagedDefaultJavaScriptSetting, this);
- pref_change_registrar_.Add(prefs::kManagedDefaultPluginsSetting, this);
- pref_change_registrar_.Add(prefs::kManagedDefaultPopupsSetting, this);
- notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED,
- Source<Profile>(profile_));
-}
-
-// static
-void HostContentSettingsMap::RegisterUserPrefs(PrefService* prefs) {
- prefs->RegisterDictionaryPref(prefs::kDefaultContentSettings);
- prefs->RegisterIntegerPref(prefs::kContentSettingsVersion,
- kContentSettingsPatternVersion);
- prefs->RegisterDictionaryPref(prefs::kContentSettingsPatterns);
- prefs->RegisterBooleanPref(prefs::kBlockThirdPartyCookies, false);
- prefs->RegisterBooleanPref(prefs::kBlockNonsandboxedPlugins, false);
- prefs->RegisterIntegerPref(prefs::kContentSettingsWindowLastTabIndex, 0);
-
- // Preferences for default content setting policies. A policy is not set of
- // the corresponding preferences below is set to CONTENT_SETTING_DEFAULT.
- prefs->RegisterIntegerPref(prefs::kManagedDefaultCookiesSetting,
- CONTENT_SETTING_DEFAULT);
- prefs->RegisterIntegerPref(prefs::kManagedDefaultImagesSetting,
- CONTENT_SETTING_DEFAULT);
- prefs->RegisterIntegerPref(prefs::kManagedDefaultJavaScriptSetting,
- CONTENT_SETTING_DEFAULT);
- prefs->RegisterIntegerPref(prefs::kManagedDefaultPluginsSetting,
- CONTENT_SETTING_DEFAULT);
- prefs->RegisterIntegerPref(prefs::kManagedDefaultPopupsSetting,
- CONTENT_SETTING_DEFAULT);
-
- // Obsolete prefs, for migration:
- prefs->RegisterIntegerPref(prefs::kCookieBehavior,
- net::StaticCookiePolicy::ALLOW_ALL_COOKIES);
- prefs->RegisterListPref(prefs::kPopupWhitelistedHosts);
- prefs->RegisterDictionaryPref(prefs::kPerHostContentSettings);
-}
-
-ContentSetting HostContentSettingsMap::GetDefaultContentSetting(
- ContentSettingsType content_type) const {
- AutoLock auto_lock(lock_);
- if (IsDefaultContentSettingManaged(content_type))
- return managed_default_content_settings_.settings[content_type];
- return default_content_settings_.settings[content_type];
-}
-
-ContentSetting HostContentSettingsMap::GetContentSetting(
- const GURL& url,
- ContentSettingsType content_type,
- const std::string& resource_identifier) const {
- ContentSetting setting = GetNonDefaultContentSetting(url,
- content_type,
- resource_identifier);
- if (setting == CONTENT_SETTING_DEFAULT ||
- IsDefaultContentSettingManaged(content_type)) {
- return GetDefaultContentSetting(content_type);
- }
- return setting;
-}
-
-ContentSetting HostContentSettingsMap::GetNonDefaultContentSetting(
- const GURL& url,
- ContentSettingsType content_type,
- const std::string& resource_identifier) const {
- if (ShouldAllowAllContent(url))
- return CONTENT_SETTING_ALLOW;
-
- if (!RequiresResourceIdentifier(content_type))
- return GetNonDefaultContentSettings(url).settings[content_type];
-
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableResourceContentSettings)) {
- DCHECK(!resource_identifier.empty());
- }
-
- // Host content settings are ignored if the default_content_setting is
- // managed.
- if (IsDefaultContentSettingManaged(content_type)) {
- return GetDefaultContentSetting(content_type);
- }
-
- AutoLock auto_lock(lock_);
-
- const std::string host(net::GetHostOrSpecFromURL(url));
- ContentSettingsTypeResourceIdentifierPair
- requested_setting(content_type, resource_identifier);
-
- // Check for exact matches first.
- HostContentSettings::const_iterator i(host_content_settings_.find(host));
- if (i != host_content_settings_.end() &&
- i->second.content_settings_for_resources.find(requested_setting) !=
- i->second.content_settings_for_resources.end()) {
- return i->second.content_settings_for_resources.find(
- requested_setting)->second;
- }
-
- // If this map is not for an off-the-record profile, these searches will never
- // match. The additional off-the-record exceptions always overwrite the
- // regular ones.
- i = off_the_record_settings_.find(host);
- if (i != off_the_record_settings_.end() &&
- i->second.content_settings_for_resources.find(requested_setting) !=
- i->second.content_settings_for_resources.end()) {
- return i->second.content_settings_for_resources.find(
- requested_setting)->second;
- }
-
- // Match patterns starting with the most concrete pattern match.
- for (std::string key = std::string(kDomainWildcard) + host; ; ) {
- HostContentSettings::const_iterator i(off_the_record_settings_.find(key));
- if (i != off_the_record_settings_.end() &&
- i->second.content_settings_for_resources.find(requested_setting) !=
- i->second.content_settings_for_resources.end()) {
- return i->second.content_settings_for_resources.find(
- requested_setting)->second;
- }
-
- i = host_content_settings_.find(key);
- if (i != host_content_settings_.end() &&
- i->second.content_settings_for_resources.find(requested_setting) !=
- i->second.content_settings_for_resources.end()) {
- return i->second.content_settings_for_resources.find(
- requested_setting)->second;
- }
-
- const size_t next_dot = key.find('.', kDomainWildcardLength);
- if (next_dot == std::string::npos)
- break;
- key.erase(kDomainWildcardLength, next_dot - kDomainWildcardLength + 1);
- }
-
- return CONTENT_SETTING_DEFAULT;
-}
-
-ContentSettings HostContentSettingsMap::GetContentSettings(
- const GURL& url) const {
- ContentSettings output = GetNonDefaultContentSettings(url);
-
- AutoLock auto_lock(lock_);
-
- // If we require a resource identifier, set the content settings to default,
- // otherwise make the defaults explicit.
- for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j) {
- if (RequiresResourceIdentifier(ContentSettingsType(j))) {
- output.settings[j] = CONTENT_SETTING_DEFAULT;
- } else {
- if (output.settings[j] == CONTENT_SETTING_DEFAULT) {
- output.settings[j] = default_content_settings_.settings[j];
- }
- // A managed default content setting has the highest priority and hence
- // will overwrite any previously set value.
- if (IsDefaultContentSettingManaged(ContentSettingsType(j))) {
- output.settings[j] =
- managed_default_content_settings_.settings[j];
- }
- }
- }
- return output;
-}
-
-ContentSettings HostContentSettingsMap::GetNonDefaultContentSettings(
- const GURL& url) const {
- if (ShouldAllowAllContent(url))
- return ContentSettings(CONTENT_SETTING_ALLOW);
-
- AutoLock auto_lock(lock_);
-
- const std::string host(net::GetHostOrSpecFromURL(url));
- ContentSettings output;
- for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j)
- output.settings[j] = CONTENT_SETTING_DEFAULT;
-
- // Check for exact matches first.
- HostContentSettings::const_iterator i(host_content_settings_.find(host));
- if (i != host_content_settings_.end())
- output = i->second.content_settings;
-
- // If this map is not for an off-the-record profile, these searches will never
- // match. The additional off-the-record exceptions always overwrite the
- // regular ones.
- i = off_the_record_settings_.find(host);
- if (i != off_the_record_settings_.end()) {
- for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j)
- if (i->second.content_settings.settings[j] != CONTENT_SETTING_DEFAULT)
- output.settings[j] = i->second.content_settings.settings[j];
- }
-
- // Match patterns starting with the most concrete pattern match.
- for (std::string key = std::string(kDomainWildcard) + host; ; ) {
- HostContentSettings::const_iterator i(off_the_record_settings_.find(key));
- if (i != off_the_record_settings_.end()) {
- for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j) {
- if (output.settings[j] == CONTENT_SETTING_DEFAULT)
- output.settings[j] = i->second.content_settings.settings[j];
- }
- }
- i = host_content_settings_.find(key);
- if (i != host_content_settings_.end()) {
- for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j) {
- if (output.settings[j] == CONTENT_SETTING_DEFAULT)
- output.settings[j] = i->second.content_settings.settings[j];
- }
- }
- const size_t next_dot = key.find('.', kDomainWildcardLength);
- if (next_dot == std::string::npos)
- break;
- key.erase(kDomainWildcardLength, next_dot - kDomainWildcardLength + 1);
- }
-
- return output;
-}
-
-void HostContentSettingsMap::GetSettingsForOneType(
- ContentSettingsType content_type,
- const std::string& resource_identifier,
- SettingsForOneType* settings) const {
- DCHECK(RequiresResourceIdentifier(content_type) !=
- resource_identifier.empty());
- DCHECK(settings);
- settings->clear();
-
- const HostContentSettings* map_to_return =
- is_off_the_record_ ? &off_the_record_settings_ : &host_content_settings_;
- ContentSettingsTypeResourceIdentifierPair
- requested_setting(content_type, resource_identifier);
-
- AutoLock auto_lock(lock_);
- for (HostContentSettings::const_iterator i(map_to_return->begin());
- i != map_to_return->end(); ++i) {
- ContentSetting setting;
- if (RequiresResourceIdentifier(content_type)) {
- if (i->second.content_settings_for_resources.find(requested_setting) !=
- i->second.content_settings_for_resources.end())
- setting = i->second.content_settings_for_resources.find(
- requested_setting)->second;
- else
- setting = CONTENT_SETTING_DEFAULT;
- } else {
- setting = i->second.content_settings.settings[content_type];
- }
- if (setting != CONTENT_SETTING_DEFAULT) {
- // Use of push_back() relies on the map iterator traversing in order of
- // ascending keys.
- settings->push_back(std::make_pair(Pattern(i->first), setting));
- }
- }
-}
-
-void HostContentSettingsMap::SetDefaultContentSetting(
- ContentSettingsType content_type,
- ContentSetting setting) {
- DCHECK(kTypeNames[content_type] != NULL); // Don't call this for Geolocation.
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(content_type != CONTENT_SETTINGS_TYPE_PLUGINS ||
- setting != CONTENT_SETTING_ASK ||
- CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableClickToPlay));
- PrefService* prefs = profile_->GetPrefs();
-
- // The default settings may not be directly modified for OTR sessions.
- // Instead, they are synced to the main profile's setting.
- if (is_off_the_record_) {
- NOTREACHED();
- return;
- }
-
- DictionaryValue* default_settings_dictionary =
- prefs->GetMutableDictionary(prefs::kDefaultContentSettings);
- std::string dictionary_path(kTypeNames[content_type]);
- updating_preferences_ = true;
- {
- AutoLock auto_lock(lock_);
- ScopedPrefUpdate update(prefs, prefs::kDefaultContentSettings);
- if ((setting == CONTENT_SETTING_DEFAULT) ||
- (setting == kDefaultSettings[content_type])) {
- default_content_settings_.settings[content_type] =
- kDefaultSettings[content_type];
- default_settings_dictionary->RemoveWithoutPathExpansion(dictionary_path,
- NULL);
- } else {
- default_content_settings_.settings[content_type] = setting;
- default_settings_dictionary->SetWithoutPathExpansion(
- dictionary_path, Value::CreateIntegerValue(setting));
- }
- }
- updating_preferences_ = false;
-
- NotifyObservers(ContentSettingsDetails(Pattern(), content_type, ""));
-}
-
-void HostContentSettingsMap::SetContentSetting(
- const Pattern& original_pattern,
- ContentSettingsType content_type,
- const std::string& resource_identifier,
- ContentSetting setting) {
- DCHECK(kTypeNames[content_type] != NULL); // Don't call this for Geolocation.
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK_NE(RequiresResourceIdentifier(content_type),
- resource_identifier.empty());
- DCHECK(content_type != CONTENT_SETTINGS_TYPE_PLUGINS ||
- setting != CONTENT_SETTING_ASK ||
- CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableClickToPlay));
-
- const Pattern pattern(original_pattern.CanonicalizePattern());
-
- bool early_exit = false;
- std::string pattern_str(pattern.AsString());
- PrefService* prefs = NULL;
- DictionaryValue* all_settings_dictionary = NULL;
- HostContentSettings* map_to_modify = &off_the_record_settings_;
- if (!is_off_the_record_) {
- prefs = profile_->GetPrefs();
- all_settings_dictionary =
- prefs->GetMutableDictionary(prefs::kContentSettingsPatterns);
- map_to_modify = &host_content_settings_;
- }
-
- {
- AutoLock auto_lock(lock_);
- if (!map_to_modify->count(pattern_str))
- (*map_to_modify)[pattern_str].content_settings = ContentSettings();
- HostContentSettings::iterator
- i(map_to_modify->find(pattern_str));
- ContentSettings& settings = i->second.content_settings;
- if (RequiresResourceIdentifier(content_type)) {
- settings.settings[content_type] = CONTENT_SETTING_DEFAULT;
- if (setting != CONTENT_SETTING_DEFAULT) {
- i->second.content_settings_for_resources[
- ContentSettingsTypeResourceIdentifierPair(content_type,
- resource_identifier)] = setting;
- } else {
- i->second.content_settings_for_resources.erase(
- ContentSettingsTypeResourceIdentifierPair(content_type,
- resource_identifier));
- }
- } else {
- settings.settings[content_type] = setting;
- }
- if (AllDefault(i->second)) {
- map_to_modify->erase(i);
- if (all_settings_dictionary)
- all_settings_dictionary->RemoveWithoutPathExpansion(pattern_str, NULL);
-
- // We can't just return because |NotifyObservers()| needs to be called,
- // without |lock_| being held.
- early_exit = true;
- }
- }
-
- if (!early_exit && all_settings_dictionary) {
- DictionaryValue* host_settings_dictionary = NULL;
- bool found = all_settings_dictionary->GetDictionaryWithoutPathExpansion(
- pattern_str, &host_settings_dictionary);
- if (!found) {
- host_settings_dictionary = new DictionaryValue;
- all_settings_dictionary->SetWithoutPathExpansion(
- pattern_str, host_settings_dictionary);
- DCHECK_NE(setting, CONTENT_SETTING_DEFAULT);
- }
- if (RequiresResourceIdentifier(content_type)) {
- std::string dictionary_path(kResourceTypeNames[content_type]);
- DictionaryValue* resource_dictionary = NULL;
- found = host_settings_dictionary->GetDictionary(
- dictionary_path, &resource_dictionary);
- if (!found) {
- resource_dictionary = new DictionaryValue;
- host_settings_dictionary->Set(dictionary_path, resource_dictionary);
- }
- if (setting == CONTENT_SETTING_DEFAULT) {
- resource_dictionary->RemoveWithoutPathExpansion(resource_identifier,
- NULL);
- } else {
- resource_dictionary->SetWithoutPathExpansion(
- resource_identifier, Value::CreateIntegerValue(setting));
- }
- } else {
- std::string dictionary_path(kTypeNames[content_type]);
- if (setting == CONTENT_SETTING_DEFAULT) {
- host_settings_dictionary->RemoveWithoutPathExpansion(dictionary_path,
- NULL);
- } else {
- host_settings_dictionary->SetWithoutPathExpansion(
- dictionary_path, Value::CreateIntegerValue(setting));
- }
- }
- }
-
- updating_preferences_ = true;
- if (!is_off_the_record_)
- ScopedPrefUpdate update(prefs, prefs::kContentSettingsPatterns);
- updating_preferences_ = false;
-
- NotifyObservers(ContentSettingsDetails(pattern, content_type, ""));
-}
-
-void HostContentSettingsMap::AddExceptionForURL(
- const GURL& url,
- ContentSettingsType content_type,
- const std::string& resource_identifier,
- ContentSetting setting) {
- // Make sure there is no entry that would override the pattern we are about
- // to insert for exactly this URL.
- SetContentSetting(Pattern::FromURLNoWildcard(url),
- content_type,
- resource_identifier,
- CONTENT_SETTING_DEFAULT);
- SetContentSetting(Pattern::FromURL(url),
- content_type,
- resource_identifier,
- setting);
-}
-
-void HostContentSettingsMap::ClearSettingsForOneType(
- ContentSettingsType content_type) {
- DCHECK(kTypeNames[content_type] != NULL); // Don't call this for Geolocation.
-
- PrefService* prefs = NULL;
- DictionaryValue* all_settings_dictionary = NULL;
- HostContentSettings* map_to_modify = &off_the_record_settings_;
-
- if (!is_off_the_record_) {
- prefs = profile_->GetPrefs();
- all_settings_dictionary =
- prefs->GetMutableDictionary(prefs::kContentSettingsPatterns);
- map_to_modify = &host_content_settings_;
- }
-
- {
- AutoLock auto_lock(lock_);
- for (HostContentSettings::iterator i(map_to_modify->begin());
- i != map_to_modify->end(); ) {
- if (RequiresResourceIdentifier(content_type) ||
- i->second.content_settings.settings[content_type] !=
- CONTENT_SETTING_DEFAULT) {
- if (RequiresResourceIdentifier(content_type))
- i->second.content_settings_for_resources.clear();
- i->second.content_settings.settings[content_type] =
- CONTENT_SETTING_DEFAULT;
- std::string host(i->first);
- if (AllDefault(i->second)) {
- if (all_settings_dictionary)
- all_settings_dictionary->
- RemoveWithoutPathExpansion(host, NULL);
- map_to_modify->erase(i++);
- } else if (all_settings_dictionary) {
- DictionaryValue* host_settings_dictionary;
- bool found =
- all_settings_dictionary->GetDictionaryWithoutPathExpansion(
- host, &host_settings_dictionary);
- DCHECK(found);
- host_settings_dictionary->RemoveWithoutPathExpansion(
- kTypeNames[content_type], NULL);
- ++i;
- }
- } else {
- ++i;
- }
- }
- }
-
- updating_preferences_ = true;
- if (!is_off_the_record_)
- ScopedPrefUpdate update(prefs, prefs::kContentSettingsPatterns);
- updating_preferences_ = false;
-
- NotifyObservers(ContentSettingsDetails(Pattern(), content_type, ""));
-}
-
-bool HostContentSettingsMap::RequiresResourceIdentifier(
- ContentSettingsType content_type) const {
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableResourceContentSettings)) {
- return kRequiresResourceIdentifier[content_type];
- } else {
- return false;
- }
-}
-
-void HostContentSettingsMap::SetBlockThirdPartyCookies(bool block) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // This setting may not be directly modified for OTR sessions. Instead, it
- // is synced to the main profile's setting.
- if (is_off_the_record_) {
- NOTREACHED();
- return;
- }
-
- PrefService* prefs = profile_->GetPrefs();
- // If the preference block-third-party-cookies is managed then do not allow to
- // change it.
- if (prefs->IsManagedPreference(prefs::kBlockThirdPartyCookies)) {
- NOTREACHED();
- return;
- }
-
- {
- AutoLock auto_lock(lock_);
- block_third_party_cookies_ = block;
- }
-
- if (block)
- prefs->SetBoolean(prefs::kBlockThirdPartyCookies, true);
- else
- prefs->ClearPref(prefs::kBlockThirdPartyCookies);
-}
-
-void HostContentSettingsMap::SetBlockNonsandboxedPlugins(bool block) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // This setting may not be directly modified for OTR sessions. Instead, it
- // is synced to the main profile's setting.
- if (is_off_the_record_) {
- NOTREACHED();
- return;
- }
-
- {
- AutoLock auto_lock(lock_);
- block_nonsandboxed_plugins_ = block;
- }
-
-
- PrefService* prefs = profile_->GetPrefs();
- if (block) {
- UserMetrics::RecordAction(
- UserMetricsAction("BlockNonsandboxedPlugins_Enable"));
- prefs->SetBoolean(prefs::kBlockNonsandboxedPlugins, true);
- } else {
- UserMetrics::RecordAction(
- UserMetricsAction("BlockNonsandboxedPlugins_Disable"));
- prefs->ClearPref(prefs::kBlockNonsandboxedPlugins);
- }
-}
-
-void HostContentSettingsMap::ResetToDefaults() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- {
- AutoLock auto_lock(lock_);
- default_content_settings_ = ContentSettings();
- ForceDefaultsToBeExplicit();
- host_content_settings_.clear();
- off_the_record_settings_.clear();
- block_third_party_cookies_ = false;
- block_nonsandboxed_plugins_ = false;
- }
-
- if (!is_off_the_record_) {
- PrefService* prefs = profile_->GetPrefs();
- updating_preferences_ = true;
- prefs->ClearPref(prefs::kDefaultContentSettings);
- prefs->ClearPref(prefs::kContentSettingsPatterns);
- prefs->ClearPref(prefs::kBlockThirdPartyCookies);
- prefs->ClearPref(prefs::kBlockNonsandboxedPlugins);
- updating_preferences_ = false;
- NotifyObservers(
- ContentSettingsDetails(Pattern(), CONTENT_SETTINGS_TYPE_DEFAULT, ""));
- }
-}
-
-void HostContentSettingsMap::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- if (NotificationType::PREF_CHANGED == type) {
- if (updating_preferences_)
- return;
-
- std::string* name = Details<std::string>(details).ptr();
- if (prefs::kDefaultContentSettings == *name) {
- ReadDefaultSettings(true);
- } else if (prefs::kContentSettingsPatterns == *name) {
- ReadExceptions(true);
- } else if (prefs::kBlockThirdPartyCookies == *name) {
- AutoLock auto_lock(lock_);
- block_third_party_cookies_ = profile_->GetPrefs()->GetBoolean(
- prefs::kBlockThirdPartyCookies);
- is_block_third_party_cookies_managed_ =
- profile_->GetPrefs()->IsManagedPreference(
- prefs::kBlockThirdPartyCookies);
- } else if (prefs::kBlockNonsandboxedPlugins == *name) {
- AutoLock auto_lock(lock_);
- block_nonsandboxed_plugins_ = profile_->GetPrefs()->GetBoolean(
- prefs::kBlockNonsandboxedPlugins);
- } else if (prefs::kManagedDefaultCookiesSetting == *name) {
- UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES,
- profile_->GetPrefs(),
- &managed_default_content_settings_);
- } else if (prefs::kManagedDefaultImagesSetting == *name) {
- UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_IMAGES,
- profile_->GetPrefs(),
- &managed_default_content_settings_);
- } else if (prefs::kManagedDefaultJavaScriptSetting == *name) {
- UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_JAVASCRIPT,
- profile_->GetPrefs(),
- &managed_default_content_settings_);
- } else if (prefs::kManagedDefaultPluginsSetting == *name) {
- UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_PLUGINS,
- profile_->GetPrefs(),
- &managed_default_content_settings_);
- } else if (prefs::kManagedDefaultPopupsSetting == *name) {
- UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_POPUPS,
- profile_->GetPrefs(),
- &managed_default_content_settings_);
- } else {
- NOTREACHED() << "Unexpected preference observed";
- return;
- }
-
- if (!is_off_the_record_) {
- NotifyObservers(
- ContentSettingsDetails(Pattern(), CONTENT_SETTINGS_TYPE_DEFAULT, ""));
- }
- } else if (NotificationType::PROFILE_DESTROYED == type) {
- UnregisterObservers();
- } else {
- NOTREACHED() << "Unexpected notification";
- }
-}
-
-HostContentSettingsMap::~HostContentSettingsMap() {
- UnregisterObservers();
-}
-
-void HostContentSettingsMap::GetSettingsFromDictionary(
- const DictionaryValue* dictionary,
- ContentSettings* settings) {
- for (DictionaryValue::key_iterator i(dictionary->begin_keys());
- i != dictionary->end_keys(); ++i) {
- const std::string& content_type(*i);
- for (size_t type = 0; type < arraysize(kTypeNames); ++type) {
- if ((kTypeNames[type] != NULL) && (kTypeNames[type] == content_type)) {
- int setting = CONTENT_SETTING_DEFAULT;
- bool found = dictionary->GetIntegerWithoutPathExpansion(content_type,
- &setting);
- DCHECK(found);
- settings->settings[type] = IntToContentSetting(setting);
- break;
- }
- }
- }
- // Migrate obsolete cookie prompt mode.
- if (settings->settings[CONTENT_SETTINGS_TYPE_COOKIES] ==
- CONTENT_SETTING_ASK)
- settings->settings[CONTENT_SETTINGS_TYPE_COOKIES] = CONTENT_SETTING_BLOCK;
-
- settings->settings[CONTENT_SETTINGS_TYPE_PLUGINS] =
- ClickToPlayFixup(CONTENT_SETTINGS_TYPE_PLUGINS,
- settings->settings[CONTENT_SETTINGS_TYPE_PLUGINS]);
-}
-
-void HostContentSettingsMap::GetResourceSettingsFromDictionary(
- const DictionaryValue* dictionary,
- ResourceContentSettings* settings) {
- for (DictionaryValue::key_iterator i(dictionary->begin_keys());
- i != dictionary->end_keys(); ++i) {
- const std::string& content_type(*i);
- for (size_t type = 0; type < arraysize(kResourceTypeNames); ++type) {
- if ((kResourceTypeNames[type] != NULL) &&
- (kResourceTypeNames[type] == content_type)) {
- DictionaryValue* resource_dictionary = NULL;
- bool found = dictionary->GetDictionary(content_type,
- &resource_dictionary);
- DCHECK(found);
- for (DictionaryValue::key_iterator j(resource_dictionary->begin_keys());
- j != resource_dictionary->end_keys(); ++j) {
- const std::string& resource_identifier(*j);
- int setting = CONTENT_SETTING_DEFAULT;
- bool found = resource_dictionary->GetIntegerWithoutPathExpansion(
- resource_identifier, &setting);
- DCHECK(found);
- (*settings)[ContentSettingsTypeResourceIdentifierPair(
- ContentSettingsType(type), resource_identifier)] =
- ClickToPlayFixup(ContentSettingsType(type),
- ContentSetting(setting));
- }
-
- break;
- }
- }
- }
-}
-
-void HostContentSettingsMap::ForceDefaultsToBeExplicit() {
- DCHECK_EQ(arraysize(kDefaultSettings),
- static_cast<size_t>(CONTENT_SETTINGS_NUM_TYPES));
-
- for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
- if (default_content_settings_.settings[i] == CONTENT_SETTING_DEFAULT)
- default_content_settings_.settings[i] = kDefaultSettings[i];
- }
-}
-
-bool HostContentSettingsMap::AllDefault(
- const ExtendedContentSettings& settings) const {
- for (size_t i = 0; i < arraysize(settings.content_settings.settings); ++i) {
- if (settings.content_settings.settings[i] != CONTENT_SETTING_DEFAULT)
- return false;
- }
- return settings.content_settings_for_resources.empty();
-}
-
-void HostContentSettingsMap::ReadDefaultSettings(bool overwrite) {
- PrefService* prefs = profile_->GetPrefs();
- const DictionaryValue* default_settings_dictionary =
- prefs->GetDictionary(prefs::kDefaultContentSettings);
-
- if (overwrite)
- default_content_settings_ = ContentSettings();
-
- // Careful: The returned value could be NULL if the pref has never been set.
- if (default_settings_dictionary != NULL) {
- GetSettingsFromDictionary(default_settings_dictionary,
- &default_content_settings_);
- }
- ForceDefaultsToBeExplicit();
-
- // Read managed default content settings.
- ReadManagedDefaultSettings(prefs, &managed_default_content_settings_);
-}
-
-void HostContentSettingsMap::ReadManagedDefaultSettings (
- const PrefService* prefs, ContentSettings* settings) {
- for (size_t type = 0; type < arraysize(kPrefToManageType); ++type) {
- if (kPrefToManageType[type] == NULL) {
- // TODO(markusheintz): Handle Geolocation and notification separately.
- continue;
- }
- UpdateManagedDefaultSetting(ContentSettingsType(type), prefs, settings);
- }
-}
-
-void HostContentSettingsMap::UpdateManagedDefaultSetting(
- ContentSettingsType type,
- const PrefService* prefs,
- ContentSettings* settings) {
- // If a pref to manage a default-content-setting was not set (NOTICE:
- // "HasPrefPath" returns false if no value was set for a registered pref) then
- // the default value of the preference is used. The default value of a
- // preference to manage a default-content-settings is
- // CONTENT_SETTING_DEFAULT. This indicates that no managed value is set. If a
- // pref was set, than it MUST be managed.
- DCHECK(!prefs->HasPrefPath(kPrefToManageType[type]) ||
- prefs->IsManagedPreference(kPrefToManageType[type]));
- AutoLock auto_lock(lock_);
- settings->settings[type] = IntToContentSetting(
- prefs->GetInteger(kPrefToManageType[type]));
-}
-
-bool HostContentSettingsMap::IsDefaultContentSettingManaged(
- ContentSettingsType content_type) const {
- // All managed_default_content_settings_ are always set explicitly or
- // initialized to CONTENT_SETTINGS_DEFAULT. Hence each content settings type
- // that is set to CONTENT_SETTINGS_DEFAULT is not managed since it was not set
- // explicitly.
- return managed_default_content_settings_.settings[content_type] !=
- CONTENT_SETTING_DEFAULT;
-}
-
-void HostContentSettingsMap::ReadExceptions(bool overwrite) {
- PrefService* prefs = profile_->GetPrefs();
- DictionaryValue* all_settings_dictionary =
- prefs->GetMutableDictionary(prefs::kContentSettingsPatterns);
-
- if (overwrite)
- host_content_settings_.clear();
-
- // Careful: The returned value could be NULL if the pref has never been set.
- if (all_settings_dictionary != NULL) {
- // Convert all Unicode patterns into punycode form, then read.
- CanonicalizeContentSettingsExceptions(all_settings_dictionary);
-
- for (DictionaryValue::key_iterator i(all_settings_dictionary->begin_keys());
- i != all_settings_dictionary->end_keys(); ++i) {
- const std::string& pattern(*i);
- if (!Pattern(pattern).IsValid())
- LOG(WARNING) << "Invalid pattern stored in content settings";
- DictionaryValue* pattern_settings_dictionary = NULL;
- bool found = all_settings_dictionary->GetDictionaryWithoutPathExpansion(
- pattern, &pattern_settings_dictionary);
- DCHECK(found);
- ContentSettings settings;
- GetSettingsFromDictionary(pattern_settings_dictionary, &settings);
- host_content_settings_[pattern].content_settings = settings;
- GetResourceSettingsFromDictionary(
- pattern_settings_dictionary,
- &host_content_settings_[pattern].content_settings_for_resources);
- }
- }
-}
-
-void HostContentSettingsMap::NotifyObservers(
- const ContentSettingsDetails& details) {
- NotificationService::current()->Notify(
- NotificationType::CONTENT_SETTINGS_CHANGED,
- Source<HostContentSettingsMap>(this),
- Details<const ContentSettingsDetails>(&details));
-}
-
-void HostContentSettingsMap::UnregisterObservers() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (!profile_)
- return;
- pref_change_registrar_.RemoveAll();
- notification_registrar_.Remove(this, NotificationType::PROFILE_DESTROYED,
- Source<Profile>(profile_));
- profile_ = NULL;
-}
-
-void HostContentSettingsMap::MigrateObsoleteCookiePref(PrefService* prefs) {
- if (prefs->HasPrefPath(prefs::kCookieBehavior)) {
- int cookie_behavior = prefs->GetInteger(prefs::kCookieBehavior);
- prefs->ClearPref(prefs::kCookieBehavior);
- if (!prefs->HasPrefPath(prefs::kDefaultContentSettings)) {
- SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_COOKIES,
- (cookie_behavior == net::StaticCookiePolicy::BLOCK_ALL_COOKIES) ?
- CONTENT_SETTING_BLOCK : CONTENT_SETTING_ALLOW);
- }
- if (!prefs->HasPrefPath(prefs::kBlockThirdPartyCookies)) {
- SetBlockThirdPartyCookies(cookie_behavior ==
- net::StaticCookiePolicy::BLOCK_THIRD_PARTY_COOKIES);
- }
- }
-}
-
-void HostContentSettingsMap::MigrateObsoletePopupsPref(PrefService* prefs) {
- if (prefs->HasPrefPath(prefs::kPopupWhitelistedHosts)) {
- const ListValue* whitelist_pref =
- prefs->GetList(prefs::kPopupWhitelistedHosts);
- for (ListValue::const_iterator i(whitelist_pref->begin());
- i != whitelist_pref->end(); ++i) {
- std::string host;
- (*i)->GetAsString(&host);
- SetContentSetting(Pattern(host), CONTENT_SETTINGS_TYPE_POPUPS, "",
- CONTENT_SETTING_ALLOW);
- }
- prefs->ClearPref(prefs::kPopupWhitelistedHosts);
- }
-}
-
-void HostContentSettingsMap::MigrateObsoletePerhostPref(PrefService* prefs) {
- if (prefs->HasPrefPath(prefs::kPerHostContentSettings)) {
- const DictionaryValue* all_settings_dictionary =
- prefs->GetDictionary(prefs::kPerHostContentSettings);
- for (DictionaryValue::key_iterator i(all_settings_dictionary->begin_keys());
- i != all_settings_dictionary->end_keys(); ++i) {
- const std::string& host(*i);
- Pattern pattern(std::string(kDomainWildcard) + host);
- DictionaryValue* host_settings_dictionary = NULL;
- bool found = all_settings_dictionary->GetDictionaryWithoutPathExpansion(
- host, &host_settings_dictionary);
- DCHECK(found);
- ContentSettings settings;
- GetSettingsFromDictionary(host_settings_dictionary, &settings);
- for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j) {
- if (settings.settings[j] != CONTENT_SETTING_DEFAULT &&
- !RequiresResourceIdentifier(ContentSettingsType(j)))
- SetContentSetting(
- pattern, ContentSettingsType(j), "", settings.settings[j]);
- }
- }
- prefs->ClearPref(prefs::kPerHostContentSettings);
- }
-}
-
-void HostContentSettingsMap::CanonicalizeContentSettingsExceptions(
- DictionaryValue* all_settings_dictionary) {
- DCHECK(all_settings_dictionary);
-
- std::vector<std::string> remove_items;
- std::vector<std::pair<std::string, std::string> > move_items;
- for (DictionaryValue::key_iterator i(all_settings_dictionary->begin_keys());
- i != all_settings_dictionary->end_keys(); ++i) {
- const std::string& pattern(*i);
- const std::string canonicalized_pattern =
- Pattern(pattern).CanonicalizePattern();
-
- if (canonicalized_pattern.empty() || canonicalized_pattern == pattern)
- continue;
-
- // Clear old pattern if prefs already have canonicalized pattern.
- DictionaryValue* new_pattern_settings_dictionary = NULL;
- if (all_settings_dictionary->GetDictionaryWithoutPathExpansion(
- canonicalized_pattern, &new_pattern_settings_dictionary)) {
- remove_items.push_back(pattern);
- continue;
- }
-
- // Move old pattern to canonicalized pattern.
- DictionaryValue* old_pattern_settings_dictionary = NULL;
- if (all_settings_dictionary->GetDictionaryWithoutPathExpansion(
- pattern, &old_pattern_settings_dictionary)) {
- move_items.push_back(std::make_pair(pattern, canonicalized_pattern));
- }
- }
-
- for (size_t i = 0; i < remove_items.size(); ++i) {
- all_settings_dictionary->RemoveWithoutPathExpansion(remove_items[i], NULL);
- }
-
- for (size_t i = 0; i < move_items.size(); ++i) {
- Value* pattern_settings_dictionary = NULL;
- all_settings_dictionary->RemoveWithoutPathExpansion(
- move_items[i].first, &pattern_settings_dictionary);
- all_settings_dictionary->SetWithoutPathExpansion(
- move_items[i].second, pattern_settings_dictionary);
- }
-}
diff --git a/chrome/browser/host_content_settings_map.h b/chrome/browser/host_content_settings_map.h
deleted file mode 100644
index 00e15bd..0000000
--- a/chrome/browser/host_content_settings_map.h
+++ /dev/null
@@ -1,354 +0,0 @@
-// 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.
-
-// Maps hostnames to custom content settings. Written on the UI thread and read
-// on any thread. One instance per profile.
-
-#ifndef CHROME_BROWSER_HOST_CONTENT_SETTINGS_MAP_H_
-#define CHROME_BROWSER_HOST_CONTENT_SETTINGS_MAP_H_
-#pragma once
-
-#include <map>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/lock.h"
-#include "base/ref_counted.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/prefs/pref_change_registrar.h"
-#include "chrome/common/content_settings.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
-
-class DictionaryValue;
-class GURL;
-class PrefService;
-class Profile;
-
-class HostContentSettingsMap
- : public NotificationObserver,
- public base::RefCountedThreadSafe<HostContentSettingsMap,
- BrowserThread::DeleteOnUIThread> {
- public:
- // A hostname pattern. See |IsValid| for a description of possible patterns.
- class Pattern {
- public:
- // Returns a pattern that matches the host of this URL and all subdomains.
- static Pattern FromURL(const GURL& url);
-
- // Returns a pattern that matches exactly this URL.
- static Pattern FromURLNoWildcard(const GURL& url);
-
- Pattern() {}
-
- explicit Pattern(const std::string& pattern) : pattern_(pattern) {}
-
- // True if this is a valid pattern. Valid patterns are
- // - [*.]domain.tld (matches domain.tld and all sub-domains)
- // - host (matches an exact hostname)
- // - a.b.c.d (matches an exact IPv4 ip)
- // - [a:b:c:d:e:f:g:h] (matches an exact IPv6 ip)
- bool IsValid() const;
-
- // True if |url| matches this pattern.
- bool Matches(const GURL& url) const;
-
- // Returns a std::string representation of this pattern.
- const std::string& AsString() const { return pattern_; }
-
- bool operator==(const Pattern& other) const {
- return pattern_ == other.pattern_;
- }
-
- // Canonicalizes the pattern so that it's ASCII only, either
- // in original or punycode form.
- std::string CanonicalizePattern() const;
-
- private:
- std::string pattern_;
- };
-
- // Details for the CONTENT_SETTINGS_CHANGED notification. This is sent when
- // content settings change for at least one host. If settings change for more
- // than one pattern in one user interaction, this will usually send a single
- // notification with update_all() returning true instead of one notification
- // for each pattern.
- class ContentSettingsDetails {
- public:
- // Update the setting that matches this pattern/content type/resource.
- ContentSettingsDetails(const Pattern& pattern,
- ContentSettingsType type,
- const std::string& resource_identifier)
- : pattern_(pattern),
- type_(type),
- resource_identifier_(resource_identifier) {}
-
- // The pattern whose settings have changed.
- const Pattern& pattern() const { return pattern_; }
-
- // True if all settings should be updated for the given type.
- bool update_all() const { return pattern_.AsString().empty(); }
-
- // The type of the pattern whose settings have changed.
- ContentSettingsType type() const { return type_; }
-
- // The resource identifier for the settings type that has changed.
- const std::string& resource_identifier() const {
- return resource_identifier_;
- }
-
- // True if all types should be updated. If update_all() is false, this will
- // be false as well (although the reverse does not hold true).
- bool update_all_types() const {
- return CONTENT_SETTINGS_TYPE_DEFAULT == type_;
- }
-
- private:
- Pattern pattern_;
- ContentSettingsType type_;
- std::string resource_identifier_;
- };
-
- typedef std::pair<Pattern, ContentSetting> PatternSettingPair;
- typedef std::vector<PatternSettingPair> SettingsForOneType;
-
- explicit HostContentSettingsMap(Profile* profile);
- ~HostContentSettingsMap();
-
- static void RegisterUserPrefs(PrefService* prefs);
-
- // Returns the default setting for a particular content type.
- //
- // This may be called on any thread.
- ContentSetting GetDefaultContentSetting(
- ContentSettingsType content_type) const;
-
- // Returns a single ContentSetting which applies to a given URL. Note that
- // certain internal schemes are whitelisted. For ContentSettingsTypes that
- // require an resource identifier to be specified, the |resource_identifier|
- // must be non-empty.
- //
- // This may be called on any thread.
- ContentSetting GetContentSetting(
- const GURL& url,
- ContentSettingsType content_type,
- const std::string& resource_identifier) const;
-
- // Returns a single ContentSetting which applies to a given URL or
- // CONTENT_SETTING_DEFAULT, if no exception applies. Note that certain
- // internal schemes are whitelisted. For ContentSettingsTypes that require an
- // resource identifier to be specified, the |resource_identifier| must be
- // non-empty.
- //
- // This may be called on any thread.
- ContentSetting GetNonDefaultContentSetting(
- const GURL& url,
- ContentSettingsType content_type,
- const std::string& resource_identifier) const;
-
- // Returns all ContentSettings which apply to a given URL. For content
- // setting types that require an additional resource identifier, the default
- // content setting is returned.
- //
- // This may be called on any thread.
- ContentSettings GetContentSettings(const GURL& url) const;
-
- // Returns all non-default ContentSettings which apply to a given URL. For
- // content setting types that require an additional resource identifier,
- // CONTENT_SETTING_DEFAULT is returned.
- //
- // This may be called on any thread.
- ContentSettings GetNonDefaultContentSettings(const GURL& url) const;
-
- // For a given content type, returns all patterns with a non-default setting,
- // mapped to their actual settings, in lexicographical order. |settings|
- // must be a non-NULL outparam. If this map was created for the
- // off-the-record profile, it will only return those settings differing from
- // the main map. For ContentSettingsTypes that require an resource identifier
- // to be specified, the |resource_identifier| must be non-empty.
- //
- // This may be called on any thread.
- void GetSettingsForOneType(ContentSettingsType content_type,
- const std::string& resource_identifier,
- SettingsForOneType* settings) const;
-
- // Sets the default setting for a particular content type. This method must
- // not be invoked on an off-the-record map.
- //
- // This should only be called on the UI thread.
- void SetDefaultContentSetting(ContentSettingsType content_type,
- ContentSetting setting);
-
- // Sets the blocking setting for a particular pattern and content type.
- // Setting the value to CONTENT_SETTING_DEFAULT causes the default setting
- // for that type to be used when loading pages matching this pattern. For
- // ContentSettingsTypes that require an resource identifier to be specified,
- // the |resource_identifier| must be non-empty.
- //
- // This should only be called on the UI thread.
- void SetContentSetting(const Pattern& pattern,
- ContentSettingsType content_type,
- const std::string& resource_identifier,
- ContentSetting setting);
-
- // Convenience method to add a content setting for a given URL, making sure
- // that there is no setting overriding it. For ContentSettingsTypes that
- // require an resource identifier to be specified, the |resource_identifier|
- // must be non-empty.
- //
- // This should only be called on the UI thread.
- void AddExceptionForURL(const GURL& url,
- ContentSettingsType content_type,
- const std::string& resource_identifier,
- ContentSetting setting);
-
- // Clears all host-specific settings for one content type.
- //
- // This should only be called on the UI thread.
- void ClearSettingsForOneType(ContentSettingsType content_type);
-
- // Whether the |content_type| requires an additional resource identifier for
- // accessing content settings.
- bool RequiresResourceIdentifier(ContentSettingsType content_type) const;
-
- // This setting trumps any host-specific settings.
- bool BlockThirdPartyCookies() const { return block_third_party_cookies_; }
- bool IsBlockThirdPartyCookiesManaged() const {
- return is_block_third_party_cookies_managed_;
- }
-
- // Sets whether we block all third-party cookies. This method must not be
- // invoked on an off-the-record map.
- //
- // This should only be called on the UI thread.
- void SetBlockThirdPartyCookies(bool block);
-
- bool GetBlockNonsandboxedPlugins() const {
- return block_nonsandboxed_plugins_;
- }
-
- void SetBlockNonsandboxedPlugins(bool block);
-
- // Resets all settings levels.
- //
- // This should only be called on the UI thread.
- void ResetToDefaults();
-
- // Returns true if the default setting for the |content_type| is managed.
- bool IsDefaultContentSettingManaged(ContentSettingsType content_type) const;
-
- // NotificationObserver implementation.
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- private:
- friend class base::RefCountedThreadSafe<HostContentSettingsMap>;
-
- typedef std::pair<ContentSettingsType, std::string>
- ContentSettingsTypeResourceIdentifierPair;
- typedef std::map<ContentSettingsTypeResourceIdentifierPair, ContentSetting>
- ResourceContentSettings;
-
- struct ExtendedContentSettings;
- typedef std::map<std::string, ExtendedContentSettings> HostContentSettings;
-
- // Sets the fields of |settings| based on the values in |dictionary|.
- void GetSettingsFromDictionary(const DictionaryValue* dictionary,
- ContentSettings* settings);
-
- // Populates |settings| based on the values in |dictionary|.
- void GetResourceSettingsFromDictionary(const DictionaryValue* dictionary,
- ResourceContentSettings* settings);
-
- // Forces the default settings to be explicitly set instead of themselves
- // being CONTENT_SETTING_DEFAULT.
- void ForceDefaultsToBeExplicit();
-
- // Returns true if |settings| consists entirely of CONTENT_SETTING_DEFAULT.
- bool AllDefault(const ExtendedContentSettings& settings) const;
-
- // Reads the default settings from the prefereces service. If |overwrite| is
- // true and the preference is missing, the local copy will be cleared as well.
- void ReadDefaultSettings(bool overwrite);
-
- // Reads managed default content settings from the preference service |prefs|.
- // |settings| is set to the respective content setting for managed settings,
- // and to CONTENT_SETTING_DEFAULT for other settings.
- void ReadManagedDefaultSettings(const PrefService* prefs,
- ContentSettings* settings);
-
- // Updates the managed setting of the default-content-settings-type |type|.
- // The updated setting is read from the preference service |prefs| and written
- // to |settings|.
- void UpdateManagedDefaultSetting(ContentSettingsType type,
- const PrefService* prefs,
- ContentSettings* settings);
-
- // Reads the host exceptions from the prefereces service. If |overwrite| is
- // true and the preference is missing, the local copy will be cleared as well.
- void ReadExceptions(bool overwrite);
-
- // Informs observers that content settings have changed. Make sure that
- // |lock_| is not held when calling this, as listeners will usually call one
- // of the GetSettings functions in response, which would then lead to a
- // mutex deadlock.
- void NotifyObservers(const ContentSettingsDetails& details);
-
- void UnregisterObservers();
-
- // Various migration methods (old cookie, popup and per-host data gets
- // migrated to the new format).
- void MigrateObsoleteCookiePref(PrefService* prefs);
- void MigrateObsoletePopupsPref(PrefService* prefs);
- void MigrateObsoletePerhostPref(PrefService* prefs);
-
- // Converts all exceptions that have non-canonicalized pattern into
- // canonicalized pattern. If such pattern already exists, we just remove the
- // old exception.
- void CanonicalizeContentSettingsExceptions(DictionaryValue* settings);
-
- // The profile we're associated with.
- Profile* profile_;
-
- NotificationRegistrar notification_registrar_;
- PrefChangeRegistrar pref_change_registrar_;
-
- // Copies of the pref data, so that we can read it on the IO thread.
- ContentSettings default_content_settings_;
- ContentSettings managed_default_content_settings_;
- HostContentSettings host_content_settings_;
-
- // Differences to the preference-stored host content settings for
- // off-the-record settings.
- HostContentSettings off_the_record_settings_;
-
- // Misc global settings.
- bool block_third_party_cookies_;
- bool is_block_third_party_cookies_managed_;
- bool block_nonsandboxed_plugins_;
-
- // Used around accesses to the settings objects to guarantee thread safety.
- mutable Lock lock_;
-
- // Whether this settings map is for an OTR session.
- bool is_off_the_record_;
-
- // Whether we are currently updating preferences, this is used to ignore
- // notifications from the preferences service that we triggered ourself.
- bool updating_preferences_;
-
- DISALLOW_COPY_AND_ASSIGN(HostContentSettingsMap);
-};
-
-// Stream operator so HostContentSettingsMap::Pattern can be used in
-// assertion statements.
-inline std::ostream& operator<<(
- std::ostream& out, const HostContentSettingsMap::Pattern& pattern) {
- return out << pattern.AsString();
-}
-
-#endif // CHROME_BROWSER_HOST_CONTENT_SETTINGS_MAP_H_
diff --git a/chrome/browser/host_content_settings_map_unittest.cc b/chrome/browser/host_content_settings_map_unittest.cc
deleted file mode 100644
index 1312d43..0000000
--- a/chrome/browser/host_content_settings_map_unittest.cc
+++ /dev/null
@@ -1,987 +0,0 @@
-// 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.
-
-#include "chrome/browser/host_content_settings_map.h"
-
-#include "base/auto_reset.h"
-#include "base/command_line.h"
-#include "base/json/json_reader.h"
-#include "base/json/json_writer.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/url_constants.h"
-#include "chrome/test/testing_pref_service.h"
-#include "chrome/test/testing_profile.h"
-#include "googleurl/src/gurl.h"
-#include "net/base/static_cookie_policy.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-
-namespace {
-
-bool SettingsEqual(const ContentSettings& settings1,
- const ContentSettings& settings2) {
- for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
- if (settings1.settings[i] != settings2.settings[i])
- return false;
- }
- return true;
-}
-
-class StubSettingsObserver : public NotificationObserver {
- public:
- StubSettingsObserver() : last_notifier(NULL), counter(0) {
- registrar_.Add(this, NotificationType::CONTENT_SETTINGS_CHANGED,
- NotificationService::AllSources());
- }
-
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- ++counter;
- Source<HostContentSettingsMap> content_settings(source);
- Details<HostContentSettingsMap::ContentSettingsDetails>
- settings_details(details);
- last_notifier = content_settings.ptr();
- last_pattern = settings_details.ptr()->pattern();
- last_update_all = settings_details.ptr()->update_all();
- last_update_all_types = settings_details.ptr()->update_all_types();
- last_type = settings_details.ptr()->type();
- // This checks that calling a Get function from an observer doesn't
- // deadlock.
- last_notifier->GetContentSettings(GURL("http://random-hostname.com/"));
- }
-
- HostContentSettingsMap* last_notifier;
- HostContentSettingsMap::Pattern last_pattern;
- bool last_update_all;
- bool last_update_all_types;
- int counter;
- ContentSettingsType last_type;
-
- private:
- NotificationRegistrar registrar_;
-};
-
-class HostContentSettingsMapTest : public testing::Test {
- public:
- HostContentSettingsMapTest() : ui_thread_(BrowserThread::UI, &message_loop_) {
- }
-
- protected:
- MessageLoop message_loop_;
- BrowserThread ui_thread_;
-};
-
-TEST_F(HostContentSettingsMapTest, DefaultValues) {
- TestingProfile profile;
- HostContentSettingsMap* host_content_settings_map =
- profile.GetHostContentSettingsMap();
-
- // Check setting defaults.
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_JAVASCRIPT));
- host_content_settings_map->SetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_IMAGES, CONTENT_SETTING_BLOCK);
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_IMAGES));
- EXPECT_EQ(CONTENT_SETTING_ALLOW, host_content_settings_map->GetContentSetting(
- GURL(chrome::kChromeUINewTabURL),
- CONTENT_SETTINGS_TYPE_IMAGES, ""));
- {
- // Click-to-play needs to be enabled to set the content setting to ASK.
- CommandLine* cmd = CommandLine::ForCurrentProcess();
- AutoReset<CommandLine> auto_reset(cmd, *cmd);
- cmd->AppendSwitch(switches::kEnableClickToPlay);
-
- host_content_settings_map->SetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_PLUGINS, CONTENT_SETTING_ASK);
- EXPECT_EQ(CONTENT_SETTING_ASK,
- host_content_settings_map->GetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_PLUGINS));
- }
- host_content_settings_map->SetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_POPUPS, CONTENT_SETTING_ALLOW);
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_POPUPS));
- host_content_settings_map->ResetToDefaults();
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_PLUGINS));
-
- // Check returning individual settings.
- GURL host("http://example.com/");
- HostContentSettingsMap::Pattern pattern("[*.]example.com");
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_IMAGES, ""));
- host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_DEFAULT);
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_IMAGES, ""));
- host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_IMAGES, ""));
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_PLUGINS, ""));
-
- // Check returning all settings for a host.
- ContentSettings desired_settings;
- desired_settings.settings[CONTENT_SETTINGS_TYPE_COOKIES] =
- CONTENT_SETTING_ALLOW;
- host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_DEFAULT);
- desired_settings.settings[CONTENT_SETTINGS_TYPE_IMAGES] =
- CONTENT_SETTING_ALLOW;
- host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_JAVASCRIPT, "", CONTENT_SETTING_BLOCK);
- desired_settings.settings[CONTENT_SETTINGS_TYPE_JAVASCRIPT] =
- CONTENT_SETTING_BLOCK;
- host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_PLUGINS, "", CONTENT_SETTING_ALLOW);
- desired_settings.settings[CONTENT_SETTINGS_TYPE_PLUGINS] =
- CONTENT_SETTING_ALLOW;
- desired_settings.settings[CONTENT_SETTINGS_TYPE_POPUPS] =
- CONTENT_SETTING_BLOCK;
- desired_settings.settings[CONTENT_SETTINGS_TYPE_GEOLOCATION] =
- CONTENT_SETTING_ASK;
- desired_settings.settings[CONTENT_SETTINGS_TYPE_NOTIFICATIONS] =
- CONTENT_SETTING_ASK;
- ContentSettings settings =
- host_content_settings_map->GetContentSettings(host);
- EXPECT_TRUE(SettingsEqual(desired_settings, settings));
-
- // Check returning all hosts for a setting.
- HostContentSettingsMap::Pattern pattern2("[*.]example.org");
- host_content_settings_map->SetContentSetting(pattern2,
- CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
- host_content_settings_map->SetContentSetting(pattern2,
- CONTENT_SETTINGS_TYPE_PLUGINS, "", CONTENT_SETTING_BLOCK);
- HostContentSettingsMap::SettingsForOneType host_settings;
- host_content_settings_map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_IMAGES,
- "",
- &host_settings);
- EXPECT_EQ(1U, host_settings.size());
- host_content_settings_map->GetSettingsForOneType(
- CONTENT_SETTINGS_TYPE_PLUGINS, "", &host_settings);
- EXPECT_EQ(2U, host_settings.size());
- host_content_settings_map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_POPUPS,
- "",
- &host_settings);
- EXPECT_EQ(0U, host_settings.size());
- host_content_settings_map->ResetToDefaults();
- host_content_settings_map->GetSettingsForOneType(
- CONTENT_SETTINGS_TYPE_PLUGINS, "", &host_settings);
- EXPECT_EQ(0U, host_settings.size());
-
- // Check clearing one type.
- HostContentSettingsMap::Pattern pattern3("[*.]example.net");
- host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
- host_content_settings_map->SetContentSetting(pattern2,
- CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
- host_content_settings_map->SetContentSetting(pattern2,
- CONTENT_SETTINGS_TYPE_PLUGINS, "", CONTENT_SETTING_BLOCK);
- host_content_settings_map->SetContentSetting(pattern3,
- CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
- host_content_settings_map->ClearSettingsForOneType(
- CONTENT_SETTINGS_TYPE_IMAGES);
- host_content_settings_map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_IMAGES,
- "",
- &host_settings);
- EXPECT_EQ(0U, host_settings.size());
- host_content_settings_map->GetSettingsForOneType(
- CONTENT_SETTINGS_TYPE_PLUGINS, "", &host_settings);
- EXPECT_EQ(1U, host_settings.size());
-}
-
-TEST_F(HostContentSettingsMapTest, Patterns) {
- TestingProfile profile;
- HostContentSettingsMap* host_content_settings_map =
- profile.GetHostContentSettingsMap();
-
- GURL host1("http://example.com/");
- GURL host2("http://www.example.com/");
- GURL host3("http://example.org/");
- HostContentSettingsMap::Pattern pattern1("[*.]example.com");
- HostContentSettingsMap::Pattern pattern2("example.org");
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetContentSetting(
- host1, CONTENT_SETTINGS_TYPE_IMAGES, ""));
- host_content_settings_map->SetContentSetting(pattern1,
- CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetContentSetting(
- host1, CONTENT_SETTINGS_TYPE_IMAGES, ""));
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetContentSetting(
- host2, CONTENT_SETTINGS_TYPE_IMAGES, ""));
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetContentSetting(
- host3, CONTENT_SETTINGS_TYPE_IMAGES, ""));
- host_content_settings_map->SetContentSetting(pattern2,
- CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetContentSetting(
- host3, CONTENT_SETTINGS_TYPE_IMAGES, ""));
-}
-
-TEST_F(HostContentSettingsMapTest, PatternSupport) {
- EXPECT_TRUE(HostContentSettingsMap::Pattern("[*.]example.com").IsValid());
- EXPECT_TRUE(HostContentSettingsMap::Pattern("example.com").IsValid());
- EXPECT_TRUE(HostContentSettingsMap::Pattern("192.168.0.1").IsValid());
- EXPECT_TRUE(HostContentSettingsMap::Pattern("[::1]").IsValid());
- EXPECT_FALSE(HostContentSettingsMap::Pattern("*example.com").IsValid());
- EXPECT_FALSE(HostContentSettingsMap::Pattern("example.*").IsValid());
- EXPECT_FALSE(HostContentSettingsMap::Pattern("http://example.com").IsValid());
-
- EXPECT_TRUE(HostContentSettingsMap::Pattern("[*.]example.com").Matches(
- GURL("http://example.com/")));
- EXPECT_TRUE(HostContentSettingsMap::Pattern("[*.]example.com").Matches(
- GURL("http://www.example.com/")));
- EXPECT_TRUE(HostContentSettingsMap::Pattern("www.example.com").Matches(
- GURL("http://www.example.com/")));
- EXPECT_FALSE(HostContentSettingsMap::Pattern("").Matches(
- GURL("http://www.example.com/")));
- EXPECT_FALSE(HostContentSettingsMap::Pattern("[*.]example.com").Matches(
- GURL("http://example.org/")));
- EXPECT_FALSE(HostContentSettingsMap::Pattern("example.com").Matches(
- GURL("http://example.org/")));
-}
-
-TEST_F(HostContentSettingsMapTest, CanonicalizePattern) {
- // Basic patterns.
- EXPECT_STREQ("[*.]ikea.com", HostContentSettingsMap::Pattern("[*.]ikea.com")
- .CanonicalizePattern().c_str());
- EXPECT_STREQ("example.com", HostContentSettingsMap::Pattern("example.com")
- .CanonicalizePattern().c_str());
- EXPECT_STREQ("192.168.1.1", HostContentSettingsMap::Pattern("192.168.1.1")
- .CanonicalizePattern().c_str());
- EXPECT_STREQ("[::1]", HostContentSettingsMap::Pattern("[::1]")
- .CanonicalizePattern().c_str());
- // IsValid returns false for file:/// patterns.
- EXPECT_STREQ("", HostContentSettingsMap::Pattern(
- "file:///temp/file.html").CanonicalizePattern().c_str());
-
- // UTF-8 patterns.
- EXPECT_STREQ("[*.]xn--ira-ppa.com", HostContentSettingsMap::Pattern(
- "[*.]\xC4\x87ira.com").CanonicalizePattern().c_str());
- EXPECT_STREQ("xn--ira-ppa.com", HostContentSettingsMap::Pattern(
- "\xC4\x87ira.com").CanonicalizePattern().c_str());
- // IsValid returns false for file:/// patterns.
- EXPECT_STREQ("", HostContentSettingsMap::Pattern(
- "file:///\xC4\x87ira.html").CanonicalizePattern().c_str());
-
- // Invalid patterns.
- EXPECT_STREQ("", HostContentSettingsMap::Pattern(
- "*example.com").CanonicalizePattern().c_str());
- EXPECT_STREQ("", HostContentSettingsMap::Pattern(
- "example.*").CanonicalizePattern().c_str());
- EXPECT_STREQ("", HostContentSettingsMap::Pattern(
- "*\xC4\x87ira.com").CanonicalizePattern().c_str());
- EXPECT_STREQ("", HostContentSettingsMap::Pattern(
- "\xC4\x87ira.*").CanonicalizePattern().c_str());
-}
-
-TEST_F(HostContentSettingsMapTest, Observer) {
- TestingProfile profile;
- HostContentSettingsMap* host_content_settings_map =
- profile.GetHostContentSettingsMap();
- StubSettingsObserver observer;
-
- HostContentSettingsMap::Pattern pattern("[*.]example.com");
- host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_ALLOW);
- EXPECT_EQ(host_content_settings_map, observer.last_notifier);
- EXPECT_EQ(pattern, observer.last_pattern);
- EXPECT_FALSE(observer.last_update_all);
- EXPECT_FALSE(observer.last_update_all_types);
- EXPECT_EQ(1, observer.counter);
-
- host_content_settings_map->ClearSettingsForOneType(
- CONTENT_SETTINGS_TYPE_IMAGES);
- EXPECT_EQ(host_content_settings_map, observer.last_notifier);
- EXPECT_TRUE(observer.last_update_all);
- EXPECT_FALSE(observer.last_update_all_types);
- EXPECT_EQ(2, observer.counter);
-
- host_content_settings_map->ResetToDefaults();
- EXPECT_EQ(host_content_settings_map, observer.last_notifier);
- EXPECT_TRUE(observer.last_update_all);
- EXPECT_TRUE(observer.last_update_all_types);
- EXPECT_EQ(3, observer.counter);
-
- host_content_settings_map->SetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_IMAGES, CONTENT_SETTING_BLOCK);
- EXPECT_EQ(host_content_settings_map, observer.last_notifier);
- EXPECT_TRUE(observer.last_update_all);
- EXPECT_FALSE(observer.last_update_all_types);
- EXPECT_EQ(4, observer.counter);
-}
-
-TEST_F(HostContentSettingsMapTest, ObserveDefaultPref) {
- TestingProfile profile;
- HostContentSettingsMap* host_content_settings_map =
- profile.GetHostContentSettingsMap();
-
- PrefService* prefs = profile.GetPrefs();
-
- // Make a copy of the default pref value so we can reset it later.
- scoped_ptr<Value> default_value(prefs->FindPreference(
- prefs::kDefaultContentSettings)->GetValue()->DeepCopy());
-
- GURL host("http://example.com");
-
- host_content_settings_map->SetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_BLOCK);
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_COOKIES, ""));
-
- // Make a copy of the pref's new value so we can reset it later.
- scoped_ptr<Value> new_value(prefs->FindPreference(
- prefs::kDefaultContentSettings)->GetValue()->DeepCopy());
-
- // Clearing the backing pref should also clear the internal cache.
- prefs->Set(prefs::kDefaultContentSettings, *default_value);
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_COOKIES, ""));
-
- // Reseting the pref to its previous value should update the cache.
- prefs->Set(prefs::kDefaultContentSettings, *new_value);
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_COOKIES, ""));
-}
-
-TEST_F(HostContentSettingsMapTest, ObserveExceptionPref) {
- TestingProfile profile;
- HostContentSettingsMap* host_content_settings_map =
- profile.GetHostContentSettingsMap();
-
- PrefService* prefs = profile.GetPrefs();
-
- // Make a copy of the default pref value so we can reset it later.
- scoped_ptr<Value> default_value(prefs->FindPreference(
- prefs::kContentSettingsPatterns)->GetValue()->DeepCopy());
-
- HostContentSettingsMap::Pattern pattern("[*.]example.com");
- GURL host("http://example.com");
-
- host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_COOKIES, "", CONTENT_SETTING_BLOCK);
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_COOKIES, ""));
-
- // Make a copy of the pref's new value so we can reset it later.
- scoped_ptr<Value> new_value(prefs->FindPreference(
- prefs::kContentSettingsPatterns)->GetValue()->DeepCopy());
-
- // Clearing the backing pref should also clear the internal cache.
- prefs->Set(prefs::kContentSettingsPatterns, *default_value);
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_COOKIES, ""));
-
- // Reseting the pref to its previous value should update the cache.
- prefs->Set(prefs::kContentSettingsPatterns, *new_value);
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_COOKIES, ""));
-}
-
-TEST_F(HostContentSettingsMapTest, HostTrimEndingDotCheck) {
- TestingProfile profile;
- HostContentSettingsMap* host_content_settings_map =
- profile.GetHostContentSettingsMap();
-
- HostContentSettingsMap::Pattern pattern("[*.]example.com");
- GURL host_ending_with_dot("http://example.com./");
-
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetContentSetting(
- host_ending_with_dot, CONTENT_SETTINGS_TYPE_IMAGES, ""));
- host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_DEFAULT);
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetContentSetting(
- host_ending_with_dot, CONTENT_SETTINGS_TYPE_IMAGES, ""));
- host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetContentSetting(
- host_ending_with_dot, CONTENT_SETTINGS_TYPE_IMAGES, ""));
-
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetContentSetting(
- host_ending_with_dot, CONTENT_SETTINGS_TYPE_COOKIES, ""));
- host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_COOKIES, "", CONTENT_SETTING_DEFAULT);
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetContentSetting(
- host_ending_with_dot, CONTENT_SETTINGS_TYPE_COOKIES, ""));
- host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_COOKIES, "", CONTENT_SETTING_BLOCK);
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetContentSetting(
- host_ending_with_dot, CONTENT_SETTINGS_TYPE_COOKIES, ""));
-
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetContentSetting(
- host_ending_with_dot, CONTENT_SETTINGS_TYPE_JAVASCRIPT, ""));
- host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_JAVASCRIPT, "", CONTENT_SETTING_DEFAULT);
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetContentSetting(
- host_ending_with_dot, CONTENT_SETTINGS_TYPE_JAVASCRIPT, ""));
- host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_JAVASCRIPT, "", CONTENT_SETTING_BLOCK);
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetContentSetting(
- host_ending_with_dot, CONTENT_SETTINGS_TYPE_JAVASCRIPT, ""));
-
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetContentSetting(
- host_ending_with_dot, CONTENT_SETTINGS_TYPE_PLUGINS, ""));
- host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_PLUGINS, "", CONTENT_SETTING_DEFAULT);
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetContentSetting(
- host_ending_with_dot, CONTENT_SETTINGS_TYPE_PLUGINS, ""));
- host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_PLUGINS, "", CONTENT_SETTING_BLOCK);
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetContentSetting(
- host_ending_with_dot, CONTENT_SETTINGS_TYPE_PLUGINS, ""));
-
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetContentSetting(
- host_ending_with_dot, CONTENT_SETTINGS_TYPE_POPUPS, ""));
- host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_POPUPS, "", CONTENT_SETTING_DEFAULT);
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetContentSetting(
- host_ending_with_dot, CONTENT_SETTINGS_TYPE_POPUPS, ""));
- host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_POPUPS, "", CONTENT_SETTING_ALLOW);
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetContentSetting(
- host_ending_with_dot, CONTENT_SETTINGS_TYPE_POPUPS, ""));
-}
-
-TEST_F(HostContentSettingsMapTest, NestedSettings) {
- TestingProfile profile;
- HostContentSettingsMap* host_content_settings_map =
- profile.GetHostContentSettingsMap();
-
- GURL host("http://a.b.example.com/");
- HostContentSettingsMap::Pattern pattern1("[*.]example.com");
- HostContentSettingsMap::Pattern pattern2("[*.]b.example.com");
- HostContentSettingsMap::Pattern pattern3("a.b.example.com");
-
- host_content_settings_map->SetContentSetting(pattern1,
- CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
- host_content_settings_map->SetContentSetting(pattern2,
- CONTENT_SETTINGS_TYPE_COOKIES, "", CONTENT_SETTING_BLOCK);
- host_content_settings_map->SetContentSetting(pattern3,
- CONTENT_SETTINGS_TYPE_PLUGINS, "", CONTENT_SETTING_BLOCK);
- host_content_settings_map->SetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_JAVASCRIPT, CONTENT_SETTING_BLOCK);
-
- ContentSettings desired_settings;
- desired_settings.settings[CONTENT_SETTINGS_TYPE_COOKIES] =
- CONTENT_SETTING_BLOCK;
- desired_settings.settings[CONTENT_SETTINGS_TYPE_IMAGES] =
- CONTENT_SETTING_BLOCK;
- desired_settings.settings[CONTENT_SETTINGS_TYPE_JAVASCRIPT] =
- CONTENT_SETTING_BLOCK;
- desired_settings.settings[CONTENT_SETTINGS_TYPE_PLUGINS] =
- CONTENT_SETTING_BLOCK;
- desired_settings.settings[CONTENT_SETTINGS_TYPE_POPUPS] =
- CONTENT_SETTING_BLOCK;
- desired_settings.settings[CONTENT_SETTINGS_TYPE_GEOLOCATION] =
- CONTENT_SETTING_ASK;
- desired_settings.settings[CONTENT_SETTINGS_TYPE_NOTIFICATIONS] =
- CONTENT_SETTING_ASK;
- ContentSettings settings =
- host_content_settings_map->GetContentSettings(host);
- EXPECT_TRUE(SettingsEqual(desired_settings, settings));
- EXPECT_EQ(desired_settings.settings[CONTENT_SETTINGS_TYPE_COOKIES],
- settings.settings[CONTENT_SETTINGS_TYPE_COOKIES]);
- EXPECT_EQ(desired_settings.settings[CONTENT_SETTINGS_TYPE_IMAGES],
- settings.settings[CONTENT_SETTINGS_TYPE_IMAGES]);
- EXPECT_EQ(desired_settings.settings[CONTENT_SETTINGS_TYPE_PLUGINS],
- settings.settings[CONTENT_SETTINGS_TYPE_PLUGINS]);
- EXPECT_EQ(desired_settings.settings[CONTENT_SETTINGS_TYPE_POPUPS],
- settings.settings[CONTENT_SETTINGS_TYPE_POPUPS]);
- EXPECT_EQ(desired_settings.settings[CONTENT_SETTINGS_TYPE_GEOLOCATION],
- settings.settings[CONTENT_SETTINGS_TYPE_GEOLOCATION]);
- EXPECT_EQ(desired_settings.settings[CONTENT_SETTINGS_TYPE_COOKIES],
- settings.settings[CONTENT_SETTINGS_TYPE_COOKIES]);
-}
-
-TEST_F(HostContentSettingsMapTest, OffTheRecord) {
- TestingProfile profile;
- HostContentSettingsMap* host_content_settings_map =
- profile.GetHostContentSettingsMap();
- profile.set_off_the_record(true);
- scoped_refptr<HostContentSettingsMap> otr_map(
- new HostContentSettingsMap(&profile));
- profile.set_off_the_record(false);
-
- GURL host("http://example.com/");
- HostContentSettingsMap::Pattern pattern("[*.]example.com");
-
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_IMAGES, ""));
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- otr_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_IMAGES, ""));
-
- // Changing content settings on the main map should also affect the
- // off-the-record map.
- host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_IMAGES, ""));
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- otr_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_IMAGES, ""));
-
- // Changing content settings on the off-the-record map should NOT affect the
- // main map.
- otr_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_ALLOW);
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_IMAGES, ""));
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- otr_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_IMAGES, ""));
-}
-
-TEST_F(HostContentSettingsMapTest, MigrateObsoletePrefs) {
- // This feature is currently behind a flag.
- CommandLine* cmd = CommandLine::ForCurrentProcess();
- AutoReset<CommandLine> auto_reset(cmd, *cmd);
- cmd->AppendSwitch(switches::kEnableResourceContentSettings);
-
- TestingProfile profile;
- PrefService* prefs = profile.GetPrefs();
-
- // Set obsolete data.
- prefs->SetInteger(prefs::kCookieBehavior,
- net::StaticCookiePolicy::BLOCK_ALL_COOKIES);
-
- ListValue popup_hosts;
- popup_hosts.Append(new StringValue("[*.]example.com"));
- prefs->Set(prefs::kPopupWhitelistedHosts, popup_hosts);
-
- HostContentSettingsMap* host_content_settings_map =
- profile.GetHostContentSettingsMap();
-
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_COOKIES));
-
- GURL host("http://example.com");
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_POPUPS, ""));
-}
-
-// For a single Unicode encoded pattern, check if it gets converted to punycode
-// and old pattern gets deleted.
-TEST_F(HostContentSettingsMapTest, CanonicalizeExceptionsUnicodeOnly) {
- TestingProfile profile;
- PrefService* prefs = profile.GetPrefs();
-
- // Set utf-8 data.
- DictionaryValue* all_settings_dictionary =
- prefs->GetMutableDictionary(prefs::kContentSettingsPatterns);
- ASSERT_TRUE(NULL != all_settings_dictionary);
-
- DictionaryValue* dummy_payload = new DictionaryValue;
- dummy_payload->SetInteger("images", CONTENT_SETTING_ALLOW);
- all_settings_dictionary->SetWithoutPathExpansion("[*.]\xC4\x87ira.com",
- dummy_payload);
-
- profile.GetHostContentSettingsMap();
-
- DictionaryValue* result = NULL;
- EXPECT_FALSE(all_settings_dictionary->GetDictionaryWithoutPathExpansion(
- "[*.]\xC4\x87ira.com", &result));
- EXPECT_TRUE(all_settings_dictionary->GetDictionaryWithoutPathExpansion(
- "[*.]xn--ira-ppa.com", &result));
-}
-
-// If both Unicode and its punycode pattern exist, make sure we don't touch the
-// settings for the punycode, and that Unicode pattern gets deleted.
-TEST_F(HostContentSettingsMapTest, CanonicalizeExceptionsUnicodeAndPunycode) {
- // This feature is currently behind a flag.
- CommandLine* cmd = CommandLine::ForCurrentProcess();
- AutoReset<CommandLine> auto_reset(cmd, *cmd);
- cmd->AppendSwitch(switches::kEnableResourceContentSettings);
-
- TestingProfile profile;
-
- scoped_ptr<Value> value(base::JSONReader::Read(
- "{\"[*.]\\xC4\\x87ira.com\":{\"per_plugin\":{\"pluginx\":2}}}", false));
- profile.GetPrefs()->Set(prefs::kContentSettingsPatterns, *value);
-
- // Set punycode equivalent, with different setting.
- scoped_ptr<Value> puny_value(base::JSONReader::Read(
- "{\"[*.]xn--ira-ppa.com\":{\"per_plugin\":{\"pluginy\":2}}}", false));
- profile.GetPrefs()->Set(prefs::kContentSettingsPatterns, *puny_value);
-
- // Initialize the content map.
- profile.GetHostContentSettingsMap();
-
- const DictionaryValue* content_setting_prefs =
- profile.GetPrefs()->GetDictionary(prefs::kContentSettingsPatterns);
- std::string prefs_as_json;
- base::JSONWriter::Write(content_setting_prefs, false, &prefs_as_json);
- EXPECT_STREQ("{\"[*.]xn--ira-ppa.com\":{\"per_plugin\":{\"pluginy\":2}}}",
- prefs_as_json.c_str());
-}
-
-TEST_F(HostContentSettingsMapTest, NonDefaultSettings) {
- TestingProfile profile;
- HostContentSettingsMap* host_content_settings_map =
- profile.GetHostContentSettingsMap();
-
- GURL host("http://example.com/");
- HostContentSettingsMap::Pattern pattern("[*.]example.com");
-
- ContentSettings desired_settings(CONTENT_SETTING_DEFAULT);
- ContentSettings settings =
- host_content_settings_map->GetNonDefaultContentSettings(host);
- EXPECT_TRUE(SettingsEqual(desired_settings, settings));
-
- host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_IMAGES, "", CONTENT_SETTING_BLOCK);
- desired_settings.settings[CONTENT_SETTINGS_TYPE_IMAGES] =
- CONTENT_SETTING_BLOCK;
- settings =
- host_content_settings_map->GetNonDefaultContentSettings(host);
- EXPECT_TRUE(SettingsEqual(desired_settings, settings));
-}
-
-TEST_F(HostContentSettingsMapTest, ResourceIdentifier) {
- // This feature is currently behind a flag.
- CommandLine* cmd = CommandLine::ForCurrentProcess();
- AutoReset<CommandLine> auto_reset(cmd, *cmd);
- cmd->AppendSwitch(switches::kEnableResourceContentSettings);
-
- TestingProfile profile;
- HostContentSettingsMap* host_content_settings_map =
- profile.GetHostContentSettingsMap();
-
- GURL host("http://example.com/");
- HostContentSettingsMap::Pattern pattern("[*.]example.com");
- std::string resource1("someplugin");
- std::string resource2("otherplugin");
-
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_PLUGINS, resource1));
- host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_PLUGINS, resource1, CONTENT_SETTING_BLOCK);
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_PLUGINS, resource1));
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_PLUGINS, resource2));
-}
-
-TEST_F(HostContentSettingsMapTest, ResourceIdentifierPrefs) {
- // This feature is currently behind a flag.
- CommandLine* cmd = CommandLine::ForCurrentProcess();
- AutoReset<CommandLine> auto_reset(cmd, *cmd);
- cmd->AppendSwitch(switches::kEnableResourceContentSettings);
-
- TestingProfile profile;
- scoped_ptr<Value> value(base::JSONReader::Read(
- "{\"[*.]example.com\":{\"per_plugin\":{\"someplugin\":2}}}", false));
- profile.GetPrefs()->Set(prefs::kContentSettingsPatterns, *value);
- HostContentSettingsMap* host_content_settings_map =
- profile.GetHostContentSettingsMap();
-
- GURL host("http://example.com/");
- HostContentSettingsMap::Pattern pattern("[*.]example.com");
- std::string resource1("someplugin");
- std::string resource2("otherplugin");
-
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_PLUGINS, resource1));
-
- host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_PLUGINS, resource1, CONTENT_SETTING_DEFAULT);
-
- const DictionaryValue* content_setting_prefs =
- profile.GetPrefs()->GetDictionary(prefs::kContentSettingsPatterns);
- std::string prefs_as_json;
- base::JSONWriter::Write(content_setting_prefs, false, &prefs_as_json);
- EXPECT_STREQ("{}", prefs_as_json.c_str());
-
- host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_PLUGINS, resource2, CONTENT_SETTING_BLOCK);
-
- content_setting_prefs =
- profile.GetPrefs()->GetDictionary(prefs::kContentSettingsPatterns);
- base::JSONWriter::Write(content_setting_prefs, false, &prefs_as_json);
- EXPECT_STREQ("{\"[*.]example.com\":{\"per_plugin\":{\"otherplugin\":2}}}",
- prefs_as_json.c_str());
-}
-
-// If a default-content-setting is managed, the managed value should be used
-// instead of the default value.
-TEST_F(HostContentSettingsMapTest, ManagedDefaultContentSetting) {
- TestingProfile profile;
- HostContentSettingsMap* host_content_settings_map =
- profile.GetHostContentSettingsMap();
- TestingPrefService* prefs = profile.GetTestingPrefService();
-
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_JAVASCRIPT));
-
- // Set managed-default-content-setting through the coresponding preferences.
- prefs->SetManagedPref(prefs::kManagedDefaultJavaScriptSetting,
- Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_JAVASCRIPT));
-
- // Remove managed-default-content-settings-preferences.
- prefs->RemoveManagedPref(prefs::kManagedDefaultJavaScriptSetting);
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_JAVASCRIPT));
-
- // Set preference to manage the default-content-setting for Plugins.
- prefs->SetManagedPref(prefs::kManagedDefaultPluginsSetting,
- Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_PLUGINS));
-
- // Remove the preference to manage the default-content-setting for Plugins.
- prefs->RemoveManagedPref(prefs::kManagedDefaultPluginsSetting);
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_PLUGINS));
-}
-
-TEST_F(HostContentSettingsMapTest,
- GetNonDefaultContentSettingsIfTypeManaged) {
- TestingProfile profile;
- HostContentSettingsMap* host_content_settings_map =
- profile.GetHostContentSettingsMap();
- TestingPrefService* prefs = profile.GetTestingPrefService();
-
- // Set pattern for JavaScript setting.
- HostContentSettingsMap::Pattern pattern("[*.]example.com");
- host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_JAVASCRIPT, "", CONTENT_SETTING_BLOCK);
-
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_JAVASCRIPT));
-
- GURL host("http://example.com/");
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_JAVASCRIPT, ""));
-
- // Set managed-default-content-setting for content-settings-type JavaScript.
- prefs->SetManagedPref(prefs::kManagedDefaultJavaScriptSetting,
- Value::CreateIntegerValue(CONTENT_SETTING_ALLOW));
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_JAVASCRIPT, ""));
-}
-
-// Managed default content setting should have higher priority
-// than user defined patterns.
-TEST_F(HostContentSettingsMapTest,
- ManagedDefaultContentSettingIgnoreUserPattern) {
- TestingProfile profile;
- HostContentSettingsMap* host_content_settings_map =
- profile.GetHostContentSettingsMap();
- TestingPrefService* prefs = profile.GetTestingPrefService();
-
- // Block all JavaScript.
- host_content_settings_map->SetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_JAVASCRIPT, CONTENT_SETTING_BLOCK);
-
- // Set an exception to allow "[*.]example.com"
- HostContentSettingsMap::Pattern pattern("[*.]example.com");
- host_content_settings_map->SetContentSetting(pattern,
- CONTENT_SETTINGS_TYPE_JAVASCRIPT, "", CONTENT_SETTING_ALLOW);
-
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_JAVASCRIPT));
- GURL host("http://example.com/");
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_JAVASCRIPT, ""));
-
- // Set managed-default-content-settings-preferences.
- prefs->SetManagedPref(prefs::kManagedDefaultJavaScriptSetting,
- Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_JAVASCRIPT, ""));
-
- // Remove managed-default-content-settings-preferences.
- prefs->RemoveManagedPref(prefs::kManagedDefaultJavaScriptSetting);
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetContentSetting(
- host, CONTENT_SETTINGS_TYPE_JAVASCRIPT, ""));
-}
-
-// If a default-content-setting is set to managed setting, the user defined
-// setting should be preserved.
-TEST_F(HostContentSettingsMapTest, OverwrittenDefaultContentSetting) {
- TestingProfile profile;
- HostContentSettingsMap* host_content_settings_map =
- profile.GetHostContentSettingsMap();
- TestingPrefService* prefs = profile.GetTestingPrefService();
-
- // Set user defined default-content-setting for Cookies.
- host_content_settings_map->SetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_BLOCK);
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_COOKIES));
-
- // Set preference to manage the default-content-setting for Cookies.
- prefs->SetManagedPref(prefs::kManagedDefaultCookiesSetting,
- Value::CreateIntegerValue(CONTENT_SETTING_ALLOW));
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_COOKIES));
-
- // Remove the preference to manage the default-content-setting for Cookies.
- prefs->RemoveManagedPref(prefs::kManagedDefaultCookiesSetting);
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_COOKIES));
- }
-
-// When a default-content-setting is set to a managed setting a
-// CONTENT_SETTINGS_CHANGED notification should be fired. The same should happen
-// if the managed setting is removed.
-TEST_F(HostContentSettingsMapTest, ObserveManagedSettingsChange) {
- TestingProfile profile;
- HostContentSettingsMap* host_content_settings_map =
- profile.GetHostContentSettingsMap();
- StubSettingsObserver observer;
- TestingPrefService* prefs = profile.GetTestingPrefService();
-
- // TODO(markusheintz): I think it would be better to send notifications only
- // for a specific content-settings-type.
-
- // Set the managed default-content-setting.
- prefs->SetManagedPref(prefs::kManagedDefaultImagesSetting,
- Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
- EXPECT_EQ(host_content_settings_map, observer.last_notifier);
- EXPECT_EQ(HostContentSettingsMap::Pattern(), observer.last_pattern);
- EXPECT_EQ(CONTENT_SETTINGS_TYPE_DEFAULT, observer.last_type);
- EXPECT_TRUE(observer.last_update_all);
- EXPECT_TRUE(observer.last_update_all_types);
- EXPECT_EQ(1, observer.counter);
-
- // Remove the managed default-content-setting.
- prefs->RemoveManagedPref(prefs::kManagedDefaultImagesSetting);
- EXPECT_EQ(host_content_settings_map, observer.last_notifier);
- EXPECT_EQ(CONTENT_SETTINGS_TYPE_DEFAULT, observer.last_type);
- EXPECT_EQ(HostContentSettingsMap::Pattern(), observer.last_pattern);
- EXPECT_TRUE(observer.last_update_all);
- EXPECT_TRUE(observer.last_update_all_types);
- EXPECT_EQ(2, observer.counter);
-}
-
-// When a default-content-setting is set to a managed setting a
-// CONTENT_SETTINGS_CHANGED notification should be fired. The same should happen
-// if the managed setting is removed. In this test-case the actual managed
-// setting is the same. Just the managed status of the default-content-setting
-// changes.
-TEST_F(HostContentSettingsMapTest, ObserveManagedSettingsNoChange) {
- TestingProfile profile;
- HostContentSettingsMap* host_content_settings_map =
- profile.GetHostContentSettingsMap();
- StubSettingsObserver observer;
- TestingPrefService* prefs = profile.GetTestingPrefService();
-
- // TODO(markusheintz): I think it would be better to send notifications only
- // for a specific content-settings-type.
-
- // Set the managed default-content-setting. In this case the actual setting
- // does not change.
- prefs->SetManagedPref(prefs::kManagedDefaultImagesSetting,
- Value::CreateIntegerValue(CONTENT_SETTING_ALLOW));
- EXPECT_EQ(host_content_settings_map, observer.last_notifier);
- EXPECT_EQ(HostContentSettingsMap::Pattern(), observer.last_pattern);
- EXPECT_EQ(CONTENT_SETTINGS_TYPE_DEFAULT, observer.last_type);
- EXPECT_TRUE(observer.last_update_all);
- EXPECT_TRUE(observer.last_update_all_types);
- EXPECT_EQ(1, observer.counter);
-
- // Remove the managed default-content-setting.
- prefs->RemoveManagedPref(prefs::kManagedDefaultImagesSetting);
- EXPECT_EQ(host_content_settings_map, observer.last_notifier);
- EXPECT_EQ(CONTENT_SETTINGS_TYPE_DEFAULT, observer.last_type);
- EXPECT_EQ(HostContentSettingsMap::Pattern(), observer.last_pattern);
- EXPECT_TRUE(observer.last_update_all);
- EXPECT_TRUE(observer.last_update_all_types);
- EXPECT_EQ(2, observer.counter);
-}
-
-// If a setting for a default-content-setting-type is set while the type is
-// managed, then the new setting should be preserved and used after the
-// default-content-setting-type is not managed anymore.
-TEST_F(HostContentSettingsMapTest, SettingDefaultContentSettingsWhenManaged) {
- TestingProfile profile;
- HostContentSettingsMap* host_content_settings_map =
- profile.GetHostContentSettingsMap();
- TestingPrefService* prefs = profile.GetTestingPrefService();
-
- prefs->SetManagedPref(prefs::kManagedDefaultPluginsSetting,
- Value::CreateIntegerValue(CONTENT_SETTING_ALLOW));
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_PLUGINS));
-
- host_content_settings_map->SetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_PLUGINS, CONTENT_SETTING_BLOCK);
- EXPECT_EQ(CONTENT_SETTING_ALLOW,
- host_content_settings_map->GetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_PLUGINS));
-
- prefs->RemoveManagedPref(prefs::kManagedDefaultPluginsSetting);
- EXPECT_EQ(CONTENT_SETTING_BLOCK,
- host_content_settings_map->GetDefaultContentSetting(
- CONTENT_SETTINGS_TYPE_PLUGINS));
-}
-
-} // namespace
diff --git a/chrome/browser/host_zoom_map.cc b/chrome/browser/host_zoom_map.cc
index 19e55bb..3e6ce27 100644
--- a/chrome/browser/host_zoom_map.cc
+++ b/chrome/browser/host_zoom_map.cc
@@ -11,7 +11,7 @@
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prefs/scoped_pref_update.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/common/notification_details.h"
diff --git a/chrome/browser/host_zoom_map_unittest.cc b/chrome/browser/host_zoom_map_unittest.cc
index f77f96b..d99bfbf 100644
--- a/chrome/browser/host_zoom_map_unittest.cc
+++ b/chrome/browser/host_zoom_map_unittest.cc
@@ -12,7 +12,7 @@
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_observer_mock.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_profile.h"
@@ -129,4 +129,3 @@ TEST_F(HostZoomMapTest, ChangeDefaultZoomLevel) {
scoped_refptr<HostZoomMap> map(new HostZoomMap(&profile_));
EXPECT_EQ(kDefaultZoomLevel, map->GetZoomLevel(url_));
}
-
diff --git a/chrome/browser/idbbindingutilities_browsertest.cc b/chrome/browser/idbbindingutilities_browsertest.cc
index 6297d96..3f832b7 100644
--- a/chrome/browser/idbbindingutilities_browsertest.cc
+++ b/chrome/browser/idbbindingutilities_browsertest.cc
@@ -199,7 +199,7 @@ IN_PROC_BROWSER_TEST_F(InProcessBrowserTest, IDBKeyPathExtract) {
const int kId = 7;
std::vector<IndexedDBKey> expected_values;
IndexedDBKey value;
- value.Set(UTF8ToUTF16("zoo"));
+ value.SetString(UTF8ToUTF16("zoo"));
expected_values.push_back(value);
IndexedDBKey invalid_value;
@@ -262,7 +262,7 @@ IN_PROC_BROWSER_TEST_F(InProcessBrowserTest, IDBKeyPathMultipleCalls) {
// Call again with the Utility process in batch mode and with valid keys.
expected_values.clear();
IndexedDBKey value;
- value.Set(UTF8ToUTF16("zoo"));
+ value.SetString(UTF8ToUTF16("zoo"));
expected_values.push_back(value);
expected_values.push_back(invalid_value);
scoped_helper.SetExpected(kId + 1, expected_values, false);
diff --git a/chrome/browser/importer/firefox_importer_unittest_messages_internal.h b/chrome/browser/importer/firefox_importer_unittest_messages_internal.h
index 68b2582..fd70f7f 100644
--- a/chrome/browser/importer/firefox_importer_unittest_messages_internal.h
+++ b/chrome/browser/importer/firefox_importer_unittest_messages_internal.h
@@ -2,15 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// This header is meant to be included in multiple passes, hence no traditional
-// header guard.
-// See ipc_message_macros.h for explanation of the macros and passes.
-
#include "ipc/ipc_message_macros.h"
+#define IPC_MESSAGE_START FirefoxImporterUnittestMsgStart
+
// Messages definitions for messages sent between the unit test binary and
// a child process by FFUnitTestDecryptorProxy.
-IPC_BEGIN_MESSAGES(Test)
// Server->Child: Initialize the decrytor with the following paramters.
IPC_MESSAGE_CONTROL2(Msg_Decryptor_Init,
@@ -29,5 +26,3 @@ IPC_MESSAGE_CONTROL1(Msg_Decryptor_Response,
// Server->Child: Die.
IPC_MESSAGE_CONTROL0(Msg_Decryptor_Quit)
-
-IPC_END_MESSAGES(Test)
diff --git a/chrome/browser/importer/firefox_importer_unittest_utils_mac.cc b/chrome/browser/importer/firefox_importer_unittest_utils_mac.cc
index fbe3d3d..15ac4a2 100644
--- a/chrome/browser/importer/firefox_importer_unittest_utils_mac.cc
+++ b/chrome/browser/importer/firefox_importer_unittest_utils_mac.cc
@@ -14,19 +14,11 @@
#include "ipc/ipc_channel.h"
#include "ipc/ipc_descriptors.h"
#include "ipc/ipc_message.h"
-#include "ipc/ipc_message_utils.h"
#include "ipc/ipc_switches.h"
#include "testing/multiprocess_func_list.h"
-// Declaration of IPC Messages used for this test.
-#define MESSAGES_INTERNAL_FILE \
- "chrome/browser/importer/firefox_importer_unittest_messages_internal.h"
-#include "ipc/ipc_message_macros.h"
-
-// Definition of IPC Messages used for this test.
-#define MESSAGES_INTERNAL_IMPL_FILE \
- "chrome/browser/importer/firefox_importer_unittest_messages_internal.h"
-#include "ipc/ipc_message_impl_macros.h"
+#define IPC_MESSAGE_IMPL
+#include "chrome/browser/importer/firefox_importer_unittest_messages_internal.h"
namespace {
@@ -102,11 +94,14 @@ class FFDecryptorServerChannelListener : public IPC::Channel::Listener {
sender_->Send(new Msg_Decryptor_Quit());
}
- virtual void OnMessageReceived(const IPC::Message& msg) {
+ virtual bool OnMessageReceived(const IPC::Message& msg) {
+ bool handled = true;
IPC_BEGIN_MESSAGE_MAP(FFDecryptorServerChannelListener, msg)
IPC_MESSAGE_HANDLER(Msg_Decryptor_InitReturnCode, OnInitDecryptorResponse)
IPC_MESSAGE_HANDLER(Msg_Decryptor_Response, OnDecryptedTextResonse)
+ IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
+ return handled;
}
// If an error occured, just kill the message Loop.
@@ -239,12 +234,15 @@ class FFDecryptorClientChannelListener : public IPC::Channel::Listener {
MessageLoop::current()->Quit();
}
- virtual void OnMessageReceived(const IPC::Message& msg) {
+ virtual bool OnMessageReceived(const IPC::Message& msg) {
+ bool handled = true;
IPC_BEGIN_MESSAGE_MAP(FFDecryptorClientChannelListener, msg)
IPC_MESSAGE_HANDLER(Msg_Decryptor_Init, OnDecryptor_Init)
IPC_MESSAGE_HANDLER(Msg_Decrypt, OnDecrypt)
IPC_MESSAGE_HANDLER(Msg_Decryptor_Quit, OnQuitRequest)
+ IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
+ return handled;
}
virtual void OnChannelError() {
diff --git a/chrome/browser/importer/importer.cc b/chrome/browser/importer/importer.cc
index a9deb82..6379e7b 100644
--- a/chrome/browser/importer/importer.cc
+++ b/chrome/browser/importer/importer.cc
@@ -20,7 +20,7 @@
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/webdata/web_data_service.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
#include "gfx/codec/png_codec.h"
#include "gfx/favicon_size.h"
#include "grit/generated_resources.h"
@@ -33,7 +33,7 @@
#include "chrome/browser/views/importer_lock_view.h"
#include "views/window/window.h"
#elif defined(OS_MACOSX)
-#include "chrome/browser/cocoa/importer_lock_dialog.h"
+#include "chrome/browser/ui/cocoa/importer_lock_dialog.h"
#elif defined(TOOLKIT_USES_GTK)
#include "chrome/browser/gtk/import_lock_dialog_gtk.h"
#endif
@@ -42,6 +42,8 @@ using webkit_glue::PasswordForm;
// Importer.
+void Importer::Cancel() { cancelled_ = true; }
+
Importer::Importer()
: cancelled_(false),
import_to_bookmark_bar_(false),
@@ -85,8 +87,23 @@ ImporterHost::ImporterHost()
installed_bookmark_observer_(false),
is_source_readable_(true),
headless_(false),
- parent_window_(NULL) {
- importer_list_.DetectSourceProfiles();
+ parent_window_(NULL),
+ importer_list_(new ImporterList) {
+ importer_list_->DetectSourceProfilesHack();
+}
+
+ImporterHost::ImporterHost(ImporterList::Observer* observer)
+ : profile_(NULL),
+ observer_(NULL),
+ task_(NULL),
+ importer_(NULL),
+ waiting_for_bookmarkbar_model_(false),
+ installed_bookmark_observer_(false),
+ is_source_readable_(true),
+ headless_(false),
+ parent_window_(NULL),
+ importer_list_(new ImporterList) {
+ importer_list_->DetectSourceProfiles(observer);
}
ImporterHost::~ImporterHost() {
@@ -171,7 +188,7 @@ void ImporterHost::StartImportSettings(
// so that it doesn't block the UI. When the import is complete, observer
// will be notified.
writer_ = writer;
- importer_ = importer_list_.CreateImporterByType(profile_info.browser_type);
+ importer_ = ImporterList::CreateImporterByType(profile_info.browser_type);
// If we fail to create Importer, exit as we cannot do anything.
if (!importer_) {
ImportEnded();
@@ -307,6 +324,15 @@ ExternalProcessImporterHost::ExternalProcessImporterHost()
import_process_launched_(false) {
}
+ExternalProcessImporterHost::ExternalProcessImporterHost(
+ ImporterList::Observer* observer)
+ : ImporterHost(observer),
+ items_(0),
+ import_to_bookmark_bar_(false),
+ cancelled_(false),
+ import_process_launched_(false) {
+}
+
void ExternalProcessImporterHost::Loaded(BookmarkModel* model) {
DCHECK(model->IsLoaded());
model->RemoveObserver(this);
@@ -434,7 +460,7 @@ void ExternalProcessImporterClient::NotifyItemFinishedOnIOThread(
profile_import_process_host_->ReportImportItemFinished(import_item);
}
-void ExternalProcessImporterClient::OnProcessCrashed() {
+void ExternalProcessImporterClient::OnProcessCrashed(int exit_code) {
if (cancelled_)
return;
diff --git a/chrome/browser/importer/importer.h b/chrome/browser/importer/importer.h
index 1cb9db7..e994036 100644
--- a/chrome/browser/importer/importer.h
+++ b/chrome/browser/importer/importer.h
@@ -55,9 +55,37 @@ class ImporterHost : public base::RefCountedThreadSafe<ImporterHost>,
public BookmarkModelObserver,
public NotificationObserver {
public:
+ // An interface which an object can implement to be notified of events during
+ // the import process.
+ class Observer {
+ public:
+ // Invoked when data for the specified item is about to be collected.
+ virtual void ImportItemStarted(importer::ImportItem item) = 0;
+
+ // Invoked when data for the specified item has been collected from the
+ // source profile and is now ready for further processing.
+ virtual void ImportItemEnded(importer::ImportItem item) = 0;
+
+ // Invoked when the import begins.
+ virtual void ImportStarted() = 0;
+
+ // Invoked when the source profile has been imported.
+ virtual void ImportEnded() = 0;
+
+ protected:
+ virtual ~Observer() {}
+ };
+
+ // DEPRECATED: Calls the synchronous version of
+ // ImporterList::DetectSourceProfiles.
+ // TODO(jhawkins): Remove this constructor once all callers are fixed.
+ // See http://crbug.com/65633 and http://crbug.com/65638.
ImporterHost();
- // BookmarkModelObserver methods.
+ // |observer| must not be NULL.
+ explicit ImporterHost(ImporterList::Observer* observer);
+
+ // BookmarkModelObserver implementation.
virtual void Loaded(BookmarkModel* model);
virtual void BookmarkNodeMoved(BookmarkModel* model,
const BookmarkNode* old_parent,
@@ -79,10 +107,11 @@ class ImporterHost : public base::RefCountedThreadSafe<ImporterHost>,
const BookmarkNode* node) {}
virtual void BookmarkModelBeingDeleted(BookmarkModel* model);
- // NotificationObserver method. Called when TemplateURLModel has been loaded.
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
+ // NotificationObserver implementation. Called when TemplateURLModel has been
+ // loaded.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
// ShowWarningDialog() asks user to close the application that is owning the
// lock. They can retry or skip the importing process.
@@ -122,24 +151,6 @@ class ImporterHost : public base::RefCountedThreadSafe<ImporterHost>,
parent_window_ = parent_window;
}
- // An interface which an object can implement to be notified of events during
- // the import process.
- class Observer {
- public:
- virtual ~Observer() {}
- // Invoked when data for the specified item is about to be collected.
- virtual void ImportItemStarted(importer::ImportItem item) = 0;
-
- // Invoked when data for the specified item has been collected from the
- // source profile and is now ready for further processing.
- virtual void ImportItemEnded(importer::ImportItem item) = 0;
-
- // Invoked when the import begins.
- virtual void ImportStarted() = 0;
-
- // Invoked when the source profile has been imported.
- virtual void ImportEnded() = 0;
- };
void SetObserver(Observer* observer);
// A series of functions invoked at the start, during and end of the end
@@ -152,25 +163,30 @@ class ImporterHost : public base::RefCountedThreadSafe<ImporterHost>,
virtual void ImportEnded();
int GetAvailableProfileCount() const {
- return importer_list_.GetAvailableProfileCount();
+ return importer_list_->GetAvailableProfileCount();
}
// Returns the name of the profile at the 'index' slot. The profiles are
// ordered such that the profile at index 0 is the likely default browser.
std::wstring GetSourceProfileNameAt(int index) const {
- return importer_list_.GetSourceProfileNameAt(index);
+ return importer_list_->GetSourceProfileNameAt(index);
}
// Returns the ProfileInfo at the specified index. The ProfileInfo should be
// passed to StartImportSettings().
const importer::ProfileInfo& GetSourceProfileInfoAt(int index) const {
- return importer_list_.GetSourceProfileInfoAt(index);
+ return importer_list_->GetSourceProfileInfoAt(index);
}
// Returns the ProfileInfo with the given browser type.
const importer::ProfileInfo& GetSourceProfileInfoForBrowserType(
int browser_type) const {
- return importer_list_.GetSourceProfileInfoForBrowserType(browser_type);
+ return importer_list_->GetSourceProfileInfoForBrowserType(browser_type);
+ }
+
+ // Returns true if the source profiles have been loaded.
+ bool source_profiles_loaded() const {
+ return importer_list_->source_profiles_loaded();
}
protected:
@@ -240,7 +256,7 @@ class ImporterHost : public base::RefCountedThreadSafe<ImporterHost>,
virtual void InvokeTaskIfDone();
// Used to create an importer of the appropriate type.
- ImporterList importer_list_;
+ scoped_refptr<ImporterList> importer_list_;
DISALLOW_COPY_AND_ASSIGN(ImporterHost);
};
@@ -249,8 +265,14 @@ class ImporterHost : public base::RefCountedThreadSafe<ImporterHost>,
// the importer bridge and the external process importer client.
class ExternalProcessImporterHost : public ImporterHost {
public:
+ // DEPRECATED: Calls the deprecated ImporterHost constructor.
+ // TODO(jhawkins): Remove this constructor once all callers are fixed.
+ // See http://crbug.com/65633 and http://crbug.com/65638.
ExternalProcessImporterHost();
+ // |observer| must not be NULL.
+ explicit ExternalProcessImporterHost(ImporterList::Observer* observer);
+
// Called when the BookmarkModel has finished loading. Calls InvokeTaskIfDone
// to start importing.
virtual void Loaded(BookmarkModel* model);
@@ -327,7 +349,7 @@ class ExternalProcessImporterClient
void NotifyItemFinishedOnIOThread(importer::ImportItem import_item);
// Cancel import on process crash.
- virtual void OnProcessCrashed();
+ virtual void OnProcessCrashed(int exit_code);
// Notifies the importerhost that import has finished, and calls Release().
void Cleanup();
@@ -447,7 +469,7 @@ class Importer : public base::RefCountedThreadSafe<Importer> {
ImporterBridge* bridge) = 0;
// Cancels the import process.
- virtual void Cancel() { cancelled_ = true; }
+ virtual void Cancel();
void set_import_to_bookmark_bar(bool import_to_bookmark_bar) {
import_to_bookmark_bar_ = import_to_bookmark_bar;
diff --git a/chrome/browser/importer/importer_bridge.h b/chrome/browser/importer/importer_bridge.h
index 186821e..43667b5 100644
--- a/chrome/browser/importer/importer_bridge.h
+++ b/chrome/browser/importer/importer_bridge.h
@@ -6,14 +6,11 @@
#define CHROME_BROWSER_IMPORTER_IMPORTER_BRIDGE_H_
#pragma once
-#include "build/build_config.h"
-
#include <vector>
#include "base/basictypes.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/importer/importer_data_types.h"
// TODO: remove this, see friend declaration in ImporterBridge.
#include "chrome/browser/importer/toolbar_importer.h"
diff --git a/chrome/browser/importer/importer_list.cc b/chrome/browser/importer/importer_list.cc
index 6ac6517..10e1101 100644
--- a/chrome/browser/importer/importer_list.cc
+++ b/chrome/browser/importer/importer_list.cc
@@ -27,39 +27,95 @@
#include "chrome/browser/importer/safari_importer.h"
#endif
-ImporterList::ImporterList() {
+namespace {
+
+#if defined(OS_WIN)
+void DetectIEProfiles(std::vector<importer::ProfileInfo*>* profiles) {
+ // IE always exists and doesn't have multiple profiles.
+ ProfileInfo* ie = new ProfileInfo();
+ ie->description = l10n_util::GetString(IDS_IMPORT_FROM_IE);
+ ie->browser_type = importer::MS_IE;
+ ie->source_path.clear();
+ ie->app_path.clear();
+ ie->services_supported = importer::HISTORY | importer::FAVORITES |
+ importer::COOKIES | importer::PASSWORDS | importer::SEARCH_ENGINES;
+ profiles->push_back(ie);
}
+#endif // defined(OS_WIN)
-ImporterList::~ImporterList() {
- STLDeleteContainerPointers(source_profiles_.begin(), source_profiles_.end());
+#if defined(OS_MACOSX)
+void DetectSafariProfiles(std::vector<importer::ProfileInfo*>* profiles) {
+ uint16 items = importer::NONE;
+ if (!SafariImporter::CanImport(mac_util::GetUserLibraryPath(), &items))
+ return;
+
+ importer::ProfileInfo* safari = new importer::ProfileInfo();
+ safari->browser_type = importer::SAFARI;
+ safari->description = l10n_util::GetString(IDS_IMPORT_FROM_SAFARI);
+ safari->source_path.clear();
+ safari->app_path.clear();
+ safari->services_supported = items;
+ profiles->push_back(safari);
}
+#endif // defined(OS_MACOSX)
-void ImporterList::DetectSourceProfiles() {
-// The first run import will automatically take settings from the first
-// profile detected, which should be the user's current default.
+void DetectFirefoxProfiles(std::vector<importer::ProfileInfo*>* profiles) {
+ FilePath profile_path = GetFirefoxProfilePath();
+ if (profile_path.empty())
+ return;
+
+ // Detects which version of Firefox is installed.
+ importer::ProfileType firefox_type;
+ FilePath app_path;
+ int version = 0;
#if defined(OS_WIN)
- if (ShellIntegration::IsFirefoxDefaultBrowser()) {
- DetectFirefoxProfiles();
- DetectIEProfiles();
- } else {
- DetectIEProfiles();
- DetectFirefoxProfiles();
- }
- // TODO(brg) : Current UI requires win_util.
- DetectGoogleToolbarProfiles();
-#elif defined(OS_MACOSX)
- if (ShellIntegration::IsFirefoxDefaultBrowser()) {
- DetectFirefoxProfiles();
- DetectSafariProfiles();
+ version = GetCurrentFirefoxMajorVersionFromRegistry();
+#endif
+ if (version < 2)
+ GetFirefoxVersionAndPathFromProfile(profile_path, &version, &app_path);
+
+ if (version == 2) {
+ firefox_type = importer::FIREFOX2;
+ } else if (version >= 3) {
+ firefox_type = importer::FIREFOX3;
} else {
- DetectSafariProfiles();
- DetectFirefoxProfiles();
+ // Ignores other versions of firefox.
+ return;
}
-#else
- DetectFirefoxProfiles();
+
+ importer::ProfileInfo* firefox = new importer::ProfileInfo();
+ firefox->description = l10n_util::GetString(IDS_IMPORT_FROM_FIREFOX);
+ firefox->browser_type = firefox_type;
+ firefox->source_path = profile_path;
+#if defined(OS_WIN)
+ firefox->app_path = FilePath::FromWStringHack(
+ GetFirefoxInstallPathFromRegistry());
#endif
+ if (firefox->app_path.empty())
+ firefox->app_path = app_path;
+ firefox->services_supported = importer::HISTORY | importer::FAVORITES |
+ importer::PASSWORDS | importer::SEARCH_ENGINES;
+ profiles->push_back(firefox);
+}
+
+void DetectGoogleToolbarProfiles(
+ std::vector<importer::ProfileInfo*>* profiles) {
+ if (FirstRun::IsChromeFirstRun())
+ return;
+
+ importer::ProfileInfo* google_toolbar = new importer::ProfileInfo();
+ google_toolbar->browser_type = importer::GOOGLE_TOOLBAR5;
+ google_toolbar->description = l10n_util::GetString(
+ IDS_IMPORT_FROM_GOOGLE_TOOLBAR);
+ google_toolbar->source_path.clear();
+ google_toolbar->app_path.clear();
+ google_toolbar->services_supported = importer::FAVORITES;
+ profiles->push_back(google_toolbar);
}
+} // namespace
+
+// static
Importer* ImporterList::CreateImporterByType(importer::ProfileType type) {
switch (type) {
#if defined(OS_WIN)
@@ -85,23 +141,53 @@ Importer* ImporterList::CreateImporterByType(importer::ProfileType type) {
return NULL;
}
+ImporterList::ImporterList()
+ : source_thread_id_(BrowserThread::UI),
+ observer_(NULL),
+ source_profiles_loaded_(false) {
+}
+
+ImporterList::~ImporterList() {
+}
+
+void ImporterList::DetectSourceProfiles(Observer* observer) {
+ DCHECK(observer);
+ observer_ = observer;
+
+ BrowserThread::GetCurrentThreadIdentifier(&source_thread_id_);
+
+ BrowserThread::PostTask(
+ BrowserThread::FILE,
+ FROM_HERE,
+ NewRunnableMethod(this, &ImporterList::DetectSourceProfilesWorker));
+}
+
+void ImporterList::DetectSourceProfilesHack() {
+ DetectSourceProfilesWorker();
+}
+
int ImporterList::GetAvailableProfileCount() const {
+ DCHECK(source_profiles_loaded_);
return static_cast<int>(source_profiles_.size());
}
std::wstring ImporterList::GetSourceProfileNameAt(int index) const {
+ DCHECK(source_profiles_loaded_);
DCHECK(index >=0 && index < GetAvailableProfileCount());
return source_profiles_[index]->description;
}
const importer::ProfileInfo& ImporterList::GetSourceProfileInfoAt(
int index) const {
+ DCHECK(source_profiles_loaded_);
DCHECK(index >=0 && index < GetAvailableProfileCount());
return *source_profiles_[index];
}
const importer::ProfileInfo& ImporterList::GetSourceProfileInfoForBrowserType(
int browser_type) const {
+ DCHECK(source_profiles_loaded_);
+
int count = GetAvailableProfileCount();
for (int i = 0; i < count; ++i) {
if (source_profiles_[i]->browser_type == browser_type)
@@ -111,83 +197,66 @@ const importer::ProfileInfo& ImporterList::GetSourceProfileInfoForBrowserType(
return *(new importer::ProfileInfo());
}
-#if defined(OS_WIN)
-void ImporterList::DetectIEProfiles() {
- // IE always exists and don't have multiple profiles.
- ProfileInfo* ie = new ProfileInfo();
- ie->description = l10n_util::GetString(IDS_IMPORT_FROM_IE);
- ie->browser_type = importer::MS_IE;
- ie->source_path.clear();
- ie->app_path.clear();
- ie->services_supported = importer::HISTORY | importer::FAVORITES |
- importer::COOKIES | importer::PASSWORDS | importer::SEARCH_ENGINES;
- source_profiles_.push_back(ie);
+bool ImporterList::source_profiles_loaded() const {
+ return source_profiles_loaded_;
}
-#endif
-void ImporterList::DetectFirefoxProfiles() {
- FilePath profile_path = GetFirefoxProfilePath();
- if (profile_path.empty())
- return;
+void ImporterList::DetectSourceProfilesWorker() {
+ // TODO(jhawkins): Remove this condition once DetectSourceProfileHack is
+ // removed. |observer_| is NULL when said method is called.
+ if (observer_)
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- // Detects which version of Firefox is installed.
- importer::ProfileType firefox_type;
- FilePath app_path;
- int version = 0;
-#if defined(OS_WIN)
- version = GetCurrentFirefoxMajorVersionFromRegistry();
-#endif
- if (version < 2)
- GetFirefoxVersionAndPathFromProfile(profile_path, &version, &app_path);
+ std::vector<importer::ProfileInfo*> profiles;
- if (version == 2) {
- firefox_type = importer::FIREFOX2;
- } else if (version >= 3) {
- firefox_type = importer::FIREFOX3;
+// The first run import will automatically take settings from the first
+// profile detected, which should be the user's current default.
+#if defined(OS_WIN)
+ if (ShellIntegration::IsFirefoxDefaultBrowser()) {
+ DetectFirefoxProfiles(&profiles);
+ DetectIEProfiles(&profiles);
} else {
- // Ignores other versions of firefox.
- return;
+ DetectIEProfiles(&profiles);
+ DetectFirefoxProfiles(&profiles);
}
-
- importer::ProfileInfo* firefox = new importer::ProfileInfo();
- firefox->description = l10n_util::GetString(IDS_IMPORT_FROM_FIREFOX);
- firefox->browser_type = firefox_type;
- firefox->source_path = profile_path;
-#if defined(OS_WIN)
- firefox->app_path = FilePath::FromWStringHack(
- GetFirefoxInstallPathFromRegistry());
+ // TODO(brg) : Current UI requires win_util.
+ DetectGoogleToolbarProfiles(&profiles);
+#elif defined(OS_MACOSX)
+ if (ShellIntegration::IsFirefoxDefaultBrowser()) {
+ DetectFirefoxProfiles(&profiles);
+ DetectSafariProfiles(&profiles);
+ } else {
+ DetectSafariProfiles(&profiles);
+ DetectFirefoxProfiles(&profiles);
+ }
+#else
+ DetectFirefoxProfiles(&profiles);
#endif
- if (firefox->app_path.empty())
- firefox->app_path = app_path;
- firefox->services_supported = importer::HISTORY | importer::FAVORITES |
- importer::PASSWORDS | importer::SEARCH_ENGINES;
- source_profiles_.push_back(firefox);
-}
-
-void ImporterList::DetectGoogleToolbarProfiles() {
- if (!FirstRun::IsChromeFirstRun()) {
- importer::ProfileInfo* google_toolbar = new importer::ProfileInfo();
- google_toolbar->browser_type = importer::GOOGLE_TOOLBAR5;
- google_toolbar->description = l10n_util::GetString(
- IDS_IMPORT_FROM_GOOGLE_TOOLBAR);
- google_toolbar->source_path.clear();
- google_toolbar->app_path.clear();
- google_toolbar->services_supported = importer::FAVORITES;
- source_profiles_.push_back(google_toolbar);
+
+ // TODO(jhawkins): Remove this condition once DetectSourceProfileHack is
+ // removed. |observer_| is NULL when said method is called.
+ if (observer_) {
+ BrowserThread::PostTask(
+ source_thread_id_,
+ FROM_HERE,
+ NewRunnableMethod(this, &ImporterList::SourceProfilesLoaded, profiles));
+ } else {
+ source_profiles_->assign(profiles.begin(), profiles.end());
+ source_profiles_loaded_ = true;
}
}
-#if defined(OS_MACOSX)
-void ImporterList::DetectSafariProfiles() {
- uint16 items = importer::NONE;
- if (SafariImporter::CanImport(mac_util::GetUserLibraryPath(), &items)) {
- importer::ProfileInfo* safari = new importer::ProfileInfo();
- safari->browser_type = importer::SAFARI;
- safari->description = l10n_util::GetString(IDS_IMPORT_FROM_SAFARI);
- safari->source_path.clear();
- safari->app_path.clear();
- safari->services_supported = items;
- source_profiles_.push_back(safari);
- }
+void ImporterList::SourceProfilesLoaded(
+ const std::vector<importer::ProfileInfo*>& profiles) {
+ DCHECK_NE(static_cast<Observer*>(NULL), observer_);
+
+ BrowserThread::ID current_thread_id;
+ BrowserThread::GetCurrentThreadIdentifier(&current_thread_id);
+ DCHECK_EQ(current_thread_id, source_thread_id_);
+
+ source_profiles_->assign(profiles.begin(), profiles.end());
+ source_profiles_loaded_ = true;
+ observer_->SourceProfilesLoaded();
+ observer_ = NULL;
+ source_thread_id_ = BrowserThread::UI;
}
-#endif // OS_MACOSX
diff --git a/chrome/browser/importer/importer_list.h b/chrome/browser/importer/importer_list.h
index 6f98046..f3db148 100644
--- a/chrome/browser/importer/importer_list.h
+++ b/chrome/browser/importer/importer_list.h
@@ -9,23 +9,42 @@
#include <string>
#include <vector>
-#include "build/build_config.h"
#include "base/basictypes.h"
+#include "base/platform_thread.h"
+#include "base/ref_counted.h"
+#include "base/scoped_vector.h"
+#include "build/build_config.h"
+#include "chrome/browser/browser_thread.h"
#include "chrome/browser/importer/importer_data_types.h"
class Importer;
-class ImporterList {
+class ImporterList : public base::RefCountedThreadSafe<ImporterList> {
public:
+ // Any class calling DetectSourceProfiles() must implement this interface in
+ // order to be called back when the source profiles are loaded.
+ class Observer {
+ public:
+ virtual void SourceProfilesLoaded() = 0;
+
+ protected:
+ virtual ~Observer() {}
+ };
+
+ static Importer* CreateImporterByType(importer::ProfileType type);
+
ImporterList();
- ~ImporterList();
// Detects the installed browsers and their associated profiles, then
// stores their information in a list. It returns the list of description
- // of all profiles.
- void DetectSourceProfiles();
+ // of all profiles. Calls into DetectSourceProfilesWorker() on the FILE thread
+ // to do the real work of detecting source profiles. |observer| must be
+ // non-NULL.
+ void DetectSourceProfiles(Observer* observer);
- Importer* CreateImporterByType(importer::ProfileType type);
+ // DEPRECATED: This method is synchronous and performs file operations which
+ // may end up blocking the current thread, which is usually the UI thread.
+ void DetectSourceProfilesHack();
// Returns the number of different browser profiles you can import from.
int GetAvailableProfileCount() const;
@@ -42,19 +61,38 @@ class ImporterList {
const importer::ProfileInfo& GetSourceProfileInfoForBrowserType(
int browser_type) const;
- // Helper methods for detecting available profiles.
-#if defined(OS_WIN)
- void DetectIEProfiles();
-#endif
- void DetectFirefoxProfiles();
- void DetectGoogleToolbarProfiles();
-#if defined(OS_MACOSX)
- void DetectSafariProfiles();
-#endif
+ // Returns true if the source profiles have been loaded.
+ bool source_profiles_loaded() const;
private:
+ friend class base::RefCountedThreadSafe<ImporterList>;
+
+ ~ImporterList();
+
+ // The worker method for DetectSourceProfiles(). Must be called on the FILE
+ // thread.
+ void DetectSourceProfilesWorker();
+
+ // Called by DetectSourceProfilesWorker() on the source thread. This method
+ // notifies |observer_| that the source profiles are loaded. |profiles| is
+ // the vector of loaded profiles.
+ void SourceProfilesLoaded(
+ const std::vector<importer::ProfileInfo*>& profiles);
+
// The list of profiles with the default one first.
- std::vector<importer::ProfileInfo*> source_profiles_;
+ ScopedVector<importer::ProfileInfo> source_profiles_;
+
+ // The ID of the thread DetectSourceProfiles() is called on. Only valid after
+ // DetectSourceProfiles() is called and until SourceProfilesLoaded() has
+ // returned.
+ BrowserThread::ID source_thread_id_;
+
+ // Weak reference. Only valid after DetectSourceProfiles() is called and until
+ // SourceProfilesLoaded() has returned.
+ Observer* observer_;
+
+ // True if source profiles are loaded.
+ bool source_profiles_loaded_;
DISALLOW_COPY_AND_ASSIGN(ImporterList);
};
diff --git a/chrome/browser/importer/importer_messages.cc b/chrome/browser/importer/importer_messages.cc
index d20452a..9120a2b 100644
--- a/chrome/browser/importer/importer_messages.cc
+++ b/chrome/browser/importer/importer_messages.cc
@@ -2,10 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/importer/importer_messages.h"
-
#include "base/values.h"
-#define MESSAGES_INTERNAL_IMPL_FILE \
- "chrome/browser/importer/importer_messages_internal.h"
-#include "ipc/ipc_message_impl_macros.h"
+#define IPC_MESSAGE_IMPL
+#include "chrome/browser/importer/importer_messages.h"
diff --git a/chrome/browser/importer/importer_messages.h b/chrome/browser/importer/importer_messages.h
index fd7b1dc..e05aac8 100644
--- a/chrome/browser/importer/importer_messages.h
+++ b/chrome/browser/importer/importer_messages.h
@@ -363,8 +363,6 @@ struct ParamTraits<TemplateURL> {
} // namespace IPC
-#define MESSAGES_INTERNAL_FILE \
- "chrome/browser/importer/importer_messages_internal.h"
-#include "ipc/ipc_message_macros.h"
+#include "chrome/browser/importer/importer_messages_internal.h"
#endif // CHROME_BROWSER_IMPORTER_IMPORTER_MESSAGES_H_
diff --git a/chrome/browser/importer/importer_messages_internal.h b/chrome/browser/importer/importer_messages_internal.h
index 980e397..20e7770 100644
--- a/chrome/browser/importer/importer_messages_internal.h
+++ b/chrome/browser/importer/importer_messages_internal.h
@@ -10,73 +10,70 @@
#include "ipc/ipc_message_macros.h"
#include "webkit/glue/password_form.h"
+#define IPC_MESSAGE_START ProfileImportMsgStart
+
//-----------------------------------------------------------------------------
// ProfileImportProcess messages
// These are messages sent from the browser to the profile import process.
-IPC_BEGIN_MESSAGES(ProfileImportProcess)
- IPC_MESSAGE_CONTROL4(ProfileImportProcessMsg_StartImport,
- importer::ProfileInfo /* ProfileInfo struct */,
- int /* bitmask of items to import */,
- DictionaryValue /* localized strings */,
- bool /* import to bookmark bar */)
+IPC_MESSAGE_CONTROL4(ProfileImportProcessMsg_StartImport,
+ importer::ProfileInfo /* ProfileInfo struct */,
+ int /* bitmask of items to import */,
+ DictionaryValue /* localized strings */,
+ bool /* import to bookmark bar */)
- IPC_MESSAGE_CONTROL0(ProfileImportProcessMsg_CancelImport)
+IPC_MESSAGE_CONTROL0(ProfileImportProcessMsg_CancelImport)
- IPC_MESSAGE_CONTROL1(ProfileImportProcessMsg_ReportImportItemFinished,
- int /* ImportItem */)
-IPC_END_MESSAGES(ProfileImportProcess)
+IPC_MESSAGE_CONTROL1(ProfileImportProcessMsg_ReportImportItemFinished,
+ int /* ImportItem */)
//---------------------------------------------------------------------------
// ProfileImportProcessHost messages
// These are messages sent from the profile import process to the browser.
-IPC_BEGIN_MESSAGES(ProfileImportProcessHost)
- // These messages send information about the status of the import and
- // individual import tasks.
- IPC_MESSAGE_CONTROL0(ProfileImportProcessHostMsg_Import_Started)
-
- IPC_MESSAGE_CONTROL2(ProfileImportProcessHostMsg_Import_Finished,
- bool /* was import successful? */,
- std::string /* error message, if any */)
+// These messages send information about the status of the import and
+// individual import tasks.
+IPC_MESSAGE_CONTROL0(ProfileImportProcessHostMsg_Import_Started)
- IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_ImportItem_Started,
- int /* ImportItem */)
+IPC_MESSAGE_CONTROL2(ProfileImportProcessHostMsg_Import_Finished,
+ bool /* was import successful? */,
+ std::string /* error message, if any */)
- IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_ImportItem_Finished,
- int /* ImportItem */)
+IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_ImportItem_Started,
+ int /* ImportItem */)
- // These messages send data from the external importer process back to
- // the process host so it can be written to the profile.
- IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_NotifyHistoryImportStart,
- int /* total number of history::URLRow items */)
+IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_ImportItem_Finished,
+ int /* ImportItem */)
- IPC_MESSAGE_CONTROL2(ProfileImportProcessHostMsg_NotifyHistoryImportGroup,
- std::vector<history::URLRow>,
- int /* the source of URLs as in history::VisitSource.*/
- /* To simplify IPC call, pass as an integer */)
+// These messages send data from the external importer process back to
+// the process host so it can be written to the profile.
+IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_NotifyHistoryImportStart,
+ int /* total number of history::URLRow items */)
- IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_NotifyHomePageImportReady,
- GURL /* GURL of home page */)
+IPC_MESSAGE_CONTROL2(ProfileImportProcessHostMsg_NotifyHistoryImportGroup,
+ std::vector<history::URLRow>,
+ int /* the source of URLs as in history::VisitSource.*/
+ /* To simplify IPC call, pass as an integer */)
- IPC_MESSAGE_CONTROL3(ProfileImportProcessHostMsg_NotifyBookmarksImportStart,
- std::wstring /* first folder name */,
- int /* options */,
- int /* total number of bookmarks */)
+IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_NotifyHomePageImportReady,
+ GURL /* GURL of home page */)
- IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_NotifyBookmarksImportGroup,
- std::vector<ProfileWriter::BookmarkEntry>)
+IPC_MESSAGE_CONTROL3(ProfileImportProcessHostMsg_NotifyBookmarksImportStart,
+ std::wstring /* first folder name */,
+ int /* options */,
+ int /* total number of bookmarks */)
- IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_NotifyFavIconsImportStart,
- int /* total number of FavIcons */)
+IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_NotifyBookmarksImportGroup,
+ std::vector<ProfileWriter::BookmarkEntry>)
- IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_NotifyFavIconsImportGroup,
- std::vector<history::ImportedFavIconUsage> )
+IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_NotifyFavIconsImportStart,
+ int /* total number of FavIcons */)
- IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_NotifyPasswordFormReady,
- webkit_glue::PasswordForm )
+IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_NotifyFavIconsImportGroup,
+ std::vector<history::ImportedFavIconUsage> )
- IPC_MESSAGE_CONTROL3(ProfileImportProcessHostMsg_NotifyKeywordsReady,
- std::vector<TemplateURL>,
- int, /* default keyword index */
- bool /* unique on host and path */)
-IPC_END_MESSAGES(ProfileImportProcessHost)
+IPC_MESSAGE_CONTROL1(ProfileImportProcessHostMsg_NotifyPasswordFormReady,
+ webkit_glue::PasswordForm )
+IPC_MESSAGE_CONTROL3(ProfileImportProcessHostMsg_NotifyKeywordsReady,
+ std::vector<TemplateURL>,
+ int, /* default keyword index */
+ bool /* unique on host and path */)
diff --git a/chrome/browser/importer/importer_unittest.cc b/chrome/browser/importer/importer_unittest.cc
index 214f056..56ac2cc 100644
--- a/chrome/browser/importer/importer_unittest.cc
+++ b/chrome/browser/importer/importer_unittest.cc
@@ -29,14 +29,13 @@
#include "chrome/browser/importer/importer.h"
#include "chrome/browser/importer/importer_bridge.h"
#include "chrome/browser/importer/importer_data_types.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/common/chrome_paths.h"
#include "webkit/glue/password_form.h"
#if defined(OS_WIN)
-#include "base/scoped_comptr_win.h"
#include "app/win_util.h"
+#include "base/scoped_comptr_win.h"
#include "chrome/browser/importer/ie_importer.h"
#include "chrome/browser/password_manager/ie7_password.h"
#endif
diff --git a/chrome/browser/importer/profile_writer.cc b/chrome/browser/importer/profile_writer.cc
index 57ddffc..68e5c96 100644
--- a/chrome/browser/importer/profile_writer.cc
+++ b/chrome/browser/importer/profile_writer.cc
@@ -11,7 +11,7 @@
#include "chrome/browser/importer/importer.h"
#include "chrome/browser/password_manager/password_store.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/common/notification_service.h"
diff --git a/chrome/browser/importer/toolbar_importer.cc b/chrome/browser/importer/toolbar_importer.cc
index da367f8..cc3411c 100644
--- a/chrome/browser/importer/toolbar_importer.cc
+++ b/chrome/browser/importer/toolbar_importer.cc
@@ -16,7 +16,7 @@
#include "chrome/browser/first_run/first_run.h"
#include "chrome/browser/importer/importer_bridge.h"
#include "chrome/browser/importer/importer_data_types.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/libxml_utils.h"
#include "chrome/common/net/url_request_context_getter.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/in_process_webkit/browser_webkitclient_impl.cc b/chrome/browser/in_process_webkit/browser_webkitclient_impl.cc
index afe12ca..57a0a14 100644
--- a/chrome/browser/in_process_webkit/browser_webkitclient_impl.cc
+++ b/chrome/browser/in_process_webkit/browser_webkitclient_impl.cc
@@ -6,7 +6,7 @@
#include "base/file_util.h"
#include "base/logging.h"
-#include "chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h"
+#include "chrome/browser/in_process_webkit/dom_storage_message_filter.h"
#include "chrome/browser/in_process_webkit/indexed_db_key_utility_client.h"
#include "chrome/common/indexed_db_key.h"
#include "chrome/common/serialized_script_value.h"
@@ -131,8 +131,8 @@ void BrowserWebKitClientImpl::dispatchStorageEvent(
if (!is_local_storage)
return;
- DOMStorageDispatcherHost::DispatchStorageEvent(key, old_value, new_value,
- origin, url, is_local_storage);
+ DOMStorageMessageFilter::DispatchStorageEvent(key, old_value, new_value,
+ origin, url, is_local_storage);
}
WebKit::WebSharedWorkerRepository*
@@ -148,10 +148,8 @@ int BrowserWebKitClientImpl::databaseDeleteFile(
}
void BrowserWebKitClientImpl::idbShutdown() {
- if (indexed_db_key_utility_client_.get()) {
+ if (indexed_db_key_utility_client_.get())
indexed_db_key_utility_client_->EndUtilityProcess();
- indexed_db_key_utility_client_ = NULL;
- }
}
void BrowserWebKitClientImpl::createIDBKeysFromSerializedValuesAndKeyPath(
diff --git a/chrome/browser/in_process_webkit/dom_storage_area.cc b/chrome/browser/in_process_webkit/dom_storage_area.cc
index e0e9b74..fdf2ebc 100644
--- a/chrome/browser/in_process_webkit/dom_storage_area.cc
+++ b/chrome/browser/in_process_webkit/dom_storage_area.cc
@@ -5,11 +5,9 @@
#include "chrome/browser/in_process_webkit/dom_storage_area.h"
#include "base/task.h"
-#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/in_process_webkit/dom_storage_context.h"
-#include "chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h"
#include "chrome/browser/in_process_webkit/dom_storage_namespace.h"
-#include "chrome/browser/host_content_settings_map.h"
#include "chrome/common/render_messages.h"
#include "third_party/WebKit/WebKit/chromium/public/WebSecurityOrigin.h"
#include "third_party/WebKit/WebKit/chromium/public/WebStorageArea.h"
@@ -56,8 +54,8 @@ NullableString16 DOMStorageArea::GetItem(const string16& key) {
NullableString16 DOMStorageArea::SetItem(
const string16& key, const string16& value,
- WebStorageArea::Result* result, DOMStorageDispatcherHost* sender) {
- if (!CheckContentSetting(key, value, sender)) {
+ WebStorageArea::Result* result) {
+ if (!CheckContentSetting(key, value)) {
*result = WebStorageArea::ResultBlockedByPolicy;
return NullableString16(true); // Ignored if the content was blocked.
}
@@ -92,8 +90,7 @@ void DOMStorageArea::CreateWebStorageAreaIfNecessary() {
}
bool DOMStorageArea::CheckContentSetting(
- const string16& key, const string16& value,
- DOMStorageDispatcherHost* sender) {
+ const string16& key, const string16& value) {
ContentSetting content_setting =
host_content_settings_map_->GetContentSetting(
origin_url_, CONTENT_SETTINGS_TYPE_COOKIES, "");
diff --git a/chrome/browser/in_process_webkit/dom_storage_area.h b/chrome/browser/in_process_webkit/dom_storage_area.h
index 7740bb9..cf5a0c7 100644
--- a/chrome/browser/in_process_webkit/dom_storage_area.h
+++ b/chrome/browser/in_process_webkit/dom_storage_area.h
@@ -15,7 +15,6 @@
#include "googleurl/src/gurl.h"
#include "third_party/WebKit/WebKit/chromium/public/WebStorageArea.h"
-class DOMStorageDispatcherHost;
class DOMStorageNamespace;
class HostContentSettingsMap;
@@ -32,14 +31,9 @@ class DOMStorageArea {
unsigned Length();
NullableString16 Key(unsigned index);
NullableString16 GetItem(const string16& key);
- // The DOMStorageDispatcherHost parameter is required in case we get a
- // CONTENT_SETTING_ASK response from the HostContentettingsMap. If we do,
- // we'll need to let the renderer know that it'll need to run a nested message
- // loop.
NullableString16 SetItem(
const string16& key, const string16& value,
- WebKit::WebStorageArea::Result* result,
- DOMStorageDispatcherHost* sender);
+ WebKit::WebStorageArea::Result* result);
NullableString16 RemoveItem(const string16& key);
bool Clear();
void PurgeMemory();
@@ -53,8 +47,7 @@ class DOMStorageArea {
void CreateWebStorageAreaIfNecessary();
// Used to see if setItem has permission to do its thing.
- bool CheckContentSetting(const string16& key, const string16& value,
- DOMStorageDispatcherHost* sender);
+ bool CheckContentSetting(const string16& key, const string16& value);
// The origin this storage area represents.
string16 origin_;
diff --git a/chrome/browser/in_process_webkit/dom_storage_browsertest.cc b/chrome/browser/in_process_webkit/dom_storage_browsertest.cc
new file mode 100644
index 0000000..fac7d42
--- /dev/null
+++ b/chrome/browser/in_process_webkit/dom_storage_browsertest.cc
@@ -0,0 +1,53 @@
+// 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.
+
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/scoped_temp_dir.h"
+#include "chrome/browser/in_process_webkit/dom_storage_context.h"
+#include "chrome/browser/in_process_webkit/webkit_context.h"
+#include "chrome/test/in_process_browser_test.h"
+#include "chrome/test/testing_profile.h"
+#include "chrome/test/thread_test_helper.h"
+
+typedef InProcessBrowserTest DOMStorageBrowserTest;
+
+// In proc browser test is needed here because ClearLocalState indirectly calls
+// WebKit's isMainThread through WebSecurityOrigin->SecurityOrigin.
+IN_PROC_BROWSER_TEST_F(DOMStorageBrowserTest, ClearLocalState) {
+ // Create test files.
+ ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ FilePath domstorage_dir = temp_dir.path().Append(
+ DOMStorageContext::kLocalStorageDirectory);
+ ASSERT_TRUE(file_util::CreateDirectory(domstorage_dir));
+
+ FilePath::StringType file_name_1(FILE_PATH_LITERAL("http_foo_0"));
+ file_name_1.append(DOMStorageContext::kLocalStorageExtension);
+ FilePath::StringType file_name_2(FILE_PATH_LITERAL("chrome-extension_foo_0"));
+ file_name_2.append(DOMStorageContext::kLocalStorageExtension);
+ FilePath temp_file_path_1 = domstorage_dir.Append(file_name_1);
+ FilePath temp_file_path_2 = domstorage_dir.Append(file_name_2);
+
+ ASSERT_EQ(1, file_util::WriteFile(temp_file_path_1, ".", 1));
+ ASSERT_EQ(1, file_util::WriteFile(temp_file_path_2, "o", 1));
+
+ // Create the scope which will ensure we run the destructor of the webkit
+ // context which should trigger the clean up.
+ {
+ TestingProfile profile;
+ WebKitContext *webkit_context = profile.GetWebKitContext();
+ webkit_context->dom_storage_context()->set_data_path(temp_dir.path());
+ webkit_context->set_clear_local_state_on_exit(true);
+ }
+ // Make sure we wait until the destructor has run.
+ scoped_refptr<ThreadTestHelper> helper(
+ new ThreadTestHelper(BrowserThread::WEBKIT));
+ ASSERT_TRUE(helper->Run());
+
+ // Because we specified https for scheme to be skipped the second file
+ // should survive and the first go into vanity.
+ ASSERT_FALSE(file_util::PathExists(temp_file_path_1));
+ ASSERT_TRUE(file_util::PathExists(temp_file_path_2));
+}
diff --git a/chrome/browser/in_process_webkit/dom_storage_context.cc b/chrome/browser/in_process_webkit/dom_storage_context.cc
index 28f1d84..1d6d627 100644
--- a/chrome/browser/in_process_webkit/dom_storage_context.cc
+++ b/chrome/browser/in_process_webkit/dom_storage_context.cc
@@ -14,12 +14,35 @@
#include "chrome/browser/in_process_webkit/dom_storage_namespace.h"
#include "chrome/browser/in_process_webkit/webkit_context.h"
#include "chrome/common/dom_storage_common.h"
+#include "chrome/common/url_constants.h"
#include "third_party/WebKit/WebKit/chromium/public/WebSecurityOrigin.h"
#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
#include "webkit/glue/webkit_glue.h"
using WebKit::WebSecurityOrigin;
+namespace {
+
+void ClearLocalState(const FilePath& domstorage_path,
+ const char* url_scheme_to_be_skipped) {
+ file_util::FileEnumerator file_enumerator(
+ domstorage_path, false, file_util::FileEnumerator::FILES);
+ for (FilePath file_path = file_enumerator.Next(); !file_path.empty();
+ file_path = file_enumerator.Next()) {
+ if (file_path.Extension() == DOMStorageContext::kLocalStorageExtension) {
+ WebSecurityOrigin web_security_origin =
+ WebSecurityOrigin::createFromDatabaseIdentifier(
+ webkit_glue::FilePathToWebString(file_path.BaseName()));
+ if (!EqualsASCII(web_security_origin.protocol(),
+ url_scheme_to_be_skipped)) {
+ file_util::Delete(file_path, false);
+ }
+ }
+ }
+}
+
+} // namespace
+
const FilePath::CharType DOMStorageContext::kLocalStorageDirectory[] =
FILE_PATH_LITERAL("Local Storage");
@@ -44,18 +67,27 @@ DOMStorageContext::DOMStorageContext(WebKitContext* webkit_context)
: last_storage_area_id_(0),
last_session_storage_namespace_id_on_ui_thread_(kLocalStorageNamespaceId),
last_session_storage_namespace_id_on_io_thread_(kLocalStorageNamespaceId),
- webkit_context_(webkit_context) {
+ clear_local_state_on_exit_(false) {
+ data_path_ = webkit_context->data_path();
}
DOMStorageContext::~DOMStorageContext() {
- // This should not go away until all DOM Storage Dispatcher hosts have gone
+ // This should not go away until all DOM Storage message filters have gone
// away. And they remove themselves from this list.
- DCHECK(dispatcher_host_set_.empty());
+ DCHECK(message_filter_set_.empty());
for (StorageNamespaceMap::iterator iter(storage_namespace_map_.begin());
iter != storage_namespace_map_.end(); ++iter) {
delete iter->second;
}
+
+ // Not being on the WEBKIT thread here means we are running in a unit test
+ // where no clean up is needed.
+ if (clear_local_state_on_exit_ &&
+ BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)) {
+ ClearLocalState(data_path_.Append(kLocalStorageDirectory),
+ chrome::kExtensionScheme);
+ }
}
int64 DOMStorageContext::AllocateStorageAreaId() {
@@ -125,26 +157,26 @@ DOMStorageNamespace* DOMStorageContext::GetStorageNamespace(
return CreateSessionStorage(id);
}
-void DOMStorageContext::RegisterDispatcherHost(
- DOMStorageDispatcherHost* dispatcher_host) {
+void DOMStorageContext::RegisterMessageFilter(
+ DOMStorageMessageFilter* message_filter) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK(dispatcher_host_set_.find(dispatcher_host) ==
- dispatcher_host_set_.end());
- dispatcher_host_set_.insert(dispatcher_host);
+ DCHECK(message_filter_set_.find(message_filter) ==
+ message_filter_set_.end());
+ message_filter_set_.insert(message_filter);
}
-void DOMStorageContext::UnregisterDispatcherHost(
- DOMStorageDispatcherHost* dispatcher_host) {
+void DOMStorageContext::UnregisterMessageFilter(
+ DOMStorageMessageFilter* message_filter) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK(dispatcher_host_set_.find(dispatcher_host) !=
- dispatcher_host_set_.end());
- dispatcher_host_set_.erase(dispatcher_host);
+ DCHECK(message_filter_set_.find(message_filter) !=
+ message_filter_set_.end());
+ message_filter_set_.erase(message_filter);
}
-const DOMStorageContext::DispatcherHostSet*
-DOMStorageContext::GetDispatcherHostSet() const {
+const DOMStorageContext::MessageFilterSet*
+DOMStorageContext::GetMessageFilterSet() const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- return &dispatcher_host_set_;
+ return &message_filter_set_;
}
void DOMStorageContext::PurgeMemory() {
@@ -167,7 +199,7 @@ void DOMStorageContext::DeleteDataModifiedSince(
PurgeMemory();
file_util::FileEnumerator file_enumerator(
- webkit_context_->data_path().Append(kLocalStorageDirectory), false,
+ data_path_.Append(kLocalStorageDirectory), false,
file_util::FileEnumerator::FILES);
for (FilePath path = file_enumerator.Next(); !path.value().empty();
path = file_enumerator.Next()) {
@@ -215,7 +247,7 @@ void DOMStorageContext::DeleteAllLocalStorageFiles() {
PurgeMemory();
file_util::FileEnumerator file_enumerator(
- webkit_context_->data_path().Append(kLocalStorageDirectory), false,
+ data_path_.Append(kLocalStorageDirectory), false,
file_util::FileEnumerator::FILES);
for (FilePath file_path = file_enumerator.Next(); !file_path.empty();
file_path = file_enumerator.Next()) {
@@ -225,11 +257,10 @@ void DOMStorageContext::DeleteAllLocalStorageFiles() {
}
DOMStorageNamespace* DOMStorageContext::CreateLocalStorage() {
- FilePath data_path = webkit_context_->data_path();
FilePath dir_path;
- if (!data_path.empty()) {
- MigrateLocalStorageDirectory(data_path);
- dir_path = data_path.Append(kLocalStorageDirectory);
+ if (!data_path_.empty()) {
+ MigrateLocalStorageDirectory(data_path_);
+ dir_path = data_path_.Append(kLocalStorageDirectory);
}
DOMStorageNamespace* new_namespace =
DOMStorageNamespace::CreateLocalStorageNamespace(this, dir_path);
@@ -264,28 +295,9 @@ void DOMStorageContext::CompleteCloningSessionStorage(
context->RegisterStorageNamespace(existing_namespace->Copy(clone_id));
}
-// static
-void DOMStorageContext::ClearLocalState(const FilePath& profile_path,
- const char* url_scheme_to_be_skipped) {
- file_util::FileEnumerator file_enumerator(profile_path.Append(
- kLocalStorageDirectory), false, file_util::FileEnumerator::FILES);
- for (FilePath file_path = file_enumerator.Next(); !file_path.empty();
- file_path = file_enumerator.Next()) {
- if (file_path.Extension() == kLocalStorageExtension) {
- WebSecurityOrigin web_security_origin =
- WebSecurityOrigin::createFromDatabaseIdentifier(
- webkit_glue::FilePathToWebString(file_path.BaseName()));
- if (!EqualsASCII(web_security_origin.protocol(),
- url_scheme_to_be_skipped)) {
- file_util::Delete(file_path, false);
- }
- }
- }
-}
-
FilePath DOMStorageContext::GetLocalStorageFilePath(
const string16& origin_id) const {
- FilePath storageDir = webkit_context_->data_path().Append(
+ FilePath storageDir = data_path_.Append(
DOMStorageContext::kLocalStorageDirectory);
FilePath::StringType id =
webkit_glue::WebStringToFilePathString(origin_id);
diff --git a/chrome/browser/in_process_webkit/dom_storage_context.h b/chrome/browser/in_process_webkit/dom_storage_context.h
index 1552a91..68993f4 100644
--- a/chrome/browser/in_process_webkit/dom_storage_context.h
+++ b/chrome/browser/in_process_webkit/dom_storage_context.h
@@ -14,15 +14,15 @@
#include "base/time.h"
class DOMStorageArea;
-class DOMStorageDispatcherHost;
+class DOMStorageMessageFilter;
class DOMStorageNamespace;
class WebKitContext;
// This is owned by WebKitContext and is all the dom storage information that's
-// shared by all the ResourceMessageFilter/DOMStorageDispatcherHosts that share
-// the same profile. The specifics of responsibilities are fairly well
-// documented here and in StorageNamespace and StorageArea. Everything is only
-// to be accessed on the WebKit thread unless noted otherwise.
+// shared by all the DOMStorageMessageFilters that share the same profile. The
+// specifics of responsibilities are fairly well documented here and in
+// StorageNamespace and StorageArea. Everything is only to be accessed on the
+// WebKit thread unless noted otherwise.
//
// NOTE: Virtual methods facilitate mocking functions for testing.
class DOMStorageContext {
@@ -54,12 +54,12 @@ class DOMStorageContext {
// namespace if it hasn't been already.
DOMStorageNamespace* GetStorageNamespace(int64 id, bool allocation_allowed);
- // Sometimes an event from one DOM storage dispatcher host requires
+ // Sometimes an event from one DOM storage message filter requires
// communication to all of them.
- typedef std::set<DOMStorageDispatcherHost*> DispatcherHostSet;
- void RegisterDispatcherHost(DOMStorageDispatcherHost* dispatcher_host);
- void UnregisterDispatcherHost(DOMStorageDispatcherHost* dispatcher_host);
- const DispatcherHostSet* GetDispatcherHostSet() const;
+ typedef std::set<DOMStorageMessageFilter*> MessageFilterSet;
+ void RegisterMessageFilter(DOMStorageMessageFilter* message_filter);
+ void UnregisterMessageFilter(DOMStorageMessageFilter* MessageFilter);
+ const MessageFilterSet* GetMessageFilterSet() const;
// Tells storage namespaces to purge any memory they do not need.
virtual void PurgeMemory();
@@ -85,13 +85,18 @@ class DOMStorageContext {
// The local storage file extension.
static const FilePath::CharType kLocalStorageExtension[];
- // Delete all non-extension local storage files.
- static void ClearLocalState(const FilePath& profile_path,
- const char* url_scheme_to_be_skipped);
-
// Get the file name of the local storage file for the given origin.
FilePath GetLocalStorageFilePath(const string16& origin_id) const;
+ void set_clear_local_state_on_exit_(bool clear_local_state) {
+ clear_local_state_on_exit_ = clear_local_state;
+ }
+
+#ifdef UNIT_TEST
+ // For unit tests allow to override the |data_path_|.
+ void set_data_path(const FilePath& data_path) { data_path_ = data_path; }
+#endif
+
private:
// Get the local storage instance. The object is owned by this class.
DOMStorageNamespace* CreateLocalStorage();
@@ -118,12 +123,19 @@ class DOMStorageContext {
int64 last_session_storage_namespace_id_on_ui_thread_;
int64 last_session_storage_namespace_id_on_io_thread_;
- // We're owned by this WebKit context. Used while instantiating LocalStorage.
- WebKitContext* webkit_context_;
+ // True if the destructor should delete its files.
+ bool clear_local_state_on_exit_;
+
+ // Path where the profile data is stored.
+ // TODO(pastarmovj): Keep in mind that unlike indexed db data_path_ variable
+ // this one still has to point to the upper level dir because of the
+ // MigrateLocalStorageDirectory function. Once this function disappears we can
+ // make it point directly to the dom storage path.
+ FilePath data_path_;
- // All the DOMStorageDispatcherHosts that are attached to us. ONLY USE ON THE
+ // All the DOMStorageMessageFilters that are attached to us. ONLY USE ON THE
// IO THREAD!
- DispatcherHostSet dispatcher_host_set_;
+ MessageFilterSet message_filter_set_;
// Maps ids to StorageAreas. We do NOT own these objects. StorageNamespace
// (which does own them) will notify us when we should remove the entries.
diff --git a/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc b/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc
deleted file mode 100644
index 9e8bcb9..0000000
--- a/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc
+++ /dev/null
@@ -1,341 +0,0 @@
-// 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.
-
-#include "chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h"
-
-#include "base/nullable_string16.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/in_process_webkit/dom_storage_area.h"
-#include "chrome/browser/in_process_webkit/dom_storage_context.h"
-#include "chrome/browser/in_process_webkit/dom_storage_namespace.h"
-#include "chrome/browser/net/chrome_url_request_context.h"
-#include "chrome/browser/renderer_host/browser_render_process_host.h"
-#include "chrome/browser/renderer_host/render_view_host_notification_task.h"
-#include "chrome/browser/renderer_host/resource_message_filter.h"
-#include "chrome/common/render_messages.h"
-#include "chrome/common/render_messages_params.h"
-#include "googleurl/src/gurl.h"
-
-using WebKit::WebStorageArea;
-
-DOMStorageDispatcherHost* DOMStorageDispatcherHost::storage_event_host_ = NULL;
-const GURL* DOMStorageDispatcherHost::storage_event_url_ = NULL;
-
-DOMStorageDispatcherHost::
-ScopedStorageEventContext::ScopedStorageEventContext(
- DOMStorageDispatcherHost* dispatcher_host, const GURL* url) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
- DCHECK(!storage_event_host_);
- DCHECK(!storage_event_url_);
- storage_event_host_ = dispatcher_host;
- storage_event_url_ = url;
- DCHECK(storage_event_host_);
- DCHECK(storage_event_url_);
-}
-
-DOMStorageDispatcherHost::
-ScopedStorageEventContext::~ScopedStorageEventContext() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
- DCHECK(storage_event_host_);
- DCHECK(storage_event_url_);
- storage_event_host_ = NULL;
- storage_event_url_ = NULL;
-}
-
-DOMStorageDispatcherHost::DOMStorageDispatcherHost(
- ResourceMessageFilter* resource_message_filter,
- WebKitContext* webkit_context)
- : webkit_context_(webkit_context),
- resource_message_filter_(resource_message_filter),
- process_handle_(0),
- process_id_(0) {
- DCHECK(webkit_context_.get());
- DCHECK(resource_message_filter_);
-}
-
-DOMStorageDispatcherHost::~DOMStorageDispatcherHost() {
-}
-
-void DOMStorageDispatcherHost::Init(int process_id,
- base::ProcessHandle process_handle) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK(resource_message_filter_); // Ensure Shutdown() has not been called.
- DCHECK(!process_handle_); // Make sure Init() has not yet been called.
- DCHECK(process_handle);
- Context()->RegisterDispatcherHost(this);
- process_id_ = process_id;
- process_handle_ = process_handle;
-}
-
-void DOMStorageDispatcherHost::Shutdown() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- // This is not always true during testing.
- if (process_handle_)
- Context()->UnregisterDispatcherHost(this);
- resource_message_filter_ = NULL;
-}
-
-/* static */
-void DOMStorageDispatcherHost::DispatchStorageEvent(const NullableString16& key,
- const NullableString16& old_value, const NullableString16& new_value,
- const string16& origin, const GURL& url, bool is_local_storage) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
- DCHECK(is_local_storage); // Only LocalStorage is implemented right now.
- DCHECK(storage_event_host_);
- ViewMsg_DOMStorageEvent_Params params;
- params.key_ = key;
- params.old_value_ = old_value;
- params.new_value_ = new_value;
- params.origin_ = origin;
- params.url_ = *storage_event_url_; // The url passed in is junk.
- params.storage_type_ = is_local_storage ? DOM_STORAGE_LOCAL
- : DOM_STORAGE_SESSION;
- // The storage_event_host_ is the DOMStorageDispatcherHost that is up in the
- // current call stack since it caused the storage event to fire.
- BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(storage_event_host_,
- &DOMStorageDispatcherHost::OnStorageEvent, params));
-}
-
-bool DOMStorageDispatcherHost::OnMessageReceived(const IPC::Message& message,
- bool* msg_is_ok) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK(process_handle_);
-
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP_EX(DOMStorageDispatcherHost, message, *msg_is_ok)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageStorageAreaId,
- OnStorageAreaId)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageLength, OnLength)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageKey, OnKey)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageGetItem, OnGetItem)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageSetItem, OnSetItem)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageRemoveItem,
- OnRemoveItem)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageClear, OnClear)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-int64 DOMStorageDispatcherHost::CloneSessionStorage(int64 original_id) {
- return Context()->CloneSessionStorage(original_id);
-}
-
-void DOMStorageDispatcherHost::Send(IPC::Message* message) {
- if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
- // TODO(jorlow): Even if we successfully post, I believe it's possible for
- // the task to never run (if the IO thread is already shutting
- // down). We may want to handle this case, though
- // realistically it probably doesn't matter.
- if (!BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE, NewRunnableMethod(
- this, &DOMStorageDispatcherHost::Send, message))) {
- // The IO thread is dead.
- delete message;
- }
- return;
- }
-
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (!resource_message_filter_)
- delete message;
- else
- resource_message_filter_->Send(message);
-}
-
-void DOMStorageDispatcherHost::OnStorageAreaId(int64 namespace_id,
- const string16& origin,
- IPC::Message* reply_msg) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- ChromeURLRequestContext* url_request_context =
- resource_message_filter_->GetRequestContextForURL(GURL(origin));
- BrowserThread::PostTask(BrowserThread::WEBKIT, FROM_HERE, NewRunnableMethod(
- this, &DOMStorageDispatcherHost::OnStorageAreaIdWebKit, namespace_id,
- origin, reply_msg,
- make_scoped_refptr(url_request_context->host_content_settings_map())));
-}
-
-void DOMStorageDispatcherHost::OnStorageAreaIdWebKit(
- int64 namespace_id, const string16& origin, IPC::Message* reply_msg,
- HostContentSettingsMap* host_content_settings_map) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
- DOMStorageNamespace* storage_namespace =
- Context()->GetStorageNamespace(namespace_id, true);
- if (!storage_namespace) {
- BrowserRenderProcessHost::BadMessageTerminateProcess(
- ViewHostMsg_DOMStorageStorageAreaId::ID, process_handle_);
- delete reply_msg;
- return;
- }
- DOMStorageArea* storage_area = storage_namespace->GetStorageArea(
- origin, host_content_settings_map);
- ViewHostMsg_DOMStorageStorageAreaId::WriteReplyParams(reply_msg,
- storage_area->id());
- Send(reply_msg);
-}
-
-void DOMStorageDispatcherHost::OnLength(int64 storage_area_id,
- IPC::Message* reply_msg) {
- if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
- BrowserThread::PostTask(BrowserThread::WEBKIT, FROM_HERE, NewRunnableMethod(
- this, &DOMStorageDispatcherHost::OnLength, storage_area_id, reply_msg));
- return;
- }
-
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
- DOMStorageArea* storage_area = Context()->GetStorageArea(storage_area_id);
- if (!storage_area) {
- BrowserRenderProcessHost::BadMessageTerminateProcess(
- ViewHostMsg_DOMStorageLength::ID, process_handle_);
- delete reply_msg;
- return;
- }
- unsigned length = storage_area->Length();
- ViewHostMsg_DOMStorageLength::WriteReplyParams(reply_msg, length);
- Send(reply_msg);
-}
-
-void DOMStorageDispatcherHost::OnKey(int64 storage_area_id, unsigned index,
- IPC::Message* reply_msg) {
- if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
- BrowserThread::PostTask(BrowserThread::WEBKIT, FROM_HERE, NewRunnableMethod(
- this, &DOMStorageDispatcherHost::OnKey, storage_area_id, index,
- reply_msg));
- return;
- }
-
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
- DOMStorageArea* storage_area = Context()->GetStorageArea(storage_area_id);
- if (!storage_area) {
- BrowserRenderProcessHost::BadMessageTerminateProcess(
- ViewHostMsg_DOMStorageKey::ID, process_handle_);
- delete reply_msg;
- return;
- }
- const NullableString16& key = storage_area->Key(index);
- ViewHostMsg_DOMStorageKey::WriteReplyParams(reply_msg, key);
- Send(reply_msg);
-}
-
-void DOMStorageDispatcherHost::OnGetItem(int64 storage_area_id,
- const string16& key,
- IPC::Message* reply_msg) {
- if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
- BrowserThread::PostTask(BrowserThread::WEBKIT, FROM_HERE, NewRunnableMethod(
- this, &DOMStorageDispatcherHost::OnGetItem, storage_area_id, key,
- reply_msg));
- return;
- }
-
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
- DOMStorageArea* storage_area = Context()->GetStorageArea(storage_area_id);
- if (!storage_area) {
- BrowserRenderProcessHost::BadMessageTerminateProcess(
- ViewHostMsg_DOMStorageGetItem::ID, process_handle_);
- delete reply_msg;
- return;
- }
- const NullableString16& value = storage_area->GetItem(key);
- ViewHostMsg_DOMStorageGetItem::WriteReplyParams(reply_msg, value);
- Send(reply_msg);
-}
-
-void DOMStorageDispatcherHost::OnSetItem(
- int64 storage_area_id, const string16& key, const string16& value,
- const GURL& url, IPC::Message* reply_msg) {
- if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
- BrowserThread::PostTask(BrowserThread::WEBKIT, FROM_HERE, NewRunnableMethod(
- this, &DOMStorageDispatcherHost::OnSetItem, storage_area_id, key, value,
- url, reply_msg));
- return;
- }
-
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
- DOMStorageArea* storage_area = Context()->GetStorageArea(storage_area_id);
- if (!storage_area) {
- BrowserRenderProcessHost::BadMessageTerminateProcess(
- ViewHostMsg_DOMStorageSetItem::ID, process_handle_);
- return;
- }
-
- ScopedStorageEventContext scope(this, &url);
- WebStorageArea::Result result;
- NullableString16 old_value = storage_area->SetItem(key, value, &result, this);
-
- // If content was blocked, tell the UI to display the blocked content icon.
- if (reply_msg->routing_id() == MSG_ROUTING_CONTROL) {
- DLOG(WARNING) << "setItem was not given a proper routing id";
- } else {
- CallRenderViewHostContentSettingsDelegate(
- process_id_, reply_msg->routing_id(),
- &RenderViewHostDelegate::ContentSettings::OnLocalStorageAccessed,
- url, storage_area->owner()->dom_storage_type(),
- result == WebStorageArea::ResultBlockedByPolicy);
- }
-
- ViewHostMsg_DOMStorageSetItem::WriteReplyParams(reply_msg, result, old_value);
- Send(reply_msg);
-}
-
-void DOMStorageDispatcherHost::OnRemoveItem(
- int64 storage_area_id, const string16& key, const GURL& url,
- IPC::Message* reply_msg) {
- if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
- BrowserThread::PostTask(BrowserThread::WEBKIT, FROM_HERE, NewRunnableMethod(
- this, &DOMStorageDispatcherHost::OnRemoveItem, storage_area_id, key,
- url, reply_msg));
- return;
- }
-
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
- DOMStorageArea* storage_area = Context()->GetStorageArea(storage_area_id);
- if (!storage_area) {
- BrowserRenderProcessHost::BadMessageTerminateProcess(
- ViewHostMsg_DOMStorageRemoveItem::ID, process_handle_);
- return;
- }
-
- ScopedStorageEventContext scope(this, &url);
- NullableString16 old_value = storage_area->RemoveItem(key);
- ViewHostMsg_DOMStorageRemoveItem::WriteReplyParams(reply_msg, old_value);
- Send(reply_msg);
-}
-
-void DOMStorageDispatcherHost::OnClear(int64 storage_area_id, const GURL& url,
- IPC::Message* reply_msg) {
- if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
- BrowserThread::PostTask(BrowserThread::WEBKIT, FROM_HERE, NewRunnableMethod(
- this, &DOMStorageDispatcherHost::OnClear, storage_area_id, url,
- reply_msg));
- return;
- }
-
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
- DOMStorageArea* storage_area = Context()->GetStorageArea(storage_area_id);
- if (!storage_area) {
- BrowserRenderProcessHost::BadMessageTerminateProcess(
- ViewHostMsg_DOMStorageClear::ID, process_handle_);
- return;
- }
-
- ScopedStorageEventContext scope(this, &url);
- bool something_cleared = storage_area->Clear();
- ViewHostMsg_DOMStorageClear::WriteReplyParams(reply_msg, something_cleared);
- Send(reply_msg);
-}
-
-void DOMStorageDispatcherHost::OnStorageEvent(
- const ViewMsg_DOMStorageEvent_Params& params) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- const DOMStorageContext::DispatcherHostSet* set =
- Context()->GetDispatcherHostSet();
- DOMStorageContext::DispatcherHostSet::const_iterator cur = set->begin();
- while (cur != set->end()) {
- // The renderer that generates the event handles it itself.
- if (*cur != this)
- (*cur)->Send(new ViewMsg_DOMStorageEvent(params));
- ++cur;
- }
-}
diff --git a/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h b/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h
deleted file mode 100644
index 736e55d..0000000
--- a/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h
+++ /dev/null
@@ -1,117 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_DISPATCHER_HOST_H_
-#define CHROME_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_DISPATCHER_HOST_H_
-#pragma once
-
-#include "base/process.h"
-#include "base/ref_counted.h"
-#include "base/tracked.h"
-#include "chrome/browser/in_process_webkit/dom_storage_area.h"
-#include "chrome/browser/in_process_webkit/webkit_context.h"
-#include "chrome/common/dom_storage_common.h"
-#include "ipc/ipc_message.h"
-
-class DOMStorageContext;
-class GURL;
-class HostContentSettingsMap;
-class ResourceMessageFilter;
-class Task;
-struct ViewMsg_DOMStorageEvent_Params;
-
-// This class handles the logistics of DOM Storage within the browser process.
-// It mostly ferries information between IPCs and the WebKit implementations,
-// but it also handles some special cases like when renderer processes die.
-class DOMStorageDispatcherHost
- : public base::RefCountedThreadSafe<DOMStorageDispatcherHost> {
- public:
- // Only call the constructor from the UI thread.
- DOMStorageDispatcherHost(
- ResourceMessageFilter* resource_message_filter,
- WebKitContext* webkit_context);
-
- // Only call from ResourceMessageFilter on the IO thread.
- void Init(int process_id, base::ProcessHandle process_handle);
-
- // Only call from ResourceMessageFilter on the IO thread. Calls self on the
- // WebKit thread in some cases.
- void Shutdown();
-
- // Only call from ResourceMessageFilter on the IO thread.
- bool OnMessageReceived(const IPC::Message& message, bool* msg_is_ok);
-
- // Clones a session storage namespace and returns the cloned namespaces' id.
- // Only call on the IO thread.
- int64 CloneSessionStorage(int64 original_id);
-
- // Send a message to the renderer process associated with our
- // message_sender_ via the IO thread. May be called from any thread.
- void Send(IPC::Message* message);
-
- // Only call on the WebKit thread.
- static void DispatchStorageEvent(const NullableString16& key,
- const NullableString16& old_value, const NullableString16& new_value,
- const string16& origin, const GURL& url, bool is_local_storage);
-
- private:
- friend class base::RefCountedThreadSafe<DOMStorageDispatcherHost>;
- ~DOMStorageDispatcherHost();
-
- // Message Handlers.
- void OnStorageAreaId(int64 namespace_id, const string16& origin,
- IPC::Message* reply_msg);
- void OnLength(int64 storage_area_id, IPC::Message* reply_msg);
- void OnKey(int64 storage_area_id, unsigned index, IPC::Message* reply_msg);
- void OnGetItem(int64 storage_area_id, const string16& key,
- IPC::Message* reply_msg);
- void OnSetItem(int64 storage_area_id, const string16& key,
- const string16& value, const GURL& url,
- IPC::Message* reply_msg);
- void OnRemoveItem(int64 storage_area_id, const string16& key,
- const GURL& url, IPC::Message* reply_msg);
- void OnClear(int64 storage_area_id, const GURL& url, IPC::Message* reply_msg);
-
- // WebKit thread half of OnStorageAreaId
- void OnStorageAreaIdWebKit(
- int64 namespace_id, const string16& origin, IPC::Message* reply_msg,
- HostContentSettingsMap* host_context_settings_map);
-
- // Only call on the IO thread.
- void OnStorageEvent(const ViewMsg_DOMStorageEvent_Params& params);
-
- // A shortcut for accessing our context.
- DOMStorageContext* Context() {
- return webkit_context_->dom_storage_context();
- }
-
- // Use whenever there's a chance OnStorageEvent will be called.
- class ScopedStorageEventContext {
- public:
- ScopedStorageEventContext(DOMStorageDispatcherHost* dispatcher_host,
- const GURL* url);
- ~ScopedStorageEventContext();
- };
-
- // Only access on the WebKit thread! Used for storage events.
- static DOMStorageDispatcherHost* storage_event_host_;
- static const GURL* storage_event_url_;
-
- // Data shared between renderer processes with the same profile.
- scoped_refptr<WebKitContext> webkit_context_;
-
- // Only set and use on the IO thread.
- ResourceMessageFilter* resource_message_filter_;
-
- // If we get a corrupt message from a renderer, we need to kill it using this
- // handle.
- base::ProcessHandle process_handle_;
-
- // Used to dispatch messages to the correct view host.
- int process_id_;
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(DOMStorageDispatcherHost);
-};
-
-#endif // CHROME_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_DISPATCHER_HOST_H_
diff --git a/chrome/browser/in_process_webkit/dom_storage_dispatcher_host_unittest.cc b/chrome/browser/in_process_webkit/dom_storage_dispatcher_host_unittest.cc
deleted file mode 100644
index a277492..0000000
--- a/chrome/browser/in_process_webkit/dom_storage_dispatcher_host_unittest.cc
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-// TODO(jorlow): Write once dom_storage_dispatcher_host is more than just a
-// stub.
diff --git a/chrome/browser/in_process_webkit/dom_storage_message_filter.cc b/chrome/browser/in_process_webkit/dom_storage_message_filter.cc
new file mode 100644
index 0000000..8b91c4c
--- /dev/null
+++ b/chrome/browser/in_process_webkit/dom_storage_message_filter.cc
@@ -0,0 +1,232 @@
+// 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.
+
+#include "chrome/browser/in_process_webkit/dom_storage_message_filter.h"
+
+#include "base/nullable_string16.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/in_process_webkit/dom_storage_area.h"
+#include "chrome/browser/in_process_webkit/dom_storage_context.h"
+#include "chrome/browser/in_process_webkit/dom_storage_namespace.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/browser_render_process_host.h"
+#include "chrome/browser/renderer_host/render_view_host_notification_task.h"
+#include "chrome/common/dom_storage_messages.h"
+#include "chrome/common/url_constants.h"
+#include "googleurl/src/gurl.h"
+
+using WebKit::WebStorageArea;
+
+DOMStorageMessageFilter* DOMStorageMessageFilter::storage_event_message_filter =
+ NULL;
+const GURL* DOMStorageMessageFilter::storage_event_url_ = NULL;
+
+DOMStorageMessageFilter::
+ScopedStorageEventContext::ScopedStorageEventContext(
+ DOMStorageMessageFilter* dispatcher_message_filter, const GURL* url) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ DCHECK(!storage_event_message_filter);
+ DCHECK(!storage_event_url_);
+ storage_event_message_filter = dispatcher_message_filter;
+ storage_event_url_ = url;
+ DCHECK(storage_event_message_filter);
+ DCHECK(storage_event_url_);
+}
+
+DOMStorageMessageFilter::
+ScopedStorageEventContext::~ScopedStorageEventContext() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ DCHECK(storage_event_message_filter);
+ DCHECK(storage_event_url_);
+ storage_event_message_filter = NULL;
+ storage_event_url_ = NULL;
+}
+
+DOMStorageMessageFilter::DOMStorageMessageFilter(int process_id,
+ Profile* profile)
+ : webkit_context_(profile->GetWebKitContext()),
+ process_id_(process_id),
+ host_content_settings_map_(profile->GetHostContentSettingsMap()) {
+}
+
+DOMStorageMessageFilter::~DOMStorageMessageFilter() {
+ // This is not always true during testing.
+ if (peer_handle())
+ Context()->UnregisterMessageFilter(this);
+}
+
+void DOMStorageMessageFilter::OnChannelConnected(int32 peer_pid) {
+ BrowserMessageFilter::OnChannelConnected(peer_pid);
+
+ Context()->RegisterMessageFilter(this);
+}
+
+/* static */
+void DOMStorageMessageFilter::DispatchStorageEvent(const NullableString16& key,
+ const NullableString16& old_value, const NullableString16& new_value,
+ const string16& origin, const GURL& url, bool is_local_storage) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ DCHECK(is_local_storage); // Only LocalStorage is implemented right now.
+ DCHECK(storage_event_message_filter);
+ DOMStorageMsg_Event_Params params;
+ params.key = key;
+ params.old_value = old_value;
+ params.new_value = new_value;
+ params.origin = origin;
+ params.url = *storage_event_url_; // The url passed in is junk.
+ params.storage_type = is_local_storage ? DOM_STORAGE_LOCAL
+ : DOM_STORAGE_SESSION;
+ // The storage_event_message_filter is the DOMStorageMessageFilter that is up
+ // in the current call stack since it caused the storage event to fire.
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(storage_event_message_filter,
+ &DOMStorageMessageFilter::OnStorageEvent, params));
+}
+
+bool DOMStorageMessageFilter::OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(DOMStorageMessageFilter, message, *message_was_ok)
+ IPC_MESSAGE_HANDLER(DOMStorageHostMsg_StorageAreaId, OnStorageAreaId)
+ IPC_MESSAGE_HANDLER(DOMStorageHostMsg_Length, OnLength)
+ IPC_MESSAGE_HANDLER(DOMStorageHostMsg_Key, OnKey)
+ IPC_MESSAGE_HANDLER(DOMStorageHostMsg_GetItem, OnGetItem)
+ IPC_MESSAGE_HANDLER(DOMStorageHostMsg_SetItem, OnSetItem)
+ IPC_MESSAGE_HANDLER(DOMStorageHostMsg_RemoveItem, OnRemoveItem)
+ IPC_MESSAGE_HANDLER(DOMStorageHostMsg_Clear, OnClear)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+
+ return handled;
+}
+
+void DOMStorageMessageFilter::BadMessageReceived() {
+ UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_DSMF"));
+ BrowserMessageFilter::BadMessageReceived();
+}
+
+void DOMStorageMessageFilter::OverrideThreadForMessage(
+ const IPC::Message& message,
+ BrowserThread::ID* thread) {
+ if (IPC_MESSAGE_CLASS(message) == DOMStorageMsgStart)
+ *thread = BrowserThread::WEBKIT;
+}
+
+void DOMStorageMessageFilter::OnStorageAreaId(int64 namespace_id,
+ const string16& origin,
+ int64* storage_area_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+
+ DOMStorageNamespace* storage_namespace =
+ Context()->GetStorageNamespace(namespace_id, true);
+ if (!storage_namespace) {
+ BadMessageReceived();
+ return;
+ }
+ DOMStorageArea* storage_area = storage_namespace->GetStorageArea(
+ origin, host_content_settings_map_);
+ *storage_area_id = storage_area->id();
+}
+
+void DOMStorageMessageFilter::OnLength(int64 storage_area_id,
+ unsigned* length) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ DOMStorageArea* storage_area = Context()->GetStorageArea(storage_area_id);
+ if (!storage_area) {
+ BadMessageReceived();
+ return;
+ }
+ *length = storage_area->Length();
+}
+
+void DOMStorageMessageFilter::OnKey(int64 storage_area_id, unsigned index,
+ NullableString16* key) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ DOMStorageArea* storage_area = Context()->GetStorageArea(storage_area_id);
+ if (!storage_area) {
+ BadMessageReceived();
+ return;
+ }
+ *key = storage_area->Key(index);
+}
+
+void DOMStorageMessageFilter::OnGetItem(int64 storage_area_id,
+ const string16& key,
+ NullableString16* value) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ DOMStorageArea* storage_area = Context()->GetStorageArea(storage_area_id);
+ if (!storage_area) {
+ BadMessageReceived();
+ return;
+ }
+ *value = storage_area->GetItem(key);
+}
+
+void DOMStorageMessageFilter::OnSetItem(
+ int render_view_id, int64 storage_area_id, const string16& key,
+ const string16& value, const GURL& url,
+ WebKit::WebStorageArea::Result* result, NullableString16* old_value) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ DOMStorageArea* storage_area = Context()->GetStorageArea(storage_area_id);
+ if (!storage_area) {
+ BadMessageReceived();
+ return;
+ }
+
+ ScopedStorageEventContext scope(this, &url);
+ *old_value = storage_area->SetItem(key, value, result);
+
+ // If content was blocked, tell the UI to display the blocked content icon.
+ if (render_view_id == MSG_ROUTING_CONTROL) {
+ DLOG(WARNING) << "setItem was not given a proper routing id";
+ } else {
+ CallRenderViewHostContentSettingsDelegate(
+ process_id_, render_view_id,
+ &RenderViewHostDelegate::ContentSettings::OnLocalStorageAccessed,
+ url, storage_area->owner()->dom_storage_type(),
+ *result == WebStorageArea::ResultBlockedByPolicy);
+ }
+}
+
+void DOMStorageMessageFilter::OnRemoveItem(
+ int64 storage_area_id, const string16& key, const GURL& url,
+ NullableString16* old_value) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ DOMStorageArea* storage_area = Context()->GetStorageArea(storage_area_id);
+ if (!storage_area) {
+ BadMessageReceived();
+ return;
+ }
+
+ ScopedStorageEventContext scope(this, &url);
+ *old_value = storage_area->RemoveItem(key);
+}
+
+void DOMStorageMessageFilter::OnClear(int64 storage_area_id, const GURL& url,
+ bool* something_cleared) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ DOMStorageArea* storage_area = Context()->GetStorageArea(storage_area_id);
+ if (!storage_area) {
+ BadMessageReceived();
+ return;
+ }
+
+ ScopedStorageEventContext scope(this, &url);
+ *something_cleared = storage_area->Clear();
+}
+
+void DOMStorageMessageFilter::OnStorageEvent(
+ const DOMStorageMsg_Event_Params& params) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ const DOMStorageContext::MessageFilterSet* set =
+ Context()->GetMessageFilterSet();
+ DOMStorageContext::MessageFilterSet::const_iterator cur = set->begin();
+ while (cur != set->end()) {
+ // The renderer that generates the event handles it itself.
+ if (*cur != this)
+ (*cur)->Send(new DOMStorageMsg_Event(params));
+ ++cur;
+ }
+}
diff --git a/chrome/browser/in_process_webkit/dom_storage_message_filter.h b/chrome/browser/in_process_webkit/dom_storage_message_filter.h
new file mode 100644
index 0000000..bf56c04
--- /dev/null
+++ b/chrome/browser/in_process_webkit/dom_storage_message_filter.h
@@ -0,0 +1,98 @@
+// 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.
+
+#ifndef CHROME_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_MESSAGE_FILTER_H_
+#define CHROME_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_MESSAGE_FILTER_H_
+#pragma once
+
+#include "base/process.h"
+#include "base/ref_counted.h"
+#include "base/tracked.h"
+#include "chrome/browser/browser_message_filter.h"
+#include "chrome/browser/in_process_webkit/dom_storage_area.h"
+#include "chrome/browser/in_process_webkit/webkit_context.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
+#include "chrome/common/dom_storage_common.h"
+#include "ipc/ipc_message.h"
+
+class DOMStorageContext;
+class GURL;
+class Profile;
+struct DOMStorageMsg_Event_Params;
+
+// This class handles the logistics of DOM Storage within the browser process.
+// It mostly ferries information between IPCs and the WebKit implementations,
+// but it also handles some special cases like when renderer processes die.
+class DOMStorageMessageFilter : public BrowserMessageFilter {
+ public:
+ // Only call the constructor from the UI thread.
+ DOMStorageMessageFilter(int process_id, Profile* profile);
+
+ // BrowserMessageFilter implementation
+ virtual void OnChannelConnected(int32 peer_pid);
+ virtual void OverrideThreadForMessage(const IPC::Message& message,
+ BrowserThread::ID* thread);
+ virtual bool OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok);
+
+ // Only call on the WebKit thread.
+ static void DispatchStorageEvent(const NullableString16& key,
+ const NullableString16& old_value, const NullableString16& new_value,
+ const string16& origin, const GURL& url, bool is_local_storage);
+
+ private:
+ friend class base::RefCountedThreadSafe<DOMStorageMessageFilter>;
+ ~DOMStorageMessageFilter();
+
+ // BrowserMessageFilter override.
+ virtual void BadMessageReceived();
+
+ // Message Handlers.
+ void OnStorageAreaId(int64 namespace_id, const string16& origin,
+ int64* storage_area_id);
+ void OnLength(int64 storage_area_id, unsigned* length);
+ void OnKey(int64 storage_area_id, unsigned index, NullableString16* key);
+ void OnGetItem(int64 storage_area_id, const string16& key,
+ NullableString16* value);
+ void OnSetItem(int render_view_id, int64 storage_area_id, const string16& key,
+ const string16& value, const GURL& url,
+ WebKit::WebStorageArea::Result* result,
+ NullableString16* old_value);
+ void OnRemoveItem(int64 storage_area_id, const string16& key,
+ const GURL& url, NullableString16* old_value);
+ void OnClear(int64 storage_area_id, const GURL& url, bool* something_cleared);
+
+ // Only call on the IO thread.
+ void OnStorageEvent(const DOMStorageMsg_Event_Params& params);
+
+ // A shortcut for accessing our context.
+ DOMStorageContext* Context() {
+ return webkit_context_->dom_storage_context();
+ }
+
+ // Use whenever there's a chance OnStorageEvent will be called.
+ class ScopedStorageEventContext {
+ public:
+ ScopedStorageEventContext(
+ DOMStorageMessageFilter* dispatcher_message_filter,
+ const GURL* url);
+ ~ScopedStorageEventContext();
+ };
+
+ // Only access on the WebKit thread! Used for storage events.
+ static DOMStorageMessageFilter* storage_event_message_filter;
+ static const GURL* storage_event_url_;
+
+ // Data shared between renderer processes with the same profile.
+ scoped_refptr<WebKitContext> webkit_context_;
+
+ // Used to dispatch messages to the correct view host.
+ int process_id_;
+
+ scoped_refptr<HostContentSettingsMap> host_content_settings_map_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(DOMStorageMessageFilter);
+};
+
+#endif // CHROME_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_MESSAGE_FILTER_H_
diff --git a/chrome/browser/in_process_webkit/dom_storage_message_filter_unittest.cc b/chrome/browser/in_process_webkit/dom_storage_message_filter_unittest.cc
new file mode 100644
index 0000000..c56ee71
--- /dev/null
+++ b/chrome/browser/in_process_webkit/dom_storage_message_filter_unittest.cc
@@ -0,0 +1,8 @@
+// Copyright (c) 2009 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 "chrome/browser/in_process_webkit/dom_storage_message_filter.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// TODO(jorlow): Write me
diff --git a/chrome/browser/in_process_webkit/dom_storage_namespace.cc b/chrome/browser/in_process_webkit/dom_storage_namespace.cc
index b0cfaf4..a663a05 100644
--- a/chrome/browser/in_process_webkit/dom_storage_namespace.cc
+++ b/chrome/browser/in_process_webkit/dom_storage_namespace.cc
@@ -7,7 +7,7 @@
#include "base/file_path.h"
#include "chrome/browser/in_process_webkit/dom_storage_area.h"
#include "chrome/browser/in_process_webkit/dom_storage_context.h"
-#include "chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h"
+#include "chrome/browser/in_process_webkit/dom_storage_message_filter.h"
#include "third_party/WebKit/WebKit/chromium/public/WebStorageArea.h"
#include "third_party/WebKit/WebKit/chromium/public/WebStorageNamespace.h"
#include "webkit/glue/webkit_glue.h"
diff --git a/chrome/browser/in_process_webkit/indexed_db_browsertest.cc b/chrome/browser/in_process_webkit/indexed_db_browsertest.cc
index 1d360c0..70a8d13 100644
--- a/chrome/browser/in_process_webkit/indexed_db_browsertest.cc
+++ b/chrome/browser/in_process_webkit/indexed_db_browsertest.cc
@@ -9,10 +9,13 @@
#include "base/scoped_temp_dir.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/in_process_webkit/indexed_db_context.h"
+#include "chrome/browser/in_process_webkit/webkit_context.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/in_process_browser_test.h"
+#include "chrome/test/testing_profile.h"
+#include "chrome/test/thread_test_helper.h"
#include "chrome/test/ui_test_utils.h"
// This browser test is aimed towards exercising the IndexedDB bindings and
@@ -23,11 +26,6 @@ class IndexedDBBrowserTest : public InProcessBrowserTest {
EnableDOMAutomation();
}
- // From InProcessBrowserTest.
- virtual void SetUpCommandLine(CommandLine* command_line) {
- command_line->AppendSwitch(switches::kEnableIndexedDatabase);
- }
-
GURL testUrl(const FilePath& file_path) {
const FilePath kTestDir(FILE_PATH_LITERAL("indexeddb"));
return ui_test_utils::GetTestUrl(kTestDir, file_path);
@@ -56,7 +54,8 @@ IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorTest) {
}
// TODO(hans): Keep an eye out for these tests going flaky. See crbug.com/63675.
-IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, IndexTest) {
+// Crashy, http://crbug.com/67422.
+IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DISABLED_IndexTest) {
SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("index_test.html"))));
}
@@ -76,11 +75,13 @@ IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DatabaseTest) {
SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("database_test.html"))));
}
-IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, TransactionTest) {
+// Crashy, http://crbug.com/67422.
+IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DISABLED_TransactionTest) {
SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("transaction_test.html"))));
}
-IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DoesntHangTest) {
+// Crashy, http://crbug.com/66394.
+IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DISABLED_DoesntHangTest) {
SimpleTest(testUrl(FilePath(
FILE_PATH_LITERAL("transaction_run_forever.html"))));
ui_test_utils::CrashTab(browser()->GetSelectedTabContents());
@@ -97,9 +98,9 @@ IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ClearLocalState) {
IndexedDBContext::kIndexedDBDirectory);
ASSERT_TRUE(file_util::CreateDirectory(indexeddb_dir));
- FilePath::StringType file_name_1(FILE_PATH_LITERAL("http_www.google.com_0"));
+ FilePath::StringType file_name_1(FILE_PATH_LITERAL("http_foo_0"));
file_name_1.append(IndexedDBContext::kIndexedDBExtension);
- FilePath::StringType file_name_2(FILE_PATH_LITERAL("https_www.google.com_0"));
+ FilePath::StringType file_name_2(FILE_PATH_LITERAL("chrome-extension_foo_0"));
file_name_2.append(IndexedDBContext::kIndexedDBExtension);
FilePath temp_file_path_1 = indexeddb_dir.Append(file_name_1);
FilePath temp_file_path_2 = indexeddb_dir.Append(file_name_2);
@@ -107,7 +108,18 @@ IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ClearLocalState) {
ASSERT_EQ(1, file_util::WriteFile(temp_file_path_1, ".", 1));
ASSERT_EQ(1, file_util::WriteFile(temp_file_path_2, "o", 1));
- IndexedDBContext::ClearLocalState(temp_dir.path(), "https");
+ // Create the scope which will ensure we run the destructor of the webkit
+ // context which should trigger the clean up.
+ {
+ TestingProfile profile;
+ WebKitContext *webkit_context = profile.GetWebKitContext();
+ webkit_context->indexed_db_context()->set_data_path(indexeddb_dir);
+ webkit_context->set_clear_local_state_on_exit(true);
+ }
+ // Make sure we wait until the destructor has run.
+ scoped_refptr<ThreadTestHelper> helper(
+ new ThreadTestHelper(BrowserThread::WEBKIT));
+ ASSERT_TRUE(helper->Run());
// Because we specified https for scheme to be skipped the second file
// should survive and the first go into vanity.
diff --git a/chrome/browser/in_process_webkit/indexed_db_callbacks.cc b/chrome/browser/in_process_webkit/indexed_db_callbacks.cc
index faaa933..41ac4ed 100644
--- a/chrome/browser/in_process_webkit/indexed_db_callbacks.cc
+++ b/chrome/browser/in_process_webkit/indexed_db_callbacks.cc
@@ -23,21 +23,21 @@ IndexedDBTransactionCallbacks::IndexedDBTransactionCallbacks(
IndexedDBTransactionCallbacks::~IndexedDBTransactionCallbacks() {}
void IndexedDBCallbacksBase::onError(const WebKit::WebIDBDatabaseError& error) {
- dispatcher_host_->Send(new ViewMsg_IDBCallbacksError(
+ dispatcher_host_->Send(new IndexedDBMsg_CallbacksError(
response_id_, error.code(), error.message()));
}
void IndexedDBTransactionCallbacks::onAbort() {
dispatcher_host_->Send(
- new ViewMsg_IDBTransactionCallbacksAbort(transaction_id_));
+ new IndexedDBMsg_TransactionCallbacksAbort(transaction_id_));
}
void IndexedDBTransactionCallbacks::onComplete() {
dispatcher_host_->Send(
- new ViewMsg_IDBTransactionCallbacksComplete(transaction_id_));
+ new IndexedDBMsg_TransactionCallbacksComplete(transaction_id_));
}
void IndexedDBTransactionCallbacks::onTimeout() {
dispatcher_host_->Send(
- new ViewMsg_IDBTransactionCallbacksTimeout(transaction_id_));
+ new IndexedDBMsg_TransactionCallbacksTimeout(transaction_id_));
}
diff --git a/chrome/browser/in_process_webkit/indexed_db_callbacks.h b/chrome/browser/in_process_webkit/indexed_db_callbacks.h
index 653e211..55bc77e 100644
--- a/chrome/browser/in_process_webkit/indexed_db_callbacks.h
+++ b/chrome/browser/in_process_webkit/indexed_db_callbacks.h
@@ -9,9 +9,7 @@
#include "base/basictypes.h"
#include "base/ref_counted.h"
#include "chrome/browser/in_process_webkit/indexed_db_dispatcher_host.h"
-#include "chrome/common/indexed_db_key.h"
-#include "chrome/common/render_messages.h"
-#include "chrome/common/serialized_script_value.h"
+#include "chrome/common/indexed_db_messages.h"
#include "third_party/WebKit/WebKit/chromium/public/WebIDBCallbacks.h"
#include "third_party/WebKit/WebKit/chromium/public/WebIDBCursor.h"
#include "third_party/WebKit/WebKit/chromium/public/WebIDBDatabaseError.h"
@@ -22,16 +20,16 @@
// which (overloaded) onSuccess method we expect to be called.
template <class Type> struct WebIDBToMsgHelper { };
template <> struct WebIDBToMsgHelper<WebKit::WebIDBDatabase> {
- typedef ViewMsg_IDBCallbacksSuccessIDBDatabase MsgType;
+ typedef IndexedDBMsg_CallbacksSuccessIDBDatabase MsgType;
};
template <> struct WebIDBToMsgHelper<WebKit::WebIDBIndex> {
- typedef ViewMsg_IDBCallbacksSuccessIDBIndex MsgType;
+ typedef IndexedDBMsg_CallbacksSuccessIDBIndex MsgType;
};
template <> struct WebIDBToMsgHelper<WebKit::WebIDBObjectStore> {
- typedef ViewMsg_IDBCallbacksSuccessIDBObjectStore MsgType;
+ typedef IndexedDBMsg_CallbacksSuccessIDBObjectStore MsgType;
};
template <> struct WebIDBToMsgHelper<WebKit::WebIDBTransaction> {
- typedef ViewMsg_IDBCallbacksSuccessIDBTransaction MsgType;
+ typedef IndexedDBMsg_CallbacksSuccessIDBTransaction MsgType;
};
// The code the following two classes share.
@@ -90,11 +88,12 @@ class IndexedDBCallbacks<WebKit::WebIDBCursor>
virtual void onSuccess(WebKit::WebIDBCursor* idb_object) {
int32 object_id = dispatcher_host()->Add(idb_object);
dispatcher_host()->Send(
- new ViewMsg_IDBCallbacksSuccessIDBCursor(response_id(), object_id));
+ new IndexedDBMsg_CallbacksSuccessIDBCursor(response_id(), object_id));
}
virtual void onSuccess() {
- dispatcher_host()->Send(new ViewMsg_IDBCallbacksSuccessNull(response_id()));
+ dispatcher_host()->Send(new IndexedDBMsg_CallbacksSuccessNull(
+ response_id()));
}
private:
@@ -114,7 +113,7 @@ class IndexedDBCallbacks<WebKit::WebIDBKey>
virtual void onSuccess(const WebKit::WebIDBKey& value) {
dispatcher_host()->Send(
- new ViewMsg_IDBCallbacksSuccessIndexedDBKey(
+ new IndexedDBMsg_CallbacksSuccessIndexedDBKey(
response_id(), IndexedDBKey(value)));
}
@@ -135,7 +134,7 @@ class IndexedDBCallbacks<WebKit::WebSerializedScriptValue>
virtual void onSuccess(const WebKit::WebSerializedScriptValue& value) {
dispatcher_host()->Send(
- new ViewMsg_IDBCallbacksSuccessSerializedScriptValue(
+ new IndexedDBMsg_CallbacksSuccessSerializedScriptValue(
response_id(), SerializedScriptValue(value)));
}
@@ -153,7 +152,7 @@ class IndexedDBCallbacks<void> : public IndexedDBCallbacksBase {
virtual void onSuccess() {
dispatcher_host()->Send(
- new ViewMsg_IDBCallbacksSuccessNull(response_id()));
+ new IndexedDBMsg_CallbacksSuccessNull(response_id()));
}
private:
diff --git a/chrome/browser/in_process_webkit/indexed_db_context.cc b/chrome/browser/in_process_webkit/indexed_db_context.cc
index 7f492ac..86aa5fd 100644
--- a/chrome/browser/in_process_webkit/indexed_db_context.cc
+++ b/chrome/browser/in_process_webkit/indexed_db_context.cc
@@ -10,6 +10,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/in_process_webkit/webkit_context.h"
+#include "chrome/common/url_constants.h"
#include "third_party/WebKit/WebKit/chromium/public/WebCString.h"
#include "third_party/WebKit/WebKit/chromium/public/WebIDBDatabase.h"
#include "third_party/WebKit/WebKit/chromium/public/WebIDBFactory.h"
@@ -21,6 +22,28 @@ using WebKit::WebIDBDatabase;
using WebKit::WebIDBFactory;
using WebKit::WebSecurityOrigin;
+namespace {
+
+void ClearLocalState(const FilePath& indexeddb_path,
+ const char* url_scheme_to_be_skipped) {
+ file_util::FileEnumerator file_enumerator(
+ indexeddb_path, false, file_util::FileEnumerator::FILES);
+ // TODO(pastarmovj): We might need to consider exchanging this loop for
+ // something more efficient in the future.
+ for (FilePath file_path = file_enumerator.Next(); !file_path.empty();
+ file_path = file_enumerator.Next()) {
+ if (file_path.Extension() != IndexedDBContext::kIndexedDBExtension)
+ continue;
+ WebSecurityOrigin origin =
+ WebSecurityOrigin::createFromDatabaseIdentifier(
+ webkit_glue::FilePathToWebString(file_path.BaseName()));
+ if (!EqualsASCII(origin.protocol(), url_scheme_to_be_skipped))
+ file_util::Delete(file_path, false);
+ }
+}
+
+} // namespace
+
const FilePath::CharType IndexedDBContext::kIndexedDBDirectory[] =
FILE_PATH_LITERAL("IndexedDB");
@@ -28,10 +51,17 @@ const FilePath::CharType IndexedDBContext::kIndexedDBExtension[] =
FILE_PATH_LITERAL(".indexeddb");
IndexedDBContext::IndexedDBContext(WebKitContext* webkit_context)
- : webkit_context_(webkit_context) {
+ : clear_local_state_on_exit_(false) {
+ data_path_ = webkit_context->data_path().Append(kIndexedDBDirectory);
}
IndexedDBContext::~IndexedDBContext() {
+ // Not being on the WEBKIT thread here means we are running in a unit test
+ // where no clean up is needed.
+ if (clear_local_state_on_exit_ &&
+ BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)) {
+ ClearLocalState(data_path_, chrome::kExtensionScheme);
+ }
}
WebIDBFactory* IndexedDBContext::GetIDBFactory() {
@@ -43,29 +73,8 @@ WebIDBFactory* IndexedDBContext::GetIDBFactory() {
FilePath IndexedDBContext::GetIndexedDBFilePath(
const string16& origin_id) const {
- FilePath storage_dir = webkit_context_->data_path().Append(
- kIndexedDBDirectory);
FilePath::StringType id = webkit_glue::WebStringToFilePathString(origin_id);
- return storage_dir.Append(id.append(kIndexedDBExtension));
-}
-
-// static
-void IndexedDBContext::ClearLocalState(const FilePath& profile_path,
- const char* url_scheme_to_be_skipped) {
- file_util::FileEnumerator file_enumerator(profile_path.Append(
- kIndexedDBDirectory), false, file_util::FileEnumerator::FILES);
- // TODO(pastarmovj): We might need to consider exchanging this loop for
- // something more efficient in the future.
- for (FilePath file_path = file_enumerator.Next(); !file_path.empty();
- file_path = file_enumerator.Next()) {
- if (file_path.Extension() != IndexedDBContext::kIndexedDBExtension)
- continue;
- WebSecurityOrigin origin =
- WebSecurityOrigin::createFromDatabaseIdentifier(
- webkit_glue::FilePathToWebString(file_path.BaseName()));
- if (!EqualsASCII(origin.protocol(), url_scheme_to_be_skipped))
- file_util::Delete(file_path, false);
- }
+ return data_path_.Append(id.append(kIndexedDBExtension));
}
void IndexedDBContext::DeleteIndexedDBFile(const FilePath& file_path) {
diff --git a/chrome/browser/in_process_webkit/indexed_db_context.h b/chrome/browser/in_process_webkit/indexed_db_context.h
index 95f6536..16f8a0f 100644
--- a/chrome/browser/in_process_webkit/indexed_db_context.h
+++ b/chrome/browser/in_process_webkit/indexed_db_context.h
@@ -33,10 +33,9 @@ class IndexedDBContext {
// Get the file name of the indexed db file for the given origin.
FilePath GetIndexedDBFilePath(const string16& origin_id) const;
- // Deletes all idb files except for those on the url scheme
- // |url_scheme_to_be_skipped|.
- static void ClearLocalState(const FilePath& profile_path,
- const char* url_scheme_to_be_skipped);
+ void set_clear_local_state_on_exit(bool clear_local_state) {
+ clear_local_state_on_exit_ = clear_local_state;
+ }
// Deletes a single indexed db file.
void DeleteIndexedDBFile(const FilePath& file_path);
@@ -44,11 +43,19 @@ class IndexedDBContext {
// Deletes all indexed db files for the given origin.
void DeleteIndexedDBForOrigin(const string16& origin_id);
+#ifdef UNIT_TEST
+ // For unit tests allow to override the |data_path_|.
+ void set_data_path(const FilePath& data_path) { data_path_ = data_path; }
+#endif
+
private:
scoped_ptr<WebKit::WebIDBFactory> idb_factory_;
- // We're owned by this WebKit context.
- WebKitContext* webkit_context_;
+ // Path where the indexed db data is stored
+ FilePath data_path_;
+
+ // True if the destructor should delete its files.
+ bool clear_local_state_on_exit_;
DISALLOW_COPY_AND_ASSIGN(IndexedDBContext);
};
diff --git a/chrome/browser/in_process_webkit/indexed_db_dispatcher_host.cc b/chrome/browser/in_process_webkit/indexed_db_dispatcher_host.cc
index 52c6153..1463ab5 100644
--- a/chrome/browser/in_process_webkit/indexed_db_dispatcher_host.cc
+++ b/chrome/browser/in_process_webkit/indexed_db_dispatcher_host.cc
@@ -7,17 +7,16 @@
#include "base/command_line.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/host_content_settings_map.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/in_process_webkit/indexed_db_callbacks.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/browser_render_process_host.h"
+#include "chrome/browser/renderer_host/render_message_filter.h"
#include "chrome/browser/renderer_host/render_view_host_notification_task.h"
-#include "chrome/browser/renderer_host/resource_message_filter.h"
#include "chrome/common/chrome_switches.h"
-#include "chrome/common/indexed_db_key.h"
-#include "chrome/common/render_messages.h"
-#include "chrome/common/render_messages_params.h"
-#include "chrome/common/serialized_script_value.h"
+#include "chrome/common/indexed_db_messages.h"
+#include "chrome/common/result_codes.h"
#include "googleurl/src/gurl.h"
#include "third_party/WebKit/WebKit/chromium/public/WebDOMStringList.h"
#include "third_party/WebKit/WebKit/chromium/public/WebIDBCursor.h"
@@ -61,10 +60,9 @@ void DeleteOnWebKitThread(T* obj) {
}
-IndexedDBDispatcherHost::IndexedDBDispatcherHost(
- IPC::Message::Sender* sender, Profile* profile)
- : sender_(sender),
- webkit_context_(profile->GetWebKitContext()),
+IndexedDBDispatcherHost::IndexedDBDispatcherHost(int process_id,
+ Profile* profile)
+ : webkit_context_(profile->GetWebKitContext()),
host_content_settings_map_(profile->GetHostContentSettingsMap()),
ALLOW_THIS_IN_INITIALIZER_LIST(database_dispatcher_host_(
new DatabaseDispatcherHost(this))),
@@ -76,154 +74,60 @@ IndexedDBDispatcherHost::IndexedDBDispatcherHost(
new CursorDispatcherHost(this))),
ALLOW_THIS_IN_INITIALIZER_LIST(transaction_dispatcher_host_(
new TransactionDispatcherHost(this))),
- process_handle_(0) {
- DCHECK(sender_);
+ process_id_(process_id) {
DCHECK(webkit_context_.get());
}
IndexedDBDispatcherHost::~IndexedDBDispatcherHost() {
}
-void IndexedDBDispatcherHost::Init(int process_id,
- base::ProcessHandle process_handle) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK(sender_); // Ensure Shutdown() has not been called.
- DCHECK(!process_handle_); // Make sure Init() has not yet been called.
- DCHECK(process_handle);
- process_id_ = process_id;
- process_handle_ = process_handle;
-}
-
-void IndexedDBDispatcherHost::Shutdown() {
- if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
- sender_ = NULL;
-
- bool success = BrowserThread::PostTask(
+void IndexedDBDispatcherHost::OnChannelClosing() {
+ BrowserMessageFilter::OnChannelClosing();
+ BrowserThread::DeleteSoon(
+ BrowserThread::WEBKIT, FROM_HERE, database_dispatcher_host_.release());
+ BrowserThread::DeleteSoon(
+ BrowserThread::WEBKIT, FROM_HERE, index_dispatcher_host_.release());
+ BrowserThread::DeleteSoon(
BrowserThread::WEBKIT, FROM_HERE,
- NewRunnableMethod(this, &IndexedDBDispatcherHost::Shutdown));
- if (success)
- return;
- }
-
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT) ||
- CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess));
- DCHECK(!sender_);
-
- database_dispatcher_host_.reset();
- index_dispatcher_host_.reset();
- object_store_dispatcher_host_.reset();
- cursor_dispatcher_host_.reset();
- transaction_dispatcher_host_.reset();
-}
-
-bool IndexedDBDispatcherHost::OnMessageReceived(const IPC::Message& message) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK(process_handle_);
-
- switch (message.type()) {
- case ViewHostMsg_IDBCursorDirection::ID:
- case ViewHostMsg_IDBCursorKey::ID:
- case ViewHostMsg_IDBCursorValue::ID:
- case ViewHostMsg_IDBCursorUpdate::ID:
- case ViewHostMsg_IDBCursorContinue::ID:
- case ViewHostMsg_IDBCursorRemove::ID:
- case ViewHostMsg_IDBCursorDestroyed::ID:
- case ViewHostMsg_IDBFactoryOpen::ID:
- case ViewHostMsg_IDBDatabaseName::ID:
- case ViewHostMsg_IDBDatabaseVersion::ID:
- case ViewHostMsg_IDBDatabaseObjectStoreNames::ID:
- case ViewHostMsg_IDBDatabaseCreateObjectStore::ID:
- case ViewHostMsg_IDBDatabaseRemoveObjectStore::ID:
- case ViewHostMsg_IDBDatabaseSetVersion::ID:
- case ViewHostMsg_IDBDatabaseTransaction::ID:
- case ViewHostMsg_IDBDatabaseDestroyed::ID:
- case ViewHostMsg_IDBIndexName::ID:
- case ViewHostMsg_IDBIndexStoreName::ID:
- case ViewHostMsg_IDBIndexKeyPath::ID:
- case ViewHostMsg_IDBIndexUnique::ID:
- case ViewHostMsg_IDBIndexDestroyed::ID:
- case ViewHostMsg_IDBIndexOpenObjectCursor::ID:
- case ViewHostMsg_IDBIndexOpenKeyCursor::ID:
- case ViewHostMsg_IDBIndexGetObject::ID:
- case ViewHostMsg_IDBIndexGetKey::ID:
- case ViewHostMsg_IDBObjectStoreName::ID:
- case ViewHostMsg_IDBObjectStoreKeyPath::ID:
- case ViewHostMsg_IDBObjectStoreIndexNames::ID:
- case ViewHostMsg_IDBObjectStoreGet::ID:
- case ViewHostMsg_IDBObjectStorePut::ID:
- case ViewHostMsg_IDBObjectStoreRemove::ID:
- case ViewHostMsg_IDBObjectStoreCreateIndex::ID:
- case ViewHostMsg_IDBObjectStoreIndex::ID:
- case ViewHostMsg_IDBObjectStoreRemoveIndex::ID:
- case ViewHostMsg_IDBObjectStoreOpenCursor::ID:
- case ViewHostMsg_IDBObjectStoreDestroyed::ID:
- case ViewHostMsg_IDBTransactionAbort::ID:
- case ViewHostMsg_IDBTransactionMode::ID:
- case ViewHostMsg_IDBTransactionDestroyed::ID:
- case ViewHostMsg_IDBTransactionDidCompleteTaskEvents::ID:
- case ViewHostMsg_IDBTransactionObjectStore::ID:
- break;
- default:
- return false;
- }
-
- bool success = BrowserThread::PostTask(
- BrowserThread::WEBKIT, FROM_HERE, NewRunnableMethod(
- this, &IndexedDBDispatcherHost::OnMessageReceivedWebKit, message));
- DCHECK(success);
- return true;
-}
-
-void IndexedDBDispatcherHost::Send(IPC::Message* message) {
- if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
- // TODO(jorlow): Even if we successfully post, I believe it's possible for
- // the task to never run (if the IO thread is already shutting
- // down). We may want to handle this case, though
- // realistically it probably doesn't matter.
- if (!BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE, NewRunnableMethod(
- this, &IndexedDBDispatcherHost::Send, message))) {
- // The IO thread is dead.
- delete message;
- }
- return;
- }
+ object_store_dispatcher_host_.release());
+ BrowserThread::DeleteSoon(
+ BrowserThread::WEBKIT, FROM_HERE, cursor_dispatcher_host_.release());
+ BrowserThread::DeleteSoon(
+ BrowserThread::WEBKIT, FROM_HERE,
+ transaction_dispatcher_host_.release());
+}
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (!sender_)
- delete message;
- else
- sender_->Send(message);
+void IndexedDBDispatcherHost::OverrideThreadForMessage(
+ const IPC::Message& message,
+ BrowserThread::ID* thread) {
+ if (IPC_MESSAGE_CLASS(message) == IndexedDBMsgStart)
+ *thread = BrowserThread::WEBKIT;
}
-void IndexedDBDispatcherHost::OnMessageReceivedWebKit(
- const IPC::Message& message) {
+bool IndexedDBDispatcherHost::OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok) {
+ if (IPC_MESSAGE_CLASS(message) != IndexedDBMsgStart)
+ return false;
+
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
- DCHECK(process_handle_);
- bool msg_is_ok = true;
bool handled =
- database_dispatcher_host_->OnMessageReceived(message, &msg_is_ok) ||
- index_dispatcher_host_->OnMessageReceived(message, &msg_is_ok) ||
- object_store_dispatcher_host_->OnMessageReceived(message, &msg_is_ok) ||
- cursor_dispatcher_host_->OnMessageReceived(message, &msg_is_ok) ||
- transaction_dispatcher_host_->OnMessageReceived(message, &msg_is_ok);
+ database_dispatcher_host_->OnMessageReceived(message, message_was_ok) ||
+ index_dispatcher_host_->OnMessageReceived(message, message_was_ok) ||
+ object_store_dispatcher_host_->OnMessageReceived(
+ message, message_was_ok) ||
+ cursor_dispatcher_host_->OnMessageReceived(message, message_was_ok) ||
+ transaction_dispatcher_host_->OnMessageReceived(message, message_was_ok);
if (!handled) {
handled = true;
- DCHECK(msg_is_ok);
- IPC_BEGIN_MESSAGE_MAP_EX(IndexedDBDispatcherHost, message, msg_is_ok)
- IPC_MESSAGE_HANDLER(ViewHostMsg_IDBFactoryOpen,
- OnIDBFactoryOpen)
+ IPC_BEGIN_MESSAGE_MAP_EX(IndexedDBDispatcherHost, message, *message_was_ok)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryOpen, OnIDBFactoryOpen)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
}
- DCHECK(handled);
- if (!msg_is_ok) {
- BrowserRenderProcessHost::BadMessageTerminateProcess(message.type(),
- process_handle_);
- }
+ return handled;
}
int32 IndexedDBDispatcherHost::Add(WebIDBCursor* idb_cursor) {
@@ -253,7 +157,7 @@ int32 IndexedDBDispatcherHost::Add(WebIDBTransaction* idb_transaction) {
}
void IndexedDBDispatcherHost::OnIDBFactoryOpen(
- const ViewHostMsg_IDBFactoryOpen_Params& params) {
+ const IndexedDBHostMsg_FactoryOpen_Params& params) {
FilePath base_path = webkit_context_->data_path();
FilePath indexed_db_path;
if (!base_path.empty()) {
@@ -263,16 +167,16 @@ void IndexedDBDispatcherHost::OnIDBFactoryOpen(
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
GURL host(string16(WebSecurityOrigin::createFromDatabaseIdentifier(
- params.origin_).toString()));
+ params.origin).toString()));
ContentSetting content_setting =
host_content_settings_map_->GetContentSetting(
host, CONTENT_SETTINGS_TYPE_COOKIES, "");
CallRenderViewHostContentSettingsDelegate(
- process_id_, params.routing_id_,
+ process_id_, params.routing_id,
&RenderViewHostDelegate::ContentSettings::OnIndexedDBAccessed,
- host, params.description_, content_setting == CONTENT_SETTING_BLOCK);
+ host, params.name, content_setting == CONTENT_SETTING_BLOCK);
if (content_setting == CONTENT_SETTING_BLOCK) {
// TODO(jorlow): Change this to the proper error code once we figure out
@@ -280,12 +184,12 @@ void IndexedDBDispatcherHost::OnIDBFactoryOpen(
int error_code = 0; // Defined by the IndexedDB spec.
static string16 error_message = ASCIIToUTF16(
"The user denied permission to open the database.");
- Send(new ViewMsg_IDBCallbacksError(params.response_id_, error_code,
- error_message));
+ Send(new IndexedDBMsg_CallbacksError(params.response_id, error_code,
+ error_message));
return;
}
- DCHECK(kDefaultQuota == params.maximum_size_);
+ DCHECK(kDefaultQuota == params.maximum_size);
uint64 quota = kDefaultQuota;
if (CommandLine::ForCurrentProcess()->HasSwitch(
@@ -294,9 +198,9 @@ void IndexedDBDispatcherHost::OnIDBFactoryOpen(
}
Context()->GetIDBFactory()->open(
- params.name_, params.description_,
- new IndexedDBCallbacks<WebIDBDatabase>(this, params.response_id_),
- WebSecurityOrigin::createFromDatabaseIdentifier(params.origin_), NULL,
+ params.name,
+ new IndexedDBCallbacks<WebIDBDatabase>(this, params.response_id),
+ WebSecurityOrigin::createFromDatabaseIdentifier(params.origin), NULL,
webkit_glue::FilePathToWebString(indexed_db_path), quota);
}
@@ -306,38 +210,31 @@ void IndexedDBDispatcherHost::OnIDBFactoryOpen(
template <typename ObjectType>
ObjectType* IndexedDBDispatcherHost::GetOrTerminateProcess(
- IDMap<ObjectType, IDMapOwnPointer>* map, int32 return_object_id,
- IPC::Message* reply_msg, uint32 message_type) {
+ IDMap<ObjectType, IDMapOwnPointer>* map, int32 return_object_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
ObjectType* return_object = map->Lookup(return_object_id);
if (!return_object) {
- BrowserRenderProcessHost::BadMessageTerminateProcess(message_type,
- process_handle_);
- delete reply_msg;
+ UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_IDBMF"));
+ BadMessageReceived();
}
return return_object;
}
-template <typename ReplyType, typename MessageType,
- typename MapObjectType, typename Method>
+template <typename ReplyType, typename MapObjectType, typename Method>
void IndexedDBDispatcherHost::SyncGetter(
IDMap<MapObjectType, IDMapOwnPointer>* map, int32 object_id,
- IPC::Message* reply_msg, Method method) {
- MapObjectType* object = GetOrTerminateProcess(map, object_id, reply_msg,
- MessageType::ID);
+ ReplyType* reply, Method method) {
+ MapObjectType* object = GetOrTerminateProcess(map, object_id);
if (!object)
return;
- ReplyType reply = (object->*method)();
- MessageType::WriteReplyParams(reply_msg, reply);
- Send(reply_msg);
+ *reply = (object->*method)();
}
template <typename ObjectType>
void IndexedDBDispatcherHost::DestroyObject(
- IDMap<ObjectType, IDMapOwnPointer>* map, int32 object_id,
- uint32 message_type) {
- GetOrTerminateProcess(map, object_id, NULL, message_type);
+ IDMap<ObjectType, IDMapOwnPointer>* map, int32 object_id) {
+ GetOrTerminateProcess(map, object_id);
map->Remove(object_id);
}
@@ -360,19 +257,17 @@ bool IndexedDBDispatcherHost::DatabaseDispatcherHost::OnMessageReceived(
bool handled = true;
IPC_BEGIN_MESSAGE_MAP_EX(IndexedDBDispatcherHost::DatabaseDispatcherHost,
message, *msg_is_ok)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBDatabaseName, OnName)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBDatabaseVersion, OnVersion)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBDatabaseObjectStoreNames,
- OnObjectStoreNames)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBDatabaseCreateObjectStore,
- OnCreateObjectStore)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBDatabaseRemoveObjectStore,
- OnRemoveObjectStore)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBDatabaseSetVersion,
- OnSetVersion)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBDatabaseTransaction,
- OnTransaction)
- IPC_MESSAGE_HANDLER(ViewHostMsg_IDBDatabaseDestroyed, OnDestroyed)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseName, OnName)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseVersion, OnVersion)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseObjectStoreNames,
+ OnObjectStoreNames)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateObjectStore,
+ OnCreateObjectStore)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteObjectStore,
+ OnDeleteObjectStore)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetVersion, OnSetVersion)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseTransaction, OnTransaction)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDestroyed, OnDestroyed)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
@@ -380,104 +275,84 @@ bool IndexedDBDispatcherHost::DatabaseDispatcherHost::OnMessageReceived(
void IndexedDBDispatcherHost::DatabaseDispatcherHost::Send(
IPC::Message* message) {
- // The macro magic in OnMessageReceived requires this to link, but it should
- // never actually be called.
- NOTREACHED();
parent_->Send(message);
}
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnName(
- int32 object_id, IPC::Message* reply_msg) {
- parent_->SyncGetter<string16, ViewHostMsg_IDBDatabaseName>(
- &map_, object_id, reply_msg, &WebIDBDatabase::name);
+ int32 object_id, string16* name) {
+ parent_->SyncGetter<string16>(&map_, object_id, name, &WebIDBDatabase::name);
}
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnVersion(
- int32 object_id, IPC::Message* reply_msg) {
- parent_->SyncGetter<string16, ViewHostMsg_IDBDatabaseVersion>(
- &map_, object_id, reply_msg, &WebIDBDatabase::version);
+ int32 object_id, string16* version) {
+ parent_->SyncGetter<string16>(
+ &map_, object_id, version, &WebIDBDatabase::version);
}
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnObjectStoreNames(
- int32 idb_database_id, IPC::Message* reply_msg) {
+ int32 idb_database_id, std::vector<string16>* object_stores) {
WebIDBDatabase* idb_database = parent_->GetOrTerminateProcess(
- &map_, idb_database_id, reply_msg,
- ViewHostMsg_IDBDatabaseObjectStoreNames::ID);
+ &map_, idb_database_id);
if (!idb_database)
return;
WebDOMStringList web_object_stores = idb_database->objectStoreNames();
- std::vector<string16> object_stores;
- object_stores.reserve(web_object_stores.length());
+ object_stores->reserve(web_object_stores.length());
for (unsigned i = 0; i < web_object_stores.length(); ++i)
- object_stores.push_back(web_object_stores.item(i));
- ViewHostMsg_IDBDatabaseObjectStoreNames::WriteReplyParams(reply_msg,
- object_stores);
- parent_->Send(reply_msg);
+ object_stores->push_back(web_object_stores.item(i));
}
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateObjectStore(
- const ViewHostMsg_IDBDatabaseCreateObjectStore_Params& params,
- IPC::Message* reply_msg) {
+ const IndexedDBHostMsg_DatabaseCreateObjectStore_Params& params,
+ int32* object_store_id, WebKit::WebExceptionCode* ec) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
WebIDBDatabase* idb_database = parent_->GetOrTerminateProcess(
- &map_, params.idb_database_id_, NULL,
- ViewHostMsg_IDBDatabaseCreateObjectStore::ID);
+ &map_, params.idb_database_id);
WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
- &parent_->transaction_dispatcher_host_->map_, params.transaction_id_,
- NULL, ViewHostMsg_IDBDatabaseCreateObjectStore::ID);
+ &parent_->transaction_dispatcher_host_->map_, params.transaction_id);
if (!idb_database || !idb_transaction)
return;
- WebExceptionCode ec = 0;
+ *ec = 0;
WebIDBObjectStore* object_store = idb_database->createObjectStore(
- params.name_, params.key_path_, params.auto_increment_,
- *idb_transaction, ec);
- ViewHostMsg_IDBDatabaseCreateObjectStore::WriteReplyParams(
- reply_msg, ec ? 0 : parent_->Add(object_store), ec);
- parent_->Send(reply_msg);
+ params.name, params.key_path, params.auto_increment,
+ *idb_transaction, *ec);
+ *object_store_id = *ec ? 0 : parent_->Add(object_store);
}
-void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnRemoveObjectStore(
+void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteObjectStore(
int32 idb_database_id,
const string16& name,
int32 transaction_id,
- IPC::Message* reply_msg) {
+ WebKit::WebExceptionCode* ec) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
WebIDBDatabase* idb_database = parent_->GetOrTerminateProcess(
- &map_, idb_database_id, NULL,
- ViewHostMsg_IDBDatabaseRemoveObjectStore::ID);
+ &map_, idb_database_id);
WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
- &parent_->transaction_dispatcher_host_->map_, transaction_id, NULL,
- ViewHostMsg_IDBDatabaseRemoveObjectStore::ID);
+ &parent_->transaction_dispatcher_host_->map_, transaction_id);
if (!idb_database || !idb_transaction)
return;
- WebExceptionCode ec = 0;
- idb_database->removeObjectStore(name, *idb_transaction, ec);
- ViewHostMsg_IDBDatabaseRemoveObjectStore::WriteReplyParams(reply_msg, ec);
- parent_->Send(reply_msg);
+ *ec = 0;
+ idb_database->deleteObjectStore(name, *idb_transaction, *ec);
}
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetVersion(
int32 idb_database_id,
int32 response_id,
const string16& version,
- IPC::Message* reply_msg) {
+ WebKit::WebExceptionCode* ec) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
WebIDBDatabase* idb_database = parent_->GetOrTerminateProcess(
- &map_, idb_database_id, NULL,
- ViewHostMsg_IDBDatabaseSetVersion::ID);
+ &map_, idb_database_id);
if (!idb_database)
return;
- WebExceptionCode ec = 0;
+ *ec = 0;
idb_database->setVersion(
version,
new IndexedDBCallbacks<WebIDBTransaction>(parent_, response_id),
- ec);
- ViewHostMsg_IDBDatabaseSetVersion::WriteReplyParams(reply_msg, ec);
- parent_->Send(reply_msg);
+ *ec);
}
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnTransaction(
@@ -485,10 +360,10 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnTransaction(
const std::vector<string16>& names,
int32 mode,
int32 timeout,
- IPC::Message* reply_msg) {
+ int32* idb_transaction_id,
+ WebKit::WebExceptionCode* ec) {
WebIDBDatabase* database = parent_->GetOrTerminateProcess(
- &map_, idb_database_id, reply_msg,
- ViewHostMsg_IDBDatabaseTransaction::ID);
+ &map_, idb_database_id);
if (!database)
return;
@@ -498,19 +373,16 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnTransaction(
object_stores.append(*it);
}
- WebExceptionCode ec = 0;
+ *ec = 0;
WebIDBTransaction* transaction = database->transaction(
- object_stores, mode, timeout, ec);
- DCHECK(!transaction != !ec);
- int32 id = ec ? 0 : parent_->Add(transaction);
- ViewHostMsg_IDBDatabaseTransaction::WriteReplyParams(reply_msg, id, ec);
- parent_->Send(reply_msg);
+ object_stores, mode, timeout, *ec);
+ DCHECK(!transaction != !*ec);
+ *idb_transaction_id = *ec ? 0 : parent_->Add(transaction);
}
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDestroyed(
int32 object_id) {
- parent_->DestroyObject(&map_, object_id,
- ViewHostMsg_IDBDatabaseDestroyed::ID);
+ parent_->DestroyObject(&map_, object_id);
}
@@ -532,17 +404,16 @@ bool IndexedDBDispatcherHost::IndexDispatcherHost::OnMessageReceived(
bool handled = true;
IPC_BEGIN_MESSAGE_MAP_EX(IndexedDBDispatcherHost::IndexDispatcherHost,
message, *msg_is_ok)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBIndexName, OnName)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBIndexStoreName, OnStoreName)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBIndexKeyPath, OnKeyPath)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBIndexUnique, OnUnique)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBIndexOpenObjectCursor,
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_IndexName, OnName)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_IndexStoreName, OnStoreName)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_IndexKeyPath, OnKeyPath)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_IndexUnique, OnUnique)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_IndexOpenObjectCursor,
OnOpenObjectCursor)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBIndexOpenKeyCursor,
- OnOpenKeyCursor)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBIndexGetObject, OnGetObject)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBIndexGetKey, OnGetKey)
- IPC_MESSAGE_HANDLER(ViewHostMsg_IDBIndexDestroyed, OnDestroyed)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_IndexOpenKeyCursor, OnOpenKeyCursor)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_IndexGetObject, OnGetObject)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_IndexGetKey, OnGetKey)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_IndexDestroyed, OnDestroyed)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
@@ -550,81 +421,69 @@ bool IndexedDBDispatcherHost::IndexDispatcherHost::OnMessageReceived(
void IndexedDBDispatcherHost::IndexDispatcherHost::Send(
IPC::Message* message) {
- // The macro magic in OnMessageReceived requires this to link, but it should
- // never actually be called.
- NOTREACHED();
parent_->Send(message);
}
void IndexedDBDispatcherHost::IndexDispatcherHost::OnName(
- int32 object_id, IPC::Message* reply_msg) {
- parent_->SyncGetter<string16, ViewHostMsg_IDBIndexName>(
- &map_, object_id, reply_msg, &WebIDBIndex::name);
+ int32 object_id, string16* name) {
+ parent_->SyncGetter<string16>(&map_, object_id, name, &WebIDBIndex::name);
}
void IndexedDBDispatcherHost::IndexDispatcherHost::OnStoreName(
- int32 object_id, IPC::Message* reply_msg) {
- parent_->SyncGetter<string16, ViewHostMsg_IDBIndexStoreName>(
- &map_, object_id, reply_msg, &WebIDBIndex::storeName);
+ int32 object_id, string16* store_name) {
+ parent_->SyncGetter<string16>(
+ &map_, object_id, store_name, &WebIDBIndex::storeName);
}
void IndexedDBDispatcherHost::IndexDispatcherHost::OnKeyPath(
- int32 object_id, IPC::Message* reply_msg) {
- parent_->SyncGetter<NullableString16, ViewHostMsg_IDBIndexKeyPath>(
- &map_, object_id, reply_msg, &WebIDBIndex::keyPath);
+ int32 object_id, NullableString16* key_path) {
+ parent_->SyncGetter<NullableString16>(
+ &map_, object_id, key_path, &WebIDBIndex::keyPath);
}
void IndexedDBDispatcherHost::IndexDispatcherHost::OnUnique(
- int32 object_id, IPC::Message* reply_msg) {
- parent_->SyncGetter<bool, ViewHostMsg_IDBIndexUnique>(
- &map_, object_id, reply_msg, &WebIDBIndex::unique);
+ int32 object_id, bool* unique) {
+ parent_->SyncGetter<bool>(&map_, object_id, unique, &WebIDBIndex::unique);
}
void IndexedDBDispatcherHost::IndexDispatcherHost::OnOpenObjectCursor(
- const ViewHostMsg_IDBIndexOpenCursor_Params& params,
- IPC::Message* reply_msg) {
+ const IndexedDBHostMsg_IndexOpenCursor_Params& params,
+ WebKit::WebExceptionCode* ec) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
WebIDBIndex* idb_index = parent_->GetOrTerminateProcess(
- &map_, params.idb_index_id_, NULL,
- ViewHostMsg_IDBIndexOpenObjectCursor::ID);
+ &map_, params.idb_index_id);
WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
- &parent_->transaction_dispatcher_host_->map_,
- params.transaction_id_, NULL, ViewHostMsg_IDBIndexOpenObjectCursor::ID);
+ &parent_->transaction_dispatcher_host_->map_, params.transaction_id);
if (!idb_transaction || !idb_index)
return;
+ *ec = 0;
scoped_ptr<WebIDBCallbacks> callbacks(
- new IndexedDBCallbacks<WebIDBCursor>(parent_, params.response_id_));
- WebExceptionCode ec = 0;
+ new IndexedDBCallbacks<WebIDBCursor>(parent_, params.response_id));
idb_index->openObjectCursor(
- WebIDBKeyRange(params.lower_key_, params.upper_key_, params.lower_open_,
- params.upper_open_),
- params.direction_, callbacks.release(), *idb_transaction, ec);
- ViewHostMsg_IDBIndexOpenObjectCursor::WriteReplyParams(reply_msg, ec);
- parent_->Send(reply_msg);
+ WebIDBKeyRange(params.lower_key, params.upper_key, params.lower_open,
+ params.upper_open),
+ params.direction, callbacks.release(), *idb_transaction, *ec);
}
void IndexedDBDispatcherHost::IndexDispatcherHost::OnOpenKeyCursor(
- const ViewHostMsg_IDBIndexOpenCursor_Params& params,
- IPC::Message* reply_msg) {
+ const IndexedDBHostMsg_IndexOpenCursor_Params& params,
+ WebKit::WebExceptionCode* ec) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
WebIDBIndex* idb_index = parent_->GetOrTerminateProcess(
- &map_, params.idb_index_id_, NULL, ViewHostMsg_IDBIndexOpenKeyCursor::ID);
+ &map_, params.idb_index_id);
WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
- &parent_->transaction_dispatcher_host_->map_, params.transaction_id_,
- NULL, ViewHostMsg_IDBIndexOpenKeyCursor::ID);
+ &parent_->transaction_dispatcher_host_->map_, params.transaction_id);
if (!idb_transaction || !idb_index)
return;
+ *ec = 0;
scoped_ptr<WebIDBCallbacks> callbacks(
- new IndexedDBCallbacks<WebIDBCursor>(parent_, params.response_id_));
- WebExceptionCode ec = 0;
+ new IndexedDBCallbacks<WebIDBCursor>(parent_, params.response_id));
idb_index->openKeyCursor(
- WebIDBKeyRange(params.lower_key_, params.upper_key_, params.lower_open_,
- params.upper_open_),
- params.direction_, callbacks.release(), *idb_transaction, ec);
- ViewHostMsg_IDBIndexOpenKeyCursor::WriteReplyParams(reply_msg, ec);
- parent_->Send(reply_msg);
+ WebIDBKeyRange(params.lower_key, params.upper_key, params.lower_open,
+ params.upper_open),
+ params.direction, callbacks.release(), *idb_transaction, *ec);
}
void IndexedDBDispatcherHost::IndexDispatcherHost::OnGetObject(
@@ -632,22 +491,19 @@ void IndexedDBDispatcherHost::IndexDispatcherHost::OnGetObject(
int32 response_id,
const IndexedDBKey& key,
int32 transaction_id,
- IPC::Message* reply_msg) {
+ WebKit::WebExceptionCode* ec) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
WebIDBIndex* idb_index = parent_->GetOrTerminateProcess(
- &map_, idb_index_id, NULL, ViewHostMsg_IDBIndexGetObject::ID);
+ &map_, idb_index_id);
WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
- &parent_->transaction_dispatcher_host_->map_, transaction_id, NULL,
- ViewHostMsg_IDBIndexGetObject::ID);
+ &parent_->transaction_dispatcher_host_->map_, transaction_id);
if (!idb_transaction || !idb_index)
return;
+ *ec = 0;
scoped_ptr<WebIDBCallbacks> callbacks(
new IndexedDBCallbacks<WebSerializedScriptValue>(parent_, response_id));
- WebExceptionCode ec = 0;
- idb_index->getObject(key, callbacks.release(), *idb_transaction, ec);
- ViewHostMsg_IDBIndexGetObject::WriteReplyParams(reply_msg, ec);
- parent_->Send(reply_msg);
+ idb_index->getObject(key, callbacks.release(), *idb_transaction, *ec);
}
void IndexedDBDispatcherHost::IndexDispatcherHost::OnGetKey(
@@ -655,27 +511,24 @@ void IndexedDBDispatcherHost::IndexDispatcherHost::OnGetKey(
int32 response_id,
const IndexedDBKey& key,
int32 transaction_id,
- IPC::Message* reply_msg) {
+ WebKit::WebExceptionCode* ec) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
WebIDBIndex* idb_index = parent_->GetOrTerminateProcess(
- &map_, idb_index_id, NULL, ViewHostMsg_IDBIndexGetKey::ID);
+ &map_, idb_index_id);
WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
- &parent_->transaction_dispatcher_host_->map_, transaction_id, NULL,
- ViewHostMsg_IDBIndexGetKey::ID);
+ &parent_->transaction_dispatcher_host_->map_, transaction_id);
if (!idb_transaction || !idb_index)
return;
+ *ec = 0;
scoped_ptr<WebIDBCallbacks> callbacks(
new IndexedDBCallbacks<WebIDBKey>(parent_, response_id));
- WebExceptionCode ec = 0;
- idb_index->getKey(key, callbacks.release(), *idb_transaction, ec);
- ViewHostMsg_IDBIndexGetKey::WriteReplyParams(reply_msg, ec);
- parent_->Send(reply_msg);
+ idb_index->getKey(key, callbacks.release(), *idb_transaction, *ec);
}
void IndexedDBDispatcherHost::IndexDispatcherHost::OnDestroyed(
int32 object_id) {
- parent_->DestroyObject(&map_, object_id, ViewHostMsg_IDBIndexDestroyed::ID);
+ parent_->DestroyObject(&map_, object_id);
}
//////////////////////////////////////////////////////////////////////
@@ -697,22 +550,17 @@ bool IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnMessageReceived(
bool handled = true;
IPC_BEGIN_MESSAGE_MAP_EX(IndexedDBDispatcherHost::ObjectStoreDispatcherHost,
message, *msg_is_ok)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBObjectStoreName, OnName)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBObjectStoreKeyPath,
- OnKeyPath)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBObjectStoreIndexNames,
- OnIndexNames)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBObjectStoreGet, OnGet);
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBObjectStorePut, OnPut);
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBObjectStoreRemove, OnRemove);
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBObjectStoreCreateIndex,
- OnCreateIndex);
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBObjectStoreIndex, OnIndex);
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBObjectStoreRemoveIndex,
- OnRemoveIndex);
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBObjectStoreOpenCursor,
- OnOpenCursor)
- IPC_MESSAGE_HANDLER(ViewHostMsg_IDBObjectStoreDestroyed, OnDestroyed)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreName, OnName)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreKeyPath, OnKeyPath)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreIndexNames, OnIndexNames)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreGet, OnGet)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStorePut, OnPut)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreDelete, OnDelete)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreCreateIndex, OnCreateIndex)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreIndex, OnIndex)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreDeleteIndex, OnDeleteIndex)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreOpenCursor, OnOpenCursor)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreDestroyed, OnDestroyed)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
@@ -720,40 +568,32 @@ bool IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnMessageReceived(
void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::Send(
IPC::Message* message) {
- // The macro magic in OnMessageReceived requires this to link, but it should
- // never actually be called.
- NOTREACHED();
parent_->Send(message);
}
void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnName(
- int32 object_id, IPC::Message* reply_msg) {
- parent_->SyncGetter<string16, ViewHostMsg_IDBObjectStoreName>(
- &map_, object_id, reply_msg, &WebIDBObjectStore::name);
+ int32 object_id, string16* name) {
+ parent_->SyncGetter<string16>(
+ &map_, object_id, name, &WebIDBObjectStore::name);
}
void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnKeyPath(
- int32 object_id, IPC::Message* reply_msg) {
- parent_->SyncGetter<NullableString16, ViewHostMsg_IDBObjectStoreKeyPath>(
- &map_, object_id, reply_msg, &WebIDBObjectStore::keyPath);
+ int32 object_id, NullableString16* keyPath) {
+ parent_->SyncGetter<NullableString16>(
+ &map_, object_id, keyPath, &WebIDBObjectStore::keyPath);
}
void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnIndexNames(
- int32 idb_object_store_id, IPC::Message* reply_msg) {
+ int32 idb_object_store_id, std::vector<string16>* index_names) {
WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess(
- &map_, idb_object_store_id, reply_msg,
- ViewHostMsg_IDBObjectStoreIndexNames::ID);
+ &map_, idb_object_store_id);
if (!idb_object_store)
return;
WebDOMStringList web_index_names = idb_object_store->indexNames();
- std::vector<string16> index_names;
- index_names.reserve(web_index_names.length());
+ index_names->reserve(web_index_names.length());
for (unsigned i = 0; i < web_index_names.length(); ++i)
- index_names.push_back(web_index_names.item(i));
- ViewHostMsg_IDBObjectStoreIndexNames::WriteReplyParams(reply_msg,
- index_names);
- parent_->Send(reply_msg);
+ index_names->push_back(web_index_names.item(i));
}
void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnGet(
@@ -761,157 +601,133 @@ void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnGet(
int32 response_id,
const IndexedDBKey& key,
int32 transaction_id,
- IPC::Message* reply_msg) {
+ WebKit::WebExceptionCode* ec) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess(
- &map_, idb_object_store_id, NULL, ViewHostMsg_IDBObjectStoreGet::ID);
+ &map_, idb_object_store_id);
WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
- &parent_->transaction_dispatcher_host_->map_, transaction_id, NULL,
- ViewHostMsg_IDBObjectStoreGet::ID);
+ &parent_->transaction_dispatcher_host_->map_, transaction_id);
if (!idb_transaction || !idb_object_store)
return;
+ *ec = 0;
scoped_ptr<WebIDBCallbacks> callbacks(
new IndexedDBCallbacks<WebSerializedScriptValue>(parent_, response_id));
- WebExceptionCode ec = 0;
- idb_object_store->get(key, callbacks.release(), *idb_transaction, ec);
- ViewHostMsg_IDBObjectStoreGet::WriteReplyParams(reply_msg, ec);
- parent_->Send(reply_msg);
+ idb_object_store->get(key, callbacks.release(), *idb_transaction, *ec);
}
void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnPut(
- const ViewHostMsg_IDBObjectStorePut_Params& params,
- IPC::Message* reply_msg) {
+ const IndexedDBHostMsg_ObjectStorePut_Params& params,
+ WebKit::WebExceptionCode* ec) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess(
- &map_, params.idb_object_store_id_, NULL,
- ViewHostMsg_IDBObjectStorePut::ID);
+ &map_, params.idb_object_store_id);
WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
- &parent_->transaction_dispatcher_host_->map_, params.transaction_id_,
- NULL, ViewHostMsg_IDBObjectStorePut::ID);
+ &parent_->transaction_dispatcher_host_->map_, params.transaction_id);
if (!idb_transaction || !idb_object_store)
return;
+ *ec = 0;
scoped_ptr<WebIDBCallbacks> callbacks(
- new IndexedDBCallbacks<WebIDBKey>(parent_, params.response_id_));
- WebExceptionCode ec = 0;
- idb_object_store->put(params.serialized_value_, params.key_, params.add_only_,
- callbacks.release(), *idb_transaction, ec);
- ViewHostMsg_IDBObjectStorePut::WriteReplyParams(reply_msg, ec);
- parent_->Send(reply_msg);
+ new IndexedDBCallbacks<WebIDBKey>(parent_, params.response_id));
+ idb_object_store->put(params.serialized_value, params.key, params.add_only,
+ callbacks.release(), *idb_transaction, *ec);
}
-void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnRemove(
+void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnDelete(
int idb_object_store_id,
int32 response_id,
const IndexedDBKey& key,
int32 transaction_id,
- IPC::Message* reply_msg) {
+ WebKit::WebExceptionCode* ec) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess(
- &map_, idb_object_store_id, NULL, ViewHostMsg_IDBObjectStoreRemove::ID);
+ &map_, idb_object_store_id);
WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
- &parent_->transaction_dispatcher_host_->map_, transaction_id, NULL,
- ViewHostMsg_IDBObjectStoreRemove::ID);
+ &parent_->transaction_dispatcher_host_->map_, transaction_id);
if (!idb_transaction || !idb_object_store)
return;
+ *ec = 0;
scoped_ptr<WebIDBCallbacks> callbacks(
new IndexedDBCallbacks<void>(parent_, response_id));
- WebExceptionCode ec = 0;
- idb_object_store->remove(key, callbacks.release(), *idb_transaction, ec);
- ViewHostMsg_IDBObjectStoreRemove::WriteReplyParams(reply_msg, ec);
- parent_->Send(reply_msg);
+ idb_object_store->deleteFunction(
+ key, callbacks.release(), *idb_transaction, *ec);
}
void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnCreateIndex(
- const ViewHostMsg_IDBObjectStoreCreateIndex_Params& params,
- IPC::Message* reply_msg) {
+ const IndexedDBHostMsg_ObjectStoreCreateIndex_Params& params,
+ int32* index_id, WebKit::WebExceptionCode* ec) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess(
- &map_, params.idb_object_store_id_, NULL,
- ViewHostMsg_IDBObjectStoreCreateIndex::ID);
+ &map_, params.idb_object_store_id);
WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
- &parent_->transaction_dispatcher_host_->map_, params.transaction_id_,
- NULL, ViewHostMsg_IDBObjectStoreCreateIndex::ID);
+ &parent_->transaction_dispatcher_host_->map_, params.transaction_id);
if (!idb_object_store || !idb_transaction)
return;
- WebExceptionCode ec = 0;
+ *ec = 0;
WebIDBIndex* index = idb_object_store->createIndex(
- params.name_, params.key_path_, params.unique_, *idb_transaction, ec);
- ViewHostMsg_IDBObjectStoreCreateIndex::WriteReplyParams(
- reply_msg, ec ? 0 : parent_->Add(index), ec);
- parent_->Send(reply_msg);
+ params.name, params.key_path, params.unique, *idb_transaction, *ec);
+ *index_id = *ec ? 0 : parent_->Add(index);
}
void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnIndex(
int32 idb_object_store_id,
const string16& name,
- IPC::Message* reply_msg) {
+ int32* idb_index_id,
+ WebKit::WebExceptionCode* ec) {
WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess(
- &map_, idb_object_store_id, reply_msg,
- ViewHostMsg_IDBObjectStoreIndex::ID);
+ &map_, idb_object_store_id);
if (!idb_object_store)
return;
- WebExceptionCode ec = 0;
- WebIDBIndex* index = idb_object_store->index(name, ec);
- int32 object_id = parent_->Add(index);
- ViewHostMsg_IDBObjectStoreIndex::WriteReplyParams(reply_msg, object_id, ec);
- parent_->Send(reply_msg);
+ *ec = 0;
+ WebIDBIndex* index = idb_object_store->index(name, *ec);
+ *idb_index_id = parent_->Add(index);
}
-void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnRemoveIndex(
+void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnDeleteIndex(
int32 idb_object_store_id,
const string16& name,
int32 transaction_id,
- IPC::Message* reply_msg) {
+ WebKit::WebExceptionCode* ec) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess(
- &map_, idb_object_store_id, NULL,
- ViewHostMsg_IDBObjectStoreRemoveIndex::ID);
+ &map_, idb_object_store_id);
WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
- &parent_->transaction_dispatcher_host_->map_, transaction_id, NULL,
- ViewHostMsg_IDBObjectStoreRemoveIndex::ID);
+ &parent_->transaction_dispatcher_host_->map_, transaction_id);
if (!idb_object_store || !idb_transaction)
return;
- WebExceptionCode ec = 0;
- idb_object_store->deleteIndex(name, *idb_transaction, ec);
- ViewHostMsg_IDBObjectStoreRemoveIndex::WriteReplyParams(reply_msg, ec);
- parent_->Send(reply_msg);
+ *ec = 0;
+ idb_object_store->deleteIndex(name, *idb_transaction, *ec);
}
void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnOpenCursor(
- const ViewHostMsg_IDBObjectStoreOpenCursor_Params& params,
- IPC::Message* reply_msg) {
+ const IndexedDBHostMsg_ObjectStoreOpenCursor_Params& params,
+ WebKit::WebExceptionCode* ec) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess(
&parent_->object_store_dispatcher_host_->map_,
- params.idb_object_store_id_, NULL,
- ViewHostMsg_IDBObjectStoreOpenCursor::ID);
+ params.idb_object_store_id);
WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
- &parent_->transaction_dispatcher_host_->map_, params.transaction_id_,
- NULL, ViewHostMsg_IDBObjectStoreOpenCursor::ID);
+ &parent_->transaction_dispatcher_host_->map_, params.transaction_id);
if (!idb_transaction || !idb_object_store)
return;
+ *ec = 0;
scoped_ptr<WebIDBCallbacks> callbacks(
- new IndexedDBCallbacks<WebIDBCursor>(parent_, params.response_id_));
- WebExceptionCode ec = 0;
+ new IndexedDBCallbacks<WebIDBCursor>(parent_, params.response_id));
idb_object_store->openCursor(
- WebIDBKeyRange(params.lower_key_, params.upper_key_, params.lower_open_,
- params.upper_open_),
- params.direction_, callbacks.release(), *idb_transaction, ec);
- ViewHostMsg_IDBObjectStoreOpenCursor::WriteReplyParams(reply_msg, ec);
- parent_->Send(reply_msg);
+ WebIDBKeyRange(params.lower_key, params.upper_key, params.lower_open,
+ params.upper_open),
+ params.direction, callbacks.release(), *idb_transaction, *ec);
}
void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnDestroyed(
int32 object_id) {
- parent_->DestroyObject(
- &map_, object_id, ViewHostMsg_IDBObjectStoreDestroyed::ID);
+ parent_->DestroyObject(&map_, object_id);
}
//////////////////////////////////////////////////////////////////////
@@ -932,14 +748,13 @@ bool IndexedDBDispatcherHost::CursorDispatcherHost::OnMessageReceived(
bool handled = true;
IPC_BEGIN_MESSAGE_MAP_EX(IndexedDBDispatcherHost::CursorDispatcherHost,
message, *msg_is_ok)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBCursorDirection,
- OnDirection)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBCursorKey, OnKey)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBCursorValue, OnValue)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBCursorUpdate, OnUpdate)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBCursorContinue, OnContinue)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBCursorRemove, OnRemove)
- IPC_MESSAGE_HANDLER(ViewHostMsg_IDBCursorDestroyed, OnDestroyed)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorDirection, OnDirection)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorKey, OnKey)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorValue, OnValue)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorUpdate, OnUpdate)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorContinue, OnContinue)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorDelete, OnDelete)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorDestroyed, OnDestroyed)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
@@ -948,110 +763,90 @@ bool IndexedDBDispatcherHost::CursorDispatcherHost::OnMessageReceived(
void IndexedDBDispatcherHost::CursorDispatcherHost::Send(
IPC::Message* message) {
- // The macro magic in OnMessageReceived requires this to link, but it should
- // never actually be called.
- NOTREACHED();
parent_->Send(message);
}
void IndexedDBDispatcherHost::CursorDispatcherHost::OnDirection(
- int32 object_id, IPC::Message* reply_msg) {
- WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(
- &map_, object_id, reply_msg,
- ViewHostMsg_IDBCursorDirection::ID);
+ int32 object_id, int32* direction) {
+ WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(&map_, object_id);
if (!idb_cursor)
return;
- int direction = idb_cursor->direction();
- ViewHostMsg_IDBCursorDirection::WriteReplyParams(reply_msg, direction);
- parent_->Send(reply_msg);
+ *direction = idb_cursor->direction();
}
void IndexedDBDispatcherHost::CursorDispatcherHost::OnKey(
- int32 object_id, IPC::Message* reply_msg) {
- WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(
- &map_, object_id, reply_msg,
- ViewHostMsg_IDBCursorKey::ID);
+ int32 object_id, IndexedDBKey* key) {
+ WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(&map_, object_id);
if (!idb_cursor)
return;
- IndexedDBKey key(idb_cursor->key());
- ViewHostMsg_IDBCursorKey::WriteReplyParams(reply_msg, key);
- parent_->Send(reply_msg);
+ *key = IndexedDBKey(idb_cursor->key());
}
void IndexedDBDispatcherHost::CursorDispatcherHost::OnValue(
- int32 object_id, IPC::Message* reply_msg) {
- WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(
- &map_, object_id, reply_msg,
- ViewHostMsg_IDBCursorValue::ID);
+ int32 object_id,
+ SerializedScriptValue* script_value,
+ IndexedDBKey* key) {
+ WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(&map_, object_id);
if (!idb_cursor)
return;
- WebSerializedScriptValue scriptValue;
- WebIDBKey key;
- idb_cursor->value(scriptValue, key);
- ViewHostMsg_IDBCursorValue::WriteReplyParams(
- reply_msg, SerializedScriptValue(scriptValue), IndexedDBKey(key));
- parent_->Send(reply_msg);
+ WebSerializedScriptValue temp_script_value;
+ WebIDBKey temp_key;
+ idb_cursor->value(temp_script_value, temp_key);
+
+ *script_value = SerializedScriptValue(temp_script_value);
+ *key = IndexedDBKey(temp_key);
}
void IndexedDBDispatcherHost::CursorDispatcherHost::OnUpdate(
int32 cursor_id,
int32 response_id,
const SerializedScriptValue& value,
- IPC::Message* reply_msg) {
+ WebKit::WebExceptionCode* ec) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
- WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(
- &map_, cursor_id, NULL, ViewHostMsg_IDBCursorUpdate::ID);
+ WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(&map_, cursor_id);
if (!idb_cursor)
return;
- WebExceptionCode ec = 0;
+ *ec = 0;
idb_cursor->update(
- value, new IndexedDBCallbacks<void>(parent_, response_id), ec);
- ViewHostMsg_IDBCursorUpdate::WriteReplyParams(reply_msg, ec);
- parent_->Send(reply_msg);
+ value, new IndexedDBCallbacks<void>(parent_, response_id), *ec);
}
void IndexedDBDispatcherHost::CursorDispatcherHost::OnContinue(
int32 cursor_id,
int32 response_id,
const IndexedDBKey& key,
- IPC::Message* reply_msg) {
+ WebKit::WebExceptionCode* ec) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
- WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(
- &map_, cursor_id, NULL, ViewHostMsg_IDBCursorContinue::ID);
+ WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(&map_, cursor_id);
if (!idb_cursor)
return;
- WebExceptionCode ec = 0;
+ *ec = 0;
idb_cursor->continueFunction(
- key, new IndexedDBCallbacks<WebIDBCursor>(parent_, response_id), ec);
- ViewHostMsg_IDBCursorContinue::WriteReplyParams(reply_msg, ec);
- parent_->Send(reply_msg);
+ key, new IndexedDBCallbacks<WebIDBCursor>(parent_, response_id), *ec);
}
-void IndexedDBDispatcherHost::CursorDispatcherHost::OnRemove(
+void IndexedDBDispatcherHost::CursorDispatcherHost::OnDelete(
int32 cursor_id,
int32 response_id,
- IPC::Message* reply_msg) {
+ WebKit::WebExceptionCode* ec) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
- WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(
- &map_, cursor_id, NULL, ViewHostMsg_IDBCursorUpdate::ID);
+ WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(&map_, cursor_id);
if (!idb_cursor)
return;
- WebExceptionCode ec = 0;
- idb_cursor->remove(new IndexedDBCallbacks<void>(parent_, response_id), ec);
- ViewHostMsg_IDBCursorUpdate::WriteReplyParams(reply_msg, ec);
- parent_->Send(reply_msg);
+ *ec = 0;
+ // TODO(jorlow): This should be delete.
+ idb_cursor->remove(new IndexedDBCallbacks<void>(parent_, response_id), *ec);
}
void IndexedDBDispatcherHost::CursorDispatcherHost::OnDestroyed(
int32 object_id) {
- parent_->DestroyObject(
- &map_, object_id, ViewHostMsg_IDBCursorDestroyed::ID);
+ parent_->DestroyObject(&map_, object_id);
}
//////////////////////////////////////////////////////////////////////
@@ -1078,13 +873,12 @@ bool IndexedDBDispatcherHost::TransactionDispatcherHost::OnMessageReceived(
bool handled = true;
IPC_BEGIN_MESSAGE_MAP_EX(IndexedDBDispatcherHost::TransactionDispatcherHost,
message, *msg_is_ok)
- IPC_MESSAGE_HANDLER(ViewHostMsg_IDBTransactionAbort, OnAbort)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBTransactionMode, OnMode)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_IDBTransactionObjectStore,
- OnObjectStore)
- IPC_MESSAGE_HANDLER(ViewHostMsg_IDBTransactionDidCompleteTaskEvents,
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_TransactionAbort, OnAbort)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_TransactionMode, OnMode)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_TransactionObjectStore, OnObjectStore)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_TransactionDidCompleteTaskEvents,
OnDidCompleteTaskEvents)
- IPC_MESSAGE_HANDLER(ViewHostMsg_IDBTransactionDestroyed, OnDestroyed)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_TransactionDestroyed, OnDestroyed)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
@@ -1092,16 +886,13 @@ bool IndexedDBDispatcherHost::TransactionDispatcherHost::OnMessageReceived(
void IndexedDBDispatcherHost::TransactionDispatcherHost::Send(
IPC::Message* message) {
- // The macro magic in OnMessageReceived requires this to link, but it should
- // never actually be called.
- NOTREACHED();
parent_->Send(message);
}
void IndexedDBDispatcherHost::TransactionDispatcherHost::OnAbort(
int32 transaction_id) {
WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
- &map_, transaction_id, 0, ViewHostMsg_IDBTransactionAbort::ID);
+ &map_, transaction_id);
if (!idb_transaction)
return;
@@ -1110,39 +901,33 @@ void IndexedDBDispatcherHost::TransactionDispatcherHost::OnAbort(
void IndexedDBDispatcherHost::TransactionDispatcherHost::OnMode(
int32 transaction_id,
- IPC::Message* reply_msg) {
+ int* mode) {
WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
- &map_, transaction_id, 0, ViewHostMsg_IDBTransactionMode::ID);
+ &map_, transaction_id);
if (!idb_transaction)
return;
- int mode = idb_transaction->mode();
- ViewHostMsg_IDBTransactionMode::WriteReplyParams(reply_msg, mode);
- parent_->Send(reply_msg);
+ *mode = idb_transaction->mode();
}
void IndexedDBDispatcherHost::TransactionDispatcherHost::OnObjectStore(
- int32 transaction_id, const string16& name, IPC::Message* reply_msg) {
+ int32 transaction_id, const string16& name, int32* object_store_id,
+ WebKit::WebExceptionCode* ec) {
WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
- &map_, transaction_id, reply_msg,
- ViewHostMsg_IDBTransactionObjectStore::ID);
+ &map_, transaction_id);
if (!idb_transaction)
return;
- WebExceptionCode ec = 0;
- WebIDBObjectStore* object_store = idb_transaction->objectStore(name, ec);
- int32 object_id = object_store ? parent_->Add(object_store) : 0;
- ViewHostMsg_IDBTransactionObjectStore::WriteReplyParams(
- reply_msg, object_id, ec);
- parent_->Send(reply_msg);
+ *ec = 0;
+ WebIDBObjectStore* object_store = idb_transaction->objectStore(name, *ec);
+ *object_store_id = object_store ? parent_->Add(object_store) : 0;
}
void IndexedDBDispatcherHost::
TransactionDispatcherHost::OnDidCompleteTaskEvents(int transaction_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
- &map_, transaction_id, 0,
- ViewHostMsg_IDBTransactionDidCompleteTaskEvents::ID);
+ &map_, transaction_id);
if (!idb_transaction)
return;
@@ -1151,6 +936,5 @@ void IndexedDBDispatcherHost::
void IndexedDBDispatcherHost::TransactionDispatcherHost::OnDestroyed(
int32 object_id) {
- parent_->DestroyObject(
- &map_, object_id, ViewHostMsg_IDBTransactionDestroyed::ID);
+ parent_->DestroyObject(&map_, object_id);
}
diff --git a/chrome/browser/in_process_webkit/indexed_db_dispatcher_host.h b/chrome/browser/in_process_webkit/indexed_db_dispatcher_host.h
index 9f6fd0a..ff21529 100644
--- a/chrome/browser/in_process_webkit/indexed_db_dispatcher_host.h
+++ b/chrome/browser/in_process_webkit/indexed_db_dispatcher_host.h
@@ -8,21 +8,21 @@
#include "base/basictypes.h"
#include "base/id_map.h"
-#include "base/process.h"
-#include "base/ref_counted.h"
+#include "chrome/browser/browser_message_filter.h"
#include "chrome/browser/in_process_webkit/webkit_context.h"
-#include "ipc/ipc_message.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebExceptionCode.h"
class HostContentSettingsMap;
class IndexedDBKey;
+class NullableString16;
class Profile;
class SerializedScriptValue;
-struct ViewHostMsg_IDBDatabaseCreateObjectStore_Params;
-struct ViewHostMsg_IDBFactoryOpen_Params;
-struct ViewHostMsg_IDBIndexOpenCursor_Params;
-struct ViewHostMsg_IDBObjectStoreCreateIndex_Params;
-struct ViewHostMsg_IDBObjectStoreOpenCursor_Params;
-struct ViewHostMsg_IDBObjectStorePut_Params;
+struct IndexedDBHostMsg_DatabaseCreateObjectStore_Params;
+struct IndexedDBHostMsg_FactoryOpen_Params;
+struct IndexedDBHostMsg_IndexOpenCursor_Params;
+struct IndexedDBHostMsg_ObjectStoreCreateIndex_Params;
+struct IndexedDBHostMsg_ObjectStoreOpenCursor_Params;
+struct IndexedDBHostMsg_ObjectStorePut_Params;
namespace WebKit {
class WebIDBCursor;
@@ -33,25 +33,17 @@ class WebIDBTransaction;
}
// Handles all IndexedDB related messages from a particular renderer process.
-class IndexedDBDispatcherHost
- : public base::RefCountedThreadSafe<IndexedDBDispatcherHost> {
+class IndexedDBDispatcherHost : public BrowserMessageFilter {
public:
// Only call the constructor from the UI thread.
- IndexedDBDispatcherHost(IPC::Message::Sender* sender, Profile* profile);
+ IndexedDBDispatcherHost(int process_id, Profile* profile);
- // Only call from ResourceMessageFilter on the IO thread.
- void Init(int process_id, base::ProcessHandle process_handle);
-
- // Only call from ResourceMessageFilter on the IO thread. Calls self on the
- // WebKit thread in some cases.
- void Shutdown();
-
- // Only call from ResourceMessageFilter on the IO thread.
- bool OnMessageReceived(const IPC::Message& message);
-
- // Send a message to the renderer process associated with our sender_ via the
- // IO thread. May be called from any thread.
- void Send(IPC::Message* message);
+ // BrowserMessageFilter implementation.
+ virtual void OnChannelClosing();
+ virtual void OverrideThreadForMessage(const IPC::Message& message,
+ BrowserThread::ID* thread);
+ virtual bool OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok);
// A shortcut for accessing our context.
IndexedDBContext* Context() {
@@ -67,28 +59,23 @@ class IndexedDBDispatcherHost
int32 Add(WebKit::WebIDBTransaction* idb_transaction);
private:
- friend class base::RefCountedThreadSafe<IndexedDBDispatcherHost>;
~IndexedDBDispatcherHost();
// Message processing. Most of the work is delegated to the dispatcher hosts
// below.
- void OnMessageReceivedWebKit(const IPC::Message& message);
- void OnIDBFactoryOpen(const ViewHostMsg_IDBFactoryOpen_Params& p);
+ void OnIDBFactoryOpen(const IndexedDBHostMsg_FactoryOpen_Params& p);
// Helper templates.
template <class ReturnType>
ReturnType* GetOrTerminateProcess(
- IDMap<ReturnType, IDMapOwnPointer>* map, int32 return_object_id,
- IPC::Message* reply_msg, uint32 message_type);
+ IDMap<ReturnType, IDMapOwnPointer>* map, int32 return_object_id);
- template <typename ReplyType, typename MessageType,
- typename WebObjectType, typename Method>
+ template <typename ReplyType, typename WebObjectType, typename Method>
void SyncGetter(IDMap<WebObjectType, IDMapOwnPointer>* map, int32 object_id,
- IPC::Message* reply_msg, Method method);
+ ReplyType* reply, Method method);
template <typename ObjectType>
- void DestroyObject(IDMap<ObjectType, IDMapOwnPointer>* map, int32 object_id,
- uint32 message_type);
+ void DestroyObject(IDMap<ObjectType, IDMapOwnPointer>* map, int32 object_id);
class DatabaseDispatcherHost {
public:
@@ -98,24 +85,26 @@ class IndexedDBDispatcherHost
bool OnMessageReceived(const IPC::Message& message, bool *msg_is_ok);
void Send(IPC::Message* message);
- void OnName(int32 idb_database_id, IPC::Message* reply_msg);
- void OnVersion(int32 idb_database_id, IPC::Message* reply_msg);
- void OnObjectStoreNames(int32 idb_database_id, IPC::Message* reply_msg);
+ void OnName(int32 idb_database_id, string16* name);
+ void OnVersion(int32 idb_database_id, string16* version);
+ void OnObjectStoreNames(int32 idb_database_id,
+ std::vector<string16>* object_stores);
void OnCreateObjectStore(
- const ViewHostMsg_IDBDatabaseCreateObjectStore_Params& params,
- IPC::Message* reply_msg);
- void OnRemoveObjectStore(int32 idb_database_id,
+ const IndexedDBHostMsg_DatabaseCreateObjectStore_Params& params,
+ int32* object_store_id, WebKit::WebExceptionCode* ec);
+ void OnDeleteObjectStore(int32 idb_database_id,
const string16& name,
int32 transaction_id,
- IPC::Message* reply_msg);
+ WebKit::WebExceptionCode* ec);
void OnSetVersion(int32 idb_database_id,
int32 response_id,
const string16& version,
- IPC::Message* reply_msg);
+ WebKit::WebExceptionCode* ec);
void OnTransaction(int32 idb_database_id,
const std::vector<string16>& names,
int32 mode, int32 timeout,
- IPC::Message* reply_msg);
+ int32* idb_transaction_id,
+ WebKit::WebExceptionCode* ec);
void OnDestroyed(int32 idb_database_id);
IndexedDBDispatcherHost* parent_;
@@ -130,25 +119,25 @@ class IndexedDBDispatcherHost
bool OnMessageReceived(const IPC::Message& message, bool *msg_is_ok);
void Send(IPC::Message* message);
- void OnName(int32 idb_index_id, IPC::Message* reply_msg);
- void OnStoreName(int32 idb_index_id, IPC::Message* reply_msg);
- void OnKeyPath(int32 idb_index_id, IPC::Message* reply_msg);
- void OnUnique(int32 idb_index_id, IPC::Message* reply_msg);
+ void OnName(int32 idb_index_id, string16* name);
+ void OnStoreName(int32 idb_index_id, string16* store_name);
+ void OnKeyPath(int32 idb_index_id, NullableString16* key_path);
+ void OnUnique(int32 idb_index_id, bool* unique);
void OnOpenObjectCursor(
- const ViewHostMsg_IDBIndexOpenCursor_Params& params,
- IPC::Message* reply_msg);
- void OnOpenKeyCursor(const ViewHostMsg_IDBIndexOpenCursor_Params& params,
- IPC::Message* reply_msg);
+ const IndexedDBHostMsg_IndexOpenCursor_Params& params,
+ WebKit::WebExceptionCode* ec);
+ void OnOpenKeyCursor(const IndexedDBHostMsg_IndexOpenCursor_Params& params,
+ WebKit::WebExceptionCode* ec);
void OnGetObject(int idb_index_id,
int32 response_id,
const IndexedDBKey& key,
int32 transaction_id,
- IPC::Message* reply_msg);
+ WebKit::WebExceptionCode* ec);
void OnGetKey(int idb_index_id,
int32 response_id,
const IndexedDBKey& key,
int32 transaction_id,
- IPC::Message* reply_msg);
+ WebKit::WebExceptionCode* ec);
void OnDestroyed(int32 idb_index_id);
IndexedDBDispatcherHost* parent_;
@@ -163,34 +152,37 @@ class IndexedDBDispatcherHost
bool OnMessageReceived(const IPC::Message& message, bool *msg_is_ok);
void Send(IPC::Message* message);
- void OnName(int32 idb_object_store_id, IPC::Message* reply_msg);
- void OnKeyPath(int32 idb_object_store_id, IPC::Message* reply_msg);
- void OnIndexNames(int32 idb_object_store_id, IPC::Message* reply_msg);
+ void OnName(int32 idb_object_store_id, string16* name);
+ void OnKeyPath(int32 idb_object_store_id, NullableString16* keyPath);
+ void OnIndexNames(int32 idb_object_store_id,
+ std::vector<string16>* index_names);
void OnGet(int idb_object_store_id,
int32 response_id,
const IndexedDBKey& key,
int32 transaction_id,
- IPC::Message* reply_msg);
- void OnPut(const ViewHostMsg_IDBObjectStorePut_Params& params,
- IPC::Message* reply_msg);
- void OnRemove(int idb_object_store_id,
+ WebKit::WebExceptionCode* ec);
+ void OnPut(const IndexedDBHostMsg_ObjectStorePut_Params& params,
+ WebKit::WebExceptionCode* ec);
+ void OnDelete(int idb_object_store_id,
int32 response_id,
const IndexedDBKey& key,
int32 transaction_id,
- IPC::Message* reply_msg);
+ WebKit::WebExceptionCode* ec);
void OnCreateIndex(
- const ViewHostMsg_IDBObjectStoreCreateIndex_Params& params,
- IPC::Message* reply_msg);
+ const IndexedDBHostMsg_ObjectStoreCreateIndex_Params& params,
+ int32* index_id,
+ WebKit::WebExceptionCode* ec);
void OnIndex(int32 idb_object_store_id,
const string16& name,
- IPC::Message* reply_msg);
- void OnRemoveIndex(int32 idb_object_store_id,
+ int32* idb_index_id,
+ WebKit::WebExceptionCode* ec);
+ void OnDeleteIndex(int32 idb_object_store_id,
const string16& name,
int32 transaction_id,
- IPC::Message* reply_msg);
+ WebKit::WebExceptionCode* ec);
void OnOpenCursor(
- const ViewHostMsg_IDBObjectStoreOpenCursor_Params& params,
- IPC::Message* reply_msg);
+ const IndexedDBHostMsg_ObjectStoreOpenCursor_Params& params,
+ WebKit::WebExceptionCode* ec);
void OnDestroyed(int32 idb_object_store_id);
IndexedDBDispatcherHost* parent_;
@@ -205,20 +197,22 @@ class IndexedDBDispatcherHost
bool OnMessageReceived(const IPC::Message& message, bool *msg_is_ok);
void Send(IPC::Message* message);
- void OnDirection(int32 idb_object_store_id, IPC::Message* reply_msg);
- void OnKey(int32 idb_object_store_id, IPC::Message* reply_msg);
- void OnValue(int32 idb_object_store_id, IPC::Message* reply_msg);
+ void OnDirection(int32 idb_object_store_id, int32* direction);
+ void OnKey(int32 idb_object_store_id, IndexedDBKey* key);
+ void OnValue(int32 idb_object_store_id,
+ SerializedScriptValue* script_value,
+ IndexedDBKey* key);
void OnUpdate(int32 idb_object_store_id,
int32 response_id,
const SerializedScriptValue& value,
- IPC::Message* reply_msg);
+ WebKit::WebExceptionCode* ec);
void OnContinue(int32 idb_object_store_id,
int32 response_id,
const IndexedDBKey& key,
- IPC::Message* reply_msg);
- void OnRemove(int32 idb_object_store_id,
+ WebKit::WebExceptionCode* ec);
+ void OnDelete(int32 idb_object_store_id,
int32 response_id,
- IPC::Message* reply_msg);
+ WebKit::WebExceptionCode* ec);
void OnDestroyed(int32 idb_cursor_id);
IndexedDBDispatcherHost* parent_;
@@ -235,10 +229,11 @@ class IndexedDBDispatcherHost
// TODO: add the rest of the transaction methods.
void OnAbort(int32 transaction_id);
- void OnMode(int32 transaction_id, IPC::Message* reply_msg);
+ void OnMode(int32 transaction_id, int* mode);
void OnObjectStore(int32 transaction_id,
const string16& name,
- IPC::Message* reply_msg);
+ int32* object_store_id,
+ WebKit::WebExceptionCode* ec);
void OnDidCompleteTaskEvents(int transaction_id);
void OnDestroyed(int32 idb_transaction_id);
@@ -247,9 +242,6 @@ class IndexedDBDispatcherHost
MapType map_;
};
- // Only use on the IO thread.
- IPC::Message::Sender* sender_;
-
// Data shared between renderer processes with the same profile.
scoped_refptr<WebKitContext> webkit_context_;
@@ -263,10 +255,6 @@ class IndexedDBDispatcherHost
scoped_ptr<CursorDispatcherHost> cursor_dispatcher_host_;
scoped_ptr<TransactionDispatcherHost> transaction_dispatcher_host_;
- // If we get a corrupt message from a renderer, we need to kill it using this
- // handle.
- base::ProcessHandle process_handle_;
-
// Used to dispatch messages to the correct view host.
int process_id_;
diff --git a/chrome/browser/in_process_webkit/indexed_db_key_utility_client.cc b/chrome/browser/in_process_webkit/indexed_db_key_utility_client.cc
index 920da34..f708b43 100644
--- a/chrome/browser/in_process_webkit/indexed_db_key_utility_client.cc
+++ b/chrome/browser/in_process_webkit/indexed_db_key_utility_client.cc
@@ -4,9 +4,10 @@
#include "chrome/browser/in_process_webkit/indexed_db_key_utility_client.h"
+#include <vector>
+
#include "chrome/browser/browser_process.h"
#include "chrome/common/indexed_db_key.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/serialized_script_value.h"
IndexedDBKeyUtilityClient::IndexedDBKeyUtilityClient()
@@ -148,7 +149,7 @@ IndexedDBKeyUtilityClient::Client::Client(IndexedDBKeyUtilityClient* parent)
: parent_(parent) {
}
-void IndexedDBKeyUtilityClient::Client::OnProcessCrashed() {
+void IndexedDBKeyUtilityClient::Client::OnProcessCrashed(int exit_code) {
if (parent_->state_ == STATE_CREATING_KEYS)
parent_->FinishCreatingKeys();
}
diff --git a/chrome/browser/in_process_webkit/indexed_db_key_utility_client.h b/chrome/browser/in_process_webkit/indexed_db_key_utility_client.h
index ee03ed9..6b8aec1 100644
--- a/chrome/browser/in_process_webkit/indexed_db_key_utility_client.h
+++ b/chrome/browser/in_process_webkit/indexed_db_key_utility_client.h
@@ -45,7 +45,7 @@ class IndexedDBKeyUtilityClient
explicit Client(IndexedDBKeyUtilityClient* parent);
// UtilityProcessHost::Client
- virtual void OnProcessCrashed();
+ virtual void OnProcessCrashed(int exit_code);
virtual void OnIDBKeysFromValuesAndKeyPathSucceeded(
int id, const std::vector<IndexedDBKey>& keys);
virtual void OnIDBKeysFromValuesAndKeyPathFailed(int id);
diff --git a/chrome/browser/in_process_webkit/session_storage_namespace.cc b/chrome/browser/in_process_webkit/session_storage_namespace.cc
index cfa2a5a..98cc5e9 100644
--- a/chrome/browser/in_process_webkit/session_storage_namespace.cc
+++ b/chrome/browser/in_process_webkit/session_storage_namespace.cc
@@ -6,7 +6,7 @@
#include "chrome/browser/in_process_webkit/dom_storage_context.h"
#include "chrome/browser/in_process_webkit/webkit_context.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
SessionStorageNamespace::SessionStorageNamespace(Profile* profile)
: webkit_context_(profile->GetWebKitContext()),
diff --git a/chrome/browser/in_process_webkit/webkit_context.cc b/chrome/browser/in_process_webkit/webkit_context.cc
index 32fccf7..5022ad5 100644
--- a/chrome/browser/in_process_webkit/webkit_context.cc
+++ b/chrome/browser/in_process_webkit/webkit_context.cc
@@ -6,12 +6,13 @@
#include "base/command_line.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"
-WebKitContext::WebKitContext(Profile* profile)
+WebKitContext::WebKitContext(Profile* profile, bool clear_local_state_on_exit)
: data_path_(profile->IsOffTheRecord() ? FilePath() : profile->GetPath()),
is_incognito_(profile->IsOffTheRecord()),
+ clear_local_state_on_exit_(clear_local_state_on_exit),
ALLOW_THIS_IN_INITIALIZER_LIST(
dom_storage_context_(new DOMStorageContext(this))),
ALLOW_THIS_IN_INITIALIZER_LIST(
@@ -22,6 +23,8 @@ WebKitContext::~WebKitContext() {
// If the WebKit thread was ever spun up, delete the object there. The task
// will just get deleted if the WebKit thread isn't created (which only
// happens during testing).
+ dom_storage_context_->set_clear_local_state_on_exit_(
+ clear_local_state_on_exit_);
DOMStorageContext* dom_storage_context = dom_storage_context_.release();
if (!BrowserThread::DeleteSoon(
BrowserThread::WEBKIT, FROM_HERE, dom_storage_context)) {
@@ -30,6 +33,8 @@ WebKitContext::~WebKitContext() {
delete dom_storage_context;
}
+ indexed_db_context_->set_clear_local_state_on_exit(
+ clear_local_state_on_exit_);
IndexedDBContext* indexed_db_context = indexed_db_context_.release();
if (!BrowserThread::DeleteSoon(
BrowserThread::WEBKIT, FROM_HERE, indexed_db_context)) {
diff --git a/chrome/browser/in_process_webkit/webkit_context.h b/chrome/browser/in_process_webkit/webkit_context.h
index be20825..31a90fe 100644
--- a/chrome/browser/in_process_webkit/webkit_context.h
+++ b/chrome/browser/in_process_webkit/webkit_context.h
@@ -24,9 +24,10 @@ class Profile;
//
// This class is created on the UI thread and accessed on the UI, IO, and WebKit
// threads.
-class WebKitContext : public base::RefCountedThreadSafe<WebKitContext> {
+class WebKitContext
+ : public base::RefCountedThreadSafe<WebKitContext> {
public:
- explicit WebKitContext(Profile* profile);
+ explicit WebKitContext(Profile* profile, bool clear_local_state_on_exit);
const FilePath& data_path() const { return data_path_; }
bool is_incognito() const { return is_incognito_; }
@@ -39,6 +40,10 @@ class WebKitContext : public base::RefCountedThreadSafe<WebKitContext> {
return indexed_db_context_.get();
}
+ void set_clear_local_state_on_exit(bool clear_local_state) {
+ clear_local_state_on_exit_ = clear_local_state;
+ }
+
#ifdef UNIT_TEST
// For unit tests, allow specifying a DOMStorageContext directly so it can be
// mocked.
@@ -62,12 +67,15 @@ class WebKitContext : public base::RefCountedThreadSafe<WebKitContext> {
private:
friend class base::RefCountedThreadSafe<WebKitContext>;
- ~WebKitContext();
+ virtual ~WebKitContext();
// Copies of profile data that can be accessed on any thread.
const FilePath data_path_;
const bool is_incognito_;
+ // True if the destructors of context objects should delete their files.
+ bool clear_local_state_on_exit_;
+
scoped_ptr<DOMStorageContext> dom_storage_context_;
scoped_ptr<IndexedDBContext> indexed_db_context_;
diff --git a/chrome/browser/in_process_webkit/webkit_context_unittest.cc b/chrome/browser/in_process_webkit/webkit_context_unittest.cc
index 92334d6..c8870aa 100644
--- a/chrome/browser/in_process_webkit/webkit_context_unittest.cc
+++ b/chrome/browser/in_process_webkit/webkit_context_unittest.cc
@@ -30,11 +30,11 @@ class MockDOMStorageContext : public DOMStorageContext {
TEST(WebKitContextTest, Basic) {
TestingProfile profile;
- scoped_refptr<WebKitContext> context1(new WebKitContext(&profile));
+ scoped_refptr<WebKitContext> context1(new WebKitContext(&profile, false));
EXPECT_TRUE(profile.GetPath() == context1->data_path());
EXPECT_TRUE(profile.IsOffTheRecord() == context1->is_incognito());
- scoped_refptr<WebKitContext> context2(new WebKitContext(&profile));
+ scoped_refptr<WebKitContext> context2(new WebKitContext(&profile, false));
EXPECT_TRUE(context1->data_path() == context2->data_path());
EXPECT_TRUE(context1->is_incognito() == context2->is_incognito());
}
@@ -47,7 +47,7 @@ TEST(WebKitContextTest, PurgeMemory) {
// Create the contexts.
TestingProfile profile;
- scoped_refptr<WebKitContext> context(new WebKitContext(&profile));
+ scoped_refptr<WebKitContext> context(new WebKitContext(&profile, false));
MockDOMStorageContext* mock_context =
new MockDOMStorageContext(context.get());
context->set_dom_storage_context(mock_context); // Takes ownership.
diff --git a/chrome/browser/input_window_dialog.h b/chrome/browser/input_window_dialog.h
deleted file mode 100644
index bb8d575..0000000
--- a/chrome/browser/input_window_dialog.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_INPUT_WINDOW_DIALOG_H_
-#define CHROME_BROWSER_INPUT_WINDOW_DIALOG_H_
-#pragma once
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "gfx/native_widget_types.h"
-
-// Cross platform access to a modal input window.
-class InputWindowDialog {
- public:
- class Delegate {
- public:
- virtual ~Delegate() {}
-
- // Checks whether |text| is a valid input string.
- virtual bool IsValid(const std::wstring& text) = 0;
-
- // Callback for when the user clicks the OK button.
- virtual void InputAccepted(const std::wstring& text) = 0;
-
- // Callback for when the user clicks the Cancel button.
- virtual void InputCanceled() = 0;
- };
-
- // Creates a new input window dialog parented to |parent|. Ownership of
- // |delegate| is taken by InputWindowDialog or InputWindowDialog's owner.
- static InputWindowDialog* Create(gfx::NativeWindow parent,
- const std::wstring& window_title,
- const std::wstring& label,
- const std::wstring& contents,
- Delegate* delegate);
-
- // Displays the window.
- virtual void Show() = 0;
-
- // Closes the window.
- virtual void Close() = 0;
-
- protected:
- InputWindowDialog() {}
- virtual ~InputWindowDialog() {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(InputWindowDialog);
-};
-
-#endif // CHROME_BROWSER_INPUT_WINDOW_DIALOG_H_
diff --git a/chrome/browser/input_window_dialog_gtk.cc b/chrome/browser/input_window_dialog_gtk.cc
deleted file mode 100644
index 136aed1..0000000
--- a/chrome/browser/input_window_dialog_gtk.cc
+++ /dev/null
@@ -1,146 +0,0 @@
-// 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.
-
-#include "chrome/browser/input_window_dialog.h"
-
-#include <gtk/gtk.h>
-
-#include "app/gtk_signal.h"
-#include "base/message_loop.h"
-#include "base/scoped_ptr.h"
-#include "base/string_piece.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/gtk/gtk_util.h"
-
-class InputWindowDialogGtk : public InputWindowDialog {
- public:
- // Creates a dialog. Takes ownership of |delegate|.
- InputWindowDialogGtk(GtkWindow* parent,
- const std::string& window_title,
- const std::string& label,
- const std::string& contents,
- Delegate* delegate);
- virtual ~InputWindowDialogGtk();
-
- virtual void Show();
- virtual void Close();
-
- private:
- CHROMEG_CALLBACK_0(InputWindowDialogGtk, void, OnEntryChanged, GtkEditable*);
- CHROMEGTK_CALLBACK_1(InputWindowDialogGtk, void, OnResponse, int);
- CHROMEGTK_CALLBACK_1(InputWindowDialogGtk, gboolean,
- OnWindowDeleteEvent, GdkEvent*);
- CHROMEGTK_CALLBACK_0(InputWindowDialogGtk, void, OnWindowDestroy);
-
- // The underlying gtk dialog window.
- GtkWidget* dialog_;
-
- // The GtkEntry in this form.
- GtkWidget* input_;
-
- // Our delegate. Consumes the window's output.
- scoped_ptr<InputWindowDialog::Delegate> delegate_;
-};
-
-
-InputWindowDialogGtk::InputWindowDialogGtk(GtkWindow* parent,
- const std::string& window_title,
- const std::string& label,
- const std::string& contents,
- Delegate* delegate)
- : dialog_(gtk_dialog_new_with_buttons(
- window_title.c_str(),
- parent,
- GTK_DIALOG_MODAL,
- GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
- GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
- NULL)),
- delegate_(delegate) {
- gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_ACCEPT);
- gtk_dialog_set_has_separator(GTK_DIALOG(dialog_), FALSE);
-
- GtkWidget* content_area = GTK_DIALOG(dialog_)->vbox;
- gtk_box_set_spacing(GTK_BOX(content_area), 18);
-
- GtkWidget* hbox = gtk_hbox_new(FALSE, 6);
- GtkWidget* label_widget = gtk_label_new(label.c_str());
- gtk_box_pack_start(GTK_BOX(hbox), label_widget, FALSE, FALSE, 0);
-
- input_ = gtk_entry_new();
- gtk_entry_set_text(GTK_ENTRY(input_), contents.c_str());
- g_signal_connect(input_, "changed",
- G_CALLBACK(OnEntryChangedThunk), this);
- g_object_set(G_OBJECT(input_), "activates-default", TRUE, NULL);
- gtk_box_pack_start(GTK_BOX(hbox), input_, TRUE, TRUE, 0);
-
- gtk_widget_show_all(hbox);
-
- gtk_box_pack_start(GTK_BOX(content_area), hbox, FALSE, FALSE, 0);
-
- g_signal_connect(dialog_, "response",
- G_CALLBACK(OnResponseThunk), this);
- g_signal_connect(dialog_, "delete-event",
- G_CALLBACK(OnWindowDeleteEventThunk), this);
- g_signal_connect(dialog_, "destroy",
- G_CALLBACK(OnWindowDestroyThunk), this);
-}
-
-InputWindowDialogGtk::~InputWindowDialogGtk() {
-}
-
-void InputWindowDialogGtk::Show() {
- gtk_util::ShowDialog(dialog_);
-}
-
-void InputWindowDialogGtk::Close() {
- // Under the model that we've inherited from Windows, dialogs can receive
- // more than one Close() call inside the current message loop event.
- if (dialog_) {
- gtk_widget_destroy(GTK_WIDGET(dialog_));
- dialog_ = NULL;
- }
-}
-
-void InputWindowDialogGtk::OnEntryChanged(GtkEditable* entry) {
- std::wstring value(UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(entry))));
- gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog_),
- GTK_RESPONSE_ACCEPT,
- delegate_->IsValid(value));
-}
-
-void InputWindowDialogGtk::OnResponse(GtkWidget* dialog, int response_id) {
- if (response_id == GTK_RESPONSE_ACCEPT) {
- std::wstring value(UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(input_))));
- delegate_->InputAccepted(value);
- } else {
- delegate_->InputCanceled();
- }
- Close();
-}
-
-gboolean InputWindowDialogGtk::OnWindowDeleteEvent(GtkWidget* widget,
- GdkEvent* event) {
- Close();
-
- // Return true to prevent the gtk dialog from being destroyed. Close will
- // destroy it for us and the default gtk_dialog_delete_event_handler() will
- // force the destruction without us being able to stop it.
- return TRUE;
-}
-
-void InputWindowDialogGtk::OnWindowDestroy(GtkWidget* widget) {
- MessageLoop::current()->DeleteSoon(FROM_HERE, this);
-}
-
-InputWindowDialog* InputWindowDialog::Create(gfx::NativeWindow parent,
- const std::wstring& window_title,
- const std::wstring& label,
- const std::wstring& contents,
- Delegate* delegate) {
- return new InputWindowDialogGtk(parent,
- WideToUTF8(window_title),
- WideToUTF8(label),
- WideToUTF8(contents),
- delegate);
-}
diff --git a/chrome/browser/input_window_dialog_win.cc b/chrome/browser/input_window_dialog_win.cc
deleted file mode 100644
index f8c8d32..0000000
--- a/chrome/browser/input_window_dialog_win.cc
+++ /dev/null
@@ -1,235 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/input_window_dialog.h"
-
-#include "base/compiler_specific.h"
-#include "base/message_loop.h"
-#include "base/task.h"
-#include "views/grid_layout.h"
-#include "views/controls/label.h"
-#include "views/controls/textfield/textfield.h"
-#include "views/standard_layout.h"
-#include "views/window/dialog_delegate.h"
-#include "views/window/window.h"
-#include "grit/generated_resources.h"
-
-// Width to make the text field, in pixels.
-static const int kTextfieldWidth = 200;
-
-class ContentView;
-
-// The Windows implementation of the cross platform input dialog interface.
-class WinInputWindowDialog : public InputWindowDialog {
- public:
- WinInputWindowDialog(HWND parent,
- const std::wstring& window_title,
- const std::wstring& label,
- const std::wstring& contents,
- Delegate* delegate);
- virtual ~WinInputWindowDialog();
-
- virtual void Show();
- virtual void Close();
-
- const std::wstring& window_title() const { return window_title_; }
- const std::wstring& label() const { return label_; }
- const std::wstring& contents() const { return contents_; }
-
- InputWindowDialog::Delegate* delegate() { return delegate_.get(); }
-
- private:
- // Our chrome views window.
- views::Window* window_;
-
- // Strings to feed to the on screen window.
- std::wstring window_title_;
- std::wstring label_;
- std::wstring contents_;
-
- // Our delegate. Consumes the window's output.
- scoped_ptr<InputWindowDialog::Delegate> delegate_;
-};
-
-// ContentView, as the name implies, is the content view for the InputWindow.
-// It registers accelerators that accept/cancel the input.
-class ContentView : public views::View,
- public views::DialogDelegate,
- public views::Textfield::Controller {
- public:
- explicit ContentView(WinInputWindowDialog* delegate)
- : delegate_(delegate),
- ALLOW_THIS_IN_INITIALIZER_LIST(focus_grabber_factory_(this)) {
- DCHECK(delegate_);
- }
-
- // views::DialogDelegate overrides:
- virtual bool IsDialogButtonEnabled(
- MessageBoxFlags::DialogButton button) const;
- virtual bool Accept();
- virtual bool Cancel();
- virtual void DeleteDelegate();
- virtual std::wstring GetWindowTitle() const;
- virtual bool IsModal() const { return true; }
- virtual views::View* GetContentsView();
-
- // views::Textfield::Controller overrides:
- virtual void ContentsChanged(views::Textfield* sender,
- const std::wstring& new_contents);
- virtual bool HandleKeystroke(views::Textfield*,
- const views::Textfield::Keystroke&) {
- return false;
- }
-
- protected:
- // views::View overrides:
- virtual void ViewHierarchyChanged(bool is_add, views::View* parent,
- views::View* child);
-
- private:
- // Set up dialog controls and layout.
- void InitControlLayout();
-
- // Sets focus to the first focusable element within the dialog.
- void FocusFirstFocusableControl();
-
- // The Textfield that the user can type into.
- views::Textfield* text_field_;
-
- // The delegate that the ContentView uses to communicate changes to the
- // caller.
- WinInputWindowDialog* delegate_;
-
- // Helps us set focus to the first Textfield in the window.
- ScopedRunnableMethodFactory<ContentView> focus_grabber_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(ContentView);
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// ContentView, views::DialogDelegate implementation:
-
-bool ContentView::IsDialogButtonEnabled(
- MessageBoxFlags::DialogButton button) const {
- if (button == MessageBoxFlags::DIALOGBUTTON_OK &&
- !delegate_->delegate()->IsValid(text_field_->text())) {
- return false;
- }
- return true;
-}
-
-bool ContentView::Accept() {
- delegate_->delegate()->InputAccepted(text_field_->text());
- return true;
-}
-
-bool ContentView::Cancel() {
- delegate_->delegate()->InputCanceled();
- return true;
-}
-
-void ContentView::DeleteDelegate() {
- delete delegate_;
-}
-
-std::wstring ContentView::GetWindowTitle() const {
- return delegate_->window_title();
-}
-
-views::View* ContentView::GetContentsView() {
- return this;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// ContentView, views::Textfield::Controller implementation:
-
-void ContentView::ContentsChanged(views::Textfield* sender,
- const std::wstring& new_contents) {
- GetDialogClientView()->UpdateDialogButtons();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// ContentView, protected:
-
-void ContentView::ViewHierarchyChanged(bool is_add,
- views::View* parent,
- views::View* child) {
- if (is_add && child == this)
- InitControlLayout();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// ContentView, private:
-
-void ContentView::InitControlLayout() {
- text_field_ = new views::Textfield;
- text_field_->SetText(delegate_->contents());
- text_field_->SetController(this);
-
- using views::ColumnSet;
- using views::GridLayout;
-
- // TODO(sky): Vertical alignment should be baseline.
- GridLayout* layout = CreatePanelGridLayout(this);
- SetLayoutManager(layout);
-
- ColumnSet* c1 = layout->AddColumnSet(0);
- c1->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0,
- GridLayout::USE_PREF, 0, 0);
- c1->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
- c1->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
- GridLayout::USE_PREF, kTextfieldWidth, kTextfieldWidth);
-
- layout->StartRow(0, 0);
- views::Label* label = new views::Label(delegate_->label());
- layout->AddView(label);
- layout->AddView(text_field_);
-
- MessageLoop::current()->PostTask(FROM_HERE,
- focus_grabber_factory_.NewRunnableMethod(
- &ContentView::FocusFirstFocusableControl));
-}
-
-void ContentView::FocusFirstFocusableControl() {
- text_field_->SelectAll();
- text_field_->RequestFocus();
-}
-
-WinInputWindowDialog::WinInputWindowDialog(HWND parent,
- const std::wstring& window_title,
- const std::wstring& label,
- const std::wstring& contents,
- Delegate* delegate)
- : window_title_(window_title),
- label_(label),
- contents_(contents),
- delegate_(delegate) {
- window_ = views::Window::CreateChromeWindow(parent, gfx::Rect(),
- new ContentView(this));
- window_->GetClientView()->AsDialogClientView()->UpdateDialogButtons();
-}
-
-WinInputWindowDialog::~WinInputWindowDialog() {
-}
-
-void WinInputWindowDialog::Show() {
- window_->Show();
-}
-
-void WinInputWindowDialog::Close() {
- window_->Close();
-}
-
-// static
-InputWindowDialog* InputWindowDialog::Create(HWND parent,
- const std::wstring& window_title,
- const std::wstring& label,
- const std::wstring& contents,
- Delegate* delegate) {
- return new WinInputWindowDialog(parent,
- window_title,
- label,
- contents,
- delegate);
-}
diff --git a/chrome/browser/instant/instant_browsertest.cc b/chrome/browser/instant/instant_browsertest.cc
index 29dd768..ef1ac64 100644
--- a/chrome/browser/instant/instant_browsertest.cc
+++ b/chrome/browser/instant/instant_browsertest.cc
@@ -7,18 +7,17 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/autocomplete/autocomplete_edit_view.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/instant/instant_controller.h"
-#include "chrome/browser/location_bar.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/omnibox/location_bar.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
@@ -28,6 +27,7 @@ class InstantTest : public InProcessBrowserTest {
InstantTest()
: location_bar_(NULL),
preview_(NULL) {
+ set_show_window(true);
EnableDOMAutomation();
}
@@ -60,7 +60,7 @@ class InstantTest : public InProcessBrowserTest {
model->SetDefaultSearchProvider(template_url);
}
- virtual void FindLocationBar() {
+ void FindLocationBar() {
if (location_bar_)
return;
location_bar_ = browser()->window()->GetLocationBar();
@@ -94,26 +94,13 @@ class InstantTest : public InProcessBrowserTest {
// Wait for the preview to navigate.
WaitForPreviewToNavigate(true);
- EXPECT_TRUE(browser()->instant()->IsShowingInstant());
- EXPECT_FALSE(browser()->instant()->is_displayable());
- EXPECT_TRUE(browser()->instant()->is_active());
+ ASSERT_TRUE(browser()->instant()->IsShowingInstant());
+ ASSERT_FALSE(browser()->instant()->is_displayable());
+ ASSERT_TRUE(browser()->instant()->is_active());
// When the page loads, the initial searchBox values are set and only a
// resize will have been sent.
- EXPECT_NO_FATAL_FAILURE(CheckBoolValueFromJavascript(
- true, "window.chrome.sv", preview_));
- EXPECT_NO_FATAL_FAILURE(CheckIntValueFromJavascript(
- 0, "window.onsubmitcalls", preview_));
- EXPECT_NO_FATAL_FAILURE(CheckIntValueFromJavascript(
- 0, "window.oncancelcalls", preview_));
- EXPECT_NO_FATAL_FAILURE(CheckIntValueFromJavascript(
- 0, "window.onchangecalls", preview_));
- EXPECT_NO_FATAL_FAILURE(CheckIntValueFromJavascript(
- 1, "window.onresizecalls", preview_));
- EXPECT_NO_FATAL_FAILURE(CheckStringValueFromJavascript(
- "a", "window.chrome.searchBox.value", preview_));
- EXPECT_NO_FATAL_FAILURE(CheckBoolValueFromJavascript(
- false, "window.chrome.searchBox.verbatim", preview_));
+ ASSERT_EQ("true 0 0 0 1 a false", GetSearchStateAsString(preview_));
}
void SetLocationBarText(const std::wstring& text) {
@@ -128,43 +115,99 @@ class InstantTest : public InProcessBrowserTest {
browser(), key, false, false, false, false));
}
+ bool GetStringFromJavascript(TabContents* tab_contents,
+ const std::string& function,
+ std::string* result) {
+ std::string script = StringPrintf(
+ "window.domAutomationController.send(%s)", function.c_str());
+ return ui_test_utils::ExecuteJavaScriptAndExtractString(
+ tab_contents->render_view_host(),
+ std::wstring(), UTF8ToWide(script), result);
+ }
+
+ bool GetIntFromJavascript(TabContents* tab_contents,
+ const std::string& function,
+ int* result) {
+ std::string script = StringPrintf(
+ "window.domAutomationController.send(%s)", function.c_str());
+ return ui_test_utils::ExecuteJavaScriptAndExtractInt(
+ tab_contents->render_view_host(),
+ std::wstring(), UTF8ToWide(script), result);
+ }
+
+ bool GetBoolFromJavascript(TabContents* tab_contents,
+ const std::string& function,
+ bool* result) {
+ std::string script = StringPrintf(
+ "window.domAutomationController.send(%s)", function.c_str());
+ return ui_test_utils::ExecuteJavaScriptAndExtractBool(
+ tab_contents->render_view_host(),
+ std::wstring(), UTF8ToWide(script), result);
+ }
+
+ // Returns the state of the search box as a string. This consists of the
+ // following:
+ // window.chrome.sv window.onsubmitcalls window.oncancelcalls
+ // window.onchangecalls window.onresizecalls
+ // window.chrome.searchBox.value
+ // window.chrome.searchBox.verbatim
+ // If determining any of the values fails, the value is 'fail'.
+ std::string GetSearchStateAsString(TabContents* tab_contents) {
+ bool sv = false;
+ int onsubmitcalls = 0;
+ int oncancelcalls = 0;
+ int onchangecalls = 0;
+ int onresizecalls = 0;
+ std::string value;
+ bool verbatim = false;
+
+ if (!GetBoolFromJavascript(tab_contents, "window.chrome.sv", &sv) ||
+ !GetIntFromJavascript(tab_contents, "window.onsubmitcalls",
+ &onsubmitcalls) ||
+ !GetIntFromJavascript(tab_contents, "window.oncancelcalls",
+ &oncancelcalls) ||
+ !GetIntFromJavascript(tab_contents, "window.onchangecalls",
+ &onchangecalls) ||
+ !GetIntFromJavascript(tab_contents, "window.onresizecalls",
+ &onresizecalls) ||
+ !GetStringFromJavascript(tab_contents, "window.chrome.searchBox.value",
+ &value) ||
+ !GetBoolFromJavascript(tab_contents, "window.chrome.searchBox.verbatim",
+ &verbatim)) {
+ return "fail";
+ }
+
+ return StringPrintf("%s %d %d %d %d %s %s",
+ sv ? "true" : "false", onsubmitcalls, oncancelcalls,
+ onchangecalls, onresizecalls, value.c_str(),
+ verbatim ? "true" : "false");
+ }
+
void CheckStringValueFromJavascript(
const std::string& expected,
const std::string& function,
TabContents* tab_contents) {
- std::string script = StringPrintf(
- "window.domAutomationController.send(%s)", function.c_str());
std::string result;
- ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString(
- tab_contents->render_view_host(),
- std::wstring(), UTF8ToWide(script), &result));
- EXPECT_EQ(expected, result);
+ ASSERT_TRUE(GetStringFromJavascript(tab_contents, function, &result));
+ ASSERT_EQ(expected, result);
}
void CheckBoolValueFromJavascript(
bool expected,
const std::string& function,
TabContents* tab_contents) {
- std::string script = StringPrintf(
- "window.domAutomationController.send(%s)", function.c_str());
bool result;
- ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
- tab_contents->render_view_host(),
- std::wstring(), UTF8ToWide(script), &result));
- EXPECT_EQ(expected, result);
+ ASSERT_TRUE(GetBoolFromJavascript(tab_contents, function, &result));
+ ASSERT_EQ(expected, result);
}
void CheckIntValueFromJavascript(
int expected,
const std::string& function,
TabContents* tab_contents) {
- std::string script = StringPrintf(
- "window.domAutomationController.send(%s)", function.c_str());
int result;
- ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractInt(
- tab_contents->render_view_host(),
- std::wstring(), UTF8ToWide(script), &result));
- EXPECT_EQ(expected, result);
+ ASSERT_TRUE(GetIntFromJavascript(tab_contents, function, &result));
+ ASSERT_EQ(expected, result);
}
// Sends a message to the renderer and waits for the response to come back to
@@ -199,12 +242,7 @@ IN_PROC_BROWSER_TEST_F(InstantTest, OnChangeEvent) {
ASSERT_NO_FATAL_FAILURE(SetLocationBarText(L"abc"));
// Check that the value is reflected and onchange is called.
- EXPECT_NO_FATAL_FAILURE(CheckStringValueFromJavascript(
- "abc", "window.chrome.searchBox.value", preview_));
- EXPECT_NO_FATAL_FAILURE(CheckBoolValueFromJavascript(
- false, "window.chrome.searchBox.verbatim", preview_));
- EXPECT_NO_FATAL_FAILURE(CheckIntValueFromJavascript(
- 1, "window.onchangecalls", preview_));
+ EXPECT_EQ("true 0 0 1 1 abc false", GetSearchStateAsString(preview_));
}
// Verify instant preview is shown correctly for a non-search query.
@@ -411,10 +449,11 @@ IN_PROC_BROWSER_TEST_F(InstantTest, HideOn403) {
}
// Verify that the onsubmit event is dispatched upon pressing enter.
-// TODO(sky): Disabled, http://crbug.com/62940.
-IN_PROC_BROWSER_TEST_F(InstantTest, DISABLED_OnSubmitEvent) {
+IN_PROC_BROWSER_TEST_F(InstantTest, OnSubmitEvent) {
ASSERT_TRUE(test_server()->Start());
ASSERT_NO_FATAL_FAILURE(SetupInstantProvider("search.html"));
+
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
ASSERT_NO_FATAL_FAILURE(SetupLocationBar());
ASSERT_NO_FATAL_FAILURE(SetupPreview());
@@ -423,30 +462,20 @@ IN_PROC_BROWSER_TEST_F(InstantTest, DISABLED_OnSubmitEvent) {
// Check that the preview contents have been committed.
ASSERT_FALSE(browser()->instant()->GetPreviewContents());
+ ASSERT_FALSE(browser()->instant()->is_active());
TabContents* contents = browser()->GetSelectedTabContents();
ASSERT_TRUE(contents);
// Check that the value is reflected and onsubmit is called.
- EXPECT_NO_FATAL_FAILURE(CheckBoolValueFromJavascript(
- true, "window.chrome.sv", contents));
- EXPECT_NO_FATAL_FAILURE(CheckStringValueFromJavascript(
- "abc", "window.chrome.searchBox.value", contents));
- EXPECT_NO_FATAL_FAILURE(CheckBoolValueFromJavascript(
- true, "window.chrome.searchBox.verbatim", contents));
- EXPECT_NO_FATAL_FAILURE(CheckIntValueFromJavascript(
- 1, "window.onsubmitcalls", contents));
+ EXPECT_EQ("true 1 0 1 1 abc true", GetSearchStateAsString(preview_));
}
-#if defined(OS_MACOSX)
-// Does not pass on Mac. http://crbug.com/64696
-#define MAYBE_OnCancelEvent FAILS_OnCancelEvent
-#else
-#define MAYBE_OnCancelEvent OnCancelEvent
-#endif
// Verify that the oncancel event is dispatched upon losing focus.
-IN_PROC_BROWSER_TEST_F(InstantTest, MAYBE_OnCancelEvent) {
+IN_PROC_BROWSER_TEST_F(InstantTest, OnCancelEvent) {
ASSERT_TRUE(test_server()->Start());
ASSERT_NO_FATAL_FAILURE(SetupInstantProvider("search.html"));
+
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
ASSERT_NO_FATAL_FAILURE(SetupLocationBar());
ASSERT_NO_FATAL_FAILURE(SetupPreview());
@@ -456,16 +485,46 @@ IN_PROC_BROWSER_TEST_F(InstantTest, MAYBE_OnCancelEvent) {
// Check that the preview contents have been committed.
ASSERT_FALSE(browser()->instant()->GetPreviewContents());
+ ASSERT_FALSE(browser()->instant()->is_active());
TabContents* contents = browser()->GetSelectedTabContents();
ASSERT_TRUE(contents);
// Check that the value is reflected and oncancel is called.
- EXPECT_NO_FATAL_FAILURE(CheckBoolValueFromJavascript(
- true, "window.chrome.sv", contents));
- EXPECT_NO_FATAL_FAILURE(CheckStringValueFromJavascript(
- "abc", "window.chrome.searchBox.value", contents));
- EXPECT_NO_FATAL_FAILURE(CheckBoolValueFromJavascript(
- false, "window.chrome.searchBox.verbatim", contents));
- EXPECT_NO_FATAL_FAILURE(CheckIntValueFromJavascript(
- 1, "window.oncancelcalls", contents));
+ EXPECT_EQ("true 0 1 1 1 abc false", GetSearchStateAsString(preview_));
+}
+
+#if !defined(OS_MACOSX)
+// Only passes on Mac. http://crbug.com/66850
+#define MAYBE_TabKey FAILS_TabKey
+#else
+#define MAYBE_TabKey TabKey
+#endif
+IN_PROC_BROWSER_TEST_F(InstantTest, MAYBE_TabKey) {
+ ASSERT_TRUE(test_server()->Start());
+ ASSERT_NO_FATAL_FAILURE(SetupInstantProvider("search.html"));
+
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+ ASSERT_NO_FATAL_FAILURE(SetupLocationBar());
+ ASSERT_NO_FATAL_FAILURE(SetupPreview());
+
+ ASSERT_NO_FATAL_FAILURE(SetLocationBarText(L"abc"));
+
+ // Pressing tab to convert instant suggest into inline autocomplete.
+ ASSERT_NO_FATAL_FAILURE(SendKey(app::VKEY_TAB));
+
+ ASSERT_EQ(L"abcdef", location_bar_->location_entry()->GetText());
+
+ EXPECT_EQ("true 0 0 2 2 abcdef false", GetSearchStateAsString(preview_));
+
+ // Pressing tab again to accept the current instant preview.
+ ASSERT_NO_FATAL_FAILURE(SendKey(app::VKEY_TAB));
+
+ // Check that the preview contents have been committed.
+ ASSERT_FALSE(browser()->instant()->GetPreviewContents());
+ ASSERT_FALSE(browser()->instant()->is_active());
+ TabContents* contents = browser()->GetSelectedTabContents();
+ ASSERT_TRUE(contents);
+
+ // Check that the value is reflected and onsubmit is called.
+ EXPECT_EQ("true 1 0 2 2 abcdef true", GetSearchStateAsString(preview_));
}
diff --git a/chrome/browser/instant/instant_confirm_dialog.cc b/chrome/browser/instant/instant_confirm_dialog.cc
index 9999b9c..e56a822 100644
--- a/chrome/browser/instant/instant_confirm_dialog.cc
+++ b/chrome/browser/instant/instant_confirm_dialog.cc
@@ -8,7 +8,7 @@
#include "chrome/browser/instant/instant_controller.h"
#include "chrome/browser/instant/promo_counter.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "googleurl/src/gurl.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/instant/instant_controller.cc b/chrome/browser/instant/instant_controller.cc
index 7517e10..ed01fc5 100644
--- a/chrome/browser/instant/instant_controller.cc
+++ b/chrome/browser/instant/instant_controller.cc
@@ -16,12 +16,12 @@
#include "chrome/browser/instant/promo_counter.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
@@ -141,6 +141,15 @@ void InstantController::Disable(Profile* profile) {
service->SetBoolean(prefs::kInstantEnabled, false);
}
+// static
+bool InstantController::CommitIfCurrent(InstantController* controller) {
+ if (controller && controller->IsCurrent()) {
+ controller->CommitCurrentPreview(INSTANT_COMMIT_PRESSED_ENTER);
+ return true;
+ }
+ return false;
+}
+
void InstantController::Update(TabContentsWrapper* tab_contents,
const AutocompleteMatch& match,
const string16& user_text,
@@ -215,8 +224,7 @@ void InstantController::DestroyPreviewContents() {
}
// ReleasePreviewContents sets is_active_ to false, but we need to set it
- // before notifying the delegate, otherwise if the delegate asks for the state
- // we'll still be active.
+ // beore notifying the delegate so.
is_active_ = false;
delegate_->HideInstant();
delete ReleasePreviewContents(INSTANT_COMMIT_DESTROY);
@@ -610,8 +618,10 @@ bool InstantController::GetType(Profile* profile, Type* type) {
*type = VERBATIM_TYPE;
return true;
}
-
- // There is no switch for PREDICTIVE_NO_AUTO_COMPLETE_TYPE.
+ if (cl->HasSwitch(switches::kEnablePredictiveNoAutoCompleteInstant)) {
+ *type = PREDICTIVE_NO_AUTO_COMPLETE_TYPE;
+ return true;
+ }
// Then prefs.
PrefService* prefs = profile->GetPrefs();
diff --git a/chrome/browser/instant/instant_controller.h b/chrome/browser/instant/instant_controller.h
index 1482481..018101d 100644
--- a/chrome/browser/instant/instant_controller.h
+++ b/chrome/browser/instant/instant_controller.h
@@ -91,6 +91,10 @@ class InstantController : public InstantLoaderDelegate {
// Disables instant.
static void Disable(Profile* profile);
+ // Accepts the currently showing instant preview, if any, and returns true.
+ // Returns false if there is no instant preview showing.
+ static bool CommitIfCurrent(InstantController* controller);
+
// Invoked as the user types in the omnibox with the url to navigate to. If
// the url is empty and there is a preview TabContents it is destroyed. If url
// is non-empty and the preview TabContents has not been created it is
@@ -194,7 +198,6 @@ class InstantController : public InstantLoaderDelegate {
virtual void InstantLoaderDoesntSupportInstant(InstantLoader* loader);
virtual void AddToBlacklist(InstantLoader* loader, const GURL& url);
-
private:
friend class InstantTest;
diff --git a/chrome/browser/instant/instant_loader.cc b/chrome/browser/instant/instant_loader.cc
index 6f9d098..b6b47a6 100644
--- a/chrome/browser/instant/instant_loader.cc
+++ b/chrome/browser/instant/instant_loader.cc
@@ -5,7 +5,9 @@
#include "chrome/browser/instant/instant_loader.h"
#include <algorithm>
+#include <string>
#include <utility>
+#include <vector>
#include "app/l10n_util.h"
#include "base/command_line.h"
@@ -16,7 +18,7 @@
#include "chrome/browser/favicon_service.h"
#include "chrome/browser/history/history_marshaling.h"
#include "chrome/browser/instant/instant_loader_delegate.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
@@ -26,11 +28,12 @@
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
-#include "chrome/browser/tab_contents_wrapper.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/notification_details.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/page_transition_types.h"
#include "chrome/common/render_messages.h"
diff --git a/chrome/browser/instant/instant_loader_manager.cc b/chrome/browser/instant/instant_loader_manager.cc
index 35705bd..88c35f6 100644
--- a/chrome/browser/instant/instant_loader_manager.cc
+++ b/chrome/browser/instant/instant_loader_manager.cc
@@ -8,7 +8,7 @@
#include "chrome/browser/instant/instant_loader.h"
#include "chrome/browser/instant/instant_loader_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
InstantLoaderManager::InstantLoaderManager(
InstantLoaderDelegate* loader_delegate)
diff --git a/chrome/browser/instant/instant_unload_handler.cc b/chrome/browser/instant/instant_unload_handler.cc
index 7a56d35..811bde2 100644
--- a/chrome/browser/instant/instant_unload_handler.cc
+++ b/chrome/browser/instant/instant_unload_handler.cc
@@ -7,9 +7,9 @@
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_navigator.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
// TabContentsDelegate implementation. This owns the TabContents supplied to the
// constructor.
diff --git a/chrome/browser/instant/promo_counter.cc b/chrome/browser/instant/promo_counter.cc
index 34c9b2f..91df78e 100644
--- a/chrome/browser/instant/promo_counter.cc
+++ b/chrome/browser/instant/promo_counter.cc
@@ -7,7 +7,7 @@
#include "base/metrics/histogram.h"
#include "base/values.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
// Pref keys. These are relative to pref_key_.
static const char* kShowKey = ".show";
diff --git a/chrome/browser/intranet_redirect_detector.cc b/chrome/browser/intranet_redirect_detector.cc
index 46fd8be..78c4089 100644
--- a/chrome/browser/intranet_redirect_detector.cc
+++ b/chrome/browser/intranet_redirect_detector.cc
@@ -10,7 +10,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index 1067bf8..f20c8a6 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -15,7 +15,6 @@
#include "base/string_split.h"
#include "base/string_util.h"
#include "base/thread_restrictions.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/gpu_process_host.h"
#include "chrome/browser/net/chrome_net_log.h"
@@ -23,12 +22,13 @@
#include "chrome/browser/net/connect_interceptor.h"
#include "chrome/browser/net/passive_log_collector.h"
#include "chrome/browser/net/predictor_api.h"
-#include "chrome/browser/net/prerender_interceptor.h"
#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/prerender/prerender_interceptor.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/net/raw_host_resolver_proc.h"
#include "chrome/common/net/url_fetcher.h"
#include "chrome/common/pref_names.h"
+#include "net/base/cert_verifier.h"
#include "net/base/dnsrr_resolver.h"
#include "net/base/host_cache.h"
#include "net/base/host_resolver.h"
@@ -37,10 +37,13 @@
#include "net/base/net_util.h"
#include "net/http/http_auth_filter.h"
#include "net/http/http_auth_handler_factory.h"
+#include "net/http/http_network_layer.h"
#if defined(USE_NSS)
#include "net/ocsp/nss_ocsp.h"
#endif // defined(USE_NSS)
#include "net/proxy/proxy_script_fetcher_impl.h"
+#include "net/socket/client_socket_factory.h"
+#include "net/spdy/spdy_session_pool.h"
namespace {
@@ -174,35 +177,25 @@ class LoggingNetworkChangeObserver
DISALLOW_COPY_AND_ASSIGN(LoggingNetworkChangeObserver);
};
-} // namespace
-
-// This is a wrapper class around ProxyScriptFetcherImpl that will
-// keep track of live instances.
-class IOThread::ManagedProxyScriptFetcher
- : public net::ProxyScriptFetcherImpl {
- public:
- ManagedProxyScriptFetcher(URLRequestContext* context,
- IOThread* io_thread)
- : net::ProxyScriptFetcherImpl(context),
- io_thread_(io_thread) {
- DCHECK(!ContainsKey(*fetchers(), this));
- fetchers()->insert(this);
- }
-
- virtual ~ManagedProxyScriptFetcher() {
- DCHECK(ContainsKey(*fetchers(), this));
- fetchers()->erase(this);
- }
-
- private:
- ProxyScriptFetchers* fetchers() {
- return &io_thread_->fetchers_;
- }
-
- IOThread* io_thread_;
+scoped_refptr<URLRequestContext>
+ConstructProxyScriptFetcherContext(IOThread::Globals* globals,
+ net::NetLog* net_log) {
+ scoped_refptr<URLRequestContext> context(new URLRequestContext);
+ context->set_net_log(net_log);
+ context->set_host_resolver(globals->host_resolver.get());
+ context->set_cert_verifier(globals->cert_verifier.get());
+ context->set_dnsrr_resolver(globals->dnsrr_resolver.get());
+ context->set_http_auth_handler_factory(
+ globals->http_auth_handler_factory.get());
+ context->set_proxy_service(globals->proxy_script_fetcher_proxy_service.get());
+ context->set_http_transaction_factory(
+ globals->proxy_script_fetcher_http_transaction_factory.get());
+ // In-memory cookie store.
+ context->set_cookie_store(new net::CookieMonster(NULL, NULL));
+ return context;
+}
- DISALLOW_COPY_AND_ASSIGN(ManagedProxyScriptFetcher);
-};
+} // namespace
// The IOThread object must outlive any tasks posted to the IO thread before the
// Quit task.
@@ -214,8 +207,9 @@ IOThread::Globals::~Globals() {}
// |local_state| is passed in explicitly in order to (1) reduce implicit
// dependencies and (2) make IOThread more flexible for testing.
-IOThread::IOThread(PrefService* local_state)
+IOThread::IOThread(PrefService* local_state, ChromeNetLog* net_log)
: BrowserProcessSubThread(BrowserThread::IO),
+ net_log_(net_log),
globals_(NULL),
speculative_interceptor_(NULL),
predictor_(NULL) {
@@ -245,6 +239,10 @@ IOThread::Globals* IOThread::globals() {
return globals_;
}
+ChromeNetLog* IOThread::net_log() {
+ return net_log_;
+}
+
void IOThread::InitNetworkPredictor(
bool prefetching_enabled,
base::TimeDelta max_dns_queue_delay,
@@ -296,11 +294,6 @@ void IOThread::ChangedToOnTheRecord() {
&IOThread::ChangedToOnTheRecordOnIOThread));
}
-net::ProxyScriptFetcher* IOThread::CreateAndRegisterProxyScriptFetcher(
- URLRequestContext* url_request_context) {
- return new ManagedProxyScriptFetcher(url_request_context, this);
-}
-
void IOThread::Init() {
#if !defined(OS_CHROMEOS)
// TODO(evan): test and enable this on all platforms.
@@ -320,30 +313,54 @@ void IOThread::Init() {
DCHECK(!globals_);
globals_ = new Globals;
- globals_->net_log.reset(new ChromeNetLog());
-
// Add an observer that will emit network change events to the ChromeNetLog.
// Assuming NetworkChangeNotifier dispatches in FIFO order, we should be
// logging the network change before other IO thread consumers respond to it.
network_change_observer_.reset(
- new LoggingNetworkChangeObserver(globals_->net_log.get()));
+ new LoggingNetworkChangeObserver(net_log_));
+ globals_->client_socket_factory =
+ net::ClientSocketFactory::GetDefaultFactory();
globals_->host_resolver.reset(
- CreateGlobalHostResolver(globals_->net_log.get()));
+ CreateGlobalHostResolver(net_log_));
+ globals_->cert_verifier.reset(new net::CertVerifier);
globals_->dnsrr_resolver.reset(new net::DnsRRResolver);
+ // TODO(willchan): Use the real SSLConfigService.
+ globals_->ssl_config_service =
+ net::SSLConfigService::CreateSystemSSLConfigService();
globals_->http_auth_handler_factory.reset(CreateDefaultAuthHandlerFactory(
globals_->host_resolver.get()));
+ // For the ProxyScriptFetcher, we use a direct ProxyService.
+ globals_->proxy_script_fetcher_proxy_service =
+ net::ProxyService::CreateDirectWithNetLog(net_log_);
+ globals_->proxy_script_fetcher_http_transaction_factory.reset(
+ new net::HttpNetworkLayer(
+ globals_->client_socket_factory,
+ globals_->host_resolver.get(),
+ globals_->cert_verifier.get(),
+ globals_->dnsrr_resolver.get(),
+ NULL /* dns_cert_checker */,
+ NULL /* ssl_host_info_factory */,
+ globals_->proxy_script_fetcher_proxy_service.get(),
+ globals_->ssl_config_service.get(),
+ new net::SpdySessionPool(globals_->ssl_config_service.get()),
+ globals_->http_auth_handler_factory.get(),
+ &globals_->network_delegate,
+ net_log_));
+
+ scoped_refptr<URLRequestContext> proxy_script_fetcher_context =
+ ConstructProxyScriptFetcherContext(globals_, net_log_);
+ globals_->proxy_script_fetcher_context = proxy_script_fetcher_context;
if (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnablePagePrerender)) {
- prerender_interceptor_.reset(
- new chrome_browser_net::PrerenderInterceptor());
+ prerender_interceptor_.reset(new PrerenderInterceptor());
}
}
void IOThread::CleanUp() {
// Step 1: Kill all things that might be holding onto
- // URLRequest/URLRequestContexts.
+ // net::URLRequest/URLRequestContexts.
#if defined(USE_NSS)
net::ShutdownOCSP();
@@ -352,23 +369,6 @@ void IOThread::CleanUp() {
// Destroy all URLRequests started by URLFetchers.
URLFetcher::CancelAll();
- // Break any cycles between the ProxyScriptFetcher and URLRequestContext.
- for (ProxyScriptFetchers::const_iterator it = fetchers_.begin();
- it != fetchers_.end();) {
- ManagedProxyScriptFetcher* fetcher = *it;
- {
- // Hang on to the context while cancelling to avoid problems
- // with the cancellation causing the context to be destroyed
- // (see http://crbug.com/63796 ). Ideally, the IOThread would
- // own the URLRequestContexts.
- scoped_refptr<URLRequestContext> context(fetcher->GetRequestContext());
- fetcher->Cancel();
- }
- // Any number of fetchers may have been deleted at this point, so
- // use upper_bound instead of a simple increment.
- it = fetchers_.upper_bound(fetcher);
- }
-
// If any child processes are still running, terminate them and
// and delete the BrowserChildProcessHost instances to release whatever
// IO thread only resources they are referencing.
@@ -416,10 +416,6 @@ void IOThread::CleanUp() {
globals_->host_resolver.get()->GetAsHostResolverImpl()->Shutdown();
}
- // We will delete the NetLog as part of CleanUpAfterMessageLoopDestruction()
- // in case any of the message loop destruction observers try to access it.
- deferred_net_log_to_delete_.reset(globals_->net_log.release());
-
delete globals_;
globals_ = NULL;
@@ -427,22 +423,16 @@ void IOThread::CleanUp() {
}
void IOThread::CleanUpAfterMessageLoopDestruction() {
- // TODO(eroman): get rid of this special case for 39723. If we could instead
- // have a method that runs after the message loop destruction observers have
- // run, but before the message loop itself is destroyed, we could safely
- // combine the two cleanups.
- deferred_net_log_to_delete_.reset();
-
// This will delete the |notification_service_|. Make sure it's done after
// anything else can reference it.
BrowserProcessSubThread::CleanUpAfterMessageLoopDestruction();
- // URLRequest instances must NOT outlive the IO thread.
+ // net::URLRequest instances must NOT outlive the IO thread.
//
// To allow for URLRequests to be deleted from
// MessageLoop::DestructionObserver this check has to happen after CleanUp
// (which runs before DestructionObservers).
- base::debug::LeakTracker<URLRequest>::CheckForLeaks();
+ base::debug::LeakTracker<net::URLRequest>::CheckForLeaks();
}
// static
@@ -529,5 +519,5 @@ void IOThread::ChangedToOnTheRecordOnIOThread() {
// Clear all of the passively logged data.
// TODO(eroman): this is a bit heavy handed, really all we need to do is
// clear the data pertaining to off the record context.
- globals_->net_log->passive_collector()->Clear();
+ net_log_->ClearAllPassivelyCapturedEvents();
}
diff --git a/chrome/browser/io_thread.h b/chrome/browser/io_thread.h
index a2dad58..2f47a42 100644
--- a/chrome/browser/io_thread.h
+++ b/chrome/browser/io_thread.h
@@ -7,7 +7,6 @@
#pragma once
#include <list>
-#include <set>
#include <string>
#include "base/basictypes.h"
#include "base/ref_counted.h"
@@ -21,19 +20,24 @@ class ChromeNetLog;
class ChromeURLRequestContextGetter;
class ListValue;
class PrefService;
+class PrerenderInterceptor;
class URLRequestContext;
namespace chrome_browser_net {
class ConnectInterceptor;
class Predictor;
-class PrerenderInterceptor;
} // namespace chrome_browser_net
namespace net {
+class CertVerifier;
+class ClientSocketFactory;
class DnsRRResolver;
class HostResolver;
class HttpAuthHandlerFactory;
+class HttpTransactionFactory;
class ProxyScriptFetcher;
+class ProxyService;
+class SSLConfigService;
class URLSecurityManager;
} // namespace net
@@ -43,21 +47,30 @@ class IOThread : public BrowserProcessSubThread {
Globals();
~Globals();
- scoped_ptr<ChromeNetLog> net_log;
+ net::ClientSocketFactory* client_socket_factory;
scoped_ptr<net::HostResolver> host_resolver;
+ scoped_ptr<net::CertVerifier> cert_verifier;
scoped_ptr<net::DnsRRResolver> dnsrr_resolver;
+ scoped_refptr<net::SSLConfigService> ssl_config_service;
scoped_ptr<net::HttpAuthHandlerFactory> http_auth_handler_factory;
+ scoped_refptr<net::ProxyService> proxy_script_fetcher_proxy_service;
+ scoped_ptr<net::HttpTransactionFactory>
+ proxy_script_fetcher_http_transaction_factory;
scoped_ptr<net::URLSecurityManager> url_security_manager;
ChromeNetworkDelegate network_delegate;
+ scoped_refptr<URLRequestContext> proxy_script_fetcher_context;
};
- explicit IOThread(PrefService* local_state);
+ // |net_log| must either outlive the IOThread or be NULL.
+ IOThread(PrefService* local_state, ChromeNetLog* net_log);
virtual ~IOThread();
// Can only be called on the IO thread.
Globals* globals();
+ ChromeNetLog* net_log();
+
// Initializes the network predictor, which induces DNS pre-resolution and/or
// TCP/IP preconnections. |prefetching_enabled| indicates whether or not DNS
// prefetching should be enabled, and |preconnect_enabled| controls whether
@@ -89,22 +102,12 @@ class IOThread : public BrowserProcessSubThread {
// IOThread's message loop.
void ChangedToOnTheRecord();
- // Creates a ProxyScriptFetcherImpl which will be automatically aborted
- // during shutdown.
- // This is used to avoid cycles between the ProxyScriptFetcher and the
- // URLRequestContext that owns it (indirectly via the ProxyService).
- net::ProxyScriptFetcher* CreateAndRegisterProxyScriptFetcher(
- URLRequestContext* url_request_context);
-
protected:
virtual void Init();
virtual void CleanUp();
virtual void CleanUpAfterMessageLoopDestruction();
private:
- class ManagedProxyScriptFetcher;
- typedef std::set<ManagedProxyScriptFetcher*> ProxyScriptFetchers;
-
static void RegisterPrefs(PrefService* local_state);
net::HttpAuthHandlerFactory* CreateDefaultAuthHandlerFactory(
@@ -120,22 +123,20 @@ class IOThread : public BrowserProcessSubThread {
void ChangedToOnTheRecordOnIOThread();
+ // The NetLog is owned by the browser process, to allow logging from other
+ // threads during shutdown, but is used most frequently on the IOThread.
+ ChromeNetLog* net_log_;
+
// These member variables are basically global, but their lifetimes are tied
// to the IOThread. IOThread owns them all, despite not using scoped_ptr.
// This is because the destructor of IOThread runs on the wrong thread. All
- // member variables should be deleted in CleanUp(), except ChromeNetLog
- // which is deleted later in CleanUpAfterMessageLoopDestruction().
+ // member variables should be deleted in CleanUp().
// These member variables are initialized in Init() and do not change for the
// lifetime of the IO thread.
Globals* globals_;
- // This variable is only meaningful during shutdown. It is used to defer
- // deletion of the NetLog to CleanUpAfterMessageLoopDestruction() even
- // though |globals_| is reset by CleanUp().
- scoped_ptr<ChromeNetLog> deferred_net_log_to_delete_;
-
// Observer that logs network changes to the ChromeNetLog.
scoped_ptr<net::NetworkChangeNotifier::Observer> network_change_observer_;
@@ -156,11 +157,7 @@ class IOThread : public BrowserProcessSubThread {
// down.
chrome_browser_net::ConnectInterceptor* speculative_interceptor_;
chrome_browser_net::Predictor* predictor_;
- scoped_ptr<chrome_browser_net::PrerenderInterceptor>
- prerender_interceptor_;
-
- // List of live ProxyScriptFetchers.
- ProxyScriptFetchers fetchers_;
+ scoped_ptr<PrerenderInterceptor> prerender_interceptor_;
// Keeps track of all live ChromeURLRequestContextGetters, so the
// ChromeURLRequestContexts can be released during
diff --git a/chrome/browser/js_modal_dialog.cc b/chrome/browser/js_modal_dialog.cc
deleted file mode 100644
index 4cfe4ae..0000000
--- a/chrome/browser/js_modal_dialog.cc
+++ /dev/null
@@ -1,138 +0,0 @@
-// 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.
-
-#include "chrome/browser/js_modal_dialog.h"
-
-#include "base/string_util.h"
-#include "chrome/browser/browser_shutdown.h"
-#include "chrome/browser/extensions/extension_host.h"
-#include "chrome/browser/native_app_modal_dialog.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/notification_type.h"
-#include "ipc/ipc_message.h"
-
-namespace {
-
-// The maximum sizes of various texts passed to us from javascript.
-const int kMessageTextMaxSize = 3000;
-const int kDefaultPromptTextSize = 2000;
-
-} // namespace
-
-JavaScriptAppModalDialog::JavaScriptAppModalDialog(
- JavaScriptAppModalDialogDelegate* delegate,
- const std::wstring& title,
- int dialog_flags,
- const std::wstring& message_text,
- const std::wstring& default_prompt_text,
- bool display_suppress_checkbox,
- bool is_before_unload_dialog,
- IPC::Message* reply_msg)
- : AppModalDialog(delegate->AsTabContents(), title),
- delegate_(delegate),
- extension_host_(delegate->AsExtensionHost()),
- dialog_flags_(dialog_flags),
- display_suppress_checkbox_(display_suppress_checkbox),
- is_before_unload_dialog_(is_before_unload_dialog),
- reply_msg_(reply_msg) {
- // We trim the various parts of the message dialog because otherwise we can
- // overflow the message dialog (and crash/hang the GTK+ version).
- ElideString(message_text, kMessageTextMaxSize, &message_text_);
- ElideString(default_prompt_text, kDefaultPromptTextSize,
- &default_prompt_text_);
-
- DCHECK((tab_contents_ != NULL) != (extension_host_ != NULL));
- InitNotifications();
-}
-
-JavaScriptAppModalDialog::~JavaScriptAppModalDialog() {
-}
-
-NativeAppModalDialog* JavaScriptAppModalDialog::CreateNativeDialog() {
- gfx::NativeWindow parent_window = tab_contents_ ?
- tab_contents_->GetMessageBoxRootWindow() :
- extension_host_->GetMessageBoxRootWindow();
- return NativeAppModalDialog::CreateNativeJavaScriptPrompt(this,
- parent_window);
-}
-
-void JavaScriptAppModalDialog::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- if (skip_this_dialog_)
- return;
-
- if (NotificationType::EXTENSION_HOST_DESTROYED == type &&
- Details<ExtensionHost>(extension_host_) != details)
- return;
-
- // If we reach here, we know the notification is relevant to us, either
- // because we're only observing applicable sources or because we passed the
- // check above. Both of those indicate that we should ignore this dialog.
- // Also clear the delegate, since it's now invalid.
- skip_this_dialog_ = true;
- delegate_ = NULL;
- if (native_dialog_)
- CloseModalDialog();
-}
-
-void JavaScriptAppModalDialog::InitNotifications() {
- // Make sure we get relevant navigation notifications so we know when our
- // parent contents will disappear or navigate to a different page.
- if (tab_contents_) {
- registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
- Source<NavigationController>(&tab_contents_->controller()));
- registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
- Source<TabContents>(tab_contents_));
- } else if (extension_host_) {
- // EXTENSION_HOST_DESTROYED uses the Profile as its source, but we care
- // about the ExtensionHost (which is passed in the details).
- registrar_.Add(this, NotificationType::EXTENSION_HOST_DESTROYED,
- NotificationService::AllSources());
- } else {
- NOTREACHED();
- }
-}
-
-void JavaScriptAppModalDialog::OnCancel(bool suppress_js_messages) {
- // If we are shutting down and this is an onbeforeunload dialog, cancel the
- // shutdown.
- if (is_before_unload_dialog_)
- browser_shutdown::SetTryingToQuit(false);
-
- // We need to do this before WM_DESTROY (WindowClosing()) as any parent frame
- // will receive its activation messages before this dialog receives
- // WM_DESTROY. The parent frame would then try to activate any modal dialogs
- // that were still open in the ModalDialogQueue, which would send activation
- // back to this one. The framework should be improved to handle this, so this
- // is a temporary workaround.
- CompleteDialog();
-
- UpdateDelegate(false, L"", suppress_js_messages);
-}
-
-void JavaScriptAppModalDialog::OnAccept(const std::wstring& prompt_text,
- bool suppress_js_messages) {
- CompleteDialog();
- UpdateDelegate(true, prompt_text, suppress_js_messages);
-}
-
-void JavaScriptAppModalDialog::OnClose() {
- // Should we be handling suppress here too? See crbug.com/65008.
- UpdateDelegate(false, L"", false);
-}
-
-void JavaScriptAppModalDialog::UpdateDelegate(bool success,
- const std::wstring& prompt_text,
- bool suppress_js_messages) {
- if (skip_this_dialog_)
- return;
-
- delegate_->OnMessageBoxClosed(reply_msg_, success, prompt_text);
- if (suppress_js_messages)
- delegate_->SetSuppressMessageBoxes(true);
-
- skip_this_dialog_ = true;
-}
diff --git a/chrome/browser/js_modal_dialog.h b/chrome/browser/js_modal_dialog.h
deleted file mode 100644
index c531352..0000000
--- a/chrome/browser/js_modal_dialog.h
+++ /dev/null
@@ -1,117 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_JS_MODAL_DIALOG_H_
-#define CHROME_BROWSER_JS_MODAL_DIALOG_H_
-#pragma once
-
-#include <string>
-
-#include "build/build_config.h"
-#include "chrome/browser/app_modal_dialog.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
-#include "gfx/native_widget_types.h"
-
-class ExtensionHost;
-class NativeAppModalDialog;
-class TabContents;
-
-namespace IPC {
-class Message;
-}
-
-class JavaScriptAppModalDialogDelegate {
- public:
- // AppModalDialog calls this when the dialog is closed.
- virtual void OnMessageBoxClosed(IPC::Message* reply_msg,
- bool success,
- const std::wstring& prompt) = 0;
-
- // Indicates whether additional message boxes should be suppressed.
- virtual void SetSuppressMessageBoxes(bool suppress_message_boxes) = 0;
-
- // Returns the root native window with which the message box is associated.
- virtual gfx::NativeWindow GetMessageBoxRootWindow() = 0;
-
- // Returns the TabContents or ExtensionHost associated with this message
- // box -- in practice, the object implementing this interface. Exactly one
- // of these must be non-NULL; behavior is undefined (read: it'll probably
- // crash) if that is not the case.
- virtual TabContents* AsTabContents() = 0;
- virtual ExtensionHost* AsExtensionHost() = 0;
-
- protected:
- virtual ~JavaScriptAppModalDialogDelegate() {}
-};
-
-// A controller + model class for JavaScript alert, confirm, prompt, and
-// onbeforeunload dialog boxes.
-class JavaScriptAppModalDialog : public AppModalDialog,
- public NotificationObserver {
- public:
- JavaScriptAppModalDialog(JavaScriptAppModalDialogDelegate* delegate,
- const std::wstring& title,
- int dialog_flags,
- const std::wstring& message_text,
- const std::wstring& default_prompt_text,
- bool display_suppress_checkbox,
- bool is_before_unload_dialog,
- IPC::Message* reply_msg);
- virtual ~JavaScriptAppModalDialog();
-
- // Overridden from AppModalDialog:
- virtual NativeAppModalDialog* CreateNativeDialog();
-
- JavaScriptAppModalDialogDelegate* delegate() const { return delegate_; }
-
- // Callbacks from NativeDialog when the user accepts or cancels the dialog.
- void OnCancel(bool suppress_js_messages);
- void OnAccept(const std::wstring& prompt_text, bool suppress_js_messages);
- void OnClose();
-
- // Accessors
- int dialog_flags() const { return dialog_flags_; }
- std::wstring message_text() const { return message_text_; }
- std::wstring default_prompt_text() const { return default_prompt_text_; }
- bool display_suppress_checkbox() const { return display_suppress_checkbox_; }
- bool is_before_unload_dialog() const { return is_before_unload_dialog_; }
-
- private:
- // Overridden from NotificationObserver:
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- // Initializes for notifications to listen.
- void InitNotifications();
-
- // Updates the delegate with the result of the dialog.
- void UpdateDelegate(bool success, const std::wstring& prompt_text,
- bool suppress_js_messages);
-
- NotificationRegistrar registrar_;
-
- // An implementation of the client interface to provide supporting methods
- // and receive results.
- JavaScriptAppModalDialogDelegate* delegate_;
-
- // The client_ as an ExtensionHost, cached for use during notifications that
- // may arrive after the client has entered its destructor (and is thus
- // treated as a base Delegate). This will be NULL if the |delegate_| is not an
- // ExtensionHost.
- ExtensionHost* extension_host_;
-
- // Information about the message box is held in the following variables.
- int dialog_flags_;
- std::wstring message_text_;
- std::wstring default_prompt_text_;
- bool display_suppress_checkbox_;
- bool is_before_unload_dialog_;
- IPC::Message* reply_msg_;
-
- DISALLOW_COPY_AND_ASSIGN(JavaScriptAppModalDialog);
-};
-
-#endif // CHROME_BROWSER_JS_MODAL_DIALOG_H_
diff --git a/chrome/browser/jumplist_win.cc b/chrome/browser/jumplist_win.cc
index ddea51c..5337df7 100644
--- a/chrome/browser/jumplist_win.cc
+++ b/chrome/browser/jumplist_win.cc
@@ -26,7 +26,7 @@
#include "chrome/browser/favicon_service.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/history/page_usage_data.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_types.h"
#include "chrome/browser/sessions/tab_restore_service.h"
#include "chrome/browser/shell_integration.h"
@@ -416,7 +416,7 @@ bool UpdateJumpList(const wchar_t* app_id,
return false;
// Retrieve the absolute path to "chrome.exe".
- std::wstring chrome_path;
+ FilePath chrome_path;
if (!PathService::Get(base::FILE_EXE, &chrome_path))
return false;
@@ -447,20 +447,21 @@ bool UpdateJumpList(const wchar_t* app_id,
// This update request is applied into the JumpList when we commit this
// transaction.
result = UpdateCategory(destination_list, IDS_NEW_TAB_MOST_VISITED,
- chrome_path, chrome_switches, most_visited_pages,
- most_visited_items);
+ chrome_path.value(), chrome_switches,
+ most_visited_pages, most_visited_items);
if (FAILED(result))
return false;
// Update the "Recently Closed" category of the JumpList.
result = UpdateCategory(destination_list, IDS_NEW_TAB_RECENTLY_CLOSED,
- chrome_path, chrome_switches, recently_closed_pages,
- recently_closed_items);
+ chrome_path.value(), chrome_switches,
+ recently_closed_pages, recently_closed_items);
if (FAILED(result))
return false;
// Update the "Tasks" category of the JumpList.
- result = UpdateTaskCategory(destination_list, chrome_path, chrome_switches);
+ result = UpdateTaskCategory(destination_list, chrome_path.value(),
+ chrome_switches);
if (FAILED(result))
return false;
diff --git a/chrome/browser/language_combobox_model.cc b/chrome/browser/language_combobox_model.cc
index c2787b8..69a3e11 100644
--- a/chrome/browser/language_combobox_model.cc
+++ b/chrome/browser/language_combobox_model.cc
@@ -12,7 +12,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "grit/generated_resources.h"
#include "unicode/uloc.h"
diff --git a/chrome/browser/location_bar.h b/chrome/browser/location_bar.h
deleted file mode 100644
index b6a6d0d..0000000
--- a/chrome/browser/location_bar.h
+++ /dev/null
@@ -1,106 +0,0 @@
-// 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.
-
-// The LocationBar class is a virtual interface, defining access to the
-// window's location bar component. This class exists so that cross-platform
-// components like the browser command system can talk to the platform
-// specific implementations of the location bar control. It also allows the
-// location bar to be mocked for testing.
-
-#ifndef CHROME_BROWSER_LOCATION_BAR_H_
-#define CHROME_BROWSER_LOCATION_BAR_H_
-#pragma once
-
-#include <string>
-
-#include "base/string16.h"
-#include "chrome/browser/first_run/first_run.h"
-#include "chrome/common/page_transition_types.h"
-#include "webkit/glue/window_open_disposition.h"
-
-class AutocompleteEditView;
-class ExtensionAction;
-class LocationBarTesting;
-class TabContents;
-
-class LocationBar {
- public:
- // Shows the first run information bubble anchored to the location bar.
- virtual void ShowFirstRunBubble(FirstRun::BubbleType bubble_type) = 0;
-
- // Sets the suggested text to show in the omnibox. This is shown in addition
- // to the current text of the omnibox.
- virtual void SetSuggestedText(const string16& text) = 0;
-
- // Returns the string of text entered in the location bar.
- virtual std::wstring GetInputString() const = 0;
-
- // Returns the WindowOpenDisposition that should be used to determine where
- // to open a URL entered in the location bar.
- virtual WindowOpenDisposition GetWindowOpenDisposition() const = 0;
-
- // Returns the PageTransition that should be recorded in history when the URL
- // entered in the location bar is loaded.
- virtual PageTransition::Type GetPageTransition() const = 0;
-
- // Accepts the current string of text entered in the location bar.
- virtual void AcceptInput() = 0;
-
- // Focuses the location bar. Optionally also selects its contents.
- virtual void FocusLocation(bool select_all) = 0;
-
- // Clears the location bar, inserts an annoying little "?" turd and sets
- // focus to it.
- virtual void FocusSearch() = 0;
-
- // Updates the state of the images showing the content settings status.
- virtual void UpdateContentSettingsIcons() = 0;
-
- // Updates the state of the page actions.
- virtual void UpdatePageActions() = 0;
-
- // Called when the page-action data needs to be refreshed, e.g. when an
- // extension is unloaded or crashes.
- virtual void InvalidatePageActions() = 0;
-
- // Saves the state of the location bar to the specified TabContents, so that
- // it can be restored later. (Done when switching tabs).
- virtual void SaveStateToContents(TabContents* contents) = 0;
-
- // Reverts the location bar. The bar's permanent text will be shown.
- virtual void Revert() = 0;
-
- // Returns a pointer to the text entry view.
- virtual const AutocompleteEditView* location_entry() const = 0;
- virtual AutocompleteEditView* location_entry() = 0;
-
- // Returns a pointer to the testing interface.
- virtual LocationBarTesting* GetLocationBarForTesting() = 0;
-
- protected:
- virtual ~LocationBar() {}
-};
-
-class LocationBarTesting {
- public:
- // Returns the total number of page actions in the Omnibox.
- virtual int PageActionCount() = 0;
-
- // Returns the number of visible page actions in the Omnibox.
- virtual int PageActionVisibleCount() = 0;
-
- // Returns the ExtensionAction at |index|.
- virtual ExtensionAction* GetPageAction(size_t index) = 0;
-
- // Returns the visible ExtensionAction at |index|.
- virtual ExtensionAction* GetVisiblePageAction(size_t index) = 0;
-
- // Simulates a left mouse pressed on the visible page action at |index|.
- virtual void TestPageActionPressed(size_t index) = 0;
-
- protected:
- virtual ~LocationBarTesting() {}
-};
-
-#endif // CHROME_BROWSER_LOCATION_BAR_H_
diff --git a/chrome/browser/location_bar_util.cc b/chrome/browser/location_bar_util.cc
deleted file mode 100644
index a398ada..0000000
--- a/chrome/browser/location_bar_util.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// 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.
-
-#include "chrome/browser/location_bar_util.h"
-
-#include "app/l10n_util.h"
-#include "base/i18n/rtl.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_model.h"
-
-namespace location_bar_util {
-
-std::wstring GetKeywordName(Profile* profile, const std::wstring& keyword) {
-// Make sure the TemplateURL still exists.
-// TODO(sky): Once LocationBarView adds a listener to the TemplateURLModel
-// to track changes to the model, this should become a DCHECK.
- const TemplateURL* template_url =
- profile->GetTemplateURLModel()->GetTemplateURLForKeyword(keyword);
- if (template_url)
- return template_url->AdjustedShortNameForLocaleDirection();
- return std::wstring();
-}
-
-std::wstring CalculateMinString(const std::wstring& description) {
- // Chop at the first '.' or whitespace.
- const size_t dot_index = description.find(L'.');
- const size_t ws_index = description.find_first_of(kWhitespaceWide);
- size_t chop_index = std::min(dot_index, ws_index);
- std::wstring min_string;
- if (chop_index == std::wstring::npos) {
- // No dot or whitespace, truncate to at most 3 chars.
- min_string = l10n_util::TruncateString(description, 3);
- } else {
- min_string = description.substr(0, chop_index);
- }
- base::i18n::AdjustStringForLocaleDirection(&min_string);
- return min_string;
-}
-
-} // namespace location_bar_util
diff --git a/chrome/browser/location_bar_util.h b/chrome/browser/location_bar_util.h
deleted file mode 100644
index 891c67f..0000000
--- a/chrome/browser/location_bar_util.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_LOCATION_BAR_UTIL_H_
-#define CHROME_BROWSER_LOCATION_BAR_UTIL_H_
-#pragma once
-
-#include <string>
-
-class Profile;
-
-namespace location_bar_util {
-
-// Returns the short name for a keyword.
-std::wstring GetKeywordName(Profile* profile, const std::wstring& keyword);
-
-// Build a short string to use in keyword-search when the field isn't
-// very big.
-std::wstring CalculateMinString(const std::wstring& description);
-
-} // namespace location_bar_util
-
-#endif // CHROME_BROWSER_LOCATION_BAR_UTIL_H_
diff --git a/chrome/browser/login_model.h b/chrome/browser/login_model.h
deleted file mode 100644
index 4e69cad..0000000
--- a/chrome/browser/login_model.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_LOGIN_MODEL_H_
-#define CHROME_BROWSER_LOGIN_MODEL_H_
-#pragma once
-
-#include <string>
-
-// Simple Model & Observer interfaces for a LoginView to facilitate exchanging
-// information.
-class LoginModelObserver {
- public:
- // Called by the model when a username,password pair has been identified
- // as a match for the pending login prompt.
- virtual void OnAutofillDataAvailable(const std::wstring& username,
- const std::wstring& password) = 0;
-
- protected:
- virtual ~LoginModelObserver() {}
-};
-
-class LoginModel {
- public:
- // Set the observer interested in the data from the model.
- // observer can be null, signifying there is no longer any observer
- // interested in the data.
- virtual void SetObserver(LoginModelObserver* observer) = 0;
-
- protected:
- virtual ~LoginModel() {}
-};
-
-#endif // CHROME_BROWSER_LOGIN_MODEL_H_
diff --git a/chrome/browser/login_prompt.cc b/chrome/browser/login_prompt.cc
deleted file mode 100644
index 69e0f20..0000000
--- a/chrome/browser/login_prompt.cc
+++ /dev/null
@@ -1,452 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/login_prompt.h"
-
-#include <vector>
-
-#include "app/l10n_util.h"
-#include "base/command_line.h"
-#include "base/lock.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/password_manager/password_manager.h"
-#include "chrome/browser/renderer_host/render_process_host.h"
-#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
-#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
-#include "chrome/browser/tab_contents/constrained_window.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents/tab_util.h"
-#include "chrome/browser/tab_contents_wrapper.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/notification_service.h"
-#include "grit/generated_resources.h"
-#include "net/base/auth.h"
-#include "net/base/net_util.h"
-#include "net/url_request/url_request.h"
-
-using webkit_glue::PasswordForm;
-
-class LoginHandlerImpl;
-
-// Helper to remove the ref from an URLRequest to the LoginHandler.
-// Should only be called from the IO thread, since it accesses an URLRequest.
-void ResetLoginHandlerForRequest(URLRequest* request) {
- ResourceDispatcherHostRequestInfo* info =
- ResourceDispatcherHost::InfoForRequest(request);
- if (!info)
- return;
-
- info->set_login_handler(NULL);
-}
-
-// Get the signon_realm under which this auth info should be stored.
-//
-// The format of the signon_realm for proxy auth is:
-// proxy-host/auth-realm
-// The format of the signon_realm for server auth is:
-// url-scheme://url-host[:url-port]/auth-realm
-//
-// Be careful when changing this function, since you could make existing
-// saved logins un-retrievable.
-std::string GetSignonRealm(const GURL& url,
- const net::AuthChallengeInfo& auth_info) {
- std::string signon_realm;
- if (auth_info.is_proxy) {
- signon_realm = WideToASCII(auth_info.host_and_port);
- signon_realm.append("/");
- } else {
- // Take scheme, host, and port from the url.
- signon_realm = url.GetOrigin().spec();
- // This ends with a "/".
- }
- signon_realm.append(WideToUTF8(auth_info.realm));
- return signon_realm;
-}
-
-// ----------------------------------------------------------------------------
-// LoginHandler
-
-LoginHandler::LoginHandler(net::AuthChallengeInfo* auth_info,
- URLRequest* request)
- : handled_auth_(false),
- dialog_(NULL),
- auth_info_(auth_info),
- request_(request),
- password_manager_(NULL),
- login_model_(NULL) {
- // This constructor is called on the I/O thread, so we cannot load the nib
- // here. BuildViewForPasswordManager() will be invoked on the UI thread
- // later, so wait with loading the nib until then.
- DCHECK(request_) << "LoginHandler constructed with NULL request";
- DCHECK(auth_info_) << "LoginHandler constructed with NULL auth info";
-
- AddRef(); // matched by LoginHandler::ReleaseSoon().
-
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(this, &LoginHandler::AddObservers));
-
- if (!ResourceDispatcherHost::RenderViewForRequest(
- request_, &render_process_host_id_, &tab_contents_id_)) {
- NOTREACHED();
- }
-}
-
-LoginHandler::~LoginHandler() {
- SetModel(NULL);
-}
-
-void LoginHandler::SetPasswordForm(const webkit_glue::PasswordForm& form) {
- password_form_ = form;
-}
-
-void LoginHandler::SetPasswordManager(PasswordManager* password_manager) {
- password_manager_ = password_manager;
-}
-
-TabContents* LoginHandler::GetTabContentsForLogin() const {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- return tab_util::GetTabContentsByID(render_process_host_id_,
- tab_contents_id_);
-}
-
-void LoginHandler::SetAuth(const std::wstring& username,
- const std::wstring& password) {
- if (WasAuthHandled(true))
- return;
-
- // Tell the password manager the credentials were submitted / accepted.
- if (password_manager_) {
- password_form_.username_value = WideToUTF16Hack(username);
- password_form_.password_value = WideToUTF16Hack(password);
- password_manager_->ProvisionallySavePassword(password_form_);
- }
-
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(this, &LoginHandler::CloseContentsDeferred));
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(
- this, &LoginHandler::NotifyAuthSupplied, username, password));
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(
- this, &LoginHandler::SetAuthDeferred, username, password));
-}
-
-void LoginHandler::CancelAuth() {
- if (WasAuthHandled(true))
- return;
-
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(this, &LoginHandler::CloseContentsDeferred));
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(this, &LoginHandler::NotifyAuthCancelled));
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(this, &LoginHandler::CancelAuthDeferred));
-}
-
-void LoginHandler::OnRequestCancelled() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)) <<
- "Why is OnRequestCancelled called from the UI thread?";
-
- // Reference is no longer valid.
- request_ = NULL;
-
- // Give up on auth if the request was cancelled.
- CancelAuth();
-}
-
-void LoginHandler::AddObservers() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- registrar_.Add(this, NotificationType::AUTH_SUPPLIED,
- NotificationService::AllSources());
- registrar_.Add(this, NotificationType::AUTH_CANCELLED,
- NotificationService::AllSources());
-}
-
-void LoginHandler::RemoveObservers() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- registrar_.Remove(this, NotificationType::AUTH_SUPPLIED,
- NotificationService::AllSources());
- registrar_.Remove(this, NotificationType::AUTH_CANCELLED,
- NotificationService::AllSources());
-
- DCHECK(registrar_.IsEmpty());
-}
-
-void LoginHandler::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(type == NotificationType::AUTH_SUPPLIED ||
- type == NotificationType::AUTH_CANCELLED);
-
- TabContents* requesting_contents = GetTabContentsForLogin();
- if (!requesting_contents)
- return;
-
- NavigationController* this_controller = &requesting_contents->controller();
- NavigationController* that_controller =
- Source<NavigationController>(source).ptr();
-
- // Only handle notifications from other handlers.
- if (this_controller == that_controller)
- return;
-
- LoginNotificationDetails* login_details =
- Details<LoginNotificationDetails>(details).ptr();
-
- // Only handle notification for the identical auth info.
- if (*login_details->handler()->auth_info() != *auth_info())
- return;
-
- // Set or cancel the auth in this handler.
- if (type == NotificationType::AUTH_SUPPLIED) {
- AuthSuppliedLoginNotificationDetails* supplied_details =
- Details<AuthSuppliedLoginNotificationDetails>(details).ptr();
- SetAuth(supplied_details->username(), supplied_details->password());
- } else {
- DCHECK(type == NotificationType::AUTH_CANCELLED);
- CancelAuth();
- }
-}
-
-void LoginHandler::SetModel(LoginModel* model) {
- if (login_model_)
- login_model_->SetObserver(NULL);
- login_model_ = model;
- if (login_model_)
- login_model_->SetObserver(this);
-}
-
-void LoginHandler::SetDialog(ConstrainedWindow* dialog) {
- dialog_ = dialog;
-}
-
-void LoginHandler::NotifyAuthNeeded() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (WasAuthHandled(false))
- return;
-
- TabContents* requesting_contents = GetTabContentsForLogin();
- if (!requesting_contents)
- return;
-
- NotificationService* service = NotificationService::current();
- NavigationController* controller = &requesting_contents->controller();
- LoginNotificationDetails details(this);
-
- service->Notify(NotificationType::AUTH_NEEDED,
- Source<NavigationController>(controller),
- Details<LoginNotificationDetails>(&details));
-}
-
-void LoginHandler::NotifyAuthCancelled() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(WasAuthHandled(false));
-
- TabContents* requesting_contents = GetTabContentsForLogin();
- if (!requesting_contents)
- return;
-
- NotificationService* service = NotificationService::current();
- NavigationController* controller = &requesting_contents->controller();
- LoginNotificationDetails details(this);
-
- service->Notify(NotificationType::AUTH_CANCELLED,
- Source<NavigationController>(controller),
- Details<LoginNotificationDetails>(&details));
-}
-
-void LoginHandler::NotifyAuthSupplied(const std::wstring& username,
- const std::wstring& password) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(WasAuthHandled(false));
-
- TabContents* requesting_contents = GetTabContentsForLogin();
- if (!requesting_contents)
- return;
-
- NotificationService* service = NotificationService::current();
- NavigationController* controller = &requesting_contents->controller();
- AuthSuppliedLoginNotificationDetails details(this, username, password);
-
- service->Notify(NotificationType::AUTH_SUPPLIED,
- Source<NavigationController>(controller),
- Details<AuthSuppliedLoginNotificationDetails>(&details));
-}
-
-void LoginHandler::ReleaseSoon() {
- if (!WasAuthHandled(true)) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(this, &LoginHandler::CancelAuthDeferred));
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(this, &LoginHandler::NotifyAuthCancelled));
- }
-
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(this, &LoginHandler::RemoveObservers));
-
- // Delete this object once all InvokeLaters have been called.
- BrowserThread::ReleaseSoon(BrowserThread::IO, FROM_HERE, this);
-}
-
-// Returns whether authentication had been handled (SetAuth or CancelAuth).
-// If |set_handled| is true, it will mark authentication as handled.
-bool LoginHandler::WasAuthHandled(bool set_handled) {
- AutoLock lock(handled_auth_lock_);
- bool was_handled = handled_auth_;
- if (set_handled)
- handled_auth_ = true;
- return was_handled;
-}
-
-// Calls SetAuth from the IO loop.
-void LoginHandler::SetAuthDeferred(const std::wstring& username,
- const std::wstring& password) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- if (request_) {
- request_->SetAuth(WideToUTF16Hack(username), WideToUTF16Hack(password));
- ResetLoginHandlerForRequest(request_);
- }
-}
-
-// Calls CancelAuth from the IO loop.
-void LoginHandler::CancelAuthDeferred() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- if (request_) {
- request_->CancelAuth();
- // Verify that CancelAuth doesn't destroy the request via our delegate.
- DCHECK(request_ != NULL);
- ResetLoginHandlerForRequest(request_);
- }
-}
-
-// Closes the view_contents from the UI loop.
-void LoginHandler::CloseContentsDeferred() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // The hosting ConstrainedWindow may have been freed.
- if (dialog_)
- dialog_->CloseConstrainedWindow();
-}
-
-// ----------------------------------------------------------------------------
-// LoginDialogTask
-
-// This task is run on the UI thread and creates a constrained window with
-// a LoginView to prompt the user. The response will be sent to LoginHandler,
-// which then routes it to the URLRequest on the I/O thread.
-class LoginDialogTask : public Task {
- public:
- LoginDialogTask(const GURL& request_url,
- net::AuthChallengeInfo* auth_info,
- LoginHandler* handler)
- : request_url_(request_url), auth_info_(auth_info), handler_(handler) {
- }
- virtual ~LoginDialogTask() {
- }
-
- void Run() {
- TabContents* parent_contents = handler_->GetTabContentsForLogin();
- if (!parent_contents) {
- // The request may have been cancelled, or it may be for a renderer
- // not hosted by a tab (e.g. an extension). Cancel just in case
- // (cancelling twice is a no-op).
- handler_->CancelAuth();
- return;
- }
-
- // Tell the password manager to look for saved passwords.
- TabContentsWrapper** wrapper =
- TabContentsWrapper::property_accessor()->GetProperty(
- parent_contents->property_bag());
- if (!wrapper)
- return;
- PasswordManager* password_manager = (*wrapper)->GetPasswordManager();
- std::vector<PasswordForm> v;
- MakeInputForPasswordManager(&v);
- password_manager->PasswordFormsFound(v);
- handler_->SetPasswordManager(password_manager);
-
- std::wstring explanation = auth_info_->realm.empty() ?
- l10n_util::GetStringF(IDS_LOGIN_DIALOG_DESCRIPTION_NO_REALM,
- auth_info_->host_and_port) :
- l10n_util::GetStringF(IDS_LOGIN_DIALOG_DESCRIPTION,
- auth_info_->host_and_port,
- auth_info_->realm);
- handler_->BuildViewForPasswordManager(password_manager,
- explanation);
- }
-
- private:
- // Helper to create a PasswordForm and stuff it into a vector as input
- // for PasswordManager::PasswordFormsFound, the hook into PasswordManager.
- void MakeInputForPasswordManager(
- std::vector<PasswordForm>* password_manager_input) {
- PasswordForm dialog_form;
- if (LowerCaseEqualsASCII(auth_info_->scheme, "basic")) {
- dialog_form.scheme = PasswordForm::SCHEME_BASIC;
- } else if (LowerCaseEqualsASCII(auth_info_->scheme, "digest")) {
- dialog_form.scheme = PasswordForm::SCHEME_DIGEST;
- } else {
- dialog_form.scheme = PasswordForm::SCHEME_OTHER;
- }
- std::string host_and_port(WideToASCII(auth_info_->host_and_port));
- if (auth_info_->is_proxy) {
- std::string origin = host_and_port;
- // We don't expect this to already start with http:// or https://.
- DCHECK(origin.find("http://") != 0 && origin.find("https://") != 0);
- origin = std::string("http://") + origin;
- dialog_form.origin = GURL(origin);
- } else if (net::GetHostAndPort(request_url_) != host_and_port) {
- dialog_form.origin = GURL();
- NOTREACHED(); // crbug.com/32718
- } else {
- dialog_form.origin = GURL(request_url_.scheme() + "://" + host_and_port);
- }
- dialog_form.signon_realm = GetSignonRealm(dialog_form.origin, *auth_info_);
- password_manager_input->push_back(dialog_form);
- // Set the password form for the handler (by copy).
- handler_->SetPasswordForm(dialog_form);
- }
-
- // The url from the URLRequest initiating the auth challenge.
- GURL request_url_;
-
- // Info about who/where/what is asking for authentication.
- scoped_refptr<net::AuthChallengeInfo> auth_info_;
-
- // Where to send the authentication when obtained.
- // This is owned by the ResourceDispatcherHost that invoked us.
- LoginHandler* handler_;
-
- DISALLOW_COPY_AND_ASSIGN(LoginDialogTask);
-};
-
-// ----------------------------------------------------------------------------
-// Public API
-
-LoginHandler* CreateLoginPrompt(net::AuthChallengeInfo* auth_info,
- URLRequest* request) {
- LoginHandler* handler = LoginHandler::Create(auth_info, request);
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE, new LoginDialogTask(
- request->url(), auth_info, handler));
- return handler;
-}
diff --git a/chrome/browser/login_prompt.h b/chrome/browser/login_prompt.h
deleted file mode 100644
index db7b081..0000000
--- a/chrome/browser/login_prompt.h
+++ /dev/null
@@ -1,213 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_LOGIN_PROMPT_H_
-#define CHROME_BROWSER_LOGIN_PROMPT_H_
-#pragma once
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/lock.h"
-#include "base/ref_counted.h"
-#include "chrome/browser/password_manager/password_manager.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
-
-namespace net {
-class AuthChallengeInfo;
-class URLRequest;
-} // namespace net
-
-class ConstrainedWindow;
-class GURL;
-
-// This is the base implementation for the OS-specific classes that route
-// authentication info to the URLRequest that needs it. These functions must
-// be implemented in a thread safe manner.
-class LoginHandler : public base::RefCountedThreadSafe<LoginHandler>,
- public LoginModelObserver,
- public NotificationObserver {
- public:
- LoginHandler(net::AuthChallengeInfo* auth_info, net::URLRequest* request);
- virtual ~LoginHandler();
-
- // Builds the platform specific LoginHandler. Used from within
- // CreateLoginPrompt() which creates tasks.
- static LoginHandler* Create(net::AuthChallengeInfo* auth_info,
- net::URLRequest* request);
-
- // Initializes the underlying platform specific view.
- virtual void BuildViewForPasswordManager(PasswordManager* manager,
- std::wstring explanation) = 0;
-
- // Sets information about the authentication type (|form|) and the
- // |password_manager| for this profile.
- void SetPasswordForm(const webkit_glue::PasswordForm& form);
- void SetPasswordManager(PasswordManager* password_manager);
-
- // Returns the TabContents that needs authentication.
- TabContents* GetTabContentsForLogin() const;
-
- // Resend the request with authentication credentials.
- // This function can be called from either thread.
- void SetAuth(const std::wstring& username, const std::wstring& password);
-
- // Display the error page without asking for credentials again.
- // This function can be called from either thread.
- void CancelAuth();
-
- // Notify the handler that the request was cancelled.
- // This function can only be called from the IO thread.
- void OnRequestCancelled();
-
- // Implements the NotificationObserver interface.
- // Listens for AUTH_SUPPLIED and AUTH_CANCELLED notifications from other
- // LoginHandlers so that this LoginHandler has the chance to dismiss itself
- // if it was waiting for the same authentication.
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- protected:
- void SetModel(LoginModel* model);
-
- void SetDialog(ConstrainedWindow* dialog);
-
- // Notify observers that authentication is needed.
- void NotifyAuthNeeded();
-
- // Performs necessary cleanup before deletion.
- void ReleaseSoon();
-
- // Who/where/what asked for the authentication.
- net::AuthChallengeInfo* auth_info() const { return auth_info_.get(); }
-
- private:
- // Starts observing notifications from other LoginHandlers.
- void AddObservers();
-
- // Stops observing notifications from other LoginHandlers.
- void RemoveObservers();
-
- // Notify observers that authentication is supplied.
- void NotifyAuthSupplied(const std::wstring& username,
- const std::wstring& password);
-
- // Notify observers that authentication is cancelled.
- void NotifyAuthCancelled();
-
- // Returns whether authentication had been handled (SetAuth or CancelAuth).
- // If |set_handled| is true, it will mark authentication as handled.
- bool WasAuthHandled(bool set_handled);
-
- // Calls SetAuth from the IO loop.
- void SetAuthDeferred(const std::wstring& username,
- const std::wstring& password);
-
- // Calls CancelAuth from the IO loop.
- void CancelAuthDeferred();
-
- // Closes the view_contents from the UI loop.
- void CloseContentsDeferred();
-
- // True if we've handled auth (SetAuth or CancelAuth has been called).
- bool handled_auth_;
- Lock handled_auth_lock_;
-
- // The ConstrainedWindow that is hosting our LoginView.
- // This should only be accessed on the UI loop.
- ConstrainedWindow* dialog_;
-
- // Who/where/what asked for the authentication.
- scoped_refptr<net::AuthChallengeInfo> auth_info_;
-
- // The request that wants login data.
- // This should only be accessed on the IO loop.
- net::URLRequest* request_;
-
- // The PasswordForm sent to the PasswordManager. This is so we can refer to it
- // when later notifying the password manager if the credentials were accepted
- // or rejected.
- // This should only be accessed on the UI loop.
- webkit_glue::PasswordForm password_form_;
-
- // Points to the password manager owned by the TabContents requesting auth.
- // Can be null if the TabContents is not a TabContents.
- // This should only be accessed on the UI loop.
- PasswordManager* password_manager_;
-
- // Cached from the URLRequest, in case it goes NULL on us.
- int render_process_host_id_;
- int tab_contents_id_;
-
- // If not null, points to a model we need to notify of our own destruction
- // so it doesn't try and access this when its too late.
- LoginModel* login_model_;
-
- // Observes other login handlers so this login handler can respond.
- NotificationRegistrar registrar_;
-};
-
-// Details to provide the NotificationObserver. Used by the automation proxy
-// for testing.
-class LoginNotificationDetails {
- public:
- explicit LoginNotificationDetails(LoginHandler* handler)
- : handler_(handler) {}
- LoginHandler* handler() const { return handler_; }
-
- private:
- LoginNotificationDetails() {}
-
- LoginHandler* handler_; // Where to send the response.
-
- DISALLOW_COPY_AND_ASSIGN(LoginNotificationDetails);
-};
-
-// Details to provide the NotificationObserver. Used by the automation proxy
-// for testing and by other LoginHandlers to dismiss themselves when an
-// identical auth is supplied.
-class AuthSuppliedLoginNotificationDetails : public LoginNotificationDetails {
- public:
- AuthSuppliedLoginNotificationDetails(LoginHandler* handler,
- const std::wstring& username,
- const std::wstring& password)
- : LoginNotificationDetails(handler),
- username_(username),
- password_(password) {}
- const std::wstring& username() const { return username_; }
- const std::wstring& password() const { return password_; }
-
- private:
- // The username that was used for the authentication.
- const std::wstring username_;
-
- // The password that was used for the authentication.
- const std::wstring password_;
-
- DISALLOW_COPY_AND_ASSIGN(AuthSuppliedLoginNotificationDetails);
-};
-
-// Prompts the user for their username and password. This is designed to
-// be called on the background (I/O) thread, in response to
-// URLRequest::Delegate::OnAuthRequired. The prompt will be created
-// on the main UI thread via a call to UI loop's InvokeLater, and will send the
-// credentials back to the URLRequest on the calling thread.
-// A LoginHandler object (which lives on the calling thread) is returned,
-// which can be used to set or cancel authentication programmatically. The
-// caller must invoke OnRequestCancelled() on this LoginHandler before
-// destroying the URLRequest.
-LoginHandler* CreateLoginPrompt(net::AuthChallengeInfo* auth_info,
- net::URLRequest* request);
-
-// Helper to remove the ref from an URLRequest to the LoginHandler.
-// Should only be called from the IO thread, since it accesses an URLRequest.
-void ResetLoginHandlerForRequest(net::URLRequest* request);
-
-// Get the signon_realm under which the identity should be saved.
-std::string GetSignonRealm(const GURL& url,
- const net::AuthChallengeInfo& auth_info);
-
-#endif // CHROME_BROWSER_LOGIN_PROMPT_H_
diff --git a/chrome/browser/login_prompt_gtk.cc b/chrome/browser/login_prompt_gtk.cc
deleted file mode 100644
index 6752925..0000000
--- a/chrome/browser/login_prompt_gtk.cc
+++ /dev/null
@@ -1,199 +0,0 @@
-// 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.
-
-#include "chrome/browser/login_prompt.h"
-
-#include <gtk/gtk.h>
-
-#include "app/l10n_util.h"
-#include "app/gtk_signal.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/gtk/constrained_window_gtk.h"
-#include "chrome/browser/gtk/gtk_util.h"
-#include "chrome/browser/login_model.h"
-#include "chrome/browser/password_manager/password_manager.h"
-#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
-#include "chrome/browser/tab_contents/navigation_controller.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents/tab_contents_delegate.h"
-#include "chrome/browser/tab_contents/tab_contents_view_gtk.h"
-#include "chrome/browser/tab_contents/tab_util.h"
-#include "chrome/common/notification_service.h"
-#include "grit/generated_resources.h"
-#include "net/url_request/url_request.h"
-
-using webkit_glue::PasswordForm;
-
-// ----------------------------------------------------------------------------
-// LoginHandlerGtk
-
-// This class simply forwards the authentication from the LoginView (on
-// the UI thread) to the URLRequest (on the I/O thread).
-// This class uses ref counting to ensure that it lives until all InvokeLaters
-// have been called.
-class LoginHandlerGtk : public LoginHandler,
- public ConstrainedWindowGtkDelegate {
- public:
- LoginHandlerGtk(net::AuthChallengeInfo* auth_info, URLRequest* request)
- : LoginHandler(auth_info, request),
- username_entry_(NULL),
- password_entry_(NULL),
- ok_(NULL) {
- }
-
- virtual ~LoginHandlerGtk() {
- root_.Destroy();
- }
-
- // LoginModelObserver implementation.
- virtual void OnAutofillDataAvailable(const std::wstring& username,
- const std::wstring& password) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // NOTE: Would be nice to use gtk_entry_get_text_length, but it is fairly
- // new and not always in our GTK version.
- if (strlen(gtk_entry_get_text(GTK_ENTRY(username_entry_))) == 0) {
- gtk_entry_set_text(GTK_ENTRY(username_entry_),
- WideToUTF8(username).c_str());
- gtk_entry_set_text(GTK_ENTRY(password_entry_),
- WideToUTF8(password).c_str());
- gtk_editable_select_region(GTK_EDITABLE(username_entry_), 0, -1);
- }
- }
-
- // LoginHandler:
- virtual void BuildViewForPasswordManager(PasswordManager* manager,
- std::wstring explanation) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- root_.Own(gtk_vbox_new(FALSE, gtk_util::kContentAreaBorder));
- GtkWidget* label = gtk_label_new(WideToUTF8(explanation).c_str());
- gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
- gtk_box_pack_start(GTK_BOX(root_.get()), label, FALSE, FALSE, 0);
-
- username_entry_ = gtk_entry_new();
- gtk_entry_set_activates_default(GTK_ENTRY(username_entry_), TRUE);
-
- password_entry_ = gtk_entry_new();
- gtk_entry_set_activates_default(GTK_ENTRY(password_entry_), TRUE);
- gtk_entry_set_visibility(GTK_ENTRY(password_entry_), FALSE);
-
- GtkWidget* table = gtk_util::CreateLabeledControlsGroup(NULL,
- l10n_util::GetStringUTF8(IDS_LOGIN_DIALOG_USERNAME_FIELD).c_str(),
- username_entry_,
- l10n_util::GetStringUTF8(IDS_LOGIN_DIALOG_PASSWORD_FIELD).c_str(),
- password_entry_,
- NULL);
- gtk_box_pack_start(GTK_BOX(root_.get()), table, FALSE, FALSE, 0);
-
- GtkWidget* hbox = gtk_hbox_new(FALSE, 12);
- gtk_box_pack_start(GTK_BOX(root_.get()), hbox, FALSE, FALSE, 0);
-
- ok_ = gtk_button_new_from_stock(GTK_STOCK_OK);
- gtk_button_set_label(
- GTK_BUTTON(ok_),
- l10n_util::GetStringUTF8(IDS_LOGIN_DIALOG_OK_BUTTON_LABEL).c_str());
- g_signal_connect(ok_, "clicked", G_CALLBACK(OnOKClickedThunk), this);
- gtk_box_pack_end(GTK_BOX(hbox), ok_, FALSE, FALSE, 0);
-
- GtkWidget* cancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
- g_signal_connect(cancel, "clicked", G_CALLBACK(OnCancelClickedThunk), this);
- gtk_box_pack_end(GTK_BOX(hbox), cancel, FALSE, FALSE, 0);
-
- g_signal_connect(root_.get(), "hierarchy-changed",
- G_CALLBACK(OnPromptHierarchyChangedThunk), this);
-
- SetModel(manager);
-
- // Scary thread safety note: This can potentially be called *after* SetAuth
- // or CancelAuth (say, if the request was cancelled before the UI thread got
- // control). However, that's OK since any UI interaction in those functions
- // will occur via an InvokeLater on the UI thread, which is guaranteed
- // to happen after this is called (since this was InvokeLater'd first).
- SetDialog(GetTabContentsForLogin()->CreateConstrainedDialog(this));
-
- NotifyAuthNeeded();
- }
-
- // Overridden from ConstrainedWindowGtkDelegate:
- virtual GtkWidget* GetWidgetRoot() {
- return root_.get();
- }
-
- virtual void DeleteDelegate() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // The constrained window is going to delete itself; clear our pointer.
- SetDialog(NULL);
- SetModel(NULL);
-
- ReleaseSoon();
- }
-
- private:
- friend class LoginPrompt;
-
- CHROMEGTK_CALLBACK_0(LoginHandlerGtk, void, OnOKClicked);
- CHROMEGTK_CALLBACK_0(LoginHandlerGtk, void, OnCancelClicked);
- CHROMEGTK_CALLBACK_1(LoginHandlerGtk, void, OnPromptHierarchyChanged,
- GtkWidget*);
-
- // The GtkWidgets that form our visual hierarchy:
- // The root container we pass to our parent.
- OwnedWidgetGtk root_;
-
- // GtkEntry widgets that the user types into.
- GtkWidget* username_entry_;
- GtkWidget* password_entry_;
- GtkWidget* ok_;
-
- DISALLOW_COPY_AND_ASSIGN(LoginHandlerGtk);
-};
-
-void LoginHandlerGtk::OnOKClicked(GtkWidget* sender) {
- SetAuth(
- UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(username_entry_))),
- UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(password_entry_))));
-}
-
-void LoginHandlerGtk::OnCancelClicked(GtkWidget* sender) {
- CancelAuth();
-}
-
-void LoginHandlerGtk::OnPromptHierarchyChanged(GtkWidget* sender,
- GtkWidget* previous_toplevel) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- if (!GTK_WIDGET_TOPLEVEL(gtk_widget_get_toplevel(ok_)))
- return;
-
- // Now that we have attached ourself to the window, we can make our OK
- // button the default action and mess with the focus.
- GTK_WIDGET_SET_FLAGS(ok_, GTK_CAN_DEFAULT);
- gtk_widget_grab_default(ok_);
-
- TabContents* contents = GetTabContentsForLogin();
-
- // The user may have focused another tab. In this case do not grab focus
- // until this tab is refocused.
- if ((!contents->delegate() ||
- contents->delegate()->ShouldFocusConstrainedWindow()) &&
- gtk_util::IsWidgetAncestryVisible(username_entry_)) {
- gtk_widget_grab_focus(username_entry_);
- } else {
- // TODO(estade): this define should not need to be here because this class
- // should not be used on linux/views.
-#if defined(TOOLKIT_GTK)
- static_cast<TabContentsViewGtk*>(contents->view())->
- SetFocusedWidget(username_entry_);
-#endif
- }
-}
-
-// static
-LoginHandler* LoginHandler::Create(net::AuthChallengeInfo* auth_info,
- URLRequest* request) {
- return new LoginHandlerGtk(auth_info, request);
-}
diff --git a/chrome/browser/login_prompt_mac.h b/chrome/browser/login_prompt_mac.h
deleted file mode 100644
index 9d052ad..0000000
--- a/chrome/browser/login_prompt_mac.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_LOGIN_PROMPT_MAC_H_
-#define CHROME_BROWSER_LOGIN_PROMPT_MAC_H_
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-class LoginHandlerMac;
-
-// Controller of the sheet used by LoginHandlerMac. Interface Builder wants
-// this to be in a .h file.
-@interface LoginHandlerSheet : NSWindowController {
- @private
- IBOutlet NSTextField* nameField_;
- IBOutlet NSSecureTextField* passwordField_;
- IBOutlet NSTextField* explanationField_;
- IBOutlet NSButton* loginButton_;
- IBOutlet NSButton* cancelButton_;
- LoginHandlerMac* handler_; // weak, owns us
-}
-- (id)initWithLoginHandler:(LoginHandlerMac*)handler;
-- (IBAction)loginPressed:(id)sender;
-- (IBAction)cancelPressed:(id)sender;
-- (void)sheetDidEnd:(NSWindow*)sheet
- returnCode:(int)returnCode
- contextInfo:(void*)contextInfo;
-- (void)autofillLogin:(NSString*)login password:(NSString*)password;
-- (void)setExplanation:(NSString*)explanation;
-@end
-
-#endif // CHROME_BROWSER_LOGIN_PROMPT_MAC_H_
diff --git a/chrome/browser/login_prompt_mac.mm b/chrome/browser/login_prompt_mac.mm
deleted file mode 100644
index dcc2d1b..0000000
--- a/chrome/browser/login_prompt_mac.mm
+++ /dev/null
@@ -1,191 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/login_prompt.h"
-#import "chrome/browser/login_prompt_mac.h"
-
-#include "app/l10n_util.h"
-#include "base/mac_util.h"
-#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/cocoa/constrained_window_mac.h"
-#include "chrome/browser/login_model.h"
-#include "chrome/browser/password_manager/password_manager.h"
-#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
-#include "chrome/browser/tab_contents/navigation_controller.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents/tab_util.h"
-#include "chrome/common/notification_service.h"
-#include "grit/generated_resources.h"
-#include "net/url_request/url_request.h"
-#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-
-using webkit_glue::PasswordForm;
-
-// ----------------------------------------------------------------------------
-// LoginHandlerMac
-
-// This class simply forwards the authentication from the LoginView (on
-// the UI thread) to the URLRequest (on the I/O thread).
-// This class uses ref counting to ensure that it lives until all InvokeLaters
-// have been called.
-class LoginHandlerMac : public LoginHandler,
- public ConstrainedWindowMacDelegateCustomSheet {
- public:
- LoginHandlerMac(net::AuthChallengeInfo* auth_info, URLRequest* request)
- : LoginHandler(auth_info, request),
- sheet_controller_(nil) {
- }
-
- virtual ~LoginHandlerMac() {
- }
-
- // LoginModelObserver implementation.
- virtual void OnAutofillDataAvailable(const std::wstring& username,
- const std::wstring& password) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- [sheet_controller_ autofillLogin:base::SysWideToNSString(username)
- password:base::SysWideToNSString(password)];
- }
-
- // LoginHandler:
- virtual void BuildViewForPasswordManager(PasswordManager* manager,
- std::wstring explanation) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // Load nib here instead of in constructor.
- sheet_controller_ = [[[LoginHandlerSheet alloc]
- initWithLoginHandler:this] autorelease];
- init([sheet_controller_ window], sheet_controller_,
- @selector(sheetDidEnd:returnCode:contextInfo:));
-
- SetModel(manager);
-
- [sheet_controller_ setExplanation:base::SysWideToNSString(explanation)];
-
- // Scary thread safety note: This can potentially be called *after* SetAuth
- // or CancelAuth (say, if the request was cancelled before the UI thread got
- // control). However, that's OK since any UI interaction in those functions
- // will occur via an InvokeLater on the UI thread, which is guaranteed
- // to happen after this is called (since this was InvokeLater'd first).
- SetDialog(GetTabContentsForLogin()->CreateConstrainedDialog(this));
-
- NotifyAuthNeeded();
- }
-
- // Overridden from ConstrainedWindowMacDelegate:
- virtual void DeleteDelegate() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // The constrained window is going to delete itself; clear our pointer.
- SetDialog(NULL);
- SetModel(NULL);
-
- // Close sheet if it's still open, as required by
- // ConstrainedWindowMacDelegate.
- if (is_sheet_open())
- [NSApp endSheet:sheet()];
-
- ReleaseSoon();
- }
-
- void OnLoginPressed(const std::wstring& username,
- const std::wstring& password) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- SetAuth(username, password);
- }
-
- void OnCancelPressed() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- CancelAuth();
- }
-
- private:
- friend class LoginPrompt;
-
- // The Cocoa controller of the GUI.
- LoginHandlerSheet* sheet_controller_;
-
- DISALLOW_COPY_AND_ASSIGN(LoginHandlerMac);
-};
-
-// static
-LoginHandler* LoginHandler::Create(net::AuthChallengeInfo* auth_info,
- URLRequest* request) {
- return new LoginHandlerMac(auth_info, request);
-}
-
-// ----------------------------------------------------------------------------
-// LoginHandlerSheet
-
-@implementation LoginHandlerSheet
-
-- (id)initWithLoginHandler:(LoginHandlerMac*)handler {
- NSString* nibPath =
- [mac_util::MainAppBundle() pathForResource:@"HttpAuthLoginSheet"
- ofType:@"nib"];
- if ((self = [super initWithWindowNibPath:nibPath
- owner:self])) {
- handler_ = handler;
- }
- return self;
-}
-
-- (void)dealloc {
- // The buttons could be in a modal loop, so disconnect them so they cannot
- // call back to us after we're dead.
- [loginButton_ setTarget:nil];
- [cancelButton_ setTarget:nil];
- [super dealloc];
-}
-
-- (IBAction)loginPressed:(id)sender {
- using base::SysNSStringToWide;
- [NSApp endSheet:[self window]];
- handler_->OnLoginPressed(SysNSStringToWide([nameField_ stringValue]),
- SysNSStringToWide([passwordField_ stringValue]));
-}
-
-- (IBAction)cancelPressed:(id)sender {
- [NSApp endSheet:[self window]];
- handler_->OnCancelPressed();
-}
-
-- (void)sheetDidEnd:(NSWindow*)sheet
- returnCode:(int)returnCode
- contextInfo:(void *)contextInfo {
- [sheet orderOut:self];
- // Also called when user navigates to another page while the sheet is open.
-}
-
-- (void)autofillLogin:(NSString*)login password:(NSString*)password {
- if ([[nameField_ stringValue] length] == 0) {
- [nameField_ setStringValue:login];
- [passwordField_ setStringValue:password];
- [nameField_ selectText:self];
- }
-}
-
-- (void)setExplanation:(NSString*)explanation {
- // Put in the text.
- [explanationField_ setStringValue:explanation];
-
- // Resize the TextField.
- CGFloat explanationShift =
- [GTMUILocalizerAndLayoutTweaker
- sizeToFitFixedWidthTextField:explanationField_];
-
- // Resize the window (no shifting needed due to window layout).
- NSSize windowDelta = NSMakeSize(0, explanationShift);
- [GTMUILocalizerAndLayoutTweaker
- resizeWindowWithoutAutoResizingSubViews:[self window]
- delta:windowDelta];
-}
-
-@end
diff --git a/chrome/browser/login_prompt_unittest.cc b/chrome/browser/login_prompt_unittest.cc
deleted file mode 100644
index 1e8eabd..0000000
--- a/chrome/browser/login_prompt_unittest.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// 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.
-
-#include "chrome/browser/login_prompt.h"
-#include "googleurl/src/gurl.h"
-#include "net/base/auth.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-
-TEST(LoginPromptTest, GetSignonRealm) {
- scoped_refptr<net::AuthChallengeInfo> auth_info = new net::AuthChallengeInfo;
- auth_info->is_proxy = false; // server auth
- // auth_info->host is intentionally left empty.
- auth_info->scheme = L"Basic";
- auth_info->realm = L"WallyWorld";
-
- std::string url[] = {
- "https://www.nowhere.org/dir/index.html",
- "https://www.nowhere.org:443/dir/index.html", // default port
- "https://www.nowhere.org:8443/dir/index.html", // non-default port
- "https://www.nowhere.org", // no trailing slash
- "https://foo:bar@www.nowhere.org/dir/index.html", // username:password
- "https://www.nowhere.org/dir/index.html?id=965362", // query
- "https://www.nowhere.org/dir/index.html#toc", // reference
- };
-
- std::string expected[] = {
- "https://www.nowhere.org/WallyWorld",
- "https://www.nowhere.org/WallyWorld",
- "https://www.nowhere.org:8443/WallyWorld",
- "https://www.nowhere.org/WallyWorld",
- "https://www.nowhere.org/WallyWorld",
- "https://www.nowhere.org/WallyWorld",
- "https://www.nowhere.org/WallyWorld"
- };
-
- for (size_t i = 0; i < arraysize(url); i++) {
- std::string key = GetSignonRealm(GURL(url[i]), *auth_info);
- EXPECT_EQ(expected[i], key);
- }
-}
diff --git a/chrome/browser/login_prompt_win.cc b/chrome/browser/login_prompt_win.cc
deleted file mode 100644
index 703dbbb..0000000
--- a/chrome/browser/login_prompt_win.cc
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/login_prompt.h"
-
-#include "app/l10n_util.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/password_manager/password_manager.h"
-#include "chrome/browser/renderer_host/render_process_host.h"
-#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
-#include "chrome/browser/tab_contents/navigation_controller.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents/tab_contents_delegate.h"
-#include "chrome/browser/tab_contents/tab_util.h"
-#include "chrome/browser/views/login_view.h"
-#include "chrome/common/notification_service.h"
-#include "grit/generated_resources.h"
-#include "net/url_request/url_request.h"
-#include "views/window/dialog_delegate.h"
-
-using webkit_glue::PasswordForm;
-
-// ----------------------------------------------------------------------------
-// LoginHandlerWin
-
-// This class simply forwards the authentication from the LoginView (on
-// the UI thread) to the URLRequest (on the I/O thread).
-// This class uses ref counting to ensure that it lives until all InvokeLaters
-// have been called.
-class LoginHandlerWin : public LoginHandler,
- public ConstrainedDialogDelegate {
- public:
- LoginHandlerWin(net::AuthChallengeInfo* auth_info, URLRequest* request)
- : LoginHandler(auth_info, request) {
- }
-
- // LoginModelObserver implementation.
- virtual void OnAutofillDataAvailable(const std::wstring& username,
- const std::wstring& password) {
- // Nothing to do here since LoginView takes care of autofil for win.
- }
-
- void set_login_view(LoginView* login_view) {
- login_view_ = login_view;
- }
-
- // views::DialogDelegate methods:
- virtual std::wstring GetDialogButtonLabel(
- MessageBoxFlags::DialogButton button) const {
- if (button == MessageBoxFlags::DIALOGBUTTON_OK)
- return l10n_util::GetString(IDS_LOGIN_DIALOG_OK_BUTTON_LABEL);
- return DialogDelegate::GetDialogButtonLabel(button);
- }
-
- virtual std::wstring GetWindowTitle() const {
- return l10n_util::GetString(IDS_LOGIN_DIALOG_TITLE);
- }
-
- virtual void WindowClosing() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- TabContents* tab = GetTabContentsForLogin();
- if (tab)
- tab->render_view_host()->set_ignore_input_events(false);
-
- // Reference is no longer valid.
- SetDialog(NULL);
-
- CancelAuth();
- }
-
- virtual void DeleteDelegate() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // The constrained window is going to delete itself; clear our pointer.
- SetDialog(NULL);
- SetModel(NULL);
-
- ReleaseSoon();
- }
-
- virtual bool Cancel() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- CancelAuth();
- return true;
- }
-
- virtual bool Accept() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- SetAuth(login_view_->GetUsername(), login_view_->GetPassword());
- return true;
- }
-
- virtual views::View* GetContentsView() {
- return login_view_;
- }
-
- // LoginHandler:
-
- virtual void BuildViewForPasswordManager(PasswordManager* manager,
- std::wstring explanation) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- TabContents* tab_contents = GetTabContentsForLogin();
- bool should_focus_view = !tab_contents->delegate() ||
- tab_contents->delegate()->ShouldFocusConstrainedWindow();
-
- LoginView* view = new LoginView(explanation, should_focus_view);
-
- // Set the model for the login view. The model (password manager) is owned
- // by the view's parent TabContents, so natural destruction order means we
- // don't have to worry about calling SetModel(NULL), because the view will
- // be deleted before the password manager.
- view->SetModel(manager);
-
- set_login_view(view);
-
- // Scary thread safety note: This can potentially be called *after* SetAuth
- // or CancelAuth (say, if the request was cancelled before the UI thread got
- // control). However, that's OK since any UI interaction in those functions
- // will occur via an InvokeLater on the UI thread, which is guaranteed
- // to happen after this is called (since this was InvokeLater'd first).
- SetDialog(GetTabContentsForLogin()->CreateConstrainedDialog(this));
- NotifyAuthNeeded();
- }
-
- private:
- friend class base::RefCountedThreadSafe<LoginHandlerWin>;
- friend class LoginPrompt;
-
- ~LoginHandlerWin() {}
-
- // The LoginView that contains the user's login information
- LoginView* login_view_;
-
- DISALLOW_COPY_AND_ASSIGN(LoginHandlerWin);
-};
-
-// static
-LoginHandler* LoginHandler::Create(net::AuthChallengeInfo* auth_info,
- URLRequest* request) {
- return new LoginHandlerWin(auth_info, request);
-}
diff --git a/chrome/browser/mach_broker_mac.cc b/chrome/browser/mach_broker_mac.cc
index 18bb546..b3afe94 100644
--- a/chrome/browser/mach_broker_mac.cc
+++ b/chrome/browser/mach_broker_mac.cc
@@ -121,7 +121,7 @@ class MachListenerThreadDelegate : public PlatformThread::Delegate {
};
// Returns the global MachBroker.
-MachBroker* MachBroker::instance() {
+MachBroker* MachBroker::GetInstance() {
return Singleton<MachBroker, LeakySingletonTraits<MachBroker> >::get();
}
diff --git a/chrome/browser/mach_broker_mac.h b/chrome/browser/mach_broker_mac.h
index 7b0257f..2007055 100644
--- a/chrome/browser/mach_broker_mac.h
+++ b/chrome/browser/mach_broker_mac.h
@@ -36,7 +36,7 @@ class MachBroker : public base::ProcessMetrics::PortProvider,
public NotificationObserver {
public:
// Returns the global MachBroker.
- static MachBroker* instance();
+ static MachBroker* GetInstance();
// Performs any necessary setup that cannot happen in the constructor.
// Clients MUST call this method before fork()ing any children.
diff --git a/chrome/browser/media_uitest.cc b/chrome/browser/media_uitest.cc
index fbbdebc..61861e0 100644
--- a/chrome/browser/media_uitest.cc
+++ b/chrome/browser/media_uitest.cc
@@ -66,10 +66,10 @@ class MediaTest : public UITest {
};
#if defined(OS_LINUX)
-// Test fails on linux: http://crbug.com/56364
-#define MAYBE_MediaUILayoutTest DISABLED_MediaUILayoutTest
-#else
-#define MAYBE_MediaUILayoutTest MediaUILayoutTest
+// Test appears to be fine on linux, but let's first change to flaky and
+// see how that goes.
+// http://crbug.com/56364
+#define MediaUILayoutTest FLAKY_MediaUILayoutTest
#endif
TEST_F(MediaTest, VideoBearTheora) {
@@ -102,7 +102,7 @@ TEST_F(MediaTest, VideoBearWav) {
PlayVideo("bear.wav");
}
-TEST_F(UILayoutTest, MAYBE_MediaUILayoutTest) {
+TEST_F(UILayoutTest, MediaUILayoutTest) {
static const char* kResources[] = {
"content",
"media-file.js",
diff --git a/chrome/browser/memory_details.cc b/chrome/browser/memory_details.cc
index b728543..6f83083 100644
--- a/chrome/browser/memory_details.cc
+++ b/chrome/browser/memory_details.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/memory_details.h"
+#include "app/l10n_util.h"
#include "base/file_version_info.h"
#include "base/metrics/histogram.h"
#include "base/process_util.h"
@@ -18,6 +19,7 @@
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/url_constants.h"
#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
#if defined(OS_LINUX)
#include "chrome/browser/zygote_host_linux.h"
@@ -88,7 +90,7 @@ void MemoryDetails::CollectChildInfoOnIOThread() {
continue;
info.type = iter->type();
- info.titles.push_back(iter->name());
+ info.titles.push_back(WideToUTF16Hack(iter->name()));
child_info.push_back(info);
}
@@ -102,8 +104,8 @@ void MemoryDetails::CollectChildInfoOnUIThread() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
#if defined(OS_LINUX)
- const pid_t zygote_pid = Singleton<ZygoteHost>()->pid();
- const pid_t sandbox_helper_pid = Singleton<RenderSandboxHostLinux>()->pid();
+ const pid_t zygote_pid = ZygoteHost::GetInstance()->pid();
+ const pid_t sandbox_helper_pid = RenderSandboxHostLinux::GetInstance()->pid();
#endif
ProcessData* const chrome_browser = ChromeBrowser();
@@ -149,9 +151,9 @@ void MemoryDetails::CollectChildInfoOnUIThread() {
contents = host->delegate()->GetAsTabContents();
if (!contents)
continue;
- std::wstring title = UTF16ToWideHack(contents->GetTitle());
+ string16 title = contents->GetTitle();
if (!title.length())
- title = L"Untitled";
+ title = l10n_util::GetStringUTF16(IDS_DEFAULT_TAB_TITLE);
process.titles.push_back(title);
// We need to check the pending entry as well as the virtual_url to
diff --git a/chrome/browser/memory_details.h b/chrome/browser/memory_details.h
index 2b152b6..b39a1a6 100644
--- a/chrome/browser/memory_details.h
+++ b/chrome/browser/memory_details.h
@@ -10,6 +10,7 @@
#include "base/process_util.h"
#include "base/ref_counted.h"
+#include "base/string16.h"
#include "chrome/common/child_process_info.h"
// We collect data about each browser process. A browser may
@@ -26,9 +27,9 @@ struct ProcessMemoryInformation {
// The committed bytes.
base::CommittedKBytes committed;
// The process version
- std::wstring version;
+ string16 version;
// The process product name.
- std::wstring product_name;
+ string16 product_name;
// The number of processes which this memory represents.
int num_processes;
// A process is a diagnostics process if it is rendering
@@ -37,7 +38,7 @@ struct ProcessMemoryInformation {
// If this is a child process of Chrome, what type (i.e. plugin) it is.
ChildProcessInfo::ProcessType type;
// A collection of titles used, i.e. for a tab it'll show all the page titles.
- std::vector<std::wstring> titles;
+ std::vector<string16> titles;
};
typedef std::vector<ProcessMemoryInformation> ProcessMemoryInformationList;
@@ -49,8 +50,8 @@ struct ProcessData {
~ProcessData();
ProcessData& operator=(const ProcessData& rhs);
- std::wstring name;
- std::wstring process_name;
+ string16 name;
+ string16 process_name;
ProcessMemoryInformationList processes;
};
diff --git a/chrome/browser/memory_details_linux.cc b/chrome/browser/memory_details_linux.cc
index fabb1d0..a5e58b8 100644
--- a/chrome/browser/memory_details_linux.cc
+++ b/chrome/browser/memory_details_linux.cc
@@ -8,13 +8,14 @@
#include <fcntl.h>
#include <dirent.h>
+#include <set>
+
#include "base/eintr_wrapper.h"
#include "base/file_version_info.h"
#include "base/string_util.h"
#include "base/process_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_child_process_host.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/zygote_host_linux.h"
#include "chrome/common/chrome_constants.h"
@@ -235,12 +236,12 @@ void MemoryDetails::CollectProcessData(
}
std::vector<pid_t> current_browser_processes;
- const pid_t zygote = Singleton<ZygoteHost>()->pid();
+ const pid_t zygote = ZygoteHost::GetInstance()->pid();
GetAllChildren(processes, getpid(), zygote, &current_browser_processes);
ProcessData current_browser;
GetProcessDataMemoryInformation(current_browser_processes, &current_browser);
- current_browser.name = chrome::kBrowserAppName;
- current_browser.process_name = L"chrome";
+ current_browser.name = WideToUTF16(chrome::kBrowserAppName);
+ current_browser.process_name = ASCIIToUTF16("chrome");
process_data_.push_back(current_browser);
// For each browser process, collect a list of its children and get the
@@ -257,7 +258,7 @@ void MemoryDetails::CollectProcessData(
if (j->pid == *i) {
BrowserType type = GetBrowserType(j->name);
if (type != MAX_BROWSERS)
- browser.name = ASCIIToWide(kBrowserPrettyNames[type]);
+ browser.name = ASCIIToUTF16(kBrowserPrettyNames[type]);
break;
}
}
diff --git a/chrome/browser/memory_details_mac.cc b/chrome/browser/memory_details_mac.cc
index 399049e..09a298f 100644
--- a/chrome/browser/memory_details_mac.cc
+++ b/chrome/browser/memory_details_mac.cc
@@ -17,13 +17,11 @@
#include "base/thread.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_child_process_host.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/process_info_snapshot.h"
#include "chrome/browser/renderer_host/backing_store_manager.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/url_constants.h"
@@ -53,8 +51,8 @@ enum BrowserType {
MemoryDetails::MemoryDetails() {
- static const std::wstring google_browser_name =
- l10n_util::GetString(IDS_PRODUCT_NAME);
+ static const std::string google_browser_name =
+ l10n_util::GetStringUTF8(IDS_PRODUCT_NAME);
// (Human and process) names of browsers; should match the ordering for
// |BrowserProcess| (i.e., |BrowserType|).
// TODO(viettrungluu): The current setup means that we can't detect both
@@ -62,21 +60,21 @@ MemoryDetails::MemoryDetails() {
// TODO(viettrungluu): Get localized browser names for other browsers
// (crbug.com/25779).
struct {
- const wchar_t* name;
- const wchar_t* process_name;
+ const char* name;
+ const char* process_name;
} process_template[MAX_BROWSERS] = {
{ google_browser_name.c_str(), chrome::kBrowserProcessExecutableName, },
- { L"Safari", L"Safari", },
- { L"Firefox", L"firefox-bin", },
- { L"Camino", L"Camino", },
- { L"Opera", L"Opera", },
- { L"OmniWeb", L"OmniWeb", },
+ { "Safari", "Safari", },
+ { "Firefox", "firefox-bin", },
+ { "Camino", "Camino", },
+ { "Opera", "Opera", },
+ { "OmniWeb", "OmniWeb", },
};
for (size_t index = 0; index < MAX_BROWSERS; ++index) {
ProcessData process;
- process.name = process_template[index].name;
- process.process_name = process_template[index].process_name;
+ process.name = UTF8ToUTF16(process_template[index].name);
+ process.process_name = UTF8ToUTF16(process_template[index].process_name);
process_data_.push_back(process);
}
}
@@ -106,8 +104,8 @@ void MemoryDetails::CollectProcessData(
std::vector<base::ProcessId> pids_by_browser[MAX_BROWSERS];
std::vector<base::ProcessId> all_pids;
for (size_t index = CHROME_BROWSER; index < MAX_BROWSERS; index++) {
- base::NamedProcessIterator process_it(process_data_[index].process_name,
- NULL);
+ base::NamedProcessIterator process_it(
+ UTF16ToUTF8(process_data_[index].process_name), NULL);
while (const base::ProcessEntry* entry = process_it.NextProcessEntry()) {
pids_by_browser[index].push_back(entry->pid());
@@ -160,7 +158,7 @@ void MemoryDetails::CollectProcessData(
info.version = version_info->product_version();
} else {
info.product_name = process_data_[index].name;
- info.version = L"";
+ info.version = string16();
}
// Memory info.
@@ -204,11 +202,11 @@ void MemoryDetails::CollectProcessDataChrome(
chrome::VersionInfo version_info;
if (version_info.is_valid()) {
- info.product_name = ASCIIToWide(version_info.Name());
- info.version = ASCIIToWide(version_info.Version());
+ info.product_name = ASCIIToUTF16(version_info.Name());
+ info.version = ASCIIToUTF16(version_info.Version());
} else {
info.product_name = process_data_[CHROME_BROWSER].name;
- info.version = L"";
+ info.version = string16();
}
// Check if this is one of the child processes whose data we collected
diff --git a/chrome/browser/memory_details_win.cc b/chrome/browser/memory_details_win.cc
index 045321f..91f0b6d 100644
--- a/chrome/browser/memory_details_win.cc
+++ b/chrome/browser/memory_details_win.cc
@@ -6,6 +6,7 @@
#include <psapi.h>
#include "app/l10n_util.h"
+#include "base/file_path.h"
#include "base/file_version_info.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
@@ -14,7 +15,6 @@
#include "chrome/browser/renderer_host/backing_store_manager.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/url_constants.h"
#include "grit/chromium_strings.h"
@@ -136,7 +136,7 @@ void MemoryDetails::CollectProcessData(
} else if (GetModuleFileNameEx(handle, NULL, name, MAX_PATH - 1)) {
std::wstring str_name(name);
scoped_ptr<FileVersionInfo> version_info(
- FileVersionInfo::CreateFileVersionInfo(str_name));
+ FileVersionInfo::CreateFileVersionInfo(FilePath(str_name)));
if (version_info != NULL) {
info.version = version_info->product_version();
info.product_name = version_info->product_name();
diff --git a/chrome/browser/memory_purger.cc b/chrome/browser/memory_purger.cc
index 3543ee5..2bfbebd 100644
--- a/chrome/browser/memory_purger.cc
+++ b/chrome/browser/memory_purger.cc
@@ -11,7 +11,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/in_process_webkit/webkit_context.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/renderer_host/backing_store_manager.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
diff --git a/chrome/browser/message_box_handler.cc b/chrome/browser/message_box_handler.cc
deleted file mode 100644
index 4150945..0000000
--- a/chrome/browser/message_box_handler.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-// 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.
-
-#include "chrome/browser/message_box_handler.h"
-
-#include "app/l10n_util.h"
-#include "app/message_box_flags.h"
-#include "app/text_elider.h"
-#include "base/i18n/rtl.h"
-#include "base/utf_string_conversions.h"
-#include "build/build_config.h"
-#include "chrome/browser/app_modal_dialog_queue.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/js_modal_dialog.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/url_constants.h"
-#include "gfx/font.h"
-#include "googleurl/src/gurl.h"
-#include "grit/generated_resources.h"
-#include "grit/chromium_strings.h"
-
-static std::wstring GetTitle(Profile* profile,
- bool is_alert,
- const GURL& frame_url) {
- ExtensionsService* extensions_service = profile->GetExtensionsService();
- if (extensions_service) {
- const Extension* extension =
- extensions_service->GetExtensionByURL(frame_url);
- if (!extension)
- extension = extensions_service->GetExtensionByWebExtent(frame_url);
-
- if (extension && (extension->location() == Extension::COMPONENT)) {
- return l10n_util::GetString(IDS_PRODUCT_NAME);
- } else if (extension && !extension->name().empty()) {
- return UTF8ToWide(extension->name());
- }
- }
- if (!frame_url.has_host()) {
- return l10n_util::GetString(
- is_alert ? IDS_JAVASCRIPT_ALERT_DEFAULT_TITLE
- : IDS_JAVASCRIPT_MESSAGEBOX_DEFAULT_TITLE);
- }
-
- // TODO(brettw) it should be easier than this to do the correct language
- // handling without getting the accept language from the profile.
- string16 base_address = gfx::ElideUrl(frame_url.GetOrigin(),
- gfx::Font(), 0,
- UTF8ToWide(profile->GetPrefs()->GetString(prefs::kAcceptLanguages)));
-
- // Force URL to have LTR directionality.
- base_address = base::i18n::GetDisplayStringInLTRDirectionality(
- base_address);
-
- return UTF16ToWide(l10n_util::GetStringFUTF16(
- is_alert ? IDS_JAVASCRIPT_ALERT_TITLE :
- IDS_JAVASCRIPT_MESSAGEBOX_TITLE,
- base_address));
-}
-
-void RunJavascriptMessageBox(Profile* profile,
- JavaScriptAppModalDialogDelegate* delegate,
- const GURL& frame_url,
- int dialog_flags,
- const std::wstring& message_text,
- const std::wstring& default_prompt_text,
- bool display_suppress_checkbox,
- IPC::Message* reply_msg) {
- bool is_alert = dialog_flags == MessageBoxFlags::kIsJavascriptAlert;
- std::wstring title = GetTitle(profile, is_alert, frame_url);
- Singleton<AppModalDialogQueue>()->AddDialog(new JavaScriptAppModalDialog(
- delegate, title, dialog_flags, message_text, default_prompt_text,
- display_suppress_checkbox, false, reply_msg));
-}
-
-void RunBeforeUnloadDialog(TabContents* tab_contents,
- const std::wstring& message_text,
- IPC::Message* reply_msg) {
- std::wstring full_message =
- message_text + L"\n\n" +
- l10n_util::GetString(IDS_BEFOREUNLOAD_MESSAGEBOX_FOOTER);
- Singleton<AppModalDialogQueue>()->AddDialog(new JavaScriptAppModalDialog(
- tab_contents, l10n_util::GetString(IDS_BEFOREUNLOAD_MESSAGEBOX_TITLE),
- MessageBoxFlags::kIsJavascriptConfirm, message_text, std::wstring(),
- false, true, reply_msg));
-}
diff --git a/chrome/browser/message_box_handler.h b/chrome/browser/message_box_handler.h
deleted file mode 100644
index e6f08e5..0000000
--- a/chrome/browser/message_box_handler.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_MESSAGE_BOX_HANDLER_H_
-#define CHROME_BROWSER_MESSAGE_BOX_HANDLER_H_
-#pragma once
-
-#include <string>
-
-#include "ipc/ipc_message.h"
-
-class GURL;
-class JavaScriptAppModalDialogDelegate;
-class TabContents;
-class Profile;
-
-// Creates and runs a Javascript Message Box dialog.
-// The dialog type is specified within |dialog_flags|, the
-// default static display text is in |message_text| and if the dialog box is
-// a user input prompt() box, the default text for the text field is in
-// |default_prompt_text|. The result of the operation is returned using
-// |reply_msg|.
-void RunJavascriptMessageBox(Profile* profile,
- JavaScriptAppModalDialogDelegate* delegate,
- const GURL& frame_url,
- int dialog_flags,
- const std::wstring& message_text,
- const std::wstring& default_prompt_text,
- bool display_suppress_checkbox,
- IPC::Message* reply_msg);
-
-// This will display a modal dialog box with a header and footer asking the
-// the user if they wish to navigate away from a page, with additional text
-// |message_text| between the header and footer. The users response is
-// returned to the renderer using |reply_msg|.
-void RunBeforeUnloadDialog(TabContents* tab_contents,
- const std::wstring& message_text,
- IPC::Message* reply_msg);
-
-#endif // CHROME_BROWSER_MESSAGE_BOX_HANDLER_H_
diff --git a/chrome/browser/metrics/metrics_log.cc b/chrome/browser/metrics/metrics_log.cc
index e21f075..bf54134 100644
--- a/chrome/browser/metrics/metrics_log.cc
+++ b/chrome/browser/metrics/metrics_log.cc
@@ -25,6 +25,7 @@
#include "chrome/common/logging_chrome.h"
#include "chrome/common/pref_names.h"
#include "googleurl/src/gurl.h"
+#include "webkit/plugins/npapi/webplugininfo.h"
#define OPEN_ELEMENT_FOR_SCOPE(name) ScopedElement scoped_element(this, name)
@@ -237,12 +238,13 @@ void MetricsLog::WriteRealtimeStabilityAttributes(PrefService* pref) {
}
void MetricsLog::WritePluginList(
- const std::vector<WebPluginInfo>& plugin_list) {
+ const std::vector<webkit::npapi::WebPluginInfo>& plugin_list) {
DCHECK(!locked_);
OPEN_ELEMENT_FOR_SCOPE("plugins");
- for (std::vector<WebPluginInfo>::const_iterator iter = plugin_list.begin();
+ for (std::vector<webkit::npapi::WebPluginInfo>::const_iterator iter =
+ plugin_list.begin();
iter != plugin_list.end(); ++iter) {
OPEN_ELEMENT_FOR_SCOPE("plugin");
@@ -262,7 +264,7 @@ void MetricsLog::WriteInstallElement() {
}
void MetricsLog::RecordEnvironment(
- const std::vector<WebPluginInfo>& plugin_list,
+ const std::vector<webkit::npapi::WebPluginInfo>& plugin_list,
const DictionaryValue* profile_metrics) {
DCHECK(!locked_);
@@ -300,10 +302,12 @@ void MetricsLog::RecordEnvironment(
{
OPEN_ELEMENT_FOR_SCOPE("gpu");
- WriteIntAttribute("vendorid",
- GpuProcessHostUIShim::Get()->gpu_info().vendor_id());
- WriteIntAttribute("deviceid",
- GpuProcessHostUIShim::Get()->gpu_info().device_id());
+ WriteIntAttribute(
+ "vendorid",
+ GpuProcessHostUIShim::GetInstance()->gpu_info().vendor_id());
+ WriteIntAttribute(
+ "deviceid",
+ GpuProcessHostUIShim::GetInstance()->gpu_info().device_id());
}
{
diff --git a/chrome/browser/metrics/metrics_log.h b/chrome/browser/metrics/metrics_log.h
index 8f35705..0cb8b29 100644
--- a/chrome/browser/metrics/metrics_log.h
+++ b/chrome/browser/metrics/metrics_log.h
@@ -12,13 +12,18 @@
#include "base/basictypes.h"
#include "chrome/common/metrics_helpers.h"
#include "chrome/common/page_transition_types.h"
-#include "webkit/glue/plugins/webplugininfo.h"
struct AutocompleteLog;
class DictionaryValue;
class GURL;
class PrefService;
+namespace webkit {
+namespace npapi {
+struct WebPluginInfo;
+}
+}
+
class MetricsLog : public MetricsLogBase {
public:
// Creates a new metrics log
@@ -35,8 +40,9 @@ class MetricsLog : public MetricsLogBase {
// profile_metrics, if non-null, gives a dictionary of all profile metrics
// that are to be recorded. Each value in profile_metrics should be a
// dictionary giving the metrics for the profile.
- void RecordEnvironment(const std::vector<WebPluginInfo>& plugin_list,
- const DictionaryValue* profile_metrics);
+ void RecordEnvironment(
+ const std::vector<webkit::npapi::WebPluginInfo>& plugin_list,
+ const DictionaryValue* profile_metrics);
// Records the input text, available choices, and selected entry when the
// user uses the Omnibox to open a URL.
@@ -80,7 +86,8 @@ class MetricsLog : public MetricsLogBase {
void WriteRealtimeStabilityAttributes(PrefService* pref);
// Writes the list of installed plugins.
- void WritePluginList(const std::vector<WebPluginInfo>& plugin_list);
+ void WritePluginList(
+ const std::vector<webkit::npapi::WebPluginInfo>& plugin_list);
// Within the profile group, write basic install info including appversion.
void WriteInstallElement();
diff --git a/chrome/browser/metrics/metrics_service.cc b/chrome/browser/metrics/metrics_service.cc
index 9cafefc..5e1af15 100644
--- a/chrome/browser/metrics/metrics_service.cc
+++ b/chrome/browser/metrics/metrics_service.cc
@@ -169,23 +169,23 @@
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/guid.h"
#include "chrome/browser/load_notification_details.h"
#include "chrome/browser/memory_details.h"
#include "chrome/browser/metrics/histogram_synchronizer.h"
#include "chrome/browser/metrics/metrics_log.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/common/child_process_info.h"
#include "chrome/common/child_process_logging.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/guid.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
-#include "webkit/glue/plugins/plugin_list.h"
-#include "webkit/glue/plugins/webplugininfo.h"
+#include "webkit/plugins/npapi/plugin_list.h"
+#include "webkit/plugins/npapi/webplugininfo.h"
#include "libxml/xmlwriter.h"
// TODO(port): port browser_distribution.h.
@@ -336,8 +336,9 @@ class MetricsMemoryDetails : public MemoryDetails {
class MetricsService::InitTaskComplete : public Task {
public:
- explicit InitTaskComplete(const std::string& hardware_class,
- const std::vector<WebPluginInfo>& plugins)
+ explicit InitTaskComplete(
+ const std::string& hardware_class,
+ const std::vector<webkit::npapi::WebPluginInfo>& plugins)
: hardware_class_(hardware_class), plugins_(plugins) {}
virtual void Run() {
@@ -347,7 +348,7 @@ class MetricsService::InitTaskComplete : public Task {
private:
std::string hardware_class_;
- std::vector<WebPluginInfo> plugins_;
+ std::vector<webkit::npapi::WebPluginInfo> plugins_;
};
class MetricsService::InitTask : public Task {
@@ -356,12 +357,12 @@ class MetricsService::InitTask : public Task {
: callback_loop_(callback_loop) {}
virtual void Run() {
- std::vector<WebPluginInfo> plugins;
- NPAPI::PluginList::Singleton()->GetPlugins(false, &plugins);
+ std::vector<webkit::npapi::WebPluginInfo> plugins;
+ webkit::npapi::PluginList::Singleton()->GetPlugins(false, &plugins);
std::string hardware_class; // Empty string by default.
#if defined(OS_CHROMEOS)
chromeos::SystemLibrary* system_library =
- chromeos::CrosLibrary::Get()->GetSystemLibrary();
+ chromeos::CrosLibrary::Get()->GetSystemLibrary();
system_library->GetMachineStatistic("hardware_class", &hardware_class);
#endif // OS_CHROMEOS
callback_loop_->PostTask(FROM_HERE, new InitTaskComplete(
@@ -606,11 +607,13 @@ void MetricsService::Observe(NotificationType type,
LogLoadStarted();
break;
- case NotificationType::RENDERER_PROCESS_CLOSED:
- {
+ case NotificationType::RENDERER_PROCESS_CLOSED: {
RenderProcessHost::RendererClosedDetails* process_details =
Details<RenderProcessHost::RendererClosedDetails>(details).ptr();
- if (process_details->did_crash) {
+ if (process_details->status ==
+ base::TERMINATION_STATUS_PROCESS_CRASHED ||
+ process_details->status ==
+ base::TERMINATION_STATUS_ABNORMAL_TERMINATION) {
if (process_details->was_extension_renderer) {
LogExtensionRendererCrash();
} else {
@@ -799,7 +802,7 @@ void MetricsService::InitializeMetricsState() {
void MetricsService::OnInitTaskComplete(
const std::string& hardware_class,
- const std::vector<WebPluginInfo>& plugins) {
+ const std::vector<webkit::npapi::WebPluginInfo>& plugins) {
DCHECK(state_ == INIT_TASK_SCHEDULED);
hardware_class_ = hardware_class;
plugins_ = plugins;
diff --git a/chrome/browser/metrics/metrics_service.h b/chrome/browser/metrics/metrics_service.h
index f1cfbb2..fa15a12 100644
--- a/chrome/browser/metrics/metrics_service.h
+++ b/chrome/browser/metrics/metrics_service.h
@@ -33,7 +33,12 @@ class HistogramSynchronizer;
class MetricsLogBase;
class PrefService;
class TemplateURLModel;
+
+namespace webkit {
+namespace npapi {
struct WebPluginInfo;
+}
+}
// Forward declaration of the xmlNode to avoid having tons of gyp files
// needing to depend on the libxml third party lib.
@@ -155,7 +160,7 @@ class MetricsService : public NotificationObserver,
// Callback to let us know that the init task is done.
void OnInitTaskComplete(
const std::string& hardware_class,
- const std::vector<WebPluginInfo>& plugins);
+ const std::vector<webkit::npapi::WebPluginInfo>& plugins);
// When we start a new version of Chromium (different from our last run), we
// need to discard the old crash stats so that we don't attribute crashes etc.
@@ -418,7 +423,7 @@ class MetricsService : public NotificationObserver,
std::string hardware_class_;
// The list of plugins which was retrieved on the file thread.
- std::vector<WebPluginInfo> plugins_;
+ std::vector<webkit::npapi::WebPluginInfo> plugins_;
// The outstanding transmission appears as a URL Fetch operation.
scoped_ptr<URLFetcher> current_fetch_;
diff --git a/chrome/browser/metrics/metrics_service_uitest.cc b/chrome/browser/metrics/metrics_service_uitest.cc
index 93889c5..16eb641 100644
--- a/chrome/browser/metrics/metrics_service_uitest.cc
+++ b/chrome/browser/metrics/metrics_service_uitest.cc
@@ -11,16 +11,16 @@
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/platform_thread.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/prefs/pref_service_mock_builder.h"
#include "chrome/browser/prefs/pref_value_store.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/json_pref_store.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
-#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/automation/browser_proxy.h"
+#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/base/net_util.h"
@@ -51,10 +51,8 @@ class MetricsServiceTest : public UITest {
// that was saved by the app as it closed. The caller takes ownership of the
// returned PrefService object.
PrefService* GetLocalState() {
- FilePath local_state_path = user_data_dir()
- .Append(chrome::kLocalStateFilename);
-
- return PrefService::CreateUserPrefService(local_state_path);
+ FilePath path = user_data_dir().Append(chrome::kLocalStateFilename);
+ return PrefServiceMockBuilder().WithUserFilePrefs(path).Create();
}
};
diff --git a/chrome/browser/metrics/user_metrics.cc b/chrome/browser/metrics/user_metrics.cc
index 51aab70..e0b719d 100644
--- a/chrome/browser/metrics/user_metrics.cc
+++ b/chrome/browser/metrics/user_metrics.cc
@@ -1,9 +1,11 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// 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.
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/profile.h"
+
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/notification_service.h"
void UserMetrics::RecordAction(const UserMetricsAction& action,
@@ -29,10 +31,18 @@ void UserMetrics::RecordComputedAction(const std::string& action) {
}
void UserMetrics::Record(const char *action) {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableFunction(&UserMetrics::CallRecordOnUI, action));
+ return;
+ }
+
NotificationService::current()->Notify(NotificationType::USER_ACTION,
NotificationService::AllSources(),
Details<const char*>(&action));
}
-
-
+void UserMetrics::CallRecordOnUI(const std::string& action) {
+ Record(action.c_str());
+}
diff --git a/chrome/browser/metrics/user_metrics.h b/chrome/browser/metrics/user_metrics.h
index e9addb6..1c992ac 100644
--- a/chrome/browser/metrics/user_metrics.h
+++ b/chrome/browser/metrics/user_metrics.h
@@ -61,6 +61,7 @@ class UserMetrics {
private:
static void Record(const char *action, Profile *profile);
static void Record(const char *action);
+ static void CallRecordOnUI(const std::string& action);
};
#endif // CHROME_BROWSER_METRICS_USER_METRICS_H_
diff --git a/chrome/browser/mime_registry_dispatcher.cc b/chrome/browser/mime_registry_dispatcher.cc
deleted file mode 100644
index bc8653f..0000000
--- a/chrome/browser/mime_registry_dispatcher.cc
+++ /dev/null
@@ -1,96 +0,0 @@
-// 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.
-
-#include "chrome/browser/mime_registry_dispatcher.h"
-
-#include "chrome/browser/browser_thread.h"
-#include "chrome/common/render_messages.h"
-#include "net/base/mime_util.h"
-
-MimeRegistryDispatcher::MimeRegistryDispatcher(IPC::Message::Sender* sender)
- : message_sender_(sender) {
- DCHECK(message_sender_);
-}
-
-MimeRegistryDispatcher::~MimeRegistryDispatcher() {
-}
-
-void MimeRegistryDispatcher::Shutdown() {
- message_sender_ = NULL;
-}
-
-bool MimeRegistryDispatcher::OnMessageReceived(const IPC::Message& message) {
- // On Windows MIME registry requests may access the Windows Registry so
- // they need to run on the FILE thread.
- if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
- // Return false if the message is not for us.
- if (message.type() != ViewHostMsg_GetMimeTypeFromExtension::ID &&
- message.type() != ViewHostMsg_GetMimeTypeFromFile::ID &&
- message.type() != ViewHostMsg_GetPreferredExtensionForMimeType::ID)
- return false;
-
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(
- this, &MimeRegistryDispatcher::OnMessageReceived, message));
- return true;
- }
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(MimeRegistryDispatcher, message)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetMimeTypeFromExtension,
- OnGetMimeTypeFromExtension)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetMimeTypeFromFile,
- OnGetMimeTypeFromFile)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(
- ViewHostMsg_GetPreferredExtensionForMimeType,
- OnGetPreferredExtensionForMimeType)
- IPC_MESSAGE_UNHANDLED((handled = false))
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void MimeRegistryDispatcher::OnGetMimeTypeFromExtension(
- const FilePath::StringType& ext, IPC::Message* reply_msg) {
- std::string mime_type;
- net::GetMimeTypeFromExtension(ext, &mime_type);
- ViewHostMsg_GetMimeTypeFromExtension::WriteReplyParams(reply_msg, mime_type);
- Send(reply_msg);
-}
-
-void MimeRegistryDispatcher::OnGetMimeTypeFromFile(
- const FilePath& file_path, IPC::Message* reply_msg) {
- std::string mime_type;
- net::GetMimeTypeFromFile(file_path, &mime_type);
- ViewHostMsg_GetMimeTypeFromFile::WriteReplyParams(reply_msg, mime_type);
- Send(reply_msg);
-}
-
-void MimeRegistryDispatcher::OnGetPreferredExtensionForMimeType(
- const std::string& mime_type, IPC::Message* reply_msg) {
- FilePath::StringType ext;
- net::GetPreferredExtensionForMimeType(mime_type, &ext);
- ViewHostMsg_GetPreferredExtensionForMimeType::WriteReplyParams(
- reply_msg, ext);
- Send(reply_msg);
-}
-
-void MimeRegistryDispatcher::Send(IPC::Message* message) {
- if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
- if (!BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE, NewRunnableMethod(
- this, &MimeRegistryDispatcher::Send, message))) {
- // The IO thread is dead.
- delete message;
- }
- return;
- }
-
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (message_sender_)
- message_sender_->Send(message);
- else
- delete message;
-}
diff --git a/chrome/browser/mime_registry_dispatcher.h b/chrome/browser/mime_registry_dispatcher.h
deleted file mode 100644
index 0bd17dd..0000000
--- a/chrome/browser/mime_registry_dispatcher.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_MIME_REGISTRY_DISPATCHER_H_
-#define CHROME_BROWSER_MIME_REGISTRY_DISPATCHER_H_
-
-#include "base/file_path.h"
-#include "base/ref_counted.h"
-#include "ipc/ipc_message.h"
-
-class MimeRegistryDispatcher
- : public base::RefCountedThreadSafe<MimeRegistryDispatcher> {
- public:
- explicit MimeRegistryDispatcher(IPC::Message::Sender* sender);
- void Shutdown();
- bool OnMessageReceived(const IPC::Message& message);
- void Send(IPC::Message* message);
-
- private:
- friend class base::RefCountedThreadSafe<MimeRegistryDispatcher>;
- ~MimeRegistryDispatcher();
-
- void OnGetMimeTypeFromExtension(const FilePath::StringType& ext,
- IPC::Message* reply);
- void OnGetMimeTypeFromFile(const FilePath& file_path,
- IPC::Message* reply);
- void OnGetPreferredExtensionForMimeType(const std::string& mime_type,
- IPC::Message* reply);
-
- // The sender to be used for sending out IPC messages.
- IPC::Message::Sender* message_sender_;
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(MimeRegistryDispatcher);
-};
-
-#endif // CHROME_BROWSER_MIME_REGISTRY_DISPATCHER_H_
diff --git a/chrome/browser/mime_registry_message_filter.cc b/chrome/browser/mime_registry_message_filter.cc
new file mode 100644
index 0000000..c57cad3
--- /dev/null
+++ b/chrome/browser/mime_registry_message_filter.cc
@@ -0,0 +1,51 @@
+// 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.
+
+#include "chrome/browser/mime_registry_message_filter.h"
+
+#include "chrome/common/mime_registry_messages.h"
+#include "net/base/mime_util.h"
+
+MimeRegistryMessageFilter::MimeRegistryMessageFilter() {
+}
+
+MimeRegistryMessageFilter::~MimeRegistryMessageFilter() {
+}
+
+void MimeRegistryMessageFilter::OverrideThreadForMessage(
+ const IPC::Message& message,
+ BrowserThread::ID* thread) {
+ if (IPC_MESSAGE_CLASS(message) == MimeRegistryMsgStart)
+ *thread = BrowserThread::FILE;
+}
+
+bool MimeRegistryMessageFilter::OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(MimeRegistryMessageFilter, message, *message_was_ok)
+ IPC_MESSAGE_HANDLER(MimeRegistryMsg_GetMimeTypeFromExtension,
+ OnGetMimeTypeFromExtension)
+ IPC_MESSAGE_HANDLER(MimeRegistryMsg_GetMimeTypeFromFile,
+ OnGetMimeTypeFromFile)
+ IPC_MESSAGE_HANDLER(MimeRegistryMsg_GetPreferredExtensionForMimeType,
+ OnGetPreferredExtensionForMimeType)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void MimeRegistryMessageFilter::OnGetMimeTypeFromExtension(
+ const FilePath::StringType& ext, std::string* mime_type) {
+ net::GetMimeTypeFromExtension(ext, mime_type);
+}
+
+void MimeRegistryMessageFilter::OnGetMimeTypeFromFile(
+ const FilePath& file_path, std::string* mime_type) {
+ net::GetMimeTypeFromFile(file_path, mime_type);
+}
+
+void MimeRegistryMessageFilter::OnGetPreferredExtensionForMimeType(
+ const std::string& mime_type, FilePath::StringType* extension) {
+ net::GetPreferredExtensionForMimeType(mime_type, extension);
+}
diff --git a/chrome/browser/mime_registry_message_filter.h b/chrome/browser/mime_registry_message_filter.h
new file mode 100644
index 0000000..71348e5
--- /dev/null
+++ b/chrome/browser/mime_registry_message_filter.h
@@ -0,0 +1,31 @@
+// 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.
+
+#ifndef CHROME_BROWSER_MIME_REGISTRY_MESSAGE_FILTER_H_
+#define CHROME_BROWSER_MIME_REGISTRY_MESSAGE_FILTER_H_
+
+#include "base/file_path.h"
+#include "chrome/browser/browser_message_filter.h"
+
+class MimeRegistryMessageFilter : public BrowserMessageFilter {
+ public:
+ MimeRegistryMessageFilter();
+
+ virtual void OverrideThreadForMessage(const IPC::Message& message,
+ BrowserThread::ID* thread);
+ virtual bool OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok);
+
+ private:
+ ~MimeRegistryMessageFilter();
+
+ void OnGetMimeTypeFromExtension(const FilePath::StringType& ext,
+ std::string* mime_type);
+ void OnGetMimeTypeFromFile(const FilePath& file_path,
+ std::string* mime_type);
+ void OnGetPreferredExtensionForMimeType(const std::string& mime_type,
+ FilePath::StringType* extension);
+};
+
+#endif // CHROME_BROWSER_MIME_REGISTRY_MESSAGE_FILTER_H_
diff --git a/chrome/browser/mock_plugin_exceptions_table_model.cc b/chrome/browser/mock_plugin_exceptions_table_model.cc
index e2d38a7..1c88524 100644
--- a/chrome/browser/mock_plugin_exceptions_table_model.cc
+++ b/chrome/browser/mock_plugin_exceptions_table_model.cc
@@ -5,11 +5,11 @@
#include "chrome/browser/mock_plugin_exceptions_table_model.h"
void MockPluginExceptionsTableModel::set_plugins(
- const NPAPI::PluginList::PluginMap& plugins) {
+ std::vector<webkit::npapi::PluginGroup>& plugins) {
plugins_ = plugins;
}
void MockPluginExceptionsTableModel::GetPlugins(
- NPAPI::PluginList::PluginMap* plugins) {
- *plugins = plugins_;
+ std::vector<webkit::npapi::PluginGroup>* plugin_groups) {
+ *plugin_groups = plugins_;
}
diff --git a/chrome/browser/mock_plugin_exceptions_table_model.h b/chrome/browser/mock_plugin_exceptions_table_model.h
index d1f5da7..c63d67f 100644
--- a/chrome/browser/mock_plugin_exceptions_table_model.h
+++ b/chrome/browser/mock_plugin_exceptions_table_model.h
@@ -17,13 +17,14 @@ class MockPluginExceptionsTableModel : public PluginExceptionsTableModel {
: PluginExceptionsTableModel(map, otr_map) {}
virtual ~MockPluginExceptionsTableModel() {}
- void set_plugins(const NPAPI::PluginList::PluginMap& plugins);
+ void set_plugins(std::vector<webkit::npapi::PluginGroup>& plugins);
protected:
- virtual void GetPlugins(NPAPI::PluginList::PluginMap* plugins);
+ virtual void GetPlugins(
+ std::vector<webkit::npapi::PluginGroup>* plugin_groups);
private:
- NPAPI::PluginList::PluginMap plugins_;
+ std::vector<webkit::npapi::PluginGroup> plugins_;
};
#endif // CHROME_BROWSER_MOCK_PLUGIN_EXCEPTIONS_TABLE_MODEL_H_
diff --git a/chrome/browser/modal_html_dialog_delegate.cc b/chrome/browser/modal_html_dialog_delegate.cc
index 715edd9..bae474d 100644
--- a/chrome/browser/modal_html_dialog_delegate.cc
+++ b/chrome/browser/modal_html_dialog_delegate.cc
@@ -1,13 +1,15 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// 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.
#include "chrome/browser/modal_html_dialog_delegate.h"
+#include <string>
+
#include "chrome/browser/browser_list.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
#include "gfx/size.h"
ModalHtmlDialogDelegate::ModalHtmlDialogDelegate(
@@ -42,6 +44,10 @@ bool ModalHtmlDialogDelegate::IsDialogModal() const {
return true;
}
+std::wstring ModalHtmlDialogDelegate::GetDialogTitle() const {
+ return L"Gears";
+}
+
GURL ModalHtmlDialogDelegate::GetDialogContentURL() const {
return params_.url;
}
@@ -65,3 +71,7 @@ void ModalHtmlDialogDelegate::OnDialogClosed(const std::string& json_retval) {
// We are done with this request, so delete us.
delete this;
}
+
+bool ModalHtmlDialogDelegate::ShouldShowDialogTitle() const {
+ return true;
+}
diff --git a/chrome/browser/modal_html_dialog_delegate.h b/chrome/browser/modal_html_dialog_delegate.h
index 23bb0f7..dbdd812 100644
--- a/chrome/browser/modal_html_dialog_delegate.h
+++ b/chrome/browser/modal_html_dialog_delegate.h
@@ -39,7 +39,7 @@ class ModalHtmlDialogDelegate
// HTMLDialogUIDelegate implementation:
virtual bool IsDialogModal() const;
- virtual std::wstring GetDialogTitle() const { return L"Gears"; }
+ virtual std::wstring GetDialogTitle() const;
virtual GURL GetDialogContentURL() const;
virtual void GetDOMMessageHandlers(
std::vector<DOMMessageHandler*>* handlers) const { }
@@ -47,7 +47,7 @@ class ModalHtmlDialogDelegate
virtual std::string GetDialogArgs() const;
virtual void OnDialogClosed(const std::string& json_retval);
virtual void OnCloseContents(TabContents* source, bool* out_close_dialog) { }
- virtual bool ShouldShowDialogTitle() const { return true; }
+ virtual bool ShouldShowDialogTitle() const;
private:
NotificationRegistrar registrar_;
diff --git a/chrome/browser/nacl_host/nacl_broker_host_win.cc b/chrome/browser/nacl_host/nacl_broker_host_win.cc
index 7cd9bf2..7d0fbea 100644
--- a/chrome/browser/nacl_host/nacl_broker_host_win.cc
+++ b/chrome/browser/nacl_host/nacl_broker_host_win.cc
@@ -7,7 +7,6 @@
#include "base/command_line.h"
#include "base/path_service.h"
#include "ipc/ipc_switches.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/nacl_host/nacl_broker_service_win.h"
#include "chrome/browser/nacl_host/nacl_process_host.h"
#include "chrome/common/chrome_constants.h"
@@ -24,12 +23,6 @@ NaClBrokerHost::NaClBrokerHost(
NaClBrokerHost::~NaClBrokerHost() {
}
-URLRequestContext* NaClBrokerHost::GetRequestContext(
- uint32 request_id,
- const ViewHostMsg_Resource_Request& request_data) {
- return NULL;
-}
-
bool NaClBrokerHost::Init() {
// Create the channel that will be used for communicating with the broker.
if (!CreateChannel())
@@ -53,10 +46,13 @@ bool NaClBrokerHost::Init() {
return true;
}
-void NaClBrokerHost::OnMessageReceived(const IPC::Message& msg) {
+bool NaClBrokerHost::OnMessageReceived(const IPC::Message& msg) {
+ bool handled = true;
IPC_BEGIN_MESSAGE_MAP(NaClBrokerHost, msg)
IPC_MESSAGE_HANDLER(NaClProcessMsg_LoaderLaunched, OnLoaderLaunched)
+ IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
+ return handled;
}
bool NaClBrokerHost::LaunchLoader(
diff --git a/chrome/browser/nacl_host/nacl_broker_host_win.h b/chrome/browser/nacl_host/nacl_broker_host_win.h
index 9e07e3e..27ceb24 100644
--- a/chrome/browser/nacl_host/nacl_broker_host_win.h
+++ b/chrome/browser/nacl_host/nacl_broker_host_win.h
@@ -7,9 +7,7 @@
#pragma once
#include "base/basictypes.h"
-#include "base/process.h"
#include "chrome/browser/browser_child_process_host.h"
-#include "ipc/ipc_message.h"
class NaClBrokerHost : public BrowserChildProcessHost {
public:
@@ -28,11 +26,6 @@ class NaClBrokerHost : public BrowserChildProcessHost {
void StopBroker();
private:
- // ResourceDispatcherHost::Receiver implementation:
- virtual URLRequestContext* GetRequestContext(
- uint32 request_id,
- const ViewHostMsg_Resource_Request& request_data);
-
virtual bool CanShutdown() { return true; }
// Handler for NaClProcessMsg_LoaderLaunched message
@@ -40,7 +33,7 @@ class NaClBrokerHost : public BrowserChildProcessHost {
base::ProcessHandle handle);
// IPC::Channel::Listener
- virtual void OnMessageReceived(const IPC::Message& msg);
+ virtual bool OnMessageReceived(const IPC::Message& msg);
bool stopping_;
diff --git a/chrome/browser/nacl_host/nacl_broker_service_win.cc b/chrome/browser/nacl_host/nacl_broker_service_win.cc
index d5524ad..602f98e 100644
--- a/chrome/browser/nacl_host/nacl_broker_service_win.cc
+++ b/chrome/browser/nacl_host/nacl_broker_service_win.cc
@@ -4,7 +4,6 @@
#include "chrome/browser/nacl_host/nacl_broker_service_win.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/nacl_host/nacl_process_host.h"
#include "chrome/common/chrome_switches.h"
diff --git a/chrome/browser/nacl_host/nacl_process_host.cc b/chrome/browser/nacl_host/nacl_process_host.cc
index 8200892..a009702 100644
--- a/chrome/browser/nacl_host/nacl_process_host.cc
+++ b/chrome/browser/nacl_host/nacl_process_host.cc
@@ -13,7 +13,7 @@
#include "base/command_line.h"
#include "base/metrics/nacl_histogram.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/renderer_host/resource_message_filter.h"
+#include "chrome/browser/renderer_host/render_message_filter.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/logging_chrome.h"
#include "chrome/common/nacl_cmd_line.h"
@@ -74,10 +74,10 @@ NaClProcessHost::~NaClProcessHost() {
// OnProcessLaunched didn't get called because the process couldn't launch.
// Don't keep the renderer hanging.
reply_msg_->set_reply_error();
- resource_message_filter_->Send(reply_msg_);
+ render_message_filter_->Send(reply_msg_);
}
-bool NaClProcessHost::Launch(ResourceMessageFilter* resource_message_filter,
+bool NaClProcessHost::Launch(RenderMessageFilter* render_message_filter,
int socket_count,
IPC::Message* reply_msg) {
#ifdef DISABLE_NACL
@@ -116,7 +116,7 @@ bool NaClProcessHost::Launch(ResourceMessageFilter* resource_message_filter,
return false;
}
UmaNaclHistogramEnumeration(NACL_STARTED);
- resource_message_filter_ = resource_message_filter;
+ render_message_filter_ = render_message_filter;
reply_msg_ = reply_msg;
return true;
@@ -163,10 +163,11 @@ void NaClProcessHost::OnProcessLaunchedByBroker(base::ProcessHandle handle) {
OnProcessLaunched();
}
-bool NaClProcessHost::DidChildCrash() {
+base::TerminationStatus NaClProcessHost::GetChildTerminationStatus(
+ int* exit_code) {
if (running_on_wow64_)
- return base::DidProcessCrash(NULL, handle());
- return BrowserChildProcessHost::DidChildCrash();
+ return base::GetTerminationStatus(handle(), exit_code);
+ return BrowserChildProcessHost::GetChildTerminationStatus(exit_code);
}
void NaClProcessHost::OnChildDied() {
@@ -186,7 +187,7 @@ void NaClProcessHost::OnProcessLaunched() {
HANDLE handle_in_renderer;
DuplicateHandle(base::GetCurrentProcessHandle(),
reinterpret_cast<HANDLE>(sockets_for_renderer_[i]),
- resource_message_filter_->handle(),
+ render_message_filter_->peer_handle(),
&handle_in_renderer,
GENERIC_READ | GENERIC_WRITE,
FALSE,
@@ -207,7 +208,7 @@ void NaClProcessHost::OnProcessLaunched() {
// Copy the process handle into the renderer process.
DuplicateHandle(base::GetCurrentProcessHandle(),
handle(),
- resource_message_filter_->handle(),
+ render_message_filter_->peer_handle(),
&nacl_process_handle,
PROCESS_DUP_HANDLE,
FALSE,
@@ -222,8 +223,8 @@ void NaClProcessHost::OnProcessLaunched() {
ViewHostMsg_LaunchNaCl::WriteReplyParams(
reply_msg_, handles_for_renderer, nacl_process_handle, nacl_process_id);
- resource_message_filter_->Send(reply_msg_);
- resource_message_filter_ = NULL;
+ render_message_filter_->Send(reply_msg_);
+ render_message_filter_ = NULL;
reply_msg_ = NULL;
sockets_for_renderer_.clear();
@@ -281,14 +282,13 @@ void NaClProcessHost::SendStartMessage() {
sockets_for_sel_ldr_.clear();
}
-void NaClProcessHost::OnMessageReceived(const IPC::Message& msg) {
+bool NaClProcessHost::OnMessageReceived(const IPC::Message& msg) {
NOTREACHED() << "Invalid message with type = " << msg.type();
+ return false;
}
-URLRequestContext* NaClProcessHost::GetRequestContext(
- uint32 request_id,
- const ViewHostMsg_Resource_Request& request_data) {
- return NULL;
+bool NaClProcessHost::CanShutdown() {
+ return true;
}
#if defined(OS_WIN)
diff --git a/chrome/browser/nacl_host/nacl_process_host.h b/chrome/browser/nacl_host/nacl_process_host.h
index 618492a..c0d5731 100644
--- a/chrome/browser/nacl_host/nacl_process_host.h
+++ b/chrome/browser/nacl_host/nacl_process_host.h
@@ -13,7 +13,7 @@
#include "chrome/common/nacl_types.h"
#include "native_client/src/shared/imc/nacl_imc.h"
-class ResourceMessageFilter;
+class RenderMessageFilter;
// Represents the browser side of the browser <--> NaCl communication
// channel. There will be one NaClProcessHost per NaCl process
@@ -28,16 +28,16 @@ class NaClProcessHost : public BrowserChildProcessHost {
~NaClProcessHost();
// Initialize the new NaCl process, returning true on success.
- bool Launch(ResourceMessageFilter* resource_message_filter,
+ bool Launch(RenderMessageFilter* render_message_filter,
int socket_count,
IPC::Message* reply_msg);
- virtual void OnMessageReceived(const IPC::Message& msg);
+ virtual bool OnMessageReceived(const IPC::Message& msg);
void OnProcessLaunchedByBroker(base::ProcessHandle handle);
protected:
- virtual bool DidChildCrash();
+ virtual base::TerminationStatus GetChildTerminationStatus(int* exit_code);
virtual void OnChildDied();
private:
@@ -47,12 +47,7 @@ class NaClProcessHost : public BrowserChildProcessHost {
virtual void OnProcessLaunched();
- // ResourceDispatcherHost::Receiver implementation:
- virtual URLRequestContext* GetRequestContext(
- uint32 request_id,
- const ViewHostMsg_Resource_Request& request_data);
-
- virtual bool CanShutdown() { return true; }
+ virtual bool CanShutdown();
#if defined(OS_WIN)
// Check whether the browser process is running on WOW64 - Windows only
@@ -62,9 +57,9 @@ class NaClProcessHost : public BrowserChildProcessHost {
private:
ResourceDispatcherHost* resource_dispatcher_host_;
- // The ResourceMessageFilter that requested this NaCl process. We use this
+ // The RenderMessageFilter that requested this NaCl process. We use this
// for sending the reply once the process has started.
- scoped_refptr<ResourceMessageFilter> resource_message_filter_;
+ scoped_refptr<RenderMessageFilter> render_message_filter_;
// The reply message to send.
IPC::Message* reply_msg_;
diff --git a/chrome/browser/native_app_modal_dialog.h b/chrome/browser/native_app_modal_dialog.h
deleted file mode 100644
index 7b4c5b2..0000000
--- a/chrome/browser/native_app_modal_dialog.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_NATIVE_APP_MODAL_DIALOG_H_
-#define CHROME_BROWSER_NATIVE_APP_MODAL_DIALOG_H_
-#pragma once
-
-#include "gfx/native_widget_types.h"
-
-class JavaScriptAppModalDialog;
-
-class NativeAppModalDialog {
- public:
- // Returns the buttons to be shown. See MessageBoxFlags for a description of
- // the values.
- virtual int GetAppModalDialogButtons() const = 0;
-
- // Shows the dialog.
- virtual void ShowAppModalDialog() = 0;
-
- // Activates the dialog.
- virtual void ActivateAppModalDialog() = 0;
-
- // Closes the dialog.
- virtual void CloseAppModalDialog() = 0;
-
- // Accepts or cancels the dialog.
- virtual void AcceptAppModalDialog() = 0;
- virtual void CancelAppModalDialog() = 0;
-
- // Creates an app modal dialog for a JavaScript prompt.
- static NativeAppModalDialog* CreateNativeJavaScriptPrompt(
- JavaScriptAppModalDialog* dialog,
- gfx::NativeWindow parent_window);
-};
-
-#endif // CHROME_BROWSER_NATIVE_APP_MODAL_DIALOG_H_
-
diff --git a/chrome/browser/net/blob_url_request_job_factory.cc b/chrome/browser/net/blob_url_request_job_factory.cc
index d2e9bff..2aaebc7 100644
--- a/chrome/browser/net/blob_url_request_job_factory.cc
+++ b/chrome/browser/net/blob_url_request_job_factory.cc
@@ -15,8 +15,8 @@
namespace {
-URLRequestJob* BlobURLRequestJobFactory(URLRequest* request,
- const std::string& scheme) {
+net::URLRequestJob* BlobURLRequestJobFactory(net::URLRequest* request,
+ const std::string& scheme) {
scoped_refptr<webkit_blob::BlobData> data;
ResourceDispatcherHostRequestInfo* info =
ResourceDispatcherHost::InfoForRequest(request);
@@ -37,6 +37,6 @@ URLRequestJob* BlobURLRequestJobFactory(URLRequest* request,
}
void RegisterBlobURLRequestJobFactory() {
- URLRequest::RegisterProtocolFactory(chrome::kBlobScheme,
+ net::URLRequest::RegisterProtocolFactory(chrome::kBlobScheme,
&BlobURLRequestJobFactory);
}
diff --git a/chrome/browser/net/chrome_cookie_policy.cc b/chrome/browser/net/chrome_cookie_policy.cc
index c467954..88ff606 100644
--- a/chrome/browser/net/chrome_cookie_policy.cc
+++ b/chrome/browser/net/chrome_cookie_policy.cc
@@ -7,7 +7,7 @@
#include "base/string_util.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/host_content_settings_map.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "net/base/net_errors.h"
#include "net/base/static_cookie_policy.h"
diff --git a/chrome/browser/net/chrome_dns_cert_provenance_checker.cc b/chrome/browser/net/chrome_dns_cert_provenance_checker.cc
index e9bcf2f..fe0ca9d 100644
--- a/chrome/browser/net/chrome_dns_cert_provenance_checker.cc
+++ b/chrome/browser/net/chrome_dns_cert_provenance_checker.cc
@@ -48,7 +48,7 @@ class ChromeDnsCertProvenanceChecker :
const std::vector<std::string>& der_certs) {
const std::string report = BuildEncryptedReport(hostname, der_certs);
- URLRequest* url_request(new URLRequest(upload_url_, &delegate_));
+ net::URLRequest* url_request(new net::URLRequest(upload_url_, &delegate_));
url_request->set_context(url_req_context_);
url_request->set_method("POST");
url_request->AppendBytesToUpload(report.data(), report.size());
@@ -61,8 +61,8 @@ class ChromeDnsCertProvenanceChecker :
}
private:
- void RequestComplete(URLRequest* request) {
- std::set<URLRequest*>::iterator i = inflight_requests_.find(request);
+ void RequestComplete(net::URLRequest* request) {
+ std::set<net::URLRequest*>::iterator i = inflight_requests_.find(request);
DCHECK(i != inflight_requests_.end());
delete *i;
inflight_requests_.erase(i);
@@ -71,14 +71,14 @@ class ChromeDnsCertProvenanceChecker :
// URLRequestDelegate is the delegate for the upload. Since this is a
// fire-and-forget operation, we don't care if there are any errors in the
// upload.
- class URLRequestDelegate : public URLRequest::Delegate {
+ class URLRequestDelegate : public net::URLRequest::Delegate {
public:
explicit URLRequestDelegate(ChromeDnsCertProvenanceChecker* checker)
: checker_(checker) {
}
// Delegate implementation
- void OnResponseStarted(URLRequest* request) {
+ void OnResponseStarted(net::URLRequest* request) {
const URLRequestStatus& status(request->status());
if (!status.is_success()) {
LOG(WARNING) << "Certificate upload failed"
@@ -91,7 +91,7 @@ class ChromeDnsCertProvenanceChecker :
checker_->RequestComplete(request);
}
- void OnReadCompleted(URLRequest* request, int bytes_read) {
+ void OnReadCompleted(net::URLRequest* request, int bytes_read) {
NOTREACHED();
}
@@ -103,7 +103,7 @@ class ChromeDnsCertProvenanceChecker :
ChromeURLRequestContext* const url_req_context_;
const GURL upload_url_;
URLRequestDelegate delegate_;
- std::set<URLRequest*> inflight_requests_;
+ std::set<net::URLRequest*> inflight_requests_;
};
} // namespace
diff --git a/chrome/browser/net/chrome_net_log.cc b/chrome/browser/net/chrome_net_log.cc
index b6ef86e..6cfc893 100644
--- a/chrome/browser/net/chrome_net_log.cc
+++ b/chrome/browser/net/chrome_net_log.cc
@@ -9,27 +9,59 @@
#include "base/command_line.h"
#include "base/logging.h"
#include "base/string_util.h"
-#include "chrome/browser/browser_thread.h"
+#include "base/values.h"
#include "chrome/browser/net/load_timing_observer.h"
#include "chrome/browser/net/net_log_logger.h"
#include "chrome/browser/net/passive_log_collector.h"
#include "chrome/common/chrome_switches.h"
-ChromeNetLog::Observer::Observer(LogLevel log_level) : log_level_(log_level) {}
+ChromeNetLog::ThreadSafeObserver::ThreadSafeObserver(LogLevel log_level)
+ : net_log_(NULL),
+ log_level_(log_level) {
+}
+
+ChromeNetLog::ThreadSafeObserver::~ThreadSafeObserver() {
+ DCHECK(!net_log_);
+}
-net::NetLog::LogLevel ChromeNetLog::Observer::log_level() const {
+net::NetLog::LogLevel ChromeNetLog::ThreadSafeObserver::log_level() const {
return log_level_;
}
-void ChromeNetLog::Observer::set_log_level(net::NetLog::LogLevel log_level) {
+void ChromeNetLog::ThreadSafeObserver::AssertNetLogLockAcquired() const {
+ if (net_log_)
+ net_log_->lock_.AssertAcquired();
+}
+
+void ChromeNetLog::ThreadSafeObserver::SetLogLevel(
+ net::NetLog::LogLevel log_level) {
+ DCHECK(net_log_);
+ AutoLock lock(net_log_->lock_);
log_level_ = log_level;
+ net_log_->UpdateLogLevel_();
+}
+
+ChromeNetLog::Entry::Entry(uint32 order,
+ net::NetLog::EventType type,
+ const base::TimeTicks& time,
+ net::NetLog::Source source,
+ net::NetLog::EventPhase phase,
+ net::NetLog::EventParameters* params)
+ : order(order),
+ type(type),
+ time(time),
+ source(source),
+ phase(phase),
+ params(params) {
}
+ChromeNetLog::Entry::~Entry() {}
+
ChromeNetLog::ChromeNetLog()
- : next_id_(1),
+ : last_id_(0),
+ log_level_(LOG_BASIC),
passive_collector_(new PassiveLogCollector),
load_timing_observer_(new LoadTimingObserver) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
AddObserver(passive_collector_.get());
AddObserver(load_timing_observer_.get());
@@ -41,7 +73,6 @@ ChromeNetLog::ChromeNetLog()
}
ChromeNetLog::~ChromeNetLog() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
RemoveObserver(passive_collector_.get());
RemoveObserver(load_timing_observer_.get());
if (net_log_logger_.get()) {
@@ -54,42 +85,69 @@ void ChromeNetLog::AddEntry(EventType type,
const Source& source,
EventPhase phase,
EventParameters* params) {
- // This must be invoked when we're on the IO thread, or if the IO thread's
- // message loop isn't valid. The later can happen if this is invoked when the
- // IOThread is shuting down the MessageLoop.
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO) ||
- !BrowserThread::IsMessageLoopValid(BrowserThread::IO));
+ AutoLock lock(lock_);
// Notify all of the log observers.
- FOR_EACH_OBSERVER(Observer, observers_,
+ FOR_EACH_OBSERVER(ThreadSafeObserver, observers_,
OnAddEntry(type, time, source, phase, params));
}
uint32 ChromeNetLog::NextID() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- return next_id_++;
+ return base::subtle::NoBarrier_AtomicIncrement(&last_id_, 1);
}
net::NetLog::LogLevel ChromeNetLog::GetLogLevel() const {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ base::subtle::Atomic32 log_level = base::subtle::NoBarrier_Load(&log_level_);
+ return static_cast<net::NetLog::LogLevel>(log_level);
+}
+
+void ChromeNetLog::AddObserver(ThreadSafeObserver* observer) {
+ AutoLock lock(lock_);
+ AddObserverWhileLockHeld(observer);
+}
+
+void ChromeNetLog::RemoveObserver(ThreadSafeObserver* observer) {
+ AutoLock lock(lock_);
+ DCHECK_EQ(observer->net_log_, this);
+ observer->net_log_ = NULL;
+ observers_.RemoveObserver(observer);
+ UpdateLogLevel_();
+}
+
+void ChromeNetLog::AddObserverAndGetAllPassivelyCapturedEvents(
+ ThreadSafeObserver* observer, EntryList* passive_entries) {
+ AutoLock lock(lock_);
+ AddObserverWhileLockHeld(observer);
+ passive_collector_->GetAllCapturedEvents(passive_entries);
+}
+
+void ChromeNetLog::GetAllPassivelyCapturedEvents(EntryList* passive_entries) {
+ AutoLock lock(lock_);
+ passive_collector_->GetAllCapturedEvents(passive_entries);
+}
+
+void ChromeNetLog::ClearAllPassivelyCapturedEvents() {
+ AutoLock lock(lock_);
+ passive_collector_->Clear();
+}
+
+void ChromeNetLog::UpdateLogLevel_() {
+ lock_.AssertAcquired();
// Look through all the observers and find the finest granularity
// log level (higher values of the enum imply *lower* log levels).
- LogLevel log_level = LOG_BASIC;
- ObserverListBase<Observer>::Iterator it(observers_);
- Observer* observer;
+ LogLevel new_log_level = LOG_BASIC;
+ ObserverListBase<ThreadSafeObserver>::Iterator it(observers_);
+ ThreadSafeObserver* observer;
while ((observer = it.GetNext()) != NULL) {
- log_level = std::min(log_level, observer->log_level());
+ new_log_level = std::min(new_log_level, observer->log_level());
}
- return log_level;
+ base::subtle::NoBarrier_Store(&log_level_, new_log_level);
}
-void ChromeNetLog::AddObserver(Observer* observer) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+void ChromeNetLog::AddObserverWhileLockHeld(ThreadSafeObserver* observer) {
+ DCHECK(!observer->net_log_);
+ observer->net_log_ = this;
observers_.AddObserver(observer);
-}
-
-void ChromeNetLog::RemoveObserver(Observer* observer) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- observers_.RemoveObserver(observer);
+ UpdateLogLevel_();
}
diff --git a/chrome/browser/net/chrome_net_log.h b/chrome/browser/net/chrome_net_log.h
index aac09e6..12daee8 100644
--- a/chrome/browser/net/chrome_net_log.h
+++ b/chrome/browser/net/chrome_net_log.h
@@ -6,8 +6,13 @@
#define CHROME_BROWSER_NET_CHROME_NET_LOG_H_
#pragma once
+#include <vector>
+
+#include "base/atomicops.h"
+#include "base/lock.h"
#include "base/observer_list.h"
#include "base/scoped_ptr.h"
+#include "base/time.h"
#include "net/base/net_log.h"
class LoadTimingObserver;
@@ -17,39 +22,85 @@ class PassiveLogCollector;
// ChromeNetLog is an implementation of NetLog that dispatches network log
// messages to a list of observers.
//
+// All methods are thread safe, with the exception that no ChromeNetLog or
+// ChromeNetLog::ThreadSafeObserver functions may be called by an observer's
+// OnAddEntry() method. Doing so will result in a deadlock.
+//
// By default, ChromeNetLog will attach the observer PassiveLogCollector which
// will keep track of recent request information (which used when displaying
// the about:net-internals page).
//
-// TODO(eroman): Move this default observer out of ChromeNetLog.
-//
class ChromeNetLog : public net::NetLog {
public:
+ // This structure encapsulates all of the parameters of an event,
+ // including an "order" field that identifies when it was captured relative
+ // to other events.
+ struct Entry {
+ Entry(uint32 order,
+ net::NetLog::EventType type,
+ const base::TimeTicks& time,
+ net::NetLog::Source source,
+ net::NetLog::EventPhase phase,
+ net::NetLog::EventParameters* params);
+ ~Entry();
+
+ uint32 order;
+ net::NetLog::EventType type;
+ base::TimeTicks time;
+ net::NetLog::Source source;
+ net::NetLog::EventPhase phase;
+ scoped_refptr<net::NetLog::EventParameters> params;
+ };
+
+ typedef std::vector<Entry> EntryList;
+
// Interface for observing the events logged by the network stack.
- class Observer {
+ class ThreadSafeObserver {
public:
// Constructs an observer that wants to see network events, with
- // the specified minimum event granularity.
+ // the specified minimum event granularity. A ThreadSafeObserver can only
+ // observe a single ChromeNetLog at a time.
//
// Typical observers should specify LOG_BASIC.
//
// Observers that need to see the full granularity of events can
// specify LOG_ALL. However doing so will have performance consequences,
- // and may cause PassiveLogCollector to use more memory than anticiapted.
- explicit Observer(LogLevel log_level);
+ // and may cause PassiveLogCollector to use more memory than anticipated.
+ //
+ // Observers will be called on the same thread an entry is added on,
+ // and are responsible for ensuring their own thread safety.
+ explicit ThreadSafeObserver(LogLevel log_level);
+
+ virtual ~ThreadSafeObserver();
- virtual ~Observer() {}
+ // This method will be called on the thread that the event occurs on. It
+ // is the responsibility of the observer to handle it in a thread safe
+ // manner.
+ //
+ // It is illegal for an Observer to call any ChromeNetLog or
+ // ChromeNetLog::ThreadSafeObserver functions in response to a call to
+ // OnAddEntry.
virtual void OnAddEntry(EventType type,
const base::TimeTicks& time,
const Source& source,
EventPhase phase,
EventParameters* params) = 0;
LogLevel log_level() const;
+
protected:
- void set_log_level(LogLevel log_level);
+ void AssertNetLogLockAcquired() const;
+
+ // Can only be called when actively observing a ChromeNetLog.
+ void SetLogLevel(LogLevel log_level);
+
+ // ChromeNetLog currently being observed, if any. Set by ChromeNetLog's
+ // AddObserver and RemoveObserver methods.
+ ChromeNetLog* net_log_;
+
private:
+ friend class ChromeNetLog;
LogLevel log_level_;
- DISALLOW_COPY_AND_ASSIGN(Observer);
+ DISALLOW_COPY_AND_ASSIGN(ThreadSafeObserver);
};
ChromeNetLog();
@@ -64,26 +115,48 @@ class ChromeNetLog : public net::NetLog {
virtual uint32 NextID();
virtual LogLevel GetLogLevel() const;
- void AddObserver(Observer* observer);
- void RemoveObserver(Observer* observer);
+ void AddObserver(ThreadSafeObserver* observer);
+ void RemoveObserver(ThreadSafeObserver* observer);
- PassiveLogCollector* passive_collector() {
- return passive_collector_.get();
- }
+ // Adds |observer| and writes all passively captured events to
+ // |passive_entries|. Guarantees that no events in |passive_entries| will be
+ // sent to |observer| and all future events that have yet been sent to the
+ // PassiveLogCollector will be sent to |observer|.
+ void AddObserverAndGetAllPassivelyCapturedEvents(ThreadSafeObserver* observer,
+ EntryList* passive_entries);
+
+ void GetAllPassivelyCapturedEvents(EntryList* passive_entries);
+
+ void ClearAllPassivelyCapturedEvents();
LoadTimingObserver* load_timing_observer() {
return load_timing_observer_.get();
}
private:
- uint32 next_id_;
+ void AddObserverWhileLockHeld(ThreadSafeObserver* observer);
+
+ // Called whenever an observer is added or removed, or changes its log level.
+ // Must have acquired |lock_| prior to calling.
+ void UpdateLogLevel_();
+
+ // |lock_| protects access to |observers_| and, indirectly, to
+ // |passive_collector_|. Should not be acquired by observers.
+ Lock lock_;
+
+ // Last assigned source ID. Incremented to get the next one.
+ base::subtle::Atomic32 last_id_;
+
+ base::subtle::Atomic32 log_level_;
+
+ // Not thread safe. Must only be used when |lock_| is acquired.
scoped_ptr<PassiveLogCollector> passive_collector_;
+
scoped_ptr<LoadTimingObserver> load_timing_observer_;
scoped_ptr<NetLogLogger> net_log_logger_;
- // Note that this needs to be "mutable" so we can iterate over the observer
- // list in GetLogLevel().
- mutable ObserverList<Observer, true> observers_;
+ // |lock_| must be acquired whenever reading or writing to this.
+ ObserverList<ThreadSafeObserver, true> observers_;
DISALLOW_COPY_AND_ASSIGN(ChromeNetLog);
};
diff --git a/chrome/browser/net/chrome_net_log_unittest.cc b/chrome/browser/net/chrome_net_log_unittest.cc
new file mode 100644
index 0000000..7bd9301
--- /dev/null
+++ b/chrome/browser/net/chrome_net_log_unittest.cc
@@ -0,0 +1,73 @@
+// 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.
+
+#include "chrome/browser/net/chrome_net_log.h"
+
+#include "base/waitable_event.h"
+#include "base/simple_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const int kThreads = 10;
+const int kEvents = 100;
+
+class ChromeNetLogTestThread : public base::SimpleThread {
+ public:
+ ChromeNetLogTestThread() : base::SimpleThread("ChromeNetLogTest"),
+ can_start_loop_(false, false),
+ log_(NULL) {
+ }
+
+ void Init(ChromeNetLog* log) {
+ log_ = log;
+ }
+
+ virtual void Run() {
+ can_start_loop_.Wait();
+ for (int i = 0; i < kEvents; ++i) {
+ net::NetLog::Source source(net::NetLog::SOURCE_SOCKET, log_->NextID());
+ log_->AddEntry(net::NetLog::TYPE_SOCKET_ALIVE, base::TimeTicks(),
+ source, net::NetLog::PHASE_BEGIN, NULL);
+ }
+ log_->ClearAllPassivelyCapturedEvents();
+ }
+
+ void ReallyStart() {
+ can_start_loop_.Signal();
+ }
+
+ private:
+ // Only triggered once all threads have been created, to make it much less
+ // likely each thread completes before the next one starts.
+ base::WaitableEvent can_start_loop_;
+
+ ChromeNetLog* log_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChromeNetLogTestThread);
+};
+
+} // namespace
+
+// Attempts to check thread safety, exercising checks in ChromeNetLog and
+// PassiveLogCollector.
+TEST(ChromeNetLogTest, NetLogThreads) {
+ ChromeNetLog log;
+ ChromeNetLogTestThread threads[kThreads];
+
+ for (int i = 0; i < kThreads; ++i) {
+ threads[i].Init(&log);
+ threads[i].Start();
+ }
+
+ for (int i = 0; i < kThreads; ++i)
+ threads[i].ReallyStart();
+
+ for (int i = 0; i < kThreads; ++i)
+ threads[i].Join();
+
+ ChromeNetLog::EntryList entries;
+ log.GetAllPassivelyCapturedEvents(&entries);
+ EXPECT_EQ(0u, entries.size());
+}
diff --git a/chrome/browser/net/chrome_url_request_context.cc b/chrome/browser/net/chrome_url_request_context.cc
index f4ba1ca..d06d806 100644
--- a/chrome/browser/net/chrome_url_request_context.cc
+++ b/chrome/browser/net/chrome_url_request_context.cc
@@ -11,7 +11,7 @@
#include "base/string_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/user_script_master.h"
#include "chrome/browser/io_thread.h"
#include "chrome/browser/net/chrome_cookie_notification_details.h"
@@ -20,7 +20,7 @@
#include "chrome/browser/net/sqlite_persistent_cookie_store.h"
#include "chrome/browser/net/predictor_api.h"
#include "chrome/browser/net/pref_proxy_config_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
@@ -33,7 +33,7 @@
#include "net/http/http_network_layer.h"
#include "net/http/http_util.h"
#include "net/proxy/proxy_config_service_fixed.h"
-#include "net/proxy/proxy_script_fetcher.h"
+#include "net/proxy/proxy_script_fetcher_impl.h"
#include "net/proxy/proxy_service.h"
#include "net/url_request/url_request.h"
#include "webkit/glue/webkit_glue.h"
@@ -95,8 +95,7 @@ net::ProxyService* CreateProxyService(
net::NetLog* net_log,
URLRequestContext* context,
net::ProxyConfigService* proxy_config_service,
- const CommandLine& command_line,
- IOThread* io_thread) {
+ const CommandLine& command_line) {
CheckCurrentlyOnIOThread();
bool use_v8 = !command_line.HasSwitch(switches::kWinHttpProxyResolver);
@@ -127,7 +126,7 @@ net::ProxyService* CreateProxyService(
return net::ProxyService::CreateUsingV8ProxyResolver(
proxy_config_service,
num_pac_threads,
- io_thread->CreateAndRegisterProxyScriptFetcher(context),
+ new net::ProxyScriptFetcherImpl(context),
context->host_resolver(),
net_log);
}
@@ -262,6 +261,7 @@ ChromeURLRequestContext* FactoryForOriginal::Create() {
// Global host resolver for the context.
context->set_host_resolver(io_thread_globals->host_resolver.get());
+ context->set_cert_verifier(io_thread_globals->cert_verifier.get());
context->set_dnsrr_resolver(io_thread_globals->dnsrr_resolver.get());
context->set_http_auth_handler_factory(
io_thread_globals->http_auth_handler_factory.get());
@@ -273,24 +273,24 @@ ChromeURLRequestContext* FactoryForOriginal::Create() {
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
context->set_proxy_service(
- CreateProxyService(io_thread_globals->net_log.get(),
- context,
+ CreateProxyService(io_thread()->net_log(),
+ io_thread_globals->proxy_script_fetcher_context.get(),
proxy_config_service_.release(),
- command_line,
- io_thread()));
+ command_line));
net::HttpCache::DefaultBackend* backend = new net::HttpCache::DefaultBackend(
net::DISK_CACHE, disk_cache_path_, cache_size_,
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE));
net::HttpCache* cache =
new net::HttpCache(context->host_resolver(),
+ context->cert_verifier(),
context->dnsrr_resolver(),
context->dns_cert_checker(),
context->proxy_service(),
context->ssl_config_service(),
context->http_auth_handler_factory(),
&io_thread_globals->network_delegate,
- io_thread_globals->net_log.get(),
+ io_thread()->net_log(),
backend);
bool record_mode = chrome::kRecordModeEnabled &&
@@ -315,6 +315,7 @@ ChromeURLRequestContext* FactoryForOriginal::Create() {
scoped_refptr<SQLitePersistentCookieStore> cookie_db =
new SQLitePersistentCookieStore(cookie_store_path_);
+ cookie_db->SetClearLocalStateOnExit(clear_local_state_on_exit_);
context->set_cookie_store(new net::CookieMonster(cookie_db.get(),
cookie_monster_delegate_));
}
@@ -324,7 +325,7 @@ ChromeURLRequestContext* FactoryForOriginal::Create() {
appcache_service_->set_request_context(context);
- context->set_net_log(io_thread_globals->net_log.get());
+ context->set_net_log(io_thread()->net_log());
return context;
}
@@ -399,9 +400,10 @@ ChromeURLRequestContext* FactoryForOffTheRecord::Create() {
IOThread::Globals* io_thread_globals = io_thread()->globals();
- // Share the same proxy service, host resolver, and http_auth_handler_factory
- // as the original profile.
+ // Share the same proxy service, host resolver, cert verifier,
+ // and http_auth_handler_factory as the original profile.
context->set_host_resolver(original_context->host_resolver());
+ context->set_cert_verifier(original_context->cert_verifier());
context->set_proxy_service(original_context->proxy_service());
context->set_http_auth_handler_factory(
original_context->http_auth_handler_factory());
@@ -411,13 +413,14 @@ ChromeURLRequestContext* FactoryForOffTheRecord::Create() {
net::HttpCache* cache =
new net::HttpCache(context->host_resolver(),
+ context->cert_verifier(),
context->dnsrr_resolver(),
NULL /* dns_cert_checker */,
context->proxy_service(),
context->ssl_config_service(),
context->http_auth_handler_factory(),
&io_thread_globals->network_delegate,
- io_thread_globals->net_log.get(),
+ io_thread()->net_log(),
backend);
context->set_cookie_store(new net::CookieMonster(NULL,
cookie_monster_delegate_));
@@ -430,7 +433,7 @@ ChromeURLRequestContext* FactoryForOffTheRecord::Create() {
appcache_service_->set_request_context(context);
- context->set_net_log(io_thread_globals->net_log.get());
+ context->set_net_log(io_thread()->net_log());
return context;
}
@@ -504,18 +507,19 @@ ChromeURLRequestContext* FactoryForMedia::Create() {
// If original HttpCache doesn't exist, simply construct one with a whole
// new set of network stack.
cache = new net::HttpCache(main_context->host_resolver(),
+ main_context->cert_verifier(),
main_context->dnsrr_resolver(),
NULL /* dns_cert_checker */,
main_context->proxy_service(),
main_context->ssl_config_service(),
main_context->http_auth_handler_factory(),
&io_thread_globals->network_delegate,
- io_thread_globals->net_log.get(),
+ io_thread()->net_log(),
backend);
}
context->set_http_transaction_factory(cache);
- context->set_net_log(io_thread_globals->net_log.get());
+ context->set_net_log(io_thread()->net_log());
return context;
}
@@ -696,6 +700,15 @@ void ChromeURLRequestContextGetter::Observe(
this,
&ChromeURLRequestContextGetter::OnDefaultCharsetChange,
default_charset));
+ } else if (*pref_name_in == prefs::kClearSiteDataOnExit) {
+ bool clear_site_data =
+ prefs->GetBoolean(prefs::kClearSiteDataOnExit);
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &ChromeURLRequestContextGetter::OnClearSiteDataOnExitChange,
+ clear_site_data));
}
} else {
NOTREACHED();
@@ -708,6 +721,7 @@ void ChromeURLRequestContextGetter::RegisterPrefsObserver(Profile* profile) {
registrar_.Init(profile->GetPrefs());
registrar_.Add(prefs::kAcceptLanguages, this);
registrar_.Add(prefs::kDefaultCharset, this);
+ registrar_.Add(prefs::kClearSiteDataOnExit, this);
}
// static
@@ -733,6 +747,12 @@ void ChromeURLRequestContextGetter::OnDefaultCharsetChange(
GetIOContext()->OnDefaultCharsetChange(default_charset);
}
+void ChromeURLRequestContextGetter::OnClearSiteDataOnExitChange(
+ bool clear_site_data) {
+ GetCookieStore()->GetCookieMonster()->
+ SetClearPersistentStoreOnExit(clear_site_data);
+}
+
void ChromeURLRequestContextGetter::GetCookieStoreAsyncHelper(
base::WaitableEvent* completion,
net::CookieStore** result) {
@@ -798,45 +818,6 @@ bool ChromeURLRequestContext::IsExternal() const {
return false;
}
-ChromeURLRequestContext::ChromeURLRequestContext(
- ChromeURLRequestContext* other) {
- CheckCurrentlyOnIOThread();
-
- // Set URLRequestContext members
- net_log_ = other->net_log_;
- host_resolver_ = other->host_resolver_;
- proxy_service_ = other->proxy_service_;
- ssl_config_service_ = other->ssl_config_service_;
- http_transaction_factory_ = other->http_transaction_factory_;
- ftp_transaction_factory_ = other->ftp_transaction_factory_;
- cookie_store_ = other->cookie_store_;
- cookie_policy_ = other->cookie_policy_;
- transport_security_state_ = other->transport_security_state_;
- accept_language_ = other->accept_language_;
- accept_charset_ = other->accept_charset_;
- referrer_charset_ = other->referrer_charset_;
- // NOTE(cbentzel): Sharing the http_auth_handler_factory_ is potentially
- // dangerous because it is a raw pointer. However, the current implementation
- // creates and destroys the pointed-to-object in the io_thread and it is
- // valid for the lifetime of all ChromeURLRequestContext objects.
- // If this is no longer the case, HttpAuthHandlerFactory will need to be
- // ref-counted or cloneable.
- http_auth_handler_factory_ = other->http_auth_handler_factory_;
-
- // Set ChromeURLRequestContext members
- user_script_dir_path_ = other->user_script_dir_path_;
- appcache_service_ = other->appcache_service_;
- database_tracker_ = other->database_tracker_;
- chrome_cookie_policy_ = other->chrome_cookie_policy_;
- host_content_settings_map_ = other->host_content_settings_map_;
- host_zoom_map_ = other->host_zoom_map_;
- is_media_ = other->is_media_;
- is_off_the_record_ = other->is_off_the_record_;
- blob_storage_context_ = other->blob_storage_context_;
- browser_file_system_context_ = other->browser_file_system_context_;
- extension_info_map_ = other->extension_info_map_;
-}
-
void ChromeURLRequestContext::OnAcceptLanguageChange(
const std::string& accept_language) {
CheckCurrentlyOnIOThread();
@@ -873,6 +854,7 @@ ChromeURLRequestContextFactory::ChromeURLRequestContextFactory(Profile* profile)
std::string default_charset = prefs->GetString(prefs::kDefaultCharset);
accept_charset_ =
net::HttpUtil::GenerateAcceptCharsetHeader(default_charset);
+ clear_local_state_on_exit_ = prefs->GetBoolean(prefs::kClearSiteDataOnExit);
// At this point, we don't know the charset of the referring page
// where a url request originates from. This is used to get a suggested
@@ -901,7 +883,7 @@ ChromeURLRequestContextFactory::ChromeURLRequestContextFactory(Profile* profile)
appcache_service_ = profile->GetAppCacheService();
database_tracker_ = profile->GetDatabaseTracker();
blob_storage_context_ = profile->GetBlobStorageContext();
- browser_file_system_context_ = profile->GetFileSystemContext();
+ file_system_context_ = profile->GetFileSystemContext();
extension_info_map_ = profile->GetExtensionInfoMap();
}
@@ -927,6 +909,6 @@ void ChromeURLRequestContextFactory::ApplyProfileParametersToContext(
context->set_appcache_service(appcache_service_);
context->set_database_tracker(database_tracker_);
context->set_blob_storage_context(blob_storage_context_);
- context->set_browser_file_system_context(browser_file_system_context_);
+ context->set_file_system_context(file_system_context_);
context->set_extension_info_map(extension_info_map_);
}
diff --git a/chrome/browser/net/chrome_url_request_context.h b/chrome/browser/net/chrome_url_request_context.h
index e4e8ad8..8d1377b 100644
--- a/chrome/browser/net/chrome_url_request_context.h
+++ b/chrome/browser/net/chrome_url_request_context.h
@@ -12,9 +12,8 @@
#include "base/file_path.h"
#include "chrome/browser/appcache/chrome_appcache_service.h"
#include "chrome/browser/chrome_blob_storage_context.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/extensions/extension_info_map.h"
-#include "chrome/browser/file_system/browser_file_system_context.h"
-#include "chrome/browser/host_content_settings_map.h"
#include "chrome/browser/host_zoom_map.h"
#include "chrome/browser/io_thread.h"
#include "chrome/browser/net/chrome_cookie_policy.h"
@@ -27,6 +26,7 @@
#include "net/base/cookie_policy.h"
#include "net/url_request/url_request_context.h"
#include "webkit/database/database_tracker.h"
+#include "webkit/fileapi/sandboxed_file_system_context.h"
class CommandLine;
class PrefService;
@@ -35,7 +35,6 @@ class Profile;
namespace net {
class DnsCertProvenanceChecker;
class NetworkDelegate;
-class ProxyConfig;
}
class ChromeURLRequestContext;
@@ -72,8 +71,8 @@ class ChromeURLRequestContext : public URLRequestContext {
}
// Gets the file system host context with this context's profile.
- BrowserFileSystemContext* browser_file_system_context() const {
- return browser_file_system_context_.get();
+ fileapi::SandboxedFileSystemContext* file_system_context() const {
+ return file_system_context_.get();
}
bool is_off_the_record() const {
@@ -100,10 +99,6 @@ class ChromeURLRequestContext : public URLRequestContext {
virtual bool IsExternal() const;
protected:
- // Copies the dependencies from |other| into |this|. If you use this
- // constructor, then you should hold a reference to |other|, as we
- // depend on |other| being alive.
- explicit ChromeURLRequestContext(ChromeURLRequestContext* other);
virtual ~ChromeURLRequestContext();
public:
@@ -125,34 +120,16 @@ class ChromeURLRequestContext : public URLRequestContext {
void set_ssl_config_service(net::SSLConfigService* service) {
ssl_config_service_ = service;
}
- void set_host_resolver(net::HostResolver* resolver) {
- host_resolver_ = resolver;
- }
- void set_dnsrr_resolver(net::DnsRRResolver* dnsrr_resolver) {
- dnsrr_resolver_ = dnsrr_resolver;
- }
void set_dns_cert_checker(net::DnsCertProvenanceChecker* ctx) {
dns_cert_checker_.reset(ctx);
}
- void set_http_transaction_factory(net::HttpTransactionFactory* factory) {
- http_transaction_factory_ = factory;
- }
void set_ftp_transaction_factory(net::FtpTransactionFactory* factory) {
ftp_transaction_factory_ = factory;
}
- void set_http_auth_handler_factory(net::HttpAuthHandlerFactory* factory) {
- http_auth_handler_factory_ = factory;
- }
- void set_cookie_store(net::CookieStore* cookie_store) {
- cookie_store_ = cookie_store;
- }
void set_cookie_policy(ChromeCookiePolicy* cookie_policy) {
chrome_cookie_policy_ = cookie_policy; // Take a strong reference.
cookie_policy_ = cookie_policy;
}
- void set_proxy_service(net::ProxyService* service) {
- proxy_service_ = service;
- }
void set_user_script_dir_path(const FilePath& path) {
user_script_dir_path_ = path;
}
@@ -178,15 +155,12 @@ class ChromeURLRequestContext : public URLRequestContext {
void set_blob_storage_context(ChromeBlobStorageContext* context) {
blob_storage_context_ = context;
}
- void set_browser_file_system_context(BrowserFileSystemContext* context) {
- browser_file_system_context_ = context;
+ void set_file_system_context(fileapi::SandboxedFileSystemContext* context) {
+ file_system_context_ = context;
}
void set_extension_info_map(ExtensionInfoMap* map) {
extension_info_map_ = map;
}
- void set_net_log(net::NetLog* net_log) {
- net_log_ = net_log;
- }
void set_network_delegate(
net::HttpNetworkDelegate* network_delegate) {
network_delegate_ = network_delegate;
@@ -208,7 +182,7 @@ class ChromeURLRequestContext : public URLRequestContext {
scoped_refptr<HostContentSettingsMap> host_content_settings_map_;
scoped_refptr<HostZoomMap> host_zoom_map_;
scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;
- scoped_refptr<BrowserFileSystemContext> browser_file_system_context_;
+ scoped_refptr<fileapi::SandboxedFileSystemContext> file_system_context_;
scoped_refptr<ExtensionInfoMap> extension_info_map_;
bool is_media_;
@@ -308,6 +282,7 @@ class ChromeURLRequestContextGetter : public URLRequestContextGetter,
// ChromeURLRequestContext.
void OnAcceptLanguageChange(const std::string& accept_language);
void OnDefaultCharsetChange(const std::string& default_charset);
+ void OnClearSiteDataOnExitChange(bool clear_site_data);
// Saves the cookie store to |result| and signals |completion|.
void GetCookieStoreAsyncHelper(base::WaitableEvent* completion,
@@ -360,6 +335,7 @@ class ChromeURLRequestContextFactory {
// ApplyProfileParametersToContext().
bool is_media_;
bool is_off_the_record_;
+ bool clear_local_state_on_exit_;
std::string accept_language_;
std::string accept_charset_;
std::string referrer_charset_;
@@ -375,7 +351,7 @@ class ChromeURLRequestContextFactory {
scoped_refptr<net::SSLConfigService> ssl_config_service_;
scoped_refptr<net::CookieMonster::Delegate> cookie_monster_delegate_;
scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;
- scoped_refptr<BrowserFileSystemContext> browser_file_system_context_;
+ scoped_refptr<fileapi::SandboxedFileSystemContext> file_system_context_;
scoped_refptr<ExtensionInfoMap> extension_info_map_;
FilePath profile_dir_path_;
diff --git a/chrome/browser/net/connect_interceptor.cc b/chrome/browser/net/connect_interceptor.cc
index 893039b..3809da2 100644
--- a/chrome/browser/net/connect_interceptor.cc
+++ b/chrome/browser/net/connect_interceptor.cc
@@ -10,11 +10,11 @@
namespace chrome_browser_net {
ConnectInterceptor::ConnectInterceptor() {
- URLRequest::RegisterRequestInterceptor(this);
+ net::URLRequest::RegisterRequestInterceptor(this);
}
ConnectInterceptor::~ConnectInterceptor() {
- URLRequest::UnregisterRequestInterceptor(this);
+ net::URLRequest::UnregisterRequestInterceptor(this);
}
net::URLRequestJob* ConnectInterceptor::MaybeIntercept(
diff --git a/chrome/browser/net/connect_interceptor.h b/chrome/browser/net/connect_interceptor.h
index ee4422b..b0b15f1 100644
--- a/chrome/browser/net/connect_interceptor.h
+++ b/chrome/browser/net/connect_interceptor.h
@@ -13,7 +13,7 @@ namespace chrome_browser_net {
//------------------------------------------------------------------------------
// An interceptor to monitor URLRequests so that we can do speculative DNS
// resolution and/or speculative TCP preconnections.
-class ConnectInterceptor : public URLRequest::Interceptor {
+class ConnectInterceptor : public net::URLRequest::Interceptor {
public:
// Construction includes registration as an URL.
ConnectInterceptor();
@@ -21,7 +21,7 @@ class ConnectInterceptor : public URLRequest::Interceptor {
virtual ~ConnectInterceptor();
protected:
- // URLRequest::Interceptor overrides
+ // Overridden from net::URLRequest::Interceptor:
// Learn about referrers, and optionally preconnect based on history.
virtual net::URLRequestJob* MaybeIntercept(net::URLRequest* request);
virtual net::URLRequestJob* MaybeInterceptResponse(net::URLRequest* request);
diff --git a/chrome/browser/net/connection_tester.cc b/chrome/browser/net/connection_tester.cc
index 35a9a71..588cf57 100644
--- a/chrome/browser/net/connection_tester.cc
+++ b/chrome/browser/net/connection_tester.cc
@@ -8,10 +8,11 @@
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/message_loop.h"
+#include "base/thread_restrictions.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/importer/firefox_proxy_settings.h"
-#include "chrome/browser/io_thread.h"
#include "chrome/common/chrome_switches.h"
+#include "net/base/cert_verifier.h"
#include "net/base/cookie_monster.h"
#include "net/base/dnsrr_resolver.h"
#include "net/base/host_resolver.h"
@@ -26,6 +27,7 @@
#include "net/http/http_cache.h"
#include "net/http/http_network_layer.h"
#include "net/proxy/proxy_config_service_fixed.h"
+#include "net/proxy/proxy_script_fetcher_impl.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
@@ -38,8 +40,8 @@ namespace {
// to the specified "experiment".
class ExperimentURLRequestContext : public URLRequestContext {
public:
- explicit ExperimentURLRequestContext(IOThread* io_thread)
- : io_thread_(io_thread) {}
+ explicit ExperimentURLRequestContext(URLRequestContext* proxy_request_context)
+ : proxy_request_context_(proxy_request_context) {}
int Init(const ConnectionTester::Experiment& experiment) {
int rv;
@@ -58,14 +60,15 @@ class ExperimentURLRequestContext : public URLRequestContext {
// The rest of the dependencies are standard, and don't depend on the
// experiment being run.
+ cert_verifier_ = new net::CertVerifier;
dnsrr_resolver_ = new net::DnsRRResolver;
ftp_transaction_factory_ = new net::FtpNetworkLayer(host_resolver_);
ssl_config_service_ = new net::SSLConfigServiceDefaults;
http_auth_handler_factory_ = net::HttpAuthHandlerFactory::CreateDefault(
host_resolver_);
http_transaction_factory_ = new net::HttpCache(
- net::HttpNetworkLayer::CreateFactory(host_resolver_, dnsrr_resolver_,
- NULL /* dns_cert_checker */,
+ net::HttpNetworkLayer::CreateFactory(host_resolver_, cert_verifier_,
+ dnsrr_resolver_, NULL /* dns_cert_checker */,
NULL /* ssl_host_info_factory */, proxy_service_,
ssl_config_service_, http_auth_handler_factory_, NULL, NULL),
net::HttpCache::DefaultBackend::InMemory(0));
@@ -81,6 +84,7 @@ class ExperimentURLRequestContext : public URLRequestContext {
delete http_transaction_factory_;
delete http_auth_handler_factory_;
delete dnsrr_resolver_;
+ delete cert_verifier_;
delete host_resolver_;
}
@@ -126,10 +130,14 @@ class ExperimentURLRequestContext : public URLRequestContext {
int CreateProxyConfigService(
ConnectionTester::ProxySettingsExperiment experiment,
scoped_ptr<net::ProxyConfigService>* config_service) {
+ scoped_ptr<base::ThreadRestrictions::ScopedAllowIO> allow_io;
switch (experiment) {
case ConnectionTester::PROXY_EXPERIMENT_USE_SYSTEM_SETTINGS:
return CreateSystemProxyConfigService(config_service);
case ConnectionTester::PROXY_EXPERIMENT_USE_FIREFOX_SETTINGS:
+ // http://crbug.com/67664: This call can lead to blocking IO on the IO
+ // thread. This is a bug and should be fixed.
+ allow_io.reset(new base::ThreadRestrictions::ScopedAllowIO);
return CreateFirefoxProxyConfigService(config_service);
case ConnectionTester::PROXY_EXPERIMENT_USE_AUTO_DETECT:
config_service->reset(new net::ProxyConfigServiceFixed(
@@ -167,7 +175,7 @@ class ExperimentURLRequestContext : public URLRequestContext {
*proxy_service = net::ProxyService::CreateUsingV8ProxyResolver(
config_service.release(),
0u,
- io_thread_->CreateAndRegisterProxyScriptFetcher(this),
+ new net::ProxyScriptFetcherImpl(proxy_request_context_),
host_resolver(),
NULL);
@@ -214,7 +222,7 @@ class ExperimentURLRequestContext : public URLRequestContext {
return net::ERR_FAILED;
}
- IOThread* io_thread_;
+ const scoped_refptr<URLRequestContext> proxy_request_context_;
};
} // namespace
@@ -223,7 +231,7 @@ class ExperimentURLRequestContext : public URLRequestContext {
// TestRunner is a helper class for running an individual experiment. It can
// be deleted any time after it is started, and this will abort the request.
-class ConnectionTester::TestRunner : public URLRequest::Delegate {
+class ConnectionTester::TestRunner : public net::URLRequest::Delegate {
public:
// |tester| must remain alive throughout the TestRunner's lifetime.
// |tester| will be notified of completion.
@@ -233,9 +241,9 @@ class ConnectionTester::TestRunner : public URLRequest::Delegate {
// it is done.
void Run(const Experiment& experiment);
- // URLRequest::Delegate implementation.
- virtual void OnResponseStarted(URLRequest* request);
- virtual void OnReadCompleted(URLRequest* request, int bytes_read);
+ // Overridden from net::URLRequest::Delegate:
+ virtual void OnResponseStarted(net::URLRequest* request);
+ virtual void OnReadCompleted(net::URLRequest* request, int bytes_read);
// TODO(eroman): handle cases requiring authentication.
private:
@@ -244,18 +252,18 @@ class ConnectionTester::TestRunner : public URLRequest::Delegate {
// Starts reading the response's body (and keeps reading until an error or
// end of stream).
- void ReadBody(URLRequest* request);
+ void ReadBody(net::URLRequest* request);
// Called when the request has completed (for both success and failure).
- void OnResponseCompleted(URLRequest* request);
+ void OnResponseCompleted(net::URLRequest* request);
ConnectionTester* tester_;
- scoped_ptr<URLRequest> request_;
+ scoped_ptr<net::URLRequest> request_;
DISALLOW_COPY_AND_ASSIGN(TestRunner);
};
-void ConnectionTester::TestRunner::OnResponseStarted(URLRequest* request) {
+void ConnectionTester::TestRunner::OnResponseStarted(net::URLRequest* request) {
if (!request->status().is_success()) {
OnResponseCompleted(request);
return;
@@ -265,7 +273,7 @@ void ConnectionTester::TestRunner::OnResponseStarted(URLRequest* request) {
ReadBody(request);
}
-void ConnectionTester::TestRunner::OnReadCompleted(URLRequest* request,
+void ConnectionTester::TestRunner::OnReadCompleted(net::URLRequest* request,
int bytes_read) {
if (bytes_read <= 0) {
OnResponseCompleted(request);
@@ -276,7 +284,7 @@ void ConnectionTester::TestRunner::OnReadCompleted(URLRequest* request,
ReadBody(request);
}
-void ConnectionTester::TestRunner::ReadBody(URLRequest* request) {
+void ConnectionTester::TestRunner::ReadBody(net::URLRequest* request) {
// Read the response body |kReadBufferSize| bytes at a time.
scoped_refptr<net::IOBuffer> unused_buffer(
new net::IOBuffer(kReadBufferSize));
@@ -289,7 +297,8 @@ void ConnectionTester::TestRunner::ReadBody(URLRequest* request) {
}
}
-void ConnectionTester::TestRunner::OnResponseCompleted(URLRequest* request) {
+void ConnectionTester::TestRunner::OnResponseCompleted(
+ net::URLRequest* request) {
int result = net::OK;
if (!request->status().is_success()) {
DCHECK_NE(net::ERR_IO_PENDING, request->status().os_error());
@@ -301,7 +310,7 @@ void ConnectionTester::TestRunner::OnResponseCompleted(URLRequest* request) {
void ConnectionTester::TestRunner::Run(const Experiment& experiment) {
// Try to create a URLRequestContext for this experiment.
scoped_refptr<ExperimentURLRequestContext> context(
- new ExperimentURLRequestContext(tester_->io_thread_));
+ new ExperimentURLRequestContext(tester_->proxy_request_context_));
int rv = context->Init(experiment);
if (rv != net::OK) {
// Complete the experiment with a failure.
@@ -310,17 +319,18 @@ void ConnectionTester::TestRunner::Run(const Experiment& experiment) {
}
// Fetch a request using the experimental context.
- request_.reset(new URLRequest(experiment.url, this));
+ request_.reset(new net::URLRequest(experiment.url, this));
request_->set_context(context);
request_->Start();
}
// ConnectionTester ----------------------------------------------------------
-ConnectionTester::ConnectionTester(Delegate* delegate, IOThread* io_thread)
- : delegate_(delegate), io_thread_(io_thread) {
+ConnectionTester::ConnectionTester(Delegate* delegate,
+ URLRequestContext* proxy_request_context)
+ : delegate_(delegate), proxy_request_context_(proxy_request_context) {
DCHECK(delegate);
- DCHECK(io_thread);
+ DCHECK(proxy_request_context);
}
ConnectionTester::~ConnectionTester() {
diff --git a/chrome/browser/net/connection_tester.h b/chrome/browser/net/connection_tester.h
index e0a7446..1d206ac 100644
--- a/chrome/browser/net/connection_tester.h
+++ b/chrome/browser/net/connection_tester.h
@@ -13,7 +13,7 @@
#include "googleurl/src/gurl.h"
#include "net/base/completion_callback.h"
-class IOThread;
+class URLRequestContext;
// ConnectionTester runs a suite of tests (also called "experiments"),
// to try and discover why loading a particular URL is failing with an error
@@ -125,7 +125,8 @@ class ConnectionTester {
// Constructs a ConnectionTester that notifies test progress to |delegate|.
// |delegate| is owned by the caller, and must remain valid for the lifetime
// of ConnectionTester.
- ConnectionTester(Delegate* delegate, IOThread* io_thread);
+ ConnectionTester(Delegate* delegate,
+ URLRequestContext* proxy_request_context);
// Note that destruction cancels any in-progress tests.
~ConnectionTester();
@@ -171,10 +172,9 @@ class ConnectionTester {
// of the list is the one currently in progress.
ExperimentList remaining_experiments_;
- IOThread* io_thread_;
+ const scoped_refptr<URLRequestContext> proxy_request_context_;
DISALLOW_COPY_AND_ASSIGN(ConnectionTester);
};
#endif // CHROME_BROWSER_NET_CONNECTION_TESTER_H_
-
diff --git a/chrome/browser/net/connection_tester_unittest.cc b/chrome/browser/net/connection_tester_unittest.cc
index 5bab81e..6735599 100644
--- a/chrome/browser/net/connection_tester_unittest.cc
+++ b/chrome/browser/net/connection_tester_unittest.cc
@@ -4,10 +4,21 @@
#include "chrome/browser/net/connection_tester.h"
-#include "chrome/browser/io_thread.h"
+#include "chrome/browser/browser_thread.h"
#include "chrome/test/testing_pref_service.h"
+#include "net/base/cert_verifier.h"
+#include "net/base/cookie_monster.h"
+#include "net/base/dnsrr_resolver.h"
#include "net/base/mock_host_resolver.h"
+#include "net/base/ssl_config_service_defaults.h"
+#include "net/ftp/ftp_network_layer.h"
+#include "net/http/http_auth_handler_factory.h"
+#include "net/http/http_network_layer.h"
+#include "net/proxy/proxy_config_service_fixed.h"
+#include "net/socket/client_socket_factory.h"
+#include "net/spdy/spdy_session_pool.h"
#include "net/test/test_server.h"
+#include "net/url_request/url_request_context.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -76,30 +87,65 @@ class ConnectionTesterTest : public PlatformTest {
ConnectionTesterTest()
: test_server_(net::TestServer::TYPE_HTTP,
FilePath(FILE_PATH_LITERAL("net/data/url_request_unittest"))),
+ client_socket_factory_(net::ClientSocketFactory::GetDefaultFactory()),
+ proxy_script_fetcher_context_(new URLRequestContext),
message_loop_(MessageLoop::TYPE_IO),
- pref_service(new TestingPrefService()),
- io_thread_(pref_service.get()) {
- scoped_refptr<net::RuleBasedHostResolverProc> catchall_resolver(
- new net::RuleBasedHostResolverProc(NULL));
-
- catchall_resolver->AddRule("*", "127.0.0.1");
-
- scoped_host_resolver_proc_.Init(catchall_resolver);
+ io_thread_(BrowserThread::IO, &message_loop_) {
+ InitializeRequestContext();
}
protected:
- net::ScopedDefaultHostResolverProc scoped_host_resolver_proc_;
net::TestServer test_server_;
ConnectionTesterDelegate test_delegate_;
+ net::ClientSocketFactory* const client_socket_factory_;
+ net::MockHostResolver host_resolver_;
+ net::CertVerifier cert_verifier_;
+ net::DnsRRResolver dnsrr_resolver_;
+ scoped_refptr<net::ProxyService> proxy_service_;
+ scoped_refptr<net::SSLConfigService> ssl_config_service_;
+ scoped_ptr<net::HttpTransactionFactory> http_transaction_factory_;
+ net::HttpAuthHandlerRegistryFactory http_auth_handler_factory_;
+ scoped_refptr<URLRequestContext> proxy_script_fetcher_context_;
+
+ private:
+ void InitializeRequestContext() {
+ proxy_script_fetcher_context_->set_host_resolver(&host_resolver_);
+ proxy_script_fetcher_context_->set_cert_verifier(&cert_verifier_);
+ proxy_script_fetcher_context_->set_dnsrr_resolver(&dnsrr_resolver_);
+ proxy_script_fetcher_context_->set_http_auth_handler_factory(
+ &http_auth_handler_factory_);
+ proxy_service_ = net::ProxyService::CreateDirect();
+ proxy_script_fetcher_context_->set_proxy_service(proxy_service_);
+ ssl_config_service_ = net::SSLConfigService::CreateSystemSSLConfigService();
+ http_transaction_factory_.reset(
+ new net::HttpNetworkLayer(
+ client_socket_factory_,
+ &host_resolver_,
+ &cert_verifier_,
+ &dnsrr_resolver_,
+ NULL /* DNS cert provenance checker */,
+ NULL /* ssl_host_info_factory */,
+ proxy_service_.get(),
+ ssl_config_service_,
+ new net::SpdySessionPool(ssl_config_service_),
+ &http_auth_handler_factory_,
+ NULL /* NetworkDelegate */,
+ NULL /* NetLog */));
+ proxy_script_fetcher_context_->set_http_transaction_factory(
+ http_transaction_factory_.get());
+ // In-memory cookie store.
+ proxy_script_fetcher_context_->set_cookie_store(
+ new net::CookieMonster(NULL, NULL));
+ }
+
MessageLoop message_loop_;
- scoped_ptr<PrefService> pref_service;
- IOThread io_thread_; // Needed for creating ProxyScriptFetchers.
+ BrowserThread io_thread_;
};
TEST_F(ConnectionTesterTest, RunAllTests) {
ASSERT_TRUE(test_server_.Start());
- ConnectionTester tester(&test_delegate_, &io_thread_);
+ ConnectionTester tester(&test_delegate_, proxy_script_fetcher_context_);
// Start the test suite on URL "echoall".
// TODO(eroman): Is this URL right?
@@ -124,7 +170,7 @@ TEST_F(ConnectionTesterTest, DeleteWhileInProgress) {
ASSERT_TRUE(test_server_.Start());
scoped_ptr<ConnectionTester> tester(
- new ConnectionTester(&test_delegate_, &io_thread_));
+ new ConnectionTester(&test_delegate_, proxy_script_fetcher_context_));
// Start the test suite on URL "echoall".
// TODO(eroman): Is this URL right?
@@ -153,4 +199,3 @@ TEST_F(ConnectionTesterTest, DeleteWhileInProgress) {
}
} // namespace
-
diff --git a/chrome/browser/net/cookie_policy_browsertest.cc b/chrome/browser/net/cookie_policy_browsertest.cc
index 414b8aa..fef104d 100644
--- a/chrome/browser/net/cookie_policy_browsertest.cc
+++ b/chrome/browser/net/cookie_policy_browsertest.cc
@@ -4,8 +4,8 @@
#include "base/task.h"
#include "base/waitable_event.h"
-#include "chrome/browser/host_content_settings_map.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/net/url_request_context_getter.h"
#include "chrome/test/in_process_browser_test.h"
diff --git a/chrome/browser/net/gaia/token_service.cc b/chrome/browser/net/gaia/token_service.cc
index b79a6f4..8f533e7 100644
--- a/chrome/browser/net/gaia/token_service.cc
+++ b/chrome/browser/net/gaia/token_service.cc
@@ -7,7 +7,7 @@
#include "base/command_line.h"
#include "base/string_util.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/net/gaia/gaia_auth_fetcher.h"
#include "chrome/common/net/gaia/gaia_constants.h"
diff --git a/chrome/browser/net/gaia/token_service_unittest.h b/chrome/browser/net/gaia/token_service_unittest.h
index 674baf0..46cffb0 100644
--- a/chrome/browser/net/gaia/token_service_unittest.h
+++ b/chrome/browser/net/gaia/token_service_unittest.h
@@ -12,6 +12,8 @@
#include "chrome/browser/password_manager/encryptor.h"
#include "chrome/browser/webdata/web_data_service.h"
#include "chrome/common/net/gaia/gaia_auth_consumer.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
#include "chrome/test/signaling_task.h"
#include "chrome/test/test_notification_tracker.h"
#include "chrome/test/testing_profile.h"
diff --git a/chrome/browser/net/load_timing_observer.cc b/chrome/browser/net/load_timing_observer.cc
index 62e8b04..ea22ccc 100644
--- a/chrome/browser/net/load_timing_observer.cc
+++ b/chrome/browser/net/load_timing_observer.cc
@@ -4,8 +4,8 @@
#include "chrome/browser/net/load_timing_observer.h"
-#include "base/compiler_specific.h"
#include "base/time.h"
+#include "chrome/browser/browser_thread.h"
#include "chrome/browser/net/chrome_net_log.h"
#include "chrome/common/resource_response.h"
#include "net/base/load_flags.h"
@@ -48,7 +48,7 @@ static int32 TimeTicksToOffset(
(time_ticks - record->base_ticks).InMillisecondsRoundedUp());
}
-}
+} // namespace
LoadTimingObserver::URLRequestRecord::URLRequestRecord()
: connect_job_id(net::NetLog::Source::kInvalidId),
@@ -57,7 +57,7 @@ LoadTimingObserver::URLRequestRecord::URLRequestRecord()
}
LoadTimingObserver::LoadTimingObserver()
- : Observer(net::NetLog::LOG_BASIC),
+ : ThreadSafeObserver(net::NetLog::LOG_BASIC),
last_connect_job_id_(net::NetLog::Source::kInvalidId) {
}
@@ -66,6 +66,8 @@ LoadTimingObserver::~LoadTimingObserver() {
LoadTimingObserver::URLRequestRecord*
LoadTimingObserver::GetURLRequestRecord(uint32 source_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
URLRequestToRecordMap::iterator it = url_request_to_record_.find(source_id);
if (it != url_request_to_record_.end())
return &it->second;
@@ -77,6 +79,9 @@ void LoadTimingObserver::OnAddEntry(net::NetLog::EventType type,
const net::NetLog::Source& source,
net::NetLog::EventPhase phase,
net::NetLog::EventParameters* params) {
+ // The events that the Observer is interested in only occur on the IO thread.
+ if (!BrowserThread::CurrentlyOn(BrowserThread::IO))
+ return;
if (source.type == net::NetLog::SOURCE_URL_REQUEST)
OnAddURLRequestEntry(type, time, source, phase, params);
else if (source.type == net::NetLog::SOURCE_CONNECT_JOB)
@@ -86,8 +91,9 @@ void LoadTimingObserver::OnAddEntry(net::NetLog::EventType type,
}
// static
-void LoadTimingObserver::PopulateTimingInfo(URLRequest* request,
+void LoadTimingObserver::PopulateTimingInfo(net::URLRequest* request,
ResourceResponse* response) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (!(request->load_flags() & net::LOAD_ENABLE_LOAD_TIMING))
return;
@@ -113,14 +119,17 @@ void LoadTimingObserver::OnAddURLRequestEntry(
const net::NetLog::Source& source,
net::NetLog::EventPhase phase,
net::NetLog::EventParameters* params) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
bool is_begin = phase == net::NetLog::PHASE_BEGIN;
bool is_end = phase == net::NetLog::PHASE_END;
if (type == net::NetLog::TYPE_URL_REQUEST_START_JOB) {
if (is_begin) {
// Only record timing for entries with corresponding flag.
- int load_flags = static_cast<URLRequestStartEventParameters*>(params)->
- load_flags();
+ int load_flags =
+ static_cast<net::URLRequestStartEventParameters*>(params)->
+ load_flags();
if (!(load_flags & net::LOAD_ENABLE_LOAD_TIMING))
return;
@@ -214,6 +223,8 @@ void LoadTimingObserver::OnAddConnectJobEntry(
const net::NetLog::Source& source,
net::NetLog::EventPhase phase,
net::NetLog::EventParameters* params) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
bool is_begin = phase == net::NetLog::PHASE_BEGIN;
bool is_end = phase == net::NetLog::PHASE_END;
@@ -257,6 +268,8 @@ void LoadTimingObserver::OnAddSocketEntry(
const net::NetLog::Source& source,
net::NetLog::EventPhase phase,
net::NetLog::EventParameters* params) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
bool is_begin = phase == net::NetLog::PHASE_BEGIN;
bool is_end = phase == net::NetLog::PHASE_END;
diff --git a/chrome/browser/net/load_timing_observer.h b/chrome/browser/net/load_timing_observer.h
index ec3c2e5..a280398 100644
--- a/chrome/browser/net/load_timing_observer.h
+++ b/chrome/browser/net/load_timing_observer.h
@@ -21,7 +21,10 @@ struct ResourceResponse;
// LoadTimingObserver watches the NetLog event stream and collects the network
// timing information.
-class LoadTimingObserver : public ChromeNetLog::Observer {
+//
+// LoadTimingObserver lives completely on the IOThread and ignores events from
+// other threads. It is not safe to use from other threads.
+class LoadTimingObserver : public ChromeNetLog::ThreadSafeObserver {
public:
struct URLRequestRecord {
URLRequestRecord();
@@ -48,7 +51,7 @@ class LoadTimingObserver : public ChromeNetLog::Observer {
URLRequestRecord* GetURLRequestRecord(uint32 source_id);
- // Observer implementation:
+ // ThreadSafeObserver implementation:
virtual void OnAddEntry(net::NetLog::EventType type,
const base::TimeTicks& time,
const net::NetLog::Source& source,
diff --git a/chrome/browser/net/load_timing_observer_unittest.cc b/chrome/browser/net/load_timing_observer_unittest.cc
index 8ded133..43f95dc 100644
--- a/chrome/browser/net/load_timing_observer_unittest.cc
+++ b/chrome/browser/net/load_timing_observer_unittest.cc
@@ -8,6 +8,7 @@
#include "base/format_macros.h"
#include "base/string_util.h"
#include "base/time.h"
+#include "chrome/browser/browser_thread.h"
#include "net/base/load_flags.h"
#include "net/url_request/url_request_netlog_params.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -17,6 +18,17 @@ namespace {
using net::NetLog;
using base::TimeDelta;
+// Serves to Identify the current thread as the IO thread.
+class LoadTimingObserverTest : public testing::Test {
+ public:
+ LoadTimingObserverTest() : io_thread_(BrowserThread::IO, &message_loop_) {
+ }
+
+ private:
+ MessageLoop message_loop_;
+ BrowserThread io_thread_;
+};
+
base::TimeTicks current_time;
void AddStartEntry(LoadTimingObserver& observer,
@@ -36,8 +48,8 @@ void AddEndEntry(LoadTimingObserver& observer,
void AddStartURLRequestEntries(LoadTimingObserver& observer,
uint32 id,
bool request_timing) {
- scoped_refptr<URLRequestStartEventParameters> params(
- new URLRequestStartEventParameters(
+ scoped_refptr<net::URLRequestStartEventParameters> params(
+ new net::URLRequestStartEventParameters(
GURL(StringPrintf("http://req%d", id)),
"GET",
request_timing ? net::LOAD_ENABLE_LOAD_TIMING : 0,
@@ -81,8 +93,8 @@ void AddEndSocketEntries(LoadTimingObserver& observer, uint32 id) {
} // namespace
-// Test that URLRequest with no load timing flag is not processed.
-TEST(LoadTimingObserverTest, NoLoadTimingEnabled) {
+// Test that net::URLRequest with no load timing flag is not processed.
+TEST_F(LoadTimingObserverTest, NoLoadTimingEnabled) {
LoadTimingObserver observer;
AddStartURLRequestEntries(observer, 0, false);
@@ -92,7 +104,7 @@ TEST(LoadTimingObserverTest, NoLoadTimingEnabled) {
}
// Test that URLRequestRecord is created, deleted and is not growing unbound.
-TEST(LoadTimingObserverTest, URLRequestRecord) {
+TEST_F(LoadTimingObserverTest, URLRequestRecord) {
LoadTimingObserver observer;
// Create record.
@@ -114,7 +126,7 @@ TEST(LoadTimingObserverTest, URLRequestRecord) {
}
// Test that ConnectJobRecord is created, deleted and is not growing unbound.
-TEST(LoadTimingObserverTest, ConnectJobRecord) {
+TEST_F(LoadTimingObserverTest, ConnectJobRecord) {
LoadTimingObserver observer;
// Create record.
@@ -135,7 +147,7 @@ TEST(LoadTimingObserverTest, ConnectJobRecord) {
}
// Test that SocketRecord is created, deleted and is not growing unbound.
-TEST(LoadTimingObserverTest, SocketRecord) {
+TEST_F(LoadTimingObserverTest, SocketRecord) {
LoadTimingObserver observer;
// Create record.
@@ -157,7 +169,7 @@ TEST(LoadTimingObserverTest, SocketRecord) {
}
// Test that basic time is set to the request.
-TEST(LoadTimingObserverTest, BaseTicks) {
+TEST_F(LoadTimingObserverTest, BaseTicks) {
LoadTimingObserver observer;
current_time += TimeDelta::FromSeconds(1);
AddStartURLRequestEntries(observer, 0, true);
@@ -168,7 +180,7 @@ TEST(LoadTimingObserverTest, BaseTicks) {
}
// Test proxy time detection.
-TEST(LoadTimingObserverTest, ProxyTime) {
+TEST_F(LoadTimingObserverTest, ProxyTime) {
LoadTimingObserver observer;
current_time += TimeDelta::FromSeconds(1);
@@ -187,7 +199,7 @@ TEST(LoadTimingObserverTest, ProxyTime) {
}
// Test connect time detection.
-TEST(LoadTimingObserverTest, ConnectTime) {
+TEST_F(LoadTimingObserverTest, ConnectTime) {
LoadTimingObserver observer;
current_time += TimeDelta::FromSeconds(1);
@@ -206,7 +218,7 @@ TEST(LoadTimingObserverTest, ConnectTime) {
}
// Test dns time detection.
-TEST(LoadTimingObserverTest, DnsTime) {
+TEST_F(LoadTimingObserverTest, DnsTime) {
LoadTimingObserver observer;
// Start request.
@@ -240,7 +252,7 @@ TEST(LoadTimingObserverTest, DnsTime) {
}
// Test send time detection.
-TEST(LoadTimingObserverTest, SendTime) {
+TEST_F(LoadTimingObserverTest, SendTime) {
LoadTimingObserver observer;
// Start request.
@@ -266,7 +278,7 @@ TEST(LoadTimingObserverTest, SendTime) {
}
// Test receive time detection.
-TEST(LoadTimingObserverTest, ReceiveTime) {
+TEST_F(LoadTimingObserverTest, ReceiveTime) {
LoadTimingObserver observer;
// Start request.
@@ -292,7 +304,7 @@ TEST(LoadTimingObserverTest, ReceiveTime) {
}
// Test ssl time detection.
-TEST(LoadTimingObserverTest, SslTime) {
+TEST_F(LoadTimingObserverTest, SslTime) {
LoadTimingObserver observer;
// Start request.
diff --git a/chrome/browser/net/metadata_url_request.cc b/chrome/browser/net/metadata_url_request.cc
index dacfc5d..9d990c5 100644
--- a/chrome/browser/net/metadata_url_request.cc
+++ b/chrome/browser/net/metadata_url_request.cc
@@ -19,11 +19,12 @@ namespace {
class MetadataRequestHandler : public net::URLRequestJob {
public:
- explicit MetadataRequestHandler(URLRequest* request);
+ explicit MetadataRequestHandler(net::URLRequest* request);
- static URLRequestJob* Factory(URLRequest* request, const std::string& scheme);
+ static net::URLRequestJob* Factory(net::URLRequest* request,
+ const std::string& scheme);
- // URLRequestJob implementation.
+ // net::URLRequestJob implementation.
virtual void Start();
virtual void Kill();
virtual bool ReadRawData(net::IOBuffer* buf, int buf_size, int *bytes_read);
@@ -39,8 +40,8 @@ class MetadataRequestHandler : public net::URLRequestJob {
DISALLOW_COPY_AND_ASSIGN(MetadataRequestHandler);
};
-MetadataRequestHandler::MetadataRequestHandler(URLRequest* request)
- : URLRequestJob(request),
+MetadataRequestHandler::MetadataRequestHandler(net::URLRequest* request)
+ : net::URLRequestJob(request),
data_offset_(0) {
parsed = false;
}
@@ -48,7 +49,7 @@ MetadataRequestHandler::MetadataRequestHandler(URLRequest* request)
MetadataRequestHandler::~MetadataRequestHandler() {
}
-URLRequestJob* MetadataRequestHandler::Factory(URLRequest* request,
+net::URLRequestJob* MetadataRequestHandler::Factory(net::URLRequest* request,
const std::string& scheme) {
return new MetadataRequestHandler(request);
}
@@ -74,7 +75,7 @@ bool MetadataRequestHandler::ReadRawData(net::IOBuffer* buf, int buf_size,
return false;
}
if (!parsed) {
- MetadataParserManager* manager = MetadataParserManager::Get();
+ MetadataParserManager* manager = MetadataParserManager::GetInstance();
scoped_ptr<MetadataParser> parser(manager->GetParserForFile(path));
if (parser != NULL) {
result_ = "{\n";
@@ -125,7 +126,7 @@ void MetadataRequestHandler::StartAsync() {
void RegisterMetadataURLRequestHandler() {
#if defined(OS_CHROMEOS)
- URLRequest::RegisterProtocolFactory(chrome::kMetadataScheme,
- &MetadataRequestHandler::Factory);
+ net::URLRequest::RegisterProtocolFactory(chrome::kMetadataScheme,
+ &MetadataRequestHandler::Factory);
#endif
}
diff --git a/chrome/browser/net/net_log_logger.cc b/chrome/browser/net/net_log_logger.cc
index b533e95..bba75ca 100644
--- a/chrome/browser/net/net_log_logger.cc
+++ b/chrome/browser/net/net_log_logger.cc
@@ -7,7 +7,9 @@
#include "base/json/json_writer.h"
#include "base/values.h"
-NetLogLogger::NetLogLogger() : Observer(net::NetLog::LOG_ALL_BUT_BYTES) {}
+NetLogLogger::NetLogLogger()
+ : ThreadSafeObserver(net::NetLog::LOG_ALL_BUT_BYTES) {
+}
NetLogLogger::~NetLogLogger() {}
diff --git a/chrome/browser/net/net_log_logger.h b/chrome/browser/net/net_log_logger.h
index 7f90d94..564f232 100644
--- a/chrome/browser/net/net_log_logger.h
+++ b/chrome/browser/net/net_log_logger.h
@@ -11,12 +11,12 @@
// NetLogLogger watches the NetLog event stream, and sends all entries to
// VLOG(1). This is to debug errors that prevent getting to the
// about:net-internals page.
-class NetLogLogger : public ChromeNetLog::Observer {
+class NetLogLogger : public ChromeNetLog::ThreadSafeObserver {
public:
NetLogLogger();
~NetLogLogger();
- // Observer implementation:
+ // ThreadSafeObserver implementation:
virtual void OnAddEntry(net::NetLog::EventType type,
const base::TimeTicks& time,
const net::NetLog::Source& source,
diff --git a/chrome/browser/net/net_pref_observer.cc b/chrome/browser/net/net_pref_observer.cc
index 5ab75ff..b912958 100644
--- a/chrome/browser/net/net_pref_observer.cc
+++ b/chrome/browser/net/net_pref_observer.cc
@@ -7,6 +7,7 @@
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/net/predictor_api.h"
#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "net/http/http_stream_factory.h"
diff --git a/chrome/browser/net/passive_log_collector.cc b/chrome/browser/net/passive_log_collector.cc
index 84a9403..0d41479 100644
--- a/chrome/browser/net/passive_log_collector.cc
+++ b/chrome/browser/net/passive_log_collector.cc
@@ -7,9 +7,9 @@
#include <algorithm>
#include "base/compiler_specific.h"
+#include "base/lock.h"
#include "base/string_util.h"
#include "base/format_macros.h"
-#include "chrome/browser/browser_thread.h"
#include "net/url_request/url_request_netlog_params.h"
namespace {
@@ -18,7 +18,7 @@ namespace {
const size_t kMaxNumEntriesPerLog = 30;
-void AddEntryToSourceInfo(const PassiveLogCollector::Entry& entry,
+void AddEntryToSourceInfo(const ChromeNetLog::Entry& entry,
PassiveLogCollector::SourceInfo* out_info) {
// Start dropping new entries when the log has gotten too big.
if (out_info->entries.size() + 1 <= kMaxNumEntriesPerLog) {
@@ -30,29 +30,13 @@ void AddEntryToSourceInfo(const PassiveLogCollector::Entry& entry,
}
// Comparator to sort entries by their |order| property, ascending.
-bool SortByOrderComparator(const PassiveLogCollector::Entry& a,
- const PassiveLogCollector::Entry& b) {
+bool SortByOrderComparator(const ChromeNetLog::Entry& a,
+ const ChromeNetLog::Entry& b) {
return a.order < b.order;
}
} // namespace
-PassiveLogCollector::Entry::Entry(uint32 order,
- net::NetLog::EventType type,
- const base::TimeTicks& time,
- net::NetLog::Source source,
- net::NetLog::EventPhase phase,
- net::NetLog::EventParameters* params)
- : order(order),
- type(type),
- time(time),
- source(source),
- phase(phase),
- params(params) {
-}
-
-PassiveLogCollector::Entry::~Entry() {}
-
PassiveLogCollector::SourceInfo::SourceInfo()
: source_id(net::NetLog::Source::kInvalidId),
num_entries_truncated(0),
@@ -67,7 +51,7 @@ PassiveLogCollector::SourceInfo::~SourceInfo() {}
//----------------------------------------------------------------------------
PassiveLogCollector::PassiveLogCollector()
- : Observer(net::NetLog::LOG_BASIC),
+ : ThreadSafeObserver(net::NetLog::LOG_BASIC),
ALLOW_THIS_IN_INITIALIZER_LIST(connect_job_tracker_(this)),
ALLOW_THIS_IN_INITIALIZER_LIST(url_request_tracker_(this)),
ALLOW_THIS_IN_INITIALIZER_LIST(socket_stream_tracker_(this)),
@@ -100,28 +84,33 @@ void PassiveLogCollector::OnAddEntry(
const net::NetLog::Source& source,
net::NetLog::EventPhase phase,
net::NetLog::EventParameters* params) {
+ AssertNetLogLockAcquired();
// Package the parameters into a single struct for convenience.
- Entry entry(num_events_seen_++, type, time, source, phase, params);
+ ChromeNetLog::Entry entry(num_events_seen_++, type, time, source, phase,
+ params);
- SourceTrackerInterface* tracker = GetTrackerForSourceType(entry.source.type);
+ SourceTrackerInterface* tracker = GetTrackerForSourceType_(entry.source.type);
if (tracker)
tracker->OnAddEntry(entry);
}
+void PassiveLogCollector::Clear() {
+ AssertNetLogLockAcquired();
+ for (size_t i = 0; i < arraysize(trackers_); ++i)
+ trackers_[i]->Clear();
+}
+
PassiveLogCollector::SourceTrackerInterface*
-PassiveLogCollector::GetTrackerForSourceType(
+PassiveLogCollector::GetTrackerForSourceType_(
net::NetLog::SourceType source_type) {
DCHECK_LE(source_type, static_cast<int>(arraysize(trackers_)));
DCHECK_GE(source_type, 0);
return trackers_[source_type];
}
-void PassiveLogCollector::Clear() {
- for (size_t i = 0; i < arraysize(trackers_); ++i)
- trackers_[i]->Clear();
-}
-
-void PassiveLogCollector::GetAllCapturedEvents(EntryList* out) const {
+void PassiveLogCollector::GetAllCapturedEvents(
+ ChromeNetLog::EntryList* out) const {
+ AssertNetLogLockAcquired();
out->clear();
// Append all of the captured entries held by the various trackers to
@@ -137,11 +126,11 @@ std::string PassiveLogCollector::SourceInfo::GetURL() const {
// Note: we look at the first *two* entries, since the outer REQUEST_ALIVE
// doesn't actually contain any data.
for (size_t i = 0; i < 2 && i < entries.size(); ++i) {
- const PassiveLogCollector::Entry& entry = entries[i];
+ const ChromeNetLog::Entry& entry = entries[i];
if (entry.phase == net::NetLog::PHASE_BEGIN && entry.params) {
switch (entry.type) {
case net::NetLog::TYPE_URL_REQUEST_START_JOB:
- return static_cast<URLRequestStartEventParameters*>(
+ return static_cast<net::URLRequestStartEventParameters*>(
entry.params.get())->url().possibly_invalid_spec();
case net::NetLog::TYPE_SOCKET_STREAM_CONNECT:
return static_cast<net::NetLogStringParameter*>(
@@ -161,7 +150,8 @@ std::string PassiveLogCollector::SourceInfo::GetURL() const {
PassiveLogCollector::GlobalSourceTracker::GlobalSourceTracker() {}
PassiveLogCollector::GlobalSourceTracker::~GlobalSourceTracker() {}
-void PassiveLogCollector::GlobalSourceTracker::OnAddEntry(const Entry& entry) {
+void PassiveLogCollector::GlobalSourceTracker::OnAddEntry(
+ const ChromeNetLog::Entry& entry) {
const size_t kMaxEntries = 30u;
entries_.push_back(entry);
if (entries_.size() > kMaxEntries)
@@ -173,7 +163,7 @@ void PassiveLogCollector::GlobalSourceTracker::Clear() {
}
void PassiveLogCollector::GlobalSourceTracker::AppendAllEntries(
- EntryList* out) const {
+ ChromeNetLog::EntryList* out) const {
out->insert(out->end(), entries_.begin(), entries_.end());
}
@@ -192,7 +182,8 @@ PassiveLogCollector::SourceTracker::SourceTracker(
PassiveLogCollector::SourceTracker::~SourceTracker() {}
-void PassiveLogCollector::SourceTracker::OnAddEntry(const Entry& entry) {
+void PassiveLogCollector::SourceTracker::OnAddEntry(
+ const ChromeNetLog::Entry& entry) {
// Lookup or insert a new entry into the bounded map.
SourceIDToInfoMap::iterator it = sources_.find(entry.source.id);
if (it == sources_.end()) {
@@ -259,7 +250,7 @@ void PassiveLogCollector::SourceTracker::Clear() {
}
void PassiveLogCollector::SourceTracker::AppendAllEntries(
- EntryList* out) const {
+ ChromeNetLog::EntryList* out) const {
// Append all of the entries for each of the sources.
for (SourceIDToInfoMap::const_iterator it = sources_.begin();
it != sources_.end();
@@ -344,7 +335,7 @@ void PassiveLogCollector::SourceTracker::AddReferenceToSourceDependency(
DCHECK(parent_);
DCHECK_NE(source.type, net::NetLog::SOURCE_NONE);
SourceTracker* tracker = static_cast<SourceTracker*>(
- parent_->GetTrackerForSourceType(source.type));
+ parent_->GetTrackerForSourceType_(source.type));
DCHECK(tracker);
// Tell the owning tracker to increment the reference count of |source|.
@@ -366,7 +357,7 @@ PassiveLogCollector::SourceTracker::ReleaseAllReferencesToDependencies(
DCHECK(parent_);
DCHECK_NE(source.type, net::NetLog::SOURCE_NONE);
SourceTracker* tracker = static_cast<SourceTracker*>(
- parent_->GetTrackerForSourceType(source.type));
+ parent_->GetTrackerForSourceType_(source.type));
DCHECK(tracker);
// Tell the owning tracker to decrement the reference count of |source|.
@@ -389,8 +380,8 @@ PassiveLogCollector::ConnectJobTracker::ConnectJobTracker(
}
PassiveLogCollector::SourceTracker::Action
-PassiveLogCollector::ConnectJobTracker::DoAddEntry(const Entry& entry,
- SourceInfo* out_info) {
+PassiveLogCollector::ConnectJobTracker::DoAddEntry(
+ const ChromeNetLog::Entry& entry, SourceInfo* out_info) {
AddEntryToSourceInfo(entry, out_info);
if (entry.type == net::NetLog::TYPE_CONNECT_JOB_SET_SOCKET) {
@@ -420,7 +411,7 @@ PassiveLogCollector::SocketTracker::SocketTracker()
}
PassiveLogCollector::SourceTracker::Action
-PassiveLogCollector::SocketTracker::DoAddEntry(const Entry& entry,
+PassiveLogCollector::SocketTracker::DoAddEntry(const ChromeNetLog::Entry& entry,
SourceInfo* out_info) {
// TODO(eroman): aggregate the byte counts once truncation starts to happen,
// to summarize transaction read/writes for each SOCKET_IN_USE
@@ -452,8 +443,8 @@ PassiveLogCollector::RequestTracker::RequestTracker(PassiveLogCollector* parent)
}
PassiveLogCollector::SourceTracker::Action
-PassiveLogCollector::RequestTracker::DoAddEntry(const Entry& entry,
- SourceInfo* out_info) {
+PassiveLogCollector::RequestTracker::DoAddEntry(
+ const ChromeNetLog::Entry& entry, SourceInfo* out_info) {
if (entry.type == net::NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB ||
entry.type == net::NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET) {
const net::NetLog::Source& source_dependency =
@@ -491,7 +482,7 @@ PassiveLogCollector::InitProxyResolverTracker::InitProxyResolverTracker()
PassiveLogCollector::SourceTracker::Action
PassiveLogCollector::InitProxyResolverTracker::DoAddEntry(
- const Entry& entry, SourceInfo* out_info) {
+ const ChromeNetLog::Entry& entry, SourceInfo* out_info) {
AddEntryToSourceInfo(entry, out_info);
if (entry.type == net::NetLog::TYPE_INIT_PROXY_RESOLVER &&
entry.phase == net::NetLog::PHASE_END) {
@@ -513,8 +504,8 @@ PassiveLogCollector::SpdySessionTracker::SpdySessionTracker()
}
PassiveLogCollector::SourceTracker::Action
-PassiveLogCollector::SpdySessionTracker::DoAddEntry(const Entry& entry,
- SourceInfo* out_info) {
+PassiveLogCollector::SpdySessionTracker::DoAddEntry(
+ const ChromeNetLog::Entry& entry, SourceInfo* out_info) {
AddEntryToSourceInfo(entry, out_info);
if (entry.type == net::NetLog::TYPE_SPDY_SESSION &&
entry.phase == net::NetLog::PHASE_END) {
@@ -536,8 +527,8 @@ PassiveLogCollector::DNSRequestTracker::DNSRequestTracker()
}
PassiveLogCollector::SourceTracker::Action
-PassiveLogCollector::DNSRequestTracker::DoAddEntry(const Entry& entry,
- SourceInfo* out_info) {
+PassiveLogCollector::DNSRequestTracker::DoAddEntry(
+ const ChromeNetLog::Entry& entry, SourceInfo* out_info) {
AddEntryToSourceInfo(entry, out_info);
if (entry.type == net::NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST &&
entry.phase == net::NetLog::PHASE_END) {
@@ -559,7 +550,7 @@ PassiveLogCollector::DNSJobTracker::DNSJobTracker()
}
PassiveLogCollector::SourceTracker::Action
-PassiveLogCollector::DNSJobTracker::DoAddEntry(const Entry& entry,
+PassiveLogCollector::DNSJobTracker::DoAddEntry(const ChromeNetLog::Entry& entry,
SourceInfo* out_info) {
AddEntryToSourceInfo(entry, out_info);
if (entry.type == net::NetLog::TYPE_HOST_RESOLVER_IMPL_JOB &&
diff --git a/chrome/browser/net/passive_log_collector.h b/chrome/browser/net/passive_log_collector.h
index 5d46fb3..114e439 100644
--- a/chrome/browser/net/passive_log_collector.h
+++ b/chrome/browser/net/passive_log_collector.h
@@ -32,29 +32,12 @@
// The data captured by PassiveLogCollector is grouped by NetLog::Source, into
// a SourceInfo structure. These in turn are grouped by NetLog::SourceType, and
// owned by a SourceTracker instance for the specific source type.
-class PassiveLogCollector : public ChromeNetLog::Observer {
+//
+// The PassiveLogCollector is owned by the ChromeNetLog itself, and is not
+// thread safe. The ChromeNetLog is responsible for calling it in a thread safe
+// manner.
+class PassiveLogCollector : public ChromeNetLog::ThreadSafeObserver {
public:
- // This structure encapsulates all of the parameters of a captured event,
- // including an "order" field that identifies when it was captured relative
- // to other events.
- struct Entry {
- Entry(uint32 order,
- net::NetLog::EventType type,
- const base::TimeTicks& time,
- net::NetLog::Source source,
- net::NetLog::EventPhase phase,
- net::NetLog::EventParameters* params);
- ~Entry();
-
- uint32 order;
- net::NetLog::EventType type;
- base::TimeTicks time;
- net::NetLog::Source source;
- net::NetLog::EventPhase phase;
- scoped_refptr<net::NetLog::EventParameters> params;
- };
-
- typedef std::vector<Entry> EntryList;
typedef std::vector<net::NetLog::Source> SourceDependencyList;
struct SourceInfo {
@@ -67,7 +50,7 @@ class PassiveLogCollector : public ChromeNetLog::Observer {
std::string GetURL() const;
uint32 source_id;
- EntryList entries;
+ ChromeNetLog::EntryList entries;
size_t num_entries_truncated;
// List of other sources which contain information relevant to this
@@ -93,13 +76,13 @@ class PassiveLogCollector : public ChromeNetLog::Observer {
public:
virtual ~SourceTrackerInterface() {}
- virtual void OnAddEntry(const Entry& entry) = 0;
+ virtual void OnAddEntry(const ChromeNetLog::Entry& entry) = 0;
// Clears all the passively logged data from this tracker.
virtual void Clear() = 0;
// Appends all the captured entries to |out|. The ordering is undefined.
- virtual void AppendAllEntries(EntryList* out) const = 0;
+ virtual void AppendAllEntries(ChromeNetLog::EntryList* out) const = 0;
};
// This source tracker is intended for TYPE_NONE. All entries go into a
@@ -110,12 +93,12 @@ class PassiveLogCollector : public ChromeNetLog::Observer {
~GlobalSourceTracker();
// SourceTrackerInterface implementation:
- virtual void OnAddEntry(const Entry& entry);
+ virtual void OnAddEntry(const ChromeNetLog::Entry& entry);
virtual void Clear();
- virtual void AppendAllEntries(EntryList* out) const;
+ virtual void AppendAllEntries(ChromeNetLog::EntryList* out) const;
private:
- typedef std::deque<Entry> CircularEntryList;
+ typedef std::deque<ChromeNetLog::Entry> CircularEntryList;
CircularEntryList entries_;
DISALLOW_COPY_AND_ASSIGN(GlobalSourceTracker);
};
@@ -136,9 +119,9 @@ class PassiveLogCollector : public ChromeNetLog::Observer {
virtual ~SourceTracker();
// SourceTrackerInterface implementation:
- virtual void OnAddEntry(const Entry& entry);
+ virtual void OnAddEntry(const ChromeNetLog::Entry& entry);
virtual void Clear();
- virtual void AppendAllEntries(EntryList* out) const;
+ virtual void AppendAllEntries(ChromeNetLog::EntryList* out) const;
#ifdef UNIT_TEST
// Helper used to inspect the current state by unit-tests.
@@ -172,7 +155,8 @@ class PassiveLogCollector : public ChromeNetLog::Observer {
// Updates |out_info| with the information from |entry|. Returns an action
// to perform for this map entry on completion.
- virtual Action DoAddEntry(const Entry& entry, SourceInfo* out_info) = 0;
+ virtual Action DoAddEntry(const ChromeNetLog::Entry& entry,
+ SourceInfo* out_info) = 0;
// Removes |source_id| from |sources_|. This also releases any references
// to dependencies held by this source.
@@ -217,7 +201,8 @@ class PassiveLogCollector : public ChromeNetLog::Observer {
explicit ConnectJobTracker(PassiveLogCollector* parent);
protected:
- virtual Action DoAddEntry(const Entry& entry, SourceInfo* out_info);
+ virtual Action DoAddEntry(const ChromeNetLog::Entry& entry,
+ SourceInfo* out_info);
private:
DISALLOW_COPY_AND_ASSIGN(ConnectJobTracker);
};
@@ -231,13 +216,14 @@ class PassiveLogCollector : public ChromeNetLog::Observer {
SocketTracker();
protected:
- virtual Action DoAddEntry(const Entry& entry, SourceInfo* out_info);
+ virtual Action DoAddEntry(const ChromeNetLog::Entry& entry,
+ SourceInfo* out_info);
private:
DISALLOW_COPY_AND_ASSIGN(SocketTracker);
};
- // Specialization of SourceTracker for handling URLRequest/SocketStream.
+ // Specialization of SourceTracker for handling net::URLRequest/SocketStream.
class RequestTracker : public SourceTracker {
public:
static const size_t kMaxNumSources;
@@ -246,7 +232,8 @@ class PassiveLogCollector : public ChromeNetLog::Observer {
explicit RequestTracker(PassiveLogCollector* parent);
protected:
- virtual Action DoAddEntry(const Entry& entry, SourceInfo* out_info);
+ virtual Action DoAddEntry(const ChromeNetLog::Entry& entry,
+ SourceInfo* out_info);
private:
DISALLOW_COPY_AND_ASSIGN(RequestTracker);
@@ -262,7 +249,8 @@ class PassiveLogCollector : public ChromeNetLog::Observer {
InitProxyResolverTracker();
protected:
- virtual Action DoAddEntry(const Entry& entry, SourceInfo* out_info);
+ virtual Action DoAddEntry(const ChromeNetLog::Entry& entry,
+ SourceInfo* out_info);
private:
DISALLOW_COPY_AND_ASSIGN(InitProxyResolverTracker);
@@ -277,7 +265,8 @@ class PassiveLogCollector : public ChromeNetLog::Observer {
SpdySessionTracker();
protected:
- virtual Action DoAddEntry(const Entry& entry, SourceInfo* out_info);
+ virtual Action DoAddEntry(const ChromeNetLog::Entry& entry,
+ SourceInfo* out_info);
private:
DISALLOW_COPY_AND_ASSIGN(SpdySessionTracker);
@@ -292,7 +281,8 @@ class PassiveLogCollector : public ChromeNetLog::Observer {
DNSRequestTracker();
protected:
- virtual Action DoAddEntry(const Entry& entry, SourceInfo* out_info);
+ virtual Action DoAddEntry(const ChromeNetLog::Entry& entry,
+ SourceInfo* out_info);
private:
DISALLOW_COPY_AND_ASSIGN(DNSRequestTracker);
@@ -307,7 +297,8 @@ class PassiveLogCollector : public ChromeNetLog::Observer {
DNSJobTracker();
protected:
- virtual Action DoAddEntry(const Entry& entry, SourceInfo* out_info);
+ virtual Action DoAddEntry(const ChromeNetLog::Entry& entry,
+ SourceInfo* out_info);
private:
DISALLOW_COPY_AND_ASSIGN(DNSJobTracker);
@@ -316,25 +307,25 @@ class PassiveLogCollector : public ChromeNetLog::Observer {
PassiveLogCollector();
~PassiveLogCollector();
- // Observer implementation:
+ // ThreadSafeObserver implementation:
virtual void OnAddEntry(net::NetLog::EventType type,
const base::TimeTicks& time,
const net::NetLog::Source& source,
net::NetLog::EventPhase phase,
net::NetLog::EventParameters* params);
- // Returns the tracker to use for sources of type |source_type|, or NULL.
- SourceTrackerInterface* GetTrackerForSourceType(
- net::NetLog::SourceType source_type);
-
// Clears all of the passively logged data.
void Clear();
// Fills |out| with the full list of events that have been passively
// captured. The list is ordered by capture time.
- void GetAllCapturedEvents(EntryList* out) const;
+ void GetAllCapturedEvents(ChromeNetLog::EntryList* out) const;
private:
+ // Returns the tracker to use for sources of type |source_type|, or NULL.
+ SourceTrackerInterface* GetTrackerForSourceType_(
+ net::NetLog::SourceType source_type);
+
FRIEND_TEST_ALL_PREFIXES(PassiveLogCollectorTest,
HoldReferenceToDependentSource);
FRIEND_TEST_ALL_PREFIXES(PassiveLogCollectorTest,
diff --git a/chrome/browser/net/passive_log_collector_unittest.cc b/chrome/browser/net/passive_log_collector_unittest.cc
index e7d6074..c948baa 100644
--- a/chrome/browser/net/passive_log_collector_unittest.cc
+++ b/chrome/browser/net/passive_log_collector_unittest.cc
@@ -19,24 +19,24 @@ using net::NetLog;
const NetLog::SourceType kSourceType = NetLog::SOURCE_NONE;
-PassiveLogCollector::Entry MakeStartLogEntryWithURL(int source_id,
- const std::string& url) {
- return PassiveLogCollector::Entry(
+ChromeNetLog::Entry MakeStartLogEntryWithURL(int source_id,
+ const std::string& url) {
+ return ChromeNetLog::Entry(
0,
NetLog::TYPE_URL_REQUEST_START_JOB,
base::TimeTicks(),
NetLog::Source(kSourceType, source_id),
NetLog::PHASE_BEGIN,
- new URLRequestStartEventParameters(GURL(url), "GET", 0, net::LOW));
+ new net::URLRequestStartEventParameters(GURL(url), "GET", 0, net::LOW));
}
-PassiveLogCollector::Entry MakeStartLogEntry(int source_id) {
+ChromeNetLog::Entry MakeStartLogEntry(int source_id) {
return MakeStartLogEntryWithURL(source_id,
StringPrintf("http://req%d", source_id));
}
-PassiveLogCollector::Entry MakeEndLogEntry(int source_id) {
- return PassiveLogCollector::Entry(
+ChromeNetLog::Entry MakeEndLogEntry(int source_id) {
+ return ChromeNetLog::Entry(
0,
NetLog::TYPE_REQUEST_ALIVE,
base::TimeTicks(),
@@ -176,7 +176,7 @@ TEST(SpdySessionTracker, MovesToGraveyard) {
EXPECT_EQ(0u, GetLiveSources(tracker).size());
EXPECT_EQ(0u, GetDeadSources(tracker).size());
- PassiveLogCollector::Entry begin(
+ ChromeNetLog::Entry begin(
0u,
NetLog::TYPE_SPDY_SESSION,
base::TimeTicks(),
@@ -188,7 +188,7 @@ TEST(SpdySessionTracker, MovesToGraveyard) {
EXPECT_EQ(1u, GetLiveSources(tracker).size());
EXPECT_EQ(0u, GetDeadSources(tracker).size());
- PassiveLogCollector::Entry end(
+ ChromeNetLog::Entry end(
0u,
NetLog::TYPE_SPDY_SESSION,
base::TimeTicks(),
diff --git a/chrome/browser/net/preconnect.cc b/chrome/browser/net/preconnect.cc
index 5946c85..972e302 100644
--- a/chrome/browser/net/preconnect.cc
+++ b/chrome/browser/net/preconnect.cc
@@ -6,7 +6,7 @@
#include "base/logging.h"
#include "base/metrics/histogram.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/common/net/url_request_context_getter.h"
#include "net/http/http_network_session.h"
diff --git a/chrome/browser/net/predictor_api.cc b/chrome/browser/net/predictor_api.cc
index 290a566..40a583e 100644
--- a/chrome/browser/net/predictor_api.cc
+++ b/chrome/browser/net/predictor_api.cc
@@ -8,7 +8,7 @@
#include <string>
#include "base/metrics/field_trial.h"
-#include "base/singleton.h"
+#include "base/lazy_instance.h"
#include "base/stl_util-inl.h"
#include "base/string_number_conversions.h"
#include "base/thread.h"
@@ -22,7 +22,7 @@
#include "chrome/browser/net/url_info.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prefs/session_startup_pref.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
@@ -133,12 +133,9 @@ void OnTheRecord(bool enable) {
g_browser_process->io_thread()->ChangedToOnTheRecord();
}
-void RegisterPrefs(PrefService* local_state) {
- local_state->RegisterListPref(prefs::kDnsStartupPrefetchList);
- local_state->RegisterListPref(prefs::kDnsHostReferralList);
-}
-
void RegisterUserPrefs(PrefService* user_prefs) {
+ user_prefs->RegisterListPref(prefs::kDnsPrefetchingStartupList);
+ user_prefs->RegisterListPref(prefs::kDnsPrefetchingHostReferralList);
user_prefs->RegisterBooleanPref(prefs::kDnsPrefetchingEnabled, true);
}
@@ -330,7 +327,8 @@ class OffTheRecordObserver : public NotificationObserver {
}
private:
- friend struct DefaultSingletonTraits<OffTheRecordObserver>;
+ friend struct base::DefaultLazyInstanceTraits<OffTheRecordObserver>;
+
OffTheRecordObserver() : count_off_the_record_windows_(0) {}
~OffTheRecordObserver() {}
@@ -340,6 +338,9 @@ class OffTheRecordObserver : public NotificationObserver {
DISALLOW_COPY_AND_ASSIGN(OffTheRecordObserver);
};
+static base::LazyInstance<OffTheRecordObserver> g_off_the_record_observer(
+ base::LINKER_INITIALIZED);
+
//------------------------------------------------------------------------------
// This section supports the about:dns page.
//------------------------------------------------------------------------------
@@ -389,8 +390,21 @@ static void InitNetworkPredictor(TimeDelta max_dns_queue_delay,
GetPredictedUrlListAtStartup(user_prefs, local_state);
ListValue* referral_list =
- static_cast<ListValue*>(
- local_state->GetMutableList(prefs::kDnsHostReferralList)->DeepCopy());
+ static_cast<ListValue*>(user_prefs->GetMutableList(
+ prefs::kDnsPrefetchingHostReferralList)->DeepCopy());
+
+ // Remove obsolete preferences from local state if necessary.
+ int dns_prefs_version =
+ user_prefs->GetInteger(prefs::kMultipleProfilePrefMigration);
+ if (dns_prefs_version < 1) {
+ // These prefs only need to be registered if they need to be cleared from
+ // local state.
+ local_state->RegisterListPref(prefs::kDnsStartupPrefetchList);
+ local_state->RegisterListPref(prefs::kDnsHostReferralList);
+ local_state->ClearPref(prefs::kDnsStartupPrefetchList);
+ local_state->ClearPref(prefs::kDnsHostReferralList);
+ user_prefs->SetInteger(prefs::kMultipleProfilePrefMigration, 1);
+ }
g_browser_process->io_thread()->InitNetworkPredictor(
prefetching_enabled, max_dns_queue_delay, max_parallel_resolves, urls,
@@ -458,9 +472,9 @@ void SavePredictorStateForNextStartupAndTrim(PrefService* prefs) {
BrowserThread::IO,
FROM_HERE,
NewRunnableFunction(SaveDnsPrefetchStateForNextStartupAndTrimOnIOThread,
- prefs->GetMutableList(prefs::kDnsStartupPrefetchList),
- prefs->GetMutableList(prefs::kDnsHostReferralList),
- &completion));
+ prefs->GetMutableList(prefs::kDnsPrefetchingStartupList),
+ prefs->GetMutableList(prefs::kDnsPrefetchingHostReferralList),
+ &completion));
DCHECK(posted);
if (posted)
@@ -476,7 +490,8 @@ static UrlList GetPredictedUrlListAtStartup(PrefService* user_prefs,
// also catch more of the "primary" home pages, since that was (presumably)
// rendered first (and will be rendered first this time too).
ListValue* startup_list =
- local_state->GetMutableList(prefs::kDnsStartupPrefetchList);
+ user_prefs->GetMutableList(prefs::kDnsPrefetchingStartupList);
+
if (startup_list) {
ListValue::iterator it = startup_list->begin();
int format_version = -1;
@@ -576,7 +591,7 @@ PredictorInit::PredictorInit(PrefService* user_prefs,
// We will register the incognito observer regardless of whether prefetching
// is enabled, as it is also used to clear the host cache.
- Singleton<OffTheRecordObserver>::get()->Register();
+ g_off_the_record_observer.Get().Register();
if (trial_->group() != disabled_prefetch) {
// Initialize the DNS prefetch system.
diff --git a/chrome/browser/net/predictor_api.h b/chrome/browser/net/predictor_api.h
index a03f7c9..8f22d31 100644
--- a/chrome/browser/net/predictor_api.h
+++ b/chrome/browser/net/predictor_api.h
@@ -41,7 +41,6 @@ void FreePredictorResources();
//------------------------------------------------------------------------------
// Global APIs relating to predictions in browser.
void EnablePredictor(bool enable);
-void RegisterPrefs(PrefService* local_state);
void RegisterUserPrefs(PrefService* user_prefs);
// Renderer bundles up list and sends to this browser API via IPC.
diff --git a/chrome/browser/net/pref_proxy_config_service.cc b/chrome/browser/net/pref_proxy_config_service.cc
index 9b0f545..2b10104 100644
--- a/chrome/browser/net/pref_proxy_config_service.cc
+++ b/chrome/browser/net/pref_proxy_config_service.cc
@@ -8,38 +8,12 @@
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prefs/pref_set_observer.h"
+#include "chrome/browser/prefs/proxy_prefs.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
-namespace {
-
-const bool kProxyPrefDefaultBoolean = false;
-const char kProxyPrefDefaultString[] = "";
-
-// Determines if a value of a proxy pref is set to its default. Default values
-// have a special role in the proxy pref system, because if all of the proxy
-// prefs are set to their defaults, then the system proxy settings are applied.
-// TODO(gfeher): Proxy preferences should be refactored to avoid the need
-// for such solutions. See crbug.com/65732
-bool IsDefaultValue(const Value* value) {
- bool b = false;
- std::string s;
- if (value->IsType(Value::TYPE_BOOLEAN) &&
- value->GetAsBoolean(&b)) {
- return b == kProxyPrefDefaultBoolean;
- } else if (value->IsType(Value::TYPE_STRING) &&
- value->GetAsString(&s)) {
- return s == kProxyPrefDefaultString;
- } else {
- NOTREACHED() << "Invalid type for a proxy preference.";
- return false;
- }
-}
-
-} // namespace
-
PrefProxyConfigTracker::PrefProxyConfigTracker(PrefService* pref_service)
: pref_service_(pref_service) {
valid_ = ReadPrefConfig(&pref_config_);
@@ -66,13 +40,13 @@ void PrefProxyConfigTracker::DetachFromPrefService() {
}
void PrefProxyConfigTracker::AddObserver(
- PrefProxyConfigTracker::ObserverInterface* observer) {
+ PrefProxyConfigTracker::Observer* observer) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
observers_.AddObserver(observer);
}
void PrefProxyConfigTracker::RemoveObserver(
- PrefProxyConfigTracker::ObserverInterface* observer) {
+ PrefProxyConfigTracker::Observer* observer) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
observers_.RemoveObserver(observer);
}
@@ -98,12 +72,11 @@ void PrefProxyConfigTracker::Observe(NotificationType type,
void PrefProxyConfigTracker::InstallProxyConfig(const net::ProxyConfig& config,
bool valid) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (valid_ != valid || !pref_config_.Equals(config)) {
+ if (valid_ != valid || (valid && !pref_config_.Equals(config))) {
valid_ = valid;
if (valid_)
pref_config_ = config;
- FOR_EACH_OBSERVER(ObserverInterface, observers_,
- OnPrefProxyConfigChanged());
+ FOR_EACH_OBSERVER(Observer, observers_, OnPrefProxyConfigChanged());
}
}
@@ -113,65 +86,62 @@ bool PrefProxyConfigTracker::ReadPrefConfig(net::ProxyConfig* config) {
// Clear the configuration.
*config = net::ProxyConfig();
- // Scan for all "enable" type proxy switches.
- static const char* proxy_prefs[] = {
- prefs::kProxyPacUrl,
- prefs::kProxyServer,
- prefs::kProxyBypassList,
- prefs::kProxyAutoDetect
- };
-
- // Check whether the preference system holds a valid proxy configuration. Note
- // that preferences coming from a lower-priority source than the user settings
- // are ignored. That's because chrome treats the system settings as the
- // default values, which should apply if there's no explicit value forced by
- // policy or the user.
- // Preferences that are set to their default values are also ignored,
- // regardless of their controlling source. This is because 'use system proxy
- // settings' is currently encoded by all the preferences being set to their
- // defaults. This will change when crbug.com/65732 is addressed.
- bool found_enable_proxy_pref = false;
- for (size_t i = 0; i < arraysize(proxy_prefs); i++) {
- const PrefService::Preference* pref =
- pref_service_->FindPreference(proxy_prefs[i]);
- DCHECK(pref);
- if (pref && (!pref->IsUserModifiable() || pref->HasUserSetting()) &&
- !IsDefaultValue(pref->GetValue())) {
- found_enable_proxy_pref = true;
- break;
- }
- }
-
- if (!found_enable_proxy_pref &&
- !pref_service_->GetBoolean(prefs::kNoProxyServer)) {
+ ProxyPrefs::ProxyMode mode;
+ int proxy_mode = pref_service_->GetInteger(prefs::kProxyMode);
+ if (!ProxyPrefs::IntToProxyMode(proxy_mode, &mode)) {
+ // Fall back to system settings if the mode preference is invalid.
return false;
}
- if (pref_service_->GetBoolean(prefs::kNoProxyServer)) {
- // Ignore all the other proxy config preferences if the use of a proxy
- // has been explicitly disabled.
- return true;
- }
-
- if (pref_service_->HasPrefPath(prefs::kProxyServer)) {
- std::string proxy_server = pref_service_->GetString(prefs::kProxyServer);
- config->proxy_rules().ParseFromString(proxy_server);
- }
-
- if (pref_service_->HasPrefPath(prefs::kProxyPacUrl)) {
- std::string proxy_pac = pref_service_->GetString(prefs::kProxyPacUrl);
- config->set_pac_url(GURL(proxy_pac));
- }
-
- config->set_auto_detect(pref_service_->GetBoolean(prefs::kProxyAutoDetect));
-
- if (pref_service_->HasPrefPath(prefs::kProxyBypassList)) {
- std::string proxy_bypass =
- pref_service_->GetString(prefs::kProxyBypassList);
- config->proxy_rules().bypass_rules.ParseFromString(proxy_bypass);
+ switch (mode) {
+ case ProxyPrefs::MODE_SYSTEM:
+ // Use system settings.
+ return false;
+ case ProxyPrefs::MODE_DIRECT:
+ // Ignore all the other proxy config preferences if the use of a proxy
+ // has been explicitly disabled.
+ return true;
+ case ProxyPrefs::MODE_AUTO_DETECT:
+ config->set_auto_detect(true);
+ return true;
+ case ProxyPrefs::MODE_PAC_SCRIPT: {
+ if (!pref_service_->HasPrefPath(prefs::kProxyPacUrl)) {
+ LOG(ERROR) << "Proxy settings request PAC script but do not specify "
+ << "its URL. Falling back to direct connection.";
+ return true;
+ }
+ std::string proxy_pac = pref_service_->GetString(prefs::kProxyPacUrl);
+ GURL proxy_pac_url(proxy_pac);
+ if (!proxy_pac_url.is_valid()) {
+ LOG(ERROR) << "Invalid proxy PAC url: " << proxy_pac;
+ return true;
+ }
+ config->set_pac_url(proxy_pac_url);
+ return true;
+ }
+ case ProxyPrefs::MODE_FIXED_SERVERS: {
+ if (!pref_service_->HasPrefPath(prefs::kProxyServer)) {
+ LOG(ERROR) << "Proxy settings request fixed proxy servers but do not "
+ << "specify their URLs. Falling back to direct connection.";
+ return true;
+ }
+ std::string proxy_server =
+ pref_service_->GetString(prefs::kProxyServer);
+ config->proxy_rules().ParseFromString(proxy_server);
+
+ if (pref_service_->HasPrefPath(prefs::kProxyBypassList)) {
+ std::string proxy_bypass =
+ pref_service_->GetString(prefs::kProxyBypassList);
+ config->proxy_rules().bypass_rules.ParseFromString(proxy_bypass);
+ }
+ return true;
+ }
+ case ProxyPrefs::kModeCount: {
+ // Fall through to NOTREACHED().
+ }
}
-
- return true;
+ NOTREACHED() << "Unknown proxy mode, falling back to system settings.";
+ return false;
}
PrefProxyConfigService::PrefProxyConfigService(
@@ -202,9 +172,11 @@ void PrefProxyConfigService::RemoveObserver(
bool PrefProxyConfigService::GetLatestProxyConfig(net::ProxyConfig* config) {
RegisterObservers();
- const net::ProxyConfig pref_config;
- if (pref_config_tracker_->GetProxyConfig(config))
+ net::ProxyConfig pref_config;
+ if (pref_config_tracker_->GetProxyConfig(&pref_config)) {
+ *config = pref_config;
return true;
+ }
return base_service_->GetLatestProxyConfig(config);
}
@@ -257,14 +229,8 @@ void PrefProxyConfigService::RegisterObservers() {
// static
void PrefProxyConfigService::RegisterUserPrefs(
PrefService* pref_service) {
- pref_service->RegisterBooleanPref(prefs::kNoProxyServer,
- kProxyPrefDefaultBoolean);
- pref_service->RegisterBooleanPref(prefs::kProxyAutoDetect,
- kProxyPrefDefaultBoolean);
- pref_service->RegisterStringPref(prefs::kProxyServer,
- kProxyPrefDefaultString);
- pref_service->RegisterStringPref(prefs::kProxyPacUrl,
- kProxyPrefDefaultString);
- pref_service->RegisterStringPref(prefs::kProxyBypassList,
- kProxyPrefDefaultString);
+ pref_service->RegisterIntegerPref(prefs::kProxyMode, ProxyPrefs::MODE_SYSTEM);
+ pref_service->RegisterStringPref(prefs::kProxyServer, "");
+ pref_service->RegisterStringPref(prefs::kProxyPacUrl, "");
+ pref_service->RegisterStringPref(prefs::kProxyBypassList, "");
}
diff --git a/chrome/browser/net/pref_proxy_config_service.h b/chrome/browser/net/pref_proxy_config_service.h
index fe917bb..a0f6cd0 100644
--- a/chrome/browser/net/pref_proxy_config_service.h
+++ b/chrome/browser/net/pref_proxy_config_service.h
@@ -26,9 +26,9 @@ class PrefProxyConfigTracker
public:
// Observer interface used to send out notifications on the IO thread about
// changes to the proxy configuration.
- class ObserverInterface {
+ class Observer {
public:
- virtual ~ObserverInterface() {}
+ virtual ~Observer() {}
virtual void OnPrefProxyConfigChanged() = 0;
};
@@ -36,8 +36,8 @@ class PrefProxyConfigTracker
virtual ~PrefProxyConfigTracker();
// Observer manipulation is only valid on the IO thread.
- void AddObserver(ObserverInterface* observer);
- void RemoveObserver(ObserverInterface* observer);
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
// Get the proxy configuration currently defined by preferences. Writes the
// configuration to |config| and returns true on success. |config| is not
@@ -68,14 +68,14 @@ class PrefProxyConfigTracker
bool ReadPrefConfig(net::ProxyConfig* config);
// Configuration as defined by prefs. Only to be accessed from the IO thread
- // (expect for construction).
+ // (except for construction).
net::ProxyConfig pref_config_;
// Whether |pref_config_| is valid. Only accessed from the IO thread.
bool valid_;
// List of observers, accessed exclusively from the IO thread.
- ObserverList<ObserverInterface, true> observers_;
+ ObserverList<Observer, true> observers_;
// Pref-related members that should only be accessed from the UI thread.
PrefService* pref_service_;
@@ -90,7 +90,7 @@ class PrefProxyConfigTracker
class PrefProxyConfigService
: public net::ProxyConfigService,
public net::ProxyConfigService::Observer,
- public PrefProxyConfigTracker::ObserverInterface {
+ public PrefProxyConfigTracker::Observer {
public:
// Takes ownership of the passed |base_service|.
PrefProxyConfigService(PrefProxyConfigTracker* tracker,
diff --git a/chrome/browser/net/pref_proxy_config_service_unittest.cc b/chrome/browser/net/pref_proxy_config_service_unittest.cc
index fd24dd6..dad5c53 100644
--- a/chrome/browser/net/pref_proxy_config_service_unittest.cc
+++ b/chrome/browser/net/pref_proxy_config_service_unittest.cc
@@ -7,6 +7,8 @@
#include "base/command_line.h"
#include "base/file_path.h"
#include "chrome/browser/net/chrome_url_request_context.h"
+#include "chrome/browser/prefs/pref_service_mock_builder.h"
+#include "chrome/browser/prefs/proxy_prefs.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_pref_service.h"
@@ -65,12 +67,12 @@ class PrefProxyConfigServiceTestBase : public TESTBASE {
: ui_thread_(BrowserThread::UI, &loop_),
io_thread_(BrowserThread::IO, &loop_) {}
- virtual void SetUp() {
- ASSERT_TRUE(pref_service_.get());
- PrefProxyConfigService::RegisterUserPrefs(pref_service_.get());
+ virtual void Init(PrefService* pref_service) {
+ ASSERT_TRUE(pref_service);
+ PrefProxyConfigService::RegisterUserPrefs(pref_service);
fixed_config_.set_pac_url(GURL(kFixedPacUrl));
delegate_service_ = new TestProxyConfigService(fixed_config_);
- proxy_config_tracker_ = new PrefProxyConfigTracker(pref_service_.get());
+ proxy_config_tracker_ = new PrefProxyConfigTracker(pref_service);
proxy_config_service_.reset(
new PrefProxyConfigService(proxy_config_tracker_.get(),
delegate_service_));
@@ -80,12 +82,10 @@ class PrefProxyConfigServiceTestBase : public TESTBASE {
proxy_config_tracker_->DetachFromPrefService();
loop_.RunAllPending();
proxy_config_service_.reset();
- pref_service_.reset();
}
MessageLoop loop_;
TestProxyConfigService* delegate_service_; // weak
- scoped_ptr<TestingPrefService> pref_service_;
scoped_ptr<PrefProxyConfigService> proxy_config_service_;
net::ProxyConfig fixed_config_;
@@ -99,9 +99,11 @@ class PrefProxyConfigServiceTest
: public PrefProxyConfigServiceTestBase<testing::Test> {
protected:
virtual void SetUp() {
- pref_service_.reset(new TestingPrefService);
- PrefProxyConfigServiceTestBase<testing::Test>::SetUp();
+ pref_service_.reset(new TestingPrefService());
+ Init(pref_service_.get());
}
+
+ scoped_ptr<TestingPrefService> pref_service_;
};
TEST_F(PrefProxyConfigServiceTest, BaseConfiguration) {
@@ -113,6 +115,9 @@ TEST_F(PrefProxyConfigServiceTest, BaseConfiguration) {
TEST_F(PrefProxyConfigServiceTest, DynamicPrefOverrides) {
pref_service_->SetManagedPref(
prefs::kProxyServer, Value::CreateStringValue("http://example.com:3128"));
+ pref_service_->SetManagedPref(
+ prefs::kProxyMode,
+ Value::CreateIntegerValue(ProxyPrefs::MODE_FIXED_SERVERS));
loop_.RunAllPending();
net::ProxyConfig actual_config;
@@ -125,7 +130,8 @@ TEST_F(PrefProxyConfigServiceTest, DynamicPrefOverrides) {
net::ProxyServer::SCHEME_HTTP));
pref_service_->SetManagedPref(
- prefs::kProxyAutoDetect, Value::CreateBooleanValue(true));
+ prefs::kProxyMode,
+ Value::CreateIntegerValue(ProxyPrefs::MODE_AUTO_DETECT));
loop_.RunAllPending();
proxy_config_service_->GetLatestProxyConfig(&actual_config);
@@ -155,10 +161,20 @@ TEST_F(PrefProxyConfigServiceTest, Observers) {
// Override configuration, this should trigger a notification.
net::ProxyConfig pref_config;
pref_config.set_pac_url(GURL(kFixedPacUrl));
+
EXPECT_CALL(observer,
OnProxyConfigChanged(ProxyConfigMatches(pref_config))).Times(1);
+
pref_service_->SetManagedPref(prefs::kProxyPacUrl,
Value::CreateStringValue(kFixedPacUrl));
+ // The above does not trigger a notification, because PrefProxyConfig still
+ // sees the mode as the default (ProxyPrefs::SYSTEM), so that it doesn't claim
+ // to have proxy config.
+ // TODO(battre): Remove this comment when http://crbug.com/65732 is
+ // resolved.
+ pref_service_->SetManagedPref(
+ prefs::kProxyMode,
+ Value::CreateIntegerValue(ProxyPrefs::MODE_PAC_SCRIPT));
loop_.RunAllPending();
Mock::VerifyAndClearExpectations(&observer);
@@ -174,6 +190,11 @@ TEST_F(PrefProxyConfigServiceTest, Observers) {
// Clear the override should switch back to the fixed configuration.
EXPECT_CALL(observer,
OnProxyConfigChanged(ProxyConfigMatches(config3))).Times(1);
+ pref_service_->RemoveManagedPref(prefs::kProxyMode);
+ // The above switches the mode to the default (ProxyPrefs::SYSTEM), so the
+ // next removal won't bother PrefProxyConfigService.
+ // TODO(battre): Remove this comment when http://crbug.com/65732 is
+ // completed.
pref_service_->RemoveManagedPref(prefs::kProxyPacUrl);
loop_.RunAllPending();
Mock::VerifyAndClearExpectations(&observer);
@@ -240,13 +261,14 @@ class PrefProxyConfigServiceCommandLineTest
else if (name)
command_line_.AppendSwitch(name);
}
- pref_service_.reset(new TestingPrefService(NULL, NULL, &command_line_));
- PrefProxyConfigServiceTestBase<
- testing::TestWithParam<CommandLineTestParams> >::SetUp();
+ pref_service_.reset(
+ PrefServiceMockBuilder().WithCommandLine(&command_line_).Create());
+ Init(pref_service_.get());
}
private:
CommandLine command_line_;
+ scoped_ptr<PrefService> pref_service_;
};
TEST_P(PrefProxyConfigServiceCommandLineTest, CommandLine) {
@@ -348,19 +370,16 @@ static const CommandLineTestParams kCommandLineTestParams[] = {
"*.google.com,foo.com:99,1.2.3.4:22,127.0.0.1/8"),
},
{
- "Pac URL with proxy bypass URLs",
+ "Pac URL",
// Input
{
{ switches::kProxyPacUrl, "http://wpad/wpad.dat" },
- { switches::kProxyBypassList,
- ".google.com, foo.com:99, 1.2.3.4:22, 127.0.0.1/8" },
},
// Expected result
false, // is_null
false, // auto_detect
GURL("http://wpad/wpad.dat"), // pac_url
- net::ProxyRulesExpectation::EmptyWithBypass(
- "*.google.com,foo.com:99,1.2.3.4:22,127.0.0.1/8"),
+ net::ProxyRulesExpectation::Empty(),
},
{
"Autodetect",
diff --git a/chrome/browser/net/prerender_interceptor.cc b/chrome/browser/net/prerender_interceptor.cc
deleted file mode 100644
index c1e5698..0000000
--- a/chrome/browser/net/prerender_interceptor.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-// 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.
-
-#include "chrome/browser/net/prerender_interceptor.h"
-
-#include <string>
-
-#include "base/logging.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/io_thread.h"
-#include "googleurl/src/gurl.h"
-#include "net/base/load_flags.h"
-
-DISABLE_RUNNABLE_METHOD_REFCOUNT(chrome_browser_net::PrerenderInterceptor);
-
-namespace chrome_browser_net {
-
-PrerenderInterceptor::PrerenderInterceptor()
- : ALLOW_THIS_IN_INITIALIZER_LIST(
- callback_(NewCallback(this,
- &PrerenderInterceptor::PrerenderDispatch))) {
- URLRequest::RegisterRequestInterceptor(this);
-}
-
-PrerenderInterceptor::PrerenderInterceptor(
- PrerenderInterceptorCallback* callback)
- : callback_(callback) {
- URLRequest::RegisterRequestInterceptor(this);
-}
-
-PrerenderInterceptor::~PrerenderInterceptor() {
- URLRequest::UnregisterRequestInterceptor(this);
-}
-
-net::URLRequestJob* PrerenderInterceptor::MaybeIntercept(
- net::URLRequest* request) {
- return NULL;
-}
-
-net::URLRequestJob* PrerenderInterceptor::MaybeInterceptResponse(
- net::URLRequest* request) {
- // TODO(gavinp): unfortunately, we can't figure out the origin
- // of this request here on systems where the referrer is blocked by
- // configuration.
-
- // TODO(gavinp): note that the response still might be intercepted
- // by a later interceptor. Should we write an interposing delegate
- // and only prerender dispatch on requests that aren't intercepted?
- // Or is this a slippery slope?
-
- if (request->load_flags() & net::LOAD_PREFETCH) {
- std::string mime_type;
- request->GetMimeType(&mime_type);
- if (mime_type == "text/html")
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- NewRunnableMethod(this,
- &PrerenderInterceptor::RunCallbackFromUIThread,
- request->url()));
- }
- return NULL;
-}
-
-void PrerenderInterceptor::RunCallbackFromUIThread(const GURL& url) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- callback_->Run(url);
-}
-
-void PrerenderInterceptor::PrerenderDispatch(
- const GURL& url) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DVLOG(2) << "PrerenderDispatchOnUIThread: url=" << url;
-}
-
-} // namespace chrome_browser_net
-
diff --git a/chrome/browser/net/prerender_interceptor.h b/chrome/browser/net/prerender_interceptor.h
deleted file mode 100644
index 02cdbff..0000000
--- a/chrome/browser/net/prerender_interceptor.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_NET_PRERENDER_INTERCEPTOR_H_
-#define CHROME_BROWSER_NET_PRERENDER_INTERCEPTOR_H_
-
-#include "base/basictypes.h"
-#include "base/callback.h"
-#include "base/scoped_ptr.h"
-#include "base/task.h"
-#include "net/url_request/url_request.h"
-
-class GURL;
-
-namespace chrome_browser_net {
-
-// The PrerenderInterceptor watches prefetch requests, and when
-// they are for type text/html, notifies the prerendering
-// system about the fetch so it may consider the URL.
-class PrerenderInterceptor : public URLRequest::Interceptor {
- public:
- PrerenderInterceptor();
- virtual ~PrerenderInterceptor();
-
- // URLRequest::Interceptor overrides. We only care about
- // MaybeInterceptResponse, but must capture MaybeIntercept since
- // it is pure virtual.
- virtual net::URLRequestJob* MaybeIntercept(net::URLRequest* request);
- virtual net::URLRequestJob* MaybeInterceptResponse(net::URLRequest* request);
-
- private:
- friend class PrerenderInterceptorTest;
-
- typedef Callback1<const GURL&>::Type PrerenderInterceptorCallback;
-
- // This constructor is provided for the unit test only, to provide
- // an an alternative dispatch target for the test only. The callback
- // parameter is owned and deleted by this object.
- explicit PrerenderInterceptor(PrerenderInterceptorCallback* callback);
-
- void RunCallbackFromUIThread(const GURL& url);
- void PrerenderDispatch(const GURL& url);
-
- scoped_ptr<PrerenderInterceptorCallback> callback_;
-
- DISALLOW_COPY_AND_ASSIGN(PrerenderInterceptor);
-};
-
-} // namespace chrome_browser_net
-
-#endif // CHROME_BROWSER_NET_PRERENDER_INTERCEPTOR_H_
-
diff --git a/chrome/browser/net/prerender_interceptor_unittest.cc b/chrome/browser/net/prerender_interceptor_unittest.cc
deleted file mode 100644
index 55e5a31..0000000
--- a/chrome/browser/net/prerender_interceptor_unittest.cc
+++ /dev/null
@@ -1,107 +0,0 @@
-// 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.
-
-#include "chrome/browser/net/prerender_interceptor.h"
-
-#include <string>
-
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "base/file_path.h"
-#include "base/message_loop_proxy.h"
-#include "base/scoped_ptr.h"
-#include "chrome/browser/browser_thread.h"
-#include "googleurl/src/gurl.h"
-#include "net/base/load_flags.h"
-#include "net/test/test_server.h"
-#include "net/url_request/url_request_unittest.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace chrome_browser_net {
-
-class PrerenderInterceptorTest : public testing::Test {
- protected:
- PrerenderInterceptorTest();
-
- void MakeTestUrl(const std::string& base);
- virtual void SetUp();
-
- net::TestServer test_server_;
- GURL gurl_;
- GURL last_intercepted_gurl_;
- scoped_ptr<URLRequest> req_;
-
- private:
- void SetLastInterceptedGurl(const GURL& url);
-
- PrerenderInterceptor prerender_interceptor_;
- MessageLoopForIO io_loop_;
- scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
- BrowserThread ui_thread_;
- TestDelegate delegate_;
-};
-
-PrerenderInterceptorTest::PrerenderInterceptorTest()
- : test_server_(net::TestServer::TYPE_HTTP,
- FilePath(FILE_PATH_LITERAL("chrome/test/data"))),
- last_intercepted_gurl_("http://not.initialized/"),
- ALLOW_THIS_IN_INITIALIZER_LIST(
- prerender_interceptor_(
- NewCallback(this,
- &PrerenderInterceptorTest::SetLastInterceptedGurl))),
- ui_thread_(BrowserThread::UI, &io_loop_) {
-}
-
-void PrerenderInterceptorTest::SetUp() {
- testing::Test::SetUp();
- last_intercepted_gurl_ = GURL("http://nothing.intercepted/");
-
- io_message_loop_proxy_ = base::MessageLoopProxy::CreateForCurrentThread();
- ASSERT_TRUE(test_server_.Start());
-}
-
-void PrerenderInterceptorTest::MakeTestUrl(const std::string& base) {
- gurl_ = test_server_.GetURL(base);
- req_.reset(new TestURLRequest(gurl_, &delegate_));
-}
-
-void PrerenderInterceptorTest::SetLastInterceptedGurl(const GURL& url) {
- last_intercepted_gurl_ = url;
-}
-
-namespace {
-
-TEST_F(PrerenderInterceptorTest, Interception) {
- MakeTestUrl("files/prerender/doc1.html");
- req_->set_load_flags(req_->load_flags() | net::LOAD_PREFETCH);
- req_->Start();
-
- MessageLoop::current()->Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, req_->status().status());
- EXPECT_EQ(gurl_, last_intercepted_gurl_);
-}
-
-TEST_F(PrerenderInterceptorTest, NotAPrefetch) {
- MakeTestUrl("files/prerender/doc2.html");
- req_->set_load_flags(req_->load_flags() & ~net::LOAD_PREFETCH);
- req_->Start();
-
- MessageLoop::current()->Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, req_->status().status());
- EXPECT_NE(gurl_, last_intercepted_gurl_);
-}
-
-TEST_F(PrerenderInterceptorTest, WrongMimeType) {
- MakeTestUrl("files/prerender/image.jpeg");
- req_->set_load_flags(req_->load_flags() | net::LOAD_PREFETCH);
- req_->Start();
-
- MessageLoop::current()->Run();
- EXPECT_EQ(URLRequestStatus::SUCCESS, req_->status().status());
- EXPECT_NE(gurl_, last_intercepted_gurl_);
-}
-
-} // namespace
-
-} // namespace chrome_browser_net
diff --git a/chrome/browser/net/resolve_proxy_msg_helper.cc b/chrome/browser/net/resolve_proxy_msg_helper.cc
index 3ceab9a..967e529 100644
--- a/chrome/browser/net/resolve_proxy_msg_helper.cc
+++ b/chrome/browser/net/resolve_proxy_msg_helper.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/net/resolve_proxy_msg_helper.h"
#include "base/compiler_specific.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/net/url_request_context_getter.h"
#include "net/base/net_errors.h"
#include "net/url_request/url_request_context.h"
diff --git a/chrome/browser/net/sdch_dictionary_fetcher.cc b/chrome/browser/net/sdch_dictionary_fetcher.cc
index 04542a6..696d311 100644
--- a/chrome/browser/net/sdch_dictionary_fetcher.cc
+++ b/chrome/browser/net/sdch_dictionary_fetcher.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/net/sdch_dictionary_fetcher.h"
#include "base/compiler_specific.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "net/url_request/url_request_status.h"
SdchDictionaryFetcher::SdchDictionaryFetcher()
diff --git a/chrome/browser/net/sqlite_persistent_cookie_store.cc b/chrome/browser/net/sqlite_persistent_cookie_store.cc
index db116b8..5a64979 100644
--- a/chrome/browser/net/sqlite_persistent_cookie_store.cc
+++ b/chrome/browser/net/sqlite_persistent_cookie_store.cc
@@ -6,9 +6,11 @@
#include <list>
+#include "app/sql/meta_table.h"
#include "app/sql/statement.h"
#include "app/sql/transaction.h"
#include "base/basictypes.h"
+#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
@@ -51,6 +53,7 @@ using base::Time;
class SQLitePersistentCookieStore::Backend
: public base::RefCountedThreadSafe<SQLitePersistentCookieStore::Backend> {
public:
+<<<<<<< HEAD
// The passed database pointer must be already-initialized. This object will
// take ownership.
explicit Backend(sql::Connection* db)
@@ -61,8 +64,18 @@ class SQLitePersistentCookieStore::Backend
#endif
{
DCHECK(db_) << "Database must exist.";
+=======
+ explicit Backend(const FilePath& path)
+ : path_(path),
+ db_(NULL),
+ num_pending_(0),
+ clear_local_state_on_exit_(false) {
+>>>>>>> chromium.org at r10.0.621.0
}
+ // Creates or load the SQLite database.
+ bool Load(std::vector<net::CookieMonster::CanonicalCookie*>* cookies);
+
// Batch a cookie addition.
void AddCookie(const net::CookieMonster::CanonicalCookie& cc);
@@ -72,29 +85,41 @@ class SQLitePersistentCookieStore::Backend
// Batch a cookie deletion.
void DeleteCookie(const net::CookieMonster::CanonicalCookie& cc);
+<<<<<<< HEAD
#if defined(ANDROID)
// Commit pending operations as soon as possible.
void Flush(Task* completion_task);
#endif
+=======
+ // Commit pending operations as soon as possible.
+ void Flush(Task* completion_task);
+>>>>>>> chromium.org at r10.0.621.0
// Commit any pending operations and close the database. This must be called
// before the object is destructed.
void Close();
+<<<<<<< HEAD
#if defined(ANDROID)
int get_cookie_count() const { return cookie_count_; }
void set_cookie_count(int count) { cookie_count_ = count; }
#endif
+=======
+ void SetClearLocalStateOnExit(bool clear_local_state);
+>>>>>>> chromium.org at r10.0.621.0
private:
friend class base::RefCountedThreadSafe<SQLitePersistentCookieStore::Backend>;
// You should call Close() before destructing this object.
~Backend() {
- DCHECK(!db_) << "Close should have already been called.";
+ DCHECK(!db_.get()) << "Close should have already been called.";
DCHECK(num_pending_ == 0 && pending_.empty());
}
+ // Database upgrade statements.
+ bool EnsureDatabaseVersion();
+
class PendingOperation {
public:
typedef enum {
@@ -128,12 +153,17 @@ class SQLitePersistentCookieStore::Backend
// Close() executed on the background thread.
void InternalBackgroundClose();
- sql::Connection* db_;
+ FilePath path_;
+ scoped_ptr<sql::Connection> db_;
+ sql::MetaTable meta_table_;
typedef std::list<PendingOperation*> PendingOperationsList;
PendingOperationsList pending_;
PendingOperationsList::size_type num_pending_;
- Lock pending_lock_; // Guard pending_ and num_pending_
+ // True if the persistent store should be deleted upon destruction.
+ bool clear_local_state_on_exit_;
+ // Guard |pending_|, |num_pending_| and |clear_local_state_on_exit_|.
+ Lock lock_;
#if defined(ANDROID)
// Number of cookies that have actually been saved. Updated during Commit().
@@ -143,6 +173,171 @@ class SQLitePersistentCookieStore::Backend
DISALLOW_COPY_AND_ASSIGN(Backend);
};
+// Version number of the database. In version 4, we migrated the time epoch.
+// If you open the DB with an older version on Mac or Linux, the times will
+// look wonky, but the file will likely be usable. On Windows version 3 and 4
+// are the same.
+//
+// Version 3 updated the database to include the last access time, so we can
+// expire them in decreasing order of use when we've reached the maximum
+// number of cookies.
+static const int kCurrentVersionNumber = 4;
+static const int kCompatibleVersionNumber = 3;
+
+namespace {
+
+// Initializes the cookies table, returning true on success.
+bool InitTable(sql::Connection* db) {
+ if (!db->DoesTableExist("cookies")) {
+ if (!db->Execute("CREATE TABLE cookies ("
+ "creation_utc INTEGER NOT NULL UNIQUE PRIMARY KEY,"
+ "host_key TEXT NOT NULL,"
+ "name TEXT NOT NULL,"
+ "value TEXT NOT NULL,"
+ "path TEXT NOT NULL,"
+ // We only store persistent, so we know it expires
+ "expires_utc INTEGER NOT NULL,"
+ "secure INTEGER NOT NULL,"
+ "httponly INTEGER NOT NULL,"
+ "last_access_utc INTEGER NOT NULL)"))
+ return false;
+ }
+
+ // Try to create the index every time. Older versions did not have this index,
+ // so we want those people to get it. Ignore errors, since it may exist.
+ db->Execute("CREATE INDEX cookie_times ON cookies (creation_utc)");
+ return true;
+}
+
+} // namespace
+
+bool SQLitePersistentCookieStore::Backend::Load(
+ std::vector<net::CookieMonster::CanonicalCookie*>* cookies) {
+ // This function should be called only once per instance.
+ DCHECK(!db_.get());
+
+ db_.reset(new sql::Connection);
+ if (!db_->Open(path_)) {
+ NOTREACHED() << "Unable to open cookie DB.";
+ db_.reset();
+ return false;
+ }
+
+ db_->set_error_delegate(GetErrorHandlerForCookieDb());
+
+ if (!EnsureDatabaseVersion() || !InitTable(db_.get())) {
+ NOTREACHED() << "Unable to open cookie DB.";
+ db_.reset();
+ return false;
+ }
+
+ db_->Preload();
+
+ // Slurp all the cookies into the out-vector.
+ sql::Statement smt(db_->GetUniqueStatement(
+ "SELECT creation_utc, host_key, name, value, path, expires_utc, secure, "
+ "httponly, last_access_utc FROM cookies"));
+ if (!smt) {
+ NOTREACHED() << "select statement prep failed";
+ db_.reset();
+ return false;
+ }
+
+ while (smt.Step()) {
+ scoped_ptr<net::CookieMonster::CanonicalCookie> cc(
+ new net::CookieMonster::CanonicalCookie(
+ smt.ColumnString(2), // name
+ smt.ColumnString(3), // value
+ smt.ColumnString(1), // domain
+ smt.ColumnString(4), // path
+ smt.ColumnInt(6) != 0, // secure
+ smt.ColumnInt(7) != 0, // httponly
+ Time::FromInternalValue(smt.ColumnInt64(0)), // creation_utc
+ Time::FromInternalValue(smt.ColumnInt64(8)), // last_access_utc
+ true, // has_expires
+ Time::FromInternalValue(smt.ColumnInt64(5)))); // expires_utc
+ DLOG_IF(WARNING,
+ cc->CreationDate() > Time::Now()) << L"CreationDate too recent";
+ cookies->push_back(cc.release());
+ }
+
+ return true;
+}
+
+bool SQLitePersistentCookieStore::Backend::EnsureDatabaseVersion() {
+ // Version check.
+ if (!meta_table_.Init(
+ db_.get(), kCurrentVersionNumber, kCompatibleVersionNumber)) {
+ return false;
+ }
+
+ if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) {
+ LOG(WARNING) << "Cookie database is too new.";
+ return false;
+ }
+
+ int cur_version = meta_table_.GetVersionNumber();
+ if (cur_version == 2) {
+ sql::Transaction transaction(db_.get());
+ if (!transaction.Begin())
+ return false;
+ if (!db_->Execute("ALTER TABLE cookies ADD COLUMN last_access_utc "
+ "INTEGER DEFAULT 0") ||
+ !db_->Execute("UPDATE cookies SET last_access_utc = creation_utc")) {
+ LOG(WARNING) << "Unable to update cookie database to version 3.";
+ return false;
+ }
+ ++cur_version;
+ meta_table_.SetVersionNumber(cur_version);
+ meta_table_.SetCompatibleVersionNumber(
+ std::min(cur_version, kCompatibleVersionNumber));
+ transaction.Commit();
+ }
+
+ if (cur_version == 3) {
+ // The time epoch changed for Mac & Linux in this version to match Windows.
+ // This patch came after the main epoch change happened, so some
+ // developers have "good" times for cookies added by the more recent
+ // versions. So we have to be careful to only update times that are under
+ // the old system (which will appear to be from before 1970 in the new
+ // system). The magic number used below is 1970 in our time units.
+ sql::Transaction transaction(db_.get());
+ transaction.Begin();
+#if !defined(OS_WIN)
+ db_->Execute(
+ "UPDATE cookies "
+ "SET creation_utc = creation_utc + 11644473600000000 "
+ "WHERE rowid IN "
+ "(SELECT rowid FROM cookies WHERE "
+ "creation_utc > 0 AND creation_utc < 11644473600000000)");
+ db_->Execute(
+ "UPDATE cookies "
+ "SET expires_utc = expires_utc + 11644473600000000 "
+ "WHERE rowid IN "
+ "(SELECT rowid FROM cookies WHERE "
+ "expires_utc > 0 AND expires_utc < 11644473600000000)");
+ db_->Execute(
+ "UPDATE cookies "
+ "SET last_access_utc = last_access_utc + 11644473600000000 "
+ "WHERE rowid IN "
+ "(SELECT rowid FROM cookies WHERE "
+ "last_access_utc > 0 AND last_access_utc < 11644473600000000)");
+#endif
+ ++cur_version;
+ meta_table_.SetVersionNumber(cur_version);
+ transaction.Commit();
+ }
+
+ // Put future migration cases here.
+
+ // When the version is too old, we just try to continue anyway, there should
+ // not be a released product that makes a database too old for us to handle.
+ LOG_IF(WARNING, cur_version < kCurrentVersionNumber) <<
+ "Cookie database version " << cur_version << " is too old to handle.";
+
+ return true;
+}
+
void SQLitePersistentCookieStore::Backend::AddCookie(
const net::CookieMonster::CanonicalCookie& cc) {
BatchOperation(PendingOperation::COOKIE_ADD, cc);
@@ -174,7 +369,7 @@ void SQLitePersistentCookieStore::Backend::BatchOperation(
PendingOperationsList::size_type num_pending;
{
- AutoLock locked(pending_lock_);
+ AutoLock locked(lock_);
pending_.push_back(po.release());
num_pending = ++num_pending_;
}
@@ -213,6 +408,7 @@ void SQLitePersistentCookieStore::Backend::Commit(Task* completion_task) {
#else
void SQLitePersistentCookieStore::Backend::Commit() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+<<<<<<< HEAD
#endif
#if defined(ANDROID)
@@ -221,16 +417,18 @@ void SQLitePersistentCookieStore::Backend::Commit() {
MessageLoop::current()->PostTask(FROM_HERE, completion_task);
}
#endif
+=======
+>>>>>>> chromium.org at r10.0.621.0
PendingOperationsList ops;
{
- AutoLock locked(pending_lock_);
+ AutoLock locked(lock_);
pending_.swap(ops);
num_pending_ = 0;
}
// Maybe an old timer fired or we are already Close()'ed.
- if (!db_ || ops.empty())
+ if (!db_.get() || ops.empty())
return;
sql::Statement add_smt(db_->GetCachedStatement(SQL_FROM_HERE,
@@ -256,7 +454,7 @@ void SQLitePersistentCookieStore::Backend::Commit() {
return;
}
- sql::Transaction transaction(db_);
+ sql::Transaction transaction(db_.get());
if (!transaction.Begin()) {
NOTREACHED();
return;
@@ -321,6 +519,7 @@ void SQLitePersistentCookieStore::Backend::Commit() {
succeeded ? 0 : 1, 2);
}
+<<<<<<< HEAD
#if defined(ANDROID)
void SQLitePersistentCookieStore::Backend::Flush(Task* completion_task) {
// Keep this #ifdef when upstreaming to Chromium.
@@ -342,6 +541,19 @@ void SQLitePersistentCookieStore::Backend::Flush(Task* completion_task) {
#endif
}
#endif
+=======
+void SQLitePersistentCookieStore::Backend::Flush(Task* completion_task) {
+ DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::DB));
+ BrowserThread::PostTask(
+ BrowserThread::DB, FROM_HERE, NewRunnableMethod(this, &Backend::Commit));
+ if (completion_task) {
+ // We want the completion task to run immediately after Commit() returns.
+ // Posting it from here means there is less chance of another task getting
+ // onto the message queue first, than if we posted it from Commit() itself.
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, completion_task);
+ }
+}
+>>>>>>> chromium.org at r10.0.621.0
// Fire off a close message to the background thread. We could still have a
// pending commit timer that will be holding a reference on us, but if/when
@@ -375,13 +587,26 @@ void SQLitePersistentCookieStore::Backend::InternalBackgroundClose() {
Commit(NULL);
#else
Commit();
+<<<<<<< HEAD
#endif
delete db_;
db_ = NULL;
+=======
+
+ db_.reset();
+
+ if (clear_local_state_on_exit_)
+ file_util::Delete(path_, false);
+>>>>>>> chromium.org at r10.0.621.0
}
+void SQLitePersistentCookieStore::Backend::SetClearLocalStateOnExit(
+ bool clear_local_state) {
+ AutoLock locked(lock_);
+ clear_local_state_on_exit_ = clear_local_state;
+}
SQLitePersistentCookieStore::SQLitePersistentCookieStore(const FilePath& path)
- : path_(path) {
+ : backend_(new Backend(path)) {
}
SQLitePersistentCookieStore::~SQLitePersistentCookieStore() {
@@ -393,6 +618,7 @@ SQLitePersistentCookieStore::~SQLitePersistentCookieStore() {
}
}
+<<<<<<< HEAD
// Version number of the database. In version 4, we migrated the time epoch.
// If you open the DB with an older version on Mac or Linux, the times will
// look wonky, but the file will likely be usable. On Windows version 3 and 4
@@ -576,6 +802,11 @@ bool SQLitePersistentCookieStore::EnsureDatabaseVersion(sql::Connection* db) {
"Cookie database version " << cur_version << " is too old to handle.";
return true;
+=======
+bool SQLitePersistentCookieStore::Load(
+ std::vector<net::CookieMonster::CanonicalCookie*>* cookies) {
+ return backend_->Load(cookies);
+>>>>>>> chromium.org at r10.0.621.0
}
void SQLitePersistentCookieStore::AddCookie(
@@ -596,6 +827,7 @@ void SQLitePersistentCookieStore::DeleteCookie(
backend_->DeleteCookie(cc);
}
+<<<<<<< HEAD
#if defined(ANDROID)
void SQLitePersistentCookieStore::Flush(Task* completion_callback) {
if (backend_.get())
@@ -618,4 +850,17 @@ int SQLitePersistentCookieStore::GetCookieCount() {
void SQLitePersistentCookieStore::ClearLocalState(
const FilePath& path) {
file_util::Delete(path, false);
+=======
+void SQLitePersistentCookieStore::SetClearLocalStateOnExit(
+ bool clear_local_state) {
+ if (backend_.get())
+ backend_->SetClearLocalStateOnExit(clear_local_state);
+}
+
+void SQLitePersistentCookieStore::Flush(Task* completion_task) {
+ if (backend_.get())
+ backend_->Flush(completion_task);
+ else if (completion_task)
+ MessageLoop::current()->PostTask(FROM_HERE, completion_task);
+>>>>>>> chromium.org at r10.0.621.0
}
diff --git a/chrome/browser/net/sqlite_persistent_cookie_store.h b/chrome/browser/net/sqlite_persistent_cookie_store.h
index 9bccdeb..ef18830 100644
--- a/chrome/browser/net/sqlite_persistent_cookie_store.h
+++ b/chrome/browser/net/sqlite_persistent_cookie_store.h
@@ -11,30 +11,30 @@
#include <string>
#include <vector>
-#include "app/sql/meta_table.h"
-#include "base/file_path.h"
#include "base/ref_counted.h"
#include "net/base/cookie_monster.h"
-namespace sql {
-class Connection;
-}
-
class FilePath;
+// Implements the PersistentCookieStore interface in terms of a SQLite database.
+// For documentation about the actual member functions consult the documentation
+// of the parent class |net::CookieMonster::PersistentCookieStore|.
class SQLitePersistentCookieStore
: public net::CookieMonster::PersistentCookieStore {
public:
explicit SQLitePersistentCookieStore(const FilePath& path);
virtual ~SQLitePersistentCookieStore();
- virtual bool Load(std::vector<net::CookieMonster::CanonicalCookie*>*);
+ virtual bool Load(std::vector<net::CookieMonster::CanonicalCookie*>* cookies);
- virtual void AddCookie(const net::CookieMonster::CanonicalCookie&);
+ virtual void AddCookie(const net::CookieMonster::CanonicalCookie& cc);
virtual void UpdateCookieAccessTime(
- const net::CookieMonster::CanonicalCookie&);
- virtual void DeleteCookie(const net::CookieMonster::CanonicalCookie&);
+ const net::CookieMonster::CanonicalCookie& cc);
+ virtual void DeleteCookie(const net::CookieMonster::CanonicalCookie& cc);
+
+ virtual void SetClearLocalStateOnExit(bool clear_local_state);
+<<<<<<< HEAD
#if defined(ANDROID)
virtual void Flush(Task* completion_task);
#endif
@@ -44,18 +44,15 @@ class SQLitePersistentCookieStore
#endif
static void ClearLocalState(const FilePath& path);
+=======
+ virtual void Flush(Task* completion_task);
+>>>>>>> chromium.org at r10.0.621.0
private:
class Backend;
- // Database upgrade statements.
- bool EnsureDatabaseVersion(sql::Connection* db);
-
- FilePath path_;
scoped_refptr<Backend> backend_;
- sql::MetaTable meta_table_;
-
DISALLOW_COPY_AND_ASSIGN(SQLitePersistentCookieStore);
};
diff --git a/chrome/browser/net/sqlite_persistent_cookie_store_unittest.cc b/chrome/browser/net/sqlite_persistent_cookie_store_unittest.cc
new file mode 100644
index 0000000..4ce2e53
--- /dev/null
+++ b/chrome/browser/net/sqlite_persistent_cookie_store_unittest.cc
@@ -0,0 +1,178 @@
+// 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.
+
+#include "base/file_util.h"
+#include "base/message_loop.h"
+#include "base/ref_counted.h"
+#include "base/scoped_temp_dir.h"
+#include "base/stl_util-inl.h"
+#include "base/time.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/net/sqlite_persistent_cookie_store.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/test/thread_test_helper.h"
+#include "googleurl/src/gurl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class SQLitePersistentCookieStoreTest : public testing::Test {
+ public:
+ SQLitePersistentCookieStoreTest()
+ : ui_thread_(BrowserThread::UI),
+ db_thread_(BrowserThread::DB) {
+ }
+
+ protected:
+ virtual void SetUp() {
+ ui_thread_.Start();
+ db_thread_.Start();
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ store_ = new SQLitePersistentCookieStore(
+ temp_dir_.path().Append(chrome::kCookieFilename));
+ std::vector<net::CookieMonster::CanonicalCookie*> cookies;
+ ASSERT_TRUE(store_->Load(&cookies));
+ ASSERT_TRUE(0 == cookies.size());
+ // Make sure the store gets written at least once.
+ store_->AddCookie(
+ net::CookieMonster::CanonicalCookie("A", "B", "http://foo.bar", "/",
+ false, false,
+ base::Time::Now(),
+ base::Time::Now(),
+ true, base::Time::Now()));
+ }
+
+ BrowserThread ui_thread_;
+ BrowserThread db_thread_;
+ ScopedTempDir temp_dir_;
+ scoped_refptr<SQLitePersistentCookieStore> store_;
+};
+
+TEST_F(SQLitePersistentCookieStoreTest, KeepOnDestruction) {
+ store_->SetClearLocalStateOnExit(false);
+ store_ = NULL;
+ // Make sure we wait until the destructor has run.
+ scoped_refptr<ThreadTestHelper> helper(
+ new ThreadTestHelper(BrowserThread::DB));
+ ASSERT_TRUE(helper->Run());
+
+ ASSERT_TRUE(file_util::PathExists(
+ temp_dir_.path().Append(chrome::kCookieFilename)));
+ ASSERT_TRUE(file_util::Delete(
+ temp_dir_.path().Append(chrome::kCookieFilename), false));
+}
+
+TEST_F(SQLitePersistentCookieStoreTest, RemoveOnDestruction) {
+ store_->SetClearLocalStateOnExit(true);
+ // Replace the store effectively destroying the current one and forcing it
+ // to write it's data to disk. Then we can see if after loading it again it
+ // is still there.
+ store_ = NULL;
+ // Make sure we wait until the destructor has run.
+ scoped_refptr<ThreadTestHelper> helper(
+ new ThreadTestHelper(BrowserThread::DB));
+ ASSERT_TRUE(helper->Run());
+
+ ASSERT_FALSE(file_util::PathExists(
+ temp_dir_.path().Append(chrome::kCookieFilename)));
+}
+
+// Test if data is stored as expected in the SQLite database.
+TEST_F(SQLitePersistentCookieStoreTest, TestPersistance) {
+ std::vector<net::CookieMonster::CanonicalCookie*> cookies;
+ // Replace the store effectively destroying the current one and forcing it
+ // to write it's data to disk. Then we can see if after loading it again it
+ // is still there.
+ store_ = NULL;
+ scoped_refptr<ThreadTestHelper> helper(
+ new ThreadTestHelper(BrowserThread::DB));
+ // Make sure we wait until the destructor has run.
+ ASSERT_TRUE(helper->Run());
+ store_ = new SQLitePersistentCookieStore(
+ temp_dir_.path().Append(chrome::kCookieFilename));
+
+ // Reload and test for persistence
+ ASSERT_TRUE(store_->Load(&cookies));
+ ASSERT_EQ(1U, cookies.size());
+ ASSERT_STREQ("http://foo.bar", cookies[0]->Domain().c_str());
+ ASSERT_STREQ("A", cookies[0]->Name().c_str());
+ ASSERT_STREQ("B", cookies[0]->Value().c_str());
+
+ // Now delete the cookie and check persistence again.
+ store_->DeleteCookie(*cookies[0]);
+ store_ = NULL;
+ // Make sure we wait until the destructor has run.
+ ASSERT_TRUE(helper->Run());
+ STLDeleteContainerPointers(cookies.begin(), cookies.end());
+ cookies.clear();
+ store_ = new SQLitePersistentCookieStore(
+ temp_dir_.path().Append(chrome::kCookieFilename));
+
+ // Reload and check if the cookie has been removed.
+ ASSERT_TRUE(store_->Load(&cookies));
+ ASSERT_EQ(0U, cookies.size());
+}
+
+// Test that we can force the database to be written by calling Flush().
+TEST_F(SQLitePersistentCookieStoreTest, TestFlush) {
+ // File timestamps don't work well on all platforms, so we'll determine
+ // whether the DB file has been modified by checking its size.
+ FilePath path = temp_dir_.path().Append(chrome::kCookieFilename);
+ base::PlatformFileInfo info;
+ ASSERT_TRUE(file_util::GetFileInfo(path, &info));
+ int64 base_size = info.size;
+
+ // Write some large cookies, so the DB will have to expand by several KB.
+ for (char c = 'a'; c < 'z'; ++c) {
+ // Each cookie needs a unique timestamp for creation_utc (see DB schema).
+ base::Time t = base::Time::Now() + base::TimeDelta::FromMicroseconds(c);
+ std::string name(1, c);
+ std::string value(1000, c);
+ store_->AddCookie(
+ net::CookieMonster::CanonicalCookie(name, value, "http://foo.bar", "/",
+ false, false, t, t, true, t));
+ }
+
+ // Call Flush() and wait until the DB thread is idle.
+ store_->Flush(NULL);
+ scoped_refptr<ThreadTestHelper> helper(
+ new ThreadTestHelper(BrowserThread::DB));
+ ASSERT_TRUE(helper->Run());
+
+ // We forced a write, so now the file will be bigger.
+ ASSERT_TRUE(file_util::GetFileInfo(path, &info));
+ ASSERT_GT(info.size, base_size);
+}
+
+// Counts the number of times Callback() has been run.
+class CallbackCounter : public base::RefCountedThreadSafe<CallbackCounter> {
+ public:
+ CallbackCounter() : callback_count_(0) {}
+
+ void Callback() {
+ ++callback_count_;
+ }
+
+ int callback_count() {
+ return callback_count_;
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<CallbackCounter>;
+ volatile int callback_count_;
+};
+
+// Test that we can get a completion callback after a Flush().
+TEST_F(SQLitePersistentCookieStoreTest, TestFlushCompletionCallback) {
+ scoped_refptr<CallbackCounter> counter(new CallbackCounter());
+
+ // Callback shouldn't be invoked until we call Flush().
+ ASSERT_EQ(0, counter->callback_count());
+
+ store_->Flush(NewRunnableMethod(counter.get(), &CallbackCounter::Callback));
+
+ scoped_refptr<ThreadTestHelper> helper(
+ new ThreadTestHelper(BrowserThread::DB));
+ ASSERT_TRUE(helper->Run());
+
+ ASSERT_EQ(1, counter->callback_count());
+}
diff --git a/chrome/browser/net/ssl_config_service_manager_pref.cc b/chrome/browser/net/ssl_config_service_manager_pref.cc
index 626e40e..d024f72 100644
--- a/chrome/browser/net/ssl_config_service_manager_pref.cc
+++ b/chrome/browser/net/ssl_config_service_manager_pref.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// 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.
@@ -9,8 +9,10 @@
#include "chrome/browser/net/ssl_config_service_manager.h"
#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "net/base/ssl_config_service.h"
@@ -81,7 +83,6 @@ class SSLConfigServiceManagerPref
// The prefs (should only be accessed from UI thread)
BooleanPrefMember rev_checking_enabled_;
- BooleanPrefMember ssl2_enabled_;
BooleanPrefMember ssl3_enabled_;
BooleanPrefMember tls1_enabled_;
@@ -96,7 +97,6 @@ SSLConfigServiceManagerPref::SSLConfigServiceManagerPref(Profile* profile)
rev_checking_enabled_.Init(prefs::kCertRevocationCheckingEnabled,
profile->GetPrefs(), this);
- ssl2_enabled_.Init(prefs::kSSL2Enabled, profile->GetPrefs(), this);
ssl3_enabled_.Init(prefs::kSSL3Enabled, profile->GetPrefs(), this);
tls1_enabled_.Init(prefs::kTLS1Enabled, profile->GetPrefs(), this);
@@ -110,8 +110,6 @@ void SSLConfigServiceManagerPref::RegisterUserPrefs(PrefService* user_prefs) {
net::SSLConfig default_config;
user_prefs->RegisterBooleanPref(prefs::kCertRevocationCheckingEnabled,
default_config.rev_checking_enabled);
- user_prefs->RegisterBooleanPref(prefs::kSSL2Enabled,
- default_config.ssl2_enabled);
user_prefs->RegisterBooleanPref(prefs::kSSL3Enabled,
default_config.ssl3_enabled);
user_prefs->RegisterBooleanPref(prefs::kTLS1Enabled,
@@ -144,7 +142,6 @@ void SSLConfigServiceManagerPref::Observe(NotificationType type,
void SSLConfigServiceManagerPref::GetSSLConfigFromPrefs(
net::SSLConfig* config) {
config->rev_checking_enabled = rev_checking_enabled_.GetValue();
- config->ssl2_enabled = ssl2_enabled_.GetValue();
config->ssl3_enabled = ssl3_enabled_.GetValue();
config->tls1_enabled = tls1_enabled_.GetValue();
SSLConfigServicePref::SetSSLConfigFlags(config);
diff --git a/chrome/browser/net/url_fixer_upper.cc b/chrome/browser/net/url_fixer_upper.cc
index 4b392df..4c36368 100644
--- a/chrome/browser/net/url_fixer_upper.cc
+++ b/chrome/browser/net/url_fixer_upper.cc
@@ -316,19 +316,6 @@ static inline void FixupRef(const std::string& text,
url->append(text, part.begin, part.len);
}
-static void OffsetComponent(int offset, url_parse::Component* part) {
- DCHECK(part);
-
- if (part->is_valid()) {
- // Offset the location of this component.
- part->begin += offset;
-
- // This part might not have existed in the original text.
- if (part->begin < 0)
- part->reset();
- }
-}
-
static bool HasPort(const std::string& original_text,
const url_parse::Component& scheme_component) {
// Find the range between the ":" and the "/".
@@ -599,3 +586,16 @@ GURL URLFixerUpper::FixupRelativeFile(const std::wstring& base_dir,
return FixupRelativeFile(FilePath::FromWStringHack(base_dir),
FilePath::FromWStringHack(text));
}
+
+void URLFixerUpper::OffsetComponent(int offset, url_parse::Component* part) {
+ DCHECK(part);
+
+ if (part->is_valid()) {
+ // Offset the location of this component.
+ part->begin += offset;
+
+ // This part might not have existed in the original text.
+ if (part->begin < 0)
+ part->reset();
+ }
+}
diff --git a/chrome/browser/net/url_fixer_upper.h b/chrome/browser/net/url_fixer_upper.h
index 1e5d731..9f5beb5 100644
--- a/chrome/browser/net/url_fixer_upper.h
+++ b/chrome/browser/net/url_fixer_upper.h
@@ -11,6 +11,7 @@
#include "googleurl/src/gurl.h"
namespace url_parse {
+ struct Component;
struct Parsed;
}
@@ -62,6 +63,14 @@ namespace URLFixerUpper {
GURL FixupRelativeFile(const std::wstring& base_dir,
const std::wstring& text);
+ // Offsets the beginning index of |part| by |offset|, which is allowed to be
+ // negative. In some cases, the desired component does not exist at the given
+ // offset. For example, when converting from "http://foo" to "foo", the
+ // scheme component no longer exists. In such a case, the beginning index is
+ // set to 0.
+ // Does nothing if |part| is invalid.
+ void OffsetComponent(int offset, url_parse::Component* part);
+
// For paths like ~, we use $HOME for the current user's home
// directory. For tests, we allow our idea of $HOME to be overriden
// by this variable.
diff --git a/chrome/browser/net/url_request_failed_dns_job.cc b/chrome/browser/net/url_request_failed_dns_job.cc
index e436204..7137468 100644
--- a/chrome/browser/net/url_request_failed_dns_job.cc
+++ b/chrome/browser/net/url_request_failed_dns_job.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/net/url_request_failed_dns_job.h"
+#include "base/compiler_specific.h"
#include "base/message_loop.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_errors.h"
@@ -13,9 +14,17 @@
const char URLRequestFailedDnsJob::kTestUrl[] =
"http://url.handled.by.fake.dns/";
+URLRequestFailedDnsJob::URLRequestFailedDnsJob(net::URLRequest* request)
+ : net::URLRequestJob(request),
+ ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {}
+
+URLRequestFailedDnsJob::~URLRequestFailedDnsJob() {}
+
void URLRequestFailedDnsJob::Start() {
- MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
- this, &URLRequestFailedDnsJob::StartAsync));
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &URLRequestFailedDnsJob::StartAsync));
}
/* static */
@@ -26,7 +35,7 @@ void URLRequestFailedDnsJob::AddUrlHandler() {
}
/*static */
-URLRequestJob* URLRequestFailedDnsJob::Factory(URLRequest* request,
+net::URLRequestJob* URLRequestFailedDnsJob::Factory(net::URLRequest* request,
const std::string& scheme) {
return new URLRequestFailedDnsJob(request);
}
diff --git a/chrome/browser/net/url_request_failed_dns_job.h b/chrome/browser/net/url_request_failed_dns_job.h
index 14e5402..197fb2a 100644
--- a/chrome/browser/net/url_request_failed_dns_job.h
+++ b/chrome/browser/net/url_request_failed_dns_job.h
@@ -7,12 +7,12 @@
#define CHROME_BROWSER_NET_URL_REQUEST_FAILED_DNS_JOB_H_
#pragma once
+#include "base/task.h"
#include "net/url_request/url_request_job.h"
class URLRequestFailedDnsJob : public net::URLRequestJob {
public:
- explicit URLRequestFailedDnsJob(net::URLRequest* request)
- : URLRequestJob(request) { }
+ explicit URLRequestFailedDnsJob(net::URLRequest* request);
virtual void Start();
@@ -26,10 +26,12 @@ class URLRequestFailedDnsJob : public net::URLRequestJob {
static void AddUrlHandler();
private:
- ~URLRequestFailedDnsJob() {}
+ ~URLRequestFailedDnsJob();
// Simulate a DNS failure.
void StartAsync();
+
+ ScopedRunnableMethodFactory<URLRequestFailedDnsJob> method_factory_;
};
#endif // CHROME_BROWSER_NET_URL_REQUEST_FAILED_DNS_JOB_H_
diff --git a/chrome/browser/net/url_request_mock_http_job.cc b/chrome/browser/net/url_request_mock_http_job.cc
index 4029605..cad1a1e 100644
--- a/chrome/browser/net/url_request_mock_http_job.cc
+++ b/chrome/browser/net/url_request_mock_http_job.cc
@@ -21,8 +21,8 @@ static const FilePath::CharType kMockHeaderFileSuffix[] =
FilePath URLRequestMockHTTPJob::base_path_;
/* static */
-URLRequestJob* URLRequestMockHTTPJob::Factory(URLRequest* request,
- const std::string& scheme) {
+net::URLRequestJob* URLRequestMockHTTPJob::Factory(net::URLRequest* request,
+ const std::string& scheme) {
return new URLRequestMockHTTPJob(request,
GetOnDiskPath(base_path_, request, scheme));
}
@@ -56,7 +56,7 @@ GURL URLRequestMockHTTPJob::GetMockViewSourceUrl(const FilePath& path) {
/* static */
FilePath URLRequestMockHTTPJob::GetOnDiskPath(const FilePath& base_path,
- URLRequest* request,
+ net::URLRequest* request,
const std::string& scheme) {
std::string file_url("file:///");
file_url += WideToUTF8(base_path.ToWStringHack());
@@ -68,9 +68,9 @@ FilePath URLRequestMockHTTPJob::GetOnDiskPath(const FilePath& base_path,
return file_path;
}
-URLRequestMockHTTPJob::URLRequestMockHTTPJob(URLRequest* request,
+URLRequestMockHTTPJob::URLRequestMockHTTPJob(net::URLRequest* request,
const FilePath& file_path)
- : URLRequestFileJob(request, file_path) { }
+ : net::URLRequestFileJob(request, file_path) { }
// Public virtual version.
void URLRequestMockHTTPJob::GetResponseInfo(net::HttpResponseInfo* info) {
@@ -80,9 +80,9 @@ void URLRequestMockHTTPJob::GetResponseInfo(net::HttpResponseInfo* info) {
bool URLRequestMockHTTPJob::IsRedirectResponse(GURL* location,
int* http_status_code) {
- // Override the URLRequestFileJob implementation to invoke the default one
- // based on HttpResponseInfo.
- return URLRequestJob::IsRedirectResponse(location, http_status_code);
+ // Override the net::URLRequestFileJob implementation to invoke the default
+ // one based on HttpResponseInfo.
+ return net::URLRequestJob::IsRedirectResponse(location, http_status_code);
}
// Private const version.
diff --git a/chrome/browser/net/url_request_mock_http_job.h b/chrome/browser/net/url_request_mock_http_job.h
index 35a251c..bba882e 100644
--- a/chrome/browser/net/url_request_mock_http_job.h
+++ b/chrome/browser/net/url_request_mock_http_job.h
@@ -1,8 +1,8 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// 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.
//
-// A URLRequestJob class that pulls the content and http headers from disk.
+// A net::URLRequestJob class that pulls the content and http headers from disk.
#ifndef CHROME_BROWSER_NET_URL_REQUEST_MOCK_HTTP_JOB_H_
#define CHROME_BROWSER_NET_URL_REQUEST_MOCK_HTTP_JOB_H_
@@ -14,16 +14,16 @@
class FilePath;
-class URLRequestMockHTTPJob : public URLRequestFileJob {
+class URLRequestMockHTTPJob : public net::URLRequestFileJob {
public:
- URLRequestMockHTTPJob(URLRequest* request, const FilePath& file_path);
+ URLRequestMockHTTPJob(net::URLRequest* request, const FilePath& file_path);
virtual bool GetMimeType(std::string* mime_type) const;
virtual bool GetCharset(std::string* charset);
virtual void GetResponseInfo(net::HttpResponseInfo* info);
virtual bool IsRedirectResponse(GURL* location, int* http_status_code);
- static URLRequest::ProtocolFactory Factory;
+ static net::URLRequest::ProtocolFactory Factory;
// Adds the testing URLs to the URLRequestFilter.
static void AddUrlHandler(const FilePath& base_path);
@@ -39,7 +39,7 @@ class URLRequestMockHTTPJob : public URLRequestFileJob {
virtual ~URLRequestMockHTTPJob() { }
static FilePath GetOnDiskPath(const FilePath& base_path,
- URLRequest* request,
+ net::URLRequest* request,
const std::string& scheme);
private:
diff --git a/chrome/browser/net/url_request_mock_link_doctor_job.cc b/chrome/browser/net/url_request_mock_link_doctor_job.cc
index e34baa9..e11978e 100644
--- a/chrome/browser/net/url_request_mock_link_doctor_job.cc
+++ b/chrome/browser/net/url_request_mock_link_doctor_job.cc
@@ -22,8 +22,9 @@ FilePath GetMockFilePath() {
} // namespace
/* static */
-URLRequestJob* URLRequestMockLinkDoctorJob::Factory(URLRequest* request,
- const std::string& scheme) {
+net::URLRequestJob* URLRequestMockLinkDoctorJob::Factory(
+ net::URLRequest* request,
+ const std::string& scheme) {
return new URLRequestMockLinkDoctorJob(request);
}
@@ -35,6 +36,7 @@ void URLRequestMockLinkDoctorJob::AddUrlHandler() {
URLRequestMockLinkDoctorJob::Factory);
}
-URLRequestMockLinkDoctorJob::URLRequestMockLinkDoctorJob(URLRequest* request)
+URLRequestMockLinkDoctorJob::URLRequestMockLinkDoctorJob(
+ net::URLRequest* request)
: URLRequestMockHTTPJob(request, GetMockFilePath()) {
}
diff --git a/chrome/browser/net/url_request_mock_link_doctor_job.h b/chrome/browser/net/url_request_mock_link_doctor_job.h
index 4af4fe7..3c3af31 100644
--- a/chrome/browser/net/url_request_mock_link_doctor_job.h
+++ b/chrome/browser/net/url_request_mock_link_doctor_job.h
@@ -1,8 +1,8 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// 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.
//
-// A URLRequestJob class that substitutes LinkDoctor requests.
+// A net::URLRequestJob class that substitutes LinkDoctor requests.
#ifndef CHROME_BROWSER_NET_URL_REQUEST_MOCK_LINK_DOCTOR_JOB_H_
#define CHROME_BROWSER_NET_URL_REQUEST_MOCK_LINK_DOCTOR_JOB_H_
@@ -12,9 +12,9 @@
class URLRequestMockLinkDoctorJob : public URLRequestMockHTTPJob {
public:
- explicit URLRequestMockLinkDoctorJob(URLRequest* request);
+ explicit URLRequestMockLinkDoctorJob(net::URLRequest* request);
- static URLRequest::ProtocolFactory Factory;
+ static net::URLRequest::ProtocolFactory Factory;
// Adds the testing URLs to the URLRequestFilter.
static void AddUrlHandler();
diff --git a/chrome/browser/net/url_request_mock_net_error_job.cc b/chrome/browser/net/url_request_mock_net_error_job.cc
index f4aa330..5f66bc4 100644
--- a/chrome/browser/net/url_request_mock_net_error_job.cc
+++ b/chrome/browser/net/url_request_mock_net_error_job.cc
@@ -57,8 +57,9 @@ void URLRequestMockNetErrorJob::RemoveMockedURL(const GURL& url) {
}
// static
-URLRequestJob* URLRequestMockNetErrorJob::Factory(URLRequest* request,
- const std::string& scheme) {
+net::URLRequestJob* URLRequestMockNetErrorJob::Factory(
+ net::URLRequest* request,
+ const std::string& scheme) {
GURL url = request->url();
URLMockInfoMap::const_iterator iter = url_mock_info_map_.find(url);
@@ -66,9 +67,9 @@ URLRequestJob* URLRequestMockNetErrorJob::Factory(URLRequest* request,
MockInfo mock_info = iter->second;
- // URLRequestMockNetErrorJob derives from URLRequestFileJob. We pass a
- // FilePath so that the URLRequestFileJob methods will do the loading from
- // the files.
+ // URLRequestMockNetErrorJob derives from net::URLRequestFileJob. We pass a
+ // FilePath so that the net::URLRequestFileJob methods will do the loading
+ // from the files.
std::wstring file_url(L"file:///");
file_url.append(mock_info.base);
file_url.append(UTF8ToWide(url.path()));
@@ -80,7 +81,7 @@ URLRequestJob* URLRequestMockNetErrorJob::Factory(URLRequest* request,
file_path);
}
-URLRequestMockNetErrorJob::URLRequestMockNetErrorJob(URLRequest* request,
+URLRequestMockNetErrorJob::URLRequestMockNetErrorJob(net::URLRequest* request,
const std::vector<int>& errors, net::X509Certificate* cert,
const FilePath& file_path)
: URLRequestMockHTTPJob(request, file_path),
diff --git a/chrome/browser/net/url_request_mock_net_error_job.h b/chrome/browser/net/url_request_mock_net_error_job.h
index 059272f..33b1fc0 100644
--- a/chrome/browser/net/url_request_mock_net_error_job.h
+++ b/chrome/browser/net/url_request_mock_net_error_job.h
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// A URLRequestJob class that simulates network errors (including https
+// A net::URLRequestJob class that simulates network errors (including https
// related).
// It is based on URLRequestMockHttpJob.
@@ -14,7 +14,7 @@
class URLRequestMockNetErrorJob : public URLRequestMockHTTPJob {
public:
- URLRequestMockNetErrorJob(URLRequest* request,
+ URLRequestMockNetErrorJob(net::URLRequest* request,
const std::vector<int>& errors,
net::X509Certificate* ssl_cert,
const FilePath& file_path);
@@ -39,7 +39,7 @@ class URLRequestMockNetErrorJob : public URLRequestMockHTTPJob {
private:
~URLRequestMockNetErrorJob();
- static URLRequest::ProtocolFactory Factory;
+ static net::URLRequest::ProtocolFactory Factory;
void StartAsync();
diff --git a/chrome/browser/net/url_request_mock_util.cc b/chrome/browser/net/url_request_mock_util.cc
index b3ac398..ce32af3 100644
--- a/chrome/browser/net/url_request_mock_util.cc
+++ b/chrome/browser/net/url_request_mock_util.cc
@@ -20,8 +20,8 @@
namespace chrome_browser_net {
void SetUrlRequestMocksEnabled(bool enabled) {
- // Since this involves changing the URLRequest ProtocolFactory, we need to
- // run on the IO thread.
+ // Since this involves changing the net::URLRequest ProtocolFactory, we need
+ // to run on the IO thread.
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (enabled) {
diff --git a/chrome/browser/net/url_request_slow_download_job.cc b/chrome/browser/net/url_request_slow_download_job.cc
index 138a57c..d10591d 100644
--- a/chrome/browser/net/url_request_slow_download_job.cc
+++ b/chrome/browser/net/url_request_slow_download_job.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/net/url_request_slow_download_job.h"
+#include "base/compiler_specific.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "googleurl/src/gurl.h"
@@ -26,8 +27,10 @@ std::vector<URLRequestSlowDownloadJob*>
URLRequestSlowDownloadJob::kPendingRequests;
void URLRequestSlowDownloadJob::Start() {
- MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(this,
- &URLRequestSlowDownloadJob::StartAsync));
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &URLRequestSlowDownloadJob::StartAsync));
}
/* static */
@@ -42,7 +45,8 @@ void URLRequestSlowDownloadJob::AddUrlHandler() {
}
/*static */
-URLRequestJob* URLRequestSlowDownloadJob::Factory(URLRequest* request,
+net::URLRequestJob* URLRequestSlowDownloadJob::Factory(
+ net::URLRequest* request,
const std::string& scheme) {
URLRequestSlowDownloadJob* job = new URLRequestSlowDownloadJob(request);
if (request->url().spec() != kFinishDownloadUrl)
@@ -60,12 +64,12 @@ void URLRequestSlowDownloadJob::FinishPendingRequests() {
kPendingRequests.clear();
}
-URLRequestSlowDownloadJob::URLRequestSlowDownloadJob(URLRequest* request)
- : URLRequestJob(request),
- first_download_size_remaining_(kFirstDownloadSize),
- should_finish_download_(false),
- should_send_second_chunk_(false) {
-}
+URLRequestSlowDownloadJob::URLRequestSlowDownloadJob(net::URLRequest* request)
+ : net::URLRequestJob(request),
+ first_download_size_remaining_(kFirstDownloadSize),
+ should_finish_download_(false),
+ should_send_second_chunk_(false),
+ ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {}
void URLRequestSlowDownloadJob::StartAsync() {
if (LowerCaseEqualsASCII(kFinishDownloadUrl, request_->url().spec().c_str()))
@@ -138,6 +142,8 @@ void URLRequestSlowDownloadJob::GetResponseInfo(net::HttpResponseInfo* info) {
GetResponseInfoConst(info);
}
+URLRequestSlowDownloadJob::~URLRequestSlowDownloadJob() {}
+
// Private const version.
void URLRequestSlowDownloadJob::GetResponseInfoConst(
net::HttpResponseInfo* info) const {
diff --git a/chrome/browser/net/url_request_slow_download_job.h b/chrome/browser/net/url_request_slow_download_job.h
index 22da86a..d6927b8 100644
--- a/chrome/browser/net/url_request_slow_download_job.h
+++ b/chrome/browser/net/url_request_slow_download_job.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// 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.
// This class simulates a slow download. This used in a UI test to test the
@@ -12,9 +12,10 @@
#include <string>
#include <vector>
+#include "base/task.h"
#include "net/url_request/url_request_job.h"
-class URLRequestSlowDownloadJob : public URLRequestJob {
+class URLRequestSlowDownloadJob : public net::URLRequestJob {
public:
explicit URLRequestSlowDownloadJob(net::URLRequest* request);
@@ -22,7 +23,7 @@ class URLRequestSlowDownloadJob : public URLRequestJob {
// send the second chunk.
void CheckDoneStatus();
- // URLRequestJob methods
+ // net::URLRequestJob methods
virtual void Start();
virtual bool GetMimeType(std::string* mime_type) const;
virtual void GetResponseInfo(net::HttpResponseInfo* info);
@@ -40,7 +41,7 @@ class URLRequestSlowDownloadJob : public URLRequestJob {
static void AddUrlHandler();
private:
- virtual ~URLRequestSlowDownloadJob() { }
+ virtual ~URLRequestSlowDownloadJob();
void GetResponseInfoConst(net::HttpResponseInfo* info) const;
@@ -56,6 +57,8 @@ class URLRequestSlowDownloadJob : public URLRequestJob {
int first_download_size_remaining_;
bool should_finish_download_;
bool should_send_second_chunk_;
+
+ ScopedRunnableMethodFactory<URLRequestSlowDownloadJob> method_factory_;
};
#endif // CHROME_BROWSER_NET_URL_REQUEST_SLOW_DOWNLOAD_JOB_H_
diff --git a/chrome/browser/net/url_request_slow_http_job.cc b/chrome/browser/net/url_request_slow_http_job.cc
index a8205f0..967ea1e 100644
--- a/chrome/browser/net/url_request_slow_http_job.cc
+++ b/chrome/browser/net/url_request_slow_http_job.cc
@@ -19,8 +19,8 @@ const int URLRequestSlowHTTPJob::kDelayMs = 1000;
using base::TimeDelta;
/* static */
-URLRequestJob* URLRequestSlowHTTPJob::Factory(URLRequest* request,
- const std::string& scheme) {
+net::URLRequestJob* URLRequestSlowHTTPJob::Factory(net::URLRequest* request,
+ const std::string& scheme) {
return new URLRequestSlowHTTPJob(request,
GetOnDiskPath(base_path_, request, scheme));
}
@@ -44,7 +44,7 @@ GURL URLRequestSlowHTTPJob::GetMockUrl(const FilePath& path) {
return GURL(url);
}
-URLRequestSlowHTTPJob::URLRequestSlowHTTPJob(URLRequest* request,
+URLRequestSlowHTTPJob::URLRequestSlowHTTPJob(net::URLRequest* request,
const FilePath& file_path)
: URLRequestMockHTTPJob(request, file_path) { }
diff --git a/chrome/browser/net/url_request_slow_http_job.h b/chrome/browser/net/url_request_slow_http_job.h
index fab7a01..e58f8df 100644
--- a/chrome/browser/net/url_request_slow_http_job.h
+++ b/chrome/browser/net/url_request_slow_http_job.h
@@ -13,11 +13,11 @@
class URLRequestSlowHTTPJob : public URLRequestMockHTTPJob {
public:
- URLRequestSlowHTTPJob(URLRequest* request, const FilePath& file_path);
+ URLRequestSlowHTTPJob(net::URLRequest* request, const FilePath& file_path);
static const int kDelayMs;
- static URLRequest::ProtocolFactory Factory;
+ static net::URLRequest::ProtocolFactory Factory;
// Adds the testing URLs to the URLRequestFilter.
static void AddUrlHandler(const FilePath& base_path);
diff --git a/chrome/browser/net/url_request_tracking.cc b/chrome/browser/net/url_request_tracking.cc
index 60ad7d2..a931856 100644
--- a/chrome/browser/net/url_request_tracking.cc
+++ b/chrome/browser/net/url_request_tracking.cc
@@ -13,7 +13,7 @@ namespace {
// PID.
const void* kOriginProcessUniqueIDKey = 0;
-class UniqueIDData : public URLRequest::UserData {
+class UniqueIDData : public net::URLRequest::UserData {
public:
explicit UniqueIDData(int id) : id_(id) {}
virtual ~UniqueIDData() {}
@@ -31,12 +31,12 @@ class UniqueIDData : public URLRequest::UserData {
namespace chrome_browser_net {
-void SetOriginProcessUniqueIDForRequest(int id, URLRequest* request) {
+void SetOriginProcessUniqueIDForRequest(int id, net::URLRequest* request) {
// The request will take ownership.
request->SetUserData(&kOriginProcessUniqueIDKey, new UniqueIDData(id));
}
-int GetOriginProcessUniqueIDForRequest(const URLRequest* request) {
+int GetOriginProcessUniqueIDForRequest(const net::URLRequest* request) {
const UniqueIDData* data = static_cast<const UniqueIDData*>(
request->GetUserData(&kOriginProcessUniqueIDKey));
if (!data)
diff --git a/chrome/browser/net/view_blob_internals_job_factory.cc b/chrome/browser/net/view_blob_internals_job_factory.cc
index 847d70d..ad2349f 100644
--- a/chrome/browser/net/view_blob_internals_job_factory.cc
+++ b/chrome/browser/net/view_blob_internals_job_factory.cc
@@ -18,12 +18,11 @@ bool ViewBlobInternalsJobFactory::IsSupportedURL(const GURL& url) {
}
// static.
-URLRequestJob* ViewBlobInternalsJobFactory::CreateJobForRequest(
- URLRequest* request) {
+net::URLRequestJob* ViewBlobInternalsJobFactory::CreateJobForRequest(
+ net::URLRequest* request) {
webkit_blob::BlobStorageController* blob_storage_controller =
static_cast<ChromeURLRequestContext*>(request->context())->
blob_storage_context()->controller();
return new webkit_blob::ViewBlobInternalsJob(
request, blob_storage_controller);
}
-
diff --git a/chrome/browser/net/view_http_cache_job_factory.cc b/chrome/browser/net/view_http_cache_job_factory.cc
index 8e14a11..839130d 100644
--- a/chrome/browser/net/view_http_cache_job_factory.cc
+++ b/chrome/browser/net/view_http_cache_job_factory.cc
@@ -18,8 +18,11 @@ namespace {
// A job subclass that dumps an HTTP cache entry.
class ViewHttpCacheJob : public net::URLRequestJob {
public:
- explicit ViewHttpCacheJob(URLRequest* request)
- : URLRequestJob(request), data_offset_(0), cancel_(false), busy_(false),
+ explicit ViewHttpCacheJob(net::URLRequest* request)
+ : net::URLRequestJob(request),
+ data_offset_(0),
+ cancel_(false),
+ busy_(false),
ALLOW_THIS_IN_INITIALIZER_LIST(
callback_(this, &ViewHttpCacheJob::OnIOComplete)) {}
@@ -75,7 +78,7 @@ void ViewHttpCacheJob::Kill() {
// is safe.
cancel_ = true;
if (!busy_)
- URLRequestJob::Kill();
+ net::URLRequestJob::Kill();
}
bool ViewHttpCacheJob::GetMimeType(std::string* mime_type) const {
@@ -108,7 +111,7 @@ void ViewHttpCacheJob::OnIOComplete(int result) {
Release(); // Acquired on Start().
if (cancel_)
- return URLRequestJob::Kill();
+ return net::URLRequestJob::Kill();
// Notify that the headers are complete.
NotifyHeadersComplete();
@@ -123,7 +126,7 @@ bool ViewHttpCacheJobFactory::IsSupportedURL(const GURL& url) {
}
// Static.
-URLRequestJob* ViewHttpCacheJobFactory::CreateJobForRequest(
- URLRequest* request) {
+net::URLRequestJob* ViewHttpCacheJobFactory::CreateJobForRequest(
+ net::URLRequest* request) {
return new ViewHttpCacheJob(request);
}
diff --git a/chrome/browser/net/websocket_experiment/websocket_experiment_task.cc b/chrome/browser/net/websocket_experiment/websocket_experiment_task.cc
index 05b2315..f116119 100644
--- a/chrome/browser/net/websocket_experiment/websocket_experiment_task.cc
+++ b/chrome/browser/net/websocket_experiment/websocket_experiment_task.cc
@@ -7,7 +7,7 @@
#include "base/hash_tables.h"
#include "base/metrics/histogram.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/net/url_request_context_getter.h"
#include "net/base/host_resolver.h"
#include "net/base/load_flags.h"
diff --git a/chrome/browser/notifications/balloon_collection.cc b/chrome/browser/notifications/balloon_collection.cc
index 9d60626..218126b 100644
--- a/chrome/browser/notifications/balloon_collection.cc
+++ b/chrome/browser/notifications/balloon_collection.cc
@@ -9,7 +9,7 @@
#include "chrome/browser/notifications/balloon.h"
#include "chrome/browser/notifications/balloon_host.h"
#include "chrome/browser/notifications/notification.h"
-#include "chrome/browser/window_sizer.h"
+#include "chrome/browser/ui/window_sizer.h"
#include "gfx/rect.h"
#include "gfx/size.h"
diff --git a/chrome/browser/notifications/balloon_collection_mac.mm b/chrome/browser/notifications/balloon_collection_mac.mm
index e3ac179..7615415 100644
--- a/chrome/browser/notifications/balloon_collection_mac.mm
+++ b/chrome/browser/notifications/balloon_collection_mac.mm
@@ -6,7 +6,7 @@
#import <Cocoa/Cocoa.h>
-#include "chrome/browser/cocoa/notifications/balloon_view_bridge.h"
+#include "chrome/browser/ui/cocoa/notifications/balloon_view_bridge.h"
Balloon* BalloonCollectionImpl::MakeBalloon(const Notification& notification,
Profile* profile) {
diff --git a/chrome/browser/notifications/balloon_host.cc b/chrome/browser/notifications/balloon_host.cc
index 6fbc1e0..d24f3d7 100644
--- a/chrome/browser/notifications/balloon_host.cc
+++ b/chrome/browser/notifications/balloon_host.cc
@@ -8,7 +8,7 @@
#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/notifications/balloon.h"
#include "chrome/browser/notifications/notification.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/renderer_preferences_util.h"
@@ -91,7 +91,8 @@ const string16& BalloonHost::GetSource() const {
WebPreferences BalloonHost::GetWebkitPrefs() {
WebPreferences web_prefs =
- RenderViewHostDelegateHelper::GetWebkitPrefs(GetProfile(), enable_dom_ui_);
+ RenderViewHostDelegateHelper::GetWebkitPrefs(GetProfile(),
+ enable_dom_ui_);
web_prefs.allow_scripts_to_close_windows = true;
return web_prefs;
}
@@ -132,7 +133,9 @@ void BalloonHost::RenderViewReady(RenderViewHost* render_view_host) {
Source<BalloonHost>(this), NotificationService::NoDetails());
}
-void BalloonHost::RenderViewGone(RenderViewHost* render_view_host) {
+void BalloonHost::RenderViewGone(RenderViewHost* render_view_host,
+ base::TerminationStatus status,
+ int error_code) {
Close(render_view_host);
}
@@ -190,6 +193,11 @@ void BalloonHost::ShowCreatedWindow(int route_id,
browser->AddTabContents(contents, disposition, initial_pos, user_gesture);
}
+bool BalloonHost::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
+ bool* is_keyboard_shortcut) {
+ return false;
+}
+
void BalloonHost::UpdatePreferredSize(const gfx::Size& new_size) {
balloon_->SetContentPreferredSize(new_size);
}
@@ -208,7 +216,7 @@ void BalloonHost::Init() {
DCHECK(!render_view_host_) << "BalloonViewHost already initialized.";
RenderViewHost* rvh = new RenderViewHost(
site_instance_.get(), this, MSG_ROUTING_NONE, NULL);
- if (GetProfile()->GetExtensionsService()) {
+ if (GetProfile()->GetExtensionService()) {
extension_function_dispatcher_.reset(
ExtensionFunctionDispatcher::Create(
rvh, this, balloon_->notification().content_url()));
diff --git a/chrome/browser/notifications/balloon_host.h b/chrome/browser/notifications/balloon_host.h
index c5a88e7..358cb61 100644
--- a/chrome/browser/notifications/balloon_host.h
+++ b/chrome/browser/notifications/balloon_host.h
@@ -49,7 +49,9 @@ class BalloonHost : public RenderViewHostDelegate,
virtual void Close(RenderViewHost* render_view_host);
virtual void RenderViewCreated(RenderViewHost* render_view_host);
virtual void RenderViewReady(RenderViewHost* render_view_host);
- virtual void RenderViewGone(RenderViewHost* render_view_host);
+ virtual void RenderViewGone(RenderViewHost* render_view_host,
+ base::TerminationStatus status,
+ int error_code);
virtual void UpdateTitle(RenderViewHost* render_view_host,
int32 page_id, const std::wstring& title) {}
virtual int GetBrowserWindowID() const;
@@ -93,9 +95,7 @@ class BalloonHost : public RenderViewHostDelegate,
virtual void Activate() {}
virtual void Deactivate() {}
virtual bool PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
- bool* is_keyboard_shortcut) {
- return false;
- }
+ bool* is_keyboard_shortcut);
virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {}
virtual void HandleMouseMove() {}
virtual void HandleMouseDown();
diff --git a/chrome/browser/notifications/desktop_notification_service.cc b/chrome/browser/notifications/desktop_notification_service.cc
index 8aa82d1..afc01c7 100644
--- a/chrome/browser/notifications/desktop_notification_service.cc
+++ b/chrome/browser/notifications/desktop_notification_service.cc
@@ -11,14 +11,14 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_child_process_host.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/notifications/notification.h"
#include "chrome/browser/notifications/notification_object_proxy.h"
#include "chrome/browser/notifications/notification_ui_manager.h"
#include "chrome/browser/notifications/notifications_prefs_cache.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prefs/scoped_pref_update.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/site_instance.h"
@@ -317,7 +317,8 @@ void DesktopNotificationService::Observe(NotificationType type,
} else if (NotificationType::EXTENSION_UNLOADED == type) {
// Remove all notifications currently shown or queued by the extension
// which was unloaded.
- Extension* extension = Details<Extension>(details).ptr();
+ const Extension* extension =
+ Details<UnloadedExtensionInfo>(details)->extension;
if (extension)
ui_manager_->CancelAllBySourceOrigin(extension->url());
} else if (NotificationType::PROFILE_DESTROYED == type) {
@@ -452,6 +453,11 @@ void DesktopNotificationService::SetDefaultContentSetting(
// The cache is updated through the notification observer.
}
+bool DesktopNotificationService::IsDefaultContentSettingManaged() const {
+ return profile_->GetPrefs()->IsManagedPreference(
+ prefs::kDesktopNotificationDefaultContentSetting);
+}
+
void DesktopNotificationService::ResetToDefaultContentSetting() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -615,7 +621,7 @@ string16 DesktopNotificationService::DisplayNameForOrigin(
const GURL& origin) {
// If the source is an extension, lookup the display name.
if (origin.SchemeIs(chrome::kExtensionScheme)) {
- ExtensionsService* ext_service = profile_->GetExtensionsService();
+ ExtensionService* ext_service = profile_->GetExtensionService();
if (ext_service) {
const Extension* extension = ext_service->GetExtensionByURL(origin);
if (extension)
diff --git a/chrome/browser/notifications/desktop_notification_service.h b/chrome/browser/notifications/desktop_notification_service.h
index a7a4ce2..bb6691b 100644
--- a/chrome/browser/notifications/desktop_notification_service.h
+++ b/chrome/browser/notifications/desktop_notification_service.h
@@ -93,6 +93,7 @@ class DesktopNotificationService : public NotificationObserver {
// been allowed or denied yet.
ContentSetting GetDefaultContentSetting();
void SetDefaultContentSetting(ContentSetting setting);
+ bool IsDefaultContentSettingManaged() const;
// NOTE: This should only be called on the UI thread.
void ResetToDefaultContentSetting();
diff --git a/chrome/browser/notifications/desktop_notification_service_unittest.cc b/chrome/browser/notifications/desktop_notification_service_unittest.cc
index 3c1c8ca..4532dd2 100644
--- a/chrome/browser/notifications/desktop_notification_service_unittest.cc
+++ b/chrome/browser/notifications/desktop_notification_service_unittest.cc
@@ -4,8 +4,10 @@
#include "chrome/browser/notifications/desktop_notification_service.h"
+#include "base/message_loop.h"
#include "base/ref_counted.h"
#include "base/waitable_event.h"
+#include "chrome/browser/browser_thread.h"
#include "chrome/browser/notifications/notifications_prefs_cache.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prefs/scoped_pref_update.h"
diff --git a/chrome/browser/notifications/notification_object_proxy.cc b/chrome/browser/notifications/notification_object_proxy.cc
index 6b10afe..a973473 100644
--- a/chrome/browser/notifications/notification_object_proxy.cc
+++ b/chrome/browser/notifications/notification_object_proxy.cc
@@ -6,7 +6,6 @@
#include "base/message_loop.h"
#include "base/string16.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/common/render_messages.h"
diff --git a/chrome/browser/notifications/notification_options_menu_model.cc b/chrome/browser/notifications/notification_options_menu_model.cc
index 7172cf7..45620c9 100644
--- a/chrome/browser/notifications/notification_options_menu_model.cc
+++ b/chrome/browser/notifications/notification_options_menu_model.cc
@@ -8,11 +8,12 @@
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/notifications/desktop_notification_service.h"
#include "chrome/browser/notifications/notification.h"
#include "chrome/browser/notifications/notifications_prefs_cache.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_switches.h"
#include "chrome/common/content_settings_types.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/url_constants.h"
@@ -20,7 +21,6 @@
#if defined(OS_WIN)
#include "chrome/browser/ui/views/browser_dialogs.h"
-#include "chrome/installer/util/install_util.h"
#endif // OS_WIN
// Menu commands
@@ -54,7 +54,7 @@ NotificationOptionsMenuModel::NotificationOptionsMenuModel(Balloon* balloon)
NotificationOptionsMenuModel::~NotificationOptionsMenuModel() {
}
-bool NotificationOptionsMenuModel::IsLabelForCommandIdDynamic(int command_id)
+bool NotificationOptionsMenuModel::IsItemForCommandIdDynamic(int command_id)
const {
return command_id == kTogglePermissionCommand ||
command_id == kToggleExtensionCommand;
@@ -72,8 +72,8 @@ string16 NotificationOptionsMenuModel::GetLabelForCommandId(int command_id)
DesktopNotificationService* service =
balloon_->profile()->GetDesktopNotificationService();
if (origin.SchemeIs(chrome::kExtensionScheme)) {
- ExtensionsService* ext_service =
- balloon_->profile()->GetExtensionsService();
+ ExtensionService* ext_service =
+ balloon_->profile()->GetExtensionService();
const Extension* extension = ext_service->GetExtensionByURL(origin);
if (extension) {
ExtensionPrefs* extension_prefs = ext_service->extension_prefs();
@@ -121,8 +121,8 @@ bool NotificationOptionsMenuModel::GetAcceleratorForCommandId(
void NotificationOptionsMenuModel::ExecuteCommand(int command_id) {
DesktopNotificationService* service =
balloon_->profile()->GetDesktopNotificationService();
- ExtensionsService* ext_service =
- balloon_->profile()->GetExtensionsService();
+ ExtensionService* ext_service =
+ balloon_->profile()->GetExtensionService();
const GURL& origin = balloon_->notification().origin_url();
switch (command_id) {
case kTogglePermissionCommand:
@@ -150,7 +150,8 @@ void NotificationOptionsMenuModel::ExecuteCommand(int command_id) {
CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
} else {
#if defined(OS_WIN)
- if (InstallUtil::IsChromeFrameProcess()) {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kChromeFrame)) {
// We may not have a browser if this is a chrome frame process.
browser::ShowContentSettingsWindow(NULL,
CONTENT_SETTINGS_TYPE_DEFAULT,
diff --git a/chrome/browser/notifications/notification_options_menu_model.h b/chrome/browser/notifications/notification_options_menu_model.h
index b276e11..f7f4c77 100644
--- a/chrome/browser/notifications/notification_options_menu_model.h
+++ b/chrome/browser/notifications/notification_options_menu_model.h
@@ -16,7 +16,7 @@ class NotificationOptionsMenuModel : public menus::SimpleMenuModel,
virtual ~NotificationOptionsMenuModel();
// Overridden from menus::SimpleMenuModel:
- virtual bool IsLabelForCommandIdDynamic(int command_id) const;
+ virtual bool IsItemForCommandIdDynamic(int command_id) const;
virtual string16 GetLabelForCommandId(int command_id) const;
// Overridden from menus::SimpleMenuModel::Delegate:
diff --git a/chrome/browser/omnibox_search_hint.cc b/chrome/browser/omnibox_search_hint.cc
index 42cbe63..e06931a 100644
--- a/chrome/browser/omnibox_search_hint.cc
+++ b/chrome/browser/omnibox_search_hint.cc
@@ -15,15 +15,16 @@
#include "chrome/browser/autocomplete/autocomplete_match.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
-#include "chrome/browser/location_bar.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/omnibox/location_bar.h"
#include "chrome/common/chrome_switches.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/oom_priority_manager.cc b/chrome/browser/oom_priority_manager.cc
index 446f108..bb8ba7e 100644
--- a/chrome/browser/oom_priority_manager.cc
+++ b/chrome/browser/oom_priority_manager.cc
@@ -14,8 +14,8 @@
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/browser/zygote_host_linux.h"
#if !defined(OS_CHROMEOS)
@@ -166,7 +166,7 @@ void OomPriorityManager::DoAdjustOomPriorities(StatsList renderer_stats) {
iterator != renderer_stats.end(); ++iterator) {
if (already_seen.find(iterator->renderer_handle) == already_seen.end()) {
already_seen.insert(iterator->renderer_handle);
- Singleton<ZygoteHost>::get()->AdjustRendererOOMScore(
+ ZygoteHost::GetInstance()->AdjustRendererOOMScore(
iterator->renderer_handle,
static_cast<int>(priority + 0.5f));
priority += priority_increment;
diff --git a/chrome/browser/options_page_base.cc b/chrome/browser/options_page_base.cc
deleted file mode 100644
index 6ee5610..0000000
--- a/chrome/browser/options_page_base.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// 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.
-
-#include "chrome/browser/options_page_base.h"
-
-#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/common/notification_service.h"
-
-///////////////////////////////////////////////////////////////////////////////
-// OptionsPageBase
-
-OptionsPageBase::OptionsPageBase(Profile* profile)
- : profile_(profile) {
-}
-
-OptionsPageBase::~OptionsPageBase() {
-}
-
-void OptionsPageBase::UserMetricsRecordAction(const UserMetricsAction& action,
- PrefService* prefs) {
- UserMetrics::RecordAction(action, profile());
- if (prefs)
- prefs->ScheduleSavePersistentPrefs();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// OptionsPageBase, NotificationObserver implementation:
-
-void OptionsPageBase::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- if (type == NotificationType::PREF_CHANGED)
- NotifyPrefChanged(Details<std::string>(details).ptr());
-}
diff --git a/chrome/browser/options_page_base.h b/chrome/browser/options_page_base.h
deleted file mode 100644
index 0e6c756..0000000
--- a/chrome/browser/options_page_base.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_OPTIONS_PAGE_BASE_H_
-#define CHROME_BROWSER_OPTIONS_PAGE_BASE_H_
-#pragma once
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "chrome/browser/options_window.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/browser/metrics/user_metrics.h"
-
-class PrefService;
-class Profile;
-struct UserMetricsAction;
-
-///////////////////////////////////////////////////////////////////////////////
-// OptionsPageBase
-//
-// A base class for Options dialog pages that handles observing preferences
-//
-class OptionsPageBase : public NotificationObserver {
- public:
- virtual ~OptionsPageBase();
-
- // Highlights the specified group to attract the user's attention.
- virtual void HighlightGroup(OptionsGroup highlight_group) { }
-
- // Overridden from NotificationObserver:
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- protected:
- // This class cannot be instantiated directly, but its constructor must be
- // called by derived classes.
- explicit OptionsPageBase(Profile* profile);
-
- // Returns the Profile associated with this page.
- Profile* profile() const { return profile_; }
-
- // Records a user action and schedules the prefs file to be saved.
- void UserMetricsRecordAction(const UserMetricsAction &action,
- PrefService* prefs);
-
- // Allows the UI to update when a preference value changes. The parameter is
- // the specific pref that changed, or NULL if all pref UI should be
- // validated. This should be called during setup, but with NULL as the
- // parameter to allow initial state to be set.
- virtual void NotifyPrefChanged(const std::string* pref_name) {}
-
- private:
- // The Profile associated with this page.
- Profile* profile_;
-
- DISALLOW_COPY_AND_ASSIGN(OptionsPageBase);
-};
-
-#endif // CHROME_BROWSER_OPTIONS_PAGE_BASE_H_
diff --git a/chrome/browser/options_util.cc b/chrome/browser/options_util.cc
deleted file mode 100644
index 5d46ab5..0000000
--- a/chrome/browser/options_util.cc
+++ /dev/null
@@ -1,133 +0,0 @@
-// 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.
-
-#include "chrome/browser/options_util.h"
-
-#include "base/thread_restrictions.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/download/download_manager.h"
-#include "chrome/browser/download/download_prefs.h"
-#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
-#include "chrome/browser/host_content_settings_map.h"
-#include "chrome/browser/host_zoom_map.h"
-#include "chrome/browser/metrics/metrics_service.h"
-#include "chrome/browser/notifications/desktop_notification_service.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/installer/util/google_update_settings.h"
-
-// static
-void OptionsUtil::ResetToDefaults(Profile* profile) {
- // TODO(tc): It would be nice if we could generate this list automatically so
- // changes to any of the options pages doesn't require updating this list
- // manually.
- PrefService* prefs = profile->GetPrefs();
- const char* kUserPrefs[] = {
- prefs::kAcceptLanguages,
- prefs::kAlternateErrorPagesEnabled,
- prefs::kClearSiteDataOnExit,
- prefs::kCookieBehavior,
- prefs::kDefaultCharset,
- prefs::kDefaultZoomLevel,
- prefs::kDeleteBrowsingHistory,
- prefs::kDeleteCache,
- prefs::kDeleteCookies,
- prefs::kDeleteDownloadHistory,
- prefs::kDeleteFormData,
- prefs::kDeletePasswords,
- prefs::kDnsPrefetchingEnabled,
-#if defined(OS_LINUX) || defined(OS_FREEBSD) || defined(OS_OPENBSD)
- prefs::kCertRevocationCheckingEnabled,
- prefs::kSSL2Enabled,
- prefs::kSSL3Enabled,
- prefs::kTLS1Enabled,
-#endif
-#if defined(OS_CHROMEOS)
- prefs::kTapToClickEnabled,
- prefs::kTouchpadSensitivity,
-#endif
- prefs::kDownloadDefaultDirectory,
- prefs::kDownloadExtensionsToOpen,
- prefs::kSavingBrowserHistoryDisabled,
- prefs::kEnableSpellCheck,
- prefs::kEnableTranslate,
- prefs::kAutoFillEnabled,
- prefs::kAutoFillAuxiliaryProfilesEnabled,
- prefs::kHomePage,
- prefs::kHomePageIsNewTabPage,
- prefs::kPromptForDownload,
- prefs::kPasswordManagerEnabled,
- prefs::kRestoreOnStartup,
- prefs::kSafeBrowsingEnabled,
- prefs::kSafeBrowsingReportingEnabled,
- prefs::kSearchSuggestEnabled,
- prefs::kShowHomeButton,
- prefs::kSpellCheckDictionary,
- prefs::kURLsToRestoreOnStartup,
- prefs::kWebKitDefaultFixedFontSize,
- prefs::kWebKitDefaultFontSize,
- prefs::kWebKitFixedFontFamily,
- prefs::kWebKitJavaEnabled,
- prefs::kWebKitJavascriptEnabled,
- prefs::kWebKitLoadsImagesAutomatically,
- prefs::kWebKitPluginsEnabled,
- prefs::kWebKitSansSerifFontFamily,
- prefs::kWebKitSerifFontFamily,
- prefs::kWebKitMinimumFontSize,
- prefs::kWebKitMinimumLogicalFontSize,
- prefs::kWebkitTabsToLinks,
- };
- profile->GetDownloadManager()->download_prefs()->ResetToDefaults();
- profile->GetHostContentSettingsMap()->ResetToDefaults();
- profile->GetGeolocationContentSettingsMap()->ResetToDefault();
- profile->GetHostZoomMap()->ResetToDefaults();
- profile->GetDesktopNotificationService()->ResetToDefaultContentSetting();
- for (size_t i = 0; i < arraysize(kUserPrefs); ++i)
- prefs->ClearPref(kUserPrefs[i]);
-
- PrefService* local_state = g_browser_process->local_state();
- // Note that we don't reset the kMetricsReportingEnabled preference here
- // because the reset will reset it to the default setting specified in Chrome
- // source, not the default setting selected by the user on the web page where
- // they downloaded Chrome. This means that if the user ever resets their
- // settings they'll either inadvertedly enable this logging or disable it.
- // One is undesirable for them, one is undesirable for us. For now, we just
- // don't reset it.
- const char* kLocalStatePrefs[] = {
- prefs::kApplicationLocale,
- };
- for (size_t i = 0; i < arraysize(kLocalStatePrefs); ++i)
- local_state->ClearPref(kLocalStatePrefs[i]);
-}
-
-// static
-bool OptionsUtil::ResolveMetricsReportingEnabled(bool enabled) {
- // GoogleUpdateSettings touches the disk from the UI thread. MetricsService
- // also calls GoogleUpdateSettings below. http://crbug/62626
- base::ThreadRestrictions::ScopedAllowIO allow_io;
-
- GoogleUpdateSettings::SetCollectStatsConsent(enabled);
- bool update_pref = GoogleUpdateSettings::GetCollectStatsConsent();
-
- if (enabled != update_pref) {
- DVLOG(1) << "OptionsUtil: Unable to set crash report status to " << enabled;
- }
-
- // Only change the pref if GoogleUpdateSettings::GetCollectStatsConsent
- // succeeds.
- enabled = update_pref;
-
- MetricsService* metrics = g_browser_process->metrics_service();
- DCHECK(metrics);
- if (metrics) {
- metrics->SetUserPermitsUpload(enabled);
- if (enabled)
- metrics->Start();
- else
- metrics->Stop();
- }
-
- return enabled;
-}
diff --git a/chrome/browser/options_util.h b/chrome/browser/options_util.h
deleted file mode 100644
index 3dd10cf..0000000
--- a/chrome/browser/options_util.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_OPTIONS_UTIL_H_
-#define CHROME_BROWSER_OPTIONS_UTIL_H_
-#pragma once
-
-#include "base/basictypes.h"
-
-class Profile;
-
-class OptionsUtil {
- public:
- // Resets all prefs to their default values.
- static void ResetToDefaults(Profile* profile);
-
- // Try to make the the crash stats consent and the metrics upload
- // permission match |enabled|, returns the actual enabled setting.
- static bool ResolveMetricsReportingEnabled(bool enabled);
-
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(OptionsUtil);
-};
-
-#endif // CHROME_BROWSER_OPTIONS_UTIL_H_
diff --git a/chrome/browser/options_window.h b/chrome/browser/options_window.h
deleted file mode 100644
index 53292bd..0000000
--- a/chrome/browser/options_window.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_OPTIONS_WINDOW_H__
-#define CHROME_BROWSER_OPTIONS_WINDOW_H__
-#pragma once
-
-class Profile;
-
-// An identifier for a Options Tab page. These are treated as indices into
-// the list of available tabs to be displayed. PAGE_DEFAULT means select the
-// last tab viewed when the Options window was opened, or PAGE_GENERAL if the
-// Options was never opened.
-enum OptionsPage {
- OPTIONS_PAGE_DEFAULT = -1,
-#if defined(OS_CHROMEOS)
- OPTIONS_PAGE_SYSTEM,
- OPTIONS_PAGE_INTERNET,
-#endif
- OPTIONS_PAGE_GENERAL,
- OPTIONS_PAGE_CONTENT,
- OPTIONS_PAGE_ADVANCED,
- OPTIONS_PAGE_COUNT
-};
-
-// These are some well known groups within the Options dialog box that we may
-// wish to highlight to attract the user's attention to.
-enum OptionsGroup {
- OPTIONS_GROUP_NONE,
- OPTIONS_GROUP_DEFAULT_SEARCH
-};
-
-// Show the Options window selecting the specified page. If an Options window
-// is currently open, this just activates it instead of opening a new one.
-void ShowOptionsWindow(OptionsPage page,
- OptionsGroup highlight_group,
- Profile* profile);
-
-#endif // CHROME_BROWSER_OPTIONS_WINDOW_H_
diff --git a/chrome/browser/page_info_model.cc b/chrome/browser/page_info_model.cc
index 16a8255..750c45b 100644
--- a/chrome/browser/page_info_model.cc
+++ b/chrome/browser/page_info_model.cc
@@ -14,7 +14,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/cert_store.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ssl/ssl_manager.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
@@ -59,7 +59,7 @@ PageInfoModel::PageInfoModel(Profile* profile,
int status_with_warnings_removed = ssl.cert_status() & ~cert_warnings;
if (ssl.cert_id() &&
- CertStore::GetSharedInstance()->RetrieveCert(ssl.cert_id(), &cert) &&
+ CertStore::GetInstance()->RetrieveCert(ssl.cert_id(), &cert) &&
!net::IsCertStatusError(status_with_warnings_removed)) {
// No error found so far, check cert_status warnings.
int cert_status = ssl.cert_status();
@@ -329,7 +329,7 @@ void PageInfoModel::OnGotVisitCountToHost(HistoryService::Handle handle,
headline,
l10n_util::GetStringFUTF16(
IDS_PAGE_INFO_SECURITY_TAB_VISITED_BEFORE_TODAY,
- WideToUTF16(base::TimeFormatShortDate(first_visit))),
+ base::TimeFormatShortDate(first_visit)),
SECTION_INFO_FIRST_VISIT));
}
observer_->ModelChanged();
diff --git a/chrome/browser/parsers/metadata_parser_filebase.h b/chrome/browser/parsers/metadata_parser_filebase.h
index 9ed5775..e1614a8 100644
--- a/chrome/browser/parsers/metadata_parser_filebase.h
+++ b/chrome/browser/parsers/metadata_parser_filebase.h
@@ -27,7 +27,7 @@ class FileMetadataParser : public MetadataParser {
virtual bool Parse();
virtual bool GetProperty(const std::string& key, std::string* value);
- MetadataPropertyIterator* GetPropertyIterator();
+ virtual MetadataPropertyIterator* GetPropertyIterator();
protected:
PropertyMap properties_;
diff --git a/chrome/browser/parsers/metadata_parser_manager.cc b/chrome/browser/parsers/metadata_parser_manager.cc
index f428fa3..9d5d12c 100644
--- a/chrome/browser/parsers/metadata_parser_manager.cc
+++ b/chrome/browser/parsers/metadata_parser_manager.cc
@@ -15,12 +15,11 @@
static const int kAmountToRead = 256;
// Gets the singleton
-MetadataParserManager* MetadataParserManager::Get() {
- // Uses the LeakySingletonTrait because cleanup is optional.
- return
- Singleton<MetadataParserManager,
- LeakySingletonTraits<MetadataParserManager> >::get();
- }
+MetadataParserManager* MetadataParserManager::GetInstance() {
+ // Uses the LeakySingletonTrait because cleanup is optional.
+ return Singleton<MetadataParserManager,
+ LeakySingletonTraits<MetadataParserManager> >::get();
+}
bool MetadataParserManager::RegisterParserFactory(
MetadataParserFactory* parser) {
diff --git a/chrome/browser/parsers/metadata_parser_manager.h b/chrome/browser/parsers/metadata_parser_manager.h
index 67d7d51..ed922e3 100644
--- a/chrome/browser/parsers/metadata_parser_manager.h
+++ b/chrome/browser/parsers/metadata_parser_manager.h
@@ -22,7 +22,7 @@ class MetadataParserManager {
~MetadataParserManager();
// Gets the singleton
- static MetadataParserManager* Get();
+ static MetadataParserManager* GetInstance();
// Adds a new Parser to the manager, when requests come in for a parser
// the manager will loop through the list of parsers, and query each.
diff --git a/chrome/browser/password_manager/password_form_manager.cc b/chrome/browser/password_manager/password_form_manager.cc
index 977806d..f5c0f84 100644
--- a/chrome/browser/password_manager/password_form_manager.cc
+++ b/chrome/browser/password_manager/password_form_manager.cc
@@ -10,7 +10,7 @@
#include "base/string_split.h"
#include "base/string_util.h"
#include "chrome/browser/password_manager/password_manager.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "webkit/glue/password_form_dom_manager.h"
using base::Time;
diff --git a/chrome/browser/password_manager/password_form_manager_unittest.cc b/chrome/browser/password_manager/password_form_manager_unittest.cc
index 32e42d7..c0197e1 100644
--- a/chrome/browser/password_manager/password_form_manager_unittest.cc
+++ b/chrome/browser/password_manager/password_form_manager_unittest.cc
@@ -8,7 +8,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/password_manager/password_form_manager.h"
#include "chrome/browser/password_manager/password_manager.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/test/testing_profile.h"
#include "webkit/glue/password_form.h"
diff --git a/chrome/browser/password_manager/password_manager.cc b/chrome/browser/password_manager/password_manager.cc
index b5762b8..90de8be 100644
--- a/chrome/browser/password_manager/password_manager.cc
+++ b/chrome/browser/password_manager/password_manager.cc
@@ -13,9 +13,8 @@
#include "chrome/browser/password_manager/password_form_manager.h"
#include "chrome/browser/password_manager/password_manager_delegate.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages_params.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/password_manager/password_manager.h b/chrome/browser/password_manager/password_manager.h
index 0ebb451..23f8ca3 100644
--- a/chrome/browser/password_manager/password_manager.h
+++ b/chrome/browser/password_manager/password_manager.h
@@ -8,10 +8,10 @@
#include "base/scoped_ptr.h"
#include "base/stl_util-inl.h"
-#include "chrome/browser/login_model.h"
#include "chrome/browser/password_manager/password_form_manager.h"
#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/tab_contents/web_navigation_observer.h"
+#include "chrome/browser/ui/login/login_model.h"
#include "webkit/glue/password_form.h"
#include "webkit/glue/password_form_dom_manager.h"
diff --git a/chrome/browser/password_manager/password_manager_unittest.cc b/chrome/browser/password_manager/password_manager_unittest.cc
index 2be490f..78eae4a 100644
--- a/chrome/browser/password_manager/password_manager_unittest.cc
+++ b/chrome/browser/password_manager/password_manager_unittest.cc
@@ -2,8 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
+#include "chrome/browser/browser_thread.h"
#include "chrome/browser/password_manager/password_manager.h"
#include "chrome/browser/password_manager/password_manager_delegate.h"
#include "chrome/browser/password_manager/password_store.h"
diff --git a/chrome/browser/password_manager/password_store_default.cc b/chrome/browser/password_manager/password_store_default.cc
index d40672d..2be4551 100644
--- a/chrome/browser/password_manager/password_store_default.cc
+++ b/chrome/browser/password_manager/password_store_default.cc
@@ -9,6 +9,7 @@
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/password_manager/password_store_change.h"
#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/webdata/web_data_service.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/notification_service.h"
diff --git a/chrome/browser/password_manager/password_store_default.h b/chrome/browser/password_manager/password_store_default.h
index 4906ce8..82b93f4 100644
--- a/chrome/browser/password_manager/password_store_default.h
+++ b/chrome/browser/password_manager/password_store_default.h
@@ -6,13 +6,17 @@
#define CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_DEFAULT_H_
#pragma once
+#include <set>
+#include <vector>
+
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/password_manager/login_database.h"
#include "chrome/browser/password_manager/password_store.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/webdata/web_data_service.h"
+class Profile;
+
// Simple password store implementation that delegates everything to
// the LoginDatabase.
class PasswordStoreDefault : public PasswordStore,
@@ -27,26 +31,26 @@ class PasswordStoreDefault : public PasswordStore,
virtual ~PasswordStoreDefault();
// Implements PasswordStore interface.
- void ReportMetricsImpl();
- void AddLoginImpl(const webkit_glue::PasswordForm& form);
- void UpdateLoginImpl(const webkit_glue::PasswordForm& form);
- void RemoveLoginImpl(const webkit_glue::PasswordForm& form);
- void RemoveLoginsCreatedBetweenImpl(const base::Time& delete_begin,
- const base::Time& delete_end);
- void GetLoginsImpl(GetLoginsRequest* request,
- const webkit_glue::PasswordForm& form);
- void GetAutofillableLoginsImpl(GetLoginsRequest* request);
- void GetBlacklistLoginsImpl(GetLoginsRequest* request);
- bool FillAutofillableLogins(
+ virtual void ReportMetricsImpl();
+ virtual void AddLoginImpl(const webkit_glue::PasswordForm& form);
+ virtual void UpdateLoginImpl(const webkit_glue::PasswordForm& form);
+ virtual void RemoveLoginImpl(const webkit_glue::PasswordForm& form);
+ virtual void RemoveLoginsCreatedBetweenImpl(const base::Time& delete_begin,
+ const base::Time& delete_end);
+ virtual void GetLoginsImpl(GetLoginsRequest* request,
+ const webkit_glue::PasswordForm& form);
+ virtual void GetAutofillableLoginsImpl(GetLoginsRequest* request);
+ virtual void GetBlacklistLoginsImpl(GetLoginsRequest* request);
+ virtual bool FillAutofillableLogins(
std::vector<webkit_glue::PasswordForm*>* forms);
- bool FillBlacklistLogins(
+ virtual bool FillBlacklistLogins(
std::vector<webkit_glue::PasswordForm*>* forms);
scoped_refptr<WebDataService> web_data_service_;
// Implements the WebDataService consumer interface.
- void OnWebDataServiceRequestDone(WebDataService::Handle handle,
- const WDTypedResult *result);
+ virtual void OnWebDataServiceRequestDone(WebDataService::Handle handle,
+ const WDTypedResult *result);
protected:
inline bool DeleteAndRecreateDatabaseFile() {
diff --git a/chrome/browser/password_manager/password_store_default_unittest.cc b/chrome/browser/password_manager/password_store_default_unittest.cc
index 43bed39..537b134 100644
--- a/chrome/browser/password_manager/password_store_default_unittest.cc
+++ b/chrome/browser/password_manager/password_store_default_unittest.cc
@@ -14,9 +14,11 @@
#include "chrome/browser/password_manager/password_form_data.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/webdata/web_data_service.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_observer_mock.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/pref_names.h"
-#include "chrome/test/mock_notification_observer.h"
#include "chrome/test/signaling_task.h"
#include "chrome/test/testing_profile.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -60,7 +62,7 @@ class DBThreadObserverHelper :
FROM_HERE,
NewRunnableMethod(this,
&DBThreadObserverHelper::AddObserverTask,
- password_store));
+ make_scoped_refptr(password_store)));
done_event_.Wait();
}
@@ -69,7 +71,7 @@ class DBThreadObserverHelper :
registrar_.RemoveAll();
}
- MockNotificationObserver& observer() {
+ NotificationObserverMock& observer() {
return observer_;
}
@@ -86,7 +88,7 @@ class DBThreadObserverHelper :
WaitableEvent done_event_;
NotificationRegistrar registrar_;
- MockNotificationObserver observer_;
+ NotificationObserverMock observer_;
};
} // anonymous namespace
diff --git a/chrome/browser/password_manager/password_store_mac.cc b/chrome/browser/password_manager/password_store_mac.cc
index 0a0a88b..f45200a 100644
--- a/chrome/browser/password_manager/password_store_mac.cc
+++ b/chrome/browser/password_manager/password_store_mac.cc
@@ -20,6 +20,7 @@
#include "chrome/browser/keychain_mac.h"
#include "chrome/browser/password_manager/login_database.h"
#include "chrome/browser/password_manager/password_store_change.h"
+#include "chrome/common/notification_service.h"
using webkit_glue::PasswordForm;
diff --git a/chrome/browser/password_manager/password_store_mac.h b/chrome/browser/password_manager/password_store_mac.h
index aa5b144..8a70338 100644
--- a/chrome/browser/password_manager/password_store_mac.h
+++ b/chrome/browser/password_manager/password_store_mac.h
@@ -12,9 +12,9 @@
#include "base/thread.h"
#include "chrome/browser/password_manager/login_database.h"
#include "chrome/browser/password_manager/password_store.h"
-#include "chrome/common/notification_service.h"
class MacKeychain;
+class NotificationService;
// Implements PasswordStore on top of the OS X Keychain, with an internal
// database for extra metadata. For an overview of the interactions with the
diff --git a/chrome/browser/password_manager/password_store_win.cc b/chrome/browser/password_manager/password_store_win.cc
index 1ae4fbf..d31098e 100644
--- a/chrome/browser/password_manager/password_store_win.cc
+++ b/chrome/browser/password_manager/password_store_win.cc
@@ -9,7 +9,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/password_manager/ie7_password.h"
#include "chrome/browser/password_manager/password_manager.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
using std::map;
using std::vector;
diff --git a/chrome/browser/password_manager/password_store_x_unittest.cc b/chrome/browser/password_manager/password_store_x_unittest.cc
index 8379600..eb9f5b3 100644
--- a/chrome/browser/password_manager/password_store_x_unittest.cc
+++ b/chrome/browser/password_manager/password_store_x_unittest.cc
@@ -12,9 +12,9 @@
#include "chrome/browser/password_manager/password_store_change.h"
#include "chrome/browser/password_manager/password_store_x.h"
#include "chrome/browser/webdata/web_data_service.h"
+#include "chrome/common/notification_observer_mock.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
-#include "chrome/test/mock_notification_observer.h"
#include "chrome/test/signaling_task.h"
#include "chrome/test/testing_profile.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -67,7 +67,7 @@ class DBThreadObserverHelper
registrar_.RemoveAll();
}
- MockNotificationObserver& observer() {
+ NotificationObserverMock& observer() {
return observer_;
}
@@ -84,7 +84,7 @@ class DBThreadObserverHelper
WaitableEvent done_event_;
NotificationRegistrar registrar_;
- MockNotificationObserver observer_;
+ NotificationObserverMock observer_;
};
class FailingBackend : public PasswordStoreX::NativeBackend {
diff --git a/chrome/browser/platform_util_chromeos.cc b/chrome/browser/platform_util_chromeos.cc
index b8fd8e3..f059385 100644
--- a/chrome/browser/platform_util_chromeos.cc
+++ b/chrome/browser/platform_util_chromeos.cc
@@ -88,7 +88,7 @@ void OpenItem(const FilePath& full_path) {
ext == ".mp3" ||
ext == ".mkv" ||
ext == ".ogg") {
- MediaPlayer* mediaplayer = MediaPlayer::Get();
+ MediaPlayer* mediaplayer = MediaPlayer::GetInstance();
std::string url = "file://";
url += full_path.value();
GURL gurl(url);
diff --git a/chrome/browser/plugin_carbon_interpose_mac.cc b/chrome/browser/plugin_carbon_interpose_mac.cc
index 55e1405..2b60d66 100644
--- a/chrome/browser/plugin_carbon_interpose_mac.cc
+++ b/chrome/browser/plugin_carbon_interpose_mac.cc
@@ -8,7 +8,7 @@
#include "chrome/plugin/plugin_interpose_util_mac.h"
#include "gfx/rect.h"
-#include "webkit/glue/plugins/carbon_plugin_window_tracker_mac.h"
+#include "webkit/plugins/npapi/carbon_plugin_window_tracker_mac.h"
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
@@ -61,16 +61,16 @@ static void OnPluginWindowSelected(WindowRef window) {
static Boolean ChromePluginIsWindowActive(WindowRef window) {
const OpaquePluginRef delegate =
- CarbonPluginWindowTracker::SharedInstance()->GetDelegateForDummyWindow(
- window);
+ webkit::npapi::CarbonPluginWindowTracker::SharedInstance()->
+ GetDelegateForDummyWindow(window);
return delegate ? IsContainingWindowActive(delegate)
: IsWindowActive(window);
}
static Boolean ChromePluginIsWindowHilited(WindowRef window) {
const OpaquePluginRef delegate =
- CarbonPluginWindowTracker::SharedInstance()->GetDelegateForDummyWindow(
- window);
+ webkit::npapi::CarbonPluginWindowTracker::SharedInstance()->
+ GetDelegateForDummyWindow(window);
return delegate ? IsContainingWindowActive(delegate)
: IsWindowHilited(window);
}
@@ -126,8 +126,8 @@ static void ChromePluginDisposeDialog(DialogRef dialog) {
static WindowPartCode ChromePluginFindWindow(Point point, WindowRef* window) {
OpaquePluginRef delegate = mac_plugin_interposing::GetActiveDelegate();
- CarbonPluginWindowTracker* tracker =
- CarbonPluginWindowTracker::SharedInstance();
+ webkit::npapi::CarbonPluginWindowTracker* tracker =
+ webkit::npapi::CarbonPluginWindowTracker::SharedInstance();
WindowRef plugin_window = tracker->GetDummyWindowForDelegate(delegate);
if (plugin_window) {
// If plugin_window is non-NULL, then we are in the middle of routing an
diff --git a/chrome/browser/plugin_data_remover.cc b/chrome/browser/plugin_data_remover.cc
index 4415c5f..2baf0d0 100644
--- a/chrome/browser/plugin_data_remover.cc
+++ b/chrome/browser/plugin_data_remover.cc
@@ -5,46 +5,55 @@
#include "chrome/browser/plugin_data_remover.h"
#include "base/message_loop_proxy.h"
+#include "base/metrics/histogram.h"
+#include "base/version.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/plugin_service.h"
#include "chrome/common/plugin_messages.h"
-#include "ipc/ipc_channel.h"
+#include "webkit/plugins/npapi/plugin_group.h"
+#include "webkit/plugins/npapi/plugin_list.h"
#if defined(OS_POSIX)
#include "ipc/ipc_channel_posix.h"
#endif
namespace {
-const std::string flash_mime_type = "application/x-shockwave-flash";
-const int64 timeout_ms = 10000;
-}
+const char* g_flash_mime_type = "application/x-shockwave-flash";
+// TODO(bauerb): Update minimum required Flash version as soon as there is one
+// implementing the API.
+const char* g_min_flash_version = "100";
+const int64 g_timeout_ms = 10000;
+} // namespace
PluginDataRemover::PluginDataRemover()
- : channel_(NULL),
- method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
-}
+ : is_removing_(false),
+ channel_(NULL) { }
PluginDataRemover::~PluginDataRemover() {
- DCHECK(!done_task_.get());
- if (!BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, channel_))
- delete channel_;
+ DCHECK(!is_removing_);
+ if (channel_)
+ BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, channel_);
}
void PluginDataRemover::StartRemoving(base::Time begin_time, Task* done_task) {
DCHECK(!done_task_.get());
+ DCHECK(!is_removing_);
+ remove_start_time_ = base::Time::Now();
begin_time_ = begin_time;
message_loop_ = base::MessageLoopProxy::CreateForCurrentThread();
done_task_.reset(done_task);
+ is_removing_ = true;
+ AddRef();
PluginService::GetInstance()->OpenChannelToPlugin(
- GURL(), flash_mime_type, this);
+ GURL(), g_flash_mime_type, this);
BrowserThread::PostDelayedTask(
BrowserThread::IO,
FROM_HERE,
- method_factory_.NewRunnableMethod(&PluginDataRemover::OnTimeout),
- timeout_ms);
+ NewRunnableMethod(this, &PluginDataRemover::OnTimeout),
+ g_timeout_ms);
}
int PluginDataRemover::ID() {
@@ -56,27 +65,33 @@ bool PluginDataRemover::OffTheRecord() {
return false;
}
-void PluginDataRemover::SetPluginInfo(const WebPluginInfo& info) {
+void PluginDataRemover::SetPluginInfo(
+ const webkit::npapi::WebPluginInfo& info) {
}
void PluginDataRemover::OnChannelOpened(const IPC::ChannelHandle& handle) {
+ ConnectToChannel(handle);
+ Release();
+}
+
+void PluginDataRemover::ConnectToChannel(const IPC::ChannelHandle& handle) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ // If we timed out, don't bother connecting.
+ if (!is_removing_)
+ return;
+
DCHECK(!channel_);
-#if defined(OS_POSIX)
- // If we received a ChannelHandle, register it now.
- if (handle.socket.fd >= 0)
- IPC::AddChannelSocket(handle.name, handle.socket.fd);
-#endif
- channel_ = new IPC::Channel(handle.name, IPC::Channel::MODE_CLIENT, this);
+ channel_ = new IPC::Channel(handle, IPC::Channel::MODE_CLIENT, this);
if (!channel_->Connect()) {
- NOTREACHED() << "Couldn't connect to plugin";
+ LOG(DFATAL) << "Couldn't connect to plugin";
SignalDone();
return;
}
if (!channel_->Send(
new PluginMsg_ClearSiteData(0, std::string(), begin_time_))) {
- NOTREACHED() << "Couldn't send ClearSiteData message";
+ LOG(DFATAL) << "Couldn't send ClearSiteData message";
SignalDone();
}
}
@@ -84,10 +99,14 @@ void PluginDataRemover::OnChannelOpened(const IPC::ChannelHandle& handle) {
void PluginDataRemover::OnError() {
NOTREACHED() << "Couldn't open plugin channel";
SignalDone();
+ Release();
}
void PluginDataRemover::OnClearSiteDataResult(bool success) {
- DCHECK(success) << "ClearSiteData returned error";
+ if (!success)
+ LOG(DFATAL) << "ClearSiteData returned error";
+ UMA_HISTOGRAM_TIMES("ClearPluginData.time",
+ base::Time::Now() - remove_start_time_);
SignalDone();
}
@@ -96,23 +115,49 @@ void PluginDataRemover::OnTimeout() {
SignalDone();
}
-void PluginDataRemover::OnMessageReceived(const IPC::Message& msg) {
+bool PluginDataRemover::OnMessageReceived(const IPC::Message& msg) {
IPC_BEGIN_MESSAGE_MAP(PluginDataRemover, msg)
IPC_MESSAGE_HANDLER(PluginHostMsg_ClearSiteDataResult,
OnClearSiteDataResult)
IPC_MESSAGE_UNHANDLED_ERROR()
IPC_END_MESSAGE_MAP()
+
+ return true;
}
void PluginDataRemover::OnChannelError() {
- NOTREACHED() << "Channel error";
+ LOG(DFATAL) << "Channel error";
SignalDone();
}
void PluginDataRemover::SignalDone() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (!done_task_.get())
+ if (!is_removing_)
return;
- message_loop_->PostTask(FROM_HERE, done_task_.release());
- message_loop_ = NULL;
+ is_removing_ = false;
+ if (done_task_.get()) {
+ message_loop_->PostTask(FROM_HERE, done_task_.release());
+ message_loop_ = NULL;
+ }
+}
+
+// static
+bool PluginDataRemover::IsSupported() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ bool allow_wildcard = false;
+ webkit::npapi::WebPluginInfo plugin;
+ std::string mime_type;
+ if (!webkit::npapi::PluginList::Singleton()->GetPluginInfo(GURL(),
+ g_flash_mime_type,
+ allow_wildcard,
+ &plugin,
+ &mime_type))
+ return false;
+ scoped_ptr<Version> version(
+ webkit::npapi::PluginGroup::CreateVersionFromString(plugin.version));
+ scoped_ptr<Version> min_version(
+ Version::GetVersionFromString(g_min_flash_version));
+ return plugin.enabled &&
+ version.get() &&
+ min_version->CompareTo(*version) == -1;
}
diff --git a/chrome/browser/plugin_data_remover.h b/chrome/browser/plugin_data_remover.h
index cbc2556..77f7f58 100644
--- a/chrome/browser/plugin_data_remover.h
+++ b/chrome/browser/plugin_data_remover.h
@@ -9,8 +9,7 @@
#include "base/ref_counted.h"
#include "base/time.h"
#include "chrome/browser/plugin_process_host.h"
-#include "ipc/ipc_channel_proxy.h"
-#include "ipc/ipc_message.h"
+#include "ipc/ipc_channel.h"
class Task;
@@ -18,40 +17,57 @@ namespace base {
class MessageLoopProxy;
}
-class PluginDataRemover : public PluginProcessHost::Client,
+class PluginDataRemover : public base::RefCountedThreadSafe<PluginDataRemover>,
+ public PluginProcessHost::Client,
public IPC::Channel::Listener {
public:
PluginDataRemover();
- ~PluginDataRemover();
- // Starts removing plug-in data stored since |begin_time| and calls
- // |done_task| on the current thread when finished.
+ // Starts removing plug-in data stored since |begin_time|. If |done_task| is
+ // not NULL, it is run on the current thread when removing has finished.
void StartRemoving(base::Time begin_time, Task* done_task);
+ // Returns whether there is a plug-in installed that supports removing
+ // LSO data. Because this method possibly has to load the plug-in list, it
+ // should only be called on the FILE thread.
+ static bool IsSupported();
+
+ bool is_removing() const { return is_removing_; }
+
+ // Sets the task to run when removing has finished. Takes ownership of
+ // the passed task.
+ void set_done_task(Task* task) { done_task_.reset(task); }
+
// PluginProcessHost::Client methods
virtual int ID();
virtual bool OffTheRecord();
- virtual void SetPluginInfo(const WebPluginInfo& info);
+ virtual void SetPluginInfo(const webkit::npapi::WebPluginInfo& info);
virtual void OnChannelOpened(const IPC::ChannelHandle& handle);
virtual void OnError();
- // IPC::ChannelProxy::MessageFilter methods
- virtual void OnMessageReceived(const IPC::Message& message);
+ // IPC::Channel::Listener methods
+ virtual bool OnMessageReceived(const IPC::Message& message);
virtual void OnChannelError();
private:
+ friend class base::RefCountedThreadSafe<PluginDataRemover>;
+ ~PluginDataRemover();
+
void SignalDone();
- void SignalError();
+ void ConnectToChannel(const IPC::ChannelHandle& handle);
void OnClearSiteDataResult(bool success);
void OnTimeout();
scoped_refptr<base::MessageLoopProxy> message_loop_;
+ bool is_removing_;
scoped_ptr<Task> done_task_;
+ // The point in time when we start removing data.
+ base::Time remove_start_time_;
+ // The point in time from which on we remove data.
base::Time begin_time_;
// We own the channel, but it's used on the IO thread, so it needs to be
// deleted there as well.
IPC::Channel* channel_;
- ScopedRunnableMethodFactory<PluginDataRemover> method_factory_;
};
#endif // CHROME_BROWSER_PLUGIN_DATA_REMOVER_H_
diff --git a/chrome/browser/plugin_data_remover_helper.cc b/chrome/browser/plugin_data_remover_helper.cc
new file mode 100644
index 0000000..43eb4f6
--- /dev/null
+++ b/chrome/browser/plugin_data_remover_helper.cc
@@ -0,0 +1,90 @@
+// 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.
+
+#include "chrome/browser/plugin_data_remover_helper.h"
+
+#include "base/ref_counted.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/plugin_data_remover.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+
+// The internal class is refcounted so it can outlive PluginDataRemoverHelper.
+class PluginDataRemoverHelper::Internal
+ : public base::RefCountedThreadSafe<PluginDataRemoverHelper::Internal> {
+ public:
+ explicit Internal(const char* pref_name, PrefService* prefs)
+ : pref_name_(pref_name), prefs_(prefs) {}
+
+ void StartUpdate() {
+ BrowserThread::PostTask(
+ BrowserThread::FILE,
+ FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &PluginDataRemoverHelper::Internal::UpdateOnFileThread));
+ }
+
+ void Invalidate() {
+ prefs_ = NULL;
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<Internal>;
+
+ ~Internal() {}
+
+ void UpdateOnFileThread() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ bool result = PluginDataRemover::IsSupported();
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ NewRunnableMethod(this,
+ &PluginDataRemoverHelper::Internal::SetPrefOnUIThread,
+ result));
+ }
+
+ void SetPrefOnUIThread(bool value) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (prefs_)
+ prefs_->SetBoolean(pref_name_.c_str(), value);
+ }
+
+ std::string pref_name_;
+ // Weak pointer.
+ PrefService* prefs_;
+
+ DISALLOW_COPY_AND_ASSIGN(Internal);
+};
+
+PluginDataRemoverHelper::PluginDataRemoverHelper() {}
+
+PluginDataRemoverHelper::~PluginDataRemoverHelper() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (internal_)
+ internal_->Invalidate();
+}
+
+void PluginDataRemoverHelper::Init(const char* pref_name,
+ PrefService* prefs,
+ NotificationObserver* observer) {
+ pref_.Init(pref_name, prefs, observer);
+ registrar_.Add(this, NotificationType::PLUGIN_ENABLE_STATUS_CHANGED,
+ NotificationService::AllSources());
+ internal_ = make_scoped_refptr(new Internal(pref_name, prefs));
+ internal_->StartUpdate();
+}
+
+void PluginDataRemoverHelper::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type.value == NotificationType::PLUGIN_ENABLE_STATUS_CHANGED) {
+ internal_->StartUpdate();
+ } else {
+ NOTREACHED();
+ }
+}
diff --git a/chrome/browser/plugin_data_remover_helper.h b/chrome/browser/plugin_data_remover_helper.h
new file mode 100644
index 0000000..a1a6537
--- /dev/null
+++ b/chrome/browser/plugin_data_remover_helper.h
@@ -0,0 +1,51 @@
+// 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.
+
+#ifndef CHROME_BROWSER_PLUGIN_DATA_REMOVER_HELPER_H_
+#define CHROME_BROWSER_PLUGIN_DATA_REMOVER_HELPER_H_
+#pragma once
+
+#include "base/ref_counted.h"
+#include "chrome/browser/prefs/pref_member.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+
+class Profile;
+
+// Helper class modeled after BooleanPrefMember to (asynchronously) update
+// the preference specifying whether clearing plug-in data is supported
+// by an installed plug-in.
+// It should only be used from the UI thread. The client has to make sure that
+// the passed PrefService outlives this object.
+class PluginDataRemoverHelper : public NotificationObserver {
+ public:
+ PluginDataRemoverHelper();
+ ~PluginDataRemoverHelper();
+
+ // Binds this object to the |pref_name| preference in |prefs|, notifying
+ // |observer| if the value changes.
+ // This fires off a request to the NPAPI::PluginList (via PluginDataRemover)
+ // on the FILE thread to get the list of installed plug-ins.
+ void Init(const char* pref_name,
+ PrefService* prefs,
+ NotificationObserver* observer);
+
+ bool GetValue() const { return pref_.GetValue(); }
+
+ // NotificationObserver methods:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ private:
+ class Internal;
+
+ BooleanPrefMember pref_;
+ NotificationRegistrar registrar_;
+ scoped_refptr<Internal> internal_;
+
+ DISALLOW_COPY_AND_ASSIGN(PluginDataRemoverHelper);
+};
+
+#endif // CHROME_BROWSER_PLUGIN_DATA_REMOVER_HELPER_H_
diff --git a/chrome/browser/plugin_download_helper.cc b/chrome/browser/plugin_download_helper.cc
index 5f17725..0d85e27 100644
--- a/chrome/browser/plugin_download_helper.cc
+++ b/chrome/browser/plugin_download_helper.cc
@@ -35,7 +35,7 @@ PluginDownloadUrlHelper::~PluginDownloadUrlHelper() {
void PluginDownloadUrlHelper::InitiateDownload(
URLRequestContext* request_context) {
- download_file_request_ = new URLRequest(GURL(download_url_), this);
+ download_file_request_ = new net::URLRequest(GURL(download_url_), this);
chrome_browser_net::SetOriginProcessUniqueIDForRequest(
download_source_child_unique_id_, download_file_request_);
download_file_request_->set_context(request_context);
@@ -43,21 +43,21 @@ void PluginDownloadUrlHelper::InitiateDownload(
}
void PluginDownloadUrlHelper::OnAuthRequired(
- URLRequest* request,
+ net::URLRequest* request,
net::AuthChallengeInfo* auth_info) {
- URLRequest::Delegate::OnAuthRequired(request, auth_info);
+ net::URLRequest::Delegate::OnAuthRequired(request, auth_info);
DownloadCompletedHelper(false);
}
void PluginDownloadUrlHelper::OnSSLCertificateError(
- URLRequest* request,
+ net::URLRequest* request,
int cert_error,
net::X509Certificate* cert) {
- URLRequest::Delegate::OnSSLCertificateError(request, cert_error, cert);
+ net::URLRequest::Delegate::OnSSLCertificateError(request, cert_error, cert);
DownloadCompletedHelper(false);
}
-void PluginDownloadUrlHelper::OnResponseStarted(URLRequest* request) {
+void PluginDownloadUrlHelper::OnResponseStarted(net::URLRequest* request) {
if (!download_file_->IsOpen()) {
// This is safe because once the temp file has been safely created, an
// attacker can't drop a symlink etc into place.
@@ -91,7 +91,7 @@ void PluginDownloadUrlHelper::OnResponseStarted(URLRequest* request) {
}
}
-void PluginDownloadUrlHelper::OnReadCompleted(URLRequest* request,
+void PluginDownloadUrlHelper::OnReadCompleted(net::URLRequest* request,
int bytes_read) {
DCHECK(download_file_->IsOpen());
@@ -129,7 +129,7 @@ void PluginDownloadUrlHelper::OnReadCompleted(URLRequest* request,
}
}
-void PluginDownloadUrlHelper::OnDownloadCompleted(URLRequest* request) {
+void PluginDownloadUrlHelper::OnDownloadCompleted(net::URLRequest* request) {
bool success = true;
if (!request->status().is_success()) {
success = false;
diff --git a/chrome/browser/plugin_download_helper.h b/chrome/browser/plugin_download_helper.h
index 5d1a243..cccf3f0 100644
--- a/chrome/browser/plugin_download_helper.h
+++ b/chrome/browser/plugin_download_helper.h
@@ -18,7 +18,7 @@
// The PluginDownloadUrlHelper is used to handle one download URL request
// from the plugin. Each download request is handled by a new instance
// of this class.
-class PluginDownloadUrlHelper : public URLRequest::Delegate {
+class PluginDownloadUrlHelper : public net::URLRequest::Delegate {
static const int kDownloadFileBufferSize = 32768;
public:
// The delegate receives notification about the status of downloads
@@ -38,27 +38,27 @@ class PluginDownloadUrlHelper : public URLRequest::Delegate {
void InitiateDownload(URLRequestContext* request_context);
- // URLRequest::Delegate
- virtual void OnAuthRequired(URLRequest* request,
+ // net::URLRequest::Delegate
+ virtual void OnAuthRequired(net::URLRequest* request,
net::AuthChallengeInfo* auth_info);
- virtual void OnSSLCertificateError(URLRequest* request,
+ virtual void OnSSLCertificateError(net::URLRequest* request,
int cert_error,
net::X509Certificate* cert);
- virtual void OnResponseStarted(URLRequest* request);
- virtual void OnReadCompleted(URLRequest* request, int bytes_read);
+ virtual void OnResponseStarted(net::URLRequest* request);
+ virtual void OnReadCompleted(net::URLRequest* request, int bytes_read);
- void OnDownloadCompleted(URLRequest* request);
+ void OnDownloadCompleted(net::URLRequest* request);
protected:
void DownloadCompletedHelper(bool success);
// The download file request initiated by the plugin.
- URLRequest* download_file_request_;
+ net::URLRequest* download_file_request_;
// Handle to the downloaded file.
scoped_ptr<net::FileStream> download_file_;
// The full path of the downloaded file.
FilePath download_file_path_;
- // The buffer passed off to URLRequest::Read.
+ // The buffer passed off to net::URLRequest::Read.
scoped_refptr<net::IOBuffer> download_file_buffer_;
// TODO(port): this comment doesn't describe the situation on Posix.
// The window handle for sending the WM_COPYDATA notification,
diff --git a/chrome/browser/plugin_exceptions_table_model.cc b/chrome/browser/plugin_exceptions_table_model.cc
index 21ed547..5b2a2c1 100644
--- a/chrome/browser/plugin_exceptions_table_model.cc
+++ b/chrome/browser/plugin_exceptions_table_model.cc
@@ -102,6 +102,10 @@ std::wstring PluginExceptionsTableModel::GetText(int row, int column_id) {
return std::wstring();
}
+bool PluginExceptionsTableModel::HasGroups() {
+ return true;
+}
+
void PluginExceptionsTableModel::SetObserver(TableModelObserver* observer) {
observer_ = observer;
}
@@ -130,17 +134,16 @@ void PluginExceptionsTableModel::ClearSettings() {
}
void PluginExceptionsTableModel::GetPlugins(
- NPAPI::PluginList::PluginMap* plugins) {
- NPAPI::PluginList::Singleton()->GetPluginGroups(false, plugins);
+ std::vector<webkit::npapi::PluginGroup>* plugin_groups) {
+ webkit::npapi::PluginList::Singleton()->GetPluginGroups(false, plugin_groups);
}
void PluginExceptionsTableModel::LoadSettings() {
int group_id = 0;
- NPAPI::PluginList::PluginMap plugins;
+ std::vector<webkit::npapi::PluginGroup> plugins;
GetPlugins(&plugins);
- for (NPAPI::PluginList::PluginMap::iterator it = plugins.begin();
- it != plugins.end(); ++it) {
- std::string plugin = it->first;
+ for (size_t i = 0; i < plugins.size(); ++i) {
+ std::string plugin = plugins[i].identifier();
HostContentSettingsMap::SettingsForOneType settings;
map_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
plugin,
@@ -151,7 +154,7 @@ void PluginExceptionsTableModel::LoadSettings() {
plugin,
&otr_settings);
}
- std::wstring title = UTF16ToWide(it->second->GetGroupName());
+ std::wstring title = UTF16ToWide(plugins[i].GetGroupName());
for (HostContentSettingsMap::SettingsForOneType::iterator setting_it =
settings.begin(); setting_it != settings.end(); ++setting_it) {
SettingsEntry entry = {
diff --git a/chrome/browser/plugin_exceptions_table_model.h b/chrome/browser/plugin_exceptions_table_model.h
index f4f59e8..045c218 100644
--- a/chrome/browser/plugin_exceptions_table_model.h
+++ b/chrome/browser/plugin_exceptions_table_model.h
@@ -7,15 +7,14 @@
#pragma once
#include <deque>
+#include <string>
+#include <vector>
-#include "chrome/browser/host_content_settings_map.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/remove_rows_table_model.h"
#include "chrome/common/notification_observer.h"
-#include "webkit/glue/plugins/plugin_list.h"
+#include "webkit/plugins/npapi/plugin_list.h"
-namespace plugin_test_internal {
-class PluginExceptionsTableModelTest;
-}
struct WebPluginInfo;
class PluginExceptionsTableModel : public RemoveRowsTableModel,
@@ -38,7 +37,7 @@ class PluginExceptionsTableModel : public RemoveRowsTableModel,
virtual int RowCount();
virtual std::wstring GetText(int row, int column_id);
virtual void SetObserver(TableModelObserver* observer);
- virtual bool HasGroups() { return true; }
+ virtual bool HasGroups();
virtual Groups GetGroups();
virtual int GetGroupID(int row);
@@ -49,16 +48,17 @@ class PluginExceptionsTableModel : public RemoveRowsTableModel,
protected:
// Subclasses can override this method for testing.
- virtual void GetPlugins(NPAPI::PluginList::PluginMap* plugins);
+ virtual void GetPlugins(
+ std::vector<webkit::npapi::PluginGroup>* plugin_groups);
private:
- friend class plugin_test_internal::PluginExceptionsTableModelTest;
+ friend class PluginExceptionsTableModelTest;
struct SettingsEntry {
- HostContentSettingsMap::Pattern pattern;
- int plugin_id;
- ContentSetting setting;
- bool is_otr;
+ ContentSettingsPattern pattern;
+ int plugin_id;
+ ContentSetting setting;
+ bool is_otr;
};
void ClearSettings();
diff --git a/chrome/browser/plugin_exceptions_table_model_unittest.cc b/chrome/browser/plugin_exceptions_table_model_unittest.cc
index 813083c..e7efcca 100644
--- a/chrome/browser/plugin_exceptions_table_model_unittest.cc
+++ b/chrome/browser/plugin_exceptions_table_model_unittest.cc
@@ -13,15 +13,14 @@
#include "chrome/test/testing_profile.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/glue/plugins/plugin_group.h"
-#include "webkit/glue/plugins/webplugininfo.h"
+#include "webkit/plugins/npapi/plugin_group.h"
+#include "webkit/plugins/npapi/webplugininfo.h"
// Can't be an internal namespace because PluginExceptionsTableModel declares
// as a friend.
namespace plugin_test_internal {
using ::testing::_;
-using ::testing::InSequence;
using ::testing::Invoke;
class MockTableModelObserver : public TableModelObserver {
@@ -50,6 +49,10 @@ class MockTableModelObserver : public TableModelObserver {
TableModel* model_;
};
+} // namespace plugin_test_internal
+
+using ::testing::InSequence;
+
class PluginExceptionsTableModelTest : public testing::Test {
public:
PluginExceptionsTableModelTest()
@@ -65,8 +68,8 @@ class PluginExceptionsTableModelTest : public testing::Test {
HostContentSettingsMap* map = profile_->GetHostContentSettingsMap();
- HostContentSettingsMap::Pattern example_com("[*.]example.com");
- HostContentSettingsMap::Pattern moose_org("[*.]moose.org");
+ ContentSettingsPattern example_com("[*.]example.com");
+ ContentSettingsPattern moose_org("[*.]moose.org");
map->SetContentSetting(example_com,
CONTENT_SETTINGS_TYPE_PLUGINS,
"a-foo",
@@ -82,20 +85,22 @@ class PluginExceptionsTableModelTest : public testing::Test {
table_model_.reset(new MockPluginExceptionsTableModel(map, NULL));
- NPAPI::PluginList::PluginMap plugins;
- WebPluginInfo foo_plugin;
+ std::vector<webkit::npapi::PluginGroup> plugins;
+ webkit::npapi::WebPluginInfo foo_plugin;
foo_plugin.path = FilePath(FILE_PATH_LITERAL("a-foo"));
foo_plugin.name = ASCIIToUTF16("FooPlugin");
foo_plugin.enabled = true;
- PluginGroup* foo_group = PluginGroup::FromWebPluginInfo(foo_plugin);
- plugins[foo_group->identifier()] = linked_ptr<PluginGroup>(foo_group);
+ scoped_ptr<webkit::npapi::PluginGroup> foo_group(
+ webkit::npapi::PluginGroup::FromWebPluginInfo(foo_plugin));
+ plugins.push_back(*foo_group);
- WebPluginInfo bar_plugin;
+ webkit::npapi::WebPluginInfo bar_plugin;
bar_plugin.path = FilePath(FILE_PATH_LITERAL("b-bar"));
bar_plugin.name = ASCIIToUTF16("BarPlugin");
bar_plugin.enabled = true;
- PluginGroup* bar_group = PluginGroup::FromWebPluginInfo(bar_plugin);
- plugins[bar_group->identifier()] = linked_ptr<PluginGroup>(bar_group);
+ scoped_ptr<webkit::npapi::PluginGroup> bar_group(
+ webkit::npapi::PluginGroup::FromWebPluginInfo(bar_plugin));
+ plugins.push_back(*bar_group);
table_model_->set_plugins(plugins);
table_model_->ReloadSettings();
@@ -152,7 +157,7 @@ TEST_F(PluginExceptionsTableModelTest, Basic) {
}
TEST_F(PluginExceptionsTableModelTest, RemoveOneRow) {
- MockTableModelObserver observer(table_model_.get());
+ plugin_test_internal::MockTableModelObserver observer(table_model_.get());
table_model_->SetObserver(&observer);
EXPECT_CALL(observer, OnItemsRemoved(1, 1));
@@ -166,7 +171,7 @@ TEST_F(PluginExceptionsTableModelTest, RemoveOneRow) {
}
TEST_F(PluginExceptionsTableModelTest, RemoveLastRowInGroup) {
- MockTableModelObserver observer(table_model_.get());
+ plugin_test_internal::MockTableModelObserver observer(table_model_.get());
table_model_->SetObserver(&observer);
EXPECT_CALL(observer, OnModelChanged());
@@ -179,7 +184,7 @@ TEST_F(PluginExceptionsTableModelTest, RemoveLastRowInGroup) {
HostContentSettingsMap* map = profile_->GetHostContentSettingsMap();
EXPECT_CALL(observer, OnModelChanged());
- map->SetContentSetting(HostContentSettingsMap::Pattern("[*.]blurp.net"),
+ map->SetContentSetting(ContentSettingsPattern("[*.]blurp.net"),
CONTENT_SETTINGS_TYPE_PLUGINS,
"b-bar",
CONTENT_SETTING_BLOCK);
@@ -200,7 +205,7 @@ TEST_F(PluginExceptionsTableModelTest, RemoveLastRowInGroup) {
}
TEST_F(PluginExceptionsTableModelTest, RemoveAllRows) {
- MockTableModelObserver observer(table_model_.get());
+ plugin_test_internal::MockTableModelObserver observer(table_model_.get());
table_model_->SetObserver(&observer);
EXPECT_CALL(observer, OnModelChanged());
@@ -210,5 +215,3 @@ TEST_F(PluginExceptionsTableModelTest, RemoveAllRows) {
CheckInvariants();
table_model_->SetObserver(NULL);
}
-
-} // namespace plugin_test_internal
diff --git a/chrome/browser/plugin_installer.cc b/chrome/browser/plugin_installer.cc
index b6ceb3c..8d63679 100644
--- a/chrome/browser/plugin_installer.cc
+++ b/chrome/browser/plugin_installer.cc
@@ -12,7 +12,7 @@
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "grit/theme_resources.h"
-#include "webkit/glue/plugins/default_plugin_shared.h"
+#include "webkit/plugins/npapi/default_plugin_shared.h"
// The URL for the "Problems installing" page for the Plugins infobar.
static const char kLearnMorePluginInstallerUrl[] =
@@ -30,11 +30,11 @@ PluginInstaller::~PluginInstaller() {
void PluginInstaller::OnMissingPluginStatus(int status) {
switch (status) {
- case default_plugin::MISSING_PLUGIN_AVAILABLE: {
+ case webkit::npapi::default_plugin::MISSING_PLUGIN_AVAILABLE: {
tab_contents_->AddInfoBar(this);
break;
}
- case default_plugin::MISSING_PLUGIN_USER_STARTED_DOWNLOAD: {
+ case webkit::npapi::default_plugin::MISSING_PLUGIN_USER_STARTED_DOWNLOAD: {
// Hide the InfoBar if user already started download/install of the
// missing plugin.
tab_contents_->RemoveInfoBar(this);
diff --git a/chrome/browser/plugin_process_host.cc b/chrome/browser/plugin_process_host.cc
index 8e459ee..cb99a80 100644
--- a/chrome/browser/plugin_process_host.cc
+++ b/chrome/browser/plugin_process_host.cc
@@ -26,8 +26,9 @@
#include "chrome/browser/net/url_request_tracking.h"
#include "chrome/browser/plugin_download_helper.h"
#include "chrome/browser/plugin_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+#include "chrome/browser/renderer_host/resource_message_filter.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_plugin_lib.h"
#include "chrome/common/chrome_switches.h"
@@ -55,6 +56,28 @@
static const char kDefaultPluginFinderURL[] =
"https://dl-ssl.google.com/edgedl/chrome/plugins/plugins2.xml";
+namespace {
+
+// Helper class that we pass to ResourceMessageFilter so that it can find the
+// right URLRequestContext for a request.
+class PluginURLRequestContextOverride
+ : public ResourceMessageFilter::URLRequestContextOverride {
+ public:
+ PluginURLRequestContextOverride() {
+ }
+
+ virtual URLRequestContext* GetRequestContext(
+ uint32 request_id, ResourceType::Type resource_type) {
+ return CPBrowsingContextManager::GetInstance()->ToURLRequestContext(
+ request_id);
+ }
+
+ private:
+ virtual ~PluginURLRequestContextOverride() {}
+};
+
+} // namespace
+
#if defined(OS_WIN)
void PluginProcessHost::OnPluginWindowDestroyed(HWND window, HWND parent) {
// The window is destroyed at this point, we just care about its parent, which
@@ -87,14 +110,15 @@ void PluginProcessHost::AddWindow(HWND window) {
void PluginProcessHost::OnMapNativeViewId(gfx::NativeViewId id,
gfx::PluginWindowHandle* output) {
*output = 0;
- Singleton<GtkNativeViewManager>()->GetXIDForId(output, id);
+ GtkNativeViewManager::GetInstance()->GetXIDForId(output, id);
}
#endif // defined(TOOLKIT_USES_GTK)
PluginProcessHost::PluginProcessHost()
: BrowserChildProcessHost(
PLUGIN_PROCESS,
- PluginService::GetInstance()->resource_dispatcher_host()),
+ PluginService::GetInstance()->resource_dispatcher_host(),
+ new PluginURLRequestContextOverride()),
ALLOW_THIS_IN_INITIALIZER_LIST(resolve_proxy_msg_helper_(this, NULL))
#if defined(OS_MACOSX)
, plugin_cursor_visible_(true)
@@ -148,7 +172,7 @@ PluginProcessHost::~PluginProcessHost() {
CancelRequests();
}
-bool PluginProcessHost::Init(const WebPluginInfo& info,
+bool PluginProcessHost::Init(const webkit::npapi::WebPluginInfo& info,
const std::string& locale) {
info_ = info;
set_name(UTF16ToWideHack(info_.name));
@@ -274,7 +298,8 @@ void PluginProcessHost::OnProcessLaunched() {
}
}
-void PluginProcessHost::OnMessageReceived(const IPC::Message& msg) {
+bool PluginProcessHost::OnMessageReceived(const IPC::Message& msg) {
+ bool handled = true;
IPC_BEGIN_MESSAGE_MAP(PluginProcessHost, msg)
IPC_MESSAGE_HANDLER(PluginProcessHostMsg_ChannelCreated, OnChannelCreated)
IPC_MESSAGE_HANDLER(PluginProcessHostMsg_GetPluginFinderUrl,
@@ -303,8 +328,11 @@ void PluginProcessHost::OnMessageReceived(const IPC::Message& msg) {
IPC_MESSAGE_HANDLER(PluginProcessHostMsg_PluginSetCursorVisibility,
OnPluginSetCursorVisibility)
#endif
- IPC_MESSAGE_UNHANDLED_ERROR()
+ IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
+
+ DCHECK(handled);
+ return handled;
}
void PluginProcessHost::OnChannelConnected(int32 peer_pid) {
@@ -319,6 +347,10 @@ void PluginProcessHost::OnChannelError() {
CancelRequests();
}
+bool PluginProcessHost::CanShutdown() {
+ return sent_requests_.empty();
+}
+
void PluginProcessHost::CancelRequests() {
for (size_t i = 0; i < pending_requests_.size(); ++i)
pending_requests_[i]->OnError();
@@ -348,7 +380,7 @@ void PluginProcessHost::OpenChannelToPlugin(Client* client) {
void PluginProcessHost::OnGetCookies(uint32 request_context,
const GURL& url,
std::string* cookies) {
- URLRequestContext* context = CPBrowsingContextManager::Instance()->
+ URLRequestContext* context = CPBrowsingContextManager::GetInstance()->
ToURLRequestContext(request_context);
// TODO(mpcomplete): remove fallback case when Gears support is prevalent.
if (!context)
@@ -395,12 +427,6 @@ void PluginProcessHost::OnResolveProxyCompleted(IPC::Message* reply_msg,
Send(reply_msg);
}
-URLRequestContext* PluginProcessHost::GetRequestContext(
- uint32 request_id,
- const ViewHostMsg_Resource_Request& request_data) {
- return CPBrowsingContextManager::Instance()->ToURLRequestContext(request_id);
-}
-
void PluginProcessHost::RequestPluginChannel(Client* client) {
// We can't send any sync messages from the browser because it might lead to
// a hang. However this async messages must be answered right away by the
diff --git a/chrome/browser/plugin_process_host.h b/chrome/browser/plugin_process_host.h
index 3857c73..d30a77a 100644
--- a/chrome/browser/plugin_process_host.h
+++ b/chrome/browser/plugin_process_host.h
@@ -18,7 +18,7 @@
#include "chrome/browser/browser_child_process_host.h"
#include "chrome/browser/net/resolve_proxy_msg_helper.h"
#include "gfx/native_widget_types.h"
-#include "webkit/glue/plugins/webplugininfo.h"
+#include "webkit/plugins/npapi/webplugininfo.h"
namespace gfx {
class Rect;
@@ -28,8 +28,6 @@ namespace IPC {
struct ChannelHandle;
}
-class URLRequestContext;
-struct ViewHostMsg_Resource_Request;
class GURL;
// Represents the browser side of the browser <--> plugin communication
@@ -49,7 +47,7 @@ class PluginProcessHost : public BrowserChildProcessHost,
// the channel.
virtual int ID() = 0;
virtual bool OffTheRecord() = 0;
- virtual void SetPluginInfo(const WebPluginInfo& info) = 0;
+ virtual void SetPluginInfo(const webkit::npapi::WebPluginInfo& info) = 0;
// The client should delete itself when one of these methods is called.
virtual void OnChannelOpened(const IPC::ChannelHandle& handle) = 0;
virtual void OnError() = 0;
@@ -63,12 +61,12 @@ class PluginProcessHost : public BrowserChildProcessHost,
// Initialize the new plugin process, returning true on success. This must
// be called before the object can be used.
- bool Init(const WebPluginInfo& info, const std::string& locale);
+ bool Init(const webkit::npapi::WebPluginInfo& info, const std::string& locale);
// Force the plugin process to shutdown (cleanly).
- void ForceShutdown();
+ virtual void ForceShutdown();
- virtual void OnMessageReceived(const IPC::Message& msg);
+ virtual bool OnMessageReceived(const IPC::Message& msg);
virtual void OnChannelConnected(int32 peer_pid);
virtual void OnChannelError();
@@ -94,7 +92,7 @@ class PluginProcessHost : public BrowserChildProcessHost,
void OnAppActivation();
#endif
- const WebPluginInfo& info() const { return info_; }
+ const webkit::npapi::WebPluginInfo& info() const { return info_; }
#if defined(OS_WIN)
// Tracks plugin parent windows created on the browser UI thread.
@@ -104,11 +102,6 @@ class PluginProcessHost : public BrowserChildProcessHost,
private:
friend class PluginResolveProxyHelper;
- // ResourceDispatcherHost::Receiver implementation:
- virtual URLRequestContext* GetRequestContext(
- uint32 request_id,
- const ViewHostMsg_Resource_Request& request_data);
-
// Sends a message to the plugin process to request creation of a new channel
// for the given mime type.
void RequestPluginChannel(Client* client);
@@ -144,7 +137,7 @@ class PluginProcessHost : public BrowserChildProcessHost,
void OnPluginSetCursorVisibility(bool visible);
#endif
- virtual bool CanShutdown() { return sent_requests_.empty(); }
+ virtual bool CanShutdown();
void CancelRequests();
@@ -157,7 +150,7 @@ class PluginProcessHost : public BrowserChildProcessHost,
std::queue<Client*> sent_requests_;
// Information about the plugin.
- WebPluginInfo info_;
+ webkit::npapi::WebPluginInfo info_;
// Helper class for handling PluginProcessHost_ResolveProxy messages (manages
// the requests to the proxy service).
diff --git a/chrome/browser/plugin_service.cc b/chrome/browser/plugin_service.cc
index e3e23fd..ee7cd81 100644
--- a/chrome/browser/plugin_service.cc
+++ b/chrome/browser/plugin_service.cc
@@ -16,10 +16,10 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/chrome_plugin_host.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/plugin_updater.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/common/chrome_plugin_lib.h"
#include "chrome/common/chrome_paths.h"
@@ -34,12 +34,13 @@
#include "chrome/common/plugin_messages.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
+#include "webkit/plugins/npapi/plugin_constants_win.h"
+#include "webkit/plugins/npapi/plugin_list.h"
+#include "webkit/plugins/npapi/webplugininfo.h"
+
#ifndef DISABLE_NACL
#include "native_client/src/trusted/plugin/nacl_entry_points.h"
#endif
-#include "webkit/glue/plugins/plugin_constants_win.h"
-#include "webkit/glue/plugins/plugin_list.h"
-#include "webkit/glue/plugins/webplugininfo.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/plugin_selection_policy.h"
@@ -65,12 +66,7 @@ void PluginService::InitGlobalInstance(Profile* profile) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
// We first group the plugins and then figure out which groups to disable.
- PluginUpdater::GetPluginUpdater()->DisablePluginGroupsFromPrefs(profile);
-
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableOutdatedPlugins)) {
- NPAPI::PluginList::Singleton()->DisableOutdatedPluginGroups();
- }
+ PluginUpdater::GetInstance()->DisablePluginGroupsFromPrefs(profile);
// Have Chrome plugins write their data to the profile directory.
GetInstance()->SetChromePluginDataDir(profile->GetPath());
@@ -99,10 +95,10 @@ PluginService::PluginService()
const CommandLine* command_line = CommandLine::ForCurrentProcess();
FilePath path = command_line->GetSwitchValuePath(switches::kLoadPlugin);
if (!path.empty())
- NPAPI::PluginList::Singleton()->AddExtraPluginPath(path);
+ webkit::npapi::PluginList::Singleton()->AddExtraPluginPath(path);
path = command_line->GetSwitchValuePath(switches::kExtraPluginDir);
if (!path.empty())
- NPAPI::PluginList::Singleton()->AddExtraPluginDir(path);
+ webkit::npapi::PluginList::Singleton()->AddExtraPluginDir(path);
chrome::RegisterInternalDefaultPlugin();
@@ -110,7 +106,7 @@ PluginService::PluginService()
if (!CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableInternalFlash) &&
PathService::Get(chrome::FILE_FLASH_PLUGIN, &path)) {
- NPAPI::PluginList::Singleton()->AddExtraPluginPath(path);
+ webkit::npapi::PluginList::Singleton()->AddExtraPluginPath(path);
}
#ifndef DISABLE_NACL
@@ -128,9 +124,9 @@ PluginService::PluginService()
#if defined(OS_WIN)
hkcu_key_.Create(
- HKEY_CURRENT_USER, kRegistryMozillaPlugins, KEY_NOTIFY);
+ HKEY_CURRENT_USER, webkit::npapi::kRegistryMozillaPlugins, KEY_NOTIFY);
hklm_key_.Create(
- HKEY_LOCAL_MACHINE, kRegistryMozillaPlugins, KEY_NOTIFY);
+ HKEY_LOCAL_MACHINE, webkit::npapi::kRegistryMozillaPlugins, KEY_NOTIFY);
if (hkcu_key_.StartWatching()) {
hkcu_event_.reset(new base::WaitableEvent(hkcu_key_.watch_event()));
hkcu_watcher_.StartWatching(hkcu_event_.get(), this);
@@ -145,7 +141,7 @@ PluginService::PluginService()
// e.g. ~/.config/chromium/Plugins.
FilePath user_data_dir;
if (PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) {
- NPAPI::PluginList::Singleton()->AddExtraPluginDir(
+ webkit::npapi::PluginList::Singleton()->AddExtraPluginDir(
user_data_dir.Append("Plugins"));
}
#endif
@@ -217,10 +213,9 @@ PluginProcessHost* PluginService::FindOrStartPluginProcess(
if (plugin_host)
return plugin_host;
- WebPluginInfo info;
- if (!NPAPI::PluginList::Singleton()->GetPluginInfoByPath(
- plugin_path, &info)) {
- NOTREACHED();
+ webkit::npapi::WebPluginInfo info;
+ if (!webkit::npapi::PluginList::Singleton()->GetPluginInfoByPath(
+ plugin_path, &info)) {
return NULL;
}
@@ -252,7 +247,7 @@ void PluginService::GetAllowedPluginForOpenChannelToPlugin(
const std::string& mime_type,
PluginProcessHost::Client* client) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- WebPluginInfo info;
+ webkit::npapi::WebPluginInfo info;
bool found = GetFirstAllowedPluginInfo(url, mime_type, &info, NULL);
FilePath plugin_path;
if (found && info.enabled)
@@ -281,16 +276,16 @@ void PluginService::FinishOpenChannelToPlugin(
bool PluginService::GetFirstAllowedPluginInfo(
const GURL& url,
const std::string& mime_type,
- WebPluginInfo* info,
+ webkit::npapi::WebPluginInfo* info,
std::string* actual_mime_type) {
// GetPluginInfoArray may need to load the plugins, so we need to be
// on the FILE thread.
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
bool allow_wildcard = true;
#if defined(OS_CHROMEOS)
- std::vector<WebPluginInfo> info_array;
+ std::vector<webkit::npapi::WebPluginInfo> info_array;
std::vector<std::string> actual_mime_types;
- NPAPI::PluginList::Singleton()->GetPluginInfoArray(
+ webkit::npapi::PluginList::Singleton()->GetPluginInfoArray(
url, mime_type, allow_wildcard, &info_array, &actual_mime_types);
// Now we filter by the plugin selection policy.
@@ -304,7 +299,7 @@ bool PluginService::GetFirstAllowedPluginInfo(
}
return false;
#else
- return NPAPI::PluginList::Singleton()->GetPluginInfo(
+ return webkit::npapi::PluginList::Singleton()->GetPluginInfo(
url, mime_type, allow_wildcard, info, actual_mime_type);
#endif
}
@@ -325,7 +320,7 @@ void PluginService::OnWaitableEventSignaled(
hklm_key_.StartWatching();
}
- NPAPI::PluginList::Singleton()->RefreshPlugins();
+ webkit::npapi::PluginList::Singleton()->RefreshPlugins();
PurgePluginListCache(true);
#endif // defined(OS_WIN)
}
@@ -346,8 +341,8 @@ void PluginService::Observe(NotificationType type,
bool plugins_changed = false;
for (size_t i = 0; i < extension->plugins().size(); ++i) {
const Extension::PluginInfo& plugin = extension->plugins()[i];
- NPAPI::PluginList::Singleton()->RefreshPlugins();
- NPAPI::PluginList::Singleton()->AddExtraPluginPath(plugin.path);
+ webkit::npapi::PluginList::Singleton()->RefreshPlugins();
+ webkit::npapi::PluginList::Singleton()->AddExtraPluginPath(plugin.path);
plugins_changed = true;
if (!plugin.is_public)
private_plugins_[plugin.path] = extension->url();
@@ -358,15 +353,17 @@ void PluginService::Observe(NotificationType type,
}
case NotificationType::EXTENSION_UNLOADED: {
- const Extension* extension = Details<const Extension>(details).ptr();
+ const Extension* extension =
+ Details<UnloadedExtensionInfo>(details)->extension;
bool plugins_changed = false;
for (size_t i = 0; i < extension->plugins().size(); ++i) {
const Extension::PluginInfo& plugin = extension->plugins()[i];
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
NewRunnableFunction(&ForceShutdownPlugin,
plugin.path));
- NPAPI::PluginList::Singleton()->RefreshPlugins();
- NPAPI::PluginList::Singleton()->RemoveExtraPluginPath(plugin.path);
+ webkit::npapi::PluginList::Singleton()->RefreshPlugins();
+ webkit::npapi::PluginList::Singleton()->RemoveExtraPluginPath(
+ plugin.path);
plugins_changed = true;
if (!plugin.is_public)
private_plugins_.erase(plugin.path);
@@ -413,7 +410,7 @@ void PluginService::RegisterPepperPlugins() {
std::vector<PepperPluginInfo> plugins;
PepperPluginRegistry::GetList(&plugins);
for (size_t i = 0; i < plugins.size(); ++i) {
- NPAPI::PluginVersionInfo info;
+ webkit::npapi::PluginVersionInfo info;
info.path = plugins[i].path;
info.product_name = plugins[i].name.empty() ?
plugins[i].path.BaseName().ToWStringHack() :
@@ -428,6 +425,6 @@ void PluginService::RegisterPepperPlugins() {
// or perhaps refactor the PluginList to be less specific to NPAPI.
memset(&info.entry_points, 0, sizeof(info.entry_points));
- NPAPI::PluginList::Singleton()->RegisterInternalPlugin(info);
+ webkit::npapi::PluginList::Singleton()->RegisterInternalPlugin(info);
}
}
diff --git a/chrome/browser/plugin_service.h b/chrome/browser/plugin_service.h
index d6de864..a66d76a 100644
--- a/chrome/browser/plugin_service.h
+++ b/chrome/browser/plugin_service.h
@@ -40,9 +40,14 @@ class Message;
class MessageLoop;
class Profile;
class ResourceDispatcherHost;
-class ResourceMessageFilter;
class URLRequestContext;
+
+
+namespace webkit {
+namespace npapi {
struct WebPluginInfo;
+}
+}
// This must be created on the main thread but it's only called on the IO/file
// thread.
@@ -91,7 +96,7 @@ class PluginService
// the given url and mime type. Must be called on the FILE thread.
bool GetFirstAllowedPluginInfo(const GURL& url,
const std::string& mime_type,
- WebPluginInfo* info,
+ webkit::npapi::WebPluginInfo* info,
std::string* actual_mime_type);
// Returns true if the given plugin is allowed to be used by a page with
diff --git a/chrome/browser/plugin_service_browsertest.cc b/chrome/browser/plugin_service_browsertest.cc
index 8d9e82e..5fed897 100644
--- a/chrome/browser/plugin_service_browsertest.cc
+++ b/chrome/browser/plugin_service_browsertest.cc
@@ -11,7 +11,7 @@
#include "chrome/test/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gmock/include/gmock/gmock.h"
-#include "webkit/glue/plugins/plugin_list.h"
+#include "webkit/plugins/npapi/plugin_list.h"
namespace {
@@ -26,7 +26,7 @@ class MockPluginProcessHostClient : public PluginProcessHost::Client {
MOCK_METHOD0(ID, int());
MOCK_METHOD0(OffTheRecord, bool());
- MOCK_METHOD1(SetPluginInfo, void(const WebPluginInfo& info));
+ MOCK_METHOD1(SetPluginInfo, void(const webkit::npapi::WebPluginInfo& info));
MOCK_METHOD1(OnChannelOpened, void(const IPC::ChannelHandle& handle));
MOCK_METHOD0(OnError, void());
@@ -73,10 +73,10 @@ IN_PROC_BROWSER_TEST_F(PluginServiceTest, StartAndFindPluginProcess) {
// calls to FindPluginProcess should return non-zero values.
PluginProcessHost* default_plugin_process_host =
plugin_service_->FindOrStartPluginProcess(
- FilePath(kDefaultPluginLibraryName));
+ FilePath(webkit::npapi::kDefaultPluginLibraryName));
- EXPECT_EQ(default_plugin_process_host,
- plugin_service_->FindPluginProcess(FilePath(kDefaultPluginLibraryName)));
+ EXPECT_EQ(default_plugin_process_host, plugin_service_->FindPluginProcess(
+ FilePath(webkit::npapi::kDefaultPluginLibraryName)));
}
IN_PROC_BROWSER_TEST_F(PluginServiceTest, OpenChannelToPlugin) {
@@ -95,7 +95,7 @@ IN_PROC_BROWSER_TEST_F(PluginServiceTest, GetFirstAllowedPluginInfo) {
// We should always get a positive response no matter whether we really have
// a plugin to support that particular mime type because the Default plugin
// supports all mime types.
- WebPluginInfo plugin_info;
+ webkit::npapi::WebPluginInfo plugin_info;
std::string plugin_mime_type;
plugin_service_->GetFirstAllowedPluginInfo(GURL("http://google.com/"),
"application/pdf",
diff --git a/chrome/browser/plugin_service_unittest.cc b/chrome/browser/plugin_service_unittest.cc
index 4e54526..6950d2a 100644
--- a/chrome/browser/plugin_service_unittest.cc
+++ b/chrome/browser/plugin_service_unittest.cc
@@ -9,7 +9,6 @@
#include "chrome/browser/browser_thread.h"
#include "chrome/test/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/glue/plugins/plugin_list.h"
namespace {
diff --git a/chrome/browser/plugin_updater.cc b/chrome/browser/plugin_updater.cc
index 8e8227c..d994efd 100644
--- a/chrome/browser/plugin_updater.cc
+++ b/chrome/browser/plugin_updater.cc
@@ -4,8 +4,8 @@
#include "chrome/browser/plugin_updater.h"
+#include <set>
#include <string>
-#include <vector>
#include "base/command_line.h"
#include "base/message_loop.h"
@@ -16,13 +16,14 @@
#include "base/version.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pepper_plugin_registry.h"
#include "chrome/common/pref_names.h"
-#include "webkit/glue/plugins/webplugininfo.h"
+#include "webkit/plugins/npapi/plugin_list.h"
+#include "webkit/plugins/npapi/webplugininfo.h"
// How long to wait to save the plugin enabled information, which might need to
// go to disk.
@@ -34,7 +35,7 @@ PluginUpdater::PluginUpdater()
}
DictionaryValue* PluginUpdater::CreatePluginFileSummary(
- const WebPluginInfo& plugin) {
+ const webkit::npapi::WebPluginInfo& plugin) {
DictionaryValue* data = new DictionaryValue();
data->SetString("path", plugin.path.value());
data->SetString("name", plugin.name);
@@ -45,34 +46,32 @@ DictionaryValue* PluginUpdater::CreatePluginFileSummary(
// static
ListValue* PluginUpdater::GetPluginGroupsData() {
- NPAPI::PluginList::PluginMap plugin_groups;
- NPAPI::PluginList::Singleton()->GetPluginGroups(true, &plugin_groups);
+ std::vector<webkit::npapi::PluginGroup> plugin_groups;
+ webkit::npapi::PluginList::Singleton()->GetPluginGroups(true, &plugin_groups);
// Construct DictionaryValues to return to the UI
ListValue* plugin_groups_data = new ListValue();
- for (NPAPI::PluginList::PluginMap::const_iterator it =
- plugin_groups.begin();
- it != plugin_groups.end();
- ++it) {
- plugin_groups_data->Append(it->second->GetDataForUI());
+ for (size_t i = 0; i < plugin_groups.size(); ++i) {
+ plugin_groups_data->Append(plugin_groups[i].GetDataForUI());
}
return plugin_groups_data;
}
void PluginUpdater::EnablePluginGroup(bool enable, const string16& group_name) {
- if (PluginGroup::IsPluginNameDisabledByPolicy(group_name))
+ if (webkit::npapi::PluginGroup::IsPluginNameDisabledByPolicy(group_name))
enable = false;
- NPAPI::PluginList::Singleton()->EnableGroup(enable, group_name);
+ webkit::npapi::PluginList::Singleton()->EnableGroup(enable, group_name);
NotifyPluginStatusChanged();
}
void PluginUpdater::EnablePluginFile(bool enable,
const FilePath::StringType& path) {
FilePath file_path(path);
- if (enable && !PluginGroup::IsPluginPathDisabledByPolicy(file_path))
- NPAPI::PluginList::Singleton()->EnablePlugin(file_path);
+ if (enable &&
+ !webkit::npapi::PluginGroup::IsPluginPathDisabledByPolicy(file_path))
+ webkit::npapi::PluginList::Singleton()->EnablePlugin(file_path);
else
- NPAPI::PluginList::Singleton()->DisablePlugin(file_path);
+ webkit::npapi::PluginList::Singleton()->DisablePlugin(file_path);
NotifyPluginStatusChanged();
}
@@ -108,7 +107,8 @@ void PluginUpdater::DisablePluginsFromPolicy(const ListValue* plugin_names) {
}
}
}
- PluginGroup::SetPolicyDisabledPluginPatterns(policy_disabled_plugin_patterns);
+ webkit::npapi::PluginGroup::SetPolicyDisabledPluginPatterns(
+ policy_disabled_plugin_patterns);
NotifyPluginStatusChanged();
}
@@ -193,7 +193,7 @@ void PluginUpdater::DisablePluginGroupsFromPrefs(Profile* profile) {
}
}
if (!enabled)
- NPAPI::PluginList::Singleton()->DisablePlugin(plugin_path);
+ webkit::npapi::PluginList::Singleton()->DisablePlugin(plugin_path);
} else if (!enabled && plugin->GetString("name", &group_name)) {
// Don't disable this group if it's for the pdf plugin and we just
// forced it on.
@@ -216,14 +216,14 @@ void PluginUpdater::DisablePluginGroupsFromPrefs(Profile* profile) {
!force_internal_pdf_for_this_run) {
// The internal PDF plugin is disabled by default, and the user hasn't
// overridden the default.
- NPAPI::PluginList::Singleton()->DisablePlugin(pdf_path);
+ webkit::npapi::PluginList::Singleton()->DisablePlugin(pdf_path);
EnablePluginGroup(false, pdf_group_name);
}
if (force_enable_internal_pdf) {
// See http://crbug.com/50105 for background.
- EnablePluginGroup(false, ASCIIToUTF16(PluginGroup::kAdobeReader8GroupName));
- EnablePluginGroup(false, ASCIIToUTF16(PluginGroup::kAdobeReader9GroupName));
+ EnablePluginGroup(false, ASCIIToUTF16(
+ webkit::npapi::PluginGroup::kAdobeReaderGroupName));
// We want to save this, but doing so requires loading the list of plugins,
// so do it after a minute as to not impact startup performance. Note that
@@ -241,11 +241,11 @@ void PluginUpdater::UpdatePreferences(Profile* profile, int delay_ms) {
}
void PluginUpdater::GetPreferencesDataOnFileThread(void* profile) {
- std::vector<WebPluginInfo> plugins;
- NPAPI::PluginList::Singleton()->GetPlugins(false, &plugins);
+ std::vector<webkit::npapi::WebPluginInfo> plugins;
+ webkit::npapi::PluginList::Singleton()->GetPlugins(false, &plugins);
- NPAPI::PluginList::PluginMap groups;
- NPAPI::PluginList::Singleton()->GetPluginGroups(false, &groups);
+ std::vector<webkit::npapi::PluginGroup> groups;
+ webkit::npapi::PluginList::Singleton()->GetPluginGroups(false, &groups);
BrowserThread::PostTask(
BrowserThread::UI,
@@ -257,8 +257,8 @@ void PluginUpdater::GetPreferencesDataOnFileThread(void* profile) {
void PluginUpdater::OnUpdatePreferences(
Profile* profile,
- const std::vector<WebPluginInfo>& plugins,
- const NPAPI::PluginList::PluginMap& groups) {
+ const std::vector<webkit::npapi::WebPluginInfo>& plugins,
+ const std::vector<webkit::npapi::PluginGroup>& groups) {
ListValue* plugins_list = profile->GetPrefs()->GetMutableList(
prefs::kPluginsPluginsList);
plugins_list->Clear();
@@ -269,21 +269,16 @@ void PluginUpdater::OnUpdatePreferences(
internal_dir);
// Add the plugin files.
- for (std::vector<WebPluginInfo>::const_iterator it = plugins.begin();
+ for (std::vector<webkit::npapi::WebPluginInfo>::const_iterator it =
+ plugins.begin();
it != plugins.end();
++it) {
plugins_list->Append(CreatePluginFileSummary(*it));
}
// Add the groups as well.
- for (NPAPI::PluginList::PluginMap::const_iterator it = groups.begin();
- it != groups.end(); ++it) {
- // Don't save preferences for vulnerable pugins.
- if (!CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableOutdatedPlugins) ||
- !it->second->IsVulnerable()) {
- plugins_list->Append(it->second->GetSummary());
- }
+ for (size_t i = 0; i < groups.size(); ++i) {
+ plugins_list->Append(groups[i].GetSummary());
}
}
@@ -297,14 +292,14 @@ void PluginUpdater::NotifyPluginStatusChanged() {
}
void PluginUpdater::OnNotifyPluginStatusChanged() {
- GetPluginUpdater()->notify_pending_ = false;
+ GetInstance()->notify_pending_ = false;
NotificationService::current()->Notify(
NotificationType::PLUGIN_ENABLE_STATUS_CHANGED,
- Source<PluginUpdater>(GetPluginUpdater()),
+ Source<PluginUpdater>(GetInstance()),
NotificationService::NoDetails());
}
/*static*/
-PluginUpdater* PluginUpdater::GetPluginUpdater() {
+PluginUpdater* PluginUpdater::GetInstance() {
return Singleton<PluginUpdater>::get();
}
diff --git a/chrome/browser/plugin_updater.h b/chrome/browser/plugin_updater.h
index 2b8cd10..dc18595 100644
--- a/chrome/browser/plugin_updater.h
+++ b/chrome/browser/plugin_updater.h
@@ -6,19 +6,25 @@
#define CHROME_BROWSER_PLUGIN_UPDATER_H_
#pragma once
+#include <vector>
+
#include "base/basictypes.h"
#include "base/file_path.h"
#include "base/singleton.h"
#include "chrome/common/notification_observer.h"
-#include "webkit/glue/plugins/plugin_list.h"
class DictionaryValue;
class ListValue;
class NotificationDetails;
class NotificationSource;
-class PluginGroup;
class Profile;
+
+namespace webkit {
+namespace npapi {
+class PluginGroup;
struct WebPluginInfo;
+}
+}
class PluginUpdater : public NotificationObserver {
public:
@@ -39,11 +45,11 @@ class PluginUpdater : public NotificationObserver {
void UpdatePreferences(Profile* profile, int delay_ms);
// NotificationObserver method overrides
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
- static PluginUpdater* GetPluginUpdater();
+ static PluginUpdater* GetInstance();
private:
PluginUpdater();
@@ -54,9 +60,10 @@ class PluginUpdater : public NotificationObserver {
static void GetPreferencesDataOnFileThread(void* profile);
// Called on the UI thread with the plugin data to save the preferences.
- static void OnUpdatePreferences(Profile* profile,
- const std::vector<WebPluginInfo>& plugins,
- const NPAPI::PluginList::PluginMap& groups);
+ static void OnUpdatePreferences(
+ Profile* profile,
+ const std::vector<webkit::npapi::WebPluginInfo>& plugins,
+ const std::vector<webkit::npapi::PluginGroup>& groups);
// Queues sending the notification that plugin data has changed. This is done
// so that if a bunch of changes happen, we only send one notification.
@@ -65,7 +72,8 @@ class PluginUpdater : public NotificationObserver {
// Used for the post task to notify that plugin enabled status changed.
static void OnNotifyPluginStatusChanged();
- static DictionaryValue* CreatePluginFileSummary(const WebPluginInfo& plugin);
+ static DictionaryValue* CreatePluginFileSummary(
+ const webkit::npapi::WebPluginInfo& plugin);
// Force plugins to be disabled due to policy. |plugins| contains
// the list of StringValues of the names of the policy-disabled plugins.
diff --git a/chrome/browser/policy/asynchronous_policy_loader.cc b/chrome/browser/policy/asynchronous_policy_loader.cc
new file mode 100644
index 0000000..6ccae7a
--- /dev/null
+++ b/chrome/browser/policy/asynchronous_policy_loader.cc
@@ -0,0 +1,158 @@
+// 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.
+
+#include "chrome/browser/policy/asynchronous_policy_loader.h"
+
+#include "base/message_loop.h"
+#include "base/task.h"
+#include "chrome/browser/browser_thread.h"
+
+namespace policy {
+
+AsynchronousPolicyLoader::AsynchronousPolicyLoader(
+ AsynchronousPolicyProvider::Delegate* delegate,
+ int reload_interval_minutes)
+ : delegate_(delegate),
+ reload_task_(NULL),
+ reload_interval_(base::TimeDelta::FromMinutes(reload_interval_minutes)),
+ origin_loop_(MessageLoop::current()),
+ stopped_(false) {}
+
+void AsynchronousPolicyLoader::Init() {
+ policy_.reset(delegate_->Load());
+ // Initialization can happen early when the file thread is not yet available,
+ // but the subclass of the loader must do some of their initialization on the
+ // file thread. Posting to the file thread directly before it is initialized
+ // will cause the task to be forgotten. Instead, post a task to the ui thread
+ // to delay the remainder of initialization until threading is fully
+ // initialized.
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &AsynchronousPolicyLoader::InitAfterFileThreadAvailable));
+}
+
+void AsynchronousPolicyLoader::Stop() {
+ if (!stopped_) {
+ stopped_ = true;
+ delegate_.reset();
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(this, &AsynchronousPolicyLoader::StopOnFileThread));
+ }
+}
+
+AsynchronousPolicyLoader::~AsynchronousPolicyLoader() {
+}
+
+// Manages the life cycle of a new policy map during until its life cycle is
+// taken over by the policy loader.
+class UpdatePolicyTask : public Task {
+ public:
+ UpdatePolicyTask(scoped_refptr<AsynchronousPolicyLoader> loader,
+ DictionaryValue* new_policy)
+ : loader_(loader),
+ new_policy_(new_policy) {}
+
+ virtual void Run() {
+ loader_->UpdatePolicy(new_policy_.release());
+ }
+
+ private:
+ scoped_refptr<AsynchronousPolicyLoader> loader_;
+ scoped_ptr<DictionaryValue> new_policy_;
+ DISALLOW_COPY_AND_ASSIGN(UpdatePolicyTask);
+};
+
+void AsynchronousPolicyLoader::Reload() {
+ if (delegate_.get()) {
+ DictionaryValue* new_policy = delegate_->Load();
+ PostUpdatePolicyTask(new_policy);
+ }
+}
+
+void AsynchronousPolicyLoader::AddObserver(
+ ConfigurationPolicyProvider::Observer* observer) {
+ observer_list_.AddObserver(observer);
+}
+
+void AsynchronousPolicyLoader::RemoveObserver(
+ ConfigurationPolicyProvider::Observer* observer) {
+ observer_list_.RemoveObserver(observer);
+}
+
+void AsynchronousPolicyLoader::CancelReloadTask() {
+ if (reload_task_) {
+ // Only check the thread if there's still a reload task. During
+ // destruction of unit tests, the message loop destruction can
+ // call this method when the file thread is no longer around,
+ // but in that case reload_task_ is NULL.
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ reload_task_->Cancel();
+ reload_task_ = NULL;
+ }
+}
+
+void AsynchronousPolicyLoader::ScheduleReloadTask(
+ const base::TimeDelta& delay) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+ CancelReloadTask();
+
+ reload_task_ =
+ NewRunnableMethod(this, &AsynchronousPolicyLoader::ReloadFromTask);
+ BrowserThread::PostDelayedTask(BrowserThread::FILE, FROM_HERE, reload_task_,
+ delay.InMilliseconds());
+}
+
+void AsynchronousPolicyLoader::ScheduleFallbackReloadTask() {
+ // As a safeguard in case that the load delegate failed to timely notice a
+ // change in policy, schedule a reload task that'll make us recheck after a
+ // reasonable interval.
+ ScheduleReloadTask(reload_interval_);
+}
+
+void AsynchronousPolicyLoader::ReloadFromTask() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+ // Drop the reference to the reload task, since the task might be the only
+ // referrer that keeps us alive, so we should not Cancel() it.
+ reload_task_ = NULL;
+
+ Reload();
+}
+
+void AsynchronousPolicyLoader::InitOnFileThread() {
+}
+
+void AsynchronousPolicyLoader::StopOnFileThread() {
+ CancelReloadTask();
+}
+
+void AsynchronousPolicyLoader::PostUpdatePolicyTask(
+ DictionaryValue* new_policy) {
+ origin_loop_->PostTask(FROM_HERE, new UpdatePolicyTask(this, new_policy));
+}
+
+void AsynchronousPolicyLoader::UpdatePolicy(DictionaryValue* new_policy_raw) {
+ scoped_ptr<DictionaryValue> new_policy(new_policy_raw);
+ DCHECK(policy_.get());
+ if (!policy_->Equals(new_policy.get())) {
+ policy_.reset(new_policy.release());
+ FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer,
+ observer_list_,
+ OnUpdatePolicy());
+ }
+}
+
+void AsynchronousPolicyLoader::InitAfterFileThreadAvailable() {
+ if (!stopped_) {
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(this, &AsynchronousPolicyLoader::InitOnFileThread));
+ }
+}
+
+} // namespace policy
diff --git a/chrome/browser/policy/asynchronous_policy_loader.h b/chrome/browser/policy/asynchronous_policy_loader.h
new file mode 100644
index 0000000..677ce6f
--- /dev/null
+++ b/chrome/browser/policy/asynchronous_policy_loader.h
@@ -0,0 +1,118 @@
+// 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.
+
+#ifndef CHROME_BROWSER_POLICY_ASYNCHRONOUS_POLICY_LOADER_H_
+#define CHROME_BROWSER_POLICY_ASYNCHRONOUS_POLICY_LOADER_H_
+#pragma once
+
+#include "base/message_loop.h"
+#include "base/observer_list.h"
+#include "base/ref_counted.h"
+#include "base/values.h"
+#include "chrome/browser/policy/asynchronous_policy_provider.h"
+#include "chrome/browser/policy/configuration_policy_provider.h"
+
+namespace policy {
+
+// Used by the implementation of asynchronous policy provider to manage the
+// tasks on the file thread that do the heavy lifting of loading policies.
+class AsynchronousPolicyLoader
+ : public base::RefCountedThreadSafe<AsynchronousPolicyLoader> {
+ public:
+ explicit AsynchronousPolicyLoader(
+ AsynchronousPolicyProvider::Delegate* delegate,
+ int reload_interval_minutes);
+
+ // Triggers initial policy load.
+ virtual void Init();
+
+ // Reloads policy, sending notification of changes if necessary. Must be
+ // called on the file thread.
+ virtual void Reload();
+
+ // Stops any pending reload tasks.
+ virtual void Stop();
+
+ void AddObserver(ConfigurationPolicyProvider::Observer* observer);
+ void RemoveObserver(ConfigurationPolicyProvider::Observer* observer);
+
+ const DictionaryValue* policy() const { return policy_.get(); }
+
+ protected:
+ friend class UpdatePolicyTask;
+
+ // AsynchronousPolicyLoader objects should only be deleted by
+ // RefCountedThreadSafe.
+ friend class base::RefCountedThreadSafe<AsynchronousPolicyLoader>;
+ virtual ~AsynchronousPolicyLoader();
+
+ // Schedules a call to UpdatePolicy on |origin_loop_|. Takes ownership of
+ // |new_policy|.
+ void PostUpdatePolicyTask(DictionaryValue* new_policy);
+
+ AsynchronousPolicyProvider::Delegate* delegate() {
+ return delegate_.get();
+ }
+
+ // Performs start operations that must be performed on the file thread.
+ virtual void InitOnFileThread();
+
+ // Performs stop operations that must be performed on the file thread.
+ virtual void StopOnFileThread();
+
+ // Schedules a reload task to run when |delay| expires. Must be called on the
+ // file thread.
+ void ScheduleReloadTask(const base::TimeDelta& delay);
+
+ // Schedules a reload task to run after the number of minutes specified
+ // in |reload_interval_minutes_|. Must be called on the file thread.
+ void ScheduleFallbackReloadTask();
+
+ void CancelReloadTask();
+
+ // Invoked from the reload task on the file thread.
+ void ReloadFromTask();
+
+ private:
+ friend class AsynchronousPolicyLoaderTest;
+
+ // Finishes loader initialization after the threading system has been fully
+ // intialized.
+ void InitAfterFileThreadAvailable();
+
+ // Replaces the existing policy to value map with a new one, sending
+ // notification to the observers if there is a policy change. Must be called
+ // on |origin_loop_| so that it's safe to call back into the provider, which
+ // is not thread-safe. Takes ownership of |new_policy|.
+ void UpdatePolicy(DictionaryValue* new_policy);
+
+ // Provides the low-level mechanics for loading policy.
+ scoped_ptr<AsynchronousPolicyProvider::Delegate> delegate_;
+
+ // Current policy.
+ scoped_ptr<DictionaryValue> policy_;
+
+ // The reload task. Access only on the file thread. Holds a reference to the
+ // currently posted task, so we can cancel and repost it if necessary.
+ CancelableTask* reload_task_;
+
+ // The interval at which a policy reload will be triggered as a fallback.
+ const base::TimeDelta reload_interval_;
+
+ // The message loop on which this object was constructed. Recorded so that
+ // it's possible to call back into the non thread safe provider to fire the
+ // notification.
+ MessageLoop* origin_loop_;
+
+ // True if Stop has been called.
+ bool stopped_;
+
+ ObserverList<ConfigurationPolicyProvider::Observer, true> observer_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsynchronousPolicyLoader);
+};
+
+} // namespace policy
+
+#endif // CHROME_BROWSER_POLICY_ASYNCHRONOUS_POLICY_LOADER_H_
diff --git a/chrome/browser/policy/asynchronous_policy_loader_unittest.cc b/chrome/browser/policy/asynchronous_policy_loader_unittest.cc
new file mode 100644
index 0000000..3cc416c
--- /dev/null
+++ b/chrome/browser/policy/asynchronous_policy_loader_unittest.cc
@@ -0,0 +1,134 @@
+// 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.
+
+#include "chrome/browser/policy/asynchronous_policy_loader.h"
+#include "chrome/browser/policy/asynchronous_policy_provider.h"
+#include "chrome/browser/policy/asynchronous_policy_test_base.h"
+#include "chrome/browser/policy/mock_configuration_policy_provider.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using ::testing::_;
+using ::testing::InSequence;
+using ::testing::Return;
+
+namespace policy {
+
+class MockConfigurationPolicyObserver
+ : public ConfigurationPolicyProvider::Observer {
+ public:
+ MOCK_METHOD0(OnUpdatePolicy, void());
+};
+
+class AsynchronousPolicyLoaderTest : public AsynchronousPolicyTestBase {
+ public:
+ AsynchronousPolicyLoaderTest() {}
+ virtual ~AsynchronousPolicyLoaderTest() {}
+
+ virtual void SetUp() {
+ AsynchronousPolicyTestBase::SetUp();
+ mock_provider_.reset(new MockConfigurationPolicyProvider());
+ }
+
+ protected:
+ scoped_ptr<MockConfigurationPolicyProvider> mock_provider_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AsynchronousPolicyLoaderTest);
+};
+
+ACTION(CreateTestDictionary) {
+ return new DictionaryValue();
+}
+
+ACTION_P(CreateSequencedTestDictionary, number) {
+ DictionaryValue* test_dictionary = new DictionaryValue();
+ test_dictionary->SetInteger("id", ++(*number));
+ return test_dictionary;
+}
+
+ACTION(RescheduleImmediatePolicyReload) {
+ *arg1 = base::TimeDelta();
+ return false;
+}
+
+TEST_F(AsynchronousPolicyLoaderTest, InitialLoad) {
+ DictionaryValue* template_dict(new DictionaryValue());
+ EXPECT_CALL(*delegate_, Load()).WillOnce(Return(template_dict));
+ scoped_refptr<AsynchronousPolicyLoader> loader =
+ new AsynchronousPolicyLoader(delegate_.release(), 10);
+ loader->Init();
+ const DictionaryValue* loaded_dict(loader->policy());
+ EXPECT_TRUE(loaded_dict->Equals(template_dict));
+}
+
+// Verify that the fallback policy requests are made.
+TEST_F(AsynchronousPolicyLoaderTest, InitialLoadWithFallback) {
+ int dictionary_number = 0;
+ InSequence s;
+ EXPECT_CALL(*delegate_, Load()).WillOnce(
+ CreateSequencedTestDictionary(&dictionary_number));
+ EXPECT_CALL(*delegate_, Load()).WillOnce(
+ CreateSequencedTestDictionary(&dictionary_number));
+ scoped_refptr<AsynchronousPolicyLoader> loader =
+ new AsynchronousPolicyLoader(delegate_.release(), 10);
+ loader->Init();
+ loop_.RunAllPending();
+ loader->Reload();
+ loop_.RunAllPending();
+
+ const DictionaryValue* loaded_dict(loader->policy());
+ int loaded_number;
+ EXPECT_TRUE(loaded_dict->GetInteger("id", &loaded_number));
+ EXPECT_EQ(dictionary_number, loaded_number);
+}
+
+// Ensure that calling stop on the loader stops subsequent reloads from
+// happening.
+TEST_F(AsynchronousPolicyLoaderTest, Stop) {
+ ON_CALL(*delegate_, Load()).WillByDefault(CreateTestDictionary());
+ EXPECT_CALL(*delegate_, Load()).Times(1);
+ scoped_refptr<AsynchronousPolicyLoader> loader =
+ new AsynchronousPolicyLoader(delegate_.release(), 10);
+ loader->Init();
+ loop_.RunAllPending();
+ loader->Stop();
+ loop_.RunAllPending();
+ loader->Reload();
+ loop_.RunAllPending();
+}
+
+// Verifies that the provider is notified upon policy reload, but only
+// if the policy changed.
+TEST_F(AsynchronousPolicyLoaderTest, ProviderNotificationOnPolicyChange) {
+ InSequence s;
+ MockConfigurationPolicyObserver observer;
+ int dictionary_number_1 = 0;
+ int dictionary_number_2 = 0;
+ EXPECT_CALL(*delegate_, Load()).WillOnce(
+ CreateSequencedTestDictionary(&dictionary_number_1));
+ EXPECT_CALL(*delegate_, Load()).WillOnce(
+ CreateSequencedTestDictionary(&dictionary_number_2));
+ EXPECT_CALL(observer, OnUpdatePolicy()).Times(0);
+ EXPECT_CALL(*delegate_, Load()).WillOnce(
+ CreateSequencedTestDictionary(&dictionary_number_2));
+ EXPECT_CALL(observer, OnUpdatePolicy()).Times(1);
+ EXPECT_CALL(*delegate_, Load()).WillOnce(
+ CreateSequencedTestDictionary(&dictionary_number_1));
+ scoped_refptr<AsynchronousPolicyLoader> loader =
+ new AsynchronousPolicyLoader(delegate_.release(), 10);
+ AsynchronousPolicyProvider provider(NULL, loader);
+ // |registrar| must be declared last so that it is destroyed first.
+ ConfigurationPolicyObserverRegistrar registrar;
+ registrar.Init(&provider);
+ registrar.AddObserver(&observer);
+ loop_.RunAllPending();
+ loader->Reload();
+ loop_.RunAllPending();
+ loader->Reload();
+ loop_.RunAllPending();
+ loader->Reload();
+ loop_.RunAllPending();
+}
+
+} // namespace policy
diff --git a/chrome/browser/policy/asynchronous_policy_provider.cc b/chrome/browser/policy/asynchronous_policy_provider.cc
new file mode 100644
index 0000000..e697b05
--- /dev/null
+++ b/chrome/browser/policy/asynchronous_policy_provider.cc
@@ -0,0 +1,46 @@
+// 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.
+
+#include "chrome/browser/policy/asynchronous_policy_provider.h"
+
+#include "chrome/browser/policy/asynchronous_policy_loader.h"
+
+namespace policy {
+
+AsynchronousPolicyProvider::AsynchronousPolicyProvider(
+ const PolicyDefinitionList* policy_list,
+ scoped_refptr<AsynchronousPolicyLoader> loader)
+ : ConfigurationPolicyProvider(policy_list),
+ loader_(loader) {
+ loader_->Init();
+}
+
+AsynchronousPolicyProvider::~AsynchronousPolicyProvider() {
+ DCHECK(CalledOnValidThread());
+ loader_->Stop();
+}
+
+bool AsynchronousPolicyProvider::Provide(
+ ConfigurationPolicyStoreInterface* store) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(loader_->policy());
+ DecodePolicyValueTree(loader_->policy(), store);
+ return true;
+}
+
+void AsynchronousPolicyProvider::AddObserver(
+ ConfigurationPolicyProvider::Observer* observer) {
+ loader_->AddObserver(observer);
+}
+
+void AsynchronousPolicyProvider::RemoveObserver(
+ ConfigurationPolicyProvider::Observer* observer) {
+ loader_->RemoveObserver(observer);
+}
+
+scoped_refptr<AsynchronousPolicyLoader> AsynchronousPolicyProvider::loader() {
+ return loader_;
+}
+
+} // namespace policy
diff --git a/chrome/browser/policy/asynchronous_policy_provider.h b/chrome/browser/policy/asynchronous_policy_provider.h
new file mode 100644
index 0000000..561fc37
--- /dev/null
+++ b/chrome/browser/policy/asynchronous_policy_provider.h
@@ -0,0 +1,61 @@
+// 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.
+
+#ifndef CHROME_BROWSER_POLICY_ASYNCHRONOUS_POLICY_PROVIDER_H_
+#define CHROME_BROWSER_POLICY_ASYNCHRONOUS_POLICY_PROVIDER_H_
+#pragma once
+
+#include "base/non_thread_safe.h"
+#include "base/ref_counted.h"
+#include "base/weak_ptr.h"
+#include "chrome/browser/policy/configuration_policy_provider.h"
+
+namespace policy {
+
+class AsynchronousPolicyLoader;
+
+// Policy provider that loads policy asynchronously. Providers should subclass
+// from this class if loading the policy requires disk access or must for some
+// other reason be performed on the file thread. The actual logic for loading
+// policy is handled by a delegate passed at construction time.
+class AsynchronousPolicyProvider
+ : public ConfigurationPolicyProvider,
+ public NonThreadSafe {
+ public:
+ // Must be implemented by subclasses of the asynchronous policy provider to
+ // provide the implementation details of how policy is loaded.
+ class Delegate {
+ public:
+ virtual ~Delegate() {}
+
+ virtual DictionaryValue* Load() = 0;
+ };
+
+ // Assumes ownership of |loader|.
+ AsynchronousPolicyProvider(
+ const PolicyDefinitionList* policy_list,
+ scoped_refptr<AsynchronousPolicyLoader> loader);
+ virtual ~AsynchronousPolicyProvider();
+
+ // ConfigurationPolicyProvider implementation.
+ virtual bool Provide(ConfigurationPolicyStoreInterface* store);
+
+ // For tests to trigger reloads.
+ scoped_refptr<AsynchronousPolicyLoader> loader();
+
+ protected:
+ // The loader object used internally.
+ scoped_refptr<AsynchronousPolicyLoader> loader_;
+
+ private:
+ // ConfigurationPolicyProvider overrides:
+ virtual void AddObserver(ConfigurationPolicyProvider::Observer* observer);
+ virtual void RemoveObserver(ConfigurationPolicyProvider::Observer* observer);
+
+ DISALLOW_COPY_AND_ASSIGN(AsynchronousPolicyProvider);
+};
+
+} // namespace policy
+
+#endif // CHROME_BROWSER_POLICY_ASYNCHRONOUS_POLICY_PROVIDER_H_
diff --git a/chrome/browser/policy/asynchronous_policy_provider_unittest.cc b/chrome/browser/policy/asynchronous_policy_provider_unittest.cc
new file mode 100644
index 0000000..c6aee70
--- /dev/null
+++ b/chrome/browser/policy/asynchronous_policy_provider_unittest.cc
@@ -0,0 +1,57 @@
+// 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.
+
+#include "chrome/browser/policy/asynchronous_policy_loader.h"
+#include "chrome/browser/policy/asynchronous_policy_provider.h"
+#include "chrome/browser/policy/asynchronous_policy_test_base.h"
+#include "chrome/browser/policy/configuration_policy_pref_store.h"
+#include "chrome/browser/policy/mock_configuration_policy_store.h"
+#include "chrome/common/policy_constants.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+using ::testing::InSequence;
+using ::testing::Return;
+
+namespace policy {
+
+// Creating the provider should provide initial policy.
+TEST_F(AsynchronousPolicyTestBase, Provide) {
+ InSequence s;
+ DictionaryValue* policies = new DictionaryValue();
+ policies->SetBoolean(policy::key::kSyncDisabled, true);
+ EXPECT_CALL(*delegate_, Load()).WillOnce(Return(policies));
+ EXPECT_CALL(*store_, Apply(policy::kPolicySyncDisabled, _)).Times(1);
+ AsynchronousPolicyProvider provider(
+ ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(),
+ new AsynchronousPolicyLoader(delegate_.release(), 10));
+ provider.Provide(store_.get());
+}
+
+
+// Trigger a refresh manually and ensure that policy gets reloaded.
+TEST_F(AsynchronousPolicyTestBase, ProvideAfterRefresh) {
+ InSequence s;
+ DictionaryValue* original_policies = new DictionaryValue();
+ original_policies->SetBoolean(policy::key::kSyncDisabled, true);
+ EXPECT_CALL(*delegate_, Load()).WillOnce(Return(original_policies));
+ DictionaryValue* refresh_policies = new DictionaryValue();
+ refresh_policies->SetBoolean(
+ policy::key::kJavascriptEnabled,
+ true);
+ EXPECT_CALL(*delegate_, Load()).WillOnce(Return(refresh_policies));
+ AsynchronousPolicyLoader* loader =
+ new AsynchronousPolicyLoader(delegate_.release(), 10);
+ AsynchronousPolicyProvider provider(
+ ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(),
+ loader);
+ loop_.RunAllPending();
+ loader->Reload();
+ loop_.RunAllPending();
+ EXPECT_CALL(*store_, Apply(policy::kPolicyJavascriptEnabled, _)).Times(1);
+ provider.Provide(store_.get());
+}
+
+} // namespace policy
diff --git a/chrome/browser/policy/asynchronous_policy_test_base.h b/chrome/browser/policy/asynchronous_policy_test_base.h
new file mode 100644
index 0000000..0281afd
--- /dev/null
+++ b/chrome/browser/policy/asynchronous_policy_test_base.h
@@ -0,0 +1,64 @@
+// 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.
+
+#ifndef CHROME_BROWSER_POLICY_ASYNCHRONOUS_POLICY_TEST_BASE_H_
+#define CHROME_BROWSER_POLICY_ASYNCHRONOUS_POLICY_TEST_BASE_H_
+#pragma once
+
+#include "base/message_loop.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/policy/asynchronous_policy_provider.h"
+#include "chrome/browser/policy/mock_configuration_policy_store.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace policy {
+
+// A delegate for testing that can feed arbitrary information to the loader.
+class ProviderDelegateMock : public AsynchronousPolicyProvider::Delegate {
+ public:
+ ProviderDelegateMock() : AsynchronousPolicyProvider::Delegate() {}
+ virtual ~ProviderDelegateMock() {}
+
+ MOCK_METHOD0(Load, DictionaryValue*());
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ProviderDelegateMock);
+};
+
+class AsynchronousPolicyTestBase : public testing::Test {
+ public:
+ AsynchronousPolicyTestBase()
+ : ui_thread_(BrowserThread::UI, &loop_),
+ file_thread_(BrowserThread::FILE, &loop_) {}
+
+ virtual ~AsynchronousPolicyTestBase() {}
+
+ virtual void SetUp() {
+ delegate_.reset(new ProviderDelegateMock());
+ store_.reset(new MockConfigurationPolicyStore);
+ }
+
+ virtual void TearDown() {
+ loop_.RunAllPending();
+ }
+
+ protected:
+ MessageLoop loop_;
+
+ // The mocks that are used in the test must outlive the scope of the test
+ // because they still get accessed in the RunAllPending of the TearDown.
+ scoped_ptr<MockConfigurationPolicyStore> store_;
+ scoped_ptr<ProviderDelegateMock> delegate_;
+
+ private:
+ BrowserThread ui_thread_;
+ BrowserThread file_thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsynchronousPolicyTestBase);
+};
+
+} // namespace policy
+
+#endif // CHROME_BROWSER_POLICY_ASYNCHRONOUS_POLICY_TEST_BASE_H_
diff --git a/chrome/browser/policy/config_dir_policy_provider.cc b/chrome/browser/policy/config_dir_policy_provider.cc
index f134aeb..fb2f6eb 100644
--- a/chrome/browser/policy/config_dir_policy_provider.cc
+++ b/chrome/browser/policy/config_dir_policy_provider.cc
@@ -12,11 +12,12 @@
namespace policy {
-ConfigDirPolicyLoader::ConfigDirPolicyLoader(const FilePath& config_dir)
- : FileBasedPolicyProvider::Delegate(config_dir) {
+ConfigDirPolicyProviderDelegate::ConfigDirPolicyProviderDelegate(
+ const FilePath& config_dir)
+ : FileBasedPolicyProvider::ProviderDelegate(config_dir) {
}
-DictionaryValue* ConfigDirPolicyLoader::Load() {
+DictionaryValue* ConfigDirPolicyProviderDelegate::Load() {
// Enumerate the files and sort them lexicographically.
std::set<FilePath> files;
file_util::FileEnumerator file_enumerator(config_file_path(), false,
@@ -49,7 +50,7 @@ DictionaryValue* ConfigDirPolicyLoader::Load() {
return policy;
}
-base::Time ConfigDirPolicyLoader::GetLastModification() {
+base::Time ConfigDirPolicyProviderDelegate::GetLastModification() {
base::Time last_modification = base::Time();
base::PlatformFileInfo file_info;
@@ -68,7 +69,7 @@ base::Time ConfigDirPolicyLoader::GetLastModification() {
config_file = file_enumerator.Next()) {
if (file_util::GetFileInfo(config_file, &file_info) &&
!file_info.is_directory) {
- last_modification = std::min(last_modification, file_info.last_modified);
+ last_modification = std::max(last_modification, file_info.last_modified);
}
}
@@ -78,8 +79,9 @@ base::Time ConfigDirPolicyLoader::GetLastModification() {
ConfigDirPolicyProvider::ConfigDirPolicyProvider(
const ConfigurationPolicyProvider::PolicyDefinitionList* policy_list,
const FilePath& config_dir)
- : FileBasedPolicyProvider(policy_list,
- new ConfigDirPolicyLoader(config_dir)) {
+ : FileBasedPolicyProvider(
+ policy_list,
+ new ConfigDirPolicyProviderDelegate(config_dir)) {
}
} // namespace policy
diff --git a/chrome/browser/policy/config_dir_policy_provider.h b/chrome/browser/policy/config_dir_policy_provider.h
index 6096513..3647489 100644
--- a/chrome/browser/policy/config_dir_policy_provider.h
+++ b/chrome/browser/policy/config_dir_policy_provider.h
@@ -10,23 +10,6 @@
namespace policy {
-// A policy loader implementation backed by a set of files in a given directory.
-// The files should contain JSON-formatted policy settings. They are merged
-// together and the result is returned via the PolicyLoader interface. The files
-// are consulted in lexicographic file name order, so the last value read takes
-// precedence in case of preference key collisions.
-class ConfigDirPolicyLoader : public FileBasedPolicyProvider::Delegate {
- public:
- explicit ConfigDirPolicyLoader(const FilePath& config_dir);
-
- // FileBasedPolicyLoader::Delegate implementation.
- virtual DictionaryValue* Load();
- virtual base::Time GetLastModification();
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ConfigDirPolicyLoader);
-};
-
// Policy provider backed by JSON files in a configuration directory.
class ConfigDirPolicyProvider : public FileBasedPolicyProvider {
public:
@@ -38,6 +21,24 @@ class ConfigDirPolicyProvider : public FileBasedPolicyProvider {
DISALLOW_COPY_AND_ASSIGN(ConfigDirPolicyProvider);
};
+// A provider delegate implementation backed by a set of files in a given
+// directory. The files should contain JSON-formatted policy settings. They are
+// merged together and the result is returned via the ProviderDelegate
+// interface. The files are consulted in lexicographic file name order, so the
+// last value read takes precedence in case of preference key collisions.
+class ConfigDirPolicyProviderDelegate
+ : public FileBasedPolicyProvider::ProviderDelegate {
+ public:
+ explicit ConfigDirPolicyProviderDelegate(const FilePath& config_dir);
+
+ // FileBasedPolicyProvider::ProviderDelegate implementation.
+ virtual DictionaryValue* Load();
+ virtual base::Time GetLastModification();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ConfigDirPolicyProviderDelegate);
+};
+
} // namespace policy
#endif // CHROME_BROWSER_POLICY_CONFIG_DIR_POLICY_PROVIDER_H_
diff --git a/chrome/browser/policy/config_dir_policy_provider_unittest.cc b/chrome/browser/policy/config_dir_policy_provider_unittest.cc
index 25893da..8b7e9a0 100644
--- a/chrome/browser/policy/config_dir_policy_provider_unittest.cc
+++ b/chrome/browser/policy/config_dir_policy_provider_unittest.cc
@@ -8,6 +8,7 @@
#include "base/path_service.h"
#include "base/scoped_temp_dir.h"
#include "base/string_number_conversions.h"
+#include "chrome/browser/browser_thread.h"
#include "chrome/browser/policy/config_dir_policy_provider.h"
#include "chrome/browser/policy/configuration_policy_pref_store.h"
#include "chrome/browser/policy/mock_configuration_policy_store.h"
@@ -49,7 +50,7 @@ class ConfigDirPolicyLoaderTest
// The preferences dictionary is expected to be empty when there are no files to
// load.
TEST_F(ConfigDirPolicyLoaderTest, ReadPrefsEmpty) {
- ConfigDirPolicyLoader loader(test_dir());
+ ConfigDirPolicyProviderDelegate loader(test_dir());
scoped_ptr<DictionaryValue> policy(loader.Load());
EXPECT_TRUE(policy.get());
EXPECT_TRUE(policy->empty());
@@ -59,7 +60,7 @@ TEST_F(ConfigDirPolicyLoaderTest, ReadPrefsEmpty) {
// dictionary.
TEST_F(ConfigDirPolicyLoaderTest, ReadPrefsNonExistentDirectory) {
FilePath non_existent_dir(test_dir().Append(FILE_PATH_LITERAL("not_there")));
- ConfigDirPolicyLoader loader(non_existent_dir);
+ ConfigDirPolicyProviderDelegate loader(non_existent_dir);
scoped_ptr<DictionaryValue> policy(loader.Load());
EXPECT_TRUE(policy.get());
EXPECT_TRUE(policy->empty());
@@ -71,7 +72,7 @@ TEST_F(ConfigDirPolicyLoaderTest, ReadPrefsSinglePref) {
test_dict.SetString("HomepageLocation", "http://www.google.com");
WriteConfigFile(test_dict, "config_file");
- ConfigDirPolicyLoader loader(test_dir());
+ ConfigDirPolicyProviderDelegate loader(test_dir());
scoped_ptr<DictionaryValue> policy(loader.Load());
EXPECT_TRUE(policy.get());
EXPECT_TRUE(policy->Equals(&test_dict));
@@ -93,7 +94,7 @@ TEST_F(ConfigDirPolicyLoaderTest, ReadPrefsMergePrefs) {
for (unsigned int i = 5; i <= 8; ++i)
WriteConfigFile(test_dict_bar, base::IntToString(i));
- ConfigDirPolicyLoader loader(test_dir());
+ ConfigDirPolicyProviderDelegate loader(test_dir());
scoped_ptr<DictionaryValue> policy(loader.Load());
EXPECT_TRUE(policy.get());
EXPECT_TRUE(policy->Equals(&test_dict_foo));
@@ -258,8 +259,8 @@ INSTANTIATE_TEST_CASE_P(
kPolicyDefaultSearchProviderEncodings,
key::kDefaultSearchProviderEncodings),
ValueTestParams::ForIntegerPolicy(
- kPolicyProxyServerMode,
- key::kProxyServerMode),
+ kPolicyProxyMode,
+ key::kProxyMode),
ValueTestParams::ForStringPolicy(
kPolicyProxyServer,
key::kProxyServer),
diff --git a/chrome/browser/policy/configuration_policy_loader_win.cc b/chrome/browser/policy/configuration_policy_loader_win.cc
new file mode 100644
index 0000000..68ccf80
--- /dev/null
+++ b/chrome/browser/policy/configuration_policy_loader_win.cc
@@ -0,0 +1,90 @@
+// 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.
+
+#include "chrome/browser/policy/configuration_policy_loader_win.h"
+
+#include <userenv.h>
+
+#include "chrome/browser/browser_thread.h"
+
+namespace policy {
+
+ConfigurationPolicyLoaderWin::ConfigurationPolicyLoaderWin(
+ AsynchronousPolicyProvider::Delegate* delegate,
+ int reload_interval_minutes)
+ : AsynchronousPolicyLoader(delegate, reload_interval_minutes),
+ user_policy_changed_event_(false, false),
+ machine_policy_changed_event_(false, false),
+ user_policy_watcher_failed_(false),
+ machine_policy_watcher_failed_(false) {
+ if (!RegisterGPNotification(user_policy_changed_event_.handle(), false)) {
+ PLOG(WARNING) << "Failed to register user group policy notification";
+ user_policy_watcher_failed_ = true;
+ }
+ if (!RegisterGPNotification(machine_policy_changed_event_.handle(), true)) {
+ PLOG(WARNING) << "Failed to register machine group policy notification.";
+ machine_policy_watcher_failed_ = true;
+ }
+}
+
+void ConfigurationPolicyLoaderWin::InitOnFileThread() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ AsynchronousPolicyLoader::InitOnFileThread();
+ MessageLoop::current()->AddDestructionObserver(this);
+ SetupWatches();
+}
+
+void ConfigurationPolicyLoaderWin::StopOnFileThread() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ MessageLoop::current()->RemoveDestructionObserver(this);
+ user_policy_watcher_.StopWatching();
+ machine_policy_watcher_.StopWatching();
+ AsynchronousPolicyLoader::StopOnFileThread();
+}
+
+void ConfigurationPolicyLoaderWin::SetupWatches() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ CancelReloadTask();
+
+ if (!user_policy_watcher_failed_ &&
+ !user_policy_watcher_.GetWatchedObject() &&
+ !user_policy_watcher_.StartWatching(
+ user_policy_changed_event_.handle(), this)) {
+ LOG(WARNING) << "Failed to start watch for user policy change event";
+ user_policy_watcher_failed_ = true;
+ }
+ if (!machine_policy_watcher_failed_ &&
+ !machine_policy_watcher_.GetWatchedObject() &&
+ !machine_policy_watcher_.StartWatching(
+ machine_policy_changed_event_.handle(), this)) {
+ LOG(WARNING) << "Failed to start watch for machine policy change event";
+ machine_policy_watcher_failed_ = true;
+ }
+
+ if (user_policy_watcher_failed_ || machine_policy_watcher_failed_)
+ ScheduleFallbackReloadTask();
+}
+
+void ConfigurationPolicyLoaderWin::Reload() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ AsynchronousPolicyLoader::Reload();
+ SetupWatches();
+}
+
+void ConfigurationPolicyLoaderWin::OnObjectSignaled(HANDLE object) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK(object == user_policy_changed_event_.handle() ||
+ object == machine_policy_changed_event_.handle())
+ << "unexpected object signaled policy reload, obj = "
+ << std::showbase << std::hex << object;
+ Reload();
+}
+
+void ConfigurationPolicyLoaderWin::
+ WillDestroyCurrentMessageLoop() {
+ CancelReloadTask();
+ MessageLoop::current()->RemoveDestructionObserver(this);
+}
+
+} // namespace policy
diff --git a/chrome/browser/policy/configuration_policy_loader_win.h b/chrome/browser/policy/configuration_policy_loader_win.h
new file mode 100644
index 0000000..a898afc
--- /dev/null
+++ b/chrome/browser/policy/configuration_policy_loader_win.h
@@ -0,0 +1,57 @@
+// 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.
+
+#ifndef CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_LOADER_WIN_H_
+#define CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_LOADER_WIN_H_
+#pragma once
+
+#include "base/object_watcher.h"
+#include "base/waitable_event.h"
+#include "chrome/browser/policy/asynchronous_policy_loader.h"
+
+namespace policy {
+
+// Keeps watch on Windows Group Policy notification event to trigger a policy
+// reload when Group Policy changes.
+class ConfigurationPolicyLoaderWin
+ : public AsynchronousPolicyLoader,
+ public base::ObjectWatcher::Delegate,
+ public MessageLoop::DestructionObserver {
+ public:
+ ConfigurationPolicyLoaderWin(
+ AsynchronousPolicyProvider::Delegate* delegate,
+ int reload_interval_minutes);
+ virtual ~ConfigurationPolicyLoaderWin() {}
+
+ protected:
+ // AsynchronousPolicyLoader overrides:
+ virtual void InitOnFileThread();
+ virtual void StopOnFileThread();
+
+ private:
+ // Updates the watchers and schedules the reload task if appropriate.
+ void SetupWatches();
+
+ // Post a reload notification and update the watch machinery.
+ void Reload();
+
+ // ObjectWatcher::Delegate overrides:
+ virtual void OnObjectSignaled(HANDLE object);
+
+ // MessageLoop::DestructionObserver overrides:
+ virtual void WillDestroyCurrentMessageLoop();
+
+ base::WaitableEvent user_policy_changed_event_;
+ base::WaitableEvent machine_policy_changed_event_;
+ base::ObjectWatcher user_policy_watcher_;
+ base::ObjectWatcher machine_policy_watcher_;
+ bool user_policy_watcher_failed_;
+ bool machine_policy_watcher_failed_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyLoaderWin);
+};
+
+} // namespace policy
+
+#endif // CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_LOADER_WIN_H_
diff --git a/chrome/browser/policy/configuration_policy_pref_store.cc b/chrome/browser/policy/configuration_policy_pref_store.cc
index 5a1eaaa..23e6510 100644
--- a/chrome/browser/policy/configuration_policy_pref_store.cc
+++ b/chrome/browser/policy/configuration_policy_pref_store.cc
@@ -4,15 +4,19 @@
#include "chrome/browser/policy/configuration_policy_pref_store.h"
+#include <set>
+#include <string>
+#include <vector>
+
#include "base/command_line.h"
+#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/path_service.h"
-#include "base/singleton.h"
+#include "base/stl_util-inl.h"
#include "base/string16.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/policy/configuration_policy_provider.h"
#if defined(OS_WIN)
#include "chrome/browser/policy/configuration_policy_provider_win.h"
@@ -24,98 +28,135 @@
#include "chrome/browser/policy/device_management_policy_provider.h"
#include "chrome/browser/policy/dummy_configuration_policy_provider.h"
#include "chrome/browser/policy/profile_policy_context.h"
+#include "chrome/browser/prefs/pref_value_map.h"
+#include "chrome/browser/prefs/proxy_prefs.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/search_terms_data.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/notification_service.h"
#include "chrome/common/policy_constants.h"
#include "chrome/common/pref_names.h"
namespace policy {
-// Manages the lifecycle of the shared platform-specific policy providers for
-// managed platform, device management and recommended policy. Instantiated as a
-// Singleton.
-class ConfigurationPolicyProviderKeeper {
+// Accepts policy settings from a ConfigurationPolicyProvider, converts them
+// to preferences and caches the result.
+class ConfigurationPolicyPrefKeeper
+ : private ConfigurationPolicyStoreInterface {
public:
- ConfigurationPolicyProviderKeeper()
- : managed_platform_provider_(CreateManagedPlatformProvider()),
- device_management_provider_(CreateDeviceManagementProvider()),
- recommended_provider_(CreateRecommendedProvider()) {}
- virtual ~ConfigurationPolicyProviderKeeper() {}
+ explicit ConfigurationPolicyPrefKeeper(ConfigurationPolicyProvider* provider);
+ virtual ~ConfigurationPolicyPrefKeeper();
- ConfigurationPolicyProvider* managed_platform_provider() const {
- return managed_platform_provider_.get();
- }
-
- ConfigurationPolicyProvider* device_management_provider() const {
- return device_management_provider_.get();
- }
+ // Get a preference value.
+ PrefStore::ReadResult GetValue(const std::string& key, Value** result) const;
- ConfigurationPolicyProvider* recommended_provider() const {
- return recommended_provider_.get();
- }
+ // Compute the set of preference names that are different in |keeper|. This
+ // includes preferences that are missing in either one.
+ void GetDifferingPrefPaths(const ConfigurationPolicyPrefKeeper* other,
+ std::vector<std::string>* differing_prefs) const;
private:
- scoped_ptr<ConfigurationPolicyProvider> managed_platform_provider_;
- scoped_ptr<ConfigurationPolicyProvider> device_management_provider_;
- scoped_ptr<ConfigurationPolicyProvider> recommended_provider_;
-
- static ConfigurationPolicyProvider* CreateManagedPlatformProvider();
- static ConfigurationPolicyProvider* CreateDeviceManagementProvider();
- static ConfigurationPolicyProvider* CreateRecommendedProvider();
+ // ConfigurationPolicyStore methods:
+ virtual void Apply(ConfigurationPolicyType setting, Value* value);
+
+ // Policies that map to a single preference are handled
+ // by an automated converter. Each one of these policies
+ // has an entry in |simple_policy_map_| with the following type.
+ struct PolicyToPreferenceMapEntry {
+ Value::ValueType value_type;
+ ConfigurationPolicyType policy_type;
+ const char* preference_path; // A DictionaryValue path, not a file path.
+ };
- DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyProviderKeeper);
+ // Returns the map entry that corresponds to |policy| in the map.
+ const PolicyToPreferenceMapEntry* FindPolicyInMap(
+ ConfigurationPolicyType policy,
+ const PolicyToPreferenceMapEntry* map,
+ int size) const;
+
+ // Remove the preferences found in the map from |prefs_|. Returns true if any
+ // such preferences were found and removed.
+ bool RemovePreferencesOfMap(const PolicyToPreferenceMapEntry* map,
+ int table_size);
+
+ bool ApplyPolicyFromMap(ConfigurationPolicyType policy,
+ Value* value,
+ const PolicyToPreferenceMapEntry* map,
+ int size);
+
+ // Processes proxy-specific policies. Returns true if the specified policy
+ // is a proxy-related policy. ApplyProxyPolicy assumes the ownership
+ // of |value| in the case that the policy is proxy-specific.
+ bool ApplyProxyPolicy(ConfigurationPolicyType policy, Value* value);
+
+ // Handles sync-related policies. Returns true if the policy was handled.
+ // Assumes ownership of |value| in that case.
+ bool ApplySyncPolicy(ConfigurationPolicyType policy, Value* value);
+
+ // Handles policies that affect AutoFill. Returns true if the policy was
+ // handled and assumes ownership of |value| in that case.
+ bool ApplyAutoFillPolicy(ConfigurationPolicyType policy, Value* value);
+
+ // Make sure that the |path| if present in |prefs_|. If not, set it to
+ // a blank string.
+ void EnsureStringPrefExists(const std::string& path);
+
+ // If the required entries for default search are specified and valid,
+ // finalizes the policy-specified configuration by initializing the
+ // unspecified map entries. Otherwise wipes all default search related
+ // map entries from |prefs_|.
+ void FinalizeDefaultSearchPolicySettings();
+
+ // If the required entries for the proxy settings are specified and valid,
+ // finalizes the policy-specified configuration by initializing the
+ // respective values in |prefs_|.
+ void FinalizeProxyPolicySettings();
+
+ // Returns true if the policy values stored in proxy_* represent a valid
+ // proxy configuration.
+ bool CheckProxySettings();
+
+ // Assumes CheckProxySettings returns true and applies the values stored
+ // in proxy_*.
+ void ApplyProxySettings();
+
+ bool HasProxyPolicy(ConfigurationPolicyType policy) const;
+
+ // Temporary cache that stores values until FinalizeProxyPolicySettings()
+ // is called.
+ std::map<ConfigurationPolicyType, Value*> proxy_policies_;
+
+ // Set to false until the first proxy-relevant policy is applied. At that
+ // time, default values are provided for all proxy-relevant prefs
+ // to override any values set from stores with a lower priority.
+ bool lower_priority_proxy_settings_overridden_;
+
+ // The following are used to track what proxy-relevant policy has been applied
+ // accross calls to Apply to provide a warning if a policy specifies a
+ // contradictory proxy configuration. |proxy_disabled_| is set to true if and
+ // only if the kPolicyNoProxyServer has been applied,
+ // |proxy_configuration_specified_| is set to true if and only if any other
+ // proxy policy other than kPolicyNoProxyServer has been applied.
+ bool proxy_disabled_;
+ bool proxy_configuration_specified_;
+
+ // Set to true if a the proxy mode policy has been set to force Chrome
+ // to use the system proxy.
+ bool use_system_proxy_;
+
+ PrefValueMap prefs_;
+
+ static const PolicyToPreferenceMapEntry kSimplePolicyMap[];
+ static const PolicyToPreferenceMapEntry kProxyPolicyMap[];
+ static const PolicyToPreferenceMapEntry kDefaultSearchPolicyMap[];
+
+ DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyPrefKeeper);
};
-ConfigurationPolicyProvider*
- ConfigurationPolicyProviderKeeper::CreateManagedPlatformProvider() {
- const ConfigurationPolicyProvider::PolicyDefinitionList* policy_list =
- ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList();
-#if defined(OS_WIN)
- return new ConfigurationPolicyProviderWin(policy_list);
-#elif defined(OS_MACOSX)
- return new ConfigurationPolicyProviderMac(policy_list);
-#elif defined(OS_POSIX)
- FilePath config_dir_path;
- if (PathService::Get(chrome::DIR_POLICY_FILES, &config_dir_path)) {
- return new ConfigDirPolicyProvider(
- policy_list,
- config_dir_path.Append(FILE_PATH_LITERAL("managed")));
- } else {
- return new DummyConfigurationPolicyProvider(policy_list);
- }
-#else
- return new DummyConfigurationPolicyProvider(policy_list);
-#endif
-}
-
-ConfigurationPolicyProvider*
- ConfigurationPolicyProviderKeeper::CreateDeviceManagementProvider() {
- return new DummyConfigurationPolicyProvider(
- ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList());
-}
-
-ConfigurationPolicyProvider*
- ConfigurationPolicyProviderKeeper::CreateRecommendedProvider() {
- const ConfigurationPolicyProvider::PolicyDefinitionList* policy_list =
- ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList();
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
- FilePath config_dir_path;
- if (PathService::Get(chrome::DIR_POLICY_FILES, &config_dir_path)) {
- return new ConfigDirPolicyProvider(
- policy_list,
- config_dir_path.Append(FILE_PATH_LITERAL("recommended")));
- } else {
- return new DummyConfigurationPolicyProvider(policy_list);
- }
-#else
- return new DummyConfigurationPolicyProvider(policy_list);
-#endif
-}
-
-const ConfigurationPolicyPrefStore::PolicyToPreferenceMapEntry
- ConfigurationPolicyPrefStore::kSimplePolicyMap[] = {
+const ConfigurationPolicyPrefKeeper::PolicyToPreferenceMapEntry
+ ConfigurationPolicyPrefKeeper::kSimplePolicyMap[] = {
{ Value::TYPE_STRING, kPolicyHomePage, prefs::kHomePage },
{ Value::TYPE_BOOLEAN, kPolicyHomepageIsNewTabPage,
prefs::kHomePageIsNewTabPage },
@@ -160,17 +201,21 @@ const ConfigurationPolicyPrefStore::PolicyToPreferenceMapEntry
{ Value::TYPE_BOOLEAN, kPolicyDeveloperToolsDisabled,
prefs::kDevToolsDisabled },
{ Value::TYPE_BOOLEAN, kPolicyBlockThirdPartyCookies,
- prefs::kBlockThirdPartyCookies},
+ prefs::kBlockThirdPartyCookies },
{ Value::TYPE_INTEGER, kPolicyDefaultCookiesSetting,
- prefs::kManagedDefaultCookiesSetting},
+ prefs::kManagedDefaultCookiesSetting },
{ Value::TYPE_INTEGER, kPolicyDefaultImagesSetting,
- prefs::kManagedDefaultImagesSetting},
+ prefs::kManagedDefaultImagesSetting },
{ Value::TYPE_INTEGER, kPolicyDefaultJavaScriptSetting,
- prefs::kManagedDefaultJavaScriptSetting},
+ prefs::kManagedDefaultJavaScriptSetting },
{ Value::TYPE_INTEGER, kPolicyDefaultPluginsSetting,
- prefs::kManagedDefaultPluginsSetting},
+ prefs::kManagedDefaultPluginsSetting },
{ Value::TYPE_INTEGER, kPolicyDefaultPopupsSetting,
- prefs::kManagedDefaultPopupsSetting},
+ prefs::kManagedDefaultPopupsSetting },
+ { Value::TYPE_INTEGER, kPolicyDefaultNotificationSetting,
+ prefs::kDesktopNotificationDefaultContentSetting },
+ { Value::TYPE_INTEGER, kPolicyDefaultGeolocationSetting,
+ prefs::kGeolocationDefaultContentSetting },
{ Value::TYPE_STRING, kPolicyAuthSchemes,
prefs::kAuthSchemes },
{ Value::TYPE_BOOLEAN, kPolicyDisableAuthNegotiateCnameLookup,
@@ -192,8 +237,8 @@ const ConfigurationPolicyPrefStore::PolicyToPreferenceMapEntry
#endif
};
-const ConfigurationPolicyPrefStore::PolicyToPreferenceMapEntry
- ConfigurationPolicyPrefStore::kDefaultSearchPolicyMap[] = {
+const ConfigurationPolicyPrefKeeper::PolicyToPreferenceMapEntry
+ ConfigurationPolicyPrefKeeper::kDefaultSearchPolicyMap[] = {
{ Value::TYPE_BOOLEAN, kPolicyDefaultSearchProviderEnabled,
prefs::kDefaultSearchProviderEnabled },
{ Value::TYPE_STRING, kPolicyDefaultSearchProviderName,
@@ -210,137 +255,53 @@ const ConfigurationPolicyPrefStore::PolicyToPreferenceMapEntry
prefs::kDefaultSearchProviderEncodings },
};
-const ConfigurationPolicyPrefStore::PolicyToPreferenceMapEntry
- ConfigurationPolicyPrefStore::kProxyPolicyMap[] = {
+const ConfigurationPolicyPrefKeeper::PolicyToPreferenceMapEntry
+ ConfigurationPolicyPrefKeeper::kProxyPolicyMap[] = {
{ Value::TYPE_STRING, kPolicyProxyServer, prefs::kProxyServer },
{ Value::TYPE_STRING, kPolicyProxyPacUrl, prefs::kProxyPacUrl },
{ Value::TYPE_STRING, kPolicyProxyBypassList, prefs::kProxyBypassList }
};
-/* static */
-const ConfigurationPolicyProvider::PolicyDefinitionList*
-ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList() {
- static ConfigurationPolicyProvider::PolicyDefinitionList::Entry entries[] = {
- { kPolicyHomePage, Value::TYPE_STRING, key::kHomepageLocation },
- { kPolicyHomepageIsNewTabPage, Value::TYPE_BOOLEAN,
- key::kHomepageIsNewTabPage },
- { kPolicyRestoreOnStartup, Value::TYPE_INTEGER, key::kRestoreOnStartup },
- { kPolicyURLsToRestoreOnStartup, Value::TYPE_LIST,
- key::kURLsToRestoreOnStartup },
- { kPolicyDefaultSearchProviderEnabled, Value::TYPE_BOOLEAN,
- key::kDefaultSearchProviderEnabled },
- { kPolicyDefaultSearchProviderName, Value::TYPE_STRING,
- key::kDefaultSearchProviderName },
- { kPolicyDefaultSearchProviderKeyword, Value::TYPE_STRING,
- key::kDefaultSearchProviderKeyword },
- { kPolicyDefaultSearchProviderSearchURL, Value::TYPE_STRING,
- key::kDefaultSearchProviderSearchURL },
- { kPolicyDefaultSearchProviderSuggestURL, Value::TYPE_STRING,
- key::kDefaultSearchProviderSuggestURL },
- { kPolicyDefaultSearchProviderIconURL, Value::TYPE_STRING,
- key::kDefaultSearchProviderIconURL },
- { kPolicyDefaultSearchProviderEncodings, Value::TYPE_STRING,
- key::kDefaultSearchProviderEncodings },
- { kPolicyProxyServerMode, Value::TYPE_INTEGER, key::kProxyServerMode },
- { kPolicyProxyServer, Value::TYPE_STRING, key::kProxyServer },
- { kPolicyProxyPacUrl, Value::TYPE_STRING, key::kProxyPacUrl },
- { kPolicyProxyBypassList, Value::TYPE_STRING, key::kProxyBypassList },
- { kPolicyAlternateErrorPagesEnabled, Value::TYPE_BOOLEAN,
- key::kAlternateErrorPagesEnabled },
- { kPolicySearchSuggestEnabled, Value::TYPE_BOOLEAN,
- key::kSearchSuggestEnabled },
- { kPolicyDnsPrefetchingEnabled, Value::TYPE_BOOLEAN,
- key::kDnsPrefetchingEnabled },
- { kPolicyDisableSpdy, Value::TYPE_BOOLEAN, key::kDisableSpdy },
- { kPolicySafeBrowsingEnabled, Value::TYPE_BOOLEAN,
- key::kSafeBrowsingEnabled },
- { kPolicyMetricsReportingEnabled, Value::TYPE_BOOLEAN,
- key::kMetricsReportingEnabled },
- { kPolicyPasswordManagerEnabled, Value::TYPE_BOOLEAN,
- key::kPasswordManagerEnabled },
- { kPolicyPasswordManagerAllowShowPasswords, Value::TYPE_BOOLEAN,
- key::kPasswordManagerAllowShowPasswords },
- { kPolicyAutoFillEnabled, Value::TYPE_BOOLEAN, key::kAutoFillEnabled },
- { kPolicyDisabledPlugins, Value::TYPE_LIST, key::kDisabledPlugins },
- { kPolicyApplicationLocale, Value::TYPE_STRING,
- key::kApplicationLocaleValue },
- { kPolicySyncDisabled, Value::TYPE_BOOLEAN, key::kSyncDisabled },
- { kPolicyExtensionInstallAllowList, Value::TYPE_LIST,
- key::kExtensionInstallAllowList },
- { kPolicyExtensionInstallDenyList, Value::TYPE_LIST,
- key::kExtensionInstallDenyList },
- { kPolicyExtensionInstallForceList, Value::TYPE_LIST,
- key::kExtensionInstallForceList },
- { kPolicyShowHomeButton, Value::TYPE_BOOLEAN, key::kShowHomeButton },
- { kPolicyPrintingEnabled, Value::TYPE_BOOLEAN, key::kPrintingEnabled },
- { kPolicyJavascriptEnabled, Value::TYPE_BOOLEAN, key::kJavascriptEnabled },
- { kPolicySavingBrowserHistoryDisabled, Value::TYPE_BOOLEAN,
- key::kSavingBrowserHistoryDisabled },
- { kPolicyDeveloperToolsDisabled, Value::TYPE_BOOLEAN,
- key::kDeveloperToolsDisabled },
- { kPolicyBlockThirdPartyCookies, Value::TYPE_BOOLEAN,
- key::kBlockThirdPartyCookies },
- { kPolicyDefaultCookiesSetting, Value::TYPE_INTEGER,
- key::kDefaultCookiesSetting},
- { kPolicyDefaultImagesSetting, Value::TYPE_INTEGER,
- key::kDefaultImagesSetting},
- { kPolicyDefaultJavaScriptSetting, Value::TYPE_INTEGER,
- key::kDefaultJavaScriptSetting},
- { kPolicyDefaultPluginsSetting, Value::TYPE_INTEGER,
- key::kDefaultPluginsSetting},
- { kPolicyDefaultPopupsSetting, Value::TYPE_INTEGER,
- key::kDefaultPopupsSetting},
- { kPolicyAuthSchemes, Value::TYPE_STRING, key::kAuthSchemes },
- { kPolicyDisableAuthNegotiateCnameLookup, Value::TYPE_BOOLEAN,
- key::kDisableAuthNegotiateCnameLookup },
- { kPolicyEnableAuthNegotiatePort, Value::TYPE_BOOLEAN,
- key::kEnableAuthNegotiatePort },
- { kPolicyAuthServerWhitelist, Value::TYPE_STRING,
- key::kAuthServerWhitelist },
- { kPolicyAuthNegotiateDelegateWhitelist, Value::TYPE_STRING,
- key::kAuthNegotiateDelegateWhitelist },
- { kPolicyGSSAPILibraryName, Value::TYPE_STRING,
- key::kGSSAPILibraryName },
- { kPolicyDisable3DAPIs, Value::TYPE_BOOLEAN,
- key::kDisable3DAPIs },
+ConfigurationPolicyPrefKeeper::ConfigurationPolicyPrefKeeper(
+ ConfigurationPolicyProvider* provider)
+ : lower_priority_proxy_settings_overridden_(false),
+ proxy_disabled_(false),
+ proxy_configuration_specified_(false),
+ use_system_proxy_(false) {
+ if (!provider->Provide(this))
+ LOG(WARNING) << "Failed to get policy from provider.";
+ FinalizeProxyPolicySettings();
+ FinalizeDefaultSearchPolicySettings();
+}
+ConfigurationPolicyPrefKeeper::~ConfigurationPolicyPrefKeeper() {
+ DCHECK(proxy_policies_.empty());
+}
-#if defined(OS_CHROMEOS)
- { kPolicyChromeOsLockOnIdleSuspend, Value::TYPE_BOOLEAN,
- key::kChromeOsLockOnIdleSuspend },
-#endif
- };
+PrefStore::ReadResult
+ConfigurationPolicyPrefKeeper::GetValue(const std::string& key,
+ Value** result) const {
+ Value* stored_value = NULL;
+ if (!prefs_.GetValue(key, &stored_value))
+ return PrefStore::READ_NO_VALUE;
- static ConfigurationPolicyProvider::PolicyDefinitionList policy_list = {
- entries,
- entries + arraysize(entries),
- };
- return &policy_list;
-}
+ // Check whether there's a default value, which indicates READ_USE_DEFAULT
+ // should be returned.
+ if (stored_value->IsType(Value::TYPE_NULL))
+ return PrefStore::READ_USE_DEFAULT;
-ConfigurationPolicyPrefStore::ConfigurationPolicyPrefStore(
- ConfigurationPolicyProvider* provider)
- : provider_(provider),
- prefs_(new DictionaryValue()),
- lower_priority_proxy_settings_overridden_(false),
- proxy_disabled_(false),
- proxy_configuration_specified_(false),
- use_system_proxy_(false) {
+ *result = stored_value;
+ return PrefStore::READ_OK;
}
-PrefStore::PrefReadError ConfigurationPolicyPrefStore::ReadPrefs() {
- proxy_disabled_ = false;
- proxy_configuration_specified_ = false;
- lower_priority_proxy_settings_overridden_ = false;
-
- const bool success = (provider_ == NULL || provider_->Provide(this));
- FinalizeDefaultSearchPolicySettings();
- return success ? PrefStore::PREF_READ_ERROR_NONE :
- PrefStore::PREF_READ_ERROR_OTHER;
+void ConfigurationPolicyPrefKeeper::GetDifferingPrefPaths(
+ const ConfigurationPolicyPrefKeeper* other,
+ std::vector<std::string>* differing_prefs) const {
+ prefs_.GetDifferingKeys(&other->prefs_, differing_prefs);
}
-void ConfigurationPolicyPrefStore::Apply(ConfigurationPolicyType policy,
- Value* value) {
+void ConfigurationPolicyPrefKeeper::Apply(ConfigurationPolicyType policy,
+ Value* value) {
if (ApplyProxyPolicy(policy, value))
return;
@@ -363,49 +324,8 @@ void ConfigurationPolicyPrefStore::Apply(ConfigurationPolicyType policy,
delete value;
}
-// static
-ConfigurationPolicyPrefStore*
-ConfigurationPolicyPrefStore::CreateManagedPlatformPolicyPrefStore() {
- ConfigurationPolicyProviderKeeper* keeper =
- Singleton<ConfigurationPolicyProviderKeeper>::get();
- return new ConfigurationPolicyPrefStore(keeper->managed_platform_provider());
-}
-
-// static
-ConfigurationPolicyPrefStore*
-ConfigurationPolicyPrefStore::CreateDeviceManagementPolicyPrefStore(
- Profile* profile) {
- ConfigurationPolicyProviderKeeper* keeper =
- Singleton<ConfigurationPolicyProviderKeeper>::get();
- ConfigurationPolicyProvider* provider = NULL;
- if (profile)
- provider = profile->GetPolicyContext()->GetDeviceManagementPolicyProvider();
- if (!provider)
- provider = keeper->device_management_provider();
- return new ConfigurationPolicyPrefStore(provider);
-}
-
-// static
-ConfigurationPolicyPrefStore*
-ConfigurationPolicyPrefStore::CreateRecommendedPolicyPrefStore() {
- ConfigurationPolicyProviderKeeper* keeper =
- Singleton<ConfigurationPolicyProviderKeeper>::get();
- return new ConfigurationPolicyPrefStore(keeper->recommended_provider());
-}
-
-// static
-void ConfigurationPolicyPrefStore::GetProxyPreferenceSet(
- ProxyPreferenceSet* proxy_pref_set) {
- proxy_pref_set->clear();
- for (size_t current = 0; current < arraysize(kProxyPolicyMap); ++current) {
- proxy_pref_set->insert(kProxyPolicyMap[current].preference_path);
- }
- proxy_pref_set->insert(prefs::kNoProxyServer);
- proxy_pref_set->insert(prefs::kProxyAutoDetect);
-}
-
-const ConfigurationPolicyPrefStore::PolicyToPreferenceMapEntry*
-ConfigurationPolicyPrefStore::FindPolicyInMap(
+const ConfigurationPolicyPrefKeeper::PolicyToPreferenceMapEntry*
+ConfigurationPolicyPrefKeeper::FindPolicyInMap(
ConfigurationPolicyType policy,
const PolicyToPreferenceMapEntry* map,
int table_size) const {
@@ -416,17 +336,17 @@ ConfigurationPolicyPrefStore::FindPolicyInMap(
return NULL;
}
-bool ConfigurationPolicyPrefStore::RemovePreferencesOfMap(
+bool ConfigurationPolicyPrefKeeper::RemovePreferencesOfMap(
const PolicyToPreferenceMapEntry* map, int table_size) {
bool found_any = false;
for (int i = 0; i < table_size; ++i) {
- if (prefs_->Remove(map[i].preference_path, NULL))
+ if (prefs_.RemoveValue(map[i].preference_path))
found_any = true;
}
return found_any;
}
-bool ConfigurationPolicyPrefStore::ApplyPolicyFromMap(
+bool ConfigurationPolicyPrefKeeper::ApplyPolicyFromMap(
ConfigurationPolicyType policy,
Value* value,
const PolicyToPreferenceMapEntry* map,
@@ -437,124 +357,37 @@ bool ConfigurationPolicyPrefStore::ApplyPolicyFromMap(
<< "mismatch in provided and expected policy value for preferences"
<< map[current].preference_path << ". expected = "
<< map[current].value_type << ", actual = "<< value->GetType();
- prefs_->Set(map[current].preference_path, value);
+ prefs_.SetValue(map[current].preference_path, value);
return true;
}
}
return false;
}
-bool ConfigurationPolicyPrefStore::ApplyProxyPolicy(
+bool ConfigurationPolicyPrefKeeper::ApplyProxyPolicy(
ConfigurationPolicyType policy,
Value* value) {
- bool result = false;
- bool warn_about_proxy_disable_config = false;
- bool warn_about_proxy_system_config = false;
-
- const PolicyToPreferenceMapEntry* match_entry =
- FindPolicyInMap(policy, kProxyPolicyMap, arraysize(kProxyPolicyMap));
-
- // When the first proxy-related policy is applied, ALL proxy-related
- // preferences that have been set by command-line switches, extensions,
- // user preferences or any other mechanism are overridden. Otherwise
- // it's possible for a user to interfere with proxy policy by setting
- // proxy-related command-line switches or set proxy-related prefs in an
- // extension that are related, but not identical, to the ones set through
- // policy.
- if (!lower_priority_proxy_settings_overridden_ &&
- (match_entry ||
- policy == kPolicyProxyServerMode)) {
- ProxyPreferenceSet proxy_preference_set;
- GetProxyPreferenceSet(&proxy_preference_set);
- for (ProxyPreferenceSet::const_iterator i = proxy_preference_set.begin();
- i != proxy_preference_set.end(); ++i) {
- prefs_->Set(*i, PrefStore::CreateUseDefaultSentinelValue());
- }
- lower_priority_proxy_settings_overridden_ = true;
- }
-
- // Translate the proxy policy into preferences.
- if (policy == kPolicyProxyServerMode) {
- int int_value;
- bool proxy_auto_detect = false;
- if (value->GetAsInteger(&int_value)) {
- result = true;
- switch (int_value) {
- case kPolicyNoProxyServerMode:
- if (!proxy_disabled_) {
- if (proxy_configuration_specified_)
- warn_about_proxy_disable_config = true;
- proxy_disabled_ = true;
- }
- break;
- case kPolicyAutoDetectProxyMode:
- proxy_auto_detect = true;
- break;
- case kPolicyManuallyConfiguredProxyMode:
- break;
- case kPolicyUseSystemProxyMode:
- if (!use_system_proxy_) {
- if (proxy_configuration_specified_)
- warn_about_proxy_system_config = true;
- use_system_proxy_ = true;
- }
- break;
- default:
- // Not a valid policy, don't assume ownership of |value|
- result = false;
- break;
- }
-
- if (int_value != kPolicyUseSystemProxyMode) {
- prefs_->Set(prefs::kNoProxyServer,
- Value::CreateBooleanValue(proxy_disabled_));
- prefs_->Set(prefs::kProxyAutoDetect,
- Value::CreateBooleanValue(proxy_auto_detect));
- }
- }
- } else if (match_entry) {
- // Determine if the applied proxy policy settings conflict and issue
- // a corresponding warning if they do.
- if (!proxy_configuration_specified_) {
- if (proxy_disabled_)
- warn_about_proxy_disable_config = true;
- if (use_system_proxy_)
- warn_about_proxy_system_config = true;
- proxy_configuration_specified_ = true;
- }
- if (!use_system_proxy_ && !proxy_disabled_) {
- prefs_->Set(match_entry->preference_path, value);
- // The ownership of value has been passed on to |prefs_|,
- // don't clean it up later.
- value = NULL;
- }
- result = true;
- }
-
- if (warn_about_proxy_disable_config) {
- LOG(WARNING) << "A centrally-administered policy disables the use of"
- << " a proxy but also specifies an explicit proxy"
- << " configuration.";
- }
-
- if (warn_about_proxy_system_config) {
- LOG(WARNING) << "A centrally-administered policy dictates that the"
- << " system proxy settings should be used but also specifies"
- << " an explicit proxy configuration.";
+ // We only collect the values until we have sufficient information when
+ // FinalizeProxyPolicySettings() is called to determine whether the presented
+ // values were correct and apply them in that case.
+ if (policy == kPolicyProxyMode ||
+ policy == kPolicyProxyServer ||
+ policy == kPolicyProxyPacUrl ||
+ policy == kPolicyProxyBypassList) {
+ delete proxy_policies_[policy];
+ proxy_policies_[policy] = value;
+ return true;
}
-
- // If the policy was a proxy policy, cleanup |value|.
- if (result && value)
- delete value;
- return result;
+ // We are not interested in this policy.
+ return false;
}
-bool ConfigurationPolicyPrefStore::ApplySyncPolicy(
+bool ConfigurationPolicyPrefKeeper::ApplySyncPolicy(
ConfigurationPolicyType policy, Value* value) {
if (policy == kPolicySyncDisabled) {
bool disable_sync;
if (value->GetAsBoolean(&disable_sync) && disable_sync)
- prefs_->Set(prefs::kSyncManaged, value);
+ prefs_.SetValue(prefs::kSyncManaged, value);
else
delete value;
return true;
@@ -562,23 +395,24 @@ bool ConfigurationPolicyPrefStore::ApplySyncPolicy(
return false;
}
-bool ConfigurationPolicyPrefStore::ApplyAutoFillPolicy(
+bool ConfigurationPolicyPrefKeeper::ApplyAutoFillPolicy(
ConfigurationPolicyType policy, Value* value) {
if (policy == kPolicyAutoFillEnabled) {
bool auto_fill_enabled;
if (value->GetAsBoolean(&auto_fill_enabled) && !auto_fill_enabled)
- prefs_->Set(prefs::kAutoFillEnabled, Value::CreateBooleanValue(false));
+ prefs_.SetValue(prefs::kAutoFillEnabled,
+ Value::CreateBooleanValue(false));
delete value;
return true;
}
return false;
}
-void ConfigurationPolicyPrefStore::EnsureStringPrefExists(
+void ConfigurationPolicyPrefKeeper::EnsureStringPrefExists(
const std::string& path) {
std::string value;
- if (!prefs_->GetString(path, &value))
- prefs_->SetString(path, value);
+ if (!prefs_.GetString(path, &value))
+ prefs_.SetString(path, value);
}
namespace {
@@ -604,24 +438,24 @@ class SearchTermsDataForValidation : public SearchTermsData {
DISALLOW_COPY_AND_ASSIGN(SearchTermsDataForValidation);
};
-} // namepsace
+} // namespace
-void ConfigurationPolicyPrefStore::FinalizeDefaultSearchPolicySettings() {
+void ConfigurationPolicyPrefKeeper::FinalizeDefaultSearchPolicySettings() {
bool enabled = true;
- if (prefs_->GetBoolean(prefs::kDefaultSearchProviderEnabled, &enabled) &&
+ if (prefs_.GetBoolean(prefs::kDefaultSearchProviderEnabled, &enabled) &&
!enabled) {
// If default search is disabled, we ignore the other fields.
- prefs_->SetString(prefs::kDefaultSearchProviderName, std::string());
- prefs_->SetString(prefs::kDefaultSearchProviderSearchURL, std::string());
- prefs_->SetString(prefs::kDefaultSearchProviderSuggestURL, std::string());
- prefs_->SetString(prefs::kDefaultSearchProviderIconURL, std::string());
- prefs_->SetString(prefs::kDefaultSearchProviderEncodings, std::string());
- prefs_->SetString(prefs::kDefaultSearchProviderKeyword, std::string());
+ prefs_.SetString(prefs::kDefaultSearchProviderName, std::string());
+ prefs_.SetString(prefs::kDefaultSearchProviderSearchURL, std::string());
+ prefs_.SetString(prefs::kDefaultSearchProviderSuggestURL, std::string());
+ prefs_.SetString(prefs::kDefaultSearchProviderIconURL, std::string());
+ prefs_.SetString(prefs::kDefaultSearchProviderEncodings, std::string());
+ prefs_.SetString(prefs::kDefaultSearchProviderKeyword, std::string());
return;
}
std::string search_url;
// The search URL is required.
- if (prefs_->GetString(prefs::kDefaultSearchProviderSearchURL, &search_url) &&
+ if (prefs_.GetString(prefs::kDefaultSearchProviderSearchURL, &search_url) &&
!search_url.empty()) {
SearchTermsDataForValidation search_terms_data;
const TemplateURLRef search_url_ref(search_url, 0, 0);
@@ -636,14 +470,14 @@ void ConfigurationPolicyPrefStore::FinalizeDefaultSearchPolicySettings() {
// For the name, default to the host if not specified.
std::string name;
- if (!prefs_->GetString(prefs::kDefaultSearchProviderName, &name) ||
+ if (!prefs_.GetString(prefs::kDefaultSearchProviderName, &name) ||
name.empty())
- prefs_->SetString(prefs::kDefaultSearchProviderName,
+ prefs_.SetString(prefs::kDefaultSearchProviderName,
GURL(search_url).host());
// And clear the IDs since these are not specified via policy.
- prefs_->SetString(prefs::kDefaultSearchProviderID, std::string());
- prefs_->SetString(prefs::kDefaultSearchProviderPrepopulateID,
+ prefs_.SetString(prefs::kDefaultSearchProviderID, std::string());
+ prefs_.SetString(prefs::kDefaultSearchProviderPrepopulateID,
std::string());
return;
}
@@ -653,4 +487,419 @@ void ConfigurationPolicyPrefStore::FinalizeDefaultSearchPolicySettings() {
arraysize(kDefaultSearchPolicyMap));
}
+void ConfigurationPolicyPrefKeeper::FinalizeProxyPolicySettings() {
+ if (CheckProxySettings())
+ ApplyProxySettings();
+
+ STLDeleteContainerPairSecondPointers(proxy_policies_.begin(),
+ proxy_policies_.end());
+ proxy_policies_.clear();
+}
+
+bool ConfigurationPolicyPrefKeeper::CheckProxySettings() {
+ bool mode = HasProxyPolicy(kPolicyProxyMode);
+ bool server = HasProxyPolicy(kPolicyProxyServer);
+ bool pac_url = HasProxyPolicy(kPolicyProxyPacUrl);
+ bool bypass_list = HasProxyPolicy(kPolicyProxyBypassList);
+
+ if ((server || pac_url || bypass_list) && !mode) {
+ LOG(WARNING) << "A centrally-administered policy defines proxy setting"
+ << " details without setting a proxy mode.";
+ return false;
+ }
+
+ if (!mode)
+ return true;
+
+ int mode_value;
+ if (!proxy_policies_[kPolicyProxyMode]->GetAsInteger(&mode_value)) {
+ LOG(WARNING) << "Invalid proxy mode value.";
+ return false;
+ }
+
+ switch (mode_value) {
+ case kPolicyNoProxyServerMode:
+ if (server || pac_url || bypass_list) {
+ LOG(WARNING) << "A centrally-administered policy disables the use of"
+ << " a proxy but also specifies an explicit proxy"
+ << " configuration.";
+ return false;
+ }
+ break;
+ case kPolicyAutoDetectProxyMode:
+ if (server || bypass_list) {
+ LOG(WARNING) << "A centrally-administered policy dictates that a proxy"
+ << " shall be auto configured but specifies fixed proxy"
+ << " servers or a by-pass list.";
+ return false;
+ }
+ break;
+ case kPolicyManuallyConfiguredProxyMode:
+ if (!server) {
+ LOG(WARNING) << "A centrally-administered policy dictates that the"
+ << " system proxy settings should use fixed proxy servers"
+ << " without specifying which ones.";
+ return false;
+ }
+ if (pac_url) {
+ LOG(WARNING) << "A centrally-administered policy dictates that the"
+ << " system proxy settings should use fixed proxy servers"
+ << " but also specifies a PAC script.";
+ return false;
+ }
+ break;
+ case kPolicyUseSystemProxyMode:
+ if (server || pac_url || bypass_list) {
+ LOG(WARNING) << "A centrally-administered policy dictates that the"
+ << " system proxy settings should be used but also "
+ << " specifies an explicit proxy configuration.";
+ return false;
+ }
+ break;
+ default:
+ LOG(WARNING) << "Invalid proxy mode " << mode_value;
+ return false;
+ }
+ return true;
+}
+
+void ConfigurationPolicyPrefKeeper::ApplyProxySettings() {
+ if (!HasProxyPolicy(kPolicyProxyMode))
+ return;
+
+ int int_mode;
+ CHECK(proxy_policies_[kPolicyProxyMode]->GetAsInteger(&int_mode));
+ ProxyPrefs::ProxyMode mode;
+ switch (int_mode) {
+ case kPolicyNoProxyServerMode:
+ mode = ProxyPrefs::MODE_DIRECT;
+ break;
+ case kPolicyAutoDetectProxyMode:
+ mode = ProxyPrefs::MODE_AUTO_DETECT;
+ if (HasProxyPolicy(kPolicyProxyPacUrl))
+ mode = ProxyPrefs::MODE_PAC_SCRIPT;
+ break;
+ case kPolicyManuallyConfiguredProxyMode:
+ mode = ProxyPrefs::MODE_FIXED_SERVERS;
+ break;
+ case kPolicyUseSystemProxyMode:
+ mode = ProxyPrefs::MODE_SYSTEM;
+ break;
+ default:
+ mode = ProxyPrefs::MODE_DIRECT;
+ NOTREACHED();
+ }
+ prefs_.SetValue(prefs::kProxyMode, Value::CreateIntegerValue(mode));
+
+ if (HasProxyPolicy(kPolicyProxyServer)) {
+ prefs_.SetValue(prefs::kProxyServer, proxy_policies_[kPolicyProxyServer]);
+ proxy_policies_[kPolicyProxyServer] = NULL;
+ } else {
+ prefs_.SetValue(prefs::kProxyServer, Value::CreateNullValue());
+ }
+ if (HasProxyPolicy(kPolicyProxyPacUrl)) {
+ prefs_.SetValue(prefs::kProxyPacUrl, proxy_policies_[kPolicyProxyPacUrl]);
+ proxy_policies_[kPolicyProxyPacUrl] = NULL;
+ } else {
+ prefs_.SetValue(prefs::kProxyPacUrl, Value::CreateNullValue());
+ }
+ if (HasProxyPolicy(kPolicyProxyBypassList)) {
+ prefs_.SetValue(prefs::kProxyBypassList,
+ proxy_policies_[kPolicyProxyBypassList]);
+ proxy_policies_[kPolicyProxyBypassList] = NULL;
+ } else {
+ prefs_.SetValue(prefs::kProxyBypassList, Value::CreateNullValue());
+ }
+}
+
+bool ConfigurationPolicyPrefKeeper::HasProxyPolicy(
+ ConfigurationPolicyType policy) const {
+ std::map<ConfigurationPolicyType, Value*>::const_iterator iter;
+ iter = proxy_policies_.find(policy);
+ return iter != proxy_policies_.end() &&
+ iter->second && !iter->second->IsType(Value::TYPE_NULL);
+}
+
+namespace {
+
+// Manages the lifecycle of the shared platform-specific policy providers for
+// managed platform, device management and recommended policy. Instantiated as a
+// Singleton.
+class ConfigurationPolicyProviderKeeper {
+ public:
+ ConfigurationPolicyProviderKeeper()
+ : managed_platform_provider_(CreateManagedPlatformProvider()),
+ device_management_provider_(CreateDeviceManagementProvider()),
+ recommended_provider_(CreateRecommendedProvider()) {}
+ virtual ~ConfigurationPolicyProviderKeeper() {}
+
+ ConfigurationPolicyProvider* managed_platform_provider() const {
+ return managed_platform_provider_.get();
+ }
+
+ ConfigurationPolicyProvider* device_management_provider() const {
+ return device_management_provider_.get();
+ }
+
+ ConfigurationPolicyProvider* recommended_provider() const {
+ return recommended_provider_.get();
+ }
+
+ private:
+ scoped_ptr<ConfigurationPolicyProvider> managed_platform_provider_;
+ scoped_ptr<ConfigurationPolicyProvider> device_management_provider_;
+ scoped_ptr<ConfigurationPolicyProvider> recommended_provider_;
+
+ static ConfigurationPolicyProvider* CreateManagedPlatformProvider();
+ static ConfigurationPolicyProvider* CreateDeviceManagementProvider();
+ static ConfigurationPolicyProvider* CreateRecommendedProvider();
+
+ DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyProviderKeeper);
+};
+
+static base::LazyInstance<ConfigurationPolicyProviderKeeper>
+ g_configuration_policy_provider_keeper(base::LINKER_INITIALIZED);
+
+ConfigurationPolicyProvider*
+ConfigurationPolicyProviderKeeper::CreateManagedPlatformProvider() {
+ const ConfigurationPolicyProvider::PolicyDefinitionList* policy_list =
+ ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList();
+#if defined(OS_WIN)
+ return new ConfigurationPolicyProviderWin(policy_list);
+#elif defined(OS_MACOSX)
+ return new ConfigurationPolicyProviderMac(policy_list);
+#elif defined(OS_POSIX)
+ FilePath config_dir_path;
+ if (PathService::Get(chrome::DIR_POLICY_FILES, &config_dir_path)) {
+ return new ConfigDirPolicyProvider(
+ policy_list,
+ config_dir_path.Append(FILE_PATH_LITERAL("managed")));
+ } else {
+ return new DummyConfigurationPolicyProvider(policy_list);
+ }
+#else
+ return new DummyConfigurationPolicyProvider(policy_list);
+#endif
+}
+
+ConfigurationPolicyProvider*
+ConfigurationPolicyProviderKeeper::CreateDeviceManagementProvider() {
+ return new DummyConfigurationPolicyProvider(
+ ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList());
+}
+
+ConfigurationPolicyProvider*
+ConfigurationPolicyProviderKeeper::CreateRecommendedProvider() {
+ const ConfigurationPolicyProvider::PolicyDefinitionList* policy_list =
+ ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList();
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+ FilePath config_dir_path;
+ if (PathService::Get(chrome::DIR_POLICY_FILES, &config_dir_path)) {
+ return new ConfigDirPolicyProvider(
+ policy_list,
+ config_dir_path.Append(FILE_PATH_LITERAL("recommended")));
+ } else {
+ return new DummyConfigurationPolicyProvider(policy_list);
+ }
+#else
+ return new DummyConfigurationPolicyProvider(policy_list);
+#endif
+}
+
+} // namespace
+
+ConfigurationPolicyPrefStore::ConfigurationPolicyPrefStore(
+ ConfigurationPolicyProvider* provider)
+ : provider_(provider),
+ initialization_complete_(provider->IsInitializationComplete()) {
+ // Read initial policy.
+ policy_keeper_.reset(new ConfigurationPolicyPrefKeeper(provider));
+
+ registrar_.Init(provider_);
+ registrar_.AddObserver(this);
+}
+
+ConfigurationPolicyPrefStore::~ConfigurationPolicyPrefStore() {
+}
+
+void ConfigurationPolicyPrefStore::AddObserver(PrefStore::Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void ConfigurationPolicyPrefStore::RemoveObserver(
+ PrefStore::Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+bool ConfigurationPolicyPrefStore::IsInitializationComplete() const {
+ return initialization_complete_;
+}
+
+PrefStore::ReadResult
+ConfigurationPolicyPrefStore::GetValue(const std::string& key,
+ Value** value) const {
+ return policy_keeper_->GetValue(key, value);
+}
+
+void ConfigurationPolicyPrefStore::OnUpdatePolicy() {
+ Refresh();
+}
+
+// static
+ConfigurationPolicyPrefStore*
+ConfigurationPolicyPrefStore::CreateManagedPlatformPolicyPrefStore() {
+ return new ConfigurationPolicyPrefStore(
+ g_configuration_policy_provider_keeper.Get().managed_platform_provider());
+}
+
+// static
+ConfigurationPolicyPrefStore*
+ConfigurationPolicyPrefStore::CreateDeviceManagementPolicyPrefStore(
+ Profile* profile) {
+ ConfigurationPolicyProviderKeeper* keeper =
+ g_configuration_policy_provider_keeper.Pointer();
+ ConfigurationPolicyProvider* provider = NULL;
+ if (profile)
+ provider = profile->GetPolicyContext()->GetDeviceManagementPolicyProvider();
+ if (!provider)
+ provider = keeper->device_management_provider();
+ return new ConfigurationPolicyPrefStore(provider);
+}
+
+// static
+ConfigurationPolicyPrefStore*
+ConfigurationPolicyPrefStore::CreateRecommendedPolicyPrefStore() {
+ return new ConfigurationPolicyPrefStore(
+ g_configuration_policy_provider_keeper.Get().recommended_provider());
+}
+
+/* static */
+const ConfigurationPolicyProvider::PolicyDefinitionList*
+ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList() {
+ static ConfigurationPolicyProvider::PolicyDefinitionList::Entry entries[] = {
+ { kPolicyHomePage, Value::TYPE_STRING, key::kHomepageLocation },
+ { kPolicyHomepageIsNewTabPage, Value::TYPE_BOOLEAN,
+ key::kHomepageIsNewTabPage },
+ { kPolicyRestoreOnStartup, Value::TYPE_INTEGER, key::kRestoreOnStartup },
+ { kPolicyURLsToRestoreOnStartup, Value::TYPE_LIST,
+ key::kURLsToRestoreOnStartup },
+ { kPolicyDefaultSearchProviderEnabled, Value::TYPE_BOOLEAN,
+ key::kDefaultSearchProviderEnabled },
+ { kPolicyDefaultSearchProviderName, Value::TYPE_STRING,
+ key::kDefaultSearchProviderName },
+ { kPolicyDefaultSearchProviderKeyword, Value::TYPE_STRING,
+ key::kDefaultSearchProviderKeyword },
+ { kPolicyDefaultSearchProviderSearchURL, Value::TYPE_STRING,
+ key::kDefaultSearchProviderSearchURL },
+ { kPolicyDefaultSearchProviderSuggestURL, Value::TYPE_STRING,
+ key::kDefaultSearchProviderSuggestURL },
+ { kPolicyDefaultSearchProviderIconURL, Value::TYPE_STRING,
+ key::kDefaultSearchProviderIconURL },
+ { kPolicyDefaultSearchProviderEncodings, Value::TYPE_STRING,
+ key::kDefaultSearchProviderEncodings },
+ { kPolicyProxyMode, Value::TYPE_INTEGER, key::kProxyMode },
+ { kPolicyProxyServer, Value::TYPE_STRING, key::kProxyServer },
+ { kPolicyProxyPacUrl, Value::TYPE_STRING, key::kProxyPacUrl },
+ { kPolicyProxyBypassList, Value::TYPE_STRING, key::kProxyBypassList },
+ { kPolicyAlternateErrorPagesEnabled, Value::TYPE_BOOLEAN,
+ key::kAlternateErrorPagesEnabled },
+ { kPolicySearchSuggestEnabled, Value::TYPE_BOOLEAN,
+ key::kSearchSuggestEnabled },
+ { kPolicyDnsPrefetchingEnabled, Value::TYPE_BOOLEAN,
+ key::kDnsPrefetchingEnabled },
+ { kPolicyDisableSpdy, Value::TYPE_BOOLEAN, key::kDisableSpdy },
+ { kPolicySafeBrowsingEnabled, Value::TYPE_BOOLEAN,
+ key::kSafeBrowsingEnabled },
+ { kPolicyMetricsReportingEnabled, Value::TYPE_BOOLEAN,
+ key::kMetricsReportingEnabled },
+ { kPolicyPasswordManagerEnabled, Value::TYPE_BOOLEAN,
+ key::kPasswordManagerEnabled },
+ { kPolicyPasswordManagerAllowShowPasswords, Value::TYPE_BOOLEAN,
+ key::kPasswordManagerAllowShowPasswords },
+ { kPolicyAutoFillEnabled, Value::TYPE_BOOLEAN, key::kAutoFillEnabled },
+ { kPolicyDisabledPlugins, Value::TYPE_LIST, key::kDisabledPlugins },
+ { kPolicyApplicationLocale, Value::TYPE_STRING,
+ key::kApplicationLocaleValue },
+ { kPolicySyncDisabled, Value::TYPE_BOOLEAN, key::kSyncDisabled },
+ { kPolicyExtensionInstallAllowList, Value::TYPE_LIST,
+ key::kExtensionInstallAllowList },
+ { kPolicyExtensionInstallDenyList, Value::TYPE_LIST,
+ key::kExtensionInstallDenyList },
+ { kPolicyExtensionInstallForceList, Value::TYPE_LIST,
+ key::kExtensionInstallForceList },
+ { kPolicyShowHomeButton, Value::TYPE_BOOLEAN, key::kShowHomeButton },
+ { kPolicyPrintingEnabled, Value::TYPE_BOOLEAN, key::kPrintingEnabled },
+ { kPolicyJavascriptEnabled, Value::TYPE_BOOLEAN, key::kJavascriptEnabled },
+ { kPolicySavingBrowserHistoryDisabled, Value::TYPE_BOOLEAN,
+ key::kSavingBrowserHistoryDisabled },
+ { kPolicyDeveloperToolsDisabled, Value::TYPE_BOOLEAN,
+ key::kDeveloperToolsDisabled },
+ { kPolicyBlockThirdPartyCookies, Value::TYPE_BOOLEAN,
+ key::kBlockThirdPartyCookies },
+ { kPolicyDefaultCookiesSetting, Value::TYPE_INTEGER,
+ key::kDefaultCookiesSetting },
+ { kPolicyDefaultImagesSetting, Value::TYPE_INTEGER,
+ key::kDefaultImagesSetting },
+ { kPolicyDefaultJavaScriptSetting, Value::TYPE_INTEGER,
+ key::kDefaultJavaScriptSetting },
+ { kPolicyDefaultPluginsSetting, Value::TYPE_INTEGER,
+ key::kDefaultPluginsSetting },
+ { kPolicyDefaultPopupsSetting, Value::TYPE_INTEGER,
+ key::kDefaultPopupsSetting },
+ { kPolicyDefaultNotificationSetting, Value::TYPE_INTEGER,
+ key::kDefaultNotificationSetting },
+ { kPolicyDefaultGeolocationSetting, Value::TYPE_INTEGER,
+ key::kDefaultGeolocationSetting },
+ { kPolicyAuthSchemes, Value::TYPE_STRING, key::kAuthSchemes },
+ { kPolicyDisableAuthNegotiateCnameLookup, Value::TYPE_BOOLEAN,
+ key::kDisableAuthNegotiateCnameLookup },
+ { kPolicyEnableAuthNegotiatePort, Value::TYPE_BOOLEAN,
+ key::kEnableAuthNegotiatePort },
+ { kPolicyAuthServerWhitelist, Value::TYPE_STRING,
+ key::kAuthServerWhitelist },
+ { kPolicyAuthNegotiateDelegateWhitelist, Value::TYPE_STRING,
+ key::kAuthNegotiateDelegateWhitelist },
+ { kPolicyGSSAPILibraryName, Value::TYPE_STRING,
+ key::kGSSAPILibraryName },
+ { kPolicyDisable3DAPIs, Value::TYPE_BOOLEAN,
+ key::kDisable3DAPIs },
+
+#if defined(OS_CHROMEOS)
+ { kPolicyChromeOsLockOnIdleSuspend, Value::TYPE_BOOLEAN,
+ key::kChromeOsLockOnIdleSuspend },
+#endif
+ };
+
+ static ConfigurationPolicyProvider::PolicyDefinitionList policy_list = {
+ entries,
+ entries + arraysize(entries),
+ };
+ return &policy_list;
+}
+
+void ConfigurationPolicyPrefStore::Refresh() {
+ // Construct a new keeper, determine what changed and swap the keeper in.
+ scoped_ptr<ConfigurationPolicyPrefKeeper> new_keeper(
+ new ConfigurationPolicyPrefKeeper(provider_));
+ std::vector<std::string> changed_prefs;
+ new_keeper->GetDifferingPrefPaths(policy_keeper_.get(), &changed_prefs);
+ policy_keeper_.reset(new_keeper.release());
+
+ // Send out change notifications.
+ for (std::vector<std::string>::const_iterator pref(changed_prefs.begin());
+ pref != changed_prefs.end();
+ ++pref) {
+ FOR_EACH_OBSERVER(PrefStore::Observer, observers_,
+ OnPrefValueChanged(*pref));
+ }
+
+ // Update the initialization flag.
+ if (!initialization_complete_ &&
+ provider_->IsInitializationComplete()) {
+ initialization_complete_ = true;
+ FOR_EACH_OBSERVER(PrefStore::Observer, observers_,
+ OnInitializationCompleted());
+ }
+}
+
} // namespace policy
diff --git a/chrome/browser/policy/configuration_policy_pref_store.h b/chrome/browser/policy/configuration_policy_pref_store.h
index be898a8..526d884 100644
--- a/chrome/browser/policy/configuration_policy_pref_store.h
+++ b/chrome/browser/policy/configuration_policy_pref_store.h
@@ -10,7 +10,7 @@
#include <string>
#include "base/basictypes.h"
-#include "base/gtest_prod_util.h"
+#include "base/observer_list.h"
#include "base/scoped_ptr.h"
#include "base/values.h"
#include "chrome/browser/policy/configuration_policy_provider.h"
@@ -21,24 +21,27 @@ class Profile;
namespace policy {
-// An implementation of the |PrefStore| that holds a Dictionary
-// created through applied policy.
-class ConfigurationPolicyPrefStore : public PrefStore,
- public ConfigurationPolicyStoreInterface {
- public:
- typedef std::set<const char*> ProxyPreferenceSet;
+class ConfigurationPolicyPrefKeeper;
+// An implementation of PrefStore that bridges policy settings as read from a
+// ConfigurationPolicyProvider to preferences.
+class ConfigurationPolicyPrefStore
+ : public PrefStore,
+ public ConfigurationPolicyProvider::Observer {
+ public:
// The ConfigurationPolicyPrefStore does not take ownership of the
// passed-in |provider|.
explicit ConfigurationPolicyPrefStore(ConfigurationPolicyProvider* provider);
- virtual ~ConfigurationPolicyPrefStore() {}
+ virtual ~ConfigurationPolicyPrefStore();
// PrefStore methods:
- virtual PrefReadError ReadPrefs();
- virtual DictionaryValue* prefs() const { return prefs_.get(); }
+ virtual void AddObserver(PrefStore::Observer* observer);
+ virtual void RemoveObserver(PrefStore::Observer* observer);
+ virtual bool IsInitializationComplete() const;
+ virtual ReadResult GetValue(const std::string& key, Value** result) const;
- // ConfigurationPolicyStore methods:
- virtual void Apply(ConfigurationPolicyType setting, Value* value);
+ // ConfigurationPolicyProvider::Observer methods:
+ virtual void OnUpdatePolicy();
// Creates a ConfigurationPolicyPrefStore that reads managed platform policy.
static ConfigurationPolicyPrefStore* CreateManagedPlatformPolicyPrefStore();
@@ -55,85 +58,27 @@ class ConfigurationPolicyPrefStore : public PrefStore,
static const ConfigurationPolicyProvider::PolicyDefinitionList*
GetChromePolicyDefinitionList();
- // Returns the set of preference paths that can be affected by a proxy
- // policy.
- static void GetProxyPreferenceSet(ProxyPreferenceSet* proxy_pref_set);
-
private:
- // Policies that map to a single preference are handled
- // by an automated converter. Each one of these policies
- // has an entry in |simple_policy_map_| with the following type.
- struct PolicyToPreferenceMapEntry {
- Value::ValueType value_type;
- ConfigurationPolicyType policy_type;
- const char* preference_path; // A DictionaryValue path, not a file path.
- };
-
- static const PolicyToPreferenceMapEntry kSimplePolicyMap[];
- static const PolicyToPreferenceMapEntry kProxyPolicyMap[];
- static const PolicyToPreferenceMapEntry kDefaultSearchPolicyMap[];
+ // Refreshes policy information, rereading policy from the provider and
+ // sending out change notifications as appropriate.
+ void Refresh();
+
static const ConfigurationPolicyProvider::PolicyDefinitionList
kPolicyDefinitionList;
+ // The policy provider from which policy settings are read.
ConfigurationPolicyProvider* provider_;
- scoped_ptr<DictionaryValue> prefs_;
-
- // Set to false until the first proxy-relevant policy is applied. At that
- // time, default values are provided for all proxy-relevant prefs
- // to override any values set from stores with a lower priority.
- bool lower_priority_proxy_settings_overridden_;
-
- // The following are used to track what proxy-relevant policy has been applied
- // accross calls to Apply to provide a warning if a policy specifies a
- // contradictory proxy configuration. |proxy_disabled_| is set to true if and
- // only if the kPolicyNoProxyServer has been applied,
- // |proxy_configuration_specified_| is set to true if and only if any other
- // proxy policy other than kPolicyNoProxyServer has been applied.
- bool proxy_disabled_;
- bool proxy_configuration_specified_;
-
- // Set to true if a the proxy mode policy has been set to force Chrome
- // to use the system proxy.
- bool use_system_proxy_;
-
- // Returns the map entry that corresponds to |policy| in the map.
- const PolicyToPreferenceMapEntry* FindPolicyInMap(
- ConfigurationPolicyType policy,
- const PolicyToPreferenceMapEntry* map,
- int size) const;
-
- // Remove the preferences found in the map from |prefs_|. Returns true if
- // any such preferences were found and removed.
- bool RemovePreferencesOfMap(const PolicyToPreferenceMapEntry* map,
- int table_size);
-
- bool ApplyPolicyFromMap(ConfigurationPolicyType policy,
- Value* value,
- const PolicyToPreferenceMapEntry* map,
- int size);
-
- // Processes proxy-specific policies. Returns true if the specified policy
- // is a proxy-related policy. ApplyProxyPolicy assumes the ownership
- // of |value| in the case that the policy is proxy-specific.
- bool ApplyProxyPolicy(ConfigurationPolicyType policy, Value* value);
-
- // Handles sync-related policies. Returns true if the policy was handled.
- // Assumes ownership of |value| in that case.
- bool ApplySyncPolicy(ConfigurationPolicyType policy, Value* value);
-
- // Handles policies that affect AutoFill. Returns true if the policy was
- // handled and assumes ownership of |value| in that case.
- bool ApplyAutoFillPolicy(ConfigurationPolicyType policy, Value* value);
-
- // Make sure that the |path| if present in |prefs_|. If not, set it to
- // a blank string.
- void EnsureStringPrefExists(const std::string& path);
-
- // If the required entries for default search are specified and valid,
- // finalizes the policy-specified configuration by initializing the
- // unspecified map entries. Otherwise wipes all default search related
- // map entries from |prefs_|.
- void FinalizeDefaultSearchPolicySettings();
+
+ // Initialization status as reported by the policy provider the last time we
+ // queried it.
+ bool initialization_complete_;
+
+ // Current policy preferences.
+ scoped_ptr<ConfigurationPolicyPrefKeeper> policy_keeper_;
+
+ ObserverList<PrefStore::Observer, true> observers_;
+
+ ConfigurationPolicyObserverRegistrar registrar_;
DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyPrefStore);
};
diff --git a/chrome/browser/policy/configuration_policy_pref_store_unittest.cc b/chrome/browser/policy/configuration_policy_pref_store_unittest.cc
index af9f8e4..1896aaa 100644
--- a/chrome/browser/policy/configuration_policy_pref_store_unittest.cc
+++ b/chrome/browser/policy/configuration_policy_pref_store_unittest.cc
@@ -2,13 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <gtest/gtest.h>
-
#include "base/file_path.h"
#include "chrome/browser/policy/configuration_policy_pref_store.h"
#include "chrome/browser/policy/mock_configuration_policy_provider.h"
-#include "chrome/common/pref_names.h"
+#include "chrome/browser/prefs/proxy_prefs.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/pref_store_observer_mock.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Mock;
namespace policy {
@@ -27,37 +33,38 @@ class TypeAndName {
const char* pref_name_;
};
+template<typename TESTBASE>
+class ConfigurationPolicyPrefStoreTestBase : public TESTBASE {
+ protected:
+ ConfigurationPolicyPrefStoreTestBase()
+ : provider_(),
+ store_(&provider_) {}
+
+ MockConfigurationPolicyProvider provider_;
+ ConfigurationPolicyPrefStore store_;
+};
+
// Test cases for list-valued policy settings.
class ConfigurationPolicyPrefStoreListTest
- : public testing::TestWithParam<TypeAndName> {
+ : public ConfigurationPolicyPrefStoreTestBase<
+ testing::TestWithParam<TypeAndName> > {
};
TEST_P(ConfigurationPolicyPrefStoreListTest, GetDefault) {
- ConfigurationPolicyPrefStore store(NULL);
- ListValue* list = NULL;
- EXPECT_FALSE(store.prefs()->GetList(GetParam().pref_name(), &list));
+ EXPECT_EQ(PrefStore::READ_NO_VALUE,
+ store_.GetValue(GetParam().pref_name(), NULL));
}
TEST_P(ConfigurationPolicyPrefStoreListTest, SetValue) {
- ConfigurationPolicyPrefStore store(NULL);
ListValue* in_value = new ListValue();
in_value->Append(Value::CreateStringValue("test1"));
in_value->Append(Value::CreateStringValue("test2,"));
- store.Apply(GetParam().type(), in_value);
- ListValue* list = NULL;
- EXPECT_TRUE(store.prefs()->GetList(GetParam().pref_name(), &list));
- ListValue::const_iterator current(list->begin());
- const ListValue::const_iterator end(list->end());
- ASSERT_TRUE(current != end);
- std::string value;
- (*current)->GetAsString(&value);
- EXPECT_EQ("test1", value);
- ++current;
- ASSERT_TRUE(current != end);
- (*current)->GetAsString(&value);
- EXPECT_EQ("test2,", value);
- ++current;
- EXPECT_TRUE(current == end);
+ provider_.AddPolicy(GetParam().type(), in_value);
+ store_.OnUpdatePolicy();
+ Value* value;
+ EXPECT_EQ(PrefStore::READ_OK,
+ store_.GetValue(GetParam().pref_name(), &value));
+ EXPECT_TRUE(in_value->Equals(value));
}
INSTANTIATE_TEST_CASE_P(
@@ -75,22 +82,23 @@ INSTANTIATE_TEST_CASE_P(
// Test cases for string-valued policy settings.
class ConfigurationPolicyPrefStoreStringTest
- : public testing::TestWithParam<TypeAndName> {
+ : public ConfigurationPolicyPrefStoreTestBase<
+ testing::TestWithParam<TypeAndName> > {
};
TEST_P(ConfigurationPolicyPrefStoreStringTest, GetDefault) {
- ConfigurationPolicyPrefStore store(NULL);
- std::string result;
- EXPECT_FALSE(store.prefs()->GetString(GetParam().pref_name(), &result));
+ EXPECT_EQ(PrefStore::READ_NO_VALUE,
+ store_.GetValue(GetParam().pref_name(), NULL));
}
TEST_P(ConfigurationPolicyPrefStoreStringTest, SetValue) {
- ConfigurationPolicyPrefStore store(NULL);
- store.Apply(GetParam().type(),
- Value::CreateStringValue("http://chromium.org"));
- std::string result;
- EXPECT_TRUE(store.prefs()->GetString(GetParam().pref_name(), &result));
- EXPECT_EQ(result, "http://chromium.org");
+ provider_.AddPolicy(GetParam().type(),
+ Value::CreateStringValue("http://chromium.org"));
+ store_.OnUpdatePolicy();
+ Value* value;
+ EXPECT_EQ(PrefStore::READ_OK,
+ store_.GetValue(GetParam().pref_name(), &value));
+ EXPECT_TRUE(StringValue("http://chromium.org").Equals(value));
}
INSTANTIATE_TEST_CASE_P(
@@ -99,12 +107,6 @@ INSTANTIATE_TEST_CASE_P(
testing::Values(
TypeAndName(kPolicyHomePage,
prefs::kHomePage),
- TypeAndName(kPolicyProxyServer,
- prefs::kProxyServer),
- TypeAndName(kPolicyProxyPacUrl,
- prefs::kProxyPacUrl),
- TypeAndName(kPolicyProxyBypassList,
- prefs::kProxyBypassList),
TypeAndName(kPolicyApplicationLocale,
prefs::kApplicationLocale),
TypeAndName(kPolicyApplicationLocale,
@@ -120,26 +122,30 @@ INSTANTIATE_TEST_CASE_P(
// Test cases for boolean-valued policy settings.
class ConfigurationPolicyPrefStoreBooleanTest
- : public testing::TestWithParam<TypeAndName> {
+ : public ConfigurationPolicyPrefStoreTestBase<
+ testing::TestWithParam<TypeAndName> > {
};
TEST_P(ConfigurationPolicyPrefStoreBooleanTest, GetDefault) {
- ConfigurationPolicyPrefStore store(NULL);
- bool result = false;
- EXPECT_FALSE(store.prefs()->GetBoolean(GetParam().pref_name(), &result));
+ EXPECT_EQ(PrefStore::READ_NO_VALUE,
+ store_.GetValue(GetParam().pref_name(), NULL));
}
TEST_P(ConfigurationPolicyPrefStoreBooleanTest, SetValue) {
- ConfigurationPolicyPrefStore store(NULL);
- store.Apply(GetParam().type(), Value::CreateBooleanValue(false));
+ provider_.AddPolicy(GetParam().type(), Value::CreateBooleanValue(false));
+ store_.OnUpdatePolicy();
+ Value* value;
bool result = true;
- EXPECT_TRUE(store.prefs()->GetBoolean(GetParam().pref_name(), &result));
- EXPECT_FALSE(result);
+ EXPECT_EQ(PrefStore::READ_OK,
+ store_.GetValue(GetParam().pref_name(), &value));
+ EXPECT_TRUE(FundamentalValue(false).Equals(value));
- store.Apply(GetParam().type(), Value::CreateBooleanValue(true));
+ provider_.AddPolicy(GetParam().type(), Value::CreateBooleanValue(true));
+ store_.OnUpdatePolicy();
result = false;
- EXPECT_TRUE(store.prefs()->GetBoolean(GetParam().pref_name(), &result));
- EXPECT_TRUE(result);
+ EXPECT_EQ(PrefStore::READ_OK,
+ store_.GetValue(GetParam().pref_name(), &value));
+ EXPECT_TRUE(FundamentalValue(true).Equals(value));
}
INSTANTIATE_TEST_CASE_P(
@@ -192,21 +198,22 @@ INSTANTIATE_TEST_CASE_P(
// Test cases for integer-valued policy settings.
class ConfigurationPolicyPrefStoreIntegerTest
- : public testing::TestWithParam<TypeAndName> {
+ : public ConfigurationPolicyPrefStoreTestBase<
+ testing::TestWithParam<TypeAndName> > {
};
TEST_P(ConfigurationPolicyPrefStoreIntegerTest, GetDefault) {
- ConfigurationPolicyPrefStore store(NULL);
- int result = 0;
- EXPECT_FALSE(store.prefs()->GetInteger(GetParam().pref_name(), &result));
+ EXPECT_EQ(PrefStore::READ_NO_VALUE,
+ store_.GetValue(GetParam().pref_name(), NULL));
}
TEST_P(ConfigurationPolicyPrefStoreIntegerTest, SetValue) {
- ConfigurationPolicyPrefStore store(NULL);
- store.Apply(GetParam().type(), Value::CreateIntegerValue(2));
- int result = 0;
- EXPECT_TRUE(store.prefs()->GetInteger(GetParam().pref_name(), &result));
- EXPECT_EQ(result, 2);
+ provider_.AddPolicy(GetParam().type(), Value::CreateIntegerValue(2));
+ store_.OnUpdatePolicy();
+ Value* value = NULL;
+ EXPECT_EQ(PrefStore::READ_OK,
+ store_.GetValue(GetParam().pref_name(), &value));
+ EXPECT_TRUE(FundamentalValue(2).Equals(value));
}
INSTANTIATE_TEST_CASE_P(
@@ -218,153 +225,133 @@ INSTANTIATE_TEST_CASE_P(
// Test cases for the proxy policy settings.
class ConfigurationPolicyPrefStoreProxyTest : public testing::Test {
+ protected:
+ // Verify that all the proxy prefs are set to the specified expected values.
+ static void VerifyProxyPrefs(
+ const ConfigurationPolicyPrefStore& store,
+ const std::string& expected_proxy_server,
+ const std::string& expected_proxy_pac_url,
+ const std::string& expected_proxy_bypass_list,
+ const ProxyPrefs::ProxyMode& expected_proxy_mode) {
+ Value* value = NULL;
+
+ if (expected_proxy_server.empty()) {
+ EXPECT_EQ(PrefStore::READ_USE_DEFAULT,
+ store.GetValue(prefs::kProxyServer, NULL));
+ } else {
+ EXPECT_EQ(PrefStore::READ_OK,
+ store.GetValue(prefs::kProxyServer, &value));
+ EXPECT_TRUE(StringValue(expected_proxy_server).Equals(value));
+ }
+ if (expected_proxy_pac_url.empty()) {
+ EXPECT_EQ(PrefStore::READ_USE_DEFAULT,
+ store.GetValue(prefs::kProxyPacUrl, NULL));
+ } else {
+ EXPECT_EQ(PrefStore::READ_OK,
+ store.GetValue(prefs::kProxyPacUrl, &value));
+ EXPECT_TRUE(StringValue(expected_proxy_pac_url).Equals(value));
+ }
+ if (expected_proxy_bypass_list.empty()) {
+ EXPECT_EQ(PrefStore::READ_USE_DEFAULT,
+ store.GetValue(prefs::kProxyBypassList, NULL));
+ } else {
+ EXPECT_EQ(PrefStore::READ_OK,
+ store.GetValue(prefs::kProxyBypassList, &value));
+ EXPECT_TRUE(StringValue(expected_proxy_bypass_list).Equals(value));
+ }
+ EXPECT_EQ(PrefStore::READ_OK, store.GetValue(prefs::kProxyMode, &value));
+ EXPECT_TRUE(FundamentalValue(expected_proxy_mode).Equals(value));
+ }
};
TEST_F(ConfigurationPolicyPrefStoreProxyTest, ManualOptions) {
- scoped_ptr<MockConfigurationPolicyProvider> provider(
- new MockConfigurationPolicyProvider());
- provider->AddPolicy(kPolicyProxyBypassList,
- Value::CreateStringValue("http://chromium.org/override"));
- provider->AddPolicy(kPolicyProxyPacUrl,
- Value::CreateStringValue("http://short.org/proxy.pac"));
- provider->AddPolicy(kPolicyProxyServer,
- Value::CreateStringValue("chromium.org"));
- provider->AddPolicy(kPolicyProxyServerMode,
- Value::CreateIntegerValue(
- kPolicyManuallyConfiguredProxyMode));
-
- ConfigurationPolicyPrefStore store(provider.get());
- EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
-
- std::string string_result;
- EXPECT_TRUE(store.prefs()->GetString(prefs::kProxyBypassList,
- &string_result));
- EXPECT_EQ("http://chromium.org/override", string_result);
- EXPECT_TRUE(store.prefs()->GetString(prefs::kProxyPacUrl, &string_result));
- EXPECT_EQ("http://short.org/proxy.pac", string_result);
- EXPECT_TRUE(store.prefs()->GetString(prefs::kProxyServer, &string_result));
- EXPECT_EQ("chromium.org", string_result);
- bool bool_result;
- EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kNoProxyServer, &bool_result));
- EXPECT_FALSE(bool_result);
- EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kProxyAutoDetect, &bool_result));
- EXPECT_FALSE(bool_result);
+ MockConfigurationPolicyProvider provider;
+ provider.AddPolicy(kPolicyProxyBypassList,
+ Value::CreateStringValue("http://chromium.org/override"));
+ provider.AddPolicy(kPolicyProxyServer,
+ Value::CreateStringValue("chromium.org"));
+ provider.AddPolicy(kPolicyProxyMode,
+ Value::CreateIntegerValue(
+ kPolicyManuallyConfiguredProxyMode));
+
+ ConfigurationPolicyPrefStore store(&provider);
+ VerifyProxyPrefs(
+ store, "chromium.org", "", "http://chromium.org/override",
+ ProxyPrefs::MODE_FIXED_SERVERS);
}
-TEST_F(ConfigurationPolicyPrefStoreProxyTest, NoProxy) {
- scoped_ptr<MockConfigurationPolicyProvider> provider(
- new MockConfigurationPolicyProvider());
- provider->AddPolicy(kPolicyProxyBypassList,
- Value::CreateStringValue("http://chromium.org/override"));
- provider->AddPolicy(kPolicyProxyServerMode,
- Value::CreateIntegerValue(
- kPolicyNoProxyServerMode));
-
- ConfigurationPolicyPrefStore store(provider.get());
- EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
-
- std::string string_result;
- EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyBypassList,
- &string_result));
- EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyPacUrl, &string_result));
- EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyServer, &string_result));
- bool bool_result;
- EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kNoProxyServer, &bool_result));
- EXPECT_TRUE(bool_result);
- EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kProxyAutoDetect, &bool_result));
- EXPECT_FALSE(bool_result);
+TEST_F(ConfigurationPolicyPrefStoreProxyTest, ManualOptionsReversedApplyOrder) {
+ MockConfigurationPolicyProvider provider;
+ provider.AddPolicy(kPolicyProxyMode,
+ Value::CreateIntegerValue(
+ kPolicyManuallyConfiguredProxyMode));
+ provider.AddPolicy(kPolicyProxyBypassList,
+ Value::CreateStringValue("http://chromium.org/override"));
+ provider.AddPolicy(kPolicyProxyServer,
+ Value::CreateStringValue("chromium.org"));
+
+ ConfigurationPolicyPrefStore store(&provider);
+ VerifyProxyPrefs(
+ store, "chromium.org", "", "http://chromium.org/override",
+ ProxyPrefs::MODE_FIXED_SERVERS);
}
-TEST_F(ConfigurationPolicyPrefStoreProxyTest, NoProxyReversedApplyOrder) {
- scoped_ptr<MockConfigurationPolicyProvider> provider(
- new MockConfigurationPolicyProvider());
- provider->AddPolicy(kPolicyProxyServerMode,
- Value::CreateIntegerValue(
- kPolicyNoProxyServerMode));
- provider->AddPolicy(kPolicyProxyBypassList,
- Value::CreateStringValue("http://chromium.org/override"));
-
- ConfigurationPolicyPrefStore store(provider.get());
- EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
-
- std::string string_result;
- EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyBypassList,
- &string_result));
- EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyPacUrl, &string_result));
- EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyServer, &string_result));
- bool bool_result;
- EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kNoProxyServer, &bool_result));
- EXPECT_TRUE(bool_result);
- EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kProxyAutoDetect, &bool_result));
- EXPECT_FALSE(bool_result);
+TEST_F(ConfigurationPolicyPrefStoreProxyTest, NoProxy) {
+ MockConfigurationPolicyProvider provider;
+ provider.AddPolicy(kPolicyProxyMode,
+ Value::CreateIntegerValue(kPolicyNoProxyServerMode));
+
+ ConfigurationPolicyPrefStore store(&provider);
+ VerifyProxyPrefs(store, "", "", "", ProxyPrefs::MODE_DIRECT);
}
TEST_F(ConfigurationPolicyPrefStoreProxyTest, AutoDetect) {
- scoped_ptr<MockConfigurationPolicyProvider> provider(
- new MockConfigurationPolicyProvider());
- provider->AddPolicy(kPolicyProxyServerMode,
- Value::CreateIntegerValue(
- kPolicyAutoDetectProxyMode));
-
- ConfigurationPolicyPrefStore store(provider.get());
- EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
-
- std::string string_result;
- EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyBypassList,
- &string_result));
- EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyPacUrl, &string_result));
- EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyServer, &string_result));
- bool bool_result;
- EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kNoProxyServer, &bool_result));
- EXPECT_FALSE(bool_result);
- EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kProxyAutoDetect, &bool_result));
- EXPECT_TRUE(bool_result);
+ MockConfigurationPolicyProvider provider;
+ provider.AddPolicy(kPolicyProxyMode,
+ Value::CreateIntegerValue(kPolicyAutoDetectProxyMode));
+
+ ConfigurationPolicyPrefStore store(&provider);
+ VerifyProxyPrefs(store, "", "", "", ProxyPrefs::MODE_AUTO_DETECT);
+}
+
+TEST_F(ConfigurationPolicyPrefStoreProxyTest, AutoDetectPac) {
+ MockConfigurationPolicyProvider provider;
+ provider.AddPolicy(kPolicyProxyPacUrl,
+ Value::CreateStringValue("http://short.org/proxy.pac"));
+ provider.AddPolicy(kPolicyProxyMode,
+ Value::CreateIntegerValue(kPolicyAutoDetectProxyMode));
+
+ ConfigurationPolicyPrefStore store(&provider);
+ VerifyProxyPrefs(
+ store, "", "http://short.org/proxy.pac", "", ProxyPrefs::MODE_PAC_SCRIPT);
}
TEST_F(ConfigurationPolicyPrefStoreProxyTest, UseSystem) {
- scoped_ptr<MockConfigurationPolicyProvider> provider(
- new MockConfigurationPolicyProvider());
- provider->AddPolicy(kPolicyProxyBypassList,
- Value::CreateStringValue("http://chromium.org/override"));
- provider->AddPolicy(kPolicyProxyServerMode,
- Value::CreateIntegerValue(
- kPolicyUseSystemProxyMode));
-
- ConfigurationPolicyPrefStore store(provider.get());
- EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
-
- std::string string_result;
- EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyBypassList,
- &string_result));
- EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyPacUrl, &string_result));
- EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyServer, &string_result));
- bool bool_result;
- EXPECT_FALSE(store.prefs()->GetBoolean(prefs::kNoProxyServer, &bool_result));
- EXPECT_FALSE(store.prefs()->GetBoolean(prefs::kProxyAutoDetect,
- &bool_result));
+ MockConfigurationPolicyProvider provider;
+ provider.AddPolicy(kPolicyProxyMode,
+ Value::CreateIntegerValue(kPolicyUseSystemProxyMode));
+
+ ConfigurationPolicyPrefStore store(&provider);
+ VerifyProxyPrefs(store, "", "", "", ProxyPrefs::MODE_SYSTEM);
}
-TEST_F(ConfigurationPolicyPrefStoreProxyTest, UseSystemReversedApplyOrder) {
- scoped_ptr<MockConfigurationPolicyProvider> provider(
- new MockConfigurationPolicyProvider());
- provider->AddPolicy(kPolicyProxyServerMode,
- Value::CreateIntegerValue(
- kPolicyUseSystemProxyMode));
- provider->AddPolicy(kPolicyProxyBypassList,
- Value::CreateStringValue("http://chromium.org/override"));
-
- ConfigurationPolicyPrefStore store(provider.get());
- EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
-
- std::string string_result;
- EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyBypassList,
- &string_result));
- EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyPacUrl, &string_result));
- EXPECT_FALSE(store.prefs()->GetString(prefs::kProxyServer, &string_result));
- bool bool_result;
- EXPECT_FALSE(store.prefs()->GetBoolean(prefs::kNoProxyServer, &bool_result));
- EXPECT_FALSE(store.prefs()->GetBoolean(prefs::kProxyAutoDetect,
- &bool_result));
+TEST_F(ConfigurationPolicyPrefStoreProxyTest, ProxyInvalid) {
+ for (int i = 0; i < MODE_COUNT; ++i) {
+ MockConfigurationPolicyProvider provider;
+ provider.AddPolicy(kPolicyProxyMode, Value::CreateIntegerValue(i));
+ // No mode expects all three parameters being set.
+ provider.AddPolicy(kPolicyProxyPacUrl,
+ Value::CreateStringValue("http://short.org/proxy.pac"));
+ provider.AddPolicy(kPolicyProxyBypassList,
+ Value::CreateStringValue(
+ "http://chromium.org/override"));
+ provider.AddPolicy(kPolicyProxyServer,
+ Value::CreateStringValue("chromium.org"));
+
+ ConfigurationPolicyPrefStore store(&provider);
+ EXPECT_EQ(PrefStore::READ_NO_VALUE,
+ store.GetValue(prefs::kProxyMode, NULL));
+ }
}
class ConfigurationPolicyPrefStoreDefaultSearchTest : public testing::Test {
@@ -374,44 +361,38 @@ class ConfigurationPolicyPrefStoreDefaultSearchTest : public testing::Test {
// search URL, that all the elements have been given proper defaults.
TEST_F(ConfigurationPolicyPrefStoreDefaultSearchTest, MinimallyDefined) {
const char* const search_url = "http://test.com/search?t={searchTerms}";
- scoped_ptr<MockConfigurationPolicyProvider> provider(
- new MockConfigurationPolicyProvider());
- provider->AddPolicy(
- kPolicyDefaultSearchProviderEnabled,
- Value::CreateBooleanValue(true));
- provider->AddPolicy(
- kPolicyDefaultSearchProviderSearchURL,
- Value::CreateStringValue(search_url));
-
- ConfigurationPolicyPrefStore store(provider.get());
-
- EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
- const DictionaryValue* prefs = store.prefs();
-
- std::string string_result;
- EXPECT_TRUE(prefs->GetString(prefs::kDefaultSearchProviderSearchURL,
- &string_result));
- EXPECT_EQ(string_result, search_url);
-
- EXPECT_TRUE(prefs->GetString(prefs::kDefaultSearchProviderName,
- &string_result));
- EXPECT_EQ(string_result, "test.com");
-
- EXPECT_TRUE(prefs->GetString(prefs::kDefaultSearchProviderKeyword,
- &string_result));
- EXPECT_EQ(string_result, std::string());
-
- EXPECT_TRUE(prefs->GetString(prefs::kDefaultSearchProviderSuggestURL,
- &string_result));
- EXPECT_EQ(string_result, std::string());
-
- EXPECT_TRUE(prefs->GetString(prefs::kDefaultSearchProviderIconURL,
- &string_result));
- EXPECT_EQ(string_result, std::string());
-
- EXPECT_TRUE(prefs->GetString(prefs::kDefaultSearchProviderEncodings,
- &string_result));
- EXPECT_EQ(string_result, std::string());
+ MockConfigurationPolicyProvider provider;
+ provider.AddPolicy(kPolicyDefaultSearchProviderEnabled,
+ Value::CreateBooleanValue(true));
+ provider.AddPolicy(kPolicyDefaultSearchProviderSearchURL,
+ Value::CreateStringValue(search_url));
+
+ ConfigurationPolicyPrefStore store(&provider);
+
+ Value* value = NULL;
+ EXPECT_EQ(PrefStore::READ_OK,
+ store.GetValue(prefs::kDefaultSearchProviderSearchURL, &value));
+ EXPECT_TRUE(StringValue(search_url).Equals(value));
+
+ EXPECT_EQ(PrefStore::READ_OK,
+ store.GetValue(prefs::kDefaultSearchProviderName, &value));
+ EXPECT_TRUE(StringValue("test.com").Equals(value));
+
+ EXPECT_EQ(PrefStore::READ_OK,
+ store.GetValue(prefs::kDefaultSearchProviderKeyword, &value));
+ EXPECT_TRUE(StringValue(std::string()).Equals(value));
+
+ EXPECT_EQ(PrefStore::READ_OK,
+ store.GetValue(prefs::kDefaultSearchProviderSuggestURL, &value));
+ EXPECT_TRUE(StringValue(std::string()).Equals(value));
+
+ EXPECT_EQ(PrefStore::READ_OK,
+ store.GetValue(prefs::kDefaultSearchProviderIconURL, &value));
+ EXPECT_TRUE(StringValue(std::string()).Equals(value));
+
+ EXPECT_EQ(PrefStore::READ_OK,
+ store.GetValue(prefs::kDefaultSearchProviderEncodings, &value));
+ EXPECT_TRUE(StringValue(std::string()).Equals(value));
}
// Checks that for a fully defined search policy, all elements have been
@@ -423,63 +404,48 @@ TEST_F(ConfigurationPolicyPrefStoreDefaultSearchTest, FullyDefined) {
const char* const name = "MyName";
const char* const keyword = "MyKeyword";
const char* const encodings = "UTF-16;UTF-8";
- scoped_ptr<MockConfigurationPolicyProvider> provider(
- new MockConfigurationPolicyProvider());
- provider->AddPolicy(
- kPolicyDefaultSearchProviderEnabled,
- Value::CreateBooleanValue(true));
- provider->AddPolicy(
- kPolicyDefaultSearchProviderSearchURL,
- Value::CreateStringValue(search_url));
- provider->AddPolicy(
- kPolicyDefaultSearchProviderName,
- Value::CreateStringValue(name));
- provider->AddPolicy(
- kPolicyDefaultSearchProviderKeyword,
- Value::CreateStringValue(keyword));
- provider->AddPolicy(
- kPolicyDefaultSearchProviderSuggestURL,
- Value::CreateStringValue(suggest_url));
- provider->AddPolicy(
- kPolicyDefaultSearchProviderIconURL,
- Value::CreateStringValue(icon_url));
- provider->AddPolicy(
- kPolicyDefaultSearchProviderEncodings,
- Value::CreateStringValue(encodings));
-
- ConfigurationPolicyPrefStore store(provider.get());
- EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
- const DictionaryValue* prefs = store.prefs();
-
- std::string result_search_url;
- EXPECT_TRUE(prefs->GetString(prefs::kDefaultSearchProviderSearchURL,
- &result_search_url));
- EXPECT_EQ(result_search_url, search_url);
-
- std::string result_name;
- EXPECT_TRUE(prefs->GetString(prefs::kDefaultSearchProviderName,
- &result_name));
- EXPECT_EQ(result_name, name);
-
- std::string result_keyword;
- EXPECT_TRUE(prefs->GetString(prefs::kDefaultSearchProviderKeyword,
- &result_keyword));
- EXPECT_EQ(result_keyword, keyword);
-
- std::string result_suggest_url;
- EXPECT_TRUE(prefs->GetString(prefs::kDefaultSearchProviderSuggestURL,
- &result_suggest_url));
- EXPECT_EQ(result_suggest_url, suggest_url);
-
- std::string result_icon_url;
- EXPECT_TRUE(prefs->GetString(prefs::kDefaultSearchProviderIconURL,
- &result_icon_url));
- EXPECT_EQ(result_icon_url, icon_url);
-
- std::string result_encodings;
- EXPECT_TRUE(prefs->GetString(prefs::kDefaultSearchProviderEncodings,
- &result_encodings));
- EXPECT_EQ(result_encodings, encodings);
+ MockConfigurationPolicyProvider provider;
+ provider.AddPolicy(kPolicyDefaultSearchProviderEnabled,
+ Value::CreateBooleanValue(true));
+ provider.AddPolicy(kPolicyDefaultSearchProviderSearchURL,
+ Value::CreateStringValue(search_url));
+ provider.AddPolicy(kPolicyDefaultSearchProviderName,
+ Value::CreateStringValue(name));
+ provider.AddPolicy(kPolicyDefaultSearchProviderKeyword,
+ Value::CreateStringValue(keyword));
+ provider.AddPolicy(kPolicyDefaultSearchProviderSuggestURL,
+ Value::CreateStringValue(suggest_url));
+ provider.AddPolicy(kPolicyDefaultSearchProviderIconURL,
+ Value::CreateStringValue(icon_url));
+ provider.AddPolicy(kPolicyDefaultSearchProviderEncodings,
+ Value::CreateStringValue(encodings));
+
+ ConfigurationPolicyPrefStore store(&provider);
+
+ Value* value = NULL;
+ EXPECT_EQ(PrefStore::READ_OK,
+ store.GetValue(prefs::kDefaultSearchProviderSearchURL, &value));
+ EXPECT_TRUE(StringValue(search_url).Equals(value));
+
+ EXPECT_EQ(PrefStore::READ_OK,
+ store.GetValue(prefs::kDefaultSearchProviderName, &value));
+ EXPECT_TRUE(StringValue(name).Equals(value));
+
+ EXPECT_EQ(PrefStore::READ_OK,
+ store.GetValue(prefs::kDefaultSearchProviderKeyword, &value));
+ EXPECT_TRUE(StringValue(keyword).Equals(value));
+
+ EXPECT_EQ(PrefStore::READ_OK,
+ store.GetValue(prefs::kDefaultSearchProviderSuggestURL, &value));
+ EXPECT_TRUE(StringValue(suggest_url).Equals(value));
+
+ EXPECT_EQ(PrefStore::READ_OK,
+ store.GetValue(prefs::kDefaultSearchProviderIconURL, &value));
+ EXPECT_TRUE(StringValue(icon_url).Equals(value));
+
+ EXPECT_EQ(PrefStore::READ_OK,
+ store.GetValue(prefs::kDefaultSearchProviderEncodings, &value));
+ EXPECT_TRUE(StringValue(encodings).Equals(value));
}
// Checks that if the default search policy is missing, that no elements of the
@@ -490,44 +456,34 @@ TEST_F(ConfigurationPolicyPrefStoreDefaultSearchTest, MissingUrl) {
const char* const name = "MyName";
const char* const keyword = "MyKeyword";
const char* const encodings = "UTF-16;UTF-8";
- scoped_ptr<MockConfigurationPolicyProvider> provider(
- new MockConfigurationPolicyProvider());
- provider->AddPolicy(
- kPolicyDefaultSearchProviderEnabled,
- Value::CreateBooleanValue(true));
- provider->AddPolicy(
- kPolicyDefaultSearchProviderName,
- Value::CreateStringValue(name));
- provider->AddPolicy(
- kPolicyDefaultSearchProviderKeyword,
- Value::CreateStringValue(keyword));
- provider->AddPolicy(
- kPolicyDefaultSearchProviderSuggestURL,
- Value::CreateStringValue(suggest_url));
- provider->AddPolicy(
- kPolicyDefaultSearchProviderIconURL,
- Value::CreateStringValue(icon_url));
- provider->AddPolicy(
- kPolicyDefaultSearchProviderEncodings,
- Value::CreateStringValue(encodings));
-
- ConfigurationPolicyPrefStore store(provider.get());
- EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
- const DictionaryValue* prefs = store.prefs();
-
- std::string string_result;
- EXPECT_FALSE(prefs->GetString(prefs::kDefaultSearchProviderSearchURL,
- &string_result));
- EXPECT_FALSE(prefs->GetString(prefs::kDefaultSearchProviderName,
- &string_result));
- EXPECT_FALSE(prefs->GetString(prefs::kDefaultSearchProviderKeyword,
- &string_result));
- EXPECT_FALSE(prefs->GetString(prefs::kDefaultSearchProviderSuggestURL,
- &string_result));
- EXPECT_FALSE(prefs->GetString(prefs::kDefaultSearchProviderIconURL,
- &string_result));
- EXPECT_FALSE(prefs->GetString(prefs::kDefaultSearchProviderEncodings,
- &string_result));
+ MockConfigurationPolicyProvider provider;
+ provider.AddPolicy(kPolicyDefaultSearchProviderEnabled,
+ Value::CreateBooleanValue(true));
+ provider.AddPolicy(kPolicyDefaultSearchProviderName,
+ Value::CreateStringValue(name));
+ provider.AddPolicy(kPolicyDefaultSearchProviderKeyword,
+ Value::CreateStringValue(keyword));
+ provider.AddPolicy(kPolicyDefaultSearchProviderSuggestURL,
+ Value::CreateStringValue(suggest_url));
+ provider.AddPolicy(kPolicyDefaultSearchProviderIconURL,
+ Value::CreateStringValue(icon_url));
+ provider.AddPolicy(kPolicyDefaultSearchProviderEncodings,
+ Value::CreateStringValue(encodings));
+
+ ConfigurationPolicyPrefStore store(&provider);
+
+ EXPECT_EQ(PrefStore::READ_NO_VALUE,
+ store.GetValue(prefs::kDefaultSearchProviderSearchURL, NULL));
+ EXPECT_EQ(PrefStore::READ_NO_VALUE,
+ store.GetValue(prefs::kDefaultSearchProviderName, NULL));
+ EXPECT_EQ(PrefStore::READ_NO_VALUE,
+ store.GetValue(prefs::kDefaultSearchProviderKeyword, NULL));
+ EXPECT_EQ(PrefStore::READ_NO_VALUE,
+ store.GetValue(prefs::kDefaultSearchProviderSuggestURL, NULL));
+ EXPECT_EQ(PrefStore::READ_NO_VALUE,
+ store.GetValue(prefs::kDefaultSearchProviderIconURL, NULL));
+ EXPECT_EQ(PrefStore::READ_NO_VALUE,
+ store.GetValue(prefs::kDefaultSearchProviderEncodings, NULL));
}
// Checks that if the default search policy is invalid, that no elements of the
@@ -539,103 +495,146 @@ TEST_F(ConfigurationPolicyPrefStoreDefaultSearchTest, Invalid) {
const char* const name = "MyName";
const char* const keyword = "MyKeyword";
const char* const encodings = "UTF-16;UTF-8";
- scoped_ptr<MockConfigurationPolicyProvider> provider(
- new MockConfigurationPolicyProvider());
- provider->AddPolicy(
- kPolicyDefaultSearchProviderEnabled,
- Value::CreateBooleanValue(true));
- provider->AddPolicy(
- kPolicyDefaultSearchProviderSearchURL,
- Value::CreateStringValue(bad_search_url));
- provider->AddPolicy(
- kPolicyDefaultSearchProviderName,
- Value::CreateStringValue(name));
- provider->AddPolicy(
- kPolicyDefaultSearchProviderKeyword,
- Value::CreateStringValue(keyword));
- provider->AddPolicy(
- kPolicyDefaultSearchProviderSuggestURL,
- Value::CreateStringValue(suggest_url));
- provider->AddPolicy(
- kPolicyDefaultSearchProviderIconURL,
- Value::CreateStringValue(icon_url));
- provider->AddPolicy(
- kPolicyDefaultSearchProviderEncodings,
- Value::CreateStringValue(encodings));
-
- ConfigurationPolicyPrefStore store(provider.get());
- EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
- const DictionaryValue* const prefs = store.prefs();
-
- std::string string_result;
- EXPECT_FALSE(prefs->GetString(prefs::kDefaultSearchProviderEnabled,
- &string_result));
- EXPECT_FALSE(prefs->GetString(prefs::kDefaultSearchProviderSearchURL,
- &string_result));
- EXPECT_FALSE(prefs->GetString(prefs::kDefaultSearchProviderName,
- &string_result));
- EXPECT_FALSE(prefs->GetString(prefs::kDefaultSearchProviderKeyword,
- &string_result));
- EXPECT_FALSE(prefs->GetString(prefs::kDefaultSearchProviderSuggestURL,
- &string_result));
- EXPECT_FALSE(prefs->GetString(prefs::kDefaultSearchProviderIconURL,
- &string_result));
- EXPECT_FALSE(prefs->GetString(prefs::kDefaultSearchProviderEncodings,
- &string_result));
+ MockConfigurationPolicyProvider provider;
+ provider.AddPolicy(kPolicyDefaultSearchProviderEnabled,
+ Value::CreateBooleanValue(true));
+ provider.AddPolicy(kPolicyDefaultSearchProviderSearchURL,
+ Value::CreateStringValue(bad_search_url));
+ provider.AddPolicy(kPolicyDefaultSearchProviderName,
+ Value::CreateStringValue(name));
+ provider.AddPolicy(kPolicyDefaultSearchProviderKeyword,
+ Value::CreateStringValue(keyword));
+ provider.AddPolicy(kPolicyDefaultSearchProviderSuggestURL,
+ Value::CreateStringValue(suggest_url));
+ provider.AddPolicy(kPolicyDefaultSearchProviderIconURL,
+ Value::CreateStringValue(icon_url));
+ provider.AddPolicy(kPolicyDefaultSearchProviderEncodings,
+ Value::CreateStringValue(encodings));
+
+ ConfigurationPolicyPrefStore store(&provider);
+
+ EXPECT_EQ(PrefStore::READ_NO_VALUE,
+ store.GetValue(prefs::kDefaultSearchProviderSearchURL, NULL));
+ EXPECT_EQ(PrefStore::READ_NO_VALUE,
+ store.GetValue(prefs::kDefaultSearchProviderName, NULL));
+ EXPECT_EQ(PrefStore::READ_NO_VALUE,
+ store.GetValue(prefs::kDefaultSearchProviderKeyword, NULL));
+ EXPECT_EQ(PrefStore::READ_NO_VALUE,
+ store.GetValue(prefs::kDefaultSearchProviderSuggestURL, NULL));
+ EXPECT_EQ(PrefStore::READ_NO_VALUE,
+ store.GetValue(prefs::kDefaultSearchProviderIconURL, NULL));
+ EXPECT_EQ(PrefStore::READ_NO_VALUE,
+ store.GetValue(prefs::kDefaultSearchProviderEncodings, NULL));
}
// Test cases for the Sync policy setting.
-class ConfigurationPolicyPrefStoreSyncTest : public testing::Test {
+class ConfigurationPolicyPrefStoreSyncTest
+ : public ConfigurationPolicyPrefStoreTestBase<testing::Test> {
};
TEST_F(ConfigurationPolicyPrefStoreSyncTest, Default) {
- ConfigurationPolicyPrefStore store(NULL);
- bool result = false;
- EXPECT_FALSE(store.prefs()->GetBoolean(prefs::kSyncManaged, &result));
+ EXPECT_EQ(PrefStore::READ_NO_VALUE,
+ store_.GetValue(prefs::kSyncManaged, NULL));
}
TEST_F(ConfigurationPolicyPrefStoreSyncTest, Enabled) {
- ConfigurationPolicyPrefStore store(NULL);
- store.Apply(kPolicySyncDisabled, Value::CreateBooleanValue(false));
+ provider_.AddPolicy(kPolicySyncDisabled, Value::CreateBooleanValue(false));
+ store_.OnUpdatePolicy();
// Enabling Sync should not set the pref.
- bool result = false;
- EXPECT_FALSE(store.prefs()->GetBoolean(prefs::kSyncManaged, &result));
+ EXPECT_EQ(PrefStore::READ_NO_VALUE,
+ store_.GetValue(prefs::kSyncManaged, NULL));
}
TEST_F(ConfigurationPolicyPrefStoreSyncTest, Disabled) {
- ConfigurationPolicyPrefStore store(NULL);
- store.Apply(kPolicySyncDisabled, Value::CreateBooleanValue(true));
+ provider_.AddPolicy(kPolicySyncDisabled, Value::CreateBooleanValue(true));
+ store_.OnUpdatePolicy();
// Sync should be flagged as managed.
- bool result = false;
- EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kSyncManaged, &result));
- EXPECT_TRUE(result);
+ Value* value = NULL;
+ EXPECT_EQ(PrefStore::READ_OK, store_.GetValue(prefs::kSyncManaged, &value));
+ ASSERT_TRUE(value != NULL);
+ EXPECT_TRUE(FundamentalValue(true).Equals(value));
}
// Test cases for the AutoFill policy setting.
-class ConfigurationPolicyPrefStoreAutoFillTest : public testing::Test {
+class ConfigurationPolicyPrefStoreAutoFillTest
+ : public ConfigurationPolicyPrefStoreTestBase<testing::Test> {
};
TEST_F(ConfigurationPolicyPrefStoreAutoFillTest, Default) {
- ConfigurationPolicyPrefStore store(NULL);
- bool result = false;
- EXPECT_FALSE(store.prefs()->GetBoolean(prefs::kAutoFillEnabled, &result));
+ EXPECT_EQ(PrefStore::READ_NO_VALUE,
+ store_.GetValue(prefs::kSyncManaged, NULL));
}
TEST_F(ConfigurationPolicyPrefStoreAutoFillTest, Enabled) {
- ConfigurationPolicyPrefStore store(NULL);
- store.Apply(kPolicyAutoFillEnabled, Value::CreateBooleanValue(true));
+ provider_.AddPolicy(kPolicyAutoFillEnabled, Value::CreateBooleanValue(true));
+ store_.OnUpdatePolicy();
// Enabling AutoFill should not set the pref.
- bool result = false;
- EXPECT_FALSE(store.prefs()->GetBoolean(prefs::kAutoFillEnabled, &result));
+ EXPECT_EQ(PrefStore::READ_NO_VALUE,
+ store_.GetValue(prefs::kSyncManaged, NULL));
}
TEST_F(ConfigurationPolicyPrefStoreAutoFillTest, Disabled) {
- ConfigurationPolicyPrefStore store(NULL);
- store.Apply(kPolicyAutoFillEnabled, Value::CreateBooleanValue(false));
+ provider_.AddPolicy(kPolicyAutoFillEnabled, Value::CreateBooleanValue(false));
+ store_.OnUpdatePolicy();
// Disabling AutoFill should switch the pref to managed.
- bool result = true;
- EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kAutoFillEnabled, &result));
- EXPECT_FALSE(result);
+ Value* value = NULL;
+ EXPECT_EQ(PrefStore::READ_OK,
+ store_.GetValue(prefs::kAutoFillEnabled, &value));
+ EXPECT_TRUE(FundamentalValue(false).Equals(value));
+}
+
+// Exercises the policy refresh mechanism.
+class ConfigurationPolicyPrefStoreRefreshTest
+ : public ConfigurationPolicyPrefStoreTestBase<testing::Test> {
+ protected:
+ virtual void SetUp() {
+ store_.AddObserver(&observer_);
+ }
+
+ virtual void TearDown() {
+ store_.RemoveObserver(&observer_);
+ }
+
+ PrefStoreObserverMock observer_;
+};
+
+TEST_F(ConfigurationPolicyPrefStoreRefreshTest, Refresh) {
+ Value* value = NULL;
+ EXPECT_EQ(PrefStore::READ_NO_VALUE,
+ store_.GetValue(prefs::kHomePage, NULL));
+
+ EXPECT_CALL(observer_, OnPrefValueChanged(prefs::kHomePage)).Times(1);
+ provider_.AddPolicy(kPolicyHomePage,
+ Value::CreateStringValue("http://www.chromium.org"));
+ store_.OnUpdatePolicy();
+ Mock::VerifyAndClearExpectations(&observer_);
+ EXPECT_EQ(PrefStore::READ_OK,
+ store_.GetValue(prefs::kHomePage, &value));
+ EXPECT_TRUE(StringValue("http://www.chromium.org").Equals(value));
+
+ EXPECT_CALL(observer_, OnPrefValueChanged(_)).Times(0);
+ store_.OnUpdatePolicy();
+ Mock::VerifyAndClearExpectations(&observer_);
+
+ EXPECT_CALL(observer_, OnPrefValueChanged(prefs::kHomePage)).Times(1);
+ provider_.RemovePolicy(kPolicyHomePage);
+ store_.OnUpdatePolicy();
+ Mock::VerifyAndClearExpectations(&observer_);
+ EXPECT_EQ(PrefStore::READ_NO_VALUE,
+ store_.GetValue(prefs::kHomePage, NULL));
+}
+
+TEST_F(ConfigurationPolicyPrefStoreRefreshTest, Initialization) {
+ EXPECT_FALSE(store_.IsInitializationComplete());
+
+ EXPECT_CALL(observer_, OnInitializationCompleted()).Times(1);
+
+ provider_.SetInitializationComplete(true);
+ EXPECT_FALSE(store_.IsInitializationComplete());
+
+ store_.OnUpdatePolicy();
+ Mock::VerifyAndClearExpectations(&observer_);
+ EXPECT_TRUE(store_.IsInitializationComplete());
}
} // namespace policy
diff --git a/chrome/browser/policy/configuration_policy_provider.cc b/chrome/browser/policy/configuration_policy_provider.cc
index ce7106f..2aee046 100644
--- a/chrome/browser/policy/configuration_policy_provider.cc
+++ b/chrome/browser/policy/configuration_policy_provider.cc
@@ -4,11 +4,45 @@
#include "chrome/browser/policy/configuration_policy_provider.h"
+#include <algorithm>
+
#include "base/values.h"
-#include "chrome/common/notification_service.h"
namespace policy {
+ConfigurationPolicyObserverRegistrar::ConfigurationPolicyObserverRegistrar() {}
+
+ConfigurationPolicyObserverRegistrar::~ConfigurationPolicyObserverRegistrar() {
+ RemoveAll();
+}
+
+void ConfigurationPolicyObserverRegistrar::Init(
+ ConfigurationPolicyProvider* provider) {
+ provider_ = provider;
+}
+
+void ConfigurationPolicyObserverRegistrar::AddObserver(
+ ConfigurationPolicyProvider::Observer* observer) {
+ observers_.push_back(observer);
+ provider_->AddObserver(observer);
+}
+
+void ConfigurationPolicyObserverRegistrar::RemoveObserver(
+ ConfigurationPolicyProvider::Observer* observer) {
+ std::remove(observers_.begin(), observers_.end(), observer);
+ provider_->RemoveObserver(observer);
+}
+
+void ConfigurationPolicyObserverRegistrar::RemoveAll() {
+ for (std::vector<ConfigurationPolicyProvider::Observer*>::iterator it =
+ observers_.begin(); it != observers_.end(); ++it) {
+ provider_->RemoveObserver(*it);
+ }
+ observers_.clear();
+}
+
+// Class ConfigurationPolicyProvider.
+
ConfigurationPolicyProvider::ConfigurationPolicyProvider(
const PolicyDefinitionList* policy_list)
: policy_definition_list_(policy_list) {
@@ -16,15 +50,8 @@ ConfigurationPolicyProvider::ConfigurationPolicyProvider(
ConfigurationPolicyProvider::~ConfigurationPolicyProvider() {}
-void ConfigurationPolicyProvider::NotifyStoreOfPolicyChange() {
- NotificationService::current()->Notify(
- NotificationType::POLICY_CHANGED,
- Source<ConfigurationPolicyProvider>(this),
- NotificationService::NoDetails());
-}
-
void ConfigurationPolicyProvider::DecodePolicyValueTree(
- DictionaryValue* policies,
+ const DictionaryValue* policies,
ConfigurationPolicyStoreInterface* store) {
const PolicyDefinitionList* policy_list(policy_definition_list());
for (const PolicyDefinitionList::Entry* i = policy_list->begin;
diff --git a/chrome/browser/policy/configuration_policy_provider.h b/chrome/browser/policy/configuration_policy_provider.h
index e3989b9..5639235 100644
--- a/chrome/browser/policy/configuration_policy_provider.h
+++ b/chrome/browser/policy/configuration_policy_provider.h
@@ -21,6 +21,12 @@ namespace policy {
// etc.) should implement a subclass of this class.
class ConfigurationPolicyProvider {
public:
+ class Observer {
+ public:
+ virtual ~Observer() {}
+ virtual void OnUpdatePolicy() = 0;
+ };
+
// Used for static arrays of policy values that is used to initialize an
// instance of the ConfigurationPolicyProvider.
struct PolicyDefinitionList {
@@ -38,29 +44,35 @@ class ConfigurationPolicyProvider {
virtual ~ConfigurationPolicyProvider();
- // Must be implemented by provider subclasses to specify the
- // provider-specific policy decisions. The preference service
- // invokes this |Provide| method when it needs a policy
- // provider to specify its policy choices. In |Provide|,
- // the |ConfigurationPolicyProvider| must make calls to the
- // |Apply| method of |store| to apply specific policies.
- // Returns true if the policy could be provided, otherwise false.
+ // Must be implemented by provider subclasses to specify the provider-specific
+ // policy decisions. The preference service invokes this |Provide| method when
+ // it needs a policy provider to specify its policy choices. In |Provide|, the
+ // |ConfigurationPolicyProvider| must make calls to the |Apply| method of
+ // |store| to apply specific policies. Returns true if the policy could be
+ // provided, otherwise false.
virtual bool Provide(ConfigurationPolicyStoreInterface* store) = 0;
- // Called by the subclass provider at any time to indicate that the currently
- // applied policy is not longer current. A policy refresh will be initiated as
- // soon as possible.
- virtual void NotifyStoreOfPolicyChange();
+ // Check whether this provider has completed initialization. This is used to
+ // detect whether initialization is done in case providers implementations
+ // need to do asynchronous operations for initialization.
+ virtual bool IsInitializationComplete() const { return true; }
+ protected:
// Decodes the value tree and writes the configuration to the given |store|.
- void DecodePolicyValueTree(DictionaryValue* policies,
+ void DecodePolicyValueTree(const DictionaryValue* policies,
ConfigurationPolicyStoreInterface* store);
- protected:
+
const PolicyDefinitionList* policy_definition_list() const {
return policy_definition_list_;
}
private:
+ friend class ConfigurationPolicyObserverRegistrar;
+
+ virtual void AddObserver(ConfigurationPolicyProvider::Observer* observer) = 0;
+ virtual void RemoveObserver(
+ ConfigurationPolicyProvider::Observer* observer) = 0;
+
// Contains the default mapping from policy values to the actual names.
const ConfigurationPolicyProvider::PolicyDefinitionList*
policy_definition_list_;
@@ -69,6 +81,22 @@ class ConfigurationPolicyProvider {
DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyProvider);
};
+// Manages observers for a ConfigurationPolicyProvider. Is used to register
+// observers, and automatically removes them upon destruction.
+class ConfigurationPolicyObserverRegistrar {
+ public:
+ ConfigurationPolicyObserverRegistrar();
+ ~ConfigurationPolicyObserverRegistrar();
+ void Init(ConfigurationPolicyProvider* provider);
+ void AddObserver(ConfigurationPolicyProvider::Observer* observer);
+ void RemoveObserver(ConfigurationPolicyProvider::Observer* observer);
+ void RemoveAll();
+ private:
+ ConfigurationPolicyProvider* provider_;
+ std::vector<ConfigurationPolicyProvider::Observer*> observers_;
+ DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyObserverRegistrar);
+};
+
} // namespace policy
#endif // CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_H_
diff --git a/chrome/browser/policy/configuration_policy_provider_delegate_win.cc b/chrome/browser/policy/configuration_policy_provider_delegate_win.cc
new file mode 100644
index 0000000..68947de
--- /dev/null
+++ b/chrome/browser/policy/configuration_policy_provider_delegate_win.cc
@@ -0,0 +1,160 @@
+// 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.
+
+#include "chrome/browser/policy/configuration_policy_provider_delegate_win.h"
+
+#include "base/string_number_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "base/win/registry.h"
+#include "chrome/common/policy_constants.h"
+
+using base::win::RegKey;
+
+namespace {
+
+bool ReadRegistryStringValue(RegKey* key, const string16& name,
+ string16* result) {
+ DWORD value_size = 0;
+ DWORD key_type = 0;
+ scoped_array<uint8> buffer;
+
+ if (!key->ReadValue(name.c_str(), 0, &value_size, &key_type))
+ return false;
+ if (key_type != REG_SZ)
+ return false;
+
+ // According to the Microsoft documentation, the string
+ // buffer may not be explicitly 0-terminated. Allocate a
+ // slightly larger buffer and pre-fill to zeros to guarantee
+ // the 0-termination.
+ buffer.reset(new uint8[value_size + 2]);
+ memset(buffer.get(), 0, value_size + 2);
+ key->ReadValue(name.c_str(), buffer.get(), &value_size, NULL);
+ result->assign(reinterpret_cast<const wchar_t*>(buffer.get()));
+ return true;
+}
+
+} // namespace
+
+namespace policy {
+
+ConfigurationPolicyProviderDelegateWin::ConfigurationPolicyProviderDelegateWin(
+ const ConfigurationPolicyProvider::PolicyDefinitionList*
+ policy_definition_list)
+ : policy_definition_list_(policy_definition_list) {
+}
+
+DictionaryValue* ConfigurationPolicyProviderDelegateWin::Load() {
+ DictionaryValue* result = new DictionaryValue();
+ const ConfigurationPolicyProvider::PolicyDefinitionList::Entry* current;
+ for (current = policy_definition_list_->begin;
+ current != policy_definition_list_->end;
+ ++current) {
+ const string16 name(ASCIIToUTF16(current->name));
+ switch (current->value_type) {
+ case Value::TYPE_STRING: {
+ string16 string_value;
+ if (GetRegistryPolicyString(name, &string_value)) {
+ result->SetString(current->name, string_value);
+ }
+ break;
+ }
+ case Value::TYPE_LIST: {
+ scoped_ptr<ListValue> list_value(new ListValue);
+ if (GetRegistryPolicyStringList(name, list_value.get()))
+ result->Set(current->name, list_value.release());
+ break;
+ }
+ case Value::TYPE_BOOLEAN: {
+ bool bool_value;
+ if (GetRegistryPolicyBoolean(name, &bool_value)) {
+ result->SetBoolean(current->name, bool_value);
+ }
+ break;
+ }
+ case Value::TYPE_INTEGER: {
+ uint32 int_value;
+ if (GetRegistryPolicyInteger(name, &int_value)) {
+ result->SetInteger(current->name, int_value);
+ }
+ break;
+ }
+ default:
+ NOTREACHED();
+ }
+ }
+ return result;
+}
+
+bool ConfigurationPolicyProviderDelegateWin::GetRegistryPolicyString(
+ const string16& name, string16* result) const {
+ string16 path = string16(kRegistrySubKey);
+ RegKey policy_key;
+ // First try the global policy.
+ if (policy_key.Open(HKEY_LOCAL_MACHINE, path.c_str(), KEY_READ)) {
+ if (ReadRegistryStringValue(&policy_key, name, result))
+ return true;
+ policy_key.Close();
+ }
+ // Fall back on user-specific policy.
+ if (!policy_key.Open(HKEY_CURRENT_USER, path.c_str(), KEY_READ))
+ return false;
+ return ReadRegistryStringValue(&policy_key, name, result);
+}
+
+bool ConfigurationPolicyProviderDelegateWin::GetRegistryPolicyStringList(
+ const string16& key, ListValue* result) const {
+ string16 path = string16(kRegistrySubKey);
+ path += ASCIIToUTF16("\\") + key;
+ RegKey policy_key;
+ if (!policy_key.Open(HKEY_LOCAL_MACHINE, path.c_str(), KEY_READ)) {
+ policy_key.Close();
+ // Fall back on user-specific policy.
+ if (!policy_key.Open(HKEY_CURRENT_USER, path.c_str(), KEY_READ))
+ return false;
+ }
+ string16 policy_string;
+ int index = 0;
+ while (ReadRegistryStringValue(&policy_key, base::IntToString16(++index),
+ &policy_string)) {
+ result->Append(Value::CreateStringValue(policy_string));
+ }
+ return true;
+}
+
+bool ConfigurationPolicyProviderDelegateWin::GetRegistryPolicyBoolean(
+ const string16& value_name, bool* result) const {
+ DWORD value;
+ RegKey hkcu_policy_key(HKEY_LOCAL_MACHINE, kRegistrySubKey, KEY_READ);
+ if (hkcu_policy_key.ReadValueDW(value_name.c_str(), &value)) {
+ *result = value != 0;
+ return true;
+ }
+
+ RegKey hklm_policy_key(HKEY_CURRENT_USER, kRegistrySubKey, KEY_READ);
+ if (hklm_policy_key.ReadValueDW(value_name.c_str(), &value)) {
+ *result = value != 0;
+ return true;
+ }
+ return false;
+}
+
+bool ConfigurationPolicyProviderDelegateWin::GetRegistryPolicyInteger(
+ const string16& value_name, uint32* result) const {
+ DWORD value;
+ RegKey hkcu_policy_key(HKEY_LOCAL_MACHINE, kRegistrySubKey, KEY_READ);
+ if (hkcu_policy_key.ReadValueDW(value_name.c_str(), &value)) {
+ *result = value;
+ return true;
+ }
+
+ RegKey hklm_policy_key(HKEY_CURRENT_USER, kRegistrySubKey, KEY_READ);
+ if (hklm_policy_key.ReadValueDW(value_name.c_str(), &value)) {
+ *result = value;
+ return true;
+ }
+ return false;
+}
+
+} // namespace policy
diff --git a/chrome/browser/policy/configuration_policy_provider_delegate_win.h b/chrome/browser/policy/configuration_policy_provider_delegate_win.h
new file mode 100644
index 0000000..63d36b2
--- /dev/null
+++ b/chrome/browser/policy/configuration_policy_provider_delegate_win.h
@@ -0,0 +1,47 @@
+// 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.
+
+#ifndef CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_DELEGATE_WIN_H_
+#define CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_DELEGATE_WIN_H_
+#pragma once
+
+#include "chrome/browser/policy/asynchronous_policy_provider.h"
+
+namespace policy {
+
+class ConfigurationPolicyProviderDelegateWin
+ : public AsynchronousPolicyProvider::Delegate {
+ public:
+ ConfigurationPolicyProviderDelegateWin(
+ const ConfigurationPolicyProvider::PolicyDefinitionList*
+ policy_definition_list);
+ virtual ~ConfigurationPolicyProviderDelegateWin() {}
+
+ // AsynchronousPolicyProvider::Delegate overrides:
+ virtual DictionaryValue* Load();
+
+ private:
+ // Methods to perform type-specific policy lookups in the registry.
+ // HKLM is checked first, then HKCU.
+
+ // Reads a string registry value |name| at the specified |key| and puts the
+ // resulting string in |result|.
+ bool GetRegistryPolicyString(const string16& name, string16* result) const;
+ // Gets a list value contained under |key| one level below the policy root.
+ bool GetRegistryPolicyStringList(const string16& key,
+ ListValue* result) const;
+ bool GetRegistryPolicyBoolean(const string16& value_name,
+ bool* result) const;
+ bool GetRegistryPolicyInteger(const string16& value_name,
+ uint32* result) const;
+
+ const ConfigurationPolicyProvider::PolicyDefinitionList*
+ policy_definition_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyProviderDelegateWin);
+};
+
+} // namespace policy
+
+#endif // CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_DELEGATE_WIN_H_
diff --git a/chrome/browser/policy/configuration_policy_provider_mac.cc b/chrome/browser/policy/configuration_policy_provider_mac.cc
index 62b7436..b8b6011 100644
--- a/chrome/browser/policy/configuration_policy_provider_mac.cc
+++ b/chrome/browser/policy/configuration_policy_provider_mac.cc
@@ -34,15 +34,15 @@ static FilePath GetManagedPolicyPath() {
return path.Append(base::SysCFStringRefToUTF8(bundle_id) + ".plist");
}
-MacPreferencesPolicyLoader::MacPreferencesPolicyLoader(
+MacPreferencesPolicyProviderDelegate::MacPreferencesPolicyProviderDelegate(
MacPreferences* preferences,
const ConfigurationPolicyProvider::PolicyDefinitionList* policy_list)
- : FileBasedPolicyProvider::Delegate(GetManagedPolicyPath()),
+ : FileBasedPolicyProvider::ProviderDelegate(GetManagedPolicyPath()),
policy_list_(policy_list),
preferences_(preferences) {
}
-DictionaryValue* MacPreferencesPolicyLoader::Load() {
+DictionaryValue* MacPreferencesPolicyProviderDelegate::Load() {
preferences_->AppSynchronize(kCFPreferencesCurrentApplication);
DictionaryValue* policy = new DictionaryValue;
@@ -110,7 +110,7 @@ DictionaryValue* MacPreferencesPolicyLoader::Load() {
return policy;
}
-base::Time MacPreferencesPolicyLoader::GetLastModification() {
+base::Time MacPreferencesPolicyProviderDelegate::GetLastModification() {
base::PlatformFileInfo file_info;
if (!file_util::GetFileInfo(config_file_path(), &file_info) ||
file_info.is_directory) {
@@ -123,14 +123,16 @@ base::Time MacPreferencesPolicyLoader::GetLastModification() {
ConfigurationPolicyProviderMac::ConfigurationPolicyProviderMac(
const ConfigurationPolicyProvider::PolicyDefinitionList* policy_list)
: FileBasedPolicyProvider(policy_list,
- new MacPreferencesPolicyLoader(new MacPreferences, policy_list)) {
+ new MacPreferencesPolicyProviderDelegate(new MacPreferences,
+ policy_list)) {
}
ConfigurationPolicyProviderMac::ConfigurationPolicyProviderMac(
const ConfigurationPolicyProvider::PolicyDefinitionList* policy_list,
MacPreferences* preferences)
: FileBasedPolicyProvider(policy_list,
- new MacPreferencesPolicyLoader(preferences, policy_list)) {
+ new MacPreferencesPolicyProviderDelegate(preferences,
+ policy_list)) {
}
} // namespace policy
diff --git a/chrome/browser/policy/configuration_policy_provider_mac.h b/chrome/browser/policy/configuration_policy_provider_mac.h
index d804500..9332e2b 100644
--- a/chrome/browser/policy/configuration_policy_provider_mac.h
+++ b/chrome/browser/policy/configuration_policy_provider_mac.h
@@ -13,11 +13,12 @@
namespace policy {
-// A policy loader implementation that read Mac OS X's managed preferences.
-class MacPreferencesPolicyLoader : public FileBasedPolicyProvider::Delegate {
+// A provider delegate implementation that reads Mac OS X's managed preferences.
+class MacPreferencesPolicyProviderDelegate
+ : public FileBasedPolicyProvider::ProviderDelegate {
public:
// Takes ownership of |preferences|.
- MacPreferencesPolicyLoader(
+ MacPreferencesPolicyProviderDelegate(
MacPreferences* preferences,
const ConfigurationPolicyProvider::PolicyDefinitionList* policy_list);
@@ -35,7 +36,7 @@ class MacPreferencesPolicyLoader : public FileBasedPolicyProvider::Delegate {
scoped_ptr<MacPreferences> preferences_;
- DISALLOW_COPY_AND_ASSIGN(MacPreferencesPolicyLoader);
+ DISALLOW_COPY_AND_ASSIGN(MacPreferencesPolicyProviderDelegate);
};
// An implementation of |ConfigurationPolicyProvider| using the mechanism
diff --git a/chrome/browser/policy/configuration_policy_provider_mac_unittest.cc b/chrome/browser/policy/configuration_policy_provider_mac_unittest.cc
index 5690375..345a3f6 100644
--- a/chrome/browser/policy/configuration_policy_provider_mac_unittest.cc
+++ b/chrome/browser/policy/configuration_policy_provider_mac_unittest.cc
@@ -233,8 +233,8 @@ INSTANTIATE_TEST_CASE_P(
kPolicyDefaultSearchProviderEncodings,
key::kDefaultSearchProviderEncodings),
PolicyTestParams::ForIntegerPolicy(
- kPolicyProxyServerMode,
- key::kProxyServerMode),
+ kPolicyProxyMode,
+ key::kProxyMode),
PolicyTestParams::ForStringPolicy(
kPolicyProxyServer,
key::kProxyServer),
diff --git a/chrome/browser/policy/configuration_policy_provider_win.cc b/chrome/browser/policy/configuration_policy_provider_win.cc
index 8f86973..df336d3 100644
--- a/chrome/browser/policy/configuration_policy_provider_win.cc
+++ b/chrome/browser/policy/configuration_policy_provider_win.cc
@@ -4,285 +4,22 @@
#include "chrome/browser/policy/configuration_policy_provider_win.h"
-#include <userenv.h>
-
-#include <algorithm>
-
-#include "base/logging.h"
-#include "base/object_watcher.h"
-#include "base/scoped_ptr.h"
-#include "base/string_number_conversions.h"
-#include "base/string_piece.h"
-#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "base/values.h"
-#include "base/win/registry.h"
-#include "chrome/common/policy_constants.h"
-
-using base::win::RegKey;
+#include "chrome/browser/policy/asynchronous_policy_provider.h"
+#include "chrome/browser/policy/configuration_policy_loader_win.h"
+#include "chrome/browser/policy/configuration_policy_provider_delegate_win.h"
namespace policy {
-namespace {
-
-bool ReadRegistryStringValue(RegKey* key, const string16& name,
- string16* result) {
- DWORD value_size = 0;
- DWORD key_type = 0;
- scoped_array<uint8> buffer;
-
- if (!key->ReadValue(name.c_str(), 0, &value_size, &key_type))
- return false;
- if (key_type != REG_SZ)
- return false;
-
- // According to the Microsoft documentation, the string
- // buffer may not be explicitly 0-terminated. Allocate a
- // slightly larger buffer and pre-fill to zeros to guarantee
- // the 0-termination.
- buffer.reset(new uint8[value_size + 2]);
- memset(buffer.get(), 0, value_size + 2);
- key->ReadValue(name.c_str(), buffer.get(), &value_size, NULL);
- result->assign(reinterpret_cast<const wchar_t*>(buffer.get()));
- return true;
-}
-
-} // namespace
-
// Period at which to run the reload task in case the group policy change
// watchers fail.
const int kReloadIntervalMinutes = 15;
-ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::
- GroupPolicyChangeWatcher(
- base::WeakPtr<ConfigurationPolicyProviderWin> provider,
- int reload_interval_minutes)
- : provider_(provider),
- user_policy_changed_event_(false, false),
- machine_policy_changed_event_(false, false),
- user_policy_watcher_failed_(false),
- machine_policy_watcher_failed_(false),
- reload_interval_minutes_(reload_interval_minutes),
- reload_task_(NULL) {
- if (!RegisterGPNotification(user_policy_changed_event_.handle(), false)) {
- PLOG(WARNING) << "Failed to register user group policy notification";
- user_policy_watcher_failed_ = true;
- }
- if (!RegisterGPNotification(machine_policy_changed_event_.handle(), true)) {
- PLOG(WARNING) << "Failed to register machine group policy notification.";
- machine_policy_watcher_failed_ = true;
- }
-}
-
-ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::
- ~GroupPolicyChangeWatcher() {
- if (MessageLoop::current())
- MessageLoop::current()->RemoveDestructionObserver(this);
- DCHECK(!reload_task_);
-}
-
-void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::Start() {
- MessageLoop::current()->AddDestructionObserver(this);
- SetupWatches();
-}
-
-void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::Stop() {
- user_policy_watcher_.StopWatching();
- machine_policy_watcher_.StopWatching();
- if (reload_task_) {
- reload_task_->Cancel();
- reload_task_ = NULL;
- }
-}
-
-void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::SetupWatches() {
- if (reload_task_) {
- reload_task_->Cancel();
- reload_task_ = NULL;
- }
-
- if (!user_policy_watcher_failed_) {
- if (!user_policy_watcher_.GetWatchedObject() &&
- !user_policy_watcher_.StartWatching(
- user_policy_changed_event_.handle(), this)) {
- LOG(WARNING) << "Failed to start watch for user policy change event";
- user_policy_watcher_failed_ = true;
- }
- }
- if (!machine_policy_watcher_failed_) {
- if (!machine_policy_watcher_.GetWatchedObject() &&
- !machine_policy_watcher_.StartWatching(
- machine_policy_changed_event_.handle(), this)) {
- LOG(WARNING) << "Failed to start watch for machine policy change event";
- machine_policy_watcher_failed_ = true;
- }
- }
-
- if (user_policy_watcher_failed_ || machine_policy_watcher_failed_) {
- reload_task_ =
- NewRunnableMethod(this, &GroupPolicyChangeWatcher::ReloadFromTask);
- int64 delay =
- base::TimeDelta::FromMinutes(reload_interval_minutes_).InMilliseconds();
- MessageLoop::current()->PostDelayedTask(FROM_HERE, reload_task_, delay);
- }
-}
-
-void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::Reload() {
- if (provider_.get())
- provider_->NotifyStoreOfPolicyChange();
- SetupWatches();
-}
-
-void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::
- ReloadFromTask() {
- // Make sure to not call Cancel() on the task, since it might hold the last
- // reference that keeps this object alive.
- reload_task_ = NULL;
- Reload();
-}
-
-void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::
- OnObjectSignaled(HANDLE object) {
- DCHECK(object == user_policy_changed_event_.handle() ||
- object == machine_policy_changed_event_.handle())
- << "unexpected object signaled policy reload, obj = "
- << std::showbase << std::hex << object;
- Reload();
-}
-
-void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::
- WillDestroyCurrentMessageLoop() {
- reload_task_ = NULL;
- MessageLoop::current()->RemoveDestructionObserver(this);
-}
-
ConfigurationPolicyProviderWin::ConfigurationPolicyProviderWin(
const PolicyDefinitionList* policy_list)
- : ConfigurationPolicyProvider(policy_list) {
- watcher_ = new GroupPolicyChangeWatcher(this->AsWeakPtr(),
- kReloadIntervalMinutes);
- watcher_->Start();
-}
-
-ConfigurationPolicyProviderWin::~ConfigurationPolicyProviderWin() {
- watcher_->Stop();
-}
-
-bool ConfigurationPolicyProviderWin::GetRegistryPolicyString(
- const string16& name, string16* result) const {
- string16 path = string16(kRegistrySubKey);
- RegKey policy_key;
- // First try the global policy.
- if (policy_key.Open(HKEY_LOCAL_MACHINE, path.c_str(), KEY_READ)) {
- if (ReadRegistryStringValue(&policy_key, name, result))
- return true;
- policy_key.Close();
- }
- // Fall back on user-specific policy.
- if (!policy_key.Open(HKEY_CURRENT_USER, path.c_str(), KEY_READ))
- return false;
- return ReadRegistryStringValue(&policy_key, name, result);
-}
-
-bool ConfigurationPolicyProviderWin::GetRegistryPolicyStringList(
- const string16& key, ListValue* result) const {
- string16 path = string16(kRegistrySubKey);
- path += ASCIIToUTF16("\\") + key;
- RegKey policy_key;
- if (!policy_key.Open(HKEY_LOCAL_MACHINE, path.c_str(), KEY_READ)) {
- policy_key.Close();
- // Fall back on user-specific policy.
- if (!policy_key.Open(HKEY_CURRENT_USER, path.c_str(), KEY_READ))
- return false;
- }
- string16 policy_string;
- int index = 0;
- while (ReadRegistryStringValue(&policy_key, base::IntToString16(++index),
- &policy_string)) {
- result->Append(Value::CreateStringValue(policy_string));
- }
- return true;
-}
-
-bool ConfigurationPolicyProviderWin::GetRegistryPolicyBoolean(
- const string16& value_name, bool* result) const {
- DWORD value;
- RegKey hkcu_policy_key(HKEY_LOCAL_MACHINE, kRegistrySubKey, KEY_READ);
- if (hkcu_policy_key.ReadValueDW(value_name.c_str(), &value)) {
- *result = value != 0;
- return true;
- }
-
- RegKey hklm_policy_key(HKEY_CURRENT_USER, kRegistrySubKey, KEY_READ);
- if (hklm_policy_key.ReadValueDW(value_name.c_str(), &value)) {
- *result = value != 0;
- return true;
- }
- return false;
-}
-
-bool ConfigurationPolicyProviderWin::GetRegistryPolicyInteger(
- const string16& value_name, uint32* result) const {
- DWORD value;
- RegKey hkcu_policy_key(HKEY_LOCAL_MACHINE, kRegistrySubKey, KEY_READ);
- if (hkcu_policy_key.ReadValueDW(value_name.c_str(), &value)) {
- *result = value;
- return true;
- }
-
- RegKey hklm_policy_key(HKEY_CURRENT_USER, kRegistrySubKey, KEY_READ);
- if (hklm_policy_key.ReadValueDW(value_name.c_str(), &value)) {
- *result = value;
- return true;
- }
- return false;
-}
-
-bool ConfigurationPolicyProviderWin::Provide(
- ConfigurationPolicyStoreInterface* store) {
- const PolicyDefinitionList* policy_list(policy_definition_list());
- for (const PolicyDefinitionList::Entry* current = policy_list->begin;
- current != policy_list->end; ++current) {
- std::wstring name = UTF8ToWide(current->name);
- switch (current->value_type) {
- case Value::TYPE_STRING: {
- std::wstring string_value;
- if (GetRegistryPolicyString(name.c_str(), &string_value)) {
- store->Apply(current->policy_type,
- Value::CreateStringValue(string_value));
- }
- break;
- }
- case Value::TYPE_LIST: {
- scoped_ptr<ListValue> list_value(new ListValue);
- if (GetRegistryPolicyStringList(name.c_str(), list_value.get()))
- store->Apply(current->policy_type, list_value.release());
- break;
- }
- case Value::TYPE_BOOLEAN: {
- bool bool_value;
- if (GetRegistryPolicyBoolean(name.c_str(), &bool_value)) {
- store->Apply(current->policy_type,
- Value::CreateBooleanValue(bool_value));
- }
- break;
- }
- case Value::TYPE_INTEGER: {
- uint32 int_value;
- if (GetRegistryPolicyInteger(name.c_str(), &int_value)) {
- store->Apply(current->policy_type,
- Value::CreateIntegerValue(int_value));
- }
- break;
- }
- default:
- NOTREACHED();
- return false;
- }
- }
-
- return true;
-}
+ : AsynchronousPolicyProvider(
+ policy_list,
+ new ConfigurationPolicyLoaderWin(
+ new ConfigurationPolicyProviderDelegateWin(policy_list),
+ kReloadIntervalMinutes)) {}
} // namespace policy
diff --git a/chrome/browser/policy/configuration_policy_provider_win.h b/chrome/browser/policy/configuration_policy_provider_win.h
index c2d5509..31e4a2b 100644
--- a/chrome/browser/policy/configuration_policy_provider_win.h
+++ b/chrome/browser/policy/configuration_policy_provider_win.h
@@ -6,19 +6,7 @@
#define CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_WIN_H_
#pragma once
-#include "base/object_watcher.h"
-#include "base/ref_counted.h"
-#include "base/scoped_ptr.h"
-#include "base/waitable_event.h"
-#include "base/weak_ptr.h"
-#include "chrome/browser/policy/configuration_policy_store_interface.h"
-#include "chrome/browser/policy/configuration_policy_provider.h"
-
-namespace base {
-namespace win {
-class RegKey;
-} // namespace win
-} // namespace base
+#include "chrome/browser/policy/asynchronous_policy_provider.h"
namespace policy {
@@ -28,89 +16,14 @@ namespace policy {
// On a managed machine in a domain, this portion of the registry is
// periodically updated by the Windows Group Policy machinery to contain
// the latest version of the policy set by administrators.
-class ConfigurationPolicyProviderWin
- : public ConfigurationPolicyProvider,
- public base::SupportsWeakPtr<ConfigurationPolicyProviderWin> {
+class ConfigurationPolicyProviderWin : public AsynchronousPolicyProvider {
public:
- // Keeps watch on Windows Group Policy notification event to trigger a policy
- // reload when Group Policy changes. This class is reference counted to
- // facilitate timer-based reloads through the message loop. It is not safe to
- // access GroupPolicyChangeWatcher concurrently from multiple threads.
- class GroupPolicyChangeWatcher
- : public base::ObjectWatcher::Delegate,
- public MessageLoop::DestructionObserver,
- public base::RefCountedThreadSafe<GroupPolicyChangeWatcher> {
- public:
- GroupPolicyChangeWatcher(
- base::WeakPtr<ConfigurationPolicyProviderWin> provider,
- int reload_interval_minutes);
- virtual ~GroupPolicyChangeWatcher();
-
- // Start watching.
- void Start();
-
- // Stop any pending watch activity in order to allow for timely shutdown.
- void Stop();
-
- private:
- // Updates the watchers and schedules the reload task if appropriate.
- void SetupWatches();
-
- // Post a reload notification and update the watch machinery.
- void Reload();
-
- // Called for timer-based refresh from the message loop.
- void ReloadFromTask();
-
- // ObjectWatcher::Delegate implementation:
- virtual void OnObjectSignaled(HANDLE object);
-
- // MessageLoop::DestructionObserver implementation:
- virtual void WillDestroyCurrentMessageLoop();
-
- base::WeakPtr<ConfigurationPolicyProviderWin> provider_;
- base::WaitableEvent user_policy_changed_event_;
- base::WaitableEvent machine_policy_changed_event_;
- base::ObjectWatcher user_policy_watcher_;
- base::ObjectWatcher machine_policy_watcher_;
- bool user_policy_watcher_failed_;
- bool machine_policy_watcher_failed_;
-
- // Period to schedule the reload task at.
- int reload_interval_minutes_;
-
- // A reference to a delayed task for timer-based reloading.
- CancelableTask* reload_task_;
- };
-
explicit ConfigurationPolicyProviderWin(
const PolicyDefinitionList* policy_list);
- virtual ~ConfigurationPolicyProviderWin();
-
- // ConfigurationPolicyProvider method overrides:
- virtual bool Provide(ConfigurationPolicyStoreInterface* store);
-
- protected:
- // The sub key path for Chromium's Group Policy information in the
- // Windows registry.
- static const wchar_t kPolicyRegistrySubKey[];
+ virtual ~ConfigurationPolicyProviderWin() {}
private:
- scoped_refptr<GroupPolicyChangeWatcher> watcher_;
-
- // Methods to perform type-specific policy lookups in the registry.
- // HKLM is checked first, then HKCU.
-
- // Reads a string registry value |name| at the specified |key| and puts the
- // resulting string in |result|.
- bool GetRegistryPolicyString(const string16& name, string16* result) const;
- // Gets a list value contained under |key| one level below the policy root.
- bool GetRegistryPolicyStringList(const string16& key,
- ListValue* result) const;
- bool GetRegistryPolicyBoolean(const string16& value_name,
- bool* result) const;
- bool GetRegistryPolicyInteger(const string16& value_name,
- uint32* result) const;
+ DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyProviderWin);
};
} // namespace policy
diff --git a/chrome/browser/policy/configuration_policy_provider_win_unittest.cc b/chrome/browser/policy/configuration_policy_provider_win_unittest.cc
index 39c4dce..beed450 100644
--- a/chrome/browser/policy/configuration_policy_provider_win_unittest.cc
+++ b/chrome/browser/policy/configuration_policy_provider_win_unittest.cc
@@ -3,15 +3,17 @@
// found in the LICENSE file.
#include <gtest/gtest.h>
-
#include <windows.h>
+#include "base/message_loop.h"
#include "base/scoped_ptr.h"
#include "base/stl_util-inl.h"
#include "base/string_number_conversions.h"
#include "base/string_piece.h"
#include "base/utf_string_conversions.h"
#include "base/win/registry.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/policy/asynchronous_policy_loader.h"
#include "chrome/browser/policy/configuration_policy_pref_store.h"
#include "chrome/browser/policy/configuration_policy_provider_win.h"
#include "chrome/browser/policy/mock_configuration_policy_store.h"
@@ -151,13 +153,16 @@ class ConfigurationPolicyProviderWinTest
scoped_ptr<MockConfigurationPolicyStore> store_;
scoped_ptr<ConfigurationPolicyProviderWin> provider_;
- private:
// A message loop must be declared and instantiated for these tests,
// because Windows policy provider create WaitableEvents and
// ObjectWatchers that require the tests to have a MessageLoop associated
// with the thread executing the tests.
MessageLoop loop_;
+ private:
+ BrowserThread ui_thread_;
+ BrowserThread file_thread_;
+
// Keys are created for the lifetime of a test to contain
// the sandboxed HKCU and HKLM hives, respectively.
RegKey temp_hkcu_hive_key_;
@@ -165,7 +170,9 @@ class ConfigurationPolicyProviderWinTest
};
ConfigurationPolicyProviderWinTest::ConfigurationPolicyProviderWinTest()
- : temp_hklm_hive_key_(HKEY_CURRENT_USER, kUnitTestMachineOverrideSubKey,
+ : ui_thread_(BrowserThread::UI, &loop_),
+ file_thread_(BrowserThread::FILE, &loop_),
+ temp_hklm_hive_key_(HKEY_CURRENT_USER, kUnitTestMachineOverrideSubKey,
KEY_READ),
temp_hkcu_hive_key_(HKEY_CURRENT_USER, kUnitTestUserOverrideSubKey,
KEY_READ) {
@@ -194,6 +201,7 @@ void ConfigurationPolicyProviderWinTest::SetUp() {
void ConfigurationPolicyProviderWinTest::TearDown() {
DeactivateOverrides();
DeleteRegistrySandbox();
+ loop_.RunAllPending();
}
void ConfigurationPolicyProviderWinTest::ActivateOverrides() {
@@ -299,6 +307,8 @@ TEST_P(ConfigurationPolicyProviderWinTest, InvalidValue) {
WriteInvalidValue(HKEY_CURRENT_USER,
GetParam().policy_name(),
GetParam().hkcu_value());
+ provider_->loader()->Reload();
+ loop_.RunAllPending();
provider_->Provide(store_.get());
EXPECT_TRUE(store_->policy_map().empty());
}
@@ -307,6 +317,8 @@ TEST_P(ConfigurationPolicyProviderWinTest, HKLM) {
WriteValue(HKEY_LOCAL_MACHINE,
GetParam().policy_name(),
GetParam().hklm_value());
+ provider_->loader()->Reload();
+ loop_.RunAllPending();
provider_->Provide(store_.get());
const Value* value = store_->Get(GetParam().type());
ASSERT_TRUE(value);
@@ -317,6 +329,8 @@ TEST_P(ConfigurationPolicyProviderWinTest, HKCU) {
WriteValue(HKEY_CURRENT_USER,
GetParam().policy_name(),
GetParam().hkcu_value());
+ provider_->loader()->Reload();
+ loop_.RunAllPending();
provider_->Provide(store_.get());
const Value* value = store_->Get(GetParam().type());
ASSERT_TRUE(value);
@@ -330,6 +344,8 @@ TEST_P(ConfigurationPolicyProviderWinTest, HKLMOverHKCU) {
WriteValue(HKEY_CURRENT_USER,
GetParam().policy_name(),
GetParam().hkcu_value());
+ provider_->loader()->Reload();
+ loop_.RunAllPending();
provider_->Provide(store_.get());
const Value* value = store_->Get(GetParam().type());
ASSERT_TRUE(value);
@@ -375,8 +391,8 @@ INSTANTIATE_TEST_CASE_P(
kPolicyDefaultSearchProviderEncodings,
key::kDefaultSearchProviderEncodings),
PolicyTestParams::ForIntegerPolicy(
- kPolicyProxyServerMode,
- key::kProxyServerMode),
+ kPolicyProxyMode,
+ key::kProxyMode),
PolicyTestParams::ForStringPolicy(
kPolicyProxyServer,
key::kProxyServer),
diff --git a/chrome/browser/policy/configuration_policy_store_interface.h b/chrome/browser/policy/configuration_policy_store_interface.h
index b47069e..b6d1f3b 100644
--- a/chrome/browser/policy/configuration_policy_store_interface.h
+++ b/chrome/browser/policy/configuration_policy_store_interface.h
@@ -25,7 +25,7 @@ enum ConfigurationPolicyType {
kPolicyDefaultSearchProviderIconURL,
kPolicyDefaultSearchProviderEncodings,
kPolicyDisableSpdy,
- kPolicyProxyServerMode,
+ kPolicyProxyMode,
kPolicyProxyServer,
kPolicyProxyPacUrl,
kPolicyProxyBypassList,
@@ -56,6 +56,8 @@ enum ConfigurationPolicyType {
kPolicyDefaultJavaScriptSetting,
kPolicyDefaultPluginsSetting,
kPolicyDefaultPopupsSetting,
+ kPolicyDefaultNotificationSetting,
+ kPolicyDefaultGeolocationSetting,
kPolicyExtensionInstallForceList,
kPolicyChromeOsLockOnIdleSuspend,
kPolicyAuthSchemes,
@@ -67,10 +69,24 @@ enum ConfigurationPolicyType {
kPolicyDisable3DAPIs
};
-static const int kPolicyNoProxyServerMode = 0;
-static const int kPolicyAutoDetectProxyMode = 1;
-static const int kPolicyManuallyConfiguredProxyMode = 2;
-static const int kPolicyUseSystemProxyMode = 3;
+
+// Constants for the "Proxy Server Mode" defined in the policies.
+// Note that these diverge from internal presentation defined in
+// ProxyPrefs::ProxyMode for legacy reasons. The following four
+// PolicyProxyModeType types were not very precise and had overlapping use
+// cases.
+enum PolicyProxyModeType {
+ // Disable Proxy, connect directly.
+ kPolicyNoProxyServerMode = 0,
+ // Auto detect proxy or use specific PAC script if given.
+ kPolicyAutoDetectProxyMode = 1,
+ // Use manually configured proxy servers (fixed servers).
+ kPolicyManuallyConfiguredProxyMode = 2,
+ // Use system proxy server.
+ kPolicyUseSystemProxyMode = 3,
+
+ MODE_COUNT
+};
// An abstract super class for policy stores that provides a method that can be
// called by a |ConfigurationPolicyProvider| to specify a policy.
diff --git a/chrome/browser/policy/device_management_policy_cache.cc b/chrome/browser/policy/device_management_policy_cache.cc
index 81af0f4..ab5dd15 100644
--- a/chrome/browser/policy/device_management_policy_cache.cc
+++ b/chrome/browser/policy/device_management_policy_cache.cc
@@ -70,6 +70,8 @@ DeviceManagementPolicyCache::DeviceManagementPolicyCache(
is_device_unmanaged_(false) {
}
+DeviceManagementPolicyCache::~DeviceManagementPolicyCache() {}
+
void DeviceManagementPolicyCache::LoadPolicyFromFile() {
if (!file_util::PathExists(backing_file_path_) || fresh_policy_)
return;
diff --git a/chrome/browser/policy/device_management_policy_cache.h b/chrome/browser/policy/device_management_policy_cache.h
index 86ae845..9c09a07 100644
--- a/chrome/browser/policy/device_management_policy_cache.h
+++ b/chrome/browser/policy/device_management_policy_cache.h
@@ -28,6 +28,7 @@ namespace em = enterprise_management;
class DeviceManagementPolicyCache {
public:
explicit DeviceManagementPolicyCache(const FilePath& backing_file_path);
+ ~DeviceManagementPolicyCache();
// Loads policy information from the backing file. Non-existing or erroneous
// cache files are ignored.
diff --git a/chrome/browser/policy/device_management_policy_provider.cc b/chrome/browser/policy/device_management_policy_provider.cc
index 9fa7f58..1a1f0c2 100644
--- a/chrome/browser/policy/device_management_policy_provider.cc
+++ b/chrome/browser/policy/device_management_policy_provider.cc
@@ -10,10 +10,10 @@
#include "base/rand_util.h"
#include "base/task.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/policy/device_management_backend.h"
#include "chrome/browser/policy/device_management_policy_cache.h"
#include "chrome/browser/policy/proto/device_management_constants.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
@@ -117,10 +117,14 @@ bool DeviceManagementPolicyProvider::Provide(
return true;
}
+bool DeviceManagementPolicyProvider::IsInitializationComplete() const {
+ return !waiting_for_initial_policies_;
+}
+
void DeviceManagementPolicyProvider::HandlePolicyResponse(
const em::DevicePolicyResponse& response) {
if (cache_->SetPolicy(response))
- NotifyStoreOfPolicyChange();
+ NotifyCloudPolicyUpdate();
policy_request_pending_ = false;
// Reset the error delay since policy fetching succeeded this time.
policy_refresh_error_delay_ms_ = kPolicyRefreshErrorDelayInMilliseconds;
@@ -185,6 +189,22 @@ void DeviceManagementPolicyProvider::Shutdown() {
token_fetcher_->Shutdown();
}
+void DeviceManagementPolicyProvider::AddObserver(
+ ConfigurationPolicyProvider::Observer* observer) {
+ observer_list_.AddObserver(observer);
+}
+
+void DeviceManagementPolicyProvider::RemoveObserver(
+ ConfigurationPolicyProvider::Observer* observer) {
+ observer_list_.RemoveObserver(observer);
+}
+
+void DeviceManagementPolicyProvider::NotifyCloudPolicyUpdate() {
+ FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer,
+ observer_list_,
+ OnUpdatePolicy());
+}
+
void DeviceManagementPolicyProvider::Initialize(
DeviceManagementBackend* backend,
Profile* profile,
@@ -314,18 +334,10 @@ void DeviceManagementPolicyProvider::SetDeviceTokenFetcher(
void DeviceManagementPolicyProvider::StopWaitingForInitialPolicies() {
waiting_for_initial_policies_ = false;
- // Send a CLOUD_POLICY_UPDATE notification to unblock ChromeOS logins that
- // are waiting for an initial policy fetch to complete.
+ // Notify observers that initial policy fetch is complete.
NotifyCloudPolicyUpdate();
}
-void DeviceManagementPolicyProvider::NotifyCloudPolicyUpdate() const {
- NotificationService::current()->Notify(
- NotificationType::CLOUD_POLICY_UPDATE,
- Source<DeviceManagementPolicyProvider>(this),
- NotificationService::NoDetails());
-}
-
// static
std::string DeviceManagementPolicyProvider::GetDeviceManagementURL() {
return CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
diff --git a/chrome/browser/policy/device_management_policy_provider.h b/chrome/browser/policy/device_management_policy_provider.h
index c7cdcbc..17edf82 100644
--- a/chrome/browser/policy/device_management_policy_provider.h
+++ b/chrome/browser/policy/device_management_policy_provider.h
@@ -9,6 +9,7 @@
#include <string>
#include "base/file_path.h"
+#include "base/observer_list.h"
#include "base/scoped_ptr.h"
#include "base/time.h"
#include "base/weak_ptr.h"
@@ -41,6 +42,7 @@ class DeviceManagementPolicyProvider
// ConfigurationPolicyProvider implementation:
virtual bool Provide(ConfigurationPolicyStoreInterface* store);
+ virtual bool IsInitializationComplete() const;
// DevicePolicyResponseDelegate implementation:
virtual void HandlePolicyResponse(
@@ -48,17 +50,9 @@ class DeviceManagementPolicyProvider
virtual void OnError(DeviceManagementBackend::ErrorCode code);
// DeviceTokenFetcher::Observer implementation:
- void OnTokenSuccess();
- void OnTokenError();
- void OnNotManaged();
-
- // True if a policy request has been sent to the device management backend
- // server and no response or error has yet been received.
- bool IsPolicyRequestPending() const { return policy_request_pending_; }
-
- bool waiting_for_initial_policies() const {
- return waiting_for_initial_policies_;
- }
+ virtual void OnTokenSuccess();
+ virtual void OnTokenError();
+ virtual void OnNotManaged();
// Tells the provider that the passed in token service reference is about to
// become invalid.
@@ -96,6 +90,10 @@ class DeviceManagementPolicyProvider
// of initialization that requires the IOThread.
void InitializeAfterIOThreadExists();
+ // ConfigurationPolicyProvider overrides:
+ virtual void AddObserver(ConfigurationPolicyProvider::Observer* observer);
+ virtual void RemoveObserver(ConfigurationPolicyProvider::Observer* observer);
+
// Sends a request to the device manager backend to fetch policy if one isn't
// already outstanding.
void SendPolicyRequest();
@@ -112,8 +110,8 @@ class DeviceManagementPolicyProvider
void StopWaitingForInitialPolicies();
- // Send a CLOUD_POLICY_UPDATE notification.
- void NotifyCloudPolicyUpdate() const;
+ // Notify observers about a policy update.
+ void NotifyCloudPolicyUpdate();
// The path of the device token file.
FilePath GetTokenPath();
@@ -135,6 +133,7 @@ class DeviceManagementPolicyProvider
scoped_ptr<DeviceManagementPolicyCache> cache_;
scoped_refptr<DeviceTokenFetcher> token_fetcher_;
DeviceTokenFetcher::ObserverRegistrar registrar_;
+ ObserverList<ConfigurationPolicyProvider::Observer, true> observer_list_;
FilePath storage_dir_;
bool policy_request_pending_;
bool refresh_task_pending_;
diff --git a/chrome/browser/policy/device_management_policy_provider_unittest.cc b/chrome/browser/policy/device_management_policy_provider_unittest.cc
index 3269531..4886f9d 100644
--- a/chrome/browser/policy/device_management_policy_provider_unittest.cc
+++ b/chrome/browser/policy/device_management_policy_provider_unittest.cc
@@ -8,16 +8,18 @@
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/net/gaia/token_service.h"
#include "chrome/browser/policy/configuration_policy_pref_store.h"
+#include "chrome/browser/policy/configuration_policy_provider.h"
#include "chrome/browser/policy/device_management_policy_cache.h"
#include "chrome/browser/policy/device_management_policy_provider.h"
#include "chrome/browser/policy/mock_configuration_policy_store.h"
#include "chrome/browser/policy/mock_device_management_backend.h"
#include "chrome/common/net/gaia/gaia_constants.h"
+#include "chrome/common/notification_observer_mock.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/policy_constants.h"
-#include "chrome/test/mock_notification_observer.h"
#include "chrome/test/testing_device_token_fetcher.h"
#include "chrome/test/testing_profile.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
const char kTestToken[] = "device_policy_provider_test_auth_token";
@@ -28,6 +30,12 @@ using ::testing::_;
using ::testing::InSequence;
using ::testing::Mock;
+class MockConfigurationPolicyObserver
+ : public ConfigurationPolicyProvider::Observer {
+ public:
+ MOCK_METHOD0(OnUpdatePolicy, void());
+};
+
class DeviceManagementPolicyProviderTest : public testing::Test {
public:
DeviceManagementPolicyProviderTest()
@@ -39,7 +47,7 @@ class DeviceManagementPolicyProviderTest : public testing::Test {
virtual void SetUp() {
profile_.reset(new TestingProfile);
CreateNewProvider();
- EXPECT_TRUE(provider_->waiting_for_initial_policies());
+ EXPECT_TRUE(waiting_for_initial_policies());
loop_.RunAllPending();
}
@@ -99,7 +107,7 @@ class DeviceManagementPolicyProviderTest : public testing::Test {
MockDeviceManagementBackendSucceedBooleanPolicy(
key::kDisableSpdy, true));
SimulateSuccessfulLoginAndRunPending();
- EXPECT_FALSE(provider_->waiting_for_initial_policies());
+ EXPECT_FALSE(waiting_for_initial_policies());
EXPECT_CALL(store, Apply(kPolicyDisableSpdy, _)).Times(1);
provider_->Provide(&store);
ASSERT_EQ(1U, store.policy_map().size());
@@ -111,6 +119,10 @@ class DeviceManagementPolicyProviderTest : public testing::Test {
loop_.RunAllPending();
}
+ bool waiting_for_initial_policies() const {
+ return provider_->waiting_for_initial_policies_;
+ }
+
MockDeviceManagementBackend* backend_; // weak
scoped_ptr<DeviceManagementPolicyProvider> provider_;
@@ -136,14 +148,14 @@ TEST_F(DeviceManagementPolicyProviderTest, InitialProvideNoLogin) {
EXPECT_CALL(store, Apply(_, _)).Times(0);
provider_->Provide(&store);
EXPECT_TRUE(store.policy_map().empty());
- EXPECT_TRUE(provider_->waiting_for_initial_policies());
+ EXPECT_TRUE(waiting_for_initial_policies());
}
// If the login is successful and there's no previously-fetched policy, the
// policy should be fetched from the server and should be available the first
// time the Provide method is called.
TEST_F(DeviceManagementPolicyProviderTest, InitialProvideWithLogin) {
- EXPECT_TRUE(provider_->waiting_for_initial_policies());
+ EXPECT_TRUE(waiting_for_initial_policies());
SimulateSuccessfulInitialPolicyFetch();
}
@@ -193,12 +205,11 @@ TEST_F(DeviceManagementPolicyProviderTest, SecondProvide) {
// When policy is successfully fetched from the device management server, it
// should force a policy refresh.
TEST_F(DeviceManagementPolicyProviderTest, FetchTriggersRefresh) {
- MockNotificationObserver observer;
- NotificationRegistrar registrar;
- registrar.Add(&observer,
- NotificationType::POLICY_CHANGED,
- NotificationService::AllSources());
- EXPECT_CALL(observer, Observe(_, _, _)).Times(1);
+ MockConfigurationPolicyObserver observer;
+ ConfigurationPolicyObserverRegistrar registrar;
+ registrar.Init(provider_.get());
+ registrar.AddObserver(&observer);
+ EXPECT_CALL(observer, OnUpdatePolicy()).Times(1);
SimulateSuccessfulInitialPolicyFetch();
}
@@ -305,7 +316,7 @@ TEST_F(DeviceManagementPolicyProviderTest, UnmanagedDevice) {
// (2) On restart, the provider should detect that this is not the first
// login.
CreateNewProvider(1000*1000, 0, 0, 0, 0);
- EXPECT_FALSE(provider_->waiting_for_initial_policies());
+ EXPECT_FALSE(waiting_for_initial_policies());
EXPECT_CALL(*backend_, ProcessRegisterRequest(_, _, _, _)).WillOnce(
MockDeviceManagementBackendSucceedRegister());
EXPECT_CALL(*backend_, ProcessPolicyRequest(_, _, _, _)).WillOnce(
diff --git a/chrome/browser/policy/device_management_service.cc b/chrome/browser/policy/device_management_service.cc
index 05c8789..689c947 100644
--- a/chrome/browser/policy/device_management_service.cc
+++ b/chrome/browser/policy/device_management_service.cc
@@ -14,7 +14,6 @@
#include "net/proxy/proxy_service.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_status.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/io_thread.h"
#include "chrome/browser/net/chrome_net_log.h"
#include "chrome/browser/policy/device_management_backend_impl.h"
diff --git a/chrome/browser/policy/device_management_service_browsertest.cc b/chrome/browser/policy/device_management_service_browsertest.cc
index 6c07e9e..feed86f 100644
--- a/chrome/browser/policy/device_management_service_browsertest.cc
+++ b/chrome/browser/policy/device_management_service_browsertest.cc
@@ -3,11 +3,10 @@
// found in the LICENSE file.
#include "base/message_loop.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/policy/device_management_backend_mock.h"
#include "chrome/browser/policy/device_management_service.h"
#include "chrome/browser/policy/proto/device_management_constants.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/in_process_browser_test.h"
#include "net/test/test_server.h"
@@ -43,22 +42,22 @@ const char kServiceResponseUnregister[] =
#define PROTO_STRING(name) (std::string(name, arraysize(name) - 1))
// Interceptor implementation that returns test data back to the service.
-class CannedResponseInterceptor : public URLRequest::Interceptor {
+class CannedResponseInterceptor : public net::URLRequest::Interceptor {
public:
CannedResponseInterceptor(const GURL& service_url,
const std::string& response_data)
: service_url_(service_url),
response_data_(response_data) {
- URLRequest::RegisterRequestInterceptor(this);
+ net::URLRequest::RegisterRequestInterceptor(this);
}
virtual ~CannedResponseInterceptor() {
- URLRequest::UnregisterRequestInterceptor(this);
+ net::URLRequest::UnregisterRequestInterceptor(this);
}
private:
- // URLRequest::Interceptor overrides.
- virtual URLRequestJob* MaybeIntercept(URLRequest* request) {
+ // net::URLRequest::Interceptor overrides.
+ virtual net::URLRequestJob* MaybeIntercept(net::URLRequest* request) {
if (request->url().GetOrigin() == service_url_.GetOrigin() &&
request->url().path() == service_url_.path()) {
return new URLRequestTestJob(request,
diff --git a/chrome/browser/policy/device_token_fetcher.cc b/chrome/browser/policy/device_token_fetcher.cc
index 8f42544..678c90f 100644
--- a/chrome/browser/policy/device_token_fetcher.cc
+++ b/chrome/browser/policy/device_token_fetcher.cc
@@ -8,11 +8,11 @@
#include "base/path_service.h"
#include "base/singleton.h"
#include "base/string_util.h"
-#include "chrome/browser/guid.h"
#include "chrome/browser/net/gaia/token_service.h"
#include "chrome/browser/policy/proto/device_management_local.pb.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_paths.h"
+#include "chrome/common/guid.h"
#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_service.h"
@@ -57,6 +57,31 @@ namespace policy {
namespace em = enterprise_management;
+DeviceTokenFetcher::ObserverRegistrar::ObserverRegistrar() {}
+
+DeviceTokenFetcher::ObserverRegistrar::~ObserverRegistrar() {
+ RemoveAll();
+}
+
+void DeviceTokenFetcher::ObserverRegistrar::Init(
+ DeviceTokenFetcher* token_fetcher) {
+ token_fetcher_ = token_fetcher;
+}
+
+void DeviceTokenFetcher::ObserverRegistrar::AddObserver(
+ DeviceTokenFetcher::Observer* observer) {
+ observers_.push_back(observer);
+ token_fetcher_->AddObserver(observer);
+}
+
+void DeviceTokenFetcher::ObserverRegistrar::RemoveAll() {
+ for (std::vector<DeviceTokenFetcher::Observer*>::iterator it =
+ observers_.begin(); it != observers_.end(); ++it) {
+ token_fetcher_->RemoveObserver(*it);
+ }
+ observers_.clear();
+}
+
DeviceTokenFetcher::DeviceTokenFetcher(
DeviceManagementBackend* backend,
Profile* profile,
@@ -88,6 +113,8 @@ DeviceTokenFetcher::DeviceTokenFetcher(
#endif
}
+DeviceTokenFetcher::~DeviceTokenFetcher() {}
+
void DeviceTokenFetcher::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
diff --git a/chrome/browser/policy/device_token_fetcher.h b/chrome/browser/policy/device_token_fetcher.h
index 9b991de..c36af5b 100644
--- a/chrome/browser/policy/device_token_fetcher.h
+++ b/chrome/browser/policy/device_token_fetcher.h
@@ -43,23 +43,12 @@ class DeviceTokenFetcher
class ObserverRegistrar {
public:
- void Init(DeviceTokenFetcher* token_fetcher) {
- token_fetcher_ = token_fetcher;
- }
- ~ObserverRegistrar() {
- RemoveAll();
- }
- void AddObserver(DeviceTokenFetcher::Observer* observer) {
- observers_.push_back(observer);
- token_fetcher_->AddObserver(observer);
- }
- void RemoveAll() {
- for (std::vector<DeviceTokenFetcher::Observer*>::iterator it =
- observers_.begin(); it != observers_.end(); ++it) {
- token_fetcher_->RemoveObserver(*it);
- }
- observers_.clear();
- }
+ ObserverRegistrar();
+ ~ObserverRegistrar();
+
+ void Init(DeviceTokenFetcher* token_fetcher);
+ void AddObserver(DeviceTokenFetcher::Observer* observer);
+ void RemoveAll();
private:
DeviceTokenFetcher* token_fetcher_;
std::vector<DeviceTokenFetcher::Observer*> observers_;
@@ -71,7 +60,7 @@ class DeviceTokenFetcher
DeviceTokenFetcher(DeviceManagementBackend* backend,
Profile* profile,
const FilePath& token_path);
- virtual ~DeviceTokenFetcher() {}
+ virtual ~DeviceTokenFetcher();
// NotificationObserver method overrides:
virtual void Observe(NotificationType type,
diff --git a/chrome/browser/policy/device_token_fetcher_unittest.cc b/chrome/browser/policy/device_token_fetcher_unittest.cc
index e8c2c92..f4a7e23 100644
--- a/chrome/browser/policy/device_token_fetcher_unittest.cc
+++ b/chrome/browser/policy/device_token_fetcher_unittest.cc
@@ -12,7 +12,6 @@
#include "chrome/browser/policy/device_token_fetcher.h"
#include "chrome/browser/policy/mock_device_management_backend.h"
#include "chrome/common/net/gaia/gaia_constants.h"
-#include "chrome/common/notification_service.h"
#include "chrome/test/testing_device_token_fetcher.h"
#include "chrome/test/testing_profile.h"
#include "testing/gmock/include/gmock/gmock.h"
diff --git a/chrome/browser/policy/dummy_configuration_policy_provider.cc b/chrome/browser/policy/dummy_configuration_policy_provider.cc
new file mode 100644
index 0000000..9a8f491
--- /dev/null
+++ b/chrome/browser/policy/dummy_configuration_policy_provider.cc
@@ -0,0 +1,22 @@
+// 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.
+
+#include "chrome/browser/policy/dummy_configuration_policy_provider.h"
+
+namespace policy {
+
+DummyConfigurationPolicyProvider::DummyConfigurationPolicyProvider(
+ const PolicyDefinitionList* policy_list)
+ : ConfigurationPolicyProvider(policy_list) {
+}
+
+DummyConfigurationPolicyProvider::~DummyConfigurationPolicyProvider() {
+}
+
+bool DummyConfigurationPolicyProvider::Provide(
+ ConfigurationPolicyStoreInterface* store) {
+ return true;
+}
+
+} // namespace policy
diff --git a/chrome/browser/policy/dummy_configuration_policy_provider.h b/chrome/browser/policy/dummy_configuration_policy_provider.h
index 2c519cb..22ca152 100644
--- a/chrome/browser/policy/dummy_configuration_policy_provider.h
+++ b/chrome/browser/policy/dummy_configuration_policy_provider.h
@@ -6,24 +6,26 @@
#define CHROME_BROWSER_POLICY_DUMMY_CONFIGURATION_POLICY_PROVIDER_H_
#pragma once
-#include "chrome/browser/policy/configuration_policy_store_interface.h"
#include "chrome/browser/policy/configuration_policy_provider.h"
namespace policy {
+class ConfigurationPolicyStoreInterface;
+
class DummyConfigurationPolicyProvider : public ConfigurationPolicyProvider {
public:
explicit DummyConfigurationPolicyProvider(
- const PolicyDefinitionList* policy_list)
- : ConfigurationPolicyProvider(policy_list) {
- }
- virtual ~DummyConfigurationPolicyProvider() {}
+ const PolicyDefinitionList* policy_list);
+ virtual ~DummyConfigurationPolicyProvider();
- virtual bool Provide(ConfigurationPolicyStoreInterface* store) {
- return true;
- }
+ virtual bool Provide(ConfigurationPolicyStoreInterface* store);
private:
+ // ConfigurationPolicyProvider overrides:
+ virtual void AddObserver(ConfigurationPolicyProvider::Observer* observer) {}
+ virtual void RemoveObserver(
+ ConfigurationPolicyProvider::Observer* observer) {}
+
DISALLOW_COPY_AND_ASSIGN(DummyConfigurationPolicyProvider);
};
diff --git a/chrome/browser/policy/file_based_policy_loader.cc b/chrome/browser/policy/file_based_policy_loader.cc
new file mode 100644
index 0000000..cc89d13
--- /dev/null
+++ b/chrome/browser/policy/file_based_policy_loader.cc
@@ -0,0 +1,144 @@
+// 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.
+
+#include "chrome/browser/policy/file_based_policy_loader.h"
+
+namespace {
+
+// Amount of time we wait for the files on disk to settle before trying to load
+// them. This alleviates the problem of reading partially written files and
+// makes it possible to batch quasi-simultaneous changes.
+const int kSettleIntervalSeconds = 5;
+
+// The time interval for rechecking policy. This is our fallback in case the
+// delegate never reports a change to the ReloadObserver.
+const int kReloadIntervalMinutes = 15;
+
+} // namespace
+
+namespace policy {
+
+FileBasedPolicyLoader::FileBasedPolicyLoader(
+ FileBasedPolicyProvider::ProviderDelegate* provider_delegate)
+ : AsynchronousPolicyLoader(provider_delegate,
+ kReloadIntervalMinutes),
+ config_file_path_(provider_delegate->config_file_path()),
+ settle_interval_(base::TimeDelta::FromSeconds(kSettleIntervalSeconds)) {
+}
+
+FileBasedPolicyLoader::~FileBasedPolicyLoader() {}
+
+class FileBasedPolicyWatcherDelegate : public FilePathWatcher::Delegate {
+ public:
+ explicit FileBasedPolicyWatcherDelegate(
+ scoped_refptr<FileBasedPolicyLoader> loader)
+ : loader_(loader) {}
+ virtual ~FileBasedPolicyWatcherDelegate() {}
+
+ // FilePathWatcher::Delegate implementation:
+ void OnFilePathChanged(const FilePath& path) {
+ loader_->OnFilePathChanged(path);
+ }
+
+ void OnError() {
+ loader_->OnError();
+ }
+
+ private:
+ scoped_refptr<FileBasedPolicyLoader> loader_;
+ DISALLOW_COPY_AND_ASSIGN(FileBasedPolicyWatcherDelegate);
+};
+
+void FileBasedPolicyLoader::OnFilePathChanged(
+ const FilePath& path) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ Reload();
+}
+
+void FileBasedPolicyLoader::OnError() {
+ LOG(ERROR) << "FilePathWatcher on " << config_file_path().value()
+ << " failed.";
+}
+
+void FileBasedPolicyLoader::Reload() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+ if (!delegate())
+ return;
+
+ // Check the directory time in order to see whether a reload is required.
+ base::TimeDelta delay;
+ base::Time now = base::Time::Now();
+ if (!IsSafeToReloadPolicy(now, &delay)) {
+ ScheduleReloadTask(delay);
+ return;
+ }
+
+ // Load the policy definitions.
+ scoped_ptr<DictionaryValue> new_policy(delegate()->Load());
+
+ // Check again in case the directory has changed while reading it.
+ if (!IsSafeToReloadPolicy(now, &delay)) {
+ ScheduleReloadTask(delay);
+ return;
+ }
+
+ PostUpdatePolicyTask(new_policy.release());
+
+ ScheduleFallbackReloadTask();
+}
+
+void FileBasedPolicyLoader::InitOnFileThread() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ watcher_.reset(new FilePathWatcher);
+ if (!config_file_path().empty() &&
+ !watcher_->Watch(config_file_path(),
+ new FileBasedPolicyWatcherDelegate(this))) {
+ OnError();
+ }
+
+ // There might have been changes to the directory in the time between
+ // construction of the loader and initialization of the watcher. Call reload
+ // to detect if that is the case.
+ Reload();
+
+ ScheduleFallbackReloadTask();
+}
+
+void FileBasedPolicyLoader::StopOnFileThread() {
+ watcher_.reset();
+ AsynchronousPolicyLoader::StopOnFileThread();
+}
+
+bool FileBasedPolicyLoader::IsSafeToReloadPolicy(
+ const base::Time& now,
+ base::TimeDelta* delay) {
+ DCHECK(delay);
+
+ // A null modification time indicates there's no data.
+ FileBasedPolicyProvider::ProviderDelegate* provider_delegate =
+ static_cast<FileBasedPolicyProvider::ProviderDelegate*>(delegate());
+ base::Time last_modification(provider_delegate->GetLastModification());
+ if (last_modification.is_null())
+ return true;
+
+ // If there was a change since the last recorded modification, wait some more.
+ if (last_modification != last_modification_file_) {
+ last_modification_file_ = last_modification;
+ last_modification_clock_ = now;
+ *delay = settle_interval_;
+ return false;
+ }
+
+ // Check whether the settle interval has elapsed.
+ base::TimeDelta age = now - last_modification_clock_;
+ if (age < settle_interval_) {
+ *delay = settle_interval_ - age;
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace policy
diff --git a/chrome/browser/policy/file_based_policy_loader.h b/chrome/browser/policy/file_based_policy_loader.h
new file mode 100644
index 0000000..97c3198
--- /dev/null
+++ b/chrome/browser/policy/file_based_policy_loader.h
@@ -0,0 +1,78 @@
+// 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.
+
+#ifndef CHROME_BROWSER_POLICY_FILE_BASED_POLICY_LOADER_H_
+#define CHROME_BROWSER_POLICY_FILE_BASED_POLICY_LOADER_H_
+#pragma once
+
+#include "chrome/browser/file_path_watcher/file_path_watcher.h"
+#include "chrome/browser/policy/asynchronous_policy_loader.h"
+#include "chrome/browser/policy/file_based_policy_provider.h"
+
+namespace policy {
+
+// A customized asynchronous policy loader that handles loading policy from a
+// file using a FilePathWatcher. The loader creates a fallback task to load
+// policy periodically in case the watcher fails and retries policy loads when
+// the watched file is in flux.
+class FileBasedPolicyLoader : public AsynchronousPolicyLoader {
+ public:
+ FileBasedPolicyLoader(
+ FileBasedPolicyProvider::ProviderDelegate* provider_delegate);
+
+ // AsynchronousPolicyLoader overrides:
+ virtual void Reload();
+
+ void OnFilePathChanged(const FilePath& path);
+ void OnError();
+
+ protected:
+ // FileBasedPolicyLoader objects should only be deleted by
+ // RefCountedThreadSafe.
+ friend class base::RefCountedThreadSafe<AsynchronousPolicyLoader>;
+ virtual ~FileBasedPolicyLoader();
+
+ const FilePath& config_file_path() { return config_file_path_; }
+
+ // AsynchronousPolicyLoader overrides:
+
+ // Creates the file path watcher and configures it to watch
+ // |config_file_path_|. Must be called on the file thread.
+ virtual void InitOnFileThread();
+ virtual void StopOnFileThread();
+
+ private:
+ // Checks whether policy information is safe to read. If not, returns false
+ // and then delays until it is considered safe to reload in |delay|.
+ // Must be called on the file thread.
+ bool IsSafeToReloadPolicy(const base::Time& now, base::TimeDelta* delay);
+
+ // The path at which we look for configuration files.
+ const FilePath config_file_path_;
+
+ // Managed with a scoped_ptr rather than being declared as an inline member to
+ // decouple the watcher's life cycle from the loader's. This decoupling makes
+ // it possible to destroy the watcher before the loader's destructor is called
+ // (e.g. during Stop), since |watcher_| internally holds a reference to the
+ // loader and keeps it alive.
+ scoped_ptr<FilePathWatcher> watcher_;
+
+ // Settle interval.
+ const base::TimeDelta settle_interval_;
+
+ // Records last known modification timestamp of |config_file_path_|.
+ base::Time last_modification_file_;
+
+ // The wall clock time at which the last modification timestamp was
+ // recorded. It's better to not assume the file notification time and the
+ // wall clock times come from the same source, just in case there is some
+ // non-local filesystem involved.
+ base::Time last_modification_clock_;
+
+ DISALLOW_COPY_AND_ASSIGN(FileBasedPolicyLoader);
+};
+
+} // namespace policy
+
+#endif // CHROME_BROWSER_POLICY_FILE_BASED_POLICY_LOADER_H_
diff --git a/chrome/browser/policy/file_based_policy_provider.cc b/chrome/browser/policy/file_based_policy_provider.cc
index 578277d..488f19f 100644
--- a/chrome/browser/policy/file_based_policy_provider.cc
+++ b/chrome/browser/policy/file_based_policy_provider.cc
@@ -4,241 +4,21 @@
#include "chrome/browser/policy/file_based_policy_provider.h"
-#include <set>
-
-#include "base/logging.h"
-#include "base/message_loop.h"
-#include "base/task.h"
-#include "base/utf_string_conversions.h"
-#include "base/values.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/common/json_value_serializer.h"
+#include "chrome/browser/policy/file_based_policy_loader.h"
namespace policy {
-// Amount of time we wait for the files on disk to settle before trying to load
-// it. This alleviates the problem of reading partially written files and allows
-// to batch quasi-simultaneous changes.
-const int kSettleIntervalSeconds = 5;
-
-// The time interval for rechecking policy. This is our fallback in case the
-// file path watch fails or doesn't report a change.
-const int kReloadIntervalMinutes = 15;
-
-// FileBasedPolicyProvider implementation:
+FileBasedPolicyProvider::ProviderDelegate::ProviderDelegate(
+ const FilePath& config_file_path)
+ : config_file_path_(config_file_path) {}
-FileBasedPolicyProvider::Delegate::~Delegate() {
-}
-
-FileBasedPolicyProvider::Delegate::Delegate(const FilePath& config_file_path)
- : config_file_path_(config_file_path) {
-}
+FileBasedPolicyProvider::ProviderDelegate::~ProviderDelegate() {}
FileBasedPolicyProvider::FileBasedPolicyProvider(
const ConfigurationPolicyProvider::PolicyDefinitionList* policy_list,
- FileBasedPolicyProvider::Delegate* delegate)
- : ConfigurationPolicyProvider(policy_list) {
- loader_ = new FileBasedPolicyLoader(AsWeakPtr(),
- delegate,
- kSettleIntervalSeconds,
- kReloadIntervalMinutes);
- watcher_ = new FileBasedPolicyWatcher;
- watcher_->Init(loader_.get());
-}
-
-FileBasedPolicyProvider::~FileBasedPolicyProvider() {
- loader_->Stop();
-}
-
-bool FileBasedPolicyProvider::Provide(
- ConfigurationPolicyStoreInterface* store) {
- scoped_ptr<DictionaryValue> policy(loader_->GetPolicy());
- DCHECK(policy.get());
- DecodePolicyValueTree(policy.get(), store);
- return true;
-}
-
-// FileBasedPolicyLoader implementation:
-
-FileBasedPolicyLoader::FileBasedPolicyLoader(
- base::WeakPtr<ConfigurationPolicyProvider> provider,
- FileBasedPolicyProvider::Delegate* delegate,
- int settle_interval_seconds,
- int reload_interval_minutes)
- : delegate_(delegate),
- provider_(provider),
- origin_loop_(MessageLoop::current()),
- reload_task_(NULL),
- settle_interval_seconds_(settle_interval_seconds),
- reload_interval_minutes_(reload_interval_minutes) {
- // Force an initial load, so GetPolicy() works.
- policy_.reset(delegate_->Load());
- DCHECK(policy_.get());
-}
-
-void FileBasedPolicyLoader::Stop() {
- if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(this, &FileBasedPolicyLoader::Stop));
- return;
- }
-
- if (reload_task_) {
- reload_task_->Cancel();
- reload_task_ = NULL;
- }
-}
-
-void FileBasedPolicyLoader::Reload() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- // Check the directory time in order to see whether a reload is required.
- base::TimeDelta delay;
- base::Time now = base::Time::Now();
- if (!IsSafeToReloadPolicy(now, &delay)) {
- ScheduleReloadTask(delay);
- return;
- }
-
- // Load the policy definitions.
- scoped_ptr<DictionaryValue> new_policy(delegate_->Load());
-
- // Check again in case the directory has changed while reading it.
- if (!IsSafeToReloadPolicy(now, &delay)) {
- ScheduleReloadTask(delay);
- return;
- }
-
- // Replace policy definition.
- bool changed = false;
- {
- AutoLock lock(lock_);
- changed = !policy_->Equals(new_policy.get());
- policy_.reset(new_policy.release());
- }
-
- // There's a change, report it!
- if (changed) {
- VLOG(0) << "Policy reload from " << config_file_path().value()
- << " succeeded.";
- origin_loop_->PostTask(FROM_HERE,
- NewRunnableMethod(this, &FileBasedPolicyLoader::NotifyPolicyChanged));
- }
-
- // As a safeguard in case the file watcher fails, schedule a reload task
- // that'll make us recheck after a reasonable interval.
- ScheduleReloadTask(base::TimeDelta::FromMinutes(reload_interval_minutes_));
-}
-
-DictionaryValue* FileBasedPolicyLoader::GetPolicy() {
- AutoLock lock(lock_);
- return static_cast<DictionaryValue*>(policy_->DeepCopy());
-}
-
-void FileBasedPolicyLoader::OnFilePathChanged(const FilePath& path) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- Reload();
-}
-
-void FileBasedPolicyLoader::OnError() {
- LOG(ERROR) << "FilePathWatcher on " << config_file_path().value()
- << " failed.";
-}
-
-FileBasedPolicyLoader::~FileBasedPolicyLoader() {
-}
-
-bool FileBasedPolicyLoader::IsSafeToReloadPolicy(const base::Time& now,
- base::TimeDelta* delay) {
- DCHECK(delay);
-
- // A null modification time indicates there's no data.
- base::Time last_modification(delegate_->GetLastModification());
- if (last_modification.is_null())
- return true;
-
- // If there was a change since the last recorded modification, wait some more.
- base::TimeDelta settleInterval(
- base::TimeDelta::FromSeconds(settle_interval_seconds_));
- if (last_modification != last_modification_file_) {
- last_modification_file_ = last_modification;
- last_modification_clock_ = now;
- *delay = settleInterval;
- return false;
- }
-
- // Check whether the settle interval has elapsed.
- base::TimeDelta age = now - last_modification_clock_;
- if (age < settleInterval) {
- *delay = settleInterval - age;
- return false;
- }
-
- return true;
-}
-
-void FileBasedPolicyLoader::ScheduleReloadTask(const base::TimeDelta& delay) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- if (reload_task_)
- reload_task_->Cancel();
-
- reload_task_ =
- NewRunnableMethod(this, &FileBasedPolicyLoader::ReloadFromTask);
- BrowserThread::PostDelayedTask(BrowserThread::FILE, FROM_HERE, reload_task_,
- delay.InMilliseconds());
-}
-
-void FileBasedPolicyLoader::NotifyPolicyChanged() {
- DCHECK_EQ(origin_loop_, MessageLoop::current());
- if (provider_)
- provider_->NotifyStoreOfPolicyChange();
-}
-
-void FileBasedPolicyLoader::ReloadFromTask() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- // Drop the reference to the reload task, since the task might be the only
- // referer that keeps us alive, so we should not Cancel() it.
- reload_task_ = NULL;
-
- Reload();
-}
-
-// FileBasedPolicyWatcher implementation:
-
-FileBasedPolicyWatcher::FileBasedPolicyWatcher() {
-}
-
-void FileBasedPolicyWatcher::Init(FileBasedPolicyLoader* loader) {
- // Initialization can happen early when the file thread is not yet available.
- // So post a task to ourselves on the UI thread which will run after threading
- // is up and schedule watch initialization on the file thread.
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(this,
- &FileBasedPolicyWatcher::InitWatcher,
- scoped_refptr<FileBasedPolicyLoader>(loader)));
-}
-
-FileBasedPolicyWatcher::~FileBasedPolicyWatcher() {
-}
-
-void FileBasedPolicyWatcher::InitWatcher(
- const scoped_refptr<FileBasedPolicyLoader>& loader) {
- if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(this, &FileBasedPolicyWatcher::InitWatcher, loader));
- return;
- }
-
- if (!loader->config_file_path().empty() &&
- !watcher_.Watch(loader->config_file_path(), loader.get()))
- loader->OnError();
-
- // There might have been changes to the directory in the time between
- // construction of the loader and initialization of the watcher. Call reload
- // to detect if that is the case.
- loader->Reload();
-}
+ FileBasedPolicyProvider::ProviderDelegate* delegate)
+ : AsynchronousPolicyProvider(
+ policy_list,
+ new FileBasedPolicyLoader(delegate)) {}
} // namespace policy
diff --git a/chrome/browser/policy/file_based_policy_provider.h b/chrome/browser/policy/file_based_policy_provider.h
index a4e989d..c94e1d4 100644
--- a/chrome/browser/policy/file_based_policy_provider.h
+++ b/chrome/browser/policy/file_based_policy_provider.h
@@ -6,39 +6,25 @@
#define CHROME_BROWSER_POLICY_FILE_BASED_POLICY_PROVIDER_H_
#pragma once
-#include "base/basictypes.h"
#include "base/file_path.h"
-#include "base/lock.h"
-#include "base/ref_counted.h"
-#include "base/scoped_ptr.h"
#include "base/time.h"
-#include "base/weak_ptr.h"
-#include "chrome/browser/file_path_watcher.h"
-#include "chrome/browser/policy/configuration_policy_provider.h"
-
-class CancelableTask;
-class DictionaryValue;
-class MessageLoop;
+#include "chrome/browser/policy/asynchronous_policy_provider.h"
namespace policy {
-class FileBasedPolicyLoader;
-class FileBasedPolicyWatcher;
-
// File based policy provider that coordinates watching and reloading policy
// information from the configuration path. Actual logic for loading policy
// information is handled by a delegate passed at construction time.
-class FileBasedPolicyProvider
- : public ConfigurationPolicyProvider,
- public base::SupportsWeakPtr<FileBasedPolicyProvider> {
+class FileBasedPolicyProvider : public AsynchronousPolicyProvider {
public:
+
// Delegate interface for actual policy loading from the system.
- class Delegate {
+ class ProviderDelegate : public AsynchronousPolicyProvider::Delegate {
public:
- virtual ~Delegate();
+ explicit ProviderDelegate(const FilePath& config_file_path);
+ virtual ~ProviderDelegate();
- // Loads the policy information. Ownership of the return value is
- // transferred to the caller.
+ // AsynchronousPolicyProvider::Delegate implementation:
virtual DictionaryValue* Load() = 0;
// Gets the last modification timestamp for the policy information from the
@@ -48,152 +34,21 @@ class FileBasedPolicyProvider
const FilePath& config_file_path() { return config_file_path_; }
- protected:
- explicit Delegate(const FilePath& config_file_path);
-
private:
- // The path at which we look for configuration files.
const FilePath config_file_path_;
- DISALLOW_COPY_AND_ASSIGN(Delegate);
+ DISALLOW_COPY_AND_ASSIGN(ProviderDelegate);
};
// Assumes ownership of |delegate|.
FileBasedPolicyProvider(const PolicyDefinitionList* policy_list,
- Delegate* delegate);
- virtual ~FileBasedPolicyProvider();
-
- // ConfigurationPolicyProvider implementation.
- virtual bool Provide(ConfigurationPolicyStoreInterface* store);
+ ProviderDelegate* delegate);
+ virtual ~FileBasedPolicyProvider() {}
private:
- // Watches for changes to the configuration directory.
- scoped_refptr<FileBasedPolicyWatcher> watcher_;
-
- // The loader object we use internally.
- scoped_refptr<FileBasedPolicyLoader> loader_;
-
DISALLOW_COPY_AND_ASSIGN(FileBasedPolicyProvider);
};
-// FilePathWatcher delegate implementation that handles change notifications for
-// the configuration file or directory. It keeps the authorative version of the
-// currently effective policy dictionary and updates it as appropriate. The
-// actual loading logic is handled by a delegate.
-class FileBasedPolicyLoader : public FilePathWatcher::Delegate {
- public:
- // Creates a new loader that'll load its data from |config_file_path|.
- // Assumes ownership of |delegate|, which provides the actual loading logic.
- // The parameters |settle_interval_seconds| and |reload_interval_minutes|
- // specify the time to wait before reading the file contents after a change
- // and the period for checking |config_file_path| for changes, respectively.
- FileBasedPolicyLoader(base::WeakPtr<ConfigurationPolicyProvider> provider,
- FileBasedPolicyProvider::Delegate* delegate,
- int settle_interval_seconds,
- int reload_interval_minutes);
-
- // Stops any pending reload tasks.
- void Stop();
-
- // Reloads the policies and sends out a notification, if appropriate. Must be
- // called on the file thread.
- void Reload();
-
- // Gets the current dictionary value object. Ownership of the returned value
- // is transferred to the caller.
- DictionaryValue* GetPolicy();
-
- const FilePath& config_file_path() { return delegate_->config_file_path(); }
-
- // FilePathWatcher::Delegate implementation:
- void OnFilePathChanged(const FilePath& path);
- void OnError();
-
- private:
- // FileBasedPolicyLoader objects should only be deleted by
- // RefCountedThreadSafe.
- friend class base::RefCountedThreadSafe<FileBasedPolicyLoader>;
- virtual ~FileBasedPolicyLoader();
-
- // Checks whether reading policy information is safe to do. If not, returns
- // false and the delay until it is considered safe to reload in |delay|.
- bool IsSafeToReloadPolicy(const base::Time& now, base::TimeDelta* delay);
-
- // Schedules a reload task to run when |delay| expires. Must be called on the
- // file thread.
- void ScheduleReloadTask(const base::TimeDelta& delay);
-
- // Notifies the policy provider to send out a policy changed notification.
- // Must be called on |origin_loop_|.
- void NotifyPolicyChanged();
-
- // Invoked from the reload task on the file thread.
- void ReloadFromTask();
-
- // The delegate.
- scoped_ptr<FileBasedPolicyProvider::Delegate> delegate_;
-
- // The provider this loader is associated with. Access only on the thread that
- // called the constructor. See |origin_loop_| below.
- base::WeakPtr<ConfigurationPolicyProvider> provider_;
-
- // The message loop on which this object was constructed and |provider_|
- // received on. Recorded so we can call back into the non thread safe provider
- // to fire the notification.
- MessageLoop* origin_loop_;
-
- // Records last known modification timestamp of |config_file_path_|.
- base::Time last_modification_file_;
-
- // The wall clock time at which the last modification timestamp was recorded.
- // It's better to not assume the file notification time and the wall clock
- // times come from the same source, just in case there is some non-local
- // filesystem involved.
- base::Time last_modification_clock_;
-
- // Protects |policy_|.
- Lock lock_;
-
- // The current policy definition.
- scoped_ptr<DictionaryValue> policy_;
-
- // The reload task. Access only on the file thread. Holds a reference to the
- // currently posted task, so we can cancel and repost it if necessary.
- CancelableTask* reload_task_;
-
- // Settle and reload intervals.
- const int settle_interval_seconds_;
- const int reload_interval_minutes_;
-
- DISALLOW_COPY_AND_ASSIGN(FileBasedPolicyLoader);
-};
-
-// Wraps a FilePathWatcher for the configuration path and takes care of
-// initializing the watcher object on the file thread.
-class FileBasedPolicyWatcher
- : public base::RefCountedThreadSafe<FileBasedPolicyWatcher> {
- public:
- FileBasedPolicyWatcher();
-
- // Runs initialization. This is in a separate method since we need to post a
- // task (which cannot be done from the constructor).
- void Init(FileBasedPolicyLoader* loader);
-
- private:
- // FileBasedPolicyWatcher objects should only be deleted by
- // RefCountedThreadSafe.
- friend class base::RefCountedThreadSafe<FileBasedPolicyWatcher>;
- virtual ~FileBasedPolicyWatcher();
-
- // Actually sets up the watch with the FilePathWatcher code.
- void InitWatcher(const scoped_refptr<FileBasedPolicyLoader>& loader);
-
- // Wrapped watcher that takes care of the actual watching.
- FilePathWatcher watcher_;
-
- DISALLOW_COPY_AND_ASSIGN(FileBasedPolicyWatcher);
-};
-
} // namespace policy
#endif // CHROME_BROWSER_POLICY_FILE_BASED_POLICY_PROVIDER_H_
diff --git a/chrome/browser/policy/file_based_policy_provider_unittest.cc b/chrome/browser/policy/file_based_policy_provider_unittest.cc
index c78c586..1bb2185 100644
--- a/chrome/browser/policy/file_based_policy_provider_unittest.cc
+++ b/chrome/browser/policy/file_based_policy_provider_unittest.cc
@@ -2,130 +2,80 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "chrome/browser/policy/asynchronous_policy_loader.h"
+#include "chrome/browser/policy/asynchronous_policy_test_base.h"
#include "chrome/browser/policy/configuration_policy_pref_store.h"
+#include "chrome/browser/policy/configuration_policy_store_interface.h"
#include "chrome/browser/policy/file_based_policy_provider.h"
+#include "chrome/common/policy_constants.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-using testing::Mock;
+using testing::_;
+using testing::InSequence;
+using testing::Return;
namespace policy {
-// Shorter reload intervals for testing FileBasedPolicyLoader.
-const int kSettleIntervalSecondsForTesting = 0;
-const int kReloadIntervalMinutesForTesting = 1;
-
-// A delegate for testing that can feed arbitrary information to the loader.
-class TestDelegate : public FileBasedPolicyProvider::Delegate {
- public:
- TestDelegate()
- : FileBasedPolicyProvider::Delegate(FilePath(FILE_PATH_LITERAL("fake"))) {
- }
-
- // FileBasedPolicyProvider::Delegate implementation:
- virtual DictionaryValue* Load() {
- return static_cast<DictionaryValue*>(dict_.DeepCopy());
- }
-
- virtual base::Time GetLastModification() {
- return last_modification_;
- }
-
- DictionaryValue* dict() { return &dict_; }
- void set_last_modification(const base::Time& last_modification) {
- last_modification_ = last_modification;
- }
-
- private:
- DictionaryValue dict_;
- base::Time last_modification_;
-};
-
-// A mock provider that allows us to capture reload notifications.
-class MockPolicyProvider : public ConfigurationPolicyProvider,
- public base::SupportsWeakPtr<MockPolicyProvider> {
+class FileBasedPolicyProviderDelegateMock
+ : public FileBasedPolicyProvider::ProviderDelegate {
public:
- explicit MockPolicyProvider()
- : ConfigurationPolicyProvider(
- ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList()) {
- }
-
- virtual bool Provide(ConfigurationPolicyStoreInterface* store) {
- return true;
- }
-
- MOCK_METHOD0(NotifyStoreOfPolicyChange, void());
+ FileBasedPolicyProviderDelegateMock()
+ : FileBasedPolicyProvider::ProviderDelegate(FilePath()) {}
+ MOCK_METHOD0(Load, DictionaryValue*());
+ MOCK_METHOD0(GetLastModification, base::Time());
};
-class FileBasedPolicyLoaderTest : public testing::Test {
- protected:
- FileBasedPolicyLoaderTest()
- : ui_thread_(BrowserThread::UI, &loop_),
- file_thread_(BrowserThread::FILE, &loop_) {}
-
- virtual void TearDown() {
- loop_.RunAllPending();
- }
-
- MessageLoop loop_;
-
- private:
- BrowserThread ui_thread_;
- BrowserThread file_thread_;
-};
-
-TEST_F(FileBasedPolicyLoaderTest, BasicLoad) {
- TestDelegate* test_delegate = new TestDelegate;
- test_delegate->dict()->SetString("HomepageLocation", "http://www.google.com");
-
- scoped_refptr<FileBasedPolicyLoader> loader(
- new FileBasedPolicyLoader(base::WeakPtr<FileBasedPolicyProvider>(),
- test_delegate,
- kSettleIntervalSecondsForTesting,
- kReloadIntervalMinutesForTesting));
- scoped_ptr<DictionaryValue> policy(loader->GetPolicy());
- EXPECT_TRUE(policy.get());
- EXPECT_EQ(1U, policy->size());
-
- std::string str_value;
- EXPECT_TRUE(policy->GetString("HomepageLocation", &str_value));
- EXPECT_EQ("http://www.google.com", str_value);
-
- loader->Stop();
+TEST_F(AsynchronousPolicyTestBase, ProviderInit) {
+ base::Time last_modified;
+ FileBasedPolicyProviderDelegateMock* provider_delegate =
+ new FileBasedPolicyProviderDelegateMock();
+ EXPECT_CALL(*provider_delegate, GetLastModification()).WillRepeatedly(
+ Return(last_modified));
+ InSequence s;
+ EXPECT_CALL(*provider_delegate, Load()).WillOnce(Return(
+ new DictionaryValue));
+ DictionaryValue* policies = new DictionaryValue();
+ policies->SetBoolean(policy::key::kSyncDisabled, true);
+ // A second call to Load gets triggered during the provider's construction
+ // when the file watcher is initialized, since this file may have changed
+ // between the initial load and creating watcher.
+ EXPECT_CALL(*provider_delegate, Load()).WillOnce(Return(policies));
+ FileBasedPolicyProvider provider(
+ ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(),
+ provider_delegate);
+ loop_.RunAllPending();
+ EXPECT_CALL(*store_, Apply(policy::kPolicySyncDisabled, _)).Times(1);
+ provider.Provide(store_.get());
}
-TEST_F(FileBasedPolicyLoaderTest, TestRefresh) {
- MockPolicyProvider provider;
- TestDelegate* test_delegate = new TestDelegate;
-
- scoped_refptr<FileBasedPolicyLoader> loader(
- new FileBasedPolicyLoader(provider.AsWeakPtr(),
- test_delegate,
- kSettleIntervalSecondsForTesting,
- kReloadIntervalMinutesForTesting));
- scoped_ptr<DictionaryValue> policy(loader->GetPolicy());
- EXPECT_TRUE(policy.get());
- EXPECT_EQ(0U, policy->size());
-
- test_delegate->dict()->SetString("HomepageLocation", "http://www.google.com");
-
- EXPECT_CALL(provider, NotifyStoreOfPolicyChange()).Times(1);
- loader->OnFilePathChanged(FilePath(FILE_PATH_LITERAL("fake")));
-
- // Run the loop. The refresh should be handled immediately since the settle
- // interval has been disabled.
+TEST_F(AsynchronousPolicyTestBase, ProviderRefresh) {
+ base::Time last_modified;
+ FileBasedPolicyProviderDelegateMock* provider_delegate =
+ new FileBasedPolicyProviderDelegateMock();
+ EXPECT_CALL(*provider_delegate, GetLastModification()).WillRepeatedly(
+ Return(last_modified));
+ InSequence s;
+ EXPECT_CALL(*provider_delegate, Load()).WillOnce(Return(
+ new DictionaryValue));
+ FileBasedPolicyProvider file_based_provider(
+ ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(),
+ provider_delegate);
+ // A second call to Load gets triggered during the provider's construction
+ // when the file watcher is initialized, since this file may have changed
+ // between the initial load and creating watcher.
+ EXPECT_CALL(*provider_delegate, Load()).WillOnce(Return(
+ new DictionaryValue));
loop_.RunAllPending();
- Mock::VerifyAndClearExpectations(&provider);
-
- policy.reset(loader->GetPolicy());
- EXPECT_TRUE(policy.get());
- EXPECT_EQ(1U, policy->size());
-
- std::string str_value;
- EXPECT_TRUE(policy->GetString("HomepageLocation", &str_value));
- EXPECT_EQ("http://www.google.com", str_value);
-
- loader->Stop();
+ // A third and final call to Load is made by the explicit Reload. This
+ // should be the one that provides the current policy.
+ DictionaryValue* policies = new DictionaryValue();
+ policies->SetBoolean(policy::key::kSyncDisabled, true);
+ EXPECT_CALL(*provider_delegate, Load()).WillOnce(Return(policies));
+ file_based_provider.loader()->Reload();
+ loop_.RunAllPending();
+ EXPECT_CALL(*store_, Apply(policy::kPolicySyncDisabled, _)).Times(1);
+ file_based_provider.Provide(store_.get());
}
} // namespace policy
diff --git a/chrome/browser/policy/managed_prefs_banner_base.cc b/chrome/browser/policy/managed_prefs_banner_base.cc
index 1351da4..7c20a09 100644
--- a/chrome/browser/policy/managed_prefs_banner_base.cc
+++ b/chrome/browser/policy/managed_prefs_banner_base.cc
@@ -84,8 +84,7 @@ void ManagedPrefsBannerBase::Init(PrefService* local_state,
#if defined(GOOGLE_CHROME_BUILD)
AddLocalStatePref(prefs::kMetricsReportingEnabled);
#endif
- AddUserPref(prefs::kNoProxyServer);
- AddUserPref(prefs::kProxyAutoDetect);
+ AddUserPref(prefs::kProxyMode);
AddUserPref(prefs::kProxyServer);
AddUserPref(prefs::kProxyPacUrl);
AddUserPref(prefs::kProxyBypassList);
diff --git a/chrome/browser/policy/managed_prefs_banner_base.h b/chrome/browser/policy/managed_prefs_banner_base.h
index e087cb1..40b798e 100644
--- a/chrome/browser/policy/managed_prefs_banner_base.h
+++ b/chrome/browser/policy/managed_prefs_banner_base.h
@@ -8,7 +8,7 @@
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
-#include "chrome/browser/options_window.h"
+#include "chrome/browser/ui/options/options_window.h"
#include "chrome/common/notification_observer.h"
class PrefService;
diff --git a/chrome/browser/policy/managed_prefs_banner_base_unittest.cc b/chrome/browser/policy/managed_prefs_banner_base_unittest.cc
index 35425b1..3f2569d 100644
--- a/chrome/browser/policy/managed_prefs_banner_base_unittest.cc
+++ b/chrome/browser/policy/managed_prefs_banner_base_unittest.cc
@@ -3,7 +3,6 @@
// found in the LICENSE file.
#include "chrome/browser/policy/managed_prefs_banner_base.h"
-#include "chrome/browser/prefs/dummy_pref_store.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_pref_service.h"
#include "testing/gmock/include/gmock/gmock.h"
diff --git a/chrome/browser/policy/mock_configuration_policy_provider.cc b/chrome/browser/policy/mock_configuration_policy_provider.cc
index 4f11497..a2566b0 100644
--- a/chrome/browser/policy/mock_configuration_policy_provider.cc
+++ b/chrome/browser/policy/mock_configuration_policy_provider.cc
@@ -4,13 +4,15 @@
#include "chrome/browser/policy/mock_configuration_policy_provider.h"
+#include "base/stl_util-inl.h"
#include "chrome/browser/policy/configuration_policy_pref_store.h"
namespace policy {
MockConfigurationPolicyProvider::MockConfigurationPolicyProvider()
: ConfigurationPolicyProvider(
- ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList()) {
+ ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList()),
+ initialization_complete_(false) {
}
MockConfigurationPolicyProvider::~MockConfigurationPolicyProvider() {
@@ -23,6 +25,20 @@ void MockConfigurationPolicyProvider::AddPolicy(ConfigurationPolicyType policy,
delete value;
}
+void MockConfigurationPolicyProvider::RemovePolicy(
+ ConfigurationPolicyType policy) {
+ const PolicyMap::iterator entry = policy_map_.find(policy);
+ if (entry != policy_map_.end()) {
+ delete entry->second;
+ policy_map_.erase(entry);
+ }
+}
+
+void MockConfigurationPolicyProvider::SetInitializationComplete(
+ bool initialization_complete) {
+ initialization_complete_ = initialization_complete;
+}
+
bool MockConfigurationPolicyProvider::Provide(
ConfigurationPolicyStoreInterface* store) {
for (PolicyMap::const_iterator current = policy_map_.begin();
@@ -32,4 +48,8 @@ bool MockConfigurationPolicyProvider::Provide(
return true;
}
+bool MockConfigurationPolicyProvider::IsInitializationComplete() const {
+ return initialization_complete_;
+}
+
}
diff --git a/chrome/browser/policy/mock_configuration_policy_provider.h b/chrome/browser/policy/mock_configuration_policy_provider.h
index 8ba8a88..5620f81 100644
--- a/chrome/browser/policy/mock_configuration_policy_provider.h
+++ b/chrome/browser/policy/mock_configuration_policy_provider.h
@@ -9,8 +9,8 @@
#include <map>
#include <utility>
-#include "base/stl_util-inl.h"
#include "chrome/browser/policy/configuration_policy_provider.h"
+#include "testing/gmock/include/gmock/gmock.h"
namespace policy {
@@ -22,14 +22,24 @@ class MockConfigurationPolicyProvider : public ConfigurationPolicyProvider {
virtual ~MockConfigurationPolicyProvider();
void AddPolicy(ConfigurationPolicyType policy, Value* value);
+ void RemovePolicy(ConfigurationPolicyType policy);
+
+ void SetInitializationComplete(bool initialization_complete);
// ConfigurationPolicyProvider method overrides.
virtual bool Provide(ConfigurationPolicyStoreInterface* store);
+ virtual bool IsInitializationComplete() const;
private:
+ // ConfigurationPolicyProvider overrides:
+ virtual void AddObserver(ConfigurationPolicyProvider::Observer* observer) {}
+ virtual void RemoveObserver(
+ ConfigurationPolicyProvider::Observer* observer) {}
+
typedef std::map<ConfigurationPolicyType, Value*> PolicyMap;
PolicyMap policy_map_;
+ bool initialization_complete_;
};
} // namespace policy
diff --git a/chrome/browser/policy/profile_policy_context.cc b/chrome/browser/policy/profile_policy_context.cc
index 0882ab4..c4b6e5b 100644
--- a/chrome/browser/policy/profile_policy_context.cc
+++ b/chrome/browser/policy/profile_policy_context.cc
@@ -7,7 +7,7 @@
#include "chrome/browser/policy/device_management_policy_provider.h"
#include "chrome/browser/policy/device_management_service.h"
#include "chrome/browser/policy/profile_policy_context.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"
namespace policy {
diff --git a/chrome/browser/popup_blocker_browsertest.cc b/chrome/browser/popup_blocker_browsertest.cc
index 9a99d7f..890eff4 100644
--- a/chrome/browser/popup_blocker_browsertest.cc
+++ b/chrome/browser/popup_blocker_browsertest.cc
@@ -9,7 +9,7 @@
#include "base/message_loop.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_paths.h"
diff --git a/chrome/browser/possible_url_model.cc b/chrome/browser/possible_url_model.cc
index d84c54f..3d4d662 100644
--- a/chrome/browser/possible_url_model.cc
+++ b/chrome/browser/possible_url_model.cc
@@ -14,7 +14,7 @@
#include "chrome/browser/cancelable_request.h"
#include "chrome/browser/favicon_service.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "gfx/codec/png_codec.h"
#include "grit/app_resources.h"
diff --git a/chrome/browser/ppapi_plugin_process_host.cc b/chrome/browser/ppapi_plugin_process_host.cc
index ba47b86..c90d1f4 100644
--- a/chrome/browser/ppapi_plugin_process_host.cc
+++ b/chrome/browser/ppapi_plugin_process_host.cc
@@ -7,14 +7,13 @@
#include "base/command_line.h"
#include "base/file_path.h"
#include "base/process_util.h"
-#include "chrome/browser/renderer_host/resource_message_filter.h"
+#include "chrome/browser/renderer_host/render_message_filter.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/render_messages.h"
-#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_switches.h"
#include "ppapi/proxy/ppapi_messages.h"
-PpapiPluginProcessHost::PpapiPluginProcessHost(ResourceMessageFilter* filter)
+PpapiPluginProcessHost::PpapiPluginProcessHost(RenderMessageFilter* filter)
: BrowserChildProcessHost(ChildProcessInfo::PPAPI_PLUGIN_PROCESS,
filter->resource_dispatcher_host()),
filter_(filter) {
@@ -29,7 +28,7 @@ void PpapiPluginProcessHost::Init(const FilePath& path,
reply_msg_.reset(reply_msg);
if (!CreateChannel()) {
- ReplyToRenderer(IPC::ChannelHandle());
+ ReplyToRenderer(NULL, IPC::ChannelHandle());
return;
}
@@ -39,7 +38,7 @@ void PpapiPluginProcessHost::Init(const FilePath& path,
FilePath exe_path = ChildProcessHost::GetChildPath(plugin_launcher.empty());
if (exe_path.empty()) {
- ReplyToRenderer(IPC::ChannelHandle());
+ ReplyToRenderer(NULL, IPC::ChannelHandle());
return;
}
@@ -63,42 +62,66 @@ void PpapiPluginProcessHost::Init(const FilePath& path,
cmd_line);
}
-void PpapiPluginProcessHost::OnProcessLaunched() {
+bool PpapiPluginProcessHost::CanShutdown() {
+ return true;
}
-URLRequestContext* PpapiPluginProcessHost::GetRequestContext(
- uint32 request_id,
- const ViewHostMsg_Resource_Request& request_data) {
- return NULL;
+void PpapiPluginProcessHost::OnProcessLaunched() {
}
-void PpapiPluginProcessHost::OnMessageReceived(const IPC::Message& msg) {
+bool PpapiPluginProcessHost::OnMessageReceived(const IPC::Message& msg) {
+ bool handled = true;
IPC_BEGIN_MESSAGE_MAP(PpapiPluginProcessHost, msg)
IPC_MESSAGE_HANDLER(PpapiHostMsg_PluginLoaded, OnPluginLoaded)
- IPC_MESSAGE_UNHANDLED_ERROR();
+ IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
+ DCHECK(handled);
+ return handled;
}
void PpapiPluginProcessHost::OnChannelConnected(int32 peer_pid) {
- PpapiMsg_LoadPlugin* msg = new PpapiMsg_LoadPlugin(plugin_path_,
- filter_->id());
+#if defined(OS_WIN)
+ base::ProcessHandle plugins_renderer_handle = NULL;
+ ::DuplicateHandle(::GetCurrentProcess(), filter_->peer_handle(),
+ GetChildProcessHandle(), &plugins_renderer_handle,
+ 0, FALSE, DUPLICATE_SAME_ACCESS);
+#elif defined(OS_POSIX)
+ base::ProcessHandle plugins_renderer_handle = filter_->peer_handle();
+#endif
+
+ PpapiMsg_LoadPlugin* msg = new PpapiMsg_LoadPlugin(
+ plugins_renderer_handle, plugin_path_, filter_->render_process_id());
if (!Send(msg)) // Just send an empty handle on failure.
- ReplyToRenderer(IPC::ChannelHandle());
+ ReplyToRenderer(NULL, IPC::ChannelHandle());
// This function will result in OnChannelCreated getting called to finish.
}
void PpapiPluginProcessHost::OnChannelError() {
if (reply_msg_.get())
- ReplyToRenderer(IPC::ChannelHandle());
+ ReplyToRenderer(NULL, IPC::ChannelHandle());
}
-void PpapiPluginProcessHost::OnPluginLoaded(const IPC::ChannelHandle& handle) {
- ReplyToRenderer(handle);
+void PpapiPluginProcessHost::OnPluginLoaded(
+ const IPC::ChannelHandle& channel_handle) {
+ base::ProcessHandle plugin_process = GetChildProcessHandle();
+#if defined(OS_WIN)
+ base::ProcessHandle renderers_plugin_handle = NULL;
+ ::DuplicateHandle(::GetCurrentProcess(), plugin_process,
+ filter_->peer_handle(), &renderers_plugin_handle,
+ 0, FALSE, DUPLICATE_SAME_ACCESS);
+#elif defined(OS_POSIX)
+ // Don't need to duplicate anything on POSIX since it's just a PID.
+ base::ProcessHandle renderers_plugin_handle = plugin_process;
+#endif
+ ReplyToRenderer(renderers_plugin_handle, channel_handle);
}
-void PpapiPluginProcessHost::ReplyToRenderer(const IPC::ChannelHandle& handle) {
+void PpapiPluginProcessHost::ReplyToRenderer(
+ base::ProcessHandle plugin_handle,
+ const IPC::ChannelHandle& channel_handle) {
DCHECK(reply_msg_.get());
ViewHostMsg_OpenChannelToPepperPlugin::WriteReplyParams(reply_msg_.get(),
- handle);
+ plugin_handle,
+ channel_handle);
filter_->Send(reply_msg_.release());
}
diff --git a/chrome/browser/ppapi_plugin_process_host.h b/chrome/browser/ppapi_plugin_process_host.h
index 956148c..227cf31 100644
--- a/chrome/browser/ppapi_plugin_process_host.h
+++ b/chrome/browser/ppapi_plugin_process_host.h
@@ -10,28 +10,20 @@
#include "base/file_path.h"
#include "chrome/browser/browser_child_process_host.h"
-class ResourceMessageFilter;
-
-namespace IPC {
-struct ChannelHandle;
-class Message;
-}
+class RenderMessageFilter;
class PpapiPluginProcessHost : public BrowserChildProcessHost {
public:
- explicit PpapiPluginProcessHost(ResourceMessageFilter* filter);
+ explicit PpapiPluginProcessHost(RenderMessageFilter* filter);
virtual ~PpapiPluginProcessHost();
void Init(const FilePath& path, IPC::Message* reply_msg);
private:
- virtual bool CanShutdown() { return true; }
+ virtual bool CanShutdown();
virtual void OnProcessLaunched();
- virtual URLRequestContext* GetRequestContext(
- uint32 request_id,
- const ViewHostMsg_Resource_Request& request_data);
- virtual void OnMessageReceived(const IPC::Message& msg);
+ virtual bool OnMessageReceived(const IPC::Message& msg);
virtual void OnChannelConnected(int32 peer_pid);
virtual void OnChannelError();
@@ -39,9 +31,10 @@ class PpapiPluginProcessHost : public BrowserChildProcessHost {
void OnPluginLoaded(const IPC::ChannelHandle& handle);
// Sends the reply_msg_ to the renderer with the given channel info.
- void ReplyToRenderer(const IPC::ChannelHandle& handle);
+ void ReplyToRenderer(base::ProcessHandle plugin_handle,
+ const IPC::ChannelHandle& channel_handle);
- ResourceMessageFilter* filter_;
+ RenderMessageFilter* filter_;
// Path to the plugin library.
FilePath plugin_path_;
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index ddc149b..1d21c1f 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -11,6 +11,9 @@
#include "chrome/browser/background_page_tracker.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/browser_shutdown.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
+#include "chrome/browser/content_settings/policy_content_settings_provider.h"
+#include "chrome/browser/content_settings/pref_content_settings_provider.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/dom_ui/flags_ui.h"
#include "chrome/browser/dom_ui/new_tab_ui.h"
@@ -23,7 +26,6 @@
#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
#include "chrome/browser/geolocation/geolocation_prefs.h"
#include "chrome/browser/google/google_url_tracker.h"
-#include "chrome/browser/host_content_settings_map.h"
#include "chrome/browser/host_zoom_map.h"
#include "chrome/browser/intranet_redirect_detector.h"
#include "chrome/browser/instant/instant_controller.h"
@@ -36,7 +38,7 @@
#include "chrome/browser/page_info_model.h"
#include "chrome/browser/password_manager/password_manager.h"
#include "chrome/browser/prefs/session_startup_pref.h"
-#include "chrome/browser/profile_impl.h"
+#include "chrome/browser/profiles/profile_impl.h"
#include "chrome/browser/renderer_host/browser_render_process_host.h"
#include "chrome/browser/renderer_host/web_cache_manager.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
@@ -90,7 +92,6 @@ void RegisterLocalState(PrefService* local_state) {
MetricsService::RegisterPrefs(local_state);
SafeBrowsingService::RegisterPrefs(local_state);
browser_shutdown::RegisterPrefs(local_state);
- chrome_browser_net::RegisterPrefs(local_state);
#if defined(TOOLKIT_VIEWS)
BrowserView::RegisterBrowserViewPrefs(local_state);
#endif
@@ -112,7 +113,6 @@ void RegisterLocalState(PrefService* local_state) {
void RegisterUserPrefs(PrefService* user_prefs) {
// User prefs
AutoFillManager::RegisterUserPrefs(user_prefs);
- BackgroundModeManager::RegisterUserPrefs(user_prefs);
SessionStartupPref::RegisterUserPrefs(user_prefs);
Browser::RegisterUserPrefs(user_prefs);
PasswordManager::RegisterUserPrefs(user_prefs);
@@ -128,6 +128,8 @@ void RegisterUserPrefs(PrefService* user_prefs) {
PluginsUI::RegisterUserPrefs(user_prefs);
ProfileImpl::RegisterUserPrefs(user_prefs);
HostContentSettingsMap::RegisterUserPrefs(user_prefs);
+ PolicyContentSettingsProvider::RegisterUserPrefs(user_prefs);
+ PrefContentSettingsProvider::RegisterUserPrefs(user_prefs);
HostZoomMap::RegisterUserPrefs(user_prefs);
DevToolsManager::RegisterUserPrefs(user_prefs);
PinnedTabCodec::RegisterUserPrefs(user_prefs);
diff --git a/chrome/browser/prefs/command_line_pref_store.cc b/chrome/browser/prefs/command_line_pref_store.cc
index cbb7ef7..4a386d6 100644
--- a/chrome/browser/prefs/command_line_pref_store.cc
+++ b/chrome/browser/prefs/command_line_pref_store.cc
@@ -7,6 +7,7 @@
#include "app/app_switches.h"
#include "base/logging.h"
#include "base/values.h"
+#include "chrome/browser/prefs/proxy_prefs.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
@@ -25,8 +26,6 @@ const CommandLinePrefStore::StringSwitchToPreferenceMapEntry
const CommandLinePrefStore::BooleanSwitchToPreferenceMapEntry
CommandLinePrefStore::boolean_switch_map_[] = {
- { switches::kNoProxyServer, prefs::kNoProxyServer, true },
- { switches::kProxyAutoDetect, prefs::kProxyAutoDetect, true },
{ switches::kDisableAuthNegotiateCnameLookup,
prefs::kDisableAuthNegotiateCnameLookup, true },
{ switches::kEnableAuthNegotiatePort, prefs::kEnableAuthNegotiatePort,
@@ -35,24 +34,21 @@ const CommandLinePrefStore::BooleanSwitchToPreferenceMapEntry
};
CommandLinePrefStore::CommandLinePrefStore(const CommandLine* command_line)
- : command_line_(command_line),
- prefs_(new DictionaryValue()) {}
-
-CommandLinePrefStore::~CommandLinePrefStore() {}
-
-PrefStore::PrefReadError CommandLinePrefStore::ReadPrefs() {
+ : command_line_(command_line) {
ApplySimpleSwitches();
+ ApplyProxyMode();
ValidateProxySwitches();
- return PrefStore::PREF_READ_ERROR_NONE;
}
+CommandLinePrefStore::~CommandLinePrefStore() {}
+
void CommandLinePrefStore::ApplySimpleSwitches() {
// Look for each switch we know about and set its preference accordingly.
for (size_t i = 0; i < arraysize(string_switch_map_); ++i) {
if (command_line_->HasSwitch(string_switch_map_[i].switch_name)) {
Value* value = Value::CreateStringValue(command_line_->
GetSwitchValueASCII(string_switch_map_[i].switch_name));
- prefs_->Set(string_switch_map_[i].preference_path, value);
+ SetValue(string_switch_map_[i].preference_path, value);
}
}
@@ -60,7 +56,7 @@ void CommandLinePrefStore::ApplySimpleSwitches() {
if (command_line_->HasSwitch(boolean_switch_map_[i].switch_name)) {
Value* value = Value::CreateBooleanValue(
boolean_switch_map_[i].set_value);
- prefs_->Set(boolean_switch_map_[i].preference_path, value);
+ SetValue(boolean_switch_map_[i].preference_path, value);
}
}
}
@@ -77,3 +73,19 @@ bool CommandLinePrefStore::ValidateProxySwitches() {
}
return true;
}
+
+void CommandLinePrefStore::ApplyProxyMode() {
+ if (command_line_->HasSwitch(switches::kNoProxyServer)) {
+ SetValue(prefs::kProxyMode,
+ Value::CreateIntegerValue(ProxyPrefs::MODE_DIRECT));
+ } else if (command_line_->HasSwitch(switches::kProxyPacUrl)) {
+ SetValue(prefs::kProxyMode,
+ Value::CreateIntegerValue(ProxyPrefs::MODE_PAC_SCRIPT));
+ } else if (command_line_->HasSwitch(switches::kProxyAutoDetect)) {
+ SetValue(prefs::kProxyMode,
+ Value::CreateIntegerValue(ProxyPrefs::MODE_AUTO_DETECT));
+ } else if (command_line_->HasSwitch(switches::kProxyServer)) {
+ SetValue(prefs::kProxyMode,
+ Value::CreateIntegerValue(ProxyPrefs::MODE_FIXED_SERVERS));
+ }
+}
diff --git a/chrome/browser/prefs/command_line_pref_store.h b/chrome/browser/prefs/command_line_pref_store.h
index 2ea29ae..75d8b10 100644
--- a/chrome/browser/prefs/command_line_pref_store.h
+++ b/chrome/browser/prefs/command_line_pref_store.h
@@ -9,21 +9,18 @@
#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/scoped_ptr.h"
-#include "chrome/common/pref_store.h"
+#include "base/values.h"
+#include "chrome/browser/prefs/value_map_pref_store.h"
class DictionaryValue;
// This PrefStore keeps track of preferences set by command-line switches,
// such as proxy settings.
-class CommandLinePrefStore : public PrefStore {
+class CommandLinePrefStore : public ValueMapPrefStore {
public:
explicit CommandLinePrefStore(const CommandLine* command_line);
virtual ~CommandLinePrefStore();
- // PrefStore methods:
- virtual PrefReadError ReadPrefs();
- virtual DictionaryValue* prefs() const { return prefs_.get(); }
-
protected:
// Logs a message and returns false if the proxy switches are
// self-contradictory. Protected so it can be used in unit testing.
@@ -48,11 +45,12 @@ class CommandLinePrefStore : public PrefStore {
// corresponding preferences in this pref store.
void ApplySimpleSwitches();
+ // Determines the proxy mode preference from the given proxy switches.
+ void ApplyProxyMode();
+
// Weak reference.
const CommandLine* command_line_;
- scoped_ptr<DictionaryValue> prefs_;
-
static const StringSwitchToPreferenceMapEntry string_switch_map_[];
DISALLOW_COPY_AND_ASSIGN(CommandLinePrefStore);
diff --git a/chrome/browser/prefs/command_line_pref_store_unittest.cc b/chrome/browser/prefs/command_line_pref_store_unittest.cc
index 064c7e6..1be9c0a 100644
--- a/chrome/browser/prefs/command_line_pref_store_unittest.cc
+++ b/chrome/browser/prefs/command_line_pref_store_unittest.cc
@@ -9,6 +9,7 @@
#include "base/string_util.h"
#include "base/values.h"
#include "chrome/browser/prefs/command_line_pref_store.h"
+#include "chrome/browser/prefs/proxy_prefs.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
@@ -22,6 +23,12 @@ class TestCommandLinePrefStore : public CommandLinePrefStore {
bool ProxySwitchesAreValid() {
return ValidateProxySwitches();
}
+
+ void VerifyIntPref(const std::string& path, int expected_value) {
+ Value* actual = NULL;
+ ASSERT_EQ(PrefStore::READ_OK, GetValue(path, &actual));
+ EXPECT_TRUE(FundamentalValue(expected_value).Equals(actual));
+ }
};
const char unknown_bool[] = "unknown_switch";
@@ -34,10 +41,12 @@ TEST(CommandLinePrefStoreTest, SimpleStringPref) {
CommandLine cl(CommandLine::NO_PROGRAM);
cl.AppendSwitchASCII(switches::kLang, "hi-MOM");
CommandLinePrefStore store(&cl);
- EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
+ Value* actual = NULL;
+ EXPECT_EQ(PrefStore::READ_OK,
+ store.GetValue(prefs::kApplicationLocale, &actual));
std::string result;
- EXPECT_TRUE(store.prefs()->GetString(prefs::kApplicationLocale, &result));
+ EXPECT_TRUE(actual->GetAsString(&result));
EXPECT_EQ("hi-MOM", result);
}
@@ -45,12 +54,9 @@ TEST(CommandLinePrefStoreTest, SimpleStringPref) {
TEST(CommandLinePrefStoreTest, SimpleBooleanPref) {
CommandLine cl(CommandLine::NO_PROGRAM);
cl.AppendSwitch(switches::kNoProxyServer);
- CommandLinePrefStore store(&cl);
- EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
+ TestCommandLinePrefStore store(&cl);
- bool result;
- EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kNoProxyServer, &result));
- EXPECT_TRUE(result);
+ store.VerifyIntPref(prefs::kProxyMode, ProxyPrefs::MODE_DIRECT);
}
// Tests a command line with no recognized prefs.
@@ -59,15 +65,10 @@ TEST(CommandLinePrefStoreTest, NoPrefs) {
cl.AppendSwitch(unknown_string);
cl.AppendSwitchASCII(unknown_bool, "a value");
CommandLinePrefStore store(&cl);
- EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
-
- bool bool_result = false;
- EXPECT_FALSE(store.prefs()->GetBoolean(unknown_bool, &bool_result));
- EXPECT_FALSE(bool_result);
- std::string string_result = "";
- EXPECT_FALSE(store.prefs()->GetString(unknown_string, &string_result));
- EXPECT_EQ("", string_result);
+ Value* actual = NULL;
+ EXPECT_EQ(PrefStore::READ_NO_VALUE, store.GetValue(unknown_bool, &actual));
+ EXPECT_EQ(PrefStore::READ_NO_VALUE, store.GetValue(unknown_string, &actual));
}
// Tests a complex command line with multiple known and unknown switches.
@@ -78,22 +79,20 @@ TEST(CommandLinePrefStoreTest, MultipleSwitches) {
cl.AppendSwitchASCII(switches::kProxyServer, "proxy");
cl.AppendSwitchASCII(switches::kProxyBypassList, "list");
cl.AppendSwitchASCII(unknown_bool, "a value");
- CommandLinePrefStore store(&cl);
- EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
+ TestCommandLinePrefStore store(&cl);
- bool bool_result = false;
- EXPECT_FALSE(store.prefs()->GetBoolean(unknown_bool, &bool_result));
- EXPECT_FALSE(bool_result);
- EXPECT_TRUE(store.prefs()->GetBoolean(prefs::kProxyAutoDetect, &bool_result));
- EXPECT_TRUE(bool_result);
+ Value* actual = NULL;
+ EXPECT_EQ(PrefStore::READ_NO_VALUE, store.GetValue(unknown_bool, &actual));
+ store.VerifyIntPref(prefs::kProxyMode, ProxyPrefs::MODE_AUTO_DETECT);
+ EXPECT_EQ(PrefStore::READ_NO_VALUE, store.GetValue(unknown_string, &actual));
std::string string_result = "";
- EXPECT_FALSE(store.prefs()->GetString(unknown_string, &string_result));
- EXPECT_EQ("", string_result);
- EXPECT_TRUE(store.prefs()->GetString(prefs::kProxyServer, &string_result));
+ ASSERT_EQ(PrefStore::READ_OK, store.GetValue(prefs::kProxyServer, &actual));
+ EXPECT_TRUE(actual->GetAsString(&string_result));
EXPECT_EQ("proxy", string_result);
- EXPECT_TRUE(store.prefs()->GetString(prefs::kProxyBypassList,
- &string_result));
+ ASSERT_EQ(PrefStore::READ_OK,
+ store.GetValue(prefs::kProxyBypassList, &actual));
+ EXPECT_TRUE(actual->GetAsString(&string_result));
EXPECT_EQ("list", string_result);
}
@@ -103,19 +102,16 @@ TEST(CommandLinePrefStoreTest, ProxySwitchValidation) {
// No switches.
TestCommandLinePrefStore store(&cl);
- EXPECT_EQ(store.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
EXPECT_TRUE(store.ProxySwitchesAreValid());
// Only no-proxy.
cl.AppendSwitch(switches::kNoProxyServer);
TestCommandLinePrefStore store2(&cl);
- EXPECT_EQ(store2.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
EXPECT_TRUE(store2.ProxySwitchesAreValid());
// Another proxy switch too.
cl.AppendSwitch(switches::kProxyAutoDetect);
TestCommandLinePrefStore store3(&cl);
- EXPECT_EQ(store3.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
EXPECT_FALSE(store3.ProxySwitchesAreValid());
// All proxy switches except no-proxy.
@@ -125,6 +121,18 @@ TEST(CommandLinePrefStoreTest, ProxySwitchValidation) {
cl2.AppendSwitchASCII(switches::kProxyPacUrl, "url");
cl2.AppendSwitchASCII(switches::kProxyBypassList, "list");
TestCommandLinePrefStore store4(&cl2);
- EXPECT_EQ(store4.ReadPrefs(), PrefStore::PREF_READ_ERROR_NONE);
EXPECT_TRUE(store4.ProxySwitchesAreValid());
}
+
+TEST(CommandLinePrefStoreTest, ManualProxyModeInference) {
+ CommandLine cl1(CommandLine::NO_PROGRAM);
+ cl1.AppendSwitch(unknown_string);
+ cl1.AppendSwitchASCII(switches::kProxyServer, "proxy");
+ TestCommandLinePrefStore store1(&cl1);
+ store1.VerifyIntPref(prefs::kProxyMode, ProxyPrefs::MODE_FIXED_SERVERS);
+
+ CommandLine cl2(CommandLine::NO_PROGRAM);
+ cl2.AppendSwitchASCII(switches::kProxyPacUrl, "proxy");
+ TestCommandLinePrefStore store2(&cl2);
+ store2.VerifyIntPref(prefs::kProxyMode, ProxyPrefs::MODE_PAC_SCRIPT);
+}
diff --git a/chrome/browser/prefs/default_pref_store.cc b/chrome/browser/prefs/default_pref_store.cc
deleted file mode 100644
index a9e6861..0000000
--- a/chrome/browser/prefs/default_pref_store.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// 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.
-
-#include "chrome/browser/prefs/default_pref_store.h"
-
-#include "base/values.h"
-
-DefaultPrefStore::DefaultPrefStore() : prefs_(new DictionaryValue()) {
-}
-
-DefaultPrefStore::~DefaultPrefStore() {
-}
-
-DictionaryValue* DefaultPrefStore::prefs() const {
- return prefs_.get();
-}
-
-PrefStore::PrefReadError DefaultPrefStore::ReadPrefs() {
- return PrefStore::PREF_READ_ERROR_NONE;
-}
diff --git a/chrome/browser/prefs/default_pref_store.h b/chrome/browser/prefs/default_pref_store.h
index 6378aca..9e2e715 100644
--- a/chrome/browser/prefs/default_pref_store.h
+++ b/chrome/browser/prefs/default_pref_store.h
@@ -6,25 +6,24 @@
#define CHROME_BROWSER_PREFS_DEFAULT_PREF_STORE_H_
#pragma once
+#include <map>
+
#include "base/basictypes.h"
-#include "base/scoped_ptr.h"
-#include "chrome/common/pref_store.h"
+#include "chrome/browser/prefs/value_map_pref_store.h"
// This PrefStore keeps track of default preference values set when a
// preference is registered with the PrefService.
-class DefaultPrefStore : public PrefStore {
+class DefaultPrefStore : public ValueMapPrefStore {
public:
- DefaultPrefStore();
- virtual ~DefaultPrefStore();
+ DefaultPrefStore() {}
+ virtual ~DefaultPrefStore() {}
- // PrefStore methods:
- virtual DictionaryValue* prefs() const;
- virtual PrefStore::PrefReadError ReadPrefs();
+ // Stores a new |value| for |key|. Assumes ownership of |value|.
+ void SetDefaultValue(const std::string& key, Value* value) {
+ SetValue(key, value);
+ }
private:
- // The default preference values.
- scoped_ptr<DictionaryValue> prefs_;
-
DISALLOW_COPY_AND_ASSIGN(DefaultPrefStore);
};
diff --git a/chrome/browser/prefs/dummy_pref_store.cc b/chrome/browser/prefs/dummy_pref_store.cc
deleted file mode 100644
index 3a0a81a..0000000
--- a/chrome/browser/prefs/dummy_pref_store.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// 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.
-
-#include "chrome/browser/prefs/dummy_pref_store.h"
-
-#include "base/values.h"
-
-DummyPrefStore::DummyPrefStore()
- : prefs_(new DictionaryValue()),
- read_only_(true),
- prefs_written_(false) { }
-
-PrefStore::PrefReadError DummyPrefStore::ReadPrefs() {
- prefs_.reset(new DictionaryValue());
- return PrefStore::PREF_READ_ERROR_NONE;
-}
-
-bool DummyPrefStore::WritePrefs() {
- prefs_written_ = true;
- return prefs_written_;
-}
diff --git a/chrome/browser/prefs/dummy_pref_store.h b/chrome/browser/prefs/dummy_pref_store.h
deleted file mode 100644
index 4a4e6ba..0000000
--- a/chrome/browser/prefs/dummy_pref_store.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_PREFS_DUMMY_PREF_STORE_H_
-#define CHROME_BROWSER_PREFS_DUMMY_PREF_STORE_H_
-#pragma once
-
-#include "base/basictypes.h"
-#include "base/scoped_ptr.h"
-#include "chrome/common/pref_store.h"
-
-class DictionaryValue;
-
-// |DummyPrefStore| is a stub implementation of the |PrefStore| interface.
-// It allows to get and set the state of the |PrefStore|.
-class DummyPrefStore : public PrefStore {
- public:
- DummyPrefStore();
- virtual ~DummyPrefStore() {}
-
- virtual DictionaryValue* prefs() const { return prefs_.get(); }
-
- virtual PrefStore::PrefReadError ReadPrefs();
-
- virtual bool ReadOnly() { return read_only_; }
-
- virtual bool WritePrefs();
-
- // Getter and Setter methods for setting and getting the state of the
- // |DummyPrefStore|.
- virtual void set_read_only(bool read_only) { read_only_ = read_only; }
- virtual void set_prefs(DictionaryValue* prefs) { prefs_.reset(prefs); }
- virtual void set_prefs_written(bool status) { prefs_written_ = status; }
- virtual bool get_prefs_written() { return prefs_written_; }
-
- private:
- scoped_ptr<DictionaryValue> prefs_;
-
- // Flag that indicates if the PrefStore is read-only
- bool read_only_;
-
- // Flag that indicates if the method WritePrefs was called.
- bool prefs_written_;
-
- DISALLOW_COPY_AND_ASSIGN(DummyPrefStore);
-};
-
-#endif // CHROME_BROWSER_PREFS_DUMMY_PREF_STORE_H_
diff --git a/chrome/browser/prefs/pref_change_registrar.cc b/chrome/browser/prefs/pref_change_registrar.cc
index 05372b1..5655a8e 100644
--- a/chrome/browser/prefs/pref_change_registrar.cc
+++ b/chrome/browser/prefs/pref_change_registrar.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/prefs/pref_change_registrar.h"
+#include "base/logging.h"
#include "chrome/browser/prefs/pref_service.h"
PrefChangeRegistrar::PrefChangeRegistrar() : service_(NULL) {}
diff --git a/chrome/browser/prefs/pref_change_registrar_unittest.cc b/chrome/browser/prefs/pref_change_registrar_unittest.cc
index 8096ee6..2e4cd0e 100644
--- a/chrome/browser/prefs/pref_change_registrar_unittest.cc
+++ b/chrome/browser/prefs/pref_change_registrar_unittest.cc
@@ -4,8 +4,9 @@
#include "chrome/browser/prefs/pref_change_registrar.h"
#include "chrome/common/notification_details.h"
-#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_observer_mock.h"
#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_pref_service.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -14,6 +15,8 @@
using testing::Mock;
using testing::Eq;
+namespace {
+
// A mock provider that allows us to capture pref observer changes.
class MockPrefService : public TestingPrefService {
public:
@@ -24,12 +27,7 @@ class MockPrefService : public TestingPrefService {
MOCK_METHOD2(RemovePrefObserver, void(const char*, NotificationObserver*));
};
-// A mock observer used as a pref observer
-class MockObserver : public NotificationObserver {
- public:
- MOCK_METHOD3(Observe, void(NotificationType, const NotificationSource& source,
- const NotificationDetails& details));
-};
+} // namespace
class PrefChangeRegistrarTest : public testing::Test {
public:
@@ -44,12 +42,12 @@ class PrefChangeRegistrarTest : public testing::Test {
private:
scoped_ptr<MockPrefService> service_;
- scoped_ptr<MockObserver> observer_;
+ scoped_ptr<NotificationObserverMock> observer_;
};
void PrefChangeRegistrarTest::SetUp() {
service_.reset(new MockPrefService());
- observer_.reset(new MockObserver());
+ observer_.reset(new NotificationObserverMock());
}
TEST_F(PrefChangeRegistrarTest, AddAndRemove) {
diff --git a/chrome/browser/prefs/pref_member_unittest.cc b/chrome/browser/prefs/pref_member_unittest.cc
index f59f937..3f786afb 100644
--- a/chrome/browser/prefs/pref_member_unittest.cc
+++ b/chrome/browser/prefs/pref_member_unittest.cc
@@ -2,10 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/prefs/dummy_pref_store.h"
#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/prefs/pref_value_store.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
#include "chrome/test/testing_pref_service.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/prefs/pref_notifier.cc b/chrome/browser/prefs/pref_notifier.cc
deleted file mode 100644
index 151b128..0000000
--- a/chrome/browser/prefs/pref_notifier.cc
+++ /dev/null
@@ -1,137 +0,0 @@
-// 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.
-
-#include "chrome/browser/prefs/pref_notifier.h"
-
-#include "base/stl_util-inl.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/policy/configuration_policy_pref_store.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/prefs/pref_value_store.h"
-#include "chrome/common/notification_service.h"
-
-
-PrefNotifier::PrefNotifier(PrefService* service, PrefValueStore* value_store)
- : pref_service_(service),
- pref_value_store_(value_store) {
- registrar_.Add(this,
- NotificationType(NotificationType::POLICY_CHANGED),
- NotificationService::AllSources());
-}
-
-PrefNotifier::~PrefNotifier() {
- DCHECK(CalledOnValidThread());
-
- // Verify that there are no pref observers when we shut down.
- for (PrefObserverMap::iterator it = pref_observers_.begin();
- it != pref_observers_.end(); ++it) {
- NotificationObserverList::Iterator obs_iterator(*(it->second));
- if (obs_iterator.GetNext()) {
- LOG(WARNING) << "pref observer found at shutdown " << it->first;
- }
- }
-
- STLDeleteContainerPairSecondPointers(pref_observers_.begin(),
- pref_observers_.end());
- pref_observers_.clear();
-}
-
-void PrefNotifier::OnPreferenceSet(const char* pref_name,
- PrefNotifier::PrefStoreType new_store) {
- if (pref_value_store_->PrefHasChanged(pref_name, new_store))
- FireObservers(pref_name);
-}
-
-void PrefNotifier::OnUserPreferenceSet(const char* pref_name) {
- OnPreferenceSet(pref_name, PrefNotifier::USER_STORE);
-}
-
-void PrefNotifier::FireObservers(const char* path) {
- DCHECK(CalledOnValidThread());
-
- // Convert path to a std::string because the Details constructor requires a
- // class.
- std::string path_str(path);
- PrefObserverMap::iterator observer_iterator = pref_observers_.find(path_str);
- if (observer_iterator == pref_observers_.end())
- return;
-
- NotificationObserverList::Iterator it(*(observer_iterator->second));
- NotificationObserver* observer;
- while ((observer = it.GetNext()) != NULL) {
- observer->Observe(NotificationType::PREF_CHANGED,
- Source<PrefService>(pref_service_),
- Details<std::string>(&path_str));
- }
-}
-
-void PrefNotifier::AddPrefObserver(const char* path,
- NotificationObserver* obs) {
- // Get the pref observer list associated with the path.
- NotificationObserverList* observer_list = NULL;
- PrefObserverMap::iterator observer_iterator = pref_observers_.find(path);
- if (observer_iterator == pref_observers_.end()) {
- observer_list = new NotificationObserverList;
- pref_observers_[path] = observer_list;
- } else {
- observer_list = observer_iterator->second;
- }
-
- // Verify that this observer doesn't already exist.
- NotificationObserverList::Iterator it(*observer_list);
- NotificationObserver* existing_obs;
- while ((existing_obs = it.GetNext()) != NULL) {
- DCHECK(existing_obs != obs) << path << " observer already registered";
- if (existing_obs == obs)
- return;
- }
-
- // Ok, safe to add the pref observer.
- observer_list->AddObserver(obs);
-}
-
-void PrefNotifier::RemovePrefObserver(const char* path,
- NotificationObserver* obs) {
- DCHECK(CalledOnValidThread());
-
- PrefObserverMap::iterator observer_iterator = pref_observers_.find(path);
- if (observer_iterator == pref_observers_.end()) {
- return;
- }
-
- NotificationObserverList* observer_list = observer_iterator->second;
- observer_list->RemoveObserver(obs);
-}
-
-void PrefNotifier::FireObserversForRefreshedManagedPrefs(
- std::vector<std::string> changed_prefs_paths) {
- DCHECK(CalledOnValidThread());
- std::vector<std::string>::const_iterator current;
- for (current = changed_prefs_paths.begin();
- current != changed_prefs_paths.end();
- ++current) {
- FireObservers(current->c_str());
- }
-}
-
-void PrefNotifier::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- using policy::ConfigurationPolicyPrefStore;
-
- if (type == NotificationType::POLICY_CHANGED) {
- PrefValueStore::AfterRefreshCallback* callback =
- NewCallback(this,
- &PrefNotifier::FireObserversForRefreshedManagedPrefs);
- // The notification of the policy refresh can come from any thread,
- // but the manipulation of the PrefValueStore must happen on the UI
- // thread, thus the policy refresh must be explicitly started on it.
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(
- pref_value_store_,
- &PrefValueStore::RefreshPolicyPrefs,
- callback));
- }
-}
diff --git a/chrome/browser/prefs/pref_notifier.h b/chrome/browser/prefs/pref_notifier.h
index 7334a51..f2d9c52 100644
--- a/chrome/browser/prefs/pref_notifier.h
+++ b/chrome/browser/prefs/pref_notifier.h
@@ -7,112 +7,21 @@
#pragma once
#include <string>
-#include <vector>
-#include "base/hash_tables.h"
-#include "base/non_thread_safe.h"
-#include "base/observer_list.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
-
-class NotificationObserver;
-class PrefService;
-class PrefValueStore;
-class Value;
-
-// Registers observers for particular preferences and sends notifications when
-// preference values or sources (i.e., which preference layer controls the
-// preference) change.
-class PrefNotifier : public NonThreadSafe,
- public NotificationObserver {
+// Delegate interface used by PrefValueStore to notify its owner about changes
+// to the preference values.
+// TODO(mnissler, danno): Move this declaration to pref_value_store.h once we've
+// cleaned up all public uses of this interface.
+class PrefNotifier {
public:
- // PrefStores must be listed here in order from highest to lowest priority.
- // MANAGED_PLATFORM contains all managed preference values that are
- // provided by a platform-specific policy mechanism (e.g. Windows
- // Group Policy).
- // DEVICE_MANAGEMENT contains all managed preference values supplied
- // by the device management server (cloud policy).
- // EXTENSION contains preference values set by extensions.
- // COMMAND_LINE contains preference values set by command-line switches.
- // USER contains all user-set preference values.
- // RECOMMENDED contains all recommended (policy) preference values.
- // DEFAULT contains all application default preference values.
- // This enum is kept in pref_notifier.h rather than pref_value_store.h in
- // order to minimize additional headers needed by the *PrefStore files.
- enum PrefStoreType {
- // INVALID_STORE is not associated with an actual PrefStore but used as
- // an invalid marker, e.g. as a return value.
- INVALID_STORE = -1,
- MANAGED_PLATFORM_STORE = 0,
- DEVICE_MANAGEMENT_STORE,
- EXTENSION_STORE,
- COMMAND_LINE_STORE,
- USER_STORE,
- RECOMMENDED_STORE,
- DEFAULT_STORE,
- PREF_STORE_TYPE_MAX = DEFAULT_STORE
- };
-
- // The |service| with which this notifier is associated will be sent as the
- // source of any notifications.
- PrefNotifier(PrefService* service, PrefValueStore* value_store);
-
- virtual ~PrefNotifier();
-
- // For the given pref_name, fire any observer of the pref if the effective
- // value of the pref or the store controlling its value has changed, been
- // added, or been removed (but not if it's re-setting the same value it had
- // already). |new_store| should be the PrefStoreType of the store reporting
- // the change.
- void OnPreferenceSet(const char* pref_name,
- PrefNotifier::PrefStoreType new_store);
-
- // Convenience method to be called when a preference is set in the
- // USER_STORE. See OnPreferenceSet().
- void OnUserPreferenceSet(const char* pref_name);
-
- // For the given pref_name, fire any observer of the pref. Virtual so it can
- // be mocked for unit testing.
- virtual void FireObservers(const char* path);
-
- // If the pref at the given path changes, we call the observer's Observe
- // method with PREF_CHANGED.
- void AddPrefObserver(const char* path, NotificationObserver* obs);
- void RemovePrefObserver(const char* path, NotificationObserver* obs);
-
- protected:
- // A map from pref names to a list of observers. Observers get fired in the
- // order they are added. These should only be accessed externally for unit
- // testing.
- typedef ObserverList<NotificationObserver> NotificationObserverList;
- typedef base::hash_map<std::string, NotificationObserverList*>
- PrefObserverMap;
- const PrefObserverMap* pref_observers() { return &pref_observers_; }
-
- private:
- // Weak references.
- PrefService* pref_service_;
- PrefValueStore* pref_value_store_;
-
- NotificationRegistrar registrar_;
-
- PrefObserverMap pref_observers_;
-
- // Called after a policy refresh to notify relevant preference observers.
- // |changed_prefs_paths| is the vector of preference paths changed by the
- // policy update. It is passed by value and not reference because
- // this method is called asynchronously as a callback from another thread.
- // Copying the vector guarantees that the vector's lifecycle spans the
- // method's invocation.
- void FireObserversForRefreshedManagedPrefs(
- std::vector<std::string> changed_prefs_paths);
+ virtual ~PrefNotifier() {}
- // NotificationObserver methods:
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
+ // Sends out a change notification for the preference identified by
+ // |pref_name|.
+ virtual void OnPreferenceChanged(const std::string& pref_name) = 0;
- DISALLOW_COPY_AND_ASSIGN(PrefNotifier);
+ // Broadcasts the intialization completed notification.
+ virtual void OnInitializationCompleted() = 0;
};
#endif // CHROME_BROWSER_PREFS_PREF_NOTIFIER_H_
diff --git a/chrome/browser/prefs/pref_notifier_impl.cc b/chrome/browser/prefs/pref_notifier_impl.cc
new file mode 100644
index 0000000..d15f425
--- /dev/null
+++ b/chrome/browser/prefs/pref_notifier_impl.cc
@@ -0,0 +1,105 @@
+// 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.
+
+#include "chrome/browser/prefs/pref_notifier_impl.h"
+
+#include "base/stl_util-inl.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_service.h"
+
+PrefNotifierImpl::PrefNotifierImpl(PrefService* service)
+ : pref_service_(service) {
+}
+
+PrefNotifierImpl::~PrefNotifierImpl() {
+ DCHECK(CalledOnValidThread());
+
+ // Verify that there are no pref observers when we shut down.
+ for (PrefObserverMap::iterator it = pref_observers_.begin();
+ it != pref_observers_.end(); ++it) {
+ NotificationObserverList::Iterator obs_iterator(*(it->second));
+ if (obs_iterator.GetNext()) {
+ LOG(WARNING) << "pref observer found at shutdown " << it->first;
+ }
+ }
+
+ STLDeleteContainerPairSecondPointers(pref_observers_.begin(),
+ pref_observers_.end());
+ pref_observers_.clear();
+}
+
+void PrefNotifierImpl::AddPrefObserver(const char* path,
+ NotificationObserver* obs) {
+ // Get the pref observer list associated with the path.
+ NotificationObserverList* observer_list = NULL;
+ const PrefObserverMap::iterator observer_iterator =
+ pref_observers_.find(path);
+ if (observer_iterator == pref_observers_.end()) {
+ observer_list = new NotificationObserverList;
+ pref_observers_[path] = observer_list;
+ } else {
+ observer_list = observer_iterator->second;
+ }
+
+ // Verify that this observer doesn't already exist.
+ NotificationObserverList::Iterator it(*observer_list);
+ NotificationObserver* existing_obs;
+ while ((existing_obs = it.GetNext()) != NULL) {
+ DCHECK(existing_obs != obs) << path << " observer already registered";
+ if (existing_obs == obs)
+ return;
+ }
+
+ // Ok, safe to add the pref observer.
+ observer_list->AddObserver(obs);
+}
+
+void PrefNotifierImpl::RemovePrefObserver(const char* path,
+ NotificationObserver* obs) {
+ DCHECK(CalledOnValidThread());
+
+ const PrefObserverMap::iterator observer_iterator =
+ pref_observers_.find(path);
+ if (observer_iterator == pref_observers_.end()) {
+ return;
+ }
+
+ NotificationObserverList* observer_list = observer_iterator->second;
+ observer_list->RemoveObserver(obs);
+}
+
+void PrefNotifierImpl::OnPreferenceChanged(const std::string& path) {
+ FireObservers(path);
+}
+
+void PrefNotifierImpl::OnInitializationCompleted() {
+ DCHECK(CalledOnValidThread());
+
+ NotificationService::current()->Notify(
+ NotificationType::PREF_INITIALIZATION_COMPLETED,
+ Source<PrefService>(pref_service_),
+ NotificationService::NoDetails());
+}
+
+void PrefNotifierImpl::FireObservers(const std::string& path) {
+ DCHECK(CalledOnValidThread());
+
+ // Only send notifications for registered preferences.
+ if (!pref_service_->FindPreference(path.c_str()))
+ return;
+
+ const PrefObserverMap::iterator observer_iterator =
+ pref_observers_.find(path);
+ if (observer_iterator == pref_observers_.end())
+ return;
+
+ NotificationObserverList::Iterator it(*(observer_iterator->second));
+ NotificationObserver* observer;
+ while ((observer = it.GetNext()) != NULL) {
+ observer->Observe(NotificationType::PREF_CHANGED,
+ Source<PrefService>(pref_service_),
+ Details<const std::string>(&path));
+ }
+}
diff --git a/chrome/browser/prefs/pref_notifier_impl.h b/chrome/browser/prefs/pref_notifier_impl.h
new file mode 100644
index 0000000..1d61830
--- /dev/null
+++ b/chrome/browser/prefs/pref_notifier_impl.h
@@ -0,0 +1,58 @@
+// 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.
+
+#ifndef CHROME_BROWSER_PREFS_PREF_NOTIFIER_IMPL_H_
+#define CHROME_BROWSER_PREFS_PREF_NOTIFIER_IMPL_H_
+#pragma once
+
+#include <string>
+
+#include "base/hash_tables.h"
+#include "base/non_thread_safe.h"
+#include "base/observer_list.h"
+#include "chrome/browser/prefs/pref_notifier.h"
+
+class PrefService;
+class NotificationObserver;
+
+// The PrefNotifier implementation used by the PrefService.
+class PrefNotifierImpl : public PrefNotifier,
+ public NonThreadSafe {
+ public:
+ explicit PrefNotifierImpl(PrefService* pref_service);
+ virtual ~PrefNotifierImpl();
+
+ // If the pref at the given path changes, we call the observer's Observe
+ // method with PREF_CHANGED.
+ void AddPrefObserver(const char* path, NotificationObserver* obs);
+ void RemovePrefObserver(const char* path, NotificationObserver* obs);
+
+ // PrefNotifier overrides.
+ virtual void OnPreferenceChanged(const std::string& pref_name);
+ virtual void OnInitializationCompleted();
+
+ protected:
+ // A map from pref names to a list of observers. Observers get fired in the
+ // order they are added. These should only be accessed externally for unit
+ // testing.
+ typedef ObserverList<NotificationObserver> NotificationObserverList;
+ typedef base::hash_map<std::string, NotificationObserverList*>
+ PrefObserverMap;
+
+ const PrefObserverMap* pref_observers() const { return &pref_observers_; }
+
+ private:
+ // For the given pref_name, fire any observer of the pref. Virtual so it can
+ // be mocked for unit testing.
+ virtual void FireObservers(const std::string& path);
+
+ // Weak reference; the notifier is owned by the PrefService.
+ PrefService* pref_service_;
+
+ PrefObserverMap pref_observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrefNotifierImpl);
+};
+
+#endif // CHROME_BROWSER_PREFS_PREF_NOTIFIER_IMPL_H_
diff --git a/chrome/browser/prefs/pref_notifier_impl_unittest.cc b/chrome/browser/prefs/pref_notifier_impl_unittest.cc
new file mode 100644
index 0000000..a410884
--- /dev/null
+++ b/chrome/browser/prefs/pref_notifier_impl_unittest.cc
@@ -0,0 +1,200 @@
+// 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.
+
+#include "chrome/browser/prefs/pref_notifier_impl.h"
+#include "chrome/browser/prefs/pref_observer_mock.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/prefs/pref_value_store.h"
+#include "chrome/common/notification_observer_mock.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/test/testing_pref_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Field;
+using testing::Invoke;
+using testing::Mock;
+using testing::Truly;
+
+namespace {
+
+const char kChangedPref[] = "changed_pref";
+const char kUnchangedPref[] = "unchanged_pref";
+
+bool DetailsAreChangedPref(const Details<std::string>& details) {
+ std::string* string_in = Details<std::string>(details).ptr();
+ return strcmp(string_in->c_str(), kChangedPref) == 0;
+}
+
+// Test PrefNotifier that allows tracking of observers and notifications.
+class MockPrefNotifier : public PrefNotifierImpl {
+ public:
+ explicit MockPrefNotifier(PrefService* pref_service)
+ : PrefNotifierImpl(pref_service) {}
+ virtual ~MockPrefNotifier() {}
+
+ MOCK_METHOD1(FireObservers, void(const std::string& path));
+
+ size_t CountObserver(const char* path, NotificationObserver* obs) {
+ PrefObserverMap::const_iterator observer_iterator =
+ pref_observers()->find(path);
+ if (observer_iterator == pref_observers()->end())
+ return false;
+
+ NotificationObserverList* observer_list = observer_iterator->second;
+ NotificationObserverList::Iterator it(*observer_list);
+ NotificationObserver* existing_obs;
+ size_t count = 0;
+ while ((existing_obs = it.GetNext()) != NULL) {
+ if (existing_obs == obs)
+ count++;
+ }
+
+ return count;
+ }
+};
+
+// Test fixture class.
+class PrefNotifierTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ pref_service_.RegisterBooleanPref(kChangedPref, true);
+ pref_service_.RegisterBooleanPref(kUnchangedPref, true);
+ }
+
+ TestingPrefService pref_service_;
+
+ PrefObserverMock obs1_;
+ PrefObserverMock obs2_;
+};
+
+TEST_F(PrefNotifierTest, OnPreferenceChanged) {
+ MockPrefNotifier notifier(&pref_service_);
+ EXPECT_CALL(notifier, FireObservers(kChangedPref)).Times(1);
+ notifier.OnPreferenceChanged(kChangedPref);
+}
+
+TEST_F(PrefNotifierTest, OnInitializationCompleted) {
+ MockPrefNotifier notifier(&pref_service_);
+ NotificationObserverMock observer;
+ NotificationRegistrar registrar;
+ registrar.Add(&observer, NotificationType::PREF_INITIALIZATION_COMPLETED,
+ Source<PrefService>(&pref_service_));
+ EXPECT_CALL(observer, Observe(
+ Field(&NotificationType::value,
+ NotificationType::PREF_INITIALIZATION_COMPLETED),
+ Source<PrefService>(&pref_service_),
+ NotificationService::NoDetails()));
+ notifier.OnInitializationCompleted();
+}
+
+TEST_F(PrefNotifierTest, AddAndRemovePrefObservers) {
+ const char pref_name[] = "homepage";
+ const char pref_name2[] = "proxy";
+
+ MockPrefNotifier notifier(&pref_service_);
+ notifier.AddPrefObserver(pref_name, &obs1_);
+ ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_));
+ ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs1_));
+ ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
+ ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
+
+ // Re-adding the same observer for the same pref doesn't change anything.
+ // Skip this in debug mode, since it hits a DCHECK and death tests aren't
+ // thread-safe.
+#if defined(NDEBUG)
+ notifier.AddPrefObserver(pref_name, &obs1_);
+ ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_));
+ ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs1_));
+ ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
+ ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
+#endif // NDEBUG
+
+ // Ensure that we can add the same observer to a different pref.
+ notifier.AddPrefObserver(pref_name2, &obs1_);
+ ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_));
+ ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_));
+ ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
+ ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
+
+ // Ensure that we can add another observer to the same pref.
+ notifier.AddPrefObserver(pref_name, &obs2_);
+ ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_));
+ ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_));
+ ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs2_));
+ ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
+
+ // Ensure that we can remove all observers, and that removing a non-existent
+ // observer is harmless.
+ notifier.RemovePrefObserver(pref_name, &obs1_);
+ ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_));
+ ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_));
+ ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs2_));
+ ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
+
+ notifier.RemovePrefObserver(pref_name, &obs2_);
+ ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_));
+ ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_));
+ ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
+ ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
+
+ notifier.RemovePrefObserver(pref_name, &obs1_);
+ ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_));
+ ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_));
+ ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
+ ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
+
+ notifier.RemovePrefObserver(pref_name2, &obs1_);
+ ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_));
+ ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs1_));
+ ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
+ ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
+}
+
+TEST_F(PrefNotifierTest, FireObservers) {
+ FundamentalValue value_true(true);
+ PrefNotifierImpl notifier(&pref_service_);
+ notifier.AddPrefObserver(kChangedPref, &obs1_);
+ notifier.AddPrefObserver(kUnchangedPref, &obs1_);
+
+ obs1_.Expect(&pref_service_, kChangedPref, &value_true);
+ EXPECT_CALL(obs2_, Observe(_, _, _)).Times(0);
+ notifier.OnPreferenceChanged(kChangedPref);
+ Mock::VerifyAndClearExpectations(&obs1_);
+ Mock::VerifyAndClearExpectations(&obs2_);
+
+ notifier.AddPrefObserver(kChangedPref, &obs2_);
+ notifier.AddPrefObserver(kUnchangedPref, &obs2_);
+
+ obs1_.Expect(&pref_service_, kChangedPref, &value_true);
+ obs2_.Expect(&pref_service_, kChangedPref, &value_true);
+ notifier.OnPreferenceChanged(kChangedPref);
+ Mock::VerifyAndClearExpectations(&obs1_);
+ Mock::VerifyAndClearExpectations(&obs2_);
+
+ // Make sure removing an observer from one pref doesn't affect anything else.
+ notifier.RemovePrefObserver(kChangedPref, &obs1_);
+
+ EXPECT_CALL(obs1_, Observe(_, _, _)).Times(0);
+ obs2_.Expect(&pref_service_, kChangedPref, &value_true);
+ notifier.OnPreferenceChanged(kChangedPref);
+ Mock::VerifyAndClearExpectations(&obs1_);
+ Mock::VerifyAndClearExpectations(&obs2_);
+
+ // Make sure removing an observer entirely doesn't affect anything else.
+ notifier.RemovePrefObserver(kUnchangedPref, &obs1_);
+
+ EXPECT_CALL(obs1_, Observe(_, _, _)).Times(0);
+ obs2_.Expect(&pref_service_, kChangedPref, &value_true);
+ notifier.OnPreferenceChanged(kChangedPref);
+ Mock::VerifyAndClearExpectations(&obs1_);
+ Mock::VerifyAndClearExpectations(&obs2_);
+
+ notifier.RemovePrefObserver(kChangedPref, &obs2_);
+ notifier.RemovePrefObserver(kUnchangedPref, &obs2_);
+}
+
+} // namespace
diff --git a/chrome/browser/prefs/pref_notifier_unittest.cc b/chrome/browser/prefs/pref_notifier_unittest.cc
deleted file mode 100644
index 6792ada..0000000
--- a/chrome/browser/prefs/pref_notifier_unittest.cc
+++ /dev/null
@@ -1,294 +0,0 @@
-// 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.
-
-#include "chrome/browser/prefs/default_pref_store.h"
-#include "chrome/browser/prefs/pref_notifier.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/prefs/pref_value_store.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_type.h"
-#include "chrome/common/notification_service.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-
-namespace {
-
-const char kChangedPref[] = "changed_pref";
-const char kUnchangedPref[] = "unchanged_pref";
-
-bool DetailsAreChangedPref(const Details<std::string>& details) {
- std::string* string_in = Details<std::string>(details).ptr();
- return strcmp(string_in->c_str(), kChangedPref) == 0;
-}
-
-// Test PrefNotifier that allows tracking of observers and notifications.
-class MockPrefNotifier : public PrefNotifier {
- public:
- MockPrefNotifier(PrefService* prefs, PrefValueStore* value_store)
- : PrefNotifier(prefs, value_store) {}
-
- virtual ~MockPrefNotifier() {}
-
- MOCK_METHOD1(FireObservers, void(const char* path));
-
- void RealFireObservers(const char* path) {
- PrefNotifier::FireObservers(path);
- }
-
- size_t CountObserver(const char* path, NotificationObserver* obs) {
- PrefObserverMap::const_iterator observer_iterator =
- pref_observers()->find(path);
- if (observer_iterator == pref_observers()->end())
- return false;
-
- NotificationObserverList* observer_list = observer_iterator->second;
- NotificationObserverList::Iterator it(*observer_list);
- NotificationObserver* existing_obs;
- size_t count = 0;
- while ((existing_obs = it.GetNext()) != NULL) {
- if (existing_obs == obs)
- count++;
- }
-
- return count;
- }
-};
-
-// Mock PrefValueStore that has no unnecessary PrefStores and injects a simpler
-// PrefHasChanged().
-class MockPrefValueStore : public PrefValueStore {
- public:
- MockPrefValueStore()
- : PrefValueStore(NULL, NULL, NULL, NULL, NULL, NULL,
- new DefaultPrefStore(), NULL) {}
-
- virtual ~MockPrefValueStore() {}
-
- // This mock version returns true if the pref path starts with "changed".
- virtual bool PrefHasChanged(const char* path,
- PrefNotifier::PrefStoreType new_store) {
- std::string path_str(path);
- if (path_str.compare(0, 7, "changed") == 0)
- return true;
- return false;
- }
-};
-
-// Mock PrefService that allows the PrefNotifier to be injected.
-class MockPrefService : public PrefService {
- public:
- explicit MockPrefService(PrefValueStore* pref_value_store)
- : PrefService(pref_value_store) {}
-
- void SetPrefNotifier(PrefNotifier* notifier) {
- pref_notifier_.reset(notifier);
- }
-};
-
-// Mock PrefObserver that verifies notifications.
-class MockPrefObserver : public NotificationObserver {
- public:
- virtual ~MockPrefObserver() {}
-
- MOCK_METHOD3(Observe, void(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details));
-};
-
-// Test fixture class.
-class PrefNotifierTest : public testing::Test {
- protected:
- virtual void SetUp() {
- value_store_ = new MockPrefValueStore;
- pref_service_.reset(new MockPrefService(value_store_));
- notifier_ = new MockPrefNotifier(pref_service_.get(), value_store_);
- pref_service_->SetPrefNotifier(notifier_);
-
- pref_service_->RegisterBooleanPref(kChangedPref, true);
- pref_service_->RegisterBooleanPref(kUnchangedPref, true);
- }
-
- // The PrefService takes ownership of the PrefValueStore and PrefNotifier.
- PrefValueStore* value_store_;
- MockPrefNotifier* notifier_;
- scoped_ptr<MockPrefService> pref_service_;
-
- MockPrefObserver obs1_;
- MockPrefObserver obs2_;
-};
-
-TEST_F(PrefNotifierTest, OnPreferenceSet) {
- EXPECT_CALL(*notifier_, FireObservers(kChangedPref))
- .Times(PrefNotifier::PREF_STORE_TYPE_MAX + 1);
- EXPECT_CALL(*notifier_, FireObservers(kUnchangedPref)).Times(0);
-
- for (size_t i = 0; i <= PrefNotifier::PREF_STORE_TYPE_MAX; ++i) {
- notifier_->OnPreferenceSet(kChangedPref,
- static_cast<PrefNotifier::PrefStoreType>(i));
- notifier_->OnPreferenceSet(kUnchangedPref,
- static_cast<PrefNotifier::PrefStoreType>(i));
- }
-}
-
-TEST_F(PrefNotifierTest, OnUserPreferenceSet) {
- EXPECT_CALL(*notifier_, FireObservers(kChangedPref));
- EXPECT_CALL(*notifier_, FireObservers(kUnchangedPref)).Times(0);
- notifier_->OnUserPreferenceSet(kChangedPref);
- notifier_->OnUserPreferenceSet(kUnchangedPref);
-}
-
-TEST_F(PrefNotifierTest, AddAndRemovePrefObservers) {
- const char pref_name[] = "homepage";
- const char pref_name2[] = "proxy";
-
- notifier_->AddPrefObserver(pref_name, &obs1_);
- ASSERT_EQ(1u, notifier_->CountObserver(pref_name, &obs1_));
- ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs1_));
- ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs2_));
- ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs2_));
-
- // Re-adding the same observer for the same pref doesn't change anything.
- // Skip this in debug mode, since it hits a DCHECK and death tests aren't
- // thread-safe.
-#if defined(NDEBUG)
- notifier_->AddPrefObserver(pref_name, &obs1_);
- ASSERT_EQ(1u, notifier_->CountObserver(pref_name, &obs1_));
- ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs1_));
- ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs2_));
- ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs2_));
-#endif // NDEBUG
-
- // Ensure that we can add the same observer to a different pref.
- notifier_->AddPrefObserver(pref_name2, &obs1_);
- ASSERT_EQ(1u, notifier_->CountObserver(pref_name, &obs1_));
- ASSERT_EQ(1u, notifier_->CountObserver(pref_name2, &obs1_));
- ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs2_));
- ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs2_));
-
- // Ensure that we can add another observer to the same pref.
- notifier_->AddPrefObserver(pref_name, &obs2_);
- ASSERT_EQ(1u, notifier_->CountObserver(pref_name, &obs1_));
- ASSERT_EQ(1u, notifier_->CountObserver(pref_name2, &obs1_));
- ASSERT_EQ(1u, notifier_->CountObserver(pref_name, &obs2_));
- ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs2_));
-
- // Ensure that we can remove all observers, and that removing a non-existent
- // observer is harmless.
- notifier_->RemovePrefObserver(pref_name, &obs1_);
- ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs1_));
- ASSERT_EQ(1u, notifier_->CountObserver(pref_name2, &obs1_));
- ASSERT_EQ(1u, notifier_->CountObserver(pref_name, &obs2_));
- ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs2_));
-
- notifier_->RemovePrefObserver(pref_name, &obs2_);
- ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs1_));
- ASSERT_EQ(1u, notifier_->CountObserver(pref_name2, &obs1_));
- ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs2_));
- ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs2_));
-
- notifier_->RemovePrefObserver(pref_name, &obs1_);
- ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs1_));
- ASSERT_EQ(1u, notifier_->CountObserver(pref_name2, &obs1_));
- ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs2_));
- ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs2_));
-
- notifier_->RemovePrefObserver(pref_name2, &obs1_);
- ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs1_));
- ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs1_));
- ASSERT_EQ(0u, notifier_->CountObserver(pref_name, &obs2_));
- ASSERT_EQ(0u, notifier_->CountObserver(pref_name2, &obs2_));
-}
-
-TEST_F(PrefNotifierTest, FireObservers) {
- using testing::_;
- using testing::Field;
- using testing::Invoke;
- using testing::Mock;
- using testing::Truly;
-
- // Tell googlemock to pass calls to the mock's "back door" too.
- ON_CALL(*notifier_, FireObservers(_))
- .WillByDefault(Invoke(notifier_, &MockPrefNotifier::RealFireObservers));
- EXPECT_CALL(*notifier_, FireObservers(kChangedPref)).Times(4);
- EXPECT_CALL(*notifier_, FireObservers(kUnchangedPref)).Times(0);
-
- notifier_->AddPrefObserver(kChangedPref, &obs1_);
- notifier_->AddPrefObserver(kUnchangedPref, &obs1_);
-
- EXPECT_CALL(obs1_, Observe(
- Field(&NotificationType::value, NotificationType::PREF_CHANGED),
- Source<PrefService>(pref_service_.get()),
- Truly(DetailsAreChangedPref)));
- EXPECT_CALL(obs2_, Observe(_, _, _)).Times(0);
- notifier_->OnUserPreferenceSet(kChangedPref);
- Mock::VerifyAndClearExpectations(&obs1_);
- Mock::VerifyAndClearExpectations(&obs2_);
-
- EXPECT_CALL(obs1_, Observe(_, _, _)).Times(0);
- EXPECT_CALL(obs2_, Observe(_, _, _)).Times(0);
- notifier_->OnUserPreferenceSet(kUnchangedPref);
- Mock::VerifyAndClearExpectations(&obs1_);
- Mock::VerifyAndClearExpectations(&obs2_);
-
- notifier_->AddPrefObserver(kChangedPref, &obs2_);
- notifier_->AddPrefObserver(kUnchangedPref, &obs2_);
-
- EXPECT_CALL(obs1_, Observe(
- Field(&NotificationType::value, NotificationType::PREF_CHANGED),
- Source<PrefService>(pref_service_.get()),
- Truly(DetailsAreChangedPref)));
- EXPECT_CALL(obs2_, Observe(
- Field(&NotificationType::value, NotificationType::PREF_CHANGED),
- Source<PrefService>(pref_service_.get()),
- Truly(DetailsAreChangedPref)));
- notifier_->OnUserPreferenceSet(kChangedPref);
- Mock::VerifyAndClearExpectations(&obs1_);
- Mock::VerifyAndClearExpectations(&obs2_);
-
- EXPECT_CALL(obs1_, Observe(_, _, _)).Times(0);
- EXPECT_CALL(obs2_, Observe(_, _, _)).Times(0);
- notifier_->OnUserPreferenceSet(kUnchangedPref);
- Mock::VerifyAndClearExpectations(&obs1_);
- Mock::VerifyAndClearExpectations(&obs2_);
-
- // Make sure removing an observer from one pref doesn't affect anything else.
- notifier_->RemovePrefObserver(kChangedPref, &obs1_);
-
- EXPECT_CALL(obs1_, Observe(_, _, _)).Times(0);
- EXPECT_CALL(obs2_, Observe(
- Field(&NotificationType::value, NotificationType::PREF_CHANGED),
- Source<PrefService>(pref_service_.get()),
- Truly(DetailsAreChangedPref)));
- notifier_->OnUserPreferenceSet(kChangedPref);
- Mock::VerifyAndClearExpectations(&obs1_);
- Mock::VerifyAndClearExpectations(&obs2_);
-
- EXPECT_CALL(obs1_, Observe(_, _, _)).Times(0);
- EXPECT_CALL(obs2_, Observe(_, _, _)).Times(0);
- notifier_->OnUserPreferenceSet(kUnchangedPref);
- Mock::VerifyAndClearExpectations(&obs1_);
- Mock::VerifyAndClearExpectations(&obs2_);
-
- // Make sure removing an observer entirely doesn't affect anything else.
- notifier_->RemovePrefObserver(kUnchangedPref, &obs1_);
-
- EXPECT_CALL(obs1_, Observe(_, _, _)).Times(0);
- EXPECT_CALL(obs2_, Observe(
- Field(&NotificationType::value, NotificationType::PREF_CHANGED),
- Source<PrefService>(pref_service_.get()),
- Truly(DetailsAreChangedPref)));
- notifier_->OnUserPreferenceSet(kChangedPref);
- Mock::VerifyAndClearExpectations(&obs1_);
- Mock::VerifyAndClearExpectations(&obs2_);
-
- EXPECT_CALL(obs1_, Observe(_, _, _)).Times(0);
- EXPECT_CALL(obs2_, Observe(_, _, _)).Times(0);
- notifier_->OnUserPreferenceSet(kUnchangedPref);
-
- notifier_->RemovePrefObserver(kChangedPref, &obs2_);
- notifier_->RemovePrefObserver(kUnchangedPref, &obs2_);
-}
-
-} // namespace
diff --git a/chrome/browser/prefs/pref_observer_mock.h b/chrome/browser/prefs/pref_observer_mock.h
new file mode 100644
index 0000000..f339841
--- /dev/null
+++ b/chrome/browser/prefs/pref_observer_mock.h
@@ -0,0 +1,60 @@
+// 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.
+
+#ifndef CHROME_BROWSER_PREFS_PREF_OBSERVER_MOCK_H_
+#define CHROME_BROWSER_PREFS_PREF_OBSERVER_MOCK_H_
+#pragma once
+
+#include <string>
+
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using testing::Pointee;
+using testing::Property;
+using testing::Truly;
+
+// Matcher that checks whether the current value of the preference named
+// |pref_name| in |prefs| matches |value|. If |value| is NULL, the matcher
+// checks that the value is not set.
+MATCHER_P3(PrefValueMatches, prefs, pref_name, value, "") {
+ const PrefService::Preference* pref =
+ prefs->FindPreference(pref_name.c_str());
+ if (!pref)
+ return false;
+
+ const Value* actual_value = pref->GetValue();
+ if (!actual_value)
+ return value == NULL;
+ if (!value)
+ return actual_value == NULL;
+ return value->Equals(actual_value);
+}
+
+// A mock for testing preference notifications and easy setup of expectations.
+class PrefObserverMock : public NotificationObserver {
+ public:
+ PrefObserverMock() {}
+ virtual ~PrefObserverMock() {}
+
+ MOCK_METHOD3(Observe, void(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details));
+
+ void Expect(const PrefService* prefs,
+ const std::string& pref_name,
+ const Value* value) {
+ EXPECT_CALL(*this, Observe(NotificationType(NotificationType::PREF_CHANGED),
+ Source<PrefService>(prefs),
+ Property(&Details<std::string>::ptr,
+ Pointee(pref_name))))
+ .With(PrefValueMatches(prefs, pref_name, value));
+ }
+};
+
+#endif // CHROME_BROWSER_PREFS_PREF_OBSERVER_MOCK_H_
diff --git a/chrome/browser/prefs/pref_service.cc b/chrome/browser/prefs/pref_service.cc
index 8662f88..86149c5 100644
--- a/chrome/browser/prefs/pref_service.cc
+++ b/chrome/browser/prefs/pref_service.cc
@@ -23,10 +23,19 @@
#include "base/utf_string_conversions.h"
#include "build/build_config.h"
#include "chrome/browser/browser_thread.h"
+<<<<<<< HEAD
#include "chrome/browser/profile.h"
#ifndef ANDROID
// Notifications do not compile on Android and are the cause
// of most of the ANDROID guards in this file.
+=======
+#include "chrome/browser/policy/configuration_policy_pref_store.h"
+#include "chrome/browser/prefs/command_line_pref_store.h"
+#include "chrome/browser/prefs/default_pref_store.h"
+#include "chrome/browser/prefs/pref_notifier_impl.h"
+#include "chrome/browser/prefs/pref_value_store.h"
+#include "chrome/common/json_pref_store.h"
+>>>>>>> chromium.org at r10.0.621.0
#include "chrome/common/notification_service.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
@@ -90,8 +99,15 @@ void NotifyReadError(PrefService* pref, int message_id) {
// static
PrefService* PrefService::CreatePrefService(const FilePath& pref_filename,
+ PrefStore* extension_prefs,
Profile* profile) {
+<<<<<<< HEAD
#if defined(OS_LINUX) && !defined(ANDROID)
+=======
+ using policy::ConfigurationPolicyPrefStore;
+
+#if defined(OS_LINUX)
+>>>>>>> chromium.org at r10.0.621.0
// We'd like to see what fraction of our users have the preferences
// stored on a network file system, as we've had no end of troubles
// with NFS/AFS.
@@ -104,6 +120,7 @@ PrefService* PrefService::CreatePrefService(const FilePath& pref_filename,
}
#endif
+<<<<<<< HEAD
return new PrefService(
PrefValueStore::CreatePrefValueStore(pref_filename, profile, false));
}
@@ -119,6 +136,43 @@ PrefService::PrefService(PrefValueStore* pref_value_store)
#ifndef ANDROID
pref_notifier_.reset(new PrefNotifier(this, pref_value_store));
#endif
+=======
+ ConfigurationPolicyPrefStore* managed =
+ ConfigurationPolicyPrefStore::CreateManagedPlatformPolicyPrefStore();
+ ConfigurationPolicyPrefStore* device_management =
+ ConfigurationPolicyPrefStore::CreateDeviceManagementPolicyPrefStore(
+ profile);
+ CommandLinePrefStore* command_line =
+ new CommandLinePrefStore(CommandLine::ForCurrentProcess());
+ JsonPrefStore* user = new JsonPrefStore(
+ pref_filename,
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
+ ConfigurationPolicyPrefStore* recommended =
+ ConfigurationPolicyPrefStore::CreateRecommendedPolicyPrefStore();
+
+ return new PrefService(managed, device_management, extension_prefs,
+ command_line, user, recommended);
+}
+
+PrefService::PrefService(PrefStore* managed_platform_prefs,
+ PrefStore* device_management_prefs,
+ PrefStore* extension_prefs,
+ PrefStore* command_line_prefs,
+ PersistentPrefStore* user_prefs,
+ PrefStore* recommended_prefs)
+ : user_pref_store_(user_prefs) {
+ pref_notifier_.reset(new PrefNotifierImpl(this));
+ default_store_ = new DefaultPrefStore();
+ pref_value_store_ =
+ new PrefValueStore(managed_platform_prefs,
+ device_management_prefs,
+ extension_prefs,
+ command_line_prefs,
+ user_pref_store_,
+ recommended_prefs,
+ default_store_,
+ pref_notifier_.get());
+>>>>>>> chromium.org at r10.0.621.0
InitFromStorage();
}
@@ -129,18 +183,24 @@ PrefService::~PrefService() {
}
void PrefService::InitFromStorage() {
+<<<<<<< HEAD
#ifndef ANDROID
PrefStore::PrefReadError error = LoadPersistentPrefs();
if (error == PrefStore::PREF_READ_ERROR_NONE)
+=======
+ const PersistentPrefStore::PrefReadError error =
+ user_pref_store_->ReadPrefs();
+ if (error == PersistentPrefStore::PREF_READ_ERROR_NONE)
+>>>>>>> chromium.org at r10.0.621.0
return;
// Failing to load prefs on startup is a bad thing(TM). See bug 38352 for
// an example problem that this can cause.
// Do some diagnosis and try to avoid losing data.
int message_id = 0;
- if (error <= PrefStore::PREF_READ_ERROR_JSON_TYPE) {
+ if (error <= PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE) {
message_id = IDS_PREFERENCES_CORRUPT_ERROR;
- } else if (error != PrefStore::PREF_READ_ERROR_NO_FILE) {
+ } else if (error != PersistentPrefStore::PREF_READ_ERROR_NO_FILE) {
message_id = IDS_PREFERENCES_UNREADABLE_ERROR;
}
@@ -153,32 +213,20 @@ void PrefService::InitFromStorage() {
}
bool PrefService::ReloadPersistentPrefs() {
- return (LoadPersistentPrefs() == PrefStore::PREF_READ_ERROR_NONE);
-}
-
-PrefStore::PrefReadError PrefService::LoadPersistentPrefs() {
- DCHECK(CalledOnValidThread());
-
- PrefStore::PrefReadError pref_error = pref_value_store_->ReadPrefs();
-
- for (PreferenceSet::iterator it = prefs_.begin();
- it != prefs_.end(); ++it) {
- (*it)->pref_service_ = this;
- }
-
- return pref_error;
+ return user_pref_store_->ReadPrefs() ==
+ PersistentPrefStore::PREF_READ_ERROR_NONE;
}
bool PrefService::SavePersistentPrefs() {
DCHECK(CalledOnValidThread());
- return pref_value_store_->WritePrefs();
+ return user_pref_store_->WritePrefs();
}
void PrefService::ScheduleSavePersistentPrefs() {
DCHECK(CalledOnValidThread());
- pref_value_store_->ScheduleWritePrefs();
+ user_pref_store_->ScheduleWritePrefs();
}
void PrefService::RegisterBooleanPref(const char* path,
@@ -331,6 +379,14 @@ const PrefService::Preference* PrefService::FindPreference(
return it == prefs_.end() ? NULL : *it;
}
+bool PrefService::ReadOnly() const {
+ return user_pref_store_->ReadOnly();
+}
+
+PrefNotifier* PrefService::pref_notifier() const {
+ return pref_notifier_.get();
+}
+
bool PrefService::IsManagedPreference(const char* pref_name) const {
const Preference* pref = FindPreference(pref_name);
if (pref && pref->IsManaged()) {
@@ -398,11 +454,10 @@ void PrefService::RegisterPreference(const char* path, Value* default_value) {
// easier for callers to check for empty dict/list prefs. The PrefValueStore
// accepts ownership of the value (null or default_value).
if (Value::TYPE_LIST == orig_type || Value::TYPE_DICTIONARY == orig_type) {
- pref_value_store_->SetDefaultPrefValue(path, Value::CreateNullValue());
+ default_store_->SetDefaultValue(path, Value::CreateNullValue());
} else {
// Hand off ownership.
- DCHECK(!PrefStore::IsUseDefaultSentinelValue(default_value));
- pref_value_store_->SetDefaultPrefValue(path, scoped_value.release());
+ default_store_->SetDefaultValue(path, scoped_value.release());
}
pref_value_store_->RegisterPreferenceType(path, orig_type);
@@ -417,10 +472,14 @@ void PrefService::ClearPref(const char* path) {
NOTREACHED() << "Trying to clear an unregistered pref: " << path;
return;
}
+<<<<<<< HEAD
#ifndef ANDROID
if (pref_value_store_->RemoveUserPrefValue(path))
pref_notifier_->OnUserPreferenceSet(path);
#endif
+=======
+ user_pref_store_->RemoveValue(path);
+>>>>>>> chromium.org at r10.0.621.0
}
void PrefService::Set(const char* path, const Value& value) {
@@ -434,22 +493,24 @@ void PrefService::Set(const char* path, const Value& value) {
// Allow dictionary and list types to be set to null, which removes their
// user values.
- bool value_changed = false;
if (value.GetType() == Value::TYPE_NULL &&
(pref->GetType() == Value::TYPE_DICTIONARY ||
pref->GetType() == Value::TYPE_LIST)) {
- value_changed = pref_value_store_->RemoveUserPrefValue(path);
+ user_pref_store_->RemoveValue(path);
} else if (pref->GetType() != value.GetType()) {
NOTREACHED() << "Trying to set pref " << path
<< " of type " << pref->GetType()
<< " to value of type " << value.GetType();
} else {
- value_changed = pref_value_store_->SetUserPrefValue(path, value.DeepCopy());
+ user_pref_store_->SetValue(path, value.DeepCopy());
}
+<<<<<<< HEAD
#ifndef ANDROID
if (value_changed)
pref_notifier_->OnUserPreferenceSet(path);
#endif
+=======
+>>>>>>> chromium.org at r10.0.621.0
}
void PrefService::SetBoolean(const char* path, bool value) {
@@ -524,10 +585,11 @@ DictionaryValue* PrefService::GetMutableDictionary(const char* path) {
Value* tmp_value = NULL;
// Look for an existing preference in the user store. If it doesn't
// exist or isn't the correct type, create a new user preference.
- if (!pref_value_store_->GetUserValue(path, &tmp_value) ||
+ if (user_pref_store_->GetValue(path, &tmp_value)
+ != PersistentPrefStore::READ_OK ||
!tmp_value->IsType(Value::TYPE_DICTIONARY)) {
dict = new DictionaryValue;
- pref_value_store_->SetUserPrefValue(path, dict);
+ user_pref_store_->SetValueSilently(path, dict);
} else {
dict = static_cast<DictionaryValue*>(tmp_value);
}
@@ -551,24 +613,17 @@ ListValue* PrefService::GetMutableList(const char* path) {
Value* tmp_value = NULL;
// Look for an existing preference in the user store. If it doesn't
// exist or isn't the correct type, create a new user preference.
- if (!pref_value_store_->GetUserValue(path, &tmp_value) ||
+ if (user_pref_store_->GetValue(path, &tmp_value)
+ != PersistentPrefStore::READ_OK ||
!tmp_value->IsType(Value::TYPE_LIST)) {
list = new ListValue;
- pref_value_store_->SetUserPrefValue(path, list);
+ user_pref_store_->SetValueSilently(path, list);
} else {
list = static_cast<ListValue*>(tmp_value);
}
return list;
}
-Value* PrefService::GetPrefCopy(const char* path) {
- DCHECK(CalledOnValidThread());
-
- const Preference* pref = FindPreference(path);
- DCHECK(pref);
- return pref->GetValue()->DeepCopy();
-}
-
void PrefService::SetUserPrefValue(const char* path, Value* new_value) {
DCHECK(CalledOnValidThread());
@@ -577,10 +632,6 @@ void PrefService::SetUserPrefValue(const char* path, Value* new_value) {
NOTREACHED() << "Trying to write an unregistered pref: " << path;
return;
}
- if (pref->IsManaged()) {
- NOTREACHED() << "Preference is managed: " << path;
- return;
- }
if (pref->GetType() != new_value->GetType()) {
NOTREACHED() << "Trying to set pref " << path
<< " of type " << pref->GetType()
@@ -588,10 +639,14 @@ void PrefService::SetUserPrefValue(const char* path, Value* new_value) {
return;
}
+<<<<<<< HEAD
#ifndef ANDROID
if (pref_value_store_->SetUserPrefValue(path, new_value))
pref_notifier_->OnUserPreferenceSet(path);
#endif
+=======
+ user_pref_store_->SetValue(path, new_value);
+>>>>>>> chromium.org at r10.0.621.0
}
///////////////////////////////////////////////////////////////////////////////
@@ -623,8 +678,7 @@ const Value* PrefService::Preference::GetValue() const {
}
bool PrefService::Preference::IsManaged() const {
- PrefValueStore* pref_value_store =
- pref_service_->pref_value_store_;
+ PrefValueStore* pref_value_store = pref_service_->pref_value_store_;
return pref_value_store->PrefValueInManagedPlatformStore(name_.c_str()) ||
pref_value_store->PrefValueInDeviceManagementStore(name_.c_str());
}
diff --git a/chrome/browser/prefs/pref_service.h b/chrome/browser/prefs/pref_service.h
index 44ae00b..40500b5 100644
--- a/chrome/browser/prefs/pref_service.h
+++ b/chrome/browser/prefs/pref_service.h
@@ -12,19 +12,23 @@
#include <string>
#include "base/non_thread_safe.h"
+#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "base/values.h"
-#include "chrome/browser/prefs/pref_value_store.h"
-#include "chrome/common/pref_store.h"
+class DefaultPrefStore;
class FilePath;
class NotificationObserver;
+class PersistentPrefStore;
class PrefChangeObserver;
class PrefNotifier;
+class PrefNotifierImpl;
+class PrefStore;
+class PrefValueStore;
class Profile;
namespace subtle {
- class PrefMemberBase;
+class PrefMemberBase;
};
class PrefService : public NonThreadSafe {
@@ -94,24 +98,17 @@ class PrefService : public NonThreadSafe {
DISALLOW_COPY_AND_ASSIGN(Preference);
};
- // Factory method that creates a new instance of a PrefService with
- // a PrefValueStore containing all platform-applicable PrefStores.
- // The |pref_filename| points to the user preference file. The |profile| is
- // the one to which these preferences apply; it may be NULL if we're dealing
- // with the local state. This is the usual way to create a new PrefService.
+ // Factory method that creates a new instance of a PrefService with the
+ // applicable PrefStores. The |pref_filename| points to the user preference
+ // file. The |profile| is the one to which these preferences apply; it may be
+ // NULL if we're dealing with the local state. This is the usual way to create
+ // a new PrefService. |extension_pref_store| is used as the source for
+ // extension-controlled preferences and may be NULL. The PrefService takes
+ // ownership of |extension_pref_store|.
static PrefService* CreatePrefService(const FilePath& pref_filename,
+ PrefStore* extension_pref_store,
Profile* profile);
- // Convenience factory method for use in unit tests. Creates a new
- // PrefService that uses a PrefValueStore with user preferences at the given
- // |pref_filename|, a default PrefStore, and no other PrefStores (i.e., no
- // other types of preferences).
- static PrefService* CreateUserPrefService(const FilePath& pref_filename);
-
- // This constructor is primarily used by tests. The |pref_value_store|
- // provides preference values.
- explicit PrefService(PrefValueStore* pref_value_store);
-
virtual ~PrefService();
// Reloads the data from file. This should only be called when the importer
@@ -142,7 +139,7 @@ class PrefService : public NonThreadSafe {
void RegisterListPref(const char* path);
void RegisterDictionaryPref(const char* path);
- // These varients use a default value from the locale dll instead.
+ // These variants use a default value from the locale dll instead.
void RegisterLocalizedBooleanPref(const char* path,
int locale_default_message_id);
void RegisterLocalizedIntegerPref(const char* path,
@@ -218,23 +215,45 @@ class PrefService : public NonThreadSafe {
// preference is not registered.
const Preference* FindPreference(const char* pref_name) const;
+<<<<<<< HEAD
bool read_only() const { return pref_value_store_->ReadOnly(); }
#ifndef ANDROID
PrefNotifier* pref_notifier() const { return pref_notifier_.get(); }
#endif
+=======
+ bool ReadOnly() const;
+>>>>>>> chromium.org at r10.0.621.0
- PrefValueStore* pref_value_store() const { return pref_value_store_.get(); }
+ // TODO(mnissler): This should not be public. Change client code to call a
+ // preference setter or use ScopedPrefUpdate.
+ PrefNotifier* pref_notifier() const;
#ifndef ANDROID
protected:
+ // Construct a new pref service, specifying the pref sources as explicit
+ // PrefStore pointers. This constructor is what CreatePrefService() ends up
+ // calling. It's also used for unit tests.
+ PrefService(PrefStore* managed_platform_prefs,
+ PrefStore* device_management_prefs,
+ PrefStore* extension_prefs,
+ PrefStore* command_line_prefs,
+ PersistentPrefStore* user_prefs,
+ PrefStore* recommended_prefs);
+
// The PrefNotifier handles registering and notifying preference observers.
// It is created and owned by this PrefService. Subclasses may access it for
// unit testing.
+<<<<<<< HEAD
scoped_ptr<PrefNotifier> pref_notifier_;
#endif
+=======
+ scoped_ptr<PrefNotifierImpl> pref_notifier_;
+>>>>>>> chromium.org at r10.0.621.0
private:
+ friend class PrefServiceMockBuilder;
+
// Registration of pref change observers must be done using the
// PrefChangeRegistrar, which is declared as a friend here to grant it
// access to the otherwise protected members Add/RemovePrefObserver.
@@ -257,17 +276,10 @@ class PrefService : public NonThreadSafe {
// false. This method takes ownership of |default_value|.
void RegisterPreference(const char* path, Value* default_value);
- // Returns a copy of the current pref value. The caller is responsible for
- // deleting the returned object.
- Value* GetPrefCopy(const char* pref_name);
-
// Sets the value for this pref path in the user pref store and informs the
// PrefNotifier of the change.
void SetUserPrefValue(const char* path, Value* new_value);
- // Load from disk. Returns a non-zero error code on failure.
- PrefStore::PrefReadError LoadPersistentPrefs();
-
// Load preferences from storage, attempting to diagnose and handle errors.
// This should only be called from the constructor.
void InitFromStorage();
@@ -276,6 +288,12 @@ class PrefService : public NonThreadSafe {
// and owned by this PrefService. Subclasses may access it for unit testing.
scoped_refptr<PrefValueStore> pref_value_store_;
+ // The persistent pref store used for actual user data.
+ PersistentPrefStore* user_pref_store_;
+
+ // Points to the default pref store we passed to the PrefValueStore.
+ DefaultPrefStore* default_store_;
+
// A set of all the registered Preference objects.
PreferenceSet prefs_;
diff --git a/chrome/browser/prefs/pref_service_mock_builder.cc b/chrome/browser/prefs/pref_service_mock_builder.cc
new file mode 100644
index 0000000..005b700
--- /dev/null
+++ b/chrome/browser/prefs/pref_service_mock_builder.cc
@@ -0,0 +1,103 @@
+// 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.
+
+#include "chrome/browser/prefs/pref_service_mock_builder.h"
+
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/policy/configuration_policy_pref_store.h"
+#include "chrome/browser/prefs/command_line_pref_store.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/prefs/testing_pref_store.h"
+#include "chrome/common/json_pref_store.h"
+
+PrefServiceMockBuilder::PrefServiceMockBuilder()
+ : user_prefs_(new TestingPrefStore) {
+}
+
+PrefServiceMockBuilder&
+PrefServiceMockBuilder::WithManagedPlatformPrefs(PrefStore* store) {
+ managed_platform_prefs_.reset(store);
+ return *this;
+}
+
+PrefServiceMockBuilder&
+PrefServiceMockBuilder::WithDeviceManagementPrefs(PrefStore* store) {
+ device_management_prefs_.reset(store);
+ return *this;
+}
+
+PrefServiceMockBuilder&
+PrefServiceMockBuilder::WithExtensionPrefs(PrefStore* store) {
+ extension_prefs_.reset(store);
+ return *this;
+}
+
+PrefServiceMockBuilder&
+PrefServiceMockBuilder::WithCommandLinePrefs(PrefStore* store) {
+ command_line_prefs_.reset(store);
+ return *this;
+}
+
+PrefServiceMockBuilder&
+PrefServiceMockBuilder::WithUserPrefs(PersistentPrefStore* store) {
+ user_prefs_.reset(store);
+ return *this;
+}
+
+PrefServiceMockBuilder&
+PrefServiceMockBuilder::WithRecommendedPrefs(PrefStore* store) {
+ recommended_prefs_.reset(store);
+ return *this;
+}
+
+PrefServiceMockBuilder&
+PrefServiceMockBuilder::WithManagedPlatformProvider(
+ policy::ConfigurationPolicyProvider* provider) {
+ managed_platform_prefs_.reset(
+ new policy::ConfigurationPolicyPrefStore(provider));
+ return *this;
+}
+
+PrefServiceMockBuilder&
+PrefServiceMockBuilder::WithDeviceManagementProvider(
+ policy::ConfigurationPolicyProvider* provider) {
+ device_management_prefs_.reset(
+ new policy::ConfigurationPolicyPrefStore(provider));
+ return *this;
+}
+
+PrefServiceMockBuilder&
+PrefServiceMockBuilder::WithRecommendedProvider(
+ policy::ConfigurationPolicyProvider* provider) {
+ recommended_prefs_.reset(
+ new policy::ConfigurationPolicyPrefStore(provider));
+ return *this;
+}
+
+PrefServiceMockBuilder&
+PrefServiceMockBuilder::WithCommandLine(CommandLine* command_line) {
+ command_line_prefs_.reset(new CommandLinePrefStore(command_line));
+ return *this;
+}
+
+PrefServiceMockBuilder&
+PrefServiceMockBuilder::WithUserFilePrefs(const FilePath& prefs_file) {
+ user_prefs_.reset(
+ new JsonPrefStore(prefs_file,
+ BrowserThread::GetMessageLoopProxyForThread(
+ BrowserThread::FILE)));
+ return *this;
+}
+
+PrefService* PrefServiceMockBuilder::Create() {
+ PrefService* pref_service =
+ new PrefService(managed_platform_prefs_.release(),
+ device_management_prefs_.release(),
+ extension_prefs_.release(),
+ command_line_prefs_.release(),
+ user_prefs_.release(),
+ recommended_prefs_.release());
+ user_prefs_.reset(new TestingPrefStore);
+ return pref_service;
+}
diff --git a/chrome/browser/prefs/pref_service_mock_builder.h b/chrome/browser/prefs/pref_service_mock_builder.h
new file mode 100644
index 0000000..b8e3275
--- /dev/null
+++ b/chrome/browser/prefs/pref_service_mock_builder.h
@@ -0,0 +1,68 @@
+// 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.
+
+#ifndef CHROME_BROWSER_PREFS_PREF_SERVICE_MOCK_BUILDER_H_
+#define CHROME_BROWSER_PREFS_PREF_SERVICE_MOCK_BUILDER_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "chrome/common/persistent_pref_store.h"
+#include "chrome/common/pref_store.h"
+
+class CommandLine;
+class FilePath;
+class PrefService;
+class Profile;
+
+namespace policy {
+class ConfigurationPolicyProvider;
+}
+
+// A helper that allows convenient building of custom PrefServices in tests.
+class PrefServiceMockBuilder {
+ public:
+ PrefServiceMockBuilder();
+
+ // Functions for setting the various parameters of the PrefService to build.
+ // These take ownership of the |store| parameter.
+ PrefServiceMockBuilder& WithManagedPlatformPrefs(PrefStore* store);
+ PrefServiceMockBuilder& WithDeviceManagementPrefs(PrefStore* store);
+ PrefServiceMockBuilder& WithExtensionPrefs(PrefStore* store);
+ PrefServiceMockBuilder& WithCommandLinePrefs(PrefStore* store);
+ PrefServiceMockBuilder& WithUserPrefs(PersistentPrefStore* store);
+ PrefServiceMockBuilder& WithRecommendedPrefs(PrefStore* store);
+
+ // Set up policy pref stores using the given policy provider.
+ PrefServiceMockBuilder& WithManagedPlatformProvider(
+ policy::ConfigurationPolicyProvider* provider);
+ PrefServiceMockBuilder& WithDeviceManagementProvider(
+ policy::ConfigurationPolicyProvider* provider);
+ PrefServiceMockBuilder& WithRecommendedProvider(
+ policy::ConfigurationPolicyProvider* provider);
+
+ // Specifies to use an actual command-line backed command-line pref store.
+ PrefServiceMockBuilder& WithCommandLine(CommandLine* command_line);
+
+ // Specifies to use an actual file-backed user pref store.
+ PrefServiceMockBuilder& WithUserFilePrefs(const FilePath& prefs_file);
+
+ // Sets the profile to pass to the PrefService.
+ PrefServiceMockBuilder& WithRecommendedPrefs(Profile* profile);
+
+ // Creates the PrefService, invalidating the entire builder configuration.
+ PrefService* Create();
+
+ private:
+ scoped_ptr<PrefStore> managed_platform_prefs_;
+ scoped_ptr<PrefStore> device_management_prefs_;
+ scoped_ptr<PrefStore> extension_prefs_;
+ scoped_ptr<PrefStore> command_line_prefs_;
+ scoped_ptr<PersistentPrefStore> user_prefs_;
+ scoped_ptr<PrefStore> recommended_prefs_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrefServiceMockBuilder);
+};
+
+#endif // CHROME_BROWSER_PREFS_PREF_SERVICE_MOCK_BUILDER_H_
diff --git a/chrome/browser/prefs/pref_service_unittest.cc b/chrome/browser/prefs/pref_service_unittest.cc
index e7c737c..1a79708 100644
--- a/chrome/browser/prefs/pref_service_unittest.cc
+++ b/chrome/browser/prefs/pref_service_unittest.cc
@@ -12,15 +12,14 @@
#include "chrome/browser/policy/mock_configuration_policy_provider.h"
#include "chrome/browser/prefs/browser_prefs.h"
#include "chrome/browser/prefs/command_line_pref_store.h"
-#include "chrome/browser/prefs/default_pref_store.h"
-#include "chrome/browser/prefs/dummy_pref_store.h"
#include "chrome/browser/prefs/pref_change_registrar.h"
+#include "chrome/browser/prefs/pref_observer_mock.h"
+#include "chrome/browser/prefs/pref_service_mock_builder.h"
#include "chrome/browser/prefs/pref_value_store.h"
+#include "chrome/browser/prefs/proxy_prefs.h"
+#include "chrome/browser/prefs/testing_pref_store.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
-#include "chrome/common/notification_observer_mock.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_pref_service.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -28,49 +27,6 @@
using testing::_;
using testing::Mock;
-using testing::Pointee;
-using testing::Property;
-
-namespace {
-
-class TestPrefObserver : public NotificationObserver {
- public:
- TestPrefObserver(const PrefService* prefs,
- const std::string& pref_name,
- const std::string& new_pref_value)
- : observer_fired_(false),
- prefs_(prefs),
- pref_name_(pref_name),
- new_pref_value_(new_pref_value) {}
- virtual ~TestPrefObserver() {}
-
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- EXPECT_EQ(type.value, NotificationType::PREF_CHANGED);
- const PrefService* prefs_in = Source<PrefService>(source).ptr();
- EXPECT_EQ(prefs_in, prefs_);
- const std::string* pref_name_in = Details<std::string>(details).ptr();
- EXPECT_EQ(*pref_name_in, pref_name_);
- EXPECT_EQ(new_pref_value_, prefs_in->GetString("homepage"));
- observer_fired_ = true;
- }
-
- bool observer_fired() { return observer_fired_; }
-
- void Reset(const std::string& new_pref_value) {
- observer_fired_ = false;
- new_pref_value_ = new_pref_value;
- }
-
- private:
- bool observer_fired_;
- const PrefService* prefs_;
- const std::string pref_name_;
- std::string new_pref_value_;
-};
-
-} // namespace
// TODO(port): port this test to POSIX.
#if defined(OS_WIN)
@@ -103,33 +59,34 @@ TEST(PrefServiceTest, NoObserverFire) {
const char pref_name[] = "homepage";
prefs.RegisterStringPref(pref_name, std::string());
- const std::string new_pref_value("http://www.google.com/");
- TestPrefObserver obs(&prefs, pref_name, new_pref_value);
-
+ const char new_pref_value[] = "http://www.google.com/";
+ PrefObserverMock obs;
PrefChangeRegistrar registrar;
registrar.Init(&prefs);
registrar.Add(pref_name, &obs);
- // This should fire the checks in TestPrefObserver::Observe.
- prefs.SetString(pref_name, new_pref_value);
- // Make sure the observer was actually fired.
- EXPECT_TRUE(obs.observer_fired());
+ // This should fire the checks in PrefObserverMock::Observe.
+ const StringValue expected_value(new_pref_value);
+ obs.Expect(&prefs, pref_name, &expected_value);
+ prefs.SetString(pref_name, new_pref_value);
+ Mock::VerifyAndClearExpectations(&obs);
// Setting the pref to the same value should not set the pref value a second
// time.
- obs.Reset(new_pref_value);
+ EXPECT_CALL(obs, Observe(_, _, _)).Times(0);
prefs.SetString(pref_name, new_pref_value);
- EXPECT_FALSE(obs.observer_fired());
+ Mock::VerifyAndClearExpectations(&obs);
// Clearing the pref should cause the pref to fire.
- obs.Reset(std::string());
+ const StringValue expected_default_value("");
+ obs.Expect(&prefs, pref_name, &expected_default_value);
prefs.ClearPref(pref_name);
- EXPECT_TRUE(obs.observer_fired());
+ Mock::VerifyAndClearExpectations(&obs);
// Clearing the pref again should not cause the pref to fire.
- obs.Reset(std::string());
+ EXPECT_CALL(obs, Observe(_, _, _)).Times(0);
prefs.ClearPref(pref_name);
- EXPECT_FALSE(obs.observer_fired());
+ Mock::VerifyAndClearExpectations(&obs);
}
TEST(PrefServiceTest, HasPrefPath) {
@@ -157,120 +114,114 @@ TEST(PrefServiceTest, Observers) {
prefs.SetUserPref(pref_name, Value::CreateStringValue("http://www.cnn.com"));
prefs.RegisterStringPref(pref_name, std::string());
- const std::string new_pref_value("http://www.google.com/");
- TestPrefObserver obs(&prefs, pref_name, new_pref_value);
+ const char new_pref_value[] = "http://www.google.com/";
+ const StringValue expected_new_pref_value(new_pref_value);
+ PrefObserverMock obs;
PrefChangeRegistrar registrar;
registrar.Init(&prefs);
registrar.Add(pref_name, &obs);
- // This should fire the checks in TestPrefObserver::Observe.
- prefs.SetString(pref_name, new_pref_value);
- // Make sure the tests were actually run.
- EXPECT_TRUE(obs.observer_fired());
+ // This should fire the checks in PrefObserverMock::Observe.
+ obs.Expect(&prefs, pref_name, &expected_new_pref_value);
+ prefs.SetString(pref_name, new_pref_value);
+ Mock::VerifyAndClearExpectations(&obs);
// Now try adding a second pref observer.
- const std::string new_pref_value2("http://www.youtube.com/");
- obs.Reset(new_pref_value2);
- TestPrefObserver obs2(&prefs, pref_name, new_pref_value2);
+ const char new_pref_value2[] = "http://www.youtube.com/";
+ const StringValue expected_new_pref_value2(new_pref_value2);
+ PrefObserverMock obs2;
+ obs.Expect(&prefs, pref_name, &expected_new_pref_value2);
+ obs2.Expect(&prefs, pref_name, &expected_new_pref_value2);
registrar.Add(pref_name, &obs2);
// This should fire the checks in obs and obs2.
prefs.SetString(pref_name, new_pref_value2);
- EXPECT_TRUE(obs.observer_fired());
- EXPECT_TRUE(obs2.observer_fired());
+ Mock::VerifyAndClearExpectations(&obs);
+ Mock::VerifyAndClearExpectations(&obs2);
// Make sure obs2 still works after removing obs.
registrar.Remove(pref_name, &obs);
- obs.Reset(std::string());
- obs2.Reset(new_pref_value);
+ EXPECT_CALL(obs, Observe(_, _, _)).Times(0);
+ obs2.Expect(&prefs, pref_name, &expected_new_pref_value);
// This should only fire the observer in obs2.
prefs.SetString(pref_name, new_pref_value);
- EXPECT_FALSE(obs.observer_fired());
- EXPECT_TRUE(obs2.observer_fired());
-}
-
-TEST(PrefServiceTest, ProxyFromCommandLineNotPolicy) {
- CommandLine command_line(CommandLine::NO_PROGRAM);
- command_line.AppendSwitch(switches::kProxyAutoDetect);
- TestingPrefService prefs(NULL, NULL, &command_line);
- browser::RegisterUserPrefs(&prefs);
- EXPECT_TRUE(prefs.GetBoolean(prefs::kProxyAutoDetect));
- const PrefService::Preference* pref =
- prefs.FindPreference(prefs::kProxyAutoDetect);
- ASSERT_TRUE(pref);
- EXPECT_FALSE(pref->IsManaged());
+ Mock::VerifyAndClearExpectations(&obs);
+ Mock::VerifyAndClearExpectations(&obs2);
}
TEST(PrefServiceTest, ProxyPolicyOverridesCommandLineOptions) {
CommandLine command_line(CommandLine::NO_PROGRAM);
command_line.AppendSwitchASCII(switches::kProxyBypassList, "123");
- command_line.AppendSwitchASCII(switches::kProxyPacUrl, "456");
command_line.AppendSwitchASCII(switches::kProxyServer, "789");
scoped_ptr<policy::MockConfigurationPolicyProvider> provider(
new policy::MockConfigurationPolicyProvider());
Value* mode_value = Value::CreateIntegerValue(
policy::kPolicyManuallyConfiguredProxyMode);
- provider->AddPolicy(policy::kPolicyProxyServerMode, mode_value);
+ provider->AddPolicy(policy::kPolicyProxyMode, mode_value);
provider->AddPolicy(policy::kPolicyProxyBypassList,
Value::CreateStringValue("abc"));
- provider->AddPolicy(policy::kPolicyProxyPacUrl,
- Value::CreateStringValue("def"));
provider->AddPolicy(policy::kPolicyProxyServer,
Value::CreateStringValue("ghi"));
// First verify that command-line options are set correctly when
// there is no policy in effect.
- TestingPrefService prefs(NULL, NULL, &command_line);
- browser::RegisterUserPrefs(&prefs);
- EXPECT_FALSE(prefs.GetBoolean(prefs::kProxyAutoDetect));
- EXPECT_FALSE(prefs.GetBoolean(prefs::kNoProxyServer));
- EXPECT_EQ("789", prefs.GetString(prefs::kProxyServer));
- EXPECT_EQ("456", prefs.GetString(prefs::kProxyPacUrl));
- EXPECT_EQ("123", prefs.GetString(prefs::kProxyBypassList));
+ PrefServiceMockBuilder builder;
+ builder.WithCommandLine(&command_line);
+ scoped_ptr<PrefService> prefs(builder.Create());
+ browser::RegisterUserPrefs(prefs.get());
+ EXPECT_EQ(ProxyPrefs::MODE_FIXED_SERVERS,
+ prefs->GetInteger(prefs::kProxyMode));
+ EXPECT_EQ("789", prefs->GetString(prefs::kProxyServer));
+ EXPECT_EQ(std::string(), prefs->GetString(prefs::kProxyPacUrl));
+ EXPECT_EQ("123", prefs->GetString(prefs::kProxyBypassList));
// Try a second time time with the managed PrefStore in place, the
// manual proxy policy should have removed all traces of the command
// line and replaced them with the policy versions.
- TestingPrefService prefs2(provider.get(), NULL, &command_line);
- browser::RegisterUserPrefs(&prefs2);
- EXPECT_FALSE(prefs2.GetBoolean(prefs::kProxyAutoDetect));
- EXPECT_FALSE(prefs2.GetBoolean(prefs::kNoProxyServer));
- EXPECT_EQ("ghi", prefs2.GetString(prefs::kProxyServer));
- EXPECT_EQ("def", prefs2.GetString(prefs::kProxyPacUrl));
- EXPECT_EQ("abc", prefs2.GetString(prefs::kProxyBypassList));
+ builder.WithCommandLine(&command_line);
+ builder.WithManagedPlatformProvider(provider.get());
+ scoped_ptr<PrefService> prefs2(builder.Create());
+ browser::RegisterUserPrefs(prefs2.get());
+ EXPECT_EQ(ProxyPrefs::MODE_FIXED_SERVERS,
+ prefs2->GetInteger(prefs::kProxyMode));
+ EXPECT_EQ("ghi", prefs2->GetString(prefs::kProxyServer));
+ EXPECT_EQ(std::string(), prefs2->GetString(prefs::kProxyPacUrl));
+ EXPECT_EQ("abc", prefs2->GetString(prefs::kProxyBypassList));
}
TEST(PrefServiceTest, ProxyPolicyOverridesUnrelatedCommandLineOptions) {
CommandLine command_line(CommandLine::NO_PROGRAM);
command_line.AppendSwitchASCII(switches::kProxyBypassList, "123");
- command_line.AppendSwitchASCII(switches::kProxyPacUrl, "456");
command_line.AppendSwitchASCII(switches::kProxyServer, "789");
scoped_ptr<policy::MockConfigurationPolicyProvider> provider(
new policy::MockConfigurationPolicyProvider());
Value* mode_value = Value::CreateIntegerValue(
- policy::kPolicyUseSystemProxyMode);
- provider->AddPolicy(policy::kPolicyProxyServerMode, mode_value);
+ policy::kPolicyAutoDetectProxyMode);
+ provider->AddPolicy(policy::kPolicyProxyMode, mode_value);
// First verify that command-line options are set correctly when
// there is no policy in effect.
- TestingPrefService prefs(NULL, NULL, &command_line);
- browser::RegisterUserPrefs(&prefs);
- EXPECT_FALSE(prefs.GetBoolean(prefs::kProxyAutoDetect));
- EXPECT_FALSE(prefs.GetBoolean(prefs::kNoProxyServer));
- EXPECT_EQ("789", prefs.GetString(prefs::kProxyServer));
- EXPECT_EQ("456", prefs.GetString(prefs::kProxyPacUrl));
- EXPECT_EQ("123", prefs.GetString(prefs::kProxyBypassList));
+ PrefServiceMockBuilder builder;
+ builder.WithCommandLine(&command_line);
+ scoped_ptr<PrefService> prefs(builder.Create());
+ browser::RegisterUserPrefs(prefs.get());
+ EXPECT_EQ(ProxyPrefs::MODE_FIXED_SERVERS,
+ prefs->GetInteger(prefs::kProxyMode));
+ EXPECT_EQ("789", prefs->GetString(prefs::kProxyServer));
+ EXPECT_EQ("123", prefs->GetString(prefs::kProxyBypassList));
// Try a second time time with the managed PrefStore in place, the
// no proxy policy should have removed all traces of the command
// line proxy settings, even though they were not the specific one
// set in policy.
- TestingPrefService prefs2(provider.get(), NULL, &command_line);
- browser::RegisterUserPrefs(&prefs2);
- EXPECT_FALSE(prefs2.GetBoolean(prefs::kProxyAutoDetect));
- EXPECT_FALSE(prefs2.GetBoolean(prefs::kNoProxyServer));
- EXPECT_EQ(std::string(), prefs2.GetString(prefs::kProxyServer));
- EXPECT_EQ(std::string(), prefs2.GetString(prefs::kProxyPacUrl));
- EXPECT_EQ(std::string(), prefs2.GetString(prefs::kProxyBypassList));
+ builder.WithCommandLine(&command_line);
+ builder.WithManagedPlatformProvider(provider.get());
+ scoped_ptr<PrefService> prefs2(builder.Create());
+ browser::RegisterUserPrefs(prefs2.get());
+ EXPECT_EQ(ProxyPrefs::MODE_AUTO_DETECT,
+ prefs2->GetInteger(prefs::kProxyMode));
+ EXPECT_EQ(std::string(), prefs2->GetString(prefs::kProxyServer));
+ EXPECT_EQ(std::string(), prefs2->GetString(prefs::kProxyPacUrl));
+ EXPECT_EQ(std::string(), prefs2->GetString(prefs::kProxyBypassList));
}
TEST(PrefServiceTest, ProxyPolicyOverridesCommandLineNoProxy) {
@@ -280,28 +231,31 @@ TEST(PrefServiceTest, ProxyPolicyOverridesCommandLineNoProxy) {
new policy::MockConfigurationPolicyProvider());
Value* mode_value = Value::CreateIntegerValue(
policy::kPolicyAutoDetectProxyMode);
- provider->AddPolicy(policy::kPolicyProxyServerMode, mode_value);
+ provider->AddPolicy(policy::kPolicyProxyMode, mode_value);
// First verify that command-line options are set correctly when
// there is no policy in effect.
- TestingPrefService prefs(NULL, NULL, &command_line);
- browser::RegisterUserPrefs(&prefs);
- EXPECT_FALSE(prefs.GetBoolean(prefs::kProxyAutoDetect));
- EXPECT_TRUE(prefs.GetBoolean(prefs::kNoProxyServer));
- EXPECT_EQ(std::string(), prefs.GetString(prefs::kProxyServer));
- EXPECT_EQ(std::string(), prefs.GetString(prefs::kProxyPacUrl));
- EXPECT_EQ(std::string(), prefs.GetString(prefs::kProxyBypassList));
+ PrefServiceMockBuilder builder;
+ builder.WithCommandLine(&command_line);
+ scoped_ptr<PrefService> prefs(builder.Create());
+ browser::RegisterUserPrefs(prefs.get());
+ EXPECT_EQ(ProxyPrefs::MODE_DIRECT, prefs->GetInteger(prefs::kProxyMode));
+ EXPECT_EQ(std::string(), prefs->GetString(prefs::kProxyServer));
+ EXPECT_EQ(std::string(), prefs->GetString(prefs::kProxyPacUrl));
+ EXPECT_EQ(std::string(), prefs->GetString(prefs::kProxyBypassList));
// Try a second time time with the managed PrefStore in place, the
// auto-detect should be overridden. The default pref store must be
// in place with the appropriate default value for this to work.
- TestingPrefService prefs2(provider.get(), NULL, &command_line);
- browser::RegisterUserPrefs(&prefs2);
- EXPECT_TRUE(prefs2.GetBoolean(prefs::kProxyAutoDetect));
- EXPECT_FALSE(prefs2.GetBoolean(prefs::kNoProxyServer));
- EXPECT_EQ(std::string(), prefs2.GetString(prefs::kProxyServer));
- EXPECT_EQ(std::string(), prefs2.GetString(prefs::kProxyPacUrl));
- EXPECT_EQ(std::string(), prefs2.GetString(prefs::kProxyBypassList));
+ builder.WithCommandLine(&command_line);
+ builder.WithManagedPlatformProvider(provider.get());
+ scoped_ptr<PrefService> prefs2(builder.Create());
+ browser::RegisterUserPrefs(prefs2.get());
+ EXPECT_EQ(ProxyPrefs::MODE_AUTO_DETECT,
+ prefs2->GetInteger(prefs::kProxyMode));
+ EXPECT_EQ(std::string(), prefs2->GetString(prefs::kProxyServer));
+ EXPECT_EQ(std::string(), prefs2->GetString(prefs::kProxyPacUrl));
+ EXPECT_EQ(std::string(), prefs2->GetString(prefs::kProxyBypassList));
}
TEST(PrefServiceTest, ProxyPolicyOverridesCommandLineAutoDetect) {
@@ -311,28 +265,30 @@ TEST(PrefServiceTest, ProxyPolicyOverridesCommandLineAutoDetect) {
new policy::MockConfigurationPolicyProvider());
Value* mode_value = Value::CreateIntegerValue(
policy::kPolicyNoProxyServerMode);
- provider->AddPolicy(policy::kPolicyProxyServerMode, mode_value);
+ provider->AddPolicy(policy::kPolicyProxyMode, mode_value);
// First verify that the auto-detect is set if there is no managed
// PrefStore.
- TestingPrefService prefs(NULL, NULL, &command_line);
- browser::RegisterUserPrefs(&prefs);
- EXPECT_TRUE(prefs.GetBoolean(prefs::kProxyAutoDetect));
- EXPECT_FALSE(prefs.GetBoolean(prefs::kNoProxyServer));
- EXPECT_EQ(std::string(), prefs.GetString(prefs::kProxyServer));
- EXPECT_EQ(std::string(), prefs.GetString(prefs::kProxyPacUrl));
- EXPECT_EQ(std::string(), prefs.GetString(prefs::kProxyBypassList));
+ PrefServiceMockBuilder builder;
+ builder.WithCommandLine(&command_line);
+ scoped_ptr<PrefService> prefs(builder.Create());
+ browser::RegisterUserPrefs(prefs.get());
+ EXPECT_EQ(ProxyPrefs::MODE_AUTO_DETECT, prefs->GetInteger(prefs::kProxyMode));
+ EXPECT_EQ(std::string(), prefs->GetString(prefs::kProxyServer));
+ EXPECT_EQ(std::string(), prefs->GetString(prefs::kProxyPacUrl));
+ EXPECT_EQ(std::string(), prefs->GetString(prefs::kProxyBypassList));
// Try a second time time with the managed PrefStore in place, the
// auto-detect should be overridden. The default pref store must be
// in place with the appropriate default value for this to work.
- TestingPrefService prefs2(provider.get(), NULL, &command_line);
- browser::RegisterUserPrefs(&prefs2);
- EXPECT_FALSE(prefs2.GetBoolean(prefs::kProxyAutoDetect));
- EXPECT_TRUE(prefs2.GetBoolean(prefs::kNoProxyServer));
- EXPECT_EQ(std::string(), prefs2.GetString(prefs::kProxyServer));
- EXPECT_EQ(std::string(), prefs2.GetString(prefs::kProxyPacUrl));
- EXPECT_EQ(std::string(), prefs2.GetString(prefs::kProxyBypassList));
+ builder.WithCommandLine(&command_line);
+ builder.WithManagedPlatformProvider(provider.get());
+ scoped_ptr<PrefService> prefs2(builder.Create());
+ browser::RegisterUserPrefs(prefs2.get());
+ EXPECT_EQ(ProxyPrefs::MODE_DIRECT, prefs2->GetInteger(prefs::kProxyMode));
+ EXPECT_EQ(std::string(), prefs2->GetString(prefs::kProxyServer));
+ EXPECT_EQ(std::string(), prefs2->GetString(prefs::kProxyPacUrl));
+ EXPECT_EQ(std::string(), prefs2->GetString(prefs::kProxyBypassList));
}
class PrefServiceSetValueTest : public testing::Test {
@@ -341,24 +297,11 @@ class PrefServiceSetValueTest : public testing::Test {
static const char kValue[];
PrefServiceSetValueTest()
- : name_string_(kName),
- null_value_(Value::CreateNullValue()) {}
-
- void SetExpectNoNotification() {
- EXPECT_CALL(observer_, Observe(_, _, _)).Times(0);
- }
-
- void SetExpectPrefChanged() {
- EXPECT_CALL(observer_,
- Observe(NotificationType(NotificationType::PREF_CHANGED), _,
- Property(&Details<std::string>::ptr,
- Pointee(name_string_))));
- }
+ : null_value_(Value::CreateNullValue()) {}
TestingPrefService prefs_;
- std::string name_string_;
scoped_ptr<Value> null_value_;
- NotificationObserverMock observer_;
+ PrefObserverMock observer_;
};
const char PrefServiceSetValueTest::kName[] = "name";
@@ -366,8 +309,7 @@ const char PrefServiceSetValueTest::kValue[] = "value";
TEST_F(PrefServiceSetValueTest, SetStringValue) {
const char default_string[] = "default";
- const scoped_ptr<Value> default_value(
- Value::CreateStringValue(default_string));
+ const StringValue default_value(default_string);
prefs_.RegisterStringPref(kName, default_string);
PrefChangeRegistrar registrar;
@@ -375,18 +317,18 @@ TEST_F(PrefServiceSetValueTest, SetStringValue) {
registrar.Add(kName, &observer_);
// Changing the controlling store from default to user triggers notification.
- SetExpectPrefChanged();
- prefs_.Set(kName, *default_value);
+ observer_.Expect(&prefs_, kName, &default_value);
+ prefs_.Set(kName, default_value);
Mock::VerifyAndClearExpectations(&observer_);
- SetExpectNoNotification();
- prefs_.Set(kName, *default_value);
+ EXPECT_CALL(observer_, Observe(_, _, _)).Times(0);
+ prefs_.Set(kName, default_value);
Mock::VerifyAndClearExpectations(&observer_);
- const scoped_ptr<Value> new_value(Value::CreateStringValue(kValue));
- SetExpectPrefChanged();
- prefs_.Set(kName, *new_value);
- EXPECT_EQ(kValue, prefs_.GetString(kName));
+ StringValue new_value(kValue);
+ observer_.Expect(&prefs_, kName, &new_value);
+ prefs_.Set(kName, new_value);
+ Mock::VerifyAndClearExpectations(&observer_);
}
TEST_F(PrefServiceSetValueTest, SetDictionaryValue) {
@@ -397,30 +339,23 @@ TEST_F(PrefServiceSetValueTest, SetDictionaryValue) {
// Dictionary values are special: setting one to NULL is the same as clearing
// the user value, allowing the NULL default to take (or keep) control.
- SetExpectNoNotification();
+ EXPECT_CALL(observer_, Observe(_, _, _)).Times(0);
prefs_.Set(kName, *null_value_);
Mock::VerifyAndClearExpectations(&observer_);
DictionaryValue new_value;
new_value.SetString(kName, kValue);
- SetExpectPrefChanged();
+ observer_.Expect(&prefs_, kName, &new_value);
prefs_.Set(kName, new_value);
Mock::VerifyAndClearExpectations(&observer_);
- DictionaryValue* dict = prefs_.GetMutableDictionary(kName);
- EXPECT_EQ(1U, dict->size());
- std::string out_value;
- dict->GetString(kName, &out_value);
- EXPECT_EQ(kValue, out_value);
- SetExpectNoNotification();
+ EXPECT_CALL(observer_, Observe(_, _, _)).Times(0);
prefs_.Set(kName, new_value);
Mock::VerifyAndClearExpectations(&observer_);
- SetExpectPrefChanged();
+ observer_.Expect(&prefs_, kName, null_value_.get());
prefs_.Set(kName, *null_value_);
Mock::VerifyAndClearExpectations(&observer_);
- dict = prefs_.GetMutableDictionary(kName);
- EXPECT_EQ(0U, dict->size());
}
TEST_F(PrefServiceSetValueTest, SetListValue) {
@@ -431,28 +366,21 @@ TEST_F(PrefServiceSetValueTest, SetListValue) {
// List values are special: setting one to NULL is the same as clearing the
// user value, allowing the NULL default to take (or keep) control.
- SetExpectNoNotification();
+ EXPECT_CALL(observer_, Observe(_, _, _)).Times(0);
prefs_.Set(kName, *null_value_);
Mock::VerifyAndClearExpectations(&observer_);
ListValue new_value;
new_value.Append(Value::CreateStringValue(kValue));
- SetExpectPrefChanged();
+ observer_.Expect(&prefs_, kName, &new_value);
prefs_.Set(kName, new_value);
Mock::VerifyAndClearExpectations(&observer_);
- const ListValue* list = prefs_.GetMutableList(kName);
- ASSERT_EQ(1U, list->GetSize());
- std::string out_value;
- list->GetString(0, &out_value);
- EXPECT_EQ(kValue, out_value);
- SetExpectNoNotification();
+ EXPECT_CALL(observer_, Observe(_, _, _)).Times(0);
prefs_.Set(kName, new_value);
Mock::VerifyAndClearExpectations(&observer_);
- SetExpectPrefChanged();
+ observer_.Expect(&prefs_, kName, null_value_.get());
prefs_.Set(kName, *null_value_);
Mock::VerifyAndClearExpectations(&observer_);
- list = prefs_.GetMutableList(kName);
- EXPECT_EQ(0U, list->GetSize());
}
diff --git a/chrome/browser/prefs/pref_set_observer.cc b/chrome/browser/prefs/pref_set_observer.cc
index a073eb2..133b219 100644
--- a/chrome/browser/prefs/pref_set_observer.cc
+++ b/chrome/browser/prefs/pref_set_observer.cc
@@ -47,8 +47,7 @@ PrefSetObserver* PrefSetObserver::CreateProxyPrefSetObserver(
PrefService* pref_service,
NotificationObserver* observer) {
PrefSetObserver* pref_set = new PrefSetObserver(pref_service, observer);
- pref_set->AddPref(prefs::kNoProxyServer);
- pref_set->AddPref(prefs::kProxyAutoDetect);
+ pref_set->AddPref(prefs::kProxyMode);
pref_set->AddPref(prefs::kProxyServer);
pref_set->AddPref(prefs::kProxyPacUrl);
pref_set->AddPref(prefs::kProxyBypassList);
diff --git a/chrome/browser/prefs/pref_value_map.cc b/chrome/browser/prefs/pref_value_map.cc
new file mode 100644
index 0000000..6e7bf79
--- /dev/null
+++ b/chrome/browser/prefs/pref_value_map.cc
@@ -0,0 +1,107 @@
+// 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.
+
+#include "chrome/browser/prefs/pref_value_map.h"
+
+#include "base/logging.h"
+#include "base/scoped_ptr.h"
+#include "base/stl_util-inl.h"
+#include "base/values.h"
+
+PrefValueMap::PrefValueMap() {}
+
+PrefValueMap::~PrefValueMap() {
+ Clear();
+}
+
+bool PrefValueMap::GetValue(const std::string& key, Value** value) const {
+ const Map::const_iterator entry = prefs_.find(key);
+ if (entry != prefs_.end()) {
+ if (value)
+ *value = entry->second;
+ return true;
+ }
+
+ return false;
+}
+
+bool PrefValueMap::SetValue(const std::string& key, Value* value) {
+ DCHECK(value);
+ scoped_ptr<Value> value_ptr(value);
+ const Map::iterator entry = prefs_.find(key);
+ if (entry != prefs_.end()) {
+ if (Value::Equals(entry->second, value))
+ return false;
+ delete entry->second;
+ entry->second = value_ptr.release();
+ } else {
+ prefs_[key] = value_ptr.release();
+ }
+
+ return true;
+}
+
+bool PrefValueMap::RemoveValue(const std::string& key) {
+ const Map::iterator entry = prefs_.find(key);
+ if (entry != prefs_.end()) {
+ delete entry->second;
+ prefs_.erase(entry);
+ return true;
+ }
+
+ return false;
+}
+
+void PrefValueMap::Clear() {
+ STLDeleteValues(&prefs_);
+ prefs_.clear();
+}
+
+bool PrefValueMap::GetBoolean(const std::string& key,
+ bool* value) const {
+ Value* stored_value = NULL;
+ return GetValue(key, &stored_value) && stored_value->GetAsBoolean(value);
+}
+
+bool PrefValueMap::GetString(const std::string& key,
+ std::string* value) const {
+ Value* stored_value = NULL;
+ return GetValue(key, &stored_value) && stored_value->GetAsString(value);
+}
+
+void PrefValueMap::SetString(const std::string& key,
+ const std::string& value) {
+ SetValue(key, Value::CreateStringValue(value));
+}
+
+void PrefValueMap::GetDifferingKeys(
+ const PrefValueMap* other,
+ std::vector<std::string>* differing_keys) const {
+ differing_keys->clear();
+
+ // Walk over the maps in lockstep, adding everything that is different.
+ Map::const_iterator this_pref(prefs_.begin());
+ Map::const_iterator other_pref(other->prefs_.begin());
+ while (this_pref != prefs_.end() && other_pref != other->prefs_.end()) {
+ const int diff = this_pref->first.compare(other_pref->first);
+ if (diff == 0) {
+ if (!this_pref->second->Equals(other_pref->second))
+ differing_keys->push_back(this_pref->first);
+ ++this_pref;
+ ++other_pref;
+ } else if (diff < 0) {
+ differing_keys->push_back(this_pref->first);
+ ++this_pref;
+ } else if (diff > 0) {
+ differing_keys->push_back(other_pref->first);
+ ++other_pref;
+ }
+ }
+
+ // Add the remaining entries.
+ for ( ; this_pref != prefs_.end(); ++this_pref)
+ differing_keys->push_back(this_pref->first);
+ for ( ; other_pref != other->prefs_.end(); ++other_pref)
+ differing_keys->push_back(other_pref->first);
+}
diff --git a/chrome/browser/prefs/pref_value_map.h b/chrome/browser/prefs/pref_value_map.h
new file mode 100644
index 0000000..0e99920
--- /dev/null
+++ b/chrome/browser/prefs/pref_value_map.h
@@ -0,0 +1,64 @@
+// 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.
+
+#ifndef CHROME_BROWSER_PREFS_PREF_VALUE_MAP_H_
+#define CHROME_BROWSER_PREFS_PREF_VALUE_MAP_H_
+#pragma once
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+
+class Value;
+
+// A generic string to value map used by the PrefStore implementations.
+class PrefValueMap {
+ public:
+ PrefValueMap();
+ virtual ~PrefValueMap();
+
+ // Gets the value for |key| and stores it in |value|. Ownership remains with
+ // the map. Returns true if a value is present. If not, |value| is not
+ // touched.
+ bool GetValue(const std::string& key, Value** value) const;
+
+ // Sets a new |value| for |key|. Takes ownership of |value|, which must be
+ // non-NULL. Returns true if the value changed.
+ bool SetValue(const std::string& key, Value* value);
+
+ // Removes the value for |key| from the map. Returns true if a value was
+ // removed.
+ bool RemoveValue(const std::string& key);
+
+ // Clears the map.
+ void Clear();
+
+ // Gets a boolean value for |key| and stores it in |value|. Returns true if
+ // the value was found and of the proper type.
+ bool GetBoolean(const std::string& key, bool* value) const;
+
+ // Gets a string value for |key| and stores it in |value|. Returns true if
+ // the value was found and of the proper type.
+ bool GetString(const std::string& key, std::string* value) const;
+
+ // Sets the value for |key| to the string |value|.
+ void SetString(const std::string& key, const std::string& value);
+
+ // Compares this value map against |other| and stores all key names that have
+ // different values in |differing_keys|. This includes keys that are present
+ // only in one of the maps.
+ void GetDifferingKeys(const PrefValueMap* other,
+ std::vector<std::string>* differing_keys) const;
+
+ private:
+ typedef std::map<std::string, Value*> Map;
+
+ Map prefs_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrefValueMap);
+};
+
+#endif // CHROME_BROWSER_PREFS_PREF_VALUE_MAP_H_
diff --git a/chrome/browser/prefs/pref_value_map_unittest.cc b/chrome/browser/prefs/pref_value_map_unittest.cc
new file mode 100644
index 0000000..5e248b0
--- /dev/null
+++ b/chrome/browser/prefs/pref_value_map_unittest.cc
@@ -0,0 +1,76 @@
+// 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.
+
+#include "base/values.h"
+#include "chrome/browser/prefs/pref_value_map.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class PrefValueMapTest : public testing::Test {
+};
+
+TEST_F(PrefValueMapTest, SetValue) {
+ PrefValueMap map;
+ Value* result = NULL;
+ EXPECT_FALSE(map.GetValue("key", &result));
+ EXPECT_FALSE(result);
+
+ EXPECT_TRUE(map.SetValue("key", Value::CreateStringValue("test")));
+ EXPECT_FALSE(map.SetValue("key", Value::CreateStringValue("test")));
+ EXPECT_TRUE(map.SetValue("key", Value::CreateStringValue("hi mom!")));
+
+ EXPECT_TRUE(map.GetValue("key", &result));
+ EXPECT_TRUE(StringValue("hi mom!").Equals(result));
+}
+
+TEST_F(PrefValueMapTest, RemoveValue) {
+ PrefValueMap map;
+ EXPECT_FALSE(map.RemoveValue("key"));
+
+ EXPECT_TRUE(map.SetValue("key", Value::CreateStringValue("test")));
+ EXPECT_TRUE(map.GetValue("key", NULL));
+
+ EXPECT_TRUE(map.RemoveValue("key"));
+ EXPECT_FALSE(map.GetValue("key", NULL));
+
+ EXPECT_FALSE(map.RemoveValue("key"));
+}
+
+TEST_F(PrefValueMapTest, Clear) {
+ PrefValueMap map;
+ EXPECT_TRUE(map.SetValue("key", Value::CreateStringValue("test")));
+ EXPECT_TRUE(map.GetValue("key", NULL));
+
+ map.Clear();
+
+ EXPECT_FALSE(map.GetValue("key", NULL));
+}
+
+TEST_F(PrefValueMapTest, GetDifferingKeys) {
+ PrefValueMap reference;
+ EXPECT_TRUE(reference.SetValue("b", Value::CreateStringValue("test")));
+ EXPECT_TRUE(reference.SetValue("c", Value::CreateStringValue("test")));
+ EXPECT_TRUE(reference.SetValue("e", Value::CreateStringValue("test")));
+
+ PrefValueMap check;
+ std::vector<std::string> differing_paths;
+ std::vector<std::string> expected_differing_paths;
+
+ reference.GetDifferingKeys(&check, &differing_paths);
+ expected_differing_paths.push_back("b");
+ expected_differing_paths.push_back("c");
+ expected_differing_paths.push_back("e");
+ EXPECT_EQ(expected_differing_paths, differing_paths);
+
+ EXPECT_TRUE(check.SetValue("a", Value::CreateStringValue("test")));
+ EXPECT_TRUE(check.SetValue("c", Value::CreateStringValue("test")));
+ EXPECT_TRUE(check.SetValue("d", Value::CreateStringValue("test")));
+
+ reference.GetDifferingKeys(&check, &differing_paths);
+ expected_differing_paths.clear();
+ expected_differing_paths.push_back("a");
+ expected_differing_paths.push_back("b");
+ expected_differing_paths.push_back("d");
+ expected_differing_paths.push_back("e");
+ EXPECT_EQ(expected_differing_paths, differing_paths);
+}
diff --git a/chrome/browser/prefs/pref_value_store.cc b/chrome/browser/prefs/pref_value_store.cc
index ee23b3b..431e55f 100644
--- a/chrome/browser/prefs/pref_value_store.cc
+++ b/chrome/browser/prefs/pref_value_store.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/prefs/pref_value_store.h"
+<<<<<<< HEAD
#ifndef ANDROID
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/extensions/extension_pref_store.h"
@@ -15,26 +16,34 @@
#include "chrome/common/json_pref_store.h"
#include "chrome/common/notification_service.h"
#endif
+=======
+#include "chrome/browser/prefs/pref_notifier.h"
+>>>>>>> chromium.org at r10.0.621.0
-namespace {
+PrefValueStore::PrefStoreKeeper::PrefStoreKeeper()
+ : pref_value_store_(NULL),
+ type_(PrefValueStore::INVALID_STORE) {
+}
-// Returns true if the actual value is a valid type for the expected type when
-// found in the given store.
-bool IsValidType(Value::ValueType expected, Value::ValueType actual,
- PrefNotifier::PrefStoreType store) {
- if (expected == actual)
- return true;
+PrefValueStore::PrefStoreKeeper::~PrefStoreKeeper() {
+ if (pref_store_.get())
+ pref_store_->RemoveObserver(this);
+}
- // Dictionaries and lists are allowed to hold TYPE_NULL values too, but only
- // in the default pref store.
- if (store == PrefNotifier::DEFAULT_STORE &&
- actual == Value::TYPE_NULL &&
- (expected == Value::TYPE_DICTIONARY || expected == Value::TYPE_LIST)) {
- return true;
- }
- return false;
+void PrefValueStore::PrefStoreKeeper::Initialize(
+ PrefValueStore* store,
+ PrefStore* pref_store,
+ PrefValueStore::PrefStoreType type) {
+ if (pref_store_.get())
+ pref_store_->RemoveObserver(this);
+ type_ = type;
+ pref_value_store_ = store;
+ pref_store_.reset(pref_store);
+ if (pref_store_.get())
+ pref_store_->AddObserver(this);
}
+<<<<<<< HEAD
} // namespace
// static
@@ -73,6 +82,35 @@ PrefValueStore* PrefValueStore::CreatePrefValueStore(
command_line, user, recommended, default_store,
profile);
#endif
+=======
+void PrefValueStore::PrefStoreKeeper::OnPrefValueChanged(
+ const std::string& key) {
+ pref_value_store_->OnPrefValueChanged(type_, key);
+}
+
+void PrefValueStore::PrefStoreKeeper::OnInitializationCompleted() {
+ pref_value_store_->OnInitializationCompleted(type_);
+}
+
+PrefValueStore::PrefValueStore(PrefStore* managed_platform_prefs,
+ PrefStore* device_management_prefs,
+ PrefStore* extension_prefs,
+ PrefStore* command_line_prefs,
+ PrefStore* user_prefs,
+ PrefStore* recommended_prefs,
+ PrefStore* default_prefs,
+ PrefNotifier* pref_notifier)
+ : pref_notifier_(pref_notifier) {
+ InitPrefStore(MANAGED_PLATFORM_STORE, managed_platform_prefs);
+ InitPrefStore(DEVICE_MANAGEMENT_STORE, device_management_prefs);
+ InitPrefStore(EXTENSION_STORE, extension_prefs);
+ InitPrefStore(COMMAND_LINE_STORE, command_line_prefs);
+ InitPrefStore(USER_STORE, user_prefs);
+ InitPrefStore(RECOMMENDED_STORE, recommended_prefs);
+ InitPrefStore(DEFAULT_STORE, default_prefs);
+
+ CheckInitializationCompleted();
+>>>>>>> chromium.org at r10.0.621.0
}
PrefValueStore::~PrefValueStore() {}
@@ -81,20 +119,14 @@ bool PrefValueStore::GetValue(const std::string& name,
Value** out_value) const {
// Check the |PrefStore|s in order of their priority from highest to lowest
// to find the value of the preference described by the given preference name.
- for (size_t i = 0; i <= PrefNotifier::PREF_STORE_TYPE_MAX; ++i) {
- if (GetValueFromStore(name.c_str(),
- static_cast<PrefNotifier::PrefStoreType>(i),
+ for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) {
+ if (GetValueFromStore(name.c_str(), static_cast<PrefStoreType>(i),
out_value))
return true;
}
return false;
}
-bool PrefValueStore::GetUserValue(const std::string& name,
- Value** out_value) const {
- return GetValueFromStore(name.c_str(), PrefNotifier::USER_STORE, out_value);
-}
-
void PrefValueStore::RegisterPreferenceType(const std::string& name,
Value::ValueType type) {
pref_types_[name] = type;
@@ -108,43 +140,6 @@ Value::ValueType PrefValueStore::GetRegisteredType(
return found->second;
}
-bool PrefValueStore::WritePrefs() {
- bool success = true;
- for (size_t i = 0; i <= PrefNotifier::PREF_STORE_TYPE_MAX; ++i) {
- if (pref_stores_[i].get())
- success = pref_stores_[i]->WritePrefs() && success;
- }
- return success;
-}
-
-void PrefValueStore::ScheduleWritePrefs() {
- for (size_t i = 0; i <= PrefNotifier::PREF_STORE_TYPE_MAX; ++i) {
- if (pref_stores_[i].get())
- pref_stores_[i]->ScheduleWritePrefs();
- }
-}
-
-PrefStore::PrefReadError PrefValueStore::ReadPrefs() {
- PrefStore::PrefReadError result = PrefStore::PREF_READ_ERROR_NONE;
- for (size_t i = 0; i <= PrefNotifier::PREF_STORE_TYPE_MAX; ++i) {
- if (pref_stores_[i].get()) {
- PrefStore::PrefReadError this_error = pref_stores_[i]->ReadPrefs();
- if (result == PrefStore::PREF_READ_ERROR_NONE)
- result = this_error;
- }
- }
-
- if (HasPolicyConflictingUserProxySettings()) {
- LOG(WARNING) << "user-requested proxy options have been overridden"
- << " by a proxy configuration specified in a centrally"
- << " administered policy.";
- }
-
- // TODO(markusheintz): Return a better error status: maybe a struct with
- // the error status of all PrefStores.
- return result;
-}
-
bool PrefValueStore::HasPrefPath(const char* path) const {
Value* tmp_value = NULL;
const std::string name(path);
@@ -154,158 +149,112 @@ bool PrefValueStore::HasPrefPath(const char* path) const {
return rv && !PrefValueFromDefaultStore(path);
}
-bool PrefValueStore::PrefHasChanged(const char* path,
- PrefNotifier::PrefStoreType new_store) {
- DCHECK(new_store != PrefNotifier::INVALID_STORE);
- // Replying that the pref has changed may cause problems, but it's the safer
- // choice.
- if (new_store == PrefNotifier::INVALID_STORE)
- return true;
-
- PrefNotifier::PrefStoreType controller = ControllingPrefStoreForPref(path);
- DCHECK(controller != PrefNotifier::INVALID_STORE);
- if (controller == PrefNotifier::INVALID_STORE)
- return true;
-
- // If the pref is controlled by a higher-priority store, its effective value
- // cannot have changed.
- if (controller < new_store)
- return false;
-
- // Otherwise, we take the pref store's word that something changed.
- return true;
-}
-
-// Note the |DictionaryValue| referenced by the |PrefStore| USER_STORE
-// (returned by the method prefs()) takes the ownership of the Value referenced
-// by in_value.
-bool PrefValueStore::SetUserPrefValue(const char* name, Value* in_value) {
- Value* old_value = NULL;
- pref_stores_[PrefNotifier::USER_STORE]->prefs()->Get(name, &old_value);
- bool value_changed = !(old_value && old_value->Equals(in_value));
+void PrefValueStore::NotifyPrefChanged(
+ const char* path,
+ PrefValueStore::PrefStoreType new_store) {
+ DCHECK(new_store != INVALID_STORE);
- pref_stores_[PrefNotifier::USER_STORE]->prefs()->Set(name, in_value);
- return value_changed;
-}
-
-// Note the |DictionaryValue| referenced by the |PrefStore| DEFAULT_STORE
-// (returned by the method prefs()) takes the ownership of the Value referenced
-// by in_value.
-void PrefValueStore::SetDefaultPrefValue(const char* name, Value* in_value) {
- pref_stores_[PrefNotifier::DEFAULT_STORE]->prefs()->Set(name, in_value);
-}
-
-bool PrefValueStore::ReadOnly() {
- return pref_stores_[PrefNotifier::USER_STORE]->ReadOnly();
-}
+ // If this pref is not registered, just discard the notification.
+ if (!pref_types_.count(path))
+ return;
-bool PrefValueStore::RemoveUserPrefValue(const char* name) {
- if (pref_stores_[PrefNotifier::USER_STORE].get()) {
- return pref_stores_[PrefNotifier::USER_STORE]->prefs()->Remove(name, NULL);
+ bool changed = true;
+ // Replying that the pref has changed in case the new store is invalid may
+ // cause problems, but it's the safer choice.
+ if (new_store != INVALID_STORE) {
+ PrefStoreType controller = ControllingPrefStoreForPref(path);
+ DCHECK(controller != INVALID_STORE);
+ // If the pref is controlled by a higher-priority store, its effective value
+ // cannot have changed.
+ if (controller != INVALID_STORE &&
+ controller < new_store) {
+ changed = false;
+ }
}
- return false;
+
+ if (changed)
+ pref_notifier_->OnPreferenceChanged(path);
}
bool PrefValueStore::PrefValueInManagedPlatformStore(const char* name) const {
- return PrefValueInStore(name, PrefNotifier::MANAGED_PLATFORM_STORE);
+ return PrefValueInStore(name, MANAGED_PLATFORM_STORE);
}
bool PrefValueStore::PrefValueInDeviceManagementStore(const char* name) const {
- return PrefValueInStore(name, PrefNotifier::DEVICE_MANAGEMENT_STORE);
+ return PrefValueInStore(name, DEVICE_MANAGEMENT_STORE);
}
bool PrefValueStore::PrefValueInExtensionStore(const char* name) const {
- return PrefValueInStore(name, PrefNotifier::EXTENSION_STORE);
+ return PrefValueInStore(name, EXTENSION_STORE);
}
bool PrefValueStore::PrefValueInUserStore(const char* name) const {
- return PrefValueInStore(name, PrefNotifier::USER_STORE);
-}
-
-bool PrefValueStore::PrefValueInStoreRange(
- const char* name,
- PrefNotifier::PrefStoreType first_checked_store,
- PrefNotifier::PrefStoreType last_checked_store) {
- if (first_checked_store > last_checked_store) {
- NOTREACHED();
- return false;
- }
-
- for (size_t i = first_checked_store;
- i <= static_cast<size_t>(last_checked_store); ++i) {
- if (PrefValueInStore(name, static_cast<PrefNotifier::PrefStoreType>(i)))
- return true;
- }
- return false;
+ return PrefValueInStore(name, USER_STORE);
}
bool PrefValueStore::PrefValueFromExtensionStore(const char* name) const {
- return ControllingPrefStoreForPref(name) == PrefNotifier::EXTENSION_STORE;
+ return ControllingPrefStoreForPref(name) == EXTENSION_STORE;
}
bool PrefValueStore::PrefValueFromUserStore(const char* name) const {
- return ControllingPrefStoreForPref(name) == PrefNotifier::USER_STORE;
+ return ControllingPrefStoreForPref(name) == USER_STORE;
}
bool PrefValueStore::PrefValueFromDefaultStore(const char* name) const {
- return ControllingPrefStoreForPref(name) == PrefNotifier::DEFAULT_STORE;
+ return ControllingPrefStoreForPref(name) == DEFAULT_STORE;
}
bool PrefValueStore::PrefValueUserModifiable(const char* name) const {
- PrefNotifier::PrefStoreType effective_store =
- ControllingPrefStoreForPref(name);
- return effective_store >= PrefNotifier::USER_STORE ||
- effective_store == PrefNotifier::INVALID_STORE;
+ PrefStoreType effective_store = ControllingPrefStoreForPref(name);
+ return effective_store >= USER_STORE ||
+ effective_store == INVALID_STORE;
}
-PrefNotifier::PrefStoreType PrefValueStore::ControllingPrefStoreForPref(
- const char* name) const {
- for (int i = 0; i <= PrefNotifier::PREF_STORE_TYPE_MAX; ++i) {
- if (PrefValueInStore(name, static_cast<PrefNotifier::PrefStoreType>(i)))
- return static_cast<PrefNotifier::PrefStoreType>(i);
+// Returns true if the actual value is a valid type for the expected type when
+// found in the given store.
+bool PrefValueStore::IsValidType(Value::ValueType expected,
+ Value::ValueType actual,
+ PrefValueStore::PrefStoreType store) {
+ if (expected == actual)
+ return true;
+
+ // Dictionaries and lists are allowed to hold TYPE_NULL values too, but only
+ // in the default pref store.
+ if (store == DEFAULT_STORE &&
+ actual == Value::TYPE_NULL &&
+ (expected == Value::TYPE_DICTIONARY || expected == Value::TYPE_LIST)) {
+ return true;
}
- return PrefNotifier::INVALID_STORE;
+ return false;
}
bool PrefValueStore::PrefValueInStore(
const char* name,
- PrefNotifier::PrefStoreType store) const {
+ PrefValueStore::PrefStoreType store) const {
// Declare a temp Value* and call GetValueFromStore,
// ignoring the output value.
Value* tmp_value = NULL;
return GetValueFromStore(name, store, &tmp_value);
}
-bool PrefValueStore::GetValueFromStore(
+bool PrefValueStore::PrefValueInStoreRange(
const char* name,
- PrefNotifier::PrefStoreType store,
- Value** out_value) const {
- // Only return true if we find a value and it is the correct type, so stale
- // values with the incorrect type will be ignored.
- if (pref_stores_[store].get() &&
- pref_stores_[store]->prefs()->Get(name, out_value)) {
- // If the value is the sentinel that redirects to the default
- // store, re-fetch the value from the default store explicitly.
- // Because the default values are not available when creating
- // stores, the default value must be fetched dynamically for every
- // redirect.
- if (PrefStore::IsUseDefaultSentinelValue(*out_value)) {
- DCHECK(pref_stores_[PrefNotifier::DEFAULT_STORE].get());
- if (!pref_stores_[PrefNotifier::DEFAULT_STORE]->prefs()->Get(name,
- out_value)) {
- *out_value = NULL;
- return false;
- }
- store = PrefNotifier::DEFAULT_STORE;
- }
- if (IsValidType(GetRegisteredType(name), (*out_value)->GetType(), store))
+ PrefValueStore::PrefStoreType first_checked_store,
+ PrefValueStore::PrefStoreType last_checked_store) const {
+ if (first_checked_store > last_checked_store) {
+ NOTREACHED();
+ return false;
+ }
+
+ for (size_t i = first_checked_store;
+ i <= static_cast<size_t>(last_checked_store); ++i) {
+ if (PrefValueInStore(name, static_cast<PrefStoreType>(i)))
return true;
}
- // No valid value found for the given preference name: set the return false.
- *out_value = NULL;
return false;
}
+<<<<<<< HEAD
#ifndef ANDROID
void PrefValueStore::RefreshPolicyPrefsOnFileThread(
BrowserThread::ID calling_thread_id,
@@ -334,130 +283,61 @@ void PrefValueStore::RefreshPolicyPrefsOnFileThread(
LOG(ERROR) << "refresh of device management policy failed: "
<< "PrefReadError = " << read_error;
return;
+=======
+PrefValueStore::PrefStoreType PrefValueStore::ControllingPrefStoreForPref(
+ const char* name) const {
+ for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) {
+ if (PrefValueInStore(name, static_cast<PrefStoreType>(i)))
+ return static_cast<PrefStoreType>(i);
+>>>>>>> chromium.org at r10.0.621.0
}
+ return INVALID_STORE;
+}
- read_error = new_recommended_pref_store->ReadPrefs();
- if (read_error != PrefStore::PREF_READ_ERROR_NONE) {
- LOG(ERROR) << "refresh of recommended policy failed: PrefReadError = "
- << read_error;
- return;
+bool PrefValueStore::GetValueFromStore(const char* name,
+ PrefValueStore::PrefStoreType store_type,
+ Value** out_value) const {
+ // Only return true if we find a value and it is the correct type, so stale
+ // values with the incorrect type will be ignored.
+ const PrefStore* store = GetPrefStore(static_cast<PrefStoreType>(store_type));
+ if (store) {
+ switch (store->GetValue(name, out_value)) {
+ case PrefStore::READ_USE_DEFAULT:
+ store = GetPrefStore(DEFAULT_STORE);
+ if (!store || store->GetValue(name, out_value) != PrefStore::READ_OK) {
+ *out_value = NULL;
+ return false;
+ }
+ // Fall through...
+ case PrefStore::READ_OK:
+ if (IsValidType(GetRegisteredType(name),
+ (*out_value)->GetType(),
+ store_type)) {
+ return true;
+ }
+ break;
+ case PrefStore::READ_NO_VALUE:
+ break;
+ }
}
- BrowserThread::PostTask(
- calling_thread_id, FROM_HERE,
- NewRunnableMethod(this,
- &PrefValueStore::RefreshPolicyPrefsCompletion,
- managed_platform_pref_store.release(),
- device_management_pref_store.release(),
- recommended_pref_store.release(),
- callback.release()));
+ // No valid value found for the given preference name: set the return false.
+ *out_value = NULL;
+ return false;
}
-void PrefValueStore::RefreshPolicyPrefsCompletion(
- PrefStore* new_managed_platform_pref_store,
- PrefStore* new_device_management_pref_store,
- PrefStore* new_recommended_pref_store,
- AfterRefreshCallback* callback_pointer) {
- scoped_ptr<AfterRefreshCallback> callback(callback_pointer);
-
- // Determine the paths of all the changed preferences values in the three
- // policy-related stores (managed platform, device management and
- // recommended).
- DictionaryValue* managed_platform_prefs_before(
- pref_stores_[PrefNotifier::MANAGED_PLATFORM_STORE]->prefs());
- DictionaryValue* managed_platform_prefs_after(
- new_managed_platform_pref_store->prefs());
- DictionaryValue* device_management_prefs_before(
- pref_stores_[PrefNotifier::DEVICE_MANAGEMENT_STORE]->prefs());
- DictionaryValue* device_management_prefs_after(
- new_device_management_pref_store->prefs());
- DictionaryValue* recommended_prefs_before(
- pref_stores_[PrefNotifier::RECOMMENDED_STORE]->prefs());
- DictionaryValue* recommended_prefs_after(new_recommended_pref_store->prefs());
-
- std::vector<std::string> changed_managed_platform_paths;
- managed_platform_prefs_before->GetDifferingPaths(managed_platform_prefs_after,
- &changed_managed_platform_paths);
-
- std::vector<std::string> changed_device_management_paths;
- device_management_prefs_before->GetDifferingPaths(
- device_management_prefs_after,
- &changed_device_management_paths);
-
- std::vector<std::string> changed_recommended_paths;
- recommended_prefs_before->GetDifferingPaths(recommended_prefs_after,
- &changed_recommended_paths);
-
- // Merge all three vectors of changed value paths together, filtering
- // duplicates in a post-processing step.
- std::vector<std::string> all_changed_managed_platform_paths(
- changed_managed_platform_paths.size() +
- changed_device_management_paths.size());
-
- std::vector<std::string>::iterator last_insert =
- std::merge(changed_managed_platform_paths.begin(),
- changed_managed_platform_paths.end(),
- changed_device_management_paths.begin(),
- changed_device_management_paths.end(),
- all_changed_managed_platform_paths.begin());
- all_changed_managed_platform_paths.resize(
- last_insert - all_changed_managed_platform_paths.begin());
-
- std::vector<std::string> changed_paths(
- all_changed_managed_platform_paths.size() +
- changed_recommended_paths.size());
- last_insert = std::merge(all_changed_managed_platform_paths.begin(),
- all_changed_managed_platform_paths.end(),
- changed_recommended_paths.begin(),
- changed_recommended_paths.end(),
- changed_paths.begin());
- changed_paths.resize(last_insert - changed_paths.begin());
-
- last_insert = unique(changed_paths.begin(), changed_paths.end());
- changed_paths.resize(last_insert - changed_paths.begin());
-
- // Replace the old stores with the new and send notification of the changed
- // preferences.
- pref_stores_[PrefNotifier::MANAGED_PLATFORM_STORE].reset(
- new_managed_platform_pref_store);
- pref_stores_[PrefNotifier::DEVICE_MANAGEMENT_STORE].reset(
- new_device_management_pref_store);
- pref_stores_[PrefNotifier::RECOMMENDED_STORE].reset(
- new_recommended_pref_store);
- callback->Run(changed_paths);
+void PrefValueStore::OnPrefValueChanged(PrefValueStore::PrefStoreType type,
+ const std::string& key) {
+ NotifyPrefChanged(key.c_str(), type);
}
-void PrefValueStore::RefreshPolicyPrefs(
- AfterRefreshCallback* callback) {
- using policy::ConfigurationPolicyPrefStore;
- // Because loading of policy information must happen on the FILE
- // thread, it's not possible to just replace the contents of the
- // managed and recommended stores in place due to possible
- // concurrent access from the UI thread. Instead, new stores are
- // created and the refreshed policy read into them. The new stores
- // are swapped with the old from a Task on the UI thread after the
- // load is complete.
- PrefStore* new_managed_platform_pref_store(
- ConfigurationPolicyPrefStore::CreateManagedPlatformPolicyPrefStore());
- PrefStore* new_device_management_pref_store(
- ConfigurationPolicyPrefStore::CreateDeviceManagementPolicyPrefStore(
- profile_));
- PrefStore* new_recommended_pref_store(
- ConfigurationPolicyPrefStore::CreateRecommendedPolicyPrefStore());
- BrowserThread::ID current_thread_id;
- CHECK(BrowserThread::GetCurrentThreadIdentifier(&current_thread_id));
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(this,
- &PrefValueStore::RefreshPolicyPrefsOnFileThread,
- current_thread_id,
- new_managed_platform_pref_store,
- new_device_management_pref_store,
- new_recommended_pref_store,
- callback));
+void PrefValueStore::OnInitializationCompleted(
+ PrefValueStore::PrefStoreType type) {
+ CheckInitializationCompleted();
}
#endif // ANDROID
+<<<<<<< HEAD
bool PrefValueStore::HasPolicyConflictingUserProxySettings() {
#if !defined(ANDROID)
using policy::ConfigurationPolicyPrefStore;
@@ -474,27 +354,18 @@ bool PrefValueStore::HasPolicyConflictingUserProxySettings() {
}
#endif
return false;
-}
-
-PrefValueStore::PrefValueStore(PrefStore* managed_platform_prefs,
- PrefStore* device_management_prefs,
- PrefStore* extension_prefs,
- PrefStore* command_line_prefs,
- PrefStore* user_prefs,
- PrefStore* recommended_prefs,
- PrefStore* default_prefs,
- Profile* profile)
- : profile_(profile) {
- // NULL default pref store is usually bad, but may be OK for some unit tests.
- if (!default_prefs)
- LOG(WARNING) << "default pref store is null";
- pref_stores_[PrefNotifier::MANAGED_PLATFORM_STORE].reset(
- managed_platform_prefs);
- pref_stores_[PrefNotifier::DEVICE_MANAGEMENT_STORE].reset(
- device_management_prefs);
- pref_stores_[PrefNotifier::EXTENSION_STORE].reset(extension_prefs);
- pref_stores_[PrefNotifier::COMMAND_LINE_STORE].reset(command_line_prefs);
- pref_stores_[PrefNotifier::USER_STORE].reset(user_prefs);
- pref_stores_[PrefNotifier::RECOMMENDED_STORE].reset(recommended_prefs);
- pref_stores_[PrefNotifier::DEFAULT_STORE].reset(default_prefs);
+=======
+void PrefValueStore::InitPrefStore(PrefValueStore::PrefStoreType type,
+ PrefStore* pref_store) {
+ pref_stores_[type].Initialize(this, pref_store, type);
+>>>>>>> chromium.org at r10.0.621.0
+}
+
+void PrefValueStore::CheckInitializationCompleted() {
+ for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) {
+ PrefStore* store = GetPrefStore(static_cast<PrefStoreType>(i));
+ if (store && !store->IsInitializationComplete())
+ return;
+ }
+ pref_notifier_->OnInitializationCompleted();
}
diff --git a/chrome/browser/prefs/pref_value_store.h b/chrome/browser/prefs/pref_value_store.h
index a82944d..2b8c539 100644
--- a/chrome/browser/prefs/pref_value_store.h
+++ b/chrome/browser/prefs/pref_value_store.h
@@ -11,18 +11,21 @@
#include <vector>
#include "base/basictypes.h"
-#include "base/callback.h"
#include "base/gtest_prod_util.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "base/values.h"
#ifndef ANDROID
#include "chrome/browser/browser_thread.h"
+<<<<<<< HEAD
#endif
#include "chrome/browser/prefs/pref_notifier.h"
+=======
+>>>>>>> chromium.org at r10.0.621.0
#include "chrome/common/pref_store.h"
class FilePath;
+class PrefNotifier;
class PrefStore;
class Profile;
@@ -30,13 +33,12 @@ class Profile;
// (e.g., configuration policies, extensions, and user settings). It returns
// the value of a Preference from the source with the highest priority, and
// allows setting user-defined values for preferences that are not managed.
-// See PrefNotifier for a list of the available preference sources (PrefStores)
-// and their descriptions.
//
// Unless otherwise explicitly noted, all of the methods of this class must
// be called on the UI thread.
class PrefValueStore : public base::RefCountedThreadSafe<PrefValueStore> {
public:
+<<<<<<< HEAD
// Returns a new PrefValueStore with all applicable PrefStores. The
// |pref_filename| points to the user preference file. The |profile| is the
// one to which these preferences apply; it may be NULL if we're dealing
@@ -53,6 +55,38 @@ class PrefValueStore : public base::RefCountedThreadSafe<PrefValueStore> {
virtual
#endif
~PrefValueStore();
+=======
+ // In decreasing order of precedence:
+ // |managed_platform_prefs| contains all managed platform (non-cloud policy)
+ // preference values.
+ // |device_management_prefs| contains all device management (cloud policy)
+ // preference values.
+ // |extension_prefs| contains preference values set by extensions.
+ // |command_line_prefs| contains preference values set by command-line
+ // switches.
+ // |user_prefs| contains all user-set preference values.
+ // |recommended_prefs| contains all recommended (policy) preference values.
+ // |default_prefs| contains application-default preference values. It must
+ // be non-null if any preferences are to be registered.
+ //
+ // |pref_notifier| facilitates broadcasting preference change notifications
+ // to the world.
+ //
+ // The |profile| parameter is used to construct a replacement device
+ // management pref store. This is done after policy refresh when we swap out
+ // the policy pref stores for new ones, so the |profile| pointer needs to be
+ // kept around for then. It is safe to pass a NULL pointer for local state
+ // preferences.
+ PrefValueStore(PrefStore* managed_platform_prefs,
+ PrefStore* device_management_prefs,
+ PrefStore* extension_prefs,
+ PrefStore* command_line_prefs,
+ PrefStore* user_prefs,
+ PrefStore* recommended_prefs,
+ PrefStore* default_prefs,
+ PrefNotifier* pref_notifier);
+ virtual ~PrefValueStore();
+>>>>>>> chromium.org at r10.0.621.0
// Gets the value for the given preference name that has a valid value type;
// that is, the same type the preference was registered with, or NULL for
@@ -61,9 +95,6 @@ class PrefValueStore : public base::RefCountedThreadSafe<PrefValueStore> {
// Preference::GetValue() instead of calling this method directly.
bool GetValue(const std::string& name, Value** out_value) const;
- // Same as GetValue but only searches USER_STORE.
- bool GetUserValue(const std::string& name, Value** out_value) const;
-
// Adds a preference to the mapping of names to types.
void RegisterPreferenceType(const std::string& name, Value::ValueType type);
@@ -71,20 +102,6 @@ class PrefValueStore : public base::RefCountedThreadSafe<PrefValueStore> {
// Value::TYPE_NULL if the preference has never been registered.
Value::ValueType GetRegisteredType(const std::string& name) const;
- // Read preference values into the three PrefStores so that they are available
- // through the GetValue method. Return the first error that occurs (but
- // continue reading the remaining PrefStores).
- PrefStore::PrefReadError ReadPrefs();
-
- // Persists prefs (to disk or elsewhere). Returns true if writing values was
- // successful. In practice, only the user prefs are expected to be written
- // out.
- bool WritePrefs();
-
- // Calls the method ScheduleWritePrefs on the PrefStores. In practice, only
- // the user prefs are expected to be written out.
- void ScheduleWritePrefs();
-
// Returns true if the PrefValueStore contains the given preference (i.e.,
// it's been registered), and a value with the correct type has been actively
// set in some pref store. The application default specified when the pref was
@@ -92,38 +109,6 @@ class PrefValueStore : public base::RefCountedThreadSafe<PrefValueStore> {
// store setting a value that happens to be equal to the default does.
bool HasPrefPath(const char* name) const;
- // Called by the PrefNotifier when the value of the preference at |path| has
- // changed, been added, or been removed in one of the PrefStores. The
- // |new_store| is the PrefStoreType of the caller. Returns true if the
- // effective value of the preference has changed, or if the store controlling
- // the pref has changed. Virtual so it can be mocked for a unit test.
- virtual bool PrefHasChanged(const char* path,
- PrefNotifier::PrefStoreType new_store);
-
- // Returns true if the PrefValueStore is read-only. Because the managed
- // platform, device management and recommended PrefStores are always
- // read-only, the PrefValueStore as a whole is read-only if the PrefStore
- // containing the user preferences is read-only.
- bool ReadOnly();
-
- // Alters the user-defined value of a preference. Even if the preference is
- // managed this method allows the user-defined value of the preference to be
- // set. But GetValue calls will not return this value as long as the
- // preference is managed. Instead GetValue will return the managed value
- // of the preference. Note that the PrefValueStore takes the ownership of
- // the value referenced by |in_value|. It is an error to call this when no
- // user PrefStore has been set. Returns true if the user-set value of the
- // preference was newly added or changed.
- bool SetUserPrefValue(const char* name, Value* in_value);
-
- // Removes a value from the user PrefStore. If a preference is managed
- // this function should have no visible effect. Returns true if there was a
- // user-set value to be removed.
- bool RemoveUserPrefValue(const char* name);
-
- // Sets a value in the DefaultPrefStore, which takes ownership of the Value.
- void SetDefaultPrefValue(const char* name, Value* in_value);
-
// These methods return true if a preference with the given name is in the
// indicated pref store, even if that value is currently being overridden by
// a higher-priority source.
@@ -132,14 +117,6 @@ class PrefValueStore : public base::RefCountedThreadSafe<PrefValueStore> {
bool PrefValueInExtensionStore(const char* name) const;
bool PrefValueInUserStore(const char* name) const;
- // Returns true if a preference has an explicit value in any of the
- // stores in the range specified by |first_checked_store| and
- // |last_checked_store|, even if that value is currently being
- // overridden by a higher-priority store.
- bool PrefValueInStoreRange(const char* name,
- PrefNotifier::PrefStoreType first_checked_store,
- PrefNotifier::PrefStoreType last_checked_store);
-
// These methods return true if a preference with the given name is actually
// being controlled by the indicated pref store and not being overridden by
// a higher-priority source.
@@ -151,6 +128,7 @@ class PrefValueStore : public base::RefCountedThreadSafe<PrefValueStore> {
// there is no higher-priority source controlling it.
bool PrefValueUserModifiable(const char* name) const;
+<<<<<<< HEAD
// Returns the pref store type identifying the source that controls the
// Preference identified by |name|. If none of the sources has a value,
// PrefNotifier::INVALID_STORE is returned. In practice, the default PrefStore
@@ -215,24 +193,109 @@ class PrefValueStore : public base::RefCountedThreadSafe<PrefValueStore> {
PrefStore* default_prefs,
Profile* profile);
+=======
+>>>>>>> chromium.org at r10.0.621.0
private:
+ // PrefStores must be listed here in order from highest to lowest priority.
+ // MANAGED_PLATFORM contains all managed preference values that are
+ // provided by a platform-specific policy mechanism (e.g. Windows
+ // Group Policy).
+ // DEVICE_MANAGEMENT contains all managed preference values supplied
+ // by the device management server (cloud policy).
+ // EXTENSION contains preference values set by extensions.
+ // COMMAND_LINE contains preference values set by command-line switches.
+ // USER contains all user-set preference values.
+ // RECOMMENDED contains all recommended (policy) preference values.
+ // DEFAULT contains all application default preference values.
+ enum PrefStoreType {
+ // INVALID_STORE is not associated with an actual PrefStore but used as
+ // an invalid marker, e.g. as a return value.
+ INVALID_STORE = -1,
+ MANAGED_PLATFORM_STORE = 0,
+ DEVICE_MANAGEMENT_STORE,
+ EXTENSION_STORE,
+ COMMAND_LINE_STORE,
+ USER_STORE,
+ RECOMMENDED_STORE,
+ DEFAULT_STORE,
+ PREF_STORE_TYPE_MAX = DEFAULT_STORE
+ };
+
+ // Keeps a PrefStore reference on behalf of the PrefValueStore and monitors
+ // the PrefStore for changes, forwarding notifications to PrefValueStore. This
+ // indirection is here for the sake of disambiguating notifications from the
+ // individual PrefStores.
+ class PrefStoreKeeper : public PrefStore::Observer {
+ public:
+ PrefStoreKeeper();
+ virtual ~PrefStoreKeeper();
+
+ // Takes ownership of |pref_store|.
+ void Initialize(PrefValueStore* store,
+ PrefStore* pref_store,
+ PrefStoreType type);
+
+ PrefStore* store() { return pref_store_.get(); }
+ const PrefStore* store() const { return pref_store_.get(); }
+
+ private:
+ // PrefStore::Observer implementation.
+ virtual void OnPrefValueChanged(const std::string& key);
+ virtual void OnInitializationCompleted();
+
+ // PrefValueStore this keeper is part of.
+ PrefValueStore* pref_value_store_;
+
+ // The PrefStore managed by this keeper.
+ scoped_ptr<PrefStore> pref_store_;
+
+ // Type of the pref store.
+ PrefStoreType type_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrefStoreKeeper);
+ };
+
typedef std::map<std::string, Value::ValueType> PrefTypeMap;
- friend class PrefValueStoreTest;
- FRIEND_TEST_ALL_PREFIXES(PrefValueStoreTest,
+ friend class PrefValueStorePolicyRefreshTest;
+ FRIEND_TEST_ALL_PREFIXES(PrefValueStorePolicyRefreshTest, TestPolicyRefresh);
+ FRIEND_TEST_ALL_PREFIXES(PrefValueStorePolicyRefreshTest,
TestRefreshPolicyPrefsCompletion);
+ FRIEND_TEST_ALL_PREFIXES(PrefValueStorePolicyRefreshTest,
+ TestConcurrentPolicyRefresh);
+
+ // Returns true if the actual type is a valid type for the expected type when
+ // found in the given store.
+ static bool IsValidType(Value::ValueType expected,
+ Value::ValueType actual,
+ PrefStoreType store);
// Returns true if the preference with the given name has a value in the
// given PrefStoreType, of the same value type as the preference was
// registered with.
- bool PrefValueInStore(const char* name,
- PrefNotifier::PrefStoreType store) const;
+ bool PrefValueInStore(const char* name, PrefStoreType store) const;
+
+ // Returns true if a preference has an explicit value in any of the
+ // stores in the range specified by |first_checked_store| and
+ // |last_checked_store|, even if that value is currently being
+ // overridden by a higher-priority store.
+ bool PrefValueInStoreRange(const char* name,
+ PrefStoreType first_checked_store,
+ PrefStoreType last_checked_store) const;
+
+ // Returns the pref store type identifying the source that controls the
+ // Preference identified by |name|. If none of the sources has a value,
+ // INVALID_STORE is returned. In practice, the default PrefStore
+ // should always have a value for any registered preferencem, so INVALID_STORE
+ // indicates an error.
+ PrefStoreType ControllingPrefStoreForPref(const char* name) const;
// Get a value from the specified store type.
bool GetValueFromStore(const char* name,
- PrefNotifier::PrefStoreType store,
+ PrefStoreType store,
Value** out_value) const;
+<<<<<<< HEAD
#ifndef ANDROID
// Called during policy refresh after ReadPrefs completes on the thread
// that initiated the policy refresh. RefreshPolicyPrefsCompletion takes
@@ -254,15 +317,49 @@ class PrefValueStore : public base::RefCountedThreadSafe<PrefValueStore> {
#endif
scoped_ptr<PrefStore> pref_stores_[PrefNotifier::PREF_STORE_TYPE_MAX + 1];
+=======
+ // Called upon changes in individual pref stores in order to determine whether
+ // the user-visible pref value has changed. Triggers the change notification
+ // if the effective value of the preference has changed, or if the store
+ // controlling the pref has changed.
+ void NotifyPrefChanged(const char* path, PrefStoreType new_store);
+
+ // Called from the PrefStoreKeeper implementation when a pref value for |key|
+ // changed in the pref store for |type|.
+ void OnPrefValueChanged(PrefStoreType type, const std::string& key);
+
+ // Handle the event that the store for |type| has completed initialization.
+ void OnInitializationCompleted(PrefStoreType type);
+
+ // Initializes a pref store keeper. Sets up a PrefStoreKeeper that will take
+ // ownership of the passed |pref_store|.
+ void InitPrefStore(PrefStoreType type, PrefStore* pref_store);
+
+ // Checks whether initialization is completed and tells the notifier if that
+ // is the case.
+ void CheckInitializationCompleted();
+
+ // Get the PrefStore pointer for the given type. May return NULL if there is
+ // no PrefStore for that type.
+ PrefStore* GetPrefStore(PrefStoreType type) {
+ return pref_stores_[type].store();
+ }
+ const PrefStore* GetPrefStore(PrefStoreType type) const {
+ return pref_stores_[type].store();
+ }
+
+ // Keeps the PrefStore references in order of precedence.
+ PrefStoreKeeper pref_stores_[PREF_STORE_TYPE_MAX + 1];
+
+ // Used for generating PREF_CHANGED and PREF_INITIALIZATION_COMPLETED
+ // notifications. This is a weak reference, since the notifier is owned by the
+ // corresponding PrefService.
+ PrefNotifier* pref_notifier_;
+>>>>>>> chromium.org at r10.0.621.0
// A mapping of preference names to their registered types.
PrefTypeMap pref_types_;
- // The associated profile, in case this value store is associated with a
- // profile pref service. Used for recreating the device management pref store
- // upon policy refresh.
- Profile* profile_;
-
DISALLOW_COPY_AND_ASSIGN(PrefValueStore);
};
diff --git a/chrome/browser/prefs/pref_value_store_unittest.cc b/chrome/browser/prefs/pref_value_store_unittest.cc
index cbf7ccc..5c0fa53 100644
--- a/chrome/browser/prefs/pref_value_store_unittest.cc
+++ b/chrome/browser/prefs/pref_value_store_unittest.cc
@@ -2,26 +2,33 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <set>
+#include <string>
+
#include "base/scoped_ptr.h"
#include "base/values.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/policy/configuration_policy_pref_store.h"
-#include "chrome/browser/prefs/dummy_pref_store.h"
+#include "chrome/browser/policy/dummy_configuration_policy_provider.h"
+#include "chrome/browser/prefs/pref_notifier.h"
#include "chrome/browser/prefs/pref_value_store.h"
+#include "chrome/browser/prefs/testing_pref_store.h"
#include "chrome/common/pref_names.h"
-#include "chrome/test/testing_pref_service.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
+using testing::AnyNumber;
using testing::Mock;
+using testing::Invoke;
namespace {
-class MockPolicyRefreshCallback {
+// Allows to capture pref notifications through gmock.
+class MockPrefNotifier : public PrefNotifier {
public:
- MockPolicyRefreshCallback() {}
- MOCK_METHOD1(DoCallback, void(const std::vector<std::string>));
+ MOCK_METHOD1(OnPreferenceChanged, void(const std::string&));
+ MOCK_METHOD0(OnInitializationCompleted, void());
};
} // namespace
@@ -83,44 +90,25 @@ const std::string kSearchProviderNameValue = "AreYouFeelingExtraLucky";
class PrefValueStoreTest : public testing::Test {
protected:
virtual void SetUp() {
- // Create dummy user preferences.
- managed_platform_prefs_= CreateManagedPlatformPrefs();
- device_management_prefs_ = CreateDeviceManagementPrefs();
- extension_prefs_ = CreateExtensionPrefs();
- command_line_prefs_ = CreateCommandLinePrefs();
- user_prefs_ = CreateUserPrefs();
- recommended_prefs_ = CreateRecommendedPrefs();
- default_prefs_ = CreateDefaultPrefs();
-
- std::sort(expected_differing_paths_.begin(),
- expected_differing_paths_.end());
-
- // Create |DummyPrefStore|s.
- managed_platform_pref_store_ = new DummyPrefStore();
- managed_platform_pref_store_->set_prefs(managed_platform_prefs_);
- device_management_pref_store_ = new DummyPrefStore();
- device_management_pref_store_->set_prefs(device_management_prefs_);
- extension_pref_store_ = new DummyPrefStore();
- extension_pref_store_->set_prefs(extension_prefs_);
- command_line_pref_store_ = new DummyPrefStore();
- command_line_pref_store_->set_prefs(command_line_prefs_);
- user_pref_store_ = new DummyPrefStore();
- user_pref_store_->set_read_only(false);
- user_pref_store_->set_prefs(user_prefs_);
- recommended_pref_store_ = new DummyPrefStore();
- recommended_pref_store_->set_prefs(recommended_prefs_);
- default_pref_store_ = new DummyPrefStore();
- default_pref_store_->set_prefs(default_prefs_);
-
- // Create a new pref-value-store.
- pref_value_store_ = new TestingPrefService::TestingPrefValueStore(
+ // Create TestingPrefStores.
+ CreateManagedPlatformPrefs();
+ CreateDeviceManagementPrefs();
+ CreateExtensionPrefs();
+ CreateCommandLinePrefs();
+ CreateUserPrefs();
+ CreateRecommendedPrefs();
+ CreateDefaultPrefs();
+
+ // Create a fresh PrefValueStore.
+ pref_value_store_ = new PrefValueStore(
managed_platform_pref_store_,
device_management_pref_store_,
extension_pref_store_,
command_line_pref_store_,
user_pref_store_,
recommended_pref_store_,
- default_pref_store_);
+ default_pref_store_,
+ &pref_notifier_);
// Register prefs with the PrefValueStore.
pref_value_store_->RegisterPreferenceType(prefs::kApplicationLocale,
@@ -144,99 +132,76 @@ class PrefValueStoreTest : public testing::Test {
Value::TYPE_LIST);
pref_value_store_->RegisterPreferenceType(prefs::kDefaultPref,
Value::TYPE_INTEGER);
- pref_value_store_->RegisterPreferenceType(prefs::kProxyAutoDetect,
- Value::TYPE_BOOLEAN);
-
- ui_thread_.reset(new BrowserThread(BrowserThread::UI, &loop_));
- file_thread_.reset(new BrowserThread(BrowserThread::FILE, &loop_));
+ pref_value_store_->RegisterPreferenceType(prefs::kProxyMode,
+ Value::TYPE_INTEGER);
}
// Creates a new dictionary and stores some sample user preferences
// in it.
- DictionaryValue* CreateUserPrefs() {
- DictionaryValue* user_prefs = new DictionaryValue();
- user_prefs->SetBoolean(prefs::kDeleteCache, user_pref::kDeleteCacheValue);
- user_prefs->SetInteger(prefs::kStabilityLaunchCount,
- user_pref::kStabilityLaunchCountValue);
- user_prefs->SetString(prefs::kCurrentThemeID,
+ void CreateUserPrefs() {
+ user_pref_store_ = new TestingPrefStore;
+ user_pref_store_->SetBoolean(prefs::kDeleteCache,
+ user_pref::kDeleteCacheValue);
+ user_pref_store_->SetInteger(prefs::kStabilityLaunchCount,
+ user_pref::kStabilityLaunchCountValue);
+ user_pref_store_->SetString(prefs::kCurrentThemeID,
user_pref::kCurrentThemeIDValue);
- user_prefs->SetString(prefs::kApplicationLocale,
+ user_pref_store_->SetString(prefs::kApplicationLocale,
user_pref::kApplicationLocaleValue);
- user_prefs->SetString(prefs::kDefaultSearchProviderName,
+ user_pref_store_->SetString(prefs::kDefaultSearchProviderName,
user_pref::kSearchProviderNameValue);
- user_prefs->SetString(prefs::kHomePage, user_pref::kHomepageValue);
- return user_prefs;
+ user_pref_store_->SetString(prefs::kHomePage,
+ user_pref::kHomepageValue);
}
- DictionaryValue* CreateManagedPlatformPrefs() {
- DictionaryValue* managed_platform_prefs = new DictionaryValue();
- managed_platform_prefs->SetString(
- prefs::kHomePage,
+ void CreateManagedPlatformPrefs() {
+ managed_platform_pref_store_ = new TestingPrefStore;
+ managed_platform_pref_store_->SetString(prefs::kHomePage,
managed_platform_pref::kHomepageValue);
- expected_differing_paths_.push_back(prefs::kHomePage);
- return managed_platform_prefs;
}
- DictionaryValue* CreateDeviceManagementPrefs() {
- DictionaryValue* device_management_prefs = new DictionaryValue();
- device_management_prefs->SetString(
- prefs::kDefaultSearchProviderName,
+ void CreateDeviceManagementPrefs() {
+ device_management_pref_store_ = new TestingPrefStore;
+ device_management_pref_store_->SetString(prefs::kDefaultSearchProviderName,
device_management_pref::kSearchProviderNameValue);
- expected_differing_paths_.push_back("default_search_provider");
- expected_differing_paths_.push_back(prefs::kDefaultSearchProviderName);
- device_management_prefs->SetString(prefs::kHomePage,
- device_management_pref::kHomepageValue);
- return device_management_prefs;
+ device_management_pref_store_->SetString(prefs::kHomePage,
+ device_management_pref::kHomepageValue);
}
- DictionaryValue* CreateExtensionPrefs() {
- DictionaryValue* extension_prefs = new DictionaryValue();
- extension_prefs->SetString(prefs::kCurrentThemeID,
+ void CreateExtensionPrefs() {
+ extension_pref_store_ = new TestingPrefStore;
+ extension_pref_store_->SetString(prefs::kCurrentThemeID,
extension_pref::kCurrentThemeIDValue);
- extension_prefs->SetString(prefs::kHomePage,
+ extension_pref_store_->SetString(prefs::kHomePage,
extension_pref::kHomepageValue);
- extension_prefs->SetString(prefs::kDefaultSearchProviderName,
- extension_pref::kSearchProviderNameValue);
- return extension_prefs;
+ extension_pref_store_->SetString(prefs::kDefaultSearchProviderName,
+ extension_pref::kSearchProviderNameValue);
}
- DictionaryValue* CreateCommandLinePrefs() {
- DictionaryValue* command_line_prefs = new DictionaryValue();
- command_line_prefs->SetString(prefs::kCurrentThemeID,
+ void CreateCommandLinePrefs() {
+ command_line_pref_store_ = new TestingPrefStore;
+ command_line_pref_store_->SetString(prefs::kCurrentThemeID,
command_line_pref::kCurrentThemeIDValue);
- command_line_prefs->SetString(prefs::kApplicationLocale,
+ command_line_pref_store_->SetString(prefs::kApplicationLocale,
command_line_pref::kApplicationLocaleValue);
- command_line_prefs->SetString(prefs::kHomePage,
+ command_line_pref_store_->SetString(prefs::kHomePage,
command_line_pref::kHomepageValue);
- command_line_prefs->SetString(
- prefs::kDefaultSearchProviderName,
+ command_line_pref_store_->SetString(prefs::kDefaultSearchProviderName,
command_line_pref::kSearchProviderNameValue);
- return command_line_prefs;
}
- DictionaryValue* CreateRecommendedPrefs() {
- DictionaryValue* recommended_prefs = new DictionaryValue();
- recommended_prefs->SetInteger(prefs::kStabilityLaunchCount,
+ void CreateRecommendedPrefs() {
+ recommended_pref_store_ = new TestingPrefStore;
+ recommended_pref_store_->SetInteger(prefs::kStabilityLaunchCount,
recommended_pref::kStabilityLaunchCountValue);
- recommended_prefs->SetBoolean(
- prefs::kRecommendedPref,
+ recommended_pref_store_->SetBoolean(prefs::kRecommendedPref,
recommended_pref::kRecommendedPrefValue);
-
- // Expected differing paths must be added in lexicographic order
- // to work properly
- expected_differing_paths_.push_back("this");
- expected_differing_paths_.push_back("this.pref");
- expected_differing_paths_.push_back(prefs::kRecommendedPref);
- expected_differing_paths_.push_back("user_experience_metrics");
- expected_differing_paths_.push_back("user_experience_metrics.stability");
- expected_differing_paths_.push_back(prefs::kStabilityLaunchCount);
- return recommended_prefs;
}
- DictionaryValue* CreateDefaultPrefs() {
- DictionaryValue* default_prefs = new DictionaryValue();
- default_prefs->SetInteger(prefs::kDefaultPref, default_pref::kDefaultValue);
- return default_prefs;
+ void CreateDefaultPrefs() {
+ default_pref_store_ = new TestingPrefStore;
+ default_pref_store_->SetInteger(prefs::kDefaultPref,
+ default_pref::kDefaultValue);
}
DictionaryValue* CreateSampleDictValue() {
@@ -256,56 +221,19 @@ class PrefValueStoreTest : public testing::Test {
return sample_list;
}
- virtual void TearDown() {
- loop_.RunAllPending();
- }
-
- MessageLoop loop_;
-
- scoped_refptr<TestingPrefService::TestingPrefValueStore> pref_value_store_;
+ MockPrefNotifier pref_notifier_;
+ scoped_refptr<PrefValueStore> pref_value_store_;
// |PrefStore|s are owned by the |PrefValueStore|.
- DummyPrefStore* managed_platform_pref_store_;
- DummyPrefStore* device_management_pref_store_;
- DummyPrefStore* extension_pref_store_;
- DummyPrefStore* command_line_pref_store_;
- DummyPrefStore* user_pref_store_;
- DummyPrefStore* recommended_pref_store_;
- DummyPrefStore* default_pref_store_;
-
- // A vector of the preferences paths in the managed and recommended
- // PrefStores that are set at the beginning of a test. Can be modified
- // by the test to track changes that it makes to the preferences
- // stored in the managed and recommended PrefStores.
- std::vector<std::string> expected_differing_paths_;
-
- // Preferences are owned by the individual |DummyPrefStores|.
- DictionaryValue* managed_platform_prefs_;
- DictionaryValue* device_management_prefs_;
- DictionaryValue* extension_prefs_;
- DictionaryValue* command_line_prefs_;
- DictionaryValue* user_prefs_;
- DictionaryValue* recommended_prefs_;
- DictionaryValue* default_prefs_;
-
- private:
- scoped_ptr<BrowserThread> ui_thread_;
- scoped_ptr<BrowserThread> file_thread_;
+ TestingPrefStore* managed_platform_pref_store_;
+ TestingPrefStore* device_management_pref_store_;
+ TestingPrefStore* extension_pref_store_;
+ TestingPrefStore* command_line_pref_store_;
+ TestingPrefStore* user_pref_store_;
+ TestingPrefStore* recommended_pref_store_;
+ TestingPrefStore* default_pref_store_;
};
-TEST_F(PrefValueStoreTest, IsReadOnly) {
- managed_platform_pref_store_->set_read_only(true);
- extension_pref_store_->set_read_only(true);
- command_line_pref_store_->set_read_only(true);
- user_pref_store_->set_read_only(true);
- recommended_pref_store_->set_read_only(true);
- default_pref_store_->set_read_only(true);
- EXPECT_TRUE(pref_value_store_->ReadOnly());
-
- user_pref_store_->set_read_only(false);
- EXPECT_FALSE(pref_value_store_->ReadOnly());
-}
-
TEST_F(PrefValueStoreTest, GetValue) {
Value* value;
@@ -378,8 +306,10 @@ TEST_F(PrefValueStoreTest, GetValue) {
// Make sure that if a preference changes type, so the wrong type is stored in
// the user pref file, it uses the correct fallback value instead.
TEST_F(PrefValueStoreTest, GetValueChangedType) {
+ EXPECT_CALL(pref_notifier_, OnPreferenceChanged(_)).Times(AnyNumber());
+
// Check falling back to a recommended value.
- user_pref_store_->prefs()->SetString(prefs::kStabilityLaunchCount,
+ user_pref_store_->SetString(prefs::kStabilityLaunchCount,
"not an integer");
Value* value = NULL;
ASSERT_TRUE(pref_value_store_->GetValue(prefs::kStabilityLaunchCount,
@@ -391,14 +321,14 @@ TEST_F(PrefValueStoreTest, GetValueChangedType) {
EXPECT_EQ(recommended_pref::kStabilityLaunchCountValue, actual_int_value);
// Check falling back multiple times, to a default string.
- managed_platform_pref_store_->prefs()->SetInteger(prefs::kHomePage, 1);
- device_management_pref_store_->prefs()->SetInteger(prefs::kHomePage, 1);
- extension_pref_store_->prefs()->SetInteger(prefs::kHomePage, 1);
- command_line_pref_store_->prefs()->SetInteger(prefs::kHomePage, 1);
- user_pref_store_->prefs()->SetInteger(prefs::kHomePage, 1);
- recommended_pref_store_->prefs()->SetInteger(prefs::kHomePage, 1);
- default_pref_store_->prefs()->SetString(prefs::kHomePage,
- default_pref::kHomepageValue);
+ default_pref_store_->SetString(prefs::kHomePage,
+ default_pref::kHomepageValue);
+ managed_platform_pref_store_->SetInteger(prefs::kHomePage, 1);
+ device_management_pref_store_->SetInteger(prefs::kHomePage, 1);
+ extension_pref_store_->SetInteger(prefs::kHomePage, 1);
+ command_line_pref_store_->SetInteger(prefs::kHomePage, 1);
+ user_pref_store_->SetInteger(prefs::kHomePage, 1);
+ recommended_pref_store_->SetInteger(prefs::kHomePage, 1);
value = NULL;
ASSERT_TRUE(pref_value_store_->GetValue(prefs::kHomePage, &value));
@@ -427,109 +357,70 @@ TEST_F(PrefValueStoreTest, HasPrefPath) {
EXPECT_FALSE(pref_value_store_->HasPrefPath(prefs::kMissingPref));
}
-TEST_F(PrefValueStoreTest, PrefHasChanged) {
+TEST_F(PrefValueStoreTest, PrefChanges) {
// Setup.
+ EXPECT_CALL(pref_notifier_, OnPreferenceChanged(_)).Times(AnyNumber());
const char managed_platform_pref_path[] = "managed_platform_pref";
pref_value_store_->RegisterPreferenceType(managed_platform_pref_path,
Value::TYPE_STRING);
- managed_platform_pref_store_->prefs()->SetString(managed_platform_pref_path,
+ managed_platform_pref_store_->SetString(managed_platform_pref_path,
"managed value");
const char user_pref_path[] = "user_pref";
pref_value_store_->RegisterPreferenceType(user_pref_path, Value::TYPE_STRING);
- user_pref_store_->prefs()->SetString(user_pref_path, "user value");
+ user_pref_store_->SetString(user_pref_path, "user value");
const char default_pref_path[] = "default_pref";
pref_value_store_->RegisterPreferenceType(default_pref_path,
Value::TYPE_STRING);
- default_pref_store_->prefs()->SetString(default_pref_path, "default value");
+ default_pref_store_->SetString(default_pref_path, "default value");
+ Mock::VerifyAndClearExpectations(&pref_notifier_);
// Check pref controlled by highest-priority store.
- EXPECT_TRUE(pref_value_store_->PrefHasChanged(managed_platform_pref_path,
- static_cast<PrefNotifier::PrefStoreType>(0)));
- EXPECT_FALSE(pref_value_store_->PrefHasChanged(managed_platform_pref_path,
- PrefNotifier::USER_STORE));
+ EXPECT_CALL(pref_notifier_, OnPreferenceChanged(managed_platform_pref_path));
+ managed_platform_pref_store_->NotifyPrefValueChanged(
+ managed_platform_pref_path);
+ Mock::VerifyAndClearExpectations(&pref_notifier_);
- // Check pref controlled by user store.
- EXPECT_TRUE(pref_value_store_->PrefHasChanged(user_pref_path,
- static_cast<PrefNotifier::PrefStoreType>(0)));
- EXPECT_TRUE(pref_value_store_->PrefHasChanged(user_pref_path,
- PrefNotifier::USER_STORE));
- EXPECT_FALSE(pref_value_store_->PrefHasChanged(user_pref_path,
- PrefNotifier::PREF_STORE_TYPE_MAX));
-
- // Check pref controlled by default-pref store.
- EXPECT_TRUE(pref_value_store_->PrefHasChanged(default_pref_path,
- PrefNotifier::USER_STORE));
- EXPECT_TRUE(pref_value_store_->PrefHasChanged(default_pref_path,
- PrefNotifier::DEFAULT_STORE));
-}
+ EXPECT_CALL(pref_notifier_, OnPreferenceChanged(_)).Times(0);
+ user_pref_store_->NotifyPrefValueChanged(managed_platform_pref_path);
+ Mock::VerifyAndClearExpectations(&pref_notifier_);
-TEST_F(PrefValueStoreTest, ReadPrefs) {
- pref_value_store_->ReadPrefs();
- // The ReadPrefs method of the |DummyPrefStore| deletes the |pref_store|s
- // internal dictionary and creates a new empty dictionary. Hence this
- // dictionary does not contain any of the preloaded preferences.
- // This shows that the ReadPrefs method of the |DummyPrefStore| was called.
- EXPECT_FALSE(pref_value_store_->HasPrefPath(prefs::kDeleteCache));
-}
+ // Check pref controlled by user store.
+ EXPECT_CALL(pref_notifier_, OnPreferenceChanged(user_pref_path));
+ managed_platform_pref_store_->NotifyPrefValueChanged(user_pref_path);
+ Mock::VerifyAndClearExpectations(&pref_notifier_);
-TEST_F(PrefValueStoreTest, WritePrefs) {
- user_pref_store_->set_prefs_written(false);
- pref_value_store_->WritePrefs();
- ASSERT_TRUE(user_pref_store_->get_prefs_written());
-}
+ EXPECT_CALL(pref_notifier_, OnPreferenceChanged(user_pref_path));
+ user_pref_store_->NotifyPrefValueChanged(user_pref_path);
+ Mock::VerifyAndClearExpectations(&pref_notifier_);
-TEST_F(PrefValueStoreTest, SetUserPrefValue) {
- Value* new_value = NULL;
- Value* actual_value = NULL;
+ EXPECT_CALL(pref_notifier_, OnPreferenceChanged(_)).Times(0);
+ default_pref_store_->NotifyPrefValueChanged(user_pref_path);
+ Mock::VerifyAndClearExpectations(&pref_notifier_);
- // Test that managed platform values can not be set.
- ASSERT_TRUE(pref_value_store_->PrefValueInManagedPlatformStore(
- prefs::kHomePage));
- // The Ownership is tranfered to |PrefValueStore|.
- new_value = Value::CreateStringValue("http://www.youtube.com");
- pref_value_store_->SetUserPrefValue(prefs::kHomePage, new_value);
+ // Check pref controlled by default-pref store.
+ EXPECT_CALL(pref_notifier_, OnPreferenceChanged(default_pref_path));
+ user_pref_store_->NotifyPrefValueChanged(default_pref_path);
+ Mock::VerifyAndClearExpectations(&pref_notifier_);
- ASSERT_TRUE(pref_value_store_->GetValue(prefs::kHomePage, &actual_value));
- std::string value_str;
- actual_value->GetAsString(&value_str);
- ASSERT_EQ(managed_platform_pref::kHomepageValue, value_str);
+ EXPECT_CALL(pref_notifier_, OnPreferenceChanged(default_pref_path));
+ default_pref_store_->NotifyPrefValueChanged(default_pref_path);
+ Mock::VerifyAndClearExpectations(&pref_notifier_);
+}
- // User preferences values can be set
- ASSERT_FALSE(pref_value_store_->PrefValueInManagedPlatformStore(
- prefs::kStabilityLaunchCount));
- actual_value = NULL;
- pref_value_store_->GetValue(prefs::kStabilityLaunchCount, &actual_value);
- int int_value;
- EXPECT_TRUE(actual_value->GetAsInteger(&int_value));
- EXPECT_EQ(user_pref::kStabilityLaunchCountValue, int_value);
-
- new_value = Value::CreateIntegerValue(1);
- pref_value_store_->SetUserPrefValue(prefs::kStabilityLaunchCount, new_value);
- actual_value = NULL;
- pref_value_store_->GetValue(prefs::kStabilityLaunchCount, &actual_value);
- EXPECT_TRUE(new_value->Equals(actual_value));
-
- // Set and Get |DictionaryValue|
- DictionaryValue* expected_dict_value = CreateSampleDictValue();
- pref_value_store_->SetUserPrefValue(prefs::kSampleDict, expected_dict_value);
-
- actual_value = NULL;
- std::string key(prefs::kSampleDict);
- pref_value_store_->GetValue(key, &actual_value);
-
- ASSERT_EQ(expected_dict_value, actual_value);
- ASSERT_TRUE(expected_dict_value->Equals(actual_value));
-
- // Set and Get a |ListValue|
- ListValue* expected_list_value = CreateSampleListValue();
- pref_value_store_->SetUserPrefValue(prefs::kSampleList, expected_list_value);
-
- actual_value = NULL;
- key = prefs::kSampleList;
- pref_value_store_->GetValue(key, &actual_value);
-
- ASSERT_EQ(expected_list_value, actual_value);
- ASSERT_TRUE(expected_list_value->Equals(actual_value));
+TEST_F(PrefValueStoreTest, OnInitializationCompleted) {
+ EXPECT_CALL(pref_notifier_, OnInitializationCompleted()).Times(0);
+ managed_platform_pref_store_->SetInitializationCompleted();
+ device_management_pref_store_->SetInitializationCompleted();
+ extension_pref_store_->SetInitializationCompleted();
+ command_line_pref_store_->SetInitializationCompleted();
+ recommended_pref_store_->SetInitializationCompleted();
+ default_pref_store_->SetInitializationCompleted();
+ Mock::VerifyAndClearExpectations(&pref_notifier_);
+
+ // The notification should only be triggered after the last store is done.
+ EXPECT_CALL(pref_notifier_, OnInitializationCompleted()).Times(1);
+ user_pref_store_->SetInitializationCompleted();
+ Mock::VerifyAndClearExpectations(&pref_notifier_);
}
TEST_F(PrefValueStoreTest, PrefValueInManagedPlatformStore) {
@@ -633,18 +524,6 @@ TEST_F(PrefValueStoreTest, PrefValueInExtensionStore) {
prefs::kMissingPref));
}
-TEST_F(PrefValueStoreTest, DetectProxyConfigurationConflict) {
- // There should be no conflicting proxy prefs in the default
- // preference stores created for the test.
- ASSERT_FALSE(pref_value_store_->HasPolicyConflictingUserProxySettings());
-
- // Create conflicting proxy settings in the managed and command-line
- // preference stores.
- command_line_prefs_->SetBoolean(prefs::kProxyAutoDetect, false);
- managed_platform_prefs_->SetBoolean(prefs::kProxyAutoDetect, true);
- ASSERT_TRUE(pref_value_store_->HasPolicyConflictingUserProxySettings());
-}
-
TEST_F(PrefValueStoreTest, PrefValueInUserStore) {
// Test a managed platform preference.
ASSERT_TRUE(pref_value_store_->HasPrefPath(prefs::kHomePage));
@@ -739,147 +618,3 @@ TEST_F(PrefValueStoreTest, PrefValueFromDefaultStore) {
EXPECT_FALSE(
pref_value_store_->PrefValueFromDefaultStore(prefs::kMissingPref));
}
-
-TEST_F(PrefValueStoreTest, TestPolicyRefresh) {
- // pref_value_store_ is initialized by PrefValueStoreTest to have values in
- // the managed platform, device management and recommended stores. By
- // replacing them with dummy stores, all of the paths of the prefs originally
- // in the managed platform, device management and recommended stores should
- // change.
- MockPolicyRefreshCallback callback;
- EXPECT_CALL(callback, DoCallback(_)).Times(0);
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(
- pref_value_store_.get(),
- &PrefValueStore::RefreshPolicyPrefs,
- NewCallback(&callback,
- &MockPolicyRefreshCallback::DoCallback)));
- Mock::VerifyAndClearExpectations(&callback);
- EXPECT_CALL(callback, DoCallback(expected_differing_paths_)).Times(1);
- loop_.RunAllPending();
-}
-
-TEST_F(PrefValueStoreTest, TestRefreshPolicyPrefsCompletion) {
- // Test changed preferences in the managed platform store and removed
- // preferences in the recommended store. In addition to "homepage", the other
- // prefs that are set by default in the test class are removed by the
- // DummyStore.
- scoped_ptr<DummyPrefStore> new_managed_platform_store(new DummyPrefStore());
- DictionaryValue* dict = new DictionaryValue();
- dict->SetString("homepage", "some other changed homepage");
- new_managed_platform_store->set_prefs(dict);
- MockPolicyRefreshCallback callback;
- EXPECT_CALL(callback, DoCallback(expected_differing_paths_)).Times(1);
- pref_value_store_->RefreshPolicyPrefsCompletion(
- new_managed_platform_store.release(),
- new DummyPrefStore(),
- new DummyPrefStore(),
- NewCallback(&callback,
- &MockPolicyRefreshCallback::DoCallback));
-
- // Test properties that have been removed from the managed platform store.
- // Homepage is still set in managed prefs.
- expected_differing_paths_.clear();
- expected_differing_paths_.push_back(std::string("homepage"));
- MockPolicyRefreshCallback callback2;
- EXPECT_CALL(callback2, DoCallback(expected_differing_paths_)).Times(1);
- pref_value_store_->RefreshPolicyPrefsCompletion(
- new DummyPrefStore(),
- new DummyPrefStore(),
- new DummyPrefStore(),
- NewCallback(&callback2,
- &MockPolicyRefreshCallback::DoCallback));
-
- // Test properties that are added to the device management store.
- expected_differing_paths_.clear();
- expected_differing_paths_.push_back(std::string("homepage"));
- scoped_ptr<DummyPrefStore> new_device_management_store(
- new DummyPrefStore());
- dict = new DictionaryValue();
- dict->SetString("homepage", "some other changed homepage");
- new_device_management_store->set_prefs(dict);
- MockPolicyRefreshCallback callback3;
- EXPECT_CALL(callback3, DoCallback(expected_differing_paths_)).Times(1);
- pref_value_store_->RefreshPolicyPrefsCompletion(
- new DummyPrefStore(),
- new_device_management_store.release(),
- new DummyPrefStore(),
- NewCallback(&callback3,
- &MockPolicyRefreshCallback::DoCallback));
-
- // Test properties that are added to the recommended store.
- scoped_ptr<DummyPrefStore> new_recommended_store(new DummyPrefStore());
- dict = new DictionaryValue();
- dict->SetString("homepage", "some other changed homepage 2");
- new_recommended_store->set_prefs(dict);
- expected_differing_paths_.clear();
- expected_differing_paths_.push_back(std::string("homepage"));
- MockPolicyRefreshCallback callback4;
- EXPECT_CALL(callback4, DoCallback(expected_differing_paths_)).Times(1);
- pref_value_store_->RefreshPolicyPrefsCompletion(
- new DummyPrefStore(),
- new DummyPrefStore(),
- new_recommended_store.release(),
- NewCallback(&callback4,
- &MockPolicyRefreshCallback::DoCallback));
-
- // Test adding a multi-key path.
- new_managed_platform_store.reset(new DummyPrefStore());
- dict = new DictionaryValue();
- dict->SetString("segment1.segment2", "value");
- new_managed_platform_store->set_prefs(dict);
- expected_differing_paths_.clear();
- expected_differing_paths_.push_back(std::string("homepage"));
- expected_differing_paths_.push_back(std::string("segment1"));
- expected_differing_paths_.push_back(std::string("segment1.segment2"));
- MockPolicyRefreshCallback callback5;
- EXPECT_CALL(callback5, DoCallback(expected_differing_paths_)).Times(1);
- pref_value_store_->RefreshPolicyPrefsCompletion(
- new_managed_platform_store.release(),
- new DummyPrefStore(),
- new DummyPrefStore(),
- NewCallback(&callback5,
- &MockPolicyRefreshCallback::DoCallback));
-}
-
-TEST_F(PrefValueStoreTest, TestConcurrentPolicyRefresh) {
- MockPolicyRefreshCallback callback1;
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(
- pref_value_store_.get(),
- &PrefValueStore::RefreshPolicyPrefs,
- NewCallback(&callback1,
- &MockPolicyRefreshCallback::DoCallback)));
- EXPECT_CALL(callback1, DoCallback(_)).Times(0);
-
- MockPolicyRefreshCallback callback2;
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(
- pref_value_store_.get(),
- &PrefValueStore::RefreshPolicyPrefs,
- NewCallback(&callback2,
- &MockPolicyRefreshCallback::DoCallback)));
- EXPECT_CALL(callback2, DoCallback(_)).Times(0);
-
- MockPolicyRefreshCallback callback3;
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(
- pref_value_store_.get(),
- &PrefValueStore::RefreshPolicyPrefs,
- NewCallback(&callback3,
- &MockPolicyRefreshCallback::DoCallback)));
- EXPECT_CALL(callback3, DoCallback(_)).Times(0);
- Mock::VerifyAndClearExpectations(&callback1);
- Mock::VerifyAndClearExpectations(&callback2);
- Mock::VerifyAndClearExpectations(&callback3);
-
- EXPECT_CALL(callback1, DoCallback(expected_differing_paths_)).Times(1);
- std::vector<std::string> no_differing_paths;
- EXPECT_CALL(callback2, DoCallback(no_differing_paths)).Times(1);
- EXPECT_CALL(callback3, DoCallback(no_differing_paths)).Times(1);
- loop_.RunAllPending();
-}
diff --git a/chrome/browser/prefs/proxy_prefs.cc b/chrome/browser/prefs/proxy_prefs.cc
new file mode 100644
index 0000000..7eb504c
--- /dev/null
+++ b/chrome/browser/prefs/proxy_prefs.cc
@@ -0,0 +1,45 @@
+// 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.
+
+#include "chrome/browser/prefs/proxy_prefs.h"
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace {
+
+// These names are exposed to the proxy extension API. They must be in sync
+// with the constants of ProxyPrefs.
+const char* kProxyModeNames[] = { "direct",
+ "auto_detect",
+ "pac_script",
+ "fixed_servers",
+ "system" };
+
+} // namespace
+
+namespace ProxyPrefs {
+
+COMPILE_ASSERT(arraysize(kProxyModeNames) == kModeCount,
+ kProxyModeNames_must_have_size_of_NUM_MODES);
+
+bool IntToProxyMode(int in_value, ProxyMode* out_value) {
+ DCHECK(out_value);
+ if (in_value < 0 || in_value >= kModeCount)
+ return false;
+ *out_value = static_cast<ProxyMode>(in_value);
+ return true;
+}
+
+// static
+bool StringToProxyMode(const std::string& in_value, ProxyMode* out_value) {
+ DCHECK(out_value);
+ for (int i = 0; i < kModeCount; i++) {
+ if (in_value == kProxyModeNames[i])
+ return IntToProxyMode(i, out_value);
+ }
+ return false;
+}
+
+} // namespace
diff --git a/chrome/browser/prefs/proxy_prefs.h b/chrome/browser/prefs/proxy_prefs.h
new file mode 100644
index 0000000..bbeb44d
--- /dev/null
+++ b/chrome/browser/prefs/proxy_prefs.h
@@ -0,0 +1,45 @@
+// 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.
+
+#ifndef CHROME_BROWSER_PREFS_PROXY_PREFS_H_
+#define CHROME_BROWSER_PREFS_PROXY_PREFS_H_
+#pragma once
+
+#include <string>
+
+namespace ProxyPrefs {
+
+// Possible types of specifying proxy settings. Do not change the order of
+// the constants, because numeric values are exposed to users.
+// If you add an enum constant, you should also add a string to
+// kProxyModeNames in the .cc file.
+enum ProxyMode {
+ // Direct connection to the network, other proxy preferences are ignored.
+ MODE_DIRECT = 0,
+
+ // Try to retrieve a PAC script from http://wpad/wpad.dat or fall back to
+ // direct connection.
+ MODE_AUTO_DETECT = 1,
+
+ // Try to retrieve a PAC script from kProxyPacURL or fall back to direct
+ // connection.
+ MODE_PAC_SCRIPT = 2,
+
+ // Use the settings specified in kProxyServer and kProxyBypassList.
+ MODE_FIXED_SERVERS = 3,
+
+ // The system's proxy settings are used, other proxy preferences are
+ // ignored.
+ MODE_SYSTEM = 4,
+
+ kModeCount
+};
+
+bool IntToProxyMode(int in_value, ProxyMode* out_value);
+bool StringToProxyMode(const std::string& in_value,
+ ProxyMode* out_value);
+
+} // namespace ProxyPrefs
+
+#endif // CHROME_BROWSER_PREFS_PROXY_PREFS_H_
diff --git a/chrome/browser/prefs/proxy_prefs_unittest.cc b/chrome/browser/prefs/proxy_prefs_unittest.cc
new file mode 100644
index 0000000..72aa0f1
--- /dev/null
+++ b/chrome/browser/prefs/proxy_prefs_unittest.cc
@@ -0,0 +1,52 @@
+// 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.
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/values.h"
+#include "base/version.h"
+#include "chrome/browser/prefs/proxy_prefs.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(ProxyPrefsTest, StringToProxyMode) {
+ ProxyPrefs::ProxyMode mode;
+ EXPECT_TRUE(ProxyPrefs::StringToProxyMode("direct", &mode));
+ EXPECT_EQ(ProxyPrefs::MODE_DIRECT, mode);
+ EXPECT_TRUE(ProxyPrefs::StringToProxyMode("auto_detect", &mode));
+ EXPECT_EQ(ProxyPrefs::MODE_AUTO_DETECT, mode);
+ EXPECT_TRUE(ProxyPrefs::StringToProxyMode("pac_script", &mode));
+ EXPECT_EQ(ProxyPrefs::MODE_PAC_SCRIPT, mode);
+ EXPECT_TRUE(ProxyPrefs::StringToProxyMode("system", &mode));
+ EXPECT_EQ(ProxyPrefs::MODE_SYSTEM, mode);
+ EXPECT_TRUE(ProxyPrefs::StringToProxyMode("fixed_servers", &mode));
+ EXPECT_EQ(ProxyPrefs::MODE_FIXED_SERVERS, mode);
+
+ EXPECT_FALSE(ProxyPrefs::StringToProxyMode("monkey", &mode));
+}
+
+TEST(ProxyPrefsTest, IntToProxyMode) {
+ ASSERT_EQ(ProxyPrefs::MODE_DIRECT, 0);
+ ASSERT_EQ(ProxyPrefs::MODE_AUTO_DETECT, 1);
+ ASSERT_EQ(ProxyPrefs::MODE_PAC_SCRIPT, 2);
+ ASSERT_EQ(ProxyPrefs::MODE_FIXED_SERVERS, 3);
+ ASSERT_EQ(ProxyPrefs::MODE_SYSTEM, 4);
+ // Update the following as necessary, don't change the previous ones.
+ ASSERT_EQ(ProxyPrefs::kModeCount, 5);
+
+ ProxyPrefs::ProxyMode mode;
+ EXPECT_TRUE(ProxyPrefs::IntToProxyMode(0, &mode));
+ EXPECT_EQ(ProxyPrefs::MODE_DIRECT, mode);
+ EXPECT_TRUE(ProxyPrefs::IntToProxyMode(1, &mode));
+ EXPECT_EQ(ProxyPrefs::MODE_AUTO_DETECT, mode);
+ EXPECT_TRUE(ProxyPrefs::IntToProxyMode(2, &mode));
+ EXPECT_EQ(ProxyPrefs::MODE_PAC_SCRIPT, mode);
+ EXPECT_TRUE(ProxyPrefs::IntToProxyMode(3, &mode));
+ EXPECT_EQ(ProxyPrefs::MODE_FIXED_SERVERS, mode);
+ EXPECT_TRUE(ProxyPrefs::IntToProxyMode(4, &mode));
+ EXPECT_EQ(ProxyPrefs::MODE_SYSTEM, mode);
+
+ EXPECT_FALSE(ProxyPrefs::IntToProxyMode(-1, &mode));
+ EXPECT_FALSE(ProxyPrefs::IntToProxyMode(ProxyPrefs::kModeCount, &mode));
+}
diff --git a/chrome/browser/prefs/scoped_pref_update.cc b/chrome/browser/prefs/scoped_pref_update.cc
index bc77b28..024d71b 100644
--- a/chrome/browser/prefs/scoped_pref_update.cc
+++ b/chrome/browser/prefs/scoped_pref_update.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/prefs/scoped_pref_update.h"
+#include "chrome/browser/prefs/pref_notifier.h"
#include "chrome/browser/prefs/pref_service.h"
ScopedPrefUpdate::ScopedPrefUpdate(PrefService* service, const char* path)
@@ -11,5 +12,8 @@ ScopedPrefUpdate::ScopedPrefUpdate(PrefService* service, const char* path)
path_(path) {}
ScopedPrefUpdate::~ScopedPrefUpdate() {
- service_->pref_notifier()->FireObservers(path_.c_str());
+ // TODO(mnissler, danno): This sends a notification unconditionally, which is
+ // wrong. We should rather tell the PrefService that the user pref got
+ // updated.
+ service_->pref_notifier()->OnPreferenceChanged(path_.c_str());
}
diff --git a/chrome/browser/prefs/session_startup_pref.cc b/chrome/browser/prefs/session_startup_pref.cc
index 188bb4c..b339e1d 100644
--- a/chrome/browser/prefs/session_startup_pref.cc
+++ b/chrome/browser/prefs/session_startup_pref.cc
@@ -12,7 +12,7 @@
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prefs/scoped_pref_update.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
namespace {
diff --git a/chrome/browser/prefs/testing_pref_store.cc b/chrome/browser/prefs/testing_pref_store.cc
new file mode 100644
index 0000000..39c20f2
--- /dev/null
+++ b/chrome/browser/prefs/testing_pref_store.cc
@@ -0,0 +1,100 @@
+// 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.
+
+#include "chrome/browser/prefs/testing_pref_store.h"
+
+#include "base/values.h"
+
+TestingPrefStore::TestingPrefStore()
+ : read_only_(true),
+ prefs_written_(false),
+ init_complete_(false) { }
+
+PrefStore::ReadResult TestingPrefStore::GetValue(const std::string& key,
+ Value** value) const {
+ return prefs_.GetValue(key, value) ? READ_OK : READ_NO_VALUE;
+}
+
+void TestingPrefStore::AddObserver(PrefStore::Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void TestingPrefStore::RemoveObserver(PrefStore::Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void TestingPrefStore::SetValue(const std::string& key, Value* value) {
+ if (prefs_.SetValue(key, value))
+ NotifyPrefValueChanged(key);
+}
+
+void TestingPrefStore::SetValueSilently(const std::string& key, Value* value) {
+ prefs_.SetValue(key, value);
+}
+
+void TestingPrefStore::RemoveValue(const std::string& key) {
+ if (prefs_.RemoveValue(key))
+ NotifyPrefValueChanged(key);
+}
+
+PersistentPrefStore::PrefReadError TestingPrefStore::ReadPrefs() {
+ prefs_.Clear();
+ return PersistentPrefStore::PREF_READ_ERROR_NONE;
+}
+
+bool TestingPrefStore::WritePrefs() {
+ prefs_written_ = true;
+ return prefs_written_;
+}
+
+void TestingPrefStore::SetInitializationCompleted() {
+ init_complete_ = true;
+ NotifyInitializationCompleted();
+}
+
+void TestingPrefStore::NotifyPrefValueChanged(const std::string& key) {
+ FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
+}
+
+void TestingPrefStore::NotifyInitializationCompleted() {
+ FOR_EACH_OBSERVER(Observer, observers_, OnInitializationCompleted());
+}
+
+void TestingPrefStore::SetString(const std::string& key,
+ const std::string& value) {
+ SetValue(key, Value::CreateStringValue(value));
+}
+
+void TestingPrefStore::SetInteger(const std::string& key, int value) {
+ SetValue(key, Value::CreateIntegerValue(value));
+}
+
+void TestingPrefStore::SetBoolean(const std::string& key, bool value) {
+ SetValue(key, Value::CreateBooleanValue(value));
+}
+
+bool TestingPrefStore::GetString(const std::string& key,
+ std::string* value) const {
+ Value* stored_value;
+ if (!prefs_.GetValue(key, &stored_value) || !stored_value)
+ return false;
+
+ return stored_value->GetAsString(value);
+}
+
+bool TestingPrefStore::GetInteger(const std::string& key, int* value) const {
+ Value* stored_value;
+ if (!prefs_.GetValue(key, &stored_value) || !stored_value)
+ return false;
+
+ return stored_value->GetAsInteger(value);
+}
+
+bool TestingPrefStore::GetBoolean(const std::string& key, bool* value) const {
+ Value* stored_value;
+ if (!prefs_.GetValue(key, &stored_value) || !stored_value)
+ return false;
+
+ return stored_value->GetAsBoolean(value);
+}
diff --git a/chrome/browser/prefs/testing_pref_store.h b/chrome/browser/prefs/testing_pref_store.h
new file mode 100644
index 0000000..555ee69
--- /dev/null
+++ b/chrome/browser/prefs/testing_pref_store.h
@@ -0,0 +1,80 @@
+// 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.
+
+#ifndef CHROME_BROWSER_PREFS_TESTING_PREF_STORE_H_
+#define CHROME_BROWSER_PREFS_TESTING_PREF_STORE_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/observer_list.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/prefs/pref_value_map.h"
+#include "chrome/common/persistent_pref_store.h"
+
+class DictionaryValue;
+
+// |TestingPrefStore| is a preference store implementation that allows tests to
+// explicitly manipulate the contents of the store, triggering notifications
+// where appropriate.
+class TestingPrefStore : public PersistentPrefStore {
+ public:
+ TestingPrefStore();
+ virtual ~TestingPrefStore() {}
+
+ // Overriden from PrefStore.
+ virtual ReadResult GetValue(const std::string& key, Value** result) const;
+ virtual void AddObserver(PrefStore::Observer* observer);
+ virtual void RemoveObserver(PrefStore::Observer* observer);
+ virtual bool IsInitializationComplete() const { return init_complete_; }
+
+ // PersistentPrefStore overrides:
+ virtual void SetValue(const std::string& key, Value* value);
+ virtual void SetValueSilently(const std::string& key, Value* value);
+ virtual void RemoveValue(const std::string& key);
+ virtual bool ReadOnly() const { return read_only_; }
+ virtual PersistentPrefStore::PrefReadError ReadPrefs();
+ virtual bool WritePrefs();
+ virtual void ScheduleWritePrefs() {}
+
+ // 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;
+
+ // Getter and Setter methods for setting and getting the state of the
+ // |TestingPrefStore|.
+ virtual void set_read_only(bool read_only) { read_only_ = read_only; }
+ virtual void set_prefs_written(bool status) { prefs_written_ = status; }
+ virtual bool get_prefs_written() { return prefs_written_; }
+
+ private:
+ // Stores the preference values.
+ PrefValueMap prefs_;
+
+ // Flag that indicates if the PrefStore is read-only
+ bool read_only_;
+
+ // Flag that indicates if the method WritePrefs was called.
+ bool prefs_written_;
+
+ // Whether initialization has been completed.
+ bool init_complete_;
+
+ ObserverList<PrefStore::Observer, true> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestingPrefStore);
+};
+
+#endif // CHROME_BROWSER_PREFS_TESTING_PREF_STORE_H_
diff --git a/chrome/browser/prefs/value_map_pref_store.cc b/chrome/browser/prefs/value_map_pref_store.cc
new file mode 100644
index 0000000..705c958
--- /dev/null
+++ b/chrome/browser/prefs/value_map_pref_store.cc
@@ -0,0 +1,41 @@
+// 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.
+
+#include "chrome/browser/prefs/value_map_pref_store.h"
+
+#include <algorithm>
+
+#include "base/stl_util-inl.h"
+#include "base/values.h"
+
+ValueMapPrefStore::ValueMapPrefStore() {}
+
+ValueMapPrefStore::~ValueMapPrefStore() {}
+
+PrefStore::ReadResult ValueMapPrefStore::GetValue(const std::string& key,
+ Value** value) const {
+ return prefs_.GetValue(key, value) ? READ_OK : READ_NO_VALUE;
+}
+
+void ValueMapPrefStore::AddObserver(PrefStore::Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void ValueMapPrefStore::RemoveObserver(PrefStore::Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void ValueMapPrefStore::SetValue(const std::string& key, Value* value) {
+ if (prefs_.SetValue(key, value))
+ FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
+}
+
+void ValueMapPrefStore::RemoveValue(const std::string& key) {
+ if (prefs_.RemoveValue(key))
+ FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
+}
+
+void ValueMapPrefStore::NotifyInitializationCompleted() {
+ FOR_EACH_OBSERVER(Observer, observers_, OnInitializationCompleted());
+}
diff --git a/chrome/browser/prefs/value_map_pref_store.h b/chrome/browser/prefs/value_map_pref_store.h
new file mode 100644
index 0000000..20bf290
--- /dev/null
+++ b/chrome/browser/prefs/value_map_pref_store.h
@@ -0,0 +1,48 @@
+// 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.
+
+#ifndef CHROME_BROWSER_PREFS_VALUE_MAP_PREF_STORE_H_
+#define CHROME_BROWSER_PREFS_VALUE_MAP_PREF_STORE_H_
+#pragma once
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/observer_list.h"
+#include "chrome/browser/prefs/pref_value_map.h"
+#include "chrome/common/pref_store.h"
+
+// A basic PrefStore implementation that uses a simple name-value map for
+// storing the preference values.
+class ValueMapPrefStore : public PrefStore {
+ public:
+ ValueMapPrefStore();
+ virtual ~ValueMapPrefStore();
+
+ // PrefStore overrides:
+ virtual ReadResult GetValue(const std::string& key, Value** value) const;
+ virtual void AddObserver(PrefStore::Observer* observer);
+ virtual void RemoveObserver(PrefStore::Observer* observer);
+
+ protected:
+ // Store a |value| for |key| in the store. Also generates an notification if
+ // the value changed. Assumes ownership of |value|, which must be non-NULL.
+ void SetValue(const std::string& key, Value* value);
+
+ // Remove the value for |key| from the store. Sends a notification if there
+ // was a value to be removed.
+ void RemoveValue(const std::string& key);
+
+ // Notify observers about the initialization completed event.
+ void NotifyInitializationCompleted();
+
+ private:
+ PrefValueMap prefs_;
+
+ ObserverList<PrefStore::Observer, true> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(ValueMapPrefStore);
+};
+
+#endif // CHROME_BROWSER_PREFS_VALUE_MAP_PREF_STORE_H_
diff --git a/chrome/browser/prerender/prerender_contents.cc b/chrome/browser/prerender/prerender_contents.cc
new file mode 100644
index 0000000..4970739
--- /dev/null
+++ b/chrome/browser/prerender/prerender_contents.cc
@@ -0,0 +1,217 @@
+// 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.
+
+#include "chrome/browser/prerender/prerender_contents.h"
+
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/background_contents_service.h"
+#include "chrome/browser/browsing_instance.h"
+#include "chrome/browser/prerender/prerender_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/renderer_host/site_instance.h"
+#include "chrome/browser/renderer_preferences_util.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/common/view_types.h"
+#include "chrome/common/render_messages_params.h"
+#include "gfx/rect.h"
+
+PrerenderContents::PrerenderContents(PrerenderManager* prerender_manager,
+ Profile* profile,
+ const GURL& url)
+ : prerender_manager_(prerender_manager),
+ render_view_host_(NULL),
+ prerender_url_(url),
+ profile_(profile),
+ page_id_(0) {
+ DCHECK(prerender_manager != NULL);
+}
+
+void PrerenderContents::StartPrerendering() {
+ DCHECK(profile_ != NULL);
+ SiteInstance* site_instance = SiteInstance::CreateSiteInstance(profile_);
+ render_view_host_ = new RenderViewHost(site_instance, this, MSG_ROUTING_NONE,
+ NULL);
+ render_view_host_->AllowScriptToClose(true);
+
+ // Close ourselves when the application is shutting down.
+ registrar_.Add(this, NotificationType::APP_TERMINATING,
+ NotificationService::AllSources());
+
+ // Register for our parent profile to shutdown, so we can shut ourselves down
+ // as well (should only be called for OTR profiles, as we should receive
+ // APP_TERMINATING before non-OTR profiles are destroyed).
+ // TODO(tburkard): figure out if this is needed.
+ registrar_.Add(this, NotificationType::PROFILE_DESTROYED,
+ Source<Profile>(profile_));
+ render_view_host_->CreateRenderView(string16());
+ render_view_host_->NavigateToURL(prerender_url_);
+}
+
+PrerenderContents::~PrerenderContents() {
+ if (!render_view_host_) // Will be null for unit tests.
+ return;
+
+ render_view_host_->Shutdown(); // deletes render_view_host
+}
+
+RenderViewHostDelegate::View* PrerenderContents::GetViewDelegate() {
+ return this;
+}
+
+const GURL& PrerenderContents::GetURL() const {
+ return url_;
+}
+
+ViewType::Type PrerenderContents::GetRenderViewType() const {
+ return ViewType::BACKGROUND_CONTENTS;
+}
+
+int PrerenderContents::GetBrowserWindowID() const {
+ return extension_misc::kUnknownWindowId;
+}
+
+void PrerenderContents::DidNavigate(
+ RenderViewHost* render_view_host,
+ const ViewHostMsg_FrameNavigate_Params& params) {
+ // We only care when the outer frame changes.
+ if (!PageTransition::IsMainFrame(params.transition))
+ return;
+
+ // Store the navigation params.
+ ViewHostMsg_FrameNavigate_Params* p = new ViewHostMsg_FrameNavigate_Params();
+ *p = params;
+ navigate_params_.reset(p);
+
+ url_ = params.url;
+}
+
+void PrerenderContents::UpdateTitle(RenderViewHost* render_view_host,
+ int32 page_id,
+ const std::wstring& title) {
+ if (title.empty()) {
+ return;
+ }
+
+ title_ = WideToUTF16Hack(title);
+ page_id_ = page_id;
+}
+
+void PrerenderContents::RunJavaScriptMessage(
+ const std::wstring& message,
+ const std::wstring& default_prompt,
+ const GURL& frame_url,
+ const int flags,
+ IPC::Message* reply_msg,
+ bool* did_suppress_message) {
+ *did_suppress_message = true;
+}
+
+bool PrerenderContents::PreHandleKeyboardEvent(
+ const NativeWebKeyboardEvent& event,
+ bool* is_keyboard_shortcut) {
+ return false;
+}
+
+void PrerenderContents::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ switch (type.value) {
+ case NotificationType::PROFILE_DESTROYED:
+ case NotificationType::APP_TERMINATING: {
+ prerender_manager_->RemoveEntry(this);
+ break;
+ }
+ default:
+ NOTREACHED() << "Unexpected notification sent.";
+ break;
+ }
+}
+
+void PrerenderContents::OnMessageBoxClosed(IPC::Message* reply_msg,
+ bool success,
+ const std::wstring& prompt) {
+ render_view_host_->JavaScriptMessageBoxClosed(reply_msg, success, prompt);
+}
+
+gfx::NativeWindow PrerenderContents::GetMessageBoxRootWindow() {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+TabContents* PrerenderContents::AsTabContents() {
+ return NULL;
+}
+
+ExtensionHost* PrerenderContents::AsExtensionHost() {
+ return NULL;
+}
+
+void PrerenderContents::UpdateInspectorSetting(const std::string& key,
+ const std::string& value) {
+ RenderViewHostDelegateHelper::UpdateInspectorSetting(profile_, key, value);
+}
+
+void PrerenderContents::ClearInspectorSettings() {
+ RenderViewHostDelegateHelper::ClearInspectorSettings(profile_);
+}
+
+void PrerenderContents::Close(RenderViewHost* render_view_host) {
+ prerender_manager_->RemoveEntry(this);
+}
+
+RendererPreferences PrerenderContents::GetRendererPrefs(
+ Profile* profile) const {
+ RendererPreferences preferences;
+ renderer_preferences_util::UpdateFromSystemSettings(&preferences, profile);
+ return preferences;
+}
+
+WebPreferences PrerenderContents::GetWebkitPrefs() {
+ return RenderViewHostDelegateHelper::GetWebkitPrefs(profile_,
+ false); // is_dom_ui
+}
+
+void PrerenderContents::ProcessDOMUIMessage(
+ const ViewHostMsg_DomMessage_Params& params) {
+ render_view_host_->BlockExtensionRequest(params.request_id);
+}
+
+void PrerenderContents::CreateNewWindow(
+ int route_id,
+ WindowContainerType window_container_type,
+ const string16& frame_name) {
+ // Since we don't want to permit child windows that would have a
+ // window.opener property, terminate prerendering.
+ prerender_manager_->RemoveEntry(this);
+}
+
+void PrerenderContents::CreateNewWidget(int route_id,
+ WebKit::WebPopupType popup_type) {
+ NOTREACHED();
+}
+
+void PrerenderContents::CreateNewFullscreenWidget(
+ int route_id, WebKit::WebPopupType popup_type) {
+ NOTREACHED();
+}
+
+void PrerenderContents::ShowCreatedWindow(int route_id,
+ WindowOpenDisposition disposition,
+ const gfx::Rect& initial_pos,
+ bool user_gesture) {
+ // TODO(tburkard): need to figure out what the correct behavior here is
+ NOTIMPLEMENTED();
+}
+
+void PrerenderContents::ShowCreatedWidget(int route_id,
+ const gfx::Rect& initial_pos) {
+ NOTIMPLEMENTED();
+}
+
+void PrerenderContents::ShowCreatedFullscreenWidget(int route_id) {
+ NOTIMPLEMENTED();
+}
diff --git a/chrome/browser/prerender/prerender_contents.h b/chrome/browser/prerender/prerender_contents.h
new file mode 100644
index 0000000..bf2963f
--- /dev/null
+++ b/chrome/browser/prerender/prerender_contents.h
@@ -0,0 +1,168 @@
+// 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.
+
+#ifndef CHROME_BROWSER_PRERENDER_PRERENDER_CONTENTS_H_
+#define CHROME_BROWSER_PRERENDER_PRERENDER_CONTENTS_H_
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "chrome/browser/renderer_host/render_view_host_delegate.h"
+#include "chrome/browser/tab_contents/render_view_host_delegate_helper.h"
+#include "chrome/browser/ui/app_modal_dialogs/js_modal_dialog.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/view_types.h"
+#include "chrome/common/window_container_type.h"
+#include "webkit/glue/window_open_disposition.h"
+
+class TabContents;
+class PrerenderManager;
+struct WebPreferences;
+struct ViewHostMsg_FrameNavigate_Params;
+
+namespace gfx {
+class Rect;
+}
+
+// This class is a peer of TabContents. It can host a renderer, but does not
+// have any visible display. Its navigation is not managed by a
+// NavigationController because is has no facility for navigating (other than
+// programatically view window.location.href) or RenderViewHostManager because
+// it is never allowed to navigate across a SiteInstance boundary.
+class PrerenderContents : public RenderViewHostDelegate,
+ public RenderViewHostDelegate::View,
+ public NotificationObserver,
+ public JavaScriptAppModalDialogDelegate {
+ public:
+ PrerenderContents(PrerenderManager* prerender_manager, Profile* profile,
+ const GURL& url);
+ virtual ~PrerenderContents();
+ virtual void StartPrerendering();
+
+ RenderViewHost* render_view_host() { return render_view_host_; }
+ // Allows replacing of the RenderViewHost owned by this class, including
+ // replacing with a NULL value. When a caller uses this, the caller will
+ // own (and is responsible for freeing) the old RVH.
+ void set_render_view_host(RenderViewHost* rvh) { render_view_host_ = rvh; }
+ ViewHostMsg_FrameNavigate_Params* navigate_params() {
+ return navigate_params_.get();
+ }
+ string16 title() const { return title_; }
+ int32 page_id() const { return page_id_; }
+
+ // RenderViewHostDelegate implementation.
+ virtual RenderViewHostDelegate::View* GetViewDelegate();
+ virtual const GURL& GetURL() const;
+ virtual ViewType::Type GetRenderViewType() const;
+ virtual int GetBrowserWindowID() const;
+ virtual void DidNavigate(RenderViewHost* render_view_host,
+ const ViewHostMsg_FrameNavigate_Params& params);
+ virtual void UpdateTitle(RenderViewHost* render_view_host,
+ int32 page_id,
+ const std::wstring& title);
+ virtual WebPreferences GetWebkitPrefs();
+ virtual void ProcessDOMUIMessage(const ViewHostMsg_DomMessage_Params& params);
+ virtual void RunJavaScriptMessage(const std::wstring& message,
+ const std::wstring& default_prompt,
+ const GURL& frame_url,
+ const int flags,
+ IPC::Message* reply_msg,
+ bool* did_suppress_message);
+ virtual void Close(RenderViewHost* render_view_host);
+ virtual RendererPreferences GetRendererPrefs(Profile* profile) const;
+
+ // RenderViewHostDelegate::View
+ virtual void CreateNewWindow(
+ int route_id,
+ WindowContainerType window_container_type,
+ const string16& frame_name);
+ virtual void CreateNewWidget(int route_id, WebKit::WebPopupType popup_type);
+ virtual void CreateNewFullscreenWidget(
+ int route_id, WebKit::WebPopupType popup_type);
+ virtual void ShowCreatedWindow(int route_id,
+ WindowOpenDisposition disposition,
+ const gfx::Rect& initial_pos,
+ bool user_gesture);
+ virtual void ShowCreatedWidget(int route_id,
+ const gfx::Rect& initial_pos);
+ virtual void ShowCreatedFullscreenWidget(int route_id);
+ virtual void ShowContextMenu(const ContextMenuParams& params) {}
+ virtual void ShowPopupMenu(const gfx::Rect& bounds,
+ int item_height,
+ double item_font_size,
+ int selected_item,
+ const std::vector<WebMenuItem>& items,
+ bool right_aligned) {}
+ virtual void StartDragging(const WebDropData& drop_data,
+ WebKit::WebDragOperationsMask allowed_operations,
+ const SkBitmap& image,
+ const gfx::Point& image_offset) {}
+ virtual void UpdateDragCursor(WebKit::WebDragOperation operation) {}
+ virtual void GotFocus() {}
+ virtual void TakeFocus(bool reverse) {}
+ virtual void LostCapture() {}
+ virtual void Activate() {}
+ virtual void Deactivate() {}
+ virtual bool PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
+ bool* is_keyboard_shortcut);
+ virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {}
+ virtual void HandleMouseMove() {}
+ virtual void HandleMouseDown() {}
+ virtual void HandleMouseLeave() {}
+ virtual void HandleMouseUp() {}
+ virtual void HandleMouseActivate() {}
+ virtual void UpdatePreferredSize(const gfx::Size& new_size) {}
+
+ // NotificationObserver
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // Overridden from JavaScriptAppModalDialogDelegate:
+ virtual void OnMessageBoxClosed(IPC::Message* reply_msg,
+ bool success,
+ const std::wstring& prompt);
+ virtual void SetSuppressMessageBoxes(bool suppress_message_boxes) {}
+ virtual gfx::NativeWindow GetMessageBoxRootWindow();
+ virtual TabContents* AsTabContents();
+ virtual ExtensionHost* AsExtensionHost();
+
+ virtual void UpdateInspectorSetting(const std::string& key,
+ const std::string& value);
+ virtual void ClearInspectorSettings();
+
+ private:
+ // The prerender manager owning this object.
+ PrerenderManager* prerender_manager_;
+
+ // The host for our HTML content.
+ RenderViewHost* render_view_host_;
+
+ // Common implementations of some RenderViewHostDelegate::View methods.
+ RenderViewHostDelegateViewHelper delegate_view_helper_;
+
+ // The URL being prerendered.
+ GURL prerender_url_;
+
+ // The NavigationParameters of the finished navigation.
+ scoped_ptr<ViewHostMsg_FrameNavigate_Params> navigate_params_;
+
+ // The profile being used
+ Profile* profile_;
+
+ // Information about the title and URL of the page that this class as a
+ // RenderViewHostDelegate has received from the RenderView.
+ // Used to apply to the new RenderViewHost delegate that might eventually
+ // own the contained RenderViewHost when the prerendered page is shown
+ // in a TabContents.
+ string16 title_;
+ int32 page_id_;
+ GURL url_;
+ NotificationRegistrar registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrerenderContents);
+};
+
+#endif // CHROME_BROWSER_PRERENDER_PRERENDER_CONTENTS_H_
diff --git a/chrome/browser/prerender/prerender_interceptor.cc b/chrome/browser/prerender/prerender_interceptor.cc
new file mode 100644
index 0000000..831cfff
--- /dev/null
+++ b/chrome/browser/prerender/prerender_interceptor.cc
@@ -0,0 +1,75 @@
+// 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.
+
+#include "chrome/browser/prerender/prerender_interceptor.h"
+
+#include <string>
+
+#include "base/logging.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/io_thread.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/load_flags.h"
+
+DISABLE_RUNNABLE_METHOD_REFCOUNT(PrerenderInterceptor);
+
+PrerenderInterceptor::PrerenderInterceptor()
+ : ALLOW_THIS_IN_INITIALIZER_LIST(
+ callback_(NewCallback(this,
+ &PrerenderInterceptor::PrerenderDispatch))) {
+ net::URLRequest::RegisterRequestInterceptor(this);
+}
+
+PrerenderInterceptor::PrerenderInterceptor(
+ PrerenderInterceptorCallback* callback)
+ : callback_(callback) {
+ net::URLRequest::RegisterRequestInterceptor(this);
+}
+
+PrerenderInterceptor::~PrerenderInterceptor() {
+ net::URLRequest::UnregisterRequestInterceptor(this);
+}
+
+net::URLRequestJob* PrerenderInterceptor::MaybeIntercept(
+ net::URLRequest* request) {
+ return NULL;
+}
+
+net::URLRequestJob* PrerenderInterceptor::MaybeInterceptResponse(
+ net::URLRequest* request) {
+ // TODO(gavinp): unfortunately, we can't figure out the origin
+ // of this request here on systems where the referrer is blocked by
+ // configuration.
+
+ // TODO(gavinp): note that the response still might be intercepted
+ // by a later interceptor. Should we write an interposing delegate
+ // and only prerender dispatch on requests that aren't intercepted?
+ // Or is this a slippery slope?
+
+ if (request->load_flags() & net::LOAD_PREFETCH) {
+ std::string mime_type;
+ request->GetMimeType(&mime_type);
+ if (mime_type == "text/html")
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ NewRunnableMethod(this,
+ &PrerenderInterceptor::RunCallbackFromUIThread,
+ request->url()));
+ }
+ return NULL;
+}
+
+void PrerenderInterceptor::RunCallbackFromUIThread(const GURL& url) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ callback_->Run(url);
+}
+
+void PrerenderInterceptor::PrerenderDispatch(
+ const GURL& url) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DVLOG(2) << "PrerenderDispatchOnUIThread: url=" << url;
+}
+
diff --git a/chrome/browser/prerender/prerender_interceptor.h b/chrome/browser/prerender/prerender_interceptor.h
new file mode 100644
index 0000000..8a0fe32
--- /dev/null
+++ b/chrome/browser/prerender/prerender_interceptor.h
@@ -0,0 +1,49 @@
+// 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.
+
+#ifndef CHROME_BROWSER_PRERENDER_PRERENDER_INTERCEPTOR_H_
+#define CHROME_BROWSER_PRERENDER_PRERENDER_INTERCEPTOR_H_
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/scoped_ptr.h"
+#include "base/task.h"
+#include "net/url_request/url_request.h"
+
+class GURL;
+
+// The PrerenderInterceptor watches prefetch requests, and when
+// they are for type text/html, notifies the prerendering
+// system about the fetch so it may consider the URL.
+class PrerenderInterceptor : public net::URLRequest::Interceptor {
+ public:
+ PrerenderInterceptor();
+ virtual ~PrerenderInterceptor();
+
+ // URLRequest::Interceptor overrides. We only care about
+ // MaybeInterceptResponse, but must capture MaybeIntercept since
+ // it is pure virtual.
+ virtual net::URLRequestJob* MaybeIntercept(net::URLRequest* request);
+ virtual net::URLRequestJob* MaybeInterceptResponse(net::URLRequest* request);
+
+ private:
+ friend class PrerenderInterceptorTest;
+
+ typedef Callback1<const GURL&>::Type PrerenderInterceptorCallback;
+
+ // This constructor is provided for the unit test only, to provide
+ // an an alternative dispatch target for the test only. The callback
+ // parameter is owned and deleted by this object.
+ explicit PrerenderInterceptor(PrerenderInterceptorCallback* callback);
+
+ void RunCallbackFromUIThread(const GURL& url);
+ void PrerenderDispatch(const GURL& url);
+
+ scoped_ptr<PrerenderInterceptorCallback> callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrerenderInterceptor);
+};
+
+#endif // CHROME_BROWSER_PRERENDER_PRERENDER_INTERCEPTOR_H_
+
diff --git a/chrome/browser/prerender/prerender_interceptor_unittest.cc b/chrome/browser/prerender/prerender_interceptor_unittest.cc
new file mode 100644
index 0000000..2fc236f
--- /dev/null
+++ b/chrome/browser/prerender/prerender_interceptor_unittest.cc
@@ -0,0 +1,101 @@
+// 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.
+
+#include "chrome/browser/prerender/prerender_interceptor.h"
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/file_path.h"
+#include "base/message_loop_proxy.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/browser_thread.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/load_flags.h"
+#include "net/test/test_server.h"
+#include "net/url_request/url_request_unittest.h"
+
+class PrerenderInterceptorTest : public testing::Test {
+ protected:
+ PrerenderInterceptorTest();
+
+ void MakeTestUrl(const std::string& base);
+ virtual void SetUp();
+
+ net::TestServer test_server_;
+ GURL gurl_;
+ GURL last_intercepted_gurl_;
+ scoped_ptr<net::URLRequest> req_;
+
+ private:
+ void SetLastInterceptedGurl(const GURL& url);
+
+ PrerenderInterceptor prerender_interceptor_;
+ MessageLoopForIO io_loop_;
+ scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
+ BrowserThread ui_thread_;
+ TestDelegate delegate_for_req_;
+};
+
+PrerenderInterceptorTest::PrerenderInterceptorTest()
+ : test_server_(net::TestServer::TYPE_HTTP,
+ FilePath(FILE_PATH_LITERAL("chrome/test/data"))),
+ last_intercepted_gurl_("http://not.initialized/"),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ prerender_interceptor_(
+ NewCallback(this,
+ &PrerenderInterceptorTest::SetLastInterceptedGurl))),
+ ui_thread_(BrowserThread::UI, &io_loop_) {
+}
+
+void PrerenderInterceptorTest::SetUp() {
+ testing::Test::SetUp();
+ last_intercepted_gurl_ = GURL("http://nothing.intercepted/");
+
+ io_message_loop_proxy_ = base::MessageLoopProxy::CreateForCurrentThread();
+ ASSERT_TRUE(test_server_.Start());
+}
+
+void PrerenderInterceptorTest::MakeTestUrl(const std::string& base) {
+ gurl_ = test_server_.GetURL(base);
+ req_.reset(new TestURLRequest(gurl_, &delegate_for_req_));
+}
+
+void PrerenderInterceptorTest::SetLastInterceptedGurl(const GURL& url) {
+ last_intercepted_gurl_ = url;
+}
+
+namespace {
+
+TEST_F(PrerenderInterceptorTest, Interception) {
+ MakeTestUrl("files/prerender/doc1.html");
+ req_->set_load_flags(req_->load_flags() | net::LOAD_PREFETCH);
+ req_->Start();
+
+ MessageLoop::current()->Run();
+ EXPECT_EQ(URLRequestStatus::SUCCESS, req_->status().status());
+ EXPECT_EQ(gurl_, last_intercepted_gurl_);
+}
+
+TEST_F(PrerenderInterceptorTest, NotAPrefetch) {
+ MakeTestUrl("files/prerender/doc2.html");
+ req_->set_load_flags(req_->load_flags() & ~net::LOAD_PREFETCH);
+ req_->Start();
+
+ MessageLoop::current()->Run();
+ EXPECT_EQ(URLRequestStatus::SUCCESS, req_->status().status());
+ EXPECT_NE(gurl_, last_intercepted_gurl_);
+}
+
+TEST_F(PrerenderInterceptorTest, WrongMimeType) {
+ MakeTestUrl("files/prerender/image.jpeg");
+ req_->set_load_flags(req_->load_flags() | net::LOAD_PREFETCH);
+ req_->Start();
+
+ MessageLoop::current()->Run();
+ EXPECT_EQ(URLRequestStatus::SUCCESS, req_->status().status());
+ EXPECT_NE(gurl_, last_intercepted_gurl_);
+}
+
+} // namespace
diff --git a/chrome/browser/prerender/prerender_manager.cc b/chrome/browser/prerender/prerender_manager.cc
new file mode 100644
index 0000000..0135880
--- /dev/null
+++ b/chrome/browser/prerender/prerender_manager.cc
@@ -0,0 +1,134 @@
+// 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.
+
+#include "chrome/browser/prerender/prerender_manager.h"
+
+#include "base/logging.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/prerender/prerender_contents.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/render_view_host_manager.h"
+
+struct PrerenderManager::PrerenderContentsData {
+ PrerenderContents* contents_;
+ base::Time start_time_;
+ GURL url_;
+ PrerenderContentsData(PrerenderContents* contents,
+ base::Time start_time,
+ GURL url)
+ : contents_(contents),
+ start_time_(start_time),
+ url_(url) {
+ }
+};
+
+PrerenderManager::PrerenderManager(Profile* profile)
+ : profile_(profile),
+ max_prerender_age_(base::TimeDelta::FromSeconds(
+ kDefaultMaxPrerenderAgeSeconds)),
+ max_elements_(kDefaultMaxPrerenderElements) {
+}
+
+PrerenderManager::~PrerenderManager() {
+ while (prerender_list_.size() > 0) {
+ PrerenderContentsData data = prerender_list_.front();
+ prerender_list_.pop_front();
+ delete data.contents_;
+ }
+}
+
+void PrerenderManager::AddPreload(const GURL& url) {
+ DCHECK(CalledOnValidThread());
+ DeleteOldEntries();
+ // If the URL already exists in the set of preloaded URLs, don't do anything.
+ for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin();
+ it != prerender_list_.end();
+ ++it) {
+ if (it->url_ == url)
+ return;
+ }
+ PrerenderContentsData data(CreatePrerenderContents(url),
+ GetCurrentTime(), url);
+ prerender_list_.push_back(data);
+ data.contents_->StartPrerendering();
+ while (prerender_list_.size() > max_elements_) {
+ data = prerender_list_.front();
+ prerender_list_.pop_front();
+ delete data.contents_;
+ }
+}
+
+void PrerenderManager::DeleteOldEntries() {
+ while (prerender_list_.size() > 0) {
+ PrerenderContentsData data = prerender_list_.front();
+ if (IsPrerenderElementFresh(data.start_time_))
+ return;
+ prerender_list_.pop_front();
+ delete data.contents_;
+ }
+}
+
+PrerenderContents* PrerenderManager::GetEntry(const GURL& url) {
+ DeleteOldEntries();
+ for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin();
+ it != prerender_list_.end();
+ ++it) {
+ if (it->url_ == url) {
+ PrerenderContents* pc = it->contents_;
+ prerender_list_.erase(it);
+ return pc;
+ }
+ }
+ // Entry not found.
+ return NULL;
+}
+
+bool PrerenderManager::MaybeUsePreloadedPage(TabContents* tc, const GURL& url) {
+ DCHECK(CalledOnValidThread());
+ scoped_ptr<PrerenderContents> pc(GetEntry(url));
+ if (pc.get() == NULL)
+ return false;
+
+ RenderViewHost* rvh = pc->render_view_host();
+ pc->set_render_view_host(NULL);
+ tc->SwapInRenderViewHost(rvh);
+
+ ViewHostMsg_FrameNavigate_Params* p = pc->navigate_params();
+ if (p != NULL)
+ tc->DidNavigate(rvh, *p);
+
+ string16 title = pc->title();
+ if (!title.empty())
+ tc->UpdateTitle(rvh, pc->page_id(), UTF16ToWideHack(title));
+
+ return true;
+}
+
+void PrerenderManager::RemoveEntry(PrerenderContents* entry) {
+ DCHECK(CalledOnValidThread());
+ for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin();
+ it != prerender_list_.end();
+ ++it) {
+ if (it->contents_ == entry) {
+ prerender_list_.erase(it);
+ break;
+ }
+ }
+ delete entry;
+ DeleteOldEntries();
+}
+
+base::Time PrerenderManager::GetCurrentTime() const {
+ return base::Time::Now();
+}
+
+bool PrerenderManager::IsPrerenderElementFresh(const base::Time start) const {
+ base::Time now = GetCurrentTime();
+ return (now - start < max_prerender_age_);
+}
+
+PrerenderContents* PrerenderManager::CreatePrerenderContents(const GURL& url) {
+ return new PrerenderContents(this, profile_, url);
+}
diff --git a/chrome/browser/prerender/prerender_manager.h b/chrome/browser/prerender/prerender_manager.h
new file mode 100644
index 0000000..045581c
--- /dev/null
+++ b/chrome/browser/prerender/prerender_manager.h
@@ -0,0 +1,81 @@
+// 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.
+
+#ifndef CHROME_BROWSER_PRERENDER_PRERENDER_MANAGER_H_
+#define CHROME_BROWSER_PRERENDER_PRERENDER_MANAGER_H_
+#pragma once
+
+#include <list>
+
+#include "base/non_thread_safe.h"
+#include "base/scoped_ptr.h"
+#include "base/time.h"
+#include "googleurl/src/gurl.h"
+
+class PrerenderContents;
+class Profile;
+class TabContents;
+
+// PrerenderManager is responsible for initiating and keeping prerendered
+// views of webpages.
+class PrerenderManager : NonThreadSafe {
+ public:
+ // Owned by a Profile object for the lifetime of the profile.
+ explicit PrerenderManager(Profile* profile);
+ virtual ~PrerenderManager();
+
+ // Preloads the URL supplied.
+ void AddPreload(const GURL& url);
+
+ // For a given TabContents that wants to navigate to the URL supplied,
+ // determines whether a preloaded version of the URL can be used,
+ // and substitutes the prerendered RVH into the TabContents. Returns
+ // whether or not a prerendered RVH could be used or not.
+ bool MaybeUsePreloadedPage(TabContents* tc, const GURL& url);
+
+ // Allows PrerenderContents to remove itself when prerendering should
+ // be cancelled. Also deletes the entry.
+ void RemoveEntry(PrerenderContents* entry);
+
+ // Retrieves the PrerenderContents object for the specified URL, if it
+ // has been prerendered. The caller will then have ownership of the
+ // PrerenderContents object and is responsible for freeing it.
+ // Returns NULL if the specified URL has not been prerendered.
+ PrerenderContents* GetEntry(const GURL& url);
+
+ base::TimeDelta max_prerender_age() const { return max_prerender_age_; }
+ void set_max_prerender_age(base::TimeDelta td) { max_prerender_age_ = td; }
+ unsigned int max_elements() const { return max_elements_; }
+ void set_max_elements(unsigned int num) { max_elements_ = num; }
+
+ protected:
+ // The following methods exist explicitly rather than just inlined to
+ // facilitate testing.
+ virtual base::Time GetCurrentTime() const;
+ virtual PrerenderContents* CreatePrerenderContents(const GURL& url);
+
+ private:
+ struct PrerenderContentsData;
+
+ bool IsPrerenderElementFresh(const base::Time start) const;
+ void DeleteOldEntries();
+
+ Profile* profile_;
+
+ base::TimeDelta max_prerender_age_;
+ unsigned int max_elements_;
+
+ // List of prerendered elements.
+ std::list<PrerenderContentsData> prerender_list_;
+
+ // Default maximum permitted elements to prerender.
+ static const unsigned int kDefaultMaxPrerenderElements = 1;
+
+ // Default maximum age a prerendered element may have, in seconds.
+ static const int kDefaultMaxPrerenderAgeSeconds = 20;
+
+ DISALLOW_COPY_AND_ASSIGN(PrerenderManager);
+};
+
+#endif // CHROME_BROWSER_PRERENDER_PRERENDER_MANAGER_H_
diff --git a/chrome/browser/prerender/prerender_manager_unittest.cc b/chrome/browser/prerender/prerender_manager_unittest.cc
new file mode 100644
index 0000000..b5cb65b
--- /dev/null
+++ b/chrome/browser/prerender/prerender_manager_unittest.cc
@@ -0,0 +1,179 @@
+// 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.
+
+#include "base/time.h"
+#include "chrome/browser/prerender/prerender_contents.h"
+#include "chrome/browser/prerender/prerender_manager.h"
+#include "googleurl/src/gurl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class DummyPrerenderContents : public PrerenderContents {
+ public:
+ DummyPrerenderContents(PrerenderManager* prerender_manager, const GURL& url)
+ : PrerenderContents(prerender_manager, NULL, url),
+ has_started_(false) {
+ }
+
+ virtual void StartPrerendering() {
+ has_started_ = true;
+ }
+
+ bool has_started() const { return has_started_; }
+
+ private:
+ bool has_started_;
+};
+
+class TestPrerenderManager : public PrerenderManager {
+ public:
+ TestPrerenderManager()
+ : PrerenderManager(NULL),
+ time_(base::Time::Now()),
+ next_pc_(NULL) {
+ }
+
+ void AdvanceTime(base::TimeDelta delta) {
+ time_ += delta;
+ }
+
+ void SetNextPrerenderContents(PrerenderContents* pc) {
+ next_pc_.reset(pc);
+ }
+
+ PrerenderContents* next_pc() { return next_pc_.get(); }
+
+ protected:
+ virtual base::Time GetCurrentTime() const {
+ return time_;
+ }
+
+ virtual PrerenderContents* CreatePrerenderContents(const GURL& url) {
+ return next_pc_.release();
+ }
+
+ private:
+ base::Time time_;
+ scoped_ptr<PrerenderContents> next_pc_;
+};
+
+} // namespace
+
+class PrerenderManagerTest : public testing::Test {
+ public:
+ PrerenderManagerTest() : prerender_manager_(new TestPrerenderManager()) {
+ }
+
+ protected:
+ scoped_ptr<TestPrerenderManager> prerender_manager_;
+};
+
+TEST_F(PrerenderManagerTest, EmptyTest) {
+ GURL url("http://www.google.com/");
+ EXPECT_FALSE(prerender_manager_->MaybeUsePreloadedPage(NULL, url));
+}
+
+TEST_F(PrerenderManagerTest, FoundTest) {
+ GURL url("http://www.google.com/");
+ DummyPrerenderContents* pc =
+ new DummyPrerenderContents(prerender_manager_.get(), url);
+ prerender_manager_->SetNextPrerenderContents(pc);
+ prerender_manager_->AddPreload(url);
+ EXPECT_TRUE(pc->has_started());
+ EXPECT_EQ(pc, prerender_manager_->GetEntry(url));
+ delete pc;
+}
+
+// Make sure that if queue a request, and a second prerender request for the
+// same URL comes in, that we drop the second request and keep the first one.
+TEST_F(PrerenderManagerTest, DropSecondRequestTest) {
+ GURL url("http://www.google.com/");
+ DummyPrerenderContents* pc =
+ new DummyPrerenderContents(prerender_manager_.get(), url);
+ DummyPrerenderContents* null = NULL;
+ prerender_manager_->SetNextPrerenderContents(pc);
+ prerender_manager_->AddPreload(url);
+ EXPECT_EQ(null, prerender_manager_->next_pc());
+ EXPECT_TRUE(pc->has_started());
+ DummyPrerenderContents* pc1 =
+ new DummyPrerenderContents(prerender_manager_.get(), url);
+ prerender_manager_->SetNextPrerenderContents(pc1);
+ prerender_manager_->AddPreload(url);
+ EXPECT_EQ(pc1, prerender_manager_->next_pc());
+ EXPECT_FALSE(pc1->has_started());
+ EXPECT_EQ(pc, prerender_manager_->GetEntry(url));
+ delete pc;
+}
+
+// Ensure that we expire a prerendered page after the max. permitted time.
+TEST_F(PrerenderManagerTest, ExpireTest) {
+ GURL url("http://www.google.com/");
+ DummyPrerenderContents* pc =
+ new DummyPrerenderContents(prerender_manager_.get(), url);
+ DummyPrerenderContents* null = NULL;
+ prerender_manager_->SetNextPrerenderContents(pc);
+ prerender_manager_->AddPreload(url);
+ EXPECT_EQ(null, prerender_manager_->next_pc());
+ EXPECT_TRUE(pc->has_started());
+ prerender_manager_->AdvanceTime(prerender_manager_->max_prerender_age()
+ + base::TimeDelta::FromSeconds(1));
+ EXPECT_EQ(null, prerender_manager_->GetEntry(url));
+}
+
+// LRU Test. Make sure that if we prerender more than one request, that
+// the oldest one will be dropped.
+TEST_F(PrerenderManagerTest, DropOldestRequestTest) {
+ GURL url("http://www.google.com/");
+ DummyPrerenderContents* pc =
+ new DummyPrerenderContents(prerender_manager_.get(), url);
+ DummyPrerenderContents* null = NULL;
+ prerender_manager_->SetNextPrerenderContents(pc);
+ prerender_manager_->AddPreload(url);
+ EXPECT_EQ(null, prerender_manager_->next_pc());
+ EXPECT_TRUE(pc->has_started());
+ GURL url1("http://news.google.com/");
+ DummyPrerenderContents* pc1 =
+ new DummyPrerenderContents(prerender_manager_.get(), url1);
+ prerender_manager_->SetNextPrerenderContents(pc1);
+ prerender_manager_->AddPreload(url1);
+ EXPECT_EQ(null, prerender_manager_->next_pc());
+ EXPECT_TRUE(pc1->has_started());
+ EXPECT_EQ(null, prerender_manager_->GetEntry(url));
+ EXPECT_EQ(pc1, prerender_manager_->GetEntry(url1));
+ delete pc1;
+}
+
+// Two element prerender test. Ensure that the LRU operates correctly if we
+// permit 2 elements to be kept prerendered.
+TEST_F(PrerenderManagerTest, TwoElementPrerenderTest) {
+ prerender_manager_->set_max_elements(2);
+ GURL url("http://www.google.com/");
+ DummyPrerenderContents* pc =
+ new DummyPrerenderContents(prerender_manager_.get(), url);
+ DummyPrerenderContents* null = NULL;
+ prerender_manager_->SetNextPrerenderContents(pc);
+ prerender_manager_->AddPreload(url);
+ EXPECT_EQ(null, prerender_manager_->next_pc());
+ EXPECT_TRUE(pc->has_started());
+ GURL url1("http://news.google.com/");
+ DummyPrerenderContents* pc1 =
+ new DummyPrerenderContents(prerender_manager_.get(), url1);
+ prerender_manager_->SetNextPrerenderContents(pc1);
+ prerender_manager_->AddPreload(url1);
+ EXPECT_EQ(null, prerender_manager_->next_pc());
+ EXPECT_TRUE(pc1->has_started());
+ GURL url2("http://images.google.com/");
+ DummyPrerenderContents* pc2 =
+ new DummyPrerenderContents(prerender_manager_.get(), url2);
+ prerender_manager_->SetNextPrerenderContents(pc2);
+ prerender_manager_->AddPreload(url2);
+ EXPECT_EQ(null, prerender_manager_->next_pc());
+ EXPECT_TRUE(pc2->has_started());
+ EXPECT_EQ(null, prerender_manager_->GetEntry(url));
+ EXPECT_EQ(pc1, prerender_manager_->GetEntry(url1));
+ EXPECT_EQ(pc2, prerender_manager_->GetEntry(url2));
+ delete pc1;
+ delete pc2;
+}
diff --git a/chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc b/chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc
index c27b1a3..cafad5a 100644
--- a/chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc
+++ b/chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc
@@ -11,11 +11,12 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_thread.h"
#include "chrome/browser/notifications/desktop_notification_service.h"
#include "chrome/browser/notifications/notification.h"
#include "chrome/browser/notifications/notification_ui_manager.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/service/service_process_control.h"
#include "chrome/browser/service/service_process_control_manager.h"
#include "chrome/common/pref_names.h"
@@ -140,7 +141,7 @@ void CloudPrintProxyService::OnDialogClosed() {
void CloudPrintProxyService::RefreshCloudPrintProxyStatus() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
ServiceProcessControl* process_control =
- ServiceProcessControlManager::instance()->GetProcessControl(profile_);
+ ServiceProcessControlManager::GetInstance()->GetProcessControl(profile_);
DCHECK(process_control->is_connected());
Callback2<bool, std::string>::Type* callback =
NewCallback(this, &CloudPrintProxyService::StatusCallback);
@@ -151,7 +152,7 @@ void CloudPrintProxyService::RefreshCloudPrintProxyStatus() {
void CloudPrintProxyService::EnableCloudPrintProxy(const std::string& lsid,
const std::string& email) {
ServiceProcessControl* process_control =
- ServiceProcessControlManager::instance()->GetProcessControl(profile_);
+ ServiceProcessControlManager::GetInstance()->GetProcessControl(profile_);
DCHECK(process_control->is_connected());
process_control->Send(new ServiceMsg_EnableCloudPrintProxy(lsid));
// Assume the IPC worked.
@@ -160,7 +161,7 @@ void CloudPrintProxyService::EnableCloudPrintProxy(const std::string& lsid,
void CloudPrintProxyService::DisableCloudPrintProxy() {
ServiceProcessControl* process_control =
- ServiceProcessControlManager::instance()->GetProcessControl(profile_);
+ ServiceProcessControlManager::GetInstance()->GetProcessControl(profile_);
DCHECK(process_control->is_connected());
process_control->Send(new ServiceMsg_DisableCloudPrintProxy);
// Assume the IPC worked.
@@ -174,7 +175,7 @@ void CloudPrintProxyService::StatusCallback(bool enabled, std::string email) {
bool CloudPrintProxyService::InvokeServiceTask(Task* task) {
ServiceProcessControl* process_control =
- ServiceProcessControlManager::instance()->GetProcessControl(profile_);
+ ServiceProcessControlManager::GetInstance()->GetProcessControl(profile_);
DCHECK(process_control);
if (process_control)
process_control->Launch(task, NULL);
diff --git a/chrome/browser/printing/cloud_print/cloud_print_setup_flow.cc b/chrome/browser/printing/cloud_print/cloud_print_setup_flow.cc
index 79e32f4..fddff26 100644
--- a/chrome/browser/printing/cloud_print/cloud_print_setup_flow.cc
+++ b/chrome/browser/printing/cloud_print/cloud_print_setup_flow.cc
@@ -11,6 +11,7 @@
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/browser_list.h"
+#include "chrome/browser/browser_thread.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
#include "chrome/browser/dom_ui/dom_ui_util.h"
#if defined(TOOLKIT_GTK)
@@ -22,7 +23,7 @@
#include "chrome/browser/printing/cloud_print/cloud_print_setup_message_handler.h"
#include "chrome/browser/printing/cloud_print/cloud_print_setup_source.h"
#include "chrome/browser/printing/cloud_print/cloud_print_url.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/service/service_process_control.h"
#include "chrome/browser/service/service_process_control_manager.h"
@@ -101,7 +102,7 @@ CloudPrintSetupFlow::CloudPrintSetupFlow(const std::string& args,
profile_ = profile;
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(Singleton<ChromeURLDataManager>::get(),
+ NewRunnableMethod(ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(new CloudPrintSetupSource())));
}
@@ -164,19 +165,23 @@ std::string CloudPrintSetupFlow::GetDialogArgs() const {
return dialog_start_args_;
}
-void CloudPrintSetupFlow::OnCloseContents(TabContents* source,
- bool* out_close_dialog) {
+void CloudPrintSetupFlow::OnCloseContents(TabContents* source,
+ bool* out_close_dialog) {
}
-std::wstring CloudPrintSetupFlow::GetDialogTitle() const {
+std::wstring CloudPrintSetupFlow::GetDialogTitle() const {
return l10n_util::GetString(IDS_CLOUD_PRINT_SETUP_DIALOG_TITLE);
}
-bool CloudPrintSetupFlow::IsDialogModal() const {
+bool CloudPrintSetupFlow::IsDialogModal() const {
// We are always modeless.
return false;
}
+bool CloudPrintSetupFlow::ShouldShowDialogTitle() const {
+ return true;
+}
+
///////////////////////////////////////////////////////////////////////////////
// GaiaAuthConsumer implementation.
void CloudPrintSetupFlow::OnClientLoginFailure(
diff --git a/chrome/browser/printing/cloud_print/cloud_print_setup_flow.h b/chrome/browser/printing/cloud_print/cloud_print_setup_flow.h
index 14354e3..86077ab 100644
--- a/chrome/browser/printing/cloud_print/cloud_print_setup_flow.h
+++ b/chrome/browser/printing/cloud_print/cloud_print_setup_flow.h
@@ -70,7 +70,7 @@ class CloudPrintSetupFlow : public HtmlDialogUIDelegate,
virtual void OnCloseContents(TabContents* source, bool* out_close_dialog);
virtual std::wstring GetDialogTitle() const;
virtual bool IsDialogModal() const;
- virtual bool ShouldShowDialogTitle() const { return true; }
+ virtual bool ShouldShowDialogTitle() const;
// GaiaAuthConsumer implementation.
virtual void OnClientLoginFailure(
diff --git a/chrome/browser/printing/cloud_print/cloud_print_setup_source.cc b/chrome/browser/printing/cloud_print/cloud_print_setup_source.cc
index 62a9a3f..972f088 100644
--- a/chrome/browser/printing/cloud_print/cloud_print_setup_source.cc
+++ b/chrome/browser/printing/cloud_print/cloud_print_setup_source.cc
@@ -4,12 +4,13 @@
#include "chrome/browser/printing/cloud_print/cloud_print_setup_source.h"
+#include <algorithm>
+
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/message_loop.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/jstemplate_builder.h"
@@ -125,6 +126,10 @@ void CloudPrintSetupSource::StartDataRequest(const std::string& path_raw,
SendResponse(request_id, html_bytes);
}
+std::string CloudPrintSetupSource::GetMimeType(const std::string& path) const {
+ return "text/html";
+}
+
std::string CloudPrintSetupSource::GetLocalizedUrl(
const std::string& url) const {
GURL original_url(url);
diff --git a/chrome/browser/printing/cloud_print/cloud_print_setup_source.h b/chrome/browser/printing/cloud_print/cloud_print_setup_source.h
index 3fa3048..7050c5e 100644
--- a/chrome/browser/printing/cloud_print/cloud_print_setup_source.h
+++ b/chrome/browser/printing/cloud_print/cloud_print_setup_source.h
@@ -18,9 +18,7 @@ class CloudPrintSetupSource : public ChromeURLDataManager::DataSource {
bool is_off_the_record,
int request_id);
- virtual std::string GetMimeType(const std::string& path) const {
- return "text/html";
- }
+ virtual std::string GetMimeType(const std::string& path) const;
static const char kInvalidPasswordHelpUrl[];
static const char kCanNotAccessAccountUrl[];
diff --git a/chrome/browser/printing/cloud_print/cloud_print_url.cc b/chrome/browser/printing/cloud_print/cloud_print_url.cc
index 1001f5f..236c03d 100644
--- a/chrome/browser/printing/cloud_print/cloud_print_url.cc
+++ b/chrome/browser/printing/cloud_print/cloud_print_url.cc
@@ -7,7 +7,7 @@
#include "base/command_line.h"
#include "base/logging.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "googleurl/src/gurl.h"
diff --git a/chrome/browser/printing/print_dialog_cloud.cc b/chrome/browser/printing/print_dialog_cloud.cc
index 1af016e..95248a9 100644
--- a/chrome/browser/printing/print_dialog_cloud.cc
+++ b/chrome/browser/printing/print_dialog_cloud.cc
@@ -17,7 +17,7 @@
#include "chrome/browser/dom_ui/dom_ui_util.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/printing/cloud_print/cloud_print_url.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
diff --git a/chrome/browser/printing/print_dialog_cloud_uitest.cc b/chrome/browser/printing/print_dialog_cloud_uitest.cc
index 3b57961..40824de 100644
--- a/chrome/browser/printing/print_dialog_cloud_uitest.cc
+++ b/chrome/browser/printing/print_dialog_cloud_uitest.cc
@@ -31,7 +31,9 @@ namespace {
class TestData {
public:
- TestData() {}
+ static TestData* GetInstance() {
+ return Singleton<TestData>::get();
+ }
const char* GetTestData() {
// Fetching this data blocks the IO thread, but we don't really care because
@@ -48,16 +50,20 @@ class TestData {
return test_data_.c_str();
}
private:
+ TestData() {}
+
std::string test_data_;
+
+ friend struct DefaultSingletonTraits<TestData>;
};
-// A simple test URLRequestJob. We don't care what it does, only that
+// A simple test net::URLRequestJob. We don't care what it does, only that
// whether it starts and finishes.
class SimpleTestJob : public URLRequestTestJob {
public:
- explicit SimpleTestJob(URLRequest* request)
+ explicit SimpleTestJob(net::URLRequest* request)
: URLRequestTestJob(request, test_headers(),
- Singleton<TestData>()->GetTestData(), true) {}
+ TestData::GetInstance()->GetTestData(), true) {}
virtual void GetResponseInfo(net::HttpResponseInfo* info) {
URLRequestTestJob::GetResponseInfo(info);
@@ -84,10 +90,9 @@ class SimpleTestJob : public URLRequestTestJob {
class TestController {
public:
- TestController()
- : result_(false),
- use_delegate_(false),
- delegate_(NULL) {}
+ static TestController* GetInstance() {
+ return Singleton<TestController>::get();
+ }
void set_result(bool value) {
result_ = value;
}
@@ -113,10 +118,17 @@ class TestController {
return use_delegate_;
}
private:
+ TestController()
+ : result_(false),
+ use_delegate_(false),
+ delegate_(NULL) {}
+
bool result_;
bool use_delegate_;
GURL expected_url_;
TestDelegate* delegate_;
+
+ friend struct DefaultSingletonTraits<TestController>;
};
} // namespace
@@ -128,20 +140,20 @@ class PrintDialogCloudTest : public InProcessBrowserTest {
}
// Must be static for handing into AddHostnameHandler.
- static URLRequest::ProtocolFactory Factory;
+ static net::URLRequest::ProtocolFactory Factory;
class AutoQuitDelegate : public TestDelegate {
public:
AutoQuitDelegate() {}
- virtual void OnResponseCompleted(URLRequest* request) {
+ virtual void OnResponseCompleted(net::URLRequest* request) {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
new MessageLoop::QuitTask());
}
};
virtual void SetUp() {
- Singleton<TestController>()->set_result(false);
+ TestController::GetInstance()->set_result(false);
InProcessBrowserTest::SetUp();
}
@@ -150,7 +162,7 @@ class PrintDialogCloudTest : public InProcessBrowserTest {
URLRequestFilter* filter = URLRequestFilter::GetInstance();
filter->RemoveHostnameHandler(scheme_, host_name_);
handler_added_ = false;
- Singleton<TestController>()->set_delegate(NULL);
+ TestController::GetInstance()->set_delegate(NULL);
}
InProcessBrowserTest::TearDown();
}
@@ -174,8 +186,8 @@ class PrintDialogCloudTest : public InProcessBrowserTest {
GURL cloud_print_dialog_url =
CloudPrintURL(browser()->profile()).
GetCloudPrintServiceDialogURL();
- Singleton<TestController>()->set_expected_url(cloud_print_dialog_url);
- Singleton<TestController>()->set_delegate(&delegate_);
+ TestController::GetInstance()->set_expected_url(cloud_print_dialog_url);
+ TestController::GetInstance()->set_delegate(&delegate_);
}
CreateDialogForTest();
@@ -196,13 +208,13 @@ class PrintDialogCloudTest : public InProcessBrowserTest {
AutoQuitDelegate delegate_;
};
-URLRequestJob* PrintDialogCloudTest::Factory(URLRequest* request,
- const std::string& scheme) {
- if (Singleton<TestController>()->use_delegate())
- request->set_delegate(Singleton<TestController>()->delegate());
+net::URLRequestJob* PrintDialogCloudTest::Factory(net::URLRequest* request,
+ const std::string& scheme) {
+ if (TestController::GetInstance()->use_delegate())
+ request->set_delegate(TestController::GetInstance()->delegate());
if (request &&
- (request->url() == Singleton<TestController>()->expected_url())) {
- Singleton<TestController>()->set_result(true);
+ (request->url() == TestController::GetInstance()->expected_url())) {
+ TestController::GetInstance()->set_result(true);
}
return new SimpleTestJob(request);
}
@@ -213,11 +225,11 @@ IN_PROC_BROWSER_TEST_F(PrintDialogCloudTest, HandlersRegistered) {
AddTestHandlers();
- Singleton<TestController>()->set_use_delegate(true);
+ TestController::GetInstance()->set_use_delegate(true);
ui_test_utils::RunMessageLoop();
- ASSERT_TRUE(Singleton<TestController>()->result());
+ ASSERT_TRUE(TestController::GetInstance()->result());
}
#if defined(OS_CHROMEOS)
@@ -240,6 +252,6 @@ IN_PROC_BROWSER_TEST_F(PrintDialogCloudTest, DISABLED_DialogGrabbed) {
ui_test_utils::RunMessageLoop();
- ASSERT_TRUE(Singleton<TestController>()->result());
+ ASSERT_TRUE(TestController::GetInstance()->result());
}
#endif
diff --git a/chrome/browser/printing/print_job.cc b/chrome/browser/printing/print_job.cc
index df9df0f..db57103 100644
--- a/chrome/browser/printing/print_job.cc
+++ b/chrome/browser/printing/print_job.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/printing/print_job.h"
#include "base/message_loop.h"
+#include "base/thread_restrictions.h"
#include "base/timer.h"
#include "chrome/browser/printing/print_job_worker.h"
#include "chrome/common/notification_service.h"
@@ -86,6 +87,14 @@ PrintJobWorker* PrintJob::DetachWorker(PrintJobWorkerOwner* new_owner) {
return NULL;
}
+MessageLoop* PrintJob::message_loop() {
+ return ui_message_loop_;
+}
+
+const PrintSettings& PrintJob::settings() const {
+ return settings_;
+}
+
int PrintJob::cookie() const {
if (!document_.get())
// Always use an invalid cookie in this case.
@@ -328,6 +337,10 @@ void PrintJob::ControlledWorkerShutdown() {
}
#endif
+ // Temporarily allow it until we fix
+ // http://code.google.com/p/chromium/issues/detail?id=67044
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+
// Now make sure the thread object is cleaned up.
worker_->Stop();
}
diff --git a/chrome/browser/printing/print_job.h b/chrome/browser/printing/print_job.h
index e78f1a9..03aacda 100644
--- a/chrome/browser/printing/print_job.h
+++ b/chrome/browser/printing/print_job.h
@@ -54,8 +54,8 @@ class PrintJob : public PrintJobWorkerOwner,
virtual void GetSettingsDone(const PrintSettings& new_settings,
PrintingContext::Result result);
virtual PrintJobWorker* DetachWorker(PrintJobWorkerOwner* new_owner);
- virtual MessageLoop* message_loop() { return ui_message_loop_; }
- virtual const PrintSettings& settings() const { return settings_; }
+ virtual MessageLoop* message_loop();
+ virtual const PrintSettings& settings() const;
virtual int cookie() const;
// DestructionObserver
diff --git a/chrome/browser/printing/print_job_manager.h b/chrome/browser/printing/print_job_manager.h
index 017b732..228f7ad 100644
--- a/chrome/browser/printing/print_job_manager.h
+++ b/chrome/browser/printing/print_job_manager.h
@@ -73,7 +73,7 @@ class PrintJobManager : public NotificationObserver {
PrintJobs current_jobs_;
// Printing is enabled/disabled. This variable is checked at only one place,
- // by ResourceMessageFilter::OnGetDefaultPrintSettings. If its value is true
+ // by RenderMessageFilter::OnGetDefaultPrintSettings. If its value is true
// at that point, then the initiated print flow will complete itself,
// even if the value of this variable changes afterwards.
bool printing_enabled_;
diff --git a/chrome/browser/printing/print_job_worker.cc b/chrome/browser/printing/print_job_worker.cc
index bf096c8..26b5fb3 100644
--- a/chrome/browser/printing/print_job_worker.cc
+++ b/chrome/browser/printing/print_job_worker.cc
@@ -1,10 +1,11 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// 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.
#include "chrome/browser/printing/print_job_worker.h"
#include "base/message_loop.h"
+#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/printing/print_job.h"
#include "chrome/common/notification_service.h"
@@ -53,7 +54,8 @@ PrintJobWorker::PrintJobWorker(PrintJobWorkerOwner* owner)
// The object is created in the IO thread.
DCHECK_EQ(owner_->message_loop(), MessageLoop::current());
- printing_context_.reset(PrintingContext::Create());
+ printing_context_.reset(PrintingContext::Create(
+ g_browser_process->GetApplicationLocale()));
}
PrintJobWorker::~PrintJobWorker() {
@@ -82,14 +84,26 @@ void PrintJobWorker::GetSettings(bool ask_user_for_settings,
printing_context_->set_use_overlays(use_overlays);
if (ask_user_for_settings) {
+#if defined(OS_POSIX)
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
NewRunnableMethod(this, &PrintJobWorker::GetSettingsWithUI,
parent_view, document_page_count,
has_selection));
+#else
+ printing_context_->AskUserForSettings(
+ parent_view,
+ document_page_count,
+ has_selection,
+ NewCallback(this, &PrintJobWorker::GetSettingsDone));
+#endif // defined(OS_POSIX)
} else {
+#if defined(OS_POSIX)
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
NewRunnableMethod(this, &PrintJobWorker::UseDefaultSettings));
+#else
+ UseDefaultSettings();
+#endif // defined(OS_POSIX)
}
}
@@ -108,6 +122,7 @@ void PrintJobWorker::GetSettingsDone(PrintingContext::Result result) {
result));
}
+#if defined(OS_POSIX)
void PrintJobWorker::GetSettingsWithUI(gfx::NativeView parent_view,
int document_page_count,
bool has_selection) {
@@ -124,6 +139,7 @@ void PrintJobWorker::GetSettingsWithUIDone(PrintingContext::Result result) {
message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
this, &PrintJobWorker::GetSettingsDone, result));
}
+#endif // defined(OS_POSIX)
void PrintJobWorker::UseDefaultSettings() {
PrintingContext::Result result = printing_context_->UseDefaultSettings();
diff --git a/chrome/browser/printing/print_job_worker.h b/chrome/browser/printing/print_job_worker.h
index 817c0b0..e568286 100644
--- a/chrome/browser/printing/print_job_worker.h
+++ b/chrome/browser/printing/print_job_worker.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// 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.
@@ -83,9 +83,9 @@ class PrintJobWorker : public base::Thread {
// context.
void OnFailure();
+#if defined(OS_POSIX)
// Asks the user for print settings. Must be called on the UI thread.
- // Required on Mac and Linux. Windows can display UI from non-main threads,
- // but sticks with this for consistency.
+ // Mac and Linux-only since Windows can display UI from non-main threads.
void GetSettingsWithUI(gfx::NativeView parent_view,
int document_page_count,
bool has_selection);
@@ -94,6 +94,7 @@ class PrintJobWorker : public base::Thread {
// object that the print settings are set. This is needed in order to bounce
// back into the IO thread for GetSettingsDone().
void GetSettingsWithUIDone(PrintingContext::Result result);
+#endif // defined(OS_POSIX)
// Reports settings back to owner_.
void GetSettingsDone(PrintingContext::Result result);
diff --git a/chrome/browser/printing/print_job_worker_owner.h b/chrome/browser/printing/print_job_worker_owner.h
index eb35716..4125fa8 100644
--- a/chrome/browser/printing/print_job_worker_owner.h
+++ b/chrome/browser/printing/print_job_worker_owner.h
@@ -19,8 +19,8 @@ class PrintSettings;
class PrintJobWorkerOwner
: public base::RefCountedThreadSafe<PrintJobWorkerOwner> {
public:
- // Finishes the initialization began by PrintJobWorker::Init(). Creates a
- // new PrintedDocument if necessary. Solely meant to be called by
+ // Finishes the initialization began by PrintJobWorker::GetSettings().
+ // Creates a new PrintedDocument if necessary. Solely meant to be called by
// PrintJobWorker.
virtual void GetSettingsDone(const PrintSettings& new_settings,
PrintingContext::Result result) = 0;
diff --git a/chrome/browser/printing/print_preview_tab_controller.cc b/chrome/browser/printing/print_preview_tab_controller.cc
index 69a5763..f6135c9 100644
--- a/chrome/browser/printing/print_preview_tab_controller.cc
+++ b/chrome/browser/printing/print_preview_tab_controller.cc
@@ -6,16 +6,23 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_navigator.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/url_constants.h"
namespace printing {
+PrintPreviewTabController::PrintPreviewTabController()
+ : waiting_for_new_preview_page_(false) {
+}
+
+PrintPreviewTabController::~PrintPreviewTabController() {}
+
// static
PrintPreviewTabController* PrintPreviewTabController::GetInstance() {
if (!g_browser_process)
@@ -23,21 +30,10 @@ PrintPreviewTabController* PrintPreviewTabController::GetInstance() {
return g_browser_process->print_preview_tab_controller();
}
-PrintPreviewTabController::PrintPreviewTabController()
- : waiting_for_new_preview_page_(false) {
-}
-
-PrintPreviewTabController::~PrintPreviewTabController() {
- preview_tab_map_.clear();
-}
-
TabContents* PrintPreviewTabController::GetOrCreatePreviewTab(
TabContents* initiator_tab, int browser_window_id ) {
DCHECK(initiator_tab);
- if (IsPrintPreviewTab(initiator_tab))
- return initiator_tab;
-
// Get the print preview tab for |initiator_tab|.
TabContents* preview_tab = GetPrintPreviewForTab(initiator_tab);
if (preview_tab) {
@@ -48,71 +44,6 @@ TabContents* PrintPreviewTabController::GetOrCreatePreviewTab(
return CreatePrintPreviewTab(initiator_tab, browser_window_id);
}
-bool PrintPreviewTabController::IsPrintPreviewTab(TabContents* tab) {
- const GURL& url = tab->GetURL();
- return (url.SchemeIs(chrome::kChromeUIScheme) &&
- url.host() == chrome::kChromeUIPrintHost);
-}
-
-TabContents* PrintPreviewTabController::GetInitiatorTab(
- TabContents* preview_tab) {
- PrintPreviewTabMap::iterator it = preview_tab_map_.find(preview_tab);
- if (it != preview_tab_map_.end())
- return preview_tab_map_[preview_tab];
- return NULL;
-}
-
-TabContents* PrintPreviewTabController::GetPrintPreviewForTab(
- TabContents* tab) {
- PrintPreviewTabMap::iterator it = preview_tab_map_.find(tab);
- if (it != preview_tab_map_.end())
- return tab;
-
- for (it = preview_tab_map_.begin(); it != preview_tab_map_.end(); ++it) {
- if (it->second == tab)
- return it->first;
- }
- return NULL;
-}
-
-void PrintPreviewTabController::AddObservers(TabContents* tab) {
- registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
- Source<TabContents>(tab));
- registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
- Source<NavigationController>(&tab->controller()));
-}
-
-void PrintPreviewTabController::RemoveObservers(TabContents* tab) {
- registrar_.Remove(this, NotificationType::TAB_CONTENTS_DESTROYED,
- Source<TabContents>(tab));
- registrar_.Remove(this, NotificationType::NAV_ENTRY_COMMITTED,
- Source<NavigationController>(&tab->controller()));
-}
-
-TabContents* PrintPreviewTabController::CreatePrintPreviewTab(
- TabContents* initiator_tab, int browser_window_id) {
- Browser* current_browser = BrowserList::FindBrowserWithID(browser_window_id);
- // Add a new tab next to initiator tab.
- browser::NavigateParams params(current_browser,
- GURL(chrome::kChromeUIPrintURL),
- PageTransition::LINK);
- params.disposition = NEW_FOREGROUND_TAB;
- params.tabstrip_index = current_browser->tabstrip_model()->
- GetWrapperIndex(initiator_tab) + 1;
- browser::Navigate(&params);
- TabContentsWrapper* preview_tab = params.target_contents;
- preview_tab->tab_contents()->Activate();
-
- // Add an entry to the map.
- preview_tab_map_[preview_tab->tab_contents()] = initiator_tab;
- waiting_for_new_preview_page_ = true;
-
- AddObservers(initiator_tab);
- AddObservers(preview_tab->tab_contents());
-
- return preview_tab->tab_contents();
-}
-
void PrintPreviewTabController::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
@@ -192,4 +123,70 @@ void PrintPreviewTabController::Observe(NotificationType type,
RemoveObservers(initiator_tab);
}
-} // namespace printing
+// static
+bool PrintPreviewTabController::IsPrintPreviewTab(TabContents* tab) {
+ const GURL& url = tab->GetURL();
+ return (url.SchemeIs(chrome::kChromeUIScheme) &&
+ url.host() == chrome::kChromeUIPrintHost);
+}
+
+TabContents* PrintPreviewTabController::GetInitiatorTab(
+ TabContents* preview_tab) {
+ PrintPreviewTabMap::iterator it = preview_tab_map_.find(preview_tab);
+ if (it != preview_tab_map_.end())
+ return preview_tab_map_[preview_tab];
+ return NULL;
+}
+
+TabContents* PrintPreviewTabController::GetPrintPreviewForTab(
+ TabContents* tab) {
+ PrintPreviewTabMap::iterator it = preview_tab_map_.find(tab);
+ if (it != preview_tab_map_.end())
+ return tab;
+
+ for (it = preview_tab_map_.begin(); it != preview_tab_map_.end(); ++it) {
+ if (it->second == tab)
+ return it->first;
+ }
+ return NULL;
+}
+
+TabContents* PrintPreviewTabController::CreatePrintPreviewTab(
+ TabContents* initiator_tab, int browser_window_id) {
+ Browser* current_browser = BrowserList::FindBrowserWithID(browser_window_id);
+ // Add a new tab next to initiator tab.
+ browser::NavigateParams params(current_browser,
+ GURL(chrome::kChromeUIPrintURL),
+ PageTransition::LINK);
+ params.disposition = NEW_FOREGROUND_TAB;
+ params.tabstrip_index = current_browser->tabstrip_model()->
+ GetWrapperIndex(initiator_tab) + 1;
+ browser::Navigate(&params);
+ TabContentsWrapper* preview_tab = params.target_contents;
+ preview_tab->tab_contents()->Activate();
+
+ // Add an entry to the map.
+ preview_tab_map_[preview_tab->tab_contents()] = initiator_tab;
+ waiting_for_new_preview_page_ = true;
+
+ AddObservers(initiator_tab);
+ AddObservers(preview_tab->tab_contents());
+
+ return preview_tab->tab_contents();
+}
+
+void PrintPreviewTabController::AddObservers(TabContents* tab) {
+ registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
+ Source<TabContents>(tab));
+ registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
+ Source<NavigationController>(&tab->controller()));
+}
+
+void PrintPreviewTabController::RemoveObservers(TabContents* tab) {
+ registrar_.Remove(this, NotificationType::TAB_CONTENTS_DESTROYED,
+ Source<TabContents>(tab));
+ registrar_.Remove(this, NotificationType::NAV_ENTRY_COMMITTED,
+ Source<NavigationController>(&tab->controller()));
+}
+
+} // namespace printing
diff --git a/chrome/browser/printing/print_preview_tab_controller.h b/chrome/browser/printing/print_preview_tab_controller.h
index 6eec3f4..a3d01ea 100644
--- a/chrome/browser/printing/print_preview_tab_controller.h
+++ b/chrome/browser/printing/print_preview_tab_controller.h
@@ -2,7 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// For print preview, a print preview (PP) tab is linked with the initiator tab
+// that initiated the printing operation. If the tab initiates a second
+// printing operation while the first print preview tab is still open, that PP
+// tab is focused/activated. There may be more than one PP tab open. There is a
+// 1:1 relationship between PP tabs and initiating tabs. This class manages PP
+// tabs and initiator tabs.
#ifndef CHROME_BROWSER_PRINTING_PRINT_PREVIEW_TAB_CONTROLLER_H_
+
#define CHROME_BROWSER_PRINTING_PRINT_PREVIEW_TAB_CONTROLLER_H_
#pragma once
@@ -17,22 +24,16 @@ class TabContents;
namespace printing {
-// For print preview, a print preview (PP) tab is linked with the initiator tab
-// that initiated the printing operation. If the tab initiates a second
-// printing operation while the first print preview tab is still open, that PP
-// tab is focused/activated. There may be more than one PP tab open. There is a
-// 1:1 relationship between PP tabs and initiating tabs. This class manages PP
-// tabs and initiator tabs.
class PrintPreviewTabController
- : public base::RefCounted<PrintPreviewTabController>,
- public NotificationObserver {
+ : public base::RefCounted<PrintPreviewTabController>,
+ public NotificationObserver {
public:
- static PrintPreviewTabController* GetInstance();
-
PrintPreviewTabController();
virtual ~PrintPreviewTabController();
+ static PrintPreviewTabController* GetInstance();
+
// Get/Create the print preview tab for |initiator_tab|.
// |browser_window_id| is the browser window containing |initiator_tab|.
TabContents* GetOrCreatePreviewTab(
@@ -43,11 +44,16 @@ class PrintPreviewTabController
const NotificationSource& source,
const NotificationDetails& details);
+ // Returns true if |tab| is a print preview tab.
+ static bool IsPrintPreviewTab(TabContents* tab);
+
private:
friend class base::RefCounted<PrintPreviewTabController>;
- // Returns true if |tab| is a print preview tab.
- bool IsPrintPreviewTab(TabContents* tab);
+ // 1:1 relationship between initiator tab and print preview tab.
+ // Key: Preview tab.
+ // Value: Initiator tab.
+ typedef std::map<TabContents*, TabContents*> PrintPreviewTabMap;
// Returns initiator tab for |preview_tab|.
// Returns NULL if no initiator tab exists for |preview_tab|.
@@ -66,10 +72,6 @@ class PrintPreviewTabController
void AddObservers(TabContents* tab);
void RemoveObservers(TabContents* tab);
- // 1:1 relationship between initiator tab and print preview tab.
- // Key: Preview tab.
- // Value: Initiator tab.
- typedef std::map<TabContents*, TabContents*> PrintPreviewTabMap;
PrintPreviewTabMap preview_tab_map_;
// A registrar for listening notifications.
diff --git a/chrome/browser/printing/print_view_manager.cc b/chrome/browser/printing/print_view_manager.cc
index 35b4566..6381f61 100644
--- a/chrome/browser/printing/print_view_manager.cc
+++ b/chrome/browser/printing/print_view_manager.cc
@@ -14,7 +14,8 @@
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/render_messages_params.h"
#include "grit/generated_resources.h"
#include "printing/native_metafile.h"
diff --git a/chrome/browser/printing/printer_query.cc b/chrome/browser/printing/printer_query.cc
index 0b776e2..87ec00f 100644
--- a/chrome/browser/printing/printer_query.cc
+++ b/chrome/browser/printing/printer_query.cc
@@ -5,17 +5,18 @@
#include "chrome/browser/printing/printer_query.h"
#include "base/message_loop.h"
+#include "base/thread_restrictions.h"
#include "chrome/browser/printing/print_job_worker.h"
namespace printing {
PrinterQuery::PrinterQuery()
- : ui_message_loop_(MessageLoop::current()),
+ : io_message_loop_(MessageLoop::current()),
ALLOW_THIS_IN_INITIALIZER_LIST(worker_(new PrintJobWorker(this))),
is_print_dialog_box_shown_(false),
cookie_(PrintSettings::NewCookie()),
last_status_(PrintingContext::FAILED) {
- DCHECK_EQ(ui_message_loop_->type(), MessageLoop::TYPE_UI);
+ DCHECK_EQ(io_message_loop_->type(), MessageLoop::TYPE_IO);
}
PrinterQuery::~PrinterQuery() {
@@ -28,7 +29,6 @@ PrinterQuery::~PrinterQuery() {
callback_->Cancel();
}
// It may get deleted in a different thread that the one that created it.
- // That's fine so don't DCHECK_EQ(ui_message_loop_, MessageLoop::current());
}
void PrinterQuery::GetSettingsDone(const PrintSettings& new_settings,
@@ -58,13 +58,25 @@ PrintJobWorker* PrinterQuery::DetachWorker(PrintJobWorkerOwner* new_owner) {
return worker_.release();
}
+MessageLoop* PrinterQuery::message_loop() {
+ return io_message_loop_;
+}
+
+const PrintSettings& PrinterQuery::settings() const {
+ return settings_;
+}
+
+int PrinterQuery::cookie() const {
+ return cookie_;
+}
+
void PrinterQuery::GetSettings(GetSettingsAskParam ask_user_for_settings,
gfx::NativeView parent_view,
int expected_page_count,
bool has_selection,
bool use_overlays,
CancelableTask* callback) {
- DCHECK_EQ(ui_message_loop_, MessageLoop::current());
+ DCHECK_EQ(io_message_loop_, MessageLoop::current());
DCHECK(!is_print_dialog_box_shown_);
DCHECK(!callback_.get());
DCHECK(worker_.get());
@@ -97,6 +109,10 @@ void PrinterQuery::GetSettings(GetSettingsAskParam ask_user_for_settings,
void PrinterQuery::StopWorker() {
if (worker_.get()) {
+ // http://crbug.com/66082: We're blocking on the PrinterQuery's worker
+ // thread. It's not clear to me if this may result in blocking the current
+ // thread for an unacceptable time. We should probably fix it.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
worker_->Stop();
worker_.reset();
}
diff --git a/chrome/browser/printing/printer_query.h b/chrome/browser/printing/printer_query.h
index e55be3d..dc18b1f 100644
--- a/chrome/browser/printing/printer_query.h
+++ b/chrome/browser/printing/printer_query.h
@@ -36,12 +36,9 @@ class PrinterQuery : public PrintJobWorkerOwner {
virtual void GetSettingsDone(const PrintSettings& new_settings,
PrintingContext::Result result);
virtual PrintJobWorker* DetachWorker(PrintJobWorkerOwner* new_owner);
- virtual MessageLoop* message_loop() {
- return ui_message_loop_;
- }
- virtual const PrintSettings& settings() const { return settings_; }
-
- virtual int cookie() const { return cookie_; }
+ virtual MessageLoop* message_loop();
+ virtual const PrintSettings& settings() const;
+ virtual int cookie() const;
// Initializes the printing context. It is fine to call this function multiple
// times to reinitialize the settings. |parent_view| parameter's window will
@@ -73,7 +70,7 @@ class PrinterQuery : public PrintJobWorkerOwner {
// Main message loop reference. Used to send notifications in the right
// thread.
- MessageLoop* const ui_message_loop_;
+ MessageLoop* const io_message_loop_;
// All the UI is done in a worker thread because many Win32 print functions
// are blocking and enters a message loop without your consent. There is one
diff --git a/chrome/browser/printing/printing_layout_uitest.cc b/chrome/browser/printing/printing_layout_uitest.cc
index a87e239..754e8f5 100644
--- a/chrome/browser/printing/printing_layout_uitest.cc
+++ b/chrome/browser/printing/printing_layout_uitest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// 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.
@@ -6,16 +6,11 @@
#include "base/file_util.h"
#include "base/simple_thread.h"
#include "base/test/test_file_util.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
-#include "chrome/test/automation/window_proxy.h"
#include "chrome/test/ui/ui_test.h"
-#include "gfx/gdi_util.h"
#include "net/test/test_server.h"
#include "printing/image.h"
#include "printing/printing_test.h"
-#include "printing/native_metafile.h"
namespace {
@@ -199,8 +194,8 @@ class PrintingLayoutTextTest : public PrintingLayoutTest {
typedef PrintingLayoutTest Parent;
public:
// Returns if the test is disabled.
- // TODO(maruel): http://b/1157665 Until the issue is fixed, disable the test
- // if ClearType is enabled.
+ // http://crbug.com/64869 Until the issue is fixed, disable the test if
+ // ClearType is enabled.
static bool IsTestCaseDisabled() {
return Parent::IsTestCaseDisabled() || IsClearTypeEnabled();
}
@@ -280,7 +275,7 @@ class DismissTheWindow : public base::DelegateSimpleThread::Delegate {
} // namespace
// Fails, see http://crbug.com/7721.
-TEST_F(PrintingLayoutTextTest, FAILS_Complex) {
+TEST_F(PrintingLayoutTextTest, DISABLED_Complex) {
if (IsTestCaseDisabled())
return;
@@ -311,11 +306,9 @@ const TestPool kTestPool[] = {
"files/printing/test3.html", L"test3",
// ImageColor
"files/printing/test4.html", L"test4",
- // TODO(maruel): http://b/1171450 Transparent overlays are drawn opaque
- // "files/printing/test5.html", L"test5",
};
-// TODO(maruel:) http://code.google.com/p/chromium/issues/detail?id=7721
+// http://crbug.com/7721
TEST_F(PrintingLayoutTestHidden, DISABLED_ManyTimes) {
if (IsTestCaseDisabled())
return;
@@ -365,8 +358,7 @@ TEST_F(PrintingLayoutTestHidden, DISABLED_ManyTimes) {
}
}
-// Prints a popup and immediately closes it.
-// TODO(maruel): Reenable it, it causes crashes.
+// Prints a popup and immediately closes it. Disabled because it crashes.
TEST_F(PrintingLayoutTest, DISABLED_Delayed) {
if (IsTestCaseDisabled())
return;
@@ -399,8 +391,7 @@ TEST_F(PrintingLayoutTest, DISABLED_Delayed) {
<< L"popup_delayed_print";
}
-// Prints a popup and immediately closes it.
-// TODO(maruel:) http://code.google.com/p/chromium/issues/detail?id=7721
+// Prints a popup and immediately closes it. http://crbug.com/7721
TEST_F(PrintingLayoutTest, DISABLED_IFrame) {
if (IsTestCaseDisabled())
return;
diff --git a/chrome/browser/process_info_snapshot_mac_unittest.cc b/chrome/browser/process_info_snapshot_mac_unittest.cc
index babdf27..fe28c74 100644
--- a/chrome/browser/process_info_snapshot_mac_unittest.cc
+++ b/chrome/browser/process_info_snapshot_mac_unittest.cc
@@ -9,6 +9,10 @@
#include <vector>
+#include "base/command_line.h"
+#include "base/file_path.h"
+#include "base/process_util.h"
+
#include "testing/gtest/include/gtest/gtest.h"
typedef testing::Test ProcessInfoSnapshotMacTest;
@@ -83,3 +87,24 @@ TEST_F(ProcessInfoSnapshotMacTest, FindPidSelfTest) {
// Can't say anything definite about its |rss|.
EXPECT_GT(proc_info.vsize, 0u); // Its |vsize| should be nonzero though.
}
+
+TEST_F(ProcessInfoSnapshotMacTest, EffectiveVsRealUserIDTest) {
+ // Run top which has a uid of the caller and effective uid of 0.
+ base::ProcessHandle process_handle;
+ ASSERT_TRUE(base::LaunchApp(CommandLine(FilePath("/usr/bin/top")),
+ false, false, &process_handle));
+
+ std::vector<base::ProcessId> pid_list;
+ pid_list.push_back(process_handle);
+ ProcessInfoSnapshot snapshot;
+ ASSERT_TRUE(snapshot.Sample(pid_list));
+
+ ProcessInfoSnapshot::ProcInfoEntry proc_info;
+ ASSERT_TRUE(snapshot.GetProcInfo(process_handle, &proc_info));
+ // Effective user ID should be 0 (root).
+ EXPECT_EQ(proc_info.euid, 0u);
+ // Real user ID should match the calling process's user id.
+ EXPECT_EQ(proc_info.uid, geteuid());
+
+ ASSERT_TRUE(base::KillProcess(process_handle, 0, true));
+}
diff --git a/chrome/browser/process_singleton.h b/chrome/browser/process_singleton.h
index c8f34ed..250d96b 100644
--- a/chrome/browser/process_singleton.h
+++ b/chrome/browser/process_singleton.h
@@ -10,19 +10,21 @@
#if defined(OS_WIN)
#include <windows.h>
-#endif
+#endif // defined(OS_WIN)
#include "base/basictypes.h"
-#if defined(USE_X11) || defined(OS_MACOSX)
-#include "base/file_path.h"
-#endif
#include "base/logging.h"
#include "base/non_thread_safe.h"
#include "base/ref_counted.h"
#include "gfx/native_widget_types.h"
+
+#if defined(OS_POSIX)
+#include "base/file_path.h"
+#endif // defined(OS_POSIX)
+
#if defined(USE_X11)
#include "base/scoped_temp_dir.h"
-#endif
+#endif // defined(USE_X11)
class CommandLine;
class FilePath;
@@ -65,7 +67,7 @@ class ProcessSingleton : public NonThreadSafe {
// instance.
NotifyResult NotifyOtherProcessOrCreate();
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
+#if defined(OS_LINUX)
// Exposed for testing. We use a timeout on Linux, and in tests we want
// this timeout to be short.
NotifyResult NotifyOtherProcessWithTimeout(const CommandLine& command_line,
@@ -74,7 +76,7 @@ class ProcessSingleton : public NonThreadSafe {
NotifyResult NotifyOtherProcessWithTimeoutOrCreate(
const CommandLine& command_line,
int timeout_seconds);
-#endif
+#endif // defined(OS_LINUX)
// Sets ourself up as the singleton instance. Returns true on success. If
// false is returned, we are not the singleton instance and the caller must
diff --git a/chrome/browser/process_singleton_linux.cc b/chrome/browser/process_singleton_linux.cc
index fa66e17..a95d668 100644
--- a/chrome/browser/process_singleton_linux.cc
+++ b/chrome/browser/process_singleton_linux.cc
@@ -60,6 +60,7 @@
#include "base/command_line.h"
#include "base/eintr_wrapper.h"
#include "base/file_path.h"
+#include "base/file_util.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/path_service.h"
@@ -80,8 +81,8 @@
#include "chrome/browser/gtk/process_singleton_dialog.h"
#endif
#include "chrome/browser/io_thread.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser_init.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
@@ -229,43 +230,29 @@ void SetupSocket(const std::string& path, int* sock, struct sockaddr_un* addr) {
SetupSockAddr(path, addr);
}
-// Read a symbolic link, return empty string if given path is not a
-// symbol link. This version does not interpret the errno, leaving
-// the caller to do so.
-bool ReadLinkSilent(const std::string& path, std::string* output) {
- char buf[PATH_MAX];
- ssize_t len = readlink(path.c_str(), buf, PATH_MAX);
- if (len >= 0) {
- output->assign(buf, len);
- return true;
- }
- output->clear();
- return false;
-}
-
// Read a symbolic link, return empty string if given path is not a symbol link.
-std::string ReadLink(const std::string& path) {
- std::string target;
- if (!ReadLinkSilent(path, &target)) {
+FilePath ReadLink(const FilePath& path) {
+ FilePath target;
+ if (!file_util::ReadSymbolicLink(path, &target)) {
// The only errno that should occur is ENOENT.
if (errno != 0 && errno != ENOENT)
- PLOG(ERROR) << "readlink(" << path << ") failed";
+ PLOG(ERROR) << "readlink(" << path.value() << ") failed";
}
return target;
}
// Unlink a path. Return true on success.
-bool UnlinkPath(const std::string& path) {
- int rv = unlink(path.c_str());
+bool UnlinkPath(const FilePath& path) {
+ int rv = unlink(path.value().c_str());
if (rv < 0 && errno != ENOENT)
- PLOG(ERROR) << "Failed to unlink " << path;
+ PLOG(ERROR) << "Failed to unlink " << path.value();
return rv == 0;
}
// Create a symlink. Returns true on success.
-bool SymlinkPath(const std::string& target, const std::string& path) {
- if (symlink(target.c_str(), path.c_str()) < 0) {
+bool SymlinkPath(const FilePath& target, const FilePath& path) {
+ if (!file_util::CreateSymbolicLink(target, path)) {
// Double check the value in case symlink suceeded but we got an incorrect
// failure due to NFS packet loss & retry.
int saved_errno = errno;
@@ -273,7 +260,7 @@ bool SymlinkPath(const std::string& target, const std::string& path) {
// If we failed to create the lock, most likely another instance won the
// startup race.
errno = saved_errno;
- PLOG(ERROR) << "Failed to create " << path;
+ PLOG(ERROR) << "Failed to create " << path.value();
return false;
}
}
@@ -282,10 +269,10 @@ bool SymlinkPath(const std::string& target, const std::string& path) {
// Extract the hostname and pid from the lock symlink.
// Returns true if the lock existed.
-bool ParseLockPath(const std::string& path,
+bool ParseLockPath(const FilePath& path,
std::string* hostname,
int* pid) {
- std::string real_path = ReadLink(path);
+ std::string real_path = ReadLink(path).value();
if (real_path.empty())
return false;
@@ -328,7 +315,7 @@ bool IsChromeProcess(pid_t pid) {
FilePath other_chrome_path(base::GetProcessExecutablePath(pid));
return (!other_chrome_path.empty() &&
other_chrome_path.BaseName() ==
- FilePath::FromWStringHack(chrome::kBrowserProcessExecutableName));
+ FilePath(chrome::kBrowserProcessExecutableName));
}
// Return true if the given pid is one of our child processes.
@@ -350,13 +337,13 @@ bool IsSameChromeInstance(pid_t pid) {
// If the process is part of the same chrome instance, unlink the lock file and
// return true without killing it.
// If the process is on a different host, return false.
-bool KillProcessByLockPath(const std::string& path) {
+bool KillProcessByLockPath(const FilePath& path) {
std::string hostname;
int pid;
ParseLockPath(path, &hostname, &pid);
if (!hostname.empty() && hostname != net::GetHostName()) {
- DisplayProfileInUseError(path, hostname, pid);
+ DisplayProfileInUseError(path.value(), hostname, pid);
return false;
}
UnlinkPath(path);
@@ -374,7 +361,7 @@ bool KillProcessByLockPath(const std::string& path) {
return true;
}
- LOG(ERROR) << "Failed to extract pid from path: " << path;
+ LOG(ERROR) << "Failed to extract pid from path: " << path.value();
return true;
}
@@ -402,21 +389,21 @@ std::string GenerateCookie() {
return base::Uint64ToString(base::RandUint64());
}
-bool CheckCookie(const FilePath& path, const std::string& cookie) {
- return (cookie == ReadLink(path.value()));
+bool CheckCookie(const FilePath& path, const FilePath& cookie) {
+ return (cookie == ReadLink(path));
}
bool ConnectSocket(ScopedSocket* socket,
const FilePath& socket_path,
const FilePath& cookie_path) {
- std::string socket_target;
- if (ReadLinkSilent(socket_path.value(), &socket_target)) {
+ FilePath socket_target;
+ if (file_util::ReadSymbolicLink(socket_path, &socket_target)) {
// It's a symlink. Read the cookie.
- std::string cookie = ReadLink(cookie_path.value());
+ FilePath cookie = ReadLink(cookie_path);
if (cookie.empty())
return false;
- FilePath remote_cookie = FilePath(socket_target).DirName().
- Append(chrome::kSingletonCookieFilename);
+ FilePath remote_cookie = socket_target.DirName().
+ Append(chrome::kSingletonCookieFilename);
// Verify the cookie before connecting.
if (!CheckCookie(remote_cookie, cookie))
return false;
@@ -794,14 +781,14 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
std::string hostname;
int pid;
- if (!ParseLockPath(lock_path_.value(), &hostname, &pid)) {
+ if (!ParseLockPath(lock_path_, &hostname, &pid)) {
// No lockfile exists.
return PROCESS_NONE;
}
if (hostname.empty()) {
// Invalid lockfile.
- UnlinkPath(lock_path_.value());
+ UnlinkPath(lock_path_);
return PROCESS_NONE;
}
@@ -813,20 +800,20 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
if (!IsChromeProcess(pid)) {
// Orphaned lockfile (no process with pid, or non-chrome process.)
- UnlinkPath(lock_path_.value());
+ UnlinkPath(lock_path_);
return PROCESS_NONE;
}
if (IsSameChromeInstance(pid)) {
// Orphaned lockfile (pid is part of same chrome instance we are, even
// though we haven't tried to create a lockfile yet).
- UnlinkPath(lock_path_.value());
+ UnlinkPath(lock_path_);
return PROCESS_NONE;
}
if (retries == timeout_seconds) {
// Retries failed. Kill the unresponsive chrome process and continue.
- if (!kill_unresponsive || !KillProcessByLockPath(lock_path_.value()))
+ if (!kill_unresponsive || !KillProcessByLockPath(lock_path_))
return PROFILE_IN_USE;
return PROCESS_NONE;
}
@@ -857,7 +844,7 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
// Send the message
if (!WriteToSocket(socket.fd(), to_send.data(), to_send.length())) {
// Try to kill the other process, because it might have been dead.
- if (!kill_unresponsive || !KillProcessByLockPath(lock_path_.value()))
+ if (!kill_unresponsive || !KillProcessByLockPath(lock_path_))
return PROFILE_IN_USE;
return PROCESS_NONE;
}
@@ -873,7 +860,7 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
// Failed to read ACK, the other process might have been frozen.
if (len <= 0) {
- if (!kill_unresponsive || !KillProcessByLockPath(lock_path_.value()))
+ if (!kill_unresponsive || !KillProcessByLockPath(lock_path_))
return PROFILE_IN_USE;
return PROCESS_NONE;
}
@@ -928,15 +915,15 @@ bool ProcessSingleton::Create() {
// The symlink lock is pointed to the hostname and process id, so other
// processes can find it out.
- std::string symlink_content = StringPrintf(
+ FilePath symlink_content(StringPrintf(
"%s%c%u",
net::GetHostName().c_str(),
kLockDelimiter,
- base::GetCurrentProcId());
+ base::GetCurrentProcId()));
// Create symbol link before binding the socket, to ensure only one instance
// can have the socket open.
- if (!SymlinkPath(symlink_content, lock_path_.value())) {
+ if (!SymlinkPath(symlink_content, lock_path_)) {
// If we failed to create the lock, most likely another instance won the
// startup race.
return false;
@@ -952,14 +939,14 @@ bool ProcessSingleton::Create() {
// Setup the socket symlink and the two cookies.
FilePath socket_target_path =
socket_dir_.path().Append(chrome::kSingletonSocketFilename);
- std::string cookie = GenerateCookie();
+ FilePath cookie(GenerateCookie());
FilePath remote_cookie_path =
socket_dir_.path().Append(chrome::kSingletonCookieFilename);
- UnlinkPath(socket_path_.value());
- UnlinkPath(cookie_path_.value());
- if (!SymlinkPath(socket_target_path.value(), socket_path_.value()) ||
- !SymlinkPath(cookie, cookie_path_.value()) ||
- !SymlinkPath(cookie, remote_cookie_path.value())) {
+ UnlinkPath(socket_path_);
+ UnlinkPath(cookie_path_);
+ if (!SymlinkPath(socket_target_path, socket_path_) ||
+ !SymlinkPath(cookie, cookie_path_) ||
+ !SymlinkPath(cookie, remote_cookie_path)) {
// We've already locked things, so we can't have lost the startup race,
// but something doesn't like us.
LOG(ERROR) << "Failed to create symlinks.";
@@ -992,7 +979,7 @@ bool ProcessSingleton::Create() {
}
void ProcessSingleton::Cleanup() {
- UnlinkPath(socket_path_.value());
- UnlinkPath(cookie_path_.value());
- UnlinkPath(lock_path_.value());
+ UnlinkPath(socket_path_);
+ UnlinkPath(cookie_path_);
+ UnlinkPath(lock_path_);
}
diff --git a/chrome/browser/process_singleton_linux_uitest.cc b/chrome/browser/process_singleton_linux_uitest.cc
index f1ad59c..73e1365 100644
--- a/chrome/browser/process_singleton_linux_uitest.cc
+++ b/chrome/browser/process_singleton_linux_uitest.cc
@@ -16,7 +16,6 @@
#include "base/string_util.h"
#include "base/thread.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
diff --git a/chrome/browser/process_singleton_mac.cc b/chrome/browser/process_singleton_mac.cc
index 9666e4a..8639711 100644
--- a/chrome/browser/process_singleton_mac.cc
+++ b/chrome/browser/process_singleton_mac.cc
@@ -62,10 +62,8 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate() {
}
// Attempt to acquire an exclusive lock on an empty file in the
-// profile directory. Returns |true| if it gets the lock.
-// TODO(shess): The older code always returned |true|. Monitor the
-// histograms and convert the marked failure cases to |false| once
-// it's clear that it is safe to do. http://crbug.com/58986
+// profile directory. Returns |true| if it gets the lock. Returns
+// |false| if the lock is held, or if there is an error.
// TODO(shess): Rather than logging failures, popup an alert. Punting
// that for now because it would require confidence that this code is
// never called in a situation where an alert wouldn't work.
@@ -80,8 +78,7 @@ bool ProcessSingleton::Create() {
DPCHECK(lock_fd_ != -1) << "Unexpected failure opening profile lockfile";
UMA_HISTOGRAM_ENUMERATION("ProcessSingleton.OpenError",
capture_errno, kMaxErrno);
- // TODO(shess): Change to |false|.
- return true;
+ return false;
}
// Acquire an exclusive lock in non-blocking fashion. If the lock
@@ -98,8 +95,7 @@ bool ProcessSingleton::Create() {
if (capture_errno != EWOULDBLOCK) {
UMA_HISTOGRAM_ENUMERATION("ProcessSingleton.LockError",
capture_errno, kMaxErrno);
- // TODO(shess): Change to |false|.
- return true;
+ return false;
}
// The file is open by another process and locked.
diff --git a/chrome/browser/process_singleton_uitest.cc b/chrome/browser/process_singleton_uitest.cc
index 57656c2..f04b29f 100644
--- a/chrome/browser/process_singleton_uitest.cc
+++ b/chrome/browser/process_singleton_uitest.cc
@@ -61,7 +61,7 @@ class ChromeStarter : public base::RefCountedThreadSafe<ChromeStarter> {
FilePath browser_directory;
PathService::Get(chrome::DIR_APP, &browser_directory);
CommandLine command_line(browser_directory.Append(
- FilePath::FromWStringHack(chrome::kBrowserProcessExecutablePath)));
+ chrome::kBrowserProcessExecutablePath));
command_line.AppendSwitchPath(switches::kUserDataDir, user_data_dir_);
diff --git a/chrome/browser/process_singleton_win.cc b/chrome/browser/process_singleton_win.cc
index 875c6c2..1e86daa 100644
--- a/chrome/browser/process_singleton_win.cc
+++ b/chrome/browser/process_singleton_win.cc
@@ -16,14 +16,13 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extensions_startup.h"
#include "chrome/browser/platform_util.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser_init.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/result_codes.h"
-#include "chrome/installer/util/browser_distribution.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
@@ -53,8 +52,7 @@ ProcessSingleton::ProcessSingleton(const FilePath& user_data_dir)
// access. As documented, it's clearer to NOT request ownership on creation
// since it isn't guaranteed we will get it. It is better to create it
// without ownership and explicitly get the ownership afterward.
- std::wstring mutex_name(L"Local\\ProcessSingletonStartup!");
- mutex_name += BrowserDistribution::GetDistribution()->GetAppGuid();
+ std::wstring mutex_name(L"Local\\ChromeProcessSingletonStartup!");
ScopedHandle only_me(CreateMutex(NULL, FALSE, mutex_name.c_str()));
DCHECK(only_me.Get() != NULL) << "GetLastError = " << GetLastError();
@@ -91,10 +89,10 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() {
// Found another window, send our command line to it
// format is "START\0<<<current directory>>>\0<<<commandline>>>".
std::wstring to_send(L"START\0", 6); // want the NULL in the string.
- std::wstring cur_dir;
+ FilePath cur_dir;
if (!PathService::Get(base::DIR_CURRENT, &cur_dir))
return PROCESS_NONE;
- to_send.append(cur_dir);
+ to_send.append(cur_dir.value());
to_send.append(L"\0", 1); // Null separator.
to_send.append(GetCommandLineW());
to_send.append(L"\0", 1); // Null separator.
@@ -285,8 +283,8 @@ LRESULT ProcessSingleton::OnCopyData(HWND hwnd, const COPYDATASTRUCT* cds) {
// in the process that is running with the target profile, otherwise the
// uninstall will fail to unload and remove all components.
if (parsed_command_line.HasSwitch(switches::kUninstallExtension)) {
- extensions_startup::HandleUninstallExtension(parsed_command_line,
- profile);
+ ExtensionsStartupUtil ext_startup_util;
+ ext_startup_util.UninstallExtension(parsed_command_line, profile);
return TRUE;
}
diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc
deleted file mode 100644
index 9ccda97..0000000
--- a/chrome/browser/profile.cc
+++ /dev/null
@@ -1,663 +0,0 @@
-// 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.
-
-#include "chrome/browser/profile.h"
-
-#include "app/resource_bundle.h"
-#include "base/command_line.h"
-#include "base/file_path.h"
-#include "base/file_util.h"
-#include "base/path_service.h"
-#include "base/scoped_ptr.h"
-#include "base/string_util.h"
-#include "chrome/browser/background_contents_service.h"
-#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/chrome_blob_storage_context.h"
-#include "chrome/browser/download/download_manager.h"
-#include "chrome/browser/extensions/extension_message_service.h"
-#include "chrome/browser/extensions/extension_process_manager.h"
-#include "chrome/browser/file_system/browser_file_system_context.h"
-#include "chrome/browser/find_bar_state.h"
-#include "chrome/browser/in_process_webkit/webkit_context.h"
-#include "chrome/browser/net/chrome_url_request_context.h"
-#include "chrome/browser/notifications/desktop_notification_service.h"
-#include "chrome/browser/ssl/ssl_host_state.h"
-#include "chrome/browser/sync/profile_sync_service.h"
-#include "chrome/browser/themes/browser_theme_provider.h"
-#include "chrome/common/chrome_constants.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/json_pref_store.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/render_messages.h"
-#include "grit/browser_resources.h"
-#include "grit/locale_settings.h"
-#include "net/base/transport_security_state.h"
-#include "webkit/database/database_tracker.h"
-#if defined(TOOLKIT_USES_GTK)
-#include "chrome/browser/gtk/gtk_theme_provider.h"
-#endif
-
-#if defined(OS_WIN)
-#include "chrome/browser/password_manager/password_store_win.h"
-#elif defined(OS_MACOSX)
-#include "chrome/browser/keychain_mac.h"
-#include "chrome/browser/password_manager/password_store_mac.h"
-#elif defined(OS_POSIX) && !defined(OS_CHROMEOS)
-#include "chrome/browser/password_manager/native_backend_gnome_x.h"
-#include "chrome/browser/password_manager/native_backend_kwallet_x.h"
-#include "chrome/browser/password_manager/password_store_x.h"
-#endif
-
-using base::Time;
-using base::TimeDelta;
-
-// A pointer to the request context for the default profile. See comments on
-// Profile::GetDefaultRequestContext.
-URLRequestContextGetter* Profile::default_request_context_;
-
-namespace {
-
-// TODO(pathorn): Duplicated in profile_impl.cc
-void CleanupRequestContext(ChromeURLRequestContextGetter* context) {
- if (context)
- context->CleanupOnUIThread();
-}
-
-} // namespace
-
-// static
-const ProfileId Profile::InvalidProfileId = static_cast<ProfileId>(0);
-
-// static
-void Profile::RegisterUserPrefs(PrefService* prefs) {
- prefs->RegisterBooleanPref(prefs::kSearchSuggestEnabled, true);
- prefs->RegisterBooleanPref(prefs::kSessionExitedCleanly, true);
- prefs->RegisterBooleanPref(prefs::kSafeBrowsingEnabled, true);
- prefs->RegisterBooleanPref(prefs::kSafeBrowsingReportingEnabled, false);
- // TODO(estade): IDS_SPELLCHECK_DICTIONARY should be an ASCII string.
- prefs->RegisterLocalizedStringPref(prefs::kSpellCheckDictionary,
- IDS_SPELLCHECK_DICTIONARY);
- prefs->RegisterBooleanPref(prefs::kEnableSpellCheck, true);
- prefs->RegisterBooleanPref(prefs::kEnableAutoSpellCorrect, true);
-#if defined(TOOLKIT_USES_GTK)
- prefs->RegisterBooleanPref(prefs::kUsesSystemTheme,
- GtkThemeProvider::DefaultUsesSystemTheme());
-#endif
- prefs->RegisterFilePathPref(prefs::kCurrentThemePackFilename, FilePath());
- prefs->RegisterStringPref(prefs::kCurrentThemeID,
- BrowserThemeProvider::kDefaultThemeID);
- prefs->RegisterDictionaryPref(prefs::kCurrentThemeImages);
- prefs->RegisterDictionaryPref(prefs::kCurrentThemeColors);
- prefs->RegisterDictionaryPref(prefs::kCurrentThemeTints);
- prefs->RegisterDictionaryPref(prefs::kCurrentThemeDisplayProperties);
- prefs->RegisterBooleanPref(prefs::kDisableExtensions, false);
- prefs->RegisterStringPref(prefs::kSelectFileLastDirectory, "");
-#if defined(OS_CHROMEOS)
- // TODO(dilmah): For OS_CHROMEOS we maintain kApplicationLocale in both
- // local state and user's profile. For other platforms we maintain
- // kApplicationLocale only in local state.
- // In the future we may want to maintain kApplicationLocale
- // in user's profile for other platforms as well.
- prefs->RegisterStringPref(prefs::kApplicationLocale, "");
-#endif
-}
-
-// static
-URLRequestContextGetter* Profile::GetDefaultRequestContext() {
- return default_request_context_;
-}
-
-bool Profile::IsSyncAccessible() {
- ProfileSyncService* syncService = GetProfileSyncService();
- return syncService && !syncService->IsManaged();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// OffTheRecordProfileImpl is a profile subclass that wraps an existing profile
-// to make it suitable for the off the record mode.
-//
-////////////////////////////////////////////////////////////////////////////////
-class OffTheRecordProfileImpl : public Profile,
- public BrowserList::Observer {
- public:
- explicit OffTheRecordProfileImpl(Profile* real_profile)
- : profile_(real_profile),
- start_time_(Time::Now()) {
- request_context_ = ChromeURLRequestContextGetter::CreateOffTheRecord(this);
- extension_process_manager_.reset(ExtensionProcessManager::Create(this));
-
- BrowserList::AddObserver(this);
-
- background_contents_service_.reset(
- new BackgroundContentsService(this, CommandLine::ForCurrentProcess()));
- }
-
- virtual ~OffTheRecordProfileImpl() {
- NotificationService::current()->Notify(NotificationType::PROFILE_DESTROYED,
- Source<Profile>(this),
- NotificationService::NoDetails());
- CleanupRequestContext(request_context_);
- CleanupRequestContext(extensions_request_context_);
-
- // Clean up all DB files/directories
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(
- db_tracker_.get(),
- &webkit_database::DatabaseTracker::DeleteIncognitoDBDirectory));
-
- BrowserList::RemoveObserver(this);
- }
-
- virtual ProfileId GetRuntimeId() {
- return reinterpret_cast<ProfileId>(this);
- }
-
- virtual FilePath GetPath() { return profile_->GetPath(); }
-
- virtual bool IsOffTheRecord() {
- return true;
- }
-
- virtual Profile* GetOffTheRecordProfile() {
- return this;
- }
-
- virtual void DestroyOffTheRecordProfile() {
- // Suicide is bad!
- NOTREACHED();
- }
-
- virtual bool HasOffTheRecordProfile() {
- return true;
- }
-
- virtual Profile* GetOriginalProfile() {
- return profile_;
- }
-
- virtual ChromeAppCacheService* GetAppCacheService() {
- if (!appcache_service_) {
- appcache_service_ = new ChromeAppCacheService;
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(appcache_service_.get(),
- &ChromeAppCacheService::InitializeOnIOThread,
- GetPath(), IsOffTheRecord(),
- make_scoped_refptr(GetHostContentSettingsMap())));
- }
- return appcache_service_;
- }
-
- virtual webkit_database::DatabaseTracker* GetDatabaseTracker() {
- if (!db_tracker_) {
- db_tracker_ = new webkit_database::DatabaseTracker(
- GetPath(), IsOffTheRecord());
- }
- return db_tracker_;
- }
-
- virtual VisitedLinkMaster* GetVisitedLinkMaster() {
- // We don't provide access to the VisitedLinkMaster when we're OffTheRecord
- // because we don't want to leak the sites that the user has visited before.
- return NULL;
- }
-
- virtual ExtensionsService* GetExtensionsService() {
- return GetOriginalProfile()->GetExtensionsService();
- }
-
- virtual BackgroundContentsService* GetBackgroundContentsService() const {
- return background_contents_service_.get();
- }
-
- virtual StatusTray* GetStatusTray() {
- return GetOriginalProfile()->GetStatusTray();
- }
-
- virtual UserScriptMaster* GetUserScriptMaster() {
- return GetOriginalProfile()->GetUserScriptMaster();
- }
-
- virtual ExtensionDevToolsManager* GetExtensionDevToolsManager() {
- // TODO(mpcomplete): figure out whether we should return the original
- // profile's version.
- return NULL;
- }
-
- virtual ExtensionProcessManager* GetExtensionProcessManager() {
- return extension_process_manager_.get();
- }
-
- virtual ExtensionMessageService* GetExtensionMessageService() {
- return GetOriginalProfile()->GetExtensionMessageService();
- }
-
- virtual ExtensionEventRouter* GetExtensionEventRouter() {
- return GetOriginalProfile()->GetExtensionEventRouter();
- }
-
- virtual SSLHostState* GetSSLHostState() {
- if (!ssl_host_state_.get())
- ssl_host_state_.reset(new SSLHostState());
-
- DCHECK(ssl_host_state_->CalledOnValidThread());
- return ssl_host_state_.get();
- }
-
- virtual net::TransportSecurityState* GetTransportSecurityState() {
- if (!transport_security_state_.get())
- transport_security_state_ = new net::TransportSecurityState();
-
- return transport_security_state_.get();
- }
-
- virtual HistoryService* GetHistoryService(ServiceAccessType sat) {
- if (sat == EXPLICIT_ACCESS)
- return profile_->GetHistoryService(sat);
-
- NOTREACHED() << "This profile is OffTheRecord";
- return NULL;
- }
-
- virtual HistoryService* GetHistoryServiceWithoutCreating() {
- return profile_->GetHistoryServiceWithoutCreating();
- }
-
- virtual FaviconService* GetFaviconService(ServiceAccessType sat) {
- if (sat == EXPLICIT_ACCESS)
- return profile_->GetFaviconService(sat);
-
- NOTREACHED() << "This profile is OffTheRecord";
- return NULL;
- }
-
- virtual AutocompleteClassifier* GetAutocompleteClassifier() {
- return profile_->GetAutocompleteClassifier();
- }
-
- virtual WebDataService* GetWebDataService(ServiceAccessType sat) {
- if (sat == EXPLICIT_ACCESS)
- return profile_->GetWebDataService(sat);
-
- NOTREACHED() << "This profile is OffTheRecord";
- return NULL;
- }
-
- virtual WebDataService* GetWebDataServiceWithoutCreating() {
- return profile_->GetWebDataServiceWithoutCreating();
- }
-
- virtual PasswordStore* GetPasswordStore(ServiceAccessType sat) {
- if (sat == EXPLICIT_ACCESS)
- return profile_->GetPasswordStore(sat);
-
- NOTREACHED() << "This profile is OffTheRecord";
- return NULL;
- }
-
- virtual PrefService* GetPrefs() {
- return profile_->GetPrefs();
- }
-
- virtual TemplateURLModel* GetTemplateURLModel() {
- return profile_->GetTemplateURLModel();
- }
-
- virtual TemplateURLFetcher* GetTemplateURLFetcher() {
- return profile_->GetTemplateURLFetcher();
- }
-
- virtual DownloadManager* GetDownloadManager() {
- if (!download_manager_.get()) {
- scoped_refptr<DownloadManager> dlm(
- new DownloadManager(g_browser_process->download_status_updater()));
- dlm->Init(this);
- download_manager_.swap(dlm);
- }
- return download_manager_.get();
- }
-
- virtual bool HasCreatedDownloadManager() const {
- return (download_manager_.get() != NULL);
- }
-
- virtual PersonalDataManager* GetPersonalDataManager() {
- return NULL;
- }
-
- virtual BrowserFileSystemContext* GetFileSystemContext() {
- if (!browser_file_system_context_)
- browser_file_system_context_ = new BrowserFileSystemContext(
- GetPath(), IsOffTheRecord());
- DCHECK(browser_file_system_context_.get());
- return browser_file_system_context_.get();
- }
-
- virtual void InitThemes() {
- profile_->InitThemes();
- }
-
- virtual void SetTheme(const Extension* extension) {
- profile_->SetTheme(extension);
- }
-
- virtual void SetNativeTheme() {
- profile_->SetNativeTheme();
- }
-
- virtual void ClearTheme() {
- profile_->ClearTheme();
- }
-
- virtual const Extension* GetTheme() {
- return profile_->GetTheme();
- }
-
- virtual BrowserThemeProvider* GetThemeProvider() {
- return profile_->GetThemeProvider();
- }
-
- virtual URLRequestContextGetter* GetRequestContext() {
- return request_context_;
- }
-
- virtual URLRequestContextGetter* GetRequestContextForMedia() {
- // In OTR mode, media request context is the same as the original one.
- return request_context_;
- }
-
- URLRequestContextGetter* GetRequestContextForExtensions() {
- if (!extensions_request_context_) {
- extensions_request_context_ =
- ChromeURLRequestContextGetter::CreateOffTheRecordForExtensions(this);
- }
-
- return extensions_request_context_;
- }
-
- virtual net::SSLConfigService* GetSSLConfigService() {
- return profile_->GetSSLConfigService();
- }
-
- virtual HostContentSettingsMap* GetHostContentSettingsMap() {
- // Retrieve the host content settings map of the parent profile in order to
- // ensure the preferences have been migrated.
- profile_->GetHostContentSettingsMap();
- if (!host_content_settings_map_.get())
- host_content_settings_map_ = new HostContentSettingsMap(this);
- return host_content_settings_map_.get();
- }
-
- virtual HostZoomMap* GetHostZoomMap() {
- if (!host_zoom_map_)
- host_zoom_map_ = new HostZoomMap(this);
- return host_zoom_map_.get();
- }
-
- virtual GeolocationContentSettingsMap* GetGeolocationContentSettingsMap() {
- return profile_->GetGeolocationContentSettingsMap();
- }
-
- virtual GeolocationPermissionContext* GetGeolocationPermissionContext() {
- return profile_->GetGeolocationPermissionContext();
- }
-
- virtual UserStyleSheetWatcher* GetUserStyleSheetWatcher() {
- return profile_->GetUserStyleSheetWatcher();
- }
-
- virtual FindBarState* GetFindBarState() {
- if (!find_bar_state_.get())
- find_bar_state_.reset(new FindBarState());
- return find_bar_state_.get();
- }
-
- virtual SessionService* GetSessionService() {
- // Don't save any sessions when off the record.
- return NULL;
- }
-
- virtual void ShutdownSessionService() {
- // We don't allow a session service, nothing to do.
- }
-
- virtual bool HasSessionService() const {
- // We never have a session service.
- return false;
- }
-
- virtual bool HasProfileSyncService() const {
- // We never have a profile sync service.
- return false;
- }
-
- virtual bool DidLastSessionExitCleanly() {
- return profile_->DidLastSessionExitCleanly();
- }
-
- virtual BookmarkModel* GetBookmarkModel() {
- return profile_->GetBookmarkModel();
- }
-
- virtual DesktopNotificationService* GetDesktopNotificationService() {
- if (!desktop_notification_service_.get()) {
- desktop_notification_service_.reset(new DesktopNotificationService(
- this, g_browser_process->notification_ui_manager()));
- }
- return desktop_notification_service_.get();
- }
-
- virtual TokenService* GetTokenService() {
- return NULL;
- }
-
- virtual ProfileSyncService* GetProfileSyncService() {
- return NULL;
- }
-
- virtual ProfileSyncService* GetProfileSyncService(
- const std::string& cros_user) {
- return NULL;
- }
-
- virtual BrowserSignin* GetBrowserSignin() {
- return profile_->GetBrowserSignin();
- }
-
- virtual CloudPrintProxyService* GetCloudPrintProxyService() {
- return NULL;
- }
-
- virtual bool IsSameProfile(Profile* profile) {
- return (profile == this) || (profile == profile_);
- }
-
- virtual Time GetStartTime() const {
- return start_time_;
- }
-
- virtual TabRestoreService* GetTabRestoreService() {
- return NULL;
- }
-
- virtual void ResetTabRestoreService() {
- }
-
- virtual SpellCheckHost* GetSpellCheckHost() {
- return profile_->GetSpellCheckHost();
- }
-
- virtual void ReinitializeSpellCheckHost(bool force) {
- profile_->ReinitializeSpellCheckHost(force);
- }
-
- virtual WebKitContext* GetWebKitContext() {
- if (!webkit_context_.get())
- webkit_context_ = new WebKitContext(this);
- DCHECK(webkit_context_.get());
- return webkit_context_.get();
- }
-
- virtual history::TopSites* GetTopSitesWithoutCreating() {
- return NULL;
- }
-
- virtual history::TopSites* GetTopSites() {
- return NULL;
- }
-
- virtual void MarkAsCleanShutdown() {
- }
-
- virtual void InitExtensions() {
- NOTREACHED();
- }
-
- virtual void InitWebResources() {
- NOTREACHED();
- }
-
- virtual NTPResourceCache* GetNTPResourceCache() {
- // Just return the real profile resource cache.
- return profile_->GetNTPResourceCache();
- }
-
- virtual FilePath last_selected_directory() {
- const FilePath& directory = last_selected_directory_;
- if (directory.empty()) {
- return profile_->last_selected_directory();
- }
- return directory;
- }
-
- virtual void set_last_selected_directory(const FilePath& path) {
- last_selected_directory_ = path;
- }
-
-#if defined(OS_CHROMEOS)
- virtual chromeos::ProxyConfigServiceImpl*
- GetChromeOSProxyConfigServiceImpl() {
- return profile_->GetChromeOSProxyConfigServiceImpl();
- }
-#endif // defined(OS_CHROMEOS)
-
- virtual void ExitedOffTheRecordMode() {
- // DownloadManager is lazily created, so check before accessing it.
- if (download_manager_.get()) {
- // Drop our download manager so we forget about all the downloads made
- // in off-the-record mode.
- download_manager_->Shutdown();
- download_manager_ = NULL;
- }
- }
-
- virtual void OnBrowserAdded(const Browser* browser) {
- }
-
- virtual void OnBrowserRemoved(const Browser* browser) {
- if (BrowserList::GetBrowserCount(this) == 0)
- ExitedOffTheRecordMode();
- }
-
- virtual ChromeBlobStorageContext* GetBlobStorageContext() {
- if (!blob_storage_context_) {
- blob_storage_context_ = new ChromeBlobStorageContext();
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(
- blob_storage_context_.get(),
- &ChromeBlobStorageContext::InitializeOnIOThread));
- }
- return blob_storage_context_;
- }
-
- virtual ExtensionInfoMap* GetExtensionInfoMap() {
- return profile_->GetExtensionInfoMap();
- }
-
- virtual policy::ProfilePolicyContext* GetPolicyContext() {
- return NULL;
- }
-
- virtual PromoCounter* GetInstantPromoCounter() {
- return NULL;
- }
-
- virtual PrefProxyConfigTracker* GetProxyConfigTracker() {
- return profile_->GetProxyConfigTracker();
- }
-
- private:
- NotificationRegistrar registrar_;
-
- // The real underlying profile.
- Profile* profile_;
-
- scoped_ptr<ExtensionProcessManager> extension_process_manager_;
-
- // The context to use for requests made from this OTR session.
- scoped_refptr<ChromeURLRequestContextGetter> request_context_;
-
- // The context to use for requests made by an extension while in OTR mode.
- scoped_refptr<ChromeURLRequestContextGetter> extensions_request_context_;
-
- // The download manager that only stores downloaded items in memory.
- scoped_refptr<DownloadManager> download_manager_;
-
- // Use a separate desktop notification service for OTR.
- scoped_ptr<DesktopNotificationService> desktop_notification_service_;
-
- // We use a non-writable content settings map for OTR.
- scoped_refptr<HostContentSettingsMap> host_content_settings_map_;
-
- // Use a separate zoom map for OTR.
- scoped_refptr<HostZoomMap> host_zoom_map_;
-
- // Use a special WebKit context for OTR browsing.
- scoped_refptr<WebKitContext> webkit_context_;
-
- // We don't want SSLHostState from the OTR profile to leak back to the main
- // profile because then the main profile would learn some of the host names
- // the user visited while OTR.
- scoped_ptr<SSLHostState> ssl_host_state_;
-
- // Use a separate FindBarState so search terms do not leak back to the main
- // profile.
- scoped_ptr<FindBarState> find_bar_state_;
-
- // The TransportSecurityState that only stores enabled sites in memory.
- scoped_refptr<net::TransportSecurityState>
- transport_security_state_;
-
- // Time we were started.
- Time start_time_;
-
- scoped_refptr<ChromeAppCacheService> appcache_service_;
-
- // The main database tracker for this profile.
- // Should be used only on the file thread.
- scoped_refptr<webkit_database::DatabaseTracker> db_tracker_;
-
- FilePath last_selected_directory_;
-
- // Tracks all BackgroundContents running under this profile.
- scoped_ptr<BackgroundContentsService> background_contents_service_;
-
- scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;
-
- // The file_system context for this profile.
- scoped_refptr<BrowserFileSystemContext> browser_file_system_context_;
-
- DISALLOW_COPY_AND_ASSIGN(OffTheRecordProfileImpl);
-};
-
-Profile* Profile::CreateOffTheRecordProfile() {
- return new OffTheRecordProfileImpl(this);
-}
diff --git a/chrome/browser/profile.h b/chrome/browser/profile.h
deleted file mode 100644
index 5b5cdaf..0000000
--- a/chrome/browser/profile.h
+++ /dev/null
@@ -1,544 +0,0 @@
-// 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.
-
-// This class gathers state related to a single user profile.
-
-#ifndef CHROME_BROWSER_PROFILE_H_
-#define CHROME_BROWSER_PROFILE_H_
-#pragma once
-
-#include "base/basictypes.h"
-#include "base/logging.h"
-
-namespace base {
-class Time;
-}
-
-#if defined(OS_CHROMEOS)
-namespace chromeos {
-class ProxyConfigServiceImpl;
-}
-#endif
-
-namespace history {
-class TopSites;
-}
-
-namespace net {
-class TransportSecurityState;
-class SSLConfigService;
-}
-
-namespace policy {
-class ProfilePolicyContext;
-}
-
-namespace webkit_database {
-class DatabaseTracker;
-}
-
-class AutocompleteClassifier;
-class BackgroundContentsService;
-class BackgroundModeManager;
-class BookmarkModel;
-class BrowserSignin;
-class BrowserThemeProvider;
-class ChromeAppCacheService;
-class ChromeBlobStorageContext;
-class ChromeURLRequestContextGetter;
-class CloudPrintProxyService;
-class DesktopNotificationService;
-class DownloadManager;
-class Extension;
-class ExtensionDevToolsManager;
-class ExtensionEventRouter;
-class ExtensionMessageService;
-class ExtensionProcessManager;
-class ExtensionsService;
-class FaviconService;
-class FilePath;
-class BrowserFileSystemContext;
-class FindBarState;
-class GeolocationContentSettingsMap;
-class GeolocationPermissionContext;
-class HistoryService;
-class HostContentSettingsMap;
-class HostZoomMap;
-class NavigationController;
-class NTPResourceCache;
-class PasswordStore;
-class PersonalDataManager;
-class PinnedTabService;
-class PrefService;
-class ExtensionInfoMap;
-class PrefProxyConfigTracker;
-class PromoCounter;
-class ProfileSyncService;
-class ProfileSyncFactory;
-class SessionService;
-class SpellCheckHost;
-class SSLConfigServiceManager;
-class SSLHostState;
-class StatusTray;
-class TransportSecurityPersister;
-class SQLitePersistentCookieStore;
-class TabRestoreService;
-class TemplateURLFetcher;
-class TemplateURLModel;
-class ThemeProvider;
-class TokenService;
-class URLRequestContextGetter;
-class UserScriptMaster;
-class UserStyleSheetWatcher;
-class VisitedLinkMaster;
-class VisitedLinkEventListener;
-class WebDataService;
-class WebKitContext;
-class WebResourceService;
-
-typedef intptr_t ProfileId;
-
-class Profile {
- public:
- // Profile services are accessed with the following parameter. This parameter
- // defines what the caller plans to do with the service.
- // The caller is responsible for not performing any operation that would
- // result in persistent implicit records while using an OffTheRecord profile.
- // This flag allows the profile to perform an additional check.
- //
- // It also gives us an opportunity to perform further checks in the future. We
- // could, for example, return an history service that only allow some specific
- // methods.
- enum ServiceAccessType {
- // The caller plans to perform a read or write that takes place as a result
- // of the user input. Use this flag when the operation you are doing can be
- // performed while off the record. (ex: creating a bookmark)
- //
- // Since EXPLICIT_ACCESS means "as a result of a user action", this request
- // always succeeds.
- EXPLICIT_ACCESS,
-
- // The caller plans to call a method that will permanently change some data
- // in the profile, as part of Chrome's implicit data logging. Use this flag
- // when you are about to perform an operation which is incompatible with the
- // off the record mode.
- IMPLICIT_ACCESS
- };
-
- // Value that represents no profile Id.
- static const ProfileId InvalidProfileId;
-
- Profile() : restored_last_session_(false), accessibility_pause_level_(0) {}
- virtual ~Profile() {}
-
- // Profile prefs are registered as soon as the prefs are loaded for the first
- // time.
- static void RegisterUserPrefs(PrefService* prefs);
-
- // Create a new profile given a path.
- static Profile* CreateProfile(const FilePath& path);
-
- // Returns the request context for the "default" profile. This may be called
- // from any thread. This CAN return NULL if a first request context has not
- // yet been created. If necessary, listen on the UI thread for
- // NOTIFY_DEFAULT_REQUEST_CONTEXT_AVAILABLE.
- static URLRequestContextGetter* GetDefaultRequestContext();
-
- // Returns a unique Id that can be used to identify this profile at runtime.
- // This Id is not persistent and will not survive a restart of the browser.
- virtual ProfileId GetRuntimeId() = 0;
-
- // Returns the path of the directory where this profile's data is stored.
- virtual FilePath GetPath() = 0;
-
- // Return whether this profile is off the record. Default is false.
- virtual bool IsOffTheRecord() = 0;
-
- // Return the off the record version of this profile. The returned pointer
- // is owned by the receiving profile. If the receiving profile is off the
- // record, the same profile is returned.
- virtual Profile* GetOffTheRecordProfile() = 0;
-
- // Destroys the off the record profile.
- virtual void DestroyOffTheRecordProfile() = 0;
-
- // True if an off the record profile exists.
- virtual bool HasOffTheRecordProfile() = 0;
-
- // Return the original "recording" profile. This method returns this if the
- // profile is not off the record.
- virtual Profile* GetOriginalProfile() = 0;
-
- // Returns a pointer to the ChromeAppCacheService instance for this profile.
- virtual ChromeAppCacheService* GetAppCacheService() = 0;
-
- // Returns a pointer to the DatabaseTracker instance for this profile.
- virtual webkit_database::DatabaseTracker* GetDatabaseTracker() = 0;
-
- // Returns a pointer to the TopSites (thumbnail manager) instance
- // for this profile.
- virtual history::TopSites* GetTopSites() = 0;
-
- // Variant of GetTopSites that doesn't force creation.
- virtual history::TopSites* GetTopSitesWithoutCreating() = 0;
-
- // Retrieves a pointer to the VisitedLinkMaster associated with this
- // profile. The VisitedLinkMaster is lazily created the first time
- // that this method is called.
- virtual VisitedLinkMaster* GetVisitedLinkMaster() = 0;
-
- // Retrieves a pointer to the ExtensionsService associated with this
- // profile. The ExtensionsService is created at startup.
- virtual ExtensionsService* GetExtensionsService() = 0;
-
- // Retrieves a pointer to the UserScriptMaster associated with this
- // profile. The UserScriptMaster is lazily created the first time
- // that this method is called.
- virtual UserScriptMaster* GetUserScriptMaster() = 0;
-
- // Retrieves a pointer to the ExtensionDevToolsManager associated with this
- // profile. The instance is created at startup.
- virtual ExtensionDevToolsManager* GetExtensionDevToolsManager() = 0;
-
- // Retrieves a pointer to the ExtensionProcessManager associated with this
- // profile. The instance is created at startup.
- virtual ExtensionProcessManager* GetExtensionProcessManager() = 0;
-
- // Retrieves a pointer to the ExtensionMessageService associated with this
- // profile. The instance is created at startup.
- virtual ExtensionMessageService* GetExtensionMessageService() = 0;
-
- // Accessor. The instance is created at startup.
- virtual ExtensionEventRouter* GetExtensionEventRouter() = 0;
-
- // Retrieves a pointer to the SSLHostState associated with this profile.
- // The SSLHostState is lazily created the first time that this method is
- // called.
- virtual SSLHostState* GetSSLHostState() = 0;
-
- // Retrieves a pointer to the TransportSecurityState associated with
- // this profile. The TransportSecurityState is lazily created the
- // first time that this method is called.
- virtual net::TransportSecurityState*
- GetTransportSecurityState() = 0;
-
- // Retrieves a pointer to the FaviconService associated with this
- // profile. The FaviconService is lazily created the first time
- // that this method is called.
- //
- // Although FaviconService is refcounted, this will not addref, and callers
- // do not need to do any reference counting as long as they keep the pointer
- // only for the local scope (which they should do anyway since the browser
- // process may decide to shut down).
- //
- // |access| defines what the caller plans to do with the service. See
- // the ServiceAccessType definition above.
- virtual FaviconService* GetFaviconService(ServiceAccessType access) = 0;
-
- // Retrieves a pointer to the HistoryService associated with this
- // profile. The HistoryService is lazily created the first time
- // that this method is called.
- //
- // Although HistoryService is refcounted, this will not addref, and callers
- // do not need to do any reference counting as long as they keep the pointer
- // only for the local scope (which they should do anyway since the browser
- // process may decide to shut down).
- //
- // |access| defines what the caller plans to do with the service. See
- // the ServiceAccessType definition above.
- virtual HistoryService* GetHistoryService(ServiceAccessType access) = 0;
-
- // Similar to GetHistoryService(), but won't create the history service if it
- // doesn't already exist.
- virtual HistoryService* GetHistoryServiceWithoutCreating() = 0;
-
- // Retrieves a pointer to the AutocompleteClassifier associated with this
- // profile. The AutocompleteClassifier is lazily created the first time that
- // this method is called.
- virtual AutocompleteClassifier* GetAutocompleteClassifier() = 0;
-
- // Returns the WebDataService for this profile. This is owned by
- // the Profile. Callers that outlive the life of this profile need to be
- // sure they refcount the returned value.
- //
- // |access| defines what the caller plans to do with the service. See
- // the ServiceAccessType definition above.
- virtual WebDataService* GetWebDataService(ServiceAccessType access) = 0;
-
- // Similar to GetWebDataService(), but won't create the web data service if it
- // doesn't already exist.
- virtual WebDataService* GetWebDataServiceWithoutCreating() = 0;
-
- // Returns the PasswordStore for this profile. This is owned by the Profile.
- virtual PasswordStore* GetPasswordStore(ServiceAccessType access) = 0;
-
- // Retrieves a pointer to the PrefService that manages the preferences
- // for this user profile. The PrefService is lazily created the first
- // time that this method is called.
- virtual PrefService* GetPrefs() = 0;
-
- // Returns the TemplateURLModel for this profile. This is owned by the
- // the Profile.
- virtual TemplateURLModel* GetTemplateURLModel() = 0;
-
- // Returns the TemplateURLFetcher for this profile. This is owned by the
- // profile.
- virtual TemplateURLFetcher* GetTemplateURLFetcher() = 0;
-
- // Returns the DownloadManager associated with this profile.
- virtual DownloadManager* GetDownloadManager() = 0;
- virtual bool HasCreatedDownloadManager() const = 0;
-
- // Returns the PersonalDataManager associated with this profile.
- virtual PersonalDataManager* GetPersonalDataManager() = 0;
-
- // Returns the FileSystemContext associated to this profile. The context
- // is lazily created the first time this method is called. This is owned
- // by the profile.
- virtual BrowserFileSystemContext* GetFileSystemContext() = 0;
-
- // Returns the BrowserSignin object assigned to this profile.
- virtual BrowserSignin* GetBrowserSignin() = 0;
-
- // Init our themes system.
- virtual void InitThemes() = 0;
-
- // Set the theme to the specified extension.
- virtual void SetTheme(const Extension* extension) = 0;
-
- // Set the theme to the machine's native theme.
- virtual void SetNativeTheme() = 0;
-
- // Clear the theme and reset it to default.
- virtual void ClearTheme() = 0;
-
- // Gets the theme that was last set. Returns NULL if the theme is no longer
- // installed, if there is no installed theme, or the theme was cleared.
- virtual const Extension* GetTheme() = 0;
-
- // Returns or creates the ThemeProvider associated with this profile
- virtual BrowserThemeProvider* GetThemeProvider() = 0;
-
- // Returns the request context information associated with this profile. Call
- // this only on the UI thread, since it can send notifications that should
- // happen on the UI thread.
- virtual URLRequestContextGetter* GetRequestContext() = 0;
-
- // Returns the request context for media resources asociated with this
- // profile.
- virtual URLRequestContextGetter* GetRequestContextForMedia() = 0;
-
- // Returns the request context used for extension-related requests. This
- // is only used for a separate cookie store currently.
- virtual URLRequestContextGetter* GetRequestContextForExtensions() = 0;
-
- // Called by the ExtensionsService that lives in this profile. Gives the
- // profile a chance to react to the load event before the EXTENSION_LOADED
- // notification has fired. The purpose for handling this event first is to
- // avoid race conditions by making sure URLRequestContexts learn about new
- // extensions before anything else needs them to know.
- virtual void RegisterExtensionWithRequestContexts(
- const Extension* extension) {}
-
- // Called by the ExtensionsService that lives in this profile. Lets the
- // profile clean up its RequestContexts once all the listeners to the
- // EXTENSION_UNLOADED notification have finished running.
- virtual void UnregisterExtensionWithRequestContexts(
- const Extension* extension) {}
-
- // Returns the SSLConfigService for this profile.
- virtual net::SSLConfigService* GetSSLConfigService() = 0;
-
- // Returns the Hostname <-> Content settings map for this profile.
- virtual HostContentSettingsMap* GetHostContentSettingsMap() = 0;
-
- // Returns the Hostname <-> Zoom Level map for this profile.
- virtual HostZoomMap* GetHostZoomMap() = 0;
-
- // Returns the geolocation settings map for this profile.
- virtual GeolocationContentSettingsMap* GetGeolocationContentSettingsMap() = 0;
-
- // Returns the geolocation permission context for this profile.
- virtual GeolocationPermissionContext* GetGeolocationPermissionContext() = 0;
-
- // Returns the user style sheet watcher.
- virtual UserStyleSheetWatcher* GetUserStyleSheetWatcher() = 0;
-
- // Returns the find bar state for this profile. The find bar state is lazily
- // created the first time that this method is called.
- virtual FindBarState* GetFindBarState() = 0;
-
- // Returns the session service for this profile. This may return NULL. If
- // this profile supports a session service (it isn't off the record), and
- // the session service hasn't yet been created, this forces creation of
- // the session service.
- //
- // This returns NULL in two situations: the profile is off the record, or the
- // session service has been explicitly shutdown (browser is exiting). Callers
- // should always check the return value for NULL.
- virtual SessionService* GetSessionService() = 0;
-
- // If this profile has a session service, it is shut down. To properly record
- // the current state this forces creation of the session service, then shuts
- // it down.
- virtual void ShutdownSessionService() = 0;
-
- // Returns true if this profile has a session service.
- virtual bool HasSessionService() const = 0;
-
- // Returns true if this profile has a profile sync service.
- virtual bool HasProfileSyncService() const = 0;
-
- // Returns true if the last time this profile was open it was exited cleanly.
- virtual bool DidLastSessionExitCleanly() = 0;
-
- // Returns the BookmarkModel, creating if not yet created.
- virtual BookmarkModel* GetBookmarkModel() = 0;
-
- // Returns the Gaia Token Service, creating if not yet created.
- virtual TokenService* GetTokenService() = 0;
-
- // Returns the ProfileSyncService, creating if not yet created.
- virtual ProfileSyncService* GetProfileSyncService() = 0;
-
- // Returns the ProfileSyncService, creating if not yet created, with
- // the specified CrOS username.
- virtual ProfileSyncService* GetProfileSyncService(
- const std::string& cros_user) = 0;
-
- // Returns the CloudPrintProxyService, creating if not yet created.
- virtual CloudPrintProxyService* GetCloudPrintProxyService() = 0;
-
- // Return whether 2 profiles are the same. 2 profiles are the same if they
- // represent the same profile. This can happen if there is pointer equality
- // or if one profile is the off the record version of another profile (or vice
- // versa).
- virtual bool IsSameProfile(Profile* profile) = 0;
-
- // Returns the time the profile was started. This is not the time the profile
- // was created, rather it is the time the user started chrome and logged into
- // this profile. For the single profile case, this corresponds to the time
- // the user started chrome.
- virtual base::Time GetStartTime() const = 0;
-
- // Returns the TabRestoreService. This returns NULL when off the record.
- virtual TabRestoreService* GetTabRestoreService() = 0;
-
- virtual void ResetTabRestoreService() = 0;
-
- // May return NULL.
- virtual SpellCheckHost* GetSpellCheckHost() = 0;
-
- // If |force| is false, and the spellchecker is already initialized (or is in
- // the process of initializing), then do nothing. Otherwise clobber the
- // current spellchecker and replace it with a new one.
- virtual void ReinitializeSpellCheckHost(bool force) = 0;
-
- // Returns the WebKitContext assigned to this profile.
- virtual WebKitContext* GetWebKitContext() = 0;
-
- // Returns the provider of desktop notifications for this profile.
- virtual DesktopNotificationService* GetDesktopNotificationService() = 0;
-
- // Returns the service that manages BackgroundContents for this profile.
- virtual BackgroundContentsService* GetBackgroundContentsService() const = 0;
-
- // Returns the StatusTray, which provides an API for displaying status icons
- // in the system status tray. Returns NULL if status icons are not supported
- // on this platform (or this is a unit test).
- virtual StatusTray* GetStatusTray() = 0;
-
- // Marks the profile as cleanly shutdown.
- //
- // NOTE: this is invoked internally on a normal shutdown, but is public so
- // that it can be invoked when the user logs out/powers down (WM_ENDSESSION).
- virtual void MarkAsCleanShutdown() = 0;
-
- virtual void InitExtensions() = 0;
-
- // Start up service that gathers data from a web resource feed.
- virtual void InitWebResources() = 0;
-
- // Returns the new tab page resource cache.
- virtual NTPResourceCache* GetNTPResourceCache() = 0;
-
- // Returns the last directory that was chosen for uploading or opening a file.
- virtual FilePath last_selected_directory() = 0;
- virtual void set_last_selected_directory(const FilePath& path) = 0;
-
- // Returns a pointer to the ChromeBlobStorageContext instance for this
- // profile.
- virtual ChromeBlobStorageContext* GetBlobStorageContext() = 0;
-
- // Returns the IO-thread-accessible profile data for this profile.
- virtual ExtensionInfoMap* GetExtensionInfoMap() = 0;
-
- // Returns the PromoCounter for Instant, or NULL if not applicable.
- virtual PromoCounter* GetInstantPromoCounter() = 0;
-
- // Gets the policy context associated with this profile.
- virtual policy::ProfilePolicyContext* GetPolicyContext() = 0;
-
-#if defined(OS_CHROMEOS)
- // Returns ChromeOS's ProxyConfigServiceImpl, creating if not yet created.
- virtual chromeos::ProxyConfigServiceImpl*
- GetChromeOSProxyConfigServiceImpl() = 0;
-#endif // defined(OS_CHROMEOS)
-
- // Returns the helper object that provides the proxy configuration service
- // access to the the proxy configuration possibly defined by preferences.
- virtual PrefProxyConfigTracker* GetProxyConfigTracker() = 0;
-
-#ifdef UNIT_TEST
- // Use with caution. GetDefaultRequestContext may be called on any thread!
- static void set_default_request_context(URLRequestContextGetter* c) {
- default_request_context_ = c;
- }
-#endif
-
- // Did the user restore the last session? This is set by SessionRestore.
- void set_restored_last_session(bool restored_last_session) {
- restored_last_session_ = restored_last_session;
- }
- bool restored_last_session() const {
- return restored_last_session_;
- }
-
- // Stop sending accessibility events until ResumeAccessibilityEvents().
- // Calls to Pause nest; no events will be sent until the number of
- // Resume calls matches the number of Pause calls received.
- void PauseAccessibilityEvents() {
- accessibility_pause_level_++;
- }
-
- void ResumeAccessibilityEvents() {
- DCHECK(accessibility_pause_level_ > 0);
- accessibility_pause_level_--;
- }
-
- bool ShouldSendAccessibilityEvents() {
- return 0 == accessibility_pause_level_;
- }
-
- // Checks whether sync is configurable by the user. Returns false if sync is
- // disabled or controlled by configuration management.
- bool IsSyncAccessible();
-
- // Creates an OffTheRecordProfile which points to this Profile.
- Profile* CreateOffTheRecordProfile();
-
- protected:
- static URLRequestContextGetter* default_request_context_;
-
- private:
- bool restored_last_session_;
-
- // Accessibility events will only be propagated when the pause
- // level is zero. PauseAccessibilityEvents and ResumeAccessibilityEvents
- // increment and decrement the level, respectively, rather than set it to
- // true or false, so that calls can be nested.
- int accessibility_pause_level_;
-};
-
-#endif // CHROME_BROWSER_PROFILE_H_
diff --git a/chrome/browser/profile_impl.cc b/chrome/browser/profile_impl.cc
deleted file mode 100644
index 816d8ae..0000000
--- a/chrome/browser/profile_impl.cc
+++ /dev/null
@@ -1,1319 +0,0 @@
-// 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.
-
-#include "chrome/browser/profile_impl.h"
-
-#include "app/resource_bundle.h"
-#include "base/command_line.h"
-#include "base/environment.h"
-#include "base/file_path.h"
-#include "base/file_util.h"
-#include "base/metrics/histogram.h"
-#include "base/path_service.h"
-#include "base/scoped_ptr.h"
-#include "base/string_number_conversions.h"
-#include "base/string_util.h"
-#include "chrome/browser/about_flags.h"
-#include "chrome/browser/appcache/chrome_appcache_service.h"
-#include "chrome/browser/autocomplete/autocomplete_classifier.h"
-#include "chrome/browser/autofill/personal_data_manager.h"
-#include "chrome/browser/background_contents_service.h"
-#include "chrome/browser/background_mode_manager.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_signin.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/chrome_blob_storage_context.h"
-#include "chrome/browser/dom_ui/ntp_resource_cache.h"
-#include "chrome/browser/download/download_manager.h"
-#include "chrome/browser/extensions/default_apps.h"
-#include "chrome/browser/extensions/extension_devtools_manager.h"
-#include "chrome/browser/extensions/extension_error_reporter.h"
-#include "chrome/browser/extensions/extension_info_map.h"
-#include "chrome/browser/extensions/extension_event_router.h"
-#include "chrome/browser/extensions/extension_message_service.h"
-#include "chrome/browser/extensions/extension_process_manager.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/extensions/user_script_master.h"
-#include "chrome/browser/favicon_service.h"
-#include "chrome/browser/file_system/browser_file_system_context.h"
-#include "chrome/browser/find_bar_state.h"
-#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
-#include "chrome/browser/geolocation/geolocation_permission_context.h"
-#include "chrome/browser/history/history.h"
-#include "chrome/browser/history/top_sites.h"
-#include "chrome/browser/host_content_settings_map.h"
-#include "chrome/browser/host_zoom_map.h"
-#include "chrome/browser/instant/instant_controller.h"
-#include "chrome/browser/in_process_webkit/webkit_context.h"
-#include "chrome/browser/net/chrome_url_request_context.h"
-#include "chrome/browser/net/gaia/token_service.h"
-#include "chrome/browser/net/net_pref_observer.h"
-#include "chrome/browser/net/pref_proxy_config_service.h"
-#include "chrome/browser/net/ssl_config_service_manager.h"
-#include "chrome/browser/notifications/desktop_notification_service.h"
-#include "chrome/browser/password_manager/password_store_default.h"
-#include "chrome/browser/policy/configuration_policy_provider.h"
-#include "chrome/browser/policy/configuration_policy_pref_store.h"
-#include "chrome/browser/policy/profile_policy_context.h"
-#include "chrome/browser/prefs/browser_prefs.h"
-#include "chrome/browser/prefs/pref_value_store.h"
-#include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h"
-#include "chrome/browser/profile_manager.h"
-#include "chrome/browser/renderer_host/render_process_host.h"
-#include "chrome/browser/search_engines/template_url_fetcher.h"
-#include "chrome/browser/search_engines/template_url_model.h"
-#include "chrome/browser/sessions/session_service.h"
-#include "chrome/browser/sessions/tab_restore_service.h"
-#include "chrome/browser/spellcheck_host.h"
-#include "chrome/browser/ssl/ssl_host_state.h"
-#include "chrome/browser/status_icons/status_tray.h"
-#include "chrome/browser/sync/profile_sync_factory_impl.h"
-#include "chrome/browser/sync/profile_sync_service.h"
-#include "chrome/browser/tabs/pinned_tab_service.h"
-#include "chrome/browser/themes/browser_theme_provider.h"
-#include "chrome/browser/transport_security_persister.h"
-#include "chrome/browser/user_style_sheet_watcher.h"
-#include "chrome/browser/visitedlink_event_listener.h"
-#include "chrome/browser/visitedlink_master.h"
-#include "chrome/browser/web_resource/web_resource_service.h"
-#include "chrome/browser/webdata/web_data_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 "chrome/common/json_pref_store.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/render_messages.h"
-#include "grit/browser_resources.h"
-#include "grit/locale_settings.h"
-#include "net/base/transport_security_state.h"
-#include "webkit/database/database_tracker.h"
-
-#if defined(TOOLKIT_USES_GTK)
-#include "chrome/browser/gtk/gtk_theme_provider.h"
-#endif
-
-#if defined(OS_WIN)
-#include "chrome/browser/instant/promo_counter.h"
-#include "chrome/browser/password_manager/password_store_win.h"
-#include "chrome/installer/util/install_util.h"
-#elif defined(OS_MACOSX)
-#include "chrome/browser/keychain_mac.h"
-#include "chrome/browser/password_manager/password_store_mac.h"
-#elif defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/proxy_config_service_impl.h"
-#elif defined(OS_POSIX) && !defined(OS_CHROMEOS)
-#include "base/nix/xdg_util.h"
-#if defined(USE_GNOME_KEYRING)
-#include "chrome/browser/password_manager/native_backend_gnome_x.h"
-#endif
-#include "chrome/browser/password_manager/native_backend_kwallet_x.h"
-#include "chrome/browser/password_manager/password_store_x.h"
-#endif
-
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/preferences.h"
-#endif
-
-using base::Time;
-using base::TimeDelta;
-
-namespace {
-
-void CleanupRequestContext(ChromeURLRequestContextGetter* context) {
- if (context)
- context->CleanupOnUIThread();
-}
-
-// Delay, in milliseconds, before we explicitly create the SessionService.
-static const int kCreateSessionServiceDelayMS = 500;
-
-enum ContextType {
- kNormalContext,
- kMediaContext
-};
-
-// Gets the cache parameters from the command line. |type| is the type of
-// request context that we need, |cache_path| will be set to the user provided
-// path, or will not be touched if there is not an argument. |max_size| will
-// be the user provided value or zero by default.
-void GetCacheParameters(ContextType type, FilePath* cache_path,
- int* max_size) {
- DCHECK(cache_path);
- DCHECK(max_size);
-
- // Override the cache location if specified by the user.
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDiskCacheDir)) {
- *cache_path = CommandLine::ForCurrentProcess()->GetSwitchValuePath(
- switches::kDiskCacheDir);
- }
-
- const char* arg = kNormalContext == type ? switches::kDiskCacheSize :
- switches::kMediaCacheSize;
- std::string value =
- CommandLine::ForCurrentProcess()->GetSwitchValueASCII(arg);
-
- // By default we let the cache determine the right size.
- *max_size = 0;
- if (!base::StringToInt(value, max_size)) {
- *max_size = 0;
- } else if (max_size < 0) {
- *max_size = 0;
- }
-}
-
-FilePath GetCachePath(const FilePath& base) {
- return base.Append(chrome::kCacheDirname);
-}
-
-FilePath GetMediaCachePath(const FilePath& base) {
- return base.Append(chrome::kMediaCacheDirname);
-}
-
-// Simple task to log the size of the current profile.
-class ProfileSizeTask : public Task {
- public:
- explicit ProfileSizeTask(const FilePath& path) : path_(path) {}
- virtual ~ProfileSizeTask() {}
-
- virtual void Run();
- private:
- FilePath path_;
-};
-
-void ProfileSizeTask::Run() {
- int64 size = file_util::ComputeFilesSize(path_, FILE_PATH_LITERAL("*"));
- int size_MB = static_cast<int>(size / (1024 * 1024));
- UMA_HISTOGRAM_COUNTS_10000("Profile.TotalSize", size_MB);
-
- size = file_util::ComputeFilesSize(path_, FILE_PATH_LITERAL("History"));
- size_MB = static_cast<int>(size / (1024 * 1024));
- UMA_HISTOGRAM_COUNTS_10000("Profile.HistorySize", size_MB);
-
- size = file_util::ComputeFilesSize(path_, FILE_PATH_LITERAL("History*"));
- size_MB = static_cast<int>(size / (1024 * 1024));
- UMA_HISTOGRAM_COUNTS_10000("Profile.TotalHistorySize", size_MB);
-
- size = file_util::ComputeFilesSize(path_, FILE_PATH_LITERAL("Cookies"));
- size_MB = static_cast<int>(size / (1024 * 1024));
- UMA_HISTOGRAM_COUNTS_10000("Profile.CookiesSize", size_MB);
-
- size = file_util::ComputeFilesSize(path_, FILE_PATH_LITERAL("Bookmarks"));
- size_MB = static_cast<int>(size / (1024 * 1024));
- UMA_HISTOGRAM_COUNTS_10000("Profile.BookmarksSize", size_MB);
-
- size = file_util::ComputeFilesSize(path_, FILE_PATH_LITERAL("Favicons"));
- size_MB = static_cast<int>(size / (1024 * 1024));
- UMA_HISTOGRAM_COUNTS_10000("Profile.FaviconsSize", size_MB);
-
- size = file_util::ComputeFilesSize(path_, FILE_PATH_LITERAL("Top Sites"));
- size_MB = static_cast<int>(size / (1024 * 1024));
- UMA_HISTOGRAM_COUNTS_10000("Profile.TopSitesSize", size_MB);
-
- size = file_util::ComputeFilesSize(path_, FILE_PATH_LITERAL("Visited Links"));
- size_MB = static_cast<int>(size / (1024 * 1024));
- UMA_HISTOGRAM_COUNTS_10000("Profile.VisitedLinksSize", size_MB);
-
- size = file_util::ComputeFilesSize(path_, FILE_PATH_LITERAL("Web Data"));
- size_MB = static_cast<int>(size / (1024 * 1024));
- UMA_HISTOGRAM_COUNTS_10000("Profile.WebDataSize", size_MB);
-
- size = file_util::ComputeFilesSize(path_, FILE_PATH_LITERAL("Extension*"));
- size_MB = static_cast<int>(size / (1024 * 1024));
- UMA_HISTOGRAM_COUNTS_10000("Profile.ExtensionSize", size_MB);
-}
-
-} // namespace
-
-// static
-Profile* Profile::CreateProfile(const FilePath& path) {
- return new ProfileImpl(path);
-}
-
-// static
-void ProfileImpl::RegisterUserPrefs(PrefService* prefs) {
- prefs->RegisterBooleanPref(prefs::kSavingBrowserHistoryDisabled, false);
- DefaultApps::RegisterUserPrefs(prefs);
-}
-
-ProfileImpl::ProfileImpl(const FilePath& path)
- : path_(path),
- visited_link_event_listener_(new VisitedLinkEventListener()),
- extension_devtools_manager_(NULL),
- request_context_(NULL),
- media_request_context_(NULL),
- extensions_request_context_(NULL),
- host_content_settings_map_(NULL),
- host_zoom_map_(NULL),
- history_service_created_(false),
- favicon_service_created_(false),
- created_web_data_service_(false),
- created_password_store_(false),
- created_download_manager_(false),
- created_theme_provider_(false),
- start_time_(Time::Now()),
- spellcheck_host_(NULL),
- spellcheck_host_ready_(false),
-#if defined(OS_WIN)
- checked_instant_promo_(false),
-#endif
- shutdown_session_service_(false) {
- DCHECK(!path.empty()) << "Using an empty path will attempt to write " <<
- "profile files to the root directory!";
- create_session_service_timer_.Start(
- TimeDelta::FromMilliseconds(kCreateSessionServiceDelayMS), this,
- &ProfileImpl::EnsureSessionServiceCreated);
-
- PrefService* prefs = GetPrefs();
- pref_change_registrar_.Init(prefs);
- pref_change_registrar_.Add(prefs::kSpellCheckDictionary, this);
- pref_change_registrar_.Add(prefs::kEnableSpellCheck, this);
- pref_change_registrar_.Add(prefs::kEnableAutoSpellCorrect, this);
-
- // Convert active labs into switches. Modifies the current command line.
- about_flags::ConvertFlagsToSwitches(prefs, CommandLine::ForCurrentProcess());
-
- // It would be nice to use PathService for fetching this directory, but
- // the cache directory depends on the profile directory, which isn't available
- // to PathService.
- chrome::GetUserCacheDirectory(path_, &base_cache_path_);
- file_util::CreateDirectory(base_cache_path_);
-
- // Listen for theme installations from our original profile.
- registrar_.Add(this, NotificationType::THEME_INSTALLED,
- Source<Profile>(GetOriginalProfile()));
-
- // Listen for bookmark model load, to bootstrap the sync service.
- registrar_.Add(this, NotificationType::BOOKMARK_MODEL_LOADED,
- Source<Profile>(this));
-
- ssl_config_service_manager_.reset(
- SSLConfigServiceManager::CreateDefaultManager(this));
-
-#if defined(OS_CHROMEOS)
- chromeos_preferences_.reset(new chromeos::Preferences());
- chromeos_preferences_->Init(prefs);
-#endif
-
- pinned_tab_service_.reset(new PinnedTabService(this));
-
- // Initialize the BackgroundModeManager - this has to be done here before
- // InitExtensions() is called because it relies on receiving notifications
- // when extensions are loaded. BackgroundModeManager is not needed under
- // ChromeOS because Chrome is always running (no need for special keep-alive
- // or launch-on-startup support).
-#if !defined(OS_CHROMEOS)
- background_mode_manager_.reset(new BackgroundModeManager(this,
- CommandLine::ForCurrentProcess()));
-#endif
-
- background_contents_service_.reset(
- new BackgroundContentsService(this, CommandLine::ForCurrentProcess()));
-
- extension_info_map_ = new ExtensionInfoMap();
-
- GetPolicyContext()->Initialize();
-
- // Log the profile size after a reasonable startup delay.
- BrowserThread::PostDelayedTask(BrowserThread::FILE, FROM_HERE,
- new ProfileSizeTask(path_), 112000);
-
- InstantController::RecordMetrics(this);
-}
-
-void ProfileImpl::InitExtensions() {
- if (user_script_master_ || extensions_service_)
- return; // Already initialized.
-
- const CommandLine* command_line = CommandLine::ForCurrentProcess();
- if (command_line->HasSwitch(
- switches::kEnableExtensionTimelineApi)) {
- extension_devtools_manager_ = new ExtensionDevToolsManager(this);
- }
-
- extension_process_manager_.reset(ExtensionProcessManager::Create(this));
- extension_event_router_.reset(new ExtensionEventRouter(this));
- extension_message_service_ = new ExtensionMessageService(this);
-
- ExtensionErrorReporter::Init(true); // allow noisy errors.
-
- FilePath script_dir; // Don't look for user scripts in any directory.
- // TODO(aa): We should just remove this functionality,
- // since it isn't used anymore.
- user_script_master_ = new UserScriptMaster(script_dir, this);
-
- extensions_service_ = new ExtensionsService(
- this,
- CommandLine::ForCurrentProcess(),
- GetPath().AppendASCII(ExtensionsService::kInstallDirectoryName),
- true);
-
- RegisterComponentExtensions();
- extensions_service_->Init();
- InstallDefaultApps();
-
- // Load any extensions specified with --load-extension.
- if (command_line->HasSwitch(switches::kLoadExtension)) {
- FilePath path = command_line->GetSwitchValuePath(switches::kLoadExtension);
- extensions_service_->LoadExtension(path);
- }
-}
-
-void ProfileImpl::RegisterComponentExtensions() {
- // Register the component extensions.
- typedef std::list<std::pair<std::string, int> > ComponentExtensionList;
- ComponentExtensionList component_extensions;
-
- // Bookmark manager.
- component_extensions.push_back(
- std::make_pair("bookmark_manager", IDR_BOOKMARKS_MANIFEST));
-
-#if defined(TOUCH_UI)
- component_extensions.push_back(
- std::make_pair("keyboard", IDR_KEYBOARD_MANIFEST));
-#endif
-
- // Web Store.
- component_extensions.push_back(
- std::make_pair("web_store", IDR_WEBSTORE_MANIFEST));
-
- for (ComponentExtensionList::iterator iter = component_extensions.begin();
- iter != component_extensions.end(); ++iter) {
- FilePath path;
- if (PathService::Get(chrome::DIR_RESOURCES, &path)) {
- path = path.AppendASCII(iter->first);
- } else {
- NOTREACHED();
- }
-
- std::string manifest =
- ResourceBundle::GetSharedInstance().GetRawDataResource(
- iter->second).as_string();
- extensions_service_->register_component_extension(
- ExtensionsService::ComponentExtensionInfo(manifest, path));
- }
-}
-
-void ProfileImpl::InstallDefaultApps() {
- ExtensionsService* extension_service = GetExtensionsService();
- DefaultApps* default_apps = extension_service->default_apps();
-
- if (!default_apps->ShouldInstallDefaultApps(extension_service->GetAppIds()))
- return;
-
- const ExtensionIdSet& app_ids = default_apps->default_apps();
- for (ExtensionIdSet::const_iterator iter = app_ids.begin();
- iter != app_ids.end(); ++iter) {
- extension_service->AddPendingExtensionFromDefaultAppList(*iter);
- }
-}
-
-void ProfileImpl::InitWebResources() {
- if (web_resource_service_)
- return;
-
- web_resource_service_ = new WebResourceService(this);
- web_resource_service_->StartAfterDelay();
-}
-
-NTPResourceCache* ProfileImpl::GetNTPResourceCache() {
- if (!ntp_resource_cache_.get())
- ntp_resource_cache_.reset(new NTPResourceCache(this));
- return ntp_resource_cache_.get();
-}
-
-FilePath ProfileImpl::last_selected_directory() {
- return GetPrefs()->GetFilePath(prefs::kSelectFileLastDirectory);
-}
-
-void ProfileImpl::set_last_selected_directory(const FilePath& path) {
- GetPrefs()->SetFilePath(prefs::kSelectFileLastDirectory, path);
-}
-
-ProfileImpl::~ProfileImpl() {
- NotificationService::current()->Notify(
- NotificationType::PROFILE_DESTROYED,
- Source<Profile>(this),
- NotificationService::NoDetails());
-
- GetPolicyContext()->Shutdown();
-
- tab_restore_service_ = NULL;
-
- StopCreateSessionServiceTimer();
- // TemplateURLModel schedules a task on the WebDataService from its
- // destructor. Delete it first to ensure the task gets scheduled before we
- // shut down the database.
- template_url_model_.reset();
-
- // DownloadManager is lazily created, so check before accessing it.
- if (download_manager_.get()) {
- // The download manager queries the history system and should be shutdown
- // before the history is shutdown so it can properly cancel all requests.
- download_manager_->Shutdown();
- download_manager_ = NULL;
- }
-
- // The theme provider provides bitmaps to whoever wants them.
- theme_provider_.reset();
-
- // Remove pref observers
- pref_change_registrar_.RemoveAll();
-
- // Delete the NTP resource cache so we can unregister pref observers.
- ntp_resource_cache_.reset();
-
- // The sync service needs to be deleted before the services it calls.
- sync_service_.reset();
-
- // Both HistoryService and WebDataService maintain threads for background
- // processing. Its possible each thread still has tasks on it that have
- // increased the ref count of the service. In such a situation, when we
- // decrement the refcount, it won't be 0, and the threads/databases aren't
- // properly shut down. By explicitly calling Cleanup/Shutdown we ensure the
- // databases are properly closed.
- if (web_data_service_.get())
- web_data_service_->Shutdown();
-
- if (top_sites_.get())
- top_sites_->Shutdown();
-
- if (history_service_.get())
- history_service_->Cleanup();
-
- if (spellcheck_host_.get())
- spellcheck_host_->UnsetObserver();
-
- if (default_request_context_ == request_context_)
- default_request_context_ = NULL;
-
- CleanupRequestContext(request_context_);
- CleanupRequestContext(media_request_context_);
- CleanupRequestContext(extensions_request_context_);
-
- // HistoryService may call into the BookmarkModel, as such we need to
- // delete HistoryService before the BookmarkModel. The destructor for
- // HistoryService will join with HistoryService's backend thread so that
- // by the time the destructor has finished we're sure it will no longer call
- // into the BookmarkModel.
- history_service_ = NULL;
- bookmark_bar_model_.reset();
-
- // FaviconService depends on HistoryServce so make sure we delete
- // HistoryService first.
- favicon_service_ = NULL;
-
- if (extension_message_service_)
- extension_message_service_->DestroyingProfile();
-
- if (extensions_service_)
- extensions_service_->DestroyingProfile();
-
- if (pref_proxy_config_tracker_)
- pref_proxy_config_tracker_->DetachFromPrefService();
-
- // This causes the Preferences file to be written to disk.
- MarkAsCleanShutdown();
-}
-
-ProfileId ProfileImpl::GetRuntimeId() {
- return reinterpret_cast<ProfileId>(this);
-}
-
-FilePath ProfileImpl::GetPath() {
- return path_;
-}
-
-bool ProfileImpl::IsOffTheRecord() {
- return false;
-}
-
-Profile* ProfileImpl::GetOffTheRecordProfile() {
- if (!off_the_record_profile_.get()) {
- scoped_ptr<Profile> p(CreateOffTheRecordProfile());
- off_the_record_profile_.swap(p);
-
- NotificationService::current()->Notify(
- NotificationType::OTR_PROFILE_CREATED,
- Source<Profile>(off_the_record_profile_.get()),
- NotificationService::NoDetails());
- }
- return off_the_record_profile_.get();
-}
-
-void ProfileImpl::DestroyOffTheRecordProfile() {
- off_the_record_profile_.reset();
-}
-
-bool ProfileImpl::HasOffTheRecordProfile() {
- return off_the_record_profile_.get() != NULL;
-}
-
-Profile* ProfileImpl::GetOriginalProfile() {
- return this;
-}
-
-ChromeAppCacheService* ProfileImpl::GetAppCacheService() {
- if (!appcache_service_) {
- appcache_service_ = new ChromeAppCacheService;
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(appcache_service_.get(),
- &ChromeAppCacheService::InitializeOnIOThread,
- GetPath(), IsOffTheRecord(),
- make_scoped_refptr(GetHostContentSettingsMap())));
- }
- return appcache_service_;
-}
-
-webkit_database::DatabaseTracker* ProfileImpl::GetDatabaseTracker() {
- if (!db_tracker_) {
- db_tracker_ = new webkit_database::DatabaseTracker(
- GetPath(), IsOffTheRecord());
- }
- return db_tracker_;
-}
-
-VisitedLinkMaster* ProfileImpl::GetVisitedLinkMaster() {
- if (!visited_link_master_.get()) {
- scoped_ptr<VisitedLinkMaster> visited_links(
- new VisitedLinkMaster(visited_link_event_listener_.get(), this));
- if (!visited_links->Init())
- return NULL;
- visited_link_master_.swap(visited_links);
- }
-
- return visited_link_master_.get();
-}
-
-ExtensionsService* ProfileImpl::GetExtensionsService() {
- return extensions_service_.get();
-}
-
-BackgroundContentsService* ProfileImpl::GetBackgroundContentsService() const {
- return background_contents_service_.get();
-}
-
-StatusTray* ProfileImpl::GetStatusTray() {
- if (!status_tray_.get())
- status_tray_.reset(StatusTray::Create());
- return status_tray_.get();
-}
-
-UserScriptMaster* ProfileImpl::GetUserScriptMaster() {
- return user_script_master_.get();
-}
-
-ExtensionDevToolsManager* ProfileImpl::GetExtensionDevToolsManager() {
- return extension_devtools_manager_.get();
-}
-
-ExtensionProcessManager* ProfileImpl::GetExtensionProcessManager() {
- return extension_process_manager_.get();
-}
-
-ExtensionMessageService* ProfileImpl::GetExtensionMessageService() {
- return extension_message_service_.get();
-}
-
-ExtensionEventRouter* ProfileImpl::GetExtensionEventRouter() {
- return extension_event_router_.get();
-}
-
-SSLHostState* ProfileImpl::GetSSLHostState() {
- if (!ssl_host_state_.get())
- ssl_host_state_.reset(new SSLHostState());
-
- DCHECK(ssl_host_state_->CalledOnValidThread());
- return ssl_host_state_.get();
-}
-
-net::TransportSecurityState*
- ProfileImpl::GetTransportSecurityState() {
- if (!transport_security_state_.get()) {
- transport_security_state_ = new net::TransportSecurityState();
- transport_security_persister_ =
- new TransportSecurityPersister();
- transport_security_persister_->Initialize(
- transport_security_state_.get(), path_);
- }
-
- return transport_security_state_.get();
-}
-
-PrefService* ProfileImpl::GetPrefs() {
- if (!prefs_.get()) {
- prefs_.reset(PrefService::CreatePrefService(GetPrefFilePath(),
- GetOriginalProfile()));
-
- // The Profile class and ProfileManager class may read some prefs so
- // register known prefs as soon as possible.
- Profile::RegisterUserPrefs(prefs_.get());
- browser::RegisterUserPrefs(prefs_.get());
-
- // The last session exited cleanly if there is no pref for
- // kSessionExitedCleanly or the value for kSessionExitedCleanly is true.
- last_session_exited_cleanly_ =
- prefs_->GetBoolean(prefs::kSessionExitedCleanly);
- // Mark the session as open.
- prefs_->SetBoolean(prefs::kSessionExitedCleanly, false);
- // Make sure we save to disk that the session has opened.
- prefs_->ScheduleSavePersistentPrefs();
-
- DCHECK(!net_pref_observer_.get());
- net_pref_observer_.reset(new NetPrefObserver(prefs_.get()));
- }
-
- return prefs_.get();
-}
-
-FilePath ProfileImpl::GetPrefFilePath() {
- FilePath pref_file_path = path_;
- pref_file_path = pref_file_path.Append(chrome::kPreferencesFilename);
- return pref_file_path;
-}
-
-URLRequestContextGetter* ProfileImpl::GetRequestContext() {
- if (!request_context_) {
- FilePath cookie_path = GetPath();
- cookie_path = cookie_path.Append(chrome::kCookieFilename);
- FilePath cache_path = base_cache_path_;
- int max_size;
- GetCacheParameters(kNormalContext, &cache_path, &max_size);
-
- cache_path = GetCachePath(cache_path);
- request_context_ = ChromeURLRequestContextGetter::CreateOriginal(
- this, cookie_path, cache_path, max_size);
-
- // The first request context is always a normal (non-OTR) request context.
- // Even when Chromium is started in OTR mode, a normal profile is always
- // created first.
- if (!default_request_context_) {
- default_request_context_ = request_context_;
- request_context_->set_is_main(true);
- // TODO(eroman): this isn't terribly useful anymore now that the
- // URLRequestContext is constructed by the IO thread...
- NotificationService::current()->Notify(
- NotificationType::DEFAULT_REQUEST_CONTEXT_AVAILABLE,
- NotificationService::AllSources(), NotificationService::NoDetails());
- }
- }
-
- return request_context_;
-}
-
-URLRequestContextGetter* ProfileImpl::GetRequestContextForMedia() {
- if (!media_request_context_) {
- FilePath cache_path = base_cache_path_;
- int max_size;
- GetCacheParameters(kMediaContext, &cache_path, &max_size);
-
- cache_path = GetMediaCachePath(cache_path);
- media_request_context_ =
- ChromeURLRequestContextGetter::CreateOriginalForMedia(
- this, cache_path, max_size);
- }
-
- return media_request_context_;
-}
-
-FaviconService* ProfileImpl::GetFaviconService(ServiceAccessType sat) {
- if (!favicon_service_created_) {
- favicon_service_created_ = true;
- scoped_refptr<FaviconService> service(new FaviconService(this));
- favicon_service_.swap(service);
- }
- return favicon_service_.get();
-}
-
-URLRequestContextGetter* ProfileImpl::GetRequestContextForExtensions() {
- if (!extensions_request_context_) {
- FilePath cookie_path = GetPath();
- cookie_path = cookie_path.Append(chrome::kExtensionsCookieFilename);
-
- extensions_request_context_ =
- ChromeURLRequestContextGetter::CreateOriginalForExtensions(
- this, cookie_path);
- }
-
- return extensions_request_context_;
-}
-
-void ProfileImpl::RegisterExtensionWithRequestContexts(
- const Extension* extension) {
- // AddRef to ensure the data lives until the other thread gets it. Balanced in
- // OnNewExtensions.
- extension->AddRef();
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(extension_info_map_.get(),
- &ExtensionInfoMap::AddExtension,
- extension));
-}
-
-void ProfileImpl::UnregisterExtensionWithRequestContexts(
- const Extension* extension) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(extension_info_map_.get(),
- &ExtensionInfoMap::RemoveExtension,
- extension->id()));
-}
-
-net::SSLConfigService* ProfileImpl::GetSSLConfigService() {
- return ssl_config_service_manager_->Get();
-}
-
-HostContentSettingsMap* ProfileImpl::GetHostContentSettingsMap() {
- if (!host_content_settings_map_.get())
- host_content_settings_map_ = new HostContentSettingsMap(this);
- return host_content_settings_map_.get();
-}
-
-HostZoomMap* ProfileImpl::GetHostZoomMap() {
- if (!host_zoom_map_)
- host_zoom_map_ = new HostZoomMap(this);
- return host_zoom_map_.get();
-}
-
-GeolocationContentSettingsMap* ProfileImpl::GetGeolocationContentSettingsMap() {
- if (!geolocation_content_settings_map_.get())
- geolocation_content_settings_map_ = new GeolocationContentSettingsMap(this);
- return geolocation_content_settings_map_.get();
-}
-
-GeolocationPermissionContext* ProfileImpl::GetGeolocationPermissionContext() {
- if (!geolocation_permission_context_.get())
- geolocation_permission_context_ = new GeolocationPermissionContext(this);
- return geolocation_permission_context_.get();
-}
-
-UserStyleSheetWatcher* ProfileImpl::GetUserStyleSheetWatcher() {
- if (!user_style_sheet_watcher_.get()) {
- user_style_sheet_watcher_ = new UserStyleSheetWatcher(GetPath());
- user_style_sheet_watcher_->Init();
- }
- return user_style_sheet_watcher_.get();
-}
-
-FindBarState* ProfileImpl::GetFindBarState() {
- if (!find_bar_state_.get()) {
- find_bar_state_.reset(new FindBarState());
- }
- return find_bar_state_.get();
-}
-
-HistoryService* ProfileImpl::GetHistoryService(ServiceAccessType sat) {
- // If saving history is disabled, only allow explicit access.
- if (GetPrefs()->GetBoolean(prefs::kSavingBrowserHistoryDisabled) &&
- sat != EXPLICIT_ACCESS)
- return NULL;
-
- if (!history_service_created_) {
- history_service_created_ = true;
- scoped_refptr<HistoryService> history(new HistoryService(this));
- if (!history->Init(GetPath(), GetBookmarkModel()))
- return NULL;
- history_service_.swap(history);
-
- // Send out the notification that the history service was created.
- NotificationService::current()->
- Notify(NotificationType::HISTORY_CREATED, Source<Profile>(this),
- Details<HistoryService>(history_service_.get()));
- }
- return history_service_.get();
-}
-
-HistoryService* ProfileImpl::GetHistoryServiceWithoutCreating() {
- return history_service_.get();
-}
-
-TemplateURLModel* ProfileImpl::GetTemplateURLModel() {
- if (!template_url_model_.get())
- template_url_model_.reset(new TemplateURLModel(this));
- return template_url_model_.get();
-}
-
-TemplateURLFetcher* ProfileImpl::GetTemplateURLFetcher() {
- if (!template_url_fetcher_.get())
- template_url_fetcher_.reset(new TemplateURLFetcher(this));
- return template_url_fetcher_.get();
-}
-
-AutocompleteClassifier* ProfileImpl::GetAutocompleteClassifier() {
- if (!autocomplete_classifier_.get())
- autocomplete_classifier_.reset(new AutocompleteClassifier(this));
- return autocomplete_classifier_.get();
-}
-
-WebDataService* ProfileImpl::GetWebDataService(ServiceAccessType sat) {
- if (!created_web_data_service_)
- CreateWebDataService();
- return web_data_service_.get();
-}
-
-WebDataService* ProfileImpl::GetWebDataServiceWithoutCreating() {
- return web_data_service_.get();
-}
-
-void ProfileImpl::CreateWebDataService() {
- DCHECK(!created_web_data_service_ && web_data_service_.get() == NULL);
- created_web_data_service_ = true;
- scoped_refptr<WebDataService> wds(new WebDataService());
- if (!wds->Init(GetPath()))
- return;
- web_data_service_.swap(wds);
-}
-
-PasswordStore* ProfileImpl::GetPasswordStore(ServiceAccessType sat) {
- if (!created_password_store_)
- CreatePasswordStore();
- return password_store_.get();
-}
-
-void ProfileImpl::CreatePasswordStore() {
- DCHECK(!created_password_store_ && password_store_.get() == NULL);
- created_password_store_ = true;
- scoped_refptr<PasswordStore> ps;
- FilePath login_db_file_path = GetPath();
- login_db_file_path = login_db_file_path.Append(chrome::kLoginDataFileName);
- LoginDatabase* login_db = new LoginDatabase();
- if (!login_db->Init(login_db_file_path)) {
- LOG(ERROR) << "Could not initialize login database.";
- delete login_db;
- return;
- }
-#if defined(OS_WIN)
- ps = new PasswordStoreWin(login_db, this,
- GetWebDataService(Profile::IMPLICIT_ACCESS));
-#elif defined(OS_MACOSX)
- ps = new PasswordStoreMac(new MacKeychain(), login_db);
-#elif defined(OS_CHROMEOS)
- // For now, we use PasswordStoreDefault. We might want to make a native
- // backend for PasswordStoreX (see below) in the future though.
- ps = new PasswordStoreDefault(login_db, this,
- GetWebDataService(Profile::IMPLICIT_ACCESS));
-#elif defined(OS_POSIX)
- // On POSIX systems, we try to use the "native" password management system of
- // the desktop environment currently running, allowing GNOME Keyring in XFCE.
- // (In all cases we fall back on the default store in case of failure.)
- base::nix::DesktopEnvironment desktop_env;
- std::string store_type =
- CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kPasswordStore);
- if (store_type == "kwallet") {
- desktop_env = base::nix::DESKTOP_ENVIRONMENT_KDE4;
- } else if (store_type == "gnome") {
- desktop_env = base::nix::DESKTOP_ENVIRONMENT_GNOME;
- } else if (store_type == "detect") {
- scoped_ptr<base::Environment> env(base::Environment::Create());
- desktop_env = base::nix::GetDesktopEnvironment(env.get());
- VLOG(1) << "Password storage detected desktop environment: "
- << base::nix::GetDesktopEnvironmentName(desktop_env);
- } else {
- // TODO(mdm): If the flag is not given, or has an unknown value, use the
- // default store for now. Once we're confident in the other stores, we can
- // default to detecting the desktop environment instead.
- desktop_env = base::nix::DESKTOP_ENVIRONMENT_OTHER;
- }
-
- scoped_ptr<PasswordStoreX::NativeBackend> backend;
- if (desktop_env == base::nix::DESKTOP_ENVIRONMENT_KDE4) {
- // KDE3 didn't use DBus, which our KWallet store uses.
- VLOG(1) << "Trying KWallet for password storage.";
- backend.reset(new NativeBackendKWallet());
- if (backend->Init())
- VLOG(1) << "Using KWallet for password storage.";
- else
- backend.reset();
- } else if (desktop_env == base::nix::DESKTOP_ENVIRONMENT_GNOME ||
- desktop_env == base::nix::DESKTOP_ENVIRONMENT_XFCE) {
-#if defined(USE_GNOME_KEYRING)
- VLOG(1) << "Trying GNOME keyring for password storage.";
- backend.reset(new NativeBackendGnome());
- if (backend->Init())
- VLOG(1) << "Using GNOME keyring for password storage.";
- else
- backend.reset();
-#endif // defined(USE_GNOME_KEYRING)
- }
- // TODO(mdm): this can change to a WARNING when we detect by default.
- if (!backend.get())
- VLOG(1) << "Using default (unencrypted) store for password storage.";
-
- ps = new PasswordStoreX(login_db, this,
- GetWebDataService(Profile::IMPLICIT_ACCESS),
- backend.release());
-#else
- NOTIMPLEMENTED();
-#endif
- if (!ps)
- delete login_db;
-
- if (!ps || !ps->Init()) {
- NOTREACHED() << "Could not initialize password manager.";
- return;
- }
- password_store_.swap(ps);
-}
-
-DownloadManager* ProfileImpl::GetDownloadManager() {
- if (!created_download_manager_) {
- scoped_refptr<DownloadManager> dlm(
- new DownloadManager(g_browser_process->download_status_updater()));
- dlm->Init(this);
- created_download_manager_ = true;
- download_manager_.swap(dlm);
- }
- return download_manager_.get();
-}
-
-bool ProfileImpl::HasCreatedDownloadManager() const {
- return created_download_manager_;
-}
-
-PersonalDataManager* ProfileImpl::GetPersonalDataManager() {
- if (!personal_data_manager_.get()) {
- personal_data_manager_ = new PersonalDataManager();
- personal_data_manager_->Init(this);
- }
- return personal_data_manager_.get();
-}
-
-BrowserFileSystemContext* ProfileImpl::GetFileSystemContext() {
- if (!browser_file_system_context_.get())
- browser_file_system_context_ = new BrowserFileSystemContext(
- GetPath(), IsOffTheRecord());
- DCHECK(browser_file_system_context_.get());
- return browser_file_system_context_.get();
-}
-
-void ProfileImpl::InitThemes() {
- if (!created_theme_provider_) {
-#if defined(TOOLKIT_USES_GTK)
- theme_provider_.reset(new GtkThemeProvider);
-#else
- theme_provider_.reset(new BrowserThemeProvider);
-#endif
- theme_provider_->Init(this);
- created_theme_provider_ = true;
- }
-}
-
-void ProfileImpl::SetTheme(const Extension* extension) {
- InitThemes();
- theme_provider_.get()->SetTheme(extension);
-}
-
-void ProfileImpl::SetNativeTheme() {
- InitThemes();
- theme_provider_.get()->SetNativeTheme();
-}
-
-void ProfileImpl::ClearTheme() {
- InitThemes();
- theme_provider_.get()->UseDefaultTheme();
-}
-
-const Extension* ProfileImpl::GetTheme() {
- InitThemes();
-
- std::string id = theme_provider_.get()->GetThemeID();
- if (id == BrowserThemeProvider::kDefaultThemeID)
- return NULL;
-
- return extensions_service_->GetExtensionById(id, false);
-}
-
-BrowserThemeProvider* ProfileImpl::GetThemeProvider() {
- InitThemes();
- return theme_provider_.get();
-}
-
-SessionService* ProfileImpl::GetSessionService() {
- if (!session_service_.get() && !shutdown_session_service_) {
- session_service_ = new SessionService(this);
- session_service_->ResetFromCurrentBrowsers();
- }
- return session_service_.get();
-}
-
-void ProfileImpl::ShutdownSessionService() {
- if (shutdown_session_service_)
- return;
-
- // We're about to exit, force creation of the session service if it hasn't
- // been created yet. We do this to ensure session state matches the point in
- // time the user exited.
- GetSessionService();
- shutdown_session_service_ = true;
- session_service_ = NULL;
-}
-
-bool ProfileImpl::HasSessionService() const {
- return (session_service_.get() != NULL);
-}
-
-bool ProfileImpl::HasProfileSyncService() const {
- return (sync_service_.get() != NULL);
-}
-
-bool ProfileImpl::DidLastSessionExitCleanly() {
- // last_session_exited_cleanly_ is set when the preferences are loaded. Force
- // it to be set by asking for the prefs.
- GetPrefs();
- return last_session_exited_cleanly_;
-}
-
-BookmarkModel* ProfileImpl::GetBookmarkModel() {
- if (!bookmark_bar_model_.get()) {
- bookmark_bar_model_.reset(new BookmarkModel(this));
- bookmark_bar_model_->Load();
- }
- return bookmark_bar_model_.get();
-}
-
-bool ProfileImpl::IsSameProfile(Profile* profile) {
- if (profile == static_cast<Profile*>(this))
- return true;
- Profile* otr_profile = off_the_record_profile_.get();
- return otr_profile && profile == otr_profile;
-}
-
-Time ProfileImpl::GetStartTime() const {
- return start_time_;
-}
-
-TabRestoreService* ProfileImpl::GetTabRestoreService() {
- if (!tab_restore_service_.get())
- tab_restore_service_ = new TabRestoreService(this);
- return tab_restore_service_.get();
-}
-
-history::TopSites* ProfileImpl::GetTopSites() {
- if (!top_sites_.get()) {
- top_sites_ = new history::TopSites(this);
- top_sites_->Init(GetPath().Append(chrome::kTopSitesFilename));
- }
- return top_sites_;
-}
-
-history::TopSites* ProfileImpl::GetTopSitesWithoutCreating() {
- return top_sites_;
-}
-
-void ProfileImpl::ResetTabRestoreService() {
- tab_restore_service_ = NULL;
-}
-
-SpellCheckHost* ProfileImpl::GetSpellCheckHost() {
- return spellcheck_host_ready_ ? spellcheck_host_.get() : NULL;
-}
-
-void ProfileImpl::ReinitializeSpellCheckHost(bool force) {
- // If we are already loading the spellchecker, and this is just a hint to
- // load the spellchecker, do nothing.
- if (!force && spellcheck_host_.get())
- return;
-
- spellcheck_host_ready_ = false;
-
- bool notify = false;
- if (spellcheck_host_.get()) {
- spellcheck_host_->UnsetObserver();
- spellcheck_host_ = NULL;
- notify = true;
- }
-
- PrefService* prefs = GetPrefs();
- if (prefs->GetBoolean(prefs::kEnableSpellCheck)) {
- // Retrieve the (perhaps updated recently) dictionary name from preferences.
- spellcheck_host_ = new SpellCheckHost(
- this,
- prefs->GetString(prefs::kSpellCheckDictionary),
- GetRequestContext());
- spellcheck_host_->Initialize();
- } else if (notify) {
- // The spellchecker has been disabled.
- SpellCheckHostInitialized();
- }
-}
-
-void ProfileImpl::SpellCheckHostInitialized() {
- spellcheck_host_ready_ = spellcheck_host_ &&
- (spellcheck_host_->bdict_file() != base::kInvalidPlatformFileValue ||
- spellcheck_host_->use_platform_spellchecker());
- NotificationService::current()->Notify(
- NotificationType::SPELLCHECK_HOST_REINITIALIZED,
- Source<Profile>(this), NotificationService::NoDetails());
-}
-
-WebKitContext* ProfileImpl::GetWebKitContext() {
- if (!webkit_context_.get())
- webkit_context_ = new WebKitContext(this);
- DCHECK(webkit_context_.get());
- return webkit_context_.get();
-}
-
-DesktopNotificationService* ProfileImpl::GetDesktopNotificationService() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (!desktop_notification_service_.get()) {
- desktop_notification_service_.reset(new DesktopNotificationService(
- this, g_browser_process->notification_ui_manager()));
- }
- return desktop_notification_service_.get();
-}
-
-void ProfileImpl::MarkAsCleanShutdown() {
- if (prefs_.get()) {
- // The session cleanly exited, set kSessionExitedCleanly appropriately.
- prefs_->SetBoolean(prefs::kSessionExitedCleanly, true);
-
- // NOTE: If you change what thread this writes on, be sure and update
- // ChromeFrame::EndSession().
- prefs_->SavePersistentPrefs();
- }
-}
-
-void ProfileImpl::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- if (NotificationType::PREF_CHANGED == type) {
- std::string* pref_name_in = Details<std::string>(details).ptr();
- PrefService* prefs = Source<PrefService>(source).ptr();
- DCHECK(pref_name_in && prefs);
- if (*pref_name_in == prefs::kSpellCheckDictionary ||
- *pref_name_in == prefs::kEnableSpellCheck) {
- ReinitializeSpellCheckHost(true);
- } else if (*pref_name_in == prefs::kEnableAutoSpellCorrect) {
- NotificationService::current()->Notify(
- NotificationType::SPELLCHECK_AUTOSPELL_TOGGLED,
- Source<Profile>(this), NotificationService::NoDetails());
- }
- } else if (NotificationType::THEME_INSTALLED == type) {
- DCHECK_EQ(Source<Profile>(source).ptr(), GetOriginalProfile());
- const Extension* extension = Details<const Extension>(details).ptr();
- SetTheme(extension);
- } else if (NotificationType::BOOKMARK_MODEL_LOADED == type) {
- GetProfileSyncService(); // Causes lazy-load if sync is enabled.
- registrar_.Remove(this, NotificationType::BOOKMARK_MODEL_LOADED,
- Source<Profile>(this));
- }
-}
-
-void ProfileImpl::StopCreateSessionServiceTimer() {
- create_session_service_timer_.Stop();
-}
-
-TokenService* ProfileImpl::GetTokenService() {
- if (!token_service_.get()) {
- token_service_.reset(new TokenService());
- }
- return token_service_.get();
-}
-
-ProfileSyncService* ProfileImpl::GetProfileSyncService() {
- return GetProfileSyncService("");
-}
-
-ProfileSyncService* ProfileImpl::GetProfileSyncService(
- const std::string& cros_user) {
-
- if (!ProfileSyncService::IsSyncEnabled())
- return NULL;
- if (!sync_service_.get())
- InitSyncService(cros_user);
- return sync_service_.get();
-}
-
-BrowserSignin* ProfileImpl::GetBrowserSignin() {
- if (!browser_signin_.get()) {
- browser_signin_.reset(new BrowserSignin(this));
- }
- return browser_signin_.get();
-}
-
-CloudPrintProxyService* ProfileImpl::GetCloudPrintProxyService() {
- if (!cloud_print_proxy_service_.get())
- InitCloudPrintProxyService();
- return cloud_print_proxy_service_.get();
-}
-
-void ProfileImpl::InitSyncService(const std::string& cros_user) {
- profile_sync_factory_.reset(
- new ProfileSyncFactoryImpl(this, CommandLine::ForCurrentProcess()));
- sync_service_.reset(
- profile_sync_factory_->CreateProfileSyncService(cros_user));
- sync_service_->Initialize();
-}
-
-void ProfileImpl::InitCloudPrintProxyService() {
- cloud_print_proxy_service_ = new CloudPrintProxyService(this);
- cloud_print_proxy_service_->Initialize();
-}
-
-ChromeBlobStorageContext* ProfileImpl::GetBlobStorageContext() {
- if (!blob_storage_context_) {
- blob_storage_context_ = new ChromeBlobStorageContext();
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(blob_storage_context_.get(),
- &ChromeBlobStorageContext::InitializeOnIOThread));
- }
- return blob_storage_context_;
-}
-
-ExtensionInfoMap* ProfileImpl::GetExtensionInfoMap() {
- return extension_info_map_.get();
-}
-
-policy::ProfilePolicyContext* ProfileImpl::GetPolicyContext() {
- if (!profile_policy_context_.get())
- profile_policy_context_.reset(new policy::ProfilePolicyContext(this));
-
- return profile_policy_context_.get();
-}
-
-PromoCounter* ProfileImpl::GetInstantPromoCounter() {
-#if defined(OS_WIN)
- // TODO: enable this when we're ready to turn on the promo.
- /*
- if (!checked_instant_promo_) {
- checked_instant_promo_ = true;
- PrefService* prefs = GetPrefs();
- if (!prefs->GetBoolean(prefs::kInstantEnabledOnce) &&
- !InstantController::IsEnabled(this) &&
- InstallUtil::IsChromeSxSProcess()) {
- DCHECK(!instant_promo_counter_.get());
- instant_promo_counter_.reset(
- new PromoCounter(this, prefs::kInstantPromo, "Instant.Promo", 3, 3));
- }
- }
- */
- return instant_promo_counter_.get();
-#else
- return NULL;
-#endif
-}
-
-#if defined(OS_CHROMEOS)
-chromeos::ProxyConfigServiceImpl*
- ProfileImpl::GetChromeOSProxyConfigServiceImpl() {
- if (!chromeos_proxy_config_service_impl_) {
- chromeos_proxy_config_service_impl_ =
- new chromeos::ProxyConfigServiceImpl();
- }
- return chromeos_proxy_config_service_impl_;
-}
-#endif // defined(OS_CHROMEOS)
-
-PrefProxyConfigTracker* ProfileImpl::GetProxyConfigTracker() {
- if (!pref_proxy_config_tracker_)
- pref_proxy_config_tracker_ = new PrefProxyConfigTracker(GetPrefs());
-
- return pref_proxy_config_tracker_;
-}
diff --git a/chrome/browser/profile_impl.h b/chrome/browser/profile_impl.h
deleted file mode 100644
index b0ea586..0000000
--- a/chrome/browser/profile_impl.h
+++ /dev/null
@@ -1,290 +0,0 @@
-// 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.
-
-// This class gathers state related to a single user profile.
-
-#ifndef CHROME_BROWSER_PROFILE_IMPL_H_
-#define CHROME_BROWSER_PROFILE_IMPL_H_
-#pragma once
-
-#include "base/file_path.h"
-#include "base/ref_counted.h"
-#include "base/scoped_ptr.h"
-#include "base/timer.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/prefs/pref_change_registrar.h"
-#include "chrome/browser/spellcheck_host_observer.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
-
-class PrefService;
-
-#if defined(OS_CHROMEOS)
-namespace chromeos {
-class Preferences;
-}
-#endif
-
-class NetPrefObserver;
-
-// The default profile implementation.
-class ProfileImpl : public Profile,
- public SpellCheckHostObserver,
- public NotificationObserver {
- public:
- virtual ~ProfileImpl();
-
- static void RegisterUserPrefs(PrefService* prefs);
-
- // Profile implementation.
- virtual ProfileId GetRuntimeId();
- virtual FilePath GetPath();
- virtual bool IsOffTheRecord();
- virtual Profile* GetOffTheRecordProfile();
- virtual void DestroyOffTheRecordProfile();
- virtual bool HasOffTheRecordProfile();
- virtual Profile* GetOriginalProfile();
- virtual ChromeAppCacheService* GetAppCacheService();
- virtual webkit_database::DatabaseTracker* GetDatabaseTracker();
- virtual history::TopSites* GetTopSites();
- virtual history::TopSites* GetTopSitesWithoutCreating();
- virtual VisitedLinkMaster* GetVisitedLinkMaster();
- virtual UserScriptMaster* GetUserScriptMaster();
- virtual SSLHostState* GetSSLHostState();
- virtual net::TransportSecurityState* GetTransportSecurityState();
- virtual ExtensionsService* GetExtensionsService();
- virtual ExtensionDevToolsManager* GetExtensionDevToolsManager();
- virtual ExtensionProcessManager* GetExtensionProcessManager();
- virtual ExtensionMessageService* GetExtensionMessageService();
- virtual ExtensionEventRouter* GetExtensionEventRouter();
- virtual FaviconService* GetFaviconService(ServiceAccessType sat);
- virtual HistoryService* GetHistoryService(ServiceAccessType sat);
- virtual HistoryService* GetHistoryServiceWithoutCreating();
- virtual AutocompleteClassifier* GetAutocompleteClassifier();
- virtual WebDataService* GetWebDataService(ServiceAccessType sat);
- virtual WebDataService* GetWebDataServiceWithoutCreating();
- virtual PasswordStore* GetPasswordStore(ServiceAccessType sat);
- virtual PrefService* GetPrefs();
- virtual TemplateURLModel* GetTemplateURLModel();
- virtual TemplateURLFetcher* GetTemplateURLFetcher();
- virtual DownloadManager* GetDownloadManager();
- virtual PersonalDataManager* GetPersonalDataManager();
- virtual BrowserFileSystemContext* GetFileSystemContext();
- virtual void InitThemes();
- virtual void SetTheme(const Extension* extension);
- virtual void SetNativeTheme();
- virtual void ClearTheme();
- virtual const Extension* GetTheme();
- virtual BrowserThemeProvider* GetThemeProvider();
- virtual bool HasCreatedDownloadManager() const;
- virtual URLRequestContextGetter* GetRequestContext();
- virtual URLRequestContextGetter* GetRequestContextForMedia();
- virtual URLRequestContextGetter* GetRequestContextForExtensions();
- virtual void RegisterExtensionWithRequestContexts(const Extension* extension);
- virtual void UnregisterExtensionWithRequestContexts(
- const Extension* extension);
- virtual net::SSLConfigService* GetSSLConfigService();
- virtual HostContentSettingsMap* GetHostContentSettingsMap();
- virtual HostZoomMap* GetHostZoomMap();
- virtual GeolocationContentSettingsMap* GetGeolocationContentSettingsMap();
- virtual GeolocationPermissionContext* GetGeolocationPermissionContext();
- virtual UserStyleSheetWatcher* GetUserStyleSheetWatcher();
- virtual FindBarState* GetFindBarState();
- virtual SessionService* GetSessionService();
- virtual void ShutdownSessionService();
- virtual bool HasSessionService() const;
- virtual bool HasProfileSyncService() const;
- virtual bool DidLastSessionExitCleanly();
- virtual BookmarkModel* GetBookmarkModel();
- virtual bool IsSameProfile(Profile* profile);
- virtual base::Time GetStartTime() const;
- virtual TabRestoreService* GetTabRestoreService();
- virtual void ResetTabRestoreService();
- virtual SpellCheckHost* GetSpellCheckHost();
- virtual void ReinitializeSpellCheckHost(bool force);
- virtual WebKitContext* GetWebKitContext();
- virtual DesktopNotificationService* GetDesktopNotificationService();
- virtual BackgroundContentsService* GetBackgroundContentsService() const;
- virtual StatusTray* GetStatusTray();
- virtual void MarkAsCleanShutdown();
- virtual void InitExtensions();
- virtual void InitWebResources();
- virtual NTPResourceCache* GetNTPResourceCache();
- virtual FilePath last_selected_directory();
- virtual void set_last_selected_directory(const FilePath& path);
- virtual ProfileSyncService* GetProfileSyncService();
- virtual ProfileSyncService* GetProfileSyncService(
- const std::string& cros_user);
- virtual TokenService* GetTokenService();
- void InitSyncService(const std::string& cros_user);
- virtual CloudPrintProxyService* GetCloudPrintProxyService();
- void InitCloudPrintProxyService();
- virtual ChromeBlobStorageContext* GetBlobStorageContext();
- virtual ExtensionInfoMap* GetExtensionInfoMap();
- virtual PromoCounter* GetInstantPromoCounter();
- virtual BrowserSignin* GetBrowserSignin();
- virtual policy::ProfilePolicyContext* GetPolicyContext();
-
-#if defined(OS_CHROMEOS)
- virtual chromeos::ProxyConfigServiceImpl* GetChromeOSProxyConfigServiceImpl();
-#endif // defined(OS_CHROMEOS)
-
- virtual PrefProxyConfigTracker* GetProxyConfigTracker();
-
- // NotificationObserver implementation.
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- // SpellCheckHostObserver implementation.
- virtual void SpellCheckHostInitialized();
-
- private:
- friend class Profile;
-
- explicit ProfileImpl(const FilePath& path);
-
- void CreateWebDataService();
- FilePath GetPrefFilePath();
-
- void CreatePasswordStore();
-
- void StopCreateSessionServiceTimer();
-
- void EnsureRequestContextCreated() {
- GetRequestContext();
- }
-
- void EnsureSessionServiceCreated() {
- GetSessionService();
- }
-
- void RegisterComponentExtensions();
- void InstallDefaultApps();
-
- NotificationRegistrar registrar_;
- PrefChangeRegistrar pref_change_registrar_;
-
- FilePath path_;
- FilePath base_cache_path_;
- scoped_ptr<VisitedLinkEventListener> visited_link_event_listener_;
- scoped_ptr<VisitedLinkMaster> visited_link_master_;
- scoped_refptr<ExtensionsService> extensions_service_;
- scoped_refptr<UserScriptMaster> user_script_master_;
- scoped_refptr<ExtensionDevToolsManager> extension_devtools_manager_;
- scoped_ptr<ExtensionProcessManager> extension_process_manager_;
- scoped_refptr<ExtensionMessageService> extension_message_service_;
- scoped_ptr<ExtensionEventRouter> extension_event_router_;
- scoped_ptr<SSLHostState> ssl_host_state_;
- scoped_refptr<net::TransportSecurityState>
- transport_security_state_;
- scoped_refptr<TransportSecurityPersister>
- transport_security_persister_;
- scoped_ptr<policy::ProfilePolicyContext> profile_policy_context_;
- scoped_ptr<PrefService> prefs_;
- scoped_ptr<NetPrefObserver> net_pref_observer_;
- scoped_ptr<TemplateURLFetcher> template_url_fetcher_;
- scoped_ptr<TemplateURLModel> template_url_model_;
- scoped_ptr<BookmarkModel> bookmark_bar_model_;
- scoped_refptr<WebResourceService> web_resource_service_;
- scoped_ptr<NTPResourceCache> ntp_resource_cache_;
-
- scoped_ptr<TokenService> token_service_;
- scoped_ptr<ProfileSyncFactory> profile_sync_factory_;
- scoped_ptr<ProfileSyncService> sync_service_;
- scoped_refptr<CloudPrintProxyService> cloud_print_proxy_service_;
-
- scoped_refptr<ChromeURLRequestContextGetter> request_context_;
-
- scoped_refptr<ChromeURLRequestContextGetter> media_request_context_;
-
- scoped_refptr<ChromeURLRequestContextGetter> extensions_request_context_;
-
- scoped_ptr<SSLConfigServiceManager> ssl_config_service_manager_;
-
- scoped_refptr<HostContentSettingsMap> host_content_settings_map_;
- scoped_refptr<HostZoomMap> host_zoom_map_;
- scoped_refptr<GeolocationContentSettingsMap>
- geolocation_content_settings_map_;
- scoped_refptr<GeolocationPermissionContext>
- geolocation_permission_context_;
- scoped_refptr<UserStyleSheetWatcher> user_style_sheet_watcher_;
- scoped_ptr<FindBarState> find_bar_state_;
- scoped_refptr<DownloadManager> download_manager_;
- scoped_refptr<HistoryService> history_service_;
- scoped_refptr<FaviconService> favicon_service_;
- scoped_ptr<AutocompleteClassifier> autocomplete_classifier_;
- scoped_refptr<WebDataService> web_data_service_;
- scoped_refptr<PasswordStore> password_store_;
- scoped_refptr<SessionService> session_service_;
- scoped_ptr<BrowserThemeProvider> theme_provider_;
- scoped_refptr<WebKitContext> webkit_context_;
- scoped_ptr<DesktopNotificationService> desktop_notification_service_;
- scoped_ptr<BackgroundContentsService> background_contents_service_;
- scoped_ptr<BackgroundModeManager> background_mode_manager_;
- scoped_ptr<StatusTray> status_tray_;
- scoped_refptr<PersonalDataManager> personal_data_manager_;
- scoped_ptr<PinnedTabService> pinned_tab_service_;
- scoped_refptr<BrowserFileSystemContext> browser_file_system_context_;
- scoped_ptr<BrowserSignin> browser_signin_;
- bool history_service_created_;
- bool favicon_service_created_;
- bool created_web_data_service_;
- bool created_password_store_;
- bool created_download_manager_;
- bool created_theme_provider_;
- // Whether or not the last session exited cleanly. This is set only once.
- bool last_session_exited_cleanly_;
-
- base::OneShotTimer<ProfileImpl> create_session_service_timer_;
-
- scoped_ptr<Profile> off_the_record_profile_;
-
- // See GetStartTime for details.
- base::Time start_time_;
-
- scoped_refptr<TabRestoreService> tab_restore_service_;
-
- scoped_refptr<SpellCheckHost> spellcheck_host_;
-
- // Indicates whether |spellcheck_host_| has told us initialization is
- // finished.
- bool spellcheck_host_ready_;
-
-#if defined(OS_WIN)
- bool checked_instant_promo_;
- scoped_ptr<PromoCounter> instant_promo_counter_;
-#endif
-
- // Set to true when ShutdownSessionService is invoked. If true
- // GetSessionService won't recreate the SessionService.
- bool shutdown_session_service_;
-
- // The AppCacheService for this profile, shared by all requests contexts
- // associated with this profile. Should only be used on the IO thread.
- scoped_refptr<ChromeAppCacheService> appcache_service_;
-
- // The main database tracker for this profile.
- // Should be used only on the file thread.
- scoped_refptr<webkit_database::DatabaseTracker> db_tracker_;
-
- scoped_refptr<history::TopSites> top_sites_; // For history and thumbnails.
-
- scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;
-
- scoped_refptr<ExtensionInfoMap> extension_info_map_;
-
-#if defined(OS_CHROMEOS)
- scoped_ptr<chromeos::Preferences> chromeos_preferences_;
-
- scoped_refptr<chromeos::ProxyConfigServiceImpl>
- chromeos_proxy_config_service_impl_;
-#endif
-
- scoped_refptr<PrefProxyConfigTracker> pref_proxy_config_tracker_;
-
- DISALLOW_COPY_AND_ASSIGN(ProfileImpl);
-};
-
-#endif // CHROME_BROWSER_PROFILE_IMPL_H_
diff --git a/chrome/browser/profile_import_process_host.cc b/chrome/browser/profile_import_process_host.cc
index 26e4ec1..3663ef7 100644
--- a/chrome/browser/profile_import_process_host.cc
+++ b/chrome/browser/profile_import_process_host.cc
@@ -118,39 +118,36 @@ bool ProfileImportProcessHost::StartProcess() {
return true;
}
-void ProfileImportProcessHost::OnMessageReceived(const IPC::Message& message) {
+bool ProfileImportProcessHost::OnMessageReceived(const IPC::Message& message) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
BrowserThread::PostTask(
thread_id_, FROM_HERE,
NewRunnableMethod(import_process_client_.get(),
&ImportProcessClient::OnMessageReceived,
message));
+ return true;
}
-void ProfileImportProcessHost::OnProcessCrashed() {
+void ProfileImportProcessHost::OnProcessCrashed(int exit_code) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
BrowserThread::PostTask(
thread_id_, FROM_HERE,
NewRunnableMethod(import_process_client_.get(),
- &ImportProcessClient::OnProcessCrashed));
+ &ImportProcessClient::OnProcessCrashed,
+ exit_code));
}
bool ProfileImportProcessHost::CanShutdown() {
return true;
}
-URLRequestContext* ProfileImportProcessHost::GetRequestContext(
- uint32 request_id,
- const ViewHostMsg_Resource_Request& request_data) {
- return NULL;
-}
-
ProfileImportProcessHost::ImportProcessClient::ImportProcessClient() {}
ProfileImportProcessHost::ImportProcessClient::~ImportProcessClient() {}
-void ProfileImportProcessHost::ImportProcessClient::OnMessageReceived(
+bool ProfileImportProcessHost::ImportProcessClient::OnMessageReceived(
const IPC::Message& message) {
+ bool handled = true;
IPC_BEGIN_MESSAGE_MAP(ProfileImportProcessHost, message)
// Notification messages about the state of the import process.
IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_Import_Started,
@@ -181,5 +178,7 @@ void ProfileImportProcessHost::ImportProcessClient::OnMessageReceived(
ImportProcessClient::OnPasswordFormImportReady)
IPC_MESSAGE_HANDLER(ProfileImportProcessHostMsg_NotifyKeywordsReady,
ImportProcessClient::OnKeywordsImportReady)
+ IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP_EX()
+ return handled;
}
diff --git a/chrome/browser/profile_import_process_host.h b/chrome/browser/profile_import_process_host.h
index a9d5805..dae6108 100644
--- a/chrome/browser/profile_import_process_host.h
+++ b/chrome/browser/profile_import_process_host.h
@@ -16,7 +16,6 @@
#include "chrome/browser/history/history_types.h"
#include "chrome/browser/importer/importer_data_types.h"
#include "chrome/browser/importer/profile_writer.h"
-#include "ipc/ipc_channel.h"
namespace webkit_glue {
struct PasswordForm;
@@ -40,7 +39,7 @@ class ProfileImportProcessHost : public BrowserChildProcessHost {
// These methods are used by the ProfileImportProcessHost to pass messages
// received from the external process back to the ImportProcessClient in
// ImporterHost.
- virtual void OnProcessCrashed() {}
+ virtual void OnProcessCrashed(int exit_status) {}
virtual void OnImportStart() {}
virtual void OnImportFinished(bool succeeded, std::string error_msg) {}
virtual void OnImportItemStart(int item) {}
@@ -74,7 +73,7 @@ class ProfileImportProcessHost : public BrowserChildProcessHost {
const std::vector<TemplateURL>& template_urls,
int default_keyword_index, bool unique_on_host_and_path) {}
- virtual void OnMessageReceived(const IPC::Message& message);
+ virtual bool OnMessageReceived(const IPC::Message& message);
protected:
friend class base::RefCountedThreadSafe<ImportProcessClient>;
@@ -123,14 +122,11 @@ class ProfileImportProcessHost : public BrowserChildProcessHost {
// Called by the external importer process to send messages back to the
// ImportProcessClient.
- void OnMessageReceived(const IPC::Message& message);
+ virtual bool OnMessageReceived(const IPC::Message& message);
// Overridden from BrowserChildProcessHost:
- virtual void OnProcessCrashed();
+ virtual void OnProcessCrashed(int exit_code);
virtual bool CanShutdown();
- virtual URLRequestContext* GetRequestContext(
- uint32 request_id,
- const ViewHostMsg_Resource_Request& request_data);
// Receives messages to be passed back to the importer host.
scoped_refptr<ImportProcessClient> import_process_client_;
diff --git a/chrome/browser/profile_manager.cc b/chrome/browser/profile_manager.cc
deleted file mode 100644
index 2b5048a..0000000
--- a/chrome/browser/profile_manager.cc
+++ /dev/null
@@ -1,284 +0,0 @@
-// 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.
-
-#include <set>
-
-#include "chrome/browser/profile_manager.h"
-
-#include "base/command_line.h"
-#include "base/file_util.h"
-#include "base/path_service.h"
-#include "base/string_util.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_list.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/common/chrome_constants.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/logging_chrome.h"
-#include "chrome/common/net/url_request_context_getter.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/notification_type.h"
-#include "chrome/common/pref_names.h"
-#include "grit/generated_resources.h"
-#include "net/http/http_transaction_factory.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_job.h"
-#include "net/url_request/url_request_job_tracker.h"
-
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/cros/cros_library.h"
-#include "chrome/browser/chromeos/cros/cryptohome_library.h"
-#endif
-
-// static
-void ProfileManager::ShutdownSessionServices() {
- ProfileManager* pm = g_browser_process->profile_manager();
- if (!pm) // Is NULL when running unit tests.
- return;
- for (ProfileManager::const_iterator i = pm->begin(); i != pm->end(); ++i)
- (*i)->ShutdownSessionService();
-}
-
-// static
-Profile* ProfileManager::GetDefaultProfile() {
- FilePath user_data_dir;
- PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
- ProfileManager* profile_manager = g_browser_process->profile_manager();
- return profile_manager->GetDefaultProfile(user_data_dir);
-}
-
-ProfileManager::ProfileManager() : logged_in_(false) {
- SystemMonitor::Get()->AddObserver(this);
-#if defined(OS_CHROMEOS)
- registrar_.Add(
- this,
- NotificationType::LOGIN_USER_CHANGED,
- NotificationService::AllSources());
-#endif
-}
-
-ProfileManager::~ProfileManager() {
- SystemMonitor* system_monitor = SystemMonitor::Get();
- if (system_monitor)
- system_monitor->RemoveObserver(this);
-
- // Destroy all profiles that we're keeping track of.
- for (const_iterator i(begin()); i != end(); ++i)
- delete *i;
- profiles_.clear();
-}
-
-FilePath ProfileManager::GetDefaultProfileDir(
- const FilePath& user_data_dir) {
- FilePath default_profile_dir(user_data_dir);
- default_profile_dir = default_profile_dir.Append(
- FilePath::FromWStringHack(chrome::kNotSignedInProfile));
- return default_profile_dir;
-}
-
-FilePath ProfileManager::GetProfilePrefsPath(
- const FilePath &profile_dir) {
- FilePath default_prefs_path(profile_dir);
- default_prefs_path = default_prefs_path.Append(chrome::kPreferencesFilename);
- return default_prefs_path;
-}
-
-FilePath ProfileManager::GetCurrentProfileDir() {
- FilePath relative_profile_dir;
-#if defined(OS_CHROMEOS)
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- if (logged_in_) {
- FilePath profile_dir;
- // If the user has logged in, pick up the new profile.
- if (command_line.HasSwitch(switches::kLoginProfile)) {
- profile_dir = command_line.GetSwitchValuePath(switches::kLoginProfile);
- } else {
- // We should never be logged in with no profile dir.
- NOTREACHED();
- return FilePath("");
- }
- relative_profile_dir = relative_profile_dir.Append(profile_dir);
- return relative_profile_dir;
- }
-#endif
- relative_profile_dir = relative_profile_dir.Append(
- FilePath::FromWStringHack(chrome::kNotSignedInProfile));
- return relative_profile_dir;
-}
-
-Profile* ProfileManager::GetDefaultProfile(const FilePath& user_data_dir) {
- FilePath default_profile_dir(user_data_dir);
- default_profile_dir = default_profile_dir.Append(GetCurrentProfileDir());
-#if defined(OS_CHROMEOS)
- if (!logged_in_) {
- Profile* profile;
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
-
- // For cros, return the OTR profile so we never accidentally keep
- // user data in an unencrypted profile. But doing this makes
- // many of the browser and ui tests fail. We do return the OTR profile
- // if the login-profile switch is passed so that we can test this.
- // TODO(davemoore) Fix the tests so they allow OTR profiles.
- if (!command_line.HasSwitch(switches::kTestType) ||
- command_line.HasSwitch(switches::kLoginProfile)) {
- // Don't init extensions for this profile
- profile = GetProfile(default_profile_dir, false);
- profile = profile->GetOffTheRecordProfile();
- } else {
- profile = GetProfile(default_profile_dir, true);
- }
- return profile;
- }
-#endif
- return GetProfile(default_profile_dir);
-}
-
-Profile* ProfileManager::GetProfile(const FilePath& profile_dir) {
- return GetProfile(profile_dir, true);
-}
-
-Profile* ProfileManager::GetProfile(
- const FilePath& profile_dir, bool init_extensions) {
- // If the profile is already loaded (e.g., chrome.exe launched twice), just
- // return it.
- Profile* profile = GetProfileByPath(profile_dir);
- if (NULL != profile)
- return profile;
-
- if (!ProfileManager::IsProfile(profile_dir)) {
- // If the profile directory doesn't exist, create it.
- profile = ProfileManager::CreateProfile(profile_dir);
- } else {
- // The profile already exists on disk, just load it.
- profile = Profile::CreateProfile(profile_dir);
- }
- DCHECK(profile);
- if (profile) {
- bool result = AddProfile(profile, init_extensions);
- DCHECK(result);
- }
- return profile;
-}
-
-bool ProfileManager::AddProfile(Profile* profile, bool init_extensions) {
- DCHECK(profile);
-
- // Make sure that we're not loading a profile with the same ID as a profile
- // that's already loaded.
- if (GetProfileByPath(profile->GetPath())) {
- NOTREACHED() << "Attempted to add profile with the same path (" <<
- profile->GetPath().value() <<
- ") as an already-loaded profile.";
- return false;
- }
-
- profiles_.insert(profiles_.end(), profile);
- if (init_extensions)
- profile->InitExtensions();
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- if (!command_line.HasSwitch(switches::kDisableWebResources))
- profile->InitWebResources();
- return true;
-}
-
-Profile* ProfileManager::GetProfileByPath(const FilePath& path) const {
- for (const_iterator i(begin()); i != end(); ++i) {
- if ((*i)->GetPath() == path)
- return *i;
- }
-
- return NULL;
-}
-
-void ProfileManager::OnSuspend() {
- DCHECK(CalledOnValidThread());
-
- for (const_iterator i(begin()); i != end(); ++i) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableFunction(&ProfileManager::SuspendProfile, *i));
- }
-}
-
-void ProfileManager::OnResume() {
- DCHECK(CalledOnValidThread());
- for (const_iterator i(begin()); i != end(); ++i) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableFunction(&ProfileManager::ResumeProfile, *i));
- }
-}
-
-void ProfileManager::Observe(
- NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
-#if defined(OS_CHROMEOS)
- if (type == NotificationType::LOGIN_USER_CHANGED) {
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- if (!command_line.HasSwitch(switches::kTestType)) {
- // This will fail when running on non cros os.
- // TODO(davemoore) Need to mock this enough to enable testing.
- CHECK(chromeos::CrosLibrary::Get()->EnsureLoaded());
- // If we don't have a mounted profile directory we're in trouble.
- // TODO(davemoore) Once we have better api this check should ensure that
- // our profile directory is the one that's mounted, and that it's mounted
- // as the current user.
- CHECK(chromeos::CrosLibrary::Get()->GetCryptohomeLibrary()->IsMounted());
- }
- logged_in_ = true;
- }
-#endif
-}
-
-void ProfileManager::SuspendProfile(Profile* profile) {
- DCHECK(profile);
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- for (URLRequestJobTracker::JobIterator i = g_url_request_job_tracker.begin();
- i != g_url_request_job_tracker.end(); ++i)
- (*i)->Kill();
-
- profile->GetRequestContext()->GetURLRequestContext()->
- http_transaction_factory()->Suspend(true);
-}
-
-void ProfileManager::ResumeProfile(Profile* profile) {
- DCHECK(profile);
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- profile->GetRequestContext()->GetURLRequestContext()->
- http_transaction_factory()->Suspend(false);
-}
-
-// static
-bool ProfileManager::IsProfile(const FilePath& path) {
- FilePath prefs_path = GetProfilePrefsPath(path);
- FilePath history_path = path;
- history_path = history_path.Append(chrome::kHistoryFilename);
-
- return file_util::PathExists(prefs_path) &&
- file_util::PathExists(history_path);
-}
-
-// static
-Profile* ProfileManager::CreateProfile(const FilePath& path) {
- if (IsProfile(path)) {
- DCHECK(false) << "Attempted to create a profile with the path:\n"
- << path.value() << "\n but that path already contains a profile";
- }
-
- if (!file_util::PathExists(path)) {
- // TODO(tc): http://b/1094718 Bad things happen if we can't write to the
- // profile directory. We should eventually be able to run in this
- // situation.
- if (!file_util::CreateDirectory(path))
- return NULL;
- }
-
- return Profile::CreateProfile(path);
-}
diff --git a/chrome/browser/profile_manager.h b/chrome/browser/profile_manager.h
deleted file mode 100644
index 4d540f1..0000000
--- a/chrome/browser/profile_manager.h
+++ /dev/null
@@ -1,128 +0,0 @@
-// 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.
-
-// This class keeps track of the currently-active profiles in the runtime.
-
-#ifndef CHROME_BROWSER_PROFILE_MANAGER_H__
-#define CHROME_BROWSER_PROFILE_MANAGER_H__
-#pragma once
-
-#include <vector>
-
-#include "app/system_monitor.h"
-#include "base/basictypes.h"
-#include "base/message_loop.h"
-#include "base/non_thread_safe.h"
-#include "chrome/browser/profile.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
-
-class FilePath;
-
-class ProfileManager : public NonThreadSafe,
- public SystemMonitor::PowerObserver,
- public NotificationObserver {
- public:
- ProfileManager();
- virtual ~ProfileManager();
-
- // Invokes ShutdownSessionService() on all profiles.
- static void ShutdownSessionServices();
-
- // Returns the default profile. This adds the profile to the
- // ProfileManager if it doesn't already exist. This method returns NULL if
- // the profile doesn't exist and we can't create it.
- // The profile used can be overridden by using --login-profile on cros.
- Profile* GetDefaultProfile(const FilePath& user_data_dir);
-
- // Same as instance method but provides the default user_data_dir as well.
- static Profile* GetDefaultProfile();
-
- // Returns a profile for a specific profile directory within the user data
- // dir. This will return an existing profile it had already been created,
- // otherwise it will create and manage it.
- Profile* GetProfile(const FilePath& profile_dir);
-
- // Returns a profile for a specific profile directory within the user data
- // dir with the option of controlling whether extensions are initialized
- // or not. This will return an existing profile it had already been created,
- // otherwise it will create and manage it.
- // Note that if the profile has already been created, extensions may have
- // been initialized. If this matters to you, you should call GetProfileByPath
- // first to see if the profile already exists.
- Profile* GetProfile(const FilePath& profile_dir, bool init_extensions);
-
- // Returns the directory where the currently active profile is
- // stored, relative to the user data directory currently in use..
- FilePath GetCurrentProfileDir();
-
- // These allow iteration through the current list of profiles.
- typedef std::vector<Profile*> ProfileVector;
- typedef ProfileVector::iterator iterator;
- typedef ProfileVector::const_iterator const_iterator;
-
- iterator begin() { return profiles_.begin(); }
- const_iterator begin() const { return profiles_.begin(); }
- iterator end() { return profiles_.end(); }
- const_iterator end() const { return profiles_.end(); }
-
- // PowerObserver notifications
- void OnSuspend();
- void OnResume();
-
- // NotificationObserver implementation.
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- // ------------------ static utility functions -------------------
-
- // Returns the path to the default profile directory, based on the given
- // user data directory.
- static FilePath GetDefaultProfileDir(const FilePath& user_data_dir);
-
- // Returns the path to the preferences file given the user profile directory.
- static FilePath GetProfilePrefsPath(const FilePath& profile_dir);
-
- // Tries to determine whether the given path represents a profile
- // directory, and returns true if it thinks it does.
- static bool IsProfile(const FilePath& path);
-
- // If a profile with the given path is currently managed by this object,
- // return a pointer to the corresponding Profile object;
- // otherwise return NULL.
- Profile* GetProfileByPath(const FilePath& path) const;
-
- // Creates a new profile at the specified path.
- // This method should always return a valid Profile (i.e., should never
- // return NULL).
- static Profile* CreateProfile(const FilePath& path);
-
- private:
- // Hooks to suspend/resume per-profile network traffic.
- // These must be called on the IO thread.
- static void SuspendProfile(Profile*);
- static void ResumeProfile(Profile*);
-
- // Adds a pre-existing Profile object to the set managed by this
- // ProfileManager. This ProfileManager takes ownership of the Profile.
- // The Profile should not already be managed by this ProfileManager.
- // Returns true if the profile was added, false otherwise.
- bool AddProfile(Profile* profile, bool init_extensions);
-
- // We keep a simple vector of profiles rather than something fancier
- // because we expect there to be a small number of profiles active.
- ProfileVector profiles_;
-
- NotificationRegistrar registrar_;
-
- // Indicates that a user has logged in and that the profile specified
- // in the --login-profile command line argument should be used as the
- // default.
- bool logged_in_;
-
- DISALLOW_COPY_AND_ASSIGN(ProfileManager);
-};
-
-#endif // CHROME_BROWSER_PROFILE_MANAGER_H__
diff --git a/chrome/browser/profile_manager_unittest.cc b/chrome/browser/profile_manager_unittest.cc
deleted file mode 100644
index b3e7aad..0000000
--- a/chrome/browser/profile_manager_unittest.cc
+++ /dev/null
@@ -1,148 +0,0 @@
-// 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.
-
-#include "app/system_monitor.h"
-#include "base/command_line.h"
-#include "base/file_util.h"
-#include "base/message_loop.h"
-#include "base/path_service.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/profile_manager.h"
-#include "chrome/common/chrome_constants.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/pref_names.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-class ProfileManagerTest : public testing::Test {
- protected:
- ProfileManagerTest() : ui_thread_(BrowserThread::UI, &message_loop_) {
- }
-
- virtual void SetUp() {
- // Name a subdirectory of the temp directory.
- ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &test_dir_));
- test_dir_ = test_dir_.Append(FILE_PATH_LITERAL("ProfileManagerTest"));
-
- // Create a fresh, empty copy of this directory.
- file_util::Delete(test_dir_, true);
- file_util::CreateDirectory(test_dir_);
- }
- virtual void TearDown() {
- // Clean up test directory
- ASSERT_TRUE(file_util::Delete(test_dir_, true));
- ASSERT_FALSE(file_util::PathExists(test_dir_));
- }
-
- MessageLoopForUI message_loop_;
- BrowserThread ui_thread_;
-
- // the path to temporary directory used to contain the test operations
- FilePath test_dir_;
-};
-
-TEST_F(ProfileManagerTest, CreateProfile) {
- FilePath source_path;
- PathService::Get(chrome::DIR_TEST_DATA, &source_path);
- source_path = source_path.Append(FILE_PATH_LITERAL("profiles"));
- source_path = source_path.Append(FILE_PATH_LITERAL("sample"));
-
- FilePath dest_path = test_dir_;
- dest_path = dest_path.Append(FILE_PATH_LITERAL("New Profile"));
-
- scoped_ptr<Profile> profile;
-
- // Successfully create a profile.
- profile.reset(ProfileManager::CreateProfile(dest_path));
- ASSERT_TRUE(profile.get());
-
- profile.reset();
-
-#ifdef NDEBUG
- // In Release mode, we always try to always return a profile. In debug,
- // these cases would trigger DCHECKs.
-
- // The profile already exists when we call CreateProfile. Just load it.
- profile.reset(ProfileManager::CreateProfile(dest_path));
- ASSERT_TRUE(profile.get());
-#endif
-}
-
-TEST_F(ProfileManagerTest, DefaultProfileDir) {
- CommandLine *cl = CommandLine::ForCurrentProcess();
- SystemMonitor dummy;
- ProfileManager profile_manager;
- std::string profile_dir("my_user");
-
- cl->AppendSwitch(switches::kTestType);
-
- FilePath expected_default =
- FilePath::FromWStringHack(chrome::kNotSignedInProfile);
- EXPECT_EQ(expected_default.value(),
- profile_manager.GetCurrentProfileDir().value());
-}
-
-#if defined(OS_CHROMEOS)
-// This functionality only exists on Chrome OS.
-TEST_F(ProfileManagerTest, LoggedInProfileDir) {
- CommandLine *cl = CommandLine::ForCurrentProcess();
- SystemMonitor dummy;
- ProfileManager profile_manager;
- std::string profile_dir("my_user");
-
- cl->AppendSwitchASCII(switches::kLoginProfile, profile_dir);
- cl->AppendSwitch(switches::kTestType);
-
- FilePath expected_default =
- FilePath::FromWStringHack(chrome::kNotSignedInProfile);
- EXPECT_EQ(expected_default.value(),
- profile_manager.GetCurrentProfileDir().value());
-
- profile_manager.Observe(NotificationType::LOGIN_USER_CHANGED,
- NotificationService::AllSources(),
- NotificationService::NoDetails());
- FilePath expected_logged_in(profile_dir);
- EXPECT_EQ(expected_logged_in.value(),
- profile_manager.GetCurrentProfileDir().value());
- VLOG(1) << test_dir_.Append(profile_manager.GetCurrentProfileDir()).value();
-}
-
-#endif
-
-TEST_F(ProfileManagerTest, CreateAndUseTwoProfiles) {
- FilePath source_path;
- PathService::Get(chrome::DIR_TEST_DATA, &source_path);
- source_path = source_path.Append(FILE_PATH_LITERAL("profiles"));
- source_path = source_path.Append(FILE_PATH_LITERAL("sample"));
-
- FilePath dest_path1 = test_dir_;
- dest_path1 = dest_path1.Append(FILE_PATH_LITERAL("New Profile 1"));
-
- FilePath dest_path2 = test_dir_;
- dest_path2 = dest_path2.Append(FILE_PATH_LITERAL("New Profile 2"));
-
- scoped_ptr<Profile> profile1;
- scoped_ptr<Profile> profile2;
-
- // Successfully create the profiles.
- profile1.reset(ProfileManager::CreateProfile(dest_path1));
- ASSERT_TRUE(profile1.get());
-
- profile2.reset(ProfileManager::CreateProfile(dest_path2));
- ASSERT_TRUE(profile2.get());
-
- // Force lazy-init of some profile services to simulate use.
- EXPECT_TRUE(profile1->GetHistoryService(Profile::EXPLICIT_ACCESS));
- EXPECT_TRUE(profile1->GetBookmarkModel());
- EXPECT_TRUE(profile2->GetBookmarkModel());
- EXPECT_TRUE(profile2->GetHistoryService(Profile::EXPLICIT_ACCESS));
- profile1.reset();
- profile2.reset();
- // Make sure history cleans up correctly.
- message_loop_.RunAllPending();
-}
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc
new file mode 100644
index 0000000..1e2bba4
--- /dev/null
+++ b/chrome/browser/profiles/profile.cc
@@ -0,0 +1,680 @@
+// 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.
+
+#include "chrome/browser/profiles/profile.h"
+
+#include "app/resource_bundle.h"
+#include "base/command_line.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/scoped_ptr.h"
+#include "base/string_util.h"
+#include "chrome/browser/background_contents_service.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/chrome_blob_storage_context.h"
+#include "chrome/browser/download/download_manager.h"
+#include "chrome/browser/extensions/extension_message_service.h"
+#include "chrome/browser/extensions/extension_process_manager.h"
+#include "chrome/browser/file_system/browser_file_system_helper.h"
+#include "chrome/browser/in_process_webkit/webkit_context.h"
+#include "chrome/browser/net/chrome_url_request_context.h"
+#include "chrome/browser/notifications/desktop_notification_service.h"
+#include "chrome/browser/ssl/ssl_host_state.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/ui/find_bar/find_bar_state.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/json_pref_store.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/render_messages.h"
+#include "grit/browser_resources.h"
+#include "grit/locale_settings.h"
+#include "net/base/transport_security_state.h"
+#include "webkit/database/database_tracker.h"
+#if defined(TOOLKIT_USES_GTK)
+#include "chrome/browser/gtk/gtk_theme_provider.h"
+#endif
+
+#if defined(OS_WIN)
+#include "chrome/browser/password_manager/password_store_win.h"
+#elif defined(OS_MACOSX)
+#include "chrome/browser/keychain_mac.h"
+#include "chrome/browser/password_manager/password_store_mac.h"
+#elif defined(OS_POSIX) && !defined(OS_CHROMEOS)
+#include "chrome/browser/password_manager/native_backend_gnome_x.h"
+#include "chrome/browser/password_manager/native_backend_kwallet_x.h"
+#include "chrome/browser/password_manager/password_store_x.h"
+#endif
+
+using base::Time;
+using base::TimeDelta;
+
+// A pointer to the request context for the default profile. See comments on
+// Profile::GetDefaultRequestContext.
+URLRequestContextGetter* Profile::default_request_context_;
+
+namespace {
+
+// TODO(pathorn): Duplicated in profile_impl.cc
+void CleanupRequestContext(ChromeURLRequestContextGetter* context) {
+ if (context)
+ context->CleanupOnUIThread();
+}
+
+} // namespace
+
+Profile::Profile()
+ : restored_last_session_(false),
+ accessibility_pause_level_(0) {
+}
+
+// static
+const ProfileId Profile::InvalidProfileId = static_cast<ProfileId>(0);
+
+// static
+void Profile::RegisterUserPrefs(PrefService* prefs) {
+ prefs->RegisterBooleanPref(prefs::kSearchSuggestEnabled, true);
+ prefs->RegisterBooleanPref(prefs::kSessionExitedCleanly, true);
+ prefs->RegisterBooleanPref(prefs::kSafeBrowsingEnabled, true);
+ prefs->RegisterBooleanPref(prefs::kSafeBrowsingReportingEnabled, false);
+ // TODO(estade): IDS_SPELLCHECK_DICTIONARY should be an ASCII string.
+ prefs->RegisterLocalizedStringPref(prefs::kSpellCheckDictionary,
+ IDS_SPELLCHECK_DICTIONARY);
+ prefs->RegisterBooleanPref(prefs::kEnableSpellCheck, true);
+ prefs->RegisterBooleanPref(prefs::kEnableAutoSpellCorrect, true);
+#if defined(TOOLKIT_USES_GTK)
+ prefs->RegisterBooleanPref(prefs::kUsesSystemTheme,
+ GtkThemeProvider::DefaultUsesSystemTheme());
+#endif
+ prefs->RegisterFilePathPref(prefs::kCurrentThemePackFilename, FilePath());
+ prefs->RegisterStringPref(prefs::kCurrentThemeID,
+ BrowserThemeProvider::kDefaultThemeID);
+ prefs->RegisterDictionaryPref(prefs::kCurrentThemeImages);
+ prefs->RegisterDictionaryPref(prefs::kCurrentThemeColors);
+ prefs->RegisterDictionaryPref(prefs::kCurrentThemeTints);
+ prefs->RegisterDictionaryPref(prefs::kCurrentThemeDisplayProperties);
+ prefs->RegisterBooleanPref(prefs::kDisableExtensions, false);
+ prefs->RegisterStringPref(prefs::kSelectFileLastDirectory, "");
+#if defined(OS_CHROMEOS)
+ // TODO(dilmah): For OS_CHROMEOS we maintain kApplicationLocale in both
+ // local state and user's profile. For other platforms we maintain
+ // kApplicationLocale only in local state.
+ // In the future we may want to maintain kApplicationLocale
+ // in user's profile for other platforms as well.
+ prefs->RegisterStringPref(prefs::kApplicationLocale, "");
+ prefs->RegisterStringPref(prefs::kApplicationLocaleBackup, "");
+#endif
+}
+
+// static
+URLRequestContextGetter* Profile::GetDefaultRequestContext() {
+ return default_request_context_;
+}
+
+bool Profile::IsSyncAccessible() {
+ ProfileSyncService* syncService = GetProfileSyncService();
+ return syncService && !syncService->IsManaged();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// OffTheRecordProfileImpl is a profile subclass that wraps an existing profile
+// to make it suitable for the off the record mode.
+//
+////////////////////////////////////////////////////////////////////////////////
+class OffTheRecordProfileImpl : public Profile,
+ public BrowserList::Observer {
+ public:
+ explicit OffTheRecordProfileImpl(Profile* real_profile)
+ : profile_(real_profile),
+ start_time_(Time::Now()) {
+ request_context_ = ChromeURLRequestContextGetter::CreateOffTheRecord(this);
+ extension_process_manager_.reset(ExtensionProcessManager::Create(this));
+
+ BrowserList::AddObserver(this);
+
+ background_contents_service_.reset(
+ new BackgroundContentsService(this, CommandLine::ForCurrentProcess()));
+ }
+
+ virtual ~OffTheRecordProfileImpl() {
+ NotificationService::current()->Notify(NotificationType::PROFILE_DESTROYED,
+ Source<Profile>(this),
+ NotificationService::NoDetails());
+ CleanupRequestContext(request_context_);
+ CleanupRequestContext(extensions_request_context_);
+
+ // Clean up all DB files/directories
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(
+ db_tracker_.get(),
+ &webkit_database::DatabaseTracker::DeleteIncognitoDBDirectory));
+
+ BrowserList::RemoveObserver(this);
+ }
+
+ virtual ProfileId GetRuntimeId() {
+ return reinterpret_cast<ProfileId>(this);
+ }
+
+ virtual FilePath GetPath() { return profile_->GetPath(); }
+
+ virtual bool IsOffTheRecord() {
+ return true;
+ }
+
+ virtual Profile* GetOffTheRecordProfile() {
+ return this;
+ }
+
+ virtual void DestroyOffTheRecordProfile() {
+ // Suicide is bad!
+ NOTREACHED();
+ }
+
+ virtual bool HasOffTheRecordProfile() {
+ return true;
+ }
+
+ virtual Profile* GetOriginalProfile() {
+ return profile_;
+ }
+
+ virtual ChromeAppCacheService* GetAppCacheService() {
+ if (!appcache_service_) {
+ appcache_service_ = new ChromeAppCacheService;
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(appcache_service_.get(),
+ &ChromeAppCacheService::InitializeOnIOThread,
+ GetPath(), IsOffTheRecord(),
+ make_scoped_refptr(GetHostContentSettingsMap())));
+ }
+ return appcache_service_;
+ }
+
+ virtual webkit_database::DatabaseTracker* GetDatabaseTracker() {
+ if (!db_tracker_) {
+ db_tracker_ = new webkit_database::DatabaseTracker(
+ GetPath(), IsOffTheRecord());
+ }
+ return db_tracker_;
+ }
+
+ virtual VisitedLinkMaster* GetVisitedLinkMaster() {
+ // We don't provide access to the VisitedLinkMaster when we're OffTheRecord
+ // because we don't want to leak the sites that the user has visited before.
+ return NULL;
+ }
+
+ virtual ExtensionService* GetExtensionService() {
+ return GetOriginalProfile()->GetExtensionService();
+ }
+
+ virtual BackgroundContentsService* GetBackgroundContentsService() const {
+ return background_contents_service_.get();
+ }
+
+ virtual StatusTray* GetStatusTray() {
+ return GetOriginalProfile()->GetStatusTray();
+ }
+
+ virtual UserScriptMaster* GetUserScriptMaster() {
+ return GetOriginalProfile()->GetUserScriptMaster();
+ }
+
+ virtual ExtensionDevToolsManager* GetExtensionDevToolsManager() {
+ // TODO(mpcomplete): figure out whether we should return the original
+ // profile's version.
+ return NULL;
+ }
+
+ virtual ExtensionProcessManager* GetExtensionProcessManager() {
+ return extension_process_manager_.get();
+ }
+
+ virtual ExtensionMessageService* GetExtensionMessageService() {
+ return GetOriginalProfile()->GetExtensionMessageService();
+ }
+
+ virtual ExtensionEventRouter* GetExtensionEventRouter() {
+ return GetOriginalProfile()->GetExtensionEventRouter();
+ }
+
+ virtual SSLHostState* GetSSLHostState() {
+ if (!ssl_host_state_.get())
+ ssl_host_state_.reset(new SSLHostState());
+
+ DCHECK(ssl_host_state_->CalledOnValidThread());
+ return ssl_host_state_.get();
+ }
+
+ virtual net::TransportSecurityState* GetTransportSecurityState() {
+ if (!transport_security_state_.get())
+ transport_security_state_ = new net::TransportSecurityState();
+
+ return transport_security_state_.get();
+ }
+
+ virtual HistoryService* GetHistoryService(ServiceAccessType sat) {
+ if (sat == EXPLICIT_ACCESS)
+ return profile_->GetHistoryService(sat);
+
+ NOTREACHED() << "This profile is OffTheRecord";
+ return NULL;
+ }
+
+ virtual HistoryService* GetHistoryServiceWithoutCreating() {
+ return profile_->GetHistoryServiceWithoutCreating();
+ }
+
+ virtual FaviconService* GetFaviconService(ServiceAccessType sat) {
+ if (sat == EXPLICIT_ACCESS)
+ return profile_->GetFaviconService(sat);
+
+ NOTREACHED() << "This profile is OffTheRecord";
+ return NULL;
+ }
+
+ virtual AutocompleteClassifier* GetAutocompleteClassifier() {
+ return profile_->GetAutocompleteClassifier();
+ }
+
+ virtual WebDataService* GetWebDataService(ServiceAccessType sat) {
+ if (sat == EXPLICIT_ACCESS)
+ return profile_->GetWebDataService(sat);
+
+ NOTREACHED() << "This profile is OffTheRecord";
+ return NULL;
+ }
+
+ virtual WebDataService* GetWebDataServiceWithoutCreating() {
+ return profile_->GetWebDataServiceWithoutCreating();
+ }
+
+ virtual PasswordStore* GetPasswordStore(ServiceAccessType sat) {
+ if (sat == EXPLICIT_ACCESS)
+ return profile_->GetPasswordStore(sat);
+
+ NOTREACHED() << "This profile is OffTheRecord";
+ return NULL;
+ }
+
+ virtual PrefService* GetPrefs() {
+ return profile_->GetPrefs();
+ }
+
+ virtual TemplateURLModel* GetTemplateURLModel() {
+ return profile_->GetTemplateURLModel();
+ }
+
+ virtual TemplateURLFetcher* GetTemplateURLFetcher() {
+ return profile_->GetTemplateURLFetcher();
+ }
+
+ virtual DownloadManager* GetDownloadManager() {
+ if (!download_manager_.get()) {
+ scoped_refptr<DownloadManager> dlm(
+ new DownloadManager(g_browser_process->download_status_updater()));
+ dlm->Init(this);
+ download_manager_.swap(dlm);
+ }
+ return download_manager_.get();
+ }
+
+ virtual bool HasCreatedDownloadManager() const {
+ return (download_manager_.get() != NULL);
+ }
+
+ virtual PersonalDataManager* GetPersonalDataManager() {
+ return NULL;
+ }
+
+ virtual fileapi::SandboxedFileSystemContext* GetFileSystemContext() {
+ if (!file_system_context_)
+ file_system_context_ = CreateFileSystemContext(
+ GetPath(), IsOffTheRecord());
+ DCHECK(file_system_context_.get());
+ return file_system_context_.get();
+ }
+
+ virtual void InitThemes() {
+ profile_->InitThemes();
+ }
+
+ virtual void SetTheme(const Extension* extension) {
+ profile_->SetTheme(extension);
+ }
+
+ virtual void SetNativeTheme() {
+ profile_->SetNativeTheme();
+ }
+
+ virtual void ClearTheme() {
+ profile_->ClearTheme();
+ }
+
+ virtual const Extension* GetTheme() {
+ return profile_->GetTheme();
+ }
+
+ virtual BrowserThemeProvider* GetThemeProvider() {
+ return profile_->GetThemeProvider();
+ }
+
+ virtual URLRequestContextGetter* GetRequestContext() {
+ return request_context_;
+ }
+
+ virtual URLRequestContextGetter* GetRequestContextForMedia() {
+ // In OTR mode, media request context is the same as the original one.
+ return request_context_;
+ }
+
+ URLRequestContextGetter* GetRequestContextForExtensions() {
+ if (!extensions_request_context_) {
+ extensions_request_context_ =
+ ChromeURLRequestContextGetter::CreateOffTheRecordForExtensions(this);
+ }
+
+ return extensions_request_context_;
+ }
+
+ virtual net::SSLConfigService* GetSSLConfigService() {
+ return profile_->GetSSLConfigService();
+ }
+
+ virtual HostContentSettingsMap* GetHostContentSettingsMap() {
+ // Retrieve the host content settings map of the parent profile in order to
+ // ensure the preferences have been migrated.
+ profile_->GetHostContentSettingsMap();
+ if (!host_content_settings_map_.get())
+ host_content_settings_map_ = new HostContentSettingsMap(this);
+ return host_content_settings_map_.get();
+ }
+
+ virtual HostZoomMap* GetHostZoomMap() {
+ if (!host_zoom_map_)
+ host_zoom_map_ = new HostZoomMap(this);
+ return host_zoom_map_.get();
+ }
+
+ virtual GeolocationContentSettingsMap* GetGeolocationContentSettingsMap() {
+ return profile_->GetGeolocationContentSettingsMap();
+ }
+
+ virtual GeolocationPermissionContext* GetGeolocationPermissionContext() {
+ return profile_->GetGeolocationPermissionContext();
+ }
+
+ virtual UserStyleSheetWatcher* GetUserStyleSheetWatcher() {
+ return profile_->GetUserStyleSheetWatcher();
+ }
+
+ virtual FindBarState* GetFindBarState() {
+ if (!find_bar_state_.get())
+ find_bar_state_.reset(new FindBarState());
+ return find_bar_state_.get();
+ }
+
+ virtual SessionService* GetSessionService() {
+ // Don't save any sessions when off the record.
+ return NULL;
+ }
+
+ virtual void ShutdownSessionService() {
+ // We don't allow a session service, nothing to do.
+ }
+
+ virtual bool HasSessionService() const {
+ // We never have a session service.
+ return false;
+ }
+
+ virtual bool HasProfileSyncService() const {
+ // We never have a profile sync service.
+ return false;
+ }
+
+ virtual bool DidLastSessionExitCleanly() {
+ return profile_->DidLastSessionExitCleanly();
+ }
+
+ virtual BookmarkModel* GetBookmarkModel() {
+ return profile_->GetBookmarkModel();
+ }
+
+ virtual DesktopNotificationService* GetDesktopNotificationService() {
+ if (!desktop_notification_service_.get()) {
+ desktop_notification_service_.reset(new DesktopNotificationService(
+ this, g_browser_process->notification_ui_manager()));
+ }
+ return desktop_notification_service_.get();
+ }
+
+ virtual TokenService* GetTokenService() {
+ return NULL;
+ }
+
+ virtual ProfileSyncService* GetProfileSyncService() {
+ return NULL;
+ }
+
+ virtual ProfileSyncService* GetProfileSyncService(
+ const std::string& cros_user) {
+ return NULL;
+ }
+
+ virtual BrowserSignin* GetBrowserSignin() {
+ return profile_->GetBrowserSignin();
+ }
+
+ virtual CloudPrintProxyService* GetCloudPrintProxyService() {
+ return NULL;
+ }
+
+ virtual bool IsSameProfile(Profile* profile) {
+ return (profile == this) || (profile == profile_);
+ }
+
+ virtual Time GetStartTime() const {
+ return start_time_;
+ }
+
+ virtual TabRestoreService* GetTabRestoreService() {
+ return NULL;
+ }
+
+ virtual void ResetTabRestoreService() {
+ }
+
+ virtual SpellCheckHost* GetSpellCheckHost() {
+ return profile_->GetSpellCheckHost();
+ }
+
+ virtual void ReinitializeSpellCheckHost(bool force) {
+ profile_->ReinitializeSpellCheckHost(force);
+ }
+
+ virtual WebKitContext* GetWebKitContext() {
+ if (!webkit_context_.get())
+ webkit_context_ = new WebKitContext(this, false);
+ DCHECK(webkit_context_.get());
+ return webkit_context_.get();
+ }
+
+ virtual history::TopSites* GetTopSitesWithoutCreating() {
+ return NULL;
+ }
+
+ virtual history::TopSites* GetTopSites() {
+ return NULL;
+ }
+
+ virtual void MarkAsCleanShutdown() {
+ }
+
+ virtual void InitExtensions() {
+ NOTREACHED();
+ }
+
+ virtual void InitWebResources() {
+ NOTREACHED();
+ }
+
+ virtual NTPResourceCache* GetNTPResourceCache() {
+ // Just return the real profile resource cache.
+ return profile_->GetNTPResourceCache();
+ }
+
+ virtual FilePath last_selected_directory() {
+ const FilePath& directory = last_selected_directory_;
+ if (directory.empty()) {
+ return profile_->last_selected_directory();
+ }
+ return directory;
+ }
+
+ virtual void set_last_selected_directory(const FilePath& path) {
+ last_selected_directory_ = path;
+ }
+
+#if defined(OS_CHROMEOS)
+ virtual chromeos::ProxyConfigServiceImpl*
+ GetChromeOSProxyConfigServiceImpl() {
+ return profile_->GetChromeOSProxyConfigServiceImpl();
+ }
+
+ virtual void SetupChromeOSEnterpriseExtensionObserver() {
+ profile_->SetupChromeOSEnterpriseExtensionObserver();
+ }
+#endif // defined(OS_CHROMEOS)
+
+ virtual void ExitedOffTheRecordMode() {
+ // DownloadManager is lazily created, so check before accessing it.
+ if (download_manager_.get()) {
+ // Drop our download manager so we forget about all the downloads made
+ // in off-the-record mode.
+ download_manager_->Shutdown();
+ download_manager_ = NULL;
+ }
+ }
+
+ virtual void OnBrowserAdded(const Browser* browser) {
+ }
+
+ virtual void OnBrowserRemoved(const Browser* browser) {
+ if (BrowserList::GetBrowserCount(this) == 0)
+ ExitedOffTheRecordMode();
+ }
+
+ virtual ChromeBlobStorageContext* GetBlobStorageContext() {
+ if (!blob_storage_context_) {
+ blob_storage_context_ = new ChromeBlobStorageContext();
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(
+ blob_storage_context_.get(),
+ &ChromeBlobStorageContext::InitializeOnIOThread));
+ }
+ return blob_storage_context_;
+ }
+
+ virtual ExtensionInfoMap* GetExtensionInfoMap() {
+ return profile_->GetExtensionInfoMap();
+ }
+
+ virtual policy::ProfilePolicyContext* GetPolicyContext() {
+ return NULL;
+ }
+
+ virtual PromoCounter* GetInstantPromoCounter() {
+ return NULL;
+ }
+
+ virtual PrefProxyConfigTracker* GetProxyConfigTracker() {
+ return profile_->GetProxyConfigTracker();
+ }
+
+ virtual PrerenderManager* GetPrerenderManager() {
+ // We do not allow prerendering in OTR profiles at this point.
+ // TODO(tburkard): Figure out if we want to support this, and how, at some
+ // point in the future.
+ return NULL;
+ }
+
+ private:
+ NotificationRegistrar registrar_;
+
+ // The real underlying profile.
+ Profile* profile_;
+
+ scoped_ptr<ExtensionProcessManager> extension_process_manager_;
+
+ // The context to use for requests made from this OTR session.
+ scoped_refptr<ChromeURLRequestContextGetter> request_context_;
+
+ // The context to use for requests made by an extension while in OTR mode.
+ scoped_refptr<ChromeURLRequestContextGetter> extensions_request_context_;
+
+ // The download manager that only stores downloaded items in memory.
+ scoped_refptr<DownloadManager> download_manager_;
+
+ // Use a separate desktop notification service for OTR.
+ scoped_ptr<DesktopNotificationService> desktop_notification_service_;
+
+ // We use a non-writable content settings map for OTR.
+ scoped_refptr<HostContentSettingsMap> host_content_settings_map_;
+
+ // Use a separate zoom map for OTR.
+ scoped_refptr<HostZoomMap> host_zoom_map_;
+
+ // Use a special WebKit context for OTR browsing.
+ scoped_refptr<WebKitContext> webkit_context_;
+
+ // We don't want SSLHostState from the OTR profile to leak back to the main
+ // profile because then the main profile would learn some of the host names
+ // the user visited while OTR.
+ scoped_ptr<SSLHostState> ssl_host_state_;
+
+ // Use a separate FindBarState so search terms do not leak back to the main
+ // profile.
+ scoped_ptr<FindBarState> find_bar_state_;
+
+ // The TransportSecurityState that only stores enabled sites in memory.
+ scoped_refptr<net::TransportSecurityState>
+ transport_security_state_;
+
+ // Time we were started.
+ Time start_time_;
+
+ scoped_refptr<ChromeAppCacheService> appcache_service_;
+
+ // The main database tracker for this profile.
+ // Should be used only on the file thread.
+ scoped_refptr<webkit_database::DatabaseTracker> db_tracker_;
+
+ FilePath last_selected_directory_;
+
+ // Tracks all BackgroundContents running under this profile.
+ scoped_ptr<BackgroundContentsService> background_contents_service_;
+
+ scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;
+
+ // The file_system context for this profile.
+ scoped_refptr<fileapi::SandboxedFileSystemContext> file_system_context_;
+
+ DISALLOW_COPY_AND_ASSIGN(OffTheRecordProfileImpl);
+};
+
+Profile* Profile::CreateOffTheRecordProfile() {
+ return new OffTheRecordProfileImpl(this);
+}
diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h
new file mode 100644
index 0000000..9df977c
--- /dev/null
+++ b/chrome/browser/profiles/profile.h
@@ -0,0 +1,558 @@
+// 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.
+
+// This class gathers state related to a single user profile.
+
+#ifndef CHROME_BROWSER_PROFILES_PROFILE_H_
+#define CHROME_BROWSER_PROFILES_PROFILE_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace base {
+class Time;
+}
+
+#if defined(OS_CHROMEOS)
+namespace chromeos {
+class EnterpriseExtensionObserver;
+class ProxyConfigServiceImpl;
+}
+#endif
+
+namespace history {
+class TopSites;
+}
+
+namespace net {
+class TransportSecurityState;
+class SSLConfigService;
+}
+
+namespace policy {
+class ProfilePolicyContext;
+}
+
+namespace webkit_database {
+class DatabaseTracker;
+}
+
+namespace fileapi {
+class SandboxedFileSystemContext;
+}
+
+class AutocompleteClassifier;
+class BackgroundContentsService;
+class BookmarkModel;
+class BrowserSignin;
+class BrowserThemeProvider;
+class ChromeAppCacheService;
+class ChromeBlobStorageContext;
+class ChromeURLRequestContextGetter;
+class CloudPrintProxyService;
+class DesktopNotificationService;
+class DownloadManager;
+class Extension;
+class ExtensionDevToolsManager;
+class ExtensionEventRouter;
+class ExtensionInfoMap;
+class ExtensionMessageService;
+class ExtensionProcessManager;
+class ExtensionService;
+class FaviconService;
+class FilePath;
+class FindBarState;
+class GeolocationContentSettingsMap;
+class GeolocationPermissionContext;
+class HistoryService;
+class HostContentSettingsMap;
+class HostZoomMap;
+class NTPResourceCache;
+class NavigationController;
+class PasswordStore;
+class PersonalDataManager;
+class PinnedTabService;
+class PrefProxyConfigTracker;
+class PrefService;
+class PrerenderManager;
+class ProfileSyncFactory;
+class ProfileSyncService;
+class ProfileSyncService;
+class PromoCounter;
+class PromoCounter;
+class SQLitePersistentCookieStore;
+class SSLConfigServiceManager;
+class SSLHostState;
+class SessionService;
+class SpellCheckHost;
+class StatusTray;
+class TabRestoreService;
+class TemplateURLFetcher;
+class TemplateURLModel;
+class ThemeProvider;
+class TokenService;
+class TransportSecurityPersister;
+class URLRequestContextGetter;
+class UserScriptMaster;
+class UserStyleSheetWatcher;
+class VisitedLinkEventListener;
+class VisitedLinkMaster;
+class WebDataService;
+class WebKitContext;
+class WebResourceService;
+
+typedef intptr_t ProfileId;
+
+class Profile {
+ public:
+ // Profile services are accessed with the following parameter. This parameter
+ // defines what the caller plans to do with the service.
+ // The caller is responsible for not performing any operation that would
+ // result in persistent implicit records while using an OffTheRecord profile.
+ // This flag allows the profile to perform an additional check.
+ //
+ // It also gives us an opportunity to perform further checks in the future. We
+ // could, for example, return an history service that only allow some specific
+ // methods.
+ enum ServiceAccessType {
+ // The caller plans to perform a read or write that takes place as a result
+ // of the user input. Use this flag when the operation you are doing can be
+ // performed while off the record. (ex: creating a bookmark)
+ //
+ // Since EXPLICIT_ACCESS means "as a result of a user action", this request
+ // always succeeds.
+ EXPLICIT_ACCESS,
+
+ // The caller plans to call a method that will permanently change some data
+ // in the profile, as part of Chrome's implicit data logging. Use this flag
+ // when you are about to perform an operation which is incompatible with the
+ // off the record mode.
+ IMPLICIT_ACCESS
+ };
+
+ // Value that represents no profile Id.
+ static const ProfileId InvalidProfileId;
+
+ Profile();
+ virtual ~Profile() {}
+
+ // Profile prefs are registered as soon as the prefs are loaded for the first
+ // time.
+ static void RegisterUserPrefs(PrefService* prefs);
+
+ // Create a new profile given a path.
+ static Profile* CreateProfile(const FilePath& path);
+
+ // Returns the request context for the "default" profile. This may be called
+ // from any thread. This CAN return NULL if a first request context has not
+ // yet been created. If necessary, listen on the UI thread for
+ // NOTIFY_DEFAULT_REQUEST_CONTEXT_AVAILABLE.
+ static URLRequestContextGetter* GetDefaultRequestContext();
+
+ // Returns a unique Id that can be used to identify this profile at runtime.
+ // This Id is not persistent and will not survive a restart of the browser.
+ virtual ProfileId GetRuntimeId() = 0;
+
+ // Returns the path of the directory where this profile's data is stored.
+ virtual FilePath GetPath() = 0;
+
+ // Return whether this profile is off the record. Default is false.
+ virtual bool IsOffTheRecord() = 0;
+
+ // Return the off the record version of this profile. The returned pointer
+ // is owned by the receiving profile. If the receiving profile is off the
+ // record, the same profile is returned.
+ virtual Profile* GetOffTheRecordProfile() = 0;
+
+ // Destroys the off the record profile.
+ virtual void DestroyOffTheRecordProfile() = 0;
+
+ // True if an off the record profile exists.
+ virtual bool HasOffTheRecordProfile() = 0;
+
+ // Return the original "recording" profile. This method returns this if the
+ // profile is not off the record.
+ virtual Profile* GetOriginalProfile() = 0;
+
+ // Returns a pointer to the ChromeAppCacheService instance for this profile.
+ virtual ChromeAppCacheService* GetAppCacheService() = 0;
+
+ // Returns a pointer to the DatabaseTracker instance for this profile.
+ virtual webkit_database::DatabaseTracker* GetDatabaseTracker() = 0;
+
+ // Returns a pointer to the TopSites (thumbnail manager) instance
+ // for this profile.
+ virtual history::TopSites* GetTopSites() = 0;
+
+ // Variant of GetTopSites that doesn't force creation.
+ virtual history::TopSites* GetTopSitesWithoutCreating() = 0;
+
+ // Retrieves a pointer to the VisitedLinkMaster associated with this
+ // profile. The VisitedLinkMaster is lazily created the first time
+ // that this method is called.
+ virtual VisitedLinkMaster* GetVisitedLinkMaster() = 0;
+
+ // Retrieves a pointer to the ExtensionService associated with this
+ // profile. The ExtensionService is created at startup.
+ virtual ExtensionService* GetExtensionService() = 0;
+
+ // Retrieves a pointer to the UserScriptMaster associated with this
+ // profile. The UserScriptMaster is lazily created the first time
+ // that this method is called.
+ virtual UserScriptMaster* GetUserScriptMaster() = 0;
+
+ // Retrieves a pointer to the ExtensionDevToolsManager associated with this
+ // profile. The instance is created at startup.
+ virtual ExtensionDevToolsManager* GetExtensionDevToolsManager() = 0;
+
+ // Retrieves a pointer to the ExtensionProcessManager associated with this
+ // profile. The instance is created at startup.
+ virtual ExtensionProcessManager* GetExtensionProcessManager() = 0;
+
+ // Retrieves a pointer to the ExtensionMessageService associated with this
+ // profile. The instance is created at startup.
+ virtual ExtensionMessageService* GetExtensionMessageService() = 0;
+
+ // Accessor. The instance is created at startup.
+ virtual ExtensionEventRouter* GetExtensionEventRouter() = 0;
+
+ // Retrieves a pointer to the SSLHostState associated with this profile.
+ // The SSLHostState is lazily created the first time that this method is
+ // called.
+ virtual SSLHostState* GetSSLHostState() = 0;
+
+ // Retrieves a pointer to the TransportSecurityState associated with
+ // this profile. The TransportSecurityState is lazily created the
+ // first time that this method is called.
+ virtual net::TransportSecurityState*
+ GetTransportSecurityState() = 0;
+
+ // Retrieves a pointer to the FaviconService associated with this
+ // profile. The FaviconService is lazily created the first time
+ // that this method is called.
+ //
+ // Although FaviconService is refcounted, this will not addref, and callers
+ // do not need to do any reference counting as long as they keep the pointer
+ // only for the local scope (which they should do anyway since the browser
+ // process may decide to shut down).
+ //
+ // |access| defines what the caller plans to do with the service. See
+ // the ServiceAccessType definition above.
+ virtual FaviconService* GetFaviconService(ServiceAccessType access) = 0;
+
+ // Retrieves a pointer to the HistoryService associated with this
+ // profile. The HistoryService is lazily created the first time
+ // that this method is called.
+ //
+ // Although HistoryService is refcounted, this will not addref, and callers
+ // do not need to do any reference counting as long as they keep the pointer
+ // only for the local scope (which they should do anyway since the browser
+ // process may decide to shut down).
+ //
+ // |access| defines what the caller plans to do with the service. See
+ // the ServiceAccessType definition above.
+ virtual HistoryService* GetHistoryService(ServiceAccessType access) = 0;
+
+ // Similar to GetHistoryService(), but won't create the history service if it
+ // doesn't already exist.
+ virtual HistoryService* GetHistoryServiceWithoutCreating() = 0;
+
+ // Retrieves a pointer to the AutocompleteClassifier associated with this
+ // profile. The AutocompleteClassifier is lazily created the first time that
+ // this method is called.
+ virtual AutocompleteClassifier* GetAutocompleteClassifier() = 0;
+
+ // Returns the WebDataService for this profile. This is owned by
+ // the Profile. Callers that outlive the life of this profile need to be
+ // sure they refcount the returned value.
+ //
+ // |access| defines what the caller plans to do with the service. See
+ // the ServiceAccessType definition above.
+ virtual WebDataService* GetWebDataService(ServiceAccessType access) = 0;
+
+ // Similar to GetWebDataService(), but won't create the web data service if it
+ // doesn't already exist.
+ virtual WebDataService* GetWebDataServiceWithoutCreating() = 0;
+
+ // Returns the PasswordStore for this profile. This is owned by the Profile.
+ virtual PasswordStore* GetPasswordStore(ServiceAccessType access) = 0;
+
+ // Retrieves a pointer to the PrefService that manages the preferences
+ // for this user profile. The PrefService is lazily created the first
+ // time that this method is called.
+ virtual PrefService* GetPrefs() = 0;
+
+ // Returns the TemplateURLModel for this profile. This is owned by the
+ // the Profile.
+ virtual TemplateURLModel* GetTemplateURLModel() = 0;
+
+ // Returns the TemplateURLFetcher for this profile. This is owned by the
+ // profile.
+ virtual TemplateURLFetcher* GetTemplateURLFetcher() = 0;
+
+ // Returns the DownloadManager associated with this profile.
+ virtual DownloadManager* GetDownloadManager() = 0;
+ virtual bool HasCreatedDownloadManager() const = 0;
+
+ // Returns the PersonalDataManager associated with this profile.
+ virtual PersonalDataManager* GetPersonalDataManager() = 0;
+
+ // Returns the FileSystemContext associated to this profile. The context
+ // is lazily created the first time this method is called. This is owned
+ // by the profile.
+ virtual fileapi::SandboxedFileSystemContext* GetFileSystemContext() = 0;
+
+ // Returns the BrowserSignin object assigned to this profile.
+ virtual BrowserSignin* GetBrowserSignin() = 0;
+
+ // Init our themes system.
+ virtual void InitThemes() = 0;
+
+ // Set the theme to the specified extension.
+ virtual void SetTheme(const Extension* extension) = 0;
+
+ // Set the theme to the machine's native theme.
+ virtual void SetNativeTheme() = 0;
+
+ // Clear the theme and reset it to default.
+ virtual void ClearTheme() = 0;
+
+ // Gets the theme that was last set. Returns NULL if the theme is no longer
+ // installed, if there is no installed theme, or the theme was cleared.
+ virtual const Extension* GetTheme() = 0;
+
+ // Returns or creates the ThemeProvider associated with this profile
+ virtual BrowserThemeProvider* GetThemeProvider() = 0;
+
+ // Returns the request context information associated with this profile. Call
+ // this only on the UI thread, since it can send notifications that should
+ // happen on the UI thread.
+ virtual URLRequestContextGetter* GetRequestContext() = 0;
+
+ // Returns the request context for media resources asociated with this
+ // profile.
+ virtual URLRequestContextGetter* GetRequestContextForMedia() = 0;
+
+ // Returns the request context used for extension-related requests. This
+ // is only used for a separate cookie store currently.
+ virtual URLRequestContextGetter* GetRequestContextForExtensions() = 0;
+
+ // Called by the ExtensionService that lives in this profile. Gives the
+ // profile a chance to react to the load event before the EXTENSION_LOADED
+ // notification has fired. The purpose for handling this event first is to
+ // avoid race conditions by making sure URLRequestContexts learn about new
+ // extensions before anything else needs them to know.
+ virtual void RegisterExtensionWithRequestContexts(
+ const Extension* extension) {}
+
+ // Called by the ExtensionService that lives in this profile. Lets the
+ // profile clean up its RequestContexts once all the listeners to the
+ // EXTENSION_UNLOADED notification have finished running.
+ virtual void UnregisterExtensionWithRequestContexts(
+ const Extension* extension) {}
+
+ // Returns the SSLConfigService for this profile.
+ virtual net::SSLConfigService* GetSSLConfigService() = 0;
+
+ // Returns the Hostname <-> Content settings map for this profile.
+ virtual HostContentSettingsMap* GetHostContentSettingsMap() = 0;
+
+ // Returns the Hostname <-> Zoom Level map for this profile.
+ virtual HostZoomMap* GetHostZoomMap() = 0;
+
+ // Returns the geolocation settings map for this profile.
+ virtual GeolocationContentSettingsMap* GetGeolocationContentSettingsMap() = 0;
+
+ // Returns the geolocation permission context for this profile.
+ virtual GeolocationPermissionContext* GetGeolocationPermissionContext() = 0;
+
+ // Returns the user style sheet watcher.
+ virtual UserStyleSheetWatcher* GetUserStyleSheetWatcher() = 0;
+
+ // Returns the find bar state for this profile. The find bar state is lazily
+ // created the first time that this method is called.
+ virtual FindBarState* GetFindBarState() = 0;
+
+ // Returns the session service for this profile. This may return NULL. If
+ // this profile supports a session service (it isn't off the record), and
+ // the session service hasn't yet been created, this forces creation of
+ // the session service.
+ //
+ // This returns NULL in two situations: the profile is off the record, or the
+ // session service has been explicitly shutdown (browser is exiting). Callers
+ // should always check the return value for NULL.
+ virtual SessionService* GetSessionService() = 0;
+
+ // If this profile has a session service, it is shut down. To properly record
+ // the current state this forces creation of the session service, then shuts
+ // it down.
+ virtual void ShutdownSessionService() = 0;
+
+ // Returns true if this profile has a session service.
+ virtual bool HasSessionService() const = 0;
+
+ // Returns true if this profile has a profile sync service.
+ virtual bool HasProfileSyncService() const = 0;
+
+ // Returns true if the last time this profile was open it was exited cleanly.
+ virtual bool DidLastSessionExitCleanly() = 0;
+
+ // Returns the BookmarkModel, creating if not yet created.
+ virtual BookmarkModel* GetBookmarkModel() = 0;
+
+ // Returns the Gaia Token Service, creating if not yet created.
+ virtual TokenService* GetTokenService() = 0;
+
+ // Returns the ProfileSyncService, creating if not yet created.
+ virtual ProfileSyncService* GetProfileSyncService() = 0;
+
+ // Returns the ProfileSyncService, creating if not yet created, with
+ // the specified CrOS username.
+ virtual ProfileSyncService* GetProfileSyncService(
+ const std::string& cros_user) = 0;
+
+ // Returns the CloudPrintProxyService, creating if not yet created.
+ virtual CloudPrintProxyService* GetCloudPrintProxyService() = 0;
+
+ // Return whether 2 profiles are the same. 2 profiles are the same if they
+ // represent the same profile. This can happen if there is pointer equality
+ // or if one profile is the off the record version of another profile (or vice
+ // versa).
+ virtual bool IsSameProfile(Profile* profile) = 0;
+
+ // Returns the time the profile was started. This is not the time the profile
+ // was created, rather it is the time the user started chrome and logged into
+ // this profile. For the single profile case, this corresponds to the time
+ // the user started chrome.
+ virtual base::Time GetStartTime() const = 0;
+
+ // Returns the TabRestoreService. This returns NULL when off the record.
+ virtual TabRestoreService* GetTabRestoreService() = 0;
+
+ virtual void ResetTabRestoreService() = 0;
+
+ // May return NULL.
+ virtual SpellCheckHost* GetSpellCheckHost() = 0;
+
+ // If |force| is false, and the spellchecker is already initialized (or is in
+ // the process of initializing), then do nothing. Otherwise clobber the
+ // current spellchecker and replace it with a new one.
+ virtual void ReinitializeSpellCheckHost(bool force) = 0;
+
+ // Returns the WebKitContext assigned to this profile.
+ virtual WebKitContext* GetWebKitContext() = 0;
+
+ // Returns the provider of desktop notifications for this profile.
+ virtual DesktopNotificationService* GetDesktopNotificationService() = 0;
+
+ // Returns the service that manages BackgroundContents for this profile.
+ virtual BackgroundContentsService* GetBackgroundContentsService() const = 0;
+
+ // Returns the StatusTray, which provides an API for displaying status icons
+ // in the system status tray. Returns NULL if status icons are not supported
+ // on this platform (or this is a unit test).
+ virtual StatusTray* GetStatusTray() = 0;
+
+ // Marks the profile as cleanly shutdown.
+ //
+ // NOTE: this is invoked internally on a normal shutdown, but is public so
+ // that it can be invoked when the user logs out/powers down (WM_ENDSESSION).
+ virtual void MarkAsCleanShutdown() = 0;
+
+ virtual void InitExtensions() = 0;
+
+ // Start up service that gathers data from a web resource feed.
+ virtual void InitWebResources() = 0;
+
+ // Returns the new tab page resource cache.
+ virtual NTPResourceCache* GetNTPResourceCache() = 0;
+
+ // Returns the last directory that was chosen for uploading or opening a file.
+ virtual FilePath last_selected_directory() = 0;
+ virtual void set_last_selected_directory(const FilePath& path) = 0;
+
+ // Returns a pointer to the ChromeBlobStorageContext instance for this
+ // profile.
+ virtual ChromeBlobStorageContext* GetBlobStorageContext() = 0;
+
+ // Returns the IO-thread-accessible profile data for this profile.
+ virtual ExtensionInfoMap* GetExtensionInfoMap() = 0;
+
+ // Returns the PromoCounter for Instant, or NULL if not applicable.
+ virtual PromoCounter* GetInstantPromoCounter() = 0;
+
+ // Gets the policy context associated with this profile.
+ virtual policy::ProfilePolicyContext* GetPolicyContext() = 0;
+
+#if defined(OS_CHROMEOS)
+ // Returns ChromeOS's ProxyConfigServiceImpl, creating if not yet created.
+ virtual chromeos::ProxyConfigServiceImpl*
+ GetChromeOSProxyConfigServiceImpl() = 0;
+
+ // Creates ChromeOS's EnterpriseExtensionListener.
+ virtual void SetupChromeOSEnterpriseExtensionObserver() = 0;
+
+#endif // defined(OS_CHROMEOS)
+
+ // Returns the helper object that provides the proxy configuration service
+ // access to the the proxy configuration possibly defined by preferences.
+ virtual PrefProxyConfigTracker* GetProxyConfigTracker() = 0;
+
+ // Returns the PrerenderManager used to prerender entire webpages for this
+ // profile.
+ virtual PrerenderManager* GetPrerenderManager() = 0;
+
+#ifdef UNIT_TEST
+ // Use with caution. GetDefaultRequestContext may be called on any thread!
+ static void set_default_request_context(URLRequestContextGetter* c) {
+ default_request_context_ = c;
+ }
+#endif
+
+ // Did the user restore the last session? This is set by SessionRestore.
+ void set_restored_last_session(bool restored_last_session) {
+ restored_last_session_ = restored_last_session;
+ }
+ bool restored_last_session() const {
+ return restored_last_session_;
+ }
+
+ // Stop sending accessibility events until ResumeAccessibilityEvents().
+ // Calls to Pause nest; no events will be sent until the number of
+ // Resume calls matches the number of Pause calls received.
+ void PauseAccessibilityEvents() {
+ accessibility_pause_level_++;
+ }
+
+ void ResumeAccessibilityEvents() {
+ DCHECK(accessibility_pause_level_ > 0);
+ accessibility_pause_level_--;
+ }
+
+ bool ShouldSendAccessibilityEvents() {
+ return 0 == accessibility_pause_level_;
+ }
+
+ // Checks whether sync is configurable by the user. Returns false if sync is
+ // disabled or controlled by configuration management.
+ bool IsSyncAccessible();
+
+ // Creates an OffTheRecordProfile which points to this Profile.
+ Profile* CreateOffTheRecordProfile();
+
+ protected:
+ static URLRequestContextGetter* default_request_context_;
+
+ private:
+ bool restored_last_session_;
+
+ // Accessibility events will only be propagated when the pause
+ // level is zero. PauseAccessibilityEvents and ResumeAccessibilityEvents
+ // increment and decrement the level, respectively, rather than set it to
+ // true or false, so that calls can be nested.
+ int accessibility_pause_level_;
+};
+
+#endif // CHROME_BROWSER_PROFILES_PROFILE_H_
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
new file mode 100644
index 0000000..2c610e1
--- /dev/null
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -0,0 +1,1372 @@
+// 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.
+
+#include "chrome/browser/profiles/profile_impl.h"
+
+#include "app/resource_bundle.h"
+#include "base/command_line.h"
+#include "base/environment.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/metrics/histogram.h"
+#include "base/path_service.h"
+#include "base/scoped_ptr.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
+#include "chrome/browser/about_flags.h"
+#include "chrome/browser/appcache/chrome_appcache_service.h"
+#include "chrome/browser/autocomplete/autocomplete_classifier.h"
+#include "chrome/browser/autofill/personal_data_manager.h"
+#include "chrome/browser/background_contents_service.h"
+#include "chrome/browser/background_mode_manager.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_signin.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/chrome_blob_storage_context.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
+#include "chrome/browser/dom_ui/ntp_resource_cache.h"
+#include "chrome/browser/download/download_manager.h"
+#include "chrome/browser/extensions/default_apps.h"
+#include "chrome/browser/extensions/extension_devtools_manager.h"
+#include "chrome/browser/extensions/extension_error_reporter.h"
+#include "chrome/browser/extensions/extension_info_map.h"
+#include "chrome/browser/extensions/extension_event_router.h"
+#include "chrome/browser/extensions/extension_message_service.h"
+#include "chrome/browser/extensions/extension_pref_store.h"
+#include "chrome/browser/extensions/extension_process_manager.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/user_script_master.h"
+#include "chrome/browser/favicon_service.h"
+#include "chrome/browser/file_system/browser_file_system_helper.h"
+#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
+#include "chrome/browser/geolocation/geolocation_permission_context.h"
+#include "chrome/browser/history/history.h"
+#include "chrome/browser/history/top_sites.h"
+#include "chrome/browser/host_zoom_map.h"
+#include "chrome/browser/instant/instant_controller.h"
+#include "chrome/browser/in_process_webkit/webkit_context.h"
+#include "chrome/browser/net/chrome_url_request_context.h"
+#include "chrome/browser/net/gaia/token_service.h"
+#include "chrome/browser/net/net_pref_observer.h"
+#include "chrome/browser/net/pref_proxy_config_service.h"
+#include "chrome/browser/net/ssl_config_service_manager.h"
+#include "chrome/browser/notifications/desktop_notification_service.h"
+#include "chrome/browser/password_manager/password_store_default.h"
+#include "chrome/browser/policy/configuration_policy_provider.h"
+#include "chrome/browser/policy/configuration_policy_pref_store.h"
+#include "chrome/browser/policy/profile_policy_context.h"
+#include "chrome/browser/prefs/browser_prefs.h"
+#include "chrome/browser/prefs/pref_value_store.h"
+#include "chrome/browser/prerender/prerender_manager.h"
+#include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/renderer_host/render_process_host.h"
+#include "chrome/browser/search_engines/template_url_fetcher.h"
+#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/sessions/session_service.h"
+#include "chrome/browser/sessions/tab_restore_service.h"
+#include "chrome/browser/spellcheck_host.h"
+#include "chrome/browser/ssl/ssl_host_state.h"
+#include "chrome/browser/status_icons/status_tray.h"
+#include "chrome/browser/sync/profile_sync_factory_impl.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/tabs/pinned_tab_service.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/transport_security_persister.h"
+#include "chrome/browser/ui/find_bar/find_bar_state.h"
+#include "chrome/browser/user_style_sheet_watcher.h"
+#include "chrome/browser/visitedlink/visitedlink_event_listener.h"
+#include "chrome/browser/visitedlink/visitedlink_master.h"
+#include "chrome/browser/web_resource/web_resource_service.h"
+#include "chrome/browser/webdata/web_data_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 "chrome/common/json_pref_store.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/render_messages.h"
+#include "grit/browser_resources.h"
+#include "grit/locale_settings.h"
+#include "net/base/transport_security_state.h"
+#include "webkit/database/database_tracker.h"
+
+#if defined(TOOLKIT_USES_GTK)
+#include "chrome/browser/gtk/gtk_theme_provider.h"
+#endif
+
+#if defined(OS_WIN)
+#include "chrome/browser/instant/promo_counter.h"
+#include "chrome/browser/password_manager/password_store_win.h"
+#include "chrome/installer/util/install_util.h"
+#elif defined(OS_MACOSX)
+#include "chrome/browser/keychain_mac.h"
+#include "chrome/browser/password_manager/password_store_mac.h"
+#elif defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/enterprise_extension_observer.h"
+#include "chrome/browser/chromeos/proxy_config_service_impl.h"
+#elif defined(OS_POSIX) && !defined(OS_CHROMEOS)
+#include "base/nix/xdg_util.h"
+#if defined(USE_GNOME_KEYRING)
+#include "chrome/browser/password_manager/native_backend_gnome_x.h"
+#endif
+#include "chrome/browser/password_manager/native_backend_kwallet_x.h"
+#include "chrome/browser/password_manager/password_store_x.h"
+#endif
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/preferences.h"
+#endif
+
+using base::Time;
+using base::TimeDelta;
+
+namespace {
+
+void CleanupRequestContext(ChromeURLRequestContextGetter* context) {
+ if (context)
+ context->CleanupOnUIThread();
+}
+
+// Delay, in milliseconds, before we explicitly create the SessionService.
+static const int kCreateSessionServiceDelayMS = 500;
+
+enum ContextType {
+ kNormalContext,
+ kMediaContext
+};
+
+// Gets the cache parameters from the command line. |type| is the type of
+// request context that we need, |cache_path| will be set to the user provided
+// path, or will not be touched if there is not an argument. |max_size| will
+// be the user provided value or zero by default.
+void GetCacheParameters(ContextType type, FilePath* cache_path,
+ int* max_size) {
+ DCHECK(cache_path);
+ DCHECK(max_size);
+
+ // Override the cache location if specified by the user.
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDiskCacheDir)) {
+ *cache_path = CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+ switches::kDiskCacheDir);
+ }
+
+ const char* arg = kNormalContext == type ? switches::kDiskCacheSize :
+ switches::kMediaCacheSize;
+ std::string value =
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII(arg);
+
+ // By default we let the cache determine the right size.
+ *max_size = 0;
+ if (!base::StringToInt(value, max_size)) {
+ *max_size = 0;
+ } else if (max_size < 0) {
+ *max_size = 0;
+ }
+}
+
+FilePath GetCachePath(const FilePath& base) {
+ return base.Append(chrome::kCacheDirname);
+}
+
+FilePath GetMediaCachePath(const FilePath& base) {
+ return base.Append(chrome::kMediaCacheDirname);
+}
+
+// Simple task to log the size of the current profile.
+class ProfileSizeTask : public Task {
+ public:
+ explicit ProfileSizeTask(const FilePath& path) : path_(path) {}
+ virtual ~ProfileSizeTask() {}
+
+ virtual void Run();
+ private:
+ FilePath path_;
+};
+
+void ProfileSizeTask::Run() {
+ int64 size = file_util::ComputeFilesSize(path_, FILE_PATH_LITERAL("*"));
+ int size_MB = static_cast<int>(size / (1024 * 1024));
+ UMA_HISTOGRAM_COUNTS_10000("Profile.TotalSize", size_MB);
+
+ size = file_util::ComputeFilesSize(path_, FILE_PATH_LITERAL("History"));
+ size_MB = static_cast<int>(size / (1024 * 1024));
+ UMA_HISTOGRAM_COUNTS_10000("Profile.HistorySize", size_MB);
+
+ size = file_util::ComputeFilesSize(path_, FILE_PATH_LITERAL("History*"));
+ size_MB = static_cast<int>(size / (1024 * 1024));
+ UMA_HISTOGRAM_COUNTS_10000("Profile.TotalHistorySize", size_MB);
+
+ size = file_util::ComputeFilesSize(path_, FILE_PATH_LITERAL("Cookies"));
+ size_MB = static_cast<int>(size / (1024 * 1024));
+ UMA_HISTOGRAM_COUNTS_10000("Profile.CookiesSize", size_MB);
+
+ size = file_util::ComputeFilesSize(path_, FILE_PATH_LITERAL("Bookmarks"));
+ size_MB = static_cast<int>(size / (1024 * 1024));
+ UMA_HISTOGRAM_COUNTS_10000("Profile.BookmarksSize", size_MB);
+
+ size = file_util::ComputeFilesSize(path_, FILE_PATH_LITERAL("Favicons"));
+ size_MB = static_cast<int>(size / (1024 * 1024));
+ UMA_HISTOGRAM_COUNTS_10000("Profile.FaviconsSize", size_MB);
+
+ size = file_util::ComputeFilesSize(path_, FILE_PATH_LITERAL("Top Sites"));
+ size_MB = static_cast<int>(size / (1024 * 1024));
+ UMA_HISTOGRAM_COUNTS_10000("Profile.TopSitesSize", size_MB);
+
+ size = file_util::ComputeFilesSize(path_, FILE_PATH_LITERAL("Visited Links"));
+ size_MB = static_cast<int>(size / (1024 * 1024));
+ UMA_HISTOGRAM_COUNTS_10000("Profile.VisitedLinksSize", size_MB);
+
+ size = file_util::ComputeFilesSize(path_, FILE_PATH_LITERAL("Web Data"));
+ size_MB = static_cast<int>(size / (1024 * 1024));
+ UMA_HISTOGRAM_COUNTS_10000("Profile.WebDataSize", size_MB);
+
+ size = file_util::ComputeFilesSize(path_, FILE_PATH_LITERAL("Extension*"));
+ size_MB = static_cast<int>(size / (1024 * 1024));
+ UMA_HISTOGRAM_COUNTS_10000("Profile.ExtensionSize", size_MB);
+}
+
+} // namespace
+
+// static
+Profile* Profile::CreateProfile(const FilePath& path) {
+ return new ProfileImpl(path);
+}
+
+// static
+void ProfileImpl::RegisterUserPrefs(PrefService* prefs) {
+ prefs->RegisterBooleanPref(prefs::kSavingBrowserHistoryDisabled, false);
+ DefaultApps::RegisterUserPrefs(prefs);
+}
+
+ProfileImpl::ProfileImpl(const FilePath& path)
+ : path_(path),
+ visited_link_event_listener_(new VisitedLinkEventListener()),
+ extension_devtools_manager_(NULL),
+ request_context_(NULL),
+ media_request_context_(NULL),
+ extensions_request_context_(NULL),
+ host_content_settings_map_(NULL),
+ host_zoom_map_(NULL),
+ history_service_created_(false),
+ favicon_service_created_(false),
+ created_web_data_service_(false),
+ created_password_store_(false),
+ created_download_manager_(false),
+ created_theme_provider_(false),
+ start_time_(Time::Now()),
+ spellcheck_host_(NULL),
+ spellcheck_host_ready_(false),
+#if defined(OS_WIN)
+ checked_instant_promo_(false),
+#endif
+ shutdown_session_service_(false) {
+ DCHECK(!path.empty()) << "Using an empty path will attempt to write " <<
+ "profile files to the root directory!";
+ create_session_service_timer_.Start(
+ TimeDelta::FromMilliseconds(kCreateSessionServiceDelayMS), this,
+ &ProfileImpl::EnsureSessionServiceCreated);
+
+ PrefService* prefs = GetPrefs();
+ pref_change_registrar_.Init(prefs);
+ pref_change_registrar_.Add(prefs::kSpellCheckDictionary, this);
+ pref_change_registrar_.Add(prefs::kEnableSpellCheck, this);
+ pref_change_registrar_.Add(prefs::kEnableAutoSpellCorrect, this);
+ pref_change_registrar_.Add(prefs::kClearSiteDataOnExit, this);
+
+ // Convert active labs into switches. Modifies the current command line.
+ about_flags::ConvertFlagsToSwitches(prefs, CommandLine::ForCurrentProcess());
+
+ // It would be nice to use PathService for fetching this directory, but
+ // the cache directory depends on the profile directory, which isn't available
+ // to PathService.
+ chrome::GetUserCacheDirectory(path_, &base_cache_path_);
+ file_util::CreateDirectory(base_cache_path_);
+
+ // Listen for theme installations from our original profile.
+ registrar_.Add(this, NotificationType::THEME_INSTALLED,
+ Source<Profile>(GetOriginalProfile()));
+
+#if !defined(OS_CHROMEOS)
+ // Listen for bookmark model load, to bootstrap the sync service.
+ // On CrOS sync service will be initialized after sign in.
+ registrar_.Add(this, NotificationType::BOOKMARK_MODEL_LOADED,
+ Source<Profile>(this));
+#endif
+
+ ssl_config_service_manager_.reset(
+ SSLConfigServiceManager::CreateDefaultManager(this));
+
+#if defined(OS_CHROMEOS)
+ chromeos_preferences_.reset(new chromeos::Preferences());
+ chromeos_preferences_->Init(prefs);
+#endif
+
+ pinned_tab_service_.reset(new PinnedTabService(this));
+
+ // Initialize the BackgroundModeManager - this has to be done here before
+ // InitExtensions() is called because it relies on receiving notifications
+ // when extensions are loaded. BackgroundModeManager is not needed under
+ // ChromeOS because Chrome is always running (no need for special keep-alive
+ // or launch-on-startup support).
+#if !defined(OS_CHROMEOS)
+ background_mode_manager_.reset(new BackgroundModeManager(this,
+ CommandLine::ForCurrentProcess()));
+#endif
+
+ background_contents_service_.reset(
+ new BackgroundContentsService(this, CommandLine::ForCurrentProcess()));
+
+ extension_info_map_ = new ExtensionInfoMap();
+
+ GetPolicyContext()->Initialize();
+
+ clear_local_state_on_exit_ = prefs->GetBoolean(prefs::kClearSiteDataOnExit);
+
+ // Log the profile size after a reasonable startup delay.
+ BrowserThread::PostDelayedTask(BrowserThread::FILE, FROM_HERE,
+ new ProfileSizeTask(path_), 112000);
+
+ InstantController::RecordMetrics(this);
+}
+
+void ProfileImpl::InitExtensions() {
+ if (user_script_master_ || extensions_service_)
+ return; // Already initialized.
+
+ const CommandLine* command_line = CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(
+ switches::kEnableExtensionTimelineApi)) {
+ extension_devtools_manager_ = new ExtensionDevToolsManager(this);
+ }
+
+ extension_process_manager_.reset(ExtensionProcessManager::Create(this));
+ extension_event_router_.reset(new ExtensionEventRouter(this));
+ extension_message_service_ = new ExtensionMessageService(this);
+
+ ExtensionErrorReporter::Init(true); // allow noisy errors.
+
+ FilePath script_dir; // Don't look for user scripts in any directory.
+ // TODO(aa): We should just remove this functionality,
+ // since it isn't used anymore.
+ user_script_master_ = new UserScriptMaster(script_dir, this);
+
+ extensions_service_ = new ExtensionService(
+ this,
+ CommandLine::ForCurrentProcess(),
+ GetPath().AppendASCII(ExtensionService::kInstallDirectoryName),
+ extension_prefs_.get(),
+ true);
+
+ RegisterComponentExtensions();
+ extensions_service_->Init();
+ InstallDefaultApps();
+
+ // Load any extensions specified with --load-extension.
+ if (command_line->HasSwitch(switches::kLoadExtension)) {
+ FilePath path = command_line->GetSwitchValuePath(switches::kLoadExtension);
+ extensions_service_->LoadExtension(path);
+ }
+}
+
+void ProfileImpl::RegisterComponentExtensions() {
+ // Register the component extensions.
+ typedef std::list<std::pair<std::string, int> > ComponentExtensionList;
+ ComponentExtensionList component_extensions;
+
+ // Bookmark manager.
+ component_extensions.push_back(
+ std::make_pair("bookmark_manager", IDR_BOOKMARKS_MANIFEST));
+
+#if defined(TOUCH_UI)
+ component_extensions.push_back(
+ std::make_pair("keyboard", IDR_KEYBOARD_MANIFEST));
+#endif
+
+ // Web Store.
+ component_extensions.push_back(
+ std::make_pair("web_store", IDR_WEBSTORE_MANIFEST));
+
+ for (ComponentExtensionList::iterator iter = component_extensions.begin();
+ iter != component_extensions.end(); ++iter) {
+ FilePath path;
+ if (PathService::Get(chrome::DIR_RESOURCES, &path)) {
+ path = path.AppendASCII(iter->first);
+ } else {
+ NOTREACHED();
+ }
+
+ std::string manifest =
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ iter->second).as_string();
+ extensions_service_->register_component_extension(
+ ExtensionService::ComponentExtensionInfo(manifest, path));
+ }
+}
+
+void ProfileImpl::InstallDefaultApps() {
+ // The web store only supports en-US at the moment, so we don't install
+ // default apps in other locales.
+ if (g_browser_process->GetApplicationLocale() != "en-US")
+ return;
+
+ ExtensionService* extensions_service = GetExtensionService();
+ const ExtensionIdSet* app_ids =
+ extensions_service->default_apps()->GetAppsToInstall();
+ if (!app_ids)
+ return;
+
+ for (ExtensionIdSet::const_iterator iter = app_ids->begin();
+ iter != app_ids->end(); ++iter) {
+ extensions_service->AddPendingExtensionFromDefaultAppList(*iter);
+ }
+}
+
+void ProfileImpl::InitWebResources() {
+ if (web_resource_service_)
+ return;
+
+ web_resource_service_ = new WebResourceService(this);
+ web_resource_service_->StartAfterDelay();
+}
+
+NTPResourceCache* ProfileImpl::GetNTPResourceCache() {
+ if (!ntp_resource_cache_.get())
+ ntp_resource_cache_.reset(new NTPResourceCache(this));
+ return ntp_resource_cache_.get();
+}
+
+FilePath ProfileImpl::last_selected_directory() {
+ return GetPrefs()->GetFilePath(prefs::kSelectFileLastDirectory);
+}
+
+void ProfileImpl::set_last_selected_directory(const FilePath& path) {
+ GetPrefs()->SetFilePath(prefs::kSelectFileLastDirectory, path);
+}
+
+ProfileImpl::~ProfileImpl() {
+ NotificationService::current()->Notify(
+ NotificationType::PROFILE_DESTROYED,
+ Source<Profile>(this),
+ NotificationService::NoDetails());
+
+ GetPolicyContext()->Shutdown();
+
+ tab_restore_service_ = NULL;
+
+ StopCreateSessionServiceTimer();
+ // TemplateURLModel schedules a task on the WebDataService from its
+ // destructor. Delete it first to ensure the task gets scheduled before we
+ // shut down the database.
+ template_url_model_.reset();
+
+ // DownloadManager is lazily created, so check before accessing it.
+ if (download_manager_.get()) {
+ // The download manager queries the history system and should be shutdown
+ // before the history is shutdown so it can properly cancel all requests.
+ download_manager_->Shutdown();
+ download_manager_ = NULL;
+ }
+
+ // The theme provider provides bitmaps to whoever wants them.
+ theme_provider_.reset();
+
+ // Remove pref observers
+ pref_change_registrar_.RemoveAll();
+
+ // Delete the NTP resource cache so we can unregister pref observers.
+ ntp_resource_cache_.reset();
+
+ // The sync service needs to be deleted before the services it calls.
+ sync_service_.reset();
+
+ // Both HistoryService and WebDataService maintain threads for background
+ // processing. Its possible each thread still has tasks on it that have
+ // increased the ref count of the service. In such a situation, when we
+ // decrement the refcount, it won't be 0, and the threads/databases aren't
+ // properly shut down. By explicitly calling Cleanup/Shutdown we ensure the
+ // databases are properly closed.
+ if (web_data_service_.get())
+ web_data_service_->Shutdown();
+
+ if (top_sites_.get())
+ top_sites_->Shutdown();
+
+ if (history_service_.get())
+ history_service_->Cleanup();
+
+ if (spellcheck_host_.get())
+ spellcheck_host_->UnsetObserver();
+
+ if (default_request_context_ == request_context_)
+ default_request_context_ = NULL;
+
+ CleanupRequestContext(request_context_);
+ CleanupRequestContext(media_request_context_);
+ CleanupRequestContext(extensions_request_context_);
+
+ // HistoryService may call into the BookmarkModel, as such we need to
+ // delete HistoryService before the BookmarkModel. The destructor for
+ // HistoryService will join with HistoryService's backend thread so that
+ // by the time the destructor has finished we're sure it will no longer call
+ // into the BookmarkModel.
+ history_service_ = NULL;
+ bookmark_bar_model_.reset();
+
+ // FaviconService depends on HistoryServce so make sure we delete
+ // HistoryService first.
+ favicon_service_ = NULL;
+
+ if (extension_message_service_)
+ extension_message_service_->DestroyingProfile();
+
+ if (extensions_service_)
+ extensions_service_->DestroyingProfile();
+
+ if (pref_proxy_config_tracker_)
+ pref_proxy_config_tracker_->DetachFromPrefService();
+
+ // This causes the Preferences file to be written to disk.
+ MarkAsCleanShutdown();
+}
+
+ProfileId ProfileImpl::GetRuntimeId() {
+ return reinterpret_cast<ProfileId>(this);
+}
+
+FilePath ProfileImpl::GetPath() {
+ return path_;
+}
+
+bool ProfileImpl::IsOffTheRecord() {
+ return false;
+}
+
+Profile* ProfileImpl::GetOffTheRecordProfile() {
+ if (!off_the_record_profile_.get()) {
+ scoped_ptr<Profile> p(CreateOffTheRecordProfile());
+ off_the_record_profile_.swap(p);
+
+ NotificationService::current()->Notify(
+ NotificationType::OTR_PROFILE_CREATED,
+ Source<Profile>(off_the_record_profile_.get()),
+ NotificationService::NoDetails());
+ }
+ return off_the_record_profile_.get();
+}
+
+void ProfileImpl::DestroyOffTheRecordProfile() {
+ off_the_record_profile_.reset();
+}
+
+bool ProfileImpl::HasOffTheRecordProfile() {
+ return off_the_record_profile_.get() != NULL;
+}
+
+Profile* ProfileImpl::GetOriginalProfile() {
+ return this;
+}
+
+ChromeAppCacheService* ProfileImpl::GetAppCacheService() {
+ if (!appcache_service_) {
+ appcache_service_ = new ChromeAppCacheService;
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(appcache_service_.get(),
+ &ChromeAppCacheService::InitializeOnIOThread,
+ GetPath(), IsOffTheRecord(),
+ make_scoped_refptr(GetHostContentSettingsMap())));
+ }
+ return appcache_service_;
+}
+
+webkit_database::DatabaseTracker* ProfileImpl::GetDatabaseTracker() {
+ if (!db_tracker_) {
+ db_tracker_ = new webkit_database::DatabaseTracker(
+ GetPath(), IsOffTheRecord());
+ }
+ return db_tracker_;
+}
+
+VisitedLinkMaster* ProfileImpl::GetVisitedLinkMaster() {
+ if (!visited_link_master_.get()) {
+ scoped_ptr<VisitedLinkMaster> visited_links(
+ new VisitedLinkMaster(visited_link_event_listener_.get(), this));
+ if (!visited_links->Init())
+ return NULL;
+ visited_link_master_.swap(visited_links);
+ }
+
+ return visited_link_master_.get();
+}
+
+ExtensionService* ProfileImpl::GetExtensionService() {
+ return extensions_service_.get();
+}
+
+BackgroundContentsService* ProfileImpl::GetBackgroundContentsService() const {
+ return background_contents_service_.get();
+}
+
+StatusTray* ProfileImpl::GetStatusTray() {
+ if (!status_tray_.get())
+ status_tray_.reset(StatusTray::Create());
+ return status_tray_.get();
+}
+
+UserScriptMaster* ProfileImpl::GetUserScriptMaster() {
+ return user_script_master_.get();
+}
+
+ExtensionDevToolsManager* ProfileImpl::GetExtensionDevToolsManager() {
+ return extension_devtools_manager_.get();
+}
+
+ExtensionProcessManager* ProfileImpl::GetExtensionProcessManager() {
+ return extension_process_manager_.get();
+}
+
+ExtensionMessageService* ProfileImpl::GetExtensionMessageService() {
+ return extension_message_service_.get();
+}
+
+ExtensionEventRouter* ProfileImpl::GetExtensionEventRouter() {
+ return extension_event_router_.get();
+}
+
+SSLHostState* ProfileImpl::GetSSLHostState() {
+ if (!ssl_host_state_.get())
+ ssl_host_state_.reset(new SSLHostState());
+
+ DCHECK(ssl_host_state_->CalledOnValidThread());
+ return ssl_host_state_.get();
+}
+
+net::TransportSecurityState*
+ ProfileImpl::GetTransportSecurityState() {
+ if (!transport_security_state_.get()) {
+ transport_security_state_ = new net::TransportSecurityState();
+ transport_security_persister_ =
+ new TransportSecurityPersister();
+ transport_security_persister_->Initialize(
+ transport_security_state_.get(), path_);
+ }
+
+ return transport_security_state_.get();
+}
+
+PrefService* ProfileImpl::GetPrefs() {
+ if (!prefs_.get()) {
+ ExtensionPrefStore* extension_pref_store = new ExtensionPrefStore;
+ prefs_.reset(PrefService::CreatePrefService(GetPrefFilePath(),
+ extension_pref_store,
+ GetOriginalProfile()));
+
+ // The Profile class and ProfileManager class may read some prefs so
+ // register known prefs as soon as possible.
+ Profile::RegisterUserPrefs(prefs_.get());
+ browser::RegisterUserPrefs(prefs_.get());
+
+ // The last session exited cleanly if there is no pref for
+ // kSessionExitedCleanly or the value for kSessionExitedCleanly is true.
+ last_session_exited_cleanly_ =
+ prefs_->GetBoolean(prefs::kSessionExitedCleanly);
+ // Mark the session as open.
+ prefs_->SetBoolean(prefs::kSessionExitedCleanly, false);
+ // Make sure we save to disk that the session has opened.
+ prefs_->ScheduleSavePersistentPrefs();
+
+ // Ensure that preferences set by extensions are restored in the profile
+ // as early as possible. The constructor takes care of that.
+ extension_prefs_.reset(new ExtensionPrefs(
+ prefs_.get(),
+ GetPath().AppendASCII(ExtensionService::kInstallDirectoryName),
+ extension_pref_store));
+
+ DCHECK(!net_pref_observer_.get());
+ net_pref_observer_.reset(new NetPrefObserver(prefs_.get()));
+ }
+
+ return prefs_.get();
+}
+
+FilePath ProfileImpl::GetPrefFilePath() {
+ FilePath pref_file_path = path_;
+ pref_file_path = pref_file_path.Append(chrome::kPreferencesFilename);
+ return pref_file_path;
+}
+
+URLRequestContextGetter* ProfileImpl::GetRequestContext() {
+ if (!request_context_) {
+ FilePath cookie_path = GetPath();
+ cookie_path = cookie_path.Append(chrome::kCookieFilename);
+ FilePath cache_path = base_cache_path_;
+ int max_size;
+ GetCacheParameters(kNormalContext, &cache_path, &max_size);
+
+ cache_path = GetCachePath(cache_path);
+ request_context_ = ChromeURLRequestContextGetter::CreateOriginal(
+ this, cookie_path, cache_path, max_size);
+
+ // The first request context is always a normal (non-OTR) request context.
+ // Even when Chromium is started in OTR mode, a normal profile is always
+ // created first.
+ if (!default_request_context_) {
+ default_request_context_ = request_context_;
+ request_context_->set_is_main(true);
+ // TODO(eroman): this isn't terribly useful anymore now that the
+ // URLRequestContext is constructed by the IO thread...
+ NotificationService::current()->Notify(
+ NotificationType::DEFAULT_REQUEST_CONTEXT_AVAILABLE,
+ NotificationService::AllSources(), NotificationService::NoDetails());
+ }
+ }
+
+ return request_context_;
+}
+
+URLRequestContextGetter* ProfileImpl::GetRequestContextForMedia() {
+ if (!media_request_context_) {
+ FilePath cache_path = base_cache_path_;
+ int max_size;
+ GetCacheParameters(kMediaContext, &cache_path, &max_size);
+
+ cache_path = GetMediaCachePath(cache_path);
+ media_request_context_ =
+ ChromeURLRequestContextGetter::CreateOriginalForMedia(
+ this, cache_path, max_size);
+ }
+
+ return media_request_context_;
+}
+
+FaviconService* ProfileImpl::GetFaviconService(ServiceAccessType sat) {
+ if (!favicon_service_created_) {
+ favicon_service_created_ = true;
+ scoped_refptr<FaviconService> service(new FaviconService(this));
+ favicon_service_.swap(service);
+ }
+ return favicon_service_.get();
+}
+
+URLRequestContextGetter* ProfileImpl::GetRequestContextForExtensions() {
+ if (!extensions_request_context_) {
+ FilePath cookie_path = GetPath();
+ cookie_path = cookie_path.Append(chrome::kExtensionsCookieFilename);
+
+ extensions_request_context_ =
+ ChromeURLRequestContextGetter::CreateOriginalForExtensions(
+ this, cookie_path);
+ }
+
+ return extensions_request_context_;
+}
+
+void ProfileImpl::RegisterExtensionWithRequestContexts(
+ const Extension* extension) {
+ // AddRef to ensure the data lives until the other thread gets it. Balanced in
+ // OnNewExtensions.
+ extension->AddRef();
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(extension_info_map_.get(),
+ &ExtensionInfoMap::AddExtension,
+ extension));
+}
+
+void ProfileImpl::UnregisterExtensionWithRequestContexts(
+ const Extension* extension) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(extension_info_map_.get(),
+ &ExtensionInfoMap::RemoveExtension,
+ extension->id()));
+}
+
+net::SSLConfigService* ProfileImpl::GetSSLConfigService() {
+ return ssl_config_service_manager_->Get();
+}
+
+HostContentSettingsMap* ProfileImpl::GetHostContentSettingsMap() {
+ if (!host_content_settings_map_.get())
+ host_content_settings_map_ = new HostContentSettingsMap(this);
+ return host_content_settings_map_.get();
+}
+
+HostZoomMap* ProfileImpl::GetHostZoomMap() {
+ if (!host_zoom_map_)
+ host_zoom_map_ = new HostZoomMap(this);
+ return host_zoom_map_.get();
+}
+
+GeolocationContentSettingsMap* ProfileImpl::GetGeolocationContentSettingsMap() {
+ if (!geolocation_content_settings_map_.get())
+ geolocation_content_settings_map_ = new GeolocationContentSettingsMap(this);
+ return geolocation_content_settings_map_.get();
+}
+
+GeolocationPermissionContext* ProfileImpl::GetGeolocationPermissionContext() {
+ if (!geolocation_permission_context_.get())
+ geolocation_permission_context_ = new GeolocationPermissionContext(this);
+ return geolocation_permission_context_.get();
+}
+
+UserStyleSheetWatcher* ProfileImpl::GetUserStyleSheetWatcher() {
+ if (!user_style_sheet_watcher_.get()) {
+ user_style_sheet_watcher_ = new UserStyleSheetWatcher(GetPath());
+ user_style_sheet_watcher_->Init();
+ }
+ return user_style_sheet_watcher_.get();
+}
+
+FindBarState* ProfileImpl::GetFindBarState() {
+ if (!find_bar_state_.get()) {
+ find_bar_state_.reset(new FindBarState());
+ }
+ return find_bar_state_.get();
+}
+
+HistoryService* ProfileImpl::GetHistoryService(ServiceAccessType sat) {
+ // If saving history is disabled, only allow explicit access.
+ if (GetPrefs()->GetBoolean(prefs::kSavingBrowserHistoryDisabled) &&
+ sat != EXPLICIT_ACCESS)
+ return NULL;
+
+ if (!history_service_created_) {
+ history_service_created_ = true;
+ scoped_refptr<HistoryService> history(new HistoryService(this));
+ if (!history->Init(GetPath(), GetBookmarkModel()))
+ return NULL;
+ history_service_.swap(history);
+
+ // Send out the notification that the history service was created.
+ NotificationService::current()->
+ Notify(NotificationType::HISTORY_CREATED, Source<Profile>(this),
+ Details<HistoryService>(history_service_.get()));
+ }
+ return history_service_.get();
+}
+
+HistoryService* ProfileImpl::GetHistoryServiceWithoutCreating() {
+ return history_service_.get();
+}
+
+TemplateURLModel* ProfileImpl::GetTemplateURLModel() {
+ if (!template_url_model_.get())
+ template_url_model_.reset(new TemplateURLModel(this));
+ return template_url_model_.get();
+}
+
+TemplateURLFetcher* ProfileImpl::GetTemplateURLFetcher() {
+ if (!template_url_fetcher_.get())
+ template_url_fetcher_.reset(new TemplateURLFetcher(this));
+ return template_url_fetcher_.get();
+}
+
+AutocompleteClassifier* ProfileImpl::GetAutocompleteClassifier() {
+ if (!autocomplete_classifier_.get())
+ autocomplete_classifier_.reset(new AutocompleteClassifier(this));
+ return autocomplete_classifier_.get();
+}
+
+WebDataService* ProfileImpl::GetWebDataService(ServiceAccessType sat) {
+ if (!created_web_data_service_)
+ CreateWebDataService();
+ return web_data_service_.get();
+}
+
+WebDataService* ProfileImpl::GetWebDataServiceWithoutCreating() {
+ return web_data_service_.get();
+}
+
+void ProfileImpl::CreateWebDataService() {
+ DCHECK(!created_web_data_service_ && web_data_service_.get() == NULL);
+ created_web_data_service_ = true;
+ scoped_refptr<WebDataService> wds(new WebDataService());
+ if (!wds->Init(GetPath()))
+ return;
+ web_data_service_.swap(wds);
+}
+
+PasswordStore* ProfileImpl::GetPasswordStore(ServiceAccessType sat) {
+ if (!created_password_store_)
+ CreatePasswordStore();
+ return password_store_.get();
+}
+
+void ProfileImpl::CreatePasswordStore() {
+ DCHECK(!created_password_store_ && password_store_.get() == NULL);
+ created_password_store_ = true;
+ scoped_refptr<PasswordStore> ps;
+ FilePath login_db_file_path = GetPath();
+ login_db_file_path = login_db_file_path.Append(chrome::kLoginDataFileName);
+ LoginDatabase* login_db = new LoginDatabase();
+ if (!login_db->Init(login_db_file_path)) {
+ LOG(ERROR) << "Could not initialize login database.";
+ delete login_db;
+ return;
+ }
+#if defined(OS_WIN)
+ ps = new PasswordStoreWin(login_db, this,
+ GetWebDataService(Profile::IMPLICIT_ACCESS));
+#elif defined(OS_MACOSX)
+ ps = new PasswordStoreMac(new MacKeychain(), login_db);
+#elif defined(OS_CHROMEOS)
+ // For now, we use PasswordStoreDefault. We might want to make a native
+ // backend for PasswordStoreX (see below) in the future though.
+ ps = new PasswordStoreDefault(login_db, this,
+ GetWebDataService(Profile::IMPLICIT_ACCESS));
+#elif defined(OS_POSIX)
+ // On POSIX systems, we try to use the "native" password management system of
+ // the desktop environment currently running, allowing GNOME Keyring in XFCE.
+ // (In all cases we fall back on the default store in case of failure.)
+ base::nix::DesktopEnvironment desktop_env;
+ std::string store_type =
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kPasswordStore);
+ if (store_type == "kwallet") {
+ desktop_env = base::nix::DESKTOP_ENVIRONMENT_KDE4;
+ } else if (store_type == "gnome") {
+ desktop_env = base::nix::DESKTOP_ENVIRONMENT_GNOME;
+ } else if (store_type == "detect") {
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+ desktop_env = base::nix::GetDesktopEnvironment(env.get());
+ VLOG(1) << "Password storage detected desktop environment: "
+ << base::nix::GetDesktopEnvironmentName(desktop_env);
+ } else {
+ // TODO(mdm): If the flag is not given, or has an unknown value, use the
+ // default store for now. Once we're confident in the other stores, we can
+ // default to detecting the desktop environment instead.
+ desktop_env = base::nix::DESKTOP_ENVIRONMENT_OTHER;
+ }
+
+ scoped_ptr<PasswordStoreX::NativeBackend> backend;
+ if (desktop_env == base::nix::DESKTOP_ENVIRONMENT_KDE4) {
+ // KDE3 didn't use DBus, which our KWallet store uses.
+ VLOG(1) << "Trying KWallet for password storage.";
+ backend.reset(new NativeBackendKWallet());
+ if (backend->Init())
+ VLOG(1) << "Using KWallet for password storage.";
+ else
+ backend.reset();
+ } else if (desktop_env == base::nix::DESKTOP_ENVIRONMENT_GNOME ||
+ desktop_env == base::nix::DESKTOP_ENVIRONMENT_XFCE) {
+#if defined(USE_GNOME_KEYRING)
+ VLOG(1) << "Trying GNOME keyring for password storage.";
+ backend.reset(new NativeBackendGnome());
+ if (backend->Init())
+ VLOG(1) << "Using GNOME keyring for password storage.";
+ else
+ backend.reset();
+#endif // defined(USE_GNOME_KEYRING)
+ }
+ // TODO(mdm): this can change to a WARNING when we detect by default.
+ if (!backend.get())
+ VLOG(1) << "Using default (unencrypted) store for password storage.";
+
+ ps = new PasswordStoreX(login_db, this,
+ GetWebDataService(Profile::IMPLICIT_ACCESS),
+ backend.release());
+#else
+ NOTIMPLEMENTED();
+#endif
+ if (!ps)
+ delete login_db;
+
+ if (!ps || !ps->Init()) {
+ NOTREACHED() << "Could not initialize password manager.";
+ return;
+ }
+ password_store_.swap(ps);
+}
+
+DownloadManager* ProfileImpl::GetDownloadManager() {
+ if (!created_download_manager_) {
+ scoped_refptr<DownloadManager> dlm(
+ new DownloadManager(g_browser_process->download_status_updater()));
+ dlm->Init(this);
+ created_download_manager_ = true;
+ download_manager_.swap(dlm);
+ }
+ return download_manager_.get();
+}
+
+bool ProfileImpl::HasCreatedDownloadManager() const {
+ return created_download_manager_;
+}
+
+PersonalDataManager* ProfileImpl::GetPersonalDataManager() {
+ if (!personal_data_manager_.get()) {
+ personal_data_manager_ = new PersonalDataManager();
+ personal_data_manager_->Init(this);
+ }
+ return personal_data_manager_.get();
+}
+
+fileapi::SandboxedFileSystemContext* ProfileImpl::GetFileSystemContext() {
+ if (!file_system_context_.get())
+ file_system_context_ = CreateFileSystemContext(
+ GetPath(), IsOffTheRecord());
+ DCHECK(file_system_context_.get());
+ return file_system_context_.get();
+}
+
+void ProfileImpl::InitThemes() {
+ if (!created_theme_provider_) {
+#if defined(TOOLKIT_USES_GTK)
+ theme_provider_.reset(new GtkThemeProvider);
+#else
+ theme_provider_.reset(new BrowserThemeProvider);
+#endif
+ theme_provider_->Init(this);
+ created_theme_provider_ = true;
+ }
+}
+
+void ProfileImpl::SetTheme(const Extension* extension) {
+ InitThemes();
+ theme_provider_.get()->SetTheme(extension);
+}
+
+void ProfileImpl::SetNativeTheme() {
+ InitThemes();
+ theme_provider_.get()->SetNativeTheme();
+}
+
+void ProfileImpl::ClearTheme() {
+ InitThemes();
+ theme_provider_.get()->UseDefaultTheme();
+}
+
+const Extension* ProfileImpl::GetTheme() {
+ InitThemes();
+
+ std::string id = theme_provider_.get()->GetThemeID();
+ if (id == BrowserThemeProvider::kDefaultThemeID)
+ return NULL;
+
+ return extensions_service_->GetExtensionById(id, false);
+}
+
+BrowserThemeProvider* ProfileImpl::GetThemeProvider() {
+ InitThemes();
+ return theme_provider_.get();
+}
+
+SessionService* ProfileImpl::GetSessionService() {
+ if (!session_service_.get() && !shutdown_session_service_) {
+ session_service_ = new SessionService(this);
+ session_service_->ResetFromCurrentBrowsers();
+ }
+ return session_service_.get();
+}
+
+void ProfileImpl::ShutdownSessionService() {
+ if (shutdown_session_service_)
+ return;
+
+ // We're about to exit, force creation of the session service if it hasn't
+ // been created yet. We do this to ensure session state matches the point in
+ // time the user exited.
+ GetSessionService();
+ shutdown_session_service_ = true;
+ session_service_ = NULL;
+}
+
+bool ProfileImpl::HasSessionService() const {
+ return (session_service_.get() != NULL);
+}
+
+bool ProfileImpl::HasProfileSyncService() const {
+ return (sync_service_.get() != NULL);
+}
+
+bool ProfileImpl::DidLastSessionExitCleanly() {
+ // last_session_exited_cleanly_ is set when the preferences are loaded. Force
+ // it to be set by asking for the prefs.
+ GetPrefs();
+ return last_session_exited_cleanly_;
+}
+
+BookmarkModel* ProfileImpl::GetBookmarkModel() {
+ if (!bookmark_bar_model_.get()) {
+ bookmark_bar_model_.reset(new BookmarkModel(this));
+ bookmark_bar_model_->Load();
+ }
+ return bookmark_bar_model_.get();
+}
+
+bool ProfileImpl::IsSameProfile(Profile* profile) {
+ if (profile == static_cast<Profile*>(this))
+ return true;
+ Profile* otr_profile = off_the_record_profile_.get();
+ return otr_profile && profile == otr_profile;
+}
+
+Time ProfileImpl::GetStartTime() const {
+ return start_time_;
+}
+
+TabRestoreService* ProfileImpl::GetTabRestoreService() {
+ if (!tab_restore_service_.get())
+ tab_restore_service_ = new TabRestoreService(this);
+ return tab_restore_service_.get();
+}
+
+history::TopSites* ProfileImpl::GetTopSites() {
+ if (!top_sites_.get()) {
+ top_sites_ = new history::TopSites(this);
+ top_sites_->Init(GetPath().Append(chrome::kTopSitesFilename));
+ }
+ return top_sites_;
+}
+
+history::TopSites* ProfileImpl::GetTopSitesWithoutCreating() {
+ return top_sites_;
+}
+
+void ProfileImpl::ResetTabRestoreService() {
+ tab_restore_service_ = NULL;
+}
+
+SpellCheckHost* ProfileImpl::GetSpellCheckHost() {
+ return spellcheck_host_ready_ ? spellcheck_host_.get() : NULL;
+}
+
+void ProfileImpl::ReinitializeSpellCheckHost(bool force) {
+ // If we are already loading the spellchecker, and this is just a hint to
+ // load the spellchecker, do nothing.
+ if (!force && spellcheck_host_.get())
+ return;
+
+ spellcheck_host_ready_ = false;
+
+ bool notify = false;
+ if (spellcheck_host_.get()) {
+ spellcheck_host_->UnsetObserver();
+ spellcheck_host_ = NULL;
+ notify = true;
+ }
+
+ PrefService* prefs = GetPrefs();
+ if (prefs->GetBoolean(prefs::kEnableSpellCheck)) {
+ // Retrieve the (perhaps updated recently) dictionary name from preferences.
+ spellcheck_host_ = new SpellCheckHost(
+ this,
+ prefs->GetString(prefs::kSpellCheckDictionary),
+ GetRequestContext());
+ spellcheck_host_->Initialize();
+ } else if (notify) {
+ // The spellchecker has been disabled.
+ SpellCheckHostInitialized();
+ }
+}
+
+void ProfileImpl::SpellCheckHostInitialized() {
+ spellcheck_host_ready_ = spellcheck_host_ &&
+ (spellcheck_host_->bdict_file() != base::kInvalidPlatformFileValue ||
+ spellcheck_host_->use_platform_spellchecker());
+ NotificationService::current()->Notify(
+ NotificationType::SPELLCHECK_HOST_REINITIALIZED,
+ Source<Profile>(this), NotificationService::NoDetails());
+}
+
+WebKitContext* ProfileImpl::GetWebKitContext() {
+ if (!webkit_context_.get())
+ webkit_context_ = new WebKitContext(this, clear_local_state_on_exit_);
+ DCHECK(webkit_context_.get());
+ return webkit_context_.get();
+}
+
+DesktopNotificationService* ProfileImpl::GetDesktopNotificationService() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!desktop_notification_service_.get()) {
+ desktop_notification_service_.reset(new DesktopNotificationService(
+ this, g_browser_process->notification_ui_manager()));
+ }
+ return desktop_notification_service_.get();
+}
+
+void ProfileImpl::MarkAsCleanShutdown() {
+ if (prefs_.get()) {
+ // The session cleanly exited, set kSessionExitedCleanly appropriately.
+ prefs_->SetBoolean(prefs::kSessionExitedCleanly, true);
+
+ // NOTE: If you change what thread this writes on, be sure and update
+ // ChromeFrame::EndSession().
+ prefs_->SavePersistentPrefs();
+ }
+}
+
+void ProfileImpl::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (NotificationType::PREF_CHANGED == type) {
+ std::string* pref_name_in = Details<std::string>(details).ptr();
+ PrefService* prefs = Source<PrefService>(source).ptr();
+ DCHECK(pref_name_in && prefs);
+ if (*pref_name_in == prefs::kSpellCheckDictionary ||
+ *pref_name_in == prefs::kEnableSpellCheck) {
+ ReinitializeSpellCheckHost(true);
+ } else if (*pref_name_in == prefs::kEnableAutoSpellCorrect) {
+ NotificationService::current()->Notify(
+ NotificationType::SPELLCHECK_AUTOSPELL_TOGGLED,
+ Source<Profile>(this), NotificationService::NoDetails());
+ } else if (*pref_name_in == prefs::kClearSiteDataOnExit) {
+ clear_local_state_on_exit_ =
+ prefs->GetBoolean(prefs::kClearSiteDataOnExit);
+ if (webkit_context_)
+ webkit_context_->set_clear_local_state_on_exit(
+ clear_local_state_on_exit_);
+ }
+ } else if (NotificationType::THEME_INSTALLED == type) {
+ DCHECK_EQ(Source<Profile>(source).ptr(), GetOriginalProfile());
+ const Extension* extension = Details<const Extension>(details).ptr();
+ SetTheme(extension);
+ } else if (NotificationType::BOOKMARK_MODEL_LOADED == type) {
+ GetProfileSyncService(); // Causes lazy-load if sync is enabled.
+ registrar_.Remove(this, NotificationType::BOOKMARK_MODEL_LOADED,
+ Source<Profile>(this));
+ }
+}
+
+void ProfileImpl::StopCreateSessionServiceTimer() {
+ create_session_service_timer_.Stop();
+}
+
+TokenService* ProfileImpl::GetTokenService() {
+ if (!token_service_.get()) {
+ token_service_.reset(new TokenService());
+ }
+ return token_service_.get();
+}
+
+ProfileSyncService* ProfileImpl::GetProfileSyncService() {
+#if defined(OS_CHROMEOS)
+ // If kLoginManager is specified, we shouldn't call this unless login has
+ // completed and specified cros_user. Guard with if (HasProfileSyncService())
+ // where this might legitimately get called before login has completed.
+ if (!sync_service_.get() &&
+ CommandLine::ForCurrentProcess()->HasSwitch(switches::kLoginManager)) {
+ LOG(FATAL) << "GetProfileSyncService() called before login complete.";
+ }
+#endif
+ return GetProfileSyncService("");
+}
+
+ProfileSyncService* ProfileImpl::GetProfileSyncService(
+ const std::string& cros_user) {
+
+ if (!ProfileSyncService::IsSyncEnabled())
+ return NULL;
+ if (!sync_service_.get())
+ InitSyncService(cros_user);
+ return sync_service_.get();
+}
+
+BrowserSignin* ProfileImpl::GetBrowserSignin() {
+ if (!browser_signin_.get()) {
+ browser_signin_.reset(new BrowserSignin(this));
+ }
+ return browser_signin_.get();
+}
+
+CloudPrintProxyService* ProfileImpl::GetCloudPrintProxyService() {
+ if (!cloud_print_proxy_service_.get())
+ InitCloudPrintProxyService();
+ return cloud_print_proxy_service_.get();
+}
+
+void ProfileImpl::InitSyncService(const std::string& cros_user) {
+ profile_sync_factory_.reset(
+ new ProfileSyncFactoryImpl(this, CommandLine::ForCurrentProcess()));
+ sync_service_.reset(
+ profile_sync_factory_->CreateProfileSyncService(cros_user));
+ sync_service_->Initialize();
+}
+
+void ProfileImpl::InitCloudPrintProxyService() {
+ cloud_print_proxy_service_ = new CloudPrintProxyService(this);
+ cloud_print_proxy_service_->Initialize();
+}
+
+ChromeBlobStorageContext* ProfileImpl::GetBlobStorageContext() {
+ if (!blob_storage_context_) {
+ blob_storage_context_ = new ChromeBlobStorageContext();
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(blob_storage_context_.get(),
+ &ChromeBlobStorageContext::InitializeOnIOThread));
+ }
+ return blob_storage_context_;
+}
+
+ExtensionInfoMap* ProfileImpl::GetExtensionInfoMap() {
+ return extension_info_map_.get();
+}
+
+policy::ProfilePolicyContext* ProfileImpl::GetPolicyContext() {
+ if (!profile_policy_context_.get())
+ profile_policy_context_.reset(new policy::ProfilePolicyContext(this));
+
+ return profile_policy_context_.get();
+}
+
+PromoCounter* ProfileImpl::GetInstantPromoCounter() {
+#if defined(OS_WIN)
+ // TODO: enable this when we're ready to turn on the promo.
+ /*
+ if (!checked_instant_promo_) {
+ checked_instant_promo_ = true;
+ PrefService* prefs = GetPrefs();
+ if (!prefs->GetBoolean(prefs::kInstantEnabledOnce) &&
+ !InstantController::IsEnabled(this) &&
+ InstallUtil::IsChromeSxSProcess()) {
+ DCHECK(!instant_promo_counter_.get());
+ instant_promo_counter_.reset(
+ new PromoCounter(this, prefs::kInstantPromo, "Instant.Promo", 3, 3));
+ }
+ }
+ */
+ return instant_promo_counter_.get();
+#else
+ return NULL;
+#endif
+}
+
+#if defined(OS_CHROMEOS)
+chromeos::ProxyConfigServiceImpl*
+ ProfileImpl::GetChromeOSProxyConfigServiceImpl() {
+ if (!chromeos_proxy_config_service_impl_) {
+ chromeos_proxy_config_service_impl_ =
+ new chromeos::ProxyConfigServiceImpl();
+ }
+ return chromeos_proxy_config_service_impl_;
+}
+
+void ProfileImpl::SetupChromeOSEnterpriseExtensionObserver() {
+ DCHECK(!chromeos_enterprise_extension_observer_.get());
+ chromeos_enterprise_extension_observer_.reset(
+ new chromeos::EnterpriseExtensionObserver(this));
+}
+#endif // defined(OS_CHROMEOS)
+
+PrefProxyConfigTracker* ProfileImpl::GetProxyConfigTracker() {
+ if (!pref_proxy_config_tracker_)
+ pref_proxy_config_tracker_ = new PrefProxyConfigTracker(GetPrefs());
+
+ return pref_proxy_config_tracker_;
+}
+
+PrerenderManager* ProfileImpl::GetPrerenderManager() {
+ CommandLine* cl = CommandLine::ForCurrentProcess();
+ if (!cl->HasSwitch(switches::kEnablePagePrerender))
+ return NULL;
+ if (!prerender_manager_.get())
+ prerender_manager_.reset(new PrerenderManager(this));
+ return prerender_manager_.get();
+}
diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h
new file mode 100644
index 0000000..ce29d28
--- /dev/null
+++ b/chrome/browser/profiles/profile_impl.h
@@ -0,0 +1,306 @@
+// 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.
+
+// This class gathers state related to a single user profile.
+
+#ifndef CHROME_BROWSER_PROFILES_PROFILE_IMPL_H_
+#define CHROME_BROWSER_PROFILES_PROFILE_IMPL_H_
+#pragma once
+
+#include "base/file_path.h"
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+#include "base/timer.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/prefs/pref_change_registrar.h"
+#include "chrome/browser/spellcheck_host_observer.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+
+class BackgroundModeManager;
+class ExtensionPrefs;
+class PrefService;
+
+#if defined(OS_CHROMEOS)
+namespace chromeos {
+class Preferences;
+}
+#endif
+
+class NetPrefObserver;
+
+// The default profile implementation.
+class ProfileImpl : public Profile,
+ public SpellCheckHostObserver,
+ public NotificationObserver {
+ public:
+ virtual ~ProfileImpl();
+
+ static void RegisterUserPrefs(PrefService* prefs);
+
+ // Profile implementation.
+ virtual ProfileId GetRuntimeId();
+ virtual FilePath GetPath();
+ virtual bool IsOffTheRecord();
+ virtual Profile* GetOffTheRecordProfile();
+ virtual void DestroyOffTheRecordProfile();
+ virtual bool HasOffTheRecordProfile();
+ virtual Profile* GetOriginalProfile();
+ virtual ChromeAppCacheService* GetAppCacheService();
+ virtual webkit_database::DatabaseTracker* GetDatabaseTracker();
+ virtual history::TopSites* GetTopSites();
+ virtual history::TopSites* GetTopSitesWithoutCreating();
+ virtual VisitedLinkMaster* GetVisitedLinkMaster();
+ virtual UserScriptMaster* GetUserScriptMaster();
+ virtual SSLHostState* GetSSLHostState();
+ virtual net::TransportSecurityState* GetTransportSecurityState();
+ virtual ExtensionService* GetExtensionService();
+ virtual ExtensionDevToolsManager* GetExtensionDevToolsManager();
+ virtual ExtensionProcessManager* GetExtensionProcessManager();
+ virtual ExtensionMessageService* GetExtensionMessageService();
+ virtual ExtensionEventRouter* GetExtensionEventRouter();
+ virtual FaviconService* GetFaviconService(ServiceAccessType sat);
+ virtual HistoryService* GetHistoryService(ServiceAccessType sat);
+ virtual HistoryService* GetHistoryServiceWithoutCreating();
+ virtual AutocompleteClassifier* GetAutocompleteClassifier();
+ virtual WebDataService* GetWebDataService(ServiceAccessType sat);
+ virtual WebDataService* GetWebDataServiceWithoutCreating();
+ virtual PasswordStore* GetPasswordStore(ServiceAccessType sat);
+ virtual PrefService* GetPrefs();
+ virtual TemplateURLModel* GetTemplateURLModel();
+ virtual TemplateURLFetcher* GetTemplateURLFetcher();
+ virtual DownloadManager* GetDownloadManager();
+ virtual PersonalDataManager* GetPersonalDataManager();
+ virtual fileapi::SandboxedFileSystemContext* GetFileSystemContext();
+ virtual void InitThemes();
+ virtual void SetTheme(const Extension* extension);
+ virtual void SetNativeTheme();
+ virtual void ClearTheme();
+ virtual const Extension* GetTheme();
+ virtual BrowserThemeProvider* GetThemeProvider();
+ virtual bool HasCreatedDownloadManager() const;
+ virtual URLRequestContextGetter* GetRequestContext();
+ virtual URLRequestContextGetter* GetRequestContextForMedia();
+ virtual URLRequestContextGetter* GetRequestContextForExtensions();
+ virtual void RegisterExtensionWithRequestContexts(const Extension* extension);
+ virtual void UnregisterExtensionWithRequestContexts(
+ const Extension* extension);
+ virtual net::SSLConfigService* GetSSLConfigService();
+ virtual HostContentSettingsMap* GetHostContentSettingsMap();
+ virtual HostZoomMap* GetHostZoomMap();
+ virtual GeolocationContentSettingsMap* GetGeolocationContentSettingsMap();
+ virtual GeolocationPermissionContext* GetGeolocationPermissionContext();
+ virtual UserStyleSheetWatcher* GetUserStyleSheetWatcher();
+ virtual FindBarState* GetFindBarState();
+ virtual SessionService* GetSessionService();
+ virtual void ShutdownSessionService();
+ virtual bool HasSessionService() const;
+ virtual bool HasProfileSyncService() const;
+ virtual bool DidLastSessionExitCleanly();
+ virtual BookmarkModel* GetBookmarkModel();
+ virtual bool IsSameProfile(Profile* profile);
+ virtual base::Time GetStartTime() const;
+ virtual TabRestoreService* GetTabRestoreService();
+ virtual void ResetTabRestoreService();
+ virtual SpellCheckHost* GetSpellCheckHost();
+ virtual void ReinitializeSpellCheckHost(bool force);
+ virtual WebKitContext* GetWebKitContext();
+ virtual DesktopNotificationService* GetDesktopNotificationService();
+ virtual BackgroundContentsService* GetBackgroundContentsService() const;
+ virtual StatusTray* GetStatusTray();
+ virtual void MarkAsCleanShutdown();
+ virtual void InitExtensions();
+ virtual void InitWebResources();
+ virtual NTPResourceCache* GetNTPResourceCache();
+ virtual FilePath last_selected_directory();
+ virtual void set_last_selected_directory(const FilePath& path);
+ virtual ProfileSyncService* GetProfileSyncService();
+ virtual ProfileSyncService* GetProfileSyncService(
+ const std::string& cros_user);
+ virtual TokenService* GetTokenService();
+ void InitSyncService(const std::string& cros_user);
+ virtual CloudPrintProxyService* GetCloudPrintProxyService();
+ void InitCloudPrintProxyService();
+ virtual ChromeBlobStorageContext* GetBlobStorageContext();
+ virtual ExtensionInfoMap* GetExtensionInfoMap();
+ virtual PromoCounter* GetInstantPromoCounter();
+ virtual BrowserSignin* GetBrowserSignin();
+ virtual policy::ProfilePolicyContext* GetPolicyContext();
+
+#if defined(OS_CHROMEOS)
+ virtual chromeos::ProxyConfigServiceImpl* GetChromeOSProxyConfigServiceImpl();
+ virtual void SetupChromeOSEnterpriseExtensionObserver();
+#endif // defined(OS_CHROMEOS)
+
+ virtual PrefProxyConfigTracker* GetProxyConfigTracker();
+ virtual PrerenderManager* GetPrerenderManager();
+
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // SpellCheckHostObserver implementation.
+ virtual void SpellCheckHostInitialized();
+
+ private:
+ friend class Profile;
+
+ explicit ProfileImpl(const FilePath& path);
+
+ void CreateWebDataService();
+ FilePath GetPrefFilePath();
+
+ void CreatePasswordStore();
+
+ void StopCreateSessionServiceTimer();
+
+ void EnsureRequestContextCreated() {
+ GetRequestContext();
+ }
+
+ void EnsureSessionServiceCreated() {
+ GetSessionService();
+ }
+
+ void RegisterComponentExtensions();
+ void InstallDefaultApps();
+
+ NotificationRegistrar registrar_;
+ PrefChangeRegistrar pref_change_registrar_;
+
+ FilePath path_;
+ FilePath base_cache_path_;
+ // Keep prefs_ on top for destruction order because extension_prefs_,
+ // net_pref_observer_, web_resource_service_ and background_contents_service_
+ // store pointers to prefs_ and shall be destructed first.
+ scoped_ptr<PrefService> prefs_;
+ scoped_ptr<VisitedLinkEventListener> visited_link_event_listener_;
+ scoped_ptr<VisitedLinkMaster> visited_link_master_;
+ // Keep extension_prefs_ on top of extensions_service_ because the latter
+ // maintains a pointer to the first and shall be destructed first.
+ scoped_ptr<ExtensionPrefs> extension_prefs_;
+ scoped_refptr<ExtensionService> extensions_service_;
+ scoped_refptr<UserScriptMaster> user_script_master_;
+ scoped_refptr<ExtensionDevToolsManager> extension_devtools_manager_;
+ scoped_ptr<ExtensionProcessManager> extension_process_manager_;
+ scoped_refptr<ExtensionMessageService> extension_message_service_;
+ scoped_ptr<ExtensionEventRouter> extension_event_router_;
+ scoped_ptr<SSLHostState> ssl_host_state_;
+ scoped_refptr<net::TransportSecurityState>
+ transport_security_state_;
+ scoped_refptr<TransportSecurityPersister>
+ transport_security_persister_;
+ scoped_ptr<policy::ProfilePolicyContext> profile_policy_context_;
+ scoped_ptr<NetPrefObserver> net_pref_observer_;
+ scoped_ptr<TemplateURLFetcher> template_url_fetcher_;
+ scoped_ptr<TemplateURLModel> template_url_model_;
+ scoped_ptr<BookmarkModel> bookmark_bar_model_;
+ scoped_refptr<WebResourceService> web_resource_service_;
+ scoped_ptr<NTPResourceCache> ntp_resource_cache_;
+
+ scoped_ptr<TokenService> token_service_;
+ scoped_ptr<ProfileSyncFactory> profile_sync_factory_;
+ scoped_ptr<ProfileSyncService> sync_service_;
+ scoped_refptr<CloudPrintProxyService> cloud_print_proxy_service_;
+
+ scoped_refptr<ChromeURLRequestContextGetter> request_context_;
+
+ scoped_refptr<ChromeURLRequestContextGetter> media_request_context_;
+
+ scoped_refptr<ChromeURLRequestContextGetter> extensions_request_context_;
+
+ scoped_ptr<SSLConfigServiceManager> ssl_config_service_manager_;
+
+ scoped_refptr<HostContentSettingsMap> host_content_settings_map_;
+ scoped_refptr<HostZoomMap> host_zoom_map_;
+ scoped_refptr<GeolocationContentSettingsMap>
+ geolocation_content_settings_map_;
+ scoped_refptr<GeolocationPermissionContext>
+ geolocation_permission_context_;
+ scoped_refptr<UserStyleSheetWatcher> user_style_sheet_watcher_;
+ scoped_ptr<FindBarState> find_bar_state_;
+ scoped_refptr<DownloadManager> download_manager_;
+ scoped_refptr<HistoryService> history_service_;
+ scoped_refptr<FaviconService> favicon_service_;
+ scoped_ptr<AutocompleteClassifier> autocomplete_classifier_;
+ scoped_refptr<WebDataService> web_data_service_;
+ scoped_refptr<PasswordStore> password_store_;
+ scoped_refptr<SessionService> session_service_;
+ scoped_ptr<BrowserThemeProvider> theme_provider_;
+ scoped_refptr<WebKitContext> webkit_context_;
+ scoped_ptr<DesktopNotificationService> desktop_notification_service_;
+ scoped_ptr<BackgroundContentsService> background_contents_service_;
+ scoped_ptr<BackgroundModeManager> background_mode_manager_;
+ scoped_ptr<StatusTray> status_tray_;
+ scoped_refptr<PersonalDataManager> personal_data_manager_;
+ scoped_ptr<PinnedTabService> pinned_tab_service_;
+ scoped_refptr<fileapi::SandboxedFileSystemContext> file_system_context_;
+ scoped_ptr<BrowserSignin> browser_signin_;
+ bool history_service_created_;
+ bool favicon_service_created_;
+ bool created_web_data_service_;
+ bool created_password_store_;
+ bool created_download_manager_;
+ bool created_theme_provider_;
+ bool clear_local_state_on_exit_;
+ // Whether or not the last session exited cleanly. This is set only once.
+ bool last_session_exited_cleanly_;
+
+ base::OneShotTimer<ProfileImpl> create_session_service_timer_;
+
+ scoped_ptr<Profile> off_the_record_profile_;
+
+ // See GetStartTime for details.
+ base::Time start_time_;
+
+ scoped_refptr<TabRestoreService> tab_restore_service_;
+
+ scoped_refptr<SpellCheckHost> spellcheck_host_;
+
+ // Indicates whether |spellcheck_host_| has told us initialization is
+ // finished.
+ bool spellcheck_host_ready_;
+
+#if defined(OS_WIN)
+ bool checked_instant_promo_;
+ scoped_ptr<PromoCounter> instant_promo_counter_;
+#endif
+
+ // Set to true when ShutdownSessionService is invoked. If true
+ // GetSessionService won't recreate the SessionService.
+ bool shutdown_session_service_;
+
+ // The AppCacheService for this profile, shared by all requests contexts
+ // associated with this profile. Should only be used on the IO thread.
+ scoped_refptr<ChromeAppCacheService> appcache_service_;
+
+ // The main database tracker for this profile.
+ // Should be used only on the file thread.
+ scoped_refptr<webkit_database::DatabaseTracker> db_tracker_;
+
+ scoped_refptr<history::TopSites> top_sites_; // For history and thumbnails.
+
+ scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;
+
+ scoped_refptr<ExtensionInfoMap> extension_info_map_;
+
+#if defined(OS_CHROMEOS)
+ scoped_ptr<chromeos::Preferences> chromeos_preferences_;
+
+ scoped_refptr<chromeos::ProxyConfigServiceImpl>
+ chromeos_proxy_config_service_impl_;
+
+ scoped_ptr<chromeos::EnterpriseExtensionObserver>
+ chromeos_enterprise_extension_observer_;
+#endif
+
+ scoped_refptr<PrefProxyConfigTracker> pref_proxy_config_tracker_;
+
+ scoped_ptr<PrerenderManager> prerender_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProfileImpl);
+};
+
+#endif // CHROME_BROWSER_PROFILES_PROFILE_IMPL_H_
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
new file mode 100644
index 0000000..ae942df
--- /dev/null
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -0,0 +1,285 @@
+// 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.
+
+#include <set>
+
+#include "chrome/browser/profiles/profile_manager.h"
+
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/string_util.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/logging_chrome.h"
+#include "chrome/common/net/url_request_context_getter.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
+#include "chrome/common/pref_names.h"
+#include "grit/generated_resources.h"
+#include "net/http/http_transaction_factory.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_job.h"
+#include "net/url_request/url_request_job_tracker.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/cros/cros_library.h"
+#include "chrome/browser/chromeos/cros/cryptohome_library.h"
+#endif
+
+// static
+void ProfileManager::ShutdownSessionServices() {
+ ProfileManager* pm = g_browser_process->profile_manager();
+ if (!pm) // Is NULL when running unit tests.
+ return;
+ for (ProfileManager::const_iterator i = pm->begin(); i != pm->end(); ++i)
+ (*i)->ShutdownSessionService();
+}
+
+// static
+Profile* ProfileManager::GetDefaultProfile() {
+ FilePath user_data_dir;
+ PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ return profile_manager->GetDefaultProfile(user_data_dir);
+}
+
+ProfileManager::ProfileManager() : logged_in_(false) {
+ SystemMonitor::Get()->AddObserver(this);
+#if defined(OS_CHROMEOS)
+ registrar_.Add(
+ this,
+ NotificationType::LOGIN_USER_CHANGED,
+ NotificationService::AllSources());
+#endif
+}
+
+ProfileManager::~ProfileManager() {
+ SystemMonitor* system_monitor = SystemMonitor::Get();
+ if (system_monitor)
+ system_monitor->RemoveObserver(this);
+
+ // Destroy all profiles that we're keeping track of.
+ for (const_iterator i(begin()); i != end(); ++i)
+ delete *i;
+ profiles_.clear();
+}
+
+FilePath ProfileManager::GetDefaultProfileDir(
+ const FilePath& user_data_dir) {
+ FilePath default_profile_dir(user_data_dir);
+ default_profile_dir = default_profile_dir.Append(
+ FilePath::FromWStringHack(chrome::kNotSignedInProfile));
+ return default_profile_dir;
+}
+
+FilePath ProfileManager::GetProfilePrefsPath(
+ const FilePath &profile_dir) {
+ FilePath default_prefs_path(profile_dir);
+ default_prefs_path = default_prefs_path.Append(chrome::kPreferencesFilename);
+ return default_prefs_path;
+}
+
+FilePath ProfileManager::GetCurrentProfileDir() {
+ FilePath relative_profile_dir;
+#if defined(OS_CHROMEOS)
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ if (logged_in_) {
+ FilePath profile_dir;
+ // If the user has logged in, pick up the new profile.
+ if (command_line.HasSwitch(switches::kLoginProfile)) {
+ profile_dir = command_line.GetSwitchValuePath(switches::kLoginProfile);
+ } else {
+ // We should never be logged in with no profile dir.
+ NOTREACHED();
+ return FilePath("");
+ }
+ relative_profile_dir = relative_profile_dir.Append(profile_dir);
+ return relative_profile_dir;
+ }
+#endif
+ relative_profile_dir = relative_profile_dir.Append(
+ FilePath::FromWStringHack(chrome::kNotSignedInProfile));
+ return relative_profile_dir;
+}
+
+Profile* ProfileManager::GetDefaultProfile(const FilePath& user_data_dir) {
+ FilePath default_profile_dir(user_data_dir);
+ default_profile_dir = default_profile_dir.Append(GetCurrentProfileDir());
+#if defined(OS_CHROMEOS)
+ if (!logged_in_) {
+ Profile* profile;
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+
+ // For cros, return the OTR profile so we never accidentally keep
+ // user data in an unencrypted profile. But doing this makes
+ // many of the browser and ui tests fail. We do return the OTR profile
+ // if the login-profile switch is passed so that we can test this.
+ // TODO(davemoore) Fix the tests so they allow OTR profiles.
+ if (!command_line.HasSwitch(switches::kTestType) ||
+ command_line.HasSwitch(switches::kLoginProfile)) {
+ // Don't init extensions for this profile
+ profile = GetProfile(default_profile_dir, false);
+ profile = profile->GetOffTheRecordProfile();
+ } else {
+ profile = GetProfile(default_profile_dir, true);
+ }
+ return profile;
+ }
+#endif
+ return GetProfile(default_profile_dir);
+}
+
+Profile* ProfileManager::GetProfile(const FilePath& profile_dir) {
+ return GetProfile(profile_dir, true);
+}
+
+Profile* ProfileManager::GetProfile(
+ const FilePath& profile_dir, bool init_extensions) {
+ // If the profile is already loaded (e.g., chrome.exe launched twice), just
+ // return it.
+ Profile* profile = GetProfileByPath(profile_dir);
+ if (NULL != profile)
+ return profile;
+
+ if (!ProfileManager::IsProfile(profile_dir)) {
+ // If the profile directory doesn't exist, create it.
+ profile = ProfileManager::CreateProfile(profile_dir);
+ } else {
+ // The profile already exists on disk, just load it.
+ profile = Profile::CreateProfile(profile_dir);
+ }
+ DCHECK(profile);
+ if (profile) {
+ bool result = AddProfile(profile, init_extensions);
+ DCHECK(result);
+ }
+ return profile;
+}
+
+bool ProfileManager::AddProfile(Profile* profile, bool init_extensions) {
+ DCHECK(profile);
+
+ // Make sure that we're not loading a profile with the same ID as a profile
+ // that's already loaded.
+ if (GetProfileByPath(profile->GetPath())) {
+ NOTREACHED() << "Attempted to add profile with the same path (" <<
+ profile->GetPath().value() <<
+ ") as an already-loaded profile.";
+ return false;
+ }
+
+ profiles_.insert(profiles_.end(), profile);
+ if (init_extensions)
+ profile->InitExtensions();
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ if (!command_line.HasSwitch(switches::kDisableWebResources))
+ profile->InitWebResources();
+ return true;
+}
+
+Profile* ProfileManager::GetProfileByPath(const FilePath& path) const {
+ for (const_iterator i(begin()); i != end(); ++i) {
+ if ((*i)->GetPath() == path)
+ return *i;
+ }
+
+ return NULL;
+}
+
+void ProfileManager::OnSuspend() {
+ DCHECK(CalledOnValidThread());
+
+ for (const_iterator i(begin()); i != end(); ++i) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableFunction(&ProfileManager::SuspendProfile, *i));
+ }
+}
+
+void ProfileManager::OnResume() {
+ DCHECK(CalledOnValidThread());
+ for (const_iterator i(begin()); i != end(); ++i) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableFunction(&ProfileManager::ResumeProfile, *i));
+ }
+}
+
+void ProfileManager::Observe(
+ NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+#if defined(OS_CHROMEOS)
+ if (type == NotificationType::LOGIN_USER_CHANGED) {
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ if (!command_line.HasSwitch(switches::kTestType)) {
+ // This will fail when running on non cros os.
+ // TODO(davemoore) Need to mock this enough to enable testing.
+ CHECK(chromeos::CrosLibrary::Get()->EnsureLoaded());
+ // If we don't have a mounted profile directory we're in trouble.
+ // TODO(davemoore) Once we have better api this check should ensure that
+ // our profile directory is the one that's mounted, and that it's mounted
+ // as the current user.
+ CHECK(chromeos::CrosLibrary::Get()->GetCryptohomeLibrary()->IsMounted());
+ }
+ logged_in_ = true;
+ }
+#endif
+}
+
+void ProfileManager::SuspendProfile(Profile* profile) {
+ DCHECK(profile);
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ for (net::URLRequestJobTracker::JobIterator i =
+ net::g_url_request_job_tracker.begin();
+ i != net::g_url_request_job_tracker.end(); ++i)
+ (*i)->Kill();
+
+ profile->GetRequestContext()->GetURLRequestContext()->
+ http_transaction_factory()->Suspend(true);
+}
+
+void ProfileManager::ResumeProfile(Profile* profile) {
+ DCHECK(profile);
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ profile->GetRequestContext()->GetURLRequestContext()->
+ http_transaction_factory()->Suspend(false);
+}
+
+// static
+bool ProfileManager::IsProfile(const FilePath& path) {
+ FilePath prefs_path = GetProfilePrefsPath(path);
+ FilePath history_path = path;
+ history_path = history_path.Append(chrome::kHistoryFilename);
+
+ return file_util::PathExists(prefs_path) &&
+ file_util::PathExists(history_path);
+}
+
+// static
+Profile* ProfileManager::CreateProfile(const FilePath& path) {
+ if (IsProfile(path)) {
+ DCHECK(false) << "Attempted to create a profile with the path:\n"
+ << path.value() << "\n but that path already contains a profile";
+ }
+
+ if (!file_util::PathExists(path)) {
+ // TODO(tc): http://b/1094718 Bad things happen if we can't write to the
+ // profile directory. We should eventually be able to run in this
+ // situation.
+ if (!file_util::CreateDirectory(path))
+ return NULL;
+ }
+
+ return Profile::CreateProfile(path);
+}
diff --git a/chrome/browser/profiles/profile_manager.h b/chrome/browser/profiles/profile_manager.h
new file mode 100644
index 0000000..d46c900
--- /dev/null
+++ b/chrome/browser/profiles/profile_manager.h
@@ -0,0 +1,128 @@
+// 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.
+
+// This class keeps track of the currently-active profiles in the runtime.
+
+#ifndef CHROME_BROWSER_PROFILES_PROFILE_MANAGER_H_
+#define CHROME_BROWSER_PROFILES_PROFILE_MANAGER_H_
+#pragma once
+
+#include <vector>
+
+#include "app/system_monitor.h"
+#include "base/basictypes.h"
+#include "base/message_loop.h"
+#include "base/non_thread_safe.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+
+class FilePath;
+
+class ProfileManager : public NonThreadSafe,
+ public SystemMonitor::PowerObserver,
+ public NotificationObserver {
+ public:
+ ProfileManager();
+ virtual ~ProfileManager();
+
+ // Invokes ShutdownSessionService() on all profiles.
+ static void ShutdownSessionServices();
+
+ // Returns the default profile. This adds the profile to the
+ // ProfileManager if it doesn't already exist. This method returns NULL if
+ // the profile doesn't exist and we can't create it.
+ // The profile used can be overridden by using --login-profile on cros.
+ Profile* GetDefaultProfile(const FilePath& user_data_dir);
+
+ // Same as instance method but provides the default user_data_dir as well.
+ static Profile* GetDefaultProfile();
+
+ // Returns a profile for a specific profile directory within the user data
+ // dir. This will return an existing profile it had already been created,
+ // otherwise it will create and manage it.
+ Profile* GetProfile(const FilePath& profile_dir);
+
+ // Returns a profile for a specific profile directory within the user data
+ // dir with the option of controlling whether extensions are initialized
+ // or not. This will return an existing profile it had already been created,
+ // otherwise it will create and manage it.
+ // Note that if the profile has already been created, extensions may have
+ // been initialized. If this matters to you, you should call GetProfileByPath
+ // first to see if the profile already exists.
+ Profile* GetProfile(const FilePath& profile_dir, bool init_extensions);
+
+ // Returns the directory where the currently active profile is
+ // stored, relative to the user data directory currently in use..
+ FilePath GetCurrentProfileDir();
+
+ // These allow iteration through the current list of profiles.
+ typedef std::vector<Profile*> ProfileVector;
+ typedef ProfileVector::iterator iterator;
+ typedef ProfileVector::const_iterator const_iterator;
+
+ iterator begin() { return profiles_.begin(); }
+ const_iterator begin() const { return profiles_.begin(); }
+ iterator end() { return profiles_.end(); }
+ const_iterator end() const { return profiles_.end(); }
+
+ // PowerObserver notifications
+ virtual void OnSuspend();
+ virtual void OnResume();
+
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // ------------------ static utility functions -------------------
+
+ // Returns the path to the default profile directory, based on the given
+ // user data directory.
+ static FilePath GetDefaultProfileDir(const FilePath& user_data_dir);
+
+ // Returns the path to the preferences file given the user profile directory.
+ static FilePath GetProfilePrefsPath(const FilePath& profile_dir);
+
+ // Tries to determine whether the given path represents a profile
+ // directory, and returns true if it thinks it does.
+ static bool IsProfile(const FilePath& path);
+
+ // If a profile with the given path is currently managed by this object,
+ // return a pointer to the corresponding Profile object;
+ // otherwise return NULL.
+ Profile* GetProfileByPath(const FilePath& path) const;
+
+ // Creates a new profile at the specified path.
+ // This method should always return a valid Profile (i.e., should never
+ // return NULL).
+ static Profile* CreateProfile(const FilePath& path);
+
+ private:
+ // Hooks to suspend/resume per-profile network traffic.
+ // These must be called on the IO thread.
+ static void SuspendProfile(Profile*);
+ static void ResumeProfile(Profile*);
+
+ // Adds a pre-existing Profile object to the set managed by this
+ // ProfileManager. This ProfileManager takes ownership of the Profile.
+ // The Profile should not already be managed by this ProfileManager.
+ // Returns true if the profile was added, false otherwise.
+ bool AddProfile(Profile* profile, bool init_extensions);
+
+ // We keep a simple vector of profiles rather than something fancier
+ // because we expect there to be a small number of profiles active.
+ ProfileVector profiles_;
+
+ NotificationRegistrar registrar_;
+
+ // Indicates that a user has logged in and that the profile specified
+ // in the --login-profile command line argument should be used as the
+ // default.
+ bool logged_in_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProfileManager);
+};
+
+#endif // CHROME_BROWSER_PROFILES_PROFILE_MANAGER_H_
diff --git a/chrome/browser/profiles/profile_manager_unittest.cc b/chrome/browser/profiles/profile_manager_unittest.cc
new file mode 100644
index 0000000..e2f1381
--- /dev/null
+++ b/chrome/browser/profiles/profile_manager_unittest.cc
@@ -0,0 +1,149 @@
+// 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.
+
+#include <string>
+
+#include "app/system_monitor.h"
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/message_loop.h"
+#include "base/path_service.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/pref_names.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class ProfileManagerTest : public testing::Test {
+ protected:
+ ProfileManagerTest() : ui_thread_(BrowserThread::UI, &message_loop_) {
+ }
+
+ virtual void SetUp() {
+ // Name a subdirectory of the temp directory.
+ ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &test_dir_));
+ test_dir_ = test_dir_.Append(FILE_PATH_LITERAL("ProfileManagerTest"));
+
+ // Create a fresh, empty copy of this directory.
+ file_util::Delete(test_dir_, true);
+ file_util::CreateDirectory(test_dir_);
+ }
+ virtual void TearDown() {
+ // Clean up test directory
+ ASSERT_TRUE(file_util::Delete(test_dir_, true));
+ ASSERT_FALSE(file_util::PathExists(test_dir_));
+ }
+
+ MessageLoopForUI message_loop_;
+ BrowserThread ui_thread_;
+
+ // the path to temporary directory used to contain the test operations
+ FilePath test_dir_;
+};
+
+TEST_F(ProfileManagerTest, CreateProfile) {
+ FilePath source_path;
+ PathService::Get(chrome::DIR_TEST_DATA, &source_path);
+ source_path = source_path.Append(FILE_PATH_LITERAL("profiles"));
+ source_path = source_path.Append(FILE_PATH_LITERAL("sample"));
+
+ FilePath dest_path = test_dir_;
+ dest_path = dest_path.Append(FILE_PATH_LITERAL("New Profile"));
+
+ scoped_ptr<Profile> profile;
+
+ // Successfully create a profile.
+ profile.reset(ProfileManager::CreateProfile(dest_path));
+ ASSERT_TRUE(profile.get());
+
+ profile.reset();
+
+#ifdef NDEBUG
+ // In Release mode, we always try to always return a profile. In debug,
+ // these cases would trigger DCHECKs.
+
+ // The profile already exists when we call CreateProfile. Just load it.
+ profile.reset(ProfileManager::CreateProfile(dest_path));
+ ASSERT_TRUE(profile.get());
+#endif
+}
+
+TEST_F(ProfileManagerTest, DefaultProfileDir) {
+ CommandLine *cl = CommandLine::ForCurrentProcess();
+ SystemMonitor dummy;
+ ProfileManager profile_manager;
+ std::string profile_dir("my_user");
+
+ cl->AppendSwitch(switches::kTestType);
+
+ FilePath expected_default =
+ FilePath::FromWStringHack(chrome::kNotSignedInProfile);
+ EXPECT_EQ(expected_default.value(),
+ profile_manager.GetCurrentProfileDir().value());
+}
+
+#if defined(OS_CHROMEOS)
+// This functionality only exists on Chrome OS.
+TEST_F(ProfileManagerTest, LoggedInProfileDir) {
+ CommandLine *cl = CommandLine::ForCurrentProcess();
+ SystemMonitor dummy;
+ ProfileManager profile_manager;
+ std::string profile_dir("my_user");
+
+ cl->AppendSwitchASCII(switches::kLoginProfile, profile_dir);
+ cl->AppendSwitch(switches::kTestType);
+
+ FilePath expected_default =
+ FilePath::FromWStringHack(chrome::kNotSignedInProfile);
+ EXPECT_EQ(expected_default.value(),
+ profile_manager.GetCurrentProfileDir().value());
+
+ profile_manager.Observe(NotificationType::LOGIN_USER_CHANGED,
+ NotificationService::AllSources(),
+ NotificationService::NoDetails());
+ FilePath expected_logged_in(profile_dir);
+ EXPECT_EQ(expected_logged_in.value(),
+ profile_manager.GetCurrentProfileDir().value());
+ VLOG(1) << test_dir_.Append(profile_manager.GetCurrentProfileDir()).value();
+}
+
+#endif
+
+TEST_F(ProfileManagerTest, CreateAndUseTwoProfiles) {
+ FilePath source_path;
+ PathService::Get(chrome::DIR_TEST_DATA, &source_path);
+ source_path = source_path.Append(FILE_PATH_LITERAL("profiles"));
+ source_path = source_path.Append(FILE_PATH_LITERAL("sample"));
+
+ FilePath dest_path1 = test_dir_;
+ dest_path1 = dest_path1.Append(FILE_PATH_LITERAL("New Profile 1"));
+
+ FilePath dest_path2 = test_dir_;
+ dest_path2 = dest_path2.Append(FILE_PATH_LITERAL("New Profile 2"));
+
+ scoped_ptr<Profile> profile1;
+ scoped_ptr<Profile> profile2;
+
+ // Successfully create the profiles.
+ profile1.reset(ProfileManager::CreateProfile(dest_path1));
+ ASSERT_TRUE(profile1.get());
+
+ profile2.reset(ProfileManager::CreateProfile(dest_path2));
+ ASSERT_TRUE(profile2.get());
+
+ // Force lazy-init of some profile services to simulate use.
+ EXPECT_TRUE(profile1->GetHistoryService(Profile::EXPLICIT_ACCESS));
+ EXPECT_TRUE(profile1->GetBookmarkModel());
+ EXPECT_TRUE(profile2->GetBookmarkModel());
+ EXPECT_TRUE(profile2->GetHistoryService(Profile::EXPLICIT_ACCESS));
+ profile1.reset();
+ profile2.reset();
+ // Make sure history cleans up correctly.
+ message_loop_.RunAllPending();
+}
diff --git a/chrome/browser/remoting/directory_add_request.cc b/chrome/browser/remoting/directory_add_request.cc
new file mode 100644
index 0000000..c7d2645
--- /dev/null
+++ b/chrome/browser/remoting/directory_add_request.cc
@@ -0,0 +1,125 @@
+// 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.
+
+#include "chrome/browser/remoting/directory_add_request.h"
+
+#include <vector>
+
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/values.h"
+#include "chrome/common/net/http_return.h"
+#include "chrome/common/net/url_request_context_getter.h"
+#include "net/http/http_request_headers.h"
+#include "net/url_request/url_request_status.h"
+
+namespace remoting {
+
+static const char kRemotingDirectoryUrl[] =
+ "https://www.googleapis.com/chromoting/v1/@me/hosts";
+
+DirectoryAddRequest::DirectoryAddRequest(URLRequestContextGetter* getter)
+ : getter_(getter) {
+}
+
+DirectoryAddRequest::~DirectoryAddRequest() {
+ DCHECK(!fetcher_.get()) << "URLFetcher not destroyed.";
+}
+
+void DirectoryAddRequest::AddHost(const remoting::ChromotingHostInfo& host_info,
+ const std::string& auth_token,
+ DoneCallback* done_callback) {
+ DCHECK(done_callback);
+ done_callback_.reset(done_callback);
+
+ // Prepare the parameters for the request.
+ DictionaryValue data;
+ data.SetString("hostId", host_info.host_id);
+ data.SetString("hostName", host_info.hostname);
+ data.SetString("publicKey", host_info.public_key);
+
+ // Generate the final json query.
+ DictionaryValue args;
+ args.Set("data", data.DeepCopy());
+ std::string request_content;
+ base::JSONWriter::Write(&args, false, &request_content);
+
+ // Prepare the HTTP header for authentication.
+ net::HttpRequestHeaders headers;
+ headers.SetHeader("Authorization", "GoogleLogin auth=" + auth_token);
+ fetcher_.reset(
+ new URLFetcher(GURL(kRemotingDirectoryUrl), URLFetcher::POST, this));
+ fetcher_->set_request_context(getter_);
+ fetcher_->set_upload_data("application/json", request_content);
+ fetcher_->set_extra_request_headers(headers.ToString());
+
+ // And then start the request.
+ fetcher_->Start();
+}
+
+void DirectoryAddRequest::OnURLFetchComplete(
+ const URLFetcher* source,
+ const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data) {
+ DCHECK_EQ(source, fetcher_.get());
+
+ // Destroy the fetcher after the response has been received.
+ fetcher_.reset();
+
+ Result result;
+ std::string error_message;
+
+ if (status.is_success()) {
+ DictionaryValue* response = NULL;
+ scoped_ptr<Value> response_json(base::JSONReader::Read(data, true));
+ if (response_json != NULL &&
+ response_json->IsType(Value::TYPE_DICTIONARY)) {
+ response = static_cast<DictionaryValue*>(response_json.get());
+ response->GetString("error.message", &error_message);
+ }
+
+ switch (response_code) {
+ case RC_REQUEST_OK:
+ result = SUCCESS;
+ break;
+
+ case RC_BAD_REQUEST:
+ // TODO(sergeyu): Implement duplicate error detection that doesn't
+ // depend on error message.
+ if (error_message.find("duplicate") != std::string::npos) {
+ result = ERROR_EXISTS;
+ } else {
+ result = ERROR_INVALID_REQUEST;
+ }
+ break;
+
+ case RC_UNAUTHORIZED:
+ result = ERROR_AUTH;
+ break;
+
+ case RC_INTERNAL_SERVER_ERROR:
+ result = ERROR_SERVER;
+ break;
+
+ default:
+ result = ERROR_OTHER;
+ }
+ } else {
+ result = ERROR_OTHER;
+ }
+
+ if (result != SUCCESS) {
+ LOG(WARNING) << "Received error when trying to register Chromoting host. "
+ << "status.is_success(): " << status.is_success()
+ << " response_code: " << response_code
+ << " error_message: " << error_message;
+ }
+
+ done_callback_->Run(result, error_message);
+}
+
+} // namespace remoting
diff --git a/chrome/browser/remoting/directory_add_request.h b/chrome/browser/remoting/directory_add_request.h
new file mode 100644
index 0000000..2ec6ed2
--- /dev/null
+++ b/chrome/browser/remoting/directory_add_request.h
@@ -0,0 +1,75 @@
+// 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.
+
+#ifndef CHROME_BROWSER_REMOTING_DIRECTORY_ADD_REQUEST_H_
+#define CHROME_BROWSER_REMOTING_DIRECTORY_ADD_REQUEST_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/scoped_ptr.h"
+#include "chrome/common/remoting/chromoting_host_info.h"
+#include "chrome/common/net/url_fetcher.h"
+#include "googleurl/src/gurl.h"
+
+namespace remoting {
+
+// A class implements REST API insert call for the Chromoting directory service.
+class DirectoryAddRequest : public URLFetcher::Delegate {
+ public:
+ enum Result {
+ // Host was added successfully.
+ SUCCESS,
+ // Invalid authentication token.
+ ERROR_AUTH,
+ // Server rejected request because it was invalid (e.g. specified
+ // public key is invalid).
+ ERROR_INVALID_REQUEST,
+ // Host is already registered.
+ ERROR_EXISTS,
+ // Internal server error.
+ ERROR_SERVER,
+ // Timeout expired.
+ ERROR_TIMEOUT_EXPIRED,
+ // Some other error, e.g. network failure.
+ ERROR_OTHER,
+ };
+
+ // Callback called when request is finished. The second parameter
+ // contains error message in case of an error. The error message may
+ // not be localized, and should be used for logging, but not shown
+ // to the user.
+ typedef Callback2<Result, const std::string&>::Type DoneCallback;
+
+ explicit DirectoryAddRequest(URLRequestContextGetter* getter);
+ ~DirectoryAddRequest();
+
+ // Add this computer as a host. Use the token for
+ // authentication. |done_callback| is called when the request is
+ // finished. Request can be cancelled by destroying this object.
+ void AddHost(const remoting::ChromotingHostInfo& host_info,
+ const std::string& auth_token,
+ DoneCallback* done_callback);
+
+ // URLFetcher::Delegate implementation.
+ virtual void OnURLFetchComplete(const URLFetcher* source,
+ const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data);
+
+ private:
+ friend class DirectoryAddRequestTest;
+
+ URLRequestContextGetter* getter_;
+ scoped_ptr<DoneCallback> done_callback_;
+ scoped_ptr<URLFetcher> fetcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(DirectoryAddRequest);
+};
+
+} // namespace remoting
+
+#endif // CHROME_BROWSER_REMOTING_DIRECTORY_ADD_REQUEST_H_
diff --git a/chrome/browser/remoting/directory_add_request_unittest.cc b/chrome/browser/remoting/directory_add_request_unittest.cc
new file mode 100644
index 0000000..6389b3e
--- /dev/null
+++ b/chrome/browser/remoting/directory_add_request_unittest.cc
@@ -0,0 +1,82 @@
+// 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.
+
+#include "chrome/browser/remoting/directory_add_request.h"
+#include "chrome/test/testing_profile.h"
+#include "net/url_request/url_request_status.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace remoting {
+
+namespace {
+class MockDoneCallback {
+ public:
+ MOCK_METHOD2(OnDone,
+ void(DirectoryAddRequest::Result,
+ const std::string& message));
+};
+} // namespace
+
+class DirectoryAddRequestTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ target_.reset(new DirectoryAddRequest(profile_.GetRequestContext()));
+ }
+
+ void TestResult(int response_code, const std::string& data,
+ DirectoryAddRequest::Result expected_result,
+ const std::string& expected_message) {
+ MockDoneCallback callback;
+ EXPECT_CALL(callback, OnDone(expected_result, expected_message))
+ .Times(1);
+
+ target_->done_callback_.reset(
+ NewCallback(&callback, &MockDoneCallback::OnDone));
+
+ GURL url;
+ URLRequestStatus status_ok;
+ ResponseCookies cookies;
+ target_->OnURLFetchComplete(NULL, url, status_ok, response_code,
+ cookies, data);
+ }
+
+ TestingProfile profile_;
+ scoped_ptr<DirectoryAddRequest> target_;
+};
+
+TEST_F(DirectoryAddRequestTest, Success) {
+ TestResult(200, "{\"data\":{\"kind\":\"chromoting#host\","
+ "\"hostId\":\"e64906c9-fdc9-4921-80cb-563cf7f564f3\","
+ "\"hostName\":\"host_name\",\"publicKey\":\"PUBLIC+KEY\"}}",
+ DirectoryAddRequest::SUCCESS, "");
+}
+
+TEST_F(DirectoryAddRequestTest, Duplicate) {
+ TestResult(400, "{\"error\":{\"errors\":[{\"domain\":\"global\","
+ "\"reason\":\"invalid\",\"message\":\"Attempt to register "
+ "a duplicate host.\"}],\"code\":400,\"message\":\"Attempt to "
+ "register a duplicate host.\"}}",
+ DirectoryAddRequest::ERROR_EXISTS,
+ "Attempt to register a duplicate host.");
+}
+
+TEST_F(DirectoryAddRequestTest, InvalidRequest) {
+ TestResult(400, "{\"error\":{\"errors\":[{\"domain\":\"global\","
+ "\"reason\":\"invalid\",\"message\":\"Invalid Value\"}],"
+ "\"code\":400,\"message\":\"Invalid Value\"}}",
+ DirectoryAddRequest::ERROR_INVALID_REQUEST,
+ "Invalid Value");
+}
+
+TEST_F(DirectoryAddRequestTest, InvalidToken) {
+ TestResult(401, "{\"error\":{\"errors\":[{\"domain\":\"global\","
+ "\"reason\":\"invalid\",\"message\":\"Token invalid\","
+ "\"locationType\":\"header\",\"location\":\"Authorization\"}],"
+ "\"code\":401,\"message\":\"Token invalid\"}}",
+ DirectoryAddRequest::ERROR_AUTH,
+ "Token invalid");
+}
+
+} // namespace remoting
diff --git a/chrome/browser/remoting/remoting_resources_source.cc b/chrome/browser/remoting/remoting_resources_source.cc
index 6be7cbc..9057e1d 100644
--- a/chrome/browser/remoting/remoting_resources_source.cc
+++ b/chrome/browser/remoting/remoting_resources_source.cc
@@ -4,12 +4,14 @@
#include "chrome/browser/remoting/remoting_resources_source.h"
+#include <algorithm>
+#include <string>
+
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/message_loop.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/jstemplate_builder.h"
@@ -111,6 +113,11 @@ void RemotingResourcesSource::StartDataRequest(const std::string& path_raw,
SendResponse(request_id, html_bytes);
}
+std::string RemotingResourcesSource::GetMimeType(
+ const std::string& path) const {
+ return "text/html";
+}
+
std::string RemotingResourcesSource::GetLocalizedUrl(
const std::string& url) const {
GURL original_url(url);
diff --git a/chrome/browser/remoting/remoting_resources_source.h b/chrome/browser/remoting/remoting_resources_source.h
index 96d1b4d..4d73d8e 100644
--- a/chrome/browser/remoting/remoting_resources_source.h
+++ b/chrome/browser/remoting/remoting_resources_source.h
@@ -13,9 +13,7 @@ class RemotingResourcesSource : public ChromeURLDataManager::DataSource {
bool is_off_the_record,
int request_id);
- virtual std::string GetMimeType(const std::string& path) const {
- return "text/html";
- }
+ virtual std::string GetMimeType(const std::string& path) const;
static const char kInvalidPasswordHelpUrl[];
static const char kCanNotAccessAccountUrl[];
diff --git a/chrome/browser/remoting/remoting_setup_flow.cc b/chrome/browser/remoting/remoting_setup_flow.cc
index a7975bc..05c7590 100644
--- a/chrome/browser/remoting/remoting_setup_flow.cc
+++ b/chrome/browser/remoting/remoting_setup_flow.cc
@@ -10,11 +10,12 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
+#include "chrome/browser/browser_thread.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
#include "chrome/browser/dom_ui/dom_ui_util.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/remoting/remoting_resources_source.h"
#include "chrome/browser/remoting/remoting_setup_message_handler.h"
#include "chrome/browser/renderer_host/render_view_host.h"
@@ -101,7 +102,7 @@ RemotingSetupFlow::RemotingSetupFlow(const std::string& args, Profile* profile)
// TODO(hclam): The data source should be added once.
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(Singleton<ChromeURLDataManager>::get(),
+ NewRunnableMethod(ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(new RemotingResourcesSource())));
}
@@ -208,7 +209,7 @@ void RemotingSetupFlow::OnIssueAuthTokenSuccess(const std::string& service,
// If we have already connected to the service process then submit the tokens
// to it to register the host.
process_control_ =
- ServiceProcessControlManager::instance()->GetProcessControl(profile_);
+ ServiceProcessControlManager::GetInstance()->GetProcessControl(profile_);
if (process_control_->is_connected()) {
// TODO(hclam): Need to figure out what to do when the service process is
@@ -261,8 +262,8 @@ void RemotingSetupFlow::OnUserSubmittedAuth(const std::string& user,
void RemotingSetupFlow::OnProcessLaunched() {
DCHECK(process_control_->is_connected());
// TODO(hclam): Need to wait for an ACK to be sure that it is actually active.
- process_control_->EnableRemotingWithTokens(login_, remoting_token_,
- sync_token_);
+ process_control_->SetRemotingHostCredentials(login_, sync_token_);
+ process_control_->EnableRemotingHost();
// Save the preference that we have completed the setup of remoting.
profile_->GetPrefs()->SetBoolean(prefs::kRemotingHasSetupCompleted, true);
diff --git a/chrome/browser/renderer_host/accelerated_surface_container_mac.cc b/chrome/browser/renderer_host/accelerated_surface_container_mac.cc
index 1a7c07c..f379931 100644
--- a/chrome/browser/renderer_host/accelerated_surface_container_mac.cc
+++ b/chrome/browser/renderer_host/accelerated_surface_container_mac.cc
@@ -7,7 +7,7 @@
#include "app/surface/io_surface_support_mac.h"
#include "base/logging.h"
#include "chrome/browser/renderer_host/accelerated_surface_container_manager_mac.h"
-#include "webkit/glue/plugins/webplugin.h"
+#include "webkit/plugins/npapi/webplugin.h"
AcceleratedSurfaceContainerMac::AcceleratedSurfaceContainerMac(
AcceleratedSurfaceContainerManagerMac* manager,
@@ -51,7 +51,7 @@ void AcceleratedSurfaceContainerMac::SetSizeAndTransportDIB(
}
void AcceleratedSurfaceContainerMac::SetGeometry(
- const webkit_glue::WebPluginGeometry& geom) {
+ const webkit::npapi::WebPluginGeometry& geom) {
visible_ = geom.visible;
if (geom.rects_valid)
clip_rect_ = geom.clip_rect;
diff --git a/chrome/browser/renderer_host/accelerated_surface_container_mac.h b/chrome/browser/renderer_host/accelerated_surface_container_mac.h
index deda9ef..45979e0 100644
--- a/chrome/browser/renderer_host/accelerated_surface_container_mac.h
+++ b/chrome/browser/renderer_host/accelerated_surface_container_mac.h
@@ -36,9 +36,11 @@
#include "gfx/native_widget_types.h"
#include "gfx/rect.h"
-namespace webkit_glue {
+namespace webkit {
+namespace npapi {
struct WebPluginGeometry;
}
+}
class AcceleratedSurfaceContainerManagerMac;
@@ -65,7 +67,7 @@ class AcceleratedSurfaceContainerMac {
// currently only pays attention to the clip width and height, since the
// view in which it is hosted is responsible for positioning it on the
// page.)
- void SetGeometry(const webkit_glue::WebPluginGeometry& geom);
+ void SetGeometry(const webkit::npapi::WebPluginGeometry& geom);
// Draws this accelerated surface's contents, texture mapped onto a quad in
// the given OpenGL context. TODO(kbr): figure out and define exactly how the
diff --git a/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.cc b/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.cc
index 1ad09ba..a96782b 100644
--- a/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.cc
+++ b/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.cc
@@ -6,7 +6,7 @@
#include "base/logging.h"
#include "chrome/browser/renderer_host/accelerated_surface_container_mac.h"
-#include "webkit/glue/plugins/webplugin.h"
+#include "webkit/plugins/npapi/webplugin.h"
AcceleratedSurfaceContainerManagerMac::AcceleratedSurfaceContainerManagerMac()
: current_id_(0),
@@ -86,7 +86,7 @@ void AcceleratedSurfaceContainerManagerMac::SetSizeAndTransportDIB(
}
void AcceleratedSurfaceContainerManagerMac::SetPluginContainerGeometry(
- const webkit_glue::WebPluginGeometry& move) {
+ const webkit::npapi::WebPluginGeometry& move) {
AutoLock lock(lock_);
AcceleratedSurfaceContainerMac* container = MapIDToContainer(move.window);
diff --git a/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.h b/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.h
index a03a5c4..a2855a4 100644
--- a/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.h
+++ b/chrome/browser/renderer_host/accelerated_surface_container_manager_mac.h
@@ -14,9 +14,11 @@
#include "base/lock.h"
#include "gfx/native_widget_types.h"
-namespace webkit_glue {
+namespace webkit {
+namespace npapi {
struct WebPluginGeometry;
}
+}
class AcceleratedSurfaceContainerMac;
@@ -63,7 +65,8 @@ class AcceleratedSurfaceContainerManagerMac {
// Takes an update from WebKit about a plugin's position and size and moves
// the plugin accordingly.
- void SetPluginContainerGeometry(const webkit_glue::WebPluginGeometry& move);
+ void SetPluginContainerGeometry(
+ const webkit::npapi::WebPluginGeometry& move);
// Draws the plugin container associated with the given id into the given
// OpenGL context, which must already be current.
diff --git a/chrome/browser/renderer_host/async_resource_handler.cc b/chrome/browser/renderer_host/async_resource_handler.cc
index 70dfc74..8f84d08 100644
--- a/chrome/browser/renderer_host/async_resource_handler.cc
+++ b/chrome/browser/renderer_host/async_resource_handler.cc
@@ -4,16 +4,19 @@
#include "chrome/browser/renderer_host/async_resource_handler.h"
+#include <algorithm>
+#include <vector>
+
#include "base/hash_tables.h"
#include "base/logging.h"
-#include "base/process.h"
#include "base/shared_memory.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/debugger/devtools_netlog_observer.h"
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/browser/net/load_timing_observer.h"
#include "chrome/browser/renderer_host/global_request_id.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
+#include "chrome/browser/renderer_host/resource_message_filter.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/resource_response.h"
#include "net/base/io_buffer.h"
@@ -72,16 +75,12 @@ class SharedIOBuffer : public net::IOBuffer {
};
AsyncResourceHandler::AsyncResourceHandler(
- ResourceDispatcherHost::Receiver* receiver,
- int process_id,
+ ResourceMessageFilter* filter,
int routing_id,
- base::ProcessHandle process_handle,
const GURL& url,
ResourceDispatcherHost* resource_dispatcher_host)
- : receiver_(receiver),
- process_id_(process_id),
+ : filter_(filter),
routing_id_(routing_id),
- process_handle_(process_handle),
rdh_(resource_dispatcher_host),
next_buffer_size_(kInitialReadBufSize) {
}
@@ -92,9 +91,9 @@ AsyncResourceHandler::~AsyncResourceHandler() {
bool AsyncResourceHandler::OnUploadProgress(int request_id,
uint64 position,
uint64 size) {
- return receiver_->Send(new ViewMsg_Resource_UploadProgress(routing_id_,
- request_id,
- position, size));
+ return filter_->Send(new ViewMsg_Resource_UploadProgress(routing_id_,
+ request_id,
+ position, size));
}
bool AsyncResourceHandler::OnRequestRedirected(int request_id,
@@ -102,11 +101,11 @@ bool AsyncResourceHandler::OnRequestRedirected(int request_id,
ResourceResponse* response,
bool* defer) {
*defer = true;
- URLRequest* request = rdh_->GetURLRequest(
- GlobalRequestID(process_id_, request_id));
+ net::URLRequest* request = rdh_->GetURLRequest(
+ GlobalRequestID(filter_->child_id(), request_id));
LoadTimingObserver::PopulateTimingInfo(request, response);
DevToolsNetLogObserver::PopulateResponseInfo(request, response);
- return receiver_->Send(new ViewMsg_Resource_ReceivedRedirect(
+ return filter_->Send(new ViewMsg_Resource_ReceivedRedirect(
routing_id_, request_id, new_url, response->response_head));
}
@@ -117,8 +116,8 @@ bool AsyncResourceHandler::OnResponseStarted(int request_id,
// renderer will be able to set these precisely at the time the
// request commits, avoiding the possibility of e.g. zooming the old content
// or of having to layout the new content twice.
- URLRequest* request = rdh_->GetURLRequest(
- GlobalRequestID(process_id_, request_id));
+ net::URLRequest* request = rdh_->GetURLRequest(
+ GlobalRequestID(filter_->child_id(), request_id));
LoadTimingObserver::PopulateTimingInfo(request, response);
DevToolsNetLogObserver::PopulateResponseInfo(request, response);
@@ -129,23 +128,23 @@ bool AsyncResourceHandler::OnResponseStarted(int request_id,
ChromeURLRequestContext* context =
static_cast<ChromeURLRequestContext*>(request->context());
if (context) {
- receiver_->Send(new ViewMsg_SetContentSettingsForLoadingURL(
+ filter_->Send(new ViewMsg_SetContentSettingsForLoadingURL(
info->route_id(), request_url,
context->host_content_settings_map()->GetContentSettings(
request_url)));
- receiver_->Send(new ViewMsg_SetZoomLevelForLoadingURL(info->route_id(),
+ filter_->Send(new ViewMsg_SetZoomLevelForLoadingURL(info->route_id(),
request_url, context->host_zoom_map()->GetZoomLevel(request_url)));
}
}
- receiver_->Send(new ViewMsg_Resource_ReceivedResponse(
+ filter_->Send(new ViewMsg_Resource_ReceivedResponse(
routing_id_, request_id, response->response_head));
if (request->response_info().metadata) {
std::vector<char> copy(request->response_info().metadata->data(),
request->response_info().metadata->data() +
request->response_info().metadata->size());
- receiver_->Send(new ViewMsg_Resource_ReceivedCachedMetadata(
+ filter_->Send(new ViewMsg_Resource_ReceivedCachedMetadata(
routing_id_, request_id, copy));
}
@@ -196,18 +195,19 @@ bool AsyncResourceHandler::OnReadCompleted(int request_id, int* bytes_read) {
next_buffer_size_ = std::min(next_buffer_size_ * 2, kMaxReadBufSize);
}
- if (!rdh_->WillSendData(process_id_, request_id)) {
+ if (!rdh_->WillSendData(filter_->child_id(), request_id)) {
// We should not send this data now, we have too many pending requests.
return true;
}
base::SharedMemoryHandle handle;
- if (!read_buffer_->shared_memory()->GiveToProcess(process_handle_, &handle)) {
+ if (!read_buffer_->shared_memory()->GiveToProcess(
+ filter_->peer_handle(), &handle)) {
// We wrongfully incremented the pending data count. Fake an ACK message
// to fix this. We can't move this call above the WillSendData because
// it's killing our read_buffer_, and we don't want that when we pause
// the request.
- rdh_->DataReceivedACK(process_id_, request_id);
+ rdh_->DataReceivedACK(filter_->child_id(), request_id);
// We just unmapped the memory.
read_buffer_ = NULL;
return false;
@@ -215,7 +215,7 @@ bool AsyncResourceHandler::OnReadCompleted(int request_id, int* bytes_read) {
// We just unmapped the memory.
read_buffer_ = NULL;
- receiver_->Send(new ViewMsg_Resource_DataReceived(
+ filter_->Send(new ViewMsg_Resource_DataReceived(
routing_id_, request_id, handle, *bytes_read));
return true;
@@ -223,7 +223,7 @@ bool AsyncResourceHandler::OnReadCompleted(int request_id, int* bytes_read) {
void AsyncResourceHandler::OnDataDownloaded(
int request_id, int bytes_downloaded) {
- receiver_->Send(new ViewMsg_Resource_DataDownloaded(
+ filter_->Send(new ViewMsg_Resource_DataDownloaded(
routing_id_, request_id, bytes_downloaded));
}
@@ -232,11 +232,11 @@ bool AsyncResourceHandler::OnResponseCompleted(
const URLRequestStatus& status,
const std::string& security_info) {
Time completion_time = Time::Now();
- receiver_->Send(new ViewMsg_Resource_RequestComplete(routing_id_,
- request_id,
- status,
- security_info,
- completion_time));
+ filter_->Send(new ViewMsg_Resource_RequestComplete(routing_id_,
+ request_id,
+ status,
+ security_info,
+ completion_time));
// If we still have a read buffer, then see about caching it for later...
// Note that we have to make sure the buffer is not still being used, so we
diff --git a/chrome/browser/renderer_host/async_resource_handler.h b/chrome/browser/renderer_host/async_resource_handler.h
index be89d87..2b0df7d 100644
--- a/chrome/browser/renderer_host/async_resource_handler.h
+++ b/chrome/browser/renderer_host/async_resource_handler.h
@@ -8,48 +8,44 @@
#include <string>
-#include "base/process.h"
-#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/renderer_host/resource_handler.h"
+class ResourceDispatcherHost;
+class ResourceMessageFilter;
class SharedIOBuffer;
// Used to complete an asynchronous resource request in response to resource
// load events from the resource dispatcher host.
class AsyncResourceHandler : public ResourceHandler {
public:
- AsyncResourceHandler(ResourceDispatcherHost::Receiver* receiver,
- int process_id,
+ AsyncResourceHandler(ResourceMessageFilter* filter,
int routing_id,
- base::ProcessHandle process_handle,
const GURL& url,
ResourceDispatcherHost* resource_dispatcher_host);
// ResourceHandler implementation:
- bool OnUploadProgress(int request_id, uint64 position, uint64 size);
- bool OnRequestRedirected(int request_id, const GURL& new_url,
- ResourceResponse* response, bool* defer);
- bool OnResponseStarted(int request_id, ResourceResponse* response);
- bool OnWillStart(int request_id, const GURL& url, bool* defer);
- bool OnWillRead(int request_id, net::IOBuffer** buf, int* buf_size,
- int min_size);
- bool OnReadCompleted(int request_id, int* bytes_read);
- bool OnResponseCompleted(int request_id,
- const URLRequestStatus& status,
- const std::string& security_info);
- void OnRequestClosed();
- void OnDataDownloaded(int request_id, int bytes_downloaded);
+ virtual bool OnUploadProgress(int request_id, uint64 position, uint64 size);
+ virtual bool OnRequestRedirected(int request_id, const GURL& new_url,
+ ResourceResponse* response, bool* defer);
+ virtual bool OnResponseStarted(int request_id, ResourceResponse* response);
+ virtual bool OnWillStart(int request_id, const GURL& url, bool* defer);
+ virtual bool OnWillRead(int request_id, net::IOBuffer** buf, int* buf_size,
+ int min_size);
+ virtual bool OnReadCompleted(int request_id, int* bytes_read);
+ virtual bool OnResponseCompleted(int request_id,
+ const URLRequestStatus& status,
+ const std::string& security_info);
+ virtual void OnRequestClosed();
+ virtual void OnDataDownloaded(int request_id, int bytes_downloaded);
static void GlobalCleanup();
private:
- ~AsyncResourceHandler();
+ virtual ~AsyncResourceHandler();
scoped_refptr<SharedIOBuffer> read_buffer_;
- ResourceDispatcherHost::Receiver* receiver_;
- int process_id_;
+ ResourceMessageFilter* filter_;
int routing_id_;
- base::ProcessHandle process_handle_;
ResourceDispatcherHost* rdh_;
// |next_buffer_size_| is the size of the buffer to be allocated on the next
diff --git a/chrome/browser/renderer_host/audio_renderer_host.cc b/chrome/browser/renderer_host/audio_renderer_host.cc
index e77153e..1b5ce0a 100644
--- a/chrome/browser/renderer_host/audio_renderer_host.cc
+++ b/chrome/browser/renderer_host/audio_renderer_host.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// 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.
@@ -48,54 +48,24 @@ AudioRendererHost::AudioEntry::~AudioEntry() {}
///////////////////////////////////////////////////////////////////////////////
// AudioRendererHost implementations.
-AudioRendererHost::AudioRendererHost()
- : process_id_(0),
- process_handle_(0),
- ipc_sender_(NULL) {
- // Increase the ref count of this object so it is active until we do
- // Release().
- AddRef();
+AudioRendererHost::AudioRendererHost() {
}
AudioRendererHost::~AudioRendererHost() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DCHECK(audio_entries_.empty());
-
- // Make sure we received IPCChannelClosing() signal.
- DCHECK(!ipc_sender_);
- DCHECK(!process_handle_);
-}
-
-void AudioRendererHost::Destroy() {
- // Post a message to the thread where this object should live and do the
- // actual operations there.
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(this, &AudioRendererHost::DoDestroy));
-}
-
-// Event received when IPC channel is connected to the renderer process.
-void AudioRendererHost::IPCChannelConnected(int process_id,
- base::ProcessHandle process_handle,
- IPC::Message::Sender* ipc_sender) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- process_handle_ = process_handle;
- ipc_sender_ = ipc_sender;
}
-// Event received when IPC channel is closing.
-void AudioRendererHost::IPCChannelClosing() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- // Reset IPC related member variables.
- ipc_sender_ = NULL;
- process_handle_ = 0;
+void AudioRendererHost::OnChannelClosing() {
+ BrowserMessageFilter::OnChannelClosing();
// Since the IPC channel is gone, close all requested audio streams.
DeleteEntries();
}
+void AudioRendererHost::OnDestruct() const {
+ BrowserThread::DeleteOnIOThread::Destruct(this);
+}
+
///////////////////////////////////////////////////////////////////////////////
// media::AudioOutputController::EventHandler implementations.
void AudioRendererHost::OnCreated(media::AudioOutputController* controller) {
@@ -158,7 +128,7 @@ void AudioRendererHost::DoCompleteCreation(
if (!entry)
return;
- if (!process_handle_) {
+ if (!peer_handle()) {
NOTREACHED() << "Renderer process handle is invalid.";
DeleteEntryOnError(entry);
return;
@@ -167,8 +137,8 @@ void AudioRendererHost::DoCompleteCreation(
// Once the audio stream is created then complete the creation process by
// mapping shared memory and sharing with the renderer process.
base::SharedMemoryHandle foreign_memory_handle;
- if (!entry->shared_memory.ShareToProcess(process_handle_,
- &foreign_memory_handle)) {
+ if (!entry->shared_memory.ShareToProcess(peer_handle(),
+ &foreign_memory_handle)) {
// If we failed to map and share the shared memory then close the audio
// stream and send an error message.
DeleteEntryOnError(entry);
@@ -187,13 +157,13 @@ void AudioRendererHost::DoCompleteCreation(
// If we failed to prepare the sync socket for the renderer then we fail
// the construction of audio stream.
- if (!reader->PrepareForeignSocketHandle(process_handle_,
+ if (!reader->PrepareForeignSocketHandle(peer_handle(),
&foreign_socket_handle)) {
DeleteEntryOnError(entry);
return;
}
- SendMessage(new ViewMsg_NotifyLowLatencyAudioStreamCreated(
+ Send(new ViewMsg_NotifyLowLatencyAudioStreamCreated(
entry->render_view_id, entry->stream_id, foreign_memory_handle,
foreign_socket_handle, entry->shared_memory.created_size()));
return;
@@ -201,7 +171,7 @@ void AudioRendererHost::DoCompleteCreation(
// The normal audio stream has created, send a message to the renderer
// process.
- SendMessage(new ViewMsg_NotifyAudioStreamCreated(
+ Send(new ViewMsg_NotifyAudioStreamCreated(
entry->render_view_id, entry->stream_id, foreign_memory_handle,
entry->shared_memory.created_size()));
}
@@ -216,7 +186,7 @@ void AudioRendererHost::DoSendPlayingMessage(
ViewMsg_AudioStreamState_Params params;
params.state = ViewMsg_AudioStreamState_Params::kPlaying;
- SendMessage(new ViewMsg_NotifyAudioStreamStateChanged(
+ Send(new ViewMsg_NotifyAudioStreamStateChanged(
entry->render_view_id, entry->stream_id, params));
}
@@ -230,7 +200,7 @@ void AudioRendererHost::DoSendPausedMessage(
ViewMsg_AudioStreamState_Params params;
params.state = ViewMsg_AudioStreamState_Params::kPaused;
- SendMessage(new ViewMsg_NotifyAudioStreamStateChanged(
+ Send(new ViewMsg_NotifyAudioStreamStateChanged(
entry->render_view_id, entry->stream_id, params));
}
@@ -246,9 +216,8 @@ void AudioRendererHost::DoRequestMoreData(
DCHECK(!entry->controller->LowLatencyMode());
entry->pending_buffer_request = true;
- SendMessage(
- new ViewMsg_RequestAudioPacket(
- entry->render_view_id, entry->stream_id, buffers_state));
+ Send(new ViewMsg_RequestAudioPacket(
+ entry->render_view_id, entry->stream_id, buffers_state));
}
void AudioRendererHost::DoHandleError(media::AudioOutputController* controller,
@@ -266,10 +235,7 @@ void AudioRendererHost::DoHandleError(media::AudioOutputController* controller,
// IPC Messages handler
bool AudioRendererHost::OnMessageReceived(const IPC::Message& message,
bool* message_was_ok) {
- if (!IsAudioRendererHostMessage(message))
- return false;
- *message_was_ok = true;
-
+ bool handled = true;
IPC_BEGIN_MESSAGE_MAP_EX(AudioRendererHost, message, *message_was_ok)
IPC_MESSAGE_HANDLER(ViewHostMsg_CreateAudioStream, OnCreateStream)
IPC_MESSAGE_HANDLER(ViewHostMsg_PlayAudioStream, OnPlayStream)
@@ -279,27 +245,10 @@ bool AudioRendererHost::OnMessageReceived(const IPC::Message& message,
IPC_MESSAGE_HANDLER(ViewHostMsg_NotifyAudioPacketReady, OnNotifyPacketReady)
IPC_MESSAGE_HANDLER(ViewHostMsg_GetAudioVolume, OnGetVolume)
IPC_MESSAGE_HANDLER(ViewHostMsg_SetAudioVolume, OnSetVolume)
+ IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP_EX()
- return true;
-}
-
-bool AudioRendererHost::IsAudioRendererHostMessage(
- const IPC::Message& message) {
- switch (message.type()) {
- case ViewHostMsg_CreateAudioStream::ID:
- case ViewHostMsg_PlayAudioStream::ID:
- case ViewHostMsg_PauseAudioStream::ID:
- case ViewHostMsg_FlushAudioStream::ID:
- case ViewHostMsg_CloseAudioStream::ID:
- case ViewHostMsg_NotifyAudioPacketReady::ID:
- case ViewHostMsg_GetAudioVolume::ID:
- case ViewHostMsg_SetAudioVolume::ID:
- return true;
- default:
- break;
- }
- return false;
+ return handled;
}
void AudioRendererHost::OnCreateStream(
@@ -419,8 +368,7 @@ void AudioRendererHost::OnSetVolume(const IPC::Message& msg, int stream_id,
}
// Make sure the volume is valid.
- if (volume < 0 || volume > 1.0)
- return;
+ CHECK(volume >= 0 && volume <= 1.0);
entry->controller->SetVolume(volume);
}
@@ -453,32 +401,11 @@ void AudioRendererHost::OnNotifyPacketReady(
packet_size);
}
-void AudioRendererHost::DoDestroy() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- // Reset IPC releated members.
- ipc_sender_ = NULL;
- process_handle_ = 0;
-
- // Close all audio streams.
- DeleteEntries();
-
- // Decrease the reference to this object, which may lead to self-destruction.
- Release();
-}
-
-void AudioRendererHost::SendMessage(IPC::Message* message) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- if (ipc_sender_)
- ipc_sender_->Send(message);
-}
-
void AudioRendererHost::SendErrorMessage(int32 render_view_id,
int32 stream_id) {
ViewMsg_AudioStreamState_Params state;
state.state = ViewMsg_AudioStreamState_Params::kError;
- SendMessage(new ViewMsg_NotifyAudioStreamStateChanged(
+ Send(new ViewMsg_NotifyAudioStreamStateChanged(
render_view_id, stream_id, state));
}
@@ -532,7 +459,7 @@ AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(
AudioEntryMap::iterator i = audio_entries_.find(
AudioEntryId(route_id, stream_id));
- if (i != audio_entries_.end() && !i->second->pending_close)
+ if (i != audio_entries_.end())
return i->second;
return NULL;
}
@@ -545,7 +472,7 @@ AudioRendererHost::AudioEntry* AudioRendererHost::LookupByController(
// TODO(hclam): Implement a faster look up method.
for (AudioEntryMap::iterator i = audio_entries_.begin();
i != audio_entries_.end(); ++i) {
- if (!i->second->pending_close && controller == i->second->controller.get())
+ if (controller == i->second->controller.get())
return i->second;
}
return NULL;
diff --git a/chrome/browser/renderer_host/audio_renderer_host.h b/chrome/browser/renderer_host/audio_renderer_host.h
index 85311ab..b91be77 100644
--- a/chrome/browser/renderer_host/audio_renderer_host.h
+++ b/chrome/browser/renderer_host/audio_renderer_host.h
@@ -6,17 +6,12 @@
// lives inside the render process and provide access to audio hardware.
//
// This class is owned by BrowserRenderProcessHost, and instantiated on UI
-// thread, but all other operations and method calls (except Destroy()) happens
-// in IO thread, so we need to be extra careful about the lifetime of this
-// object. AudioManager is a singleton and created in IO thread, audio output
-// streams are also created in the IO thread, so we need to destroy them also
-// in IO thread. After this class is created, a task of OnInitialized() is
-// posted on IO thread in which singleton of AudioManager is created and
-// AddRef() is called to increase one ref count of this object. Owner of this
-// class should call Destroy() before decrementing the ref count to this object,
-// which essentially post a task of OnDestroyed() on IO thread. Inside
-// OnDestroyed(), audio output streams are destroyed and Release() is called
-// which may result in self-destruction.
+// thread, but all other operations and method calls happen on IO thread, so we
+// need to be extra careful about the lifetime of this object. AudioManager is a
+// singleton and created in IO thread, audio output streams are also created in
+// the IO thread, so we need to destroy them also in IO thread. After this class
+// is created, a task of OnInitialized() is posted on IO thread in which
+// singleton of AudioManager is created and.
//
// Here's an example of a typical IPC dialog for audio:
//
@@ -65,6 +60,7 @@
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "base/shared_memory.h"
+#include "chrome/browser/browser_message_filter.h"
#include "chrome/browser/browser_thread.h"
#include "ipc/ipc_message.h"
#include "media/audio/audio_io.h"
@@ -74,9 +70,7 @@
class AudioManager;
struct ViewHostMsg_Audio_CreateStream_Params;
-class AudioRendererHost : public base::RefCountedThreadSafe<
- AudioRendererHost,
- BrowserThread::DeleteOnIOThread>,
+class AudioRendererHost : public BrowserMessageFilter,
public media::AudioOutputController::EventHandler {
public:
typedef std::pair<int32, int> AudioEntryId;
@@ -112,24 +106,12 @@ class AudioRendererHost : public base::RefCountedThreadSafe<
// Called from UI thread from the owner of this object.
AudioRendererHost();
- // Called from UI thread from the owner of this object to kick start
- // destruction of streams in IO thread.
- void Destroy();
- /////////////////////////////////////////////////////////////////////////////
- // The following public methods are called from ResourceMessageFilter in the
- // IO thread.
-
- // Event received when IPC channel is connected with the renderer process.
- void IPCChannelConnected(int process_id, base::ProcessHandle process_handle,
- IPC::Message::Sender* ipc_sender);
-
- // Event received when IPC channel is closing.
- void IPCChannelClosing();
-
- // Returns true if the message is a audio related message and was processed.
- // If it was, message_was_ok will be false iff the message was corrupt.
- bool OnMessageReceived(const IPC::Message& message, bool* message_was_ok);
+ // BrowserMessageFilter implementation.
+ virtual void OnChannelClosing();
+ virtual void OnDestruct() const;
+ virtual bool OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok);
/////////////////////////////////////////////////////////////////////////////
// AudioOutputController::EventHandler implementations.
@@ -187,9 +169,6 @@ class AudioRendererHost : public base::RefCountedThreadSafe<
void OnNotifyPacketReady(const IPC::Message& msg, int stream_id,
uint32 packet_size);
- // Release all acquired resources and decrease reference to this object.
- void DoDestroy();
-
// Complete the process of creating an audio stream. This will set up the
// shared memory or shared socket in low latency mode.
void DoCompleteCreation(media::AudioOutputController* controller);
@@ -206,10 +185,6 @@ class AudioRendererHost : public base::RefCountedThreadSafe<
// Handle error coming from audio stream.
void DoHandleError(media::AudioOutputController* controller, int error_code);
- // A helper method to send an IPC message to renderer process on IO thread.
- // This method is virtual for testing purpose.
- virtual void SendMessage(IPC::Message* message);
-
// Send an error message to the renderer.
void SendErrorMessage(int32 render_view_id, int32 stream_id);
@@ -239,10 +214,6 @@ class AudioRendererHost : public base::RefCountedThreadSafe<
// event is received.
AudioEntry* LookupByController(media::AudioOutputController* controller);
- int process_id_;
- base::ProcessHandle process_handle_;
- IPC::Message::Sender* ipc_sender_;
-
// A map of id to audio sources.
AudioEntryMap audio_entries_;
diff --git a/chrome/browser/renderer_host/audio_renderer_host_unittest.cc b/chrome/browser/renderer_host/audio_renderer_host_unittest.cc
index 7c3b500..a71401f 100644
--- a/chrome/browser/renderer_host/audio_renderer_host_unittest.cc
+++ b/chrome/browser/renderer_host/audio_renderer_host_unittest.cc
@@ -67,7 +67,7 @@ class MockAudioRendererHost : public AudioRendererHost {
// This method is used to dispatch IPC messages to the renderer. We intercept
// these messages here and dispatch to our mock methods to verify the
// conversation between this object and the renderer.
- virtual void SendMessage(IPC::Message* message) {
+ virtual bool Send(IPC::Message* message) {
CHECK(message);
// In this method we dispatch the messages to the according handlers as if
@@ -86,6 +86,7 @@ class MockAudioRendererHost : public AudioRendererHost {
EXPECT_TRUE(handled);
delete message;
+ return true;
}
// These handler methods do minimal things and delegate to the mock methods.
@@ -175,20 +176,15 @@ class AudioRendererHostTest : public testing::Test {
host_ = new MockAudioRendererHost();
// Simulate IPC channel connected.
- host_->IPCChannelConnected(base::GetCurrentProcId(),
- base::GetCurrentProcessHandle(),
- NULL);
+ host_->OnChannelConnected(base::GetCurrentProcId());
}
virtual void TearDown() {
// Simulate closing the IPC channel.
- host_->IPCChannelClosing();
-
- // This task post a task to message_loop_ to do internal destruction on
- // message_loop_.
- host_->Destroy();
+ host_->OnChannelClosing();
- // Release the reference to the mock object.
+ // Release the reference to the mock object. The object will be destructed
+ // on message_loop_.
host_ = NULL;
// We need to continue running message_loop_ to complete all destructions.
diff --git a/chrome/browser/renderer_host/blob_dispatcher_host.cc b/chrome/browser/renderer_host/blob_dispatcher_host.cc
deleted file mode 100644
index 1946b68..0000000
--- a/chrome/browser/renderer_host/blob_dispatcher_host.cc
+++ /dev/null
@@ -1,88 +0,0 @@
-// 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.
-
-#include "chrome/browser/renderer_host/blob_dispatcher_host.h"
-
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/child_process_security_policy.h"
-#include "chrome/browser/chrome_blob_storage_context.h"
-#include "chrome/common/render_messages.h"
-#include "googleurl/src/gurl.h"
-#include "ipc/ipc_message.h"
-#include "webkit/blob/blob_data.h"
-#include "webkit/blob/blob_storage_controller.h"
-
-BlobDispatcherHost::BlobDispatcherHost(
- int process_id,
- ChromeBlobStorageContext* blob_storage_context)
- : process_id_(process_id),
- blob_storage_context_(blob_storage_context) {
-}
-
-BlobDispatcherHost::~BlobDispatcherHost() {
-}
-
-void BlobDispatcherHost::Shutdown() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- // Unregister all the blob URLs that are previously registered in this
- // process.
- for (base::hash_set<std::string>::const_iterator iter = blob_urls_.begin();
- iter != blob_urls_.end(); ++iter) {
- blob_storage_context_->controller()->UnregisterBlobUrl(GURL(*iter));
- }
-}
-
-bool BlobDispatcherHost::OnMessageReceived(const IPC::Message& message,
- bool* msg_is_ok) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- *msg_is_ok = true;
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP_EX(BlobDispatcherHost, message, *msg_is_ok)
- IPC_MESSAGE_HANDLER(ViewHostMsg_RegisterBlobUrl, OnRegisterBlobUrl)
- IPC_MESSAGE_HANDLER(ViewHostMsg_RegisterBlobUrlFrom, OnRegisterBlobUrlFrom)
- IPC_MESSAGE_HANDLER(ViewHostMsg_UnregisterBlobUrl, OnUnregisterBlobUrl)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-// Check if the child process has been granted permission to register the files.
-bool BlobDispatcherHost::CheckPermission(
- webkit_blob::BlobData* blob_data) const {
- ChildProcessSecurityPolicy* policy =
- ChildProcessSecurityPolicy::GetInstance();
- for (std::vector<webkit_blob::BlobData::Item>::const_iterator iter =
- blob_data->items().begin();
- iter != blob_data->items().end(); ++iter) {
- if (iter->type() == webkit_blob::BlobData::TYPE_FILE) {
- if (!policy->CanReadFile(process_id_, iter->file_path()))
- return false;
- }
- }
- return true;
-}
-
-void BlobDispatcherHost::OnRegisterBlobUrl(
- const GURL& url, const scoped_refptr<webkit_blob::BlobData>& blob_data) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (!CheckPermission(blob_data.get()))
- return;
- blob_storage_context_->controller()->RegisterBlobUrl(url, blob_data);
- blob_urls_.insert(url.spec());
-}
-
-void BlobDispatcherHost::OnRegisterBlobUrlFrom(
- const GURL& url, const GURL& src_url) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- blob_storage_context_->controller()->RegisterBlobUrlFrom(url, src_url);
- blob_urls_.insert(url.spec());
-}
-
-void BlobDispatcherHost::OnUnregisterBlobUrl(const GURL& url) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- blob_storage_context_->controller()->UnregisterBlobUrl(url);
- blob_urls_.erase(url.spec());
-}
diff --git a/chrome/browser/renderer_host/blob_dispatcher_host.h b/chrome/browser/renderer_host/blob_dispatcher_host.h
deleted file mode 100644
index 8ba95ff..0000000
--- a/chrome/browser/renderer_host/blob_dispatcher_host.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_RENDERER_HOST_BLOB_DISPATCHER_HOST_H_
-#define CHROME_BROWSER_RENDERER_HOST_BLOB_DISPATCHER_HOST_H_
-
-#include "base/hash_tables.h"
-#include "base/ref_counted.h"
-
-class ChromeBlobStorageContext;
-class GURL;
-
-namespace IPC {
-class Message;
-}
-
-namespace webkit_blob {
-class BlobData;
-}
-
-class BlobDispatcherHost {
- public:
- BlobDispatcherHost(int process_id,
- ChromeBlobStorageContext* blob_storage_context);
- ~BlobDispatcherHost();
-
- void Shutdown();
- bool OnMessageReceived(const IPC::Message& message, bool* msg_is_ok);
-
- private:
- void OnRegisterBlobUrl(const GURL& url,
- const scoped_refptr<webkit_blob::BlobData>& blob_data);
- void OnRegisterBlobUrlFrom(const GURL& url, const GURL& src_url);
- void OnUnregisterBlobUrl(const GURL& url);
-
- bool CheckPermission(webkit_blob::BlobData* blob_data) const;
-
- int process_id_;
- scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;
-
- // Keep track of blob URLs registered in this process. Need to unregister
- // all of them when the renderer process dies.
- base::hash_set<std::string> blob_urls_;
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(BlobDispatcherHost);
-};
-
-#endif // CHROME_BROWSER_RENDERER_HOST_BLOB_DISPATCHER_HOST_H_
diff --git a/chrome/browser/renderer_host/blob_message_filter.cc b/chrome/browser/renderer_host/blob_message_filter.cc
new file mode 100644
index 0000000..d31d5f7
--- /dev/null
+++ b/chrome/browser/renderer_host/blob_message_filter.cc
@@ -0,0 +1,85 @@
+// 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.
+
+#include "chrome/browser/renderer_host/blob_message_filter.h"
+
+#include "chrome/browser/child_process_security_policy.h"
+#include "chrome/browser/chrome_blob_storage_context.h"
+#include "chrome/common/render_messages.h"
+#include "googleurl/src/gurl.h"
+#include "webkit/blob/blob_data.h"
+#include "webkit/blob/blob_storage_controller.h"
+
+BlobMessageFilter::BlobMessageFilter(
+ int process_id,
+ ChromeBlobStorageContext* blob_storage_context)
+ : process_id_(process_id),
+ blob_storage_context_(blob_storage_context) {
+}
+
+BlobMessageFilter::~BlobMessageFilter() {
+}
+
+void BlobMessageFilter::OnChannelClosing() {
+ BrowserMessageFilter::OnChannelClosing();
+
+ // Unregister all the blob URLs that are previously registered in this
+ // process.
+ for (base::hash_set<std::string>::const_iterator iter = blob_urls_.begin();
+ iter != blob_urls_.end(); ++iter) {
+ blob_storage_context_->controller()->UnregisterBlobUrl(GURL(*iter));
+ }
+}
+
+bool BlobMessageFilter::OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(BlobMessageFilter, message, *message_was_ok)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_RegisterBlobUrl, OnRegisterBlobUrl)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_RegisterBlobUrlFrom, OnRegisterBlobUrlFrom)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_UnregisterBlobUrl, OnUnregisterBlobUrl)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+// Check if the child process has been granted permission to register the files.
+bool BlobMessageFilter::CheckPermission(
+ webkit_blob::BlobData* blob_data) const {
+ ChildProcessSecurityPolicy* policy =
+ ChildProcessSecurityPolicy::GetInstance();
+ for (std::vector<webkit_blob::BlobData::Item>::const_iterator iter =
+ blob_data->items().begin();
+ iter != blob_data->items().end(); ++iter) {
+ if (iter->type() == webkit_blob::BlobData::TYPE_FILE) {
+ if (!policy->CanReadFile(process_id_, iter->file_path()))
+ return false;
+ }
+ }
+ return true;
+}
+
+void BlobMessageFilter::OnRegisterBlobUrl(
+ const GURL& url, const scoped_refptr<webkit_blob::BlobData>& blob_data) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (!CheckPermission(blob_data.get()))
+ return;
+ blob_storage_context_->controller()->RegisterBlobUrl(url, blob_data);
+ blob_urls_.insert(url.spec());
+}
+
+void BlobMessageFilter::OnRegisterBlobUrlFrom(
+ const GURL& url, const GURL& src_url) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ blob_storage_context_->controller()->RegisterBlobUrlFrom(url, src_url);
+ blob_urls_.insert(url.spec());
+}
+
+void BlobMessageFilter::OnUnregisterBlobUrl(const GURL& url) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ blob_storage_context_->controller()->UnregisterBlobUrl(url);
+ blob_urls_.erase(url.spec());
+}
diff --git a/chrome/browser/renderer_host/blob_message_filter.h b/chrome/browser/renderer_host/blob_message_filter.h
new file mode 100644
index 0000000..2809763
--- /dev/null
+++ b/chrome/browser/renderer_host/blob_message_filter.h
@@ -0,0 +1,51 @@
+// 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.
+
+#ifndef CHROME_BROWSER_RENDERER_HOST_BLOB_MESSAGE_FILTER_H_
+#define CHROME_BROWSER_RENDERER_HOST_BLOB_MESSAGE_FILTER_H_
+
+#include "base/hash_tables.h"
+#include "chrome/browser/browser_message_filter.h"
+
+class ChromeBlobStorageContext;
+class GURL;
+
+namespace IPC {
+class Message;
+}
+
+namespace webkit_blob {
+class BlobData;
+}
+
+class BlobMessageFilter : public BrowserMessageFilter {
+ public:
+ BlobMessageFilter(int process_id,
+ ChromeBlobStorageContext* blob_storage_context);
+ ~BlobMessageFilter();
+
+ // BrowserMessageFilter implementation.
+ virtual void OnChannelClosing();
+ virtual bool OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok);
+
+ private:
+ void OnRegisterBlobUrl(const GURL& url,
+ const scoped_refptr<webkit_blob::BlobData>& blob_data);
+ void OnRegisterBlobUrlFrom(const GURL& url, const GURL& src_url);
+ void OnUnregisterBlobUrl(const GURL& url);
+
+ bool CheckPermission(webkit_blob::BlobData* blob_data) const;
+
+ int process_id_;
+ scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;
+
+ // Keep track of blob URLs registered in this process. Need to unregister
+ // all of them when the renderer process dies.
+ base::hash_set<std::string> blob_urls_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(BlobMessageFilter);
+};
+
+#endif // CHROME_BROWSER_RENDERER_HOST_BLOB_MESSAGE_FILTER_H_
diff --git a/chrome/browser/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc
index 41dcff2..e3849fb 100644
--- a/chrome/browser/renderer_host/browser_render_process_host.cc
+++ b/chrome/browser/renderer_host/browser_render_process_host.cc
@@ -16,6 +16,7 @@
#endif
#include "app/app_switches.h"
+#include "base/callback.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/metrics/field_trial.h"
@@ -26,32 +27,48 @@
#include "base/string_util.h"
#include "base/thread.h"
#include "base/thread_restrictions.h"
+#include "chrome/browser/appcache/appcache_dispatcher_host.h"
#include "chrome/browser/browser_child_process_host.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/child_process_security_policy.h"
+#include "chrome/browser/device_orientation/message_filter.h"
#include "chrome/browser/extensions/extension_event_router.h"
#include "chrome/browser/extensions/extension_function_dispatcher.h"
#include "chrome/browser/extensions/extension_message_service.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/user_script_master.h"
+#include "chrome/browser/file_system/file_system_dispatcher_host.h"
+#include "chrome/browser/geolocation/geolocation_dispatcher_host.h"
#include "chrome/browser/gpu_process_host.h"
#include "chrome/browser/history/history.h"
+#include "chrome/browser/in_process_webkit/dom_storage_message_filter.h"
+#include "chrome/browser/in_process_webkit/indexed_db_dispatcher_host.h"
#include "chrome/browser/io_thread.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/mime_registry_message_filter.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/plugin_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/audio_renderer_host.h"
+#include "chrome/browser/renderer_host/blob_message_filter.h"
+#include "chrome/browser/renderer_host/database_message_filter.h"
+#include "chrome/browser/renderer_host/file_utilities_message_filter.h"
#include "chrome/browser/renderer_host/pepper_file_message_filter.h"
+#include "chrome/browser/renderer_host/render_message_filter.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
#include "chrome/browser/renderer_host/render_widget_helper.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
#include "chrome/browser/renderer_host/resource_message_filter.h"
+#include "chrome/browser/renderer_host/socket_stream_dispatcher_host.h"
#include "chrome/browser/renderer_host/web_cache_manager.h"
-#include "chrome/browser/speech/speech_input_manager.h"
+#include "chrome/browser/safe_browsing/client_side_detection_service.h"
+#include "chrome/browser/search_engines/search_provider_install_state_message_filter.h"
+#include "chrome/browser/speech/speech_input_dispatcher_host.h"
#include "chrome/browser/spellcheck_host.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/visitedlink_master.h"
+#include "chrome/browser/visitedlink/visitedlink_master.h"
+#include "chrome/browser/worker_host/worker_message_filter.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/child_process_info.h"
@@ -75,7 +92,7 @@
#include "ipc/ipc_switches.h"
#include "media/base/media_switches.h"
#include "webkit/fileapi/file_system_path_manager.h"
-#include "webkit/glue/plugins/plugin_switches.h"
+#include "webkit/plugins/plugin_switches.h"
#if defined(OS_WIN)
#include "app/win_util.h"
@@ -207,6 +224,38 @@ class VisitedLinkUpdater {
VisitedLinkCommon::Fingerprints pending_;
};
+namespace {
+
+// Helper class that we pass to ResourceMessageFilter so that it can find the
+// right URLRequestContext for a request.
+class RendererURLRequestContextOverride
+ : public ResourceMessageFilter::URLRequestContextOverride {
+ public:
+ explicit RendererURLRequestContextOverride(Profile* profile)
+ : request_context_(profile->GetRequestContext()),
+ media_request_context_(profile->GetRequestContextForMedia()) {
+ }
+
+ virtual URLRequestContext* GetRequestContext(
+ uint32 request_id, ResourceType::Type resource_type) {
+ URLRequestContextGetter* request_context = request_context_;
+ // If the request has resource type of ResourceType::MEDIA, we use a request
+ // context specific to media for handling it because these resources have
+ // specific needs for caching.
+ if (resource_type == ResourceType::MEDIA)
+ request_context = media_request_context_;
+ return request_context->GetURLRequestContext();
+ }
+
+ private:
+ virtual ~RendererURLRequestContextOverride() {}
+
+ scoped_refptr<URLRequestContextGetter> request_context_;
+ scoped_refptr<URLRequestContextGetter> media_request_context_;
+};
+
+} // namespace
+
BrowserRenderProcessHost::BrowserRenderProcessHost(Profile* profile)
: RenderProcessHost(profile),
visible_widgets_(0),
@@ -215,7 +264,8 @@ BrowserRenderProcessHost::BrowserRenderProcessHost(Profile* profile)
base::TimeDelta::FromSeconds(5),
this, &BrowserRenderProcessHost::ClearTransportDIBCache)),
accessibility_enabled_(false),
- extension_process_(false) {
+ extension_process_(false),
+ callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
widget_helper_ = new RenderWidgetHelper();
registrar_.Add(this, NotificationType::USER_SCRIPTS_UPDATED,
@@ -241,9 +291,8 @@ BrowserRenderProcessHost::BrowserRenderProcessHost(Profile* profile)
// PLATFORM_FILE_DELETE_ON_CLOSE are not granted, because no existing API
// requests them.
ChildProcessSecurityPolicy::GetInstance()->GrantPermissionsForFile(
- id(),
- fileapi::FileSystemPathManager::GetFileSystemCommonRootDirectory(
- profile->GetPath()),
+ id(), profile->GetPath().Append(
+ fileapi::FileSystemPathManager::kFileSystemDirectory),
base::PLATFORM_FILE_OPEN |
base::PLATFORM_FILE_CREATE |
base::PLATFORM_FILE_OPEN_ALWAYS |
@@ -275,10 +324,6 @@ BrowserRenderProcessHost::~BrowserRenderProcessHost() {
queued_messages_.pop();
}
- // Destroy the AudioRendererHost properly.
- if (audio_renderer_host_.get())
- audio_renderer_host_->Destroy();
-
ClearTransportDIBCache();
}
@@ -298,18 +343,6 @@ bool BrowserRenderProcessHost::Init(
// run the IPC channel on the shared IO thread.
base::Thread* io_thread = g_browser_process->io_thread();
- // Construct the AudioRendererHost with the IO thread.
- audio_renderer_host_ = new AudioRendererHost();
-
- scoped_refptr<ResourceMessageFilter> resource_message_filter(
- new ResourceMessageFilter(g_browser_process->resource_dispatcher_host(),
- id(),
- audio_renderer_host_.get(),
- PluginService::GetInstance(),
- g_browser_process->print_job_manager(),
- profile(),
- widget_helper_));
-
CommandLine::StringType renderer_prefix;
#if defined(OS_POSIX)
// A command prefix is something prepended to the command line of the spawned
@@ -331,7 +364,6 @@ bool BrowserRenderProcessHost::Init(
ChildProcessInfo::GenerateRandomChannelID(this);
channel_.reset(
new IPC::SyncChannel(channel_id, IPC::Channel::MODE_SERVER, this,
- resource_message_filter,
io_thread->message_loop(), true,
g_browser_process->shutdown_event()));
// As a preventive mesure, we DCHECK if someone sends a synchronous message
@@ -339,9 +371,7 @@ bool BrowserRenderProcessHost::Init(
// be doing.
channel_->set_sync_messages_with_no_timeout_allowed(false);
- scoped_refptr<PepperFileMessageFilter> pepper_file_message_filter(
- new PepperFileMessageFilter(id(), profile()));
- channel_->AddFilter(pepper_file_message_filter);
+ CreateMessageFilters();
if (run_renderer_in_process()) {
// Crank up a thread and run the initialization there. With the way that
@@ -393,6 +423,59 @@ bool BrowserRenderProcessHost::Init(
return true;
}
+void BrowserRenderProcessHost::CreateMessageFilters() {
+ scoped_refptr<RenderMessageFilter> render_message_filter(
+ new RenderMessageFilter(id(),
+ PluginService::GetInstance(),
+ profile(),
+ widget_helper_));
+ channel_->AddFilter(render_message_filter);
+
+ scoped_refptr<RendererURLRequestContextOverride> url_request_context_override(
+ new RendererURLRequestContextOverride(profile()));
+
+ ResourceMessageFilter* resource_message_filter = new ResourceMessageFilter(
+ id(), ChildProcessInfo::RENDER_PROCESS,
+ g_browser_process->resource_dispatcher_host());
+ resource_message_filter->set_url_request_context_override(
+ url_request_context_override);
+ channel_->AddFilter(resource_message_filter);
+
+ channel_->AddFilter(new AudioRendererHost());
+ channel_->AddFilter(
+ new AppCacheDispatcherHost(profile()->GetRequestContext(), id()));
+ channel_->AddFilter(new DOMStorageMessageFilter(id(), profile()));
+ channel_->AddFilter(new IndexedDBDispatcherHost(id(), profile()));
+ channel_->AddFilter(
+ GeolocationDispatcherHost::New(
+ id(), profile()->GetGeolocationPermissionContext()));
+ channel_->AddFilter(new PepperFileMessageFilter(id(), profile()));
+ channel_->AddFilter(new speech_input::SpeechInputDispatcherHost(id()));
+ channel_->AddFilter(
+ new SearchProviderInstallStateMessageFilter(id(), profile()));
+ channel_->AddFilter(new FileSystemDispatcherHost(profile()));
+ channel_->AddFilter(new device_orientation::MessageFilter());
+ channel_->AddFilter(
+ new BlobMessageFilter(id(), profile()->GetBlobStorageContext()));
+ channel_->AddFilter(new FileUtilitiesMessageFilter(id()));
+ channel_->AddFilter(new MimeRegistryMessageFilter());
+ channel_->AddFilter(new DatabaseMessageFilter(
+ profile()->GetDatabaseTracker(), profile()->GetHostContentSettingsMap()));
+
+ SocketStreamDispatcherHost* socket_stream_dispatcher_host =
+ new SocketStreamDispatcherHost();
+ socket_stream_dispatcher_host->set_url_request_context_override(
+ url_request_context_override);
+ channel_->AddFilter(socket_stream_dispatcher_host);
+
+ channel_->AddFilter(new WorkerMessageFilter(
+ id(),
+ profile()->GetRequestContext(),
+ g_browser_process->resource_dispatcher_host(),
+ NewCallbackWithReturnValue(
+ widget_helper_.get(), &RenderWidgetHelper::GetNextRoutingID)));
+}
+
int BrowserRenderProcessHost::GetNextRoutingID() {
return widget_helper_->GetNextRoutingID();
}
@@ -418,8 +501,14 @@ bool BrowserRenderProcessHost::WaitForUpdateMsg(
return widget_helper_->WaitForUpdateMsg(render_widget_id, max_delay, msg);
}
-void BrowserRenderProcessHost::ReceivedBadMessage(uint32 msg_type) {
- BadMessageTerminateProcess(msg_type, GetHandle());
+void BrowserRenderProcessHost::ReceivedBadMessage() {
+ if (run_renderer_in_process()) {
+ // In single process mode it is better if we don't suicide but just
+ // crash.
+ CHECK(false);
+ }
+ NOTREACHED();
+ base::KillProcess(GetHandle(), ResultCodes::KILLED_BAD_MESSAGE, false);
}
void BrowserRenderProcessHost::ViewCreated() {
@@ -549,11 +638,8 @@ void BrowserRenderProcessHost::PropagateBrowserCommandLineToRenderer(
switches::kRendererStartupDialog,
switches::kNoSandbox,
switches::kTestSandbox,
-#if defined(USE_SECCOMP_SANDBOX)
switches::kDisableSeccompSandbox,
-#else
switches::kEnableSeccompSandbox,
-#endif
#if !defined (GOOGLE_CHROME_BUILD)
// These are unsupported and not fully tested modes, so don't enable them
// for official Google Chrome builds.
@@ -599,7 +685,7 @@ void BrowserRenderProcessHost::PropagateBrowserCommandLineToRenderer(
switches::kDisableSharedWorkers,
switches::kDisableApplicationCache,
switches::kDisableDeviceOrientation,
- switches::kEnableIndexedDatabase,
+ switches::kDisableIndexedDatabase,
switches::kDisableSpeechInput,
switches::kDisableGeolocation,
switches::kShowPaintRects,
@@ -628,8 +714,7 @@ void BrowserRenderProcessHost::PropagateBrowserCommandLineToRenderer(
#endif
switches::kRemoteShellPort,
switches::kEnablePepperTesting,
- switches::kBlockNonSandboxedPlugins,
- switches::kDisableOutdatedPlugins,
+ switches::kAllowOutdatedPlugins,
switches::kEnableRemoting,
switches::kEnableClickToPlay,
switches::kEnableResourceContentSettings,
@@ -638,7 +723,6 @@ void BrowserRenderProcessHost::PropagateBrowserCommandLineToRenderer(
switches::kDisableFileSystem,
switches::kPpapiOutOfProcess,
switches::kEnablePrintPreview,
- switches::kEnableClientSidePhishingDetection,
switches::kEnableCrxlessWebApps,
switches::kDisable3DAPIs
};
@@ -650,6 +734,12 @@ void BrowserRenderProcessHost::PropagateBrowserCommandLineToRenderer(
!browser_cmd.HasSwitch(switches::kDisableDatabases)) {
renderer_cmd->AppendSwitch(switches::kDisableDatabases);
}
+
+ // Only enable client-side phishing detection in the renderer if it is enabled
+ // in the browser process.
+ if (g_browser_process->safe_browsing_detection_service()) {
+ renderer_cmd->AppendSwitch(switches::kEnableClientSidePhishingDetection);
+ }
}
base::ProcessHandle BrowserRenderProcessHost::GetHandle() {
@@ -697,8 +787,23 @@ void BrowserRenderProcessHost::InitExtensions() {
}
void BrowserRenderProcessHost::InitSpeechInput() {
- Send(new ViewMsg_SpeechInput_SetFeatureEnabled(
- speech_input::SpeechInputManager::IsFeatureEnabled()));
+ bool enabled = true;
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+
+ if (command_line.HasSwitch(switches::kDisableSpeechInput)) {
+ enabled = false;
+#if defined(GOOGLE_CHROME_BUILD)
+ } else if (!command_line.HasSwitch(switches::kEnableSpeechInput)) {
+ // We need to evaluate whether IO is OK here. http://crbug.com/63335.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+ // Official Chrome builds have speech input enabled by default only in the
+ // dev channel.
+ std::string channel = platform_util::GetVersionStringModifier();
+ enabled = (channel == "dev");
+#endif
+ }
+
+ Send(new ViewMsg_SpeechInput_SetFeatureEnabled(enabled));
}
void BrowserRenderProcessHost::SendUserScriptsUpdate(
@@ -727,7 +832,7 @@ void BrowserRenderProcessHost::SendExtensionInfo() {
return;
}
- ExtensionsService* service = profile()->GetExtensionsService();
+ ExtensionService* service = profile()->GetExtensionService();
if (!service)
return;
ViewMsg_ExtensionsUpdated_Params params;
@@ -872,11 +977,11 @@ bool BrowserRenderProcessHost::Send(IPC::Message* msg) {
return channel_->Send(msg);
}
-void BrowserRenderProcessHost::OnMessageReceived(const IPC::Message& msg) {
+bool BrowserRenderProcessHost::OnMessageReceived(const IPC::Message& msg) {
// If we're about to be deleted, we can no longer trust that our profile is
// valid, so we ignore incoming messages.
if (deleting_soon_)
- return;
+ return false;
#if defined(OS_CHROMEOS)
// To troubleshoot crosbug.com/7327.
@@ -909,9 +1014,11 @@ void BrowserRenderProcessHost::OnMessageReceived(const IPC::Message& msg) {
if (!msg_is_ok) {
// The message had a handler, but its de-serialization failed.
// We consider this a capital crime. Kill the renderer if we have one.
- ReceivedBadMessage(msg.type());
+ LOG(ERROR) << "bad message " << msg.type() << " terminating renderer.";
+ UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_BRPH"));
+ ReceivedBadMessage();
}
- return;
+ return true;
}
// Dispatch incoming messages to the appropriate RenderView/WidgetHost.
@@ -924,29 +1031,18 @@ void BrowserRenderProcessHost::OnMessageReceived(const IPC::Message& msg) {
reply->set_reply_error();
Send(reply);
}
- return;
+ return true;
}
- listener->OnMessageReceived(msg);
+ return listener->OnMessageReceived(msg);
}
void BrowserRenderProcessHost::OnChannelConnected(int32 peer_pid) {
#if defined(IPC_MESSAGE_LOG_ENABLED)
- Send(new ViewMsg_SetIPCLoggingEnabled(IPC::Logging::current()->Enabled()));
+ Send(new ViewMsg_SetIPCLoggingEnabled(
+ IPC::Logging::GetInstance()->Enabled()));
#endif
}
-// Static. This function can be called from any thread.
-void BrowserRenderProcessHost::BadMessageTerminateProcess(
- uint32 msg_type, base::ProcessHandle process) {
- LOG(ERROR) << "bad message " << msg_type << " terminating renderer.";
- if (run_renderer_in_process()) {
- // In single process mode it is better if we don't suicide but just crash.
- CHECK(false);
- }
- NOTREACHED();
- base::KillProcess(process, ResultCodes::KILLED_BAD_MESSAGE, false);
-}
-
void BrowserRenderProcessHost::OnChannelError() {
// Our child process has died. If we didn't expect it, it's a crash.
// In any case, we need to let everyone know it's gone.
@@ -956,16 +1052,26 @@ void BrowserRenderProcessHost::OnChannelError() {
if (!channel_.get())
return;
- // NULL in single process mode or if fast termination happened.
- bool did_crash =
- child_process_.get() ? child_process_->DidProcessCrash() : false;
+ // child_process_ can be NULL in single process mode or if fast
+ // termination happened.
+ int exit_code = 0;
+ base::TerminationStatus status =
+ child_process_.get() ?
+ child_process_->GetChildTerminationStatus(&exit_code) :
+ base::TERMINATION_STATUS_NORMAL_TERMINATION;
- if (did_crash) {
+ if (status == base::TERMINATION_STATUS_PROCESS_CRASHED ||
+ status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION) {
UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildCrashes",
extension_process_ ? 2 : 1);
}
- RendererClosedDetails details(did_crash, extension_process_);
+ if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED) {
+ UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildKills",
+ extension_process_ ? 2 : 1);
+ }
+
+ RendererClosedDetails details(status, exit_code, extension_process_);
NotificationService::current()->Notify(
NotificationType::RENDERER_PROCESS_CLOSED,
Source<RenderProcessHost>(this),
@@ -978,7 +1084,9 @@ void BrowserRenderProcessHost::OnChannelError() {
IDMap<IPC::Channel::Listener>::iterator iter(&listeners_);
while (!iter.IsAtEnd()) {
iter.GetCurrentValue()->OnMessageReceived(
- ViewHostMsg_RenderViewGone(iter.GetCurrentKey()));
+ ViewHostMsg_RenderViewGone(iter.GetCurrentKey(),
+ static_cast<int>(status),
+ exit_code));
iter.Advance();
}
@@ -1085,6 +1193,8 @@ void BrowserRenderProcessHost::OnProcessLaunched() {
if (profile()->GetSpellCheckHost())
InitSpellChecker();
+ InitClientSidePhishingDetection();
+
if (max_page_id_ != -1)
Send(new ViewMsg_SetNextPageID(max_page_id_ + 1));
@@ -1176,3 +1286,29 @@ void BrowserRenderProcessHost::InitSpellChecker() {
void BrowserRenderProcessHost::EnableAutoSpellCorrect(bool enable) {
Send(new ViewMsg_SpellChecker_EnableAutoSpellCorrect(enable));
}
+
+void BrowserRenderProcessHost::InitClientSidePhishingDetection() {
+ if (g_browser_process->safe_browsing_detection_service()) {
+ // The BrowserRenderProcessHost object might get deleted before the
+ // safe browsing client-side detection service class is done with opening
+ // the model file. To avoid crashing we use the callback factory which will
+ // cancel the callback if |this| is destroyed.
+ g_browser_process->safe_browsing_detection_service()->GetModelFile(
+ callback_factory_.NewCallback(
+ &BrowserRenderProcessHost::OpenPhishingModelDone));
+ }
+}
+
+void BrowserRenderProcessHost::OpenPhishingModelDone(
+ base::PlatformFile model_file) {
+ if (model_file != base::kInvalidPlatformFileValue) {
+ IPC::PlatformFileForTransit file;
+#if defined(OS_POSIX)
+ file = base::FileDescriptor(model_file, false);
+#elif defined(OS_WIN)
+ ::DuplicateHandle(::GetCurrentProcess(), model_file, GetHandle(), &file, 0,
+ false, DUPLICATE_SAME_ACCESS);
+#endif
+ Send(new ViewMsg_SetPhishingModel(file));
+ }
+}
diff --git a/chrome/browser/renderer_host/browser_render_process_host.h b/chrome/browser/renderer_host/browser_render_process_host.h
index 2ca02e7..f1bc47a 100644
--- a/chrome/browser/renderer_host/browser_render_process_host.h
+++ b/chrome/browser/renderer_host/browser_render_process_host.h
@@ -13,7 +13,9 @@
#include <string>
#include "app/surface/transport_dib.h"
+#include "base/platform_file.h"
#include "base/process.h"
+#include "base/scoped_callback_factory.h"
#include "base/scoped_ptr.h"
#include "base/timer.h"
#include "chrome/browser/child_process_launcher.h"
@@ -22,7 +24,6 @@
#include "chrome/common/notification_registrar.h"
#include "third_party/WebKit/WebKit/chromium/public/WebCache.h"
-class AudioRendererHost;
class CommandLine;
class GURL;
class RendererMainThread;
@@ -68,7 +69,7 @@ class BrowserRenderProcessHost : public RenderProcessHost,
virtual bool WaitForUpdateMsg(int render_widget_id,
const base::TimeDelta& max_delay,
IPC::Message* msg);
- virtual void ReceivedBadMessage(uint32 msg_type);
+ virtual void ReceivedBadMessage();
virtual void WidgetRestored();
virtual void WidgetHidden();
virtual void ViewCreated();
@@ -84,16 +85,10 @@ class BrowserRenderProcessHost : public RenderProcessHost,
virtual bool Send(IPC::Message* msg);
// IPC::Channel::Listener via RenderProcessHost.
- virtual void OnMessageReceived(const IPC::Message& msg);
+ virtual bool OnMessageReceived(const IPC::Message& msg);
virtual void OnChannelConnected(int32 peer_pid);
virtual void OnChannelError();
- // If the a process has sent a message that cannot be decoded, it is deemed
- // corrupted and thus needs to be terminated using this call. This function
- // can be safely called from any thread.
- static void BadMessageTerminateProcess(uint32 msg_type,
- base::ProcessHandle renderer);
-
// NotificationObserver implementation.
virtual void Observe(NotificationType type,
const NotificationSource& source,
@@ -105,6 +100,9 @@ class BrowserRenderProcessHost : public RenderProcessHost,
private:
friend class VisitRelayingRenderProcessHost;
+ // Creates and adds the IO thread message filters.
+ void CreateMessageFilters();
+
// Control message handlers.
void OnUpdatedCacheStats(const WebKit::WebCache::UsageStats& stats);
void SuddenTerminationChanged(bool enabled);
@@ -168,6 +166,15 @@ class BrowserRenderProcessHost : public RenderProcessHost,
// Tell the renderer that auto spell correction has been enabled/disabled.
void EnableAutoSpellCorrect(bool enable);
+ // Initializes client-side phishing detection. Starts reading the phishing
+ // model from the client-side detection service class. Once the model is read
+ // OpenPhishingModelDone() is invoked.
+ void InitClientSidePhishingDetection();
+
+ // Called once the client-side detection service class is done with opening
+ // the model file.
+ void OpenPhishingModelDone(base::PlatformFile model_file);
+
NotificationRegistrar registrar_;
// The count of currently visible widgets. Since the host can be a container
@@ -182,9 +189,6 @@ class BrowserRenderProcessHost : public RenderProcessHost,
// IO thread.
scoped_refptr<RenderWidgetHelper> widget_helper_;
- // The host of audio renderers in the renderer process.
- scoped_refptr<AudioRendererHost> audio_renderer_host_;
-
// A map of transport DIB ids to cached TransportDIBs
std::map<TransportDIB::Id, TransportDIB*> cached_dibs_;
enum {
@@ -221,6 +225,8 @@ class BrowserRenderProcessHost : public RenderProcessHost,
// because the queued messages may have dependencies on the init messages.
std::queue<IPC::Message*> queued_messages_;
+ base::ScopedCallbackFactory<BrowserRenderProcessHost> callback_factory_;
+
DISALLOW_COPY_AND_ASSIGN(BrowserRenderProcessHost);
};
diff --git a/chrome/browser/renderer_host/buffered_resource_handler.cc b/chrome/browser/renderer_host/buffered_resource_handler.cc
index 0a141b0..bc35c42 100644
--- a/chrome/browser/renderer_host/buffered_resource_handler.cc
+++ b/chrome/browser/renderer_host/buffered_resource_handler.cc
@@ -22,7 +22,7 @@
#include "net/base/mime_util.h"
#include "net/base/net_errors.h"
#include "net/http/http_response_headers.h"
-#include "webkit/glue/plugins/plugin_list.h"
+#include "webkit/plugins/npapi/plugin_list.h"
namespace {
@@ -52,7 +52,7 @@ void RecordSnifferMetrics(bool sniffing_blocked,
BufferedResourceHandler::BufferedResourceHandler(ResourceHandler* handler,
ResourceDispatcherHost* host,
- URLRequest* request)
+ net::URLRequest* request)
: real_handler_(handler),
host_(host),
request_(request),
@@ -422,18 +422,18 @@ bool BufferedResourceHandler::ShouldDownload(bool* need_plugin_list) {
return false;
if (need_plugin_list) {
- if (!NPAPI::PluginList::Singleton()->PluginsLoaded()) {
+ if (!webkit::npapi::PluginList::Singleton()->PluginsLoaded()) {
*need_plugin_list = true;
return true;
}
} else {
- DCHECK(NPAPI::PluginList::Singleton()->PluginsLoaded());
+ DCHECK(webkit::npapi::PluginList::Singleton()->PluginsLoaded());
}
// Finally, check the plugin list.
- WebPluginInfo info;
+ webkit::npapi::WebPluginInfo info;
bool allow_wildcard = false;
- return !NPAPI::PluginList::Singleton()->GetPluginInfo(
+ return !webkit::npapi::PluginList::Singleton()->GetPluginInfo(
GURL(), type, allow_wildcard, &info, NULL) || !info.enabled;
}
@@ -469,8 +469,8 @@ void BufferedResourceHandler::UseAlternateResourceHandler(
}
void BufferedResourceHandler::LoadPlugins() {
- std::vector<WebPluginInfo> plugins;
- NPAPI::PluginList::Singleton()->GetPlugins(false, &plugins);
+ std::vector<webkit::npapi::WebPluginInfo> plugins;
+ webkit::npapi::PluginList::Singleton()->GetPlugins(false, &plugins);
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
diff --git a/chrome/browser/renderer_host/cross_site_resource_handler.cc b/chrome/browser/renderer_host/cross_site_resource_handler.cc
index ddab0e7..b1ac20a 100644
--- a/chrome/browser/renderer_host/cross_site_resource_handler.cc
+++ b/chrome/browser/renderer_host/cross_site_resource_handler.cc
@@ -7,7 +7,6 @@
#include "chrome/browser/renderer_host/cross_site_resource_handler.h"
#include "base/logging.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/renderer_host/global_request_id.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
@@ -59,7 +58,7 @@ bool CrossSiteResourceHandler::OnResponseStarted(int request_id,
// Look up the request and associated info.
GlobalRequestID global_id(render_process_host_id_, request_id);
- URLRequest* request = rdh_->GetURLRequest(global_id);
+ net::URLRequest* request = rdh_->GetURLRequest(global_id);
if (!request) {
DLOG(WARNING) << "Request wasn't found";
return false;
@@ -141,7 +140,7 @@ void CrossSiteResourceHandler::ResumeResponse() {
// Find the request for this response.
GlobalRequestID global_id(render_process_host_id_, request_id_);
- URLRequest* request = rdh_->GetURLRequest(global_id);
+ net::URLRequest* request = rdh_->GetURLRequest(global_id);
if (!request) {
DLOG(WARNING) << "Resuming a request that wasn't found";
return;
@@ -189,7 +188,7 @@ void CrossSiteResourceHandler::StartCrossSiteTransition(
// Store this handler on the ExtraRequestInfo, so that RDH can call our
// ResumeResponse method when the close ACK is received.
- URLRequest* request = rdh_->GetURLRequest(global_id);
+ net::URLRequest* request = rdh_->GetURLRequest(global_id);
if (!request) {
DLOG(WARNING) << "Cross site response for a request that wasn't found";
return;
diff --git a/chrome/browser/renderer_host/database_dispatcher_host.cc b/chrome/browser/renderer_host/database_dispatcher_host.cc
deleted file mode 100644
index 11c5125..0000000
--- a/chrome/browser/renderer_host/database_dispatcher_host.cc
+++ /dev/null
@@ -1,437 +0,0 @@
-// 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.
-
-#include "chrome/browser/renderer_host/database_dispatcher_host.h"
-
-#if defined(OS_POSIX)
-#include "base/file_descriptor_posix.h"
-#endif
-
-#include "base/string_util.h"
-#include "base/thread.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/host_content_settings_map.h"
-#include "chrome/browser/net/chrome_url_request_context.h"
-#include "chrome/browser/renderer_host/browser_render_process_host.h"
-#include "chrome/common/render_messages.h"
-#include "googleurl/src/gurl.h"
-#include "third_party/sqlite/sqlite3.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebSecurityOrigin.h"
-#include "webkit/database/database_util.h"
-#include "webkit/database/vfs_backend.h"
-
-using WebKit::WebSecurityOrigin;
-using webkit_database::DatabaseTracker;
-using webkit_database::DatabaseUtil;
-using webkit_database::VfsBackend;
-
-const int kNumDeleteRetries = 2;
-const int kDelayDeleteRetryMs = 100;
-
-DatabaseDispatcherHost::DatabaseDispatcherHost(
- DatabaseTracker* db_tracker,
- IPC::Message::Sender* sender,
- HostContentSettingsMap *host_content_settings_map)
- : db_tracker_(db_tracker),
- message_sender_(sender),
- process_handle_(0),
- observer_added_(false),
- shutdown_(false),
- host_content_settings_map_(host_content_settings_map) {
- DCHECK(db_tracker_);
- DCHECK(message_sender_);
-}
-
-void DatabaseDispatcherHost::Init(base::ProcessHandle process_handle) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK(!shutdown_);
- DCHECK(!process_handle_);
- DCHECK(process_handle);
- process_handle_ = process_handle;
-}
-
-void DatabaseDispatcherHost::Shutdown() {
- shutdown_ = true;
- message_sender_ = NULL;
- if (observer_added_) {
- observer_added_ = false;
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(this, &DatabaseDispatcherHost::RemoveObserver));
- }
-}
-
-void DatabaseDispatcherHost::AddObserver() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- db_tracker_->AddObserver(this);
-}
-
-void DatabaseDispatcherHost::RemoveObserver() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- // If the renderer process died without closing all databases,
- // then we need to manually close those connections
- db_tracker_->CloseDatabases(database_connections_);
- database_connections_.RemoveAllConnections();
-
- db_tracker_->RemoveObserver(this);
-}
-
-bool DatabaseDispatcherHost::OnMessageReceived(
- const IPC::Message& message, bool* message_was_ok) {
- DCHECK(!shutdown_);
- *message_was_ok = true;
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP_EX(DatabaseDispatcherHost, message, *message_was_ok)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DatabaseOpenFile,
- OnDatabaseOpenFile)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DatabaseDeleteFile,
- OnDatabaseDeleteFile)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DatabaseGetFileAttributes,
- OnDatabaseGetFileAttributes)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DatabaseGetFileSize,
- OnDatabaseGetFileSize)
- IPC_MESSAGE_HANDLER(ViewHostMsg_DatabaseOpened, OnDatabaseOpened)
- IPC_MESSAGE_HANDLER(ViewHostMsg_DatabaseModified, OnDatabaseModified)
- IPC_MESSAGE_HANDLER(ViewHostMsg_DatabaseClosed, OnDatabaseClosed)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_AllowDatabase, OnAllowDatabase)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP_EX()
- return handled;
-}
-
-void DatabaseDispatcherHost::ReceivedBadMessage(uint32 msg_type) {
- BrowserRenderProcessHost::BadMessageTerminateProcess(
- msg_type, process_handle_);
-}
-
-void DatabaseDispatcherHost::Send(IPC::Message* message) {
- if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
- if (!BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(this,
- &DatabaseDispatcherHost::Send,
- message)))
- delete message;
- return;
- }
-
- if (!shutdown_ && message_sender_)
- message_sender_->Send(message);
- else
- delete message;
-}
-
-DatabaseDispatcherHost::~DatabaseDispatcherHost() {}
-
-void DatabaseDispatcherHost::OnDatabaseOpenFile(const string16& vfs_file_name,
- int desired_flags,
- IPC::Message* reply_msg) {
- if (!observer_added_) {
- observer_added_ = true;
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(this, &DatabaseDispatcherHost::AddObserver));
- }
-
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(this,
- &DatabaseDispatcherHost::DatabaseOpenFile,
- vfs_file_name,
- desired_flags,
- reply_msg));
-}
-
-// Scheduled by the IO thread on the file thread.
-// Opens the given database file, then schedules
-// a task on the IO thread's message loop to send an IPC back to
-// corresponding renderer process with the file handle.
-void DatabaseDispatcherHost::DatabaseOpenFile(const string16& vfs_file_name,
- int desired_flags,
- IPC::Message* reply_msg) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- base::PlatformFile file_handle = base::kInvalidPlatformFileValue;
- base::PlatformFile target_handle = base::kInvalidPlatformFileValue;
- string16 origin_identifier;
- string16 database_name;
-
- // When in incognito mode, we want to make sure that all DB files are
- // removed when the incognito profile goes away, so we add the
- // SQLITE_OPEN_DELETEONCLOSE flag when opening all files, and keep
- // open handles to them in the database tracker to make sure they're
- // around for as long as needed.
- if (vfs_file_name.empty()) {
- VfsBackend::OpenTempFileInDirectory(db_tracker_->DatabaseDirectory(),
- desired_flags, &file_handle);
- } else if (DatabaseUtil::CrackVfsFileName(vfs_file_name, &origin_identifier,
- &database_name, NULL) &&
- !db_tracker_->IsDatabaseScheduledForDeletion(origin_identifier,
- database_name)) {
- FilePath db_file =
- DatabaseUtil::GetFullFilePathForVfsFile(db_tracker_, vfs_file_name);
- if (!db_file.empty()) {
- if (db_tracker_->IsIncognitoProfile()) {
- db_tracker_->GetIncognitoFileHandle(vfs_file_name, &file_handle);
- if (file_handle == base::kInvalidPlatformFileValue) {
- VfsBackend::OpenFile(db_file,
- desired_flags | SQLITE_OPEN_DELETEONCLOSE,
- &file_handle);
- if (VfsBackend::FileTypeIsMainDB(desired_flags) ||
- VfsBackend::FileTypeIsJournal(desired_flags))
- db_tracker_->SaveIncognitoFileHandle(vfs_file_name, file_handle);
- }
- } else {
- VfsBackend::OpenFile(db_file, desired_flags, &file_handle);
- }
- }
- }
-
- // Then we duplicate the file handle to make it useable in the renderer
- // process. The original handle is closed, unless we saved it in the
- // database tracker.
- bool auto_close = !db_tracker_->HasSavedIncognitoFileHandle(vfs_file_name);
- VfsBackend::GetFileHandleForProcess(process_handle_, file_handle,
- &target_handle, auto_close);
-
- ViewHostMsg_DatabaseOpenFile::WriteReplyParams(
- reply_msg,
-#if defined(OS_WIN)
- target_handle
-#elif defined(OS_POSIX)
- base::FileDescriptor(target_handle, auto_close)
-#endif
- );
- Send(reply_msg);
-}
-
-void DatabaseDispatcherHost::OnDatabaseDeleteFile(const string16& vfs_file_name,
- const bool& sync_dir,
- IPC::Message* reply_msg) {
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(this,
- &DatabaseDispatcherHost::DatabaseDeleteFile,
- vfs_file_name,
- sync_dir,
- reply_msg,
- kNumDeleteRetries));
-}
-
-// Scheduled by the IO thread on the file thread.
-// Deletes the given database file, then schedules
-// a task on the IO thread's message loop to send an IPC back to
-// corresponding renderer process with the error code.
-void DatabaseDispatcherHost::DatabaseDeleteFile(const string16& vfs_file_name,
- bool sync_dir,
- IPC::Message* reply_msg,
- int reschedule_count) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- // Return an error if the file name is invalid or if the file could not
- // be deleted after kNumDeleteRetries attempts.
- int error_code = SQLITE_IOERR_DELETE;
- FilePath db_file =
- DatabaseUtil::GetFullFilePathForVfsFile(db_tracker_, vfs_file_name);
- if (!db_file.empty()) {
- // In order to delete a journal file in incognito mode, we only need to
- // close the open handle to it that's stored in the database tracker.
- if (db_tracker_->IsIncognitoProfile()) {
- if (db_tracker_->CloseIncognitoFileHandle(vfs_file_name))
- error_code = SQLITE_OK;
- } else {
- error_code = VfsBackend::DeleteFile(db_file, sync_dir);
- }
-
- if ((error_code == SQLITE_IOERR_DELETE) && reschedule_count) {
- // If the file could not be deleted, try again.
- BrowserThread::PostDelayedTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(this,
- &DatabaseDispatcherHost::DatabaseDeleteFile,
- vfs_file_name,
- sync_dir,
- reply_msg,
- reschedule_count - 1),
- kDelayDeleteRetryMs);
- return;
- }
- }
-
- ViewHostMsg_DatabaseDeleteFile::WriteReplyParams(reply_msg, error_code);
- Send(reply_msg);
-}
-
-void DatabaseDispatcherHost::OnDatabaseGetFileAttributes(
- const string16& vfs_file_name,
- IPC::Message* reply_msg) {
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(this,
- &DatabaseDispatcherHost::DatabaseGetFileAttributes,
- vfs_file_name,
- reply_msg));
-}
-
-// Scheduled by the IO thread on the file thread.
-// Gets the attributes of the given database file, then schedules
-// a task on the IO thread's message loop to send an IPC back to
-// corresponding renderer process.
-void DatabaseDispatcherHost::DatabaseGetFileAttributes(
- const string16& vfs_file_name,
- IPC::Message* reply_msg) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- int32 attributes = -1;
- FilePath db_file =
- DatabaseUtil::GetFullFilePathForVfsFile(db_tracker_, vfs_file_name);
- if (!db_file.empty())
- attributes = VfsBackend::GetFileAttributes(db_file);
-
- ViewHostMsg_DatabaseGetFileAttributes::WriteReplyParams(
- reply_msg, attributes);
- Send(reply_msg);
-}
-
-void DatabaseDispatcherHost::OnDatabaseGetFileSize(
- const string16& vfs_file_name, IPC::Message* reply_msg) {
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(this,
- &DatabaseDispatcherHost::DatabaseGetFileSize,
- vfs_file_name,
- reply_msg));
-}
-
-// Scheduled by the IO thread on the file thread.
-// Gets the size of the given file, then schedules a task
-// on the IO thread's message loop to send an IPC back to
-// the corresponding renderer process.
-void DatabaseDispatcherHost::DatabaseGetFileSize(const string16& vfs_file_name,
- IPC::Message* reply_msg) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- int64 size = 0;
- FilePath db_file =
- DatabaseUtil::GetFullFilePathForVfsFile(db_tracker_, vfs_file_name);
- if (!db_file.empty())
- size = VfsBackend::GetFileSize(db_file);
-
- ViewHostMsg_DatabaseGetFileSize::WriteReplyParams(reply_msg, size);
- Send(reply_msg);
-}
-
-void DatabaseDispatcherHost::OnDatabaseOpened(const string16& origin_identifier,
- const string16& database_name,
- const string16& description,
- int64 estimated_size) {
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(this,
- &DatabaseDispatcherHost::DatabaseOpened,
- origin_identifier,
- database_name,
- description,
- estimated_size));
-}
-
-void DatabaseDispatcherHost::DatabaseOpened(const string16& origin_identifier,
- const string16& database_name,
- const string16& description,
- int64 estimated_size) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- int64 database_size = 0;
- int64 space_available = 0;
- database_connections_.AddConnection(origin_identifier, database_name);
- db_tracker_->DatabaseOpened(origin_identifier, database_name, description,
- estimated_size, &database_size, &space_available);
- Send(new ViewMsg_DatabaseUpdateSize(origin_identifier, database_name,
- database_size, space_available));
-}
-
-void DatabaseDispatcherHost::OnDatabaseModified(
- const string16& origin_identifier,
- const string16& database_name) {
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(this,
- &DatabaseDispatcherHost::DatabaseModified,
- origin_identifier,
- database_name));
-}
-
-void DatabaseDispatcherHost::DatabaseModified(const string16& origin_identifier,
- const string16& database_name) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- if (!database_connections_.IsDatabaseOpened(
- origin_identifier, database_name)) {
- ReceivedBadMessage(ViewHostMsg_DatabaseModified::ID);
- return;
- }
-
- db_tracker_->DatabaseModified(origin_identifier, database_name);
-}
-
-void DatabaseDispatcherHost::OnDatabaseClosed(const string16& origin_identifier,
- const string16& database_name) {
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(this,
- &DatabaseDispatcherHost::DatabaseClosed,
- origin_identifier,
- database_name));
-}
-
-void DatabaseDispatcherHost::OnAllowDatabase(const std::string& origin_url,
- const string16& name,
- const string16& display_name,
- unsigned long estimated_size,
- IPC::Message* reply_msg) {
- GURL url = GURL(origin_url);
- ContentSetting content_setting =
- host_content_settings_map_->GetContentSetting(
- url, CONTENT_SETTINGS_TYPE_COOKIES, "");
- AllowDatabaseResponse(reply_msg, content_setting);
-}
-
-void DatabaseDispatcherHost::AllowDatabaseResponse(
- IPC::Message* reply_msg, ContentSetting content_setting) {
- DCHECK((content_setting == CONTENT_SETTING_ALLOW) ||
- (content_setting == CONTENT_SETTING_BLOCK) ||
- (content_setting == CONTENT_SETTING_SESSION_ONLY));
- ViewHostMsg_AllowDatabase::WriteReplyParams(
- reply_msg, content_setting != CONTENT_SETTING_BLOCK);
- Send(reply_msg);
-}
-
-void DatabaseDispatcherHost::DatabaseClosed(const string16& origin_identifier,
- const string16& database_name) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- if (!database_connections_.IsDatabaseOpened(
- origin_identifier, database_name)) {
- ReceivedBadMessage(ViewHostMsg_DatabaseClosed::ID);
- return;
- }
-
- db_tracker_->DatabaseClosed(origin_identifier, database_name);
- database_connections_.RemoveConnection(origin_identifier, database_name);
-}
-
-void DatabaseDispatcherHost::OnDatabaseSizeChanged(
- const string16& origin_identifier,
- const string16& database_name,
- int64 database_size,
- int64 space_available) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- if (database_connections_.IsOriginUsed(origin_identifier)) {
- Send(new ViewMsg_DatabaseUpdateSize(origin_identifier, database_name,
- database_size, space_available));
- }
-}
-
-void DatabaseDispatcherHost::OnDatabaseScheduledForDeletion(
- const string16& origin_identifier,
- const string16& database_name) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- Send(new ViewMsg_DatabaseCloseImmediately(origin_identifier, database_name));
-}
diff --git a/chrome/browser/renderer_host/database_dispatcher_host.h b/chrome/browser/renderer_host/database_dispatcher_host.h
deleted file mode 100644
index 000c063..0000000
--- a/chrome/browser/renderer_host/database_dispatcher_host.h
+++ /dev/null
@@ -1,139 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_RENDERER_HOST_DATABASE_DISPATCHER_HOST_H_
-#define CHROME_BROWSER_RENDERER_HOST_DATABASE_DISPATCHER_HOST_H_
-#pragma once
-
-#include "base/hash_tables.h"
-#include "base/process.h"
-#include "base/ref_counted.h"
-#include "base/string16.h"
-#include "chrome/common/content_settings.h"
-#include "ipc/ipc_message.h"
-#include "webkit/database/database_connections.h"
-#include "webkit/database/database_tracker.h"
-
-class GURL;
-class HostContentSettingsMap;
-class Receiver;
-class ResourceMessageFilter;
-
-class DatabaseDispatcherHost
- : public base::RefCountedThreadSafe<DatabaseDispatcherHost>,
- public webkit_database::DatabaseTracker::Observer {
- public:
- DatabaseDispatcherHost(webkit_database::DatabaseTracker* db_tracker,
- IPC::Message::Sender* sender,
- HostContentSettingsMap *host_content_settings_map);
- void Init(base::ProcessHandle process_handle);
- void Shutdown();
-
- bool OnMessageReceived(const IPC::Message& message, bool* message_was_ok);
-
- // VFS message handlers (IO thread)
- void OnDatabaseOpenFile(const string16& vfs_file_name,
- int desired_flags,
- IPC::Message* reply_msg);
- void OnDatabaseDeleteFile(const string16& vfs_file_name,
- const bool& sync_dir,
- IPC::Message* reply_msg);
- void OnDatabaseGetFileAttributes(const string16& vfs_file_name,
- IPC::Message* reply_msg);
- void OnDatabaseGetFileSize(const string16& vfs_file_name,
- IPC::Message* reply_msg);
-
- // Database tracker message handlers (IO thread)
- void OnDatabaseOpened(const string16& origin_identifier,
- const string16& database_name,
- const string16& description,
- int64 estimated_size);
- void OnDatabaseModified(const string16& origin_identifier,
- const string16& database_name);
- void OnDatabaseClosed(const string16& origin_identifier,
- const string16& database_name);
- void OnAllowDatabase(const std::string& origin_url,
- const string16& name,
- const string16& display_name,
- unsigned long estimated_size,
- IPC::Message* reply_msg);
-
- // DatabaseTracker::Observer callbacks (file thread)
- virtual void OnDatabaseSizeChanged(const string16& origin_identifier,
- const string16& database_name,
- int64 database_size,
- int64 space_available);
- virtual void OnDatabaseScheduledForDeletion(const string16& origin_identifier,
- const string16& database_name);
-
- webkit_database::DatabaseTracker* database_tracker() const {
- return db_tracker_.get();
- }
-
- void Send(IPC::Message* message);
-
- private:
- friend class base::RefCountedThreadSafe<DatabaseDispatcherHost>;
- virtual ~DatabaseDispatcherHost();
-
- class PromptDelegate;
-
- void AddObserver();
- void RemoveObserver();
-
- void ReceivedBadMessage(uint32 msg_type);
-
- // VFS message handlers (file thread)
- void DatabaseOpenFile(const string16& vfs_file_name,
- int desired_flags,
- IPC::Message* reply_msg);
- void DatabaseDeleteFile(const string16& vfs_file_name,
- bool sync_dir,
- IPC::Message* reply_msg,
- int reschedule_count);
- void DatabaseGetFileAttributes(const string16& vfs_file_name,
- IPC::Message* reply_msg);
- void DatabaseGetFileSize(const string16& vfs_file_name,
- IPC::Message* reply_msg);
-
- // Database tracker message handlers (file thread)
- void DatabaseOpened(const string16& origin_identifier,
- const string16& database_name,
- const string16& description,
- int64 estimated_size);
- void DatabaseModified(const string16& origin_identifier,
- const string16& database_name);
- void DatabaseClosed(const string16& origin_identifier,
- const string16& database_name);
-
- // CookiePromptModalDialog response handler (io thread)
- void AllowDatabaseResponse(IPC::Message* reply_msg,
- ContentSetting content_setting);
-
- // The database tracker for the current profile.
- scoped_refptr<webkit_database::DatabaseTracker> db_tracker_;
-
- // The sender to be used for sending out IPC messages.
- IPC::Message::Sender* message_sender_;
-
- // The handle of this process.
- base::ProcessHandle process_handle_;
-
- // True if and only if this instance was added as an observer
- // to DatabaseTracker.
- bool observer_added_;
-
- // If true, all messages that are normally processed by this class
- // will be silently discarded. This field should be set to true
- // only when the corresponding renderer process is about to go away.
- bool shutdown_;
-
- // Keeps track of all DB connections opened by this renderer
- webkit_database::DatabaseConnections database_connections_;
-
- // Used to look up permissions at database creation time.
- scoped_refptr<HostContentSettingsMap> host_content_settings_map_;
-};
-
-#endif // CHROME_BROWSER_RENDERER_HOST_DATABASE_DISPATCHER_HOST_H_
diff --git a/chrome/browser/renderer_host/database_message_filter.cc b/chrome/browser/renderer_host/database_message_filter.cc
new file mode 100644
index 0000000..b8258f9
--- /dev/null
+++ b/chrome/browser/renderer_host/database_message_filter.cc
@@ -0,0 +1,323 @@
+// 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.
+
+#include "chrome/browser/renderer_host/database_message_filter.h"
+
+#include <string>
+
+#include "base/string_util.h"
+#include "base/thread.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/net/chrome_url_request_context.h"
+#include "chrome/common/database_messages.h"
+#include "chrome/common/result_codes.h"
+#include "googleurl/src/gurl.h"
+#include "third_party/sqlite/sqlite3.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebSecurityOrigin.h"
+#include "webkit/database/database_util.h"
+#include "webkit/database/vfs_backend.h"
+
+#if defined(OS_POSIX)
+#include "base/file_descriptor_posix.h"
+#endif
+
+using WebKit::WebSecurityOrigin;
+using webkit_database::DatabaseTracker;
+using webkit_database::DatabaseUtil;
+using webkit_database::VfsBackend;
+
+const int kNumDeleteRetries = 2;
+const int kDelayDeleteRetryMs = 100;
+
+DatabaseMessageFilter::DatabaseMessageFilter(
+ webkit_database::DatabaseTracker* db_tracker,
+ HostContentSettingsMap *host_content_settings_map)
+ : db_tracker_(db_tracker),
+ observer_added_(false),
+ host_content_settings_map_(host_content_settings_map) {
+ DCHECK(db_tracker_);
+}
+
+void DatabaseMessageFilter::OnChannelClosing() {
+ BrowserMessageFilter::OnChannelClosing();
+ if (observer_added_) {
+ observer_added_ = false;
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(this, &DatabaseMessageFilter::RemoveObserver));
+ }
+}
+
+void DatabaseMessageFilter::AddObserver() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ db_tracker_->AddObserver(this);
+}
+
+void DatabaseMessageFilter::RemoveObserver() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+ // If the renderer process died without closing all databases,
+ // then we need to manually close those connections
+ db_tracker_->CloseDatabases(database_connections_);
+ database_connections_.RemoveAllConnections();
+
+ db_tracker_->RemoveObserver(this);
+}
+
+void DatabaseMessageFilter::OverrideThreadForMessage(
+ const IPC::Message& message,
+ BrowserThread::ID* thread) {
+ if (IPC_MESSAGE_CLASS(message) == DatabaseMsgStart &&
+ message.type() != DatabaseHostMsg_Allow::ID) {
+ *thread = BrowserThread::FILE;
+ }
+
+ if (message.type() == DatabaseHostMsg_OpenFile::ID && !observer_added_) {
+ observer_added_ = true;
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(this, &DatabaseMessageFilter::AddObserver));
+ }
+}
+
+bool DatabaseMessageFilter::OnMessageReceived(
+ const IPC::Message& message,
+ bool* message_was_ok) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(DatabaseMessageFilter, message, *message_was_ok)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(DatabaseHostMsg_OpenFile,
+ OnDatabaseOpenFile)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(DatabaseHostMsg_DeleteFile,
+ OnDatabaseDeleteFile)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(DatabaseHostMsg_GetFileAttributes,
+ OnDatabaseGetFileAttributes)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(DatabaseHostMsg_GetFileSize,
+ OnDatabaseGetFileSize)
+ IPC_MESSAGE_HANDLER(DatabaseHostMsg_Opened, OnDatabaseOpened)
+ IPC_MESSAGE_HANDLER(DatabaseHostMsg_Modified, OnDatabaseModified)
+ IPC_MESSAGE_HANDLER(DatabaseHostMsg_Closed, OnDatabaseClosed)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(DatabaseHostMsg_Allow, OnAllowDatabase)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP_EX()
+ return handled;
+}
+
+DatabaseMessageFilter::~DatabaseMessageFilter() {
+}
+
+void DatabaseMessageFilter::OnDatabaseOpenFile(const string16& vfs_file_name,
+ int desired_flags,
+ IPC::Message* reply_msg) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ base::PlatformFile file_handle = base::kInvalidPlatformFileValue;
+ base::PlatformFile target_handle = base::kInvalidPlatformFileValue;
+ string16 origin_identifier;
+ string16 database_name;
+
+ // When in incognito mode, we want to make sure that all DB files are
+ // removed when the incognito profile goes away, so we add the
+ // SQLITE_OPEN_DELETEONCLOSE flag when opening all files, and keep
+ // open handles to them in the database tracker to make sure they're
+ // around for as long as needed.
+ if (vfs_file_name.empty()) {
+ VfsBackend::OpenTempFileInDirectory(db_tracker_->DatabaseDirectory(),
+ desired_flags, &file_handle);
+ } else if (DatabaseUtil::CrackVfsFileName(vfs_file_name, &origin_identifier,
+ &database_name, NULL) &&
+ !db_tracker_->IsDatabaseScheduledForDeletion(origin_identifier,
+ database_name)) {
+ FilePath db_file =
+ DatabaseUtil::GetFullFilePathForVfsFile(db_tracker_, vfs_file_name);
+ if (!db_file.empty()) {
+ if (db_tracker_->IsIncognitoProfile()) {
+ db_tracker_->GetIncognitoFileHandle(vfs_file_name, &file_handle);
+ if (file_handle == base::kInvalidPlatformFileValue) {
+ VfsBackend::OpenFile(db_file,
+ desired_flags | SQLITE_OPEN_DELETEONCLOSE,
+ &file_handle);
+ if (VfsBackend::FileTypeIsMainDB(desired_flags) ||
+ VfsBackend::FileTypeIsJournal(desired_flags))
+ db_tracker_->SaveIncognitoFileHandle(vfs_file_name, file_handle);
+ }
+ } else {
+ VfsBackend::OpenFile(db_file, desired_flags, &file_handle);
+ }
+ }
+ }
+
+ // Then we duplicate the file handle to make it useable in the renderer
+ // process. The original handle is closed, unless we saved it in the
+ // database tracker.
+ bool auto_close = !db_tracker_->HasSavedIncognitoFileHandle(vfs_file_name);
+ VfsBackend::GetFileHandleForProcess(peer_handle(), file_handle,
+ &target_handle, auto_close);
+
+ DatabaseHostMsg_OpenFile::WriteReplyParams(
+ reply_msg,
+#if defined(OS_WIN)
+ target_handle
+#elif defined(OS_POSIX)
+ base::FileDescriptor(target_handle, auto_close)
+#endif
+ );
+ Send(reply_msg);
+}
+
+void DatabaseMessageFilter::OnDatabaseDeleteFile(const string16& vfs_file_name,
+ const bool& sync_dir,
+ IPC::Message* reply_msg) {
+ DatabaseDeleteFile(vfs_file_name, sync_dir, reply_msg, kNumDeleteRetries);
+}
+
+void DatabaseMessageFilter::DatabaseDeleteFile(const string16& vfs_file_name,
+ bool sync_dir,
+ IPC::Message* reply_msg,
+ int reschedule_count) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+ // Return an error if the file name is invalid or if the file could not
+ // be deleted after kNumDeleteRetries attempts.
+ int error_code = SQLITE_IOERR_DELETE;
+ FilePath db_file =
+ DatabaseUtil::GetFullFilePathForVfsFile(db_tracker_, vfs_file_name);
+ if (!db_file.empty()) {
+ // In order to delete a journal file in incognito mode, we only need to
+ // close the open handle to it that's stored in the database tracker.
+ if (db_tracker_->IsIncognitoProfile()) {
+ if (db_tracker_->CloseIncognitoFileHandle(vfs_file_name))
+ error_code = SQLITE_OK;
+ } else {
+ error_code = VfsBackend::DeleteFile(db_file, sync_dir);
+ }
+
+ if ((error_code == SQLITE_IOERR_DELETE) && reschedule_count) {
+ // If the file could not be deleted, try again.
+ BrowserThread::PostDelayedTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(this,
+ &DatabaseMessageFilter::DatabaseDeleteFile,
+ vfs_file_name,
+ sync_dir,
+ reply_msg,
+ reschedule_count - 1),
+ kDelayDeleteRetryMs);
+ return;
+ }
+ }
+
+ DatabaseHostMsg_DeleteFile::WriteReplyParams(reply_msg, error_code);
+ Send(reply_msg);
+}
+
+void DatabaseMessageFilter::OnDatabaseGetFileAttributes(
+ const string16& vfs_file_name,
+ IPC::Message* reply_msg) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ int32 attributes = -1;
+ FilePath db_file =
+ DatabaseUtil::GetFullFilePathForVfsFile(db_tracker_, vfs_file_name);
+ if (!db_file.empty())
+ attributes = VfsBackend::GetFileAttributes(db_file);
+
+ DatabaseHostMsg_GetFileAttributes::WriteReplyParams(
+ reply_msg, attributes);
+ Send(reply_msg);
+}
+
+void DatabaseMessageFilter::OnDatabaseGetFileSize(
+ const string16& vfs_file_name, IPC::Message* reply_msg) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ int64 size = 0;
+ FilePath db_file =
+ DatabaseUtil::GetFullFilePathForVfsFile(db_tracker_, vfs_file_name);
+ if (!db_file.empty())
+ size = VfsBackend::GetFileSize(db_file);
+
+ DatabaseHostMsg_GetFileSize::WriteReplyParams(reply_msg, size);
+ Send(reply_msg);
+}
+
+void DatabaseMessageFilter::OnDatabaseOpened(const string16& origin_identifier,
+ const string16& database_name,
+ const string16& description,
+ int64 estimated_size) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ int64 database_size = 0;
+ int64 space_available = 0;
+ database_connections_.AddConnection(origin_identifier, database_name);
+ db_tracker_->DatabaseOpened(origin_identifier, database_name, description,
+ estimated_size, &database_size, &space_available);
+ Send(new DatabaseMsg_UpdateSize(origin_identifier, database_name,
+ database_size, space_available));
+}
+
+void DatabaseMessageFilter::OnDatabaseModified(
+ const string16& origin_identifier,
+ const string16& database_name) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ if (!database_connections_.IsDatabaseOpened(
+ origin_identifier, database_name)) {
+ UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_DBMF"));
+ BadMessageReceived();
+ return;
+ }
+
+ db_tracker_->DatabaseModified(origin_identifier, database_name);
+}
+
+void DatabaseMessageFilter::OnDatabaseClosed(const string16& origin_identifier,
+ const string16& database_name) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ if (!database_connections_.IsDatabaseOpened(
+ origin_identifier, database_name)) {
+ UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_DBMF"));
+ BadMessageReceived();
+ return;
+ }
+
+ db_tracker_->DatabaseClosed(origin_identifier, database_name);
+ database_connections_.RemoveConnection(origin_identifier, database_name);
+}
+
+void DatabaseMessageFilter::OnAllowDatabase(const std::string& origin_url,
+ const string16& name,
+ const string16& display_name,
+ unsigned long estimated_size,
+ IPC::Message* reply_msg) {
+ GURL url = GURL(origin_url);
+ ContentSetting content_setting =
+ host_content_settings_map_->GetContentSetting(
+ url, CONTENT_SETTINGS_TYPE_COOKIES, "");
+ AllowDatabaseResponse(reply_msg, content_setting);
+}
+
+void DatabaseMessageFilter::AllowDatabaseResponse(
+ IPC::Message* reply_msg, ContentSetting content_setting) {
+ DCHECK((content_setting == CONTENT_SETTING_ALLOW) ||
+ (content_setting == CONTENT_SETTING_BLOCK) ||
+ (content_setting == CONTENT_SETTING_SESSION_ONLY));
+ DatabaseHostMsg_Allow::WriteReplyParams(
+ reply_msg, content_setting != CONTENT_SETTING_BLOCK);
+ Send(reply_msg);
+}
+
+void DatabaseMessageFilter::OnDatabaseSizeChanged(
+ const string16& origin_identifier,
+ const string16& database_name,
+ int64 database_size,
+ int64 space_available) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ if (database_connections_.IsOriginUsed(origin_identifier)) {
+ Send(new DatabaseMsg_UpdateSize(origin_identifier, database_name,
+ database_size, space_available));
+ }
+}
+
+void DatabaseMessageFilter::OnDatabaseScheduledForDeletion(
+ const string16& origin_identifier,
+ const string16& database_name) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ Send(new DatabaseMsg_CloseImmediately(origin_identifier, database_name));
+}
diff --git a/chrome/browser/renderer_host/database_message_filter.h b/chrome/browser/renderer_host/database_message_filter.h
new file mode 100644
index 0000000..4bd9994
--- /dev/null
+++ b/chrome/browser/renderer_host/database_message_filter.h
@@ -0,0 +1,103 @@
+// 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.
+
+#ifndef CHROME_BROWSER_RENDERER_HOST_DATABASE_MESSAGE_FILTER_H_
+#define CHROME_BROWSER_RENDERER_HOST_DATABASE_MESSAGE_FILTER_H_
+#pragma once
+
+#include "base/hash_tables.h"
+#include "base/string16.h"
+#include "chrome/browser/browser_message_filter.h"
+#include "chrome/common/content_settings.h"
+#include "webkit/database/database_connections.h"
+#include "webkit/database/database_tracker.h"
+
+class HostContentSettingsMap;
+
+class DatabaseMessageFilter
+ : public BrowserMessageFilter,
+ public webkit_database::DatabaseTracker::Observer {
+ public:
+ DatabaseMessageFilter(
+ webkit_database::DatabaseTracker* db_tracker,
+ HostContentSettingsMap *host_content_settings_map);
+
+ // BrowserMessageFilter implementation.
+ virtual void OnChannelClosing();
+ virtual void OverrideThreadForMessage(const IPC::Message& message,
+ BrowserThread::ID* thread);
+ virtual bool OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok);
+
+ webkit_database::DatabaseTracker* database_tracker() const {
+ return db_tracker_.get();
+ }
+
+ private:
+ virtual ~DatabaseMessageFilter();
+
+ class PromptDelegate;
+
+ void AddObserver();
+ void RemoveObserver();
+
+ // VFS message handlers (file thread)
+ void OnDatabaseOpenFile(const string16& vfs_file_name,
+ int desired_flags,
+ IPC::Message* reply_msg);
+ void OnDatabaseDeleteFile(const string16& vfs_file_name,
+ const bool& sync_dir,
+ IPC::Message* reply_msg);
+ void OnDatabaseGetFileAttributes(const string16& vfs_file_name,
+ IPC::Message* reply_msg);
+ void OnDatabaseGetFileSize(const string16& vfs_file_name,
+ IPC::Message* reply_msg);
+
+ // Database tracker message handlers (file thread)
+ void OnDatabaseOpened(const string16& origin_identifier,
+ const string16& database_name,
+ const string16& description,
+ int64 estimated_size);
+ void OnDatabaseModified(const string16& origin_identifier,
+ const string16& database_name);
+ void OnDatabaseClosed(const string16& origin_identifier,
+ const string16& database_name);
+ void OnAllowDatabase(const std::string& origin_url,
+ const string16& name,
+ const string16& display_name,
+ unsigned long estimated_size,
+ IPC::Message* reply_msg);
+
+ // DatabaseTracker::Observer callbacks (file thread)
+ virtual void OnDatabaseSizeChanged(const string16& origin_identifier,
+ const string16& database_name,
+ int64 database_size,
+ int64 space_available);
+ virtual void OnDatabaseScheduledForDeletion(const string16& origin_identifier,
+ const string16& database_name);
+
+ void DatabaseDeleteFile(const string16& vfs_file_name,
+ bool sync_dir,
+ IPC::Message* reply_msg,
+ int reschedule_count);
+
+ // CookiePromptModalDialog response handler (io thread)
+ void AllowDatabaseResponse(IPC::Message* reply_msg,
+ ContentSetting content_setting);
+
+ // The database tracker for the current profile.
+ scoped_refptr<webkit_database::DatabaseTracker> db_tracker_;
+
+ // True if and only if this instance was added as an observer
+ // to DatabaseTracker.
+ bool observer_added_;
+
+ // Keeps track of all DB connections opened by this renderer
+ webkit_database::DatabaseConnections database_connections_;
+
+ // Used to look up permissions at database creation time.
+ scoped_refptr<HostContentSettingsMap> host_content_settings_map_;
+};
+
+#endif // CHROME_BROWSER_RENDERER_HOST_DATABASE_MESSAGE_FILTER_H_
diff --git a/chrome/browser/renderer_host/download_resource_handler.cc b/chrome/browser/renderer_host/download_resource_handler.cc
index 83d64f8..7adc462 100644
--- a/chrome/browser/renderer_host/download_resource_handler.cc
+++ b/chrome/browser/renderer_host/download_resource_handler.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// 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.
@@ -7,6 +7,8 @@
#include <string>
#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/stats_counters.h"
#include "base/stringprintf.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/download/download_item.h"
@@ -14,6 +16,7 @@
#include "chrome/browser/history/download_create_info.h"
#include "chrome/browser/renderer_host/global_request_id.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
#include "chrome/common/resource_response.h"
#include "net/base/io_buffer.h"
#include "net/http/http_response_headers.h"
@@ -26,7 +29,7 @@ DownloadResourceHandler::DownloadResourceHandler(
int request_id,
const GURL& url,
DownloadFileManager* download_file_manager,
- URLRequest* request,
+ net::URLRequest* request,
bool save_as,
const DownloadSaveInfo& save_info)
: download_id_(-1),
@@ -40,7 +43,8 @@ DownloadResourceHandler::DownloadResourceHandler(
save_info_(save_info),
buffer_(new DownloadBuffer),
rdh_(rdh),
- is_paused_(false) {
+ is_paused_(false),
+ url_check_pending_(false) {
}
bool DownloadResourceHandler::OnUploadProgress(int request_id,
@@ -58,17 +62,64 @@ bool DownloadResourceHandler::OnRequestRedirected(int request_id,
return true;
}
+// Callback when the result of checking a download URL is known.
+// TODO(lzheng): We should create a information bar with buttons to ask
+// if users want to proceed when the download is malicious.
+void DownloadResourceHandler::OnDownloadUrlCheckResult(
+ const GURL& url, SafeBrowsingService::UrlCheckResult result) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(url_check_pending_);
+
+ UMA_HISTOGRAM_TIMES("SB2.DownloadUrlCheckDuration",
+ base::TimeTicks::Now() - download_start_time_);
+
+ if (result == SafeBrowsingService::BINARY_MALWARE) {
+ // TODO(lzheng): More UI work to show warnings properly on download shelf.
+ DLOG(WARNING) << "This url leads to a malware downloading: "
+ << url.spec();
+ UpdateDownloadUrlCheckStats(DOWNLOAD_URL_CHECKS_MALWARE);
+ }
+
+ url_check_pending_ = false;
+ // Note: Release() should be the last line in this call. It is for
+ // the AddRef in CheckSafeBrowsing.
+ Release();
+}
+
+// Send the download creation information to the download thread.
+void DownloadResourceHandler::StartDownloadUrlCheck() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ AddRef();
+ if (!rdh_->safe_browsing_service()->CheckDownloadUrl(url_, this)) {
+ url_check_pending_ = true;
+ UpdateDownloadUrlCheckStats(DOWNLOAD_URL_CHECKS_TOTAL);
+ // Note: in this case, the AddRef will be balanced in
+ // "OnDownloadUrlCheckResult" or "OnRequestClosed".
+ } else {
+ // Immediately release the AddRef() at the beginning of this function
+ // since no more callbacks will happen.
+ Release();
+ DVLOG(1) << "url: " << url_.spec() << " is safe to download.";
+ }
+}
+
// Send the download creation information to the download thread.
bool DownloadResourceHandler::OnResponseStarted(int request_id,
ResourceResponse* response) {
VLOG(20) << __FUNCTION__ << "()" << DebugString()
<< " request_id = " << request_id;
+ DCHECK(!url_check_pending_);
+ download_start_time_ = base::TimeTicks::Now();
+ StartDownloadUrlCheck();
std::string content_disposition;
request_->GetResponseHeaderByName("content-disposition",
&content_disposition);
set_content_disposition(content_disposition);
set_content_length(response->response_head.content_length);
+ const ResourceDispatcherHostRequestInfo* request_info =
+ ResourceDispatcherHost::InfoForRequest(request_);
+
download_id_ = download_file_manager_->GetNextId();
// |download_file_manager_| consumes (deletes):
DownloadCreateInfo* info = new DownloadCreateInfo;
@@ -79,6 +130,7 @@ bool DownloadResourceHandler::OnResponseStarted(int request_id,
info->total_bytes = content_length_;
info->state = DownloadItem::IN_PROGRESS;
info->download_id = download_id_;
+ info->has_user_gesture = request_info->has_user_gesture();
info->child_id = global_id_.child_id;
info->render_view_id = render_view_id_;
info->request_id = global_id_.request_id;
@@ -178,6 +230,17 @@ bool DownloadResourceHandler::OnResponseCompleted(
}
void DownloadResourceHandler::OnRequestClosed() {
+ UMA_HISTOGRAM_TIMES("SB2.DownloadDuration",
+ base::TimeTicks::Now() - download_start_time_);
+ if (url_check_pending_) {
+ DVLOG(1) << "Cancel pending download url checking request: " << this;
+ rdh_->safe_browsing_service()->CancelCheck(this);
+ UpdateDownloadUrlCheckStats(DOWNLOAD_URL_CHECKS_CANCELED);
+ url_check_pending_ = false;
+ // Balance the AddRef() from StartDownloadUrlCheck() which would usually be
+ // balanced by OnDownloadUrlCheckResult().
+ Release();
+ }
}
// If the content-length header is not present (or contains something other
@@ -235,7 +298,7 @@ std::string DownloadResourceHandler::DebugString() const {
" request_id = " "%d"
" }"
" render_view_id_ = " "%d"
- " save_info_.file_path = " "\"%s\""
+ " save_info_.file_path = \"%" PRFilePath "\""
" }",
url_.spec().c_str(),
download_id_,
@@ -244,3 +307,10 @@ std::string DownloadResourceHandler::DebugString() const {
render_view_id_,
save_info_.file_path.value().c_str());
}
+
+void DownloadResourceHandler::UpdateDownloadUrlCheckStats(
+ SBStatsType stat_type) {
+ UMA_HISTOGRAM_ENUMERATION("SB2.DownloadUrlChecks",
+ stat_type,
+ DOWNLOAD_URL_CHECKS_MAX);
+}
diff --git a/chrome/browser/renderer_host/download_resource_handler.h b/chrome/browser/renderer_host/download_resource_handler.h
index 95c09da..5a66f66 100644
--- a/chrome/browser/renderer_host/download_resource_handler.h
+++ b/chrome/browser/renderer_host/download_resource_handler.h
@@ -12,6 +12,7 @@
#include "chrome/browser/download/download_file.h"
#include "chrome/browser/renderer_host/global_request_id.h"
#include "chrome/browser/renderer_host/resource_handler.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
class DownloadFileManager;
class ResourceDispatcherHost;
@@ -22,7 +23,8 @@ class URLRequest;
} // namespace net
// Forwards data to the download thread.
-class DownloadResourceHandler : public ResourceHandler {
+class DownloadResourceHandler : public ResourceHandler,
+ public SafeBrowsingService::Client {
public:
DownloadResourceHandler(ResourceDispatcherHost* rdh,
int render_process_host_id,
@@ -34,29 +36,29 @@ class DownloadResourceHandler : public ResourceHandler {
bool save_as,
const DownloadSaveInfo& save_info);
- bool OnUploadProgress(int request_id, uint64 position, uint64 size);
+ virtual bool OnUploadProgress(int request_id, uint64 position, uint64 size);
// Not needed, as this event handler ought to be the final resource.
- bool OnRequestRedirected(int request_id, const GURL& url,
- ResourceResponse* response, bool* defer);
+ virtual bool OnRequestRedirected(int request_id, const GURL& url,
+ ResourceResponse* response, bool* defer);
// Send the download creation information to the download thread.
- bool OnResponseStarted(int request_id, ResourceResponse* response);
+ virtual bool OnResponseStarted(int request_id, ResourceResponse* response);
// Pass-through implementation.
- bool OnWillStart(int request_id, const GURL& url, bool* defer);
+ virtual bool OnWillStart(int request_id, const GURL& url, bool* defer);
// Create a new buffer, which will be handed to the download thread for file
// writing and deletion.
- bool OnWillRead(int request_id, net::IOBuffer** buf, int* buf_size,
- int min_size);
+ virtual bool OnWillRead(int request_id, net::IOBuffer** buf, int* buf_size,
+ int min_size);
- bool OnReadCompleted(int request_id, int* bytes_read);
+ virtual bool OnReadCompleted(int request_id, int* bytes_read);
- bool OnResponseCompleted(int request_id,
- const URLRequestStatus& status,
- const std::string& security_info);
- void OnRequestClosed();
+ virtual bool OnResponseCompleted(int request_id,
+ const URLRequestStatus& status,
+ const std::string& security_info);
+ virtual void OnRequestClosed();
// If the content-length header is not present (or contains something other
// than numbers), the incoming content_length is -1 (unknown size).
@@ -70,10 +72,31 @@ class DownloadResourceHandler : public ResourceHandler {
std::string DebugString() const;
private:
+ // Enumerate for histogramming purposes. DO NOT CHANGE THE
+ // ORDERING OF THESE VALUES.
+ enum SBStatsType {
+ DOWNLOAD_URL_CHECKS_TOTAL,
+ DOWNLOAD_URL_CHECKS_CANCELED,
+ DOWNLOAD_URL_CHECKS_MALWARE,
+
+ // Memory space for histograms is determined by the max. ALWAYS
+ // ADD NEW VALUES BEFORE THIS ONE.
+ DOWNLOAD_URL_CHECKS_MAX
+ };
+
~DownloadResourceHandler();
void StartPauseTimer();
+ void StartDownloadUrlCheck();
+
+ // Called when the result of checking a download URL is known.
+ void OnDownloadUrlCheckResult(const GURL& url,
+ SafeBrowsingService::UrlCheckResult result);
+
+ // A helper function that updates UMA for download url checks.
+ static void UpdateDownloadUrlCheckStats(SBStatsType stat_type);
+
int download_id_;
GlobalRequestID global_id_;
int render_view_id_;
@@ -89,6 +112,8 @@ class DownloadResourceHandler : public ResourceHandler {
ResourceDispatcherHost* rdh_;
bool is_paused_;
base::OneShotTimer<DownloadResourceHandler> pause_timer_;
+ bool url_check_pending_;
+ base::TimeTicks download_start_time_; // used to collect stats.
static const int kReadBufSize = 32768; // bytes
static const size_t kLoadsToWrite = 100; // number of data buffers queued
diff --git a/chrome/browser/renderer_host/download_throttling_resource_handler.cc b/chrome/browser/renderer_host/download_throttling_resource_handler.cc
index 3c0e32b..833c8a1 100644
--- a/chrome/browser/renderer_host/download_throttling_resource_handler.cc
+++ b/chrome/browser/renderer_host/download_throttling_resource_handler.cc
@@ -13,7 +13,7 @@
DownloadThrottlingResourceHandler::DownloadThrottlingResourceHandler(
ResourceDispatcherHost* host,
- URLRequest* request,
+ net::URLRequest* request,
const GURL& url,
int render_process_host_id,
int render_view_id,
diff --git a/chrome/browser/renderer_host/file_utilities_dispatcher_host.cc b/chrome/browser/renderer_host/file_utilities_dispatcher_host.cc
deleted file mode 100644
index ad6fe97..0000000
--- a/chrome/browser/renderer_host/file_utilities_dispatcher_host.cc
+++ /dev/null
@@ -1,199 +0,0 @@
-// 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.
-
-#include "chrome/browser/renderer_host/file_utilities_dispatcher_host.h"
-
-#include "base/file_util.h"
-#include "base/platform_file.h"
-#include "chrome/browser/child_process_security_policy.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/common/render_messages.h"
-#include "chrome/common/render_messages_params.h"
-
-namespace {
-
-void WriteFileSize(IPC::Message* reply_msg,
- const base::PlatformFileInfo& file_info) {
- ViewHostMsg_GetFileSize::WriteReplyParams(reply_msg, file_info.size);
-}
-
-void WriteFileModificationTime(IPC::Message* reply_msg,
- const base::PlatformFileInfo& file_info) {
- ViewHostMsg_GetFileModificationTime::WriteReplyParams(
- reply_msg, file_info.last_modified);
-}
-
-} // namespace
-
-FileUtilitiesDispatcherHost::FileUtilitiesDispatcherHost(
- IPC::Message::Sender* sender, int process_id)
- : message_sender_(sender),
- process_id_(process_id),
- process_handle_(0),
- shutdown_(false) {
- DCHECK(message_sender_);
-}
-
-FileUtilitiesDispatcherHost::~FileUtilitiesDispatcherHost() {
-}
-
-void FileUtilitiesDispatcherHost::Init(base::ProcessHandle process_handle) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK(!shutdown_);
- DCHECK(!process_handle_);
- DCHECK(process_handle);
- process_handle_ = process_handle;
-}
-
-void FileUtilitiesDispatcherHost::Shutdown() {
- message_sender_ = NULL;
- shutdown_ = true;
-}
-
-bool FileUtilitiesDispatcherHost::OnMessageReceived(
- const IPC::Message& message) {
- DCHECK(!shutdown_);
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(FileUtilitiesDispatcherHost, message)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetFileSize, OnGetFileSize)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetFileModificationTime,
- OnGetFileModificationTime)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_OpenFile, OnOpenFile)
- IPC_MESSAGE_UNHANDLED((handled = false))
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void FileUtilitiesDispatcherHost::OnGetFileSize(
- const FilePath& path, IPC::Message* reply_msg) {
- // Get file size only when the child process has been granted permission to
- // upload the file.
- if (!ChildProcessSecurityPolicy::GetInstance()->CanReadFile(
- process_id_, path)) {
- ViewHostMsg_GetFileSize::WriteReplyParams(
- reply_msg, static_cast<int64>(-1));
- Send(reply_msg);
- return;
- }
-
- // Getting file size could take long time if it lives on a network share,
- // so run it on FILE thread.
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(
- this, &FileUtilitiesDispatcherHost::OnGetFileInfoOnFileThread, path,
- reply_msg, &WriteFileSize));
-}
-
-void FileUtilitiesDispatcherHost::OnGetFileModificationTime(
- const FilePath& path, IPC::Message* reply_msg) {
- // Get file modification time only when the child process has been granted
- // permission to upload the file.
- if (!ChildProcessSecurityPolicy::GetInstance()->CanReadFile(
- process_id_, path)) {
- ViewHostMsg_GetFileModificationTime::WriteReplyParams(reply_msg,
- base::Time());
- Send(reply_msg);
- return;
- }
-
- // Getting file modification time could take a long time if it lives on a
- // network share, so run it on the FILE thread.
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(
- this, &FileUtilitiesDispatcherHost::OnGetFileInfoOnFileThread,
- path, reply_msg, &WriteFileModificationTime));
-}
-
-void FileUtilitiesDispatcherHost::OnGetFileInfoOnFileThread(
- const FilePath& path,
- IPC::Message* reply_msg,
- FileInfoWriteFunc write_func) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- base::PlatformFileInfo file_info;
- file_info.size = 0;
- file_util::GetFileInfo(path, &file_info);
-
- (*write_func)(reply_msg, file_info);
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(this, &FileUtilitiesDispatcherHost::Send, reply_msg));
-}
-
-void FileUtilitiesDispatcherHost::OnOpenFile(
- const FilePath& path, int mode, IPC::Message* reply_msg) {
- // Open the file only when the child process has been granted permission to
- // upload the file.
- // TODO(jianli): Do we need separate permission to control opening the file?
- if (!ChildProcessSecurityPolicy::GetInstance()->CanReadFile(
- process_id_, path)) {
- ViewHostMsg_OpenFile::WriteReplyParams(
- reply_msg,
-#if defined(OS_WIN)
- base::kInvalidPlatformFileValue
-#elif defined(OS_POSIX)
- base::FileDescriptor(base::kInvalidPlatformFileValue, true)
-#endif
- );
- Send(reply_msg);
- return;
- }
-
- // Opening the file could take a long time if it lives on a network share,
- // so run it on the FILE thread.
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(
- this, &FileUtilitiesDispatcherHost::OnOpenFileOnFileThread,
- path, mode, reply_msg));
-}
-
-void FileUtilitiesDispatcherHost::OnOpenFileOnFileThread(
- const FilePath& path, int mode, IPC::Message* reply_msg) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- base::PlatformFile file_handle = base::CreatePlatformFile(
- path,
- (mode == 0) ? (base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ)
- : (base::PLATFORM_FILE_CREATE_ALWAYS |
- base::PLATFORM_FILE_WRITE),
- NULL, NULL);
-
- base::PlatformFile target_file_handle;
-#if defined(OS_WIN)
- // Duplicate the file handle so that the renderer process can access the file.
- if (!DuplicateHandle(GetCurrentProcess(), file_handle,
- process_handle_, &target_file_handle, 0, false,
- DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
- // file_handle is closed whether or not DuplicateHandle succeeds.
- target_file_handle = INVALID_HANDLE_VALUE;
- }
-#else
- target_file_handle = file_handle;
-#endif
-
- ViewHostMsg_OpenFile::WriteReplyParams(
- reply_msg,
-#if defined(OS_WIN)
- target_file_handle
-#elif defined(OS_POSIX)
- base::FileDescriptor(target_file_handle, true)
-#endif
- );
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(this, &FileUtilitiesDispatcherHost::Send, reply_msg));
-}
-
-void FileUtilitiesDispatcherHost::Send(IPC::Message* message) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (!shutdown_ && message_sender_)
- message_sender_->Send(message);
- else
- delete message;
-}
diff --git a/chrome/browser/renderer_host/file_utilities_dispatcher_host.h b/chrome/browser/renderer_host/file_utilities_dispatcher_host.h
deleted file mode 100644
index b62aff5..0000000
--- a/chrome/browser/renderer_host/file_utilities_dispatcher_host.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_RENDERER_HOST_FILE_UTILITIES_DISPATCHER_HOST_H_
-#define CHROME_BROWSER_RENDERER_HOST_FILE_UTILITIES_DISPATCHER_HOST_H_
-
-#include "base/basictypes.h"
-#include "base/file_path.h"
-#include "base/process.h"
-#include "base/ref_counted.h"
-#include "ipc/ipc_message.h"
-
-namespace base {
-struct PlatformFileInfo;
-}
-
-namespace IPC {
-class Message;
-}
-
-class FileUtilitiesDispatcherHost
- : public base::RefCountedThreadSafe<FileUtilitiesDispatcherHost> {
- public:
- FileUtilitiesDispatcherHost(IPC::Message::Sender* sender, int process_id);
- void Init(base::ProcessHandle process_handle);
- void Shutdown();
- bool OnMessageReceived(const IPC::Message& message);
-
- void Send(IPC::Message* message);
-
- private:
- friend class base::RefCountedThreadSafe<FileUtilitiesDispatcherHost>;
- ~FileUtilitiesDispatcherHost();
-
- typedef void (*FileInfoWriteFunc)(IPC::Message* reply_msg,
- const base::PlatformFileInfo& file_info);
-
- void OnGetFileSize(const FilePath& path, IPC::Message* reply_msg);
- void OnGetFileModificationTime(const FilePath& path, IPC::Message* reply_msg);
- void OnGetFileInfoOnFileThread(const FilePath& path,
- IPC::Message* reply_msg,
- FileInfoWriteFunc write_func);
- void OnOpenFile(const FilePath& path, int mode,IPC::Message* reply_msg);
- void OnOpenFileOnFileThread(const FilePath& path,
- int mode,
- IPC::Message* reply_msg);
-
- // The sender to be used for sending out IPC messages.
- IPC::Message::Sender* message_sender_;
-
- // The ID of this process.
- int process_id_;
-
- // The handle of this process.
- base::ProcessHandle process_handle_;
-
- bool shutdown_;
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(FileUtilitiesDispatcherHost);
-};
-
-#endif // CHROME_BROWSER_RENDERER_HOST_FILE_UTILITIES_DISPATCHER_HOST_H_
diff --git a/chrome/browser/renderer_host/file_utilities_message_filter.cc b/chrome/browser/renderer_host/file_utilities_message_filter.cc
new file mode 100644
index 0000000..f49c634
--- /dev/null
+++ b/chrome/browser/renderer_host/file_utilities_message_filter.cc
@@ -0,0 +1,106 @@
+// 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.
+
+#include "chrome/browser/renderer_host/file_utilities_message_filter.h"
+
+#include "base/file_util.h"
+#include "chrome/browser/child_process_security_policy.h"
+#include "chrome/common/file_utilities_messages.h"
+
+
+FileUtilitiesMessageFilter::FileUtilitiesMessageFilter(int process_id)
+ : process_id_(process_id) {
+}
+
+FileUtilitiesMessageFilter::~FileUtilitiesMessageFilter() {
+}
+
+void FileUtilitiesMessageFilter::OverrideThreadForMessage(
+ const IPC::Message& message,
+ BrowserThread::ID* thread) {
+ if (IPC_MESSAGE_CLASS(message) == FileUtilitiesMsgStart)
+ *thread = BrowserThread::FILE;
+}
+
+bool FileUtilitiesMessageFilter::OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(FileUtilitiesMessageFilter, message, *message_was_ok)
+ IPC_MESSAGE_HANDLER(FileUtilitiesMsg_GetFileSize, OnGetFileSize)
+ IPC_MESSAGE_HANDLER(FileUtilitiesMsg_GetFileModificationTime,
+ OnGetFileModificationTime)
+ IPC_MESSAGE_HANDLER(FileUtilitiesMsg_OpenFile, OnOpenFile)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void FileUtilitiesMessageFilter::OnGetFileSize(const FilePath& path,
+ int64* result) {
+ // Get file size only when the child process has been granted permission to
+ // upload the file.
+ if (!ChildProcessSecurityPolicy::GetInstance()->CanReadFile(
+ process_id_, path)) {
+ *result = -1;
+ return;
+ }
+
+ base::PlatformFileInfo file_info;
+ file_info.size = 0;
+ file_util::GetFileInfo(path, &file_info);
+ *result = file_info.size;
+}
+
+void FileUtilitiesMessageFilter::OnGetFileModificationTime(
+ const FilePath& path, base::Time* result) {
+ // Get file modification time only when the child process has been granted
+ // permission to upload the file.
+ if (!ChildProcessSecurityPolicy::GetInstance()->CanReadFile(
+ process_id_, path)) {
+ *result = base::Time();
+ return;
+ }
+
+ base::PlatformFileInfo file_info;
+ file_info.size = 0;
+ file_util::GetFileInfo(path, &file_info);
+ *result = file_info.last_modified;
+}
+
+void FileUtilitiesMessageFilter::OnOpenFile(
+ const FilePath& path,
+ int mode,
+ IPC::PlatformFileForTransit* result) {
+ // Open the file only when the child process has been granted permission to
+ // upload the file.
+ // TODO(jianli): Do we need separate permission to control opening the file?
+ if (!ChildProcessSecurityPolicy::GetInstance()->CanReadFile(
+ process_id_, path)) {
+#if defined(OS_WIN)
+ *result = base::kInvalidPlatformFileValue;
+#elif defined(OS_POSIX)
+ *result = base::FileDescriptor(base::kInvalidPlatformFileValue, true);
+#endif
+ return;
+ }
+
+ base::PlatformFile file_handle = base::CreatePlatformFile(
+ path,
+ (mode == 0) ? (base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ)
+ : (base::PLATFORM_FILE_CREATE_ALWAYS |
+ base::PLATFORM_FILE_WRITE),
+ NULL, NULL);
+
+#if defined(OS_WIN)
+ // Duplicate the file handle so that the renderer process can access the file.
+ if (!DuplicateHandle(GetCurrentProcess(), file_handle,
+ peer_handle(), result, 0, false,
+ DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+ // file_handle is closed whether or not DuplicateHandle succeeds.
+ *result = INVALID_HANDLE_VALUE;
+ }
+#else
+ *result = base::FileDescriptor(file_handle, true);
+#endif
+}
diff --git a/chrome/browser/renderer_host/file_utilities_message_filter.h b/chrome/browser/renderer_host/file_utilities_message_filter.h
new file mode 100644
index 0000000..9a1c9af
--- /dev/null
+++ b/chrome/browser/renderer_host/file_utilities_message_filter.h
@@ -0,0 +1,48 @@
+// 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.
+
+#ifndef CHROME_BROWSER_RENDERER_HOST_FILE_UTILITIES_MESSAGE_FILTER_H_
+#define CHROME_BROWSER_RENDERER_HOST_FILE_UTILITIES_MESSAGE_FILTER_H_
+
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "chrome/browser/browser_message_filter.h"
+#include "ipc/ipc_platform_file.h"
+
+namespace base {
+struct PlatformFileInfo;
+}
+
+namespace IPC {
+class Message;
+}
+
+class FileUtilitiesMessageFilter : public BrowserMessageFilter {
+ public:
+ explicit FileUtilitiesMessageFilter(int process_id);
+
+ // BrowserMessageFilter implementation.
+ virtual void OverrideThreadForMessage(const IPC::Message& message,
+ BrowserThread::ID* thread);
+ virtual bool OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok);
+ private:
+ ~FileUtilitiesMessageFilter();
+
+ typedef void (*FileInfoWriteFunc)(IPC::Message* reply_msg,
+ const base::PlatformFileInfo& file_info);
+
+ void OnGetFileSize(const FilePath& path, int64* result);
+ void OnGetFileModificationTime(const FilePath& path, base::Time* result);
+ void OnOpenFile(const FilePath& path,
+ int mode,
+ IPC::PlatformFileForTransit* result);
+
+ // The ID of this process.
+ int process_id_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(FileUtilitiesMessageFilter);
+};
+
+#endif // CHROME_BROWSER_RENDERER_HOST_FILE_UTILITIES_MESSAGE_FILTER_H_
diff --git a/chrome/browser/renderer_host/global_request_id.h b/chrome/browser/renderer_host/global_request_id.h
index eb9520b..cb87c39 100644
--- a/chrome/browser/renderer_host/global_request_id.h
+++ b/chrome/browser/renderer_host/global_request_id.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// 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.
@@ -6,7 +6,7 @@
#define CHROME_BROWSER_RENDERER_HOST_GLOBAL_REQUEST_ID_H_
#pragma once
-// Uniquely identifies a URLRequest.
+// Uniquely identifies a net::URLRequest.
struct GlobalRequestID {
GlobalRequestID() : child_id(-1), request_id(-1) {
}
diff --git a/chrome/browser/renderer_host/gtk_im_context_wrapper.cc b/chrome/browser/renderer_host/gtk_im_context_wrapper.cc
index 25ec4f0..0c2002c 100644
--- a/chrome/browser/renderer_host/gtk_im_context_wrapper.cc
+++ b/chrome/browser/renderer_host/gtk_im_context_wrapper.cc
@@ -28,6 +28,22 @@
#include "grit/generated_resources.h"
#include "third_party/skia/include/core/SkColor.h"
+namespace {
+// Copied from third_party/WebKit/WebCore/page/EventHandler.cpp
+//
+// Match key code of composition keydown event on windows.
+// IE sends VK_PROCESSKEY which has value 229;
+//
+// Please refer to following documents for detals:
+// - Virtual-Key Codes
+// http://msdn.microsoft.com/en-us/library/ms645540(VS.85).aspx
+// - How the IME System Works
+// http://msdn.microsoft.com/en-us/library/cc194848.aspx
+// - ImmGetVirtualKey Function
+// http://msdn.microsoft.com/en-us/library/dd318570(VS.85).aspx
+const int kCompositionEventKeyCode = 229;
+} // namespace
+
GtkIMContextWrapper::GtkIMContextWrapper(RenderWidgetHostViewGtk* host_view)
: host_view_(host_view),
context_(gtk_im_multicontext_new()),
@@ -317,20 +333,6 @@ bool GtkIMContextWrapper::NeedCommitByForwardingCharEvent() {
void GtkIMContextWrapper::ProcessFilteredKeyPressEvent(
NativeWebKeyboardEvent* wke) {
- // Copied from third_party/WebKit/WebCore/page/EventHandler.cpp
- //
- // Match key code of composition keydown event on windows.
- // IE sends VK_PROCESSKEY which has value 229;
- //
- // Please refer to following documents for detals:
- // - Virtual-Key Codes
- // http://msdn.microsoft.com/en-us/library/ms645540(VS.85).aspx
- // - How the IME System Works
- // http://msdn.microsoft.com/en-us/library/cc194848.aspx
- // - ImmGetVirtualKey Function
- // http://msdn.microsoft.com/en-us/library/dd318570(VS.85).aspx
- const int kCompositionEventKeyCode = 229;
-
// If IME has filtered this event, then replace virtual key code with
// VK_PROCESSKEY. See comment in ProcessKeyEvent() for details.
// It's only required for keydown events.
@@ -450,8 +452,12 @@ void GtkIMContextWrapper::HandleCommit(const string16& text) {
// It's possible that commit signal is fired without a key event, for
// example when user input via a voice or handwriting recognition software.
// In this case, the text must be committed directly.
- if (!is_in_key_event_handler_ && host_view_->GetRenderWidgetHost())
+ if (!is_in_key_event_handler_ && host_view_->GetRenderWidgetHost()) {
+ // Workaround http://crbug.com/45478 by sending fake key down/up events.
+ SendFakeCompositionKeyEvent(WebKit::WebInputEvent::RawKeyDown);
host_view_->GetRenderWidgetHost()->ImeConfirmComposition(text);
+ SendFakeCompositionKeyEvent(WebKit::WebInputEvent::KeyUp);
+ }
}
void GtkIMContextWrapper::HandlePreeditStart() {
@@ -490,9 +496,12 @@ void GtkIMContextWrapper::HandlePreeditChanged(const gchar* text,
// Otherwise, we need send it here if it's been changed.
if (!is_in_key_event_handler_ && is_composing_text_ &&
host_view_->GetRenderWidgetHost()) {
+ // Workaround http://crbug.com/45478 by sending fake key down/up events.
+ SendFakeCompositionKeyEvent(WebKit::WebInputEvent::RawKeyDown);
host_view_->GetRenderWidgetHost()->ImeSetComposition(
preedit_text_, preedit_underlines_, preedit_selection_start_,
preedit_selection_end_);
+ SendFakeCompositionKeyEvent(WebKit::WebInputEvent::KeyUp);
}
}
@@ -529,6 +538,15 @@ void GtkIMContextWrapper::HandleHostViewUnrealize() {
gtk_im_context_set_client_window(context_simple_, NULL);
}
+void GtkIMContextWrapper::SendFakeCompositionKeyEvent(
+ WebKit::WebInputEvent::Type type) {
+ NativeWebKeyboardEvent fake_event;
+ fake_event.windowsKeyCode = kCompositionEventKeyCode;
+ fake_event.skip_in_browser = true;
+ fake_event.type = type;
+ host_view_->ForwardKeyboardEvent(fake_event);
+}
+
void GtkIMContextWrapper::HandleCommitThunk(
GtkIMContext* context, gchar* text, GtkIMContextWrapper* self) {
self->HandleCommit(UTF8ToUTF16(text));
diff --git a/chrome/browser/renderer_host/gtk_im_context_wrapper.h b/chrome/browser/renderer_host/gtk_im_context_wrapper.h
index 1538e26..94d6bfa 100644
--- a/chrome/browser/renderer_host/gtk_im_context_wrapper.h
+++ b/chrome/browser/renderer_host/gtk_im_context_wrapper.h
@@ -14,6 +14,7 @@
#include "base/gtest_prod_util.h"
#include "base/string16.h"
#include "third_party/WebKit/WebKit/chromium/public/WebCompositionUnderline.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h"
#include "third_party/WebKit/WebKit/chromium/public/WebTextInputType.h"
namespace gfx {
@@ -100,6 +101,10 @@ class GtkIMContextWrapper {
// client window.
void HandleHostViewUnrealize();
+ // Sends a fake composition key event with specified event type. A composition
+ // key event is a key event with special key code 229.
+ void SendFakeCompositionKeyEvent(WebKit::WebInputEvent::Type type);
+
// Signal handlers of GtkIMContext object.
static void HandleCommitThunk(GtkIMContext* context, gchar* text,
GtkIMContextWrapper* self);
diff --git a/chrome/browser/renderer_host/gtk_key_bindings_handler_unittest.cc b/chrome/browser/renderer_host/gtk_key_bindings_handler_unittest.cc
index 1ac020c..bf62fe7 100644
--- a/chrome/browser/renderer_host/gtk_key_bindings_handler_unittest.cc
+++ b/chrome/browser/renderer_host/gtk_key_bindings_handler_unittest.cc
@@ -10,6 +10,7 @@
#include "base/basictypes.h"
#include "base/file_util.h"
+#include "base/logging.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "chrome/common/chrome_paths.h"
@@ -30,6 +31,7 @@ class GtkKeyBindingsHandlerTest : public testing::Test {
FilePath gtkrc;
PathService::Get(chrome::DIR_TEST_DATA, &gtkrc);
gtkrc = gtkrc.AppendASCII("gtk_key_bindings_test_gtkrc");
+
gtk_rc_parse(gtkrc.value().c_str());
GtkWidget* fixed = gtk_fixed_new();
@@ -65,6 +67,7 @@ class GtkKeyBindingsHandlerTest : public testing::Test {
g_free(keys);
return NativeWebKeyboardEvent(&event);
}
+ LOG(ERROR) << "Failed to create key event for keyval:" << keyval;
return NativeWebKeyboardEvent();
}
@@ -85,8 +88,7 @@ class GtkKeyBindingsHandlerTest : public testing::Test {
GtkKeyBindingsHandler* handler_;
};
-// Does not work in a chroot. See bug 60363.
-TEST_F(GtkKeyBindingsHandlerTest, FLAKY_MoveCursor) {
+TEST_F(GtkKeyBindingsHandlerTest, MoveCursor) {
static const EditCommand kEditCommands[] = {
// "move-cursor" (logical-positions, -2, 0)
{ "MoveBackward", "" },
@@ -128,8 +130,7 @@ TEST_F(GtkKeyBindingsHandlerTest, FLAKY_MoveCursor) {
kEditCommands, arraysize(kEditCommands));
}
-// Does not work in a chroot. See bug 60363.
-TEST_F(GtkKeyBindingsHandlerTest, FLAKY_DeleteFromCursor) {
+TEST_F(GtkKeyBindingsHandlerTest, DeleteFromCursor) {
static const EditCommand kEditCommands[] = {
// "delete-from-cursor" (chars, -2)
{ "DeleteBackward", "" },
@@ -173,8 +174,7 @@ TEST_F(GtkKeyBindingsHandlerTest, FLAKY_DeleteFromCursor) {
kEditCommands, arraysize(kEditCommands));
}
-// Does not work in a chroot. See bug 60363.
-TEST_F(GtkKeyBindingsHandlerTest, FLAKY_OtherActions) {
+TEST_F(GtkKeyBindingsHandlerTest, OtherActions) {
static const EditCommand kBackspace[] = {
{ "DeleteBackward", "" }
};
diff --git a/chrome/browser/renderer_host/mock_render_process_host.cc b/chrome/browser/renderer_host/mock_render_process_host.cc
index a2ccfa0..1f1a2b3 100644
--- a/chrome/browser/renderer_host/mock_render_process_host.cc
+++ b/chrome/browser/renderer_host/mock_render_process_host.cc
@@ -46,7 +46,7 @@ bool MockRenderProcessHost::WaitForUpdateMsg(int render_widget_id,
return false;
}
-void MockRenderProcessHost::ReceivedBadMessage(uint32 msg_type) {
+void MockRenderProcessHost::ReceivedBadMessage() {
++bad_msg_count_;
}
@@ -117,7 +117,8 @@ TransportDIB* MockRenderProcessHost::GetTransportDIB(TransportDIB::Id dib_id) {
return transport_dib_;
}
-void MockRenderProcessHost::OnMessageReceived(const IPC::Message& msg) {
+bool MockRenderProcessHost::OnMessageReceived(const IPC::Message& msg) {
+ return false;
}
void MockRenderProcessHost::OnChannelConnected(int32 peer_pid) {
diff --git a/chrome/browser/renderer_host/mock_render_process_host.h b/chrome/browser/renderer_host/mock_render_process_host.h
index 232725b..6309685 100644
--- a/chrome/browser/renderer_host/mock_render_process_host.h
+++ b/chrome/browser/renderer_host/mock_render_process_host.h
@@ -40,7 +40,7 @@ class MockRenderProcessHost : public RenderProcessHost {
virtual bool WaitForUpdateMsg(int render_widget_id,
const base::TimeDelta& max_delay,
IPC::Message* msg);
- virtual void ReceivedBadMessage(uint32 msg_type);
+ virtual void ReceivedBadMessage();
virtual void WidgetRestored();
virtual void WidgetHidden();
virtual void ViewCreated();
@@ -59,7 +59,7 @@ class MockRenderProcessHost : public RenderProcessHost {
virtual bool Send(IPC::Message* msg);
// IPC::Channel::Listener via RenderProcessHost.
- virtual void OnMessageReceived(const IPC::Message& msg);
+ virtual bool OnMessageReceived(const IPC::Message& msg);
virtual void OnChannelConnected(int32 peer_pid);
// Attaches the factory object so we can remove this object in its destructor
diff --git a/chrome/browser/renderer_host/offline_resource_handler.cc b/chrome/browser/renderer_host/offline_resource_handler.cc
index ba94bee..362f411 100644
--- a/chrome/browser/renderer_host/offline_resource_handler.cc
+++ b/chrome/browser/renderer_host/offline_resource_handler.cc
@@ -23,7 +23,7 @@ OfflineResourceHandler::OfflineResourceHandler(
int host_id,
int route_id,
ResourceDispatcherHost* rdh,
- URLRequest* request)
+ net::URLRequest* request)
: next_handler_(handler),
process_host_id_(host_id),
render_view_id_(route_id),
diff --git a/chrome/browser/renderer_host/pepper_file_message_filter.cc b/chrome/browser/renderer_host/pepper_file_message_filter.cc
index cbd09af..8c30300 100644
--- a/chrome/browser/renderer_host/pepper_file_message_filter.cc
+++ b/chrome/browser/renderer_host/pepper_file_message_filter.cc
@@ -8,13 +8,12 @@
#include "base/file_util.h"
#include "base/file_path.h"
#include "base/process_util.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/browser_render_process_host.h"
#include "chrome/common/child_process_host.h"
#include "chrome/common/chrome_switches.h"
-#include "chrome/common/render_messages.h"
+#include "chrome/common/pepper_file_messages.h"
#include "ipc/ipc_platform_file.h"
#if defined(OS_POSIX)
@@ -22,86 +21,36 @@
#endif
PepperFileMessageFilter::PepperFileMessageFilter(
- int child_id, Profile* profile)
- : handle_(base::kNullProcessHandle),
- channel_(NULL) {
+ int child_id, Profile* profile) {
pepper_path_ = profile->GetPath().Append(FILE_PATH_LITERAL("Pepper Data"));
}
PepperFileMessageFilter::~PepperFileMessageFilter() {
// This function should be called on the IO thread.
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- if (handle_)
- base::CloseProcessHandle(handle_);
-}
-
-// Called on the IPC thread:
-void PepperFileMessageFilter::OnFilterAdded(IPC::Channel* channel) {
- channel_ = channel;
}
-// Called on the IPC thread:
-void PepperFileMessageFilter::OnChannelConnected(int32 peer_pid) {
- DCHECK(!handle_) << " " << handle_;
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- if (!base::OpenProcessHandle(peer_pid, &handle_)) {
- NOTREACHED();
- }
-}
-
-void PepperFileMessageFilter::OnChannelError() {
-}
-
-// Called on the IPC thread:
-void PepperFileMessageFilter::OnChannelClosing() {
- channel_ = NULL;
-}
-
-// Called on the IPC thread:
-bool PepperFileMessageFilter::OnMessageReceived(const IPC::Message& msg) {
- switch (msg.type()) {
- case ViewHostMsg_PepperOpenFile::ID:
- case ViewHostMsg_PepperRenameFile::ID:
- case ViewHostMsg_PepperDeleteFileOrDir::ID:
- case ViewHostMsg_PepperCreateDir::ID:
- case ViewHostMsg_PepperQueryFile::ID:
- case ViewHostMsg_PepperGetDirContents::ID:
- break;
- default:
- return false;
- }
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(
- this, &PepperFileMessageFilter::OnMessageReceivedFileThread, msg));
-
- return true;
-}
-
-void PepperFileMessageFilter::OnMessageReceivedFileThread(
- const IPC::Message& msg) {
- bool msg_is_ok = true;
- IPC_BEGIN_MESSAGE_MAP_EX(PepperFileMessageFilter, msg, msg_is_ok)
- IPC_MESSAGE_HANDLER(ViewHostMsg_PepperOpenFile, OnPepperOpenFile)
- IPC_MESSAGE_HANDLER(ViewHostMsg_PepperRenameFile, OnPepperRenameFile)
- IPC_MESSAGE_HANDLER(ViewHostMsg_PepperDeleteFileOrDir,
- OnPepperDeleteFileOrDir)
- IPC_MESSAGE_HANDLER(ViewHostMsg_PepperCreateDir, OnPepperCreateDir)
- IPC_MESSAGE_HANDLER(ViewHostMsg_PepperQueryFile, OnPepperQueryFile)
- IPC_MESSAGE_HANDLER(ViewHostMsg_PepperGetDirContents,
- OnPepperGetDirContents)
- IPC_MESSAGE_UNHANDLED_ERROR()
+void PepperFileMessageFilter::OverrideThreadForMessage(
+ const IPC::Message& message,
+ BrowserThread::ID* thread) {
+ if (IPC_MESSAGE_CLASS(message) == PepperFileMsgStart)
+ *thread = BrowserThread::FILE;
+}
+
+bool PepperFileMessageFilter::OnMessageReceived(
+ const IPC::Message& message,
+ bool* message_was_ok) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(PepperFileMessageFilter, message, *message_was_ok)
+ IPC_MESSAGE_HANDLER(PepperFileMsg_OpenFile, OnPepperOpenFile)
+ IPC_MESSAGE_HANDLER(PepperFileMsg_RenameFile, OnPepperRenameFile)
+ IPC_MESSAGE_HANDLER(PepperFileMsg_DeleteFileOrDir, OnPepperDeleteFileOrDir)
+ IPC_MESSAGE_HANDLER(PepperFileMsg_CreateDir, OnPepperCreateDir)
+ IPC_MESSAGE_HANDLER(PepperFileMsg_QueryFile, OnPepperQueryFile)
+ IPC_MESSAGE_HANDLER(PepperFileMsg_GetDirContents, OnPepperGetDirContents)
+ IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP_EX()
-
- if (!msg_is_ok) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableFunction(
- &BrowserRenderProcessHost::BadMessageTerminateProcess,
- msg.type(), handle_));
- }
+ return handled;
}
void PepperFileMessageFilter::OnDestruct() const {
@@ -109,24 +58,6 @@ void PepperFileMessageFilter::OnDestruct() const {
}
// Called on the FILE thread:
-void PepperFileMessageFilter::Send(IPC::Message* message) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(
- this, &PepperFileMessageFilter::SendFromIOThread, message));
-}
-
-// Called on the IPC thread:
-bool PepperFileMessageFilter::SendFromIOThread(IPC::Message* message) {
- if (!channel_) {
- delete message;
- return false;
- }
-
- return channel_->Send(message);
-}
-
-// Called on the FILE thread:
void PepperFileMessageFilter::OnPepperOpenFile(
const FilePath& path,
int flags,
@@ -160,7 +91,7 @@ void PepperFileMessageFilter::OnPepperOpenFile(
#if defined(OS_WIN)
// Duplicate the file handle so that the renderer process can access the file.
if (!DuplicateHandle(GetCurrentProcess(), file_handle,
- handle_, file, 0, false,
+ peer_handle(), file, 0, false,
DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
// file_handle is closed whether or not DuplicateHandle succeeds.
*error = base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
@@ -233,7 +164,7 @@ void PepperFileMessageFilter::OnPepperQueryFile(
void PepperFileMessageFilter::OnPepperGetDirContents(
const FilePath& path,
- PepperDirContents* contents,
+ webkit::ppapi::DirContents* contents,
base::PlatformFileError* error) {
FilePath full_path = MakePepperPath(path);
if (full_path.empty()) {
@@ -253,7 +184,7 @@ void PepperFileMessageFilter::OnPepperGetDirContents(
while (!enumerator.Next().empty()) {
file_util::FileEnumerator::FindInfo info;
enumerator.GetFindInfo(&info);
- PepperDirEntry entry = {
+ webkit::ppapi::DirEntry entry = {
file_util::FileEnumerator::GetFilename(info),
file_util::FileEnumerator::IsDirectory(info)
};
diff --git a/chrome/browser/renderer_host/pepper_file_message_filter.h b/chrome/browser/renderer_host/pepper_file_message_filter.h
index 003d258..fbcd5e5 100644
--- a/chrome/browser/renderer_host/pepper_file_message_filter.h
+++ b/chrome/browser/renderer_host/pepper_file_message_filter.h
@@ -14,40 +14,28 @@
#include "base/ref_counted.h"
#include "base/task.h"
#include "build/build_config.h"
-#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
-#include "ipc/ipc_channel_proxy.h"
+#include "chrome/browser/browser_message_filter.h"
#include "ipc/ipc_platform_file.h"
-#include "webkit/glue/plugins/pepper_dir_contents.h"
+#include "webkit/plugins/ppapi/dir_contents.h"
class Profile;
// A message filter for Pepper-specific File I/O messages.
-//
-// NOTE: Contrary to most message filters, this one handles the messages (On*
-// functions) on the FILE thread instead of the IO thread: OnMessageReceived
-// forwards the mesage to the FILE thread, where it's handled by
-// OnMessageReceivedFileThread.
-class PepperFileMessageFilter : public IPC::ChannelProxy::MessageFilter {
+class PepperFileMessageFilter : public BrowserMessageFilter {
public:
PepperFileMessageFilter(int child_id, Profile* profile);
- // IPC::ChannelProxy::MessageFilter methods:
- virtual void OnFilterAdded(IPC::Channel* channel);
- virtual void OnChannelConnected(int32 peer_pid);
- virtual void OnChannelError();
- virtual void OnChannelClosing();
- virtual bool OnMessageReceived(const IPC::Message& message);
+ // BrowserMessageFilter methods:
+ virtual void OverrideThreadForMessage(const IPC::Message& message,
+ BrowserThread::ID* thread);
+ virtual bool OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok);
virtual void OnDestruct() const;
- // Called from the FILE thread.
- void Send(IPC::Message* message);
-
private:
friend class BrowserThread;
friend class DeleteTask<PepperFileMessageFilter>;
virtual ~PepperFileMessageFilter();
- void OnMessageReceivedFileThread(const IPC::Message& message);
- bool SendFromIOThread(IPC::Message* message);
// Called on the FILE thread:
void OnPepperOpenFile(const FilePath& path,
@@ -66,14 +54,11 @@ class PepperFileMessageFilter : public IPC::ChannelProxy::MessageFilter {
base::PlatformFileInfo* info,
base::PlatformFileError* error);
void OnPepperGetDirContents(const FilePath& path,
- PepperDirContents* contents,
+ webkit::ppapi::DirContents* contents,
base::PlatformFileError* error);
FilePath MakePepperPath(const FilePath& base_path);
- // The process handle for the peer.
- base::ProcessHandle handle_;
-
// The channel associated with the renderer connection. This pointer is not
// owned by this class.
IPC::Channel* channel_;
diff --git a/chrome/browser/renderer_host/redirect_to_file_resource_handler.h b/chrome/browser/renderer_host/redirect_to_file_resource_handler.h
index 4929711..5e8624a 100644
--- a/chrome/browser/renderer_host/redirect_to_file_resource_handler.h
+++ b/chrome/browser/renderer_host/redirect_to_file_resource_handler.h
@@ -35,18 +35,18 @@ class RedirectToFileResourceHandler : public ResourceHandler {
ResourceDispatcherHost* resource_dispatcher_host);
// ResourceHandler implementation:
- bool OnUploadProgress(int request_id, uint64 position, uint64 size);
- bool OnRequestRedirected(int request_id, const GURL& new_url,
- ResourceResponse* response, bool* defer);
- bool OnResponseStarted(int request_id, ResourceResponse* response);
- bool OnWillStart(int request_id, const GURL& url, bool* defer);
- bool OnWillRead(int request_id, net::IOBuffer** buf, int* buf_size,
- int min_size);
- bool OnReadCompleted(int request_id, int* bytes_read);
- bool OnResponseCompleted(int request_id,
- const URLRequestStatus& status,
- const std::string& security_info);
- void OnRequestClosed();
+ virtual bool OnUploadProgress(int request_id, uint64 position, uint64 size);
+ virtual bool OnRequestRedirected(int request_id, const GURL& new_url,
+ ResourceResponse* response, bool* defer);
+ virtual bool OnResponseStarted(int request_id, ResourceResponse* response);
+ virtual bool OnWillStart(int request_id, const GURL& url, bool* defer);
+ virtual bool OnWillRead(int request_id, net::IOBuffer** buf, int* buf_size,
+ int min_size);
+ virtual bool OnReadCompleted(int request_id, int* bytes_read);
+ virtual bool OnResponseCompleted(int request_id,
+ const URLRequestStatus& status,
+ const std::string& security_info);
+ virtual void OnRequestClosed();
private:
virtual ~RedirectToFileResourceHandler();
diff --git a/chrome/browser/renderer_host/render_message_filter.cc b/chrome/browser/renderer_host/render_message_filter.cc
new file mode 100644
index 0000000..b5adbaa
--- /dev/null
+++ b/chrome/browser/renderer_host/render_message_filter.cc
@@ -0,0 +1,1616 @@
+// 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.
+
+#include "chrome/browser/renderer_host/render_message_filter.h"
+
+#include <map>
+
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/metrics/histogram.h"
+#include "base/process_util.h"
+#include "base/shared_memory.h"
+#include "base/sys_string_conversions.h"
+#include "base/thread.h"
+#include "base/utf_string_conversions.h"
+#include "base/worker_pool.h"
+#include "chrome/browser/automation/automation_resource_message_filter.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/child_process_security_policy.h"
+#include "chrome/browser/chrome_plugin_browsing_context.h"
+#include "chrome/browser/clipboard_dispatcher.h"
+#include "chrome/browser/download/download_types.h"
+#include "chrome/browser/extensions/extension_message_service.h"
+#include "chrome/browser/gpu_process_host.h"
+#include "chrome/browser/host_zoom_map.h"
+#include "chrome/browser/metrics/histogram_synchronizer.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/nacl_host/nacl_process_host.h"
+#include "chrome/browser/net/chrome_url_request_context.h"
+#include "chrome/browser/net/predictor_api.h"
+#include "chrome/browser/notifications/desktop_notification_service.h"
+#include "chrome/browser/notifications/notifications_prefs_cache.h"
+#include "chrome/browser/platform_util.h"
+#include "chrome/browser/plugin_process_host.h"
+#include "chrome/browser/plugin_service.h"
+#include "chrome/browser/ppapi_plugin_process_host.h"
+#include "chrome/browser/printing/print_job_manager.h"
+#include "chrome/browser/printing/printer_query.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/browser_render_process_host.h"
+#include "chrome/browser/renderer_host/render_view_host_delegate.h"
+#include "chrome/browser/renderer_host/render_view_host_notification_task.h"
+#include "chrome/browser/renderer_host/render_widget_helper.h"
+#include "chrome/browser/spellchecker_platform_engine.h"
+#include "chrome/browser/task_manager/task_manager.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/extension_file_util.h"
+#include "chrome/common/extensions/extension_message_bundle.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
+#include "chrome/common/url_constants.h"
+#include "ipc/ipc_channel_handle.h"
+#include "net/base/cookie_monster.h"
+#include "net/base/io_buffer.h"
+#include "net/base/keygen_handler.h"
+#include "net/base/mime_util.h"
+#include "net/base/net_errors.h"
+#include "net/disk_cache/disk_cache.h"
+#include "net/http/http_cache.h"
+#include "net/http/http_network_layer.h"
+#include "net/url_request/url_request_context.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebNotificationPresenter.h"
+#include "webkit/glue/context_menu.h"
+#include "webkit/glue/webcookie.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/plugins/npapi/plugin_group.h"
+#include "webkit/plugins/npapi/plugin_list.h"
+#include "webkit/plugins/npapi/webplugin.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/plugin_selection_policy.h"
+#endif
+#if defined(OS_MACOSX)
+#include "chrome/browser/ui/cocoa/task_helpers.h"
+#include "chrome/common/font_descriptor_mac.h"
+#include "chrome/common/font_loader_mac.h"
+#endif
+#if defined(OS_POSIX)
+#include "base/file_descriptor_posix.h"
+#endif
+#if defined(OS_WIN)
+#include "chrome/common/child_process_host.h"
+#endif
+#if defined(USE_TCMALLOC)
+#include "chrome/browser/browser_about_handler.h"
+#endif
+
+using net::CookieStore;
+using WebKit::WebCache;
+
+namespace {
+
+const int kPluginsRefreshThresholdInSeconds = 3;
+
+// Context menus are somewhat complicated. We need to intercept them here on
+// the I/O thread to add any spelling suggestions to them. After that's done,
+// we need to forward the modified message to the UI thread and the normal
+// message forwarding isn't set up for sending modified messages.
+//
+// Therefore, this class dispatches the IPC message to the RenderProcessHost
+// with the given ID (if possible) to emulate the normal dispatch.
+class ContextMenuMessageDispatcher : public Task {
+ public:
+ ContextMenuMessageDispatcher(
+ int render_process_id,
+ const ViewHostMsg_ContextMenu& context_menu_message)
+ : render_process_id_(render_process_id),
+ context_menu_message_(context_menu_message) {
+ }
+
+ void Run() {
+ RenderProcessHost* host =
+ RenderProcessHost::FromID(render_process_id_);
+ if (host)
+ host->OnMessageReceived(context_menu_message_);
+ }
+
+ private:
+ int render_process_id_;
+ const ViewHostMsg_ContextMenu context_menu_message_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContextMenuMessageDispatcher);
+};
+
+// Completes a clipboard write initiated by the renderer. The write must be
+// performed on the UI thread because the clipboard service from the IO thread
+// cannot create windows so it cannot be the "owner" of the clipboard's
+// contents.
+class WriteClipboardTask : public Task {
+ public:
+ explicit WriteClipboardTask(Clipboard::ObjectMap* objects)
+ : objects_(objects) {}
+ ~WriteClipboardTask() {}
+
+ void Run() {
+ g_browser_process->clipboard()->WriteObjects(*objects_.get());
+ }
+
+ private:
+ scoped_ptr<Clipboard::ObjectMap> objects_;
+};
+
+void RenderParamsFromPrintSettings(const printing::PrintSettings& settings,
+ ViewMsg_Print_Params* params) {
+ DCHECK(params);
+ params->page_size = settings.page_setup_device_units().physical_size();
+ params->printable_size.SetSize(
+ settings.page_setup_device_units().content_area().width(),
+ settings.page_setup_device_units().content_area().height());
+ params->margin_top = settings.page_setup_device_units().content_area().x();
+ params->margin_left = settings.page_setup_device_units().content_area().y();
+ params->dpi = settings.dpi();
+ // Currently hardcoded at 1.25. See PrintSettings' constructor.
+ params->min_shrink = settings.min_shrink;
+ // Currently hardcoded at 2.0. See PrintSettings' constructor.
+ params->max_shrink = settings.max_shrink;
+ // Currently hardcoded at 72dpi. See PrintSettings' constructor.
+ params->desired_dpi = settings.desired_dpi;
+ // Always use an invalid cookie.
+ params->document_cookie = 0;
+ params->selection_only = settings.selection_only;
+}
+
+class ClearCacheCompletion : public net::CompletionCallback {
+ public:
+ ClearCacheCompletion(IPC::Message* reply_msg,
+ RenderMessageFilter* filter)
+ : reply_msg_(reply_msg),
+ filter_(filter) {
+ }
+
+ virtual void RunWithParams(const Tuple1<int>& params) {
+ ViewHostMsg_ClearCache::WriteReplyParams(reply_msg_, params.a);
+ filter_->Send(reply_msg_);
+ delete this;
+ }
+
+ private:
+ IPC::Message* reply_msg_;
+ scoped_refptr<RenderMessageFilter> filter_;
+};
+
+class OpenChannelToPluginCallback : public PluginProcessHost::Client {
+ public:
+ OpenChannelToPluginCallback(RenderMessageFilter* filter,
+ IPC::Message* reply_msg)
+ : filter_(filter),
+ reply_msg_(reply_msg) {
+ }
+
+ virtual int ID() {
+ return filter_->render_process_id();
+ }
+
+ virtual bool OffTheRecord() {
+ return filter_->off_the_record();
+ }
+
+ virtual void SetPluginInfo(const webkit::npapi::WebPluginInfo& info) {
+ info_ = info;
+ }
+
+ virtual void OnChannelOpened(const IPC::ChannelHandle& handle) {
+ WriteReply(handle);
+ }
+
+ virtual void OnError() {
+ WriteReply(IPC::ChannelHandle());
+ }
+
+ private:
+ void WriteReply(const IPC::ChannelHandle& handle) {
+ ViewHostMsg_OpenChannelToPlugin::WriteReplyParams(reply_msg_,
+ handle,
+ info_);
+ filter_->Send(reply_msg_);
+ delete this;
+ }
+
+ scoped_refptr<RenderMessageFilter> filter_;
+ IPC::Message* reply_msg_;
+ webkit::npapi::WebPluginInfo info_;
+};
+
+} // namespace
+
+RenderMessageFilter::RenderMessageFilter(
+ int render_process_id,
+ PluginService* plugin_service,
+ Profile* profile,
+ RenderWidgetHelper* render_widget_helper)
+ : resource_dispatcher_host_(g_browser_process->resource_dispatcher_host()),
+ plugin_service_(plugin_service),
+ print_job_manager_(g_browser_process->print_job_manager()),
+ profile_(profile),
+ content_settings_(profile->GetHostContentSettingsMap()),
+ ALLOW_THIS_IN_INITIALIZER_LIST(resolve_proxy_msg_helper_(this, NULL)),
+ extensions_request_context_(profile->GetRequestContextForExtensions()),
+ render_widget_helper_(render_widget_helper),
+ notification_prefs_(
+ profile->GetDesktopNotificationService()->prefs_cache()),
+ host_zoom_map_(profile->GetHostZoomMap()),
+ off_the_record_(profile->IsOffTheRecord()),
+ webkit_context_(profile->GetWebKitContext()),
+ render_process_id_(render_process_id) {
+ request_context_ = profile_->GetRequestContext();
+ DCHECK(request_context_);
+
+ render_widget_helper_->Init(render_process_id_, resource_dispatcher_host_);
+#if defined(OS_CHROMEOS)
+ cloud_print_enabled_ = true;
+#else
+ cloud_print_enabled_ = CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableCloudPrint);
+#endif
+}
+
+RenderMessageFilter::~RenderMessageFilter() {
+ // This function should be called on the IO thread.
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+}
+
+// Called on the IPC thread:
+bool RenderMessageFilter::OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(RenderMessageFilter, message, *message_was_ok)
+ // On Linux we need to dispatch these messages to the UI2 thread
+ // because we cannot make X calls from the IO thread. Mac
+ // doesn't have windowed plug-ins so we handle the messages in
+ // the UI thread. On Windows, we intercept the messages and
+ // handle them directly.
+#if !defined(OS_MACOSX)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetScreenInfo, OnGetScreenInfo)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetWindowRect, OnGetWindowRect)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetRootWindowRect,
+ OnGetRootWindowRect)
+#endif
+
+ IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWindow, OnMsgCreateWindow)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWidget, OnMsgCreateWidget)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_CreateFullscreenWidget,
+ OnMsgCreateFullscreenWidget)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_SetCookie, OnSetCookie)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetCookies, OnGetCookies)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetRawCookies, OnGetRawCookies)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DeleteCookie, OnDeleteCookie)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_CookiesEnabled,
+ OnCookiesEnabled)
+#if defined(OS_MACOSX)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_LoadFont, OnLoadFont)
+#endif
+#if defined(OS_WIN) // This hack is Windows-specific.
+ IPC_MESSAGE_HANDLER(ViewHostMsg_PreCacheFont, OnPreCacheFont)
+#endif
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetPlugins, OnGetPlugins)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetPluginInfo, OnGetPluginInfo)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DownloadUrl, OnDownloadUrl)
+ IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_ContextMenu,
+ OnReceiveContextMenuMsg(message))
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_OpenChannelToPlugin,
+ OnOpenChannelToPlugin)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_OpenChannelToPepperPlugin,
+ OnOpenChannelToPepperPlugin)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_LaunchNaCl, OnLaunchNaCl)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_SpellChecker_PlatformCheckSpelling,
+ OnPlatformCheckSpelling)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_SpellChecker_PlatformFillSuggestionList,
+ OnPlatformFillSuggestionList)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetDocumentTag,
+ OnGetDocumentTag)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DocumentWithTagClosed,
+ OnDocumentWithTagClosed)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_ShowSpellingPanel, OnShowSpellingPanel)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateSpellingPanelWithMisspelledWord,
+ OnUpdateSpellingPanelWithMisspelledWord)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DnsPrefetch, OnDnsPrefetch)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_RendererHistograms, OnRendererHistograms)
+ IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_UpdateRect,
+ render_widget_helper_->DidReceiveUpdateMsg(message))
+ IPC_MESSAGE_HANDLER(ViewHostMsg_ClipboardWriteObjectsAsync,
+ OnClipboardWriteObjectsAsync)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_ClipboardWriteObjectsSync,
+ OnClipboardWriteObjectsSync)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ClipboardIsFormatAvailable,
+ OnClipboardIsFormatAvailable)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ClipboardReadText,
+ OnClipboardReadText)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ClipboardReadAsciiText,
+ OnClipboardReadAsciiText)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ClipboardReadHTML,
+ OnClipboardReadHTML)
+#if defined(OS_MACOSX)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_ClipboardFindPboardWriteStringAsync,
+ OnClipboardFindPboardWriteString)
+#endif
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ClipboardReadAvailableTypes,
+ OnClipboardReadAvailableTypes)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ClipboardReadData,
+ OnClipboardReadData)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ClipboardReadFilenames,
+ OnClipboardReadFilenames)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_CheckNotificationPermission,
+ OnCheckNotificationPermission)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_RevealFolderInOS, OnRevealFolderInOS)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_GetCPBrowsingContext,
+ OnGetCPBrowsingContext)
+#if defined(OS_WIN)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DuplicateSection, OnDuplicateSection)
+#endif
+#if defined(OS_POSIX)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_AllocateSharedMemoryBuffer,
+ OnAllocateSharedMemoryBuffer)
+#endif
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_AllocateTempFileForPrinting,
+ OnAllocateTempFileForPrinting)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_TempFileForPrintingWritten,
+ OnTempFileForPrintingWritten)
+#endif
+ IPC_MESSAGE_HANDLER(ViewHostMsg_ResourceTypeStats, OnResourceTypeStats)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_V8HeapStats, OnV8HeapStats)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DidZoomURL, OnDidZoomURL)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ResolveProxy, OnResolveProxy)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetDefaultPrintSettings,
+ OnGetDefaultPrintSettings)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ScriptedPrint, OnScriptedPrint)
+#if defined(OS_MACOSX)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_AllocTransportDIB, OnAllocTransportDIB)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_FreeTransportDIB, OnFreeTransportDIB)
+#endif
+ IPC_MESSAGE_HANDLER(ViewHostMsg_OpenChannelToExtension,
+ OnOpenChannelToExtension)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_OpenChannelToTab, OnOpenChannelToTab)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_CloseCurrentConnections,
+ OnCloseCurrentConnections)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_SetCacheMode, OnSetCacheMode)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ClearCache, OnClearCache)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DidGenerateCacheableMetadata,
+ OnCacheableMetadataAvailable)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_EnableSpdy, OnEnableSpdy)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_Keygen, OnKeygen)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetExtensionMessageBundle,
+ OnGetExtensionMessageBundle)
+#if defined(USE_TCMALLOC)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_RendererTcmalloc, OnRendererTcmalloc)
+#endif
+ IPC_MESSAGE_HANDLER(ViewHostMsg_EstablishGpuChannel, OnEstablishGpuChannel)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_SynchronizeGpu,
+ OnSynchronizeGpu)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_AsyncOpenFile, OnAsyncOpenFile)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP_EX()
+
+ return handled;
+}
+
+void RenderMessageFilter::OnRevealFolderInOS(const FilePath& path) {
+#if defined(OS_MACOSX)
+ const BrowserThread::ID kThreadID = BrowserThread::UI;
+#else
+ const BrowserThread::ID kThreadID = BrowserThread::FILE;
+#endif
+ if (!BrowserThread::CurrentlyOn(kThreadID)) {
+ // Only honor the request if appropriate persmissions are granted.
+ if (ChildProcessSecurityPolicy::GetInstance()->CanReadFile(
+ render_process_id_, path)) {
+ BrowserThread::PostTask(
+ kThreadID, FROM_HERE,
+ NewRunnableMethod(
+ this, &RenderMessageFilter::OnRevealFolderInOS, path));
+ }
+ return;
+ }
+
+ DCHECK(BrowserThread::CurrentlyOn(kThreadID));
+ platform_util::OpenItem(path);
+}
+
+void RenderMessageFilter::OnDestruct() const {
+ BrowserThread::DeleteOnIOThread::Destruct(this);
+}
+
+void RenderMessageFilter::OnReceiveContextMenuMsg(const IPC::Message& msg) {
+ void* iter = NULL;
+ ContextMenuParams params;
+ if (!IPC::ParamTraits<ContextMenuParams>::Read(&msg, &iter, &params))
+ return;
+
+ // Create a new ViewHostMsg_ContextMenu message.
+ const ViewHostMsg_ContextMenu context_menu_message(msg.routing_id(), params);
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ new ContextMenuMessageDispatcher(
+ render_process_id_, context_menu_message));
+}
+
+void RenderMessageFilter::OnMsgCreateWindow(
+ const ViewHostMsg_CreateWindow_Params& params,
+ int* route_id, int64* cloned_session_storage_namespace_id) {
+ *cloned_session_storage_namespace_id =
+ webkit_context_->dom_storage_context()->CloneSessionStorage(
+ params.session_storage_namespace_id);
+ render_widget_helper_->CreateNewWindow(params.opener_id,
+ params.user_gesture,
+ params.window_container_type,
+ params.frame_name,
+ peer_handle(),
+ route_id);
+}
+
+void RenderMessageFilter::OnMsgCreateWidget(int opener_id,
+ WebKit::WebPopupType popup_type,
+ int* route_id) {
+ render_widget_helper_->CreateNewWidget(opener_id, popup_type, route_id);
+}
+
+void RenderMessageFilter::OnMsgCreateFullscreenWidget(
+ int opener_id, WebKit::WebPopupType popup_type, int* route_id) {
+ render_widget_helper_->CreateNewFullscreenWidget(
+ opener_id, popup_type, route_id);
+}
+
+void RenderMessageFilter::OnSetCookie(const IPC::Message& message,
+ const GURL& url,
+ const GURL& first_party_for_cookies,
+ const std::string& cookie) {
+ ChromeURLRequestContext* context = GetRequestContextForURL(url);
+
+ SetCookieCompletion* callback = new SetCookieCompletion(
+ render_process_id_, message.routing_id(), url, cookie, context);
+
+ // If this render view is associated with an automation channel, aka
+ // ChromeFrame then we need to set cookies in the external host.
+ if (!AutomationResourceMessageFilter::SetCookiesForUrl(url,
+ cookie,
+ callback)) {
+ int policy = net::OK;
+ if (context->cookie_policy()) {
+ policy = context->cookie_policy()->CanSetCookie(
+ url, first_party_for_cookies, cookie, callback);
+ if (policy == net::ERR_IO_PENDING)
+ return;
+ }
+ callback->Run(policy);
+ }
+}
+
+void RenderMessageFilter::OnGetCookies(const GURL& url,
+ const GURL& first_party_for_cookies,
+ IPC::Message* reply_msg) {
+ ChromeURLRequestContext* context = GetRequestContextForURL(url);
+
+ GetCookiesCompletion* callback = new GetCookiesCompletion(
+ render_process_id_, reply_msg->routing_id(), url, reply_msg, this,
+ context, false);
+
+ // If this render view is associated with an automation channel, aka
+ // ChromeFrame then we need to retrieve cookies from the external host.
+ if (!AutomationResourceMessageFilter::GetCookiesForUrl(url, callback)) {
+ int policy = net::OK;
+ if (context->cookie_policy()) {
+ policy = context->cookie_policy()->CanGetCookies(
+ url, first_party_for_cookies, callback);
+ if (policy == net::ERR_IO_PENDING) {
+ Send(new ViewMsg_SignalCookiePromptEvent());
+ return;
+ }
+ }
+ callback->Run(policy);
+ }
+}
+
+void RenderMessageFilter::OnGetRawCookies(
+ const GURL& url,
+ const GURL& first_party_for_cookies,
+ IPC::Message* reply_msg) {
+
+ ChromeURLRequestContext* context = GetRequestContextForURL(url);
+
+ // Only return raw cookies to trusted renderers or if this request is
+ // not targeted to an an external host like ChromeFrame.
+ // TODO(ananta) We need to support retreiving raw cookies from external
+ // hosts.
+ if (!ChildProcessSecurityPolicy::GetInstance()->CanReadRawCookies(
+ render_process_id_) || context->IsExternal()) {
+ ViewHostMsg_GetRawCookies::WriteReplyParams(
+ reply_msg,
+ std::vector<webkit_glue::WebCookie>());
+ Send(reply_msg);
+ return;
+ }
+
+ GetCookiesCompletion* callback = new GetCookiesCompletion(
+ render_process_id_, reply_msg->routing_id(), url, reply_msg, this,
+ context, true);
+
+ // We check policy here to avoid sending back cookies that would not normally
+ // be applied to outbound requests for the given URL. Since this cookie info
+ // is visible in the developer tools, it is helpful to make it match reality.
+ int policy = net::OK;
+ if (context->cookie_policy()) {
+ policy = context->cookie_policy()->CanGetCookies(
+ url, first_party_for_cookies, callback);
+ if (policy == net::ERR_IO_PENDING) {
+ Send(new ViewMsg_SignalCookiePromptEvent());
+ return;
+ }
+ }
+ callback->Run(policy);
+}
+
+void RenderMessageFilter::OnDeleteCookie(const GURL& url,
+ const std::string& cookie_name) {
+ URLRequestContext* context = GetRequestContextForURL(url);
+ context->cookie_store()->DeleteCookie(url, cookie_name);
+}
+
+void RenderMessageFilter::OnCookiesEnabled(
+ const GURL& url,
+ const GURL& first_party_for_cookies,
+ IPC::Message* reply_msg) {
+ URLRequestContext* context = GetRequestContextForURL(url);
+ CookiesEnabledCompletion* callback =
+ new CookiesEnabledCompletion(reply_msg, this);
+ int policy = net::OK;
+ // TODO(ananta): If this render view is associated with an automation channel,
+ // aka ChromeFrame then we need to retrieve cookie settings from the external
+ // host.
+ if (context->cookie_policy()) {
+ policy = context->cookie_policy()->CanGetCookies(
+ url, first_party_for_cookies, callback);
+ if (policy == net::ERR_IO_PENDING) {
+ Send(new ViewMsg_SignalCookiePromptEvent());
+ return; // CanGetCookies will call our callback in this case.
+ }
+ }
+ callback->Run(policy);
+}
+
+#if defined(OS_MACOSX)
+void RenderMessageFilter::OnLoadFont(const FontDescriptor& font,
+ uint32* handle_size,
+ base::SharedMemoryHandle* handle) {
+ base::SharedMemory font_data;
+ uint32 font_data_size = 0;
+ bool ok = FontLoader::LoadFontIntoBuffer(font.nsFont(), &font_data,
+ &font_data_size);
+ if (!ok || font_data_size == 0) {
+ LOG(ERROR) << "Couldn't load font data for " << font.font_name <<
+ " ok=" << ok << " font_data_size=" << font_data_size;
+ *handle_size = 0;
+ *handle = base::SharedMemory::NULLHandle();
+ return;
+ }
+
+ *handle_size = font_data_size;
+ font_data.GiveToProcess(base::GetCurrentProcessHandle(), handle);
+}
+#endif // OS_MACOSX
+
+#if defined(OS_WIN) // This hack is Windows-specific.
+void RenderMessageFilter::OnPreCacheFont(LOGFONT font) {
+ ChildProcessHost::PreCacheFont(font);
+}
+#endif // OS_WIN
+
+void RenderMessageFilter::OnGetPlugins(bool refresh,
+ IPC::Message* reply_msg) {
+ // Don't refresh if the specified threshold has not been passed. Note that
+ // this check is performed before off-loading to the file thread. The reason
+ // we do this is that some pages tend to request that the list of plugins be
+ // refreshed at an excessive rate. This instigates disk scanning, as the list
+ // is accumulated by doing multiple reads from disk. This effect is
+ // multiplied when we have several pages requesting this operation.
+ if (refresh) {
+ const base::TimeDelta threshold = base::TimeDelta::FromSeconds(
+ kPluginsRefreshThresholdInSeconds);
+ const base::TimeTicks now = base::TimeTicks::Now();
+ if (now - last_plugin_refresh_time_ < threshold)
+ refresh = false; // Ignore refresh request; threshold not exceeded yet.
+ else
+ last_plugin_refresh_time_ = now;
+ }
+
+ // Can't load plugins on IO thread, so go to the FILE thread.
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(
+ this, &RenderMessageFilter::OnGetPluginsOnFileThread, refresh,
+ reply_msg));
+}
+
+void RenderMessageFilter::OnGetPluginsOnFileThread(
+ bool refresh, IPC::Message* reply_msg) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ std::vector<webkit::npapi::WebPluginInfo> plugins;
+ webkit::npapi::PluginList::Singleton()->GetEnabledPlugins(refresh, &plugins);
+ ViewHostMsg_GetPlugins::WriteReplyParams(reply_msg, plugins);
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(this, &RenderMessageFilter::Send, reply_msg));
+}
+
+void RenderMessageFilter::OnGetPluginInfo(const GURL& url,
+ const GURL& policy_url,
+ const std::string& mime_type,
+ IPC::Message* reply_msg) {
+ // The PluginService::GetFirstAllowedPluginInfo may need to load the
+ // plugins. Don't do it on the IO thread.
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(
+ this, &RenderMessageFilter::OnGetPluginInfoOnFileThread,
+ url, policy_url, mime_type, reply_msg));
+}
+
+void RenderMessageFilter::OnGetPluginInfoOnFileThread(
+ const GURL& url,
+ const GURL& policy_url,
+ const std::string& mime_type,
+ IPC::Message* reply_msg) {
+ std::string actual_mime_type;
+ webkit::npapi::WebPluginInfo info;
+ bool found = plugin_service_->GetFirstAllowedPluginInfo(url,
+ mime_type,
+ &info,
+ &actual_mime_type);
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(
+ this, &RenderMessageFilter::OnGotPluginInfo,
+ found, info, actual_mime_type, policy_url, reply_msg));
+}
+
+void RenderMessageFilter::OnGotPluginInfo(
+ bool found,
+ const webkit::npapi::WebPluginInfo& info,
+ const std::string& actual_mime_type,
+ const GURL& policy_url,
+ IPC::Message* reply_msg) {
+ ContentSetting setting = CONTENT_SETTING_DEFAULT;
+ webkit::npapi::WebPluginInfo info_copy = info;
+ if (found) {
+ info_copy.enabled = info_copy.enabled &&
+ plugin_service_->PrivatePluginAllowedForURL(info_copy.path, policy_url);
+ std::string resource =
+ webkit::npapi::PluginList::Singleton()->GetPluginGroupIdentifier(
+ info_copy);
+ setting = content_settings_->GetContentSetting(
+ policy_url,
+ CONTENT_SETTINGS_TYPE_PLUGINS,
+ resource);
+ }
+
+ ViewHostMsg_GetPluginInfo::WriteReplyParams(
+ reply_msg, found, info_copy, setting, actual_mime_type);
+ Send(reply_msg);
+}
+
+void RenderMessageFilter::OnOpenChannelToPlugin(const GURL& url,
+ const std::string& mime_type,
+ IPC::Message* reply_msg) {
+ plugin_service_->OpenChannelToPlugin(
+ url,
+ mime_type,
+ new OpenChannelToPluginCallback(this, reply_msg));
+}
+
+void RenderMessageFilter::OnOpenChannelToPepperPlugin(
+ const FilePath& path,
+ IPC::Message* reply_msg) {
+ PpapiPluginProcessHost* host = new PpapiPluginProcessHost(this);
+ host->Init(path, reply_msg);
+ ppapi_plugin_hosts_.push_back(linked_ptr<PpapiPluginProcessHost>(host));
+}
+
+void RenderMessageFilter::OnLaunchNaCl(
+ const std::wstring& url, int channel_descriptor, IPC::Message* reply_msg) {
+ NaClProcessHost* host = new NaClProcessHost(resource_dispatcher_host_, url);
+ host->Launch(this, channel_descriptor, reply_msg);
+}
+
+void RenderMessageFilter::OnDownloadUrl(const IPC::Message& message,
+ const GURL& url,
+ const GURL& referrer) {
+ URLRequestContext* context = request_context_->GetURLRequestContext();
+
+ // Don't show "Save As" UI.
+ bool prompt_for_save_location = false;
+ resource_dispatcher_host_->BeginDownload(url,
+ referrer,
+ DownloadSaveInfo(),
+ prompt_for_save_location,
+ render_process_id_,
+ message.routing_id(),
+ context);
+}
+
+void RenderMessageFilter::OnClipboardWriteObjectsSync(
+ const Clipboard::ObjectMap& objects,
+ base::SharedMemoryHandle bitmap_handle) {
+ DCHECK(base::SharedMemory::IsHandleValid(bitmap_handle))
+ << "Bad bitmap handle";
+ // We cannot write directly from the IO thread, and cannot service the IPC
+ // on the UI thread. We'll copy the relevant data and get a handle to any
+ // shared memory so it doesn't go away when we resume the renderer, and post
+ // a task to perform the write on the UI thread.
+ Clipboard::ObjectMap* long_living_objects = new Clipboard::ObjectMap(objects);
+
+ // Splice the shared memory handle into the clipboard data.
+ Clipboard::ReplaceSharedMemHandle(long_living_objects, bitmap_handle,
+ peer_handle());
+
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ new WriteClipboardTask(long_living_objects));
+}
+
+void RenderMessageFilter::OnClipboardWriteObjectsAsync(
+ const Clipboard::ObjectMap& objects) {
+ // We cannot write directly from the IO thread, and cannot service the IPC
+ // on the UI thread. We'll copy the relevant data and post a task to preform
+ // the write on the UI thread.
+ Clipboard::ObjectMap* long_living_objects = new Clipboard::ObjectMap(objects);
+
+ // This async message doesn't support shared-memory based bitmaps; they must
+ // be removed otherwise we might dereference a rubbish pointer.
+ long_living_objects->erase(Clipboard::CBF_SMBITMAP);
+
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ new WriteClipboardTask(long_living_objects));
+}
+
+#if !defined(USE_X11)
+// On non-X11 platforms, clipboard actions can be performed on the IO thread.
+// On X11, since the clipboard is linked with GTK, we either have to do this
+// with GTK on the UI thread, or with Xlib on the BACKGROUND_X11 thread. In an
+// ideal world, we would do the latter. However, for now we're going to
+// terminate these calls on the UI thread. This risks deadlock in the case of
+// plugins, but it's better than crashing which is what doing on the IO thread
+// gives us.
+//
+// See resource_message_filter_gtk.cc for the Linux implementation of these
+// functions.
+
+void RenderMessageFilter::OnClipboardIsFormatAvailable(
+ Clipboard::FormatType format, Clipboard::Buffer buffer,
+ IPC::Message* reply) {
+ const bool result = GetClipboard()->IsFormatAvailable(format, buffer);
+ ViewHostMsg_ClipboardIsFormatAvailable::WriteReplyParams(reply, result);
+ Send(reply);
+}
+
+void RenderMessageFilter::OnClipboardReadText(Clipboard::Buffer buffer,
+ IPC::Message* reply) {
+ string16 result;
+ GetClipboard()->ReadText(buffer, &result);
+ ViewHostMsg_ClipboardReadText::WriteReplyParams(reply, result);
+ Send(reply);
+}
+
+void RenderMessageFilter::OnClipboardReadAsciiText(Clipboard::Buffer buffer,
+ IPC::Message* reply) {
+ std::string result;
+ GetClipboard()->ReadAsciiText(buffer, &result);
+ ViewHostMsg_ClipboardReadAsciiText::WriteReplyParams(reply, result);
+ Send(reply);
+}
+
+void RenderMessageFilter::OnClipboardReadHTML(Clipboard::Buffer buffer,
+ IPC::Message* reply) {
+ std::string src_url_str;
+ string16 markup;
+ GetClipboard()->ReadHTML(buffer, &markup, &src_url_str);
+ const GURL src_url = GURL(src_url_str);
+
+ ViewHostMsg_ClipboardReadHTML::WriteReplyParams(reply, markup, src_url);
+ Send(reply);
+}
+
+void RenderMessageFilter::OnClipboardReadAvailableTypes(
+ Clipboard::Buffer buffer, IPC::Message* reply) {
+ std::vector<string16> types;
+ bool contains_filenames = false;
+ bool result = ClipboardDispatcher::ReadAvailableTypes(
+ buffer, &types, &contains_filenames);
+ ViewHostMsg_ClipboardReadAvailableTypes::WriteReplyParams(
+ reply, result, types, contains_filenames);
+ Send(reply);
+}
+
+void RenderMessageFilter::OnClipboardReadData(
+ Clipboard::Buffer buffer, const string16& type, IPC::Message* reply) {
+ string16 data;
+ string16 metadata;
+ bool result = ClipboardDispatcher::ReadData(buffer, type, &data, &metadata);
+ ViewHostMsg_ClipboardReadData::WriteReplyParams(
+ reply, result, data, metadata);
+ Send(reply);
+}
+
+void RenderMessageFilter::OnClipboardReadFilenames(
+ Clipboard::Buffer buffer, IPC::Message* reply) {
+ std::vector<string16> filenames;
+ bool result = ClipboardDispatcher::ReadFilenames(buffer, &filenames);
+ ViewHostMsg_ClipboardReadFilenames::WriteReplyParams(
+ reply, result, filenames);
+ Send(reply);
+}
+
+#endif
+
+void RenderMessageFilter::OnCheckNotificationPermission(
+ const GURL& source_url, int* result) {
+ *result = WebKit::WebNotificationPresenter::PermissionNotAllowed;
+
+ ChromeURLRequestContext* context = GetRequestContextForURL(source_url);
+ if (context->extension_info_map()->CheckURLAccessToExtensionPermission(
+ source_url, Extension::kNotificationPermission)) {
+ *result = WebKit::WebNotificationPresenter::PermissionAllowed;
+ return;
+ }
+
+ // Fall back to the regular notification preferences, which works on an
+ // origin basis.
+ *result = notification_prefs_->HasPermission(source_url.GetOrigin());
+}
+
+void RenderMessageFilter::OnGetCPBrowsingContext(uint32* context) {
+ // Always allocate a new context when a plugin requests one, since it needs to
+ // be unique for that plugin instance.
+ *context = CPBrowsingContextManager::GetInstance()->Allocate(
+ request_context_->GetURLRequestContext());
+}
+
+#if defined(OS_WIN)
+void RenderMessageFilter::OnDuplicateSection(
+ base::SharedMemoryHandle renderer_handle,
+ base::SharedMemoryHandle* browser_handle) {
+ // Duplicate the handle in this process right now so the memory is kept alive
+ // (even if it is not mapped)
+ base::SharedMemory shared_buf(renderer_handle, true, peer_handle());
+ shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), browser_handle);
+}
+#endif
+
+#if defined(OS_POSIX)
+void RenderMessageFilter::OnAllocateSharedMemoryBuffer(
+ uint32 buffer_size,
+ base::SharedMemoryHandle* handle) {
+ base::SharedMemory shared_buf;
+ if (!shared_buf.CreateAndMapAnonymous(buffer_size)) {
+ *handle = base::SharedMemory::NULLHandle();
+ NOTREACHED() << "Cannot map shared memory buffer";
+ return;
+ }
+ shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), handle);
+}
+#endif
+
+void RenderMessageFilter::OnResourceTypeStats(
+ const WebCache::ResourceTypeStats& stats) {
+ HISTOGRAM_COUNTS("WebCoreCache.ImagesSizeKB",
+ static_cast<int>(stats.images.size / 1024));
+ HISTOGRAM_COUNTS("WebCoreCache.CSSStylesheetsSizeKB",
+ static_cast<int>(stats.cssStyleSheets.size / 1024));
+ HISTOGRAM_COUNTS("WebCoreCache.ScriptsSizeKB",
+ static_cast<int>(stats.scripts.size / 1024));
+ HISTOGRAM_COUNTS("WebCoreCache.XSLStylesheetsSizeKB",
+ static_cast<int>(stats.xslStyleSheets.size / 1024));
+ HISTOGRAM_COUNTS("WebCoreCache.FontsSizeKB",
+ static_cast<int>(stats.fonts.size / 1024));
+ // We need to notify the TaskManager of these statistics from the UI
+ // thread.
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableFunction(
+ &RenderMessageFilter::OnResourceTypeStatsOnUIThread,
+ stats,
+ base::GetProcId(peer_handle())));
+}
+
+void RenderMessageFilter::OnResourceTypeStatsOnUIThread(
+ const WebCache::ResourceTypeStats& stats, base::ProcessId renderer_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ TaskManager::GetInstance()->model()->NotifyResourceTypeStats(
+ renderer_id, stats);
+}
+
+
+void RenderMessageFilter::OnV8HeapStats(int v8_memory_allocated,
+ int v8_memory_used) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableFunction(&RenderMessageFilter::OnV8HeapStatsOnUIThread,
+ v8_memory_allocated,
+ v8_memory_used,
+ base::GetProcId(peer_handle())));
+}
+
+// static
+void RenderMessageFilter::OnV8HeapStatsOnUIThread(
+ int v8_memory_allocated, int v8_memory_used, base::ProcessId renderer_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ TaskManager::GetInstance()->model()->NotifyV8HeapStats(
+ renderer_id,
+ static_cast<size_t>(v8_memory_allocated),
+ static_cast<size_t>(v8_memory_used));
+}
+
+void RenderMessageFilter::OnDidZoomURL(const IPC::Message& message,
+ double zoom_level,
+ bool remember,
+ const GURL& url) {
+ Task* task = NewRunnableMethod(this,
+ &RenderMessageFilter::UpdateHostZoomLevelsOnUIThread, zoom_level,
+ remember, url, render_process_id_, message.routing_id());
+#if defined(OS_MACOSX)
+ cocoa_utils::PostTaskInEventTrackingRunLoopMode(FROM_HERE, task);
+#else
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, task);
+#endif
+}
+
+void RenderMessageFilter::UpdateHostZoomLevelsOnUIThread(
+ double zoom_level,
+ bool remember,
+ const GURL& url,
+ int render_process_id,
+ int render_view_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (remember) {
+ host_zoom_map_->SetZoomLevel(url, zoom_level);
+ // Notify renderers from this profile.
+ for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
+ !i.IsAtEnd(); i.Advance()) {
+ RenderProcessHost* render_process_host = i.GetCurrentValue();
+ if (render_process_host->profile() == profile_) {
+ render_process_host->Send(
+ new ViewMsg_SetZoomLevelForCurrentURL(url, zoom_level));
+ }
+ }
+ } else {
+ host_zoom_map_->SetTemporaryZoomLevel(
+ render_process_id, render_view_id, zoom_level);
+ }
+}
+
+void RenderMessageFilter::OnResolveProxy(const GURL& url,
+ IPC::Message* reply_msg) {
+ resolve_proxy_msg_helper_.Start(url, reply_msg);
+}
+
+void RenderMessageFilter::OnResolveProxyCompleted(
+ IPC::Message* reply_msg,
+ int result,
+ const std::string& proxy_list) {
+ ViewHostMsg_ResolveProxy::WriteReplyParams(reply_msg, result, proxy_list);
+ Send(reply_msg);
+}
+
+void RenderMessageFilter::OnGetDefaultPrintSettings(IPC::Message* reply_msg) {
+ scoped_refptr<printing::PrinterQuery> printer_query;
+ if (!print_job_manager_->printing_enabled()) {
+ // Reply with NULL query.
+ OnGetDefaultPrintSettingsReply(printer_query, reply_msg);
+ return;
+ }
+
+ print_job_manager_->PopPrinterQuery(0, &printer_query);
+ if (!printer_query.get()) {
+ printer_query = new printing::PrinterQuery;
+ }
+
+ CancelableTask* task = NewRunnableMethod(
+ this,
+ &RenderMessageFilter::OnGetDefaultPrintSettingsReply,
+ printer_query,
+ reply_msg);
+ // Loads default settings. This is asynchronous, only the IPC message sender
+ // will hang until the settings are retrieved.
+ printer_query->GetSettings(printing::PrinterQuery::DEFAULTS,
+ NULL,
+ 0,
+ false,
+ true,
+ task);
+}
+
+void RenderMessageFilter::OnGetDefaultPrintSettingsReply(
+ scoped_refptr<printing::PrinterQuery> printer_query,
+ IPC::Message* reply_msg) {
+ ViewMsg_Print_Params params;
+ if (!printer_query.get() ||
+ printer_query->last_status() != printing::PrintingContext::OK) {
+ memset(&params, 0, sizeof(params));
+ } else {
+ RenderParamsFromPrintSettings(printer_query->settings(), &params);
+ params.document_cookie = printer_query->cookie();
+ }
+ ViewHostMsg_GetDefaultPrintSettings::WriteReplyParams(reply_msg, params);
+ Send(reply_msg);
+ // If printing was enabled.
+ if (printer_query.get()) {
+ // If user hasn't cancelled.
+ if (printer_query->cookie() && printer_query->settings().dpi()) {
+ print_job_manager_->QueuePrinterQuery(printer_query.get());
+ } else {
+ printer_query->StopWorker();
+ }
+ }
+}
+
+void RenderMessageFilter::OnScriptedPrint(
+ const ViewHostMsg_ScriptedPrint_Params& params,
+ IPC::Message* reply_msg) {
+ gfx::NativeView host_view =
+ gfx::NativeViewFromIdInBrowser(params.host_window_id);
+
+ scoped_refptr<printing::PrinterQuery> printer_query;
+ print_job_manager_->PopPrinterQuery(params.cookie, &printer_query);
+ if (!printer_query.get()) {
+ printer_query = new printing::PrinterQuery;
+ }
+
+ CancelableTask* task = NewRunnableMethod(
+ this,
+ &RenderMessageFilter::OnScriptedPrintReply,
+ printer_query,
+ params.routing_id,
+ reply_msg);
+
+ printer_query->GetSettings(printing::PrinterQuery::ASK_USER,
+ host_view,
+ params.expected_pages_count,
+ params.has_selection,
+ params.use_overlays,
+ task);
+}
+
+void RenderMessageFilter::OnScriptedPrintReply(
+ scoped_refptr<printing::PrinterQuery> printer_query,
+ int routing_id,
+ IPC::Message* reply_msg) {
+ ViewMsg_PrintPages_Params params;
+ if (printer_query->last_status() != printing::PrintingContext::OK ||
+ !printer_query->settings().dpi()) {
+ memset(&params, 0, sizeof(params));
+ } else {
+ RenderParamsFromPrintSettings(printer_query->settings(), &params.params);
+ params.params.document_cookie = printer_query->cookie();
+ params.pages =
+ printing::PageRange::GetPages(printer_query->settings().ranges);
+ }
+ ViewHostMsg_ScriptedPrint::WriteReplyParams(reply_msg, params);
+ Send(reply_msg);
+ if (params.params.dpi && params.params.document_cookie) {
+ print_job_manager_->QueuePrinterQuery(printer_query.get());
+ } else {
+ printer_query->StopWorker();
+ }
+}
+
+// static
+Clipboard* RenderMessageFilter::GetClipboard() {
+ // We have a static instance of the clipboard service for use by all message
+ // filters. This instance lives for the life of the browser processes.
+ static Clipboard* clipboard = new Clipboard;
+
+ return clipboard;
+}
+
+ChromeURLRequestContext* RenderMessageFilter::GetRequestContextForURL(
+ const GURL& url) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ URLRequestContextGetter* context_getter =
+ url.SchemeIs(chrome::kExtensionScheme) ?
+ extensions_request_context_ : request_context_;
+ return static_cast<ChromeURLRequestContext*>(
+ context_getter->GetURLRequestContext());
+}
+
+void RenderMessageFilter::OnPlatformCheckSpelling(const string16& word,
+ int tag,
+ bool* correct) {
+ *correct = SpellCheckerPlatform::CheckSpelling(word, tag);
+}
+
+void RenderMessageFilter::OnPlatformFillSuggestionList(
+ const string16& word,
+ std::vector<string16>* suggestions) {
+ SpellCheckerPlatform::FillSuggestionList(word, suggestions);
+}
+
+void RenderMessageFilter::OnGetDocumentTag(IPC::Message* reply_msg) {
+ int tag = SpellCheckerPlatform::GetDocumentTag();
+ ViewHostMsg_GetDocumentTag::WriteReplyParams(reply_msg, tag);
+ Send(reply_msg);
+ return;
+}
+
+void RenderMessageFilter::OnDocumentWithTagClosed(int tag) {
+ SpellCheckerPlatform::CloseDocumentWithTag(tag);
+}
+
+void RenderMessageFilter::OnShowSpellingPanel(bool show) {
+ SpellCheckerPlatform::ShowSpellingPanel(show);
+}
+
+void RenderMessageFilter::OnUpdateSpellingPanelWithMisspelledWord(
+ const string16& word) {
+ SpellCheckerPlatform::UpdateSpellingPanelWithMisspelledWord(word);
+}
+
+void RenderMessageFilter::OnDnsPrefetch(
+ const std::vector<std::string>& hostnames) {
+ chrome_browser_net::DnsPrefetchList(hostnames);
+}
+
+void RenderMessageFilter::OnRendererHistograms(
+ int sequence_number,
+ const std::vector<std::string>& histograms) {
+ HistogramSynchronizer::DeserializeHistogramList(sequence_number, histograms);
+}
+
+#if defined(OS_MACOSX)
+void RenderMessageFilter::OnAllocTransportDIB(
+ size_t size, bool cache_in_browser, TransportDIB::Handle* handle) {
+ render_widget_helper_->AllocTransportDIB(size, cache_in_browser, handle);
+}
+
+void RenderMessageFilter::OnFreeTransportDIB(
+ TransportDIB::Id dib_id) {
+ render_widget_helper_->FreeTransportDIB(dib_id);
+}
+#endif
+
+void RenderMessageFilter::OnOpenChannelToExtension(
+ int routing_id, const std::string& source_extension_id,
+ const std::string& target_extension_id,
+ const std::string& channel_name, int* port_id) {
+ int port2_id;
+ ExtensionMessageService::AllocatePortIdPair(port_id, &port2_id);
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ this, &RenderMessageFilter::OpenChannelToExtensionOnUIThread,
+ render_process_id_, routing_id, port2_id, source_extension_id,
+ target_extension_id, channel_name));
+}
+
+void RenderMessageFilter::OpenChannelToExtensionOnUIThread(
+ int source_process_id, int source_routing_id,
+ int receiver_port_id,
+ const std::string& source_extension_id,
+ const std::string& target_extension_id,
+ const std::string& channel_name) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ profile_->GetExtensionMessageService()->OpenChannelToExtension(
+ source_process_id, source_routing_id, receiver_port_id,
+ source_extension_id, target_extension_id, channel_name);
+}
+
+void RenderMessageFilter::OnOpenChannelToTab(
+ int routing_id, int tab_id, const std::string& extension_id,
+ const std::string& channel_name, int* port_id) {
+ int port2_id;
+ ExtensionMessageService::AllocatePortIdPair(port_id, &port2_id);
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ this, &RenderMessageFilter::OpenChannelToTabOnUIThread,
+ render_process_id_, routing_id, port2_id, tab_id, extension_id,
+ channel_name));
+}
+
+void RenderMessageFilter::OpenChannelToTabOnUIThread(
+ int source_process_id, int source_routing_id,
+ int receiver_port_id,
+ int tab_id,
+ const std::string& extension_id,
+ const std::string& channel_name) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ profile_->GetExtensionMessageService()->OpenChannelToTab(
+ source_process_id, source_routing_id, receiver_port_id,
+ tab_id, extension_id, channel_name);
+}
+
+bool RenderMessageFilter::CheckBenchmarkingEnabled() const {
+ static bool checked = false;
+ static bool result = false;
+ if (!checked) {
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ result = command_line.HasSwitch(switches::kEnableBenchmarking);
+ checked = true;
+ }
+ return result;
+}
+
+void RenderMessageFilter::OnCloseCurrentConnections() {
+ // This function is disabled unless the user has enabled
+ // benchmarking extensions.
+ if (!CheckBenchmarkingEnabled())
+ return;
+ request_context_->GetURLRequestContext()->
+ http_transaction_factory()->GetCache()->CloseCurrentConnections();
+}
+
+void RenderMessageFilter::OnSetCacheMode(bool enabled) {
+ // This function is disabled unless the user has enabled
+ // benchmarking extensions.
+ if (!CheckBenchmarkingEnabled())
+ return;
+
+ net::HttpCache::Mode mode = enabled ?
+ net::HttpCache::NORMAL : net::HttpCache::DISABLE;
+ net::HttpCache* http_cache = request_context_->GetURLRequestContext()->
+ http_transaction_factory()->GetCache();
+ http_cache->set_mode(mode);
+}
+
+void RenderMessageFilter::OnClearCache(IPC::Message* reply_msg) {
+ // This function is disabled unless the user has enabled
+ // benchmarking extensions.
+ int rv = -1;
+ if (CheckBenchmarkingEnabled()) {
+ disk_cache::Backend* backend = request_context_->GetURLRequestContext()->
+ http_transaction_factory()->GetCache()->GetCurrentBackend();
+ if (backend) {
+ ClearCacheCompletion* callback =
+ new ClearCacheCompletion(reply_msg, this);
+ rv = backend->DoomAllEntries(callback);
+ if (rv == net::ERR_IO_PENDING) {
+ // The callback will send the reply.
+ return;
+ }
+ // Completed synchronously, no need for the callback.
+ delete callback;
+ }
+ }
+ ViewHostMsg_ClearCache::WriteReplyParams(reply_msg, rv);
+ Send(reply_msg);
+}
+
+bool RenderMessageFilter::CheckPreparsedJsCachingEnabled() const {
+ static bool checked = false;
+ static bool result = false;
+ if (!checked) {
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ result = command_line.HasSwitch(switches::kEnablePreparsedJsCaching);
+ checked = true;
+ }
+ return result;
+}
+
+void RenderMessageFilter::OnCacheableMetadataAvailable(
+ const GURL& url,
+ double expected_response_time,
+ const std::vector<char>& data) {
+ if (!CheckPreparsedJsCachingEnabled())
+ return;
+
+ net::HttpCache* cache = request_context_->GetURLRequestContext()->
+ http_transaction_factory()->GetCache();
+ DCHECK(cache);
+
+ scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(data.size()));
+ memcpy(buf->data(), &data.front(), data.size());
+ cache->WriteMetadata(
+ url, base::Time::FromDoubleT(expected_response_time), buf, data.size());
+}
+
+// TODO(lzheng): This only enables spdy over ssl. Enable spdy for http
+// when needed.
+void RenderMessageFilter::OnEnableSpdy(bool enable) {
+ if (enable) {
+ net::HttpNetworkLayer::EnableSpdy("npn,force-alt-protocols");
+ } else {
+ net::HttpNetworkLayer::EnableSpdy("npn-http");
+ }
+}
+
+void RenderMessageFilter::OnKeygen(uint32 key_size_index,
+ const std::string& challenge_string,
+ const GURL& url,
+ IPC::Message* reply_msg) {
+ // Map displayed strings indicating level of keysecurity in the <keygen>
+ // menu to the key size in bits. (See SSLKeyGeneratorChromium.cpp in WebCore.)
+ int key_size_in_bits;
+ switch (key_size_index) {
+ case 0:
+ key_size_in_bits = 2048;
+ break;
+ case 1:
+ key_size_in_bits = 1024;
+ break;
+ default:
+ DCHECK(false) << "Illegal key_size_index " << key_size_index;
+ ViewHostMsg_Keygen::WriteReplyParams(reply_msg, std::string());
+ Send(reply_msg);
+ return;
+ }
+
+ VLOG(1) << "Dispatching keygen task to worker pool.";
+ // Dispatch to worker pool, so we do not block the IO thread.
+ if (!WorkerPool::PostTask(
+ FROM_HERE,
+ NewRunnableMethod(
+ this, &RenderMessageFilter::OnKeygenOnWorkerThread,
+ key_size_in_bits, challenge_string, url, reply_msg),
+ true)) {
+ NOTREACHED() << "Failed to dispatch keygen task to worker pool";
+ ViewHostMsg_Keygen::WriteReplyParams(reply_msg, std::string());
+ Send(reply_msg);
+ return;
+ }
+}
+
+void RenderMessageFilter::OnKeygenOnWorkerThread(
+ int key_size_in_bits,
+ const std::string& challenge_string,
+ const GURL& url,
+ IPC::Message* reply_msg) {
+ DCHECK(reply_msg);
+
+ // Generate a signed public key and challenge, then send it back.
+ net::KeygenHandler keygen_handler(key_size_in_bits, challenge_string, url);
+
+ ViewHostMsg_Keygen::WriteReplyParams(
+ reply_msg,
+ keygen_handler.GenKeyAndSignChallenge());
+
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(this, &RenderMessageFilter::Send, reply_msg));
+}
+
+#if defined(USE_TCMALLOC)
+void RenderMessageFilter::OnRendererTcmalloc(base::ProcessId pid,
+ const std::string& output) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableFunction(AboutTcmallocRendererCallback, pid, output));
+}
+#endif
+
+void RenderMessageFilter::OnEstablishGpuChannel() {
+ GpuProcessHost::Get()->EstablishGpuChannel(render_process_id_, this);
+}
+
+void RenderMessageFilter::OnSynchronizeGpu(IPC::Message* reply) {
+ // We handle this message (and the other GPU process messages) here
+ // rather than handing the message to the GpuProcessHost for
+ // dispatch so that we can use the DELAY_REPLY macro to synthesize
+ // the reply message, and also send down a "this" pointer so that
+ // the GPU process host can send the reply later.
+ GpuProcessHost::Get()->Synchronize(reply, this);
+}
+
+void RenderMessageFilter::OnGetExtensionMessageBundle(
+ const std::string& extension_id, IPC::Message* reply_msg) {
+ ChromeURLRequestContext* context = static_cast<ChromeURLRequestContext*>(
+ request_context_->GetURLRequestContext());
+
+ FilePath extension_path =
+ context->extension_info_map()->GetPathForExtension(extension_id);
+ std::string default_locale =
+ context->extension_info_map()->GetDefaultLocaleForExtension(extension_id);
+
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(
+ this, &RenderMessageFilter::OnGetExtensionMessageBundleOnFileThread,
+ extension_path, extension_id, default_locale, reply_msg));
+}
+
+void RenderMessageFilter::OnGetExtensionMessageBundleOnFileThread(
+ const FilePath& extension_path,
+ const std::string& extension_id,
+ const std::string& default_locale,
+ IPC::Message* reply_msg) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+ std::map<std::string, std::string> dictionary_map;
+ if (!default_locale.empty()) {
+ // Touch disk only if extension is localized.
+ std::string error;
+ scoped_ptr<ExtensionMessageBundle> bundle(
+ extension_file_util::LoadExtensionMessageBundle(
+ extension_path, default_locale, &error));
+
+ if (bundle.get())
+ dictionary_map = *bundle->dictionary();
+ }
+
+ // Add @@extension_id reserved message here, so it's available to
+ // non-localized extensions too.
+ dictionary_map.insert(
+ std::make_pair(ExtensionMessageBundle::kExtensionIdKey, extension_id));
+
+ ViewHostMsg_GetExtensionMessageBundle::WriteReplyParams(
+ reply_msg, dictionary_map);
+
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(this, &RenderMessageFilter::Send, reply_msg));
+}
+
+void RenderMessageFilter::OnAsyncOpenFile(const IPC::Message& msg,
+ const FilePath& path,
+ int flags,
+ int message_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ if (!ChildProcessSecurityPolicy::GetInstance()->HasPermissionsForFile(
+ render_process_id_, path, flags)) {
+ DLOG(ERROR) << "Bad flags in ViewMsgHost_AsyncOpenFile message: " << flags;
+ UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_AOF"));
+ BadMessageReceived();
+ return;
+ }
+
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE, NewRunnableMethod(
+ this, &RenderMessageFilter::AsyncOpenFileOnFileThread,
+ path, flags, message_id, msg.routing_id()));
+}
+
+void RenderMessageFilter::AsyncOpenFileOnFileThread(const FilePath& path,
+ int flags,
+ int message_id,
+ int routing_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ base::PlatformFileError error_code = base::PLATFORM_FILE_OK;
+ base::PlatformFile file = base::CreatePlatformFile(
+ path, flags, NULL, &error_code);
+ IPC::PlatformFileForTransit file_for_transit =
+ IPC::InvalidPlatformFileForTransit();
+ if (file != base::kInvalidPlatformFileValue) {
+#if defined(OS_WIN)
+ ::DuplicateHandle(::GetCurrentProcess(), file, peer_handle(),
+ &file_for_transit, 0, false, DUPLICATE_SAME_ACCESS);
+#else
+ file_for_transit = base::FileDescriptor(file, true);
+#endif
+ }
+
+ IPC::Message* reply = new ViewMsg_AsyncOpenFile_ACK(
+ routing_id, error_code, file_for_transit, message_id);
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE, NewRunnableMethod(
+ this, &RenderMessageFilter::Send, reply));
+}
+
+SetCookieCompletion::SetCookieCompletion(int render_process_id,
+ int render_view_id,
+ const GURL& url,
+ const std::string& cookie_line,
+ ChromeURLRequestContext* context)
+ : render_process_id_(render_process_id),
+ render_view_id_(render_view_id),
+ url_(url),
+ cookie_line_(cookie_line),
+ context_(context) {
+}
+
+SetCookieCompletion::~SetCookieCompletion() {}
+
+void SetCookieCompletion::RunWithParams(const Tuple1<int>& params) {
+ int result = params.a;
+ bool blocked_by_policy = true;
+ net::CookieOptions options;
+ if (result == net::OK ||
+ result == net::OK_FOR_SESSION_ONLY) {
+ blocked_by_policy = false;
+ if (result == net::OK_FOR_SESSION_ONLY)
+ options.set_force_session();
+ context_->cookie_store()->SetCookieWithOptions(url_, cookie_line_,
+ options);
+ }
+ if (!context_->IsExternal()) {
+ CallRenderViewHostContentSettingsDelegate(
+ render_process_id_, render_view_id_,
+ &RenderViewHostDelegate::ContentSettings::OnCookieChanged,
+ url_, cookie_line_, options, blocked_by_policy);
+ }
+ delete this;
+}
+
+GetCookiesCompletion::GetCookiesCompletion(int render_process_id,
+ int render_view_id,
+ const GURL& url,
+ IPC::Message* reply_msg,
+ RenderMessageFilter* filter,
+ ChromeURLRequestContext* context,
+ bool raw_cookies)
+ : url_(url),
+ reply_msg_(reply_msg),
+ filter_(filter),
+ context_(context),
+ render_process_id_(render_process_id),
+ render_view_id_(render_view_id),
+ raw_cookies_(raw_cookies) {
+ set_cookie_store(context_->cookie_store());
+}
+
+GetCookiesCompletion::~GetCookiesCompletion() {}
+
+void GetCookiesCompletion::RunWithParams(const Tuple1<int>& params) {
+ if (!raw_cookies_) {
+ int result = params.a;
+ std::string cookies;
+ if (result == net::OK)
+ cookies = cookie_store()->GetCookies(url_);
+ ViewHostMsg_GetCookies::WriteReplyParams(reply_msg_, cookies);
+ filter_->Send(reply_msg_);
+ if (!context_->IsExternal()) {
+ net::CookieMonster* cookie_monster =
+ context_->cookie_store()->GetCookieMonster();
+ net::CookieList cookie_list =
+ cookie_monster->GetAllCookiesForURLWithOptions(
+ url_, net::CookieOptions());
+ CallRenderViewHostContentSettingsDelegate(
+ render_process_id_, render_view_id_,
+ &RenderViewHostDelegate::ContentSettings::OnCookiesRead,
+ url_, cookie_list, result != net::OK);
+ }
+ delete this;
+ } else {
+ // Ignore the policy result. We only waited on the policy result so that
+ // any pending 'set-cookie' requests could be flushed. The intent of
+ // querying the raw cookies is to reveal the contents of the cookie DB, so
+ // it important that we don't read the cookie db ahead of pending writes.
+ net::CookieMonster* cookie_monster =
+ context_->cookie_store()->GetCookieMonster();
+ net::CookieList cookie_list = cookie_monster->GetAllCookiesForURL(url_);
+
+ std::vector<webkit_glue::WebCookie> cookies;
+ for (size_t i = 0; i < cookie_list.size(); ++i) {
+ cookies.push_back(webkit_glue::WebCookie(cookie_list[i]));
+ }
+
+ ViewHostMsg_GetRawCookies::WriteReplyParams(reply_msg_, cookies);
+ filter_->Send(reply_msg_);
+ delete this;
+ }
+}
+
+void GetCookiesCompletion::set_cookie_store(CookieStore* cookie_store) {
+ cookie_store_ = cookie_store;
+}
+
+CookiesEnabledCompletion::CookiesEnabledCompletion(
+ IPC::Message* reply_msg,
+ RenderMessageFilter* filter)
+ : reply_msg_(reply_msg),
+ filter_(filter) {
+}
+
+CookiesEnabledCompletion::~CookiesEnabledCompletion() {}
+
+void CookiesEnabledCompletion::RunWithParams(const Tuple1<int>& params) {
+ bool result = params.a != net::ERR_ACCESS_DENIED;
+ ViewHostMsg_CookiesEnabled::WriteReplyParams(reply_msg_, result);
+ filter_->Send(reply_msg_);
+ delete this;
+}
diff --git a/chrome/browser/renderer_host/render_message_filter.h b/chrome/browser/renderer_host/render_message_filter.h
new file mode 100644
index 0000000..98e8402
--- /dev/null
+++ b/chrome/browser/renderer_host/render_message_filter.h
@@ -0,0 +1,498 @@
+// 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.
+
+#ifndef CHROME_BROWSER_RENDERER_HOST_RENDER_MESSAGE_FILTER_H_
+#define CHROME_BROWSER_RENDERER_HOST_RENDER_MESSAGE_FILTER_H_
+#pragma once
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+#include <string>
+#include <vector>
+
+#include "app/clipboard/clipboard.h"
+#include "app/surface/transport_dib.h"
+#include "base/file_path.h"
+#include "base/linked_ptr.h"
+#include "base/string16.h"
+#include "base/task.h"
+#include "build/build_config.h"
+#include "chrome/browser/browser_message_filter.h"
+#include "chrome/browser/in_process_webkit/webkit_context.h"
+#include "chrome/browser/net/resolve_proxy_msg_helper.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+#include "chrome/common/content_settings.h"
+#include "gfx/native_widget_types.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebCache.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebPopupType.h"
+
+class ChromeURLRequestContext;
+struct FontDescriptor;
+class HostContentSettingsMap;
+class HostZoomMap;
+class NotificationsPrefsCache;
+class PpapiPluginProcessHost;
+class Profile;
+class RenderWidgetHelper;
+class URLRequestContextGetter;
+struct ViewHostMsg_CreateWindow_Params;
+struct ViewHostMsg_CreateWorker_Params;
+
+namespace webkit {
+namespace npapi {
+struct WebPluginInfo;
+}
+}
+
+namespace base {
+class SharedMemory;
+}
+
+namespace net {
+class CookieStore;
+}
+
+namespace printing {
+class PrinterQuery;
+class PrintJobManager;
+}
+
+struct ViewHostMsg_ScriptedPrint_Params;
+
+// This class filters out incoming IPC messages for the renderer process on the
+// IPC thread.
+class RenderMessageFilter : public BrowserMessageFilter,
+ public ResolveProxyMsgHelper::Delegate {
+ public:
+ // Create the filter.
+ RenderMessageFilter(int render_process_id,
+ PluginService* plugin_service,
+ Profile* profile,
+ RenderWidgetHelper* render_widget_helper);
+
+ // BrowserMessageFilter methods:
+ virtual bool OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok);
+ virtual void OnDestruct() const;
+
+ int render_process_id() const { return render_process_id_; }
+ ResourceDispatcherHost* resource_dispatcher_host() {
+ return resource_dispatcher_host_;
+ }
+ bool off_the_record() { return off_the_record_; }
+
+ // Returns either the extension URLRequestContext or regular URLRequestContext
+ // depending on whether |url| is an extension URL.
+ // Only call on the IO thread.
+ ChromeURLRequestContext* GetRequestContextForURL(const GURL& url);
+
+ private:
+ friend class BrowserThread;
+ friend class DeleteTask<RenderMessageFilter>;
+
+ virtual ~RenderMessageFilter();
+
+ void OnMsgCreateWindow(const ViewHostMsg_CreateWindow_Params& params,
+ int* route_id,
+ int64* cloned_session_storage_namespace_id);
+ void OnMsgCreateWidget(int opener_id,
+ WebKit::WebPopupType popup_type,
+ int* route_id);
+ void OnMsgCreateFullscreenWidget(int opener_id,
+ WebKit::WebPopupType popup_type,
+ int* route_id);
+ void OnSetCookie(const IPC::Message& message,
+ const GURL& url,
+ const GURL& first_party_for_cookies,
+ const std::string& cookie);
+ void OnGetCookies(const GURL& url,
+ const GURL& first_party_for_cookies,
+ IPC::Message* reply_msg);
+ void OnGetRawCookies(const GURL& url,
+ const GURL& first_party_for_cookies,
+ IPC::Message* reply_msg);
+ void OnDeleteCookie(const GURL& url,
+ const std::string& cookieName);
+ void OnCookiesEnabled(const GURL& url,
+ const GURL& first_party_for_cookies,
+ IPC::Message* reply_msg);
+ void OnPluginFileDialog(const IPC::Message& msg,
+ bool multiple_files,
+ const std::wstring& title,
+ const std::wstring& filter,
+ uint32 user_data);
+
+#if defined(OS_MACOSX)
+ void OnLoadFont(const FontDescriptor& font,
+ uint32* handle_size,
+ base::SharedMemoryHandle* handle);
+#endif
+
+#if defined(OS_WIN) // This hack is Windows-specific.
+ // Cache fonts for the renderer. See RenderMessageFilter::OnPreCacheFont
+ // implementation for more details.
+ void OnPreCacheFont(LOGFONT font);
+#endif
+
+#if !defined(OS_MACOSX)
+ // Not handled in the IO thread on Mac.
+ void OnGetScreenInfo(gfx::NativeViewId window, IPC::Message* reply);
+#endif
+ void OnGetPlugins(bool refresh, IPC::Message* reply_msg);
+ void OnGetPluginsOnFileThread(bool refresh, IPC::Message* reply_msg);
+ void OnGetPluginInfo(const GURL& url,
+ const GURL& policy_url,
+ const std::string& mime_type,
+ IPC::Message* reply_msg);
+ void OnGetPluginInfoOnFileThread(const GURL& url,
+ const GURL& policy_url,
+ const std::string& mime_type,
+ IPC::Message* reply_msg);
+ void OnGotPluginInfo(bool found,
+ const webkit::npapi::WebPluginInfo& info,
+ const std::string& actual_mime_type,
+ const GURL& policy_url,
+ IPC::Message* reply_msg);
+ void OnOpenChannelToPlugin(const GURL& url,
+ const std::string& mime_type,
+ IPC::Message* reply_msg);
+ void OnOpenChannelToPepperPlugin(const FilePath& path,
+ IPC::Message* reply_msg);
+ void OnLaunchNaCl(const std::wstring& url,
+ int channel_descriptor,
+ IPC::Message* reply_msg);
+ void OnDownloadUrl(const IPC::Message& message,
+ const GURL& url,
+ const GURL& referrer);
+ void OnPlatformCheckSpelling(const string16& word, int tag, bool* correct);
+ void OnPlatformFillSuggestionList(const string16& word,
+ std::vector<string16>* suggestions);
+ void OnGetDocumentTag(IPC::Message* reply_msg);
+ void OnDocumentWithTagClosed(int tag);
+ void OnShowSpellingPanel(bool show);
+ void OnUpdateSpellingPanelWithMisspelledWord(const string16& word);
+ void OnDnsPrefetch(const std::vector<std::string>& hostnames);
+ void OnRendererHistograms(int sequence_number,
+ const std::vector<std::string>& histogram_info);
+#if defined(USE_TCMALLOC)
+ void OnRendererTcmalloc(base::ProcessId pid, const std::string& output);
+#endif
+ void OnReceiveContextMenuMsg(const IPC::Message& msg);
+ // Clipboard messages
+ void OnClipboardWriteObjectsAsync(const Clipboard::ObjectMap& objects);
+ void OnClipboardWriteObjectsSync(const Clipboard::ObjectMap& objects,
+ base::SharedMemoryHandle bitmap_handle);
+
+ void OnClipboardIsFormatAvailable(Clipboard::FormatType format,
+ Clipboard::Buffer buffer,
+ IPC::Message* reply);
+ void OnClipboardReadText(Clipboard::Buffer buffer, IPC::Message* reply);
+ void OnClipboardReadAsciiText(Clipboard::Buffer buffer, IPC::Message* reply);
+ void OnClipboardReadHTML(Clipboard::Buffer buffer, IPC::Message* reply);
+#if defined(OS_MACOSX)
+ void OnClipboardFindPboardWriteString(const string16& text);
+#endif
+ void OnClipboardReadAvailableTypes(Clipboard::Buffer buffer,
+ IPC::Message* reply);
+ void OnClipboardReadData(Clipboard::Buffer buffer, const string16& type,
+ IPC::Message* reply);
+ void OnClipboardReadFilenames(Clipboard::Buffer buffer, IPC::Message* reply);
+
+ void OnCheckNotificationPermission(const GURL& source_url,
+ int* permission_level);
+
+#if !defined(OS_MACOSX)
+ // Not handled in the IO thread on Mac.
+ void OnGetWindowRect(gfx::NativeViewId window, IPC::Message* reply);
+ void OnGetRootWindowRect(gfx::NativeViewId window, IPC::Message* reply);
+#endif
+
+ void OnRevealFolderInOS(const FilePath& path);
+ void OnGetCPBrowsingContext(uint32* context);
+
+#if defined(OS_WIN)
+ // Used to pass resulting EMF from renderer to browser in printing.
+ void OnDuplicateSection(base::SharedMemoryHandle renderer_handle,
+ base::SharedMemoryHandle* browser_handle);
+#endif
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+ // Used to ask the browser allocate a temporary file for the renderer
+ // to fill in resulting PDF in renderer.
+ void OnAllocateTempFileForPrinting(IPC::Message* reply_msg);
+ void OnTempFileForPrintingWritten(int fd_in_browser);
+#endif
+
+#if defined(OS_POSIX)
+ // Used to ask the browser to allocate a block of shared memory for the
+ // renderer to send back data in, since shared memory can't be created
+ // in the renderer on POSIX due to the sandbox.
+ void OnAllocateSharedMemoryBuffer(uint32 buffer_size,
+ base::SharedMemoryHandle* handle);
+#endif
+
+ void OnResourceTypeStats(const WebKit::WebCache::ResourceTypeStats& stats);
+ static void OnResourceTypeStatsOnUIThread(
+ const WebKit::WebCache::ResourceTypeStats&,
+ base::ProcessId renderer_id);
+
+ void OnV8HeapStats(int v8_memory_allocated, int v8_memory_used);
+ static void OnV8HeapStatsOnUIThread(int v8_memory_allocated,
+ int v8_memory_used,
+ base::ProcessId renderer_id);
+
+ void OnDidZoomURL(const IPC::Message& message,
+ double zoom_level,
+ bool remember,
+ const GURL& url);
+ void UpdateHostZoomLevelsOnUIThread(double zoom_level,
+ bool remember,
+ const GURL& url,
+ int render_process_id,
+ int render_view_id);
+
+ void OnResolveProxy(const GURL& url, IPC::Message* reply_msg);
+
+ // ResolveProxyMsgHelper::Delegate implementation:
+ virtual void OnResolveProxyCompleted(IPC::Message* reply_msg,
+ int result,
+ const std::string& proxy_list);
+
+ // A javascript code requested to print the current page. This is done in two
+ // steps and this is the first step. Get the print setting right here
+ // synchronously. It will hang the I/O completely.
+ void OnGetDefaultPrintSettings(IPC::Message* reply_msg);
+ void OnGetDefaultPrintSettingsReply(
+ scoped_refptr<printing::PrinterQuery> printer_query,
+ IPC::Message* reply_msg);
+
+ // A javascript code requested to print the current page. The renderer host
+ // have to show to the user the print dialog and returns the selected print
+ // settings.
+ void OnScriptedPrint(const ViewHostMsg_ScriptedPrint_Params& params,
+ IPC::Message* reply_msg);
+ void OnScriptedPrintReply(
+ scoped_refptr<printing::PrinterQuery> printer_query,
+ int routing_id,
+ IPC::Message* reply_msg);
+
+ // Browser side transport DIB allocation
+ void OnAllocTransportDIB(size_t size,
+ bool cache_in_browser,
+ TransportDIB::Handle* result);
+ void OnFreeTransportDIB(TransportDIB::Id dib_id);
+
+ void OnOpenChannelToExtension(int routing_id,
+ const std::string& source_extension_id,
+ const std::string& target_extension_id,
+ const std::string& channel_name, int* port_id);
+ void OpenChannelToExtensionOnUIThread(int source_process_id,
+ int source_routing_id,
+ int receiver_port_id,
+ const std::string& source_extension_id,
+ const std::string& target_extension_id,
+ const std::string& channel_name);
+ void OnOpenChannelToTab(int routing_id, int tab_id,
+ const std::string& extension_id,
+ const std::string& channel_name, int* port_id);
+ void OpenChannelToTabOnUIThread(int source_process_id, int source_routing_id,
+ int receiver_port_id,
+ int tab_id, const std::string& extension_id,
+ const std::string& channel_name);
+
+ void OnCloseCurrentConnections();
+ void OnSetCacheMode(bool enabled);
+ void OnClearCache(IPC::Message* reply_msg);
+ void OnCacheableMetadataAvailable(const GURL& url,
+ double expected_response_time,
+ const std::vector<char>& data);
+ void OnEnableSpdy(bool enable);
+ void OnKeygen(uint32 key_size_index, const std::string& challenge_string,
+ const GURL& url, IPC::Message* reply_msg);
+ void OnKeygenOnWorkerThread(
+ int key_size_in_bits,
+ const std::string& challenge_string,
+ const GURL& url,
+ IPC::Message* reply_msg);
+ void OnGetExtensionMessageBundle(const std::string& extension_id,
+ IPC::Message* reply_msg);
+ void OnGetExtensionMessageBundleOnFileThread(
+ const FilePath& extension_path,
+ const std::string& extension_id,
+ const std::string& default_locale,
+ IPC::Message* reply_msg);
+ void OnEstablishGpuChannel();
+ void OnSynchronizeGpu(IPC::Message* reply);
+
+ void OnAsyncOpenFile(const IPC::Message& msg,
+ const FilePath& path,
+ int flags,
+ int message_id);
+ void AsyncOpenFileOnFileThread(const FilePath& path,
+ int flags,
+ int message_id,
+ int routing_id);
+
+#if defined(USE_X11)
+ void DoOnGetScreenInfo(gfx::NativeViewId view, IPC::Message* reply_msg);
+ void DoOnGetWindowRect(gfx::NativeViewId view, IPC::Message* reply_msg);
+ void DoOnGetRootWindowRect(gfx::NativeViewId view, IPC::Message* reply_msg);
+ void DoOnClipboardIsFormatAvailable(Clipboard::FormatType format,
+ Clipboard::Buffer buffer,
+ IPC::Message* reply_msg);
+ void DoOnClipboardReadText(Clipboard::Buffer buffer, IPC::Message* reply_msg);
+ void DoOnClipboardReadAsciiText(Clipboard::Buffer buffer,
+ IPC::Message* reply_msg);
+ void DoOnClipboardReadHTML(Clipboard::Buffer buffer, IPC::Message* reply_msg);
+ void DoOnClipboardReadAvailableTypes(Clipboard::Buffer buffer,
+ IPC::Message* reply_msg);
+ void DoOnClipboardReadData(Clipboard::Buffer buffer, const string16& type,
+ IPC::Message* reply_msg);
+ void DoOnClipboardReadFilenames(Clipboard::Buffer buffer,
+ IPC::Message* reply_msg);
+ void DoOnAllocateTempFileForPrinting(IPC::Message* reply_msg);
+#endif
+
+ bool CheckBenchmarkingEnabled() const;
+ bool CheckPreparsedJsCachingEnabled() const;
+
+ // We have our own clipboard because we want to access the clipboard on the
+ // IO thread instead of forwarding (possibly synchronous) messages to the UI
+ // thread. This instance of the clipboard should be accessed only on the IO
+ // thread.
+ static Clipboard* GetClipboard();
+
+ // Cached resource request dispatcher host and plugin service, guaranteed to
+ // be non-null if Init succeeds. We do not own the objects, they are managed
+ // by the BrowserProcess, which has a wider scope than we do.
+ ResourceDispatcherHost* resource_dispatcher_host_;
+ PluginService* plugin_service_;
+ printing::PrintJobManager* print_job_manager_;
+
+ // The Profile associated with our renderer process. This should only be
+ // accessed on the UI thread!
+ Profile* profile_;
+
+ // The host content settings map. Stored separately from the profile so we can
+ // access it on other threads.
+ HostContentSettingsMap* content_settings_;
+
+ // Helper class for handling PluginProcessHost_ResolveProxy messages (manages
+ // the requests to the proxy service).
+ ResolveProxyMsgHelper resolve_proxy_msg_helper_;
+
+ // Contextual information to be used for requests created here.
+ scoped_refptr<URLRequestContextGetter> request_context_;
+
+ // A request context that holds a cookie store for chrome-extension URLs.
+ scoped_refptr<URLRequestContextGetter> extensions_request_context_;
+
+ scoped_refptr<RenderWidgetHelper> render_widget_helper_;
+
+ // A cache of notifications preferences which is used to handle
+ // Desktop Notifications permission messages.
+ scoped_refptr<NotificationsPrefsCache> notification_prefs_;
+
+ // Handles zoom-related messages.
+ scoped_refptr<HostZoomMap> host_zoom_map_;
+
+ // Whether this process is used for off the record tabs.
+ bool off_the_record_;
+
+ bool cloud_print_enabled_;
+
+ base::TimeTicks last_plugin_refresh_time_; // Initialized to 0.
+
+ // A list of all Ppapi plugin processes for this renderer.
+ std::vector<linked_ptr<PpapiPluginProcessHost> > ppapi_plugin_hosts_;
+
+ scoped_refptr<WebKitContext> webkit_context_;
+
+ int render_process_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(RenderMessageFilter);
+};
+
+// These classes implement completion callbacks for getting and setting
+// cookies.
+class SetCookieCompletion : public net::CompletionCallback {
+ public:
+ SetCookieCompletion(int render_process_id,
+ int render_view_id,
+ const GURL& url,
+ const std::string& cookie_line,
+ ChromeURLRequestContext* context);
+ virtual ~SetCookieCompletion();
+
+ virtual void RunWithParams(const Tuple1<int>& params);
+
+ int render_process_id() const {
+ return render_process_id_;
+ }
+
+ int render_view_id() const {
+ return render_view_id_;
+ }
+
+ private:
+ int render_process_id_;
+ int render_view_id_;
+ GURL url_;
+ std::string cookie_line_;
+ scoped_refptr<ChromeURLRequestContext> context_;
+};
+
+class GetCookiesCompletion : public net::CompletionCallback {
+ public:
+ GetCookiesCompletion(int render_process_id,
+ int render_view_id,
+ const GURL& url, IPC::Message* reply_msg,
+ RenderMessageFilter* filter,
+ ChromeURLRequestContext* context,
+ bool raw_cookies);
+ virtual ~GetCookiesCompletion();
+
+ virtual void RunWithParams(const Tuple1<int>& params);
+
+ int render_process_id() const {
+ return render_process_id_;
+ }
+
+ int render_view_id() const {
+ return render_view_id_;
+ }
+
+ void set_cookie_store(net::CookieStore* cookie_store);
+
+ net::CookieStore* cookie_store() {
+ return cookie_store_.get();
+ }
+
+ private:
+ GURL url_;
+ IPC::Message* reply_msg_;
+ scoped_refptr<RenderMessageFilter> filter_;
+ scoped_refptr<ChromeURLRequestContext> context_;
+ int render_process_id_;
+ int render_view_id_;
+ bool raw_cookies_;
+ scoped_refptr<net::CookieStore> cookie_store_;
+};
+
+class CookiesEnabledCompletion : public net::CompletionCallback {
+ public:
+ CookiesEnabledCompletion(IPC::Message* reply_msg,
+ RenderMessageFilter* filter);
+ virtual ~CookiesEnabledCompletion();
+
+ virtual void RunWithParams(const Tuple1<int>& params);
+
+ private:
+ IPC::Message* reply_msg_;
+ scoped_refptr<RenderMessageFilter> filter_;
+};
+
+#endif // CHROME_BROWSER_RENDERER_HOST_RENDER_MESSAGE_FILTER_H_
diff --git a/chrome/browser/renderer_host/render_message_filter_gtk.cc b/chrome/browser/renderer_host/render_message_filter_gtk.cc
new file mode 100644
index 0000000..4088c8a
--- /dev/null
+++ b/chrome/browser/renderer_host/render_message_filter_gtk.cc
@@ -0,0 +1,344 @@
+// Copyright (c) 2009 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 "chrome/browser/renderer_host/render_message_filter.h"
+
+#include <fcntl.h>
+#include <map>
+
+#include "app/clipboard/clipboard.h"
+#include "app/x11_util.h"
+#include "base/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/path_service.h"
+#include "chrome/browser/browser_thread.h"
+#if defined(TOOLKIT_GTK)
+#include "chrome/browser/printing/print_dialog_gtk.h"
+#else
+#include "chrome/browser/printing/print_dialog_cloud.h"
+#endif
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/render_messages.h"
+#include "gfx/gtk_native_view_id_manager.h"
+#include "grit/generated_resources.h"
+
+#include "third_party/WebKit/WebKit/chromium/public/WebScreenInfo.h"
+#include "third_party/WebKit/WebKit/chromium/public/x11/WebScreenInfoFactory.h"
+
+using WebKit::WebScreenInfo;
+using WebKit::WebScreenInfoFactory;
+
+namespace {
+
+typedef std::map<int, FilePath> FdMap;
+
+struct PrintingFileDescriptorMap {
+ FdMap map;
+};
+
+static base::LazyInstance<PrintingFileDescriptorMap>
+ g_printing_file_descriptor_map(base::LINKER_INITIALIZED);
+
+} // namespace
+
+// We get null window_ids passed into the two functions below; please see
+// http://crbug.com/9060 for more details.
+
+// Called on the BACKGROUND_X11 thread.
+void RenderMessageFilter::DoOnGetScreenInfo(gfx::NativeViewId view,
+ IPC::Message* reply_msg) {
+ Display* display = x11_util::GetSecondaryDisplay();
+ int screen = x11_util::GetDefaultScreen(display);
+ WebScreenInfo results = WebScreenInfoFactory::screenInfo(display, screen);
+ ViewHostMsg_GetScreenInfo::WriteReplyParams(reply_msg, results);
+ Send(reply_msg);
+}
+
+// Called on the BACKGROUND_X11 thread.
+void RenderMessageFilter::DoOnGetWindowRect(gfx::NativeViewId view,
+ IPC::Message* reply_msg) {
+ // This is called to get the x, y offset (in screen coordinates) of the given
+ // view and its width and height.
+ gfx::Rect rect;
+ XID window;
+
+ AutoLock lock(GtkNativeViewManager::GetInstance()->unrealize_lock());
+ if (GtkNativeViewManager::GetInstance()->GetXIDForId(&window, view)) {
+ if (window) {
+ int x, y;
+ unsigned width, height;
+ if (x11_util::GetWindowGeometry(&x, &y, &width, &height, window))
+ rect = gfx::Rect(x, y, width, height);
+ }
+ }
+
+ ViewHostMsg_GetWindowRect::WriteReplyParams(reply_msg, rect);
+ Send(reply_msg);
+}
+
+// Return the top-level parent of the given window. Called on the
+// BACKGROUND_X11 thread.
+static XID GetTopLevelWindow(XID window) {
+ bool parent_is_root;
+ XID parent_window;
+
+ if (!x11_util::GetWindowParent(&parent_window, &parent_is_root, window))
+ return 0;
+ if (parent_is_root)
+ return window;
+
+ return GetTopLevelWindow(parent_window);
+}
+
+// Called on the BACKGROUND_X11 thread.
+void RenderMessageFilter::DoOnGetRootWindowRect(gfx::NativeViewId view,
+ IPC::Message* reply_msg) {
+ // This is called to get the screen coordinates and size of the browser
+ // window itself.
+ gfx::Rect rect;
+ XID window;
+
+ AutoLock lock(GtkNativeViewManager::GetInstance()->unrealize_lock());
+ if (GtkNativeViewManager::GetInstance()->GetXIDForId(&window, view)) {
+ if (window) {
+ const XID toplevel = GetTopLevelWindow(window);
+ if (toplevel) {
+ int x, y;
+ unsigned width, height;
+ if (x11_util::GetWindowGeometry(&x, &y, &width, &height, toplevel))
+ rect = gfx::Rect(x, y, width, height);
+ }
+ }
+ }
+
+ ViewHostMsg_GetRootWindowRect::WriteReplyParams(reply_msg, rect);
+ Send(reply_msg);
+}
+
+// Called on the UI thread.
+void RenderMessageFilter::DoOnClipboardIsFormatAvailable(
+ Clipboard::FormatType format, Clipboard::Buffer buffer,
+ IPC::Message* reply_msg) {
+ const bool result = GetClipboard()->IsFormatAvailable(format, buffer);
+
+ ViewHostMsg_ClipboardIsFormatAvailable::WriteReplyParams(reply_msg, result);
+ Send(reply_msg);
+}
+
+// Called on the UI thread.
+void RenderMessageFilter::DoOnClipboardReadText(Clipboard::Buffer buffer,
+ IPC::Message* reply_msg) {
+ string16 result;
+ GetClipboard()->ReadText(buffer, &result);
+
+ ViewHostMsg_ClipboardReadText::WriteReplyParams(reply_msg, result);
+ Send(reply_msg);
+}
+
+// Called on the UI thread.
+void RenderMessageFilter::DoOnClipboardReadAsciiText(
+ Clipboard::Buffer buffer, IPC::Message* reply_msg) {
+ std::string result;
+ GetClipboard()->ReadAsciiText(buffer, &result);
+
+ ViewHostMsg_ClipboardReadAsciiText::WriteReplyParams(reply_msg, result);
+ Send(reply_msg);
+}
+
+// Called on the UI thread.
+void RenderMessageFilter::DoOnClipboardReadHTML(Clipboard::Buffer buffer,
+ IPC::Message* reply_msg) {
+ std::string src_url_str;
+ string16 markup;
+ GetClipboard()->ReadHTML(buffer, &markup, &src_url_str);
+ const GURL src_url = GURL(src_url_str);
+
+ ViewHostMsg_ClipboardReadHTML::WriteReplyParams(reply_msg, markup, src_url);
+ Send(reply_msg);
+}
+
+// Called on the UI thread.
+void RenderMessageFilter::DoOnClipboardReadAvailableTypes(
+ Clipboard::Buffer buffer, IPC::Message* reply_msg) {
+ Send(reply_msg);
+}
+
+// Called on the UI thread.
+void RenderMessageFilter::DoOnClipboardReadData(Clipboard::Buffer buffer,
+ const string16& type,
+ IPC::Message* reply_msg) {
+ Send(reply_msg);
+}
+// Called on the UI thread.
+void RenderMessageFilter::DoOnClipboardReadFilenames(
+ Clipboard::Buffer buffer, IPC::Message* reply_msg) {
+ Send(reply_msg);
+}
+
+// Called on the FILE thread.
+void RenderMessageFilter::DoOnAllocateTempFileForPrinting(
+ IPC::Message* reply_msg) {
+ base::FileDescriptor temp_file_fd;
+ int fd_in_browser;
+ temp_file_fd.fd = fd_in_browser = -1;
+ temp_file_fd.auto_close = false;
+
+ bool allow_print =
+#if defined(TOOLKIT_GTK)
+ !PrintDialogGtk::DialogShowing();
+#else
+ true;
+#endif
+ FilePath path;
+ if (allow_print &&
+ file_util::CreateTemporaryFile(&path)) {
+ int fd = open(path.value().c_str(), O_WRONLY);
+ if (fd >= 0) {
+ FdMap* map = &g_printing_file_descriptor_map.Get().map;
+ FdMap::iterator it = map->find(fd);
+ if (it != map->end()) {
+ NOTREACHED() << "The file descriptor is in use. fd=" << fd;
+ } else {
+ (*map)[fd] = path;
+ temp_file_fd.fd = fd_in_browser = fd;
+ temp_file_fd.auto_close = true;
+ }
+ }
+ }
+
+ ViewHostMsg_AllocateTempFileForPrinting::WriteReplyParams(
+ reply_msg, temp_file_fd, fd_in_browser);
+ Send(reply_msg);
+}
+
+// Called on the IO thread.
+void RenderMessageFilter::OnGetScreenInfo(gfx::NativeViewId view,
+ IPC::Message* reply_msg) {
+ BrowserThread::PostTask(
+ BrowserThread::BACKGROUND_X11, FROM_HERE,
+ NewRunnableMethod(
+ this, &RenderMessageFilter::DoOnGetScreenInfo, view, reply_msg));
+}
+
+// Called on the IO thread.
+void RenderMessageFilter::OnGetWindowRect(gfx::NativeViewId view,
+ IPC::Message* reply_msg) {
+ BrowserThread::PostTask(
+ BrowserThread::BACKGROUND_X11, FROM_HERE,
+ NewRunnableMethod(
+ this, &RenderMessageFilter::DoOnGetWindowRect, view, reply_msg));
+}
+
+// Called on the IO thread.
+void RenderMessageFilter::OnGetRootWindowRect(gfx::NativeViewId view,
+ IPC::Message* reply_msg) {
+ BrowserThread::PostTask(
+ BrowserThread::BACKGROUND_X11, FROM_HERE,
+ NewRunnableMethod(
+ this, &RenderMessageFilter::DoOnGetRootWindowRect, view, reply_msg));
+}
+
+// Called on the IO thread.
+void RenderMessageFilter::OnClipboardIsFormatAvailable(
+ Clipboard::FormatType format, Clipboard::Buffer buffer,
+ IPC::Message* reply_msg) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ this, &RenderMessageFilter::DoOnClipboardIsFormatAvailable, format,
+ buffer, reply_msg));
+}
+
+// Called on the IO thread.
+void RenderMessageFilter::OnClipboardReadText(Clipboard::Buffer buffer,
+ IPC::Message* reply_msg) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ this, &RenderMessageFilter::DoOnClipboardReadText, buffer,
+ reply_msg));
+}
+
+// Called on the IO thread.
+void RenderMessageFilter::OnClipboardReadAsciiText(Clipboard::Buffer buffer,
+ IPC::Message* reply_msg) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ this, &RenderMessageFilter::DoOnClipboardReadAsciiText, buffer,
+ reply_msg));
+}
+
+// Called on the IO thread.
+void RenderMessageFilter::OnClipboardReadHTML(Clipboard::Buffer buffer,
+ IPC::Message* reply_msg) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ this, &RenderMessageFilter::DoOnClipboardReadHTML, buffer,
+ reply_msg));
+}
+
+// Called on the IO thread.
+void RenderMessageFilter::OnClipboardReadAvailableTypes(
+ Clipboard::Buffer buffer, IPC::Message* reply_msg) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ this, &RenderMessageFilter::DoOnClipboardReadAvailableTypes, buffer,
+ reply_msg));
+}
+
+// Called on the IO thread.
+void RenderMessageFilter::OnClipboardReadData(
+ Clipboard::Buffer buffer, const string16& type, IPC::Message* reply_msg) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ this, &RenderMessageFilter::DoOnClipboardReadData, buffer, type,
+ reply_msg));
+}
+
+// Called on the IO thread.
+void RenderMessageFilter::OnClipboardReadFilenames(
+ Clipboard::Buffer buffer, IPC::Message* reply_msg) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ this, &RenderMessageFilter::DoOnClipboardReadFilenames, buffer,
+ reply_msg));
+}
+
+// Called on the IO thread.
+void RenderMessageFilter::OnAllocateTempFileForPrinting(
+ IPC::Message* reply_msg) {
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ NewRunnableMethod(
+ this, &RenderMessageFilter::DoOnAllocateTempFileForPrinting,
+ reply_msg));
+}
+
+// Called on the IO thread.
+void RenderMessageFilter::OnTempFileForPrintingWritten(int fd_in_browser) {
+ FdMap* map = &g_printing_file_descriptor_map.Get().map;
+ FdMap::iterator it = map->find(fd_in_browser);
+ if (it == map->end()) {
+ NOTREACHED() << "Got a file descriptor that we didn't pass to the "
+ "renderer: " << fd_in_browser;
+ return;
+ }
+
+#if defined(TOOLKIT_GTK)
+ PrintDialogGtk::CreatePrintDialogForPdf(it->second);
+#else
+ if (cloud_print_enabled_)
+ PrintDialogCloud::CreatePrintDialogForPdf(it->second);
+ else
+ NOTIMPLEMENTED();
+#endif
+
+ // Erase the entry in the map.
+ map->erase(it);
+}
diff --git a/chrome/browser/renderer_host/render_message_filter_mac.mm b/chrome/browser/renderer_host/render_message_filter_mac.mm
new file mode 100644
index 0000000..dd80f2e
--- /dev/null
+++ b/chrome/browser/renderer_host/render_message_filter_mac.mm
@@ -0,0 +1,43 @@
+// Copyright (c) 2006-2009 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 "chrome/browser/renderer_host/render_message_filter.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/message_loop.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/browser_thread.h"
+#import "chrome/browser/ui/cocoa/find_pasteboard.h"
+
+// The number of utf16 code units that will be written to the find pasteboard,
+// longer texts are silently ignored. This is to prevent that a compromised
+// renderer can write unlimited amounts of data into the find pasteboard.
+static const size_t kMaxFindPboardStringLength = 4096;
+
+class WriteFindPboardTask : public Task {
+ public:
+ explicit WriteFindPboardTask(NSString* text)
+ : text_([text retain]) {}
+
+ void Run() {
+ [[FindPasteboard sharedInstance] setFindText:text_];
+ }
+
+ private:
+ scoped_nsobject<NSString> text_;
+};
+
+// Called on the IO thread.
+void RenderMessageFilter::OnClipboardFindPboardWriteString(
+ const string16& text) {
+ if (text.length() <= kMaxFindPboardStringLength) {
+ NSString* nsText = base::SysUTF16ToNSString(text);
+ if (nsText) {
+ // FindPasteboard must be used on the UI thread.
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE, new WriteFindPboardTask(nsText));
+ }
+ }
+}
diff --git a/chrome/browser/renderer_host/render_message_filter_win.cc b/chrome/browser/renderer_host/render_message_filter_win.cc
new file mode 100644
index 0000000..6bcd0c6
--- /dev/null
+++ b/chrome/browser/renderer_host/render_message_filter_win.cc
@@ -0,0 +1,48 @@
+// Copyright (c) 2006-2009 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 "chrome/browser/renderer_host/render_message_filter.h"
+#include "chrome/common/render_messages.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebScreenInfo.h"
+#include "third_party/WebKit/WebKit/chromium/public/win/WebScreenInfoFactory.h"
+
+using WebKit::WebScreenInfo;
+using WebKit::WebScreenInfoFactory;
+
+// We get null window_ids passed into the two functions below; please see
+// http://crbug.com/9060 for more details.
+
+// TODO(shess): Provide a mapping from reply_msg->routing_id() to HWND
+// so that we can eliminate the NativeViewId parameter.
+
+void RenderMessageFilter::OnGetWindowRect(gfx::NativeViewId window_id,
+ IPC::Message* reply_msg) {
+ HWND window = gfx::NativeViewFromId(window_id);
+ RECT window_rect = {0};
+ GetWindowRect(window, &window_rect);
+ gfx::Rect rect(window_rect);
+
+ ViewHostMsg_GetWindowRect::WriteReplyParams(reply_msg, rect);
+ Send(reply_msg);
+}
+
+void RenderMessageFilter::OnGetRootWindowRect(gfx::NativeViewId window_id,
+ IPC::Message* reply_msg) {
+ HWND window = gfx::NativeViewFromId(window_id);
+ RECT window_rect = {0};
+ HWND root_window = ::GetAncestor(window, GA_ROOT);
+ GetWindowRect(root_window, &window_rect);
+ gfx::Rect rect(window_rect);
+
+ ViewHostMsg_GetRootWindowRect::WriteReplyParams(reply_msg, rect);
+ Send(reply_msg);
+}
+
+void RenderMessageFilter::OnGetScreenInfo(gfx::NativeViewId view,
+ IPC::Message* reply_msg) {
+ WebScreenInfo results =
+ WebScreenInfoFactory::screenInfo(gfx::NativeViewFromId(view));
+ ViewHostMsg_GetScreenInfo::WriteReplyParams(reply_msg, results);
+ Send(reply_msg);
+}
diff --git a/chrome/browser/renderer_host/render_process_host.h b/chrome/browser/renderer_host/render_process_host.h
index a5fd378..1e8523b 100644
--- a/chrome/browser/renderer_host/render_process_host.h
+++ b/chrome/browser/renderer_host/render_process_host.h
@@ -11,6 +11,7 @@
#include "app/surface/transport_dib.h"
#include "base/id_map.h"
#include "base/process.h"
+#include "base/process_util.h"
#include "base/scoped_ptr.h"
#include "base/time.h"
#include "chrome/common/visitedlink_common.h"
@@ -48,11 +49,15 @@ class RenderProcessHost : public IPC::Channel::Sender,
// Details for RENDERER_PROCESS_CLOSED notifications.
struct RendererClosedDetails {
- RendererClosedDetails(bool did_crash, bool was_extension_renderer) {
- this->did_crash = did_crash;
+ RendererClosedDetails(base::TerminationStatus status,
+ int exit_code,
+ bool was_extension_renderer) {
+ this->status = status;
+ this->exit_code = exit_code;
this->was_extension_renderer = was_extension_renderer;
}
- bool did_crash;
+ base::TerminationStatus status;
+ int exit_code;
bool was_extension_renderer;
};
@@ -173,7 +178,7 @@ class RenderProcessHost : public IPC::Channel::Sender,
IPC::Message* msg) = 0;
// Called when a received message cannot be decoded.
- virtual void ReceivedBadMessage(uint32 msg_type) = 0;
+ virtual void ReceivedBadMessage() = 0;
// Track the count of visible widgets. Called by listeners to register and
// unregister visibility.
diff --git a/chrome/browser/renderer_host/render_sandbox_host_linux.cc b/chrome/browser/renderer_host/render_sandbox_host_linux.cc
index 92105b4..8f265b1 100644
--- a/chrome/browser/renderer_host/render_sandbox_host_linux.cc
+++ b/chrome/browser/renderer_host/render_sandbox_host_linux.cc
@@ -23,16 +23,16 @@
#include "base/process_util.h"
#include "base/scoped_ptr.h"
#include "base/shared_memory.h"
+#include "base/singleton.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
-#include "base/unix_domain_socket_posix.h"
+#include "chrome/common/font_config_ipc_linux.h"
#include "chrome/common/sandbox_methods_linux.h"
+#include "chrome/common/unix_domain_socket_posix.h"
+#include "skia/ext/SkFontHost_fontconfig_direct.h"
#include "third_party/npapi/bindings/npapi_extensions.h"
#include "third_party/WebKit/WebKit/chromium/public/gtk/WebFontInfo.h"
-#include "SkFontHost_fontconfig_direct.h"
-#include "SkFontHost_fontconfig_ipc.h"
-
using WebKit::WebCString;
using WebKit::WebFontInfo;
using WebKit::WebUChar;
@@ -113,7 +113,7 @@ class SandboxIPCProcess {
// error for a maximum length message.
char buf[FontConfigInterface::kMaxFontFamilyLength + 128];
- const ssize_t len = base::RecvMsg(fd, buf, sizeof(buf), &fds);
+ const ssize_t len = UnixDomainSocket::RecvMsg(fd, buf, sizeof(buf), &fds);
if (len == -1) {
// TODO: should send an error reply, or the sender might block forever.
NOTREACHED()
@@ -643,6 +643,11 @@ RenderSandboxHostLinux::RenderSandboxHostLinux()
pid_(0) {
}
+// static
+RenderSandboxHostLinux* RenderSandboxHostLinux::GetInstance() {
+ return Singleton<RenderSandboxHostLinux>::get();
+}
+
void RenderSandboxHostLinux::Init(const std::string& sandbox_path) {
DCHECK(!initialized_);
initialized_ = true;
diff --git a/chrome/browser/renderer_host/render_sandbox_host_linux.h b/chrome/browser/renderer_host/render_sandbox_host_linux.h
index b0122e8..2cb0604 100644
--- a/chrome/browser/renderer_host/render_sandbox_host_linux.h
+++ b/chrome/browser/renderer_host/render_sandbox_host_linux.h
@@ -11,12 +11,16 @@
#include <string>
#include "base/logging.h"
-#include "base/singleton.h"
+
+template <typename T> struct DefaultSingletonTraits;
// This is a singleton object which handles sandbox requests from the
// renderers.
class RenderSandboxHostLinux {
public:
+ // Returns the singleton instance.
+ static RenderSandboxHostLinux* GetInstance();
+
// Get the file descriptor which renderers should be given in order to signal
// crashes to the browser.
int GetRendererSocket() const {
diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc
index b8a9c1e..950c60e 100644
--- a/chrome/browser/renderer_host/render_view_host.cc
+++ b/chrome/browser/renderer_host/render_view_host.cc
@@ -14,6 +14,7 @@
#include "base/metrics/stats_counters.h"
#include "base/string_util.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
@@ -24,12 +25,13 @@
#include "chrome/browser/dom_operation_notification_details.h"
#include "chrome/browser/extensions/extension_message_service.h"
#include "chrome/browser/in_process_webkit/session_storage_namespace.h"
+#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/net/predictor_api.h"
#include "chrome/browser/notifications/desktop_notification_service.h"
#include "chrome/browser/printing/printer_query.h"
#include "chrome/browser/printing/print_job_manager.h"
#include "chrome/browser/printing/print_preview_tab_controller.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
@@ -52,6 +54,7 @@
#include "chrome/common/web_apps.h"
#include "gfx/native_widget_types.h"
#include "net/base/net_util.h"
+#include "printing/native_metafile.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/WebKit/WebKit/chromium/public/WebFindOptions.h"
#include "webkit/glue/context_menu.h"
@@ -139,7 +142,8 @@ RenderViewHost::RenderViewHost(SiteInstance* instance,
session_storage_namespace_(session_storage),
is_extension_process_(false),
autofill_query_id_(0),
- save_accessibility_tree_for_testing_(false) {
+ save_accessibility_tree_for_testing_(false),
+ render_view_termination_status_(base::TERMINATION_STATUS_STILL_RUNNING) {
if (!session_storage_namespace_) {
session_storage_namespace_ =
new SessionStorageNamespace(process()->profile());
@@ -153,7 +157,7 @@ RenderViewHost::~RenderViewHost() {
delegate()->RenderViewDeleted(this);
// Be sure to clean up any leftover state from cross-site requests.
- Singleton<CrossSiteRequestManager>()->SetHasPendingCrossSiteRequest(
+ CrossSiteRequestManager::GetInstance()->SetHasPendingCrossSiteRequest(
process()->id(), routing_id(), false);
}
@@ -368,7 +372,7 @@ void RenderViewHost::ClosePageIgnoringUnloadEvents() {
void RenderViewHost::SetHasPendingCrossSiteRequest(bool has_pending_request,
int request_id) {
- Singleton<CrossSiteRequestManager>()->SetHasPendingCrossSiteRequest(
+ CrossSiteRequestManager::GetInstance()->SetHasPendingCrossSiteRequest(
process()->id(), routing_id(), has_pending_request);
pending_request_id_ = request_id;
}
@@ -693,6 +697,10 @@ void RenderViewHost::ClearFocusedNode() {
Send(new ViewMsg_ClearFocusedNode(routing_id()));
}
+void RenderViewHost::ScrollFocusedEditableNodeIntoView() {
+ Send(new ViewMsg_ScrollFocusedEditableNodeIntoView(routing_id()));
+}
+
void RenderViewHost::UpdateWebPreferences(const WebPreferences& prefs) {
Send(new ViewMsg_UpdateWebPreferences(routing_id(), prefs));
}
@@ -730,7 +738,7 @@ bool RenderViewHost::SuddenTerminationAllowed() const {
///////////////////////////////////////////////////////////////////////////////
// RenderViewHost, IPC message handlers:
-void RenderViewHost::OnMessageReceived(const IPC::Message& msg) {
+bool RenderViewHost::OnMessageReceived(const IPC::Message& msg) {
#if defined(OS_WIN)
// On Windows there's a potential deadlock with sync messsages going in
// a circle from browser -> plugin -> renderer -> browser.
@@ -748,10 +756,11 @@ void RenderViewHost::OnMessageReceived(const IPC::Message& msg) {
IPC::Message* reply = IPC::SyncMessage::GenerateReply(&msg);
reply->set_reply_error();
Send(reply);
- return;
+ return true;
}
#endif
+ bool handled = true;
bool msg_is_ok = true;
IPC_BEGIN_MESSAGE_MAP_EX(RenderViewHost, msg, msg_is_ok)
IPC_MESSAGE_HANDLER(ViewHostMsg_ShowView, OnMsgShowView)
@@ -774,6 +783,8 @@ void RenderViewHost::OnMessageReceived(const IPC::Message& msg) {
IPC_MESSAGE_HANDLER(ViewHostMsg_RequestMove, OnMsgRequestMove)
IPC_MESSAGE_HANDLER(ViewHostMsg_DidStartLoading, OnMsgDidStartLoading)
IPC_MESSAGE_HANDLER(ViewHostMsg_DidStopLoading, OnMsgDidStopLoading)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DidChangeLoadProgress,
+ OnMsgDidChangeLoadProgress)
IPC_MESSAGE_HANDLER(ViewHostMsg_DocumentAvailableInMainFrame,
OnMsgDocumentAvailableInMainFrame)
IPC_MESSAGE_HANDLER(ViewHostMsg_DocumentOnLoadCompletedInMainFrame,
@@ -848,8 +859,8 @@ void RenderViewHost::OnMessageReceived(const IPC::Message& msg) {
OnDevToolsRuntimePropertyChanged);
IPC_MESSAGE_HANDLER(ViewHostMsg_MissingPluginStatus, OnMissingPluginStatus);
IPC_MESSAGE_HANDLER(ViewHostMsg_CrashedPlugin, OnCrashedPlugin);
- IPC_MESSAGE_HANDLER(ViewHostMsg_DisabledOutdatedPlugin,
- OnDisabledOutdatedPlugin);
+ IPC_MESSAGE_HANDLER(ViewHostMsg_BlockedOutdatedPlugin,
+ OnBlockedOutdatedPlugin);
IPC_MESSAGE_HANDLER(ViewHostMsg_SendCurrentPageAllSavableResourceLinks,
OnReceivedSavableResourceLinksForCurrentPage);
IPC_MESSAGE_HANDLER(ViewHostMsg_SendSerializedHtmlData,
@@ -907,14 +918,17 @@ void RenderViewHost::OnMessageReceived(const IPC::Message& msg) {
IPC_MESSAGE_HANDLER(ViewHostMsg_PagesReadyForPreview,
OnPagesReadyForPreview)
// Have the super handle all other messages.
- IPC_MESSAGE_UNHANDLED(RenderWidgetHost::OnMessageReceived(msg))
+ IPC_MESSAGE_UNHANDLED(handled = RenderWidgetHost::OnMessageReceived(msg))
IPC_END_MESSAGE_MAP_EX()
if (!msg_is_ok) {
// The message had a handler, but its de-serialization failed.
// Kill the renderer.
- process()->ReceivedBadMessage(msg.type());
+ UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_RVH"));
+ process()->ReceivedBadMessage();
}
+
+ return handled;
}
void RenderViewHost::Shutdown() {
@@ -931,6 +945,10 @@ void RenderViewHost::Shutdown() {
RenderWidgetHost::Shutdown();
}
+bool RenderViewHost::IsRenderView() const {
+ return true;
+}
+
void RenderViewHost::CreateNewWindow(
int route_id,
WindowContainerType window_container_type,
@@ -993,15 +1011,23 @@ void RenderViewHost::OnMsgRunModal(IPC::Message* reply_msg) {
}
void RenderViewHost::OnMsgRenderViewReady() {
+ render_view_termination_status_ = base::TERMINATION_STATUS_STILL_RUNNING;
WasResized();
delegate_->RenderViewReady(this);
}
-void RenderViewHost::OnMsgRenderViewGone() {
+void RenderViewHost::OnMsgRenderViewGone(int status, int exit_code) {
+ // Keep the termination status so we can get at it later when we
+ // need to know why it died.
+ render_view_termination_status_ =
+ static_cast<base::TerminationStatus>(status);
+
// Our base class RenderWidgetHost needs to reset some stuff.
- RendererExited();
+ RendererExited(render_view_termination_status_, exit_code);
- delegate_->RenderViewGone(this);
+ delegate_->RenderViewGone(this,
+ static_cast<base::TerminationStatus>(status),
+ exit_code);
}
// Called when the renderer navigates. For every frame loaded, we'll get this
@@ -1148,6 +1174,10 @@ void RenderViewHost::OnMsgDidStopLoading() {
delegate_->DidStopLoading();
}
+void RenderViewHost::OnMsgDidChangeLoadProgress(double load_progress) {
+ delegate_->DidChangeLoadProgress(load_progress);
+}
+
void RenderViewHost::OnMsgDocumentAvailableInMainFrame() {
delegate_->DocumentAvailableInMainFrame(this);
}
@@ -1187,9 +1217,10 @@ void RenderViewHost::OnMsgDidRunInsecureContent(
resource_delegate->DidRunInsecureContent(security_origin);
}
-void RenderViewHost::OnMsgDidStartProvisionalLoadForFrame(long long frame_id,
+void RenderViewHost::OnMsgDidStartProvisionalLoadForFrame(int64 frame_id,
bool is_main_frame,
const GURL& url) {
+ bool is_error_page = (url.spec() == chrome::kUnreachableWebDataURL);
GURL validated_url(url);
FilterURL(ChildProcessSecurityPolicy::GetInstance(),
process()->id(), &validated_url);
@@ -1198,12 +1229,12 @@ void RenderViewHost::OnMsgDidStartProvisionalLoadForFrame(long long frame_id,
delegate_->GetResourceDelegate();
if (resource_delegate) {
resource_delegate->DidStartProvisionalLoadForFrame(
- this, frame_id, is_main_frame, validated_url);
+ this, frame_id, is_main_frame, is_error_page, validated_url);
}
}
void RenderViewHost::OnMsgDidFailProvisionalLoadWithError(
- long long frame_id,
+ int64 frame_id,
bool is_main_frame,
int error_code,
const GURL& url,
@@ -1365,14 +1396,14 @@ void RenderViewHost::OnMsgForwardMessageToExternalHost(
delegate_->ProcessExternalHostMessage(message, origin, target);
}
-void RenderViewHost::OnMsgDocumentLoadedInFrame(long long frame_id) {
+void RenderViewHost::OnMsgDocumentLoadedInFrame(int64 frame_id) {
RenderViewHostDelegate::Resource* resource_delegate =
delegate_->GetResourceDelegate();
if (resource_delegate)
resource_delegate->DocumentLoadedInFrame(frame_id);
}
-void RenderViewHost::OnMsgDidFinishLoad(long long frame_id) {
+void RenderViewHost::OnMsgDidFinishLoad(int64 frame_id) {
RenderViewHostDelegate::Resource* resource_delegate =
delegate_->GetResourceDelegate();
if (resource_delegate)
@@ -1624,12 +1655,12 @@ void RenderViewHost::OnCrashedPlugin(const FilePath& plugin_path) {
integration_delegate->OnCrashedPlugin(plugin_path);
}
-void RenderViewHost::OnDisabledOutdatedPlugin(const string16& name,
+void RenderViewHost::OnBlockedOutdatedPlugin(const string16& name,
const GURL& update_url) {
RenderViewHostDelegate::BrowserIntegration* integration_delegate =
delegate_->GetBrowserIntegrationDelegate();
if (integration_delegate)
- integration_delegate->OnDisabledOutdatedPlugin(name, update_url);
+ integration_delegate->OnBlockedOutdatedPlugin(name, update_url);
}
void RenderViewHost::GetAllSavableResourceLinksForCurrentPage(
@@ -1843,21 +1874,7 @@ void RenderViewHost::NotifyRendererResponsive() {
}
void RenderViewHost::OnMsgFocusedNodeChanged(bool is_editable_node) {
- delegate_->FocusedNodeChanged();
-
-#if defined(TOUCH_UI)
- if (is_editable_node) {
- // Need to summon on-screen keyboard
- // TODO(bryeung): implement this
-
- // The currently focused element can be placed out of the view as the screen
- // is now shared by the keyboard. Hence, we tell the renderer to scroll
- // until the focused element comes in view.
- Send(new ViewMsg_ScrollFocusedEditableNodeIntoView(routing_id()));
- } else {
- // TODO(bryeung): implement this. Should hide the on-screen keyboard.
- }
-#endif
+ delegate_->FocusedNodeChanged(is_editable_node);
}
void RenderViewHost::OnMsgFocus() {
@@ -2013,6 +2030,15 @@ void RenderViewHost::TranslatePage(int page_id,
const std::string& translate_script,
const std::string& source_lang,
const std::string& target_lang) {
+ // Ideally we'd have a better way to uniquely identify form control elements,
+ // but we don't have that yet. So before start translation, we clear the
+ // current form and re-parse it in AutoFillManager first to get the new
+ // labels.
+ RenderViewHostDelegate::AutoFill* autofill_delegate =
+ delegate_->GetAutoFillDelegate();
+ if (autofill_delegate)
+ autofill_delegate->Reset();
+
Send(new ViewMsg_TranslatePage(routing_id(), page_id, translate_script,
source_lang, target_lang));
}
@@ -2194,9 +2220,10 @@ void RenderViewHost::OnDetectedPhishingSite(const GURL& phishing_url,
// to confirm that the URL is really phishing.
}
-void RenderViewHost::OnScriptEvalResponse(int id, bool result) {
- scoped_ptr<Value> result_value(Value::CreateBooleanValue(result));
- std::pair<int, Value*> details(id, result_value.get());
+void RenderViewHost::OnScriptEvalResponse(int id, const ListValue& result) {
+ Value* result_value;
+ result.Get(0, &result_value);
+ std::pair<int, Value*> details(id, result_value);
NotificationService::current()->Notify(
NotificationType::EXECUTE_JAVASCRIPT_RESULT,
Source<RenderViewHost>(this),
@@ -2235,25 +2262,38 @@ TabContents* RenderViewHost::GetOrCreatePrintPreviewTab() {
return NULL;
}
-void RenderViewHost::OnPagesReadyForPreview(int document_cookie,
- int fd_in_browser) {
+void RenderViewHost::OnPagesReadyForPreview(
+ const ViewHostMsg_DidPreviewDocument_Params& params) {
+#if defined(OS_MACOSX)
+ base::SharedMemory shared_buf(params.metafile_data_handle, true);
+ if (!shared_buf.Map(params.data_size)) {
+ NOTREACHED();
+ return;
+ }
+ scoped_ptr<printing::NativeMetafile> metafile(new printing::NativeMetafile());
+ if (!metafile->Init(shared_buf.memory(), params.data_size)) {
+ NOTREACHED();
+ return;
+ }
+
+ // TODO(kmadhusu): Add more functionality for the preview tab to access this
+ // |metafile| data.
+#endif
+
// Get/Create print preview tab.
TabContents* print_preview_tab = GetOrCreatePrintPreviewTab();
DCHECK(print_preview_tab);
- // TODO(kmadhusu): Function definition needs to be changed.
- // fd_in_browser should be the file descriptor of the metafile.
-
scoped_refptr<printing::PrinterQuery> printer_query;
- g_browser_process->print_job_manager()->PopPrinterQuery(document_cookie,
- &printer_query);
+ g_browser_process->print_job_manager()->PopPrinterQuery(
+ params.document_cookie, &printer_query);
if (printer_query.get()) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(printer_query.get(),
- &printing::PrinterQuery::StopWorker));
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(printer_query.get(),
+ &printing::PrinterQuery::StopWorker));
}
// Send the printingDone msg for now.
- Send(new ViewMsg_PrintingDone(routing_id(), -1, true));
+ Send(new ViewMsg_PrintingDone(routing_id(), params.document_cookie, true));
}
diff --git a/chrome/browser/renderer_host/render_view_host.h b/chrome/browser/renderer_host/render_view_host.h
index 30566f0..02c08d1 100644
--- a/chrome/browser/renderer_host/render_view_host.h
+++ b/chrome/browser/renderer_host/render_view_host.h
@@ -9,9 +9,10 @@
#include <string>
#include <vector>
+#include "base/process_util.h"
#include "base/scoped_ptr.h"
-#include "chrome/browser/find_bar_controller.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
+#include "chrome/browser/ui/find_bar/find_bar_controller.h"
#include "chrome/common/content_settings_types.h"
#include "chrome/common/page_zoom.h"
#include "chrome/common/translate_errors.h"
@@ -38,6 +39,7 @@ struct ContextMenuParams;
struct MediaPlayerAction;
struct ThumbnailScore;
struct ViewHostMsg_AccessibilityNotification_Params;
+struct ViewHostMsg_DidPreviewDocument_Params;
struct ViewHostMsg_DidPrintPage_Params;
struct ViewHostMsg_DomMessage_Params;
struct ViewHostMsg_PageHasOSDD_Type;
@@ -116,6 +118,7 @@ class RenderViewHost : public RenderWidgetHost {
SiteInstance* site_instance() const { return instance_; }
RenderViewHostDelegate* delegate() const { return delegate_; }
+ void set_delegate(RenderViewHostDelegate* d) { delegate_ = d; }
// Set up the RenderView child process. Virtual because it is overridden by
// TestRenderViewHost. If the |frame_name| parameter is non-empty, it is used
@@ -126,6 +129,10 @@ class RenderViewHost : public RenderWidgetHost {
// because it is overridden by TestRenderViewHost.
virtual bool IsRenderViewLive() const;
+ base::TerminationStatus render_view_termination_status() const {
+ return render_view_termination_status_;
+ }
+
// Send the renderer process the current preferences supplied by the
// RenderViewHostDelegate.
void SyncRendererPrefs();
@@ -360,6 +367,9 @@ class RenderViewHost : public RenderWidgetHost {
// Clears the node that is currently focused (if any).
void ClearFocusedNode();
+ // Tells the renderer view to scroll to the focused node.
+ void ScrollFocusedEditableNodeIntoView();
+
// Update render view specific (WebKit) preferences.
void UpdateWebPreferences(const WebPreferences& prefs);
@@ -435,8 +445,8 @@ class RenderViewHost : public RenderWidgetHost {
// RenderWidgetHost public overrides.
virtual void Shutdown();
- virtual bool IsRenderView() const { return true; }
- virtual void OnMessageReceived(const IPC::Message& msg);
+ virtual bool IsRenderView() const;
+ virtual bool OnMessageReceived(const IPC::Message& msg);
virtual void GotFocus();
virtual void LostCapture();
virtual void ForwardMouseEvent(const WebKit::WebMouseEvent& mouse_event);
@@ -549,7 +559,7 @@ class RenderViewHost : public RenderWidgetHost {
void OnMsgShowFullscreenWidget(int route_id);
void OnMsgRunModal(IPC::Message* reply_msg);
void OnMsgRenderViewReady();
- void OnMsgRenderViewGone();
+ void OnMsgRenderViewGone(int status, int error_code);
void OnMsgNavigate(const IPC::Message& msg);
void OnMsgUpdateState(int32 page_id,
const std::string& state);
@@ -567,6 +577,7 @@ class RenderViewHost : public RenderWidgetHost {
const GURL& target_url);
void OnMsgDidStartLoading();
void OnMsgDidStopLoading();
+ void OnMsgDidChangeLoadProgress(double load_progress);
void OnMsgDocumentAvailableInMainFrame();
void OnMsgDocumentOnLoadCompletedInMainFrame(int32 page_id);
void OnMsgDidLoadResourceFromMemoryCache(const GURL& url,
@@ -575,10 +586,10 @@ class RenderViewHost : public RenderWidgetHost {
const std::string& security_info);
void OnMsgDidDisplayInsecureContent();
void OnMsgDidRunInsecureContent(const std::string& security_origin);
- void OnMsgDidStartProvisionalLoadForFrame(long long frame_id,
+ void OnMsgDidStartProvisionalLoadForFrame(int64 frame_id,
bool main_frame,
const GURL& url);
- void OnMsgDidFailProvisionalLoadWithError(long long frame_id,
+ void OnMsgDidFailProvisionalLoadWithError(int64 frame_id,
bool main_frame,
int error_code,
const GURL& url,
@@ -606,8 +617,8 @@ class RenderViewHost : public RenderWidgetHost {
void OnMsgForwardMessageToExternalHost(const std::string& message,
const std::string& origin,
const std::string& target);
- void OnMsgDocumentLoadedInFrame(long long frame_id);
- void OnMsgDidFinishLoad(long long frame_id);
+ void OnMsgDocumentLoadedInFrame(int64 frame_id);
+ void OnMsgDidFinishLoad(int64 frame_id);
void OnMsgGoToEntryAtOffset(int offset);
void OnMsgSetTooltipText(const std::wstring& tooltip_text,
WebKit::WebTextDirection text_direction_hint);
@@ -658,7 +669,7 @@ class RenderViewHost : public RenderWidgetHost {
const std::string& value);
void OnMissingPluginStatus(int status);
void OnCrashedPlugin(const FilePath& plugin_path);
- void OnDisabledOutdatedPlugin(const string16& name, const GURL& update_url);
+ void OnBlockedOutdatedPlugin(const string16& name, const GURL& update_url);
void OnReceivedSavableResourceLinksForCurrentPage(
const std::vector<GURL>& resources_list,
@@ -721,9 +732,10 @@ class RenderViewHost : public RenderWidgetHost {
void OnDetectedPhishingSite(const GURL& phishing_url,
double phishing_score,
const SkBitmap& thumbnail);
- void OnScriptEvalResponse(int id, bool result);
+ void OnScriptEvalResponse(int id, const ListValue& result);
void OnUpdateContentRestrictions(int restrictions);
- void OnPagesReadyForPreview(int document_cookie, int fd_in_browser);
+ void OnPagesReadyForPreview(
+ const ViewHostMsg_DidPreviewDocument_Params& params);
#if defined(OS_MACOSX)
void OnMsgShowPopup(const ViewHostMsg_ShowPopup_Params& params);
@@ -818,6 +830,9 @@ class RenderViewHost : public RenderWidgetHost {
// The most recently received accessibility tree - for unit testing only.
webkit_glue::WebAccessibility accessibility_tree_;
+ // The termination status of the last render view that terminated.
+ base::TerminationStatus render_view_termination_status_;
+
DISALLOW_COPY_AND_ASSIGN(RenderViewHost);
};
diff --git a/chrome/browser/renderer_host/render_view_host_delegate.h b/chrome/browser/renderer_host/render_view_host_delegate.h
index 184a472..d769d05 100644
--- a/chrome/browser/renderer_host/render_view_host_delegate.h
+++ b/chrome/browser/renderer_host/render_view_host_delegate.h
@@ -10,6 +10,7 @@
#include <vector>
#include "base/basictypes.h"
+#include "base/process_util.h"
#include "base/ref_counted.h"
#include "base/string16.h"
#include "chrome/common/content_settings_types.h"
@@ -71,6 +72,7 @@ class Message;
}
namespace net {
+class CookieList;
class CookieOptions;
}
@@ -281,8 +283,8 @@ class RenderViewHostDelegate {
// Notification that a worker process has crashed.
virtual void OnCrashedWorker() = 0;
- virtual void OnDisabledOutdatedPlugin(const string16& name,
- const GURL& update_url) = 0;
+ virtual void OnBlockedOutdatedPlugin(const string16& name,
+ const GURL& update_url) = 0;
// Notification that a user's request to install an application has
// completed.
@@ -328,8 +330,9 @@ class RenderViewHostDelegate {
// The RenderView is starting a provisional load.
virtual void DidStartProvisionalLoadForFrame(
RenderViewHost* render_view_host,
- long long frame_id,
+ int64 frame_id,
bool is_main_frame,
+ bool is_error_page,
const GURL& url) = 0;
// Notification by the resource loading system (not the renderer) that it
@@ -368,17 +371,17 @@ class RenderViewHostDelegate {
// The RenderView failed a provisional load with an error.
virtual void DidFailProvisionalLoadWithError(
RenderViewHost* render_view_host,
- long long frame_id,
+ int64 frame_id,
bool is_main_frame,
int error_code,
const GURL& url,
bool showing_repost_interstitial) = 0;
// Notification that a document has been loaded in a frame.
- virtual void DocumentLoadedInFrame(long long frame_id) = 0;
+ virtual void DocumentLoadedInFrame(int64 frame_id) = 0;
// Notification that a frame finished loading.
- virtual void DidFinishLoad(long long frame_id) = 0;
+ virtual void DidFinishLoad(int64 frame_id) = 0;
protected:
virtual ~Resource() {}
@@ -394,14 +397,23 @@ class RenderViewHostDelegate {
virtual void OnContentBlocked(ContentSettingsType type,
const std::string& resource_identifier) = 0;
- // Called when a specific cookie in the current page was accessed.
+ // Called when cookies for the given URL were read either from within the
+ // current page or while loading it. |blocked_by_policy| should be true, if
+ // reading cookies was blocked due to the user's content settings. In that
+ // case, this function should invoke OnContentBlocked.
+ virtual void OnCookiesRead(
+ const GURL& url,
+ const net::CookieList& cookie_list,
+ bool blocked_by_policy) = 0;
+
+ // Called when a specific cookie in the current page was changed.
// |blocked_by_policy| should be true, if the cookie was blocked due to the
// user's content settings. In that case, this function should invoke
// OnContentBlocked.
- virtual void OnCookieAccessed(const GURL& url,
- const std::string& cookie_line,
- const net::CookieOptions& options,
- bool blocked_by_policy) = 0;
+ virtual void OnCookieChanged(const GURL& url,
+ const std::string& cookie_line,
+ const net::CookieOptions& options,
+ bool blocked_by_policy) = 0;
// Called when a specific indexed db factory in the current page was
// accessed. If access was blocked due to the user's content settings,
@@ -577,6 +589,9 @@ class RenderViewHostDelegate {
// AutoFill popup.
virtual void ShowAutoFillDialog() = 0;
+ // Reset cache in AutoFillManager.
+ virtual void Reset() = 0;
+
protected:
virtual ~AutoFill() {}
};
@@ -700,7 +715,9 @@ class RenderViewHostDelegate {
virtual void RenderViewReady(RenderViewHost* render_view_host) {}
// The RenderView died somehow (crashed or was killed by the user).
- virtual void RenderViewGone(RenderViewHost* render_view_host) {}
+ virtual void RenderViewGone(RenderViewHost* render_view_host,
+ base::TerminationStatus status,
+ int error_code) {}
// The RenderView is going to be deleted. This is called when each
// RenderView is going to be destroyed
@@ -752,6 +769,11 @@ class RenderViewHostDelegate {
// notion of the throbber stopping.
virtual void DidStopLoading() {}
+ // The RenderView made progress loading a page's top frame.
+ // |progress| is a value between 0 (nothing loaded) to 1.0 (top frame
+ // entirely loaded).
+ virtual void DidChangeLoadProgress(double progress) {}
+
// The RenderView's main frame document element is ready. This happens when
// the document has finished parsing.
virtual void DocumentAvailableInMainFrame(RenderViewHost* render_view_host) {}
@@ -854,7 +876,7 @@ class RenderViewHostDelegate {
virtual void DidInsertCSS() {}
// A different node in the page got focused.
- virtual void FocusedNodeChanged() {}
+ virtual void FocusedNodeChanged(bool is_editable_node) {}
// Updates the minimum and maximum zoom percentages.
virtual void UpdateZoomLimits(int minimum_percent,
diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc
index 863b9a8..28862af 100644
--- a/chrome/browser/renderer_host/render_widget_host.cc
+++ b/chrome/browser/renderer_host/render_widget_host.cc
@@ -10,7 +10,7 @@
#include "base/message_loop.h"
#include "base/metrics/histogram.h"
#include "chrome/browser/accessibility/browser_accessibility_state.h"
-#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/renderer_host/backing_store.h"
#include "chrome/browser/renderer_host/backing_store_manager.h"
#include "chrome/browser/renderer_host/render_process_host.h"
@@ -18,13 +18,14 @@
#include "chrome/browser/renderer_host/render_widget_host_painting_observer.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/result_codes.h"
#include "chrome/common/native_web_keyboard_event.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/render_messages_params.h"
#include "third_party/WebKit/WebKit/chromium/public/WebCompositionUnderline.h"
-#include "webkit/glue/plugins/webplugin.h"
#include "webkit/glue/webcursor.h"
+#include "webkit/plugins/npapi/webplugin.h"
#if defined(TOOLKIT_VIEWS)
#include "views/view.h"
@@ -101,7 +102,7 @@ RenderWidgetHost::RenderWidgetHost(RenderProcessHost* process,
if (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kForceRendererAccessibility) ||
- Singleton<BrowserAccessibilityState>()->IsAccessibleBrowser()) {
+ BrowserAccessibilityState::GetInstance()->IsAccessibleBrowser()) {
EnableRendererAccessibility();
}
}
@@ -119,6 +120,12 @@ gfx::NativeViewId RenderWidgetHost::GetNativeViewId() {
return 0;
}
+bool RenderWidgetHost::PreHandleKeyboardEvent(
+ const NativeWebKeyboardEvent& event,
+ bool* is_keyboard_shortcut) {
+ return false;
+}
+
void RenderWidgetHost::Init() {
DCHECK(process_->HasConnection());
@@ -140,7 +147,12 @@ void RenderWidgetHost::Shutdown() {
Destroy();
}
-void RenderWidgetHost::OnMessageReceived(const IPC::Message &msg) {
+bool RenderWidgetHost::IsRenderView() const {
+ return false;
+}
+
+bool RenderWidgetHost::OnMessageReceived(const IPC::Message &msg) {
+ bool handled = true;
bool msg_is_ok = true;
IPC_BEGIN_MESSAGE_MAP_EX(RenderWidgetHost, msg, msg_is_ok)
IPC_MESSAGE_HANDLER(ViewHostMsg_RenderViewReady, OnMsgRenderViewReady)
@@ -181,13 +193,15 @@ void RenderWidgetHost::OnMessageReceived(const IPC::Message &msg) {
IPC_MESSAGE_HANDLER(ViewHostMsg_DestroyPluginContainer,
OnMsgDestroyPluginContainer)
#endif
- IPC_MESSAGE_UNHANDLED_ERROR()
+ IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP_EX()
if (!msg_is_ok) {
// The message de-serialization failed. Kill the renderer process.
- process()->ReceivedBadMessage(msg.type());
+ UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_RWH"));
+ process()->ReceivedBadMessage();
}
+ return handled;
}
bool RenderWidgetHost::Send(IPC::Message* msg) {
@@ -382,8 +396,7 @@ BackingStore* RenderWidgetHost::GetBackingStore(bool force_create) {
IPC::Message msg;
TimeDelta max_delay = TimeDelta::FromMilliseconds(kPaintMsgTimeoutMS);
if (process_->WaitForUpdateMsg(routing_id_, max_delay, &msg)) {
- ViewHostMsg_UpdateRect::Dispatch(
- &msg, this, &RenderWidgetHost::OnMsgUpdateRect);
+ OnMessageReceived(msg);
backing_store = BackingStoreManager::GetBackingStore(this, current_size_);
}
}
@@ -418,10 +431,8 @@ void RenderWidgetHost::ScheduleComposite() {
// We always block on response because we do not have a backing store.
IPC::Message msg;
TimeDelta max_delay = TimeDelta::FromMilliseconds(kPaintMsgTimeoutMS);
- if (process_->WaitForUpdateMsg(routing_id_, max_delay, &msg)) {
- ViewHostMsg_UpdateRect::Dispatch(
- &msg, this, &RenderWidgetHost::OnMsgUpdateRect);
- }
+ if (process_->WaitForUpdateMsg(routing_id_, max_delay, &msg))
+ OnMessageReceived(msg);
}
void RenderWidgetHost::StartHangMonitorTimeout(TimeDelta delay) {
@@ -634,7 +645,8 @@ void RenderWidgetHost::ForwardTouchEvent(
}
#endif
-void RenderWidgetHost::RendererExited() {
+void RenderWidgetHost::RendererExited(base::TerminationStatus status,
+ int exit_code) {
// Clearing this flag causes us to re-create the renderer when recovering
// from a crashed renderer.
renderer_initialized_ = false;
@@ -662,7 +674,7 @@ void RenderWidgetHost::RendererExited() {
is_accelerated_compositing_active_ = false;
if (view_) {
- view_->RenderViewGone();
+ view_->RenderViewGone(status, exit_code);
view_ = NULL; // The View should be deleted by RenderViewGone.
}
@@ -768,7 +780,7 @@ void RenderWidgetHost::OnMsgRenderViewReady() {
WasResized();
}
-void RenderWidgetHost::OnMsgRenderViewGone() {
+void RenderWidgetHost::OnMsgRenderViewGone(int status, int exit_code) {
// TODO(evanm): This synchronously ends up calling "delete this".
// Is that really what we want in response to this message? I'm matching
// previous behavior of the code here.
@@ -843,7 +855,9 @@ void RenderWidgetHost::OnMsgUpdateRect(
if (dib) {
if (dib->size() < size) {
DLOG(WARNING) << "Transport DIB too small for given rectangle";
- process()->ReceivedBadMessage(ViewHostMsg_UpdateRect__ID);
+ UserMetrics::RecordAction(UserMetricsAction(
+ "BadMessageTerminate_RWH1"));
+ process()->ReceivedBadMessage();
} else {
// Scroll the backing store.
if (!params.scroll_rect.IsEmpty()) {
@@ -917,7 +931,8 @@ void RenderWidgetHost::OnMsgInputEventAck(const IPC::Message& message) {
void* iter = NULL;
int type = 0;
if (!message.ReadInt(&iter, &type) || (type < WebInputEvent::Undefined)) {
- process()->ReceivedBadMessage(message.type());
+ UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_RWH2"));
+ process()->ReceivedBadMessage();
} else if (type == WebInputEvent::MouseMove) {
mouse_move_pending_ = false;
@@ -930,8 +945,10 @@ void RenderWidgetHost::OnMsgInputEventAck(const IPC::Message& message) {
ProcessWheelAck();
} else if (WebInputEvent::isKeyboardEventType(type)) {
bool processed = false;
- if (!message.ReadBool(&iter, &processed))
- process()->ReceivedBadMessage(message.type());
+ if (!message.ReadBool(&iter, &processed)) {
+ UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_RWH3"));
+ process()->ReceivedBadMessage();
+ }
ProcessKeyboardEventAck(type, processed);
}
@@ -951,12 +968,14 @@ void RenderWidgetHost::ProcessWheelAck() {
void RenderWidgetHost::OnMsgFocus() {
// Only RenderViewHost can deal with that message.
- process()->ReceivedBadMessage(ViewHostMsg_Focus__ID);
+ UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_RWH4"));
+ process()->ReceivedBadMessage();
}
void RenderWidgetHost::OnMsgBlur() {
// Only RenderViewHost can deal with that message.
- process()->ReceivedBadMessage(ViewHostMsg_Blur__ID);
+ UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_RWH5"));
+ process()->ReceivedBadMessage();
}
void RenderWidgetHost::OnMsgSetCursor(const WebCursor& cursor) {
@@ -1083,7 +1102,7 @@ void RenderWidgetHost::OnMsgCreatePluginContainer(gfx::PluginWindowHandle id) {
if (view_) {
view_->CreatePluginContainer(id);
} else {
- NOTIMPLEMENTED();
+ deferred_plugin_handles_.push_back(id);
}
}
@@ -1091,7 +1110,14 @@ void RenderWidgetHost::OnMsgDestroyPluginContainer(gfx::PluginWindowHandle id) {
if (view_) {
view_->DestroyPluginContainer(id);
} else {
- NOTIMPLEMENTED();
+ for (int i = 0;
+ i < static_cast<int>(deferred_plugin_handles_.size());
+ i++) {
+ if (deferred_plugin_handles_[i] == id) {
+ deferred_plugin_handles_.erase(deferred_plugin_handles_.begin() + i);
+ i--;
+ }
+ }
}
}
#endif
@@ -1218,3 +1244,16 @@ void RenderWidgetHost::ProcessKeyboardEventAck(int type, bool processed) {
}
}
}
+
+void RenderWidgetHost::ActivateDeferredPluginHandles() {
+ if (view_ == NULL)
+ return;
+
+ for (int i = 0; i < static_cast<int>(deferred_plugin_handles_.size()); i++) {
+#if defined(TOOLKIT_USES_GTK)
+ view_->CreatePluginContainer(deferred_plugin_handles_[i]);
+#endif
+ }
+
+ deferred_plugin_handles_.clear();
+}
diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h
index 47e4dab..73d7fa4 100644
--- a/chrome/browser/renderer_host/render_widget_host.h
+++ b/chrome/browser/renderer_host/render_widget_host.h
@@ -12,6 +12,7 @@
#include "app/surface/transport_dib.h"
#include "base/gtest_prod_util.h"
+#include "base/process_util.h"
#include "base/scoped_ptr.h"
#include "base/string16.h"
#include "base/timer.h"
@@ -177,13 +178,13 @@ class RenderWidgetHost : public IPC::Channel::Listener,
virtual void Shutdown();
// Manual RTTI FTW. We are not hosting a web page.
- virtual bool IsRenderView() const { return false; }
+ virtual bool IsRenderView() const;
// IPC::Channel::Listener
- virtual void OnMessageReceived(const IPC::Message& msg);
+ virtual bool OnMessageReceived(const IPC::Message& msg);
// Sends a message to the corresponding object in the renderer.
- bool Send(IPC::Message* msg);
+ virtual bool Send(IPC::Message* msg);
// Called to notify the RenderWidget that it has been hidden or restored from
// having been hidden.
@@ -404,6 +405,9 @@ class RenderWidgetHost : public IPC::Channel::Listener,
return ignore_input_events_;
}
+ // Activate deferred plugin handles.
+ void ActivateDeferredPluginHandles();
+
protected:
// Internal implementation of the public Forward*Event() methods.
void ForwardInputEvent(const WebKit::WebInputEvent& input_event,
@@ -412,7 +416,7 @@ class RenderWidgetHost : public IPC::Channel::Listener,
// Called when we receive a notification indicating that the renderer
// process has gone. This will reset our state so that our state will be
// consistent if a new renderer is created.
- void RendererExited();
+ void RendererExited(base::TerminationStatus status, int exit_code);
// Retrieves an id the renderer can use to refer to its view.
// This is used for various IPC messages, including plugins.
@@ -425,9 +429,7 @@ class RenderWidgetHost : public IPC::Channel::Listener,
// be handled in HandleKeyboardEvent() method as a normal keyboard shortcut,
// |*is_keyboard_shortcut| should be set to true.
virtual bool PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
- bool* is_keyboard_shortcut) {
- return false;
- }
+ bool* is_keyboard_shortcut);
// Called when a keyboard event was not processed by the renderer. This is
// overridden by RenderView to send upwards to its delegate.
@@ -472,7 +474,7 @@ class RenderWidgetHost : public IPC::Channel::Listener,
// IPC message handlers
void OnMsgRenderViewReady();
- void OnMsgRenderViewGone();
+ void OnMsgRenderViewGone(int status, int error_code);
void OnMsgClose();
void OnMsgRequestMove(const gfx::Rect& pos);
void OnMsgPaintAtSizeAck(int tag, const gfx::Size& size);
@@ -683,6 +685,8 @@ class RenderWidgetHost : public IPC::Channel::Listener,
// changed.
bool suppress_next_char_events_;
+ std::vector<gfx::PluginWindowHandle> deferred_plugin_handles_;
+
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHost);
};
diff --git a/chrome/browser/renderer_host/render_widget_host_unittest.cc b/chrome/browser/renderer_host/render_widget_host_unittest.cc
index 72495d3..758a5bd 100644
--- a/chrome/browser/renderer_host/render_widget_host_unittest.cc
+++ b/chrome/browser/renderer_host/render_widget_host_unittest.cc
@@ -397,7 +397,7 @@ TEST_F(RenderWidgetHostTest, ResizeThenCrash) {
// resize ack logic is cleared. Must clear the view first so it doesn't get
// deleted.
host_->set_view(NULL);
- host_->RendererExited();
+ host_->RendererExited(base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
EXPECT_FALSE(host_->resize_ack_pending_);
EXPECT_EQ(gfx::Size(), host_->in_flight_size_);
diff --git a/chrome/browser/renderer_host/render_widget_host_view.cc b/chrome/browser/renderer_host/render_widget_host_view.cc
new file mode 100644
index 0000000..6413f3a
--- /dev/null
+++ b/chrome/browser/renderer_host/render_widget_host_view.cc
@@ -0,0 +1,11 @@
+// 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.
+
+#include "chrome/browser/renderer_host/render_widget_host_view.h"
+
+RenderWidgetHostView::~RenderWidgetHostView() {}
+
+void RenderWidgetHostView::SetBackground(const SkBitmap& background) {
+ background_ = background;
+}
diff --git a/chrome/browser/renderer_host/render_widget_host_view.h b/chrome/browser/renderer_host/render_widget_host_view.h
index af6300e..2d4b1ea 100644
--- a/chrome/browser/renderer_host/render_widget_host_view.h
+++ b/chrome/browser/renderer_host/render_widget_host_view.h
@@ -14,6 +14,7 @@
#include <vector>
#include "app/surface/transport_dib.h"
+#include "base/process_util.h"
#include "gfx/native_widget_types.h"
#include "gfx/rect.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -38,8 +39,13 @@ struct ViewHostMsg_AccessibilityNotification_Params;
namespace webkit_glue {
struct WebAccessibility;
+}
+
+namespace webkit {
+namespace npapi {
struct WebPluginGeometry;
}
+}
// RenderWidgetHostView is an interface implemented by an object that acts as
// the "View" portion of a RenderWidgetHost. The RenderWidgetHost and its
@@ -50,7 +56,7 @@ struct WebPluginGeometry;
// changes.
class RenderWidgetHostView {
public:
- virtual ~RenderWidgetHostView() {}
+ virtual ~RenderWidgetHostView();
// Platform-specific creator. Use this to construct new RenderWidgetHostViews
// rather than using RenderWidgetHostViewWin & friends.
@@ -96,7 +102,7 @@ class RenderWidgetHostView {
// Moves all plugin windows as described in the given list.
virtual void MovePluginWindows(
- const std::vector<webkit_glue::WebPluginGeometry>& moves) = 0;
+ const std::vector<webkit::npapi::WebPluginGeometry>& moves) = 0;
// Actually set/take focus to/from the associated View component.
virtual void Focus() = 0;
@@ -152,7 +158,8 @@ class RenderWidgetHostView {
const std::vector<gfx::Rect>& copy_rects) = 0;
// Notifies the View that the renderer has ceased to exist.
- virtual void RenderViewGone() = 0;
+ virtual void RenderViewGone(base::TerminationStatus status,
+ int error_code) = 0;
// Notifies the View that the renderer will be delete soon.
virtual void WillDestroyRenderWidget(RenderWidgetHost* rwh) = 0;
@@ -266,11 +273,9 @@ class RenderWidgetHostView {
}
WebKit::WebPopupType popup_type() const { return popup_type_; }
- // Subclasses should override this method to do is appropriate to set
+ // Subclasses should override this method to do what is appropriate to set
// the custom background for their platform.
- virtual void SetBackground(const SkBitmap& background) {
- background_ = background;
- }
+ virtual void SetBackground(const SkBitmap& background);
const SkBitmap& background() const { return background_; }
// Returns true if the native view, |native_view|, is contained within in the
diff --git a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
index bce7089..1616378 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
+++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
@@ -38,9 +38,9 @@
#include "chrome/common/native_web_keyboard_event.h"
#include "gfx/gtk_preserve_window.h"
#include "third_party/WebKit/WebKit/chromium/public/gtk/WebInputEventFactory.h"
-#include "webkit/glue/plugins/webplugin.h"
#include "webkit/glue/webaccessibility.h"
#include "webkit/glue/webcursor_gtk_data.h"
+#include "webkit/plugins/npapi/webplugin.h"
#if defined(OS_CHROMEOS)
#include "views/widget/tooltip_window_gtk.h"
@@ -531,6 +531,10 @@ void RenderWidgetHostViewGtk::InitAsFullscreen(
DoInitAsPopup(parent_host_view, GTK_WINDOW_TOPLEVEL, gfx::Rect(), true);
}
+RenderWidgetHost* RenderWidgetHostViewGtk::GetRenderWidgetHost() const {
+ return host_;
+}
+
void RenderWidgetHostViewGtk::DidBecomeSelected() {
if (!is_hidden_)
return;
@@ -583,7 +587,7 @@ gfx::NativeView RenderWidgetHostViewGtk::GetNativeView() {
}
void RenderWidgetHostViewGtk::MovePluginWindows(
- const std::vector<webkit_glue::WebPluginGeometry>& moves) {
+ const std::vector<webkit::npapi::WebPluginGeometry>& moves) {
for (size_t i = 0; i < moves.size(); ++i) {
plugin_container_manager_.MovePluginContainer(moves[i]);
}
@@ -681,7 +685,8 @@ void RenderWidgetHostViewGtk::DidUpdateBackingStore(
}
}
-void RenderWidgetHostViewGtk::RenderViewGone() {
+void RenderWidgetHostViewGtk::RenderViewGone(base::TerminationStatus status,
+ int error_code) {
Destroy();
plugin_container_manager_.set_host_widget(NULL);
}
@@ -718,16 +723,17 @@ void RenderWidgetHostViewGtk::SetTooltipText(const std::wstring& tooltip_text) {
// accidentally DOS the user with a mega tooltip (since GTK doesn't do
// this itself).
// I filed https://bugzilla.gnome.org/show_bug.cgi?id=604641 upstream.
- const std::wstring& clamped_tooltip =
- l10n_util::TruncateString(tooltip_text, kMaxTooltipLength);
+ const string16 clamped_tooltip =
+ l10n_util::TruncateString(WideToUTF16Hack(tooltip_text),
+ kMaxTooltipLength);
if (clamped_tooltip.empty()) {
gtk_widget_set_has_tooltip(view_.get(), FALSE);
} else {
gtk_widget_set_tooltip_text(view_.get(),
- WideToUTF8(clamped_tooltip).c_str());
+ UTF16ToUTF8(clamped_tooltip).c_str());
#if defined(OS_CHROMEOS)
- tooltip_window_->SetTooltipText(clamped_tooltip);
+ tooltip_window_->SetTooltipText(UTF16ToWideHack(clamped_tooltip));
#endif // defined(OS_CHROMEOS)
}
}
@@ -1091,7 +1097,12 @@ void RenderWidgetHostViewGtk::ForwardKeyboardEvent(
if (!event.skip_in_browser &&
key_bindings_handler_->Match(event, &edit_commands)) {
host_->ForwardEditCommandsForNextKeyEvent(edit_commands);
+ NativeWebKeyboardEvent copy_event(event);
+ copy_event.match_edit_command = true;
+ host_->ForwardKeyboardEvent(copy_event);
+ return;
}
+
host_->ForwardKeyboardEvent(event);
}
diff --git a/chrome/browser/renderer_host/render_widget_host_view_gtk.h b/chrome/browser/renderer_host/render_widget_host_view_gtk.h
index cd89ddb..2c47c01 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_gtk.h
+++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.h
@@ -19,8 +19,8 @@
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "gfx/native_widget_types.h"
#include "gfx/rect.h"
-#include "webkit/glue/plugins/gtk_plugin_container_manager.h"
#include "webkit/glue/webcursor.h"
+#include "webkit/plugins/npapi/gtk_plugin_container_manager.h"
class RenderWidgetHost;
class GtkIMContextWrapper;
@@ -55,13 +55,13 @@ class RenderWidgetHostViewGtk : public RenderWidgetHostView,
virtual void InitAsPopup(RenderWidgetHostView* parent_host_view,
const gfx::Rect& pos);
virtual void InitAsFullscreen(RenderWidgetHostView* parent_host_view);
- virtual RenderWidgetHost* GetRenderWidgetHost() const { return host_; }
+ virtual RenderWidgetHost* GetRenderWidgetHost() const;
virtual void DidBecomeSelected();
virtual void WasHidden();
virtual void SetSize(const gfx::Size& size);
virtual gfx::NativeView GetNativeView();
virtual void MovePluginWindows(
- const std::vector<webkit_glue::WebPluginGeometry>& moves);
+ const std::vector<webkit::npapi::WebPluginGeometry>& moves);
virtual void Focus();
virtual void Blur();
virtual bool HasFocus();
@@ -77,7 +77,8 @@ class RenderWidgetHostViewGtk : public RenderWidgetHostView,
virtual void DidUpdateBackingStore(
const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy,
const std::vector<gfx::Rect>& copy_rects);
- virtual void RenderViewGone();
+ virtual void RenderViewGone(base::TerminationStatus status,
+ int error_code);
virtual void Destroy();
virtual void WillDestroyRenderWidget(RenderWidgetHost* rwh) {}
virtual void SetTooltipText(const std::wstring& tooltip_text);
@@ -207,7 +208,7 @@ class RenderWidgetHostViewGtk : public RenderWidgetHostView,
scoped_ptr<GtkKeyBindingsHandler> key_bindings_handler_;
// Helper class that lets us allocate plugin containers and move them.
- GtkPluginContainerManager plugin_container_manager_;
+ webkit::npapi::GtkPluginContainerManager plugin_container_manager_;
// The size that we want the renderer to be. We keep this in a separate
// variable because resizing in GTK+ is async.
diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.h b/chrome/browser/renderer_host/render_widget_host_view_mac.h
index ef5149c..d538758 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_mac.h
+++ b/chrome/browser/renderer_host/render_widget_host_view_mac.h
@@ -15,9 +15,9 @@
#include "base/time.h"
#include "chrome/browser/accessibility/browser_accessibility_delegate_mac.h"
#include "chrome/browser/accessibility/browser_accessibility_manager.h"
-#include "chrome/browser/cocoa/base_view.h"
#include "chrome/browser/renderer_host/accelerated_surface_container_manager_mac.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
+#include "chrome/browser/ui/cocoa/base_view.h"
#include "chrome/common/edit_command.h"
#include "third_party/WebKit/WebKit/chromium/public/WebCompositionUnderline.h"
#include "webkit/glue/webcursor.h"
@@ -184,7 +184,7 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView {
virtual void SetSize(const gfx::Size& size);
virtual gfx::NativeView GetNativeView();
virtual void MovePluginWindows(
- const std::vector<webkit_glue::WebPluginGeometry>& moves);
+ const std::vector<webkit::npapi::WebPluginGeometry>& moves);
virtual void Focus();
virtual void Blur();
virtual bool HasFocus();
@@ -200,7 +200,8 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView {
virtual void DidUpdateBackingStore(
const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy,
const std::vector<gfx::Rect>& copy_rects);
- virtual void RenderViewGone();
+ virtual void RenderViewGone(base::TerminationStatus status,
+ int error_code);
virtual void WillDestroyRenderWidget(RenderWidgetHost* rwh) {};
virtual void Destroy();
virtual void SetTooltipText(const std::wstring& tooltip_text);
diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.mm b/chrome/browser/renderer_host/render_widget_host_view_mac.mm
index 3f223a1..14b4d82 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm
@@ -8,7 +8,6 @@
#include "app/app_switches.h"
#include "app/surface/io_surface_support_mac.h"
-#import "base/chrome_application_mac.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/mac/scoped_cftyperef.h"
@@ -22,8 +21,6 @@
#include "chrome/browser/accessibility/browser_accessibility_state.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/browser_trial.h"
-#import "chrome/browser/cocoa/rwhvm_editcommand_helper.h"
-#import "chrome/browser/cocoa/view_id_util.h"
#include "chrome/browser/gpu_process_host.h"
#include "chrome/browser/plugin_process_host.h"
#include "chrome/browser/renderer_host/backing_store_mac.h"
@@ -31,6 +28,8 @@
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
#include "chrome/browser/spellchecker_platform_engine.h"
+#import "chrome/browser/ui/cocoa/rwhvm_editcommand_helper.h"
+#import "chrome/browser/ui/cocoa/view_id_util.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/native_web_keyboard_event.h"
#include "chrome/common/edit_command.h"
@@ -41,8 +40,8 @@
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/WebKit/WebKit/chromium/public/mac/WebInputEventFactory.h"
#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h"
-#include "webkit/glue/plugins/webplugin.h"
#include "webkit/glue/webaccessibility.h"
+#include "webkit/plugins/npapi/webplugin.h"
#import "third_party/mozilla/ComplexTextInputPanel.h"
using WebKit::WebInputEvent;
@@ -524,7 +523,7 @@ RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget)
// Turn on accessibility only if VoiceOver is running.
if (IsVoiceOverRunning()) {
- Singleton<BrowserAccessibilityState>()->OnScreenReaderDetected();
+ BrowserAccessibilityState::GetInstance()->OnScreenReaderDetected();
render_widget_host_->EnableRendererAccessibility();
}
}
@@ -624,15 +623,15 @@ gfx::NativeView RenderWidgetHostViewMac::GetNativeView() {
}
void RenderWidgetHostViewMac::MovePluginWindows(
- const std::vector<webkit_glue::WebPluginGeometry>& moves) {
+ const std::vector<webkit::npapi::WebPluginGeometry>& moves) {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
// Handle movement of accelerated plugins, which are the only "windowed"
// plugins that exist on the Mac.
- for (std::vector<webkit_glue::WebPluginGeometry>::const_iterator iter =
+ for (std::vector<webkit::npapi::WebPluginGeometry>::const_iterator iter =
moves.begin();
iter != moves.end();
++iter) {
- webkit_glue::WebPluginGeometry geom = *iter;
+ webkit::npapi::WebPluginGeometry geom = *iter;
AcceleratedPluginView* view = ViewForPluginWindowHandle(geom.window);
DCHECK(view);
@@ -794,7 +793,8 @@ void RenderWidgetHostViewMac::DidUpdateBackingStore(
HandleDelayedGpuViewHiding();
}
-void RenderWidgetHostViewMac::RenderViewGone() {
+void RenderWidgetHostViewMac::RenderViewGone(base::TerminationStatus status,
+ int error_code) {
// TODO(darin): keep this around, and draw sad-tab into it.
UpdateCursorIfOverSelf();
Destroy();
@@ -1019,14 +1019,14 @@ void RenderWidgetHostViewMac::AcceleratedSurfaceSetIOSurface(
// Fake up a WebPluginGeometry for the root window to set the
// container's size; we will never get a notification from the
// browser about the root window, only plugins.
- webkit_glue::WebPluginGeometry geom;
+ webkit::npapi::WebPluginGeometry geom;
gfx::Rect rect(0, 0, width, height);
geom.window = window;
geom.window_rect = rect;
geom.clip_rect = rect;
geom.visible = true;
geom.rects_valid = true;
- MovePluginWindows(std::vector<webkit_glue::WebPluginGeometry>(1, geom));
+ MovePluginWindows(std::vector<webkit::npapi::WebPluginGeometry>(1, geom));
}
}
@@ -1124,6 +1124,17 @@ void RenderWidgetHostViewMac::AcknowledgeSwapBuffers(
int renderer_id,
int32 route_id,
uint64 swap_buffers_count) {
+ // Called on the display link thread. Hand actual work off to the IO thread,
+ // because |GpuProcessHost::Get()| can only be called there.
+ // Currently, this is never called for plugins.
+ if (render_widget_host_) {
+ DCHECK_EQ(render_widget_host_->process()->id(), renderer_id);
+ // |render_widget_host_->routing_id()| and |route_id| are usually not
+ // equal: The former identifies the channel from the RWH in the browser
+ // process to the corresponding render widget in the renderer process, while
+ // the latter identifies the channel from the GpuCommandBufferStub in the
+ // GPU process to the corresponding command buffer client in the renderer.
+ }
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
new BuffersSwappedAcknowledger(
@@ -1754,8 +1765,6 @@ void RenderWidgetHostViewMac::SetTextInputActive(bool active) {
return;
}
- DCHECK(
- renderWidgetHostView_->render_widget_host_->process()->HasConnection());
DCHECK(!renderWidgetHostView_->about_to_validate_and_paint_);
renderWidgetHostView_->about_to_validate_and_paint_ = true;
diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac_unittest.mm b/chrome/browser/renderer_host/render_widget_host_view_mac_unittest.mm
index 7ae9e25..a36c88f 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_mac_unittest.mm
+++ b/chrome/browser/renderer_host/render_widget_host_view_mac_unittest.mm
@@ -4,24 +4,43 @@
#include "chrome/browser/renderer_host/render_widget_host_view_mac.h"
+#include "base/mac/scoped_nsautorelease_pool.h"
#include "chrome/browser/browser_thread.h"
-#import "chrome/browser/cocoa/cocoa_test_helper.h"
-#include "chrome/browser/cocoa/test_event_utils.h"
#include "chrome/browser/renderer_host/test/test_render_view_host.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/test_event_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
class RenderWidgetHostViewMacTest : public RenderViewHostTestHarness {
public:
- RenderWidgetHostViewMacTest() {}
+ RenderWidgetHostViewMacTest() : old_rwhv_(NULL), rwhv_mac_(NULL) {}
virtual void SetUp() {
+ // Set up Cocoa.
+ [CrApplication sharedApplication];
+
RenderViewHostTestHarness::SetUp();
- // Owned by its |native_view()|.
+ // TestRenderViewHost's destruction assumes that its view is a
+ // TestRenderWidgetHostView, so store its view and reset it back to the
+ // stored view in |TearDown()|.
+ old_rwhv_ = rvh()->view();
+
+ // Owned by its |native_view()|, i.e. |rwhv_cocoa_|.
rwhv_mac_ = new RenderWidgetHostViewMac(rvh());
+ rwhv_cocoa_.reset([rwhv_mac_->native_view() retain]);
+ }
+ virtual void TearDown() {
+ // See comment in SetUp().
+ rvh()->set_view(old_rwhv_);
- // Will be released when the superclass's RenderWidgetHost is destroyed.
- rwhv_cocoa_ = [rwhv_mac_->native_view() retain];
+ // Make sure the rwhv_mac_ is gone once the superclass's |TearDown()| runs.
+ rwhv_cocoa_.reset();
+ pool_.Recycle();
+ MessageLoop::current()->RunAllPending();
+ pool_.Recycle();
+
+ RenderViewHostTestHarness::TearDown();
}
protected:
// Adds an accelerated plugin view to |rwhv_cocoa_|. Returns a handle to the
@@ -29,7 +48,7 @@ class RenderWidgetHostViewMacTest : public RenderViewHostTestHarness {
// running before calling this function.
gfx::PluginWindowHandle AddAcceleratedPluginView(int w, int h) {
// Create an accelerated view the size of the rhwvmac.
- [rwhv_cocoa_ setFrame:NSMakeRect(0, 0, w, h)];
+ [rwhv_cocoa_.get() setFrame:NSMakeRect(0, 0, w, h)];
gfx::PluginWindowHandle accelerated_handle =
rwhv_mac_->AllocateFakePluginWindowHandle(/*opaque=*/false,
/*root=*/false);
@@ -38,7 +57,7 @@ class RenderWidgetHostViewMacTest : public RenderViewHostTestHarness {
// The accelerated view isn't shown until it has a valid rect and has been
// painted to.
rwhv_mac_->AcceleratedSurfaceBuffersSwapped(accelerated_handle, 0, 0, 0, 0);
- webkit_glue::WebPluginGeometry geom;
+ webkit::npapi::WebPluginGeometry geom;
gfx::Rect rect(0, 0, w, h);
geom.window = accelerated_handle;
geom.window_rect = rect;
@@ -46,14 +65,21 @@ class RenderWidgetHostViewMacTest : public RenderViewHostTestHarness {
geom.visible = true;
geom.rects_valid = true;
rwhv_mac_->MovePluginWindows(
- std::vector<webkit_glue::WebPluginGeometry>(1, geom));
+ std::vector<webkit::npapi::WebPluginGeometry>(1, geom));
return accelerated_handle;
}
+ private:
+ // This class isn't derived from PlatformTest.
+ base::mac::ScopedNSAutoreleasePool pool_;
+
+ RenderWidgetHostView* old_rwhv_;
+ protected:
RenderWidgetHostViewMac* rwhv_mac_;
- RenderWidgetHostViewCocoa* rwhv_cocoa_;
+ scoped_nsobject<RenderWidgetHostViewCocoa> rwhv_cocoa_;
+ private:
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewMacTest);
};
@@ -68,7 +94,7 @@ TEST_F(RenderWidgetHostViewMacTest, FocusAcceleratedView) {
int w = 400, h = 300;
gfx::PluginWindowHandle accelerated_handle = AddAcceleratedPluginView(w, h);
- EXPECT_FALSE([rwhv_cocoa_ isHidden]);
+ EXPECT_FALSE([rwhv_cocoa_.get() isHidden]);
NSView* accelerated_view = static_cast<NSView*>(
rwhv_mac_->ViewForPluginWindowHandle(accelerated_handle));
EXPECT_FALSE([accelerated_view isHidden]);
@@ -79,21 +105,21 @@ TEST_F(RenderWidgetHostViewMacTest, FocusAcceleratedView) {
scoped_nsobject<NSWindow> window([[CocoaTestHelperWindow alloc] init]);
scoped_nsobject<NSView> other_view(
[[NSTextField alloc] initWithFrame:NSMakeRect(0, h, w, 40)]);
- [[window contentView] addSubview:rwhv_cocoa_];
+ [[window contentView] addSubview:rwhv_cocoa_.get()];
[[window contentView] addSubview:other_view.get()];
- EXPECT_TRUE([rwhv_cocoa_ acceptsFirstResponder]);
- [window makeFirstResponder:rwhv_cocoa_];
- EXPECT_EQ(rwhv_cocoa_, [window firstResponder]);
+ EXPECT_TRUE([rwhv_cocoa_.get() acceptsFirstResponder]);
+ [window makeFirstResponder:rwhv_cocoa_.get()];
+ EXPECT_EQ(rwhv_cocoa_.get(), [window firstResponder]);
EXPECT_FALSE([accelerated_view acceptsFirstResponder]);
EXPECT_TRUE([other_view acceptsFirstResponder]);
[window makeFirstResponder:other_view];
- EXPECT_NE(rwhv_cocoa_, [window firstResponder]);
+ EXPECT_NE(rwhv_cocoa_.get(), [window firstResponder]);
EXPECT_TRUE([accelerated_view acceptsFirstResponder]);
[window makeFirstResponder:accelerated_view];
- EXPECT_EQ(rwhv_cocoa_, [window firstResponder]);
+ EXPECT_EQ(rwhv_cocoa_.get(), [window firstResponder]);
// Clean up.
rwhv_mac_->DestroyFakePluginWindowHandle(accelerated_handle);
@@ -101,33 +127,33 @@ TEST_F(RenderWidgetHostViewMacTest, FocusAcceleratedView) {
TEST_F(RenderWidgetHostViewMacTest, AcceptsFirstResponder) {
// The RWHVCocoa should normally accept first responder status.
- EXPECT_TRUE([rwhv_cocoa_ acceptsFirstResponder]);
+ EXPECT_TRUE([rwhv_cocoa_.get() acceptsFirstResponder]);
// Unless we tell it not to.
rwhv_mac_->SetTakesFocusOnlyOnMouseDown(true);
- EXPECT_FALSE([rwhv_cocoa_ acceptsFirstResponder]);
+ EXPECT_FALSE([rwhv_cocoa_.get() acceptsFirstResponder]);
// But we can set things back to the way they were originally.
rwhv_mac_->SetTakesFocusOnlyOnMouseDown(false);
- EXPECT_TRUE([rwhv_cocoa_ acceptsFirstResponder]);
+ EXPECT_TRUE([rwhv_cocoa_.get() acceptsFirstResponder]);
}
TEST_F(RenderWidgetHostViewMacTest, TakesFocusOnMouseDown) {
scoped_nsobject<NSWindow> window([[CocoaTestHelperWindow alloc] init]);
- [[window contentView] addSubview:rwhv_cocoa_];
+ [[window contentView] addSubview:rwhv_cocoa_.get()];
// Even if the RWHVCocoa disallows first responder, clicking on it gives it
// focus.
[window makeFirstResponder:nil];
- ASSERT_NE(rwhv_cocoa_, [window firstResponder]);
+ ASSERT_NE(rwhv_cocoa_.get(), [window firstResponder]);
rwhv_mac_->SetTakesFocusOnlyOnMouseDown(true);
- EXPECT_FALSE([rwhv_cocoa_ acceptsFirstResponder]);
+ EXPECT_FALSE([rwhv_cocoa_.get() acceptsFirstResponder]);
std::pair<NSEvent*, NSEvent*> clicks =
- test_event_utils::MouseClickInView(rwhv_cocoa_, 1);
- [rwhv_cocoa_ mouseDown:clicks.first];
- EXPECT_EQ(rwhv_cocoa_, [window firstResponder]);
+ test_event_utils::MouseClickInView(rwhv_cocoa_.get(), 1);
+ [rwhv_cocoa_.get() mouseDown:clicks.first];
+ EXPECT_EQ(rwhv_cocoa_.get(), [window firstResponder]);
}
// Regression test for http://crbug.com/64256
@@ -138,16 +164,16 @@ TEST_F(RenderWidgetHostViewMacTest, TakesFocusOnMouseDownWithAcceleratedView) {
int w = 400, h = 300;
gfx::PluginWindowHandle accelerated_handle = AddAcceleratedPluginView(w, h);
- EXPECT_FALSE([rwhv_cocoa_ isHidden]);
+ EXPECT_FALSE([rwhv_cocoa_.get() isHidden]);
NSView* accelerated_view = static_cast<NSView*>(
rwhv_mac_->ViewForPluginWindowHandle(accelerated_handle));
EXPECT_FALSE([accelerated_view isHidden]);
// Add the RWHVCocoa to the window and remove first responder status.
scoped_nsobject<NSWindow> window([[CocoaTestHelperWindow alloc] init]);
- [[window contentView] addSubview:rwhv_cocoa_];
+ [[window contentView] addSubview:rwhv_cocoa_.get()];
[window makeFirstResponder:nil];
- EXPECT_NE(rwhv_cocoa_, [window firstResponder]);
+ EXPECT_NE(rwhv_cocoa_.get(), [window firstResponder]);
// Tell the RWHVMac to not accept first responder status. The accelerated
// view should also stop accepting first responder.
@@ -157,8 +183,8 @@ TEST_F(RenderWidgetHostViewMacTest, TakesFocusOnMouseDownWithAcceleratedView) {
// A click on the accelerated view should focus the RWHVCocoa.
std::pair<NSEvent*, NSEvent*> clicks =
test_event_utils::MouseClickInView(accelerated_view, 1);
- [rwhv_cocoa_ mouseDown:clicks.first];
- EXPECT_EQ(rwhv_cocoa_, [window firstResponder]);
+ [rwhv_cocoa_.get() mouseDown:clicks.first];
+ EXPECT_EQ(rwhv_cocoa_.get(), [window firstResponder]);
// Clean up.
rwhv_mac_->DestroyFakePluginWindowHandle(accelerated_handle);
diff --git a/chrome/browser/renderer_host/render_widget_host_view_views.cc b/chrome/browser/renderer_host/render_widget_host_view_views.cc
index 371f60e..c48a1a9 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_views.cc
+++ b/chrome/browser/renderer_host/render_widget_host_view_views.cc
@@ -22,11 +22,13 @@
#include "chrome/common/chrome_switches.h"
#include "chrome/common/native_web_keyboard_event.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/result_codes.h"
#include "gfx/canvas.h"
#include "third_party/WebKit/WebKit/chromium/public/gtk/WebInputEventFactory.h"
#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h"
#include "views/event.h"
#include "views/widget/widget.h"
+#include "views/widget/widget_gtk.h"
static const int kMaxWindowWidth = 4000;
static const int kMaxWindowHeight = 4000;
@@ -130,7 +132,8 @@ RenderWidgetHostViewViews::RenderWidgetHostViewViews(RenderWidgetHost* host)
}
RenderWidgetHostViewViews::~RenderWidgetHostViewViews() {
- RenderViewGone();
+ RenderViewGone(base::TERMINATION_STATUS_NORMAL_TERMINATION,
+ ResultCodes::NORMAL_EXIT);
}
void RenderWidgetHostViewViews::InitAsChild() {
@@ -190,9 +193,9 @@ void RenderWidgetHostViewViews::SetSize(const gfx::Size& size) {
}
void RenderWidgetHostViewViews::MovePluginWindows(
- const std::vector<webkit_glue::WebPluginGeometry>& moves) {
+ const std::vector<webkit::npapi::WebPluginGeometry>& moves) {
// TODO(anicolao): NIY
- NOTIMPLEMENTED();
+ // NOTIMPLEMENTED();
}
void RenderWidgetHostViewViews::Focus() {
@@ -285,7 +288,8 @@ void RenderWidgetHostViewViews::DidUpdateBackingStore(
}
}
-void RenderWidgetHostViewViews::RenderViewGone() {
+void RenderWidgetHostViewViews::RenderViewGone(base::TerminationStatus status,
+ int error_code) {
GetRenderWidgetHost()->ViewDestroyed();
Destroy();
}
@@ -326,6 +330,13 @@ BackingStore* RenderWidgetHostViewViews::AllocBackingStore(
}
gfx::NativeView RenderWidgetHostViewViews::native_view() const {
+ // TODO(sad): Ideally this function should be equivalent to GetNativeView, and
+ // WidgetGtk-specific function call should not be necessary.
+ views::WidgetGtk* widget = static_cast<views::WidgetGtk*>(GetWidget());
+ return widget ? widget->window_contents() : NULL;
+}
+
+gfx::NativeView RenderWidgetHostViewViews::GetNativeView() {
if (GetWidget())
return GetWidget()->GetNativeView();
return NULL;
@@ -381,7 +392,7 @@ void RenderWidgetHostViewViews::Paint(gfx::Canvas* canvas) {
// In the common case, use XCopyArea. We don't draw more than once, so
// we don't need to double buffer.
backing_store->XShowRect(origin,
- paint_rect, x11_util::GetX11WindowFromGtkWidget(native_view()));
+ paint_rect, x11_util::GetX11WindowFromGdkWindow(window));
} else {
// If the grey blend is showing, we make two drawing calls. Use double
// buffering to prevent flicker. Use CairoShowRect because XShowRect
@@ -420,8 +431,6 @@ void RenderWidgetHostViewViews::Paint(gfx::Canvas* canvas) {
tab_switch_paint_time_ = base::TimeTicks();
}
} else {
- if (window)
- gdk_window_clear(window);
if (whiteout_start_time_.is_null())
whiteout_start_time_ = base::TimeTicks::Now();
}
diff --git a/chrome/browser/renderer_host/render_widget_host_view_views.h b/chrome/browser/renderer_host/render_widget_host_view_views.h
index 5a1b07e..8a582a7 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_views.h
+++ b/chrome/browser/renderer_host/render_widget_host_view_views.h
@@ -44,7 +44,7 @@ class RenderWidgetHostViewViews : public RenderWidgetHostView,
virtual void WasHidden();
virtual void SetSize(const gfx::Size& size);
virtual void MovePluginWindows(
- const std::vector<webkit_glue::WebPluginGeometry>& moves);
+ const std::vector<webkit::npapi::WebPluginGeometry>& moves);
virtual void Focus();
virtual void Blur();
virtual bool HasFocus();
@@ -60,7 +60,8 @@ class RenderWidgetHostViewViews : public RenderWidgetHostView,
virtual void DidUpdateBackingStore(
const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy,
const std::vector<gfx::Rect>& copy_rects);
- virtual void RenderViewGone();
+ virtual void RenderViewGone(base::TerminationStatus status,
+ int error_code);
virtual void Destroy();
virtual void WillDestroyRenderWidget(RenderWidgetHost* rwh) {}
virtual void SetTooltipText(const std::wstring& tooltip_text);
@@ -75,7 +76,7 @@ class RenderWidgetHostViewViews : public RenderWidgetHostView,
virtual void AcceleratedCompositingActivated(bool activated);
gfx::NativeView native_view() const;
- virtual gfx::NativeView GetNativeView() { return native_view(); }
+ virtual gfx::NativeView GetNativeView();
virtual void Paint(gfx::Canvas* canvas);
diff --git a/chrome/browser/renderer_host/render_widget_host_view_win.cc b/chrome/browser/renderer_host/render_widget_host_view_win.cc
index 9ec1512..72804de 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_win.cc
+++ b/chrome/browser/renderer_host/render_widget_host_view_win.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/renderer_host/render_widget_host_view_win.h"
+#include <algorithm>
+
#include "app/l10n_util.h"
#include "app/l10n_util_win.h"
#include "app/resource_bundle.h"
@@ -15,10 +17,10 @@
#include "base/scoped_comptr_win.h"
#include "base/thread.h"
#include "base/win_util.h"
+#include "base/win/scoped_gdi_object.h"
#include "chrome/browser/accessibility/browser_accessibility_win.h"
#include "chrome/browser/accessibility/browser_accessibility_manager.h"
#include "chrome/browser/accessibility/browser_accessibility_state.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/browser_trial.h"
#include "chrome/browser/plugin_process_host.h"
@@ -45,11 +47,11 @@
#include "views/focus/focus_util_win.h"
// Included for views::kReflectedMessage - TODO(beng): move this to win_util.h!
#include "views/widget/widget_win.h"
-#include "webkit/glue/plugins/plugin_constants_win.h"
-#include "webkit/glue/plugins/webplugin_delegate_impl.h"
-#include "webkit/glue/plugins/webplugin.h"
#include "webkit/glue/webaccessibility.h"
#include "webkit/glue/webcursor.h"
+#include "webkit/plugins/npapi/plugin_constants_win.h"
+#include "webkit/plugins/npapi/webplugin_delegate_impl.h"
+#include "webkit/plugins/npapi/webplugin.h"
using app::ViewProp;
using base::TimeDelta;
@@ -58,7 +60,7 @@ using WebKit::WebInputEvent;
using WebKit::WebInputEventFactory;
using WebKit::WebMouseEvent;
using WebKit::WebTextDirection;
-using webkit_glue::WebPluginGeometry;
+using webkit::npapi::WebPluginGeometry;
const wchar_t kRenderWidgetHostHWNDClass[] = L"Chrome_RenderWidgetHostHWND";
@@ -235,7 +237,7 @@ class NotifyPluginProcessHostTask : public Task {
// Windows callback for OnDestroy to detach the plugin windows.
BOOL CALLBACK DetachPluginWindowsCallback(HWND window, LPARAM param) {
- if (WebPluginDelegateImpl::IsPluginDelegateWindow(window) &&
+ if (webkit::npapi::WebPluginDelegateImpl::IsPluginDelegateWindow(window) &&
!IsHungAppWindow(window)) {
::ShowWindow(window, SW_HIDE);
SetParent(window, NULL);
@@ -489,7 +491,7 @@ HWND RenderWidgetHostViewWin::ReparentWindow(HWND window) {
wcex.hCursor = 0;
wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW+1);
wcex.lpszMenuName = 0;
- wcex.lpszClassName = kWrapperNativeWindowClassName;
+ wcex.lpszClassName = webkit::npapi::kWrapperNativeWindowClassName;
wcex.hIconSm = 0;
window_class = RegisterClassEx(&wcex);
}
@@ -653,11 +655,11 @@ void RenderWidgetHostViewWin::ImeCancelComposition() {
}
BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lparam) {
- if (!WebPluginDelegateImpl::IsPluginDelegateWindow(hwnd))
+ if (!webkit::npapi::WebPluginDelegateImpl::IsPluginDelegateWindow(hwnd))
return TRUE;
gfx::Rect* rect = reinterpret_cast<gfx::Rect*>(lparam);
- static UINT msg = RegisterWindowMessage(kPaintMessageName);
+ static UINT msg = RegisterWindowMessage(webkit::npapi::kPaintMessageName);
WPARAM wparam = rect->x() << 16 | rect->y();
lparam = rect->width() << 16 | rect->height();
@@ -673,7 +675,7 @@ void RenderWidgetHostViewWin::Redraw() {
RECT damage_bounds;
GetUpdateRect(&damage_bounds, FALSE);
- ScopedGDIObject<HRGN> damage_region(CreateRectRgn(0, 0, 0, 0));
+ base::win::ScopedGDIObject<HRGN> damage_region(CreateRectRgn(0, 0, 0, 0));
GetUpdateRgn(damage_region, FALSE);
// Paint the invalid region synchronously. Our caller will not paint again
@@ -721,7 +723,8 @@ void RenderWidgetHostViewWin::DidUpdateBackingStore(
Redraw();
}
-void RenderWidgetHostViewWin::RenderViewGone() {
+void RenderWidgetHostViewWin::RenderViewGone(base::TerminationStatus status,
+ int error_code) {
// TODO(darin): keep this around, and draw sad-tab into it.
UpdateCursorIfOverSelf();
being_destroyed_ = true;
@@ -899,7 +902,7 @@ void RenderWidgetHostViewWin::OnPaint(HDC unused_dc) {
// Grab the region to paint before creation of paint_dc since it clears the
// damage region.
- ScopedGDIObject<HRGN> damage_region(CreateRectRgn(0, 0, 0, 0));
+ base::win::ScopedGDIObject<HRGN> damage_region(CreateRectRgn(0, 0, 0, 0));
GetUpdateRgn(damage_region, FALSE);
CPaintDC paint_dc(m_hWnd);
@@ -1445,7 +1448,8 @@ LRESULT RenderWidgetHostViewWin::OnMouseActivate(UINT message,
::ScreenToClient(m_hWnd, &cursor_pos);
HWND child_window = ::RealChildWindowFromPoint(m_hWnd, cursor_pos);
if (::IsWindow(child_window) && child_window != m_hWnd) {
- if (win_util::GetClassName(child_window) == kWrapperNativeWindowClassName)
+ if (win_util::GetClassName(child_window) ==
+ webkit::npapi::kWrapperNativeWindowClassName)
child_window = ::GetWindow(child_window, GW_CHILD);
::SetFocus(child_window);
@@ -1652,7 +1656,7 @@ LRESULT RenderWidgetHostViewWin::OnGetObject(UINT message, WPARAM wparam,
if (kIdCustom == lparam) {
// An MSAA client requestes our custom id. Assume that we have detected an
// active windows screen reader.
- Singleton<BrowserAccessibilityState>()->OnScreenReaderDetected();
+ BrowserAccessibilityState::GetInstance()->OnScreenReaderDetected();
render_widget_host_->EnableRendererAccessibility();
// Return with failure.
diff --git a/chrome/browser/renderer_host/render_widget_host_view_win.h b/chrome/browser/renderer_host/render_widget_host_view_win.h
index 282dfe9..50e59a6 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_win.h
+++ b/chrome/browser/renderer_host/render_widget_host_view_win.h
@@ -132,7 +132,7 @@ class RenderWidgetHostViewWin
virtual void SetSize(const gfx::Size& size);
virtual gfx::NativeView GetNativeView();
virtual void MovePluginWindows(
- const std::vector<webkit_glue::WebPluginGeometry>& moves);
+ const std::vector<webkit::npapi::WebPluginGeometry>& moves);
virtual void Focus();
virtual void Blur();
virtual bool HasFocus();
@@ -148,7 +148,8 @@ class RenderWidgetHostViewWin
virtual void DidUpdateBackingStore(
const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy,
const std::vector<gfx::Rect>& copy_rects);
- virtual void RenderViewGone();
+ virtual void RenderViewGone(base::TerminationStatus status,
+ int error_code);
virtual void WillWmDestroy(); // called by TabContents before DestroyWindow
virtual void WillDestroyRenderWidget(RenderWidgetHost* rwh);
virtual void Destroy();
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host.cc b/chrome/browser/renderer_host/resource_dispatcher_host.cc
index 1473766..cad4560 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host.cc
+++ b/chrome/browser/renderer_host/resource_dispatcher_host.cc
@@ -6,6 +6,7 @@
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+#include <set>
#include <vector>
#include "base/logging.h"
@@ -27,11 +28,10 @@
#include "chrome/browser/extensions/user_script_listener.h"
#include "chrome/browser/external_protocol_handler.h"
#include "chrome/browser/in_process_webkit/webkit_thread.h"
-#include "chrome/browser/login_prompt.h"
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/browser/net/url_request_tracking.h"
#include "chrome/browser/plugin_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/async_resource_handler.h"
#include "chrome/browser/renderer_host/buffered_resource_handler.h"
#include "chrome/browser/renderer_host/cross_site_resource_handler.h"
@@ -42,18 +42,18 @@
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
#include "chrome/browser/renderer_host/render_view_host_notification_task.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
+#include "chrome/browser/renderer_host/resource_message_filter.h"
#include "chrome/browser/renderer_host/resource_queue.h"
#include "chrome/browser/renderer_host/resource_request_details.h"
#include "chrome/browser/renderer_host/safe_browsing_resource_handler.h"
#include "chrome/browser/renderer_host/save_file_resource_handler.h"
-#include "chrome/browser/renderer_host/socket_stream_dispatcher_host.h"
#include "chrome/browser/renderer_host/sync_resource_handler.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/browser/ssl/ssl_client_auth_handler.h"
#include "chrome/browser/ssl/ssl_manager.h"
+#include "chrome/browser/ui/login/login_prompt.h"
#include "chrome/browser/worker_host/worker_service.h"
#include "chrome/common/chrome_switches.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/render_messages_params.h"
#include "chrome/common/url_constants.h"
@@ -157,7 +157,7 @@ bool ShouldServiceRequest(ChildProcessInfo::ProcessType process_type,
return true;
}
-void PopulateResourceResponse(URLRequest* request,
+void PopulateResourceResponse(net::URLRequest* request,
bool replace_extension_localization_templates,
ResourceResponse* response) {
response->response_head.status = request->status();
@@ -195,14 +195,6 @@ std::vector<int> GetAllNetErrorCodes() {
} // namespace
-ResourceDispatcherHost::Receiver::Receiver(ChildProcessInfo::ProcessType type,
- int child_id)
- : ChildProcessInfo(type, child_id) {
-}
-
-ResourceDispatcherHost::Receiver::~Receiver() {
-}
-
ResourceDispatcherHost::ResourceDispatcherHost()
: ALLOW_THIS_IN_INITIALIZER_LIST(
download_file_manager_(new DownloadFileManager(this))),
@@ -211,14 +203,13 @@ ResourceDispatcherHost::ResourceDispatcherHost()
save_file_manager_(new SaveFileManager(this))),
user_script_listener_(new UserScriptListener(&resource_queue_)),
safe_browsing_(SafeBrowsingService::CreateSafeBrowsingService()),
- socket_stream_dispatcher_host_(new SocketStreamDispatcherHost),
webkit_thread_(new WebKitThread),
request_id_(-1),
ALLOW_THIS_IN_INITIALIZER_LIST(method_runner_(this)),
is_shutdown_(false),
max_outstanding_requests_cost_per_process_(
kMaxOutstandingRequestsCostPerProcess),
- receiver_(NULL) {
+ filter_(NULL) {
ResourceQueue::DelegateSet resource_queue_delegates;
resource_queue_delegates.insert(user_script_listener_.get());
resource_queue_.Initialize(resource_queue_delegates);
@@ -246,7 +237,7 @@ void ResourceDispatcherHost::Shutdown() {
}
void ResourceDispatcherHost::SetRequestInfo(
- URLRequest* request,
+ net::URLRequest* request,
ResourceDispatcherHostRequestInfo* info) {
request->SetUserData(NULL, info);
}
@@ -285,7 +276,7 @@ bool ResourceDispatcherHost::HandleExternalProtocol(int request_id,
const GURL& url,
ResourceType::Type type,
ResourceHandler* handler) {
- if (!ResourceType::IsFrame(type) || URLRequest::IsHandledURL(url))
+ if (!ResourceType::IsFrame(type) || net::URLRequest::IsHandledURL(url))
return false;
BrowserThread::PostTask(
@@ -301,16 +292,10 @@ bool ResourceDispatcherHost::HandleExternalProtocol(int request_id,
}
bool ResourceDispatcherHost::OnMessageReceived(const IPC::Message& message,
- Receiver* receiver,
+ ResourceMessageFilter* filter,
bool* message_was_ok) {
- if (!IsResourceDispatcherHostMessage(message)) {
- return socket_stream_dispatcher_host_->OnMessageReceived(
- message, receiver, message_was_ok);
- }
-
- *message_was_ok = true;
- receiver_ = receiver;
-
+ filter_ = filter;
+ bool handled = true;
IPC_BEGIN_MESSAGE_MAP_EX(ResourceDispatcherHost, message, *message_was_ok)
IPC_MESSAGE_HANDLER(ViewHostMsg_RequestResource, OnRequestResource)
IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_SyncLoad, OnSyncLoad)
@@ -322,11 +307,11 @@ bool ResourceDispatcherHost::OnMessageReceived(const IPC::Message& message,
IPC_MESSAGE_HANDLER(ViewHostMsg_CancelRequest, OnCancelRequest)
IPC_MESSAGE_HANDLER(ViewHostMsg_FollowRedirect, OnFollowRedirect)
IPC_MESSAGE_HANDLER(ViewHostMsg_ClosePage_ACK, OnClosePageACK)
+ IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP_EX()
- receiver_ = NULL;
-
- return true;
+ filter_ = NULL;
+ return handled;
}
void ResourceDispatcherHost::OnRequestResource(
@@ -357,18 +342,11 @@ void ResourceDispatcherHost::BeginRequest(
const ViewHostMsg_Resource_Request& request_data,
IPC::Message* sync_result, // only valid for sync
int route_id) {
- ChildProcessInfo::ProcessType process_type = receiver_->type();
- int child_id = receiver_->id();
- ChromeURLRequestContext* context = static_cast<ChromeURLRequestContext*>(
- receiver_->GetRequestContext(request_id, request_data));
- if (!context) {
- URLRequestContextGetter* context_getter =
- Profile::GetDefaultRequestContext();
- if (context_getter) {
- context = static_cast<ChromeURLRequestContext*>(
- context_getter->GetURLRequestContext());
- }
- }
+ ChildProcessInfo::ProcessType process_type = filter_->process_type();
+ int child_id = filter_->child_id();
+
+ ChromeURLRequestContext* context = filter_->GetURLRequestContext(
+ request_id, request_data.resource_type);
// Might need to resolve the blob references in the upload data.
if (request_data.upload_data && context) {
@@ -383,10 +361,10 @@ void ResourceDispatcherHost::BeginRequest(
SyncLoadResult result;
result.status = status;
ViewHostMsg_SyncLoad::WriteReplyParams(sync_result, result);
- receiver_->Send(sync_result);
+ filter_->Send(sync_result);
} else {
// Tell the renderer that this request was disallowed.
- receiver_->Send(new ViewMsg_Resource_RequestComplete(
+ filter_->Send(new ViewMsg_Resource_RequestComplete(
route_id,
request_id,
status,
@@ -405,18 +383,11 @@ void ResourceDispatcherHost::BeginRequest(
// Construct the event handler.
scoped_refptr<ResourceHandler> handler;
if (sync_result) {
- handler = new SyncResourceHandler(receiver_,
- child_id,
- request_data.url,
- sync_result,
- this);
+ handler = new SyncResourceHandler(
+ filter_, request_data.url, sync_result, this);
} else {
- handler = new AsyncResourceHandler(receiver_,
- child_id,
- route_id,
- receiver_->handle(),
- request_data.url,
- this);
+ handler = new AsyncResourceHandler(
+ filter_, route_id, request_data.url, this);
}
// The RedirectToFileResourceHandler depends on being next in the chain.
@@ -430,7 +401,7 @@ void ResourceDispatcherHost::BeginRequest(
}
// Construct the request.
- URLRequest* request = new URLRequest(request_data.url, this);
+ net::URLRequest* request = new net::URLRequest(request_data.url, this);
request->set_method(request_data.method);
request->set_first_party_for_cookies(request_data.first_party_for_cookies);
request->set_referrer(CommandLine::ForCurrentProcess()->HasSwitch(
@@ -478,7 +449,7 @@ void ResourceDispatcherHost::BeginRequest(
// not count as cross-site, otherwise it gets blocked indefinitely.
if (request_data.resource_type == ResourceType::MAIN_FRAME &&
process_type == ChildProcessInfo::RENDER_PROCESS &&
- Singleton<CrossSiteRequestManager>::get()->
+ CrossSiteRequestManager::GetInstance()->
HasPendingCrossSiteRequest(child_id, route_id)) {
// Wrap the event handler to be sure the current page's onunload handler
// has a chance to run before we render the new page.
@@ -518,7 +489,8 @@ void ResourceDispatcherHost::BeginRequest(
request_data.resource_type,
upload_size,
false, // is download
- ResourceType::IsFrame(request_data.resource_type), // allow_download
+ ResourceType::IsFrame(request_data.resource_type), // allow_download
+ request_data.has_user_gesture,
request_data.host_renderer_id,
request_data.host_render_view_id);
ApplyExtensionLocalizationFilter(request_data.url, request_data.resource_type,
@@ -546,12 +518,13 @@ void ResourceDispatcherHost::BeginRequest(
void ResourceDispatcherHost::OnReleaseDownloadedFile(int request_id) {
DCHECK(pending_requests_.end() ==
- pending_requests_.find(GlobalRequestID(receiver_->id(), request_id)));
- UnregisterDownloadedTempFile(receiver_->id(), request_id);
+ pending_requests_.find(
+ GlobalRequestID(filter_->child_id(), request_id)));
+ UnregisterDownloadedTempFile(filter_->child_id(), request_id);
}
void ResourceDispatcherHost::OnDataReceivedACK(int request_id) {
- DataReceivedACK(receiver_->id(), request_id);
+ DataReceivedACK(filter_->child_id(), request_id);
}
void ResourceDispatcherHost::DataReceivedACK(int child_id,
@@ -582,22 +555,21 @@ void ResourceDispatcherHost::OnDataDownloadedACK(int request_id) {
}
void ResourceDispatcherHost::RegisterDownloadedTempFile(
- int receiver_id, int request_id, DeletableFileReference* reference) {
- // Note: receiver_id is the child_id is the render_process_id...
- registered_temp_files_[receiver_id][request_id] = reference;
+ int child_id, int request_id, DeletableFileReference* reference) {
+ registered_temp_files_[child_id][request_id] = reference;
ChildProcessSecurityPolicy::GetInstance()->GrantReadFile(
- receiver_id, reference->path());
+ child_id, reference->path());
}
void ResourceDispatcherHost::UnregisterDownloadedTempFile(
- int receiver_id, int request_id) {
- DeletableFilesMap& map = registered_temp_files_[receiver_id];
+ int child_id, int request_id) {
+ DeletableFilesMap& map = registered_temp_files_[child_id];
DeletableFilesMap::iterator found = map.find(request_id);
if (found == map.end())
return;
ChildProcessSecurityPolicy::GetInstance()->RevokeAllPermissionsForFile(
- receiver_id, found->second->path());
+ child_id, found->second->path());
map.erase(found);
}
@@ -607,7 +579,7 @@ bool ResourceDispatcherHost::Send(IPC::Message* message) {
}
void ResourceDispatcherHost::OnUploadProgressACK(int request_id) {
- int child_id = receiver_->id();
+ int child_id = filter_->child_id();
PendingRequestList::iterator i = pending_requests_.find(
GlobalRequestID(child_id, request_id));
if (i == pending_requests_.end())
@@ -618,14 +590,14 @@ void ResourceDispatcherHost::OnUploadProgressACK(int request_id) {
}
void ResourceDispatcherHost::OnCancelRequest(int request_id) {
- CancelRequest(receiver_->id(), request_id, true);
+ CancelRequest(filter_->child_id(), request_id, true);
}
void ResourceDispatcherHost::OnFollowRedirect(
int request_id,
bool has_new_first_party_for_cookies,
const GURL& new_first_party_for_cookies) {
- FollowDeferredRedirect(receiver_->id(), request_id,
+ FollowDeferredRedirect(filter_->child_id(), request_id,
has_new_first_party_for_cookies,
new_first_party_for_cookies);
}
@@ -633,13 +605,8 @@ void ResourceDispatcherHost::OnFollowRedirect(
ResourceHandler* ResourceDispatcherHost::CreateSafeBrowsingResourceHandler(
ResourceHandler* handler, int child_id, int route_id,
ResourceType::Type resource_type) {
- return new SafeBrowsingResourceHandler(handler,
- child_id,
- route_id,
- resource_type,
- safe_browsing_,
- this,
- receiver_);
+ return new SafeBrowsingResourceHandler(
+ handler, child_id, route_id, resource_type, safe_browsing_, this);
}
ResourceDispatcherHostRequestInfo*
@@ -650,14 +617,15 @@ ResourceDispatcherHost::CreateRequestInfoForBrowserRequest(
child_id,
route_id,
request_id_,
- "null", // frame_origin
- "null", // main_frame_origin
+ "null", // frame_origin
+ "null", // main_frame_origin
ResourceType::SUB_RESOURCE,
- 0, // upload_size
+ 0, // upload_size
download, // is_download
download, // allow_download
- -1, // Host renderer id
- -1); // Host render view id
+ false, // has_user_gesture
+ -1, // host renderer id
+ -1); // host render view id
}
void ResourceDispatcherHost::OnClosePageACK(
@@ -707,7 +675,7 @@ void ResourceDispatcherHost::BeginDownload(
// Ensure the Chrome plugins are loaded, as they may intercept network
// requests. Does nothing if they are already loaded.
PluginService::GetInstance()->LoadChromePlugins(this);
- URLRequest* request = new URLRequest(url, this);
+ net::URLRequest* request = new net::URLRequest(url, this);
request_id_--;
@@ -727,7 +695,7 @@ void ResourceDispatcherHost::BeginDownload(
ResourceType::MAIN_FRAME);
}
- if (!URLRequest::IsHandledURL(url)) {
+ if (!net::URLRequest::IsHandledURL(url)) {
VLOG(1) << "Download request for unsupported protocol: "
<< url.possibly_invalid_spec();
return;
@@ -768,7 +736,7 @@ void ResourceDispatcherHost::BeginSaveFile(const GURL& url,
save_file_manager_.get()));
request_id_--;
- bool known_proto = URLRequest::IsHandledURL(url);
+ bool known_proto = net::URLRequest::IsHandledURL(url);
if (!known_proto) {
// Since any URLs which have non-standard scheme have been filtered
// by save manager(see GURL::SchemeIsStandard). This situation
@@ -777,7 +745,7 @@ void ResourceDispatcherHost::BeginSaveFile(const GURL& url,
return;
}
- URLRequest* request = new URLRequest(url, this);
+ net::URLRequest* request = new net::URLRequest(url, this);
request->set_method("GET");
request->set_referrer(CommandLine::ForCurrentProcess()->HasSwitch(
switches::kNoReferrers) ? std::string() : referrer.spec());
@@ -826,7 +794,7 @@ void ResourceDispatcherHost::StartDeferredRequest(int process_unique_id,
// TODO(eroman): are there other considerations for paused or blocked
// requests?
- URLRequest* request = i->second;
+ net::URLRequest* request = i->second;
InsertIntoResourceQueue(request, *InfoForRequest(request));
}
@@ -894,7 +862,6 @@ int ResourceDispatcherHost::GetOutstandingRequestsMemoryCost(
// for downloads, which belong to the browser process even if initiated via a
// renderer.
void ResourceDispatcherHost::CancelRequestsForProcess(int child_id) {
- socket_stream_dispatcher_host_->CancelRequestsForProcess(child_id);
CancelRequestsForRoute(child_id, -1 /* cancel all */);
registered_temp_files_.erase(child_id);
}
@@ -927,11 +894,12 @@ void ResourceDispatcherHost::CancelRequestsForRoute(int child_id,
// Although every matching request was in pending_requests_ when we built
// matching_requests, it is normal for a matching request to be not found
// in pending_requests_ after we have removed some matching requests from
- // pending_requests_. For example, deleting a URLRequest that has
+ // pending_requests_. For example, deleting a net::URLRequest that has
// exclusive (write) access to an HTTP cache entry may unblock another
- // URLRequest that needs exclusive access to the same cache entry, and
- // that URLRequest may complete and remove itself from pending_requests_.
- // So we need to check that iter is not equal to pending_requests_.end().
+ // net::URLRequest that needs exclusive access to the same cache entry, and
+ // that net::URLRequest may complete and remove itself from
+ // pending_requests_. So we need to check that iter is not equal to
+ // pending_requests_.end().
if (iter != pending_requests_.end())
RemovePendingRequest(iter);
}
@@ -996,9 +964,9 @@ void ResourceDispatcherHost::RemovePendingRequest(
update_load_states_timer_.Stop();
}
-// URLRequest::Delegate -------------------------------------------------------
+// net::URLRequest::Delegate ---------------------------------------------------
-void ResourceDispatcherHost::OnReceivedRedirect(URLRequest* request,
+void ResourceDispatcherHost::OnReceivedRedirect(net::URLRequest* request,
const GURL& new_url,
bool* defer_redirect) {
VLOG(1) << "OnReceivedRedirect: " << request->url().spec();
@@ -1037,17 +1005,13 @@ void ResourceDispatcherHost::OnReceivedRedirect(URLRequest* request,
}
void ResourceDispatcherHost::OnAuthRequired(
- URLRequest* request,
+ net::URLRequest* request,
net::AuthChallengeInfo* auth_info) {
- if (request->load_flags() & net::LOAD_PREFETCH) {
- request->CancelAuth();
- return;
- }
// Create a login dialog on the UI thread to get authentication data,
// or pull from cache and continue on the IO thread.
// TODO(mpcomplete): We should block the parent tab while waiting for
// authentication.
- // That would also solve the problem of the URLRequest being cancelled
+ // That would also solve the problem of the net::URLRequest being cancelled
// before we receive authentication.
ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
DCHECK(!info->login_handler()) <<
@@ -1056,7 +1020,7 @@ void ResourceDispatcherHost::OnAuthRequired(
}
void ResourceDispatcherHost::OnCertificateRequested(
- URLRequest* request,
+ net::URLRequest* request,
net::SSLCertRequestInfo* cert_request_info) {
DCHECK(request);
@@ -1075,14 +1039,38 @@ void ResourceDispatcherHost::OnCertificateRequested(
}
void ResourceDispatcherHost::OnSSLCertificateError(
- URLRequest* request,
+ net::URLRequest* request,
int cert_error,
net::X509Certificate* cert) {
DCHECK(request);
SSLManager::OnSSLCertificateError(this, request, cert_error, cert);
}
-void ResourceDispatcherHost::OnSetCookie(URLRequest* request,
+void ResourceDispatcherHost::OnGetCookies(
+ net::URLRequest* request,
+ bool blocked_by_policy) {
+ VLOG(1) << "OnGetCookies: " << request->url().spec();
+
+ int render_process_id, render_view_id;
+ if (!RenderViewForRequest(request, &render_process_id, &render_view_id))
+ return;
+
+ ChromeURLRequestContext* context =
+ static_cast<ChromeURLRequestContext*>(request->context());
+ if (context->IsExternal())
+ return;
+
+ net::CookieMonster* cookie_monster =
+ context->cookie_store()->GetCookieMonster();
+ net::CookieList cookie_list =
+ cookie_monster->GetAllCookiesForURL(request->url());
+ CallRenderViewHostContentSettingsDelegate(
+ render_process_id, render_view_id,
+ &RenderViewHostDelegate::ContentSettings::OnCookiesRead,
+ request->url(), cookie_list, blocked_by_policy);
+}
+
+void ResourceDispatcherHost::OnSetCookie(net::URLRequest* request,
const std::string& cookie_line,
const net::CookieOptions& options,
bool blocked_by_policy) {
@@ -1094,11 +1082,11 @@ void ResourceDispatcherHost::OnSetCookie(URLRequest* request,
CallRenderViewHostContentSettingsDelegate(
render_process_id, render_view_id,
- &RenderViewHostDelegate::ContentSettings::OnCookieAccessed,
+ &RenderViewHostDelegate::ContentSettings::OnCookieChanged,
request->url(), cookie_line, options, blocked_by_policy);
}
-void ResourceDispatcherHost::OnResponseStarted(URLRequest* request) {
+void ResourceDispatcherHost::OnResponseStarted(net::URLRequest* request) {
VLOG(1) << "OnResponseStarted: " << request->url().spec();
ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
if (PauseRequestIfNeeded(info)) {
@@ -1129,7 +1117,7 @@ void ResourceDispatcherHost::OnResponseStarted(URLRequest* request) {
}
}
-bool ResourceDispatcherHost::CompleteResponseStarted(URLRequest* request) {
+bool ResourceDispatcherHost::CompleteResponseStarted(net::URLRequest* request) {
ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
scoped_refptr<ResourceResponse> response(new ResourceResponse);
@@ -1138,8 +1126,8 @@ bool ResourceDispatcherHost::CompleteResponseStarted(URLRequest* request) {
if (request->ssl_info().cert) {
int cert_id =
- CertStore::GetSharedInstance()->StoreCert(request->ssl_info().cert,
- info->child_id());
+ CertStore::GetInstance()->StoreCert(request->ssl_info().cert,
+ info->child_id());
response->response_head.security_info =
SSLManager::SerializeSecurityInfo(
cert_id, request->ssl_info().cert_status,
@@ -1173,7 +1161,7 @@ void ResourceDispatcherHost::CancelRequest(int child_id,
CancelRequestInternal(i->second, from_renderer);
}
-void ResourceDispatcherHost::CancelRequestInternal(URLRequest* request,
+void ResourceDispatcherHost::CancelRequestInternal(net::URLRequest* request,
bool from_renderer) {
VLOG(1) << "CancelRequest: " << request->url().spec();
@@ -1222,7 +1210,7 @@ int ResourceDispatcherHost::IncrementOutstandingRequestsMemoryCost(
// static
int ResourceDispatcherHost::CalculateApproximateMemoryCost(
- URLRequest* request) {
+ net::URLRequest* request) {
// The following fields should be a minor size contribution (experimentally
// on the order of 100). However since they are variable length, it could
// in theory be a sizeable contribution.
@@ -1257,7 +1245,7 @@ int ResourceDispatcherHost::CalculateApproximateMemoryCost(
return kAvgBytesPerOutstandingRequest + strings_cost + upload_cost;
}
-void ResourceDispatcherHost::BeginRequestInternal(URLRequest* request) {
+void ResourceDispatcherHost::BeginRequestInternal(net::URLRequest* request) {
DCHECK(!request->is_pending());
ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
@@ -1269,7 +1257,7 @@ void ResourceDispatcherHost::BeginRequestInternal(URLRequest* request) {
// If enqueing/starting this request will exceed our per-process memory
// bound, abort it right away.
if (memory_cost > max_outstanding_requests_cost_per_process_) {
- // We call "SimulateError()" as a way of setting the URLRequest's
+ // We call "SimulateError()" as a way of setting the net::URLRequest's
// status -- it has no effect beyond this, since the request hasn't started.
request->SimulateError(net::ERR_INSUFFICIENT_RESOURCES);
@@ -1292,7 +1280,7 @@ void ResourceDispatcherHost::BeginRequestInternal(URLRequest* request) {
GlobalRequestID global_id(info->child_id(), info->request_id());
pending_requests_[global_id] = request;
- // Give the resource handlers an opportunity to delay the URLRequest from
+ // Give the resource handlers an opportunity to delay the net::URLRequest from
// being started.
//
// There are three cases:
@@ -1317,7 +1305,7 @@ void ResourceDispatcherHost::BeginRequestInternal(URLRequest* request) {
}
void ResourceDispatcherHost::InsertIntoResourceQueue(
- URLRequest* request,
+ net::URLRequest* request,
const ResourceDispatcherHostRequestInfo& request_info) {
resource_queue_.AddRequest(request, request_info);
@@ -1341,7 +1329,7 @@ void ResourceDispatcherHost::ResumeRequest(const GlobalRequestID& request_id) {
if (i == pending_requests_.end()) // The request may have been destroyed
return;
- URLRequest* request = i->second;
+ net::URLRequest* request = i->second;
ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
if (!info->is_paused())
return;
@@ -1361,7 +1349,7 @@ void ResourceDispatcherHost::ResumeRequest(const GlobalRequestID& request_id) {
}
}
-void ResourceDispatcherHost::StartReading(URLRequest* request) {
+void ResourceDispatcherHost::StartReading(net::URLRequest* request) {
// Start reading.
int bytes_read = 0;
if (Read(request, &bytes_read)) {
@@ -1373,7 +1361,7 @@ void ResourceDispatcherHost::StartReading(URLRequest* request) {
}
}
-bool ResourceDispatcherHost::Read(URLRequest* request, int* bytes_read) {
+bool ResourceDispatcherHost::Read(net::URLRequest* request, int* bytes_read) {
ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
DCHECK(!info->is_paused());
@@ -1391,7 +1379,7 @@ bool ResourceDispatcherHost::Read(URLRequest* request, int* bytes_read) {
return request->Read(buf, buf_size, bytes_read);
}
-void ResourceDispatcherHost::OnReadCompleted(URLRequest* request,
+void ResourceDispatcherHost::OnReadCompleted(net::URLRequest* request,
int bytes_read) {
DCHECK(request);
VLOG(1) << "OnReadCompleted: " << request->url().spec();
@@ -1444,7 +1432,7 @@ void ResourceDispatcherHost::OnReadCompleted(URLRequest* request,
OnResponseCompleted(request);
}
-bool ResourceDispatcherHost::CompleteRead(URLRequest* request,
+bool ResourceDispatcherHost::CompleteRead(net::URLRequest* request,
int* bytes_read) {
if (!request || !request->status().is_success()) {
NOTREACHED();
@@ -1461,14 +1449,15 @@ bool ResourceDispatcherHost::CompleteRead(URLRequest* request,
return *bytes_read != 0;
}
-void ResourceDispatcherHost::OnResponseCompleted(URLRequest* request) {
+void ResourceDispatcherHost::OnResponseCompleted(net::URLRequest* request) {
VLOG(1) << "OnResponseCompleted: " << request->url().spec();
ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
// If the load for a main frame has failed, track it in a histogram,
// since it will probably cause the user to see an error page.
if (!request->status().is_success() &&
- info->resource_type() == ResourceType::MAIN_FRAME) {
+ info->resource_type() == ResourceType::MAIN_FRAME &&
+ request->status().os_error() != net::ERR_ABORTED) {
UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.ErrorCodesForMainFrame",
-request->status().os_error(),
GetAllNetErrorCodes());
@@ -1477,7 +1466,7 @@ void ResourceDispatcherHost::OnResponseCompleted(URLRequest* request) {
std::string security_info;
const net::SSLInfo& ssl_info = request->ssl_info();
if (ssl_info.cert != NULL) {
- int cert_id = CertStore::GetSharedInstance()->StoreCert(ssl_info.cert,
+ int cert_id = CertStore::GetInstance()->StoreCert(ssl_info.cert,
info->child_id());
security_info = SSLManager::SerializeSecurityInfo(
cert_id, ssl_info.cert_status, ssl_info.security_bits,
@@ -1498,16 +1487,16 @@ void ResourceDispatcherHost::OnResponseCompleted(URLRequest* request) {
// static
ResourceDispatcherHostRequestInfo* ResourceDispatcherHost::InfoForRequest(
- URLRequest* request) {
+ net::URLRequest* request) {
// Avoid writing this function twice by casting the cosnt version.
- const URLRequest* const_request = request;
+ const net::URLRequest* const_request = request;
return const_cast<ResourceDispatcherHostRequestInfo*>(
InfoForRequest(const_request));
}
// static
const ResourceDispatcherHostRequestInfo* ResourceDispatcherHost::InfoForRequest(
- const URLRequest* request) {
+ const net::URLRequest* request) {
const ResourceDispatcherHostRequestInfo* info =
static_cast<const ResourceDispatcherHostRequestInfo*>(
request->GetUserData(NULL));
@@ -1516,9 +1505,10 @@ const ResourceDispatcherHostRequestInfo* ResourceDispatcherHost::InfoForRequest(
}
// static
-bool ResourceDispatcherHost::RenderViewForRequest(const URLRequest* request,
- int* render_process_host_id,
- int* render_view_host_id) {
+bool ResourceDispatcherHost::RenderViewForRequest(
+ const net::URLRequest* request,
+ int* render_process_host_id,
+ int* render_view_host_id) {
const ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
if (!info) {
*render_process_host_id = -1;
@@ -1528,20 +1518,14 @@ bool ResourceDispatcherHost::RenderViewForRequest(const URLRequest* request,
// If the request is from the worker process, find a tab that owns the worker.
if (info->process_type() == ChildProcessInfo::WORKER_PROCESS) {
- const WorkerProcessHost::WorkerInstance* worker_instance =
- WorkerService::GetInstance()->FindWorkerInstance(info->child_id());
- if (!worker_instance) {
+ // Need to display some related UI for this network request - pick an
+ // arbitrary parent to do so.
+ if (!WorkerService::GetInstance()->GetRendererForWorker(
+ info->child_id(), render_process_host_id, render_view_host_id)) {
*render_process_host_id = -1;
*render_view_host_id = -1;
return false;
}
- DCHECK(!worker_instance->worker_document_set()->IsEmpty());
- const WorkerDocumentSet::DocumentInfoSet& parents =
- worker_instance->worker_document_set()->documents();
- // Need to display some related UI for this network request - pick an
- // arbitrary parent to do so.
- *render_process_host_id = parents.begin()->renderer_id();
- *render_view_host_id = parents.begin()->render_view_route_id();
} else {
*render_process_host_id = info->child_id();
*render_view_host_id = info->route_id();
@@ -1557,7 +1541,7 @@ void ResourceDispatcherHost::RemoveObserver(Observer* obs) {
observer_list_.RemoveObserver(obs);
}
-URLRequest* ResourceDispatcherHost::GetURLRequest(
+net::URLRequest* ResourceDispatcherHost::GetURLRequest(
const GlobalRequestID& request_id) const {
// This should be running in the IO loop.
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
@@ -1569,24 +1553,15 @@ URLRequest* ResourceDispatcherHost::GetURLRequest(
return i->second;
}
-static int GetCertID(URLRequest* request, int child_id) {
+static int GetCertID(net::URLRequest* request, int child_id) {
if (request->ssl_info().cert) {
- return CertStore::GetSharedInstance()->StoreCert(request->ssl_info().cert,
- child_id);
- }
- // If there is no SSL info attached to this request, we must either be a non
- // secure request, or the request has been canceled or failed (before the SSL
- // info was populated), or the response is an error (we have seen 403, 404,
- // and 501) made up by the proxy.
- DCHECK(!request->url().SchemeIsSecure() ||
- (request->status().status() == URLRequestStatus::CANCELED) ||
- (request->status().status() == URLRequestStatus::FAILED) ||
- ((request->response_headers()->response_code() >= 400) &&
- (request->response_headers()->response_code() <= 599)));
+ return CertStore::GetInstance()->StoreCert(request->ssl_info().cert,
+ child_id);
+ }
return 0;
}
-void ResourceDispatcherHost::NotifyResponseStarted(URLRequest* request,
+void ResourceDispatcherHost::NotifyResponseStarted(net::URLRequest* request,
int child_id) {
// Notify the observers on the IO thread.
FOR_EACH_OBSERVER(Observer, observer_list_, OnRequestStarted(this, request));
@@ -1602,14 +1577,14 @@ void ResourceDispatcherHost::NotifyResponseStarted(URLRequest* request,
ResourceRequestDetails(request, GetCertID(request, child_id)));
}
-void ResourceDispatcherHost::NotifyResponseCompleted(URLRequest* request,
+void ResourceDispatcherHost::NotifyResponseCompleted(net::URLRequest* request,
int child_id) {
// Notify the observers on the IO thread.
FOR_EACH_OBSERVER(Observer, observer_list_,
OnResponseCompleted(this, request));
}
-void ResourceDispatcherHost::NotifyReceivedRedirect(URLRequest* request,
+void ResourceDispatcherHost::NotifyReceivedRedirect(net::URLRequest* request,
int child_id,
const GURL& new_url) {
// Notify the observers on the IO thread.
@@ -1691,7 +1666,7 @@ void ResourceDispatcherHost::UpdateLoadStates() {
// in each View (good chance it's zero).
std::map<std::pair<int, int>, uint64> largest_upload_size;
for (i = pending_requests_.begin(); i != pending_requests_.end(); ++i) {
- URLRequest* request = i->second;
+ net::URLRequest* request = i->second;
ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
uint64 upload_size = info->upload_size();
if (request->GetLoadState() != net::LOAD_STATE_SENDING_REQUEST)
@@ -1702,7 +1677,7 @@ void ResourceDispatcherHost::UpdateLoadStates() {
}
for (i = pending_requests_.begin(); i != pending_requests_.end(); ++i) {
- URLRequest* request = i->second;
+ net::URLRequest* request = i->second;
net::LoadState load_state = request->GetLoadState();
ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
@@ -1751,7 +1726,7 @@ void ResourceDispatcherHost::UpdateLoadStates() {
// Returns true iff an upload progress message should be sent to the UI thread.
bool ResourceDispatcherHost::MaybeUpdateUploadProgress(
ResourceDispatcherHostRequestInfo *info,
- URLRequest *request) {
+ net::URLRequest *request) {
if (!info->upload_size() || info->waiting_for_upload_progress_ack())
return false;
@@ -1822,7 +1797,7 @@ void ResourceDispatcherHost::ProcessBlockedRequestsForRoute(
req_iter != requests->end(); ++req_iter) {
// Remove the memory credit that we added when pushing the request onto
// the blocked list.
- URLRequest* request = *req_iter;
+ net::URLRequest* request = *req_iter;
ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
IncrementOutstandingRequestsMemoryCost(-1 * info->memory_cost(),
info->child_id());
@@ -1835,7 +1810,7 @@ void ResourceDispatcherHost::ProcessBlockedRequestsForRoute(
delete requests;
}
-bool ResourceDispatcherHost::IsValidRequest(URLRequest* request) {
+bool ResourceDispatcherHost::IsValidRequest(net::URLRequest* request) {
if (!request)
return false;
ResourceDispatcherHostRequestInfo* info = InfoForRequest(request);
@@ -1845,28 +1820,6 @@ bool ResourceDispatcherHost::IsValidRequest(URLRequest* request) {
}
// static
-bool ResourceDispatcherHost::IsResourceDispatcherHostMessage(
- const IPC::Message& message) {
- switch (message.type()) {
- case ViewHostMsg_RequestResource::ID:
- case ViewHostMsg_CancelRequest::ID:
- case ViewHostMsg_FollowRedirect::ID:
- case ViewHostMsg_ClosePage_ACK::ID:
- case ViewHostMsg_ReleaseDownloadedFile::ID:
- case ViewHostMsg_DataReceived_ACK::ID:
- case ViewHostMsg_DataDownloaded_ACK::ID:
- case ViewHostMsg_UploadProgress_ACK::ID:
- case ViewHostMsg_SyncLoad::ID:
- return true;
-
- default:
- break;
- }
-
- return false;
-}
-
-// static
void ResourceDispatcherHost::ApplyExtensionLocalizationFilter(
const GURL& url,
const ResourceType::Type& resource_type,
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host.h b/chrome/browser/renderer_host/resource_dispatcher_host.h
index 7fc27b8..9d1924d 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host.h
+++ b/chrome/browser/renderer_host/resource_dispatcher_host.h
@@ -35,9 +35,9 @@ class LoginHandler;
class PluginService;
class ResourceDispatcherHostRequestInfo;
class ResourceHandler;
+class ResourceMessageFilter;
class SafeBrowsingService;
class SaveFileManager;
-class SocketStreamDispatcherHost;
class SSLClientAuthHandler;
class UserScriptListener;
class URLRequestContext;
@@ -51,44 +51,18 @@ namespace webkit_blob {
class DeletableFileReference;
}
-class ResourceDispatcherHost : public URLRequest::Delegate {
+class ResourceDispatcherHost : public net::URLRequest::Delegate {
public:
- // Implemented by the client of ResourceDispatcherHost to receive messages in
- // response to a resource load. The messages are intended to be forwarded to
- // the ResourceDispatcher in the child process via an IPC channel that the
- // client manages.
- //
- // NOTE: This class unfortunately cannot be named 'Delegate' because that
- // conflicts with the name of ResourceDispatcherHost's base class.
- //
- // If the receiver is unable to send a given message (i.e., if Send returns
- // false), then the ResourceDispatcherHost assumes the receiver has failed,
- // and the given request will be dropped. (This happens, for example, when a
- // renderer crashes and the channel dies).
- class Receiver : public IPC::Message::Sender,
- public ChildProcessInfo {
- public:
- // Returns the URLRequestContext for the given request.
- // If NULL is returned, the default context for the profile is used.
- virtual URLRequestContext* GetRequestContext(
- uint32 request_id,
- const ViewHostMsg_Resource_Request& request_data) = 0;
-
- protected:
- explicit Receiver(ChildProcessInfo::ProcessType type, int child_id);
- virtual ~Receiver();
- };
-
class Observer {
public:
virtual ~Observer() {}
virtual void OnRequestStarted(ResourceDispatcherHost* resource_dispatcher,
- URLRequest* request) = 0;
+ net::URLRequest* request) = 0;
virtual void OnResponseCompleted(
ResourceDispatcherHost* resource_dispatcher,
- URLRequest* request) = 0;
+ net::URLRequest* request) = 0;
virtual void OnReceivedRedirect(ResourceDispatcherHost* resource_dispatcher,
- URLRequest* request,
+ net::URLRequest* request,
const GURL& new_url) = 0;
};
@@ -104,7 +78,7 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
// Returns true if the message was a resource message that was processed.
// If it was, message_was_ok will be false iff the message was corrupt.
bool OnMessageReceived(const IPC::Message& message,
- Receiver* receiver,
+ ResourceMessageFilter* filter,
bool* message_was_ok);
// Initiates a download from the browser process (as opposed to a resource
@@ -202,37 +176,40 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
// acts like CancelRequestsForProcess when route_id is -1.
void CancelRequestsForRoute(int process_unique_id, int route_id);
- // URLRequest::Delegate
- virtual void OnReceivedRedirect(URLRequest* request,
+ // net::URLRequest::Delegate
+ virtual void OnReceivedRedirect(net::URLRequest* request,
const GURL& new_url,
bool* defer_redirect);
- virtual void OnAuthRequired(URLRequest* request,
+ virtual void OnAuthRequired(net::URLRequest* request,
net::AuthChallengeInfo* auth_info);
virtual void OnCertificateRequested(
- URLRequest* request,
+ net::URLRequest* request,
net::SSLCertRequestInfo* cert_request_info);
- virtual void OnSSLCertificateError(URLRequest* request,
+ virtual void OnSSLCertificateError(net::URLRequest* request,
int cert_error,
net::X509Certificate* cert);
- virtual void OnSetCookie(URLRequest* request,
+ virtual void OnGetCookies(net::URLRequest* request,
+ bool blocked_by_policy);
+ virtual void OnSetCookie(net::URLRequest* request,
const std::string& cookie_line,
const net::CookieOptions& options,
bool blocked_by_policy);
- virtual void OnResponseStarted(URLRequest* request);
- virtual void OnReadCompleted(URLRequest* request, int bytes_read);
- void OnResponseCompleted(URLRequest* request);
+ virtual void OnResponseStarted(net::URLRequest* request);
+ virtual void OnReadCompleted(net::URLRequest* request, int bytes_read);
+ void OnResponseCompleted(net::URLRequest* request);
// Helper functions to get our extra data out of a request. The given request
// must have been one we created so that it has the proper extra data pointer.
- static ResourceDispatcherHostRequestInfo* InfoForRequest(URLRequest* request);
+ static ResourceDispatcherHostRequestInfo* InfoForRequest(
+ net::URLRequest* request);
static const ResourceDispatcherHostRequestInfo* InfoForRequest(
- const URLRequest* request);
+ const net::URLRequest* request);
// Extracts the render view/process host's identifiers from the given request
// and places them in the given out params (both required). If there are no
// such IDs associated with the request (such as non-page-related requests),
// this function will return false and both out params will be -1.
- static bool RenderViewForRequest(const URLRequest* request,
+ static bool RenderViewForRequest(const net::URLRequest* request,
int* render_process_host_id,
int* render_view_host_id);
@@ -244,11 +221,11 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
// Removes an observer.
void RemoveObserver(Observer* obs);
- // Retrieves a URLRequest. Must be called from the IO thread.
- URLRequest* GetURLRequest(const GlobalRequestID& request_id) const;
+ // Retrieves a net::URLRequest. Must be called from the IO thread.
+ net::URLRequest* GetURLRequest(const GlobalRequestID& request_id) const;
// Notifies our observers that a request has been cancelled.
- void NotifyResponseCompleted(URLRequest* request, int process_unique_id);
+ void NotifyResponseCompleted(net::URLRequest* request, int process_unique_id);
void RemovePendingRequest(int process_unique_id, int request_id);
@@ -274,9 +251,9 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
// child process and to defer deletion of the file until it's
// no longer needed.
void RegisterDownloadedTempFile(
- int receiver_id, int request_id,
+ int child_id, int request_id,
webkit_blob::DeletableFileReference* reference);
- void UnregisterDownloadedTempFile(int receiver_id, int request_id);
+ void UnregisterDownloadedTempFile(int child_id, int request_id);
// Needed for the sync IPC message dispatcher macros.
bool Send(IPC::Message* message);
@@ -304,7 +281,7 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
// Associates the given info with the given request. The info will then be
// owned by the request.
- void SetRequestInfo(URLRequest* request,
+ void SetRequestInfo(net::URLRequest* request,
ResourceDispatcherHostRequestInfo* info);
// A shutdown helper that runs on the IO thread.
@@ -317,36 +294,36 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
void ResumeRequest(const GlobalRequestID& request_id);
// Internal function to start reading for the first time.
- void StartReading(URLRequest* request);
+ void StartReading(net::URLRequest* request);
// Reads data from the response using our internal buffer as async IO.
// Returns true if data is available immediately, false otherwise. If the
// return value is false, we will receive a OnReadComplete() callback later.
- bool Read(URLRequest* request, int* bytes_read);
+ bool Read(net::URLRequest* request, int* bytes_read);
// Internal function to finish an async IO which has completed. Returns
// true if there is more data to read (e.g. we haven't read EOF yet and
// no errors have occurred).
- bool CompleteRead(URLRequest*, int* bytes_read);
+ bool CompleteRead(net::URLRequest*, int* bytes_read);
// Internal function to finish handling the ResponseStarted message. Returns
// true on success.
- bool CompleteResponseStarted(URLRequest* request);
+ bool CompleteResponseStarted(net::URLRequest* request);
// Helper function for regular and download requests.
- void BeginRequestInternal(URLRequest* request);
+ void BeginRequestInternal(net::URLRequest* request);
// Helper function that cancels |request|.
- void CancelRequestInternal(URLRequest* request, bool from_renderer);
+ void CancelRequestInternal(net::URLRequest* request, bool from_renderer);
// Helper function that inserts |request| into the resource queue.
void InsertIntoResourceQueue(
- URLRequest* request,
+ net::URLRequest* request,
const ResourceDispatcherHostRequestInfo& request_info);
// Updates the "cost" of outstanding requests for |process_unique_id|.
// The "cost" approximates how many bytes are consumed by all the in-memory
- // data structures supporting this request (URLRequest object,
+ // data structures supporting this request (net::URLRequest object,
// HttpNetworkTransaction, etc...).
// The value of |cost| is added to the running total, and the resulting
// sum is returned.
@@ -354,7 +331,7 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
int process_unique_id);
// Estimate how much heap space |request| will consume to run.
- static int CalculateApproximateMemoryCost(URLRequest* request);
+ static int CalculateApproximateMemoryCost(net::URLRequest* request);
// The list of all requests that we have pending. This list is not really
// optimized, and assumes that we have relatively few requests pending at once
@@ -363,7 +340,7 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
// It may be enhanced in the future to provide some kind of prioritization
// mechanism. We should also consider a hashtable or binary tree if it turns
// out we have a lot of things here.
- typedef std::map<GlobalRequestID, URLRequest*> PendingRequestList;
+ typedef std::map<GlobalRequestID, net::URLRequest*> PendingRequestList;
// Deletes the pending request identified by the iterator passed in.
// This function will invalidate the iterator passed in. Callers should
@@ -371,10 +348,10 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
void RemovePendingRequest(const PendingRequestList::iterator& iter);
// Notify our observers that we started receiving a response for a request.
- void NotifyResponseStarted(URLRequest* request, int process_unique_id);
+ void NotifyResponseStarted(net::URLRequest* request, int process_unique_id);
// Notify our observers that a request has been redirected.
- void NotifyReceivedRedirect(URLRequest* request,
+ void NotifyReceivedRedirect(net::URLRequest* request,
int process_unique_id,
const GURL& new_url);
@@ -393,7 +370,7 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
// Checks the upload state and sends an update if one is necessary.
bool MaybeUpdateUploadProgress(ResourceDispatcherHostRequestInfo *info,
- URLRequest *request);
+ net::URLRequest *request);
// Resumes or cancels (if |cancel_requests| is true) any blocked requests.
void ProcessBlockedRequestsForRoute(int process_unique_id,
@@ -430,10 +407,7 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
ResourceHandler* handler, int child_id, int route_id, bool download);
// Returns true if |request| is in |pending_requests_|.
- bool IsValidRequest(URLRequest* request);
-
- // Returns true if the message passed in is a resource related message.
- static bool IsResourceDispatcherHostMessage(const IPC::Message&);
+ bool IsValidRequest(net::URLRequest* request);
// Sets replace_extension_localization_templates on all text/css requests that
// have "chrome-extension://" scheme.
@@ -477,8 +451,6 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
scoped_refptr<SafeBrowsingService> safe_browsing_;
- scoped_ptr<SocketStreamDispatcherHost> socket_stream_dispatcher_host_;
-
// We own the WebKit thread and see to its destruction.
scoped_ptr<WebKitThread> webkit_thread_;
@@ -500,7 +472,7 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
// True if the resource dispatcher host has been shut down.
bool is_shutdown_;
- typedef std::vector<URLRequest*> BlockedRequestsList;
+ typedef std::vector<net::URLRequest*> BlockedRequestsList;
typedef std::pair<int, int> ProcessRouteIDs;
typedef std::map<ProcessRouteIDs, BlockedRequestsList*> BlockedRequestMap;
BlockedRequestMap blocked_requests_map_;
@@ -521,7 +493,7 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
// Used during IPC message dispatching so that the handlers can get a pointer
// to the source of the message.
- Receiver* receiver_;
+ ResourceMessageFilter* filter_;
static bool is_prefetch_enabled_;
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host_request_info.cc b/chrome/browser/renderer_host/resource_dispatcher_host_request_info.cc
index 30ca189..65f89cb 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host_request_info.cc
+++ b/chrome/browser/renderer_host/resource_dispatcher_host_request_info.cc
@@ -4,9 +4,9 @@
#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
-#include "chrome/browser/login_prompt.h"
#include "chrome/browser/renderer_host/resource_handler.h"
#include "chrome/browser/ssl/ssl_client_auth_handler.h"
+#include "chrome/browser/ui/login/login_prompt.h"
#include "webkit/blob/blob_data.h"
ResourceDispatcherHostRequestInfo::ResourceDispatcherHostRequestInfo(
@@ -21,6 +21,7 @@ ResourceDispatcherHostRequestInfo::ResourceDispatcherHostRequestInfo(
uint64 upload_size,
bool is_download,
bool allow_download,
+ bool has_user_gesture,
int host_renderer_id,
int host_render_view_id)
: resource_handler_(handler),
@@ -32,6 +33,7 @@ ResourceDispatcherHostRequestInfo::ResourceDispatcherHostRequestInfo(
pending_data_count_(0),
is_download_(is_download),
allow_download_(allow_download),
+ has_user_gesture_(has_user_gesture),
pause_count_(0),
frame_origin_(frame_origin),
main_frame_origin_(main_frame_origin),
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host_request_info.h b/chrome/browser/renderer_host/resource_dispatcher_host_request_info.h
index 9d5e386..5c92a45 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host_request_info.h
+++ b/chrome/browser/renderer_host/resource_dispatcher_host_request_info.h
@@ -27,7 +27,7 @@ class BlobData;
// Holds the data ResourceDispatcherHost associates with each request.
// Retrieve this data by calling ResourceDispatcherHost::InfoForRequest.
-class ResourceDispatcherHostRequestInfo : public URLRequest::UserData {
+class ResourceDispatcherHostRequestInfo : public net::URLRequest::UserData {
public:
// This will take a reference to the handler.
ResourceDispatcherHostRequestInfo(
@@ -42,6 +42,7 @@ class ResourceDispatcherHostRequestInfo : public URLRequest::UserData {
uint64 upload_size,
bool is_download,
bool allow_download,
+ bool has_user_gesture,
int host_renderer_id,
int host_render_view_id);
virtual ~ResourceDispatcherHostRequestInfo();
@@ -95,6 +96,8 @@ class ResourceDispatcherHostRequestInfo : public URLRequest::UserData {
// Downloads are allowed only as a top level request.
bool allow_download() const { return allow_download_; }
+ bool has_user_gesture() const { return has_user_gesture_; }
+
// Whether this is a download.
bool is_download() const { return is_download_; }
void set_is_download(bool download) { is_download_ = download; }
@@ -165,7 +168,7 @@ class ResourceDispatcherHostRequestInfo : public URLRequest::UserData {
int host_render_view_id() const { return host_render_view_id_; }
// We hold a reference to the requested blob data to ensure it doesn't
- // get finally released prior to the URLRequestJob being started.
+ // get finally released prior to the net::URLRequestJob being started.
webkit_blob::BlobData* requested_blob_data() const {
return requested_blob_data_.get();
}
@@ -214,6 +217,7 @@ class ResourceDispatcherHostRequestInfo : public URLRequest::UserData {
int pending_data_count_;
bool is_download_;
bool allow_download_;
+ bool has_user_gesture_;
int pause_count_;
std::string frame_origin_;
std::string main_frame_origin_;
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc b/chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc
index 209bce3..5b6758c 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc
+++ b/chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc
@@ -12,6 +12,7 @@
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
#include "chrome/browser/renderer_host/resource_handler.h"
+#include "chrome/browser/renderer_host/resource_message_filter.h"
#include "chrome/common/chrome_plugin_lib.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/render_messages_params.h"
@@ -127,72 +128,65 @@ void ResourceIPCAccumulator::GetClassifiedMessages(ClassifiedMessages* msgs) {
}
// This class forwards the incoming messages to the ResourceDispatcherHostTest.
-// This is used to emulate different sub-procseses, since this receiver will
+// This is used to emulate different sub-processes, since this filter will
// have a different ID than the original. For the test, we want all the incoming
// messages to go to the same place, which is why this forwards.
-class ForwardingReceiver : public ResourceDispatcherHost::Receiver {
+class ForwardingFilter : public ResourceMessageFilter {
public:
- explicit ForwardingReceiver(ResourceDispatcherHost::Receiver* dest)
- : ResourceDispatcherHost::Receiver(dest->type(), -1),
+ explicit ForwardingFilter(IPC::Message::Sender* dest)
+ : ResourceMessageFilter(ChildProcessInfo::GenerateChildProcessUniqueId(),
+ ChildProcessInfo::RENDER_PROCESS,
+ NULL),
dest_(dest) {
- set_handle(dest->handle());
+ OnChannelConnected(base::GetCurrentProcId());
}
- // ResourceDispatcherHost::Receiver implementation
+ // ResourceMessageFilter override
virtual bool Send(IPC::Message* msg) {
+ if (!dest_)
+ return false;
return dest_->Send(msg);
}
- URLRequestContext* GetRequestContext(
- uint32 request_id,
- const ViewHostMsg_Resource_Request& request_data) {
- return dest_->GetRequestContext(request_id, request_data);
- }
private:
- ResourceDispatcherHost::Receiver* dest_;
+ IPC::Message::Sender* dest_;
- DISALLOW_COPY_AND_ASSIGN(ForwardingReceiver);
+ DISALLOW_COPY_AND_ASSIGN(ForwardingFilter);
};
class ResourceDispatcherHostTest : public testing::Test,
- public ResourceDispatcherHost::Receiver {
+ public IPC::Message::Sender {
public:
ResourceDispatcherHostTest()
- : Receiver(ChildProcessInfo::RENDER_PROCESS, -1),
+ : ALLOW_THIS_IN_INITIALIZER_LIST(filter_(new ForwardingFilter(this))),
ui_thread_(BrowserThread::UI, &message_loop_),
io_thread_(BrowserThread::IO, &message_loop_),
old_factory_(NULL),
resource_type_(ResourceType::SUB_RESOURCE) {
- set_handle(base::GetCurrentProcessHandle());
}
- // ResourceDispatcherHost::Receiver implementation
+ // IPC::Message::Sender implementation
virtual bool Send(IPC::Message* msg) {
accum_.AddMessage(*msg);
delete msg;
return true;
}
- URLRequestContext* GetRequestContext(
- uint32 request_id,
- const ViewHostMsg_Resource_Request& request_data) {
- return NULL;
- }
-
protected:
// testing::Test
virtual void SetUp() {
DCHECK(!test_fixture_);
test_fixture_ = this;
ChildProcessSecurityPolicy::GetInstance()->Add(0);
- URLRequest::RegisterProtocolFactory("test",
- &ResourceDispatcherHostTest::Factory);
+ net::URLRequest::RegisterProtocolFactory(
+ "test",
+ &ResourceDispatcherHostTest::Factory);
EnsureTestSchemeIsAllowed();
}
virtual void TearDown() {
- URLRequest::RegisterProtocolFactory("test", NULL);
+ net::URLRequest::RegisterProtocolFactory("test", NULL);
if (!scheme_.empty())
- URLRequest::RegisterProtocolFactory(scheme_, old_factory_);
+ net::URLRequest::RegisterProtocolFactory(scheme_, old_factory_);
DCHECK(test_fixture_ == this);
test_fixture_ = NULL;
@@ -209,14 +203,14 @@ class ResourceDispatcherHostTest : public testing::Test,
message_loop_.RunAllPending();
}
- // Creates a request using the current test object as the receiver.
+ // Creates a request using the current test object as the filter.
void MakeTestRequest(int render_view_id,
int request_id,
const GURL& url);
- // Generates a request using the given receiver. This will probably be a
- // ForwardingReceiver.
- void MakeTestRequest(ResourceDispatcherHost::Receiver* receiver,
+ // Generates a request using the given filter. This will probably be a
+ // ForwardingFilter.
+ void MakeTestRequest(ResourceMessageFilter* filter,
int render_view_id,
int request_id,
const GURL& url);
@@ -250,13 +244,13 @@ class ResourceDispatcherHostTest : public testing::Test,
DCHECK(scheme_.empty());
DCHECK(!old_factory_);
scheme_ = scheme;
- old_factory_ = URLRequest::RegisterProtocolFactory(
- scheme_, &ResourceDispatcherHostTest::Factory);
+ old_factory_ = net::URLRequest::RegisterProtocolFactory(
+ scheme_, &ResourceDispatcherHostTest::Factory);
}
- // Our own URLRequestJob factory.
- static URLRequestJob* Factory(URLRequest* request,
- const std::string& scheme) {
+ // Our own net::URLRequestJob factory.
+ static net::URLRequestJob* Factory(net::URLRequest* request,
+ const std::string& scheme) {
if (test_fixture_->response_headers_.empty()) {
return new URLRequestTestJob(request);
} else {
@@ -265,6 +259,7 @@ class ResourceDispatcherHostTest : public testing::Test,
}
}
+ scoped_refptr<ForwardingFilter> filter_;
MessageLoopForIO message_loop_;
BrowserThread ui_thread_;
BrowserThread io_thread_;
@@ -273,7 +268,7 @@ class ResourceDispatcherHostTest : public testing::Test,
std::string response_headers_;
std::string response_data_;
std::string scheme_;
- URLRequest::ProtocolFactory* old_factory_;
+ net::URLRequest::ProtocolFactory* old_factory_;
ResourceType::Type resource_type_;
static ResourceDispatcherHostTest* test_fixture_;
};
@@ -283,11 +278,11 @@ ResourceDispatcherHostTest* ResourceDispatcherHostTest::test_fixture_ = NULL;
void ResourceDispatcherHostTest::MakeTestRequest(int render_view_id,
int request_id,
const GURL& url) {
- MakeTestRequest(this, render_view_id, request_id, url);
+ MakeTestRequest(filter_.get(), render_view_id, request_id, url);
}
void ResourceDispatcherHostTest::MakeTestRequest(
- ResourceDispatcherHost::Receiver* receiver,
+ ResourceMessageFilter* filter,
int render_view_id,
int request_id,
const GURL& url) {
@@ -295,12 +290,12 @@ void ResourceDispatcherHostTest::MakeTestRequest(
CreateResourceRequest("GET", resource_type_, url);
ViewHostMsg_RequestResource msg(render_view_id, request_id, request);
bool msg_was_ok;
- host_.OnMessageReceived(msg, receiver, &msg_was_ok);
+ host_.OnMessageReceived(msg, filter, &msg_was_ok);
KickOffRequest();
}
void ResourceDispatcherHostTest::MakeCancelRequest(int request_id) {
- host_.CancelRequest(id(), request_id, false);
+ host_.CancelRequest(filter_->child_id(), request_id, false);
}
void CheckSuccessfulRequest(const std::vector<IPC::Message>& messages,
@@ -408,35 +403,31 @@ TEST_F(ResourceDispatcherHostTest, Cancel) {
EXPECT_EQ(URLRequestStatus::CANCELED, status.status());
}
+// The host delegate acts as a second one so we can have some requests
+// pending and some canceled.
+class TestFilter : public ForwardingFilter {
+ public:
+ TestFilter()
+ : ForwardingFilter(NULL),
+ has_canceled_(false),
+ received_after_canceled_(0) {
+ }
+
+ // ForwardingFilter override
+ virtual bool Send(IPC::Message* msg) {
+ // no messages should be received when the process has been canceled
+ if (has_canceled_)
+ received_after_canceled_++;
+ delete msg;
+ return true;
+ }
+ bool has_canceled_;
+ int received_after_canceled_;
+};
+
// Tests CancelRequestsForProcess
TEST_F(ResourceDispatcherHostTest, TestProcessCancel) {
- // the host delegate acts as a second one so we can have some requests
- // pending and some canceled
- class TestReceiver : public ResourceDispatcherHost::Receiver {
- public:
- TestReceiver()
- : Receiver(ChildProcessInfo::RENDER_PROCESS, -1),
- has_canceled_(false),
- received_after_canceled_(0) {
- }
-
- // ResourceDispatcherHost::Receiver implementation
- virtual bool Send(IPC::Message* msg) {
- // no messages should be received when the process has been canceled
- if (has_canceled_)
- received_after_canceled_++;
- delete msg;
- return true;
- }
- URLRequestContext* GetRequestContext(
- uint32 request_id,
- const ViewHostMsg_Resource_Request& request_data) {
- return NULL;
- }
- bool has_canceled_;
- int received_after_canceled_;
- };
- TestReceiver test_receiver;
+ scoped_refptr<TestFilter> test_filter = new TestFilter();
// request 1 goes to the test delegate
ViewHostMsg_Resource_Request request = CreateResourceRequest(
@@ -444,13 +435,13 @@ TEST_F(ResourceDispatcherHostTest, TestProcessCancel) {
EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(0));
- MakeTestRequest(&test_receiver, 0, 1, URLRequestTestJob::test_url_1());
+ MakeTestRequest(test_filter.get(), 0, 1, URLRequestTestJob::test_url_1());
// request 2 goes to us
MakeTestRequest(0, 2, URLRequestTestJob::test_url_2());
// request 3 goes to the test delegate
- MakeTestRequest(&test_receiver, 0, 3, URLRequestTestJob::test_url_3());
+ MakeTestRequest(test_filter.get(), 0, 3, URLRequestTestJob::test_url_3());
// TODO(mbelshe):
// Now that the async IO path is in place, the IO always completes on the
@@ -463,18 +454,17 @@ TEST_F(ResourceDispatcherHostTest, TestProcessCancel) {
EXPECT_TRUE(URLRequestTestJob::ProcessOnePendingMessage());
// Cancel the requests to the test process.
- host_.CancelRequestsForProcess(id());
- test_receiver.has_canceled_ = true;
+ host_.CancelRequestsForProcess(filter_->child_id());
+ test_filter->has_canceled_ = true;
// Flush all the pending requests.
while (URLRequestTestJob::ProcessOnePendingMessage()) {}
EXPECT_EQ(0, host_.pending_requests());
- EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(
- id()));
+ EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id()));
// The test delegate should not have gotten any messages after being canceled.
- ASSERT_EQ(0, test_receiver.received_after_canceled_);
+ ASSERT_EQ(0, test_filter->received_after_canceled_);
// We should have gotten exactly one result.
ResourceIPCAccumulator::ClassifiedMessages msgs;
@@ -485,12 +475,11 @@ TEST_F(ResourceDispatcherHostTest, TestProcessCancel) {
// Tests blocking and resuming requests.
TEST_F(ResourceDispatcherHostTest, TestBlockingResumingRequests) {
- EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(
- id()));
+ EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id()));
- host_.BlockRequestsForRoute(id(), 1);
- host_.BlockRequestsForRoute(id(), 2);
- host_.BlockRequestsForRoute(id(), 3);
+ host_.BlockRequestsForRoute(filter_->child_id(), 1);
+ host_.BlockRequestsForRoute(filter_->child_id(), 2);
+ host_.BlockRequestsForRoute(filter_->child_id(), 3);
MakeTestRequest(0, 1, URLRequestTestJob::test_url_1());
MakeTestRequest(1, 2, URLRequestTestJob::test_url_2());
@@ -513,7 +502,7 @@ TEST_F(ResourceDispatcherHostTest, TestBlockingResumingRequests) {
CheckSuccessfulRequest(msgs[1], URLRequestTestJob::test_data_3());
// Resume requests for RVH 1 and flush pending requests.
- host_.ResumeBlockedRequestsForRoute(id(), 1);
+ host_.ResumeBlockedRequestsForRoute(filter_->child_id(), 1);
KickOffRequest();
while (URLRequestTestJob::ProcessOnePendingMessage()) {}
@@ -532,13 +521,12 @@ TEST_F(ResourceDispatcherHostTest, TestBlockingResumingRequests) {
CheckSuccessfulRequest(msgs[0], URLRequestTestJob::test_data_1());
// Now resumes requests for all RVH (2 and 3).
- host_.ResumeBlockedRequestsForRoute(id(), 2);
- host_.ResumeBlockedRequestsForRoute(id(), 3);
+ host_.ResumeBlockedRequestsForRoute(filter_->child_id(), 2);
+ host_.ResumeBlockedRequestsForRoute(filter_->child_id(), 3);
KickOffRequest();
while (URLRequestTestJob::ProcessOnePendingMessage()) {}
- EXPECT_EQ(0,
- host_.GetOutstandingRequestsMemoryCost(id()));
+ EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id()));
msgs.clear();
accum_.GetClassifiedMessages(&msgs);
@@ -549,10 +537,9 @@ TEST_F(ResourceDispatcherHostTest, TestBlockingResumingRequests) {
// Tests blocking and canceling requests.
TEST_F(ResourceDispatcherHostTest, TestBlockingCancelingRequests) {
- EXPECT_EQ(0,
- host_.GetOutstandingRequestsMemoryCost(id()));
+ EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id()));
- host_.BlockRequestsForRoute(id(), 1);
+ host_.BlockRequestsForRoute(filter_->child_id(), 1);
MakeTestRequest(0, 1, URLRequestTestJob::test_url_1());
MakeTestRequest(1, 2, URLRequestTestJob::test_url_2());
@@ -573,12 +560,11 @@ TEST_F(ResourceDispatcherHostTest, TestBlockingCancelingRequests) {
CheckSuccessfulRequest(msgs[1], URLRequestTestJob::test_data_3());
// Cancel requests for RVH 1.
- host_.CancelBlockedRequestsForRoute(id(), 1);
+ host_.CancelBlockedRequestsForRoute(filter_->child_id(), 1);
KickOffRequest();
while (URLRequestTestJob::ProcessOnePendingMessage()) {}
- EXPECT_EQ(0,
- host_.GetOutstandingRequestsMemoryCost(id()));
+ EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id()));
msgs.clear();
accum_.GetClassifiedMessages(&msgs);
@@ -587,31 +573,29 @@ TEST_F(ResourceDispatcherHostTest, TestBlockingCancelingRequests) {
// Tests that blocked requests are canceled if their associated process dies.
TEST_F(ResourceDispatcherHostTest, TestBlockedRequestsProcessDies) {
- // This second receiver is used to emulate a second process.
- ForwardingReceiver second_receiver(this);
+ // This second filter is used to emulate a second process.
+ scoped_refptr<ForwardingFilter> second_filter = new ForwardingFilter(this);
- EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(
- id()));
- EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(
- second_receiver.id()));
+ EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id()));
+ EXPECT_EQ(0,
+ host_.GetOutstandingRequestsMemoryCost(second_filter->child_id()));
- host_.BlockRequestsForRoute(second_receiver.id(), 0);
+ host_.BlockRequestsForRoute(second_filter->child_id(), 0);
- MakeTestRequest(this, 0, 1, URLRequestTestJob::test_url_1());
- MakeTestRequest(&second_receiver, 0, 2, URLRequestTestJob::test_url_2());
- MakeTestRequest(this, 0, 3, URLRequestTestJob::test_url_3());
- MakeTestRequest(&second_receiver, 0, 4, URLRequestTestJob::test_url_1());
+ MakeTestRequest(filter_.get(), 0, 1, URLRequestTestJob::test_url_1());
+ MakeTestRequest(second_filter.get(), 0, 2, URLRequestTestJob::test_url_2());
+ MakeTestRequest(filter_.get(), 0, 3, URLRequestTestJob::test_url_3());
+ MakeTestRequest(second_filter.get(), 0, 4, URLRequestTestJob::test_url_1());
// Simulate process death.
- host_.CancelRequestsForProcess(second_receiver.id());
+ host_.CancelRequestsForProcess(second_filter->child_id());
// Flush all the pending requests.
while (URLRequestTestJob::ProcessOnePendingMessage()) {}
- EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(
- id()));
- EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(
- second_receiver.id()));
+ EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id()));
+ EXPECT_EQ(0,
+ host_.GetOutstandingRequestsMemoryCost(second_filter->child_id()));
// Sort out all the messages we saw by request.
ResourceIPCAccumulator::ClassifiedMessages msgs;
@@ -631,19 +615,19 @@ TEST_F(ResourceDispatcherHostTest, TestBlockedRequestsProcessDies) {
// If this test turns the Purify bot red, check the ResourceDispatcherHost
// destructor to make sure the blocked requests are deleted.
TEST_F(ResourceDispatcherHostTest, TestBlockedRequestsDontLeak) {
- // This second receiver is used to emulate a second process.
- ForwardingReceiver second_receiver(this);
+ // This second filter is used to emulate a second process.
+ scoped_refptr<ForwardingFilter> second_filter = new ForwardingFilter(this);
- host_.BlockRequestsForRoute(id(), 1);
- host_.BlockRequestsForRoute(id(), 2);
- host_.BlockRequestsForRoute(second_receiver.id(), 1);
+ host_.BlockRequestsForRoute(filter_->child_id(), 1);
+ host_.BlockRequestsForRoute(filter_->child_id(), 2);
+ host_.BlockRequestsForRoute(second_filter->child_id(), 1);
- MakeTestRequest(this, 0, 1, URLRequestTestJob::test_url_1());
- MakeTestRequest(this, 1, 2, URLRequestTestJob::test_url_2());
- MakeTestRequest(this, 0, 3, URLRequestTestJob::test_url_3());
- MakeTestRequest(&second_receiver, 1, 4, URLRequestTestJob::test_url_1());
- MakeTestRequest(this, 2, 5, URLRequestTestJob::test_url_2());
- MakeTestRequest(this, 2, 6, URLRequestTestJob::test_url_3());
+ MakeTestRequest(filter_.get(), 0, 1, URLRequestTestJob::test_url_1());
+ MakeTestRequest(filter_.get(), 1, 2, URLRequestTestJob::test_url_2());
+ MakeTestRequest(filter_.get(), 0, 3, URLRequestTestJob::test_url_3());
+ MakeTestRequest(second_filter.get(), 1, 4, URLRequestTestJob::test_url_1());
+ MakeTestRequest(filter_.get(), 2, 5, URLRequestTestJob::test_url_2());
+ MakeTestRequest(filter_.get(), 2, 6, URLRequestTestJob::test_url_3());
// Flush all the pending requests.
while (URLRequestTestJob::ProcessOnePendingMessage()) {}
@@ -651,7 +635,7 @@ TEST_F(ResourceDispatcherHostTest, TestBlockedRequestsDontLeak) {
// Test the private helper method "CalculateApproximateMemoryCost()".
TEST_F(ResourceDispatcherHostTest, CalculateApproximateMemoryCost) {
- URLRequest req(GURL("http://www.google.com"), NULL);
+ net::URLRequest req(GURL("http://www.google.com"), NULL);
EXPECT_EQ(4427, ResourceDispatcherHost::CalculateApproximateMemoryCost(&req));
// Add 9 bytes of referrer.
@@ -708,8 +692,7 @@ TEST_F(ResourceDispatcherHostTest, IncrementOutstandingRequestsMemoryCost) {
// Test that when too many requests are outstanding for a particular
// render_process_host_id, any subsequent request from it fails.
TEST_F(ResourceDispatcherHostTest, TooManyOutstandingRequests) {
- EXPECT_EQ(0,
- host_.GetOutstandingRequestsMemoryCost(id()));
+ EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id()));
// Expected cost of each request as measured by
// ResourceDispatcherHost::CalculateApproximateMemoryCost().
@@ -726,30 +709,31 @@ TEST_F(ResourceDispatcherHostTest, TooManyOutstandingRequests) {
// throttling kicks in.
size_t kMaxRequests = kMaxCostPerProcess / kMemoryCostOfTest2Req;
- // This second receiver is used to emulate a second process.
- ForwardingReceiver second_receiver(this);
+ // This second filter is used to emulate a second process.
+ scoped_refptr<ForwardingFilter> second_filter = new ForwardingFilter(this);
// Saturate the number of outstanding requests for our process.
for (size_t i = 0; i < kMaxRequests; ++i)
- MakeTestRequest(this, 0, i + 1, URLRequestTestJob::test_url_2());
+ MakeTestRequest(filter_.get(), 0, i + 1, URLRequestTestJob::test_url_2());
// Issue two more requests for our process -- these should fail immediately.
- MakeTestRequest(this, 0, kMaxRequests + 1, URLRequestTestJob::test_url_2());
- MakeTestRequest(this, 0, kMaxRequests + 2, URLRequestTestJob::test_url_2());
+ MakeTestRequest(filter_.get(), 0, kMaxRequests + 1,
+ URLRequestTestJob::test_url_2());
+ MakeTestRequest(filter_.get(), 0, kMaxRequests + 2,
+ URLRequestTestJob::test_url_2());
// Issue two requests for the second process -- these should succeed since
// it is just process 0 that is saturated.
- MakeTestRequest(&second_receiver, 0, kMaxRequests + 3,
+ MakeTestRequest(second_filter.get(), 0, kMaxRequests + 3,
URLRequestTestJob::test_url_2());
- MakeTestRequest(&second_receiver, 0, kMaxRequests + 4,
+ MakeTestRequest(second_filter.get(), 0, kMaxRequests + 4,
URLRequestTestJob::test_url_2());
// Flush all the pending requests.
while (URLRequestTestJob::ProcessOnePendingMessage()) {}
MessageLoop::current()->RunAllPending();
- EXPECT_EQ(0,
- host_.GetOutstandingRequestsMemoryCost(id()));
+ EXPECT_EQ(0, host_.GetOutstandingRequestsMemoryCost(filter_->child_id()));
// Sorts out all the messages we saw by request.
ResourceIPCAccumulator::ClassifiedMessages msgs;
@@ -1002,7 +986,7 @@ class ApplyExtensionLocalizationFilterTest : public testing::Test {
return new ResourceDispatcherHostRequestInfo(
resource_handler_.get(), ChildProcessInfo::RENDER_PROCESS, 0, 0, 0,
"not important", "not important",
- ResourceType::STYLESHEET, 0U, false, false, -1, -1);
+ ResourceType::STYLESHEET, 0U, false, false, false, -1, -1);
}
scoped_ptr<GURL> url_;
diff --git a/chrome/browser/renderer_host/resource_handler.h b/chrome/browser/renderer_host/resource_handler.h
index 56f70bd..bc05b17 100644
--- a/chrome/browser/renderer_host/resource_handler.h
+++ b/chrome/browser/renderer_host/resource_handler.h
@@ -48,11 +48,11 @@ class ResourceHandler
virtual bool OnResponseStarted(int request_id,
ResourceResponse* response) = 0;
- // Called before the URLRequest for |request_id| (whose url is |url|) is to be
- // started. If the handler returns false, then the request is cancelled.
+ // Called before the net::URLRequest for |request_id| (whose url is |url|) is
+ // to be started. If the handler returns false, then the request is cancelled.
// Otherwise if the return value is true, the ResourceHandler can delay the
// request from starting by setting |*defer = true|. A deferred request will
- // not have called URLRequest::Start(), and will not resume until someone
+ // not have called net::URLRequest::Start(), and will not resume until someone
// calls ResourceDispatcherHost::StartDeferredRequest().
virtual bool OnWillStart(int request_id, const GURL& url, bool* defer) = 0;
@@ -77,7 +77,7 @@ class ResourceHandler
const std::string& security_info) = 0;
// Signals that the request is closed (i.e. finished successfully, cancelled).
- // This is a signal that the associated URLRequest isn't valid anymore.
+ // This is a signal that the associated net::URLRequest isn't valid anymore.
virtual void OnRequestClosed() = 0;
// This notification is synthesized by the RedirectToFileResourceHandler
diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc
index a9c8c79..b8005f3 100644
--- a/chrome/browser/renderer_host/resource_message_filter.cc
+++ b/chrome/browser/renderer_host/resource_message_filter.cc
@@ -4,1839 +4,52 @@
#include "chrome/browser/renderer_host/resource_message_filter.h"
-#include "base/command_line.h"
-#include "base/file_util.h"
-#include "base/metrics/histogram.h"
-#include "base/process_util.h"
-#include "base/shared_memory.h"
-#include "base/sys_string_conversions.h"
-#include "base/thread.h"
-#include "base/utf_string_conversions.h"
-#include "base/worker_pool.h"
-#include "chrome/browser/appcache/appcache_dispatcher_host.h"
-#include "chrome/browser/automation/automation_resource_message_filter.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/child_process_security_policy.h"
-#include "chrome/browser/chrome_plugin_browsing_context.h"
-#include "chrome/browser/clipboard_dispatcher.h"
-#include "chrome/browser/device_orientation/dispatcher_host.h"
-#include "chrome/browser/download/download_types.h"
-#include "chrome/browser/extensions/extension_message_service.h"
-#include "chrome/browser/file_system/file_system_dispatcher_host.h"
-#include "chrome/browser/geolocation/geolocation_dispatcher_host_old.h"
-#include "chrome/browser/geolocation/geolocation_permission_context.h"
-#include "chrome/browser/gpu_process_host.h"
-#include "chrome/browser/host_zoom_map.h"
-#include "chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h"
-#include "chrome/browser/in_process_webkit/indexed_db_dispatcher_host.h"
-#include "chrome/browser/metrics/histogram_synchronizer.h"
-#include "chrome/browser/mime_registry_dispatcher.h"
-#include "chrome/browser/nacl_host/nacl_process_host.h"
#include "chrome/browser/net/chrome_url_request_context.h"
-#include "chrome/browser/net/predictor_api.h"
-#include "chrome/browser/notifications/desktop_notification_service.h"
-#include "chrome/browser/notifications/notifications_prefs_cache.h"
-#include "chrome/browser/platform_util.h"
-#include "chrome/browser/plugin_process_host.h"
-#include "chrome/browser/plugin_service.h"
-#include "chrome/browser/ppapi_plugin_process_host.h"
-#include "chrome/browser/printing/print_job_manager.h"
-#include "chrome/browser/printing/printer_query.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/renderer_host/audio_renderer_host.h"
-#include "chrome/browser/renderer_host/blob_dispatcher_host.h"
-#include "chrome/browser/renderer_host/browser_render_process_host.h"
-#include "chrome/browser/renderer_host/database_dispatcher_host.h"
-#include "chrome/browser/renderer_host/file_utilities_dispatcher_host.h"
-#include "chrome/browser/renderer_host/render_view_host_delegate.h"
-#include "chrome/browser/renderer_host/render_view_host_notification_task.h"
-#include "chrome/browser/renderer_host/render_widget_helper.h"
-#include "chrome/browser/search_engines/search_provider_install_state_dispatcher_host.h"
-#include "chrome/browser/speech/speech_input_dispatcher_host.h"
-#include "chrome/browser/spellchecker_platform_engine.h"
-#include "chrome/browser/task_manager/task_manager.h"
-#include "chrome/browser/worker_host/message_port_dispatcher.h"
-#include "chrome/browser/worker_host/worker_service.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/extensions/extension_file_util.h"
-#include "chrome/common/extensions/extension_message_bundle.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/common/render_messages.h"
-#include "chrome/common/render_messages_params.h"
-#include "chrome/common/url_constants.h"
-#include "ipc/ipc_channel_handle.h"
-#include "net/base/cookie_monster.h"
-#include "net/base/io_buffer.h"
-#include "net/base/keygen_handler.h"
-#include "net/base/mime_util.h"
-#include "net/base/net_errors.h"
-#include "net/disk_cache/disk_cache.h"
-#include "net/http/http_cache.h"
-#include "net/http/http_network_layer.h"
-#include "net/url_request/url_request_context.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebNotificationPresenter.h"
-#include "webkit/glue/context_menu.h"
-#include "webkit/glue/plugins/plugin_group.h"
-#include "webkit/glue/plugins/plugin_list.h"
-#include "webkit/glue/plugins/webplugin.h"
-#include "webkit/glue/webcookie.h"
-#include "webkit/glue/webkit_glue.h"
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/plugin_selection_policy.h"
-#endif
-#if defined(OS_MACOSX)
-#include "chrome/browser/cocoa/task_helpers.h"
-#include "chrome/common/font_descriptor_mac.h"
-#include "chrome/common/font_loader_mac.h"
-#endif
-#if defined(OS_POSIX)
-#include "base/file_descriptor_posix.h"
-#endif
-#if defined(OS_WIN)
-#include "chrome/common/child_process_host.h"
-#endif
-#if defined(USE_TCMALLOC)
-#include "chrome/browser/browser_about_handler.h"
-#endif
-
-using net::CookieStore;
-using WebKit::WebCache;
-
-namespace {
-
-const int kPluginsRefreshThresholdInSeconds = 3;
-
-// Context menus are somewhat complicated. We need to intercept them here on
-// the I/O thread to add any spelling suggestions to them. After that's done,
-// we need to forward the modified message to the UI thread and the normal
-// message forwarding isn't set up for sending modified messages.
-//
-// Therefore, this class dispatches the IPC message to the RenderProcessHost
-// with the given ID (if possible) to emulate the normal dispatch.
-class ContextMenuMessageDispatcher : public Task {
- public:
- ContextMenuMessageDispatcher(
- int render_process_id,
- const ViewHostMsg_ContextMenu& context_menu_message)
- : render_process_id_(render_process_id),
- context_menu_message_(context_menu_message) {
- }
-
- void Run() {
- RenderProcessHost* host =
- RenderProcessHost::FromID(render_process_id_);
- if (host)
- host->OnMessageReceived(context_menu_message_);
- }
-
- private:
- int render_process_id_;
- const ViewHostMsg_ContextMenu context_menu_message_;
-
- DISALLOW_COPY_AND_ASSIGN(ContextMenuMessageDispatcher);
-};
-
-// Completes a clipboard write initiated by the renderer. The write must be
-// performed on the UI thread because the clipboard service from the IO thread
-// cannot create windows so it cannot be the "owner" of the clipboard's
-// contents.
-class WriteClipboardTask : public Task {
- public:
- explicit WriteClipboardTask(Clipboard::ObjectMap* objects)
- : objects_(objects) {}
- ~WriteClipboardTask() {}
-
- void Run() {
- g_browser_process->clipboard()->WriteObjects(*objects_.get());
- }
-
- private:
- scoped_ptr<Clipboard::ObjectMap> objects_;
-};
-
-void RenderParamsFromPrintSettings(const printing::PrintSettings& settings,
- ViewMsg_Print_Params* params) {
- DCHECK(params);
- params->page_size = settings.page_setup_device_units().physical_size();
- params->printable_size.SetSize(
- settings.page_setup_device_units().content_area().width(),
- settings.page_setup_device_units().content_area().height());
- params->margin_top = settings.page_setup_device_units().content_area().x();
- params->margin_left = settings.page_setup_device_units().content_area().y();
- params->dpi = settings.dpi();
- // Currently hardcoded at 1.25. See PrintSettings' constructor.
- params->min_shrink = settings.min_shrink;
- // Currently hardcoded at 2.0. See PrintSettings' constructor.
- params->max_shrink = settings.max_shrink;
- // Currently hardcoded at 72dpi. See PrintSettings' constructor.
- params->desired_dpi = settings.desired_dpi;
- // Always use an invalid cookie.
- params->document_cookie = 0;
- params->selection_only = settings.selection_only;
-}
-
-class ClearCacheCompletion : public net::CompletionCallback {
- public:
- ClearCacheCompletion(IPC::Message* reply_msg,
- ResourceMessageFilter* filter)
- : reply_msg_(reply_msg),
- filter_(filter) {
- }
-
- virtual void RunWithParams(const Tuple1<int>& params) {
- ViewHostMsg_ClearCache::WriteReplyParams(reply_msg_, params.a);
- filter_->Send(reply_msg_);
- delete this;
- }
-
- private:
- IPC::Message* reply_msg_;
- scoped_refptr<ResourceMessageFilter> filter_;
-};
-
-class OpenChannelToPluginCallback : public PluginProcessHost::Client {
- public:
- OpenChannelToPluginCallback(ResourceMessageFilter* filter,
- IPC::Message* reply_msg)
- : filter_(filter),
- reply_msg_(reply_msg) {
- }
-
- virtual int ID() {
- return filter_->id();
- }
-
- virtual bool OffTheRecord() {
- return filter_->off_the_record();
- }
-
- virtual void SetPluginInfo(const WebPluginInfo& info) {
- info_ = info;
- }
-
- virtual void OnChannelOpened(const IPC::ChannelHandle& handle) {
- WriteReply(handle);
- }
-
- virtual void OnError() {
- WriteReply(IPC::ChannelHandle());
- }
-
- private:
- void WriteReply(const IPC::ChannelHandle& handle) {
- ViewHostMsg_OpenChannelToPlugin::WriteReplyParams(reply_msg_,
- handle,
- info_);
- filter_->Send(reply_msg_);
- delete this;
- }
-
- scoped_refptr<ResourceMessageFilter> filter_;
- IPC::Message* reply_msg_;
- WebPluginInfo info_;
-};
-
-} // namespace
ResourceMessageFilter::ResourceMessageFilter(
- ResourceDispatcherHost* resource_dispatcher_host,
int child_id,
- AudioRendererHost* audio_renderer_host,
- PluginService* plugin_service,
- printing::PrintJobManager* print_job_manager,
- Profile* profile,
- RenderWidgetHelper* render_widget_helper)
- : Receiver(RENDER_PROCESS, child_id),
- channel_(NULL),
- resource_dispatcher_host_(resource_dispatcher_host),
- plugin_service_(plugin_service),
- print_job_manager_(print_job_manager),
- profile_(profile),
- ALLOW_THIS_IN_INITIALIZER_LIST(resolve_proxy_msg_helper_(this, NULL)),
- media_request_context_(profile->GetRequestContextForMedia()),
- extensions_request_context_(profile->GetRequestContextForExtensions()),
- render_widget_helper_(render_widget_helper),
- audio_renderer_host_(audio_renderer_host),
- appcache_dispatcher_host_(
- new AppCacheDispatcherHost(profile->GetRequestContext())),
- ALLOW_THIS_IN_INITIALIZER_LIST(dom_storage_dispatcher_host_(
- new DOMStorageDispatcherHost(this, profile->GetWebKitContext()))),
- ALLOW_THIS_IN_INITIALIZER_LIST(indexed_db_dispatcher_host_(
- new IndexedDBDispatcherHost(this, profile))),
- ALLOW_THIS_IN_INITIALIZER_LIST(db_dispatcher_host_(
- new DatabaseDispatcherHost(profile->GetDatabaseTracker(), this,
- profile->GetHostContentSettingsMap()))),
- notification_prefs_(
- profile->GetDesktopNotificationService()->prefs_cache()),
- host_zoom_map_(profile->GetHostZoomMap()),
- off_the_record_(profile->IsOffTheRecord()),
- next_route_id_callback_(NewCallbackWithReturnValue(
- render_widget_helper, &RenderWidgetHelper::GetNextRoutingID)),
- ALLOW_THIS_IN_INITIALIZER_LIST(speech_input_dispatcher_host_(
- new speech_input::SpeechInputDispatcherHost(this->id()))),
- ALLOW_THIS_IN_INITIALIZER_LIST(geolocation_dispatcher_host_(
- GeolocationDispatcherHostOld::New(
- this->id(), profile->GetGeolocationPermissionContext()))),
- ALLOW_THIS_IN_INITIALIZER_LIST(
- search_provider_install_state_dispatcher_host_(
- new SearchProviderInstallStateDispatcherHost(this, profile,
- child_id))),
- ALLOW_THIS_IN_INITIALIZER_LIST(device_orientation_dispatcher_host_(
- new device_orientation::DispatcherHost(this->id()))),
- ALLOW_THIS_IN_INITIALIZER_LIST(file_system_dispatcher_host_(
- new FileSystemDispatcherHost(this, profile))),
- ALLOW_THIS_IN_INITIALIZER_LIST(blob_dispatcher_host_(
- new BlobDispatcherHost(
- this->id(), profile->GetBlobStorageContext()))),
- ALLOW_THIS_IN_INITIALIZER_LIST(file_utilities_dispatcher_host_(
- new FileUtilitiesDispatcherHost(this, this->id()))),
- ALLOW_THIS_IN_INITIALIZER_LIST(mime_registry_dispatcher_(
- new MimeRegistryDispatcher(this))) {
- request_context_ = profile_->GetRequestContext();
- DCHECK(request_context_);
- DCHECK(media_request_context_);
- DCHECK(audio_renderer_host_.get());
- DCHECK(appcache_dispatcher_host_.get());
- DCHECK(dom_storage_dispatcher_host_.get());
-
- render_widget_helper_->Init(id(), resource_dispatcher_host_);
-#if defined(OS_CHROMEOS)
- cloud_print_enabled_ = true;
-#else
- cloud_print_enabled_ = CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableCloudPrint);
-#endif
+ ChildProcessInfo::ProcessType process_type,
+ ResourceDispatcherHost* resource_dispatcher_host)
+ : child_id_(child_id),
+ process_type_(process_type),
+ resource_dispatcher_host_(resource_dispatcher_host) {
}
ResourceMessageFilter::~ResourceMessageFilter() {
- // This function should be called on the IO thread.
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- // Tell the DOM Storage dispatcher host to stop sending messages via us.
- dom_storage_dispatcher_host_->Shutdown();
-
- // Tell the Indexed DB dispatcher host to stop sending messages via us.
- indexed_db_dispatcher_host_->Shutdown();
-
- // Shut down the database dispatcher host.
- db_dispatcher_host_->Shutdown();
-
- // Shut down the async file_system dispatcher host.
- file_system_dispatcher_host_->Shutdown();
-
- // Shut down the blob dispatcher host.
- blob_dispatcher_host_->Shutdown();
-
- // Shut down the async file_utilities dispatcher host.
- file_utilities_dispatcher_host_->Shutdown();
-
- // Shut down the mime registry dispatcher host.
- mime_registry_dispatcher_->Shutdown();
-
- // Let interested observers know we are being deleted.
- NotificationService::current()->Notify(
- NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN,
- Source<ResourceMessageFilter>(this),
- NotificationService::NoDetails());
-
- if (handle())
- base::CloseProcessHandle(handle());
-}
-
-// Called on the IPC thread:
-void ResourceMessageFilter::OnFilterAdded(IPC::Channel* channel) {
- channel_ = channel;
}
-// Called on the IPC thread:
-void ResourceMessageFilter::OnChannelConnected(int32 peer_pid) {
- DCHECK(!handle()) << " " << handle();
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- base::ProcessHandle peer_handle;
- if (!base::OpenProcessHandle(peer_pid, &peer_handle)) {
- NOTREACHED();
- }
- set_handle(peer_handle);
-
- // Hook AudioRendererHost to this object after channel is connected so it can
- // this object for sending messages.
- audio_renderer_host_->IPCChannelConnected(id(), handle(), this);
-
- WorkerService::GetInstance()->Initialize(resource_dispatcher_host_);
- appcache_dispatcher_host_->Initialize(this);
- dom_storage_dispatcher_host_->Init(id(), handle());
- indexed_db_dispatcher_host_->Init(id(), handle());
- db_dispatcher_host_->Init(handle());
- file_system_dispatcher_host_->Init(handle());
- file_utilities_dispatcher_host_->Init(handle());
-}
-
-void ResourceMessageFilter::OnChannelError() {
- NotificationService::current()->Notify(
- NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN,
- Source<ResourceMessageFilter>(this),
- NotificationService::NoDetails());
-}
-
-// Called on the IPC thread:
void ResourceMessageFilter::OnChannelClosing() {
- channel_ = NULL;
+ BrowserMessageFilter::OnChannelClosing();
// Unhook us from all pending network requests so they don't get sent to a
// deleted object.
- resource_dispatcher_host_->CancelRequestsForProcess(id());
-
- // Unhook AudioRendererHost.
- audio_renderer_host_->IPCChannelClosing();
+ resource_dispatcher_host_->CancelRequestsForProcess(child_id_);
}
-// Called on the IPC thread:
-bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& msg) {
- MessagePortDispatcher* mp_dispatcher = MessagePortDispatcher::GetInstance();
- bool msg_is_ok = true;
- bool handled =
- resource_dispatcher_host_->OnMessageReceived(msg, this, &msg_is_ok) ||
- appcache_dispatcher_host_->OnMessageReceived(msg, &msg_is_ok) ||
- dom_storage_dispatcher_host_->OnMessageReceived(msg, &msg_is_ok) ||
- indexed_db_dispatcher_host_->OnMessageReceived(msg) ||
- audio_renderer_host_->OnMessageReceived(msg, &msg_is_ok) ||
- db_dispatcher_host_->OnMessageReceived(msg, &msg_is_ok) ||
- mp_dispatcher->OnMessageReceived(
- msg, this, next_route_id_callback(), &msg_is_ok) ||
- geolocation_dispatcher_host_->OnMessageReceived(msg, &msg_is_ok) ||
- speech_input_dispatcher_host_->OnMessageReceived(msg, &msg_is_ok) ||
- search_provider_install_state_dispatcher_host_->OnMessageReceived(
- msg, &msg_is_ok) ||
- device_orientation_dispatcher_host_->OnMessageReceived(msg, &msg_is_ok) ||
- file_system_dispatcher_host_->OnMessageReceived(msg, &msg_is_ok) ||
- blob_dispatcher_host_->OnMessageReceived(msg, &msg_is_ok) ||
- file_utilities_dispatcher_host_->OnMessageReceived(msg) ||
- mime_registry_dispatcher_->OnMessageReceived(msg);
-
- if (!handled) {
- DCHECK(msg_is_ok); // It should have been marked handled if it wasn't OK.
- handled = true;
- IPC_BEGIN_MESSAGE_MAP_EX(ResourceMessageFilter, msg, msg_is_ok)
- // On Linux we need to dispatch these messages to the UI2 thread
- // because we cannot make X calls from the IO thread. Mac
- // doesn't have windowed plug-ins so we handle the messages in
- // the UI thread. On Windows, we intercept the messages and
- // handle them directly.
-#if !defined(OS_MACOSX)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetScreenInfo,
- OnGetScreenInfo)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetWindowRect,
- OnGetWindowRect)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetRootWindowRect,
- OnGetRootWindowRect)
-#endif
-
- IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWindow, OnMsgCreateWindow)
- IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWidget, OnMsgCreateWidget)
- IPC_MESSAGE_HANDLER(ViewHostMsg_CreateFullscreenWidget,
- OnMsgCreateFullscreenWidget)
- IPC_MESSAGE_HANDLER(ViewHostMsg_SetCookie, OnSetCookie)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetCookies, OnGetCookies)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetRawCookies,
- OnGetRawCookies)
- IPC_MESSAGE_HANDLER(ViewHostMsg_DeleteCookie, OnDeleteCookie)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_CookiesEnabled,
- OnCookiesEnabled)
-#if defined(OS_MACOSX)
- IPC_MESSAGE_HANDLER(ViewHostMsg_LoadFont, OnLoadFont)
-#endif
-#if defined(OS_WIN) // This hack is Windows-specific.
- IPC_MESSAGE_HANDLER(ViewHostMsg_PreCacheFont, OnPreCacheFont)
-#endif
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetPlugins, OnGetPlugins)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetPluginInfo,
- OnGetPluginInfo)
- IPC_MESSAGE_HANDLER(ViewHostMsg_DownloadUrl, OnDownloadUrl)
- IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_ContextMenu,
- OnReceiveContextMenuMsg(msg))
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_OpenChannelToPlugin,
- OnOpenChannelToPlugin)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_OpenChannelToPepperPlugin,
- OnOpenChannelToPepperPlugin)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_LaunchNaCl, OnLaunchNaCl)
- IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWorker, OnCreateWorker)
- IPC_MESSAGE_HANDLER(ViewHostMsg_LookupSharedWorker, OnLookupSharedWorker)
- IPC_MESSAGE_HANDLER(ViewHostMsg_DocumentDetached, OnDocumentDetached)
- IPC_MESSAGE_HANDLER(ViewHostMsg_CancelCreateDedicatedWorker,
- OnCancelCreateDedicatedWorker)
- IPC_MESSAGE_HANDLER(ViewHostMsg_ForwardToWorker,
- OnForwardToWorker)
- IPC_MESSAGE_HANDLER(ViewHostMsg_SpellChecker_PlatformCheckSpelling,
- OnPlatformCheckSpelling)
- IPC_MESSAGE_HANDLER(ViewHostMsg_SpellChecker_PlatformFillSuggestionList,
- OnPlatformFillSuggestionList)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetDocumentTag,
- OnGetDocumentTag)
- IPC_MESSAGE_HANDLER(ViewHostMsg_DocumentWithTagClosed,
- OnDocumentWithTagClosed)
- IPC_MESSAGE_HANDLER(ViewHostMsg_ShowSpellingPanel, OnShowSpellingPanel)
- IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateSpellingPanelWithMisspelledWord,
- OnUpdateSpellingPanelWithMisspelledWord)
- IPC_MESSAGE_HANDLER(ViewHostMsg_DnsPrefetch, OnDnsPrefetch)
- IPC_MESSAGE_HANDLER(ViewHostMsg_RendererHistograms,
- OnRendererHistograms)
- IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_UpdateRect,
- render_widget_helper_->DidReceiveUpdateMsg(msg))
- IPC_MESSAGE_HANDLER(ViewHostMsg_ClipboardWriteObjectsAsync,
- OnClipboardWriteObjectsAsync)
- IPC_MESSAGE_HANDLER(ViewHostMsg_ClipboardWriteObjectsSync,
- OnClipboardWriteObjectsSync)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ClipboardIsFormatAvailable,
- OnClipboardIsFormatAvailable)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ClipboardReadText,
- OnClipboardReadText)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ClipboardReadAsciiText,
- OnClipboardReadAsciiText)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ClipboardReadHTML,
- OnClipboardReadHTML)
-#if defined(OS_MACOSX)
- IPC_MESSAGE_HANDLER(ViewHostMsg_ClipboardFindPboardWriteStringAsync,
- OnClipboardFindPboardWriteString)
-#endif
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ClipboardReadAvailableTypes,
- OnClipboardReadAvailableTypes)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ClipboardReadData,
- OnClipboardReadData)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ClipboardReadFilenames,
- OnClipboardReadFilenames)
- IPC_MESSAGE_HANDLER(ViewHostMsg_CheckNotificationPermission,
- OnCheckNotificationPermission)
- IPC_MESSAGE_HANDLER(ViewHostMsg_RevealFolderInOS, OnRevealFolderInOS)
- IPC_MESSAGE_HANDLER(ViewHostMsg_GetCPBrowsingContext,
- OnGetCPBrowsingContext)
-#if defined(OS_WIN)
- IPC_MESSAGE_HANDLER(ViewHostMsg_DuplicateSection, OnDuplicateSection)
-#endif
-#if defined(OS_MACOSX)
- IPC_MESSAGE_HANDLER(ViewHostMsg_AllocatePDFTransport,
- OnAllocateSharedMemoryBuffer)
-#endif
-#if defined(OS_POSIX)
- IPC_MESSAGE_HANDLER(ViewHostMsg_AllocateSharedMemoryBuffer,
- OnAllocateSharedMemoryBuffer)
-#endif
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_AllocateTempFileForPrinting,
- OnAllocateTempFileForPrinting)
- IPC_MESSAGE_HANDLER(ViewHostMsg_TempFileForPrintingWritten,
- OnTempFileForPrintingWritten)
-#endif
- IPC_MESSAGE_HANDLER(ViewHostMsg_ResourceTypeStats, OnResourceTypeStats)
- IPC_MESSAGE_HANDLER(ViewHostMsg_V8HeapStats, OnV8HeapStats)
- IPC_MESSAGE_HANDLER(ViewHostMsg_DidZoomURL, OnDidZoomURL)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ResolveProxy, OnResolveProxy)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetDefaultPrintSettings,
- OnGetDefaultPrintSettings)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ScriptedPrint,
- OnScriptedPrint)
-#if defined(OS_MACOSX)
- IPC_MESSAGE_HANDLER(ViewHostMsg_AllocTransportDIB,
- OnAllocTransportDIB)
- IPC_MESSAGE_HANDLER(ViewHostMsg_FreeTransportDIB,
- OnFreeTransportDIB)
-#endif
- IPC_MESSAGE_HANDLER(ViewHostMsg_OpenChannelToExtension,
- OnOpenChannelToExtension)
- IPC_MESSAGE_HANDLER(ViewHostMsg_OpenChannelToTab, OnOpenChannelToTab)
- IPC_MESSAGE_HANDLER(ViewHostMsg_CloseCurrentConnections,
- OnCloseCurrentConnections)
- IPC_MESSAGE_HANDLER(ViewHostMsg_SetCacheMode, OnSetCacheMode)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ClearCache, OnClearCache)
- IPC_MESSAGE_HANDLER(ViewHostMsg_DidGenerateCacheableMetadata,
- OnCacheableMetadataAvailable)
- IPC_MESSAGE_HANDLER(ViewHostMsg_EnableSpdy, OnEnableSpdy)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_Keygen, OnKeygen)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetExtensionMessageBundle,
- OnGetExtensionMessageBundle)
-#if defined(USE_TCMALLOC)
- IPC_MESSAGE_HANDLER(ViewHostMsg_RendererTcmalloc, OnRendererTcmalloc)
-#endif
- IPC_MESSAGE_HANDLER(ViewHostMsg_EstablishGpuChannel,
- OnEstablishGpuChannel)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_SynchronizeGpu,
- OnSynchronizeGpu)
- IPC_MESSAGE_HANDLER(ViewHostMsg_AsyncOpenFile, OnAsyncOpenFile)
- IPC_MESSAGE_UNHANDLED(
- handled = false)
- IPC_END_MESSAGE_MAP_EX()
- }
-
- if (!msg_is_ok)
- BrowserRenderProcessHost::BadMessageTerminateProcess(msg.type(), handle());
-
- return handled;
+bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok) {
+ return resource_dispatcher_host_->OnMessageReceived(
+ message, this, message_was_ok);
}
-void ResourceMessageFilter::OnRevealFolderInOS(const FilePath& path) {
-#if defined(OS_MACOSX)
- const BrowserThread::ID kThreadID = BrowserThread::UI;
-#else
- const BrowserThread::ID kThreadID = BrowserThread::FILE;
-#endif
- if (!BrowserThread::CurrentlyOn(kThreadID)) {
- // Only honor the request if appropriate persmissions are granted.
- if (ChildProcessSecurityPolicy::GetInstance()->CanReadFile(id(), path))
- BrowserThread::PostTask(
- kThreadID, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::OnRevealFolderInOS, path));
- return;
+ChromeURLRequestContext* ResourceMessageFilter::GetURLRequestContext(
+ uint32 request_id, ResourceType::Type resource_type) {
+ URLRequestContext* rv = NULL;
+ if (url_request_context_override_.get()) {
+ rv = url_request_context_override_->GetRequestContext(
+ request_id, resource_type);
}
- DCHECK(BrowserThread::CurrentlyOn(kThreadID));
- platform_util::OpenItem(path);
-}
-
-void ResourceMessageFilter::OnDestruct() const {
- BrowserThread::DeleteOnIOThread::Destruct(this);
-}
-
-void ResourceMessageFilter::OnReceiveContextMenuMsg(const IPC::Message& msg) {
- void* iter = NULL;
- ContextMenuParams params;
- if (!IPC::ParamTraits<ContextMenuParams>::Read(&msg, &iter, &params))
- return;
-
- // Create a new ViewHostMsg_ContextMenu message.
- const ViewHostMsg_ContextMenu context_menu_message(msg.routing_id(), params);
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- new ContextMenuMessageDispatcher(id(), context_menu_message));
-}
-
-// Called on the IPC thread:
-bool ResourceMessageFilter::Send(IPC::Message* message) {
- if (!channel_) {
- delete message;
- return false;
- }
-
- return channel_->Send(message);
-}
-
-URLRequestContext* ResourceMessageFilter::GetRequestContext(
- uint32 request_id,
- const ViewHostMsg_Resource_Request& request_data) {
- URLRequestContextGetter* request_context = request_context_;
- // If the request has resource type of ResourceType::MEDIA, we use a request
- // context specific to media for handling it because these resources have
- // specific needs for caching.
- if (request_data.resource_type == ResourceType::MEDIA)
- request_context = media_request_context_;
- return request_context->GetURLRequestContext();
-}
-
-void ResourceMessageFilter::OnMsgCreateWindow(
- const ViewHostMsg_CreateWindow_Params& params,
- int* route_id, int64* cloned_session_storage_namespace_id) {
- *cloned_session_storage_namespace_id = dom_storage_dispatcher_host_->
- CloneSessionStorage(params.session_storage_namespace_id);
- render_widget_helper_->CreateNewWindow(params.opener_id,
- params.user_gesture,
- params.window_container_type,
- params.frame_name,
- handle(),
- route_id);
-}
-
-void ResourceMessageFilter::OnMsgCreateWidget(int opener_id,
- WebKit::WebPopupType popup_type,
- int* route_id) {
- render_widget_helper_->CreateNewWidget(opener_id, popup_type, route_id);
-}
-
-void ResourceMessageFilter::OnMsgCreateFullscreenWidget(
- int opener_id, WebKit::WebPopupType popup_type, int* route_id) {
- render_widget_helper_->CreateNewFullscreenWidget(
- opener_id, popup_type, route_id);
-}
-
-void ResourceMessageFilter::OnSetCookie(const IPC::Message& message,
- const GURL& url,
- const GURL& first_party_for_cookies,
- const std::string& cookie) {
- ChromeURLRequestContext* context = GetRequestContextForURL(url);
-
- SetCookieCompletion* callback =
- new SetCookieCompletion(id(), message.routing_id(), url, cookie,
- context);
-
- // If this render view is associated with an automation channel, aka
- // ChromeFrame then we need to set cookies in the external host.
- if (!AutomationResourceMessageFilter::SetCookiesForUrl(url, cookie,
- callback)) {
- int policy = net::OK;
- if (context->cookie_policy()) {
- policy = context->cookie_policy()->CanSetCookie(
- url, first_party_for_cookies, cookie, callback);
- if (policy == net::ERR_IO_PENDING)
- return;
- }
- callback->Run(policy);
+ if (!rv) {
+ URLRequestContextGetter* context_getter =
+ Profile::GetDefaultRequestContext();
+ if (context_getter)
+ rv = context_getter->GetURLRequestContext();
}
-}
-
-void ResourceMessageFilter::OnGetCookies(const GURL& url,
- const GURL& first_party_for_cookies,
- IPC::Message* reply_msg) {
- URLRequestContext* context = GetRequestContextForURL(url);
-
- GetCookiesCompletion* callback =
- new GetCookiesCompletion(id(), reply_msg->routing_id(), url, reply_msg,
- this, context, false);
-
- // If this render view is associated with an automation channel, aka
- // ChromeFrame then we need to retrieve cookies from the external host.
- if (!AutomationResourceMessageFilter::GetCookiesForUrl(url, callback)) {
- int policy = net::OK;
- if (context->cookie_policy()) {
- policy = context->cookie_policy()->CanGetCookies(
- url, first_party_for_cookies, callback);
- if (policy == net::ERR_IO_PENDING) {
- Send(new ViewMsg_SignalCookiePromptEvent());
- return;
- }
- }
- callback->Run(policy);
- }
-}
-
-void ResourceMessageFilter::OnGetRawCookies(
- const GURL& url,
- const GURL& first_party_for_cookies,
- IPC::Message* reply_msg) {
-
- ChromeURLRequestContext* context = GetRequestContextForURL(url);
-
- // Only return raw cookies to trusted renderers or if this request is
- // not targeted to an an external host like ChromeFrame.
- // TODO(ananta) We need to support retreiving raw cookies from external
- // hosts.
- if (!ChildProcessSecurityPolicy::GetInstance()->CanReadRawCookies(id()) ||
- context->IsExternal()) {
- ViewHostMsg_GetRawCookies::WriteReplyParams(
- reply_msg,
- std::vector<webkit_glue::WebCookie>());
- Send(reply_msg);
- return;
- }
-
- GetCookiesCompletion* callback =
- new GetCookiesCompletion(id(), reply_msg->routing_id(), url,
- reply_msg, this, context, true);
-
- // We check policy here to avoid sending back cookies that would not normally
- // be applied to outbound requests for the given URL. Since this cookie info
- // is visible in the developer tools, it is helpful to make it match reality.
- int policy = net::OK;
- if (context->cookie_policy()) {
- policy = context->cookie_policy()->CanGetCookies(
- url, first_party_for_cookies, callback);
- if (policy == net::ERR_IO_PENDING) {
- Send(new ViewMsg_SignalCookiePromptEvent());
- return;
- }
- }
- callback->Run(policy);
-}
-
-void ResourceMessageFilter::OnDeleteCookie(const GURL& url,
- const std::string& cookie_name) {
- URLRequestContext* context = GetRequestContextForURL(url);
- context->cookie_store()->DeleteCookie(url, cookie_name);
-}
-
-void ResourceMessageFilter::OnCookiesEnabled(
- const GURL& url,
- const GURL& first_party_for_cookies,
- IPC::Message* reply_msg) {
- URLRequestContext* context = GetRequestContextForURL(url);
- CookiesEnabledCompletion* callback =
- new CookiesEnabledCompletion(reply_msg, this);
- int policy = net::OK;
- // TODO(ananta): If this render view is associated with an automation channel,
- // aka ChromeFrame then we need to retrieve cookie settings from the external
- // host.
- if (context->cookie_policy()) {
- policy = context->cookie_policy()->CanGetCookies(
- url, first_party_for_cookies, callback);
- if (policy == net::ERR_IO_PENDING) {
- Send(new ViewMsg_SignalCookiePromptEvent());
- return; // CanGetCookies will take care to call our callback in this case.
- }
- }
- callback->Run(policy);
-}
-
-#if defined(OS_MACOSX)
-void ResourceMessageFilter::OnLoadFont(const FontDescriptor& font,
- uint32* handle_size,
- base::SharedMemoryHandle* handle) {
- base::SharedMemory font_data;
- uint32 font_data_size = 0;
- bool ok = FontLoader::LoadFontIntoBuffer(font.nsFont(), &font_data,
- &font_data_size);
- if (!ok || font_data_size == 0) {
- LOG(ERROR) << "Couldn't load font data for " << font.font_name <<
- " ok=" << ok << " font_data_size=" << font_data_size;
- *handle_size = 0;
- *handle = base::SharedMemory::NULLHandle();
- return;
- }
-
- *handle_size = font_data_size;
- font_data.GiveToProcess(base::GetCurrentProcessHandle(), handle);
-}
-#endif // OS_MACOSX
-
-#if defined(OS_WIN) // This hack is Windows-specific.
-void ResourceMessageFilter::OnPreCacheFont(LOGFONT font) {
- ChildProcessHost::PreCacheFont(font);
-}
-#endif // OS_WIN
-
-void ResourceMessageFilter::OnGetPlugins(bool refresh,
- IPC::Message* reply_msg) {
- // Don't refresh if the specified threshold has not been passed. Note that
- // this check is performed before off-loading to the file thread. The reason
- // we do this is that some pages tend to request that the list of plugins be
- // refreshed at an excessive rate. This instigates disk scanning, as the list
- // is accumulated by doing multiple reads from disk. This effect is
- // multiplied when we have several pages requesting this operation.
- if (refresh) {
- const base::TimeDelta threshold = base::TimeDelta::FromSeconds(
- kPluginsRefreshThresholdInSeconds);
- const base::TimeTicks now = base::TimeTicks::Now();
- if (now - last_plugin_refresh_time_ < threshold)
- refresh = false; // Ignore refresh request; threshold not exceeded yet.
- else
- last_plugin_refresh_time_ = now;
- }
-
- // Can't load plugins on IO thread, so go to the FILE thread.
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::OnGetPluginsOnFileThread, refresh,
- reply_msg));
-}
-
-void ResourceMessageFilter::OnGetPluginsOnFileThread(
- bool refresh, IPC::Message* reply_msg) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- std::vector<WebPluginInfo> plugins;
- NPAPI::PluginList::Singleton()->GetEnabledPlugins(refresh, &plugins);
- ViewHostMsg_GetPlugins::WriteReplyParams(reply_msg, plugins);
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(this, &ResourceMessageFilter::Send, reply_msg));
-}
-
-void ResourceMessageFilter::OnGetPluginInfo(const GURL& url,
- const GURL& policy_url,
- const std::string& mime_type,
- IPC::Message* reply_msg) {
- // The PluginService::GetFirstAllowedPluginInfo may need to load the
- // plugins. Don't do it on the IO thread.
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::OnGetPluginInfoOnFileThread,
- url, policy_url, mime_type, reply_msg));
-}
-
-void ResourceMessageFilter::OnGetPluginInfoOnFileThread(
- const GURL& url,
- const GURL& policy_url,
- const std::string& mime_type,
- IPC::Message* reply_msg) {
- std::string actual_mime_type;
- WebPluginInfo info;
- bool found = plugin_service_->GetFirstAllowedPluginInfo(url,
- mime_type,
- &info,
- &actual_mime_type);
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::OnGotPluginInfo,
- found, info, actual_mime_type, policy_url, reply_msg));
-}
-
-void ResourceMessageFilter::OnGotPluginInfo(bool found,
- const WebPluginInfo& info,
- const std::string& actual_mime_type,
- const GURL& policy_url,
- IPC::Message* reply_msg) {
- ContentSetting setting = CONTENT_SETTING_DEFAULT;
- WebPluginInfo info_copy = info;
- if (found) {
- info_copy.enabled = info_copy.enabled &&
- plugin_service_->PrivatePluginAllowedForURL(info_copy.path, policy_url);
- HostContentSettingsMap* map = profile_->GetHostContentSettingsMap();
- scoped_ptr<PluginGroup> group(
- PluginGroup::CopyOrCreatePluginGroup(info_copy));
- std::string resource = group->identifier();
- setting = map->GetContentSetting(policy_url,
- CONTENT_SETTINGS_TYPE_PLUGINS,
- resource);
- }
-
- ViewHostMsg_GetPluginInfo::WriteReplyParams(
- reply_msg, found, info_copy, setting, actual_mime_type);
- Send(reply_msg);
-}
-
-void ResourceMessageFilter::OnOpenChannelToPlugin(const GURL& url,
- const std::string& mime_type,
- IPC::Message* reply_msg) {
- plugin_service_->OpenChannelToPlugin(
- url,
- mime_type,
- new OpenChannelToPluginCallback(this, reply_msg));
-}
-
-void ResourceMessageFilter::OnOpenChannelToPepperPlugin(
- const FilePath& path,
- IPC::Message* reply_msg) {
- PpapiPluginProcessHost* host = new PpapiPluginProcessHost(this);
- host->Init(path, reply_msg);
- ppapi_plugin_hosts_.push_back(linked_ptr<PpapiPluginProcessHost>(host));
-}
-
-void ResourceMessageFilter::OnLaunchNaCl(
- const std::wstring& url, int channel_descriptor, IPC::Message* reply_msg) {
- NaClProcessHost* host = new NaClProcessHost(resource_dispatcher_host_, url);
- host->Launch(this, channel_descriptor, reply_msg);
-}
-
-void ResourceMessageFilter::OnCreateWorker(
- const ViewHostMsg_CreateWorker_Params& params, int* route_id) {
- *route_id = params.route_id != MSG_ROUTING_NONE ?
- params.route_id : render_widget_helper_->GetNextRoutingID();
- if (params.is_shared)
- WorkerService::GetInstance()->CreateSharedWorker(
- params.url, off_the_record(), params.name,
- params.document_id, id(), params.render_view_route_id, this, *route_id,
- params.script_resource_appcache_id,
- static_cast<ChromeURLRequestContext*>(
- request_context_->GetURLRequestContext()));
- else
- WorkerService::GetInstance()->CreateDedicatedWorker(
- params.url, off_the_record(),
- params.document_id, id(), params.render_view_route_id, this, *route_id,
- id(), params.parent_appcache_host_id,
- static_cast<ChromeURLRequestContext*>(
- request_context_->GetURLRequestContext()));
-}
-
-void ResourceMessageFilter::OnLookupSharedWorker(
- const ViewHostMsg_CreateWorker_Params& params, bool* exists, int* route_id,
- bool* url_mismatch) {
- *route_id = render_widget_helper_->GetNextRoutingID();
- *exists = WorkerService::GetInstance()->LookupSharedWorker(
- params.url, params.name, off_the_record(), params.document_id, id(),
- params.render_view_route_id, this, *route_id, url_mismatch);
-}
-
-void ResourceMessageFilter::OnDocumentDetached(unsigned long long document_id) {
- // Notify the WorkerService that the passed document was detached so any
- // associated shared workers can be shut down.
- WorkerService::GetInstance()->DocumentDetached(this, document_id);
-}
-
-void ResourceMessageFilter::OnCancelCreateDedicatedWorker(int route_id) {
- WorkerService::GetInstance()->CancelCreateDedicatedWorker(this, route_id);
-}
-
-void ResourceMessageFilter::OnForwardToWorker(const IPC::Message& message) {
- WorkerService::GetInstance()->ForwardMessage(message, this);
-}
-
-void ResourceMessageFilter::OnDownloadUrl(const IPC::Message& message,
- const GURL& url,
- const GURL& referrer) {
- URLRequestContext* context = request_context_->GetURLRequestContext();
-
- // Don't show "Save As" UI.
- bool prompt_for_save_location = false;
- resource_dispatcher_host_->BeginDownload(url,
- referrer,
- DownloadSaveInfo(),
- prompt_for_save_location,
- id(),
- message.routing_id(),
- context);
-}
-
-void ResourceMessageFilter::OnClipboardWriteObjectsSync(
- const Clipboard::ObjectMap& objects,
- base::SharedMemoryHandle bitmap_handle) {
- DCHECK(base::SharedMemory::IsHandleValid(bitmap_handle))
- << "Bad bitmap handle";
- // We cannot write directly from the IO thread, and cannot service the IPC
- // on the UI thread. We'll copy the relevant data and get a handle to any
- // shared memory so it doesn't go away when we resume the renderer, and post
- // a task to perform the write on the UI thread.
- Clipboard::ObjectMap* long_living_objects = new Clipboard::ObjectMap(objects);
-
- // Splice the shared memory handle into the clipboard data.
- Clipboard::ReplaceSharedMemHandle(long_living_objects, bitmap_handle,
- handle());
-
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- new WriteClipboardTask(long_living_objects));
-}
-
-void ResourceMessageFilter::OnClipboardWriteObjectsAsync(
- const Clipboard::ObjectMap& objects) {
- // We cannot write directly from the IO thread, and cannot service the IPC
- // on the UI thread. We'll copy the relevant data and post a task to preform
- // the write on the UI thread.
- Clipboard::ObjectMap* long_living_objects = new Clipboard::ObjectMap(objects);
-
- // This async message doesn't support shared-memory based bitmaps; they must
- // be removed otherwise we might dereference a rubbish pointer.
- long_living_objects->erase(Clipboard::CBF_SMBITMAP);
-
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- new WriteClipboardTask(long_living_objects));
-}
-
-#if !defined(USE_X11)
-// On non-X11 platforms, clipboard actions can be performed on the IO thread.
-// On X11, since the clipboard is linked with GTK, we either have to do this
-// with GTK on the UI thread, or with Xlib on the BACKGROUND_X11 thread. In an
-// ideal world, we would do the latter. However, for now we're going to
-// terminate these calls on the UI thread. This risks deadlock in the case of
-// plugins, but it's better than crashing which is what doing on the IO thread
-// gives us.
-//
-// See resource_message_filter_gtk.cc for the Linux implementation of these
-// functions.
-
-void ResourceMessageFilter::OnClipboardIsFormatAvailable(
- Clipboard::FormatType format, Clipboard::Buffer buffer,
- IPC::Message* reply) {
- const bool result = GetClipboard()->IsFormatAvailable(format, buffer);
- ViewHostMsg_ClipboardIsFormatAvailable::WriteReplyParams(reply, result);
- Send(reply);
-}
-
-void ResourceMessageFilter::OnClipboardReadText(Clipboard::Buffer buffer,
- IPC::Message* reply) {
- string16 result;
- GetClipboard()->ReadText(buffer, &result);
- ViewHostMsg_ClipboardReadText::WriteReplyParams(reply, result);
- Send(reply);
-}
-
-void ResourceMessageFilter::OnClipboardReadAsciiText(Clipboard::Buffer buffer,
- IPC::Message* reply) {
- std::string result;
- GetClipboard()->ReadAsciiText(buffer, &result);
- ViewHostMsg_ClipboardReadAsciiText::WriteReplyParams(reply, result);
- Send(reply);
-}
-
-void ResourceMessageFilter::OnClipboardReadHTML(Clipboard::Buffer buffer,
- IPC::Message* reply) {
- std::string src_url_str;
- string16 markup;
- GetClipboard()->ReadHTML(buffer, &markup, &src_url_str);
- const GURL src_url = GURL(src_url_str);
-
- ViewHostMsg_ClipboardReadHTML::WriteReplyParams(reply, markup, src_url);
- Send(reply);
-}
-
-void ResourceMessageFilter::OnClipboardReadAvailableTypes(
- Clipboard::Buffer buffer, IPC::Message* reply) {
- std::vector<string16> types;
- bool contains_filenames = false;
- bool result = ClipboardDispatcher::ReadAvailableTypes(
- buffer, &types, &contains_filenames);
- ViewHostMsg_ClipboardReadAvailableTypes::WriteReplyParams(
- reply, result, types, contains_filenames);
- Send(reply);
-}
-
-void ResourceMessageFilter::OnClipboardReadData(
- Clipboard::Buffer buffer, const string16& type, IPC::Message* reply) {
- string16 data;
- string16 metadata;
- bool result = ClipboardDispatcher::ReadData(buffer, type, &data, &metadata);
- ViewHostMsg_ClipboardReadData::WriteReplyParams(
- reply, result, data, metadata);
- Send(reply);
-}
-
-void ResourceMessageFilter::OnClipboardReadFilenames(
- Clipboard::Buffer buffer, IPC::Message* reply) {
- std::vector<string16> filenames;
- bool result = ClipboardDispatcher::ReadFilenames(buffer, &filenames);
- ViewHostMsg_ClipboardReadFilenames::WriteReplyParams(
- reply, result, filenames);
- Send(reply);
-}
-
-#endif
-
-void ResourceMessageFilter::OnCheckNotificationPermission(
- const GURL& source_url, int* result) {
- *result = WebKit::WebNotificationPresenter::PermissionNotAllowed;
-
- ChromeURLRequestContext* context = GetRequestContextForURL(source_url);
- if (context->extension_info_map()->CheckURLAccessToExtensionPermission(
- source_url, Extension::kNotificationPermission)) {
- *result = WebKit::WebNotificationPresenter::PermissionAllowed;
- return;
- }
-
- // Fall back to the regular notification preferences, which works on an
- // origin basis.
- *result = notification_prefs_->HasPermission(source_url.GetOrigin());
-}
-
-void ResourceMessageFilter::OnGetCPBrowsingContext(uint32* context) {
- // Always allocate a new context when a plugin requests one, since it needs to
- // be unique for that plugin instance.
- *context = CPBrowsingContextManager::Instance()->Allocate(
- request_context_->GetURLRequestContext());
-}
-
-#if defined(OS_WIN)
-void ResourceMessageFilter::OnDuplicateSection(
- base::SharedMemoryHandle renderer_handle,
- base::SharedMemoryHandle* browser_handle) {
- // Duplicate the handle in this process right now so the memory is kept alive
- // (even if it is not mapped)
- base::SharedMemory shared_buf(renderer_handle, true, handle());
- shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), browser_handle);
-}
-#endif
-
-#if defined(OS_POSIX)
-void ResourceMessageFilter::OnAllocateSharedMemoryBuffer(
- uint32 buffer_size,
- base::SharedMemoryHandle* handle) {
- base::SharedMemory shared_buf;
- if (!shared_buf.CreateAndMapAnonymous(buffer_size)) {
- *handle = base::SharedMemory::NULLHandle();
- NOTREACHED() << "Cannot map shared memory buffer";
- return;
- }
- shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), handle);
-}
-#endif
-
-void ResourceMessageFilter::OnResourceTypeStats(
- const WebCache::ResourceTypeStats& stats) {
- HISTOGRAM_COUNTS("WebCoreCache.ImagesSizeKB",
- static_cast<int>(stats.images.size / 1024));
- HISTOGRAM_COUNTS("WebCoreCache.CSSStylesheetsSizeKB",
- static_cast<int>(stats.cssStyleSheets.size / 1024));
- HISTOGRAM_COUNTS("WebCoreCache.ScriptsSizeKB",
- static_cast<int>(stats.scripts.size / 1024));
- HISTOGRAM_COUNTS("WebCoreCache.XSLStylesheetsSizeKB",
- static_cast<int>(stats.xslStyleSheets.size / 1024));
- HISTOGRAM_COUNTS("WebCoreCache.FontsSizeKB",
- static_cast<int>(stats.fonts.size / 1024));
- // We need to notify the TaskManager of these statistics from the UI
- // thread.
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableFunction(
- &ResourceMessageFilter::OnResourceTypeStatsOnUIThread,
- stats,
- base::GetProcId(handle())));
-}
-
-void ResourceMessageFilter::OnResourceTypeStatsOnUIThread(
- const WebCache::ResourceTypeStats& stats, base::ProcessId renderer_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- TaskManager::GetInstance()->model()->NotifyResourceTypeStats(
- renderer_id, stats);
-}
-
-
-void ResourceMessageFilter::OnV8HeapStats(int v8_memory_allocated,
- int v8_memory_used) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableFunction(&ResourceMessageFilter::OnV8HeapStatsOnUIThread,
- v8_memory_allocated,
- v8_memory_used,
- base::GetProcId(handle())));
-}
-
-// static
-void ResourceMessageFilter::OnV8HeapStatsOnUIThread(
- int v8_memory_allocated, int v8_memory_used, base::ProcessId renderer_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- TaskManager::GetInstance()->model()->NotifyV8HeapStats(
- renderer_id,
- static_cast<size_t>(v8_memory_allocated),
- static_cast<size_t>(v8_memory_used));
-}
-
-void ResourceMessageFilter::OnDidZoomURL(const IPC::Message& message,
- double zoom_level,
- bool remember,
- const GURL& url) {
- Task* task = NewRunnableMethod(this,
- &ResourceMessageFilter::UpdateHostZoomLevelsOnUIThread, zoom_level,
- remember, url, id(), message.routing_id());
-#if defined(OS_MACOSX)
- cocoa_utils::PostTaskInEventTrackingRunLoopMode(FROM_HERE, task);
-#else
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, task);
-#endif
-}
-
-void ResourceMessageFilter::UpdateHostZoomLevelsOnUIThread(
- double zoom_level,
- bool remember,
- const GURL& url,
- int render_process_id,
- int render_view_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (remember) {
- host_zoom_map_->SetZoomLevel(url, zoom_level);
- // Notify renderers from this profile.
- for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
- !i.IsAtEnd(); i.Advance()) {
- RenderProcessHost* render_process_host = i.GetCurrentValue();
- if (render_process_host->profile() == profile_) {
- render_process_host->Send(
- new ViewMsg_SetZoomLevelForCurrentURL(url, zoom_level));
- }
- }
- } else {
- host_zoom_map_->SetTemporaryZoomLevel(
- render_process_id, render_view_id, zoom_level);
- }
-}
-
-void ResourceMessageFilter::OnResolveProxy(const GURL& url,
- IPC::Message* reply_msg) {
- resolve_proxy_msg_helper_.Start(url, reply_msg);
-}
-
-void ResourceMessageFilter::OnResolveProxyCompleted(
- IPC::Message* reply_msg,
- int result,
- const std::string& proxy_list) {
- ViewHostMsg_ResolveProxy::WriteReplyParams(reply_msg, result, proxy_list);
- Send(reply_msg);
-}
-
-void ResourceMessageFilter::OnGetDefaultPrintSettings(IPC::Message* reply_msg) {
- scoped_refptr<printing::PrinterQuery> printer_query;
- if (!print_job_manager_->printing_enabled()) {
- // Reply with NULL query.
- OnGetDefaultPrintSettingsReply(printer_query, reply_msg);
- return;
- }
-
- print_job_manager_->PopPrinterQuery(0, &printer_query);
- if (!printer_query.get()) {
- printer_query = new printing::PrinterQuery;
- }
-
- CancelableTask* task = NewRunnableMethod(
- this,
- &ResourceMessageFilter::OnGetDefaultPrintSettingsReply,
- printer_query,
- reply_msg);
- // Loads default settings. This is asynchronous, only the IPC message sender
- // will hang until the settings are retrieved.
- printer_query->GetSettings(printing::PrinterQuery::DEFAULTS,
- NULL,
- 0,
- false,
- true,
- task);
-}
-
-void ResourceMessageFilter::OnGetDefaultPrintSettingsReply(
- scoped_refptr<printing::PrinterQuery> printer_query,
- IPC::Message* reply_msg) {
- ViewMsg_Print_Params params;
- if (!printer_query.get() ||
- printer_query->last_status() != printing::PrintingContext::OK) {
- memset(&params, 0, sizeof(params));
- } else {
- RenderParamsFromPrintSettings(printer_query->settings(), &params);
- params.document_cookie = printer_query->cookie();
- }
- ViewHostMsg_GetDefaultPrintSettings::WriteReplyParams(reply_msg, params);
- Send(reply_msg);
- // If printing was enabled.
- if (printer_query.get()) {
- // If user hasn't cancelled.
- if (printer_query->cookie() && printer_query->settings().dpi()) {
- print_job_manager_->QueuePrinterQuery(printer_query.get());
- } else {
- printer_query->StopWorker();
- }
- }
-}
-
-void ResourceMessageFilter::OnScriptedPrint(
- const ViewHostMsg_ScriptedPrint_Params& params,
- IPC::Message* reply_msg) {
- gfx::NativeView host_view =
- gfx::NativeViewFromIdInBrowser(params.host_window_id);
-
- scoped_refptr<printing::PrinterQuery> printer_query;
- print_job_manager_->PopPrinterQuery(params.cookie, &printer_query);
- if (!printer_query.get()) {
- printer_query = new printing::PrinterQuery;
- }
-
- CancelableTask* task = NewRunnableMethod(
- this,
- &ResourceMessageFilter::OnScriptedPrintReply,
- printer_query,
- params.routing_id,
- reply_msg);
-
- printer_query->GetSettings(printing::PrinterQuery::ASK_USER,
- host_view,
- params.expected_pages_count,
- params.has_selection,
- params.use_overlays,
- task);
-}
-
-void ResourceMessageFilter::OnScriptedPrintReply(
- scoped_refptr<printing::PrinterQuery> printer_query,
- int routing_id,
- IPC::Message* reply_msg) {
- ViewMsg_PrintPages_Params params;
- if (printer_query->last_status() != printing::PrintingContext::OK ||
- !printer_query->settings().dpi()) {
- memset(&params, 0, sizeof(params));
- } else {
- RenderParamsFromPrintSettings(printer_query->settings(), &params.params);
- params.params.document_cookie = printer_query->cookie();
- params.pages =
- printing::PageRange::GetPages(printer_query->settings().ranges);
- }
- ViewHostMsg_ScriptedPrint::WriteReplyParams(reply_msg, params);
- Send(reply_msg);
- if (params.params.dpi && params.params.document_cookie) {
- print_job_manager_->QueuePrinterQuery(printer_query.get());
- } else {
- printer_query->StopWorker();
- }
-}
-
-// static
-Clipboard* ResourceMessageFilter::GetClipboard() {
- // We have a static instance of the clipboard service for use by all message
- // filters. This instance lives for the life of the browser processes.
- static Clipboard* clipboard = new Clipboard;
-
- return clipboard;
-}
-
-ChromeURLRequestContext* ResourceMessageFilter::GetRequestContextForURL(
- const GURL& url) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- URLRequestContextGetter* context_getter =
- url.SchemeIs(chrome::kExtensionScheme) ?
- extensions_request_context_ : request_context_;
- return static_cast<ChromeURLRequestContext*>(
- context_getter->GetURLRequestContext());
-}
-
-void ResourceMessageFilter::OnPlatformCheckSpelling(const string16& word,
- int tag,
- bool* correct) {
- *correct = SpellCheckerPlatform::CheckSpelling(word, tag);
-}
-
-void ResourceMessageFilter::OnPlatformFillSuggestionList(
- const string16& word,
- std::vector<string16>* suggestions) {
- SpellCheckerPlatform::FillSuggestionList(word, suggestions);
-}
-
-void ResourceMessageFilter::OnGetDocumentTag(IPC::Message* reply_msg) {
- int tag = SpellCheckerPlatform::GetDocumentTag();
- ViewHostMsg_GetDocumentTag::WriteReplyParams(reply_msg, tag);
- Send(reply_msg);
- return;
-}
-
-void ResourceMessageFilter::OnDocumentWithTagClosed(int tag) {
- SpellCheckerPlatform::CloseDocumentWithTag(tag);
-}
-
-void ResourceMessageFilter::OnShowSpellingPanel(bool show) {
- SpellCheckerPlatform::ShowSpellingPanel(show);
-}
-
-void ResourceMessageFilter::OnUpdateSpellingPanelWithMisspelledWord(
- const string16& word) {
- SpellCheckerPlatform::UpdateSpellingPanelWithMisspelledWord(word);
-}
-
-void ResourceMessageFilter::OnDnsPrefetch(
- const std::vector<std::string>& hostnames) {
- chrome_browser_net::DnsPrefetchList(hostnames);
-}
-
-void ResourceMessageFilter::OnRendererHistograms(
- int sequence_number,
- const std::vector<std::string>& histograms) {
- HistogramSynchronizer::DeserializeHistogramList(sequence_number, histograms);
-}
-
-#if defined(OS_MACOSX)
-void ResourceMessageFilter::OnAllocTransportDIB(
- size_t size, bool cache_in_browser, TransportDIB::Handle* handle) {
- render_widget_helper_->AllocTransportDIB(size, cache_in_browser, handle);
-}
-
-void ResourceMessageFilter::OnFreeTransportDIB(
- TransportDIB::Id dib_id) {
- render_widget_helper_->FreeTransportDIB(dib_id);
-}
-#endif
-
-void ResourceMessageFilter::OnOpenChannelToExtension(
- int routing_id, const std::string& source_extension_id,
- const std::string& target_extension_id,
- const std::string& channel_name, int* port_id) {
- int port2_id;
- ExtensionMessageService::AllocatePortIdPair(port_id, &port2_id);
-
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::OpenChannelToExtensionOnUIThread,
- id(), routing_id, port2_id, source_extension_id,
- target_extension_id, channel_name));
-}
-
-void ResourceMessageFilter::OpenChannelToExtensionOnUIThread(
- int source_process_id, int source_routing_id,
- int receiver_port_id,
- const std::string& source_extension_id,
- const std::string& target_extension_id,
- const std::string& channel_name) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- profile_->GetExtensionMessageService()->OpenChannelToExtension(
- source_process_id, source_routing_id, receiver_port_id,
- source_extension_id, target_extension_id, channel_name);
-}
-
-void ResourceMessageFilter::OnOpenChannelToTab(
- int routing_id, int tab_id, const std::string& extension_id,
- const std::string& channel_name, int* port_id) {
- int port2_id;
- ExtensionMessageService::AllocatePortIdPair(port_id, &port2_id);
-
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::OpenChannelToTabOnUIThread,
- id(), routing_id, port2_id, tab_id, extension_id, channel_name));
-}
-
-void ResourceMessageFilter::OpenChannelToTabOnUIThread(
- int source_process_id, int source_routing_id,
- int receiver_port_id,
- int tab_id,
- const std::string& extension_id,
- const std::string& channel_name) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- profile_->GetExtensionMessageService()->OpenChannelToTab(
- source_process_id, source_routing_id, receiver_port_id,
- tab_id, extension_id, channel_name);
-}
-
-bool ResourceMessageFilter::CheckBenchmarkingEnabled() const {
- static bool checked = false;
- static bool result = false;
- if (!checked) {
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- result = command_line.HasSwitch(switches::kEnableBenchmarking);
- checked = true;
- }
- return result;
-}
-
-void ResourceMessageFilter::OnCloseCurrentConnections() {
- // This function is disabled unless the user has enabled
- // benchmarking extensions.
- if (!CheckBenchmarkingEnabled())
- return;
- request_context_->GetURLRequestContext()->
- http_transaction_factory()->GetCache()->CloseCurrentConnections();
-}
-
-void ResourceMessageFilter::OnSetCacheMode(bool enabled) {
- // This function is disabled unless the user has enabled
- // benchmarking extensions.
- if (!CheckBenchmarkingEnabled())
- return;
-
- net::HttpCache::Mode mode = enabled ?
- net::HttpCache::NORMAL : net::HttpCache::DISABLE;
- net::HttpCache* http_cache = request_context_->GetURLRequestContext()->
- http_transaction_factory()->GetCache();
- http_cache->set_mode(mode);
-}
-
-void ResourceMessageFilter::OnClearCache(IPC::Message* reply_msg) {
- // This function is disabled unless the user has enabled
- // benchmarking extensions.
- int rv = -1;
- if (CheckBenchmarkingEnabled()) {
- disk_cache::Backend* backend = request_context_->GetURLRequestContext()->
- http_transaction_factory()->GetCache()->GetCurrentBackend();
- if (backend) {
- ClearCacheCompletion* callback =
- new ClearCacheCompletion(reply_msg, this);
- rv = backend->DoomAllEntries(callback);
- if (rv == net::ERR_IO_PENDING) {
- // The callback will send the reply.
- return;
- }
- // Completed synchronously, no need for the callback.
- delete callback;
- }
- }
- ViewHostMsg_ClearCache::WriteReplyParams(reply_msg, rv);
- Send(reply_msg);
-}
-
-bool ResourceMessageFilter::CheckPreparsedJsCachingEnabled() const {
- static bool checked = false;
- static bool result = false;
- if (!checked) {
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- result = command_line.HasSwitch(switches::kEnablePreparsedJsCaching);
- checked = true;
- }
- return result;
-}
-
-void ResourceMessageFilter::OnCacheableMetadataAvailable(
- const GURL& url,
- double expected_response_time,
- const std::vector<char>& data) {
- if (!CheckPreparsedJsCachingEnabled())
- return;
-
- net::HttpCache* cache = request_context_->GetURLRequestContext()->
- http_transaction_factory()->GetCache();
- DCHECK(cache);
-
- scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(data.size()));
- memcpy(buf->data(), &data.front(), data.size());
- cache->WriteMetadata(
- url, base::Time::FromDoubleT(expected_response_time), buf, data.size());
-}
-
-// TODO(lzheng): This only enables spdy over ssl. Enable spdy for http
-// when needed.
-void ResourceMessageFilter::OnEnableSpdy(bool enable) {
- if (enable) {
- net::HttpNetworkLayer::EnableSpdy("npn,force-alt-protocols");
- } else {
- net::HttpNetworkLayer::EnableSpdy("npn-http");
- }
-}
-
-void ResourceMessageFilter::OnKeygen(uint32 key_size_index,
- const std::string& challenge_string,
- const GURL& url,
- IPC::Message* reply_msg) {
- // Map displayed strings indicating level of keysecurity in the <keygen>
- // menu to the key size in bits. (See SSLKeyGeneratorChromium.cpp in WebCore.)
- int key_size_in_bits;
- switch (key_size_index) {
- case 0:
- key_size_in_bits = 2048;
- break;
- case 1:
- key_size_in_bits = 1024;
- break;
- default:
- DCHECK(false) << "Illegal key_size_index " << key_size_index;
- ViewHostMsg_Keygen::WriteReplyParams(reply_msg, std::string());
- Send(reply_msg);
- return;
- }
-
- VLOG(1) << "Dispatching keygen task to worker pool.";
- // Dispatch to worker pool, so we do not block the IO thread.
- if (!WorkerPool::PostTask(
- FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::OnKeygenOnWorkerThread,
- key_size_in_bits, challenge_string, url, reply_msg),
- true)) {
- NOTREACHED() << "Failed to dispatch keygen task to worker pool";
- ViewHostMsg_Keygen::WriteReplyParams(reply_msg, std::string());
- Send(reply_msg);
- return;
- }
-}
-
-void ResourceMessageFilter::OnKeygenOnWorkerThread(
- int key_size_in_bits,
- const std::string& challenge_string,
- const GURL& url,
- IPC::Message* reply_msg) {
- DCHECK(reply_msg);
-
- // Generate a signed public key and challenge, then send it back.
- net::KeygenHandler keygen_handler(key_size_in_bits, challenge_string, url);
-
- ViewHostMsg_Keygen::WriteReplyParams(
- reply_msg,
- keygen_handler.GenKeyAndSignChallenge());
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(this, &ResourceMessageFilter::Send, reply_msg));
-}
-
-#if defined(USE_TCMALLOC)
-void ResourceMessageFilter::OnRendererTcmalloc(base::ProcessId pid,
- const std::string& output) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableFunction(AboutTcmallocRendererCallback, pid, output));
-}
-#endif
-
-void ResourceMessageFilter::OnEstablishGpuChannel() {
- GpuProcessHost::Get()->EstablishGpuChannel(id(), this);
-}
-
-void ResourceMessageFilter::OnSynchronizeGpu(IPC::Message* reply) {
- // We handle this message (and the other GPU process messages) here
- // rather than handing the message to the GpuProcessHost for
- // dispatch so that we can use the DELAY_REPLY macro to synthesize
- // the reply message, and also send down a "this" pointer so that
- // the GPU process host can send the reply later.
- GpuProcessHost::Get()->Synchronize(reply, this);
-}
-
-void ResourceMessageFilter::OnGetExtensionMessageBundle(
- const std::string& extension_id, IPC::Message* reply_msg) {
- ChromeURLRequestContext* context = static_cast<ChromeURLRequestContext*>(
- request_context_->GetURLRequestContext());
-
- FilePath extension_path =
- context->extension_info_map()->GetPathForExtension(extension_id);
- std::string default_locale =
- context->extension_info_map()->GetDefaultLocaleForExtension(extension_id);
-
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::OnGetExtensionMessageBundleOnFileThread,
- extension_path, extension_id, default_locale, reply_msg));
-}
-
-void ResourceMessageFilter::OnGetExtensionMessageBundleOnFileThread(
- const FilePath& extension_path,
- const std::string& extension_id,
- const std::string& default_locale,
- IPC::Message* reply_msg) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- std::map<std::string, std::string> dictionary_map;
- if (!default_locale.empty()) {
- // Touch disk only if extension is localized.
- std::string error;
- scoped_ptr<ExtensionMessageBundle> bundle(
- extension_file_util::LoadExtensionMessageBundle(
- extension_path, default_locale, &error));
-
- if (bundle.get())
- dictionary_map = *bundle->dictionary();
- }
-
- // Add @@extension_id reserved message here, so it's available to
- // non-localized extensions too.
- dictionary_map.insert(
- std::make_pair(ExtensionMessageBundle::kExtensionIdKey, extension_id));
-
- ViewHostMsg_GetExtensionMessageBundle::WriteReplyParams(
- reply_msg, dictionary_map);
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(this, &ResourceMessageFilter::Send, reply_msg));
-}
-
-void ResourceMessageFilter::OnAsyncOpenFile(const IPC::Message& msg,
- const FilePath& path,
- int flags,
- int message_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- if (!ChildProcessSecurityPolicy::GetInstance()->HasPermissionsForFile(
- id(), path, flags)) {
- DLOG(ERROR) << "Bad flags in ViewMsgHost_AsyncOpenFile message: " << flags;
- BrowserRenderProcessHost::BadMessageTerminateProcess(
- ViewHostMsg_AsyncOpenFile::ID, handle());
- return;
- }
-
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE, NewRunnableMethod(
- this, &ResourceMessageFilter::AsyncOpenFileOnFileThread,
- path, flags, message_id, msg.routing_id()));
-}
-
-void ResourceMessageFilter::AsyncOpenFileOnFileThread(const FilePath& path,
- int flags,
- int message_id,
- int routing_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- base::PlatformFileError error_code = base::PLATFORM_FILE_OK;
- base::PlatformFile file = base::CreatePlatformFile(
- path, flags, NULL, &error_code);
- IPC::PlatformFileForTransit file_for_transit =
- IPC::InvalidPlatformFileForTransit();
- if (file != base::kInvalidPlatformFileValue) {
-#if defined(OS_WIN)
- ::DuplicateHandle(::GetCurrentProcess(), file, handle(),
- &file_for_transit, 0, false, DUPLICATE_SAME_ACCESS);
-#else
- file_for_transit = base::FileDescriptor(file, true);
-#endif
- }
-
- IPC::Message* reply = new ViewMsg_AsyncOpenFile_ACK(
- routing_id, error_code, file_for_transit, message_id);
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE, NewRunnableMethod(
- this, &ResourceMessageFilter::Send, reply));
-}
-
-SetCookieCompletion::SetCookieCompletion(int render_process_id,
- int render_view_id,
- const GURL& url,
- const std::string& cookie_line,
- ChromeURLRequestContext* context)
- : render_process_id_(render_process_id),
- render_view_id_(render_view_id),
- url_(url),
- cookie_line_(cookie_line),
- context_(context) {
-}
-
-SetCookieCompletion::~SetCookieCompletion() {}
-
-void SetCookieCompletion::RunWithParams(const Tuple1<int>& params) {
- int result = params.a;
- bool blocked_by_policy = true;
- net::CookieOptions options;
- if (result == net::OK ||
- result == net::OK_FOR_SESSION_ONLY) {
- blocked_by_policy = false;
- if (result == net::OK_FOR_SESSION_ONLY)
- options.set_force_session();
- context_->cookie_store()->SetCookieWithOptions(url_, cookie_line_,
- options);
- }
- if (!context_->IsExternal()) {
- CallRenderViewHostContentSettingsDelegate(
- render_process_id_, render_view_id_,
- &RenderViewHostDelegate::ContentSettings::OnCookieAccessed,
- url_, cookie_line_, options, blocked_by_policy);
- }
- delete this;
-}
-
-GetCookiesCompletion::GetCookiesCompletion(int render_process_id,
- int render_view_id,
- const GURL& url,
- IPC::Message* reply_msg,
- ResourceMessageFilter* filter,
- URLRequestContext* context,
- bool raw_cookies)
- : url_(url),
- reply_msg_(reply_msg),
- filter_(filter),
- context_(context),
- render_process_id_(render_process_id),
- render_view_id_(render_view_id),
- raw_cookies_(raw_cookies) {
- set_cookie_store(context_->cookie_store());
-}
-
-GetCookiesCompletion::~GetCookiesCompletion() {}
-
-void GetCookiesCompletion::RunWithParams(const Tuple1<int>& params) {
- if (!raw_cookies_) {
- int result = params.a;
- std::string cookies;
- if (result == net::OK)
- cookies = cookie_store()->GetCookies(url_);
- ViewHostMsg_GetCookies::WriteReplyParams(reply_msg_, cookies);
- filter_->Send(reply_msg_);
- delete this;
- } else {
- // Ignore the policy result. We only waited on the policy result so that
- // any pending 'set-cookie' requests could be flushed. The intent of
- // querying the raw cookies is to reveal the contents of the cookie DB, so
- // it important that we don't read the cookie db ahead of pending writes.
- net::CookieMonster* cookie_monster =
- context_->cookie_store()->GetCookieMonster();
- net::CookieMonster::CookieList cookie_list =
- cookie_monster->GetAllCookiesForURL(url_);
-
- std::vector<webkit_glue::WebCookie> cookies;
- for (size_t i = 0; i < cookie_list.size(); ++i) {
- cookies.push_back(webkit_glue::WebCookie(cookie_list[i]));
- }
-
- ViewHostMsg_GetRawCookies::WriteReplyParams(reply_msg_, cookies);
- filter_->Send(reply_msg_);
- delete this;
- }
-}
-
-void GetCookiesCompletion::set_cookie_store(CookieStore* cookie_store) {
- cookie_store_ = cookie_store;
-}
-
-CookiesEnabledCompletion::CookiesEnabledCompletion(
- IPC::Message* reply_msg,
- ResourceMessageFilter* filter)
- : reply_msg_(reply_msg),
- filter_(filter) {
-}
-
-CookiesEnabledCompletion::~CookiesEnabledCompletion() {}
-void CookiesEnabledCompletion::RunWithParams(const Tuple1<int>& params) {
- bool result = params.a != net::ERR_ACCESS_DENIED;
- ViewHostMsg_CookiesEnabled::WriteReplyParams(reply_msg_, result);
- filter_->Send(reply_msg_);
- delete this;
+ return static_cast<ChromeURLRequestContext*>(rv);
}
diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h
index 38f8f15..69af8a9 100644
--- a/chrome/browser/renderer_host/resource_message_filter.h
+++ b/chrome/browser/renderer_host/resource_message_filter.h
@@ -4,591 +4,75 @@
#ifndef CHROME_BROWSER_RENDERER_HOST_RESOURCE_MESSAGE_FILTER_H_
#define CHROME_BROWSER_RENDERER_HOST_RESOURCE_MESSAGE_FILTER_H_
-#pragma once
-#if defined(OS_WIN)
-#include <windows.h>
-#endif
+#include "base/scoped_ptr.h"
+#include "chrome/browser/browser_message_filter.h"
+#include "chrome/common/child_process_info.h"
+#include "webkit/glue/resource_type.h"
-#include <string>
-#include <vector>
-
-#include "app/clipboard/clipboard.h"
-#include "app/surface/transport_dib.h"
-#include "base/callback.h"
-#include "base/file_path.h"
-#include "base/linked_ptr.h"
-#include "base/process.h"
-#include "base/ref_counted.h"
-#include "base/string16.h"
-#include "base/task.h"
-#include "build/build_config.h"
-#include "chrome/browser/net/resolve_proxy_msg_helper.h"
-#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
-#include "chrome/common/content_settings.h"
-#include "gfx/native_widget_types.h"
-#include "ipc/ipc_channel_proxy.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebCache.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebPopupType.h"
-
-class AppCacheDispatcherHost;
-class AudioRendererHost;
-class BlobDispatcherHost;
class ChromeURLRequestContext;
-class DatabaseDispatcherHost;
-class DOMStorageDispatcherHost;
-class FileSystemDispatcherHost;
-class FileUtilitiesDispatcherHost;
-struct FontDescriptor;
-class GeolocationDispatcherHostOld;
-class HostZoomMap;
-class IndexedDBDispatcherHost;
-class MimeRegistryDispatcher;
-class NotificationsPrefsCache;
-class PpapiPluginProcessHost;
-class Profile;
-class RenderWidgetHelper;
-class SearchProviderInstallStateDispatcherHost;
-class URLRequestContextGetter;
-struct ViewHostMsg_CreateWindow_Params;
-struct ViewHostMsg_CreateWorker_Params;
-struct WebPluginInfo;
-
-namespace base {
-struct PlatformFileInfo;
-class SharedMemory;
-}
-
-namespace device_orientation {
-class DispatcherHost;
-}
-
-namespace net {
-class CookieStore;
-}
-
-namespace printing {
-class PrinterQuery;
-class PrintJobManager;
-}
-
-namespace speech_input {
-class SpeechInputDispatcherHost;
-}
-
-namespace webkit_glue {
-struct WebCookie;
-}
-
-struct ViewHostMsg_ScriptedPrint_Params;
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
-struct ViewHostMsg_DidPrintPage_Params;
-#endif
+class ResourceDispatcherHost;
+class URLRequestContext;
// This class filters out incoming IPC messages for network requests and
// processes them on the IPC thread. As a result, network requests are not
// delayed by costly UI processing that may be occuring on the main thread of
// the browser. It also means that any hangs in starting a network request
// will not interfere with browser UI.
-
-class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
- public ResourceDispatcherHost::Receiver,
- public ResolveProxyMsgHelper::Delegate {
- public:
- // Create the filter.
- ResourceMessageFilter(ResourceDispatcherHost* resource_dispatcher_host,
- int child_id,
- AudioRendererHost* audio_renderer_host,
- PluginService* plugin_service,
- printing::PrintJobManager* print_job_manager,
- Profile* profile,
- RenderWidgetHelper* render_widget_helper);
-
- // IPC::ChannelProxy::MessageFilter methods:
- virtual void OnFilterAdded(IPC::Channel* channel);
- virtual void OnChannelConnected(int32 peer_pid);
- virtual void OnChannelError();
- virtual void OnChannelClosing();
- virtual bool OnMessageReceived(const IPC::Message& message);
- virtual void OnDestruct() const;
-
- // ResourceDispatcherHost::Receiver methods:
- virtual bool Send(IPC::Message* message);
- virtual URLRequestContext* GetRequestContext(
- uint32 request_id,
- const ViewHostMsg_Resource_Request& request_data);
-
- ResourceDispatcherHost* resource_dispatcher_host() {
- return resource_dispatcher_host_;
- }
- bool off_the_record() { return off_the_record_; }
- CallbackWithReturnValue<int>::Type* next_route_id_callback() {
- return next_route_id_callback_.get();
- }
-
- // Returns either the extension URLRequestContext or regular URLRequestContext
- // depending on whether |url| is an extension URL.
- // Only call on the IO thread.
- ChromeURLRequestContext* GetRequestContextForURL(const GURL& url);
-
- private:
- friend class BrowserThread;
- friend class DeleteTask<ResourceMessageFilter>;
-
- virtual ~ResourceMessageFilter();
-
- void OnMsgCreateWindow(const ViewHostMsg_CreateWindow_Params& params,
- int* route_id,
- int64* cloned_session_storage_namespace_id);
- void OnMsgCreateWidget(int opener_id,
- WebKit::WebPopupType popup_type,
- int* route_id);
- void OnMsgCreateFullscreenWidget(int opener_id,
- WebKit::WebPopupType popup_type,
- int* route_id);
- void OnSetCookie(const IPC::Message& message,
- const GURL& url,
- const GURL& first_party_for_cookies,
- const std::string& cookie);
- void OnGetCookies(const GURL& url,
- const GURL& first_party_for_cookies,
- IPC::Message* reply_msg);
- void OnGetRawCookies(const GURL& url,
- const GURL& first_party_for_cookies,
- IPC::Message* reply_msg);
- void OnDeleteCookie(const GURL& url,
- const std::string& cookieName);
- void OnCookiesEnabled(const GURL& url,
- const GURL& first_party_for_cookies,
- IPC::Message* reply_msg);
- void OnPluginFileDialog(const IPC::Message& msg,
- bool multiple_files,
- const std::wstring& title,
- const std::wstring& filter,
- uint32 user_data);
-
-#if defined(OS_MACOSX)
- void OnLoadFont(const FontDescriptor& font,
- uint32* handle_size,
- base::SharedMemoryHandle* handle);
-#endif
-
-#if defined(OS_WIN) // This hack is Windows-specific.
- // Cache fonts for the renderer. See ResourceMessageFilter::OnPreCacheFont
- // implementation for more details.
- void OnPreCacheFont(LOGFONT font);
-#endif
-
-#if !defined(OS_MACOSX)
- // Not handled in the IO thread on Mac.
- void OnGetScreenInfo(gfx::NativeViewId window, IPC::Message* reply);
-#endif
- void OnGetPlugins(bool refresh, IPC::Message* reply_msg);
- void OnGetPluginsOnFileThread(bool refresh, IPC::Message* reply_msg);
- void OnGetPluginInfo(const GURL& url,
- const GURL& policy_url,
- const std::string& mime_type,
- IPC::Message* reply_msg);
- void OnGetPluginInfoOnFileThread(const GURL& url,
- const GURL& policy_url,
- const std::string& mime_type,
- IPC::Message* reply_msg);
- void OnGotPluginInfo(bool found,
- const WebPluginInfo& info,
- const std::string& actual_mime_type,
- const GURL& policy_url,
- IPC::Message* reply_msg);
- void OnOpenChannelToPlugin(const GURL& url,
- const std::string& mime_type,
- IPC::Message* reply_msg);
- void OnOpenChannelToPepperPlugin(const FilePath& path,
- IPC::Message* reply_msg);
- void OnLaunchNaCl(const std::wstring& url,
- int channel_descriptor,
- IPC::Message* reply_msg);
- void OnCreateWorker(const ViewHostMsg_CreateWorker_Params& params,
- int* route_id);
- void OnLookupSharedWorker(const ViewHostMsg_CreateWorker_Params& params,
- bool* exists,
- int* route_id,
- bool* url_error);
- void OnDocumentDetached(unsigned long long document_id);
- void OnCancelCreateDedicatedWorker(int route_id);
- void OnForwardToWorker(const IPC::Message& msg);
- void OnDownloadUrl(const IPC::Message& message,
- const GURL& url,
- const GURL& referrer);
- void OnPlatformCheckSpelling(const string16& word, int tag, bool* correct);
- void OnPlatformFillSuggestionList(const string16& word,
- std::vector<string16>* suggestions);
- void OnGetDocumentTag(IPC::Message* reply_msg);
- void OnDocumentWithTagClosed(int tag);
- void OnShowSpellingPanel(bool show);
- void OnUpdateSpellingPanelWithMisspelledWord(const string16& word);
- void OnDnsPrefetch(const std::vector<std::string>& hostnames);
- void OnRendererHistograms(int sequence_number,
- const std::vector<std::string>& histogram_info);
-#if defined(USE_TCMALLOC)
- void OnRendererTcmalloc(base::ProcessId pid, const std::string& output);
-#endif
- void OnReceiveContextMenuMsg(const IPC::Message& msg);
- // Clipboard messages
- void OnClipboardWriteObjectsAsync(const Clipboard::ObjectMap& objects);
- void OnClipboardWriteObjectsSync(const Clipboard::ObjectMap& objects,
- base::SharedMemoryHandle bitmap_handle);
-
- void OnClipboardIsFormatAvailable(Clipboard::FormatType format,
- Clipboard::Buffer buffer,
- IPC::Message* reply);
- void OnClipboardReadText(Clipboard::Buffer buffer, IPC::Message* reply);
- void OnClipboardReadAsciiText(Clipboard::Buffer buffer, IPC::Message* reply);
- void OnClipboardReadHTML(Clipboard::Buffer buffer, IPC::Message* reply);
-#if defined(OS_MACOSX)
- void OnClipboardFindPboardWriteString(const string16& text);
-#endif
- void OnClipboardReadAvailableTypes(Clipboard::Buffer buffer,
- IPC::Message* reply);
- void OnClipboardReadData(Clipboard::Buffer buffer, const string16& type,
- IPC::Message* reply);
- void OnClipboardReadFilenames(Clipboard::Buffer buffer, IPC::Message* reply);
-
- void OnCheckNotificationPermission(const GURL& source_url,
- int* permission_level);
-
-#if !defined(OS_MACOSX)
- // Not handled in the IO thread on Mac.
- void OnGetWindowRect(gfx::NativeViewId window, IPC::Message* reply);
- void OnGetRootWindowRect(gfx::NativeViewId window, IPC::Message* reply);
-#endif
-
- void OnRevealFolderInOS(const FilePath& path);
- void OnGetCPBrowsingContext(uint32* context);
-
-#if defined(OS_WIN)
- // Used to pass resulting EMF from renderer to browser in printing.
- void OnDuplicateSection(base::SharedMemoryHandle renderer_handle,
- base::SharedMemoryHandle* browser_handle);
-#endif
-
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
- // Used to ask the browser allocate a temporary file for the renderer
- // to fill in resulting PDF in renderer.
- void OnAllocateTempFileForPrinting(IPC::Message* reply_msg);
- void OnTempFileForPrintingWritten(int fd_in_browser);
-#endif
-
-#if defined(OS_POSIX)
- // Used to ask the browser to allocate a block of shared memory for the
- // renderer to send back data in, since shared memory can't be created
- // in the renderer on POSIX due to the sandbox.
- void OnAllocateSharedMemoryBuffer(uint32 buffer_size,
- base::SharedMemoryHandle* handle);
-#endif
-
- void OnResourceTypeStats(const WebKit::WebCache::ResourceTypeStats& stats);
- static void OnResourceTypeStatsOnUIThread(
- const WebKit::WebCache::ResourceTypeStats&,
- base::ProcessId renderer_id);
-
- void OnV8HeapStats(int v8_memory_allocated, int v8_memory_used);
- static void OnV8HeapStatsOnUIThread(int v8_memory_allocated,
- int v8_memory_used,
- base::ProcessId renderer_id);
-
- void OnDidZoomURL(const IPC::Message& message,
- double zoom_level,
- bool remember,
- const GURL& url);
- void UpdateHostZoomLevelsOnUIThread(double zoom_level,
- bool remember,
- const GURL& url,
- int render_process_id,
- int render_view_id);
-
- void OnResolveProxy(const GURL& url, IPC::Message* reply_msg);
-
- // ResolveProxyMsgHelper::Delegate implementation:
- virtual void OnResolveProxyCompleted(IPC::Message* reply_msg,
- int result,
- const std::string& proxy_list);
-
- // A javascript code requested to print the current page. This is done in two
- // steps and this is the first step. Get the print setting right here
- // synchronously. It will hang the I/O completely.
- void OnGetDefaultPrintSettings(IPC::Message* reply_msg);
- void OnGetDefaultPrintSettingsReply(
- scoped_refptr<printing::PrinterQuery> printer_query,
- IPC::Message* reply_msg);
-
- // A javascript code requested to print the current page. The renderer host
- // have to show to the user the print dialog and returns the selected print
- // settings.
- void OnScriptedPrint(const ViewHostMsg_ScriptedPrint_Params& params,
- IPC::Message* reply_msg);
- void OnScriptedPrintReply(
- scoped_refptr<printing::PrinterQuery> printer_query,
- int routing_id,
- IPC::Message* reply_msg);
-
- // Browser side transport DIB allocation
- void OnAllocTransportDIB(size_t size,
- bool cache_in_browser,
- TransportDIB::Handle* result);
- void OnFreeTransportDIB(TransportDIB::Id dib_id);
-
- void OnOpenChannelToExtension(int routing_id,
- const std::string& source_extension_id,
- const std::string& target_extension_id,
- const std::string& channel_name, int* port_id);
- void OpenChannelToExtensionOnUIThread(int source_process_id,
- int source_routing_id,
- int receiver_port_id,
- const std::string& source_extension_id,
- const std::string& target_extension_id,
- const std::string& channel_name);
- void OnOpenChannelToTab(int routing_id, int tab_id,
- const std::string& extension_id,
- const std::string& channel_name, int* port_id);
- void OpenChannelToTabOnUIThread(int source_process_id, int source_routing_id,
- int receiver_port_id,
- int tab_id, const std::string& extension_id,
- const std::string& channel_name);
-
- void OnCloseCurrentConnections();
- void OnSetCacheMode(bool enabled);
- void OnClearCache(IPC::Message* reply_msg);
- void OnCacheableMetadataAvailable(const GURL& url,
- double expected_response_time,
- const std::vector<char>& data);
- void OnEnableSpdy(bool enable);
- void OnKeygen(uint32 key_size_index, const std::string& challenge_string,
- const GURL& url, IPC::Message* reply_msg);
- void OnKeygenOnWorkerThread(
- int key_size_in_bits,
- const std::string& challenge_string,
- const GURL& url,
- IPC::Message* reply_msg);
- void OnGetExtensionMessageBundle(const std::string& extension_id,
- IPC::Message* reply_msg);
- void OnGetExtensionMessageBundleOnFileThread(
- const FilePath& extension_path,
- const std::string& extension_id,
- const std::string& default_locale,
- IPC::Message* reply_msg);
- void OnEstablishGpuChannel();
- void OnSynchronizeGpu(IPC::Message* reply);
-
- void OnAsyncOpenFile(const IPC::Message& msg,
- const FilePath& path,
- int flags,
- int message_id);
- void AsyncOpenFileOnFileThread(const FilePath& path,
- int flags,
- int message_id,
- int routing_id);
-
-#if defined(USE_X11)
- void SendDelayedReply(IPC::Message* reply_msg);
- void DoOnGetScreenInfo(gfx::NativeViewId view, IPC::Message* reply_msg);
- void DoOnGetWindowRect(gfx::NativeViewId view, IPC::Message* reply_msg);
- void DoOnGetRootWindowRect(gfx::NativeViewId view, IPC::Message* reply_msg);
- void DoOnClipboardIsFormatAvailable(Clipboard::FormatType format,
- Clipboard::Buffer buffer,
- IPC::Message* reply_msg);
- void DoOnClipboardReadText(Clipboard::Buffer buffer, IPC::Message* reply_msg);
- void DoOnClipboardReadAsciiText(Clipboard::Buffer buffer,
- IPC::Message* reply_msg);
- void DoOnClipboardReadHTML(Clipboard::Buffer buffer, IPC::Message* reply_msg);
- void DoOnClipboardReadAvailableTypes(Clipboard::Buffer buffer,
- IPC::Message* reply_msg);
- void DoOnClipboardReadData(Clipboard::Buffer buffer, const string16& type,
- IPC::Message* reply_msg);
- void DoOnClipboardReadFilenames(Clipboard::Buffer buffer,
- IPC::Message* reply_msg);
- void DoOnAllocateTempFileForPrinting(IPC::Message* reply_msg);
-#endif
-
- bool CheckBenchmarkingEnabled() const;
- bool CheckPreparsedJsCachingEnabled() const;
-
- // We have our own clipboard because we want to access the clipboard on the
- // IO thread instead of forwarding (possibly synchronous) messages to the UI
- // thread. This instance of the clipboard should be accessed only on the IO
- // thread.
- static Clipboard* GetClipboard();
-
- // The channel associated with the renderer connection. This pointer is not
- // owned by this class.
- IPC::Channel* channel_;
-
- // Cached resource request dispatcher host and plugin service, guaranteed to
- // be non-null if Init succeeds. We do not own the objects, they are managed
- // by the BrowserProcess, which has a wider scope than we do.
- ResourceDispatcherHost* resource_dispatcher_host_;
- PluginService* plugin_service_;
- printing::PrintJobManager* print_job_manager_;
-
- // The Profile associated with our renderer process. This should only be
- // accessed on the UI thread!
- Profile* profile_;
-
- // Helper class for handling PluginProcessHost_ResolveProxy messages (manages
- // the requests to the proxy service).
- ResolveProxyMsgHelper resolve_proxy_msg_helper_;
-
- // Contextual information to be used for requests created here.
- scoped_refptr<URLRequestContextGetter> request_context_;
-
- // A request context specific for media resources.
- scoped_refptr<URLRequestContextGetter> media_request_context_;
-
- // A request context that holds a cookie store for chrome-extension URLs.
- scoped_refptr<URLRequestContextGetter> extensions_request_context_;
-
- scoped_refptr<RenderWidgetHelper> render_widget_helper_;
-
- // Object that should take care of audio related resource requests.
- scoped_refptr<AudioRendererHost> audio_renderer_host_;
-
- // Handles AppCache related messages.
- scoped_ptr<AppCacheDispatcherHost> appcache_dispatcher_host_;
-
- // Handles DOM Storage related messages.
- scoped_refptr<DOMStorageDispatcherHost> dom_storage_dispatcher_host_;
-
- // Handles Indexed Database related messages.
- scoped_refptr<IndexedDBDispatcherHost> indexed_db_dispatcher_host_;
-
- // Handles HTML5 DB related messages
- scoped_refptr<DatabaseDispatcherHost> db_dispatcher_host_;
-
- // A cache of notifications preferences which is used to handle
- // Desktop Notifications permission messages.
- scoped_refptr<NotificationsPrefsCache> notification_prefs_;
-
- // Handles zoom-related messages.
- scoped_refptr<HostZoomMap> host_zoom_map_;
-
- // Whether this process is used for off the record tabs.
- bool off_the_record_;
-
- bool cloud_print_enabled_;
-
- base::TimeTicks last_plugin_refresh_time_; // Initialized to 0.
-
- // A list of all Ppapi plugin processes for this renderer.
- std::vector<linked_ptr<PpapiPluginProcessHost> > ppapi_plugin_hosts_;
-
- // A callback to create a routing id for the associated renderer process.
- scoped_ptr<CallbackWithReturnValue<int>::Type> next_route_id_callback_;
-
- // Used to handle speech input related messages.
- scoped_refptr<speech_input::SpeechInputDispatcherHost>
- speech_input_dispatcher_host_;
-
- // Used to handle geolocation-related messages.
- scoped_refptr<GeolocationDispatcherHostOld> geolocation_dispatcher_host_;
-
- // Used to handle search provider related messages.
- scoped_ptr<SearchProviderInstallStateDispatcherHost>
- search_provider_install_state_dispatcher_host_;
-
- // Used to handle device orientation related messages.
- scoped_refptr<device_orientation::DispatcherHost>
- device_orientation_dispatcher_host_;
-
- // Handles FileSystem API related messages
- scoped_refptr<FileSystemDispatcherHost> file_system_dispatcher_host_;
-
- // Handles blob related messages.
- scoped_ptr<BlobDispatcherHost> blob_dispatcher_host_;
-
- // Handles file utilities messages.
- scoped_refptr<FileUtilitiesDispatcherHost> file_utilities_dispatcher_host_;
-
- // Handles mime registry requests.
- scoped_refptr<MimeRegistryDispatcher> mime_registry_dispatcher_;
-
- DISALLOW_COPY_AND_ASSIGN(ResourceMessageFilter);
-};
-
-// These classes implement completion callbacks for getting and setting
-// cookies.
-class SetCookieCompletion : public net::CompletionCallback {
+class ResourceMessageFilter : public BrowserMessageFilter {
public:
- SetCookieCompletion(int render_process_id,
- int render_view_id,
- const GURL& url,
- const std::string& cookie_line,
- ChromeURLRequestContext* context);
- virtual ~SetCookieCompletion();
+ // Allows overriding the URLRequestContext used to service requests.
+ class URLRequestContextOverride
+ : public base::RefCountedThreadSafe<URLRequestContextOverride> {
+ public:
+ URLRequestContextOverride() {}
- virtual void RunWithParams(const Tuple1<int>& params);
+ virtual URLRequestContext* GetRequestContext(
+ uint32 request_id, ResourceType::Type resource_type) = 0;
- int render_process_id() const {
- return render_process_id_;
- }
+ protected:
+ friend class base::RefCountedThreadSafe<URLRequestContextOverride>;
+ virtual ~URLRequestContextOverride() {}
- int render_view_id() const {
- return render_view_id_;
- }
+ DISALLOW_COPY_AND_ASSIGN(URLRequestContextOverride);
+ };
- private:
- int render_process_id_;
- int render_view_id_;
- GURL url_;
- std::string cookie_line_;
- scoped_refptr<ChromeURLRequestContext> context_;
-};
+ ResourceMessageFilter(int child_id,
+ ChildProcessInfo::ProcessType process_type,
+ ResourceDispatcherHost* resource_dispatcher_host);
-class GetCookiesCompletion : public net::CompletionCallback {
- public:
- GetCookiesCompletion(int render_process_id,
- int render_view_id,
- const GURL& url, IPC::Message* reply_msg,
- ResourceMessageFilter* filter,
- URLRequestContext* context,
- bool raw_cookies);
- virtual ~GetCookiesCompletion();
-
- virtual void RunWithParams(const Tuple1<int>& params);
+ // BrowserMessageFilter implementation.
+ virtual void OnChannelClosing();
+ virtual bool OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok);
- int render_process_id() const {
- return render_process_id_;
- }
+ // Returns the URLRequestContext for the given request.
+ ChromeURLRequestContext* GetURLRequestContext(
+ uint32 request_id, ResourceType::Type resource_type);
- int render_view_id() const {
- return render_view_id_;
+ void set_url_request_context_override(URLRequestContextOverride* u) {
+ url_request_context_override_ = u;
}
- void set_cookie_store(net::CookieStore* cookie_store);
+ int child_id() const { return child_id_; }
+ ChildProcessInfo::ProcessType process_type() const { return process_type_; }
- net::CookieStore* cookie_store() {
- return cookie_store_.get();
- }
+ protected:
+ // Protected destructor so that we can be overriden in tests.
+ virtual ~ResourceMessageFilter();
private:
- GURL url_;
- IPC::Message* reply_msg_;
- scoped_refptr<ResourceMessageFilter> filter_;
- scoped_refptr<URLRequestContext> context_;
- int render_process_id_;
- int render_view_id_;
- bool raw_cookies_;
- scoped_refptr<net::CookieStore> cookie_store_;
-};
+ // The ID of the child process.
+ int child_id_;
-class CookiesEnabledCompletion : public net::CompletionCallback {
- public:
- CookiesEnabledCompletion(IPC::Message* reply_msg,
- ResourceMessageFilter* filter);
- virtual ~CookiesEnabledCompletion();
+ ChildProcessInfo::ProcessType process_type_;
- virtual void RunWithParams(const Tuple1<int>& params);
+ // Owned by BrowserProcess, which is guaranteed to outlive us.
+ ResourceDispatcherHost* resource_dispatcher_host_;
- private:
- IPC::Message* reply_msg_;
- scoped_refptr<ResourceMessageFilter> filter_;
+ scoped_refptr<URLRequestContextOverride> url_request_context_override_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ResourceMessageFilter);
};
#endif // CHROME_BROWSER_RENDERER_HOST_RESOURCE_MESSAGE_FILTER_H_
diff --git a/chrome/browser/renderer_host/resource_message_filter_gtk.cc b/chrome/browser/renderer_host/resource_message_filter_gtk.cc
deleted file mode 100644
index 59c6588..0000000
--- a/chrome/browser/renderer_host/resource_message_filter_gtk.cc
+++ /dev/null
@@ -1,388 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/renderer_host/resource_message_filter.h"
-
-#include <fcntl.h>
-#include <map>
-
-#include "app/clipboard/clipboard.h"
-#include "app/x11_util.h"
-#include "base/file_util.h"
-#include "base/path_service.h"
-#include "base/singleton.h"
-#include "chrome/browser/browser_thread.h"
-#if defined(TOOLKIT_GTK)
-#include "chrome/browser/printing/print_dialog_gtk.h"
-#else
-#include "chrome/browser/printing/print_dialog_cloud.h"
-#endif
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/render_messages.h"
-#include "gfx/gtk_native_view_id_manager.h"
-#include "grit/generated_resources.h"
-
-#include "third_party/WebKit/WebKit/chromium/public/WebScreenInfo.h"
-#include "third_party/WebKit/WebKit/chromium/public/x11/WebScreenInfoFactory.h"
-
-using WebKit::WebScreenInfo;
-using WebKit::WebScreenInfoFactory;
-
-namespace {
-
-typedef std::map<int, FilePath> FdMap;
-
-struct PrintingFileDescriptorMap {
- FdMap map;
-};
-
-} // namespace
-
-// We get null window_ids passed into the two functions below; please see
-// http://crbug.com/9060 for more details.
-
-// Called on the IO thread.
-void ResourceMessageFilter::SendDelayedReply(IPC::Message* reply_msg) {
- Send(reply_msg);
-}
-
-// Called on the BACKGROUND_X11 thread.
-void ResourceMessageFilter::DoOnGetScreenInfo(gfx::NativeViewId view,
- IPC::Message* reply_msg) {
- Display* display = x11_util::GetSecondaryDisplay();
- int screen = x11_util::GetDefaultScreen(display);
- WebScreenInfo results = WebScreenInfoFactory::screenInfo(display, screen);
- ViewHostMsg_GetScreenInfo::WriteReplyParams(reply_msg, results);
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::SendDelayedReply, reply_msg));
-}
-
-// Called on the BACKGROUND_X11 thread.
-void ResourceMessageFilter::DoOnGetWindowRect(gfx::NativeViewId view,
- IPC::Message* reply_msg) {
- // This is called to get the x, y offset (in screen coordinates) of the given
- // view and its width and height.
- gfx::Rect rect;
- XID window;
-
- AutoLock lock(Singleton<GtkNativeViewManager>()->unrealize_lock());
- if (Singleton<GtkNativeViewManager>()->GetXIDForId(&window, view)) {
- if (window) {
- int x, y;
- unsigned width, height;
- if (x11_util::GetWindowGeometry(&x, &y, &width, &height, window))
- rect = gfx::Rect(x, y, width, height);
- }
- }
-
- ViewHostMsg_GetWindowRect::WriteReplyParams(reply_msg, rect);
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::SendDelayedReply, reply_msg));
-}
-
-// Return the top-level parent of the given window. Called on the
-// BACKGROUND_X11 thread.
-static XID GetTopLevelWindow(XID window) {
- bool parent_is_root;
- XID parent_window;
-
- if (!x11_util::GetWindowParent(&parent_window, &parent_is_root, window))
- return 0;
- if (parent_is_root)
- return window;
-
- return GetTopLevelWindow(parent_window);
-}
-
-// Called on the BACKGROUND_X11 thread.
-void ResourceMessageFilter::DoOnGetRootWindowRect(gfx::NativeViewId view,
- IPC::Message* reply_msg) {
- // This is called to get the screen coordinates and size of the browser
- // window itself.
- gfx::Rect rect;
- XID window;
-
- AutoLock lock(Singleton<GtkNativeViewManager>()->unrealize_lock());
- if (Singleton<GtkNativeViewManager>()->GetXIDForId(&window, view)) {
- if (window) {
- const XID toplevel = GetTopLevelWindow(window);
- if (toplevel) {
- int x, y;
- unsigned width, height;
- if (x11_util::GetWindowGeometry(&x, &y, &width, &height, toplevel))
- rect = gfx::Rect(x, y, width, height);
- }
- }
- }
-
- ViewHostMsg_GetRootWindowRect::WriteReplyParams(reply_msg, rect);
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::SendDelayedReply, reply_msg));
-}
-
-// Called on the UI thread.
-void ResourceMessageFilter::DoOnClipboardIsFormatAvailable(
- Clipboard::FormatType format, Clipboard::Buffer buffer,
- IPC::Message* reply_msg) {
- const bool result = GetClipboard()->IsFormatAvailable(format, buffer);
-
- ViewHostMsg_ClipboardIsFormatAvailable::WriteReplyParams(reply_msg, result);
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::SendDelayedReply, reply_msg));
-}
-
-// Called on the UI thread.
-void ResourceMessageFilter::DoOnClipboardReadText(Clipboard::Buffer buffer,
- IPC::Message* reply_msg) {
- string16 result;
- GetClipboard()->ReadText(buffer, &result);
-
- ViewHostMsg_ClipboardReadText::WriteReplyParams(reply_msg, result);
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::SendDelayedReply, reply_msg));
-}
-
-// Called on the UI thread.
-void ResourceMessageFilter::DoOnClipboardReadAsciiText(
- Clipboard::Buffer buffer, IPC::Message* reply_msg) {
- std::string result;
- GetClipboard()->ReadAsciiText(buffer, &result);
-
- ViewHostMsg_ClipboardReadAsciiText::WriteReplyParams(reply_msg, result);
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::SendDelayedReply, reply_msg));
-}
-
-// Called on the UI thread.
-void ResourceMessageFilter::DoOnClipboardReadHTML(Clipboard::Buffer buffer,
- IPC::Message* reply_msg) {
- std::string src_url_str;
- string16 markup;
- GetClipboard()->ReadHTML(buffer, &markup, &src_url_str);
- const GURL src_url = GURL(src_url_str);
-
- ViewHostMsg_ClipboardReadHTML::WriteReplyParams(reply_msg, markup, src_url);
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::SendDelayedReply, reply_msg));
-}
-
-// Called on the UI thread.
-void ResourceMessageFilter::DoOnClipboardReadAvailableTypes(
- Clipboard::Buffer buffer, IPC::Message* reply_msg) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::SendDelayedReply, reply_msg));
-}
-
-// Called on the UI thread.
-void ResourceMessageFilter::DoOnClipboardReadData(Clipboard::Buffer buffer,
- const string16& type,
- IPC::Message* reply_msg) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::SendDelayedReply, reply_msg));
-}
-// Called on the UI thread.
-void ResourceMessageFilter::DoOnClipboardReadFilenames(
- Clipboard::Buffer buffer, IPC::Message* reply_msg) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::SendDelayedReply, reply_msg));
-}
-
-// Called on the FILE thread.
-void ResourceMessageFilter::DoOnAllocateTempFileForPrinting(
- IPC::Message* reply_msg) {
- base::FileDescriptor temp_file_fd;
- int fd_in_browser;
- temp_file_fd.fd = fd_in_browser = -1;
- temp_file_fd.auto_close = false;
-
- bool allow_print =
-#if defined(TOOLKIT_GTK)
- !PrintDialogGtk::DialogShowing();
-#else
- true;
-#endif
- FilePath path;
- if (allow_print &&
- file_util::CreateTemporaryFile(&path)) {
- int fd = open(path.value().c_str(), O_WRONLY);
- if (fd >= 0) {
- FdMap* map = &Singleton<PrintingFileDescriptorMap>::get()->map;
- FdMap::iterator it = map->find(fd);
- if (it != map->end()) {
- NOTREACHED() << "The file descriptor is in use. fd=" << fd;
- } else {
- (*map)[fd] = path;
- temp_file_fd.fd = fd_in_browser = fd;
- temp_file_fd.auto_close = true;
- }
- }
- }
-
- ViewHostMsg_AllocateTempFileForPrinting::WriteReplyParams(
- reply_msg, temp_file_fd, fd_in_browser);
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::SendDelayedReply, reply_msg));
-}
-
-// Called on the IO thread.
-void ResourceMessageFilter::OnGetScreenInfo(gfx::NativeViewId view,
- IPC::Message* reply_msg) {
- BrowserThread::PostTask(
- BrowserThread::BACKGROUND_X11, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::DoOnGetScreenInfo, view, reply_msg));
-}
-
-// Called on the IO thread.
-void ResourceMessageFilter::OnGetWindowRect(gfx::NativeViewId view,
- IPC::Message* reply_msg) {
- BrowserThread::PostTask(
- BrowserThread::BACKGROUND_X11, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::DoOnGetWindowRect, view, reply_msg));
-}
-
-// Called on the IO thread.
-void ResourceMessageFilter::OnGetRootWindowRect(gfx::NativeViewId view,
- IPC::Message* reply_msg) {
- BrowserThread::PostTask(
- BrowserThread::BACKGROUND_X11, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::DoOnGetRootWindowRect, view,
- reply_msg));
-}
-
-// Called on the IO thread.
-void ResourceMessageFilter::OnClipboardIsFormatAvailable(
- Clipboard::FormatType format, Clipboard::Buffer buffer,
- IPC::Message* reply_msg) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::DoOnClipboardIsFormatAvailable, format,
- buffer, reply_msg));
-}
-
-// Called on the IO thread.
-void ResourceMessageFilter::OnClipboardReadText(Clipboard::Buffer buffer,
- IPC::Message* reply_msg) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::DoOnClipboardReadText, buffer,
- reply_msg));
-}
-
-// Called on the IO thread.
-void ResourceMessageFilter::OnClipboardReadAsciiText(Clipboard::Buffer buffer,
- IPC::Message* reply_msg) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::DoOnClipboardReadAsciiText, buffer,
- reply_msg));
-}
-
-// Called on the IO thread.
-void ResourceMessageFilter::OnClipboardReadHTML(Clipboard::Buffer buffer,
- IPC::Message* reply_msg) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::DoOnClipboardReadHTML, buffer,
- reply_msg));
-}
-
-// Called on the IO thread.
-void ResourceMessageFilter::OnClipboardReadAvailableTypes(
- Clipboard::Buffer buffer, IPC::Message* reply_msg) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::DoOnClipboardReadAvailableTypes, buffer,
- reply_msg));
-}
-
-// Called on the IO thread.
-void ResourceMessageFilter::OnClipboardReadData(
- Clipboard::Buffer buffer, const string16& type, IPC::Message* reply_msg) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::DoOnClipboardReadData, buffer, type,
- reply_msg));
-}
-
-// Called on the IO thread.
-void ResourceMessageFilter::OnClipboardReadFilenames(
- Clipboard::Buffer buffer, IPC::Message* reply_msg) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::DoOnClipboardReadFilenames, buffer,
- reply_msg));
-}
-
-// Called on the IO thread.
-void ResourceMessageFilter::OnAllocateTempFileForPrinting(
- IPC::Message* reply_msg) {
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- NewRunnableMethod(
- this, &ResourceMessageFilter::DoOnAllocateTempFileForPrinting,
- reply_msg));
-}
-
-// Called on the IO thread.
-void ResourceMessageFilter::OnTempFileForPrintingWritten(int fd_in_browser) {
- FdMap* map = &Singleton<PrintingFileDescriptorMap>::get()->map;
- FdMap::iterator it = map->find(fd_in_browser);
- if (it == map->end()) {
- NOTREACHED() << "Got a file descriptor that we didn't pass to the "
- "renderer: " << fd_in_browser;
- return;
- }
-
-#if defined(TOOLKIT_GTK)
- PrintDialogGtk::CreatePrintDialogForPdf(it->second);
-#else
- if (cloud_print_enabled_)
- PrintDialogCloud::CreatePrintDialogForPdf(it->second);
- else
- NOTIMPLEMENTED();
-#endif
-
- // Erase the entry in the map.
- map->erase(it);
-}
diff --git a/chrome/browser/renderer_host/resource_message_filter_mac.mm b/chrome/browser/renderer_host/resource_message_filter_mac.mm
deleted file mode 100644
index 09d17dc..0000000
--- a/chrome/browser/renderer_host/resource_message_filter_mac.mm
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) 2006-2009 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 "chrome/browser/renderer_host/resource_message_filter.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/message_loop.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/browser_thread.h"
-#import "chrome/browser/cocoa/find_pasteboard.h"
-
-// The number of utf16 code units that will be written to the find pasteboard,
-// longer texts are silently ignored. This is to prevent that a compromised
-// renderer can write unlimited amounts of data into the find pasteboard.
-static const size_t kMaxFindPboardStringLength = 4096;
-
-class WriteFindPboardTask : public Task {
- public:
- explicit WriteFindPboardTask(NSString* text)
- : text_([text retain]) {}
-
- void Run() {
- [[FindPasteboard sharedInstance] setFindText:text_];
- }
-
- private:
- scoped_nsobject<NSString> text_;
-};
-
-// Called on the IO thread.
-void ResourceMessageFilter::OnClipboardFindPboardWriteString(
- const string16& text) {
- if (text.length() <= kMaxFindPboardStringLength) {
- NSString* nsText = base::SysUTF16ToNSString(text);
- if (nsText) {
- // FindPasteboard must be used on the UI thread.
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE, new WriteFindPboardTask(nsText));
- }
- }
-}
diff --git a/chrome/browser/renderer_host/resource_message_filter_win.cc b/chrome/browser/renderer_host/resource_message_filter_win.cc
deleted file mode 100644
index 4a8c46e..0000000
--- a/chrome/browser/renderer_host/resource_message_filter_win.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2006-2009 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 "chrome/browser/renderer_host/resource_message_filter.h"
-#include "chrome/common/render_messages.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebScreenInfo.h"
-#include "third_party/WebKit/WebKit/chromium/public/win/WebScreenInfoFactory.h"
-
-using WebKit::WebScreenInfo;
-using WebKit::WebScreenInfoFactory;
-
-// We get null window_ids passed into the two functions below; please see
-// http://crbug.com/9060 for more details.
-
-// TODO(shess): Provide a mapping from reply_msg->routing_id() to HWND
-// so that we can eliminate the NativeViewId parameter.
-
-void ResourceMessageFilter::OnGetWindowRect(gfx::NativeViewId window_id,
- IPC::Message* reply_msg) {
- HWND window = gfx::NativeViewFromId(window_id);
- RECT window_rect = {0};
- GetWindowRect(window, &window_rect);
- gfx::Rect rect(window_rect);
-
- ViewHostMsg_GetWindowRect::WriteReplyParams(reply_msg, rect);
- Send(reply_msg);
-}
-
-void ResourceMessageFilter::OnGetRootWindowRect(gfx::NativeViewId window_id,
- IPC::Message* reply_msg) {
- HWND window = gfx::NativeViewFromId(window_id);
- RECT window_rect = {0};
- HWND root_window = ::GetAncestor(window, GA_ROOT);
- GetWindowRect(root_window, &window_rect);
- gfx::Rect rect(window_rect);
-
- ViewHostMsg_GetRootWindowRect::WriteReplyParams(reply_msg, rect);
- Send(reply_msg);
-}
-
-void ResourceMessageFilter::OnGetScreenInfo(gfx::NativeViewId view,
- IPC::Message* reply_msg) {
- WebScreenInfo results =
- WebScreenInfoFactory::screenInfo(gfx::NativeViewFromId(view));
- ViewHostMsg_GetScreenInfo::WriteReplyParams(reply_msg, results);
- Send(reply_msg);
-}
diff --git a/chrome/browser/renderer_host/resource_queue.cc b/chrome/browser/renderer_host/resource_queue.cc
index 668f6e6..66d02a1 100644
--- a/chrome/browser/renderer_host/resource_queue.cc
+++ b/chrome/browser/renderer_host/resource_queue.cc
@@ -37,7 +37,7 @@ void ResourceQueue::Shutdown() {
}
void ResourceQueue::AddRequest(
- URLRequest* request,
+ net::URLRequest* request,
const ResourceDispatcherHostRequestInfo& request_info) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DCHECK(!shutdown_);
@@ -84,7 +84,7 @@ void ResourceQueue::StartDelayedRequest(ResourceQueueDelegate* delegate,
interested_delegates_.erase(request_id);
if (ContainsKey(requests_, request_id)) {
- URLRequest* request = requests_[request_id];
+ net::URLRequest* request = requests_[request_id];
// The request shouldn't have started (SUCCESS is the initial state).
DCHECK_EQ(URLRequestStatus::SUCCESS, request->status().status());
request->Start();
diff --git a/chrome/browser/renderer_host/resource_queue.h b/chrome/browser/renderer_host/resource_queue.h
index d6ce412..e3e5e2f 100644
--- a/chrome/browser/renderer_host/resource_queue.h
+++ b/chrome/browser/renderer_host/resource_queue.h
@@ -18,7 +18,7 @@ class URLRequest;
class ResourceDispatcherHostRequestInfo;
struct GlobalRequestID;
-// Makes decisions about delaying or not each URLRequest in the queue.
+// Makes decisions about delaying or not each net::URLRequest in the queue.
// All methods are called on the IO thread.
class ResourceQueueDelegate {
public:
@@ -65,8 +65,8 @@ class ResourceQueue {
void AddRequest(net::URLRequest* request,
const ResourceDispatcherHostRequestInfo& request_info);
- // Tells the queue that the URLRequest object associated with |request_id|
- // is no longer valid.
+ // Tells the queue that the net::URLRequest object associated with
+ // |request_id| is no longer valid.
void RemoveRequest(const GlobalRequestID& request_id);
// A delegate should call StartDelayedRequest when it wants to allow the
@@ -83,8 +83,8 @@ class ResourceQueue {
// initialized.
DelegateSet delegates_;
- // Stores URLRequest objects associated with each GlobalRequestID. This helps
- // decoupling the queue from ResourceDispatcherHost.
+ // Stores net::URLRequest objects associated with each GlobalRequestID. This
+ // helps decoupling the queue from ResourceDispatcherHost.
RequestMap requests_;
// Maps a GlobalRequestID to the set of delegates that want to prevent the
diff --git a/chrome/browser/renderer_host/resource_queue_unittest.cc b/chrome/browser/renderer_host/resource_queue_unittest.cc
index 30ebc2f..3339701 100644
--- a/chrome/browser/renderer_host/resource_queue_unittest.cc
+++ b/chrome/browser/renderer_host/resource_queue_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// 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.
@@ -76,7 +76,7 @@ ResourceDispatcherHostRequestInfo* GetRequestInfo(int request_id) {
return new ResourceDispatcherHostRequestInfo(
new DummyResourceHandler(), ChildProcessInfo::RENDER_PROCESS, 0, 0,
request_id, "null", "null", ResourceType::MAIN_FRAME,
- 0, false, false, -1, -1);
+ 0, false, false, false, -1, -1);
}
void InitializeQueue(ResourceQueue* queue, ResourceQueueDelegate* delegate) {
@@ -100,7 +100,7 @@ class NeverDelayingDelegate : public ResourceQueueDelegate {
}
virtual bool ShouldDelayRequest(
- URLRequest* request,
+ net::URLRequest* request,
const ResourceDispatcherHostRequestInfo& request_info,
const GlobalRequestID& request_id) {
return false;
@@ -120,7 +120,7 @@ class AlwaysDelayingDelegate : public ResourceQueueDelegate {
}
virtual bool ShouldDelayRequest(
- URLRequest* request,
+ net::URLRequest* request,
const ResourceDispatcherHostRequestInfo& request_info,
const GlobalRequestID& request_id) {
delayed_requests_.push_back(request_id);
@@ -151,7 +151,8 @@ class AlwaysDelayingDelegate : public ResourceQueueDelegate {
DISALLOW_COPY_AND_ASSIGN(AlwaysDelayingDelegate);
};
-class ResourceQueueTest : public testing::Test, public URLRequest::Delegate {
+class ResourceQueueTest : public testing::Test,
+ public net::URLRequest::Delegate {
public:
ResourceQueueTest()
: response_started_count_(0),
@@ -160,14 +161,14 @@ class ResourceQueueTest : public testing::Test, public URLRequest::Delegate {
io_thread_(BrowserThread::IO, &message_loop_) {
}
- virtual void OnResponseStarted(URLRequest* request) {
+ virtual void OnResponseStarted(net::URLRequest* request) {
response_started_count_++;
// We're not going to do anything more with the request. Cancel it now
- // to avoid leaking URLRequestJob.
+ // to avoid leaking net::URLRequestJob.
request->Cancel();
}
- virtual void OnReadCompleted(URLRequest* request, int bytes_read) {
+ virtual void OnReadCompleted(net::URLRequest* request, int bytes_read) {
}
protected:
@@ -192,7 +193,7 @@ TEST_F(ResourceQueueTest, NeverDelayingDelegate) {
NeverDelayingDelegate delegate;
InitializeQueue(&queue, &delegate);
- URLRequest request(GURL(kTestUrl), this);
+ net::URLRequest request(GURL(kTestUrl), this);
scoped_ptr<ResourceDispatcherHostRequestInfo> request_info(GetRequestInfo(0));
EXPECT_EQ(0, response_started_count_);
queue.AddRequest(&request, *request_info.get());
@@ -208,7 +209,7 @@ TEST_F(ResourceQueueTest, AlwaysDelayingDelegate) {
AlwaysDelayingDelegate delegate(&queue);
InitializeQueue(&queue, &delegate);
- URLRequest request(GURL(kTestUrl), this);
+ net::URLRequest request(GURL(kTestUrl), this);
scoped_ptr<ResourceDispatcherHostRequestInfo> request_info(GetRequestInfo(0));
EXPECT_EQ(0, response_started_count_);
queue.AddRequest(&request, *request_info.get());
@@ -227,7 +228,7 @@ TEST_F(ResourceQueueTest, AlwaysDelayingDelegateAfterShutdown) {
AlwaysDelayingDelegate delegate(&queue);
InitializeQueue(&queue, &delegate);
- URLRequest request(GURL(kTestUrl), this);
+ net::URLRequest request(GURL(kTestUrl), this);
scoped_ptr<ResourceDispatcherHostRequestInfo> request_info(GetRequestInfo(0));
EXPECT_EQ(0, response_started_count_);
queue.AddRequest(&request, *request_info.get());
@@ -248,7 +249,7 @@ TEST_F(ResourceQueueTest, TwoDelegates) {
NeverDelayingDelegate never_delaying_delegate;
InitializeQueue(&queue, &always_delaying_delegate, &never_delaying_delegate);
- URLRequest request(GURL(kTestUrl), this);
+ net::URLRequest request(GURL(kTestUrl), this);
scoped_ptr<ResourceDispatcherHostRequestInfo> request_info(GetRequestInfo(0));
EXPECT_EQ(0, response_started_count_);
queue.AddRequest(&request, *request_info.get());
@@ -267,7 +268,7 @@ TEST_F(ResourceQueueTest, RemoveRequest) {
AlwaysDelayingDelegate delegate(&queue);
InitializeQueue(&queue, &delegate);
- URLRequest request(GURL(kTestUrl), this);
+ net::URLRequest request(GURL(kTestUrl), this);
scoped_ptr<ResourceDispatcherHostRequestInfo> request_info(GetRequestInfo(0));
GlobalRequestID request_id(request_info->child_id(),
request_info->request_id());
diff --git a/chrome/browser/renderer_host/resource_request_details.cc b/chrome/browser/renderer_host/resource_request_details.cc
index 20a255d..07183d4 100644
--- a/chrome/browser/renderer_host/resource_request_details.cc
+++ b/chrome/browser/renderer_host/resource_request_details.cc
@@ -4,8 +4,9 @@
#include "chrome/browser/renderer_host/resource_request_details.h"
+#include "chrome/browser/worker_host/worker_service.h"
-ResourceRequestDetails::ResourceRequestDetails(const URLRequest* request,
+ResourceRequestDetails::ResourceRequestDetails(const net::URLRequest* request,
int cert_id)
: url_(request->url()),
original_url_(request->original_url()),
@@ -26,25 +27,20 @@ ResourceRequestDetails::ResourceRequestDetails(const URLRequest* request,
// If request is from the worker process on behalf of a renderer, use
// the renderer process id, since it consumes the notification response
// such as ssl state etc.
- const WorkerProcessHost::WorkerInstance* worker_instance =
- WorkerService::GetInstance()->FindWorkerInstance(info->child_id());
- if (worker_instance) {
- DCHECK(!worker_instance->worker_document_set()->IsEmpty());
- const WorkerDocumentSet::DocumentInfoSet& parents =
- worker_instance->worker_document_set()->documents();
- // TODO(atwilson): need to notify all associated renderers in the case
- // of ssl state change (http://crbug.com/25357). For now, just notify
- // the first one (works for dedicated workers and shared workers with
- // a single process).
- origin_child_id_ = parents.begin()->renderer_id();
- } else {
+ // TODO(atwilson): need to notify all associated renderers in the case
+ // of ssl state change (http://crbug.com/25357). For now, just notify
+ // the first one (works for dedicated workers and shared workers with
+ // a single process).
+ int temp;
+ if (!WorkerService::GetInstance()->GetRendererForWorker(
+ info->child_id(), &origin_child_id_, &temp)) {
origin_child_id_ = info->child_id();
}
}
ResourceRequestDetails::~ResourceRequestDetails() {}
-ResourceRedirectDetails::ResourceRedirectDetails(const URLRequest* request,
+ResourceRedirectDetails::ResourceRedirectDetails(const net::URLRequest* request,
int cert_id,
const GURL& new_url)
: ResourceRequestDetails(request, cert_id),
diff --git a/chrome/browser/renderer_host/resource_request_details.h b/chrome/browser/renderer_host/resource_request_details.h
index bdb87bf..6f53de3 100644
--- a/chrome/browser/renderer_host/resource_request_details.h
+++ b/chrome/browser/renderer_host/resource_request_details.h
@@ -4,7 +4,7 @@
// The ResourceRequestDetails object contains additional details about a
// resource request. It copies many of the publicly accessible member variables
-// of URLRequest, but exists on the UI thread.
+// of net::URLRequest, but exists on the UI thread.
#ifndef CHROME_BROWSER_RENDERER_HOST_RESOURCE_REQUEST_DETAILS_H_
#define CHROME_BROWSER_RENDERER_HOST_RESOURCE_REQUEST_DETAILS_H_
@@ -12,7 +12,6 @@
#include <string>
-#include "chrome/browser/cert_store.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
#include "chrome/browser/worker_host/worker_service.h"
diff --git a/chrome/browser/renderer_host/safe_browsing_resource_handler.cc b/chrome/browser/renderer_host/safe_browsing_resource_handler.cc
index 3222ecc..237cad8 100644
--- a/chrome/browser/renderer_host/safe_browsing_resource_handler.cc
+++ b/chrome/browser/renderer_host/safe_browsing_resource_handler.cc
@@ -8,7 +8,6 @@
#include "chrome/browser/renderer_host/global_request_id.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/renderer_host/resource_message_filter.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/resource_response.h"
#include "net/base/net_errors.h"
#include "net/base/io_buffer.h"
@@ -27,8 +26,7 @@ SafeBrowsingResourceHandler::SafeBrowsingResourceHandler(
int render_view_id,
ResourceType::Type resource_type,
SafeBrowsingService* safe_browsing,
- ResourceDispatcherHost* resource_dispatcher_host,
- ResourceDispatcherHost::Receiver* receiver)
+ ResourceDispatcherHost* resource_dispatcher_host)
: state_(STATE_NONE),
defer_state_(DEFERRED_NONE),
deferred_request_id_(-1),
@@ -38,9 +36,6 @@ SafeBrowsingResourceHandler::SafeBrowsingResourceHandler(
safe_browsing_(safe_browsing),
rdh_(resource_dispatcher_host),
resource_type_(resource_type) {
- registrar_.Add(this, NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN,
- Source<ResourceMessageFilter>(
- static_cast<ResourceMessageFilter*>(receiver)));
}
SafeBrowsingResourceHandler::~SafeBrowsingResourceHandler() {
@@ -90,7 +85,7 @@ void SafeBrowsingResourceHandler::OnCheckUrlTimeout() {
CHECK(state_ == STATE_CHECKING_URL);
CHECK(defer_state_ != DEFERRED_NONE);
safe_browsing_->CancelCheck(this);
- OnUrlCheckResult(deferred_url_, SafeBrowsingService::URL_SAFE);
+ OnBrowseUrlCheckResult(deferred_url_, SafeBrowsingService::URL_SAFE);
}
bool SafeBrowsingResourceHandler::OnWillStart(int request_id,
@@ -139,7 +134,7 @@ void SafeBrowsingResourceHandler::OnRequestClosed() {
// SafeBrowsingService::Client implementation, called on the IO thread once
// the URL has been classified.
-void SafeBrowsingResourceHandler::OnUrlCheckResult(
+void SafeBrowsingResourceHandler::OnBrowseUrlCheckResult(
const GURL& url, SafeBrowsingService::UrlCheckResult result) {
CHECK(state_ == STATE_CHECKING_URL);
CHECK(defer_state_ != DEFERRED_NONE);
@@ -177,7 +172,7 @@ void SafeBrowsingResourceHandler::StartDisplayingBlockingPage(
// Grab the original url of this request as well.
GURL original_url;
- URLRequest* request = rdh_->GetURLRequest(
+ net::URLRequest* request = rdh_->GetURLRequest(
GlobalRequestID(render_process_host_id_, deferred_request_id_));
if (request)
original_url = request->original_url();
@@ -205,13 +200,6 @@ void SafeBrowsingResourceHandler::OnBlockingPageComplete(bool proceed) {
Release(); // Balances the AddRef() in StartDisplayingBlockingPage().
}
-void SafeBrowsingResourceHandler::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- DCHECK(type.value == NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN);
- Shutdown();
-}
-
void SafeBrowsingResourceHandler::Shutdown() {
if (state_ == STATE_CHECKING_URL) {
timer_.Stop();
@@ -225,7 +213,7 @@ void SafeBrowsingResourceHandler::Shutdown() {
bool SafeBrowsingResourceHandler::CheckUrl(const GURL& url) {
CHECK(state_ == STATE_NONE);
- bool succeeded_synchronously = safe_browsing_->CheckUrl(url, this);
+ bool succeeded_synchronously = safe_browsing_->CheckBrowseUrl(url, this);
if (succeeded_synchronously) {
safe_browsing_result_ = SafeBrowsingService::URL_SAFE;
safe_browsing_->LogPauseDelay(base::TimeDelta()); // No delay.
diff --git a/chrome/browser/renderer_host/safe_browsing_resource_handler.h b/chrome/browser/renderer_host/safe_browsing_resource_handler.h
index 14ddd4b..724297f 100644
--- a/chrome/browser/renderer_host/safe_browsing_resource_handler.h
+++ b/chrome/browser/renderer_host/safe_browsing_resource_handler.h
@@ -11,11 +11,10 @@
#include "base/ref_counted.h"
#include "base/time.h"
#include "base/timer.h"
-#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/renderer_host/resource_handler.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
+
+class ResourceDispatcherHost;
// SafeBrowsingResourceHandler checks that URLs are "safe" before navigating
// to them. To be considered "safe", a URL must not appear in the
@@ -40,44 +39,37 @@
// If on the other hand the URL was decided to be safe, the request is
// resumed.
class SafeBrowsingResourceHandler : public ResourceHandler,
- public SafeBrowsingService::Client,
- public NotificationObserver {
+ public SafeBrowsingService::Client {
public:
SafeBrowsingResourceHandler(ResourceHandler* handler,
int render_process_host_id,
int render_view_id,
ResourceType::Type resource_type,
SafeBrowsingService* safe_browsing,
- ResourceDispatcherHost* resource_dispatcher_host,
- ResourceDispatcherHost::Receiver* receiver);
+ ResourceDispatcherHost* resource_dispatcher_host);
// ResourceHandler implementation:
- bool OnUploadProgress(int request_id, uint64 position, uint64 size);
- bool OnRequestRedirected(int request_id, const GURL& new_url,
- ResourceResponse* response, bool* defer);
- bool OnResponseStarted(int request_id, ResourceResponse* response);
- bool OnWillStart(int request_id, const GURL& url, bool* defer);
- bool OnWillRead(int request_id, net::IOBuffer** buf, int* buf_size,
- int min_size);
- bool OnReadCompleted(int request_id, int* bytes_read);
- bool OnResponseCompleted(int request_id,
- const URLRequestStatus& status,
- const std::string& security_info);
+ virtual bool OnUploadProgress(int request_id, uint64 position, uint64 size);
+ virtual bool OnRequestRedirected(int request_id, const GURL& new_url,
+ ResourceResponse* response, bool* defer);
+ virtual bool OnResponseStarted(int request_id, ResourceResponse* response);
+ virtual bool OnWillStart(int request_id, const GURL& url, bool* defer);
+ virtual bool OnWillRead(int request_id, net::IOBuffer** buf, int* buf_size,
+ int min_size);
+ virtual bool OnReadCompleted(int request_id, int* bytes_read);
+ virtual bool OnResponseCompleted(int request_id,
+ const URLRequestStatus& status,
+ const std::string& security_info);
virtual void OnRequestClosed();
// SafeBrowsingService::Client implementation, called on the IO thread once
// the URL has been classified.
- void OnUrlCheckResult(const GURL& url,
- SafeBrowsingService::UrlCheckResult result);
+ virtual void OnBrowseUrlCheckResult(
+ const GURL& url, SafeBrowsingService::UrlCheckResult result);
// SafeBrowsingService::Client implementation, called on the IO thread when
// the user has decided to proceed with the current request, or go back.
- void OnBlockingPageComplete(bool proceed);
-
- // NotificationObserver interface.
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
+ virtual void OnBlockingPageComplete(bool proceed);
private:
// Describes what phase of the check a handler is in.
@@ -145,7 +137,6 @@ class SafeBrowsingResourceHandler : public ResourceHandler,
int deferred_request_id_;
scoped_refptr<ResourceResponse> deferred_redirect_response_;
- NotificationRegistrar registrar_;
scoped_refptr<ResourceHandler> next_handler_;
int render_process_host_id_;
int render_view_id_;
diff --git a/chrome/browser/renderer_host/site_instance.cc b/chrome/browser/renderer_host/site_instance.cc
index c6a660d..31f20f5 100644
--- a/chrome/browser/renderer_host/site_instance.cc
+++ b/chrome/browser/renderer_host/site_instance.cc
@@ -6,7 +6,7 @@
#include "chrome/browser/browsing_instance.h"
#include "chrome/browser/dom_ui/dom_ui_factory.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/renderer_host/browser_render_process_host.h"
#include "chrome/common/url_constants.h"
#include "chrome/common/notification_service.h"
@@ -187,11 +187,11 @@ bool SiteInstance::IsSameWebSite(Profile* profile,
/*static*/
GURL SiteInstance::GetEffectiveURL(Profile* profile, const GURL& url) {
- if (!profile || !profile->GetExtensionsService())
+ if (!profile || !profile->GetExtensionService())
return url;
const Extension* extension =
- profile->GetExtensionsService()->GetExtensionByWebExtent(url);
+ profile->GetExtensionService()->GetExtensionByWebExtent(url);
if (extension) {
// If the URL is part of an extension's web extent, convert it to an
// extension URL.
diff --git a/chrome/browser/renderer_host/site_instance.h b/chrome/browser/renderer_host/site_instance.h
index df7f69c..edb377f 100644
--- a/chrome/browser/renderer_host/site_instance.h
+++ b/chrome/browser/renderer_host/site_instance.h
@@ -161,9 +161,9 @@ class SiteInstance : public base::RefCounted<SiteInstance>,
private:
// NotificationObserver implementation.
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
NotificationRegistrar registrar_;
diff --git a/chrome/browser/renderer_host/socket_stream_dispatcher_host.cc b/chrome/browser/renderer_host/socket_stream_dispatcher_host.cc
index 6fa3fb8..fc642e8 100644
--- a/chrome/browser/renderer_host/socket_stream_dispatcher_host.cc
+++ b/chrome/browser/renderer_host/socket_stream_dispatcher_host.cc
@@ -5,129 +5,98 @@
#include "chrome/browser/renderer_host/socket_stream_dispatcher_host.h"
#include "base/logging.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/socket_stream_host.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/net/socket_stream.h"
-#include "ipc/ipc_message.h"
+#include "chrome/common/net/url_request_context_getter.h"
#include "net/websockets/websocket_job.h"
#include "net/websockets/websocket_throttle.h"
-SocketStreamDispatcherHost::SocketStreamDispatcherHost() : receiver_(NULL) {
+SocketStreamDispatcherHost::SocketStreamDispatcherHost() {
net::WebSocketJob::EnsureInit();
}
SocketStreamDispatcherHost::~SocketStreamDispatcherHost() {
// TODO(ukai): Implement IDMap::RemoveAll().
- for (IDMap< IDMap<SocketStreamHost> >::const_iterator iter(&hostmap_);
+ for (IDMap<SocketStreamHost>::const_iterator iter(&hosts_);
!iter.IsAtEnd();
iter.Advance()) {
- int host_id = iter.GetCurrentKey();
- CancelRequestsForProcess(host_id);
+ int socket_id = iter.GetCurrentKey();
+ const SocketStreamHost* socket_stream_host = iter.GetCurrentValue();
+ delete socket_stream_host;
+ hosts_.Remove(socket_id);
}
}
-bool SocketStreamDispatcherHost::OnMessageReceived(
- const IPC::Message& msg,
- ResourceDispatcherHost::Receiver* receiver,
- bool* msg_ok) {
- if (!IsSocketStreamDispatcherHostMessage(msg))
- return false;
-
- *msg_ok = true;
+bool SocketStreamDispatcherHost::OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok) {
bool handled = true;
- receiver_ = receiver;
- IPC_BEGIN_MESSAGE_MAP_EX(SocketStreamDispatcherHost, msg, *msg_ok)
+ IPC_BEGIN_MESSAGE_MAP_EX(SocketStreamDispatcherHost, message, *message_was_ok)
IPC_MESSAGE_HANDLER(ViewHostMsg_SocketStream_Connect, OnConnect)
IPC_MESSAGE_HANDLER(ViewHostMsg_SocketStream_SendData, OnSendData)
IPC_MESSAGE_HANDLER(ViewHostMsg_SocketStream_Close, OnCloseReq)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP_EX()
- receiver_ = NULL;
return handled;
}
-void SocketStreamDispatcherHost::CancelRequestsForProcess(int host_id) {
- IDMap<SocketStreamHost>* hosts = hostmap_.Lookup(host_id);
- if (hosts == NULL)
- return;
- for (IDMap<SocketStreamHost>::const_iterator hosts_iter(hosts);
- !hosts_iter.IsAtEnd();
- hosts_iter.Advance()) {
- const SocketStreamHost* socket_stream_host = hosts_iter.GetCurrentValue();
- delete socket_stream_host;
- int socket_id = hosts_iter.GetCurrentKey();
- hosts->Remove(socket_id);
- }
- hostmap_.Remove(host_id);
- delete hosts;
-}
-
// SocketStream::Delegate methods implementations.
void SocketStreamDispatcherHost::OnConnected(net::SocketStream* socket,
int max_pending_send_allowed) {
- SocketStreamHost* socket_stream_host =
- SocketStreamHost::GetSocketStreamHost(socket);
- DCHECK(socket_stream_host);
- int socket_id = socket_stream_host->socket_id();
+ int socket_id = SocketStreamHost::SocketIdFromSocketStream(socket);
DVLOG(1) << "SocketStreamDispatcherHost::OnConnected socket_id=" << socket_id
<< " max_pending_send_allowed=" << max_pending_send_allowed;
if (socket_id == chrome_common_net::kNoSocketId) {
LOG(ERROR) << "NoSocketId in OnConnected";
return;
}
- if (!socket_stream_host->Connected(max_pending_send_allowed)) {
+ if (!Send(new ViewMsg_SocketStream_Connected(
+ socket_id, max_pending_send_allowed))) {
LOG(ERROR) << "ViewMsg_SocketStream_Connected failed.";
- DeleteSocketStreamHost(socket_stream_host->receiver()->id(), socket_id);
+ DeleteSocketStreamHost(socket_id);
}
}
void SocketStreamDispatcherHost::OnSentData(net::SocketStream* socket,
int amount_sent) {
- SocketStreamHost* socket_stream_host =
- SocketStreamHost::GetSocketStreamHost(socket);
- DCHECK(socket_stream_host);
- int socket_id = socket_stream_host->socket_id();
+ int socket_id = SocketStreamHost::SocketIdFromSocketStream(socket);
DVLOG(1) << "SocketStreamDispatcherHost::OnSentData socket_id=" << socket_id
<< " amount_sent=" << amount_sent;
if (socket_id == chrome_common_net::kNoSocketId) {
LOG(ERROR) << "NoSocketId in OnReceivedData";
return;
}
- if (!socket_stream_host->SentData(amount_sent)) {
+ if (!Send(new ViewMsg_SocketStream_SentData(socket_id, amount_sent))) {
LOG(ERROR) << "ViewMsg_SocketStream_SentData failed.";
- DeleteSocketStreamHost(socket_stream_host->receiver()->id(), socket_id);
+ DeleteSocketStreamHost(socket_id);
}
}
void SocketStreamDispatcherHost::OnReceivedData(
net::SocketStream* socket, const char* data, int len) {
- SocketStreamHost* socket_stream_host =
- SocketStreamHost::GetSocketStreamHost(socket);
- DCHECK(socket_stream_host);
- int socket_id = socket_stream_host->socket_id();
+ int socket_id = SocketStreamHost::SocketIdFromSocketStream(socket);
DVLOG(1) << "SocketStreamDispatcherHost::OnReceiveData socket_id="
<< socket_id;
if (socket_id == chrome_common_net::kNoSocketId) {
LOG(ERROR) << "NoSocketId in OnReceivedData";
return;
}
- if (!socket_stream_host->ReceivedData(data, len)) {
+ if (!Send(new ViewMsg_SocketStream_ReceivedData(
+ socket_id, std::vector<char>(data, data + len)))) {
LOG(ERROR) << "ViewMsg_SocketStream_ReceivedData failed.";
- DeleteSocketStreamHost(socket_stream_host->receiver()->id(), socket_id);
+ DeleteSocketStreamHost(socket_id);
}
}
void SocketStreamDispatcherHost::OnClose(net::SocketStream* socket) {
- SocketStreamHost* socket_stream_host =
- SocketStreamHost::GetSocketStreamHost(socket);
- DCHECK(socket_stream_host);
- int socket_id = socket_stream_host->socket_id();
+ int socket_id = SocketStreamHost::SocketIdFromSocketStream(socket);
DVLOG(1) << "SocketStreamDispatcherHost::OnClosed socket_id=" << socket_id;
if (socket_id == chrome_common_net::kNoSocketId) {
LOG(ERROR) << "NoSocketId in OnClose";
return;
}
- DeleteSocketStreamHost(socket_stream_host->receiver()->id(), socket_id);
+ DeleteSocketStreamHost(socket_id);
}
// Message handlers called by OnMessageReceived.
@@ -135,28 +104,22 @@ void SocketStreamDispatcherHost::OnConnect(const GURL& url, int socket_id) {
DVLOG(1) << "SocketStreamDispatcherHost::OnConnect url=" << url
<< " socket_id=" << socket_id;
DCHECK_NE(chrome_common_net::kNoSocketId, socket_id);
- DCHECK(receiver_);
- if (LookupHostMap(receiver_->id(), socket_id)) {
- LOG(ERROR) << "host_id=" << receiver_->id()
- << " socket_id=" << socket_id << " already registered.";
+ if (hosts_.Lookup(socket_id)) {
+ LOG(ERROR) << "socket_id=" << socket_id << " already registered.";
return;
}
- SocketStreamHost* socket_stream_host =
- new SocketStreamHost(this, receiver_, socket_id);
- AddHostMap(receiver_->id(), socket_id, socket_stream_host);
- socket_stream_host->Connect(url);
+ SocketStreamHost* socket_stream_host = new SocketStreamHost(this, socket_id);
+ hosts_.AddWithID(socket_stream_host, socket_id);
+ socket_stream_host->Connect(url, GetURLRequestContext());
DVLOG(1) << "SocketStreamDispatcherHost::OnConnect -> " << socket_id;
}
void SocketStreamDispatcherHost::OnSendData(
int socket_id, const std::vector<char>& data) {
DVLOG(1) << "SocketStreamDispatcherHost::OnSendData socket_id=" << socket_id;
- DCHECK(receiver_);
- SocketStreamHost* socket_stream_host =
- LookupHostMap(receiver_->id(), socket_id);
+ SocketStreamHost* socket_stream_host = hosts_.Lookup(socket_id);
if (!socket_stream_host) {
- LOG(ERROR) << "host_id=" << receiver_->id()
- << " socket_id=" << socket_id << " already closed.";
+ LOG(ERROR) << "socket_id=" << socket_id << " already closed.";
return;
}
if (!socket_stream_host->SendData(data)) {
@@ -167,57 +130,34 @@ void SocketStreamDispatcherHost::OnSendData(
void SocketStreamDispatcherHost::OnCloseReq(int socket_id) {
DVLOG(1) << "SocketStreamDispatcherHost::OnCloseReq socket_id=" << socket_id;
- DCHECK(receiver_);
- SocketStreamHost* socket_stream_host =
- LookupHostMap(receiver_->id(), socket_id);
+ SocketStreamHost* socket_stream_host = hosts_.Lookup(socket_id);
if (!socket_stream_host)
return;
socket_stream_host->Close();
}
-void SocketStreamDispatcherHost::DeleteSocketStreamHost(
- int host_id, int socket_id) {
- SocketStreamHost* socket_stream_host = LookupHostMap(host_id, socket_id);
+void SocketStreamDispatcherHost::DeleteSocketStreamHost(int socket_id) {
+ SocketStreamHost* socket_stream_host = hosts_.Lookup(socket_id);
DCHECK(socket_stream_host);
delete socket_stream_host;
- IDMap<SocketStreamHost>* hosts = hostmap_.Lookup(host_id);
- DCHECK(hosts);
- hosts->Remove(socket_id);
- if (hosts->IsEmpty()) {
- hostmap_.Remove(host_id);
- delete hosts;
+ hosts_.Remove(socket_id);
+ if (!Send(new ViewMsg_SocketStream_Closed(socket_id))) {
+ LOG(ERROR) << "ViewMsg_SocketStream_Closed failed.";
}
}
-void SocketStreamDispatcherHost::AddHostMap(
- int host_id, int socket_id, SocketStreamHost* socket_stream_host) {
- IDMap<SocketStreamHost>* hosts = hostmap_.Lookup(host_id);
- if (!hosts) {
- hosts = new IDMap<SocketStreamHost>;
- hostmap_.AddWithID(hosts, host_id);
+URLRequestContext* SocketStreamDispatcherHost::GetURLRequestContext() {
+ URLRequestContext* rv = NULL;
+ if (url_request_context_override_.get()) {
+ rv = url_request_context_override_->GetRequestContext(
+ 0, ResourceType::SUB_RESOURCE);
}
- hosts->AddWithID(socket_stream_host, socket_id);
-}
-
-SocketStreamHost* SocketStreamDispatcherHost::LookupHostMap(
- int host_id, int socket_id) {
- IDMap<SocketStreamHost>* hosts = hostmap_.Lookup(host_id);
- if (!hosts)
- return NULL;
- return hosts->Lookup(socket_id);
-}
-
-/* static */
-bool SocketStreamDispatcherHost::IsSocketStreamDispatcherHostMessage(
- const IPC::Message& message) {
- switch (message.type()) {
- case ViewHostMsg_SocketStream_Connect::ID:
- case ViewHostMsg_SocketStream_SendData::ID:
- case ViewHostMsg_SocketStream_Close::ID:
- return true;
-
- default:
- break;
+ if (!rv) {
+ URLRequestContextGetter* context_getter =
+ Profile::GetDefaultRequestContext();
+ if (context_getter)
+ rv = context_getter->GetURLRequestContext();
}
- return false;
+
+ return rv;
}
diff --git a/chrome/browser/renderer_host/socket_stream_dispatcher_host.h b/chrome/browser/renderer_host/socket_stream_dispatcher_host.h
index ed4c461..b57d7ce 100644
--- a/chrome/browser/renderer_host/socket_stream_dispatcher_host.h
+++ b/chrome/browser/renderer_host/socket_stream_dispatcher_host.h
@@ -9,8 +9,8 @@
#include <vector>
#include "base/id_map.h"
-#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
-#include "ipc/ipc_message.h"
+#include "chrome/browser/browser_message_filter.h"
+#include "chrome/browser/renderer_host/resource_message_filter.h"
#include "net/socket_stream/socket_stream.h"
class GURL;
@@ -19,14 +19,16 @@ class SocketStreamHost;
// Dispatches ViewHostMsg_SocketStream_* messages sent from renderer.
// It also acts as SocketStream::Delegate so that it sends
// ViewMsg_SocketStream_* messages back to renderer.
-class SocketStreamDispatcherHost : public net::SocketStream::Delegate {
+class SocketStreamDispatcherHost : public BrowserMessageFilter,
+ public net::SocketStream::Delegate {
public:
SocketStreamDispatcherHost();
virtual ~SocketStreamDispatcherHost();
- bool OnMessageReceived(const IPC::Message& msg,
- ResourceDispatcherHost::Receiver* receiver,
- bool* msg_ok);
+ // BrowserMessageFilter methods.
+ virtual bool OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok);
+
// The object died, so cancel and detach all requests associated with it.
void CancelRequestsForProcess(int host_id);
@@ -38,26 +40,25 @@ class SocketStreamDispatcherHost : public net::SocketStream::Delegate {
const char* data, int len);
virtual void OnClose(net::SocketStream* socket);
+ void set_url_request_context_override(
+ ResourceMessageFilter::URLRequestContextOverride* u) {
+ url_request_context_override_ = u;
+ }
+
private:
// Message handlers called by OnMessageReceived.
void OnConnect(const GURL& url, int socket_id);
void OnSendData(int socket_id, const std::vector<char>& data);
void OnCloseReq(int socket_id);
- void DeleteSocketStreamHost(int host_id, int socket_id);
-
- void AddHostMap(int host_id, int socket_id,
- SocketStreamHost* socket_stream_host);
- SocketStreamHost* LookupHostMap(int host_id, int socket_id);
-
- // Returns true if the message passed in is a SocketStream related message.
- static bool IsSocketStreamDispatcherHostMessage(const IPC::Message& message);
+ void DeleteSocketStreamHost(int socket_id);
- // key: host_id -> { key: socket_id -> value: SocketStreamHost }
- IDMap< IDMap<SocketStreamHost> > hostmap_;
+ // Returns the URLRequestContext.
+ URLRequestContext* GetURLRequestContext();
- // valid while OnMessageReceived processing.
- ResourceDispatcherHost::Receiver* receiver_;
+ IDMap<SocketStreamHost> hosts_;
+ scoped_refptr<ResourceMessageFilter::URLRequestContextOverride>
+ url_request_context_override_;
DISALLOW_COPY_AND_ASSIGN(SocketStreamDispatcherHost);
};
diff --git a/chrome/browser/renderer_host/socket_stream_host.cc b/chrome/browser/renderer_host/socket_stream_host.cc
index a6f8ddd..6c66f79 100644
--- a/chrome/browser/renderer_host/socket_stream_host.cc
+++ b/chrome/browser/renderer_host/socket_stream_host.cc
@@ -5,60 +5,51 @@
#include "chrome/browser/renderer_host/socket_stream_host.h"
#include "base/logging.h"
-#include "chrome/browser/profile.h"
#include "chrome/common/net/socket_stream.h"
-#include "chrome/common/net/url_request_context_getter.h"
-#include "chrome/common/render_messages.h"
#include "net/socket_stream/socket_stream_job.h"
-static const char* kSocketHostKey = "socketHost";
+static const char* kSocketIdKey = "socketId";
-class SocketStreamInfo : public net::SocketStream::UserData {
+class SocketStreamId : public net::SocketStream::UserData {
public:
- explicit SocketStreamInfo(SocketStreamHost* host) : host_(host) {}
- virtual ~SocketStreamInfo() {}
- SocketStreamHost* host() const { return host_; }
+ explicit SocketStreamId(int socket_id) : socket_id_(socket_id) {}
+ virtual ~SocketStreamId() {}
+ int socket_id() const { return socket_id_; }
private:
- SocketStreamHost* host_;
+ int socket_id_;
};
SocketStreamHost::SocketStreamHost(
net::SocketStream::Delegate* delegate,
- ResourceDispatcherHost::Receiver* receiver,
int socket_id)
: delegate_(delegate),
- receiver_(receiver),
socket_id_(socket_id) {
DCHECK_NE(socket_id_, chrome_common_net::kNoSocketId);
VLOG(1) << "SocketStreamHost: socket_id=" << socket_id_;
}
/* static */
-SocketStreamHost*
-SocketStreamHost::GetSocketStreamHost(net::SocketStream* socket) {
- net::SocketStream::UserData* d = socket->GetUserData(kSocketHostKey);
+int SocketStreamHost::SocketIdFromSocketStream(net::SocketStream* socket) {
+ net::SocketStream::UserData* d = socket->GetUserData(kSocketIdKey);
if (d) {
- SocketStreamInfo* info = static_cast<SocketStreamInfo*>(d);
- return info->host();
+ SocketStreamId* socket_stream_id = static_cast<SocketStreamId*>(d);
+ return socket_stream_id->socket_id();
}
- return NULL;
+ return chrome_common_net::kNoSocketId;
}
SocketStreamHost::~SocketStreamHost() {
VLOG(1) << "SocketStreamHost destructed socket_id=" << socket_id_;
- if (!receiver_->Send(new ViewMsg_SocketStream_Closed(socket_id_)))
- LOG(ERROR) << "ViewMsg_SocketStream_Closed failed.";
socket_->DetachDelegate();
}
-void SocketStreamHost::Connect(const GURL& url) {
+void SocketStreamHost::Connect(const GURL& url,
+ URLRequestContext* request_context) {
VLOG(1) << "SocketStreamHost::Connect url=" << url;
socket_ = net::SocketStreamJob::CreateSocketStreamJob(url, delegate_);
- URLRequestContextGetter* context_getter = Profile::GetDefaultRequestContext();
- if (context_getter)
- socket_->set_context(context_getter->GetURLRequestContext());
- socket_->SetUserData(kSocketHostKey, new SocketStreamInfo(this));
+ socket_->set_context(request_context);
+ socket_->SetUserData(kSocketIdKey, new SocketStreamId(socket_id_));
socket_->Connect();
}
@@ -73,18 +64,3 @@ void SocketStreamHost::Close() {
return;
socket_->Close();
}
-
-bool SocketStreamHost::Connected(int max_pending_send_allowed) {
- return receiver_->Send(new ViewMsg_SocketStream_Connected(
- socket_id_, max_pending_send_allowed));
-}
-
-bool SocketStreamHost::SentData(int amount_sent) {
- return receiver_->Send(new ViewMsg_SocketStream_SentData(
- socket_id_, amount_sent));
-}
-
-bool SocketStreamHost::ReceivedData(const char* data, int len) {
- return receiver_->Send(new ViewMsg_SocketStream_ReceivedData(
- socket_id_, std::vector<char>(data, data + len)));
-}
diff --git a/chrome/browser/renderer_host/socket_stream_host.h b/chrome/browser/renderer_host/socket_stream_host.h
index 48a8e1b..06b3e9f 100644
--- a/chrome/browser/renderer_host/socket_stream_host.h
+++ b/chrome/browser/renderer_host/socket_stream_host.h
@@ -9,10 +9,10 @@
#include <vector>
#include "base/ref_counted.h"
-#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "net/socket_stream/socket_stream.h"
class GURL;
+class URLRequestContext;
namespace net {
class SocketStreamJob;
@@ -28,19 +28,16 @@ class SocketStreamJob;
// SocketStreamDispatcherHost.
class SocketStreamHost {
public:
- SocketStreamHost(net::SocketStream::Delegate* delegate,
- ResourceDispatcherHost::Receiver* receiver,
- int socket_id);
+ SocketStreamHost(net::SocketStream::Delegate* delegate, int socket_id);
~SocketStreamHost();
- // Gets SocketStreamHost associated with |socket|.
- static SocketStreamHost* GetSocketStreamHost(net::SocketStream* socket);
+ // Gets socket_id associated with |socket|.
+ static int SocketIdFromSocketStream(net::SocketStream* socket);
- ResourceDispatcherHost::Receiver* receiver() const { return receiver_; }
int socket_id() const { return socket_id_; }
// Starts to open connection to |url|.
- void Connect(const GURL& url);
+ void Connect(const GURL& url, URLRequestContext* request_context);
// Sends |data| over the socket stream.
// socket stream must be open to send data.
@@ -52,15 +49,8 @@ class SocketStreamHost {
// Closes the socket stream.
void Close();
- bool Connected(int max_pending_send_allowed);
-
- bool SentData(int amount_sent);
-
- bool ReceivedData(const char* data, int len);
-
private:
net::SocketStream::Delegate* delegate_;
- ResourceDispatcherHost::Receiver* receiver_;
int socket_id_;
scoped_refptr<net::SocketStreamJob> socket_;
diff --git a/chrome/browser/renderer_host/sync_resource_handler.cc b/chrome/browser/renderer_host/sync_resource_handler.cc
index db5ec9a..aa42c72 100644
--- a/chrome/browser/renderer_host/sync_resource_handler.cc
+++ b/chrome/browser/renderer_host/sync_resource_handler.cc
@@ -8,19 +8,19 @@
#include "chrome/browser/debugger/devtools_netlog_observer.h"
#include "chrome/browser/net/load_timing_observer.h"
#include "chrome/browser/renderer_host/global_request_id.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+#include "chrome/browser/renderer_host/resource_message_filter.h"
#include "chrome/common/render_messages.h"
#include "net/base/io_buffer.h"
#include "net/http/http_response_headers.h"
SyncResourceHandler::SyncResourceHandler(
- ResourceDispatcherHost::Receiver* receiver,
- int process_id,
+ ResourceMessageFilter* filter,
const GURL& url,
IPC::Message* result_message,
ResourceDispatcherHost* resource_dispatcher_host)
: read_buffer_(new net::IOBuffer(kReadBufSize)),
- receiver_(receiver),
- process_id_(process_id),
+ filter_(filter),
result_message_(result_message),
rdh_(resource_dispatcher_host) {
result_.final_url = url;
@@ -39,8 +39,8 @@ bool SyncResourceHandler::OnRequestRedirected(int request_id,
const GURL& new_url,
ResourceResponse* response,
bool* defer) {
- URLRequest* request = rdh_->GetURLRequest(
- GlobalRequestID(process_id_, request_id));
+ net::URLRequest* request = rdh_->GetURLRequest(
+ GlobalRequestID(filter_->child_id(), request_id));
LoadTimingObserver::PopulateTimingInfo(request, response);
DevToolsNetLogObserver::PopulateResponseInfo(request, response);
// TODO(darin): It would be much better if this could live in WebCore, but
@@ -56,8 +56,8 @@ bool SyncResourceHandler::OnRequestRedirected(int request_id,
bool SyncResourceHandler::OnResponseStarted(int request_id,
ResourceResponse* response) {
- URLRequest* request = rdh_->GetURLRequest(
- GlobalRequestID(process_id_, request_id));
+ net::URLRequest* request = rdh_->GetURLRequest(
+ GlobalRequestID(filter_->child_id(), request_id));
LoadTimingObserver::PopulateTimingInfo(request, response);
DevToolsNetLogObserver::PopulateResponseInfo(request, response);
@@ -103,7 +103,7 @@ bool SyncResourceHandler::OnResponseCompleted(
result_.status = status;
ViewHostMsg_SyncLoad::WriteReplyParams(result_message_, result_);
- receiver_->Send(result_message_);
+ filter_->Send(result_message_);
result_message_ = NULL;
return true;
}
@@ -113,6 +113,5 @@ void SyncResourceHandler::OnRequestClosed() {
return;
result_message_->set_reply_error();
- receiver_->Send(result_message_);
- receiver_ = NULL; // URLRequest is gone, and perhaps also the receiver.
+ filter_->Send(result_message_);
}
diff --git a/chrome/browser/renderer_host/sync_resource_handler.h b/chrome/browser/renderer_host/sync_resource_handler.h
index 6f86de7..174d1d8 100644
--- a/chrome/browser/renderer_host/sync_resource_handler.h
+++ b/chrome/browser/renderer_host/sync_resource_handler.h
@@ -8,10 +8,16 @@
#include <string>
-#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/renderer_host/resource_handler.h"
#include "chrome/common/resource_response.h"
+class ResourceDispatcherHost;
+class ResourceMessageFilter;
+
+namespace IPC {
+class Message;
+}
+
namespace net {
class IOBuffer;
}
@@ -20,24 +26,23 @@ class IOBuffer;
// events from the resource dispatcher host.
class SyncResourceHandler : public ResourceHandler {
public:
- SyncResourceHandler(ResourceDispatcherHost::Receiver* receiver,
- int process_id,
+ SyncResourceHandler(ResourceMessageFilter* filter,
const GURL& url,
IPC::Message* result_message,
ResourceDispatcherHost* resource_dispatcher_host);
- bool OnUploadProgress(int request_id, uint64 position, uint64 size);
- bool OnRequestRedirected(int request_id, const GURL& new_url,
- ResourceResponse* response, bool* defer);
- bool OnResponseStarted(int request_id, ResourceResponse* response);
- bool OnWillStart(int request_id, const GURL& url, bool* defer);
- bool OnWillRead(int request_id, net::IOBuffer** buf, int* buf_size,
- int min_size);
- bool OnReadCompleted(int request_id, int* bytes_read);
- bool OnResponseCompleted(int request_id,
- const URLRequestStatus& status,
- const std::string& security_info);
- void OnRequestClosed();
+ virtual bool OnUploadProgress(int request_id, uint64 position, uint64 size);
+ virtual bool OnRequestRedirected(int request_id, const GURL& new_url,
+ ResourceResponse* response, bool* defer);
+ virtual bool OnResponseStarted(int request_id, ResourceResponse* response);
+ virtual bool OnWillStart(int request_id, const GURL& url, bool* defer);
+ virtual bool OnWillRead(int request_id, net::IOBuffer** buf, int* buf_size,
+ int min_size);
+ virtual bool OnReadCompleted(int request_id, int* bytes_read);
+ virtual bool OnResponseCompleted(int request_id,
+ const URLRequestStatus& status,
+ const std::string& security_info);
+ virtual void OnRequestClosed();
private:
enum { kReadBufSize = 3840 };
@@ -47,8 +52,7 @@ class SyncResourceHandler : public ResourceHandler {
scoped_refptr<net::IOBuffer> read_buffer_;
SyncLoadResult result_;
- ResourceDispatcherHost::Receiver* receiver_;
- int process_id_;
+ ResourceMessageFilter* filter_;
IPC::Message* result_message_;
ResourceDispatcherHost* rdh_;
};
diff --git a/chrome/browser/renderer_host/test/render_process_host_browsertest.cc b/chrome/browser/renderer_host/test/render_process_host_browsertest.cc
index f1b8bec..38e5361 100644
--- a/chrome/browser/renderer_host/test/render_process_host_browsertest.cc
+++ b/chrome/browser/renderer_host/test/render_process_host_browsertest.cc
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/renderer_host/render_process_host.h"
diff --git a/chrome/browser/renderer_host/test/render_view_host_browsertest.cc b/chrome/browser/renderer_host/test/render_view_host_browsertest.cc
index c93a3a5..67c0dfb 100644
--- a/chrome/browser/renderer_host/test/render_view_host_browsertest.cc
+++ b/chrome/browser/renderer_host/test/render_view_host_browsertest.cc
@@ -3,16 +3,18 @@
// found in the LICENSE file.
#include "base/utf_string_conversions.h"
+#include "base/time.h"
#include "base/values.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_specific_content_settings.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "net/test/test_server.h"
-typedef InProcessBrowserTest RenderViewHostTest;
-
typedef std::pair<int, Value*> ExecuteDetailType;
namespace {
@@ -46,48 +48,178 @@ class ExecuteNotificationObserver : public NotificationObserver {
} // namespace
+class RenderViewHostTest : public InProcessBrowserTest {
+ public:
+ RenderViewHostTest() : last_execute_id_(0) {}
+
+ void ExecuteJavascriptAndGetValue(const char* script,
+ ExecuteNotificationObserver* out_result) {
+ RenderViewHost* rvh =
+ browser()->GetSelectedTabContents()->render_view_host();
+ ASSERT_TRUE(rvh);
+ int execute_id = rvh->ExecuteJavascriptInWebFrameNotifyResult(
+ string16(),
+ ASCIIToUTF16(script));
+ EXPECT_NE(execute_id, last_execute_id_);
+ ExecuteNotificationObserver observer;
+ ui_test_utils::RegisterAndWait(
+ out_result,
+ NotificationType::EXECUTE_JAVASCRIPT_RESULT,
+ Source<RenderViewHost>(rvh));
+ EXPECT_EQ(execute_id, out_result->id());
+ ASSERT_TRUE(out_result->value());
+ last_execute_id_ = execute_id;
+ }
+
+ private:
+ int last_execute_id_;
+};
+
+
// Makes sure ExecuteJavascriptInWebFrameNotifyResult works.
IN_PROC_BROWSER_TEST_F(RenderViewHostTest,
ExecuteJavascriptInWebFrameNotifyResult) {
ASSERT_TRUE(test_server()->Start());
GURL empty_url(test_server()->GetURL("files/empty.html"));
ui_test_utils::NavigateToURL(browser(), empty_url);
- RenderViewHost* rvh = browser()->GetSelectedTabContents()->render_view_host();
- ASSERT_TRUE(rvh);
// Execute the script 'true' and make sure we get back true.
- int execute_id = rvh->ExecuteJavascriptInWebFrameNotifyResult(
- string16(),
- ASCIIToUTF16("true;"));
{
ExecuteNotificationObserver observer;
- ui_test_utils::RegisterAndWait(
- &observer,
- NotificationType::EXECUTE_JAVASCRIPT_RESULT,
- Source<RenderViewHost>(rvh));
- EXPECT_EQ(execute_id, observer.id());
- ASSERT_TRUE(observer.value());
+ ExecuteJavascriptAndGetValue("true;", &observer);
+ EXPECT_EQ(Value::TYPE_BOOLEAN, observer.value()->GetType());
bool bool_value;
- ASSERT_TRUE(observer.value()->GetAsBoolean(&bool_value));
+ EXPECT_TRUE(observer.value()->GetAsBoolean(&bool_value));
EXPECT_TRUE(bool_value);
}
// Execute the script 'false' and make sure we get back false.
- int execute_id2 = rvh->ExecuteJavascriptInWebFrameNotifyResult(
- string16(),
- ASCIIToUTF16("false;"));
- // The ids should change.
- EXPECT_NE(execute_id, execute_id2);
{
ExecuteNotificationObserver observer;
- ui_test_utils::RegisterAndWait(
- &observer,
- NotificationType::EXECUTE_JAVASCRIPT_RESULT,
- Source<RenderViewHost>(rvh));
- EXPECT_EQ(execute_id2, observer.id());
- ASSERT_TRUE(observer.value());
+ ExecuteJavascriptAndGetValue("false;", &observer);
+ EXPECT_EQ(Value::TYPE_BOOLEAN, observer.value()->GetType());
bool bool_value;
- ASSERT_TRUE(observer.value()->GetAsBoolean(&bool_value));
+ EXPECT_TRUE(observer.value()->GetAsBoolean(&bool_value));
EXPECT_FALSE(bool_value);
}
+
+ // And now, for something completely different, try a number.
+ {
+ ExecuteNotificationObserver observer;
+ ExecuteJavascriptAndGetValue("42;", &observer);
+ EXPECT_EQ(Value::TYPE_INTEGER, observer.value()->GetType());
+ int int_value;
+ EXPECT_TRUE(observer.value()->GetAsInteger(&int_value));
+ EXPECT_EQ(42, int_value);
+ }
+
+ // Try a floating point number.
+ {
+ ExecuteNotificationObserver observer;
+ ExecuteJavascriptAndGetValue("42.2;", &observer);
+ EXPECT_EQ(Value::TYPE_REAL, observer.value()->GetType());
+ double double_value;
+ EXPECT_TRUE(observer.value()->GetAsReal(&double_value));
+ EXPECT_EQ(42.2, double_value);
+ }
+
+ // Let's check out string.
+ {
+ ExecuteNotificationObserver observer;
+ ExecuteJavascriptAndGetValue("\"something completely different\";",
+ &observer);
+ EXPECT_EQ(Value::TYPE_STRING, observer.value()->GetType());
+ std::string string_value;
+ EXPECT_TRUE(observer.value()->GetAsString(&string_value));
+ EXPECT_EQ(std::string("something completely different"), string_value);
+ }
+
+ // Regular expressions might be fun.
+ {
+ ExecuteNotificationObserver observer;
+ ExecuteJavascriptAndGetValue("/finder.*foo/g;", &observer);
+ EXPECT_EQ(Value::TYPE_STRING, observer.value()->GetType());
+ std::string string_value;
+ EXPECT_TRUE(observer.value()->GetAsString(&string_value));
+ EXPECT_EQ(std::string("/finder.*foo/g"), string_value);
+ }
+
+ // Let's test some date conversions. First up, epoch. Can't use 0 because
+ // that means uninitialized, so use the next best thing.
+ {
+ ExecuteNotificationObserver observer;
+ ExecuteJavascriptAndGetValue("new Date(1);", &observer);
+ EXPECT_EQ(Value::TYPE_REAL, observer.value()->GetType());
+ double date_seconds;
+ EXPECT_TRUE(observer.value()->GetAsReal(&date_seconds));
+
+ base::Time time = base::Time::FromDoubleT(date_seconds);
+
+ base::Time::Exploded time_exploded;
+ time.UTCExplode(&time_exploded);
+ EXPECT_EQ(1970, time_exploded.year);
+ EXPECT_EQ(1, time_exploded.month);
+ EXPECT_EQ(1, time_exploded.day_of_month);
+ EXPECT_EQ(0, time_exploded.hour);
+ EXPECT_EQ(0, time_exploded.minute);
+ EXPECT_EQ(0, time_exploded.second);
+ }
+
+ // Test date with a real date input.
+ {
+ ExecuteNotificationObserver observer;
+ ExecuteJavascriptAndGetValue("new Date(Date.UTC(2006, 7, 16, 12, 0, 15));",
+ &observer);
+ EXPECT_EQ(Value::TYPE_REAL, observer.value()->GetType());
+ double date_seconds;
+ EXPECT_TRUE(observer.value()->GetAsReal(&date_seconds));
+
+ base::Time time = base::Time::FromDoubleT(date_seconds);
+
+ base::Time::Exploded time_exploded;
+ time.UTCExplode(&time_exploded);
+ EXPECT_EQ(2006, time_exploded.year);
+ // Subtle; 0 based in JS, 1 based in base::Time:
+ EXPECT_EQ(8, time_exploded.month);
+ EXPECT_EQ(16, time_exploded.day_of_month);
+ EXPECT_EQ(12, time_exploded.hour);
+ EXPECT_EQ(0, time_exploded.minute);
+ EXPECT_EQ(15, time_exploded.second);
+ }
+
+ // And something more complicated - get an array back as a list.
+ {
+ ExecuteNotificationObserver observer;
+ ExecuteJavascriptAndGetValue("new Array(\"one\", 2, false);", &observer);
+ EXPECT_EQ(Value::TYPE_LIST, observer.value()->GetType());
+ ListValue* list_value;
+ EXPECT_TRUE(observer.value()->GetAsList(&list_value));
+ EXPECT_EQ(3U, list_value->GetSize());
+ Value* value;
+ EXPECT_TRUE(list_value->Get(0, &value));
+ EXPECT_EQ(Value::TYPE_STRING, value->GetType());
+ EXPECT_TRUE(list_value->Get(1, &value));
+ EXPECT_EQ(Value::TYPE_INTEGER, value->GetType());
+ EXPECT_TRUE(list_value->Get(2, &value));
+ EXPECT_EQ(Value::TYPE_BOOLEAN, value->GetType());
+ }
+}
+
+// Regression test for http://crbug.com/63649.
+IN_PROC_BROWSER_TEST_F(RenderViewHostTest, RedirectLoopCookies) {
+ ASSERT_TRUE(test_server()->Start());
+
+ GURL test_url = test_server()->GetURL("files/redirect-loop.html");
+
+ browser()->profile()->GetHostContentSettingsMap()->SetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_BLOCK);
+
+ ui_test_utils::NavigateToURL(browser(), test_url);
+
+ TabContents* tab_contents = browser()->GetSelectedTabContents();
+ ASSERT_EQ(UTF8ToUTF16(test_url.spec() + " failed to load"),
+ tab_contents->GetTitle());
+
+ EXPECT_TRUE(tab_contents->GetTabSpecificContentSettings()->IsContentBlocked(
+ CONTENT_SETTINGS_TYPE_COOKIES));
}
diff --git a/chrome/browser/renderer_host/test/render_view_host_manager_browsertest.cc b/chrome/browser/renderer_host/test/render_view_host_manager_browsertest.cc
index bf347a6..ba02667 100644
--- a/chrome/browser/renderer_host/test/render_view_host_manager_browsertest.cc
+++ b/chrome/browser/renderer_host/test/render_view_host_manager_browsertest.cc
@@ -7,7 +7,7 @@
#include "base/ref_counted.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/extensions/extension_error_reporter.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
@@ -16,7 +16,6 @@
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
@@ -91,8 +90,9 @@ IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest,
// Test for crbug.com/24447. Following a cross-site link with just
// target=_blank should not create a new SiteInstance.
+// Disabled, http://crbug.com/67532.
IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest,
- DontSwapProcessWithOnlyTargetBlank) {
+ DISABLED_DontSwapProcessWithOnlyTargetBlank) {
// Start two servers with different sites.
ASSERT_TRUE(test_server()->Start());
net::TestServer https_server_(
diff --git a/chrome/browser/renderer_host/test/render_view_host_unittest.cc b/chrome/browser/renderer_host/test/render_view_host_unittest.cc
index 2ec5b95..da5a579 100644
--- a/chrome/browser/renderer_host/test/render_view_host_unittest.cc
+++ b/chrome/browser/renderer_host/test/render_view_host_unittest.cc
@@ -46,7 +46,7 @@ TEST_F(RenderViewHostTest, ResetUnloadOnReload) {
NavigateAndCommit(url1);
controller().LoadURL(url2, GURL(), 0);
- // Simulate the ClosePage call which is normally sent by the URLRequest.
+ // Simulate the ClosePage call which is normally sent by the net::URLRequest.
rvh()->ClosePage(true, 0, 0);
// Needed so that navigations are not suspended on the RVH. Normally handled
// by way of ViewHostMsg_ShouldClose_ACK.
diff --git a/chrome/browser/renderer_host/test/test_render_view_host.cc b/chrome/browser/renderer_host/test/test_render_view_host.cc
index a6ee798..1c2e4b4 100644
--- a/chrome/browser/renderer_host/test/test_render_view_host.cc
+++ b/chrome/browser/renderer_host/test/test_render_view_host.cc
@@ -45,6 +45,9 @@ TestRenderViewHost::TestRenderViewHost(SiteInstance* instance,
kInvalidSessionStorageNamespaceId),
render_view_created_(false),
delete_counter_(NULL) {
+ // For normal RenderViewHosts, this is freed when |Shutdown()| is called.
+ // For TestRenderViewHost, the view is explicitly deleted in the destructor
+ // below, because TestRenderWidgetHostView::Destroy() doesn't |delete this|.
set_view(new TestRenderWidgetHostView(this));
}
@@ -67,8 +70,8 @@ bool TestRenderViewHost::IsRenderViewLive() const {
return render_view_created_;
}
-void TestRenderViewHost::TestOnMessageReceived(const IPC::Message& msg) {
- OnMessageReceived(msg);
+bool TestRenderViewHost::TestOnMessageReceived(const IPC::Message& msg) {
+ return OnMessageReceived(msg);
}
void TestRenderViewHost::SendNavigate(int page_id, const GURL& url) {
@@ -105,6 +108,9 @@ TestRenderWidgetHostView::TestRenderWidgetHostView(RenderWidgetHost* rwh)
is_showing_(false) {
}
+TestRenderWidgetHostView::~TestRenderWidgetHostView() {
+}
+
gfx::Rect TestRenderWidgetHostView::GetViewBounds() const {
return gfx::Rect();
}
diff --git a/chrome/browser/renderer_host/test/test_render_view_host.h b/chrome/browser/renderer_host/test/test_render_view_host.h
index 789c2fe..70f2d11 100644
--- a/chrome/browser/renderer_host/test/test_render_view_host.h
+++ b/chrome/browser/renderer_host/test/test_render_view_host.h
@@ -49,6 +49,7 @@ void InitNavigateParams(ViewHostMsg_FrameNavigate_Params* params,
class TestRenderWidgetHostView : public RenderWidgetHostView {
public:
explicit TestRenderWidgetHostView(RenderWidgetHost* rwh);
+ virtual ~TestRenderWidgetHostView();
virtual void InitAsPopup(RenderWidgetHostView* parent_host_view,
const gfx::Rect& pos) {}
@@ -59,7 +60,7 @@ class TestRenderWidgetHostView : public RenderWidgetHostView {
virtual void SetSize(const gfx::Size& size) {}
virtual gfx::NativeView GetNativeView() { return NULL; }
virtual void MovePluginWindows(
- const std::vector<webkit_glue::WebPluginGeometry>& moves) {}
+ const std::vector<webkit::npapi::WebPluginGeometry>& moves) {}
#if defined(OS_WIN)
virtual void ForwardMouseEventToRenderer(UINT message,
WPARAM wparam,
@@ -82,7 +83,8 @@ class TestRenderWidgetHostView : public RenderWidgetHostView {
virtual void DidUpdateBackingStore(
const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy,
const std::vector<gfx::Rect>& rects) {}
- virtual void RenderViewGone() { delete this; }
+ virtual void RenderViewGone(base::TerminationStatus status,
+ int error_code) { delete this; }
virtual void WillDestroyRenderWidget(RenderWidgetHost* rwh) { }
virtual void Destroy() {}
virtual void PrepareToDestroy() {}
@@ -164,7 +166,7 @@ class TestRenderViewHost : public RenderViewHost {
// Calls the RenderViewHosts' private OnMessageReceived function with the
// given message.
- void TestOnMessageReceived(const IPC::Message& msg);
+ bool TestOnMessageReceived(const IPC::Message& msg);
// Calls OnMsgNavigate on the RenderViewHost with the given information,
// setting the rest of the parameters in the message to the "typical" values.
diff --git a/chrome/browser/renderer_host/test/web_cache_manager_browsertest.cc b/chrome/browser/renderer_host/test/web_cache_manager_browsertest.cc
index 06ce085..3681c70 100644
--- a/chrome/browser/renderer_host/test/web_cache_manager_browsertest.cc
+++ b/chrome/browser/renderer_host/test/web_cache_manager_browsertest.cc
@@ -10,6 +10,7 @@
#include "chrome/browser/renderer_host/web_cache_manager.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/common/result_codes.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -33,7 +34,7 @@ IN_PROC_BROWSER_TEST_F(WebCacheManagerBrowserTest, FLAKY_CrashOnceOnly) {
TabContents* tab = browser()->GetTabContentsAt(0);
ASSERT_TRUE(tab != NULL);
base::KillProcess(tab->GetRenderProcessHost()->GetHandle(),
- base::PROCESS_END_KILLED_BY_USER, true);
+ ResultCodes::KILLED, true);
browser()->SelectTabContentsAt(0, true);
browser()->NewTab();
diff --git a/chrome/browser/renderer_host/x509_user_cert_resource_handler.cc b/chrome/browser/renderer_host/x509_user_cert_resource_handler.cc
index 9e1cccc..68b62ca 100644
--- a/chrome/browser/renderer_host/x509_user_cert_resource_handler.cc
+++ b/chrome/browser/renderer_host/x509_user_cert_resource_handler.cc
@@ -5,8 +5,6 @@
#include "chrome/browser/renderer_host/x509_user_cert_resource_handler.h"
#include "base/string_util.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/download/download_types.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
@@ -22,7 +20,7 @@
#include "net/url_request/url_request_status.h"
X509UserCertResourceHandler::X509UserCertResourceHandler(
- ResourceDispatcherHost* host, URLRequest* request,
+ ResourceDispatcherHost* host, net::URLRequest* request,
int render_process_host_id, int render_view_id)
: host_(host),
request_(request),
diff --git a/chrome/browser/renderer_host/x509_user_cert_resource_handler.h b/chrome/browser/renderer_host/x509_user_cert_resource_handler.h
index 54b481d..8ae25f8 100644
--- a/chrome/browser/renderer_host/x509_user_cert_resource_handler.h
+++ b/chrome/browser/renderer_host/x509_user_cert_resource_handler.h
@@ -30,34 +30,34 @@ class X509UserCertResourceHandler : public ResourceHandler {
net::URLRequest* request,
int render_process_host_id, int render_view_id);
- bool OnUploadProgress(int request_id, uint64 position, uint64 size);
+ virtual bool OnUploadProgress(int request_id, uint64 position, uint64 size);
// Not needed, as this event handler ought to be the final resource.
- bool OnRequestRedirected(int request_id, const GURL& url,
- ResourceResponse* resp, bool* defer);
+ virtual bool OnRequestRedirected(int request_id, const GURL& url,
+ ResourceResponse* resp, bool* defer);
// Check if this indeed an X509 cert.
- bool OnResponseStarted(int request_id, ResourceResponse* resp);
+ virtual bool OnResponseStarted(int request_id, ResourceResponse* resp);
// Pass-through implementation.
- bool OnWillStart(int request_id, const GURL& url, bool* defer);
+ virtual bool OnWillStart(int request_id, const GURL& url, bool* defer);
// Create a new buffer to store received data.
- bool OnWillRead(int request_id, net::IOBuffer** buf, int* buf_size,
- int min_size);
+ virtual bool OnWillRead(int request_id, net::IOBuffer** buf, int* buf_size,
+ int min_size);
// A read was completed, maybe allocate a new buffer for further data.
- bool OnReadCompleted(int request_id, int* bytes_read);
+ virtual bool OnReadCompleted(int request_id, int* bytes_read);
// Done downloading the certificate.
- bool OnResponseCompleted(int request_id,
- const URLRequestStatus& urs,
- const std::string& sec_info);
+ virtual bool OnResponseCompleted(int request_id,
+ const URLRequestStatus& urs,
+ const std::string& sec_info);
- void OnRequestClosed();
+ virtual void OnRequestClosed();
private:
- ~X509UserCertResourceHandler();
+ virtual ~X509UserCertResourceHandler();
void AssembleResource();
diff --git a/chrome/browser/renderer_preferences_util.cc b/chrome/browser/renderer_preferences_util.cc
index a1a94bd..bfa0811 100644
--- a/chrome/browser/renderer_preferences_util.cc
+++ b/chrome/browser/renderer_preferences_util.cc
@@ -4,7 +4,7 @@
#include "chrome/browser/renderer_preferences_util.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#if defined(TOOLKIT_USES_GTK)
#include "chrome/browser/gtk/gtk_theme_provider.h"
@@ -17,7 +17,7 @@ void UpdateFromSystemSettings(RendererPreferences* prefs, Profile* profile) {
#if defined(TOOLKIT_USES_GTK)
gtk_util::UpdateGtkFontSettings(prefs);
-#if !defined(TOOLKIT_VIEWS)
+#if !defined(OS_CHROMEOS)
GtkThemeProvider* provider = GtkThemeProvider::GetFrom(profile);
prefs->focus_ring_color = provider->get_focus_ring_color();
@@ -30,9 +30,7 @@ void UpdateFromSystemSettings(RendererPreferences* prefs, Profile* profile) {
provider->get_inactive_selection_bg_color();
prefs->inactive_selection_fg_color =
provider->get_inactive_selection_fg_color();
-#endif // !defined(TOOLKIT_VIEWS)
-
-#if defined(OS_CHROMEOS)
+#else
prefs->focus_ring_color = SkColorSetARGB(255, 229, 151, 0);
prefs->active_selection_bg_color = SkColorSetRGB(0xDC, 0xE4, 0xFA);
prefs->active_selection_fg_color = SK_ColorBLACK;
diff --git a/chrome/browser/repost_form_warning_controller.cc b/chrome/browser/repost_form_warning_controller.cc
index 2cf6ff5..f5b9c37 100644
--- a/chrome/browser/repost_form_warning_controller.cc
+++ b/chrome/browser/repost_form_warning_controller.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/repost_form_warning_controller.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
RepostFormWarningController::RepostFormWarningController(
TabContents* tab_contents)
diff --git a/chrome/browser/repost_form_warning_controller.h b/chrome/browser/repost_form_warning_controller.h
index fb8cf28..e6aef10 100644
--- a/chrome/browser/repost_form_warning_controller.h
+++ b/chrome/browser/repost_form_warning_controller.h
@@ -32,9 +32,9 @@ class RepostFormWarningController : public NotificationObserver {
private:
// NotificationObserver implementation.
// Watch for a new load or a closed tab and dismiss the dialog if they occur.
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
// Close the warning dialog.
void CloseDialog();
diff --git a/chrome/browser/resources/about_conflicts.html b/chrome/browser/resources/about_conflicts.html
index 14274f4..301fb49 100644
--- a/chrome/browser/resources/about_conflicts.html
+++ b/chrome/browser/resources/about_conflicts.html
@@ -19,14 +19,10 @@ div#header {
min-height: 67px;
overflow: hidden;
padding-bottom: 20px;
- padding-left: 0;
+ -webkit-padding-start: 0;
padding-top: 20px;
position: relative;
- -webkit-box-sizing: border-box;
-}
-
-html[dir=rtl] #header {
- padding-right: 0;
+ box-sizing: border-box;
}
#header h1 {
@@ -66,16 +62,11 @@ div.content {
border-top: 1px solid #b5c7de;
font-size: 99%;
padding-bottom: 2px;
- padding-left: 5px;
+ -webkit-padding-start: 5px;
padding-top: 3px;
width: 100%;
}
-html[dir=rtl] .section-header {
- padding-right: 5px;
- padding-left: 0;
-}
-
.section-header > table > tr > td:first-child {
width: 100%;
}
@@ -100,12 +91,7 @@ html[dir=rtl] .section-header {
}
#top {
- padding-right: 5px;
-}
-
-html[dir=rtl] #top {
- padding-left: 5px;
- padding-right: 0;
+ -webkit-padding-end: 5px;
}
.module-loaded > td {
@@ -143,6 +129,20 @@ html[dir=rtl] #top {
margin-top: -1em;
margin-bottom: 1em;
}
+
+.clearing {
+ clear: left;
+ float: left;
+}
+
+html[dir=rtl] .clearing {
+ clear: right;
+ float: right;
+}
+
+.datacell {
+ border-bottom: 1px solid #aaa;
+}
</style>
<script>
@@ -245,31 +245,37 @@ html[dir=rtl] #top {
<td valign="top">
<table cellpadding="2" cellspacing="0" border="0">
<tr jsselect="moduleList">
- <td valign="top">
+ <td valign="top" class="datacell">
<span dir="ltr"
- jsvalues=".innerHTML:description" class="nowrap"></span>
+ jsvalues=".innerHTML:description"
+ class="clearing nowrap"></span>
<div jsdisplay="status == 2 || status == 3"
- class="extra-info-text"><br>
- <span jsdisplay="status == 2"
- i18n-content="moduleSuspectedBad"
- class="suspected-bad">SUSPECTED_BAD</span>
- <span jsdisplay="status == 3"
- i18n-content="moduleConfirmedBad"
- class="confirmed-bad">CONFIRMED_BAD</span>
- <a jsdisplay="help_url.length &gt; 0"
- jsvalues=".href:help_url"><span
- i18n-content="helpCenterLink">HELP_CENTER</span></a>
- <span jsdisplay="possibleResolution.length &gt; 0"><br>
- <span jscontent="possibleResolution"
+ class="extra-info-text">
+ <span class="clearing">
+ <span jsdisplay="status == 2"
+ i18n-content="moduleSuspectedBad"
+ class="suspected-bad">SUSPECTED_BAD</span>
+ <span jsdisplay="status == 3"
+ i18n-content="moduleConfirmedBad"
+ class="confirmed-bad">CONFIRMED_BAD</span>
+ <a jsdisplay="help_url.length &gt; 0"
+ jsvalues=".href:help_url"
+ i18n-content="helpCenterLink">HELP_CENTER</a>
+ </span>
+ <span jsdisplay="possibleResolution.length &gt; 0">
+ <span jscontent="possibleResolution" class="clearing"
>POSSIBLE_RESOLUTION</span>
</span>
</div>
</td>
- <td valign="top"><span dir="ltr" jscontent="digital_signer"
+ <td valign="top" class="datacell"><span dir="ltr"
+ jscontent="digital_signer"
class="nowrap">SIGNER</span></td>
- <td valign="top"><span dir="ltr" jscontent="version"
- class="nowrap">VERSION</span></td>
- <td valign="top">
+ <td valign="top" class="datacell"><span dir="ltr"
+ jscontent="version"
+ class="nowrap">VERSION</span
+ ></td>
+ <td valign="top" class="datacell">
<span class="nowrap">
<span dir="ltr" jscontent="location">LOCATION</span><strong
><span dir="ltr" jscontent="name">NAME</span></strong>
diff --git a/chrome/browser/resources/about_credits.html b/chrome/browser/resources/about_credits.html
index 5e83294..4f617a6 100644
--- a/chrome/browser/resources/about_credits.html
+++ b/chrome/browser/resources/about_credits.html
@@ -727,217 +727,6 @@ PERFORMANCE OF THIS SOFTWARE.
<div class="product">
-<span class="title">Google Toolbox for Mac</span>
-<a class="show" href="#" onclick="return toggle(this);">show license</a>
-<span class="homepage"><a href="http://code.google.com/p/google-toolbox-for-mac/">homepage</a></span>
-<div class="licence">
-<pre>
- 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 2007 Google Inc.
-
- 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.</pre>
-</div>
-</div>
-
-
-<div class="product">
<span class="title">WebKit</span>
<a class="show" href="#" onclick="return toggle(this);">show license</a>
<span class="homepage"><a href="http://webkit.org/">homepage</a></span>
@@ -1915,68 +1704,6 @@ DAMAGES.
<div class="product">
-<span class="title">ActiveX Scripting SDK</span>
-<a class="show" href="#" onclick="return toggle(this);">show license</a>
-<span class="homepage"><a href="http://support.microsoft.com/kb/223389">homepage</a></span>
-<div class="licence">
-<pre>THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS
-
-PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS
-
-ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES
-
-OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO
-
-EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR
-
-ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL,
-
-CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF
-
-MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE
-
-POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION
-
-OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES
-
-SO THE FOREGOING LIMITATION MAY NOT APPLY.
-
-
-
-MICROSOFT DOES NOT WARRANT THAT THE FUNCTIONS FOR THE LICENSED SOFTWARE
-
-OR CODE CONTAINED IN THE KNOWLEDGE BASE WILL MEET YOUR REQUIREMENTS, OR
-
-THAT THE OPERATION OF THE LICENSED SOFTWARE OR CODE WILL BE UNINTERRUPTED
-
-OR ERROR-FREE, OR THAT DEFECTS IN THE LICENSED SOFTWARE OR CODE CAN BE
-
-CORRECTED. FURTHERMORE, MICROSOFT DOES NOT WARRANT OR MAKE ANY
-
-REPRESENTATIONS REGARDING THE USE OR THE RESULTS OF THE USE OF THE LICENSED
-
-SOFTWARE, CODE OR RELATED DOCUMENTATION IN TERMS OF THEIR CORRECTNESS,
-
-ACCURACY, RELIABILITY, OR OTHERWISE. NO ORAL OR WRITTEN INFORMATION OR ADVICE
-
-GIVEN BY MICROSOFT OR ITS AUTHORIZED REPRESENTATIVES SHALL CREATE A WARRANTY
-
-OR IN ANY WAY INCREASE THE SCOPE OF THIS WARRANTY. SHOULD THE LICENSED
-
-SOFTWARE OR CODE PROVE DEFECTIVE AFTER MICROSOFT HAS DELIVERED THE SAME,
-
-YOU, AND YOU ALONE, SHALL ASSUME THE ENTIRE COST ASSOCIATED WITH ALL
-
-NECESSARY SERVICING, REPAIR OR CORRECTION.
-
-
-
-</pre>
-</div>
-</div>
-
-
-<div class="product">
<span class="title">Almost Native Graphics Layer Engine</span>
<a class="show" href="#" onclick="return toggle(this);">show license</a>
<span class="homepage"><a href="http://code.google.com/p/angleproject/">homepage</a></span>
@@ -3576,62 +3303,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
<div class="product">
-<span class="title">ffmpeg</span>
-<a class="show" href="#" onclick="return toggle(this);">show license</a>
-<span class="homepage"><a href="http://ffmpeg.org/">homepage</a></span>
-<div class="licence">
-<pre>FFmpeg:
--------
-
-Most files in FFmpeg are under the GNU Lesser General Public License version 2.1
-or later (LGPL v2.1+). Read the file COPYING.LGPLv2.1 for details. Some other
-files have MIT/X11/BSD-style licenses. In combination the LGPL v2.1+ applies to
-FFmpeg.
-
-Some optional parts of FFmpeg are licensed under the GNU General Public License
-version 2 or later (GPL v2+). See the file COPYING.GPLv2 for details. None of
-these parts are used by default, you have to explicitly pass --enable-gpl to
-configure to activate them. In this case, FFmpeg's license changes to GPL v2+.
-
-Specifically, the GPL parts of FFmpeg are
-
-- libpostproc
-- optional x86 optimizations in the files
- libavcodec/x86/idct_mmx.c
-- the X11 grabber in libavdevice/x11grab.c
-
-There are a handful of files under other licensing terms, namely:
-
-* The files libavcodec/jfdctfst.c, libavcodec/jfdctint.c, libavcodec/jrevdct.c
- are taken from libjpeg, see the top of the files for licensing details.
-
-Should you, for whatever reason, prefer to use version 3 of the (L)GPL, then
-the configure parameter --enable-version3 will activate this licensing option
-for you. Read the file COPYING.LGPLv3 or, if you have enabled GPL parts,
-COPYING.GPLv3 to learn the exact legal terms that apply in this case.
-
-
-external libraries:
--------------------
-
-Some external libraries, e.g. libx264, are under GPL and can be used in
-conjunction with FFmpeg. They require --enable-gpl to be passed to configure
-as well.
-
-The OpenCORE external libraries are under the Apache License 2.0. That license
-is incompatible with the LGPL v2.1 and the GPL v2, but not with version 3 of
-those licenses. So to combine the OpenCORE libraries with FFmpeg, the license
-version needs to be upgraded by passing --enable-version3 to configure.
-
-The nonfree external library libfaac can be hooked up in FFmpeg. You need to
-pass --enable-nonfree to configure to enable it. Employ this option with care
-as FFmpeg then becomes nonfree and unredistributable.
-</pre>
-</div>
-</div>
-
-
-<div class="product">
<span class="title">OpenGL ES 2.0 Programming Guide</span>
<a class="show" href="#" onclick="return toggle(this);">show license</a>
<span class="homepage"><a href="http://opengles-book.com/">homepage</a></span>
@@ -3653,83 +3324,44 @@ URLs: http://safari.informit.com/9780321563835
<span class="homepage"><a href="https://www.khronos.org/opengles/adopters/login/conformance/">homepage</a></span>
<div class="licence">
<pre>/*
-
** Copyright (c) 2008 The Khronos Group Inc.
-
**
-
** All Rights Reserved. This code is protected by copyright laws and
-
** contains material proprietary to the Khronos Group, Inc. This is
-
** UNPUBLISHED PROPRIETARY SOURCE CODE that may not be disclosed in whole
-
** or in part to third parties, and may not be reproduced, republished,
-
** distributed, transmitted, displayed, broadcast or otherwise exploited
-
** in any manner without the express prior written permission of Khronos
-
** Group.
-
**
-
** The receipt or possession of this code does not convey any rights to
-
** reproduce, disclose, or distribute its contents, or to manufacture,
-
** use, or sell anything that it may describe, in whole or in part other
-
** than under the terms of the Khronos Adopters Agreement or Khronos
-
** Conformance Test Source License Agreement as executed between Khronos
-
** and the recipient.
-
**
-
** For the avoidance of doubt, this code when provided: a) under the
-
** Khronos Conformance Test Source License Agreement is for the sole
-
** purpose of creating conformance tests for delivery to Khronos and does
-
** not provide for formally testing products or use of Khronos trademarks
-
** on conformant products; b) under the Khronos Adopters Agreement is for
-
** the sole purpose of formally administering tests to products pursuant
-
** to the Khronos Conformance Process Document.
-
**
-
** Khronos, OpenKODE, OpenVG, OpenWF, glFX, OpenMAX and OpenSL ES are
-
** trademarks of the Khronos Group Inc. COLLADA is a trademark of Sony
-
** Computer Entertainment Inc. used by permission by Khronos. OpenGL and
-
** OpenML are registered trademarks and the OpenGL ES logo is a trademark
-
** of Silicon Graphics Inc. used by permission by Khronos.
-
**
-
** Use, duplication or disclosure by the Government is subject to
-
** restrictions as set forth in subdivision (c)(1)(ii) of the Rights in
-
** Technical Data and Computer Software clause at DFARS 252.227-7013, and/
-
** or in similar or successor clauses in the FAR, DOD or NASA FAR
-
** Supplement. Unpublished rights reserved under the Copyright Laws of
-
** the United States and other countries.
-
*/
-
</pre>
</div>
</div>
@@ -4287,65 +3919,35 @@ above as far as the program is concerned.
<span class="homepage"><a href="http://hg.mozilla.org/mozilla-central/src/memory">homepage</a></span>
<div class="licence">
<pre>The following is the license for the jemalloc source code, as provided
-
in the initial section of the source files.
-
-
Copyright (C) 2006-2008 Jason Evans &lt;jasone@FreeBSD.org&gt;.
-
All rights reserved.
-
-
Redistribution and use in source and binary forms, with or without
-
modification, are permitted provided that the following conditions
-
are met:
-
1. Redistributions of source code must retain the above copyright
-
notice(s), this list of conditions and the following disclaimer as
-
the first lines of this file unmodified other than the possible
-
addition of one or more copyright notices.
-
2. Redistributions in binary form must reproduce the above copyright
-
notice(s), this list of conditions and the following disclaimer in
-
the documentation and/or other materials provided with the
-
distribution.
-
-
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
-
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
-
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
-
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
-
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
</pre>
</div>
</div>
@@ -5659,143 +5261,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
<div class="product">
-<span class="title">openssl</span>
-<a class="show" href="#" onclick="return toggle(this);">show license</a>
-<span class="homepage"><a href="http://openssl.org/source/">homepage</a></span>
-<div class="licence">
-<pre>
- LICENSE ISSUES
- ==============
-
- The OpenSSL toolkit stays under a dual license, i.e. both the conditions of
- the OpenSSL License and the original SSLeay license apply to the toolkit.
- See below for the actual license texts. Actually both licenses are BSD-style
- Open Source licenses. In case of any license issues related to OpenSSL
- please contact openssl-core@openssl.org.
-
- OpenSSL License
- ---------------
-
-/* ====================================================================
- * Copyright (c) 1998-2008 The OpenSSL Project. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (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 product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
- Original SSLeay License
- -----------------------
-
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (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 licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-</pre>
-</div>
-</div>
-
-
-<div class="product">
<span class="title">OTS (OpenType Sanitizer)</span>
<a class="show" href="#" onclick="return toggle(this);">show license</a>
<span class="homepage"><a href="http://code.google.com/p/ots/">homepage</a></span>
@@ -5833,212 +5298,38 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
<div class="product">
-<span class="title">pdfsqueeze</span>
+<span class="title">ppapi</span>
<a class="show" href="#" onclick="return toggle(this);">show license</a>
-<span class="homepage"><a href="http://code.google.com/p/pdfsqueeze/">homepage</a></span>
+<span class="homepage"><a href="http://code.google.com/p/ppapi/">homepage</a></span>
<div class="licence">
-<pre>
- 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 2007 Google Inc.
-
- 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.</pre>
+<pre>// Copyright (c) 2010 The Chromium 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 names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+</pre>
</div>
</div>
@@ -6118,149 +5409,6 @@ CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
<div class="product">
-<span class="title">qcms library</span>
-<a class="show" href="#" onclick="return toggle(this);">show license</a>
-<span class="homepage"><a href="http://mxr.mozilla.org/mozilla-central/source/gfx/qcms/">homepage</a></span>
-<div class="licence">
-<pre>This license applies to certain files in the directory third_party/qcms/.
-
-
-
-Copyright (C) 2009 Mozilla Corporation
-
-Copyright (C) 1998-2007 Marti Maria
-
-
-
-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.
-
-
-
-
-
-
-
-This license applies to the ICC_H block in third_party/qcms/qcms.h.
-
-
-
-Copyright (c) 1994-1996 SunSoft, Inc.
-
-
-
- Rights Reserved
-
-
-
-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 restrict-
-
-ion, 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 NON-
-
-INFRINGEMENT. IN NO EVENT SHALL SUNSOFT, INC. OR ITS PARENT
-
-COMPANY 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.
-
-
-
-Except as contained in this notice, the name of SunSoft, Inc.
-
-shall not be used in advertising or otherwise to promote the
-
-sale, use or other dealings in this Software without written
-
-authorization from SunSoft Inc.
-
-</pre>
-</div>
-</div>
-
-
-<div class="product">
-<span class="title">Google Safe Browsing</span>
-<a class="show" href="#" onclick="return toggle(this);">show license</a>
-<span class="homepage"><a href="http://code.google.com/p/google-safe-browsing/">homepage</a></span>
-<div class="licence">
-<pre>Copyright 2009 Google Inc.
-
-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.
-</pre>
-</div>
-</div>
-
-
-<div class="product">
<span class="title">simplejson</span>
<a class="show" href="#" onclick="return toggle(this);">show license</a>
<span class="homepage"><a href="http://undefined.org/python/#simplejson">homepage</a></span>
@@ -6668,38 +5816,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<div class="product">
-<span class="title">talloc</span>
-<a class="show" href="#" onclick="return toggle(this);">show license</a>
-<span class="homepage"><a href="http://talloc.samba.org/talloc/doc/html/index.html">homepage</a></span>
-<div class="licence">
-<pre> Unix SMB/CIFS implementation.
- Samba temporary memory allocation functions
-
- Copyright (C) Andrew Tridgell 2004-2005
- Copyright (C) Stefan Metzmacher 2006
-
- ** NOTE! The following LGPL license applies to the talloc
- ** library. This does NOT imply that all of Samba is released
- ** under the LGPL
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 3 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, see &lt;http://www.gnu.org/licenses/&gt;.
-</pre>
-</div>
-</div>
-
-
-<div class="product">
<span class="title">tcmalloc</span>
<a class="show" href="#" onclick="return toggle(this);">show license</a>
<span class="homepage"><a href="http://google-perftools.googlecode.com/">homepage</a></span>
@@ -6944,135 +6060,70 @@ LICENSE: Apache 2
<span class="homepage"><a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=e5ba5ba4-6e6b-462a-b24c-61115e846f0c">homepage</a></span>
<div class="licence">
<pre>Microsoft Permissive License (Ms-PL)
-
Published: October 12, 2006
-
-
-
This license governs use of the accompanying software. If you use the software,
-
you accept this license. If you do not accept the license, do not use the
-
software.
-
-
-
1. Definitions
-
-
The terms "reproduce," "reproduction," "derivative works," and "distribution"
-
have the same meaning here as under U.S. copyright law.
-
-
A "contribution" is the original software, or any additions or changes to the
-
software.
-
-
A "contributor" is any person that distributes its contribution under this
-
license.
-
-
"Licensed patents" are a contributor’s patent claims that read directly on its
-
contribution.
-
-
-
2. Grant of Rights
-
-
(A) Copyright Grant- Subject to the terms of this license, including the
-
license conditions and limitations in section 3, each contributor grants you a
-
non-exclusive, worldwide, royalty-free copyright license to reproduce its
-
contribution, prepare derivative works of its contribution, and distribute its
-
contribution or any derivative works that you create.
-
-
(B) Patent Grant- Subject to the terms of this license, including the license
-
conditions and limitations in section 3, each contributor grants you a
-
non-exclusive, worldwide, royalty-free license under its licensed patents to
-
make, have made, use, sell, offer for sale, import, and/or otherwise dispose of
-
its contribution in the software or derivative works of the contribution in the
-
software.
-
-
-
3. Conditions and Limitations
-
-
(A) No Trademark License- This license does not grant you rights to use any
-
contributors’ name, logo, or trademarks.
-
-
(B) If you bring a patent claim against any contributor over patents that you
-
claim are infringed by the software, your patent license from such contributor
-
to the software ends automatically.
-
-
(C) If you distribute any portion of the software, you must retain all
-
copyright, patent, trademark, and attribution notices that are present in the
-
software.
-
-
(D) If you distribute any portion of the software in source code form, you may
-
do so only under this license by including a complete copy of this license with
-
your distribution. If you distribute any portion of the software in compiled or
-
object code form, you may only do so under a license that complies with this
-
license.
-
-
(E) The software is licensed "as-is." You bear the risk of using it. The
-
contributors give no express warranties, guarantees or conditions. You may have
-
additional consumer rights under your local laws which this license cannot
-
change. To the extent permitted under your local laws, the contributors exclude
-
the implied warranties of merchantability, fitness for a particular purpose and
-
non-infringement.
-
</pre>
</div>
</div>
@@ -7107,583 +6158,6 @@ non-infringement.
<div class="product">
-<span class="title">XUL Runner SDK</span>
-<a class="show" href="#" onclick="return toggle(this);">show license</a>
-<span class="homepage"><a href="https://developer.mozilla.org/en/Gecko_SDK">homepage</a></span>
-<div class="licence">
-<pre> MOZILLA PUBLIC LICENSE
- Version 1.1
-
- ---------------
-
-1. Definitions.
-
- 1.0.1. "Commercial Use" means distribution or otherwise making the
- Covered Code available to a third party.
-
- 1.1. "Contributor" means each entity that creates or contributes to
- the creation of Modifications.
-
- 1.2. "Contributor Version" means the combination of the Original
- Code, prior Modifications used by a Contributor, and the Modifications
- made by that particular Contributor.
-
- 1.3. "Covered Code" means the Original Code or Modifications or the
- combination of the Original Code and Modifications, in each case
- including portions thereof.
-
- 1.4. "Electronic Distribution Mechanism" means a mechanism generally
- accepted in the software development community for the electronic
- transfer of data.
-
- 1.5. "Executable" means Covered Code in any form other than Source
- Code.
-
- 1.6. "Initial Developer" means the individual or entity identified
- as the Initial Developer in the Source Code notice required by Exhibit
- A.
-
- 1.7. "Larger Work" means a work which combines Covered Code or
- portions thereof with code not governed by the terms of this License.
-
- 1.8. "License" means this document.
-
- 1.8.1. "Licensable" means having the right to grant, to the maximum
- extent possible, whether at the time of the initial grant or
- subsequently acquired, any and all of the rights conveyed herein.
-
- 1.9. "Modifications" means any addition to or deletion from the
- substance or structure of either the Original Code or any previous
- Modifications. When Covered Code is released as a series of files, a
- Modification is:
- A. Any addition to or deletion from the contents of a file
- containing Original Code or previous Modifications.
-
- B. Any new file that contains any part of the Original Code or
- previous Modifications.
-
- 1.10. "Original Code" means Source Code of computer software code
- which is described in the Source Code notice required by Exhibit A as
- Original Code, and which, at the time of its release under this
- License is not already Covered Code governed by this License.
-
- 1.10.1. "Patent Claims" means any patent claim(s), now owned or
- hereafter acquired, including without limitation, method, process,
- and apparatus claims, in any patent Licensable by grantor.
-
- 1.11. "Source Code" means the preferred form of the Covered Code for
- making modifications to it, including all modules it contains, plus
- any associated interface definition files, scripts used to control
- compilation and installation of an Executable, or source code
- differential comparisons against either the Original Code or another
- well known, available Covered Code of the Contributor's choice. The
- Source Code can be in a compressed or archival form, provided the
- appropriate decompression or de-archiving software is widely available
- for no charge.
-
- 1.12. "You" (or "Your") means an individual or a legal entity
- exercising rights under, and complying with all of the terms of, this
- License or a future version of this License issued under Section 6.1.
- For legal entities, "You" includes any entity which controls, is
- controlled by, or is under common control with You. For purposes of
- this definition, "control" means (a) the power, direct or indirect,
- to cause the direction or management of such entity, whether by
- contract or otherwise, or (b) ownership of more than fifty percent
- (50%) of the outstanding shares or beneficial ownership of such
- entity.
-
-2. Source Code License.
-
- 2.1. The Initial Developer Grant.
- The Initial Developer hereby grants You a world-wide, royalty-free,
- non-exclusive license, subject to third party intellectual property
- claims:
- (a) under intellectual property rights (other than patent or
- trademark) Licensable by Initial Developer to use, reproduce,
- modify, display, perform, sublicense and distribute the Original
- Code (or portions thereof) with or without Modifications, and/or
- as part of a Larger Work; and
-
- (b) under Patents Claims infringed by the making, using or
- selling of Original Code, to make, have made, use, practice,
- sell, and offer for sale, and/or otherwise dispose of the
- Original Code (or portions thereof).
-
- (c) the licenses granted in this Section 2.1(a) and (b) are
- effective on the date Initial Developer first distributes
- Original Code under the terms of this License.
-
- (d) Notwithstanding Section 2.1(b) above, no patent license is
- granted: 1) for code that You delete from the Original Code; 2)
- separate from the Original Code; or 3) for infringements caused
- by: i) the modification of the Original Code or ii) the
- combination of the Original Code with other software or devices.
-
- 2.2. Contributor Grant.
- Subject to third party intellectual property claims, each Contributor
- hereby grants You a world-wide, royalty-free, non-exclusive license
-
- (a) under intellectual property rights (other than patent or
- trademark) Licensable by Contributor, to use, reproduce, modify,
- display, perform, sublicense and distribute the Modifications
- created by such Contributor (or portions thereof) either on an
- unmodified basis, with other Modifications, as Covered Code
- and/or as part of a Larger Work; and
-
- (b) under Patent Claims infringed by the making, using, or
- selling of Modifications made by that Contributor either alone
- and/or in combination with its Contributor Version (or portions
- of such combination), to make, use, sell, offer for sale, have
- made, and/or otherwise dispose of: 1) Modifications made by that
- Contributor (or portions thereof); and 2) the combination of
- Modifications made by that Contributor with its Contributor
- Version (or portions of such combination).
-
- (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
- effective on the date Contributor first makes Commercial Use of
- the Covered Code.
-
- (d) Notwithstanding Section 2.2(b) above, no patent license is
- granted: 1) for any code that Contributor has deleted from the
- Contributor Version; 2) separate from the Contributor Version;
- 3) for infringements caused by: i) third party modifications of
- Contributor Version or ii) the combination of Modifications made
- by that Contributor with other software (except as part of the
- Contributor Version) or other devices; or 4) under Patent Claims
- infringed by Covered Code in the absence of Modifications made by
- that Contributor.
-
-3. Distribution Obligations.
-
- 3.1. Application of License.
- The Modifications which You create or to which You contribute are
- governed by the terms of this License, including without limitation
- Section 2.2. The Source Code version of Covered Code may be
- distributed only under the terms of this License or a future version
- of this License released under Section 6.1, and You must include a
- copy of this License with every copy of the Source Code You
- distribute. You may not offer or impose any terms on any Source Code
- version that alters or restricts the applicable version of this
- License or the recipients' rights hereunder. However, You may include
- an additional document offering the additional rights described in
- Section 3.5.
-
- 3.2. Availability of Source Code.
- Any Modification which You create or to which You contribute must be
- made available in Source Code form under the terms of this License
- either on the same media as an Executable version or via an accepted
- Electronic Distribution Mechanism to anyone to whom you made an
- Executable version available; and if made available via Electronic
- Distribution Mechanism, must remain available for at least twelve (12)
- months after the date it initially became available, or at least six
- (6) months after a subsequent version of that particular Modification
- has been made available to such recipients. You are responsible for
- ensuring that the Source Code version remains available even if the
- Electronic Distribution Mechanism is maintained by a third party.
-
- 3.3. Description of Modifications.
- You must cause all Covered Code to which You contribute to contain a
- file documenting the changes You made to create that Covered Code and
- the date of any change. You must include a prominent statement that
- the Modification is derived, directly or indirectly, from Original
- Code provided by the Initial Developer and including the name of the
- Initial Developer in (a) the Source Code, and (b) in any notice in an
- Executable version or related documentation in which You describe the
- origin or ownership of the Covered Code.
-
- 3.4. Intellectual Property Matters
- (a) Third Party Claims.
- If Contributor has knowledge that a license under a third party's
- intellectual property rights is required to exercise the rights
- granted by such Contributor under Sections 2.1 or 2.2,
- Contributor must include a text file with the Source Code
- distribution titled "LEGAL" which describes the claim and the
- party making the claim in sufficient detail that a recipient will
- know whom to contact. If Contributor obtains such knowledge after
- the Modification is made available as described in Section 3.2,
- Contributor shall promptly modify the LEGAL file in all copies
- Contributor makes available thereafter and shall take other steps
- (such as notifying appropriate mailing lists or newsgroups)
- reasonably calculated to inform those who received the Covered
- Code that new knowledge has been obtained.
-
- (b) Contributor APIs.
- If Contributor's Modifications include an application programming
- interface and Contributor has knowledge of patent licenses which
- are reasonably necessary to implement that API, Contributor must
- also include this information in the LEGAL file.
-
- (c) Representations.
- Contributor represents that, except as disclosed pursuant to
- Section 3.4(a) above, Contributor believes that Contributor's
- Modifications are Contributor's original creation(s) and/or
- Contributor has sufficient rights to grant the rights conveyed by
- this License.
-
- 3.5. Required Notices.
- You must duplicate the notice in Exhibit A in each file of the Source
- Code. If it is not possible to put such notice in a particular Source
- Code file due to its structure, then You must include such notice in a
- location (such as a relevant directory) where a user would be likely
- to look for such a notice. If You created one or more Modification(s)
- You may add your name as a Contributor to the notice described in
- Exhibit A. You must also duplicate this License in any documentation
- for the Source Code where You describe recipients' rights or ownership
- rights relating to Covered Code. You may choose to offer, and to
- charge a fee for, warranty, support, indemnity or liability
- obligations to one or more recipients of Covered Code. However, You
- may do so only on Your own behalf, and not on behalf of the Initial
- Developer or any Contributor. You must make it absolutely clear than
- any such warranty, support, indemnity or liability obligation is
- offered by You alone, and You hereby agree to indemnify the Initial
- Developer and every Contributor for any liability incurred by the
- Initial Developer or such Contributor as a result of warranty,
- support, indemnity or liability terms You offer.
-
- 3.6. Distribution of Executable Versions.
- You may distribute Covered Code in Executable form only if the
- requirements of Section 3.1-3.5 have been met for that Covered Code,
- and if You include a notice stating that the Source Code version of
- the Covered Code is available under the terms of this License,
- including a description of how and where You have fulfilled the
- obligations of Section 3.2. The notice must be conspicuously included
- in any notice in an Executable version, related documentation or
- collateral in which You describe recipients' rights relating to the
- Covered Code. You may distribute the Executable version of Covered
- Code or ownership rights under a license of Your choice, which may
- contain terms different from this License, provided that You are in
- compliance with the terms of this License and that the license for the
- Executable version does not attempt to limit or alter the recipient's
- rights in the Source Code version from the rights set forth in this
- License. If You distribute the Executable version under a different
- license You must make it absolutely clear that any terms which differ
- from this License are offered by You alone, not by the Initial
- Developer or any Contributor. You hereby agree to indemnify the
- Initial Developer and every Contributor for any liability incurred by
- the Initial Developer or such Contributor as a result of any such
- terms You offer.
-
- 3.7. Larger Works.
- You may create a Larger Work by combining Covered Code with other code
- not governed by the terms of this License and distribute the Larger
- Work as a single product. In such a case, You must make sure the
- requirements of this License are fulfilled for the Covered Code.
-
-4. Inability to Comply Due to Statute or Regulation.
-
- If it is impossible for You to comply with any of the terms of this
- License with respect to some or all of the Covered Code due to
- statute, judicial order, or regulation then You must: (a) comply with
- the terms of this License to the maximum extent possible; and (b)
- describe the limitations and the code they affect. Such description
- must be included in the LEGAL file described in Section 3.4 and must
- be included with all distributions of the Source Code. Except to the
- extent prohibited by statute or regulation, such description must be
- sufficiently detailed for a recipient of ordinary skill to be able to
- understand it.
-
-5. Application of this License.
-
- This License applies to code to which the Initial Developer has
- attached the notice in Exhibit A and to related Covered Code.
-
-6. Versions of the License.
-
- 6.1. New Versions.
- Netscape Communications Corporation ("Netscape") may publish revised
- and/or new versions of the License from time to time. Each version
- will be given a distinguishing version number.
-
- 6.2. Effect of New Versions.
- Once Covered Code has been published under a particular version of the
- License, You may always continue to use it under the terms of that
- version. You may also choose to use such Covered Code under the terms
- of any subsequent version of the License published by Netscape. No one
- other than Netscape has the right to modify the terms applicable to
- Covered Code created under this License.
-
- 6.3. Derivative Works.
- If You create or use a modified version of this License (which you may
- only do in order to apply it to code which is not already Covered Code
- governed by this License), You must (a) rename Your license so that
- the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
- "MPL", "NPL" or any confusingly similar phrase do not appear in your
- license (except to note that your license differs from this License)
- and (b) otherwise make it clear that Your version of the license
- contains terms which differ from the Mozilla Public License and
- Netscape Public License. (Filling in the name of the Initial
- Developer, Original Code or Contributor in the notice described in
- Exhibit A shall not of themselves be deemed to be modifications of
- this License.)
-
-7. DISCLAIMER OF WARRANTY.
-
- COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
- WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
- WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
- DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
- THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
- IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
- YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
- COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
- OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
- ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
-
-8. TERMINATION.
-
- 8.1. This License and the rights granted hereunder will terminate
- automatically if You fail to comply with terms herein and fail to cure
- such breach within 30 days of becoming aware of the breach. All
- sublicenses to the Covered Code which are properly granted shall
- survive any termination of this License. Provisions which, by their
- nature, must remain in effect beyond the termination of this License
- shall survive.
-
- 8.2. If You initiate litigation by asserting a patent infringement
- claim (excluding declatory judgment actions) against Initial Developer
- or a Contributor (the Initial Developer or Contributor against whom
- You file such action is referred to as "Participant") alleging that:
-
- (a) such Participant's Contributor Version directly or indirectly
- infringes any patent, then any and all rights granted by such
- Participant to You under Sections 2.1 and/or 2.2 of this License
- shall, upon 60 days notice from Participant terminate prospectively,
- unless if within 60 days after receipt of notice You either: (i)
- agree in writing to pay Participant a mutually agreeable reasonable
- royalty for Your past and future use of Modifications made by such
- Participant, or (ii) withdraw Your litigation claim with respect to
- the Contributor Version against such Participant. If within 60 days
- of notice, a reasonable royalty and payment arrangement are not
- mutually agreed upon in writing by the parties or the litigation claim
- is not withdrawn, the rights granted by Participant to You under
- Sections 2.1 and/or 2.2 automatically terminate at the expiration of
- the 60 day notice period specified above.
-
- (b) any software, hardware, or device, other than such Participant's
- Contributor Version, directly or indirectly infringes any patent, then
- any rights granted to You by such Participant under Sections 2.1(b)
- and 2.2(b) are revoked effective as of the date You first made, used,
- sold, distributed, or had made, Modifications made by that
- Participant.
-
- 8.3. If You assert a patent infringement claim against Participant
- alleging that such Participant's Contributor Version directly or
- indirectly infringes any patent where such claim is resolved (such as
- by license or settlement) prior to the initiation of patent
- infringement litigation, then the reasonable value of the licenses
- granted by such Participant under Sections 2.1 or 2.2 shall be taken
- into account in determining the amount or value of any payment or
- license.
-
- 8.4. In the event of termination under Sections 8.1 or 8.2 above,
- all end user license agreements (excluding distributors and resellers)
- which have been validly granted by You or any distributor hereunder
- prior to termination shall survive termination.
-
-9. LIMITATION OF LIABILITY.
-
- UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
- (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
- DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
- OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
- ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
- CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
- WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
- COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
- INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
- LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
- RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
- PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
- EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
- THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
-
-10. U.S. GOVERNMENT END USERS.
-
- The Covered Code is a "commercial item," as that term is defined in
- 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
- software" and "commercial computer software documentation," as such
- terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
- C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
- all U.S. Government End Users acquire Covered Code with only those
- rights set forth herein.
-
-11. MISCELLANEOUS.
-
- This License represents the complete agreement concerning subject
- matter hereof. If any provision of this License is held to be
- unenforceable, such provision shall be reformed only to the extent
- necessary to make it enforceable. This License shall be governed by
- California law provisions (except to the extent applicable law, if
- any, provides otherwise), excluding its conflict-of-law provisions.
- With respect to disputes in which at least one party is a citizen of,
- or an entity chartered or registered to do business in the United
- States of America, any litigation relating to this License shall be
- subject to the jurisdiction of the Federal Courts of the Northern
- District of California, with venue lying in Santa Clara County,
- California, with the losing party responsible for costs, including
- without limitation, court costs and reasonable attorneys' fees and
- expenses. The application of the United Nations Convention on
- Contracts for the International Sale of Goods is expressly excluded.
- Any law or regulation which provides that the language of a contract
- shall be construed against the drafter shall not apply to this
- License.
-
-12. RESPONSIBILITY FOR CLAIMS.
-
- As between Initial Developer and the Contributors, each party is
- responsible for claims and damages arising, directly or indirectly,
- out of its utilization of rights under this License and You agree to
- work with Initial Developer and Contributors to distribute such
- responsibility on an equitable basis. Nothing herein is intended or
- shall be deemed to constitute any admission of liability.
-
-13. MULTIPLE-LICENSED CODE.
-
- Initial Developer may designate portions of the Covered Code as
- "Multiple-Licensed". "Multiple-Licensed" means that the Initial
- Developer permits you to utilize portions of the Covered Code under
- Your choice of the NPL or the alternative licenses, if any, specified
- by the Initial Developer in the file described in Exhibit A.
-
-EXHIBIT A -Mozilla Public License.
-
- ``The contents of this file are subject to the Mozilla Public License
- Version 1.1 (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.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
- License for the specific language governing rights and limitations
- under the License.
-
- The Original Code is ______________________________________.
-
- The Initial Developer of the Original Code is ________________________.
- Portions created by ______________________ are Copyright (C) ______
- _______________________. All Rights Reserved.
-
- Contributor(s): ______________________________________.
-
- Alternatively, the contents of this file may be used under the terms
- of the _____ license (the "[___] License"), in which case the
- provisions of [______] License are applicable instead of those
- above. If you wish to allow use of your version of this file only
- under the terms of the [____] License and not to allow others to use
- your version of this file under the MPL, indicate your decision by
- deleting the provisions above and replace them with the notice and
- other provisions required by the [___] License. If you do not delete
- the provisions above, a recipient may use your version of this file
- under either the MPL or the [___] License."
-
- [NOTE: The text of this Exhibit A may differ slightly from the text of
- the notices in the Source Code files of the Original Code. You should
- use the text of this Exhibit A rather than the text found in the
- Original Code Source Code for Your Modifications.]
-
- ----------------------------------------------------------------------
-
- AMENDMENTS
-
- The Netscape Public License Version 1.1 ("NPL") consists of the
- Mozilla Public License Version 1.1 with the following Amendments,
- including Exhibit A-Netscape Public License. Files identified with
- "Exhibit A-Netscape Public License" are governed by the Netscape
- Public License Version 1.1.
-
- Additional Terms applicable to the Netscape Public License.
- I. Effect.
- These additional terms described in this Netscape Public
- License -- Amendments shall apply to the Mozilla Communicator
- client code and to all Covered Code under this License.
-
- II. "Netscape's Branded Code" means Covered Code that Netscape
- distributes and/or permits others to distribute under one or more
- trademark(s) which are controlled by Netscape but which are not
- licensed for use under this License.
-
- III. Netscape and logo.
- This License does not grant any rights to use the trademarks
- "Netscape", the "Netscape N and horizon" logo or the "Netscape
- lighthouse" logo, "Netcenter", "Gecko", "Java" or "JavaScript",
- "Smart Browsing" even if such marks are included in the Original
- Code or Modifications.
-
- IV. Inability to Comply Due to Contractual Obligation.
- Prior to licensing the Original Code under this License, Netscape
- has licensed third party code for use in Netscape's Branded Code.
- To the extent that Netscape is limited contractually from making
- such third party code available under this License, Netscape may
- choose to reintegrate such code into Covered Code without being
- required to distribute such code in Source Code form, even if
- such code would otherwise be considered "Modifications" under
- this License.
-
- V. Use of Modifications and Covered Code by Initial Developer.
- V.1. In General.
- The obligations of Section 3 apply to Netscape, except to
- the extent specified in this Amendment, Section V.2 and V.3.
-
- V.2. Other Products.
- Netscape may include Covered Code in products other than the
- Netscape's Branded Code which are released by Netscape
- during the two (2) years following the release date of the
- Original Code, without such additional products becoming
- subject to the terms of this License, and may license such
- additional products on different terms from those contained
- in this License.
-
- V.3. Alternative Licensing.
- Netscape may license the Source Code of Netscape's Branded
- Code, including Modifications incorporated therein, without
- such Netscape Branded Code becoming subject to the terms of
- this License, and may license such Netscape Branded Code on
- different terms from those contained in this License.
-
- VI. Litigation.
- Notwithstanding the limitations of Section 11 above, the
- provisions regarding litigation in Section 11(a), (b) and (c) of
- the License shall apply to all disputes relating to this License.
-
- EXHIBIT A-Netscape Public License.
-
- "The contents of this file are subject to the Netscape Public
- License Version 1.1 (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.mozilla.org/NPL/
-
- Software distributed under the License is distributed on an "AS
- IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- implied. See the License for the specific language governing
- rights and limitations under the License.
-
- The Original Code is Mozilla Communicator client code, released
- March 31, 1998.
-
- The Initial Developer of the Original Code is Netscape
- Communications Corporation. Portions created by Netscape are
- Copyright (C) 1998-1999 Netscape Communications Corporation. All
- Rights Reserved.
-
- Contributor(s): ______________________________________.
-
- Alternatively, the contents of this file may be used under the
- terms of the _____ license (the "[___] License"), in which case
- the provisions of [______] License are applicable instead of
- those above. If you wish to allow use of your version of this
- file only under the terms of the [____] License and not to allow
- others to use your version of this file under the NPL, indicate
- your decision by deleting the provisions above and replace them
- with the notice and other provisions required by the [___]
- License. If you do not delete the provisions above, a recipient
- may use your version of this file under either the NPL or the
- [___] License."
-</pre>
-</div>
-</div>
-
-
-<div class="product">
<span class="title">yasm</span>
<a class="show" href="#" onclick="return toggle(this);">show license</a>
<span class="homepage"><a href="http://www.tortall.net/projects/yasm/">homepage</a></span>
@@ -7789,45 +6263,6 @@ GNU_LGPL-2.0 - GNU Library General Public License
</div>
-<div class="product">
-<span class="title">Strongtalk</span>
-<a class="show" href="#" onclick="return toggle(this);">show license</a>
-<span class="homepage"><a href="http://www.strongtalk.org/">homepage</a></span>
-<div class="licence">
-<pre>Copyright (c) 1994-2006 Sun Microsystems 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.
-
-- Redistribution in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
-- Neither the name of Sun Microsystems or the names of contributors may
- be used to endorse or promote products derived from this software without
- specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-</pre>
-</div>
-</div>
-
-
</div>
</body>
diff --git a/chrome/browser/resources/about_os_credits.html b/chrome/browser/resources/about_os_credits.html
index 1996986..a7f66e2 100644
--- a/chrome/browser/resources/about_os_credits.html
+++ b/chrome/browser/resources/about_os_credits.html
@@ -29962,11 +29962,11 @@ THE SOFTWARE.
Copyright (C) 2002-2007, Milan Ikits &lt;milan ikits[]ieee org&gt;
Copyright (C) 2002-2007, Marcelo E. Magallon &lt;mmagallo[]debian org&gt;
Copyright (C) 2002, Lev Povalahev
-All rights reserved.
-
+All rights reserved.
+
Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
+modification, are permitted provided that the following conditions are met:
+
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
@@ -29974,20 +29974,20 @@ modification, are permitted provided that the following conditions are met:
and/or other materials provided with the distribution.
* The name of the author may be used to endorse or promote products
derived from this software without specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
-
-
+
+
Mesa 3-D graphics library
Version: 7.0
@@ -30016,20 +30016,20 @@ Copyright (c) 2007 The Khronos Group Inc.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and/or associated documentation files (the
"Materials"), to deal in the Materials without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
+without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Materials, and to
permit persons to whom the Materials are furnished to do so, subject to
-the following conditions:
-
+the following conditions:
+
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Materials.
-
+
THE MATERIALS ARE 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
+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
MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
</pre>
</div>
diff --git a/chrome/browser/resources/about_sys.html b/chrome/browser/resources/about_sys.html
index e160a10..3e62b39 100644
--- a/chrome/browser/resources/about_sys.html
+++ b/chrome/browser/resources/about_sys.html
@@ -139,19 +139,11 @@ html[dir='rtl'] .number_expanded, html[dir='rtl'] .number_collapsed {
text-align: right;
}
-tr:not(.firstRow) > *:nth-child(1,
+tr:not(.firstRow) > *:nth-child(1),
tr:not(.firstRow) > *:nth-child(2),
tr.firstRow th:nth-child(1),
tr.firstRow th:nth-child(2) {
- border-right: 1px solid #b5c6de;
-}
-
-html[dir='rtl'] tr:not(.firstRow) > *:nth-child(1),
-html[dir='rtl'] tr:not(.firstRow) > *:nth-child(2),
-html[dir='rtl'] tr.firstRow th:nth-child(1),
-html[dir='rtl'] tr.firstRow th:nth-child(2) {
- border-right: auto;
- border-left: 1px solid #b5c6de;
+ -webkit-border-end: 1px solid #b5c6de;
}
.name {
diff --git a/chrome/browser/resources/bookmark_manager/css/bmm.css b/chrome/browser/resources/bookmark_manager/css/bmm.css
index d117e8a..40e7951 100644
--- a/chrome/browser/resources/bookmark_manager/css/bmm.css
+++ b/chrome/browser/resources/bookmark_manager/css/bmm.css
@@ -26,7 +26,7 @@ list > * {
}
list > * > * {
- -webkit-box-sizing: border-box;
+ box-sizing: border-box;
-webkit-padding-start: 20px;
background: 0 50% no-repeat;
overflow: hidden;
@@ -183,7 +183,7 @@ html[os=mac] .tree-row[selected] > .tree-label {
min-width: 50px;
max-width: 50%;
overflow: auto;
- -webkit-box-sizing: border-box;
+ box-sizing: border-box;
padding: 5px;
-webkit-padding-start: 10px;
}
@@ -196,7 +196,7 @@ html[os=mac] .tree-row[selected] > .tree-label {
#list {
-webkit-box-flex: 1;
- -webkit-box-sizing: border-box;
+ box-sizing: border-box;
padding: 5px;
}
@@ -243,7 +243,7 @@ html[dir=rtl] .header form {
pointer-events: none;
border: 1px solid hsl(214, 91%, 85%);;
border-radius: 3px;
- -webkit-box-sizing: border-box;
+ box-sizing: border-box;
background-color: hsla(214, 91%, 85%, .5);
overflow: hidden;
z-index: -1;
diff --git a/chrome/browser/resources/bookmark_manager/main.html b/chrome/browser/resources/bookmark_manager/main.html
index 856fe2b..4fc5dc4 100644
--- a/chrome/browser/resources/bookmark_manager/main.html
+++ b/chrome/browser/resources/bookmark_manager/main.html
@@ -55,7 +55,7 @@ found in the LICENSE file.
<button class="logo" tabindex=3></button>
<form onsubmit="setSearch(this.term.value); return false;"
class="form">
- <input type="search" id="term" tabindex=1 autofocus
+ <input type="search" id="term" tabindex=1 autofocus incremental
i18n-values="placeholder:search_button">
</form>
</div>
@@ -154,7 +154,7 @@ const Promise = cr.Promise;
// Sometimes the extension API is not initialized.
if (!chrome.bookmarks)
- console.error('Bookmarks extension API is not avaiable');
+ console.error('Bookmarks extension API is not available');
// Allow platform specific CSS rules.
if (cr.isMac)
@@ -330,18 +330,8 @@ list.addEventListener('urlClicked', function(e) {
getLinkController().openUrlFromEvent(e.url, e.originalEvent);
});
-/**
- * Timer id used for delaying find-as-you-type
- */
-var inputDelayTimer;
-
-// Capture input changes to the search term input element and delay searching
-// for 250ms to reduce flicker.
-$('term').oninput = function(e) {
- clearTimeout(inputDelayTimer);
- inputDelayTimer = setTimeout(function() {
- setSearch($('term').value);
- }, 250);
+$('term').onsearch = function(e) {
+ setSearch(this.value);
};
/**
diff --git a/chrome/browser/resources/bug_report.css b/chrome/browser/resources/bug_report.css
index 07210b0..bbccf26 100644
--- a/chrome/browser/resources/bug_report.css
+++ b/chrome/browser/resources/bug_report.css
@@ -52,14 +52,14 @@ hr {
.image-thumbnail-container {
display: inline-block;
border: 2px solid white;
- -webkit-border-radius: 3px;
+ border-radius: 3px;
z-index: 0;
}
.image-thumbnail-container-selected {
display: inline-block;
border: 2px solid green;
- -webkit-border-radius: 3px;
+ border-radius: 3px;
z-index: 0;
}
diff --git a/chrome/browser/resources/chat_manager/128.png b/chrome/browser/resources/chat_manager/128.png
deleted file mode 100644
index 60db2ef..0000000
--- a/chrome/browser/resources/chat_manager/128.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/chat_manager/16.png b/chrome/browser/resources/chat_manager/16.png
deleted file mode 100644
index acd4e72..0000000
--- a/chrome/browser/resources/chat_manager/16.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/chat_manager/24.png b/chrome/browser/resources/chat_manager/24.png
deleted file mode 100644
index 7ce513e..0000000
--- a/chrome/browser/resources/chat_manager/24.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/chat_manager/32.png b/chrome/browser/resources/chat_manager/32.png
deleted file mode 100644
index d576c11..0000000
--- a/chrome/browser/resources/chat_manager/32.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/chat_manager/48.png b/chrome/browser/resources/chat_manager/48.png
deleted file mode 100644
index 2e4fb7c..0000000
--- a/chrome/browser/resources/chat_manager/48.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/chat_manager/_locales/en/messages.json b/chrome/browser/resources/chat_manager/_locales/en/messages.json
deleted file mode 100644
index d4788ae..0000000
--- a/chrome/browser/resources/chat_manager/_locales/en/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"chat_manager_name":{"message":"Google Talk"},"chat_manager_description":{"message":"Use Google Talk extension to chat with friends."},"chat_manager_could_not_connect":{"message":"Could not connect to Google Talk."},"chat_manager_retry_now":{"message":"Retry Now"},"chat_manager_retrying_in":{"message":"Retrying in $1:$2","placeholders":{"1":{"content":"$1"},"2":{"content":"$2"}}}}
diff --git a/chrome/browser/resources/chat_manager/background.html b/chrome/browser/resources/chat_manager/background.html
deleted file mode 100644
index ebb8a9a..0000000
--- a/chrome/browser/resources/chat_manager/background.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!DOCTYPE html>
-<html>
-<!--
-
-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.
-
-Extension purpose: route all Google Talk chats through the central roster
-hosted in this extension. The included logic is paired with logic in Gmail
-to route both incoming and outgoing chats through this central roster.
-
--->
-<body>
- <iframe id='centralRoster' src='central_roster.html'></iframe>
- <script src="js/chatbridgeeventtypes.js"></script>
- <script src="js/background.js"></script>
-</body>
-</html>
diff --git a/chrome/browser/resources/chat_manager/central_roster.html b/chrome/browser/resources/chat_manager/central_roster.html
deleted file mode 100644
index 30ace28..0000000
--- a/chrome/browser/resources/chat_manager/central_roster.html
+++ /dev/null
@@ -1,39 +0,0 @@
-<!DOCTYPE html>
-<html>
-<!--
-
-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.
-
-Central roster: hosting all Google Talk chats in ChromeOS.
-
--->
- <head>
- <style>
- .talk_roster,
- .talk_iframe {
- width: 100%;
- height: 100%;
- border: none;
- padding: 0px;
- overflow: hidden;
- }
- body {
- margin: 0px;
- padding: 0px;
- overflow: hidden;
- text-align: center;
- }
- </style>
- </head>
- <body onload='onPageLoaded()'>
- <div id='retryInfo' style='display:none'>
- <p id='retryMessage'></p>
- <p id='retryStatus'></p>
- <input id='retryButton' type='button' value='' onclick='retryConnection()'/>
- </div>
- <script src="js/centralroster.js"></script>
- </body>
-</html>
-
diff --git a/chrome/browser/resources/chat_manager/central_roster_viewer.html b/chrome/browser/resources/chat_manager/central_roster_viewer.html
deleted file mode 100644
index db91706..0000000
--- a/chrome/browser/resources/chat_manager/central_roster_viewer.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!DOCTYPE html>
-<html>
-<!--
-
-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.
-
--->
- <head>
- <style>
- iframe {
- width: 100%;
- height: 100%;
- border: none;
- padding: 0px;
- overflow: hidden;
- }
- body {
- margin: 0px;
- padding: 0px;
- overflow: hidden;
- }
- </style>
- </head>
- <body onload='reparentCentralRosterToWindow();'
- onbeforeunload='reparentCentralRosterToBackground(event);'>
- <!-- Place for central roster -->
- <script src="js/centralrosterviewer.js"></script>
- </body>
-</html>
-
diff --git a/chrome/browser/resources/chat_manager/js/background.js b/chrome/browser/resources/chat_manager/js/background.js
deleted file mode 100644
index 638a04b..0000000
--- a/chrome/browser/resources/chat_manager/js/background.js
+++ /dev/null
@@ -1,128 +0,0 @@
-// 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.
-
-var centralRosterJid;
-var centralRosterPort;
-var centralJidListenerPorts = [];
-
-// Notify all port listeners of an event.
-function forwardEventToPortListeners(evtType, chatJid) {
- var listenerPort;
- for (var portIndex in centralJidListenerPorts) {
- listenerPort = centralJidListenerPorts[portIndex];
- listenerPort.postMessage({eventType: evtType, jid: chatJid});
- }
-}
-
-// Notify all port listeners of updated central roster jid.
-function forwardCentralRosterJidToPortListeners() {
- forwardEventToPortListeners(
- ChatBridgeEventTypes.CENTRAL_USER_UPDATE, centralRosterJid);
-}
-
-// Central roster jid changed. Notify all listeners.
-function centralJidUpdate(msg) {
- if (centralRosterJid != msg.jid) {
- centralRosterJid = msg.jid;
- forwardCentralRosterJidToPortListeners();
- }
-}
-
-// Focus a chat popup.
-function focusMole(hostId) {
- findMole(hostId, function(win) {
- chrome.windows.update(win.id, {focused: true});
- });
-}
-
-// Find a chat popup from a chat's hostId and executes callback with it.
-function findMole(hostId, callback) {
- var matchUrlIdRegExp = new RegExp('[&?]id=' + hostId + '(&|$)', 'i');
- chrome.windows.getAll({populate: true}, function(wins) {
- for (var winIdx = 0, win = wins[winIdx]; win; win = wins[++winIdx]) {
- var tabs = win.tabs;
- for (var tabIdx = 0, tab = tabs[tabIdx]; tab; tab = tabs[++tabIdx]) {
- if ((tab.url).match(matchUrlIdRegExp)) {
- callback(win);
- return;
- }
- }
- }
- });
-}
-
-// Listen for content script connections.
-chrome.extension.onConnect.addListener(function(port) {
- // New central jid listener.
- // Update with current central roster jid, and add to tracking array.
- if (port.name == 'centralJidListener') {
- centralJidListenerPorts.push(port);
- port.postMessage({eventType: ChatBridgeEventTypes.CENTRAL_USER_UPDATE,
- jid: centralRosterJid});
-
- // Clear tracking array entry when content script closes.
- port.onDisconnect.addListener(function(port) {
- for (var index = 0; index < centralJidListenerPorts.length; ++index) {
- var listenerPort = centralJidListenerPorts[index];
- if (listenerPort == port) {
- centralJidListenerPorts.splice(index, 1);
- break;
- }
- }
- });
- // New central jid broadcaster.
- // Add listener for jid changes, and track port for forwarding chats.
- } else if (port.name == 'centralJidBroadcaster') {
- if (centralRosterPort != port) {
- if (centralRosterPort) {
- centralRosterPort.onMessage.removeListener(centralJidUpdate);
- }
- centralRosterPort = port;
- centralRosterPort.onMessage.addListener(centralJidUpdate);
-
- // Clear listener and central roster jid when content script closes
- centralRosterPort.onDisconnect.addListener(function(port) {
- if (centralRosterPort) {
- centralRosterPort.onMessage.removeListener(centralJidUpdate);
- centralRosterPort = null;
- centralJidUpdate({jid: null});
- }
- });
- }
- }
-});
-
-// Listen for requests from our content scripts.
-chrome.extension.onRequest.addListener(
- function(request, sender, sendResponse) {
- switch (request.msg) {
- case ChatBridgeEventTypes.CENTRAL_USER_WATCHER:
- sendResponse({jid: centralRosterJid});
- break;
- // For new initiated chats, forward to the central roster port.
- case ChatBridgeEventTypes.SHOW_CHAT:
- case ChatBridgeEventTypes.START_VIDEO:
- case ChatBridgeEventTypes.START_VOICE:
- if (centralRosterPort) {
- centralRosterPort.postMessage(
- {eventType: request.msg, jid: request.jid});
- } else {
- // We should not have been forwarded this message. Make sure our
- // listeners are updated with the current central roster jid.
- forwardCentralRosterJidToPortListeners();
- }
- break;
- case ChatBridgeEventTypes.OPENED_MOLE_INCOMING:
- forwardEventToPortListeners(ChatBridgeEventTypes.OPENED_MOLE_OUTGOING,
- request.jid);
- break;
- case ChatBridgeEventTypes.CLOSED_MOLE_INCOMING:
- forwardEventToPortListeners(ChatBridgeEventTypes.CLOSED_MOLE_OUTGOING,
- request.jid);
- break;
- case ChatBridgeEventTypes.MOLE_FOCUSED:
- focusMole(request.jid);
- break;
- }
-});
diff --git a/chrome/browser/resources/chat_manager/js/centralroster.js b/chrome/browser/resources/chat_manager/js/centralroster.js
deleted file mode 100644
index 449a3da..0000000
--- a/chrome/browser/resources/chat_manager/js/centralroster.js
+++ /dev/null
@@ -1,137 +0,0 @@
-// 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.
-
-var MIN_RETRY_MILLISECONDS = 1 * 1000;
-var MAX_RETRY_MILLISECONDS = 4 * 60 * 1000;
-var retryTime;
-var retryTimer;
-var chatClient = null;
-
-document.title = chrome.i18n.getMessage('CHAT_MANAGER_NAME');
-var args = {
- 'protocol': 'https',
- 'host': 'talkgadget.google.com',
- 'jsmode': 'pre',
- 'hl': chrome.i18n.getMessage('@@ui_locale')
-};
-
-// Read args.
-var urlParts = window.location.href.split(/[?&#]/);
-for (var i = 1; i < urlParts.length; i++) {
- var argParts = urlParts[i].split('=');
- if (argParts.length == 2) {
- args[argParts[0]] = argParts[1];
- }
-}
-var notifierScriptUrl =
- args['protocol'] + '://' + args['host'] +
- '/talkgadget/notifier-js?silent=true&host=' +
- args['protocol'] + '://' + args['host'] +
- '/talkgadget/notifier-js' +
- (args['jsmode'] != '' ? ('&jsmode=' + args['jsmode']) : '');
-
-// Implement Singleton pattern, where there is only one central roster.
-function makeSingleton() {
- // This will keep a list of all central roster panels.
- var chat_popups = [];
-
- chrome.windows.getAll({populate: true}, function(wins) {
- // Find and remember all central roster panels.
- for (var winIdx = 0, win = wins[winIdx]; win; win = wins[++winIdx]) {
- var tabs = win.tabs;
- for (var tabIdx = 0, tab = tabs[tabIdx]; tab; tab = tabs[++tabIdx]) {
- if (tab.url === location.href) {
- chat_popups.push({tabId: tab.id, winId: win.id});
- }
- }
- }
- if (chat_popups.length > 0) {
- // Multiple panels are executing this function at the same time so we need
- // a global criteria to pickup a "winner": "keep only the tab with
- // smallest id".
- chat_popups.sort(function(t1, t2) { return t1.tabId - t2.tabId; });
- for (var i = 0, l = chat_popups.length; i < l; i++) {
- if (i == 0) {
- chrome.windows.update(chat_popups[i].winId, {focused: true});
- } else {
- chrome.tabs.remove(chat_popups[i].tabId);
- }
- }
- }
- });
-}
-makeSingleton();
-
-function runGTalkScript() {
- var script = document.createElement('script');
- script.src = notifierScriptUrl;
- script.onload = loadGTalk;
- script.onerror = loadGTalk;
- document.body.appendChild(script);
-}
-
-function retryConnection() {
- location.reload();
-}
-
-function retryConnectionCountdown() {
- var seconds = retryTime / 1000;
- var minutes = Math.floor(seconds / 60);
- seconds -= minutes * 60;
-
- document.getElementById('retryStatus').textContent =
- chrome.i18n.getMessage('CHAT_MANAGER_RETRYING_IN',
- [minutes, (seconds < 10 ? '0' : '') + seconds]);
-
- if (retryTime <= 0) {
- retryConnection();
- } else {
- retryTimer = setTimeout(retryConnectionCountdown, 1000);
- retryTime -= 1000;
- }
-}
-
-function loadGTalk() {
- if (window.GTalkNotifier) {
- document.getElementById('retryInfo').style.display = 'none';
- var baseUrl = args['protocol'] + '://' + args['host'] + '/talkgadget/';
- chatClient = new window.GTalkNotifier(
- {
- 'clientBaseUrl': baseUrl,
- 'clientUrl': 'notifierclient' +
- (args['jsmode'] != '' ? ('?jsmode=' + args['jsmode']) : ''),
- 'propertyName': 'ChromeOS',
- 'xpcRelay': baseUrl + 'xpc_relay',
- 'xpcBlank': baseUrl + 'xpc_blank',
- 'locale': args['hl'],
- 'isCentralRoster': true,
- 'hideProfileCard': true,
- 'isFullFrame': true
- }
- );
- delete localStorage.retryStartTime;
- } else {
- if (!localStorage.retryStartTime) {
- localStorage.retryStartTime = MIN_RETRY_MILLISECONDS;
- } else if (localStorage.retryStartTime < MAX_RETRY_MILLISECONDS) {
- localStorage.retryStartTime = Math.min(localStorage.retryStartTime * 2,
- MAX_RETRY_MILLISECONDS);
- }
- retryTime = localStorage.retryStartTime;
- document.getElementById('retryInfo').style.display = 'inline';
- retryConnectionCountdown();
- }
-}
-
-function onPageLoaded() {
- // Localizing the page content.
- document.getElementById('retryMessage').textContent =
- chrome.i18n.getMessage('CHAT_MANAGER_COULD_NOT_CONNECT');
- document.getElementById('retryButton').value =
- chrome.i18n.getMessage('CHAT_MANAGER_RETRY_NOW');
-
- if (localStorage.hasOpenedInViewer) {
- runGTalkScript();
- }
-}
diff --git a/chrome/browser/resources/chat_manager/js/centralrosterviewer.js b/chrome/browser/resources/chat_manager/js/centralrosterviewer.js
deleted file mode 100644
index 0229a68..0000000
--- a/chrome/browser/resources/chat_manager/js/centralrosterviewer.js
+++ /dev/null
@@ -1,61 +0,0 @@
-// 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.
-
-document.title = chrome.i18n.getMessage('CHAT_MANAGER_NAME');
-
-function reparentCentralRosterToWindow() {
- var backgroundWindow = chrome.extension.getBackgroundPage();
- if (backgroundWindow) {
- var backgroundDocument = backgroundWindow.document;
- var iframe = backgroundDocument.getElementById('centralRoster');
- if (iframe) {
- if ((new Date().getTime() - localStorage.rosterClosed) < 500) {
- // If the 'unload' is followed by 'load' in less than 0.5 seconds
- // we assume it is a page refresh and the user wants to restart the app.
- iframe.parentNode.removeChild(iframe);
- iframe = backgroundDocument.createElement('iframe');
- iframe.id ='centralRoster';
- iframe.src ='central_roster.html';
- }
- if (document.adoptNode) {
- document.adoptNode(iframe);
- }
- document.body.appendChild(iframe);
-
- if (!localStorage.hasOpenedInViewer) {
- // This is the first time the user started the app, so we'll remember
- // the event, check if the centralRoster frame has already been loaded
- // and start the app and that case.
- localStorage.hasOpenedInViewer = true;
- if (iframe.contentWindow.runGTalkScript) {
- iframe.contentWindow.runGTalkScript();
- }
- }
- } else {
- // If there in no centralRoster frame in background page, this must be
- // a second panel trying to load the central roster.
- window.close();
- }
- }
-}
-
-function reparentCentralRosterToBackground(event) {
- // We'll remember when was the last time the central roster panel closes
- // in order to detect if it is a close on reload action.
- localStorage.rosterClosed = new Date().getTime();
-
- if (document) {
- var iframe = document.getElementById('centralRoster');
- if (iframe) {
- var backgroundWindow = chrome.extension.getBackgroundPage();
- if (backgroundWindow) {
- var backgroundDocument = backgroundWindow.document;
- if (backgroundDocument.adoptNode) {
- backgroundDocument.adoptNode(iframe);
- }
- backgroundDocument.body.appendChild(iframe);
- }
- }
- }
-}
diff --git a/chrome/browser/resources/chat_manager/js/chatbridgeeventtypes.js b/chrome/browser/resources/chat_manager/js/chatbridgeeventtypes.js
deleted file mode 100644
index 3397115..0000000
--- a/chrome/browser/resources/chat_manager/js/chatbridgeeventtypes.js
+++ /dev/null
@@ -1,23 +0,0 @@
-// 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.
-
-/**
- * Chat bridge event types.
- * @enum {string}
- */
-var ChatBridgeEventTypes = {
- SHOW_CHAT: 'showChat',
- START_VIDEO: 'startVideo',
- NEW_VIDEO_CHAT: 'newVideoChat',
- START_VOICE: 'startVoice',
- NEW_VOICE_CHAT: 'newVoiceChat',
- CENTRAL_USER_SET: 'centralJidSet',
- CENTRAL_USER_UPDATE: 'centralJidUpdate',
- CENTRAL_USER_WATCHER: 'getCentralJid',
- OPENED_MOLE_INCOMING: 'onMoleOpened',
- OPENED_MOLE_OUTGOING: 'onCentralMoleOpened',
- CLOSED_MOLE_INCOMING: 'onMoleClosed',
- CLOSED_MOLE_OUTGOING: 'onCentralMoleClosed',
- MOLE_FOCUSED: '*mfo'
-};
diff --git a/chrome/browser/resources/chat_manager/js/chatbridgehook.js b/chrome/browser/resources/chat_manager/js/chatbridgehook.js
deleted file mode 100644
index 9549a83..0000000
--- a/chrome/browser/resources/chat_manager/js/chatbridgehook.js
+++ /dev/null
@@ -1,159 +0,0 @@
-// 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.
-
-// Port used for:
-// 1. forwarding updated central user from the chat page to the background.
-// 2. forwarding chats from the background to the chat page we're attached to.
-var centralJidBroadcasterPort;
-
-// Port used for:
-// 1. forwarding central user requests from the chat page to the background.
-// 2. forwarding the central user from the background to the chat page.
-var centralJidListenerChatPort;
-
-// The chat page div used to funnel events through.
-var divRosterHandler;
-
-// The current central roster Jid.
-// Requested and cached as early as possible.
-var centralRosterJid;
-
-/**
- * Triggered on a user initiated chat request. Forward to extension to be
- * processed by the Chrome central roster.
- * @param {MessageEvent} event the new chat event.
- */
-function forwardChatEvent(event) {
- var eventType = event.type;
- switch (event.type) {
- case ChatBridgeEventTypes.NEW_VIDEO_CHAT:
- eventType = ChatBridgeEventTypes.START_VIDEO;
- break;
- case ChatBridgeEventTypes.NEW_VOICE_CHAT:
- eventType = ChatBridgeEventTypes.START_VOICE;
- break;
- }
- var chatJid = event.data;
- if (!centralJidBroadcasterPort) {
- chrome.extension.sendRequest({msg: eventType, jid: chatJid});
- } else {
- dispatchChatEvent(eventType, chatJid);
- }
-}
-
-/**
- * Forward mole events to extension.
- * Triggered on opening/closing/focus a central roster chat.
- * @param {MessageEvent} event the opened/closed event.
- */
-function forwardMoleEvent(event) {
- var eventType = event.type;
- var chatJid = event.data;
- chrome.extension.sendRequest({msg: eventType, jid: chatJid});
-}
-
-/**
- * Manage two-way communication with the central roster. Updated jid's are
- * forwarded to the background, while chats are forwarded to the page.
- * @param {string} eventType the event type.
- * @param {string} chatJid the jid to route the chat event to.
- */
-function dispatchChatEvent(eventType, chatJid) {
- var chatEvent = document.createEvent('MessageEvent');
- chatEvent.initMessageEvent(eventType, true, true, chatJid);
- divRosterHandler.dispatchEvent(chatEvent);
-}
-
-/**
- * Forward central roster Jid to page.
- * @param {string} jid the central roster Jid.
- */
-function dispatchCentralJid(jid) {
- dispatchChatEvent(ChatBridgeEventTypes.CENTRAL_USER_UPDATE, jid);
-}
-
-/**
- * Manage two-way communication with the central roster. Updated jid's are
- * forwarded to the background, while chats are forwarded to the page.
- * @param {MessageEvent} event the new central roster jid event.
- */
-function centralRosterHandler(event) {
- if (!centralJidBroadcasterPort) {
- centralJidBroadcasterPort = chrome.extension.connect(
- {name: 'centralJidBroadcaster'});
- centralJidBroadcasterPort.onMessage.addListener(function(msg) {
- dispatchChatEvent(msg.eventType, msg.jid);
- });
- }
- centralRosterJid = event.data;
- centralJidBroadcasterPort.postMessage({jid: centralRosterJid});
-}
-
-/**
- * Setup central roster jid listener.
- * @param {MessageEvent} event the event.
- */
-function setupCentralRosterJidListener(event) {
- if (!centralJidListenerChatPort) {
- if (centralRosterJid) {
- dispatchCentralJid(centralRosterJid);
- }
- centralJidListenerChatPort = chrome.extension.connect(
- {name: 'centralJidListener'});
- centralJidListenerChatPort.onMessage.addListener(function(msg) {
- if (msg.eventType == ChatBridgeEventTypes.CENTRAL_USER_UPDATE) {
- centralRosterJid = msg.jid;
- }
- dispatchChatEvent(msg.eventType, msg.jid);
- });
- }
-}
-
-/**
- * When the page loads, search for the communication channel div.
- */
-function onPageLoaded() {
- divRosterHandler = document.getElementById('roster_comm_link');
- if (divRosterHandler) {
- divRosterHandler.addEventListener(
- ChatBridgeEventTypes.SHOW_CHAT,
- forwardChatEvent, false);
- divRosterHandler.addEventListener(
- ChatBridgeEventTypes.NEW_VIDEO_CHAT,
- forwardChatEvent, false);
- divRosterHandler.addEventListener(
- ChatBridgeEventTypes.NEW_VOICE_CHAT,
- forwardChatEvent, false);
- divRosterHandler.addEventListener(
- ChatBridgeEventTypes.CENTRAL_USER_SET,
- centralRosterHandler, false);
- divRosterHandler.addEventListener(
- ChatBridgeEventTypes.CENTRAL_USER_WATCHER,
- setupCentralRosterJidListener, false);
- divRosterHandler.addEventListener(
- ChatBridgeEventTypes.OPENED_MOLE_INCOMING,
- forwardMoleEvent, false);
- divRosterHandler.addEventListener(
- ChatBridgeEventTypes.CLOSED_MOLE_INCOMING,
- forwardMoleEvent, false);
- divRosterHandler.addEventListener(
- ChatBridgeEventTypes.MOLE_FOCUSED,
- forwardMoleEvent, false);
- }
-}
-
-// Retrieve the initial central roster Jid and cache the result.
-chrome.extension.sendRequest(
- {msg: ChatBridgeEventTypes.CENTRAL_USER_WATCHER}, function(response) {
- centralRosterJid = response.jid;
-
- // The initial centralRosterJid is sent in setupCentralRosterJidListener,
- // but if it's already been called, send it here.
- if (centralJidListenerChatPort && centralRosterJid) {
- dispatchCentralJid(centralRosterJid);
- }
- }
-);
-
-window.addEventListener("load", onPageLoaded, false);
diff --git a/chrome/browser/resources/chat_manager/js/gmailbridgehook.js b/chrome/browser/resources/chat_manager/js/gmailbridgehook.js
deleted file mode 100644
index 2cb9041..0000000
--- a/chrome/browser/resources/chat_manager/js/gmailbridgehook.js
+++ /dev/null
@@ -1,100 +0,0 @@
-// 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.
-
-// Port used for:
-// 1. forwarding central user requests from the gmail page to the background.
-// 2. forwarding the central user from the background to the gmail page.
-var centralJidListenerGmailPort;
-
-// The gmail page div used to funnel events through.
-var divGmailHandler;
-
-// The current central roster Jid.
-// Requested and cached as early as possible.
-var centralRosterJid;
-
-/**
- * Triggered on a user initiated chat request. Forward to extension to be
- * processed by the Chrome central roster.
- * @param {MessageEvent} event the new chat event.
- */
-function forwardChatEvent(event) {
- var chatJid = event.data;
- chrome.extension.sendRequest({msg: event.type, jid: chatJid});
-}
-
-/**
- * @param {string} eventType the event type.
- * @param {string} chatJid the jid to route the chat event to.
- * TODO(seh): Move into a common JS file and reference from chatbridgehook.js.
- */
-function dispatchChatEvent(eventType, chatJid) {
- var chatEvent = document.createEvent('MessageEvent');
- chatEvent.initMessageEvent(eventType, true, true, chatJid);
- divGmailHandler.dispatchEvent(chatEvent);
-}
-
-/**
- * Forward central roster Jid to page.
- * @param {string} jid the central roster Jid.
- */
-function dispatchCentralJid(jid) {
- dispatchChatEvent(ChatBridgeEventTypes.CENTRAL_USER_UPDATE, jid);
-}
-
-/**
- * Setup central roster jid listener.
- * @param {MessageEvent} event the event.
- */
-function setupCentralRosterJidListener(event) {
- if (!centralJidListenerGmailPort) {
- if (centralRosterJid) {
- dispatchCentralJid(centralRosterJid);
- }
- centralJidListenerGmailPort = chrome.extension.connect(
- {name: 'centralJidListener'});
- centralJidListenerGmailPort.onMessage.addListener(function(msg) {
- if (msg.eventType == ChatBridgeEventTypes.CENTRAL_USER_UPDATE) {
- centralRosterJid = msg.jid;
- }
- dispatchChatEvent(msg.eventType, msg.jid);
- });
- }
-}
-
-/**
- * When the page loads, search for the communication channel div.
- */
-function onPageLoaded() {
- divGmailHandler = document.getElementById('mainElement');
- if (divGmailHandler) {
- divGmailHandler.addEventListener(
- ChatBridgeEventTypes.SHOW_CHAT,
- forwardChatEvent, false);
- divGmailHandler.addEventListener(
- ChatBridgeEventTypes.START_VIDEO,
- forwardChatEvent, false);
- divGmailHandler.addEventListener(
- ChatBridgeEventTypes.START_VOICE,
- forwardChatEvent, false);
- divGmailHandler.addEventListener(
- ChatBridgeEventTypes.CENTRAL_USER_WATCHER,
- setupCentralRosterJidListener, false);
- }
-}
-
-// Retrieve the initial central roster Jid and cache the result.
-chrome.extension.sendRequest(
- {msg: ChatBridgeEventTypes.CENTRAL_USER_WATCHER}, function(response) {
- centralRosterJid = response.jid;
-
- // The initial centralRosterJid is sent in setupCentralRosterJidListener,
- // but if it's already been called, send it here.
- if (centralJidListenerGmailPort && centralRosterJid) {
- dispatchCentralJid(centralRosterJid);
- }
- }
-);
-
-window.addEventListener("load", onPageLoaded, false);
diff --git a/chrome/browser/resources/chat_manager/manifest.json b/chrome/browser/resources/chat_manager/manifest.json
deleted file mode 100644
index 442a46d..0000000
--- a/chrome/browser/resources/chat_manager/manifest.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDrlwvcbUtVrbQvI7EPV1BTa63N8YkbBToHzxlMl0IzSBwOV+TUOsHE8vRq0HZWuwMAGeH8WdWVC3HRNdES8lScjlzxb1TsTQJAsF+hLXgcjgCUSSSGCfFzypvuvKsRQTx0d02yfWKJa47o0Ws5wL72NVtc7c51HujwWYg+Mz01wIDAQAB",
- "name": "__MSG_CHAT_MANAGER_NAME__",
- "version": "1.0.19",
- "icons": {
- "128": "128.png",
- "16": "16.png",
- "24": "24.png",
- "32": "32.png",
- "48": "48.png"
- },
- "description": "__MSG_CHAT_MANAGER_DESCRIPTION__",
- "default_locale": "en",
- "background_page": "background.html",
- "options_page": "options.html",
- "content_scripts": [ {
- "js": [
- "js/chatbridgeeventtypes.js",
- "js/chatbridgehook.js"
- ],
- "matches": [
- "*://talkgadget.google.com/*"
- ],
- "run_at": "document_start",
- "all_frames": true
- },{
- "js": [
- "js/chatbridgeeventtypes.js",
- "js/gmailbridgehook.js"
- ],
- "matches": [
- "*://mail.google.com/*"
- ],
- "run_at": "document_start"
- }],
- "permissions": [
- "tabs",
- "*://talkgadget.google.com/*"
- ],
- "app": {
- "launch": {
- "local_path": "central_roster_viewer.html",
- "container": "panel",
- "width": 225,
- "height": 316
- }
- }
-}
diff --git a/chrome/browser/resources/chat_manager/options.html b/chrome/browser/resources/chat_manager/options.html
deleted file mode 100644
index 3f21ff4..0000000
--- a/chrome/browser/resources/chat_manager/options.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<html>
-<head>
- <meta HTTP-EQUIV="REFRESH" content="0; url=https://mail.google.com/mail/?view=pu&fs=1&ui=2&st=chat">
-</head>
-</html>
diff --git a/chrome/browser/resources/dom_ui.css b/chrome/browser/resources/dom_ui.css
index 9eba4bc..d1eab85 100644
--- a/chrome/browser/resources/dom_ui.css
+++ b/chrome/browser/resources/dom_ui.css
@@ -16,7 +16,7 @@ body {
.header .form {
float:left;
margin-top:22px;
- margin-left:12px;
+ -webkit-margin-start:12px;
}
html[dir='rtl'] .logo {
@@ -25,13 +25,12 @@ html[dir='rtl'] .logo {
html[dir='rtl'] .form {
float:right;
- margin-right:12px;
}
.page-navigation {
padding:8px;
background-color:#ebeff9;
- margin-right:4px;
+ -webkit-margin-end:4px;
}
.footer {
diff --git a/chrome/browser/resources/dom_ui2.css b/chrome/browser/resources/dom_ui2.css
index 13e3756..49205f8 100644
--- a/chrome/browser/resources/dom_ui2.css
+++ b/chrome/browser/resources/dom_ui2.css
@@ -13,14 +13,13 @@ body {
.header .form {
float:left;
margin-top:22px;
- margin-left:12px;
+ -webkit-margin-start:12px;
}
html[dir='rtl'] .logo {
float:right;
}
html[dir='rtl'] .form {
float:right;
- margin-right:12px;
}
.page-navigation {
padding:8px;
@@ -29,4 +28,4 @@ html[dir='rtl'] .form {
}
.footer {
height:24px;
-} \ No newline at end of file
+}
diff --git a/chrome/browser/resources/downloads.html b/chrome/browser/resources/downloads.html
index 834d06f..013da50 100644
--- a/chrome/browser/resources/downloads.html
+++ b/chrome/browser/resources/downloads.html
@@ -23,18 +23,13 @@ body {
.header .form {
float: left;
margin-top: 22px;
- margin-left: 12px;
+ -webkit-margin-start: 12px;
}
-html[dir=rtl] .logo {
+html[dir=rtl] .logo, html[dir=rtl] .form {
float: right;
}
-html[dir=rtl] .form {
- float: right;
- margin-right: 12px;
-}
-
#downloads-summary {
margin-top: 12px;
border-top: 1px solid #9cc2ef;
@@ -62,18 +57,11 @@ html[dir=rtl] #downloads-summary > a {
.download {
position: relative;
margin-top: 6px;
- margin-left: 114px;
- padding-left: 56px;
+ -webkit-margin-start: 114px;
+ -webkit-padding-start: 56px;
margin-bottom: 15px;
}
-html[dir=rtl] .download {
- padding-left: 0px;
- margin-left: 0px;
- margin-right: 114px;
- padding-right: 56px;
-}
-
.date-container {
position: absolute;
left: -110px;
@@ -146,16 +134,11 @@ html[dir=rtl] .progress {
.name {
display: none;
- padding-right: 16px;
+ -webkit-padding-end: 16px;
max-width: 450px;
word-break: break-all;
}
-html[dir=rtl] .name {
- padding-right: 0px;
- padding-left: 16px;
-}
-
.download .status {
display: inline;
color: #999;
diff --git a/chrome/browser/resources/extensions_ui.html b/chrome/browser/resources/extensions_ui.html
index 9b090f2..e5f3976 100644
--- a/chrome/browser/resources/extensions_ui.html
+++ b/chrome/browser/resources/extensions_ui.html
@@ -20,14 +20,10 @@ div#header {
min-height: 67px;
overflow: hidden;
padding-bottom: 20px;
- padding-left: 0;
+ -webkit-padding-start: 0;
padding-top: 20px;
position: relative;
- -webkit-box-sizing: border-box;
-}
-
-html[dir=rtl] #header {
- padding-right: 0;
+ box-sizing: border-box;
}
#header h1 {
@@ -62,16 +58,11 @@ div.content {
border-top: 1px solid #b5c7de;
font-size: 99%;
padding-bottom: 2px;
- padding-left: 5px;
+ -webkit-padding-start: 5px;
padding-top: 3px;
width: 100%;
}
-html[dir=rtl] .section-header {
- padding-right: 5px;
- padding-left: 0;
-}
-
.section-header-title {
font-weight: bold;
}
@@ -134,14 +125,10 @@ body.showDevMode .showInDevMode {
border-bottom: 1px solid #edeff5;
font-size: 89%;
padding-bottom: 0.8em;
- padding-left: 10px;
+ -webkit-padding-start: 10px;
padding-top: 0.8em;
width: 100%;
}
-html[dir=rtl] .developer-mode {
- padding-right: 10px;
- padding-left: 0;
-}
.extension_disabled td {
background-color: #f0f0f0;
@@ -265,7 +252,7 @@ html[dir=rtl] #dialogBackground {
border: 1px solid #3A75BD;
border-radius: 6px 6px;
font-size: 12px;
- width: 500px;
+ width: 520px;
-webkit-box-orient: vertical;
}
@@ -298,32 +285,22 @@ html[dir=rtl] #dialogHeader {
}
.dialogBrowseRow {
- margin-left: -24px;
+ -webkit-margin-start: -24px;
width: 100%;
-webkit-box-orient: horizontal;
-webkit-box-pack: end;
}
-html[dir=rtl] .dialogBrowseRow {
- margin-right: -24px;
- /* margin-left: 0px; */
-}
-
.dialogBrowseRow>* {
margin: 2px
}
#dialogContentFooter {
margin-bottom: 6px;
- margin-left: -12px;
+ -webkit-margin-start: -12px;
margin-top: 20px;
}
-html[dir=rtl] #dialogContentFooter {
- margin-right: -12px;
- margin-left: 0px;
-}
-
.inspectPopupNote {
color: grey;
}
diff --git a/chrome/browser/resources/filebrowse.html b/chrome/browser/resources/filebrowse.html
index 7cccf3f..f6a5050 100644
--- a/chrome/browser/resources/filebrowse.html
+++ b/chrome/browser/resources/filebrowse.html
@@ -14,7 +14,6 @@ div.header {
top: 0;
height: 32px;
position: absolute;
- -webkit-box-sizing: border-box;
box-sizing: border-box;
background-image: -webkit-gradient(linear,
left top,
@@ -407,21 +406,6 @@ div.scanningcontainer {
height: 100%;
}
-div.filebutton {
- height: 18px;
- cursor: pointer;
- padding: 5px 15px 2px;
- border: 1px solid #abb6ce;
- background-image: -webkit-gradient(linear,
- left top,
- left bottom,
- color-stop(0.80, #fcfcfc),
- color-stop(0.97, #e3e3e3));
- border-radius: 3px;
- text-align: center;
- font-size: .8em;
-}
-
.filenameprompt {
top: 8px;
left: 13px;
@@ -438,18 +422,21 @@ div.filebutton {
position: absolute;
}
-div.openbutton {
- bottom: 3px;
- right: 100px;
+div.buttonscontainer {
+ display: -webkit-box;
+ bottom: 0;
+ right: 10px;
position: absolute;
- width: 50px;
+}
+
+div.openbutton {
+ min-width: 50px;
+ margin: 3px;
}
div.cancelbutton {
- bottom: 3px;
- right: 10px;
- position: absolute;
- width: 50px;
+ min-width: 50px;
+ margin: 3px;
}
div.newfolderbutton {
@@ -698,16 +685,21 @@ function enabledResult(info) {
var savemenu = document.createElement('div');
savemenu.className = 'savecontainer';
- var savebutton = document.createElement('div');
+ // The container is used for placing buttons horizontally.
+ var buttonsContainer = document.createElement('div');
+ buttonsContainer.className = 'buttonscontainer';
+ savemenu.appendChild(buttonsContainer);
+
+ var savebutton = document.createElement('button');
savebutton.id = 'savebutton';
- savebutton.className = 'filebutton openbutton disabled';
+ savebutton.className = 'openbutton disabled';
savebutton.onclick = dialogSaveClick;
savebutton.textContent = localStrings.getString('save');
- savemenu.appendChild(savebutton);
+ buttonsContainer.appendChild(savebutton);
- var cancelbutton = document.createElement('div');
- cancelbutton.className = 'filebutton cancelbutton';
- savemenu.appendChild(cancelbutton);
+ var cancelbutton = document.createElement('button');
+ cancelbutton.className = 'cancelbutton';
+ buttonsContainer.appendChild(cancelbutton);
cancelbutton.textContent = localStrings.getString('confirmcancel');
cancelbutton.onclick = dialogCancelClick;
@@ -727,25 +719,28 @@ function enabledResult(info) {
filename.value = args.current_file;
savemenu.appendChild(filename);
if (advancedEnabled) {
- var newfolderbutton = document.createElement('div');
+ var newfolderbutton = document.createElement('button');
newfolderbutton.id = 'newfolderbutton';
- newfolderbutton.className = 'filebutton newfolderbutton disabled';
+ newfolderbutton.className = 'newfolderbutton disabled';
newfolderbutton.textContent = localStrings.getString('newfolder');
newfolderbutton.onclick = dialogNewFolderClick;
savemenu.appendChild(newfolderbutton);
}
document.body.appendChild(savemenu);
+ // Give focus to the save button. This has to be done after the
+ // parent node is added to document.body.
+ savebutton.focus();
} else {
var main = mainColumn;
main.className = 'containerwithopenbuttons';
var openmenu = document.createElement('div');
openmenu.className = 'opencontainer';
- var openbutton = document.createElement('div');
+ var openbutton = document.createElement('button');
openbutton.id = 'openbutton';
- openbutton.className = 'filebutton openbutton disabled';
- var cancelbutton = document.createElement('div');
- cancelbutton.className = 'filebutton cancelbutton';
+ openbutton.className = 'openbutton disabled';
+ var cancelbutton = document.createElement('button');
+ cancelbutton.className = 'cancelbutton';
openmenu.appendChild(openbutton);
openbutton.onclick = dialogOkClick;
openmenu.appendChild(cancelbutton);
@@ -943,26 +938,26 @@ function getDataForPath(path) {
if (inSaveMode) {
if (advancedEnabled) {
var newfolderbutton = $('newfolderbutton');
- newfolderbutton.className = 'filebutton newfolderbutton disabled';
+ newfolderbutton.className = 'newfolderbutton disabled';
}
var savebutton = $('savebutton');
- savebutton.className = 'filebutton openbutton disabled';
+ savebutton.className = 'openbutton disabled';
} else if (inSelectMode) {
var openbutton = $('openbutton');
- openbutton.className = 'filebutton openbutton disabled';
+ openbutton.className = 'openbutton disabled';
}
chrome.send('getRoots', []);
} else {
if (inSaveMode) {
if (advancedEnabled) {
var newfolderbutton = $('newfolderbutton');
- newfolderbutton.className = 'filebutton newfolderbutton';
+ newfolderbutton.className = 'newfolderbutton';
}
var savebutton = $('savebutton');
- savebutton.className = 'filebutton openbutton';
+ savebutton.className = 'openbutton';
} else if (inSelectMode) {
var openbutton = $('openbutton');
- openbutton.className = 'filebutton openbutton';
+ openbutton.className = 'openbutton';
}
chrome.send('getChildren', [path]);
}
diff --git a/chrome/browser/resources/flags.html b/chrome/browser/resources/flags.html
index 9798c82..5090084 100644
--- a/chrome/browser/resources/flags.html
+++ b/chrome/browser/resources/flags.html
@@ -22,7 +22,7 @@ div#header {
padding-left: 0;
padding-top: 20px;
position: relative;
- -webkit-box-sizing: border-box;
+ box-sizing: border-box;
}
html[dir=rtl] #header {
@@ -176,7 +176,15 @@ var flagsExperimentsDataFormat = {
'internal_name': 'Experiment ID string',
'name': 'Experiment Name',
'description': 'description',
- 'enabled': true
+ 'enabled': true,
+ /* choices is only set if the experiment has multiple values */
+ 'choices': [
+ {
+ 'internal_name': 'Experiment ID string',
+ 'description': 'description',
+ 'selected': true
+ }
+ ]
}
],
'needsRestart': false
@@ -231,6 +239,17 @@ function handleEnableExperiment(node, enable) {
requestFlagsExperimentsData();
}
+/**
+ * Invoked when the selection of a multi-value choice is changed to the
+ * specified index.
+ */
+function handleSelectChoiceExperiment(node, index) {
+ // Tell the C++ FlagsDOMHandler to enable the selected choice.
+ chrome.send('enableFlagsExperiment',
+ [String(node.internal_name) + "@" + index, "true"]);
+ requestFlagsExperimentsData();
+}
+
// Get data and have it displayed upon loading.
document.addEventListener('DOMContentLoaded', requestFlagsExperimentsData);
@@ -282,6 +301,15 @@ document.addEventListener('DOMContentLoaded', requestFlagsExperimentsData);
<div>
<span dir="ltr" jsvalues=".innerHTML:description">
</div>
+ <div jsdisplay="choices && choices.length > 0">
+ <select jsvalues=".internal_name:internal_name;.disabled:!enabled"
+ onchange="handleSelectChoiceExperiment(this, this.selectedIndex)">
+ <option jsvalues=".selected:selected"
+ jsselect="choices"
+ jscontent="description">NAME
+ </option>
+ </select>
+ </div>
</div>
</div>
<div class="experiment-actions">
diff --git a/chrome/browser/resources/gpu_blacklist.json b/chrome/browser/resources/gpu_blacklist.json
index 2720a6d..188fead 100644
--- a/chrome/browser/resources/gpu_blacklist.json
+++ b/chrome/browser/resources/gpu_blacklist.json
@@ -1,8 +1,8 @@
{
"name": "gpu blacklist",
- "version": "0.7",
+ "version": "0.1",
"entries": [
- { // ATI Radeon X1900 on Mac, BUGWEBKIT=47028
+ { // ATI Radeon X1900 on Mac
"os": {
"type": "macosx"
},
@@ -11,70 +11,6 @@
"blacklist": [
"webgl"
]
- },
- { // Intel Corporation Mobile 4 Series Chipset Integrated Graphics Controller, BUG=67345,67939
- "os": {
- "type": "linux"
- },
- "vendor_id": "0x8086",
- "device_id": "0x2a42",
- "blacklist": [
- "webgl"
- ]
- },
- { // Intel Corporation Core Processor Integrated Graphics Controller, BUG=66718
- "os": {
- "type": "linux"
- },
- "vendor_id": "0x8086",
- "device_id": "0x0046",
- "blacklist": [
- "webgl"
- ]
- },
- { // Intel Mobile 945 Express Chipset Family
- "os": {
- "type": "any"
- },
- "vendor_id": "0x8086",
- "device_id": "0x27AE",
- "blacklist": [
- "webgl"
- ]
- },
- { // All ATI cards in linux, BUG=71381
- "id": "5",
- "os": {
- "type": "linux"
- },
- "vendor_id": "0x1002",
- "blacklist": [
- "webgl"
- ]
- },
- { // ATI Radeon HD2600 on Mac, BUG=68859
- "id": "6",
- "os": {
- "type": "macosx"
- },
- "vendor_id": "0x1002",
- "device_id": "0x9583",
- "blacklist": [
- "webgl",
- "accelerated_compositing"
- ]
- },
- { // ATI Radeon HD2400 on Mac, BUG=68859
- "id": "7",
- "os": {
- "type": "macosx"
- },
- "vendor_id": "0x1002",
- "device_id": "0x94c8",
- "blacklist": [
- "webgl",
- "accelerated_compositing"
- ]
}
]
}
diff --git a/chrome/browser/resources/gpu_internals.html b/chrome/browser/resources/gpu_internals.html
new file mode 100644
index 0000000..9b3fb86
--- /dev/null
+++ b/chrome/browser/resources/gpu_internals.html
@@ -0,0 +1,91 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+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.
+-->
+<head i18n-values="dir:textdirection;">
+<link rel="stylesheet" href="dom_ui.css">
+<link rel="stylesheet" href="net_internals/tabswitcherview.css">
+<style>
+* {
+ box-sizing: border-box;
+}
+body {
+ font-family: sans-serif;
+}
+</style>
+<link rel="stylesheet" href="gpu_internals/info_view.css">
+<script src="chrome://resources/js/cr.js"></script>
+<script src="net_internals/util.js"></script>
+<script src="net_internals/view.js"></script>
+<script src="net_internals/tabswitcherview.js"></script>
+<script src="gpu_internals/browser_bridge.js"></script>
+<script src="gpu_internals/info_view.js"></script>
+
+
+<script>
+var browser = null;
+
+/**
+ * Main entry point. called once the page has loaded.
+ */
+function onLoad() {
+ browserBridge = new gpu.BrowserBridge();
+
+ // Create a view which will display general information
+ // about the gpu.
+ var infoView = new gpu.InfoView('info-view');
+
+ // Create a view which lets you tab between the different sub-views.
+ var categoryTabSwitcher =
+ new TabSwitcherView('category-tab-handles');
+
+ // Populate the main tabs.
+ categoryTabSwitcher.addTab('info-tab', infoView, false);
+
+ // Build a map from the anchor name of each tab handle to its 'tab ID'.
+ // We will consider navigations to the #hash as a switch tab request.
+ var anchorMap = {};
+ var tabIds = categoryTabSwitcher.getAllTabIds();
+ for (var i = 0; i < tabIds.length; i++) {
+ var aNode = document.getElementById(tabIds[i]);
+ anchorMap[aNode.hash] = tabIds[i];
+ }
+ // Default the empty hash to the info tab.
+ anchorMap['#'] = anchorMap[''] = 'info-tab';
+
+ window.onhashchange = function() {
+ var tabId = anchorMap[window.location.hash];
+ if (tabId)
+ categoryTabSwitcher.switchToTab(tabId);
+ };
+
+ // Make this category tab widget the primary view, that fills the whole page.
+ var windowView = new WindowView(categoryTabSwitcher);
+
+ // Trigger initial layout.
+ windowView.resetGeometry();
+
+ // Select the initial view based on the current URL.
+ window.onhashchange();
+}
+
+document.addEventListener('DOMContentLoaded', onLoad);
+
+</script>
+</head>
+<body>
+
+ <!-- Tab switcher for main categories. -->
+ <div id=category-tab-handles>
+ <ul>
+ <li><a href="#info" id="info-tab">GPU Info</a></li>
+ </ul>
+ </div>
+
+ <!-- Tabs -->
+ <include src="gpu_internals/info_view.html">
+</body>
+</html>
diff --git a/chrome/browser/resources/gpu_internals/browser_bridge.js b/chrome/browser/resources/gpu_internals/browser_bridge.js
new file mode 100644
index 0000000..cd1bf6d
--- /dev/null
+++ b/chrome/browser/resources/gpu_internals/browser_bridge.js
@@ -0,0 +1,59 @@
+// 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.
+
+cr.define('gpu', function() {
+ /**
+ * This class provides a 'bridge' for communicating between javascript and
+ * the browser.
+ * @constructor
+ */
+ function BrowserBridge() {
+ // If we are not running inside DOMUI, output chrome.send messages
+ // to the console to help with quick-iteration debugging.
+ if (chrome.send === undefined && console.log) {
+ chrome.send = function(messageHandler, args) {
+ console.log('chrome.send', messageHandler, args);
+ };
+ }
+
+ this.nextRequestId_ = 0;
+ this.pendingCallbacks_ = [];
+ }
+
+ BrowserBridge.prototype = {
+ __proto__: Object.prototype,
+
+ /**
+ * Sends a message to the browser with specified args. The
+ * browser will reply asynchronously via the provided callback.
+ */
+ callAsync: function(submessage, args, callback) {
+ var requestId = this.nextRequestId_;
+ this.nextRequestId_ += 1;
+ this.pendingCallbacks_[requestId] = callback;
+ if (!args) {
+ chrome.send('callAsync', [requestId.toString(), submessage]);
+ } else {
+ var allArgs = [requestId.toString(), submessage].concat(args);
+ chrome.send('callAsync', allArgs);
+ }
+ },
+
+ /**
+ * Called by gpu c++ code when client info is ready.
+ */
+ onCallAsyncReply: function(requestId, args) {
+ if (this.pendingCallbacks_[requestId] === undefined) {
+ throw new Error('requestId ' + requestId + ' is not pending');
+ }
+ var callback = this.pendingCallbacks_[requestId];
+ callback(args);
+ delete this.pendingCallbacks_[requestId];
+ }
+ };
+
+ return {
+ BrowserBridge : BrowserBridge
+ };
+});
diff --git a/chrome/browser/resources/gpu_internals/info_view.css b/chrome/browser/resources/gpu_internals/info_view.css
new file mode 100644
index 0000000..a877032
--- /dev/null
+++ b/chrome/browser/resources/gpu_internals/info_view.css
@@ -0,0 +1,28 @@
+/*
+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.
+*/
+#info-view {
+ padding: 10px;
+}
+
+#info-view h3 {
+ margin-bottom: 5px;
+}
+
+#info-view .row-title {
+ font-weight: bold;
+}
+
+#info-view table {
+ border-collapse: collapse;
+}
+
+#info-view table,
+#info-view th,
+#info-view td {
+ border: 1px solid #777;
+ padding-right: 4px;
+ padding-left: 4px;
+}
diff --git a/chrome/browser/resources/gpu_internals/info_view.html b/chrome/browser/resources/gpu_internals/info_view.html
new file mode 100644
index 0000000..9ef43b8
--- /dev/null
+++ b/chrome/browser/resources/gpu_internals/info_view.html
@@ -0,0 +1,34 @@
+<!--
+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.
+-->
+<div id=info-view>
+ <h3>Chrome Version</h3>
+ <div id="client-info"></div>
+ <h3>Driver Information</h3>
+ <div id="basic-info"></div>
+
+ <h3>Diagnostics</h3>
+ <div id="diagnostics">None</div>
+
+ <!-- templates -->
+ <div style="display:none">
+ <div id="info-view-table-template">
+ <table id="info-view-table">
+ <tr jsselect="value">
+ <td jsdisplay="!(value instanceof Array)">
+ <span class="row-title" jscontent="description">title</span>
+ </td>
+ <td jsdisplay="!(value instanceof Array)">
+ <span jscontent="value">value</span>
+ </td>
+ <td jsdisplay="value instanceof Array" colspan=2>
+ <span jscontent="description" class="row-title"></span>
+ <div transclude="info-view-table-template">
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+</div>
diff --git a/chrome/browser/resources/gpu_internals/info_view.js b/chrome/browser/resources/gpu_internals/info_view.js
new file mode 100644
index 0000000..acc4efc
--- /dev/null
+++ b/chrome/browser/resources/gpu_internals/info_view.js
@@ -0,0 +1,119 @@
+// 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.
+
+/**
+ * This view displays options for importing/exporting the captured data. Its
+ * primarily usefulness is to allow users to copy-paste their data in an easy
+ * to read format for bug reports.
+ *
+ * - Has a button to generate a text report.
+ *
+ * - Shows how many events have been captured.
+ */
+cr.define('gpu', function() {
+ /**
+ * Provides information on the GPU process and underlying graphics hardware.
+ * @constructor
+ */
+ function InfoView(mainBoxId) {
+ DivView.call(this, mainBoxId);
+
+ this.beginRequestClientInfo();
+ this.beginRequestGpuInfo();
+ this.refresh();
+ }
+
+ InfoView.prototype = {
+ __proto__: DivView.prototype,
+
+ /**
+ * This function begins a request for the ClientInfo. If it comes back
+ * as undefined, then we will issue the request again in 250ms.
+ */
+ beginRequestClientInfo : function() {
+ browserBridge.callAsync('requestClientInfo', undefined, (function(data) {
+ this.clientInfo_ = data;
+ this.refresh();
+ if (data === undefined) { // try again in 250 ms
+ window.setTimeout(this.beginRequestClientInfo.bind(this), 250);
+ }
+ }).bind(this));
+ },
+
+ /**
+ * This function begins a request for the GpuInfo. If it comes back
+ * as undefined, then we will issue the request again in 250ms.
+ */
+ beginRequestGpuInfo : function() {
+ browserBridge.callAsync('requestGpuInfo', undefined, (function(data) {
+ this.gpuInfo_ = data;
+ this.refresh();
+ if (!data || data.progress != 'complete') { // try again in 250 ms
+ window.setTimeout(this.beginRequestGpuInfo.bind(this), 250);
+ }
+ }).bind(this));
+ },
+
+ /**
+ * Updates the view based on its currently known data
+ */
+ refresh: function(data) {
+ // Client info
+ if (this.clientInfo_) {
+ var chromeVersion = this.clientInfo_.version +
+ ' (' + this.clientInfo_.official +
+ ' ' + this.clientInfo_.cl +
+ ') ' + this.clientInfo_.version_mod;
+ this.setTable_('client-info', [
+ {
+ description: 'Data exported',
+ value: (new Date()).toLocaleString()
+ },
+ {
+ description: 'Chrome version',
+ value: chromeVersion
+ }]);
+ } else {
+ this.setText_('client-info', '... loading...');
+ }
+
+ // GPU info, basic
+ if (this.gpuInfo_) {
+ this.setTable_('basic-info', this.gpuInfo_.basic_info);
+ if (this.gpuInfo_.diagnostics) {
+ this.setTable_('diagnostics', this.gpuInfo_.diagnostics);
+ } else if (this.gpuInfo_.progress == 'partial') {
+ this.setText_('diagnostics', '... loading...');
+ } else {
+ this.setText_('diagnostics', 'None');
+ }
+ } else {
+ this.setText_('basic-info', '... loading ...');
+ this.setText_('diagnostics', '... loading ...');
+ }
+ },
+
+ setText_: function(outputElementId, text) {
+ var peg = document.getElementById(outputElementId);
+ peg.innerText = text;
+ },
+
+ setTable_: function(outputElementId, inputData) {
+ var template = jstGetTemplate('info-view-table-template');
+ jstProcess(new JsEvalContext({value: inputData}),
+ template);
+
+ var peg = document.getElementById(outputElementId);
+ if (!peg)
+ throw new Error('Node ' + outputElementId + ' not found');
+
+ peg.innerHTML = '';
+ peg.appendChild(template);
+ }
+ };
+
+ return {
+ InfoView: InfoView
+ };
+}); \ No newline at end of file
diff --git a/chrome/browser/resources/history.html b/chrome/browser/resources/history.html
index 8f29115..851601f 100644
--- a/chrome/browser/resources/history.html
+++ b/chrome/browser/resources/history.html
@@ -1068,7 +1068,7 @@ function historyDeleted() {
width: 50%;
}
#edit-button {
- text-align: right;
+ text-align: end;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
@@ -1116,13 +1116,11 @@ table.results {
color:#888;
float:left;
min-width:56px;
- margin-right:5px;
+ -webkit-margin-end:5px;
padding-top:1px;
white-space:nowrap;
}
html[dir='rtl'] .time {
- margin-right:0px;
- margin-left:5px;
float:right;
}
.entry .title {
@@ -1138,17 +1136,13 @@ html[dir='rtl'] .time {
background:url('shared/images/star_small.png');
background-repeat:no-repeat;
display:inline-block;
- margin-left:12px;
- margin-right:0;
+ -webkit-margin-start:12px;
+ -webkit-margin-end:0;
width:11px;
height:11px;
}
-html[dir='rtl'] .title > .starred {
- margin-left:0;
- margin-right:12px;
-}
.entry .title > a {
- -webkit-box-sizing: border-box;
+ box-sizing: border-box;
background-repeat:no-repeat;
background-size:16px;
background-position:0px 1px;
@@ -1164,7 +1158,7 @@ html[dir='rtl'] .entry .title > a {
}
#results-pagination {
padding-top:24px;
- margin-left:18px;
+ -webkit-margin-start:18px;
}
</style>
diff --git a/chrome/browser/resources/imageburner.html b/chrome/browser/resources/imageburner.html
index c8c9419..365143d 100644
--- a/chrome/browser/resources/imageburner.html
+++ b/chrome/browser/resources/imageburner.html
@@ -125,14 +125,12 @@ h1.title {
left: 0;
bottom: 0;
right: 600px;
- border-right: 1px solid #7289E2;
+ -webkit-border-end: 1px solid #7289E2;
}
html[dir='rtl'] .fullcontainer {
left: 600px;
right: 0;
- border-right: auto;
- border-left: 1px solid #7289E2;
}
progress {
diff --git a/chrome/browser/resources/keyboard_overlay.css b/chrome/browser/resources/keyboard_overlay.css
index 880cbd7..2827254 100644
--- a/chrome/browser/resources/keyboard_overlay.css
+++ b/chrome/browser/resources/keyboard_overlay.css
@@ -6,14 +6,14 @@ body {
}
.keyboard-overlay-keyboard {
- -webkit-border-radius: 6px;
+ border-radius: 6px;
background: -webkit-gradient(linear, left top, left bottom,
from(#484848), to(#252525)) no-repeat;
font-family: 'Droid Sans', Arial;
}
.keyboard-overlay-instructions {
- -webkit-border-radius: 5px;
+ border-radius: 5px;
background: -webkit-gradient(linear, left top, left bottom,
from(#334c7e), to(#0d172b));
border: 2px solid #576ccf;
@@ -32,7 +32,7 @@ body {
}
.keyboard-overlay-key {
- -webkit-border-radius: 4px;
+ border-radius: 4px;
-webkit-box-orient: vertical;
background-color: rgba(24, 24, 24, 0.9);
border: 2px solid #7f7f7f;
diff --git a/chrome/browser/resources/login.html b/chrome/browser/resources/login.html
new file mode 100644
index 0000000..4238a25
--- /dev/null
+++ b/chrome/browser/resources/login.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link rel="stylesheet" href="login_ui.css" >
+</head>
+
+<body>
+ <div id="sign-in-div">
+ <div id="sign-in-body">
+ <div id="title-text">
+ Sign in with your Google Account
+ </div>
+ <div>
+ <label>
+ <input type="text" id="user-text" name="user">
+ Username
+ </label>
+ </div>
+ <div>
+ <label>
+ <input type="password" id="pass-text" name="pass">
+ Password
+ </label>
+ </div>
+ <button type="button" id="login-button" onclick="callLogin();">
+ Sign In
+ </button>
+ <a id="login-incognito" onclick="callLoginIncognito();">
+ Browse without signing in
+ </a>
+ </div>
+ </div>
+</body>
+
+<script>
+function callLoginIncognito() {
+ loginStarted();
+ chrome.send('LaunchIncognito', []);
+}
+
+function callLogin() {
+ var user = document.getElementById('user-text').value;
+ var pass = document.getElementById('pass-text').value;
+ loginStarted();
+ chrome.send('AuthenticateUser', [user, pass]);
+}
+
+function loginStarted() {
+ setLock(true);
+}
+
+function loginFinished(result) {
+ setLock(false);
+}
+
+function setLock(on) {
+ document.getElementById('login-button').disabled = on;
+ document.getElementById('login-incognito').disabled = on;
+ document.getElementById('user-text').disabled = on;
+ document.getElementById('pass-text').disabled = on;
+}
+</script>
+</html>
diff --git a/chrome/browser/resources/login_ui.css b/chrome/browser/resources/login_ui.css
new file mode 100644
index 0000000..bb8a66a
--- /dev/null
+++ b/chrome/browser/resources/login_ui.css
@@ -0,0 +1,43 @@
+body {
+ background: -webkit-gradient(
+ radial, 50% 50%, 5, 50% 50%, 1000,
+ from(darkblue), to(black)
+ );
+ font-family: 'Times New Roman';
+ font-size: 15px;
+}
+
+#sign-in-div {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ display: -webkit-box;
+ -webkit-box-align: center;
+ -webkit-box-pack: center;
+}
+
+#sign-in-body {
+ padding: 5px 10px 5px 10px;
+ background: white;
+}
+
+#title-text {
+ text-align: center;
+ font-size: 20px;
+ font-weight: bold;
+}
+
+label {
+ clear: both;
+}
+
+a {
+ display: block;
+ color: blue;
+}
+
+a:hover {
+ text-decoration: underline;
+}
diff --git a/chrome/browser/resources/mediaplayer.html b/chrome/browser/resources/mediaplayer.html
index f3aae4c..effa78b 100644
--- a/chrome/browser/resources/mediaplayer.html
+++ b/chrome/browser/resources/mediaplayer.html
@@ -74,7 +74,7 @@ body {
right: 120px;
height: 5px;
position: absolute;
- -webkit-border-radius: 3px;
+ border-radius: 3px;
background: -webkit-gradient(linear,
left top,
left bottom,
@@ -88,7 +88,7 @@ body {
width:0;
left: -1px;
top: -1px;
- -webkit-border-radius: 3px;
+ border-radius: 3px;
border: 1px solid #9ca5b7;
position: absolute;
background: -webkit-gradient(linear,
@@ -103,7 +103,7 @@ body {
width:0;
left: -1px;
top: -1px;
- -webkit-border-radius: 3px;
+ border-radius: 3px;
position: absolute;
background: #6a799a;
border: 1px solid #ffffff;
diff --git a/chrome/browser/resources/net_internals/detailsview.js b/chrome/browser/resources/net_internals/detailsview.js
index f9b532e..e3543d4 100644
--- a/chrome/browser/resources/net_internals/detailsview.js
+++ b/chrome/browser/resources/net_internals/detailsview.js
@@ -14,7 +14,7 @@ function DetailsView(tabHandlesContainerId,
timelineTabId,
logBoxId,
timelineBoxId) {
- TabSwitcherView.call(this, new DivView(tabHandlesContainerId));
+ TabSwitcherView.call(this, tabHandlesContainerId);
this.logView_ = new DetailsLogView(logBoxId);
this.timelineView_ = new DetailsTimelineView(timelineBoxId);
diff --git a/chrome/browser/resources/net_internals/index.html b/chrome/browser/resources/net_internals/index.html
index 1a95210..732c4be 100644
--- a/chrome/browser/resources/net_internals/index.html
+++ b/chrome/browser/resources/net_internals/index.html
@@ -1,4 +1,5 @@
-<html>
+<!DOCTYPE HTML>
+<head i18n-values="dir:textdirection;">
<!--
Copyright (c) 2010 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
@@ -6,6 +7,7 @@ found in the LICENSE file.
-->
<head>
<link rel="stylesheet" href="main.css">
+ <link rel="stylesheet" href="tabswitcherview.css">
<script src="util.js"></script>
<script src="view.js"></script>
<script src="tabswitcherview.js"></script>
@@ -219,7 +221,7 @@ found in the LICENSE file.
<b>Capturing all events...</b>
<table style="margin: 8px">
<tr>
- <td>Pasively captured:</td>
+ <td>Passively captured:</td>
<td align=right id=passivelyCapturedCount></td>
</tr>
<tr>
@@ -276,7 +278,7 @@ function displayHelpForBugDump() {
<li>If you choose not to have cookies removed from the log, you must toggle
the checkbox before clicking the button.</li>
</ul>
-<li>Ideally you would have the tool running <b>before</b> you reproduce the
+<li>Ideally you would have the tool running <b>before</b> you reproduce the
bug.
If that isn't possible (perhaps the bug happens unpredictably), then the
next best thing is to load chrome://net-internals/ <b>as soon as you can
diff --git a/chrome/browser/resources/net_internals/main.css b/chrome/browser/resources/net_internals/main.css
index 7861a35..be3abee 100644
--- a/chrome/browser/resources/net_internals/main.css
+++ b/chrome/browser/resources/net_internals/main.css
@@ -5,7 +5,7 @@ found in the LICENSE file.
*/
* {
- -webkit-box-sizing: border-box;
+ box-sizing: border-box;
-moz-box-sizing: border-box;
}
body {
@@ -147,54 +147,6 @@ body {
font-size: 10px;
}
-#categoryTabHandles ul {
- list-style: none;
- padding: 0;
- margin: 0;
-}
-
-#categoryTabHandles {
- border-bottom: 1px solid #555;
- background: #aaa;
- overflow: hidden;
-}
-
-#categoryTabHandles li {
- float: left;
- margin-left: 5px;
-}
-
-#categoryTabHandles a {
- text-decoration: none;
- text-align: center;
- display: inline-block;
- margin-top: 4px;
- padding: 5px 10px 3px 10px;
- -webkit-border-top-right-radius: 8px;
- -webkit-border-top-left-radius: 8px;
- background-clip: border-box;
- background: #ccc;
-}
-
-#categoryTabHandles a:hover {
- background: #eee;
-}
-
-#categoryTabHandles a:visited,
-#categoryTabHandles a {
- color: blue;
-}
-
-#categoryTabHandles .selected {
- background: white;
-}
-
-#categoryTabHandles a.selected {
- position:relative;
- top: 3px;
- color: black;
-}
-
#detailsLogBox,
#detailsTimelineBox,
#httpCacheTabContent,
diff --git a/chrome/browser/resources/net_internals/main.js b/chrome/browser/resources/net_internals/main.js
index 7bfdb62..70a1b51 100644
--- a/chrome/browser/resources/net_internals/main.js
+++ b/chrome/browser/resources/net_internals/main.js
@@ -107,8 +107,7 @@ function onLoaded() {
}
// Create a view which lets you tab between the different sub-views.
- var categoryTabSwitcher =
- new TabSwitcherView(new DivView('categoryTabHandles'));
+ var categoryTabSwitcher = new TabSwitcherView('categoryTabHandles');
// Populate the main tabs.
categoryTabSwitcher.addTab('eventsTab', eventsView, false);
@@ -308,9 +307,6 @@ BrowserBridge.prototype.setLogLevel = function(logLevel) {
//------------------------------------------------------------------------------
BrowserBridge.prototype.receivedLogEntry = function(logEntry) {
- // Silently drop entries received before ready to receive them.
- if (!this.areLogTypesReady_())
- return;
// Assign unique ID, if needed.
if (logEntry.source.id == 0) {
logEntry.source.id = this.nextSourcelessEventId_;
@@ -388,12 +384,27 @@ BrowserBridge.prototype.receivedServiceProviders = function(serviceProviders) {
};
BrowserBridge.prototype.receivedPassiveLogEntries = function(entries) {
- this.numPassivelyCapturedEvents_ += entries.length;
+ // Due to an expected race condition, it is possible to receive actively
+ // captured log entries before the passively logged entries are received.
+ //
+ // When that happens, we create a copy of the actively logged entries, delete
+ // all entries, and, after handling all the passively logged entries, add back
+ // the deleted actively logged entries.
+ var earlyActivelyCapturedEvents = this.capturedEvents_.slice(0);
+ if (earlyActivelyCapturedEvents.length > 0)
+ this.deleteAllEvents();
+
+ this.numPassivelyCapturedEvents_ = entries.length;
for (var i = 0; i < entries.length; ++i) {
var entry = entries[i];
entry.wasPassivelyCaptured = true;
this.receivedLogEntry(entry);
}
+
+ // Add back early actively captured events, if any.
+ for (var i = 0; i < earlyActivelyCapturedEvents.length; ++i) {
+ this.receivedLogEntry(earlyActivelyCapturedEvents[i]);
+ }
};
@@ -427,12 +438,6 @@ BrowserBridge.prototype.receivedHttpCacheInfo = function(info) {
this.pollableDataHelpers_.httpCacheInfo.update(info);
};
-BrowserBridge.prototype.areLogTypesReady_ = function() {
- return (LogEventType != null &&
- LogEventPhase != null &&
- LogSourceType != null);
-};
-
//------------------------------------------------------------------------------
/**
diff --git a/chrome/browser/resources/net_internals/tabswitcherview.css b/chrome/browser/resources/net_internals/tabswitcherview.css
new file mode 100644
index 0000000..4b8fb50
--- /dev/null
+++ b/chrome/browser/resources/net_internals/tabswitcherview.css
@@ -0,0 +1,61 @@
+/*
+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.
+*/
+.tab-switcher-view {
+ font-family: sans-serif;
+}
+
+.tab-switcher-view ul {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+}
+
+.tab-switcher-view {
+ border-bottom: 1px solid #555;
+ background: #aaa;
+ overflow: hidden;
+}
+
+.tab-switcher-view li {
+ float: left;
+ -webkit-margin-start: 5px;
+}
+
+xhtml[dir=rtl] .tab-switcher-view li {
+ float: right;
+}
+
+.tab-switcher-view a {
+ text-decoration: none;
+ text-align: center;
+ display: inline-block;
+ margin-top: 4px;
+ padding: 5px 10px 3px 10px;
+ border-top-right-radius: 8px;
+ border-top-left-radius: 8px;
+ background-clip: border-box;
+ background: #ccc;
+}
+
+.tab-switcher-view a:hover {
+ background: #eee;
+}
+
+
+.tab-switcher-view a:visited,
+.tab-switcher-view a {
+ color: blue;
+}
+
+.tab-switcher-view .selected {
+ background: white;
+}
+
+.tab-switcher-view a.selected {
+ position: relative;
+ top: 3px;
+ color: black;
+} \ No newline at end of file
diff --git a/chrome/browser/resources/net_internals/tabswitcherview.js b/chrome/browser/resources/net_internals/tabswitcherview.js
index 1e6843c..646c983 100644
--- a/chrome/browser/resources/net_internals/tabswitcherview.js
+++ b/chrome/browser/resources/net_internals/tabswitcherview.js
@@ -22,7 +22,10 @@
*
* @constructor
*/
-function TabSwitcherView(tabHandleView) {
+function TabSwitcherView(tabHandleDivId) {
+ document.getElementById(tabHandleDivId).classList.add('tab-switcher-view');
+ var tabHandleView = new DivView(tabHandleDivId);
+
View.call(this);
this.tabHandleView_ = tabHandleView;
this.tabs_ = [];
@@ -122,7 +125,8 @@ TabSwitcherView.prototype.switchToTab = function(id, params) {
// Update data needed by newly active tab, as it may be
// significantly out of date.
- g_browser.checkForUpdatedInfo();
+ if (typeof g_browser != 'undefined' && g_browser.checkForUpdatedInfo)
+ g_browser.checkForUpdatedInfo();
};
TabSwitcherView.prototype.getAllTabIds = function() {
diff --git a/chrome/browser/resources/net_internals/view.js b/chrome/browser/resources/net_internals/view.js
index bf76b4d..68f485e 100644
--- a/chrome/browser/resources/net_internals/view.js
+++ b/chrome/browser/resources/net_internals/view.js
@@ -80,6 +80,8 @@ function DivView(divId) {
View.call(this);
this.node_ = document.getElementById(divId);
+ if (!this.node_)
+ throw new Error('Element ' + divId + ' not found');
// Initialize the default values to those of the DIV.
this.width_ = this.node_.offsetWidth;
diff --git a/chrome/browser/resources/new_new_tab.css b/chrome/browser/resources/new_new_tab.css
index 2c0dcc5..1716fb4 100644
--- a/chrome/browser/resources/new_new_tab.css
+++ b/chrome/browser/resources/new_new_tab.css
@@ -16,7 +16,7 @@ html[mode=app-launcher] {
}
#main {
- -webkit-box-sizing: border-box;
+ box-sizing: border-box;
-webkit-transition: width .15s;
margin: 0 auto;
min-height: 100%;
@@ -155,7 +155,7 @@ html[anim=false] *,
background-color: hsla(213, 63%, 93%, 0);
display: block;
line-height: 20px;
- -webkit-box-sizing: border-box;
+ box-sizing: border-box;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@@ -322,6 +322,10 @@ html[hasattribution=false] #attribution > div {
font-size: 92%;
}
+body.noscroll {
+ overflow: hidden;
+}
+
html[anim=true][enable-section-animations=true] .section {
-webkit-transition: top .15s;
}
@@ -458,6 +462,10 @@ html[dir=rtl] .section-close-button {
padding: 5px 0 30px;
position: absolute;
-webkit-mask-attachment: fixed;
+ opacity: 0;
+}
+
+.maxiview.opaque {
opacity: 1;
}
@@ -467,9 +475,14 @@ html[dir=rtl] .section-close-button {
.maxiview.hidden {
display: none;
+ opacity: 0;
+}
+
+html[anim=true][enable-section-animations=true] .maxiview {
+ -webkit-transition: opacity .10s, top .15s;
}
-html[anim=true] .maxiview {
+html[anim=true][enable-section-animations=true] .miniview {
-webkit-transition: opacity .15s;
}
@@ -484,9 +497,17 @@ html[anim=true] .maxiview {
display: none;
}
-.section.hidden > h2,
+.section.hidden > h2 {
+ display: block;
+}
+
.section.hidden > .miniview {
display: block;
+ opacity: 0;
+}
+
+.section.hidden > .miniview.opaque {
+ opacity: 1;
}
.section.hidden > h2 {
diff --git a/chrome/browser/resources/new_new_tab.html b/chrome/browser/resources/new_new_tab.html
index 9fdde30..f987bde 100644
--- a/chrome/browser/resources/new_new_tab.html
+++ b/chrome/browser/resources/new_new_tab.html
@@ -143,7 +143,7 @@ if ('mode' in hashParams) {
<div id="apps-promo">
<button id="apps-promo-hide" i18n-content="appspromohide"></button>
<h3 i18n-content="appspromoheader"></h3>
- <p id="apps-promo-text1" i18n-values=".innerHTML:appspromotext1"></p>
+ <p id="apps-promo-text1" i18n-content="appspromotext1"></p>
<p id="apps-promo-text2" i18n-content="appspromotext2"></p>
</div>
<div id="apps-content"></div>
@@ -259,7 +259,7 @@ if ('mode' in hashParams) {
<hr>
<button command="#apps-options-command"></button>
<button command="#apps-uninstall-command"></button>
- <hr>
+ <hr id="apps-create-shortcut-command-separator">
<button id="apps-create-shortcut-command-menu-item"
command="#apps-create-shortcut-command"></button>
</menu>
diff --git a/chrome/browser/resources/new_new_tab.js b/chrome/browser/resources/new_new_tab.js
index 2c8a7cc..315b54b 100644
--- a/chrome/browser/resources/new_new_tab.js
+++ b/chrome/browser/resources/new_new_tab.js
@@ -105,14 +105,27 @@ function initializeSection(sectionId, mask, opt_section) {
function updateSimpleSection(id, section) {
var elm = $(id);
var maxiview = getSectionMaxiview(elm);
+ var miniview = getSectionMiniview(elm);
if (shownSections & section) {
- $(id).classList.remove('hidden');
- if (maxiview)
+ // The section is expanded, so the maxiview should be opaque (visible) and
+ // the miniview should be hidden.
+ elm.classList.remove('hidden');
+ if (maxiview) {
maxiview.classList.remove('hidden');
+ maxiview.classList.add('opaque');
+ }
+ if (miniview)
+ miniview.classList.remove('opaque');
} else {
- $(id).classList.add('hidden');
- if (maxiview)
+ // The section is minimized, so the maxiview should be hidden and the
+ // miniview should be opaque.
+ elm.classList.add('hidden');
+ if (maxiview) {
maxiview.classList.add('hidden');
+ maxiview.classList.remove('opaque');
+ }
+ if (miniview)
+ miniview.classList.add('opaque');
}
}
@@ -337,6 +350,28 @@ function updateAllMiniviewClippings() {
}
}
+// Returns whether or not vertical scrollbars are present.
+function hasScrollBars() {
+ return window.innerHeight != document.body.clientHeight;
+}
+
+// Enables scrollbars (they will only show up if needed).
+function showScrollBars() {
+ document.body.classList.remove('noscroll');
+}
+
+// Hides all scrollbars.
+function hideScrollBars() {
+ document.body.classList.add('noscroll');
+}
+
+// Returns whether or not the sections are currently animating due to a
+// section transition.
+function isAnimating() {
+ var de = document.documentElement;
+ return de.getAttribute('enable-section-animations') == 'true';
+}
+
// Layout the sections in a modified accordian. The header and miniview, if
// visible are fixed within the viewport. If there is an expanded section, its
// it scrolls.
@@ -367,6 +402,11 @@ function updateAllMiniviewClippings() {
// don't have a bunch of dead whitespace in the case of expanded sections that
// aren't very tall.
function layoutSections() {
+ // While transitioning sections, we only want scrollbars to appear if they're
+ // already present or the window is being resized (so there's no animation).
+ if (!hasScrollBars() && isAnimating())
+ hideScrollBars();
+
var sections = SectionLayoutInfo.getAll();
var expandedSection = null;
var headerHeight = LAYOUT_SPACING_TOP;
@@ -433,11 +473,22 @@ function layoutSections() {
section.section.style.top = y + 'px';
y += section.fixedHeight;
- if (section.maxiview && section == expandedSection) {
- section.maxiview.style.top = y + 'px';
- updateMask(section.maxiview, expandedSectionHeight);
+ if (section.maxiview) {
+ if (section == expandedSection) {
+ section.maxiview.style.top = y + 'px';
+ } else {
+ // The miniviews fade out gradually, so it may have height at this
+ // point. We position the maxiview as if the miniview was not displayed
+ // by subtracting off the miniview's total height (height + margin).
+ var miniviewFudge = 40; // miniview margin-bottom + margin-top
+ var miniviewHeight = section.miniview.offsetHeight + miniviewFudge;
+ section.maxiview.style.top = y - miniviewHeight + 'px';
+ }
}
+ if (section.maxiview && section == expandedSection)
+ updateMask(section.maxiview, expandedSectionHeight);
+
if (section == expandedSection)
y += expandedSectionHeight;
}
@@ -502,6 +553,10 @@ function getSectionMaxiview(section) {
return $(section.id + '-maxiview');
}
+function getSectionMiniview(section) {
+ return section.querySelector('.miniview');
+}
+
// You usually want to call |showOnlySection()| instead of this.
function showSection(section) {
if (!(section & shownSections)) {
@@ -514,6 +569,21 @@ function showSection(section) {
if (maxiview) {
maxiview.classList.remove('hiding');
maxiview.classList.remove('hidden');
+ // The opacity won't transition if you toggle the display property
+ // at the same time. To get a fade effect, we set the opacity
+ // asynchronously from another function, after the display is toggled.
+ // 1) 'hidden' (display: none, opacity: 0)
+ // 2) none (display: block, opacity: 0)
+ // 3) 'opaque' (display: block, opacity: 1)
+ setTimeout(function () {
+ maxiview.classList.add('opaque');
+ }, 0);
+ }
+
+ var miniview = getSectionMiniview(el);
+ if (miniview) {
+ // The miniview is hidden immediately (no need to set this async).
+ miniview.classList.remove('opaque');
}
}
@@ -553,12 +623,19 @@ function hideSection(section) {
el.classList.add('hidden');
var maxiview = getSectionMaxiview(el);
- if (maxiview)
+ if (maxiview) {
maxiview.classList.add(isDoneLoading() ? 'hiding' : 'hidden');
+ maxiview.classList.remove('opaque');
+ }
- var miniview = el.querySelector('.miniview');
- if (miniview)
+ var miniview = getSectionMiniview(el);
+ if (miniview) {
+ // We need to set this asynchronously to properly get the fade effect.
+ setTimeout(function() {
+ miniview.classList.add('opaque');
+ }, 0);
updateMiniviewClipping(miniview);
+ }
}
}
}
@@ -569,7 +646,11 @@ window.addEventListener('webkitTransitionEnd', function(e) {
e.target.classList.remove('hiding');
}
- document.documentElement.setAttribute('enable-section-animations', 'false');
+ if (e.target.classList.contains('maxiview') ||
+ e.target.classList.contains('miniview')) {
+ document.documentElement.removeAttribute('enable-section-animations');
+ showScrollBars();
+ }
});
/**
@@ -599,16 +680,18 @@ function setShownSections(newShownSections) {
function layoutRecentlyClosed() {
var recentElement = $('recently-closed');
- var miniview = recentElement.querySelector('.miniview');
+ var miniview = getSectionMiniview(recentElement);
updateMiniviewClipping(miniview);
if (miniview.hasChildNodes()) {
if (!(shownSections & MINIMIZED_RECENT)) {
recentElement.classList.remove('disabled');
+ miniview.classList.add('opaque');
}
} else {
recentElement.classList.add('disabled');
+ miniview.classList.remove('opaque');
}
}
@@ -1244,7 +1327,10 @@ function isDoneLoading() {
// Initialize the apps promo.
document.addEventListener('DOMContentLoaded', function() {
- var promoLink = document.querySelector('#apps-promo-text1 a');
+ var promoText1 = $('apps-promo-text1');
+ promoText1.innerHTML = promoText1.textContent;
+
+ var promoLink = promoText1.querySelector('a');
promoLink.id = 'apps-promo-link';
promoLink.href = localStrings.getString('web_store_url');
diff --git a/chrome/browser/resources/ntp/apps.css b/chrome/browser/resources/ntp/apps.css
index 95d51f5..2d03d58 100644
--- a/chrome/browser/resources/ntp/apps.css
+++ b/chrome/browser/resources/ntp/apps.css
@@ -24,7 +24,7 @@ html.apps-promo-visible #apps-content {
.app,
.app[new=installed] {
- -webkit-box-sizing: border-box;
+ box-sizing: border-box;
-webkit-perspective: 400;
border-radius: 10px;
color: black;
diff --git a/chrome/browser/resources/ntp/apps.js b/chrome/browser/resources/ntp/apps.js
index cf92cb8..32b8a4a 100644
--- a/chrome/browser/resources/ntp/apps.js
+++ b/chrome/browser/resources/ntp/apps.js
@@ -35,6 +35,7 @@ function getAppsCallback(data) {
// The "Create App Shortcut" menu option.
$('apps-create-shortcut-command-menu-item').style.display =
+ $('apps-create-shortcut-command-separator').style.display =
(data.disableCreateAppShortcut ? 'none' : 'inline');
appsMiniview.textContent = '';
@@ -77,13 +78,10 @@ function getAppsCallback(data) {
document.documentElement.classList.add('apps-promo-visible');
else
document.documentElement.classList.remove('apps-promo-visible');
-
- var appsPromoLink = $('apps-promo-link');
- if (appsPromoLink)
- appsPromoLink.setAttribute('ping', appsPromoPing);
+ $('apps-promo-link').setAttribute('ping', appsPromoPing);
maybeDoneLoading();
- if (isDoneLoading()) {
+ if (data.apps.length > 0 && isDoneLoading()) {
if (!apps.showPromo && data.apps.length >= MAX_APPS_PER_ROW[layoutMode])
webStoreEntry.classList.add('loner');
else
diff --git a/chrome/browser/resources/ntp/most_visited.css b/chrome/browser/resources/ntp/most_visited.css
index 27f2958..44933b1 100644
--- a/chrome/browser/resources/ntp/most_visited.css
+++ b/chrome/browser/resources/ntp/most_visited.css
@@ -195,8 +195,8 @@ html[dir=rtl] .thumbnail-container > .title > div {
.thumbnail-container:hover .thumbnail {
border-color: hsl(213, 66%, 57%);
-webkit-box-shadow: 0px 2px 2px hsla(0, 0%, 0%, 0);
- -webkit-border-top-left-radius: 0;
- -webkit-border-top-right-radius: 0;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
background-image: -webkit-gradient(linear, left top, left bottom,
from(hsla(0, 0%, 0%, 0)),
diff --git a/chrome/browser/resources/options.html b/chrome/browser/resources/options.html
deleted file mode 100644
index e679135..0000000
--- a/chrome/browser/resources/options.html
+++ /dev/null
@@ -1,388 +0,0 @@
-<!DOCTYPE HTML>
-<html
- i18n-values="dir:textdirection;
- enable-cloud-print-proxy:enable-cloud-print-proxy"
- id="t">
-<head>
-<meta charset="utf-8">
-<title i18n-content="title"></title>
-
-<link rel="icon" href="../../app/theme/settings_favicon.png">
-<link rel="stylesheet" href="chrome://resources/css/list.css">
-<link rel="stylesheet" href="chrome://resources/css/tree.css">
-<link rel="stylesheet" href="dom_ui.css">
-<link rel="stylesheet" href="options/options_page.css">
-<link rel="stylesheet" href="options/add_startup_page_overlay.css">
-<link rel="stylesheet" href="options/advanced_options.css">
-<link rel="stylesheet" href="options/alert_overlay.css">
-<link rel="stylesheet" href="options/autofill_edit_address_overlay.css">
-<link rel="stylesheet" href="options/autofill_edit_creditcard_overlay.css">
-<link rel="stylesheet" href="options/autofill_options_page.css">
-<link rel="stylesheet" href="options/browser_options_page.css">
-<link rel="stylesheet" href="options/clear_browser_data_overlay.css">
-<link rel="stylesheet" href="options/content_settings.css">
-<link rel="stylesheet" href="options/content_settings_exceptions_area.css">
-<link rel="stylesheet" href="options/cookies_view.css">
-<link rel="stylesheet" href="options/edit_search_engine_overlay.css">
-<link rel="stylesheet" href="options/passwords_exceptions_list.css">
-<link rel="stylesheet" href="options/personal_options.css">
-<link rel="stylesheet" href="options/import_data_overlay.css">
-<link rel="stylesheet" href="options/search_engine_manager.css">
-<link rel="stylesheet" href="options/subpages_tab_controls.css">
-<link rel="stylesheet" href="options/zippy.css">
-<if expr="pp_ifdef('chromeos')">
- <link rel="stylesheet" href="options/about_page.css">
- <link rel="stylesheet" href="options/chromeos_accounts_options_page.css">
- <link rel="stylesheet" href="options/chromeos_internet_options_page.css">
- <link rel="stylesheet" href="options/chromeos_language_options.css">
- <link rel="stylesheet" href="options/chromeos_proxy.css">
-</if>
-
-<if expr="not pp_ifdef('win32') and not pp_ifdef('darwin')">
- <link rel="stylesheet" href="options/certificate_manager.css">
-</if>
-
-<script src="chrome://resources/css/tree.css.js"></script>
-
-<script src="chrome://resources/js/cr.js"></script>
-<script src="chrome://resources/js/cr/command_line.js"></script>
-<script src="chrome://resources/js/cr/event_target.js"></script>
-<script src="chrome://resources/js/cr/ui.js"></script>
-<script src="chrome://resources/js/cr/ui/array_data_model.js"></script>
-<script src="chrome://resources/js/cr/ui/list_selection_model.js"></script>
-<script src="chrome://resources/js/cr/ui/list_selection_controller.js"></script>
-<script src="chrome://resources/js/cr/ui/list_single_selection_model.js"></script>
-<script src="chrome://resources/js/cr/ui/list_item.js"></script>
-<script src="chrome://resources/js/cr/ui/list.js"></script>
-<script src="chrome://resources/js/cr/ui/tree.js"></script>
-<script src="chrome://resources/js/local_strings.js"></script>
-<script src="chrome://resources/js/util.js"></script>
-<script src="options/preferences.js"></script>
-<script src="options/pref_ui.js"></script>
-<script src="options/list_inline_header_selection_controller.js"></script>
-<script src="options/options_page.js"></script>
-<if expr="pp_ifdef('chromeos')">
- <script src="options/about_page.js"></script>
- <script src="options/chromeos_cellular_plan_element.js"></script>
- <script src="options/chromeos_internet_network_element.js"></script>
- <script src="options/chromeos_internet_options.js"></script>
- <script src="options/chromeos_language_add_language_overlay.js"></script>
- <script src="options/chromeos_language_list.js"></script>
- <script src="options/chromeos_language_options.js"></script>
- <script src="options/chromeos_system_options.js"></script>
- <script src="options/chromeos_accounts_options.js"></script>
- <script src="options/chromeos_proxy_options.js"></script>
- <script src="options/chromeos_proxy_rules_list.js"></script>
- <script src="options/chromeos_accounts_user_list.js"></script>
- <script src="options/chromeos_accounts_user_name_edit.js"></script>
- <script>
- var AboutPage = options.AboutPage;
- var AccountsOptions = options.AccountsOptions;
- var InternetOptions = options.InternetOptions;
- var LanguageHangulOptions = options.LanguageHangulOptions;
- var LanguageOptions = options.LanguageOptions;
- var SystemOptions = options.SystemOptions;
- </script>
-</if>
-<if expr="not pp_ifdef('win32') and not pp_ifdef('darwin')">
- <script src="options/certificate_tree.js"></script>
- <script src="options/certificate_manager.js"></script>
- <script src="options/certificate_restore_overlay.js"></script>
- <script src="options/certificate_backup_overlay.js"></script>
- <script src="options/certificate_edit_ca_trust_overlay.js"></script>
- <script src="options/certificate_import_error_overlay.js"></script>
- <script>
- var CertificateManager = options.CertificateManager;
- var CertificateRestoreOverlay = options.CertificateRestoreOverlay;
- var CertificateBackupOverlay = options.CertificateBackupOverlay;
- var CertificateEditCaTrustOverlay = options.CertificateEditCaTrustOverlay;
- var CertificateImportErrorOverlay = options.CertificateImportErrorOverlay;
- </script>
-</if>
-<script src="options/add_startup_page_overlay.js"></script>
-<script src="options/add_startup_page_recent_pages_list.js"></script>
-<script src="options/advanced_options.js"></script>
-<script src="options/alert_overlay.js"></script>
-<script src="options/autofill_edit_address_overlay.js"></script>
-<script src="options/autofill_edit_creditcard_overlay.js"></script>
-<script src="options/autofill_options.js"></script>
-<script src="options/browser_options.js"></script>
-<script src="options/browser_options_startup_page_list.js"></script>
-<script src="options/clear_browser_data_overlay.js"></script>
-<script src="options/content_settings.js"></script>
-<script src="options/content_settings_exceptions_area.js"></script>
-<script src="options/content_settings_ui.js"></script>
-<script src="options/cookies_tree.js"></script>
-<script src="options/cookies_view.js"></script>
-<script src="options/edit_search_engine_overlay.js"></script>
-<script src="options/font_settings.js"></script>
-<script src="options/font_settings_ui.js"></script>
-<script src="options/import_data_overlay.js"></script>
-<script src="options/instant_confirm_overlay.js"></script>
-<script src="options/passwords_exceptions.js"></script>
-<script src="options/passwords_exceptions_list.js"></script>
-<script src="options/personal_options.js"></script>
-<script src="options/search_engine_manager.js"></script>
-<script src="options/search_engine_manager_engine_list.js"></script>
-<script src="options/search_page.js"></script>
-<script src="options/sync_options.js"></script>
-<script src="options/zippy.js"></script>
-<script>
-
-var AddStartupPageOverlay = options.AddStartupPageOverlay;
-var AdvancedOptions = options.AdvancedOptions;
-var AlertOverlay = options.AlertOverlay;
-var AutoFillEditAddressOverlay = options.AutoFillEditAddressOverlay;
-var AutoFillEditCreditCardOverlay = options.AutoFillEditCreditCardOverlay;
-var AutoFillOptions = options.AutoFillOptions;
-var BrowserOptions = options.BrowserOptions;
-var ClearBrowserDataOverlay = options.ClearBrowserDataOverlay;
-var ContentSettings = options.ContentSettings;
-var CookiesView = options.CookiesView;
-var EditSearchEngineOverlay = options.EditSearchEngineOverlay;
-var FontSettings = options.FontSettings;
-var ImportDataOverlay = options.ImportDataOverlay;
-var InstantConfirmOverlay = options.InstantConfirmOverlay;
-var OptionsPage = options.OptionsPage;
-var PasswordsExceptions = options.PasswordsExceptions;
-var PersonalOptions = options.PersonalOptions;
-var Preferences = options.Preferences;
-var SearchEngineManager = options.SearchEngineManager;
-var SearchPage = options.SearchPage;
-var ProxyOptions = options.ProxyOptions;
-var SyncOptions = options.SyncOptions;
-
-/**
- * Window onload handler, sets up the page.
- */
-function load() {
- var start = new Date();
-
- var menuOffPattern = /(^\?|&)menu=off($|&)/;
- var menuDisabled = menuOffPattern.test(window.location.search);
- document.documentElement.setAttribute('hide-menu', menuDisabled);
-
- localStrings = new LocalStrings();
-
- OptionsPage.register(SearchPage.getInstance());
-
- if (cr.isChromeOS) {
- OptionsPage.register(SystemOptions.getInstance());
- OptionsPage.registerSubPage(AboutPage.getInstance(),
- SystemOptions.getInstance());
- OptionsPage.registerSubPage(LanguageOptions.getInstance(),
- SystemOptions.getInstance());
- OptionsPage.registerSubPage(
- new OptionsPage('languageChewing',
- localStrings.getString('languageChewingPage'),
- 'languageChewingPage'),
- SystemOptions.getInstance());
- OptionsPage.registerSubPage(
- new OptionsPage('languageHangul',
- localStrings.getString('languageHangulPage'),
- 'languageHangulPage'),
- SystemOptions.getInstance());
- OptionsPage.registerSubPage(
- new OptionsPage('languageMozc',
- localStrings.getString('languageMozcPage'),
- 'languageMozcPage'),
- SystemOptions.getInstance());
- OptionsPage.registerSubPage(
- new OptionsPage('languagePinyin',
- localStrings.getString('languagePinyinPage'),
- 'languagePinyinPage'),
- SystemOptions.getInstance());
- OptionsPage.register(InternetOptions.getInstance());
- }
-
- OptionsPage.register(BrowserOptions.getInstance());
- OptionsPage.registerSubPage(SearchEngineManager.getInstance(),
- BrowserOptions.getInstance());
- OptionsPage.register(PersonalOptions.getInstance());
- OptionsPage.registerSubPage(AutoFillOptions.getInstance(),
- PersonalOptions.getInstance());
- OptionsPage.registerSubPage(PasswordsExceptions.getInstance(),
- PersonalOptions.getInstance());
- OptionsPage.registerSubPage(SyncOptions.getInstance(),
- PersonalOptions.getInstance());
- OptionsPage.register(AdvancedOptions.getInstance());
- OptionsPage.registerSubPage(ContentSettings.getInstance(),
- AdvancedOptions.getInstance());
- OptionsPage.registerSubPage(CookiesView.getInstance(),
- AdvancedOptions.getInstance());
- OptionsPage.registerSubPage(FontSettings.getInstance(),
- AdvancedOptions.getInstance());
- if (!cr.isWindows && !cr.isMac) {
- OptionsPage.registerSubPage(CertificateManager.getInstance(),
- AdvancedOptions.getInstance());
- OptionsPage.registerOverlay(CertificateRestoreOverlay.getInstance());
- OptionsPage.registerOverlay(CertificateBackupOverlay.getInstance());
- OptionsPage.registerOverlay(CertificateEditCaTrustOverlay.getInstance());
- OptionsPage.registerOverlay(CertificateImportErrorOverlay.getInstance());
- }
- OptionsPage.registerOverlay(AddStartupPageOverlay.getInstance());
- OptionsPage.registerOverlay(AlertOverlay.getInstance());
- OptionsPage.registerOverlay(AutoFillEditAddressOverlay.getInstance());
- OptionsPage.registerOverlay(AutoFillEditCreditCardOverlay.getInstance());
- OptionsPage.registerOverlay(ClearBrowserDataOverlay.getInstance());
- OptionsPage.registerOverlay(EditSearchEngineOverlay.getInstance());
- OptionsPage.registerOverlay(ImportDataOverlay.getInstance());
- OptionsPage.registerOverlay(InstantConfirmOverlay.getInstance());
-
- if (cr.isChromeOS) {
- OptionsPage.register(AccountsOptions.getInstance());
- OptionsPage.registerSubPage(ProxyOptions.getInstance(),
- InternetOptions.getInstance());
- OptionsPage.registerOverlay(new OptionsPage(
- 'detailsInternetPage',
- 'detailsInternetPage',
- 'detailsInternetPage'));
- }
-
- var languageModifierKeysOverlay = new OptionsPage(
- 'languageCustomizeModifierKeysOverlay',
- localStrings.getString('languageCustomizeModifierKeysOverlay'),
- 'languageCustomizeModifierKeysOverlay')
- OptionsPage.registerOverlay(languageModifierKeysOverlay);
-
- Preferences.getInstance().initialize();
- OptionsPage.initialize();
-
- var path = document.location.pathname;
- var hash = document.location.hash;
-
- if (path.length > 1) {
- var pageName = path.slice(1);
- OptionsPage.showPageByName(pageName);
- if (hash.length > 1)
- OptionsPage.handleHashForPage(pageName, hash.slice(1));
- } else {
- // TODO(csilv): Save/restore last selected page.
- if (cr.isChromeOS) {
- OptionsPage.showPageByName(SystemOptions.getInstance().name);
- } else {
- OptionsPage.showPageByName(BrowserOptions.getInstance().name);
- }
- }
-
- var subpagesNavTabs = document.querySelectorAll('.subpages-nav-tabs');
- for(var i = 0; i < subpagesNavTabs.length; i++) {
- subpagesNavTabs[i].onclick = function(event) {
- OptionsPage.showTab(event.srcElement);
- }
- }
-
- // Allow platform specific CSS rules.
- if (cr.isMac)
- document.documentElement.setAttribute('os', 'mac');
- if (cr.isViews)
- document.documentElement.setAttribute('toolkit', 'views');
-
- var end = new Date();
- var total = end - start;
- console.log('time took to run load():'+ total);
-}
-
-document.addEventListener('DOMContentLoaded', load);
-
-window.onpopstate = function(e) {
- options.OptionsPage.setState(e.state);
-};
-</script>
-
-</head>
-<body i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
-<div class="header">
-</div>
-<div id="overlay" class="overlay hidden">
- <include src="options/add_startup_page_overlay.html">
- <include src="options/alert_overlay.html">
- <include src="options/autofill_edit_address_overlay.html">
- <include src="options/autofill_edit_creditcard_overlay.html">
- <include src="options/clear_browser_data_overlay.html">
- <include src="options/edit_search_engine_overlay.html">
- <include src="options/import_data_overlay.html">
- <include src="options/instant_confirm_overlay.html">
- <if expr="pp_ifdef('chromeos')">
- <include src="options/chromeos_language_add_language_overlay.html">
- <include
- src="options/chromeos_language_customize_modifier_keys_overlay.html">
- <include src="options/chromeos_internet_detail.html">
- </if>
- <if expr="not pp_ifdef('win32') and not pp_ifdef('darwin')">
- <include src="options/certificate_restore_overlay.html">
- <include src="options/certificate_backup_overlay.html">
- <include src="options/certificate_edit_ca_trust_overlay.html">
- <include src="options/certificate_import_error_overlay.html">
- </if>
-</div>
-<div id="main-content">
- <div id="navbar-container">
- <h1 id="settings-title" i18n-content="title"></h1>
- <ul id="navbar">
- </ul>
- </div>
- <div id="mainview">
- <div class="hidden" id="managed-prefs-banner">
- <span id="managed-prefs-icon"></span>
- <span id="managed-prefs-text"
- i18n-content="managedPrefsBannerText"></span>
- </div>
- <div id="mainview-content">
- <!-- Start main pages -->
- <!-- Please keep the main pages in desired order of display. This will
- allow search results to display in the desired order. -->
- <include src="options/search_page.html">
- <if expr="pp_ifdef('chromeos')">
- <include src="options/chromeos_system_options.html">
- <include src="options/chromeos_internet_options.html">
- <include src="options/chromeos_accounts_options.html">
- </if>
- <include src="options/browser_options.html">
- <include src="options/personal_options.html">
- <include src="options/advanced_options.html">
- <!-- End main pages -->
- <div id="subpage-sheet-container" class="hidden">
- <div id="subpage-sheet">
- <if expr="pp_ifdef('chromeos')">
- <include src="options/about_page.html">
- <include src="options/chromeos_language_options.html">
- <include src="options/chromeos_language_chewing_options.html">
- <include src="options/chromeos_language_hangul_options.html">
- <include src="options/chromeos_language_mozc_options.html">
- <include src="options/chromeos_language_pinyin_options.html">
- <include src="options/chromeos_proxy.html">
- </if>
- <if expr="not pp_ifdef('win32') and not pp_ifdef('darwin')">
- <include src="options/certificate_manager.html">
- </if>
- <include src="options/autofill_options.html">
- <include src="options/content_settings.html">
- <include src="options/cookies_view.html">
- <include src="options/font_settings.html">
- <include src="options/passwords_exceptions.html">
- <include src="options/search_engine_manager.html">
- <include src="options/sync_options.html">
- </div>
- </div>
- </div>
- </div>
-</div>
-
-<script>
-// Decorate the existing elements in the document.
-cr.ui.decorate('input[pref][type=checkbox]', options.PrefCheckbox);
-cr.ui.decorate('input[pref][type=number]', options.PrefNumber);
-cr.ui.decorate('input[pref][type=radio]', options.PrefRadio);
-cr.ui.decorate('input[pref][type=range]', options.PrefRange);
-cr.ui.decorate('select[pref]', options.PrefSelect);
-cr.ui.decorate('input[pref][type=text]', options.PrefTextField);
-cr.ui.decorate('input[pref][type=url]', options.PrefTextField);
-cr.ui.decorate('#contentSettingsPage input[type=radio]',
- options.ContentSettingsRadio);
-cr.ui.decorate('#fontSettingsMinimumSizeSelector',
- options.MinimumFontSizeSelect);
-console.log('in bottom script');
-</script>
-</body>
-</html>
diff --git a/chrome/browser/resources/options/add_startup_page_overlay.js b/chrome/browser/resources/options/add_startup_page_overlay.js
index 36eacae..659ef3b 100644
--- a/chrome/browser/resources/options/add_startup_page_overlay.js
+++ b/chrome/browser/resources/options/add_startup_page_overlay.js
@@ -34,7 +34,7 @@ cr.define('options', function() {
addForm.onreset = this.dismissOverlay_.bind(this);
addForm.onsubmit = function(e) {
var urlField = $('addStartupPageURL');
- BrowserOptions.addStartupPage(urlField.value);
+ StartupPageManager.addStartupPage(urlField.value);
self.dismissOverlay_();
return false;
diff --git a/chrome/browser/resources/options/add_startup_page_recent_pages_list.js b/chrome/browser/resources/options/add_startup_page_recent_pages_list.js
index 033f244..ff080f6 100644
--- a/chrome/browser/resources/options/add_startup_page_recent_pages_list.js
+++ b/chrome/browser/resources/options/add_startup_page_recent_pages_list.js
@@ -39,7 +39,7 @@ cr.define('options.add_startup_page', function() {
titleEl.className = 'title';
titleEl.classList.add('favicon-cell');
titleEl.style.backgroundImage = url('chrome://favicon/' +
- this.pageInfo['url']);
+ this.pageInfo['url']);
this.appendChild(titleEl);
if (this.pageInfo['title'].length > 0) {
titleEl.textContent = this.pageInfo['title'];
diff --git a/chrome/browser/resources/options/advanced_options.css b/chrome/browser/resources/options/advanced_options.css
index cfa8805..b897168 100644
--- a/chrome/browser/resources/options/advanced_options.css
+++ b/chrome/browser/resources/options/advanced_options.css
@@ -4,6 +4,6 @@
* found in the LICENSE file.
*/
-.disable-services-div {
+.informational-text {
color: grey;
}
diff --git a/chrome/browser/resources/options/advanced_options.html b/chrome/browser/resources/options/advanced_options.html
index 5e1f28c..06b1473 100644
--- a/chrome/browser/resources/options/advanced_options.html
+++ b/chrome/browser/resources/options/advanced_options.html
@@ -9,9 +9,14 @@
<button id="privacyClearDataButton"
i18n-content="privacyClearDataButton"></button>
</div>
- <div i18n-content="disableServices" class="disable-services-div"></div>
- <div><a target="_blank" i18n-content="learnMore"
- i18n-values="href:privacyLearnMoreURL"></a></div>
+ <div i18n-content="improveBrowsingExperience" class="informational-text">
+ </div>
+ <div>
+ <span i18n-content="disableWebServices" class="informational-text">
+ </span>
+ <a target="_blank" i18n-content="learnMore"
+ i18n-values="href:privacyLearnMoreURL"></a>
+ </div>
<label class="checkbox">
<input id="alternateErrorPagesEnabled" pref="alternate_error_pages.enabled"
metric="Options_LinkDoctorCheckbox" type="checkbox">
@@ -36,7 +41,8 @@
<label class="checkbox" id="metricsReportingSetting">
<input id="metricsReportingEnabled"
pref="cros.metrics.reportingEnabled" type="checkbox">
- <span i18n-content="enableLogging"></span>
+ <span i18n-content="enableLogging" id="metricsReportingEnabledText">
+ </span>
</label>
</if>
<if expr="pp_ifdef('_google_chrome') and not pp_ifdef('chromeos')">
@@ -57,10 +63,22 @@
<span i18n-content="tabsToLinksPref"></span>
</label>
</if>
- <div><button id="fontSettingsCustomizeFontsButton"
- i18n-content="fontSettingsCustomizeFontsButton"></button></div>
<div>
- <label style="display:inline;">
+ <label>
+ <span i18n-content="defaultFontSizeLabel"></span>
+ <select id="defaultFontSize">
+ <option value="9" i18n-content="fontSizeLabelVerySmall"></option>
+ <option value="12" i18n-content="fontSizeLabelSmall"></option>
+ <option value="16" i18n-content="fontSizeLabelMedium"></option>
+ <option value="20" i18n-content="fontSizeLabelLarge"></option>
+ <option value="24" i18n-content="fontSizeLabelVeryLarge"></option>
+ </select>
+ </label>
+ <button id="fontSettingsCustomizeFontsButton"
+ i18n-content="fontSettingsCustomizeFontsButton"></button>
+ </div>
+ <div>
+ <label>
<span i18n-content="defaultZoomLevelLabel"></span>
<select id="defaultZoomLevel">
<option value="-3">57%</option>
@@ -109,11 +127,13 @@
<h3 i18n-content="downloadLocationGroupName"></h3>
<div>
<if expr="not pp_ifdef('chromeos')">
- <div i18n-content="downloadLocationBrowseTitle"></div>
<div>
- <input id="downloadLocationPath" type="text" size="60" disabled>
- <button id="downloadLocationBrowseButton"
- i18n-content="downloadLocationBrowseButton"></button>
+ <label>
+ <span i18n-content="downloadLocationBrowseTitle"></span>
+ <input id="downloadLocationPath" type="text" size="60" disabled>
+ </label>
+ <button id="downloadLocationChangeButton"
+ i18n-content="downloadLocationChangeButton"></button>
</div>
<label class="checkbox">
<input id="promptForDownload" pref="download.prompt_for_download"
@@ -129,7 +149,6 @@
<section>
<h3 i18n-content="advancedSectionTitleSecurity"></h3>
<div>
- <div i18n-content="certificatesLabel"></div>
<div><button id="certificatesManageButton"
i18n-content="certificatesManageButton"></button></div>
<if expr="os == 'win32'">
@@ -139,10 +158,6 @@
<span i18n-content="sslCheckRevocation"></span>
</label>
<label class="checkbox">
- <input id="sslUseSSL2" type="checkbox">
- <span i18n-content="sslUseSSL2"></span>
- </label>
- <label class="checkbox">
<input id="sslUseSSL3" type="checkbox">
<span i18n-content="sslUseSSL3"></span>
</label>
@@ -159,11 +174,6 @@
<span i18n-content="sslCheckRevocation"></span>
</label>
<label class="checkbox">
- <input id="sslUseSSL2" pref="ssl.ssl2.enabled" metric="Options_SSL2"
- type="checkbox">
- <span i18n-content="sslUseSSL2"></span>
- </label>
- <label class="checkbox">
<input id="sslUseSSL3" pref="ssl.ssl3.enabled" metric="Options_SSL3"
type="checkbox">
<span i18n-content="sslUseSSL3"></span>
@@ -191,7 +201,4 @@
</div>
</section>
</if>
- <div class="button-strip">
- <button id="optionsReset" i18n-content="optionsReset"></button>
- </div>
</div>
diff --git a/chrome/browser/resources/options/advanced_options.js b/chrome/browser/resources/options/advanced_options.js
index 2ce9011..0d52a90 100644
--- a/chrome/browser/resources/options/advanced_options.js
+++ b/chrome/browser/resources/options/advanced_options.js
@@ -59,14 +59,11 @@ var OptionsPage = options.OptionsPage;
$('defaultZoomLevel').onchange = function(event) {
chrome.send('defaultZoomLevelAction',
[String(event.target.options[event.target.selectedIndex].value)]);
- }
- $('optionsReset').onclick = function(event) {
- AlertOverlay.show(undefined,
- localStrings.getString('optionsResetMessage'),
- localStrings.getString('optionsResetOkLabel'),
- localStrings.getString('optionsResetCancelLabel'),
- function() { chrome.send('resetToDefaults'); });
- }
+ };
+ $('defaultFontSize').onchange = function(event) {
+ chrome.send('defaultFontSizeAction',
+ [String(event.target.options[event.target.selectedIndex].value)]);
+ };
if (cr.isWindows || cr.isMac) {
$('certificatesManageButton').onclick = function(event) {
@@ -85,16 +82,16 @@ var OptionsPage = options.OptionsPage;
$('proxiesConfigureButton').onclick = function(event) {
chrome.send('showNetworkProxySettings');
};
- $('downloadLocationBrowseButton').onclick = function(event) {
+ $('downloadLocationChangeButton').onclick = function(event) {
chrome.send('selectDownloadLocation');
};
// Remove Windows-style accelerators from the Browse button label.
// TODO(csilv): Remove this after the accelerator has been removed from
// the localized strings file, pending removal of old options window.
- $('downloadLocationBrowseButton').textContent =
+ $('downloadLocationChangeButton').textContent =
localStrings.getStringWithoutAccelerator(
- 'downloadLocationBrowseButton');
+ 'downloadLocationChangeButton');
} else {
$('proxiesConfigureButton').onclick = function(event) {
OptionsPage.showPageByName('proxy');
@@ -108,10 +105,6 @@ var OptionsPage = options.OptionsPage;
chrome.send('checkRevocationCheckboxAction',
[String($('sslCheckRevocation').checked)]);
};
- $('sslUseSSL2').onclick = function(event) {
- chrome.send('useSSL2CheckboxAction',
- [String($('sslUseSSL2').checked)]);
- };
$('sslUseSSL3').onclick = function(event) {
chrome.send('useSSL3CheckboxAction',
[String($('sslUseSSL3').checked)]);
@@ -144,16 +137,6 @@ var OptionsPage = options.OptionsPage;
chrome.send('showCloudPrintManagePage');
};
}
- },
-
- /**
- * Show a 'restart required' alert.
- * @private
- */
- showRestartRequiredAlert_: function() {
- AlertOverlay.show(undefined,
- localStrings.getString('optionsRestartRequired'),
- undefined, '', undefined);
}
};
@@ -162,13 +145,12 @@ var OptionsPage = options.OptionsPage;
//
// Set the checked state of the metrics reporting checkbox.
- AdvancedOptions.SetMetricsReportingCheckboxState = function(checked,
- disabled, user_changed) {
+ AdvancedOptions.SetMetricsReportingCheckboxState = function(
+ checked, disabled) {
$('metricsReportingEnabled').checked = checked;
$('metricsReportingEnabled').disabled = disabled;
-
- if (user_changed)
- AdvancedOptions.getInstance().showRestartRequiredAlert_();
+ if (disabled)
+ $('metricsReportingEnabledText').className = 'disable-services-span';
}
AdvancedOptions.SetMetricsReportingSettingVisibility = function(visible) {
@@ -191,6 +173,31 @@ var OptionsPage = options.OptionsPage;
selectCtl.selectedIndex = 4; // 100%
};
+ // Set the font size selected item.
+ AdvancedOptions.SetFontSize = function(fixed_font_size_value,
+ font_size_value) {
+ var selectCtl = $('defaultFontSize');
+ if (fixed_font_size_value == font_size_value) {
+ for (var i = 0; i < selectCtl.options.length; i++) {
+ if (selectCtl.options[i].value == font_size_value) {
+ selectCtl.selectedIndex = i;
+ if ($('Custom'))
+ selectCtl.remove($('Custom').index);
+ return;
+ }
+ }
+ }
+
+ // Add/Select Custom Option in the font size label list.
+ if (!$('Custom')) {
+ var option = new Option(localStrings.getString('fontSizeLabelCustom'),
+ -1, false, true);
+ option.setAttribute("id", "Custom");
+ selectCtl.add(option);
+ }
+ $('Custom').selected = true;
+ };
+
// Set the download path.
AdvancedOptions.SetDownloadLocationPath = function(path) {
if (!cr.isChromeOS)
@@ -209,18 +216,12 @@ var OptionsPage = options.OptionsPage;
};
// Set the checked state for the sslCheckRevocation checkbox.
- AdvancedOptions.SetCheckRevocationCheckboxState = function(checked,
- disabled) {
+ AdvancedOptions.SetCheckRevocationCheckboxState = function(
+ checked, disabled) {
$('sslCheckRevocation').checked = checked;
$('sslCheckRevocation').disabled = disabled;
};
- // Set the checked state for the sslUseSSL2 checkbox.
- AdvancedOptions.SetUseSSL2CheckboxState = function(checked, disabled) {
- $('sslUseSSL2').checked = checked;
- $('sslUseSSL2').disabled = disabled;
- };
-
// Set the checked state for the sslUseSSL3 checkbox.
AdvancedOptions.SetUseSSL3CheckboxState = function(checked, disabled) {
$('sslUseSSL3').checked = checked;
diff --git a/chrome/browser/resources/options/alert_overlay.js b/chrome/browser/resources/options/alert_overlay.js
index 11b965d..9274a3b 100644
--- a/chrome/browser/resources/options/alert_overlay.js
+++ b/chrome/browser/resources/options/alert_overlay.js
@@ -68,9 +68,10 @@ cr.define('options', function() {
* callbacks.
* @param {string} title The alert title to display to the user.
* @param {string} message The alert message to display to the user.
- * @param {string} okTitle The title of the OK button. Can be undefined.
- * @param {string} cancelTitle The title of the cancel button. Can be
- * undefined.
+ * @param {string} okTitle The title of the OK button. If undefined or empty,
+ * no button is shown.
+ * @param {string} cancelTitle The title of the cancel button. If undefined or
+ * empty, no button is shown.
* @param {function} okCallback A function to be called when the user presses
* the ok button. The alert window will be closed automatically. Can be
* undefined.
@@ -78,27 +79,31 @@ cr.define('options', function() {
* presses the cancel button. The alert window will be closed
* automatically. Can be undefined.
*/
- AlertOverlay.show = function(title, message, okTitle, cancelTitle, okCallback,
- cancelCallback) {
+ AlertOverlay.show = function(
+ title, message, okTitle, cancelTitle, okCallback, cancelCallback) {
if (title != undefined) {
$('alertOverlayTitle').textContent = title;
$('alertOverlayTitle').style.display = 'block';
} else {
$('alertOverlayTitle').style.display = 'none';
}
+
if (message != undefined) {
$('alertOverlayMessage').textContent = message;
$('alertOverlayMessage').style.display = 'block';
} else {
$('alertOverlayMessage').style.display = 'none';
}
- $('alertOverlayOk').textContent =
- (okTitle != undefined ? okTitle
- : localStrings.getString('ok'));
- if (cancelTitle != '') {
- $('alertOverlayCancel').textContent =
- (cancelTitle != undefined ? cancelTitle
- : localStrings.getString('cancel'));
+
+ if (okTitle != undefined && okTitle != '') {
+ $('alertOverlayOk').textContent = okTitle;
+ $('alertOverlayOk').style.display = 'block';
+ } else {
+ $('alertOverlayOk').style.display = 'none';
+ }
+
+ if (cancelTitle != undefined && cancelTitle != '') {
+ $('alertOverlayCancel').textContent = cancelTitle;
$('alertOverlayCancel').style.display = 'inline';
} else {
$('alertOverlayCancel').style.display = 'none';
diff --git a/chrome/browser/resources/options/autofill_edit_address_overlay.js b/chrome/browser/resources/options/autofill_edit_address_overlay.js
index 46a17d0..5794daa 100644
--- a/chrome/browser/resources/options/autofill_edit_address_overlay.js
+++ b/chrome/browser/resources/options/autofill_edit_address_overlay.js
@@ -75,7 +75,7 @@ cr.define('options', function() {
address[10] = $('fax').value;
address[11] = $('email').value;
- chrome.send('updateAddress', address);
+ chrome.send('setAddress', address);
},
/**
diff --git a/chrome/browser/resources/options/autofill_edit_creditcard_overlay.js b/chrome/browser/resources/options/autofill_edit_creditcard_overlay.js
index 01b1722..c61255e 100644
--- a/chrome/browser/resources/options/autofill_edit_creditcard_overlay.js
+++ b/chrome/browser/resources/options/autofill_edit_creditcard_overlay.js
@@ -68,7 +68,7 @@ cr.define('options', function() {
creditCard[3] = $('expirationMonth').value;
creditCard[4] = $('expirationYear').value;
- chrome.send('updateCreditCard', creditCard);
+ chrome.send('setCreditCard', creditCard);
},
/**
diff --git a/chrome/browser/resources/options/autofill_options.css b/chrome/browser/resources/options/autofill_options.css
new file mode 100644
index 0000000..7ca1d45
--- /dev/null
+++ b/chrome/browser/resources/options/autofill_options.css
@@ -0,0 +1,12 @@
+.autofill-list-item {
+ -webkit-padding-start: 8px;
+}
+
+#autofill-options > div:last-child {
+ margin-top: 15px;
+}
+
+#autofill-options > div.settings-list > div:last-child {
+ border-top: 1px solid #D9D9D9;
+ padding: 5px 10px;
+}
diff --git a/chrome/browser/resources/options/autofill_options.html b/chrome/browser/resources/options/autofill_options.html
index 6e1d7a9..727c9ae 100644
--- a/chrome/browser/resources/options/autofill_options.html
+++ b/chrome/browser/resources/options/autofill_options.html
@@ -1,39 +1,22 @@
-<div class="page hidden" id="autoFillOptionsPage">
+<div id="autofill-options" class="page hidden">
<h1 i18n-content="autoFillOptionsTitle"></h1>
-
- <div class="autofill-section">
- <label class="checkbox">
- <input id="autoFillEnabled" pref="autofill.enabled"
- metric="Options_FormAutofill" type="checkbox">
- <span i18n-content="autoFillEnabled"></span>
- </label>
- </div>
-
- <div class="autofill-section" id="profileSelectContainer">
- <div id="profileSelectLeftColumn">
- <select id="profileList" size="10">
- <option value="addressesHeader" disabled
- i18n-content="addressesHeader"></option>
- <option value="addressesHorizontalRule" disabled></option>
- <option value="addressesBlankOption" disabled></option>
- <option value="creditCardsHeader" disabled
- i18n-content="creditCardsHeader"></option>
- <option value="creditCardsHorizontalRule" disabled></option>
- </select>
+ <h3 i18n-content="autoFillAddresses"></h3>
+ <div class="settings-list">
+ <list id="address-list"></list>
+ <div>
+ <button id="autofill-add-address" i18n-content="autoFillAddAddress">
+ </button>
</div>
- <div id="profileSelectRightColumn">
- <div><button id="addAddressButton" i18n-content="addAddressButton">
- </button></div>
- <div><button id="addCreditCardButton" i18n-content="addCreditCardButton">
- </button></div>
- <div><button id="autoFillEditButton" i18n-content="editButton">
- </button></div>
- <div><button id="autoFillRemoveButton" i18n-content="deleteButton">
- </button></div>
+ </div>
+ <h3 i18n-content="autoFillCreditCards"></h3>
+ <div class="settings-list">
+ <list id="creditcard-list"></list>
+ <div>
+ <button id="autofill-add-creditcard"
+ i18n-content="autoFillAddCreditCard"></button>
</div>
</div>
-
- <div class="autofill-section">
+ <div>
<if expr="pp_ifdef('chromeos')">
<a href="http://www.google.com/support/chromeos/bin/answer.py?answer=142893"
target="_blank" i18n-content="helpButton"></a>
diff --git a/chrome/browser/resources/options/autofill_options.js b/chrome/browser/resources/options/autofill_options.js
index 3b662f2..a3637c4 100644
--- a/chrome/browser/resources/options/autofill_options.js
+++ b/chrome/browser/resources/options/autofill_options.js
@@ -3,31 +3,22 @@
// found in the LICENSE file.
cr.define('options', function() {
- var OptionsPage = options.OptionsPage;
-
- // The offset of the first profile in either the address list or the credit
- // card list. Consists of the header and the horizontal rule.
- const addressOffset = 2;
- const creditCardOffset = 3;
+ const OptionsPage = options.OptionsPage;
+ const ArrayDataModel = cr.ui.ArrayDataModel;
+ const ListSingleSelectionModel = cr.ui.ListSingleSelectionModel;
/////////////////////////////////////////////////////////////////////////////
// AutoFillOptions class:
- //
- // TODO(jhawkins): Replace <select> with a DOMUI List.
/**
* Encapsulated handling of AutoFill options page.
* @constructor
*/
function AutoFillOptions() {
- this.numAddresses = 0;
- this.numCreditCards = 0;
- this.activeNavTab = null;
- this.addressGUIDs = null;
- this.creditCardGUIDs = null;
- OptionsPage.call(this, 'autoFillOptions',
+ OptionsPage.call(this,
+ 'autoFillOptions',
templateData.autoFillOptionsTitle,
- 'autoFillOptionsPage');
+ 'autofill-options');
}
cr.addSingletonGetter(AutoFillOptions);
@@ -35,32 +26,58 @@ cr.define('options', function() {
AutoFillOptions.prototype = {
__proto__: OptionsPage.prototype,
+ /**
+ * The address list.
+ * @type {DeletableItemList}
+ * @private
+ */
+ addressList_: null,
+
+ /**
+ * The credit card list.
+ * @type {DeletableItemList}
+ * @private
+ */
+ creditCardList_: null,
+
initializePage: function() {
OptionsPage.prototype.initializePage.call(this);
+ this.createAddressList_();
+ this.createCreditCardList_();
+
var self = this;
- $('profileList').onchange = function(event) {
- self.updateButtonState_();
- };
- $('profileList').addEventListener('dblclick', function(event) {
- if ($('autoFillEnabled').checked)
- self.editProfile_();
- });
- $('addAddressButton').onclick = function(event) {
+ $('autofill-add-address').onclick = function(event) {
self.showAddAddressOverlay_();
};
- $('addCreditCardButton').onclick = function(event) {
+ $('autofill-add-creditcard').onclick = function(event) {
self.showAddCreditCardOverlay_();
};
- $('autoFillEditButton').onclick = function(event) {
- self.editProfile_();
- };
- $('autoFillRemoveButton').onclick = function(event) {
- self.removeProfile_();
- };
- Preferences.getInstance().addEventListener('autofill.enabled',
- this.updateButtonState_.bind(this));
+ // TODO(jhawkins): What happens when AutoFill is disabled whilst on the
+ // AutoFill options page?
+ },
+
+ /**
+ * Creates, decorates and initializes the address list.
+ * @private
+ */
+ createAddressList_: function() {
+ this.addressList_ = $('address-list');
+ options.autoFillOptions.AutoFillList.decorate(this.addressList_);
+ this.addressList_.selectionModel = new ListSingleSelectionModel;
+ this.addressList_.autoExpands = true;
+ },
+
+ /**
+ * Creates, decorates and initializes the credit card list.
+ * @private
+ */
+ createCreditCardList_: function() {
+ this.creditCardList_ = $('creditcard-list');
+ options.autoFillOptions.AutoFillList.decorate(this.creditCardList_);
+ this.creditCardList_.selectionModel = new ListSingleSelectionModel;
+ this.creditCardList_.autoExpands = true;
},
/**
@@ -77,19 +94,6 @@ cr.define('options', function() {
},
/**
- * Shows the 'Edit address' overlay, using the data in |address| to fill the
- * input fields. |address| is a list with one item, an associative array
- * that contains the address data.
- * @private
- */
- showEditAddressOverlay_: function(address) {
- var title = localStrings.getString('editAddressTitle');
- AutoFillEditAddressOverlay.setTitle(title);
- AutoFillEditAddressOverlay.loadAddress(address[0]);
- OptionsPage.showOverlay('autoFillEditAddressOverlay');
- },
-
- /**
* Shows the 'Add credit card' overlay, specifically by loading the
* 'Edit credit card' overlay, emptying the input fields and modifying the
* overlay title.
@@ -103,175 +107,91 @@ cr.define('options', function() {
},
/**
- * Shows the 'Edit credit card' overlay, using the data in |credit_card| to
- * fill the input fields. |address| is a list with one item, an associative
- * array that contains the credit card data.
- * @private
- */
- showEditCreditCardOverlay_: function(creditCard) {
- var title = localStrings.getString('editCreditCardTitle');
- AutoFillEditCreditCardOverlay.setTitle(title);
- AutoFillEditCreditCardOverlay.loadCreditCard(creditCard[0]);
- OptionsPage.showOverlay('autoFillEditCreditCardOverlay');
- },
-
- /**
- * Resets the address list. This method leaves the header and horizontal
- * rule unchanged.
- * @private
- */
- resetAddresses_: function() {
- var profiles = $('profileList');
- for (var i = 0; i < this.numAddresses; ++i)
- profiles.remove(addressOffset);
- this.numAddresses = 0;
- },
-
- /**
- * Resets the credit card list. This method leaves the header and horizontal
- * rule unchanged.
- * @private
+ * Updates the data model for the address list with the values from
+ * |entries|.
+ * @param {Array} entries The list of addresses.
*/
- resetCreditCards_: function() {
- var profiles = $('profileList');
- var offset = this.numAddresses + addressOffset + creditCardOffset;
- for (var i = 0; i < this.numCreditCards; ++i)
- profiles.remove(offset);
- this.numCreditCards = 0;
+ setAddressList_: function(entries) {
+ this.addressList_.dataModel = new ArrayDataModel(entries);
},
/**
- * Updates the address list with the given entries.
- * @private
- * @param {Array} address List of addresses.
+ * Updates the data model for the credit card list with the values from
+ * |entries|.
+ * @param {Array} entries The list of credit cards.
*/
- updateAddresses_: function(addresses) {
- this.resetAddresses_();
- var profileList = $('profileList');
- var blankAddress = profileList.options[addressOffset];
- this.numAddresses = addresses.length;
- this.addressGUIDs = new Array(this.numAddresses);
- for (var i = 0; i < this.numAddresses; i++) {
- var address = addresses[i];
- var option = new Option(address['label']);
- this.addressGUIDs[i] = address['guid'];
- profileList.add(option, blankAddress);
- }
-
- this.updateButtonState_();
+ setCreditCardList_: function(entries) {
+ this.creditCardList_.dataModel = new ArrayDataModel(entries);
},
/**
- * Updates the credit card list with the given entries.
+ * Removes the AutoFill profile represented by |guid|.
+ * @param {String} guid The GUID of the profile to remove.
* @private
- * @param {Array} creditCards List of credit cards.
*/
- updateCreditCards_: function(creditCards) {
- this.resetCreditCards_();
- var profileList = $('profileList');
- this.numCreditCards = creditCards.length;
- this.creditCardGUIDs = new Array(this.numCreditCards);
- for (var i = 0; i < this.numCreditCards; i++) {
- var creditCard = creditCards[i];
- var option = new Option(creditCard['label']);
- this.creditCardGUIDs[i] = creditCard['guid'];
- profileList.add(option, null);
- }
-
- this.updateButtonState_();
+ removeAutoFillProfile_: function(guid) {
+ chrome.send('removeAutoFillProfile', [guid]);
},
/**
- * Sets the enabled state of the AutoFill Add Address and Credit Card
- * buttons on the current state of the |autoFillEnabled| checkbox.
- * Sets the enabled state of the AutoFill Edit and Remove buttons based on
- * the current selection in the profile list.
+ * Requests profile data for the profile represented by |guid| from the
+ * PersonalDataManager. Once the data is loaded, the AutoFillOptionsHandler
+ * calls showEdit[Address,CreditCard]Overlay(), depending on the type of the
+ * profile.
+ * @param {String} guid The GUID of the profile to edit.
* @private
*/
- updateButtonState_: function() {
- var disabled = !$('autoFillEnabled').checked;
- $('addAddressButton').disabled = disabled;
- $('addCreditCardButton').disabled = disabled;
- $('autoFillRemoveButton').disabled = $('autoFillEditButton').disabled =
- disabled || ($('profileList').selectedIndex == -1);
+ loadProfileEditor_: function(guid) {
+ chrome.send('loadProfileEditor', [guid]);
},
/**
- * Calls into the browser to load either an address or a credit card,
- * depending on the selected index. The browser calls back into either
- * editAddress() or editCreditCard() which show their respective editors.
- * @private
- */
- editProfile_: function() {
- var idx = $('profileList').selectedIndex;
- if ((profileIndex = this.getAddressIndex_(idx)) != -1) {
- chrome.send('editAddress', [this.addressGUIDs[profileIndex]]);
- } else if ((profileIndex = this.getCreditCardIndex_(idx)) != -1) {
- chrome.send('editCreditCard', [this.creditCardGUIDs[profileIndex]]);
- }
- },
-
- /**
- * Removes the currently selected profile, whether it's an address or a
- * credit card.
+ * Shows the 'Edit address' overlay, using the data in |address| to fill the
+ * input fields. |address| is a list with one item, an associative array
+ * that contains the address data.
* @private
*/
- removeProfile_: function() {
- var idx = $('profileList').selectedIndex;
- if ((profileIndex = this.getAddressIndex_(idx)) != -1)
- chrome.send('removeAddress', [this.addressGUIDs[profileIndex]]);
- else if ((profileIndex = this.getCreditCardIndex_(idx)) != -1)
- chrome.send('removeCreditCard', [this.creditCardGUIDs[profileIndex]]);
+ showEditAddressOverlay_: function(address) {
+ var title = localStrings.getString('editAddressTitle');
+ AutoFillEditAddressOverlay.setTitle(title);
+ AutoFillEditAddressOverlay.loadAddress(address[0]);
+ OptionsPage.showOverlay('autoFillEditAddressOverlay');
},
/**
- * Returns the index into the address list based on |index|, the index into
- * the select control. Returns -1 if this is not an address index.
+ * Shows the 'Edit credit card' overlay, using the data in |credit_card| to
+ * fill the input fields. |address| is a list with one item, an associative
+ * array that contains the credit card data.
* @private
*/
- getAddressIndex_: function(index) {
- index -= addressOffset;
- if (index >= 0 && index < this.numAddresses)
- return index;
-
- return -1;
+ showEditCreditCardOverlay_: function(creditCard) {
+ var title = localStrings.getString('editCreditCardTitle');
+ AutoFillEditCreditCardOverlay.setTitle(title);
+ AutoFillEditCreditCardOverlay.loadCreditCard(creditCard[0]);
+ OptionsPage.showOverlay('autoFillEditCreditCardOverlay');
},
+ };
- /**
- * Returns the index into the credit card list based on |index|, the index
- * into the select control. Returns -1 if this is not a credit card index.
- * @private
- */
- getCreditCardIndex_: function(index) {
- index -= addressOffset + this.numAddresses + creditCardOffset;
- if (index >= 0 && index < this.numCreditCards)
- return index;
+ AutoFillOptions.setAddressList = function(entries) {
+ AutoFillOptions.getInstance().setAddressList_(entries);
+ };
- return -1;
- },
+ AutoFillOptions.setCreditCardList = function(entries) {
+ AutoFillOptions.getInstance().setCreditCardList_(entries);
+ };
- /**
- * Returns true if |index| points to a credit card profile.
- * @private
- */
- profileIndexIsCreditCard_: function(index) {
- index -= addressOffset + this.numAddresses + creditCardOffset;
- return (index >= 0 && index < this.numCreditCards);
- }
+ AutoFillOptions.removeAutoFillProfile = function(guid) {
+ AutoFillOptions.getInstance().removeAutoFillProfile_(guid);
};
- AutoFillOptions.updateAddresses = function(addresses) {
- AutoFillOptions.getInstance().updateAddresses_(addresses);
+ AutoFillOptions.loadProfileEditor = function(guid) {
+ AutoFillOptions.getInstance().loadProfileEditor_(guid);
};
AutoFillOptions.editAddress = function(address) {
AutoFillOptions.getInstance().showEditAddressOverlay_(address);
};
- AutoFillOptions.updateCreditCards = function(creditCards) {
- AutoFillOptions.getInstance().updateCreditCards_(creditCards);
- };
-
AutoFillOptions.editCreditCard = function(creditCard) {
AutoFillOptions.getInstance().showEditCreditCardOverlay_(creditCard);
};
diff --git a/chrome/browser/resources/options/autofill_options_list.js b/chrome/browser/resources/options/autofill_options_list.js
new file mode 100644
index 0000000..10e0b64
--- /dev/null
+++ b/chrome/browser/resources/options/autofill_options_list.js
@@ -0,0 +1,71 @@
+// 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.
+
+cr.define('options.autoFillOptions', function() {
+ const DeletableItemList = options.DeletableItemList;
+ const DeletableItem = options.DeletableItem;
+ const List = cr.ui.List;
+
+ /**
+ * Creates a new AutoFill list item.
+ * @param {Array} entry An array of the form [guid, label].
+ * @constructor
+ * @extends {options.DeletableItem}
+ */
+ function AutoFillListItem(entry) {
+ var el = cr.doc.createElement('div');
+ el.guid = entry[0];
+ el.label = entry[1];
+ el.__proto__ = AutoFillListItem.prototype;
+ el.decorate();
+
+ return el;
+ }
+
+ AutoFillListItem.prototype = {
+ __proto__: DeletableItem.prototype,
+
+ /** @inheritDoc */
+ decorate: function() {
+ DeletableItem.prototype.decorate.call(this);
+
+ // The stored label.
+ var label = this.ownerDocument.createElement('div');
+ label.className = 'autofill-list-item';
+ label.textContent = this.label;
+ this.contentElement.appendChild(label);
+ },
+ };
+
+ /**
+ * Create a new AutoFill list.
+ * @constructor
+ * @extends {options.DeletableItemList}
+ */
+ var AutoFillList = cr.ui.define('list');
+
+ AutoFillList.prototype = {
+ __proto__: DeletableItemList.prototype,
+
+ /** @inheritDoc */
+ createItem: function(entry) {
+ return new AutoFillListItem(entry);
+ },
+
+ /** @inheritDoc */
+ activateItemAtIndex: function(index) {
+ AutoFillOptions.loadProfileEditor(this.dataModel.item(index)[0]);
+ },
+
+ /** @inheritDoc */
+ deleteItemAtIndex: function(index) {
+ AutoFillOptions.removeAutoFillProfile(this.dataModel.item(index)[0]);
+ },
+ };
+
+ return {
+ AutoFillListItem: AutoFillListItem,
+ AutoFillList: AutoFillList,
+ };
+});
diff --git a/chrome/browser/resources/options/autofill_options_page.css b/chrome/browser/resources/options/autofill_options_page.css
deleted file mode 100644
index 923479b..0000000
--- a/chrome/browser/resources/options/autofill_options_page.css
+++ /dev/null
@@ -1,15 +0,0 @@
-div.autofill-section {
- display: block;
- padding: 1em 0 0;
-}
-
-#profileSelectContainer {
- display: -webkit-box;
-}
-
-#profileSelectLeftColumn {
- -webkit-box-flex: 1;
-}
-#profileSelectLeftColumn select {
- width: 100%;
-}
diff --git a/chrome/browser/resources/options/browser_options.html b/chrome/browser/resources/options/browser_options.html
index 143f2e1..f31d364 100644
--- a/chrome/browser/resources/options/browser_options.html
+++ b/chrome/browser/resources/options/browser_options.html
@@ -1,4 +1,4 @@
-<div class="page hidden" id="browserPage">
+<div id="browserPage" class="page hidden">
<h1 i18n-content="browserPage"></h1>
<section id="startupSection">
<h3 i18n-content="startupGroupName"></h3>
@@ -14,19 +14,16 @@
<label class="radio"><input type="radio" name="startup" id="startupShowPagesButton"
pref="session.restore_on_startup" value="4"
metric="Options_Startup_Custom">
- <span i18n-content="startupShowPages"></span></label>
+ <span id="startupShowPagesLabel"
+ i18n-content="startupShowPages"></span></label>
<div class="suboption">
- <div class="left-side-table">
+ <div id="startupPageManagement" class="settings-list">
+ <list id="startupPagesShortList"></list>
<div>
- <list id="startupPages"></list>
- </div>
- <div>
- <div><button id="startupAddButton"
- i18n-content="startupAddButton"></button></div>
- <div><button id="startupRemoveButton"
- i18n-content="startupRemoveButton"></button></div>
- <div><button id="startupUseCurrentButton"
- i18n-content="startupUseCurrent"></button></div>
+ <button id="startupPageManagerButton"
+ i18n-content="startupManagePages"></button>
+ <button id="startupUseCurrentButton"
+ i18n-content="startupUseCurrent"></button>
</div>
</div>
</div>
@@ -72,7 +69,7 @@
onchange="BrowserOptions.getInstance().setDefaultSearchEngine()">
</select>
<button id="defaultSearchManageEnginesButton"
- i18n-content="defaultSearchManageEnginesLink"></button>
+ i18n-content="defaultSearchManageEngines"></button>
</div>
<label class="checkbox" id="instantOption">
<!-- TODO(estade): metric? -->
diff --git a/chrome/browser/resources/options/browser_options.js b/chrome/browser/resources/options/browser_options.js
index e6ec689..369ffb3 100644
--- a/chrome/browser/resources/options/browser_options.js
+++ b/chrome/browser/resources/options/browser_options.js
@@ -41,14 +41,12 @@ cr.define('options', function() {
OptionsPage.prototype.initializePage.call(this);
// Wire up controls.
- $('startupAddButton').onclick = function(event) {
- OptionsPage.showOverlay('addStartupPageOverlay');
- };
- $('startupRemoveButton').onclick =
- this.removeSelectedStartupPages_.bind(this);
$('startupUseCurrentButton').onclick = function(event) {
chrome.send('setStartupPagesToCurrentPages');
};
+ $('startupPageManagerButton').onclick = function(event) {
+ OptionsPage.showPageByName('startupPages');
+ };
$('defaultSearchManageEnginesButton').onclick = function(event) {
OptionsPage.showPageByName('searchEngines');
chrome.send('coreOptionsUserMetricsAction',
@@ -85,25 +83,15 @@ cr.define('options', function() {
};
}
- var list = $('startupPages');
+ var list = $('startupPagesShortList');
options.browser_options.StartupPageList.decorate(list);
+ list.autoExpands = true;
list.selectionModel = new ListSelectionModel;
- list.selectionModel.addEventListener(
- 'change', this.updateRemoveButtonState_.bind(this));
-
- this.addEventListener('visibleChange', function(event) {
- $('startupPages').redraw();
- });
-
// Check if we are in the guest mode.
if (cr.commandLine.options['--bwsi']) {
- // Disable input and button elements under the startup section.
- var elements = $('startupSection').querySelectorAll('input, button');
- for (var i = 0; i < elements.length; i++) {
- elements[i].disabled = true;
- elements[i].manually_disabled = true;
- }
+ // Hide the startup section.
+ $('startupSection').classList.add('hidden');
} else {
// Initialize control enabled states.
Preferences.getInstance().addEventListener('session.restore_on_startup',
@@ -115,13 +103,6 @@ cr.define('options', function() {
this.updateCustomStartupPageControlStates_();
}
-
- // Remove Windows-style accelerators from button labels.
- // TODO(stuartmorgan): Remove this once the strings are updated.
- $('startupAddButton').textContent =
- localStrings.getStringWithoutAccelerator('startupAddButton');
- $('startupRemoveButton').textContent =
- localStrings.getStringWithoutAccelerator('startupRemoveButton');
},
/**
@@ -187,8 +168,19 @@ cr.define('options', function() {
* @param {Array} pages List of startup pages.
*/
updateStartupPages_: function(pages) {
- $('startupPages').dataModel = new ArrayDataModel(pages);
- this.updateRemoveButtonState_();
+ var list = $('startupPagesShortList');
+ list.dataModel = new ArrayDataModel(pages);
+ if (pages.length > 0 && pages.length <= 10) {
+ list.classList.remove("hidden");
+ $('startupPageManagement').classList.add('settings-list');
+ $('startupShowPagesLabel').textContent =
+ localStrings.getStringWithoutAccelerator('startupShowPages');
+ } else {
+ list.classList.add("hidden");
+ $('startupPageManagement').classList.remove('settings-list');
+ $('startupShowPagesLabel').textContent =
+ localStrings.getStringWithoutAccelerator('startupShowManyPages');
+ }
},
/**
@@ -350,39 +342,9 @@ cr.define('options', function() {
*/
updateCustomStartupPageControlStates_: function() {
var disable = !this.shouldEnableCustomStartupPageControls_();
- $('startupAddButton').disabled = disable;
+ $('startupPagesShortList').disabled = disable;
$('startupUseCurrentButton').disabled = disable;
- this.updateRemoveButtonState_();
- },
-
- /**
- * Sets the enabled state of the startup page Remove button based on
- * the current selection in the startup pages list.
- * @private
- */
- updateRemoveButtonState_: function() {
- var groupEnabled = this.shouldEnableCustomStartupPageControls_();
- $('startupRemoveButton').disabled = !groupEnabled ||
- ($('startupPages').selectionModel.selectedIndex == -1);
- },
-
- /**
- * Removes the selected startup pages.
- * @private
- */
- removeSelectedStartupPages_: function() {
- var selections =
- $('startupPages').selectionModel.selectedIndexes.map(String);
- chrome.send('removeStartupPages', selections);
- },
-
- /**
- * Adds the given startup page at the current selection point.
- * @private
- */
- addStartupPage_: function(url) {
- var firstSelection = $('startupPages').selectionModel.selectedIndex;
- chrome.send('addStartupPage', [url, String(firstSelection)]);
+ $('startupPageManagerButton').disabled = disable;
},
/**
@@ -413,10 +375,7 @@ cr.define('options', function() {
BrowserOptions.updateStartupPages = function(pages) {
BrowserOptions.getInstance().updateStartupPages_(pages);
- };
-
- BrowserOptions.addStartupPage = function(url) {
- BrowserOptions.getInstance().addStartupPage_(url);
+ StartupPageManager.getInstance().updateStartupPages_(pages);
};
// Export
diff --git a/chrome/browser/resources/options/browser_options_page.css b/chrome/browser/resources/options/browser_options_page.css
index 34864ca..67e078f 100644
--- a/chrome/browser/resources/options/browser_options_page.css
+++ b/chrome/browser/resources/options/browser_options_page.css
@@ -1,6 +1,7 @@
-#startupPages {
- border: solid 1px #999999;
- height: 100px;
+
+#startupPageManagement.settings-list > :last-child {
+ border-top: 1px solid #d9d9d9;
+ padding: 5px 10px;
}
#customHomePageGroup {
@@ -32,6 +33,7 @@
#defaultSearchEngine {
display: block;
-webkit-box-flex: 1;
+ max-width: 300px;
}
#defaultSearchManageEnginesButton {
diff --git a/chrome/browser/resources/options/browser_options_startup_page_list.js b/chrome/browser/resources/options/browser_options_startup_page_list.js
index 85afdc9..8265e13 100644
--- a/chrome/browser/resources/options/browser_options_startup_page_list.js
+++ b/chrome/browser/resources/options/browser_options_startup_page_list.js
@@ -3,8 +3,8 @@
// found in the LICENSE file.
cr.define('options.browser_options', function() {
- const List = cr.ui.List;
- const ListItem = cr.ui.ListItem;
+ const DeletableItemList = options.DeletableItemList;
+ const DeletableItem = options.DeletableItem;
/**
* Creates a new startup page list item.
@@ -29,11 +29,11 @@ cr.define('options.browser_options', function() {
};
StartupPageListItem.prototype = {
- __proto__: ListItem.prototype,
+ __proto__: DeletableItem.prototype,
/** @inheritDoc */
decorate: function() {
- ListItem.prototype.decorate.call(this);
+ DeletableItem.prototype.decorate.call(this);
var titleEl = this.ownerDocument.createElement('span');
titleEl.className = 'title';
@@ -43,19 +43,24 @@ cr.define('options.browser_options', function() {
this.pageInfo_['url']);
titleEl.title = this.pageInfo_['tooltip'];
- this.appendChild(titleEl);
+ this.contentElement.appendChild(titleEl);
},
};
var StartupPageList = cr.ui.define('list');
StartupPageList.prototype = {
- __proto__: List.prototype,
+ __proto__: DeletableItemList.prototype,
/** @inheritDoc */
createItem: function(pageInfo) {
return new StartupPageListItem(pageInfo);
},
+
+ /** @inheritDoc */
+ deleteItemAtIndex: function(index) {
+ chrome.send('removeStartupPages', [String(index)]);
+ },
};
return {
diff --git a/chrome/browser/resources/options/certificate_manager.js b/chrome/browser/resources/options/certificate_manager.js
index 145cfcb..0209053 100644
--- a/chrome/browser/resources/options/certificate_manager.js
+++ b/chrome/browser/resources/options/certificate_manager.js
@@ -93,10 +93,9 @@ cr.define('options', function() {
AlertOverlay.show(
localStrings.getStringF(id + 'DeleteConfirm', data.name),
localStrings.getString(id + 'DeleteImpact'),
- undefined,
- undefined,
- function() { chrome.send('deleteCertificate', [data.id]); }
- );
+ localStrings.getString('ok'),
+ localStrings.getString('cancel'),
+ function() { chrome.send('deleteCertificate', [data.id]); });
}
}
diff --git a/chrome/browser/resources/options/chromeos_accounts_options.html b/chrome/browser/resources/options/chromeos_accounts_options.html
index 8519757..42b5f2e 100644
--- a/chrome/browser/resources/options/chromeos_accounts_options.html
+++ b/chrome/browser/resources/options/chromeos_accounts_options.html
@@ -2,6 +2,11 @@
<h1 i18n-content="accountsPage"></h1>
<section>
<div class="option">
+ <div id="ownerOnlyWarning" class="hidden">
+ <span id="warningIcon"></span>
+ <span i18n-content="owner_only"></span>
+ <span i18n-content="owner_user_id"></span>
+ </div>
<table class="option-control-table">
<tr>
<td class="option-name">
@@ -24,9 +29,9 @@
<tr>
<td class="option-name">
<label class="checkbox">
- <input id="allowGuestCheck" pref="cros.accounts.allowGuest"
- type="checkbox">
- <span i18n-content="allow_guest"></span>
+ <input id="useWhitelistCheck" pref="cros.accounts.allowGuest"
+ type="checkbox" inverted_pref>
+ <span i18n-content="use_whitelist"></span>
</label>
</td>
</tr>
diff --git a/chrome/browser/resources/options/chromeos_accounts_options.js b/chrome/browser/resources/options/chromeos_accounts_options.js
index 1cc5b5c..1a978c6 100644
--- a/chrome/browser/resources/options/chromeos_accounts_options.js
+++ b/chrome/browser/resources/options/chromeos_accounts_options.js
@@ -41,11 +41,15 @@ cr.define('options', function() {
userList.disabled =
userNameEdit.disabled = !AccountsOptions.currentUserIsOwner();
+ // If the current user is not the owner, show some warning.
+ if (!AccountsOptions.currentUserIsOwner()) {
+ $('ownerOnlyWarning').classList.remove('hidden');
+ }
this.addEventListener('visibleChange', this.handleVisibleChange_);
- $('allowGuestCheck').addEventListener('click',
- this.handleAllowGuestCheckClick_);
+ $('useWhitelistCheck').addEventListener('click',
+ this.handleUseWhitelistCheckClick_);
},
/**
@@ -65,9 +69,9 @@ cr.define('options', function() {
* Handler for allow guest check click.
* @private
*/
- handleAllowGuestCheckClick_: function(e) {
+ handleUseWhitelistCheckClick_: function(e) {
// Whitelist existing users when guest login is being disabled.
- if (!$('allowGuestCheck').checked) {
+ if ($('useWhitelistCheck').checked) {
chrome.send('whitelistExistingUsers', []);
}
},
diff --git a/chrome/browser/resources/options/chromeos_accounts_options_page.css b/chrome/browser/resources/options/chromeos_accounts_options_page.css
index f92132f..10aa695 100644
--- a/chrome/browser/resources/options/chromeos_accounts_options_page.css
+++ b/chrome/browser/resources/options/chromeos_accounts_options_page.css
@@ -78,6 +78,22 @@ html[dir=rtl] .remove-user-button {
width: 366px;
}
+#ownerOnlyWarning {
+ margin-bottom: 10px;
+}
+
+#ownerOnlyWarning > * {
+ vertical-align: middle;
+}
+
+#warningIcon {
+ width: 17px;
+ height: 17px;
+ display: inline-block;
+ background-repeat: no-repeat;
+ background-image: url('warning.png');
+}
+
input#userNameEdit:invalid {
background-color: #ff6666;
}
diff --git a/chrome/browser/resources/options/chromeos_accounts_user_name_edit.js b/chrome/browser/resources/options/chromeos_accounts_user_name_edit.js
index a590d81..df94754 100644
--- a/chrome/browser/resources/options/chromeos_accounts_user_name_edit.js
+++ b/chrome/browser/resources/options/chromeos_accounts_user_name_edit.js
@@ -14,12 +14,15 @@ cr.define('options.accounts', function() {
// e.g. 'john@chromium.org'
// {name: 'john', email: 'john@chromium.org'}
const format2String =
- '^\\s*([\\w\\.!#\\$%&\'\\*\\+-\\/=\\?\\^`\\{\\|\\}~]+)@(\\w+\\..+)\\s*$';
+ '^\\s*([\\w\\.!#\\$%&\'\\*\\+-\\/=\\?\\^`\\{\\|\\}~]+)@' +
+ '([A-Za-z0-9\-]{2,63}\\..+)\\s*$';
// Full format.
// e.g. '"John Doe" <john@chromium.org>'
// {name: 'John doe', email: 'john@chromium.org'}
const format3String =
- '^\\s*"{0,1}([^"]+)"{0,1}\\s*<([^@]+@\\w+\\..+)>\\s*$';
+ '^\\s*"{0,1}([^"]+)"{0,1}\\s*' +
+ '<([\\w\\.!#\\$%&\'\\*\\+-\\/=\\?\\^`\\{\\|\\}~]+@' +
+ '[A-Za-z0-9\-]{2,63}\\..+)>\\s*$';
/**
* Creates a new user name edit element.
diff --git a/chrome/browser/resources/options/chromeos_internet_detail.html b/chrome/browser/resources/options/chromeos_internet_detail.html
index b32558e..18245ea 100644
--- a/chrome/browser/resources/options/chromeos_internet_detail.html
+++ b/chrome/browser/resources/options/chromeos_internet_detail.html
@@ -69,7 +69,7 @@
<table class="option-control-table">
<tr>
<td class="option-name" i18n-content="inetIdent"></td>
- <td class="option-value"><input id="inetIdentPkcs"></td>
+ <td id="inetIdentPkcs" class="option-value"></td>
</tr>
<tr>
<td class="option-name" i18n-content="inetCert"></td>
@@ -95,10 +95,6 @@
<tr class="no-plan-info">
<td i18n-content="noPlansFound" class="option-value"></td>
</tr>
- <tr class="needs-plan">
- <td class="option-value"><button id="purchaseMore"
- i18n-content="purchaseMore"></button></td>
- </tr>
</table>
</div>
<div id="planList"></div>
@@ -238,9 +234,11 @@
<div class="action-area button-strip">
<button id="detailsInternetDismiss"
i18n-content="detailsInternetDismiss"></button>
- <button id="detailsInternetOk"
- i18n-content="detailsInternetOk"></button>
<button id="detailsInternetLogin"
- i18n-content="inetLogin"></button>
+ i18n-content="connect_button"></button>
+ <button id="activateDetails"
+ i18n-content="activate_button"></button>
+ <button id="buyplanDetails"
+ i18n-content="buyplan_button"></button>
</div>
</div>
diff --git a/chrome/browser/resources/options/chromeos_internet_network_element.js b/chrome/browser/resources/options/chromeos_internet_network_element.js
index e5facb2..5d9da41 100644
--- a/chrome/browser/resources/options/chromeos_internet_network_element.js
+++ b/chrome/browser/resources/options/chromeos_internet_network_element.js
@@ -3,6 +3,30 @@
// found in the LICENSE file.
cr.define('options.internet', function() {
+
+ /**
+ * Network settings constants. These enums usually match their C++
+ * counterparts.
+ */
+ function Constants() {}
+ // Minimum length for wireless network password.
+ Constants.MIN_WIRELESS_PASSWORD_LENGTH = 5;
+ // Minimum length for SSID name.
+ Constants.MIN_WIRELESS_SSID_LENGTH = 1;
+ // Cellular activation states:
+ Constants.ACTIVATION_STATE_UNKNOWN = 0;
+ Constants.ACTIVATION_STATE_ACTIVATED = 1;
+ Constants.ACTIVATION_STATE_ACTIVATING = 2;
+ Constants.ACTIVATION_STATE_NOT_ACTIVATED = 3;
+ Constants.ACTIVATION_STATE_PARTIALLY_ACTIVATED = 4;
+ // Network types:
+ Constants.TYPE_UNKNOWN = 0;
+ Constants.TYPE_ETHERNET = 1;
+ Constants.TYPE_WIFI = 2;
+ Constants.TYPE_WIMAX = 3;
+ Constants.TYPE_BLUETOOTH = 4;
+ Constants.TYPE_CELLULAR = 5;
+
/**
* Creates a new network list div.
* @param {Object=} opt_propertyBag Optional properties.
@@ -115,25 +139,6 @@ cr.define('options.internet', function() {
/**
- * Minimum length for wireless network password.
- * @type {number}
- */
- NetworkItem.MIN_WIRELESS_PASSWORD_LENGTH = 5;
- NetworkItem.MIN_WIRELESS_SSID_LENGTH = 1;
- // Cellular activation states:
- NetworkItem.ACTIVATION_STATE_UNKNOWN = 0;
- NetworkItem.ACTIVATION_STATE_ACTIVATED = 1;
- NetworkItem.ACTIVATION_STATE_ACTIVATING = 2;
- NetworkItem.ACTIVATION_STATE_NOT_ACTIVATED = 3;
- NetworkItem.ACTIVATION_STATE_PARTIALLY_ACTIVATED = 4;
- NetworkItem.TYPE_UNKNOWN = 0;
- NetworkItem.TYPE_ETHERNET = 1;
- NetworkItem.TYPE_WIFI = 2;
- NetworkItem.TYPE_WIMAX = 3;
- NetworkItem.TYPE_BLUETOOTH = 4;
- NetworkItem.TYPE_CELLULAR = 5;
-
- /**
* Decorates an element as a network item.
* @param {!HTMLElement} el The element to decorate.
*/
@@ -188,28 +193,15 @@ cr.define('options.internet', function() {
var self = this;
if (!this.data.remembered) {
var no_plan =
- this.data.networkType == NetworkItem.TYPE_CELLULAR &&
+ this.data.networkType == Constants.TYPE_CELLULAR &&
this.data.needs_new_plan;
var show_activate =
- (this.data.networkType == NetworkItem.TYPE_CELLULAR &&
+ (this.data.networkType == Constants.TYPE_CELLULAR &&
this.data.activation_state !=
- NetworkItem.ACTIVATION_STATE_ACTIVATED &&
+ Constants.ACTIVATION_STATE_ACTIVATED &&
this.data.activation_state !=
- NetworkItem.ACTIVATION_STATE_ACTIVATING);
+ Constants.ACTIVATION_STATE_ACTIVATING);
- // Disconnect button if not ethernet and if cellular it should be
- // activated.
- if (this.data.networkType != NetworkItem.TYPE_ETHERNET &&
- !show_activate && this.data.connected) {
- buttonsDiv.appendChild(
- this.createButton_('disconnect_button', 'disconnect',
- function(e) {
- chrome.send('buttonClickCallback',
- [String(self.data.networkType),
- self.data.servicePath,
- 'disconnect']);
- }));
- }
// Show [Activate] button for non-activated Cellular network.
if (show_activate || no_plan) {
var button_name = no_plan ? 'buyplan_button' : 'activate_button';
@@ -222,11 +214,23 @@ cr.define('options.internet', function() {
'activate']);
}));
}
+ // Show disconnect button if not ethernet.
+ if (this.data.networkType != Constants.TYPE_ETHERNET &&
+ this.data.connected) {
+ buttonsDiv.appendChild(
+ this.createButton_('disconnect_button', 'disconnect',
+ function(e) {
+ chrome.send('buttonClickCallback',
+ [String(self.data.networkType),
+ self.data.servicePath,
+ 'disconnect']);
+ }));
+ }
if (!this.data.connected && !this.data.connecting &&
this.data.connectable) {
// connect button (if not ethernet and not showing activate button
// and connectable)
- if (this.data.networkType != NetworkItem.TYPE_ETHERNET &&
+ if (this.data.networkType != Constants.TYPE_ETHERNET &&
!show_activate && !no_plan) {
buttonsDiv.appendChild(
this.createButton_('connect_button', 'connect',
@@ -239,7 +243,7 @@ cr.define('options.internet', function() {
}
}
if (this.data.connected ||
- this.data.networkType == NetworkItem.TYPE_CELLULAR) {
+ this.data.networkType == Constants.TYPE_CELLULAR) {
buttonsDiv.appendChild(
this.createButton_('options_button', 'options',
function(e) {
@@ -305,7 +309,7 @@ cr.define('options.internet', function() {
// Disable login button if there is no password.
passInput.addEventListener('keyup', function(e) {
buttonEl.disabled =
- passInput.value.length < NetworkItem.MIN_WIRELESS_PASSWORD_LENGTH;
+ passInput.value.length < Constants.MIN_WIRELESS_PASSWORD_LENGTH;
});
passwordDiv.appendChild(buttonEl);
@@ -414,10 +418,10 @@ cr.define('options.internet', function() {
// Disable login button if ssid is not long enough or
// password is not long enough (unless no security)
var ssid_good =
- ssidInput.value.length >= NetworkItem.MIN_WIRELESS_SSID_LENGTH;
+ ssidInput.value.length >= Constants.MIN_WIRELESS_SSID_LENGTH;
var pass_good =
securityInput.value == 'none' ||
- passInput.value.length >= NetworkItem.MIN_WIRELESS_PASSWORD_LENGTH;
+ passInput.value.length >= Constants.MIN_WIRELESS_PASSWORD_LENGTH;
buttonEl.disabled = !ssid_good || !pass_good;
};
ssidInput.addEventListener('keyup', keyup_listener);
@@ -494,6 +498,7 @@ cr.define('options.internet', function() {
cr.defineProperty(NetworkItem, 'connectable', cr.PropertyKind.BOOL_ATTR);
return {
+ Constants: Constants,
NetworkElement: NetworkElement
};
});
diff --git a/chrome/browser/resources/options/chromeos_internet_options.js b/chrome/browser/resources/options/chromeos_internet_options.js
index 2c6efef..37556f9 100644
--- a/chrome/browser/resources/options/chromeos_internet_options.js
+++ b/chrome/browser/resources/options/chromeos_internet_options.js
@@ -44,35 +44,35 @@ cr.define('options', function() {
$('wirelessSection').hidden = (templateData.wirelessList.length == 0);
$('rememberedSection').hidden = (templateData.rememberedList.length == 0);
InternetOptions.setupAttributes(templateData);
- // Setting up the details page
- $('detailsInternetOk').onclick = function(event) {
- InternetOptions.setDetails();
- };
- $('detailsInternetDismiss').onclick = function(event) {
- OptionsPage.clearOverlays();
- };
- $('detailsInternetLogin').onclick = function(event) {
- InternetOptions.loginFromDetails();
- };
- $('enableWifi').onclick = function(event) {
+ $('detailsInternetDismiss').addEventListener('click', function(event) {
+ OptionsPage.clearOverlays();
+ });
+ $('detailsInternetLogin').addEventListener('click', function(event) {
+ InternetOptions.loginFromDetails();
+ });;
+ $('activateDetails').addEventListener('click', function(event) {
+ InternetOptions.activateFromDetails();
+ });
+ $('enableWifi').addEventListener('click', function(event) {
event.target.disabled = true;
chrome.send('enableWifi', []);
- };
- $('disableWifi').onclick = function(event) {
+ });
+ $('disableWifi').addEventListener('click', function(event) {
event.target.disabled = true;
chrome.send('disableWifi', []);
- };
- $('enableCellular').onclick = function(event) {
+ });
+ $('enableCellular').addEventListener('click', function(event) {
event.target.disabled = true;
chrome.send('enableCellular', []);
- };
- $('disableCellular').onclick = function(event) {
+ });
+ $('disableCellular').addEventListener('click', function(event) {
event.target.disabled = true;
chrome.send('disableCellular', []);
- };
- $('purchaseMore').onclick = function(event) {
+ });
+ $('buyplanDetails').addEventListener('click', function(event) {
chrome.send('buyDataPlan', []);
- };
+ OptionsPage.clearOverlays();
+ });
this.showNetworkDetails_();
},
@@ -100,35 +100,32 @@ cr.define('options', function() {
InternetOptions.loginFromDetails = function () {
var data = $('inetAddress').data;
var servicePath = data.servicePath;
- if (data.certInPkcs) {
- chrome.send('loginToCertNetwork',[String(servicePath),
- String(data.certPath),
- String($('inetIdentPkcs').value)]);
- } else {
- chrome.send('loginToCertNetwork',[String(servicePath),
- String($('inetCert').value),
- String($('inetIdent').value),
- String($('inetCertPass').value)]);
+ if (data.type == options.internet.Constants.TYPE_WIFI) {
+ if (data.certInPkcs) {
+ chrome.send('loginToCertNetwork',[String(servicePath),
+ String(data.certPath),
+ String(data.ident)]);
+ } else {
+ chrome.send('loginToCertNetwork',[String(servicePath),
+ String($('inetCert').value),
+ String($('inetIdent').value),
+ String($('inetCertPass').value)]);
+ }
+ } else if (data.type == options.internet.Constants.TYPE_CELLULAR) {
+ chrome.send('buttonClickCallback', [String(data.type),
+ servicePath,
+ 'connect']);
}
OptionsPage.clearOverlays();
};
- InternetOptions.setDetails = function() {
+ InternetOptions.activateFromDetails = function () {
var data = $('inetAddress').data;
- if (data.type == 2) {
- var newinfo = [];
- newinfo.push(data.servicePath);
- newinfo.push($('autoConnectNetwork').checked ? "true" : "false");
- if (data.encrypted && data.certNeeded) {
- if (data.certInPkcs) {
- newinfo.push($('inetIdentPkcs').value);
- } else {
- newinfo.push($('inetIdent').value);
- newinfo.push($('inetCert').value);
- newinfo.push($('inetCertPass').value);
- }
- }
- chrome.send('setDetails', newinfo);
+ var servicePath = data.servicePath;
+ if (data.type == options.internet.Constants.TYPE_CELLULAR) {
+ chrome.send('buttonClickCallback', [String(data.type),
+ servicePath,
+ 'activate']);
}
OptionsPage.clearOverlays();
};
@@ -211,6 +208,11 @@ cr.define('options', function() {
} else {
page.removeAttribute('hasactiveplan');
}
+ if (data.activated) {
+ page.setAttribute('activated', true);
+ } else {
+ page.removeAttribute('activated');
+ }
// Nudge webkit so that it redraws the details overlay page.
// See http://crosbug.com/9616 for details.
@@ -285,7 +287,7 @@ cr.define('options', function() {
if (data.certNeeded) {
if (data.certInPkcs) {
page.setAttribute('certPkcs', true);
- $('inetIdentPkcs').value = data.ident;
+ $('inetIdentPkcs').textContent = data.ident;
} else {
page.setAttribute('cert', true);
$('inetIdent').value = data.ident;
@@ -328,9 +330,14 @@ cr.define('options', function() {
page.setAttribute('gsm', true);
}
page.removeAttribute('hascellplan');
- page.removeAttribute('nocellplan');
- page.setAttribute('cellplanloading', true);
- chrome.send('refreshCellularPlan', [data.servicePath])
+ if (data.connected) {
+ page.removeAttribute('nocellplan');
+ page.setAttribute('cellplanloading', true);
+ chrome.send('refreshCellularPlan', [data.servicePath])
+ } else {
+ page.setAttribute('nocellplan', true);
+ page.removeAttribute('cellplanloading');
+ }
} else {
OptionsPage.showTab($('internetNavTab'));
page.setAttribute('ethernet', true);
diff --git a/chrome/browser/resources/options/chromeos_internet_options_page.css b/chrome/browser/resources/options/chromeos_internet_options_page.css
index 1fc4b30..82e1fc2 100644
--- a/chrome/browser/resources/options/chromeos_internet_options_page.css
+++ b/chrome/browser/resources/options/chromeos_internet_options_page.css
@@ -153,21 +153,27 @@ html[dir='rtl'] .details-button {
#detailsInternetPage:not([connected]) > #advancedSection,
#detailsInternetPage[connecting] > * > #detailsInternetLogin,
#detailsInternetPage[connected] > * > #detailsInternetLogin,
+#detailsInternetPage:not([connected]) > * > #buyplanDetails,
#detailsInternetPage:not([wireless]) > * > #detailsInternetOk,
#detailsInternetPage[ethernet] .wifi-details,
#detailsInternetPage[ethernet] .cellular-details,
#detailsInternetPage[cellular] .wifi-details,
+#detailsInternetPage:not([cellular]) > * > #activateDetails,
+#detailsInternetPage:not([cellular]) > * > #buyplanDetails,
#detailsInternetPage[wireless] .cellular-details,
#detailsInternetPage[cellplanloading] .no-plan-info,
#detailsInternetPage[cellplanloading] .plan-details-info,
-#detailsInternetPage[cellplanloading] .needs-plan,
+#detailsInternetPage[cellplanloading] > * > #buyplanDetails,
#detailsInternetPage[cellplanloading] #planList,
+#detailsInternetPage[activated] > * > #activateDetails,
+#detailsInternetPage:not([activated]) > * > #buyplanDetails,
+#detailsInternetPage:not([activated]) > * > #detailsInternetLogin,
#detailsInternetPage[hascellplan] .plan-loading-info,
#detailsInternetPage[hascellplan] .no-plan-info,
-#detailsInternetPage[hascellplan] .needs-plan,
+#detailsInternetPage[hascellplan] > * > #buyplanDetails,
#detailsInternetPage[nocellplan] .plan-loading-info,
#detailsInternetPage[nocellplan] .plan-details-info,
-#detailsInternetPage[hasactiveplan] .needs-plan,
+#detailsInternetPage[hasactiveplan] > * > #buyplanDetails,
#detailsInternetPage:not([gsm]) .gsm-only,
#detailsInternetPage:not([password]) .password-details,
#detailsInternetPage[cert] .password-details,
diff --git a/chrome/browser/resources/options/chromeos_language_list.js b/chrome/browser/resources/options/chromeos_language_list.js
index f1c18c3..df47550 100644
--- a/chrome/browser/resources/options/chromeos_language_list.js
+++ b/chrome/browser/resources/options/chromeos_language_list.js
@@ -288,17 +288,42 @@ cr.define('options.language', function() {
// Encode the language codes into a CSV string.
Preferences.setStringPref(this.preferredLanguagesPref,
this.dataModel.slice().join(','));
- // Save the same language list as accept languages preference. In
- // theory, we don't need two separate preferences but we keep these
- // separate, as these are conceptually different. In other words,
- // using "intl.accept_languages" for preferred languages in Chrome
- // OS is a bit awkward.
+ // Save the same language list as accept languages preference as
+ // well, but we need to expand the language list, to make it more
+ // acceptable. For instance, some web sites don't understand 'en-US'
+ // but 'en'. See crosbug.com/9884.
+ var acceptLanguages = this.expandLanguageCodes(this.dataModel.slice());
Preferences.setStringPref(this.acceptLanguagesPref,
- this.dataModel.slice().join(','));
+ acceptLanguages.join(','));
cr.dispatchSimpleEvent(this, 'save');
},
/**
+ * Expands language codes to make these more suitable for Accept-Language.
+ * Example: ['en-US', 'ja', 'en-CA'] => ['en-US', 'en', 'ja', 'en-CA'].
+ * 'en' won't appear twice as this function eliminates duplicates.
+ * @param {Array} languageCodes List of language codes.
+ * @private
+ */
+ expandLanguageCodes: function(languageCodes) {
+ var expandedLanguageCodes = [];
+ var seen = {}; // Used to eliminiate duplicates.
+ for (var i = 0; i < languageCodes.length; i++) {
+ var languageCode = languageCodes[i];
+ if (!(languageCode in seen)) {
+ expandedLanguageCodes.push(languageCode);
+ seen[languageCode] = true;
+ }
+ var parts = languageCode.split('-');
+ if (!(parts[0] in seen)) {
+ expandedLanguageCodes.push(parts[0]);
+ seen[parts[0]] = true;
+ }
+ }
+ return expandedLanguageCodes;
+ },
+
+ /**
* Filters bad language codes in case bad language codes are
* stored in the preference. Removes duplicates as well.
* @param {Array} languageCodes List of language codes.
diff --git a/chrome/browser/resources/options/chromeos_system_options.js b/chrome/browser/resources/options/chromeos_system_options.js
index 2098303..fa69ad4 100644
--- a/chrome/browser/resources/options/chromeos_system_options.js
+++ b/chrome/browser/resources/options/chromeos_system_options.js
@@ -32,13 +32,11 @@ cr.define('options', function() {
var timezone = $('timezone-select');
if (timezone) {
timezone.initializeValues(templateData.timezoneList);
+
// Disable the timezone setting for non-owners, as this is a
// system wide setting.
- if (!AccountsOptions.currentUserIsOwner()) {
+ if (!AccountsOptions.currentUserIsOwner())
timezone.disabled = true;
- // Mark that this is manually disabled. See also pref_ui.js.
- timezone.manually_disabled = true;
- }
}
$('language-button').onclick = function(event) {
diff --git a/chrome/browser/resources/options/clear_browser_data_overlay.css b/chrome/browser/resources/options/clear_browser_data_overlay.css
index 1787a0e..4a274f2 100644
--- a/chrome/browser/resources/options/clear_browser_data_overlay.css
+++ b/chrome/browser/resources/options/clear_browser_data_overlay.css
@@ -1,3 +1,7 @@
+#clearBrowserDataOverlay {
+ width: 300px;
+}
+
#cbdThrobber {
background-image: url("../../../../app/resources/throbber.png");
width: 16px;
diff --git a/chrome/browser/resources/options/content_settings.css b/chrome/browser/resources/options/content_settings.css
index 52f673c..be2cc17 100644
--- a/chrome/browser/resources/options/content_settings.css
+++ b/chrome/browser/resources/options/content_settings.css
@@ -4,22 +4,53 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
*/
-.contentSettingsHeader {
- /* TODO(dhg): something nice. */
- margin: 0px;
- margin-bottom: 1em;
+.exceptionPattern {
+ display: -webkit-box;
+ margin-right: 4px;
+ overflow: hidden;
+ -webkit-box-flex: 1;
+ white-space: nowrap;
}
-.zippy div[mode=otr] {
- display: none;
+.exceptionSetting {
+ display: inline-block;
+ width: 100px;
+ margin-right: 20px;
}
-.zippy.show-otr div[mode=otr] {
- display: block;
- /* background reminiscent of an incognito window, but faded */
- background: -webkit-gradient(linear,
- left top,
- left bottom,
- from(rgba(97, 122, 156, .25)),
- to(rgba(82, 108, 145, .25)));
+select.exceptionSetting {
+ vertical-align: middle;
+}
+
+/* Hacks to make the <select> align better with the <input>. */
+html[toolkit=gtk] select.exceptionSetting {
+ height: 22px;
+ margin-top: 1px;
+}
+
+#exceptionColumnHeaders {
+ display: -webkit-box;
+ margin-top: 17px;
+ -webkit-margin-start: 3px;
+}
+
+#exceptionColumnHeaders > div {
+ font-weight: bold;
+}
+
+#exceptionPatternColumn {
+ -webkit-box-flex: 1;
+}
+
+#exceptionBehaviorColumn {
+ width: 140px;
+}
+
+.otr_explanation {
+ font-style: italic;
+}
+
+#contentSettingsExceptionsArea list {
+ margin-bottom: 10px;
+ margin-top: 4px;
}
diff --git a/chrome/browser/resources/options/content_settings.html b/chrome/browser/resources/options/content_settings.html
index 5ff6dbc..c2693f3 100644
--- a/chrome/browser/resources/options/content_settings.html
+++ b/chrome/browser/resources/options/content_settings.html
@@ -1,347 +1,153 @@
<div class="page hidden" id="contentSettingsPage">
<h1 i18n-content="contentSettingsPage"></h1>
-
- <!-- Navigation tabs -->
- <div class="subpages-nav-tabs">
- <span id="cookies-nav-tab" class="inactive-tab"
- tab-contents="cookiesFilterTab">
- <span class="inactive-tab-label" i18n-content="cookies_tab_label"></span>
- <span class="active-tab-label" i18n-content="cookies_tab_label"></span>
- </span>
- <span id="images-nav-tab" class="inactive-tab"
- tab-contents="imagesFilterTab">
- <span class="inactive-tab-label" i18n-content="images_tab_label"></span>
- <span class="active-tab-label" i18n-content="images_tab_label"></span>
- </span>
- <span id="javascript-nav-tab" class="inactive-tab"
- tab-contents="javascriptFilterTab">
- <span class="inactive-tab-label"
- i18n-content="javascript_tab_label"></span>
- <span class="active-tab-label" i18n-content="javascript_tab_label"></span>
- </span>
- <span id="plugins-nav-tab" class="inactive-tab"
- tab-contents="pluginsFilterTab">
- <span class="inactive-tab-label" i18n-content="plugins_tab_label"></span>
- <span class="active-tab-label" i18n-content="plugins_tab_label"></span>
- </span>
- <span id="popups-nav-tab" class="inactive-tab"
- tab-contents="popupsFilterTab">
- <span class="inactive-tab-label" i18n-content="popups_tab_label"></span>
- <span class="active-tab-label" i18n-content="popups_tab_label"></span>
- </span>
- <span id="location-nav-tab" class="inactive-tab"
- tab-contents="locationFilterTab">
- <span class="inactive-tab-label" i18n-content="location_tab_label"></span>
- <span class="active-tab-label" i18n-content="location_tab_label"></span>
- </span>
- <span id="notifications-nav-tab" class="inactive-tab"
- tab-contents="notificationsFilterTab">
- <span class="inactive-tab-label"
- i18n-content="notifications_tab_label"></span>
- <span class="active-tab-label"
- i18n-content="notifications_tab_label"></span>
- </span>
- </div>
-
<!-- Cookie filter tab contents -->
- <div id="cookiesFilterTab" class="subpages-tab-contents">
- <h4 i18n-content="cookies_modify" class="contentSettingsHeader"></h4>
- <table class="option-control-table">
- <tr>
- <td class="option-name">
- <label class="radio">
- <input type="radio" name="cookies" value="allow">
- <span i18n-content="cookies_allow"></span>
- </label>
- </td>
- </tr>
- <tr>
- <td class="option-name">
- <label class="radio">
- <input type="radio" name="cookies" value="block">
- <span i18n-content="cookies_block"></span>
- </label>
- </td>
- </tr>
- </table>
-
- <div class="zippy">
- <div class="zippy-header" i18n-content="content_exceptions"></div>
- <div class="zippy-content">
- <div contentType="cookies" mode="normal">
- <list></list>
- </div>
- <div contentType="cookies" mode="otr">
- <span i18n-content="otr_exceptions_explanation"></span>
- <list></list>
- </div>
- </div>
- </div>
-
- <table class="option-control-table">
- <tr>
- <td class="option-name">
- <label class="checkbox">
- <input id="block-third-party-cookies"
- pref="profile.block_third_party_cookies" type="checkbox">
- <span i18n-content="cookies_block_3rd_party"></span>
- </label>
- </td>
- </tr>
- <tr>
- <td class="option-name">
- <label class="checkbox">
- <input id="clear-cookies-on-exit"
- pref="profile.clear_site_data_on_exit" type="checkbox">
- <span i18n-content="cookies_clear_on_exit"></span>
- </label>
- </td>
- </tr>
- <tr>
- <td class="option-name"><button id="show-cookies-button"
+ <section>
+ <h3 i18n-content="cookies_tab_label"></h3>
+ <div>
+ <label class="radio">
+ <input type="radio" name="cookies" value="allow">
+ <span i18n-content="cookies_allow"></span>
+ </label>
+ <label class="radio">
+ <input type="radio" name="cookies" value="block">
+ <span i18n-content="cookies_block"></span>
+ </label>
+
+ <label class="checkbox">
+ <input id="block-third-party-cookies"
+ pref="profile.block_third_party_cookies" type="checkbox">
+ <span i18n-content="cookies_block_3rd_party"></span>
+ </label>
+ <label class="checkbox">
+ <input id="clear-cookies-on-exit"
+ pref="profile.clear_site_data_on_exit" type="checkbox">
+ <span i18n-content="cookies_clear_on_exit"></span>
+ </label>
+
+ <button class="exceptionsListButton" contentType="cookies"
+ i18n-content="manage_exceptions"></button>
+ <button id="show-cookies-button"
i18n-content="cookies_show_cookies"></button>
- </td>
- </tr>
- <tr>
- <td>
- <a i18n-values="href:flash_storage_url"
- i18n-content="flash_storage_settings" target="_blank"></a>
- </td>
- </tr>
- </table>
- </div>
-
- <!-- Image filter tab contents -->
- <div id="imagesFilterTab" class="subpages-tab-contents">
- <h4 i18n-content="images_setting" class="contentSettingsHeader"></h4>
- <table class="option-control-table">
- <tr>
- <td class="option-name">
- <label class="radio">
- <input type="radio" name="images" value="allow">
- <span i18n-content="images_allow"></span>
- </label>
- </td>
- </tr>
- <tr>
- <td class="option-name">
- <label class="radio">
- <input type="radio" name="images" value="block">
- <span i18n-content="images_block"></span>
- </label>
- </td>
- </tr>
- </table>
-
- <div class="zippy">
- <div class="zippy-header" i18n-content="content_exceptions"></div>
- <div class="zippy-content">
- <div contentType="images" mode="normal">
- <list></list>
- </div>
- <div contentType="images" mode="otr">
- <span i18n-content="otr_exceptions_explanation"></span>
- <list></list>
- </div>
- </div>
+ </div>
+ </section>
+
+ <!-- Image filter -->
+ <section>
+ <h3 i18n-content="images_tab_label"></h3>
+ <div>
+ <label class="radio">
+ <input type="radio" name="images" value="allow">
+ <span i18n-content="images_allow"></span>
+ </label>
+ <label class="radio">
+ <input type="radio" name="images" value="block">
+ <span i18n-content="images_block"></span>
+ </label>
+
+ <button class="exceptionsListButton" contentType="images"
+ i18n-content="manage_exceptions"></button>
</div>
- </div>
-
- <!-- JavaScript filter tab contents -->
- <div id="javascriptFilterTab" class="subpages-tab-contents">
- <h4 i18n-content="javascript_setting" class="contentSettingsHeader"></h4>
- <table class="option-control-table">
- <tr>
- <td class="option-name">
- <label class="radio">
- <input type="radio" name="javascript" value="allow">
- <span i18n-content="javascript_allow"></span>
- </label>
- </td>
- </tr>
- <tr>
- <td class="option-name">
- <label class="radio">
- <input type="radio" name="javascript" value="block">
- <span i18n-content="javascript_block"></span>
- </label>
- </td>
- </tr>
- </table>
-
- <div class="zippy">
- <div class="zippy-header" i18n-content="content_exceptions"></div>
- <div class="zippy-content">
- <div contentType="javascript" mode="normal">
- <list></list>
- </div>
- <div contentType="javascript" mode="otr">
- <span i18n-content="otr_exceptions_explanation"></span>
- <list></list>
- </div>
- </div>
+ </section>
+
+ <!-- JavaScript filter -->
+ <section>
+ <h3 i18n-content="javascript_tab_label"></h3>
+ <div>
+ <label class="radio">
+ <input type="radio" name="javascript" value="allow">
+ <span i18n-content="javascript_allow"></span>
+ </label>
+ <label class="radio">
+ <input type="radio" name="javascript" value="block">
+ <span i18n-content="javascript_block"></span>
+ </label>
+
+ <button class="exceptionsListButton" contentType="javascript"
+ i18n-content="manage_exceptions"></button>
</div>
- </div>
-
- <!-- Plug-ins filter tab contents -->
- <div id="pluginsFilterTab" class="subpages-tab-contents">
- <h4 i18n-content="plugins_setting" class="contentSettingsHeader"></h4>
- <table class="option-control-table">
- <tr>
- <td class="option-name">
- <label class="radio">
- <input type="radio" name="plugins" value="allow">
- <span i18n-content="plugins_allow"></span>
- </label>
- </td>
- </tr>
- <tr id="click_to_play">
- <td class="option-name">
- <label class="radio">
- <input type="radio" name="plugins" value="ask">
- <span i18n-content="plugins_ask"></span>
- </label>
- </td>
- </tr>
- <tr>
- <td class="option-name">
- <label class="radio">
- <input type="radio" name="plugins" value="block">
- <span i18n-content="plugins_block"></span>
- </label>
- </td>
- </tr>
- </table>
-
- <div class="zippy">
- <div class="zippy-header" i18n-content="content_exceptions"></div>
- <div class="zippy-content">
- <div contentType="plugins" mode="normal">
- <list></list>
- </div>
- <div contentType="plugins" mode="otr">
- <span i18n-content="otr_exceptions_explanation"></span>
- <list></list>
- </div>
- </div>
+ </section>
+
+ <!-- Plug-ins filter -->
+ <section>
+ <h3 i18n-content="plugins_tab_label"></h3>
+ <div>
+ <label class="radio">
+ <input type="radio" name="plugins" value="allow">
+ <span i18n-content="plugins_allow"></span>
+ </label>
+ <label class="radio" id="click_to_play">
+ <input type="radio" name="plugins" value="ask">
+ <span i18n-content="plugins_ask"></span>
+ </label>
+ <label class="radio">
+ <input type="radio" name="plugins" value="block">
+ <span i18n-content="plugins_block"></span>
+ </label>
+
+ <button class="exceptionsListButton" contentType="plugins"
+ i18n-content="manage_exceptions"></button>
</div>
-
- <a i18n-content="disable_individual_plugins" id="plugins-tab" href="#"></a>
- </div>
-
- <!-- Pop-ups filter tab contents -->
- <div id="popupsFilterTab" class="subpages-tab-contents">
- <h4 i18n-content="popups_setting" class="contentSettingsHeader"></h4>
- <table class="option-control-table">
- <tr>
- <td class="option-name">
- <label class="radio">
- <input type="radio" name="popups" value="allow">
- <span i18n-content="popups_allow"></span>
- </label>
- </td>
- </tr>
- <tr>
- <td class="option-name">
- <label class="radio">
- <input type="radio" name="popups" value="block">
- <span i18n-content="popups_block"></span>
- </label>
- </td>
- </tr>
- </table>
-
- <div class="zippy">
- <div class="zippy-header" i18n-content="content_exceptions"></div>
- <div class="zippy-content">
- <div contentType="popups" mode="normal">
- <list></list>
- </div>
- <div contentType="popups" mode="otr">
- <span i18n-content="otr_exceptions_explanation"></span>
- <list></list>
- </div>
- </div>
+ </section>
+
+ <!-- Pop-ups filter -->
+ <section>
+ <h3 i18n-content="popups_tab_label" class="contentSettingsHeader"></h3>
+ <div>
+ <label class="radio">
+ <input type="radio" name="popups" value="allow">
+ <span i18n-content="popups_allow"></span>
+ </label>
+ <label class="radio">
+ <input type="radio" name="popups" value="block">
+ <span i18n-content="popups_block"></span>
+ </label>
+
+ <button class="exceptionsListButton" contentType="popups"
+ i18n-content="manage_exceptions"></button>
</div>
- </div>
-
- <!-- Location filter tab contents -->
- <div id="locationFilterTab" class="subpages-tab-contents">
- <h4 i18n-content="location_setting" class="contentSettingsHeader"></h4>
- <table class="option-control-table">
- <tr>
- <td class="option-name">
- <label class="radio">
- <input type="radio" name="location" value="allow">
- <span i18n-content="location_allow"></span>
- </label>
- </td>
- </tr>
- <tr>
- <td class="option-name">
- <label class="radio">
- <input type="radio" name="location" value="ask">
- <span i18n-content="location_ask"></span>
- </label>
- </td>
- </tr>
- <tr>
- <td class="option-name">
- <label class="radio">
- <input type="radio" name="location" value="block">
- <span i18n-content="location_block"></span>
- </label>
- </td>
- </tr>
- </table>
-
- <div class="zippy">
- <div class="zippy-header" i18n-content="content_exceptions"></div>
- <div class="zippy-content">
- <div contentType="location" mode="normal">
- <list></list>
- </div>
- </div>
+ </section>
+
+ <!-- Location filter -->
+ <section>
+ <h3 i18n-content="location_tab_label"></h3>
+ <div>
+ <label class="radio">
+ <input type="radio" name="location" value="allow">
+ <span i18n-content="location_allow"></span>
+ </label>
+ <label class="radio">
+ <input type="radio" name="location" value="ask">
+ <span i18n-content="location_ask"></span>
+ </label>
+ <label class="radio">
+ <input type="radio" name="location" value="block">
+ <span i18n-content="location_block"></span>
+ </label>
+
+ <button class="exceptionsListButton" contentType="location"
+ i18n-content="manage_exceptions"></button>
</div>
- </div>
+ </section>
<!-- Notifications filter tab contents -->
- <div id="notificationsFilterTab" class="subpages-tab-contents">
- <h4 i18n-content="notifications_setting" class="contentSettingsHeader"></h4>
- <table class="option-control-table">
- <tr>
- <td class="option-name">
- <label class="radio">
- <input type="radio" name="notifications" value="allow">
- <span i18n-content="notifications_allow"></span>
- </label>
- </td>
- </tr>
- <tr>
- <td class="option-name">
- <label class="radio">
- <input type="radio" name="notifications" value="ask">
- <span i18n-content="notifications_ask"></span>
- </label>
- </td>
- </tr>
- <tr>
- <td class="option-name">
- <label class="radio">
- <input type="radio" name="notifications" value="block">
- <span i18n-content="notifications_block"></span>
- </label>
- </td>
- </tr>
- </table>
-
- <div class="zippy">
- <div class="zippy-header" i18n-content="content_exceptions"></div>
- <div class="zippy-content">
- <div contentType="notifications" mode="normal">
- <list></list>
- </div>
- </div>
+ <section>
+ <h3 i18n-content="notifications_tab_label"></h3>
+ <div>
+ <label class="radio">
+ <input type="radio" name="notifications" value="allow">
+ <span i18n-content="notifications_allow"></span>
+ </label>
+ <label class="radio">
+ <input type="radio" name="notifications" value="ask">
+ <span i18n-content="notifications_ask"></span>
+ </label>
+ <label class="radio">
+ <input type="radio" name="notifications" value="block">
+ <span i18n-content="notifications_block"></span>
+ </label>
+
+ <button class="exceptionsListButton" contentType="notifications"
+ i18n-content="manage_exceptions"></button>
</div>
- </div>
+ </section>
</div>
diff --git a/chrome/browser/resources/options/content_settings.js b/chrome/browser/resources/options/content_settings.js
index d66c3cd..787386e 100644
--- a/chrome/browser/resources/options/content_settings.js
+++ b/chrome/browser/resources/options/content_settings.js
@@ -29,23 +29,16 @@ cr.define('options', function() {
chrome.send('getContentFilterSettings');
- var exceptionsAreas = this.pageDiv.querySelectorAll('div[contentType]');
- for (var i = 0; i < exceptionsAreas.length; i++) {
- options.contentSettings.ExceptionsArea.decorate(exceptionsAreas[i]);
+ var exceptionsButtons =
+ this.pageDiv.querySelectorAll('.exceptionsListButton');
+ for (var i = 0; i < exceptionsButtons.length; i++) {
+ exceptionsButtons[i].onclick = function(event) {
+ ContentSettingsExceptionsArea.getInstance().showList(
+ event.target.getAttribute('contentType'));
+ OptionsPage.showPageByName('contentExceptions');
+ };
}
- cr.ui.decorate('.zippy', options.Zippy);
- this.pageDiv.addEventListener('measure', function(e) {
- if (e.target.classList.contains('zippy')) {
- var lists = e.target.querySelectorAll('list');
- for (var i = 0; i < lists.length; i++) {
- if (lists[i].redraw) {
- lists[i].redraw();
- }
- }
- }
- });
-
// Cookies filter page ---------------------------------------------------
$('block-third-party-cookies').onclick = function(event) {
chrome.send('setAllowThirdPartyCookies',
@@ -59,6 +52,7 @@ cr.define('options', function() {
$('plugins-tab').onclick = function(event) {
chrome.send('openPluginsTab');
+ return false;
};
if (!templateData.enable_click_to_play)
@@ -67,12 +61,12 @@ cr.define('options', function() {
/**
* Handles a hash value in the URL (such as bar in
- * chrome://options/foo#bar). Overrides the default action of showing an
- * overlay by instead navigating to a particular subtab.
+ * chrome://options/foo#bar).
* @param {string} hash The hash value.
*/
handleHash: function(hash) {
- OptionsPage.showTab($(hash + '-nav-tab'));
+ ContentSettingsExceptionsArea.getInstance().showList(hash);
+ OptionsPage.showPageByName('contentExceptions');
},
};
@@ -83,8 +77,13 @@ cr.define('options', function() {
*/
ContentSettings.setContentFilterSettingsValue = function(dict) {
for (var group in dict) {
- document.querySelector('input[type=radio][name=' + group +
- '][value=' + dict[group] + ']').checked = true;
+ document.querySelector('input[type=radio][name=' + group + '][value=' +
+ dict[group]['value'] + ']').checked = true;
+ var radios = document.querySelectorAll('input[type=radio][name=' +
+ group + ']');
+ for (var i = 0, len = radios.length; i < len; i++) {
+ radios[i].disabled = dict[group]['managed'];
+ }
}
};
@@ -97,64 +96,27 @@ cr.define('options', function() {
ContentSettings.setExceptions = function(type, list) {
var exceptionsList =
document.querySelector('div[contentType=' + type + ']' +
- '[mode=normal] list');
- exceptionsList.clear();
+ ' list[mode=normal]');
+
+ exceptionsList.reset();
for (var i = 0; i < list.length; i++) {
exceptionsList.addException(list[i]);
}
+ exceptionsList.redraw();
};
ContentSettings.setOTRExceptions = function(type, list) {
- var exceptionsArea =
- document.querySelector('div[contentType=' + type + '][mode=otr]');
- exceptionsArea.otrProfileExists = true;
-
- // Find the containing zippy, set it to show OTR profiles, and remeasure it
- // to make it smoothly animate to the new size.
- var zippy = exceptionsArea;
- while (zippy &&
- (!zippy.classList || !zippy.classList.contains('zippy'))) {
- zippy = zippy.parentNode;
- }
- if (zippy) {
- zippy.classList.add('show-otr');
- zippy.remeasure();
- }
+ var exceptionsList =
+ document.querySelector('div[contentType=' + type + ']' +
+ ' list[mode=otr]');
- var exceptionsList = exceptionsArea.querySelector('list');
- exceptionsList.clear();
+ exceptionsList.parentNode.classList.remove('hidden');
+
+ exceptionsList.reset();
for (var i = 0; i < list.length; i++) {
exceptionsList.addException(list[i]);
}
-
- // If an OTR table is added while the normal exceptions area is already
- // showing (because the exceptions area is already expanded), then show
- // the new OTR table.
- var parentExceptionsArea =
- document.querySelector('div[contentType=' + type + '][mode=normal]');
- if (!parentExceptionsArea.classList.contains('hidden')) {
- exceptionsArea.querySelector('list').redraw();
- }
- };
-
- /**
- * Clears and hides the incognito exceptions lists.
- */
- ContentSettings.OTRProfileDestroyed = function() {
- // Find all zippies, set them to hide OTR profiles, and remeasure them
- // to make them smoothly animate to the new size.
- var zippies = document.querySelectorAll('.zippy');
- for (var i = 0; i < zippies.length; i++) {
- zippies[i].classList.remove('show-otr');
- zippies[i].remeasure();
- }
-
- var exceptionsAreas =
- document.querySelectorAll('div[contentType][mode=otr]');
- for (var i = 0; i < exceptionsAreas.length; i++) {
- exceptionsAreas[i].otrProfileExists = false;
- exceptionsAreas[i].querySelector('list').clear();
- }
+ exceptionsList.redraw();
};
/**
@@ -177,8 +139,8 @@ cr.define('options', function() {
ContentSettings.patternValidityCheckComplete =
function(type, mode, pattern, valid) {
var exceptionsList =
- document.querySelector('div[contentType=' + type + '][mode=' + mode +
- '] list');
+ document.querySelector('div[contentType=' + type + '] ' +
+ 'list[mode=' + mode + ']');
exceptionsList.patternValidityCheckComplete(pattern, valid);
};
diff --git a/chrome/browser/resources/options/content_settings_exceptions_area.css b/chrome/browser/resources/options/content_settings_exceptions_area.css
deleted file mode 100644
index 7a80788..0000000
--- a/chrome/browser/resources/options/content_settings_exceptions_area.css
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
-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.
-*/
-
-.exceptionInput {
- /* TODO(estade): need something here to make it fill the remaining space. */
-}
-
-.exceptionSetting {
- float: right;
- margin-right: 30px;
-}
-
-.exceptionMode {
- float: right;
-}
diff --git a/chrome/browser/resources/options/content_settings_exceptions_area.html b/chrome/browser/resources/options/content_settings_exceptions_area.html
new file mode 100644
index 0000000..d4289bb
--- /dev/null
+++ b/chrome/browser/resources/options/content_settings_exceptions_area.html
@@ -0,0 +1,64 @@
+<div class="page hidden" id="contentSettingsExceptionsArea">
+ <h1></h1>
+
+ <div id="exceptionColumnHeaders">
+ <div id="exceptionPatternColumn">Pattern</div>
+ <div id="exceptionBehaviorColumn">Behavior</div>
+ </div>
+
+ <div contentType="cookies">
+ <list mode="normal"></list>
+ <div>
+ <span class="otr_explanation"
+ i18n-content="otr_exceptions_explanation"></span>
+ <list mode="otr"></list>
+ </div>
+ <a i18n-values="href:flash_storage_url"
+ i18n-content="flash_storage_settings" target="_blank"></a>
+ </div>
+
+ <div contentType="images">
+ <list mode="normal"></list>
+ <div>
+ <span class="otr_explanation"
+ i18n-content="otr_exceptions_explanation"></span>
+ <list mode="otr"></list>
+ </div>
+ </div>
+
+ <div contentType="javascript">
+ <list mode="normal"></list>
+ <div>
+ <span class="otr_explanation"
+ i18n-content="otr_exceptions_explanation"></span>
+ <list mode="otr"></list>
+ </div>
+ </div>
+
+ <div contentType="plugins">
+ <list mode="normal"></list>
+ <div>
+ <span class="otr_explanation"
+ i18n-content="otr_exceptions_explanation"></span>
+ <list mode="otr"></list>
+ </div>
+ <a i18n-content="disable_individual_plugins" id="plugins-tab" href="#"></a>
+ </div>
+
+ <div contentType="popups">
+ <list mode="normal"></list>
+ <div>
+ <span class="otr_explanation"
+ i18n-content="otr_exceptions_explanation"></span>
+ <list mode="otr"></list>
+ </div>
+ </div>
+
+ <div contentType="location">
+ <list mode="normal"></list>
+ </div>
+
+ <div contentType="notifications">
+ <list mode="normal"></list>
+ </div>
+</div>
diff --git a/chrome/browser/resources/options/content_settings_exceptions_area.js b/chrome/browser/resources/options/content_settings_exceptions_area.js
index 752ba0c..ddc85a0 100644
--- a/chrome/browser/resources/options/content_settings_exceptions_area.js
+++ b/chrome/browser/resources/options/content_settings_exceptions_area.js
@@ -3,8 +3,8 @@
// found in the LICENSE file.
cr.define('options.contentSettings', function() {
- const List = cr.ui.List;
- const ListItem = cr.ui.ListItem;
+ const DeletableItemList = options.DeletableItemList;
+ const DeletableItem = options.DeletableItem;
const ArrayDataModel = cr.ui.ArrayDataModel;
/**
@@ -16,10 +16,10 @@ cr.define('options.contentSettings', function() {
* @param {Object} exception A dictionary that contains the data of the
* exception.
* @constructor
- * @extends {cr.ui.ListItem}
+ * @extends {options.DeletableItem}
*/
function ExceptionsListItem(contentType, mode, enableAskOption, exception) {
- var el = cr.doc.createElement('li');
+ var el = cr.doc.createElement('div');
el.mode = mode;
el.contentType = contentType;
el.enableAskOption = enableAskOption;
@@ -31,29 +31,35 @@ cr.define('options.contentSettings', function() {
}
ExceptionsListItem.prototype = {
- __proto__: ListItem.prototype,
+ __proto__: DeletableItem.prototype,
/**
* Called when an element is decorated as a list item.
*/
decorate: function() {
- ListItem.prototype.decorate.call(this);
-
- // Labels for display mode.
- var patternLabel = cr.doc.createElement('span');
- patternLabel.textContent = this.pattern;
- this.appendChild(patternLabel);
-
- var settingLabel = cr.doc.createElement('span');
- settingLabel.textContent = this.settingForDisplay();
- settingLabel.className = 'exceptionSetting';
- this.appendChild(settingLabel);
+ DeletableItem.prototype.decorate.call(this);
+
+ // Labels for display mode. |pattern| will be null for the 'add new
+ // exception' row.
+ if (this.pattern) {
+ var patternLabel = cr.doc.createElement('span');
+ patternLabel.textContent = this.pattern;
+ patternLabel.className = 'exceptionPattern';
+ this.contentElement.appendChild(patternLabel);
+ this.patternLabel = patternLabel;
+
+ var settingLabel = cr.doc.createElement('span');
+ settingLabel.textContent = this.settingForDisplay();
+ settingLabel.className = 'exceptionSetting';
+ this.contentElement.appendChild(settingLabel);
+ this.settingLabel = settingLabel;
+ }
// Elements for edit mode.
var input = cr.doc.createElement('input');
input.type = 'text';
- this.appendChild(input);
- input.className = 'exceptionInput hidden';
+ this.contentElement.appendChild(input);
+ input.className = 'exceptionPattern hidden';
var select = cr.doc.createElement('select');
var optionAllow = cr.doc.createElement('option');
@@ -78,7 +84,7 @@ cr.define('options.contentSettings', function() {
optionBlock.textContent = templateData.blockException;
select.appendChild(optionBlock);
- this.appendChild(select);
+ this.contentElement.appendChild(select);
select.className = 'exceptionSetting hidden';
// Used to track whether the URL pattern in the input is valid.
@@ -93,26 +99,23 @@ cr.define('options.contentSettings', function() {
// empty input.
this.inputIsValid = true;
- this.patternLabel = patternLabel;
- this.settingLabel = settingLabel;
this.input = input;
this.select = select;
this.optionAllow = optionAllow;
this.optionBlock = optionBlock;
this.updateEditables();
- if (!this.pattern)
- input.value = templateData.examplePattern;
var listItem = this;
- this.ondblclick = function(event) {
+
+ this.addEventListener('selectedChange', function(event) {
// Editing notifications and geolocation is disabled for now.
if (listItem.contentType == 'notifications' ||
listItem.contentType == 'location')
return;
- listItem.editing = true;
- };
+ listItem.editing = listItem.selected;
+ });
// Handle events on the editable nodes.
input.oninput = function(event) {
@@ -132,32 +135,14 @@ cr.define('options.contentSettings', function() {
case 'U+001B': // Esc
// Reset the inputs.
listItem.updateEditables();
- if (listItem.pattern)
- listItem.maybeSetPatternValid(listItem.pattern, true);
+ listItem.setPatternValid(true);
case 'Enter':
- if (listItem.parentNode)
- listItem.parentNode.focus();
+ listItem.ownerDocument.activeElement.blur();
}
}
- function handleBlur(e) {
- // When the blur event happens we do not know who is getting focus so we
- // delay this a bit since we want to know if the other input got focus
- // before deciding if we should exit edit mode.
- var doc = e.target.ownerDocument;
- window.setTimeout(function() {
- var activeElement = doc.activeElement;
- if (!listItem.contains(activeElement)) {
- listItem.editing = false;
- }
- }, 50);
- }
-
input.addEventListener('keydown', handleKeydown);
- input.addEventListener('blur', handleBlur);
-
select.addEventListener('keydown', handleKeydown);
- select.addEventListener('blur', handleBlur);
},
/**
@@ -199,20 +184,12 @@ cr.define('options.contentSettings', function() {
},
/**
- * Update this list item to reflect whether the input is a valid pattern
- * if |pattern| matches the text currently in the input.
- * @param {string} pattern The pattern.
+ * Update this list item to reflect whether the input is a valid pattern.
* @param {boolean} valid Whether said pattern is valid in the context of
* a content exception setting.
*/
- maybeSetPatternValid: function(pattern, valid) {
- // Don't do anything for messages where we are not the intended recipient,
- // or if the response is stale (i.e. the input value has changed since we
- // sent the request to analyze it).
- if (pattern != this.input.value)
- return;
-
- if (valid)
+ setPatternValid: function(valid) {
+ if (valid || !this.input.value)
this.input.setCustomValidity('');
else
this.input.setCustomValidity(' ');
@@ -221,10 +198,18 @@ cr.define('options.contentSettings', function() {
},
/**
+ * Set the <input> to its original contents. Used when the user quits
+ * editing.
+ */
+ resetInput: function() {
+ this.input.value = this.pattern;
+ },
+
+ /**
* Copy the data model values to the editable nodes.
*/
updateEditables: function() {
- this.input.value = this.pattern;
+ this.resetInput();
if (this.setting == 'allow')
this.optionAllow.selected = true;
@@ -237,6 +222,17 @@ cr.define('options.contentSettings', function() {
},
/**
+ * Fiddle with the display of elements of this list item when the editing
+ * mode changes.
+ */
+ toggleVisibilityForEditing: function() {
+ this.patternLabel.classList.toggle('hidden');
+ this.settingLabel.classList.toggle('hidden');
+ this.input.classList.toggle('hidden');
+ this.select.classList.toggle('hidden');
+ },
+
+ /**
* Whether the user is currently able to edit the list item.
* @type {boolean}
*/
@@ -248,54 +244,41 @@ cr.define('options.contentSettings', function() {
if (oldEditing == editing)
return;
- var listItem = this;
- var pattern = this.pattern;
- var setting = this.setting;
- var patternLabel = this.patternLabel;
- var settingLabel = this.settingLabel;
var input = this.input;
- var select = this.select;
- var optionAllow = this.optionAllow;
- var optionBlock = this.optionBlock;
- var optionSession = this.optionSession;
- var optionAsk = this.optionAsk;
-
- // Just delete this row if it was added via the Add button.
- if (!editing && !pattern && !input.value) {
- var model = listItem.parentNode.dataModel;
- model.splice(model.indexOf(listItem.dataItem), 1);
- return;
- }
- // Check that we have a valid pattern and if not we do not change the
- // editing mode.
- if (!editing && (!this.inputValidityKnown || !this.inputIsValid)) {
- input.focus();
- input.select();
- return;
- }
-
- patternLabel.classList.toggle('hidden');
- settingLabel.classList.toggle('hidden');
- input.classList.toggle('hidden');
- select.classList.toggle('hidden');
-
- var doc = this.ownerDocument;
- var area = doc.querySelector('div[contentType=' +
- listItem.contentType + '][mode=' + listItem.mode + ']');
- area.enableAddAndEditButtons(!editing);
+ this.toggleVisibilityForEditing();
if (editing) {
this.setAttribute('editing', '');
cr.ui.limitInputWidth(input, this, 20);
- input.focus();
- input.select();
+ // When this is called in response to the selectedChange event,
+ // the list grabs focus immediately afterwards. Thus we must delay
+ // our focus grab.
+ window.setTimeout(function() {
+ input.focus();
+ input.select();
+ }, 50);
+
+ // TODO(estade): should we insert example text here for the AddNewRow
+ // input?
} else {
this.removeAttribute('editing');
+ // Check that we have a valid pattern and if not we do not, abort
+ // changes to the exception.
+ if (!this.inputValidityKnown || !this.inputIsValid) {
+ this.updateEditables();
+ this.setPatternValid(true);
+ return;
+ }
+
var newPattern = input.value;
var newSetting;
+ var optionAllow = this.optionAllow;
+ var optionBlock = this.optionBlock;
+ var optionSession = this.optionSession;
+ var optionAsk = this.optionAsk;
if (optionAllow.selected)
newSetting = 'allow';
else if (optionBlock.selected)
@@ -305,26 +288,105 @@ cr.define('options.contentSettings', function() {
else if (optionAsk && optionAsk.selected)
newSetting = 'ask';
- // Empty edit - do nothing.
- if (pattern == newPattern && newSetting == this.setting)
- return;
-
- this.pattern = patternLabel.textContent = newPattern;
- this.setting = newSetting;
- settingLabel.textContent = this.settingForDisplay();
+ this.finishEdit(newPattern, newSetting);
+ }
+ },
- if (pattern != this.pattern) {
- chrome.send('removeExceptions',
- [this.contentType, this.mode, pattern]);
- }
+ /**
+ * Editing is complete; update the model.
+ * @type {string} newPattern The pattern that the user entered.
+ * @type {string} newSetting The setting the user chose.
+ */
+ finishEdit: function(newPattern, newSetting) {
+ // Empty edit - do nothing.
+ if (newPattern == this.pattern && newSetting == this.setting)
+ return;
- chrome.send('setException',
- [this.contentType, this.mode, this.pattern, this.setting]);
+ this.patternLabel.textContent = newPattern;
+ this.settingLabel.textContent = this.settingForDisplay();
+ var oldPattern = this.pattern;
+ this.pattern = newPattern;
+ this.setting = newSetting;
+
+ // TODO(estade): this will need to be updated if geolocation/notifications
+ // become editable.
+ if (oldPattern != newPattern) {
+ chrome.send('removeException',
+ [this.contentType, this.mode, oldPattern]);
}
+
+ chrome.send('setException',
+ [this.contentType, this.mode, newPattern, newSetting]);
}
};
/**
+ * Creates a new list item for the Add New Item row, which doesn't represent
+ * an actual entry in the exceptions list but allows the user to add new
+ * exceptions.
+ * @param {string} contentType The type of the list.
+ * @param {string} mode The browser mode, 'otr' or 'normal'.
+ * @param {boolean} enableAskOption Whether to show an 'ask every time'
+ * option in the select.
+ * @constructor
+ * @extends {cr.ui.ExceptionsListItem}
+ */
+ function ExceptionsAddRowListItem(contentType, mode, enableAskOption) {
+ var el = cr.doc.createElement('div');
+ el.mode = mode;
+ el.contentType = contentType;
+ el.enableAskOption = enableAskOption;
+ el.dataItem = [];
+ el.__proto__ = ExceptionsAddRowListItem.prototype;
+ el.decorate();
+
+ return el;
+ }
+
+ ExceptionsAddRowListItem.prototype = {
+ __proto__: ExceptionsListItem.prototype,
+
+ decorate: function() {
+ ExceptionsListItem.prototype.decorate.call(this);
+
+ this.input.placeholder = templateData.addNewExceptionInstructions;
+ this.input.classList.remove('hidden');
+ this.select.classList.remove('hidden');
+
+ // Do we always want a default of allow?
+ this.setting = 'allow';
+ },
+
+ /**
+ * Clear the <input> and let the placeholder text show again.
+ */
+ resetInput: function() {
+ this.input.value = '';
+ },
+
+ /**
+ * No elements show or hide when going into edit mode, so do nothing.
+ */
+ toggleVisibilityForEditing: function() {
+ // No-op.
+ },
+
+ /**
+ * Editing is complete; update the model. As long as the pattern isn't
+ * empty, we'll just add it.
+ * @type {string} newPattern The pattern that the user entered.
+ * @type {string} newSetting The setting the user chose.
+ */
+ finishEdit: function(newPattern, newSetting) {
+ if (newPattern == '')
+ return;
+
+ chrome.send('setException',
+ [this.contentType, this.mode, newPattern, newSetting]);
+ },
+ };
+
+ /**
* Creates a new exceptions list.
* @constructor
* @extends {cr.ui.List}
@@ -332,19 +394,47 @@ cr.define('options.contentSettings', function() {
var ExceptionsList = cr.ui.define('list');
ExceptionsList.prototype = {
- __proto__: List.prototype,
+ __proto__: DeletableItemList.prototype,
/**
* Called when an element is decorated as a list.
*/
decorate: function() {
- List.prototype.decorate.call(this);
+ DeletableItemList.prototype.decorate.call(this);
- this.dataModel = new ArrayDataModel([]);
+ this.classList.add('settings-list');
+
+ for (var parentNode = this.parentNode; parentNode;
+ parentNode = parentNode.parentNode) {
+ if (parentNode.hasAttribute('contentType')) {
+ this.contentType = parentNode.getAttribute('contentType');
+ break;
+ }
+ }
+
+ this.mode = this.getAttribute('mode');
+
+ var exceptionList = this;
+ function handleBlur(e) {
+ // When the blur event happens we do not know who is getting focus so we
+ // delay this a bit until we know if the new focus node is outside the
+ // list.
+ var doc = e.target.ownerDocument;
+ window.setTimeout(function() {
+ var activeElement = doc.activeElement;
+ if (!exceptionList.contains(activeElement))
+ exceptionList.selectionModel.clear();
+ }, 50);
+ }
+
+ this.addEventListener('blur', handleBlur, true);
// Whether the exceptions in this list allow an 'Ask every time' option.
this.enableAskOption = (this.contentType == 'plugins' &&
templateData.enable_click_to_play);
+
+ this.autoExpands = true;
+ this.reset();
},
/**
@@ -352,10 +442,18 @@ cr.define('options.contentSettings', function() {
* @param {Object} entry The element from the data model for this row.
*/
createItem: function(entry) {
- return new ExceptionsListItem(this.contentType,
- this.mode,
- this.enableAskOption,
- entry);
+ if (entry) {
+ return new ExceptionsListItem(this.contentType,
+ this.mode,
+ this.enableAskOption,
+ entry);
+ } else {
+ var addRowItem = new ExceptionsAddRowListItem(this.contentType,
+ this.mode,
+ this.enableAskOption);
+ addRowItem.deletable = false;
+ return addRowItem;
+ }
},
/**
@@ -363,16 +461,11 @@ cr.define('options.contentSettings', function() {
* @param {Object} entry A dictionary of values for the exception.
*/
addException: function(entry) {
- this.dataModel.push(entry);
-
- // When an empty row is added, put it into editing mode.
- if (!entry['displayPattern'] && !entry['setting']) {
- var index = this.dataModel.length - 1;
- var sm = this.selectionModel;
- sm.anchorIndex = sm.leadIndex = sm.selectedIndex = index;
- this.scrollIndexIntoView(index);
- var li = this.getListItemByIndex(index);
- li.editing = true;
+ if (this.isEditable()) {
+ // We have to add it before the Add New Exception row.
+ this.dataModel.splice(this.dataModel.length - 1, 0, entry);
+ } else {
+ this.dataModel.push(entry);
}
},
@@ -384,42 +477,56 @@ cr.define('options.contentSettings', function() {
* a content exception setting.
*/
patternValidityCheckComplete: function(pattern, valid) {
- for (var i = 0; i < this.dataModel.length; i++) {
- var listItem = this.getListItemByIndex(i);
- if (listItem)
- listItem.maybeSetPatternValid(pattern, valid);
+ var listItems = this.items;
+ for (var i = 0; i < listItems.length; i++) {
+ var listItem = listItems[i];
+ // Don't do anything for messages for the item if it is not the intended
+ // recipient, or if the response is stale (i.e. the input value has
+ // changed since we sent the request to analyze it).
+ if (pattern == listItem.input.value)
+ listItem.setPatternValid(valid);
}
},
/**
- * Removes all exceptions from the js model.
+ * Returns whether the rows are editable in this list.
*/
- clear: function() {
- this.dataModel = new ArrayDataModel([]);
+ isEditable: function() {
+ // Editing notifications and geolocation is disabled for now.
+ return !(this.contentType == 'notifications' ||
+ this.contentType == 'location');
},
/**
- * Removes all selected rows from browser's model.
+ * Removes all exceptions from the js model.
*/
- removeSelectedRows: function() {
- // The first member is the content type; the rest of the values describe
- // the patterns we are removing.
- var args = [this.contentType];
- var selectedItems = this.selectedItems;
- for (var i = 0; i < selectedItems.length; i++) {
- if (this.contentType == 'location') {
- args.push(selectedItems[i]['origin']);
- args.push(selectedItems[i]['embeddingOrigin']);
- } else if (this.contentType == 'notifications') {
- args.push(selectedItems[i]['origin']);
- args.push(selectedItems[i]['setting']);
- } else {
- args.push(this.mode);
- args.push(selectedItems[i]['displayPattern']);
- }
+ reset: function() {
+ if (this.isEditable()) {
+ // The null creates the Add New Exception row.
+ this.dataModel = new ArrayDataModel([null]);
+ } else {
+ this.dataModel = new ArrayDataModel([]);
+ }
+ },
+
+ /** @inheritDoc */
+ deleteItemAtIndex: function(index) {
+ var listItem = this.getListItemByIndex(index);
+ if (listItem.undeletable) {
+ console.log('Tried to delete an undeletable row.');
+ return;
}
- chrome.send('removeExceptions', args);
+ var dataItem = listItem.dataItem;
+ var args = [listItem.contentType];
+ if (listItem.contentType == 'location')
+ args.push(dataItem['origin'], dataItem['embeddingOrigin']);
+ else if (listItem.contentType == 'notifications')
+ args.push(dataItem['origin'], dataItem['setting']);
+ else
+ args.push(listItem.mode, listItem.pattern);
+
+ chrome.send('removeException', args);
},
/**
@@ -432,121 +539,74 @@ cr.define('options.contentSettings', function() {
}
};
- var ExceptionsArea = cr.ui.define('div');
-
- ExceptionsArea.prototype = {
- __proto__: HTMLDivElement.prototype,
+ var OptionsPage = options.OptionsPage;
- decorate: function() {
- // TODO(estade): need some sort of visual indication when the list is
- // empty.
- this.exceptionsList = this.querySelector('list');
- this.exceptionsList.contentType = this.contentType;
- this.exceptionsList.mode = this.mode;
-
- ExceptionsList.decorate(this.exceptionsList);
- this.exceptionsList.selectionModel.addEventListener(
- 'change', this.handleOnSelectionChange_.bind(this));
-
- var self = this;
- if (this.contentType != 'location' &&
- this.contentType != 'notifications') {
- var addRow = cr.doc.createElement('button');
- addRow.textContent = templateData.addExceptionRow;
- this.appendChild(addRow);
-
- addRow.onclick = function(event) {
- var emptyException = new Object;
- emptyException.displayPattern = '';
- emptyException.setting = '';
- self.exceptionsList.addException(emptyException);
- };
- this.addRow = addRow;
-
- var editRow = cr.doc.createElement('button');
- editRow.textContent = templateData.editExceptionRow;
- this.appendChild(editRow);
- this.editRow = editRow;
-
- editRow.onclick = function(event) {
- self.exceptionsList.editSelectedRow();
- };
- }
-
- var removeRow = cr.doc.createElement('button');
- removeRow.textContent = templateData.removeExceptionRow;
- this.appendChild(removeRow);
- this.removeRow = removeRow;
+ /**
+ * Encapsulated handling of content settings list subpage.
+ * @constructor
+ */
+ function ContentSettingsExceptionsArea() {
+ OptionsPage.call(this, 'contentExceptions',
+ '', 'contentSettingsExceptionsArea');
+ }
- removeRow.onclick = function(event) {
- self.exceptionsList.removeSelectedRows();
- };
+ cr.addSingletonGetter(ContentSettingsExceptionsArea);
- this.updateButtonSensitivity();
+ ContentSettingsExceptionsArea.prototype = {
+ __proto__: OptionsPage.prototype,
- this.otrProfileExists = false;
- },
+ initializePage: function() {
+ OptionsPage.prototype.initializePage.call(this);
- /**
- * The content type for this exceptions area, such as 'images'.
- * @type {string}
- */
- get contentType() {
- return this.getAttribute('contentType');
- },
- set contentType(type) {
- return this.setAttribute('contentType', type);
- },
+ var exceptionsLists = this.pageDiv.querySelectorAll('list');
+ for (var i = 0; i < exceptionsLists.length; i++) {
+ options.contentSettings.ExceptionsList.decorate(exceptionsLists[i]);
+ }
- /**
- * The browser mode type for this exceptions area, 'otr' or 'normal'.
- * @type {string}
- */
- get mode() {
- return this.getAttribute('mode');
- },
- set mode(mode) {
- return this.setAttribute('mode', mode);
+ ContentSettingsExceptionsArea.hideOTRLists();
},
/**
- * Update the enabled/disabled state of the editing buttons based on which
- * rows are selected.
+ * Shows one list and hides all others.
+ * @param {string} type The content type.
*/
- updateButtonSensitivity: function() {
- var selectionSize = this.exceptionsList.selectedItems.length;
- if (this.addRow)
- this.addRow.disabled = this.addAndEditButtonsDisabled;
- if (this.editRow) {
- this.editRow.disabled = selectionSize != 1 ||
- this.addAndEditButtonsDisabled;
+ showList: function(type) {
+ var header = this.pageDiv.querySelector('h1');
+ header.textContent = templateData[type + '_header'];
+
+ var divs = this.pageDiv.querySelectorAll('div[contentType]');
+ for (var i = 0; i < divs.length; i++) {
+ if (divs[i].getAttribute('contentType') == type)
+ divs[i].classList.remove('hidden');
+ else
+ divs[i].classList.add('hidden');
}
- this.removeRow.disabled = selectionSize == 0;
},
+ };
- /**
- * Manually toggle the enabled/disabled state for the add and edit buttons.
- * They'll be disabled while another row is being edited.
- * @param {boolean}
- */
- enableAddAndEditButtons: function(enable) {
- this.addAndEditButtonsDisabled = !enable;
- this.updateButtonSensitivity();
- },
+ /**
+ * Called when the last incognito window is closed.
+ */
+ ContentSettingsExceptionsArea.OTRProfileDestroyed = function() {
+ this.hideOTRLists();
+ };
- /**
- * Callback from the selection model.
- * @param {!cr.Event} ce Event with change info.
- * @private
- */
- handleOnSelectionChange_: function(ce) {
- this.updateButtonSensitivity();
- },
+ /**
+ * Clears and hides the incognito exceptions lists.
+ */
+ ContentSettingsExceptionsArea.hideOTRLists = function() {
+ var otrLists = document.querySelectorAll('list[mode=otr]');
+
+ for (var i = 0; i < otrLists.length; i++) {
+ otrLists[i].reset();
+ otrLists[i].parentNode.classList.add('hidden');
+ }
};
return {
ExceptionsListItem: ExceptionsListItem,
+ ExceptionsAddRowListItem: ExceptionsAddRowListItem,
ExceptionsList: ExceptionsList,
- ExceptionsArea: ExceptionsArea
+ ContentSettingsExceptionsArea: ContentSettingsExceptionsArea,
};
});
diff --git a/chrome/browser/resources/options/cookies_view.js b/chrome/browser/resources/options/cookies_view.js
index e59f5bb..0f51fcb 100644
--- a/chrome/browser/resources/options/cookies_view.js
+++ b/chrome/browser/resources/options/cookies_view.js
@@ -32,6 +32,7 @@ cr.define('options', function() {
options.CookiesTree.decorate(cookiesTree);
cookiesTree.addEventListener('change',
this.handleCookieTreeChange_.bind(this));
+ cookiesTree.addEventListener('keydown', this.handleKeyDown_.bind(this));
$('cookiesSearchBox').addEventListener('keydown',
this.handleQueryEditKeyDown_.bind(this));
@@ -43,8 +44,7 @@ cr.define('options', function() {
}
$('remove-cookie').onclick = function(e) {
- var selected = cookiesTree.selectedItem;
- chrome.send('removeCookie', [selected.pathId]);
+ self.removeSelectedCookie_();
}
$('remove-all-cookie').onclick = function(e) {
@@ -230,6 +230,35 @@ cr.define('options', function() {
this.initalized_ = true;
this.searchCookie();
}
+ },
+
+ /**
+ * Remove currently selected cookie.
+ * @private
+ */
+ removeSelectedCookie_: function() {
+ var selected = cookiesTree.selectedItem;
+ if (selected)
+ chrome.send('removeCookie', [selected.pathId]);
+ },
+
+ /**
+ * Handler for keydown event.
+ * @private
+ * @param {Event} e KeyDown event.
+ */
+ handleKeyDown_: function(e) {
+ // If 'Remove' button is enabled and key is 'Delete' key on all platforms
+ // or 'Backspace' on Mac.
+ if (!$('remove-cookie').disabled &&
+ (e.keyIdentifier == 'U+007F' ||
+ (cr.isMac && e.keyIdentifier == 'U+0008'))) {
+ // No further key handling to avoid navigation triggered by 'Backspace'
+ // on Mac.
+ e.preventDefault();
+
+ this.removeSelectedCookie_();
+ }
}
};
diff --git a/chrome/browser/resources/options/deletable_item_list.js b/chrome/browser/resources/options/deletable_item_list.js
new file mode 100644
index 0000000..6781c50
--- /dev/null
+++ b/chrome/browser/resources/options/deletable_item_list.js
@@ -0,0 +1,140 @@
+// 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.
+
+cr.define('options', function() {
+ const List = cr.ui.List;
+ const ListItem = cr.ui.ListItem;
+
+ /**
+ * Creates a deletable list item, which has a button that will trigger a call
+ * to deleteItemAtIndex(index) in the list.
+ */
+ function DeletableItem(value) {
+ var el = cr.doc.createElement('div');
+ DeletableItem.decorate(el);
+ return el;
+ }
+
+ /**
+ * Decorates an element as a deletable list item.
+ * @param {!HTMLElement} el The element to decorate.
+ */
+ DeletableItem.decorate = function(el) {
+ el.__proto__ = DeletableItem.prototype;
+ el.decorate();
+ };
+
+ DeletableItem.prototype = {
+ __proto__: ListItem.prototype,
+
+ /**
+ * The element subclasses should populate with content.
+ * @type {HTMLElement}
+ * @private
+ */
+ contentElement_: null,
+
+ /**
+ * The close button element.
+ * @type {HTMLElement}
+ * @private
+ */
+ closeButtonElement_: null,
+
+ /**
+ * Whether or not this item can be deleted.
+ * @type {boolean}
+ * @private
+ */
+ deletable_: true,
+
+ /** @inheritDoc */
+ decorate: function() {
+ ListItem.prototype.decorate.call(this);
+
+ this.classList.add('deletable-item');
+
+ this.contentElement_ = this.ownerDocument.createElement('div');
+ this.appendChild(this.contentElement_);
+
+ this.closeButtonElement_ = this.ownerDocument.createElement('button');
+ this.closeButtonElement_.className = 'close-button';
+ this.closeButtonElement_.addEventListener('mousedown',
+ this.handleMouseDownOnClose_);
+ this.appendChild(this.closeButtonElement_);
+ },
+
+ /**
+ * Returns the element subclasses should add content to.
+ * @return {HTMLElement} The element subclasses should popuplate.
+ */
+ get contentElement() {
+ return this.contentElement_;
+ },
+
+ /* Gets/sets the deletable property. An item that is not deletable doesn't
+ * show the delete button (although space is still reserved for it).
+ */
+ get deletable() {
+ return this.deletable_;
+ },
+ set deletable(value) {
+ this.deletable_ = value;
+ this.closeButtonElement_.disabled = !value;
+ },
+
+ /**
+ * Don't let the list have a crack at the event. We don't want clicking the
+ * close button to select the list.
+ * @param {Event} e The mouse down event object.
+ * @private
+ */
+ handleMouseDownOnClose_: function(e) {
+ if (!e.target.disabled)
+ e.stopPropagation();
+ },
+ };
+
+ var DeletableItemList = cr.ui.define('list');
+
+ DeletableItemList.prototype = {
+ __proto__: List.prototype,
+
+ /** @inheritDoc */
+ decorate: function() {
+ List.prototype.decorate.call(this);
+ this.addEventListener('click', this.handleClick_);
+ },
+
+ /**
+ * Callback for onclick events.
+ * @param {Event} e The click event object.
+ * @private
+ */
+ handleClick_: function(e) {
+ if (this.disabled)
+ return;
+
+ var target = e.target;
+ if (target.className == 'close-button') {
+ var listItem = this.getListItemAncestor(target);
+ if (listItem)
+ this.deleteItemAtIndex(this.getIndexOfListItem(listItem));
+ }
+ },
+
+ /**
+ * Called when an item should be deleted; subclasses are responsible for
+ * implementing.
+ * @param {number} index The index of the item that is being deleted.
+ */
+ deleteItemAtIndex: function(index) {
+ },
+ };
+
+ return {
+ DeletableItemList: DeletableItemList,
+ DeletableItem: DeletableItem,
+ };
+});
diff --git a/chrome/browser/resources/options/edit_search_engine_overlay.css b/chrome/browser/resources/options/edit_search_engine_overlay.css
index 7cc2088..fad104e 100644
--- a/chrome/browser/resources/options/edit_search_engine_overlay.css
+++ b/chrome/browser/resources/options/edit_search_engine_overlay.css
@@ -13,7 +13,7 @@
#editSearchEngineOverlay table input {
width: 100%;
- -webkit-box-sizing: border-box;
+ box-sizing: border-box;
}
#editSearchEngineOverlay .action-area {
diff --git a/chrome/browser/resources/options/edit_search_engine_overlay.js b/chrome/browser/resources/options/edit_search_engine_overlay.js
index b6f9fcc..a4f72b5 100644
--- a/chrome/browser/resources/options/edit_search_engine_overlay.js
+++ b/chrome/browser/resources/options/edit_search_engine_overlay.js
@@ -69,7 +69,9 @@ cr.define('options', function() {
if (engineDetails) {
$('editSearchEngineName').value = engineDetails['name'];
$('editSearchEngineKeyword').value = engineDetails['keyword'];
- $('editSearchEngineURL').value = engineDetails['url'];
+ var urlField = $('editSearchEngineURL');
+ urlField.value = engineDetails['url'];
+ urlField.disabled = engineDetails['urlLocked'];
this.validateFields_();
} else {
$('editSearchEngineName').value = '';
diff --git a/chrome/browser/resources/options/import_data_overlay.html b/chrome/browser/resources/options/import_data_overlay.html
index 8607a0f..ace3502 100644
--- a/chrome/browser/resources/options/import_data_overlay.html
+++ b/chrome/browser/resources/options/import_data_overlay.html
@@ -1,33 +1,35 @@
-<div class="page hidden" id="importDataOverlay">
- <h1 i18n-content="import_data_title"></h1>
+<div id="import-data-overlay" class="page hidden">
+ <h1 i18n-content="importDataTitle"></h1>
<div>
- <span i18n-content="import_from_label"></span>
- <select id="import-browsers"></select>
+ <span i18n-content="importFromLabel"></span>
+ <select id="import-browsers">
+ <option i18n-content="importLoading"></option>
+ </select>
</div>
<div id="import-checkboxes">
- <div i18n-content="import_description"></div>
+ <div i18n-content="importDescription"></div>
<div>
<input id="import-history" type="checkbox">
- <label for="import-history" i18n-content="import_history"></label>
+ <label for="import-history" i18n-content="importHistory"></label>
</div>
<div>
<input id="import-favorites" type="checkbox">
- <label for="import-favorites" i18n-content="import_favorites"></label>
+ <label for="import-favorites" i18n-content="importFavorites"></label>
</div>
<div>
<input id="import-passwords" type="checkbox">
- <label for="import-passwords" i18n-content="import_passwords"></label>
+ <label for="import-passwords" i18n-content="importPasswords"></label>
</div>
<div>
<input id="import-search" type="checkbox">
- <label for="import-search" i18n-content="import_search"></label>
+ <label for="import-search" i18n-content="importSearch"></label>
</div>
</div>
<div class="action-area">
<span id="import-throbber"></span>
<div class="button-strip">
<button id="import-data-cancel" i18n-content="cancel"></button>
- <button id="import-data-commit" i18n-content="import_commit"></button>
+ <button id="import-data-commit" i18n-content="importCommit"></button>
</div>
</div>
</div>
diff --git a/chrome/browser/resources/options/import_data_overlay.js b/chrome/browser/resources/options/import_data_overlay.js
index 82b495c..0b7ebab 100644
--- a/chrome/browser/resources/options/import_data_overlay.js
+++ b/chrome/browser/resources/options/import_data_overlay.js
@@ -12,9 +12,10 @@ cr.define('options', function() {
* @class
*/
function ImportDataOverlay() {
- OptionsPage.call(this, 'importDataOverlay',
+ OptionsPage.call(this,
+ 'importDataOverlay',
templateData.import_data_title,
- 'importDataOverlay');
+ 'import-data-overlay');
}
ImportDataOverlay.throbIntervalId = 0;
@@ -29,7 +30,7 @@ cr.define('options', function() {
* Initialize the page.
*/
initializePage: function() {
- // Call base class implementation to starts preference initialization.
+ // Call base class implementation to start preference initialization.
OptionsPage.prototype.initializePage.call(this);
var self = this;
@@ -44,7 +45,7 @@ cr.define('options', function() {
$('import-browsers').onchange = function() {
self.updateCheckboxes_();
self.validateCommitButton_();
- }
+ };
$('import-data-commit').onclick = function() {
chrome.send('importData', [
@@ -53,11 +54,14 @@ cr.define('options', function() {
String($('import-favorites').checked),
String($('import-passwords').checked),
String($('import-search').checked)]);
- }
+ };
$('import-data-cancel').onclick = function() {
ImportDataOverlay.dismiss();
- }
+ };
+
+ // Form controls are disabled until the profile list has been loaded.
+ self.setControlsSensitive_(false);
},
/**
@@ -72,6 +76,18 @@ cr.define('options', function() {
},
/**
+ * Sets the sensitivity of all the checkboxes and the commit button.
+ * @private
+ */
+ setControlsSensitive_: function(sensitive) {
+ var checkboxes =
+ document.querySelectorAll('#import-checkboxes input[type=checkbox]');
+ for (var i = 0; i < checkboxes.length; i++)
+ this.setUpCheckboxState_(checkboxes[i], sensitive);
+ $('import-data-commit').disabled = !sensitive;
+ },
+
+ /**
* Set enabled and checked states a checkbox element.
* @param {Object} checkbox A checkbox element.
* @param {boolean} enabled The enabled state of the chekbox.
@@ -104,20 +120,17 @@ cr.define('options', function() {
updateSupportedBrowsers_: function(browsers) {
ImportDataOverlay.browserProfiles = browsers;
var browserSelect = $('import-browsers');
+ browserSelect.remove(0); // Remove the 'Loading...' option.
browserSelect.textContent = '';
var browserCount = browsers.length;
if (browserCount == 0) {
- var option = new Option(templateData.no_profile_found, 0);
+ var option = new Option(templateData.noProfileFound, 0);
browserSelect.appendChild(option);
- var checkboxes =
- document.querySelectorAll(
- '#import-checkboxes input[type=checkbox]');
- for (var i = 0; i < checkboxes.length; i++) {
- this.setUpCheckboxState_(checkboxes[i], false);
- }
+ this.setControlsSensitive_(false);
} else {
+ this.setControlsSensitive_(true);
for (var i = 0; i < browserCount; i++) {
var browser = browsers[i]
var option = new Option(browser['name'], browser['index']);
diff --git a/chrome/browser/resources/options/options.html b/chrome/browser/resources/options/options.html
new file mode 100644
index 0000000..30e0cb0
--- /dev/null
+++ b/chrome/browser/resources/options/options.html
@@ -0,0 +1,221 @@
+<!DOCTYPE HTML>
+<html
+ i18n-values="dir:textdirection;
+ enable-cloud-print-proxy:enable-cloud-print-proxy"
+ id="t">
+<head>
+<meta charset="utf-8">
+<title i18n-content="title"></title>
+
+<link rel="icon" href="../../../app/theme/settings_favicon.png">
+<link rel="stylesheet" href="chrome://resources/css/list.css">
+<link rel="stylesheet" href="chrome://resources/css/tree.css">
+<link rel="stylesheet" href="../dom_ui.css">
+<link rel="stylesheet" href="options_page.css">
+<link rel="stylesheet" href="add_startup_page_overlay.css">
+<link rel="stylesheet" href="advanced_options.css">
+<link rel="stylesheet" href="alert_overlay.css">
+<link rel="stylesheet" href="autofill_edit_address_overlay.css">
+<link rel="stylesheet" href="autofill_edit_creditcard_overlay.css">
+<link rel="stylesheet" href="autofill_options.css">
+<link rel="stylesheet" href="browser_options_page.css">
+<link rel="stylesheet" href="clear_browser_data_overlay.css">
+<link rel="stylesheet" href="content_settings.css">
+<link rel="stylesheet" href="cookies_view.css">
+<link rel="stylesheet" href="edit_search_engine_overlay.css">
+<link rel="stylesheet" href="password_manager.css">
+<link rel="stylesheet" href="password_manager_list.css">
+<link rel="stylesheet" href="personal_options.css">
+<link rel="stylesheet" href="import_data_overlay.css">
+<link rel="stylesheet" href="search_engine_manager.css">
+<link rel="stylesheet" href="search_page.css">
+<link rel="stylesheet" href="subpages_tab_controls.css">
+<if expr="pp_ifdef('chromeos')">
+ <link rel="stylesheet" href="about_page.css">
+ <link rel="stylesheet" href="chromeos_accounts_options_page.css">
+ <link rel="stylesheet" href="chromeos_internet_options_page.css">
+ <link rel="stylesheet" href="chromeos_language_options.css">
+ <link rel="stylesheet" href="chromeos_proxy.css">
+</if>
+
+<if expr="not pp_ifdef('win32') and not pp_ifdef('darwin')">
+ <link rel="stylesheet" href="certificate_manager.css">
+</if>
+
+<script src="chrome://resources/css/tree.css.js"></script>
+
+<script src="chrome://resources/js/cr.js"></script>
+<script src="chrome://resources/js/cr/command_line.js"></script>
+<script src="chrome://resources/js/cr/event_target.js"></script>
+<script src="chrome://resources/js/cr/ui.js"></script>
+<script src="chrome://resources/js/cr/ui/array_data_model.js"></script>
+<script src="chrome://resources/js/cr/ui/list_selection_model.js"></script>
+<script src="chrome://resources/js/cr/ui/list_selection_controller.js"></script>
+<script src="chrome://resources/js/cr/ui/list_single_selection_model.js"></script>
+<script src="chrome://resources/js/cr/ui/list_item.js"></script>
+<script src="chrome://resources/js/cr/ui/list.js"></script>
+<script src="chrome://resources/js/cr/ui/tree.js"></script>
+<script src="chrome://resources/js/local_strings.js"></script>
+<script src="chrome://resources/js/util.js"></script>
+<script src="preferences.js"></script>
+<script src="pref_ui.js"></script>
+<script src="deletable_item_list.js"></script>
+<script src="list_inline_header_selection_controller.js"></script>
+<script src="options_page.js"></script>
+<if expr="pp_ifdef('chromeos')">
+ <script src="about_page.js"></script>
+ <script src="chromeos_cellular_plan_element.js"></script>
+ <script src="chromeos_internet_network_element.js"></script>
+ <script src="chromeos_internet_options.js"></script>
+ <script src="chromeos_language_add_language_overlay.js"></script>
+ <script src="chromeos_language_list.js"></script>
+ <script src="chromeos_language_options.js"></script>
+ <script src="chromeos_system_options.js"></script>
+ <script src="chromeos_accounts_options.js"></script>
+ <script src="chromeos_proxy_options.js"></script>
+ <script src="chromeos_proxy_rules_list.js"></script>
+ <script src="chromeos_accounts_user_list.js"></script>
+ <script src="chromeos_accounts_user_name_edit.js"></script>
+ <script>
+ var AboutPage = options.AboutPage;
+ var AccountsOptions = options.AccountsOptions;
+ var InternetOptions = options.InternetOptions;
+ var LanguageHangulOptions = options.LanguageHangulOptions;
+ var LanguageOptions = options.LanguageOptions;
+ var SystemOptions = options.SystemOptions;
+ </script>
+</if>
+<if expr="not pp_ifdef('win32') and not pp_ifdef('darwin')">
+ <script src="certificate_tree.js"></script>
+ <script src="certificate_manager.js"></script>
+ <script src="certificate_restore_overlay.js"></script>
+ <script src="certificate_backup_overlay.js"></script>
+ <script src="certificate_edit_ca_trust_overlay.js"></script>
+ <script src="certificate_import_error_overlay.js"></script>
+ <script>
+ var CertificateManager = options.CertificateManager;
+ var CertificateRestoreOverlay = options.CertificateRestoreOverlay;
+ var CertificateBackupOverlay = options.CertificateBackupOverlay;
+ var CertificateEditCaTrustOverlay = options.CertificateEditCaTrustOverlay;
+ var CertificateImportErrorOverlay = options.CertificateImportErrorOverlay;
+ </script>
+</if>
+<script src="add_startup_page_overlay.js"></script>
+<script src="add_startup_page_recent_pages_list.js"></script>
+<script src="advanced_options.js"></script>
+<script src="alert_overlay.js"></script>
+<script src="autofill_edit_address_overlay.js"></script>
+<script src="autofill_edit_creditcard_overlay.js"></script>
+<script src="autofill_options_list.js"></script>
+<script src="autofill_options.js"></script>
+<script src="browser_options.js"></script>
+<script src="browser_options_startup_page_list.js"></script>
+<script src="clear_browser_data_overlay.js"></script>
+<script src="content_settings.js"></script>
+<script src="content_settings_exceptions_area.js"></script>
+<script src="content_settings_ui.js"></script>
+<script src="cookies_tree.js"></script>
+<script src="cookies_view.js"></script>
+<script src="edit_search_engine_overlay.js"></script>
+<script src="font_settings.js"></script>
+<script src="font_settings_ui.js"></script>
+<script src="import_data_overlay.js"></script>
+<script src="instant_confirm_overlay.js"></script>
+<script src="password_manager.js"></script>
+<script src="password_manager_list.js"></script>
+<script src="personal_options.js"></script>
+<script src="search_engine_manager.js"></script>
+<script src="search_engine_manager_engine_list.js"></script>
+<script src="search_page.js"></script>
+<script src="startup_page_manager.js"></script>
+<script src="options.js"></script>
+
+</head>
+<body i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
+<div class="header">
+</div>
+<div id="overlay" class="overlay hidden">
+ <include src="add_startup_page_overlay.html">
+ <include src="alert_overlay.html">
+ <include src="autofill_edit_address_overlay.html">
+ <include src="autofill_edit_creditcard_overlay.html">
+ <include src="clear_browser_data_overlay.html">
+ <include src="edit_search_engine_overlay.html">
+ <include src="import_data_overlay.html">
+ <include src="instant_confirm_overlay.html">
+ <if expr="pp_ifdef('chromeos')">
+ <include src="chromeos_language_add_language_overlay.html">
+ <include
+ src="chromeos_language_customize_modifier_keys_overlay.html">
+ <include src="chromeos_internet_detail.html">
+ </if>
+ <if expr="not pp_ifdef('win32') and not pp_ifdef('darwin')">
+ <include src="certificate_restore_overlay.html">
+ <include src="certificate_backup_overlay.html">
+ <include src="certificate_edit_ca_trust_overlay.html">
+ <include src="certificate_import_error_overlay.html">
+ </if>
+</div>
+<div id="main-content">
+ <div id="navbar-container">
+ <h1 id="settings-title" i18n-content="title"></h1>
+ <ul id="navbar">
+ </ul>
+ </div>
+ <div id="mainview">
+ <div id="managed-prefs-banner" class="hidden">
+ <span id="managed-prefs-icon"></span>
+ <span id="managed-prefs-text"
+ i18n-content="managedPrefsBannerText"></span>
+ </div>
+ <div id="mainview-content">
+ <!-- Start main pages -->
+ <!-- Please keep the main pages in desired order of display. This will
+ allow search results to display in the desired order. -->
+ <include src="search_page.html">
+ <include src="browser_options.html">
+ <include src="personal_options.html">
+ <if expr="pp_ifdef('chromeos')">
+ <include src="chromeos_system_options.html">
+ <include src="chromeos_internet_options.html">
+ <include src="chromeos_accounts_options.html">
+ </if>
+ <include src="advanced_options.html">
+ <!-- End main pages -->
+ <div id="subpage-sheet-container-1"
+ class="subpage-sheet-container hidden">
+ <div id="subpage-sheet-1" class="subpage-sheet">
+ <button class="close-subpage"></button>
+ <if expr="pp_ifdef('chromeos')">
+ <include src="about_page.html">
+ <include src="chromeos_language_options.html">
+ <include src="chromeos_language_chewing_options.html">
+ <include src="chromeos_language_hangul_options.html">
+ <include src="chromeos_language_mozc_options.html">
+ <include src="chromeos_language_pinyin_options.html">
+ <include src="chromeos_proxy.html">
+ </if>
+ <if expr="not pp_ifdef('win32') and not pp_ifdef('darwin')">
+ <include src="certificate_manager.html">
+ </if>
+ <include src="autofill_options.html">
+ <include src="content_settings.html">
+ <include src="font_settings.html">
+ <include src="password_manager.html">
+ <include src="search_engine_manager.html">
+ <include src="startup_page_manager.html">
+ </div>
+ </div>
+ <div id="subpage-sheet-container-2"
+ class="subpage-sheet-container hidden">
+ <div id="subpage-sheet-2" class="subpage-sheet">
+ <button class="close-subpage"></button>
+ <include src="cookies_view.html">
+ <include src="content_settings_exceptions_area.html">
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+</body>
+</html>
diff --git a/chrome/browser/resources/options/options.js b/chrome/browser/resources/options/options.js
new file mode 100644
index 0000000..4d77b26
--- /dev/null
+++ b/chrome/browser/resources/options/options.js
@@ -0,0 +1,183 @@
+// 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.
+
+var AddStartupPageOverlay = options.AddStartupPageOverlay;
+var AdvancedOptions = options.AdvancedOptions;
+var AlertOverlay = options.AlertOverlay;
+var AutoFillEditAddressOverlay = options.AutoFillEditAddressOverlay;
+var AutoFillEditCreditCardOverlay = options.AutoFillEditCreditCardOverlay;
+var AutoFillOptions = options.AutoFillOptions;
+var BrowserOptions = options.BrowserOptions;
+var ClearBrowserDataOverlay = options.ClearBrowserDataOverlay;
+var ContentSettings = options.ContentSettings;
+var ContentSettingsExceptionsArea =
+ options.contentSettings.ContentSettingsExceptionsArea;
+var CookiesView = options.CookiesView;
+var EditSearchEngineOverlay = options.EditSearchEngineOverlay;
+var FontSettings = options.FontSettings;
+var ImportDataOverlay = options.ImportDataOverlay;
+var InstantConfirmOverlay = options.InstantConfirmOverlay;
+var OptionsPage = options.OptionsPage;
+var PasswordManager = options.PasswordManager;
+var PersonalOptions = options.PersonalOptions;
+var Preferences = options.Preferences;
+var ProxyOptions = options.ProxyOptions;
+var SearchEngineManager = options.SearchEngineManager;
+var SearchPage = options.SearchPage;
+var StartupPageManager = options.StartupPageManager;
+
+/**
+ * DOMContentLoaded handler, sets up the page.
+ */
+function load() {
+ // Decorate the existing elements in the document.
+ cr.ui.decorate('input[pref][type=checkbox]', options.PrefCheckbox);
+ cr.ui.decorate('input[pref][type=number]', options.PrefNumber);
+ cr.ui.decorate('input[pref][type=radio]', options.PrefRadio);
+ cr.ui.decorate('input[pref][type=range]', options.PrefRange);
+ cr.ui.decorate('select[pref]', options.PrefSelect);
+ cr.ui.decorate('input[pref][type=text]', options.PrefTextField);
+ cr.ui.decorate('input[pref][type=url]', options.PrefTextField);
+ cr.ui.decorate('#contentSettingsPage input[type=radio]',
+ options.ContentSettingsRadio);
+ cr.ui.decorate('#fontSettingsMinimumSizeSelector',
+ options.MinimumFontSizeSelect);
+
+ var menuOffPattern = /(^\?|&)menu=off($|&)/;
+ var menuDisabled = menuOffPattern.test(window.location.search);
+ document.documentElement.setAttribute('hide-menu', menuDisabled);
+
+ localStrings = new LocalStrings();
+
+ OptionsPage.register(SearchPage.getInstance());
+
+ OptionsPage.register(BrowserOptions.getInstance());
+ OptionsPage.registerSubPage(SearchEngineManager.getInstance(),
+ BrowserOptions.getInstance(),
+ [$('defaultSearchManageEnginesButton')]);
+ OptionsPage.registerSubPage(StartupPageManager.getInstance(),
+ BrowserOptions.getInstance(),
+ [$('startupPageManagerButton')]);
+ OptionsPage.register(PersonalOptions.getInstance());
+ OptionsPage.registerSubPage(AutoFillOptions.getInstance(),
+ PersonalOptions.getInstance(),
+ [$('autofill-settings')]);
+ OptionsPage.registerSubPage(PasswordManager.getInstance(),
+ PersonalOptions.getInstance(),
+ [$('manage-passwords')]);
+ if (cr.isChromeOS) {
+ OptionsPage.register(SystemOptions.getInstance());
+ OptionsPage.registerSubPage(AboutPage.getInstance(),
+ SystemOptions.getInstance());
+ OptionsPage.registerSubPage(LanguageOptions.getInstance(),
+ SystemOptions.getInstance(),
+ [$('language-button')]);
+ OptionsPage.registerSubPage(
+ new OptionsPage('languageChewing',
+ localStrings.getString('languageChewingPage'),
+ 'languageChewingPage'),
+ SystemOptions.getInstance());
+ OptionsPage.registerSubPage(
+ new OptionsPage('languageHangul',
+ localStrings.getString('languageHangulPage'),
+ 'languageHangulPage'),
+ SystemOptions.getInstance());
+ OptionsPage.registerSubPage(
+ new OptionsPage('languageMozc',
+ localStrings.getString('languageMozcPage'),
+ 'languageMozcPage'),
+ SystemOptions.getInstance());
+ OptionsPage.registerSubPage(
+ new OptionsPage('languagePinyin',
+ localStrings.getString('languagePinyinPage'),
+ 'languagePinyinPage'),
+ SystemOptions.getInstance());
+ OptionsPage.register(InternetOptions.getInstance());
+ }
+ OptionsPage.register(AdvancedOptions.getInstance());
+ OptionsPage.registerSubPage(ContentSettings.getInstance(),
+ AdvancedOptions.getInstance(),
+ [$('privacyContentSettingsButton')]);
+ OptionsPage.registerSubPage(ContentSettingsExceptionsArea.getInstance(),
+ ContentSettings.getInstance());
+ OptionsPage.registerSubPage(CookiesView.getInstance(),
+ ContentSettings.getInstance(),
+ [$('privacyContentSettingsButton'),
+ $('show-cookies-button')]);
+ OptionsPage.registerSubPage(FontSettings.getInstance(),
+ AdvancedOptions.getInstance(),
+ [$('fontSettingsCustomizeFontsButton')]);
+ if (!cr.isWindows && !cr.isMac) {
+ OptionsPage.registerSubPage(CertificateManager.getInstance(),
+ AdvancedOptions.getInstance(),
+ [$('show-cookies-button')]);
+ OptionsPage.registerOverlay(CertificateRestoreOverlay.getInstance());
+ OptionsPage.registerOverlay(CertificateBackupOverlay.getInstance());
+ OptionsPage.registerOverlay(CertificateEditCaTrustOverlay.getInstance());
+ OptionsPage.registerOverlay(CertificateImportErrorOverlay.getInstance());
+ }
+ OptionsPage.registerOverlay(AddStartupPageOverlay.getInstance());
+ OptionsPage.registerOverlay(AlertOverlay.getInstance());
+ OptionsPage.registerOverlay(AutoFillEditAddressOverlay.getInstance());
+ OptionsPage.registerOverlay(AutoFillEditCreditCardOverlay.getInstance());
+ OptionsPage.registerOverlay(ClearBrowserDataOverlay.getInstance(),
+ [$('privacyClearDataButton')]);
+ OptionsPage.registerOverlay(EditSearchEngineOverlay.getInstance());
+ OptionsPage.registerOverlay(ImportDataOverlay.getInstance());
+ OptionsPage.registerOverlay(InstantConfirmOverlay.getInstance());
+
+ if (cr.isChromeOS) {
+ OptionsPage.register(AccountsOptions.getInstance());
+ OptionsPage.registerSubPage(ProxyOptions.getInstance(),
+ AdvancedOptions.getInstance(),
+ [$('proxiesConfigureButton')]);
+ OptionsPage.registerOverlay(new OptionsPage('detailsInternetPage',
+ 'detailsInternetPage',
+ 'detailsInternetPage'));
+
+ var languageModifierKeysOverlay = new OptionsPage(
+ 'languageCustomizeModifierKeysOverlay',
+ localStrings.getString('languageCustomizeModifierKeysOverlay'),
+ 'languageCustomizeModifierKeysOverlay')
+ OptionsPage.registerOverlay(languageModifierKeysOverlay,
+ [$('modifier-keys-button')]);
+ }
+
+ Preferences.getInstance().initialize();
+ OptionsPage.initialize();
+
+ var path = document.location.pathname;
+ var hash = document.location.hash;
+
+ if (path.length > 1) {
+ var pageName = path.slice(1);
+ OptionsPage.showPageByName(pageName);
+ if (hash.length > 1)
+ OptionsPage.handleHashForPage(pageName, hash.slice(1));
+ } else {
+ // TODO(csilv): Save/restore last selected page.
+ OptionsPage.showPageByName(BrowserOptions.getInstance().name);
+ }
+
+ var subpagesNavTabs = document.querySelectorAll('.subpages-nav-tabs');
+ for(var i = 0; i < subpagesNavTabs.length; i++) {
+ subpagesNavTabs[i].onclick = function(event) {
+ OptionsPage.showTab(event.srcElement);
+ }
+ }
+
+ // Allow platform specific CSS rules.
+ if (cr.isMac)
+ document.documentElement.setAttribute('os', 'mac');
+ if (cr.isLinux)
+ document.documentElement.setAttribute('toolkit', 'gtk');
+ if (cr.isViews)
+ document.documentElement.setAttribute('toolkit', 'views');
+}
+
+document.addEventListener('DOMContentLoaded', load);
+
+window.onpopstate = function(e) {
+ options.OptionsPage.setState(e.state);
+};
diff --git a/chrome/browser/resources/options/options_page.css b/chrome/browser/resources/options/options_page.css
index 74c8bb1..684ab56 100644
--- a/chrome/browser/resources/options/options_page.css
+++ b/chrome/browser/resources/options/options_page.css
@@ -24,6 +24,10 @@ body {
bottom: 0;
}
+#search-field {
+ margin: 0;
+}
+
.overlay {
position: fixed;
left: 0;
@@ -38,21 +42,32 @@ body {
-webkit-box-pack: center;
}
-#close-overlay {
+.close-subpage {
+ background-color: transparent;
+ background-image: url('chrome://theme/IDR_CLOSE_BAR');
+ border: none;
position: relative;
- top: -20px;
- width: 20px;
- height: 20px;
+ top: 12px;
+ height: 16px;
+ width: 16px;
}
-html[dir='ltr'] #close-overlay {
+.close-subpage:hover {
+ background-image: url('chrome://theme/IDR_CLOSE_BAR_H');
+}
+
+.close-subpage:active {
+ background-image: url('chrome://theme/IDR_CLOSE_BAR_P');
+}
+
+html[dir='ltr'] .close-subpage {
float: right;
- right: -20px;
+ right: 0;
}
-html[dir='rtl'] #close-overlay {
+html[dir='rtl'] .close-subpage {
float: left;
- left: -20px;
+ left: 0;
}
html[hide-menu=true] .close-subpage {
@@ -116,7 +131,7 @@ html[toolkit=views] .button-strip {
left: 0;
position: fixed;
top: 0;
- width: 250px;
+ width: 266px;
z-index: 2;
}
@@ -179,7 +194,7 @@ html[hide-menu=false] #navbar-container {
#mainview {
-webkit-box-align: stretch;
- -webkit-padding-start: 251px;
+ -webkit-padding-start: 267px;
margin: 0;
position: absolute;
left: 0;
@@ -195,24 +210,35 @@ html[hide-menu=true] #mainview {
#mainview-content {
box-sizing: border-box;
+ max-width: 888px;
min-height: 100%;
+ min-width: 600px;
padding: 0 24px;
position: relative;
- width: 600px;
}
-#subpage-sheet-container {
- box-sizing: border-box;
- height: 100%;
+.subpage-sheet-container {
padding: 8px;
-webkit-padding-start: 60px;
+ box-sizing: border-box;
+ height: 100%;
position: absolute;
top: 0;
left: 0;
+}
+
+#subpage-sheet-container-1 {
width: 748px;
+ z-index: 5;
+}
+
+#subpage-sheet-container-2 {
+ left: 60px;
+ width: 688px;
+ z-index: 10;
}
-#subpage-sheet {
+.subpage-sheet {
-webkit-box-shadow: #666 0px 3px 5px;
background-color: white;
border: 1px solid #b8b8b8;
@@ -220,6 +246,7 @@ html[hide-menu=true] #mainview {
box-sizing: border-box;
min-height: 100%;
padding: 0px 20px;
+ position: relative;
width: 100%;
}
@@ -255,7 +282,7 @@ html[hide-menu=true] #mainview {
vertical-align: middle;
}
-.page > h1 {
+.page h1 {
-webkit-padding-end: 24px;
border-bottom: 1px solid #eeeeee;
color: #53637d;
@@ -266,8 +293,8 @@ html[hide-menu=true] #mainview {
padding-top: 13px;
}
-#subpage-sheet .page > h1 {
- padding-top: 7px;
+.subpage-sheet .page h1 {
+ padding-top: 4px;
}
section {
@@ -278,10 +305,16 @@ section {
padding-bottom: 20px;
}
-section:last-child {
+div.page section:last-child {
border-bottom: none;
}
+div.page > h3 {
+ font-size: 105%;
+ font-weight: bold;
+ margin: 20px 0 10px 0;
+}
+
section > h3 {
font-size: 105%;
font-weight: bold;
@@ -298,21 +331,20 @@ section > div:only-of-type {
margin-top: 0;
}
-.option-control-table, section > div:only-of-type {
- -webkit-padding-start: 10px;
- border-spacing: 0 0;
-}
-
/* TODO(stuartmorgan): make this less specific once all pages
* are converted to the non-table style.
*/
section > div:only-of-type label {
- display: block;
margin: 5px 0;
}
+label.checkbox,
+label.radio {
+ display: block
+}
+
.hidden {
- display: none;
+ display: none !important;
}
.touch-slider {
@@ -340,6 +372,43 @@ select {
background-color: pink;
}
+.settings-list {
+ border: 1px solid #d9d9d9;
+ border-radius: 2px;
+}
+
+list > * {
+ -webkit-box-align: center;
+ -webkit-transition: .15s background-color;
+ box-sizing: border-box;
+ border-radius: 0px;
+ display: -webkit-box;
+ height: 32px;
+ border: none;
+ margin: 0;
+}
+
+list:not([disabled]) > :hover {
+ background-color: #f2f2f2;
+}
+
+list > [selected],
+list:focus > [selected],
+list:focus > [lead][selected],
+list > [selected]:hover {
+ background-color: #f2f2f2;
+ background-image: none;
+}
+
+list[disabled] > [lead][selected],
+list[disabled]:focus > [lead][selected] {
+ border: none;
+}
+
+list[disabled] {
+ opacity: 0.6;
+}
+
list > .heading {
color: #666666;
}
@@ -349,6 +418,41 @@ list > .heading:hover {
border-color: transparent;
}
+list .deletable-item {
+ -webkit-box-align: center;
+}
+
+list .deletable-item > :first-child {
+ -webkit-box-flex: 1;
+ display: -webkit-box;
+}
+
+list .close-button {
+ -webkit-transition: .15s opacity;
+ background-color: transparent;
+ /* TODO(stuartmorgan): Replace with real images once they are available. */
+ background-image: url("../../../app/theme/close_bar.png");
+ border: none;
+ height: 16px;
+ opacity: 1;
+ width: 16px;
+}
+
+list > *:not(:hover) .close-button,
+list[disabled] .close-button,
+list .close-button[disabled] {
+ opacity: 0;
+ pointer-events: none;
+}
+
+list .close-button:hover {
+ background-image: url("../../../app/theme/close_bar_h.png");
+}
+
+list .close-button:active {
+ background-image: url("../../../app/theme/close_bar_p.png");
+}
+
.left-side-table {
display: -webkit-box;
}
@@ -379,7 +483,19 @@ html[dir=rtl].option-name {
background-repeat: no-repeat;
}
-html[dir=rtl] .favicon-cell {
+list .favicon-cell {
+ -webkit-padding-start: 33px;
+ background-position: 7px;
+ display: block;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+}
+
+html[dir=rtl] list .favicon-cell {
+ /* TODO(stuartmorgan): position this 7px from the right (and remove the
+ padding override) once the CSS support is available */
+ -webkit-padding-start: 26px;
background-position: right;
}
@@ -407,32 +523,16 @@ button {
* TODO(arv): Test the vertical position on Linux and CrOS as well.
*/
-/*
- * Webkit does not move the absolute positioned input element properly and
- * filed bug 48348 to track the problem.
- * https://bugs.webkit.org/show_bug.cgi?id=48348
- * In the mean time, mark the outer label element 'relative' so that webkit
- * aligns the input element properly.
- */
-label.checkbox,
-label.radio {
- position: relative;
-}
-
-label.checkbox > input,
-label.radio > input {
+label > input[type=checkbox],
+label > input[type=radio] {
margin-top: 1px;
- position: absolute;
}
-label.checkbox > span,
-label.radio > span,
.suboption {
-webkit-margin-start: 16px;
- display: block;
}
-html[os=mac] label.checkbox > input,
-html[os=mac] label.radio > input {
+html[os=mac] label > input[type=checkbox],
+html[os=mac] label > input[type=radio] {
margin-top: 2px;
}
diff --git a/chrome/browser/resources/options/options_page.js b/chrome/browser/resources/options/options_page.js
index b293331..057e86d 100644
--- a/chrome/browser/resources/options/options_page.js
+++ b/chrome/browser/resources/options/options_page.js
@@ -24,20 +24,21 @@ cr.define('options', function() {
this.managed = false;
}
- OptionsPage.registeredPages_ = {};
-
/**
- * Pages which are nested under a main page.
+ * Main level option pages.
+ * @protected
*/
- OptionsPage.registeredSubPages_ = {};
+ OptionsPage.registeredPages = {};
/**
* Pages which are meant to behave like modal dialogs.
+ * @protected
*/
- OptionsPage.registeredOverlayPages_ = {};
+ OptionsPage.registeredOverlayPages = {};
/**
* Whether or not |initialize| has been called.
+ * @private
*/
OptionsPage.initialized_ = false;
@@ -46,16 +47,50 @@ cr.define('options', function() {
* @param {string} pageName Page name.
*/
OptionsPage.showPageByName = function(pageName) {
- for (var name in OptionsPage.registeredPages_) {
- var page = OptionsPage.registeredPages_[name];
- page.visible = name == pageName;
+ var targetPage = this.registeredPages[pageName];
+
+ // Determine if the root page is 'sticky', meaning that it
+ // shouldn't change when showing a sub-page. This can happen for special
+ // pages like Search.
+ var rootPage = null;
+ for (var name in this.registeredPages) {
+ var page = this.registeredPages[name];
+ if (page.visible && !page.parentPage) {
+ rootPage = page;
+ break;
+ }
}
- for (var name in OptionsPage.registeredSubPages_) {
- var pageInfo = OptionsPage.registeredSubPages_[name];
- var match = name == pageName;
- if (match && document.documentElement.getAttribute('hide-menu') != 'true')
- pageInfo.parentPage.visible = true;
- pageInfo.page.visible = match;
+ var isRootPageLocked =
+ rootPage && rootPage.sticky && targetPage.parentPage;
+
+ // Notify pages if they will be hidden.
+ for (var name in this.registeredPages) {
+ var page = this.registeredPages[name];
+ if (!page.parentPage && isRootPageLocked)
+ continue;
+ if (page.willHidePage && name != pageName &&
+ !page.isAncestorOfPage(targetPage))
+ page.willHidePage();
+ }
+
+ // Update visibilities to show only the hierarchy of the target page.
+ for (var name in this.registeredPages) {
+ var page = this.registeredPages[name];
+ if (!page.parentPage && isRootPageLocked)
+ continue;
+ page.visible = name == pageName ||
+ (document.documentElement.getAttribute('hide-menu') != 'true' &&
+ page.isAncestorOfPage(targetPage));
+ }
+
+ // Notify pages if they were shown.
+ for (var name in this.registeredPages) {
+ var page = this.registeredPages[name];
+ if (!page.parentPage && isRootPageLocked)
+ continue;
+ if (page.didShowPage && (name == pageName ||
+ page.isAncestorOfPage(targetPage)))
+ page.didShowPage();
}
};
@@ -66,10 +101,7 @@ cr.define('options', function() {
* @param {string} hash The value of the hash component of the URL.
*/
OptionsPage.handleHashForPage = function(pageName, hash) {
- var page = OptionsPage.registeredPages_[pageName];
- if (!page) {
- page = OptionsPage.registeredSubPages_[pageName].page;
- }
+ var page = this.registeredPages[pageName];
page.handleHash(hash);
};
@@ -78,48 +110,80 @@ cr.define('options', function() {
* @param {string} overlayName Page name.
*/
OptionsPage.showOverlay = function(overlayName) {
- if (OptionsPage.registeredOverlayPages_[overlayName]) {
- OptionsPage.registeredOverlayPages_[overlayName].visible = true;
+ if (this.registeredOverlayPages[overlayName]) {
+ this.registeredOverlayPages[overlayName].visible = true;
+ }
+ };
+
+ /**
+ * Returns whether or not an overlay is visible.
+ * @return {boolean} True if an overlay is visible.
+ * @private
+ */
+ OptionsPage.isOverlayVisible_ = function() {
+ for (var name in this.registeredOverlayPages) {
+ if (this.registeredOverlayPages[name].visible)
+ return true;
}
+ return false;
};
/**
* Clears overlays (i.e. hide all overlays).
*/
OptionsPage.clearOverlays = function() {
- for (var name in OptionsPage.registeredOverlayPages_) {
- var page = OptionsPage.registeredOverlayPages_[name];
+ for (var name in this.registeredOverlayPages) {
+ var page = this.registeredOverlayPages[name];
page.visible = false;
}
};
/**
- * Clears overlays if the key event is ESC.
- * @param {Event} e Key event.
- * @private
+ * Returns the topmost visible page, or null if no page is visible.
+ * @return {OptionPage} The topmost visible page.
*/
- OptionsPage.clearOverlaysOnEsc_ = function(e) {
- if (e.keyCode == 27) { // Esc
- OptionsPage.clearOverlays();
+ OptionsPage.getTopmostVisiblePage = function() {
+ var topPage = null;
+ for (var name in this.registeredPages) {
+ var page = this.registeredPages[name];
+ if (page.visible &&
+ (!topPage || page.nestingLevel > topPage.nestingLevel))
+ topPage = page;
}
+ return topPage;
+ }
+
+ /**
+ * Closes the topmost open subpage, if any.
+ */
+ OptionsPage.closeTopSubPage = function() {
+ var topPage = this.getTopmostVisiblePage();
+ if (topPage && topPage.parentPage)
+ topPage.visible = false;
};
/**
- * Closes any currently-open subpage.
+ * Closes all subpages below the given level.
+ * @param {number} level The nesting level to close below.
*/
- OptionsPage.closeSubPage = function() {
- for (var name in OptionsPage.registeredSubPages_) {
- var pageInfo = OptionsPage.registeredSubPages_[name];
- if (pageInfo.page.visible) {
- pageInfo.page.visible = false;
- // Since the managed pref banner lives outside the overlay, and the
- // parent is not changing visibility, update the banner explicitly.
- pageInfo.parentPage.updateManagedBannerVisibility();
- }
+ OptionsPage.closeSubPagesToLevel = function(level) {
+ var topPage = this.getTopmostVisiblePage();
+ while (topPage && topPage.nestingLevel > level) {
+ topPage.visible = false;
+ topPage = topPage.parentPage;
}
};
/**
+ * Updates managed banner visibility state based on the topmost page.
+ */
+ OptionsPage.updateManagedBannerVisibility = function() {
+ var topPage = this.getTopmostVisiblePage();
+ if (topPage)
+ topPage.updateManagedBannerVisibility();
+ };
+
+ /**
* Shows the tab contents for the given navigation tab.
* @param {!Element} tab The tab that the user clicked.
*/
@@ -149,7 +213,7 @@ cr.define('options', function() {
* @param {OptionsPage} page Page to register.
*/
OptionsPage.register = function(page) {
- OptionsPage.registeredPages_[page.name] = page;
+ this.registeredPages[page.name] = page;
// Create and add new page <li> element to navbar.
var pageNav = document.createElement('li');
pageNav.id = page.name + 'PageNav';
@@ -173,24 +237,59 @@ cr.define('options', function() {
};
/**
- * Registers a new Sub tab page.
- * @param {OptionsPage} page Page to register.
+ * Find an enclosing section for an element if it exists.
+ * @param {Element} element Element to search.
+ * @return {OptionPage} The section element, or null.
+ * @private
*/
- OptionsPage.registerSubPage = function(subPage, parentPage) {
- OptionsPage.registeredSubPages_[subPage.name] = {
- page: subPage, parentPage: parentPage };
+ OptionsPage.findSectionForNode_ = function(node) {
+ while (node = node.parentNode) {
+ if (node.nodeName == 'SECTION')
+ return node;
+ }
+ return null;
+ };
+
+ /**
+ * Registers a new Sub-page.
+ * @param {OptionsPage} subPage Sub-page to register.
+ * @param {OptionsPage} parentPage Associated parent page for this page.
+ * @param {Array} associatedControls Array of control elements that lead to
+ * this sub-page. The first item is typically a button in a root-level
+ * page. There may be additional buttons for nested sub-pages.
+ */
+ OptionsPage.registerSubPage = function(subPage,
+ parentPage,
+ associatedControls) {
+ this.registeredPages[subPage.name] = subPage;
+ subPage.parentPage = parentPage;
+ if (associatedControls) {
+ subPage.associatedControls = associatedControls;
+ if (associatedControls.length) {
+ subPage.associatedSection =
+ this.findSectionForNode_(associatedControls[0]);
+ }
+ }
subPage.tab = undefined;
- subPage.isSubPageSheet = true;
subPage.initializePage();
};
/**
* Registers a new Overlay page.
* @param {OptionsPage} page Page to register, must be a class derived from
- * OptionsPage.
+ * @param {Array} associatedControls Array of control elements associated with
+ * this page.
*/
- OptionsPage.registerOverlay = function(page) {
- OptionsPage.registeredOverlayPages_[page.name] = page;
+ OptionsPage.registerOverlay = function(page,
+ associatedControls) {
+ this.registeredOverlayPages[page.name] = page;
+ if (associatedControls) {
+ page.associatedControls = associatedControls;
+ if (associatedControls.length) {
+ page.associatedSection =
+ this.findSectionForNode_(associatedControls[0]);
+ }
+ }
page.tab = undefined;
page.isOverlay = true;
page.initializePage();
@@ -202,7 +301,7 @@ cr.define('options', function() {
*/
OptionsPage.setState = function(data) {
if (data && data.pageName) {
- OptionsPage.showPageByName(data.pageName);
+ this.showPageByName(data.pageName);
}
};
@@ -214,13 +313,48 @@ cr.define('options', function() {
chrome.send('coreOptionsInitialize');
this.initialized_ = true;
- // Set up the overlay sheet. Clicks on the visible part of the parent page
- // should close the overlay, not fall through to the parent page.
- $('subpage-sheet-container').onclick = function(event) {
- if (!$('subpage-sheet').contains(event.target))
- OptionsPage.closeSubPage();
- event.stopPropagation();
+ // Set up the overlay sheets:
+ // Close nested sub-pages when clicking the visible part of an earlier page.
+ for (var level = 1; level <= 2; level++) {
+ var containerId = 'subpage-sheet-container-' + level;
+ $(containerId).onclick = this.subPageClosingClickHandler_(level);
+ }
+ // Hook up the close buttons.
+ var self = this;
+ subpageCloseButtons = document.querySelectorAll('.close-subpage');
+ for (var i = 0; i < subpageCloseButtons.length; i++) {
+ subpageCloseButtons[i].onclick = function() {
+ self.closeTopSubPage();
+ };
}
+
+ // Close the top overlay or sub-page on esc.
+ document.addEventListener('keydown', function(e) {
+ if (e.keyCode == 27) { // Esc
+ if (self.isOverlayVisible_())
+ self.clearOverlays();
+ else
+ self.closeTopSubPage();
+ }
+ });
+ };
+
+ /**
+ * Returns a function to handle clicks behind a subpage at level |level| by
+ * closing all subpages down to |level| - 1.
+ * @param {number} level The level of the subpage being handled.
+ * @return {function} a function to handle clicks outside the given subpage.
+ * @private
+ */
+ OptionsPage.subPageClosingClickHandler_ = function(level) {
+ var self = this;
+ return function(event) {
+ // Clicks on the visible part of the parent page should close the overlay,
+ // not fall through to the parent page.
+ if (!$('subpage-sheet-' + level).contains(event.target))
+ self.closeSubPagesToLevel(level - 1);
+ event.stopPropagation();
+ };
};
/**
@@ -239,6 +373,26 @@ cr.define('options', function() {
__proto__: cr.EventTarget.prototype,
/**
+ * The parent page of this option page, or null for top-level pages.
+ * @type {OptionsPage}
+ */
+ parentPage: null,
+
+ /**
+ * The section on the parent page that is associated with this page.
+ * Can be null.
+ * @type {Element}
+ */
+ associatedSection: null,
+
+ /**
+ * An array of controls that are associated with this page. The first
+ * control should be located on a top-level page.
+ * @type {OptionsPage}
+ */
+ associatedControls: null,
+
+ /**
* Initializes page content.
*/
initializePage: function() {},
@@ -284,13 +438,17 @@ cr.define('options', function() {
this.pageDiv.classList.remove('hidden');
if (this.isOverlay) {
$('overlay').classList.remove('hidden');
- document.addEventListener('keydown',
- OptionsPage.clearOverlaysOnEsc_);
} else {
- if (this.isSubPageSheet)
- $('subpage-sheet-container').classList.remove('hidden');
+ var nestingLevel = this.nestingLevel;
+ if (nestingLevel > 0) {
+ var containerId = 'subpage-sheet-container-' + nestingLevel;
+ $(containerId).classList.remove('hidden');
+ }
- this.updateManagedBannerVisibility();
+ // The managed prefs banner is global, so after any visibility change
+ // update it based on the topmost page, not necessarily this page.
+ // (e.g., if an ancestor is made visible after a child).
+ OptionsPage.updateManagedBannerVisibility();
// Recent webkit change no longer allows url change from "chrome://".
window.history.pushState({pageName: this.name}, this.title);
@@ -302,10 +460,14 @@ cr.define('options', function() {
this.pageDiv.classList.add('hidden');
if (this.isOverlay) {
$('overlay').classList.add('hidden');
- document.removeEventListener('keydown',
- OptionsPage.clearOverlaysOnEsc_);
- } else if (this.isSubPageSheet) {
- $('subpage-sheet-container').classList.add('hidden');
+ } else if (this.parentPage) {
+ var nestingLevel = this.nestingLevel;
+ if (nestingLevel > 0) {
+ var containerId = 'subpage-sheet-container-' + nestingLevel;
+ $(containerId).classList.add('hidden');
+ }
+
+ OptionsPage.updateManagedBannerVisibility();
}
if (this.tab) {
this.tab.classList.remove('navbar-item-selected');
@@ -316,6 +478,45 @@ cr.define('options', function() {
},
/**
+ * The nesting level of this page.
+ * @type {number} The nesting level of this page (0 for top-level page)
+ */
+ get nestingLevel() {
+ var level = 0;
+ var parent = this.parentPage;
+ while (parent) {
+ level++;
+ parent = parent.parentPage;
+ }
+ return level;
+ },
+
+ /**
+ * Whether the page is considered 'sticky', such that it will
+ * remain a top-level page even if sub-pages change.
+ * @type {boolean} True if this page is sticky.
+ */
+ get sticky() {
+ return false;
+ },
+
+ /**
+ * Checks whether this page is an ancestor of the given page in terms of
+ * subpage nesting.
+ * @param {OptionsPage} page
+ * @return {boolean} True if this page is nested under |page|
+ */
+ isAncestorOfPage: function(page) {
+ var parent = page.parentPage;
+ while (parent) {
+ if (parent == this)
+ return true;
+ parent = parent.parentPage;
+ }
+ return false;
+ },
+
+ /**
* Handles a hash value in the URL (such as bar in
* chrome://options/foo#bar). Called on page load. By default, this shows
* an overlay that matches the hash name, but can be overriden by individual
diff --git a/chrome/browser/resources/options/password_manager.css b/chrome/browser/resources/options/password_manager.css
new file mode 100644
index 0000000..48ac0d9
--- /dev/null
+++ b/chrome/browser/resources/options/password_manager.css
@@ -0,0 +1,38 @@
+#saved-passwords-list .url {
+ box-sizing: border-box;
+ width: 40%;
+}
+
+#saved-passwords-list .name {
+ -webkit-box-flex: 1;
+ width: 20%;
+}
+
+#saved-passwords-list .password {
+ -webkit-box-flex: 1;
+ position: relative;
+}
+
+#saved-passwords-list .password > span {
+ background: url('show_password.png');
+ cursor: pointer;
+ height: 18px;
+ position: absolute;
+ top: 5px;
+ width: 40px;
+}
+
+html[dir='ltr'] #saved-passwords-list .password > span {
+ right: 50px;
+}
+
+html[dir='rtl'] #saved-passwords-list .password > span {
+ left: 50px;
+}
+
+#saved-passwords-list .url,
+#saved-passwords-list .name,
+#password-exceptions-list .url {
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
diff --git a/chrome/browser/resources/options/password_manager.html b/chrome/browser/resources/options/password_manager.html
new file mode 100644
index 0000000..b103dbf
--- /dev/null
+++ b/chrome/browser/resources/options/password_manager.html
@@ -0,0 +1,7 @@
+<div id="password-manager" class="page hidden">
+ <h1 i18n-content="passwordsTitle"></h1>
+ <h3 i18n-content="savedPasswordsTitle"></h3>
+ <list id="saved-passwords-list" class="settings-list"></list>
+ <h3 i18n-content="passwordExceptionsTitle"></h3>
+ <list id="password-exceptions-list" class="settings-list"></list>
+</div>
diff --git a/chrome/browser/resources/options/password_manager.js b/chrome/browser/resources/options/password_manager.js
new file mode 100644
index 0000000..ac3fc3a
--- /dev/null
+++ b/chrome/browser/resources/options/password_manager.js
@@ -0,0 +1,142 @@
+// 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.
+
+cr.define('options', function() {
+ const OptionsPage = options.OptionsPage;
+ const ArrayDataModel = cr.ui.ArrayDataModel;
+ const ListSingleSelectionModel = cr.ui.ListSingleSelectionModel;
+
+ /////////////////////////////////////////////////////////////////////////////
+ // PasswordManager class:
+
+ /**
+ * Encapsulated handling of password and exceptions page.
+ * @constructor
+ */
+ function PasswordManager() {
+ this.activeNavTab = null;
+ OptionsPage.call(this,
+ 'passwordManager',
+ templateData.passwordsTitle,
+ 'password-manager');
+ }
+
+ cr.addSingletonGetter(PasswordManager);
+
+ PasswordManager.prototype = {
+ __proto__: OptionsPage.prototype,
+
+ /**
+ * The saved passwords list.
+ * @type {DeletableItemList}
+ * @private
+ */
+ savedPasswordsList_: null,
+
+ /**
+ * The password exceptions list.
+ * @type {DeletableItemList}
+ * @private
+ */
+ passwordExceptionsList_: null,
+
+ initializePage: function() {
+ OptionsPage.prototype.initializePage.call(this);
+
+ this.createSavedPasswordsList_();
+ this.createPasswordExceptionsList_();
+
+ chrome.send('updatePasswordLists');
+ },
+
+ /**
+ * Creates, decorates and initializes the saved passwords list.
+ * @private
+ */
+ createSavedPasswordsList_: function() {
+ this.savedPasswordsList_ = $('saved-passwords-list');
+ options.passwordManager.PasswordsList.decorate(this.savedPasswordsList_);
+ this.savedPasswordsList_.selectionModel = new ListSingleSelectionModel;
+ this.savedPasswordsList_.autoExpands = true;
+ },
+
+ /**
+ * Creates, decorates and initializes the password exceptions list.
+ * @private
+ */
+ createPasswordExceptionsList_: function() {
+ this.passwordExceptionsList_ = $('password-exceptions-list');
+ options.passwordManager.PasswordExceptionsList.decorate(
+ this.passwordExceptionsList_);
+ this.passwordExceptionsList_.selectionModel =
+ new ListSingleSelectionModel;
+ this.passwordExceptionsList_.autoExpands = true;
+ },
+
+ /**
+ * Updates the data model for the saved passwords list with the values from
+ * |entries|.
+ * @param {Array} entries The list of saved password data.
+ */
+ setSavedPasswordsList_: function(entries) {
+ this.savedPasswordsList_.dataModel = new ArrayDataModel(entries);
+ },
+
+ /**
+ * Updates the data model for the password exceptions list with the values
+ * from |entries|.
+ * @param {Array} entries The list of password exception data.
+ */
+ setPasswordExceptionsList_: function(entries) {
+ this.passwordExceptionsList_.dataModel = new ArrayDataModel(entries);
+ },
+ };
+
+ /**
+ * Call to remove a saved password.
+ * @param rowIndex indicating the row to remove.
+ */
+ PasswordManager.removeSavedPassword = function(rowIndex) {
+ chrome.send('removeSavedPassword', [String(rowIndex)]);
+ };
+
+ /**
+ * Call to remove a password exception.
+ * @param rowIndex indicating the row to remove.
+ */
+ PasswordManager.removePasswordException = function(rowIndex) {
+ chrome.send('removePasswordException', [String(rowIndex)]);
+ };
+
+ /**
+ * Call to remove all saved passwords.
+ * @param tab contentType of the tab currently on.
+ */
+ PasswordManager.removeAllPasswords = function() {
+ chrome.send('removeAllSavedPasswords');
+ };
+
+ /**
+ * Call to remove all saved passwords.
+ * @param tab contentType of the tab currently on.
+ */
+ PasswordManager.removeAllPasswordExceptions = function() {
+ chrome.send('removeAllPasswordExceptions');
+ };
+
+ PasswordManager.setSavedPasswordsList = function(entries) {
+ PasswordManager.getInstance().setSavedPasswordsList_(entries);
+ };
+
+ PasswordManager.setPasswordExceptionsList = function(entries) {
+ PasswordManager.getInstance().setPasswordExceptionsList_(entries);
+ };
+
+ // Export
+ return {
+ PasswordManager: PasswordManager
+ };
+
+});
+
diff --git a/chrome/browser/resources/options/password_manager_list.css b/chrome/browser/resources/options/password_manager_list.css
new file mode 100644
index 0000000..40201e9
--- /dev/null
+++ b/chrome/browser/resources/options/password_manager_list.css
@@ -0,0 +1,10 @@
+/*
+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.
+*/
+
+.inactive-password {
+ background: transparent;
+ border: none;
+}
diff --git a/chrome/browser/resources/options/password_manager_list.js b/chrome/browser/resources/options/password_manager_list.js
new file mode 100644
index 0000000..593a9bc
--- /dev/null
+++ b/chrome/browser/resources/options/password_manager_list.js
@@ -0,0 +1,234 @@
+// 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.
+
+cr.define('options.passwordManager', function() {
+ const ArrayDataModel = cr.ui.ArrayDataModel;
+ const DeletableItemList = options.DeletableItemList;
+ const DeletableItem = options.DeletableItem;
+ const List = cr.ui.List;
+
+ /**
+ * Creates a new passwords list item.
+ * @param {Array} entry An array of the form [url, username, password].
+ * @constructor
+ * @extends {cr.ui.ListItem}
+ */
+ function PasswordListItem(entry) {
+ var el = cr.doc.createElement('div');
+ el.dataItem = entry;
+ el.__proto__ = PasswordListItem.prototype;
+ el.decorate();
+
+ return el;
+ }
+
+ PasswordListItem.prototype = {
+ __proto__: DeletableItem.prototype,
+
+ /** @inheritDoc */
+ decorate: function() {
+ DeletableItem.prototype.decorate.call(this);
+
+ // The URL of the site.
+ var urlLabel = this.ownerDocument.createElement('div');
+ urlLabel.className = 'url';
+ urlLabel.classList.add('favicon-cell');
+ urlLabel.textContent = this.url;
+ urlLabel.style.backgroundImage = url('chrome://favicon/' + this.url);
+ this.contentElement.appendChild(urlLabel);
+
+ // The stored username.
+ var usernameLabel = this.ownerDocument.createElement('div');
+ usernameLabel.className = 'name';
+ usernameLabel.textContent = this.username;
+ this.contentElement.appendChild(usernameLabel);
+
+ // The stored password.
+ var passwordInputDiv = this.ownerDocument.createElement('div');
+ passwordInputDiv.className = 'password';
+
+ // The password input field.
+ var passwordInput = this.ownerDocument.createElement('input');
+ passwordInput.className = 'inactive-password';
+ passwordInput.type = 'password';
+ passwordInput.value = this.password;
+ passwordInputDiv.appendChild(passwordInput);
+
+ // The show/hide button.
+ var buttonSpan = this.ownerDocument.createElement('span');
+ buttonSpan.className = 'hidden';
+ buttonSpan.addEventListener('click', this.onClick_, true);
+ passwordInputDiv.appendChild(buttonSpan);
+
+ this.contentElement.appendChild(passwordInputDiv);
+ },
+
+ /** @inheritDoc */
+ selectionChanged: function() {
+ var passwordInput = this.querySelector('input[type=password]');
+ var buttonSpan = passwordInput.nextSibling;
+ if (this.selected) {
+ passwordInput.classList.remove('inactive-password');
+ buttonSpan.classList.remove('hidden');
+ } else {
+ passwordInput.classList.add('inactive-password');
+ buttonSpan.classList.add('hidden');
+ }
+ },
+
+ /**
+ * On-click event handler. Swaps the type of the input field from password
+ * to text and back.
+ * @private
+ */
+ onClick_: function(event) {
+ // The password is the input element previous to the button span.
+ var buttonSpan = event.currentTarget;
+ var passwordInput = buttonSpan.previousSibling;
+ var type = passwordInput.type;
+ passwordInput.type = type == 'password' ? 'text' : 'password';
+ },
+
+ /**
+ * Get and set the URL for the entry.
+ * @type {string}
+ */
+ get url() {
+ return this.dataItem[0];
+ },
+ set url(url) {
+ this.dataItem[0] = url;
+ },
+
+ /**
+ * Get and set the username for the entry.
+ * @type {string}
+ */
+ get username() {
+ return this.dataItem[1];
+ },
+ set username(username) {
+ this.dataItem[1] = username;
+ },
+
+ /**
+ * Get and set the password for the entry.
+ * @type {string}
+ */
+ get password() {
+ return this.dataItem[2];
+ },
+ set password(password) {
+ this.dataItem[2] = password;
+ },
+ };
+
+ /**
+ * Creates a new PasswordExceptions list item.
+ * @param {Array} entry A pair of the form [url, username].
+ * @constructor
+ * @extends {Deletable.ListItem}
+ */
+ function PasswordExceptionsListItem(entry) {
+ var el = cr.doc.createElement('div');
+ el.dataItem = entry;
+ el.__proto__ = PasswordExceptionsListItem.prototype;
+ el.decorate();
+
+ return el;
+ }
+
+ PasswordExceptionsListItem.prototype = {
+ __proto__: DeletableItem.prototype,
+
+ /**
+ * Call when an element is decorated as a list item.
+ */
+ decorate: function() {
+ DeletableItem.prototype.decorate.call(this);
+
+ // The URL of the site.
+ var urlLabel = this.ownerDocument.createElement('div');
+ urlLabel.className = 'url';
+ urlLabel.classList.add('favicon-cell');
+ urlLabel.textContent = this.url;
+ urlLabel.style.backgroundImage = url('chrome://favicon/' + this.url);
+ this.contentElement.appendChild(urlLabel);
+ },
+
+ /**
+ * Get the url for the entry.
+ * @type {string}
+ */
+ get url() {
+ return this.dataItem;
+ },
+ set url(url) {
+ this.dataItem = url;
+ },
+ };
+
+ /**
+ * Create a new passwords list.
+ * @constructor
+ * @extends {cr.ui.List}
+ */
+ var PasswordsList = cr.ui.define('list');
+
+ PasswordsList.prototype = {
+ __proto__: DeletableItemList.prototype,
+
+ /** @inheritDoc */
+ createItem: function(entry) {
+ return new PasswordListItem(entry);
+ },
+
+ /** @inheritDoc */
+ deleteItemAtIndex: function(index) {
+ PasswordManager.removeSavedPassword(index);
+ },
+
+ /**
+ * The length of the list.
+ */
+ get length() {
+ return this.dataModel.length;
+ },
+ };
+
+ /**
+ * Create a new passwords list.
+ * @constructor
+ * @extends {cr.ui.List}
+ */
+ var PasswordExceptionsList = cr.ui.define('list');
+
+ PasswordExceptionsList.prototype = {
+ __proto__: DeletableItemList.prototype,
+
+ /** @inheritDoc */
+ createItem: function(entry) {
+ return new PasswordExceptionsListItem(entry);
+ },
+
+ /** @inheritDoc */
+ deleteItemAtIndex: function(index) {
+ PasswordManager.removePasswordException(index);
+ },
+
+ /**
+ * The length of the list.
+ */
+ get length() {
+ return this.dataModel.length;
+ },
+ };
+
+ return {
+ PasswordListItem: PasswordListItem,
+ PasswordExceptionsListItem: PasswordExceptionsListItem,
+ PasswordsList: PasswordsList,
+ PasswordExceptionsList: PasswordExceptionsList,
+ };
+});
diff --git a/chrome/browser/resources/options/passwords_exceptions.html b/chrome/browser/resources/options/passwords_exceptions.html
deleted file mode 100644
index c75f715..0000000
--- a/chrome/browser/resources/options/passwords_exceptions.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<div class="page hidden" id="passwordsExceptionsPage">
- <h1 i18n-content="savedPasswordsExceptionsTitle"></h1>
-
- <!-- Navigation tabs -->
- <div class="subpages-nav-tabs">
- <span id="passwords-nav-tab" class="inactive-tab"
- tab-contents="passwordsTab">
- <span class="inactive-tab-label" i18n-content="passwordsTabTitle"></span>
- <span class="active-tab-label" i18n-content="passwordsTabTitle"></span>
- </span>
- <span id="password-exceptions-nav-tab" class="inactive-tab"
- tab-contents="passwordExceptionsTab">
- <span class="inactive-tab-label"
- i18n-content="passwordExceptionsTabTitle"></span>
- <span class="active-tab-label"
- i18n-content="passwordExceptionsTabTitle"></span>
- </span>
- </div>
-
- <!-- Passwords tab contents -->
- <div id="passwordsTab" class="subpages-tab-contents">
- <section>
- <div id="passwordsArea">
- <list id="savedPasswordsList"></list>
- </div>
- </section>
- </div>
-
- <!-- Exceptions tab contents -->
- <div id="passwordExceptionsTab" class="subpages-tab-contents">
- <section>
- <div id="passwordExceptionsArea">
- <list id="passwordExceptionsList"></list>
- </div>
- </section>
- </div>
-</div>
diff --git a/chrome/browser/resources/options/passwords_exceptions.js b/chrome/browser/resources/options/passwords_exceptions.js
deleted file mode 100644
index f325b1d..0000000
--- a/chrome/browser/resources/options/passwords_exceptions.js
+++ /dev/null
@@ -1,116 +0,0 @@
-// 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.
-
-cr.define('options', function() {
-
- var OptionsPage = options.OptionsPage;
-
- /////////////////////////////////////////////////////////////////////////////
- // PasswordsExceptions class:
-
- /**
- * Encapsulated handling of password and exceptions page.
- * @constructor
- */
- function PasswordsExceptions() {
- this.activeNavTab = null;
- OptionsPage.call(this, 'passwordsExceptions',
- templateData.savedPasswordsExceptionsTitle,
- 'passwordsExceptionsPage');
- }
-
- cr.addSingletonGetter(PasswordsExceptions);
-
- PasswordsExceptions.prototype = {
- __proto__: OptionsPage.prototype,
-
- initializePage: function() {
- OptionsPage.prototype.initializePage.call(this);
-
- options.passwordsExceptions.PasswordsListArea.decorate($('passwordsArea'));
- options.passwordsExceptions.PasswordExceptionsListArea.decorate(
- $('passwordExceptionsArea'));
-
- $('password-exceptions-nav-tab').onclick = function() {
- OptionsPage.showTab($('password-exceptions-nav-tab'));
- passwordExceptionsList.redraw();
- }
- },
-
- setSavedPasswordsList_: function(entries) {
- savedPasswordsList.clear();
- for (var i = 0; i < entries.length; i++) {
- savedPasswordsList.addEntry(entries[i]);
- }
- },
-
- setPasswordExceptionsList_: function(entries) {
- passwordExceptionsList.clear();
- for (var i = 0; i < entries.length; i++) {
- passwordExceptionsList.addEntry(entries[i]);
- }
- },
-
- };
-
- PasswordsExceptions.load = function() {
- chrome.send('loadLists');
- };
-
- /**
- * Call to remove a saved password.
- * @param rowIndex indicating the row to remove.
- */
- PasswordsExceptions.removeSavedPassword = function(rowIndex) {
- chrome.send('removeSavedPassword', [String(rowIndex)]);
- };
-
- /**
- * Call to remove a password exception.
- * @param rowIndex indicating the row to remove.
- */
- PasswordsExceptions.removePasswordException = function(rowIndex) {
- chrome.send('removePasswordException', [String(rowIndex)]);
- };
-
-
- /**
- * Call to remove all saved passwords.
- * @param tab contentType of the tab currently on.
- */
- PasswordsExceptions.removeAllPasswords = function() {
- chrome.send('removeAllSavedPasswords');
- };
-
- /**
- * Call to remove all saved passwords.
- * @param tab contentType of the tab currently on.
- */
- PasswordsExceptions.removeAllPasswordExceptions = function() {
- chrome.send('removeAllPasswordExceptions');
- };
-
- PasswordsExceptions.showSelectedPassword = function(index) {
- chrome.send('showSelectedPassword', [String(index)]);
- };
-
- PasswordsExceptions.setSavedPasswordsList = function(entries) {
- PasswordsExceptions.getInstance().setSavedPasswordsList_(entries);
- };
-
- PasswordsExceptions.setPasswordExceptionsList = function(entries) {
- PasswordsExceptions.getInstance().setPasswordExceptionsList_(entries);
- };
-
- PasswordsExceptions.selectedPasswordCallback = function(password) {
- passwordsArea.displayReturnedPassword(password);
- };
-
- // Export
- return {
- PasswordsExceptions: PasswordsExceptions
- };
-
-});
-
diff --git a/chrome/browser/resources/options/passwords_exceptions_list.css b/chrome/browser/resources/options/passwords_exceptions_list.css
deleted file mode 100644
index c62adbe..0000000
--- a/chrome/browser/resources/options/passwords_exceptions_list.css
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
-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.
-*/
-
-.passwordsUsername {
- float: right;
-}
diff --git a/chrome/browser/resources/options/passwords_exceptions_list.js b/chrome/browser/resources/options/passwords_exceptions_list.js
deleted file mode 100644
index 15fd0b6..0000000
--- a/chrome/browser/resources/options/passwords_exceptions_list.js
+++ /dev/null
@@ -1,398 +0,0 @@
-// 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.
-
-cr.define('options.passwordsExceptions', function() {
-
- const List = cr.ui.List;
- const ListItem = cr.ui.ListItem;
- const ArrayDataModel = cr.ui.ArrayDataModel;
-
- /**
- * Creates a new passwords list item.
- * @param {Array} entry A pair of the form [url, username].
- * @constructor
- * @extends {cr.ui.ListItem}
- */
- function PasswordsListItem(entry) {
- var el = cr.doc.createElement('li');
- el.dataItem = entry;
- el.__proto__ = PasswordsListItem.prototype;
- el.decorate();
-
- return el;
- }
-
- PasswordsListItem.prototype = {
- __proto__: ListItem.prototype,
-
- /**
- * Call when an element is decorated as a list item.
- */
- decorate: function() {
- ListItem.prototype.decorate.call(this);
-
- // Labels for display
- var urlLabel = cr.doc.createElement('span');
- urlLabel.textContent = this.url;
- this.appendChild(urlLabel);
- this.urlLabel = urlLabel;
-
- var usernameLabel = cr.doc.createElement('span');
- usernameLabel.textContent = this.username;
- usernameLabel.className = 'passwordsUsername';
- this.appendChild(usernameLabel);
- this.usernameLabel = usernameLabel;
- },
-
- /**
- * Get the url for the entry.
- * @type {string}
- */
- get url() {
- return this.dataItem[0];
- },
- set url(url) {
- this.dataItem[0] = url;
- },
-
- /**
- * Get the username for the entry.
- * @type {string}
- */
- get username() {
- return this.dataItem[1];
- },
- set username(username) {
- this.dataItem[1] = username;
- },
- };
-
- /**
- * Creates a new PasswordExceptions list item.
- * @param {Array} entry A pair of the form [url, username].
- * @constructor
- * @extends {cr.ui.ListItem}
- */
- function PasswordExceptionsListItem(entry) {
- var el = cr.doc.createElement('li');
- el.dataItem = entry;
- el.__proto__ = PasswordExceptionsListItem.prototype;
- el.decorate();
-
- return el;
- }
-
- PasswordExceptionsListItem.prototype = {
- __proto__: ListItem.prototype,
-
- /**
- * Call when an element is decorated as a list item.
- */
- decorate: function() {
- ListItem.prototype.decorate.call(this);
-
- // Labels for display
- var urlLabel = cr.doc.createElement('span');
- urlLabel.textContent = this.url;
- this.appendChild(urlLabel);
- this.urlLabel = urlLabel;
- },
-
- /**
- * Get the url for the entry.
- * @type {string}
- */
- get url() {
- return this.dataItem;
- },
- set url(url) {
- this.dataItem = url;
- },
- };
-
-
- /**
- * Create a new passwords list.
- * @constructor
- * @extends {cr.ui.List}
- */
- var PasswordsList = cr.ui.define('list');
-
- PasswordsList.prototype = {
- __proto__: List.prototype,
- /**
- * Called when an element is decorated as a list.
- */
- decorate: function() {
- List.prototype.decorate.call(this);
-
- this.dataModel = new ArrayDataModel([]);
- },
-
- /**
- * Creates an item to go in the list.
- * @param {Object} entry The element from the data model for this row.
- */
- createItem: function(entry) {
- return new PasswordsListItem(entry);
- },
-
- /**
- * Adds an entry to the js model.
- * @param {Array} entry A pair of the form [url, username].
- */
- addEntry: function(entry) {
- this.dataModel.push(entry);
- this.listArea.updateButtonSensitivity();
- },
-
- /**
- * Remove all entries from the js model.
- */
- clear: function() {
- this.dataModel = new ArrayDataModel([]);
- this.listArea.updateButtonSensitivity();
- },
-
- /**
- * Remove selected row from browser's model.
- */
- removeSelectedRow: function() {
- var selectedIndex = this.selectionModel.selectedIndex;
- PasswordsExceptions.removeSavedPassword(selectedIndex);
- },
-
- showSelectedPassword: function() {
- var selectedIndex = this.selectionModel.selectedIndex;
- PasswordsExceptions.showSelectedPassword(selectedIndex);
- },
-
- /**
- * The length of the list.
- */
- get length() {
- return this.dataModel.length;
- },
- };
-
- /**
- * Create a new passwords list.
- * @constructor
- * @extends {cr.ui.List}
- */
- var PasswordExceptionsList = cr.ui.define('list');
-
- PasswordExceptionsList.prototype = {
- __proto__: List.prototype,
- /**
- * Called when an element is decorated as a list.
- */
- decorate: function() {
- List.prototype.decorate.call(this);
-
- this.dataModel = new ArrayDataModel([]);
- },
-
- /**
- * Creates an item to go in the list.
- * @param {Object} entry The element from the data model for this row.
- */
- createItem: function(entry) {
- return new PasswordExceptionsListItem(entry);
- },
-
- /**
- * Adds an entry to the js model.
- * @param {Array} entry A pair of the form [url, username].
- */
- addEntry: function(entry) {
- this.dataModel.push(entry);
- this.listArea.updateButtonSensitivity();
- },
-
- /**
- * Remove all entries from the js model.
- */
- clear: function() {
- this.dataModel = new ArrayDataModel([]);
- this.listArea.updateButtonSensitivity();
- },
-
- /**
- * Remove selected row from browser's model.
- */
- removeSelectedRow: function() {
- var selectedIndex = this.selectionModel.selectedIndex;
- PasswordsExceptions.removePasswordException(selectedIndex);
- },
-
- /**
- * The length of the list.
- */
- get length() {
- return this.dataModel.length;
- },
- };
-
- /**
- * Create a new passwords list area.
- * @constructor
- * @extends {cr.ui.div}
- */
- var PasswordsListArea = cr.ui.define('div');
-
- PasswordsListArea.prototype = {
- __proto__: HTMLDivElement.prototype,
-
- decorate: function() {
- this.passwordsList = this.querySelector('list');
- this.passwordsList.listArea = this;
-
- PasswordsList.decorate(this.passwordsList);
- this.passwordsList.selectionModel.addEventListener(
- 'change', this.handleOnSelectionChange_.bind(this));
-
- var removeRow = cr.doc.createElement('button');
- removeRow.textContent = templateData.passwordsRemoveButton;
- this.appendChild(removeRow);
- this.removeRow = removeRow;
-
- var removeAll = cr.doc.createElement('button');
- removeAll.textContent = templateData.passwordsRemoveAllButton;
- this.appendChild(removeAll);
- this.removeAll = removeAll;
-
- var showHidePassword = cr.doc.createElement('button');
- showHidePassword.textContent = templateData.passwordsShowButton;
- this.appendChild(showHidePassword);
- this.showHidePassword = showHidePassword;
- this.showingPassword = false
-
- var passwordLabel = cr.doc.createElement('span');
- this.appendChild(passwordLabel);
- this.passwordLabel = passwordLabel;
-
- var self = this;
- removeRow.onclick = function(event) {
- self.passwordsList.removeSelectedRow();
- };
-
- removeAll.onclick = function(event) {
- AlertOverlay.show(undefined,
- localStrings.getString('passwordsRemoveAllWarning'),
- localStrings.getString('yesButtonLabel'),
- localStrings.getString('noButtonLabel'),
- function() { PasswordsExceptions.removeAllPasswords(); });
- };
-
- showHidePassword.onclick = function(event) {
- if(self.showingPassword) {
- self.passwordLabel.textContent = "";
- this.textContent = templateData.passwordsShowButton;
- } else {
- self.passwordsList.showSelectedPassword();
- this.textContent = templateData.passwordsHideButton;
- }
- self.showingPassword = !self.showingPassword;
- };
-
- this.updateButtonSensitivity();
- },
-
- displayReturnedPassword: function(password) {
- this.passwordLabel.textContent = password;
- },
-
- /**
- * Update the button's states
- */
- updateButtonSensitivity: function() {
- var selectionSize = this.passwordsList.selectedItems.length;
- this.removeRow.disabled = selectionSize == 0;
- this.showHidePassword.disabled = selectionSize == 0;
- this.removeAll.disabled = this.passwordsList.length == 0;
- },
-
- /**
- * Callback from selection model
- * @param {!cr.Event} ce Event with change info.
- * @private
- */
- handleOnSelectionChange_: function(ce) {
- this.passwordLabel.textContent = "";
- this.showHidePassword.textContent = templateData.passwordsShowButton;
- this.showingPassword = false;
- this.updateButtonSensitivity();
- },
- };
-
- /**
- * Create a new passwords list area.
- * @constructor
- * @extends {cr.ui.div}
- */
- var PasswordExceptionsListArea = cr.ui.define('div');
-
- PasswordExceptionsListArea.prototype = {
- __proto__: HTMLDivElement.prototype,
-
- decorate: function() {
- this.passwordExceptionsList = this.querySelector('list');
- this.passwordExceptionsList.listArea = this;
-
- PasswordExceptionsList.decorate(this.passwordExceptionsList);
- this.passwordExceptionsList.selectionModel.addEventListener(
- 'change', this.handleOnSelectionChange_.bind(this));
-
- var removeRow = cr.doc.createElement('button');
- removeRow.textContent = templateData.passwordsRemoveButton;
- this.appendChild(removeRow);
- this.removeRow = removeRow;
-
- var removeAll = cr.doc.createElement('button');
- removeAll.textContent = templateData.passwordsRemoveAllButton;
- this.appendChild(removeAll);
- this.removeAll = removeAll;
-
- var self = this;
- removeRow.onclick = function(event) {
- self.passwordExceptionsList.removeSelectedRow();
- };
-
- removeAll.onclick = function(event) {
- PasswordsExceptions.removeAllPasswordExceptions();
- };
-
- this.updateButtonSensitivity();
- },
-
- /**
- * Update the button's states
- */
- updateButtonSensitivity: function() {
- var selectionSize = this.passwordExceptionsList.selectedItems.length;
- this.removeRow.disabled = selectionSize == 0;
- this.removeAll.disabled = this.passwordExceptionsList.length == 0;
- },
-
- /**
- * Callback from selection model
- * @param {!cr.Event} ce Event with change info.
- * @private
- */
- handleOnSelectionChange_: function(ce) {
- this.updateButtonSensitivity();
- },
- };
-
-
- return {
- PasswordsListItem: PasswordsListItem,
- PasswordExceptionsListItem: PasswordExceptionsListItem,
- PasswordsList: PasswordsList,
- PasswordExceptionsList: PasswordExceptionsList,
- PasswordsListArea: PasswordsListArea,
- PasswordExceptionsListArea: PasswordExceptionsListArea
- };
-});
diff --git a/chrome/browser/resources/options/personal_options.html b/chrome/browser/resources/options/personal_options.html
index 468b50a..3fba146 100644
--- a/chrome/browser/resources/options/personal_options.html
+++ b/chrome/browser/resources/options/personal_options.html
@@ -26,11 +26,76 @@
<section id="sync-section">
<h3 i18n-content="syncSection"></h3>
<div>
+ <select id="sync-select" pref="sync.keep_everything_synced"></select>
+ <table id="sync-table">
+ <tr>
+ <td class="option-name">
+ <label class="checkbox">
+ <input id="settings-check" pref="sync.preferences"
+ type="checkbox">
+ <span i18n-content="syncsettings"></span>
+ </label>
+ </td>
+ <td class="option-name">
+ <label class="checkbox">
+ <input id="bookmarks-check" pref="sync.bookmarks" type="checkbox">
+ <span i18n-content="syncbookmarks"></span>
+ </label>
+ </td>
+ <td class="option-name">
+ <label class="checkbox">
+ <input id="extensions-check" pref="sync.extensions"
+ type="checkbox">
+ <span i18n-content="syncextensions"></span>
+ </label>
+ </td>
+ </tr>
+ <tr>
+ <td class="option-name">
+ <label class="checkbox">
+ <input id="autofill-check" pref="sync.autofill" type="checkbox">
+ <span i18n-content="syncautofill"></span>
+ </label>
+ </td>
+ <td class="option-name">
+ <label class="checkbox">
+ <input id="themes-check" pref="sync.themes" type="checkbox">
+ <span i18n-content="syncthemes"></span>
+ </label>
+ </td>
+ <td class="option-name">
+ <label class="checkbox">
+ <input id="apps-check" pref="sync.apps" type="checkbox">
+ <span i18n-content="syncapps"></span>
+ </label>
+ </td>
+ </tr>
+ <tr>
+ <td class="option-name">
+ <label class="checkbox">
+ <input id="typedurls-check" pref="sync.typed_urls"
+ type="checkbox">
+ <span i18n-content="synctypedurls"></span>
+ </label>
+ </td>
+ <td class="option-name">
+ <label class="checkbox">
+ <input id="passwords-check" pref="sync.passwords" type="checkbox">
+ <span i18n-content="syncpasswords"></span>
+ </label>
+ </td>
+ <td class="option-name">
+ <label class="checkbox">
+ <input id="sessions-check" pref="sync.sessions" type="checkbox">
+ <span i18n-content="syncsessions"></span>
+ </label>
+ </td>
+ </tr>
+ </table>
<div id="sync-status" class="section-text"></div>
<button id="sync-action-link" class="link-button"></button>
<div>
<button id="start-stop-sync"></button>
- <button id="customize-sync""></button>
</div>
<a href="https://www.google.com/dashboard" id="privacy-dashboard-link"
i18n-content="privacyDashboardLink" target="_blank"></a>
@@ -58,7 +123,13 @@
<section>
<h3 i18n-content="autofill"></h3>
<div>
- <button id="autofill-options" i18n-content="autofillOptions"></button>
+ <label class="checkbox">
+ <input id="autoFillEnabled" pref="autofill.enabled"
+ metric="Options_FormAutofill" type="checkbox">
+ <span i18n-content="autoFillEnabled"></span>
+ </label>
+ <button id="autofill-settings"
+ i18n-content="manageAutofillSettings"></button>
</div>
</section>
<if expr="not pp_ifdef('chromeos')">
@@ -78,9 +149,9 @@
i18n-content="themesGTKButton"></button>
<button id="themes-reset"
i18n-content="themesSetClassic"></button>
- <a id="themes-gallery" i18n-content="themesGallery"
- i18n-values="href:themesGalleryURL" target="_blank"></a>
</div>
+ <a id="themes-gallery" i18n-content="themesGallery"
+ i18n-values="href:themesGalleryURL" target="_blank"></a>
<label class="radio">
<input name="decorations_radio"
pref="browser.custom_chrome_frame"
@@ -100,7 +171,9 @@
<section>
<h3 i18n-content="themes"></h3>
<div>
- <button id="themes-reset" i18n-content="themesReset"></button>
+ <div>
+ <button id="themes-reset" i18n-content="themesReset"></button>
+ </div>
<a id="themes-gallery" i18n-content="themesGallery"
i18n-values="href:themesGalleryURL" target="_blank"></a>
</div>
diff --git a/chrome/browser/resources/options/personal_options.js b/chrome/browser/resources/options/personal_options.js
index d3d9489..3600f07 100644
--- a/chrome/browser/resources/options/personal_options.js
+++ b/chrome/browser/resources/options/personal_options.js
@@ -10,10 +10,10 @@ cr.define('options', function() {
var syncEnabled = false;
var syncSetupCompleted = false;
- //
- // PersonalOptions class
- // Encapsulated handling of personal options page.
- //
+ /**
+ * Encapsulated handling of personal options page.
+ * @constructor
+ */
function PersonalOptions() {
OptionsPage.call(this, 'personal', templateData.personalPage,
'personal-page');
@@ -27,13 +27,10 @@ cr.define('options', function() {
// Initialize PersonalOptions page.
initializePage: function() {
- // Call base class implementation to starts preference initialization.
+ // Call base class implementation to start preference initialization.
OptionsPage.prototype.initializePage.call(this);
var self = this;
- $('customize-sync').onclick = function(event) {
- OptionsPage.showPageByName('sync');
- };
$('sync-action-link').onclick = function(event) {
chrome.send('showSyncLoginDialog');
};
@@ -47,13 +44,12 @@ cr.define('options', function() {
chrome.send('openPrivacyDashboardTabAndActivate');
};
$('manage-passwords').onclick = function(event) {
- PasswordsExceptions.load();
- OptionsPage.showPageByName('passwordsExceptions');
+ OptionsPage.showPageByName('passwordManager');
OptionsPage.showTab($('passwords-nav-tab'));
chrome.send('coreOptionsUserMetricsAction',
- ['Options_ShowPasswordsExceptions']);
+ ['Options_ShowPasswordManager']);
};
- $('autofill-options').onclick = function(event) {
+ $('autofill-settings').onclick = function(event) {
OptionsPage.showPageByName('autoFillOptions');
chrome.send('coreOptionsUserMetricsAction',
['Options_ShowAutoFillSettings']);
@@ -62,6 +58,21 @@ cr.define('options', function() {
chrome.send('themesReset');
};
+ // Initialize sync select control.
+ $('sync-select').initializeValues(templateData.syncSelectList);
+ $('sync-select').onchange = function(event) {
+ self.updateSyncSelection_();
+ }
+
+ var syncCheckboxes = $('sync-table').getElementsByTagName('input');
+ for (var i = 0; i < syncCheckboxes.length; i++) {
+ if (syncCheckboxes[i].type == "checkbox") {
+ syncCheckboxes[i].onclick = function(event) {
+ chrome.send('updatePreferredDataTypes');
+ };
+ }
+ }
+
if (!cr.isChromeOS) {
$('import-data').onclick = function(event) {
OptionsPage.showOverlay('importDataOverlay');
@@ -76,22 +87,41 @@ cr.define('options', function() {
} else {
chrome.send('loadAccountPicture');
}
+
// Disable the screen lock checkbox for the guest mode.
- if (cr.commandLine.options['--bwsi']) {
- var enableScreenLock = $('enable-screen-lock');
- enableScreenLock.disabled = true;
- // Mark that this is manually disabled. See also pref_ui.js.
- enableScreenLock.manually_disabled = true;
+ if (cr.commandLine.options['--bwsi'])
+ $('enable-screen-lock').disabled = true;
+ },
+
+ /**
+ * Updates the sync datatype checkboxes based on the selected sync option.
+ * @private
+ */
+ updateSyncSelection_: function() {
+ var idx = $('sync-select').selectedIndex;
+ var syncCheckboxes = $('sync-table').getElementsByTagName('input');
+ if (idx == 0) {
+ for (var i = 0; i < syncCheckboxes.length; i++) {
+ syncCheckboxes[i].disabled = false;
+ }
+ } else if (idx == 1) {
+ for (var i = 0; i < syncCheckboxes.length; i++) {
+ // Merely setting checked = true is not enough to trigger the pref
+ // being set; thus, we simulate the click.
+ if (!syncCheckboxes[i].checked)
+ syncCheckboxes[i].click();
+
+ syncCheckboxes[i].disabled = true;
+ }
}
},
showStopSyncingOverlay_: function(event) {
- AlertOverlay.show(
- localStrings.getString('stop_syncing_title'),
- localStrings.getString('stop_syncing_explanation'),
- localStrings.getString('stop_syncing_confirm_button_label'),
- undefined,
- function() { chrome.send('stopSyncing'); });
+ AlertOverlay.show(localStrings.getString('stop_syncing_title'),
+ localStrings.getString('stop_syncing_explanation'),
+ localStrings.getString('stop_syncing_confirm'),
+ localStrings.getString('cancel'),
+ function() { chrome.send('stopSyncing'); });
},
setElementVisible_: function(element, visible) {
@@ -154,18 +184,6 @@ cr.define('options', function() {
$('start-stop-sync').textContent = label;
},
- setCustomizeButtonVisible_: function(visible) {
- this.setElementVisible_($('customize-sync'), visible);
- },
-
- setCustomizeButtonEnabled_: function(enabled) {
- $('customize-sync').disabled = !enabled;
- },
-
- setCustomizeButtonLabel_: function(label) {
- $('customize-sync').textContent = label;
- },
-
setGtkThemeButtonEnabled_: function(enabled) {
if (!cr.isChromeOS && navigator.platform.match(/linux|BSD/i)) {
$('themes-GTK-button').disabled = !enabled;
@@ -179,6 +197,24 @@ cr.define('options', function() {
hideSyncSection_: function() {
this.setElementVisible_($('sync-section'), false);
},
+
+ /**
+ * Toggles the visibility of the data type checkboxes based on whether they
+ * are enabled on not.
+ * @param {Object} dict A mapping from data type to a boolean indicating
+ * whether it is enabled.
+ * @private
+ */
+ setRegisteredDataTypes_: function(dict) {
+ for (var type in dict) {
+ if (type.match(/Registered$/) && !dict[type]) {
+ node = $(type.replace(/([a-z]+)Registered$/i, '$1').toLowerCase()
+ + '-check');
+ if (node)
+ node.parentNode.style.display = 'none';
+ }
+ }
+ },
};
// Forward public APIs to private implementations.
@@ -194,12 +230,10 @@ cr.define('options', function() {
'setStartStopButtonVisible',
'setStartStopButtonEnabled',
'setStartStopButtonLabel',
- 'setCustomizeButtonVisible',
- 'setCustomizeButtonEnabled',
- 'setCustomizeButtonLabel',
'setGtkThemeButtonEnabled',
'setThemesResetButtonEnabled',
'hideSyncSection',
+ 'setRegisteredDataTypes',
].forEach(function(name) {
PersonalOptions[name] = function(value) {
PersonalOptions.getInstance()[name + '_'](value);
diff --git a/chrome/browser/resources/options/pref_ui.js b/chrome/browser/resources/options/pref_ui.js
index c59cf03..6372776 100644
--- a/chrome/browser/resources/options/pref_ui.js
+++ b/chrome/browser/resources/options/pref_ui.js
@@ -7,6 +7,7 @@ cr.define('options', function() {
var Preferences = options.Preferences;
/////////////////////////////////////////////////////////////////////////////
// PrefCheckbox class:
+ // TODO(jhawkins): Refactor all this copy-pasted code!
// Define a constructor that uses an input element as its underlying element.
var PrefCheckbox = cr.ui.define('input');
@@ -22,42 +23,47 @@ cr.define('options', function() {
this.type = 'checkbox';
var self = this;
+ self.initializeValueType(self.getAttribute('value-type'));
+
// Listen to pref changes.
- Preferences.getInstance().addEventListener(this.pref,
+ Preferences.getInstance().addEventListener(
+ this.pref,
function(event) {
var value = event.value && event.value['value'] != undefined ?
event.value['value'] : event.value;
- self.checked = Boolean(value);
+
+ // Invert pref value if inverted_pref == true.
+ if (self.inverted_pref)
+ self.checked = !Boolean(value);
+ else
+ self.checked = Boolean(value);
+
self.managed = event.value && event.value['managed'] != undefined ?
event.value['managed'] : false;
- self.disabled = self.managed;
- // Honor manually_disabled property, so options pages can
- // disable preferences manually when needed.
- if (self.manually_disabled) {
+
+ // Managed UI elements can only be disabled as a result of being
+ // managed. They cannot be enabled as a result of a pref being
+ // unmanaged.
+ if (self.managed)
self.disabled = true;
- }
});
// Listen to user events.
- this.addEventListener('click',
+ this.addEventListener(
+ 'click',
function(e) {
+ var value = self.inverted_pref ? !self.checked : self.checked;
switch(self.valueType) {
case 'number':
Preferences.setIntegerPref(self.pref,
- Number(self.checked), self.metric);
+ Number(value), self.metric);
break;
case 'boolean':
Preferences.setBooleanPref(self.pref,
- self.checked, self.metric);
+ value, self.metric);
break;
}
});
-
- // Initialize options.
- this.ownerDocument.addEventListener('DOMContentLoaded',
- function() {
- self.initializeValueType(self.getAttribute('value-type'));
- });
},
/**
@@ -81,6 +87,12 @@ cr.define('options', function() {
*/
cr.defineProperty(PrefCheckbox, 'metric', cr.PropertyKind.ATTR);
+ /**
+ * Whether to use inverted pref value.
+ * @type {boolean}
+ */
+ cr.defineProperty(PrefCheckbox, 'inverted_pref', cr.PropertyKind.BOOL_ATTR);
+
/////////////////////////////////////////////////////////////////////////////
// PrefRadio class:
@@ -106,12 +118,12 @@ cr.define('options', function() {
self.managed = event.value && event.value['managed'] != undefined ?
event.value['managed'] : false;
self.checked = String(value) == self.value;
- self.disabled = self.managed;
- // Honor manually_disabled property, so options pages can
- // disable preferences manually when needed.
- if (self.manually_disabled) {
+
+ // Managed UI elements can only be disabled as a result of being
+ // managed. They cannot be enabled as a result of a pref being
+ // unmanaged.
+ if (self.managed)
self.disabled = true;
- }
});
// Listen to user events.
@@ -170,7 +182,12 @@ cr.define('options', function() {
event.value['value'] : event.value;
self.managed = event.value && event.value['managed'] != undefined ?
event.value['managed'] : false;
- self.disabled = self.managed;
+
+ // Managed UI elements can only be disabled as a result of being
+ // managed. They cannot be enabled as a result of a pref being
+ // unmanaged.
+ if (self.managed)
+ self.disabled = true;
});
// Listen to user events.
@@ -275,27 +292,45 @@ cr.define('options', function() {
*/
decorate: function() {
var self = this;
+
+ var values = self.getAttribute('data-values');
+ if (values) {
+ self.initializeValues(templateData[values]);
+ }
+
// Listen to pref changes.
Preferences.getInstance().addEventListener(this.pref,
function(event) {
var value = event.value && event.value['value'] != undefined ?
event.value['value'] : event.value;
+
+ // Make sure |value| is a string, because the value is stored as a
+ // string in the HTMLOptionElement.
+ value = value.toString();
+
self.managed = event.value && event.value['managed'] != undefined ?
event.value['managed'] : false;
- self.disabled = self.managed;
- // Honor manually_disabled property, so options pages can
- // disable preferences manually when needed.
- if (self.manually_disabled) {
+
+ // Managed UI elements can only be disabled as a result of being
+ // managed. They cannot be enabled as a result of a pref being
+ // unmanaged.
+ if (self.managed)
self.disabled = true;
- }
+
+ var found = false;
for (var i = 0; i < self.options.length; i++) {
if (self.options[i].value == value) {
self.selectedIndex = i;
- return;
+ found = true;
}
}
+
// Item not found, select first item.
- self.selectedIndex = 0;
+ if (!found)
+ self.selectedIndex = 0;
+
+ if (self.onchange != undefined)
+ self.onchange(event);
});
// Listen to user events.
@@ -307,8 +342,9 @@ cr.define('options', function() {
self.options[self.selectedIndex].value, self.metric);
break;
case 'boolean':
- Preferences.setBooleanValue(self.pref,
- self.options[self.selectedIndex].value, self.metric);
+ var option = self.options[self.selectedIndex];
+ var value = (option.value == 'true') ? true : false;
+ Preferences.setBooleanPref(self.pref, value, self.metric);
break;
case 'string':
Preferences.setStringPref(self.pref,
@@ -316,22 +352,14 @@ cr.define('options', function() {
break;
}
});
-
- // Initialize options.
- this.ownerDocument.addEventListener('DOMContentLoaded',
- function() {
- var values = self.getAttribute('data-values');
- if (values) {
- self.initializeValues(templateData[values]);
- }
- });
},
/**
* Sets up options in select element.
* @param {Array} options List of option and their display text.
- * Each element in the array is an array of length 2 which contains options
- * value in the first element and display text in the second element.
+ * Each element in the array is an array of length 2 which contains
+ * options value in the first element and display text in the second
+ * element. May be undefined.
*
* TODO(zelidrag): move this to that i18n template classes.
*/
@@ -339,6 +367,7 @@ cr.define('options', function() {
options.forEach(function (values) {
if (this.dataType == undefined)
this.dataType = typeof values[0];
+
this.appendChild(new Option(values[1], values[0]));
}, this);
}
@@ -379,7 +408,12 @@ cr.define('options', function() {
event.value['value'] : event.value;
self.managed = event.value && event.value['managed'] != undefined ?
event.value['managed'] : false;
- self.disabled = self.managed;
+
+ // Managed UI elements can only be disabled as a result of being
+ // managed. They cannot be enabled as a result of a pref being
+ // unmanaged.
+ if (self.managed)
+ self.disabled = true;
});
// Listen to user events.
diff --git a/chrome/browser/resources/options/search_engine_manager.css b/chrome/browser/resources/options/search_engine_manager.css
index 4fa9268..1eac1c4 100644
--- a/chrome/browser/resources/options/search_engine_manager.css
+++ b/chrome/browser/resources/options/search_engine_manager.css
@@ -1,17 +1,46 @@
+#searchEngineList {
+ -webkit-border-radius: 2px;
+ border-bottom: 1px solid #d9d9d9;
+ height: auto;
+}
+
+#searchEngineManagerPage .left-side-table {
+ margin-top: 12px;
+}
+
+#searchEngineList .heading {
+ -webkit-border-radius: 2px;
+ color: black;
+ border-bottom: 1px solid #d9d9d9;
+}
+
+#searchEngineList .heading:not(:nth-child(2)) {
+ border-top: 1px solid #d9d9d9;
+}
+
+#searchEngineList .heading .name {
+ font-weight: bold;
+}
+
+#searchEngineList > div:not(.heading) {
+ border-left: 1px solid #d9d9d9;
+ border-right: 1px solid #d9d9d9;
+}
+
#searchEngineList > div, #searchEngineHeading {
display: -webkit-box;
}
-#searchEngineManagerPage .name {
- -webkit-box-sizing: border-box;
+#searchEngineList .name {
+ box-sizing: border-box;
width: 50%;
}
-#searchEngineManagerPage .keyword {
+#searchEngineList .keyword {
-webkit-box-flex: 1;
}
-#searchEngineList .keyword {
+#searchEngineList > div:not(.heading) .keyword {
color: #666666;
}
@@ -23,10 +52,3 @@
overflow: hidden;
text-overflow: ellipsis;
}
-
-#searchEngineHeading {
- font-weight: bold;
- padding: 4px;
- border-bottom: solid 1px black;
- border-top: 1px solid black;
-}
diff --git a/chrome/browser/resources/options/search_engine_manager.html b/chrome/browser/resources/options/search_engine_manager.html
index d058b6f..58d1ab1 100644
--- a/chrome/browser/resources/options/search_engine_manager.html
+++ b/chrome/browser/resources/options/search_engine_manager.html
@@ -2,18 +2,11 @@
<h1 i18n-content="searchEngineManagerPage"></h1>
<div class="left-side-table">
<div>
- <div id="searchEngineHeading">
- <div class="name" i18n-content="searchEngineTableNameHeader"></div>
- <div class="keyword"
- i18n-content="searchEngineTableKeywordHeader"></div>
- </div>
<list id="searchEngineList"></list>
</div>
<div>
<div><button id="addSearchEngineButton"
i18n-content="addSearchEngineButton"></div>
- <div><button id="removeSearchEngineButton" disabled
- i18n-content="removeSearchEngineButton"></div>
<div><button id="editSearchEngineButton" disabled
i18n-content="editSearchEngineButton"></div>
<div><button id="makeDefaultSearchEngineButton" disabled
diff --git a/chrome/browser/resources/options/search_engine_manager.js b/chrome/browser/resources/options/search_engine_manager.js
index d227905..0443ed0 100644
--- a/chrome/browser/resources/options/search_engine_manager.js
+++ b/chrome/browser/resources/options/search_engine_manager.js
@@ -31,6 +31,7 @@ cr.define('options', function() {
options.search_engines.SearchEngineList.decorate(this.list_);
var selectionModel = new ListSingleSelectionModel
this.list_.selectionModel = selectionModel;
+ this.list_.autoExpands = true;
selectionModel.addEventListener('change',
this.selectionChanged_.bind(this));
@@ -40,9 +41,6 @@ cr.define('options', function() {
chrome.send('editSearchEngine', ["-1"]);
OptionsPage.showOverlay('editSearchEngineOverlay');
};
- $('removeSearchEngineButton').onclick = function(event) {
- chrome.send('removeSearchEngine', [self.selectedModelIndex_]);
- };
$('editSearchEngineButton').onclick = function(event) {
chrome.send('editSearchEngine', [self.selectedModelIndex_]);
OptionsPage.showOverlay('editSearchEngineOverlay');
@@ -56,12 +54,6 @@ cr.define('options', function() {
// TODO(stuartmorgan): Remove this once the strings are updated.
$('addSearchEngineButton').textContent =
localStrings.getStringWithoutAccelerator('addSearchEngineButton');
- $('removeSearchEngineButton').textContent =
- localStrings.getStringWithoutAccelerator('removeSearchEngineButton');
-
- this.addEventListener('visibleChange', function(event) {
- $('searchEngineList').redraw();
- });
},
/**
@@ -92,8 +84,6 @@ cr.define('options', function() {
var engine = selectedIndex != -1 ?
this.list_.dataModel.item(selectedIndex) : null;
- $('removeSearchEngineButton').disabled =
- !(engine && engine['canBeRemoved']);
$('editSearchEngineButton').disabled = engine == null;
$('makeDefaultSearchEngineButton').disabled =
!(engine && engine['canBeDefault']);
diff --git a/chrome/browser/resources/options/search_engine_manager_engine_list.js b/chrome/browser/resources/options/search_engine_manager_engine_list.js
index 0c634b1..1e7d93e 100644
--- a/chrome/browser/resources/options/search_engine_manager_engine_list.js
+++ b/chrome/browser/resources/options/search_engine_manager_engine_list.js
@@ -3,10 +3,10 @@
// found in the LICENSE file.
cr.define('options.search_engines', function() {
- const List = cr.ui.List;
+ const DeletableItem = options.DeletableItem;
+ const DeletableItemList = options.DeletableItemList;
const ListInlineHeaderSelectionController =
options.ListInlineHeaderSelectionController;
- const ListItem = cr.ui.ListItem;
/**
* Creates a new search engine list item.
@@ -31,43 +31,46 @@ cr.define('options.search_engines', function() {
};
SearchEngineListItem.prototype = {
- __proto__: ListItem.prototype,
+ __proto__: DeletableItem.prototype,
/** @inheritDoc */
decorate: function() {
- ListItem.prototype.decorate.call(this);
+ DeletableItem.prototype.decorate.call(this);
var engine = this.searchEngine_;
- if (engine['heading']) {
- var titleEl = this.ownerDocument.createElement('div');
- titleEl.textContent = engine['heading'];
+
+ if (engine['heading'])
this.classList.add('heading');
- this.appendChild(titleEl);
+ else if (engine['default'])
+ this.classList.add('default');
+
+ this.deletable = engine['canBeRemoved'];
+
+ var nameEl = this.ownerDocument.createElement('div');
+ nameEl.className = 'name';
+ if (engine['heading']) {
+ nameEl.textContent = engine['heading'];
} else {
- var nameEl = this.ownerDocument.createElement('div');
- nameEl.className = 'name';
- nameEl.classList.add('favicon-cell');
nameEl.textContent = engine['name'];
+ nameEl.classList.add('favicon-cell');
nameEl.style.backgroundImage = url('chrome://favicon/iconurl/' +
engine['iconURL']);
-
- var keywordEl = this.ownerDocument.createElement('div');
- keywordEl.className = 'keyword';
- keywordEl.textContent = engine['keyword'];
-
- this.appendChild(nameEl);
- this.appendChild(keywordEl);
-
- if (engine['default'])
- this.classList.add('default');
}
+ this.contentElement.appendChild(nameEl);
+
+ var keywordEl = this.ownerDocument.createElement('div');
+ keywordEl.className = 'keyword';
+ keywordEl.textContent = engine['heading'] ?
+ localStrings.getString('searchEngineTableKeywordHeader') :
+ engine['keyword'];
+ this.contentElement.appendChild(keywordEl);
},
};
var SearchEngineList = cr.ui.define('list');
SearchEngineList.prototype = {
- __proto__: List.prototype,
+ __proto__: DeletableItemList.prototype,
/** @inheritDoc */
createItem: function(searchEngine) {
@@ -79,13 +82,19 @@ cr.define('options.search_engines', function() {
return new ListInlineHeaderSelectionController(sm, this);
},
+ /** @inheritDoc */
+ deleteItemAtIndex: function(index) {
+ var modelIndex = this.dataModel.item(index)['modelIndex']
+ chrome.send('removeSearchEngine', [String(modelIndex)]);
+ },
+
/**
* Returns true if the given item is selectable.
* @param {number} index The index to check.
*/
canSelectIndex: function(index) {
return !this.dataModel.item(index).hasOwnProperty('heading');
- }
+ },
};
// Export
diff --git a/chrome/browser/resources/options/search_page.css b/chrome/browser/resources/options/search_page.css
new file mode 100644
index 0000000..e5e44d6
--- /dev/null
+++ b/chrome/browser/resources/options/search_page.css
@@ -0,0 +1,7 @@
+.search-hidden {
+ display: none;
+}
+
+.search-highlighted {
+ background-color: #fff29f;
+}
diff --git a/chrome/browser/resources/options/search_page.html b/chrome/browser/resources/options/search_page.html
index 413ce56..9c12cf2 100644
--- a/chrome/browser/resources/options/search_page.html
+++ b/chrome/browser/resources/options/search_page.html
@@ -3,7 +3,7 @@
<div id="searchPageInfo">
<p i18n-content="searchPageInfo"></p>
</div>
- <div id="searchPageNoMatches" class="hidden">
+ <div id="searchPageNoMatches">
<p i18n-content="searchPageNoMatches"></p>
<p><span i18n-content="searchPageHelpLabel"></span>
<a target=_blank" i18n-content="searchPageHelpTitle"
diff --git a/chrome/browser/resources/options/search_page.js b/chrome/browser/resources/options/search_page.js
index 1951f8f..965ee73 100644
--- a/chrome/browser/resources/options/search_page.js
+++ b/chrome/browser/resources/options/search_page.js
@@ -7,9 +7,11 @@ cr.define('options', function() {
/**
* Encapsulated handling of the search page.
+ * @constructor
*/
function SearchPage() {
OptionsPage.call(this, 'search', templateData.searchPage, 'searchPage');
+ this.searchActive = false;
}
cr.addSingletonGetter(SearchPage);
@@ -18,37 +20,325 @@ cr.define('options', function() {
// Inherit SearchPage from OptionsPage.
__proto__: OptionsPage.prototype,
- // Initialize SearchPage.
+ /**
+ * Initialize the page.
+ */
initializePage: function() {
// Call base class implementation to start preference initialization.
OptionsPage.prototype.initializePage.call(this);
+ var self = this;
+
// Create a search field element.
var searchField = document.createElement('input');
- searchField.id = 'searchField';
+ searchField.id = 'search-field';
searchField.type = 'search';
searchField.setAttribute('autosave', 'org.chromium.options.search');
searchField.setAttribute('results', '10');
+ searchField.setAttribute('incremental', 'true');
// Replace the contents of the navigation tab with the search field.
- this.tab.textContent = '';
- this.tab.appendChild(searchField);
+ self.tab.textContent = '';
+ self.tab.appendChild(searchField);
+
+ // Handle search events. (No need to throttle, WebKit's search field
+ // will do that automatically.)
+ searchField.onsearch = function(e) {
+ self.setSearchText_(this.value);
+ };
},
- };
- SearchPage.updateForEmptySearch = function() {
- $('searchPageInfo').classList.remove('hidden');
- $('searchPageNoMatches').classList.add('hidden');
- };
+ /**
+ * @inheritDoc
+ */
+ get sticky() {
+ return true;
+ },
- SearchPage.updateForNoSearchResults = function(message) {
- $('searchPageInfo').classList.add('hidden');
- $('searchPageNoMatches').classList.remove('hidden');
- };
+ /**
+ * Called after this page has shown.
+ */
+ didShowPage: function() {
+ // This method is called by the Options page after all pages have
+ // had their visibilty attribute set. At this point we can perform the
+ // search specific DOM manipulation.
+ this.setSearchActive_(true);
+ },
+
+ /**
+ * Called before this page will be hidden.
+ */
+ willHidePage: function() {
+ // This method is called by the Options page before all pages have
+ // their visibilty attribute set. Before that happens, we need to
+ // undo the search specific DOM manipulation that was performed in
+ // didShowPage.
+ this.setSearchActive_(false);
+ },
+
+ /**
+ * Update the UI to reflect whether we are in a search state.
+ * @param {boolean} active True if we are on the search page.
+ * @private
+ */
+ setSearchActive_: function(active) {
+ // It's fine to exit if search wasn't active and we're not going to
+ // activate it now.
+ if (!this.searchActive_ && !active)
+ return;
+
+ if (this.searchActive_ != active) {
+ this.searchActive_ = active;
+ if (active) {
+ // Reset the search criteria, effectively hiding all the sections.
+ this.setSearchText_('');
+ } else {
+ // Just wipe out any active search text since it's no longer relevant.
+ $('search-field').value = '';
+ }
+ }
+
+ var pagesToSearch = this.getSearchablePages_();
+ for (var key in pagesToSearch) {
+ var page = pagesToSearch[key];
+
+ if (!active)
+ page.visible = false;
+
+ // Update the visible state of all top-level elements that are not
+ // sections (ie titles, button strips). We do this before changing
+ // the page visibility to avoid excessive re-draw.
+ var length = page.pageDiv.childNodes.length;
+ var childDiv;
+ for (var i = 0; i < length; i++) {
+ childDiv = page.pageDiv.childNodes[i];
+ if (childDiv.nodeType == document.ELEMENT_NODE) {
+ if (active) {
+ if (childDiv.nodeName.toLowerCase() != 'section')
+ childDiv.classList.add('search-hidden');
+ } else {
+ childDiv.classList.remove('search-hidden');
+ }
+ }
+ }
+
+ if (active) {
+ // When search is active, remove the 'hidden' tag. This tag may have
+ // been added by the OptionsPage.
+ page.pageDiv.classList.remove('hidden');
+ }
+ }
+
+ // After hiding all page content, remove any highlighted matches.
+ if (!active)
+ this.unhighlightMatches_();
+ },
+
+ /**
+ * Set the current search criteria.
+ * @param {string} text Search text.
+ * @private
+ */
+ setSearchText_: function(text) {
+ var foundMatches = false;
+
+ // Remove any highlighted matches.
+ this.unhighlightMatches_();
+
+ // Generate search text by applying lowercase and escaping any characters
+ // that would be problematic for regular expressions.
+ var searchText =
+ text.toLowerCase().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
+
+ // Generate a regular expression and replace string for hilighting
+ // search terms.
+ var regEx = new RegExp('(\\b' + searchText + ')', 'ig');
+ var replaceString = '<span class="search-highlighted">$1</span>';
+
+ // Initialize all sections. If the search string matches a title page,
+ // show sections for that page.
+ var page, pageMatch, childDiv;
+ var pagesToSearch = this.getSearchablePages_();
+ for (var key in pagesToSearch) {
+ page = pagesToSearch[key];
+ pageMatch = false;
+ if (searchText.length) {
+ pageMatch = this.performReplace_(regEx, replaceString, page.tab);
+ }
+ if (pageMatch)
+ foundMatches = true;
+ for (var i = 0; i < page.pageDiv.childNodes.length; i++) {
+ childDiv = page.pageDiv.childNodes[i];
+ if (childDiv.nodeType == document.ELEMENT_NODE &&
+ childDiv.nodeName == 'SECTION') {
+ if (pageMatch) {
+ childDiv.classList.remove('search-hidden');
+ } else {
+ childDiv.classList.add('search-hidden');
+ }
+ }
+ }
+ }
+
+ if (searchText.length) {
+ // Search all sub-pages, generating an array of top-level sections that
+ // we need to make visible.
+ var subPagesToSearch = this.getSearchableSubPages_();
+ var control, node;
+ for (var key in subPagesToSearch) {
+ page = subPagesToSearch[key];
+ if (this.performReplace_(regEx, replaceString, page.pageDiv)) {
+ section = page.associatedSection;
+ if (section)
+ section.classList.remove('search-hidden');
+ controls = page.associatedControls;
+ if (controls) {
+ // TODO(csilv): highlight each control.
+ }
+
+ foundMatches = true;
+ }
+ }
+
+ // Search all top-level sections for anchored string matches.
+ for (var key in pagesToSearch) {
+ page = pagesToSearch[key];
+ for (var i = 0; i < page.pageDiv.childNodes.length; i++) {
+ childDiv = page.pageDiv.childNodes[i];
+ if (childDiv.nodeType == document.ELEMENT_NODE &&
+ childDiv.nodeName == 'SECTION' &&
+ this.performReplace_(regEx, replaceString, childDiv)) {
+ childDiv.classList.remove('search-hidden');
+ foundMatches = true;
+ }
+ }
+ }
+ }
+
+ // Configure elements on the search results page based on search results.
+ if (searchText.length == 0) {
+ $('searchPageInfo').classList.remove('search-hidden');
+ $('searchPageNoMatches').classList.add('search-hidden');
+ } else if (foundMatches) {
+ $('searchPageInfo').classList.add('search-hidden');
+ $('searchPageNoMatches').classList.add('search-hidden');
+ } else {
+ $('searchPageInfo').classList.add('search-hidden');
+ $('searchPageNoMatches').classList.remove('search-hidden');
+ }
+ },
+
+ /**
+ * Performs a string replacement based on a regex and replace string.
+ * @param {RegEx} regex A regular expression for finding search matches.
+ * @param {String} replace A string to apply the replace operation.
+ * @param {Element} element An HTML container element.
+ * @returns {Boolean} true if the element was changed.
+ * @private
+ */
+ performReplace_: function(regex, replace, element) {
+ var found = false;
+ var div, child, tmp;
+
+ // Walk the tree, searching each TEXT node.
+ var walker = document.createTreeWalker(element,
+ NodeFilter.SHOW_TEXT,
+ null,
+ false);
+ var node = walker.nextNode();
+ while (node) {
+ // Perform a search and replace on the text node value.
+ var newValue = node.nodeValue.replace(regex, replace);
+ if (newValue != node.nodeValue) {
+ // The text node has changed so that means we found at least one
+ // match.
+ found = true;
+
+ // Create a temporary div element and set the innerHTML to the new
+ // value.
+ div = document.createElement('div');
+ div.innerHTML = newValue;
+
+ // Insert all the child nodes of the temporary div element into the
+ // document, before the original node.
+ child = div.firstChild;
+ while (child = div.firstChild) {
+ node.parentNode.insertBefore(child, node);
+ };
+
+ // Delete the old text node and advance the walker to the next
+ // node.
+ tmp = node;
+ node = walker.nextNode();
+ tmp.parentNode.removeChild(tmp);
+ } else {
+ node = walker.nextNode();
+ }
+ }
+
+ return found;
+ },
+
+ /**
+ * Removes all search highlight tags from the document.
+ * @private
+ */
+ unhighlightMatches_: function() {
+ // Find all search highlight elements.
+ var elements = document.querySelectorAll('.search-highlighted');
+
+ // For each element, remove the highlighting.
+ var node, parent, i, length = elements.length;
+ for (i = 0; i < length; i++) {
+ node = elements[i];
+ parent = node.parentNode;
+
+ // Replace the highlight element with the first child (the text node).
+ parent.replaceChild(node.firstChild, node);
+
+ // Normalize the parent so that multiple text nodes will be combined.
+ parent.normalize();
+ }
+ },
+
+ /**
+ * Builds a list of top-level pages to search. Omits the search page and
+ * all sub-pages.
+ * @returns {Array} An array of pages to search.
+ * @private
+ */
+ getSearchablePages_: function() {
+ var name, page, pages = [];
+ for (name in OptionsPage.registeredPages) {
+ if (name != this.name) {
+ page = OptionsPage.registeredPages[name];
+ if (!page.parentPage)
+ pages.push(page);
+ }
+ }
+ return pages;
+ },
- SearchPage.updateForSuccessfulSearch = function(enable) {
- $('searchPageInfo').classList.add('hidden');
- $('searchPageNoMatches').classList.add('hidden');
+ /**
+ * Builds a list of sub-pages (and overlay pages) to search. Ignore pages
+ * that have no associated controls.
+ * @returns {Array} An array of pages to search.
+ * @private
+ */
+ getSearchableSubPages_: function() {
+ var name, pageInfo, page, pages = [];
+ for (name in OptionsPage.registeredPages) {
+ page = OptionsPage.registeredPages[name];
+ if (page.parentPage && page.associatedSection)
+ pages.push(page);
+ }
+ for (name in OptionsPage.registeredOverlayPages) {
+ page = OptionsPage.registeredOverlayPages[name];
+ if (page.associatedSection && page.pageDiv != undefined)
+ pages.push(page);
+ }
+ return pages;
+ }
};
// Export
diff --git a/chrome/browser/resources/options/show_password.png b/chrome/browser/resources/options/show_password.png
new file mode 100644
index 0000000..901f8e4
--- /dev/null
+++ b/chrome/browser/resources/options/show_password.png
Binary files differ
diff --git a/chrome/browser/resources/options/startup_page_manager.html b/chrome/browser/resources/options/startup_page_manager.html
new file mode 100644
index 0000000..77ad1f1
--- /dev/null
+++ b/chrome/browser/resources/options/startup_page_manager.html
@@ -0,0 +1,5 @@
+<div id="startupPageManagerPage" class="page hidden">
+ <h1 i18n-content="startupPageManagerPage"></h1>
+ <list id="startupPagesFullList" class="settings-list"></list>
+ <button id="startupAddButton" i18n-content="startupAddButton"></button>
+</div>
diff --git a/chrome/browser/resources/options/startup_page_manager.js b/chrome/browser/resources/options/startup_page_manager.js
new file mode 100644
index 0000000..56771f8
--- /dev/null
+++ b/chrome/browser/resources/options/startup_page_manager.js
@@ -0,0 +1,80 @@
+// 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.
+
+cr.define('options', function() {
+ const OptionsPage = options.OptionsPage;
+ const ArrayDataModel = cr.ui.ArrayDataModel;
+ const ListSelectionModel = cr.ui.ListSelectionModel;
+
+ /**
+ * Encapsulated handling of startup page management page.
+ * @constructor
+ */
+ function StartupPageManager() {
+ this.activeNavTab = null;
+ OptionsPage.call(this, 'startupPages',
+ templateData.StartupPageManagerPage,
+ 'startupPageManagerPage');
+ }
+
+ cr.addSingletonGetter(StartupPageManager);
+
+ StartupPageManager.prototype = {
+ __proto__: OptionsPage.prototype,
+ list_: null,
+
+ initializePage: function() {
+ OptionsPage.prototype.initializePage.call(this);
+
+ var list = $('startupPagesFullList');
+ options.browser_options.StartupPageList.decorate(list);
+ list.autoExpands = true;
+ list.selectionModel = new ListSelectionModel;
+
+ // Wire up controls.
+ $('startupAddButton').onclick = function(event) {
+ OptionsPage.showOverlay('addStartupPageOverlay');
+ };
+
+ // Remove Windows-style accelerators from button labels.
+ // TODO(stuartmorgan): Remove this once the strings are updated.
+ $('startupAddButton').textContent =
+ localStrings.getStringWithoutAccelerator('startupAddButton');
+ },
+
+ /**
+ * Updates the startup pages list with the given entries.
+ * @param {Array} pages List of startup pages.
+ * @private
+ */
+ updateStartupPages_: function(pages) {
+ $('startupPagesFullList').dataModel = new ArrayDataModel(pages);
+ },
+
+ /**
+ * Adds the given startup page at the current selection point.
+ * @private
+ */
+ addStartupPage_: function(url) {
+ var firstSelection =
+ $('startupPagesFullList').selectionModel.selectedIndex;
+ chrome.send('addStartupPage', [url, String(firstSelection)]);
+ },
+ };
+
+ StartupPageManager.updateStartupPages = function(pages) {
+ StartupPageManager.getInstance().updateStartupPages_(pages);
+ };
+
+ StartupPageManager.addStartupPage = function(url) {
+ StartupPageManager.getInstance().addStartupPage_(url);
+ };
+
+ // Export
+ return {
+ StartupPageManager: StartupPageManager
+ };
+
+});
+
diff --git a/chrome/browser/resources/options/subpages_tab_controls.css b/chrome/browser/resources/options/subpages_tab_controls.css
index cfefdcc..c9eb94d 100644
--- a/chrome/browser/resources/options/subpages_tab_controls.css
+++ b/chrome/browser/resources/options/subpages_tab_controls.css
@@ -14,8 +14,8 @@ found in the LICENSE file.
background: white;
border: 1px solid #A0A0A0; /* light gray */
border-bottom: 2px solid white;
- -webkit-border-top-left-radius: 3px;
- -webkit-border-top-right-radius: 3px;
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
}
/* To avoid tabs changing size when they are clicked and their labels become
diff --git a/chrome/browser/resources/options/sync_options.html b/chrome/browser/resources/options/sync_options.html
deleted file mode 100644
index d2b5aea..0000000
--- a/chrome/browser/resources/options/sync_options.html
+++ /dev/null
@@ -1,72 +0,0 @@
-<div class="page hidden" id="syncPage">
- <h1 i18n-content="syncPage"></h1>
- <section>
- <h3 i18n-content="sync_title"></h3>
- <table class="option-control-table">
- <tr>
- <td class="option-name">
- <label class="checkbox">
- <input id="settings-check" pref="sync.preferences" type="checkbox">
- <span i18n-content="syncsettings"></span>
- </label>
- </td>
- <td class="option-name">
- <label class="checkbox">
- <input id="bookmarks-check" pref="sync.bookmarks" type="checkbox">
- <span i18n-content="syncbookmarks"></span>
- </label>
- </td>
- </tr>
- <tr>
- <td class="option-name">
- <label class="checkbox">
- <input id="extensions-check" pref="sync.extensions" type="checkbox">
- <span i18n-content="syncextensions"></span>
- </label>
- </td>
- <td class="option-name">
- <label class="checkbox">
- <input id="autofill-check" pref="sync.autofill" type="checkbox">
- <span i18n-content="syncautofill"></span>
- </label>
- </td>
- </tr>
- <tr>
- <td class="option-name">
- <label class="checkbox">
- <input id="themes-check" pref="sync.themes" type="checkbox">
- <span i18n-content="syncthemes"></span>
- </label>
- </td>
- <td class="option-name">
- <label class="checkbox">
- <input id="apps-check" pref="sync.apps" type="checkbox">
- <span i18n-content="syncapps"></span>
- <label>
- </td>
- </tr>
- <tr>
- <td class="option-name">
- <label class="checkbox">
- <input id="typedurls-check" pref="sync.typed_urls" type="checkbox">
- <span i18n-content="synctypedurls"></span>
- </label>
- </td>
- <td class="option-name">
- <label class="checkbox">
- <input id="passwords-check" pref="sync.passwords" type="checkbox">
- <span i18n-content="syncpasswords"></span>
- </label>
- </td>
- </tr>
- <tr>
- <td class="option-name">
- <label class="checkbox">
- <input id="sessions-check" pref="sync.sessions" type="checkbox">
- <span i18n-content="syncsessions"></span>
- </label>
- </td>
- </tr>
- </table>
- </section>
-</div>
diff --git a/chrome/browser/resources/options/sync_options.js b/chrome/browser/resources/options/sync_options.js
deleted file mode 100644
index 59c3781..0000000
--- a/chrome/browser/resources/options/sync_options.js
+++ /dev/null
@@ -1,64 +0,0 @@
-// 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.
-
-cr.define('options', function() {
- const OptionsPage = options.OptionsPage;
-
- /**
- * Encapsulated handling of the sync options page.
- * @constructor
- */
- function SyncOptions() {
- OptionsPage.call(this, 'sync', templateData.syncPage, 'syncPage');
- }
-
- cr.addSingletonGetter(SyncOptions);
-
- SyncOptions.prototype = {
- __proto__: OptionsPage.prototype,
-
- initializePage: function() {
- OptionsPage.prototype.initializePage.call(this);
- this.registerEventHandlers();
- },
-
- /**
- * Registers event handler on all the data type checkboxes so that the set
- * of data types to sync get updated as the user checks/unchecks them.
- */
- registerEventHandlers: function() {
- checks = $('syncPage').getElementsByTagName('input');
- for (var i = 0; i < checks.length; i++) {
- checks[i].onclick = function(event) {
- chrome.send('updatePreferredDataTypes');
- };
- }
- }
- };
-
- /**
- * Toggles the visibility of the data type checkboxes based on whether they
- * are enabled on not.
- * @param {Object} dict A mapping from data type to a boolean indicating
- * whether it is enabled.
- */
- SyncOptions.setRegisteredDataTypes = function(dict) {
- for (var type in dict) {
- if (type.match(/Registered$/) && !dict[type]) {
- node = $(type.replace(/([a-z]+)Registered$/i, '$1').toLowerCase()
- + '-check');
- if (node) {
- node.parentNode.style.display = 'none';
- }
- }
- }
- };
-
- // Export
- return {
- SyncOptions: SyncOptions
- };
-
-});
-
diff --git a/chrome/browser/resources/options/warning.png b/chrome/browser/resources/options/warning.png
new file mode 100644
index 0000000..46d78c5
--- /dev/null
+++ b/chrome/browser/resources/options/warning.png
Binary files differ
diff --git a/chrome/browser/resources/options/zippy.css b/chrome/browser/resources/options/zippy.css
deleted file mode 100644
index 3d1d716..0000000
--- a/chrome/browser/resources/options/zippy.css
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
-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.
-*/
-
-.zippy {
- margin-top: 1ex;
- margin-bottom: 1ex;
-}
-
-.zippy > .zippy-header {
- font-weight: bold;
- cursor: pointer;
- background-color: #DFDFDF; /* medium light gray */
- background-image: url("../shared/images/minus.png");
- background-position: 3px 3px;
- background-repeat: no-repeat;
- -webkit-padding-start: 18px;
- min-height: 18px;
-}
-
-.zippy.collapsed > .zippy-header {
- background-image: url("../shared/images/plus.png");
-}
-
-html[dir=rtl] .zippy > .zippy-header {
- background-position: 3px right;
-}
-
-.zippy .zippy-content {
- background: #EFEFEF; /* extra light gray */
- padding-left: 3px;
- padding-right: 3px;
- overflow: hidden;
-}
-
-.zippy.animated .zippy-content {
- -webkit-transition: all .15s ease-in-out;
-}
-
-.zippy.collapsed .zippy-content {
- opacity: 0;
- height: 0 !important; /* must override height in DOM style parameter */
-}
-
-.zippy.measure .zippy-content {
- visibility: hidden;
- position: absolute;
-}
-
-.zippy.remeasure .zippy-content {
- visibility: hidden;
-}
diff --git a/chrome/browser/resources/options/zippy.js b/chrome/browser/resources/options/zippy.js
deleted file mode 100644
index 1259391..0000000
--- a/chrome/browser/resources/options/zippy.js
+++ /dev/null
@@ -1,202 +0,0 @@
-// 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.
-
-// A zippy is an area with a clickable header that controls whether the rest of
-// the area is displayed or not. In most zippies the header contains a +/- sign
-// to indicate the current state, and also to suggest that the content can be
-// expanded (when collapsed) or collapsed (when expanded).
-
-// This implementation smoothly animates the content of the zippy when it is
-// expanded and collapsed, using the -webkit-transition style attribute.
-
-cr.define('options', function() {
-
- //////////////////////////////////////////////////////////////////////////////
- // Zippy class:
-
- var Zippy = cr.ui.define('div');
-
- Zippy.prototype = {
- __proto__: HTMLDivElement.prototype,
-
- /**
- * Initialization function for the cr.ui framework.
- */
- decorate: function() {
- this.classList.add('collapsed');
- this.classList.add('measure');
- var self = this;
- this.addEventListener('click', function(e) {
- var target = e.target;
- while (target && !target.classList.contains('zippy')) {
- if (target.classList.contains('zippy-header')) {
- self.toggle();
- break;
- }
- target = target.parentNode;
- }
- });
- },
-
- /**
- * Toggle the expanded state of this zippy.
- */
- toggle: function() {
- this.expanded = !this.expanded;
- },
-
- /**
- * Do an initial measure of this zippy.
- *
- * This function is called just after making the zippy's contents visible
- * for the first time, and sets the calculated size into the zippy's style
- * attribute. This is needed to allow the smooth animation work correctly,
- * as 'auto' heights cannot be used in animations.
- *
- * We also dispatch a bubbling 'measure' event, allowing content to render
- * itself only after the user requests it to be shown in the first place.
- */
- measure: function() {
- cr.dispatchSimpleEvent(this, 'measure', true); // true = allow bubbling
- var contents = this.querySelectorAll('.zippy-content');
- for (var i = 0; i < contents.length; i++) {
- contents[i].style.height = 'auto';
- }
- // Use a separate loop to avoid relayout after each one.
- for (var i = 0; i < contents.length; i++) {
- contents[i].style.height = contents[i].offsetHeight + 'px';
- }
- // Enable animation only after setting a fixed size.
- this.classList.add('animated');
- // Collapse, disable measure mode, and then re-expand.
- this.classList.add('collapsed');
- this.classList.remove('measure');
- this.classList.remove('collapsed');
- },
-
- /**
- * Remeasure this zippy.
- *
- * This works by disabling animation, setting the measure property to hide
- * the zippy, letting its size auto-adjust, and then explicitly setting the
- * size to the natural size. This is required to allow smooth transitions
- * when the contents change size.
- *
- * Special care must be taken when remeasuring currently hidden zippies
- * (that is, when the entire zippy is hidden, not just when it's collapsed),
- * because the contents cannot be measured when the zippy is not displayed.
- */
- remeasure: function() {
- var contents = this.querySelectorAll('.zippy-content');
-
- if (this.classList.contains('collapsed')) {
- // Not currently expanded, set the measure class to remeasure later.
- this.classList.add('measure');
- // Disable animation in case it was previously measured.
- this.classList.remove('animated');
- return;
- }
- // There is still the possibility that the zippy is expanded but not
- // visible, so we will need to take special care to detect this case.
-
- // First disable animation and get the current heights.
- this.classList.remove('animated');
- var oldHeights = [];
- for (var i = 0; i < contents.length; i++) {
- oldHeights[i] = contents[i].style.height;
- }
-
- // This will hide the contents but make them resize correctly, unless they
- // are in a zippy which is itself not displayed.
- this.classList.add('remeasure');
- for (var i = 0; i < contents.length; i++) {
- contents[i].style.height = 'auto';
- }
-
- // Calculate the new heights and figure out if any are nonzero.
- var newHeights = [];
- var nonzero = false;
- for (var i = 0; i < contents.length; i++) {
- newHeights[i] = contents[i].offsetHeight;
- if (contents[i].offsetHeight) {
- nonzero = true;
- }
- }
-
- // There were no nonzero heights. We assume we're not currently showing,
- // yet expanded. Set heights to auto, leave visible, and set the content
- // to remeasure next time it is collapsed.
- if (!nonzero) {
- this.classList.remove('remeasure');
- // This function will be called before collapsing this zippy.
- this.precollapse = function() {
- for (var i = 0; i < contents.length; i++) {
- contents[i].style.height = contents[i].offsetHeight + 'px';
- var x = contents[i].offsetHeight; // Just need to access it.
- }
- // Only now can we re-enable animation.
- this.classList.add('animated');
- this.precollapse = null;
- };
- return;
- }
-
- // Restore the old heights so we can animate starting from them.
- for (var i = 0; i < contents.length; i++) {
- contents[i].style.height = oldHeights[i];
- }
-
- // Reshow the contents and force re-layout to avoid incorrect animation.
- this.classList.remove('remeasure');
- for (var i = 0; i < contents.length; i++) {
- var x = contents[i].offsetHeight; // Just need to access it.
- }
-
- // Now enable animation and set the new heights.
- this.classList.add('animated');
- for (var i = 0; i < contents.length; i++) {
- if (newHeights[i]) {
- contents[i].style.height = newHeights[i] + 'px';
- }
- }
- },
-
- /**
- * Returns true if this zippy is currently expanded.
- *
- * @type {boolean}
- */
- get expanded() {
- return !this.classList.contains('collapsed');
- },
-
- /**
- * Set the expanded state of this zippy.
- *
- * This mostly just toggles the 'collapsed' class on the zippy, but
- * it also checks for and runs other code needed to help the smooth
- * animation calculate the height of the contents correctly.
- *
- * @param {boolean} state Whether to expand the zippy.
- */
- set expanded(state) {
- if (this.expanded == state) {
- return;
- }
- if (this.precollapse && !state) {
- this.precollapse();
- }
- this.classList.toggle('collapsed');
- if (this.classList.contains('measure')) {
- this.measure();
- }
- },
- };
-
- // Export
- return {
- Zippy: Zippy
- };
-
-});
diff --git a/chrome/browser/resources/plugins.html b/chrome/browser/resources/plugins.html
index 7cee567..cb0a164 100644
--- a/chrome/browser/resources/plugins.html
+++ b/chrome/browser/resources/plugins.html
@@ -20,14 +20,10 @@ div#header {
min-height: 67px;
overflow: hidden;
padding-bottom: 20px;
- padding-left: 0;
+ -webkit-padding-start: 0;
padding-top: 20px;
position: relative;
- -webkit-box-sizing: border-box;
-}
-
-html[dir=rtl] #header {
- padding-right: 0;
+ box-sizing: border-box;
}
#header h1 {
@@ -62,16 +58,11 @@ div.content {
border-top: 1px solid #b5c7de;
font-size: 99%;
padding-bottom: 2px;
- padding-left: 5px;
+ -webkit-padding-start: 5px;
padding-top: 3px;
width: 100%;
}
-html[dir=rtl] .section-header {
- padding-right: 5px;
- padding-left: 0;
-}
-
.section-header > table tr td:first-child {
width: 100%;
}
@@ -96,12 +87,7 @@ html[dir=rtl] .section-header {
}
#top {
- padding-right: 5px;
-}
-
-html[dir=rtl] #top {
- padding-left: 5px;
- padding-right: 0;
+ -webkit-padding-end: 5px;
}
.showInTmiMode {
@@ -153,16 +139,11 @@ body.showTmiMode .showInTmiMode {
border-bottom: 1px solid #edeff5;
font-size: 89%;
padding-bottom: 0.8em;
- padding-left: 10px;
+ -webkit-padding-start: 10px;
padding-top: 0.8em;
width: 100%;
}
-html[dir=rtl] .tmi-mode {
- padding-right: 10px;
- padding-left: 0;
-}
-
.plugin-disabled > td {
background-color: #f0f0f0;
color: #a0a0a0;
@@ -197,12 +178,7 @@ html[dir=rtl] .tmi-mode {
/* Indent the text related to each plug-in. */
.plugin-text {
- padding-left: 5px;
-}
-
-html[dir=rtl] .plugin-text {
- padding-right: 5px;
- padding-left: 0;
+ -webkit-padding-start: 5px;
}
.plugin-name {
@@ -237,12 +213,7 @@ html[dir=rtl] .plugin-text {
/* Separate columns by 1em for the most part. */
.plugin-details td+td {
- padding-left: 1em;
-}
-
-html[dir=rtl] .plugin-details td+td {
- padding-right: 1em;
- padding-left: 0;
+ -webkit-padding-start: 1em;
}
/* Make the MIME Types tables smaller. */
@@ -258,26 +229,16 @@ html[dir=rtl] .plugin-details td+td {
/* Separate the columns for tables used for horizontal listings only a bit. */
.hlisting td+td {
- padding-left: 0.4em;
-}
-
-html[dir=rtl] .hlisting td+td {
- padding-right: 0.4em;
- padding-left: 0;
+ -webkit-padding-start: 0.4em;
}
/* Match the indentation of .plugin-text. */
.plugin-actions {
- padding-left: 5px;
+ -webkit-padding-start: 5px;
margin-top: 0.2em;
margin-bottom: 0.2em;
}
-html[dir=rtl] .plugin-actions {
- padding-right: 5px;
- padding-left: 0;
-}
-
button {
font-size: 104%;
}
diff --git a/chrome/browser/resources/print_preview.css b/chrome/browser/resources/print_preview.css
index 514210a..f338b98 100644
--- a/chrome/browser/resources/print_preview.css
+++ b/chrome/browser/resources/print_preview.css
@@ -54,6 +54,11 @@ body {
background-color: #ccc;
}
+#pdf-viewer {
+ width: 100%;
+ height: 100%;
+}
+
section {
-webkit-box-orient: horizontal;
display: -webkit-box;
diff --git a/chrome/browser/resources/print_preview.html b/chrome/browser/resources/print_preview.html
index ff755c5..b916331 100644
--- a/chrome/browser/resources/print_preview.html
+++ b/chrome/browser/resources/print_preview.html
@@ -75,7 +75,8 @@
</div>
<div id="separator"></div>
<div id="mainview">
- MAIN
+ <p id="loading" i18n-content="loading"></p>
+ <p id="no-plugin" class="hidden" i18n-content="noPlugin"></p>
</div>
<script>
diff --git a/chrome/browser/resources/print_preview.js b/chrome/browser/resources/print_preview.js
index 02a1bc4..38694ea 100644
--- a/chrome/browser/resources/print_preview.js
+++ b/chrome/browser/resources/print_preview.js
@@ -3,6 +3,7 @@
// found in the LICENSE file.
var localStrings = new LocalStrings();
+var hasPDFPlugin = true;
/**
* Window onload handler, sets up the page.
@@ -13,6 +14,7 @@ function load() {
});
chrome.send('getPrinters');
+ chrome.send('getPreview');
};
/**
@@ -34,5 +36,39 @@ function setPrinters(printers) {
}
}
-window.addEventListener('DOMContentLoaded', load);
+function onPDFLoad() {
+ $('pdf-viewer').fitToHeight();
+}
+/**
+ * Create the PDF plugin or reload the existing one.
+ */
+function createPDFPlugin(url) {
+ if (!hasPDFPlugin) {
+ return;
+ }
+
+ if ($('pdf-viewer')) {
+ $('pdf-viewer').reload();
+ return;
+ }
+
+ var loadingElement = $('loading');
+ loadingElement.classList.add('hidden');
+ var mainView = loadingElement.parentNode;
+
+ var pdfPlugin = document.createElement('object');
+ pdfPlugin.setAttribute('id', 'pdf-viewer');
+ pdfPlugin.setAttribute('type', 'application/pdf');
+ pdfPlugin.setAttribute('src', url);
+ mainView.appendChild(pdfPlugin);
+ if (!pdfPlugin.onload) {
+ hasPDFPlugin = false;
+ mainView.removeChild(pdfPlugin);
+ $('no-plugin').classList.remove('hidden');
+ return;
+ }
+ pdfPlugin.onload('onPDFLoad()');
+}
+
+window.addEventListener('DOMContentLoaded', load);
diff --git a/chrome/browser/resources/safe_browsing_malware_block.html b/chrome/browser/resources/safe_browsing_malware_block.html
index 8bd95a0..0dd7952 100644
--- a/chrome/browser/resources/safe_browsing_malware_block.html
+++ b/chrome/browser/resources/safe_browsing_malware_block.html
@@ -44,7 +44,7 @@ html[dir='rtl'] .box {
color:#660000;
}
.main {
- margin:0px 90px 0px;
+ margin:0px 90px 10px;
}
.submission {
margin:15px 5px 15px 0px;
@@ -69,113 +69,44 @@ input {
margin-right:5px;
}
-.nicebutton {
+
+.green {
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#83c260), color-stop(44%,#71b44c), color-stop(100%,#549d2c));
+ border: 1px solid #4c7336;
+ border-bottom: 1px solid #44692f;
+ border-radius: 3px;
+ -webkit-box-shadow: inset 0 1px 0 0 #a0d186, 0px 1px 2px rgba(0,0,0,0.2);
color: #fff;
- font-size: 11pt;
+ font-family: arial, helvetica, sans-serif;
+ font-size: 14px;
font-weight: bold;
- padding: 7px 20px;
- border-radius: 5px;
- outline-width: 0;
- border: 1px solid #4C7336;
- -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3),
- inset 0px 1px 0px rgba(255, 255, 255, 0.5);
- text-shadow: -1px -1px 0px rgba(0, 0, 0, 0.2);
-}
-
-#back {
- border: 1px solid #4C7336;
- background-image: -webkit-gradient(linear,
- left top, left bottom,
- color-stop(0.3, #81C05C),
- color-stop(1.0, #59A02F));
-}
-
-#more {
- border: 1px solid #23517B;
- background-image: -webkit-gradient(linear,
- left top, left bottom,
- color-stop(0.3, #5E91C1),
- color-stop(1.0, #2E689E));
-}
-
-#less {
- border: 1px solid #23517B;
- background-image: -webkit-gradient(linear,
- left top, left bottom,
- color-stop(0.3, #5E91C1),
- color-stop(1.0, #2E689E));
-}
-
-#back:hover {
- background-image: -webkit-gradient(linear,
- left top, left bottom,
- color-stop(0.3, #8CCE62),
- color-stop(1.0, #59A02F));
-}
-
-#back:active {
- background-image: -webkit-gradient(linear,
- left top, left bottom,
- color-stop(0.3, #59A02F),
- color-stop(1.0, #8CCE62));
-}
-
-#back:focus {
- border: 1px solid #000;
- background-image: -webkit-gradient(linear,
- left top, left bottom,
- color-stop(0.3, #8CCE62),
- color-stop(1.0, #59A02F));
+ line-height: 1;
+ padding: 6px 16px 7px 16px;
+ text-align: center;
+ text-shadow: 0 -1px 0 #4865e4;
+ cursor: pointer;
+ text-decoration: none;
+ display: inline-block;
}
-#more:hover{
- border: 1px solid #23517B;
- background-image: -webkit-gradient(linear,
- left top, left bottom,
- color-stop(0.3, #68A1D6),
- color-stop(1.0, #2E689E));
+.green:hover, .green:focus {
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#8bc968), color-stop(44%,#7bbc57), color-stop(100%,#4f9727)); /* webkit */
+ border: 1px solid #456a2f;
+ border-bottom: 1px solid #456a2f;
+ -webkit-box-shadow: inset 0 1px 0 0 #a0d186, 0px 1px 2px rgba(0,0,0,0.3);;
}
-#less:hover{
- border: 1px solid #23517B;
- background-image: -webkit-gradient(linear,
- left top, left bottom,
- color-stop(0.3, #68A1D6),
- color-stop(1.0, #2E689E));
+.green:active {
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#83c260), color-stop(44%,#71b44c), color-stop(100%,#549d2c)); /* webkit */
+ border: 1px solid #3e612a;
+ border-top:1px solid #4c7336;
+ border-bottom:1px solid #547b3f;
+ -webkit-box-shadow: inset 1px 1px 1px 1px rgba(0, 0, 0, 0.1);
}
-#more:active{
- border: 1px solid #23517B;
- background-image: -webkit-gradient(linear,
- left top, left bottom,
- color-stop(0.3, #2E689E),
- color-stop(1.0, #68A1D6));
-}
-
-#less:active {
- border: 1px solid #23517B;
- background-image: -webkit-gradient(linear,
- left top, left bottom,
- color-stop(0.3, #2E689E),
- color-stop(1.0, #68A1D6));
-}
-
-#more:focus {
- border: 1px solid #000;
- background-image: -webkit-gradient(linear,
- left top, left bottom,
- color-stop(0.3, #68A1D6),
- color-stop(1.0, #2E689E));
-}
-
-#less:focus {
+.green:focus {
border: 1px solid #000;
- background-image: -webkit-gradient(linear,
- left top, left bottom,
- color-stop(0.3, #68A1D6),
- color-stop(1.0, #2E689E));
}
-
</style>
<script>
@@ -183,27 +114,8 @@ input {
window.domAutomationController.setAutomationId(1);
window.domAutomationController.send(cmd);
}
-
- function agreed(form) {
- form.continue_button.disabled = !form.continue_button.disabled;
- }
-
- function toggle() {
- var moreButton = document.getElementById('more')
- var lessButton = document.getElementById('less')
- var content = document.getElementById('detailinfo')
- if (content.style.display == 'none'){
- content.style.display = 'block'
- moreButton.style.display = 'none'
- lessButton.style.display = 'inline'
- } else {
- content.style.display = 'none'
- moreButton.style.display = 'inline'
- lessButton.style.display = 'none'
- }
-
- }
</script>
+
</head>
<body oncontextmenu="return false;">
<div class="background"><img src="../security/resources/ssl_roadblock_background.png" width="100%" height="100%" alt="background" onmousedown="return false;"/></div>
@@ -212,20 +124,18 @@ input {
<div class="box">
<div class="icon"><img src="shared/images/phishing_icon.png" alt="Malware Icon" onmousedown="return false;"/></div>
<div class="title" i18n-content="headLine"></div>
- <div class="main" i18n-values=".innerHTML:description1" style="margin-bottom:15px"></div>
+ <div class="main" i18n-values=".innerHTML:description1"></div>
<div class="main" i18n-values=".innerHTML:description2"></div>
+ <div class="main" i18n-values=".innerHTML:description5" id="detailinfo" style="display:block"></div>
<div class="main">
<form class="submission">
- <input type="button" class="nicebutton" id="back" i18n-values="value:back_button" onclick="sendCommand('takeMeBack')">
- <input type="button" class="nicebutton" id="more" i18n-values="value:more_info_button" onclick="toggle()">
- <input type="button" class="nicebutton" id="less" i18n-values="value:less_info_button" style="display:none" onclick="toggle()">
- <br />
+ <input type="button" class="green" id="back" i18n-values="value:back_button" onclick="sendCommand('takeMeBack')">
+ <br>
</form>
- <span i18n-values=".innerHTML:description5" id="detailinfo" style="display:none"></span>
</div>
- <div class="main" i18n-values=".innerHTML:description3" style="margin-top:10px"></div>
+ <div class="main" i18n-values=".innerHTML:description3"></div>
</div>
</td>
diff --git a/chrome/browser/resources/safe_browsing_phishing_block.html b/chrome/browser/resources/safe_browsing_phishing_block.html
index 46d400a..52ca6a8 100644
--- a/chrome/browser/resources/safe_browsing_phishing_block.html
+++ b/chrome/browser/resources/safe_browsing_phishing_block.html
@@ -1,5 +1,5 @@
<!DOCTYPE html>
-<html i18n-values="dir:textdirection">
+<html id="template_root" i18n-values="dir:textdirection">
<head>
<title i18n-content="title"></title>
<style>
@@ -65,9 +65,43 @@ html[dir='rtl'] .helpbutton {
border-top:1px solid #ccc;
padding-top:6px;
}
-.moreinfotitle {
- margin-left:5px;
- margin-right:5px;
+
+.green {
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#83c260), color-stop(44%,#71b44c), color-stop(100%,#549d2c));
+ border: 1px solid #4c7336;
+ border-bottom: 1px solid #44692f;
+ border-radius: 3px;
+ -webkit-box-shadow: inset 0 1px 0 0 #a0d186, 0px 1px 2px rgba(0,0,0,0.2);
+ color: #fff;
+ font-family: arial, helvetica, sans-serif;
+ font-size: 14px;
+ font-weight: bold;
+ line-height: 1;
+ padding: 6px 16px 7px 16px;
+ text-align: center;
+ text-shadow: 0 -1px 0 #4865e4;
+ cursor:pointer;
+ text-decoration:none;
+ display:inline-block;
+}
+
+.green:hover, .green:focus {
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#8bc968), color-stop(44%,#7bbc57), color-stop(100%,#4f9727)); /* webkit */
+ border: 1px solid #456a2f;
+ border-bottom: 1px solid #456a2f;
+ -webkit-box-shadow: inset 0 1px 0 0 #a0d186, 0px 1px 2px rgba(0,0,0,0.3);;
+}
+
+.green:active {
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#83c260), color-stop(44%,#71b44c), color-stop(100%,#549d2c)); /* webkit */
+ border: 1px solid #3e612a;
+ border-top:1px solid #4c7336;
+ border-bottom:1px solid #547b3f;
+ -webkit-box-shadow: inset 1px 1px 1px 1px rgba(0, 0, 0, 0.1);
+}
+
+.green:focus {
+ border: 1px solid #000;
}
</style>
@@ -76,11 +110,8 @@ html[dir='rtl'] .helpbutton {
window.domAutomationController.setAutomationId(1);
window.domAutomationController.send(cmd);
}
-
- function agreed(form) {
- form.continue_button.disabled = !form.continue_button.disabled;
- }
</script>
+
</head>
<body oncontextmenu="return false;">
<div class="background"><img src="../security/resources/ssl_roadblock_background.png" width="100%" height="100%" alt="background" onmousedown="return false;"></div>
@@ -90,14 +121,14 @@ html[dir='rtl'] .helpbutton {
<div class="icon"><img src="shared/images/phishing_icon.png" alt="Phishing Warning Icon" onmousedown="return false;"></div>
<div class="title" i18n-content="headLine"></div>
<div class="main" i18n-values=".innerHTML:description1"></div>
- <div class="main"><a href="" i18n-content="description2" onclick="sendCommand('learnMore'); return false;" onmousedown="return false;"></a></div>
<div class="main">
<form class="submission">
- <input type="button" name="continue_button" i18n-values="value:continue_button" onclick="sendCommand('proceed')">
- <input type="button" name="back_button" i18n-values="value:back_button" onclick="sendCommand('takeMeBack')">
+ <input type="button" class="green" id="back" i18n-values="value:back_button" onclick="sendCommand('takeMeBack')">
</form>
</div>
+ <div class="main"><a href="" i18n-content="description2" onclick="sendCommand('learnMore'); return false;"></a></div>
<div class="main"><a href="" onclick="sendCommand('reportError'); return false;" onmousedown="return false;" i18n-content="report_error"></a></div>
+ <div class="main" i18n-values=".innerHTML:description3"></div>
</div>
</td>
</table>
diff --git a/chrome/browser/resources/shared/css/button.css b/chrome/browser/resources/shared/css/button.css
index 8a3d930..1d1c25a 100644
--- a/chrome/browser/resources/shared/css/button.css
+++ b/chrome/browser/resources/shared/css/button.css
@@ -1,7 +1,7 @@
button {
padding: 5px 8px;
border: 1px solid rgba(0, 0, 0, .50);
- -webkit-border-radius: 3px;
+ border-radius: 3px;
-webkit-box-shadow: 1px 1px 0px rgba(0, 0, 0, .10);
background: -webkit-gradient(linear, 0 50%, 0 100%,
from(#ffffff), to(#e3e3e3));
diff --git a/chrome/browser/resources/shared/css/list.css b/chrome/browser/resources/shared/css/list.css
index 65b16e6..15be68e 100644
--- a/chrome/browser/resources/shared/css/list.css
+++ b/chrome/browser/resources/shared/css/list.css
@@ -5,7 +5,6 @@ list {
overflow: auto;
position: relative; /* Make sure that item offsets are relative to the
list. */
- height: 200px;
}
list > * {
@@ -37,7 +36,7 @@ list > [anchor] {
}
-list > :hover {
+list:not([disabled]) > :hover {
border-color: hsl(214, 91%, 85%);
z-index: 1;
background-color: hsl(214, 91%, 97%);
@@ -67,7 +66,7 @@ list > [selected]:hover {
list > .spacer {
border: 0;
- -webkit-box-sizing: border-box;
+ box-sizing: border-box;
overflow: hidden;
visibility: hidden;
margin: 0;
diff --git a/chrome/browser/resources/shared/css/menu.css b/chrome/browser/resources/shared/css/menu.css
index 19f5248..2aeac3e 100644
--- a/chrome/browser/resources/shared/css/menu.css
+++ b/chrome/browser/resources/shared/css/menu.css
@@ -15,7 +15,7 @@ menu {
}
menu > * {
- -webkit-box-sizing: border-box;
+ box-sizing: border-box;
display: block;
margin: 0;
width: 100%;
diff --git a/chrome/browser/resources/shared/css/tree.css b/chrome/browser/resources/shared/css/tree.css
index d044262..5ea5f86 100644
--- a/chrome/browser/resources/shared/css/tree.css
+++ b/chrome/browser/resources/shared/css/tree.css
@@ -95,7 +95,7 @@ tree:focus .tree-row[selected] {
.tree-item > .tree-row > * {
display: inline-block;
- -webkit-box-sizing: border-box;
+ box-sizing: border-box;
}
.tree-label {
diff --git a/chrome/browser/resources/shared/js/cr.js b/chrome/browser/resources/shared/js/cr.js
index a470234..6686269 100644
--- a/chrome/browser/resources/shared/js/cr.js
+++ b/chrome/browser/resources/shared/js/cr.js
@@ -23,6 +23,12 @@ const cr = (function() {
const isChromeOS = /CrOS/.test(navigator.userAgent);
/**
+ * Whether this is on vanilla Linux (not chromeOS).
+ * @type {boolean}
+ */
+ const isLinux = /Linux/.test(navigator.userAgent);
+
+ /**
* Whether this uses the views toolkit or not.
* @type {boolean}
*/
@@ -325,6 +331,8 @@ const cr = (function() {
isChromeOS: isChromeOS,
isMac: isMac,
isWindows: isWindows,
+ isLinux: isLinux,
+ isViews: isViews,
define: define,
defineProperty: defineProperty,
PropertyKind: PropertyKind,
diff --git a/chrome/browser/resources/shared/js/cr/ui/list.js b/chrome/browser/resources/shared/js/cr/ui/list.js
index 6b98944..9a579d8 100644
--- a/chrome/browser/resources/shared/js/cr/ui/list.js
+++ b/chrome/browser/resources/shared/js/cr/ui/list.js
@@ -88,6 +88,14 @@ cr.define('cr.ui', function() {
*/
itemHeight_: 0,
+ /**
+ * Whether or not the list is autoexpanding. If true, the list resizes
+ * its height to accomadate all children.
+ * @type {boolean}
+ * @private
+ */
+ autoExpands_: false,
+
dataModel_: null,
/**
@@ -165,6 +173,20 @@ cr.define('cr.ui', function() {
},
/**
+ * Whether or not the list auto-expands.
+ * @type {boolean}
+ */
+ get autoExpands() {
+ return this.autoExpands_;
+ },
+ set autoExpands(autoExpands) {
+ if (this.autoExpands_ == autoExpands)
+ return;
+ this.autoExpands_ = autoExpands;
+ this.redraw();
+ },
+
+ /**
* Convenience alias for selectionModel.selectedItem
* @type {cr.ui.ListItem}
*/
@@ -201,12 +223,14 @@ cr.define('cr.ui', function() {
},
/**
- * The HTML elements representing the items. This is just all the element
+ * The HTML elements representing the items. This is just all the list item
* children but subclasses may override this to filter out certain elements.
* @type {HTMLCollection}
*/
get items() {
- return this.children;
+ return Array.prototype.filter.call(this.children, function(child) {
+ return !child.classList.contains('spacer');
+ });
},
batchCount_: 0,
@@ -245,6 +269,7 @@ cr.define('cr.ui', function() {
var length = this.dataModel ? this.dataModel.length : 0;
this.selectionModel = new ListSelectionModel(length);
+ this.addEventListener('dblclick', this.handleDoubleClick_);
this.addEventListener('mousedown', this.handleMouseDownUp_);
this.addEventListener('mouseup', this.handleMouseDownUp_);
this.addEventListener('keydown', this.handleKeyDown);
@@ -256,11 +281,38 @@ cr.define('cr.ui', function() {
},
/**
+ * Returns the height of an item, measuring it if necessary.
+ * @private
+ */
+ getItemHeight_: function() {
+ if (!this.itemHeight_)
+ this.itemHeight_ = measureItem(this);
+ return this.itemHeight_;
+ },
+
+ /**
+ * Callback for the double click event.
+ * @param {Event} e The mouse event object.
+ * @private
+ */
+ handleDoubleClick_: function(e) {
+ if (this.disabled)
+ return;
+
+ var target = this.getListItemAncestor(e.target);
+ var index = target ? this.getIndexOfListItem(target) : -1;
+ this.activateItemAtIndex(index);
+ },
+
+ /**
* Callback for mousedown and mouseup events.
* @param {Event} e The mouse event object.
* @private
*/
handleMouseDownUp_: function(e) {
+ if (this.disabled)
+ return;
+
var target = e.target;
// If the target was this element we need to make sure that the user did
@@ -268,19 +320,24 @@ cr.define('cr.ui', function() {
if (target == this && !inViewport(target, e))
return;
- while (target && target.parentNode != this) {
- target = target.parentNode;
- }
+ target = this.getListItemAncestor(target);
- if (!target) {
- this.selectionController_.handleMouseDownUp(e, -1);
- } else {
- var cs = getComputedStyle(target);
- var top = target.offsetTop -
- parseFloat(cs.marginTop);
- var index = Math.floor(top / this.itemHeight_);
- this.selectionController_.handleMouseDownUp(e, index);
+ var index = target ? this.getIndexOfListItem(target) : -1;
+ this.selectionController_.handleMouseDownUp(e, index);
+ },
+
+ /**
+ * Returns the list item element containing the given element, or null if
+ * it doesn't belong to any list item element.
+ * @param {HTMLElement} element The element.
+ * @return {ListItem} The list item containing |element|, or null.
+ */
+ getListItemAncestor: function(element) {
+ var container = element;
+ while (container && container.parentNode != this) {
+ container = container.parentNode;
}
+ return container;
},
/**
@@ -289,6 +346,9 @@ cr.define('cr.ui', function() {
* @return {boolean} Whether the key event was handled.
*/
handleKeyDown: function(e) {
+ if (this.disabled)
+ return;
+
return this.selectionController_.handleKeyDown(e);
},
@@ -354,7 +414,7 @@ cr.define('cr.ui', function() {
if (!dataModel || index < 0 || index >= dataModel.length)
return false;
- var itemHeight = this.itemHeight_;
+ var itemHeight = this.getItemHeight_();
var scrollTop = this.scrollTop;
var top = index * itemHeight;
@@ -417,6 +477,22 @@ cr.define('cr.ui', function() {
},
/**
+ * Find the index of the given list item element.
+ * @param {ListItem} item The list item to get the index of.
+ * @return {number} The index of the list item, or -1 if not found.
+ */
+ getIndexOfListItem: function(item) {
+ var cs = getComputedStyle(item);
+ var top = item.offsetTop - parseFloat(cs.marginTop);
+ var index = Math.floor(top / this.getItemHeight_());
+ var childIndex = index - this.firstIndex_ + 1;
+ if (childIndex >= 0 && childIndex < this.children.length &&
+ this.children[childIndex] == item)
+ return index;
+ return -1;
+ },
+
+ /**
* Creates a new list item.
* @param {*} value The value to use for the item.
* @return {!ListItem} The newly created list item.
@@ -452,10 +528,7 @@ cr.define('cr.ui', function() {
var scrollTop = this.scrollTop;
var clientHeight = this.clientHeight;
- if (!this.itemHeight_)
- this.itemHeight_ = measureItem(this);
-
- var itemHeight = this.itemHeight_;
+ var itemHeight = this.getItemHeight_();
// We cache the list items since creating the DOM nodes is the most
// expensive part of redrawing.
@@ -464,8 +537,10 @@ cr.define('cr.ui', function() {
var desiredScrollHeight = dataModel.length * itemHeight;
- var firstIndex = Math.floor(scrollTop / itemHeight);
- var itemsInViewPort = Math.min(dataModel.length - firstIndex,
+ var autoExpands = this.autoExpands_
+ var firstIndex = autoExpands ? 0 : Math.floor(scrollTop / itemHeight);
+ var itemsInViewPort = autoExpands ? dataModel.length : Math.min(
+ dataModel.length - firstIndex,
Math.ceil((scrollTop + clientHeight - firstIndex * itemHeight) /
itemHeight));
var lastIndex = firstIndex + itemsInViewPort;
@@ -523,7 +598,7 @@ cr.define('cr.ui', function() {
},
/**
- * Redraws a single item
+ * Redraws a single item.
* @param {number} index The row index to redraw.
*/
redrawItem: function(index) {
@@ -531,9 +606,11 @@ cr.define('cr.ui', function() {
delete this.cachedItems_[index];
this.redraw();
}
- }
+ },
};
+ cr.defineProperty(List, 'disabled', cr.PropertyKind.BOOL_ATTR);
+
return {
List: List
}
diff --git a/chrome/browser/resources/shared/js/cr/ui/list_item.js b/chrome/browser/resources/shared/js/cr/ui/list_item.js
index 283216f..11a8de3 100644
--- a/chrome/browser/resources/shared/js/cr/ui/list_item.js
+++ b/chrome/browser/resources/shared/js/cr/ui/list_item.js
@@ -27,10 +27,38 @@ cr.define('cr.ui', function() {
},
/**
+ * The current selection state.
+ * @type {Boolean}
+ */
+ get selected() {
+ return this.hasAttribute('selected');
+ },
+ set selected(selected) {
+ selected = Boolean(selected);
+ var oldSelected = this.selected;
+ if (oldSelected == selected)
+ return;
+
+ if (selected)
+ this.setAttribute('selected', '');
+ else
+ this.removeAttribute('selected');
+
+ cr.dispatchPropertyChange(this, 'selected', selected, oldSelected);
+ this.selectionChanged();
+ },
+
+ /**
* Called when an element is decorated as a list item.
*/
decorate: function() {
- }
+ },
+
+ /**
+ * Called when the selection state of this element changes.
+ */
+ selectionChanged: function() {
+ },
};
/**
diff --git a/chrome/browser/resources/shared/js/cr/ui/list_selection_controller.js b/chrome/browser/resources/shared/js/cr/ui/list_selection_controller.js
index 3697c9d..72aada6 100644
--- a/chrome/browser/resources/shared/js/cr/ui/list_selection_controller.js
+++ b/chrome/browser/resources/shared/js/cr/ui/list_selection_controller.js
@@ -137,7 +137,8 @@ cr.define('cr.ui', function() {
if (sm.multiple)
sm.unselectAll();
} else {
- if (sm.multiple && (cr.isMac ? e.metaKey : e.ctrlKey)) {
+ if (sm.multiple && (cr.isMac ? e.metaKey :
+ (e.ctrlKey && !e.shiftKey))) {
// Selection is handled at mouseUp on windows/linux, mouseDown on mac.
if (cr.isMac? isDown : !isDown) {
// toggle the current one and make it anchor index
diff --git a/chrome/browser/rlz/rlz.cc b/chrome/browser/rlz/rlz.cc
index 5031f43..48ac262 100644
--- a/chrome/browser/rlz/rlz.cc
+++ b/chrome/browser/rlz/rlz.cc
@@ -22,8 +22,8 @@
#include "base/thread_restrictions.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/common/chrome_paths.h"
diff --git a/chrome/browser/safe_browsing/client_side_detection_service.cc b/chrome/browser/safe_browsing/client_side_detection_service.cc
index 4000e8b..14aac20 100644
--- a/chrome/browser/safe_browsing/client_side_detection_service.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_service.cc
@@ -32,6 +32,11 @@ const char ClientSideDetectionService::kClientReportPhishingUrl[] =
const char ClientSideDetectionService::kClientModelUrl[] =
"https://ssl.gstatic.com/safebrowsing/csd/client_model_v0.pb";
+struct ClientSideDetectionService::ClientReportInfo {
+ scoped_ptr<ClientReportPhishingRequestCallback> callback;
+ GURL phishing_url;
+};
+
ClientSideDetectionService::ClientSideDetectionService(
const FilePath& model_path,
URLRequestContextGetter* request_context_getter)
diff --git a/chrome/browser/safe_browsing/client_side_detection_service.h b/chrome/browser/safe_browsing/client_side_detection_service.h
index 9f1ca39..41c87f6 100644
--- a/chrome/browser/safe_browsing/client_side_detection_service.h
+++ b/chrome/browser/safe_browsing/client_side_detection_service.h
@@ -97,11 +97,6 @@ class ClientSideDetectionService : public URLFetcher::Delegate {
ERROR_STATUS,
};
- struct ClientReportInfo {
- scoped_ptr<ClientReportPhishingRequestCallback> callback;
- GURL phishing_url;
- };
-
static const char kClientReportPhishingUrl[];
static const char kClientModelUrl[];
@@ -177,6 +172,7 @@ class ClientSideDetectionService : public URLFetcher::Delegate {
// Map of client report phishing request to the corresponding callback that
// has to be invoked when the request is done.
+ struct ClientReportInfo;
std::map<const URLFetcher*, ClientReportInfo*> client_phishing_reports_;
// Used to asynchronously call the callbacks for GetModelFile and
diff --git a/chrome/browser/safe_browsing/malware_details.cc b/chrome/browser/safe_browsing/malware_details.cc
new file mode 100644
index 0000000..b4860a2
--- /dev/null
+++ b/chrome/browser/safe_browsing/malware_details.cc
@@ -0,0 +1,98 @@
+// 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.
+//
+// Implementation of the MalwareDetails class.
+
+#include "chrome/browser/safe_browsing/malware_details.h"
+
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
+#include "chrome/browser/tab_contents/navigation_entry.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/safe_browsing/report.pb.h"
+
+// Create a MalwareDetails for the given tab. Runs in the UI thread.
+MalwareDetails::MalwareDetails(
+ TabContents* tab_contents,
+ const SafeBrowsingService::UnsafeResource resource)
+ : tab_contents_(tab_contents),
+ resource_(resource) {
+ StartCollection();
+}
+
+MalwareDetails::~MalwareDetails() {}
+
+bool MalwareDetails::IsPublicUrl(const GURL& url) const {
+ return url.SchemeIs("http"); // TODO(panayiotis): also skip internal urls.
+}
+
+void MalwareDetails::AddNode(const std::string& url,
+ const std::string& parent) {
+ if (!IsPublicUrl(GURL(url)))
+ return;
+ linked_ptr<safe_browsing::ClientMalwareReportRequest::Resource> resource(
+ new safe_browsing::ClientMalwareReportRequest::Resource());
+ resource->set_url(url);
+ if (!parent.empty() && IsPublicUrl(GURL(parent)))
+ resource->set_parent(parent);
+ urls_[url] = resource;
+}
+
+void MalwareDetails::StartCollection() {
+ DVLOG(1) << "Starting to compute malware details.";
+ report_.reset(new safe_browsing::ClientMalwareReportRequest());
+
+ if (IsPublicUrl(resource_.url)) {
+ report_->set_malware_url(resource_.url.spec());
+ }
+
+ GURL page_url = tab_contents_->GetURL();
+ if (IsPublicUrl(page_url)) {
+ report_->set_page_url(page_url.spec());
+ }
+
+ GURL referrer_url;
+ NavigationEntry* nav_entry = tab_contents_->controller().GetActiveEntry();
+ if (nav_entry) {
+ referrer_url = nav_entry->referrer();
+ if (IsPublicUrl(referrer_url)) {
+ report_->set_referrer_url(referrer_url.spec());
+ }
+ }
+
+ // Add the nodes, starting from the page url.
+ AddNode(page_url.spec(), "");
+
+ // Add the resource_url and its original url, if non-empty and different.
+ if (!resource_.original_url.spec().empty() &&
+ resource_.url != resource_.original_url) {
+ // Add original_url, as the parent of resource_url.
+ AddNode(resource_.original_url.spec(), "");
+ AddNode(resource_.url.spec(), resource_.original_url.spec());
+ } else {
+ AddNode(resource_.url.spec(), "");
+ }
+
+ // Add the referrer url.
+ if (nav_entry && !referrer_url.spec().empty()) {
+ AddNode(referrer_url.spec(), "");
+ }
+
+ // Add all the urls in our |urls_| map to the |report_| protobuf.
+ for (ResourceMap::const_iterator it = urls_.begin();
+ it != urls_.end(); it++) {
+ safe_browsing::ClientMalwareReportRequest::Resource* pb_resource =
+ report_->add_nodes();
+ pb_resource->CopyFrom(*(it->second));
+ }
+}
+
+// Called from the SB Service on the IO thread.
+const std::string* MalwareDetails::GetSerializedReport() {
+ scoped_ptr<std::string> request_data(new std::string());
+ if (!report_->SerializeToString(request_data.get())) {
+ DLOG(ERROR) << "Unable to serialize the malware report.";
+ }
+
+ return request_data.release();
+}
diff --git a/chrome/browser/safe_browsing/malware_details.h b/chrome/browser/safe_browsing/malware_details.h
new file mode 100644
index 0000000..7d21dc4
--- /dev/null
+++ b/chrome/browser/safe_browsing/malware_details.h
@@ -0,0 +1,68 @@
+// 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.
+
+#ifndef CHROME_BROWSER_SAFE_BROWSING_MALWARE_DETAILS_H_
+#define CHROME_BROWSER_SAFE_BROWSING_MALWARE_DETAILS_H_
+#pragma once
+
+// A class that encapsulates the detailed malware reports sent when
+// users opt-in to do so from the malware warning page.
+
+// An instance of this class is generated when a malware warning page
+// is shown (SafeBrowsingBlockingPage). It is passed on to the
+// SafeBrowsing service when the warning goes away.
+
+#include <string>
+#include <vector>
+
+#include "base/hash_tables.h"
+#include "base/linked_ptr.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/safe_browsing/report.pb.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
+
+class TabContents;
+
+class MalwareDetails : public base::RefCountedThreadSafe<MalwareDetails> {
+ public:
+ MalwareDetails(TabContents* tab_contents,
+ const SafeBrowsingService::UnsafeResource resource);
+
+ // The SafeBrowsingService calls this from the IO thread, to get the
+ // serialized report as a string and send it over.
+ const std::string* GetSerializedReport();
+
+ private:
+ friend class base::RefCountedThreadSafe<MalwareDetails>;
+
+ typedef base::hash_map<
+ std::string,
+ linked_ptr<safe_browsing::ClientMalwareReportRequest::Resource> >
+ ResourceMap;
+
+ // Starts the collection of the report.
+ void StartCollection();
+
+ // Whether the url is "public" so we can add it to the report.
+ bool IsPublicUrl(const GURL& url) const;
+
+ // Adds a node to |urls_|. |parent| can be empty.
+ void AddNode(const std::string& url, const std::string& parent);
+
+ ~MalwareDetails();
+
+ TabContents* tab_contents_;
+ const SafeBrowsingService::UnsafeResource resource_;
+
+ // The urls that we collect. We first add them into this map and then
+ // generate a protocol buffer from it.
+ ResourceMap urls_;
+
+ // The report protocol buffer.
+ scoped_ptr<safe_browsing::ClientMalwareReportRequest> report_;
+
+ DISALLOW_COPY_AND_ASSIGN(MalwareDetails);
+};
+
+#endif // CHROME_BROWSER_SAFE_BROWSING_MALWARE_DETAILS_H_
diff --git a/chrome/browser/safe_browsing/malware_details_unittest.cc b/chrome/browser/safe_browsing/malware_details_unittest.cc
new file mode 100644
index 0000000..b6136c8
--- /dev/null
+++ b/chrome/browser/safe_browsing/malware_details_unittest.cc
@@ -0,0 +1,175 @@
+// 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.
+
+#include <algorithm>
+#include "chrome/browser/renderer_host/test/test_render_view_host.h"
+
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/safe_browsing/malware_details.h"
+#include "chrome/browser/safe_browsing/report.pb.h"
+#include "chrome/browser/tab_contents/navigation_entry.h"
+#include "chrome/browser/tab_contents/test_tab_contents.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
+
+static const char* kOriginalLandingURL = "http://www.originallandingpage.com/";
+static const char* kLandingURL = "http://www.landingpage.com/";
+static const char* kMalwareURL = "http://www.malware.com/";
+static const char* kHttpsURL = "https://www.url.com/";
+
+class MalwareDetailsTest : public RenderViewHostTestHarness {
+ public:
+ MalwareDetailsTest()
+ : ui_thread_(BrowserThread::UI, MessageLoop::current()),
+ io_thread_(BrowserThread::IO, MessageLoop::current()) {
+ }
+
+ virtual void SetUp() {
+ RenderViewHostTestHarness::SetUp();
+ }
+
+ static bool ResourceLessThan(
+ const safe_browsing::ClientMalwareReportRequest::Resource* lhs,
+ const safe_browsing::ClientMalwareReportRequest::Resource* rhs) {
+ return lhs->url() < rhs->url();
+ }
+
+ protected:
+ void InitResource(SafeBrowsingService::UnsafeResource* resource,
+ ResourceType::Type resource_type,
+ const GURL& url) {
+ resource->client = NULL;
+ resource->url = url;
+ resource->resource_type = resource_type;
+ resource->threat_type = SafeBrowsingService::URL_MALWARE;
+ resource->render_process_host_id = contents_->GetRenderProcessHost()->id();
+ resource->render_view_id = contents_->render_view_host()->routing_id();
+ }
+
+ void VerifyResults(
+ const safe_browsing::ClientMalwareReportRequest& report_pb,
+ const safe_browsing::ClientMalwareReportRequest& expected_pb) {
+ EXPECT_EQ(expected_pb.malware_url(), report_pb.malware_url());
+ EXPECT_EQ(expected_pb.page_url(), report_pb.page_url());
+ EXPECT_EQ(expected_pb.referrer_url(), report_pb.referrer_url());
+
+ ASSERT_EQ(expected_pb.nodes_size(), report_pb.nodes_size());
+ // Sort the nodes, to make the test deterministic
+ std::vector<const safe_browsing::ClientMalwareReportRequest::Resource*>
+ nodes;
+ for (int i = 0; i < report_pb.nodes_size(); ++i) {
+ const safe_browsing::ClientMalwareReportRequest::Resource& resource =
+ report_pb.nodes(i);
+ nodes.push_back(&resource);
+ }
+ std::sort(nodes.begin(), nodes.end(),
+ &MalwareDetailsTest::ResourceLessThan);
+
+ std::vector<const safe_browsing::ClientMalwareReportRequest::Resource*>
+ expected;
+ for (int i = 0; i < report_pb.nodes_size(); ++i) {
+ const safe_browsing::ClientMalwareReportRequest::Resource& resource =
+ expected_pb.nodes(i);
+ expected.push_back(&resource);
+ }
+ std::sort(expected.begin(), expected.end(),
+ &MalwareDetailsTest::ResourceLessThan);
+
+ for (uint32 i = 0; i < expected.size(); ++i) {
+ EXPECT_EQ(expected[i]->url(), nodes[i]->url());
+ EXPECT_EQ(expected[i]->parent(), nodes[i]->parent());
+ }
+ }
+
+ BrowserThread ui_thread_;
+ BrowserThread io_thread_;
+};
+
+// Tests creating a simple malware report.
+TEST_F(MalwareDetailsTest, MalwareSubResource) {
+ // Start a load.
+ controller().LoadURL(GURL(kLandingURL), GURL(), PageTransition::TYPED);
+
+ SafeBrowsingService::UnsafeResource resource;
+ InitResource(&resource, ResourceType::SUB_RESOURCE, GURL(kMalwareURL));
+
+ scoped_refptr<MalwareDetails> report = new MalwareDetails(
+ contents(), resource);
+
+ scoped_ptr<const std::string> serialized(report->GetSerializedReport());
+ safe_browsing::ClientMalwareReportRequest actual;
+ actual.ParseFromString(*serialized);
+
+ safe_browsing::ClientMalwareReportRequest expected;
+ expected.set_malware_url(kMalwareURL);
+ expected.set_page_url(kLandingURL);
+ expected.set_referrer_url("");
+
+ safe_browsing::ClientMalwareReportRequest::Resource* node =
+ expected.add_nodes();
+ node->set_url(kLandingURL);
+ node = expected.add_nodes();
+ node->set_url(kMalwareURL);
+
+ VerifyResults(actual, expected);
+}
+
+// Tests creating a simple malware report where the subresource has a
+// different original_url.
+TEST_F(MalwareDetailsTest, MalwareSubResourceWithOriginalUrl) {
+ controller().LoadURL(GURL(kLandingURL), GURL(), PageTransition::TYPED);
+
+ SafeBrowsingService::UnsafeResource resource;
+ InitResource(&resource, ResourceType::SUB_RESOURCE, GURL(kMalwareURL));
+ resource.original_url = GURL(kOriginalLandingURL);
+
+ scoped_refptr<MalwareDetails> report = new MalwareDetails(
+ contents(), resource);
+
+ scoped_ptr<const std::string> serialized(report->GetSerializedReport());
+ safe_browsing::ClientMalwareReportRequest actual;
+ actual.ParseFromString(*serialized);
+
+ safe_browsing::ClientMalwareReportRequest expected;
+ expected.set_malware_url(kMalwareURL);
+ expected.set_page_url(kLandingURL);
+ expected.set_referrer_url("");
+
+ safe_browsing::ClientMalwareReportRequest::Resource* node =
+ expected.add_nodes();
+ node->set_url(kLandingURL);
+
+ // Malware url should have originalurl as parent.
+ node = expected.add_nodes();
+ node->set_url(kMalwareURL);
+ node->set_parent(kOriginalLandingURL);
+
+ node = expected.add_nodes();
+ node->set_url(kOriginalLandingURL);
+
+ VerifyResults(actual, expected);
+}
+
+// Verify that https:// urls are dropped.
+TEST_F(MalwareDetailsTest, NotPublicUrl) {
+ controller().LoadURL(GURL(kHttpsURL), GURL(), PageTransition::TYPED);
+ SafeBrowsingService::UnsafeResource resource;
+ InitResource(&resource, ResourceType::SUB_RESOURCE, GURL(kMalwareURL));
+ scoped_refptr<MalwareDetails> report = new MalwareDetails(
+ contents(), resource);
+
+ scoped_ptr<const std::string> serialized(report->GetSerializedReport());
+ safe_browsing::ClientMalwareReportRequest actual;
+ actual.ParseFromString(*serialized);
+
+ safe_browsing::ClientMalwareReportRequest expected;
+ expected.set_malware_url(kMalwareURL); // No page_url
+ expected.set_referrer_url("");
+
+ safe_browsing::ClientMalwareReportRequest::Resource* node =
+ expected.add_nodes();
+ node->set_url(kMalwareURL); // Only one node
+
+ VerifyResults(actual, expected);
+}
diff --git a/chrome/browser/safe_browsing/protocol_manager.cc b/chrome/browser/safe_browsing/protocol_manager.cc
index d76cd7a..8e29489 100644
--- a/chrome/browser/safe_browsing/protocol_manager.cc
+++ b/chrome/browser/safe_browsing/protocol_manager.cc
@@ -16,7 +16,6 @@
#include "base/task.h"
#include "base/timer.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/safe_browsing/protocol_parser.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/common/chrome_version_info.h"
@@ -38,10 +37,36 @@ static const int kSbMaxUpdateWaitSec = 10;
// Maximum back off multiplier.
static const int kSbMaxBackOff = 8;
+// The default SBProtocolManagerFactory.
+class SBProtocolManagerFactoryImpl : public SBProtocolManagerFactory {
+ public:
+ SBProtocolManagerFactoryImpl() { }
+ virtual ~SBProtocolManagerFactoryImpl() { }
+ virtual SafeBrowsingProtocolManager* CreateProtocolManager(
+ SafeBrowsingService* sb_service,
+ const std::string& client_name,
+ const std::string& client_key,
+ const std::string& wrapped_key,
+ URLRequestContextGetter* request_context_getter,
+ const std::string& info_url_prefix,
+ const std::string& mackey_url_prefix,
+ bool disable_auto_update) {
+ return new SafeBrowsingProtocolManager(
+ sb_service, client_name, client_key, wrapped_key,
+ request_context_getter, info_url_prefix, mackey_url_prefix,
+ disable_auto_update);
+ }
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SBProtocolManagerFactoryImpl);
+};
// SafeBrowsingProtocolManager implementation ----------------------------------
-SafeBrowsingProtocolManager::SafeBrowsingProtocolManager(
+// static
+SBProtocolManagerFactory* SafeBrowsingProtocolManager::factory_ = NULL;
+
+// static
+SafeBrowsingProtocolManager* SafeBrowsingProtocolManager::Create(
SafeBrowsingService* sb_service,
const std::string& client_name,
const std::string& client_key,
@@ -49,6 +74,24 @@ SafeBrowsingProtocolManager::SafeBrowsingProtocolManager(
URLRequestContextGetter* request_context_getter,
const std::string& info_url_prefix,
const std::string& mackey_url_prefix,
+ bool disable_auto_update) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (!factory_)
+ factory_ = new SBProtocolManagerFactoryImpl();
+ return factory_->CreateProtocolManager(sb_service, client_name, client_key,
+ wrapped_key, request_context_getter,
+ info_url_prefix, mackey_url_prefix,
+ disable_auto_update);
+}
+
+SafeBrowsingProtocolManager::SafeBrowsingProtocolManager(
+ SafeBrowsingService* sb_service,
+ const std::string& client_name,
+ const std::string& client_key,
+ const std::string& wrapped_key,
+ URLRequestContextGetter* request_context_getter,
+ const std::string& http_url_prefix,
+ const std::string& https_url_prefix,
bool disable_auto_update)
: sb_service_(sb_service),
request_type_(NO_REQUEST),
@@ -65,10 +108,10 @@ SafeBrowsingProtocolManager::SafeBrowsingProtocolManager(
update_size_(0),
client_name_(client_name),
request_context_getter_(request_context_getter),
- info_url_prefix_(info_url_prefix),
- mackey_url_prefix_(mackey_url_prefix),
+ http_url_prefix_(http_url_prefix),
+ https_url_prefix_(https_url_prefix),
disable_auto_update_(disable_auto_update) {
- DCHECK(!info_url_prefix_.empty() && !mackey_url_prefix_.empty());
+ DCHECK(!http_url_prefix_.empty() && !https_url_prefix_.empty());
// Set the backoff multiplier fuzz to a random value between 0 and 1.
back_off_fuzz_ = static_cast<float>(base::RandDouble());
@@ -88,7 +131,7 @@ SafeBrowsingProtocolManager::~SafeBrowsingProtocolManager() {
hash_requests_.end());
hash_requests_.clear();
- // Delete in-progress safebrowsing reports.
+ // Delete in-progress safebrowsing reports (hits and details).
STLDeleteContainerPointers(safebrowsing_reports_.begin(),
safebrowsing_reports_.end());
safebrowsing_reports_.clear();
@@ -207,11 +250,11 @@ void SafeBrowsingProtocolManager::OnURLFetchComplete(
} else {
HandleGetHashError(Time::Now());
if (status.status() == URLRequestStatus::FAILED) {
- VLOG(1) << "SafeBrowsing GetHash request for: " << source->url()
- << " failed with os error: " << status.os_error();
+ VLOG(1) << "SafeBrowsing GetHash request for: " << source->url()
+ << " failed with os error: " << status.os_error();
} else {
- VLOG(1) << "SafeBrowsing GetHash request for: " << source->url()
- << " failed with error: " << response_code;
+ VLOG(1) << "SafeBrowsing GetHash request for: " << source->url()
+ << " failed with error: " << response_code;
}
}
@@ -588,15 +631,16 @@ void SafeBrowsingProtocolManager::OnChunkInserted() {
}
}
+// Sends a SafeBrowsing "hit" for UMA users.
void SafeBrowsingProtocolManager::ReportSafeBrowsingHit(
const GURL& malicious_url,
const GURL& page_url,
const GURL& referrer_url,
bool is_subresource,
SafeBrowsingService::UrlCheckResult threat_type) {
- GURL report_url = SafeBrowsingReportUrl(malicious_url, page_url,
- referrer_url, is_subresource,
- threat_type);
+ GURL report_url = SafeBrowsingHitUrl(malicious_url, page_url,
+ referrer_url, is_subresource,
+ threat_type);
URLFetcher* report = new URLFetcher(report_url, URLFetcher::GET, this);
report->set_load_flags(net::LOAD_DISABLE_CACHE);
report->set_request_context(request_context_getter_);
@@ -604,6 +648,21 @@ void SafeBrowsingProtocolManager::ReportSafeBrowsingHit(
safebrowsing_reports_.insert(report);
}
+// Sends malware details for users who opt-in.
+void SafeBrowsingProtocolManager::ReportMalwareDetails(
+ const std::string& report) {
+ GURL report_url = MalwareDetailsUrl();
+ URLFetcher* fetcher = new URLFetcher(report_url, URLFetcher::POST, this);
+ fetcher->set_load_flags(net::LOAD_DISABLE_CACHE);
+ fetcher->set_request_context(request_context_getter_);
+ fetcher->set_upload_data("application/octet-stream", report);
+ // Don't try too hard to send reports on failures.
+ fetcher->set_automatically_retry_on_5xx(false);
+ fetcher->Start();
+ safebrowsing_reports_.insert(fetcher);
+}
+
+
// static
std::string SafeBrowsingProtocolManager::FormatList(
const SBListChunkRanges& list, bool use_mac) {
@@ -662,7 +721,7 @@ std::string SafeBrowsingProtocolManager::ComposeUrl(
}
GURL SafeBrowsingProtocolManager::UpdateUrl(bool use_mac) const {
- std::string url = ComposeUrl(info_url_prefix_, "downloads", client_name_,
+ std::string url = ComposeUrl(http_url_prefix_, "downloads", client_name_,
version_, additional_query_);
if (use_mac) {
url.append("&wrkey=");
@@ -672,7 +731,7 @@ GURL SafeBrowsingProtocolManager::UpdateUrl(bool use_mac) const {
}
GURL SafeBrowsingProtocolManager::GetHashUrl(bool use_mac) const {
- std::string url= ComposeUrl(info_url_prefix_, "gethash", client_name_,
+ std::string url= ComposeUrl(http_url_prefix_, "gethash", client_name_,
version_, additional_query_);
if (use_mac) {
url.append("&wrkey=");
@@ -682,17 +741,18 @@ GURL SafeBrowsingProtocolManager::GetHashUrl(bool use_mac) const {
}
GURL SafeBrowsingProtocolManager::MacKeyUrl() const {
- return GURL(ComposeUrl(mackey_url_prefix_, "newkey", client_name_, version_,
+ return GURL(ComposeUrl(https_url_prefix_, "newkey", client_name_, version_,
additional_query_));
}
-GURL SafeBrowsingProtocolManager::SafeBrowsingReportUrl(
+GURL SafeBrowsingProtocolManager::SafeBrowsingHitUrl(
const GURL& malicious_url, const GURL& page_url,
const GURL& referrer_url, bool is_subresource,
SafeBrowsingService::UrlCheckResult threat_type) const {
DCHECK(threat_type == SafeBrowsingService::URL_MALWARE ||
threat_type == SafeBrowsingService::URL_PHISHING);
- std::string url = ComposeUrl(info_url_prefix_, "report", client_name_,
+ // The malware and phishing hits go over HTTP.
+ std::string url = ComposeUrl(http_url_prefix_, "report", client_name_,
version_, additional_query_);
return GURL(StringPrintf("%s&evts=%s&evtd=%s&evtr=%s&evhr=%s&evtb=%d",
url.c_str(),
@@ -704,6 +764,16 @@ GURL SafeBrowsingProtocolManager::SafeBrowsingReportUrl(
is_subresource));
}
+GURL SafeBrowsingProtocolManager::MalwareDetailsUrl() const {
+ // The malware details go over HTTPS.
+ std::string url = StringPrintf(
+ "%s/clientreport/malware?client=%s&appver=%s&pver=1.0",
+ https_url_prefix_.c_str(),
+ client_name_.c_str(),
+ version_.c_str());
+ return GURL(url);
+}
+
GURL SafeBrowsingProtocolManager::NextChunkUrl(const std::string& url) const {
std::string next_url;
if (!StartsWithASCII(url, "http://", false) &&
diff --git a/chrome/browser/safe_browsing/protocol_manager.h b/chrome/browser/safe_browsing/protocol_manager.h
index 8dea7f1..7869e0f 100644
--- a/chrome/browser/safe_browsing/protocol_manager.h
+++ b/chrome/browser/safe_browsing/protocol_manager.h
@@ -42,6 +42,25 @@ struct hash<const URLFetcher*> {
}
#endif
+class SafeBrowsingProtocolManager;
+// Interface of a factory to create ProtocolManager. Useful for tests.
+class SBProtocolManagerFactory {
+ public:
+ SBProtocolManagerFactory() {}
+ virtual ~SBProtocolManagerFactory() {}
+ virtual SafeBrowsingProtocolManager* CreateProtocolManager(
+ SafeBrowsingService* sb_service,
+ const std::string& client_name,
+ const std::string& client_key,
+ const std::string& wrapped_key,
+ URLRequestContextGetter* request_context_getter,
+ const std::string& info_url_prefix,
+ const std::string& mackey_url_prefix,
+ bool disable_auto_update) = 0;
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SBProtocolManagerFactory);
+};
+
class SafeBrowsingProtocolManager : public URLFetcher::Delegate {
FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest, TestBackOffTimes);
FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest, TestChunkStrings);
@@ -50,29 +69,36 @@ class SafeBrowsingProtocolManager : public URLFetcher::Delegate {
TestGetHashBackOffTimes);
FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest, TestMacKeyUrl);
FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest,
- TestSafeBrowsingReportUrl);
+ TestSafeBrowsingHitUrl);
+ FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest,
+ TestMalwareDetailsUrl);
FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest, TestNextChunkUrl);
FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest, TestUpdateUrl);
friend class SafeBrowsingServiceTest;
public:
- // Constructs a SafeBrowsingProtocolManager for |sb_service| that issues
- // network requests using |request_context_getter|. When |disable_auto_update|
- // is true, protocol manager won't schedule next update until
- // ForceScheduleNextUpdate is called.
- SafeBrowsingProtocolManager(SafeBrowsingService* sb_service,
- const std::string& client_name,
- const std::string& client_key,
- const std::string& wrapped_key,
- URLRequestContextGetter* request_context_getter,
- const std::string& info_url_prefix,
- const std::string& mackey_url_prefix,
- bool disable_auto_update);
virtual ~SafeBrowsingProtocolManager();
+ // Makes the passed |factory| the factory used to instantiate
+ // a SafeBrowsingService. Useful for tests.
+ static void RegisterFactory(SBProtocolManagerFactory* factory) {
+ factory_ = factory;
+ }
+
+ // Create an instance of the safe browsing service.
+ static SafeBrowsingProtocolManager* Create(
+ SafeBrowsingService* sb_service,
+ const std::string& client_name,
+ const std::string& client_key,
+ const std::string& wrapped_key,
+ URLRequestContextGetter* request_context_getter,
+ const std::string& info_url_prefix,
+ const std::string& mackey_url_prefix,
+ bool disable_auto_update);
+
// Sets up the update schedule and internal state for making periodic requests
// of the SafeBrowsing service.
- void Initialize();
+ virtual void Initialize();
// URLFetcher::Delegate interface.
virtual void OnURLFetchComplete(const URLFetcher* source,
@@ -84,14 +110,12 @@ class SafeBrowsingProtocolManager : public URLFetcher::Delegate {
// API used by the SafeBrowsingService for issuing queries. When the results
// are available, SafeBrowsingService::HandleGetHashResults is called.
- void GetFullHash(SafeBrowsingService::SafeBrowsingCheck* check,
- const std::vector<SBPrefix>& prefixes);
+ virtual void GetFullHash(SafeBrowsingService::SafeBrowsingCheck* check,
+ const std::vector<SBPrefix>& prefixes);
// Forces the start of next update after |next_update_msec| in msec.
void ForceScheduleNextUpdate(int next_update_msec);
- bool is_initial_request() const { return initial_request_; }
-
// Scheduled update callback.
void GetNextUpdate();
@@ -105,9 +129,6 @@ class SafeBrowsingProtocolManager : public URLFetcher::Delegate {
// Called after the chunks that were parsed were inserted in the database.
void OnChunkInserted();
- // The last time we received an update.
- base::Time last_update() const { return last_update_; }
-
// For UMA users we report to Google when a SafeBrowsing interstitial is shown
// to the user. We assume that the threat type is either URL_MALWARE or
// URL_PHISHING.
@@ -117,6 +138,14 @@ class SafeBrowsingProtocolManager : public URLFetcher::Delegate {
bool is_subresource,
SafeBrowsingService::UrlCheckResult threat_type);
+ // Users can opt-in on the SafeBrowsing interstitial to send detailed
+ // malware reports. |report| is the serialized report.
+ void ReportMalwareDetails(const std::string& report);
+
+ bool is_initial_request() const { return initial_request_; }
+
+ // The last time we received an update.
+ base::Time last_update() const { return last_update_; }
// Setter for additional_query_. To make sure the additional_query_ won't
// be changed in the middle of an update, caller (e.g.: SafeBrowsingService)
@@ -129,7 +158,22 @@ class SafeBrowsingProtocolManager : public URLFetcher::Delegate {
return additional_query_;
}
+ protected:
+ // Constructs a SafeBrowsingProtocolManager for |sb_service| that issues
+ // network requests using |request_context_getter|. When |disable_auto_update|
+ // is true, protocol manager won't schedule next update until
+ // ForceScheduleNextUpdate is called.
+ SafeBrowsingProtocolManager(SafeBrowsingService* sb_service,
+ const std::string& client_name,
+ const std::string& client_key,
+ const std::string& wrapped_key,
+ URLRequestContextGetter* request_context_getter,
+ const std::string& http_url_prefix,
+ const std::string& https_url_prefix,
+ bool disable_auto_update);
private:
+ friend class SBProtocolManagerFactoryImpl;
+
// Internal API for fetching information from the SafeBrowsing servers. The
// GetHash requests are higher priority since they can block user requests
// so are handled separately.
@@ -158,11 +202,14 @@ class SafeBrowsingProtocolManager : public URLFetcher::Delegate {
GURL GetHashUrl(bool use_mac) const;
// Generates new MAC client key request URL.
GURL MacKeyUrl() const;
- // Generates URL for reporting malicious pages.
- GURL SafeBrowsingReportUrl(
+ // Generates URL for reporting safe browsing hits for UMA users.
+ GURL SafeBrowsingHitUrl(
const GURL& malicious_url, const GURL& page_url, const GURL& referrer_url,
bool is_subresource,
SafeBrowsingService::UrlCheckResult threat_type) const;
+ // Generates URL for reporting malware details for users who opt-in.
+ GURL MalwareDetailsUrl() const;
+
// Composes a ChunkUrl based on input string.
GURL NextChunkUrl(const std::string& input) const;
@@ -222,6 +269,10 @@ class SafeBrowsingProtocolManager : public URLFetcher::Delegate {
void UpdateResponseTimeout();
private:
+ // The factory that controls the creation of SafeBrowsingProtocolManager.
+ // This is used by tests.
+ static SBProtocolManagerFactory* factory_;
+
// Main SafeBrowsing interface object.
SafeBrowsingService* sb_service_;
@@ -297,24 +348,26 @@ class SafeBrowsingProtocolManager : public URLFetcher::Delegate {
int update_size_;
// Track outstanding SafeBrowsing report fetchers for clean up.
+ // We add both "hit" and "detail" fetchers in this set.
std::set<const URLFetcher*> safebrowsing_reports_;
// The safe browsing client name sent in each request.
std::string client_name_;
// A string that is appended to the end of URLs for download, gethash,
- // newkey, malware report and chunk update requests.
+ // newkey, safebrowsing hits and chunk update requests.
std::string additional_query_;
// The context we use to issue network requests.
scoped_refptr<URLRequestContextGetter> request_context_getter_;
// URL prefix where browser fetches safebrowsing chunk updates, hashes, and
- // reports malware.
- std::string info_url_prefix_;
+ // reports hits to the safebrowsing list for UMA users.
+ std::string http_url_prefix_;
- // URL prefix where browser fetches MAC client key.
- std::string mackey_url_prefix_;
+ // URL prefix where browser fetches MAC client key, and reports detailed
+ // malware reports for users who opt-in.
+ std::string https_url_prefix_;
// When true, protocol manager will not start an update unless
// ForceScheduleNextUpdate() is called. This is set for testing purpose.
diff --git a/chrome/browser/safe_browsing/protocol_manager_unittest.cc b/chrome/browser/safe_browsing/protocol_manager_unittest.cc
index 6343931..fc119ff 100644
--- a/chrome/browser/safe_browsing/protocol_manager_unittest.cc
+++ b/chrome/browser/safe_browsing/protocol_manager_unittest.cc
@@ -193,7 +193,7 @@ TEST_F(SafeBrowsingProtocolManagerTest, TestUpdateUrl) {
"9g==", pm.UpdateUrl(true).spec());
}
-TEST_F(SafeBrowsingProtocolManagerTest, TestSafeBrowsingReportUrl) {
+TEST_F(SafeBrowsingProtocolManagerTest, TestSafeBrowsingHitUrl) {
SafeBrowsingProtocolManager pm(NULL, kClient, kClientKey, kWrappedKey, NULL,
kInfoUrlPrefix, kMacKeyUrlPrefix, false);
pm.version_ = kAppVer;
@@ -205,7 +205,7 @@ TEST_F(SafeBrowsingProtocolManagerTest, TestSafeBrowsingReportUrl) {
"pver=2.2&evts=malblhit&evtd=http%3A%2F%2Fmalicious.url.com%2F&"
"evtr=http%3A%2F%2Fpage.url.com%2F&evhr=http%3A%2F%2Freferrer."
"url.com%2F&evtb=1",
- pm.SafeBrowsingReportUrl(
+ pm.SafeBrowsingHitUrl(
malicious_url, page_url, referrer_url,
true, SafeBrowsingService::URL_MALWARE).spec());
@@ -215,11 +215,22 @@ TEST_F(SafeBrowsingProtocolManagerTest, TestSafeBrowsingReportUrl) {
"evtd=http%3A%2F%2Fmalicious.url.com%2F&"
"evtr=http%3A%2F%2Fpage.url.com%2F&evhr=http%3A%2F%2Freferrer."
"url.com%2F&evtb=0",
- pm.SafeBrowsingReportUrl(
+ pm.SafeBrowsingHitUrl(
malicious_url, page_url, referrer_url,
false, SafeBrowsingService::URL_PHISHING).spec());
}
+TEST_F(SafeBrowsingProtocolManagerTest, TestMalwareDetailsUrl) {
+ SafeBrowsingProtocolManager pm(NULL, kClient, kClientKey, kWrappedKey, NULL,
+ kInfoUrlPrefix, kMacKeyUrlPrefix, false);
+
+ pm.version_ = kAppVer;
+ pm.set_additional_query(kAdditionalQuery); // AdditionalQuery is not used.
+ EXPECT_EQ("https://key.prefix.com/bar/clientreport/malware?"
+ "client=unittest&appver=1.0&pver=1.0",
+ pm.MalwareDetailsUrl().spec());
+}
+
TEST_F(SafeBrowsingProtocolManagerTest, TestMacKeyUrl) {
SafeBrowsingProtocolManager pm(NULL, kClient, kClientKey, kWrappedKey, NULL,
kInfoUrlPrefix, kMacKeyUrlPrefix, false);
diff --git a/chrome/browser/safe_browsing/report.proto b/chrome/browser/safe_browsing/report.proto
new file mode 100644
index 0000000..ea4cfda
--- /dev/null
+++ b/chrome/browser/safe_browsing/report.proto
@@ -0,0 +1,91 @@
+// 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.
+//
+// Safe Browsing reporting protocol buffers.
+//
+// A ClientMalwareReportRequest is sent when a user opts-in to
+// sending detailed malware reports from the safe browsing interstitial page.
+//
+// It is a list of Resource messages, which may contain the url of a
+// resource such as the page in the address bar or any other resource
+// that was loaded for this page.
+//
+// In addition to the url, a resource can contain HTTP request and response
+// headers and bodies.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package safe_browsing;
+
+message ClientMalwareReportRequest {
+
+ message HTTPHeader {
+ required string name = 1;
+ optional string value = 2;
+ }
+
+ message HTTPRequest {
+ message FirstLine {
+ optional string verb = 1; // Also known as method, eg "GET"
+ optional string uri = 2;
+ optional string version = 3;
+ }
+
+ optional FirstLine firstline = 1;
+ repeated HTTPHeader headers = 2;
+ optional string body = 3;
+
+ // bodydigest and bodylength can be useful if the report does not
+ // contain the body itself.
+ optional string bodydigest = 4;
+ optional int32 bodylength = 5;
+ }
+
+ message HTTPResponse {
+ message FirstLine {
+ optional int32 code = 1;
+ optional string reason = 2;
+ optional string version = 3;
+ }
+
+ optional FirstLine firstline = 1;
+ repeated HTTPHeader headers = 2;
+ optional string body = 3;
+
+ // bodydigest and bodylength can be useful if the report does not
+ // contain the body itself.
+ optional string bodydigest = 4;
+ optional int32 bodylength = 5;
+ optional string remote_ip = 6;
+ }
+
+ message Resource {
+ optional string url = 1;
+
+ // URL of the parent frame.
+ optional string parent = 2;
+
+ // Tag that was used to include this resource, eg "iframe"
+ optional string tag_name = 3;
+
+ optional HTTPRequest request = 4;
+ optional HTTPResponse response = 5;
+
+ // A list of children. The order of the children in this list is
+ // significant. The |parent| field for child nodes can be derived
+ // from this, but this allows us to be more flexible.
+ repeated string children = 6;
+ }
+
+ // URL of the resource that matches the safe browsing list.
+ optional string malware_url = 1;
+
+ // URL of the page in the address bar.
+ optional string page_url = 2;
+
+ optional string referrer_url = 3;
+ repeated Resource nodes = 4;
+}
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
index 2601023..d683d97 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
@@ -11,7 +11,7 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/i18n/rtl.h"
-#include "base/singleton.h"
+#include "base/lazy_instance.h"
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
@@ -20,12 +20,16 @@
#include "chrome/browser/dom_ui/new_tab_ui.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/safe_browsing/malware_details.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/jstemplate_builder.h"
+#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "grit/browser_resources.h"
#include "grit/generated_resources.h"
@@ -72,6 +76,9 @@ static const char* const kTakeMeBackCommand = "takeMeBack";
// static
SafeBrowsingBlockingPageFactory* SafeBrowsingBlockingPage::factory_ = NULL;
+static base::LazyInstance<SafeBrowsingBlockingPage::UnsafeResourceMap>
+ g_unsafe_resource_map(base::LINKER_INITIALIZED);
+
// The default SafeBrowsingBlockingPageFactory. Global, made a singleton so we
// don't leak it.
class SafeBrowsingBlockingPageFactoryImpl
@@ -86,13 +93,17 @@ class SafeBrowsingBlockingPageFactoryImpl
}
private:
- friend struct DefaultSingletonTraits<SafeBrowsingBlockingPageFactoryImpl>;
+ friend struct base::DefaultLazyInstanceTraits<
+ SafeBrowsingBlockingPageFactoryImpl>;
SafeBrowsingBlockingPageFactoryImpl() { }
DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPageFactoryImpl);
};
+static base::LazyInstance<SafeBrowsingBlockingPageFactoryImpl>
+ g_safe_browsing_blocking_page_factory_impl(base::LINKER_INITIALIZED);
+
SafeBrowsingBlockingPage::SafeBrowsingBlockingPage(
SafeBrowsingService* sb_service,
TabContents* tab_contents,
@@ -102,7 +113,8 @@ SafeBrowsingBlockingPage::SafeBrowsingBlockingPage(
unsafe_resources[0].url),
sb_service_(sb_service),
is_main_frame_(IsMainPage(unsafe_resources)),
- unsafe_resources_(unsafe_resources) {
+ unsafe_resources_(unsafe_resources),
+ malware_details_(NULL) {
RecordUserAction(SHOW);
if (!is_main_frame_) {
navigation_entry_index_to_remove_ =
@@ -110,6 +122,23 @@ SafeBrowsingBlockingPage::SafeBrowsingBlockingPage(
} else {
navigation_entry_index_to_remove_ = -1;
}
+
+ // Start computing malware details. They will be sent only
+ // if the user opts-in on the blocking page later.
+ // If there's more than one malicious resources, it means the user
+ // clicked through the first warning, so we don't prepare additional
+ // reports.
+ if (unsafe_resources.size() == 1 &&
+ unsafe_resources[0].threat_type == SafeBrowsingService::URL_MALWARE &&
+ malware_details_ == NULL &&
+ CanShowMalwareDetailsOption()) {
+ malware_details_ = new MalwareDetails(tab(), unsafe_resources[0]);
+ }
+}
+
+bool SafeBrowsingBlockingPage::CanShowMalwareDetailsOption() {
+ return (!tab()->profile()->IsOffTheRecord() &&
+ tab()->GetURL().SchemeIs(chrome::kHttpScheme));
}
SafeBrowsingBlockingPage::~SafeBrowsingBlockingPage() {
@@ -277,10 +306,6 @@ void SafeBrowsingBlockingPage::PopulateMalwareStringDictionary(
strings->SetString("back_button",
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_BACK_BUTTON));
- strings->SetString("more_info_button",
- l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_MORE_INFO_BUTTON));
- strings->SetString("less_info_button",
- l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_LESS_INFO_BUTTON));
strings->SetString("proceed_link",
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_PROCEED_LINK));
strings->SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
@@ -288,6 +313,13 @@ void SafeBrowsingBlockingPage::PopulateMalwareStringDictionary(
void SafeBrowsingBlockingPage::PopulatePhishingStringDictionary(
DictionaryValue* strings) {
+ std::wstring proceed_link = StringPrintf(
+ kPLinkHtml,
+ l10n_util::GetString(IDS_SAFE_BROWSING_PHISHING_PROCEED_LINK).c_str());
+ std::wstring description3 = l10n_util::GetStringF(
+ IDS_SAFE_BROWSING_PHISHING_DESCRIPTION3,
+ proceed_link);
+
PopulateStringDictionary(
strings,
l10n_util::GetString(IDS_SAFE_BROWSING_PHISHING_TITLE),
@@ -295,10 +327,8 @@ void SafeBrowsingBlockingPage::PopulatePhishingStringDictionary(
l10n_util::GetStringF(IDS_SAFE_BROWSING_PHISHING_DESCRIPTION1,
UTF8ToWide(url().host())),
l10n_util::GetString(IDS_SAFE_BROWSING_PHISHING_DESCRIPTION2),
- L"");
+ description3);
- strings->SetString("continue_button",
- l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_PROCEED_BUTTON));
strings->SetString("back_button",
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_BACK_BUTTON));
strings->SetString("report_error",
@@ -390,6 +420,7 @@ void SafeBrowsingBlockingPage::CommandReceived(const std::string& cmd) {
void SafeBrowsingBlockingPage::Proceed() {
RecordUserAction(PROCEED);
+ FinishMalwareDetails(); // Send the malware details, if we opted to.
NotifySafeBrowsingService(sb_service_, unsafe_resources_, true);
@@ -427,6 +458,7 @@ void SafeBrowsingBlockingPage::DontProceed() {
}
RecordUserAction(DONT_PROCEED);
+ FinishMalwareDetails(); // Send the malware details, if we opted to.
NotifySafeBrowsingService(sb_service_, unsafe_resources_, false);
@@ -492,6 +524,25 @@ void SafeBrowsingBlockingPage::RecordUserAction(BlockingPageEvent event) {
UserMetrics::RecordComputedAction(action);
}
+void SafeBrowsingBlockingPage::FinishMalwareDetails() {
+ if (malware_details_ == NULL)
+ return; // Not all interstitials have malware details (eg phishing).
+
+ const PrefService::Preference* pref =
+ tab()->profile()->GetPrefs()->FindPreference(
+ prefs::kSafeBrowsingReportingEnabled);
+
+ bool value;
+ if (pref && pref->GetValue()->GetAsBoolean(&value) && value) {
+ // Give the details object to the service class, so it can send it.
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(
+ sb_service_, &SafeBrowsingService::ReportMalwareDetails,
+ malware_details_));
+ }
+}
+
// static
void SafeBrowsingBlockingPage::NotifySafeBrowsingService(
SafeBrowsingService* sb_service,
@@ -507,7 +558,7 @@ void SafeBrowsingBlockingPage::NotifySafeBrowsingService(
// static
SafeBrowsingBlockingPage::UnsafeResourceMap*
SafeBrowsingBlockingPage::GetUnsafeResourcesMap() {
- return Singleton<UnsafeResourceMap>::get();
+ return g_unsafe_resource_map.Pointer();
}
// static
@@ -536,7 +587,7 @@ void SafeBrowsingBlockingPage::ShowBlockingPage(
// Set up the factory if this has not been done already (tests do that
// before this method is called).
if (!factory_)
- factory_ = Singleton<SafeBrowsingBlockingPageFactoryImpl>::get();
+ factory_ = g_safe_browsing_blocking_page_factory_impl.Pointer();
SafeBrowsingBlockingPage* blocking_page =
factory_->CreateSafeBrowsingPage(sb_service, tab_contents, resources);
blocking_page->Show();
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.h b/chrome/browser/safe_browsing/safe_browsing_blocking_page.h
index 7e7cb22..cfe2358 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.h
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.h
@@ -39,10 +39,14 @@
class DictionaryValue;
class MessageLoop;
class SafeBrowsingBlockingPageFactory;
+class MalwareDetails;
class TabContents;
class SafeBrowsingBlockingPage : public InterstitialPage {
public:
+ typedef std::vector<SafeBrowsingService::UnsafeResource> UnsafeResourceList;
+ typedef std::map<TabContents*, UnsafeResourceList> UnsafeResourceMap;
+
virtual ~SafeBrowsingBlockingPage();
// Shows a blocking page warning the user about phishing/malware for a
@@ -65,8 +69,6 @@ class SafeBrowsingBlockingPage : public InterstitialPage {
virtual void Proceed();
virtual void DontProceed();
- typedef std::vector<SafeBrowsingService::UnsafeResource> UnsafeResourceList;
-
protected:
friend class SafeBrowsingBlockingPageTest;
@@ -104,10 +106,19 @@ class SafeBrowsingBlockingPage : public InterstitialPage {
// SBInterstitial[Phishing|Malware|Multiple][Show|Proceed|DontProceed].
void RecordUserAction(BlockingPageEvent event);
+ // See if we should even show the malware details option. For example, we
+ // don't show it in incognito mode.
+ bool CanShowMalwareDetailsOption();
+
+ // Called when the insterstitial is going away. If there is a
+ // pending malware details object, we look at the user's
+ // preferences, and if the option to send malware details is
+ // enabled, the report is scheduled to be sent on the |sb_service_|.
+ void FinishMalwareDetails();
+
// A list of SafeBrowsingService::UnsafeResource for a tab that the user
// should be warned about. They are queued when displaying more than one
// interstitial at a time.
- typedef std::map<TabContents*, UnsafeResourceList> UnsafeResourceMap;
static UnsafeResourceMap* GetUnsafeResourcesMap();
// Notifies the SafeBrowsingService on the IO thread whether to proceed or not
@@ -136,6 +147,11 @@ class SafeBrowsingBlockingPage : public InterstitialPage {
// The list of unsafe resources this page is warning about.
UnsafeResourceList unsafe_resources_;
+ // A MalwareDetails object that we start generating when the
+ // blocking page is shown. The object will be sent when the warning
+ // is gone (if the user enables the feature).
+ scoped_refptr<MalwareDetails> malware_details_;
+
// The factory used to instanciate SafeBrowsingBlockingPage objects.
// Usefull for tests, so they can provide their own implementation of
// SafeBrowsingBlockingPage.
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
index fa30068..19eae29 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
@@ -9,13 +9,17 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+#include "chrome/browser/safe_browsing/malware_details.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
@@ -32,7 +36,7 @@ class FakeSafeBrowsingService : public SafeBrowsingService {
// Otherwise it returns false, and "client" is called asynchronously with the
// result when it is ready.
// Overrides SafeBrowsingService::CheckUrl.
- virtual bool CheckUrl(const GURL& gurl, Client* client) {
+ virtual bool CheckBrowseUrl(const GURL& gurl, Client* client) {
const std::string& url = gurl.spec();
if (badurls[url] == URL_SAFE)
return true;
@@ -45,13 +49,33 @@ class FakeSafeBrowsingService : public SafeBrowsingService {
}
void OnCheckDone(std::string url, Client* client) {
- client->OnUrlCheckResult(GURL(url), badurls[url]);
+ client->OnSafeBrowsingResult(GURL(url), badurls[url]);
}
void AddURLResult(const GURL& url, UrlCheckResult checkresult) {
badurls[url.spec()] = checkresult;
}
+ virtual void ReportMalwareDetails(scoped_refptr<MalwareDetails> details) {
+ details_.push_back(details);
+ // Notify the UI thread, that we got a report.
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(this,
+ &FakeSafeBrowsingService::OnMalwareDetailsDone));
+ }
+
+ void OnMalwareDetailsDone() {
+ EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ MessageLoopForUI::current()->Quit();
+ }
+
+ std::list<scoped_refptr<MalwareDetails> >* GetDetails() {
+ return &details_;
+ }
+
+ std::list<scoped_refptr<MalwareDetails> > details_;
+
+
private:
base::hash_map<std::string, UrlCheckResult> badurls;
};
@@ -89,8 +113,8 @@ class SafeBrowsingBlockingPageTest : public InProcessBrowserTest,
}
// SafeBrowsingService::Client implementation.
- virtual void OnUrlCheckResult(const GURL& url,
- SafeBrowsingService::UrlCheckResult result) {
+ virtual void OnSafeBrowsingResult(
+ const GURL& url, SafeBrowsingService::UrlCheckResult result) {
}
virtual void OnBlockingPageComplete(bool proceed) {
}
@@ -102,7 +126,7 @@ class SafeBrowsingBlockingPageTest : public InProcessBrowserTest,
g_browser_process->resource_dispatcher_host()->
safe_browsing_service());
- ASSERT_TRUE(service != NULL);
+ ASSERT_TRUE(service);
service->AddURLResult(url, checkresult);
}
@@ -141,6 +165,17 @@ class SafeBrowsingBlockingPageTest : public InProcessBrowserTest,
ui_test_utils::WaitForNavigation(controller);
}
+ void AssertReportSent() {
+ // When a report is scheduled in the IO thread we should get notified.
+ ui_test_utils::RunMessageLoop();
+
+ FakeSafeBrowsingService* service =
+ static_cast<FakeSafeBrowsingService*>(
+ g_browser_process->resource_dispatcher_host()->
+ safe_browsing_service());
+ ASSERT_EQ(1u, service->GetDetails()->size());
+ }
+
private:
TestSafeBrowsingServiceFactory factory;
@@ -258,4 +293,25 @@ IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest, MalwareIframeProceed) {
EXPECT_EQ(url, browser()->GetSelectedTabContents()->GetURL());
}
+IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageTest,
+ MalwareIframeReportDetails) {
+ // Enable reporting of malware details.
+ browser()->GetProfile()->GetPrefs()->SetBoolean(
+ prefs::kSafeBrowsingReportingEnabled, true);
+ EXPECT_TRUE(browser()->GetProfile()->GetPrefs()->GetBoolean(
+ prefs::kSafeBrowsingReportingEnabled));
+
+ GURL url = test_server()->GetURL(kMalwarePage);
+ GURL iframe_url = test_server()->GetURL(kMalwareIframe);
+ AddURLResult(iframe_url, SafeBrowsingService::URL_MALWARE);
+
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ SendCommand("\"proceed\""); // Simulate the user clicking "back"
+ AssertNoInterstitial(); // Assert the interstitial is gone
+
+ EXPECT_EQ(url, browser()->GetSelectedTabContents()->GetURL());
+ AssertReportSent();
+}
+
} // namespace
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_unittest.cc
index 60f1043..195f5c0 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_unittest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_unittest.cc
@@ -5,9 +5,13 @@
#include "chrome/browser/renderer_host/test/test_render_view_host.h"
#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/safe_browsing/malware_details.h"
#include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/test_tab_contents.h"
+#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/render_messages_params.h"
@@ -32,6 +36,20 @@ class TestSafeBrowsingBlockingPage : public SafeBrowsingBlockingPage {
}
};
+class TestSafeBrowsingService: public SafeBrowsingService {
+ public:
+ virtual ~TestSafeBrowsingService() {}
+ virtual void ReportMalwareDetails(scoped_refptr<MalwareDetails> details) {
+ details_.push_back(details);
+ }
+
+ std::list<scoped_refptr<MalwareDetails> >* GetDetails() {
+ return &details_;
+ }
+
+ std::list<scoped_refptr<MalwareDetails> > details_;
+};
+
class TestSafeBrowsingBlockingPageFactory
: public SafeBrowsingBlockingPageFactory {
public:
@@ -61,7 +79,7 @@ class SafeBrowsingBlockingPageTest : public RenderViewHostTestHarness,
: ui_thread_(BrowserThread::UI, MessageLoop::current()),
io_thread_(BrowserThread::IO, MessageLoop::current()) {
ResetUserResponse();
- service_ = SafeBrowsingService::CreateSafeBrowsingService();
+ service_ = new TestSafeBrowsingService();
}
virtual void SetUp() {
@@ -128,6 +146,8 @@ class SafeBrowsingBlockingPageTest : public RenderViewHostTestHarness,
MessageLoop::current()->RunAllPending();
}
+ scoped_refptr<TestSafeBrowsingService> service_;
+
private:
void InitResource(SafeBrowsingService::UnsafeResource* resource,
ResourceType::Type resource_type,
@@ -141,7 +161,6 @@ class SafeBrowsingBlockingPageTest : public RenderViewHostTestHarness,
}
UserResponse user_response_;
- scoped_refptr<SafeBrowsingService> service_;
TestSafeBrowsingBlockingPageFactory factory_;
BrowserThread ui_thread_;
BrowserThread io_thread_;
@@ -149,9 +168,14 @@ class SafeBrowsingBlockingPageTest : public RenderViewHostTestHarness,
// Tests showing a blocking page for a malware page and not proceeding.
TEST_F(SafeBrowsingBlockingPageTest, MalwarePageDontProceed) {
+ // Enable malware details.
+ contents()->profile()->GetPrefs()->SetBoolean(
+ prefs::kSafeBrowsingReportingEnabled, true);
+
// Start a load.
controller().LoadURL(GURL(kBadURL), GURL(), PageTransition::TYPED);
+
// Simulate the load causing a safe browsing interstitial to be shown.
ShowInterstitial(ResourceType::MAIN_FRAME, kBadURL);
SafeBrowsingBlockingPage* sb_interstitial = GetSafeBrowsingBlockingPage();
@@ -168,10 +192,18 @@ TEST_F(SafeBrowsingBlockingPageTest, MalwarePageDontProceed) {
// We did not proceed, the pending entry should be gone.
EXPECT_FALSE(controller().pending_entry());
+
+ // A report should have been sent.
+ EXPECT_EQ(1u, service_->GetDetails()->size());
+ service_->GetDetails()->clear();
}
// Tests showing a blocking page for a malware page and then proceeding.
TEST_F(SafeBrowsingBlockingPageTest, MalwarePageProceed) {
+ // Enable malware reports.
+ contents()->profile()->GetPrefs()->SetBoolean(
+ prefs::kSafeBrowsingReportingEnabled, true);
+
// Start a load.
controller().LoadURL(GURL(kBadURL), GURL(), PageTransition::TYPED);
@@ -189,11 +221,19 @@ TEST_F(SafeBrowsingBlockingPageTest, MalwarePageProceed) {
Navigate(kBadURL, 1);
// The interstitial should be gone now.
ASSERT_FALSE(InterstitialPage::GetInterstitialPage(contents()));
+
+ // A report should have been sent.
+ EXPECT_EQ(1u, service_->GetDetails()->size());
+ service_->GetDetails()->clear();
}
// Tests showing a blocking page for a page that contains malware subresources
// and not proceeding.
TEST_F(SafeBrowsingBlockingPageTest, PageWithMalwareResourceDontProceed) {
+ // Enable malware reports.
+ contents()->profile()->GetPrefs()->SetBoolean(
+ prefs::kSafeBrowsingReportingEnabled, true);
+
// Navigate somewhere.
Navigate(kGoogleURL, 1);
@@ -215,11 +255,19 @@ TEST_F(SafeBrowsingBlockingPageTest, PageWithMalwareResourceDontProceed) {
// have been removed from the navigation controller.
ASSERT_EQ(1, controller().entry_count());
EXPECT_EQ(kGoogleURL, controller().GetActiveEntry()->url().spec());
+
+ // A report should have been sent.
+ EXPECT_EQ(1u, service_->GetDetails()->size());
+ service_->GetDetails()->clear();
}
// Tests showing a blocking page for a page that contains malware subresources
// and proceeding.
TEST_F(SafeBrowsingBlockingPageTest, PageWithMalwareResourceProceed) {
+ // Enable malware reports.
+ contents()->profile()->GetPrefs()->SetBoolean(
+ prefs::kSafeBrowsingReportingEnabled, true);
+
// Navigate somewhere.
Navigate(kGoodURL, 1);
@@ -237,6 +285,10 @@ TEST_F(SafeBrowsingBlockingPageTest, PageWithMalwareResourceProceed) {
// We did proceed, we should be back to showing the page.
ASSERT_EQ(1, controller().entry_count());
EXPECT_EQ(kGoodURL, controller().GetActiveEntry()->url().spec());
+
+ // A report should have been sent.
+ EXPECT_EQ(1u, service_->GetDetails()->size());
+ service_->GetDetails()->clear();
}
// Tests showing a blocking page for a page that contains multiple malware
@@ -244,6 +296,10 @@ TEST_F(SafeBrowsingBlockingPageTest, PageWithMalwareResourceProceed) {
// subresources (which trigger queued interstitial pages) do not break anything.
TEST_F(SafeBrowsingBlockingPageTest,
PageWithMultipleMalwareResourceDontProceed) {
+ // Enable malware reports.
+ contents()->profile()->GetPrefs()->SetBoolean(
+ prefs::kSafeBrowsingReportingEnabled, true);
+
// Navigate somewhere.
Navigate(kGoogleURL, 1);
@@ -270,12 +326,20 @@ TEST_F(SafeBrowsingBlockingPageTest,
// have been removed from the navigation controller.
ASSERT_EQ(1, controller().entry_count());
EXPECT_EQ(kGoogleURL, controller().GetActiveEntry()->url().spec());
+
+ // A report should have been sent.
+ EXPECT_EQ(1u, service_->GetDetails()->size());
+ service_->GetDetails()->clear();
}
// Tests showing a blocking page for a page that contains multiple malware
// subresources and proceeding through the first interstitial, but not the next.
TEST_F(SafeBrowsingBlockingPageTest,
PageWithMultipleMalwareResourceProceedThenDontProceed) {
+ // Enable malware reports.
+ contents()->profile()->GetPrefs()->SetBoolean(
+ prefs::kSafeBrowsingReportingEnabled, true);
+
// Navigate somewhere.
Navigate(kGoogleURL, 1);
@@ -297,6 +361,10 @@ TEST_F(SafeBrowsingBlockingPageTest,
ProceedThroughInterstitial(sb_interstitial);
EXPECT_EQ(OK, user_response());
+ // A report should have been sent.
+ EXPECT_EQ(1u, service_->GetDetails()->size());
+ service_->GetDetails()->clear();
+
ResetUserResponse();
// We should land to a 2nd interstitial (aggregating all the malware resources
@@ -313,11 +381,20 @@ TEST_F(SafeBrowsingBlockingPageTest,
// have been removed from the navigation controller.
ASSERT_EQ(1, controller().entry_count());
EXPECT_EQ(kGoogleURL, controller().GetActiveEntry()->url().spec());
+
+ // No report should have been sent -- we don't create a report the
+ // second time.
+ EXPECT_EQ(0u, service_->GetDetails()->size());
+ service_->GetDetails()->clear();
}
// Tests showing a blocking page for a page that contains multiple malware
// subresources and proceeding through the multiple interstitials.
TEST_F(SafeBrowsingBlockingPageTest, PageWithMultipleMalwareResourceProceed) {
+ // Enable malware reports.
+ contents()->profile()->GetPrefs()->SetBoolean(
+ prefs::kSafeBrowsingReportingEnabled, true);
+
// Navigate somewhere else.
Navigate(kGoodURL, 1);
@@ -336,6 +413,10 @@ TEST_F(SafeBrowsingBlockingPageTest, PageWithMultipleMalwareResourceProceed) {
ProceedThroughInterstitial(sb_interstitial);
EXPECT_EQ(OK, user_response());
+ // A report should have been sent.
+ EXPECT_EQ(1u, service_->GetDetails()->size());
+ service_->GetDetails()->clear();
+
ResetUserResponse();
// We should land to a 2nd interstitial (aggregating all the malware resources
@@ -350,11 +431,20 @@ TEST_F(SafeBrowsingBlockingPageTest, PageWithMultipleMalwareResourceProceed) {
// We did proceed, we should be back to the initial page.
ASSERT_EQ(1, controller().entry_count());
EXPECT_EQ(kGoodURL, controller().GetActiveEntry()->url().spec());
+
+ // No report should have been sent -- we don't create a report the
+ // second time.
+ EXPECT_EQ(0u, service_->GetDetails()->size());
+ service_->GetDetails()->clear();
}
// Tests showing a blocking page then navigating back and forth to make sure the
// controller entries are OK. http://crbug.com/17627
TEST_F(SafeBrowsingBlockingPageTest, NavigatingBackAndForth) {
+ // Enable malware reports.
+ contents()->profile()->GetPrefs()->SetBoolean(
+ prefs::kSafeBrowsingReportingEnabled, true);
+
// Navigate somewhere.
Navigate(kGoodURL, 1);
@@ -388,11 +478,19 @@ TEST_F(SafeBrowsingBlockingPageTest, NavigatingBackAndForth) {
ASSERT_FALSE(sb_interstitial);
ASSERT_EQ(2, controller().entry_count());
EXPECT_EQ(kBadURL, controller().GetActiveEntry()->url().spec());
+
+ // Two reports should have been sent.
+ EXPECT_EQ(2u, service_->GetDetails()->size());
+ service_->GetDetails()->clear();
}
// Tests that calling "don't proceed" after "proceed" has been called doesn't
// cause problems. http://crbug.com/30079
TEST_F(SafeBrowsingBlockingPageTest, ProceedThenDontProceed) {
+ // Enable malware reports.
+ contents()->profile()->GetPrefs()->SetBoolean(
+ prefs::kSafeBrowsingReportingEnabled, true);
+
// Start a load.
controller().LoadURL(GURL(kBadURL), GURL(), PageTransition::TYPED);
@@ -414,4 +512,39 @@ TEST_F(SafeBrowsingBlockingPageTest, ProceedThenDontProceed) {
// The interstitial should be gone.
EXPECT_EQ(OK, user_response());
EXPECT_FALSE(GetSafeBrowsingBlockingPage());
+
+ // Only one report should have been sent.
+ EXPECT_EQ(1u, service_->GetDetails()->size());
+ service_->GetDetails()->clear();
+}
+
+// Tests showing a blocking page for a malware page with reports disabled.
+TEST_F(SafeBrowsingBlockingPageTest, MalwareReportsDisabled) {
+ // Disable malware reports.
+ contents()->profile()->GetPrefs()->SetBoolean(
+ prefs::kSafeBrowsingReportingEnabled, false);
+
+ // Start a load.
+ controller().LoadURL(GURL(kBadURL), GURL(), PageTransition::TYPED);
+
+ // Simulate the load causing a safe browsing interstitial to be shown.
+ ShowInterstitial(ResourceType::MAIN_FRAME, kBadURL);
+ SafeBrowsingBlockingPage* sb_interstitial = GetSafeBrowsingBlockingPage();
+ ASSERT_TRUE(sb_interstitial);
+
+ MessageLoop::current()->RunAllPending();
+
+ // Simulate the user clicking "don't proceed".
+ DontProceedThroughInterstitial(sb_interstitial);
+
+ // The interstitial should be gone.
+ EXPECT_EQ(CANCEL, user_response());
+ EXPECT_FALSE(GetSafeBrowsingBlockingPage());
+
+ // We did not proceed, the pending entry should be gone.
+ EXPECT_FALSE(controller().pending_entry());
+
+ // No report should have been sent.
+ EXPECT_EQ(0u, service_->GetDetails()->size());
+ service_->GetDetails()->clear();
}
diff --git a/chrome/browser/safe_browsing/safe_browsing_database.cc b/chrome/browser/safe_browsing/safe_browsing_database.cc
index e741c60..9b4c57e 100644
--- a/chrome/browser/safe_browsing/safe_browsing_database.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_database.cc
@@ -14,12 +14,18 @@
#include "chrome/browser/safe_browsing/bloom_filter.h"
#include "chrome/browser/safe_browsing/safe_browsing_store_file.h"
#include "chrome/browser/safe_browsing/safe_browsing_store_sqlite.h"
+#include "chrome/browser/safe_browsing/safe_browsing_util.h"
#include "googleurl/src/gurl.h"
namespace {
// Filename suffix for the bloom filter.
const FilePath::CharType kBloomFilterFile[] = FILE_PATH_LITERAL(" Filter 2");
+// Filename suffix for download store.
+const FilePath::CharType kDownloadDBFile[] = FILE_PATH_LITERAL(" Download");
+// Filename suffix for browse store.
+// TODO(lzheng): change to a better name when we change the file format.
+const FilePath::CharType kBrowseDBFile[] = FILE_PATH_LITERAL(" Bloom");
// The maximum staleness for a cached entry.
const int kMaxStalenessMinutes = 45;
@@ -27,15 +33,31 @@ const int kMaxStalenessMinutes = 45;
// To save space, the incoming |chunk_id| and |list_id| are combined
// into an |encoded_chunk_id| for storage by shifting the |list_id|
// into the low-order bits. These functions decode that information.
-int DecodeListId(const int encoded_chunk_id) {
+// TODO(lzheng): It was reasonable when database is saved in sqlite, but
+// there should be better ways to save chunk_id and list_id after we use
+// SafeBrowsingStoreFile.
+int GetListIdBit(const int encoded_chunk_id) {
return encoded_chunk_id & 1;
}
int DecodeChunkId(int encoded_chunk_id) {
return encoded_chunk_id >> 1;
}
-int EncodeChunkId(int chunk, int list_id) {
- DCHECK(list_id == 0 || list_id == 1);
- return chunk << 1 | list_id;
+int EncodeChunkId(const int chunk, const int list_id) {
+ DCHECK_NE(list_id, safe_browsing_util::INVALID);
+ return chunk << 1 | list_id % 2;
+}
+
+// Get the prefix for download url.
+void GetDownloadUrlPrefix(const GURL& url, SBPrefix* prefix) {
+ std::string hostname;
+ std::string path;
+ std::string query;
+ safe_browsing_util::CanonicalizeUrl(url, &hostname, &path, &query);
+
+ SBFullHash full_hash;
+ base::SHA256HashString(hostname + path + query, &full_hash,
+ sizeof(full_hash));
+ *prefix = full_hash.prefix;
}
// Generate the set of prefixes to check for |url|.
@@ -44,7 +66,7 @@ int EncodeChunkId(int chunk, int list_id) {
// does an early exit on match. Since match should be the infrequent
// case (phishing or malware found), consider combining this function
// with that one.
-void PrefixesToCheck(const GURL& url, std::vector<SBPrefix>* prefixes) {
+void BrowsePrefixesToCheck(const GURL& url, std::vector<SBPrefix>* prefixes) {
std::vector<std::string> hosts;
if (url.HostIsIPAddress()) {
hosts.push_back(url.host());
@@ -59,7 +81,7 @@ void PrefixesToCheck(const GURL& url, std::vector<SBPrefix>* prefixes) {
for (size_t j = 0; j < paths.size(); ++j) {
SBFullHash full_hash;
base::SHA256HashString(hosts[i] + paths[j], &full_hash,
- sizeof(SBFullHash));
+ sizeof(full_hash));
prefixes->push_back(full_hash.prefix);
}
}
@@ -73,10 +95,10 @@ void PrefixesToCheck(const GURL& url, std::vector<SBPrefix>* prefixes) {
//
// For efficiency reasons the code walks |prefix_hits| and
// |full_hashes| in parallel, so they must be sorted by prefix.
-void GetCachedFullHashes(const std::vector<SBPrefix>& prefix_hits,
- const std::vector<SBAddFullHash>& full_hashes,
- std::vector<SBFullHashResult>* full_hits,
- base::Time last_update) {
+void GetCachedFullHashesForBrowse(const std::vector<SBPrefix>& prefix_hits,
+ const std::vector<SBAddFullHash>& full_hashes,
+ std::vector<SBFullHashResult>* full_hits,
+ base::Time last_update) {
const base::Time expire_time =
base::Time::Now() - base::TimeDelta::FromMinutes(kMaxStalenessMinutes);
@@ -92,8 +114,11 @@ void GetCachedFullHashes(const std::vector<SBPrefix>& prefix_hits,
if (expire_time < last_update ||
expire_time.ToTimeT() < hiter->received) {
SBFullHashResult result;
- const int list_id = DecodeListId(hiter->chunk_id);
- result.list_name = safe_browsing_util::GetListName(list_id);
+ const int list_bit = GetListIdBit(hiter->chunk_id);
+ DCHECK(list_bit == safe_browsing_util::MALWARE ||
+ list_bit == safe_browsing_util::PHISH);
+ if (!safe_browsing_util::GetListName(list_bit, &result.list_name))
+ continue;
result.add_chunk_id = DecodeChunkId(hiter->chunk_id);
result.hash = hiter->full_hash;
full_hits->push_back(result);
@@ -105,26 +130,47 @@ void GetCachedFullHashes(const std::vector<SBPrefix>& prefix_hits,
}
}
-// Helper for |UpdateStarted()|. Separates |chunks| into malware and
-// phishing vectors, and converts the results into range strings.
-void GetChunkIds(const std::vector<int>& chunks,
- std::string* malware_list, std::string* phishing_list) {
- std::vector<int> malware_chunks;
- std::vector<int> phishing_chunks;
+void GetChunkRanges(const std::vector<int>& chunks,
+ std::string* list0,
+ std::string* list1) {
+ std::vector<int> chunks0;
+ std::vector<int> chunks1;
for (std::vector<int>::const_iterator iter = chunks.begin();
iter != chunks.end(); ++iter) {
- if (safe_browsing_util::MALWARE == DecodeListId(*iter)) {
- malware_chunks.push_back(DecodeChunkId(*iter));
- } else if (safe_browsing_util::PHISH == DecodeListId(*iter)) {
- phishing_chunks.push_back(DecodeChunkId(*iter));
+ int mod_list_id = GetListIdBit(*iter);
+ if (0 == mod_list_id) {
+ chunks0.push_back(DecodeChunkId(*iter));
} else {
- NOTREACHED();
+ DCHECK_EQ(1, mod_list_id);
+ chunks1.push_back(DecodeChunkId(*iter));
}
}
- ChunksToRangeString(malware_chunks, malware_list);
- ChunksToRangeString(phishing_chunks, phishing_list);
+ ChunksToRangeString(chunks0, list0);
+ ChunksToRangeString(chunks1, list1);
+}
+
+// Helper function to create chunk range lists for Browse related
+// lists.
+void UpdateChunkRanges(const std::vector<int>& add_chunks,
+ const std::vector<int>& sub_chunks,
+ const std::string& list_name0,
+ const std::string& list_name1,
+ std::vector<SBListChunkRanges>* lists) {
+ DCHECK_EQ(safe_browsing_util::GetListId(list_name0) % 2, 0);
+ DCHECK_EQ(safe_browsing_util::GetListId(list_name1) % 2, 1);
+ DCHECK_NE(safe_browsing_util::GetListId(list_name0),
+ safe_browsing_util::INVALID);
+ DCHECK_NE(safe_browsing_util::GetListId(list_name1),
+ safe_browsing_util::INVALID);
+
+ SBListChunkRanges chunkrange0(list_name0);
+ SBListChunkRanges chunkrange1(list_name1);
+ GetChunkRanges(add_chunks, &chunkrange0.adds, &chunkrange1.adds);
+ GetChunkRanges(sub_chunks, &chunkrange0.subs, &chunkrange1.subs);
+ lists->push_back(chunkrange0);
+ lists->push_back(chunkrange1);
}
// Order |SBAddFullHash| on the prefix part. |SBAddPrefixLess()| from
@@ -135,51 +181,106 @@ bool SBAddFullHashPrefixLess(const SBAddFullHash& a, const SBAddFullHash& b) {
} // namespace
-// Factory method.
+// The default SafeBrowsingDatabaseFactory.
+class SafeBrowsingDatabaseFactoryImpl : public SafeBrowsingDatabaseFactory {
+ public:
+ virtual SafeBrowsingDatabase* CreateSafeBrowsingDatabase(
+ bool enable_download_protection) {
+ if (enable_download_protection) {
+ // Create database with browse url store and download store.
+ return new SafeBrowsingDatabaseNew(new SafeBrowsingStoreFile,
+ new SafeBrowsingStoreFile);
+ }
+ // Create database with only browse url store.
+ return new SafeBrowsingDatabaseNew(new SafeBrowsingStoreFile, NULL);
+ }
+
+ SafeBrowsingDatabaseFactoryImpl() { }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SafeBrowsingDatabaseFactoryImpl);
+};
+
+// static
+SafeBrowsingDatabaseFactory* SafeBrowsingDatabase::factory_ = NULL;
+
+// Factory method, non-thread safe. Caller has to make sure this s called
+// on SafeBrowsing Thread.
// TODO(shess): Milestone-7 is converting from SQLite-based
// SafeBrowsingDatabaseBloom to the new file format with
// SafeBrowsingDatabaseNew. Once that conversion is too far along to
// consider reversing, circle back and lift SafeBrowsingDatabaseNew up
// to SafeBrowsingDatabase and get rid of the abstract class.
-SafeBrowsingDatabase* SafeBrowsingDatabase::Create() {
- return new SafeBrowsingDatabaseNew(new SafeBrowsingStoreFile);
+SafeBrowsingDatabase* SafeBrowsingDatabase::Create(
+ bool enable_download_protection) {
+ if (!factory_)
+ factory_ = new SafeBrowsingDatabaseFactoryImpl();
+ return factory_->CreateSafeBrowsingDatabase(enable_download_protection);
}
SafeBrowsingDatabase::~SafeBrowsingDatabase() {
}
// static
+FilePath SafeBrowsingDatabase::BrowseDBFilename(
+ const FilePath& db_base_filename) {
+ return FilePath(db_base_filename.value() + kBrowseDBFile);
+}
+
+// static
+FilePath SafeBrowsingDatabase::DownloadDBFilename(
+ const FilePath& db_base_filename) {
+ return FilePath(db_base_filename.value() + kDownloadDBFile);
+}
+
+// static
FilePath SafeBrowsingDatabase::BloomFilterForFilename(
const FilePath& db_filename) {
return FilePath(db_filename.value() + kBloomFilterFile);
}
+SafeBrowsingStore* SafeBrowsingDatabaseNew::GetStore(const int list_id) {
+ DVLOG(3) << "Get store for list: " << list_id;
+ if (list_id == safe_browsing_util::PHISH ||
+ list_id == safe_browsing_util::MALWARE) {
+ return browse_store_.get();
+ } else if (list_id == safe_browsing_util::BINURL ||
+ list_id == safe_browsing_util::BINHASH) {
+ return download_store_.get();
+ }
+ return NULL;
+}
+
// static
void SafeBrowsingDatabase::RecordFailure(FailureType failure_type) {
UMA_HISTOGRAM_ENUMERATION("SB2.DatabaseFailure", failure_type,
FAILURE_DATABASE_MAX);
}
-SafeBrowsingDatabaseNew::SafeBrowsingDatabaseNew(SafeBrowsingStore* store)
+SafeBrowsingDatabaseNew::SafeBrowsingDatabaseNew()
: creation_loop_(MessageLoop::current()),
- store_(store),
- ALLOW_THIS_IN_INITIALIZER_LIST(reset_factory_(this)),
- corruption_detected_(false) {
- DCHECK(store_.get());
+ browse_store_(new SafeBrowsingStoreSqlite),
+ download_store_(NULL),
+ ALLOW_THIS_IN_INITIALIZER_LIST(reset_factory_(this)) {
+ DCHECK(browse_store_.get());
+ DCHECK(!download_store_.get());
}
-SafeBrowsingDatabaseNew::SafeBrowsingDatabaseNew()
+SafeBrowsingDatabaseNew::SafeBrowsingDatabaseNew(
+ SafeBrowsingStore* browse_store, SafeBrowsingStore* download_store)
: creation_loop_(MessageLoop::current()),
- store_(new SafeBrowsingStoreSqlite),
- ALLOW_THIS_IN_INITIALIZER_LIST(reset_factory_(this)) {
- DCHECK(store_.get());
+ browse_store_(browse_store),
+ download_store_(download_store),
+ ALLOW_THIS_IN_INITIALIZER_LIST(reset_factory_(this)),
+ corruption_detected_(false) {
+ DCHECK(browse_store_.get());
}
SafeBrowsingDatabaseNew::~SafeBrowsingDatabaseNew() {
DCHECK_EQ(creation_loop_, MessageLoop::current());
}
-void SafeBrowsingDatabaseNew::Init(const FilePath& filename) {
+void SafeBrowsingDatabaseNew::Init(const FilePath& filename_base) {
DCHECK_EQ(creation_loop_, MessageLoop::current());
// NOTE: There is no need to grab the lock in this function, since
@@ -188,18 +289,28 @@ void SafeBrowsingDatabaseNew::Init(const FilePath& filename) {
// contention on the lock...
AutoLock locked(lookup_lock_);
- DCHECK(filename_.empty()); // Ensure we haven't been run before.
+ DCHECK(browse_filename_.empty()); // Ensure we haven't been run before.
+ DCHECK(download_filename_.empty()); // Ensure we haven't been run before.
- filename_ = filename;
- store_->Init(
- filename_,
+ browse_filename_ = BrowseDBFilename(filename_base);
+ browse_store_->Init(
+ browse_filename_,
NewCallback(this, &SafeBrowsingDatabaseNew::HandleCorruptDatabase));
- full_hashes_.clear();
- pending_hashes_.clear();
+ full_browse_hashes_.clear();
+ pending_browse_hashes_.clear();
- bloom_filter_filename_ = BloomFilterForFilename(filename_);
+ bloom_filter_filename_ = BloomFilterForFilename(browse_filename_);
LoadBloomFilter();
+ DVLOG(1) << "Init browse store: " << browse_filename_.value();
+
+ if (download_store_.get()) {
+ download_filename_ = DownloadDBFilename(filename_base);
+ download_store_->Init(
+ download_filename_,
+ NewCallback(this, &SafeBrowsingDatabaseNew::HandleCorruptDatabase));
+ DVLOG(1) << "Init download store: " << download_filename_.value();
+ }
}
bool SafeBrowsingDatabaseNew::ResetDatabase() {
@@ -214,18 +325,19 @@ bool SafeBrowsingDatabaseNew::ResetDatabase() {
// Reset objects in memory.
{
AutoLock locked(lookup_lock_);
- full_hashes_.clear();
- pending_hashes_.clear();
+ full_browse_hashes_.clear();
+ pending_browse_hashes_.clear();
prefix_miss_cache_.clear();
// TODO(shess): This could probably be |bloom_filter_.reset()|.
- bloom_filter_ = new BloomFilter(BloomFilter::kBloomFilterMinSize *
- BloomFilter::kBloomFilterSizeRatio);
+ browse_bloom_filter_ = new BloomFilter(BloomFilter::kBloomFilterMinSize *
+ BloomFilter::kBloomFilterSizeRatio);
}
return true;
}
-bool SafeBrowsingDatabaseNew::ContainsUrl(
+// TODO(lzheng): Remove matching_list, it is not used anywhere.
+bool SafeBrowsingDatabaseNew::ContainsBrowseUrl(
const GURL& url,
std::string* matching_list,
std::vector<SBPrefix>* prefix_hits,
@@ -237,7 +349,7 @@ bool SafeBrowsingDatabaseNew::ContainsUrl(
full_hits->clear();
std::vector<SBPrefix> prefixes;
- PrefixesToCheck(url, &prefixes);
+ BrowsePrefixesToCheck(url, &prefixes);
if (prefixes.empty())
return false;
@@ -245,13 +357,12 @@ bool SafeBrowsingDatabaseNew::ContainsUrl(
// bloom filter and caches.
AutoLock locked(lookup_lock_);
- if (!bloom_filter_.get())
+ if (!browse_bloom_filter_.get())
return false;
- // TODO(erikkay): Not filling in matching_list - is that OK?
size_t miss_count = 0;
for (size_t i = 0; i < prefixes.size(); ++i) {
- if (bloom_filter_->Exists(prefixes[i])) {
+ if (browse_bloom_filter_->Exists(prefixes[i])) {
prefix_hits->push_back(prefixes[i]);
if (prefix_miss_cache_.count(prefixes[i]) > 0)
++miss_count;
@@ -262,21 +373,51 @@ bool SafeBrowsingDatabaseNew::ContainsUrl(
if (miss_count == prefix_hits->size())
return false;
- // Find the matching full-hash results. |full_hashes_| are from the
- // database, |pending_hashes_| are from GetHash requests between
+ // Find the matching full-hash results. |full_browse_hashes_| are from the
+ // database, |pending_browse_hashes_| are from GetHash requests between
// updates.
std::sort(prefix_hits->begin(), prefix_hits->end());
- GetCachedFullHashes(*prefix_hits, full_hashes_, full_hits, last_update);
- GetCachedFullHashes(*prefix_hits, pending_hashes_, full_hits, last_update);
+
+ GetCachedFullHashesForBrowse(*prefix_hits, full_browse_hashes_,
+ full_hits, last_update);
+ GetCachedFullHashesForBrowse(*prefix_hits, pending_browse_hashes_,
+ full_hits, last_update);
return true;
}
+bool SafeBrowsingDatabaseNew::ContainsDownloadUrl(
+ const GURL& url, std::vector<SBPrefix>* prefix_hits) {
+ DCHECK_EQ(creation_loop_, MessageLoop::current());
+ prefix_hits->clear();
+
+ // Ignore this check when download checking is not enabled.
+ if (!download_store_.get()) return false;
+
+ SBPrefix prefix;
+ GetDownloadUrlPrefix(url, &prefix);
+
+ std::vector<SBAddPrefix> add_prefixes;
+ download_store_->GetAddPrefixes(&add_prefixes);
+ for (size_t i = 0; i < add_prefixes.size(); ++i) {
+ if (prefix == add_prefixes[i].prefix &&
+ GetListIdBit(add_prefixes[i].chunk_id) ==
+ safe_browsing_util::BINURL % 2) {
+ prefix_hits->push_back(prefix);
+ return true;
+ }
+ }
+ return false;
+}
+
// Helper to insert entries for all of the prefixes or full hashes in
// |entry| into the store.
void SafeBrowsingDatabaseNew::InsertAdd(int chunk_id, SBPrefix host,
const SBEntry* entry, int list_id) {
DCHECK_EQ(creation_loop_, MessageLoop::current());
+ SafeBrowsingStore* store = GetStore(list_id);
+ if (!store) return;
+
STATS_COUNTER("SB.HostInsert", 1);
const int encoded_chunk_id = EncodeChunkId(chunk_id, list_id);
const int count = entry->prefix_count();
@@ -285,13 +426,13 @@ void SafeBrowsingDatabaseNew::InsertAdd(int chunk_id, SBPrefix host,
if (!count) {
// No prefixes, use host instead.
STATS_COUNTER("SB.PrefixAdd", 1);
- store_->WriteAddPrefix(encoded_chunk_id, host);
+ store->WriteAddPrefix(encoded_chunk_id, host);
} else if (entry->IsPrefix()) {
// Prefixes only.
for (int i = 0; i < count; i++) {
const SBPrefix prefix = entry->PrefixAt(i);
STATS_COUNTER("SB.PrefixAdd", 1);
- store_->WriteAddPrefix(encoded_chunk_id, prefix);
+ store->WriteAddPrefix(encoded_chunk_id, prefix);
}
} else {
// Prefixes and hashes.
@@ -301,19 +442,23 @@ void SafeBrowsingDatabaseNew::InsertAdd(int chunk_id, SBPrefix host,
const SBPrefix prefix = full_hash.prefix;
STATS_COUNTER("SB.PrefixAdd", 1);
- store_->WriteAddPrefix(encoded_chunk_id, prefix);
+ store->WriteAddPrefix(encoded_chunk_id, prefix);
STATS_COUNTER("SB.PrefixAddFull", 1);
- store_->WriteAddHash(encoded_chunk_id, receive_time, full_hash);
+ store->WriteAddHash(encoded_chunk_id, receive_time, full_hash);
}
}
}
// Helper to iterate over all the entries in the hosts in |chunks| and
// add them to the store.
-void SafeBrowsingDatabaseNew::InsertAddChunks(int list_id,
+void SafeBrowsingDatabaseNew::InsertAddChunks(const int list_id,
const SBChunkList& chunks) {
DCHECK_EQ(creation_loop_, MessageLoop::current());
+
+ SafeBrowsingStore* store = GetStore(list_id);
+ if (!store) return;
+
for (SBChunkList::const_iterator citer = chunks.begin();
citer != chunks.end(); ++citer) {
const int chunk_id = citer->chunk_number;
@@ -321,10 +466,10 @@ void SafeBrowsingDatabaseNew::InsertAddChunks(int list_id,
// The server can give us a chunk that we already have because
// it's part of a range. Don't add it again.
const int encoded_chunk_id = EncodeChunkId(chunk_id, list_id);
- if (store_->CheckAddChunk(encoded_chunk_id))
+ if (store->CheckAddChunk(encoded_chunk_id))
continue;
- store_->SetAddChunk(encoded_chunk_id);
+ store->SetAddChunk(encoded_chunk_id);
for (std::deque<SBChunkHost>::const_iterator hiter = citer->hosts.begin();
hiter != citer->hosts.end(); ++hiter) {
// NOTE: Could pass |encoded_chunk_id|, but then inserting add
@@ -340,6 +485,9 @@ void SafeBrowsingDatabaseNew::InsertSub(int chunk_id, SBPrefix host,
const SBEntry* entry, int list_id) {
DCHECK_EQ(creation_loop_, MessageLoop::current());
+ SafeBrowsingStore* store = GetStore(list_id);
+ if (!store) return;
+
STATS_COUNTER("SB.HostDelete", 1);
const int encoded_chunk_id = EncodeChunkId(chunk_id, list_id);
const int count = entry->prefix_count();
@@ -349,7 +497,7 @@ void SafeBrowsingDatabaseNew::InsertSub(int chunk_id, SBPrefix host,
// No prefixes, use host instead.
STATS_COUNTER("SB.PrefixSub", 1);
const int add_chunk_id = EncodeChunkId(entry->chunk_id(), list_id);
- store_->WriteSubPrefix(encoded_chunk_id, add_chunk_id, host);
+ store->WriteSubPrefix(encoded_chunk_id, add_chunk_id, host);
} else if (entry->IsPrefix()) {
// Prefixes only.
for (int i = 0; i < count; i++) {
@@ -358,7 +506,7 @@ void SafeBrowsingDatabaseNew::InsertSub(int chunk_id, SBPrefix host,
EncodeChunkId(entry->ChunkIdAtPrefix(i), list_id);
STATS_COUNTER("SB.PrefixSub", 1);
- store_->WriteSubPrefix(encoded_chunk_id, add_chunk_id, prefix);
+ store->WriteSubPrefix(encoded_chunk_id, add_chunk_id, prefix);
}
} else {
// Prefixes and hashes.
@@ -368,10 +516,10 @@ void SafeBrowsingDatabaseNew::InsertSub(int chunk_id, SBPrefix host,
EncodeChunkId(entry->ChunkIdAtPrefix(i), list_id);
STATS_COUNTER("SB.PrefixSub", 1);
- store_->WriteSubPrefix(encoded_chunk_id, add_chunk_id, full_hash.prefix);
+ store->WriteSubPrefix(encoded_chunk_id, add_chunk_id, full_hash.prefix);
STATS_COUNTER("SB.PrefixSubFull", 1);
- store_->WriteSubHash(encoded_chunk_id, add_chunk_id, full_hash);
+ store->WriteSubHash(encoded_chunk_id, add_chunk_id, full_hash);
}
}
}
@@ -381,6 +529,10 @@ void SafeBrowsingDatabaseNew::InsertSub(int chunk_id, SBPrefix host,
void SafeBrowsingDatabaseNew::InsertSubChunks(int list_id,
const SBChunkList& chunks) {
DCHECK_EQ(creation_loop_, MessageLoop::current());
+
+ SafeBrowsingStore* store = GetStore(list_id);
+ if (!store) return;
+
for (SBChunkList::const_iterator citer = chunks.begin();
citer != chunks.end(); ++citer) {
const int chunk_id = citer->chunk_number;
@@ -388,10 +540,10 @@ void SafeBrowsingDatabaseNew::InsertSubChunks(int list_id,
// The server can give us a chunk that we already have because
// it's part of a range. Don't add it again.
const int encoded_chunk_id = EncodeChunkId(chunk_id, list_id);
- if (store_->CheckSubChunk(encoded_chunk_id))
+ if (store->CheckSubChunk(encoded_chunk_id))
continue;
- store_->SetSubChunk(encoded_chunk_id);
+ store->SetSubChunk(encoded_chunk_id);
for (std::deque<SBChunkHost>::const_iterator hiter = citer->hosts.begin();
hiter != citer->hosts.end(); ++hiter) {
InsertSub(chunk_id, hiter->host, hiter->entry, list_id);
@@ -409,13 +561,18 @@ void SafeBrowsingDatabaseNew::InsertChunks(const std::string& list_name,
const base::Time insert_start = base::Time::Now();
const int list_id = safe_browsing_util::GetListId(list_name);
- store_->BeginChunk();
+ DVLOG(2) << list_name << ": " << list_id;
+
+ SafeBrowsingStore* store = GetStore(list_id);
+ if (!store) return;
+
+ store->BeginChunk();
if (chunks.front().is_add) {
InsertAddChunks(list_id, chunks);
} else {
InsertSubChunks(list_id, chunks);
}
- store_->FinishChunk();
+ store->FinishChunk();
UMA_HISTOGRAM_TIMES("SB2.ChunkInsert", base::Time::Now() - insert_start);
}
@@ -430,15 +587,18 @@ void SafeBrowsingDatabaseNew::DeleteChunks(
const std::string& list_name = chunk_deletes.front().list_name;
const int list_id = safe_browsing_util::GetListId(list_name);
+ SafeBrowsingStore* store = GetStore(list_id);
+ if (!store) return;
+
for (size_t i = 0; i < chunk_deletes.size(); ++i) {
std::vector<int> chunk_numbers;
RangesToChunks(chunk_deletes[i].chunk_del, &chunk_numbers);
for (size_t j = 0; j < chunk_numbers.size(); ++j) {
const int encoded_chunk_id = EncodeChunkId(chunk_numbers[j], list_id);
if (chunk_deletes[i].is_sub_del)
- store_->DeleteSubChunk(encoded_chunk_id);
+ store->DeleteSubChunk(encoded_chunk_id);
else
- store_->DeleteAddChunk(encoded_chunk_id);
+ store->DeleteAddChunk(encoded_chunk_id);
}
}
}
@@ -457,19 +617,24 @@ void SafeBrowsingDatabaseNew::CacheHashResults(
// TODO(shess): SBFullHashResult and SBAddFullHash are very similar.
// Refactor to make them identical.
const base::Time now = base::Time::Now();
- const size_t orig_size = pending_hashes_.size();
+ const size_t orig_size = pending_browse_hashes_.size();
for (std::vector<SBFullHashResult>::const_iterator iter = full_hits.begin();
iter != full_hits.end(); ++iter) {
const int list_id = safe_browsing_util::GetListId(iter->list_name);
- const int encoded_chunk_id = EncodeChunkId(iter->add_chunk_id, list_id);
- pending_hashes_.push_back(SBAddFullHash(encoded_chunk_id, now, iter->hash));
+ if (list_id == safe_browsing_util::MALWARE ||
+ list_id == safe_browsing_util::PHISH) {
+ int encoded_chunk_id = EncodeChunkId(iter->add_chunk_id, list_id);
+ SBAddFullHash add_full_hash(encoded_chunk_id, now, iter->hash);
+ pending_browse_hashes_.push_back(add_full_hash);
+ }
}
// Sort new entries then merge with the previously-sorted entries.
std::vector<SBAddFullHash>::iterator
- orig_end = pending_hashes_.begin() + orig_size;
- std::sort(orig_end, pending_hashes_.end(), SBAddFullHashPrefixLess);
- std::inplace_merge(pending_hashes_.begin(), orig_end, pending_hashes_.end(),
+ orig_end = pending_browse_hashes_.begin() + orig_size;
+ std::sort(orig_end, pending_browse_hashes_.end(), SBAddFullHashPrefixLess);
+ std::inplace_merge(pending_browse_hashes_.begin(),
+ orig_end, pending_browse_hashes_.end(),
SBAddFullHashPrefixLess);
}
@@ -479,50 +644,95 @@ bool SafeBrowsingDatabaseNew::UpdateStarted(
DCHECK(lists);
// If |BeginUpdate()| fails, reset the database.
- if (!store_->BeginUpdate()) {
- RecordFailure(FAILURE_DATABASE_UPDATE_BEGIN);
+ if (!browse_store_->BeginUpdate()) {
+ RecordFailure(FAILURE_BROWSE_DATABASE_UPDATE_BEGIN);
HandleCorruptDatabase();
return false;
}
- SBListChunkRanges malware(safe_browsing_util::kMalwareList);
- SBListChunkRanges phishing(safe_browsing_util::kPhishingList);
-
- std::vector<int> add_chunks;
- store_->GetAddChunks(&add_chunks);
- GetChunkIds(add_chunks, &malware.adds, &phishing.adds);
-
- std::vector<int> sub_chunks;
- store_->GetSubChunks(&sub_chunks);
- GetChunkIds(sub_chunks, &malware.subs, &phishing.subs);
+ if (download_store_.get() && !download_store_->BeginUpdate()) {
+ RecordFailure(FAILURE_DOWNLOAD_DATABASE_UPDATE_BEGIN);
+ HandleCorruptDatabase();
+ return false;
+ }
- lists->push_back(malware);
- lists->push_back(phishing);
+ std::vector<int> browse_add_chunks;
+ browse_store_->GetAddChunks(&browse_add_chunks);
+ std::vector<int> browse_sub_chunks;
+ browse_store_->GetSubChunks(&browse_sub_chunks);
+ UpdateChunkRanges(browse_add_chunks, browse_sub_chunks,
+ safe_browsing_util::kMalwareList,
+ safe_browsing_util::kPhishingList,
+ lists);
+
+ if (download_store_.get()) {
+ std::vector<int> download_add_chunks;
+ download_store_->GetAddChunks(&download_add_chunks);
+ std::vector<int> download_sub_chunks;
+ download_store_->GetSubChunks(&download_sub_chunks);
+ UpdateChunkRanges(download_add_chunks, download_sub_chunks,
+ safe_browsing_util::kBinUrlList,
+ safe_browsing_util::kBinHashList,
+ lists);
+ }
corruption_detected_ = false;
-
return true;
}
void SafeBrowsingDatabaseNew::UpdateFinished(bool update_succeeded) {
DCHECK_EQ(creation_loop_, MessageLoop::current());
-
if (corruption_detected_)
return;
// Unroll any partially-received transaction.
if (!update_succeeded) {
- store_->CancelUpdate();
+ browse_store_->CancelUpdate();
+ if (download_store_.get())
+ download_store_->CancelUpdate();
return;
}
+ // for download
+ UpdateDownloadStore();
+ // for browsing
+ UpdateBrowseStore();
+}
+
+void SafeBrowsingDatabaseNew:: UpdateDownloadStore() {
+ if (!download_store_.get())
+ return;
+
+ // For download, we don't cache and save full hashes.
+ std::vector<SBAddFullHash> empty_add_hashes;
+
+ // For download, backend lookup happens only if a prefix is in add list.
+ // No need to pass in miss cache when call FinishUpdate to caculate
+ // bloomfilter false positives.
+ std::set<SBPrefix> empty_miss_cache;
+
+ // These results are not used after this call. Simply ignore the
+ // returned value after FinishUpdate(...).
+ std::vector<SBAddPrefix> add_prefixes_result;
+ std::vector<SBAddFullHash> add_full_hashes_result;
+
+ if (download_store_->FinishUpdate(empty_add_hashes,
+ empty_miss_cache,
+ &add_prefixes_result,
+ &add_full_hashes_result))
+ RecordFailure(FAILURE_DOWNLOAD_DATABASE_UPDATE_FINISH);
+ return;
+}
+
+void SafeBrowsingDatabaseNew::UpdateBrowseStore() {
// Copy out the pending add hashes. Copy rather than swapping in
- // case |ContainsURL()| is called before the new filter is complete.
+ // case |ContainsBrowseURL()| is called before the new filter is complete.
std::vector<SBAddFullHash> pending_add_hashes;
{
AutoLock locked(lookup_lock_);
pending_add_hashes.insert(pending_add_hashes.end(),
- pending_hashes_.begin(), pending_hashes_.end());
+ pending_browse_hashes_.begin(),
+ pending_browse_hashes_.end());
}
// Measure the amount of IO during the bloom filter build.
@@ -546,9 +756,9 @@ void SafeBrowsingDatabaseNew::UpdateFinished(bool update_succeeded) {
std::vector<SBAddPrefix> add_prefixes;
std::vector<SBAddFullHash> add_full_hashes;
- if (!store_->FinishUpdate(pending_add_hashes,
- &add_prefixes, &add_full_hashes)) {
- RecordFailure(FAILURE_DATABASE_UPDATE_FINISH);
+ if (!browse_store_->FinishUpdate(pending_add_hashes, prefix_miss_cache_,
+ &add_prefixes, &add_full_hashes)) {
+ RecordFailure(FAILURE_BROWSE_DATABASE_UPDATE_FINISH);
return;
}
@@ -569,23 +779,22 @@ void SafeBrowsingDatabaseNew::UpdateFinished(bool update_succeeded) {
// Swap in the newly built filter and cache.
{
AutoLock locked(lookup_lock_);
- full_hashes_.swap(add_full_hashes);
+ full_browse_hashes_.swap(add_full_hashes);
// TODO(shess): If |CacheHashResults()| is posted between the
// earlier lock and this clear, those pending hashes will be lost.
// It could be fixed by only removing hashes which were collected
// at the earlier point. I believe that is fail-safe as-is (the
// hash will be fetched again).
- pending_hashes_.clear();
-
+ pending_browse_hashes_.clear();
prefix_miss_cache_.clear();
- bloom_filter_.swap(filter);
+ browse_bloom_filter_.swap(filter);
}
const base::TimeDelta bloom_gen = base::Time::Now() - before;
// Persist the bloom filter to disk. Since only this thread changes
- // |bloom_filter_|, there is no need to lock.
+ // |browse_bloom_filter_|, there is no need to lock.
WriteBloomFilter();
// Gather statistics.
@@ -603,16 +812,19 @@ void SafeBrowsingDatabaseNew::UpdateFinished(bool update_succeeded) {
static_cast<int>(io_after.WriteOperationCount -
io_before.WriteOperationCount));
}
- VLOG(1) << "SafeBrowsingDatabaseImpl built bloom filter in "
- << bloom_gen.InMilliseconds() << " ms total. prefix count: "
- << add_prefixes.size();
+ DVLOG(1) << "SafeBrowsingDatabaseImpl built bloom filter in "
+ << bloom_gen.InMilliseconds() << " ms total. prefix count: "
+ << add_prefixes.size();
UMA_HISTOGRAM_LONG_TIMES("SB2.BuildFilter", bloom_gen);
- UMA_HISTOGRAM_COUNTS("SB2.FilterKilobytes", bloom_filter_->size() / 1024);
+ UMA_HISTOGRAM_COUNTS("SB2.FilterKilobytes",
+ browse_bloom_filter_->size() / 1024);
int64 size_64;
- if (file_util::GetFileSize(filename_, &size_64)) {
- UMA_HISTOGRAM_COUNTS("SB2.DatabaseKilobytes",
+ if (file_util::GetFileSize(browse_filename_, &size_64))
+ UMA_HISTOGRAM_COUNTS("SB2.BrowseDatabaseKilobytes",
+ static_cast<int>(size_64 / 1024));
+ if (file_util::GetFileSize(download_filename_, &size_64))
+ UMA_HISTOGRAM_COUNTS("SB2.DownloadDatabaseKilobytes",
static_cast<int>(size_64 / 1024));
- }
}
void SafeBrowsingDatabaseNew::HandleCorruptDatabase() {
@@ -627,7 +839,6 @@ void SafeBrowsingDatabaseNew::HandleCorruptDatabase() {
}
void SafeBrowsingDatabaseNew::OnHandleCorruptDatabase() {
- UMA_HISTOGRAM_COUNTS("SB2.HandleCorrupt", 1);
RecordFailure(FAILURE_DATABASE_CORRUPT_HANDLER);
corruption_detected_ = true; // Stop updating the database.
ResetDatabase();
@@ -645,52 +856,52 @@ void SafeBrowsingDatabaseNew::LoadBloomFilter() {
// TODO(paulg): Investigate how often the filter file is missing and how
// expensive it would be to regenerate it.
int64 size_64;
- if (!file_util::GetFileSize(filename_, &size_64) || size_64 == 0)
+ if (!file_util::GetFileSize(browse_filename_, &size_64) || size_64 == 0)
return;
if (!file_util::GetFileSize(bloom_filter_filename_, &size_64) ||
size_64 == 0) {
- UMA_HISTOGRAM_COUNTS("SB2.FilterMissing", 1);
RecordFailure(FAILURE_DATABASE_FILTER_MISSING);
return;
}
const base::TimeTicks before = base::TimeTicks::Now();
- bloom_filter_ = BloomFilter::LoadFile(bloom_filter_filename_);
- VLOG(1) << "SafeBrowsingDatabaseNew read bloom filter in "
- << (base::TimeTicks::Now() - before).InMilliseconds() << " ms";
+ browse_bloom_filter_ = BloomFilter::LoadFile(bloom_filter_filename_);
+ DVLOG(1) << "SafeBrowsingDatabaseNew read bloom filter in "
+ << (base::TimeTicks::Now() - before).InMilliseconds() << " ms";
- if (!bloom_filter_.get()) {
- UMA_HISTOGRAM_COUNTS("SB2.FilterReadFail", 1);
+ if (!browse_bloom_filter_.get())
RecordFailure(FAILURE_DATABASE_FILTER_READ);
- }
}
bool SafeBrowsingDatabaseNew::Delete() {
DCHECK_EQ(creation_loop_, MessageLoop::current());
- const bool r1 = store_->Delete();
+ const bool r1 = browse_store_->Delete();
if (!r1)
RecordFailure(FAILURE_DATABASE_STORE_DELETE);
- const bool r2 = file_util::Delete(bloom_filter_filename_, false);
+
+ const bool r2 = download_store_.get() ? download_store_->Delete() : true;
if (!r2)
+ RecordFailure(FAILURE_DATABASE_STORE_DELETE);
+
+ const bool r3 = file_util::Delete(bloom_filter_filename_, false);
+ if (!r3)
RecordFailure(FAILURE_DATABASE_FILTER_DELETE);
- return r1 && r2;
+ return r1 && r2 && r3;
}
void SafeBrowsingDatabaseNew::WriteBloomFilter() {
DCHECK_EQ(creation_loop_, MessageLoop::current());
- if (!bloom_filter_.get())
+ if (!browse_bloom_filter_.get())
return;
const base::TimeTicks before = base::TimeTicks::Now();
- const bool write_ok = bloom_filter_->WriteFile(bloom_filter_filename_);
- VLOG(1) << "SafeBrowsingDatabaseNew wrote bloom filter in "
- << (base::TimeTicks::Now() - before).InMilliseconds() << " ms";
+ const bool write_ok = browse_bloom_filter_->WriteFile(bloom_filter_filename_);
+ DVLOG(1) << "SafeBrowsingDatabaseNew wrote bloom filter in "
+ << (base::TimeTicks::Now() - before).InMilliseconds() << " ms";
- if (!write_ok) {
- UMA_HISTOGRAM_COUNTS("SB2.FilterWriteFail", 1);
+ if (!write_ok)
RecordFailure(FAILURE_DATABASE_FILTER_WRITE);
- }
}
diff --git a/chrome/browser/safe_browsing/safe_browsing_database.h b/chrome/browser/safe_browsing/safe_browsing_database.h
index 9ca53f7..980a8d3 100644
--- a/chrome/browser/safe_browsing/safe_browsing_database.h
+++ b/chrome/browser/safe_browsing/safe_browsing_database.h
@@ -14,7 +14,6 @@
#include "base/scoped_ptr.h"
#include "base/task.h"
#include "chrome/browser/safe_browsing/safe_browsing_store.h"
-#include "chrome/browser/safe_browsing/safe_browsing_util.h"
#include "testing/gtest/include/gtest/gtest_prod.h"
namespace base {
@@ -24,17 +23,44 @@ namespace base {
class BloomFilter;
class GURL;
class MessageLoop;
+class SafeBrowsingDatabase;
+
+// Factory for creating SafeBrowsingDatabase. Tests implement this factory
+// to create fake Databases for testing.
+class SafeBrowsingDatabaseFactory {
+ public:
+ SafeBrowsingDatabaseFactory() { }
+ virtual ~SafeBrowsingDatabaseFactory() { }
+ virtual SafeBrowsingDatabase* CreateSafeBrowsingDatabase(
+ bool enable_download_protection) = 0;
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SafeBrowsingDatabaseFactory);
+};
-// Encapsulates the database that stores information about phishing
-// and malware sites. There is one on-disk database for all profiles,
-// as it doesn't contain user-specific data. This object is not
-// thread-safe, i.e. all its methods should be used on the same thread
-// that it was created on.
+
+// Encapsulates on-disk databases that for safebrowsing. There are two
+// databases: browse database and download database. The browse database
+// contains information about phishing and malware urls. The download
+// database contains URLs for bad binaries (e.g: those containing virus)
+// and hash of these downloaded contents. These on-disk databases are shared
+// among all profiles, as it doesn't contain user-specific data. This object
+// is not thread-safe, i.e. all its methods should be used on the same thread
+// that it was created on.
class SafeBrowsingDatabase {
public:
// Factory method for obtaining a SafeBrowsingDatabase implementation.
- static SafeBrowsingDatabase* Create();
+ // It is not thread safe.
+ // |enable_download_protection| is used to control the download database
+ // feature.
+ static SafeBrowsingDatabase* Create(bool enable_download_protection);
+
+ // Makes the passed |factory| the factory used to instantiate
+ // a SafeBrowsingDatabase. This is used for tests.
+ static void RegisterFactory(SafeBrowsingDatabaseFactory* factory) {
+ factory_ = factory;
+ }
+
virtual ~SafeBrowsingDatabase();
// Initializes the database with the given filename.
@@ -43,16 +69,22 @@ class SafeBrowsingDatabase {
// Deletes the current database and creates a new one.
virtual bool ResetDatabase() = 0;
- // Returns false if |url| is not in the database. If it returns
- // true, then either |matching_list| is the name of the matching
+ // Returns false if |url| is not in the browse database. If it
+ // returns true, then either |matching_list| is the name of the matching
// list, or |prefix_hits| and |full_hits| contains the matching hash
// prefixes. This function is safe to call from threads other than
// the creation thread.
- virtual bool ContainsUrl(const GURL& url,
- std::string* matching_list,
- std::vector<SBPrefix>* prefix_hits,
- std::vector<SBFullHashResult>* full_hits,
- base::Time last_update) = 0;
+ virtual bool ContainsBrowseUrl(const GURL& url,
+ std::string* matching_list,
+ std::vector<SBPrefix>* prefix_hits,
+ std::vector<SBFullHashResult>* full_hits,
+ base::Time last_update) = 0;
+
+ // Returns false if |url| is not in Download database. If it returns true,
+ // |prefix_hits| should contain the prefix for |url|.
+ // This function could ONLY be accessed from creation thread.
+ virtual bool ContainsDownloadUrl(const GURL& url,
+ std::vector<SBPrefix>* prefix_hits) = 0;
// A database transaction should look like:
//
@@ -92,19 +124,27 @@ class SafeBrowsingDatabase {
// The name of the bloom-filter file for the given database file.
static FilePath BloomFilterForFilename(const FilePath& db_filename);
+ // Filename for malware and phishing URL database.
+ static FilePath BrowseDBFilename(const FilePath& db_base_filename);
+
+ // Filename for download URL and download binary hash database.
+ static FilePath DownloadDBFilename(const FilePath& db_base_filename);
+
// Enumerate failures for histogramming purposes. DO NOT CHANGE THE
// ORDERING OF THESE VALUES.
enum FailureType {
FAILURE_DATABASE_CORRUPT,
FAILURE_DATABASE_CORRUPT_HANDLER,
- FAILURE_DATABASE_UPDATE_BEGIN,
- FAILURE_DATABASE_UPDATE_FINISH,
+ FAILURE_BROWSE_DATABASE_UPDATE_BEGIN,
+ FAILURE_BROWSE_DATABASE_UPDATE_FINISH,
FAILURE_DATABASE_FILTER_MISSING,
FAILURE_DATABASE_FILTER_READ,
FAILURE_DATABASE_FILTER_WRITE,
FAILURE_DATABASE_FILTER_DELETE,
FAILURE_DATABASE_STORE_MISSING,
FAILURE_DATABASE_STORE_DELETE,
+ FAILURE_DOWNLOAD_DATABASE_UPDATE_BEGIN,
+ FAILURE_DOWNLOAD_DATABASE_UPDATE_FINISH,
// Memory space for histograms is determined by the max. ALWAYS
// ADD NEW VALUES BEFORE THIS ONE.
@@ -112,16 +152,25 @@ class SafeBrowsingDatabase {
};
static void RecordFailure(FailureType failure_type);
+
+ private:
+ // The factory used to instantiate a SafeBrowsingDatabase object.
+ // Useful for tests, so they can provide their own implementation of
+ // SafeBrowsingDatabase.
+ static SafeBrowsingDatabaseFactory* factory_;
};
class SafeBrowsingDatabaseNew : public SafeBrowsingDatabase {
public:
- // Create a database on the given store. Takes ownership of
- // |store|. This method is temporary for
- // SafeBrowsingDatabase::Create(), do not use it otherwise.
- explicit SafeBrowsingDatabaseNew(SafeBrowsingStore* store);
-
- // Create a database with a default store.
+ // Create a database with a browse store and download store. Takes ownership
+ // of browse_store and download_store. When |download_store| is NULL,
+ // the database will ignore any operations related download (url hashes and
+ // binary hashes).
+ SafeBrowsingDatabaseNew(SafeBrowsingStore* browse_store,
+ SafeBrowsingStore* download_store);
+
+ // Create a database with a browse store. This is a legacy interface that
+ // useds Sqlite.
SafeBrowsingDatabaseNew();
virtual ~SafeBrowsingDatabaseNew();
@@ -129,11 +178,14 @@ class SafeBrowsingDatabaseNew : public SafeBrowsingDatabase {
// Implement SafeBrowsingDatabase interface.
virtual void Init(const FilePath& filename);
virtual bool ResetDatabase();
- virtual bool ContainsUrl(const GURL& url,
- std::string* matching_list,
- std::vector<SBPrefix>* prefix_hits,
- std::vector<SBFullHashResult>* full_hits,
- base::Time last_update);
+ virtual bool ContainsBrowseUrl(const GURL& url,
+ std::string* matching_list,
+ std::vector<SBPrefix>* prefix_hits,
+ std::vector<SBFullHashResult>* full_hits,
+ base::Time last_update);
+ virtual bool ContainsDownloadUrl(const GURL& url,
+ std::vector<SBPrefix>* prefix_hits);
+
virtual bool UpdateStarted(std::vector<SBListChunkRanges>* lists);
virtual void InsertChunks(const std::string& list_name,
const SBChunkList& chunks);
@@ -146,7 +198,10 @@ class SafeBrowsingDatabaseNew : public SafeBrowsingDatabase {
friend class SafeBrowsingDatabaseTest;
FRIEND_TEST(SafeBrowsingDatabaseTest, HashCaching);
- // Deletes the files on disk.
+ // Return the browse_store_ or download_store_ based on list_id.
+ SafeBrowsingStore* GetStore(int list_id);
+
+ // Deletes the files on disk.
bool Delete();
// Load the bloom filter off disk, or generates one if it doesn't exist.
@@ -171,29 +226,39 @@ class SafeBrowsingDatabaseNew : public SafeBrowsingDatabase {
void InsertSub(int chunk, SBPrefix host, const SBEntry* entry, int list_id);
void InsertSubChunks(int list_id, const SBChunkList& chunks);
+ void UpdateDownloadStore();
+ void UpdateBrowseStore();
+
// Used to verify that various calls are made from the thread the
// object was created on.
MessageLoop* creation_loop_;
// Lock for protecting access to variables that may be used on the
- // IO thread. This includes |bloom_filter_|, |full_hashes_|,
- // |pending_hashes_|, and |prefix_miss_cache_|.
+ // IO thread. This includes |browse_bloom_filter_|, |full_browse_hashes_|,
+ // |pending_browse_hashes_|, and |prefix_miss_cache_|.
Lock lookup_lock_;
// Underlying persistent store for chunk data.
- FilePath filename_;
- scoped_ptr<SafeBrowsingStore> store_;
+ // For browsing related (phishing and malware URLs) chunks and prefixes.
+ FilePath browse_filename_;
+ scoped_ptr<SafeBrowsingStore> browse_store_;
+
+ // For download related (download URL and binary hash) chunks and prefixes.
+ FilePath download_filename_;
+ scoped_ptr<SafeBrowsingStore> download_store_;
- // Bloom filter generated from the add-prefixes in |store_|.
+ // Bloom filter generated from the add-prefixes in |browse_store_|.
+ // Only browse_store_ requires the BloomFilter for fast query.
FilePath bloom_filter_filename_;
- scoped_refptr<BloomFilter> bloom_filter_;
-
- // Cached full-hash items, ordered by prefix for efficient scanning.
- // |full_hashes_| are items from |store_|, |pending_hashes_| are
- // items from |CacheHashResults()|, which will be pushed to the
- // store on the next update.
- std::vector<SBAddFullHash> full_hashes_;
- std::vector<SBAddFullHash> pending_hashes_;
+ scoped_refptr<BloomFilter> browse_bloom_filter_;
+
+ // Cached browse store related full-hash items, ordered by prefix for
+ // efficient scanning.
+ // |full_browse_hashes_| are items from |browse_store_|,
+ // |pending_browse_hashes_| are items from |CacheHashResults()|, which
+ // will be pushed to the store on the next update.
+ std::vector<SBAddFullHash> full_browse_hashes_;
+ std::vector<SBAddFullHash> pending_browse_hashes_;
// Cache of prefixes that returned empty results (no full hash
// match) to |CacheHashResults()|. Cached to prevent asking for
diff --git a/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc
index 89cc553..32ef6d2 100644
--- a/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc
@@ -89,7 +89,7 @@ bool CorruptSqliteTable(const FilePath& filename,
page_size = stmt.ColumnInt(0);
stmt.Assign(db.GetUniqueStatement(
- "SELECT rootpage FROM sqlite_master WHERE name = ?"));
+ "SELECT rootpage FROM sqlite_master WHERE name = ?"));
stmt.BindString(0, "sub_prefix");
if (!stmt.Step())
return false;
@@ -177,7 +177,7 @@ class SafeBrowsingDatabaseTest : public PlatformTest {
};
// Tests retrieving list name information.
-TEST_F(SafeBrowsingDatabaseTest, ListName) {
+TEST_F(SafeBrowsingDatabaseTest, ListNameForBrowse) {
SBChunkList chunks;
// Insert some malware add chunks.
@@ -307,8 +307,90 @@ TEST_F(SafeBrowsingDatabaseTest, ListName) {
EXPECT_EQ(lists[1].subs, "200-201");
}
-// Checks database reading and writing.
-TEST_F(SafeBrowsingDatabaseTest, Database) {
+TEST_F(SafeBrowsingDatabaseTest, ListNameForBrowseAndDownload) {
+ database_.reset();
+ MessageLoop loop(MessageLoop::TYPE_DEFAULT);
+ SafeBrowsingStoreFile* browse_store = new SafeBrowsingStoreFile();
+ SafeBrowsingStoreFile* download_store = new SafeBrowsingStoreFile();
+ database_.reset(new SafeBrowsingDatabaseNew(browse_store, download_store));
+ database_->Init(database_filename_);
+
+ SBChunkList chunks;
+
+ // Insert malware, phish, binurl and bindownload add chunks.
+ SBChunkHost host;
+ host.host = Sha256Prefix("www.evil.com/");
+ host.entry = SBEntry::Create(SBEntry::ADD_PREFIX, 1);
+ host.entry->set_chunk_id(1);
+ host.entry->SetPrefixAt(0, Sha256Prefix("www.evil.com/malware.html"));
+ SBChunk chunk;
+ chunk.chunk_number = 1;
+ chunk.is_add = true;
+ chunk.hosts.push_back(host);
+ chunks.clear();
+ chunks.push_back(chunk);
+ std::vector<SBListChunkRanges> lists;
+
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
+ database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
+
+ host.host = Sha256Prefix("www.foo.com/");
+ host.entry = SBEntry::Create(SBEntry::ADD_PREFIX, 1);
+ host.entry->set_chunk_id(2);
+ host.entry->SetPrefixAt(0, Sha256Prefix("www.foo.com/malware.html"));
+ chunk.chunk_number = 2;
+ chunk.is_add = true;
+ chunk.hosts.clear();
+ chunk.hosts.push_back(host);
+ chunks.clear();
+ chunks.push_back(chunk);
+ database_->InsertChunks(safe_browsing_util::kPhishingList, chunks);
+
+ host.host = Sha256Prefix("www.whatever.com/");
+ host.entry = SBEntry::Create(SBEntry::ADD_PREFIX, 1);
+ host.entry->set_chunk_id(3);
+ host.entry->SetPrefixAt(0, Sha256Prefix("www.whatever.com/download.html"));
+ chunk.chunk_number = 3;
+ chunk.is_add = true;
+ chunk.hosts.clear();
+ chunk.hosts.push_back(host);
+ chunks.clear();
+ chunks.push_back(chunk);
+ database_->InsertChunks(safe_browsing_util::kBinUrlList, chunks);
+
+ host.host = Sha256Prefix("www.forhash.com/");
+ host.entry = SBEntry::Create(SBEntry::ADD_PREFIX, 1);
+ host.entry->set_chunk_id(4);
+ host.entry->SetPrefixAt(0, Sha256Prefix("www.forhash.com/download.html"));
+ chunk.chunk_number = 4;
+ chunk.is_add = true;
+ chunk.hosts.clear();
+ chunk.hosts.push_back(host);
+ chunks.clear();
+ chunks.push_back(chunk);
+ database_->InsertChunks(safe_browsing_util::kBinHashList, chunks);
+
+ database_->UpdateFinished(true);
+
+ GetListsInfo(&lists);
+ EXPECT_EQ(4U, lists.size());
+ EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList);
+ EXPECT_EQ(lists[0].adds, "1");
+ EXPECT_TRUE(lists[0].subs.empty());
+ EXPECT_TRUE(lists[1].name == safe_browsing_util::kPhishingList);
+ EXPECT_EQ(lists[1].adds, "2");
+ EXPECT_TRUE(lists[1].subs.empty());
+ EXPECT_TRUE(lists[2].name == safe_browsing_util::kBinUrlList);
+ EXPECT_EQ(lists[2].adds, "3");
+ EXPECT_TRUE(lists[2].subs.empty());
+ EXPECT_TRUE(lists[3].name == safe_browsing_util::kBinHashList);
+ EXPECT_EQ(lists[3].adds, "4");
+ EXPECT_TRUE(lists[3].subs.empty());
+ database_.reset();
+}
+
+// Checks database reading and writing for browse.
+TEST_F(SafeBrowsingDatabaseTest, BrowseDatabase) {
SBChunkList chunks;
// Add a simple chunk with one hostkey.
@@ -379,44 +461,53 @@ TEST_F(SafeBrowsingDatabaseTest, Database) {
std::vector<SBFullHashResult> full_hashes;
std::vector<SBPrefix> prefix_hits;
std::string matching_list;
- EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.evil.com/phishing.html"),
- &matching_list, &prefix_hits,
- &full_hashes, now));
+ EXPECT_TRUE(database_->ContainsBrowseUrl(
+ GURL("http://www.evil.com/phishing.html"),
+ &matching_list, &prefix_hits,
+ &full_hashes, now));
EXPECT_EQ(prefix_hits[0], Sha256Prefix("www.evil.com/phishing.html"));
EXPECT_EQ(prefix_hits.size(), 1U);
- EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.evil.com/malware.html"),
- &matching_list, &prefix_hits,
- &full_hashes, now));
-
- EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.evil.com/notevil1.html"),
- &matching_list, &prefix_hits,
- &full_hashes, now));
-
- EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.evil.com/notevil2.html"),
- &matching_list, &prefix_hits,
- &full_hashes, now));
-
- EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.good.com/good1.html"),
- &matching_list, &prefix_hits,
- &full_hashes, now));
-
- EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.good.com/good2.html"),
- &matching_list, &prefix_hits,
- &full_hashes, now));
-
- EXPECT_TRUE(database_->ContainsUrl(GURL("http://192.168.0.1/malware.html"),
- &matching_list, &prefix_hits,
- &full_hashes, now));
-
- EXPECT_FALSE(database_->ContainsUrl(GURL("http://www.evil.com/"),
- &matching_list, &prefix_hits,
- &full_hashes, now));
+ EXPECT_TRUE(database_->ContainsBrowseUrl(
+ GURL("http://www.evil.com/malware.html"),
+ &matching_list, &prefix_hits,
+ &full_hashes, now));
+
+ EXPECT_TRUE(database_->ContainsBrowseUrl(
+ GURL("http://www.evil.com/notevil1.html"),
+ &matching_list, &prefix_hits,
+ &full_hashes, now));
+
+ EXPECT_TRUE(database_->ContainsBrowseUrl(
+ GURL("http://www.evil.com/notevil2.html"),
+ &matching_list, &prefix_hits,
+ &full_hashes, now));
+
+ EXPECT_TRUE(database_->ContainsBrowseUrl(
+ GURL("http://www.good.com/good1.html"),
+ &matching_list, &prefix_hits,
+ &full_hashes, now));
+
+ EXPECT_TRUE(database_->ContainsBrowseUrl(
+ GURL("http://www.good.com/good2.html"),
+ &matching_list, &prefix_hits,
+ &full_hashes, now));
+
+ EXPECT_TRUE(database_->ContainsBrowseUrl(
+ GURL("http://192.168.0.1/malware.html"),
+ &matching_list, &prefix_hits,
+ &full_hashes, now));
+
+ EXPECT_FALSE(database_->ContainsBrowseUrl(
+ GURL("http://www.evil.com/"),
+ &matching_list, &prefix_hits,
+ &full_hashes, now));
EXPECT_TRUE(prefix_hits.empty());
- EXPECT_FALSE(database_->ContainsUrl(GURL("http://www.evil.com/robots.txt"),
- &matching_list, &prefix_hits,
- &full_hashes, now));
+ EXPECT_FALSE(database_->ContainsBrowseUrl(
+ GURL("http://www.evil.com/robots.txt"),
+ &matching_list, &prefix_hits,
+ &full_hashes, now));
@@ -464,28 +555,33 @@ TEST_F(SafeBrowsingDatabaseTest, Database) {
database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
database_->UpdateFinished(true);
- EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.evil.com/phishing.html"),
- &matching_list, &prefix_hits,
- &full_hashes, now));
+ EXPECT_TRUE(database_->ContainsBrowseUrl(
+ GURL("http://www.evil.com/phishing.html"),
+ &matching_list, &prefix_hits,
+ &full_hashes, now));
EXPECT_EQ(prefix_hits[0], Sha256Prefix("www.evil.com/phishing.html"));
EXPECT_EQ(prefix_hits.size(), 1U);
- EXPECT_FALSE(database_->ContainsUrl(GURL("http://www.evil.com/notevil1.html"),
- &matching_list, &prefix_hits,
- &full_hashes, now));
+ EXPECT_FALSE(database_->ContainsBrowseUrl(
+ GURL("http://www.evil.com/notevil1.html"),
+ &matching_list, &prefix_hits,
+ &full_hashes, now));
EXPECT_TRUE(prefix_hits.empty());
- EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.evil.com/notevil2.html"),
- &matching_list, &prefix_hits,
- &full_hashes, now));
+ EXPECT_TRUE(database_->ContainsBrowseUrl(
+ GURL("http://www.evil.com/notevil2.html"),
+ &matching_list, &prefix_hits,
+ &full_hashes, now));
- EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.good.com/good1.html"),
- &matching_list, &prefix_hits,
- &full_hashes, now));
+ EXPECT_TRUE(database_->ContainsBrowseUrl(
+ GURL("http://www.good.com/good1.html"),
+ &matching_list, &prefix_hits,
+ &full_hashes, now));
- EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.good.com/good2.html"),
- &matching_list, &prefix_hits,
- &full_hashes, now));
+ EXPECT_TRUE(database_->ContainsBrowseUrl(
+ GURL("http://www.good.com/good2.html"),
+ &matching_list, &prefix_hits,
+ &full_hashes, now));
GetListsInfo(&lists);
EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList);
@@ -520,17 +616,20 @@ TEST_F(SafeBrowsingDatabaseTest, Database) {
AddDelChunk(safe_browsing_util::kMalwareList, 2);
database_->UpdateFinished(true);
- EXPECT_FALSE(database_->ContainsUrl(GURL("http://www.evil.com/notevil2.html"),
- &matching_list, &prefix_hits,
- &full_hashes, now));
+ EXPECT_FALSE(database_->ContainsBrowseUrl(
+ GURL("http://www.evil.com/notevil2.html"),
+ &matching_list, &prefix_hits,
+ &full_hashes, now));
- EXPECT_FALSE(database_->ContainsUrl(GURL("http://www.good.com/good1.html"),
- &matching_list, &prefix_hits,
- &full_hashes, now));
+ EXPECT_FALSE(database_->ContainsBrowseUrl(
+ GURL("http://www.good.com/good1.html"),
+ &matching_list, &prefix_hits,
+ &full_hashes, now));
- EXPECT_FALSE(database_->ContainsUrl(GURL("http://www.good.com/good2.html"),
- &matching_list, &prefix_hits,
- &full_hashes, now));
+ EXPECT_FALSE(database_->ContainsBrowseUrl(
+ GURL("http://www.good.com/good2.html"),
+ &matching_list, &prefix_hits,
+ &full_hashes, now));
GetListsInfo(&lists);
EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList);
@@ -588,7 +687,7 @@ TEST_F(SafeBrowsingDatabaseTest, Database) {
database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
database_->UpdateFinished(true);
- EXPECT_FALSE(database_->ContainsUrl(
+ EXPECT_FALSE(database_->ContainsBrowseUrl(
GURL("http://www.notevilanymore.com/index.html"),
&matching_list, &prefix_hits, &full_hashes, now));
@@ -609,11 +708,11 @@ TEST_F(SafeBrowsingDatabaseTest, Database) {
database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
database_->UpdateFinished(true);
- EXPECT_FALSE(database_->ContainsUrl(
+ EXPECT_FALSE(database_->ContainsBrowseUrl(
GURL("http://www.notevilanymore.com/index.html"),
&matching_list, &prefix_hits, &full_hashes, now));
- EXPECT_FALSE(database_->ContainsUrl(
+ EXPECT_FALSE(database_->ContainsBrowseUrl(
GURL("http://www.notevilanymore.com/good.html"),
&matching_list, &prefix_hits, &full_hashes, now));
}
@@ -712,12 +811,14 @@ TEST_F(SafeBrowsingDatabaseTest, ZeroSizeChunk) {
std::vector<SBFullHashResult> full_hashes;
std::vector<SBPrefix> prefix_hits;
std::string matching_list;
- EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.notempty.com/full1.html"),
- &matching_list, &prefix_hits,
- &full_hashes, now));
- EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.notempty.com/full2.html"),
- &matching_list, &prefix_hits,
- &full_hashes, now));
+ EXPECT_TRUE(database_->ContainsBrowseUrl(
+ GURL("http://www.notempty.com/full1.html"),
+ &matching_list, &prefix_hits,
+ &full_hashes, now));
+ EXPECT_TRUE(database_->ContainsBrowseUrl(
+ GURL("http://www.notempty.com/full2.html"),
+ &matching_list, &prefix_hits,
+ &full_hashes, now));
GetListsInfo(&lists);
EXPECT_EQ(lists[0].adds, "1,10,19-22");
@@ -783,14 +884,15 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) {
PopulateDatabaseForCacheTest();
// We should have both full hashes in the cache.
- EXPECT_EQ(database_->pending_hashes_.size(), 2U);
+ EXPECT_EQ(database_->pending_browse_hashes_.size(), 2U);
// Test the cache lookup for the first prefix.
std::string listname;
std::vector<SBPrefix> prefixes;
std::vector<SBFullHashResult> full_hashes;
- database_->ContainsUrl(GURL("http://www.evil.com/phishing.html"),
- &listname, &prefixes, &full_hashes, Time::Now());
+ database_->ContainsBrowseUrl(
+ GURL("http://www.evil.com/phishing.html"),
+ &listname, &prefixes, &full_hashes, Time::Now());
EXPECT_EQ(full_hashes.size(), 1U);
EXPECT_TRUE(SBFullHashEq(full_hashes[0].hash,
Sha256Hash("www.evil.com/phishing.html")));
@@ -799,8 +901,9 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) {
full_hashes.clear();
// Test the cache lookup for the second prefix.
- database_->ContainsUrl(GURL("http://www.evil.com/malware.html"),
- &listname, &prefixes, &full_hashes, Time::Now());
+ database_->ContainsBrowseUrl(
+ GURL("http://www.evil.com/malware.html"),
+ &listname, &prefixes, &full_hashes, Time::Now());
EXPECT_EQ(full_hashes.size(), 1U);
EXPECT_TRUE(SBFullHashEq(full_hashes[0].hash,
Sha256Hash("www.evil.com/malware.html")));
@@ -830,8 +933,9 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) {
database_->UpdateFinished(true);
// This prefix should still be there.
- database_->ContainsUrl(GURL("http://www.evil.com/malware.html"),
- &listname, &prefixes, &full_hashes, Time::Now());
+ database_->ContainsBrowseUrl(
+ GURL("http://www.evil.com/malware.html"),
+ &listname, &prefixes, &full_hashes, Time::Now());
EXPECT_EQ(full_hashes.size(), 1U);
EXPECT_TRUE(SBFullHashEq(full_hashes[0].hash,
Sha256Hash("www.evil.com/malware.html")));
@@ -840,8 +944,9 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) {
full_hashes.clear();
// This prefix should be gone.
- database_->ContainsUrl(GURL("http://www.evil.com/phishing.html"),
- &listname, &prefixes, &full_hashes, Time::Now());
+ database_->ContainsBrowseUrl(
+ GURL("http://www.evil.com/phishing.html"),
+ &listname, &prefixes, &full_hashes, Time::Now());
EXPECT_TRUE(full_hashes.empty());
prefixes.clear();
@@ -851,11 +956,12 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) {
EXPECT_TRUE(database_->UpdateStarted(&lists));
AddDelChunk(safe_browsing_util::kMalwareList, 1);
database_->UpdateFinished(true);
- database_->ContainsUrl(GURL("http://www.evil.com/malware.html"),
- &listname, &prefixes, &full_hashes, Time::Now());
+ database_->ContainsBrowseUrl(
+ GURL("http://www.evil.com/malware.html"),
+ &listname, &prefixes, &full_hashes, Time::Now());
EXPECT_TRUE(full_hashes.empty());
- EXPECT_TRUE(database_->full_hashes_.empty());
- EXPECT_TRUE(database_->pending_hashes_.empty());
+ EXPECT_TRUE(database_->full_browse_hashes_.empty());
+ EXPECT_TRUE(database_->pending_browse_hashes_.empty());
prefixes.clear();
full_hashes.clear();
@@ -865,7 +971,7 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) {
// cache insert uses Time::Now(). First, store some entries.
PopulateDatabaseForCacheTest();
- std::vector<SBAddFullHash>* hash_cache = &database_->pending_hashes_;
+ std::vector<SBAddFullHash>* hash_cache = &database_->pending_browse_hashes_;
EXPECT_EQ(hash_cache->size(), 2U);
// Now adjust one of the entries times to be in the past.
@@ -880,13 +986,15 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) {
}
EXPECT_TRUE(iter != hash_cache->end());
- database_->ContainsUrl(GURL("http://www.evil.com/malware.html"),
- &listname, &prefixes, &full_hashes, expired);
+ database_->ContainsBrowseUrl(
+ GURL("http://www.evil.com/malware.html"),
+ &listname, &prefixes, &full_hashes, expired);
EXPECT_TRUE(full_hashes.empty());
// This entry should still exist.
- database_->ContainsUrl(GURL("http://www.evil.com/phishing.html"),
- &listname, &prefixes, &full_hashes, expired);
+ database_->ContainsBrowseUrl(
+ GURL("http://www.evil.com/phishing.html"),
+ &listname, &prefixes, &full_hashes, expired);
EXPECT_EQ(full_hashes.size(), 1U);
@@ -921,9 +1029,10 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) {
empty_full_hash.clear();
prefix_misses.push_back(Sha256Prefix("www.evil.com/phishing.html"));
database_->CacheHashResults(prefix_misses, empty_full_hash);
- EXPECT_FALSE(database_->ContainsUrl(GURL("http://www.evil.com/phishing.html"),
- &listname, &prefixes,
- &full_hashes, Time::Now()));
+ EXPECT_FALSE(database_->ContainsBrowseUrl(
+ GURL("http://www.evil.com/phishing.html"),
+ &listname, &prefixes,
+ &full_hashes, Time::Now()));
prefixes.clear();
full_hashes.clear();
@@ -945,18 +1054,20 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) {
database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
database_->UpdateFinished(true);
- EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.fullevil.com/bad1.html"),
- &listname, &prefixes, &full_hashes,
- Time::Now()));
+ EXPECT_TRUE(database_->ContainsBrowseUrl(
+ GURL("http://www.fullevil.com/bad1.html"),
+ &listname, &prefixes, &full_hashes,
+ Time::Now()));
EXPECT_EQ(full_hashes.size(), 1U);
EXPECT_TRUE(SBFullHashEq(full_hashes[0].hash,
Sha256Hash("www.fullevil.com/bad1.html")));
prefixes.clear();
full_hashes.clear();
- EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.fullevil.com/bad2.html"),
- &listname, &prefixes, &full_hashes,
- Time::Now()));
+ EXPECT_TRUE(database_->ContainsBrowseUrl(
+ GURL("http://www.fullevil.com/bad2.html"),
+ &listname, &prefixes, &full_hashes,
+ Time::Now()));
EXPECT_EQ(full_hashes.size(), 1U);
EXPECT_TRUE(SBFullHashEq(full_hashes[0].hash,
Sha256Hash("www.fullevil.com/bad2.html")));
@@ -980,15 +1091,17 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) {
database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
database_->UpdateFinished(true);
- EXPECT_FALSE(database_->ContainsUrl(GURL("http://www.fullevil.com/bad1.html"),
- &listname, &prefixes, &full_hashes,
- Time::Now()));
+ EXPECT_FALSE(database_->ContainsBrowseUrl(
+ GURL("http://www.fullevil.com/bad1.html"),
+ &listname, &prefixes, &full_hashes,
+ Time::Now()));
EXPECT_TRUE(full_hashes.empty());
// There should be one remaining full add.
- EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.fullevil.com/bad2.html"),
- &listname, &prefixes, &full_hashes,
- Time::Now()));
+ EXPECT_TRUE(database_->ContainsBrowseUrl(
+ GURL("http://www.fullevil.com/bad2.html"),
+ &listname, &prefixes, &full_hashes,
+ Time::Now()));
EXPECT_EQ(full_hashes.size(), 1U);
EXPECT_TRUE(SBFullHashEq(full_hashes[0].hash,
Sha256Hash("www.fullevil.com/bad2.html")));
@@ -1000,12 +1113,14 @@ TEST_F(SafeBrowsingDatabaseTest, HashCaching) {
AddDelChunk(safe_browsing_util::kMalwareList, 20);
database_->UpdateFinished(true);
- EXPECT_FALSE(database_->ContainsUrl(GURL("http://www.fullevil.com/bad1.html"),
- &listname, &prefixes, &full_hashes,
- Time::Now()));
- EXPECT_FALSE(database_->ContainsUrl(GURL("http://www.fullevil.com/bad2.html"),
- &listname, &prefixes, &full_hashes,
- Time::Now()));
+ EXPECT_FALSE(database_->ContainsBrowseUrl(
+ GURL("http://www.fullevil.com/bad1.html"),
+ &listname, &prefixes, &full_hashes,
+ Time::Now()));
+ EXPECT_FALSE(database_->ContainsBrowseUrl(
+ GURL("http://www.fullevil.com/bad2.html"),
+ &listname, &prefixes, &full_hashes,
+ Time::Now()));
}
// Test that corrupt databases are appropriately handled, even if the
@@ -1019,7 +1134,7 @@ TEST_F(SafeBrowsingDatabaseTest, DISABLED_SqliteCorruptionHandling) {
database_.reset();
MessageLoop loop(MessageLoop::TYPE_DEFAULT);
SafeBrowsingStoreSqlite* store = new SafeBrowsingStoreSqlite();
- database_.reset(new SafeBrowsingDatabaseNew(store));
+ database_.reset(new SafeBrowsingDatabaseNew(store, NULL));
database_->Init(database_filename_);
// This will cause an empty database to be created.
@@ -1097,7 +1212,7 @@ TEST_F(SafeBrowsingDatabaseTest, DISABLED_FileCorruptionHandling) {
database_.reset();
MessageLoop loop(MessageLoop::TYPE_DEFAULT);
SafeBrowsingStoreFile* store = new SafeBrowsingStoreFile();
- database_.reset(new SafeBrowsingDatabaseNew(store));
+ database_.reset(new SafeBrowsingDatabaseNew(store, NULL));
database_->Init(database_filename_);
// This will cause an empty database to be created.
@@ -1159,3 +1274,65 @@ TEST_F(SafeBrowsingDatabaseTest, DISABLED_FileCorruptionHandling) {
database_.reset();
}
+
+// Checks database reading and writing.
+TEST_F(SafeBrowsingDatabaseTest, ContainsDownloadUrl) {
+ database_.reset();
+ MessageLoop loop(MessageLoop::TYPE_DEFAULT);
+ SafeBrowsingStoreFile* browse_store = new SafeBrowsingStoreFile();
+ SafeBrowsingStoreFile* download_store = new SafeBrowsingStoreFile();
+ database_.reset(new SafeBrowsingDatabaseNew(browse_store, download_store));
+ database_->Init(database_filename_);
+
+ const char kEvil1Host[] = "www.evil1.com/";
+ const char kEvil1Url1[] = "www.evil1.com/download1.html";
+ const char kEvil1Url2[] = "www.evil1.com/download2.html";
+
+ SBChunkList chunks;
+ // Add a simple chunk with one hostkey for download url list.
+ SBChunkHost host;
+ host.host = Sha256Prefix(kEvil1Host);
+ host.entry = SBEntry::Create(SBEntry::ADD_PREFIX, 2);
+ host.entry->set_chunk_id(1);
+ host.entry->SetPrefixAt(0, Sha256Prefix(kEvil1Url1));
+ host.entry->SetPrefixAt(1, Sha256Prefix(kEvil1Url2));
+ SBChunk chunk;
+ chunk.chunk_number = 1;
+ chunk.is_add = true;
+ chunk.hosts.push_back(host);
+ chunks.clear();
+ chunks.push_back(chunk);
+ std::vector<SBListChunkRanges> lists;
+ EXPECT_TRUE(database_->UpdateStarted(&lists));
+ database_->InsertChunks(safe_browsing_util::kBinUrlList, chunks);
+ database_->UpdateFinished(true);
+
+ const Time now = Time::Now();
+ std::vector<SBPrefix> prefix_hits;
+ std::string matching_list;
+
+ EXPECT_TRUE(database_->ContainsDownloadUrl(
+ GURL(std::string("http://") + kEvil1Url1), &prefix_hits));
+ EXPECT_EQ(prefix_hits[0], Sha256Prefix(kEvil1Url1));
+ EXPECT_EQ(prefix_hits.size(), 1U);
+
+ EXPECT_TRUE(database_->ContainsDownloadUrl(
+ GURL(std::string("http://") + kEvil1Url2), &prefix_hits));
+ EXPECT_EQ(prefix_hits[0], Sha256Prefix(kEvil1Url2));
+ EXPECT_EQ(prefix_hits.size(), 1U);
+
+ EXPECT_TRUE(database_->ContainsDownloadUrl(
+ GURL(std::string("https://") + kEvil1Url2), &prefix_hits));
+ EXPECT_EQ(prefix_hits[0], Sha256Prefix(kEvil1Url2));
+ EXPECT_EQ(prefix_hits.size(), 1U);
+
+ EXPECT_TRUE(database_->ContainsDownloadUrl(
+ GURL(std::string("ftp://") + kEvil1Url2), &prefix_hits));
+ EXPECT_EQ(prefix_hits[0], Sha256Prefix(kEvil1Url2));
+ EXPECT_EQ(prefix_hits.size(), 1U);
+
+ EXPECT_FALSE(database_->ContainsDownloadUrl(GURL("http://www.randomevil.com"),
+ &prefix_hits));
+ EXPECT_EQ(prefix_hits.size(), 0U);
+ database_.reset();
+}
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.cc b/chrome/browser/safe_browsing/safe_browsing_service.cc
index dbb28f1..9e24b03 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service.cc
@@ -6,14 +6,15 @@
#include "base/callback.h"
#include "base/command_line.h"
+#include "base/lazy_instance.h"
#include "base/path_service.h"
-#include "base/singleton.h"
#include "base/string_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/safe_browsing/malware_details.h"
#include "chrome/browser/safe_browsing/protocol_manager.h"
#include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
#include "chrome/browser/safe_browsing/safe_browsing_database.h"
@@ -35,11 +36,12 @@ using base::Time;
using base::TimeDelta;
// The default URL prefix where browser fetches chunk updates, hashes,
-// and reports malware.
+// and reports safe browsing hits.
static const char* const kSbDefaultInfoURLPrefix =
"http://safebrowsing.clients.google.com/safebrowsing";
-// The default URL prefix where browser fetches MAC client key.
+// The default URL prefix where browser fetches MAC client key and reports
+// malware details.
static const char* const kSbDefaultMacKeyURLPrefix =
"https://sb-ssl.google.com/safebrowsing";
@@ -62,13 +64,16 @@ class SafeBrowsingServiceFactoryImpl : public SafeBrowsingServiceFactory {
}
private:
- friend struct DefaultSingletonTraits<SafeBrowsingServiceFactoryImpl>;
+ friend struct base::DefaultLazyInstanceTraits<SafeBrowsingServiceFactoryImpl>;
SafeBrowsingServiceFactoryImpl() { }
DISALLOW_COPY_AND_ASSIGN(SafeBrowsingServiceFactoryImpl);
};
+static base::LazyInstance<SafeBrowsingServiceFactoryImpl>
+ g_safe_browsing_service_factory_impl(base::LINKER_INITIALIZED);
+
struct SafeBrowsingService::WhiteListedEntry {
int render_process_host_id;
int render_view_id;
@@ -97,7 +102,7 @@ SafeBrowsingService::SafeBrowsingCheck::~SafeBrowsingCheck() {}
/* static */
SafeBrowsingService* SafeBrowsingService::CreateSafeBrowsingService() {
if (!factory_)
- factory_ = Singleton<SafeBrowsingServiceFactoryImpl>::get();
+ factory_ = g_safe_browsing_service_factory_impl.Pointer();
return factory_->CreateSafeBrowsingService();
}
@@ -105,6 +110,7 @@ SafeBrowsingService::SafeBrowsingService()
: database_(NULL),
protocol_manager_(NULL),
enabled_(false),
+ enable_download_protection_(false),
update_in_progress_(false),
database_update_in_progress_(false),
closing_database_(false) {
@@ -129,7 +135,63 @@ bool SafeBrowsingService::CanCheckUrl(const GURL& url) const {
url.SchemeIs(chrome::kHttpsScheme);
}
-bool SafeBrowsingService::CheckUrl(const GURL& url, Client* client) {
+void SafeBrowsingService::CheckDownloadUrlDone(
+ SafeBrowsingCheck* check, UrlCheckResult result) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(enable_download_protection_);
+ VLOG(1) << "CheckDownloadUrlDone: " << result;
+
+ if (checks_.find(check) == checks_.end() || !check->client)
+ return;
+ check->client->OnSafeBrowsingResult(check->url, result);
+ checks_.erase(check);
+}
+
+void SafeBrowsingService::CheckDownloadUrlOnSBThread(SafeBrowsingCheck* check) {
+ DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
+ DCHECK(enable_download_protection_);
+
+ std::vector<SBPrefix> prefix_hits;
+
+ if (!database_->ContainsDownloadUrl(check->url, &prefix_hits)) {
+ // Good, we don't have hash for this url prefix.
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(this,
+ &SafeBrowsingService::CheckDownloadUrlDone,
+ check, URL_SAFE));
+ return;
+ }
+
+ check->need_get_hash = true;
+ check->prefix_hits.swap(prefix_hits);
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(this, &SafeBrowsingService::OnCheckDone, check));
+}
+
+bool SafeBrowsingService::CheckDownloadUrl(const GURL& url,
+ Client* client) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (!enabled_ || !enable_download_protection_)
+ return true;
+
+ // We need to check the database for url prefix, and later may fetch the url
+ // from the safebrowsing backends. These need to be asynchronous.
+ SafeBrowsingCheck* check = new SafeBrowsingCheck();
+
+ check->url = url;
+ check->client = client;
+ check->result = URL_SAFE;
+ checks_.insert(check);
+ safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &SafeBrowsingService::CheckDownloadUrlOnSBThread, check));
+
+ return false;
+}
+
+bool SafeBrowsingService::CheckBrowseUrl(const GURL& url,
+ Client* client) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (!enabled_)
return true;
@@ -149,9 +211,10 @@ bool SafeBrowsingService::CheckUrl(const GURL& url, Client* client) {
std::vector<SBPrefix> prefix_hits;
std::vector<SBFullHashResult> full_hits;
base::Time check_start = base::Time::Now();
- bool prefix_match = database_->ContainsUrl(url, &list, &prefix_hits,
- &full_hits,
- protocol_manager_->last_update());
+ bool prefix_match =
+ database_->ContainsBrowseUrl(url, &list, &prefix_hits,
+ &full_hits,
+ protocol_manager_->last_update());
UMA_HISTOGRAM_TIMES("SB2.FilterCheck", base::Time::Now() - check_start);
@@ -400,6 +463,11 @@ void SafeBrowsingService::OnIOInitialize(
URLRequestContextGetter* request_context_getter) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
enabled_ = true;
+
+ CommandLine* cmdline = CommandLine::ForCurrentProcess();
+ enable_download_protection_ =
+ cmdline->HasSwitch(switches::kSbEnableDownloadProtection);
+
MakeDatabaseAvailable();
// On Windows, get the safe browsing client name from the browser
@@ -415,7 +483,6 @@ void SafeBrowsingService::OnIOInitialize(
std::string client_name("chromium");
#endif
#endif
- CommandLine* cmdline = CommandLine::ForCurrentProcess();
bool disable_auto_update =
cmdline->HasSwitch(switches::kSbDisableAutoUpdate) ||
cmdline->HasSwitch(switches::kDisableBackgroundNetworking);
@@ -428,14 +495,16 @@ void SafeBrowsingService::OnIOInitialize(
cmdline->GetSwitchValueASCII(switches::kSbMacKeyURLPrefix) :
kSbDefaultMacKeyURLPrefix;
- protocol_manager_ = new SafeBrowsingProtocolManager(this,
- client_name,
- client_key,
- wrapped_key,
- request_context_getter,
- info_url_prefix,
- mackey_url_prefix,
- disable_auto_update);
+ DCHECK(!protocol_manager_);
+ protocol_manager_ =
+ SafeBrowsingProtocolManager::Create(this,
+ client_name,
+ client_key,
+ wrapped_key,
+ request_context_getter,
+ info_url_prefix,
+ mackey_url_prefix,
+ disable_auto_update);
protocol_manager_->Initialize();
}
@@ -456,7 +525,7 @@ void SafeBrowsingService::OnIOShutdown() {
while (!queued_checks_.empty()) {
QueuedCheck check = queued_checks_.front();
if (check.client)
- check.client->OnUrlCheckResult(check.url, URL_SAFE);
+ check.client->OnSafeBrowsingResult(check.url, URL_SAFE);
queued_checks_.pop_front();
}
@@ -480,7 +549,7 @@ void SafeBrowsingService::OnIOShutdown() {
for (CurrentChecks::iterator it = checks_.begin();
it != checks_.end(); ++it) {
if ((*it)->client)
- (*it)->client->OnUrlCheckResult((*it)->url, URL_SAFE);
+ (*it)->client->OnSafeBrowsingResult((*it)->url, URL_SAFE);
delete *it;
}
checks_.clear();
@@ -511,10 +580,13 @@ SafeBrowsingDatabase* SafeBrowsingService::GetDatabase() {
FilePath path;
bool result = PathService::Get(chrome::DIR_USER_DATA, &path);
DCHECK(result);
- path = path.Append(chrome::kSafeBrowsingFilename);
+ path = path.Append(chrome::kSafeBrowsingBaseFilename);
Time before = Time::Now();
- SafeBrowsingDatabase* database = SafeBrowsingDatabase::Create();
+
+ SafeBrowsingDatabase* database =
+ SafeBrowsingDatabase::Create(enable_download_protection_);
+
database->Init(path);
{
// Acquiring the lock here guarantees correct ordering between the writes to
@@ -625,15 +697,14 @@ void SafeBrowsingService::DatabaseLoadComplete() {
// If CheckUrl() determines the URL is safe immediately, it doesn't call the
// client's handler function (because normally it's being directly called by
// the client). Since we're not the client, we have to convey this result.
- if (check.client && CheckUrl(check.url, check.client))
- check.client->OnUrlCheckResult(check.url, URL_SAFE);
+ if (check.client && CheckBrowseUrl(check.url, check.client))
+ check.client->OnSafeBrowsingResult(check.url, URL_SAFE);
queued_checks_.pop_front();
}
}
void SafeBrowsingService::HandleChunkForDatabase(
- const std::string& list_name,
- SBChunkList* chunks) {
+ const std::string& list_name, SBChunkList* chunks) {
DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
if (chunks) {
GetDatabase()->InsertChunks(list_name, *chunks);
@@ -663,6 +734,10 @@ SafeBrowsingService::UrlCheckResult SafeBrowsingService::GetResultFromListname(
return URL_MALWARE;
}
+ if (safe_browsing_util::IsBadbinurlList(list_name)) {
+ return BINARY_MALWARE;
+ }
+
DVLOG(1) << "Unknown safe browsing list " << list_name;
return URL_SAFE;
}
@@ -774,7 +849,7 @@ void SafeBrowsingService::HandleOneCheck(
}
// Let the client continue handling the original request.
- check->client->OnUrlCheckResult(check->url, result);
+ check->client->OnSafeBrowsingResult(check->url, result);
}
checks_.erase(check);
@@ -842,6 +917,8 @@ void SafeBrowsingService::DoDisplayBlockingPage(
SafeBrowsingBlockingPage::ShowBlockingPage(this, resource);
}
+// A safebrowsing hit is sent right after we create a blocking page,
+// only for UMA users.
void SafeBrowsingService::ReportSafeBrowsingHit(
const GURL& malicious_url,
const GURL& page_url,
@@ -859,3 +936,16 @@ void SafeBrowsingService::ReportSafeBrowsingHit(
referrer_url, is_subresource,
threat_type);
}
+
+// A MalwareDetails report is sent after the blocking page is going
+// away, at which point we see if the user had opted-in using the
+// checkbox on the blocking page.
+void SafeBrowsingService::ReportMalwareDetails(
+ scoped_refptr<MalwareDetails> details) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ scoped_ptr<const std::string> serialized(details->GetSerializedReport());
+ if (!serialized->empty()) {
+ DVLOG(1) << "Sending serialized malware details.";
+ protocol_manager_->ReportMalwareDetails(*serialized);
+ }
+}
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.h b/chrome/browser/safe_browsing/safe_browsing_service.h
index 78e1cde..e87fc9c 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service.h
+++ b/chrome/browser/safe_browsing/safe_browsing_service.h
@@ -23,6 +23,7 @@
#include "googleurl/src/gurl.h"
#include "webkit/glue/resource_type.h"
+class MalwareDetails;
class PrefService;
class SafeBrowsingDatabase;
class SafeBrowsingProtocolManager;
@@ -43,18 +44,36 @@ class SafeBrowsingService
URL_SAFE,
URL_PHISHING,
URL_MALWARE,
+ BINARY_MALWARE, // This binary is a malware.
};
class Client {
public:
virtual ~Client() {}
- // Called when the result of checking a URL is known.
- virtual void OnUrlCheckResult(const GURL& url, UrlCheckResult result) = 0;
+ void OnSafeBrowsingResult(const GURL& url, UrlCheckResult result) {
+ OnBrowseUrlCheckResult(url, result);
+ OnDownloadUrlCheckResult(url, result);
+ // TODO(lzheng): This is not implemented yet.
+ // OnDownloadHashCheckResult(url, result);
+ }
// Called when the user has made a decision about how to handle the
// SafeBrowsing interstitial page.
- virtual void OnBlockingPageComplete(bool proceed) = 0;
+ virtual void OnBlockingPageComplete(bool proceed) {}
+
+ protected:
+ // Called when the result of checking a browse URL is known.
+ virtual void OnBrowseUrlCheckResult(const GURL& url,
+ UrlCheckResult result) {}
+
+ // Called when the result of checking a download URL is known.
+ virtual void OnDownloadUrlCheckResult(const GURL& url,
+ UrlCheckResult result) {}
+
+ // Called when the result of checking a download binary hash is known.
+ virtual void OnDownloadHashCheckResult(const GURL& url,
+ UrlCheckResult result) {}
};
// Structure used to pass parameters between the IO and UI thread when
@@ -111,7 +130,11 @@ class SafeBrowsingService
// can synchronously determine that the url is safe, CheckUrl returns true.
// Otherwise it returns false, and "client" is called asynchronously with the
// result when it is ready.
- virtual bool CheckUrl(const GURL& url, Client* client);
+ virtual bool CheckBrowseUrl(const GURL& url, Client* client);
+
+ // Check if the prefix for |url| is in safebrowsing download add lists.
+ // Result will be passed to callback in |client|.
+ bool CheckDownloadUrl(const GURL& url, Client* client);
// Called on the IO thread to cancel a pending check if the result is no
// longer needed.
@@ -181,6 +204,10 @@ class SafeBrowsingService
// the current page is 'safe'.
void LogPauseDelay(base::TimeDelta time);
+ // When a safebrowsing blocking page goes away, it calls this method
+ // so the service can serialize and send MalwareDetails.
+ virtual void ReportMalwareDetails(scoped_refptr<MalwareDetails> details);
+
protected:
// Creates the safe browsing service. Need to initialize before using.
SafeBrowsingService();
@@ -286,14 +313,21 @@ class SafeBrowsingService
// Invoked on the UI thread to show the blocking page.
void DoDisplayBlockingPage(const UnsafeResource& resource);
- // Report any pages that contain malware or phishing to the SafeBrowsing
- // service.
+ // As soon as we create a blocking page, we schedule this method to
+ // report hits to the malware or phishing list to the server.
void ReportSafeBrowsingHit(const GURL& malicious_url,
const GURL& page_url,
const GURL& referrer_url,
bool is_subresource,
UrlCheckResult threat_type);
+ // Invoked by CheckDownloadUrl. It checks the download URL on
+ // safe_browsing_thread_.
+ void CheckDownloadUrlOnSBThread(SafeBrowsingCheck* check);
+
+ // Call the Client's callback in IO thread after CheckDownloadUrl finishes.
+ void CheckDownloadUrlDone(SafeBrowsingCheck* check, UrlCheckResult result);
+
// The factory used to instanciate a SafeBrowsingService object.
// Useful for tests, so they can provide their own implementation of
// SafeBrowsingService.
@@ -320,6 +354,10 @@ class SafeBrowsingService
// on the IO thread during normal operations.
bool enabled_;
+ // Indicate if download_protection is enabled by command switch
+ // so we allow this feature to be exersized.
+ bool enable_download_protection_;
+
// The SafeBrowsing thread that runs database operations.
//
// Note: Functions that run on this thread should run synchronously and return
diff --git a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
new file mode 100644
index 0000000..0b44a25
--- /dev/null
+++ b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
@@ -0,0 +1,393 @@
+// 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.
+//
+// This test creates a safebrowsing service using test safebrowsing database
+// and a test protocol manager. It is used to test logics in safebrowsing
+// service.
+
+#include "base/command_line.h"
+#include "base/metrics/histogram.h"
+#include "base/ref_counted.h"
+#include "base/sha2.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+#include "chrome/browser/safe_browsing/protocol_manager.h"
+#include "chrome/browser/safe_browsing/safe_browsing_database.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
+#include "chrome/browser/safe_browsing/safe_browsing_util.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_contents_view.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/in_process_browser_test.h"
+#include "chrome/test/ui_test_utils.h"
+
+using base::Histogram;
+using base::StatisticsRecorder;
+
+namespace {
+
+// A SafeBrowingDatabase class that allows us to inject the malicious URLs.
+class TestSafeBrowsingDatabase : public SafeBrowsingDatabase {
+ public:
+ TestSafeBrowsingDatabase() {}
+
+ virtual ~TestSafeBrowsingDatabase() {}
+
+ // Initializes the database with the given filename.
+ virtual void Init(const FilePath& filename) {}
+
+ // Deletes the current database and creates a new one.
+ virtual bool ResetDatabase() {
+ badurls_.clear();
+ return true;
+ }
+
+ // Called on the IO thread to check if the given URL is safe or not. If we
+ // can synchronously determine that the URL is safe, CheckUrl returns true,
+ // otherwise it returns false.
+ virtual bool ContainsBrowseUrl(const GURL& url,
+ std::string* matching_list,
+ std::vector<SBPrefix>* prefix_hits,
+ std::vector<SBFullHashResult>* full_hits,
+ base::Time last_update) {
+ return ContainsUrl(safe_browsing_util::kMalwareList,
+ safe_browsing_util::kPhishingList,
+ url, prefix_hits, full_hits);
+ }
+
+ virtual bool ContainsDownloadUrl(const GURL& url,
+ std::vector<SBPrefix>* prefix_hits) {
+ std::vector<SBFullHashResult> full_hits;
+ return ContainsUrl(safe_browsing_util::kBinUrlList,
+ safe_browsing_util::kBinHashList,
+ url, prefix_hits, &full_hits);
+ }
+
+ virtual bool UpdateStarted(std::vector<SBListChunkRanges>* lists) {
+ ADD_FAILURE() << "Not implemented.";
+ return false;
+ }
+ virtual void InsertChunks(const std::string& list_name,
+ const SBChunkList& chunks) {
+ ADD_FAILURE() << "Not implemented.";
+ }
+ virtual void DeleteChunks(const std::vector<SBChunkDelete>& chunk_deletes) {
+ ADD_FAILURE() << "Not implemented.";
+ }
+ virtual void UpdateFinished(bool update_succeeded) {
+ ADD_FAILURE() << "Not implemented.";
+ }
+ virtual void CacheHashResults(const std::vector<SBPrefix>& prefixes,
+ const std::vector<SBFullHashResult>& full_hits) {
+ // Do nothing for the cache.
+ return;
+ }
+
+ // Fill up the database with test URL.
+ void AddUrl(const GURL& url,
+ const std::string& list_name,
+ const std::vector<SBPrefix>& prefix_hits,
+ const std::vector<SBFullHashResult>& full_hits) {
+ badurls_[url.spec()].list_name = list_name;
+ badurls_[url.spec()].prefix_hits = prefix_hits;
+ badurls_[url.spec()].full_hits = full_hits;
+ }
+
+ private:
+ struct Hits {
+ std::string list_name;
+ std::vector<SBPrefix> prefix_hits;
+ std::vector<SBFullHashResult> full_hits;
+ };
+
+ bool ContainsUrl(const std::string& list_name0,
+ const std::string& list_name1,
+ const GURL& url,
+ std::vector<SBPrefix>* prefix_hits,
+ std::vector<SBFullHashResult>* full_hits) {
+ base::hash_map<std::string, Hits>::const_iterator
+ badurls_it = badurls_.find(url.spec());
+
+ if (badurls_it == badurls_.end())
+ return false;
+
+ if (badurls_it->second.list_name == list_name0 ||
+ badurls_it->second.list_name == list_name1) {
+ *prefix_hits = badurls_it->second.prefix_hits;
+ *full_hits = badurls_it->second.full_hits;
+ return true;
+ }
+
+ return false;
+ }
+
+ base::hash_map<std::string, Hits> badurls_;
+};
+
+// Factory that creates TestSafeBrowsingDatabase instances.
+class TestSafeBrowsingDatabaseFactory : public SafeBrowsingDatabaseFactory {
+ public:
+ TestSafeBrowsingDatabaseFactory() : db_(NULL) {}
+ virtual ~TestSafeBrowsingDatabaseFactory() {}
+
+ virtual SafeBrowsingDatabase* CreateSafeBrowsingDatabase(
+ bool enable_download_protection) {
+ db_ = new TestSafeBrowsingDatabase();
+ return db_;
+ }
+ TestSafeBrowsingDatabase* GetDb() {
+ return db_;
+ }
+ private:
+ // Owned by the SafebrowsingService.
+ TestSafeBrowsingDatabase* db_;
+};
+
+
+// A TestProtocolManager that could return fixed responses from
+// safebrowsing server for testing purpose.
+class TestProtocolManager : public SafeBrowsingProtocolManager {
+ public:
+ TestProtocolManager(SafeBrowsingService* sb_service,
+ const std::string& client_name,
+ const std::string& client_key,
+ const std::string& wrapped_key,
+ URLRequestContextGetter* request_context_getter,
+ const std::string& info_url_prefix,
+ const std::string& mackey_url_prefix,
+ bool disable_auto_update)
+ : SafeBrowsingProtocolManager(sb_service, client_name, client_key,
+ wrapped_key, request_context_getter,
+ info_url_prefix, mackey_url_prefix,
+ disable_auto_update),
+ sb_service_(sb_service) {
+ }
+
+ // This function is called when there is a prefix hit in local safebrowsing
+ // database and safebrowsing service issues a get hash request to backends.
+ // We return a result from the prefilled full_hashes_ hash_map to simulate
+ // server's response.
+ virtual void GetFullHash(SafeBrowsingService::SafeBrowsingCheck* check,
+ const std::vector<SBPrefix>& prefixes) {
+ // The hash result should be inserted to the full_hashes_.
+ ASSERT_TRUE(full_hashes_.find(check->url.spec()) != full_hashes_.end());
+ // When we get a valid response, always cache the result.
+ bool cancache = true;
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(
+ sb_service_, &SafeBrowsingService::HandleGetHashResults,
+ check, full_hashes_[check->url.spec()], cancache));
+ }
+
+ // Prepare the GetFullHash results for |url|.
+ void SetGetFullHashResponse(const GURL& url,
+ const SBFullHashResult& full_hash_result) {
+ full_hashes_[url.spec()].push_back(full_hash_result);
+ }
+
+ private:
+ base::hash_map<std::string, std::vector<SBFullHashResult> > full_hashes_;
+ SafeBrowsingService* sb_service_;
+};
+
+// Factory that creates TestProtocolManager instances.
+class TestSBProtocolManagerFactory : public SBProtocolManagerFactory {
+ public:
+ TestSBProtocolManagerFactory() : pm_(NULL) {}
+ virtual ~TestSBProtocolManagerFactory() {}
+
+ virtual SafeBrowsingProtocolManager* CreateProtocolManager(
+ SafeBrowsingService* sb_service,
+ const std::string& client_name,
+ const std::string& client_key,
+ const std::string& wrapped_key,
+ URLRequestContextGetter* request_context_getter,
+ const std::string& info_url_prefix,
+ const std::string& mackey_url_prefix,
+ bool disable_auto_update) {
+ pm_ = new TestProtocolManager(
+ sb_service, client_name, client_key, wrapped_key,
+ request_context_getter, info_url_prefix, mackey_url_prefix,
+ disable_auto_update);
+ return pm_;
+ }
+ TestProtocolManager* GetProtocolManager() {
+ return pm_;
+ }
+ private:
+ // Owned by the SafebrowsingService.
+ TestProtocolManager* pm_;
+};
+
+// Tests the safe browsing blocking page in a browser.
+class SafeBrowsingServiceTest : public InProcessBrowserTest {
+ public:
+ SafeBrowsingServiceTest() {
+ }
+
+ static void GenerateFullhashResult(const GURL& url,
+ const std::string& list_name,
+ int add_chunk_id,
+ SBFullHashResult* full_hash) {
+ std::string host;
+ std::string path;
+ safe_browsing_util::CanonicalizeUrl(url, &host, &path, NULL);
+ base::SHA256HashString(host + path, &full_hash->hash,
+ sizeof(SBFullHash));
+ full_hash->list_name = list_name;
+ full_hash->add_chunk_id = add_chunk_id;
+ }
+
+ virtual void SetUp() {
+ // InProcessBrowserTest::SetUp() intantiates SafebrowsingService and
+ // RegisterFactory has to be called before SafeBrowsingService is created.
+ SafeBrowsingDatabase::RegisterFactory(&db_factory_);
+ SafeBrowsingProtocolManager::RegisterFactory(&pm_factory_);
+
+ InProcessBrowserTest::SetUp();
+ }
+
+ virtual void TearDown() {
+ InProcessBrowserTest::TearDown();
+
+ // Unregister test factories after InProcessBrowserTest::TearDown
+ // (which destructs SafeBrowsingService).
+ SafeBrowsingDatabase::RegisterFactory(NULL);
+ SafeBrowsingProtocolManager::RegisterFactory(NULL);
+ }
+
+ virtual void SetUpCommandLine(CommandLine* command_line) {
+ // Makes sure the auto update is not triggered during the test.
+ // This test will fill up the database using testing prefixes
+ // and urls.
+ command_line->AppendSwitch(switches::kSbDisableAutoUpdate);
+
+ command_line->AppendSwitch(switches::kSbEnableDownloadProtection);
+ }
+
+ virtual void SetUpInProcessBrowserTestFixture() {
+ ASSERT_TRUE(test_server()->Start());
+ }
+
+ // This will setup the prefix in database and prepare protocol manager
+ // to response with |full_hash| for get full hash request.
+ void SetupResponseForUrl(const GURL& url,
+ const SBFullHashResult& full_hash) {
+ std::vector<SBPrefix> prefix_hits;
+ prefix_hits.push_back(full_hash.hash.prefix);
+
+ // Make sure the full hits is empty unless we need to test the
+ // full hash is hit in database's local cache.
+ std::vector<SBFullHashResult> empty_full_hits;
+ TestSafeBrowsingDatabase* db = db_factory_.GetDb();
+ db->AddUrl(url, full_hash.list_name, prefix_hits, empty_full_hits);
+
+ TestProtocolManager* pm = pm_factory_.GetProtocolManager();
+ pm->SetGetFullHashResponse(url, full_hash);
+ }
+
+ bool ShowingInterstitialPage() {
+ TabContents* contents = browser()->GetSelectedTabContents();
+ InterstitialPage* interstitial_page = contents->interstitial_page();
+ return interstitial_page != NULL;
+ }
+
+ private:
+ TestSafeBrowsingDatabaseFactory db_factory_;
+ TestSBProtocolManagerFactory pm_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(SafeBrowsingServiceTest);
+};
+
+const char kEmptyPage[] = "files/empty.html";
+const char kMalwareFile[] = "files/downloads/dangerous/dangerous.exe";
+const char kMalwareIframe[] = "files/safe_browsing/malware_iframe.html";
+const char kMalwarePage[] = "files/safe_browsing/malware.html";
+
+// This test goes through DownloadResourceHandler.
+IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, Malware) {
+ GURL url = test_server()->GetURL(kEmptyPage);
+
+ // After adding the url to safebrowsing database and getfullhash result,
+ // we should see the interstitial page.
+ SBFullHashResult malware_full_hash;
+ int chunk_id = 0;
+ GenerateFullhashResult(url, safe_browsing_util::kMalwareList, chunk_id,
+ &malware_full_hash);
+ SetupResponseForUrl(url, malware_full_hash);
+ ui_test_utils::NavigateToURL(browser(), url);
+ EXPECT_TRUE(ShowingInterstitialPage());
+}
+
+// This test uses SafeBrowsingService::Client to directly interact with
+// SafeBrowsingService.
+class TestSBClient
+ : public base::RefCountedThreadSafe<TestSBClient>,
+ public SafeBrowsingService::Client {
+ public:
+ TestSBClient() : result_(SafeBrowsingService::URL_SAFE),
+ safe_browsing_service_(g_browser_process->
+ resource_dispatcher_host()->
+ safe_browsing_service()) {
+ }
+
+ int GetResult() {
+ return result_;
+ }
+
+ void CheckUrl(const GURL& url) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(this, &TestSBClient::CheckUrlOnIOThread, url));
+ ui_test_utils::RunMessageLoop(); // Will stop in OnDownloadUrlCheckResult.
+ }
+
+ private:
+ void CheckUrlOnIOThread(const GURL& url) {
+ safe_browsing_service_->CheckDownloadUrl(url, this);
+ }
+
+ // Called when the result of checking a download URL is known.
+ void OnDownloadUrlCheckResult(const GURL& url,
+ SafeBrowsingService::UrlCheckResult result) {
+ result_ = result;
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(this, &TestSBClient::DownloadUrlCheckDone));
+ }
+
+ void DownloadUrlCheckDone() {
+ MessageLoopForUI::current()->Quit();
+ }
+
+ SafeBrowsingService::UrlCheckResult result_;
+ SafeBrowsingService* safe_browsing_service_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestSBClient);
+};
+
+IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, CheckDownloadUrl) {
+ GURL badbin_url = test_server()->GetURL(kMalwareFile);
+
+ scoped_refptr<TestSBClient> client(new TestSBClient);
+ client->CheckUrl(badbin_url);
+
+ // Since badbin_url is not in database, it is considered to be safe.
+ EXPECT_EQ(SafeBrowsingService::URL_SAFE, client->GetResult());
+
+ SBFullHashResult badbinurl_full_hash;
+ int chunk_id = 0;
+ GenerateFullhashResult(badbin_url, safe_browsing_util::kBinUrlList,
+ chunk_id, &badbinurl_full_hash);
+ SetupResponseForUrl(badbin_url, badbinurl_full_hash);
+
+ client->CheckUrl(badbin_url);
+
+ // Now, the badbin_url is not safe since it is added to download database.
+ EXPECT_EQ(SafeBrowsingService::BINARY_MALWARE, client->GetResult());
+}
+
+} // namespace
diff --git a/chrome/browser/safe_browsing/safe_browsing_store.cc b/chrome/browser/safe_browsing/safe_browsing_store.cc
index ea5d4f5..c699c13 100644
--- a/chrome/browser/safe_browsing/safe_browsing_store.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_store.cc
@@ -6,6 +6,8 @@
#include <algorithm>
+#include "base/metrics/histogram.h"
+
namespace {
// Find items matching between |subs| and |adds|, and remove them,
@@ -119,8 +121,49 @@ void RemoveDeleted(std::vector<T>* vec, const base::hash_set<int32>& del_set) {
vec->erase(add_iter, vec->end());
}
+enum MissTypes {
+ MISS_TYPE_ALL,
+ MISS_TYPE_FALSE,
+
+ // Always at the end.
+ MISS_TYPE_MAX
+};
+
} // namespace
+void SBCheckPrefixMisses(const std::vector<SBAddPrefix>& add_prefixes,
+ const std::set<SBPrefix>& prefix_misses) {
+ if (prefix_misses.empty())
+ return;
+
+ // Record a hit for all prefixes which missed when sent to the
+ // server.
+ for (size_t i = 0; i < prefix_misses.size(); ++i) {
+ UMA_HISTOGRAM_ENUMERATION("SB2.BloomFilterFalsePositives",
+ MISS_TYPE_ALL, MISS_TYPE_MAX);
+ }
+
+ // Collect the misses which are not present in |add_prefixes|.
+ // Since |add_prefixes| can contain multiple copies of the same
+ // prefix, it is not sufficient to count the number of elements
+ // present in both collections.
+ std::set<SBPrefix> false_misses(prefix_misses.begin(), prefix_misses.end());
+ for (size_t i = 0; i < add_prefixes.size(); ++i) {
+ // |erase()| on an absent element should cost like |find()|.
+ false_misses.erase(add_prefixes[i].prefix);
+ }
+
+ // Record a hit for prefixes which we shouldn't have sent in the
+ // first place.
+ for (size_t i = 0; i < false_misses.size(); ++i) {
+ UMA_HISTOGRAM_ENUMERATION("SB2.BloomFilterFalsePositives",
+ MISS_TYPE_FALSE, MISS_TYPE_MAX);
+ }
+
+ // Divide |MISS_TYPE_FALSE| by |MISS_TYPE_ALL| to get the
+ // bloom-filter false-positive rate.
+}
+
void SBProcessSubs(std::vector<SBAddPrefix>* add_prefixes,
std::vector<SBSubPrefix>* sub_prefixes,
std::vector<SBAddFullHash>* add_full_hashes,
diff --git a/chrome/browser/safe_browsing/safe_browsing_store.h b/chrome/browser/safe_browsing/safe_browsing_store.h
index 418c55f..b099d9f 100644
--- a/chrome/browser/safe_browsing/safe_browsing_store.h
+++ b/chrome/browser/safe_browsing/safe_browsing_store.h
@@ -6,6 +6,7 @@
#define CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_STORE_H_
#pragma once
+#include <set>
#include <vector>
#include "base/basictypes.h"
@@ -145,6 +146,11 @@ void SBProcessSubs(std::vector<SBAddPrefix>* add_prefixes,
const base::hash_set<int32>& add_chunks_deleted,
const base::hash_set<int32>& sub_chunks_deleted);
+// Records a histogram of the number of items in |prefix_misses| which
+// are not in |add_prefixes|.
+void SBCheckPrefixMisses(const std::vector<SBAddPrefix>& add_prefixes,
+ const std::set<SBPrefix>& prefix_misses);
+
// TODO(shess): This uses int32 rather than int because it's writing
// specifically-sized items to files. SBPrefix should likewise be
// explicitly sized.
@@ -168,6 +174,9 @@ class SafeBrowsingStore {
// successful.
virtual bool Delete() = 0;
+ // Get all Add prefixes out from the store.
+ virtual bool GetAddPrefixes(std::vector<SBAddPrefix>* add_prefixes) = 0;
+
// Start an update. None of the following methods should be called
// unless this returns true. If this returns true, the update
// should be terminated by FinishUpdate() or CancelUpdate().
@@ -212,9 +221,12 @@ class SafeBrowsingStore {
// |pending_adds| is the set of full hashes which have been received
// since the previous update, and is provided as a convenience
// (could be written via WriteAddHash(), but that would flush the
- // chunk to disk).
+ // chunk to disk). |prefix_misses| is the set of prefixes where the
+ // |GetHash()| request returned no full hashes, used for diagnostic
+ // purposes.
virtual bool FinishUpdate(
const std::vector<SBAddFullHash>& pending_adds,
+ const std::set<SBPrefix>& prefix_misses,
std::vector<SBAddPrefix>* add_prefixes_result,
std::vector<SBAddFullHash>* add_full_hashes_result) = 0;
diff --git a/chrome/browser/safe_browsing/safe_browsing_store_file.cc b/chrome/browser/safe_browsing/safe_browsing_store_file.cc
index 493e397..cc8ae87 100644
--- a/chrome/browser/safe_browsing/safe_browsing_store_file.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_store_file.cc
@@ -40,6 +40,18 @@ bool FileRewind(FILE* fp) {
return rv == 0;
}
+// Move file read pointer forward by |bytes| relative to current position.
+bool FileSkip(size_t bytes, FILE* fp) {
+ // Although fseek takes negative values, for this case, we only want
+ // to skip forward.
+ DCHECK(static_cast<long>(bytes) >= 0);
+ if (static_cast<long>(bytes) < 0)
+ return false;
+ int rv = fseek(fp, static_cast<long>(bytes), SEEK_CUR);
+ DCHECK_EQ(rv, 0);
+ return rv == 0;
+}
+
// Read an array of |nmemb| items from |fp| into |ptr|, and fold the
// input data into the checksum in |context|, if non-NULL. Return
// true on success.
@@ -169,6 +181,21 @@ bool FileHeaderSanityCheck(const FilePath& filename,
return true;
}
+// This a helper function that reads header to |header|. Returns true if the
+// magic number is correct and santiy check passes.
+bool ReadAndVerifyHeader(const FilePath& filename,
+ FILE* fp,
+ FileHeader* header,
+ MD5Context* context) {
+ if (!ReadArray(header, 1, fp, context))
+ return false;
+ if (header->magic != kFileMagic || header->version != kFileVersion)
+ return false;
+ if (!FileHeaderSanityCheck(filename, *header))
+ return false;
+ return true;
+}
+
} // namespace
// static
@@ -263,6 +290,28 @@ bool SafeBrowsingStoreFile::WriteAddPrefix(int32 chunk_id, SBPrefix prefix) {
return true;
}
+bool SafeBrowsingStoreFile::GetAddPrefixes(
+ std::vector<SBAddPrefix>* add_prefixes) {
+ add_prefixes->clear();
+
+ file_util::ScopedFILE file(file_util::OpenFile(filename_, "rb"));
+ if (file.get() == NULL) return false;
+
+ FileHeader header;
+ if (!ReadAndVerifyHeader(filename_, file.get(), &header, NULL))
+ return OnCorruptDatabase();
+
+ size_t add_prefix_offset = header.add_chunk_count * sizeof(int32) +
+ header.sub_chunk_count * sizeof(int32);
+ if (!FileSkip(add_prefix_offset, file.get()))
+ return false;
+
+ if (!ReadToVector(add_prefixes, header.add_prefix_count, file.get(), NULL))
+ return false;
+
+ return true;
+}
+
bool SafeBrowsingStoreFile::WriteAddHash(int32 chunk_id,
base::Time receive_time,
const SBFullHash& full_hash) {
@@ -437,10 +486,13 @@ bool SafeBrowsingStoreFile::FinishChunk() {
bool SafeBrowsingStoreFile::DoUpdate(
const std::vector<SBAddFullHash>& pending_adds,
+ const std::set<SBPrefix>& prefix_misses,
std::vector<SBAddPrefix>* add_prefixes_result,
std::vector<SBAddFullHash>* add_full_hashes_result) {
DCHECK(old_store_.get() || file_.get() || empty_);
DCHECK(new_file_.get());
+ CHECK(add_prefixes_result);
+ CHECK(add_full_hashes_result);
std::vector<SBAddPrefix> add_prefixes;
std::vector<SBSubPrefix> sub_prefixes;
@@ -470,7 +522,6 @@ bool SafeBrowsingStoreFile::DoUpdate(
if (!old_store_->CancelUpdate())
return OnCorruptDatabase();
} else if (!empty_) {
- // Read |file_| into the vectors.
DCHECK(file_.get());
if (!FileRewind(file_.get()))
@@ -481,13 +532,7 @@ bool SafeBrowsingStoreFile::DoUpdate(
// Read the file header and make sure it looks right.
FileHeader header;
- if (!ReadArray(&header, 1, file_.get(), &context))
- return OnCorruptDatabase();
-
- if (header.magic != kFileMagic || header.version != kFileVersion)
- return OnCorruptDatabase();
-
- if (!FileHeaderSanityCheck(filename_, header))
+ if (!ReadAndVerifyHeader(filename_, file_.get(), &header, &context))
return OnCorruptDatabase();
// Re-read the chunks-seen data to get to the later data in the
@@ -517,6 +562,7 @@ bool SafeBrowsingStoreFile::DoUpdate(
MD5Digest file_digest;
if (!ReadArray(&file_digest, 1, file_.get(), NULL))
return OnCorruptDatabase();
+
if (0 != memcmp(&file_digest, &calculated_digest, sizeof(file_digest)))
return OnCorruptDatabase();
@@ -577,6 +623,10 @@ bool SafeBrowsingStoreFile::DoUpdate(
add_full_hashes.insert(add_full_hashes.end(),
pending_adds.begin(), pending_adds.end());
+ // Check how often a prefix was checked which wasn't in the
+ // database.
+ SBCheckPrefixMisses(add_prefixes, prefix_misses);
+
// Knock the subs from the adds and process deleted chunks.
SBProcessSubs(&add_prefixes, &sub_prefixes,
&add_full_hashes, &sub_full_hashes,
@@ -658,9 +708,13 @@ bool SafeBrowsingStoreFile::DoUpdate(
bool SafeBrowsingStoreFile::FinishUpdate(
const std::vector<SBAddFullHash>& pending_adds,
+ const std::set<SBPrefix>& prefix_misses,
std::vector<SBAddPrefix>* add_prefixes_result,
std::vector<SBAddFullHash>* add_full_hashes_result) {
- bool ret = DoUpdate(pending_adds,
+ DCHECK(add_prefixes_result);
+ DCHECK(add_full_hashes_result);
+
+ bool ret = DoUpdate(pending_adds, prefix_misses,
add_prefixes_result, add_full_hashes_result);
if (!ret) {
diff --git a/chrome/browser/safe_browsing/safe_browsing_store_file.h b/chrome/browser/safe_browsing/safe_browsing_store_file.h
index 0875cc8..02a2920 100644
--- a/chrome/browser/safe_browsing/safe_browsing_store_file.h
+++ b/chrome/browser/safe_browsing/safe_browsing_store_file.h
@@ -124,7 +124,11 @@ class SafeBrowsingStoreFile : public SafeBrowsingStore {
// Delete any on-disk files, including the permanent storage.
virtual bool Delete();
+ // Get all Add prefixes from the store.
+ virtual bool GetAddPrefixes(std::vector<SBAddPrefix>* add_prefixes);
+
virtual bool BeginChunk();
+
virtual bool WriteAddPrefix(int32 chunk_id, SBPrefix prefix);
virtual bool WriteAddHash(int32 chunk_id,
base::Time receive_time,
@@ -136,10 +140,10 @@ class SafeBrowsingStoreFile : public SafeBrowsingStore {
virtual bool FinishChunk();
virtual bool BeginUpdate();
- virtual bool DoUpdate(const std::vector<SBAddFullHash>& pending_adds,
- std::vector<SBAddPrefix>* add_prefixes_result,
- std::vector<SBAddFullHash>* add_full_hashes_result);
+ // Store updates with pending add full hashes in file store and
+ // return |add_prefixes_result| and |add_full_hashes_result|.
virtual bool FinishUpdate(const std::vector<SBAddFullHash>& pending_adds,
+ const std::set<SBPrefix>& prefix_misses,
std::vector<SBAddPrefix>* add_prefixes_result,
std::vector<SBAddFullHash>* add_full_hashes_result);
virtual bool CancelUpdate();
@@ -161,6 +165,11 @@ class SafeBrowsingStoreFile : public SafeBrowsingStore {
}
private:
+ // Update store file with pending full hashes.
+ virtual bool DoUpdate(const std::vector<SBAddFullHash>& pending_adds,
+ const std::set<SBPrefix>& prefix_misses,
+ std::vector<SBAddPrefix>* add_prefixes_result,
+ std::vector<SBAddFullHash>* add_full_hashes_result);
// Enumerate different format-change events for histogramming
// purposes. DO NOT CHANGE THE ORDERING OF THESE VALUES.
// TODO(shess): Remove this once the format change is complete.
diff --git a/chrome/browser/safe_browsing/safe_browsing_store_file_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_store_file_unittest.cc
index 74dfc4f..01977a7 100644
--- a/chrome/browser/safe_browsing/safe_browsing_store_file_unittest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_store_file_unittest.cc
@@ -99,10 +99,11 @@ TEST_F(SafeBrowsingStoreFileTest, DetectsCorruption) {
// Can successfully open and read the store.
std::vector<SBAddFullHash> pending_adds;
+ std::set<SBPrefix> prefix_misses;
std::vector<SBAddPrefix> orig_prefixes;
std::vector<SBAddFullHash> orig_hashes;
EXPECT_TRUE(test_store.BeginUpdate());
- EXPECT_TRUE(test_store.FinishUpdate(pending_adds,
+ EXPECT_TRUE(test_store.FinishUpdate(pending_adds, prefix_misses,
&orig_prefixes, &orig_hashes));
EXPECT_GT(orig_prefixes.size(), 0U);
EXPECT_GT(orig_hashes.size(), 0U);
@@ -125,7 +126,7 @@ TEST_F(SafeBrowsingStoreFileTest, DetectsCorruption) {
std::vector<SBAddFullHash> add_hashes;
corruption_detected_ = false;
EXPECT_TRUE(test_store.BeginUpdate());
- EXPECT_FALSE(test_store.FinishUpdate(pending_adds,
+ EXPECT_FALSE(test_store.FinishUpdate(pending_adds, prefix_misses,
&add_prefixes, &add_hashes));
EXPECT_TRUE(corruption_detected_);
EXPECT_EQ(add_prefixes.size(), 0U);
@@ -178,10 +179,24 @@ void LoadStore(SafeBrowsingStore* store) {
EXPECT_TRUE(store->FinishChunk());
std::vector<SBAddFullHash> pending_adds;
+ std::set<SBPrefix> prefix_misses;
std::vector<SBAddPrefix> add_prefixes;
std::vector<SBAddFullHash> add_hashes;
- EXPECT_TRUE(store->FinishUpdate(pending_adds, &add_prefixes, &add_hashes));
+ EXPECT_TRUE(store->FinishUpdate(pending_adds, prefix_misses,
+ &add_prefixes, &add_hashes));
EXPECT_EQ(3U, add_prefixes.size());
+ EXPECT_EQ(1U, add_hashes.size());
+
+ // Make sure add prefixes are correct.
+ std::vector<SBAddPrefix> in_store_add_prefixes;
+ EXPECT_TRUE(store->GetAddPrefixes(&in_store_add_prefixes));
+ ASSERT_EQ(3U, in_store_add_prefixes.size());
+ EXPECT_EQ(kPrefix1, in_store_add_prefixes[0].prefix);
+ EXPECT_EQ(kAddChunk1, in_store_add_prefixes[0].chunk_id);
+ EXPECT_EQ(kPrefix2, in_store_add_prefixes[1].prefix);
+ EXPECT_EQ(kAddChunk1, in_store_add_prefixes[1].chunk_id);
+ EXPECT_EQ(kPrefix3, in_store_add_prefixes[2].prefix);
+ EXPECT_EQ(kAddChunk2, in_store_add_prefixes[2].chunk_id);
}
// Verify that the store looks like what results from LoadStore(), and
@@ -221,10 +236,13 @@ void UpdateStore(SafeBrowsingStore* store) {
store->DeleteAddChunk(kAddChunk2);
std::vector<SBAddFullHash> pending_adds;
+ std::set<SBPrefix> prefix_misses;
std::vector<SBAddPrefix> add_prefixes;
std::vector<SBAddFullHash> add_hashes;
- EXPECT_TRUE(store->FinishUpdate(pending_adds, &add_prefixes, &add_hashes));
+ EXPECT_TRUE(store->FinishUpdate(pending_adds, prefix_misses,
+ &add_prefixes, &add_hashes));
EXPECT_EQ(2U, add_prefixes.size());
+ EXPECT_EQ(0U, add_hashes.size());
}
// Verify that the expected UpdateStore() data is present.
@@ -245,6 +263,15 @@ void CheckStore(SafeBrowsingStore* store) {
EXPECT_EQ(kSubChunk2, sub_chunks[1]);
EXPECT_TRUE(store->CancelUpdate());
+
+ // Make sure add prefixes are correct.
+ std::vector<SBAddPrefix> add_prefixes;
+ EXPECT_TRUE(store->GetAddPrefixes(&add_prefixes));
+ ASSERT_EQ(2U, add_prefixes.size());
+ EXPECT_EQ(kPrefix2, add_prefixes[0].prefix);
+ EXPECT_EQ(kAddChunk1, add_prefixes[0].chunk_id);
+ EXPECT_EQ(kPrefix5, add_prefixes[1].prefix);
+ EXPECT_EQ(kAddChunk3, add_prefixes[1].chunk_id);
}
// Verify that the migration sequence works as expected in the
diff --git a/chrome/browser/safe_browsing/safe_browsing_store_sqlite.cc b/chrome/browser/safe_browsing/safe_browsing_store_sqlite.cc
index 8deeff4..c9cf026 100644
--- a/chrome/browser/safe_browsing/safe_browsing_store_sqlite.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_store_sqlite.cc
@@ -84,6 +84,52 @@ void SafeBrowsingStoreSqlite::Init(const FilePath& filename,
corruption_callback_.reset(corruption_callback);
}
+bool SafeBrowsingStoreSqlite::BeginChunk() {
+ return true;
+}
+
+bool SafeBrowsingStoreSqlite::GetAddPrefixes(
+ std::vector<SBAddPrefix>* add_prefixes) {
+ add_prefixes->clear();
+ if (!Open()) return false;
+ bool ret = ReadAddPrefixes(add_prefixes);
+ Close();
+ return ret;
+}
+
+bool SafeBrowsingStoreSqlite::WriteAddPrefix(int32 chunk_id, SBPrefix prefix) {
+ const std::vector<SBAddPrefix> prefixes(1, SBAddPrefix(chunk_id, prefix));
+ return WriteAddPrefixes(prefixes);
+}
+
+bool SafeBrowsingStoreSqlite::WriteAddHash(int32 chunk_id,
+ base::Time receive_time,
+ const SBFullHash& full_hash) {
+ const std::vector<SBAddFullHash>
+ hashes(1, SBAddFullHash(chunk_id, receive_time, full_hash));
+ return WriteAddHashes(hashes);
+}
+
+bool SafeBrowsingStoreSqlite::WriteSubPrefix(int32 chunk_id,
+ int32 add_chunk_id,
+ SBPrefix prefix) {
+ const std::vector<SBSubPrefix>
+ prefixes(1, SBSubPrefix(chunk_id, add_chunk_id, prefix));
+ return WriteSubPrefixes(prefixes);
+}
+
+bool SafeBrowsingStoreSqlite::WriteSubHash(int32 chunk_id,
+ int32 add_chunk_id,
+ const SBFullHash& full_hash) {
+ const std::vector<SBSubFullHash>
+ hashes(1, SBSubFullHash(chunk_id, add_chunk_id, full_hash));
+ return WriteSubHashes(hashes);
+}
+
+bool SafeBrowsingStoreSqlite::FinishChunk() {
+ return true;
+}
+
bool SafeBrowsingStoreSqlite::OnCorruptDatabase() {
if (corruption_callback_.get())
corruption_callback_->Run();
@@ -645,6 +691,7 @@ bool SafeBrowsingStoreSqlite::DoUpdate(
bool SafeBrowsingStoreSqlite::FinishUpdate(
const std::vector<SBAddFullHash>& pending_adds,
+ const std::set<SBPrefix>& prefix_misses,
std::vector<SBAddPrefix>* add_prefixes_result,
std::vector<SBAddFullHash>* add_full_hashes_result) {
bool ret = DoUpdate(pending_adds,
@@ -660,3 +707,43 @@ bool SafeBrowsingStoreSqlite::FinishUpdate(
bool SafeBrowsingStoreSqlite::CancelUpdate() {
return Close();
}
+
+void SafeBrowsingStoreSqlite::SetAddChunk(int32 chunk_id) {
+ add_chunks_cache_.insert(chunk_id);
+}
+
+bool SafeBrowsingStoreSqlite::CheckAddChunk(int32 chunk_id) {
+ return add_chunks_cache_.count(chunk_id) > 0;
+}
+
+void SafeBrowsingStoreSqlite::GetAddChunks(std::vector<int32>* out) {
+ out->clear();
+ out->insert(out->end(), add_chunks_cache_.begin(), add_chunks_cache_.end());
+}
+
+void SafeBrowsingStoreSqlite::SetSubChunk(int32 chunk_id) {
+ sub_chunks_cache_.insert(chunk_id);
+}
+
+bool SafeBrowsingStoreSqlite::CheckSubChunk(int32 chunk_id) {
+ return sub_chunks_cache_.count(chunk_id) > 0;
+}
+
+void SafeBrowsingStoreSqlite::GetSubChunks(std::vector<int32>* out) {
+ out->clear();
+ out->insert(out->end(), sub_chunks_cache_.begin(), sub_chunks_cache_.end());
+}
+
+void SafeBrowsingStoreSqlite::DeleteAddChunk(int32 chunk_id) {
+ add_del_cache_.insert(chunk_id);
+}
+
+void SafeBrowsingStoreSqlite::DeleteSubChunk(int32 chunk_id) {
+ sub_del_cache_.insert(chunk_id);
+}
+
+// static
+const FilePath SafeBrowsingStoreSqlite::JournalFileForFilename(
+ const FilePath& filename) {
+ return FilePath(filename.value() + FILE_PATH_LITERAL("-journal"));
+}
diff --git a/chrome/browser/safe_browsing/safe_browsing_store_sqlite.h b/chrome/browser/safe_browsing/safe_browsing_store_sqlite.h
index 60e7fda..f9d4381 100644
--- a/chrome/browser/safe_browsing/safe_browsing_store_sqlite.h
+++ b/chrome/browser/safe_browsing/safe_browsing_store_sqlite.h
@@ -29,80 +29,47 @@ class SafeBrowsingStoreSqlite : public SafeBrowsingStore {
virtual void Init(const FilePath& filename,
Callback0::Type* corruption_callback);
- virtual bool BeginChunk() {
- return true;
- }
- virtual bool WriteAddPrefix(int32 chunk_id, SBPrefix prefix) {
- const std::vector<SBAddPrefix> prefixes(1, SBAddPrefix(chunk_id, prefix));
- return WriteAddPrefixes(prefixes);
- }
+ virtual bool BeginChunk();
+
+ // Get all Add prefixes out from the store.
+ virtual bool GetAddPrefixes(std::vector<SBAddPrefix>* add_prefixes);
+ virtual bool WriteAddPrefix(int32 chunk_id, SBPrefix prefix);
virtual bool WriteAddHash(int32 chunk_id,
base::Time receive_time,
- const SBFullHash& full_hash) {
- const std::vector<SBAddFullHash>
- hashes(1, SBAddFullHash(chunk_id, receive_time, full_hash));
- return WriteAddHashes(hashes);
- }
+ const SBFullHash& full_hash);
virtual bool WriteSubPrefix(int32 chunk_id,
- int32 add_chunk_id, SBPrefix prefix) {
- const std::vector<SBSubPrefix>
- prefixes(1, SBSubPrefix(chunk_id, add_chunk_id, prefix));
- return WriteSubPrefixes(prefixes);
- }
+ int32 add_chunk_id, SBPrefix prefix);
virtual bool WriteSubHash(int32 chunk_id, int32 add_chunk_id,
- const SBFullHash& full_hash) {
- const std::vector<SBSubFullHash>
- hashes(1, SBSubFullHash(chunk_id, add_chunk_id, full_hash));
- return WriteSubHashes(hashes);
- }
- virtual bool FinishChunk() {
- return true;
- }
+ const SBFullHash& full_hash);
+ virtual bool FinishChunk();
virtual bool BeginUpdate();
// TODO(shess): Should not be public.
virtual bool DoUpdate(const std::vector<SBAddFullHash>& pending_adds,
std::vector<SBAddPrefix>* add_prefixes_result,
std::vector<SBAddFullHash>* add_full_hashes_result);
+ // NOTE: |prefix_misses| is ignored, as it will be handled in
+ // |SafeBrowsingStoreFile::DoUpdate()|.
virtual bool FinishUpdate(const std::vector<SBAddFullHash>& pending_adds,
+ const std::set<SBPrefix>& prefix_misses,
std::vector<SBAddPrefix>* add_prefixes_result,
std::vector<SBAddFullHash>* add_full_hashes_result);
virtual bool CancelUpdate();
- virtual void SetAddChunk(int32 chunk_id) {
- add_chunks_cache_.insert(chunk_id);
- }
- virtual bool CheckAddChunk(int32 chunk_id) {
- return add_chunks_cache_.count(chunk_id) > 0;
- }
- virtual void GetAddChunks(std::vector<int32>* out) {
- out->clear();
- out->insert(out->end(), add_chunks_cache_.begin(), add_chunks_cache_.end());
- }
-
- virtual void SetSubChunk(int32 chunk_id) {
- sub_chunks_cache_.insert(chunk_id);
- }
- virtual bool CheckSubChunk(int32 chunk_id) {
- return sub_chunks_cache_.count(chunk_id) > 0;
- }
- virtual void GetSubChunks(std::vector<int32>* out) {
- out->clear();
- out->insert(out->end(), sub_chunks_cache_.begin(), sub_chunks_cache_.end());
- }
-
- virtual void DeleteAddChunk(int32 chunk_id) {
- add_del_cache_.insert(chunk_id);
- }
- virtual void DeleteSubChunk(int32 chunk_id) {
- sub_del_cache_.insert(chunk_id);
- }
+ virtual void SetAddChunk(int32 chunk_id);
+ virtual bool CheckAddChunk(int32 chunk_id);
+ virtual void GetAddChunks(std::vector<int32>* out);
+
+ virtual void SetSubChunk(int32 chunk_id);
+ virtual bool CheckSubChunk(int32 chunk_id);
+ virtual void GetSubChunks(std::vector<int32>* out);
+
+ virtual void DeleteAddChunk(int32 chunk_id);
+ virtual void DeleteSubChunk(int32 chunk_id);
// Returns the name of the SQLite journal file for |filename|.
// Exported for unit tests.
- static const FilePath JournalFileForFilename(const FilePath& filename) {
- return FilePath(filename.value() + FILE_PATH_LITERAL("-journal"));
- }
+ static const FilePath JournalFileForFilename(const FilePath& filename);
private:
// For on-the-fly migration.
diff --git a/chrome/browser/safe_browsing/safe_browsing_store_unittest_helper.cc b/chrome/browser/safe_browsing/safe_browsing_store_unittest_helper.cc
index d8ae136..b88efe7 100644
--- a/chrome/browser/safe_browsing/safe_browsing_store_unittest_helper.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_store_unittest_helper.cc
@@ -44,10 +44,12 @@ void SafeBrowsingStoreTestEmpty(SafeBrowsingStore* store) {
EXPECT_FALSE(store->CheckSubChunk(-1));
std::vector<SBAddFullHash> pending_adds;
+ std::set<SBPrefix> prefix_misses;
std::vector<SBAddPrefix> add_prefixes_result;
std::vector<SBAddFullHash> add_full_hashes_result;
EXPECT_TRUE(store->FinishUpdate(pending_adds,
+ prefix_misses,
&add_prefixes_result,
&add_full_hashes_result));
EXPECT_TRUE(add_prefixes_result.empty());
@@ -87,10 +89,12 @@ void SafeBrowsingStoreTestStorePrefix(SafeBrowsingStore* store) {
EXPECT_EQ(kSubChunk1, chunks[0]);
std::vector<SBAddFullHash> pending_adds;
+ std::set<SBPrefix> prefix_misses;
std::vector<SBAddPrefix> add_prefixes_result;
std::vector<SBAddFullHash> add_full_hashes_result;
EXPECT_TRUE(store->FinishUpdate(pending_adds,
+ prefix_misses,
&add_prefixes_result,
&add_full_hashes_result));
@@ -124,6 +128,7 @@ void SafeBrowsingStoreTestStorePrefix(SafeBrowsingStore* store) {
EXPECT_TRUE(store->CheckSubChunk(kSubChunk1));
EXPECT_TRUE(store->FinishUpdate(pending_adds,
+ prefix_misses,
&add_prefixes_result,
&add_full_hashes_result));
@@ -157,10 +162,12 @@ void SafeBrowsingStoreTestSubKnockout(SafeBrowsingStore* store) {
EXPECT_TRUE(store->FinishChunk());
std::vector<SBAddFullHash> pending_adds;
+ std::set<SBPrefix> prefix_misses;
std::vector<SBAddPrefix> add_prefixes_result;
std::vector<SBAddFullHash> add_full_hashes_result;
EXPECT_TRUE(store->FinishUpdate(pending_adds,
+ prefix_misses,
&add_prefixes_result,
&add_full_hashes_result));
@@ -181,6 +188,7 @@ void SafeBrowsingStoreTestSubKnockout(SafeBrowsingStore* store) {
EXPECT_TRUE(store->FinishChunk());
EXPECT_TRUE(store->FinishUpdate(pending_adds,
+ prefix_misses,
&add_prefixes_result,
&add_full_hashes_result));
EXPECT_EQ(1U, add_prefixes_result.size());
@@ -199,6 +207,7 @@ void SafeBrowsingStoreTestSubKnockout(SafeBrowsingStore* store) {
EXPECT_TRUE(store->FinishChunk());
EXPECT_TRUE(store->FinishUpdate(pending_adds,
+ prefix_misses,
&add_prefixes_result,
&add_full_hashes_result));
ASSERT_EQ(2U, add_prefixes_result.size());
@@ -257,10 +266,12 @@ void SafeBrowsingStoreTestDeleteChunks(SafeBrowsingStore* store) {
EXPECT_TRUE(store->CheckSubChunk(kSubChunk2));
std::vector<SBAddFullHash> pending_adds;
+ std::set<SBPrefix> prefix_misses;
std::vector<SBAddPrefix> add_prefixes_result;
std::vector<SBAddFullHash> add_full_hashes_result;
EXPECT_TRUE(store->FinishUpdate(pending_adds,
+ prefix_misses,
&add_prefixes_result,
&add_full_hashes_result));
@@ -286,6 +297,7 @@ void SafeBrowsingStoreTestDeleteChunks(SafeBrowsingStore* store) {
add_prefixes_result.clear();
add_full_hashes_result.clear();
EXPECT_TRUE(store->FinishUpdate(pending_adds,
+ prefix_misses,
&add_prefixes_result,
&add_full_hashes_result));
@@ -298,6 +310,7 @@ void SafeBrowsingStoreTestDeleteChunks(SafeBrowsingStore* store) {
add_prefixes_result.clear();
add_full_hashes_result.clear();
EXPECT_TRUE(store->FinishUpdate(pending_adds,
+ prefix_misses,
&add_prefixes_result,
&add_full_hashes_result));
EXPECT_TRUE(add_prefixes_result.empty());
@@ -323,10 +336,12 @@ void SafeBrowsingStoreTestDelete(SafeBrowsingStore* store,
EXPECT_TRUE(store->FinishChunk());
std::vector<SBAddFullHash> pending_adds;
+ std::set<SBPrefix> prefix_misses;
std::vector<SBAddPrefix> add_prefixes_result;
std::vector<SBAddFullHash> add_full_hashes_result;
EXPECT_TRUE(store->FinishUpdate(pending_adds,
+ prefix_misses,
&add_prefixes_result,
&add_full_hashes_result));
diff --git a/chrome/browser/safe_browsing/safe_browsing_test.cc b/chrome/browser/safe_browsing/safe_browsing_test.cc
index 3cfca78..259d3ff 100644
--- a/chrome/browser/safe_browsing/safe_browsing_test.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_test.cc
@@ -29,7 +29,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/safe_browsing/protocol_manager.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
@@ -228,7 +228,7 @@ class SafeBrowsingServiceTest : public InProcessBrowserTest {
void CheckUrl(SafeBrowsingService::Client* helper, const GURL& url) {
ASSERT_TRUE(safe_browsing_service_);
AutoLock lock(update_status_mutex_);
- if (safe_browsing_service_->CheckUrl(url, helper)) {
+ if (safe_browsing_service_->CheckBrowseUrl(url, helper)) {
is_checked_url_in_db_ = false;
is_checked_url_safe_ = true;
} else {
@@ -345,8 +345,8 @@ class SafeBrowsingServiceTestHelper
}
// Callbacks for SafeBrowsingService::Client.
- virtual void OnUrlCheckResult(const GURL& url,
- SafeBrowsingService::UrlCheckResult result) {
+ virtual void OnBrowseUrlCheckResult(
+ const GURL& url, SafeBrowsingService::UrlCheckResult result) {
EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
EXPECT_TRUE(safe_browsing_test_->is_checked_url_in_db());
safe_browsing_test_->set_is_checked_url_safe(
@@ -355,6 +355,11 @@ class SafeBrowsingServiceTestHelper
NewRunnableMethod(this,
&SafeBrowsingServiceTestHelper::OnCheckUrlDone));
}
+ virtual void OnDownloadUrlCheckResult(
+ const GURL& url, SafeBrowsingService::UrlCheckResult result) {
+ // TODO(lzheng): Add test for DownloadUrl.
+ }
+
virtual void OnBlockingPageComplete(bool proceed) {
NOTREACHED() << "Not implemented.";
}
diff --git a/chrome/browser/safe_browsing/safe_browsing_util.cc b/chrome/browser/safe_browsing/safe_browsing_util.cc
index 0f99bf2..f43ee51 100644
--- a/chrome/browser/safe_browsing/safe_browsing_util.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_util.cc
@@ -175,16 +175,43 @@ namespace safe_browsing_util {
const char kMalwareList[] = "goog-malware-shavar";
const char kPhishingList[] = "goog-phish-shavar";
+const char kBinUrlList[] = "goog-badbinurl-shavar";
+const char kBinHashList[] = "goog-badbinhash-shavar";
+
int GetListId(const std::string& name) {
- if (name == kMalwareList)
- return MALWARE;
- return (name == kPhishingList) ? PHISH : INVALID;
+ int id;
+ if (name == safe_browsing_util::kMalwareList) {
+ id = MALWARE;
+ } else if (name == safe_browsing_util::kPhishingList) {
+ id = PHISH;
+ } else if (name == safe_browsing_util::kBinUrlList) {
+ id = BINURL;
+ } else if (name == safe_browsing_util::kBinHashList) {
+ id = BINHASH;
+ } else {
+ id = INVALID;
+ }
+ return id;
}
-std::string GetListName(int list_id) {
- if (list_id == MALWARE)
- return kMalwareList;
- return (list_id == PHISH) ? kPhishingList : std::string();
+bool GetListName(int list_id, std::string* list) {
+ switch (list_id) {
+ case MALWARE:
+ *list = safe_browsing_util::kMalwareList;
+ break;
+ case PHISH:
+ *list = safe_browsing_util::kPhishingList;
+ break;
+ case BINURL:
+ *list = safe_browsing_util::kBinUrlList;
+ break;
+ case BINHASH:
+ *list = safe_browsing_util::kBinHashList;
+ break;
+ default:
+ return false;
+ }
+ return true;
}
std::string Unescape(const std::string& url) {
@@ -426,6 +453,10 @@ bool IsMalwareList(const std::string& list_name) {
return list_name.find("-malware-") != std::string::npos;
}
+bool IsBadbinurlList(const std::string& list_name) {
+ return list_name.find("-badbinurl-") != std::string::npos;
+}
+
static void DecodeWebSafe(std::string* decoded) {
DCHECK(decoded);
for (std::string::iterator i(decoded->begin()); i != decoded->end(); ++i) {
diff --git a/chrome/browser/safe_browsing/safe_browsing_util.h b/chrome/browser/safe_browsing/safe_browsing_util.h
index a4fd2b6..b0351c1 100644
--- a/chrome/browser/safe_browsing/safe_browsing_util.h
+++ b/chrome/browser/safe_browsing/safe_browsing_util.h
@@ -261,16 +261,23 @@ namespace safe_browsing_util {
// SafeBrowsing list names.
extern const char kMalwareList[];
extern const char kPhishingList[];
+// Binary Download list names.
+extern const char kBinUrlList[];
+extern const char kBinHashList[];
-// Converts between the SafeBrowsing list names and their enumerated value.
-// If the list names change, both of these methods must be updated.
enum ListType {
INVALID = -1,
MALWARE = 0,
PHISH = 1,
+ BINURL = 2,
+ BINHASH = 3,
};
+
+// Maps a list name to ListType.
int GetListId(const std::string& name);
-std::string GetListName(int list_id);
+// Maps a ListId to list name. Return false if fails.
+bool GetListName(int list_id, std::string* list);
+
// Canonicalizes url as per Google Safe Browsing Specification.
// See section 6.1 in
@@ -294,6 +301,7 @@ int CompareFullHashes(const GURL& url,
bool IsPhishingList(const std::string& list_name);
bool IsMalwareList(const std::string& list_name);
+bool IsBadbinurlList(const std::string& list_name);
// Returns 'true' if 'mac' can be verified using 'key' and 'data'.
bool VerifyMAC(const std::string& key,
diff --git a/chrome/browser/safe_browsing/safe_browsing_util_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_util_unittest.cc
index 5204bfe..7bf7efc 100644
--- a/chrome/browser/safe_browsing/safe_browsing_util_unittest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_util_unittest.cc
@@ -294,3 +294,43 @@ TEST(SafeBrowsingUtilTest, FullHashCompare) {
url = GURL("http://www.evil.com/okay_path.html");
EXPECT_EQ(safe_browsing_util::CompareFullHashes(url, full_hashes), -1);
}
+
+TEST(SafeBrowsingUtilTest, ListIdListNameConversion) {
+ std::string list_name;
+ EXPECT_FALSE(safe_browsing_util::GetListName(safe_browsing_util::INVALID,
+ &list_name));
+ EXPECT_TRUE(safe_browsing_util::GetListName(safe_browsing_util::MALWARE,
+ &list_name));
+ EXPECT_EQ(list_name, std::string(safe_browsing_util::kMalwareList));
+ EXPECT_EQ(safe_browsing_util::MALWARE,
+ safe_browsing_util::GetListId(list_name));
+
+ EXPECT_TRUE(safe_browsing_util::GetListName(safe_browsing_util::PHISH,
+ &list_name));
+ EXPECT_EQ(list_name, std::string(safe_browsing_util::kPhishingList));
+ EXPECT_EQ(safe_browsing_util::PHISH,
+ safe_browsing_util::GetListId(list_name));
+
+ EXPECT_TRUE(safe_browsing_util::GetListName(safe_browsing_util::BINURL,
+ &list_name));
+ EXPECT_EQ(list_name, std::string(safe_browsing_util::kBinUrlList));
+ EXPECT_EQ(safe_browsing_util::BINURL,
+ safe_browsing_util::GetListId(list_name));
+
+
+ EXPECT_TRUE(safe_browsing_util::GetListName(safe_browsing_util::BINHASH,
+ &list_name));
+ EXPECT_EQ(list_name, std::string(safe_browsing_util::kBinHashList));
+ EXPECT_EQ(safe_browsing_util::BINHASH,
+ safe_browsing_util::GetListId(list_name));
+}
+
+// Since the ids are saved in file, we need to make sure they don't change.
+// Since only the last bit of each id is saved in file together with
+// chunkids, this checks only last bit.
+TEST(SafeBrowsingUtilTest, ListIdVerification) {
+ EXPECT_EQ(0, safe_browsing_util::MALWARE % 2);
+ EXPECT_EQ(1, safe_browsing_util::PHISH % 2);
+ EXPECT_EQ(0, safe_browsing_util::BINURL %2);
+ EXPECT_EQ(1, safe_browsing_util::BINHASH % 2);
+}
diff --git a/chrome/browser/search_engines/edit_search_engine_controller.cc b/chrome/browser/search_engines/edit_search_engine_controller.cc
index 6c3120c..b2b6a6d 100644
--- a/chrome/browser/search_engines/edit_search_engine_controller.cc
+++ b/chrome/browser/search_engines/edit_search_engine_controller.cc
@@ -8,7 +8,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/net/url_fixer_upper.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "googleurl/src/gurl.h"
diff --git a/chrome/browser/search_engines/keyword_editor_controller.cc b/chrome/browser/search_engines/keyword_editor_controller.cc
index 4755bc9..b7d2c5e 100644
--- a/chrome/browser/search_engines/keyword_editor_controller.cc
+++ b/chrome/browser/search_engines/keyword_editor_controller.cc
@@ -7,7 +7,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/search_engines/template_url_table_model.h"
diff --git a/chrome/browser/search_engines/keyword_editor_controller_unittest.cc b/chrome/browser/search_engines/keyword_editor_controller_unittest.cc
index 8103ee0..4952166 100644
--- a/chrome/browser/search_engines/keyword_editor_controller_unittest.cc
+++ b/chrome/browser/search_engines/keyword_editor_controller_unittest.cc
@@ -5,13 +5,12 @@
#include "app/table_model_observer.h"
#include "base/string16.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/keyword_editor_controller.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/search_engines/template_url_table_model.h"
#include "chrome/common/notification_details.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/notification_source.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_pref_service.h"
@@ -68,19 +67,19 @@ class KeywordEditorControllerTest : public testing::Test,
void SimulateDefaultSearchIsManaged(const std::string& url) {
ASSERT_FALSE(url.empty());
TestingPrefService* service = profile_->GetTestingPrefService();
- service->SetManagedPrefWithoutNotification(
+ service->SetManagedPref(
prefs::kDefaultSearchProviderEnabled,
Value::CreateBooleanValue(true));
- service->SetManagedPrefWithoutNotification(
+ service->SetManagedPref(
prefs::kDefaultSearchProviderSearchURL,
Value::CreateStringValue(url));
- service->SetManagedPrefWithoutNotification(
+ service->SetManagedPref(
prefs::kDefaultSearchProviderName,
Value::CreateStringValue("managed"));
// Clear the IDs that are not specified via policy.
- service->SetManagedPrefWithoutNotification(
+ service->SetManagedPref(
prefs::kDefaultSearchProviderID, new StringValue(""));
- service->SetManagedPrefWithoutNotification(
+ service->SetManagedPref(
prefs::kDefaultSearchProviderPrepopulateID, new StringValue(""));
model_->Observe(
NotificationType::PREF_CHANGED,
diff --git a/chrome/browser/search_engines/search_provider_install_data_unittest.cc b/chrome/browser/search_engines/search_provider_install_data_unittest.cc
index 0165578..28bcd47 100644
--- a/chrome/browser/search_engines/search_provider_install_data_unittest.cc
+++ b/chrome/browser/search_engines/search_provider_install_data_unittest.cc
@@ -190,19 +190,19 @@ class SearchProviderInstallDataTest : public testing::Test {
void SimulateDefaultSearchIsManaged(const std::string& url) {
ASSERT_FALSE(url.empty());
TestingPrefService* service = util_.profile()->GetTestingPrefService();
- service->SetManagedPrefWithoutNotification(
+ service->SetManagedPref(
prefs::kDefaultSearchProviderEnabled,
Value::CreateBooleanValue(true));
- service->SetManagedPrefWithoutNotification(
+ service->SetManagedPref(
prefs::kDefaultSearchProviderSearchURL,
Value::CreateStringValue(url));
- service->SetManagedPrefWithoutNotification(
+ service->SetManagedPref(
prefs::kDefaultSearchProviderName,
Value::CreateStringValue("managed"));
// Clear the IDs that are not specified via policy.
- service->SetManagedPrefWithoutNotification(
+ service->SetManagedPref(
prefs::kDefaultSearchProviderID, new StringValue(""));
- service->SetManagedPrefWithoutNotification(
+ service->SetManagedPref(
prefs::kDefaultSearchProviderPrepopulateID, new StringValue(""));
util_.model()->Observe(
NotificationType::PREF_CHANGED,
diff --git a/chrome/browser/search_engines/search_provider_install_state_dispatcher_host.cc b/chrome/browser/search_engines/search_provider_install_state_dispatcher_host.cc
deleted file mode 100644
index 1b1425a..0000000
--- a/chrome/browser/search_engines/search_provider_install_state_dispatcher_host.cc
+++ /dev/null
@@ -1,123 +0,0 @@
-// 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.
-
-#include "chrome/browser/search_engines/search_provider_install_state_dispatcher_host.h"
-
-#include "base/logging.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/renderer_host/render_process_host.h"
-#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/renderer_host/resource_message_filter.h"
-#include "chrome/common/notification_source.h"
-#include "chrome/common/notification_type.h"
-#include "chrome/common/render_messages.h"
-#include "chrome/common/render_messages_params.h"
-#include "ipc/ipc_message.h"
-#include "googleurl/src/gurl.h"
-
-SearchProviderInstallStateDispatcherHost::
-SearchProviderInstallStateDispatcherHost(
- ResourceMessageFilter* ipc_sender,
- Profile* profile,
- int render_process_id)
- : ALLOW_THIS_IN_INITIALIZER_LIST(
- reply_with_provider_install_state_factory_(this)),
- provider_data_(profile->GetWebDataService(Profile::EXPLICIT_ACCESS),
- NotificationType::RENDERER_PROCESS_TERMINATED,
- Source<RenderProcessHost>(
- RenderProcessHost::FromID(render_process_id))),
- ipc_sender_(ipc_sender),
- is_off_the_record_(profile->IsOffTheRecord()) {
- // This is initialized by ResourceMessageFilter. Do not add any non-trivial
- // initialization here. Instead do it lazily when required.
- DCHECK(ipc_sender);
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-}
-
-SearchProviderInstallStateDispatcherHost::
-~SearchProviderInstallStateDispatcherHost() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-}
-
-void SearchProviderInstallStateDispatcherHost::Send(IPC::Message* message) {
- ipc_sender_->Send(message);
-}
-
-bool SearchProviderInstallStateDispatcherHost::OnMessageReceived(
- const IPC::Message& message,
- bool* message_was_ok) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP_EX(SearchProviderInstallStateDispatcherHost, message,
- *message_was_ok)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetSearchProviderInstallState,
- OnMsgGetSearchProviderInstallState)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-ViewHostMsg_GetSearchProviderInstallState_Params
-SearchProviderInstallStateDispatcherHost::GetSearchProviderInstallState(
- const GURL& page_location,
- const GURL& requested_host) {
- GURL requested_origin = requested_host.GetOrigin();
-
- // Do the security check before any others to avoid information leaks.
- if (page_location.GetOrigin() != requested_origin)
- return ViewHostMsg_GetSearchProviderInstallState_Params::Denied();
-
- // In incognito mode, no search information is exposed. (This check must be
- // done after the security check or else a web site can detect that the
- // user is in incognito mode just by doing a cross origin request.)
- if (is_off_the_record_)
- return ViewHostMsg_GetSearchProviderInstallState_Params::NotInstalled();
-
- switch (provider_data_.GetInstallState(requested_origin)) {
- case SearchProviderInstallData::NOT_INSTALLED:
- return ViewHostMsg_GetSearchProviderInstallState_Params::
- NotInstalled();
-
- case SearchProviderInstallData::INSTALLED_BUT_NOT_DEFAULT:
- return ViewHostMsg_GetSearchProviderInstallState_Params::
- InstallButNotDefault();
-
- case SearchProviderInstallData::INSTALLED_AS_DEFAULT:
- return ViewHostMsg_GetSearchProviderInstallState_Params::
- InstalledAsDefault();
- }
-
- NOTREACHED();
- return ViewHostMsg_GetSearchProviderInstallState_Params::
- NotInstalled();
-}
-
-void
-SearchProviderInstallStateDispatcherHost::OnMsgGetSearchProviderInstallState(
- const GURL& page_location,
- const GURL& requested_host,
- IPC::Message* reply_msg) {
- provider_data_.CallWhenLoaded(
- reply_with_provider_install_state_factory_.NewRunnableMethod(
- &SearchProviderInstallStateDispatcherHost::
- ReplyWithProviderInstallState,
- page_location,
- requested_host,
- reply_msg));
-}
-
-void SearchProviderInstallStateDispatcherHost::ReplyWithProviderInstallState(
- const GURL& page_location,
- const GURL& requested_host,
- IPC::Message* reply_msg) {
- DCHECK(reply_msg);
- ViewHostMsg_GetSearchProviderInstallState_Params install_state =
- GetSearchProviderInstallState(page_location, requested_host);
-
- ViewHostMsg_GetSearchProviderInstallState::WriteReplyParams(
- reply_msg,
- install_state);
- Send(reply_msg);
-}
diff --git a/chrome/browser/search_engines/search_provider_install_state_dispatcher_host.h b/chrome/browser/search_engines/search_provider_install_state_dispatcher_host.h
deleted file mode 100644
index d597eb4..0000000
--- a/chrome/browser/search_engines/search_provider_install_state_dispatcher_host.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_SEARCH_ENGINES_SEARCH_PROVIDER_INSTALL_STATE_DISPATCHER_HOST_H_
-#define CHROME_BROWSER_SEARCH_ENGINES_SEARCH_PROVIDER_INSTALL_STATE_DISPATCHER_HOST_H_
-
-#include "base/basictypes.h"
-#include "base/scoped_ptr.h"
-#include "base/task.h"
-#include "chrome/browser/search_engines/search_provider_install_data.h"
-
-namespace IPC {
-class Message;
-}
-
-class GURL;
-class Profile;
-class ResourceMessageFilter;
-struct ViewHostMsg_GetSearchProviderInstallState_Params;
-
-// Handles messages regarding search provider install state on the I/O thread.
-class SearchProviderInstallStateDispatcherHost {
- public:
- // Unlike the other methods, the constructor is called on the UI thread.
- SearchProviderInstallStateDispatcherHost(ResourceMessageFilter* ipc_sender,
- Profile* profile,
- int render_process_id);
- ~SearchProviderInstallStateDispatcherHost();
-
- // Send a message to the renderer process.
- void Send(IPC::Message* message);
-
- // Called to possibly handle the incoming IPC message. Returns true if
- // handled.
- bool OnMessageReceived(const IPC::Message& message, bool* message_was_ok);
-
- private:
- // Figures out the install state for the search provider.
- ViewHostMsg_GetSearchProviderInstallState_Params
- GetSearchProviderInstallState(const GURL& page_location,
- const GURL& requested_host);
-
- // Starts handling the message requesting the search provider install state.
- void OnMsgGetSearchProviderInstallState(const GURL& page_location,
- const GURL& requested_host,
- IPC::Message* reply_msg);
-
- // Sends the reply message about the search provider install state.
- void ReplyWithProviderInstallState(const GURL& page_location,
- const GURL& requested_host,
- IPC::Message* reply_msg);
-
- // Used to schedule invocations of ReplyWithProviderInstallState.
- ScopedRunnableMethodFactory<SearchProviderInstallStateDispatcherHost>
- reply_with_provider_install_state_factory_;
-
- // Used to do a load and get information about install states.
- SearchProviderInstallData provider_data_;
-
- // Used to reply to messages.
- ResourceMessageFilter* ipc_sender_;
-
- // Copied from the profile since the profile can't be accessed on the I/O
- // thread.
- const bool is_off_the_record_;
-
- DISALLOW_COPY_AND_ASSIGN(SearchProviderInstallStateDispatcherHost);
-};
-
-#endif // CHROME_BROWSER_SEARCH_ENGINES_SEARCH_PROVIDER_INSTALL_STATE_DISPATCHER_HOST_H_
diff --git a/chrome/browser/search_engines/search_provider_install_state_message_filter.cc b/chrome/browser/search_engines/search_provider_install_state_message_filter.cc
new file mode 100644
index 0000000..a24bc1b
--- /dev/null
+++ b/chrome/browser/search_engines/search_provider_install_state_message_filter.cc
@@ -0,0 +1,113 @@
+// 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.
+
+#include "chrome/browser/search_engines/search_provider_install_state_message_filter.h"
+
+#include "base/logging.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/render_process_host.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
+#include "googleurl/src/gurl.h"
+
+SearchProviderInstallStateMessageFilter::
+SearchProviderInstallStateMessageFilter(
+ int render_process_id,
+ Profile* profile)
+ : ALLOW_THIS_IN_INITIALIZER_LIST(
+ reply_with_provider_install_state_factory_(this)),
+ provider_data_(profile->GetWebDataService(Profile::EXPLICIT_ACCESS),
+ NotificationType::RENDERER_PROCESS_TERMINATED,
+ Source<RenderProcessHost>(
+ RenderProcessHost::FromID(render_process_id))),
+ is_off_the_record_(profile->IsOffTheRecord()) {
+ // This is initialized by BrowserRenderProcessHost. Do not add any non-trivial
+ // initialization here. Instead do it lazily when required.
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+}
+
+SearchProviderInstallStateMessageFilter::
+~SearchProviderInstallStateMessageFilter() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+}
+
+bool SearchProviderInstallStateMessageFilter::OnMessageReceived(
+ const IPC::Message& message,
+ bool* message_was_ok) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(SearchProviderInstallStateMessageFilter, message,
+ *message_was_ok)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetSearchProviderInstallState,
+ OnMsgGetSearchProviderInstallState)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+ViewHostMsg_GetSearchProviderInstallState_Params
+SearchProviderInstallStateMessageFilter::GetSearchProviderInstallState(
+ const GURL& page_location,
+ const GURL& requested_host) {
+ GURL requested_origin = requested_host.GetOrigin();
+
+ // Do the security check before any others to avoid information leaks.
+ if (page_location.GetOrigin() != requested_origin)
+ return ViewHostMsg_GetSearchProviderInstallState_Params::Denied();
+
+ // In incognito mode, no search information is exposed. (This check must be
+ // done after the security check or else a web site can detect that the
+ // user is in incognito mode just by doing a cross origin request.)
+ if (is_off_the_record_)
+ return ViewHostMsg_GetSearchProviderInstallState_Params::NotInstalled();
+
+ switch (provider_data_.GetInstallState(requested_origin)) {
+ case SearchProviderInstallData::NOT_INSTALLED:
+ return ViewHostMsg_GetSearchProviderInstallState_Params::
+ NotInstalled();
+
+ case SearchProviderInstallData::INSTALLED_BUT_NOT_DEFAULT:
+ return ViewHostMsg_GetSearchProviderInstallState_Params::
+ InstallButNotDefault();
+
+ case SearchProviderInstallData::INSTALLED_AS_DEFAULT:
+ return ViewHostMsg_GetSearchProviderInstallState_Params::
+ InstalledAsDefault();
+ }
+
+ NOTREACHED();
+ return ViewHostMsg_GetSearchProviderInstallState_Params::
+ NotInstalled();
+}
+
+void
+SearchProviderInstallStateMessageFilter::OnMsgGetSearchProviderInstallState(
+ const GURL& page_location,
+ const GURL& requested_host,
+ IPC::Message* reply_msg) {
+ provider_data_.CallWhenLoaded(
+ reply_with_provider_install_state_factory_.NewRunnableMethod(
+ &SearchProviderInstallStateMessageFilter::
+ ReplyWithProviderInstallState,
+ page_location,
+ requested_host,
+ reply_msg));
+}
+
+void SearchProviderInstallStateMessageFilter::ReplyWithProviderInstallState(
+ const GURL& page_location,
+ const GURL& requested_host,
+ IPC::Message* reply_msg) {
+ DCHECK(reply_msg);
+ ViewHostMsg_GetSearchProviderInstallState_Params install_state =
+ GetSearchProviderInstallState(page_location, requested_host);
+
+ ViewHostMsg_GetSearchProviderInstallState::WriteReplyParams(
+ reply_msg,
+ install_state);
+ Send(reply_msg);
+}
diff --git a/chrome/browser/search_engines/search_provider_install_state_message_filter.h b/chrome/browser/search_engines/search_provider_install_state_message_filter.h
new file mode 100644
index 0000000..63ea44e
--- /dev/null
+++ b/chrome/browser/search_engines/search_provider_install_state_message_filter.h
@@ -0,0 +1,57 @@
+// 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.
+
+#ifndef CHROME_BROWSER_SEARCH_ENGINES_SEARCH_PROVIDER_INSTALL_STATE_MESSAGE_FILTER_H_
+#define CHROME_BROWSER_SEARCH_ENGINES_SEARCH_PROVIDER_INSTALL_STATE_MESSAGE_FILTER_H_
+
+#include "chrome/browser/browser_message_filter.h"
+#include "chrome/browser/search_engines/search_provider_install_data.h"
+
+class GURL;
+class Profile;
+struct ViewHostMsg_GetSearchProviderInstallState_Params;
+
+// Handles messages regarding search provider install state on the I/O thread.
+class SearchProviderInstallStateMessageFilter : public BrowserMessageFilter {
+ public:
+ // Unlike the other methods, the constructor is called on the UI thread.
+ SearchProviderInstallStateMessageFilter(int render_process_id,
+ Profile* profile);
+ ~SearchProviderInstallStateMessageFilter();
+
+ // BrowserMessageFilter implementation.
+ virtual bool OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok);
+
+ private:
+ // Figures out the install state for the search provider.
+ ViewHostMsg_GetSearchProviderInstallState_Params
+ GetSearchProviderInstallState(const GURL& page_location,
+ const GURL& requested_host);
+
+ // Starts handling the message requesting the search provider install state.
+ void OnMsgGetSearchProviderInstallState(const GURL& page_location,
+ const GURL& requested_host,
+ IPC::Message* reply_msg);
+
+ // Sends the reply message about the search provider install state.
+ void ReplyWithProviderInstallState(const GURL& page_location,
+ const GURL& requested_host,
+ IPC::Message* reply_msg);
+
+ // Used to schedule invocations of ReplyWithProviderInstallState.
+ ScopedRunnableMethodFactory<SearchProviderInstallStateMessageFilter>
+ reply_with_provider_install_state_factory_;
+
+ // Used to do a load and get information about install states.
+ SearchProviderInstallData provider_data_;
+
+ // Copied from the profile since the profile can't be accessed on the I/O
+ // thread.
+ const bool is_off_the_record_;
+
+ DISALLOW_COPY_AND_ASSIGN(SearchProviderInstallStateMessageFilter);
+};
+
+#endif // CHROME_BROWSER_SEARCH_ENGINES_SEARCH_PROVIDER_INSTALL_STATE_MESSAGE_FILTER_H_
diff --git a/chrome/browser/search_engines/template_url_fetcher.cc b/chrome/browser/search_engines/template_url_fetcher.cc
index 9d89164..b5fe3db 100644
--- a/chrome/browser/search_engines/template_url_fetcher.cc
+++ b/chrome/browser/search_engines/template_url_fetcher.cc
@@ -8,7 +8,7 @@
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_fetcher_callbacks.h"
#include "chrome/browser/search_engines/template_url_model.h"
diff --git a/chrome/browser/search_engines/template_url_model.cc b/chrome/browser/search_engines/template_url_model.cc
index cde70f3..7372262 100644
--- a/chrome/browser/search_engines/template_url_model.cc
+++ b/chrome/browser/search_engines/template_url_model.cc
@@ -11,14 +11,14 @@
#include "base/string_number_conversions.h"
#include "base/string_split.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/google/google_url_tracker.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/history/history_notifications.h"
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prefs/pref_set_observer.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/rlz/rlz.h"
#include "chrome/browser/search_engines/search_host_to_urls_map.h"
#include "chrome/browser/search_engines/search_terms_data.h"
@@ -741,7 +741,7 @@ void TemplateURLModel::NotifyLoaded() {
NotificationService::NoDetails());
for (size_t i = 0; i < pending_extension_ids_.size(); ++i) {
- const Extension* extension = profile_->GetExtensionsService()->
+ const Extension* extension = profile_->GetExtensionService()->
GetExtensionById(pending_extension_ids_[i], true);
if (extension)
RegisterExtensionKeyword(extension);
@@ -844,12 +844,12 @@ bool TemplateURLModel::LoadDefaultSearchProviderFromPrefs(
std::vector<std::string> encodings_vector;
base::SplitString(encodings, ';', &encodings_vector);
(*default_provider)->set_input_encodings(encodings_vector);
- if (!id_string.empty()) {
+ if (!id_string.empty() && !*is_managed) {
int64 value;
base::StringToInt64(id_string, &value);
(*default_provider)->set_id(value);
}
- if (!prepopulate_id.empty()) {
+ if (!prepopulate_id.empty() && !*is_managed) {
int value;
base::StringToInt(prepopulate_id, &value);
(*default_provider)->set_prepopulate_id(value);
@@ -1258,4 +1258,3 @@ void TemplateURLModel::NotifyObservers() {
FOR_EACH_OBSERVER(TemplateURLModelObserver, model_observers_,
OnTemplateURLModelChanged());
}
-
diff --git a/chrome/browser/search_engines/template_url_model_test_util.cc b/chrome/browser/search_engines/template_url_model_test_util.cc
index 52a6c91..e6ebc8d 100644
--- a/chrome/browser/search_engines/template_url_model_test_util.cc
+++ b/chrome/browser/search_engines/template_url_model_test_util.cc
@@ -167,9 +167,8 @@ void TemplateURLModelTestUtil::OnTemplateURLModelChanged() {
changed_count_++;
}
-void TemplateURLModelTestUtil::VerifyObserverCount(int expected_changed_count) {
- ASSERT_EQ(expected_changed_count, changed_count_);
- changed_count_ = 0;
+int TemplateURLModelTestUtil::GetObserverCount() {
+ return changed_count_;
}
void TemplateURLModelTestUtil::ResetObserverCount() {
@@ -188,7 +187,8 @@ void TemplateURLModelTestUtil::VerifyLoad() {
ASSERT_FALSE(model()->loaded());
model()->Load();
BlockTillServiceProcessesRequests();
- VerifyObserverCount(1);
+ EXPECT_EQ(1, GetObserverCount());
+ ResetObserverCount();
}
void TemplateURLModelTestUtil::ChangeModelToLoadState() {
diff --git a/chrome/browser/search_engines/template_url_model_test_util.h b/chrome/browser/search_engines/template_url_model_test_util.h
index 3921b44..058b64b 100644
--- a/chrome/browser/search_engines/template_url_model_test_util.h
+++ b/chrome/browser/search_engines/template_url_model_test_util.h
@@ -40,8 +40,8 @@ class TemplateURLModelTestUtil : public TemplateURLModelObserver {
// TemplateURLModelObserver implemementation.
virtual void OnTemplateURLModelChanged();
- // Checks that the observer count is what is expected.
- void VerifyObserverCount(int expected_changed_count);
+ // Gets the observer count.
+ int GetObserverCount();
// Sets the observer count to 0.
void ResetObserverCount();
diff --git a/chrome/browser/search_engines/template_url_model_unittest.cc b/chrome/browser/search_engines/template_url_model_unittest.cc
index 15c4b12..532fce6 100644
--- a/chrome/browser/search_engines/template_url_model_unittest.cc
+++ b/chrome/browser/search_engines/template_url_model_unittest.cc
@@ -19,7 +19,6 @@
#include "chrome/browser/search_engines/template_url_prepopulate_data.h"
#include "chrome/browser/webdata/web_database.h"
#include "chrome/common/notification_details.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/notification_source.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_pref_service.h"
@@ -37,8 +36,8 @@ using base::TimeDelta;
#endif
// Test the GenerateSearchURL on a thread or the main thread.
-class TestGenerateSearchURL :
- public base::RefCountedThreadSafe<TestGenerateSearchURL> {
+class TestGenerateSearchURL
+ : public base::RefCountedThreadSafe<TestGenerateSearchURL> {
public:
explicit TestGenerateSearchURL(SearchTermsData* search_terms_data)
: search_terms_data_(search_terms_data),
@@ -194,58 +193,51 @@ class TemplateURLModelTest : public testing::Test {
const char* encodings,
const char* keyword) {
TestingPrefService* service = profile()->GetTestingPrefService();
- service->SetManagedPrefWithoutNotification(
+ service->SetManagedPref(
prefs::kDefaultSearchProviderEnabled,
Value::CreateBooleanValue(enabled));
- service->SetManagedPrefWithoutNotification(
+ service->SetManagedPref(
prefs::kDefaultSearchProviderName,
Value::CreateStringValue(name));
- service->SetManagedPrefWithoutNotification(
+ service->SetManagedPref(
prefs::kDefaultSearchProviderSearchURL,
Value::CreateStringValue(search_url));
- service->SetManagedPrefWithoutNotification(
+ service->SetManagedPref(
prefs::kDefaultSearchProviderSuggestURL,
Value::CreateStringValue(suggest_url));
- service->SetManagedPrefWithoutNotification(
+ service->SetManagedPref(
prefs::kDefaultSearchProviderIconURL,
Value::CreateStringValue(icon_url));
- service->SetManagedPrefWithoutNotification(
+ service->SetManagedPref(
prefs::kDefaultSearchProviderEncodings,
Value::CreateStringValue(encodings));
- service->SetManagedPrefWithoutNotification(
+ service->SetManagedPref(
prefs::kDefaultSearchProviderKeyword,
Value::CreateStringValue(keyword));
- // Clear the IDs that are not specified via policy.
- service->SetManagedPrefWithoutNotification(
- prefs::kDefaultSearchProviderID, new StringValue(""));
- service->SetManagedPrefWithoutNotification(
- prefs::kDefaultSearchProviderPrepopulateID, new StringValue(""));
- NotifyManagedPrefsHaveChanged();
}
// Remove all the managed preferences for the default search provider and
// trigger notification.
void RemoveManagedDefaultSearchPreferences() {
TestingPrefService* service = profile()->GetTestingPrefService();
- service->RemoveManagedPrefWithoutNotification(
+ service->RemoveManagedPref(
+ prefs::kDefaultSearchProviderSearchURL);
+ service->RemoveManagedPref(
prefs::kDefaultSearchProviderEnabled);
- service->RemoveManagedPrefWithoutNotification(
+ service->RemoveManagedPref(
prefs::kDefaultSearchProviderName);
- service->RemoveManagedPrefWithoutNotification(
- prefs::kDefaultSearchProviderSearchURL);
- service->RemoveManagedPrefWithoutNotification(
+ service->RemoveManagedPref(
prefs::kDefaultSearchProviderSuggestURL);
- service->RemoveManagedPrefWithoutNotification(
+ service->RemoveManagedPref(
prefs::kDefaultSearchProviderIconURL);
- service->RemoveManagedPrefWithoutNotification(
+ service->RemoveManagedPref(
prefs::kDefaultSearchProviderEncodings);
- service->RemoveManagedPrefWithoutNotification(
+ service->RemoveManagedPref(
prefs::kDefaultSearchProviderKeyword);
- service->RemoveManagedPrefWithoutNotification(
+ service->RemoveManagedPref(
prefs::kDefaultSearchProviderID);
- service->RemoveManagedPrefWithoutNotification(
+ service->RemoveManagedPref(
prefs::kDefaultSearchProviderPrepopulateID);
- NotifyManagedPrefsHaveChanged();
}
// Creates a TemplateURL with the same prepopluated id as a real prepopulated
@@ -264,7 +256,12 @@ class TemplateURLModelTest : public testing::Test {
// Helper methods to make calling TemplateURLModelTestUtil methods less
// visually noisy in the test code.
void VerifyObserverCount(int expected_changed_count) {
- test_util_.VerifyObserverCount(expected_changed_count);
+ EXPECT_EQ(expected_changed_count, test_util_.GetObserverCount());
+ test_util_.ResetObserverCount();
+ }
+ void VerifyObserverFired() {
+ EXPECT_LE(1, test_util_.GetObserverCount());
+ test_util_.ResetObserverCount();
}
void BlockTillServiceProcessesRequests() {
TemplateURLModelTestUtil::BlockTillServiceProcessesRequests();
@@ -1113,7 +1110,7 @@ TEST_F(TemplateURLModelTest, TestManagedDefaultSearch) {
const char kEncodings[] = "UTF-16;UTF-32";
SetManagedDefaultSearchPreferences(true, kName, kSearchURL, "", kIconURL,
kEncodings, "");
- VerifyObserverCount(1);
+ VerifyObserverFired();
EXPECT_TRUE(model()->is_default_search_managed());
EXPECT_EQ(2 + initial_count, model()->GetTemplateURLs().size());
@@ -1137,7 +1134,7 @@ TEST_F(TemplateURLModelTest, TestManagedDefaultSearch) {
const char kNewSuggestURL[] = "http://other.com/suggest?t={searchTerms}";
SetManagedDefaultSearchPreferences(true, kNewName, kNewSearchURL,
kNewSuggestURL, "", "", "");
- VerifyObserverCount(1);
+ VerifyObserverFired();
EXPECT_TRUE(model()->is_default_search_managed());
EXPECT_EQ(2 + initial_count, model()->GetTemplateURLs().size());
@@ -1153,7 +1150,7 @@ TEST_F(TemplateURLModelTest, TestManagedDefaultSearch) {
// Remove all the managed prefs and check that we are no longer managed.
RemoveManagedDefaultSearchPreferences();
- VerifyObserverCount(1);
+ VerifyObserverFired();
EXPECT_FALSE(model()->is_default_search_managed());
EXPECT_EQ(1 + initial_count, model()->GetTemplateURLs().size());
@@ -1166,7 +1163,7 @@ TEST_F(TemplateURLModelTest, TestManagedDefaultSearch) {
// Disable the default search provider through policy.
SetManagedDefaultSearchPreferences(false, "", "", "", "", "", "");
- VerifyObserverCount(1);
+ VerifyObserverFired();
EXPECT_TRUE(model()->is_default_search_managed());
EXPECT_TRUE(NULL == model()->GetDefaultSearchProvider());
EXPECT_EQ(1 + initial_count, model()->GetTemplateURLs().size());
@@ -1174,7 +1171,7 @@ TEST_F(TemplateURLModelTest, TestManagedDefaultSearch) {
// Re-enable it.
SetManagedDefaultSearchPreferences(true, kName, kSearchURL, "", kIconURL,
kEncodings, "");
- VerifyObserverCount(1);
+ VerifyObserverFired();
EXPECT_TRUE(model()->is_default_search_managed());
EXPECT_EQ(2 + initial_count, model()->GetTemplateURLs().size());
diff --git a/chrome/browser/search_engines/template_url_prepopulate_data_unittest.cc b/chrome/browser/search_engines/template_url_prepopulate_data_unittest.cc
index 5275146..f79f6b6 100644
--- a/chrome/browser/search_engines/template_url_prepopulate_data_unittest.cc
+++ b/chrome/browser/search_engines/template_url_prepopulate_data_unittest.cc
@@ -5,13 +5,13 @@
#include "base/file_util.h"
#include "base/scoped_temp_dir.h"
#include "base/scoped_vector.h"
-#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/search_engines/search_engine_type.h"
#include "chrome/browser/search_engines/search_terms_data.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_prepopulate_data.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/common/pref_names.h"
+#include "chrome/test/testing_pref_service.h"
#include "chrome/test/testing_profile.h"
#include "grit/theme_resources.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -91,40 +91,32 @@ TEST_F(TemplateURLPrepopulateDataTest, UniqueIDs) {
// Verifies that default search providers from the preferences file
// override the built-in ones.
TEST_F(TemplateURLPrepopulateDataTest, ProvidersFromPrefs) {
- const char pref_data[] =
- "{ "
- " \"search_provider_overrides_version\":1,"
- " \"search_provider_overrides\": ["
- " { \"name\":\"foo\","
- " \"keyword\":\"fook\","
- " \"search_url\":\"http://foo.com/s?q={searchTerms}\","
- " \"favicon_url\":\"http://foi.com/favicon.ico\","
- " \"suggest_url\":\"\","
- " \"instant_url\":\"\","
- " \"encoding\":\"UTF-8\","
- " \"search_engine_type\":1,"
- " \"logo_id\":0,"
- " \"id\":1001"
- " }"
- " ]"
- "}";
-
- ScopedTempDir temp_dir;
- ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
- FilePath preferences_file = temp_dir.path().AppendASCII("Preferences");
- file_util::WriteFile(preferences_file, pref_data, sizeof(pref_data));
-
- scoped_ptr<PrefService> prefs(
- PrefService::CreateUserPrefService(preferences_file));
- TemplateURLPrepopulateData::RegisterUserPrefs(prefs.get());
-
- int version = TemplateURLPrepopulateData::GetDataVersion(prefs.get());
+ TestingPrefService prefs;
+ TemplateURLPrepopulateData::RegisterUserPrefs(&prefs);
+ prefs.SetUserPref(prefs::kSearchProviderOverridesVersion,
+ Value::CreateIntegerValue(1));
+ ListValue* overrides = new ListValue;
+ DictionaryValue* entry = new DictionaryValue;
+ entry->SetString("name", "foo");
+ entry->SetString("keyword", "fook");
+ entry->SetString("search_url", "http://foo.com/s?q={searchTerms}");
+ entry->SetString("favicon_url", "http://foi.com/favicon.ico");
+ entry->SetString("suggest_url", "");
+ entry->SetString("instant_url", "");
+ entry->SetString("encoding", "UTF-8");
+ entry->SetInteger("search_engine_type", 1);
+ entry->SetInteger("logo_id", 0);
+ entry->SetInteger("id", 1001);
+ overrides->Append(entry);
+ prefs.SetUserPref(prefs::kSearchProviderOverrides, overrides);
+
+ int version = TemplateURLPrepopulateData::GetDataVersion(&prefs);
EXPECT_EQ(1, version);
ScopedVector<TemplateURL> t_urls;
size_t default_index;
TemplateURLPrepopulateData::GetPrepopulatedEngines(
- prefs.get(), &(t_urls.get()), &default_index);
+ &prefs, &(t_urls.get()), &default_index);
ASSERT_EQ(1u, t_urls.size());
EXPECT_EQ(L"foo", t_urls[0]->short_name());
diff --git a/chrome/browser/search_engines/template_url_scraper_unittest.cc b/chrome/browser/search_engines/template_url_scraper_unittest.cc
index 3988217..76a2e1f 100644
--- a/chrome/browser/search_engines/template_url_scraper_unittest.cc
+++ b/chrome/browser/search_engines/template_url_scraper_unittest.cc
@@ -2,7 +2,7 @@
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/search_engines/template_url_prepopulate_data.h"
#include "chrome/browser/ui/browser.h"
diff --git a/chrome/browser/search_engines/template_url_table_model.cc b/chrome/browser/search_engines/template_url_table_model.cc
index f335ba3..6ab7794 100644
--- a/chrome/browser/search_engines/template_url_table_model.cc
+++ b/chrome/browser/search_engines/template_url_table_model.cc
@@ -15,7 +15,7 @@
#include "base/stl_util-inl.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/favicon_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "gfx/codec/png_codec.h"
diff --git a/chrome/browser/search_engines/util.cc b/chrome/browser/search_engines/util.cc
index 418653b..94b46d6 100644
--- a/chrome/browser/search_engines/util.cc
+++ b/chrome/browser/search_engines/util.cc
@@ -14,7 +14,7 @@
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/search_engines/template_url_prepopulate_data.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
string16 GetDefaultSearchEngineName(Profile* profile) {
if (!profile) {
diff --git a/chrome/browser/service/service_process_control.cc b/chrome/browser/service/service_process_control.cc
index 74efc36..27e3a2d 100644
--- a/chrome/browser/service/service_process_control.cc
+++ b/chrome/browser/service/service_process_control.cc
@@ -122,14 +122,14 @@ void ServiceProcessControl::ConnectInternal() {
// TODO(hclam): Handle error connecting to channel.
const std::string channel_id = GetServiceProcessChannelName();
channel_.reset(
- new IPC::SyncChannel(channel_id, IPC::Channel::MODE_CLIENT, this, NULL,
+ new IPC::SyncChannel(channel_id, IPC::Channel::MODE_CLIENT, this,
io_thread->message_loop(), true,
g_browser_process->shutdown_event()));
channel_->set_sync_messages_with_no_timeout_allowed(false);
// We just established a channel with the service process. Notify it if an
// upgrade is available.
- if (Singleton<UpgradeDetector>::get()->notify_upgrade()) {
+ if (UpgradeDetector::GetInstance()->notify_upgrade()) {
Send(new ServiceMsg_UpdateAvailable);
} else {
if (registrar_.IsEmpty())
@@ -238,12 +238,17 @@ void ServiceProcessControl::OnProcessLaunched() {
launcher_ = NULL;
}
-void ServiceProcessControl::OnMessageReceived(const IPC::Message& message) {
+bool ServiceProcessControl::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;;
IPC_BEGIN_MESSAGE_MAP(ServiceProcessControl, message)
- IPC_MESSAGE_HANDLER(ServiceHostMsg_GoodDay, OnGoodDay)
- IPC_MESSAGE_HANDLER(ServiceHostMsg_CloudPrintProxy_IsEnabled,
- OnCloudPrintProxyIsEnabled)
+ IPC_MESSAGE_HANDLER(ServiceHostMsg_GoodDay, OnGoodDay)
+ IPC_MESSAGE_HANDLER(ServiceHostMsg_CloudPrintProxy_IsEnabled,
+ OnCloudPrintProxyIsEnabled)
+ IPC_MESSAGE_HANDLER(ServiceHostMsg_RemotingHost_HostInfo,
+ OnRemotingHostInfo)
+ IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
+ return handled;
}
void ServiceProcessControl::OnChannelConnected(int32 peer_pid) {
@@ -273,7 +278,6 @@ void ServiceProcessControl::Observe(NotificationType type,
}
}
-
void ServiceProcessControl::OnGoodDay() {
if (!message_handler_)
return;
@@ -290,6 +294,22 @@ void ServiceProcessControl::OnCloudPrintProxyIsEnabled(bool enabled,
}
}
+void ServiceProcessControl::OnRemotingHostInfo(
+ remoting::ChromotingHostInfo host_info) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (remoting_host_status_callback_ != NULL) {
+ remoting_host_status_callback_->Run(host_info);
+ remoting_host_status_callback_.reset();
+ }
+}
+
+bool ServiceProcessControl::GetCloudPrintProxyStatus(
+ Callback2<bool, std::string>::Type* cloud_print_status_callback) {
+ DCHECK(cloud_print_status_callback);
+ cloud_print_status_callback_.reset(cloud_print_status_callback);
+ return Send(new ServiceMsg_IsCloudPrintProxyEnabled);
+}
+
bool ServiceProcessControl::SendHello() {
return Send(new ServiceMsg_Hello());
}
@@ -300,20 +320,26 @@ bool ServiceProcessControl::Shutdown() {
return ret;
}
-bool ServiceProcessControl::EnableRemotingWithTokens(
+bool ServiceProcessControl::SetRemotingHostCredentials(
const std::string& user,
- const std::string& remoting_token,
const std::string& talk_token) {
return Send(
- new ServiceMsg_EnableRemotingWithTokens(user, remoting_token,
- talk_token));
+ new ServiceMsg_SetRemotingHostCredentials(user, talk_token));
}
-bool ServiceProcessControl::GetCloudPrintProxyStatus(
- Callback2<bool, std::string>::Type* cloud_print_status_callback) {
- DCHECK(cloud_print_status_callback);
- cloud_print_status_callback_.reset(cloud_print_status_callback);
- return Send(new ServiceMsg_IsCloudPrintProxyEnabled);
+bool ServiceProcessControl::EnableRemotingHost() {
+ return Send(new ServiceMsg_EnableRemotingHost());
+}
+
+bool ServiceProcessControl::DisableRemotingHost() {
+ return Send(new ServiceMsg_DisableRemotingHost());
+}
+
+bool ServiceProcessControl::GetRemotingHostStatus(
+ GetRemotingHostStatusCallback* status_callback) {
+ DCHECK(status_callback);
+ remoting_host_status_callback_.reset(status_callback);
+ return Send(new ServiceMsg_GetRemotingHostInfo);
}
DISABLE_RUNNABLE_METHOD_REFCOUNT(ServiceProcessControl);
diff --git a/chrome/browser/service/service_process_control.h b/chrome/browser/service/service_process_control.h
index ff22eb3..9162736 100644
--- a/chrome/browser/service/service_process_control.h
+++ b/chrome/browser/service/service_process_control.h
@@ -20,6 +20,10 @@
class Profile;
+namespace remoting {
+struct ChromotingHostInfo;
+} // namespace remoting
+
// A ServiceProcessControl works as a portal between the service process and
// the browser process.
//
@@ -36,6 +40,8 @@ class ServiceProcessControl : public IPC::Channel::Sender,
public:
typedef IDMap<ServiceProcessControl>::iterator iterator;
typedef std::queue<IPC::Message> MessageQueue;
+ typedef Callback1<const remoting::ChromotingHostInfo&>::Type
+ GetRemotingHostStatusCallback;
// An interface for handling messages received from the service process.
class MessageHandler {
@@ -71,7 +77,7 @@ class ServiceProcessControl : public IPC::Channel::Sender,
void Launch(Task* success_task, Task* failure_task);
// IPC::Channel::Listener implementation.
- virtual void OnMessageReceived(const IPC::Message& message);
+ virtual bool OnMessageReceived(const IPC::Message& message);
virtual void OnChannelConnected(int32 peer_pid);
virtual void OnChannelError();
@@ -86,6 +92,7 @@ class ServiceProcessControl : public IPC::Channel::Sender,
// Message handlers
void OnGoodDay();
void OnCloudPrintProxyIsEnabled(bool enabled, std::string email);
+ void OnRemotingHostInfo(remoting::ChromotingHostInfo host_info);
// Send a hello message to the service process for testing purpose.
// Return true if the message was sent.
@@ -96,12 +103,6 @@ class ServiceProcessControl : public IPC::Channel::Sender,
// Return true if the message was sent.
bool Shutdown();
- // Send a message to enable the remoting service in the service process.
- // Return true if the message was sent.
- bool EnableRemotingWithTokens(const std::string& user,
- const std::string& remoting_token,
- const std::string& talk_token);
-
// Send a message to the service process to request a response
// containing the enablement status of the cloud print proxy and the
// registered email address. The callback gets the information when
@@ -109,6 +110,17 @@ class ServiceProcessControl : public IPC::Channel::Sender,
bool GetCloudPrintProxyStatus(
Callback2<bool, std::string>::Type* cloud_print_status_callback);
+ // Send a message to enable the remoting service in the service process.
+ // Return true if the message was sent.
+ bool SetRemotingHostCredentials(const std::string& user,
+ const std::string& auth_token);
+
+ bool EnableRemotingHost();
+ bool DisableRemotingHost();
+
+ bool GetRemotingHostStatus(
+ GetRemotingHostStatusCallback* status_callback);
+
// Set the message handler for receiving messages from the service process.
// TODO(hclam): Allow more than 1 handler.
void SetMessageHandler(MessageHandler* message_handler) {
@@ -149,6 +161,7 @@ class ServiceProcessControl : public IPC::Channel::Sender,
// Callback that gets invoked when a status message is received from
// the cloud print proxy.
scoped_ptr<Callback2<bool, std::string>::Type> cloud_print_status_callback_;
+ scoped_ptr<GetRemotingHostStatusCallback> remoting_host_status_callback_;
// Handler for messages from service process.
MessageHandler* message_handler_;
diff --git a/chrome/browser/service/service_process_control_browsertest.cc b/chrome/browser/service/service_process_control_browsertest.cc
index ca47f9e..8cf596c 100644
--- a/chrome/browser/service/service_process_control_browsertest.cc
+++ b/chrome/browser/service/service_process_control_browsertest.cc
@@ -23,13 +23,13 @@ class ServiceProcessControlBrowserTest
base::CloseProcessHandle(service_process_handle_);
service_process_handle_ = base::kNullProcessHandle;
// Delete all instances of ServiceProcessControl.
- ServiceProcessControlManager::instance()->Shutdown();
+ ServiceProcessControlManager::GetInstance()->Shutdown();
}
protected:
void LaunchServiceProcessControl() {
ServiceProcessControl* process =
- ServiceProcessControlManager::instance()->GetProcessControl(
+ ServiceProcessControlManager::GetInstance()->GetProcessControl(
browser()->profile());
process_ = process;
@@ -55,7 +55,7 @@ class ServiceProcessControlBrowserTest
void Disconnect() {
// This will delete all instances of ServiceProcessControl and close the IPC
// connections.
- ServiceProcessControlManager::instance()->Shutdown();
+ ServiceProcessControlManager::GetInstance()->Shutdown();
process_ = NULL;
}
@@ -140,7 +140,7 @@ static void DecrementUntilZero(int* count) {
// get invoked.
IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, MultipleLaunchTasks) {
ServiceProcessControl* process =
- ServiceProcessControlManager::instance()->GetProcessControl(
+ ServiceProcessControlManager::GetInstance()->GetProcessControl(
browser()->profile());
int launch_count = 5;
for (int i = 0; i < launch_count; i++) {
@@ -159,7 +159,7 @@ IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, MultipleLaunchTasks) {
// Make sure using the same task for success and failure tasks works.
IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, SameLaunchTask) {
ServiceProcessControl* process =
- ServiceProcessControlManager::instance()->GetProcessControl(
+ ServiceProcessControlManager::GetInstance()->GetProcessControl(
browser()->profile());
int launch_count = 5;
for (int i = 0; i < launch_count; i++) {
diff --git a/chrome/browser/service/service_process_control_manager.cc b/chrome/browser/service/service_process_control_manager.cc
index 2cddf12..cb405fe 100644
--- a/chrome/browser/service/service_process_control_manager.cc
+++ b/chrome/browser/service/service_process_control_manager.cc
@@ -7,7 +7,7 @@
#include "base/singleton.h"
#include "base/stl_util-inl.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/service/service_process_control.h"
ServiceProcessControlManager::ServiceProcessControlManager() {
@@ -42,6 +42,6 @@ void ServiceProcessControlManager::Shutdown() {
}
// static
-ServiceProcessControlManager* ServiceProcessControlManager::instance() {
+ServiceProcessControlManager* ServiceProcessControlManager::GetInstance() {
return Singleton<ServiceProcessControlManager>::get();
}
diff --git a/chrome/browser/service/service_process_control_manager.h b/chrome/browser/service/service_process_control_manager.h
index a57c43e..a27ec03 100644
--- a/chrome/browser/service/service_process_control_manager.h
+++ b/chrome/browser/service/service_process_control_manager.h
@@ -32,7 +32,7 @@ class ServiceProcessControlManager {
void Shutdown();
// Return the instance of ServiceProcessControlManager.
- static ServiceProcessControlManager* instance();
+ static ServiceProcessControlManager* GetInstance();
private:
ServiceProcessControlList process_control_list_;
diff --git a/chrome/browser/sessions/base_session_service.cc b/chrome/browser/sessions/base_session_service.cc
index 6b809eb..aa981f9 100644
--- a/chrome/browser/sessions/base_session_service.cc
+++ b/chrome/browser/sessions/base_session_service.cc
@@ -8,7 +8,7 @@
#include "base/stl_util-inl.h"
#include "base/thread.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_backend.h"
#include "chrome/browser/sessions/session_types.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
diff --git a/chrome/browser/sessions/session_restore.cc b/chrome/browser/sessions/session_restore.cc
index 3417215..43f677a 100644
--- a/chrome/browser/sessions/session_restore.cc
+++ b/chrome/browser/sessions/session_restore.cc
@@ -4,6 +4,9 @@
#include "chrome/browser/sessions/session_restore.h"
+#include <algorithm>
+#include <list>
+#include <set>
#include <vector>
#include "base/callback.h"
@@ -11,9 +14,8 @@
#include "base/scoped_ptr.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_service.h"
#include "chrome/browser/sessions/session_types.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
diff --git a/chrome/browser/sessions/session_restore_browsertest.cc b/chrome/browser/sessions/session_restore_browsertest.cc
index e3c3145..a6b6f2a 100644
--- a/chrome/browser/sessions/session_restore_browsertest.cc
+++ b/chrome/browser/sessions/session_restore_browsertest.cc
@@ -4,6 +4,7 @@
#include "base/file_path.h"
#include "chrome/browser/defaults.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/tab_restore_service.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tabs/tab_strip_model.h"
diff --git a/chrome/browser/sessions/session_service.cc b/chrome/browser/sessions/session_service.cc
index 0498b34..35ddee5 100644
--- a/chrome/browser/sessions/session_service.cc
+++ b/chrome/browser/sessions/session_service.cc
@@ -2,13 +2,13 @@
// 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"
-
#include "chrome/browser/sessions/session_service.h"
+#include <algorithm>
#include <limits>
+#include <set>
+#include <vector>
-#include "base/callback.h"
#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/metrics/histogram.h"
@@ -16,11 +16,9 @@
#include "base/scoped_vector.h"
#include "base/thread.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_window.h"
-#include "chrome/browser/defaults.h"
#include "chrome/browser/prefs/session_startup_pref.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_backend.h"
#include "chrome/browser/sessions/session_command.h"
#include "chrome/browser/sessions/session_restore.h"
diff --git a/chrome/browser/sessions/session_service.h b/chrome/browser/sessions/session_service.h
index 2b51734..f17b77a 100644
--- a/chrome/browser/sessions/session_service.h
+++ b/chrome/browser/sessions/session_service.h
@@ -347,7 +347,7 @@ class SessionService : public BaseSessionService,
// Schedules the specified command. This method takes ownership of the
// command.
- void ScheduleCommand(SessionCommand* command);
+ virtual void ScheduleCommand(SessionCommand* command);
// Converts all pending tab/window closes to commands and schedules them.
void CommitPendingCloses();
diff --git a/chrome/browser/sessions/session_types.h b/chrome/browser/sessions/session_types.h
index 4f84246..a16b680 100644
--- a/chrome/browser/sessions/session_types.h
+++ b/chrome/browser/sessions/session_types.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// 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.
@@ -11,13 +11,13 @@
#include "base/stl_util-inl.h"
#include "base/string16.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/sessions/session_id.h"
#include "chrome/common/page_transition_types.h"
#include "gfx/rect.h"
#include "googleurl/src/gurl.h"
class NavigationEntry;
+class Profile;
// TabNavigation -------------------------------------------------------------
@@ -190,4 +190,3 @@ struct ForeignSession {
};
#endif // CHROME_BROWSER_SESSIONS_SESSION_TYPES_H_
-
diff --git a/chrome/browser/sessions/tab_restore_service.cc b/chrome/browser/sessions/tab_restore_service.cc
index c295d76..3839321 100644
--- a/chrome/browser/sessions/tab_restore_service.cc
+++ b/chrome/browser/sessions/tab_restore_service.cc
@@ -13,7 +13,7 @@
#include "base/stl_util-inl.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_service.h"
#include "chrome/browser/sessions/session_command.h"
#include "chrome/browser/sessions/session_types.h"
diff --git a/chrome/browser/sessions/tab_restore_service_browsertest.cc b/chrome/browser/sessions/tab_restore_service_browsertest.cc
index 46f91e8..dc37fa1 100644
--- a/chrome/browser/sessions/tab_restore_service_browsertest.cc
+++ b/chrome/browser/sessions/tab_restore_service_browsertest.cc
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/defaults.h"
#include "chrome/browser/renderer_host/test/test_render_view_host.h"
#include "chrome/browser/sessions/session_types.h"
#include "chrome/browser/sessions/session_service.h"
diff --git a/chrome/browser/shell_integration_linux.cc b/chrome/browser/shell_integration_linux.cc
index 0a88c5d..b74df15 100644
--- a/chrome/browser/shell_integration_linux.cc
+++ b/chrome/browser/shell_integration_linux.cc
@@ -29,7 +29,6 @@
#include "base/task.h"
#include "base/thread.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
@@ -294,7 +293,7 @@ bool ShellIntegration::GetDesktopShortcutTemplate(
FilePath ShellIntegration::GetDesktopShortcutFilename(const GURL& url) {
// Use a prefix, because xdg-desktop-menu requires it.
std::string filename =
- WideToUTF8(chrome::kBrowserProcessExecutableName) + "-" + url.spec();
+ std::string(chrome::kBrowserProcessExecutableName) + "-" + url.spec();
file_util::ReplaceIllegalCharactersInPath(&filename, '_');
FilePath desktop_path;
diff --git a/chrome/browser/shell_integration_unittest.cc b/chrome/browser/shell_integration_unittest.cc
index c832b74..9b9a218 100644
--- a/chrome/browser/shell_integration_unittest.cc
+++ b/chrome/browser/shell_integration_unittest.cc
@@ -150,7 +150,7 @@ TEST(ShellIntegrationTest, GetDesktopShortcutFilename) {
{ FPL("http___.._.desktop"), "http://../../../../" },
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); i++) {
- EXPECT_EQ(WideToASCII(chrome::kBrowserProcessExecutableName) + "-" +
+ EXPECT_EQ(std::string(chrome::kBrowserProcessExecutableName) + "-" +
test_cases[i].path,
ShellIntegration::GetDesktopShortcutFilename(
GURL(test_cases[i].url)).value()) <<
diff --git a/chrome/browser/shell_integration_win.cc b/chrome/browser/shell_integration_win.cc
index f358ffd..ad1f653 100644
--- a/chrome/browser/shell_integration_win.cc
+++ b/chrome/browser/shell_integration_win.cc
@@ -265,15 +265,16 @@ bool MigrateChromiumShortcutsTask::GetShortcutAppId(
};
bool ShellIntegration::SetAsDefaultBrowser() {
- std::wstring chrome_exe;
+ FilePath chrome_exe;
if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
LOG(ERROR) << "Error getting app exe path";
return false;
}
// From UI currently we only allow setting default browser for current user.
- if (!ShellUtil::MakeChromeDefault(ShellUtil::CURRENT_USER,
- chrome_exe, true)) {
+ BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+ if (!ShellUtil::MakeChromeDefault(dist, ShellUtil::CURRENT_USER,
+ chrome_exe.value(), true)) {
LOG(ERROR) << "Chrome could not be set as default browser.";
return false;
}
@@ -285,7 +286,7 @@ bool ShellIntegration::SetAsDefaultBrowser() {
ShellIntegration::DefaultBrowserState ShellIntegration::IsDefaultBrowser() {
// First determine the app path. If we can't determine what that is, we have
// bigger fish to fry...
- std::wstring app_path;
+ FilePath app_path;
if (!PathService::Get(base::FILE_EXE, &app_path)) {
LOG(ERROR) << "Error getting app exe path";
return UNKNOWN_DEFAULT_BROWSER;
@@ -315,7 +316,7 @@ ShellIntegration::DefaultBrowserState ShellIntegration::IsDefaultBrowser() {
// app name being default. If not, then default browser is just called
// Google Chrome or Chromium so we do not append suffix to app name.
std::wstring suffix;
- if (ShellUtil::GetUserSpecificDefaultBrowserSuffix(&suffix))
+ if (ShellUtil::GetUserSpecificDefaultBrowserSuffix(dist, &suffix))
app_name += suffix;
for (int i = 0; i < _countof(kChromeProtocols); i++) {
@@ -330,7 +331,8 @@ ShellIntegration::DefaultBrowserState ShellIntegration::IsDefaultBrowser() {
pAAR->Release();
} else {
std::wstring short_app_path;
- GetShortPathName(app_path.c_str(), WriteInto(&short_app_path, MAX_PATH),
+ GetShortPathName(app_path.value().c_str(),
+ WriteInto(&short_app_path, MAX_PATH),
MAX_PATH);
// open command for protocol associations
diff --git a/chrome/browser/show_options_url.cc b/chrome/browser/show_options_url.cc
deleted file mode 100644
index 3761da4..0000000
--- a/chrome/browser/show_options_url.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// 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.
-
-#include "chrome/browser/show_options_url.h"
-
-#include "chrome/browser/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_window.h"
-
-namespace browser {
-
-void ShowOptionsURL(Profile* profile, const GURL& url) {
- // We open a new browser window so the Options dialog doesn't get lost behind
- // other windows.
- Browser* browser = Browser::Create(profile);
- browser->AddSelectedTabWithURL(url, PageTransition::LINK);
- browser->window()->Show();
-}
-
-} // namespace browser
diff --git a/chrome/browser/show_options_url.h b/chrome/browser/show_options_url.h
deleted file mode 100644
index afa339d..0000000
--- a/chrome/browser/show_options_url.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_SHOW_OPTIONS_URL_H_
-#define CHROME_BROWSER_SHOW_OPTIONS_URL_H_
-#pragma once
-
-class GURL;
-class Profile;
-
-namespace browser {
-
-// Opens a tab showing the specified url. This is intended for use any place
-// we show a URL in the options dialogs.
-void ShowOptionsURL(Profile* profile, const GURL& url);
-
-} // namespace browser
-
-#endif // CHROME_BROWSER_SHOW_OPTIONS_URL_H_
diff --git a/chrome/browser/sidebar/sidebar_container.cc b/chrome/browser/sidebar/sidebar_container.cc
index aae917a..7112433 100644
--- a/chrome/browser/sidebar/sidebar_container.cc
+++ b/chrome/browser/sidebar/sidebar_container.cc
@@ -67,3 +67,8 @@ void SidebarContainer::SetIcon(const SkBitmap& bitmap) {
void SidebarContainer::SetTitle(const string16& title) {
title_ = title;
}
+
+bool SidebarContainer::IsPopup(const TabContents* source) const {
+ return false;
+}
+
diff --git a/chrome/browser/sidebar/sidebar_container.h b/chrome/browser/sidebar/sidebar_container.h
index 0572f43..b519de8 100644
--- a/chrome/browser/sidebar/sidebar_container.h
+++ b/chrome/browser/sidebar/sidebar_container.h
@@ -105,7 +105,7 @@ class SidebarContainer
virtual void LoadingStateChanged(TabContents* source) {}
virtual void CloseContents(TabContents* source) {}
virtual void MoveContents(TabContents* source, const gfx::Rect& pos) {}
- virtual bool IsPopup(const TabContents* source) const { return false; }
+ virtual bool IsPopup(const TabContents* source) const;
virtual void URLStarredChanged(TabContents* source, bool starred) {}
virtual void UpdateTargetURL(TabContents* source, const GURL& url) {}
virtual void ToolbarSizeChanged(TabContents* source, bool is_animating) {}
@@ -136,4 +136,3 @@ class SidebarContainer
};
#endif // CHROME_BROWSER_SIDEBAR_SIDEBAR_CONTAINER_H_
-
diff --git a/chrome/browser/sidebar/sidebar_manager.cc b/chrome/browser/sidebar/sidebar_manager.cc
index e77041c..9793224 100644
--- a/chrome/browser/sidebar/sidebar_manager.cc
+++ b/chrome/browser/sidebar/sidebar_manager.cc
@@ -10,7 +10,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extension_sidebar_api.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/sidebar/sidebar_container.h"
#include "chrome/common/chrome_switches.h"
diff --git a/chrome/browser/sidebar/sidebar_test.cc b/chrome/browser/sidebar/sidebar_test.cc
index eb83630..e567791 100644
--- a/chrome/browser/sidebar/sidebar_test.cc
+++ b/chrome/browser/sidebar/sidebar_test.cc
@@ -44,9 +44,7 @@ class SidebarTest : public InProcessBrowserTest {
}
void NavigateSidebarForCurrentTabTo(const std::string& test_page) {
- net::TestServer* server = test_server();
- ASSERT_TRUE(server);
- GURL url = server->GetURL(test_page);
+ GURL url = test_server()->GetURL(test_page);
TabContents* tab = browser()->GetSelectedTabContents();
@@ -165,13 +163,9 @@ IN_PROC_BROWSER_TEST_F(SidebarTest, SidebarOnInactiveTab) {
HideSidebarForCurrentTab();
}
-// FAILS, http://crbug.com/57964
-#if defined(OS_WIN)
-#define MAYBE_SidebarNavigate DISABLED_SidebarNavigate
-#else
-#define MAYBE_SidebarNavigate SidebarNavigate
-#endif
-IN_PROC_BROWSER_TEST_F(SidebarTest, MAYBE_SidebarNavigate) {
+IN_PROC_BROWSER_TEST_F(SidebarTest, SidebarNavigate) {
+ ASSERT_TRUE(test_server()->Start());
+
ShowSidebarForCurrentTab();
NavigateSidebarForCurrentTabTo(kSimplePage);
diff --git a/chrome/browser/speech/speech_input_browsertest.cc b/chrome/browser/speech/speech_input_browsertest.cc
index d49cb3c..05dd4f6 100644
--- a/chrome/browser/speech/speech_input_browsertest.cc
+++ b/chrome/browser/speech/speech_input_browsertest.cc
@@ -160,16 +160,13 @@ class SpeechInputBrowserTest : public InProcessBrowserTest {
SpeechInputManager* SpeechInputBrowserTest::speech_input_manager_ = NULL;
+// Marked as FLAKY due to http://crbug.com/51337
+//
// TODO(satish): Once this flakiness has been fixed, add a second test here to
// check for sending many clicks in succession to the speech button and verify
// that it doesn't cause any crash but works as expected. This should act as the
// test for http://crbug.com/59173
-#if defined(GOOGLE_CHROME_BUILD)
-// The tests are disabled for release branches since the speech input API is
-// disabled on the release branches.
-#define MAYBE_TestBasicRecognition DISABLED_TestBasicRecognition
-#elif defined(OS_WIN)
-// Marked as FLAKY due to http://crbug.com/51337
+#if defined(OS_WIN)
#define MAYBE_TestBasicRecognition FLAKY_TestBasicRecognition
#else
#define MAYBE_TestBasicRecognition TestBasicRecognition
@@ -179,12 +176,8 @@ IN_PROC_BROWSER_TEST_F(SpeechInputBrowserTest, MAYBE_TestBasicRecognition) {
EXPECT_TRUE(fake_speech_input_manager_.grammar().empty());
}
-#if defined(GOOGLE_CHROME_BUILD)
-// The tests are disabled for release branches since the speech input API is
-// disabled on the release branches.
-#define MAYBE_GrammarAttribute DISABLED_GrammarAttribute
-#elif defined(OS_WIN)
// Marked as FLAKY due to http://crbug.com/51337
+#if defined(OS_WIN)
#define MAYBE_GrammarAttribute FLAKY_GrammarAttribute
#else
#define MAYBE_GrammarAttribute GrammarAttribute
diff --git a/chrome/browser/speech/speech_input_bubble.cc b/chrome/browser/speech/speech_input_bubble.cc
index 77619e9..655415f 100644
--- a/chrome/browser/speech/speech_input_bubble.cc
+++ b/chrome/browser/speech/speech_input_bubble.cc
@@ -32,10 +32,9 @@ SpeechInputBubble* SpeechInputBubble::Create(TabContents* tab_contents,
return CreateNativeBubble(tab_contents, delegate, element_rect);
}
-SpeechInputBubbleBase::SpeechInputBubbleBase(TabContents* tab_contents)
+SpeechInputBubbleBase::SpeechInputBubbleBase()
: ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
- display_mode_(DISPLAY_MODE_RECORDING),
- tab_contents_(tab_contents) {
+ display_mode_(DISPLAY_MODE_RECORDING) {
if (!mic_empty_) { // Static variables.
mic_empty_ = ResourceBundle::GetSharedInstance().GetBitmapNamed(
IDR_SPEECH_INPUT_MIC_EMPTY);
diff --git a/chrome/browser/speech/speech_input_bubble.h b/chrome/browser/speech/speech_input_bubble.h
index 436e6bb..3faabe0 100644
--- a/chrome/browser/speech/speech_input_bubble.h
+++ b/chrome/browser/speech/speech_input_bubble.h
@@ -99,9 +99,6 @@ class SpeechInputBubble {
// Updates the current captured audio volume displayed on screen.
virtual void SetInputVolume(float volume) = 0;
- // Returns the TabContents for which this bubble gets displayed.
- virtual TabContents* tab_contents() = 0;
-
// The horizontal distance between the start of the html widget and the speech
// bubble's arrow.
static const int kBubbleTargetOffsetX;
@@ -122,7 +119,7 @@ class SpeechInputBubbleBase : public SpeechInputBubble {
DISPLAY_MODE_MESSAGE
};
- explicit SpeechInputBubbleBase(TabContents* tab_contents);
+ SpeechInputBubbleBase();
virtual ~SpeechInputBubbleBase();
// SpeechInputBubble methods
@@ -130,7 +127,6 @@ class SpeechInputBubbleBase : public SpeechInputBubble {
virtual void SetRecognizingMode();
virtual void SetMessage(const string16& text);
virtual void SetInputVolume(float volume);
- virtual TabContents* tab_contents() { return tab_contents_; }
protected:
// Updates the platform specific UI layout for the current display mode.
@@ -163,8 +159,6 @@ class SpeechInputBubbleBase : public SpeechInputBubble {
scoped_ptr<SkBitmap> mic_image_;
// A temporary buffer image used in creating the above mic image.
scoped_ptr<SkBitmap> buffer_image_;
- // TabContents in which this this bubble gets displayed.
- TabContents* tab_contents_;
static SkBitmap* mic_full_; // Mic image with full volume.
static SkBitmap* mic_empty_; // Mic image with zero volume.
diff --git a/chrome/browser/speech/speech_input_bubble_controller.cc b/chrome/browser/speech/speech_input_bubble_controller.cc
index b048589..682d028 100644
--- a/chrome/browser/speech/speech_input_bubble_controller.cc
+++ b/chrome/browser/speech/speech_input_bubble_controller.cc
@@ -7,17 +7,13 @@
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_util.h"
-#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_source.h"
-#include "chrome/common/notification_type.h"
#include "gfx/rect.h"
namespace speech_input {
SpeechInputBubbleController::SpeechInputBubbleController(Delegate* delegate)
: delegate_(delegate),
- current_bubble_caller_id_(0),
- registrar_(new NotificationRegistrar) {
+ current_bubble_caller_id_(0) {
}
SpeechInputBubbleController::~SpeechInputBubbleController() {
@@ -47,8 +43,6 @@ void SpeechInputBubbleController::CreateBubble(int caller_id,
return;
bubbles_[caller_id] = bubble;
-
- UpdateTabContentsSubscription(caller_id, BUBBLE_ADDED);
}
void SpeechInputBubbleController::CloseBubble(int caller_id) {
@@ -76,60 +70,6 @@ void SpeechInputBubbleController::SetBubbleMessage(int caller_id,
ProcessRequestInUiThread(caller_id, REQUEST_SET_MESSAGE, text, 0);
}
-void SpeechInputBubbleController::UpdateTabContentsSubscription(
- int caller_id, ManageSubscriptionAction action) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- // If there are any other bubbles existing for the same TabContents, we would
- // have subscribed to tab close notifications on their behalf and we need to
- // stay registered. So we don't change the subscription in such cases.
- TabContents* tab_contents = bubbles_[caller_id]->tab_contents();
- for (BubbleCallerIdMap::iterator iter = bubbles_.begin();
- iter != bubbles_.end(); ++iter) {
- if (iter->second->tab_contents() == tab_contents &&
- iter->first != caller_id) {
- // At least one other bubble exists for the same TabContents. So don't
- // make any change to the subscription.
- return;
- }
- }
-
- if (action == BUBBLE_ADDED) {
- registrar_->Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
- Source<TabContents>(tab_contents));
- } else {
- registrar_->Remove(this, NotificationType::TAB_CONTENTS_DESTROYED,
- Source<TabContents>(tab_contents));
- }
-}
-
-void SpeechInputBubbleController::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- if (type == NotificationType::TAB_CONTENTS_DESTROYED) {
- // Cancel all bubbles and active recognition sessions for this tab.
- TabContents* tab_contents = Source<TabContents>(source).ptr();
- BubbleCallerIdMap::iterator iter = bubbles_.begin();
- while (iter != bubbles_.end()) {
- if (iter->second->tab_contents() == tab_contents) {
- BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(
- this,
- &SpeechInputBubbleController::InvokeDelegateButtonClicked,
- iter->first, SpeechInputBubble::BUTTON_CANCEL));
- CloseBubble(iter->first);
- // We expect to have a very small number of items in this map so
- // redo-ing from start is ok.
- iter = bubbles_.begin();
- } else {
- ++iter;
- }
- }
- } else {
- NOTREACHED() << "Unknown notification";
- }
-}
-
void SpeechInputBubbleController::ProcessRequestInUiThread(
int caller_id, RequestType type, const string16& text, float volume) {
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
@@ -169,7 +109,6 @@ void SpeechInputBubbleController::ProcessRequestInUiThread(
case REQUEST_CLOSE:
if (current_bubble_caller_id_ == caller_id)
current_bubble_caller_id_ = 0;
- UpdateTabContentsSubscription(caller_id, BUBBLE_REMOVED);
delete bubble;
bubbles_.erase(caller_id);
break;
diff --git a/chrome/browser/speech/speech_input_bubble_controller.h b/chrome/browser/speech/speech_input_bubble_controller.h
index 7bacfad..0a20333 100644
--- a/chrome/browser/speech/speech_input_bubble_controller.h
+++ b/chrome/browser/speech/speech_input_bubble_controller.h
@@ -11,12 +11,10 @@
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/speech/speech_input_bubble.h"
-#include "chrome/common/notification_observer.h"
namespace gfx {
class Rect;
}
-class NotificationRegistrar;
namespace speech_input {
@@ -27,8 +25,7 @@ namespace speech_input {
// that bubble are reported to the delegate.
class SpeechInputBubbleController
: public base::RefCountedThreadSafe<SpeechInputBubbleController>,
- public SpeechInputBubbleDelegate,
- public NotificationObserver {
+ public SpeechInputBubbleDelegate {
public:
// All methods of this delegate are called in the IO thread.
class Delegate {
@@ -76,11 +73,6 @@ class SpeechInputBubbleController
virtual void InfoBubbleButtonClicked(SpeechInputBubble::Button button);
virtual void InfoBubbleFocusChanged();
- // NotificationObserver implementation.
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
private:
// The various calls received by this object and handled in the UI thread.
enum RequestType {
@@ -91,11 +83,6 @@ class SpeechInputBubbleController
REQUEST_CLOSE,
};
- enum ManageSubscriptionAction {
- BUBBLE_ADDED,
- BUBBLE_REMOVED
- };
-
void InvokeDelegateButtonClicked(int caller_id,
SpeechInputBubble::Button button);
void InvokeDelegateFocusChanged(int caller_id);
@@ -104,18 +91,10 @@ class SpeechInputBubbleController
const string16& text,
float volume);
- // Called whenever a bubble was added to or removed from the list. If the
- // bubble was being added, this method registers for close notifications with
- // the TabContents if this was the first bubble for the tab. Similarly if the
- // bubble was being removed, this method unregisters from TabContents if this
- // was the last bubble associated with that tab.
- void UpdateTabContentsSubscription(int caller_id,
- ManageSubscriptionAction action);
-
// Only accessed in the IO thread.
Delegate* delegate_;
- // *** The following are accessed only in the UI thread.
+ //*** The following are accessed only in the UI thread.
// The caller id for currently visible bubble (since only one bubble is
// visible at any time).
@@ -123,10 +102,7 @@ class SpeechInputBubbleController
// Map of caller-ids to bubble objects. The bubbles are weak pointers owned by
// this object and get destroyed by |CloseBubble|.
- typedef std::map<int, SpeechInputBubble*> BubbleCallerIdMap;
- BubbleCallerIdMap bubbles_;
-
- scoped_ptr<NotificationRegistrar> registrar_;
+ std::map<int, SpeechInputBubble*> bubbles_;
};
// This typedef is to workaround the issue with certain versions of
diff --git a/chrome/browser/speech/speech_input_bubble_controller_unittest.cc b/chrome/browser/speech/speech_input_bubble_controller_unittest.cc
index e0ca5ba..2ed1f1b 100644
--- a/chrome/browser/speech/speech_input_bubble_controller_unittest.cc
+++ b/chrome/browser/speech/speech_input_bubble_controller_unittest.cc
@@ -5,8 +5,6 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/speech/speech_input_bubble_controller.h"
-#include "chrome/test/browser_with_test_window_test.h"
-#include "chrome/test/testing_profile.h"
#include "gfx/rect.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -24,10 +22,7 @@ class MockSpeechInputBubble : public SpeechInputBubbleBase {
BUBBLE_TEST_CLICK_TRY_AGAIN,
};
- MockSpeechInputBubble(TabContents* tab_contents,
- Delegate* delegate,
- const gfx::Rect&)
- : SpeechInputBubbleBase(tab_contents) {
+ MockSpeechInputBubble(TabContents*, Delegate* delegate, const gfx::Rect&) {
VLOG(1) << "MockSpeechInputBubble created";
MessageLoop::current()->PostTask(
FROM_HERE, NewRunnableFunction(&InvokeDelegate, delegate));
@@ -67,11 +62,12 @@ class MockSpeechInputBubble : public SpeechInputBubbleBase {
// The test fixture.
class SpeechInputBubbleControllerTest
: public SpeechInputBubbleControllerDelegate,
- public BrowserWithTestWindowTest {
+ public testing::Test {
public:
SpeechInputBubbleControllerTest()
- : BrowserWithTestWindowTest(),
- io_thread_(BrowserThread::IO), // constructs a new thread and loop
+ : io_loop_(MessageLoop::TYPE_IO),
+ ui_thread_(BrowserThread::UI), // constructs a new thread and loop
+ io_thread_(BrowserThread::IO, &io_loop_), // resuses main thread loop
cancel_clicked_(false),
try_again_clicked_(false),
focus_changed_(false),
@@ -95,28 +91,26 @@ class SpeechInputBubbleControllerTest
} else if (button == SpeechInputBubble::BUTTON_TRY_AGAIN) {
try_again_clicked_ = true;
}
- message_loop()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
+ MessageLoop::current()->Quit();
}
virtual void InfoBubbleFocusChanged(int caller_id) {
VLOG(1) << "Received InfoBubbleFocusChanged";
EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
focus_changed_ = true;
- message_loop()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
+ MessageLoop::current()->Quit();
}
// testing::Test methods.
virtual void SetUp() {
- BrowserWithTestWindowTest::SetUp();
SpeechInputBubble::set_factory(
&SpeechInputBubbleControllerTest::CreateBubble);
- io_thread_.Start();
+ ui_thread_.Start();
}
virtual void TearDown() {
SpeechInputBubble::set_factory(NULL);
- io_thread_.Stop();
- BrowserWithTestWindowTest::TearDown();
+ ui_thread_.Stop();
}
static void ActivateBubble() {
@@ -138,19 +132,14 @@ class SpeechInputBubbleControllerTest
// active.
MessageLoop::current()->PostTask(FROM_HERE,
NewRunnableFunction(&ActivateBubble));
-
- // The |tab_contents| parameter would be NULL since the dummy caller id
- // passed to CreateBubble would not have matched any active tab. So get a
- // real TabContents pointer from the test fixture and pass that, because
- // the bubble controller registers for tab close notifications which need
- // a valid TabContents.
- tab_contents = test_fixture_->browser()->GetSelectedTabContents();
return new MockSpeechInputBubble(tab_contents, delegate, element_rect);
}
protected:
// The main thread of the test is marked as the IO thread and we create a new
// one for the UI thread.
+ MessageLoop io_loop_;
+ BrowserThread ui_thread_;
BrowserThread io_thread_;
bool cancel_clicked_;
bool try_again_clicked_;
diff --git a/chrome/browser/speech/speech_input_bubble_gtk.cc b/chrome/browser/speech/speech_input_bubble_gtk.cc
index eb8b906..2b159bf 100644
--- a/chrome/browser/speech/speech_input_bubble_gtk.cc
+++ b/chrome/browser/speech/speech_input_bubble_gtk.cc
@@ -54,6 +54,7 @@ class SpeechInputBubbleGtk
Delegate* delegate_;
InfoBubbleGtk* info_bubble_;
+ TabContents* tab_contents_;
gfx::Rect element_rect_;
bool did_invoke_close_;
@@ -67,9 +68,9 @@ class SpeechInputBubbleGtk
SpeechInputBubbleGtk::SpeechInputBubbleGtk(TabContents* tab_contents,
Delegate* delegate,
const gfx::Rect& element_rect)
- : SpeechInputBubbleBase(tab_contents),
- delegate_(delegate),
+ : delegate_(delegate),
info_bubble_(NULL),
+ tab_contents_(tab_contents),
element_rect_(element_rect),
did_invoke_close_(false),
label_(NULL),
@@ -144,10 +145,10 @@ void SpeechInputBubbleGtk::Show() {
gtk_container_add(GTK_CONTAINER(content), vbox);
GtkThemeProvider* theme_provider = GtkThemeProvider::GetFrom(
- tab_contents()->profile());
+ tab_contents_->profile());
gfx::Rect rect(element_rect_.x() + kBubbleTargetOffsetX,
element_rect_.y() + element_rect_.height(), 1, 1);
- info_bubble_ = InfoBubbleGtk::Show(tab_contents()->GetNativeView(),
+ info_bubble_ = InfoBubbleGtk::Show(tab_contents_->GetNativeView(),
&rect,
content,
InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT,
diff --git a/chrome/browser/speech/speech_input_bubble_mac.mm b/chrome/browser/speech/speech_input_bubble_mac.mm
index f70ab13..d4a54f2 100644
--- a/chrome/browser/speech/speech_input_bubble_mac.mm
+++ b/chrome/browser/speech/speech_input_bubble_mac.mm
@@ -7,9 +7,9 @@
#include "chrome/browser/speech/speech_input_bubble.h"
#import "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/speech_input_window_controller.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
+#import "chrome/browser/ui/cocoa/speech_input_window_controller.h"
#include "skia/ext/skia_utils_mac.h"
namespace {
@@ -30,6 +30,7 @@ class SpeechInputBubbleImpl : public SpeechInputBubbleBase {
private:
scoped_nsobject<SpeechInputWindowController> window_;
+ TabContents* tab_contents_;
Delegate* delegate_;
gfx::Rect element_rect_;
};
@@ -37,7 +38,7 @@ class SpeechInputBubbleImpl : public SpeechInputBubbleBase {
SpeechInputBubbleImpl::SpeechInputBubbleImpl(TabContents* tab_contents,
Delegate* delegate,
const gfx::Rect& element_rect)
- : SpeechInputBubbleBase(tab_contents),
+ : tab_contents_(tab_contents),
delegate_(delegate),
element_rect_(element_rect) {
}
@@ -61,7 +62,7 @@ void SpeechInputBubbleImpl::Show() {
// Find the screen coordinates for the given tab and position the bubble's
// arrow anchor point inside that to point at the bottom-left of the html
// input element rect.
- gfx::NativeView view = tab_contents()->view()->GetNativeView();
+ gfx::NativeView view = tab_contents_->view()->GetNativeView();
NSRect tab_bounds = [view bounds];
NSPoint anchor = NSMakePoint(
tab_bounds.origin.x + element_rect_.x() + kBubbleTargetOffsetX,
@@ -71,7 +72,7 @@ void SpeechInputBubbleImpl::Show() {
anchor = [[view window] convertBaseToScreen:anchor];
window_.reset([[SpeechInputWindowController alloc]
- initWithParentWindow:tab_contents()->view()->GetTopLevelNativeWindow()
+ initWithParentWindow:tab_contents_->view()->GetTopLevelNativeWindow()
delegate:delegate_
anchoredAt:anchor]);
diff --git a/chrome/browser/speech/speech_input_bubble_views.cc b/chrome/browser/speech/speech_input_bubble_views.cc
index 1eadfc3..83ccad0 100644
--- a/chrome/browser/speech/speech_input_bubble_views.cc
+++ b/chrome/browser/speech/speech_input_bubble_views.cc
@@ -13,6 +13,10 @@
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/views/info_bubble.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
#include "gfx/canvas.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
@@ -192,7 +196,8 @@ void ContentView::Layout() {
// Implementation of SpeechInputBubble.
class SpeechInputBubbleImpl
: public SpeechInputBubbleBase,
- public InfoBubbleDelegate {
+ public InfoBubbleDelegate,
+ public NotificationObserver {
public:
SpeechInputBubbleImpl(TabContents* tab_contents,
Delegate* delegate,
@@ -211,6 +216,11 @@ class SpeechInputBubbleImpl
// |element_rect| is the html element's bounds in page coordinates.
gfx::Rect GetInfoBubbleTarget(const gfx::Rect& element_rect);
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
// InfoBubbleDelegate
virtual void InfoBubbleClosing(InfoBubble* info_bubble,
bool closed_by_escape);
@@ -220,7 +230,9 @@ class SpeechInputBubbleImpl
private:
Delegate* delegate_;
InfoBubble* info_bubble_;
+ TabContents* tab_contents_;
ContentView* bubble_content_;
+ NotificationRegistrar registrar_;
gfx::Rect element_rect_;
// Set to true if the object is being destroyed normally instead of the
@@ -233,9 +245,9 @@ class SpeechInputBubbleImpl
SpeechInputBubbleImpl::SpeechInputBubbleImpl(TabContents* tab_contents,
Delegate* delegate,
const gfx::Rect& element_rect)
- : SpeechInputBubbleBase(tab_contents),
- delegate_(delegate),
+ : delegate_(delegate),
info_bubble_(NULL),
+ tab_contents_(tab_contents),
bubble_content_(NULL),
element_rect_(element_rect),
did_invoke_close_(false) {
@@ -249,14 +261,26 @@ SpeechInputBubbleImpl::~SpeechInputBubbleImpl() {
gfx::Rect SpeechInputBubbleImpl::GetInfoBubbleTarget(
const gfx::Rect& element_rect) {
gfx::Rect container_rect;
- tab_contents()->GetContainerBounds(&container_rect);
+ tab_contents_->GetContainerBounds(&container_rect);
return gfx::Rect(
container_rect.x() + element_rect.x() + kBubbleTargetOffsetX,
container_rect.y() + element_rect.y() + element_rect.height(), 1, 1);
}
+void SpeechInputBubbleImpl::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NotificationType::TAB_CONTENTS_DESTROYED) {
+ delegate_->InfoBubbleButtonClicked(SpeechInputBubble::BUTTON_CANCEL);
+ } else {
+ NOTREACHED() << "Unknown notification";
+ }
+}
+
void SpeechInputBubbleImpl::InfoBubbleClosing(InfoBubble* info_bubble,
bool closed_by_escape) {
+ registrar_.Remove(this, NotificationType::TAB_CONTENTS_DESTROYED,
+ Source<TabContents>(tab_contents_));
info_bubble_ = NULL;
bubble_content_ = NULL;
if (!did_invoke_close_)
@@ -279,7 +303,7 @@ void SpeechInputBubbleImpl::Show() {
UpdateLayout();
views::Widget* parent = views::Widget::GetWidgetFromNativeWindow(
- tab_contents()->view()->GetTopLevelNativeWindow());
+ tab_contents_->view()->GetTopLevelNativeWindow());
info_bubble_ = InfoBubble::Show(parent,
GetInfoBubbleTarget(element_rect_),
BubbleBorder::TOP_LEFT, bubble_content_,
@@ -291,6 +315,9 @@ void SpeechInputBubbleImpl::Show() {
// to end so the caller can manage this object's life cycle like a normal
// stack based or member variable object.
info_bubble_->set_fade_away_on_close(false);
+
+ registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
+ Source<TabContents>(tab_contents_));
}
void SpeechInputBubbleImpl::Hide() {
diff --git a/chrome/browser/speech/speech_input_dispatcher_host.cc b/chrome/browser/speech/speech_input_dispatcher_host.cc
index dc5ff07..f1abebf 100644
--- a/chrome/browser/speech/speech_input_dispatcher_host.cc
+++ b/chrome/browser/speech/speech_input_dispatcher_host.cc
@@ -4,11 +4,7 @@
#include "chrome/browser/speech/speech_input_dispatcher_host.h"
-#include "base/singleton.h"
-#include "chrome/browser/renderer_host/render_process_host.h"
-#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/renderer_host/render_view_host_notification_task.h"
-#include "chrome/browser/renderer_host/resource_message_filter.h"
+#include "base/lazy_instance.h"
#include "chrome/common/render_messages.h"
namespace speech_input {
@@ -40,7 +36,7 @@ class SpeechInputDispatcherHost::SpeechInputCallers {
int render_view_id;
int request_id;
};
- friend struct DefaultSingletonTraits<SpeechInputCallers>;
+ friend struct base::DefaultLazyInstanceTraits<SpeechInputCallers>;
SpeechInputCallers();
@@ -48,6 +44,9 @@ class SpeechInputDispatcherHost::SpeechInputCallers {
int next_id_;
};
+static base::LazyInstance<SpeechInputDispatcherHost::SpeechInputCallers>
+ g_speech_input_callers(base::LINKER_INITIALIZED);
+
SpeechInputDispatcherHost::SpeechInputCallers::SpeechInputCallers()
: next_id_(1) {
}
@@ -105,11 +104,9 @@ int SpeechInputDispatcherHost::SpeechInputCallers::request_id(int id) {
SpeechInputManager::AccessorMethod*
SpeechInputDispatcherHost::manager_accessor_ = &SpeechInputManager::Get;
-SpeechInputDispatcherHost::SpeechInputDispatcherHost(
- int resource_message_filter_process_id)
- : resource_message_filter_process_id_(resource_message_filter_process_id),
- callers_(Singleton<SpeechInputCallers>::get()) {
- // This is initialized by ResourceMessageFilter. Do not add any non-trivial
+SpeechInputDispatcherHost::SpeechInputDispatcherHost(int render_process_id)
+ : render_process_id_(render_process_id) {
+ // This is initialized by Browser. Do not add any non-trivial
// initialization here, instead do it lazily when required (e.g. see the
// method |manager()|) or add an Init() method.
}
@@ -124,28 +121,17 @@ SpeechInputManager* SpeechInputDispatcherHost::manager() {
bool SpeechInputDispatcherHost::OnMessageReceived(
const IPC::Message& message, bool* message_was_ok) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- uint32 message_type = message.type();
- if (message_type == ViewHostMsg_SpeechInput_StartRecognition::ID ||
- message_type == ViewHostMsg_SpeechInput_CancelRecognition::ID ||
- message_type == ViewHostMsg_SpeechInput_StopRecording::ID) {
- if (!SpeechInputManager::IsFeatureEnabled()) {
- *message_was_ok = false;
- return true;
- }
-
- IPC_BEGIN_MESSAGE_MAP_EX(SpeechInputDispatcherHost, message,
- *message_was_ok)
- IPC_MESSAGE_HANDLER(ViewHostMsg_SpeechInput_StartRecognition,
- OnStartRecognition)
- IPC_MESSAGE_HANDLER(ViewHostMsg_SpeechInput_CancelRecognition,
- OnCancelRecognition)
- IPC_MESSAGE_HANDLER(ViewHostMsg_SpeechInput_StopRecording,
- OnStopRecording)
- IPC_END_MESSAGE_MAP()
- return true;
- }
-
- return false;
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(SpeechInputDispatcherHost, message, *message_was_ok)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_SpeechInput_StartRecognition,
+ OnStartRecognition)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_SpeechInput_CancelRecognition,
+ OnCancelRecognition)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_SpeechInput_StopRecording,
+ OnStopRecording)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
}
void SpeechInputDispatcherHost::OnStartRecognition(
@@ -154,75 +140,67 @@ void SpeechInputDispatcherHost::OnStartRecognition(
const gfx::Rect& element_rect,
const std::string& language,
const std::string& grammar) {
- int caller_id = callers_->CreateId(resource_message_filter_process_id_,
- render_view_id, request_id);
+ int caller_id = g_speech_input_callers.Get().CreateId(
+ render_process_id_, render_view_id, request_id);
manager()->StartRecognition(this, caller_id,
- resource_message_filter_process_id_,
+ render_process_id_,
render_view_id, element_rect,
language, grammar);
}
void SpeechInputDispatcherHost::OnCancelRecognition(int render_view_id,
int request_id) {
- int caller_id = callers_->GetId(resource_message_filter_process_id_,
- render_view_id, request_id);
+ int caller_id = g_speech_input_callers.Get().GetId(
+ render_process_id_, render_view_id, request_id);
if (caller_id) {
manager()->CancelRecognition(caller_id);
- callers_->RemoveId(caller_id); // Request sequence ended so remove mapping.
+ // Request sequence ended so remove mapping.
+ g_speech_input_callers.Get().RemoveId(caller_id);
}
}
void SpeechInputDispatcherHost::OnStopRecording(int render_view_id,
int request_id) {
- int caller_id = callers_->GetId(resource_message_filter_process_id_,
- render_view_id, request_id);
+ int caller_id = g_speech_input_callers.Get().GetId(
+ render_process_id_, render_view_id, request_id);
if (caller_id)
manager()->StopRecording(caller_id);
}
-void SpeechInputDispatcherHost::SendMessageToRenderView(IPC::Message* message,
- int render_view_id) {
- CallRenderViewHost(
- resource_message_filter_process_id_, render_view_id,
- &RenderViewHost::Send, message);
-}
-
void SpeechInputDispatcherHost::SetRecognitionResult(
int caller_id, const SpeechInputResultArray& result) {
VLOG(1) << "SpeechInputDispatcherHost::SetRecognitionResult enter";
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- int caller_render_view_id = callers_->render_view_id(caller_id);
- int caller_request_id = callers_->request_id(caller_id);
- SendMessageToRenderView(
- new ViewMsg_SpeechInput_SetRecognitionResult(caller_render_view_id,
- caller_request_id,
- result),
- caller_render_view_id);
+ int caller_render_view_id =
+ g_speech_input_callers.Get().render_view_id(caller_id);
+ int caller_request_id = g_speech_input_callers.Get().request_id(caller_id);
+ Send(new ViewMsg_SpeechInput_SetRecognitionResult(caller_render_view_id,
+ caller_request_id,
+ result));
VLOG(1) << "SpeechInputDispatcherHost::SetRecognitionResult exit";
}
void SpeechInputDispatcherHost::DidCompleteRecording(int caller_id) {
VLOG(1) << "SpeechInputDispatcherHost::DidCompleteRecording enter";
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- int caller_render_view_id = callers_->render_view_id(caller_id);
- int caller_request_id = callers_->request_id(caller_id);
- SendMessageToRenderView(
- new ViewMsg_SpeechInput_RecordingComplete(caller_render_view_id,
- caller_request_id),
- caller_render_view_id);
+ int caller_render_view_id =
+ g_speech_input_callers.Get().render_view_id(caller_id);
+ int caller_request_id = g_speech_input_callers.Get().request_id(caller_id);
+ Send(new ViewMsg_SpeechInput_RecordingComplete(caller_render_view_id,
+ caller_request_id));
VLOG(1) << "SpeechInputDispatcherHost::DidCompleteRecording exit";
}
void SpeechInputDispatcherHost::DidCompleteRecognition(int caller_id) {
VLOG(1) << "SpeechInputDispatcherHost::DidCompleteRecognition enter";
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- int caller_render_view_id = callers_->render_view_id(caller_id);
- int caller_request_id = callers_->request_id(caller_id);
- SendMessageToRenderView(
- new ViewMsg_SpeechInput_RecognitionComplete(caller_render_view_id,
- caller_request_id),
- caller_render_view_id);
- callers_->RemoveId(caller_id); // Request sequence ended, so remove mapping.
+ int caller_render_view_id =
+ g_speech_input_callers.Get().render_view_id(caller_id);
+ int caller_request_id = g_speech_input_callers.Get().request_id(caller_id);
+ Send(new ViewMsg_SpeechInput_RecognitionComplete(caller_render_view_id,
+ caller_request_id));
+ // Request sequence ended, so remove mapping.
+ g_speech_input_callers.Get().RemoveId(caller_id);
VLOG(1) << "SpeechInputDispatcherHost::DidCompleteRecognition exit";
}
diff --git a/chrome/browser/speech/speech_input_dispatcher_host.h b/chrome/browser/speech/speech_input_dispatcher_host.h
index 85ca5c0..51ae04c 100644
--- a/chrome/browser/speech/speech_input_dispatcher_host.h
+++ b/chrome/browser/speech/speech_input_dispatcher_host.h
@@ -5,32 +5,31 @@
#ifndef CHROME_BROWSER_SPEECH_SPEECH_INPUT_DISPATCHER_HOST_H_
#define CHROME_BROWSER_SPEECH_SPEECH_INPUT_DISPATCHER_HOST_H_
-#include "base/basictypes.h"
-#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
+#include "chrome/browser/browser_message_filter.h"
#include "chrome/browser/speech/speech_input_manager.h"
-#include "ipc/ipc_message.h"
namespace speech_input {
// SpeechInputDispatcherHost is a delegate for Speech API messages used by
-// ResourceMessageFilter.
+// RenderMessageFilter.
// It's the complement of SpeechInputDispatcher (owned by RenderView).
-class SpeechInputDispatcherHost
- : public base::RefCountedThreadSafe<SpeechInputDispatcherHost>,
- public SpeechInputManager::Delegate {
+class SpeechInputDispatcherHost : public BrowserMessageFilter,
+ public SpeechInputManager::Delegate {
public:
- explicit SpeechInputDispatcherHost(int resource_message_filter_process_id);
+ class SpeechInputCallers;
+
+ explicit SpeechInputDispatcherHost(int render_process_id);
// SpeechInputManager::Delegate methods.
- void SetRecognitionResult(int caller_id,
- const SpeechInputResultArray& result);
- void DidCompleteRecording(int caller_id);
- void DidCompleteRecognition(int caller_id);
+ virtual void SetRecognitionResult(int caller_id,
+ const SpeechInputResultArray& result);
+ virtual void DidCompleteRecording(int caller_id);
+ virtual void DidCompleteRecognition(int caller_id);
- // Called to possibly handle the incoming IPC message. Returns true if
- // handled.
- bool OnMessageReceived(const IPC::Message& msg, bool* msg_was_ok);
+ // BrowserMessageFilter implementation.
+ virtual bool OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok);
// Singleton accessor setter useful for tests.
static void set_manager_accessor(SpeechInputManager::AccessorMethod* method) {
@@ -38,11 +37,7 @@ class SpeechInputDispatcherHost
}
private:
- class SpeechInputCallers;
- friend class base::RefCountedThreadSafe<SpeechInputDispatcherHost>;
-
virtual ~SpeechInputDispatcherHost();
- void SendMessageToRenderView(IPC::Message* message, int render_view_id);
void OnStartRecognition(int render_view_id, int request_id,
const gfx::Rect& element_rect,
@@ -55,8 +50,7 @@ class SpeechInputDispatcherHost
// needed.
SpeechInputManager* manager();
- int resource_message_filter_process_id_;
- SpeechInputCallers* callers_; // weak reference to a singleton.
+ int render_process_id_;
static SpeechInputManager::AccessorMethod* manager_accessor_;
diff --git a/chrome/browser/speech/speech_input_manager.cc b/chrome/browser/speech/speech_input_manager.cc
index b418265..b370da4 100644
--- a/chrome/browser/speech/speech_input_manager.cc
+++ b/chrome/browser/speech/speech_input_manager.cc
@@ -4,29 +4,26 @@
#include "chrome/browser/speech/speech_input_manager.h"
+#include <map>
+#include <string>
+
#include "app/l10n_util.h"
-#include "base/command_line.h"
#include "base/lock.h"
#include "base/ref_counted.h"
-#include "base/singleton.h"
-#include "base/thread_restrictions.h"
+#include "base/lazy_instance.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/browser/platform_util.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/speech/speech_input_bubble_controller.h"
#include "chrome/browser/speech/speech_recognizer.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
#include "media/audio/audio_manager.h"
-#include <map>
#if defined(OS_WIN)
+#include "chrome/browser/browser_process.h"
#include "chrome/installer/util/wmi.h"
#endif
@@ -75,15 +72,15 @@ class HardwareInfo : public base::RefCountedThreadSafe<HardwareInfo> {
Lock lock_;
std::string value_;
-#else // defined(OS_WIN)
+#else // defined(OS_WIN)
void Refresh() {}
std::string value() { return std::string(); }
-#endif // defined(OS_WIN)
+#endif // defined(OS_WIN)
DISALLOW_COPY_AND_ASSIGN(HardwareInfo);
};
-}
+} // namespace
namespace speech_input {
@@ -126,7 +123,7 @@ class SpeechInputManagerImpl : public SpeechInputManager,
};
// Private constructor to enforce singleton.
- friend struct DefaultSingletonTraits<SpeechInputManagerImpl>;
+ friend struct base::DefaultLazyInstanceTraits<SpeechInputManagerImpl>;
SpeechInputManagerImpl();
virtual ~SpeechInputManagerImpl();
@@ -138,6 +135,7 @@ class SpeechInputManagerImpl : public SpeechInputManager,
// Starts/restarts recognition for an existing request.
void StartRecognitionForRequest(int caller_id);
+ SpeechInputManagerDelegate* delegate_;
typedef std::map<int, SpeechInputRequest> SpeechRecognizerMap;
SpeechRecognizerMap requests_;
int recording_caller_id_;
@@ -145,28 +143,11 @@ class SpeechInputManagerImpl : public SpeechInputManager,
scoped_refptr<HardwareInfo> hardware_info_;
};
-SpeechInputManager* SpeechInputManager::Get() {
- return Singleton<SpeechInputManagerImpl>::get();
-}
+static ::base::LazyInstance<SpeechInputManagerImpl> g_speech_input_manager_impl(
+ base::LINKER_INITIALIZED);
-bool SpeechInputManager::IsFeatureEnabled() {
- bool enabled = true;
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
-
- if (command_line.HasSwitch(switches::kDisableSpeechInput)) {
- enabled = false;
-#if defined(GOOGLE_CHROME_BUILD)
- } else if (!command_line.HasSwitch(switches::kEnableSpeechInput)) {
- // We need to evaluate whether IO is OK here. http://crbug.com/63335.
- base::ThreadRestrictions::ScopedAllowIO allow_io;
- // Official Chrome builds have speech input enabled by default only in the
- // dev channel.
- std::string channel = platform_util::GetVersionStringModifier();
- enabled = (channel == "dev");
-#endif
- }
-
- return enabled;
+SpeechInputManager* SpeechInputManager::Get() {
+ return g_speech_input_manager_impl.Pointer();
}
SpeechInputManagerImpl::SpeechInputManagerImpl()
diff --git a/chrome/browser/speech/speech_input_manager.h b/chrome/browser/speech/speech_input_manager.h
index b16b76a..be9779f 100644
--- a/chrome/browser/speech/speech_input_manager.h
+++ b/chrome/browser/speech/speech_input_manager.h
@@ -32,10 +32,6 @@ class SpeechInputManager {
virtual ~Delegate() {}
};
- // Whether the speech input feature is enabled, based on the browser channel
- // information and command line flags.
- static bool IsFeatureEnabled();
-
// Factory method to access the singleton. We have this method here instead of
// using Singleton<> directly in the calling code to aid tests in injection
// mocks.
diff --git a/chrome/browser/speech/speech_recognition_request.h b/chrome/browser/speech/speech_recognition_request.h
index 585b0a4..d6e9566 100644
--- a/chrome/browser/speech/speech_recognition_request.h
+++ b/chrome/browser/speech/speech_recognition_request.h
@@ -53,12 +53,12 @@ class SpeechRecognitionRequest : public URLFetcher::Delegate {
bool HasPendingRequest() { return url_fetcher_ != NULL; }
// URLFetcher::Delegate methods.
- void OnURLFetchComplete(const URLFetcher* source,
- const GURL& url,
- const URLRequestStatus& status,
- int response_code,
- const ResponseCookies& cookies,
- const std::string& data);
+ virtual void OnURLFetchComplete(const URLFetcher* source,
+ const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data);
private:
scoped_refptr<URLRequestContextGetter> url_context_;
diff --git a/chrome/browser/speech/speech_recognizer.cc b/chrome/browser/speech/speech_recognizer.cc
index 4905914..3140d46 100644
--- a/chrome/browser/speech/speech_recognizer.cc
+++ b/chrome/browser/speech/speech_recognizer.cc
@@ -8,7 +8,7 @@
#include "base/scoped_ptr.h"
#include "base/time.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/net/url_request_context_getter.h"
#include "third_party/speex/include/speex/speex.h"
diff --git a/chrome/browser/speech/speech_recognizer.h b/chrome/browser/speech/speech_recognizer.h
index 3b0f707..cafba28 100644
--- a/chrome/browser/speech/speech_recognizer.h
+++ b/chrome/browser/speech/speech_recognizer.h
@@ -94,14 +94,16 @@ class SpeechRecognizer
void CancelRecognition();
// AudioInputController::EventHandler methods.
- void OnCreated(media::AudioInputController* controller) { }
- void OnRecording(media::AudioInputController* controller) { }
- void OnError(media::AudioInputController* controller, int error_code);
- void OnData(media::AudioInputController* controller, const uint8* data,
- uint32 size);
+ virtual void OnCreated(media::AudioInputController* controller) { }
+ virtual void OnRecording(media::AudioInputController* controller) { }
+ virtual void OnError(media::AudioInputController* controller, int error_code);
+ virtual void OnData(media::AudioInputController* controller,
+ const uint8* data,
+ uint32 size);
// SpeechRecognitionRequest::Delegate methods.
- void SetRecognitionResult(bool error, const SpeechInputResultArray& result);
+ virtual void SetRecognitionResult(bool error,
+ const SpeechInputResultArray& result);
static const int kAudioSampleRate;
static const int kAudioPacketIntervalMs; // Duration of each audio packet.
diff --git a/chrome/browser/spellcheck_host.cc b/chrome/browser/spellcheck_host.cc
index 7caeb6c..638c83f 100644
--- a/chrome/browser/spellcheck_host.cc
+++ b/chrome/browser/spellcheck_host.cc
@@ -14,7 +14,7 @@
#include "base/thread_restrictions.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/prefs/pref_member.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/spellcheck_host_observer.h"
#include "chrome/browser/spellchecker_platform_engine.h"
#include "chrome/common/chrome_constants.h"
diff --git a/chrome/browser/ssl/ssl_add_cert_handler.cc b/chrome/browser/ssl/ssl_add_cert_handler.cc
index 668df59..e2356af 100644
--- a/chrome/browser/ssl/ssl_add_cert_handler.cc
+++ b/chrome/browser/ssl/ssl_add_cert_handler.cc
@@ -14,7 +14,7 @@
#include "net/base/x509_certificate.h"
#include "net/url_request/url_request.h"
-SSLAddCertHandler::SSLAddCertHandler(URLRequest* request,
+SSLAddCertHandler::SSLAddCertHandler(net::URLRequest* request,
net::X509Certificate* cert,
int render_process_host_id,
int render_view_id)
diff --git a/chrome/browser/ssl/ssl_blocking_page.cc b/chrome/browser/ssl/ssl_blocking_page.cc
index 45bca07..b2bf6a1 100644
--- a/chrome/browser/ssl/ssl_blocking_page.cc
+++ b/chrome/browser/ssl/ssl_blocking_page.cc
@@ -103,7 +103,7 @@ std::string SSLBlockingPage::GetHTMLContents() {
void SSLBlockingPage::UpdateEntry(NavigationEntry* entry) {
const net::SSLInfo& ssl_info = handler_->ssl_info();
- int cert_id = CertStore::GetSharedInstance()->StoreCert(
+ int cert_id = CertStore::GetInstance()->StoreCert(
ssl_info.cert, tab()->render_view_host()->process()->id());
entry->ssl().set_security_style(SECURITY_STYLE_AUTHENTICATION_BROKEN);
diff --git a/chrome/browser/ssl/ssl_browser_tests.cc b/chrome/browser/ssl/ssl_browser_tests.cc
index ad614d4..3919fc3 100644
--- a/chrome/browser/ssl/ssl_browser_tests.cc
+++ b/chrome/browser/ssl/ssl_browser_tests.cc
@@ -5,14 +5,13 @@
#include "base/time.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/interstitial_page.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_navigator.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
@@ -164,6 +163,33 @@ class SSLUITest : public InProcessBrowserTest {
top_frame_path);
}
+ static bool GetPageWithUnsafeWorkerPath(
+ const net::TestServer& expired_https_server,
+ std::string* page_with_unsafe_worker_path) {
+ // Get the "imported.js" URL from the expired https server and
+ // substitute it into the unsafe_worker.js file.
+ GURL imported_js_url = expired_https_server.GetURL("files/ssl/imported.js");
+ std::vector<net::TestServer::StringPair> replacement_text_for_unsafe_worker;
+ replacement_text_for_unsafe_worker.push_back(
+ make_pair("REPLACE_WITH_IMPORTED_JS_URL", imported_js_url.spec()));
+ std::string unsafe_worker_path;
+ if (!net::TestServer::GetFilePathWithReplacements(
+ "unsafe_worker.js",
+ replacement_text_for_unsafe_worker,
+ &unsafe_worker_path))
+ return false;
+
+ // Now, substitute this into the page with unsafe worker.
+ std::vector<net::TestServer::StringPair>
+ replacement_text_for_page_with_unsafe_worker;
+ replacement_text_for_page_with_unsafe_worker.push_back(
+ make_pair("REPLACE_WITH_UNSAFE_WORKER_PATH", unsafe_worker_path));
+ return net::TestServer::GetFilePathWithReplacements(
+ "files/ssl/page_with_unsafe_worker.html",
+ replacement_text_for_page_with_unsafe_worker,
+ page_with_unsafe_worker_path);
+ }
+
net::TestServer https_server_;
net::TestServer https_server_expired_;
net::TestServer https_server_mismatched_;
@@ -1031,8 +1057,11 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, FLAKY_TestUnsafeContentsInWorkerFiltered) {
// This page will spawn a Worker which will try to load content from
// BadCertServer.
+ std::string page_with_unsafe_worker_path;
+ ASSERT_TRUE(GetPageWithUnsafeWorkerPath(https_server_expired_,
+ &page_with_unsafe_worker_path));
ui_test_utils::NavigateToURL(browser(), https_server_.GetURL(
- "files/ssl/page_with_unsafe_worker.html"));
+ page_with_unsafe_worker_path));
TabContents* tab = browser()->GetSelectedTabContents();
// Expect Worker not to load insecure content.
CheckWorkerLoadResult(tab, false);
@@ -1059,8 +1088,11 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, FLAKY_TestUnsafeContentsInWorker) {
// Navigate to safe page that has Worker loading unsafe content.
// Expect content to load but be marked as auth broken due to running insecure
// content.
+ std::string page_with_unsafe_worker_path;
+ ASSERT_TRUE(GetPageWithUnsafeWorkerPath(https_server_expired_,
+ &page_with_unsafe_worker_path));
ui_test_utils::NavigateToURL(browser(), https_server_.GetURL(
- "files/ssl/page_with_unsafe_worker.html"));
+ page_with_unsafe_worker_path));
CheckWorkerLoadResult(tab, true); // Worker loads insecure content
CheckAuthenticationBrokenState(tab, 0, true, false);
}
diff --git a/chrome/browser/ssl/ssl_cert_error_handler.cc b/chrome/browser/ssl/ssl_cert_error_handler.cc
index b3d7f87..97b0e05 100644
--- a/chrome/browser/ssl/ssl_cert_error_handler.cc
+++ b/chrome/browser/ssl/ssl_cert_error_handler.cc
@@ -11,7 +11,7 @@
SSLCertErrorHandler::SSLCertErrorHandler(
ResourceDispatcherHost* rdh,
- URLRequest* request,
+ net::URLRequest* request,
ResourceType::Type resource_type,
const std::string& frame_origin,
const std::string& main_frame_origin,
@@ -28,6 +28,10 @@ SSLCertErrorHandler::SSLCertErrorHandler(
ssl_info_.SetCertError(cert_error);
}
+SSLCertErrorHandler* SSLCertErrorHandler::AsSSLCertErrorHandler() {
+ return this;
+}
+
void SSLCertErrorHandler::OnDispatchFailed() {
CancelRequest();
}
diff --git a/chrome/browser/ssl/ssl_cert_error_handler.h b/chrome/browser/ssl/ssl_cert_error_handler.h
index a4bdd0d..4f71999 100644
--- a/chrome/browser/ssl/ssl_cert_error_handler.h
+++ b/chrome/browser/ssl/ssl_cert_error_handler.h
@@ -29,7 +29,7 @@ class SSLCertErrorHandler : public SSLErrorHandler {
int cert_error,
net::X509Certificate* cert);
- virtual SSLCertErrorHandler* AsSSLCertErrorHandler() { return this; }
+ virtual SSLCertErrorHandler* AsSSLCertErrorHandler();
// These accessors are available on either thread
const net::SSLInfo& ssl_info() const { return ssl_info_; }
diff --git a/chrome/browser/ssl/ssl_client_auth_handler.cc b/chrome/browser/ssl/ssl_client_auth_handler.cc
index 2081f33..159c1ed 100644
--- a/chrome/browser/ssl/ssl_client_auth_handler.cc
+++ b/chrome/browser/ssl/ssl_client_auth_handler.cc
@@ -11,7 +11,7 @@
#include "net/url_request/url_request.h"
SSLClientAuthHandler::SSLClientAuthHandler(
- URLRequest* request,
+ net::URLRequest* request,
net::SSLCertRequestInfo* cert_request_info)
: request_(request),
cert_request_info_(cert_request_info) {
@@ -39,7 +39,7 @@ void SSLClientAuthHandler::SelectCertificate() {
// If the RVH does not exist by the time this task gets run, then the task
// will be dropped and the scoped_refptr to SSLClientAuthHandler will go
// away, so we do not leak anything. The destructor takes care of ensuring
- // the URLRequest always gets a response.
+ // the net::URLRequest always gets a response.
CallRenderViewHostSSLDelegate(
render_process_host_id, render_view_host_id,
&RenderViewHostDelegate::SSL::ShowClientCertificateRequestDialog,
diff --git a/chrome/browser/ssl/ssl_client_auth_handler.h b/chrome/browser/ssl/ssl_client_auth_handler.h
index 4680602..a1de68e 100644
--- a/chrome/browser/ssl/ssl_client_auth_handler.h
+++ b/chrome/browser/ssl/ssl_client_auth_handler.h
@@ -19,7 +19,7 @@ class X509Certificate;
// This class handles the approval and selection of a certificate for SSL client
// authentication by the user.
// It is self-owned and deletes itself when the UI reports the user selection or
-// when the URLRequest is cancelled.
+// when the net::URLRequest is cancelled.
class SSLClientAuthHandler
: public base::RefCountedThreadSafe<SSLClientAuthHandler,
BrowserThread::DeleteOnIOThread> {
@@ -54,7 +54,7 @@ class SSLClientAuthHandler
// Called on the IO thread.
void DoCertificateSelected(net::X509Certificate* cert);
- // The URLRequest that triggered this client auth.
+ // The net::URLRequest that triggered this client auth.
net::URLRequest* request_;
// The certs to choose from.
diff --git a/chrome/browser/ssl/ssl_error_handler.cc b/chrome/browser/ssl/ssl_error_handler.cc
index d05c17f..0bc04d8 100644
--- a/chrome/browser/ssl/ssl_error_handler.cc
+++ b/chrome/browser/ssl/ssl_error_handler.cc
@@ -14,7 +14,7 @@
#include "net/url_request/url_request.h"
SSLErrorHandler::SSLErrorHandler(ResourceDispatcherHost* rdh,
- URLRequest* request,
+ net::URLRequest* request,
ResourceType::Type resource_type,
const std::string& frame_origin,
const std::string& main_frame_origin)
@@ -39,7 +39,7 @@ SSLErrorHandler::SSLErrorHandler(ResourceDispatcherHost* rdh,
NOTREACHED();
// This makes sure we don't disappear on the IO thread until we've given an
- // answer to the URLRequest.
+ // answer to the net::URLRequest.
//
// Release in CompleteCancelRequest, CompleteContinueRequest, or
// CompleteTakeNoAction.
@@ -56,6 +56,10 @@ void SSLErrorHandler::OnDispatched() {
TakeNoAction();
}
+SSLCertErrorHandler* SSLErrorHandler::AsSSLCertErrorHandler() {
+ return NULL;
+}
+
void SSLErrorHandler::Dispatch() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -119,14 +123,15 @@ void SSLErrorHandler::TakeNoAction() {
void SSLErrorHandler::CompleteCancelRequest(int error) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- // It is important that we notify the URLRequest only once. If we try to
- // notify the request twice, it may no longer exist and |this| might have
+ // It is important that we notify the net::URLRequest only once. If we try
+ // to notify the request twice, it may no longer exist and |this| might have
// already have been deleted.
DCHECK(!request_has_been_notified_);
if (request_has_been_notified_)
return;
- URLRequest* request = resource_dispatcher_host_->GetURLRequest(request_id_);
+ net::URLRequest* request =
+ resource_dispatcher_host_->GetURLRequest(request_id_);
if (request) {
// The request can be NULL if it was cancelled by the renderer (as the
// result of the user navigating to a new page from the location bar).
@@ -146,14 +151,15 @@ void SSLErrorHandler::CompleteCancelRequest(int error) {
void SSLErrorHandler::CompleteContinueRequest() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- // It is important that we notify the URLRequest only once. If we try to
+ // It is important that we notify the net::URLRequest only once. If we try to
// notify the request twice, it may no longer exist and |this| might have
// already have been deleted.
DCHECK(!request_has_been_notified_);
if (request_has_been_notified_)
return;
- URLRequest* request = resource_dispatcher_host_->GetURLRequest(request_id_);
+ net::URLRequest* request =
+ resource_dispatcher_host_->GetURLRequest(request_id_);
if (request) {
// The request can be NULL if it was cancelled by the renderer (as the
// result of the user navigating to a new page from the location bar).
@@ -169,7 +175,7 @@ void SSLErrorHandler::CompleteContinueRequest() {
void SSLErrorHandler::CompleteTakeNoAction() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- // It is important that we notify the URLRequest only once. If we try to
+ // It is important that we notify the net::URLRequest only once. If we try to
// notify the request twice, it may no longer exist and |this| might have
// already have been deleted.
DCHECK(!request_has_been_notified_);
diff --git a/chrome/browser/ssl/ssl_error_handler.h b/chrome/browser/ssl/ssl_error_handler.h
index 104e9b5..578429c 100644
--- a/chrome/browser/ssl/ssl_error_handler.h
+++ b/chrome/browser/ssl/ssl_error_handler.h
@@ -28,7 +28,7 @@ class URLRequest;
// UI thread. Subclasses should override the OnDispatched/OnDispatchFailed
// methods to implement the actions that should be taken on the UI thread.
// These methods can call the different convenience methods ContinueRequest/
-// CancelRequest to perform any required action on the URLRequest the
+// CancelRequest to perform any required action on the net::URLRequest the
// ErrorHandler was created with.
//
// IMPORTANT NOTE:
@@ -39,9 +39,9 @@ class URLRequest;
//
class SSLErrorHandler : public base::RefCountedThreadSafe<SSLErrorHandler> {
public:
- virtual SSLCertErrorHandler* AsSSLCertErrorHandler() { return NULL; }
+ virtual SSLCertErrorHandler* AsSSLCertErrorHandler();
- // Find the appropriate SSLManager for the URLRequest and begin handling
+ // Find the appropriate SSLManager for the net::URLRequest and begin handling
// this error.
//
// Call on UI thread.
@@ -63,24 +63,24 @@ class SSLErrorHandler : public base::RefCountedThreadSafe<SSLErrorHandler> {
// called from the UI thread.
TabContents* GetTabContents();
- // Cancels the associated URLRequest.
+ // Cancels the associated net::URLRequest.
// This method can be called from OnDispatchFailed and OnDispatched.
void CancelRequest();
- // Continue the URLRequest ignoring any previous errors. Note that some
+ // Continue the net::URLRequest ignoring any previous errors. Note that some
// errors cannot be ignored, in which case this will result in the request
// being canceled.
// This method can be called from OnDispatchFailed and OnDispatched.
void ContinueRequest();
- // Cancels the associated URLRequest and mark it as denied. The renderer
+ // Cancels the associated net::URLRequest and mark it as denied. The renderer
// processes such request in a special manner, optionally replacing them
// with alternate content (typically frames content is replaced with a
// warning message).
// This method can be called from OnDispatchFailed and OnDispatched.
void DenyRequest();
- // Does nothing on the URLRequest but ensures the current instance ref
+ // Does nothing on the net::URLRequest but ensures the current instance ref
// count is decremented appropriately. Subclasses that do not want to
// take any specific actions in their OnDispatched/OnDispatchFailed should
// call this.
@@ -107,7 +107,7 @@ class SSLErrorHandler : public base::RefCountedThreadSafe<SSLErrorHandler> {
// Should only be accessed on the UI thread.
SSLManager* manager_; // Our manager.
- // The id of the URLRequest associated with this object.
+ // The id of the net::URLRequest associated with this object.
// Should only be accessed from the IO thread.
GlobalRequestID request_id_;
@@ -150,7 +150,7 @@ class SSLErrorHandler : public base::RefCountedThreadSafe<SSLErrorHandler> {
// This read-only member can be accessed on any thread.
const std::string main_frame_origin_;
- // A flag to make sure we notify the URLRequest exactly once.
+ // A flag to make sure we notify the net::URLRequest exactly once.
// Should only be accessed on the IO thread
bool request_has_been_notified_;
diff --git a/chrome/browser/ssl/ssl_error_info.cc b/chrome/browser/ssl/ssl_error_info.cc
index 674a64b..b10e212 100644
--- a/chrome/browser/ssl/ssl_error_info.cc
+++ b/chrome/browser/ssl/ssl_error_info.cc
@@ -253,7 +253,7 @@ int SSLErrorInfo::GetErrorsForCertStatus(int cert_id,
if (cert_status & kErrorFlags[i]) {
count++;
if (!cert.get()) {
- bool r = CertStore::GetSharedInstance()->RetrieveCert(cert_id, &cert);
+ bool r = CertStore::GetInstance()->RetrieveCert(cert_id, &cert);
DCHECK(r);
}
if (errors)
diff --git a/chrome/browser/ssl/ssl_manager.cc b/chrome/browser/ssl/ssl_manager.cc
index abb5a1a..f874cc0 100644
--- a/chrome/browser/ssl/ssl_manager.cc
+++ b/chrome/browser/ssl/ssl_manager.cc
@@ -24,7 +24,7 @@
// static
void SSLManager::OnSSLCertificateError(ResourceDispatcherHost* rdh,
- URLRequest* request,
+ net::URLRequest* request,
int cert_error,
net::X509Certificate* cert) {
DVLOG(1) << "OnSSLCertificateError() cert_error: " << cert_error
diff --git a/chrome/browser/ssl/ssl_manager.h b/chrome/browser/ssl/ssl_manager.h
index d45fe8c..0c61596 100644
--- a/chrome/browser/ssl/ssl_manager.h
+++ b/chrome/browser/ssl/ssl_manager.h
@@ -42,7 +42,7 @@ class SSLManager : public NotificationObserver {
// Entry point for SSLCertificateErrors. This function begins the process
// of resolving a certificate error during an SSL connection. SSLManager
// will adjust the security UI and either call |Cancel| or
- // |ContinueDespiteLastError| on the URLRequest.
+ // |ContinueDespiteLastError| on the net::URLRequest.
//
// Called on the IO thread.
static void OnSSLCertificateError(ResourceDispatcherHost* resource_dispatcher,
diff --git a/chrome/browser/ssl/ssl_policy.cc b/chrome/browser/ssl/ssl_policy.cc
index c10e219..6205722 100644
--- a/chrome/browser/ssl/ssl_policy.cc
+++ b/chrome/browser/ssl/ssl_policy.cc
@@ -9,9 +9,7 @@
#include "base/singleton.h"
#include "base/string_piece.h"
#include "base/string_util.h"
-#include "chrome/browser/cert_store.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/site_instance.h"
@@ -22,7 +20,6 @@
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/jstemplate_builder.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/time_format.h"
#include "chrome/common/url_constants.h"
diff --git a/chrome/browser/ssl/ssl_policy_backend.cc b/chrome/browser/ssl/ssl_policy_backend.cc
index 76d75ac..f193658 100644
--- a/chrome/browser/ssl/ssl_policy_backend.cc
+++ b/chrome/browser/ssl/ssl_policy_backend.cc
@@ -4,7 +4,7 @@
#include "chrome/browser/ssl/ssl_policy_backend.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ssl/ssl_host_state.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
diff --git a/chrome/browser/sync/engine/change_reorder_buffer.cc b/chrome/browser/sync/engine/change_reorder_buffer.cc
index 6af2399..aead013 100644
--- a/chrome/browser/sync/engine/change_reorder_buffer.cc
+++ b/chrome/browser/sync/engine/change_reorder_buffer.cc
@@ -148,7 +148,10 @@ void ChangeReorderBuffer::GetAllChangesInTreeOrder(
i->second == OP_UPDATE_POSITION_AND_PROPERTIES) {
ReadNode node(sync_trans);
CHECK(node.InitByIdLookup(i->first));
- parents_of_position_changes.insert(node.GetParentId());
+
+ // We only care about parents of entry's with position-sensitive models.
+ if (node.GetEntry()->ShouldMaintainPosition())
+ parents_of_position_changes.insert(node.GetParentId());
}
}
}
diff --git a/chrome/browser/sync/engine/model_changing_syncer_command.cc b/chrome/browser/sync/engine/model_changing_syncer_command.cc
index b2131b4..cc2a8eb 100644
--- a/chrome/browser/sync/engine/model_changing_syncer_command.cc
+++ b/chrome/browser/sync/engine/model_changing_syncer_command.cc
@@ -29,4 +29,9 @@ void ModelChangingSyncerCommand::ExecuteImpl(sessions::SyncSession* session) {
}
}
+bool ModelChangingSyncerCommand::ModelNeutralExecuteImpl(
+ sessions::SyncSession* session) {
+ return true;
+}
+
} // namespace browser_sync
diff --git a/chrome/browser/sync/engine/model_changing_syncer_command.h b/chrome/browser/sync/engine/model_changing_syncer_command.h
index ae59272..f6d6a43 100644
--- a/chrome/browser/sync/engine/model_changing_syncer_command.h
+++ b/chrome/browser/sync/engine/model_changing_syncer_command.h
@@ -42,9 +42,7 @@ class ModelChangingSyncerCommand : public SyncerCommand {
// *without* a ModelSafeGroup restriction in place on the SyncSession.
// Returns true on success, false on failure.
// TODO(tim): Remove this (bug 36594).
- virtual bool ModelNeutralExecuteImpl(sessions::SyncSession* session) {
- return true;
- }
+ virtual bool ModelNeutralExecuteImpl(sessions::SyncSession* session);
// Abstract method to be implemented by subclasses to handle logic that
// operates on the model. This is invoked with a SyncSession ModelSafeGroup
diff --git a/chrome/browser/sync/engine/net/server_connection_manager.cc b/chrome/browser/sync/engine/net/server_connection_manager.cc
index 41e79f4..20776fe 100644
--- a/chrome/browser/sync/engine/net/server_connection_manager.cc
+++ b/chrome/browser/sync/engine/net/server_connection_manager.cc
@@ -329,6 +329,10 @@ std::string ServerConnectionManager::GetServerHost() const {
return gurl.host();
}
+ServerConnectionManager::Post* ServerConnectionManager::MakePost() {
+ return NULL; // For testing.
+}
+
bool FillMessageWithShareDetails(sync_pb::ClientToServerMessage* csm,
syncable::DirectoryManager* manager,
const std::string& share) {
diff --git a/chrome/browser/sync/engine/net/server_connection_manager.h b/chrome/browser/sync/engine/net/server_connection_manager.h
index 0363993..6380151 100644
--- a/chrome/browser/sync/engine/net/server_connection_manager.h
+++ b/chrome/browser/sync/engine/net/server_connection_manager.h
@@ -275,9 +275,7 @@ class ServerConnectionManager {
// Factory method to create a Post object we can use for communication with
// the server.
- virtual Post* MakePost() {
- return NULL; // For testing.
- };
+ virtual Post* MakePost();
void set_client_id(const std::string& client_id) {
DCHECK(client_id_.empty());
diff --git a/chrome/browser/sync/engine/syncapi.cc b/chrome/browser/sync/engine/syncapi.cc
index bc34982..112878d 100644
--- a/chrome/browser/sync/engine/syncapi.cc
+++ b/chrome/browser/sync/engine/syncapi.cc
@@ -4,15 +4,12 @@
#include "chrome/browser/sync/engine/syncapi.h"
-#include "build/build_config.h"
-
#include <bitset>
#include <iomanip>
#include <list>
#include <string>
#include <vector>
-#include "base/basictypes.h"
#include "base/base64.h"
#include "base/lock.h"
#include "base/logging.h"
@@ -23,7 +20,6 @@
#include "base/string_util.h"
#include "base/task.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/sync/sync_constants.h"
#include "chrome/browser/sync/engine/all_status.h"
@@ -40,7 +36,6 @@
#include "chrome/browser/sync/protocol/bookmark_specifics.pb.h"
#include "chrome/browser/sync/protocol/extension_specifics.pb.h"
#include "chrome/browser/sync/protocol/nigori_specifics.pb.h"
-#include "chrome/browser/sync/protocol/password_specifics.pb.h"
#include "chrome/browser/sync/protocol/preference_specifics.pb.h"
#include "chrome/browser/sync/protocol/session_specifics.pb.h"
#include "chrome/browser/sync/protocol/service_constants.h"
@@ -48,6 +43,7 @@
#include "chrome/browser/sync/protocol/theme_specifics.pb.h"
#include "chrome/browser/sync/protocol/typed_url_specifics.pb.h"
#include "chrome/browser/sync/sessions/sync_session_context.h"
+#include "chrome/browser/sync/syncable/autofill_migration.h"
#include "chrome/browser/sync/syncable/directory_manager.h"
#include "chrome/browser/sync/syncable/syncable.h"
#include "chrome/browser/sync/util/crypto_helpers.h"
@@ -380,6 +376,20 @@ void WriteNode::PutAutofillSpecificsAndMarkForSyncing(
PutSpecificsAndMarkForSyncing(entity_specifics);
}
+void WriteNode::SetAutofillProfileSpecifics(
+ const sync_pb::AutofillProfileSpecifics& new_value) {
+ DCHECK_EQ(GetModelType(), syncable::AUTOFILL_PROFILE);
+ PutAutofillProfileSpecificsAndMarkForSyncing(new_value);
+}
+
+void WriteNode::PutAutofillProfileSpecificsAndMarkForSyncing(
+ const sync_pb::AutofillProfileSpecifics& new_value) {
+ sync_pb::EntitySpecifics entity_specifics;
+ entity_specifics.MutableExtension(sync_pb::autofill_profile)->CopyFrom(
+ new_value);
+ PutSpecificsAndMarkForSyncing(entity_specifics);
+}
+
void WriteNode::SetBookmarkSpecifics(
const sync_pb::BookmarkSpecifics& new_value) {
DCHECK(GetModelType() == syncable::BOOKMARKS);
@@ -1099,6 +1109,50 @@ class SyncManager::SyncInternal
return true;
}
+ syncable::AutofillMigrationState GetAutofillMigrationState() {
+ syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
+ if (!lookup.good()) {
+ DCHECK(false) << "ScopedDirLookup failed when checking initial sync";
+ return syncable::NOT_MIGRATED;
+ }
+
+ return lookup->get_autofill_migration_state();
+ }
+
+ void SetAutofillMigrationState(syncable::AutofillMigrationState state) {
+ syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
+ if (!lookup.good()) {
+ DCHECK(false) << "ScopedDirLookup failed when checking initial sync";
+ return;
+ }
+
+ return lookup->set_autofill_migration_state(state);
+ }
+
+ void SetAutofillMigrationDebugInfo(
+ syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set,
+ const syncable::AutofillMigrationDebugInfo& info) {
+ syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
+ if (!lookup.good()) {
+ DCHECK(false) << "ScopedDirLookup failed when checking initial sync";
+ return;
+ }
+
+ return lookup->set_autofill_migration_state_debug_info(
+ property_to_set, info);
+ }
+
+ syncable::AutofillMigrationDebugInfo
+ GetAutofillMigrationDebugInfo() {
+ syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
+ if (!lookup.good()) {
+ DCHECK(false) << "ScopedDirLookup failed when checking initial sync";
+ syncable::AutofillMigrationDebugInfo null_value = {0};
+ return null_value;
+ }
+ return lookup->get_autofill_migration_debug_info();
+ }
+
// SyncEngineEventListener implementation.
virtual void OnSyncEngineEvent(const SyncEngineEvent& event);
private:
@@ -1320,6 +1374,27 @@ void SyncManager::StartSyncing() {
data_->StartSyncing();
}
+syncable::AutofillMigrationState
+ SyncManager::GetAutofillMigrationState() {
+ return data_->GetAutofillMigrationState();
+}
+
+void SyncManager::SetAutofillMigrationState(
+ syncable::AutofillMigrationState state) {
+ return data_->SetAutofillMigrationState(state);
+}
+
+syncable::AutofillMigrationDebugInfo
+ SyncManager::GetAutofillMigrationDebugInfo() {
+ return data_->GetAutofillMigrationDebugInfo();
+}
+
+void SyncManager::SetAutofillMigrationDebugInfo(
+ syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set,
+ const syncable::AutofillMigrationDebugInfo& info) {
+ return data_->SetAutofillMigrationDebugInfo(property_to_set, info);
+}
+
void SyncManager::SetPassphrase(const std::string& passphrase,
bool is_explicit) {
data_->SetPassphrase(passphrase, is_explicit);
diff --git a/chrome/browser/sync/engine/syncapi.h b/chrome/browser/sync/engine/syncapi.h
index 2019f41..e2503cb 100644
--- a/chrome/browser/sync/engine/syncapi.h
+++ b/chrome/browser/sync/engine/syncapi.h
@@ -47,6 +47,7 @@
#include "base/scoped_ptr.h"
#include "build/build_config.h"
#include "chrome/browser/sync/protocol/password_specifics.pb.h"
+#include "chrome/browser/sync/syncable/autofill_migration.h"
#include "chrome/browser/sync/syncable/model_type.h"
#include "chrome/browser/sync/util/cryptographer.h"
#include "chrome/common/net/gaia/google_service_auth_error.h"
@@ -347,6 +348,9 @@ class WriteNode : public BaseNode {
// Should only be called if GetModelType() == AUTOFILL.
void SetAutofillSpecifics(const sync_pb::AutofillSpecifics& specifics);
+ void SetAutofillProfileSpecifics(
+ const sync_pb::AutofillProfileSpecifics& specifics);
+
// Set the nigori specifics.
// Should only be called if GetModelType() == NIGORI.
void SetNigoriSpecifics(const sync_pb::NigoriSpecifics& specifics);
@@ -398,6 +402,8 @@ class WriteNode : public BaseNode {
const sync_pb::AppSpecifics& new_value);
void PutAutofillSpecificsAndMarkForSyncing(
const sync_pb::AutofillSpecifics& new_value);
+ void PutAutofillProfileSpecificsAndMarkForSyncing(
+ const sync_pb::AutofillProfileSpecifics& new_value);
void PutBookmarkSpecificsAndMarkForSyncing(
const sync_pb::BookmarkSpecifics& new_value);
void PutNigoriSpecificsAndMarkForSyncing(
@@ -817,6 +823,17 @@ class SyncManager {
// called.
bool InitialSyncEndedForAllEnabledTypes();
+ syncable::AutofillMigrationState GetAutofillMigrationState();
+
+ void SetAutofillMigrationState(
+ syncable::AutofillMigrationState state);
+
+ syncable::AutofillMigrationDebugInfo GetAutofillMigrationDebugInfo();
+
+ void SetAutofillMigrationDebugInfo(
+ syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set,
+ const syncable::AutofillMigrationDebugInfo& info);
+
// Migrate tokens from user settings DB to the token service.
void MigrateTokens();
diff --git a/chrome/browser/sync/engine/syncer.cc b/chrome/browser/sync/engine/syncer.cc
index d6a03a0..cbf9753 100644
--- a/chrome/browser/sync/engine/syncer.cc
+++ b/chrome/browser/sync/engine/syncer.cc
@@ -6,7 +6,6 @@
#include "base/message_loop.h"
#include "base/time.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/sync/engine/apply_updates_command.h"
#include "chrome/browser/sync/engine/build_and_process_conflict_sets_command.h"
#include "chrome/browser/sync/engine/build_commit_command.h"
diff --git a/chrome/browser/sync/engine/syncer_thread.cc b/chrome/browser/sync/engine/syncer_thread.cc
index 12b3435..501577d 100644
--- a/chrome/browser/sync/engine/syncer_thread.cc
+++ b/chrome/browser/sync/engine/syncer_thread.cc
@@ -364,6 +364,22 @@ void SyncerThread::ThreadMainLoop() {
#endif
}
+void SyncerThread::SetConnected(bool connected) {
+ DCHECK(!thread_.IsRunning());
+ vault_.connected_ = connected;
+}
+
+void SyncerThread::SetSyncerPollingInterval(base::TimeDelta interval) {
+ // TODO(timsteele): Use TimeDelta internally.
+ syncer_polling_interval_ = static_cast<int>(interval.InSeconds());
+}
+
+void SyncerThread::SetSyncerShortPollInterval(base::TimeDelta interval) {
+ // TODO(timsteele): Use TimeDelta internally.
+ syncer_short_poll_interval_seconds_ =
+ static_cast<int>(interval.InSeconds());
+}
+
void SyncerThread::WaitUntilConnectedOrQuit() {
VLOG(1) << "Syncer thread waiting for connection.";
Notify(SyncEngineEvent::SYNCER_THREAD_WAITING_FOR_CONNECTION);
@@ -428,6 +444,10 @@ void SyncerThread::ExitPausedState() {
Notify(SyncEngineEvent::SYNCER_THREAD_RESUMED);
}
+void SyncerThread::DisableIdleDetection() {
+ disable_idle_detection_ = true;
+}
+
// We check how long the user's been idle and sync less often if the machine is
// not in use. The aim is to reduce server load.
SyncerThread::WaitInterval SyncerThread::CalculatePollingWaitTime(
diff --git a/chrome/browser/sync/engine/syncer_thread.h b/chrome/browser/sync/engine/syncer_thread.h
index b079c55..6681225 100644
--- a/chrome/browser/sync/engine/syncer_thread.h
+++ b/chrome/browser/sync/engine/syncer_thread.h
@@ -151,20 +151,10 @@ class SyncerThread : public base::RefCountedThreadSafe<SyncerThread>,
virtual void ThreadMain();
void ThreadMainLoop();
- virtual void SetConnected(bool connected) {
- DCHECK(!thread_.IsRunning());
- vault_.connected_ = connected;
- }
-
- virtual void SetSyncerPollingInterval(base::TimeDelta interval) {
- // TODO(timsteele): Use TimeDelta internally.
- syncer_polling_interval_ = static_cast<int>(interval.InSeconds());
- }
- virtual void SetSyncerShortPollInterval(base::TimeDelta interval) {
- // TODO(timsteele): Use TimeDelta internally.
- syncer_short_poll_interval_seconds_ =
- static_cast<int>(interval.InSeconds());
- }
+ virtual void SetConnected(bool connected);
+
+ virtual void SetSyncerPollingInterval(base::TimeDelta interval);
+ virtual void SetSyncerShortPollInterval(base::TimeDelta interval);
// Needed to emulate the behavior of pthread_create, which synchronously
// started the thread and set the value of thread_running_ to true.
@@ -305,7 +295,7 @@ class SyncerThread : public base::RefCountedThreadSafe<SyncerThread>,
void ExitPausedState();
// For unit tests only.
- virtual void DisableIdleDetection() { disable_idle_detection_ = true; }
+ virtual void DisableIdleDetection();
// This sets all conditions for syncer thread termination but does not
// actually join threads. It is expected that Stop will be called at some
diff --git a/chrome/browser/sync/glue/app_data_type_controller.cc b/chrome/browser/sync/glue/app_data_type_controller.cc
index cb6cb54..d26b5fa 100644
--- a/chrome/browser/sync/glue/app_data_type_controller.cc
+++ b/chrome/browser/sync/glue/app_data_type_controller.cc
@@ -8,7 +8,7 @@
#include "base/logging.h"
#include "base/time.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/profile_sync_factory.h"
#include "chrome/browser/sync/unrecoverable_error_handler.h"
@@ -84,6 +84,27 @@ void AppDataTypeController::Stop() {
state_ = NOT_RUNNING;
}
+bool AppDataTypeController::enabled() {
+ return true;
+}
+
+syncable::ModelType AppDataTypeController::type() {
+ return syncable::APPS;
+}
+
+browser_sync::ModelSafeGroup AppDataTypeController::model_safe_group() {
+ return browser_sync::GROUP_UI;
+}
+
+const char* AppDataTypeController::name() const {
+ // For logging only.
+ return "app";
+}
+
+DataTypeController::State AppDataTypeController::state() {
+ return state_;
+}
+
void AppDataTypeController::OnUnrecoverableError(
const tracked_objects::Location& from_here,
const std::string& message) {
diff --git a/chrome/browser/sync/glue/app_data_type_controller.h b/chrome/browser/sync/glue/app_data_type_controller.h
index e8797f4..4bd2750 100644
--- a/chrome/browser/sync/glue/app_data_type_controller.h
+++ b/chrome/browser/sync/glue/app_data_type_controller.h
@@ -34,26 +34,15 @@ class AppDataTypeController : public DataTypeController {
virtual void Stop();
- virtual bool enabled() {
- return true;
- }
-
- virtual syncable::ModelType type() {
- return syncable::APPS;
- }
-
- virtual browser_sync::ModelSafeGroup model_safe_group() {
- return browser_sync::GROUP_UI;
- }
-
- virtual const char* name() const {
- // For logging only.
- return "app";
- }
-
- virtual State state() {
- return state_;
- }
+ virtual bool enabled();
+
+ virtual syncable::ModelType type();
+
+ virtual browser_sync::ModelSafeGroup model_safe_group();
+
+ virtual const char* name() const;
+
+ virtual State state();
// UnrecoverableErrorHandler interface.
virtual void OnUnrecoverableError(
diff --git a/chrome/browser/sync/glue/autofill_change_processor.cc b/chrome/browser/sync/glue/autofill_change_processor.cc
index d415950..6914308 100644
--- a/chrome/browser/sync/glue/autofill_change_processor.cc
+++ b/chrome/browser/sync/glue/autofill_change_processor.cc
@@ -9,16 +9,20 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/guid.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/autofill/personal_data_manager.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/glue/autofill_change_processor2.h"
#include "chrome/browser/sync/glue/autofill_model_associator.h"
+#include "chrome/browser/sync/glue/autofill_profile_model_associator.h"
+#include "chrome/browser/sync/glue/do_optimistic_refresh_task.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/webdata/autofill_change.h"
#include "chrome/browser/webdata/web_data_service.h"
#include "chrome/browser/webdata/web_database.h"
+#include "chrome/common/guid.h"
#include "chrome/common/notification_service.h"
+#include "chrome/common/pref_names.h"
namespace browser_sync {
@@ -83,7 +87,7 @@ void AutofillChangeProcessor::Observe(NotificationType type,
void AutofillChangeProcessor::PostOptimisticRefreshTask() {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- new AutofillModelAssociator::DoOptimisticRefreshTask(
+ new DoOptimisticRefreshForAutofill(
personal_data_));
}
@@ -195,6 +199,8 @@ void AutofillChangeProcessor::ApplyChangesFromSyncModel(
return;
StopObserving();
+ bool autofill_profile_not_migrated = HasNotMigratedYet(trans);
+
sync_api::ReadNode autofill_root(trans);
if (!autofill_root.InitByTagLookup(kAutofillTag)) {
error_handler()->OnUnrecoverableError(FROM_HERE,
@@ -210,7 +216,7 @@ void AutofillChangeProcessor::ApplyChangesFromSyncModel(
const sync_pb::AutofillSpecifics& autofill =
changes[i].specifics.GetExtension(sync_pb::autofill);
if (autofill.has_value() ||
- (HasNotMigratedYet() && autofill.has_profile())) {
+ (autofill_profile_not_migrated && autofill.has_profile())) {
autofill_changes_.push_back(AutofillChangeRecord(changes[i].action,
changes[i].id,
autofill));
@@ -236,7 +242,7 @@ void AutofillChangeProcessor::ApplyChangesFromSyncModel(
sync_node.GetAutofillSpecifics());
int64 sync_id = sync_node.GetId();
if (autofill.has_value() ||
- (HasNotMigratedYet() && autofill.has_profile())) {
+ (autofill_profile_not_migrated && autofill.has_profile())) {
autofill_changes_.push_back(AutofillChangeRecord(changes[i].action,
sync_id, autofill));
} else {
@@ -261,7 +267,6 @@ void AutofillChangeProcessor::CommitChangesFromSyncModel() {
if (autofill_changes_[i].autofill_.has_value()) {
ApplySyncAutofillEntryDelete(autofill_changes_[i].autofill_);
} else if (autofill_changes_[i].autofill_.has_profile()) {
- DCHECK(HasNotMigratedYet());
ApplySyncAutofillProfileDelete(autofill_changes_[i].id_);
} else {
NOTREACHED() << "Autofill's CommitChanges received change with no"
@@ -276,7 +281,6 @@ void AutofillChangeProcessor::CommitChangesFromSyncModel() {
autofill_changes_[i].autofill_, &new_entries,
autofill_changes_[i].id_);
} else if (autofill_changes_[i].autofill_.has_profile()) {
- DCHECK(HasNotMigratedYet());
ApplySyncAutofillProfileChange(autofill_changes_[i].action_,
autofill_changes_[i].autofill_.profile(),
autofill_changes_[i].id_);
@@ -433,40 +437,9 @@ void AutofillChangeProcessor::WriteAutofillEntry(
node->SetAutofillSpecifics(autofill);
}
-// static
-void AutofillChangeProcessor::WriteAutofillProfile(
- const AutoFillProfile& profile, sync_api::WriteNode* node) {
- sync_pb::AutofillSpecifics autofill;
- sync_pb::AutofillProfileSpecifics* s(autofill.mutable_profile());
- s->set_name_first(UTF16ToUTF8(
- profile.GetFieldText(AutoFillType(NAME_FIRST))));
- s->set_name_middle(UTF16ToUTF8(
- profile.GetFieldText(AutoFillType(NAME_MIDDLE))));
- s->set_name_last(UTF16ToUTF8(profile.GetFieldText(AutoFillType(NAME_LAST))));
- s->set_address_home_line1(
- UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_LINE1))));
- s->set_address_home_line2(
- UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_LINE2))));
- s->set_address_home_city(UTF16ToUTF8(profile.GetFieldText(
- AutoFillType(ADDRESS_HOME_CITY))));
- s->set_address_home_state(UTF16ToUTF8(profile.GetFieldText(
- AutoFillType(ADDRESS_HOME_STATE))));
- s->set_address_home_country(UTF16ToUTF8(profile.GetFieldText(
- AutoFillType(ADDRESS_HOME_COUNTRY))));
- s->set_address_home_zip(UTF16ToUTF8(profile.GetFieldText(
- AutoFillType(ADDRESS_HOME_ZIP))));
- s->set_email_address(UTF16ToUTF8(profile.GetFieldText(
- AutoFillType(EMAIL_ADDRESS))));
- s->set_company_name(UTF16ToUTF8(profile.GetFieldText(
- AutoFillType(COMPANY_NAME))));
- s->set_phone_fax_whole_number(UTF16ToUTF8(profile.GetFieldText(
- AutoFillType(PHONE_FAX_WHOLE_NUMBER))));
- s->set_phone_home_whole_number(UTF16ToUTF8(profile.GetFieldText(
- AutoFillType(PHONE_HOME_WHOLE_NUMBER))));
- node->SetAutofillSpecifics(autofill);
-}
-bool AutofillChangeProcessor::HasNotMigratedYet() {
- return true;
+bool AutofillChangeProcessor::HasNotMigratedYet(
+ const sync_api::BaseTransaction* trans) {
+ return model_associator_->HasNotMigratedYet(trans);
}
} // namespace browser_sync
diff --git a/chrome/browser/sync/glue/autofill_change_processor.h b/chrome/browser/sync/glue/autofill_change_processor.h
index e901c8e..ba132fa 100644
--- a/chrome/browser/sync/glue/autofill_change_processor.h
+++ b/chrome/browser/sync/glue/autofill_change_processor.h
@@ -63,9 +63,6 @@ class AutofillChangeProcessor : public ChangeProcessor,
// node.
static void WriteAutofillEntry(const AutofillEntry& entry,
sync_api::WriteNode* node);
- // As above, for autofill profiles.
- static void WriteAutofillProfile(const AutoFillProfile& profile,
- sync_api::WriteNode* node);
// TODO(georgey) : add the same processing for CC info (already in protocol
// buffers).
@@ -112,7 +109,7 @@ class AutofillChangeProcessor : public ChangeProcessor,
void PostOptimisticRefreshTask();
// Called to see if we need to upgrade to the new autofill2 profile.
- bool HasNotMigratedYet();
+ bool HasNotMigratedYet(const sync_api::BaseTransaction* trans);
// The two models should be associated according to this ModelAssociator.
AutofillModelAssociator* model_associator_;
diff --git a/chrome/browser/sync/glue/autofill_change_processor2.cc b/chrome/browser/sync/glue/autofill_change_processor2.cc
index b2b564e..49b669c 100644
--- a/chrome/browser/sync/glue/autofill_change_processor2.cc
+++ b/chrome/browser/sync/glue/autofill_change_processor2.cc
@@ -9,8 +9,8 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/autofill/personal_data_manager.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/glue/autofill_model_associator.h"
#include "chrome/browser/sync/glue/autofill_model_associator2.h"
#include "chrome/browser/sync/profile_sync_service.h"
@@ -581,4 +581,3 @@ void AutofillChangeProcessor2::WriteAutofillProfile(
}
} // namespace browser_sync
-
diff --git a/chrome/browser/sync/glue/autofill_data_type_controller.cc b/chrome/browser/sync/glue/autofill_data_type_controller.cc
index 2598977..8661e14 100644
--- a/chrome/browser/sync/glue/autofill_data_type_controller.cc
+++ b/chrome/browser/sync/glue/autofill_data_type_controller.cc
@@ -9,11 +9,11 @@
#include "base/task.h"
#include "base/time.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/glue/autofill_change_processor.h"
#include "chrome/browser/sync/glue/autofill_model_associator.h"
-#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/profile_sync_factory.h"
+#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/webdata/web_data_service.h"
#include "chrome/common/notification_service.h"
@@ -148,6 +148,41 @@ void AutofillDataTypeController::Stop() {
}
}
+bool AutofillDataTypeController::enabled() {
+ return true;
+}
+
+syncable::ModelType AutofillDataTypeController::type() {
+ return syncable::AUTOFILL;
+}
+
+browser_sync::ModelSafeGroup AutofillDataTypeController::model_safe_group() {
+ return browser_sync::GROUP_DB;
+}
+
+const char* AutofillDataTypeController::name() const {
+ // For logging only.
+ return "autofill";
+}
+
+DataTypeController::State AutofillDataTypeController::state() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ return state_;
+}
+
+ProfileSyncFactory::SyncComponents
+ AutofillDataTypeController::CreateSyncComponents(
+ ProfileSyncService* profile_sync_service,
+ WebDatabase* web_database,
+ PersonalDataManager* personal_data,
+ browser_sync::UnrecoverableErrorHandler* error_handler) {
+ return profile_sync_factory_->CreateAutofillSyncComponents(
+ profile_sync_service,
+ web_database,
+ personal_data,
+ this);
+}
+
void AutofillDataTypeController::StartImpl() {
VLOG(1) << "Autofill data type controller StartImpl called.";
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
@@ -160,7 +195,7 @@ void AutofillDataTypeController::StartImpl() {
return;
}
ProfileSyncFactory::SyncComponents sync_components =
- profile_sync_factory_->CreateAutofillSyncComponents(
+ CreateSyncComponents(
sync_service_,
web_data_service_->GetDatabase(),
profile_->GetPersonalDataManager(),
diff --git a/chrome/browser/sync/glue/autofill_data_type_controller.h b/chrome/browser/sync/glue/autofill_data_type_controller.h
index d22fcfa..d73edf2 100644
--- a/chrome/browser/sync/glue/autofill_data_type_controller.h
+++ b/chrome/browser/sync/glue/autofill_data_type_controller.h
@@ -12,6 +12,7 @@
#include "base/scoped_ptr.h"
#include "base/waitable_event.h"
#include "chrome/browser/autofill/personal_data_manager.h"
+#include "chrome/browser/sync/profile_sync_factory.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/glue/data_type_controller.h"
@@ -40,27 +41,15 @@ class AutofillDataTypeController : public DataTypeController,
virtual void Stop();
- virtual bool enabled() {
- return true;
- }
+ virtual bool enabled();
- virtual syncable::ModelType type() {
- return syncable::AUTOFILL;
- }
+ virtual syncable::ModelType type();
- virtual browser_sync::ModelSafeGroup model_safe_group() {
- return browser_sync::GROUP_DB;
- }
+ virtual browser_sync::ModelSafeGroup model_safe_group();
- virtual const char* name() const {
- // For logging only.
- return "autofill";
- }
+ virtual const char* name() const;
- virtual State state() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- return state_;
- }
+ virtual State state();
// UnrecoverableHandler implementation
virtual void OnUnrecoverableError(const tracked_objects::Location& from_here,
@@ -74,6 +63,14 @@ class AutofillDataTypeController : public DataTypeController,
// PersonalDataManager::Observer implementation:
virtual void OnPersonalDataLoaded();
+ protected:
+ virtual ProfileSyncFactory::SyncComponents CreateSyncComponents(
+ ProfileSyncService* profile_sync_service,
+ WebDatabase* web_database,
+ PersonalDataManager* personal_data,
+ browser_sync::UnrecoverableErrorHandler* error_handler);
+ ProfileSyncFactory* profile_sync_factory_;
+
private:
void StartImpl();
void StartDone(StartResult result, State state);
@@ -92,7 +89,6 @@ class AutofillDataTypeController : public DataTypeController,
state_ = state;
}
- ProfileSyncFactory* profile_sync_factory_;
Profile* profile_;
ProfileSyncService* sync_service_;
State state_;
diff --git a/chrome/browser/sync/glue/autofill_data_type_controller_unittest.cc b/chrome/browser/sync/glue/autofill_data_type_controller_unittest.cc
index d0ede1a..6ff8af6 100644
--- a/chrome/browser/sync/glue/autofill_data_type_controller_unittest.cc
+++ b/chrome/browser/sync/glue/autofill_data_type_controller_unittest.cc
@@ -11,7 +11,6 @@
#include "base/waitable_event.h"
#include "chrome/browser/autofill/personal_data_manager.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/sync/glue/autofill_data_type_controller.h"
#include "chrome/browser/sync/glue/change_processor_mock.h"
#include "chrome/browser/sync/glue/model_associator_mock.h"
@@ -19,7 +18,6 @@
#include "chrome/browser/sync/profile_sync_service_mock.h"
#include "chrome/browser/sync/profile_sync_test_util.h"
#include "chrome/browser/webdata/web_data_service.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"
#include "chrome/test/profile_mock.h"
diff --git a/chrome/browser/sync/glue/autofill_model_associator.cc b/chrome/browser/sync/glue/autofill_model_associator.cc
index 6409e9b..f1340df 100644
--- a/chrome/browser/sync/glue/autofill_model_associator.cc
+++ b/chrome/browser/sync/glue/autofill_model_associator.cc
@@ -12,13 +12,17 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/guid.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/autofill_change_processor.h"
+#include "chrome/browser/sync/glue/autofill_profile_model_associator.h"
+#include "chrome/browser/sync/glue/do_optimistic_refresh_task.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/protocol/autofill_specifics.pb.h"
#include "chrome/browser/webdata/web_database.h"
+#include "chrome/common/guid.h"
+#include "chrome/common/pref_names.h"
#include "net/base/escape.h"
using base::TimeTicks;
@@ -37,16 +41,6 @@ struct AutofillModelAssociator::DataBundle {
~DataBundle() { STLDeleteElements(&new_profiles); }
};
-AutofillModelAssociator::DoOptimisticRefreshTask::DoOptimisticRefreshTask(
- PersonalDataManager* pdm) : pdm_(pdm) {}
-
-AutofillModelAssociator::DoOptimisticRefreshTask::~DoOptimisticRefreshTask() {}
-
-void AutofillModelAssociator::DoOptimisticRefreshTask::Run() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- pdm_->Refresh();
-}
-
AutofillModelAssociator::AutofillModelAssociator(
ProfileSyncService* sync_service,
WebDatabase* web_database,
@@ -55,7 +49,8 @@ AutofillModelAssociator::AutofillModelAssociator(
web_database_(web_database),
personal_data_(personal_data),
autofill_node_id_(sync_api::kInvalidId),
- abort_association_pending_(false) {
+ abort_association_pending_(false),
+ number_of_entries_created_(0) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
DCHECK(sync_service_);
DCHECK(web_database_);
@@ -114,6 +109,7 @@ bool AutofillModelAssociator::TraverseAndAssociateChromeAutofillEntries(
node.SetTitle(UTF8ToWide(tag));
AutofillChangeProcessor::WriteAutofillEntry(*ix, &node);
Associate(&tag, node.GetId());
+ number_of_entries_created_++;
}
current_entries->insert(ix->key());
@@ -121,21 +117,6 @@ bool AutofillModelAssociator::TraverseAndAssociateChromeAutofillEntries(
return true;
}
-bool AutofillModelAssociator::MakeNewAutofillProfileSyncNode(
- sync_api::WriteTransaction* trans, const sync_api::BaseNode& autofill_root,
- const std::string& tag, const AutoFillProfile& profile, int64* sync_id) {
- sync_api::WriteNode node(trans);
- if (!node.InitUniqueByCreation(syncable::AUTOFILL, autofill_root, tag)) {
- LOG(ERROR) << "Failed to create autofill sync node.";
- return false;
- }
- node.SetTitle(UTF8ToWide(tag));
- AutofillChangeProcessor::WriteAutofillProfile(profile, &node);
- *sync_id = node.GetId();
- return true;
-}
-
-
bool AutofillModelAssociator::LoadAutofillData(
std::vector<AutofillEntry>* entries,
std::vector<AutoFillProfile*>* profiles) {
@@ -205,8 +186,18 @@ bool AutofillModelAssociator::AssociateModels() {
return false;
}
+ if (sync_service_->backend()->GetAutofillMigrationState() !=
+ syncable::MIGRATED) {
+ syncable::AutofillMigrationDebugInfo debug_info;
+ debug_info.autofill_entries_added_during_migration =
+ number_of_entries_created_;
+ sync_service_->backend()->SetAutofillMigrationDebugInfo(
+ syncable::AutofillMigrationDebugInfo::ENTRIES_ADDED,
+ debug_info);
+ }
+
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- new DoOptimisticRefreshTask(personal_data_));
+ new DoOptimisticRefreshForAutofill(personal_data_));
return true;
}
@@ -244,6 +235,27 @@ bool AutofillModelAssociator::TraverseAndAssociateAllSyncNodes(
const std::vector<AutoFillProfile*>& all_profiles_from_db) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+ bool autofill_profile_not_migrated = HasNotMigratedYet(write_trans);
+
+ if (MigrationLoggingEnabled() &&
+ autofill_profile_not_migrated) {
+ VLOG(1) << "[AUTOFILL MIGRATION]"
+ << "Printing profiles from web db";
+
+ for (std::vector<AutoFillProfile*>::const_iterator ix =
+ all_profiles_from_db.begin(); ix != all_profiles_from_db.end(); ++ix) {
+ AutoFillProfile* p = *ix;
+ VLOG(1) << "[AUTOFILL MIGRATION] "
+ << p->GetFieldText(AutoFillType(NAME_FIRST))
+ << p->GetFieldText(AutoFillType(NAME_LAST));
+ }
+ }
+
+ if (MigrationLoggingEnabled() && autofill_profile_not_migrated) {
+ VLOG(1) << "[AUTOFILL MIGRATION]"
+ << "Iterating over sync db";
+ }
+
int64 sync_child_id = autofill_root.GetFirstChildId();
while (sync_child_id != sync_api::kInvalidId) {
sync_api::ReadNode sync_child(write_trans);
@@ -256,13 +268,20 @@ bool AutofillModelAssociator::TraverseAndAssociateAllSyncNodes(
if (autofill.has_value()) {
AddNativeEntryIfNeeded(autofill, bundle, sync_child);
- } else if (autofill.has_profile() && HasNotMigratedYet()) {
+ } else if (autofill.has_profile()) {
// Ignore autofill profiles if we are not upgrading.
- AddNativeProfileIfNeeded(
- autofill.profile(),
- bundle,
- sync_child,
- all_profiles_from_db);
+ if (autofill_profile_not_migrated) {
+ if (MigrationLoggingEnabled()) {
+ VLOG(1) << "[AUTOFILL MIGRATION] Looking for "
+ << autofill.profile().name_first()
+ << autofill.profile().name_last();
+ }
+ AddNativeProfileIfNeeded(
+ autofill.profile(),
+ bundle,
+ sync_child,
+ all_profiles_from_db);
+ }
} else {
NOTREACHED() << "AutofillSpecifics has no autofill data!";
}
@@ -332,15 +351,23 @@ void AutofillModelAssociator::AddNativeProfileIfNeeded(
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
- scoped_ptr<AutoFillProfile> profile_in_web_db(FindCorrespondingNodeFromWebDB(
- profile, all_profiles_from_db));
+ AutoFillProfile* profile_in_web_db = FindCorrespondingNodeFromWebDB(
+ profile, all_profiles_from_db);
- if (profile_in_web_db.get() != NULL) {
+ if (profile_in_web_db != NULL) {
+ if (MigrationLoggingEnabled()) {
+ VLOG(1) << "[AUTOFILL MIGRATION]"
+ << "Node found in web db. So associating";
+ }
int64 sync_id = node.GetId();
std::string guid = profile_in_web_db->guid();
Associate(&guid, sync_id);
return;
} else { // Create a new node.
+ if (MigrationLoggingEnabled()) {
+ VLOG(1) << "[AUTOFILL MIGRATION]"
+ << "Node not found in web db so creating and associating";
+ }
std::string guid = guid::GenerateGUID();
Associate(&guid, node.GetId());
AutoFillProfile* p = new AutoFillProfile(guid);
@@ -393,13 +420,13 @@ AutofillModelAssociator::GetChromeNodeFromSyncId(int64 sync_id) {
}
bool AutofillModelAssociator::InitSyncNodeFromChromeId(
- std::string node_id,
+ const std::string& node_id,
sync_api::BaseNode* sync_node) {
return false;
}
int64 AutofillModelAssociator::GetSyncIdFromChromeId(
- const std::string autofill) {
+ const std::string& autofill) {
AutofillToSyncIdMap::const_iterator iter = id_map_.find(autofill);
return iter == id_map_.end() ? sync_api::kInvalidId : iter->second;
}
@@ -509,8 +536,61 @@ bool AutofillModelAssociator::FillProfileWithServerData(
return diff;
}
-bool AutofillModelAssociator::HasNotMigratedYet() {
- return true;
+bool AutofillModelAssociator::HasNotMigratedYet(
+ const sync_api::BaseTransaction* trans) {
+
+ // Now read the current value from the directory.
+ syncable::AutofillMigrationState autofill_migration_state =
+ sync_service()->backend()->GetAutofillMigrationState();
+
+ DCHECK_NE(autofill_migration_state, syncable::NOT_DETERMINED);
+
+ if (autofill_migration_state== syncable::NOT_DETERMINED) {
+ VLOG(1) << "Autofill migration state is not determined inside "
+ << " model associator";
+ }
+
+ if (autofill_migration_state == syncable::NOT_MIGRATED) {
+ return true;
+ }
+
+ if (autofill_migration_state == syncable::INSUFFICIENT_INFO_TO_DETERMINE) {
+ if (MigrationLoggingEnabled()) {
+ VLOG(1) << "[AUTOFILL MIGRATION]"
+ << "current autofill migration state is insufficient info to"
+ << "determine.";
+ }
+ sync_api::ReadNode autofill_profile_root_node(trans);
+ if (!autofill_profile_root_node.InitByTagLookup(
+ browser_sync::kAutofillProfileTag) ||
+ autofill_profile_root_node.GetFirstChildId()==
+ static_cast<int64>(0)) {
+ sync_service()->backend()->SetAutofillMigrationState(
+ syncable::NOT_MIGRATED);
+
+ if (MigrationLoggingEnabled()) {
+ VLOG(1) << "[AUTOFILL MIGRATION]"
+ << "Current autofill migration state is NOT Migrated because"
+ << "legacy autofill root node is present whereas new "
+ << "Autofill profile root node is absent.";
+ }
+ return true;
+ }
+
+ sync_service()->backend()->SetAutofillMigrationState(syncable::MIGRATED);
+
+ if (MigrationLoggingEnabled()) {
+ VLOG(1) << "[AUTOFILL MIGRATION]"
+ << "Current autofill migration state is migrated.";
+ }
+ }
+
+ return false;
}
+bool AutofillModelAssociator::MigrationLoggingEnabled() {
+ // [TODO] enable logging via a command line flag.
+ return false;
+}
} // namespace browser_sync
+
diff --git a/chrome/browser/sync/glue/autofill_model_associator.h b/chrome/browser/sync/glue/autofill_model_associator.h
index ee81ed0..3f1104e 100644
--- a/chrome/browser/sync/glue/autofill_model_associator.h
+++ b/chrome/browser/sync/glue/autofill_model_associator.h
@@ -52,17 +52,6 @@ class AutofillModelAssociator
PersonalDataManager* data_manager);
virtual ~AutofillModelAssociator();
- // A task used by this class and the change processor to inform the
- // PersonalDataManager living on the UI thread that it needs to refresh.
- class DoOptimisticRefreshTask : public Task {
- public:
- explicit DoOptimisticRefreshTask(PersonalDataManager* pdm);
- virtual ~DoOptimisticRefreshTask();
- virtual void Run();
- private:
- scoped_refptr<PersonalDataManager> pdm_;
- };
-
// PerDataTypeAssociatorInterface implementation.
//
// Iterates through the sync model looking for matched pairs of items.
@@ -82,12 +71,12 @@ class AutofillModelAssociator
virtual const std::string* GetChromeNodeFromSyncId(int64 sync_id);
// Not implemented.
- virtual bool InitSyncNodeFromChromeId(std::string node_id,
+ virtual bool InitSyncNodeFromChromeId(const std::string& node_id,
sync_api::BaseNode* sync_node);
// Returns the sync id for the given autofill name, or sync_api::kInvalidId
// if the autofill name is not associated to any sync id.
- virtual int64 GetSyncIdFromChromeId(std::string node_id);
+ virtual int64 GetSyncIdFromChromeId(const std::string& node_id);
// Associates the given autofill name with the given sync id.
virtual void Associate(const std::string* node, int64 sync_id);
@@ -114,13 +103,13 @@ class AutofillModelAssociator
// Returns sync service instance.
ProfileSyncService* sync_service() { return sync_service_; }
- protected:
// Is called to determine if we need to upgrade to the new
// autofillprofile2 data type. If so we need to sync up autofillprofile
// first to the latest available changes on the server and then upgrade
// to autofillprofile2.
- virtual bool HasNotMigratedYet();
+ virtual bool HasNotMigratedYet(const sync_api::BaseTransaction* trans);
+ protected:
// Given a profile from sync db it tries to match the profile against
// one in web db. it ignores the guid and compares the actual data.
AutoFillProfile* FindCorrespondingNodeFromWebDB(
@@ -180,20 +169,12 @@ class AutofillModelAssociator
const sync_api::ReadNode& node,
const std::vector<AutoFillProfile*>& all_profiles_from_db);
- // Helper to insert a sync node for the given AutoFillProfile (e.g. in
- // response to encountering a native profile that doesn't exist yet in the
- // cloud).
- bool MakeNewAutofillProfileSyncNode(
- sync_api::WriteTransaction* trans,
- const sync_api::BaseNode& autofill_root,
- const std::string& tag,
- const AutoFillProfile& profile,
- int64* sync_id);
-
// Called at various points in model association to determine if the
// user requested an abort.
bool IsAbortPending();
+ bool MigrationLoggingEnabled();
+
ProfileSyncService* sync_service_;
WebDatabase* web_database_;
PersonalDataManager* personal_data_;
@@ -207,6 +188,7 @@ class AutofillModelAssociator
// AssociateModels method as soon as possible.
Lock abort_association_pending_lock_;
bool abort_association_pending_;
+ int number_of_entries_created_;
DISALLOW_COPY_AND_ASSIGN(AutofillModelAssociator);
};
diff --git a/chrome/browser/sync/glue/autofill_model_associator2.cc b/chrome/browser/sync/glue/autofill_model_associator2.cc
index 272c8ae..28872df 100644
--- a/chrome/browser/sync/glue/autofill_model_associator2.cc
+++ b/chrome/browser/sync/glue/autofill_model_associator2.cc
@@ -12,7 +12,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/autofill_change_processor.h"
#include "chrome/browser/sync/profile_sync_service.h"
@@ -421,13 +421,13 @@ AutofillModelAssociator2::GetChromeNodeFromSyncId(int64 sync_id) {
}
bool AutofillModelAssociator2::InitSyncNodeFromChromeId(
- std::string node_id,
+ const std::string& node_id,
sync_api::BaseNode* sync_node) {
return false;
}
int64 AutofillModelAssociator2::GetSyncIdFromChromeId(
- const std::string autofill) {
+ const std::string& autofill) {
AutofillToSyncIdMap::const_iterator iter = id_map_.find(autofill);
return iter == id_map_.end() ? sync_api::kInvalidId : iter->second;
}
diff --git a/chrome/browser/sync/glue/autofill_model_associator2.h b/chrome/browser/sync/glue/autofill_model_associator2.h
index 0ad37de..2b50310 100644
--- a/chrome/browser/sync/glue/autofill_model_associator2.h
+++ b/chrome/browser/sync/glue/autofill_model_associator2.h
@@ -81,12 +81,12 @@ class AutofillModelAssociator2
virtual const std::string* GetChromeNodeFromSyncId(int64 sync_id);
// Not implemented.
- virtual bool InitSyncNodeFromChromeId(std::string node_id,
+ virtual bool InitSyncNodeFromChromeId(const std::string& node_id,
sync_api::BaseNode* sync_node);
// Returns the sync id for the given autofill name, or sync_api::kInvalidId
// if the autofill name is not associated to any sync id.
- virtual int64 GetSyncIdFromChromeId(std::string node_id);
+ virtual int64 GetSyncIdFromChromeId(const std::string& node_id);
// Associates the given autofill name with the given sync id.
virtual void Associate(const std::string* node, int64 sync_id);
diff --git a/chrome/browser/sync/glue/autofill_profile_change_processor.cc b/chrome/browser/sync/glue/autofill_profile_change_processor.cc
new file mode 100644
index 0000000..bb99391
--- /dev/null
+++ b/chrome/browser/sync/glue/autofill_profile_change_processor.cc
@@ -0,0 +1,338 @@
+// 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
+
+#include "chrome/browser/sync/glue/autofill_profile_change_processor.h"
+
+#include <string>
+#include <vector>
+
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/autofill/autofill_profile.h"
+#include "chrome/browser/autofill/personal_data_manager.h"
+#include "chrome/browser/sync/engine/syncapi.h"
+#include "chrome/browser/sync/glue/autofill_profile_model_associator.h"
+#include "chrome/browser/sync/glue/change_processor.h"
+#include "chrome/browser/sync/glue/do_optimistic_refresh_task.h"
+#include "chrome/browser/sync/unrecoverable_error_handler.h"
+#include "chrome/browser/webdata/autofill_change.h"
+#include "chrome/browser/webdata/web_database.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
+
+namespace browser_sync {
+
+AutofillProfileChangeProcessor::AutofillProfileChangeProcessor(
+ AutofillProfileModelAssociator *model_associator,
+ WebDatabase* web_database,
+ PersonalDataManager* personal_data_manager,
+ UnrecoverableErrorHandler* error_handler)
+ : ChangeProcessor(error_handler),
+ model_associator_(model_associator),
+ observing_(false),
+ web_database_(web_database),
+ personal_data_(personal_data_manager) {
+ DCHECK(model_associator);
+ DCHECK(web_database);
+ DCHECK(error_handler);
+ DCHECK(personal_data_manager);
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+
+ StartObserving();
+}
+
+AutofillProfileChangeProcessor::ScopedStopObserving::ScopedStopObserving(
+ AutofillProfileChangeProcessor* processor) {
+ processor_ = processor;
+ processor_->StopObserving();
+}
+
+AutofillProfileChangeProcessor::ScopedStopObserving::~ScopedStopObserving() {
+ processor_->StartObserving();
+}
+
+void AutofillProfileChangeProcessor::ApplyChangesFromSyncModel(
+ const sync_api::BaseTransaction *write_trans,
+ const sync_api::SyncManager::ChangeRecord* changes,
+ int change_count) {
+
+ ScopedStopObserving observer(this);
+
+ sync_api::ReadNode autofill_profile_root(write_trans);
+ if (!autofill_profile_root.InitByTagLookup(kAutofillProfileTag)) {
+ error_handler()->OnUnrecoverableError(FROM_HERE,
+ "Autofill Profile root node lookup failed");
+ return;
+ }
+
+ for (int i = 0; i < change_count; ++i) {
+ if (sync_api::SyncManager::ChangeRecord::ACTION_DELETE ==
+ changes[i].action) {
+ DCHECK(changes[i].specifics.HasExtension(
+ sync_pb::autofill_profile));
+
+ const sync_pb::AutofillProfileSpecifics& specifics =
+ changes[i].specifics.GetExtension(sync_pb::autofill_profile);
+
+ autofill_changes_.push_back(AutofillProfileChangeRecord(changes[i].action,
+ changes[i].id,
+ specifics));
+ continue;
+ }
+
+ // If it is not a delete.
+ sync_api::ReadNode sync_node(write_trans);
+ if (!sync_node.InitByIdLookup(changes[i].id)) {
+ LOG(ERROR) << "Could not find the id in sync db " << changes[i].id;
+ continue;
+ }
+
+ const sync_pb::AutofillProfileSpecifics& autofill(
+ sync_node.GetAutofillProfileSpecifics());
+
+ autofill_changes_.push_back(AutofillProfileChangeRecord(changes[i].action,
+ changes[i].id,
+ autofill));
+ }
+}
+
+void AutofillProfileChangeProcessor::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK_EQ(type.value, NotificationType::AUTOFILL_PROFILE_CHANGED_GUID);
+ WebDataService* wds = Source<WebDataService>(source).ptr();
+
+ if (!wds || wds->GetDatabase() != web_database_)
+ return;
+
+ sync_api::WriteTransaction trans(share_handle());
+ sync_api::ReadNode autofill_root(&trans);
+ if (!autofill_root.InitByTagLookup(kAutofillProfileTag)) {
+ error_handler()->OnUnrecoverableError(FROM_HERE,
+ "Server did not create a tolp level node");
+ return;
+ }
+
+ AutofillProfileChangeGUID* change =
+ Details<AutofillProfileChangeGUID>(details).ptr();
+
+ ActOnChange(change, &trans, autofill_root);
+}
+
+void AutofillProfileChangeProcessor::ActOnChange(
+ AutofillProfileChangeGUID* change,
+ sync_api::WriteTransaction* trans,
+ sync_api::ReadNode& autofill_root) {
+ DCHECK(change->type() == AutofillProfileChangeGUID::REMOVE ||
+ change->profile());
+ switch (change->type()) {
+ case AutofillProfileChangeGUID::ADD: {
+ AddAutofillProfileSyncNode(trans, autofill_root, *(change->profile()));
+ break;
+ }
+ case AutofillProfileChangeGUID::UPDATE: {
+ int64 sync_id = model_associator_->GetSyncIdFromChromeId(change->key());
+ if (sync_api::kInvalidId == sync_id) {
+ LOG(ERROR) << "Sync id is not found for " << change->key();
+ break;
+ }
+ sync_api::WriteNode node(trans);
+ if (!node.InitByIdLookup(sync_id)) {
+ LOG(ERROR) << "Could not find sync node for id " << sync_id;
+ break;
+ }
+
+ WriteAutofillProfile(*(change->profile()), &node);
+ break;
+ }
+ case AutofillProfileChangeGUID::REMOVE: {
+ int64 sync_id = model_associator_->GetSyncIdFromChromeId(change->key());
+ if (sync_api::kInvalidId == sync_id) {
+ LOG(ERROR) << "Sync id is not found for " << change->key();
+ break;
+ }
+ sync_api::WriteNode node(trans);
+ if (!node.InitByIdLookup(sync_id)) {
+ LOG(ERROR) << "Could not find sync node for id " << sync_id;
+ break;
+ }
+ node.Remove();
+ model_associator_->Disassociate(sync_id);
+ break;
+ }
+ default:
+ NOTREACHED();
+ }
+}
+
+void AutofillProfileChangeProcessor::CommitChangesFromSyncModel() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+
+ if (!running())
+ return;
+
+ ScopedStopObserving observer(this);
+
+ for (unsigned int i = 0;i < autofill_changes_.size(); ++i) {
+ if (sync_api::SyncManager::ChangeRecord::ACTION_DELETE ==
+ autofill_changes_[i].action_) {
+ if (!web_database_->RemoveAutoFillProfile(
+ autofill_changes_[i].profile_specifics_.guid())) {
+ LOG(ERROR) << "could not delete the profile " <<
+ autofill_changes_[i].profile_specifics_.guid();
+ continue;
+ }
+ continue;
+ }
+
+ // Now for updates and adds.
+ ApplyAutofillProfileChange(autofill_changes_[i].action_,
+ autofill_changes_[i].profile_specifics_,
+ autofill_changes_[i].id_);
+ }
+
+ autofill_changes_.clear();
+
+ PostOptimisticRefreshTask();
+}
+
+void AutofillProfileChangeProcessor::PostOptimisticRefreshTask() {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ new DoOptimisticRefreshForAutofill(
+ personal_data_));
+}
+
+void AutofillProfileChangeProcessor::ApplyAutofillProfileChange(
+ sync_api::SyncManager::ChangeRecord::Action action,
+ const sync_pb::AutofillProfileSpecifics& profile_specifics,
+ int64 sync_id) {
+
+ DCHECK_NE(sync_api::SyncManager::ChangeRecord::ACTION_DELETE, action);
+ switch (action) {
+ case sync_api::SyncManager::ChangeRecord::ACTION_ADD: {
+ AutoFillProfile p(profile_specifics.guid());
+ AutofillProfileModelAssociator::OverwriteProfileWithServerData(&p,
+ profile_specifics);
+ if (!web_database_->AddAutoFillProfile(p)) {
+ LOG(ERROR) << "could not add autofill profile for guid " << p.guid();
+ break;
+ }
+
+ // Now that the node has been succesfully created we can associate it.
+ std::string guid = p.guid();
+ model_associator_->Associate(&guid, sync_id);
+ break;
+ }
+ case sync_api::SyncManager::ChangeRecord::ACTION_UPDATE: {
+ AutoFillProfile *p;
+ if (!web_database_->GetAutoFillProfileForGUID(
+ profile_specifics.guid(), &p)) {
+ LOG(ERROR) << "Could not find the autofill profile to update for " <<
+ profile_specifics.guid();
+ break;
+ }
+ scoped_ptr<AutoFillProfile> autofill_pointer(p);
+ AutofillProfileModelAssociator::OverwriteProfileWithServerData(
+ autofill_pointer.get(),
+ profile_specifics);
+
+ if (!web_database_->UpdateAutoFillProfile(*(autofill_pointer.get()))) {
+ LOG(ERROR) << "Could not update autofill profile for " <<
+ profile_specifics.guid();
+ break;
+ }
+ break;
+ }
+ default: {
+ NOTREACHED();
+ break;
+ }
+ }
+}
+
+void AutofillProfileChangeProcessor::RemoveSyncNode(const std::string& guid,
+ sync_api::WriteTransaction* trans) {
+ sync_api::WriteNode node(trans);
+ int64 sync_id = model_associator_->GetSyncIdFromChromeId(guid);
+ if (sync_api::kInvalidId == sync_id) {
+ LOG(ERROR) << "Could not find the node in associator " << guid;
+ return;
+ }
+
+ if (!node.InitByIdLookup(sync_id)) {
+ LOG(ERROR) << "Could not find the sync node for " << guid;
+ return;
+ }
+
+ model_associator_->Disassociate(sync_id);
+ node.Remove();
+}
+
+void AutofillProfileChangeProcessor::AddAutofillProfileSyncNode(
+ sync_api::WriteTransaction* trans,
+ sync_api::BaseNode& autofill_profile_root,
+ const AutoFillProfile& profile) {
+ sync_api::WriteNode node(trans);
+ if (!node.InitUniqueByCreation(syncable::AUTOFILL_PROFILE,
+ autofill_profile_root,
+ profile.guid())) {
+ LOG(ERROR) << "could not create a sync node ";
+ return;
+ }
+
+ node.SetTitle(UTF8ToWide(profile.guid()));
+
+ WriteAutofillProfile(profile, &node);
+}
+
+void AutofillProfileChangeProcessor::StartObserving() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+ notification_registrar_.Add(this,
+ NotificationType::AUTOFILL_PROFILE_CHANGED_GUID,
+ NotificationService::AllSources());
+}
+
+void AutofillProfileChangeProcessor::StopObserving() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+ notification_registrar_.RemoveAll();
+}
+
+void AutofillProfileChangeProcessor::WriteAutofillProfile(
+ const AutoFillProfile& profile,
+ sync_api::WriteNode* node) {
+ sync_pb::AutofillProfileSpecifics specifics;
+ specifics.set_guid(profile.guid());
+ specifics.set_name_first(UTF16ToUTF8(
+ profile.GetFieldText(AutoFillType(NAME_FIRST))));
+ specifics.set_name_middle(UTF16ToUTF8(
+ profile.GetFieldText(AutoFillType(NAME_MIDDLE))));
+ specifics.set_name_last(
+ UTF16ToUTF8(profile.GetFieldText(AutoFillType(NAME_LAST))));
+ specifics.set_address_home_line1(
+ UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_LINE1))));
+ specifics.set_address_home_line2(
+ UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_LINE2))));
+ specifics.set_address_home_city(UTF16ToUTF8(profile.GetFieldText(
+ AutoFillType(ADDRESS_HOME_CITY))));
+ specifics.set_address_home_state(UTF16ToUTF8(profile.GetFieldText(
+ AutoFillType(ADDRESS_HOME_STATE))));
+ specifics.set_address_home_country(UTF16ToUTF8(profile.GetFieldText(
+ AutoFillType(ADDRESS_HOME_COUNTRY))));
+ specifics.set_address_home_zip(UTF16ToUTF8(profile.GetFieldText(
+ AutoFillType(ADDRESS_HOME_ZIP))));
+ specifics.set_email_address(UTF16ToUTF8(profile.GetFieldText(
+ AutoFillType(EMAIL_ADDRESS))));
+ specifics.set_company_name(UTF16ToUTF8(profile.GetFieldText(
+ AutoFillType(COMPANY_NAME))));
+ specifics.set_phone_fax_whole_number(UTF16ToUTF8(profile.GetFieldText(
+ AutoFillType(PHONE_FAX_WHOLE_NUMBER))));
+ specifics.set_phone_home_whole_number(UTF16ToUTF8(profile.GetFieldText(
+ AutoFillType(PHONE_HOME_WHOLE_NUMBER))));
+ node->SetAutofillProfileSpecifics(specifics);
+}
+
+} // namespace browser_sync
+
diff --git a/chrome/browser/sync/glue/autofill_profile_change_processor.h b/chrome/browser/sync/glue/autofill_profile_change_processor.h
new file mode 100644
index 0000000..0b408a3
--- /dev/null
+++ b/chrome/browser/sync/glue/autofill_profile_change_processor.h
@@ -0,0 +1,120 @@
+// 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.
+#ifndef CHROME_BROWSER_SYNC_GLUE_AUTOFILL_PROFILE_CHANGE_PROCESSOR_H_
+#define CHROME_BROWSER_SYNC_GLUE_AUTOFILL_PROFILE_CHANGE_PROCESSOR_H_
+#pragma once
+#include <string>
+#include <vector>
+
+#include "chrome/browser/autofill/autofill_profile.h"
+#include "chrome/browser/autofill/personal_data_manager.h"
+#include "chrome/browser/sync/engine/syncapi.h"
+#include "chrome/browser/sync/glue/autofill_profile_model_associator.h"
+#include "chrome/browser/sync/glue/change_processor.h"
+#include "chrome/browser/sync/unrecoverable_error_handler.h"
+#include "chrome/browser/webdata/autofill_change.h"
+#include "chrome/browser/webdata/web_database.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
+
+namespace browser_sync {
+
+class AutofillProfileChangeProcessor : public ChangeProcessor,
+ public NotificationObserver {
+ public:
+ AutofillProfileChangeProcessor(
+ AutofillProfileModelAssociator *model_associator,
+ WebDatabase* web_database,
+ PersonalDataManager* personal_data_manager,
+ UnrecoverableErrorHandler* error_handler);
+
+ virtual ~AutofillProfileChangeProcessor() {}
+
+ // Virtual methods from ChangeProcessor class.
+ virtual void ApplyChangesFromSyncModel(
+ const sync_api::BaseTransaction *write_trans,
+ const sync_api::SyncManager::ChangeRecord* changes,
+ int change_count);
+
+ virtual void CommitChangesFromSyncModel();
+
+ // Virtual method implemented for the observer class.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+
+ static void WriteAutofillProfile(const AutoFillProfile& profile,
+ sync_api::WriteNode* node);
+
+ protected:
+ // Protected methods from ChangeProcessor.
+ virtual void StartImpl(Profile* profile) {}
+ virtual void StopImpl() {}
+
+ struct AutofillProfileChangeRecord {
+ sync_api::SyncManager::ChangeRecord::Action action_;
+ int64 id_;
+ sync_pb::AutofillProfileSpecifics profile_specifics_;
+ AutofillProfileChangeRecord(
+ sync_api::SyncManager::ChangeRecord::Action action,
+ int64 id,
+ const sync_pb::AutofillProfileSpecifics profile_specifics)
+ : action_(action),
+ id_(id),
+ profile_specifics_(profile_specifics) {}
+ };
+
+ std::vector<AutofillProfileChangeRecord> autofill_changes_;
+
+ virtual void AddAutofillProfileSyncNode(sync_api::WriteTransaction* trans,
+ sync_api::BaseNode& autofill_profile_root,
+ const AutoFillProfile& profile);
+
+ void ActOnChange(AutofillProfileChangeGUID* change,
+ sync_api::WriteTransaction* trans,
+ sync_api::ReadNode& autofill_root);
+
+ private:
+
+ // This ensures that startobsrving gets called after stopobserving even
+ // if there is an early return in the function.
+ // TODO(lipalani) - generalize this and add it to other change processors.
+ class ScopedStopObserving {
+ public:
+ explicit ScopedStopObserving(AutofillProfileChangeProcessor* processor);
+ ~ScopedStopObserving();
+
+ private:
+ ScopedStopObserving() {}
+ AutofillProfileChangeProcessor* processor_;
+ };
+
+ void StartObserving();
+ void StopObserving();
+
+ void PostOptimisticRefreshTask();
+
+ void ApplyAutofillProfileChange(
+ sync_api::SyncManager::ChangeRecord::Action action,
+ const sync_pb::AutofillProfileSpecifics& profile,
+ int64 sync_id);
+
+ void RemoveSyncNode(
+ const std::string& guid, sync_api::WriteTransaction *trans);
+
+ AutofillProfileModelAssociator* model_associator_;
+ bool observing_;
+
+ WebDatabase* web_database_;
+ PersonalDataManager* personal_data_;
+ NotificationRegistrar notification_registrar_;
+};
+
+} // namespace browser_sync
+
+#endif // CHROME_BROWSER_SYNC_GLUE_AUTOFILL_PROFILE_CHANGE_PROCESSOR_H_
+
diff --git a/chrome/browser/sync/glue/autofill_profile_data_type_controller.cc b/chrome/browser/sync/glue/autofill_profile_data_type_controller.cc
new file mode 100644
index 0000000..230b680
--- /dev/null
+++ b/chrome/browser/sync/glue/autofill_profile_data_type_controller.cc
@@ -0,0 +1,33 @@
+// Copyright (c) 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 "chrome/browser/sync/glue/autofill_profile_data_type_controller.h"
+
+#include "chrome/browser/sync/glue/autofill_data_type_controller.h"
+#include "chrome/browser/sync/profile_sync_factory.h"
+
+namespace browser_sync {
+
+AutofillProfileDataTypeController::AutofillProfileDataTypeController(
+ ProfileSyncFactory* profile_sync_factory,
+ Profile* profile,
+ ProfileSyncService* sync_service) : AutofillDataTypeController(
+ profile_sync_factory,
+ profile,
+ sync_service) {}
+
+ProfileSyncFactory::SyncComponents
+ AutofillProfileDataTypeController::CreateSyncComponents(
+ ProfileSyncService* profile_sync_service,
+ WebDatabase* web_database,
+ PersonalDataManager* personal_data,
+ browser_sync::UnrecoverableErrorHandler* error_handler) {
+ return profile_sync_factory_->CreateAutofillProfileSyncComponents(
+ profile_sync_service,
+ web_database,
+ personal_data,
+ this);
+}
+} // namepsace browser_sync
+
diff --git a/chrome/browser/sync/glue/autofill_profile_data_type_controller.h b/chrome/browser/sync/glue/autofill_profile_data_type_controller.h
new file mode 100644
index 0000000..8bb6e8e
--- /dev/null
+++ b/chrome/browser/sync/glue/autofill_profile_data_type_controller.h
@@ -0,0 +1,39 @@
+// 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.
+#ifndef CHROME_BROWSER_SYNC_GLUE_AUTOFILL_PROFILE_DATA_TYPE_CONTROLLER_H_
+#define CHROME_BROWSER_SYNC_GLUE_AUTOFILL_PROFILE_DATA_TYPE_CONTROLLER_H_
+#pragma once
+
+#include "chrome/browser/sync/glue/autofill_data_type_controller.h"
+#include "chrome/browser/sync/profile_sync_factory.h"
+
+namespace browser_sync {
+
+class AutofillProfileDataTypeController : public AutofillDataTypeController {
+ public:
+ AutofillProfileDataTypeController(
+ ProfileSyncFactory* profile_sync_factory,
+ Profile* profile,
+ ProfileSyncService* sync_service);
+ virtual ~AutofillProfileDataTypeController() {}
+
+ virtual syncable::ModelType type() {
+ return syncable::AUTOFILL_PROFILE;
+ }
+
+ virtual const char* name() const {
+ // For logging only.
+ return "autofill_profile";
+ }
+ protected:
+ virtual ProfileSyncFactory::SyncComponents CreateSyncComponents(
+ ProfileSyncService* profile_sync_service,
+ WebDatabase* web_database,
+ PersonalDataManager* personal_data,
+ browser_sync::UnrecoverableErrorHandler* error_handler);
+};
+
+} // namespace browser_sync
+
+#endif // CHROME_BROWSER_SYNC_GLUE_AUTOFILL_PROFILE_DATA_TYPE_CONTROLLER_H_
diff --git a/chrome/browser/sync/glue/autofill_profile_model_associator.cc b/chrome/browser/sync/glue/autofill_profile_model_associator.cc
index 0680da8..b2d2e2c 100644
--- a/chrome/browser/sync/glue/autofill_profile_model_associator.cc
+++ b/chrome/browser/sync/glue/autofill_profile_model_associator.cc
@@ -5,13 +5,15 @@
#include "chrome/browser/sync/glue/autofill_profile_model_associator.h"
#include "base/utf_string_conversions.h"
+#include "chrome/browser/sync/glue/autofill_profile_change_processor.h"
+#include "chrome/browser/sync/glue/do_optimistic_refresh_task.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/webdata/web_database.h"
using sync_api::ReadNode;
namespace browser_sync {
-const char kAutofillProfileTag[] = "google_chrome_autofill_profile";
+const char kAutofillProfileTag[] = "google_chrome_autofill_profiles";
AutofillProfileModelAssociator::AutofillProfileModelAssociator(
ProfileSyncService* sync_service,
@@ -21,7 +23,8 @@ AutofillProfileModelAssociator::AutofillProfileModelAssociator(
web_database_(web_database),
personal_data_(personal_data),
autofill_node_id_(sync_api::kInvalidId),
- abort_association_pending_(false) {
+ abort_association_pending_(false),
+ number_of_profiles_created_(0) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
DCHECK(sync_service_);
DCHECK(web_database_);
@@ -32,6 +35,8 @@ AutofillProfileModelAssociator::~AutofillProfileModelAssociator() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
}
+AutofillProfileModelAssociator::AutofillProfileModelAssociator() {}
+
bool AutofillProfileModelAssociator::TraverseAndAssociateChromeAutoFillProfiles(
sync_api::WriteTransaction* write_trans,
const sync_api::ReadNode& autofill_root,
@@ -41,6 +46,24 @@ bool AutofillProfileModelAssociator::TraverseAndAssociateChromeAutoFillProfiles(
std::vector<AutoFillProfile*>* new_profiles,
std::vector<std::string>* profiles_to_delete) {
+ if (MigrationLoggingEnabled()) {
+ VLOG(1) << "[AUTOFILL MIGRATION]"
+ << "Printing profiles from web db";
+
+ for (std::vector<AutoFillProfile*>::const_iterator ix =
+ all_profiles_from_db.begin(); ix != all_profiles_from_db.end(); ++ix) {
+ AutoFillProfile* p = *ix;
+ VLOG(1) << "[AUTOFILL MIGRATION] "
+ << p->GetFieldText(AutoFillType(NAME_FIRST))
+ << p->GetFieldText(AutoFillType(NAME_LAST))
+ << p->guid();
+ }
+ }
+
+ if (MigrationLoggingEnabled()) {
+ VLOG(1) << "[AUTOFILL MIGRATION]"
+ << "Looking for the above data in sync db..";
+ }
// Alias the all_profiles_from_db so we fit in 80 characters
const std::vector<AutoFillProfile*>& profiles(all_profiles_from_db);
for (std::vector<AutoFillProfile*>::const_iterator ix = profiles.begin();
@@ -50,6 +73,14 @@ bool AutofillProfileModelAssociator::TraverseAndAssociateChromeAutoFillProfiles(
ReadNode node(write_trans);
if (node.InitByClientTagLookup(syncable::AUTOFILL_PROFILE, guid)) {
+ if (MigrationLoggingEnabled()) {
+ VLOG(1) << "[AUTOFILL MIGRATION]"
+ << " Found in sync db: "
+ << (*ix)->GetFieldText(AutoFillType(NAME_FIRST))
+ << (*ix)->GetFieldText(AutoFillType(NAME_LAST))
+ << (*ix)->guid()
+ << " so associating";
+ }
const sync_pb::AutofillProfileSpecifics& autofill(
node.GetAutofillProfileSpecifics());
if (OverwriteProfileWithServerData(*ix, autofill)) {
@@ -66,7 +97,18 @@ bool AutofillProfileModelAssociator::TraverseAndAssociateChromeAutoFillProfiles(
profiles_to_delete);
}
}
+ return true;
+}
+bool AutofillProfileModelAssociator::GetSyncIdForTaggedNode(
+ const std::string& tag,
+ int64* sync_id) {
+ sync_api::ReadTransaction trans(
+ sync_service_->backend()->GetUserShareHandle());
+ sync_api::ReadNode sync_node(&trans);
+ if (!sync_node.InitByTagLookup(tag.c_str()))
+ return false;
+ *sync_id = sync_node.GetId();
return true;
}
@@ -96,6 +138,11 @@ bool AutofillProfileModelAssociator::AssociateModels() {
return false;
}
+ if (MigrationLoggingEnabled()) {
+ VLOG(1) << "[AUTOFILL MIGRATION]"
+ << " Now associating to the new autofill profile model associator"
+ << " root node";
+ }
DataBundle bundle;
{
// The write transaction lock is held inside this block.
@@ -125,12 +172,20 @@ bool AutofillProfileModelAssociator::AssociateModels() {
return false;
}
- // TODO(lipalani) Bug 64111- split out the OptimisticRefreshTask
- // into its own class
- // from autofill_model_associator
- // Will be done as part of the autofill_model_associator work.
- // BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- // new DoOptimisticRefreshTask(personal_data_));
+ if (sync_service_->backend()->GetAutofillMigrationState() !=
+ syncable::MIGRATED) {
+ syncable::AutofillMigrationDebugInfo debug_info;
+ debug_info.autofill_profile_added_during_migration =
+ number_of_profiles_created_;
+ sync_service_->backend()->SetAutofillMigrationDebugInfo(
+ syncable::AutofillMigrationDebugInfo::PROFILES_ADDED,
+ debug_info);
+ sync_service()->backend()->SetAutofillMigrationState(
+ syncable::MIGRATED);
+ }
+
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ new DoOptimisticRefreshForAutofill(personal_data_));
return true;
}
@@ -158,9 +213,7 @@ bool AutofillProfileModelAssociator::SyncModelHasUserCreatedNodes(
sync_api::ReadNode node(&trans);
- if (!node.InitByClientTagLookup(
- syncable::AUTOFILL_PROFILE,
- kAutofillProfileTag)) {
+ if (!node.InitByTagLookup(kAutofillProfileTag)) {
LOG(ERROR) << "Sever did not create a top level node"
<< "Out of data server or autofill type not enabled";
return false;
@@ -203,7 +256,7 @@ int64 AutofillProfileModelAssociator::FindSyncNodeWithProfile(
while (sync_child_id != sync_api::kInvalidId) {
ReadNode read_node(trans);
AutoFillProfile p;
- if (read_node.InitByIdLookup(sync_child_id)) {
+ if (!read_node.InitByIdLookup(sync_child_id)) {
LOG(ERROR) << "unable to find the id given by getfirst child " <<
sync_child_id;
return sync_api::kInvalidId;
@@ -245,6 +298,14 @@ bool AutofillProfileModelAssociator::MakeNewAutofillProfileSyncNodeIfNeeded(
std::string guid = autofill_specifics.guid();
Associate(&guid, sync_node_id);
current_profiles->insert(autofill_specifics.guid());
+ if (MigrationLoggingEnabled()) {
+ VLOG(1) << "[AUTOFILL MIGRATION]"
+ << "Found in sync db but with a different guid: "
+ << UTF16ToUTF8(profile.GetFieldText(AutoFillType(NAME_FIRST)))
+ << UTF16ToUTF8(profile.GetFieldText(AutoFillType(NAME_LAST)))
+ << "New guid " << autofill_specifics.guid()
+ << " so associating";
+ }
} else {
sync_api::WriteNode node(trans);
if (!node.InitUniqueByCreation(
@@ -253,10 +314,18 @@ bool AutofillProfileModelAssociator::MakeNewAutofillProfileSyncNodeIfNeeded(
return false;
}
node.SetTitle(UTF8ToWide(profile.guid()));
+ if (MigrationLoggingEnabled()) {
+ VLOG(1) << "[AUTOFILL MIGRATION]"
+ << "NOT Found in sync db "
+ << UTF16ToUTF8(profile.GetFieldText(AutoFillType(NAME_FIRST)))
+ << UTF16ToUTF8(profile.GetFieldText(AutoFillType(NAME_LAST)))
+ << profile.guid()
+ << " so creating a new sync node.";
+ }
+ AutofillProfileChangeProcessor::WriteAutofillProfile(profile, &node);
+ current_profiles->insert(profile.guid());
+ number_of_profiles_created_++;
- // TODO(lipalani) -Bug 64111 This needs rewriting. This will be tackled
- // when rewriting autofill change processor.
- // AutofillChangeProcessor::WriteAutofillProfile(profile, &node);
}
return true;
}
@@ -267,6 +336,10 @@ bool AutofillProfileModelAssociator::TraverseAndAssociateAllSyncNodes(
DataBundle* bundle) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+ if (MigrationLoggingEnabled()) {
+ VLOG(1) << "[AUTOFILL MIGRATION] "
+ << " Iterating over sync nodes of autofill profile root node";
+ }
int64 sync_child_id = autofill_root.GetFirstChildId();
while (sync_child_id != sync_api::kInvalidId) {
ReadNode sync_child(write_trans);
@@ -290,6 +363,14 @@ void AutofillProfileModelAssociator::AddNativeProfileIfNeeded(
const sync_api::ReadNode& node) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
+ if (MigrationLoggingEnabled()) {
+ VLOG(1) << "[AUTOFILL MIGRATION] "
+ << "Trying to lookup "
+ << profile.name_first()
+ << " "
+ << profile.name_last()
+ << " in the web db";
+ }
if (bundle->current_profiles.find(profile.guid()) ==
bundle->current_profiles.end()) {
std::string guid(profile.guid());
@@ -297,6 +378,15 @@ void AutofillProfileModelAssociator::AddNativeProfileIfNeeded(
AutoFillProfile* p = new AutoFillProfile(profile.guid());
OverwriteProfileWithServerData(p, profile);
bundle->new_profiles.push_back(p);
+ if (MigrationLoggingEnabled()) {
+ VLOG(1) << "[AUTOFILL MIGRATION] "
+ << " Did not find one so creating it on web db";
+ }
+ } else {
+ if (MigrationLoggingEnabled()) {
+ VLOG(1) << "[AUTOFILL MIGRATION] "
+ << " Found it on web db. Moving on ";
+ }
}
}
@@ -330,6 +420,12 @@ bool AutofillProfileModelAssociator::SaveChangesToWebData(
return true;
}
+bool AutofillProfileModelAssociator::InitSyncNodeFromChromeId(
+ const std::string& node_id,
+ sync_api::BaseNode* sync_node) {
+ return false;
+}
+
void AutofillProfileModelAssociator::Associate(
const std::string* autofill,
int64 sync_id) {
@@ -351,7 +447,7 @@ void AutofillProfileModelAssociator::Disassociate(int64 sync_id) {
}
int64 AutofillProfileModelAssociator::GetSyncIdFromChromeId(
- const std::string autofill) {
+ const std::string& autofill) {
AutofillToSyncIdMap::const_iterator iter = id_map_.find(autofill);
return iter == id_map_.end() ? sync_api::kInvalidId : iter->second;
}
@@ -362,10 +458,21 @@ void AutofillProfileModelAssociator::AbortAssociation() {
abort_association_pending_ = true;
}
+const std::string* AutofillProfileModelAssociator::GetChromeNodeFromSyncId(
+ int64 sync_id) {
+ SyncIdToAutofillMap::const_iterator iter = id_map_inverse_.find(sync_id);
+ return iter == id_map_inverse_.end() ? NULL : &(iter->second);
+}
+
bool AutofillProfileModelAssociator::IsAbortPending() {
AutoLock lock(abort_association_pending_lock_);
return abort_association_pending_;
}
+bool AutofillProfileModelAssociator::MigrationLoggingEnabled() {
+ // TODO(lipalani) enable logging via a command line flag.
+ return false;
+}
+
} // namespace browser_sync
diff --git a/chrome/browser/sync/glue/autofill_profile_model_associator.h b/chrome/browser/sync/glue/autofill_profile_model_associator.h
index 8023676..f636b63 100644
--- a/chrome/browser/sync/glue/autofill_profile_model_associator.h
+++ b/chrome/browser/sync/glue/autofill_profile_model_associator.h
@@ -31,6 +31,8 @@ class WriteTransaction;
namespace browser_sync {
+extern const char kAutofillProfileTag[];
+
class AutofillChangeProcessor;
class UnrecoverableErrorHandler;
@@ -70,19 +72,14 @@ class AutofillProfileModelAssociator
// See ModelAssociator interface.
virtual void AbortAssociation();
- virtual const std::string* GetChromeNodeFromSyncId(
- int64 sync_id) {
- return NULL;
- }
+ virtual const std::string* GetChromeNodeFromSyncId(int64 sync_id);
- virtual bool InitSyncNodeFromChromeId(std::string node_id,
- sync_api::BaseNode* sync_node) {
- return false;
- }
+ virtual bool InitSyncNodeFromChromeId(const std::string& node_id,
+ sync_api::BaseNode* sync_node);
// Returns the sync id for the given autofill name, or sync_api::kInvalidId
// if the autofill name is not associated to any sync id.
- virtual int64 GetSyncIdFromChromeId(std::string node_id);
+ virtual int64 GetSyncIdFromChromeId(const std::string& node_id);
// Associates the given autofill name with the given sync id.
virtual void Associate(const std::string* node, int64 sync_id);
@@ -94,15 +91,17 @@ class AutofillProfileModelAssociator
// given permanent tag was found and update
// |sync_id| with that node's id. No current use. To Implement
// only for completeness.
- virtual bool GetSyncIdForTaggedNode(const std::string& tag, int64* sync_id) {
- return false;
- }
+ virtual bool GetSyncIdForTaggedNode(const std::string& tag, int64* sync_id);
// Returns sync service instance.
ProfileSyncService* sync_service() { return sync_service_; }
+ static bool OverwriteProfileWithServerData(
+ AutoFillProfile* merge_into,
+ const sync_pb::AutofillProfileSpecifics& specifics);
+
protected:
- AutofillProfileModelAssociator() {}
+ AutofillProfileModelAssociator();
bool TraverseAndAssociateChromeAutoFillProfiles(
sync_api::WriteTransaction* write_trans,
const sync_api::ReadNode& autofill_root,
@@ -137,10 +136,6 @@ class AutofillProfileModelAssociator
const sync_api::ReadNode& autofill_root,
DataBundle* bundle);
- static bool OverwriteProfileWithServerData(
- AutoFillProfile* merge_into,
- const sync_pb::AutofillProfileSpecifics& specifics);
-
private:
typedef std::map<std::string, int64> AutofillToSyncIdMap;
typedef std::map<int64, std::string> SyncIdToAutofillMap;
@@ -168,6 +163,8 @@ class AutofillProfileModelAssociator
const sync_api::BaseNode& autofill_root,
const AutoFillProfile& profile);
+ bool MigrationLoggingEnabled();
+
ProfileSyncService* sync_service_;
WebDatabase* web_database_;
PersonalDataManager* personal_data_;
@@ -182,6 +179,8 @@ class AutofillProfileModelAssociator
Lock abort_association_pending_lock_;
bool abort_association_pending_;
+ int number_of_profiles_created_;
+
DISALLOW_COPY_AND_ASSIGN(AutofillProfileModelAssociator);
};
diff --git a/chrome/browser/sync/glue/bookmark_change_processor.cc b/chrome/browser/sync/glue/bookmark_change_processor.cc
index 5988bd4..ebc7f1f 100644
--- a/chrome/browser/sync/glue/bookmark_change_processor.cc
+++ b/chrome/browser/sync/glue/bookmark_change_processor.cc
@@ -1,7 +1,6 @@
// 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.
-
#include "chrome/browser/sync/glue/bookmark_change_processor.h"
#include <stack>
@@ -9,11 +8,12 @@
#include "base/string16.h"
#include "base/string_util.h"
+
#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/favicon_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "gfx/codec/png_codec.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -128,6 +128,10 @@ void BookmarkChangeProcessor::RemoveSyncNodeHierarchy(
DCHECK(index_stack.empty()); // Nothing should be left on the stack.
}
+void BookmarkChangeProcessor::Loaded(BookmarkModel* model) {
+ NOTREACHED();
+}
+
void BookmarkChangeProcessor::BookmarkModelBeingDeleted(
BookmarkModel* model) {
DCHECK(!running()) << "BookmarkModel deleted while ChangeProcessor running.";
@@ -447,6 +451,7 @@ const BookmarkNode* BookmarkChangeProcessor::CreateOrUpdateBookmarkNode(
DLOG(WARNING) << "Could not find parent of node being added/updated."
<< " Node title: " << src->GetTitle()
<< ", parent id = " << src->GetParentId();
+
return NULL;
}
int index = CalculateBookmarkModelInsertionIndex(parent, src);
diff --git a/chrome/browser/sync/glue/bookmark_change_processor.h b/chrome/browser/sync/glue/bookmark_change_processor.h
index 65a2632..461cbb0 100644
--- a/chrome/browser/sync/glue/bookmark_change_processor.h
+++ b/chrome/browser/sync/glue/bookmark_change_processor.h
@@ -31,7 +31,7 @@ class BookmarkChangeProcessor : public BookmarkModelObserver,
// BookmarkModelObserver implementation.
// BookmarkModel -> sync_api model change application.
- virtual void Loaded(BookmarkModel* model) { NOTREACHED(); }
+ virtual void Loaded(BookmarkModel* model);
virtual void BookmarkModelBeingDeleted(BookmarkModel* model);
virtual void BookmarkNodeMoved(BookmarkModel* model,
const BookmarkNode* old_parent,
diff --git a/chrome/browser/sync/glue/bookmark_data_type_controller.cc b/chrome/browser/sync/glue/bookmark_data_type_controller.cc
index 093fc16..26a02f4 100644
--- a/chrome/browser/sync/glue/bookmark_data_type_controller.cc
+++ b/chrome/browser/sync/glue/bookmark_data_type_controller.cc
@@ -9,7 +9,7 @@
#include "base/time.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/glue/bookmark_change_processor.h"
#include "chrome/browser/sync/glue/bookmark_model_associator.h"
#include "chrome/browser/sync/profile_sync_service.h"
@@ -88,6 +88,27 @@ void BookmarkDataTypeController::Stop() {
state_ = NOT_RUNNING;
}
+bool BookmarkDataTypeController::enabled() {
+ return true;
+}
+
+syncable::ModelType BookmarkDataTypeController::type() {
+ return syncable::BOOKMARKS;
+}
+
+browser_sync::ModelSafeGroup BookmarkDataTypeController::model_safe_group() {
+ return browser_sync::GROUP_UI;
+}
+
+const char* BookmarkDataTypeController::name() const {
+ // For logging only.
+ return "bookmark";
+}
+
+DataTypeController::State BookmarkDataTypeController::state() {
+ return state_;
+}
+
void BookmarkDataTypeController::OnUnrecoverableError(
const tracked_objects::Location& from_here, const std::string& message) {
// The ProfileSyncService will invoke our Stop() method in response to this.
diff --git a/chrome/browser/sync/glue/bookmark_data_type_controller.h b/chrome/browser/sync/glue/bookmark_data_type_controller.h
index 41068c8..0716b44 100644
--- a/chrome/browser/sync/glue/bookmark_data_type_controller.h
+++ b/chrome/browser/sync/glue/bookmark_data_type_controller.h
@@ -41,26 +41,15 @@ class BookmarkDataTypeController : public DataTypeController,
virtual void Stop();
- virtual bool enabled() {
- return true;
- }
-
- virtual syncable::ModelType type() {
- return syncable::BOOKMARKS;
- }
-
- virtual browser_sync::ModelSafeGroup model_safe_group() {
- return browser_sync::GROUP_UI;
- }
-
- virtual const char* name() const {
- // For logging only.
- return "bookmark";
- }
-
- virtual State state() {
- return state_;
- }
+ virtual bool enabled();
+
+ virtual syncable::ModelType type();
+
+ virtual browser_sync::ModelSafeGroup model_safe_group();
+
+ virtual const char* name() const;
+
+ virtual State state();
// UnrecoverableErrorHandler interface.
virtual void OnUnrecoverableError(const tracked_objects::Location& from_here,
diff --git a/chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc b/chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc
index 78541b0..ae11d93 100644
--- a/chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc
+++ b/chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc
@@ -10,7 +10,7 @@
#include "base/task.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/glue/bookmark_data_type_controller.h"
#include "chrome/browser/sync/glue/change_processor_mock.h"
#include "chrome/browser/sync/glue/model_associator_mock.h"
diff --git a/chrome/browser/sync/glue/bookmark_model_associator.cc b/chrome/browser/sync/glue/bookmark_model_associator.cc
index 82fb511..dba6a21 100644
--- a/chrome/browser/sync/glue/bookmark_model_associator.cc
+++ b/chrome/browser/sync/glue/bookmark_model_associator.cc
@@ -12,8 +12,9 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/engine/syncapi.h"
+#include "chrome/browser/sync/syncable/autofill_migration.h"
#include "chrome/browser/sync/glue/bookmark_change_processor.h"
#include "chrome/browser/sync/profile_sync_service.h"
@@ -159,7 +160,8 @@ BookmarkModelAssociator::BookmarkModelAssociator(
UnrecoverableErrorHandler* persist_ids_error_handler)
: sync_service_(sync_service),
persist_ids_error_handler_(persist_ids_error_handler),
- ALLOW_THIS_IN_INITIALIZER_LIST(persist_associations_(this)) {
+ ALLOW_THIS_IN_INITIALIZER_LIST(persist_associations_(this)),
+ number_of_new_sync_nodes_created_at_association_(0) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(sync_service_);
DCHECK(persist_ids_error_handler_);
@@ -176,7 +178,7 @@ bool BookmarkModelAssociator::DisassociateModels() {
return true;
}
-int64 BookmarkModelAssociator::GetSyncIdFromChromeId(int64 node_id) {
+int64 BookmarkModelAssociator::GetSyncIdFromChromeId(const int64& node_id) {
BookmarkIdToSyncIdMap::const_iterator iter = id_map_.find(node_id);
return iter == id_map_.end() ? sync_api::kInvalidId : iter->second;
}
@@ -188,7 +190,7 @@ const BookmarkNode* BookmarkModelAssociator::GetChromeNodeFromSyncId(
}
bool BookmarkModelAssociator::InitSyncNodeFromChromeId(
- int64 node_id,
+ const int64& node_id,
sync_api::BaseNode* sync_node) {
DCHECK(sync_node);
int64 sync_id = GetSyncIdFromChromeId(node_id);
@@ -413,8 +415,19 @@ bool BookmarkModelAssociator::BuildAssociations() {
parent_node, model, i, &trans, this, sync_service_);
if (parent_node->GetChild(i)->is_folder())
dfs_stack.push(sync_child_id);
+ number_of_new_sync_nodes_created_at_association_++;
}
}
+
+ if (sync_service_->backend()->GetAutofillMigrationState() !=
+ syncable::MIGRATED) {
+ syncable::AutofillMigrationDebugInfo debug_info;
+ debug_info.bookmarks_added_during_migration =
+ number_of_new_sync_nodes_created_at_association_;
+ sync_service_->backend()->SetAutofillMigrationDebugInfo(
+ syncable::AutofillMigrationDebugInfo::BOOKMARK_ADDED,
+ debug_info);
+ }
return true;
}
diff --git a/chrome/browser/sync/glue/bookmark_model_associator.h b/chrome/browser/sync/glue/bookmark_model_associator.h
index 8dce287..577979f 100644
--- a/chrome/browser/sync/glue/bookmark_model_associator.h
+++ b/chrome/browser/sync/glue/bookmark_model_associator.h
@@ -61,7 +61,7 @@ class BookmarkModelAssociator
// Returns sync id for the given bookmark node id.
// Returns sync_api::kInvalidId if the sync node is not found for the given
// bookmark node id.
- virtual int64 GetSyncIdFromChromeId(int64 node_id);
+ virtual int64 GetSyncIdFromChromeId(const int64& node_id);
// Returns the bookmark node for the given sync id.
// Returns NULL if no bookmark node is found for the given sync id.
@@ -70,7 +70,7 @@ class BookmarkModelAssociator
// Initializes the given sync node from the given bookmark node id.
// Returns false if no sync node was found for the given bookmark node id or
// if the initialization of sync node fails.
- virtual bool InitSyncNodeFromChromeId(int64 node_id,
+ virtual bool InitSyncNodeFromChromeId(const int64& node_id,
sync_api::BaseNode* sync_node);
// Associates the given bookmark node with the given sync id.
@@ -135,6 +135,8 @@ class BookmarkModelAssociator
// allows this class to be non-refcounted).
ScopedRunnableMethodFactory<BookmarkModelAssociator> persist_associations_;
+ int number_of_new_sync_nodes_created_at_association_;
+
DISALLOW_COPY_AND_ASSIGN(BookmarkModelAssociator);
};
diff --git a/chrome/browser/sync/glue/change_processor.cc b/chrome/browser/sync/glue/change_processor.cc
index 6b25382..f779070 100644
--- a/chrome/browser/sync/glue/change_processor.cc
+++ b/chrome/browser/sync/glue/change_processor.cc
@@ -3,7 +3,7 @@
// found in the LICENSE file.
#include "chrome/browser/sync/glue/change_processor.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
namespace browser_sync {
@@ -27,4 +27,8 @@ void ChangeProcessor::Stop() {
running_ = false;
}
+bool ChangeProcessor::IsRunning() const {
+ return running_;
+}
+
} // namespace browser_sync
diff --git a/chrome/browser/sync/glue/change_processor.h b/chrome/browser/sync/glue/change_processor.h
index 4d6ec09..3e8a467 100644
--- a/chrome/browser/sync/glue/change_processor.h
+++ b/chrome/browser/sync/glue/change_processor.h
@@ -34,7 +34,7 @@ class ChangeProcessor {
// |StartImpl|.
void Start(Profile* profile, sync_api::UserShare* share_handle);
void Stop();
- virtual bool IsRunning() const { return running_; }
+ virtual bool IsRunning() const;
// Changes have been applied to the backend model and are ready to be
// applied to the frontend model. See syncapi.h for detailed instructions on
diff --git a/chrome/browser/sync/glue/change_processor_mock.h b/chrome/browser/sync/glue/change_processor_mock.h
index bec1369..e138937 100644
--- a/chrome/browser/sync/glue/change_processor_mock.h
+++ b/chrome/browser/sync/glue/change_processor_mock.h
@@ -6,12 +6,13 @@
#define CHROME_BROWSER_SYNC_GLUE_CHANGE_PROCESSOR_MOCK_H__
#pragma once
-#include "chrome/browser/profile.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/change_processor.h"
#include "chrome/browser/sync/syncable/syncable.h"
#include "testing/gmock/include/gmock/gmock.h"
+class Profile;
+
namespace browser_sync {
class ChangeProcessorMock : public ChangeProcessor {
diff --git a/chrome/browser/sync/glue/data_type_manager.h b/chrome/browser/sync/glue/data_type_manager.h
index 24049f2..e904452 100644
--- a/chrome/browser/sync/glue/data_type_manager.h
+++ b/chrome/browser/sync/glue/data_type_manager.h
@@ -51,7 +51,7 @@ class DataTypeManager {
// current state. A SYNC_CONFIGURE_START notification will be sent
// to the UI thread when configuration is started and a
// SYNC_CONFIGURE_DONE notification will be sent (with a
- // ConfigurationResult detail) when configuration is complete.
+ // ConfigureResult detail) when configuration is complete.
//
// Note that you may call Configure() while configuration is in
// progress. Configuration will be complete only when the
diff --git a/chrome/browser/sync/glue/data_type_manager_impl.cc b/chrome/browser/sync/glue/data_type_manager_impl.cc
index af980fa..0177e66 100644
--- a/chrome/browser/sync/glue/data_type_manager_impl.cc
+++ b/chrome/browser/sync/glue/data_type_manager_impl.cc
@@ -23,6 +23,7 @@ static const syncable::ModelType kStartOrder[] = {
syncable::BOOKMARKS,
syncable::PREFERENCES,
syncable::AUTOFILL,
+ syncable::AUTOFILL_PROFILE,
syncable::THEMES,
syncable::TYPED_URLS,
syncable::PASSWORDS,
@@ -339,6 +340,14 @@ void DataTypeManagerImpl::Stop() {
FinishStop();
}
+const DataTypeController::TypeMap& DataTypeManagerImpl::controllers() {
+ return controllers_;
+}
+
+DataTypeManager::State DataTypeManagerImpl::state() {
+ return state_;
+}
+
void DataTypeManagerImpl::FinishStop() {
DCHECK(state_== CONFIGURING ||
state_ == STOPPING ||
diff --git a/chrome/browser/sync/glue/data_type_manager_impl.h b/chrome/browser/sync/glue/data_type_manager_impl.h
index a735394..93d000a 100644
--- a/chrome/browser/sync/glue/data_type_manager_impl.h
+++ b/chrome/browser/sync/glue/data_type_manager_impl.h
@@ -37,13 +37,9 @@ class DataTypeManagerImpl : public DataTypeManager,
virtual void Stop();
- virtual const DataTypeController::TypeMap& controllers() {
- return controllers_;
- };
+ virtual const DataTypeController::TypeMap& controllers();
- virtual State state() {
- return state_;
- }
+ virtual State state();
// NotificationObserver implementation.
virtual void Observe(NotificationType type,
diff --git a/chrome/browser/sync/glue/database_model_worker.cc b/chrome/browser/sync/glue/database_model_worker.cc
index 9bc83d5..b09c6c6 100644
--- a/chrome/browser/sync/glue/database_model_worker.cc
+++ b/chrome/browser/sync/glue/database_model_worker.cc
@@ -34,6 +34,10 @@ void DatabaseModelWorker::CallDoWorkAndSignalTask(Callback0::Type* work,
done->Signal();
}
+ModelSafeGroup DatabaseModelWorker::GetModelSafeGroup() {
+ return GROUP_DB;
+}
+
bool DatabaseModelWorker::CurrentThreadIsWorkThread() {
return BrowserThread::CurrentlyOn(BrowserThread::DB);
}
diff --git a/chrome/browser/sync/glue/database_model_worker.h b/chrome/browser/sync/glue/database_model_worker.h
index a10e2de..6d6a873 100644
--- a/chrome/browser/sync/glue/database_model_worker.h
+++ b/chrome/browser/sync/glue/database_model_worker.h
@@ -22,8 +22,8 @@ class DatabaseModelWorker : public browser_sync::ModelSafeWorker {
explicit DatabaseModelWorker() {}
// ModelSafeWorker implementation. Called on syncapi SyncerThread.
- void DoWorkAndWaitUntilDone(Callback0::Type* work);
- virtual ModelSafeGroup GetModelSafeGroup() { return GROUP_DB; }
+ virtual void DoWorkAndWaitUntilDone(Callback0::Type* work);
+ virtual ModelSafeGroup GetModelSafeGroup();
virtual bool CurrentThreadIsWorkThread();
private:
diff --git a/chrome/browser/sync/glue/do_optimistic_refresh_task.cc b/chrome/browser/sync/glue/do_optimistic_refresh_task.cc
new file mode 100644
index 0000000..654fed2
--- /dev/null
+++ b/chrome/browser/sync/glue/do_optimistic_refresh_task.cc
@@ -0,0 +1,23 @@
+// 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.
+
+#include "chrome/browser/sync/glue/do_optimistic_refresh_task.h"
+
+#include "chrome/browser/autofill/personal_data_manager.h"
+#include "chrome/browser/browser_thread.h"
+
+namespace browser_sync {
+
+DoOptimisticRefreshForAutofill::DoOptimisticRefreshForAutofill(
+ PersonalDataManager* pdm) : pdm_(pdm) {}
+
+DoOptimisticRefreshForAutofill::~DoOptimisticRefreshForAutofill() {}
+
+void DoOptimisticRefreshForAutofill::Run() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ pdm_->Refresh();
+}
+
+} // namespace browser_sync
+
diff --git a/chrome/browser/sync/glue/do_optimistic_refresh_task.h b/chrome/browser/sync/glue/do_optimistic_refresh_task.h
new file mode 100644
index 0000000..f98d436
--- /dev/null
+++ b/chrome/browser/sync/glue/do_optimistic_refresh_task.h
@@ -0,0 +1,26 @@
+// 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.
+#ifndef CHROME_BROWSER_SYNC_GLUE_DO_OPTIMISTIC_REFRESH_TASK_H_
+#define CHROME_BROWSER_SYNC_GLUE_DO_OPTIMISTIC_REFRESH_TASK_H_
+#pragma once
+
+#include "base/ref_counted.h"
+#include "chrome/browser/autofill/personal_data_manager.h"
+
+namespace browser_sync {
+
+// A task used by this class and the change processor to inform the
+// PersonalDataManager living on the UI thread that it needs to refresh.
+class DoOptimisticRefreshForAutofill : public Task {
+ public:
+ explicit DoOptimisticRefreshForAutofill(PersonalDataManager* pdm);
+ virtual ~DoOptimisticRefreshForAutofill();
+ virtual void Run();
+ private:
+ scoped_refptr<PersonalDataManager> pdm_;
+};
+
+} // namespace browser_sync
+#endif // CHROME_BROWSER_SYNC_GLUE_DO_OPTIMISTIC_REFRESH_TASK_H_
+
diff --git a/chrome/browser/sync/glue/extension_change_processor.cc b/chrome/browser/sync/glue/extension_change_processor.cc
index fcbbd01..8997b20 100644
--- a/chrome/browser/sync/glue/extension_change_processor.cc
+++ b/chrome/browser/sync/glue/extension_change_processor.cc
@@ -10,8 +10,8 @@
#include "base/logging.h"
#include "base/stl_util-inl.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/sync/glue/extension_sync.h"
#include "chrome/browser/sync/glue/extension_util.h"
#include "chrome/browser/sync/protocol/extension_specifics.pb.h"
@@ -49,8 +49,7 @@ void ExtensionChangeProcessor::Observe(NotificationType type,
(type != NotificationType::EXTENSION_UNINSTALLED) &&
(type != NotificationType::EXTENSION_LOADED) &&
(type != NotificationType::EXTENSION_UPDATE_DISABLED) &&
- (type != NotificationType::EXTENSION_UNLOADED) &&
- (type != NotificationType::EXTENSION_UNLOADED_DISABLED)) {
+ (type != NotificationType::EXTENSION_UNLOADED)) {
LOG(DFATAL) << "Received unexpected notification of type "
<< type.value;
return;
@@ -61,23 +60,24 @@ void ExtensionChangeProcessor::Observe(NotificationType type,
const UninstalledExtensionInfo* uninstalled_extension_info =
Details<UninstalledExtensionInfo>(details).ptr();
CHECK(uninstalled_extension_info);
- ExtensionType extension_type =
- GetExtensionTypeFromUninstalledExtensionInfo(
- *uninstalled_extension_info);
- if (ContainsKey(traits_.allowed_extension_types, extension_type)) {
+ if (traits_.should_handle_extension_uninstall(
+ *uninstalled_extension_info)) {
const std::string& id = uninstalled_extension_info->extension_id;
VLOG(1) << "Removing server data for uninstalled extension " << id
- << " of type " << extension_type;
+ << " of type " << uninstalled_extension_info->extension_type;
RemoveServerData(traits_, id, profile_->GetProfileSyncService());
}
} else {
- const Extension* extension = Details<const Extension>(details).ptr();
+ const Extension* extension = NULL;
+ if (type == NotificationType::EXTENSION_UNLOADED) {
+ extension = Details<UnloadedExtensionInfo>(details)->extension;
+ } else {
+ extension = Details<const Extension>(details).ptr();
+ }
CHECK(extension);
VLOG(1) << "Updating server data for extension " << extension->id()
<< " (notification type = " << type.value << ")";
- // Ignore non-syncable extensions.
- if (!IsExtensionValidAndSyncable(
- *extension, traits_.allowed_extension_types)) {
+ if (!traits_.is_valid_and_syncable(*extension)) {
return;
}
std::string error;
@@ -96,8 +96,8 @@ void ExtensionChangeProcessor::ApplyChangesFromSyncModel(
if (!running()) {
return;
}
- ExtensionsService* extensions_service =
- GetExtensionsServiceFromProfile(profile_);
+ ExtensionService* extensions_service =
+ GetExtensionServiceFromProfile(profile_);
for (int i = 0; i < change_count; ++i) {
const sync_api::SyncManager::ChangeRecord& change = changes[i];
switch (change.action) {
@@ -181,9 +181,6 @@ void ExtensionChangeProcessor::StartObserving() {
notification_registrar_.Add(
this, NotificationType::EXTENSION_UNLOADED,
Source<Profile>(profile_));
- notification_registrar_.Add(
- this, NotificationType::EXTENSION_UNLOADED_DISABLED,
- Source<Profile>(profile_));
}
void ExtensionChangeProcessor::StopObserving() {
diff --git a/chrome/browser/sync/glue/extension_change_processor.h b/chrome/browser/sync/glue/extension_change_processor.h
index 89428fb..4d50f8c 100644
--- a/chrome/browser/sync/glue/extension_change_processor.h
+++ b/chrome/browser/sync/glue/extension_change_processor.h
@@ -14,7 +14,7 @@
#include "chrome/common/notification_type.h"
#include "chrome/common/notification_registrar.h"
-class ExtensionsService;
+class ExtensionService;
class NotificationDetails;
class NotificationSource;
class Profile;
diff --git a/chrome/browser/sync/glue/extension_data_type_controller.cc b/chrome/browser/sync/glue/extension_data_type_controller.cc
index d5b7900..0f67690 100644
--- a/chrome/browser/sync/glue/extension_data_type_controller.cc
+++ b/chrome/browser/sync/glue/extension_data_type_controller.cc
@@ -8,7 +8,7 @@
#include "base/metrics/histogram.h"
#include "base/time.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/profile_sync_factory.h"
#include "chrome/browser/sync/unrecoverable_error_handler.h"
@@ -84,6 +84,27 @@ void ExtensionDataTypeController::Stop() {
state_ = NOT_RUNNING;
}
+bool ExtensionDataTypeController::enabled() {
+ return true;
+}
+
+syncable::ModelType ExtensionDataTypeController::type() {
+ return syncable::EXTENSIONS;
+}
+
+browser_sync::ModelSafeGroup ExtensionDataTypeController::model_safe_group() {
+ return browser_sync::GROUP_UI;
+}
+
+const char* ExtensionDataTypeController::name() const {
+ // For logging only.
+ return "extension";
+}
+
+DataTypeController::State ExtensionDataTypeController::state() {
+ return state_;
+}
+
void ExtensionDataTypeController::OnUnrecoverableError(
const tracked_objects::Location& from_here,
const std::string& message) {
diff --git a/chrome/browser/sync/glue/extension_data_type_controller.h b/chrome/browser/sync/glue/extension_data_type_controller.h
index 61f1d78..0c031df 100644
--- a/chrome/browser/sync/glue/extension_data_type_controller.h
+++ b/chrome/browser/sync/glue/extension_data_type_controller.h
@@ -34,26 +34,15 @@ class ExtensionDataTypeController : public DataTypeController {
virtual void Stop();
- virtual bool enabled() {
- return true;
- }
-
- virtual syncable::ModelType type() {
- return syncable::EXTENSIONS;
- }
-
- virtual browser_sync::ModelSafeGroup model_safe_group() {
- return browser_sync::GROUP_UI;
- }
-
- virtual const char* name() const {
- // For logging only.
- return "extension";
- }
-
- virtual State state() {
- return state_;
- }
+ virtual bool enabled();
+
+ virtual syncable::ModelType type();
+
+ virtual browser_sync::ModelSafeGroup model_safe_group();
+
+ virtual const char* name() const;
+
+ virtual State state();
// UnrecoverableErrorHandler interface.
virtual void OnUnrecoverableError(
diff --git a/chrome/browser/sync/glue/extension_sync.cc b/chrome/browser/sync/glue/extension_sync.cc
index facf5f1..83068df 100644
--- a/chrome/browser/sync/glue/extension_sync.cc
+++ b/chrome/browser/sync/glue/extension_sync.cc
@@ -8,11 +8,12 @@
#include "base/logging.h"
#include "chrome/browser/extensions/extension_updater.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/extension_data.h"
#include "chrome/browser/sync/glue/extension_sync_traits.h"
+#include "chrome/browser/sync/glue/extension_util.h"
#include "chrome/browser/sync/profile_sync_service.h"
namespace browser_sync {
@@ -33,20 +34,20 @@ bool RootNodeHasChildren(const char* tag,
return true;
}
-ExtensionsService* GetExtensionsServiceFromProfile(
+ExtensionService* GetExtensionServiceFromProfile(
Profile* profile) {
CHECK(profile);
- ExtensionsService* extensions_service = profile->GetExtensionsService();
+ ExtensionService* extensions_service = profile->GetExtensionService();
CHECK(extensions_service);
return extensions_service;
}
namespace {
-ExtensionsService* GetExtensionsServiceFromProfileSyncService(
+ExtensionService* GetExtensionServiceFromProfileSyncService(
ProfileSyncService* sync_service) {
CHECK(sync_service);
- return GetExtensionsServiceFromProfile(sync_service->profile());
+ return GetExtensionServiceFromProfile(sync_service->profile());
}
// Updates the value in |extension_data_map| from the given data,
@@ -79,15 +80,15 @@ ExtensionData* SetOrCreateExtensionData(
// extensions in |unsynced_extensions|.
void ReadClientDataFromExtensionList(
const ExtensionList& extensions,
- const ExtensionTypeSet& allowed_extension_types,
- ExtensionsService* extensions_service,
+ IsValidAndSyncablePredicate is_valid_and_syncable,
+ ExtensionService* extensions_service,
std::set<std::string>* unsynced_extensions,
ExtensionDataMap* extension_data_map) {
for (ExtensionList::const_iterator it = extensions.begin();
it != extensions.end(); ++it) {
CHECK(*it);
const Extension& extension = **it;
- if (IsExtensionValidAndSyncable(extension, allowed_extension_types)) {
+ if (is_valid_and_syncable(extension)) {
sync_pb::ExtensionSpecifics client_specifics;
GetExtensionSpecifics(extension, extensions_service->extension_prefs(),
&client_specifics);
@@ -109,21 +110,21 @@ void ReadClientDataFromExtensionList(
// Simply calls ReadClientDataFromExtensionList() on the list of
// enabled and disabled extensions from |extensions_service|.
void SlurpClientData(
- const ExtensionTypeSet& allowed_extension_types,
- ExtensionsService* extensions_service,
+ IsValidAndSyncablePredicate is_valid_and_syncable,
+ ExtensionService* extensions_service,
std::set<std::string>* unsynced_extensions,
ExtensionDataMap* extension_data_map) {
const ExtensionList* extensions = extensions_service->extensions();
CHECK(extensions);
ReadClientDataFromExtensionList(
- *extensions, allowed_extension_types, extensions_service,
+ *extensions, is_valid_and_syncable, extensions_service,
unsynced_extensions, extension_data_map);
const ExtensionList* disabled_extensions =
extensions_service->disabled_extensions();
CHECK(disabled_extensions);
ReadClientDataFromExtensionList(
- *disabled_extensions, allowed_extension_types, extensions_service,
+ *disabled_extensions, is_valid_and_syncable, extensions_service,
unsynced_extensions, extension_data_map);
}
@@ -191,14 +192,14 @@ bool SlurpServerData(
bool SlurpExtensionData(const ExtensionSyncTraits& traits,
ProfileSyncService* sync_service,
ExtensionDataMap* extension_data_map) {
- ExtensionsService* extensions_service =
- GetExtensionsServiceFromProfileSyncService(sync_service);
+ ExtensionService* extensions_service =
+ GetExtensionServiceFromProfileSyncService(sync_service);
std::set<std::string> unsynced_extensions;
// Read client-side data first so server data takes precedence, and
// also so we have an idea of which extensions are unsyncable.
SlurpClientData(
- traits.allowed_extension_types, extensions_service,
+ traits.is_valid_and_syncable, extensions_service,
&unsynced_extensions, extension_data_map);
if (!SlurpServerData(
@@ -258,9 +259,8 @@ bool UpdateServer(
// function is called. Otherwise, the extension needs updating to a
// new version.
void TryUpdateClient(
- const ExtensionTypeSet& allowed_extension_types,
- PendingExtensionInfo::ExpectedCrxType expected_crx_type,
- ExtensionsService* extensions_service,
+ IsValidAndSyncablePredicate is_valid_and_syncable,
+ ExtensionService* extensions_service,
ExtensionData* extension_data) {
DCHECK(!extension_data->NeedsUpdate(ExtensionData::SERVER));
DCHECK(extension_data->NeedsUpdate(ExtensionData::CLIENT));
@@ -270,7 +270,7 @@ void TryUpdateClient(
const std::string& id = specifics.id();
const Extension* extension = extensions_service->GetExtensionById(id, true);
if (extension) {
- if (!IsExtensionValidAndSyncable(*extension, allowed_extension_types)) {
+ if (!is_valid_and_syncable(*extension)) {
LOG(DFATAL) << "TryUpdateClient() called for non-syncable extension "
<< extension->id();
return;
@@ -295,7 +295,7 @@ void TryUpdateClient(
// permissions.
extensions_service->AddPendingExtensionFromSync(
id, update_url,
- expected_crx_type,
+ is_valid_and_syncable,
true, // install_silently
specifics.enabled(),
specifics.incognito_enabled());
@@ -307,10 +307,10 @@ void TryUpdateClient(
//
// TODO(akalin): Combine this with the similar function in
// theme_util.cc.
-void NudgeExtensionUpdater(ExtensionsService* extensions_service) {
+void NudgeExtensionUpdater(ExtensionService* extensions_service) {
ExtensionUpdater* extension_updater = extensions_service->updater();
// Auto-updates should now be on always (see the construction of the
- // ExtensionsService in ProfileImpl::InitExtensions()).
+ // ExtensionService in ProfileImpl::InitExtensions()).
if (extension_updater) {
extension_updater->CheckNow();
} else {
@@ -332,8 +332,8 @@ bool FlushExtensionData(const ExtensionSyncTraits& traits,
return false;
}
- ExtensionsService* extensions_service =
- GetExtensionsServiceFromProfileSyncService(sync_service);
+ ExtensionService* extensions_service =
+ GetExtensionServiceFromProfileSyncService(sync_service);
// Update server and client as necessary.
bool should_nudge_extension_updater = false;
@@ -350,8 +350,7 @@ bool FlushExtensionData(const ExtensionSyncTraits& traits,
}
DCHECK(!extension_data.NeedsUpdate(ExtensionData::SERVER));
if (extension_data.NeedsUpdate(ExtensionData::CLIENT)) {
- TryUpdateClient(traits.allowed_extension_types,
- traits.expected_crx_type,
+ TryUpdateClient(traits.is_valid_and_syncable,
extensions_service, &extension_data);
if (extension_data.NeedsUpdate(ExtensionData::CLIENT)) {
should_nudge_extension_updater = true;
@@ -372,8 +371,7 @@ bool UpdateServerData(const ExtensionSyncTraits& traits,
ProfileSyncService* sync_service,
std::string* error) {
const std::string& id = extension.id();
- if (!IsExtensionValidAndSyncable(extension,
- traits.allowed_extension_types)) {
+ if (!traits.is_valid_and_syncable(extension)) {
*error =
std::string("UpdateServerData() called for invalid or "
"unsyncable extension ") + id;
@@ -381,8 +379,8 @@ bool UpdateServerData(const ExtensionSyncTraits& traits,
return false;
}
- ExtensionsService* extensions_service =
- GetExtensionsServiceFromProfileSyncService(sync_service);
+ ExtensionService* extensions_service =
+ GetExtensionServiceFromProfileSyncService(sync_service);
sync_pb::ExtensionSpecifics client_data;
GetExtensionSpecifics(extension, extensions_service->extension_prefs(),
&client_data);
@@ -442,15 +440,14 @@ void RemoveServerData(const ExtensionSyncTraits& traits,
void UpdateClient(const ExtensionSyncTraits& traits,
const sync_pb::ExtensionSpecifics& server_data,
- ExtensionsService* extensions_service) {
+ ExtensionService* extensions_service) {
DcheckIsExtensionSpecificsValid(server_data);
ExtensionData extension_data =
ExtensionData::FromData(ExtensionData::SERVER, server_data);
const Extension* extension =
extensions_service->GetExtensionById(server_data.id(), true);
if (extension) {
- if (!IsExtensionValidAndSyncable(
- *extension, traits.allowed_extension_types)) {
+ if (!traits.is_valid_and_syncable(*extension)) {
LOG(WARNING) << "Ignoring server data for invalid or "
<< "non-syncable extension " << extension->id();
return;
@@ -465,8 +462,7 @@ void UpdateClient(const ExtensionSyncTraits& traits,
}
DCHECK(!extension_data.NeedsUpdate(ExtensionData::SERVER));
if (extension_data.NeedsUpdate(ExtensionData::CLIENT)) {
- TryUpdateClient(traits.allowed_extension_types,
- traits.expected_crx_type,
+ TryUpdateClient(traits.is_valid_and_syncable,
extensions_service, &extension_data);
if (extension_data.NeedsUpdate(ExtensionData::CLIENT)) {
NudgeExtensionUpdater(extensions_service);
@@ -477,11 +473,10 @@ void UpdateClient(const ExtensionSyncTraits& traits,
void RemoveFromClient(const ExtensionSyncTraits& traits,
const std::string& id,
- ExtensionsService* extensions_service) {
+ ExtensionService* extensions_service) {
const Extension* extension = extensions_service->GetExtensionById(id, true);
if (extension) {
- if (IsExtensionValidAndSyncable(*extension,
- traits.allowed_extension_types)) {
+ if (traits.is_valid_and_syncable(*extension)) {
extensions_service->UninstallExtension(id, false);
} else {
LOG(WARNING) << "Ignoring server data for invalid or "
diff --git a/chrome/browser/sync/glue/extension_sync.h b/chrome/browser/sync/glue/extension_sync.h
index 11295c0..af7f9a5 100644
--- a/chrome/browser/sync/glue/extension_sync.h
+++ b/chrome/browser/sync/glue/extension_sync.h
@@ -13,7 +13,7 @@
#include <string>
class Extension;
-class ExtensionsService;
+class ExtensionService;
class Profile;
class ProfileSyncService;
@@ -38,7 +38,7 @@ bool RootNodeHasChildren(const char* tag,
ProfileSyncService* sync_service,
bool* has_children);
-ExtensionsService* GetExtensionsServiceFromProfile(Profile* profile);
+ExtensionService* GetExtensionServiceFromProfile(Profile* profile);
// Fills |extension_data_map| with both client-side information about
// installed extensions and the server-side information about
@@ -74,12 +74,12 @@ void RemoveServerData(const ExtensionSyncTraits& traits,
// Starts updating the client data from the given server data.
void UpdateClient(const ExtensionSyncTraits& traits,
const sync_pb::ExtensionSpecifics& server_data,
- ExtensionsService* extensions_service);
+ ExtensionService* extensions_service);
// Removes existing client data for the given extension.
void RemoveFromClient(const ExtensionSyncTraits& traits,
const std::string& id,
- ExtensionsService* extensions_service);
+ ExtensionService* extensions_service);
} // namespace browser_sync
diff --git a/chrome/browser/sync/glue/extension_sync_traits.cc b/chrome/browser/sync/glue/extension_sync_traits.cc
index 74e291e..f45dabb 100644
--- a/chrome/browser/sync/glue/extension_sync_traits.cc
+++ b/chrome/browser/sync/glue/extension_sync_traits.cc
@@ -7,23 +7,26 @@
#include "base/string_piece.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/sync/engine/syncapi.h"
+#include "chrome/browser/sync/glue/extension_util.h"
#include "chrome/browser/sync/protocol/app_specifics.pb.h"
#include "chrome/browser/sync/protocol/extension_specifics.pb.h"
+#include "chrome/common/extensions/extension.h"
namespace browser_sync {
ExtensionSyncTraits::ExtensionSyncTraits(
syncable::ModelType model_type,
- PendingExtensionInfo::ExpectedCrxType expected_crx_type,
+ IsValidAndSyncablePredicate is_valid_and_syncable,
+ ShouldHandleExtensionUninstallPredicate
+ should_handle_extension_uninstall,
const char* root_node_tag,
- const ExtensionTypeSet& allowed_extension_types,
ExtensionSpecificsGetter extension_specifics_getter,
ExtensionSpecificsSetter extension_specifics_setter,
ExtensionSpecificsEntityGetter extension_specifics_entity_getter)
: model_type(model_type),
- expected_crx_type(expected_crx_type),
+ is_valid_and_syncable(is_valid_and_syncable),
+ should_handle_extension_uninstall(should_handle_extension_uninstall),
root_node_tag(root_node_tag),
- allowed_extension_types(allowed_extension_types),
extension_specifics_getter(extension_specifics_getter),
extension_specifics_setter(extension_specifics_setter),
extension_specifics_entity_getter(extension_specifics_entity_getter) {}
@@ -54,16 +57,37 @@ bool GetExtensionSpecificsFromEntity(
return true;
}
+bool IsSyncableExtension(Extension::Type type, const GURL& update_url) {
+ switch (type) {
+ case Extension::TYPE_EXTENSION:
+ return true;
+ case Extension::TYPE_USER_SCRIPT:
+ // We only want to sync user scripts with update URLs.
+ return !update_url.is_empty();
+ default:
+ return false;
+ }
+}
+
+bool IsValidAndSyncableExtension(const Extension& extension) {
+ return
+ IsExtensionValid(extension) &&
+ IsSyncableExtension(extension.GetType(), extension.update_url());
+}
+
+bool IsExtensionUninstall(
+ const UninstalledExtensionInfo& uninstalled_extension_info) {
+ return IsSyncableExtension(uninstalled_extension_info.extension_type,
+ uninstalled_extension_info.update_url);
+}
+
} // namespace
ExtensionSyncTraits GetExtensionSyncTraits() {
- ExtensionTypeSet allowed_extension_types;
- allowed_extension_types.insert(EXTENSION);
- allowed_extension_types.insert(UPDATEABLE_USER_SCRIPT);
return ExtensionSyncTraits(syncable::EXTENSIONS,
- PendingExtensionInfo::EXTENSION,
+ &IsValidAndSyncableExtension,
+ &IsExtensionUninstall,
"google_chrome_extensions",
- allowed_extension_types,
&GetExtensionSpecifics,
&SetExtensionSpecifics,
&GetExtensionSpecificsFromEntity);
@@ -96,15 +120,29 @@ bool GetExtensionSpecificsFromEntityOfApp(
return true;
}
+bool IsSyncableApp(Extension::Type type) {
+ return
+ (type == Extension::TYPE_HOSTED_APP) ||
+ (type == Extension::TYPE_PACKAGED_APP);
+}
+
+bool IsValidAndSyncableApp(
+ const Extension& extension) {
+ return IsExtensionValid(extension) && IsSyncableApp(extension.GetType());
+}
+
+bool IsAppUninstall(
+ const UninstalledExtensionInfo& uninstalled_extension_info) {
+ return IsSyncableApp(uninstalled_extension_info.extension_type);
+}
+
} // namespace
ExtensionSyncTraits GetAppSyncTraits() {
- ExtensionTypeSet allowed_extension_types;
- allowed_extension_types.insert(APP);
return ExtensionSyncTraits(syncable::APPS,
- PendingExtensionInfo::APP,
+ &IsValidAndSyncableApp,
+ &IsAppUninstall,
"google_chrome_apps",
- allowed_extension_types,
&GetExtensionSpecificsOfApp,
&SetExtensionSpecificsOfApp,
&GetExtensionSpecificsFromEntityOfApp);
diff --git a/chrome/browser/sync/glue/extension_sync_traits.h b/chrome/browser/sync/glue/extension_sync_traits.h
index 86a5a89..cafc790 100644
--- a/chrome/browser/sync/glue/extension_sync_traits.h
+++ b/chrome/browser/sync/glue/extension_sync_traits.h
@@ -6,9 +6,10 @@
#define CHROME_BROWSER_SYNC_GLUE_EXTENSION_SYNC_TRAITS_H_
#pragma once
-#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/sync/syncable/model_type.h"
-#include "chrome/browser/sync/glue/extension_util.h"
+
+class Extension;
+struct UninstalledExtensionInfo;
namespace sync_api {
class BaseNode;
@@ -16,11 +17,17 @@ class WriteNode;
} // namespace sync_api
namespace sync_pb {
+class EntitySpecifics;
class ExtensionSpecifics;
} // namespace sync_pb
namespace browser_sync {
+typedef bool (*IsValidAndSyncablePredicate)(const Extension&);
+
+typedef bool (*ShouldHandleExtensionUninstallPredicate)(
+ const UninstalledExtensionInfo&);
+
// ExtensionSpecificsGetter : BaseNode -> ExtensionSpecifics
typedef const sync_pb::ExtensionSpecifics& (*ExtensionSpecificsGetter)(
const sync_api::BaseNode&);
@@ -41,9 +48,10 @@ typedef bool (*ExtensionSpecificsEntityGetter)(
struct ExtensionSyncTraits {
ExtensionSyncTraits(
syncable::ModelType model_type,
- PendingExtensionInfo::ExpectedCrxType expected_crx_type,
+ IsValidAndSyncablePredicate is_valid_and_syncable,
+ ShouldHandleExtensionUninstallPredicate
+ should_handle_extension_uninstall,
const char* root_node_tag,
- const ExtensionTypeSet& allowed_extension_types,
ExtensionSpecificsGetter extension_specifics_getter,
ExtensionSpecificsSetter extension_specifics_setter,
ExtensionSpecificsEntityGetter extension_specifics_entity_getter);
@@ -51,13 +59,14 @@ struct ExtensionSyncTraits {
// The sync type for the data type.
const syncable::ModelType model_type;
- // The ExpectedCrxType to use for the data type.
- PendingExtensionInfo::ExpectedCrxType expected_crx_type;
+ // A checker to make sure that the downloaded extension is valid and
+ // syncable.
+ const IsValidAndSyncablePredicate is_valid_and_syncable;
+ // A checker to know which extension uninstall events to handle.
+ const ShouldHandleExtensionUninstallPredicate
+ should_handle_extension_uninstall;
// The tag with which the top-level data type node is marked.
const char* const root_node_tag;
- // The set of allowed ExtensionTypes (not just a single one since
- // some data types handle more than one).
- const ExtensionTypeSet allowed_extension_types;
// The function that retrieves a ExtensionSpecifics reference (which
// may be embedded in another specifics object) from a sync node.
const ExtensionSpecificsGetter extension_specifics_getter;
diff --git a/chrome/browser/sync/glue/extension_util.cc b/chrome/browser/sync/glue/extension_util.cc
index a02e8fa..4713c92 100644
--- a/chrome/browser/sync/glue/extension_util.cc
+++ b/chrome/browser/sync/glue/extension_util.cc
@@ -11,7 +11,7 @@
#include "base/stl_util-inl.h"
#include "base/version.h"
#include "chrome/browser/extensions/extension_prefs.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/sync/protocol/extension_specifics.pb.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
@@ -19,47 +19,6 @@
namespace browser_sync {
-ExtensionType GetExtensionType(const Extension& extension) {
- if (extension.is_theme()) {
- return THEME;
- }
-
- if (extension.is_app()) {
- return APP;
- }
-
- if (extension.converted_from_user_script()) {
- if (extension.update_url().is_empty()) {
- return LOCAL_USER_SCRIPT;
- }
- return UPDATEABLE_USER_SCRIPT;
- }
-
- // Otherwise, we just have a regular extension.
- return EXTENSION;
-}
-
-// Keep this in sync with the above function.
-// TODO(akalin): Or just hurry up and remove this!
-ExtensionType GetExtensionTypeFromUninstalledExtensionInfo(
- const UninstalledExtensionInfo& uninstalled_extension_info) {
- if (uninstalled_extension_info.is_theme) {
- return THEME;
- }
-
- if (uninstalled_extension_info.is_app) {
- return APP;
- }
-
- if (uninstalled_extension_info.converted_from_user_script) {
- if (uninstalled_extension_info.update_url.is_empty()) {
- return LOCAL_USER_SCRIPT;
- }
- return UPDATEABLE_USER_SCRIPT;
- }
- return EXTENSION;
-}
-
bool IsExtensionValid(const Extension& extension) {
// TODO(akalin): Figure out if we need to allow some other types.
if (extension.location() != Extension::INTERNAL) {
@@ -88,13 +47,6 @@ bool IsExtensionValid(const Extension& extension) {
return true;
}
-bool IsExtensionValidAndSyncable(const Extension& extension,
- const ExtensionTypeSet& allowed_types) {
- return
- IsExtensionValid(extension) &&
- ContainsKey(allowed_types, GetExtensionType(extension));
-}
-
std::string ExtensionSpecificsToString(
const sync_pb::ExtensionSpecifics& specifics) {
std::stringstream ss;
@@ -230,7 +182,7 @@ bool IsExtensionOutdated(const Extension& extension,
void SetExtensionProperties(
const sync_pb::ExtensionSpecifics& specifics,
- ExtensionsService* extensions_service, const Extension* extension) {
+ ExtensionService* extensions_service, const Extension* extension) {
DcheckIsExtensionSpecificsValid(specifics);
CHECK(extensions_service);
CHECK(extension);
diff --git a/chrome/browser/sync/glue/extension_util.h b/chrome/browser/sync/glue/extension_util.h
index a46d1fb..e908650 100644
--- a/chrome/browser/sync/glue/extension_util.h
+++ b/chrome/browser/sync/glue/extension_util.h
@@ -9,13 +9,11 @@
// This file contains some low-level utility functions used by
// extensions sync.
-#include <set>
#include <string>
class Extension;
class ExtensionPrefs;
-class ExtensionTypeSet;
-class ExtensionsService;
+class ExtensionService;
struct UninstalledExtensionInfo;
namespace sync_pb {
@@ -24,38 +22,9 @@ class ExtensionSpecifics;
namespace browser_sync {
-enum ExtensionType {
- THEME,
- EXTENSION,
- // A converted user script that does not have an update URL.
- LOCAL_USER_SCRIPT,
- // A converted user script that has an update URL. (We don't have a
- // similar distinction for "regular" extensions as an empty update
- // URL is interpreted to mean the default update URL [i.e., the
- // extensions gallery].)
- UPDATEABLE_USER_SCRIPT,
- APP,
-};
-
-typedef std::set<ExtensionType> ExtensionTypeSet;
-
-// Returns the type of the given extension.
-//
-// TODO(akalin): Might be useful to move this into extension.cc.
-ExtensionType GetExtensionType(const Extension& extension);
-
-// TODO(akalin): Remove this once we unify ExtensionType and simply
-// have an ExtensionType member in UninstalledExtensionInfo.
-ExtensionType GetExtensionTypeFromUninstalledExtensionInfo(
- const UninstalledExtensionInfo& uninstalled_extension_info);
-
// Returns whether or not the given extension is one we want to sync.
bool IsExtensionValid(const Extension& extension);
-// Returns whether or not the given extension is one we want to sync.
-bool IsExtensionValidAndSyncable(const Extension& extension,
- const ExtensionTypeSet& allowed_types);
-
// Stringifies the given ExtensionSpecifics.
std::string ExtensionSpecificsToString(
const sync_pb::ExtensionSpecifics& specifics);
@@ -132,7 +101,7 @@ bool IsExtensionOutdated(const Extension& extension,
// valid.
void SetExtensionProperties(
const sync_pb::ExtensionSpecifics& specifics,
- ExtensionsService* extensions_service, const Extension* extension);
+ ExtensionService* extensions_service, const Extension* extension);
// Merge |specifics| into |merged_specifics|. Both must be valid and
// have the same ID. The merge policy is currently to copy the
diff --git a/chrome/browser/sync/glue/extension_util_unittest.cc b/chrome/browser/sync/glue/extension_util_unittest.cc
index f8eac78..946ca5a 100644
--- a/chrome/browser/sync/glue/extension_util_unittest.cc
+++ b/chrome/browser/sync/glue/extension_util_unittest.cc
@@ -83,45 +83,6 @@ scoped_refptr<Extension> MakeExtension(
return extension;
}
-TEST_F(ExtensionUtilTest, GetExtensionType) {
- {
- FilePath file_path(kExtensionFilePath);
- scoped_refptr<Extension> extension(
- MakeExtension(false, GURL(), GURL(), false,
- Extension::INTERNAL, 0, file_path));
- EXPECT_EQ(EXTENSION, GetExtensionType(*extension));
- }
- {
- FilePath file_path(kExtensionFilePath);
- scoped_refptr<Extension> extension(
- MakeExtension(true, GURL(), GURL(), false,
- Extension::INTERNAL, 0, file_path));
- EXPECT_EQ(THEME, GetExtensionType(*extension));
- }
- {
- FilePath file_path(kExtensionFilePath);
- scoped_refptr<Extension> extension(
- MakeExtension(false, GURL(), GURL(), true,
- Extension::INTERNAL, 0, file_path));
- EXPECT_EQ(LOCAL_USER_SCRIPT, GetExtensionType(*extension));
- }
- {
- FilePath file_path(kExtensionFilePath);
- scoped_refptr<Extension> extension(
- MakeExtension(false, GURL("http://www.google.com"), GURL(), true,
- Extension::INTERNAL, 0, file_path));
- EXPECT_EQ(UPDATEABLE_USER_SCRIPT, GetExtensionType(*extension));
- }
- {
- FilePath file_path(kExtensionFilePath);
- scoped_refptr<Extension> extension(
- MakeExtension(false, GURL(),
- GURL("http://www.google.com"), false,
- Extension::INTERNAL, 0, file_path));
- EXPECT_EQ(APP, GetExtensionType(*extension));
- }
-}
-
TEST_F(ExtensionUtilTest, IsExtensionValid) {
{
FilePath file_path(kExtensionFilePath);
@@ -190,46 +151,6 @@ TEST_F(ExtensionUtilTest, IsExtensionValid) {
}
}
-TEST_F(ExtensionUtilTest, IsExtensionValidAndSyncable) {
- ExtensionTypeSet allowed_extension_types;
- allowed_extension_types.insert(EXTENSION);
- allowed_extension_types.insert(APP);
- {
- FilePath file_path(kExtensionFilePath);
- scoped_refptr<Extension> extension(
- MakeExtension(false, GURL(), GURL(), false,
- Extension::INTERNAL, 0, file_path));
- EXPECT_TRUE(IsExtensionValidAndSyncable(
- *extension, allowed_extension_types));
- }
- {
- FilePath file_path(kExtensionFilePath);
- scoped_refptr<Extension> extension(
- MakeExtension(false, GURL(),
- GURL("http://www.google.com"), false,
- Extension::INTERNAL, 0, file_path));
- EXPECT_TRUE(IsExtensionValidAndSyncable(
- *extension, allowed_extension_types));
- }
- {
- FilePath file_path(kExtensionFilePath);
- scoped_refptr<Extension> extension(
- MakeExtension(false, GURL(), GURL(), true,
- Extension::INTERNAL, 0, file_path));
- EXPECT_FALSE(IsExtensionValidAndSyncable(
- *extension, allowed_extension_types));
- }
- {
- FilePath file_path(kExtensionFilePath);
- scoped_refptr<Extension> extension(
- MakeExtension(false, GURL(), GURL(), false,
- Extension::EXTERNAL_PREF, 0, file_path));
- EXPECT_FALSE(IsExtensionValidAndSyncable(
- *extension, allowed_extension_types));
- }
-}
-
-
TEST_F(ExtensionUtilTest, IsExtensionSpecificsUnset) {
{
sync_pb::ExtensionSpecifics specifics;
@@ -501,7 +422,7 @@ TEST_F(ExtensionUtilTest, IsExtensionOutdated) {
EXPECT_TRUE(IsExtensionOutdated(*extension, specifics));
}
-// TODO(akalin): Make ExtensionsService/ExtensionUpdater testable
+// TODO(akalin): Make ExtensionService/ExtensionUpdater testable
// enough to be able to write a unittest for SetExtensionProperties().
TEST_F(ExtensionUtilTest, MergeExtensionSpecificsWithUserProperties) {
diff --git a/chrome/browser/sync/glue/history_model_worker.cc b/chrome/browser/sync/glue/history_model_worker.cc
index 1c39501..9b0ea50 100644
--- a/chrome/browser/sync/glue/history_model_worker.cc
+++ b/chrome/browser/sync/glue/history_model_worker.cc
@@ -8,7 +8,6 @@
#include "base/ref_counted.h"
#include "base/task.h"
#include "base/waitable_event.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/history/history.h"
using base::WaitableEvent;
@@ -51,6 +50,10 @@ void HistoryModelWorker::DoWorkAndWaitUntilDone(Callback0::Type* work) {
done.Wait();
}
+ModelSafeGroup HistoryModelWorker::GetModelSafeGroup() {
+ return GROUP_HISTORY;
+}
+
bool HistoryModelWorker::CurrentThreadIsWorkThread() {
// TODO(ncarter): How to determine this?
return true;
diff --git a/chrome/browser/sync/glue/history_model_worker.h b/chrome/browser/sync/glue/history_model_worker.h
index 4afeead..bdd0a2c 100644
--- a/chrome/browser/sync/glue/history_model_worker.h
+++ b/chrome/browser/sync/glue/history_model_worker.h
@@ -30,8 +30,8 @@ class HistoryModelWorker : public browser_sync::ModelSafeWorker,
virtual ~HistoryModelWorker();
// ModelSafeWorker implementation. Called on syncapi SyncerThread.
- void DoWorkAndWaitUntilDone(Callback0::Type* work);
- virtual ModelSafeGroup GetModelSafeGroup() { return GROUP_HISTORY; }
+ virtual void DoWorkAndWaitUntilDone(Callback0::Type* work);
+ virtual ModelSafeGroup GetModelSafeGroup();
virtual bool CurrentThreadIsWorkThread();
// CancelableRequestConsumerBase implementation.
diff --git a/chrome/browser/sync/glue/http_bridge.cc b/chrome/browser/sync/glue/http_bridge.cc
index 044cc75..8dc2b6f 100644
--- a/chrome/browser/sync/glue/http_bridge.cc
+++ b/chrome/browser/sync/glue/http_bridge.cc
@@ -8,7 +8,6 @@
#include "base/message_loop_proxy.h"
#include "base/string_number_conversions.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
#include "net/base/cookie_monster.h"
#include "net/base/host_resolver.h"
#include "net/base/load_flags.h"
diff --git a/chrome/browser/sync/glue/model_associator.h b/chrome/browser/sync/glue/model_associator.h
index f74129f..7d8f985 100644
--- a/chrome/browser/sync/glue/model_associator.h
+++ b/chrome/browser/sync/glue/model_associator.h
@@ -60,7 +60,7 @@ class PerDataTypeAssociatorInterface : public AssociatorInterface {
// Returns sync id for the given chrome model id.
// Returns sync_api::kInvalidId if the sync node is not found for the given
// chrome id.
- virtual int64 GetSyncIdFromChromeId(IDType id) = 0;
+ virtual int64 GetSyncIdFromChromeId(const IDType& id) = 0;
// Returns the chrome node for the given sync id.
// Returns NULL if no node is found for the given sync id.
@@ -69,7 +69,7 @@ class PerDataTypeAssociatorInterface : public AssociatorInterface {
// Initializes the given sync node from the given chrome node id.
// Returns false if no sync node was found for the given chrome node id or
// if the initialization of sync node fails.
- virtual bool InitSyncNodeFromChromeId(IDType node_id,
+ virtual bool InitSyncNodeFromChromeId(const IDType& node_id,
sync_api::BaseNode* sync_node) = 0;
// Associates the given chrome node with the given sync id.
diff --git a/chrome/browser/sync/glue/password_change_processor.cc b/chrome/browser/sync/glue/password_change_processor.cc
index c630553..adb7d35 100644
--- a/chrome/browser/sync/glue/password_change_processor.cc
+++ b/chrome/browser/sync/glue/password_change_processor.cc
@@ -4,15 +4,18 @@
#include "chrome/browser/sync/glue/password_change_processor.h"
+#include <string>
+
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/password_manager/password_store.h"
#include "chrome/browser/password_manager/password_store_change.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/glue/password_model_associator.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/protocol/password_specifics.pb.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"
#include "webkit/glue/password_form.h"
diff --git a/chrome/browser/sync/glue/password_data_type_controller.cc b/chrome/browser/sync/glue/password_data_type_controller.cc
index 095306a..c483860 100644
--- a/chrome/browser/sync/glue/password_data_type_controller.cc
+++ b/chrome/browser/sync/glue/password_data_type_controller.cc
@@ -10,7 +10,7 @@
#include "base/time.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/password_manager/password_store.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/glue/password_change_processor.h"
#include "chrome/browser/sync/glue/password_model_associator.h"
#include "chrome/browser/sync/profile_sync_service.h"
@@ -73,6 +73,27 @@ void PasswordDataTypeController::Stop() {
NewRunnableMethod(this, &PasswordDataTypeController::StopImpl));
}
+bool PasswordDataTypeController::enabled() {
+ return true;
+}
+
+syncable::ModelType PasswordDataTypeController::type() {
+ return syncable::PASSWORDS;
+}
+
+browser_sync::ModelSafeGroup PasswordDataTypeController::model_safe_group() {
+ return browser_sync::GROUP_PASSWORD;
+}
+
+const char* PasswordDataTypeController::name() const {
+ // For logging only.
+ return "password";
+}
+
+DataTypeController::State PasswordDataTypeController::state() {
+ return state_;
+}
+
void PasswordDataTypeController::StartImpl() {
// No additional services need to be started before we can proceed
// with model association.
diff --git a/chrome/browser/sync/glue/password_data_type_controller.h b/chrome/browser/sync/glue/password_data_type_controller.h
index 0b37334..56fb55b 100644
--- a/chrome/browser/sync/glue/password_data_type_controller.h
+++ b/chrome/browser/sync/glue/password_data_type_controller.h
@@ -13,6 +13,7 @@
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/glue/data_type_controller.h"
+class PasswordStore;
class Profile;
class ProfileSyncFactory;
class ProfileSyncService;
@@ -37,26 +38,15 @@ class PasswordDataTypeController : public DataTypeController {
virtual void Stop();
- virtual bool enabled() {
- return true;
- }
+ virtual bool enabled();
- virtual syncable::ModelType type() {
- return syncable::PASSWORDS;
- }
+ virtual syncable::ModelType type();
- virtual browser_sync::ModelSafeGroup model_safe_group() {
- return browser_sync::GROUP_PASSWORD;
- }
+ virtual browser_sync::ModelSafeGroup model_safe_group();
- virtual const char* name() const {
- // For logging only.
- return "password";
- }
+ virtual const char* name() const;
- virtual State state() {
- return state_;
- }
+ virtual State state();
// UnrecoverableHandler implementation
virtual void OnUnrecoverableError(const tracked_objects::Location& from_here,
diff --git a/chrome/browser/sync/glue/password_model_associator.cc b/chrome/browser/sync/glue/password_model_associator.cc
index f9ab890..3c9d01a 100644
--- a/chrome/browser/sync/glue/password_model_associator.cc
+++ b/chrome/browser/sync/glue/password_model_associator.cc
@@ -9,7 +9,6 @@
#include "base/stl_util-inl.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/password_manager/password_store.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/protocol/password_specifics.pb.h"
@@ -199,13 +198,24 @@ void PasswordModelAssociator::AbortAssociation() {
abort_association_pending_ = true;
}
+const std::string* PasswordModelAssociator::GetChromeNodeFromSyncId(
+ int64 sync_id) {
+ return NULL;
+}
+
+bool PasswordModelAssociator::InitSyncNodeFromChromeId(
+ const std::string& node_id,
+ sync_api::BaseNode* sync_node) {
+ return false;
+}
+
bool PasswordModelAssociator::IsAbortPending() {
AutoLock lock(abort_association_pending_lock_);
return abort_association_pending_;
}
int64 PasswordModelAssociator::GetSyncIdFromChromeId(
- const std::string password) {
+ const std::string& password) {
PasswordToSyncIdMap::const_iterator iter = id_map_.find(password);
return iter == id_map_.end() ? sync_api::kInvalidId : iter->second;
}
diff --git a/chrome/browser/sync/glue/password_model_associator.h b/chrome/browser/sync/glue/password_model_associator.h
index 22c81ba..15eb372 100644
--- a/chrome/browser/sync/glue/password_model_associator.h
+++ b/chrome/browser/sync/glue/password_model_associator.h
@@ -13,7 +13,6 @@
#include "base/basictypes.h"
#include "base/lock.h"
#include "base/task.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/history/history_types.h"
#include "chrome/browser/sync/glue/model_associator.h"
#include "chrome/browser/sync/protocol/password_specifics.pb.h"
@@ -73,19 +72,15 @@ class PasswordModelAssociator
virtual void AbortAssociation();
// Not implemented.
- virtual const std::string* GetChromeNodeFromSyncId(int64 sync_id) {
- return NULL;
- }
+ virtual const std::string* GetChromeNodeFromSyncId(int64 sync_id);
// Not implemented.
- virtual bool InitSyncNodeFromChromeId(std::string node_id,
- sync_api::BaseNode* sync_node) {
- return false;
- }
+ virtual bool InitSyncNodeFromChromeId(const std::string& node_id,
+ sync_api::BaseNode* sync_node);
// Returns the sync id for the given password name, or sync_api::kInvalidId
// if the password name is not associated to any sync id.
- virtual int64 GetSyncIdFromChromeId(std::string node_id);
+ virtual int64 GetSyncIdFromChromeId(const std::string& node_id);
// Associates the given password name with the given sync id.
virtual void Associate(const std::string* node, int64 sync_id);
diff --git a/chrome/browser/sync/glue/password_model_worker.cc b/chrome/browser/sync/glue/password_model_worker.cc
index f832ac1..c06f33f 100644
--- a/chrome/browser/sync/glue/password_model_worker.cc
+++ b/chrome/browser/sync/glue/password_model_worker.cc
@@ -35,6 +35,10 @@ void PasswordModelWorker::CallDoWorkAndSignalTask(Callback0::Type* work,
done->Signal();
}
+ModelSafeGroup PasswordModelWorker::GetModelSafeGroup() {
+ return GROUP_PASSWORD;
+}
+
bool PasswordModelWorker::CurrentThreadIsWorkThread() {
// TODO(ncarter): How to determine this?
return true;
diff --git a/chrome/browser/sync/glue/password_model_worker.h b/chrome/browser/sync/glue/password_model_worker.h
index cd16874..7ef537a 100644
--- a/chrome/browser/sync/glue/password_model_worker.h
+++ b/chrome/browser/sync/glue/password_model_worker.h
@@ -29,8 +29,8 @@ class PasswordModelWorker : public browser_sync::ModelSafeWorker {
virtual ~PasswordModelWorker();
// ModelSafeWorker implementation. Called on syncapi SyncerThread.
- void DoWorkAndWaitUntilDone(Callback0::Type* work);
- virtual ModelSafeGroup GetModelSafeGroup() { return GROUP_PASSWORD; }
+ virtual void DoWorkAndWaitUntilDone(Callback0::Type* work);
+ virtual ModelSafeGroup GetModelSafeGroup();
virtual bool CurrentThreadIsWorkThread();
private:
diff --git a/chrome/browser/sync/glue/preference_change_processor.cc b/chrome/browser/sync/glue/preference_change_processor.cc
index 131b5c4..5b6787b 100644
--- a/chrome/browser/sync/glue/preference_change_processor.cc
+++ b/chrome/browser/sync/glue/preference_change_processor.cc
@@ -11,12 +11,13 @@
#include "base/json/json_reader.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/glue/preference_model_associator.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/protocol/preference_specifics.pb.h"
#include "chrome/common/json_value_serializer.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/pref_names.h"
namespace browser_sync {
diff --git a/chrome/browser/sync/glue/preference_data_type_controller.cc b/chrome/browser/sync/glue/preference_data_type_controller.cc
index f714ed1..d5c09cf 100644
--- a/chrome/browser/sync/glue/preference_data_type_controller.cc
+++ b/chrome/browser/sync/glue/preference_data_type_controller.cc
@@ -86,6 +86,27 @@ void PreferenceDataTypeController::Stop() {
state_ = NOT_RUNNING;
}
+bool PreferenceDataTypeController::enabled() {
+ return true;
+}
+
+syncable::ModelType PreferenceDataTypeController::type() {
+ return syncable::PREFERENCES;
+}
+
+browser_sync::ModelSafeGroup PreferenceDataTypeController::model_safe_group() {
+ return browser_sync::GROUP_UI;
+}
+
+const char* PreferenceDataTypeController::name() const {
+ // For logging only.
+ return "preference";
+}
+
+DataTypeController::State PreferenceDataTypeController::state() {
+ return state_;
+}
+
void PreferenceDataTypeController::OnUnrecoverableError(
const tracked_objects::Location& from_here,
const std::string& message) {
diff --git a/chrome/browser/sync/glue/preference_data_type_controller.h b/chrome/browser/sync/glue/preference_data_type_controller.h
index bc2b93d..4fc177d 100644
--- a/chrome/browser/sync/glue/preference_data_type_controller.h
+++ b/chrome/browser/sync/glue/preference_data_type_controller.h
@@ -29,26 +29,15 @@ class PreferenceDataTypeController : public DataTypeController {
virtual void Stop();
- virtual bool enabled() {
- return true;
- }
-
- virtual syncable::ModelType type() {
- return syncable::PREFERENCES;
- }
-
- virtual browser_sync::ModelSafeGroup model_safe_group() {
- return browser_sync::GROUP_UI;
- }
-
- virtual const char* name() const {
- // For logging only.
- return "preference";
- }
-
- virtual State state() {
- return state_;
- }
+ virtual bool enabled();
+
+ virtual syncable::ModelType type();
+
+ virtual browser_sync::ModelSafeGroup model_safe_group();
+
+ virtual const char* name() const;
+
+ virtual State state();
// UnrecoverableErrorHandler interface.
virtual void OnUnrecoverableError(const tracked_objects::Location& from_here,
diff --git a/chrome/browser/sync/glue/preference_model_associator.cc b/chrome/browser/sync/glue/preference_model_associator.cc
index b6bd57e..e9fcfdf 100644
--- a/chrome/browser/sync/glue/preference_model_associator.cc
+++ b/chrome/browser/sync/glue/preference_model_associator.cc
@@ -10,7 +10,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/synchronized_preferences.h"
#include "chrome/browser/sync/profile_sync_service.h"
@@ -165,8 +165,19 @@ bool PreferenceModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) {
return true;
}
+const PrefService::Preference*
+PreferenceModelAssociator::GetChromeNodeFromSyncId(int64 sync_id) {
+ return NULL;
+}
+
+bool PreferenceModelAssociator::InitSyncNodeFromChromeId(
+ const std::string& node_id,
+ sync_api::BaseNode* sync_node) {
+ return false;
+}
+
int64 PreferenceModelAssociator::GetSyncIdFromChromeId(
- const std::string preference_name) {
+ const std::string& preference_name) {
PreferenceNameToSyncIdMap::const_iterator iter =
id_map_.find(preference_name);
return iter == id_map_.end() ? sync_api::kInvalidId : iter->second;
diff --git a/chrome/browser/sync/glue/preference_model_associator.h b/chrome/browser/sync/glue/preference_model_associator.h
index 15f3001..f50bb2c 100644
--- a/chrome/browser/sync/glue/preference_model_associator.h
+++ b/chrome/browser/sync/glue/preference_model_associator.h
@@ -70,20 +70,15 @@ class PreferenceModelAssociator
}
// Not implemented.
- virtual const PrefService::Preference* GetChromeNodeFromSyncId(
- int64 sync_id) {
- return NULL;
- }
+ virtual const PrefService::Preference* GetChromeNodeFromSyncId(int64 sync_id);
// Not implemented.
- virtual bool InitSyncNodeFromChromeId(std::string node_id,
- sync_api::BaseNode* sync_node) {
- return false;
- }
+ virtual bool InitSyncNodeFromChromeId(const std::string& node_id,
+ sync_api::BaseNode* sync_node);
// Returns the sync id for the given preference name, or sync_api::kInvalidId
// if the preference name is not associated to any sync id.
- virtual int64 GetSyncIdFromChromeId(std::string node_id);
+ virtual int64 GetSyncIdFromChromeId(const std::string& node_id);
// Associates the given preference name with the given sync id.
virtual void Associate(const PrefService::Preference* node, int64 sync_id);
diff --git a/chrome/browser/sync/glue/session_data_type_controller.cc b/chrome/browser/sync/glue/session_data_type_controller.cc
index 8b68972..162891c 100644
--- a/chrome/browser/sync/glue/session_data_type_controller.cc
+++ b/chrome/browser/sync/glue/session_data_type_controller.cc
@@ -82,6 +82,27 @@ void SessionDataTypeController::Stop() {
state_ = NOT_RUNNING;
}
+bool SessionDataTypeController::enabled() {
+ return true;
+}
+
+syncable::ModelType SessionDataTypeController::type() {
+ return syncable::SESSIONS;
+}
+
+browser_sync::ModelSafeGroup SessionDataTypeController::model_safe_group() {
+ return browser_sync::GROUP_UI;
+}
+
+const char* SessionDataTypeController::name() const {
+ // For logging only.
+ return "session";
+}
+
+DataTypeController::State SessionDataTypeController::state() {
+ return state_;
+}
+
void SessionDataTypeController::OnUnrecoverableError(
const tracked_objects::Location& from_here,
const std::string& message) {
diff --git a/chrome/browser/sync/glue/session_data_type_controller.h b/chrome/browser/sync/glue/session_data_type_controller.h
index ae815d4..8736789 100644
--- a/chrome/browser/sync/glue/session_data_type_controller.h
+++ b/chrome/browser/sync/glue/session_data_type_controller.h
@@ -33,33 +33,22 @@ class SessionDataTypeController : public DataTypeController {
virtual void Stop();
- virtual bool enabled() {
- return true;
- }
+ virtual bool enabled();
- virtual syncable::ModelType type() {
- return syncable::SESSIONS;
- }
+ virtual syncable::ModelType type();
- virtual browser_sync::ModelSafeGroup model_safe_group() {
- return browser_sync::GROUP_UI;
- }
+ virtual browser_sync::ModelSafeGroup model_safe_group();
- virtual const char* name() const {
- // For logging only.
- return "session";
- }
+ virtual const char* name() const;
- virtual State state() {
- return state_;
- }
+ virtual State state();
// UnrecoverableErrorHandler interface.
virtual void OnUnrecoverableError(
const tracked_objects::Location& from_here,
const std::string& message);
-SessionModelAssociator* GetModelAssociator();
+ SessionModelAssociator* GetModelAssociator();
private:
// Helper method to run the stashed start callback with a given result.
diff --git a/chrome/browser/sync/glue/session_model_associator.cc b/chrome/browser/sync/glue/session_model_associator.cc
index b4666f8..5ec89be 100644
--- a/chrome/browser/sync/glue/session_model_associator.cc
+++ b/chrome/browser/sync/glue/session_model_associator.cc
@@ -9,7 +9,7 @@
#include "base/logging.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_id.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/syncable/syncable.h"
@@ -99,7 +99,7 @@ bool SessionModelAssociator::GetSyncIdForTaggedNode(const std::string* tag,
return true;
}
-int64 SessionModelAssociator::GetSyncIdFromChromeId(std::string id) {
+int64 SessionModelAssociator::GetSyncIdFromChromeId(const std::string& id) {
sync_api::ReadTransaction trans(
sync_service_->backend()->GetUserShareHandle());
sync_api::ReadNode node(&trans);
@@ -108,6 +108,12 @@ int64 SessionModelAssociator::GetSyncIdFromChromeId(std::string id) {
return node.GetId();
}
+bool SessionModelAssociator::InitSyncNodeFromChromeId(
+ const std::string& id,
+ sync_api::BaseNode* sync_node) {
+ return false;
+}
+
bool SessionModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) {
DCHECK(CalledOnValidThread());
CHECK(has_nodes);
diff --git a/chrome/browser/sync/glue/session_model_associator.h b/chrome/browser/sync/glue/session_model_associator.h
index 89d30be..502af18 100644
--- a/chrome/browser/sync/glue/session_model_associator.h
+++ b/chrome/browser/sync/glue/session_model_associator.h
@@ -52,10 +52,8 @@ class SessionModelAssociator : public PerDataTypeAssociatorInterface<
explicit SessionModelAssociator(ProfileSyncService* sync_service);
virtual ~SessionModelAssociator();
-
// AssociatorInterface and PerDataTypeAssociator Interface implementation.
virtual void AbortAssociation() {
- return;
// No implementation needed, this associator runs on the main
// thread.
}
@@ -93,16 +91,14 @@ class SessionModelAssociator : public PerDataTypeAssociatorInterface<
// Returns sync id for the given chrome model id.
// Returns sync_api::kInvalidId if the sync node is not found for the given
// chrome id.
- virtual int64 GetSyncIdFromChromeId(std::string id);
+ virtual int64 GetSyncIdFromChromeId(const std::string& id);
// Initializes the given sync node from the given chrome node id.
// Returns false if no sync node was found for the given chrome node id or
// if the initialization of sync node fails.
- virtual bool InitSyncNodeFromChromeId(std::string id,
- sync_api::BaseNode* sync_node) {
- return false;
- }
+ virtual bool InitSyncNodeFromChromeId(const std::string& id,
+ sync_api::BaseNode* sync_node);
// The has_nodes out parameter is set to true if the sync model has
// nodes other than the permanent tagged nodes. The method may
diff --git a/chrome/browser/sync/glue/sync_backend_host.cc b/chrome/browser/sync/glue/sync_backend_host.cc
index 068d7b2..4dafe24 100644
--- a/chrome/browser/sync/glue/sync_backend_host.cc
+++ b/chrome/browser/sync/glue/sync_backend_host.cc
@@ -13,8 +13,10 @@
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/net/gaia/token_service.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/engine/syncapi.h"
+#include "chrome/browser/sync/glue/autofill_model_associator.h"
+#include "chrome/browser/sync/glue/autofill_profile_model_associator.h"
#include "chrome/browser/sync/glue/change_processor.h"
#include "chrome/browser/sync/glue/database_model_worker.h"
#include "chrome/browser/sync/glue/history_model_worker.h"
@@ -24,6 +26,7 @@
#include "chrome/browser/sync/sessions/session_state.h"
// TODO(tim): Remove this! We should have a syncapi pass-thru instead.
#include "chrome/browser/sync/syncable/directory_manager.h" // Cryptographer.
+#include "chrome/browser/sync/syncable/model_type.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/net/gaia/gaia_constants.h"
@@ -251,12 +254,73 @@ void SyncBackendHost::Shutdown(bool sync_disabled) {
core_ = NULL; // Releases reference to core_.
}
+syncable::AutofillMigrationState
+ SyncBackendHost::GetAutofillMigrationState() {
+ return core_->syncapi()->GetAutofillMigrationState();
+}
+
+void SyncBackendHost::SetAutofillMigrationState(
+ syncable::AutofillMigrationState state) {
+ return core_->syncapi()->SetAutofillMigrationState(state);
+}
+
+syncable::AutofillMigrationDebugInfo
+ SyncBackendHost::GetAutofillMigrationDebugInfo() {
+ return core_->syncapi()->GetAutofillMigrationDebugInfo();
+}
+
+void SyncBackendHost::SetAutofillMigrationDebugInfo(
+ syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set,
+ const syncable::AutofillMigrationDebugInfo& info) {
+ return core_->syncapi()->SetAutofillMigrationDebugInfo(property_to_set, info);
+}
+
+void SyncBackendHost::ConfigureAutofillMigration() {
+ if (GetAutofillMigrationState() == syncable::NOT_DETERMINED) {
+ sync_api::ReadTransaction trans(GetUserShareHandle());
+ sync_api::ReadNode autofil_root_node(&trans);
+
+ // Check for the presence of autofill node.
+ if (!autofil_root_node.InitByTagLookup(browser_sync::kAutofillTag)) {
+ SetAutofillMigrationState(syncable::INSUFFICIENT_INFO_TO_DETERMINE);
+ return;
+ }
+
+ // Check for children under autofill node.
+ if (autofil_root_node.GetFirstChildId() == static_cast<int64>(0)) {
+ SetAutofillMigrationState(syncable::INSUFFICIENT_INFO_TO_DETERMINE);
+ return;
+ }
+
+ sync_api::ReadNode autofill_profile_root_node(&trans);
+
+ // Check for the presence of autofill profile root node.
+ if (!autofill_profile_root_node.InitByTagLookup(
+ browser_sync::kAutofillProfileTag)) {
+ SetAutofillMigrationState(syncable::NOT_MIGRATED);
+ return;
+ }
+
+ // If our state is not determined then we should not have the autofill
+ // profile node.
+ DCHECK(false);
+
+ // just set it as not migrated.
+ SetAutofillMigrationState(syncable::NOT_MIGRATED);
+ return;
+ }
+}
+
void SyncBackendHost::ConfigureDataTypes(const syncable::ModelTypeSet& types,
CancelableTask* ready_task) {
// Only one configure is allowed at a time.
DCHECK(!configure_ready_task_.get());
DCHECK(syncapi_initialized_);
+ if (types.count(syncable::AUTOFILL_PROFILE) != 0) {
+ ConfigureAutofillMigration();
+ }
+
bool deleted_type = false;
{
diff --git a/chrome/browser/sync/glue/sync_backend_host.h b/chrome/browser/sync/glue/sync_backend_host.h
index 3edd648..fdfc7b4 100644
--- a/chrome/browser/sync/glue/sync_backend_host.h
+++ b/chrome/browser/sync/glue/sync_backend_host.h
@@ -142,6 +142,19 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
virtual void ConfigureDataTypes(const syncable::ModelTypeSet& types,
CancelableTask* ready_task);
+ syncable::AutofillMigrationState
+ GetAutofillMigrationState();
+
+ void SetAutofillMigrationState(
+ syncable::AutofillMigrationState state);
+
+ syncable::AutofillMigrationDebugInfo
+ GetAutofillMigrationDebugInfo();
+
+ void SetAutofillMigrationDebugInfo(
+ syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set,
+ const syncable::AutofillMigrationDebugInfo& info);
+
// Activates change processing for the given data type. This must
// be called synchronously with the data type's model association so
// no changes are dropped between model association and change
@@ -445,6 +458,8 @@ class SyncBackendHost : public browser_sync::ModelSafeWorkerRegistrar {
UIModelWorker* ui_worker();
+ void ConfigureAutofillMigration();
+
// A thread we dedicate for use by our Core to perform initialization,
// authentication, handle messages from the syncapi, and periodically tell
// the syncapi to persist itself.
diff --git a/chrome/browser/sync/glue/synchronized_preferences.h b/chrome/browser/sync/glue/synchronized_preferences.h
index 25135fa..545df8e 100644
--- a/chrome/browser/sync/glue/synchronized_preferences.h
+++ b/chrome/browser/sync/glue/synchronized_preferences.h
@@ -56,6 +56,7 @@ static const char* kSynchronizedPreferences[] = {
prefs::kDeleteCache,
prefs::kDeleteCookies,
prefs::kDeletePasswords,
+ prefs::kDeleteLSOData,
prefs::kDeleteFormData,
prefs::kDeleteTimePeriod,
diff --git a/chrome/browser/sync/glue/theme_change_processor.cc b/chrome/browser/sync/glue/theme_change_processor.cc
index 55f9879..58f25c2 100644
--- a/chrome/browser/sync/glue/theme_change_processor.cc
+++ b/chrome/browser/sync/glue/theme_change_processor.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/sync/glue/theme_change_processor.h"
#include "base/logging.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/theme_util.h"
#include "chrome/browser/sync/protocol/theme_specifics.pb.h"
@@ -39,7 +39,12 @@ void ThemeChangeProcessor::Observe(NotificationType type,
const NotificationDetails& details) {
DCHECK(running());
DCHECK(profile_);
- const Extension* extension = Details<const Extension>(details).ptr();
+ const Extension* extension = NULL;
+ if (type == NotificationType::EXTENSION_UNLOADED) {
+ extension = Details<UnloadedExtensionInfo>(details)->extension;
+ } else {
+ extension = Details<const Extension>(details).ptr();
+ }
std::string current_or_future_theme_id =
profile_->GetThemeProvider()->GetThemeID();
const Extension* current_theme = profile_->GetTheme();
diff --git a/chrome/browser/sync/glue/theme_data_type_controller.cc b/chrome/browser/sync/glue/theme_data_type_controller.cc
index 03cf3cd..166710d 100644
--- a/chrome/browser/sync/glue/theme_data_type_controller.cc
+++ b/chrome/browser/sync/glue/theme_data_type_controller.cc
@@ -8,7 +8,7 @@
#include "base/logging.h"
#include "base/time.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/glue/theme_change_processor.h"
#include "chrome/browser/sync/glue/theme_model_associator.h"
#include "chrome/browser/sync/profile_sync_service.h"
@@ -86,6 +86,28 @@ void ThemeDataTypeController::Stop() {
state_ = NOT_RUNNING;
}
+bool ThemeDataTypeController::enabled() {
+ return true;
+ }
+
+syncable::ModelType ThemeDataTypeController::type() {
+ return syncable::THEMES;
+}
+
+browser_sync::ModelSafeGroup ThemeDataTypeController::model_safe_group() {
+ return browser_sync::GROUP_UI;
+}
+
+const char* ThemeDataTypeController::name() const {
+ // For logging only.
+ return "theme";
+}
+
+DataTypeController::State ThemeDataTypeController::state() {
+ return state_;
+}
+
+
void ThemeDataTypeController::OnUnrecoverableError(
const tracked_objects::Location& from_here,
const std::string& message) {
diff --git a/chrome/browser/sync/glue/theme_data_type_controller.h b/chrome/browser/sync/glue/theme_data_type_controller.h
index 2951a2d..09bc572 100644
--- a/chrome/browser/sync/glue/theme_data_type_controller.h
+++ b/chrome/browser/sync/glue/theme_data_type_controller.h
@@ -34,26 +34,15 @@ class ThemeDataTypeController : public DataTypeController {
virtual void Stop();
- virtual bool enabled() {
- return true;
- }
-
- virtual syncable::ModelType type() {
- return syncable::THEMES;
- }
-
- virtual browser_sync::ModelSafeGroup model_safe_group() {
- return browser_sync::GROUP_UI;
- }
-
- virtual const char* name() const {
- // For logging only.
- return "theme";
- }
-
- virtual State state() {
- return state_;
- }
+ virtual bool enabled();
+
+ virtual syncable::ModelType type();
+
+ virtual browser_sync::ModelSafeGroup model_safe_group();
+
+ virtual const char* name() const;
+
+ virtual State state();
// UnrecoverableErrorHandler interface.
virtual void OnUnrecoverableError(
diff --git a/chrome/browser/sync/glue/theme_util.cc b/chrome/browser/sync/glue/theme_util.cc
index 0f2a16b..c2d70ca 100644
--- a/chrome/browser/sync/glue/theme_util.cc
+++ b/chrome/browser/sync/glue/theme_util.cc
@@ -10,12 +10,12 @@
#include "base/scoped_ptr.h"
#include "chrome/browser/extensions/extension_install_ui.h"
#include "chrome/browser/extensions/extension_updater.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#if defined(TOOLKIT_USES_GTK)
#include "chrome/browser/gtk/gtk_theme_provider.h"
#endif
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/protocol/theme_specifics.pb.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
@@ -75,6 +75,14 @@ bool AreThemeSpecificsEqualHelper(
}
}
+namespace {
+
+bool IsTheme(const Extension& extension) {
+ return extension.is_theme();
+}
+
+} // namespace
+
void SetCurrentThemeFromThemeSpecifics(
const sync_pb::ThemeSpecifics& theme_specifics,
Profile* profile) {
@@ -85,7 +93,7 @@ void SetCurrentThemeFromThemeSpecifics(
std::string id(theme_specifics.custom_theme_id());
GURL update_url(theme_specifics.custom_theme_update_url());
VLOG(1) << "Applying theme " << id << " with update_url " << update_url;
- ExtensionsService* extensions_service = profile->GetExtensionsService();
+ ExtensionService* extensions_service = profile->GetExtensionService();
CHECK(extensions_service);
const Extension* extension = extensions_service->GetExtensionById(id, true);
if (extension) {
@@ -125,8 +133,6 @@ void SetCurrentThemeFromThemeSpecifics(
// No extension with this id exists -- we must install it; we do
// so by adding it as a pending extension and then triggering an
// auto-update cycle.
- const PendingExtensionInfo::ExpectedCrxType kExpectedCrxType =
- PendingExtensionInfo::THEME;
// Themes don't need to install silently as they just pop up an
// informational dialog after installation instead of a
// confirmation dialog.
@@ -134,11 +140,11 @@ void SetCurrentThemeFromThemeSpecifics(
const bool kEnableOnInstall = true;
const bool kEnableIncognitoOnInstall = false;
extensions_service->AddPendingExtensionFromSync(
- id, update_url, kExpectedCrxType,
+ id, update_url, &IsTheme,
kInstallSilently, kEnableOnInstall, kEnableIncognitoOnInstall);
ExtensionUpdater* extension_updater = extensions_service->updater();
// Auto-updates should now be on always (see the construction of
- // the ExtensionsService in ProfileImpl::InitExtensions()).
+ // the ExtensionService in ProfileImpl::InitExtensions()).
if (!extension_updater) {
LOG(DFATAL) << "Extension updater unexpectedly NULL; "
<< "auto-updates may be turned off";
diff --git a/chrome/browser/sync/glue/theme_util_unittest.cc b/chrome/browser/sync/glue/theme_util_unittest.cc
index 3eac301..575ae86 100644
--- a/chrome/browser/sync/glue/theme_util_unittest.cc
+++ b/chrome/browser/sync/glue/theme_util_unittest.cc
@@ -6,7 +6,7 @@
#include "base/file_path.h"
#include "base/values.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/protocol/theme_specifics.pb.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
@@ -114,7 +114,7 @@ TEST_F(ThemeUtilTest, SetCurrentThemeSystemTheme) {
SetCurrentThemeFromThemeSpecifics(theme_specifics, &mock_profile);
}
-// TODO(akalin): Make ExtensionsService/ExtensionUpdater testable
+// TODO(akalin): Make ExtensionService/ExtensionUpdater testable
// enough to be able to write a unittest for SetCurrentTheme for a
// custom theme.
diff --git a/chrome/browser/sync/glue/typed_url_change_processor.cc b/chrome/browser/sync/glue/typed_url_change_processor.cc
index f87bc38..4651d52 100644
--- a/chrome/browser/sync/glue/typed_url_change_processor.cc
+++ b/chrome/browser/sync/glue/typed_url_change_processor.cc
@@ -8,7 +8,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/history/history_backend.h"
#include "chrome/browser/history/history_notifications.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/glue/typed_url_model_associator.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/protocol/typed_url_specifics.pb.h"
diff --git a/chrome/browser/sync/glue/typed_url_data_type_controller.cc b/chrome/browser/sync/glue/typed_url_data_type_controller.cc
index da095fc..81e8d47 100644
--- a/chrome/browser/sync/glue/typed_url_data_type_controller.cc
+++ b/chrome/browser/sync/glue/typed_url_data_type_controller.cc
@@ -10,7 +10,7 @@
#include "base/time.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/history/history.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/glue/typed_url_change_processor.h"
#include "chrome/browser/sync/glue/typed_url_model_associator.h"
#include "chrome/browser/sync/profile_sync_service.h"
@@ -115,6 +115,27 @@ void TypedUrlDataTypeController::Stop() {
history_service_->ScheduleDBTask(new ControlTask(this, false), this);
}
+bool TypedUrlDataTypeController::enabled() {
+ return true;
+}
+
+syncable::ModelType TypedUrlDataTypeController::type() {
+ return syncable::TYPED_URLS;
+}
+
+browser_sync::ModelSafeGroup TypedUrlDataTypeController::model_safe_group() {
+ return browser_sync::GROUP_HISTORY;
+}
+
+const char* TypedUrlDataTypeController::name() const {
+ // For logging only.
+ return "typed_url";
+}
+
+DataTypeController::State TypedUrlDataTypeController::state() {
+ return state_;
+}
+
void TypedUrlDataTypeController::StartImpl(history::HistoryBackend* backend) {
VLOG(1) << "TypedUrl data type controller StartImpl called.";
// No additional services need to be started before we can proceed
diff --git a/chrome/browser/sync/glue/typed_url_data_type_controller.h b/chrome/browser/sync/glue/typed_url_data_type_controller.h
index 0301135..d3892a1 100644
--- a/chrome/browser/sync/glue/typed_url_data_type_controller.h
+++ b/chrome/browser/sync/glue/typed_url_data_type_controller.h
@@ -19,6 +19,7 @@
class NotificationSource;
class NotificationDetails;
+class HistoryService;
class Profile;
class ProfileSyncFactory;
class ProfileSyncService;
@@ -49,26 +50,15 @@ class TypedUrlDataTypeController : public DataTypeController,
virtual void Stop();
- virtual bool enabled() {
- return true;
- }
+ virtual bool enabled();
- virtual syncable::ModelType type() {
- return syncable::TYPED_URLS;
- }
+ virtual syncable::ModelType type();
- virtual browser_sync::ModelSafeGroup model_safe_group() {
- return browser_sync::GROUP_HISTORY;
- }
+ virtual browser_sync::ModelSafeGroup model_safe_group();
- virtual const char* name() const {
- // For logging only.
- return "typed_url";
- }
+ virtual const char* name() const;
- virtual State state() {
- return state_;
- }
+ virtual State state();
// UnrecoverableHandler implementation
virtual void OnUnrecoverableError(const tracked_objects::Location& from_here,
diff --git a/chrome/browser/sync/glue/typed_url_model_associator.cc b/chrome/browser/sync/glue/typed_url_model_associator.cc
index ad15629..9c88fc0 100644
--- a/chrome/browser/sync/glue/typed_url_model_associator.cc
+++ b/chrome/browser/sync/glue/typed_url_model_associator.cc
@@ -8,7 +8,6 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/history/history_backend.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/protocol/typed_url_specifics.pb.h"
@@ -233,8 +232,23 @@ bool TypedUrlModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) {
return true;
}
+void TypedUrlModelAssociator::AbortAssociation() {
+ // TODO(zork): Implement this.
+}
+
+const std::string* TypedUrlModelAssociator::GetChromeNodeFromSyncId(
+ int64 sync_id) {
+ return NULL;
+}
+
+bool TypedUrlModelAssociator::InitSyncNodeFromChromeId(
+ const std::string& node_id,
+ sync_api::BaseNode* sync_node) {
+ return false;
+}
+
int64 TypedUrlModelAssociator::GetSyncIdFromChromeId(
- const std::string typed_url) {
+ const std::string& typed_url) {
TypedUrlToSyncIdMap::const_iterator iter = id_map_.find(typed_url);
return iter == id_map_.end() ? sync_api::kInvalidId : iter->second;
}
diff --git a/chrome/browser/sync/glue/typed_url_model_associator.h b/chrome/browser/sync/glue/typed_url_model_associator.h
index a07bae9..6388de4 100644
--- a/chrome/browser/sync/glue/typed_url_model_associator.h
+++ b/chrome/browser/sync/glue/typed_url_model_associator.h
@@ -13,7 +13,6 @@
#include "base/basictypes.h"
#include "base/string16.h"
#include "base/task.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/history/history_types.h"
#include "chrome/browser/sync/glue/model_associator.h"
#include "chrome/browser/sync/protocol/typed_url_specifics.pb.h"
@@ -74,24 +73,18 @@ class TypedUrlModelAssociator
// than the permanent tagged nodes.
virtual bool SyncModelHasUserCreatedNodes(bool* has_nodes);
- virtual void AbortAssociation() {
- // TODO(zork): Implement this.
- }
+ virtual void AbortAssociation();
// Not implemented.
- virtual const std::string* GetChromeNodeFromSyncId(int64 sync_id) {
- return NULL;
- }
+ virtual const std::string* GetChromeNodeFromSyncId(int64 sync_id);
// Not implemented.
- virtual bool InitSyncNodeFromChromeId(std::string node_id,
- sync_api::BaseNode* sync_node) {
- return false;
- }
+ virtual bool InitSyncNodeFromChromeId(const std::string& node_id,
+ sync_api::BaseNode* sync_node);
// Returns the sync id for the given typed_url name, or sync_api::kInvalidId
// if the typed_url name is not associated to any sync id.
- virtual int64 GetSyncIdFromChromeId(std::string node_id);
+ virtual int64 GetSyncIdFromChromeId(const std::string& node_id);
// Associates the given typed_url name with the given sync id.
virtual void Associate(const std::string* node, int64 sync_id);
diff --git a/chrome/browser/sync/glue/ui_model_worker.cc b/chrome/browser/sync/glue/ui_model_worker.cc
index 86dbf44..24622ae 100644
--- a/chrome/browser/sync/glue/ui_model_worker.cc
+++ b/chrome/browser/sync/glue/ui_model_worker.cc
@@ -89,6 +89,10 @@ void UIModelWorker::Stop() {
state_ = STOPPED;
}
+ModelSafeGroup UIModelWorker::GetModelSafeGroup() {
+ return GROUP_UI;
+}
+
bool UIModelWorker::CurrentThreadIsWorkThread() {
return MessageLoop::current() == ui_loop_;
}
diff --git a/chrome/browser/sync/glue/ui_model_worker.h b/chrome/browser/sync/glue/ui_model_worker.h
index 66a2a99..f3a988b 100644
--- a/chrome/browser/sync/glue/ui_model_worker.h
+++ b/chrome/browser/sync/glue/ui_model_worker.h
@@ -67,7 +67,7 @@ class UIModelWorker : public browser_sync::ModelSafeWorker {
// ModelSafeWorker implementation. Called on syncapi SyncerThread.
virtual void DoWorkAndWaitUntilDone(Callback0::Type* work);
- virtual ModelSafeGroup GetModelSafeGroup() { return GROUP_UI; }
+ virtual ModelSafeGroup GetModelSafeGroup();
virtual bool CurrentThreadIsWorkThread();
// Upon receiving this idempotent call, the ModelSafeWorker can
diff --git a/chrome/browser/sync/notifier/chrome_invalidation_client.cc b/chrome/browser/sync/notifier/chrome_invalidation_client.cc
index 29fd987..4a84d3d 100644
--- a/chrome/browser/sync/notifier/chrome_invalidation_client.cc
+++ b/chrome/browser/sync/notifier/chrome_invalidation_client.cc
@@ -149,20 +149,24 @@ void ChromeInvalidationClient::RegistrationStateChanged(
invalidation::RegistrationState new_state,
const invalidation::UnknownHint& unknown_hint) {
DCHECK(non_thread_safe_.CalledOnValidThread());
- VLOG(1) << "RegistrationStateChanged to " << new_state;
+ VLOG(1) << "RegistrationStateChanged: "
+ << ObjectIdToString(object_id) << " " << new_state;
if (new_state == invalidation::RegistrationState_UNKNOWN) {
VLOG(1) << "is_transient=" << unknown_hint.is_transient()
<< ", message=" << unknown_hint.message();
}
- // TODO(akalin): Figure out something else to do if the failure
- // isn't transient. Even if it is transient, we may still want to
- // add exponential back-off or limit the number of attempts.
+
syncable::ModelType model_type;
- if (ObjectIdToRealModelType(object_id, &model_type) &&
- (new_state != invalidation::RegistrationState_REGISTERED)) {
- registration_manager_->MarkRegistrationLost(model_type);
- } else {
+ if (!ObjectIdToRealModelType(object_id, &model_type)) {
LOG(WARNING) << "Could not get object id model type; ignoring";
+ return;
+ }
+
+ if (new_state != invalidation::RegistrationState_REGISTERED) {
+ // TODO(akalin): Figure out something else to do if the failure
+ // isn't transient. Even if it is transient, we may still want to
+ // add exponential back-off or limit the number of attempts.
+ registration_manager_->MarkRegistrationLost(model_type);
}
}
diff --git a/chrome/browser/sync/notifier/chrome_system_resources.cc b/chrome/browser/sync/notifier/chrome_system_resources.cc
index 46090e1..1f6703a 100644
--- a/chrome/browser/sync/notifier/chrome_system_resources.cc
+++ b/chrome/browser/sync/notifier/chrome_system_resources.cc
@@ -12,34 +12,41 @@
#include "base/message_loop.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
+#include "base/stringprintf.h"
#include "chrome/browser/sync/notifier/invalidation_util.h"
namespace sync_notifier {
ChromeSystemResources::ChromeSystemResources(StateWriter* state_writer)
- : state_writer_(state_writer) {
- CHECK(non_thread_safe_.CalledOnValidThread());
+ : state_writer_(state_writer),
+ created_on_loop_(MessageLoop::current()) {
+ DCHECK(non_thread_safe_.CalledOnValidThread());
+ CHECK(created_on_loop_);
DCHECK(state_writer_);
}
ChromeSystemResources::~ChromeSystemResources() {
- CHECK(non_thread_safe_.CalledOnValidThread());
+ DCHECK(non_thread_safe_.CalledOnValidThread());
+ CHECK_EQ(created_on_loop_, MessageLoop::current());
StopScheduler();
}
invalidation::Time ChromeSystemResources::current_time() {
- CHECK(non_thread_safe_.CalledOnValidThread());
+ DCHECK(non_thread_safe_.CalledOnValidThread());
+ CHECK_EQ(created_on_loop_, MessageLoop::current());
return base::Time::Now();
}
void ChromeSystemResources::StartScheduler() {
- CHECK(non_thread_safe_.CalledOnValidThread());
+ DCHECK(non_thread_safe_.CalledOnValidThread());
+ CHECK_EQ(created_on_loop_, MessageLoop::current());
scoped_runnable_method_factory_.reset(
new ScopedRunnableMethodFactory<ChromeSystemResources>(this));
}
void ChromeSystemResources::StopScheduler() {
- CHECK(non_thread_safe_.CalledOnValidThread());
+ DCHECK(non_thread_safe_.CalledOnValidThread());
+ CHECK_EQ(created_on_loop_, MessageLoop::current());
scoped_runnable_method_factory_.reset();
STLDeleteElements(&posted_tasks_);
}
@@ -47,7 +54,8 @@ void ChromeSystemResources::StopScheduler() {
void ChromeSystemResources::ScheduleWithDelay(
invalidation::TimeDelta delay,
invalidation::Closure* task) {
- CHECK(non_thread_safe_.CalledOnValidThread());
+ DCHECK(non_thread_safe_.CalledOnValidThread());
+ CHECK_EQ(created_on_loop_, MessageLoop::current());
Task* task_to_post = MakeTaskToPost(task);
if (!task_to_post) {
return;
@@ -58,7 +66,8 @@ void ChromeSystemResources::ScheduleWithDelay(
void ChromeSystemResources::ScheduleImmediately(
invalidation::Closure* task) {
- CHECK(non_thread_safe_.CalledOnValidThread());
+ DCHECK(non_thread_safe_.CalledOnValidThread());
+ CHECK_EQ(created_on_loop_, MessageLoop::current());
Task* task_to_post = MakeTaskToPost(task);
if (!task_to_post) {
return;
@@ -70,14 +79,16 @@ void ChromeSystemResources::ScheduleImmediately(
// notifications thread).
void ChromeSystemResources::ScheduleOnListenerThread(
invalidation::Closure* task) {
- CHECK(non_thread_safe_.CalledOnValidThread());
+ DCHECK(non_thread_safe_.CalledOnValidThread());
+ CHECK_EQ(created_on_loop_, MessageLoop::current());
ScheduleImmediately(task);
}
// 'Internal thread' means 'not the listener thread'. Since the
// listener thread is the notifications thread, always return false.
bool ChromeSystemResources::IsRunningOnInternalThread() {
- CHECK(non_thread_safe_.CalledOnValidThread());
+ DCHECK(non_thread_safe_.CalledOnValidThread());
+ CHECK_EQ(created_on_loop_, MessageLoop::current());
return false;
}
@@ -104,7 +115,7 @@ void ChromeSystemResources::Log(
va_list ap;
va_start(ap, format);
std::string result;
- StringAppendV(&result, format, ap);
+ base::StringAppendV(&result, format, ap);
logging::LogMessage(file, line, log_severity).stream() << result;
va_end(ap);
}
@@ -134,8 +145,9 @@ void ChromeSystemResources::WriteState(
Task* ChromeSystemResources::MakeTaskToPost(
invalidation::Closure* task) {
- CHECK(non_thread_safe_.CalledOnValidThread());
+ DCHECK(non_thread_safe_.CalledOnValidThread());
DCHECK(invalidation::IsCallbackRepeatable(task));
+ CHECK_EQ(created_on_loop_, MessageLoop::current());
if (!scoped_runnable_method_factory_.get()) {
delete task;
return NULL;
@@ -148,7 +160,8 @@ Task* ChromeSystemResources::MakeTaskToPost(
}
void ChromeSystemResources::RunPostedTask(invalidation::Closure* task) {
- CHECK(non_thread_safe_.CalledOnValidThread());
+ DCHECK(non_thread_safe_.CalledOnValidThread());
+ CHECK_EQ(created_on_loop_, MessageLoop::current());
RunAndDeleteClosure(task);
posted_tasks_.erase(task);
}
diff --git a/chrome/browser/sync/notifier/chrome_system_resources.h b/chrome/browser/sync/notifier/chrome_system_resources.h
index 2248aae..b6e6256 100644
--- a/chrome/browser/sync/notifier/chrome_system_resources.h
+++ b/chrome/browser/sync/notifier/chrome_system_resources.h
@@ -13,6 +13,7 @@
#include <set>
#include <string>
+#include "base/message_loop.h"
#include "base/non_thread_safe.h"
#include "base/scoped_ptr.h"
#include "base/task.h"
@@ -58,6 +59,9 @@ class ChromeSystemResources : public invalidation::SystemResources {
std::set<invalidation::Closure*> posted_tasks_;
StateWriter* state_writer_;
+ // TODO(tim): Trying to debug bug crbug.com/64652.
+ const MessageLoop* created_on_loop_;
+
// If the scheduler has been started, inserts |task| into
// |posted_tasks_| and returns a Task* to post. Otherwise,
// immediately deletes |task| and returns NULL.
diff --git a/chrome/browser/sync/profile_sync_factory.h b/chrome/browser/sync/profile_sync_factory.h
index a4a2550..776b61d 100644
--- a/chrome/browser/sync/profile_sync_factory.h
+++ b/chrome/browser/sync/profile_sync_factory.h
@@ -77,6 +77,15 @@ class ProfileSyncFactory {
browser_sync::UnrecoverableErrorHandler* error_handler) = 0;
// Instantiates both a model associator and change processor for the
+ // autofill data type. The pointers in the return struct are owned
+ // by the caller.
+ virtual SyncComponents CreateAutofillProfileSyncComponents(
+ ProfileSyncService* profile_sync_service,
+ WebDatabase* web_database,
+ PersonalDataManager* personal_data,
+ browser_sync::UnrecoverableErrorHandler* error_handler) = 0;
+
+ // Instantiates both a model associator and change processor for the
// bookmark data type. The pointers in the return struct are owned
// by the caller.
virtual SyncComponents CreateBookmarkSyncComponents(
diff --git a/chrome/browser/sync/profile_sync_factory_impl.cc b/chrome/browser/sync/profile_sync_factory_impl.cc
index 3e3945e..07c1145 100644
--- a/chrome/browser/sync/profile_sync_factory_impl.cc
+++ b/chrome/browser/sync/profile_sync_factory_impl.cc
@@ -3,14 +3,16 @@
// found in the LICENSE file.
#include "base/command_line.h"
-#include "chrome/browser/defaults.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/glue/app_data_type_controller.h"
#include "chrome/browser/sync/glue/autofill_change_processor.h"
#include "chrome/browser/sync/glue/autofill_change_processor2.h"
#include "chrome/browser/sync/glue/autofill_data_type_controller.h"
#include "chrome/browser/sync/glue/autofill_model_associator.h"
#include "chrome/browser/sync/glue/autofill_model_associator2.h"
+#include "chrome/browser/sync/glue/autofill_profile_change_processor.h"
+#include "chrome/browser/sync/glue/autofill_profile_data_type_controller.h"
+#include "chrome/browser/sync/glue/autofill_profile_model_associator.h"
#include "chrome/browser/sync/glue/bookmark_change_processor.h"
#include "chrome/browser/sync/glue/bookmark_data_type_controller.h"
#include "chrome/browser/sync/glue/bookmark_model_associator.h"
@@ -39,13 +41,17 @@
#include "chrome/browser/sync/profile_sync_factory_impl.h"
#include "chrome/browser/webdata/web_data_service.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
using browser_sync::AppDataTypeController;
using browser_sync::AutofillChangeProcessor;
using browser_sync::AutofillChangeProcessor2;
+using browser_sync::AutofillProfileChangeProcessor;
using browser_sync::AutofillDataTypeController;
+using browser_sync::AutofillProfileDataTypeController;
using browser_sync::AutofillModelAssociator;
using browser_sync::AutofillModelAssociator2;
+using browser_sync::AutofillProfileModelAssociator;
using browser_sync::BookmarkChangeProcessor;
using browser_sync::BookmarkDataTypeController;
using browser_sync::BookmarkModelAssociator;
@@ -146,6 +152,12 @@ ProfileSyncService* ProfileSyncFactoryImpl::CreateProfileSyncService(
pss->RegisterDataTypeController(
new SessionDataTypeController(this, pss));
}
+
+ if (!command_line_->HasSwitch(switches::kDisableSyncAutofillProfile) &&
+ command_line_->HasSwitch(switches::kEnableSyncNewAutofill)) {
+ pss->RegisterDataTypeController(new AutofillProfileDataTypeController(
+ this, profile_, pss));
+ }
return pss;
}
@@ -203,6 +215,25 @@ ProfileSyncFactoryImpl::CreateAutofillSyncComponents(
}
ProfileSyncFactory::SyncComponents
+ProfileSyncFactoryImpl::CreateAutofillProfileSyncComponents(
+ ProfileSyncService* profile_sync_service,
+ WebDatabase* web_database,
+ PersonalDataManager* personal_data,
+ browser_sync::UnrecoverableErrorHandler* error_handler) {
+
+ AutofillProfileModelAssociator* model_associator =
+ new AutofillProfileModelAssociator(profile_sync_service,
+ web_database,
+ personal_data);
+ AutofillProfileChangeProcessor* change_processor =
+ new AutofillProfileChangeProcessor(model_associator,
+ web_database,
+ personal_data,
+ error_handler);
+ return SyncComponents(model_associator, change_processor);
+}
+
+ProfileSyncFactory::SyncComponents
ProfileSyncFactoryImpl::CreateBookmarkSyncComponents(
ProfileSyncService* profile_sync_service,
UnrecoverableErrorHandler* error_handler) {
diff --git a/chrome/browser/sync/profile_sync_factory_impl.h b/chrome/browser/sync/profile_sync_factory_impl.h
index 233f3f1..eb93f1c 100644
--- a/chrome/browser/sync/profile_sync_factory_impl.h
+++ b/chrome/browser/sync/profile_sync_factory_impl.h
@@ -37,6 +37,12 @@ class ProfileSyncFactoryImpl : public ProfileSyncFactory {
PersonalDataManager* personal_data,
browser_sync::UnrecoverableErrorHandler* error_handler);
+ virtual SyncComponents CreateAutofillProfileSyncComponents(
+ ProfileSyncService* profile_sync_service,
+ WebDatabase* web_database,
+ PersonalDataManager* personal_data,
+ browser_sync::UnrecoverableErrorHandler* error_handler);
+
virtual SyncComponents CreateBookmarkSyncComponents(
ProfileSyncService* profile_sync_service,
browser_sync::UnrecoverableErrorHandler* error_handler);
diff --git a/chrome/browser/sync/profile_sync_factory_mock.h b/chrome/browser/sync/profile_sync_factory_mock.h
index 18cc30c..f5210a0 100644
--- a/chrome/browser/sync/profile_sync_factory_mock.h
+++ b/chrome/browser/sync/profile_sync_factory_mock.h
@@ -38,6 +38,12 @@ class ProfileSyncFactoryMock : public ProfileSyncFactory {
WebDatabase* web_database,
PersonalDataManager* personal_data,
browser_sync::UnrecoverableErrorHandler* error_handler));
+ MOCK_METHOD4(CreateAutofillProfileSyncComponents,
+ SyncComponents(
+ ProfileSyncService* profile_sync_service,
+ WebDatabase* web_database,
+ PersonalDataManager* personal_data,
+ browser_sync::UnrecoverableErrorHandler* error_handler));
MOCK_METHOD2(CreateBookmarkSyncComponents,
SyncComponents(ProfileSyncService* profile_sync_service,
browser_sync::UnrecoverableErrorHandler* error_handler));
diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc
index b8d98c8..a3da689 100644
--- a/chrome/browser/sync/profile_sync_service.cc
+++ b/chrome/browser/sync/profile_sync_service.cc
@@ -19,12 +19,12 @@
#include "base/string_util.h"
#include "base/task.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/history/history_types.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/net/gaia/token_service.h"
+#include "chrome/browser/sync/glue/autofill_profile_data_type_controller.h"
#include "chrome/browser/sync/glue/change_processor.h"
#include "chrome/browser/sync/glue/data_type_controller.h"
#include "chrome/browser/sync/glue/data_type_manager.h"
@@ -35,7 +35,6 @@
#include "chrome/common/chrome_switches.h"
#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/notification_details.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
@@ -199,7 +198,6 @@ void ProfileSyncService::Initialize() {
token_migrator_->TryMigration();
}
}
-
}
void ProfileSyncService::RegisterAuthNotifications() {
@@ -369,6 +367,9 @@ void ProfileSyncService::RegisterPreferences() {
enable_by_default);
pref_service->RegisterBooleanPref(prefs::kSyncManaged, false);
pref_service->RegisterStringPref(prefs::kEncryptionBootstrapToken, "");
+
+ pref_service->RegisterBooleanPref(prefs::kSyncAutofillProfile,
+ enable_by_default);
}
void ProfileSyncService::ClearPreferences() {
@@ -551,6 +552,9 @@ const char* ProfileSyncService::GetPrefNameForDataType(
return prefs::kSyncPreferences;
case syncable::AUTOFILL:
return prefs::kSyncAutofill;
+ case syncable::AUTOFILL_PROFILE:
+ return prefs::kSyncAutofillProfile;
+ break;
case syncable::THEMES:
return prefs::kSyncThemes;
case syncable::TYPED_URLS:
@@ -772,6 +776,10 @@ std::string ProfileSyncService::BuildSyncStatusSummaryText(
}
}
+bool ProfileSyncService::unrecoverable_error_detected() const {
+ return unrecoverable_error_detected_;
+}
+
string16 ProfileSyncService::GetLastSyncedTimeString() const {
if (last_synced_time_.is_null())
return l10n_util::GetStringUTF16(IDS_SYNC_TIME_NEVER);
@@ -880,6 +888,10 @@ void ProfileSyncService::ChangePreferredDataTypes(
continue;
profile_->GetPrefs()->SetBoolean(pref_name,
preferred_types.count(model_type) != 0);
+ if (syncable::AUTOFILL == model_type) {
+ profile_->GetPrefs()->SetBoolean(prefs::kSyncAutofillProfile,
+ preferred_types.count(model_type) != 0);
+ }
}
// If we haven't initialized yet, don't configure the DTM as it could cause
@@ -891,23 +903,33 @@ void ProfileSyncService::ChangePreferredDataTypes(
void ProfileSyncService::GetPreferredDataTypes(
syncable::ModelTypeSet* preferred_types) const {
preferred_types->clear();
-
- // Filter out any datatypes which aren't registered, or for which
- // the preference can't be read.
- syncable::ModelTypeSet registered_types;
- GetRegisteredDataTypes(&registered_types);
if (profile_->GetPrefs()->GetBoolean(prefs::kKeepEverythingSynced)) {
- *preferred_types = registered_types;
+ GetRegisteredDataTypes(preferred_types);
} else {
+ // Filter out any datatypes which aren't registered, or for which
+ // the preference can't be read.
+ syncable::ModelTypeSet registered_types;
+ GetRegisteredDataTypes(&registered_types);
for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) {
syncable::ModelType model_type = syncable::ModelTypeFromInt(i);
if (!registered_types.count(model_type))
continue;
+ if (model_type == syncable::AUTOFILL_PROFILE)
+ continue;
const char* pref_name = GetPrefNameForDataType(model_type);
if (!pref_name)
continue;
- if (profile_->GetPrefs()->GetBoolean(pref_name))
+
+ // We are trying to group autofill_profile tag with the same
+ // enabled/disabled state as autofill. Because the UI only shows autofill.
+ if (profile_->GetPrefs()->GetBoolean(pref_name)) {
preferred_types->insert(model_type);
+ if (model_type == syncable::AUTOFILL) {
+ if (!registered_types.count(syncable::AUTOFILL_PROFILE))
+ continue;
+ preferred_types->insert(syncable::AUTOFILL_PROFILE);
+ }
+ }
}
}
}
diff --git a/chrome/browser/sync/profile_sync_service.h b/chrome/browser/sync/profile_sync_service.h
index c4d8efd..19583b6 100644
--- a/chrome/browser/sync/profile_sync_service.h
+++ b/chrome/browser/sync/profile_sync_service.h
@@ -233,9 +233,7 @@ class ProfileSyncService : public browser_sync::SyncFrontend,
// TODO(timsteele): What happens if the bookmark model is loaded, a change
// takes place, and the backend isn't initialized yet?
bool sync_initialized() const { return backend_initialized_; }
- virtual bool unrecoverable_error_detected() const {
- return unrecoverable_error_detected_;
- }
+ virtual bool unrecoverable_error_detected() const;
const std::string& unrecoverable_error_message() {
return unrecoverable_error_message_;
}
diff --git a/chrome/browser/sync/profile_sync_service_harness.cc b/chrome/browser/sync/profile_sync_service_harness.cc
index d981fd8..d275147 100644
--- a/chrome/browser/sync/profile_sync_service_harness.cc
+++ b/chrome/browser/sync/profile_sync_service_harness.cc
@@ -3,14 +3,12 @@
// found in the LICENSE file.
#include "base/message_loop.h"
-#include "chrome/browser/defaults.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/net/gaia/token_service.h"
#include "chrome/browser/sync/glue/sync_backend_host.h"
#include "chrome/browser/sync/profile_sync_service_harness.h"
#include "chrome/browser/sync/sessions/session_state.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/net/gaia/google_service_auth_error.h"
@@ -96,7 +94,6 @@ ProfileSyncServiceHarness::ProfileSyncServiceHarness(
min_timestamp_needed_(kMinTimestampNeededNone),
username_(username),
password_(password),
- passphrase_acceptance_counter_(0),
id_(id) {
if (IsSyncAlreadySetup()) {
service_ = profile_->GetProfileSyncService();
@@ -134,16 +131,6 @@ bool ProfileSyncServiceHarness::SetupSync() {
return SetupSync(synced_datatypes);
}
-void ProfileSyncServiceHarness::StartObservingPassphraseEvents() {
- // Prime the counter to account for the implicit set passphrase due to
- // gaia login.
- passphrase_acceptance_counter_--;
- registrar_.Add(this, NotificationType::SYNC_PASSPHRASE_ACCEPTED,
- Source<browser_sync::SyncBackendHost>(service_->backend()));
- registrar_.Add(this, NotificationType::SYNC_PASSPHRASE_REQUIRED,
- Source<browser_sync::SyncBackendHost>(service_->backend()));
-}
-
bool ProfileSyncServiceHarness::SetupSync(
const syncable::ModelTypeSet& synced_datatypes) {
// Initialize the sync client's profile sync service object.
@@ -186,10 +173,6 @@ bool ProfileSyncServiceHarness::SetupSync(
return false;
}
- DCHECK(service()->observed_passphrase_required());
- if (id_ == 0)
- DCHECK(!service()->passphrase_required_for_decryption());
-
// Wait for initial gaia passphrase to be accepted.
DCHECK_EQ(wait_state_, WAITING_FOR_PASSPHRASE_ACCEPTED);
if (!AwaitStatusChangeWithTimeout(kLiveSyncOperationTimeoutMs,
@@ -232,21 +215,26 @@ bool ProfileSyncServiceHarness::RunStateChangeMachine() {
case WAITING_FOR_ON_BACKEND_INITIALIZED: {
LogClientInfo("WAITING_FOR_ON_BACKEND_INITIALIZED");
if (service()->sync_initialized()) {
- // The sync backend is initialized. Watch for passphrase events.
- StartObservingPassphraseEvents();
+ // The sync backend is initialized. We now wait for passphrase events.
SignalStateCompleteWithNextState(WAITING_FOR_PASSPHRASE_REQUIRED);
}
break;
}
case WAITING_FOR_PASSPHRASE_REQUIRED: {
LogClientInfo("WAITING_FOR_PASSPHRASE_REQUIRED");
- if (service_->observed_passphrase_required())
+ if (service()->observed_passphrase_required()) {
+ // Special case when the first client signs in to sync.
+ if (id_ == 0)
+ DCHECK(!service()->passphrase_required_for_decryption());
+ // The SYNC_PASSPHRASE_REQUIRED notification has been seen.
SignalStateCompleteWithNextState(WAITING_FOR_PASSPHRASE_ACCEPTED);
+ }
break;
}
case WAITING_FOR_PASSPHRASE_ACCEPTED: {
LogClientInfo("WAITING_FOR_PASSPHRASE_ACCEPTED");
- if (passphrase_acceptance_counter_ >= 0)
+ if (service()->ShouldPushChanges())
+ // The SYNC_PASSPHRASE_ACCEPTED notification has been seen.
SignalStateCompleteWithNextState(WAITING_FOR_INITIAL_SYNC);
break;
}
@@ -320,25 +308,11 @@ bool ProfileSyncServiceHarness::AwaitPassphraseAccepted() {
LOG(ERROR) << "Sync disabled for Client " << id_ << ".";
return false;
}
- passphrase_acceptance_counter_--;
- if (passphrase_acceptance_counter_ >= 0)
- return true;
wait_state_ = WAITING_FOR_PASSPHRASE_ACCEPTED;
return AwaitStatusChangeWithTimeout(kLiveSyncOperationTimeoutMs,
"Waiting for passphrase accepted.");
}
-void ProfileSyncServiceHarness::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- if (NotificationType::SYNC_PASSPHRASE_ACCEPTED == type.value) {
- passphrase_acceptance_counter_++;
- RunStateChangeMachine();
- } else if (NotificationType::SYNC_PASSPHRASE_REQUIRED == type.value) {
- RunStateChangeMachine();
- }
-}
-
bool ProfileSyncServiceHarness::AwaitSyncCycleCompletion(
const std::string& reason) {
LogClientInfo("AwaitSyncCycleCompletion");
@@ -359,7 +333,7 @@ bool ProfileSyncServiceHarness::AwaitSyncCycleCompletion(
if (wait_state_ == FULLY_SYNCED) {
// Client is online; sync was successful.
return true;
- } else if (wait_state_ == SERVER_UNREACHABLE){
+ } else if (wait_state_ == SERVER_UNREACHABLE) {
// Client is offline; sync was unsuccessful.
return false;
} else {
diff --git a/chrome/browser/sync/profile_sync_service_harness.h b/chrome/browser/sync/profile_sync_service_harness.h
index 1eb7dec..e3047af 100644
--- a/chrome/browser/sync/profile_sync_service_harness.h
+++ b/chrome/browser/sync/profile_sync_service_harness.h
@@ -11,8 +11,6 @@
#include "base/time.h"
#include "chrome/browser/sync/profile_sync_service.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
using browser_sync::sessions::SyncSessionSnapshot;
@@ -23,8 +21,7 @@ class Profile;
// profile passed to it on construction and automates certain things like setup
// and authentication. It provides ways to "wait" adequate periods of time for
// several clients to get to the same state.
-class ProfileSyncServiceHarness : public ProfileSyncServiceObserver,
- public NotificationObserver {
+class ProfileSyncServiceHarness : public ProfileSyncServiceObserver {
public:
ProfileSyncServiceHarness(Profile* profile,
const std::string& username,
@@ -57,11 +54,6 @@ class ProfileSyncServiceHarness : public ProfileSyncServiceObserver,
// ProfileSyncServiceObserver implementation.
virtual void OnStateChanged();
- // NotificationObserver implementation.
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
// Blocks the caller until this harness has completed a single sync cycle
// since the previous one. Returns true if a sync cycle has completed.
bool AwaitSyncCycleCompletion(const std::string& reason);
@@ -183,8 +175,6 @@ class ProfileSyncServiceHarness : public ProfileSyncServiceObserver,
// Returns the new value of |last_timestamp_|.
int64 GetUpdatedTimestamp();
- void StartObservingPassphraseEvents();
-
WaitState wait_state_;
Profile* profile_;
@@ -204,12 +194,6 @@ class ProfileSyncServiceHarness : public ProfileSyncServiceObserver,
std::string username_;
std::string password_;
- // A counter to track the number of await passphrase requests versus
- // actual acceptances. Can go negative if #requests > #acceptances.
- int passphrase_acceptance_counter_;
-
- NotificationRegistrar registrar_;
-
// Client ID, used for logging purposes.
int id_;
diff --git a/chrome/browser/sync/profile_sync_service_mock.h b/chrome/browser/sync/profile_sync_service_mock.h
index dea5482..a338631 100644
--- a/chrome/browser/sync/profile_sync_service_mock.h
+++ b/chrome/browser/sync/profile_sync_service_mock.h
@@ -7,8 +7,8 @@
#pragma once
#include <string>
+
#include "base/string16.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/sync/glue/change_processor.h"
#include "chrome/browser/sync/glue/data_type_controller.h"
#include "chrome/browser/sync/profile_sync_service.h"
diff --git a/chrome/browser/sync/profile_sync_service_unittest.cc b/chrome/browser/sync/profile_sync_service_unittest.cc
index 0088829..74cfc24 100644
--- a/chrome/browser/sync/profile_sync_service_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_unittest.cc
@@ -17,7 +17,7 @@
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/net/gaia/token_service.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/change_processor.h"
#include "chrome/browser/sync/glue/bookmark_change_processor.h"
diff --git a/chrome/browser/sync/profile_sync_test_util.h b/chrome/browser/sync/profile_sync_test_util.h
index aa8584e..f6e66ac 100644
--- a/chrome/browser/sync/profile_sync_test_util.h
+++ b/chrome/browser/sync/profile_sync_test_util.h
@@ -17,7 +17,6 @@
#include "base/waitable_event.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/webdata/web_database.h"
#include "chrome/browser/sync/glue/bookmark_change_processor.h"
#include "chrome/browser/sync/glue/bookmark_data_type_controller.h"
@@ -108,8 +107,8 @@ class ProfileSyncServiceObserverMock : public ProfileSyncServiceObserver {
class ThreadNotificationService
: public base::RefCountedThreadSafe<ThreadNotificationService> {
public:
- explicit ThreadNotificationService(base::Thread* notification_thread)
- : done_event_(false, false),
+ explicit ThreadNotificationService(base::Thread* notification_thread)
+ : done_event_(false, false),
notification_thread_(notification_thread) {}
void Init() {
diff --git a/chrome/browser/sync/resources/configure.html b/chrome/browser/sync/resources/configure.html
index 15fe406..90a3491 100644
--- a/chrome/browser/sync/resources/configure.html
+++ b/chrome/browser/sync/resources/configure.html
@@ -48,7 +48,11 @@ form {
margin: 10px 15px;
}
.sync-config-tabstrip {
- display: none;
+ border-bottom: 1px solid gray;
+ height: 25px;
+ margin-bottom: 10px;
+ padding-top: 10px;
+ background-color: #DDD;
}
.sync-config-tab-active {
background-color: white;
@@ -128,7 +132,7 @@ form {
text-align: center;
padding: 1px 10px;
background-color: #eeb939;
- -webkit-border-radius: 4px;
+ border-radius: 4px;
font-weight: bold;
}
.sync-error-hide {
diff --git a/chrome/browser/sync/resources/gaia_login.html b/chrome/browser/sync/resources/gaia_login.html
index bd19b34..2ae8727 100644
--- a/chrome/browser/sync/resources/gaia_login.html
+++ b/chrome/browser/sync/resources/gaia_login.html
@@ -99,7 +99,7 @@
text-align: center;
padding: 4px 10px;
background-color: #eeb939;
- -webkit-border-radius: 4px;
+ border-radius: 4px;
font-weight: bold;
font-size: 11pt;
}
diff --git a/chrome/browser/sync/signin_manager.cc b/chrome/browser/sync/signin_manager.cc
index 1a88497..43a6e44 100644
--- a/chrome/browser/sync/signin_manager.cc
+++ b/chrome/browser/sync/signin_manager.cc
@@ -7,7 +7,7 @@
#include "base/string_util.h"
#include "chrome/browser/net/gaia/token_service.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/net/gaia/gaia_constants.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
diff --git a/chrome/browser/sync/sync_setup_flow.cc b/chrome/browser/sync/sync_setup_flow.cc
index f9f9250..a6dd5ec 100644
--- a/chrome/browser/sync/sync_setup_flow.cc
+++ b/chrome/browser/sync/sync_setup_flow.cc
@@ -12,18 +12,18 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
-#if defined(OS_MACOSX)
-#include "chrome/browser/cocoa/html_dialog_window_controller_cppsafe.h"
-#endif
#include "chrome/browser/dom_ui/dom_ui_util.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
+#if defined(OS_MACOSX)
+#include "chrome/browser/ui/cocoa/html_dialog_window_controller_cppsafe.h"
+#endif
#include "chrome/common/net/gaia/google_service_auth_error.h"
#include "chrome/common/pref_names.h"
#include "gfx/font.h"
@@ -345,6 +345,10 @@ void SyncSetupFlow::GetDialogSize(gfx::Size* size) const {
#endif
}
+std::string SyncSetupFlow::GetDialogArgs() const {
+ return dialog_start_args_;
+}
+
// A callback to notify the delegate that the dialog closed.
void SyncSetupFlow::OnDialogClosed(const std::string& json_retval) {
DCHECK(json_retval.empty());
@@ -385,6 +389,18 @@ void SyncSetupFlow::OnDialogClosed(const std::string& json_retval) {
delete this;
}
+std::wstring SyncSetupFlow::GetDialogTitle() const {
+ return l10n_util::GetString(IDS_SYNC_MY_BOOKMARKS_LABEL);
+}
+
+bool SyncSetupFlow::IsDialogModal() const {
+ return false;
+}
+
+bool SyncSetupFlow::ShouldShowDialogTitle() const {
+ return true;
+}
+
// static
void SyncSetupFlow::GetArgsForGaiaLogin(const ProfileSyncService* service,
DictionaryValue* args) {
@@ -596,6 +612,10 @@ void SyncSetupFlow::Focus() {
#endif // defined(OS_MACOSX)
}
+GURL SyncSetupFlow::GetDialogContentURL() const {
+ return GURL("chrome://syncresources/setup");
+}
+
// static
SyncSetupFlow* SyncSetupFlow::Run(ProfileSyncService* service,
SyncSetupFlowContainer* container,
diff --git a/chrome/browser/sync/sync_setup_flow.h b/chrome/browser/sync/sync_setup_flow.h
index 7d64402..8bfc443 100644
--- a/chrome/browser/sync/sync_setup_flow.h
+++ b/chrome/browser/sync/sync_setup_flow.h
@@ -72,9 +72,7 @@ class SyncSetupFlow : public HtmlDialogUIDelegate {
// HtmlDialogUIDelegate implementation.
// Get the HTML file path for the content to load in the dialog.
- virtual GURL GetDialogContentURL() const {
- return GURL("chrome://syncresources/setup");
- }
+ virtual GURL GetDialogContentURL() const;
// HtmlDialogUIDelegate implementation.
virtual void GetDOMMessageHandlers(
@@ -86,27 +84,21 @@ class SyncSetupFlow : public HtmlDialogUIDelegate {
// HtmlDialogUIDelegate implementation.
// Gets the JSON string input to use when opening the dialog.
- virtual std::string GetDialogArgs() const {
- return dialog_start_args_;
- }
+ virtual std::string GetDialogArgs() const;
// HtmlDialogUIDelegate implementation.
// A callback to notify the delegate that the dialog closed.
virtual void OnDialogClosed(const std::string& json_retval);
// HtmlDialogUIDelegate implementation.
- virtual void OnCloseContents(TabContents* source, bool* out_close_dialog) { }
+ virtual void OnCloseContents(TabContents* source, bool* out_close_dialog) {}
// HtmlDialogUIDelegate implementation.
- virtual std::wstring GetDialogTitle() const {
- return l10n_util::GetString(IDS_SYNC_MY_BOOKMARKS_LABEL);
- }
+ virtual std::wstring GetDialogTitle() const;
// HtmlDialogUIDelegate implementation.
- virtual bool IsDialogModal() const {
- return false;
- }
- virtual bool ShouldShowDialogTitle() const { return true; }
+ virtual bool IsDialogModal() const;
+ virtual bool ShouldShowDialogTitle() const;
void OnUserSubmittedAuth(const std::string& username,
const std::string& password,
diff --git a/chrome/browser/sync/sync_setup_wizard.cc b/chrome/browser/sync/sync_setup_wizard.cc
index 147e112..e80afe0 100644
--- a/chrome/browser/sync/sync_setup_wizard.cc
+++ b/chrome/browser/sync/sync_setup_wizard.cc
@@ -11,7 +11,7 @@
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/sync_setup_flow.h"
#include "chrome/common/jstemplate_builder.h"
@@ -215,7 +215,7 @@ SyncSetupWizard::SyncSetupWizard(ProfileSyncService* service)
SyncResourcesSource* sync_source = new SyncResourcesSource();
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- NewRunnableMethod(Singleton<ChromeURLDataManager>::get(),
+ NewRunnableMethod(ChromeURLDataManager::GetInstance(),
&ChromeURLDataManager::AddDataSource,
make_scoped_refptr(sync_source)));
}
diff --git a/chrome/browser/sync/sync_ui_util.cc b/chrome/browser/sync/sync_ui_util.cc
index 98b6046..27fdb9a 100644
--- a/chrome/browser/sync/sync_ui_util.cc
+++ b/chrome/browser/sync/sync_ui_util.cc
@@ -6,10 +6,12 @@
#include "app/l10n_util.h"
#include "base/i18n/number_formatting.h"
+#include "base/i18n/time_formatting.h"
+#include "base/string_util.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/profile_sync_service.h"
-#include "chrome/browser/options_window.h"
+#include "chrome/browser/ui/options/options_window.h"
#include "chrome/common/net/gaia/google_service_auth_error.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
@@ -215,6 +217,15 @@ void AddIntSyncDetail(ListValue* details, const std::string& stat_name,
details->Append(val);
}
+string16 ConstructTime(int64 time_in_int) {
+ base::Time time = base::Time::FromInternalValue(time_in_int);
+
+ // If time is null the format function returns a time in 1969.
+ if (time.is_null())
+ return string16();
+ return base::TimeFormatFriendlyDateAndTime(time);
+}
+
std::string MakeSyncAuthErrorText(
const GoogleServiceAuthError::State& state) {
switch (state) {
@@ -323,6 +334,28 @@ void ConstructAboutInformation(ProfileSyncService* service,
val->SetString("group", ModelSafeGroupToString(it->second));
routing_info->Append(val);
}
+
+ sync_ui_util::AddBoolSyncDetail(details,
+ "Autofill Migrated",
+ service->backend()->GetAutofillMigrationState() ==
+ syncable::MIGRATED);
+ syncable::AutofillMigrationDebugInfo info =
+ service->backend()->GetAutofillMigrationDebugInfo();
+
+ sync_ui_util::AddIntSyncDetail(details,
+ "Bookmarks created during migration",
+ info.bookmarks_added_during_migration);
+ sync_ui_util::AddIntSyncDetail(details,
+ "Autofill entries created during migration",
+ info.autofill_entries_added_during_migration);
+ sync_ui_util::AddIntSyncDetail(details,
+ "Autofill Profiles created during migration",
+ info.autofill_profile_added_during_migration);
+
+ DictionaryValue* val = new DictionaryValue;
+ val->SetString("stat_name", "Autofill Migration Time");
+ val->SetString("stat_value", ConstructTime(info.autofill_migration_time));
+ details->Append(val);
}
}
}
diff --git a/chrome/browser/sync/sync_ui_util_mac.mm b/chrome/browser/sync/sync_ui_util_mac.mm
index 8aace0f..f65f2a0 100644
--- a/chrome/browser/sync/sync_ui_util_mac.mm
+++ b/chrome/browser/sync/sync_ui_util_mac.mm
@@ -8,7 +8,7 @@
#include "app/l10n_util_mac.h"
#include "base/logging.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/sync_ui_util.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/sync/sync_ui_util_mac_unittest.mm b/chrome/browser/sync/sync_ui_util_mac_unittest.mm
index 96f72e7..ef5e32f 100644
--- a/chrome/browser/sync/sync_ui_util_mac_unittest.mm
+++ b/chrome/browser/sync/sync_ui_util_mac_unittest.mm
@@ -9,7 +9,7 @@
#include "app/l10n_util_mac.h"
#include "base/scoped_nsobject.h"
#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
#include "grit/generated_resources.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/sync/syncable/autofill_migration.h b/chrome/browser/sync/syncable/autofill_migration.h
new file mode 100644
index 0000000..81a16be
--- /dev/null
+++ b/chrome/browser/sync/syncable/autofill_migration.h
@@ -0,0 +1,49 @@
+// 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.
+
+#ifndef CHROME_BROWSER_SYNC_SYNCABLE_AUTOFILL_MIGRATION_H_
+#define CHROME_BROWSER_SYNC_SYNCABLE_AUTOFILL_MIGRATION_H_
+#pragma once
+
+namespace syncable {
+enum AutofillMigrationState {
+
+ // Indicates the default state. After first run the state would change to
+ // one of the following.
+ NOT_DETERMINED,
+
+ // The autofill profile is not migrated. Current sync should migrate the data
+ // by syncing down the old autofill and syncing profiles back up to the server
+ // as new autofill.
+ NOT_MIGRATED,
+
+ // We have migrated the autofill profile data. From now on autofill and
+ // autofill profiles are 2 seperate data types.
+ MIGRATED,
+
+ // The autofill datatype is being synced new.(either because this is a new
+ // client or the user just enabled them for syncing). In which case if
+ // someother client had migrated the data already then our new state after
+ // first sync would be MIGRATED. Else we would be responsible for migrating
+ // the data.
+ INSUFFICIENT_INFO_TO_DETERMINE
+};
+
+struct AutofillMigrationDebugInfo {
+ enum PropertyToSet {
+ MIGRATION_TIME,
+ BOOKMARK_ADDED,
+ ENTRIES_ADDED,
+ PROFILES_ADDED
+ };
+ int64 autofill_migration_time;
+ int bookmarks_added_during_migration;
+ int autofill_entries_added_during_migration;
+ int autofill_profile_added_during_migration;
+};
+
+} // namespace syncable
+
+#endif // CHROME_BROWSER_SYNC_SYNCABLE_AUTOFILL_MIGRATION_H_
+
diff --git a/chrome/browser/sync/syncable/directory_backing_store.cc b/chrome/browser/sync/syncable/directory_backing_store.cc
index c0036d3..feefd91 100644
--- a/chrome/browser/sync/syncable/directory_backing_store.cc
+++ b/chrome/browser/sync/syncable/directory_backing_store.cc
@@ -44,7 +44,7 @@ static const string::size_type kUpdateStatementBufferSize = 2048;
// Increment this version whenever updating DB tables.
extern const int32 kCurrentDBVersion; // Global visibility for our unittest.
-const int32 kCurrentDBVersion = 73;
+const int32 kCurrentDBVersion = 74;
namespace {
@@ -379,11 +379,28 @@ bool DirectoryBackingStore::SaveChanges(
update.prepare(dbhandle, "UPDATE share_info "
"SET store_birthday = ?, "
"next_id = ?, "
- "notification_state = ?");
+ "notification_state = ?, "
+ "autofill_migration_state = ?, "
+ "bookmarks_added_during_autofill_migration = ?, "
+ "autofill_migration_time = ?, "
+ "autofill_entries_added_during_migration = ?, "
+ "autofill_profiles_added_during_migration = ? ");
+
+ const syncable::AutofillMigrationDebugInfo& debug_info =
+ info.autofill_migration_debug_info;
update.bind_string(0, info.store_birthday);
update.bind_int64(1, info.next_id);
update.bind_blob(2, info.notification_state.data(),
info.notification_state.size());
+ update.bind_int(3, info.autofill_migration_state);
+ update.bind_int(4,
+ debug_info.bookmarks_added_during_migration);
+ update.bind_int64(5,
+ debug_info.autofill_migration_time);
+ update.bind_int(6,
+ debug_info.autofill_entries_added_during_migration);
+ update.bind_int(7,
+ debug_info.autofill_profile_added_during_migration);
if (!(SQLITE_DONE == update.step() &&
SQLITE_OK == update.reset() &&
@@ -456,6 +473,11 @@ DirOpenResult DirectoryBackingStore::InitializeTables() {
version_on_disk = 73;
}
+ if (version_on_disk == 73) {
+ if (MigrateVersion73To74())
+ version_on_disk = 74;
+ }
+
// If one of the migrations requested it, drop columns that aren't current.
// It's only safe to do this after migrating all the way to the current
// version.
@@ -556,13 +578,30 @@ bool DirectoryBackingStore::LoadInfo(Directory::KernelLoadInfo* info) {
SQLStatement query;
query.prepare(load_dbhandle_,
"SELECT store_birthday, next_id, cache_guid, "
- "notification_state FROM share_info");
+ "notification_state, autofill_migration_state, "
+ "bookmarks_added_during_autofill_migration, "
+ "autofill_migration_time, "
+ "autofill_entries_added_during_migration, "
+ "autofill_profiles_added_during_migration "
+ "FROM share_info");
if (SQLITE_ROW != query.step())
return false;
info->kernel_info.store_birthday = query.column_string(0);
info->kernel_info.next_id = query.column_int64(1);
info->cache_guid = query.column_string(2);
query.column_blob_as_string(3, &info->kernel_info.notification_state);
+ info->kernel_info.autofill_migration_state =
+ static_cast<AutofillMigrationState> (query.column_int(4));
+ syncable::AutofillMigrationDebugInfo& debug_info =
+ info->kernel_info.autofill_migration_debug_info;
+ debug_info.bookmarks_added_during_migration =
+ query.column_int(5);
+ debug_info.autofill_migration_time =
+ query.column_int64(6);
+ debug_info.autofill_entries_added_during_migration =
+ query.column_int(7);
+ debug_info.autofill_profile_added_during_migration =
+ query.column_int(8);
}
{
SQLStatement query;
@@ -889,9 +928,9 @@ bool DirectoryBackingStore::MigrateVersion70To71() {
// Drop the columns from the old share_info table via a temp table.
const bool kCreateAsTempShareInfo = true;
- const bool kWithNotificationState = false;
+
int result =
- CreateShareInfoTable(kCreateAsTempShareInfo, kWithNotificationState);
+ CreateShareInfoTableVersion71(kCreateAsTempShareInfo);
if (result != SQLITE_DONE)
return false;
ExecQuery(load_dbhandle_,
@@ -926,6 +965,50 @@ bool DirectoryBackingStore::MigrateVersion72To73() {
return true;
}
+bool DirectoryBackingStore::MigrateVersion73To74() {
+ int result =
+ ExecQuery(load_dbhandle_,
+ "ALTER TABLE share_info ADD COLUMN autofill_migration_state "
+ "INT default 0");
+ if (result != SQLITE_DONE)
+ return false;
+
+ result = ExecQuery(load_dbhandle_,
+ "ALTER TABLE share_info ADD COLUMN "
+ "bookmarks_added_during_autofill_migration "
+ "INT default 0");
+
+ if (result != SQLITE_DONE)
+ return false;
+
+ result = ExecQuery(load_dbhandle_,
+ "ALTER TABLE share_info ADD COLUMN autofill_migration_time "
+ "INT default 0");
+
+ if (result != SQLITE_DONE)
+ return false;
+
+ result = ExecQuery(load_dbhandle_,
+ "ALTER TABLE share_info ADD COLUMN "
+ "autofill_entries_added_during_migration "
+ "INT default 0");
+
+ if (result != SQLITE_DONE)
+ return false;
+
+ result = ExecQuery(load_dbhandle_,
+ "ALTER TABLE share_info ADD COLUMN "
+ "autofill_profiles_added_during_migration "
+ "INT default 0");
+
+ if (result != SQLITE_DONE)
+ return false;
+
+ SetVersion(74);
+ return true;
+}
+
+
int DirectoryBackingStore::CreateTables() {
VLOG(1) << "First run, creating tables";
// Create two little tables share_version and share_info
@@ -945,9 +1028,8 @@ int DirectoryBackingStore::CreateTables() {
return result;
const bool kCreateAsTempShareInfo = false;
- const bool kWithNotificationState = true;
result =
- CreateShareInfoTable(kCreateAsTempShareInfo, kWithNotificationState);
+ CreateShareInfoTable(kCreateAsTempShareInfo);
if (result != SQLITE_DONE)
return result;
{
@@ -960,6 +1042,14 @@ int DirectoryBackingStore::CreateTables() {
"?, " // db_create_time
"-2, " // next_id
"?, " // cache_guid
+ "?, " // autofill_migration_state
+ "?, " // bookmarks_added
+ // _during_autofill_migration
+ "?, " // autofill_migration_time
+ "?, " // autofill_entries
+ // _added_during_migration
+ "?, " // autofill_profiles_added
+ // _during_migration
"?);"); // notification_state
statement.bind_string(0, dir_name_); // id
statement.bind_string(1, dir_name_); // name
@@ -967,7 +1057,12 @@ int DirectoryBackingStore::CreateTables() {
statement.bind_string(3, SYNC_ENGINE_VERSION_STRING); // db_create_version
statement.bind_int(4, static_cast<int32>(time(0))); // db_create_time
statement.bind_string(5, GenerateCacheGUID()); // cache_guid
- statement.bind_blob(6, NULL, 0); // notification_state
+ statement.bind_int(6, 0); // autofill_migration_state
+ statement.bind_int(7, 0); // autofill_migration_time
+ statement.bind_int(8, 0); // bookmarks_added_during_autofill_migration
+ statement.bind_int(9, 0); // autofill_entries_added_during_migration
+ statement.bind_int(10, 0); // autofill_profiles_added_during_migration
+ statement.bind_blob(11, NULL, 0); // notification_state
result = statement.step();
}
if (result != SQLITE_DONE)
@@ -1025,8 +1120,7 @@ int DirectoryBackingStore::CreateModelsTable() {
"initial_sync_ended BOOLEAN default 0)");
}
-int DirectoryBackingStore::CreateShareInfoTable(
- bool is_temporary, bool with_notification_state) {
+int DirectoryBackingStore::CreateShareInfoTable(bool is_temporary) {
const char* name = is_temporary ? "temp_share_info" : "share_info";
string query = "CREATE TABLE ";
query.append(name);
@@ -1040,12 +1134,34 @@ int DirectoryBackingStore::CreateShareInfoTable(
"db_create_version TEXT, "
"db_create_time INT, "
"next_id INT default -2, "
- "cache_guid TEXT");
- if (with_notification_state) {
- query.append(", notification_state BLOB");
- }
+ "cache_guid TEXT, "
+ "autofill_migration_state INT default 0, "
+ "bookmarks_added_during_autofill_migration INT default 0, "
+ "autofill_migration_time INT default 0, "
+ "autofill_entries_added_during_migration INT default 0, "
+ "autofill_profiles_added_during_migration INT default 0 ");
+
+ query.append(", notification_state BLOB");
query.append(")");
return ExecQuery(load_dbhandle_, query.c_str());
}
+int DirectoryBackingStore::CreateShareInfoTableVersion71(
+ bool is_temporary) {
+ const char* name = is_temporary ? "temp_share_info" : "share_info";
+ string query = "CREATE TABLE ";
+ query.append(name);
+ // This is the current schema for the ShareInfo table, from version 71
+ // onward. If you change the schema, you'll probably want to double-check
+ // the use of this function in the v70-v71 migration.
+ query.append(" ("
+ "id TEXT primary key, "
+ "name TEXT, "
+ "store_birthday TEXT, "
+ "db_create_version TEXT, "
+ "db_create_time INT, "
+ "next_id INT default -2, "
+ "cache_guid TEXT )");
+ return ExecQuery(load_dbhandle_, query.c_str());
+}
} // namespace syncable
diff --git a/chrome/browser/sync/syncable/directory_backing_store.h b/chrome/browser/sync/syncable/directory_backing_store.h
index 58b93d3..e7ded8d 100644
--- a/chrome/browser/sync/syncable/directory_backing_store.h
+++ b/chrome/browser/sync/syncable/directory_backing_store.h
@@ -80,6 +80,7 @@ class DirectoryBackingStore {
FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, MigrateVersion70To71);
FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, MigrateVersion71To72);
FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, MigrateVersion72To73);
+ FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, MigrateVersion73To74);
FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, ModelTypeIds);
FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, Corruption);
FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, DeleteEntries);
@@ -92,10 +93,11 @@ class DirectoryBackingStore {
int CreateTables();
// Create 'share_info' or 'temp_share_info' depending on value of
- // is_temporary. If with_notification_state is true, creates the
- // table with the notification_state column. Returns an sqlite
+ // is_temporary. Returns an sqlite
// return code, SQLITE_DONE on success.
- int CreateShareInfoTable(bool is_temporary, bool with_notification_state);
+ int CreateShareInfoTable(bool is_temporary);
+
+ int CreateShareInfoTableVersion71(bool is_temporary);
// Create 'metas' or 'temp_metas' depending on value of is_temporary.
// Returns an sqlite return code, SQLITE_DONE on success.
int CreateMetasTable(bool is_temporary);
@@ -172,6 +174,7 @@ class DirectoryBackingStore {
bool MigrateVersion70To71();
bool MigrateVersion71To72();
bool MigrateVersion72To73();
+ bool MigrateVersion73To74();
// The handle to our sqlite on-disk store for initialization and loading, and
// for saving changes periodically via SaveChanges, respectively.
diff --git a/chrome/browser/sync/syncable/directory_backing_store_unittest.cc b/chrome/browser/sync/syncable/directory_backing_store_unittest.cc
index 214690c..d80200f 100644
--- a/chrome/browser/sync/syncable/directory_backing_store_unittest.cc
+++ b/chrome/browser/sync/syncable/directory_backing_store_unittest.cc
@@ -48,6 +48,7 @@ class MigrationTest : public testing::TestWithParam<int> {
void SetUpVersion70Database();
void SetUpVersion71Database();
void SetUpVersion72Database();
+ void SetUpVersion73Database();
void SetUpCurrentDatabaseAndCheckVersion() {
SetUpVersion70Database(); // Prepopulates data.
@@ -643,7 +644,7 @@ void MigrationTest::SetUpVersion72Database() {
ASSERT_TRUE(connection.BeginTransaction());
ASSERT_TRUE(connection.Execute(
"CREATE TABLE share_version (id VARCHAR(128) primary key, data INT);"
- "INSERT INTO 'share_version' VALUES('nick@chromium.org',71);"
+ "INSERT INTO 'share_version' VALUES('nick@chromium.org',72);"
"CREATE TABLE metas(metahandle bigint primary key ON CONFLICT FAIL,"
"base_version bigint default -1,server_version bigint default 0,"
"mtime bigint default 0,server_mtime bigint default 0,ctime bigint "
@@ -741,6 +742,111 @@ void MigrationTest::SetUpVersion72Database() {
ASSERT_TRUE(connection.CommitTransaction());
}
+void MigrationTest::SetUpVersion73Database() {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(connection.BeginTransaction());
+ ASSERT_TRUE(connection.Execute(
+ "CREATE TABLE share_version (id VARCHAR(128) primary key, data INT);"
+ "INSERT INTO 'share_version' VALUES('nick@chromium.org',73);"
+ "CREATE TABLE metas(metahandle bigint primary key ON CONFLICT FAIL,"
+ "base_version bigint default -1,server_version bigint default 0,"
+ "mtime bigint default 0,server_mtime bigint default 0,ctime bigint "
+ "default 0,server_ctime bigint default 0,server_position_in_parent "
+ "bigint default 0,local_external_id bigint default 0,id varchar(255) "
+ "default 'r',parent_id varchar(255) default 'r',server_parent_id "
+ "varchar(255) default 'r',prev_id varchar(255) default 'r',next_id "
+ "varchar(255) default 'r',is_unsynced bit default 0,"
+ "is_unapplied_update bit default 0,is_del bit default 0,is_dir bit "
+ "default 0,server_is_dir bit default 0,server_is_del bit default 0,"
+ "non_unique_name varchar,server_non_unique_name varchar(255),"
+ "unique_server_tag varchar,unique_client_tag varchar,specifics blob,"
+ "server_specifics blob);"
+ "INSERT INTO 'metas' VALUES(1,-1,0,129079956640320000,0,"
+ "129079956640320000,0,0,0,'r','r','r','r','r',0,0,0,1,0,0,NULL,NULL,"
+ "NULL,NULL,X'',X'');"
+ "INSERT INTO 'metas' VALUES(2,669,669,128976886618480000,"
+ "128976886618480000,128976886618480000,128976886618480000,-2097152,4,"
+ "'s_ID_2','s_ID_9','s_ID_9','s_ID_2','s_ID_2',0,0,1,0,0,1,"
+ "'Deleted Item','Deleted Item',NULL,NULL,X'C28810220A16687474703A2F2F"
+ "7777772E676F6F676C652E636F6D2F12084141534741534741',X'C28810260A1768"
+ "7474703A2F2F7777772E676F6F676C652E636F6D2F32120B41534144474144474144"
+ "47');"
+ "INSERT INTO 'metas' VALUES(4,681,681,129002163642690000,"
+ "129002163642690000,129002163642690000,129002163642690000,-3145728,3,"
+ "'s_ID_4','s_ID_9','s_ID_9','s_ID_4','s_ID_4',0,0,1,0,0,1,"
+ "'Welcome to Chromium','Welcome to Chromium',NULL,NULL,X'C28810350A31"
+ "687474703A2F2F7777772E676F6F676C652E636F6D2F6368726F6D652F696E746C2F"
+ "656E2F77656C636F6D652E68746D6C1200',X'C28810350A31687474703A2F2F7777"
+ "772E676F6F676C652E636F6D2F6368726F6D652F696E746C2F656E2F77656C636F6D"
+ "652E68746D6C1200');"
+ "INSERT INTO 'metas' VALUES(5,677,677,129001555500000000,"
+ "129001555500000000,129001555500000000,129001555500000000,1048576,7,"
+ "'s_ID_5','s_ID_9','s_ID_9','s_ID_5','s_ID_5',0,0,1,0,0,1,'Google',"
+ "'Google',NULL,NULL,X'C28810220A16687474703A2F2F7777772E676F6F676C652"
+ "E636F6D2F12084147415347415347',X'C28810220A16687474703A2F2F7777772E6"
+ "76F6F676C652E636F6D2F12084147464447415347');"
+ "INSERT INTO 'metas' VALUES(6,694,694,129053976170000000,"
+ "129053976170000000,129053976170000000,129053976170000000,-4194304,6,"
+ "'s_ID_6','s_ID_9','s_ID_9','r','r',0,0,0,1,1,0,'The Internet',"
+ "'The Internet',NULL,NULL,X'C2881000',X'C2881000');"
+ "INSERT INTO 'metas' VALUES(7,663,663,128976864758480000,"
+ "128976864758480000,128976864758480000,128976864758480000,1048576,0,"
+ "'s_ID_7','r','r','r','r',0,0,0,1,1,0,'Google Chrome','Google Chrome'"
+ ",'google_chrome',NULL,NULL,NULL);"
+ "INSERT INTO 'metas' VALUES(8,664,664,128976864758480000,"
+ "128976864758480000,128976864758480000,128976864758480000,1048576,0,"
+ "'s_ID_8','s_ID_7','s_ID_7','r','r',0,0,0,1,1,0,'Bookmarks',"
+ "'Bookmarks','google_chrome_bookmarks',NULL,X'C2881000',X'C2881000');"
+ "INSERT INTO 'metas' VALUES(9,665,665,128976864758480000,"
+ "128976864758480000,128976864758480000,128976864758480000,1048576,1,"
+ "'s_ID_9','s_ID_8','s_ID_8','r','s_ID_10',0,0,0,1,1,0,'Bookmark Bar',"
+ "'Bookmark Bar','bookmark_bar',NULL,X'C2881000',X'C2881000');"
+ "INSERT INTO 'metas' VALUES(10,666,666,128976864758480000,"
+ "128976864758480000,128976864758480000,128976864758480000,2097152,2,"
+ "'s_ID_10','s_ID_8','s_ID_8','s_ID_9','r',0,0,0,1,1,0,"
+ "'Other Bookmarks','Other Bookmarks','other_bookmarks',NULL,"
+ "X'C2881000',X'C2881000');"
+ "INSERT INTO 'metas' VALUES(11,683,683,129079956948440000,"
+ "129079956948440000,129079956948440000,129079956948440000,-1048576,8,"
+ "'s_ID_11','s_ID_6','s_ID_6','r','s_ID_13',0,0,0,0,0,0,"
+ "'Home (The Chromium Projects)','Home (The Chromium Projects)',NULL,"
+ "NULL,X'C28810220A18687474703A2F2F6465762E6368726F6D69756D2E6F72672F1"
+ "206414741545741',X'C28810290A1D687474703A2F2F6465762E6368726F6D69756"
+ "D2E6F72672F6F7468657212084146414756415346');"
+ "INSERT INTO 'metas' VALUES(12,685,685,129079957513650000,"
+ "129079957513650000,129079957513650000,129079957513650000,0,9,"
+ "'s_ID_12','s_ID_6','s_ID_6','s_ID_13','s_ID_14',0,0,0,1,1,0,"
+ "'Extra Bookmarks','Extra Bookmarks',NULL,NULL,X'C2881000',"
+ "X'C2881000');"
+ "INSERT INTO 'metas' VALUES(13,687,687,129079957985300000,"
+ "129079957985300000,129079957985300000,129079957985300000,-917504,10,"
+ "'s_ID_13','s_ID_6','s_ID_6','s_ID_11','s_ID_12',0,0,0,0,0,0,"
+ "'ICANN | Internet Corporation for Assigned Names and Numbers',"
+ "'ICANN | Internet Corporation for Assigned Names and Numbers',NULL,"
+ "NULL,X'C28810240A15687474703A2F2F7777772E6963616E6E2E636F6D2F120B504"
+ "E474158463041414646',X'C28810200A15687474703A2F2F7777772E6963616E6E2"
+ "E636F6D2F120744414146415346');"
+ "INSERT INTO 'metas' VALUES(14,692,692,129079958383000000,"
+ "129079958383000000,129079958383000000,129079958383000000,1048576,11,"
+ "'s_ID_14','s_ID_6','s_ID_6','s_ID_12','r',0,0,0,0,0,0,"
+ "'The WebKit Open Source Project','The WebKit Open Source Project',"
+ "NULL,NULL,""X'C288101A0A12687474703A2F2F7765626B69742E6F72672F120450"
+ "4E4758',X'C288101C0A13687474703A2F2F7765626B69742E6F72672F781205504E"
+ "473259');"
+ "CREATE TABLE models (model_id BLOB primary key, "
+ "last_download_timestamp INT, initial_sync_ended BOOLEAN default 0);"
+ "INSERT INTO 'models' VALUES(X'C2881000',694,1);"
+ "CREATE TABLE 'share_info' (id TEXT primary key, name TEXT, "
+ "store_birthday TEXT, db_create_version TEXT, db_create_time INT, "
+ "next_id INT default -2, cache_guid TEXT, "
+ "notification_state BLOB);"
+ "INSERT INTO 'share_info' VALUES('nick@chromium.org','nick@chromium.org',"
+ "'c27e9f59-08ca-46f8-b0cc-f16a2ed778bb','Unknown',1263522064,-65542,"
+ "'9010788312004066376x-6609234393368420856x',X'C2881000');"));
+ ASSERT_TRUE(connection.CommitTransaction());
+}
+
TEST_F(DirectoryBackingStoreTest, MigrateVersion67To68) {
SetUpVersion67Database();
@@ -937,6 +1043,56 @@ TEST_F(DirectoryBackingStoreTest, MigrateVersion72To73) {
connection.DoesColumnExist("share_info", "notification_state"));
}
+TEST_F(DirectoryBackingStoreTest, MigrateVersion73To74) {
+ SetUpVersion73Database();
+
+ {
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_FALSE(
+ connection.DoesColumnExist("share_info", "autofill_migration_state"));
+ ASSERT_FALSE(
+ connection.DoesColumnExist("share_info",
+ "bookmarks_added_during_autofill_migration"));
+ ASSERT_FALSE(
+ connection.DoesColumnExist("share_info", "autofill_migration_time"));
+ ASSERT_FALSE(
+ connection.DoesColumnExist("share_info",
+ "autofill_entries_added_during_migration"));
+
+ ASSERT_FALSE(
+ connection.DoesColumnExist("share_info",
+ "autofill_profiles_added_during_migration"));
+ }
+
+ scoped_ptr<DirectoryBackingStore> dbs(
+ new DirectoryBackingStore(GetUsername(), GetDatabasePath()));
+
+ dbs->BeginLoad();
+ ASSERT_FALSE(dbs->needs_column_refresh_);
+ ASSERT_TRUE(dbs->MigrateVersion73To74());
+ ASSERT_EQ(74, dbs->GetVersion());
+ dbs->EndLoad();
+ ASSERT_FALSE(dbs->needs_column_refresh_);
+
+ sql::Connection connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(
+ connection.DoesColumnExist("share_info", "autofill_migration_state"));
+ ASSERT_TRUE(
+ connection.DoesColumnExist("share_info",
+ "bookmarks_added_during_autofill_migration"));
+ ASSERT_TRUE(
+ connection.DoesColumnExist("share_info", "autofill_migration_time"));
+ ASSERT_TRUE(
+ connection.DoesColumnExist("share_info",
+ "autofill_entries_added_during_migration"));
+
+ ASSERT_TRUE(
+ connection.DoesColumnExist("share_info",
+ "autofill_profiles_added_during_migration"));
+}
+
TEST_P(MigrationTest, ToCurrentVersion) {
switch (GetParam()) {
case 67:
@@ -957,6 +1113,9 @@ TEST_P(MigrationTest, ToCurrentVersion) {
case 72:
SetUpVersion72Database();
break;
+ case 73:
+ SetUpVersion73Database();
+ break;
default:
// If you see this error, it may mean that you've increased the
// database version number but you haven't finished adding unit tests
@@ -1015,6 +1174,10 @@ TEST_P(MigrationTest, ToCurrentVersion) {
// Columns added in Version 73.
ASSERT_TRUE(connection.DoesColumnExist(
"share_info", "notification_state"));
+
+ // Columns added in version 74.
+ ASSERT_TRUE(connection.DoesColumnExist("share_info",
+ "autofill_migration_state"));
}
MetahandlesIndex index;
diff --git a/chrome/browser/sync/syncable/model_type.cc b/chrome/browser/sync/syncable/model_type.cc
index c95daa8..7bbb29a 100644
--- a/chrome/browser/sync/syncable/model_type.cc
+++ b/chrome/browser/sync/syncable/model_type.cc
@@ -153,6 +153,9 @@ std::string ModelTypeToString(ModelType model_type) {
return "Sessions";
case APPS:
return "Apps";
+ case AUTOFILL_PROFILE:
+ return "Autofill Profile";
+ break;
default:
NOTREACHED() << "No known extension for model type.";
return "INVALID";
@@ -269,7 +272,7 @@ const char kAppNotificationType[] = "APP";
const char kSessionNotificationType[] = "SESSION";
// TODO(lipalani) Bug 64111.
// talk to akalin to make sure this is what I understand this to be.
-const char kAutofillProfileType[] = "AUTOFILL_PROFILE";
+const char kAutofillProfileNotificationType[] = "AUTOFILL_PROFILE";
// TODO(akalin): This is a hack to make new sync data types work with
// server-issued notifications. Remove this when it's not needed
// anymore.
@@ -310,7 +313,7 @@ bool RealModelTypeToNotificationType(ModelType model_type,
*notification_type = kSessionNotificationType;
return true;
case AUTOFILL_PROFILE:
- *notification_type = kAutofillProfileType;
+ *notification_type = kAutofillProfileNotificationType;
return true;
// TODO(akalin): This is a hack to make new sync data types work with
// server-issued notifications. Remove this when it's not needed
@@ -357,6 +360,9 @@ bool NotificationTypeToRealModelType(const std::string& notification_type,
} else if (notification_type == kSessionNotificationType) {
*model_type = SESSIONS;
return true;
+ } else if (notification_type == kAutofillProfileNotificationType) {
+ *model_type = AUTOFILL_PROFILE;
+ return true;
} else if (notification_type == kUnknownNotificationType) {
// TODO(akalin): This is a hack to make new sync data types work with
// server-issued notifications. Remove this when it's not needed
diff --git a/chrome/browser/sync/syncable/model_type.h b/chrome/browser/sync/syncable/model_type.h
index 442e462..2760fbe 100644
--- a/chrome/browser/sync/syncable/model_type.h
+++ b/chrome/browser/sync/syncable/model_type.h
@@ -49,10 +49,11 @@ enum ModelType {
PREFERENCES,
// A password folder or password object.
PASSWORDS,
+ // An AutofillProfile Object
+ AUTOFILL_PROFILE,
// An autofill folder or an autofill object.
AUTOFILL,
- // An autofill Profile Object
- AUTOFILL_PROFILE,
+
// A themes folder or a themes object.
THEMES,
// A typed_url folder or a typed_url object.
diff --git a/chrome/browser/sync/syncable/syncable.cc b/chrome/browser/sync/syncable/syncable.cc
index 903b71d..2794efa 100644
--- a/chrome/browser/sync/syncable/syncable.cc
+++ b/chrome/browser/sync/syncable/syncable.cc
@@ -179,6 +179,7 @@ Directory::PersistedKernelInfo::PersistedKernelInfo()
for (int i = 0; i < MODEL_TYPE_COUNT; ++i) {
last_download_timestamp[i] = 0;
}
+ autofill_migration_state = NOT_DETERMINED;
}
Directory::PersistedKernelInfo::~PersistedKernelInfo() {}
@@ -720,6 +721,83 @@ bool Directory::initial_sync_ended_for_type(ModelType type) const {
return kernel_->persisted_info.initial_sync_ended[type];
}
+AutofillMigrationState Directory::get_autofill_migration_state() const {
+ ScopedKernelLock lock(this);
+ return kernel_->persisted_info.autofill_migration_state;
+}
+
+AutofillMigrationDebugInfo
+ Directory::get_autofill_migration_debug_info() const {
+ ScopedKernelLock lock(this);
+ return kernel_->persisted_info.autofill_migration_debug_info;
+}
+
+template <class T> void Directory::TestAndSet(
+ T* kernel_data, const T* data_to_set) {
+ if (*kernel_data != *data_to_set) {
+ *kernel_data = *data_to_set;
+ kernel_->info_status = KERNEL_SHARE_INFO_DIRTY;
+ }
+}
+
+void Directory::set_autofill_migration_state_debug_info(
+ AutofillMigrationDebugInfo::PropertyToSet property_to_set,
+ const AutofillMigrationDebugInfo& info) {
+
+ ScopedKernelLock lock(this);
+ switch (property_to_set) {
+ case AutofillMigrationDebugInfo::MIGRATION_TIME: {
+ syncable::AutofillMigrationDebugInfo&
+ debug_info = kernel_->persisted_info.autofill_migration_debug_info;
+ TestAndSet<int64>(
+ &debug_info.autofill_migration_time,
+ &info.autofill_migration_time);
+ break;
+ }
+ case AutofillMigrationDebugInfo::BOOKMARK_ADDED: {
+ AutofillMigrationDebugInfo& debug_info =
+ kernel_->persisted_info.autofill_migration_debug_info;
+ TestAndSet<int>(
+ &debug_info.bookmarks_added_during_migration,
+ &info.bookmarks_added_during_migration);
+ break;
+ }
+ case AutofillMigrationDebugInfo::ENTRIES_ADDED: {
+ AutofillMigrationDebugInfo& debug_info =
+ kernel_->persisted_info.autofill_migration_debug_info;
+ TestAndSet<int>(
+ &debug_info.autofill_entries_added_during_migration,
+ &info.autofill_entries_added_during_migration);
+ break;
+ }
+ case AutofillMigrationDebugInfo::PROFILES_ADDED: {
+ AutofillMigrationDebugInfo& debug_info =
+ kernel_->persisted_info.autofill_migration_debug_info;
+ TestAndSet<int>(
+ &debug_info.autofill_profile_added_during_migration,
+ &info.autofill_profile_added_during_migration);
+ break;
+ }
+ default:
+ NOTREACHED();
+ }
+}
+
+void Directory::set_autofill_migration_state(AutofillMigrationState state) {
+ ScopedKernelLock lock(this);
+ if (state == kernel_->persisted_info.autofill_migration_state) {
+ return;
+ }
+ kernel_->persisted_info.autofill_migration_state = state;
+ if (state == MIGRATED) {
+ syncable::AutofillMigrationDebugInfo& debug_info =
+ kernel_->persisted_info.autofill_migration_debug_info;
+ debug_info.autofill_migration_time =
+ base::Time::Now().ToInternalValue();
+ }
+ kernel_->info_status = KERNEL_SHARE_INFO_DIRTY;
+}
+
void Directory::set_initial_sync_ended_for_type(ModelType type, bool x) {
ScopedKernelLock lock(this);
set_initial_sync_ended_for_type_unsafe(type, x);
diff --git a/chrome/browser/sync/syncable/syncable.h b/chrome/browser/sync/syncable/syncable.h
index 19d98ee..cccf417 100644
--- a/chrome/browser/sync/syncable/syncable.h
+++ b/chrome/browser/sync/syncable/syncable.h
@@ -21,6 +21,7 @@
#include "base/lock.h"
#include "base/time.h"
#include "chrome/browser/sync/protocol/sync.pb.h"
+#include "chrome/browser/sync/syncable/autofill_migration.h"
#include "chrome/browser/sync/syncable/blob.h"
#include "chrome/browser/sync/syncable/dir_open_result.h"
#include "chrome/browser/sync/syncable/directory_event.h"
@@ -660,6 +661,8 @@ class Directory {
// Various data that the Directory::Kernel we are backing (persisting data
// for) needs saved across runs of the application.
struct PersistedKernelInfo {
+ AutofillMigrationDebugInfo autofill_migration_debug_info;
+
PersistedKernelInfo();
~PersistedKernelInfo();
@@ -674,6 +677,8 @@ class Directory {
int64 next_id;
// The persisted notification state.
std::string notification_state;
+
+ AutofillMigrationState autofill_migration_state;
};
// What the Directory needs on initialization to create itself and its Kernel.
@@ -754,6 +759,15 @@ class Directory {
bool initial_sync_ended_for_type(ModelType type) const;
void set_initial_sync_ended_for_type(ModelType type, bool value);
+ AutofillMigrationState get_autofill_migration_state() const;
+
+ AutofillMigrationDebugInfo get_autofill_migration_debug_info() const;
+
+ void set_autofill_migration_state(AutofillMigrationState state);
+
+ void set_autofill_migration_state_debug_info(
+ syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set,
+ const syncable::AutofillMigrationDebugInfo& info);
const std::string& name() const { return kernel_->name; }
@@ -804,6 +818,8 @@ class Directory {
DirOpenResult OpenImpl(const FilePath& file_path, const std::string& name);
+ template <class T> void TestAndSet(T* kernel_data, const T* data_to_set);
+
struct DirectoryEventTraits {
typedef DirectoryEvent EventType;
static inline bool IsChannelShutdownEvent(const DirectoryEvent& event) {
diff --git a/chrome/browser/sync/test_profile_sync_service.h b/chrome/browser/sync/test_profile_sync_service.h
index 3cad8dc..f5da3d6 100644
--- a/chrome/browser/sync/test_profile_sync_service.h
+++ b/chrome/browser/sync/test_profile_sync_service.h
@@ -9,7 +9,6 @@
#include <string>
#include "base/message_loop.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/profile_sync_factory.h"
#include "chrome/browser/sync/profile_sync_service.h"
@@ -19,11 +18,12 @@
#include "chrome/browser/sync/sessions/session_state.h"
#include "chrome/browser/sync/syncable/directory_manager.h"
#include "chrome/browser/sync/syncable/syncable.h"
-#include "chrome/common/notification_service.h"
#include "chrome/test/profile_mock.h"
#include "chrome/test/sync/test_http_bridge_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
+class Profile;
+
using browser_sync::ModelSafeRoutingInfo;
using browser_sync::sessions::ErrorCounters;
using browser_sync::sessions::SyncerStatus;
@@ -175,7 +175,6 @@ class SyncBackendHostForProfileSyncTest : public SyncBackendHost {
Task* initial_condition_setup_task_;
bool set_initial_sync_ended_on_init_;
bool synchronous_init_;
-
};
} // namespace browser_sync
diff --git a/chrome/browser/sync/tools/sync_listen_notifications.cc b/chrome/browser/sync/tools/sync_listen_notifications.cc
index 0b20db1..d15ded3 100644
--- a/chrome/browser/sync/tools/sync_listen_notifications.cc
+++ b/chrome/browser/sync/tools/sync_listen_notifications.cc
@@ -25,6 +25,7 @@
#include "jingle/notifier/listener/send_update_task.h"
#include "jingle/notifier/listener/subscribe_task.h"
#include "jingle/notifier/listener/xml_element_util.h"
+#include "net/base/cert_verifier.h"
#include "net/base/ssl_config_service.h"
#include "net/socket/client_socket_factory.h"
#include "talk/base/cryptstring.h"
@@ -66,10 +67,12 @@ class XmppNotificationClient : public notifier::XmppConnection::Delegate {
virtual ~XmppNotificationClient() {}
// Connect with the given XMPP settings and run until disconnected.
- void Run(const buzz::XmppClientSettings& xmpp_client_settings) {
+ void Run(const buzz::XmppClientSettings& xmpp_client_settings,
+ net::CertVerifier* cert_verifier) {
DCHECK(!xmpp_connection_.get());
xmpp_connection_.reset(
- new notifier::XmppConnection(xmpp_client_settings, this, NULL));
+ new notifier::XmppConnection(xmpp_client_settings, cert_verifier,
+ this, NULL));
MessageLoop::current()->Run();
DCHECK(!xmpp_connection_.get());
}
@@ -295,6 +298,8 @@ int main(int argc, char* argv[]) {
}
xmpp_client_settings.set_server(addr);
+ net::CertVerifier cert_verifier;
+
MessageLoopForIO message_loop;
// Connect and listen.
@@ -310,7 +315,7 @@ int main(int argc, char* argv[]) {
}
XmppNotificationClient xmpp_notification_client(
observers.begin(), observers.end());
- xmpp_notification_client.Run(xmpp_client_settings);
+ xmpp_notification_client.Run(xmpp_client_settings, &cert_verifier);
return 0;
}
diff --git a/chrome/browser/tab_closeable_state_watcher.cc b/chrome/browser/tab_closeable_state_watcher.cc
index 198dee5..28c9135 100644
--- a/chrome/browser/tab_closeable_state_watcher.cc
+++ b/chrome/browser/tab_closeable_state_watcher.cc
@@ -27,3 +27,11 @@
watcher = new ::TabCloseableStateWatcher();
return watcher;
}
+
+bool TabCloseableStateWatcher::CanCloseTab(const Browser* browser) const {
+ return true;
+}
+
+bool TabCloseableStateWatcher::CanCloseBrowser(Browser* browser) {
+ return true;
+}
diff --git a/chrome/browser/tab_closeable_state_watcher.h b/chrome/browser/tab_closeable_state_watcher.h
index 8ee81c3..b77a539 100644
--- a/chrome/browser/tab_closeable_state_watcher.h
+++ b/chrome/browser/tab_closeable_state_watcher.h
@@ -32,15 +32,11 @@ class TabCloseableStateWatcher {
// - setting up tab's context menu to determine if "Close tab" should
// should be enabled
// - determining if accelerator keys to close tab should be processed
- virtual bool CanCloseTab(const Browser* browser) const {
- return true;
- }
+ virtual bool CanCloseTab(const Browser* browser) const;
// Called from Browser::IsClosingPermitted which is in turn called from
// Browser::ShouldCloseWindow to check if |browser| can be closed.
- virtual bool CanCloseBrowser(Browser* browser) {
- return true;
- }
+ virtual bool CanCloseBrowser(Browser* browser);
// Called from Browser::CancelWindowClose when closing of window is canceled.
// Watcher is potentially interested in this, especially when the closing of
diff --git a/chrome/browser/tab_contents/background_contents.cc b/chrome/browser/tab_contents/background_contents.cc
index 413810e..1904d38 100644
--- a/chrome/browser/tab_contents/background_contents.cc
+++ b/chrome/browser/tab_contents/background_contents.cc
@@ -6,7 +6,7 @@
#include "chrome/browser/background_contents_service.h"
#include "chrome/browser/browsing_instance.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/renderer_preferences_util.h"
@@ -58,6 +58,18 @@ BackgroundContents::~BackgroundContents() {
render_view_host_->Shutdown(); // deletes render_view_host
}
+BackgroundContents* BackgroundContents::GetAsBackgroundContents() {
+ return this;
+}
+
+RenderViewHostDelegate::View* BackgroundContents::GetViewDelegate() {
+ return this;
+}
+
+const GURL& BackgroundContents::GetURL() const {
+ return url_;
+}
+
ViewType::Type BackgroundContents::GetRenderViewType() const {
return ViewType::BACKGROUND_CONTENTS;
}
@@ -135,6 +147,14 @@ gfx::NativeWindow BackgroundContents::GetMessageBoxRootWindow() {
return NULL;
}
+TabContents* BackgroundContents::AsTabContents() {
+ return NULL;
+}
+
+ExtensionHost* BackgroundContents::AsExtensionHost() {
+ return NULL;
+}
+
void BackgroundContents::UpdateInspectorSetting(const std::string& key,
const std::string& value) {
Profile* profile = render_view_host_->process()->profile();
diff --git a/chrome/browser/tab_contents/background_contents.h b/chrome/browser/tab_contents/background_contents.h
index 81ae92d..ad57800 100644
--- a/chrome/browser/tab_contents/background_contents.h
+++ b/chrome/browser/tab_contents/background_contents.h
@@ -9,9 +9,9 @@
#include <string>
#include <vector>
-#include "chrome/browser/js_modal_dialog.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
#include "chrome/browser/tab_contents/render_view_host_delegate_helper.h"
+#include "chrome/browser/ui/app_modal_dialogs/js_modal_dialog.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/view_types.h"
#include "chrome/common/window_container_type.h"
@@ -58,9 +58,9 @@ class BackgroundContents : public RenderViewHostDelegate,
RenderViewHost* render_view_host() { return render_view_host_; }
// RenderViewHostDelegate implementation.
- virtual BackgroundContents* GetAsBackgroundContents() { return this; }
- virtual RenderViewHostDelegate::View* GetViewDelegate() { return this; }
- virtual const GURL& GetURL() const { return url_; }
+ virtual BackgroundContents* GetAsBackgroundContents();
+ virtual RenderViewHostDelegate::View* GetViewDelegate();
+ virtual const GURL& GetURL() const;
virtual ViewType::Type GetRenderViewType() const;
virtual int GetBrowserWindowID() const;
virtual void DidNavigate(RenderViewHost* render_view_host,
@@ -129,8 +129,8 @@ class BackgroundContents : public RenderViewHostDelegate,
const std::wstring& prompt);
virtual void SetSuppressMessageBoxes(bool suppress_message_boxes) {}
virtual gfx::NativeWindow GetMessageBoxRootWindow();
- virtual TabContents* AsTabContents() { return NULL; }
- virtual ExtensionHost* AsExtensionHost() { return NULL; }
+ virtual TabContents* AsTabContents();
+ virtual ExtensionHost* AsExtensionHost();
virtual void UpdateInspectorSetting(const std::string& key,
const std::string& value);
diff --git a/chrome/browser/tab_contents/infobar_delegate.cc b/chrome/browser/tab_contents/infobar_delegate.cc
index aae8553..671d17b 100644
--- a/chrome/browser/tab_contents/infobar_delegate.cc
+++ b/chrome/browser/tab_contents/infobar_delegate.cc
@@ -14,6 +14,10 @@
// InfoBarDelegate: ------------------------------------------------------------
+bool InfoBarDelegate::EqualsDelegate(InfoBarDelegate* delegate) const {
+ return false;
+}
+
bool InfoBarDelegate::ShouldExpire(
const NavigationController::LoadCommittedDetails& details) const {
bool is_reload =
@@ -22,6 +26,44 @@ bool InfoBarDelegate::ShouldExpire(
return is_reload || (contents_unique_id_ != details.entry->unique_id());
}
+SkBitmap* InfoBarDelegate::GetIcon() const {
+ return NULL;
+}
+
+AlertInfoBarDelegate* InfoBarDelegate::AsAlertInfoBarDelegate() {
+ return NULL;
+}
+
+LinkInfoBarDelegate* InfoBarDelegate::AsLinkInfoBarDelegate() {
+ return NULL;
+}
+
+ConfirmInfoBarDelegate* InfoBarDelegate::AsConfirmInfoBarDelegate() {
+ return NULL;
+}
+
+ThemeInstalledInfoBarDelegate*
+InfoBarDelegate::AsThemePreviewInfobarDelegate() {
+ return NULL;
+}
+
+TranslateInfoBarDelegate* InfoBarDelegate::AsTranslateInfoBarDelegate() {
+ return NULL;
+}
+
+ExtensionInfoBarDelegate* InfoBarDelegate::AsExtensionInfoBarDelegate() {
+ return NULL;
+}
+
+CrashedExtensionInfoBarDelegate*
+InfoBarDelegate::AsCrashedExtensionInfoBarDelegate() {
+ return NULL;
+}
+
+InfoBarDelegate::Type InfoBarDelegate::GetInfoBarType() {
+ return WARNING_TYPE;
+}
+
InfoBarDelegate::InfoBarDelegate(TabContents* contents)
: contents_unique_id_(0) {
if (contents)
@@ -35,6 +77,10 @@ void InfoBarDelegate::StoreActiveEntryUniqueID(TabContents* contents) {
// AlertInfoBarDelegate: -------------------------------------------------------
+SkBitmap* AlertInfoBarDelegate::GetIcon() const {
+ return NULL;
+}
+
bool AlertInfoBarDelegate::EqualsDelegate(InfoBarDelegate* delegate) const {
AlertInfoBarDelegate* alert_delegate = delegate->AsAlertInfoBarDelegate();
if (!alert_delegate)
@@ -43,18 +89,44 @@ bool AlertInfoBarDelegate::EqualsDelegate(InfoBarDelegate* delegate) const {
return alert_delegate->GetMessageText() == GetMessageText();
}
+AlertInfoBarDelegate* AlertInfoBarDelegate::AsAlertInfoBarDelegate() {
+ return this;
+}
+
AlertInfoBarDelegate::AlertInfoBarDelegate(TabContents* contents)
: InfoBarDelegate(contents) {
}
// LinkInfoBarDelegate: --------------------------------------------------------
+string16 LinkInfoBarDelegate::GetMessageTextWithOffset(
+ size_t* link_offset) const {
+ *link_offset = string16::npos;
+ return string16();
+}
+
+SkBitmap* LinkInfoBarDelegate::GetIcon() const {
+ return NULL;
+}
+
+bool LinkInfoBarDelegate::LinkClicked(WindowOpenDisposition disposition) {
+ return true;
+}
+
+LinkInfoBarDelegate* LinkInfoBarDelegate::AsLinkInfoBarDelegate() {
+ return this;
+}
+
LinkInfoBarDelegate::LinkInfoBarDelegate(TabContents* contents)
: InfoBarDelegate(contents) {
}
// ConfirmInfoBarDelegate: -----------------------------------------------------
+int ConfirmInfoBarDelegate::GetButtons() const {
+ return BUTTON_NONE;
+}
+
string16 ConfirmInfoBarDelegate::GetButtonLabel(
InfoBarButton button) const {
if (button == BUTTON_OK)
@@ -65,6 +137,30 @@ string16 ConfirmInfoBarDelegate::GetButtonLabel(
return string16();
}
+bool ConfirmInfoBarDelegate::NeedElevation(InfoBarButton button) const {
+ return false;
+}
+
+bool ConfirmInfoBarDelegate::Accept() {
+ return true;
+}
+
+bool ConfirmInfoBarDelegate::Cancel() {
+ return true;
+}
+
+string16 ConfirmInfoBarDelegate::GetLinkText() {
+ return string16();
+}
+
+bool ConfirmInfoBarDelegate::LinkClicked(WindowOpenDisposition disposition) {
+ return true;
+}
+
+ConfirmInfoBarDelegate* ConfirmInfoBarDelegate::AsConfirmInfoBarDelegate() {
+ return this;
+}
+
ConfirmInfoBarDelegate::ConfirmInfoBarDelegate(TabContents* contents)
: AlertInfoBarDelegate(contents) {
}
diff --git a/chrome/browser/tab_contents/infobar_delegate.h b/chrome/browser/tab_contents/infobar_delegate.h
index 4da3510..af9b9c9 100644
--- a/chrome/browser/tab_contents/infobar_delegate.h
+++ b/chrome/browser/tab_contents/infobar_delegate.h
@@ -58,9 +58,7 @@ class InfoBarDelegate {
// because a matching one already exists. If this function returns true, the
// TabContents will not add the new delegate because it considers one to
// already be present.
- virtual bool EqualsDelegate(InfoBarDelegate* delegate) const {
- return false;
- }
+ virtual bool EqualsDelegate(InfoBarDelegate* delegate) const;
// Returns true if the InfoBar should be closed automatically after the page
// is navigated. The default behavior is to return true if the page is
@@ -81,52 +79,36 @@ class InfoBarDelegate {
// Return the icon to be shown for this InfoBar. If the returned bitmap is
// NULL, no icon is shown.
- virtual SkBitmap* GetIcon() const { return NULL; }
+ virtual SkBitmap* GetIcon() const;
// Returns a pointer to the AlertInfoBarDelegate interface, if implemented.
- virtual AlertInfoBarDelegate* AsAlertInfoBarDelegate() {
- return NULL;
- }
+ virtual AlertInfoBarDelegate* AsAlertInfoBarDelegate();
// Returns a pointer to the LinkInfoBarDelegate interface, if implemented.
- virtual LinkInfoBarDelegate* AsLinkInfoBarDelegate() {
- return NULL;
- }
+ virtual LinkInfoBarDelegate* AsLinkInfoBarDelegate();
// Returns a pointer to the ConfirmInfoBarDelegate interface, if implemented.
- virtual ConfirmInfoBarDelegate* AsConfirmInfoBarDelegate() {
- return NULL;
- }
+ virtual ConfirmInfoBarDelegate* AsConfirmInfoBarDelegate();
// Returns a pointer to the ThemeInstalledInfoBarDelegate interface, if
// implemented.
- virtual ThemeInstalledInfoBarDelegate* AsThemePreviewInfobarDelegate() {
- return NULL;
- }
+ virtual ThemeInstalledInfoBarDelegate* AsThemePreviewInfobarDelegate();
// Returns a pointer to the TranslateInfoBarDelegate interface, if
// implemented.
- virtual TranslateInfoBarDelegate* AsTranslateInfoBarDelegate() {
- return NULL;
- }
+ virtual TranslateInfoBarDelegate* AsTranslateInfoBarDelegate();
// Returns a pointer to the ExtensionInfoBarDelegate interface, if
// implemented.
- virtual ExtensionInfoBarDelegate* AsExtensionInfoBarDelegate() {
- return NULL;
- }
+ virtual ExtensionInfoBarDelegate* AsExtensionInfoBarDelegate();
// Returns a pointer to the CrashedExtensionInfoBarDelegate interface, if
// implemented.
- virtual CrashedExtensionInfoBarDelegate* AsCrashedExtensionInfoBarDelegate() {
- return NULL;
- }
+ virtual CrashedExtensionInfoBarDelegate* AsCrashedExtensionInfoBarDelegate();
// Returns the type of the infobar. The type determines the appearance (such
// as background color) of the infobar.
- virtual Type GetInfoBarType() {
- return WARNING_TYPE;
- }
+ virtual Type GetInfoBarType();
protected:
// Provided to subclasses as a convenience to initialize the state of this
@@ -157,12 +139,12 @@ class AlertInfoBarDelegate : public InfoBarDelegate {
virtual string16 GetMessageText() const = 0;
// Overridden from InfoBarDelegate.
- virtual SkBitmap* GetIcon() const { return NULL; }
+ virtual SkBitmap* GetIcon() const;
// Overridden from InfoBarDelegate:
virtual bool EqualsDelegate(InfoBarDelegate* delegate) const;
virtual InfoBar* CreateInfoBar();
- virtual AlertInfoBarDelegate* AsAlertInfoBarDelegate() { return this; }
+ virtual AlertInfoBarDelegate* AsAlertInfoBarDelegate();
protected:
explicit AlertInfoBarDelegate(TabContents* contents);
@@ -178,31 +160,24 @@ class LinkInfoBarDelegate : public InfoBarDelegate {
// is the position where the link should be inserted. If |link_offset| is set
// to string16::npos (it is by default), the link is right aligned within
// the InfoBar rather than being embedded in the message text.
- virtual string16 GetMessageTextWithOffset(size_t* link_offset) const {
- *link_offset = string16::npos;
- return string16();
- }
+ virtual string16 GetMessageTextWithOffset(size_t* link_offset) const;
// Returns the text of the link to be displayed.
virtual string16 GetLinkText() const = 0;
// Overridden from InfoBarDelegate.
- virtual SkBitmap* GetIcon() const { return NULL; }
+ virtual SkBitmap* GetIcon() const;
// Called when the Link is clicked. The |disposition| specifies how the
// resulting document should be loaded (based on the event flags present when
// the link was clicked). This function returns true if the InfoBar should be
// closed now or false if it should remain until the user explicitly closes
// it.
- virtual bool LinkClicked(WindowOpenDisposition disposition) {
- return true;
- }
+ virtual bool LinkClicked(WindowOpenDisposition disposition);
// Overridden from InfoBarDelegate:
virtual InfoBar* CreateInfoBar();
- virtual LinkInfoBarDelegate* AsLinkInfoBarDelegate() {
- return this;
- }
+ virtual LinkInfoBarDelegate* AsLinkInfoBarDelegate();
protected:
explicit LinkInfoBarDelegate(TabContents* contents);
@@ -223,30 +198,26 @@ class ConfirmInfoBarDelegate : public AlertInfoBarDelegate {
};
// Return the buttons to be shown for this InfoBar.
- virtual int GetButtons() const {
- return BUTTON_NONE;
- }
+ virtual int GetButtons() const;
// Return the label for the specified button. The default implementation
// returns "OK" for the OK button and "Cancel" for the Cancel button.
virtual string16 GetButtonLabel(InfoBarButton button) const;
// Return whether or not the specified button needs elevation.
- virtual bool NeedElevation(InfoBarButton button) const { return false; }
+ virtual bool NeedElevation(InfoBarButton button) const;
// Called when the OK button is pressed. If the function returns true, the
// InfoBarDelegate should be removed from the associated TabContents.
- virtual bool Accept() { return true; }
+ virtual bool Accept();
// Called when the Cancel button is pressed. If the function returns true,
// the InfoBarDelegate should be removed from the associated TabContents.
- virtual bool Cancel() { return true; }
+ virtual bool Cancel();
// Returns the text of the link to be displayed, if any. Otherwise returns
// and empty string.
- virtual string16 GetLinkText() {
- return string16();
- }
+ virtual string16 GetLinkText();
// Called when the Link is clicked. The |disposition| specifies how the
// resulting document should be loaded (based on the event flags present when
@@ -254,15 +225,11 @@ class ConfirmInfoBarDelegate : public AlertInfoBarDelegate {
// closed now or false if it should remain until the user explicitly closes
// it.
// Will only be called if GetLinkText() returns non-empty string.
- virtual bool LinkClicked(WindowOpenDisposition disposition) {
- return true;
- }
+ virtual bool LinkClicked(WindowOpenDisposition disposition);
// Overridden from InfoBarDelegate:
virtual InfoBar* CreateInfoBar();
- virtual ConfirmInfoBarDelegate* AsConfirmInfoBarDelegate() {
- return this;
- }
+ virtual ConfirmInfoBarDelegate* AsConfirmInfoBarDelegate();
protected:
explicit ConfirmInfoBarDelegate(TabContents* contents);
diff --git a/chrome/browser/tab_contents/interstitial_page.cc b/chrome/browser/tab_contents/interstitial_page.cc
index 8705e62..8548c8d 100644
--- a/chrome/browser/tab_contents/interstitial_page.cc
+++ b/chrome/browser/tab_contents/interstitial_page.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/tab_contents/interstitial_page.h"
+#include <vector>
+
#include "base/compiler_specific.h"
#include "base/message_loop.h"
#include "base/string_util.h"
@@ -13,7 +15,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/dom_operation_notification_details.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
@@ -26,14 +28,14 @@
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/common/bindings_policy.h"
#include "chrome/common/dom_storage_common.h"
-#if defined(TOOLKIT_GTK)
-#include "chrome/browser/gtk/gtk_theme_provider.h"
-#endif
#include "chrome/common/net/url_request_context_getter.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
#include "grit/browser_resources.h"
#include "net/base/escape.h"
-#include "views/window/window_delegate.h"
+
+#if defined(TOOLKIT_GTK)
+#include "chrome/browser/gtk/gtk_theme_provider.h"
+#endif
using WebKit::WebDragOperation;
using WebKit::WebDragOperationsMask;
@@ -333,7 +335,9 @@ const GURL& InterstitialPage::GetURL() const {
return url_;
}
-void InterstitialPage::RenderViewGone(RenderViewHost* render_view_host) {
+void InterstitialPage::RenderViewGone(RenderViewHost* render_view_host,
+ base::TerminationStatus status,
+ int error_code) {
// Our renderer died. This should not happen in normal cases.
// Just dismiss the interstitial.
DontProceed();
@@ -461,6 +465,10 @@ void InterstitialPage::Proceed() {
}
}
+std::string InterstitialPage::GetHTMLContents() {
+ return std::string();
+}
+
void InterstitialPage::DontProceed() {
DCHECK(action_taken_ != DONT_PROCEED_ACTION);
@@ -527,6 +535,10 @@ void InterstitialPage::FocusThroughTabTraversal(bool reverse) {
render_view_host_->SetInitialFocus(reverse);
}
+ViewType::Type InterstitialPage::GetRenderViewType() const {
+ return ViewType::INTERSTITIAL_PAGE;
+}
+
void InterstitialPage::Disable() {
enabled_ = false;
}
diff --git a/chrome/browser/tab_contents/interstitial_page.h b/chrome/browser/tab_contents/interstitial_page.h
index 50ede04..3592a9d 100644
--- a/chrome/browser/tab_contents/interstitial_page.h
+++ b/chrome/browser/tab_contents/interstitial_page.h
@@ -9,6 +9,7 @@
#include <map>
#include <string>
+#include "base/process_util.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
#include "chrome/common/notification_observer.h"
@@ -69,7 +70,7 @@ class InterstitialPage : public NotificationObserver,
static InterstitialPage* GetInterstitialPage(TabContents* tab_contents);
// Sub-classes should return the HTML that should be displayed in the page.
- virtual std::string GetHTMLContents() { return std::string(); }
+ virtual std::string GetHTMLContents();
// Reverts to the page showing before the interstitial.
// Sub-classes should call this method when the user has chosen NOT to proceed
@@ -100,9 +101,7 @@ class InterstitialPage : public NotificationObserver,
// Called when tab traversing.
void FocusThroughTabTraversal(bool reverse);
- virtual ViewType::Type GetRenderViewType() const {
- return ViewType::INTERSTITIAL_PAGE;
- }
+ virtual ViewType::Type GetRenderViewType() const;
virtual int GetBrowserWindowID() const;
// See description above field.
@@ -124,7 +123,9 @@ class InterstitialPage : public NotificationObserver,
// RenderViewHostDelegate implementation:
virtual View* GetViewDelegate();
virtual const GURL& GetURL() const;
- virtual void RenderViewGone(RenderViewHost* render_view_host);
+ virtual void RenderViewGone(RenderViewHost* render_view_host,
+ base::TerminationStatus status,
+ int error_code);
virtual void DidNavigate(RenderViewHost* render_view_host,
const ViewHostMsg_FrameNavigate_Params& params);
virtual void UpdateTitle(RenderViewHost* render_view_host,
diff --git a/chrome/browser/tab_contents/navigation_controller.cc b/chrome/browser/tab_contents/navigation_controller.cc
index fac26a3..9439f21 100644
--- a/chrome/browser/tab_contents/navigation_controller.cc
+++ b/chrome/browser/tab_contents/navigation_controller.cc
@@ -10,11 +10,10 @@
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_about_handler.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_url_handler.h"
#include "chrome/browser/in_process_webkit/session_storage_namespace.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/sessions/session_types.h"
#include "chrome/browser/tab_contents/interstitial_page.h"
@@ -987,30 +986,33 @@ void NavigationController::CopyStateFromAndPrune(NavigationController* source) {
}
void NavigationController::PruneAllButActive() {
- int prune_count = entry_count();
if (transient_entry_index_ != -1) {
// There is a transient entry. Prune up to it.
DCHECK_EQ(entry_count() - 1, transient_entry_index_);
- prune_count = transient_entry_index_;
+ entries_.erase(entries_.begin(), entries_.begin() + transient_entry_index_);
transient_entry_index_ = 0;
last_committed_entry_index_ = -1;
pending_entry_index_ = -1;
} else if (!pending_entry_) {
// There's no pending entry. Leave the last entry (if there is one).
- if (!prune_count)
+ if (!entry_count())
return;
- prune_count--;
+ DCHECK(last_committed_entry_index_ >= 0);
+ entries_.erase(entries_.begin(),
+ entries_.begin() + last_committed_entry_index_);
+ entries_.erase(entries_.begin() + 1, entries_.end());
last_committed_entry_index_ = 0;
} else if (pending_entry_index_ != -1) {
- DCHECK_EQ(pending_entry_index_, prune_count - 1);
+ entries_.erase(entries_.begin(), entries_.begin() + pending_entry_index_);
+ entries_.erase(entries_.begin() + 1, entries_.end());
pending_entry_index_ = 0;
last_committed_entry_index_ = 0;
- prune_count--;
} else {
// There is a pending_entry, but it's not in entries_.
pending_entry_index_ = -1;
last_committed_entry_index_ = -1;
+ entries_.clear();
}
if (tab_contents_->interstitial_page()) {
@@ -1019,8 +1021,6 @@ void NavigationController::PruneAllButActive() {
// so the interstitial triggers a reload if the user doesn't proceed.
tab_contents_->interstitial_page()->set_reload_on_dont_proceed(true);
}
-
- entries_.erase(entries_.begin(), entries_.begin() + prune_count);
}
void NavigationController::DiscardNonCommittedEntries() {
diff --git a/chrome/browser/tab_contents/navigation_controller_unittest.cc b/chrome/browser/tab_contents/navigation_controller_unittest.cc
index b8cfcb5..91c23ea 100644
--- a/chrome/browser/tab_contents/navigation_controller_unittest.cc
+++ b/chrome/browser/tab_contents/navigation_controller_unittest.cc
@@ -8,7 +8,7 @@
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/renderer_host/test/test_render_view_host.h"
@@ -21,7 +21,6 @@
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
#include "chrome/browser/tab_contents/test_tab_contents.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/render_messages_params.h"
#include "chrome/test/test_notification_tracker.h"
@@ -1865,6 +1864,92 @@ TEST_F(NavigationControllerTest, HistoryNavigate) {
EXPECT_TRUE(message == NULL);
}
+// Test call to PruneAllButActive for the only entry.
+TEST_F(NavigationControllerTest, PruneAllButActiveForSingle) {
+ const GURL url1("http://foo1");
+ NavigateAndCommit(url1);
+ controller().PruneAllButActive();
+
+ EXPECT_EQ(-1, controller().pending_entry_index());
+ EXPECT_EQ(controller().GetEntryAtIndex(0)->url(), url1);
+}
+
+// Test call to PruneAllButActive for last entry.
+TEST_F(NavigationControllerTest, PruneAllButActiveForLast) {
+ const GURL url1("http://foo1");
+ const GURL url2("http://foo2");
+ const GURL url3("http://foo3");
+
+ NavigateAndCommit(url1);
+ NavigateAndCommit(url2);
+ NavigateAndCommit(url3);
+ controller().GoBack();
+ controller().GoBack();
+ contents()->CommitPendingNavigation();
+
+ controller().PruneAllButActive();
+
+ EXPECT_EQ(-1, controller().pending_entry_index());
+ EXPECT_EQ(controller().GetEntryAtIndex(0)->url(), url1);
+}
+
+// Test call to PruneAllButActive for intermediate entry.
+TEST_F(NavigationControllerTest, PruneAllButActiveForIntermediate) {
+ const GURL url1("http://foo1");
+ const GURL url2("http://foo2");
+ const GURL url3("http://foo3");
+
+ NavigateAndCommit(url1);
+ NavigateAndCommit(url2);
+ NavigateAndCommit(url3);
+ controller().GoBack();
+ contents()->CommitPendingNavigation();
+
+ controller().PruneAllButActive();
+
+ EXPECT_EQ(-1, controller().pending_entry_index());
+ EXPECT_EQ(controller().GetEntryAtIndex(0)->url(), url2);
+}
+
+// Test call to PruneAllButActive for intermediate entry.
+TEST_F(NavigationControllerTest, PruneAllButActiveForPending) {
+ const GURL url1("http://foo1");
+ const GURL url2("http://foo2");
+ const GURL url3("http://foo3");
+
+ NavigateAndCommit(url1);
+ NavigateAndCommit(url2);
+ NavigateAndCommit(url3);
+ controller().GoBack();
+
+ controller().PruneAllButActive();
+
+ EXPECT_EQ(0, controller().pending_entry_index());
+}
+
+// Test call to PruneAllButActive for transient entry.
+TEST_F(NavigationControllerTest, PruneAllButActiveForTransient) {
+ const GURL url0("http://foo0");
+ const GURL url1("http://foo1");
+ const GURL transient_url("http://transient");
+
+ controller().LoadURL(url0, GURL(), PageTransition::TYPED);
+ rvh()->SendNavigate(0, url0);
+ controller().LoadURL(url1, GURL(), PageTransition::TYPED);
+ rvh()->SendNavigate(1, url1);
+
+ // Adding a transient with no pending entry.
+ NavigationEntry* transient_entry = new NavigationEntry;
+ transient_entry->set_url(transient_url);
+ controller().AddTransientEntry(transient_entry);
+
+ controller().PruneAllButActive();
+
+ EXPECT_EQ(-1, controller().pending_entry_index());
+ EXPECT_EQ(-1, controller().pending_entry_index());
+ EXPECT_EQ(controller().GetTransientEntry()->url(), transient_url);
+}
+
/* TODO(brettw) These test pass on my local machine but fail on the XP buildbot
(but not Vista) cleaning up the directory after they run.
This should be fixed.
diff --git a/chrome/browser/tab_contents/navigation_entry.cc b/chrome/browser/tab_contents/navigation_entry.cc
index c345958..a14fc08 100644
--- a/chrome/browser/tab_contents/navigation_entry.cc
+++ b/chrome/browser/tab_contents/navigation_entry.cc
@@ -5,10 +5,11 @@
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "app/resource_bundle.h"
+#include "app/text_elider.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/common/chrome_constants.h"
@@ -102,7 +103,9 @@ const string16& NavigationEntry::GetTitleForDisplay(
} else if (!url_.is_empty()) {
title = net::FormatUrl(url_, languages);
}
- ElideString(UTF16ToWideHack(title), chrome::kMaxTitleChars, &elided_title);
+ gfx::ElideString(UTF16ToWideHack(title),
+ chrome::kMaxTitleChars,
+ &elided_title);
cached_display_title_ = WideToUTF16Hack(elided_title);
return cached_display_title_;
}
diff --git a/chrome/browser/tab_contents/popup_menu_helper_mac.mm b/chrome/browser/tab_contents/popup_menu_helper_mac.mm
index 0e910b7..aea6a7b 100644
--- a/chrome/browser/tab_contents/popup_menu_helper_mac.mm
+++ b/chrome/browser/tab_contents/popup_menu_helper_mac.mm
@@ -6,12 +6,12 @@
#include "chrome/browser/tab_contents/popup_menu_helper_mac.h"
-#import "base/chrome_application_mac.h"
#include "base/message_loop.h"
#include "base/scoped_nsobject.h"
-#import "chrome/browser/cocoa/base_view.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view_mac.h"
+#import "chrome/browser/ui/cocoa/base_view.h"
+#import "chrome/common/chrome_application_mac.h"
#include "chrome/common/notification_source.h"
#include "webkit/glue/webmenurunner_mac.h"
diff --git a/chrome/browser/tab_contents/provisional_load_details.cc b/chrome/browser/tab_contents/provisional_load_details.cc
index dedf3e8..3cd59a7 100644
--- a/chrome/browser/tab_contents/provisional_load_details.cc
+++ b/chrome/browser/tab_contents/provisional_load_details.cc
@@ -12,7 +12,8 @@ ProvisionalLoadDetails::ProvisionalLoadDetails(bool is_main_frame,
const GURL& url,
const std::string& security_info,
bool is_content_filtered,
- long long frame_id)
+ bool is_error_page,
+ int64 frame_id)
: error_code_(net::OK),
transition_type_(PageTransition::LINK),
url_(url),
@@ -23,6 +24,7 @@ ProvisionalLoadDetails::ProvisionalLoadDetails(bool is_main_frame,
ssl_security_bits_(-1),
ssl_connection_status_(0),
is_content_filtered_(is_content_filtered),
+ is_error_page_(is_error_page),
frame_id_(frame_id) {
SSLManager::DeserializeSecurityInfo(security_info,
&ssl_cert_id_,
diff --git a/chrome/browser/tab_contents/provisional_load_details.h b/chrome/browser/tab_contents/provisional_load_details.h
index a9b0baa..732d52c 100644
--- a/chrome/browser/tab_contents/provisional_load_details.h
+++ b/chrome/browser/tab_contents/provisional_load_details.h
@@ -28,7 +28,8 @@ class ProvisionalLoadDetails {
const GURL& url,
const std::string& security_info,
bool is_filtered,
- long long frame_id);
+ bool is_error_page,
+ int64 frame_id);
virtual ~ProvisionalLoadDetails() { }
void set_error_code(int error_code) { error_code_ = error_code; }
@@ -57,7 +58,9 @@ class ProvisionalLoadDetails {
bool is_content_filtered() const { return is_content_filtered_; }
- long long frame_id() const { return frame_id_; }
+ bool is_error_page() const { return is_error_page_; }
+
+ int64 frame_id() const { return frame_id_; }
private:
int error_code_;
@@ -70,7 +73,8 @@ class ProvisionalLoadDetails {
int ssl_security_bits_;
int ssl_connection_status_;
bool is_content_filtered_;
- long long frame_id_;
+ bool is_error_page_;
+ int64 frame_id_;
DISALLOW_COPY_AND_ASSIGN(ProvisionalLoadDetails);
};
diff --git a/chrome/browser/tab_contents/render_view_context_menu.cc b/chrome/browser/tab_contents/render_view_context_menu.cc
index 20d77d3..2ee6d08 100644
--- a/chrome/browser/tab_contents/render_view_context_menu.cc
+++ b/chrome/browser/tab_contents/render_view_context_menu.cc
@@ -14,6 +14,7 @@
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/autocomplete/autocomplete_classifier.h"
#include "chrome/browser/autocomplete/autocomplete_edit.h"
@@ -24,7 +25,7 @@
#include "chrome/browser/debugger/devtools_window.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/extensions/extension_event_router.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/fonts_languages_window.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/net/browser_url_util.h"
@@ -32,7 +33,7 @@
#include "chrome/browser/platform_util.h"
#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
@@ -182,7 +183,7 @@ static ExtensionMenuItem::List GetRelevantExtensionItems(
void RenderViewContextMenu::AppendExtensionItems(
const std::string& extension_id, int* index) {
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
ExtensionMenuManager* manager = service->menu_manager();
const Extension* extension = service->GetExtensionById(extension_id, false);
bool can_cross_incognito = service->CanCrossIncognito(extension);
@@ -301,7 +302,7 @@ void RenderViewContextMenu::RecursivelyAppendExtensionItems(
}
void RenderViewContextMenu::SetExtensionIcon(const std::string& extension_id) {
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
ExtensionMenuManager* menu_manager = service->menu_manager();
int index = menu_model_.GetItemCount() - 1;
@@ -316,7 +317,7 @@ void RenderViewContextMenu::SetExtensionIcon(const std::string& extension_id) {
void RenderViewContextMenu::AppendAllExtensionItems() {
extension_item_map_.clear();
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
if (!service)
return; // In unit-tests, we may not have an ExtensionService.
ExtensionMenuManager* menu_manager = service->menu_manager();
@@ -551,15 +552,6 @@ void RenderViewContextMenu::AppendFrameItems() {
menu_model_.AddSeparator();
menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOADFRAME,
IDS_CONTENT_CONTEXT_RELOADFRAME);
- menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENFRAMENEWTAB,
- IDS_CONTENT_CONTEXT_OPENFRAMENEWTAB);
- menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENFRAMENEWWINDOW,
- IDS_CONTENT_CONTEXT_OPENFRAMENEWWINDOW);
- if (!external_) {
- menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENFRAMEOFFTHERECORD,
- IDS_CONTENT_CONTEXT_OPENFRAMEOFFTHERECORD);
- }
-
menu_model_.AddSeparator();
// These two menu items have yet to be implemented.
// http://code.google.com/p/chromium/issues/detail?id=11827
@@ -584,7 +576,8 @@ void RenderViewContextMenu::AppendSearchProvider() {
return;
AutocompleteMatch match;
- profile_->GetAutocompleteClassifier()->Classify(params_.selection_text,
+ profile_->GetAutocompleteClassifier()->Classify(
+ UTF16ToWideHack(params_.selection_text),
std::wstring(), false, &match, NULL);
selection_navigation_url_ = match.destination_url;
if (!selection_navigation_url_.is_valid())
@@ -734,7 +727,7 @@ void RenderViewContextMenu::AppendBidiSubMenu() {
ExtensionMenuItem* RenderViewContextMenu::GetExtensionMenuItem(int id) const {
ExtensionMenuManager* manager =
- profile_->GetExtensionsService()->menu_manager();
+ profile_->GetExtensionService()->menu_manager();
std::map<int, ExtensionMenuItem::Id>::const_iterator i =
extension_item_map_.find(id);
if (i != extension_item_map_.end()) {
@@ -847,11 +840,11 @@ bool RenderViewContextMenu::IsCommandIdEnabled(int id) const {
case IDC_CONTENT_CONTEXT_SAVELINKAS:
return params_.link_url.is_valid() &&
- URLRequest::IsHandledURL(params_.link_url);
+ net::URLRequest::IsHandledURL(params_.link_url);
case IDC_CONTENT_CONTEXT_SAVEIMAGEAS:
return params_.src_url.is_valid() &&
- URLRequest::IsHandledURL(params_.src_url);
+ net::URLRequest::IsHandledURL(params_.src_url);
case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
// The images shown in the most visited thumbnails do not currently open
@@ -895,7 +888,7 @@ bool RenderViewContextMenu::IsCommandIdEnabled(int id) const {
return (params_.media_flags &
WebContextMenuData::MediaCanSave) &&
params_.src_url.is_valid() &&
- URLRequest::IsHandledURL(params_.src_url);
+ net::URLRequest::IsHandledURL(params_.src_url);
case IDC_CONTENT_CONTEXT_OPENAVNEWTAB:
return true;
@@ -912,8 +905,6 @@ bool RenderViewContextMenu::IsCommandIdEnabled(int id) const {
}
case IDC_CONTENT_CONTEXT_RELOADFRAME:
- case IDC_CONTENT_CONTEXT_OPENFRAMENEWTAB:
- case IDC_CONTENT_CONTEXT_OPENFRAMENEWWINDOW:
return params_.frame_url.is_valid();
case IDC_CONTENT_CONTEXT_UNDO:
@@ -940,9 +931,6 @@ bool RenderViewContextMenu::IsCommandIdEnabled(int id) const {
case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD:
return !profile_->IsOffTheRecord() && params_.link_url.is_valid();
- case IDC_CONTENT_CONTEXT_OPENFRAMEOFFTHERECORD:
- return !profile_->IsOffTheRecord() && params_.frame_url.is_valid();
-
case IDC_SPELLCHECK_ADD_TO_DICTIONARY:
return !params_.misspelled_word.empty();
@@ -1096,7 +1084,7 @@ void RenderViewContextMenu::ExecuteCommand(int id) {
if (id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) {
ExtensionMenuManager* manager =
- profile_->GetExtensionsService()->menu_manager();
+ profile_->GetExtensionService()->menu_manager();
std::map<int, ExtensionMenuItem::Id>::const_iterator i =
extension_item_map_.find(id);
if (i != extension_item_map_.end()) {
@@ -1228,8 +1216,7 @@ void RenderViewContextMenu::ExecuteCommand(int id) {
break;
case IDC_VIEW_SOURCE:
- OpenURL(GURL(chrome::kViewSourceScheme + std::string(":") +
- params_.page_url.spec()), NEW_FOREGROUND_TAB, PageTransition::LINK);
+ source_tab_contents_->ViewSource();
break;
case IDC_CONTENT_CONTEXT_INSPECTELEMENT:
@@ -1260,7 +1247,7 @@ void RenderViewContextMenu::ExecuteCommand(int id) {
TranslatePrefs prefs(profile_->GetPrefs());
prefs.RemoveLanguageFromBlacklist(original_lang);
prefs.RemoveSiteFromBlacklist(params_.page_url.HostNoBrackets());
- Singleton<TranslateManager>::get()->TranslatePage(
+ TranslateManager::GetInstance()->TranslatePage(
source_tab_contents_, original_lang, target_lang);
break;
}
@@ -1269,18 +1256,6 @@ void RenderViewContextMenu::ExecuteCommand(int id) {
source_tab_contents_->render_view_host()->ReloadFrame();
break;
- case IDC_CONTENT_CONTEXT_OPENFRAMENEWTAB:
- OpenURL(params_.frame_url, NEW_BACKGROUND_TAB, PageTransition::LINK);
- break;
-
- case IDC_CONTENT_CONTEXT_OPENFRAMENEWWINDOW:
- OpenURL(params_.frame_url, NEW_WINDOW, PageTransition::LINK);
- break;
-
- case IDC_CONTENT_CONTEXT_OPENFRAMEOFFTHERECORD:
- OpenURL(params_.frame_url, OFF_THE_RECORD, PageTransition::LINK);
- break;
-
case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE:
OpenURL(GURL(chrome::kViewSourceScheme + std::string(":") +
params_.frame_url.spec()), NEW_FOREGROUND_TAB, PageTransition::LINK);
@@ -1456,8 +1431,8 @@ bool RenderViewContextMenu::IsDevCommandEnabled(int id) const {
}
string16 RenderViewContextMenu::PrintableSelectionText() {
- return WideToUTF16(l10n_util::TruncateString(params_.selection_text,
- kMaxSelectionTextLength));
+ return l10n_util::TruncateString(params_.selection_text,
+ kMaxSelectionTextLength);
}
// Controller functions --------------------------------------------------------
diff --git a/chrome/browser/tab_contents/render_view_context_menu_gtk.cc b/chrome/browser/tab_contents/render_view_context_menu_gtk.cc
index 120ea9e..4c2a6d3 100644
--- a/chrome/browser/tab_contents/render_view_context_menu_gtk.cc
+++ b/chrome/browser/tab_contents/render_view_context_menu_gtk.cc
@@ -34,6 +34,12 @@ void RenderViewContextMenuGtk::PlatformInit() {
}
}
+bool RenderViewContextMenuGtk::GetAcceleratorForCommandId(
+ int command_id,
+ menus::Accelerator* accelerator) {
+ return false;
+}
+
void RenderViewContextMenuGtk::Popup(const gfx::Point& point) {
RenderWidgetHostView* rwhv = source_tab_contents_->GetRenderWidgetHostView();
if (rwhv)
diff --git a/chrome/browser/tab_contents/render_view_context_menu_gtk.h b/chrome/browser/tab_contents/render_view_context_menu_gtk.h
index 863e21e..f9da630 100644
--- a/chrome/browser/tab_contents/render_view_context_menu_gtk.h
+++ b/chrome/browser/tab_contents/render_view_context_menu_gtk.h
@@ -35,9 +35,7 @@ class RenderViewContextMenuGtk : public RenderViewContextMenu,
// TODO(port): implement.
virtual bool GetAcceleratorForCommandId(
int command_id,
- menus::Accelerator* accelerator) {
- return false;
- }
+ menus::Accelerator* accelerator);
private:
scoped_ptr<MenuGtk> menu_gtk_;
diff --git a/chrome/browser/tab_contents/render_view_context_menu_mac.mm b/chrome/browser/tab_contents/render_view_context_menu_mac.mm
index 2b9ca36..ef0cf60 100644
--- a/chrome/browser/tab_contents/render_view_context_menu_mac.mm
+++ b/chrome/browser/tab_contents/render_view_context_menu_mac.mm
@@ -9,7 +9,7 @@
#include "base/scoped_nsobject.h"
#include "base/sys_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
-#import "chrome/browser/cocoa/menu_controller.h"
+#import "chrome/browser/ui/cocoa/menu_controller.h"
#include "grit/generated_resources.h"
// Obj-C bridge class that is the target of all items in the context menu.
@@ -75,7 +75,7 @@ void RenderViewContextMenuMac::LookUpInDictionary() {
// TODO(morrita): On Safari, A dictionary panel could be shown
// based on a preference setting of Dictionary.app. We currently
// don't support it: http://crbug.com/17951
- NSString* text = base::SysWideToNSString(params_.selection_text);
+ NSString* text = base::SysUTF16ToNSString(params_.selection_text);
NSPasteboard* pboard = [NSPasteboard pasteboardWithUniqueName];
// 10.5 and earlier require declareTypes before setData.
// See the documentation on [NSPasteboard declareTypes].
diff --git a/chrome/browser/tab_contents/render_view_host_delegate_helper.cc b/chrome/browser/tab_contents/render_view_host_delegate_helper.cc
index 276b72a..491e7f6 100644
--- a/chrome/browser/tab_contents/render_view_host_delegate_helper.cc
+++ b/chrome/browser/tab_contents/render_view_host_delegate_helper.cc
@@ -4,14 +4,16 @@
#include "chrome/browser/tab_contents/render_view_host_delegate_helper.h"
+#include <string>
+
#include "base/command_line.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/background_contents_service.h"
#include "chrome/browser/character_encoding.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_widget_fullscreen_host.h"
@@ -23,7 +25,6 @@
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/user_style_sheet_watcher.h"
#include "chrome/common/chrome_switches.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
RenderViewHostDelegateViewHelper::RenderViewHostDelegateViewHelper() {}
@@ -37,7 +38,7 @@ RenderViewHostDelegateViewHelper::MaybeCreateBackgroundContents(
SiteInstance* site,
const GURL& opener_url,
const string16& frame_name) {
- ExtensionsService* extensions_service = profile->GetExtensionsService();
+ ExtensionService* extensions_service = profile->GetExtensionService();
if (!opener_url.is_valid() ||
frame_name.empty() ||
@@ -197,19 +198,19 @@ WebPreferences RenderViewHostDelegateHelper::GetWebkitPrefs(
WebPreferences web_prefs;
web_prefs.fixed_font_family =
- UTF8ToWide(prefs->GetString(prefs::kWebKitFixedFontFamily));
+ UTF8ToUTF16(prefs->GetString(prefs::kWebKitFixedFontFamily));
web_prefs.serif_font_family =
- UTF8ToWide(prefs->GetString(prefs::kWebKitSerifFontFamily));
+ UTF8ToUTF16(prefs->GetString(prefs::kWebKitSerifFontFamily));
web_prefs.sans_serif_font_family =
- UTF8ToWide(prefs->GetString(prefs::kWebKitSansSerifFontFamily));
+ UTF8ToUTF16(prefs->GetString(prefs::kWebKitSansSerifFontFamily));
if (prefs->GetBoolean(prefs::kWebKitStandardFontIsSerif))
web_prefs.standard_font_family = web_prefs.serif_font_family;
else
web_prefs.standard_font_family = web_prefs.sans_serif_font_family;
web_prefs.cursive_font_family =
- UTF8ToWide(prefs->GetString(prefs::kWebKitCursiveFontFamily));
+ UTF8ToUTF16(prefs->GetString(prefs::kWebKitCursiveFontFamily));
web_prefs.fantasy_font_family =
- UTF8ToWide(prefs->GetString(prefs::kWebKitFantasyFontFamily));
+ UTF8ToUTF16(prefs->GetString(prefs::kWebKitFantasyFontFamily));
web_prefs.default_font_size =
prefs->GetInteger(prefs::kWebKitDefaultFontSize);
diff --git a/chrome/browser/tab_contents/render_view_host_manager.cc b/chrome/browser/tab_contents/render_view_host_manager.cc
index c9e6373..bcc9a78 100644
--- a/chrome/browser/tab_contents/render_view_host_manager.cc
+++ b/chrome/browser/tab_contents/render_view_host_manager.cc
@@ -8,8 +8,8 @@
#include "base/logging.h"
#include "chrome/browser/dom_ui/dom_ui.h"
#include "chrome/browser/dom_ui/dom_ui_factory.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
#include "chrome/browser/renderer_host/render_view_host_factory.h"
@@ -17,6 +17,7 @@
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
+#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
@@ -479,8 +480,8 @@ bool RenderViewHostManager::InitRenderView(RenderViewHost* render_view_host,
// Tell the RenderView whether it will be used for an extension process.
Profile* profile = delegate_->GetControllerForRenderManager().profile();
- bool is_extension_process = profile->GetExtensionsService() &&
- profile->GetExtensionsService()->ExtensionBindingsAllowed(entry.url());
+ bool is_extension_process = profile->GetExtensionService() &&
+ profile->GetExtensionService()->ExtensionBindingsAllowed(entry.url());
render_view_host->set_is_extension_process(is_extension_process);
return delegate_->CreateRenderViewForRenderManager(render_view_host);
@@ -677,3 +678,45 @@ void RenderViewHostManager::RenderViewDeleted(RenderViewHost* rvh) {
pending_render_view_host_ = NULL;
}
}
+
+void RenderViewHostManager::SwapInRenderViewHost(RenderViewHost* rvh) {
+ dom_ui_.reset();
+
+ // Hide the current view and prepare to destroy it.
+ if (render_view_host_->view())
+ render_view_host_->view()->Hide();
+ RenderViewHost* old_render_view_host = render_view_host_;
+
+ // Swap in the new view and make it active.
+ render_view_host_ = rvh;
+ render_view_host_->set_delegate(render_view_delegate_);
+ delegate_->CreateViewAndSetSizeForRVH(render_view_host_);
+ render_view_host_->ActivateDeferredPluginHandles();
+ // If the view is gone, then this RenderViewHost died while it was hidden.
+ // We ignored the RenderViewGone call at the time, so we should send it now
+ // to make sure the sad tab shows up, etc.
+ if (render_view_host_->view()) {
+ // TODO(tburkard,cbentzel): Figure out why this hack is needed and/or
+ // if it can be removed. On Windows, prerendering will not work without
+ // doing a Hide before the Show.
+ render_view_host_->view()->Hide();
+ render_view_host_->view()->Show();
+ }
+
+ delegate_->UpdateRenderViewSizeForRenderManager();
+
+ RenderViewHostSwitchedDetails details;
+ details.new_host = render_view_host_;
+ details.old_host = old_render_view_host;
+ NotificationService::current()->Notify(
+ NotificationType::RENDER_VIEW_HOST_CHANGED,
+ Source<NavigationController>(&delegate_->GetControllerForRenderManager()),
+ Details<RenderViewHostSwitchedDetails>(&details));
+
+ // This will cause the old RenderViewHost to delete itself.
+ old_render_view_host->Shutdown();
+
+ // Let the task manager know that we've swapped RenderViewHosts, since it
+ // might need to update its process groupings.
+ delegate_->NotifySwappedFromRenderManager();
+}
diff --git a/chrome/browser/tab_contents/render_view_host_manager.h b/chrome/browser/tab_contents/render_view_host_manager.h
index 01a8f0d..345b9cd 100644
--- a/chrome/browser/tab_contents/render_view_host_manager.h
+++ b/chrome/browser/tab_contents/render_view_host_manager.h
@@ -69,6 +69,9 @@ class RenderViewHostManager
// Focuses the location bar.
virtual void SetFocusToLocationBar(bool select_all) = 0;
+ // Creates a view and sets the size for the specified RVH.
+ virtual void CreateViewAndSetSizeForRVH(RenderViewHost* rvh) = 0;
+
protected:
virtual ~Delegate() {}
};
@@ -172,6 +175,11 @@ class RenderViewHostManager
// Called when a RenderViewHost is about to be deleted.
void RenderViewDeleted(RenderViewHost* rvh);
+ // Allows a caller to swap in a provided RenderViewHost to replace the
+ // current RenderViewHost. The current RVH will be shutdown and ultimately
+ // deleted.
+ void SwapInRenderViewHost(RenderViewHost* rvh);
+
private:
friend class TestTabContents;
friend class RenderViewHostManagerTest;
diff --git a/chrome/browser/tab_contents/render_view_host_manager_unittest.cc b/chrome/browser/tab_contents/render_view_host_manager_unittest.cc
index ece7e64..d6a58a1 100644
--- a/chrome/browser/tab_contents/render_view_host_manager_unittest.cc
+++ b/chrome/browser/tab_contents/render_view_host_manager_unittest.cc
@@ -10,6 +10,8 @@
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/render_view_host_manager.h"
#include "chrome/browser/tab_contents/test_tab_contents.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/render_messages_params.h"
#include "chrome/common/url_constants.h"
diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc
index 67acf2f..3dba1a8 100644
--- a/chrome/browser/tab_contents/tab_contents.cc
+++ b/chrome/browser/tab_contents/tab_contents.cc
@@ -8,48 +8,39 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
-#if defined(OS_MACOSX)
-#include "app/surface/io_surface_support_mac.h"
-#endif
-#include "app/text_elider.h"
#include "base/auto_reset.h"
-#include "base/file_version_info.h"
-#include "base/i18n/rtl.h"
#include "base/metrics/histogram.h"
-#include "base/process_util.h"
#include "base/string16.h"
#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
#include "base/time.h"
+#include "base/utf_string_conversions.h"
#include "chrome/browser/autocomplete_history_manager.h"
#include "chrome/browser/autofill/autofill_manager.h"
#include "chrome/browser/blocked_content_container.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_shutdown.h"
-#include "chrome/browser/cert_store.h"
#include "chrome/browser/character_encoding.h"
+#include "chrome/browser/content_settings/content_settings_details.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/dom_operation_notification_details.h"
#include "chrome/browser/dom_ui/dom_ui.h"
-#include "chrome/browser/dom_ui/dom_ui_factory.h"
#include "chrome/browser/download/download_item_model.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/download/download_request_limiter.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/external_protocol_handler.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/history/history_types.h"
-#include "chrome/browser/history/top_sites.h"
-#include "chrome/browser/host_zoom_map.h"
#include "chrome/browser/favicon_service.h"
#include "chrome/browser/file_select_helper.h"
-#include "chrome/browser/find_bar_state.h"
#include "chrome/browser/google/google_util.h"
-#include "chrome/browser/host_content_settings_map.h"
+#include "chrome/browser/history/history.h"
+#include "chrome/browser/history/history_types.h"
+#include "chrome/browser/history/top_sites.h"
+#include "chrome/browser/host_zoom_map.h"
#include "chrome/browser/hung_renderer_dialog.h"
#include "chrome/browser/in_process_webkit/session_storage_namespace.h"
-#include "chrome/browser/message_box_handler.h"
#include "chrome/browser/load_from_memory_cache_details.h"
#include "chrome/browser/load_notification_details.h"
#include "chrome/browser/metrics/metric_event_duration_details.h"
@@ -58,9 +49,10 @@
#include "chrome/browser/platform_util.h"
#include "chrome/browser/plugin_installer.h"
#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/prerender/prerender_manager.h"
#include "chrome/browser/printing/print_preview_tab_controller.h"
#include "chrome/browser/printing/print_view_manager.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
@@ -80,11 +72,13 @@
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
#include "chrome/browser/tab_contents/tab_contents_ssl_helper.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
-#include "chrome/browser/tab_contents/thumbnail_generator.h"
#include "chrome/browser/tab_contents/web_navigation_observer.h"
#include "chrome/browser/translate/page_translated_details.h"
+#include "chrome/browser/ui/app_modal_dialogs/message_box_handler.h"
+#include "chrome/browser/ui/find_bar/find_bar_state.h"
#include "chrome/common/bindings_policy.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/content_restriction.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_action.h"
#include "chrome/common/extensions/extension_icon_set.h"
@@ -96,21 +90,23 @@
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/render_messages_params.h"
-#include "chrome/common/renderer_preferences.h"
#include "chrome/common/url_constants.h"
+#include "gfx/codec/png_codec.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "grit/platform_locale_settings.h"
#include "grit/theme_resources.h"
-#include "net/base/mime_util.h"
-#include "net/base/net_errors.h"
#include "net/base/net_util.h"
#include "net/base/registry_controlled_domain.h"
#include "third_party/WebKit/WebKit/chromium/public/WebView.h"
-#include "webkit/glue/webpreferences.h"
#include "webkit/glue/password_form.h"
-#include "webkit/glue/plugins/plugin_list.h"
+#include "webkit/plugins/npapi/plugin_list.h"
+#include "webkit/glue/webpreferences.h"
+
+#if defined(OS_MACOSX)
+#include "app/surface/io_surface_support_mac.h"
+#endif // defined(OS_MACOSX)
// Cross-Site Navigations
//
@@ -243,9 +239,9 @@ void MakeNavigateParams(const NavigationEntry& entry,
params->request_time = base::Time::Now();
}
-class DisabledPluginInfoBar : public ConfirmInfoBarDelegate {
+class OutdatedPluginInfoBar : public ConfirmInfoBarDelegate {
public:
- DisabledPluginInfoBar(TabContents* tab_contents,
+ OutdatedPluginInfoBar(TabContents* tab_contents,
const string16& name,
const GURL& update_url)
: ConfirmInfoBarDelegate(tab_contents),
@@ -287,9 +283,8 @@ class DisabledPluginInfoBar : public ConfirmInfoBarDelegate {
}
virtual bool Cancel() {
- tab_contents_->OpenURL(GURL(chrome::kChromeUIPluginsURL), GURL(),
- NEW_FOREGROUND_TAB, PageTransition::LINK);
- return false;
+ tab_contents_->render_view_host()->LoadBlockedPlugins();
+ return true;
}
virtual bool LinkClicked(WindowOpenDisposition disposition) {
@@ -298,6 +293,10 @@ class DisabledPluginInfoBar : public ConfirmInfoBarDelegate {
return false;
}
+ virtual void InfoBarClosed() {
+ delete this;
+ }
+
private:
TabContents* tab_contents_;
string16 name_;
@@ -334,7 +333,8 @@ TabContents::TabContents(Profile* profile,
bookmark_drag_(NULL),
ALLOW_THIS_IN_INITIALIZER_LIST(fav_icon_helper_(this)),
is_loading_(false),
- is_crashed_(false),
+ crashed_status_(base::TERMINATION_STATUS_STILL_RUNNING),
+ crashed_error_code_(0),
waiting_for_response_(false),
max_page_id_(-1),
current_load_start_(),
@@ -383,15 +383,6 @@ TabContents::TabContents(Profile* profile,
content_settings_delegate_.reset(
new TabSpecificContentSettings(this, profile));
-#if defined(OS_CHROMEOS)
- // Make sure the thumbnailer is started before starting the render manager.
- // The thumbnailer will want to listen for RVH creations, one of which will
- // happen in RVHManager::Init.
- ThumbnailGenerator* generator = g_browser_process->GetThumbnailGenerator();
- if (generator)
- generator->StartThumbnailing();
-#endif
-
render_manager_.Init(profile, site_instance, routing_id);
// We have the initial size of the view be based on the size of the passed in
@@ -431,8 +422,6 @@ TabContents::TabContents(Profile* profile,
NotificationService::AllSources());
registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
NotificationService::AllSources());
- registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED,
- NotificationService::AllSources());
// Listen for Google URL changes
registrar_.Add(this, NotificationType::GOOGLE_URL_UPDATED,
@@ -602,7 +591,7 @@ void TabContents::SetExtensionAppById(const std::string& extension_app_id) {
if (extension_app_id.empty())
return;
- ExtensionsService* extension_service = profile()->GetExtensionsService();
+ ExtensionService* extension_service = profile()->GetExtensionService();
if (!extension_service || !extension_service->is_ready())
return;
@@ -774,11 +763,12 @@ void TabContents::RemoveNavigationObserver(WebNavigationObserver* observer) {
web_navigation_observers_.RemoveObserver(observer);
}
-void TabContents::SetIsCrashed(bool state) {
- if (state == is_crashed_)
+void TabContents::SetIsCrashed(base::TerminationStatus status, int error_code) {
+ if (status == crashed_status_)
return;
- is_crashed_ = state;
+ crashed_status_ = status;
+ crashed_error_code_ = error_code;
NotifyNavigationStateChanged(INVALIDATE_TAB);
}
@@ -977,6 +967,33 @@ void TabContents::ShowPageInfo(const GURL& url,
delegate_->ShowPageInfo(profile(), url, ssl, show_history);
}
+void TabContents::SaveFavicon() {
+ NavigationEntry* entry = controller_.GetActiveEntry();
+ if (!entry || entry->url().is_empty())
+ return;
+
+ // Make sure the page is in history, otherwise adding the favicon does
+ // nothing.
+ HistoryService* history = profile()->GetOriginalProfile()->GetHistoryService(
+ Profile::IMPLICIT_ACCESS);
+ if (!history)
+ return;
+ history->AddPageNoVisitForBookmark(entry->url());
+
+ FaviconService* service = profile()->GetOriginalProfile()->GetFaviconService(
+ Profile::IMPLICIT_ACCESS);
+ if (!service)
+ return;
+ const NavigationEntry::FaviconStatus& favicon(entry->favicon());
+ if (!favicon.is_valid() || favicon.url().is_empty() ||
+ favicon.bitmap().empty()) {
+ return;
+ }
+ std::vector<unsigned char> image_data;
+ gfx::PNGCodec::EncodeBGRASkBitmap(favicon.bitmap(), false, &image_data);
+ service->SetFavicon(entry->url(), favicon.url(), image_data);
+}
+
ConstrainedWindow* TabContents::CreateConstrainedDialog(
ConstrainedWindowDelegate* delegate) {
ConstrainedWindow* window =
@@ -1527,6 +1544,17 @@ int TabContents::GetZoomPercent(bool* enable_increment,
return percent;
}
+void TabContents::ViewSource() {
+ if (!delegate_)
+ return;
+
+ NavigationEntry* active_entry = controller().GetActiveEntry();
+ if (!active_entry)
+ return;
+
+ delegate_->ViewSourceForTab(this, active_entry->url());
+}
+
// Notifies the RenderWidgetHost instance about the fact that the page is
// loading, or done loading and calls the base implementation.
void TabContents::SetIsLoading(bool is_loading,
@@ -1690,7 +1718,7 @@ void TabContents::DidNavigateMainFramePostCommit(
// Clear all page actions, blocked content notifications and browser actions
// for this tab, unless this is an in-page navigation.
if (!details.is_in_page) {
- ExtensionsService* service = profile()->GetExtensionsService();
+ ExtensionService* service = profile()->GetExtensionService();
if (service) {
for (size_t i = 0; i < service->extensions()->size(); ++i) {
ExtensionAction* browser_action =
@@ -2057,8 +2085,8 @@ void TabContents::OnCrashedPlugin(const FilePath& plugin_path) {
DCHECK(!plugin_path.value().empty());
std::wstring plugin_name = plugin_path.ToWStringHack();
- WebPluginInfo plugin_info;
- if (NPAPI::PluginList::Singleton()->GetPluginInfoByPath(
+ webkit::npapi::WebPluginInfo plugin_info;
+ if (webkit::npapi::PluginList::Singleton()->GetPluginInfoByPath(
plugin_path, &plugin_info) &&
!plugin_info.name.empty()) {
plugin_name = UTF16ToWide(plugin_info.name);
@@ -2097,9 +2125,9 @@ void TabContents::OnInstallApplication(const WebApplicationInfo& info) {
delegate()->OnInstallApplication(this, info);
}
-void TabContents::OnDisabledOutdatedPlugin(const string16& name,
- const GURL& update_url) {
- new DisabledPluginInfoBar(this, name, update_url);
+void TabContents::OnBlockedOutdatedPlugin(const string16& name,
+ const GURL& update_url) {
+ new OutdatedPluginInfoBar(this, name, update_url);
}
void TabContents::OnPageContents(const GURL& url,
@@ -2163,18 +2191,24 @@ void TabContents::OnInstantSupportDetermined(int32 page_id, bool result) {
void TabContents::DidStartProvisionalLoadForFrame(
RenderViewHost* render_view_host,
- long long frame_id,
+ int64 frame_id,
bool is_main_frame,
+ bool is_error_page,
const GURL& url) {
ProvisionalLoadDetails details(is_main_frame,
controller_.IsURLInPageNavigation(url),
- url, std::string(), false, frame_id);
+ url, std::string(), false,
+ is_error_page, frame_id);
NotificationService::current()->Notify(
NotificationType::FRAME_PROVISIONAL_LOAD_START,
Source<NavigationController>(&controller_),
Details<ProvisionalLoadDetails>(&details));
if (is_main_frame) {
- content_settings_delegate_->ClearCookieSpecificContentSettings();
+ // If we're displaying a network error page do not reset the content
+ // settings delegate's cookies so the user has a chance to modify cookie
+ // settings.
+ if (!is_error_page)
+ content_settings_delegate_->ClearCookieSpecificContentSettings();
content_settings_delegate_->ClearGeolocationContentSettings();
}
}
@@ -2227,7 +2261,7 @@ void TabContents::DidRunInsecureContent(const std::string& security_origin) {
void TabContents::DidFailProvisionalLoadWithError(
RenderViewHost* render_view_host,
- long long frame_id,
+ int64 frame_id,
bool is_main_frame,
int error_code,
const GURL& url,
@@ -2273,7 +2307,7 @@ void TabContents::DidFailProvisionalLoadWithError(
// Send out a notification that we failed a provisional load with an error.
ProvisionalLoadDetails details(is_main_frame,
controller_.IsURLInPageNavigation(url),
- url, std::string(), false, frame_id);
+ url, std::string(), false, false, frame_id);
details.set_error_code(error_code);
NotificationService::current()->Notify(
@@ -2282,19 +2316,19 @@ void TabContents::DidFailProvisionalLoadWithError(
Details<ProvisionalLoadDetails>(&details));
}
-void TabContents::DocumentLoadedInFrame(long long frame_id) {
+void TabContents::DocumentLoadedInFrame(int64 frame_id) {
controller_.DocumentLoadedInFrame();
NotificationService::current()->Notify(
NotificationType::FRAME_DOM_CONTENT_LOADED,
Source<NavigationController>(&controller_),
- Details<long long>(&frame_id));
+ Details<int64>(&frame_id));
}
-void TabContents::DidFinishLoad(long long frame_id) {
+void TabContents::DidFinishLoad(int64 frame_id) {
NotificationService::current()->Notify(
NotificationType::FRAME_DID_FINISH_LOAD,
Source<NavigationController>(&controller_),
- Details<long long>(&frame_id));
+ Details<int64>(&frame_id));
}
void TabContents::OnContentSettingsAccessed(bool content_was_blocked) {
@@ -2424,7 +2458,7 @@ void TabContents::RenderViewReady(RenderViewHost* rvh) {
NotifyConnected();
bool was_crashed = is_crashed();
- SetIsCrashed(false);
+ SetIsCrashed(base::TERMINATION_STATUS_STILL_RUNNING, 0);
// Restore the focus to the tab (otherwise the focus will be on the top
// window).
@@ -2434,7 +2468,9 @@ void TabContents::RenderViewReady(RenderViewHost* rvh) {
}
}
-void TabContents::RenderViewGone(RenderViewHost* rvh) {
+void TabContents::RenderViewGone(RenderViewHost* rvh,
+ base::TerminationStatus status,
+ int error_code) {
// Ask the print preview if this renderer was valuable.
if (!printing_->OnRenderViewGone(rvh))
return;
@@ -2445,7 +2481,7 @@ void TabContents::RenderViewGone(RenderViewHost* rvh) {
SetIsLoading(false, NULL);
NotifyDisconnected();
- SetIsCrashed(true);
+ SetIsCrashed(status, error_code);
// Remove all infobars.
for (int i = infobar_delegate_count() - 1; i >=0 ; --i)
@@ -2475,6 +2511,16 @@ void TabContents::DidNavigate(RenderViewHost* rvh,
int extra_invalidate_flags = 0;
if (PageTransition::IsMainFrame(params.transition)) {
+ PrerenderManager* pm = profile()->GetPrerenderManager();
+ if (pm != NULL) {
+ if (pm->MaybeUsePreloadedPage(this, params.url)) {
+ // TODO(tburkard): If the preloaded page has not finished preloading
+ // yet, we should not do this.
+ DidStopLoading();
+ return;
+ }
+ }
+
bool was_bookmark_bar_visible = ShouldShowBookmarkBar();
render_manager_.DidNavigateMainFrame(rvh);
@@ -2513,7 +2559,7 @@ void TabContents::DidNavigate(RenderViewHost* rvh,
bool is_main_frame = did_navigate ? details.is_main_frame : false;
ProvisionalLoadDetails load_details(
is_main_frame, details.is_in_page, params.url, std::string(), false,
- params.frame_id);
+ false, params.frame_id);
load_details.set_transition_type(params.transition);
// Whether or not a page transition was triggered by going backward or
// forward in the history is only stored in the navigation controller's
@@ -2674,9 +2720,14 @@ void TabContents::RequestMove(const gfx::Rect& new_bounds) {
void TabContents::DidStartLoading() {
SetIsLoading(true, NULL);
- if (content_restrictions_) {
- content_restrictions_= 0;
- delegate()->ContentRestrictionsChanged(this);
+ if (delegate()) {
+ bool is_print_preview_tab =
+ printing::PrintPreviewTabController::IsPrintPreviewTab(this);
+ if (content_restrictions_ || is_print_preview_tab) {
+ content_restrictions_= is_print_preview_tab ?
+ CONTENT_RESTRICTION_PRINT : 0;
+ delegate()->ContentRestrictionsChanged(this);
+ }
}
// Notify observers about navigation.
@@ -2708,6 +2759,11 @@ void TabContents::DidStopLoading() {
DidStopLoading());
}
+void TabContents::DidChangeLoadProgress(double progress) {
+ if (delegate())
+ delegate()->LoadProgressChanged(progress);
+}
+
void TabContents::DocumentOnLoadCompletedInMainFrame(
RenderViewHost* render_view_host,
int32 page_id) {
@@ -3039,11 +3095,11 @@ void TabContents::DidInsertCSS() {
// This RVHDelegate function is used for extensions and not us.
}
-void TabContents::FocusedNodeChanged() {
+void TabContents::FocusedNodeChanged(bool is_editable_node) {
NotificationService::current()->Notify(
NotificationType::FOCUS_CHANGED_IN_PAGE,
Source<RenderViewHost>(render_view_host()),
- NotificationService::NoDetails());
+ Details<const bool>(&is_editable_node));
}
void TabContents::UpdateZoomLimits(int minimum_percent,
@@ -3073,7 +3129,8 @@ void TabContents::DidStartLoadingFromRenderManager(
void TabContents::RenderViewGoneFromRenderManager(
RenderViewHost* render_view_host) {
- RenderViewGone(render_view_host);
+ DCHECK(crashed_status_ != base::TERMINATION_STATUS_STILL_RUNNING);
+ RenderViewGone(render_view_host, crashed_status_, crashed_error_code_);
}
void TabContents::UpdateRenderViewSizeForRenderManager() {
@@ -3177,8 +3234,7 @@ void TabContents::Observe(NotificationType type,
break;
case NotificationType::CONTENT_SETTINGS_CHANGED: {
- Details<const HostContentSettingsMap::ContentSettingsDetails>
- settings_details(details);
+ Details<const ContentSettingsDetails> settings_details(details);
NavigationEntry* entry = controller_.GetActiveEntry();
GURL entry_url;
if (entry)
@@ -3196,7 +3252,6 @@ void TabContents::Observe(NotificationType type,
break;
case NotificationType::EXTENSION_UNLOADED:
- case NotificationType::EXTENSION_UNLOADED_DISABLED:
break;
case NotificationType::GOOGLE_URL_UPDATED:
@@ -3226,7 +3281,7 @@ void TabContents::UpdateExtensionAppIcon(const Extension* extension) {
}
const Extension* TabContents::GetExtensionContaining(const GURL& url) {
- ExtensionsService* extensions_service = profile()->GetExtensionsService();
+ ExtensionService* extensions_service = profile()->GetExtensionService();
if (!extensions_service)
return NULL;
@@ -3282,3 +3337,12 @@ void TabContents::SetAppIcon(const SkBitmap& app_icon) {
app_icon_ = app_icon;
NotifyNavigationStateChanged(INVALIDATE_TITLE);
}
+
+void TabContents::SwapInRenderViewHost(RenderViewHost* rvh) {
+ render_manager_.SwapInRenderViewHost(rvh);
+}
+
+void TabContents::CreateViewAndSetSizeForRVH(RenderViewHost* rvh) {
+ RenderWidgetHostView* rwh_view = view()->CreateViewForWidget(rvh);
+ rwh_view->SetSize(view()->GetContainerSize());
+}
diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h
index 6d4d2db..658bd84 100644
--- a/chrome/browser/tab_contents/tab_contents.h
+++ b/chrome/browser/tab_contents/tab_contents.h
@@ -48,14 +48,10 @@ private:
#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
#include "base/scoped_ptr.h"
-#include "chrome/browser/cancelable_request.h"
#include "chrome/browser/dom_ui/dom_ui_factory.h"
#include "chrome/browser/download/save_package.h"
#include "chrome/browser/extensions/image_loading_tracker.h"
#include "chrome/browser/fav_icon_helper.h"
-#include "chrome/browser/find_bar_controller.h"
-#include "chrome/browser/find_notification_details.h"
-#include "chrome/browser/js_modal_dialog.h"
#include "chrome/browser/prefs/pref_change_registrar.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
#include "chrome/browser/tab_contents/constrained_window.h"
@@ -65,6 +61,9 @@ private:
#include "chrome/browser/tab_contents/page_navigator.h"
#include "chrome/browser/tab_contents/render_view_host_manager.h"
#include "chrome/browser/tab_contents/tab_specific_content_settings.h"
+#include "chrome/browser/ui/app_modal_dialogs/js_modal_dialog.h"
+#include "chrome/browser/ui/find_bar/find_bar_controller.h"
+#include "chrome/browser/ui/find_bar/find_notification_details.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/property_bag.h"
#include "chrome/common/renderer_preferences.h"
@@ -105,6 +104,7 @@ class LoadNotificationDetails;
class OmniboxSearchHint;
class PluginInstaller;
class Profile;
+class PrerenderManager;
struct RendererPreferences;
class RenderViewHost;
class SessionStorageNamespace;
@@ -342,8 +342,14 @@ class TabContents : public PageNavigator,
// Indicates whether this tab should be considered crashed. The setter will
// also notify the delegate when the flag is changed.
- bool is_crashed() const { return is_crashed_; }
- void SetIsCrashed(bool state);
+ bool is_crashed() const {
+ return (crashed_status_ == base::TERMINATION_STATUS_PROCESS_CRASHED ||
+ crashed_status_ == base::TERMINATION_STATUS_ABNORMAL_TERMINATION ||
+ crashed_status_ == base::TERMINATION_STATUS_PROCESS_WAS_KILLED);
+ }
+ base::TerminationStatus crashed_status() const { return crashed_status_; }
+ int crashed_error_code() const { return crashed_error_code_; }
+ void SetIsCrashed(base::TerminationStatus status, int error_code);
// Call this after updating a page action to notify clients about the changes.
void PageActionStateChanged();
@@ -390,6 +396,11 @@ class TabContents : public PageNavigator,
RenderViewHostManager* render_manager() { return &render_manager_; }
#endif
+ // In the underlying RenderViewHostManager, swaps in the provided
+ // RenderViewHost to replace the current RenderViewHost. The current RVH
+ // will be shutdown and ultimately deleted.
+ void SwapInRenderViewHost(RenderViewHost* rvh);
+
// Commands ------------------------------------------------------------------
// Implementation of PageNavigator.
@@ -426,6 +437,9 @@ class TabContents : public PageNavigator,
const NavigationEntry::SSLStatus& ssl,
bool show_history);
+ // Saves the favicon for the current page.
+ void SaveFavicon();
+
// Window management ---------------------------------------------------------
// Create a new window constrained to this TabContents' clip and visibility.
@@ -496,6 +510,9 @@ class TabContents : public PageNavigator,
// Focuses the location bar.
virtual void SetFocusToLocationBar(bool select_all);
+ // Creates a view and sets the size for the specified RVH.
+ virtual void CreateViewAndSetSizeForRVH(RenderViewHost* rvh);
+
// Infobars ------------------------------------------------------------------
// Adds an InfoBar for the specified |delegate|.
@@ -756,9 +773,13 @@ class TabContents : public PageNavigator,
// Shows a fade effect over this tab contents. Repeated calls will be ignored
// until the fade is canceled. If |animate| is true the fade should animate.
void FadeForInstant(bool animate);
+
// Immediately removes the fade.
void CancelInstantFade();
+ // Opens view-source tab for this contents.
+ void ViewSource();
+
// Gets the minimum/maximum zoom percent.
int minimum_zoom_percent() const { return minimum_zoom_percent_; }
int maximum_zoom_percent() const { return maximum_zoom_percent_; }
@@ -794,6 +815,9 @@ class TabContents : public PageNavigator,
// Used to access the CreateHistoryAddPageArgs member function.
friend class ExternalTabContainer;
+ // Used to access RVH Delegates.
+ friend class PrerenderManager;
+
// Changes the IsLoading state and notifies delegate as needed
// |details| is used to provide details on the load that just finished
// (but can be null if not applicable). Can be overridden.
@@ -913,8 +937,8 @@ class TabContents : public PageNavigator,
virtual void OnDidGetApplicationInfo(int32 page_id,
const WebApplicationInfo& info);
virtual void OnInstallApplication(const WebApplicationInfo& info);
- virtual void OnDisabledOutdatedPlugin(const string16& name,
- const GURL& update_url);
+ virtual void OnBlockedOutdatedPlugin(const string16& name,
+ const GURL& update_url);
virtual void OnPageContents(const GURL& url,
int renderer_process_id,
int32 page_id,
@@ -931,8 +955,9 @@ class TabContents : public PageNavigator,
// RenderViewHostDelegate::Resource implementation.
virtual void DidStartProvisionalLoadForFrame(RenderViewHost* render_view_host,
- long long frame_id,
+ int64 frame_id,
bool is_main_frame,
+ bool is_error_page,
const GURL& url);
virtual void DidStartReceivingResourceResponse(
const ResourceRequestDetails& details);
@@ -950,13 +975,13 @@ class TabContents : public PageNavigator,
virtual void DidRunInsecureContent(const std::string& security_origin);
virtual void DidFailProvisionalLoadWithError(
RenderViewHost* render_view_host,
- long long frame_id,
+ int64 frame_id,
bool is_main_frame,
int error_code,
const GURL& url,
bool showing_repost_interstitial);
- virtual void DocumentLoadedInFrame(long long frame_id);
- virtual void DidFinishLoad(long long frame_id);
+ virtual void DocumentLoadedInFrame(int64 frame_id);
+ virtual void DidFinishLoad(int64 frame_id);
// RenderViewHostDelegate implementation.
virtual RenderViewHostDelegate::View* GetViewDelegate();
@@ -980,7 +1005,9 @@ class TabContents : public PageNavigator,
virtual int GetBrowserWindowID() const;
virtual void RenderViewCreated(RenderViewHost* render_view_host);
virtual void RenderViewReady(RenderViewHost* render_view_host);
- virtual void RenderViewGone(RenderViewHost* render_view_host);
+ virtual void RenderViewGone(RenderViewHost* render_view_host,
+ base::TerminationStatus status,
+ int error_code);
virtual void RenderViewDeleted(RenderViewHost* render_view_host);
virtual void DidNavigate(RenderViewHost* render_view_host,
const ViewHostMsg_FrameNavigate_Params& params);
@@ -1003,6 +1030,7 @@ class TabContents : public PageNavigator,
virtual void RequestMove(const gfx::Rect& new_bounds);
virtual void DidStartLoading();
virtual void DidStopLoading();
+ virtual void DidChangeLoadProgress(double progress);
virtual void DocumentOnLoadCompletedInMainFrame(
RenderViewHost* render_view_host,
int32 page_id);
@@ -1047,7 +1075,7 @@ class TabContents : public PageNavigator,
uint64 upload_position, uint64 upload_size);
virtual bool IsExternalTabContainer() const;
virtual void DidInsertCSS();
- virtual void FocusedNodeChanged();
+ virtual void FocusedNodeChanged(bool is_editable_node);
virtual void UpdateZoomLimits(int minimum_percent,
int maximum_percent,
bool remember);
@@ -1168,7 +1196,8 @@ class TabContents : public PageNavigator,
bool is_loading_;
// Indicates if the tab is considered crashed.
- bool is_crashed_;
+ base::TerminationStatus crashed_status_;
+ int crashed_error_code_;
// See waiting_for_response() above.
bool waiting_for_response_;
diff --git a/chrome/browser/tab_contents/tab_contents_delegate.cc b/chrome/browser/tab_contents/tab_contents_delegate.cc
index 21c13ff..987e620 100644
--- a/chrome/browser/tab_contents/tab_contents_delegate.cc
+++ b/chrome/browser/tab_contents/tab_contents_delegate.cc
@@ -5,12 +5,16 @@
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/common/url_constants.h"
#include "gfx/rect.h"
std::string TabContentsDelegate::GetNavigationHeaders(const GURL& url) {
return std::string();
}
+void TabContentsDelegate::LoadProgressChanged(double progress) {
+}
+
void TabContentsDelegate::DetachContents(TabContents* source) {
}
@@ -131,6 +135,20 @@ void TabContentsDelegate::ShowPageInfo(Profile* profile,
bool show_history) {
}
+void TabContentsDelegate::ViewSourceForTab(TabContents* source,
+ const GURL& page_url) {
+ // Fall back implementation based entirely on the view-source scheme.
+ // It suffers from http://crbug.com/523 and that is why browser overrides
+ // it with proper implementation.
+ GURL url = GURL(chrome::kViewSourceScheme + std::string(":") +
+ page_url.spec());
+ OpenURLFromTab(source,
+ url,
+ GURL(),
+ NEW_FOREGROUND_TAB,
+ PageTransition::LINK);
+}
+
bool TabContentsDelegate::PreHandleKeyboardEvent(
const NativeWebKeyboardEvent& event,
bool* is_keyboard_shortcut) {
diff --git a/chrome/browser/tab_contents/tab_contents_delegate.h b/chrome/browser/tab_contents/tab_contents_delegate.h
index 6a59741..9b52e32 100644
--- a/chrome/browser/tab_contents/tab_contents_delegate.h
+++ b/chrome/browser/tab_contents/tab_contents_delegate.h
@@ -88,6 +88,13 @@ class TabContentsDelegate : public AutomationResourceRoutingDelegate {
// loading feedback. See TabContents::is_loading()
virtual void LoadingStateChanged(TabContents* source) = 0;
+ // Notifies the delegate that the page has made some progress loading.
+ // |progress| is a value between 0.0 (nothing loaded) to 1.0 (page fully
+ // loaded).
+ // Note that to receive this notification, you must have called
+ // SetReportLoadProgressEnabled(true) in the render view.
+ virtual void LoadProgressChanged(double progress);
+
// Request the delegate to close this tab contents, and do whatever cleanup
// it needs to do.
virtual void CloseContents(TabContents* source) = 0;
@@ -249,6 +256,10 @@ class TabContentsDelegate : public AutomationResourceRoutingDelegate {
const NavigationEntry::SSLStatus& ssl,
bool show_history);
+ // Opens source view for given tab contents that is navigated to the given
+ // page url.
+ virtual void ViewSourceForTab(TabContents* source, const GURL& page_url);
+
// Allows delegates to handle keyboard events before sending to the renderer.
// Returns true if the |event| was handled. Otherwise, if the |event| would be
// handled in HandleKeyboardEvent() method as a normal keyboard shortcut,
diff --git a/chrome/browser/tab_contents/tab_contents_ssl_helper.cc b/chrome/browser/tab_contents/tab_contents_ssl_helper.cc
index 685b6e1..020886c 100644
--- a/chrome/browser/tab_contents/tab_contents_ssl_helper.cc
+++ b/chrome/browser/tab_contents/tab_contents_ssl_helper.cc
@@ -15,7 +15,8 @@
#include "chrome/browser/ssl_client_certificate_selector.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "net/base/net_errors.h"
diff --git a/chrome/browser/tab_contents/tab_contents_view_gtk.cc b/chrome/browser/tab_contents/tab_contents_view_gtk.cc
index 7ec34e4..dbd2797 100644
--- a/chrome/browser/tab_contents/tab_contents_view_gtk.cc
+++ b/chrome/browser/tab_contents/tab_contents_view_gtk.cc
@@ -8,7 +8,10 @@
#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
+#include <algorithm>
+
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "build/build_config.h"
#include "chrome/browser/download/download_shelf.h"
#include "chrome/browser/gtk/browser_window_gtk.h"
@@ -27,7 +30,6 @@
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
#include "chrome/browser/tab_contents/web_drag_dest_gtk.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"
#include "gfx/point.h"
diff --git a/chrome/browser/tab_contents/tab_contents_view_mac.h b/chrome/browser/tab_contents/tab_contents_view_mac.h
index 47b88cf..1aab6b8 100644
--- a/chrome/browser/tab_contents/tab_contents_view_mac.h
+++ b/chrome/browser/tab_contents/tab_contents_view_mac.h
@@ -12,8 +12,8 @@
#include <vector>
#include "base/scoped_nsobject.h"
-#include "chrome/browser/cocoa/base_view.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
+#include "chrome/browser/ui/cocoa/base_view.h"
#include "chrome/common/notification_registrar.h"
#include "gfx/size.h"
diff --git a/chrome/browser/tab_contents/tab_contents_view_mac.mm b/chrome/browser/tab_contents/tab_contents_view_mac.mm
index 34ce802..8d810dd 100644
--- a/chrome/browser/tab_contents/tab_contents_view_mac.mm
+++ b/chrome/browser/tab_contents/tab_contents_view_mac.mm
@@ -8,14 +8,7 @@
#include <string>
-#import "base/chrome_application_mac.h"
-#import "chrome/browser/cocoa/focus_tracker.h"
-#import "chrome/browser/cocoa/browser_window_controller.h"
#include "chrome/browser/global_keyboard_shortcuts_mac.h"
-#include "chrome/browser/cocoa/sad_tab_controller.h"
-#import "chrome/browser/cocoa/web_drag_source.h"
-#import "chrome/browser/cocoa/web_drop_target.h"
-#import "chrome/browser/cocoa/view_id_util.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_view_host_factory.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
@@ -24,8 +17,16 @@
#include "chrome/browser/tab_contents/render_view_context_menu_mac.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
+#import "chrome/browser/ui/cocoa/focus_tracker.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#include "chrome/browser/ui/cocoa/sad_tab_controller.h"
+#import "chrome/browser/ui/cocoa/web_drag_source.h"
+#import "chrome/browser/ui/cocoa/web_drop_target.h"
+#import "chrome/browser/ui/cocoa/view_id_util.h"
+#import "chrome/common/chrome_application_mac.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/render_messages.h"
#include "skia/ext/skia_utils_mac.h"
#import "third_party/mozilla/NSPasteboard+Utils.h"
@@ -337,10 +338,6 @@ void TabContentsViewMac::Observe(NotificationType type,
}
}
-@interface NSApplication(SPI)
-- (void)_cycleWindowsReversed:(BOOL)reversed;
-@end
-
@implementation TabContentsViewCocoa
- (id)initWithTabContentsViewMac:(TabContentsViewMac*)w {
diff --git a/chrome/browser/tab_contents/tab_specific_content_settings.cc b/chrome/browser/tab_contents/tab_specific_content_settings.cc
index 22550ea..e5e6f42 100644
--- a/chrome/browser/tab_contents/tab_specific_content_settings.cc
+++ b/chrome/browser/tab_contents/tab_specific_content_settings.cc
@@ -103,7 +103,31 @@ void TabSpecificContentSettings::OnContentAccessed(ContentSettingsType type) {
}
}
-void TabSpecificContentSettings::OnCookieAccessed(
+void TabSpecificContentSettings::OnCookiesRead(
+ const GURL& url,
+ const net::CookieList& cookie_list,
+ bool blocked_by_policy) {
+ LocalSharedObjectsContainer& container = blocked_by_policy ?
+ blocked_local_shared_objects_ : allowed_local_shared_objects_;
+ typedef net::CookieList::const_iterator cookie_iterator;
+ for (cookie_iterator cookie = cookie_list.begin();
+ cookie != cookie_list.end(); ++cookie) {
+ container.cookies()->SetCookieWithDetails(url,
+ cookie->Name(),
+ cookie->Value(),
+ cookie->Domain(),
+ cookie->Path(),
+ cookie->ExpiryDate(),
+ cookie->IsSecure(),
+ cookie->IsHttpOnly());
+ }
+ if (blocked_by_policy)
+ OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES, std::string());
+ else
+ OnContentAccessed(CONTENT_SETTINGS_TYPE_COOKIES);
+}
+
+void TabSpecificContentSettings::OnCookieChanged(
const GURL& url,
const std::string& cookie_line,
const net::CookieOptions& options,
diff --git a/chrome/browser/tab_contents/tab_specific_content_settings.h b/chrome/browser/tab_contents/tab_specific_content_settings.h
index 26685d1..a046a86 100644
--- a/chrome/browser/tab_contents/tab_specific_content_settings.h
+++ b/chrome/browser/tab_contents/tab_specific_content_settings.h
@@ -96,10 +96,13 @@ class TabSpecificContentSettings
// RenderViewHostDelegate::ContentSettings implementation.
virtual void OnContentBlocked(ContentSettingsType type,
const std::string& resource_identifier);
- virtual void OnCookieAccessed(const GURL& url,
- const std::string& cookie_line,
- const net::CookieOptions& options,
- bool blocked_by_policy);
+ virtual void OnCookiesRead(const GURL& url,
+ const net::CookieList& cookie_list,
+ bool blocked_by_policy);
+ virtual void OnCookieChanged(const GURL& url,
+ const std::string& cookie_line,
+ const net::CookieOptions& options,
+ bool blocked_by_policy);
virtual void OnIndexedDBAccessed(const GURL& url,
const string16& description,
bool blocked_by_policy);
diff --git a/chrome/browser/tab_contents/tab_specific_content_settings_unittest.cc b/chrome/browser/tab_contents/tab_specific_content_settings_unittest.cc
index 5be081c..d23d877 100644
--- a/chrome/browser/tab_contents/tab_specific_content_settings_unittest.cc
+++ b/chrome/browser/tab_contents/tab_specific_content_settings_unittest.cc
@@ -53,7 +53,7 @@ TEST(TabSpecificContentSettingsTest, BlockedContent) {
EXPECT_FALSE(content_settings.IsContentBlocked(CONTENT_SETTINGS_TYPE_POPUPS));
// Set a cookie, block access to images, block a popup.
- content_settings.OnCookieAccessed(
+ content_settings.OnCookieChanged(
GURL("http://google.com"), "A=B", options, false);
EXPECT_TRUE(test_delegate.SettingsChanged());
EXPECT_FALSE(test_delegate.ContentBlocked());
@@ -77,11 +77,11 @@ TEST(TabSpecificContentSettingsTest, BlockedContent) {
EXPECT_FALSE(
content_settings.IsContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES));
EXPECT_TRUE(content_settings.IsContentBlocked(CONTENT_SETTINGS_TYPE_POPUPS));
- content_settings.OnCookieAccessed(
+ content_settings.OnCookieChanged(
GURL("http://google.com"), "A=B", options, false);
// Block a cookie.
- content_settings.OnCookieAccessed(
+ content_settings.OnCookieChanged(
GURL("http://google.com"), "C=D", options, true);
EXPECT_TRUE(
content_settings.IsContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES));
@@ -124,13 +124,13 @@ TEST(TabSpecificContentSettingsTest, AllowedContent) {
content_settings.IsContentAccessed(CONTENT_SETTINGS_TYPE_COOKIES));
ASSERT_FALSE(
content_settings.IsContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES));
- content_settings.OnCookieAccessed(
+ content_settings.OnCookieChanged(
GURL("http://google.com"), "A=B", options, false);
ASSERT_TRUE(
content_settings.IsContentAccessed(CONTENT_SETTINGS_TYPE_COOKIES));
ASSERT_FALSE(
content_settings.IsContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES));
- content_settings.OnCookieAccessed(
+ content_settings.OnCookieChanged(
GURL("http://google.com"), "C=D", options, true);
ASSERT_TRUE(
content_settings.IsContentAccessed(CONTENT_SETTINGS_TYPE_COOKIES));
diff --git a/chrome/browser/tab_contents/test_tab_contents.cc b/chrome/browser/tab_contents/test_tab_contents.cc
index ab6a325..0c227a4 100644
--- a/chrome/browser/tab_contents/test_tab_contents.cc
+++ b/chrome/browser/tab_contents/test_tab_contents.cc
@@ -4,13 +4,16 @@
#include "chrome/browser/tab_contents/test_tab_contents.h"
+#include <utility>
+
#include "chrome/browser/browser_url_handler.h"
#include "chrome/browser/renderer_host/mock_render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/renderer_host/test/test_render_view_host.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
TestTabContents::TestTabContents(Profile* profile, SiteInstance* instance)
: TabContents(profile, instance, MSG_ROUTING_NONE, NULL, NULL),
diff --git a/chrome/browser/tab_contents/web_contents_unittest.cc b/chrome/browser/tab_contents/web_contents_unittest.cc
index abb1578..a494dd5 100644
--- a/chrome/browser/tab_contents/web_contents_unittest.cc
+++ b/chrome/browser/tab_contents/web_contents_unittest.cc
@@ -120,8 +120,8 @@ class TestInterstitialPage : public InterstitialPage {
DidNavigate(render_view_host(), params);
}
- void TestRenderViewGone() {
- RenderViewGone(render_view_host());
+ void TestRenderViewGone(base::TerminationStatus status, int error_code) {
+ RenderViewGone(render_view_host(), status, error_code);
}
bool is_showing() const {
@@ -765,13 +765,13 @@ TEST_F(TabContentsTest, WebKitPrefs) {
// These should still be the default values.
#if defined(OS_MACOSX)
- const wchar_t kDefaultFont[] = L"Times";
+ const char kDefaultFont[] = "Times";
#elif defined(OS_CHROMEOS)
- const wchar_t kDefaultFont[] = L"Tinos";
+ const char kDefaultFont[] = "Tinos";
#else
- const wchar_t kDefaultFont[] = L"Times New Roman";
+ const char kDefaultFont[] = "Times New Roman";
#endif
- EXPECT_EQ(kDefaultFont, webkit_prefs.standard_font_family);
+ EXPECT_EQ(ASCIIToUTF16(kDefaultFont), webkit_prefs.standard_font_family);
EXPECT_TRUE(webkit_prefs.javascript_enabled);
}
@@ -1151,7 +1151,9 @@ TEST_F(TabContentsTest, ShowInterstitialCrashRendererThenGoBack) {
interstitial->TestDidNavigate(2, interstitial_url);
// Crash the renderer
- rvh()->TestOnMessageReceived(ViewHostMsg_RenderViewGone(0));
+ rvh()->TestOnMessageReceived(
+ ViewHostMsg_RenderViewGone(
+ 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
// While the interstitial is showing, go back.
controller().GoBack();
@@ -1186,7 +1188,9 @@ TEST_F(TabContentsTest, ShowInterstitialCrashRendererThenNavigate) {
interstitial->Show();
// Crash the renderer
- rvh()->TestOnMessageReceived(ViewHostMsg_RenderViewGone(0));
+ rvh()->TestOnMessageReceived(
+ ViewHostMsg_RenderViewGone(
+ 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
interstitial->TestDidNavigate(2, interstitial_url);
}
@@ -1429,7 +1433,8 @@ TEST_F(TabContentsTest, InterstitialCrasher) {
TestInterstitialPageStateGuard state_guard(interstitial);
interstitial->Show();
// Simulate a renderer crash before the interstitial is shown.
- interstitial->TestRenderViewGone();
+ interstitial->TestRenderViewGone(
+ base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
// The interstitial should have been dismissed.
EXPECT_TRUE(deleted);
EXPECT_EQ(TestInterstitialPage::CANCELED, state);
@@ -1440,7 +1445,8 @@ TEST_F(TabContentsTest, InterstitialCrasher) {
interstitial->Show();
interstitial->TestDidNavigate(1, url);
// Simulate a renderer crash.
- interstitial->TestRenderViewGone();
+ interstitial->TestRenderViewGone(
+ base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
// The interstitial should have been dismissed.
EXPECT_TRUE(deleted);
EXPECT_EQ(TestInterstitialPage::CANCELED, state);
diff --git a/chrome/browser/tab_contents/web_drag_source_win.cc b/chrome/browser/tab_contents/web_drag_source_win.cc
index a51de68..c4e4ebd 100644
--- a/chrome/browser/tab_contents/web_drag_source_win.cc
+++ b/chrome/browser/tab_contents/web_drag_source_win.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// 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.
@@ -9,8 +9,8 @@
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/web_drag_utils_win.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"
-#include "chrome/common/notification_service.h"
using WebKit::WebDragOperationNone;
diff --git a/chrome/browser/tab_contents_wrapper.cc b/chrome/browser/tab_contents_wrapper.cc
deleted file mode 100644
index a7f52f1..0000000
--- a/chrome/browser/tab_contents_wrapper.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// 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.
-
-#include "chrome/browser/tab_contents_wrapper.h"
-
-#include "base/singleton.h"
-#include "chrome/browser/password_manager/password_manager.h"
-#include "chrome/browser/password_manager_delegate_impl.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-
-////////////////////////////////////////////////////////////////////////////////
-// TabContentsWrapper, public:
-
-TabContentsWrapper::TabContentsWrapper(TabContents* contents)
- : tab_contents_(contents) {
- DCHECK(contents);
- // Stash this in the property bag so it can be retrieved without having to
- // go to a Browser.
- property_accessor()->SetProperty(contents->property_bag(), this);
-
- // Needed so that we initialize the password manager on first navigation.
- tab_contents()->AddNavigationObserver(this);
-}
-
-TabContentsWrapper::~TabContentsWrapper() {
- // Unregister observers (TabContents outlives supporting objects).
- tab_contents()->RemoveNavigationObserver(password_manager_.get());
-}
-
-PropertyAccessor<TabContentsWrapper*>* TabContentsWrapper::property_accessor() {
- return Singleton< PropertyAccessor<TabContentsWrapper*> >::get();
-}
-
-TabContentsWrapper* TabContentsWrapper::Clone() {
- TabContents* new_contents = tab_contents()->Clone();
- TabContentsWrapper* new_wrapper = new TabContentsWrapper(new_contents);
- // Instantiate the passowrd manager if it has been instantiated here.
- if (password_manager_.get())
- new_wrapper->GetPasswordManager();
- return new_wrapper;
-}
-
-PasswordManager* TabContentsWrapper::GetPasswordManager() {
- if (!password_manager_.get()) {
- // Create the delegate then create the manager.
- password_manager_delegate_.reset(
- new PasswordManagerDelegateImpl(tab_contents()));
- password_manager_.reset(
- new PasswordManager(password_manager_delegate_.get()));
- // Register the manager to receive navigation notifications.
- tab_contents()->AddNavigationObserver(password_manager_.get());
- }
- return password_manager_.get();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// TabContentsWrapper, WebNavigationObserver implementation:
-
-void TabContentsWrapper::NavigateToPendingEntry() {
- GetPasswordManager();
- tab_contents()->RemoveNavigationObserver(this);
-}
diff --git a/chrome/browser/tab_contents_wrapper.h b/chrome/browser/tab_contents_wrapper.h
deleted file mode 100644
index 4723da9..0000000
--- a/chrome/browser/tab_contents_wrapper.h
+++ /dev/null
@@ -1,79 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_TAB_CONTENTS_WRAPPER_H_
-#define CHROME_BROWSER_TAB_CONTENTS_WRAPPER_H_
-#pragma once
-
-#include "base/scoped_ptr.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents/web_navigation_observer.h"
-
-class Extension;
-class NavigationController;
-class PasswordManager;
-class PasswordManagerDelegate;
-class TabContentsDelegate;
-
-// Wraps TabContents and all of its supporting objetcs in order to control
-// their ownership and lifetime, while allowing TabContents to remain generic
-// and re-usable in other projects.
-// TODO(pinkerton): Eventually, this class will become TabContents as far as
-// the browser front-end is concerned, and the current TabContents will be
-// renamed to something like WebPage or WebView (ben's suggestions).
-class TabContentsWrapper : public WebNavigationObserver {
- public:
- // Takes ownership of |contents|, which must be heap-allocated (as it lives
- // in a scoped_ptr) and can not be NULL.
- explicit TabContentsWrapper(TabContents* contents);
- ~TabContentsWrapper();
-
- // Used to retrieve this object from |tab_contents_|, which is placed in
- // its property bag to avoid adding additional interfaces.
- static PropertyAccessor<TabContentsWrapper*>* property_accessor();
-
- // Create a TabContentsWrapper with the same state as this one. The returned
- // heap-allocated pointer is owned by the caller.
- TabContentsWrapper* Clone();
-
- TabContents* tab_contents() const { return tab_contents_.get(); }
- NavigationController& controller() const {
- return tab_contents()->controller();
- }
- TabContentsView* view() const { return tab_contents()->view(); }
- RenderViewHost* render_view_host() const {
- return tab_contents()->render_view_host();
- }
- Profile* profile() const { return tab_contents()->profile(); }
- TabContentsDelegate* delegate() const { return tab_contents()->delegate(); }
- void set_delegate(TabContentsDelegate* d) { tab_contents()->set_delegate(d); }
-
- // Convenience methods until extensions are removed from TabContents.
- void SetExtensionAppById(const std::string& extension_app_id) {
- tab_contents()->SetExtensionAppById(extension_app_id);
- }
- const Extension* extension_app() const {
- return tab_contents()->extension_app();
- }
- bool is_app() const { return tab_contents()->is_app(); }
-
- // Returns the PasswordManager, creating it if necessary.
- PasswordManager* GetPasswordManager();
-
- // WebNavigationObserver overrides:
- virtual void NavigateToPendingEntry();
-
- private:
- // PasswordManager and its delegate, lazily created. The delegate must
- // outlive the manager, per documentation in password_manager.h.
- scoped_ptr<PasswordManagerDelegate> password_manager_delegate_;
- scoped_ptr<PasswordManager> password_manager_;
-
- // The supporting objects need to outlive the TabContents dtor (as they may
- // be called upon during its execution). As a result, this must come last
- // in the list.
- scoped_ptr<TabContents> tab_contents_;
-};
-
-#endif // CHROME_BROWSER_TAB_CONTENTS_WRAPPER_H_
diff --git a/chrome/browser/tab_menu_model.cc b/chrome/browser/tab_menu_model.cc
deleted file mode 100644
index 6189080..0000000
--- a/chrome/browser/tab_menu_model.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// 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.
-
-#include "chrome/browser/tab_menu_model.h"
-
-#include "base/command_line.h"
-#include "chrome/browser/tabs/tab_strip_model.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/pref_names.h"
-#include "grit/generated_resources.h"
-
-TabMenuModel::TabMenuModel(menus::SimpleMenuModel::Delegate* delegate,
- bool is_pinned)
- : menus::SimpleMenuModel(delegate) {
- Build(is_pinned);
-}
-
-// static
-bool TabMenuModel::AreVerticalTabsEnabled() {
-#if defined(TOOLKIT_VIEWS) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
- return CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableVerticalTabs);
-#else
- return false;
-#endif
-}
-
-void TabMenuModel::Build(bool is_pinned) {
- AddItemWithStringId(TabStripModel::CommandNewTab, IDS_TAB_CXMENU_NEWTAB);
- AddSeparator();
- AddItemWithStringId(TabStripModel::CommandReload, IDS_TAB_CXMENU_RELOAD);
- AddItemWithStringId(TabStripModel::CommandDuplicate,
- IDS_TAB_CXMENU_DUPLICATE);
- AddItemWithStringId(
- TabStripModel::CommandTogglePinned,
- is_pinned ? IDS_TAB_CXMENU_UNPIN_TAB : IDS_TAB_CXMENU_PIN_TAB);
- AddSeparator();
- AddItemWithStringId(TabStripModel::CommandCloseTab,
- IDS_TAB_CXMENU_CLOSETAB);
- AddItemWithStringId(TabStripModel::CommandCloseOtherTabs,
- IDS_TAB_CXMENU_CLOSEOTHERTABS);
- AddItemWithStringId(TabStripModel::CommandCloseTabsToRight,
- IDS_TAB_CXMENU_CLOSETABSTORIGHT);
- AddSeparator();
- AddItemWithStringId(TabStripModel::CommandRestoreTab, IDS_RESTORE_TAB);
- AddItemWithStringId(TabStripModel::CommandBookmarkAllTabs,
- IDS_TAB_CXMENU_BOOKMARK_ALL_TABS);
- if (AreVerticalTabsEnabled()) {
- AddSeparator();
- AddCheckItemWithStringId(TabStripModel::CommandUseVerticalTabs,
- IDS_TAB_CXMENU_USE_VERTICAL_TABS);
- }
-}
diff --git a/chrome/browser/tab_menu_model.h b/chrome/browser/tab_menu_model.h
deleted file mode 100644
index 0f7dedd..0000000
--- a/chrome/browser/tab_menu_model.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_TAB_MENU_MODEL_H_
-#define CHROME_BROWSER_TAB_MENU_MODEL_H_
-#pragma once
-
-#include "app/menus/simple_menu_model.h"
-
-// A menu model that builds the contents of the tab context menu. This menu has
-// only one level (no submenus). TabMenuModel caches local state from the
-// tab (such as the pinned state). To make sure the menu reflects the real state
-// of the tab a new TabMenuModel should be created each time the menu is shown.
-class TabMenuModel : public menus::SimpleMenuModel {
- public:
- TabMenuModel(menus::SimpleMenuModel::Delegate* delegate, bool is_pinned);
- virtual ~TabMenuModel() {}
-
- // Returns true if vertical tabs are enabled.
- static bool AreVerticalTabsEnabled();
-
- private:
- void Build(bool is_pinned);
-
- DISALLOW_COPY_AND_ASSIGN(TabMenuModel);
-};
-
-#endif // CHROME_BROWSER_TAB_MENU_MODEL_H_
diff --git a/chrome/browser/tab_menu_model_unittest.cc b/chrome/browser/tab_menu_model_unittest.cc
deleted file mode 100644
index fd39e57..0000000
--- a/chrome/browser/tab_menu_model_unittest.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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.
-
-#include "chrome/browser/tab_menu_model.h"
-
-#include "chrome/test/menu_model_test.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-class TabMenuModelTest : public PlatformTest, public MenuModelTest {
-};
-
-TEST_F(TabMenuModelTest, Basics) {
- TabMenuModel model(&delegate_, true);
-
- // Verify it has items. The number varies by platform, so we don't check
- // the exact number.
- EXPECT_GT(model.GetItemCount(), 5);
-
- int item_count = 0;
- CountEnabledExecutable(&model, &item_count);
- EXPECT_GT(item_count, 0);
- EXPECT_EQ(item_count, delegate_.execute_count_);
- EXPECT_EQ(item_count, delegate_.enable_count_);
-}
diff --git a/chrome/browser/tabs/pinned_tab_codec.cc b/chrome/browser/tabs/pinned_tab_codec.cc
index 08264b2..74bf900 100644
--- a/chrome/browser/tabs/pinned_tab_codec.cc
+++ b/chrome/browser/tabs/pinned_tab_codec.cc
@@ -7,11 +7,11 @@
#include "base/values.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/page_transition_types.h"
#include "chrome/common/pref_names.h"
diff --git a/chrome/browser/tabs/pinned_tab_service.cc b/chrome/browser/tabs/pinned_tab_service.cc
index adb9f5c..c35235e 100644
--- a/chrome/browser/tabs/pinned_tab_service.cc
+++ b/chrome/browser/tabs/pinned_tab_service.cc
@@ -4,7 +4,7 @@
#include "chrome/browser/tabs/pinned_tab_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tabs/pinned_tab_codec.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/notification_service.h"
diff --git a/chrome/browser/tabs/tab_strip_model.cc b/chrome/browser/tabs/tab_strip_model.cc
index a16d250..7d93921 100644
--- a/chrome/browser/tabs/tab_strip_model.cc
+++ b/chrome/browser/tabs/tab_strip_model.cc
@@ -14,18 +14,18 @@
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/browser_shutdown.h"
#include "chrome/browser/defaults.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/sessions/tab_restore_service.h"
#include "chrome/browser/tabs/tab_strip_model_delegate.h"
#include "chrome/browser/tabs/tab_strip_model_order_controller.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_service.h"
@@ -168,11 +168,11 @@ void TabStripModel::InsertTabContentsAt(int index,
TabContentsWrapper* TabStripModel::ReplaceTabContentsAt(
int index,
TabContentsWrapper* new_contents) {
+ // TODO: this should reset group/opener of any tabs that point at
+ // old_contents.
DCHECK(ContainsIndex(index));
TabContentsWrapper* old_contents = GetContentsAt(index);
- ForgetOpenersAndGroupsReferencing(&(old_contents->controller()));
-
contents_data_[index]->contents = new_contents;
FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
@@ -212,7 +212,6 @@ TabContentsWrapper* TabStripModel::DetachTabContentsAt(int index) {
int next_selected_index = order_controller_->DetermineNewSelectedIndex(index);
delete contents_data_.at(index);
contents_data_.erase(contents_data_.begin() + index);
- ForgetOpenersAndGroupsReferencing(&(removed_contents->controller()));
if (empty())
closing_all_ = true;
FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
@@ -779,7 +778,8 @@ void TabStripModel::Observe(NotificationType type,
}
case NotificationType::EXTENSION_UNLOADED: {
- const Extension* extension = Details<const Extension>(details).ptr();
+ const Extension* extension =
+ Details<UnloadedExtensionInfo>(details)->extension;
// Iterate backwards as we may remove items while iterating.
for (int i = count() - 1; i >= 0; i--) {
TabContentsWrapper* contents = GetTabContentsAt(i);
@@ -1011,14 +1011,3 @@ bool TabStripModel::OpenerMatches(const TabContentsData* data,
bool use_group) {
return data->opener == opener || (use_group && data->group == opener);
}
-
-void TabStripModel::ForgetOpenersAndGroupsReferencing(
- const NavigationController* tab) {
- for (TabContentsDataVector::const_iterator i = contents_data_.begin();
- i != contents_data_.end(); ++i) {
- if ((*i)->group == tab)
- (*i)->group = NULL;
- if ((*i)->opener == tab)
- (*i)->opener = NULL;
- }
-}
diff --git a/chrome/browser/tabs/tab_strip_model.h b/chrome/browser/tabs/tab_strip_model.h
index 7ed42f1..7a3c8d9 100644
--- a/chrome/browser/tabs/tab_strip_model.h
+++ b/chrome/browser/tabs/tab_strip_model.h
@@ -480,9 +480,6 @@ class TabStripModel : public NotificationObserver {
const NavigationController* opener,
bool use_group);
- // Sets the group/opener of any tabs that reference |tab| to NULL.
- void ForgetOpenersAndGroupsReferencing(const NavigationController* tab);
-
// Our delegate.
TabStripModelDelegate* delegate_;
diff --git a/chrome/browser/tabs/tab_strip_model_order_controller.cc b/chrome/browser/tabs/tab_strip_model_order_controller.cc
index 7cadbf7..c7d10f4 100644
--- a/chrome/browser/tabs/tab_strip_model_order_controller.cc
+++ b/chrome/browser/tabs/tab_strip_model_order_controller.cc
@@ -4,7 +4,7 @@
#include "chrome/browser/tabs/tab_strip_model_order_controller.h"
-#include "chrome/browser/tab_contents_wrapper.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
///////////////////////////////////////////////////////////////////////////////
// TabStripModelOrderController, public:
diff --git a/chrome/browser/tabs/tab_strip_model_unittest.cc b/chrome/browser/tabs/tab_strip_model_unittest.cc
index ff461f6..b33aaa6 100644
--- a/chrome/browser/tabs/tab_strip_model_unittest.cc
+++ b/chrome/browser/tabs/tab_strip_model_unittest.cc
@@ -2,34 +2,36 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <map>
+#include <string>
+
#include "app/system_monitor.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/path_service.h"
-#include "base/string_number_conversions.h"
#include "base/scoped_ptr.h"
-#include "base/string_util.h"
#include "base/stl_util-inl.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/dom_ui/new_tab_ui.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/renderer_host/test/test_render_view_host.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/tabs/tab_strip_model_delegate.h"
#include "chrome/browser/tabs/tab_strip_model_order_controller.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/extensions/extension.h"
+#include "chrome/common/notification_details.h"
#include "chrome/common/notification_observer_mock.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/property_bag.h"
#include "chrome/common/url_constants.h"
diff --git a/chrome/browser/task_manager/task_manager.cc b/chrome/browser/task_manager/task_manager.cc
index 5673741..30209c7 100644
--- a/chrome/browser/task_manager/task_manager.cc
+++ b/chrome/browser/task_manager/task_manager.cc
@@ -20,12 +20,13 @@
#include "chrome/browser/browser_window.h"
#include "chrome/browser/net/url_request_tracking.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/task_manager/task_manager_resource_providers.h"
#include "chrome/common/pref_names.h"
+#include "chrome/common/result_codes.h"
#include "chrome/common/url_constants.h"
#include "grit/app_resources.h"
#include "grit/chromium_strings.h"
@@ -585,11 +586,11 @@ void TaskManagerModel::RemoveResourceProvider(
}
void TaskManagerModel::RegisterForJobDoneNotifications() {
- g_url_request_job_tracker.AddObserver(this);
+ net::g_url_request_job_tracker.AddObserver(this);
}
void TaskManagerModel::UnregisterForJobDoneNotifications() {
- g_url_request_job_tracker.RemoveObserver(this);
+ net::g_url_request_job_tracker.RemoveObserver(this);
}
void TaskManagerModel::AddResource(TaskManager::Resource* resource) {
@@ -627,7 +628,7 @@ void TaskManagerModel::AddResource(TaskManager::Resource* resource) {
base::ProcessMetrics::CreateProcessMetrics(process);
#else
base::ProcessMetrics::CreateProcessMetrics(process,
- MachBroker::instance());
+ MachBroker::GetInstance());
#endif
metrics_map_[process] = pm;
@@ -865,26 +866,26 @@ void TaskManagerModel::BytesRead(BytesReadParam param) {
}
-// In order to retrieve the network usage, we register for URLRequestJob
+// In order to retrieve the network usage, we register for net::URLRequestJob
// notifications. Every time we get notified some bytes were read we bump a
// counter of read bytes for the associated resource. When the timer ticks,
// we'll compute the actual network usage (see the Refresh method).
-void TaskManagerModel::OnJobAdded(URLRequestJob* job) {
+void TaskManagerModel::OnJobAdded(net::URLRequestJob* job) {
}
-void TaskManagerModel::OnJobRemoved(URLRequestJob* job) {
+void TaskManagerModel::OnJobRemoved(net::URLRequestJob* job) {
}
-void TaskManagerModel::OnJobDone(URLRequestJob* job,
+void TaskManagerModel::OnJobDone(net::URLRequestJob* job,
const URLRequestStatus& status) {
}
-void TaskManagerModel::OnJobRedirect(URLRequestJob* job,
+void TaskManagerModel::OnJobRedirect(net::URLRequestJob* job,
const GURL& location,
int status_code) {
}
-void TaskManagerModel::OnBytesRead(URLRequestJob* job, const char* buf,
+void TaskManagerModel::OnBytesRead(net::URLRequestJob* job, const char* buf,
int byte_count) {
int render_process_host_child_id = -1, routing_id = -1;
ResourceDispatcherHost::RenderViewForRequest(job->request(),
@@ -944,7 +945,7 @@ void TaskManager::KillProcess(int index) {
base::ProcessHandle process = model_->GetResourceProcessHandle(index);
DCHECK(process);
if (process != base::GetCurrentProcessHandle())
- base::KillProcess(process, base::PROCESS_END_KILLED_BY_USER, false);
+ base::KillProcess(process, ResultCodes::KILLED, false);
}
void TaskManager::ActivateProcess(int index) {
diff --git a/chrome/browser/task_manager/task_manager.h b/chrome/browser/task_manager/task_manager.h
index 5b33c75..c0f757e 100644
--- a/chrome/browser/task_manager/task_manager.h
+++ b/chrome/browser/task_manager/task_manager.h
@@ -213,7 +213,7 @@ class TaskManagerModelObserver {
};
// The model that the TaskManager is using.
-class TaskManagerModel : public URLRequestJobTracker::JobObserver,
+class TaskManagerModel : public net::URLRequestJobTracker::JobObserver,
public base::RefCountedThreadSafe<TaskManagerModel> {
public:
explicit TaskManagerModel(TaskManager* task_manager);
@@ -297,13 +297,16 @@ class TaskManagerModel : public URLRequestJobTracker::JobObserver,
const Extension* GetResourceExtension(int index) const;
// JobObserver methods:
- void OnJobAdded(net::URLRequestJob* job);
- void OnJobRemoved(net::URLRequestJob* job);
- void OnJobDone(net::URLRequestJob* job, const URLRequestStatus& status);
- void OnJobRedirect(net::URLRequestJob* job,
- const GURL& location,
- int status_code);
- void OnBytesRead(net::URLRequestJob* job, const char* buf, int byte_count);
+ virtual void OnJobAdded(net::URLRequestJob* job);
+ virtual void OnJobRemoved(net::URLRequestJob* job);
+ virtual void OnJobDone(net::URLRequestJob* job,
+ const URLRequestStatus& status);
+ virtual void OnJobRedirect(net::URLRequestJob* job,
+ const GURL& location,
+ int status_code);
+ virtual void OnBytesRead(net::URLRequestJob* job,
+ const char* buf,
+ int byte_count);
void AddResourceProvider(TaskManager::ResourceProvider* provider);
void RemoveResourceProvider(TaskManager::ResourceProvider* provider);
diff --git a/chrome/browser/task_manager/task_manager_browsertest.cc b/chrome/browser/task_manager/task_manager_browsertest.cc
index e2e1f7d..b944869 100644
--- a/chrome/browser/task_manager/task_manager_browsertest.cc
+++ b/chrome/browser/task_manager/task_manager_browsertest.cc
@@ -11,11 +11,12 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/crashed_extension_infobar.h"
#include "chrome/browser/extensions/extension_browsertest.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/notifications/desktop_notification_service.h"
#include "chrome/browser/notifications/notification.h"
#include "chrome/browser/notifications/notification_test_util.h"
#include "chrome/browser/notifications/notification_ui_manager.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tabs/tab_strip_model.h"
@@ -98,7 +99,7 @@ IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeTabContentsChanges) {
browser()->window()->ShowTaskManager();
// Browser and the New Tab Page.
- EXPECT_EQ(2, model()->ResourceCount());
+ WaitForResourceChange(2);
// Open a new tab and make sure we notice that.
GURL url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
@@ -106,6 +107,13 @@ IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeTabContentsChanges) {
AddTabAtIndex(0, url, PageTransition::TYPED);
WaitForResourceChange(3);
+ // Check that the third entry is a tab contents resource whose title starts
+ // starts with "Tab:".
+ ASSERT_TRUE(model()->GetResourceTabContents(2) != NULL);
+ string16 prefix = WideToUTF16Hack(l10n_util::GetStringF(
+ IDS_TASK_MANAGER_TAB_PREFIX, L""));
+ ASSERT_TRUE(StartsWith(model()->GetResourceTitle(2), prefix, true));
+
// Close the tab and verify that we notice.
TabContents* first_tab = browser()->GetTabContentsAt(0);
ASSERT_TRUE(first_tab);
@@ -121,7 +129,7 @@ IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeBGContentsChanges) {
browser()->window()->ShowTaskManager();
// Browser and the New Tab Page.
- EXPECT_EQ(2, model()->ResourceCount());
+ WaitForResourceChange(2);
// Open a new background contents and make sure we notice that.
GURL url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
@@ -141,15 +149,7 @@ IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeBGContentsChanges) {
WaitForResourceChange(2);
}
-#if defined(OS_WIN)
-// http://crbug.com/31663
-#define MAYBE_NoticeExtensionChanges DISABLED_NoticeExtensionChanges
-#else
-// Flaky test bug filed in http://crbug.com/51701
-#define MAYBE_NoticeExtensionChanges FLAKY_NoticeExtensionChanges
-#endif
-
-IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, MAYBE_NoticeExtensionChanges) {
+IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeExtensionChanges) {
EXPECT_EQ(0, model()->ResourceCount());
// Show the task manager. This populates the model, and helps with debugging
@@ -157,13 +157,89 @@ IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, MAYBE_NoticeExtensionChanges) {
browser()->window()->ShowTaskManager();
// Browser and the New Tab Page.
- EXPECT_EQ(2, model()->ResourceCount());
+ WaitForResourceChange(2);
// Loading an extension with a background page should result in a new
// resource being created for it.
ASSERT_TRUE(LoadExtension(
test_data_dir_.AppendASCII("common").AppendASCII("background_page")));
WaitForResourceChange(3);
+
+ // Unload extension to avoid crash on Windows (see http://crbug.com/31663).
+ UnloadExtension(last_loaded_extension_id_);
+ WaitForResourceChange(2);
+}
+
+IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeExtensionTabs) {
+ // Show the task manager. This populates the model, and helps with debugging
+ // (you see the task manager).
+ browser()->window()->ShowTaskManager();
+
+ ASSERT_TRUE(LoadExtension(
+ test_data_dir_.AppendASCII("good").AppendASCII("Extensions")
+ .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
+ .AppendASCII("1.0.0.0")));
+
+ // Browser, Extension background page, and the New Tab Page.
+ WaitForResourceChange(3);
+
+ // Open a new tab to an extension URL and make sure we notice that.
+ GURL url("chrome-extension://behllobkkfkfnphdnhnkndlbkcpglgmj/page.html");
+ AddTabAtIndex(0, url, PageTransition::TYPED);
+ WaitForResourceChange(4);
+
+ // Check that the third entry (background) is an extension resource whose
+ // title starts with "Extension:".
+ ASSERT_EQ(TaskManager::Resource::EXTENSION, model()->GetResourceType(2));
+ ASSERT_TRUE(model()->GetResourceTabContents(2) == NULL);
+ ASSERT_TRUE(model()->GetResourceExtension(2) != NULL);
+ string16 prefix = WideToUTF16Hack(l10n_util::GetStringF(
+ IDS_TASK_MANAGER_EXTENSION_PREFIX, L""));
+ ASSERT_TRUE(StartsWith(model()->GetResourceTitle(2), prefix, true));
+
+ // Check that the fourth entry (page.html) is of type extension and has both
+ // a tab contents and an extension. The title should start with "Extension:".
+ ASSERT_EQ(TaskManager::Resource::EXTENSION, model()->GetResourceType(3));
+ ASSERT_TRUE(model()->GetResourceTabContents(3) != NULL);
+ ASSERT_TRUE(model()->GetResourceExtension(3) != NULL);
+ ASSERT_TRUE(StartsWith(model()->GetResourceTitle(3), prefix, true));
+
+ // Unload extension to avoid crash on Windows.
+ UnloadExtension(last_loaded_extension_id_);
+ WaitForResourceChange(2);
+}
+
+IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeAppTabs) {
+ // Show the task manager. This populates the model, and helps with debugging
+ // (you see the task manager).
+ browser()->window()->ShowTaskManager();
+
+ ASSERT_TRUE(LoadExtension(
+ test_data_dir_.AppendASCII("packaged_app")));
+ ExtensionService* service = browser()->profile()->GetExtensionService();
+ const Extension* extension =
+ service->GetExtensionById(last_loaded_extension_id_, false);
+
+ // Browser and the New Tab Page.
+ WaitForResourceChange(2);
+
+ // Open a new tab to the app's launch URL and make sure we notice that.
+ GURL url(extension->GetResourceURL("main.html"));
+ AddTabAtIndex(0, url, PageTransition::TYPED);
+ WaitForResourceChange(3);
+
+ // Check that the third entry (main.html) is of type extension and has both
+ // a tab contents and an extension. The title should start with "App:".
+ ASSERT_EQ(TaskManager::Resource::EXTENSION, model()->GetResourceType(2));
+ ASSERT_TRUE(model()->GetResourceTabContents(2) != NULL);
+ ASSERT_TRUE(model()->GetResourceExtension(2) != NULL);
+ string16 prefix = WideToUTF16Hack(l10n_util::GetStringF(
+ IDS_TASK_MANAGER_APP_PREFIX, L""));
+ ASSERT_TRUE(StartsWith(model()->GetResourceTitle(2), prefix, true));
+
+ // Unload extension to avoid crash on Windows.
+ UnloadExtension(last_loaded_extension_id_);
+ WaitForResourceChange(2);
}
IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeNotificationChanges) {
@@ -172,7 +248,7 @@ IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeNotificationChanges) {
// Show the task manager.
browser()->window()->ShowTaskManager();
// Expect to see the browser and the New Tab Page renderer.
- EXPECT_EQ(2, model()->ResourceCount());
+ WaitForResourceChange(2);
// Show a notification.
NotificationUIManager* notifications =
@@ -220,7 +296,9 @@ IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, KillExtension) {
WaitForResourceChange(2);
}
-IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, KillExtensionAndReload) {
+// Disabled, http://crbug.com/66957.
+IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest,
+ DISABLED_KillExtensionAndReload) {
// Show the task manager. This populates the model, and helps with debugging
// (you see the task manager).
browser()->window()->ShowTaskManager();
@@ -297,7 +375,7 @@ IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest,
browser()->window()->ShowTaskManager();
// Browser and the New Tab Page.
- EXPECT_EQ(2, model()->ResourceCount());
+ WaitForResourceChange(2);
// Open a new tab and make sure we notice that.
GURL url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
diff --git a/chrome/browser/task_manager/task_manager_resource_providers.cc b/chrome/browser/task_manager/task_manager_resource_providers.cc
index 2b339fa..40a23b2 100644
--- a/chrome/browser/task_manager/task_manager_resource_providers.cc
+++ b/chrome/browser/task_manager/task_manager_resource_providers.cc
@@ -24,14 +24,14 @@
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_process_manager.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/notifications/balloon_collection.h"
#include "chrome/browser/notifications/balloon_host.h"
#include "chrome/browser/notifications/notification_ui_manager.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/renderer_host/render_message_filter.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/renderer_host/resource_message_filter.h"
#include "chrome/browser/tab_contents/background_contents.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_util.h"
@@ -50,6 +50,24 @@
#include "gfx/icon_util.h"
#endif // defined(OS_WIN)
+namespace {
+
+// Returns the appropriate message prefix ID for tabs and extensions,
+// reflecting whether they are apps or in incognito mode.
+int GetMessagePrefixID(bool is_app, bool is_extension,
+ bool is_off_the_record) {
+ return is_app ?
+ (is_off_the_record ?
+ IDS_TASK_MANAGER_APP_INCOGNITO_PREFIX :
+ IDS_TASK_MANAGER_APP_PREFIX) :
+ (is_extension ?
+ (is_off_the_record ?
+ IDS_TASK_MANAGER_EXTENSION_INCOGNITO_PREFIX :
+ IDS_TASK_MANAGER_EXTENSION_PREFIX) :
+ IDS_TASK_MANAGER_TAB_PREFIX);
+}
+
+} // namespace
////////////////////////////////////////////////////////////////////////////////
// TaskManagerRendererResource class
@@ -116,6 +134,22 @@ base::ProcessHandle TaskManagerRendererResource::GetProcess() const {
return process_;
}
+TaskManager::Resource::Type TaskManagerRendererResource::GetType() const {
+ return RENDERER;
+}
+
+bool TaskManagerRendererResource::ReportsCacheStats() const {
+ return true;
+}
+
+bool TaskManagerRendererResource::ReportsV8MemoryStats() const {
+ return true;
+}
+
+bool TaskManagerRendererResource::SupportNetworkUsage() const {
+ return true;
+}
+
////////////////////////////////////////////////////////////////////////////////
// TaskManagerTabContentsResource class
////////////////////////////////////////////////////////////////////////////////
@@ -131,6 +165,10 @@ TaskManagerTabContentsResource::TaskManagerTabContentsResource(
TaskManagerTabContentsResource::~TaskManagerTabContentsResource() {
}
+TaskManager::Resource::Type TaskManagerTabContentsResource::GetType() const {
+ return tab_contents_->HostsExtension() ? EXTENSION : RENDERER;
+}
+
std::wstring TaskManagerTabContentsResource::GetTitle() const {
// Fall back on the URL if there's no title.
std::wstring tab_title(UTF16ToWideHack(tab_contents_->GetTitle()));
@@ -152,10 +190,15 @@ std::wstring TaskManagerTabContentsResource::GetTitle() const {
base::i18n::AdjustStringForLocaleDirection(&tab_title);
}
- return l10n_util::GetStringF(IDS_TASK_MANAGER_TAB_PREFIX, tab_title);
+ ExtensionService* extensions_service =
+ tab_contents_->profile()->GetExtensionService();
+ int message_id = GetMessagePrefixID(
+ extensions_service->IsInstalledApp(tab_contents_->GetURL()),
+ tab_contents_->HostsExtension(),
+ tab_contents_->profile()->IsOffTheRecord());
+ return l10n_util::GetStringF(message_id, tab_title);
}
-
SkBitmap TaskManagerTabContentsResource::GetIcon() const {
return tab_contents_->GetFavIcon();
}
@@ -164,6 +207,16 @@ TabContents* TaskManagerTabContentsResource::GetTabContents() const {
return static_cast<TabContents*>(tab_contents_);
}
+const Extension* TaskManagerTabContentsResource::GetExtension() const {
+ if (tab_contents_->HostsExtension()) {
+ ExtensionService* extensions_service =
+ tab_contents_->profile()->GetExtensionService();
+ return extensions_service->GetExtensionByURL(tab_contents_->GetURL());
+ }
+
+ return NULL;
+}
+
////////////////////////////////////////////////////////////////////////////////
// TaskManagerTabContentsResourceProvider class
////////////////////////////////////////////////////////////////////////////////
@@ -267,11 +320,8 @@ void TaskManagerTabContentsResourceProvider::Add(TabContents* tab_contents) {
return;
// Don't add dead tabs or tabs that haven't yet connected.
- // Also ignore tabs which display extension content. We collapse
- // all of these into one extension row.
if (!tab_contents->GetRenderProcessHost()->GetHandle() ||
- !tab_contents->notify_disconnection() ||
- tab_contents->HostsExtension()) {
+ !tab_contents->notify_disconnection()) {
return;
}
@@ -440,7 +490,7 @@ void TaskManagerBackgroundContentsResourceProvider::StartUpdating() {
it != profile_manager->end(); ++it) {
BackgroundContentsService* background_contents_service =
(*it)->GetBackgroundContentsService();
- ExtensionsService* extensions_service = (*it)->GetExtensionsService();
+ ExtensionService* extensions_service = (*it)->GetExtensionService();
std::vector<BackgroundContents*> contents =
background_contents_service->GetBackgroundContents();
for (std::vector<BackgroundContents*>::iterator iterator = contents.begin();
@@ -540,8 +590,8 @@ void TaskManagerBackgroundContentsResourceProvider::Observe(
// except in rare cases when an extension is being unloaded or chrome is
// exiting while the task manager is displayed.
std::wstring application_name;
- ExtensionsService* service =
- Source<Profile>(source)->GetExtensionsService();
+ ExtensionService* service =
+ Source<Profile>(source)->GetExtensionService();
if (service) {
std::string application_id = UTF16ToUTF8(
Details<BackgroundContentsOpenedDetails>(details)->application_id);
@@ -650,6 +700,14 @@ TaskManager::Resource::Type TaskManagerChildProcessResource::GetType() const {
}
}
+bool TaskManagerChildProcessResource::SupportNetworkUsage() const {
+ return network_usage_support_;
+}
+
+void TaskManagerChildProcessResource::SetSupportNetworkUsage() {
+ network_usage_support_ = true;
+}
+
////////////////////////////////////////////////////////////////////////////////
// TaskManagerChildProcessResourceProvider class
////////////////////////////////////////////////////////////////////////////////
@@ -826,14 +884,8 @@ TaskManagerExtensionProcessResource::TaskManagerExtensionProcessResource(
std::wstring extension_name(UTF8ToWide(GetExtension()->name()));
DCHECK(!extension_name.empty());
- int message_id =
- GetExtension()->is_app() ?
- (extension_host_->profile()->IsOffTheRecord() ?
- IDS_TASK_MANAGER_APP_INCOGNITO_PREFIX :
- IDS_TASK_MANAGER_APP_PREFIX) :
- (extension_host_->profile()->IsOffTheRecord() ?
- IDS_TASK_MANAGER_EXTENSION_INCOGNITO_PREFIX :
- IDS_TASK_MANAGER_EXTENSION_PREFIX);
+ int message_id = GetMessagePrefixID(GetExtension()->is_app(), true,
+ extension_host_->profile()->IsOffTheRecord());
title_ = l10n_util::GetStringF(message_id, extension_name);
}
@@ -852,6 +904,19 @@ base::ProcessHandle TaskManagerExtensionProcessResource::GetProcess() const {
return process_handle_;
}
+TaskManager::Resource::Type
+TaskManagerExtensionProcessResource::GetType() const {
+ return EXTENSION;
+}
+
+bool TaskManagerExtensionProcessResource::SupportNetworkUsage() const {
+ return true;
+}
+
+void TaskManagerExtensionProcessResource::SetSupportNetworkUsage() {
+ NOTREACHED();
+}
+
const Extension* TaskManagerExtensionProcessResource::GetExtension() const {
return extension_host_->extension();
}
@@ -1026,6 +1091,10 @@ TaskManagerNotificationResource::TaskManagerNotificationResource(
TaskManagerNotificationResource::~TaskManagerNotificationResource() {
}
+std::wstring TaskManagerNotificationResource::GetTitle() const {
+ return title_;
+}
+
SkBitmap TaskManagerNotificationResource::GetIcon() const {
return *default_icon_;
}
@@ -1034,6 +1103,14 @@ base::ProcessHandle TaskManagerNotificationResource::GetProcess() const {
return process_handle_;
}
+TaskManager::Resource::Type TaskManagerNotificationResource::GetType() const {
+ return NOTIFICATION;
+}
+
+bool TaskManagerNotificationResource::SupportNetworkUsage() const {
+ return false;
+}
+
////////////////////////////////////////////////////////////////////////////////
// TaskManagerNotificationResourceProvider class
////////////////////////////////////////////////////////////////////////////////
@@ -1203,6 +1280,22 @@ base::ProcessHandle TaskManagerBrowserProcessResource::GetProcess() const {
return base::GetCurrentProcessHandle(); // process_;
}
+TaskManager::Resource::Type TaskManagerBrowserProcessResource::GetType() const {
+ return BROWSER;
+}
+
+bool TaskManagerBrowserProcessResource::SupportNetworkUsage() const {
+ return true;
+}
+
+void TaskManagerBrowserProcessResource::SetSupportNetworkUsage() {
+ NOTREACHED();
+}
+
+bool TaskManagerBrowserProcessResource::ReportsSqliteMemoryUsed() const {
+ return true;
+}
+
////////////////////////////////////////////////////////////////////////////////
// TaskManagerBrowserProcessResourceProvider class
////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/task_manager/task_manager_resource_providers.h b/chrome/browser/task_manager/task_manager_resource_providers.h
index 9c4e8c4..b43a2d3 100644
--- a/chrome/browser/task_manager/task_manager_resource_providers.h
+++ b/chrome/browser/task_manager/task_manager_resource_providers.h
@@ -35,17 +35,17 @@ class TaskManagerRendererResource : public TaskManager::Resource {
virtual ~TaskManagerRendererResource();
// TaskManager::Resource methods:
- base::ProcessHandle GetProcess() const;
- Type GetType() const { return RENDERER; }
- virtual bool ReportsCacheStats() const { return true; }
+ virtual base::ProcessHandle GetProcess() const;
+ virtual Type GetType() const;
+ virtual bool ReportsCacheStats() const;
virtual WebKit::WebCache::ResourceTypeStats GetWebCoreCacheStats() const;
- virtual bool ReportsV8MemoryStats() const { return true; }
+ virtual bool ReportsV8MemoryStats() const;
virtual size_t GetV8MemoryAllocated() const;
virtual size_t GetV8MemoryUsed() const;
// RenderResources always provide the network usage.
- bool SupportNetworkUsage() const { return true; }
- void SetSupportNetworkUsage() { }
+ virtual bool SupportNetworkUsage() const;
+ virtual void SetSupportNetworkUsage() { }
virtual void Refresh();
@@ -78,12 +78,14 @@ class TaskManagerRendererResource : public TaskManager::Resource {
class TaskManagerTabContentsResource : public TaskManagerRendererResource {
public:
explicit TaskManagerTabContentsResource(TabContents* tab_contents);
- ~TaskManagerTabContentsResource();
+ virtual ~TaskManagerTabContentsResource();
// TaskManager::Resource methods:
+ virtual Type GetType() const;
virtual std::wstring GetTitle() const;
virtual SkBitmap GetIcon() const;
virtual TabContents* GetTabContents() const;
+ virtual const Extension* GetExtension() const;
private:
TabContents* tab_contents_;
@@ -138,7 +140,7 @@ class TaskManagerBackgroundContentsResource
TaskManagerBackgroundContentsResource(
BackgroundContents* background_contents,
const std::wstring& application_name);
- ~TaskManagerBackgroundContentsResource();
+ virtual ~TaskManagerBackgroundContentsResource();
// TaskManager::Resource methods:
virtual std::wstring GetTitle() const;
@@ -206,21 +208,15 @@ class TaskManagerBackgroundContentsResourceProvider
class TaskManagerChildProcessResource : public TaskManager::Resource {
public:
explicit TaskManagerChildProcessResource(const ChildProcessInfo& child_proc);
- ~TaskManagerChildProcessResource();
+ virtual ~TaskManagerChildProcessResource();
// TaskManagerResource methods:
- std::wstring GetTitle() const;
- SkBitmap GetIcon() const;
- base::ProcessHandle GetProcess() const;
- Type GetType() const;
-
- bool SupportNetworkUsage() const {
- return network_usage_support_;
- }
-
- void SetSupportNetworkUsage() {
- network_usage_support_ = true;
- }
+ virtual std::wstring GetTitle() const;
+ virtual SkBitmap GetIcon() const;
+ virtual base::ProcessHandle GetProcess() const;
+ virtual Type GetType() const;
+ virtual bool SupportNetworkUsage() const;
+ virtual void SetSupportNetworkUsage();
// Returns the pid of the child process.
int process_id() const { return pid_; }
@@ -296,22 +292,23 @@ class TaskManagerChildProcessResourceProvider
class TaskManagerExtensionProcessResource : public TaskManager::Resource {
public:
explicit TaskManagerExtensionProcessResource(ExtensionHost* extension_host);
- ~TaskManagerExtensionProcessResource();
+ virtual ~TaskManagerExtensionProcessResource();
// TaskManagerResource methods:
- std::wstring GetTitle() const;
- SkBitmap GetIcon() const;
- base::ProcessHandle GetProcess() const;
- Type GetType() const { return EXTENSION; }
- bool SupportNetworkUsage() const { return true; }
- void SetSupportNetworkUsage() { NOTREACHED(); }
- const Extension* GetExtension() const;
+ virtual std::wstring GetTitle() const;
+ virtual SkBitmap GetIcon() const;
+ virtual base::ProcessHandle GetProcess() const;
+ virtual Type GetType() const;
+ virtual bool SupportNetworkUsage() const;
+ virtual void SetSupportNetworkUsage();
+ virtual const Extension* GetExtension() const;
// Returns the pid of the extension process.
int process_id() const { return pid_; }
// Returns true if the associated extension has a background page.
- bool IsBackground() const;
+ virtual bool IsBackground() const;
+
private:
// The icon painted for the extension process.
static SkBitmap* default_icon_;
@@ -370,14 +367,14 @@ class TaskManagerExtensionProcessResourceProvider
class TaskManagerNotificationResource : public TaskManager::Resource {
public:
explicit TaskManagerNotificationResource(BalloonHost* balloon_host);
- ~TaskManagerNotificationResource();
+ virtual ~TaskManagerNotificationResource();
// TaskManager::Resource interface
- std::wstring GetTitle() const { return title_; }
- SkBitmap GetIcon() const;
- base::ProcessHandle GetProcess() const;
- Type GetType() const { return NOTIFICATION; }
- virtual bool SupportNetworkUsage() const { return false; }
+ virtual std::wstring GetTitle() const;
+ virtual SkBitmap GetIcon() const;
+ virtual base::ProcessHandle GetProcess() const;
+ virtual Type GetType() const;
+ virtual bool SupportNetworkUsage() const;
virtual void SetSupportNetworkUsage() { }
private:
@@ -435,19 +432,19 @@ class TaskManagerNotificationResourceProvider
class TaskManagerBrowserProcessResource : public TaskManager::Resource {
public:
TaskManagerBrowserProcessResource();
- ~TaskManagerBrowserProcessResource();
+ virtual ~TaskManagerBrowserProcessResource();
// TaskManagerResource methods:
- std::wstring GetTitle() const;
- SkBitmap GetIcon() const;
- base::ProcessHandle GetProcess() const;
- Type GetType() const { return BROWSER; }
+ virtual std::wstring GetTitle() const;
+ virtual SkBitmap GetIcon() const;
+ virtual base::ProcessHandle GetProcess() const;
+ virtual Type GetType() const;
- bool SupportNetworkUsage() const { return true; }
- void SetSupportNetworkUsage() { NOTREACHED(); }
+ virtual bool SupportNetworkUsage() const;
+ virtual void SetSupportNetworkUsage();
- bool ReportsSqliteMemoryUsed() const { return true; }
- size_t SqliteMemoryUsedBytes() const;
+ virtual bool ReportsSqliteMemoryUsed() const;
+ virtual size_t SqliteMemoryUsedBytes() const;
// Returns the pid of the browser process.
int process_id() const { return pid_; }
diff --git a/chrome/browser/themes/browser_theme_pack.cc b/chrome/browser/themes/browser_theme_pack.cc
index 62f09ef..6333900 100644
--- a/chrome/browser/themes/browser_theme_pack.cc
+++ b/chrome/browser/themes/browser_theme_pack.cc
@@ -4,8 +4,8 @@
#include "chrome/browser/themes/browser_theme_pack.h"
+#include "app/data_pack.h"
#include "app/resource_bundle.h"
-#include "base/data_pack.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "base/thread_restrictions.h"
@@ -370,7 +370,7 @@ scoped_refptr<BrowserThemePack> BrowserThemePack::BuildFromDataPack(
FilePath path, const std::string& expected_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
scoped_refptr<BrowserThemePack> pack(new BrowserThemePack);
- pack->data_pack_.reset(new base::DataPack);
+ pack->data_pack_.reset(new app::DataPack);
if (!pack->data_pack_->Load(path)) {
LOG(ERROR) << "Failed to load theme data pack.";
@@ -448,7 +448,7 @@ bool BrowserThemePack::WriteToDisk(FilePath path) const {
RepackImages(prepared_images_, &reencoded_images);
AddRawImagesTo(reencoded_images, &resources);
- return base::DataPack::WritePack(path, resources);
+ return app::DataPack::WritePack(path, resources);
}
bool BrowserThemePack::GetTint(int id, color_utils::HSL* hsl) const {
@@ -583,7 +583,7 @@ void BrowserThemePack::BuildHeader(const Extension* extension) {
header_->version = kThemePackVersion;
// TODO(erg): Need to make this endian safe on other computers. Prerequisite
- // is that base::DataPack removes this same check.
+ // is that app::DataPack removes this same check.
#if defined(__BYTE_ORDER)
// Linux check
COMPILE_ASSERT(__BYTE_ORDER == __LITTLE_ENDIAN,
diff --git a/chrome/browser/themes/browser_theme_pack.h b/chrome/browser/themes/browser_theme_pack.h
index 3771462..b90f30a 100644
--- a/chrome/browser/themes/browser_theme_pack.h
+++ b/chrome/browser/themes/browser_theme_pack.h
@@ -16,7 +16,7 @@
#include "chrome/browser/browser_thread.h"
#include "chrome/common/extensions/extension.h"
-namespace base {
+namespace app {
class DataPack;
}
class DictionaryValue;
@@ -170,7 +170,7 @@ class BrowserThemePack : public base::RefCountedThreadSafe<
color_utils::HSL GetTintInternal(int id) const;
// Data pack, if we have one.
- scoped_ptr<base::DataPack> data_pack_;
+ scoped_ptr<app::DataPack> data_pack_;
// All structs written to disk need to be packed; no alignment tricks here,
// please.
diff --git a/chrome/browser/themes/browser_theme_provider.cc b/chrome/browser/themes/browser_theme_provider.cc
index 4d296a5..1f70532 100644
--- a/chrome/browser/themes/browser_theme_provider.cc
+++ b/chrome/browser/themes/browser_theme_provider.cc
@@ -8,9 +8,9 @@
#include "base/string_split.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/themes/browser_theme_pack.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/notification_service.h"
@@ -304,7 +304,7 @@ void BrowserThemeProvider::SetTheme(const Extension* extension) {
void BrowserThemeProvider::RemoveUnusedThemes() {
if (!profile_)
return;
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
if (!service)
return;
std::string current_theme = GetThemeID();
@@ -326,6 +326,10 @@ void BrowserThemeProvider::UseDefaultTheme() {
UserMetrics::RecordAction(UserMetricsAction("Themes_Reset"), profile_);
}
+void BrowserThemeProvider::SetNativeTheme() {
+ UseDefaultTheme();
+}
+
bool BrowserThemeProvider::UsingDefaultTheme() {
return GetThemeID() == BrowserThemeProvider::kDefaultThemeID;
}
@@ -554,7 +558,7 @@ void BrowserThemeProvider::LoadThemePrefs() {
} else {
// TODO(erg): We need to pop up a dialog informing the user that their
// theme is being migrated.
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
if (service) {
const Extension* extension =
service->GetExtensionById(current_id, false);
diff --git a/chrome/browser/themes/browser_theme_provider.h b/chrome/browser/themes/browser_theme_provider.h
index 2322b8b..cddd153 100644
--- a/chrome/browser/themes/browser_theme_provider.h
+++ b/chrome/browser/themes/browser_theme_provider.h
@@ -159,7 +159,7 @@ class BrowserThemeProvider : public NonThreadSafe,
// Set the current theme to the native theme. On some platforms, the native
// theme is the default theme.
- virtual void SetNativeTheme() { UseDefaultTheme(); }
+ virtual void SetNativeTheme();
// Whether we're using the chrome default theme. Virtual so linux can check
// if we're using the GTK theme.
diff --git a/chrome/browser/toolbar_model.cc b/chrome/browser/toolbar_model.cc
deleted file mode 100644
index 6d55c65..0000000
--- a/chrome/browser/toolbar_model.cc
+++ /dev/null
@@ -1,129 +0,0 @@
-// 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.
-
-#include "chrome/browser/toolbar_model.h"
-
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/autocomplete/autocomplete.h"
-#include "chrome/browser/autocomplete/autocomplete_edit.h"
-#include "chrome/browser/cert_store.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/ssl/ssl_error_info.h"
-#include "chrome/browser/tab_contents/navigation_controller.h"
-#include "chrome/browser/tab_contents/navigation_entry.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/common/chrome_constants.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/url_constants.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#include "net/base/cert_status_flags.h"
-#include "net/base/net_util.h"
-
-ToolbarModel::ToolbarModel(Browser* browser)
- : browser_(browser),
- input_in_progress_(false) {
-}
-
-ToolbarModel::~ToolbarModel() {
-}
-
-// ToolbarModel Implementation.
-std::wstring ToolbarModel::GetText() const {
- GURL url(chrome::kAboutBlankURL);
- std::string languages; // Empty if we don't have a |navigation_controller|.
-
- NavigationController* navigation_controller = GetNavigationController();
- if (navigation_controller) {
- languages = navigation_controller->profile()->GetPrefs()->GetString(
- prefs::kAcceptLanguages);
- NavigationEntry* entry = navigation_controller->GetActiveEntry();
- if (!navigation_controller->tab_contents()->ShouldDisplayURL()) {
- // Explicitly hide the URL for this tab.
- url = GURL();
- } else if (entry) {
- url = entry->virtual_url();
- }
- }
- if (url.spec().length() > chrome::kMaxURLDisplayChars)
- url = url.IsStandard() ? url.GetOrigin() : GURL(url.scheme() + ":");
- // Note that we can't unescape spaces here, because if the user copies this
- // and pastes it into another program, that program may think the URL ends at
- // the space.
- return AutocompleteInput::FormattedStringWithEquivalentMeaning(url,
- UTF16ToWideHack(net::FormatUrl(url, languages, net::kFormatUrlOmitAll,
- UnescapeRule::NORMAL, NULL, NULL, NULL)));
-}
-
-ToolbarModel::SecurityLevel ToolbarModel::GetSecurityLevel() const {
- if (input_in_progress_) // When editing, assume no security style.
- return NONE;
-
- NavigationController* navigation_controller = GetNavigationController();
- if (!navigation_controller) // We might not have a controller on init.
- return NONE;
-
- NavigationEntry* entry = navigation_controller->GetActiveEntry();
- if (!entry)
- return NONE;
-
- const NavigationEntry::SSLStatus& ssl = entry->ssl();
- switch (ssl.security_style()) {
- case SECURITY_STYLE_UNKNOWN:
- case SECURITY_STYLE_UNAUTHENTICATED:
- return NONE;
-
- case SECURITY_STYLE_AUTHENTICATION_BROKEN:
- return SECURITY_ERROR;
-
- case SECURITY_STYLE_AUTHENTICATED:
- if (ssl.displayed_insecure_content())
- return SECURITY_WARNING;
- if (net::IsCertStatusError(ssl.cert_status())) {
- DCHECK_EQ(ssl.cert_status() & net::CERT_STATUS_ALL_ERRORS,
- net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION);
- return SECURITY_WARNING;
- }
- if ((ssl.cert_status() & net::CERT_STATUS_IS_EV) &&
- CertStore::GetSharedInstance()->RetrieveCert(ssl.cert_id(), NULL))
- return EV_SECURE;
- return SECURE;
-
- default:
- NOTREACHED();
- return NONE;
- }
-}
-
-int ToolbarModel::GetIcon() const {
- static int icon_ids[NUM_SECURITY_LEVELS] = {
- IDR_OMNIBOX_HTTP,
- IDR_OMNIBOX_HTTPS_VALID,
- IDR_OMNIBOX_HTTPS_VALID,
- IDR_OMNIBOX_HTTPS_WARNING,
- IDR_OMNIBOX_HTTPS_INVALID,
- };
- DCHECK(arraysize(icon_ids) == NUM_SECURITY_LEVELS);
- return icon_ids[GetSecurityLevel()];
-}
-
-std::wstring ToolbarModel::GetEVCertName() const {
- DCHECK_EQ(GetSecurityLevel(), EV_SECURE);
- scoped_refptr<net::X509Certificate> cert;
- // Note: Navigation controller and active entry are guaranteed non-NULL or
- // the security level would be NONE.
- CertStore::GetSharedInstance()->RetrieveCert(
- GetNavigationController()->GetActiveEntry()->ssl().cert_id(), &cert);
- return SSLManager::GetEVCertName(*cert);
-}
-
-NavigationController* ToolbarModel::GetNavigationController() const {
- // This |current_tab| can be NULL during the initialization of the
- // toolbar during window creation (i.e. before any tabs have been added
- // to the window).
- TabContents* current_tab = browser_->GetSelectedTabContents();
- return current_tab ? &current_tab->controller() : NULL;
-}
diff --git a/chrome/browser/toolbar_model.h b/chrome/browser/toolbar_model.h
deleted file mode 100644
index 06050c1..0000000
--- a/chrome/browser/toolbar_model.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_TOOLBAR_MODEL_H__
-#define CHROME_BROWSER_TOOLBAR_MODEL_H__
-#pragma once
-
-#include <string>
-
-#include "base/basictypes.h"
-
-class Browser;
-class NavigationController;
-
-// This class is the model used by the toolbar, location bar and autocomplete
-// edit. It populates its states from the current navigation entry retrieved
-// from the navigation controller returned by GetNavigationController().
-class ToolbarModel {
- public:
- // TODO(wtc): unify ToolbarModel::SecurityLevel with SecurityStyle. We
- // don't need two sets of security UI levels. SECURITY_STYLE_AUTHENTICATED
- // needs to be refined into three levels: warning, standard, and EV.
- enum SecurityLevel {
- NONE = 0, // HTTP/no URL/user is editing
- EV_SECURE, // HTTPS with valid EV cert
- SECURE, // HTTPS (non-EV)
- SECURITY_WARNING, // HTTPS, but unable to check certificate revocation
- // status or with insecure content on the page
- SECURITY_ERROR, // Attempted HTTPS and failed, page not authenticated
- NUM_SECURITY_LEVELS,
- };
-
- explicit ToolbarModel(Browser* browser);
- ~ToolbarModel();
-
- // Returns the text that should be displayed in the location bar.
- std::wstring GetText() const;
-
- // Returns the security level that the toolbar should display.
- SecurityLevel GetSecurityLevel() const;
-
- // Returns the resource_id of the icon to show to the left of the address,
- // based on the current URL. This doesn't cover specialized icons while the
- // user is editing; see AutocompleteEditView::GetIcon().
- int GetIcon() const;
-
- // Returns the name of the EV cert holder. Only call this when the security
- // level is EV_SECURE.
- std::wstring GetEVCertName() const;
-
- // Getter/setter of whether the text in location bar is currently being
- // edited.
- void set_input_in_progress(bool value) { input_in_progress_ = value; }
- bool input_in_progress() const { return input_in_progress_; }
-
- private:
- // Returns the navigation controller used to retrieve the navigation entry
- // from which the states are retrieved.
- // If this returns NULL, default values are used.
- NavigationController* GetNavigationController() const;
-
- Browser* browser_;
-
- // Whether the text in the location bar is currently being edited.
- bool input_in_progress_;
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(ToolbarModel);
-};
-
-#endif // CHROME_BROWSER_TOOLBAR_MODEL_H__
diff --git a/chrome/browser/translate/options_menu_model.cc b/chrome/browser/translate/options_menu_model.cc
index e9b0943..4a074ce 100644
--- a/chrome/browser/translate/options_menu_model.cc
+++ b/chrome/browser/translate/options_menu_model.cc
@@ -7,9 +7,8 @@
#include "app/l10n_util.h"
#include "base/metrics/histogram.h"
#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/google/google_util.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/translate/translate_infobar_delegate.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/translate/translate_infobar_delegate.cc b/chrome/browser/translate/translate_infobar_delegate.cc
index 3ff8502..356975d 100644
--- a/chrome/browser/translate/translate_infobar_delegate.cc
+++ b/chrome/browser/translate/translate_infobar_delegate.cc
@@ -10,7 +10,7 @@
#include "app/resource_bundle.h"
#include "base/metrics/histogram.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/translate/translate_infobar_view.h"
#include "chrome/browser/translate/translate_manager.h"
@@ -157,19 +157,19 @@ void TranslateInfoBarDelegate::Translate() {
prefs_.IncrementTranslationAcceptedCount(original_language_code);
}
- Singleton<TranslateManager>::get()->TranslatePage(
+ TranslateManager::GetInstance()->TranslatePage(
tab_contents_,
GetLanguageCodeAt(original_language_index()),
GetLanguageCodeAt(target_language_index()));
}
void TranslateInfoBarDelegate::RevertTranslation() {
- Singleton<TranslateManager>::get()->RevertTranslation(tab_contents_);
+ TranslateManager::GetInstance()->RevertTranslation(tab_contents_);
tab_contents_->RemoveInfoBar(this);
}
void TranslateInfoBarDelegate::ReportLanguageDetectionError() {
- Singleton<TranslateManager>::get()->
+ TranslateManager::GetInstance()->
ReportLanguageDetectionError(tab_contents_);
}
@@ -339,7 +339,7 @@ void TranslateInfoBarDelegate::MessageInfoBarButtonPressed() {
return;
}
// This is the "Try again..." case.
- Singleton<TranslateManager>::get()->TranslatePage(
+ TranslateManager::GetInstance()->TranslatePage(
tab_contents_, GetOriginalLanguageCode(), GetTargetLanguageCode());
}
diff --git a/chrome/browser/translate/translate_manager.cc b/chrome/browser/translate/translate_manager.cc
index a39c24e..84b576e 100644
--- a/chrome/browser/translate/translate_manager.cc
+++ b/chrome/browser/translate/translate_manager.cc
@@ -8,12 +8,13 @@
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/metrics/histogram.h"
+#include "base/singleton.h"
#include "base/string_split.h"
#include "base/string_util.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/language_state.h"
@@ -33,6 +34,7 @@
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/translate_errors.h"
+#include "chrome/common/url_constants.h"
#include "grit/browser_resources.h"
#include "net/base/escape.h"
#include "net/url_request/url_request_status.h"
@@ -145,8 +147,20 @@ TranslateManager::~TranslateManager() {
}
// static
+TranslateManager* TranslateManager::GetInstance() {
+ return Singleton<TranslateManager>::get();
+}
+
+// static
bool TranslateManager::IsTranslatableURL(const GURL& url) {
- return !url.SchemeIs("chrome") && !url.SchemeIs("ftp");
+ // A URLs is translatable unless it is one of the following:
+ // - an internal URL (chrome:// and others)
+ // - the devtools (which is considered UI)
+ // - an FTP page (as FTP pages tend to have long lists of filenames that may
+ // confuse the CLD)
+ return !url.SchemeIs(chrome::kChromeUIScheme) &&
+ !url.SchemeIs(chrome::kChromeDevToolsScheme) &&
+ !url.SchemeIs(chrome::kFtpScheme);
}
// static
diff --git a/chrome/browser/translate/translate_manager.h b/chrome/browser/translate/translate_manager.h
index 7050484..48e1951 100644
--- a/chrome/browser/translate/translate_manager.h
+++ b/chrome/browser/translate/translate_manager.h
@@ -12,7 +12,6 @@
#include <vector>
#include "base/lazy_instance.h"
-#include "base/singleton.h"
#include "base/task.h"
#include "chrome/browser/prefs/pref_change_registrar.h"
#include "chrome/common/net/url_fetcher.h"
@@ -20,6 +19,7 @@
#include "chrome/common/notification_registrar.h"
#include "chrome/common/translate_errors.h"
+template <typename T> struct DefaultSingletonTraits;
class GURL;
struct PageTranslatedDetails;
class PrefService;
@@ -34,6 +34,9 @@ class TranslateInfoBarDelegate;
class TranslateManager : public NotificationObserver,
public URLFetcher::Delegate {
public:
+ // Returns the singleton instance.
+ static TranslateManager* GetInstance();
+
virtual ~TranslateManager();
// Translates the page contents from |source_lang| to |target_lang|.
@@ -77,9 +80,7 @@ class TranslateManager : public NotificationObserver,
// Convenience method to know if a tab is showing a translate infobar.
static bool IsShowingTranslateInfobar(TabContents* tab);
- // Returns true if the URL can be translated, if it is not an internal URL
- // (chrome:// and others) or a FTP page (as FTP pages tend to have long
- // lists of filenames that may confuse the CLD).
+ // Returns true if the URL can be translated.
static bool IsTranslatableURL(const GURL& url);
// Fills |languages| with the list of languages that the translate server can
diff --git a/chrome/browser/translate/translate_manager_unittest.cc b/chrome/browser/translate/translate_manager_unittest.cc
index 3055ed6..89cc355 100644
--- a/chrome/browser/translate/translate_manager_unittest.cc
+++ b/chrome/browser/translate/translate_manager_unittest.cc
@@ -19,7 +19,6 @@
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_observer_mock.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
@@ -121,8 +120,7 @@ class TranslateManagerTest : public RenderViewHostTestHarness,
}
void ExpireTranslateScriptImmediately() {
- Singleton<TranslateManager>::get()->
- set_translate_script_expiration_delay(0);
+ TranslateManager::GetInstance()->set_translate_script_expiration_delay(0);
}
// If there is 1 infobar and it is a translate infobar, deny translation and
@@ -155,8 +153,8 @@ class TranslateManagerTest : public RenderViewHostTestHarness,
// Also clears the translate script so it is fetched everytime and sets the
// expiration delay to a large value by default (in case it was zeroed in
// a previous test).
- Singleton<TranslateManager>::get()->ClearTranslateScript();
- Singleton<TranslateManager>::get()->
+ TranslateManager::GetInstance()->ClearTranslateScript();
+ TranslateManager::GetInstance()->
set_translate_script_expiration_delay(60 * 60 * 1000);
RenderViewHostTestHarness::SetUp();
diff --git a/chrome/browser/ui/app_modal_dialogs/app_modal_dialog.cc b/chrome/browser/ui/app_modal_dialogs/app_modal_dialog.cc
new file mode 100644
index 0000000..40e9189
--- /dev/null
+++ b/chrome/browser/ui/app_modal_dialogs/app_modal_dialog.cc
@@ -0,0 +1,57 @@
+// 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.
+
+#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
+
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h"
+#include "chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
+
+AppModalDialog::AppModalDialog(TabContents* tab_contents,
+ const std::wstring& title)
+ : skip_this_dialog_(false),
+ tab_contents_(tab_contents),
+ native_dialog_(NULL),
+ title_(title) {
+}
+
+AppModalDialog::~AppModalDialog() {
+}
+
+void AppModalDialog::ShowModalDialog() {
+ if (tab_contents_)
+ tab_contents_->Activate();
+
+ CreateAndShowDialog();
+
+ NotificationService::current()->Notify(
+ NotificationType::APP_MODAL_DIALOG_SHOWN,
+ Source<AppModalDialog>(this),
+ NotificationService::NoDetails());
+}
+
+void AppModalDialog::CreateAndShowDialog() {
+ native_dialog_ = CreateNativeDialog();
+ native_dialog_->ShowAppModalDialog();
+}
+
+bool AppModalDialog::IsValid() {
+ return !skip_this_dialog_;
+}
+
+void AppModalDialog::ActivateModalDialog() {
+ DCHECK(native_dialog_);
+ native_dialog_->ActivateAppModalDialog();
+}
+
+void AppModalDialog::CloseModalDialog() {
+ DCHECK(native_dialog_);
+ native_dialog_->CloseAppModalDialog();
+}
+
+void AppModalDialog::CompleteDialog() {
+ AppModalDialogQueue::GetInstance()->ShowNextDialog();
+}
diff --git a/chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h b/chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h
new file mode 100644
index 0000000..ddc1808
--- /dev/null
+++ b/chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h
@@ -0,0 +1,82 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_APP_MODAL_DIALOGS_APP_MODAL_DIALOG_H_
+#define CHROME_BROWSER_UI_APP_MODAL_DIALOGS_APP_MODAL_DIALOG_H_
+#pragma once
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "build/build_config.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+
+class NativeAppModalDialog;
+class TabContents;
+
+// A controller+model base class for modal dialogs.
+class AppModalDialog {
+ public:
+ // A union of data necessary to determine the type of message box to
+ // show. |tab_contents| parameter is optional, if provided that tab will be
+ // activated before the modal dialog is displayed.
+ AppModalDialog(TabContents* tab_contents, const std::wstring& title);
+ virtual ~AppModalDialog();
+
+ // Called by the AppModalDialogQueue to show this dialog.
+ void ShowModalDialog();
+
+ // Called by the AppModalDialogQueue to activate the dialog.
+ void ActivateModalDialog();
+
+ // Closes the dialog if it is showing.
+ void CloseModalDialog();
+
+ // Completes dialog handling, shows next modal dialog from the queue.
+ // TODO(beng): Get rid of this method.
+ void CompleteDialog();
+
+ // Dialog window title.
+ std::wstring title() const { return title_; }
+
+ NativeAppModalDialog* native_dialog() const { return native_dialog_; }
+
+ // Methods overridable by AppModalDialog subclasses:
+
+ // Creates an implementation of NativeAppModalDialog and shows it.
+ // When the native dialog is closed, the implementation of
+ // NativeAppModalDialog should call OnAccept or OnCancel to notify the
+ // renderer of the user's action. The NativeAppModalDialog is also
+ // expected to delete the AppModalDialog associated with it.
+ virtual void CreateAndShowDialog();
+
+ // Returns true if the dialog is still valid. As dialogs are created they are
+ // added to the AppModalDialogQueue. When the current modal dialog finishes
+ // and it's time to show the next dialog in the queue IsValid is invoked.
+ // If IsValid returns false the dialog is deleted and not shown.
+ virtual bool IsValid();
+
+ protected:
+ // Overridden by subclasses to create the feature-specific native dialog box.
+ virtual NativeAppModalDialog* CreateNativeDialog() = 0;
+
+ // True if the dialog should no longer be shown, e.g. because the underlying
+ // tab navigated away while the dialog was queued.
+ bool skip_this_dialog_;
+
+ // Parent tab contents.
+ TabContents* tab_contents_;
+
+ // The toolkit-specific implementation of the app modal dialog box.
+ NativeAppModalDialog* native_dialog_;
+
+ private:
+ // Information about the message box is held in the following variables.
+ std::wstring title_;
+
+ DISALLOW_COPY_AND_ASSIGN(AppModalDialog);
+};
+
+#endif // CHROME_BROWSER_UI_APP_MODAL_DIALOGS_APP_MODAL_DIALOG_H_
diff --git a/chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.cc b/chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.cc
new file mode 100644
index 0000000..e70285c
--- /dev/null
+++ b/chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.cc
@@ -0,0 +1,69 @@
+// 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.
+
+#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h"
+
+#include "base/singleton.h"
+
+void AppModalDialogQueue::AddDialog(AppModalDialog* dialog) {
+ if (!active_dialog_) {
+ ShowModalDialog(dialog);
+ return;
+ }
+ app_modal_dialog_queue_.push(dialog);
+}
+
+void AppModalDialogQueue::ShowNextDialog() {
+ AppModalDialog* dialog = GetNextDialog();
+ if (dialog)
+ ShowModalDialog(dialog);
+ else
+ active_dialog_ = NULL;
+}
+
+void AppModalDialogQueue::ActivateModalDialog() {
+ if (showing_modal_dialog_) {
+ // As part of showing a modal dialog we may end up back in this method
+ // (showing a dialog activates the TabContents, which can trigger a call
+ // to ActivateModalDialog). We ignore such a request as after the call to
+ // activate the tab contents the dialog is shown.
+ return;
+ }
+ if (active_dialog_)
+ active_dialog_->ActivateModalDialog();
+}
+
+AppModalDialogQueue::AppModalDialogQueue()
+ : active_dialog_(NULL), showing_modal_dialog_(false) {
+}
+
+AppModalDialogQueue::~AppModalDialogQueue() {}
+
+// static
+AppModalDialogQueue* AppModalDialogQueue::GetInstance() {
+ return Singleton<AppModalDialogQueue>::get();
+}
+
+void AppModalDialogQueue::ShowModalDialog(AppModalDialog* dialog) {
+ // Be sure and set the active_dialog_ field first, otherwise if
+ // ShowModalDialog triggers a call back to the queue they'll get the old
+ // dialog. Also, if the dialog calls |ShowNextDialog()| before returning, that
+ // would write NULL into |active_dialog_| and this function would then undo
+ // that.
+ active_dialog_ = dialog;
+ showing_modal_dialog_ = true;
+ dialog->ShowModalDialog();
+ showing_modal_dialog_ = false;
+}
+
+AppModalDialog* AppModalDialogQueue::GetNextDialog() {
+ while (!app_modal_dialog_queue_.empty()) {
+ AppModalDialog* dialog = app_modal_dialog_queue_.front();
+ app_modal_dialog_queue_.pop();
+ if (dialog->IsValid())
+ return dialog;
+ delete dialog;
+ }
+ return NULL;
+}
diff --git a/chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h b/chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h
new file mode 100644
index 0000000..be24a74
--- /dev/null
+++ b/chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h
@@ -0,0 +1,89 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_APP_MODAL_DIALOGS_APP_MODAL_DIALOG_QUEUE_H_
+#define CHROME_BROWSER_UI_APP_MODAL_DIALOGS_APP_MODAL_DIALOG_QUEUE_H_
+#pragma once
+
+#include <queue>
+
+#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
+
+template <typename T> struct DefaultSingletonTraits;
+
+// Keeps a queue of AppModalDialogs, making sure only one app modal
+// dialog is shown at a time.
+// This class is a singleton.
+class AppModalDialogQueue {
+ public:
+ // Returns the singleton instance.
+ static AppModalDialogQueue* GetInstance();
+
+ // Adds a modal dialog to the queue, if there are no other dialogs in the
+ // queue, the dialog will be shown immediately. Once it is shown, the
+ // most recently active browser window (or whichever is currently active)
+ // will be app modal, meaning it will be activated if the user tries to
+ // activate any other browser windows. So the dialog being shown should
+ // assure it is the child of BrowserList::GetLastActive() so that it is
+ // activated as well. See browser_list.h for more notes about our somewhat
+ // sloppy app modality.
+ // Note: The AppModalDialog |dialog| must be window modal before it
+ // can be added as app modal.
+ void AddDialog(AppModalDialog* dialog);
+
+ // Removes the current dialog in the queue (the one that is being shown).
+ // Shows the next dialog in the queue, if any is present. This does not
+ // ensure that the currently showing dialog is closed, it just makes it no
+ // longer app modal.
+ void ShowNextDialog();
+
+ // Activates and shows the current dialog, if the user clicks on one of the
+ // windows disabled by the presence of an app modal dialog. This forces
+ // the window to be visible on the display even if desktop manager software
+ // opened the dialog on another virtual desktop. Assumes there is currently a
+ // dialog being shown. (Call BrowserList::IsShowingAppModalDialog to test
+ // this condition).
+ void ActivateModalDialog();
+
+ // Returns true if there is currently an active app modal dialog box.
+ bool HasActiveDialog() {
+ return active_dialog_ != NULL;
+ }
+
+ // Accessor for |active_dialog_|.
+ AppModalDialog* active_dialog() {
+ return active_dialog_;
+ }
+
+ private:
+ friend struct DefaultSingletonTraits<AppModalDialogQueue>;
+
+ AppModalDialogQueue();
+ ~AppModalDialogQueue();
+
+ // Shows |dialog| and notifies the BrowserList that a modal dialog is showing.
+ void ShowModalDialog(AppModalDialog* dialog);
+
+ // Returns the next dialog to show. This removes entries from
+ // app_modal_dialog_queue_ until one is valid or the queue is empty. This
+ // returns NULL if there are no more dialogs, or all the dialogs in the queue
+ // are not valid.
+ AppModalDialog* GetNextDialog();
+
+ // Contains all app modal dialogs which are waiting to be shown, with the
+ // currently modal dialog at the front of the queue.
+ std::queue<AppModalDialog*> app_modal_dialog_queue_;
+
+ // The currently active app-modal dialog box's delegate. NULL if there is no
+ // active app-modal dialog box.
+ AppModalDialog* active_dialog_;
+
+ // Stores if |ShowModalDialog()| is currently being called on an app-modal
+ // dialog.
+ bool showing_modal_dialog_;
+
+ DISALLOW_COPY_AND_ASSIGN(AppModalDialogQueue);
+};
+
+#endif // CHROME_BROWSER_UI_APP_MODAL_DIALOGS_APP_MODAL_DIALOG_QUEUE_H_
diff --git a/chrome/browser/ui/app_modal_dialogs/js_modal_dialog.cc b/chrome/browser/ui/app_modal_dialogs/js_modal_dialog.cc
new file mode 100644
index 0000000..801562d
--- /dev/null
+++ b/chrome/browser/ui/app_modal_dialogs/js_modal_dialog.cc
@@ -0,0 +1,145 @@
+// 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.
+
+#include "chrome/browser/ui/app_modal_dialogs/js_modal_dialog.h"
+
+#include "app/text_elider.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/browser_shutdown.h"
+#include "chrome/browser/extensions/extension_host.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
+#include "ipc/ipc_message.h"
+
+namespace {
+
+// The maximum sizes of various texts passed to us from javascript.
+const int kMessageTextMaxRows = 32;
+const int kMessageTextMaxCols = 132;
+const int kDefaultPromptTextSize = 2000;
+
+} // namespace
+
+JavaScriptAppModalDialog::JavaScriptAppModalDialog(
+ JavaScriptAppModalDialogDelegate* delegate,
+ const std::wstring& title,
+ int dialog_flags,
+ const std::wstring& message_text,
+ const std::wstring& default_prompt_text,
+ bool display_suppress_checkbox,
+ bool is_before_unload_dialog,
+ IPC::Message* reply_msg)
+ : AppModalDialog(delegate->AsTabContents(), title),
+ delegate_(delegate),
+ extension_host_(delegate->AsExtensionHost()),
+ dialog_flags_(dialog_flags),
+ display_suppress_checkbox_(display_suppress_checkbox),
+ is_before_unload_dialog_(is_before_unload_dialog),
+ reply_msg_(reply_msg) {
+ // We trim the various parts of the message dialog because otherwise we can
+ // overflow the message dialog (and crash/hang the GTK+ version).
+ string16 elided_text;
+ gfx::ElideRectangleString(WideToUTF16(message_text),
+ kMessageTextMaxRows, kMessageTextMaxCols, &elided_text);
+ message_text_ = UTF16ToWide(elided_text);
+ gfx::ElideString(default_prompt_text, kDefaultPromptTextSize,
+ &default_prompt_text_);
+
+ DCHECK((tab_contents_ != NULL) != (extension_host_ != NULL));
+ InitNotifications();
+}
+
+JavaScriptAppModalDialog::~JavaScriptAppModalDialog() {
+}
+
+NativeAppModalDialog* JavaScriptAppModalDialog::CreateNativeDialog() {
+ gfx::NativeWindow parent_window = tab_contents_ ?
+ tab_contents_->GetMessageBoxRootWindow() :
+ extension_host_->GetMessageBoxRootWindow();
+ return NativeAppModalDialog::CreateNativeJavaScriptPrompt(this,
+ parent_window);
+}
+
+void JavaScriptAppModalDialog::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (skip_this_dialog_)
+ return;
+
+ if (NotificationType::EXTENSION_HOST_DESTROYED == type &&
+ Details<ExtensionHost>(extension_host_) != details)
+ return;
+
+ // If we reach here, we know the notification is relevant to us, either
+ // because we're only observing applicable sources or because we passed the
+ // check above. Both of those indicate that we should ignore this dialog.
+ // Also clear the delegate, since it's now invalid.
+ skip_this_dialog_ = true;
+ delegate_ = NULL;
+ if (native_dialog_)
+ CloseModalDialog();
+}
+
+void JavaScriptAppModalDialog::InitNotifications() {
+ // Make sure we get relevant navigation notifications so we know when our
+ // parent contents will disappear or navigate to a different page.
+ if (tab_contents_) {
+ registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
+ Source<NavigationController>(&tab_contents_->controller()));
+ registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
+ Source<TabContents>(tab_contents_));
+ } else if (extension_host_) {
+ // EXTENSION_HOST_DESTROYED uses the Profile as its source, but we care
+ // about the ExtensionHost (which is passed in the details).
+ registrar_.Add(this, NotificationType::EXTENSION_HOST_DESTROYED,
+ NotificationService::AllSources());
+ } else {
+ NOTREACHED();
+ }
+}
+
+void JavaScriptAppModalDialog::OnCancel(bool suppress_js_messages) {
+ // If we are shutting down and this is an onbeforeunload dialog, cancel the
+ // shutdown.
+ if (is_before_unload_dialog_)
+ browser_shutdown::SetTryingToQuit(false);
+
+ // We need to do this before WM_DESTROY (WindowClosing()) as any parent frame
+ // will receive its activation messages before this dialog receives
+ // WM_DESTROY. The parent frame would then try to activate any modal dialogs
+ // that were still open in the ModalDialogQueue, which would send activation
+ // back to this one. The framework should be improved to handle this, so this
+ // is a temporary workaround.
+ CompleteDialog();
+
+ NotifyDelegate(false, L"", suppress_js_messages);
+}
+
+void JavaScriptAppModalDialog::OnAccept(const std::wstring& prompt_text,
+ bool suppress_js_messages) {
+ CompleteDialog();
+ NotifyDelegate(true, prompt_text, suppress_js_messages);
+}
+
+void JavaScriptAppModalDialog::OnClose() {
+ NotifyDelegate(false, L"", false);
+}
+
+void JavaScriptAppModalDialog::NotifyDelegate(bool success,
+ const std::wstring& prompt_text,
+ bool suppress_js_messages) {
+ if (skip_this_dialog_)
+ return;
+
+ delegate_->OnMessageBoxClosed(reply_msg_, success, prompt_text);
+ if (suppress_js_messages)
+ delegate_->SetSuppressMessageBoxes(true);
+
+ // On Views, we can end up coming through this code path twice :(.
+ // See crbug.com/63732.
+ skip_this_dialog_ = true;
+}
diff --git a/chrome/browser/ui/app_modal_dialogs/js_modal_dialog.h b/chrome/browser/ui/app_modal_dialogs/js_modal_dialog.h
new file mode 100644
index 0000000..10615eb
--- /dev/null
+++ b/chrome/browser/ui/app_modal_dialogs/js_modal_dialog.h
@@ -0,0 +1,120 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_APP_MODAL_DIALOGS_JS_MODAL_DIALOG_H_
+#define CHROME_BROWSER_UI_APP_MODAL_DIALOGS_JS_MODAL_DIALOG_H_
+#pragma once
+
+#include <string>
+
+#include "build/build_config.h"
+#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+#include "gfx/native_widget_types.h"
+
+class ExtensionHost;
+class NativeAppModalDialog;
+class TabContents;
+
+namespace IPC {
+class Message;
+}
+
+class JavaScriptAppModalDialogDelegate {
+ public:
+ // AppModalDialog calls this when the dialog is closed.
+ virtual void OnMessageBoxClosed(IPC::Message* reply_msg,
+ bool success,
+ const std::wstring& prompt) = 0;
+
+ // Indicates whether additional message boxes should be suppressed.
+ virtual void SetSuppressMessageBoxes(bool suppress_message_boxes) = 0;
+
+ // Returns the root native window with which the message box is associated.
+ virtual gfx::NativeWindow GetMessageBoxRootWindow() = 0;
+
+ // Returns the TabContents or ExtensionHost associated with this message
+ // box -- in practice, the object implementing this interface. Exactly one
+ // of these must be non-NULL; behavior is undefined (read: it'll probably
+ // crash) if that is not the case.
+ virtual TabContents* AsTabContents() = 0;
+ virtual ExtensionHost* AsExtensionHost() = 0;
+
+ protected:
+ virtual ~JavaScriptAppModalDialogDelegate() {}
+};
+
+// A controller + model class for JavaScript alert, confirm, prompt, and
+// onbeforeunload dialog boxes.
+class JavaScriptAppModalDialog : public AppModalDialog,
+ public NotificationObserver {
+ public:
+ JavaScriptAppModalDialog(JavaScriptAppModalDialogDelegate* delegate,
+ const std::wstring& title,
+ int dialog_flags,
+ const std::wstring& message_text,
+ const std::wstring& default_prompt_text,
+ bool display_suppress_checkbox,
+ bool is_before_unload_dialog,
+ IPC::Message* reply_msg);
+ virtual ~JavaScriptAppModalDialog();
+
+ // Overridden from AppModalDialog:
+ virtual NativeAppModalDialog* CreateNativeDialog();
+
+ JavaScriptAppModalDialogDelegate* delegate() const { return delegate_; }
+
+ // Callbacks from NativeDialog when the user accepts or cancels the dialog.
+ void OnCancel(bool suppress_js_messages);
+ void OnAccept(const std::wstring& prompt_text, bool suppress_js_messages);
+
+ // NOTE: This is only called under Views, and should be removed. Any critical
+ // work should be done in OnCancel or OnAccept. See crbug.com/63732 for more.
+ void OnClose();
+
+ // Accessors
+ int dialog_flags() const { return dialog_flags_; }
+ std::wstring message_text() const { return message_text_; }
+ std::wstring default_prompt_text() const { return default_prompt_text_; }
+ bool display_suppress_checkbox() const { return display_suppress_checkbox_; }
+ bool is_before_unload_dialog() const { return is_before_unload_dialog_; }
+
+ private:
+ // Overridden from NotificationObserver:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // Initializes for notifications to listen.
+ void InitNotifications();
+
+ // Notifies the delegate with the result of the dialog.
+ void NotifyDelegate(bool success, const std::wstring& prompt_text,
+ bool suppress_js_messages);
+
+ NotificationRegistrar registrar_;
+
+ // An implementation of the client interface to provide supporting methods
+ // and receive results.
+ JavaScriptAppModalDialogDelegate* delegate_;
+
+ // The client_ as an ExtensionHost, cached for use during notifications that
+ // may arrive after the client has entered its destructor (and is thus
+ // treated as a base Delegate). This will be NULL if the |delegate_| is not an
+ // ExtensionHost.
+ ExtensionHost* extension_host_;
+
+ // Information about the message box is held in the following variables.
+ int dialog_flags_;
+ std::wstring message_text_;
+ std::wstring default_prompt_text_;
+ bool display_suppress_checkbox_;
+ bool is_before_unload_dialog_;
+ IPC::Message* reply_msg_;
+
+ DISALLOW_COPY_AND_ASSIGN(JavaScriptAppModalDialog);
+};
+
+#endif // CHROME_BROWSER_UI_APP_MODAL_DIALOGS_JS_MODAL_DIALOG_H_
diff --git a/chrome/browser/ui/app_modal_dialogs/message_box_handler.cc b/chrome/browser/ui/app_modal_dialogs/message_box_handler.cc
new file mode 100644
index 0000000..a486abb
--- /dev/null
+++ b/chrome/browser/ui/app_modal_dialogs/message_box_handler.cc
@@ -0,0 +1,88 @@
+// 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.
+
+#include "chrome/browser/ui/app_modal_dialogs/message_box_handler.h"
+
+#include "app/l10n_util.h"
+#include "app/message_box_flags.h"
+#include "app/text_elider.h"
+#include "base/i18n/rtl.h"
+#include "base/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h"
+#include "chrome/browser/ui/app_modal_dialogs/js_modal_dialog.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
+#include "gfx/font.h"
+#include "googleurl/src/gurl.h"
+#include "grit/generated_resources.h"
+#include "grit/chromium_strings.h"
+
+static std::wstring GetTitle(Profile* profile,
+ bool is_alert,
+ const GURL& frame_url) {
+ ExtensionService* extensions_service = profile->GetExtensionService();
+ if (extensions_service) {
+ const Extension* extension =
+ extensions_service->GetExtensionByURL(frame_url);
+ if (!extension)
+ extension = extensions_service->GetExtensionByWebExtent(frame_url);
+
+ if (extension && (extension->location() == Extension::COMPONENT)) {
+ return l10n_util::GetString(IDS_PRODUCT_NAME);
+ } else if (extension && !extension->name().empty()) {
+ return UTF8ToWide(extension->name());
+ }
+ }
+ if (!frame_url.has_host()) {
+ return l10n_util::GetString(
+ is_alert ? IDS_JAVASCRIPT_ALERT_DEFAULT_TITLE
+ : IDS_JAVASCRIPT_MESSAGEBOX_DEFAULT_TITLE);
+ }
+
+ // TODO(brettw) it should be easier than this to do the correct language
+ // handling without getting the accept language from the profile.
+ string16 base_address = gfx::ElideUrl(frame_url.GetOrigin(),
+ gfx::Font(), 0,
+ UTF8ToWide(profile->GetPrefs()->GetString(prefs::kAcceptLanguages)));
+
+ // Force URL to have LTR directionality.
+ base_address = base::i18n::GetDisplayStringInLTRDirectionality(
+ base_address);
+
+ return UTF16ToWide(l10n_util::GetStringFUTF16(
+ is_alert ? IDS_JAVASCRIPT_ALERT_TITLE :
+ IDS_JAVASCRIPT_MESSAGEBOX_TITLE,
+ base_address));
+}
+
+void RunJavascriptMessageBox(Profile* profile,
+ JavaScriptAppModalDialogDelegate* delegate,
+ const GURL& frame_url,
+ int dialog_flags,
+ const std::wstring& message_text,
+ const std::wstring& default_prompt_text,
+ bool display_suppress_checkbox,
+ IPC::Message* reply_msg) {
+ bool is_alert = dialog_flags == MessageBoxFlags::kIsJavascriptAlert;
+ std::wstring title = GetTitle(profile, is_alert, frame_url);
+ AppModalDialogQueue::GetInstance()->AddDialog(new JavaScriptAppModalDialog(
+ delegate, title, dialog_flags, message_text, default_prompt_text,
+ display_suppress_checkbox, false, reply_msg));
+}
+
+void RunBeforeUnloadDialog(TabContents* tab_contents,
+ const std::wstring& message_text,
+ IPC::Message* reply_msg) {
+ std::wstring full_message =
+ message_text + L"\n\n" +
+ l10n_util::GetString(IDS_BEFOREUNLOAD_MESSAGEBOX_FOOTER);
+ AppModalDialogQueue::GetInstance()->AddDialog(new JavaScriptAppModalDialog(
+ tab_contents, l10n_util::GetString(IDS_BEFOREUNLOAD_MESSAGEBOX_TITLE),
+ MessageBoxFlags::kIsJavascriptConfirm, message_text, std::wstring(),
+ false, true, reply_msg));
+}
diff --git a/chrome/browser/ui/app_modal_dialogs/message_box_handler.h b/chrome/browser/ui/app_modal_dialogs/message_box_handler.h
new file mode 100644
index 0000000..0acfb14
--- /dev/null
+++ b/chrome/browser/ui/app_modal_dialogs/message_box_handler.h
@@ -0,0 +1,41 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_APP_MODAL_DIALOGS_MESSAGE_BOX_HANDLER_H_
+#define CHROME_BROWSER_UI_APP_MODAL_DIALOGS_MESSAGE_BOX_HANDLER_H_
+#pragma once
+
+#include <string>
+
+#include "ipc/ipc_message.h"
+
+class GURL;
+class JavaScriptAppModalDialogDelegate;
+class TabContents;
+class Profile;
+
+// Creates and runs a Javascript Message Box dialog.
+// The dialog type is specified within |dialog_flags|, the
+// default static display text is in |message_text| and if the dialog box is
+// a user input prompt() box, the default text for the text field is in
+// |default_prompt_text|. The result of the operation is returned using
+// |reply_msg|.
+void RunJavascriptMessageBox(Profile* profile,
+ JavaScriptAppModalDialogDelegate* delegate,
+ const GURL& frame_url,
+ int dialog_flags,
+ const std::wstring& message_text,
+ const std::wstring& default_prompt_text,
+ bool display_suppress_checkbox,
+ IPC::Message* reply_msg);
+
+// This will display a modal dialog box with a header and footer asking the
+// the user if they wish to navigate away from a page, with additional text
+// |message_text| between the header and footer. The users response is
+// returned to the renderer using |reply_msg|.
+void RunBeforeUnloadDialog(TabContents* tab_contents,
+ const std::wstring& message_text,
+ IPC::Message* reply_msg);
+
+#endif // CHROME_BROWSER_UI_APP_MODAL_DIALOGS_MESSAGE_BOX_HANDLER_H_
diff --git a/chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h b/chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h
new file mode 100644
index 0000000..36701fb
--- /dev/null
+++ b/chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h
@@ -0,0 +1,39 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_APP_MODAL_DIALOGS_NATIVE_APP_MODAL_DIALOG_H_
+#define CHROME_BROWSER_UI_APP_MODAL_DIALOGS_NATIVE_APP_MODAL_DIALOG_H_
+#pragma once
+
+#include "gfx/native_widget_types.h"
+
+class JavaScriptAppModalDialog;
+
+class NativeAppModalDialog {
+ public:
+ // Returns the buttons to be shown. See MessageBoxFlags for a description of
+ // the values.
+ virtual int GetAppModalDialogButtons() const = 0;
+
+ // Shows the dialog.
+ virtual void ShowAppModalDialog() = 0;
+
+ // Activates the dialog.
+ virtual void ActivateAppModalDialog() = 0;
+
+ // Closes the dialog.
+ virtual void CloseAppModalDialog() = 0;
+
+ // Accepts or cancels the dialog.
+ virtual void AcceptAppModalDialog() = 0;
+ virtual void CancelAppModalDialog() = 0;
+
+ // Creates an app modal dialog for a JavaScript prompt.
+ static NativeAppModalDialog* CreateNativeJavaScriptPrompt(
+ JavaScriptAppModalDialog* dialog,
+ gfx::NativeWindow parent_window);
+};
+
+#endif // CHROME_BROWSER_UI_APP_MODAL_DIALOGS_NATIVE_APP_MODAL_DIALOG_H_
+
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index c943429..9d0353c 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -37,7 +37,6 @@
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/debugger/devtools_toggle_action.h"
#include "chrome/browser/debugger/devtools_window.h"
-#include "chrome/browser/dock_info.h"
#include "chrome/browser/dom_ui/filebrowse_ui.h"
#include "chrome/browser/dom_ui/options/content_settings_handler.h"
#include "chrome/browser/download/download_item.h"
@@ -52,30 +51,25 @@
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_prefs.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/find_bar.h"
-#include "chrome/browser/find_bar_controller.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/first_run/first_run.h"
#include "chrome/browser/google/google_url_tracker.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/host_zoom_map.h"
#include "chrome/browser/instant/instant_controller.h"
#include "chrome/browser/instant/instant_unload_handler.h"
-#include "chrome/browser/location_bar.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/net/browser_url_util.h"
#include "chrome/browser/net/url_fixer_upper.h"
-#include "chrome/browser/options_window.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/printing/cloud_print/cloud_print_setup_flow.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/sessions/session_service.h"
#include "chrome/browser/sessions/session_types.h"
#include "chrome/browser/sessions/tab_restore_service.h"
-#include "chrome/browser/status_bubble.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/sync_ui_util.h"
#include "chrome/browser/tab_closeable_state_watcher.h"
@@ -84,13 +78,19 @@
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
-#include "chrome/browser/tab_contents_wrapper.h"
-#include "chrome/browser/tab_menu_model.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser_navigator.h"
+#include "chrome/browser/ui/find_bar/find_bar.h"
+#include "chrome/browser/ui/find_bar/find_bar_controller.h"
+#include "chrome/browser/ui/omnibox/location_bar.h"
+#include "chrome/browser/ui/options/options_window.h"
+#include "chrome/browser/ui/status_bubble.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "chrome/browser/ui/tabs/dock_info.h"
+#include "chrome/browser/ui/tabs/tab_menu_model.h"
+#include "chrome/browser/ui/window_sizer.h"
#include "chrome/browser/upgrade_detector.h"
#include "chrome/browser/web_applications/web_app.h"
-#include "chrome/browser/window_sizer.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/content_restriction.h"
@@ -108,6 +108,7 @@
#include "net/base/registry_controlled_domain.h"
#include "net/base/static_cookie_policy.h"
#include "net/url_request/url_request_context.h"
+#include "webkit/glue/webkit_glue.h"
#include "webkit/glue/window_open_disposition.h"
#if defined(ENABLE_REMOTING)
@@ -118,24 +119,20 @@
#include "app/win_util.h"
#include "chrome/browser/autofill/autofill_ie_toolbar_import_win.h"
#include "chrome/browser/browser_child_process_host.h"
-#include "chrome/browser/cert_store.h"
#include "chrome/browser/download/save_package.h"
#include "chrome/browser/ssl/ssl_error_info.h"
#include "chrome/browser/shell_integration.h"
#include "chrome/browser/task_manager/task_manager.h"
-#include "chrome/browser/view_ids.h"
-#include "chrome/browser/views/location_bar/location_bar_view.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
#endif // OS_WIN
#if defined(OS_MACOSX)
-#include "chrome/browser/cocoa/find_pasteboard.h"
+#include "chrome/browser/ui/cocoa/find_pasteboard.h"
#endif
#if defined(OS_CHROMEOS)
-#include <gdk/gdk.h> // For GdkScreen
#include "chrome/browser/chromeos/boot_times_loader.h"
-#include "chrome/browser/chromeos/cros/cros_library.h"
-#include "chrome/browser/chromeos/cros/login_library.h"
#include "chrome/browser/chromeos/options/language_config_view.h"
#endif
@@ -148,7 +145,7 @@ namespace {
// The URL to be loaded to display Help.
#if defined(OS_CHROMEOS)
const char kHelpContentUrl[] =
- "chrome-extension://nifaohjgppdbmalmmgkmfdlodaggnbpe/main.html";
+ "chrome-extension://oonnajkebngbfpmcpekfdeofeannbapp/main.html";
const char kHelpContentOnlineUrl[] =
"http://www.google.com/support/chromeos/";
#else
@@ -207,8 +204,7 @@ Browser::Browser(Type type, Profile* profile)
block_command_execution_(false),
last_blocked_command_id_(-1),
last_blocked_command_disposition_(CURRENT_TAB),
- pending_web_app_action_(NONE),
- extension_app_(NULL) {
+ pending_web_app_action_(NONE) {
registrar_.Add(this, NotificationType::SSL_VISIBLE_STATE_CHANGED,
NotificationService::AllSources());
registrar_.Add(this, NotificationType::EXTENSION_UPDATE_DISABLED,
@@ -217,8 +213,6 @@ Browser::Browser(Type type, Profile* profile)
NotificationService::AllSources());
registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
NotificationService::AllSources());
- registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED,
- NotificationService::AllSources());
registrar_.Add(this, NotificationType::EXTENSION_PROCESS_TERMINATED,
NotificationService::AllSources());
registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
@@ -340,7 +334,7 @@ Browser* Browser::CreateForType(Type type, Profile* profile) {
// static
Browser* Browser::CreateForApp(const std::string& app_name,
- const Extension* extension,
+ const gfx::Size& window_size,
Profile* profile,
bool is_panel) {
Browser::Type type = TYPE_APP;
@@ -349,19 +343,14 @@ Browser* Browser::CreateForApp(const std::string& app_name,
// TYPE_APP_PANEL is the logical choice. However, the panel UI
// is not fully implemented. See crbug/55943.
type = TYPE_APP_POPUP;
- } else if (extension) {
- type = TYPE_EXTENSION_APP;
}
Browser* browser = new Browser(type, profile);
browser->app_name_ = app_name;
- browser->extension_app_ = extension;
- if (extension) {
- gfx::Rect initial_pos(extension->launch_width(),
- extension->launch_height());
- if (!initial_pos.IsEmpty())
- browser->set_override_bounds(initial_pos);
+ if (!window_size.IsEmpty()) {
+ gfx::Rect initial_pos(window_size);
+ browser->set_override_bounds(initial_pos);
}
browser->CreateBrowserWindow();
@@ -494,7 +483,7 @@ void Browser::OpenURLOffTheRecord(Profile* profile, const GURL& url) {
TabContents* Browser::OpenApplication(Profile* profile,
const std::string& app_id,
TabContents* existing_tab) {
- ExtensionsService* extensions_service = profile->GetExtensionsService();
+ ExtensionService* extensions_service = profile->GetExtensionService();
// If the extension with |app_id| could't be found, most likely because it
// was uninstalled.
@@ -519,15 +508,6 @@ TabContents* Browser::OpenApplication(
switch (container) {
case extension_misc::LAUNCH_WINDOW:
- // TODO(skerner): Setting |extension| to NULL is odd.
- // Not doing so triggers some vestigial extensions app window
- // behavior that leads to crashes. This sort of window is no
- // longer supported, and its remains need to be cleaned up.
- // crbug/65630 tracks this cleanup.
- tab = Browser::OpenApplicationWindow(profile, NULL, container,
- extension->GetFullLaunchURL(),
- NULL);
- break;
case extension_misc::LAUNCH_PANEL:
tab = Browser::OpenApplicationWindow(profile, extension, container,
GURL(), NULL);
@@ -565,7 +545,13 @@ TabContents* Browser::OpenApplicationWindow(
RegisterAppPrefs(app_name);
bool as_panel = extension && (container == extension_misc::LAUNCH_PANEL);
- Browser* browser = Browser::CreateForApp(app_name, extension, profile,
+
+ gfx::Size window_size;
+ if (extension)
+ window_size.SetSize(extension->launch_width(),
+ extension->launch_height());
+
+ Browser* browser = Browser::CreateForApp(app_name, window_size, profile,
as_panel);
if (app_browser)
*app_browser = browser;
@@ -619,7 +605,7 @@ TabContents* Browser::OpenApplicationTab(Profile* profile,
return contents;
// Check the prefs for overridden mode.
- ExtensionsService* extensions_service = profile->GetExtensionsService();
+ ExtensionService* extensions_service = profile->GetExtensionService();
DCHECK(extensions_service);
ExtensionPrefs::LaunchType launch_type =
@@ -822,6 +808,17 @@ void Browser::FormatTitleForDisplay(string16* title) {
///////////////////////////////////////////////////////////////////////////////
// Browser, OnBeforeUnload handling:
+bool Browser::TabsNeedBeforeUnloadFired() {
+ if (tabs_needing_before_unload_fired_.empty()) {
+ for (int i = 0; i < tab_count(); ++i) {
+ TabContents* contents = GetTabContentsAt(i);
+ if (contents->NeedToFireBeforeUnload())
+ tabs_needing_before_unload_fired_.insert(contents);
+ }
+ }
+ return !tabs_needing_before_unload_fired_.empty();
+}
+
bool Browser::ShouldCloseWindow() {
if (!CanCloseWithInProgressDownloads())
return false;
@@ -831,13 +828,7 @@ bool Browser::ShouldCloseWindow() {
is_attempting_to_close_browser_ = true;
- for (int i = 0; i < tab_count(); ++i) {
- TabContents* contents = GetTabContentsAt(i);
- if (contents->NeedToFireBeforeUnload())
- tabs_needing_before_unload_fired_.insert(contents);
- }
-
- if (tabs_needing_before_unload_fired_.empty())
+ if (!TabsNeedBeforeUnloadFired())
return IsClosingPermitted();
ProcessPendingTabs();
@@ -948,6 +939,10 @@ void Browser::CloseAllTabs() {
////////////////////////////////////////////////////////////////////////////////
// Browser, Tab adding/showing functions:
+bool Browser::IsTabStripEditable() const {
+ return window()->IsTabStripEditable();
+}
+
int Browser::GetIndexForInsertionDuringRestore(int relative_index) {
return (tab_handler_->GetTabStripModel()->insertion_policy() ==
TabStripModel::INSERT_AFTER) ? tab_count() : relative_index;
@@ -1189,16 +1184,16 @@ bool Browser::SupportsWindowFeatureImpl(WindowFeature feature,
}
if (!hide_ui_for_fullscreen) {
- if (type() != TYPE_NORMAL && type() != TYPE_EXTENSION_APP)
+ if (type() != TYPE_NORMAL)
features |= FEATURE_TITLEBAR;
- if (type() == TYPE_NORMAL || type() == TYPE_EXTENSION_APP)
+ if (type() == TYPE_NORMAL)
features |= FEATURE_TABSTRIP;
- if (type() == TYPE_NORMAL || type() == TYPE_EXTENSION_APP)
+ if (type() == TYPE_NORMAL)
features |= FEATURE_TOOLBAR;
- if (type() != TYPE_EXTENSION_APP && (type() & Browser::TYPE_APP) == 0)
+ if ((type() & Browser::TYPE_APP) == 0)
features |= FEATURE_LOCATIONBAR;
}
return !!(features & feature);
@@ -1474,6 +1469,10 @@ void Browser::Search() {
// Otherwise just open it.
NewTab();
}
+
+void Browser::ShowKeyboardOverlay() {
+ window_->ShowKeyboardOverlay(window_->GetNativeHandle());
+}
#endif
void Browser::Exit() {
@@ -1483,14 +1482,8 @@ void Browser::Exit() {
// Write /tmp/uptime-logout-started as well.
const char kLogoutStarted[] = "logout-started";
chromeos::BootTimesLoader::Get()->RecordCurrentStats(kLogoutStarted);
-
- if (chromeos::CrosLibrary::Get()->EnsureLoaded()) {
- chromeos::CrosLibrary::Get()->GetLoginLibrary()->StopSession("");
- return;
- }
- // If running the Chrome OS build, but we're not on the device, fall through
#endif
- BrowserList::CloseAllBrowsersAndExit();
+ BrowserList::Exit();
}
void Browser::BookmarkCurrentPage() {
@@ -1502,9 +1495,14 @@ void Browser::BookmarkCurrentPage() {
GURL url;
string16 title;
- bookmark_utils::GetURLAndTitleToBookmark(GetSelectedTabContents(), &url,
- &title);
+ TabContents* tab = GetSelectedTabContents();
+ bookmark_utils::GetURLAndTitleToBookmark(tab, &url, &title);
bool was_bookmarked = model->IsBookmarked(url);
+ if (!was_bookmarked && profile_->IsOffTheRecord()) {
+ // If we're off the record the favicon may not have been saved. Save it now
+ // so that bookmarks have an icon for the page.
+ tab->SaveFavicon();
+ }
model->SetURLStarred(url, title, true);
// Make sure the model actually added a bookmark before showing the star. A
// bookmark isn't created if the url is invalid.
@@ -1523,15 +1521,8 @@ void Browser::SavePage() {
GetSelectedTabContents()->OnSavePage();
}
-void Browser::ViewSource() {
- UserMetrics::RecordAction(UserMetricsAction("ViewSource"), profile_);
-
- TabContents* current_tab = GetSelectedTabContents();
- NavigationEntry* entry = current_tab->controller().GetLastCommittedEntry();
- if (entry) {
- OpenURL(GURL(chrome::kViewSourceScheme + std::string(":") +
- entry->url().spec()), GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
- }
+void Browser::ViewSelectedSource() {
+ ViewSource(GetSelectedTabContentsWrapper());
}
void Browser::ShowFindBar() {
@@ -1999,6 +1990,13 @@ void Browser::RegisterPrefs(PrefService* prefs) {
prefs->RegisterIntegerPref(prefs::kDevToolsSplitLocation, -1);
prefs->RegisterDictionaryPref(prefs::kPreferencesWindowPlacement);
prefs->RegisterIntegerPref(prefs::kExtensionSidebarWidth, -1);
+ // Educated guess: Chrome has a bundled Flash version supporting
+ // clearing LSO data, Chromium hasn't.
+#if defined(GOOGLE_CHROME_BUILD)
+ prefs->RegisterBooleanPref(prefs::kClearPluginLSODataEnabled, true);
+#else
+ prefs->RegisterBooleanPref(prefs::kClearPluginLSODataEnabled, false);
+#endif
}
// static
@@ -2007,6 +2005,7 @@ void Browser::RegisterUserPrefs(PrefService* prefs) {
chrome::kChromeUINewTabURL);
prefs->RegisterBooleanPref(prefs::kHomePageIsNewTabPage, true);
prefs->RegisterBooleanPref(prefs::kClearSiteDataOnExit, false);
+ prefs->RegisterBooleanPref(prefs::kClearPluginLSODataOnExit, false);
prefs->RegisterBooleanPref(prefs::kShowHomeButton, false);
#if defined(OS_MACOSX)
// This really belongs in platform code, but there's no good place to
@@ -2027,6 +2026,7 @@ void Browser::RegisterUserPrefs(PrefService* prefs) {
prefs->RegisterBooleanPref(prefs::kDeleteCookies, true);
prefs->RegisterBooleanPref(prefs::kDeletePasswords, false);
prefs->RegisterBooleanPref(prefs::kDeleteFormData, false);
+ prefs->RegisterBooleanPref(prefs::kDeleteLSOData, false);
prefs->RegisterIntegerPref(prefs::kDeleteTimePeriod, 0);
prefs->RegisterBooleanPref(prefs::kCheckDefaultBrowser, true);
prefs->RegisterBooleanPref(prefs::kShowOmniboxSearchHint, true);
@@ -2039,6 +2039,7 @@ void Browser::RegisterUserPrefs(PrefService* prefs) {
prefs->RegisterStringPref(prefs::kCloudPrintEmail, std::string());
prefs->RegisterBooleanPref(prefs::kDevToolsDisabled, false);
prefs->RegisterRealPref(prefs::kDefaultZoomLevel, 0.0);
+ prefs->RegisterIntegerPref(prefs::kMultipleProfilePrefMigration, 0);
// We need to register the type of this preference in order to query
// it even though it's only typically controlled via policy.
prefs->RegisterBooleanPref(prefs::kDisable3DAPIs, false);
@@ -2145,13 +2146,14 @@ void Browser::ExecuteCommandWithDisposition(
case IDC_TOGGLE_VERTICAL_TABS: ToggleUseVerticalTabs(); break;
#if defined(OS_CHROMEOS)
case IDC_SEARCH: Search(); break;
+ case IDC_SHOW_KEYBOARD_OVERLAY: ShowKeyboardOverlay(); break;
#endif
// Page-related commands
case IDC_SAVE_PAGE: SavePage(); break;
case IDC_BOOKMARK_PAGE: BookmarkCurrentPage(); break;
case IDC_BOOKMARK_ALL_TABS: BookmarkAllTabs(); break;
- case IDC_VIEW_SOURCE: ViewSource(); break;
+ case IDC_VIEW_SOURCE: ViewSelectedSource(); break;
case IDC_EMAIL_PAGE_LOCATION: EmailPageLocation(); break;
case IDC_PRINT: Print(); break;
case IDC_ENCODING_AUTO_DETECT: ToggleEncodingAutoDetect(); break;
@@ -2266,6 +2268,15 @@ void Browser::ExecuteCommandWithDisposition(
}
}
+bool Browser::ExecuteCommandIfEnabled(int id) {
+ if (command_updater_.SupportsCommand(id) &&
+ command_updater_.IsCommandEnabled(id)) {
+ ExecuteCommand(id);
+ return true;
+ }
+ return false;
+}
+
bool Browser::IsReservedCommand(int command_id) {
return command_id == IDC_CLOSE_TAB ||
command_id == IDC_CLOSE_WINDOW ||
@@ -2450,52 +2461,9 @@ bool Browser::CanDuplicateContentsAt(int index) {
void Browser::DuplicateContentsAt(int index) {
TabContentsWrapper* contents = GetTabContentsWrapperAt(index);
- TabContents* new_contents = NULL;
- DCHECK(contents);
- bool pinned = false;
-
- if (CanSupportWindowFeature(FEATURE_TABSTRIP)) {
- // If this is a tabbed browser, just create a duplicate tab inside the same
- // window next to the tab being duplicated.
- TabContentsWrapper* wrapper = contents->Clone();
- new_contents = wrapper->tab_contents();
- pinned = tab_handler_->GetTabStripModel()->IsTabPinned(index);
- int add_types = TabStripModel::ADD_SELECTED |
- TabStripModel::ADD_INHERIT_GROUP |
- (pinned ? TabStripModel::ADD_PINNED : 0);
- tab_handler_->GetTabStripModel()->InsertTabContentsAt(index + 1,
- wrapper,
- add_types);
- } else {
- Browser* browser = NULL;
- if (type_ & TYPE_APP) {
- DCHECK((type_ & TYPE_POPUP) == 0);
- DCHECK(type_ != TYPE_APP_PANEL);
- browser = Browser::CreateForApp(app_name_, extension_app_, profile_,
- false);
- } else if (type_ == TYPE_POPUP) {
- browser = Browser::CreateForType(TYPE_POPUP, profile_);
- }
-
- // Preserve the size of the original window. The new window has already
- // been given an offset by the OS, so we shouldn't copy the old bounds.
- BrowserWindow* new_window = browser->window();
- new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(),
- window()->GetRestoredBounds().size()));
-
- // We need to show the browser now. Otherwise ContainerWin assumes the
- // TabContents is invisible and won't size it.
- browser->window()->Show();
-
- // The page transition below is only for the purpose of inserting the tab.
- new_contents = browser->AddTab(contents->Clone(), PageTransition::LINK);
- }
-
- if (profile_->HasSessionService()) {
- SessionService* session_service = profile_->GetSessionService();
- if (session_service)
- session_service->TabRestored(&new_contents->controller(), pinned);
- }
+ CHECK(contents);
+ TabContentsWrapper* contents_dupe = contents->Clone();
+ InsertContentsDupe(contents, contents_dupe);
}
void Browser::CloseFrameAfterDragSession() {
@@ -2578,7 +2546,7 @@ bool Browser::LargeIconsPermitted() const {
// We don't show the big icons in tabs for TYPE_EXTENSION_APP windows because
// for those windows, we already have a big icon in the top-left outside any
// tab. Having big tab icons too looks kinda redonk.
- return TYPE_EXTENSION_APP != type();
+ return true;
}
///////////////////////////////////////////////////////////////////////////////
@@ -2962,7 +2930,8 @@ void Browser::ConvertContentsToApplication(TabContents* contents) {
RegisterAppPrefs(app_name);
DetachContents(contents);
- Browser* app_browser = Browser::CreateForApp(app_name, NULL, profile_, false);
+ Browser* app_browser = Browser::CreateForApp(
+ app_name, gfx::Size(), profile_, false);
TabContentsWrapper* wrapper = new TabContentsWrapper(contents);
app_browser->tabstrip_model()->AppendTabContents(wrapper, true);
@@ -3038,7 +3007,7 @@ void Browser::OnStartDownload(DownloadItem* download, TabContents* tab) {
#if defined(OS_CHROMEOS)
// Don't show content browser for extension/theme downloads from gallery.
if (download->is_extension_install()) {
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
if (service && service->IsDownloadFromGallery(download->url(),
download->referrer_url())) {
return;
@@ -3062,7 +3031,7 @@ void Browser::OnStartDownload(DownloadItem* download, TabContents* tab) {
// For non-theme extensions, we don't show the download animation.
if (download->is_extension_install() &&
- !ExtensionsService::IsDownloadFromMiniGallery(download->url()))
+ !ExtensionService::IsDownloadFromMiniGallery(download->url()))
return;
TabContents* current_tab = GetSelectedTabContents();
@@ -3099,6 +3068,13 @@ void Browser::ShowPageInfo(Profile* profile,
window()->ShowPageInfo(profile, url, ssl, show_history);
}
+void Browser::ViewSourceForTab(TabContents* source, const GURL& page_url) {
+ DCHECK(source);
+ int index = tabstrip_model()->GetWrapperIndex(source);
+ TabContentsWrapper* wrapper = tabstrip_model()->GetTabContentsAt(index);
+ ViewSource(wrapper);
+}
+
bool Browser::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
bool* is_keyboard_shortcut) {
return window()->PreHandleKeyboardEvent(event, is_keyboard_shortcut);
@@ -3164,7 +3140,7 @@ void Browser::OnDidGetApplicationInfo(TabContents* tab_contents,
void Browser::OnInstallApplication(TabContents* source,
const WebApplicationInfo& web_app) {
- ExtensionsService* extensions_service = profile()->GetExtensionsService();
+ ExtensionService* extensions_service = profile()->GetExtensionService();
if (!extensions_service)
return;
@@ -3224,7 +3200,7 @@ void Browser::Observe(NotificationType type,
// Show the UI if the extension was disabled for escalated permissions.
Profile* profile = Source<Profile>(source).ptr();
if (profile_->IsSameProfile(profile)) {
- ExtensionsService* service = profile->GetExtensionsService();
+ ExtensionService* service = profile->GetExtensionService();
DCHECK(service);
const Extension* extension = Details<const Extension>(details).ptr();
if (service->extension_prefs()->DidExtensionEscalatePermissions(
@@ -3234,12 +3210,12 @@ void Browser::Observe(NotificationType type,
break;
}
- case NotificationType::EXTENSION_UNLOADED:
- case NotificationType::EXTENSION_UNLOADED_DISABLED: {
+ case NotificationType::EXTENSION_UNLOADED: {
window()->GetLocationBar()->UpdatePageActions();
// Close any tabs from the unloaded extension.
- const Extension* extension = Details<const Extension>(details).ptr();
+ const Extension* extension =
+ Details<UnloadedExtensionInfo>(details)->extension;
TabStripModel* model = tab_handler_->GetTabStripModel();
for (int i = model->count() - 1; i >= 0; --i) {
TabContents* tc = model->GetTabContentsAt(i)->tab_contents();
@@ -3258,8 +3234,8 @@ void Browser::Observe(NotificationType type,
TabContents* tab_contents = GetSelectedTabContents();
if (!tab_contents)
break;
- ExtensionsService* extensions_service =
- Source<Profile>(source).ptr()->GetExtensionsService();
+ ExtensionService* extensions_service =
+ Source<Profile>(source).ptr()->GetExtensionService();
ExtensionHost* extension_host = Details<ExtensionHost>(details).ptr();
tab_contents->AddInfoBar(new CrashedExtensionInfoBarDelegate(
tab_contents, extensions_service, extension_host->extension()));
@@ -3272,20 +3248,21 @@ void Browser::Observe(NotificationType type,
// If any "This extension has crashed" InfoBarDelegates are around for
// this extension, it means that it has been reloaded in another window
// so just remove the remaining CrashedExtensionInfoBarDelegate objects.
- TabContents* tab_contents = GetSelectedTabContents();
- if (!tab_contents)
- break;
const Extension* extension = Details<const Extension>(details).ptr();
CrashedExtensionInfoBarDelegate* delegate = NULL;
- for (int i = 0; i < tab_contents->infobar_delegate_count();) {
- delegate = tab_contents->GetInfoBarDelegateAt(i)->
- AsCrashedExtensionInfoBarDelegate();
- if (delegate && delegate->extension_id() == extension->id()) {
- tab_contents->RemoveInfoBar(delegate);
- continue;
+ TabStripModel* model = tab_handler_->GetTabStripModel();
+ for (int m = 0; m < model->count(); ++m) {
+ TabContents* tab_contents = model->GetTabContentsAt(m)->tab_contents();
+ for (int i = 0; i < tab_contents->infobar_delegate_count();) {
+ delegate = tab_contents->GetInfoBarDelegateAt(i)->
+ AsCrashedExtensionInfoBarDelegate();
+ if (delegate && delegate->extension_id() == extension->id()) {
+ tab_contents->RemoveInfoBar(delegate);
+ continue;
+ }
+ // Only increment |i| if we didn't remove an entry.
+ ++i;
}
- // Only increment |i| if we didn't remove an entry.
- ++i;
}
break;
}
@@ -3306,7 +3283,7 @@ void Browser::Observe(NotificationType type,
// the download_url GURL instead. This means that themes in the extensions
// gallery won't get the loading dialog.
GURL download_url = *(Details<GURL>(details).ptr());
- if (ExtensionsService::IsDownloadFromMiniGallery(download_url))
+ if (ExtensionService::IsDownloadFromMiniGallery(download_url))
window()->ShowThemeInstallBubble();
break;
}
@@ -3489,11 +3466,12 @@ void Browser::InitCommandState() {
#if defined(OS_CHROMEOS)
command_updater_.UpdateCommandEnabled(IDC_SEARCH, true);
+ command_updater_.UpdateCommandEnabled(IDC_SHOW_KEYBOARD_OVERLAY, true);
command_updater_.UpdateCommandEnabled(IDC_SYSTEM_OPTIONS, true);
command_updater_.UpdateCommandEnabled(IDC_INTERNET_OPTIONS, true);
#endif
- ExtensionsService* extensions_service = profile()->GetExtensionsService();
+ ExtensionService* extensions_service = profile()->GetExtensionService();
bool enable_extensions =
extensions_service && extensions_service->extensions_enabled();
command_updater_.UpdateCommandEnabled(IDC_MANAGE_EXTENSIONS,
@@ -3930,37 +3908,46 @@ void Browser::ClearUnloadState(TabContents* tab) {
///////////////////////////////////////////////////////////////////////////////
// Browser, In-progress download termination handling (private):
-bool Browser::CanCloseWithInProgressDownloads() {
- if (cancel_download_confirmation_state_ != NOT_PROMPTED) {
- if (cancel_download_confirmation_state_ == WAITING_FOR_RESPONSE) {
- // We need to hear from the user before we can close.
- return false;
- }
- // RESPONSE_RECEIVED case, the user decided to go along with the closing.
- return true;
- }
- // Indicated that normal (non-incognito) downloads are pending.
- bool normal_downloads_are_present = false;
- bool incognito_downloads_are_present = false;
+void Browser::CheckDownloadsInProgress(bool* normal_downloads_are_present,
+ bool* incognito_downloads_are_present) {
+ *normal_downloads_are_present = false;
+ *incognito_downloads_are_present = false;
+
// If there are no download in-progress, our job is done.
DownloadManager* download_manager = NULL;
// But first we need to check for the existance of the download manager, as
// GetDownloadManager() will unnecessarily try to create one if it does not
// exist.
- if (profile_->HasCreatedDownloadManager())
- download_manager = profile_->GetDownloadManager();
- if (profile_->IsOffTheRecord()) {
+ if (profile()->HasCreatedDownloadManager())
+ download_manager = profile()->GetDownloadManager();
+ if (profile()->IsOffTheRecord()) {
// Browser is incognito and so download_manager if present is for incognito
// downloads.
- incognito_downloads_are_present =
+ *incognito_downloads_are_present =
(download_manager && download_manager->in_progress_count() != 0);
// Check original profile.
- if (profile_->GetOriginalProfile()->HasCreatedDownloadManager())
- download_manager = profile_->GetOriginalProfile()->GetDownloadManager();
+ if (profile()->GetOriginalProfile()->HasCreatedDownloadManager())
+ download_manager = profile()->GetOriginalProfile()->GetDownloadManager();
}
- normal_downloads_are_present =
+ *normal_downloads_are_present =
(download_manager && download_manager->in_progress_count() != 0);
+}
+
+bool Browser::CanCloseWithInProgressDownloads() {
+ if (cancel_download_confirmation_state_ != NOT_PROMPTED) {
+ if (cancel_download_confirmation_state_ == WAITING_FOR_RESPONSE) {
+ // We need to hear from the user before we can close.
+ return false;
+ }
+ // RESPONSE_RECEIVED case, the user decided to go along with the closing.
+ return true;
+ }
+ // Indicated that normal (non-incognito) downloads are pending.
+ bool normal_downloads_are_present = false;
+ bool incognito_downloads_are_present = false;
+ CheckDownloadsInProgress(&normal_downloads_are_present,
+ &incognito_downloads_are_present);
if (!normal_downloads_are_present && !incognito_downloads_are_present)
return true;
@@ -3984,16 +3971,20 @@ bool Browser::CanCloseWithInProgressDownloads() {
for (BrowserList::const_iterator iter = BrowserList::begin();
iter != BrowserList::end(); ++iter) {
// Don't count this browser window or any other in the process of closing.
- if (*iter == this || (*iter)->is_attempting_to_close_browser_)
+ // Only consider normal browser windows, not popups.
+ Browser* const browser = *iter;
+ if (browser == this
+ || browser->is_attempting_to_close_browser_
+ || browser->type() != Browser::TYPE_NORMAL)
continue;
// Verify that this is not the last non-incognito or incognito browser,
// depending on the pending downloads.
if (normal_downloads_are_present && !profile()->IsOffTheRecord() &&
- (*iter)->profile()->IsOffTheRecord())
+ browser->profile()->IsOffTheRecord())
continue;
if (incognito_downloads_are_present && profile()->IsOffTheRecord() &&
- !(*iter)->profile()->IsOffTheRecord())
+ !browser->profile()->IsOffTheRecord())
continue;
// We test the original profile, because an incognito browser window keeps
@@ -4137,11 +4128,9 @@ bool Browser::OpenInstant(WindowOpenDisposition disposition) {
return true;
}
if (disposition == NEW_FOREGROUND_TAB || disposition == NEW_BACKGROUND_TAB) {
+ HideInstant();
TabContentsWrapper* preview_contents = instant()->ReleasePreviewContents(
INSTANT_COMMIT_PRESSED_ENTER);
- // HideInstant is invoked after release so that InstantController is not
- // active when HideInstant asks it for its state.
- HideInstant();
preview_contents->controller().PruneAllButActive();
tab_handler_->GetTabStripModel()->AddTabContents(
preview_contents,
@@ -4166,3 +4155,79 @@ void Browser::CreateInstantIfNecessary() {
instant_unload_handler_.reset(new InstantUnloadHandler(this));
}
}
+
+void Browser::ViewSource(TabContentsWrapper* contents) {
+ UserMetrics::RecordAction(UserMetricsAction("ViewSource"), profile_);
+ DCHECK(contents);
+
+ TabContentsWrapper* view_source_contents = contents->Clone();
+ view_source_contents->controller().PruneAllButActive();
+ NavigationEntry* active_entry =
+ view_source_contents->controller().GetActiveEntry();
+ if (!active_entry)
+ return;
+
+ // Do not restore scroller position.
+ std::string content_state = webkit_glue::RemoveScrollOffsetFromHistoryState(
+ active_entry->content_state());
+ active_entry->set_content_state(content_state);
+
+ GURL url = GURL(chrome::kViewSourceScheme + std::string(":") +
+ active_entry->url().spec());
+ active_entry->set_virtual_url(url);
+ // Do not restore title, derive it from the url.
+ active_entry->set_title(string16());
+ InsertContentsDupe(contents, view_source_contents);
+}
+
+void Browser::InsertContentsDupe(
+ TabContentsWrapper* contents,
+ TabContentsWrapper* contents_dupe) {
+ CHECK(contents);
+
+ TabContents* new_contents = contents_dupe->tab_contents();
+ bool pinned = false;
+
+ if (CanSupportWindowFeature(FEATURE_TABSTRIP)) {
+ // If this is a tabbed browser, just create a duplicate tab inside the same
+ // window next to the tab being duplicated.
+ int index = tab_handler_->GetTabStripModel()->
+ GetIndexOfTabContents(contents);
+ pinned = tab_handler_->GetTabStripModel()->IsTabPinned(index);
+ int add_types = TabStripModel::ADD_SELECTED |
+ TabStripModel::ADD_INHERIT_GROUP |
+ (pinned ? TabStripModel::ADD_PINNED : 0);
+ tab_handler_->GetTabStripModel()->InsertTabContentsAt(index + 1,
+ contents_dupe,
+ add_types);
+ } else {
+ Browser* browser = NULL;
+ if (type_ & TYPE_APP) {
+ CHECK((type_ & TYPE_POPUP) == 0);
+ CHECK(type_ != TYPE_APP_PANEL);
+ browser = Browser::CreateForApp(app_name_, gfx::Size(), profile_,
+ false);
+ } else if (type_ == TYPE_POPUP) {
+ browser = Browser::CreateForType(TYPE_POPUP, profile_);
+ }
+
+ // Preserve the size of the original window. The new window has already
+ // been given an offset by the OS, so we shouldn't copy the old bounds.
+ BrowserWindow* new_window = browser->window();
+ new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(),
+ window()->GetRestoredBounds().size()));
+
+ // We need to show the browser now. Otherwise ContainerWin assumes the
+ // TabContents is invisible and won't size it.
+ browser->window()->Show();
+
+ // The page transition below is only for the purpose of inserting the tab.
+ browser->AddTab(contents_dupe, PageTransition::LINK);
+ }
+
+ if (profile_->HasSessionService()) {
+ SessionService* session_service = profile_->GetSessionService();
+ if (session_service)
+ session_service->TabRestored(&new_contents->controller(), pinned);
+ }
+}
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
index da228c4..00f558c 100644
--- a/chrome/browser/ui/browser.h
+++ b/chrome/browser/ui/browser.h
@@ -29,7 +29,7 @@
#include "chrome/browser/tabs/tab_strip_model_observer.h" // TODO(beng): remove
#include "chrome/browser/tab_contents/page_navigator.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
-#include "chrome/browser/toolbar_model.h"
+#include "chrome/browser/ui/toolbar/toolbar_model.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/page_transition_types.h"
@@ -63,32 +63,27 @@ class Browser : public TabHandlerDelegate,
public ProfileSyncServiceObserver,
public InstantDelegate {
public:
- // If you change the values in this enum you'll need to update browser_proxy.
- // TODO(sky): move into a common place that is referenced by both ui_tests
- // and chrome.
+ // SessionService::WindowType mirrors these values. If you add to this
+ // enum, look at SessionService::WindowType to see if it needs to be
+ // updated.
enum Type {
TYPE_NORMAL = 1,
TYPE_POPUP = 2,
// The old-style app created via "Create application shortcuts".
+ // Shortcuts to a URL and shortcuts to an installed application
+ // both have this type.
TYPE_APP = 4,
- // The new-style app created by installing a crx. This kinda needs to be
- // separate because we require larger icons and an application name that
- // are found in the crx. If we ever decide to create this kind of app
- // using some other system (eg some web standard), maybe we should
- // generalize this name to TYPE_MULTITAB or something.
- TYPE_EXTENSION_APP = 8,
TYPE_APP_POPUP = TYPE_APP | TYPE_POPUP,
- TYPE_DEVTOOLS = TYPE_APP | 16,
+ TYPE_DEVTOOLS = TYPE_APP | 8,
// TODO(skerner): crbug/56776: Until the panel UI is complete on all
// platforms, apps that set app.launch.container = "panel" have type
// APP_POPUP. (see Browser::CreateForApp)
// NOTE: TYPE_APP_PANEL is a superset of TYPE_APP_POPUP.
- TYPE_APP_PANEL = TYPE_APP | TYPE_POPUP | 32,
+ TYPE_APP_PANEL = TYPE_APP | TYPE_POPUP | 16,
TYPE_ANY = TYPE_NORMAL |
TYPE_POPUP |
TYPE_APP |
- TYPE_EXTENSION_APP |
TYPE_DEVTOOLS |
TYPE_APP_PANEL
};
@@ -144,10 +139,10 @@ class Browser : public TabHandlerDelegate,
// Like Create, but creates a toolbar-less "app" window for the specified
// app. |app_name| is required and is used to identify the window to the
- // shell. |extension| is optional. If supplied, we create a window with
- // a bigger icon and title text, that supports tabs.
+ // shell. If |extension| is set, it is used to determine the size of the
+ // window to open.
static Browser* CreateForApp(const std::string& app_name,
- const Extension* extension,
+ const gfx::Size& window_size,
Profile* profile,
bool is_panel);
@@ -155,9 +150,6 @@ class Browser : public TabHandlerDelegate,
// DevTools "app" window.
static Browser* CreateForDevTools(Profile* profile);
- // Returns the extension app associated with this window, if any.
- const Extension* extension_app() { return extension_app_; }
-
// Set overrides for the initial window bounds and maximized state.
void set_override_bounds(const gfx::Rect& bounds) {
override_bounds_ = bounds;
@@ -227,7 +219,7 @@ class Browser : public TabHandlerDelegate,
// Open an application specified by |app_id| in the appropriate launch
// container. |existing_tab| is reused if it is not NULL and the launch
// container is a tab. Returns NULL if the app_id is invalid or if
- // ExtensionsService isn't ready/available.
+ // ExtensionService isn't ready/available.
static TabContents* OpenApplication(Profile* profile,
const std::string& app_id,
TabContents* existing_tab);
@@ -321,6 +313,10 @@ class Browser : public TabHandlerDelegate,
// In-progress download termination handling /////////////////////////////////
+ // Are normal and/or incognito downloads in progress?
+ void CheckDownloadsInProgress(bool* normal_downloads,
+ bool* incognito_downloads);
+
// Called when the user has decided whether to proceed or not with the browser
// closure. |cancel_downloads| is true if the downloads should be canceled
// and the browser closed, false if the browser should stay open and the
@@ -352,6 +348,9 @@ class Browser : public TabHandlerDelegate,
// Tab adding/showing functions /////////////////////////////////////////////
+ // Returns true if the tab strip is editable (for extensions).
+ bool IsTabStripEditable() const;
+
// Returns the index to insert a tab at during session restore and startup.
// |relative_index| gives the index of the url into the number of tabs that
// are going to be opened. For example, if three urls are passed in on the
@@ -469,12 +468,13 @@ class Browser : public TabHandlerDelegate,
#if defined(OS_CHROMEOS)
void ToggleCompactNavigationBar();
void Search();
+ void ShowKeyboardOverlay();
#endif
// Page-related commands
void BookmarkCurrentPage();
void SavePage();
- void ViewSource();
+ void ViewSelectedSource();
void ShowFindBar();
// Returns true if the Browser supports the specified feature. The value of
@@ -601,6 +601,10 @@ class Browser : public TabHandlerDelegate,
// Calls ExecuteCommandWithDisposition with the given disposition.
void ExecuteCommandWithDisposition(int id, WindowOpenDisposition);
+ // Executes a command if it's enabled.
+ // Returns true if the command is executed.
+ bool ExecuteCommandIfEnabled(int id);
+
// Returns whether the |id| is a reserved command, whose keyboard shortcuts
// should not be sent to the renderer.
bool IsReservedCommand(int id);
@@ -707,6 +711,9 @@ class Browser : public TabHandlerDelegate,
virtual void TabPinnedStateChanged(TabContentsWrapper* contents, int index);
virtual void TabStripEmpty();
+ // Figure out if there are tabs that have beforeunload handlers.
+ bool TabsNeedBeforeUnloadFired();
+
private:
FRIEND_TEST_ALL_PREFIXES(BrowserTest, NoTabsInPopups);
FRIEND_TEST_ALL_PREFIXES(BrowserTest, ConvertTabToAppShortcut);
@@ -777,6 +784,7 @@ class Browser : public TabHandlerDelegate,
const GURL& url,
const NavigationEntry::SSLStatus& ssl,
bool show_history);
+ virtual void ViewSourceForTab(TabContents* source, const GURL& page_url);
virtual bool PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
bool* is_keyboard_shortcut);
virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event);
@@ -985,6 +993,15 @@ class Browser : public TabHandlerDelegate,
// If this browser should have instant one is created, otherwise does nothing.
void CreateInstantIfNecessary();
+ // Opens view-source tab for given tab contents.
+ void ViewSource(TabContentsWrapper* tab);
+
+ // Inserts contents dupe next to the original contents. This method is used
+ // to insert duplicate tab and view source tab next to the original tab.
+ void InsertContentsDupe(
+ TabContentsWrapper* original_content,
+ TabContentsWrapper* clone_content);
+
// Data members /////////////////////////////////////////////////////////////
NotificationRegistrar registrar_;
@@ -1109,9 +1126,6 @@ class Browser : public TabHandlerDelegate,
// from a TabContents. Currently, only one pending action is allowed.
WebAppAction pending_web_app_action_;
- // The extension app associated with this window, if any.
- const Extension* extension_app_;
-
// Tracks the display mode of the tabstrip.
mutable BooleanPrefMember use_vertical_tabs_;
diff --git a/chrome/browser/ui/browser_init.cc b/chrome/browser/ui/browser_init.cc
index 28c0e88..8835996 100644
--- a/chrome/browser/ui/browser_init.cc
+++ b/chrome/browser/ui/browser_init.cc
@@ -29,7 +29,7 @@
#include "chrome/browser/child_process_security_policy.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/extensions/extension_creator.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/pack_extension_job.h"
#include "chrome/browser/first_run/first_run.h"
#include "chrome/browser/net/predictor_api.h"
@@ -38,7 +38,7 @@
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prefs/session_startup_pref.h"
#include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
@@ -49,10 +49,10 @@
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/tabs/pinned_tab_codec.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser_navigator.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
@@ -69,7 +69,7 @@
#include "webkit/glue/webkit_glue.h"
#if defined(OS_MACOSX)
-#include "chrome/browser/cocoa/keystone_infobar.h"
+#include "chrome/browser/ui/cocoa/keystone_infobar.h"
#endif
#if defined(OS_WIN)
@@ -81,10 +81,12 @@
#endif
#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/brightness_observer.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/mount_library.h"
#include "chrome/browser/chromeos/cros/network_library.h"
#include "chrome/browser/chromeos/customization_document.h"
+#include "chrome/browser/chromeos/enterprise_extension_observer.h"
#include "chrome/browser/chromeos/gview_request_interceptor.h"
#include "chrome/browser/chromeos/low_battery_observer.h"
#include "chrome/browser/chromeos/network_message_observer.h"
@@ -395,7 +397,8 @@ bool BrowserInit::LaunchBrowser(const CommandLine& command_line,
// because the page load can happen in parallel to this UI thread
// and IO thread may access the NetworkStateNotifier.
chromeos::CrosLibrary::Get()->GetNetworkLibrary()
- ->AddNetworkManagerObserver(chromeos::NetworkStateNotifier::Get());
+ ->AddNetworkManagerObserver(
+ chromeos::NetworkStateNotifier::GetInstance());
}
#endif
@@ -417,33 +420,34 @@ bool BrowserInit::LaunchBrowser(const CommandLine& command_line,
#if defined(OS_CHROMEOS)
// Create the WmMessageListener so that it can listen for messages regardless
// of what window has focus.
- chromeos::WmMessageListener::instance();
+ chromeos::WmMessageListener::GetInstance();
// Create the SystemKeyEventListener so it can listen for system keyboard
// messages regardless of focus.
- chromeos::SystemKeyEventListener::instance();
+ chromeos::SystemKeyEventListener::GetInstance();
// Create the WmOverviewController so it can register with the listener.
- chromeos::WmOverviewController::instance();
+ chromeos::WmOverviewController::GetInstance();
// Install the GView request interceptor that will redirect requests
// of compatible documents (PDF, etc) to the GView document viewer.
const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
if (parsed_command_line.HasSwitch(switches::kEnableGView)) {
- chromeos::GViewRequestInterceptor::GetGViewRequestInterceptor();
+ chromeos::GViewRequestInterceptor::GetInstance();
}
if (process_startup) {
// TODO(dhg): Try to make this just USBMountObserver::Get()->set_profile
// and have the constructor take care of everything else.
chromeos::MountLibrary* lib =
chromeos::CrosLibrary::Get()->GetMountLibrary();
- chromeos::USBMountObserver* observe = chromeos::USBMountObserver::Get();
+ chromeos::USBMountObserver* observe =
+ chromeos::USBMountObserver::GetInstance();
lib->AddObserver(observe);
observe->ScanForDevices(lib);
// Connect the chromeos notifications
// This observer is a singleton. It is never deleted but the pointer is kept
- // in a global so that it isn't reported as a leak.
+ // in a static so that it isn't reported as a leak.
static chromeos::LowBatteryObserver* low_battery_observer =
new chromeos::LowBatteryObserver(profile);
chromeos::CrosLibrary::Get()->GetPowerLibrary()->AddObserver(
@@ -460,6 +464,13 @@ bool BrowserInit::LaunchBrowser(const CommandLine& command_line,
->AddNetworkManagerObserver(network_message_observer);
chromeos::CrosLibrary::Get()->GetNetworkLibrary()
->AddCellularDataPlanObserver(network_message_observer);
+
+ static chromeos::BrightnessObserver* brightness_observer =
+ new chromeos::BrightnessObserver();
+ chromeos::CrosLibrary::Get()->GetBrightnessLibrary()
+ ->AddObserver(brightness_observer);
+
+ profile->SetupChromeOSEnterpriseExtensionObserver();
}
#endif
return true;
@@ -621,7 +632,7 @@ bool BrowserInit::LaunchWithProfile::OpenApplicationWindow(Profile* profile) {
// TODO(skerner): Do something reasonable here. Pop up a warning panel?
// Open an URL to the gallery page of the extension id?
if (!app_id.empty()) {
- ExtensionsService* extensions_service = profile->GetExtensionsService();
+ ExtensionService* extensions_service = profile->GetExtensionService();
const Extension* extension =
extensions_service->GetExtensionById(app_id, false);
@@ -785,7 +796,7 @@ Browser* BrowserInit::LaunchWithProfile::OpenTabsInBrowser(
// This avoids us getting into an infinite loop asking ourselves to open
// a URL, should the handler be (incorrectly) configured to be us. Anyone
// asking us to open such a URL should really ask the handler directly.
- if (!process_startup && !URLRequest::IsHandledURL(tabs[i].url))
+ if (!process_startup && !net::URLRequest::IsHandledURL(tabs[i].url))
continue;
int add_types = first_tab ? TabStripModel::ADD_SELECTED :
diff --git a/chrome/browser/ui/browser_init_browsertest.cc b/chrome/browser/ui/browser_init_browsertest.cc
index 7cf64f9..4f1e044 100644
--- a/chrome/browser/ui/browser_init_browsertest.cc
+++ b/chrome/browser/ui/browser_init_browsertest.cc
@@ -7,7 +7,6 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_init.h"
#include "chrome/test/in_process_browser_test.h"
diff --git a/chrome/browser/ui/browser_list.cc b/chrome/browser/ui/browser_list.cc
index f5965fb..dfdd576 100644
--- a/chrome/browser/ui/browser_list.cc
+++ b/chrome/browser/ui/browser_list.cc
@@ -11,7 +11,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_shutdown.h"
#include "chrome/browser/browser_window.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/common/notification_registrar.h"
@@ -24,6 +24,8 @@
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/boot_times_loader.h"
+#include "chrome/browser/chromeos/cros/cros_library.h"
+#include "chrome/browser/chromeos/cros/login_library.h"
#endif
namespace {
@@ -180,6 +182,22 @@ void BrowserList::AddBrowser(Browser* browser) {
<< "observer list modified during notification";
}
+
+// static
+void BrowserList::NotifyAndTerminate() {
+ NotificationService::current()->Notify(NotificationType::APP_TERMINATING,
+ NotificationService::AllSources(),
+ NotificationService::NoDetails());
+#if defined(OS_CHROMEOS)
+ if (chromeos::CrosLibrary::Get()->EnsureLoaded()) {
+ chromeos::CrosLibrary::Get()->GetLoginLibrary()->StopSession("");
+ return;
+ }
+ // If running the Chrome OS build, but we're not on the device, fall through
+#endif
+ AllBrowsersClosedAndAppExiting();
+}
+
// static
void BrowserList::RemoveBrowser(Browser* browser) {
RemoveBrowserFrom(browser, &last_active_browsers_);
@@ -238,6 +256,33 @@ void BrowserList::RemoveObserver(BrowserList::Observer* observer) {
observers_.RemoveObserver(observer);
}
+#if defined(OS_CHROMEOS)
+// static
+bool BrowserList::NeedBeforeUnloadFired() {
+ bool need_before_unload_fired = false;
+ for (BrowserList::const_iterator i = BrowserList::begin();
+ i != BrowserList::end(); ++i) {
+ need_before_unload_fired = need_before_unload_fired ||
+ (*i)->TabsNeedBeforeUnloadFired();
+ }
+ return need_before_unload_fired;
+}
+
+// static
+bool BrowserList::PendingDownloads() {
+ for (BrowserList::const_iterator i = BrowserList::begin();
+ i != BrowserList::end(); ++i) {
+ bool normal_downloads_are_present = false;
+ bool incognito_downloads_are_present = false;
+ (*i)->CheckDownloadsInProgress(&normal_downloads_are_present,
+ &incognito_downloads_are_present);
+ if (normal_downloads_are_present || incognito_downloads_are_present)
+ return true;
+ }
+ return false;
+}
+#endif
+
// static
void BrowserList::CloseAllBrowsers() {
bool session_ending =
@@ -258,10 +303,7 @@ void BrowserList::CloseAllBrowsers() {
// If there are no browsers, send the APP_TERMINATING action here. Otherwise,
// it will be sent by RemoveBrowser() when the last browser has closed.
if (force_exit || browsers_.empty()) {
- NotificationService::current()->Notify(NotificationType::APP_TERMINATING,
- NotificationService::AllSources(),
- NotificationService::NoDetails());
- AllBrowsersClosedAndAppExiting();
+ NotifyAndTerminate();
return;
}
#if defined(OS_CHROMEOS)
@@ -270,14 +312,13 @@ void BrowserList::CloseAllBrowsers() {
#endif
for (BrowserList::const_iterator i = BrowserList::begin();
i != BrowserList::end();) {
+ Browser* browser = *i;
+ browser->window()->Close();
if (use_post) {
- (*i)->window()->Close();
++i;
} else {
// This path is hit during logoff/power-down. In this case we won't get
// a final message and so we force the browser to be deleted.
- Browser* browser = *i;
- browser->window()->Close();
// Close doesn't immediately destroy the browser
// (Browser::TabStripEmpty() uses invoke later) but when we're ending the
// session we need to make sure the browser is destroyed now. So, invoke
@@ -296,6 +337,20 @@ void BrowserList::CloseAllBrowsers() {
}
// static
+void BrowserList::Exit() {
+#if defined(OS_CHROMEOS)
+ // Fast shutdown for ChromeOS when there's no unload processing to be done.
+ if (chromeos::CrosLibrary::Get()->EnsureLoaded()
+ && !NeedBeforeUnloadFired()
+ && !PendingDownloads()) {
+ NotifyAndTerminate();
+ return;
+ }
+#endif
+ CloseAllBrowsersAndExit();
+}
+
+// static
void BrowserList::CloseAllBrowsersAndExit() {
NotificationService::current()->Notify(
NotificationType::APP_EXITING,
diff --git a/chrome/browser/ui/browser_list.h b/chrome/browser/ui/browser_list.h
index b8420d7..4ad4e7b 100644
--- a/chrome/browser/ui/browser_list.h
+++ b/chrome/browser/ui/browser_list.h
@@ -96,6 +96,9 @@ class BrowserList {
// 2. An update exe is present in the install folder.
static bool CanRestartForUpdate();
+ // Called from Browser::Exit.
+ static void Exit();
+
// Closes all browsers and exits. This is equivalent to
// CloseAllBrowsers(true) on platforms where the application exits when no
// more windows are remaining. On other platforms (the Mac), this will
@@ -162,6 +165,11 @@ class BrowserList {
private:
// Helper method to remove a browser instance from a list of browsers
static void RemoveBrowserFrom(Browser* browser, BrowserVector* browser_list);
+ static void NotifyAndTerminate();
+#if defined(OS_CHROMEOS)
+ static bool NeedBeforeUnloadFired();
+ static bool PendingDownloads();
+#endif
static BrowserVector browsers_;
static BrowserVector last_active_browsers_;
diff --git a/chrome/browser/ui/browser_navigator.cc b/chrome/browser/ui/browser_navigator.cc
index f548099..9f50a36 100644
--- a/chrome/browser/ui/browser_navigator.cc
+++ b/chrome/browser/ui/browser_navigator.cc
@@ -8,14 +8,14 @@
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_url_handler.h"
#include "chrome/browser/browser_window.h"
-#include "chrome/browser/location_bar.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/site_instance.h"
-#include "chrome/browser/status_bubble.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/status_bubble.h"
+#include "chrome/browser/ui/omnibox/location_bar.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/url_constants.h"
diff --git a/chrome/browser/ui/browser_navigator_browsertest.cc b/chrome/browser/ui/browser_navigator_browsertest.cc
index 299974d..37bb0de 100644
--- a/chrome/browser/ui/browser_navigator_browsertest.cc
+++ b/chrome/browser/ui/browser_navigator_browsertest.cc
@@ -3,15 +3,15 @@
// found in the LICENSE file.
#include "base/command_line.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h
index 843b407..154431e 100644
--- a/chrome/browser/ui/browser_window.h
+++ b/chrome/browser/ui/browser_window.h
@@ -168,6 +168,9 @@ class BrowserWindow {
// Returns whether the bookmark bar is animating or not.
virtual bool IsBookmarkBarAnimating() const = 0;
+ // Returns whether the tab strip is editable (for extensions).
+ virtual bool IsTabStripEditable() const = 0;
+
// Returns whether the tool bar is visible or not.
virtual bool IsToolbarVisible() const = 0;
@@ -331,6 +334,11 @@ class BrowserWindow {
// placed at.
virtual gfx::Rect GetInstantBounds() = 0;
+#if defined(OS_CHROMEOS)
+ // Shows the keyboard overlay dialog box.
+ virtual void ShowKeyboardOverlay(gfx::NativeWindow owning_window) = 0;
+#endif
+
// Construct a BrowserWindow implementation for the specified |browser|.
static BrowserWindow* CreateBrowserWindow(Browser* browser);
diff --git a/chrome/browser/cocoa/DEPS b/chrome/browser/ui/cocoa/DEPS
index c00f313..c00f313 100644
--- a/chrome/browser/cocoa/DEPS
+++ b/chrome/browser/ui/cocoa/DEPS
diff --git a/chrome/browser/ui/cocoa/about_ipc_bridge.h b/chrome/browser/ui/cocoa/about_ipc_bridge.h
new file mode 100644
index 0000000..77041b3
--- /dev/null
+++ b/chrome/browser/ui/cocoa/about_ipc_bridge.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_ABOUT_IPC_BRIDGE_H_
+#define CHROME_BROWSER_UI_COCOA_ABOUT_IPC_BRIDGE_H_
+#pragma once
+
+#include "ipc/ipc_logging.h"
+#include "ipc/ipc_message_utils.h"
+
+#if defined(IPC_MESSAGE_LOG_ENABLED)
+
+@class AboutIPCController;
+
+// On Windows, the AboutIPCDialog is a views::View. On Mac we have a
+// Cocoa dialog. This class bridges from C++ to ObjC.
+class AboutIPCBridge : public IPC::Logging::Consumer {
+ public:
+ AboutIPCBridge(AboutIPCController* controller) : controller_(controller) { }
+ virtual ~AboutIPCBridge() { }
+
+ // IPC::Logging::Consumer implementation.
+ virtual void Log(const IPC::LogData& data);
+
+ private:
+ AboutIPCController* controller_; // weak; owns me
+ DISALLOW_COPY_AND_ASSIGN(AboutIPCBridge);
+};
+
+#endif // IPC_MESSAGE_LOG_ENABLED
+
+#endif // CHROME_BROWSER_UI_COCOA_ABOUT_IPC_BRIDGE_H_
diff --git a/chrome/browser/ui/cocoa/about_ipc_bridge.mm b/chrome/browser/ui/cocoa/about_ipc_bridge.mm
new file mode 100644
index 0000000..7a7f41f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/about_ipc_bridge.mm
@@ -0,0 +1,21 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/about_ipc_bridge.h"
+#include "chrome/browser/ui/cocoa/about_ipc_controller.h"
+
+#if defined(IPC_MESSAGE_LOG_ENABLED)
+
+void AboutIPCBridge::Log(const IPC::LogData& data) {
+ CocoaLogData* cocoa_data = [[CocoaLogData alloc] initWithLogData:data];
+ if ([NSThread isMainThread]) {
+ [controller_ log:cocoa_data];
+ } else {
+ [controller_ performSelectorOnMainThread:@selector(log:)
+ withObject:cocoa_data
+ waitUntilDone:NO];
+ }
+}
+
+#endif
diff --git a/chrome/browser/ui/cocoa/about_ipc_controller.h b/chrome/browser/ui/cocoa/about_ipc_controller.h
new file mode 100644
index 0000000..f0818f9
--- /dev/null
+++ b/chrome/browser/ui/cocoa/about_ipc_controller.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_ABOUT_IPC_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_ABOUT_IPC_CONTROLLER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_ptr.h"
+#include "ipc/ipc_logging.h"
+#include "ipc/ipc_message_utils.h"
+#include "third_party/GTM/Foundation/GTMRegex.h"
+
+// Must be included after IPC_MESSAGE_LOG_ENABLED gets defined
+#import "chrome/browser/ui/cocoa/about_ipc_bridge.h"
+
+#if defined(IPC_MESSAGE_LOG_ENABLED)
+
+// An objc wrapper for IPC::LogData to allow use of Cocoa bindings.
+@interface CocoaLogData : NSObject {
+ @private
+ IPC::LogData data_;
+}
+- (id)initWithLogData:(const IPC::LogData&)data;
+@end
+
+
+// A window controller that handles the about:ipc non-modal dialog.
+@interface AboutIPCController : NSWindowController {
+ @private
+ scoped_ptr<AboutIPCBridge> bridge_;
+ IBOutlet NSButton* startStopButton_;
+ IBOutlet NSTableView* tableView_;
+ IBOutlet NSArrayController* dataController_;
+ IBOutlet NSTextField* eventCount_;
+ IBOutlet NSTextField* filteredEventCount_;
+ IBOutlet NSTextField* userStringTextField1_;
+ IBOutlet NSTextField* userStringTextField2_;
+ IBOutlet NSTextField* userStringTextField3_;
+ // Count of filtered events.
+ int filteredEventCounter_;
+ // Cocoa-bound to check boxes for filtering messages.
+ // Each BOOL allows events that have that name prefix.
+ // E.g. if set, appCache_ allows events named AppCache*.
+ // The actual string to match is defined in the xib.
+ // The userStrings allow a user-specified prefix.
+ BOOL appCache_;
+ BOOL view_;
+ BOOL utilityHost_;
+ BOOL viewHost_;
+ BOOL plugin_;
+ BOOL npObject_;
+ BOOL devTools_;
+ BOOL pluginProcessing_;
+ BOOL userString1_;
+ BOOL userString2_;
+ BOOL userString3_;
+}
+
++ (AboutIPCController*)sharedController;
+
+- (IBAction)startStop:(id)sender;
+- (IBAction)clear:(id)sender;
+
+// Called from our C++ bridge class. To accomodate multithreaded
+// ownership issues, this method ACCEPTS OWNERSHIP of the arg passed
+// in.
+- (void)log:(CocoaLogData*)data;
+
+// Update visible state (e.g. Start/Stop button) based on logging run
+// state. Does not change state.
+- (void)updateVisibleRunState;
+
+@end
+
+@interface AboutIPCController(TestingAPI)
+- (BOOL)filterOut:(CocoaLogData*)data;
+- (void)setDisplayViewMessages:(BOOL)display;
+@end
+
+#endif // IPC_MESSAGE_LOG_ENABLED
+#endif // CHROME_BROWSER_UI_COCOA_ABOUT_IPC_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/about_ipc_controller.mm b/chrome/browser/ui/cocoa/about_ipc_controller.mm
new file mode 100644
index 0000000..f7f7c31
--- /dev/null
+++ b/chrome/browser/ui/cocoa/about_ipc_controller.mm
@@ -0,0 +1,199 @@
+// Copyright (c) 2009 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/logging.h"
+#include "base/mac_util.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+#include "base/time.h"
+#include "chrome/browser/browser_process.h"
+#import "chrome/browser/ui/cocoa/about_ipc_controller.h"
+
+#if defined(IPC_MESSAGE_LOG_ENABLED)
+
+@implementation CocoaLogData
+
+- (id)initWithLogData:(const IPC::LogData&)data {
+ if ((self = [super init])) {
+ data_ = data;
+ // data_.message_name may not have been filled in if it originated
+ // somewhere other than the browser process.
+ IPC::Logging::GetMessageText(data_.type, &data_.message_name, NULL, NULL);
+ }
+ return self;
+}
+
+- (NSString*)time {
+ base::Time t = base::Time::FromInternalValue(data_.sent);
+ base::Time::Exploded exploded;
+ t.LocalExplode(&exploded);
+ return [NSString stringWithFormat:@"%02d:%02d:%02d.%03d",
+ exploded.hour, exploded.minute,
+ exploded.second, exploded.millisecond];
+}
+
+- (NSString*)channel {
+ return base::SysUTF8ToNSString(data_.channel);
+}
+
+- (NSString*)message {
+ if (data_.message_name == "") {
+ int high = data_.type >> 12;
+ int low = data_.type - (high<<12);
+ return [NSString stringWithFormat:@"type=(%d,%d) 0x%x,0x%x",
+ high, low, high, low];
+ }
+ else {
+ return base::SysUTF8ToNSString(data_.message_name);
+ }
+}
+
+- (NSString*)flags {
+ return base::SysUTF8ToNSString(data_.flags);
+}
+
+- (NSString*)dispatch {
+ base::Time sent = base::Time::FromInternalValue(data_.sent);
+ int64 delta = (base::Time::FromInternalValue(data_.receive) -
+ sent).InMilliseconds();
+ return [NSString stringWithFormat:@"%d", delta ? (int)delta : 0];
+}
+
+- (NSString*)process {
+ base::TimeDelta delta = (base::Time::FromInternalValue(data_.dispatch) -
+ base::Time::FromInternalValue(data_.receive));
+ int64 t = delta.InMilliseconds();
+ return [NSString stringWithFormat:@"%d", t ? (int)t : 0];
+}
+
+- (NSString*)parameters {
+ return base::SysUTF8ToNSString(data_.params);
+}
+
+@end
+
+namespace {
+AboutIPCController* gSharedController = nil;
+}
+
+@implementation AboutIPCController
+
++ (AboutIPCController*)sharedController {
+ if (gSharedController == nil)
+ gSharedController = [[AboutIPCController alloc] init];
+ return gSharedController;
+}
+
+- (id)init {
+ NSString* nibpath = [mac_util::MainAppBundle() pathForResource:@"AboutIPC"
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
+ // Default to all on
+ appCache_ = view_ = utilityHost_ = viewHost_ = plugin_ =
+ npObject_ = devTools_ = pluginProcessing_ = userString1_ =
+ userString2_ = userString3_ = YES;
+ }
+ return self;
+}
+
+- (void)dealloc {
+ if (gSharedController == self)
+ gSharedController = nil;
+ if (g_browser_process)
+ g_browser_process->SetIPCLoggingEnabled(false); // just in case...
+ IPC::Logging::GetInstance()->SetConsumer(NULL);
+ [super dealloc];
+}
+
+- (void)awakeFromNib {
+ // Running Chrome with the --ipc-logging switch might cause it to
+ // be enabled before the about:ipc window comes up; accomodate.
+ [self updateVisibleRunState];
+
+ // We are now able to display information, so let'er rip.
+ bridge_.reset(new AboutIPCBridge(self));
+ IPC::Logging::GetInstance()->SetConsumer(bridge_.get());
+}
+
+// Delegate callback. Closing the window means there is no more need
+// for the me, the controller.
+- (void)windowWillClose:(NSNotification*)notification {
+ [self autorelease];
+}
+
+- (void)updateVisibleRunState {
+ if (IPC::Logging::GetInstance()->Enabled())
+ [startStopButton_ setTitle:@"Stop"];
+ else
+ [startStopButton_ setTitle:@"Start"];
+}
+
+- (IBAction)startStop:(id)sender {
+ g_browser_process->SetIPCLoggingEnabled(
+ !IPC::Logging::GetInstance()->Enabled());
+ [self updateVisibleRunState];
+}
+
+- (IBAction)clear:(id)sender {
+ [dataController_ setContent:[NSMutableArray array]];
+ [eventCount_ setStringValue:@"0"];
+ [filteredEventCount_ setStringValue:@"0"];
+ filteredEventCounter_ = 0;
+}
+
+// Return YES if we should filter this out; else NO.
+// Just to be clear, [@"any string" hasPrefix:@""] returns NO.
+- (BOOL)filterOut:(CocoaLogData*)data {
+ NSString* name = [data message];
+ if ((appCache_) && [name hasPrefix:@"AppCache"])
+ return NO;
+ if ((view_) && [name hasPrefix:@"ViewMsg"])
+ return NO;
+ if ((utilityHost_) && [name hasPrefix:@"UtilityHost"])
+ return NO;
+ if ((viewHost_) && [name hasPrefix:@"ViewHost"])
+ return NO;
+ if ((plugin_) && [name hasPrefix:@"PluginMsg"])
+ return NO;
+ if ((npObject_) && [name hasPrefix:@"NPObject"])
+ return NO;
+ if ((devTools_) && [name hasPrefix:@"DevTools"])
+ return NO;
+ if ((pluginProcessing_) && [name hasPrefix:@"PluginProcessing"])
+ return NO;
+ if ((userString1_) && ([name hasPrefix:[userStringTextField1_ stringValue]]))
+ return NO;
+ if ((userString2_) && ([name hasPrefix:[userStringTextField2_ stringValue]]))
+ return NO;
+ if ((userString3_) && ([name hasPrefix:[userStringTextField3_ stringValue]]))
+ return NO;
+
+ // Special case the unknown type.
+ if ([name hasPrefix:@"type="])
+ return NO;
+
+ return YES; // filter out.
+}
+
+- (void)log:(CocoaLogData*)data {
+ if ([self filterOut:data]) {
+ [filteredEventCount_ setStringValue:[NSString stringWithFormat:@"%d",
+ ++filteredEventCounter_]];
+ return;
+ }
+ [dataController_ addObject:data];
+ NSUInteger count = [[dataController_ arrangedObjects] count];
+ // Uncomment if you want scroll-to-end behavior... but seems expensive.
+ // [tableView_ scrollRowToVisible:count-1];
+ [eventCount_ setStringValue:[NSString stringWithFormat:@"%d", count]];
+}
+
+- (void)setDisplayViewMessages:(BOOL)display {
+ view_ = display;
+}
+
+@end
+
+#endif // IPC_MESSAGE_LOG_ENABLED
+
diff --git a/chrome/browser/ui/cocoa/about_ipc_controller_unittest.mm b/chrome/browser/ui/cocoa/about_ipc_controller_unittest.mm
new file mode 100644
index 0000000..afde86e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/about_ipc_controller_unittest.mm
@@ -0,0 +1,50 @@
+// Copyright (c) 2009 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>
+
+#import "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/about_ipc_controller.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+#if defined(IPC_MESSAGE_LOG_ENABLED)
+
+namespace {
+
+class AboutIPCControllerTest : public CocoaTest {
+};
+
+TEST_F(AboutIPCControllerTest, TestFilter) {
+ AboutIPCController* controller = [[AboutIPCController alloc] init];
+ EXPECT_TRUE([controller window]); // force nib load.
+ IPC::LogData data;
+
+ // Make sure generic names do NOT get filtered.
+ std::string names[] = { "PluginProcessingIsMyLife",
+ "ViewMsgFoo",
+ "NPObjectHell" };
+ for (size_t i = 0; i < arraysize(names); i++) {
+ data.message_name = names[i];
+ scoped_nsobject<CocoaLogData> cdata([[CocoaLogData alloc]
+ initWithLogData:data]);
+ EXPECT_FALSE([controller filterOut:cdata.get()]);
+ }
+
+ // Flip a checkbox, see it filtered, flip back, all is fine.
+ data.message_name = "ViewMsgFoo";
+ scoped_nsobject<CocoaLogData> cdata([[CocoaLogData alloc]
+ initWithLogData:data]);
+ [controller setDisplayViewMessages:NO];
+ EXPECT_TRUE([controller filterOut:cdata.get()]);
+ [controller setDisplayViewMessages:YES];
+ EXPECT_FALSE([controller filterOut:cdata.get()]);
+ [controller close];
+}
+
+} // namespace
+
+#endif // IPC_MESSAGE_LOG_ENABLED
diff --git a/chrome/browser/ui/cocoa/about_ipc_dialog.h b/chrome/browser/ui/cocoa/about_ipc_dialog.h
new file mode 100644
index 0000000..3eb2bcd
--- /dev/null
+++ b/chrome/browser/ui/cocoa/about_ipc_dialog.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_ABOUT_IPC_DIALOG_H_
+#define CHROME_BROWSER_UI_COCOA_ABOUT_IPC_DIALOG_H_
+#pragma once
+
+#include "ipc/ipc_message.h"
+
+#if defined(IPC_MESSAGE_LOG_ENABLED)
+
+namespace AboutIPCDialog {
+// The dialog is a singleton. If the dialog is already opened, it won't do
+// anything, so you can just blindly call this function all you want.
+// RunDialog() is Called from chrome/browser/browser_about_handler.cc
+// in response to an about:ipc URL.
+void RunDialog();
+};
+
+
+#endif /* IPC_MESSAGE_LOG_ENABLED */
+
+#endif /* CHROME_BROWSER_UI_COCOA_ABOUT_IPC_DIALOG_H_ */
diff --git a/chrome/browser/ui/cocoa/about_ipc_dialog.mm b/chrome/browser/ui/cocoa/about_ipc_dialog.mm
new file mode 100644
index 0000000..7715f24
--- /dev/null
+++ b/chrome/browser/ui/cocoa/about_ipc_dialog.mm
@@ -0,0 +1,21 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/about_ipc_dialog.h"
+#include "chrome/browser/ui/cocoa/about_ipc_controller.h"
+
+#if defined(IPC_MESSAGE_LOG_ENABLED)
+
+namespace AboutIPCDialog {
+
+void RunDialog() {
+ // The controller gets deallocated when then window is closed,
+ // so it is safe to "fire and forget".
+ AboutIPCController* controller = [AboutIPCController sharedController];
+ [[controller window] makeKeyAndOrderFront:controller];
+}
+
+}; // namespace AboutIPCDialog
+
+#endif // IPC_MESSAGE_LOG_ENABLED
diff --git a/chrome/browser/ui/cocoa/about_window_controller.h b/chrome/browser/ui/cocoa/about_window_controller.h
new file mode 100644
index 0000000..f5b9851
--- /dev/null
+++ b/chrome/browser/ui/cocoa/about_window_controller.h
@@ -0,0 +1,69 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_ABOUT_WINDOW_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_ABOUT_WINDOW_CONTROLLER_H_
+#pragma once
+
+#import <AppKit/AppKit.h>
+
+@class BackgroundTileView;
+class Profile;
+
+// This simple subclass of |NSTextView| just doesn't show the (text) cursor
+// (|NSTextView| displays the cursor with full keyboard accessibility enabled).
+@interface AboutLegalTextView : NSTextView
+@end
+
+// A window controller that handles the About box.
+@interface AboutWindowController : NSWindowController {
+ @private
+ IBOutlet NSTextField* version_;
+ IBOutlet BackgroundTileView* backgroundView_;
+ IBOutlet NSImageView* logoView_;
+ IBOutlet NSView* legalBlock_;
+ IBOutlet AboutLegalTextView* legalText_;
+
+ // updateBlock_ holds the update image or throbber, update text, and update
+ // button.
+ IBOutlet NSView* updateBlock_;
+
+ IBOutlet NSProgressIndicator* spinner_;
+ IBOutlet NSImageView* updateStatusIndicator_;
+ IBOutlet NSTextField* updateText_;
+ IBOutlet NSButton* updateNowButton_;
+ IBOutlet NSButton* promoteButton_;
+
+ Profile* profile_; // Weak, probably the default profile.
+
+ // The window frame height. During an animation, this will contain the
+ // height being animated to.
+ CGFloat windowHeight_;
+}
+
+// Initialize the controller with the given profile, but does not show it.
+// Callers still need to call showWindow: to put it on screen.
+- (id)initWithProfile:(Profile*)profile;
+
+// Trigger an update right now, as initiated by a button.
+- (IBAction)updateNow:(id)sender;
+
+// Install a system Keystone if necessary and promote the ticket to a system
+// ticket.
+- (IBAction)promoteUpdater:(id)sender;
+
+@end // @interface AboutWindowController
+
+@interface AboutWindowController(JustForTesting)
+
+- (NSTextView*)legalText;
+- (NSButton*)updateButton;
+- (NSTextField*)updateText;
+
+// Returns an NSAttributedString that contains locale-specific legal text.
++ (NSAttributedString*)legalTextBlock;
+
+@end // @interface AboutWindowController(JustForTesting)
+
+#endif // CHROME_BROWSER_UI_COCOA_ABOUT_WINDOW_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/about_window_controller.mm b/chrome/browser/ui/cocoa/about_window_controller.mm
new file mode 100644
index 0000000..f6da6ab
--- /dev/null
+++ b/chrome/browser/ui/cocoa/about_window_controller.mm
@@ -0,0 +1,761 @@
+// 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 "chrome/browser/ui/cocoa/about_window_controller.h"
+
+#include "app/l10n_util.h"
+#include "app/l10n_util_mac.h"
+#include "app/resource_bundle.h"
+#include "base/logging.h"
+#include "base/mac_util.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/browser_window.h"
+#include "chrome/browser/platform_util.h"
+#import "chrome/browser/ui/cocoa/background_tile_view.h"
+#import "chrome/browser/ui/cocoa/keystone_glue.h"
+#include "chrome/browser/ui/cocoa/restart_browser.h"
+#include "chrome/common/url_constants.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "grit/locale_settings.h"
+#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
+
+namespace {
+
+void AttributedStringAppendString(NSMutableAttributedString* attr_str,
+ NSString* str) {
+ // You might think doing [[attr_str mutableString] appendString:str] would
+ // work, but it causes any trailing style to get extened, meaning as we
+ // append links, they grow to include the new text, not what we want.
+ NSAttributedString* new_attr_str =
+ [[[NSAttributedString alloc] initWithString:str] autorelease];
+ [attr_str appendAttributedString:new_attr_str];
+}
+
+void AttributedStringAppendHyperlink(NSMutableAttributedString* attr_str,
+ NSString* text, NSString* url_str) {
+ // Figure out the range of the text we're adding and add the text.
+ NSRange range = NSMakeRange([attr_str length], [text length]);
+ AttributedStringAppendString(attr_str, text);
+
+ // Add the link
+ [attr_str addAttribute:NSLinkAttributeName value:url_str range:range];
+
+ // Blue and underlined
+ [attr_str addAttribute:NSForegroundColorAttributeName
+ value:[NSColor blueColor]
+ range:range];
+ [attr_str addAttribute:NSUnderlineStyleAttributeName
+ value:[NSNumber numberWithInt:NSSingleUnderlineStyle]
+ range:range];
+ [attr_str addAttribute:NSCursorAttributeName
+ value:[NSCursor pointingHandCursor]
+ range:range];
+}
+
+} // namespace
+
+@interface AboutWindowController(Private)
+
+// Launches a check for available updates.
+- (void)checkForUpdate;
+
+// Turns the update and promotion blocks on and off as needed based on whether
+// updates are possible and promotion is desired or required.
+- (void)adjustUpdateUIVisibility;
+
+// Maintains the update and promotion block visibility and window sizing.
+// This uses bool instead of BOOL for the convenience of the internal
+// implementation.
+- (void)setAllowsUpdate:(bool)update allowsPromotion:(bool)promotion;
+
+// Notification callback, called with the status of asynchronous
+// -checkForUpdate and -updateNow: operations.
+- (void)updateStatus:(NSNotification*)notification;
+
+// These methods maintain the image (or throbber) and text displayed regarding
+// update status. -setUpdateThrobberMessage: starts a progress throbber and
+// sets the text. -setUpdateImage:message: displays an image and sets the
+// text.
+- (void)setUpdateThrobberMessage:(NSString*)message;
+- (void)setUpdateImage:(int)imageID message:(NSString*)message;
+
+@end // @interface AboutWindowController(Private)
+
+@implementation AboutLegalTextView
+
+// Never draw the insertion point (otherwise, it shows up without any user
+// action if full keyboard accessibility is enabled).
+- (BOOL)shouldDrawInsertionPoint {
+ return NO;
+}
+
+@end
+
+@implementation AboutWindowController
+
+- (id)initWithProfile:(Profile*)profile {
+ NSString* nibPath = [mac_util::MainAppBundle() pathForResource:@"About"
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibPath owner:self])) {
+ profile_ = profile;
+ NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+ [center addObserver:self
+ selector:@selector(updateStatus:)
+ name:kAutoupdateStatusNotification
+ object:nil];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+// YES when an About box is currently showing the kAutoupdateInstallFailed
+// status, or if no About box is visible, if the most recent About box to be
+// closed was closed while showing this status. When an About box opens, if
+// the recent status is kAutoupdateInstallFailed or kAutoupdatePromoteFailed
+// and recentShownUserActionFailedStatus is NO, the failure needs to be shown
+// instead of launching a new update check. recentShownInstallFailedStatus is
+// maintained by -updateStatus:.
+static BOOL recentShownUserActionFailedStatus = NO;
+
+- (void)awakeFromNib {
+ NSBundle* bundle = mac_util::MainAppBundle();
+ NSString* chromeVersion =
+ [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
+
+ NSString* versionModifier = @"";
+ NSString* svnRevision = @"";
+ std::string modifier = platform_util::GetVersionStringModifier();
+ if (!modifier.empty())
+ versionModifier = [NSString stringWithFormat:@" %@",
+ base::SysUTF8ToNSString(modifier)];
+
+#if !defined(GOOGLE_CHROME_BUILD)
+ svnRevision = [NSString stringWithFormat:@" (%@)",
+ [bundle objectForInfoDictionaryKey:@"SVNRevision"]];
+#endif
+ // The format string is not localized, but this is how the displayed version
+ // is built on Windows too.
+ NSString* version =
+ [NSString stringWithFormat:@"%@%@%@",
+ chromeVersion, svnRevision, versionModifier];
+
+ [version_ setStringValue:version];
+
+ // Put the two images into the UI.
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ NSImage* backgroundImage = rb.GetNativeImageNamed(IDR_ABOUT_BACKGROUND_COLOR);
+ DCHECK(backgroundImage);
+ [backgroundView_ setTileImage:backgroundImage];
+ NSImage* logoImage = rb.GetNativeImageNamed(IDR_ABOUT_BACKGROUND);
+ DCHECK(logoImage);
+ [logoView_ setImage:logoImage];
+
+ [[legalText_ textStorage] setAttributedString:[[self class] legalTextBlock]];
+
+ // Resize our text view now so that the |updateShift| below is set
+ // correctly. The About box has its controls manually positioned, so we need
+ // to calculate how much larger (or smaller) our text box is and store that
+ // difference in |legalShift|. We do something similar with |updateShift|
+ // below, which is either 0, or the amount of space to offset the window size
+ // because the view that contains the update button has been removed because
+ // this build doesn't have Keystone.
+ NSRect oldLegalRect = [legalBlock_ frame];
+ [legalText_ sizeToFit];
+ NSRect newRect = oldLegalRect;
+ newRect.size.height = [legalText_ frame].size.height;
+ [legalBlock_ setFrame:newRect];
+ CGFloat legalShift = newRect.size.height - oldLegalRect.size.height;
+
+ NSRect backgroundFrame = [backgroundView_ frame];
+ backgroundFrame.origin.y += legalShift;
+ [backgroundView_ setFrame:backgroundFrame];
+
+ NSSize windowDelta = NSMakeSize(0.0, legalShift);
+ [GTMUILocalizerAndLayoutTweaker
+ resizeWindowWithoutAutoResizingSubViews:[self window]
+ delta:windowDelta];
+
+ windowHeight_ = [[self window] frame].size.height;
+
+ [self adjustUpdateUIVisibility];
+
+ // Don't do anything update-related if adjustUpdateUIVisibility decided that
+ // updates aren't possible.
+ if (![updateBlock_ isHidden]) {
+ KeystoneGlue* keystoneGlue = [KeystoneGlue defaultKeystoneGlue];
+ AutoupdateStatus recentStatus = [keystoneGlue recentStatus];
+ if ([keystoneGlue asyncOperationPending] ||
+ recentStatus == kAutoupdateRegisterFailed ||
+ ((recentStatus == kAutoupdateInstallFailed ||
+ recentStatus == kAutoupdatePromoteFailed) &&
+ !recentShownUserActionFailedStatus)) {
+ // If an asynchronous update operation is currently pending, such as a
+ // check for updates or an update installation attempt, set the status
+ // up correspondingly without launching a new update check.
+ //
+ // If registration failed, no other operations make sense, so just go
+ // straight to the error.
+ //
+ // If a previous update or promotion attempt was unsuccessful but no
+ // About box was around to report the error, show it now, and allow
+ // another chance to perform the action.
+ [self updateStatus:[keystoneGlue recentNotification]];
+ } else {
+ // Launch a new update check, even if one was already completed, because
+ // a new update may be available or a new update may have been installed
+ // in the background since the last time an About box was displayed.
+ [self checkForUpdate];
+ }
+ }
+
+ [[self window] center];
+}
+
+- (void)windowWillClose:(NSNotification*)notification {
+ [self autorelease];
+}
+
+- (void)adjustUpdateUIVisibility {
+ bool allowUpdate;
+ bool allowPromotion;
+
+ KeystoneGlue* keystoneGlue = [KeystoneGlue defaultKeystoneGlue];
+ if (keystoneGlue && ![keystoneGlue isOnReadOnlyFilesystem]) {
+ AutoupdateStatus recentStatus = [keystoneGlue recentStatus];
+ if (recentStatus == kAutoupdateRegistering ||
+ recentStatus == kAutoupdateRegisterFailed ||
+ recentStatus == kAutoupdatePromoted) {
+ // Show the update block while registering so that there's a progress
+ // spinner, and if registration failed so that there's an error message.
+ // Show it following a promotion because updates should be possible
+ // after promotion successfully completes.
+ allowUpdate = true;
+
+ // Promotion isn't possible at this point.
+ allowPromotion = false;
+ } else if (recentStatus == kAutoupdatePromoteFailed) {
+ // TODO(mark): Add kAutoupdatePromoting to this block. KSRegistration
+ // currently handles the promotion synchronously, meaning that the main
+ // thread's loop doesn't spin, meaning that animations and other updates
+ // to the window won't occur until KSRegistration is done with
+ // promotion. This looks laggy and bad and probably qualifies as
+ // "jank." For now, there just won't be any visual feedback while
+ // promotion is in progress, but it should complete (or fail) very
+ // quickly. http://b/2290009.
+ //
+ // Also see the TODO for kAutoupdatePromoting in -updateStatus:version:.
+ //
+ // Show the update block so that there's some visual feedback that
+ // promotion is under way or that it's failed. Show the promotion block
+ // because the user either just clicked that button or because the user
+ // should be able to click it again.
+ allowUpdate = true;
+ allowPromotion = true;
+ } else {
+ // Show the update block only if a promotion is not absolutely required.
+ allowUpdate = ![keystoneGlue needsPromotion];
+
+ // Show the promotion block if promotion is a possibility.
+ allowPromotion = [keystoneGlue wantsPromotion];
+ }
+ } else {
+ // There is no glue, or the application is on a read-only filesystem.
+ // Updates and promotions are impossible.
+ allowUpdate = false;
+ allowPromotion = false;
+ }
+
+ [self setAllowsUpdate:allowUpdate allowsPromotion:allowPromotion];
+}
+
+- (void)setAllowsUpdate:(bool)update allowsPromotion:(bool)promotion {
+ bool oldUpdate = ![updateBlock_ isHidden];
+ bool oldPromotion = ![promoteButton_ isHidden];
+
+ if (promotion == oldPromotion && update == oldUpdate) {
+ return;
+ }
+
+ NSRect updateFrame = [updateBlock_ frame];
+ CGFloat delta = 0.0;
+
+ if (update != oldUpdate) {
+ [updateBlock_ setHidden:!update];
+ delta += (update ? 1.0 : -1.0) * NSHeight(updateFrame);
+ }
+
+ if (promotion != oldPromotion) {
+ [promoteButton_ setHidden:!promotion];
+ }
+
+ NSRect legalFrame = [legalBlock_ frame];
+
+ if (delta) {
+ updateFrame.origin.y += delta;
+ [updateBlock_ setFrame:updateFrame];
+
+ legalFrame.origin.y += delta;
+ [legalBlock_ setFrame:legalFrame];
+
+ NSRect backgroundFrame = [backgroundView_ frame];
+ backgroundFrame.origin.y += delta;
+ [backgroundView_ setFrame:backgroundFrame];
+
+ // GTMUILocalizerAndLayoutTweaker resizes the window without any
+ // opportunity for animation. In order to animate, disable window
+ // updates, save the current frame, let GTMUILocalizerAndLayoutTweaker do
+ // its thing, save the desired frame, restore the original frame, and then
+ // animate.
+ NSWindow* window = [self window];
+ [window disableScreenUpdatesUntilFlush];
+
+ NSRect oldFrame = [window frame];
+
+ // GTMUILocalizerAndLayoutTweaker applies its delta to the window's
+ // current size (like oldFrame.size), but oldFrame isn't trustworthy if
+ // an animation is in progress. Set the window's frame to
+ // intermediateFrame, which is a frame of the size that an existing
+ // animation is animating to, so that GTM can apply the delta to the right
+ // size.
+ NSRect intermediateFrame = oldFrame;
+ intermediateFrame.origin.y -= intermediateFrame.size.height - windowHeight_;
+ intermediateFrame.size.height = windowHeight_;
+ [window setFrame:intermediateFrame display:NO];
+
+ NSSize windowDelta = NSMakeSize(0.0, delta);
+ [GTMUILocalizerAndLayoutTweaker
+ resizeWindowWithoutAutoResizingSubViews:window
+ delta:windowDelta];
+ [window setFrameTopLeftPoint:NSMakePoint(NSMinX(intermediateFrame),
+ NSMaxY(intermediateFrame))];
+ NSRect newFrame = [window frame];
+
+ windowHeight_ += delta;
+
+ if (![[self window] isVisible]) {
+ // Don't animate if the window isn't on screen yet.
+ [window setFrame:newFrame display:NO];
+ } else {
+ [window setFrame:oldFrame display:NO];
+ [window setFrame:newFrame display:YES animate:YES];
+ }
+ }
+}
+
+- (void)setUpdateThrobberMessage:(NSString*)message {
+ [updateStatusIndicator_ setHidden:YES];
+
+ [spinner_ setHidden:NO];
+ [spinner_ startAnimation:self];
+
+ [updateText_ setStringValue:message];
+}
+
+- (void)setUpdateImage:(int)imageID message:(NSString*)message {
+ [spinner_ stopAnimation:self];
+ [spinner_ setHidden:YES];
+
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ NSImage* statusImage = rb.GetNativeImageNamed(imageID);
+ DCHECK(statusImage);
+ [updateStatusIndicator_ setImage:statusImage];
+ [updateStatusIndicator_ setHidden:NO];
+
+ [updateText_ setStringValue:message];
+}
+
+- (void)checkForUpdate {
+ [[KeystoneGlue defaultKeystoneGlue] checkForUpdate];
+
+ // Immediately, kAutoupdateStatusNotification will be posted, and
+ // -updateStatus: will be called with status kAutoupdateChecking.
+ //
+ // Upon completion, kAutoupdateStatusNotification will be posted, and
+ // -updateStatus: will be called with a status indicating the result of the
+ // check.
+}
+
+- (IBAction)updateNow:(id)sender {
+ [[KeystoneGlue defaultKeystoneGlue] installUpdate];
+
+ // Immediately, kAutoupdateStatusNotification will be posted, and
+ // -updateStatus: will be called with status kAutoupdateInstalling.
+ //
+ // Upon completion, kAutoupdateStatusNotification will be posted, and
+ // -updateStatus: will be called with a status indicating the result of the
+ // installation attempt.
+}
+
+- (IBAction)promoteUpdater:(id)sender {
+ [[KeystoneGlue defaultKeystoneGlue] promoteTicket];
+
+ // Immediately, kAutoupdateStatusNotification will be posted, and
+ // -updateStatus: will be called with status kAutoupdatePromoting.
+ //
+ // Upon completion, kAutoupdateStatusNotification will be posted, and
+ // -updateStatus: will be called with a status indicating a result of the
+ // installation attempt.
+ //
+ // If the promotion was successful, KeystoneGlue will re-register the ticket
+ // and -updateStatus: will be called again indicating first that
+ // registration is in progress and subsequently that it has completed.
+}
+
+- (void)updateStatus:(NSNotification*)notification {
+ recentShownUserActionFailedStatus = NO;
+
+ NSDictionary* dictionary = [notification userInfo];
+ AutoupdateStatus status = static_cast<AutoupdateStatus>(
+ [[dictionary objectForKey:kAutoupdateStatusStatus] intValue]);
+
+ // Don't assume |version| is a real string. It may be nil.
+ NSString* version = [dictionary objectForKey:kAutoupdateStatusVersion];
+
+ bool updateMessage = true;
+ bool throbber = false;
+ int imageID = 0;
+ NSString* message;
+ bool enableUpdateButton = false;
+ bool enablePromoteButton = true;
+
+ switch (status) {
+ case kAutoupdateRegistering:
+ // When registering, use the "checking" message. The check will be
+ // launched if appropriate immediately after registration.
+ throbber = true;
+ message = l10n_util::GetNSStringWithFixup(IDS_UPGRADE_CHECK_STARTED);
+ enablePromoteButton = false;
+
+ break;
+
+ case kAutoupdateRegistered:
+ // Once registered, the ability to update and promote is known.
+ [self adjustUpdateUIVisibility];
+
+ if (![updateBlock_ isHidden]) {
+ // If registration completes while the window is visible, go straight
+ // into an update check. Return immediately, this routine will be
+ // re-entered shortly with kAutoupdateChecking.
+ [self checkForUpdate];
+ return;
+ }
+
+ // Nothing actually failed, but updates aren't possible. The throbber
+ // and message are hidden, but they'll be reset to these dummy values
+ // just to get the throbber to stop spinning if it's running.
+ imageID = IDR_UPDATE_FAIL;
+ message = l10n_util::GetNSStringFWithFixup(IDS_UPGRADE_ERROR,
+ base::IntToString16(status));
+
+ break;
+
+ case kAutoupdateChecking:
+ throbber = true;
+ message = l10n_util::GetNSStringWithFixup(IDS_UPGRADE_CHECK_STARTED);
+ enablePromoteButton = false;
+
+ break;
+
+ case kAutoupdateCurrent:
+ imageID = IDR_UPDATE_UPTODATE;
+ message = l10n_util::GetNSStringFWithFixup(
+ IDS_UPGRADE_ALREADY_UP_TO_DATE,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
+ base::SysNSStringToUTF16(version));
+
+ break;
+
+ case kAutoupdateAvailable:
+ imageID = IDR_UPDATE_AVAILABLE;
+ message = l10n_util::GetNSStringFWithFixup(
+ IDS_UPGRADE_AVAILABLE, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
+ enableUpdateButton = true;
+
+ break;
+
+ case kAutoupdateInstalling:
+ throbber = true;
+ message = l10n_util::GetNSStringWithFixup(IDS_UPGRADE_STARTED);
+ enablePromoteButton = false;
+
+ break;
+
+ case kAutoupdateInstalled:
+ {
+ imageID = IDR_UPDATE_UPTODATE;
+ string16 productName = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
+ if (version) {
+ message = l10n_util::GetNSStringFWithFixup(
+ IDS_UPGRADE_SUCCESSFUL,
+ productName,
+ base::SysNSStringToUTF16(version));
+ } else {
+ message = l10n_util::GetNSStringFWithFixup(
+ IDS_UPGRADE_SUCCESSFUL_NOVERSION, productName);
+ }
+
+ // TODO(mark): Turn the button in the dialog into a restart button
+ // instead of springing this sheet or dialog.
+ NSWindow* window = [self window];
+ NSWindow* restartDialogParent = [window isVisible] ? window : nil;
+ restart_browser::RequestRestart(restartDialogParent);
+ }
+
+ break;
+
+ case kAutoupdatePromoting:
+#if 1
+ // TODO(mark): See the TODO in -adjustUpdateUIVisibility for an
+ // explanation of why nothing can be done here at the moment. When
+ // KSRegistration handles promotion asynchronously, this dummy block can
+ // be replaced with the #else block. For now, just leave the messaging
+ // alone. http://b/2290009.
+ updateMessage = false;
+#else
+ // The visibility may be changing.
+ [self adjustUpdateUIVisibility];
+
+ // This is not a terminal state, and kAutoupdatePromoted or
+ // kAutoupdatePromoteFailed will follow. Use the throbber and
+ // "checking" message so that it looks like something's happening.
+ throbber = true;
+ message = l10n_util::GetNSStringWithFixup(IDS_UPGRADE_CHECK_STARTED);
+#endif
+
+ enablePromoteButton = false;
+
+ break;
+
+ case kAutoupdatePromoted:
+ // The visibility may be changing.
+ [self adjustUpdateUIVisibility];
+
+ if (![updateBlock_ isHidden]) {
+ // If promotion completes while the window is visible, go straight
+ // into an update check. Return immediately, this routine will be
+ // re-entered shortly with kAutoupdateChecking.
+ [self checkForUpdate];
+ return;
+ }
+
+ // Nothing actually failed, but updates aren't possible. The throbber
+ // and message are hidden, but they'll be reset to these dummy values
+ // just to get the throbber to stop spinning if it's running.
+ imageID = IDR_UPDATE_FAIL;
+ message = l10n_util::GetNSStringFWithFixup(IDS_UPGRADE_ERROR,
+ base::IntToString16(status));
+
+ break;
+
+ case kAutoupdateRegisterFailed:
+ imageID = IDR_UPDATE_FAIL;
+ message = l10n_util::GetNSStringFWithFixup(IDS_UPGRADE_ERROR,
+ base::IntToString16(status));
+ enablePromoteButton = false;
+
+ break;
+
+ case kAutoupdateCheckFailed:
+ imageID = IDR_UPDATE_FAIL;
+ message = l10n_util::GetNSStringFWithFixup(IDS_UPGRADE_ERROR,
+ base::IntToString16(status));
+
+ break;
+
+ case kAutoupdateInstallFailed:
+ recentShownUserActionFailedStatus = YES;
+
+ imageID = IDR_UPDATE_FAIL;
+ message = l10n_util::GetNSStringFWithFixup(IDS_UPGRADE_ERROR,
+ base::IntToString16(status));
+
+ // Allow another chance.
+ enableUpdateButton = true;
+
+ break;
+
+ case kAutoupdatePromoteFailed:
+ recentShownUserActionFailedStatus = YES;
+
+ imageID = IDR_UPDATE_FAIL;
+ message = l10n_util::GetNSStringFWithFixup(IDS_UPGRADE_ERROR,
+ base::IntToString16(status));
+
+ break;
+
+ default:
+ NOTREACHED();
+
+ return;
+ }
+
+ if (updateMessage) {
+ if (throbber) {
+ [self setUpdateThrobberMessage:message];
+ } else {
+ DCHECK_NE(imageID, 0);
+ [self setUpdateImage:imageID message:message];
+ }
+ }
+
+ // Note that these buttons may be hidden depending on what
+ // -adjustUpdateUIVisibility did. Their enabled/disabled status doesn't
+ // necessarily have anything to do with their visibility.
+ [updateNowButton_ setEnabled:enableUpdateButton];
+ [promoteButton_ setEnabled:enablePromoteButton];
+}
+
+- (BOOL)textView:(NSTextView *)aTextView
+ clickedOnLink:(id)link
+ atIndex:(NSUInteger)charIndex {
+ // We always create a new window, so there's no need to try to re-use
+ // an existing one just to pass in the NEW_WINDOW disposition.
+ Browser* browser = Browser::Create(profile_);
+ browser->OpenURL(GURL([link UTF8String]), GURL(), NEW_FOREGROUND_TAB,
+ PageTransition::LINK);
+ browser->window()->Show();
+ return YES;
+}
+
+- (NSTextView*)legalText {
+ return legalText_;
+}
+
+- (NSButton*)updateButton {
+ return updateNowButton_;
+}
+
+- (NSTextField*)updateText {
+ return updateText_;
+}
+
++ (NSAttributedString*)legalTextBlock {
+ // Windows builds this up in a very complex way, we're just trying to model
+ // it the best we can to get all the information in (they actually do it
+ // but created Labels and Links that they carefully place to make it appear
+ // to be a paragraph of text).
+ // src/chrome/browser/views/about_chrome_view.cc AboutChromeView::Init()
+
+ NSMutableAttributedString* legal_block =
+ [[[NSMutableAttributedString alloc] init] autorelease];
+ [legal_block beginEditing];
+
+ NSString* copyright =
+ l10n_util::GetNSStringWithFixup(IDS_ABOUT_VERSION_COPYRIGHT);
+ AttributedStringAppendString(legal_block, copyright);
+
+ // These are the markers directly in IDS_ABOUT_VERSION_LICENSE
+ NSString* kBeginLinkChr = @"BEGIN_LINK_CHR";
+ NSString* kBeginLinkOss = @"BEGIN_LINK_OSS";
+ NSString* kEndLinkChr = @"END_LINK_CHR";
+ NSString* kEndLinkOss = @"END_LINK_OSS";
+ // The CHR link should go to here
+ NSString* kChromiumProject = l10n_util::GetNSString(IDS_CHROMIUM_PROJECT_URL);
+ // The OSS link should go to here
+ NSString* kAcknowledgements =
+ [NSString stringWithUTF8String:chrome::kAboutCreditsURL];
+
+ // Now fetch the license string and deal with the markers
+
+ NSString* license =
+ l10n_util::GetNSStringWithFixup(IDS_ABOUT_VERSION_LICENSE);
+
+ NSRange begin_chr = [license rangeOfString:kBeginLinkChr];
+ NSRange begin_oss = [license rangeOfString:kBeginLinkOss];
+ NSRange end_chr = [license rangeOfString:kEndLinkChr];
+ NSRange end_oss = [license rangeOfString:kEndLinkOss];
+ DCHECK_NE(begin_chr.location, NSNotFound);
+ DCHECK_NE(begin_oss.location, NSNotFound);
+ DCHECK_NE(end_chr.location, NSNotFound);
+ DCHECK_NE(end_oss.location, NSNotFound);
+
+ // We don't know which link will come first, so we have to deal with things
+ // like this:
+ // [text][begin][text][end][text][start][text][end][text]
+
+ bool chromium_link_first = begin_chr.location < begin_oss.location;
+
+ NSRange* begin1 = &begin_chr;
+ NSRange* begin2 = &begin_oss;
+ NSRange* end1 = &end_chr;
+ NSRange* end2 = &end_oss;
+ NSString* link1 = kChromiumProject;
+ NSString* link2 = kAcknowledgements;
+ if (!chromium_link_first) {
+ // OSS came first, switch!
+ begin2 = &begin_chr;
+ begin1 = &begin_oss;
+ end2 = &end_chr;
+ end1 = &end_oss;
+ link2 = kChromiumProject;
+ link1 = kAcknowledgements;
+ }
+
+ NSString *sub_str;
+
+ AttributedStringAppendString(legal_block, @"\n");
+ sub_str = [license substringWithRange:NSMakeRange(0, begin1->location)];
+ AttributedStringAppendString(legal_block, sub_str);
+ sub_str = [license substringWithRange:NSMakeRange(NSMaxRange(*begin1),
+ end1->location -
+ NSMaxRange(*begin1))];
+ AttributedStringAppendHyperlink(legal_block, sub_str, link1);
+ sub_str = [license substringWithRange:NSMakeRange(NSMaxRange(*end1),
+ begin2->location -
+ NSMaxRange(*end1))];
+ AttributedStringAppendString(legal_block, sub_str);
+ sub_str = [license substringWithRange:NSMakeRange(NSMaxRange(*begin2),
+ end2->location -
+ NSMaxRange(*begin2))];
+ AttributedStringAppendHyperlink(legal_block, sub_str, link2);
+ sub_str = [license substringWithRange:NSMakeRange(NSMaxRange(*end2),
+ [license length] -
+ NSMaxRange(*end2))];
+ AttributedStringAppendString(legal_block, sub_str);
+
+#if defined(GOOGLE_CHROME_BUILD)
+ // Terms of service is only valid for Google Chrome
+
+ // The url within terms should point here:
+ NSString* kTOS = [NSString stringWithUTF8String:chrome::kAboutTermsURL];
+ // Following Windows. There is one marker in the string for where the terms
+ // link goes, but the text of the link comes from a second string resources.
+ std::vector<size_t> url_offsets;
+ NSString* about_terms = l10n_util::GetNSStringF(IDS_ABOUT_TERMS_OF_SERVICE,
+ string16(),
+ string16(),
+ &url_offsets);
+ DCHECK_EQ(url_offsets.size(), 1U);
+ NSString* terms_link_text =
+ l10n_util::GetNSStringWithFixup(IDS_TERMS_OF_SERVICE);
+
+ AttributedStringAppendString(legal_block, @"\n\n");
+ sub_str = [about_terms substringToIndex:url_offsets[0]];
+ AttributedStringAppendString(legal_block, sub_str);
+ AttributedStringAppendHyperlink(legal_block, terms_link_text, kTOS);
+ sub_str = [about_terms substringFromIndex:url_offsets[0]];
+ AttributedStringAppendString(legal_block, sub_str);
+#endif // GOOGLE_CHROME_BUILD
+
+ // We need to explicitly select Lucida Grande because once we click on
+ // the NSTextView, it changes to Helvetica 12 otherwise.
+ NSRange string_range = NSMakeRange(0, [legal_block length]);
+ [legal_block addAttribute:NSFontAttributeName
+ value:[NSFont labelFontOfSize:11]
+ range:string_range];
+
+ [legal_block endEditing];
+ return legal_block;
+}
+
+@end // @implementation AboutWindowController
diff --git a/chrome/browser/ui/cocoa/about_window_controller_unittest.mm b/chrome/browser/ui/cocoa/about_window_controller_unittest.mm
new file mode 100644
index 0000000..4747efe
--- /dev/null
+++ b/chrome/browser/ui/cocoa/about_window_controller_unittest.mm
@@ -0,0 +1,137 @@
+// Copyright (c) 2009 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>
+
+#import "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/about_window_controller.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/keystone_glue.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+void PostAutoupdateStatusNotification(AutoupdateStatus status,
+ NSString* version) {
+ NSNumber* statusNumber = [NSNumber numberWithInt:status];
+ NSMutableDictionary* dictionary =
+ [NSMutableDictionary dictionaryWithObjects:&statusNumber
+ forKeys:&kAutoupdateStatusStatus
+ count:1];
+ if (version) {
+ [dictionary setObject:version forKey:kAutoupdateStatusVersion];
+ }
+
+ NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+ [center postNotificationName:kAutoupdateStatusNotification
+ object:nil
+ userInfo:dictionary];
+}
+
+class AboutWindowControllerTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ about_window_controller_ =
+ [[AboutWindowController alloc] initWithProfile:nil];
+ EXPECT_TRUE([about_window_controller_ window]);
+ }
+
+ virtual void TearDown() {
+ [about_window_controller_ close];
+ CocoaTest::TearDown();
+ }
+
+ AboutWindowController* about_window_controller_;
+};
+
+TEST_F(AboutWindowControllerTest, TestCopyright) {
+ NSString* text = [[AboutWindowController legalTextBlock] string];
+
+ // Make sure we have the word "Copyright" in it, which is present in all
+ // locales.
+ NSRange range = [text rangeOfString:@"Copyright"];
+ EXPECT_NE(NSNotFound, range.location);
+}
+
+TEST_F(AboutWindowControllerTest, RemovesLinkAnchors) {
+ NSString* text = [[AboutWindowController legalTextBlock] string];
+
+ // Make sure that we removed the "BEGIN_LINK" and "END_LINK" anchors.
+ NSRange range = [text rangeOfString:@"BEGIN_LINK"];
+ EXPECT_EQ(NSNotFound, range.location);
+
+ range = [text rangeOfString:@"END_LINK"];
+ EXPECT_EQ(NSNotFound, range.location);
+}
+
+TEST_F(AboutWindowControllerTest, AwakeNibSetsString) {
+ NSAttributedString* legal_text = [AboutWindowController legalTextBlock];
+ NSAttributedString* text_storage =
+ [[about_window_controller_ legalText] textStorage];
+
+ EXPECT_TRUE([legal_text isEqualToAttributedString:text_storage]);
+}
+
+TEST_F(AboutWindowControllerTest, TestButton) {
+ NSButton* button = [about_window_controller_ updateButton];
+ ASSERT_TRUE(button);
+
+ // Not enabled until we know if updates are available.
+ ASSERT_FALSE([button isEnabled]);
+ PostAutoupdateStatusNotification(kAutoupdateAvailable, nil);
+ ASSERT_TRUE([button isEnabled]);
+
+ // Make sure the button is hooked up
+ ASSERT_EQ([button target], about_window_controller_);
+ ASSERT_EQ([button action], @selector(updateNow:));
+}
+
+// Doesn't confirm correctness, but does confirm something happens.
+TEST_F(AboutWindowControllerTest, TestCallbacks) {
+ NSString *lastText = [[about_window_controller_ updateText]
+ stringValue];
+ PostAutoupdateStatusNotification(kAutoupdateCurrent, @"foo");
+ ASSERT_NSNE(lastText, [[about_window_controller_ updateText] stringValue]);
+
+ lastText = [[about_window_controller_ updateText] stringValue];
+ PostAutoupdateStatusNotification(kAutoupdateCurrent, @"foo");
+ ASSERT_NSEQ(lastText, [[about_window_controller_ updateText] stringValue]);
+
+ lastText = [[about_window_controller_ updateText] stringValue];
+ PostAutoupdateStatusNotification(kAutoupdateCurrent, @"bar");
+ ASSERT_NSNE(lastText, [[about_window_controller_ updateText] stringValue]);
+
+ lastText = [[about_window_controller_ updateText] stringValue];
+ PostAutoupdateStatusNotification(kAutoupdateAvailable, nil);
+ ASSERT_NSNE(lastText, [[about_window_controller_ updateText] stringValue]);
+
+ lastText = [[about_window_controller_ updateText] stringValue];
+ PostAutoupdateStatusNotification(kAutoupdateCheckFailed, nil);
+ ASSERT_NSNE(lastText, [[about_window_controller_ updateText] stringValue]);
+
+#if 0
+ // TODO(mark): The kAutoupdateInstalled portion of the test is disabled
+ // because it leaks restart dialogs. If the About box is revised to use
+ // a button within the box to advise a restart instead of popping dialogs,
+ // these tests should be enabled.
+
+ lastText = [[about_window_controller_ updateText] stringValue];
+ PostAutoupdateStatusNotification(kAutoupdateInstalled, @"ver");
+ ASSERT_NSNE(lastText, [[about_window_controller_ updateText] stringValue]);
+
+ lastText = [[about_window_controller_ updateText] stringValue];
+ PostAutoupdateStatusNotification(kAutoupdateInstalled, nil);
+ ASSERT_NSNE(lastText, [[about_window_controller_ updateText] stringValue]);
+#endif
+
+ lastText = [[about_window_controller_ updateText] stringValue];
+ PostAutoupdateStatusNotification(kAutoupdateInstallFailed, nil);
+ ASSERT_NSNE(lastText, [[about_window_controller_ updateText] stringValue]);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/accelerators_cocoa.h b/chrome/browser/ui/cocoa/accelerators_cocoa.h
new file mode 100644
index 0000000..9b0a555
--- /dev/null
+++ b/chrome/browser/ui/cocoa/accelerators_cocoa.h
@@ -0,0 +1,48 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_ACCELERATORS_COCOA_H_
+#define CHROME_BROWSER_UI_COCOA_ACCELERATORS_COCOA_H_
+#pragma once
+
+#include <map>
+
+#include "app/menus/accelerator_cocoa.h"
+
+template <typename T> struct DefaultSingletonTraits;
+
+// This class maintains a map of command_ids to AcceleratorCocoa objects (see
+// chrome/app/chrome_command_ids.h). Currently, this only lists the commands
+// that are used in the Wrench menu.
+//
+// It is recommended that this class be used as a singleton so that the key map
+// isn't created multiple places.
+//
+// #import "base/singleton.h"
+// ...
+// AcceleratorsCocoa* keymap = AcceleratorsCocoa::GetInstance();
+// return keymap->GetAcceleratorForCommand(IDC_COPY);
+//
+class AcceleratorsCocoa {
+ public:
+ typedef std::map<int, menus::AcceleratorCocoa> AcceleratorCocoaMap;
+
+ // Returns NULL if there is no accelerator for the command.
+ const menus::AcceleratorCocoa* GetAcceleratorForCommand(int command_id);
+
+ // Returns the singleton instance.
+ static AcceleratorsCocoa* GetInstance();
+
+ private:
+ friend struct DefaultSingletonTraits<AcceleratorsCocoa>;
+
+ AcceleratorsCocoa();
+ ~AcceleratorsCocoa() {}
+
+ AcceleratorCocoaMap accelerators_;
+
+ DISALLOW_COPY_AND_ASSIGN(AcceleratorsCocoa);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_ACCELERATORS_COCOA_H_
diff --git a/chrome/browser/ui/cocoa/accelerators_cocoa.mm b/chrome/browser/ui/cocoa/accelerators_cocoa.mm
new file mode 100644
index 0000000..6f28a0f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/accelerators_cocoa.mm
@@ -0,0 +1,63 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/accelerators_cocoa.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/singleton.h"
+#include "chrome/app/chrome_command_ids.h"
+
+namespace {
+
+const struct AcceleratorMapping {
+ int command_id;
+ NSString* key;
+ NSUInteger modifiers;
+} kAcceleratorMap[] = {
+ { IDC_CLEAR_BROWSING_DATA, @"\x8", NSCommandKeyMask | NSShiftKeyMask },
+ { IDC_COPY, @"c", NSCommandKeyMask },
+ { IDC_CUT, @"x", NSCommandKeyMask },
+ { IDC_DEV_TOOLS, @"i", NSCommandKeyMask | NSAlternateKeyMask },
+ { IDC_DEV_TOOLS_CONSOLE, @"j", NSCommandKeyMask | NSAlternateKeyMask },
+ { IDC_FIND, @"f", NSCommandKeyMask },
+ { IDC_FULLSCREEN, @"f", NSCommandKeyMask | NSShiftKeyMask },
+ { IDC_NEW_INCOGNITO_WINDOW, @"n", NSCommandKeyMask | NSShiftKeyMask },
+ { IDC_NEW_TAB, @"t", NSCommandKeyMask },
+ { IDC_NEW_WINDOW, @"n", NSCommandKeyMask },
+ { IDC_OPTIONS, @",", NSCommandKeyMask },
+ { IDC_PASTE, @"v", NSCommandKeyMask },
+ { IDC_PRINT, @"p", NSCommandKeyMask },
+ { IDC_SAVE_PAGE, @"s", NSCommandKeyMask },
+ { IDC_SHOW_BOOKMARK_BAR, @"b", NSCommandKeyMask | NSShiftKeyMask },
+ { IDC_SHOW_BOOKMARK_MANAGER, @"b", NSCommandKeyMask | NSAlternateKeyMask },
+ { IDC_SHOW_DOWNLOADS, @"j", NSCommandKeyMask | NSShiftKeyMask },
+ { IDC_SHOW_HISTORY, @"y", NSCommandKeyMask },
+ { IDC_VIEW_SOURCE, @"u", NSCommandKeyMask | NSAlternateKeyMask },
+ { IDC_ZOOM_MINUS, @"-", NSCommandKeyMask },
+ { IDC_ZOOM_PLUS, @"+", NSCommandKeyMask }
+};
+
+} // namespace
+
+AcceleratorsCocoa::AcceleratorsCocoa() {
+ for (size_t i = 0; i < arraysize(kAcceleratorMap); ++i) {
+ const AcceleratorMapping& entry = kAcceleratorMap[i];
+ menus::AcceleratorCocoa accelerator(entry.key, entry.modifiers);
+ accelerators_.insert(std::make_pair(entry.command_id, accelerator));
+ }
+}
+
+// static
+AcceleratorsCocoa* AcceleratorsCocoa::GetInstance() {
+ return Singleton<AcceleratorsCocoa>::get();
+}
+
+const menus::AcceleratorCocoa* AcceleratorsCocoa::GetAcceleratorForCommand(
+ int command_id) {
+ AcceleratorCocoaMap::iterator it = accelerators_.find(command_id);
+ if (it == accelerators_.end())
+ return NULL;
+ return &it->second;
+}
diff --git a/chrome/browser/ui/cocoa/accelerators_cocoa_unittest.mm b/chrome/browser/ui/cocoa/accelerators_cocoa_unittest.mm
new file mode 100644
index 0000000..ef1436d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/accelerators_cocoa_unittest.mm
@@ -0,0 +1,28 @@
+// 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 "app/menus/accelerator_cocoa.h"
+#include "base/singleton.h"
+#include "chrome/app/chrome_command_ids.h"
+#import "chrome/browser/ui/cocoa/accelerators_cocoa.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gtest_mac.h"
+
+TEST(AcceleratorsCocoaTest, GetAccelerator) {
+ AcceleratorsCocoa* keymap = AcceleratorsCocoa::GetInstance();
+ const menus::AcceleratorCocoa* accelerator =
+ keymap->GetAcceleratorForCommand(IDC_COPY);
+ ASSERT_TRUE(accelerator);
+ EXPECT_NSEQ(@"c", accelerator->characters());
+ EXPECT_EQ(static_cast<int>(NSCommandKeyMask), accelerator->modifiers());
+}
+
+TEST(AcceleratorsCocoaTest, GetNullAccelerator) {
+ AcceleratorsCocoa* keymap = AcceleratorsCocoa::GetInstance();
+ const menus::AcceleratorCocoa* accelerator =
+ keymap->GetAcceleratorForCommand(314159265);
+ EXPECT_FALSE(accelerator);
+}
diff --git a/chrome/browser/ui/cocoa/animatable_image.h b/chrome/browser/ui/cocoa/animatable_image.h
new file mode 100644
index 0000000..65fd023
--- /dev/null
+++ b/chrome/browser/ui/cocoa/animatable_image.h
@@ -0,0 +1,57 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_ANIMATABLE_IMAGE_H_
+#define CHROME_BROWSER_UI_COCOA_ANIMATABLE_IMAGE_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+#import <QuartzCore/QuartzCore.h>
+
+#include "base/scoped_nsobject.h"
+
+// This class helps animate an NSImage's frame and opacity. It works by creating
+// a blank NSWindow in the size specified and giving it a layer on which the
+// image can be animated. Clients are free to embed this object as a child
+// window for easier window management. This class will clean itself up when
+// the animation has finished. Clients that install this as a child window
+// should listen for the NSWindowWillCloseNotification to perform any additional
+// cleanup.
+@interface AnimatableImage : NSWindow {
+ @private
+ // The image to animate.
+ scoped_nsobject<NSImage> image_;
+
+ // The frame of the image before and after the animation. This is in this
+ // window's coordinate system.
+ CGRect startFrame_;
+ CGRect endFrame_;
+
+ // Opacity values for the animation.
+ CGFloat startOpacity_;
+ CGFloat endOpacity_;
+
+ // The amount of time it takes to animate the image.
+ CGFloat duration_;
+}
+
+@property (nonatomic) CGRect startFrame;
+@property (nonatomic) CGRect endFrame;
+@property (nonatomic) CGFloat startOpacity;
+@property (nonatomic) CGFloat endOpacity;
+@property (nonatomic) CGFloat duration;
+
+// Designated initializer. Do not use any other NSWindow initializers. Creates
+// but does not show the blank animation window of the given size. The
+// |animationFrame| should usually be big enough to contain the |startFrame|
+// and |endFrame| properties of the animation.
+- (id)initWithImage:(NSImage*)image
+ animationFrame:(NSRect)animationFrame;
+
+// Begins the animation.
+- (void)startAnimation;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_ANIMATABLE_IMAGE_H_
diff --git a/chrome/browser/ui/cocoa/animatable_image.mm b/chrome/browser/ui/cocoa/animatable_image.mm
new file mode 100644
index 0000000..a73f5a4
--- /dev/null
+++ b/chrome/browser/ui/cocoa/animatable_image.mm
@@ -0,0 +1,145 @@
+// 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 "chrome/browser/ui/cocoa/animatable_image.h"
+
+#include "base/logging.h"
+#import "base/mac_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
+
+@interface AnimatableImage (Private)
+- (void)setLayerContents:(CALayer*)layer;
+@end
+
+@implementation AnimatableImage
+
+@synthesize startFrame = startFrame_;
+@synthesize endFrame = endFrame_;
+@synthesize startOpacity = startOpacity_;
+@synthesize endOpacity = endOpacity_;
+@synthesize duration = duration_;
+
+- (id)initWithImage:(NSImage*)image
+ animationFrame:(NSRect)animationFrame {
+ if ((self = [super initWithContentRect:animationFrame
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO])) {
+ DCHECK(image);
+ image_.reset([image retain]);
+ duration_ = 1.0;
+ startOpacity_ = 1.0;
+ endOpacity_ = 1.0;
+
+ [self setOpaque:NO];
+ [self setBackgroundColor:[NSColor clearColor]];
+ [self setIgnoresMouseEvents:YES];
+
+ // Must be set or else self will be leaked.
+ [self setReleasedWhenClosed:YES];
+ }
+ return self;
+}
+
+- (void)startAnimation {
+ // Set up the root layer. By calling -setLayer: followed by -setWantsLayer:
+ // the view becomes a layer hosting view as opposed to a layer backed view.
+ NSView* view = [self contentView];
+ CALayer* rootLayer = [CALayer layer];
+ [view setLayer:rootLayer];
+ [view setWantsLayer:YES];
+
+ // Create the layer that will be animated.
+ CALayer* layer = [CALayer layer];
+ [self setLayerContents:layer];
+ [layer setAnchorPoint:CGPointMake(0, 1)];
+ [layer setFrame:[self startFrame]];
+ [layer setNeedsDisplayOnBoundsChange:YES];
+ [rootLayer addSublayer:layer];
+
+ // Common timing function for all animations.
+ CAMediaTimingFunction* mediaFunction =
+ [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
+
+ // Animate the bounds only if the image is resized.
+ CABasicAnimation* boundsAnimation = nil;
+ if (CGRectGetWidth([self startFrame]) != CGRectGetWidth([self endFrame]) ||
+ CGRectGetHeight([self startFrame]) != CGRectGetHeight([self endFrame])) {
+ boundsAnimation = [CABasicAnimation animationWithKeyPath:@"bounds"];
+ NSRect startRect = NSMakeRect(0, 0,
+ CGRectGetWidth([self startFrame]),
+ CGRectGetHeight([self startFrame]));
+ [boundsAnimation setFromValue:[NSValue valueWithRect:startRect]];
+ NSRect endRect = NSMakeRect(0, 0,
+ CGRectGetWidth([self endFrame]),
+ CGRectGetHeight([self endFrame]));
+ [boundsAnimation setToValue:[NSValue valueWithRect:endRect]];
+ [boundsAnimation gtm_setDuration:[self duration]
+ eventMask:NSLeftMouseUpMask];
+ [boundsAnimation setTimingFunction:mediaFunction];
+ }
+
+ // Positional animation.
+ CABasicAnimation* positionAnimation =
+ [CABasicAnimation animationWithKeyPath:@"position"];
+ [positionAnimation setFromValue:
+ [NSValue valueWithPoint:NSPointFromCGPoint([self startFrame].origin)]];
+ [positionAnimation setToValue:
+ [NSValue valueWithPoint:NSPointFromCGPoint([self endFrame].origin)]];
+ [positionAnimation gtm_setDuration:[self duration]
+ eventMask:NSLeftMouseUpMask];
+ [positionAnimation setTimingFunction:mediaFunction];
+
+ // Opacity animation.
+ CABasicAnimation* opacityAnimation =
+ [CABasicAnimation animationWithKeyPath:@"opacity"];
+ [opacityAnimation setFromValue:
+ [NSNumber numberWithFloat:[self startOpacity]]];
+ [opacityAnimation setToValue:[NSNumber numberWithFloat:[self endOpacity]]];
+ [opacityAnimation gtm_setDuration:[self duration]
+ eventMask:NSLeftMouseUpMask];
+ [opacityAnimation setTimingFunction:mediaFunction];
+ // Set the delegate just for one of the animations so that this window can
+ // be closed upon completion.
+ [opacityAnimation setDelegate:self];
+
+ // The CAAnimations only affect the presentational value of a layer, not the
+ // model value. This means that after the animation is done, it can flicker
+ // back to the original values. To avoid this, create an implicit animation of
+ // the values, which are then overridden with the CABasicAnimations.
+ //
+ // Ideally, a call to |-setBounds:| should be here, but, for reasons that
+ // are not understood, doing so causes the animation to break.
+ [layer setPosition:[self endFrame].origin];
+ [layer setOpacity:[self endOpacity]];
+
+ // Start the animations.
+ [CATransaction begin];
+ [CATransaction setValue:[NSNumber numberWithFloat:[self duration]]
+ forKey:kCATransactionAnimationDuration];
+ if (boundsAnimation) {
+ [layer addAnimation:boundsAnimation forKey:@"bounds"];
+ }
+ [layer addAnimation:positionAnimation forKey:@"position"];
+ [layer addAnimation:opacityAnimation forKey:@"opacity"];
+ [CATransaction commit];
+}
+
+// Sets the layer contents by converting the NSImage to a CGImageRef. This will
+// rasterize PDF resources.
+- (void)setLayerContents:(CALayer*)layer {
+ base::mac::ScopedCFTypeRef<CGImageRef> image(
+ mac_util::CopyNSImageToCGImage(image_.get()));
+ // Create the layer that will be animated.
+ [layer setContents:(id)image.get()];
+}
+
+// CAAnimation delegate method called when the animation is complete.
+- (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)flag {
+ // Close the window, releasing self.
+ [self close];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/animatable_image_unittest.mm b/chrome/browser/ui/cocoa/animatable_image_unittest.mm
new file mode 100644
index 0000000..112e8dd
--- /dev/null
+++ b/chrome/browser/ui/cocoa/animatable_image_unittest.mm
@@ -0,0 +1,46 @@
+// 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>
+
+#import "app/mac/nsimage_cache.h"
+#import "chrome/browser/ui/cocoa/animatable_image.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class AnimatableImageTest : public CocoaTest {
+ public:
+ AnimatableImageTest() {
+ NSRect frame = NSMakeRect(0, 0, 500, 500);
+ NSImage* image = app::mac::GetCachedImageWithName(@"forward_Template.pdf");
+ animation_ = [[AnimatableImage alloc] initWithImage:image
+ animationFrame:frame];
+ }
+
+ AnimatableImage* animation_;
+};
+
+TEST_F(AnimatableImageTest, BasicAnimation) {
+ [animation_ setStartFrame:CGRectMake(0, 0, 10, 10)];
+ [animation_ setEndFrame:CGRectMake(500, 500, 100, 100)];
+ [animation_ setStartOpacity:0.1];
+ [animation_ setEndOpacity:1.0];
+ [animation_ setDuration:0.5];
+ [animation_ startAnimation];
+}
+
+TEST_F(AnimatableImageTest, CancelAnimation) {
+ [animation_ setStartFrame:CGRectMake(0, 0, 10, 10)];
+ [animation_ setEndFrame:CGRectMake(500, 500, 100, 100)];
+ [animation_ setStartOpacity:0.1];
+ [animation_ setEndOpacity:1.0];
+ [animation_ setDuration:5.0]; // Long enough to be able to test cancelling.
+ [animation_ startAnimation];
+ [animation_ close];
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/animatable_view.h b/chrome/browser/ui/cocoa/animatable_view.h
new file mode 100644
index 0000000..2bd121a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/animatable_view.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_ANIMATABLE_VIEW_H_
+#define CHROME_BROWSER_UI_COCOA_ANIMATABLE_VIEW_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/background_gradient_view.h"
+#import "chrome/browser/ui/cocoa/view_resizer.h"
+
+// A view that provides an animatable height property. Provides methods to
+// animate to a new height, set a new height immediately, or cancel any running
+// animations.
+//
+// AnimatableView sends an |animationDidEnd:| message to its delegate when the
+// animation ends normally and an |animationDidStop:| message when the animation
+// was canceled (even when canceled as a result of a new animation starting).
+
+@interface AnimatableView : BackgroundGradientView<NSAnimationDelegate> {
+ @protected
+ IBOutlet id delegate_; // weak, used to send animation ended messages.
+
+ @private
+ scoped_nsobject<NSAnimation> currentAnimation_;
+ id<ViewResizer> resizeDelegate_; // weak, usually owns us
+}
+
+// Properties for bindings.
+@property(assign, nonatomic) id delegate;
+@property(assign, nonatomic) id<ViewResizer> resizeDelegate;
+
+// Gets the current height of the view. If an animation is currently running,
+// this will give the current height at the time of the call, not the target
+// height at the end of the animation.
+- (CGFloat)height;
+
+// Sets the height of the view immediately. Cancels any running animations.
+- (void)setHeight:(CGFloat)newHeight;
+
+// Starts a new animation to the given |newHeight| for the given |duration|.
+// Cancels any running animations.
+- (void)animateToNewHeight:(CGFloat)newHeight
+ duration:(NSTimeInterval)duration;
+
+// Cancels any running animations, leaving the view at its current
+// (mid-animation) height.
+- (void)stopAnimation;
+
+// Gets the progress of any current animation.
+- (NSAnimationProgress)currentAnimationProgress;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_ANIMATABLE_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/animatable_view.mm b/chrome/browser/ui/cocoa/animatable_view.mm
new file mode 100644
index 0000000..74dc4b1
--- /dev/null
+++ b/chrome/browser/ui/cocoa/animatable_view.mm
@@ -0,0 +1,109 @@
+// Copyright (c) 2009 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>
+#import <QuartzCore/QuartzCore.h>
+
+#import "chrome/browser/ui/cocoa/animatable_view.h"
+#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
+
+// NSAnimation subclass that animates the height of an AnimatableView. Allows
+// the caller to start and cancel the animation as desired.
+@interface HeightAnimation : NSAnimation {
+ @private
+ AnimatableView* view_; // weak, owns us.
+ CGFloat startHeight_;
+ CGFloat endHeight_;
+}
+
+// Initialize a new height animation for the given view. The animation will not
+// start until startAnimation: is called.
+- (id)initWithView:(AnimatableView*)view
+ finalHeight:(CGFloat)height
+ duration:(NSTimeInterval)duration;
+@end
+
+@implementation HeightAnimation
+- (id)initWithView:(AnimatableView*)view
+ finalHeight:(CGFloat)height
+ duration:(NSTimeInterval)duration {
+ if ((self = [super gtm_initWithDuration:duration
+ eventMask:NSLeftMouseUpMask
+ animationCurve:NSAnimationEaseIn])) {
+ view_ = view;
+ startHeight_ = [view_ height];
+ endHeight_ = height;
+ [self setAnimationBlockingMode:NSAnimationNonblocking];
+ [self setDelegate:view_];
+ }
+ return self;
+}
+
+// Overridden to call setHeight for each progress tick.
+- (void)setCurrentProgress:(NSAnimationProgress)progress {
+ [super setCurrentProgress:progress];
+ [view_ setHeight:((progress * (endHeight_ - startHeight_)) + startHeight_)];
+}
+@end
+
+
+@implementation AnimatableView
+@synthesize delegate = delegate_;
+@synthesize resizeDelegate = resizeDelegate_;
+
+- (void)dealloc {
+ // Stop the animation if it is running, since it holds a pointer to this view.
+ [self stopAnimation];
+ [super dealloc];
+}
+
+- (CGFloat)height {
+ return [self frame].size.height;
+}
+
+- (void)setHeight:(CGFloat)newHeight {
+ // Force the height to be an integer because some animations look terrible
+ // with non-integer intermediate heights. We only ever set integer heights
+ // for our views, so this shouldn't be a limitation in practice.
+ int height = floor(newHeight);
+ [resizeDelegate_ resizeView:self newHeight:height];
+}
+
+- (void)animateToNewHeight:(CGFloat)newHeight
+ duration:(NSTimeInterval)duration {
+ [currentAnimation_ stopAnimation];
+
+ currentAnimation_.reset([[HeightAnimation alloc] initWithView:self
+ finalHeight:newHeight
+ duration:duration]);
+ if ([resizeDelegate_ respondsToSelector:@selector(setAnimationInProgress:)])
+ [resizeDelegate_ setAnimationInProgress:YES];
+ [currentAnimation_ startAnimation];
+}
+
+- (void)stopAnimation {
+ [currentAnimation_ stopAnimation];
+}
+
+- (NSAnimationProgress)currentAnimationProgress {
+ return [currentAnimation_ currentProgress];
+}
+
+- (void)animationDidStop:(NSAnimation*)animation {
+ if ([resizeDelegate_ respondsToSelector:@selector(setAnimationInProgress:)])
+ [resizeDelegate_ setAnimationInProgress:NO];
+ if ([delegate_ respondsToSelector:@selector(animationDidStop:)])
+ [delegate_ animationDidStop:animation];
+ currentAnimation_.reset(nil);
+}
+
+- (void)animationDidEnd:(NSAnimation*)animation {
+ if ([resizeDelegate_ respondsToSelector:@selector(setAnimationInProgress:)])
+ [resizeDelegate_ setAnimationInProgress:NO];
+ if ([delegate_ respondsToSelector:@selector(animationDidEnd:)])
+ [delegate_ animationDidEnd:animation];
+ currentAnimation_.reset(nil);
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/animatable_view_unittest.mm b/chrome/browser/ui/cocoa/animatable_view_unittest.mm
new file mode 100644
index 0000000..b9073a8
--- /dev/null
+++ b/chrome/browser/ui/cocoa/animatable_view_unittest.mm
@@ -0,0 +1,48 @@
+// Copyright (c) 2009 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 "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/animatable_view.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/view_resizer_pong.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class AnimatableViewTest : public CocoaTest {
+ public:
+ AnimatableViewTest() {
+ NSRect frame = NSMakeRect(0, 0, 100, 100);
+ view_.reset([[AnimatableView alloc] initWithFrame:frame]);
+ [[test_window() contentView] addSubview:view_.get()];
+
+ resizeDelegate_.reset([[ViewResizerPong alloc] init]);
+ [view_ setResizeDelegate:resizeDelegate_.get()];
+ }
+
+ scoped_nsobject<ViewResizerPong> resizeDelegate_;
+ scoped_nsobject<AnimatableView> view_;
+};
+
+// Basic view tests (AddRemove, Display).
+TEST_VIEW(AnimatableViewTest, view_);
+
+TEST_F(AnimatableViewTest, GetAndSetHeight) {
+ // Make sure the view's height starts out at 100.
+ NSRect initialFrame = [view_ frame];
+ ASSERT_EQ(100, initialFrame.size.height);
+ EXPECT_EQ(initialFrame.size.height, [view_ height]);
+
+ // Set it directly to 50 and make sure it takes effect.
+ [resizeDelegate_ setHeight:-1];
+ [view_ setHeight:50];
+ EXPECT_EQ(50, [resizeDelegate_ height]);
+}
+
+// TODO(rohitrao): Find a way to unittest the animations and delegate messages.
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_unittest.h b/chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_unittest.h
new file mode 100644
index 0000000..41e22d2
--- /dev/null
+++ b/chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_unittest.h
@@ -0,0 +1,53 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_APPLESCRIPT_BOOKMARK_APPLESCRIPT_UTILS_UNITTEST_H_
+#define CHROME_BROWSER_UI_COCOA_APPLESCRIPT_BOOKMARK_APPLESCRIPT_UTILS_UNITTEST_H_
+
+#import <objc/objc-runtime.h>
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/app_controller_mac.h"
+#import "chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/test/model_test_utils.h"
+#include "testing/platform_test.h"
+
+class BookmarkModel;
+
+// The fake object that acts as our app's delegate, useful for testing purposes.
+@interface FakeAppDelegate : AppController {
+ @public
+ BrowserTestHelper* helper_; // weak.
+}
+@property (nonatomic) BrowserTestHelper* helper;
+// Return the |TestingProfile*| which is used for testing.
+- (Profile*)defaultProfile;
+@end
+
+
+// Used to emulate an active running script, useful for testing purposes.
+@interface FakeScriptCommand : NSScriptCommand {
+ Method originalMethod_;
+ Method alternateMethod_;
+}
+@end
+
+
+// The base class for all our bookmark releated unit tests.
+class BookmarkAppleScriptTest : public CocoaTest {
+ public:
+ BookmarkAppleScriptTest();
+ private:
+ BrowserTestHelper helper_;
+ scoped_nsobject<FakeAppDelegate> appDelegate_;
+ protected:
+ scoped_nsobject<BookmarkFolderAppleScript> bookmarkBar_;
+ BookmarkModel& model();
+};
+
+#endif
+// CHROME_BROWSER_UI_COCOA_APPLESCRIPT_BOOKMARK_APPLESCRIPT_UTILS_UNITTEST_H_
diff --git a/chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_unittest.mm b/chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_unittest.mm
new file mode 100644
index 0000000..108b1fb
--- /dev/null
+++ b/chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_unittest.mm
@@ -0,0 +1,62 @@
+// 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 "chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_unittest.h"
+
+#include "chrome/browser/bookmarks/bookmark_model.h"
+
+@implementation FakeAppDelegate
+
+@synthesize helper = helper_;
+
+- (Profile*)defaultProfile {
+ if (!helper_)
+ return NULL;
+ return helper_->profile();
+}
+@end
+
+// Represents the current fake command that is executing.
+static FakeScriptCommand* kFakeCurrentCommand;
+
+@implementation FakeScriptCommand
+
+- (id)init {
+ if ((self = [super init])) {
+ originalMethod_ = class_getClassMethod([NSScriptCommand class],
+ @selector(currentCommand));
+ alternateMethod_ = class_getClassMethod([self class],
+ @selector(currentCommand));
+ method_exchangeImplementations(originalMethod_, alternateMethod_);
+ kFakeCurrentCommand = self;
+ }
+ return self;
+}
+
++ (NSScriptCommand*)currentCommand {
+ return kFakeCurrentCommand;
+}
+
+- (void)dealloc {
+ method_exchangeImplementations(originalMethod_, alternateMethod_);
+ kFakeCurrentCommand = nil;
+ [super dealloc];
+}
+
+@end
+
+BookmarkAppleScriptTest::BookmarkAppleScriptTest() {
+ appDelegate_.reset([[FakeAppDelegate alloc] init]);
+ [appDelegate_.get() setHelper:&helper_];
+ [NSApp setDelegate:appDelegate_];
+ const BookmarkNode* root = model().GetBookmarkBarNode();
+ const std::string modelString("a f1:[ b d c ] d f2:[ e f g ] h ");
+ model_test_utils::AddNodesFromModelString(model(), root, modelString);
+ bookmarkBar_.reset([[BookmarkFolderAppleScript alloc]
+ initWithBookmarkNode:model().GetBookmarkBarNode()]);
+}
+
+BookmarkModel& BookmarkAppleScriptTest::model() {
+ return *helper_.profile()->GetBookmarkModel();
+}
diff --git a/chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript.h b/chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript.h
new file mode 100644
index 0000000..3e853b3
--- /dev/null
+++ b/chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript.h
@@ -0,0 +1,70 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_APPLESCRIPT_BOOKMARK_FOLDER_APPLESCRIPT_H_
+#define CHROME_BROWSER_UI_COCOA_APPLESCRIPT_BOOKMARK_FOLDER_APPLESCRIPT_H_
+
+#import <Cocoa/Cocoa.h>
+
+#import "chrome/browser/ui/cocoa/applescript/bookmark_node_applescript.h"
+
+@class BookmarkItemAppleScript;
+
+// Represent a bookmark folder scriptable object in applescript.
+@interface BookmarkFolderAppleScript : BookmarkNodeAppleScript {
+
+}
+
+// Bookmark folder manipulation methods.
+// Returns an array of |BookmarkFolderAppleScript*| of all the bookmark folders
+// contained within this particular folder.
+- (NSArray*)bookmarkFolders;
+
+// Inserts a bookmark folder at the end.
+- (void)insertInBookmarkFolders:(id)aBookmarkFolder;
+
+// Inserts a bookmark folder at some position in the list.
+// Called by applescript which takes care of bounds checking, make sure of it
+// before calling directly.
+- (void)insertInBookmarkFolders:(id)aBookmarkFolder atIndex:(int)index;
+
+// Remove a bookmark folder from the list.
+// Called by applescript which takes care of bounds checking, make sure of it
+// before calling directly.
+- (void)removeFromBookmarkFoldersAtIndex:(int)index;
+
+// Bookmark item manipulation methods.
+// Returns an array of |BookmarkItemAppleScript*| of all the bookmark items
+// contained within this particular folder.
+- (NSArray*)bookmarkItems;
+
+// Inserts a bookmark item at the end.
+- (void)insertInBookmarkItems:(BookmarkItemAppleScript*)aBookmarkItem;
+
+// Inserts a bookmark item at some position in the list.
+// Called by applescript which takes care of bounds checking, make sure of it
+// before calling directly.
+- (void)insertInBookmarkItems:(BookmarkItemAppleScript*)aBookmarkItem
+ atIndex:(int)index;
+
+// Removes a bookmarks folder from the list.
+// Called by applescript which takes care of bounds checking, make sure of it
+// before calling directly.
+- (void)removeFromBookmarkItemsAtIndex:(int)index;
+
+// Returns the position of a bookmark folder within the current bookmark folder
+// which consists of bookmark folders as well as bookmark items.
+// AppleScript makes sure that there is a bookmark folder before calling this
+// method, make sure of that before calling directly.
+- (int)calculatePositionOfBookmarkFolderAt:(int)index;
+
+// Returns the position of a bookmark item within the current bookmark folder
+// which consists of bookmark folders as well as bookmark items.
+// AppleScript makes sure that there is a bookmark item before calling this
+// method, make sure of that before calling directly.
+- (int)calculatePositionOfBookmarkItemAt:(int)index;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_APPLESCRIPT_BOOKMARK_FOLDER_APPLESCRIPT_H_
diff --git a/chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript.mm b/chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript.mm
new file mode 100644
index 0000000..40d84b2
--- /dev/null
+++ b/chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript.mm
@@ -0,0 +1,204 @@
+// 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 "chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript.h"
+
+#import "base/scoped_nsobject.h"
+#import "base/string16.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#import "chrome/browser/ui/cocoa/applescript/bookmark_item_applescript.h"
+#import "chrome/browser/ui/cocoa/applescript/constants_applescript.h"
+#include "chrome/browser/ui/cocoa/applescript/error_applescript.h"
+#include "googleurl/src/gurl.h"
+
+@implementation BookmarkFolderAppleScript
+
+- (NSArray*)bookmarkFolders {
+ NSMutableArray* bookmarkFolders = [NSMutableArray
+ arrayWithCapacity:bookmarkNode_->GetChildCount()];
+
+ for (int i = 0; i < bookmarkNode_->GetChildCount(); ++i) {
+ const BookmarkNode* node = bookmarkNode_->GetChild(i);
+
+ if (!node->is_folder())
+ continue;
+ scoped_nsobject<BookmarkFolderAppleScript> bookmarkFolder(
+ [[BookmarkFolderAppleScript alloc]
+ initWithBookmarkNode:node]);
+ [bookmarkFolder setContainer:self
+ property:AppleScript::kBookmarkFoldersProperty];
+ [bookmarkFolders addObject:bookmarkFolder];
+ }
+
+ return bookmarkFolders;
+}
+
+- (void)insertInBookmarkFolders:(id)aBookmarkFolder {
+ // This method gets called when a new bookmark folder is created so
+ // the container and property are set here.
+ [aBookmarkFolder setContainer:self
+ property:AppleScript::kBookmarkFoldersProperty];
+ BookmarkModel* model = [self bookmarkModel];
+ if (!model)
+ return;
+
+ const BookmarkNode* node = model->AddGroup(bookmarkNode_,
+ bookmarkNode_->GetChildCount(),
+ string16());
+ if (!node) {
+ AppleScript::SetError(AppleScript::errCreateBookmarkFolder);
+ return;
+ }
+
+ [aBookmarkFolder setBookmarkNode:node];
+}
+
+- (void)insertInBookmarkFolders:(id)aBookmarkFolder atIndex:(int)index {
+ // This method gets called when a new bookmark folder is created so
+ // the container and property are set here.
+ [aBookmarkFolder setContainer:self
+ property:AppleScript::kBookmarkFoldersProperty];
+ int position = [self calculatePositionOfBookmarkFolderAt:index];
+
+ BookmarkModel* model = [self bookmarkModel];
+ if (!model)
+ return;
+
+ const BookmarkNode* node = model->AddGroup(bookmarkNode_,
+ position,
+ string16());
+ if (!node) {
+ AppleScript::SetError(AppleScript::errCreateBookmarkFolder);
+ return;
+ }
+
+ [aBookmarkFolder setBookmarkNode:node];
+}
+
+- (void)removeFromBookmarkFoldersAtIndex:(int)index {
+ int position = [self calculatePositionOfBookmarkFolderAt:index];
+
+ BookmarkModel* model = [self bookmarkModel];
+ if (!model)
+ return;
+
+ model->Remove(bookmarkNode_, position);
+}
+
+- (NSArray*)bookmarkItems {
+ NSMutableArray* bookmarkItems = [NSMutableArray
+ arrayWithCapacity:bookmarkNode_->GetChildCount()];
+
+ for (int i = 0; i < bookmarkNode_->GetChildCount(); ++i) {
+ const BookmarkNode* node = bookmarkNode_->GetChild(i);
+
+ if (!node->is_url())
+ continue;
+ scoped_nsobject<BookmarkFolderAppleScript> bookmarkItem(
+ [[BookmarkItemAppleScript alloc]
+ initWithBookmarkNode:node]);
+ [bookmarkItem setContainer:self
+ property:AppleScript::kBookmarkItemsProperty];
+ [bookmarkItems addObject:bookmarkItem];
+ }
+
+ return bookmarkItems;
+}
+
+- (void)insertInBookmarkItems:(BookmarkItemAppleScript*)aBookmarkItem {
+ // This method gets called when a new bookmark item is created so
+ // the container and property are set here.
+ [aBookmarkItem setContainer:self
+ property:AppleScript::kBookmarkItemsProperty];
+
+ BookmarkModel* model = [self bookmarkModel];
+ if (!model)
+ return;
+
+ GURL url = GURL(base::SysNSStringToUTF8([aBookmarkItem URL]));
+ if (!url.is_valid()) {
+ AppleScript::SetError(AppleScript::errInvalidURL);
+ return;
+ }
+
+ const BookmarkNode* node = model->AddURL(bookmarkNode_,
+ bookmarkNode_->GetChildCount(),
+ string16(),
+ url);
+ if (!node) {
+ AppleScript::SetError(AppleScript::errCreateBookmarkItem);
+ return;
+ }
+
+ [aBookmarkItem setBookmarkNode:node];
+}
+
+- (void)insertInBookmarkItems:(BookmarkItemAppleScript*)aBookmarkItem
+ atIndex:(int)index {
+ // This method gets called when a new bookmark item is created so
+ // the container and property are set here.
+ [aBookmarkItem setContainer:self
+ property:AppleScript::kBookmarkItemsProperty];
+ int position = [self calculatePositionOfBookmarkItemAt:index];
+
+ BookmarkModel* model = [self bookmarkModel];
+ if (!model)
+ return;
+
+ GURL url(base::SysNSStringToUTF8([aBookmarkItem URL]));
+ if (!url.is_valid()) {
+ AppleScript::SetError(AppleScript::errInvalidURL);
+ return;
+ }
+
+ const BookmarkNode* node = model->AddURL(bookmarkNode_,
+ position,
+ string16(),
+ url);
+ if (!node) {
+ AppleScript::SetError(AppleScript::errCreateBookmarkItem);
+ return;
+ }
+
+ [aBookmarkItem setBookmarkNode:node];
+}
+
+- (void)removeFromBookmarkItemsAtIndex:(int)index {
+ int position = [self calculatePositionOfBookmarkItemAt:index];
+
+ BookmarkModel* model = [self bookmarkModel];
+ if (!model)
+ return;
+
+ model->Remove(bookmarkNode_, position);
+}
+
+- (int)calculatePositionOfBookmarkFolderAt:(int)index {
+ // Traverse through all the child nodes till the required node is found and
+ // return its position.
+ // AppleScript is 1-based therefore index is incremented by 1.
+ ++index;
+ int count = -1;
+ while (index) {
+ if (bookmarkNode_->GetChild(++count)->is_folder())
+ --index;
+ }
+ return count;
+}
+
+- (int)calculatePositionOfBookmarkItemAt:(int)index {
+ // Traverse through all the child nodes till the required node is found and
+ // return its position.
+ // AppleScript is 1-based therefore index is incremented by 1.
+ ++index;
+ int count = -1;
+ while (index) {
+ if (bookmarkNode_->GetChild(++count)->is_url())
+ --index;
+ }
+ return count;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript_unittest.mm b/chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript_unittest.mm
new file mode 100644
index 0000000..fbdbf09
--- /dev/null
+++ b/chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript_unittest.mm
@@ -0,0 +1,200 @@
+// 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 "base/scoped_nsobject.h"
+#include "base/sys_string_conversions.h"
+#import "chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_unittest.h"
+#import "chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript.h"
+#import "chrome/browser/ui/cocoa/applescript/bookmark_item_applescript.h"
+#import "chrome/browser/ui/cocoa/applescript/constants_applescript.h"
+#import "chrome/browser/ui/cocoa/applescript/error_applescript.h"
+#include "googleurl/src/gurl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+typedef BookmarkAppleScriptTest BookmarkFolderAppleScriptTest;
+
+namespace {
+
+// Test all the bookmark folders within.
+TEST_F(BookmarkFolderAppleScriptTest, BookmarkFolders) {
+ NSArray* bookmarkFolders = [bookmarkBar_.get() bookmarkFolders];
+
+ EXPECT_EQ(2U, [bookmarkFolders count]);
+
+ BookmarkFolderAppleScript* f1 = [bookmarkFolders objectAtIndex:0];
+ BookmarkFolderAppleScript* f2 = [bookmarkFolders objectAtIndex:1];
+ EXPECT_NSEQ(@"f1", [f1 title]);
+ EXPECT_NSEQ(@"f2", [f2 title]);
+ EXPECT_EQ(2, [[f1 index] intValue]);
+ EXPECT_EQ(4, [[f2 index] intValue]);
+
+ for (BookmarkFolderAppleScript* bookmarkFolder in bookmarkFolders) {
+ EXPECT_EQ([bookmarkFolder container], bookmarkBar_.get());
+ EXPECT_NSEQ(AppleScript::kBookmarkFoldersProperty,
+ [bookmarkFolder containerProperty]);
+ }
+}
+
+// Insert a new bookmark folder.
+TEST_F(BookmarkFolderAppleScriptTest, InsertBookmarkFolder) {
+ // Emulate what applescript would do when inserting a new bookmark folder.
+ // Emulates a script like |set var to make new bookmark folder with
+ // properties {title:"foo"}|.
+ scoped_nsobject<BookmarkFolderAppleScript> bookmarkFolder(
+ [[BookmarkFolderAppleScript alloc] init]);
+ scoped_nsobject<NSNumber> var([[bookmarkFolder.get() uniqueID] copy]);
+ [bookmarkFolder.get() setTitle:@"foo"];
+ [bookmarkBar_.get() insertInBookmarkFolders:bookmarkFolder.get()];
+
+ // Represents the bookmark folder after its added.
+ BookmarkFolderAppleScript* bf =
+ [[bookmarkBar_.get() bookmarkFolders] objectAtIndex:2];
+ EXPECT_NSEQ(@"foo", [bf title]);
+ EXPECT_EQ([bf container], bookmarkBar_.get());
+ EXPECT_NSEQ(AppleScript::kBookmarkFoldersProperty,
+ [bf containerProperty]);
+ EXPECT_NSEQ(var.get(), [bf uniqueID]);
+}
+
+// Insert a new bookmark folder at a particular position.
+TEST_F(BookmarkFolderAppleScriptTest, InsertBookmarkFolderAtPosition) {
+ // Emulate what applescript would do when inserting a new bookmark folder.
+ // Emulates a script like |set var to make new bookmark folder with
+ // properties {title:"foo"} at after bookmark folder 1|.
+ scoped_nsobject<BookmarkFolderAppleScript> bookmarkFolder(
+ [[BookmarkFolderAppleScript alloc] init]);
+ scoped_nsobject<NSNumber> var([[bookmarkFolder.get() uniqueID] copy]);
+ [bookmarkFolder.get() setTitle:@"foo"];
+ [bookmarkBar_.get() insertInBookmarkFolders:bookmarkFolder.get() atIndex:1];
+
+ // Represents the bookmark folder after its added.
+ BookmarkFolderAppleScript* bf =
+ [[bookmarkBar_.get() bookmarkFolders] objectAtIndex:1];
+ EXPECT_NSEQ(@"foo", [bf title]);
+ EXPECT_EQ([bf container], bookmarkBar_.get());
+ EXPECT_NSEQ(AppleScript::kBookmarkFoldersProperty, [bf containerProperty]);
+ EXPECT_NSEQ(var.get(), [bf uniqueID]);
+}
+
+// Delete bookmark folders.
+TEST_F(BookmarkFolderAppleScriptTest, DeleteBookmarkFolders) {
+ unsigned int folderCount = 2, itemCount = 3;
+ for (unsigned int i = 0; i < folderCount; ++i) {
+ EXPECT_EQ(folderCount - i, [[bookmarkBar_.get() bookmarkFolders] count]);
+ EXPECT_EQ(itemCount, [[bookmarkBar_.get() bookmarkItems] count]);
+ [bookmarkBar_.get() removeFromBookmarkFoldersAtIndex:0];
+ }
+}
+
+// Test all the bookmark items within.
+TEST_F(BookmarkFolderAppleScriptTest, BookmarkItems) {
+ NSArray* bookmarkItems = [bookmarkBar_.get() bookmarkItems];
+
+ EXPECT_EQ(3U, [bookmarkItems count]);
+
+ BookmarkItemAppleScript* i1 = [bookmarkItems objectAtIndex:0];
+ BookmarkItemAppleScript* i2 = [bookmarkItems objectAtIndex:1];
+ BookmarkItemAppleScript* i3 = [bookmarkItems objectAtIndex:2];
+ EXPECT_NSEQ(@"a", [i1 title]);
+ EXPECT_NSEQ(@"d", [i2 title]);
+ EXPECT_NSEQ(@"h", [i3 title]);
+ EXPECT_EQ(1, [[i1 index] intValue]);
+ EXPECT_EQ(3, [[i2 index] intValue]);
+ EXPECT_EQ(5, [[i3 index] intValue]);
+
+ for (BookmarkItemAppleScript* bookmarkItem in bookmarkItems) {
+ EXPECT_EQ([bookmarkItem container], bookmarkBar_.get());
+ EXPECT_NSEQ(AppleScript::kBookmarkItemsProperty,
+ [bookmarkItem containerProperty]);
+ }
+}
+
+// Insert a new bookmark item.
+TEST_F(BookmarkFolderAppleScriptTest, InsertBookmarkItem) {
+ // Emulate what applescript would do when inserting a new bookmark folder.
+ // Emulates a script like |set var to make new bookmark item with
+ // properties {title:"Google", URL:"http://google.com"}|.
+ scoped_nsobject<BookmarkItemAppleScript> bookmarkItem(
+ [[BookmarkItemAppleScript alloc] init]);
+ scoped_nsobject<NSNumber> var([[bookmarkItem.get() uniqueID] copy]);
+ [bookmarkItem.get() setTitle:@"Google"];
+ [bookmarkItem.get() setURL:@"http://google.com"];
+ [bookmarkBar_.get() insertInBookmarkItems:bookmarkItem.get()];
+
+ // Represents the bookmark item after its added.
+ BookmarkItemAppleScript* bi =
+ [[bookmarkBar_.get() bookmarkItems] objectAtIndex:3];
+ EXPECT_NSEQ(@"Google", [bi title]);
+ EXPECT_EQ(GURL("http://google.com/"),
+ GURL(base::SysNSStringToUTF8([bi URL])));
+ EXPECT_EQ([bi container], bookmarkBar_.get());
+ EXPECT_NSEQ(AppleScript::kBookmarkItemsProperty, [bi containerProperty]);
+ EXPECT_NSEQ(var.get(), [bi uniqueID]);
+
+ // Test to see no bookmark item is created when no/invlid URL is entered.
+ scoped_nsobject<FakeScriptCommand> fakeScriptCommand(
+ [[FakeScriptCommand alloc] init]);
+ bookmarkItem.reset([[BookmarkItemAppleScript alloc] init]);
+ [bookmarkBar_.get() insertInBookmarkItems:bookmarkItem.get()];
+ EXPECT_EQ((int)AppleScript::errInvalidURL,
+ [fakeScriptCommand.get() scriptErrorNumber]);
+}
+
+// Insert a new bookmark item at a particular position.
+TEST_F(BookmarkFolderAppleScriptTest, InsertBookmarkItemAtPosition) {
+ // Emulate what applescript would do when inserting a new bookmark item.
+ // Emulates a script like |set var to make new bookmark item with
+ // properties {title:"XKCD", URL:"http://xkcd.org}
+ // at after bookmark item 1|.
+ scoped_nsobject<BookmarkItemAppleScript> bookmarkItem(
+ [[BookmarkItemAppleScript alloc] init]);
+ scoped_nsobject<NSNumber> var([[bookmarkItem.get() uniqueID] copy]);
+ [bookmarkItem.get() setTitle:@"XKCD"];
+ [bookmarkItem.get() setURL:@"http://xkcd.org"];
+
+ [bookmarkBar_.get() insertInBookmarkItems:bookmarkItem.get() atIndex:1];
+
+ // Represents the bookmark item after its added.
+ BookmarkItemAppleScript* bi =
+ [[bookmarkBar_.get() bookmarkItems] objectAtIndex:1];
+ EXPECT_NSEQ(@"XKCD", [bi title]);
+ EXPECT_EQ(GURL("http://xkcd.org/"),
+ GURL(base::SysNSStringToUTF8([bi URL])));
+ EXPECT_EQ([bi container], bookmarkBar_.get());
+ EXPECT_NSEQ(AppleScript::kBookmarkItemsProperty,
+ [bi containerProperty]);
+ EXPECT_NSEQ(var.get(), [bi uniqueID]);
+
+ // Test to see no bookmark item is created when no/invlid URL is entered.
+ scoped_nsobject<FakeScriptCommand> fakeScriptCommand(
+ [[FakeScriptCommand alloc] init]);
+ bookmarkItem.reset([[BookmarkItemAppleScript alloc] init]);
+ [bookmarkBar_.get() insertInBookmarkItems:bookmarkItem.get() atIndex:1];
+ EXPECT_EQ((int)AppleScript::errInvalidURL,
+ [fakeScriptCommand.get() scriptErrorNumber]);
+}
+
+// Delete bookmark items.
+TEST_F(BookmarkFolderAppleScriptTest, DeleteBookmarkItems) {
+ unsigned int folderCount = 2, itemCount = 3;
+ for (unsigned int i = 0; i < itemCount; ++i) {
+ EXPECT_EQ(folderCount, [[bookmarkBar_.get() bookmarkFolders] count]);
+ EXPECT_EQ(itemCount - i, [[bookmarkBar_.get() bookmarkItems] count]);
+ [bookmarkBar_.get() removeFromBookmarkItemsAtIndex:0];
+ }
+}
+
+// Set and get title.
+TEST_F(BookmarkFolderAppleScriptTest, GetAndSetTitle) {
+ NSArray* bookmarkFolders = [bookmarkBar_.get() bookmarkFolders];
+ BookmarkFolderAppleScript* folder1 = [bookmarkFolders objectAtIndex:0];
+ [folder1 setTitle:@"Foo"];
+ EXPECT_NSEQ(@"Foo", [folder1 title]);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/applescript/bookmark_item_applescript.h b/chrome/browser/ui/cocoa/applescript/bookmark_item_applescript.h
new file mode 100644
index 0000000..b84365d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/applescript/bookmark_item_applescript.h
@@ -0,0 +1,33 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_APPLESCRIPT_BOOKMARK_ITEM_APPLESCRIPT_H_
+#define CHROME_BROWSER_UI_COCOA_APPLESCRIPT_BOOKMARK_ITEM_APPLESCRIPT_H_
+
+#import <Cocoa/Cocoa.h>
+
+#import "chrome/browser/ui/cocoa/applescript/bookmark_node_applescript.h"
+
+// Represents a bookmark item scriptable object in applescript.
+@interface BookmarkItemAppleScript : BookmarkNodeAppleScript {
+ @private
+ // Contains the temporary title when a user creates a new item with
+ // title specified like
+ // |make new bookmarks item with properties {title:"foo"}|.
+ NSString* tempURL_;
+}
+
+// Assigns a node, sets its unique ID and also copies temporary values.
+- (void)setBookmarkNode:(const BookmarkNode*)aBookmarkNode;
+
+// Returns the URL that the bookmark item holds.
+- (NSString*)URL;
+
+// Sets the URL of the bookmark item, displays error in applescript console
+// if URL is invalid.
+- (void)setURL:(NSString*)aURL;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_APPLESCRIPT_BOOKMARK_ITEM_APPLESCRIPT_H_
diff --git a/chrome/browser/ui/cocoa/applescript/bookmark_item_applescript.mm b/chrome/browser/ui/cocoa/applescript/bookmark_item_applescript.mm
new file mode 100644
index 0000000..f077552
--- /dev/null
+++ b/chrome/browser/ui/cocoa/applescript/bookmark_item_applescript.mm
@@ -0,0 +1,66 @@
+// 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 "chrome/browser/ui/cocoa/applescript/bookmark_item_applescript.h"
+
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#import "chrome/browser/ui/cocoa/applescript/error_applescript.h"
+
+@interface BookmarkItemAppleScript()
+@property (nonatomic, copy) NSString* tempURL;
+@end
+
+@implementation BookmarkItemAppleScript
+
+@synthesize tempURL = tempURL_;
+
+- (id)init {
+ if ((self = [super init])) {
+ [self setTempURL:@""];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [tempURL_ release];
+ [super dealloc];
+}
+
+- (void)setBookmarkNode:(const BookmarkNode*)aBookmarkNode {
+ [super setBookmarkNode:aBookmarkNode];
+ [self setURL:[self tempURL]];
+}
+
+- (NSString*)URL {
+ if (!bookmarkNode_)
+ return tempURL_;
+
+ const GURL& url = bookmarkNode_->GetURL();
+ return base::SysUTF8ToNSString(url.spec());
+}
+
+- (void)setURL:(NSString*)aURL {
+ // If a scripter sets a URL before the node is added, URL is saved at a
+ // temporary location.
+ if (!bookmarkNode_) {
+ [self setTempURL:aURL];
+ return;
+ }
+
+ BookmarkModel* model = [self bookmarkModel];
+ if (!model)
+ return;
+
+ GURL url(base::SysNSStringToUTF8(aURL));
+ if (!url.is_valid()) {
+ AppleScript::SetError(AppleScript::errInvalidURL);
+ return;
+ }
+
+ model->SetURL(bookmarkNode_, url);
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/applescript/bookmark_item_applescript_unittest.mm b/chrome/browser/ui/cocoa/applescript/bookmark_item_applescript_unittest.mm
new file mode 100644
index 0000000..2cd5a94
--- /dev/null
+++ b/chrome/browser/ui/cocoa/applescript/bookmark_item_applescript_unittest.mm
@@ -0,0 +1,45 @@
+// 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 "base/scoped_nsobject.h"
+#include "base/sys_string_conversions.h"
+#import "chrome/browser/ui/cocoa/applescript/bookmark_applescript_utils_unittest.h"
+#import "chrome/browser/ui/cocoa/applescript/bookmark_item_applescript.h"
+#import "chrome/browser/ui/cocoa/applescript/error_applescript.h"
+#include "googleurl/src/gurl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+typedef BookmarkAppleScriptTest BookmarkItemAppleScriptTest;
+
+namespace {
+
+// Set and get title.
+TEST_F(BookmarkItemAppleScriptTest, GetAndSetTitle) {
+ NSArray* bookmarkItems = [bookmarkBar_.get() bookmarkItems];
+ BookmarkItemAppleScript* item1 = [bookmarkItems objectAtIndex:0];
+ [item1 setTitle:@"Foo"];
+ EXPECT_NSEQ(@"Foo", [item1 title]);
+}
+
+// Set and get URL.
+TEST_F(BookmarkItemAppleScriptTest, GetAndSetURL) {
+ NSArray* bookmarkItems = [bookmarkBar_.get() bookmarkItems];
+ BookmarkItemAppleScript* item1 = [bookmarkItems objectAtIndex:0];
+ [item1 setURL:@"http://foo-bar.org"];
+ EXPECT_EQ(GURL("http://foo-bar.org"),
+ GURL(base::SysNSStringToUTF8([item1 URL])));
+
+ // If scripter enters invalid URL.
+ scoped_nsobject<FakeScriptCommand> fakeScriptCommand(
+ [[FakeScriptCommand alloc] init]);
+ [item1 setURL:@"invalid-url.org"];
+ EXPECT_EQ((int)AppleScript::errInvalidURL,
+ [fakeScriptCommand.get() scriptErrorNumber]);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/applescript/bookmark_node_applescript.h b/chrome/browser/ui/cocoa/applescript/bookmark_node_applescript.h
new file mode 100644
index 0000000..0f1db68
--- /dev/null
+++ b/chrome/browser/ui/cocoa/applescript/bookmark_node_applescript.h
@@ -0,0 +1,48 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_APPLESCRIPT_BOOKMARK_NODE_APPLESCRIPT_H_
+#define CHROME_BROWSER_UI_COCOA_APPLESCRIPT_BOOKMARK_NODE_APPLESCRIPT_H_
+
+#import <Cocoa/Cocoa.h>
+
+#import "chrome/browser/ui/cocoa/applescript/element_applescript.h"
+
+class BookmarkModel;
+class BookmarkNode;
+
+// Contains all the elements that are common to both a bookmark folder and
+// bookmark item.
+@interface BookmarkNodeAppleScript : ElementAppleScript {
+ @protected
+ const BookmarkNode* bookmarkNode_; // weak.
+ // Contains the temporary title when a scripter creates a new folder/item with
+ // title specified like
+ // |make new bookmark folder with properties {title:"foo"}|.
+ NSString* tempTitle_;
+}
+
+// Does not actually create a folder/item but just sets its ID, the folder is
+// created in insertInBookmarksFolder: in the corresponding bookmarks folder.
+- (id)init;
+
+// Does not make a folder/item but instead uses an existing one.
+- (id)initWithBookmarkNode:(const BookmarkNode*)aBookmarkNode;
+
+// Assigns a node, sets its unique ID and also copies temporary values.
+- (void)setBookmarkNode:(const BookmarkNode*)aBookmarkNode;
+
+// Get and Set title.
+- (NSString*)title;
+- (void)setTitle:(NSString*)aTitle;
+
+// Returns the index with respect to its parent bookmark folder.
+- (NSNumber*)index;
+
+// Returns the bookmark model of the browser, returns NULL if there is an error.
+- (BookmarkModel*)bookmarkModel;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_APPLESCRIPT_BOOKMARK_NODE_APPLESCRIPT_H_
diff --git a/chrome/browser/ui/cocoa/applescript/bookmark_node_applescript.mm b/chrome/browser/ui/cocoa/applescript/bookmark_node_applescript.mm
new file mode 100644
index 0000000..3dabbbe
--- /dev/null
+++ b/chrome/browser/ui/cocoa/applescript/bookmark_node_applescript.mm
@@ -0,0 +1,130 @@
+// 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 "chrome/browser/ui/cocoa/applescript/bookmark_node_applescript.h"
+
+#include "base/logging.h"
+#include "base/sys_string_conversions.h"
+#import "base/scoped_nsobject.h"
+#import "chrome/browser/app_controller_mac.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#import "chrome/browser/chrome_browser_application_mac.h"
+#include "chrome/browser/profiles/profile.h"
+#import "chrome/browser/ui/cocoa/applescript/bookmark_item_applescript.h"
+#import "chrome/browser/ui/cocoa/applescript/error_applescript.h"
+
+@interface BookmarkNodeAppleScript()
+@property (nonatomic, copy) NSString* tempTitle;
+@end
+
+@implementation BookmarkNodeAppleScript
+
+@synthesize tempTitle = tempTitle_;
+
+- (id)init {
+ if ((self = [super init])) {
+ BookmarkModel* model = [self bookmarkModel];
+ if (!model) {
+ [self release];
+ return nil;
+ }
+
+ scoped_nsobject<NSNumber> numID(
+ [[NSNumber alloc] initWithLongLong:model->next_node_id()]);
+ [self setUniqueID:numID];
+ [self setTempTitle:@""];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [tempTitle_ release];
+ [super dealloc];
+}
+
+
+- (id)initWithBookmarkNode:(const BookmarkNode*)aBookmarkNode {
+ if (!aBookmarkNode) {
+ [self release];
+ return nil;
+ }
+
+ if ((self = [super init])) {
+ // It is safe to be weak, if a bookmark item/folder goes away
+ // (eg user deleting a folder) the applescript runtime calls
+ // bookmarkFolders/bookmarkItems in BookmarkFolderAppleScript
+ // and this particular bookmark item/folder is never returned.
+ bookmarkNode_ = aBookmarkNode;
+
+ scoped_nsobject<NSNumber> numID(
+ [[NSNumber alloc] initWithLongLong:aBookmarkNode->id()]);
+ [self setUniqueID:numID];
+ }
+ return self;
+}
+
+- (void)setBookmarkNode:(const BookmarkNode*)aBookmarkNode {
+ DCHECK(aBookmarkNode);
+ // It is safe to be weak, if a bookmark item/folder goes away
+ // (eg user deleting a folder) the applescript runtime calls
+ // bookmarkFolders/bookmarkItems in BookmarkFolderAppleScript
+ // and this particular bookmark item/folder is never returned.
+ bookmarkNode_ = aBookmarkNode;
+
+ scoped_nsobject<NSNumber> numID(
+ [[NSNumber alloc] initWithLongLong:aBookmarkNode->id()]);
+ [self setUniqueID:numID];
+
+ [self setTitle:[self tempTitle]];
+}
+
+- (NSString*)title {
+ if (!bookmarkNode_)
+ return tempTitle_;
+
+ return base::SysUTF16ToNSString(bookmarkNode_->GetTitle());
+}
+
+- (void)setTitle:(NSString*)aTitle {
+ // If the scripter enters |make new bookmarks folder with properties
+ // {title:"foo"}|, the node has not yet been created so title is stored in the
+ // temp title.
+ if (!bookmarkNode_) {
+ [self setTempTitle:aTitle];
+ return;
+ }
+
+ BookmarkModel* model = [self bookmarkModel];
+ if (!model)
+ return;
+
+ model->SetTitle(bookmarkNode_, base::SysNSStringToUTF16(aTitle));
+}
+
+- (NSNumber*)index {
+ const BookmarkNode* parent = bookmarkNode_->GetParent();
+ int index = parent->IndexOfChild(bookmarkNode_);
+ // NOTE: AppleScript is 1-Based.
+ return [NSNumber numberWithInt:index+1];
+}
+
+- (BookmarkModel*)bookmarkModel {
+ AppController* appDelegate = [NSApp delegate];
+
+ Profile* defaultProfile = [appDelegate defaultProfile];
+ if (!defaultProfile) {
+ AppleScript::SetError(AppleScript::errGetProfile);
+ return NULL;
+ }
+
+ BookmarkModel* model = defaultProfile->GetBookmarkModel();
+ if (!model->IsLoaded()) {
+ AppleScript::SetError(AppleScript::errBookmarkModelLoad);
+ return NULL;
+ }
+
+ return model;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript.h b/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript.h
new file mode 100644
index 0000000..795d198
--- /dev/null
+++ b/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript.h
@@ -0,0 +1,59 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_APPLESCRIPT_BROWSERCRAPPLICATION_APPLESCRIPT_H_
+#define CHROME_BROWSER_UI_COCOA_APPLESCRIPT_BROWSERCRAPPLICATION_APPLESCRIPT_H_
+
+#import <Cocoa/Cocoa.h>
+
+#import "chrome/browser/chrome_browser_application_mac.h"
+
+@class BookmarkFolderAppleScript;
+@class WindowAppleScript;
+
+// Represent the top level application scripting object in applescript.
+@interface BrowserCrApplication (AppleScriptAdditions)
+
+// Application window manipulation methods.
+// Returns an array of |WindowAppleScript*| of all windows present in the
+// application.
+- (NSArray*)appleScriptWindows;
+
+// Inserts a window at the beginning.
+- (void)insertInAppleScriptWindows:(WindowAppleScript*)aWindow;
+
+// Inserts a window at some position in the list.
+// Called by applescript which takes care of bounds checking, make sure of it
+// before calling directly.
+- (void)insertInAppleScriptWindows:(WindowAppleScript*)aWindow
+ atIndex:(int)index;
+
+// Removes a window from the list.
+// Called by applescript which takes care of bounds checking, make sure of it
+// before calling directly.
+- (void)removeFromAppleScriptWindowsAtIndex:(int)index;
+
+// Always returns nil to indicate that it is the root container object.
+- (NSScriptObjectSpecifier*)objectSpecifier;
+
+// Returns the other bookmarks bookmark folder,
+// returns nil if there is an error.
+- (BookmarkFolderAppleScript*)otherBookmarks;
+
+// Returns the bookmarks bar bookmark folder, return nil if there is an error.
+- (BookmarkFolderAppleScript*)bookmarksBar;
+
+// Returns the Bookmarks Bar and Other Bookmarks Folders, each is of type
+// |BookmarkFolderAppleScript*|.
+- (NSArray*)bookmarkFolders;
+
+// Required functions, even though bookmarkFolders is declared as
+// read-only, cocoa scripting does not currently prevent writing.
+- (void)insertInBookmarksFolders:(id)aBookmarkFolder;
+- (void)insertInBookmarksFolders:(id)aBookmarkFolder atIndex:(int)index;
+- (void)removeFromBookmarksFoldersAtIndex:(int)index;
+
+@end
+
+#endif// CHROME_BROWSER_UI_COCOA_APPLESCRIPT_BROWSERCRAPPLICATION_APPLESCRIPT_H_
diff --git a/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript.mm b/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript.mm
new file mode 100644
index 0000000..c8659b7
--- /dev/null
+++ b/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript.mm
@@ -0,0 +1,136 @@
+// 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 "chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript.h"
+
+#include "base/logging.h"
+#import "base/scoped_nsobject.h"
+#import "chrome/browser/app_controller_mac.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/profiles/profile.h"
+#import "chrome/browser/ui/cocoa/applescript/bookmark_folder_applescript.h"
+#import "chrome/browser/ui/cocoa/applescript/constants_applescript.h"
+#import "chrome/browser/ui/cocoa/applescript/error_applescript.h"
+#import "chrome/browser/ui/cocoa/applescript/window_applescript.h"
+
+@implementation BrowserCrApplication (AppleScriptAdditions)
+
+- (NSArray*)appleScriptWindows {
+ NSMutableArray* appleScriptWindows = [NSMutableArray
+ arrayWithCapacity:BrowserList::size()];
+ // Iterate through all browsers and check if it closing,
+ // if not add it to list.
+ for (BrowserList::const_iterator browserIterator = BrowserList::begin();
+ browserIterator != BrowserList::end(); ++browserIterator) {
+ if ((*browserIterator)->IsAttemptingToCloseBrowser())
+ continue;
+
+ scoped_nsobject<WindowAppleScript> window(
+ [[WindowAppleScript alloc] initWithBrowser:*browserIterator]);
+ [window setContainer:NSApp
+ property:AppleScript::kWindowsProperty];
+ [appleScriptWindows addObject:window];
+ }
+ // Windows sorted by their index value, which is obtained by calling
+ // orderedIndex: on each window.
+ [appleScriptWindows sortUsingSelector:@selector(windowComparator:)];
+ return appleScriptWindows;
+}
+
+- (void)insertInAppleScriptWindows:(WindowAppleScript*)aWindow {
+ // This method gets called when a new window is created so
+ // the container and property are set here.
+ [aWindow setContainer:self
+ property:AppleScript::kWindowsProperty];
+}
+
+- (void)insertInAppleScriptWindows:(WindowAppleScript*)aWindow
+ atIndex:(int)index {
+ // This method gets called when a new window is created so
+ // the container and property are set here.
+ [aWindow setContainer:self
+ property:AppleScript::kWindowsProperty];
+ // Note: AppleScript is 1-based.
+ index--;
+ [aWindow setOrderedIndex:[NSNumber numberWithInt:index]];
+}
+
+- (void)removeFromAppleScriptWindowsAtIndex:(int)index {
+ [[[self appleScriptWindows] objectAtIndex:index]
+ handlesCloseScriptCommand:nil];
+}
+
+- (NSScriptObjectSpecifier*)objectSpecifier {
+ return nil;
+}
+
+- (BookmarkFolderAppleScript*)otherBookmarks {
+ AppController* appDelegate = [NSApp delegate];
+
+ Profile* defaultProfile = [appDelegate defaultProfile];
+ if (!defaultProfile) {
+ AppleScript::SetError(AppleScript::errGetProfile);
+ return nil;
+ }
+
+ BookmarkModel* model = defaultProfile->GetBookmarkModel();
+ if (!model->IsLoaded()) {
+ AppleScript::SetError(AppleScript::errBookmarkModelLoad);
+ return nil;
+ }
+
+ BookmarkFolderAppleScript* otherBookmarks =
+ [[[BookmarkFolderAppleScript alloc]
+ initWithBookmarkNode:model->other_node()] autorelease];
+ [otherBookmarks setContainer:self
+ property:AppleScript::kBookmarkFoldersProperty];
+ return otherBookmarks;
+}
+
+- (BookmarkFolderAppleScript*)bookmarksBar {
+ AppController* appDelegate = [NSApp delegate];
+
+ Profile* defaultProfile = [appDelegate defaultProfile];
+ if (!defaultProfile) {
+ AppleScript::SetError(AppleScript::errGetProfile);
+ return nil;
+ }
+
+ BookmarkModel* model = defaultProfile->GetBookmarkModel();
+ if (!model->IsLoaded()) {
+ AppleScript::SetError(AppleScript::errBookmarkModelLoad);
+ return NULL;
+ }
+
+ BookmarkFolderAppleScript* bookmarksBar =
+ [[[BookmarkFolderAppleScript alloc]
+ initWithBookmarkNode:model->GetBookmarkBarNode()] autorelease];
+ [bookmarksBar setContainer:self
+ property:AppleScript::kBookmarkFoldersProperty];
+ return bookmarksBar;
+}
+
+- (NSArray*)bookmarkFolders {
+ BookmarkFolderAppleScript* otherBookmarks = [self otherBookmarks];
+ BookmarkFolderAppleScript* bookmarksBar = [self bookmarksBar];
+ NSArray* folderArray = [NSArray arrayWithObjects:otherBookmarks,
+ bookmarksBar,
+ nil];
+ return folderArray;
+}
+
+- (void)insertInBookmarksFolders:(id)aBookmarkFolder {
+ NOTIMPLEMENTED();
+}
+
+- (void)insertInBookmarksFolders:(id)aBookmarkFolder atIndex:(int)index {
+ NOTIMPLEMENTED();
+}
+
+- (void)removeFromBookmarksFoldersAtIndex:(int)index {
+ NOTIMPLEMENTED();
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript_test.mm b/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript_test.mm
new file mode 100644
index 0000000..31af858
--- /dev/null
+++ b/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript_test.mm
@@ -0,0 +1,107 @@
+// 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 "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#import "chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript.h"
+#import "chrome/browser/ui/cocoa/applescript/constants_applescript.h"
+#import "chrome/browser/ui/cocoa/applescript/window_applescript.h"
+#include "chrome/test/in_process_browser_test.h"
+#include "gfx/size.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gtest_mac.h"
+
+typedef InProcessBrowserTest BrowserCrApplicationAppleScriptTest;
+
+// Create windows of different |Type|.
+IN_PROC_BROWSER_TEST_F(BrowserCrApplicationAppleScriptTest, Creation) {
+ // Create additional |Browser*| objects of different type.
+ Profile* profile = browser()->profile();
+ Browser* b1 = Browser::CreateForType(Browser::TYPE_POPUP, profile);
+ Browser* b2 = Browser::CreateForApp("", gfx::Size(), profile, true);
+ Browser* b3 = Browser::CreateForApp("", gfx::Size(), profile, false);
+
+ EXPECT_EQ(4U, [[NSApp appleScriptWindows] count]);
+ for (WindowAppleScript* window in [NSApp appleScriptWindows]) {
+ EXPECT_NSEQ(AppleScript::kWindowsProperty,
+ [window containerProperty]);
+ EXPECT_NSEQ(NSApp, [window container]);
+ }
+
+ // Close the additional browsers.
+ b1->CloseAllTabs();
+ b2->CloseAllTabs();
+ b3->CloseAllTabs();
+}
+
+// Insert a new window.
+IN_PROC_BROWSER_TEST_F(BrowserCrApplicationAppleScriptTest, InsertWindow) {
+ // Emulate what applescript would do when creating a new window.
+ // Emulate a script like |set var to make new window with properties
+ // {visible:false}|.
+ scoped_nsobject<WindowAppleScript> aWindow([[WindowAppleScript alloc] init]);
+ scoped_nsobject<NSNumber> var([[aWindow.get() uniqueID] copy]);
+ [aWindow.get() setValue:[NSNumber numberWithBool:YES] forKey:@"isVisible"];
+
+ [NSApp insertInAppleScriptWindows:aWindow.get()];
+
+ // Represents the window after it is added.
+ WindowAppleScript* window = [[NSApp appleScriptWindows] objectAtIndex:0];
+ EXPECT_NSEQ([NSNumber numberWithBool:YES],
+ [aWindow.get() valueForKey:@"isVisible"]);
+ EXPECT_EQ([window container], NSApp);
+ EXPECT_NSEQ(AppleScript::kWindowsProperty,
+ [window containerProperty]);
+ EXPECT_NSEQ(var, [window uniqueID]);
+}
+
+// Inserting and deleting windows.
+IN_PROC_BROWSER_TEST_F(BrowserCrApplicationAppleScriptTest,
+ InsertAndDeleteWindows) {
+ scoped_nsobject<WindowAppleScript> aWindow;
+ int count;
+ // Create a bunch of windows.
+ for (int i = 0; i < 5; ++i) {
+ for (int j = 0; j < 3; ++j) {
+ aWindow.reset([[WindowAppleScript alloc] init]);
+ [NSApp insertInAppleScriptWindows:aWindow.get()];
+ }
+ count = 3 * i + 4;
+ EXPECT_EQ(count, (int)[[NSApp appleScriptWindows] count]);
+ }
+
+ // Remove all the windows, just created.
+ count = (int)[[NSApp appleScriptWindows] count];
+ for (int i = 0; i < 5; ++i) {
+ for(int j = 0; j < 3; ++j) {
+ [NSApp removeFromAppleScriptWindowsAtIndex:0];
+ }
+ count = count - 3;
+ EXPECT_EQ(count, (int)[[NSApp appleScriptWindows] count]);
+ }
+}
+
+// Check for objectSpecifer of the root scripting object.
+IN_PROC_BROWSER_TEST_F(BrowserCrApplicationAppleScriptTest, ObjectSpecifier) {
+ // Should always return nil to indicate its the root scripting object.
+ EXPECT_EQ(nil, [NSApp objectSpecifier]);
+}
+
+// Bookmark folders at the root level.
+IN_PROC_BROWSER_TEST_F(BrowserCrApplicationAppleScriptTest, BookmarkFolders) {
+ NSArray* bookmarkFolders = [NSApp bookmarkFolders];
+ EXPECT_EQ(2U, [bookmarkFolders count]);
+
+ for (BookmarkFolderAppleScript* bookmarkFolder in bookmarkFolders) {
+ EXPECT_EQ(NSApp,
+ [bookmarkFolder container]);
+ EXPECT_NSEQ(AppleScript::kBookmarkFoldersProperty,
+ [bookmarkFolder containerProperty]);
+ }
+
+ EXPECT_NSEQ(@"Other Bookmarks", [[NSApp otherBookmarks] title]);
+ EXPECT_NSEQ(@"Bookmarks Bar", [[NSApp bookmarksBar] title]);
+}
diff --git a/chrome/browser/ui/cocoa/applescript/constants_applescript.h b/chrome/browser/ui/cocoa/applescript/constants_applescript.h
new file mode 100644
index 0000000..7ffa80e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/applescript/constants_applescript.h
@@ -0,0 +1,31 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_APPLESCRIPT_CONSTANTS_APPLESCRIPT_H_
+#define CHROME_BROWSER_UI_COCOA_APPLESCRIPT_CONSTANTS_APPLESCRIPT_H_
+
+#import <Cocoa/Cocoa.h>
+
+// This file contains the constant that are use to set the property of an
+// applescript scriptable item.
+namespace AppleScript {
+// Property to access windows.
+extern NSString* const kWindowsProperty;
+
+// Property to access tabs.
+extern NSString* const kTabsProperty;
+
+// Property to access bookmarks folders.
+extern NSString* const kBookmarkFoldersProperty;
+
+// Property to access bookmark items.
+extern NSString* const kBookmarkItemsProperty;
+
+// To indicate a window in normal mode.
+extern NSString* const kNormalWindowMode;
+
+// To indicate a window in incognito mode.
+extern NSString* const kIncognitoWindowMode;
+}
+#endif // CHROME_BROWSER_UI_COCOA_APPLESCRIPT_CONSTANTS_APPLESCRIPT_H_
diff --git a/chrome/browser/ui/cocoa/applescript/constants_applescript.mm b/chrome/browser/ui/cocoa/applescript/constants_applescript.mm
new file mode 100644
index 0000000..090077b
--- /dev/null
+++ b/chrome/browser/ui/cocoa/applescript/constants_applescript.mm
@@ -0,0 +1,25 @@
+// 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 "chrome/browser/ui/cocoa/applescript/constants_applescript.h"
+
+namespace AppleScript {
+// Property to access windows.
+NSString* const kWindowsProperty = @"appleScriptWindows";
+
+// Property to access tabs.
+NSString* const kTabsProperty = @"tabs";
+
+// Property to access bookmarks folders.
+NSString* const kBookmarkFoldersProperty = @"bookmarkFolders";
+
+// Property to access bookmark items.
+NSString* const kBookmarkItemsProperty = @"bookmarkItems";
+
+// To indicate a window in normal mode.
+NSString* const kNormalWindowMode = @"normal";
+
+// To indicate a window in incognito mode.
+NSString* const kIncognitoWindowMode = @"incognito";
+}
diff --git a/chrome/browser/ui/cocoa/applescript/element_applescript.h b/chrome/browser/ui/cocoa/applescript/element_applescript.h
new file mode 100644
index 0000000..49a3481
--- /dev/null
+++ b/chrome/browser/ui/cocoa/applescript/element_applescript.h
@@ -0,0 +1,37 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_APPLESCRIPT_ELEMENT_APPLESCRIPT_H_
+#define CHROME_BROWSER_UI_COCOA_APPLESCRIPT_ELEMENT_APPLESCRIPT_H_
+
+#import <Cocoa/Cocoa.h>
+
+// This class is the root class for all the other applescript classes.
+// It takes care of all the infrastructure type operations.
+@interface ElementAppleScript : NSObject {
+ @protected
+ // Used by the applescript runtime to identify each unique scriptable object.
+ NSNumber* uniqueID_;
+ // Used by object specifier to find a scriptable object's place in a
+ // collection.
+ id container_;
+ NSString* containerProperty_;
+}
+
+@property (nonatomic, copy) NSNumber* uniqueID;
+@property (nonatomic, retain) id container;
+@property (nonatomic, copy) NSString* containerProperty;
+
+// Calculates the objectspecifier by using the uniqueID, container and
+// container property.
+// An object specifier is used to identify objects within a
+// collection.
+- (NSScriptObjectSpecifier*)objectSpecifier;
+
+// Sets both container and property, retains container and copies property.
+- (void)setContainer:(id)value property:(NSString*)property;
+
+@end
+
+#endif// CHROME_BROWSER_UI_COCOA_APPLESCRIPT_ELEMENT_APPLESCRIPT_H_
diff --git a/chrome/browser/ui/cocoa/applescript/element_applescript.mm b/chrome/browser/ui/cocoa/applescript/element_applescript.mm
new file mode 100644
index 0000000..abaf01d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/applescript/element_applescript.mm
@@ -0,0 +1,38 @@
+// 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 "chrome/browser/ui/cocoa/applescript/element_applescript.h"
+
+@implementation ElementAppleScript
+
+@synthesize uniqueID = uniqueID_;
+@synthesize container = container_;
+@synthesize containerProperty = containerProperty_;
+
+// calling objectSpecifier asks an object to return an object specifier
+// record referring to itself. You must call setContainer:property: before
+// you can call this method.
+- (NSScriptObjectSpecifier*)objectSpecifier {
+ return [[NSUniqueIDSpecifier allocWithZone:[self zone]]
+ initWithContainerClassDescription:
+ (NSScriptClassDescription*)[[self container] classDescription]
+ containerSpecifier:
+ [[self container] objectSpecifier]
+ key:[self containerProperty]
+ uniqueID:[self uniqueID]];
+}
+
+- (void)setContainer:(id)value property:(NSString*)property {
+ [self setContainer:value];
+ [self setContainerProperty:property];
+}
+
+- (void)dealloc {
+ [uniqueID_ release];
+ [container_ release];
+ [containerProperty_ release];
+ [super dealloc];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/applescript/error_applescript.h b/chrome/browser/ui/cocoa/applescript/error_applescript.h
new file mode 100644
index 0000000..2b91a2c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/applescript/error_applescript.h
@@ -0,0 +1,41 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_APPLESCRIPT_ERROR_APPLESCRIPT_H_
+#define CHROME_BROWSER_UI_COCOA_APPLESCRIPT_ERROR_APPLESCRIPT_H_
+
+#import <Cocoa/Cocoa.h>
+
+namespace AppleScript {
+
+enum ErrorCode {
+ // Error when default profile cannot be obtained.
+ errGetProfile = 1,
+ // Error when bookmark model fails to load.
+ errBookmarkModelLoad,
+ // Error when bookmark folder cannot be created.
+ errCreateBookmarkFolder,
+ // Error when bookmark item cannot be created.
+ errCreateBookmarkItem,
+ // Error when URL entered is invalid.
+ errInvalidURL,
+ // Error when printing cannot be initiated.
+ errInitiatePrinting,
+ // Error when invalid tab save type is entered.
+ errInvalidSaveType,
+ // Error when invalid browser mode is entered.
+ errInvalidMode,
+ // Error when tab index is out of bounds.
+ errInvalidTabIndex,
+ // Error when mode is set after browser window is created.
+ errSetMode,
+ // Error when index of browser window is out of bounds.
+ errWrongIndex
+};
+
+// This function sets an error message to the currently executing command.
+void SetError(ErrorCode errorCode);
+}
+
+#endif // CHROME_BROWSER_UI_COCOA_APPLESCRIPT_ERROR_APPLESCRIPT_H_
diff --git a/chrome/browser/ui/cocoa/applescript/error_applescript.mm b/chrome/browser/ui/cocoa/applescript/error_applescript.mm
new file mode 100644
index 0000000..e86ffd0
--- /dev/null
+++ b/chrome/browser/ui/cocoa/applescript/error_applescript.mm
@@ -0,0 +1,56 @@
+// 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 "chrome/browser/ui/cocoa/applescript/error_applescript.h"
+
+#import "app/l10n_util_mac.h"
+#include "base/logging.h"
+#include "grit/generated_resources.h"
+
+void AppleScript::SetError(AppleScript::ErrorCode errorCode) {
+ using namespace l10n_util;
+ NSScriptCommand* current_command = [NSScriptCommand currentCommand];
+ [current_command setScriptErrorNumber:(int)errorCode];
+ NSString* error_string = @"";
+ switch (errorCode) {
+ case errGetProfile:
+ error_string = GetNSString(IDS_GET_PROFILE_ERROR_APPLESCRIPT_MAC);
+ break;
+ case errBookmarkModelLoad:
+ error_string = GetNSString(IDS_BOOKMARK_MODEL_LOAD_ERROR_APPLESCRIPT_MAC);
+ break;
+ case errCreateBookmarkFolder:
+ error_string =
+ GetNSString(IDS_CREATE_BOOKMARK_FOLDER_ERROR_APPLESCRIPT_MAC);
+ break;
+ case errCreateBookmarkItem:
+ error_string =
+ GetNSString(IDS_CREATE_BOOKMARK_ITEM_ERROR_APPLESCRIPT_MAC);
+ break;
+ case errInvalidURL:
+ error_string = GetNSString(IDS_INVALID_URL_APPLESCRIPT_MAC);
+ break;
+ case errInitiatePrinting:
+ error_string = GetNSString(IDS_INITIATE_PRINTING_ERROR_APPLESCRIPT_MAC);
+ break;
+ case errInvalidSaveType:
+ error_string = GetNSString(IDS_INVALID_SAVE_TYPE_ERROR_APPLESCRIPT_MAC);
+ break;
+ case errInvalidMode:
+ error_string = GetNSString(IDS_INVALID_MODE_ERROR_APPLESCRIPT_MAC);
+ break;
+ case errInvalidTabIndex:
+ error_string = GetNSString(IDS_INVALID_TAB_INDEX_APPLESCRIPT_MAC);
+ break;
+ case errSetMode:
+ error_string = GetNSString(IDS_SET_MODE_APPLESCRIPT_MAC);
+ break;
+ case errWrongIndex:
+ error_string = GetNSString(IDS_WRONG_INDEX_ERROR_APPLESCRIPT_MAC);
+ break;
+ default:
+ NOTREACHED();
+ }
+ [current_command setScriptErrorString:error_string];
+}
diff --git a/chrome/browser/cocoa/applescript/examples/advanced_tab_manipulation.applescript b/chrome/browser/ui/cocoa/applescript/examples/advanced_tab_manipulation.applescript
index d45bd86..d45bd86 100644
--- a/chrome/browser/cocoa/applescript/examples/advanced_tab_manipulation.applescript
+++ b/chrome/browser/ui/cocoa/applescript/examples/advanced_tab_manipulation.applescript
diff --git a/chrome/browser/cocoa/applescript/examples/app_info.applescript b/chrome/browser/ui/cocoa/applescript/examples/app_info.applescript
index 8377e14..8377e14 100644
--- a/chrome/browser/cocoa/applescript/examples/app_info.applescript
+++ b/chrome/browser/ui/cocoa/applescript/examples/app_info.applescript
diff --git a/chrome/browser/cocoa/applescript/examples/bookmark_current_tabs.applescript b/chrome/browser/ui/cocoa/applescript/examples/bookmark_current_tabs.applescript
index 6e88268..6e88268 100644
--- a/chrome/browser/cocoa/applescript/examples/bookmark_current_tabs.applescript
+++ b/chrome/browser/ui/cocoa/applescript/examples/bookmark_current_tabs.applescript
diff --git a/chrome/browser/cocoa/applescript/examples/copy_html.applescript b/chrome/browser/ui/cocoa/applescript/examples/copy_html.applescript
index fd7b4e0..fd7b4e0 100644
--- a/chrome/browser/cocoa/applescript/examples/copy_html.applescript
+++ b/chrome/browser/ui/cocoa/applescript/examples/copy_html.applescript
diff --git a/chrome/browser/cocoa/applescript/examples/delete_bookmarks.applescript b/chrome/browser/ui/cocoa/applescript/examples/delete_bookmarks.applescript
index 341b100..341b100 100644
--- a/chrome/browser/cocoa/applescript/examples/delete_bookmarks.applescript
+++ b/chrome/browser/ui/cocoa/applescript/examples/delete_bookmarks.applescript
diff --git a/chrome/browser/cocoa/applescript/examples/execute_javascript.applescript b/chrome/browser/ui/cocoa/applescript/examples/execute_javascript.applescript
index 33a34b4..33a34b4 100644
--- a/chrome/browser/cocoa/applescript/examples/execute_javascript.applescript
+++ b/chrome/browser/ui/cocoa/applescript/examples/execute_javascript.applescript
diff --git a/chrome/browser/cocoa/applescript/examples/open_tabs_from_bookmark_folder.applescript b/chrome/browser/ui/cocoa/applescript/examples/open_tabs_from_bookmark_folder.applescript
index af36fc1..af36fc1 100644
--- a/chrome/browser/cocoa/applescript/examples/open_tabs_from_bookmark_folder.applescript
+++ b/chrome/browser/ui/cocoa/applescript/examples/open_tabs_from_bookmark_folder.applescript
diff --git a/chrome/browser/cocoa/applescript/examples/quit_app.applescript b/chrome/browser/ui/cocoa/applescript/examples/quit_app.applescript
index a6bdd1f..a6bdd1f 100644
--- a/chrome/browser/cocoa/applescript/examples/quit_app.applescript
+++ b/chrome/browser/ui/cocoa/applescript/examples/quit_app.applescript
diff --git a/chrome/browser/cocoa/applescript/examples/tab_manipulation.applescript b/chrome/browser/ui/cocoa/applescript/examples/tab_manipulation.applescript
index 9038c17..9038c17 100644
--- a/chrome/browser/cocoa/applescript/examples/tab_manipulation.applescript
+++ b/chrome/browser/ui/cocoa/applescript/examples/tab_manipulation.applescript
diff --git a/chrome/browser/cocoa/applescript/examples/tab_navigation.applescript b/chrome/browser/ui/cocoa/applescript/examples/tab_navigation.applescript
index 2337869..2337869 100644
--- a/chrome/browser/cocoa/applescript/examples/tab_navigation.applescript
+++ b/chrome/browser/ui/cocoa/applescript/examples/tab_navigation.applescript
diff --git a/chrome/browser/cocoa/applescript/examples/window_creation.applescript b/chrome/browser/ui/cocoa/applescript/examples/window_creation.applescript
index fc1486a..fc1486a 100644
--- a/chrome/browser/cocoa/applescript/examples/window_creation.applescript
+++ b/chrome/browser/ui/cocoa/applescript/examples/window_creation.applescript
diff --git a/chrome/browser/cocoa/applescript/examples/window_operations.applescript b/chrome/browser/ui/cocoa/applescript/examples/window_operations.applescript
index 90a0288..90a0288 100644
--- a/chrome/browser/cocoa/applescript/examples/window_operations.applescript
+++ b/chrome/browser/ui/cocoa/applescript/examples/window_operations.applescript
diff --git a/chrome/browser/cocoa/applescript/scripting.sdef b/chrome/browser/ui/cocoa/applescript/scripting.sdef
index b67b2b7..b67b2b7 100644
--- a/chrome/browser/cocoa/applescript/scripting.sdef
+++ b/chrome/browser/ui/cocoa/applescript/scripting.sdef
diff --git a/chrome/browser/ui/cocoa/applescript/tab_applescript.h b/chrome/browser/ui/cocoa/applescript/tab_applescript.h
new file mode 100644
index 0000000..30064fa
--- /dev/null
+++ b/chrome/browser/ui/cocoa/applescript/tab_applescript.h
@@ -0,0 +1,79 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_APPLESCRIPT_TAB_APPLESCRIPT_H_
+#define CHROME_BROWSER_UI_COCOA_APPLESCRIPT_TAB_APPLESCRIPT_H_
+
+#import <Cocoa/Cocoa.h>
+
+#import "chrome/browser/ui/cocoa/applescript/element_applescript.h"
+
+class TabContents;
+
+// Represents a tab scriptable item in applescript.
+@interface TabAppleScript : ElementAppleScript {
+ @private
+ TabContents* tabContents_; // weak.
+ // Contains the temporary URL when a user creates a new folder/item with
+ // url specified like
+ // |make new tab with properties {url:"http://google.com"}|.
+ NSString* tempURL_;
+}
+
+// Doesn't actually create the tab here but just assigns the ID, tab is created
+// when it calls insertInTabs: of a particular window, it is used in cases
+// where user assigns a tab to a variable like |set var to make new tab|.
+- (id)init;
+
+// Does not create a new tab but uses an existing one.
+- (id)initWithTabContent:(TabContents*)aTabContent;
+
+// Assigns a tab, sets its unique ID and also copies temporary values.
+- (void)setTabContent:(TabContents*)aTabContent;
+
+// Return the URL currently visible to the user in the location bar.
+- (NSString*)URL;
+
+// Sets the URL, returns an error if it is invalid.
+- (void)setURL:(NSString*)aURL;
+
+// The title of the tab.
+- (NSString*)title;
+
+// Is the tab loading any resource?
+- (NSNumber*)loading;
+
+// Standard user commands.
+- (void)handlesUndoScriptCommand:(NSScriptCommand*)command;
+- (void)handlesRedoScriptCommand:(NSScriptCommand*)command;
+
+// Edit operations on the page.
+- (void)handlesCutScriptCommand:(NSScriptCommand*)command;
+- (void)handlesCopyScriptCommand:(NSScriptCommand*)command;
+- (void)handlesPasteScriptCommand:(NSScriptCommand*)command;
+
+// Selects all contents on the page.
+- (void)handlesSelectAllScriptCommand:(NSScriptCommand*)command;
+
+// Navigation operations.
+- (void)handlesGoBackScriptCommand:(NSScriptCommand*)command;
+- (void)handlesGoForwardScriptCommand:(NSScriptCommand*)command;
+- (void)handlesReloadScriptCommand:(NSScriptCommand*)command;
+- (void)handlesStopScriptCommand:(NSScriptCommand*)command;
+
+// Used to print a tab.
+- (void)handlesPrintScriptCommand:(NSScriptCommand*)command;
+
+// Used to save a tab, if no file is specified, prompts the user to enter it.
+- (void)handlesSaveScriptCommand:(NSScriptCommand*)command;
+
+// Displays the HTML of the tab in a new tab.
+- (void)handlesViewSourceScriptCommand:(NSScriptCommand*)command;
+
+// Executes a piece of javascript in the tab.
+- (id)handlesExecuteJavascriptScriptCommand:(NSScriptCommand*)command;
+
+@end
+
+#endif// CHROME_BROWSER_UI_COCOA_APPLESCRIPT_TAB_APPLESCRIPT_H_
diff --git a/chrome/browser/ui/cocoa/applescript/tab_applescript.mm b/chrome/browser/ui/cocoa/applescript/tab_applescript.mm
new file mode 100644
index 0000000..3a10095
--- /dev/null
+++ b/chrome/browser/ui/cocoa/applescript/tab_applescript.mm
@@ -0,0 +1,296 @@
+// 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 "chrome/browser/ui/cocoa/applescript/tab_applescript.h"
+
+#include "base/file_path.h"
+#include "base/logging.h"
+#import "base/scoped_nsobject.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/download/save_package.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/sessions/session_id.h"
+#include "chrome/browser/tab_contents/navigation_controller.h"
+#include "chrome/browser/tab_contents/navigation_entry.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/cocoa/applescript/error_applescript.h"
+#include "chrome/common/url_constants.h"
+#include "googleurl/src/gurl.h"
+
+@interface TabAppleScript()
+@property (nonatomic, copy) NSString* tempURL;
+@end
+
+@implementation TabAppleScript
+
+@synthesize tempURL = tempURL_;
+
+- (id)init {
+ if ((self = [super init])) {
+ SessionID session;
+ SessionID::id_type futureSessionIDOfTab = session.id() + 1;
+ // Holds the SessionID that the new tab is going to get.
+ scoped_nsobject<NSNumber> numID(
+ [[NSNumber alloc]
+ initWithInt:futureSessionIDOfTab]);
+ [self setUniqueID:numID];
+ [self setTempURL:@""];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [tempURL_ release];
+ [super dealloc];
+}
+
+- (id)initWithTabContent:(TabContents*)aTabContent {
+ if (!aTabContent) {
+ [self release];
+ return nil;
+ }
+
+ if ((self = [super init])) {
+ // It is safe to be weak, if a tab goes away (eg user closing a tab)
+ // the applescript runtime calls tabs in AppleScriptWindow and this
+ // particular tab is never returned.
+ tabContents_ = aTabContent;
+ scoped_nsobject<NSNumber> numID(
+ [[NSNumber alloc]
+ initWithInt:tabContents_->controller().session_id().id()]);
+ [self setUniqueID:numID];
+ }
+ return self;
+}
+
+- (void)setTabContent:(TabContents*)aTabContent {
+ DCHECK(aTabContent);
+ // It is safe to be weak, if a tab goes away (eg user closing a tab)
+ // the applescript runtime calls tabs in AppleScriptWindow and this
+ // particular tab is never returned.
+ tabContents_ = aTabContent;
+ scoped_nsobject<NSNumber> numID(
+ [[NSNumber alloc]
+ initWithInt:tabContents_->controller().session_id().id()]);
+ [self setUniqueID:numID];
+
+ [self setURL:[self tempURL]];
+}
+
+- (NSString*)URL {
+ if (!tabContents_) {
+ return nil;
+ }
+
+ NavigationEntry* entry = tabContents_->controller().GetActiveEntry();
+ if (!entry) {
+ return nil;
+ }
+ const GURL& url = entry->virtual_url();
+ return base::SysUTF8ToNSString(url.spec());
+}
+
+- (void)setURL:(NSString*)aURL {
+ // If a scripter sets a URL before the node is added save it at a temporary
+ // location.
+ if (!tabContents_) {
+ [self setTempURL:aURL];
+ return;
+ }
+
+ GURL url(base::SysNSStringToUTF8(aURL));
+ // check for valid url.
+ if (!url.is_empty() && !url.is_valid()) {
+ AppleScript::SetError(AppleScript::errInvalidURL);
+ return;
+ }
+
+ NavigationEntry* entry = tabContents_->controller().GetActiveEntry();
+ if (!entry)
+ return;
+
+ const GURL& previousURL = entry->virtual_url();
+ tabContents_->OpenURL(url,
+ previousURL,
+ CURRENT_TAB,
+ PageTransition::TYPED);
+}
+
+- (NSString*)title {
+ NavigationEntry* entry = tabContents_->controller().GetActiveEntry();
+ if (!entry)
+ return nil;
+
+ std::wstring title;
+ if (entry != NULL) {
+ title = UTF16ToWideHack(entry->title());
+ }
+
+ return base::SysWideToNSString(title);
+}
+
+- (NSNumber*)loading {
+ BOOL loadingValue = tabContents_->is_loading() ? YES : NO;
+ return [NSNumber numberWithBool:loadingValue];
+}
+
+- (void)handlesUndoScriptCommand:(NSScriptCommand*)command {
+ RenderViewHost* view = tabContents_->render_view_host();
+ if (!view) {
+ NOTREACHED();
+ return;
+ }
+
+ view->Undo();
+}
+
+- (void)handlesRedoScriptCommand:(NSScriptCommand*)command {
+ RenderViewHost* view = tabContents_->render_view_host();
+ if (!view) {
+ NOTREACHED();
+ return;
+ }
+
+ view->Redo();
+}
+
+- (void)handlesCutScriptCommand:(NSScriptCommand*)command {
+ RenderViewHost* view = tabContents_->render_view_host();
+ if (!view) {
+ NOTREACHED();
+ return;
+ }
+
+ view->Cut();
+}
+
+- (void)handlesCopyScriptCommand:(NSScriptCommand*)command {
+ RenderViewHost* view = tabContents_->render_view_host();
+ if (!view) {
+ NOTREACHED();
+ return;
+ }
+
+ view->Copy();
+}
+
+- (void)handlesPasteScriptCommand:(NSScriptCommand*)command {
+ RenderViewHost* view = tabContents_->render_view_host();
+ if (!view) {
+ NOTREACHED();
+ return;
+ }
+
+ view->Paste();
+}
+
+- (void)handlesSelectAllScriptCommand:(NSScriptCommand*)command {
+ RenderViewHost* view = tabContents_->render_view_host();
+ if (!view) {
+ NOTREACHED();
+ return;
+ }
+
+ view->SelectAll();
+}
+
+- (void)handlesGoBackScriptCommand:(NSScriptCommand*)command {
+ NavigationController& navigationController = tabContents_->controller();
+ if (navigationController.CanGoBack())
+ navigationController.GoBack();
+}
+
+- (void)handlesGoForwardScriptCommand:(NSScriptCommand*)command {
+ NavigationController& navigationController = tabContents_->controller();
+ if (navigationController.CanGoForward())
+ navigationController.GoForward();
+}
+
+- (void)handlesReloadScriptCommand:(NSScriptCommand*)command {
+ NavigationController& navigationController = tabContents_->controller();
+ const bool checkForRepost = true;
+ navigationController.Reload(checkForRepost);
+}
+
+- (void)handlesStopScriptCommand:(NSScriptCommand*)command {
+ RenderViewHost* view = tabContents_->render_view_host();
+ if (!view) {
+ // We tolerate Stop being called even before a view has been created.
+ // So just log a warning instead of a NOTREACHED().
+ DLOG(WARNING) << "Stop: no view for handle ";
+ return;
+ }
+
+ view->Stop();
+}
+
+- (void)handlesPrintScriptCommand:(NSScriptCommand*)command {
+ bool initiateStatus = tabContents_->PrintNow();
+ if (initiateStatus == false) {
+ AppleScript::SetError(AppleScript::errInitiatePrinting);
+ }
+}
+
+- (void)handlesSaveScriptCommand:(NSScriptCommand*)command {
+ NSDictionary* dictionary = [command evaluatedArguments];
+
+ NSURL* fileURL = [dictionary objectForKey:@"File"];
+ // Scripter has not specifed the location at which to save, so we prompt for
+ // it.
+ if (!fileURL) {
+ tabContents_->OnSavePage();
+ return;
+ }
+
+ FilePath mainFile(base::SysNSStringToUTF8([fileURL path]));
+ // We create a directory path at the folder within which the file exists.
+ // Eg. if main_file = '/Users/Foo/Documents/Google.html'
+ // then directory_path = '/Users/Foo/Documents/Google_files/'.
+ FilePath directoryPath = mainFile.RemoveExtension();
+ directoryPath = directoryPath.InsertBeforeExtension(std::string("_files/"));
+
+ NSString* saveType = [dictionary objectForKey:@"FileType"];
+
+ SavePackage::SavePackageType savePackageType =
+ SavePackage::SAVE_AS_COMPLETE_HTML;
+ if (saveType) {
+ if ([saveType isEqualToString:@"only html"]) {
+ savePackageType = SavePackage::SAVE_AS_ONLY_HTML;
+ } else if ([saveType isEqualToString:@"complete html"]) {
+ savePackageType = SavePackage::SAVE_AS_COMPLETE_HTML;
+ } else {
+ AppleScript::SetError(AppleScript::errInvalidSaveType);
+ return;
+ }
+ }
+
+ tabContents_->SavePage(mainFile, directoryPath, savePackageType);
+}
+
+
+- (void)handlesViewSourceScriptCommand:(NSScriptCommand*)command {
+ NavigationEntry* entry = tabContents_->controller().GetLastCommittedEntry();
+ if (entry) {
+ tabContents_->OpenURL(GURL(chrome::kViewSourceScheme + std::string(":") +
+ entry->url().spec()), GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
+ }
+}
+
+- (id)handlesExecuteJavascriptScriptCommand:(NSScriptCommand*)command {
+ RenderViewHost* view = tabContents_->render_view_host();
+ if (!view) {
+ NOTREACHED();
+ return nil;
+ }
+
+ std::wstring script = base::SysNSStringToWide(
+ [[command evaluatedArguments] objectForKey:@"javascript"]);
+ view->ExecuteJavascriptInWebFrame(L"", script);
+
+ // TODO(Shreyas): Figure out a way to get the response back.
+ return nil;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/applescript/window_applescript.h b/chrome/browser/ui/cocoa/applescript/window_applescript.h
new file mode 100644
index 0000000..6d98d10
--- /dev/null
+++ b/chrome/browser/ui/cocoa/applescript/window_applescript.h
@@ -0,0 +1,81 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_APPLESCRIPT_WINDOW_APPLESCRIPT_H_
+#define CHROME_BROWSER_UI_COCOA_APPLESCRIPT_WINDOW_APPLESCRIPT_H_
+
+#import <Cocoa/Cocoa.h>
+
+#import "chrome/browser/ui/cocoa/applescript/element_applescript.h"
+
+class Browser;
+class Profile;
+@class TabAppleScript;
+
+// Represents a window class.
+@interface WindowAppleScript : ElementAppleScript {
+ @private
+ Browser* browser_; // weak.
+}
+
+// Creates a new window, returns nil if there is an error.
+- (id)init;
+
+// Creates a new window with a particular profile.
+- (id)initWithProfile:(Profile*)aProfile;
+
+// Does not create a new window but uses an existing one.
+- (id)initWithBrowser:(Browser*)aBrowser;
+
+// Sets and gets the index of the currently selected tab.
+- (NSNumber*)activeTabIndex;
+- (void)setActiveTabIndex:(NSNumber*)anActiveTabIndex;
+
+// Mode refers to whether a window is a normal window or an incognito window
+// it can be set only once while creating the window.
+- (NSString*)mode;
+- (void)setMode:(NSString*)theMode;
+
+// Returns the currently selected tab.
+- (TabAppleScript*)activeTab;
+
+// Tab manipulation functions.
+// The tabs inside the window.
+// Returns |TabAppleScript*| of all the tabs contained
+// within this particular folder.
+- (NSArray*)tabs;
+
+// Insert a tab at the end.
+- (void)insertInTabs:(TabAppleScript*)aTab;
+
+// Insert a tab at some position in the list.
+// Called by applescript which takes care of bounds checking, make sure of it
+// before calling directly.
+- (void)insertInTabs:(TabAppleScript*)aTab atIndex:(int)index;
+
+// Remove a window from the list.
+// Called by applescript which takes care of bounds checking, make sure of it
+// before calling directly.
+- (void)removeFromTabsAtIndex:(int)index;
+
+// Set the index of a window.
+- (void)setOrderedIndex:(NSNumber*)anIndex;
+
+// Used to sort windows by index.
+- (NSComparisonResult)windowComparator:(WindowAppleScript*)otherWindow;
+
+// For standard window functions like zoomable, bounds etc, we dont handle it
+// but instead pass it onto the NSWindow associated with the window.
+- (id)valueForUndefinedKey:(NSString*)key;
+- (void)setValue:(id)value forUndefinedKey:(NSString*)key;
+
+// Used to close window.
+- (void)handlesCloseScriptCommand:(NSCloseCommand*)command;
+
+// The index of the window, windows are ordered front to back.
+- (NSNumber*)orderedIndex;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_APPLESCRIPT_WINDOW_APPLESCRIPT_H_
diff --git a/chrome/browser/ui/cocoa/applescript/window_applescript.mm b/chrome/browser/ui/cocoa/applescript/window_applescript.mm
new file mode 100644
index 0000000..d6c7b5a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/applescript/window_applescript.mm
@@ -0,0 +1,246 @@
+// 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 "chrome/browser/ui/cocoa/applescript/window_applescript.h"
+
+#include "base/logging.h"
+#import "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+#include "base/time.h"
+#import "chrome/browser/app_controller_mac.h"
+#import "chrome/browser/chrome_browser_application_mac.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_navigator.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/cocoa/applescript/constants_applescript.h"
+#include "chrome/browser/ui/cocoa/applescript/error_applescript.h"
+#import "chrome/browser/ui/cocoa/applescript/tab_applescript.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "chrome/common/url_constants.h"
+
+@interface WindowAppleScript(WindowAppleScriptPrivateMethods)
+// The NSWindow that corresponds to this window.
+- (NSWindow*)nativeHandle;
+@end
+
+@implementation WindowAppleScript
+
+- (id)init {
+ // Check which mode to open a new window.
+ NSScriptCommand* command = [NSScriptCommand currentCommand];
+ NSString* mode = [[[command evaluatedArguments]
+ objectForKey:@"KeyDictionary"] objectForKey:@"mode"];
+ AppController* appDelegate = [NSApp delegate];
+
+ Profile* defaultProfile = [appDelegate defaultProfile];
+
+ if (!defaultProfile) {
+ AppleScript::SetError(AppleScript::errGetProfile);
+ return nil;
+ }
+
+ Profile* profile;
+ if ([mode isEqualToString:AppleScript::kIncognitoWindowMode]) {
+ profile = defaultProfile->GetOffTheRecordProfile();
+ }
+ else if ([mode isEqualToString:AppleScript::kNormalWindowMode] || !mode) {
+ profile = defaultProfile;
+ } else {
+ // Mode cannot be anything else
+ AppleScript::SetError(AppleScript::errInvalidMode);
+ return nil;
+ }
+ // Set the mode to nil, to ensure that it is not set once more.
+ [[[command evaluatedArguments] objectForKey:@"KeyDictionary"]
+ setValue:nil forKey:@"mode"];
+ return [self initWithProfile:profile];
+}
+
+- (id)initWithProfile:(Profile*)aProfile {
+ if (!aProfile) {
+ [self release];
+ return nil;
+ }
+
+ if ((self = [super init])) {
+ browser_ = Browser::Create(aProfile);
+ browser_->NewTab();
+ browser_->window()->Show();
+ scoped_nsobject<NSNumber> numID(
+ [[NSNumber alloc] initWithInt:browser_->session_id().id()]);
+ [self setUniqueID:numID];
+ }
+ return self;
+}
+
+- (id)initWithBrowser:(Browser*)aBrowser {
+ if (!aBrowser) {
+ [self release];
+ return nil;
+ }
+
+ if ((self = [super init])) {
+ // It is safe to be weak, if a window goes away (eg user closing a window)
+ // the applescript runtime calls appleScriptWindows in
+ // BrowserCrApplication and this particular window is never returned.
+ browser_ = aBrowser;
+ scoped_nsobject<NSNumber> numID(
+ [[NSNumber alloc] initWithInt:browser_->session_id().id()]);
+ [self setUniqueID:numID];
+ }
+ return self;
+}
+
+- (NSWindow*)nativeHandle {
+ // window() can be NULL during startup.
+ if (browser_->window())
+ return browser_->window()->GetNativeHandle();
+ return nil;
+}
+
+- (NSNumber*)activeTabIndex {
+ // Note: applescript is 1-based, that is lists begin with index 1.
+ int activeTabIndex = browser_->selected_index() + 1;
+ if (!activeTabIndex) {
+ return nil;
+ }
+ return [NSNumber numberWithInt:activeTabIndex];
+}
+
+- (void)setActiveTabIndex:(NSNumber*)anActiveTabIndex {
+ // Note: applescript is 1-based, that is lists begin with index 1.
+ int atIndex = [anActiveTabIndex intValue] - 1;
+ if (atIndex >= 0 && atIndex < browser_->tab_count())
+ browser_->SelectTabContentsAt(atIndex, true);
+ else
+ AppleScript::SetError(AppleScript::errInvalidTabIndex);
+}
+
+- (NSString*)mode {
+ Profile* profile = browser_->profile();
+ if (profile->IsOffTheRecord())
+ return AppleScript::kIncognitoWindowMode;
+ return AppleScript::kNormalWindowMode;
+}
+
+- (void)setMode:(NSString*)theMode {
+ // cannot set mode after window is created.
+ if (theMode) {
+ AppleScript::SetError(AppleScript::errSetMode);
+ }
+}
+
+- (TabAppleScript*)activeTab {
+ TabAppleScript* currentTab = [[[TabAppleScript alloc]
+ initWithTabContent:browser_->GetSelectedTabContents()] autorelease];
+ [currentTab setContainer:self
+ property:AppleScript::kTabsProperty];
+ return currentTab;
+}
+
+- (NSArray*)tabs {
+ NSMutableArray* tabs = [NSMutableArray
+ arrayWithCapacity:browser_->tab_count()];
+
+ for (int i = 0; i < browser_->tab_count(); ++i) {
+ // Check to see if tab is closing.
+ if (browser_->GetTabContentsAt(i)->is_being_destroyed()) {
+ continue;
+ }
+
+ scoped_nsobject<TabAppleScript> tab(
+ [[TabAppleScript alloc]
+ initWithTabContent:(browser_->GetTabContentsAt(i))]);
+ [tab setContainer:self
+ property:AppleScript::kTabsProperty];
+ [tabs addObject:tab];
+ }
+ return tabs;
+}
+
+- (void)insertInTabs:(TabAppleScript*)aTab {
+ // This method gets called when a new tab is created so
+ // the container and property are set here.
+ [aTab setContainer:self
+ property:AppleScript::kTabsProperty];
+
+ // Set how long it takes a tab to be created.
+ base::TimeTicks newTabStartTime = base::TimeTicks::Now();
+ TabContentsWrapper* contents =
+ browser_->AddSelectedTabWithURL(GURL(chrome::kChromeUINewTabURL),
+ PageTransition::TYPED);
+ contents->tab_contents()->set_new_tab_start_time(newTabStartTime);
+ [aTab setTabContent:contents->tab_contents()];
+}
+
+- (void)insertInTabs:(TabAppleScript*)aTab atIndex:(int)index {
+ // This method gets called when a new tab is created so
+ // This method gets called when a new tab is created so
+ // the container and property are set here.
+ [aTab setContainer:self
+ property:AppleScript::kTabsProperty];
+
+ // Set how long it takes a tab to be created.
+ base::TimeTicks newTabStartTime = base::TimeTicks::Now();
+ browser::NavigateParams params(browser_,
+ GURL(chrome::kChromeUINewTabURL),
+ PageTransition::TYPED);
+ params.disposition = NEW_FOREGROUND_TAB;
+ params.tabstrip_index = index;
+ browser::Navigate(&params);
+ params.target_contents->tab_contents()->set_new_tab_start_time(
+ newTabStartTime);
+
+ [aTab setTabContent:params.target_contents->tab_contents()];
+}
+
+- (void)removeFromTabsAtIndex:(int)index {
+ browser_->tabstrip_model()->DetachTabContentsAt(index);
+}
+
+- (NSNumber*)orderedIndex{
+ return [NSNumber numberWithInt:[[self nativeHandle] orderedIndex]];
+}
+
+- (void)setOrderedIndex:(NSNumber*)anIndex {
+ int index = [anIndex intValue] - 1;
+ if (index < 0 || index >= (int)BrowserList::size()) {
+ AppleScript::SetError(AppleScript::errWrongIndex);
+ return;
+ }
+ [[self nativeHandle] setOrderedIndex:index];
+}
+
+- (NSComparisonResult)windowComparator:(WindowAppleScript*)otherWindow {
+ int thisIndex = [[self orderedIndex] intValue];
+ int otherIndex = [[otherWindow orderedIndex] intValue];
+ if (thisIndex < otherIndex)
+ return NSOrderedAscending;
+ else if (thisIndex > otherIndex)
+ return NSOrderedDescending;
+ // Indexes can never be same.
+ NOTREACHED();
+ return NSOrderedSame;
+}
+
+// Get and set values from the associated NSWindow.
+- (id)valueForUndefinedKey:(NSString*)key {
+ return [[self nativeHandle] valueForKey:key];
+}
+
+- (void)setValue:(id)value forUndefinedKey:(NSString*)key {
+ [[self nativeHandle] setValue:(id)value forKey:key];
+}
+
+- (void)handlesCloseScriptCommand:(NSCloseCommand*)command {
+ // window() can be NULL during startup.
+ if (browser_->window())
+ browser_->window()->Close();
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/applescript/window_applescript_test.mm b/chrome/browser/ui/cocoa/applescript/window_applescript_test.mm
new file mode 100644
index 0000000..96eb930
--- /dev/null
+++ b/chrome/browser/ui/cocoa/applescript/window_applescript_test.mm
@@ -0,0 +1,178 @@
+// 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>
+
+#import "base/scoped_nsobject.h"
+#include "base/sys_string_conversions.h"
+#import "chrome/browser/app_controller_mac.h"
+#import "chrome/browser/chrome_browser_application_mac.h"
+#include "chrome/browser/profiles/profile.h"
+#import "chrome/browser/ui/cocoa/applescript/constants_applescript.h"
+#import "chrome/browser/ui/cocoa/applescript/error_applescript.h"
+#import "chrome/browser/ui/cocoa/applescript/tab_applescript.h"
+#import "chrome/browser/ui/cocoa/applescript/window_applescript.h"
+#include "chrome/test/in_process_browser_test.h"
+#include "googleurl/src/gurl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+
+typedef InProcessBrowserTest WindowAppleScriptTest;
+
+// Create a window in default/normal mode.
+IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, DefaultCreation) {
+ scoped_nsobject<WindowAppleScript> aWindow(
+ [[WindowAppleScript alloc] init]);
+ EXPECT_TRUE(aWindow.get());
+ NSString* mode = [aWindow.get() mode];
+ EXPECT_NSEQ(AppleScript::kNormalWindowMode,
+ mode);
+}
+
+// Create a window with a |NULL profile|.
+IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, CreationWithNoProfile) {
+ scoped_nsobject<WindowAppleScript> aWindow(
+ [[WindowAppleScript alloc] initWithProfile:NULL]);
+ EXPECT_FALSE(aWindow.get());
+}
+
+// Create a window with a particular profile.
+IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, CreationWithProfile) {
+ Profile* defaultProfile = [[NSApp delegate] defaultProfile];
+ scoped_nsobject<WindowAppleScript> aWindow(
+ [[WindowAppleScript alloc] initWithProfile:defaultProfile]);
+ EXPECT_TRUE(aWindow.get());
+ EXPECT_TRUE([aWindow.get() uniqueID]);
+}
+
+// Create a window with no |Browser*|.
+IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, CreationWithNoBrowser) {
+ scoped_nsobject<WindowAppleScript> aWindow(
+ [[WindowAppleScript alloc] initWithBrowser:NULL]);
+ EXPECT_FALSE(aWindow.get());
+}
+
+// Create a window with |Browser*| already present.
+IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, CreationWithBrowser) {
+ scoped_nsobject<WindowAppleScript> aWindow(
+ [[WindowAppleScript alloc] initWithBrowser:browser()]);
+ EXPECT_TRUE(aWindow.get());
+ EXPECT_TRUE([aWindow.get() uniqueID]);
+}
+
+// Tabs within the window.
+IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, Tabs) {
+ scoped_nsobject<WindowAppleScript> aWindow(
+ [[WindowAppleScript alloc] initWithBrowser:browser()]);
+ NSArray* tabs = [aWindow.get() tabs];
+ EXPECT_EQ(1U, [tabs count]);
+ TabAppleScript* tab1 = [tabs objectAtIndex:0];
+ EXPECT_EQ([tab1 container], aWindow.get());
+ EXPECT_NSEQ(AppleScript::kTabsProperty,
+ [tab1 containerProperty]);
+}
+
+// Insert a new tab.
+IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, InsertTab) {
+ // Emulate what applescript would do when creating a new tab.
+ // Emulates a script like |set var to make new tab with
+ // properties URL:"http://google.com"}|.
+ scoped_nsobject<TabAppleScript> aTab([[TabAppleScript alloc] init]);
+ scoped_nsobject<NSNumber> var([[aTab.get() uniqueID] copy]);
+ [aTab.get() setURL:@"http://google.com"];
+ scoped_nsobject<WindowAppleScript> aWindow(
+ [[WindowAppleScript alloc] initWithBrowser:browser()]);
+ [aWindow.get() insertInTabs:aTab.get()];
+
+ // Represents the tab after it is inserted.
+ TabAppleScript* tab = [[aWindow.get() tabs] objectAtIndex:1];
+ EXPECT_EQ(GURL("http://google.com"),
+ GURL(base::SysNSStringToUTF8([tab URL])));
+ EXPECT_EQ([tab container], aWindow.get());
+ EXPECT_NSEQ(AppleScript::kTabsProperty,
+ [tab containerProperty]);
+ EXPECT_NSEQ(var.get(), [tab uniqueID]);
+}
+
+// Insert a new tab at a particular position
+IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, InsertTabAtPosition) {
+ // Emulate what applescript would do when creating a new tab.
+ // Emulates a script like |set var to make new tab with
+ // properties URL:"http://google.com"} at before tab 1|.
+ scoped_nsobject<TabAppleScript> aTab([[TabAppleScript alloc] init]);
+ scoped_nsobject<NSNumber> var([[aTab.get() uniqueID] copy]);
+ [aTab.get() setURL:@"http://google.com"];
+ scoped_nsobject<WindowAppleScript> aWindow(
+ [[WindowAppleScript alloc] initWithBrowser:browser()]);
+ [aWindow.get() insertInTabs:aTab.get() atIndex:0];
+
+ // Represents the tab after it is inserted.
+ TabAppleScript* tab = [[aWindow.get() tabs] objectAtIndex:0];
+ EXPECT_EQ(GURL("http://google.com"),
+ GURL(base::SysNSStringToUTF8([tab URL])));
+ EXPECT_EQ([tab container], aWindow.get());
+ EXPECT_NSEQ(AppleScript::kTabsProperty, [tab containerProperty]);
+ EXPECT_NSEQ(var.get(), [tab uniqueID]);
+}
+
+// Inserting and deleting tabs.
+IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, InsertAndDeleteTabs) {
+ scoped_nsobject<WindowAppleScript> aWindow(
+ [[WindowAppleScript alloc] initWithBrowser:browser()]);
+ scoped_nsobject<TabAppleScript> aTab;
+ int count;
+ for (int i = 0; i < 5; ++i) {
+ for (int j = 0; j < 3; ++j) {
+ aTab.reset([[TabAppleScript alloc] init]);
+ [aWindow.get() insertInTabs:aTab.get()];
+ }
+ count = 3 * i + 4;
+ EXPECT_EQ((int)[[aWindow.get() tabs] count], count);
+ }
+
+ count = (int)[[aWindow.get() tabs] count];
+ for (int i = 0; i < 5; ++i) {
+ for(int j = 0; j < 3; ++j) {
+ [aWindow.get() removeFromTabsAtIndex:0];
+ }
+ count = count - 3;
+ EXPECT_EQ((int)[[aWindow.get() tabs] count], count);
+ }
+}
+
+// Getting and setting values from the NSWindow.
+IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, NSWindowTest) {
+ scoped_nsobject<WindowAppleScript> aWindow(
+ [[WindowAppleScript alloc] initWithBrowser:browser()]);
+ [aWindow.get() setValue:[NSNumber numberWithBool:YES]
+ forKey:@"isMiniaturized"];
+ EXPECT_TRUE([[aWindow.get() valueForKey:@"isMiniaturized"] boolValue]);
+ [aWindow.get() setValue:[NSNumber numberWithBool:NO]
+ forKey:@"isMiniaturized"];
+ EXPECT_FALSE([[aWindow.get() valueForKey:@"isMiniaturized"] boolValue]);
+}
+
+// Getting and setting the active tab.
+IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, ActiveTab) {
+ scoped_nsobject<WindowAppleScript> aWindow(
+ [[WindowAppleScript alloc] initWithBrowser:browser()]);
+ scoped_nsobject<TabAppleScript> aTab([[TabAppleScript alloc] init]);
+ [aWindow.get() insertInTabs:aTab.get()];
+ [aWindow.get() setActiveTabIndex:[NSNumber numberWithInt:2]];
+ EXPECT_EQ(2, [[aWindow.get() activeTabIndex] intValue]);
+ TabAppleScript* tab2 = [[aWindow.get() tabs] objectAtIndex:1];
+ EXPECT_NSEQ([[aWindow.get() activeTab] uniqueID],
+ [tab2 uniqueID]);
+}
+
+// Order of windows.
+IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, WindowOrder) {
+ scoped_nsobject<WindowAppleScript> window2(
+ [[WindowAppleScript alloc] initWithBrowser:browser()]);
+ scoped_nsobject<WindowAppleScript> window1(
+ [[WindowAppleScript alloc] init]);
+ EXPECT_EQ([window1.get() windowComparator:window2.get()], NSOrderedAscending);
+ EXPECT_EQ([window2.get() windowComparator:window1.get()],
+ NSOrderedDescending);
+}
diff --git a/chrome/browser/ui/cocoa/authorization_util.h b/chrome/browser/ui/cocoa/authorization_util.h
new file mode 100644
index 0000000..9694998
--- /dev/null
+++ b/chrome/browser/ui/cocoa/authorization_util.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_AUTHORIZATION_UTIL_H_
+#define CHROME_BROWSER_UI_COCOA_AUTHORIZATION_UTIL_H_
+#pragma once
+
+// AuthorizationExecuteWithPrivileges fork()s and exec()s the tool, but it
+// does not wait() for it. It also doesn't provide the caller with access to
+// the forked pid. If used irresponsibly, zombie processes will accumulate.
+//
+// Apple's really gotten us between a rock and a hard place, here.
+//
+// Fortunately, AuthorizationExecuteWithPrivileges does give access to the
+// tool's stdout (and stdin) via a FILE* pipe. The tool can output its pid
+// to this pipe, and the main program can read it, and then have something
+// that it can wait() for.
+//
+// The contract is that any tool executed by the wrappers declared in this
+// file must print its pid to stdout on a line by itself before doing anything
+// else.
+//
+// http://developer.apple.com/mac/library/samplecode/BetterAuthorizationSample/listing1.html
+// (Look for "What's This About Zombies?")
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <Security/Authorization.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+namespace authorization_util {
+
+// Obtains an AuthorizationRef that can be used to run commands as root. If
+// necessary, prompts the user for authentication. If the user is prompted,
+// |prompt| will be used as the prompt string and an icon appropriate for the
+// application will be displayed in a prompt dialog. Note that the system
+// appends its own text to the prompt string. Returns NULL on failure.
+AuthorizationRef AuthorizationCreateToRunAsRoot(CFStringRef prompt);
+
+// Calls straight through to AuthorizationExecuteWithPrivileges. If that
+// call succeeds, |pid| will be set to the pid of the executed tool. If the
+// pid can't be determined, |pid| will be set to -1. |pid| must not be NULL.
+// |pipe| may be NULL, but the tool will always be executed with a pipe in
+// order to read the pid from its stdout.
+OSStatus ExecuteWithPrivilegesAndGetPID(AuthorizationRef authorization,
+ const char* tool_path,
+ AuthorizationFlags options,
+ const char** arguments,
+ FILE** pipe,
+ pid_t* pid);
+
+// Calls ExecuteWithPrivilegesAndGetPID, and if that call succeeds, calls
+// waitpid() to wait for the process to exit. If waitpid() succeeds, the
+// exit status is placed in |exit_status|, otherwise, -1 is stored.
+// |exit_status| may be NULL and this function will still wait for the process
+// to exit.
+OSStatus ExecuteWithPrivilegesAndWait(AuthorizationRef authorization,
+ const char* tool_path,
+ AuthorizationFlags options,
+ const char** arguments,
+ FILE** pipe,
+ int* exit_status);
+
+} // namespace authorization_util
+
+#endif // CHROME_BROWSER_UI_COCOA_AUTHORIZATION_UTIL_H_
diff --git a/chrome/browser/ui/cocoa/authorization_util.mm b/chrome/browser/ui/cocoa/authorization_util.mm
new file mode 100644
index 0000000..5893711
--- /dev/null
+++ b/chrome/browser/ui/cocoa/authorization_util.mm
@@ -0,0 +1,183 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/authorization_util.h"
+
+#import <Foundation/Foundation.h>
+#include <sys/wait.h>
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/eintr_wrapper.h"
+#include "base/logging.h"
+#import "base/mac_util.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
+#include "chrome/browser/ui/cocoa/scoped_authorizationref.h"
+
+namespace authorization_util {
+
+AuthorizationRef AuthorizationCreateToRunAsRoot(CFStringRef prompt) {
+ // Create an empty AuthorizationRef.
+ scoped_AuthorizationRef authorization;
+ OSStatus status = AuthorizationCreate(NULL,
+ kAuthorizationEmptyEnvironment,
+ kAuthorizationFlagDefaults,
+ &authorization);
+ if (status != errAuthorizationSuccess) {
+ LOG(ERROR) << "AuthorizationCreate: " << status;
+ return NULL;
+ }
+
+ // Specify the "system.privilege.admin" right, which allows
+ // AuthorizationExecuteWithPrivileges to run commands as root.
+ AuthorizationItem right_items[] = {
+ {kAuthorizationRightExecute, 0, NULL, 0}
+ };
+ AuthorizationRights rights = {arraysize(right_items), right_items};
+
+ // product_logo_32.png is used instead of app.icns because Authorization
+ // Services can't deal with .icns files.
+ NSString* icon_path =
+ [mac_util::MainAppBundle() pathForResource:@"product_logo_32"
+ ofType:@"png"];
+ const char* icon_path_c = [icon_path fileSystemRepresentation];
+ size_t icon_path_length = icon_path_c ? strlen(icon_path_c) : 0;
+
+ // The OS will append " Type an administrator's name and password to allow
+ // <CFBundleDisplayName> to make changes."
+ NSString* prompt_ns = mac_util::CFToNSCast(prompt);
+ const char* prompt_c = [prompt_ns UTF8String];
+ size_t prompt_length = prompt_c ? strlen(prompt_c) : 0;
+
+ AuthorizationItem environment_items[] = {
+ {kAuthorizationEnvironmentIcon, icon_path_length, (void*)icon_path_c, 0},
+ {kAuthorizationEnvironmentPrompt, prompt_length, (void*)prompt_c, 0}
+ };
+
+ AuthorizationEnvironment environment = {arraysize(environment_items),
+ environment_items};
+
+ AuthorizationFlags flags = kAuthorizationFlagDefaults |
+ kAuthorizationFlagInteractionAllowed |
+ kAuthorizationFlagExtendRights |
+ kAuthorizationFlagPreAuthorize;
+
+ status = AuthorizationCopyRights(authorization,
+ &rights,
+ &environment,
+ flags,
+ NULL);
+ if (status != errAuthorizationSuccess) {
+ if (status != errAuthorizationCanceled) {
+ LOG(ERROR) << "AuthorizationCopyRights: " << status;
+ }
+ return NULL;
+ }
+
+ return authorization.release();
+}
+
+OSStatus ExecuteWithPrivilegesAndGetPID(AuthorizationRef authorization,
+ const char* tool_path,
+ AuthorizationFlags options,
+ const char** arguments,
+ FILE** pipe,
+ pid_t* pid) {
+ // pipe may be NULL, but this function needs one. In that case, use a local
+ // pipe.
+ FILE* local_pipe;
+ FILE** pipe_pointer;
+ if (pipe) {
+ pipe_pointer = pipe;
+ } else {
+ pipe_pointer = &local_pipe;
+ }
+
+ // AuthorizationExecuteWithPrivileges wants |char* const*| for |arguments|,
+ // but it doesn't actually modify the arguments, and that type is kind of
+ // silly and callers probably aren't dealing with that. Put the cast here
+ // to make things a little easier on callers.
+ OSStatus status = AuthorizationExecuteWithPrivileges(authorization,
+ tool_path,
+ options,
+ (char* const*)arguments,
+ pipe_pointer);
+ if (status != errAuthorizationSuccess) {
+ return status;
+ }
+
+ int line_pid = -1;
+ size_t line_length = 0;
+ char* line_c = fgetln(*pipe_pointer, &line_length);
+ if (line_c) {
+ if (line_length > 0 && line_c[line_length - 1] == '\n') {
+ // line_c + line_length is the start of the next line if there is one.
+ // Back up one character.
+ --line_length;
+ }
+ std::string line(line_c, line_length);
+ if (!base::StringToInt(line, &line_pid)) {
+ // StringToInt may have set line_pid to something, but if the conversion
+ // was imperfect, use -1.
+ LOG(ERROR) << "ExecuteWithPrivilegesAndGetPid: funny line: " << line;
+ line_pid = -1;
+ }
+ } else {
+ LOG(ERROR) << "ExecuteWithPrivilegesAndGetPid: no line";
+ }
+
+ if (!pipe) {
+ fclose(*pipe_pointer);
+ }
+
+ if (pid) {
+ *pid = line_pid;
+ }
+
+ return status;
+}
+
+OSStatus ExecuteWithPrivilegesAndWait(AuthorizationRef authorization,
+ const char* tool_path,
+ AuthorizationFlags options,
+ const char** arguments,
+ FILE** pipe,
+ int* exit_status) {
+ pid_t pid;
+ OSStatus status = ExecuteWithPrivilegesAndGetPID(authorization,
+ tool_path,
+ options,
+ arguments,
+ pipe,
+ &pid);
+ if (status != errAuthorizationSuccess) {
+ return status;
+ }
+
+ // exit_status may be NULL, but this function needs it. In that case, use a
+ // local version.
+ int local_exit_status;
+ int* exit_status_pointer;
+ if (exit_status) {
+ exit_status_pointer = exit_status;
+ } else {
+ exit_status_pointer = &local_exit_status;
+ }
+
+ if (pid != -1) {
+ pid_t wait_result = HANDLE_EINTR(waitpid(pid, exit_status_pointer, 0));
+ if (wait_result != pid) {
+ PLOG(ERROR) << "waitpid";
+ *exit_status_pointer = -1;
+ }
+ } else {
+ *exit_status_pointer = -1;
+ }
+
+ return status;
+}
+
+} // namespace authorization_util
diff --git a/chrome/browser/ui/cocoa/back_forward_menu_controller.h b/chrome/browser/ui/cocoa/back_forward_menu_controller.h
new file mode 100644
index 0000000..13bb585
--- /dev/null
+++ b/chrome/browser/ui/cocoa/back_forward_menu_controller.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_BACK_FORWARD_MENU_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_BACK_FORWARD_MENU_CONTROLLER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/ui/toolbar/back_forward_menu_model.h"
+
+@class DelayedMenuButton;
+
+typedef BackForwardMenuModel::ModelType BackForwardMenuType;
+const BackForwardMenuType BACK_FORWARD_MENU_TYPE_BACK =
+ BackForwardMenuModel::BACKWARD_MENU;
+const BackForwardMenuType BACK_FORWARD_MENU_TYPE_FORWARD =
+ BackForwardMenuModel::FORWARD_MENU;
+
+// A class that manages the back/forward menu (and delayed-menu button, and
+// model).
+
+@interface BackForwardMenuController : NSObject {
+ @private
+ BackForwardMenuType type_;
+ DelayedMenuButton* button_; // Weak; comes from nib.
+ scoped_ptr<BackForwardMenuModel> model_;
+ scoped_nsobject<NSMenu> backForwardMenu_;
+}
+
+// Type (back or forwards); can only be set on initialization.
+@property(readonly, nonatomic) BackForwardMenuType type;
+
+- (id)initWithBrowser:(Browser*)browser
+ modelType:(BackForwardMenuType)type
+ button:(DelayedMenuButton*)button;
+
+@end // @interface BackForwardMenuController
+
+#endif // CHROME_BROWSER_UI_COCOA_BACK_FORWARD_MENU_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/back_forward_menu_controller.mm b/chrome/browser/ui/cocoa/back_forward_menu_controller.mm
new file mode 100644
index 0000000..9db04cf
--- /dev/null
+++ b/chrome/browser/ui/cocoa/back_forward_menu_controller.mm
@@ -0,0 +1,102 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/back_forward_menu_controller.h"
+
+#include "base/logging.h"
+#include "base/scoped_ptr.h"
+#include "base/sys_string_conversions.h"
+#import "chrome/browser/ui/cocoa/delayedmenu_button.h"
+#import "chrome/browser/ui/cocoa/event_utils.h"
+#include "chrome/browser/ui/toolbar/back_forward_menu_model.h"
+#include "skia/ext/skia_utils_mac.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+using base::SysUTF16ToNSString;
+using gfx::SkBitmapToNSImage;
+
+@implementation BackForwardMenuController
+
+// Accessors and mutators:
+
+@synthesize type = type_;
+
+// Own methods:
+
+- (id)initWithBrowser:(Browser*)browser
+ modelType:(BackForwardMenuType)type
+ button:(DelayedMenuButton*)button {
+ if ((self = [super init])) {
+ type_ = type;
+ button_ = button;
+ model_.reset(new BackForwardMenuModel(browser, type_));
+ DCHECK(model_.get());
+ backForwardMenu_.reset([[NSMenu alloc] initWithTitle:@""]);
+ DCHECK(backForwardMenu_.get());
+ [backForwardMenu_ setDelegate:self];
+
+ [button_ setAttachedMenu:backForwardMenu_];
+ [button_ setAttachedMenuEnabled:YES];
+ }
+ return self;
+}
+
+// Methods as delegate:
+
+// Called by backForwardMenu_ just before tracking begins.
+//TODO(viettrungluu): should we do anything for chapter stops (see model)?
+- (void)menuNeedsUpdate:(NSMenu*)menu {
+ DCHECK(menu == backForwardMenu_);
+
+ // Remove old menu items (backwards order is as good as any).
+ for (NSInteger i = [menu numberOfItems]; i > 0; i--)
+ [menu removeItemAtIndex:(i - 1)];
+
+ // 0-th item must be blank. (This is because we use a pulldown list, for which
+ // Cocoa uses the 0-th item as "title" in the button.)
+ [menu insertItemWithTitle:@""
+ action:nil
+ keyEquivalent:@""
+ atIndex:0];
+ for (int menuID = 0; menuID < model_->GetItemCount(); menuID++) {
+ if (model_->IsSeparator(menuID)) {
+ [menu insertItem:[NSMenuItem separatorItem]
+ atIndex:(menuID + 1)];
+ } else {
+ // Create a menu item with the right label.
+ NSMenuItem* menuItem = [[NSMenuItem alloc]
+ initWithTitle:SysUTF16ToNSString(model_->GetLabelAt(menuID))
+ action:nil
+ keyEquivalent:@""];
+ [menuItem autorelease];
+
+ SkBitmap icon;
+ // Icon (if it has one).
+ if (model_->GetIconAt(menuID, &icon))
+ [menuItem setImage:SkBitmapToNSImage(icon)];
+
+ // This will make it call our |-executeMenuItem:| method. We store the
+ // |menuID| (or |menu_id|) in the tag.
+ [menuItem setTag:menuID];
+ [menuItem setTarget:self];
+ [menuItem setAction:@selector(executeMenuItem:)];
+
+ // Put it in the menu!
+ [menu insertItem:menuItem
+ atIndex:(menuID + 1)];
+ }
+ }
+}
+
+// Action methods:
+
+- (void)executeMenuItem:(id)sender {
+ DCHECK([sender isKindOfClass:[NSMenuItem class]]);
+ int menuID = [sender tag];
+ model_->ActivatedAtWithDisposition(
+ menuID,
+ event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]));
+}
+
+@end // @implementation BackForwardMenuController
diff --git a/chrome/browser/ui/cocoa/background_gradient_view.h b/chrome/browser/ui/cocoa/background_gradient_view.h
new file mode 100644
index 0000000..d72fa57
--- /dev/null
+++ b/chrome/browser/ui/cocoa/background_gradient_view.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_BACKGROUND_GRADIENT_VIEW_H_
+#define CHROME_BROWSER_UI_COCOA_BACKGROUND_GRADIENT_VIEW_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+// A custom view that draws a 'standard' background gradient.
+// Base class for other Chromium views.
+@interface BackgroundGradientView : NSView {
+ @private
+ BOOL showsDivider_;
+}
+
+// The color used for the bottom stroke. Public so subclasses can use.
+- (NSColor *)strokeColor;
+
+// Draws the background for this view. Make sure that your patternphase
+// is set up correctly in your graphics context before calling.
+- (void)drawBackground;
+
+// Controls whether the bar draws a dividing line at the bottom.
+@property(nonatomic, assign) BOOL showsDivider;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_BACKGROUND_GRADIENT_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/background_gradient_view.mm b/chrome/browser/ui/cocoa/background_gradient_view.mm
new file mode 100644
index 0000000..1c5735f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/background_gradient_view.mm
@@ -0,0 +1,81 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/background_gradient_view.h"
+
+#import "chrome/browser/themes/browser_theme_provider.h"
+#import "chrome/browser/ui/cocoa/themed_window.h"
+#include "grit/theme_resources.h"
+
+#define kToolbarTopOffset 12
+#define kToolbarMaxHeight 100
+
+@implementation BackgroundGradientView
+@synthesize showsDivider = showsDivider_;
+
+- (id)initWithFrame:(NSRect)frameRect {
+ self = [super initWithFrame:frameRect];
+ if (self != nil) {
+ showsDivider_ = YES;
+ }
+ return self;
+}
+
+- (void)awakeFromNib {
+ showsDivider_ = YES;
+}
+
+- (void)setShowsDivider:(BOOL)show {
+ showsDivider_ = show;
+ [self setNeedsDisplay:YES];
+}
+
+- (void)drawBackground {
+ BOOL isKey = [[self window] isKeyWindow];
+ ThemeProvider* themeProvider = [[self window] themeProvider];
+ if (themeProvider) {
+ NSColor* backgroundImageColor =
+ themeProvider->GetNSImageColorNamed(IDR_THEME_TOOLBAR, false);
+ if (backgroundImageColor) {
+ [backgroundImageColor set];
+ NSRectFill([self bounds]);
+ } else {
+ CGFloat winHeight = NSHeight([[self window] frame]);
+ NSGradient* gradient = themeProvider->GetNSGradient(
+ isKey ? BrowserThemeProvider::GRADIENT_TOOLBAR :
+ BrowserThemeProvider::GRADIENT_TOOLBAR_INACTIVE);
+ NSPoint startPoint =
+ [self convertPoint:NSMakePoint(0, winHeight - kToolbarTopOffset)
+ fromView:nil];
+ NSPoint endPoint =
+ NSMakePoint(0, winHeight - kToolbarTopOffset - kToolbarMaxHeight);
+ endPoint = [self convertPoint:endPoint fromView:nil];
+
+ [gradient drawFromPoint:startPoint
+ toPoint:endPoint
+ options:(NSGradientDrawsBeforeStartingLocation |
+ NSGradientDrawsAfterEndingLocation)];
+ }
+
+ if (showsDivider_) {
+ // Draw bottom stroke
+ [[self strokeColor] set];
+ NSRect borderRect, contentRect;
+ NSDivideRect([self bounds], &borderRect, &contentRect, 1, NSMinYEdge);
+ NSRectFillUsingOperation(borderRect, NSCompositeSourceOver);
+ }
+ }
+}
+
+- (NSColor*)strokeColor {
+ BOOL isKey = [[self window] isKeyWindow];
+ ThemeProvider* themeProvider = [[self window] themeProvider];
+ if (!themeProvider)
+ return [NSColor blackColor];
+ return themeProvider->GetNSColor(
+ isKey ? BrowserThemeProvider::COLOR_TOOLBAR_STROKE :
+ BrowserThemeProvider::COLOR_TOOLBAR_STROKE_INACTIVE, true);
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/background_gradient_view_unittest.mm b/chrome/browser/ui/cocoa/background_gradient_view_unittest.mm
new file mode 100644
index 0000000..693c21a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/background_gradient_view_unittest.mm
@@ -0,0 +1,47 @@
+// Copyright (c) 2009 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 "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/background_gradient_view.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+// Since BackgroundGradientView doesn't do any drawing by default, we
+// create a subclass to call its draw method for us.
+@interface BackgroundGradientSubClassTest : BackgroundGradientView
+@end
+
+@implementation BackgroundGradientSubClassTest
+- (void)drawRect:(NSRect)rect {
+ [self drawBackground];
+}
+@end
+
+namespace {
+
+class BackgroundGradientViewTest : public CocoaTest {
+ public:
+ BackgroundGradientViewTest() {
+ NSRect frame = NSMakeRect(0, 0, 100, 30);
+ scoped_nsobject<BackgroundGradientSubClassTest> view;
+ view.reset([[BackgroundGradientSubClassTest alloc] initWithFrame:frame]);
+ view_ = view.get();
+ [[test_window() contentView] addSubview:view_];
+ }
+
+ BackgroundGradientSubClassTest* view_;
+};
+
+TEST_VIEW(BackgroundGradientViewTest, view_)
+
+// Test drawing, mostly to ensure nothing leaks or crashes.
+TEST_F(BackgroundGradientViewTest, DisplayWithDivider) {
+ [view_ setShowsDivider:YES];
+ [view_ display];
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/background_tile_view.h b/chrome/browser/ui/cocoa/background_tile_view.h
new file mode 100644
index 0000000..9a08113
--- /dev/null
+++ b/chrome/browser/ui/cocoa/background_tile_view.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_BACKGROUND_TILE_VIEW_H_
+#define CHROME_BROWSER_UI_COCOA_BACKGROUND_TILE_VIEW_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+// A custom view that draws a image tiled as the background. This isn't meant
+// to be used where themes might be need, and is for other windows (about box).
+
+@interface BackgroundTileView : NSView {
+ @private
+ BOOL showsDivider_;
+ NSImage* tileImage_;
+}
+
+@property(nonatomic, retain) NSImage* tileImage;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_BACKGROUND_TILE_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/background_tile_view.mm b/chrome/browser/ui/cocoa/background_tile_view.mm
new file mode 100644
index 0000000..e63141b
--- /dev/null
+++ b/chrome/browser/ui/cocoa/background_tile_view.mm
@@ -0,0 +1,32 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/background_tile_view.h"
+
+@implementation BackgroundTileView
+@synthesize tileImage = tileImage_;
+
+- (void)setTileImage:(NSImage*)tileImage {
+ [tileImage_ autorelease];
+ tileImage_ = [tileImage retain];
+ [self setNeedsDisplay:YES];
+}
+
+- (void)drawRect:(NSRect)rect {
+ // Tile within the view, so set the phase to start at the view bottom.
+ NSPoint phase = NSMakePoint(0.0, NSMinY([self frame]));
+ [[NSGraphicsContext currentContext] setPatternPhase:phase];
+
+ if (tileImage_) {
+ NSColor *color = [NSColor colorWithPatternImage:tileImage_];
+ [color set];
+ } else {
+ // Something to catch the missing image
+ [[NSColor magentaColor] set];
+ }
+
+ NSRectFill([self bounds]);
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/background_tile_view_unittest.mm b/chrome/browser/ui/cocoa/background_tile_view_unittest.mm
new file mode 100644
index 0000000..4af5751
--- /dev/null
+++ b/chrome/browser/ui/cocoa/background_tile_view_unittest.mm
@@ -0,0 +1,37 @@
+// Copyright (c) 2009 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 "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/background_tile_view.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class BackgroundTileViewTest : public CocoaTest {
+ public:
+ BackgroundTileViewTest() {
+ NSRect frame = NSMakeRect(0, 0, 100, 30);
+ scoped_nsobject<BackgroundTileView> view([[BackgroundTileView alloc]
+ initWithFrame:frame]);
+ view_ = view.get();
+ [[test_window() contentView] addSubview:view_];
+ }
+
+ BackgroundTileView *view_;
+};
+
+TEST_VIEW(BackgroundTileViewTest, view_)
+
+// Test drawing with an Image
+TEST_F(BackgroundTileViewTest, DisplayImage) {
+ NSImage* image = [NSImage imageNamed:@"NSApplicationIcon"];
+ [view_ setTileImage:image];
+ [view_ display];
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/base_bubble_controller.h b/chrome/browser/ui/cocoa/base_bubble_controller.h
new file mode 100644
index 0000000..99b491a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/base_bubble_controller.h
@@ -0,0 +1,67 @@
+// 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>
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_ptr.h"
+
+namespace BaseBubbleControllerInternal {
+class Bridge;
+}
+
+@class InfoBubbleView;
+
+// Base class for bubble controllers. Manages a xib that contains an
+// InfoBubbleWindow which contains an InfoBubbleView. Contains code to close
+// the bubble window on clicks outside of the window, and the like.
+// To use this class:
+// 1. Create a new xib that contains a window. Change the window's class to
+// InfoBubbleWindow. Give it a child view that autosizes to the window's full
+// size, give it class InfoBubbleView. Make the controller the window's
+// delegate.
+// 2. Create a subclass of BaseBubbleController.
+// 3. Change the xib's File Owner to your subclass.
+// 4. Hook up the File Owner's |bubble_| to the InfoBubbleView in the xib.
+@interface BaseBubbleController : NSWindowController<NSWindowDelegate> {
+ @private
+ NSWindow* parentWindow_; // weak
+ NSPoint anchor_;
+ IBOutlet InfoBubbleView* bubble_; // to set arrow position
+ // Bridge that listens for notifications.
+ scoped_ptr<BaseBubbleControllerInternal::Bridge> base_bridge_;
+}
+
+@property (nonatomic, readonly) NSWindow* parentWindow;
+@property (nonatomic, assign) NSPoint anchorPoint;
+@property (nonatomic, readonly) InfoBubbleView* bubble;
+
+// Creates a bubble. |nibPath| is just the basename, e.g. @"FirstRunBubble".
+// |anchoredAt| is in screen space. You need to call -showWindow: to make the
+// bubble visible. It will autorelease itself when the user dismisses the
+// bubble.
+// This is the designated initializer.
+- (id)initWithWindowNibPath:(NSString*)nibPath
+ parentWindow:(NSWindow*)parentWindow
+ anchoredAt:(NSPoint)anchoredAt;
+
+
+// Creates a bubble. |nibPath| is just the basename, e.g. @"FirstRunBubble".
+// |view| must be in a window. The bubble will point at |offset| relative to
+// |view|'s lower left corner. You need to call -showWindow: to make the
+// bubble visible. It will autorelease itself when the user dismisses the
+// bubble.
+- (id)initWithWindowNibPath:(NSString*)nibPath
+ relativeToView:(NSView*)view
+ offset:(NSPoint)offset;
+
+
+// For subclasses that do not load from a XIB, this will simply set the instance
+// variables appropriately. This will also replace the |-[self window]|'s
+// contentView with an instance of InfoBubbleView.
+- (id)initWithWindow:(NSWindow*)theWindow
+ parentWindow:(NSWindow*)parentWindow
+ anchoredAt:(NSPoint)anchoredAt;
+
+@end
diff --git a/chrome/browser/ui/cocoa/base_bubble_controller.mm b/chrome/browser/ui/cocoa/base_bubble_controller.mm
new file mode 100644
index 0000000..3c1e9d2
--- /dev/null
+++ b/chrome/browser/ui/cocoa/base_bubble_controller.mm
@@ -0,0 +1,200 @@
+// 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 "chrome/browser/ui/cocoa/base_bubble_controller.h"
+
+#include "app/l10n_util.h"
+#include "base/logging.h"
+#include "base/mac_util.h"
+#include "base/scoped_nsobject.h"
+#include "base/string_util.h"
+#import "chrome/browser/ui/cocoa/info_bubble_view.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
+#include "grit/generated_resources.h"
+
+@interface BaseBubbleController (Private)
+- (void)updateOriginFromAnchor;
+@end
+
+namespace BaseBubbleControllerInternal {
+
+// This bridge listens for notifications so that the bubble closes when a user
+// switches tabs (including by opening a new one).
+class Bridge : public NotificationObserver {
+ public:
+ explicit Bridge(BaseBubbleController* controller) : controller_(controller) {
+ registrar_.Add(this, NotificationType::TAB_CONTENTS_HIDDEN,
+ NotificationService::AllSources());
+ }
+
+ // NotificationObserver:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ [controller_ close];
+ }
+
+ private:
+ BaseBubbleController* controller_; // Weak, owns this.
+ NotificationRegistrar registrar_;
+};
+
+} // namespace BaseBubbleControllerInternal
+
+@implementation BaseBubbleController
+
+@synthesize parentWindow = parentWindow_;
+@synthesize anchorPoint = anchor_;
+@synthesize bubble = bubble_;
+
+- (id)initWithWindowNibPath:(NSString*)nibPath
+ parentWindow:(NSWindow*)parentWindow
+ anchoredAt:(NSPoint)anchoredAt {
+ nibPath = [mac_util::MainAppBundle() pathForResource:nibPath
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibPath owner:self])) {
+ parentWindow_ = parentWindow;
+ anchor_ = anchoredAt;
+
+ // Watch to see if the parent window closes, and if so, close this one.
+ NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+ [center addObserver:self
+ selector:@selector(parentWindowWillClose:)
+ name:NSWindowWillCloseNotification
+ object:parentWindow_];
+ }
+ return self;
+}
+
+- (id)initWithWindowNibPath:(NSString*)nibPath
+ relativeToView:(NSView*)view
+ offset:(NSPoint)offset {
+ DCHECK([view window]);
+ NSWindow* window = [view window];
+ NSRect bounds = [view convertRect:[view bounds] toView:nil];
+ NSPoint anchor = NSMakePoint(NSMinX(bounds) + offset.x,
+ NSMinY(bounds) + offset.y);
+ anchor = [window convertBaseToScreen:anchor];
+ return [self initWithWindowNibPath:nibPath
+ parentWindow:window
+ anchoredAt:anchor];
+}
+
+- (id)initWithWindow:(NSWindow*)theWindow
+ parentWindow:(NSWindow*)parentWindow
+ anchoredAt:(NSPoint)anchoredAt {
+ DCHECK(theWindow);
+ if ((self = [super initWithWindow:theWindow])) {
+ parentWindow_ = parentWindow;
+ anchor_ = anchoredAt;
+
+ DCHECK(![[self window] delegate]);
+ [theWindow setDelegate:self];
+
+ scoped_nsobject<InfoBubbleView> contentView(
+ [[InfoBubbleView alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)]);
+ [theWindow setContentView:contentView.get()];
+ bubble_ = contentView.get();
+
+ // Watch to see if the parent window closes, and if so, close this one.
+ NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+ [center addObserver:self
+ selector:@selector(parentWindowWillClose:)
+ name:NSWindowWillCloseNotification
+ object:parentWindow_];
+
+ [self awakeFromNib];
+ }
+ return self;
+}
+
+- (void)awakeFromNib {
+ // Check all connections have been made in Interface Builder.
+ DCHECK([self window]);
+ DCHECK(bubble_);
+ DCHECK_EQ(self, [[self window] delegate]);
+
+ base_bridge_.reset(new BaseBubbleControllerInternal::Bridge(self));
+
+ [bubble_ setArrowLocation:info_bubble::kTopRight];
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+- (void)setAnchorPoint:(NSPoint)anchor {
+ anchor_ = anchor;
+ [self updateOriginFromAnchor];
+}
+
+- (void)parentWindowWillClose:(NSNotification*)notification {
+ [self close];
+}
+
+- (void)windowWillClose:(NSNotification*)notification {
+ // We caught a close so we don't need to watch for the parent closing.
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [self autorelease];
+}
+
+// We want this to be a child of a browser window. addChildWindow:
+// (called from this function) will bring the window on-screen;
+// unfortunately, [NSWindowController showWindow:] will also bring it
+// on-screen (but will cause unexpected changes to the window's
+// position). We cannot have an addChildWindow: and a subsequent
+// showWindow:. Thus, we have our own version.
+- (void)showWindow:(id)sender {
+ NSWindow* window = [self window]; // completes nib load
+ [self updateOriginFromAnchor];
+ [parentWindow_ addChildWindow:window ordered:NSWindowAbove];
+ [window makeKeyAndOrderFront:self];
+}
+
+- (void)close {
+ [parentWindow_ removeChildWindow:[self window]];
+ [super close];
+}
+
+// The controller is the delegate of the window so it receives did resign key
+// notifications. When key is resigned mirror Windows behavior and close the
+// window.
+- (void)windowDidResignKey:(NSNotification*)notification {
+ NSWindow* window = [self window];
+ DCHECK_EQ([notification object], window);
+ if ([window isVisible]) {
+ // If the window isn't visible, it is already closed, and this notification
+ // has been sent as part of the closing operation, so no need to close.
+ [self close];
+ }
+}
+
+// By implementing this, ESC causes the window to go away.
+- (IBAction)cancel:(id)sender {
+ // This is not a "real" cancel as potential changes to the radio group are not
+ // undone. That's ok.
+ [self close];
+}
+
+// Takes the |anchor_| point and adjusts the window's origin accordingly.
+- (void)updateOriginFromAnchor {
+ NSWindow* window = [self window];
+ NSPoint origin = anchor_;
+ NSSize offsets = NSMakeSize(info_bubble::kBubbleArrowXOffset +
+ info_bubble::kBubbleArrowWidth / 2.0, 0);
+ offsets = [[parentWindow_ contentView] convertSize:offsets toView:nil];
+ if ([bubble_ arrowLocation] == info_bubble::kTopRight) {
+ origin.x -= NSWidth([window frame]) - offsets.width;
+ } else {
+ origin.x -= offsets.width;
+ }
+ origin.y -= NSHeight([window frame]);
+ [window setFrameOrigin:origin];
+}
+
+@end // BaseBubbleController
diff --git a/chrome/browser/ui/cocoa/base_view.h b/chrome/browser/ui/cocoa/base_view.h
new file mode 100644
index 0000000..0a8da9e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/base_view.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_BASE_VIEW_H_
+#define CHROME_BROWSER_UI_COCOA_BASE_VIEW_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+#include "gfx/rect.h"
+
+// A view that provides common functionality that many views will need:
+// - Automatic registration for mouse-moved events.
+// - Funneling of mouse and key events to two methods
+// - Coordinate conversion utilities
+
+@interface BaseView : NSView {
+ @private
+ NSTrackingArea *trackingArea_;
+ BOOL dragging_;
+ scoped_nsobject<NSEvent> pendingExitEvent_;
+}
+
+- (id)initWithFrame:(NSRect)frame;
+
+// Override these methods in a subclass.
+- (void)mouseEvent:(NSEvent *)theEvent;
+- (void)keyEvent:(NSEvent *)theEvent;
+
+// Useful rect conversions (doing coordinate flipping)
+- (gfx::Rect)flipNSRectToRect:(NSRect)rect;
+- (NSRect)flipRectToNSRect:(gfx::Rect)rect;
+
+@end
+
+// A notification that a view may issue when it receives first responder status.
+// The name is |kViewDidBecomeFirstResponder|, the object is the view, and the
+// NSSelectionDirection is wrapped in an NSNumber under the key
+// |kSelectionDirection|.
+extern NSString* kViewDidBecomeFirstResponder;
+extern NSString* kSelectionDirection;
+
+#endif // CHROME_BROWSER_UI_COCOA_BASE_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/base_view.mm b/chrome/browser/ui/cocoa/base_view.mm
new file mode 100644
index 0000000..b26c390
--- /dev/null
+++ b/chrome/browser/ui/cocoa/base_view.mm
@@ -0,0 +1,147 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/base_view.h"
+
+NSString* kViewDidBecomeFirstResponder =
+ @"Chromium.kViewDidBecomeFirstResponder";
+NSString* kSelectionDirection = @"Chromium.kSelectionDirection";
+
+@implementation BaseView
+
+- (id)initWithFrame:(NSRect)frame {
+ self = [super initWithFrame:frame];
+ if (self) {
+ trackingArea_ =
+ [[NSTrackingArea alloc] initWithRect:frame
+ options:NSTrackingMouseMoved |
+ NSTrackingMouseEnteredAndExited |
+ NSTrackingActiveInActiveApp |
+ NSTrackingInVisibleRect
+ owner:self
+ userInfo:nil];
+ [self addTrackingArea:trackingArea_];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [self removeTrackingArea:trackingArea_];
+ [trackingArea_ release];
+
+ [super dealloc];
+}
+
+- (void)mouseEvent:(NSEvent *)theEvent {
+ // This method left intentionally blank.
+}
+
+- (void)keyEvent:(NSEvent *)theEvent {
+ // This method left intentionally blank.
+}
+
+- (void)mouseDown:(NSEvent *)theEvent {
+ dragging_ = YES;
+ [self mouseEvent:theEvent];
+}
+
+- (void)rightMouseDown:(NSEvent *)theEvent {
+ [self mouseEvent:theEvent];
+}
+
+- (void)otherMouseDown:(NSEvent *)theEvent {
+ [self mouseEvent:theEvent];
+}
+
+- (void)mouseUp:(NSEvent *)theEvent {
+ [self mouseEvent:theEvent];
+
+ dragging_ = NO;
+ if (pendingExitEvent_.get()) {
+ NSEvent* exitEvent =
+ [NSEvent enterExitEventWithType:NSMouseExited
+ location:[theEvent locationInWindow]
+ modifierFlags:[theEvent modifierFlags]
+ timestamp:[theEvent timestamp]
+ windowNumber:[theEvent windowNumber]
+ context:[theEvent context]
+ eventNumber:[pendingExitEvent_.get() eventNumber]
+ trackingNumber:[pendingExitEvent_.get() trackingNumber]
+ userData:[pendingExitEvent_.get() userData]];
+ [self mouseEvent:exitEvent];
+ pendingExitEvent_.reset();
+ }
+}
+
+- (void)rightMouseUp:(NSEvent *)theEvent {
+ [self mouseEvent:theEvent];
+}
+
+- (void)otherMouseUp:(NSEvent *)theEvent {
+ [self mouseEvent:theEvent];
+}
+
+- (void)mouseMoved:(NSEvent *)theEvent {
+ [self mouseEvent:theEvent];
+}
+
+- (void)mouseDragged:(NSEvent *)theEvent {
+ [self mouseEvent:theEvent];
+}
+
+- (void)rightMouseDragged:(NSEvent *)theEvent {
+ [self mouseEvent:theEvent];
+}
+
+- (void)otherMouseDragged:(NSEvent *)theEvent {
+ [self mouseEvent:theEvent];
+}
+
+- (void)mouseEntered:(NSEvent *)theEvent {
+ if (pendingExitEvent_.get()) {
+ pendingExitEvent_.reset();
+ return;
+ }
+
+ [self mouseEvent:theEvent];
+}
+
+- (void)mouseExited:(NSEvent *)theEvent {
+ // The tracking area will send an exit event even during a drag, which isn't
+ // how the event flow for drags should work. This stores the exit event, and
+ // sends it when the drag completes instead.
+ if (dragging_) {
+ pendingExitEvent_.reset([theEvent retain]);
+ return;
+ }
+
+ [self mouseEvent:theEvent];
+}
+
+- (void)keyDown:(NSEvent *)theEvent {
+ [self keyEvent:theEvent];
+}
+
+- (void)keyUp:(NSEvent *)theEvent {
+ [self keyEvent:theEvent];
+}
+
+- (void)flagsChanged:(NSEvent *)theEvent {
+ [self keyEvent:theEvent];
+}
+
+- (gfx::Rect)flipNSRectToRect:(NSRect)rect {
+ gfx::Rect new_rect(NSRectToCGRect(rect));
+ new_rect.set_y([self bounds].size.height - new_rect.y() - new_rect.height());
+ return new_rect;
+}
+
+- (NSRect)flipRectToNSRect:(gfx::Rect)rect {
+ NSRect new_rect(NSRectFromCGRect(rect.ToCGRect()));
+ new_rect.origin.y =
+ [self bounds].size.height - new_rect.origin.y - new_rect.size.height;
+ return new_rect;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/base_view_unittest.mm b/chrome/browser/ui/cocoa/base_view_unittest.mm
new file mode 100644
index 0000000..bd356b4
--- /dev/null
+++ b/chrome/browser/ui/cocoa/base_view_unittest.mm
@@ -0,0 +1,48 @@
+// Copyright (c) 2009 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 "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/base_view.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class BaseViewTest : public CocoaTest {
+ public:
+ BaseViewTest() {
+ NSRect frame = NSMakeRect(0, 0, 100, 100);
+ scoped_nsobject<BaseView> view([[BaseView alloc] initWithFrame:frame]);
+ view_ = view.get();
+ [[test_window() contentView] addSubview:view_];
+ }
+
+ BaseView* view_; // weak
+};
+
+TEST_VIEW(BaseViewTest, view_)
+
+// Convert a rect in |view_|'s Cocoa coordinate system to gfx::Rect's top-left
+// coordinate system. Repeat the process in reverse and make sure we come out
+// with the original rect.
+TEST_F(BaseViewTest, flipNSRectToRect) {
+ NSRect convert = NSMakeRect(10, 10, 50, 50);
+ gfx::Rect converted = [view_ flipNSRectToRect:convert];
+ EXPECT_EQ(converted.x(), 10);
+ EXPECT_EQ(converted.y(), 40); // Due to view being 100px tall.
+ EXPECT_EQ(converted.width(), convert.size.width);
+ EXPECT_EQ(converted.height(), convert.size.height);
+
+ // Go back the other way.
+ NSRect back_again = [view_ flipRectToNSRect:converted];
+ EXPECT_EQ(back_again.origin.x, convert.origin.x);
+ EXPECT_EQ(back_again.origin.y, convert.origin.y);
+ EXPECT_EQ(back_again.size.width, convert.size.width);
+ EXPECT_EQ(back_again.size.height, convert.size.height);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_all_tabs_controller.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_all_tabs_controller.h
new file mode 100644
index 0000000..505211c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_all_tabs_controller.h
@@ -0,0 +1,46 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_ALL_TABS_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_ALL_TABS_CONTROLLER_H_
+#pragma once
+
+#include <utility>
+#include <vector>
+
+#include "base/string16.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller.h"
+
+// A list of pairs containing the name and URL associated with each
+// currently active tab in the active browser window.
+typedef std::pair<string16, GURL> ActiveTabNameURLPair;
+typedef std::vector<ActiveTabNameURLPair> ActiveTabsNameURLPairVector;
+
+// A controller for the Bookmark All Tabs sheet which is presented upon
+// selecting the Bookmark All Tabs... menu item shown by the contextual
+// menu in the bookmarks bar.
+@interface BookmarkAllTabsController : BookmarkEditorBaseController {
+ @private
+ ActiveTabsNameURLPairVector activeTabPairsVector_;
+}
+
+- (id)initWithParentWindow:(NSWindow*)parentWindow
+ profile:(Profile*)profile
+ parent:(const BookmarkNode*)parent
+ configuration:(BookmarkEditor::Configuration)configuration;
+
+@end
+
+@interface BookmarkAllTabsController(TestingAPI)
+
+// Initializes the list of all tab names and URLs. Overridden by unit test
+// to provide canned test data.
+- (void)UpdateActiveTabPairs;
+
+// Provides testing access to tab pairs list.
+- (ActiveTabsNameURLPairVector*)activeTabPairsVector;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_ALL_TABS_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_all_tabs_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_all_tabs_controller.mm
new file mode 100644
index 0000000..5e8b0f2
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_all_tabs_controller.mm
@@ -0,0 +1,88 @@
+// 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 "chrome/browser/ui/cocoa/bookmarks/bookmark_all_tabs_controller.h"
+
+#include "app/l10n_util_mac.h"
+#include "base/string16.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "grit/generated_resources.h"
+
+@implementation BookmarkAllTabsController
+
+- (id)initWithParentWindow:(NSWindow*)parentWindow
+ profile:(Profile*)profile
+ parent:(const BookmarkNode*)parent
+ configuration:(BookmarkEditor::Configuration)configuration {
+ NSString* nibName = @"BookmarkAllTabs";
+ if ((self = [super initWithParentWindow:parentWindow
+ nibName:nibName
+ profile:profile
+ parent:parent
+ configuration:configuration])) {
+ }
+ return self;
+}
+
+- (void)awakeFromNib {
+ [self setInitialName:
+ l10n_util::GetNSStringWithFixup(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME)];
+ [super awakeFromNib];
+}
+
+#pragma mark Bookmark Editing
+
+- (void)UpdateActiveTabPairs {
+ activeTabPairsVector_.clear();
+ Browser* browser = BrowserList::GetLastActive();
+ TabStripModel* tabstrip_model = browser->tabstrip_model();
+ const int tabCount = tabstrip_model->count();
+ for (int i = 0; i < tabCount; ++i) {
+ TabContents* tc = tabstrip_model->GetTabContentsAt(i)->tab_contents();
+ const string16 tabTitle = tc->GetTitle();
+ const GURL& tabURL(tc->GetURL());
+ ActiveTabNameURLPair tabPair(tabTitle, tabURL);
+ activeTabPairsVector_.push_back(tabPair);
+ }
+}
+
+// Called by -[BookmarkEditorBaseController ok:]. Creates the container
+// folder for the tabs and then the bookmarks in that new folder.
+// Returns a BOOL as an NSNumber indicating that the commit may proceed.
+- (NSNumber*)didCommit {
+ NSString* name = [[self displayName] stringByTrimmingCharactersInSet:
+ [NSCharacterSet newlineCharacterSet]];
+ std::wstring newTitle = base::SysNSStringToWide(name);
+ const BookmarkNode* newParentNode = [self selectedNode];
+ int newIndex = newParentNode->GetChildCount();
+ // Create the new folder which will contain all of the tab URLs.
+ NSString* newFolderName = [self displayName];
+ string16 newFolderString = base::SysNSStringToUTF16(newFolderName);
+ BookmarkModel* model = [self bookmarkModel];
+ const BookmarkNode* newFolder = model->AddGroup(newParentNode, newIndex,
+ newFolderString);
+ // Get a list of all open tabs, create nodes for them, and add
+ // to the new folder node.
+ [self UpdateActiveTabPairs];
+ int i = 0;
+ for (ActiveTabsNameURLPairVector::const_iterator it =
+ activeTabPairsVector_.begin();
+ it != activeTabPairsVector_.end(); ++it, ++i) {
+ model->AddURL(newFolder, i, it->first, it->second);
+ }
+ return [NSNumber numberWithBool:YES];
+}
+
+- (ActiveTabsNameURLPairVector*)activeTabPairsVector {
+ return &activeTabPairsVector_;
+}
+
+@end // BookmarkAllTabsController
+
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_all_tabs_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_all_tabs_controller_unittest.mm
new file mode 100644
index 0000000..9f8a7d8
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_all_tabs_controller_unittest.mm
@@ -0,0 +1,82 @@
+// 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 "base/scoped_nsobject.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_all_tabs_controller.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+@interface BookmarkAllTabsControllerOverride : BookmarkAllTabsController
+@end
+
+@implementation BookmarkAllTabsControllerOverride
+
+- (void)UpdateActiveTabPairs {
+ ActiveTabsNameURLPairVector* activeTabPairsVector =
+ [self activeTabPairsVector];
+ activeTabPairsVector->clear();
+ activeTabPairsVector->push_back(
+ ActiveTabNameURLPair(ASCIIToUTF16("at-0"), GURL("http://at-0.com")));
+ activeTabPairsVector->push_back(
+ ActiveTabNameURLPair(ASCIIToUTF16("at-1"), GURL("http://at-1.com")));
+ activeTabPairsVector->push_back(
+ ActiveTabNameURLPair(ASCIIToUTF16("at-2"), GURL("http://at-2.com")));
+}
+
+@end
+
+class BookmarkAllTabsControllerTest : public CocoaTest {
+ public:
+ BrowserTestHelper helper_;
+ const BookmarkNode* parent_node_;
+ BookmarkAllTabsControllerOverride* controller_;
+ const BookmarkNode* group_a_;
+
+ BookmarkAllTabsControllerTest() {
+ BookmarkModel& model(*(helper_.profile()->GetBookmarkModel()));
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ group_a_ = model.AddGroup(root, 0, ASCIIToUTF16("a"));
+ model.AddURL(group_a_, 0, ASCIIToUTF16("a-0"), GURL("http://a-0.com"));
+ model.AddURL(group_a_, 1, ASCIIToUTF16("a-1"), GURL("http://a-1.com"));
+ model.AddURL(group_a_, 2, ASCIIToUTF16("a-2"), GURL("http://a-2.com"));
+ }
+
+ virtual BookmarkAllTabsControllerOverride* CreateController() {
+ return [[BookmarkAllTabsControllerOverride alloc]
+ initWithParentWindow:test_window()
+ profile:helper_.profile()
+ parent:group_a_
+ configuration:BookmarkEditor::SHOW_TREE];
+ }
+
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ controller_ = CreateController();
+ [controller_ runAsModalSheet];
+ }
+
+ virtual void TearDown() {
+ controller_ = NULL;
+ CocoaTest::TearDown();
+ }
+};
+
+TEST_F(BookmarkAllTabsControllerTest, BookmarkAllTabs) {
+ // OK button should always be enabled.
+ EXPECT_TRUE([controller_ okButtonEnabled]);
+ [controller_ selectTestNodeInBrowser:group_a_];
+ [controller_ setDisplayName:@"ALL MY TABS"];
+ [controller_ ok:nil];
+ EXPECT_EQ(4, group_a_->GetChildCount());
+ const BookmarkNode* folderChild = group_a_->GetChild(3);
+ EXPECT_EQ(folderChild->GetTitle(), ASCIIToUTF16("ALL MY TABS"));
+ EXPECT_EQ(3, folderChild->GetChildCount());
+}
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge.h
new file mode 100644
index 0000000..811c450
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge.h
@@ -0,0 +1,60 @@
+// 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.
+
+// C++ bridge class between Chromium and Cocoa to connect the
+// Bookmarks (model) with the Bookmark Bar (view).
+//
+// There is exactly one BookmarkBarBridge per BookmarkBarController /
+// BrowserWindowController / Browser.
+
+#ifndef CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_BRIDGE_H_
+#define CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_BRIDGE_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "chrome/browser/bookmarks/bookmark_model_observer.h"
+
+class Browser;
+@class BookmarkBarController;
+
+class BookmarkBarBridge : public BookmarkModelObserver {
+ public:
+ BookmarkBarBridge(BookmarkBarController* controller,
+ BookmarkModel* model);
+ virtual ~BookmarkBarBridge();
+
+ // Overridden from BookmarkModelObserver
+ virtual void Loaded(BookmarkModel* model);
+ virtual void BookmarkModelBeingDeleted(BookmarkModel* model);
+ virtual void BookmarkNodeMoved(BookmarkModel* model,
+ const BookmarkNode* old_parent,
+ int old_index,
+ const BookmarkNode* new_parent,
+ int new_index);
+ virtual void BookmarkNodeAdded(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int index);
+ virtual void BookmarkNodeRemoved(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int old_index,
+ const BookmarkNode* node);
+ virtual void BookmarkNodeChanged(BookmarkModel* model,
+ const BookmarkNode* node);
+ virtual void BookmarkNodeFavIconLoaded(BookmarkModel* model,
+ const BookmarkNode* node);
+ virtual void BookmarkNodeChildrenReordered(BookmarkModel* model,
+ const BookmarkNode* node);
+
+ virtual void BookmarkImportBeginning(BookmarkModel* model);
+ virtual void BookmarkImportEnding(BookmarkModel* model);
+
+ private:
+ BookmarkBarController* controller_; // weak; owns me
+ BookmarkModel* model_; // weak; it is owned by a Profile.
+ bool batch_mode_;
+
+ DISALLOW_COPY_AND_ASSIGN(BookmarkBarBridge);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_BRIDGE_H_
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge.mm
new file mode 100644
index 0000000..54f5e81
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge.mm
@@ -0,0 +1,82 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge.h"
+
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
+
+BookmarkBarBridge::BookmarkBarBridge(BookmarkBarController* controller,
+ BookmarkModel* model)
+ : controller_(controller),
+ model_(model),
+ batch_mode_(false) {
+ model_->AddObserver(this);
+
+ // Bookmark loading is async; it may may not have happened yet.
+ // We will be notified when that happens with the AddObserver() call.
+ if (model->IsLoaded())
+ Loaded(model);
+}
+
+BookmarkBarBridge::~BookmarkBarBridge() {
+ model_->RemoveObserver(this);
+}
+
+void BookmarkBarBridge::Loaded(BookmarkModel* model) {
+ [controller_ loaded:model];
+}
+
+void BookmarkBarBridge::BookmarkModelBeingDeleted(BookmarkModel* model) {
+ [controller_ beingDeleted:model];
+}
+
+void BookmarkBarBridge::BookmarkNodeMoved(BookmarkModel* model,
+ const BookmarkNode* old_parent,
+ int old_index,
+ const BookmarkNode* new_parent,
+ int new_index) {
+ [controller_ nodeMoved:model
+ oldParent:old_parent oldIndex:old_index
+ newParent:new_parent newIndex:new_index];
+}
+
+void BookmarkBarBridge::BookmarkNodeAdded(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int index) {
+ if (!batch_mode_) {
+ [controller_ nodeAdded:model parent:parent index:index];
+ }
+}
+
+void BookmarkBarBridge::BookmarkNodeRemoved(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int old_index,
+ const BookmarkNode* node) {
+ [controller_ nodeRemoved:model parent:parent index:old_index];
+}
+
+void BookmarkBarBridge::BookmarkNodeChanged(BookmarkModel* model,
+ const BookmarkNode* node) {
+ [controller_ nodeChanged:model node:node];
+}
+
+void BookmarkBarBridge::BookmarkNodeFavIconLoaded(BookmarkModel* model,
+ const BookmarkNode* node) {
+ [controller_ nodeFavIconLoaded:model node:node];
+}
+
+void BookmarkBarBridge::BookmarkNodeChildrenReordered(
+ BookmarkModel* model, const BookmarkNode* node) {
+ [controller_ nodeChildrenReordered:model node:node];
+}
+
+void BookmarkBarBridge::BookmarkImportBeginning(BookmarkModel* model) {
+ batch_mode_ = true;
+}
+
+void BookmarkBarBridge::BookmarkImportEnding(BookmarkModel* model) {
+ batch_mode_ = false;
+ [controller_ loaded:model];
+}
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge_unittest.mm
new file mode 100644
index 0000000..067d327
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge_unittest.mm
@@ -0,0 +1,135 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge.h"
+#include "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+// TODO(jrg): use OCMock.
+
+namespace {
+
+// Information needed to open a URL, as passed to the
+// BookmarkBarController's delegate.
+typedef std::pair<GURL,WindowOpenDisposition> OpenInfo;
+
+} // The namespace must end here -- I need to use OpenInfo in
+ // FakeBookmarkBarController but can't place
+ // FakeBookmarkBarController itself in the namespace ("error:
+ // Objective-C declarations may only appear in global scope")
+
+// Oddly, we are our own delegate.
+@interface FakeBookmarkBarController : BookmarkBarController {
+ @public
+ scoped_nsobject<NSMutableArray> callbacks_;
+ std::vector<OpenInfo> opens_;
+}
+@end
+
+@implementation FakeBookmarkBarController
+
+- (id)initWithBrowser:(Browser*)browser {
+ if ((self = [super initWithBrowser:browser
+ initialWidth:100 // arbitrary
+ delegate:nil
+ resizeDelegate:nil])) {
+ callbacks_.reset([[NSMutableArray alloc] init]);
+ }
+ return self;
+}
+
+- (void)loaded:(BookmarkModel*)model {
+ [callbacks_ addObject:[NSNumber numberWithInt:0]];
+}
+
+- (void)beingDeleted:(BookmarkModel*)model {
+ [callbacks_ addObject:[NSNumber numberWithInt:1]];
+}
+
+- (void)nodeMoved:(BookmarkModel*)model
+ oldParent:(const BookmarkNode*)oldParent oldIndex:(int)oldIndex
+ newParent:(const BookmarkNode*)newParent newIndex:(int)newIndex {
+ [callbacks_ addObject:[NSNumber numberWithInt:2]];
+}
+
+- (void)nodeAdded:(BookmarkModel*)model
+ parent:(const BookmarkNode*)oldParent index:(int)index {
+ [callbacks_ addObject:[NSNumber numberWithInt:3]];
+}
+
+- (void)nodeChanged:(BookmarkModel*)model
+ node:(const BookmarkNode*)node {
+ [callbacks_ addObject:[NSNumber numberWithInt:4]];
+}
+
+- (void)nodeFavIconLoaded:(BookmarkModel*)model
+ node:(const BookmarkNode*)node {
+ [callbacks_ addObject:[NSNumber numberWithInt:5]];
+}
+
+- (void)nodeChildrenReordered:(BookmarkModel*)model
+ node:(const BookmarkNode*)node {
+ [callbacks_ addObject:[NSNumber numberWithInt:6]];
+}
+
+- (void)nodeRemoved:(BookmarkModel*)model
+ parent:(const BookmarkNode*)oldParent index:(int)index {
+ [callbacks_ addObject:[NSNumber numberWithInt:7]];
+}
+
+// Save the request.
+- (void)openBookmarkURL:(const GURL&)url
+ disposition:(WindowOpenDisposition)disposition {
+ opens_.push_back(OpenInfo(url, disposition));
+}
+
+@end
+
+
+class BookmarkBarBridgeTest : public CocoaTest {
+ public:
+ BrowserTestHelper browser_test_helper_;
+};
+
+// Call all the callbacks; make sure they are all redirected to the objc object.
+TEST_F(BookmarkBarBridgeTest, TestRedirect) {
+ Browser* browser = browser_test_helper_.browser();
+ Profile* profile = browser_test_helper_.profile();
+ BookmarkModel* model = profile->GetBookmarkModel();
+
+ scoped_nsobject<NSView> parentView([[NSView alloc]
+ initWithFrame:NSMakeRect(0,0,100,100)]);
+ scoped_nsobject<NSView> webView([[NSView alloc]
+ initWithFrame:NSMakeRect(0,0,100,100)]);
+ scoped_nsobject<NSView> infoBarsView(
+ [[NSView alloc] initWithFrame:NSMakeRect(0,0,100,100)]);
+
+ scoped_nsobject<FakeBookmarkBarController>
+ controller([[FakeBookmarkBarController alloc] initWithBrowser:browser]);
+ EXPECT_TRUE(controller.get());
+ scoped_ptr<BookmarkBarBridge> bridge(new BookmarkBarBridge(controller.get(),
+ model));
+ EXPECT_TRUE(bridge.get());
+
+ bridge->Loaded(NULL);
+ bridge->BookmarkModelBeingDeleted(NULL);
+ bridge->BookmarkNodeMoved(NULL, NULL, 0, NULL, 0);
+ bridge->BookmarkNodeAdded(NULL, NULL, 0);
+ bridge->BookmarkNodeChanged(NULL, NULL);
+ bridge->BookmarkNodeFavIconLoaded(NULL, NULL);
+ bridge->BookmarkNodeChildrenReordered(NULL, NULL);
+ bridge->BookmarkNodeRemoved(NULL, NULL, 0, NULL);
+
+ // 8 calls above plus an initial Loaded() in init routine makes 9
+ EXPECT_TRUE([controller.get()->callbacks_ count] == 9);
+
+ for (int x = 1; x < 9; x++) {
+ NSNumber* num = [NSNumber numberWithInt:x-1];
+ EXPECT_NSEQ(num, [controller.get()->callbacks_ objectAtIndex:x]);
+ }
+}
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h
new file mode 100644
index 0000000..b4e4bef
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h
@@ -0,0 +1,38 @@
+// 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.
+
+// Constants used for positioning the bookmark bar. These aren't placed in a
+// different file because they're conditionally included in cross platform code
+// and thus no Objective-C++ stuff.
+
+#ifndef CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_CONSTANTS_H_
+#define CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_CONSTANTS_H_
+#pragma once
+
+namespace bookmarks {
+
+// Correction used for computing other values based on the height.
+const int kVisualHeightOffset = 2;
+
+// Bar height, when opened in "always visible" mode. This is actually a little
+// smaller than it should be (by |kVisualHeightOffset| points) because of the
+// visual overlap with the main toolbar. When using this to compute values
+// other than the actual height of the toolbar, be sure to add
+// |kVisualHeightOffset|.
+const int kBookmarkBarHeight = 26;
+
+// Our height, when visible in "new tab page" mode.
+const int kNTPBookmarkBarHeight = 40;
+
+// The amount of space between the inner bookmark bar and the outer toolbar on
+// new tab pages.
+const int kNTPBookmarkBarPadding =
+ (kNTPBookmarkBarHeight - (kBookmarkBarHeight + kVisualHeightOffset)) / 2;
+
+// The height of buttons in the bookmark bar.
+const int kBookmarkButtonHeight = kBookmarkBarHeight + kVisualHeightOffset;
+
+} // namespace bookmarks
+
+#endif // CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_CONSTANTS_H_
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h
new file mode 100644
index 0000000..64591ba
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h
@@ -0,0 +1,399 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_CONTROLLER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+#include <map>
+
+#include "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_state.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
+#include "chrome/browser/ui/cocoa/tab_strip_model_observer_bridge.h"
+#import "chrome/common/chrome_application_mac.h"
+#include "webkit/glue/window_open_disposition.h"
+
+@class BookmarkBarController;
+@class BookmarkBarFolderController;
+@class BookmarkBarView;
+@class BookmarkButton;
+@class BookmarkButtonCell;
+@class BookmarkFolderTarget;
+class BookmarkModel;
+@class BookmarkMenu;
+class BookmarkNode;
+class Browser;
+class GURL;
+class PrefService;
+class TabContents;
+@class ToolbarController;
+@protocol ViewResizer;
+
+namespace bookmarks {
+
+// Magic numbers from Cole
+// TODO(jrg): create an objc-friendly version of bookmark_bar_constants.h?
+
+// Used as a maximum width for buttons on the bar.
+const CGFloat kDefaultBookmarkWidth = 150.0;
+
+// Horizontal frame inset for buttons in the bookmark bar.
+const CGFloat kBookmarkHorizontalPadding = 1.0;
+
+// Vertical frame inset for buttons in the bookmark bar.
+const CGFloat kBookmarkVerticalPadding = 2.0;
+
+// Used as a min/max width for buttons on menus (not on the bar).
+const CGFloat kBookmarkMenuButtonMinimumWidth = 100.0;
+const CGFloat kBookmarkMenuButtonMaximumWidth = 485.0;
+
+// Horizontal separation between a menu button and both edges of its menu.
+const CGFloat kBookmarkSubMenuHorizontalPadding = 5.0;
+
+// TODO(mrossetti): Add constant (kBookmarkVerticalSeparation) for the gap
+// between buttons in a folder menu. Right now we're using
+// kBookmarkVerticalPadding, which is dual purpose and wrong.
+// http://crbug.com/59057
+
+// Convenience constant giving the vertical distance from the top extent of one
+// folder button to the next button.
+const CGFloat kBookmarkButtonVerticalSpan =
+ kBookmarkButtonHeight + kBookmarkVerticalPadding;
+
+// The minimum separation between a folder menu and the edge of the screen.
+// If the menu gets closer to the edge of the screen (either right or left)
+// then it is pops up in the opposite direction.
+// (See -[BookmarkBarFolderController childFolderWindowLeftForWidth:]).
+const CGFloat kBookmarkHorizontalScreenPadding = 8.0;
+
+// Our NSScrollView is supposed to be just barely big enough to fit its
+// contentView. It is actually a hair too small.
+// This turns on horizontal scrolling which, although slight, is awkward.
+// Make sure our window (and NSScrollView) are wider than its documentView
+// by at least this much.
+const CGFloat kScrollViewContentWidthMargin = 2;
+
+// Make subfolder menus overlap their parent menu a bit to give a better
+// perception of a menuing system.
+const CGFloat kBookmarkMenuOverlap = 5.0;
+
+// Delay before opening a subfolder (and closing the previous one)
+// when hovering over a folder button.
+const NSTimeInterval kHoverOpenDelay = 0.3;
+
+// Delay on hover before a submenu opens when dragging.
+// Experimentally a drag hover open delay needs to be bigger than a
+// normal (non-drag) menu hover open such as used in the bookmark folder.
+// TODO(jrg): confirm feel of this constant with ui-team.
+// http://crbug.com/36276
+const NSTimeInterval kDragHoverOpenDelay = 0.7;
+
+// Notes on use of kDragHoverCloseDelay in
+// -[BookmarkBarFolderController draggingEntered:].
+//
+// We have an implicit delay on stop-hover-open before a submenu
+// closes. This cannot be zero since it's nice to move the mouse in a
+// direct line from "current position" to "position of item in
+// submenu". However, by doing so, it's possible to overlap a
+// different button on the current menu. Example:
+//
+// Folder1
+// Folder2 ---> Sub1
+// Folder3 Sub2
+// Sub3
+//
+// If you hover over the F in Folder2 to open the sub, and then want to
+// select Sub3, a direct line movement of the mouse may cross over
+// Folder3. Without this delay, that'll cause Sub to be closed before
+// you get there, since a "hover over" of Folder3 gets activated.
+// It's subtle but without the delay it feels broken.
+//
+// This is only really a problem with vertical menu --> vertical menu
+// movement; the bookmark bar (horizontal menu, sort of) seems fine,
+// perhaps because mouse move direction is purely vertical so there is
+// no opportunity for overlap.
+const NSTimeInterval kDragHoverCloseDelay = 0.4;
+
+} // namespace bookmarks
+
+// The interface for the bookmark bar controller's delegate. Currently, the
+// delegate is the BWC and is responsible for ensuring that the toolbar is
+// displayed correctly (as specified by |-getDesiredToolbarHeightCompression|
+// and |-toolbarDividerOpacity|) at the beginning and at the end of an animation
+// (or after a state change).
+@protocol BookmarkBarControllerDelegate
+
+// Sent when the state has changed (after any animation), but before the final
+// display update.
+- (void)bookmarkBar:(BookmarkBarController*)controller
+ didChangeFromState:(bookmarks::VisualState)oldState
+ toState:(bookmarks::VisualState)newState;
+
+// Sent before the animation begins.
+- (void)bookmarkBar:(BookmarkBarController*)controller
+willAnimateFromState:(bookmarks::VisualState)oldState
+ toState:(bookmarks::VisualState)newState;
+
+@end
+
+// A controller for the bookmark bar in the browser window. Handles showing
+// and hiding based on the preference in the given profile.
+@interface BookmarkBarController :
+ NSViewController<BookmarkBarState,
+ BookmarkBarToolbarViewController,
+ BookmarkButtonDelegate,
+ BookmarkButtonControllerProtocol,
+ CrApplicationEventHookProtocol,
+ NSUserInterfaceValidations> {
+ @private
+ // The visual state of the bookmark bar. If an animation is running, this is
+ // set to the "destination" and |lastVisualState_| is set to the "original"
+ // state. This is set to |kInvalidState| on initialization (when the
+ // appropriate state is not yet known).
+ bookmarks::VisualState visualState_;
+
+ // The "original" state of the bookmark bar if an animation is running,
+ // otherwise it should be |kInvalidState|.
+ bookmarks::VisualState lastVisualState_;
+
+ Browser* browser_; // weak; owned by its window
+ BookmarkModel* bookmarkModel_; // weak; part of the profile owned by the
+ // top-level Browser object.
+
+ // Our initial view width, which is applied in awakeFromNib.
+ CGFloat initialWidth_;
+
+ // BookmarkNodes have a 64bit id. NSMenuItems have a 32bit tag used
+ // to represent the bookmark node they refer to. This map provides
+ // a mapping from one to the other, so we can properly identify the
+ // node from the item. When adding items in, we start with seedId_.
+ int32 seedId_;
+ std::map<int32,int64> menuTagMap_;
+
+ // Our bookmark buttons, ordered from L-->R.
+ scoped_nsobject<NSMutableArray> buttons_;
+
+ // The folder image so we can use one copy for all buttons
+ scoped_nsobject<NSImage> folderImage_;
+
+ // The default image, so we can use one copy for all buttons.
+ scoped_nsobject<NSImage> defaultImage_;
+
+ // If the bar is disabled, we hide it and ignore show/hide commands.
+ // Set when using fullscreen mode.
+ BOOL barIsEnabled_;
+
+ // Bridge from Chrome-style C++ notifications (e.g. derived from
+ // BookmarkModelObserver)
+ scoped_ptr<BookmarkBarBridge> bridge_;
+
+ // Delegate that is informed about state changes in the bookmark bar.
+ id<BookmarkBarControllerDelegate> delegate_; // weak
+
+ // Delegate that can resize us.
+ id<ViewResizer> resizeDelegate_; // weak
+
+ // Logic for dealing with a click on a bookmark folder button.
+ scoped_nsobject<BookmarkFolderTarget> folderTarget_;
+
+ // A controller for a pop-up bookmark folder window (custom menu).
+ // This is not a scoped_nsobject because it owns itself (when its
+ // window closes the controller gets autoreleased).
+ BookmarkBarFolderController* folderController_;
+
+ // Are watching for a "click outside" or other event which would
+ // signal us to close the bookmark bar folder menus?
+ BOOL watchingForExitEvent_;
+
+ IBOutlet BookmarkBarView* buttonView_; // Contains 'no items' text fields.
+ IBOutlet BookmarkButton* offTheSideButton_; // aka the chevron.
+ IBOutlet NSMenu* buttonContextMenu_;
+
+ NSRect originalNoItemsRect_; // Original, pre-resized field rect.
+ NSRect originalImportBookmarksRect_; // Original, pre-resized field rect.
+
+ // "Other bookmarks" button on the right side.
+ scoped_nsobject<BookmarkButton> otherBookmarksButton_;
+
+ // We have a special menu for folder buttons. This starts as a copy
+ // of the bar menu.
+ scoped_nsobject<BookmarkMenu> buttonFolderContextMenu_;
+
+ // When doing a drag, this is folder button "hovered over" which we
+ // may want to open after a short delay. There are cases where a
+ // mouse-enter can open a folder (e.g. if the menus are "active")
+ // but that doesn't use this variable or need a delay so "hover" is
+ // the wrong term.
+ scoped_nsobject<BookmarkButton> hoverButton_;
+
+ // We save the view width when we add bookmark buttons. This lets
+ // us avoid a rebuild until we've grown the window bigger than our
+ // initial build.
+ CGFloat savedFrameWidth_;
+
+ // The number of buttons we display in the bookmark bar. This does
+ // not include the "off the side" chevron or the "Other Bookmarks"
+ // button. We use this number to determine if we need to display
+ // the chevron, and to know what to place in the chevron's menu.
+ // Since we create everything before doing layout we can't be sure
+ // that all bookmark buttons we create will be visible. Thus,
+ // [buttons_ count] isn't a definitive check.
+ int displayedButtonCount_;
+
+ // A state flag which tracks when the bar's folder menus should be shown.
+ // An initial click in any of the folder buttons turns this on and
+ // one of the following will turn it off: another click in the button,
+ // the window losing focus, a click somewhere other than in the bar
+ // or a folder menu.
+ BOOL showFolderMenus_;
+
+ // Set to YES to prevent any node animations. Useful for unit testing so that
+ // incomplete animations do not cause valgrind complaints.
+ BOOL ignoreAnimations_;
+}
+
+@property(readonly, nonatomic) bookmarks::VisualState visualState;
+@property(readonly, nonatomic) bookmarks::VisualState lastVisualState;
+@property(assign, nonatomic) id<BookmarkBarControllerDelegate> delegate;
+
+// Initializes the bookmark bar controller with the given browser
+// profile and delegates.
+- (id)initWithBrowser:(Browser*)browser
+ initialWidth:(CGFloat)initialWidth
+ delegate:(id<BookmarkBarControllerDelegate>)delegate
+ resizeDelegate:(id<ViewResizer>)resizeDelegate;
+
+// Updates the bookmark bar (from its current, possibly in-transition) state to
+// the one appropriate for the new conditions.
+- (void)updateAndShowNormalBar:(BOOL)showNormalBar
+ showDetachedBar:(BOOL)showDetachedBar
+ withAnimation:(BOOL)animate;
+
+// Update the visible state of the bookmark bar.
+- (void)updateVisibility;
+
+// Turn on or off the bookmark bar and prevent or reallow its appearance. On
+// disable, toggle off if shown. On enable, show only if needed. App and popup
+// windows do not show a bookmark bar.
+- (void)setBookmarkBarEnabled:(BOOL)enabled;
+
+// Returns the amount by which the toolbar above should be compressed.
+- (CGFloat)getDesiredToolbarHeightCompression;
+
+// Gets the appropriate opacity for the toolbar's divider; 0 means that it
+// shouldn't be shown.
+- (CGFloat)toolbarDividerOpacity;
+
+// Updates the sizes and positions of the subviews.
+// TODO(viettrungluu): I'm not convinced this should be public, but I currently
+// need it for animations. Try not to propagate its use.
+- (void)layoutSubviews;
+
+// Called by our view when it is moved to a window.
+- (void)viewDidMoveToWindow;
+
+// Import bookmarks from another browser.
+- (IBAction)importBookmarks:(id)sender;
+
+// Provide a favIcon for a bookmark node. May return nil.
+- (NSImage*)favIconForNode:(const BookmarkNode*)node;
+
+// Used for situations where the bookmark bar folder menus should no longer
+// be actively popping up. Called when the window loses focus, a click has
+// occured outside the menus or a bookmark has been activated. (Note that this
+// differs from the behavior of the -[BookmarkButtonControllerProtocol
+// closeAllBookmarkFolders] method in that the latter does not terminate menu
+// tracking since it may be being called in response to actions (such as
+// dragging) where a 'stale' menu presentation should first be collapsed before
+// presenting a new menu.)
+- (void)closeFolderAndStopTrackingMenus;
+
+// Checks if operations such as edit or delete are allowed.
+- (BOOL)canEditBookmark:(const BookmarkNode*)node;
+
+// Actions for manipulating bookmarks.
+// Open a normal bookmark or folder from a button, ...
+- (IBAction)openBookmark:(id)sender;
+- (IBAction)openBookmarkFolderFromButton:(id)sender;
+// From the "off the side" button, ...
+- (IBAction)openOffTheSideFolderFromButton:(id)sender;
+// From a context menu over the button, ...
+- (IBAction)openBookmarkInNewForegroundTab:(id)sender;
+- (IBAction)openBookmarkInNewWindow:(id)sender;
+- (IBAction)openBookmarkInIncognitoWindow:(id)sender;
+- (IBAction)editBookmark:(id)sender;
+- (IBAction)cutBookmark:(id)sender;
+- (IBAction)copyBookmark:(id)sender;
+- (IBAction)pasteBookmark:(id)sender;
+- (IBAction)deleteBookmark:(id)sender;
+// From a context menu over the bar, ...
+- (IBAction)openAllBookmarks:(id)sender;
+- (IBAction)openAllBookmarksNewWindow:(id)sender;
+- (IBAction)openAllBookmarksIncognitoWindow:(id)sender;
+// Or from a context menu over either the bar or a button.
+- (IBAction)addPage:(id)sender;
+- (IBAction)addFolder:(id)sender;
+
+@end
+
+// Redirects from BookmarkBarBridge, the C++ object which glues us to
+// the rest of Chromium. Internal to BookmarkBarController.
+@interface BookmarkBarController(BridgeRedirect)
+- (void)loaded:(BookmarkModel*)model;
+- (void)beingDeleted:(BookmarkModel*)model;
+- (void)nodeAdded:(BookmarkModel*)model
+ parent:(const BookmarkNode*)oldParent index:(int)index;
+- (void)nodeChanged:(BookmarkModel*)model
+ node:(const BookmarkNode*)node;
+- (void)nodeMoved:(BookmarkModel*)model
+ oldParent:(const BookmarkNode*)oldParent oldIndex:(int)oldIndex
+ newParent:(const BookmarkNode*)newParent newIndex:(int)newIndex;
+- (void)nodeRemoved:(BookmarkModel*)model
+ parent:(const BookmarkNode*)oldParent index:(int)index;
+- (void)nodeFavIconLoaded:(BookmarkModel*)model
+ node:(const BookmarkNode*)node;
+- (void)nodeChildrenReordered:(BookmarkModel*)model
+ node:(const BookmarkNode*)node;
+@end
+
+// These APIs should only be used by unit tests (or used internally).
+@interface BookmarkBarController(InternalOrTestingAPI)
+- (BookmarkBarView*)buttonView;
+- (NSMutableArray*)buttons;
+- (NSMenu*)offTheSideMenu;
+- (NSButton*)offTheSideButton;
+- (BOOL)offTheSideButtonIsHidden;
+- (BookmarkButton*)otherBookmarksButton;
+- (BookmarkBarFolderController*)folderController;
+- (id)folderTarget;
+- (int)displayedButtonCount;
+- (void)openURL:(GURL)url disposition:(WindowOpenDisposition)disposition;
+- (void)clearBookmarkBar;
+- (BookmarkButtonCell*)cellForBookmarkNode:(const BookmarkNode*)node;
+- (NSRect)frameForBookmarkButtonFromCell:(NSCell*)cell xOffset:(int*)xOffset;
+- (void)checkForBookmarkButtonGrowth:(NSButton*)button;
+- (void)frameDidChange;
+- (int64)nodeIdFromMenuTag:(int32)tag;
+- (int32)menuTagFromNodeId:(int64)menuid;
+- (const BookmarkNode*)nodeFromMenuItem:(id)sender;
+- (void)updateTheme:(ThemeProvider*)themeProvider;
+- (BookmarkButton*)buttonForDroppingOnAtPoint:(NSPoint)point;
+- (BOOL)isEventAnExitEvent:(NSEvent*)event;
+- (BOOL)shrinkOrHideView:(NSView*)view forMaxX:(CGFloat)maxViewX;
+
+// The following are for testing purposes only and are not used internally.
+- (NSMenu *)menuForFolderNode:(const BookmarkNode*)node;
+- (NSMenu*)buttonContextMenu;
+- (void)setButtonContextMenu:(id)menu;
+// Set to YES in order to prevent animations.
+- (void)setIgnoreAnimations:(BOOL)ignore;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm
new file mode 100644
index 0000000..c08aae0
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm
@@ -0,0 +1,2497 @@
+// 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 "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
+
+#include "app/l10n_util_mac.h"
+#include "app/resource_bundle.h"
+#include "base/mac_util.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/bookmarks/bookmark_editor.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/bookmarks/bookmark_utils.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_contents_view.h"
+#import "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#import "chrome/browser/ui/cocoa/background_gradient_view.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_bridge.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "chrome/browser/ui/cocoa/event_utils.h"
+#import "chrome/browser/ui/cocoa/fullscreen_controller.h"
+#import "chrome/browser/ui/cocoa/import_settings_dialog.h"
+#import "chrome/browser/ui/cocoa/menu_button.h"
+#import "chrome/browser/ui/cocoa/themed_window.h"
+#import "chrome/browser/ui/cocoa/toolbar_controller.h"
+#import "chrome/browser/ui/cocoa/view_id_util.h"
+#import "chrome/browser/ui/cocoa/view_resizer.h"
+#include "chrome/common/pref_names.h"
+#include "grit/app_resources.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "skia/ext/skia_utils_mac.h"
+
+// Bookmark bar state changing and animations
+//
+// The bookmark bar has three real states: "showing" (a normal bar attached to
+// the toolbar), "hidden", and "detached" (pretending to be part of the web
+// content on the NTP). It can, or at least should be able to, animate between
+// these states. There are several complications even without animation:
+// - The placement of the bookmark bar is done by the BWC, and it needs to know
+// the state in order to place the bookmark bar correctly (immediately below
+// the toolbar when showing, below the infobar when detached).
+// - The "divider" (a black line) needs to be drawn by either the toolbar (when
+// the bookmark bar is hidden or detached) or by the bookmark bar (when it is
+// showing). It should not be drawn by both.
+// - The toolbar needs to vertically "compress" when the bookmark bar is
+// showing. This ensures the proper display of both the bookmark bar and the
+// toolbar, and gives a padded area around the bookmark bar items for right
+// clicks, etc.
+//
+// Our model is that the BWC controls us and also the toolbar. We try not to
+// talk to the browser nor the toolbar directly, instead centralizing control in
+// the BWC. The key method by which the BWC controls us is
+// |-updateAndShowNormalBar:showDetachedBar:withAnimation:|. This invokes state
+// changes, and at appropriate times we request that the BWC do things for us
+// via either the resize delegate or our general delegate. If the BWC needs any
+// information about what it should do, or tell the toolbar to do, it can then
+// query us back (e.g., |-isShownAs...|, |-getDesiredToolbarHeightCompression|,
+// |-toolbarDividerOpacity|, etc.).
+//
+// Animation-related complications:
+// - Compression of the toolbar is touchy during animation. It must not be
+// compressed while the bookmark bar is animating to/from showing (from/to
+// hidden), otherwise it would look like the bookmark bar's contents are
+// sliding out of the controls inside the toolbar. As such, we have to make
+// sure that the bookmark bar is shown at the right location and at the
+// right height (at various points in time).
+// - Showing the divider is also complicated during animation between hidden
+// and showing. We have to make sure that the toolbar does not show the
+// divider despite the fact that it's not compressed. The exception to this
+// is at the beginning/end of the animation when the toolbar is still
+// uncompressed but the bookmark bar has height 0. If we're not careful, we
+// get a flicker at this point.
+// - We have to ensure that we do the right thing if we're told to change state
+// while we're running an animation. The generic/easy thing to do is to jump
+// to the end state of our current animation, and (if the new state change
+// again involves an animation) begin the new animation. We can do better
+// than that, however, and sometimes just change the current animation to go
+// to the new end state (e.g., by "reversing" the animation in the showing ->
+// hidden -> showing case). We also have to ensure that demands to
+// immediately change state are always honoured.
+//
+// Pointers to animation logic:
+// - |-moveToVisualState:withAnimation:| starts animations, deciding which ones
+// we know how to handle.
+// - |-doBookmarkBarAnimation| has most of the actual logic.
+// - |-getDesiredToolbarHeightCompression| and |-toolbarDividerOpacity| contain
+// related logic.
+// - The BWC's |-layoutSubviews| needs to know how to position things.
+// - The BWC should implement |-bookmarkBar:didChangeFromState:toState:| and
+// |-bookmarkBar:willAnimateFromState:toState:| in order to inform the
+// toolbar of required changes.
+
+namespace {
+
+// Overlap (in pixels) between the toolbar and the bookmark bar (when showing in
+// normal mode).
+const CGFloat kBookmarkBarOverlap = 3.0;
+
+// Duration of the bookmark bar animations.
+const NSTimeInterval kBookmarkBarAnimationDuration = 0.12;
+
+} // namespace
+
+@interface BookmarkBarController(Private)
+
+// Determines the appropriate state for the given situation.
++ (bookmarks::VisualState)visualStateToShowNormalBar:(BOOL)showNormalBar
+ showDetachedBar:(BOOL)showDetachedBar;
+
+// Moves to the given next state (from the current state), possibly animating.
+// If |animate| is NO, it will stop any running animation and jump to the given
+// state. If YES, it may either (depending on implementation) jump to the end of
+// the current animation and begin the next one, or stop the current animation
+// mid-flight and animate to the next state.
+- (void)moveToVisualState:(bookmarks::VisualState)nextVisualState
+ withAnimation:(BOOL)animate;
+
+// Return the backdrop to the bookmark bar as various types.
+- (BackgroundGradientView*)backgroundGradientView;
+- (AnimatableView*)animatableView;
+
+// Create buttons for all items in the given bookmark node tree.
+// Modifies self->buttons_. Do not add more buttons than will fit on the view.
+- (void)addNodesToButtonList:(const BookmarkNode*)node;
+
+// Create an autoreleased button appropriate for insertion into the bookmark
+// bar. Update |xOffset| with the offset appropriate for the subsequent button.
+- (BookmarkButton*)buttonForNode:(const BookmarkNode*)node
+ xOffset:(int*)xOffset;
+
+// Puts stuff into the final visual state without animating, stopping a running
+// animation if necessary.
+- (void)finalizeVisualState;
+
+// Stops any current animation in its tracks (midway).
+- (void)stopCurrentAnimation;
+
+// Show/hide the bookmark bar.
+// if |animate| is YES, the changes are made using the animator; otherwise they
+// are made immediately.
+- (void)showBookmarkBarWithAnimation:(BOOL)animate;
+
+// Handles animating the resize of the content view. Returns YES if it handled
+// the animation, NO if not (and hence it should be done instantly).
+- (BOOL)doBookmarkBarAnimation;
+
+// |point| is in the base coordinate system of the destination window;
+// it comes from an id<NSDraggingInfo>. |copy| is YES if a copy is to be
+// made and inserted into the new location while leaving the bookmark in
+// the old location, otherwise move the bookmark by removing from its old
+// location and inserting into the new location.
+- (BOOL)dragBookmark:(const BookmarkNode*)sourceNode
+ to:(NSPoint)point
+ copy:(BOOL)copy;
+
+// Returns the index in the model for a drag to the location given by
+// |point|. This is determined by finding the first button before the center
+// of which |point| falls, scanning left to right. Note that, currently, only
+// the x-coordinate of |point| is considered. Though not currently implemented,
+// we may check for errors, in which case this would return negative value;
+// callers should check for this.
+- (int)indexForDragToPoint:(NSPoint)point;
+
+// Add or remove buttons to/from the bar until it is filled but not overflowed.
+- (void)redistributeButtonsOnBarAsNeeded;
+
+// Determine the nature of the bookmark bar contents based on the number of
+// buttons showing. If too many then show the off-the-side list, if none
+// then show the no items label.
+- (void)reconfigureBookmarkBar;
+
+- (void)addNode:(const BookmarkNode*)child toMenu:(NSMenu*)menu;
+- (void)addFolderNode:(const BookmarkNode*)node toMenu:(NSMenu*)menu;
+- (void)tagEmptyMenu:(NSMenu*)menu;
+- (void)clearMenuTagMap;
+- (int)preferredHeight;
+- (void)addNonBookmarkButtonsToView;
+- (void)addButtonsToView;
+- (void)centerNoItemsLabel;
+- (void)setNodeForBarMenu;
+
+- (void)watchForExitEvent:(BOOL)watch;
+
+@end
+
+@implementation BookmarkBarController
+
+@synthesize visualState = visualState_;
+@synthesize lastVisualState = lastVisualState_;
+@synthesize delegate = delegate_;
+
+- (id)initWithBrowser:(Browser*)browser
+ initialWidth:(float)initialWidth
+ delegate:(id<BookmarkBarControllerDelegate>)delegate
+ resizeDelegate:(id<ViewResizer>)resizeDelegate {
+ if ((self = [super initWithNibName:@"BookmarkBar"
+ bundle:mac_util::MainAppBundle()])) {
+ // Initialize to an invalid state.
+ visualState_ = bookmarks::kInvalidState;
+ lastVisualState_ = bookmarks::kInvalidState;
+
+ browser_ = browser;
+ initialWidth_ = initialWidth;
+ bookmarkModel_ = browser_->profile()->GetBookmarkModel();
+ buttons_.reset([[NSMutableArray alloc] init]);
+ delegate_ = delegate;
+ resizeDelegate_ = resizeDelegate;
+ folderTarget_.reset([[BookmarkFolderTarget alloc] initWithController:self]);
+
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ folderImage_.reset(
+ [rb.GetNativeImageNamed(IDR_BOOKMARK_BAR_FOLDER) retain]);
+ defaultImage_.reset([rb.GetNativeImageNamed(IDR_DEFAULT_FAVICON) retain]);
+
+ // Register for theme changes, bookmark button pulsing, ...
+ NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
+ [defaultCenter addObserver:self
+ selector:@selector(themeDidChangeNotification:)
+ name:kBrowserThemeDidChangeNotification
+ object:nil];
+ [defaultCenter addObserver:self
+ selector:@selector(pulseBookmarkNotification:)
+ name:bookmark_button::kPulseBookmarkButtonNotification
+ object:nil];
+
+ // This call triggers an awakeFromNib, which builds the bar, which
+ // might uses folderImage_. So make sure it happens after
+ // folderImage_ is loaded.
+ [[self animatableView] setResizeDelegate:resizeDelegate];
+ }
+ return self;
+}
+
+- (void)pulseBookmarkNotification:(NSNotification*)notification {
+ NSDictionary* dict = [notification userInfo];
+ const BookmarkNode* node = NULL;
+ NSValue *value = [dict objectForKey:bookmark_button::kBookmarkKey];
+ DCHECK(value);
+ if (value)
+ node = static_cast<const BookmarkNode*>([value pointerValue]);
+ NSNumber* number = [dict
+ objectForKey:bookmark_button::kBookmarkPulseFlagKey];
+ DCHECK(number);
+ BOOL doPulse = number ? [number boolValue] : NO;
+
+ // 3 cases:
+ // button on the bar: flash it
+ // button in "other bookmarks" folder: flash other bookmarks
+ // button in "off the side" folder: flash the chevron
+ for (BookmarkButton* button in [self buttons]) {
+ if ([button bookmarkNode] == node) {
+ [button setIsContinuousPulsing:doPulse];
+ return;
+ }
+ }
+ if ([otherBookmarksButton_ bookmarkNode] == node) {
+ [otherBookmarksButton_ setIsContinuousPulsing:doPulse];
+ return;
+ }
+ if (node->GetParent() == bookmarkModel_->GetBookmarkBarNode()) {
+ [offTheSideButton_ setIsContinuousPulsing:doPulse];
+ return;
+ }
+
+ NOTREACHED() << "no bookmark button found to pulse!";
+}
+
+- (void)dealloc {
+ // We better stop any in-flight animation if we're being killed.
+ [[self animatableView] stopAnimation];
+
+ // Remove our view from its superview so it doesn't attempt to reference
+ // it when the controller is gone.
+ //TODO(dmaclach): Remove -- http://crbug.com/25845
+ [[self view] removeFromSuperview];
+
+ // Be sure there is no dangling pointer.
+ if ([[self view] respondsToSelector:@selector(setController:)])
+ [[self view] performSelector:@selector(setController:) withObject:nil];
+
+ // For safety, make sure the buttons can no longer call us.
+ for (BookmarkButton* button in buttons_.get()) {
+ [button setDelegate:nil];
+ [button setTarget:nil];
+ [button setAction:nil];
+ }
+
+ bridge_.reset(NULL);
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [self watchForExitEvent:NO];
+ [super dealloc];
+}
+
+- (void)awakeFromNib {
+ // We default to NOT open, which means height=0.
+ DCHECK([[self view] isHidden]); // Hidden so it's OK to change.
+
+ // Set our initial height to zero, since that is what the superview
+ // expects. We will resize ourselves open later if needed.
+ [[self view] setFrame:NSMakeRect(0, 0, initialWidth_, 0)];
+
+ // Complete init of the "off the side" button, as much as we can.
+ [offTheSideButton_ setDraggable:NO];
+
+ // We are enabled by default.
+ barIsEnabled_ = YES;
+
+ // Remember the original sizes of the 'no items' and 'import bookmarks'
+ // fields to aid in resizing when the window frame changes.
+ originalNoItemsRect_ = [[buttonView_ noItemTextfield] frame];
+ originalImportBookmarksRect_ = [[buttonView_ importBookmarksButton] frame];
+
+ // To make life happier when the bookmark bar is floating, the chevron is a
+ // child of the button view.
+ [offTheSideButton_ removeFromSuperview];
+ [buttonView_ addSubview:offTheSideButton_];
+
+ // Copy the bar menu so we know if it's from the bar or a folder.
+ // Then we set its represented item to be the bookmark bar.
+ buttonFolderContextMenu_.reset([[[self view] menu] copy]);
+
+ // When resized we may need to add new buttons, or remove them (if
+ // no longer visible), or add/remove the "off the side" menu.
+ [[self view] setPostsFrameChangedNotifications:YES];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(frameDidChange)
+ name:NSViewFrameDidChangeNotification
+ object:[self view]];
+
+ // Watch for things going to or from fullscreen.
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(willEnterOrLeaveFullscreen:)
+ name:kWillEnterFullscreenNotification
+ object:nil];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(willEnterOrLeaveFullscreen:)
+ name:kWillLeaveFullscreenNotification
+ object:nil];
+
+ // Don't pass ourself along (as 'self') until our init is completely
+ // done. Thus, this call is (almost) last.
+ bridge_.reset(new BookmarkBarBridge(self, bookmarkModel_));
+}
+
+// Called by our main view (a BookmarkBarView) when it gets moved to a
+// window. We perform operations which need to know the relevant
+// window (e.g. watch for a window close) so they can't be performed
+// earlier (such as in awakeFromNib).
+- (void)viewDidMoveToWindow {
+ NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
+
+ // Remove any existing notifications before registering for new ones.
+ [defaultCenter removeObserver:self
+ name:NSWindowWillCloseNotification
+ object:nil];
+ [defaultCenter removeObserver:self
+ name:NSWindowDidResignKeyNotification
+ object:nil];
+
+ [defaultCenter addObserver:self
+ selector:@selector(parentWindowWillClose:)
+ name:NSWindowWillCloseNotification
+ object:[[self view] window]];
+ [defaultCenter addObserver:self
+ selector:@selector(parentWindowDidResignKey:)
+ name:NSWindowDidResignKeyNotification
+ object:[[self view] window]];
+}
+
+// When going fullscreen we can run into trouble. Our view is removed
+// from the non-fullscreen window before the non-fullscreen window
+// loses key, so our parentDidResignKey: callback never gets called.
+// In addition, a bookmark folder controller needs to be autoreleased
+// (in case it's in the event chain when closed), but the release
+// implicitly needs to happen while it's connected to the original
+// (non-fullscreen) window to "unlock bar visibility". Such a
+// contract isn't honored when going fullscreen with the menu option
+// (not with the keyboard shortcut). We fake it as best we can here.
+// We have a similar problem leaving fullscreen.
+- (void)willEnterOrLeaveFullscreen:(NSNotification*)notification {
+ if (folderController_) {
+ [self childFolderWillClose:folderController_];
+ [self closeFolderAndStopTrackingMenus];
+ }
+}
+
+// NSNotificationCenter callback.
+- (void)parentWindowWillClose:(NSNotification*)notification {
+ [self closeFolderAndStopTrackingMenus];
+}
+
+// NSNotificationCenter callback.
+- (void)parentWindowDidResignKey:(NSNotification*)notification {
+ [self closeFolderAndStopTrackingMenus];
+}
+
+// Change the layout of the bookmark bar's subviews in response to a visibility
+// change (e.g., show or hide the bar) or style change (attached or floating).
+- (void)layoutSubviews {
+ NSRect frame = [[self view] frame];
+ NSRect buttonViewFrame = NSMakeRect(0, 0, NSWidth(frame), NSHeight(frame));
+
+ // The state of our morph (if any); 1 is total bubble, 0 is the regular bar.
+ CGFloat morph = [self detachedMorphProgress];
+
+ // Add padding to the detached bookmark bar.
+ buttonViewFrame = NSInsetRect(buttonViewFrame,
+ morph * bookmarks::kNTPBookmarkBarPadding,
+ morph * bookmarks::kNTPBookmarkBarPadding);
+
+ [buttonView_ setFrame:buttonViewFrame];
+}
+
+// We don't change a preference; we only change visibility. Preference changing
+// (global state) is handled in |BrowserWindowCocoa::ToggleBookmarkBar()|. We
+// simply update based on what we're told.
+- (void)updateVisibility {
+ [self showBookmarkBarWithAnimation:NO];
+}
+
+- (void)setBookmarkBarEnabled:(BOOL)enabled {
+ if (enabled != barIsEnabled_) {
+ barIsEnabled_ = enabled;
+ [self updateVisibility];
+ }
+}
+
+- (CGFloat)getDesiredToolbarHeightCompression {
+ // Some special cases....
+ if (!barIsEnabled_)
+ return 0;
+
+ if ([self isAnimationRunning]) {
+ // No toolbar compression when animating between hidden and showing, nor
+ // between showing and detached.
+ if ([self isAnimatingBetweenState:bookmarks::kHiddenState
+ andState:bookmarks::kShowingState] ||
+ [self isAnimatingBetweenState:bookmarks::kShowingState
+ andState:bookmarks::kDetachedState])
+ return 0;
+
+ // If we ever need any other animation cases, code would go here.
+ }
+
+ return [self isInState:bookmarks::kShowingState] ? kBookmarkBarOverlap : 0;
+}
+
+- (CGFloat)toolbarDividerOpacity {
+ // Some special cases....
+ if ([self isAnimationRunning]) {
+ // In general, the toolbar shouldn't show a divider while we're animating
+ // between showing and hidden. The exception is when our height is < 1, in
+ // which case we can't draw it. It's all-or-nothing (no partial opacity).
+ if ([self isAnimatingBetweenState:bookmarks::kHiddenState
+ andState:bookmarks::kShowingState])
+ return (NSHeight([[self view] frame]) < 1) ? 1 : 0;
+
+ // The toolbar should show the divider when animating between showing and
+ // detached (but opacity will vary).
+ if ([self isAnimatingBetweenState:bookmarks::kShowingState
+ andState:bookmarks::kDetachedState])
+ return static_cast<CGFloat>([self detachedMorphProgress]);
+
+ // If we ever need any other animation cases, code would go here.
+ }
+
+ // In general, only show the divider when it's in the normal showing state.
+ return [self isInState:bookmarks::kShowingState] ? 0 : 1;
+}
+
+- (NSImage*)favIconForNode:(const BookmarkNode*)node {
+ if (!node)
+ return defaultImage_;
+
+ if (node->is_folder())
+ return folderImage_;
+
+ const SkBitmap& favIcon = bookmarkModel_->GetFavIcon(node);
+ if (!favIcon.isNull())
+ return gfx::SkBitmapToNSImage(favIcon);
+
+ return defaultImage_;
+}
+
+- (void)closeFolderAndStopTrackingMenus {
+ showFolderMenus_ = NO;
+ [self closeAllBookmarkFolders];
+}
+
+- (BOOL)canEditBookmark:(const BookmarkNode*)node {
+ // Don't allow edit/delete of the bar node, or of "Other Bookmarks"
+ if ((node == nil) ||
+ (node == bookmarkModel_->other_node()) ||
+ (node == bookmarkModel_->GetBookmarkBarNode()))
+ return NO;
+ return YES;
+}
+
+#pragma mark Actions
+
+- (IBAction)openBookmark:(id)sender {
+ [self closeFolderAndStopTrackingMenus];
+ DCHECK([sender respondsToSelector:@selector(bookmarkNode)]);
+ const BookmarkNode* node = [sender bookmarkNode];
+ WindowOpenDisposition disposition =
+ event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
+ [self openURL:node->GetURL() disposition:disposition];
+}
+
+// Redirect to our logic shared with BookmarkBarFolderController.
+- (IBAction)openBookmarkFolderFromButton:(id)sender {
+ if (sender != offTheSideButton_) {
+ // Toggle presentation of bar folder menus.
+ showFolderMenus_ = !showFolderMenus_;
+ [folderTarget_ openBookmarkFolderFromButton:sender];
+ } else {
+ // Off-the-side requires special handling.
+ [self openOffTheSideFolderFromButton:sender];
+ }
+}
+
+// The button that sends this one is special; the "off the side"
+// button (chevron) opens like a folder button but isn't exactly a
+// parent folder.
+- (IBAction)openOffTheSideFolderFromButton:(id)sender {
+ DCHECK([sender isKindOfClass:[BookmarkButton class]]);
+ DCHECK([[sender cell] isKindOfClass:[BookmarkButtonCell class]]);
+ [[sender cell] setStartingChildIndex:displayedButtonCount_];
+ [folderTarget_ openBookmarkFolderFromButton:sender];
+}
+
+- (IBAction)openBookmarkInNewForegroundTab:(id)sender {
+ const BookmarkNode* node = [self nodeFromMenuItem:sender];
+ if (node)
+ [self openURL:node->GetURL() disposition:NEW_FOREGROUND_TAB];
+ [self closeAllBookmarkFolders];
+}
+
+- (IBAction)openBookmarkInNewWindow:(id)sender {
+ const BookmarkNode* node = [self nodeFromMenuItem:sender];
+ if (node)
+ [self openURL:node->GetURL() disposition:NEW_WINDOW];
+}
+
+- (IBAction)openBookmarkInIncognitoWindow:(id)sender {
+ const BookmarkNode* node = [self nodeFromMenuItem:sender];
+ if (node)
+ [self openURL:node->GetURL() disposition:OFF_THE_RECORD];
+}
+
+- (IBAction)editBookmark:(id)sender {
+ const BookmarkNode* node = [self nodeFromMenuItem:sender];
+ if (!node)
+ return;
+
+ if (node->is_folder()) {
+ BookmarkNameFolderController* controller =
+ [[BookmarkNameFolderController alloc]
+ initWithParentWindow:[[self view] window]
+ profile:browser_->profile()
+ node:node];
+ [controller runAsModalSheet];
+ return;
+ }
+
+ // There is no real need to jump to a platform-common routine at
+ // this point (which just jumps back to objc) other than consistency
+ // across platforms.
+ //
+ // TODO(jrg): identify when we NO_TREE. I can see it in the code
+ // for the other platforms but can't find a way to trigger it in the
+ // UI.
+ BookmarkEditor::Show([[self view] window],
+ browser_->profile(),
+ node->GetParent(),
+ BookmarkEditor::EditDetails(node),
+ BookmarkEditor::SHOW_TREE);
+}
+
+- (IBAction)cutBookmark:(id)sender {
+ const BookmarkNode* node = [self nodeFromMenuItem:sender];
+ if (node) {
+ std::vector<const BookmarkNode*> nodes;
+ nodes.push_back(node);
+ bookmark_utils::CopyToClipboard(bookmarkModel_, nodes, true);
+ }
+}
+
+- (IBAction)copyBookmark:(id)sender {
+ const BookmarkNode* node = [self nodeFromMenuItem:sender];
+ if (node) {
+ std::vector<const BookmarkNode*> nodes;
+ nodes.push_back(node);
+ bookmark_utils::CopyToClipboard(bookmarkModel_, nodes, false);
+ }
+}
+
+// Paste the copied node immediately after the node for which the context
+// menu has been presented if the node is a non-folder bookmark, otherwise
+// past at the end of the folder node.
+- (IBAction)pasteBookmark:(id)sender {
+ const BookmarkNode* node = [self nodeFromMenuItem:sender];
+ if (node) {
+ int index = -1;
+ if (node != bookmarkModel_->GetBookmarkBarNode() && !node->is_folder()) {
+ const BookmarkNode* parent = node->GetParent();
+ index = parent->IndexOfChild(node) + 1;
+ if (index > parent->GetChildCount())
+ index = -1;
+ node = parent;
+ }
+ bookmark_utils::PasteFromClipboard(bookmarkModel_, node, index);
+ }
+}
+
+- (IBAction)deleteBookmark:(id)sender {
+ const BookmarkNode* node = [self nodeFromMenuItem:sender];
+ if (node) {
+ bookmarkModel_->Remove(node->GetParent(),
+ node->GetParent()->IndexOfChild(node));
+ }
+}
+
+- (IBAction)openAllBookmarks:(id)sender {
+ const BookmarkNode* node = [self nodeFromMenuItem:sender];
+ if (node) {
+ [self openAll:node disposition:NEW_FOREGROUND_TAB];
+ UserMetrics::RecordAction(UserMetricsAction("OpenAllBookmarks"),
+ browser_->profile());
+ }
+}
+
+- (IBAction)openAllBookmarksNewWindow:(id)sender {
+ const BookmarkNode* node = [self nodeFromMenuItem:sender];
+ if (node) {
+ [self openAll:node disposition:NEW_WINDOW];
+ UserMetrics::RecordAction(UserMetricsAction("OpenAllBookmarksNewWindow"),
+ browser_->profile());
+ }
+}
+
+- (IBAction)openAllBookmarksIncognitoWindow:(id)sender {
+ const BookmarkNode* node = [self nodeFromMenuItem:sender];
+ if (node) {
+ [self openAll:node disposition:OFF_THE_RECORD];
+ UserMetrics::RecordAction(
+ UserMetricsAction("OpenAllBookmarksIncognitoWindow"),
+ browser_->profile());
+ }
+}
+
+// May be called from the bar or from a folder button.
+// If called from a button, that button becomes the parent.
+- (IBAction)addPage:(id)sender {
+ const BookmarkNode* parent = [self nodeFromMenuItem:sender];
+ if (!parent)
+ parent = bookmarkModel_->GetBookmarkBarNode();
+ BookmarkEditor::Show([[self view] window],
+ browser_->profile(),
+ parent,
+ BookmarkEditor::EditDetails(),
+ BookmarkEditor::SHOW_TREE);
+}
+
+// Might be called from the context menu over the bar OR over a
+// button. If called from a button, that button becomes a sibling of
+// the new node. If called from the bar, add to the end of the bar.
+- (IBAction)addFolder:(id)sender {
+ const BookmarkNode* senderNode = [self nodeFromMenuItem:sender];
+ const BookmarkNode* parent = NULL;
+ int newIndex = 0;
+ // If triggered from the bar, folder or "others" folder - add as a child to
+ // the end.
+ // If triggered from a bookmark, add as next sibling.
+ BookmarkNode::Type type = senderNode->type();
+ if (type == BookmarkNode::BOOKMARK_BAR ||
+ type == BookmarkNode::OTHER_NODE ||
+ type == BookmarkNode::FOLDER) {
+ parent = senderNode;
+ newIndex = parent->GetChildCount();
+ } else {
+ parent = senderNode->GetParent();
+ newIndex = parent->IndexOfChild(senderNode) + 1;
+ }
+ BookmarkNameFolderController* controller =
+ [[BookmarkNameFolderController alloc]
+ initWithParentWindow:[[self view] window]
+ profile:browser_->profile()
+ parent:parent
+ newIndex:newIndex];
+ [controller runAsModalSheet];
+}
+
+- (IBAction)importBookmarks:(id)sender {
+ [ImportSettingsDialogController showImportSettingsDialogForProfile:
+ browser_->profile()];
+}
+
+#pragma mark Private Methods
+
+// Called after the current theme has changed.
+- (void)themeDidChangeNotification:(NSNotification*)aNotification {
+ ThemeProvider* themeProvider =
+ static_cast<ThemeProvider*>([[aNotification object] pointerValue]);
+ [self updateTheme:themeProvider];
+}
+
+// (Private) Method is the same as [self view], but is provided to be explicit.
+- (BackgroundGradientView*)backgroundGradientView {
+ DCHECK([[self view] isKindOfClass:[BackgroundGradientView class]]);
+ return (BackgroundGradientView*)[self view];
+}
+
+// (Private) Method is the same as [self view], but is provided to be explicit.
+- (AnimatableView*)animatableView {
+ DCHECK([[self view] isKindOfClass:[AnimatableView class]]);
+ return (AnimatableView*)[self view];
+}
+
+// Position the off-the-side chevron to the left of the otherBookmarks button.
+- (void)positionOffTheSideButton {
+ NSRect frame = [offTheSideButton_ frame];
+ if (otherBookmarksButton_.get()) {
+ frame.origin.x = ([otherBookmarksButton_ frame].origin.x -
+ (frame.size.width +
+ bookmarks::kBookmarkHorizontalPadding));
+ [offTheSideButton_ setFrame:frame];
+ }
+}
+
+// Configure the off-the-side button (e.g. specify the node range,
+// check if we should enable or disable it, etc).
+- (void)configureOffTheSideButtonContentsAndVisibility {
+ // If deleting a button while off-the-side is open, buttons may be
+ // promoted from off-the-side to the bar. Accomodate.
+ if (folderController_ &&
+ ([folderController_ parentButton] == offTheSideButton_)) {
+ [folderController_ reconfigureMenu];
+ }
+
+ [[offTheSideButton_ cell] setStartingChildIndex:displayedButtonCount_];
+ [[offTheSideButton_ cell]
+ setBookmarkNode:bookmarkModel_->GetBookmarkBarNode()];
+ int bookmarkChildren = bookmarkModel_->GetBookmarkBarNode()->GetChildCount();
+ if (bookmarkChildren > displayedButtonCount_) {
+ [offTheSideButton_ setHidden:NO];
+ } else {
+ // If we just deleted the last item in an off-the-side menu so the
+ // button will be going away, make sure the menu goes away.
+ if (folderController_ &&
+ ([folderController_ parentButton] == offTheSideButton_))
+ [self closeAllBookmarkFolders];
+ // (And hide the button, too.)
+ [offTheSideButton_ setHidden:YES];
+ }
+}
+
+// Begin (or end) watching for a click outside this window. Unlike
+// normal NSWindows, bookmark folder "fake menu" windows do not become
+// key or main. Thus, traditional notification (e.g. WillResignKey)
+// won't work. Our strategy is to watch (at the app level) for a
+// "click outside" these windows to detect when they logically lose
+// focus.
+- (void)watchForExitEvent:(BOOL)watch {
+ CrApplication* app = static_cast<CrApplication*>([NSApplication
+ sharedApplication]);
+ DCHECK([app isKindOfClass:[CrApplication class]]);
+ if (watch) {
+ if (!watchingForExitEvent_)
+ [app addEventHook:self];
+ } else {
+ if (watchingForExitEvent_)
+ [app removeEventHook:self];
+ }
+ watchingForExitEvent_ = watch;
+}
+
+// Keep the "no items" label centered in response to a frame size change.
+- (void)centerNoItemsLabel {
+ // Note that this computation is done in the parent's coordinate system,
+ // which is unflipped. Also, we want the label to be a fixed distance from
+ // the bottom, so that it slides up properly (on animating to hidden).
+ // The textfield sits in the itemcontainer, so to center it we maintain
+ // equal vertical padding on the top and bottom.
+ int yoffset = (NSHeight([[buttonView_ noItemTextfield] frame]) -
+ NSHeight([[buttonView_ noItemContainer] frame])) / 2;
+ [[buttonView_ noItemContainer] setFrameOrigin:NSMakePoint(0, yoffset)];
+}
+
+// (Private)
+- (void)showBookmarkBarWithAnimation:(BOOL)animate {
+ if (animate && !ignoreAnimations_) {
+ // If |-doBookmarkBarAnimation| does the animation, we're done.
+ if ([self doBookmarkBarAnimation])
+ return;
+
+ // Else fall through and do the change instantly.
+ }
+
+ // Set our height.
+ [resizeDelegate_ resizeView:[self view]
+ newHeight:[self preferredHeight]];
+
+ // Only show the divider if showing the normal bookmark bar.
+ BOOL showsDivider = [self isInState:bookmarks::kShowingState];
+ [[self backgroundGradientView] setShowsDivider:showsDivider];
+
+ // Make sure we're shown.
+ [[self view] setHidden:![self isVisible]];
+
+ // Update everything else.
+ [self layoutSubviews];
+ [self frameDidChange];
+}
+
+// (Private)
+- (BOOL)doBookmarkBarAnimation {
+ if ([self isAnimatingFromState:bookmarks::kHiddenState
+ toState:bookmarks::kShowingState]) {
+ [[self backgroundGradientView] setShowsDivider:YES];
+ [[self view] setHidden:NO];
+ AnimatableView* view = [self animatableView];
+ // Height takes into account the extra height we have since the toolbar
+ // only compresses when we're done.
+ [view animateToNewHeight:(bookmarks::kBookmarkBarHeight -
+ kBookmarkBarOverlap)
+ duration:kBookmarkBarAnimationDuration];
+ } else if ([self isAnimatingFromState:bookmarks::kShowingState
+ toState:bookmarks::kHiddenState]) {
+ [[self backgroundGradientView] setShowsDivider:YES];
+ [[self view] setHidden:NO];
+ AnimatableView* view = [self animatableView];
+ [view animateToNewHeight:0
+ duration:kBookmarkBarAnimationDuration];
+ } else if ([self isAnimatingFromState:bookmarks::kShowingState
+ toState:bookmarks::kDetachedState]) {
+ [[self backgroundGradientView] setShowsDivider:YES];
+ [[self view] setHidden:NO];
+ AnimatableView* view = [self animatableView];
+ [view animateToNewHeight:bookmarks::kNTPBookmarkBarHeight
+ duration:kBookmarkBarAnimationDuration];
+ } else if ([self isAnimatingFromState:bookmarks::kDetachedState
+ toState:bookmarks::kShowingState]) {
+ [[self backgroundGradientView] setShowsDivider:YES];
+ [[self view] setHidden:NO];
+ AnimatableView* view = [self animatableView];
+ // Height takes into account the extra height we have since the toolbar
+ // only compresses when we're done.
+ [view animateToNewHeight:(bookmarks::kBookmarkBarHeight -
+ kBookmarkBarOverlap)
+ duration:kBookmarkBarAnimationDuration];
+ } else {
+ // Oops! An animation we don't know how to handle.
+ return NO;
+ }
+
+ return YES;
+}
+
+// Enable or disable items. We are the menu delegate for both the bar
+// and for bookmark folder buttons.
+- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)anItem {
+ // NSUserInterfaceValidations says that the passed-in object has type
+ // |id<NSValidatedUserInterfaceItem>|, but this function needs to call the
+ // NSObject method -isKindOfClass: on the parameter. In theory, this is not
+ // correct, but this is probably a bug in the method signature.
+ NSMenuItem* item = static_cast<NSMenuItem*>(anItem);
+ // Yes for everything we don't explicitly deny.
+ if (![item isKindOfClass:[NSMenuItem class]])
+ return YES;
+
+ // Yes if we're not a special BookmarkMenu.
+ if (![[item menu] isKindOfClass:[BookmarkMenu class]])
+ return YES;
+
+ // No if we think it's a special BookmarkMenu but have trouble.
+ const BookmarkNode* node = [self nodeFromMenuItem:item];
+ if (!node)
+ return NO;
+
+ // If this is the bar menu, we only have things to do if there are
+ // buttons. If this is a folder button menu, we only have things to
+ // do if the folder has items.
+ NSMenu* menu = [item menu];
+ BOOL thingsToDo = NO;
+ if (menu == [[self view] menu]) {
+ thingsToDo = [buttons_ count] ? YES : NO;
+ } else {
+ if (node && node->is_folder() && node->GetChildCount()) {
+ thingsToDo = YES;
+ }
+ }
+
+ // Disable openAll* if we have nothing to do.
+ SEL action = [item action];
+ if ((!thingsToDo) &&
+ ((action == @selector(openAllBookmarks:)) ||
+ (action == @selector(openAllBookmarksNewWindow:)) ||
+ (action == @selector(openAllBookmarksIncognitoWindow:)))) {
+ return NO;
+ }
+
+ if ((action == @selector(editBookmark:)) ||
+ (action == @selector(deleteBookmark:)) ||
+ (action == @selector(cutBookmark:)) ||
+ (action == @selector(copyBookmark:))) {
+ if (![self canEditBookmark:node]) {
+ return NO;
+ }
+ }
+
+ if (action == @selector(pasteBookmark:) &&
+ !bookmark_utils::CanPasteFromClipboard(node))
+ return NO;
+
+ // If this is an incognito window, don't allow "open in incognito".
+ if ((action == @selector(openBookmarkInIncognitoWindow:)) ||
+ (action == @selector(openAllBookmarksIncognitoWindow:))) {
+ if (browser_->profile()->IsOffTheRecord()) {
+ return NO;
+ }
+ }
+
+ // Enabled by default.
+ return YES;
+}
+
+// Actually open the URL. This is the last chance for a unit test to
+// override.
+- (void)openURL:(GURL)url disposition:(WindowOpenDisposition)disposition {
+ browser_->OpenURL(url, GURL(), disposition, PageTransition::AUTO_BOOKMARK);
+}
+
+- (void)clearMenuTagMap {
+ seedId_ = 0;
+ menuTagMap_.clear();
+}
+
+- (int)preferredHeight {
+ DCHECK(![self isAnimationRunning]);
+
+ if (!barIsEnabled_)
+ return 0;
+
+ switch (visualState_) {
+ case bookmarks::kShowingState:
+ return bookmarks::kBookmarkBarHeight;
+ case bookmarks::kDetachedState:
+ return bookmarks::kNTPBookmarkBarHeight;
+ case bookmarks::kHiddenState:
+ return 0;
+ case bookmarks::kInvalidState:
+ default:
+ NOTREACHED();
+ return 0;
+ }
+}
+
+// Recursively add the given bookmark node and all its children to
+// menu, one menu item per node.
+- (void)addNode:(const BookmarkNode*)child toMenu:(NSMenu*)menu {
+ NSString* title = [BookmarkMenuCocoaController menuTitleForNode:child];
+ NSMenuItem* item = [[[NSMenuItem alloc] initWithTitle:title
+ action:nil
+ keyEquivalent:@""] autorelease];
+ [menu addItem:item];
+ [item setImage:[self favIconForNode:child]];
+ if (child->is_folder()) {
+ NSMenu* submenu = [[[NSMenu alloc] initWithTitle:title] autorelease];
+ [menu setSubmenu:submenu forItem:item];
+ if (child->GetChildCount()) {
+ [self addFolderNode:child toMenu:submenu]; // potentially recursive
+ } else {
+ [self tagEmptyMenu:submenu];
+ }
+ } else {
+ [item setTarget:self];
+ [item setAction:@selector(openBookmarkMenuItem:)];
+ [item setTag:[self menuTagFromNodeId:child->id()]];
+ // Add a tooltip
+ std::string url_string = child->GetURL().possibly_invalid_spec();
+ NSString* tooltip = [NSString stringWithFormat:@"%@\n%s",
+ base::SysUTF16ToNSString(child->GetTitle()),
+ url_string.c_str()];
+ [item setToolTip:tooltip];
+ }
+}
+
+// Empty menus are odd; if empty, add something to look at.
+// Matches windows behavior.
+- (void)tagEmptyMenu:(NSMenu*)menu {
+ NSString* empty_menu_title = l10n_util::GetNSString(IDS_MENU_EMPTY_SUBMENU);
+ [menu addItem:[[[NSMenuItem alloc] initWithTitle:empty_menu_title
+ action:NULL
+ keyEquivalent:@""] autorelease]];
+}
+
+// Add the children of the given bookmark node (and their children...)
+// to menu, one menu item per node.
+- (void)addFolderNode:(const BookmarkNode*)node toMenu:(NSMenu*)menu {
+ for (int i = 0; i < node->GetChildCount(); i++) {
+ const BookmarkNode* child = node->GetChild(i);
+ [self addNode:child toMenu:menu];
+ }
+}
+
+// Return an autoreleased NSMenu that represents the given bookmark
+// folder node.
+- (NSMenu *)menuForFolderNode:(const BookmarkNode*)node {
+ if (!node->is_folder())
+ return nil;
+ NSString* title = base::SysUTF16ToNSString(node->GetTitle());
+ NSMenu* menu = [[[NSMenu alloc] initWithTitle:title] autorelease];
+ [self addFolderNode:node toMenu:menu];
+
+ if (![menu numberOfItems]) {
+ [self tagEmptyMenu:menu];
+ }
+ return menu;
+}
+
+// Return an appropriate width for the given bookmark button cell.
+// The "+2" is needed because, sometimes, Cocoa is off by a tad.
+// Example: for a bookmark named "Moma" or "SFGate", it is one pixel
+// too small. For "FBL" it is 2 pixels too small.
+// For a bookmark named "SFGateFooWoo", it is just fine.
+- (CGFloat)widthForBookmarkButtonCell:(NSCell*)cell {
+ CGFloat desired = [cell cellSize].width + 2;
+ return std::min(desired, bookmarks::kDefaultBookmarkWidth);
+}
+
+- (IBAction)openBookmarkMenuItem:(id)sender {
+ int64 tag = [self nodeIdFromMenuTag:[sender tag]];
+ const BookmarkNode* node = bookmarkModel_->GetNodeByID(tag);
+ WindowOpenDisposition disposition =
+ event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
+ [self openURL:node->GetURL() disposition:disposition];
+}
+
+// For the given root node of the bookmark bar, show or hide (as
+// appropriate) the "no items" container (text which says "bookmarks
+// go here").
+- (void)showOrHideNoItemContainerForNode:(const BookmarkNode*)node {
+ BOOL hideNoItemWarning = node->GetChildCount() > 0;
+ [[buttonView_ noItemContainer] setHidden:hideNoItemWarning];
+}
+
+// TODO(jrg): write a "build bar" so there is a nice spot for things
+// like the contextual menu which is invoked when not over a
+// bookmark. On Safari that menu has a "new folder" option.
+- (void)addNodesToButtonList:(const BookmarkNode*)node {
+ [self showOrHideNoItemContainerForNode:node];
+
+ CGFloat maxViewX = NSMaxX([[self view] bounds]);
+ int xOffset = 0;
+ for (int i = 0; i < node->GetChildCount(); i++) {
+ const BookmarkNode* child = node->GetChild(i);
+ BookmarkButton* button = [self buttonForNode:child xOffset:&xOffset];
+ if (NSMinX([button frame]) >= maxViewX)
+ break;
+ [buttons_ addObject:button];
+ }
+}
+
+- (BookmarkButton*)buttonForNode:(const BookmarkNode*)node
+ xOffset:(int*)xOffset {
+ BookmarkButtonCell* cell = [self cellForBookmarkNode:node];
+ NSRect frame = [self frameForBookmarkButtonFromCell:cell xOffset:xOffset];
+
+ scoped_nsobject<BookmarkButton>
+ button([[BookmarkButton alloc] initWithFrame:frame]);
+ DCHECK(button.get());
+
+ // [NSButton setCell:] warns to NOT use setCell: other than in the
+ // initializer of a control. However, we are using a basic
+ // NSButton whose initializer does not take an NSCell as an
+ // object. To honor the assumed semantics, we do nothing with
+ // NSButton between alloc/init and setCell:.
+ [button setCell:cell];
+ [button setDelegate:self];
+
+ // We cannot set the button cell's text color until it is placed in
+ // the button (e.g. the [button setCell:cell] call right above). We
+ // also cannot set the cell's text color until the view is added to
+ // the hierarchy. If that second part is now true, set the color.
+ // (If not we'll set the color on the 1st themeChanged:
+ // notification.)
+ ThemeProvider* themeProvider = [[[self view] window] themeProvider];
+ if (themeProvider) {
+ NSColor* color =
+ themeProvider->GetNSColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT,
+ true);
+ [cell setTextColor:color];
+ }
+
+ if (node->is_folder()) {
+ [button setTarget:self];
+ [button setAction:@selector(openBookmarkFolderFromButton:)];
+ } else {
+ // Make the button do something
+ [button setTarget:self];
+ [button setAction:@selector(openBookmark:)];
+ // Add a tooltip.
+ NSString* title = base::SysUTF16ToNSString(node->GetTitle());
+ std::string url_string = node->GetURL().possibly_invalid_spec();
+ NSString* tooltip = [NSString stringWithFormat:@"%@\n%s", title,
+ url_string.c_str()];
+ [button setToolTip:tooltip];
+ }
+ return [[button.get() retain] autorelease];
+}
+
+// Add non-bookmark buttons to the view. This includes the chevron
+// and the "other bookmarks" button. Technically "other bookmarks" is
+// a bookmark button but it is treated specially. Only needs to be
+// called when these buttons are new or when the bookmark bar is
+// cleared (e.g. on a loaded: call). Unlike addButtonsToView below,
+// we don't need to add/remove these dynamically in response to window
+// resize.
+- (void)addNonBookmarkButtonsToView {
+ [buttonView_ addSubview:otherBookmarksButton_.get()];
+ [buttonView_ addSubview:offTheSideButton_];
+}
+
+// Add bookmark buttons to the view only if they are completely
+// visible and don't overlap the "other bookmarks". Remove buttons
+// which are clipped. Called when building the bookmark bar the first time.
+- (void)addButtonsToView {
+ displayedButtonCount_ = 0;
+ NSMutableArray* buttons = [self buttons];
+ for (NSButton* button in buttons) {
+ if (NSMaxX([button frame]) > (NSMinX([offTheSideButton_ frame]) -
+ bookmarks::kBookmarkHorizontalPadding))
+ break;
+ [buttonView_ addSubview:button];
+ ++displayedButtonCount_;
+ }
+ NSUInteger removalCount =
+ [buttons count] - (NSUInteger)displayedButtonCount_;
+ if (removalCount > 0) {
+ NSRange removalRange = NSMakeRange(displayedButtonCount_, removalCount);
+ [buttons removeObjectsInRange:removalRange];
+ }
+}
+
+// Create the button for "Other Bookmarks" on the right of the bar.
+- (void)createOtherBookmarksButton {
+ // Can't create this until the model is loaded, but only need to
+ // create it once.
+ if (otherBookmarksButton_.get())
+ return;
+
+ // TODO(jrg): remove duplicate code
+ NSCell* cell = [self cellForBookmarkNode:bookmarkModel_->other_node()];
+ int ignored = 0;
+ NSRect frame = [self frameForBookmarkButtonFromCell:cell xOffset:&ignored];
+ frame.origin.x = [[self buttonView] bounds].size.width - frame.size.width;
+ frame.origin.x -= bookmarks::kBookmarkHorizontalPadding;
+ BookmarkButton* button = [[BookmarkButton alloc] initWithFrame:frame];
+ [button setDraggable:NO];
+ otherBookmarksButton_.reset(button);
+ view_id_util::SetID(button, VIEW_ID_OTHER_BOOKMARKS);
+
+ // Make sure this button, like all other BookmarkButtons, lives
+ // until the end of the current event loop.
+ [[button retain] autorelease];
+
+ // Peg at right; keep same height as bar.
+ [button setAutoresizingMask:(NSViewMinXMargin)];
+ [button setCell:cell];
+ [button setDelegate:self];
+ [button setTarget:self];
+ [button setAction:@selector(openBookmarkFolderFromButton:)];
+ [buttonView_ addSubview:button];
+
+ // Now that it's here, move the chevron over.
+ [self positionOffTheSideButton];
+}
+
+// Now that the model is loaded, set the bookmark bar root as the node
+// represented by the bookmark bar (default, background) menu.
+- (void)setNodeForBarMenu {
+ const BookmarkNode* node = bookmarkModel_->GetBookmarkBarNode();
+ BookmarkMenu* menu = static_cast<BookmarkMenu*>([[self view] menu]);
+
+ // Make sure types are compatible
+ DCHECK(sizeof(long long) == sizeof(int64));
+ [menu setRepresentedObject:[NSNumber numberWithLongLong:node->id()]];
+}
+
+// To avoid problems with sync, changes that may impact the current
+// bookmark (e.g. deletion) make sure context menus are closed. This
+// prevents deleting a node which no longer exists.
+- (void)cancelMenuTracking {
+ [buttonContextMenu_ cancelTracking];
+ [buttonFolderContextMenu_ cancelTracking];
+}
+
+// Determines the appropriate state for the given situation.
++ (bookmarks::VisualState)visualStateToShowNormalBar:(BOOL)showNormalBar
+ showDetachedBar:(BOOL)showDetachedBar {
+ if (showNormalBar)
+ return bookmarks::kShowingState;
+ if (showDetachedBar)
+ return bookmarks::kDetachedState;
+ return bookmarks::kHiddenState;
+}
+
+- (void)moveToVisualState:(bookmarks::VisualState)nextVisualState
+ withAnimation:(BOOL)animate {
+ BOOL isAnimationRunning = [self isAnimationRunning];
+
+ // No-op if the next state is the same as the "current" one, subject to the
+ // following conditions:
+ // - no animation is running; or
+ // - an animation is running and |animate| is YES ([*] if it's NO, we'd want
+ // to cancel the animation and jump to the final state).
+ if ((nextVisualState == visualState_) && (!isAnimationRunning || animate))
+ return;
+
+ // If an animation is running, we want to finalize it. Otherwise we'd have to
+ // be able to animate starting from the middle of one type of animation. We
+ // assume that animations that we know about can be "reversed".
+ if (isAnimationRunning) {
+ // Don't cancel if we're going to reverse the animation.
+ if (nextVisualState != lastVisualState_) {
+ [self stopCurrentAnimation];
+ [self finalizeVisualState];
+ }
+
+ // If we're in case [*] above, we can stop here.
+ if (nextVisualState == visualState_)
+ return;
+ }
+
+ // Now update with the new state change.
+ lastVisualState_ = visualState_;
+ visualState_ = nextVisualState;
+
+ // Animate only if told to and if bar is enabled.
+ if (animate && !ignoreAnimations_ && barIsEnabled_) {
+ [self closeAllBookmarkFolders];
+ // Take care of any animation cases we know how to handle.
+
+ // We know how to handle hidden <-> normal, normal <-> detached....
+ if ([self isAnimatingBetweenState:bookmarks::kHiddenState
+ andState:bookmarks::kShowingState] ||
+ [self isAnimatingBetweenState:bookmarks::kShowingState
+ andState:bookmarks::kDetachedState]) {
+ [delegate_ bookmarkBar:self willAnimateFromState:lastVisualState_
+ toState:visualState_];
+ [self showBookmarkBarWithAnimation:YES];
+ return;
+ }
+
+ // If we ever need any other animation cases, code would go here.
+ // Let any animation cases which we don't know how to handle fall through to
+ // the unanimated case.
+ }
+
+ // Just jump to the state.
+ [self finalizeVisualState];
+}
+
+// N.B.: |-moveToVisualState:...| will check if this should be a no-op or not.
+- (void)updateAndShowNormalBar:(BOOL)showNormalBar
+ showDetachedBar:(BOOL)showDetachedBar
+ withAnimation:(BOOL)animate {
+ bookmarks::VisualState newVisualState =
+ [BookmarkBarController visualStateToShowNormalBar:showNormalBar
+ showDetachedBar:showDetachedBar];
+ [self moveToVisualState:newVisualState
+ withAnimation:animate && !ignoreAnimations_];
+}
+
+// (Private)
+- (void)finalizeVisualState {
+ // We promise that our delegate that the variables will be finalized before
+ // the call to |-bookmarkBar:didChangeFromState:toState:|.
+ bookmarks::VisualState oldVisualState = lastVisualState_;
+ lastVisualState_ = bookmarks::kInvalidState;
+
+ // Notify our delegate.
+ [delegate_ bookmarkBar:self didChangeFromState:oldVisualState
+ toState:visualState_];
+
+ // Update ourselves visually.
+ [self updateVisibility];
+}
+
+// (Private)
+- (void)stopCurrentAnimation {
+ [[self animatableView] stopAnimation];
+}
+
+// Delegate method for |AnimatableView| (a superclass of
+// |BookmarkBarToolbarView|).
+- (void)animationDidEnd:(NSAnimation*)animation {
+ [self finalizeVisualState];
+}
+
+- (void)reconfigureBookmarkBar {
+ [self redistributeButtonsOnBarAsNeeded];
+ [self positionOffTheSideButton];
+ [self configureOffTheSideButtonContentsAndVisibility];
+ [self centerNoItemsLabel];
+}
+
+// Determine if the given |view| can completely fit within the constraint of
+// maximum x, given by |maxViewX|, and, if not, narrow the view up to a minimum
+// width. If the minimum width is not achievable then hide the view. Return YES
+// if the view was hidden.
+- (BOOL)shrinkOrHideView:(NSView*)view forMaxX:(CGFloat)maxViewX {
+ BOOL wasHidden = NO;
+ // See if the view needs to be narrowed.
+ NSRect frame = [view frame];
+ if (NSMaxX(frame) > maxViewX) {
+ // Resize if more than 30 pixels are showing, otherwise hide.
+ if (NSMinX(frame) + 30.0 < maxViewX) {
+ frame.size.width = maxViewX - NSMinX(frame);
+ [view setFrame:frame];
+ } else {
+ [view setHidden:YES];
+ wasHidden = YES;
+ }
+ }
+ return wasHidden;
+}
+
+// Adjust the horizontal width and the visibility of the "For quick access"
+// text field and "Import bookmarks..." button based on the current width
+// of the containing |buttonView_| (which is affected by window width).
+- (void)adjustNoItemContainerWidthsForMaxX:(CGFloat)maxViewX {
+ if (![[buttonView_ noItemContainer] isHidden]) {
+ // Reset initial frames for the two items, then adjust as necessary.
+ NSTextField* noItemTextfield = [buttonView_ noItemTextfield];
+ [noItemTextfield setFrame:originalNoItemsRect_];
+ [noItemTextfield setHidden:NO];
+ NSButton* importBookmarksButton = [buttonView_ importBookmarksButton];
+ [importBookmarksButton setFrame:originalImportBookmarksRect_];
+ [importBookmarksButton setHidden:NO];
+ // Check each to see if they need to be shrunk or hidden.
+ if ([self shrinkOrHideView:importBookmarksButton forMaxX:maxViewX])
+ [self shrinkOrHideView:noItemTextfield forMaxX:maxViewX];
+ }
+}
+
+- (void)redistributeButtonsOnBarAsNeeded {
+ const BookmarkNode* node = bookmarkModel_->GetBookmarkBarNode();
+ NSInteger barCount = node->GetChildCount();
+
+ // Determine the current maximum extent of the visible buttons.
+ CGFloat maxViewX = NSMaxX([[self view] bounds]);
+ NSButton* otherBookmarksButton = otherBookmarksButton_.get();
+ // If necessary, pull in the width to account for the Other Bookmarks button.
+ if (otherBookmarksButton_)
+ maxViewX = [otherBookmarksButton frame].origin.x -
+ bookmarks::kBookmarkHorizontalPadding;
+ // If we're already overflowing, then we need to account for the chevron.
+ if (barCount > displayedButtonCount_)
+ maxViewX = [offTheSideButton_ frame].origin.x -
+ bookmarks::kBookmarkHorizontalPadding;
+
+ // As a result of pasting or dragging, the bar may now have more buttons
+ // than will fit so remove any which overflow. They will be shown in
+ // the off-the-side folder.
+ while (displayedButtonCount_ > 0) {
+ BookmarkButton* button = [buttons_ lastObject];
+ if (NSMaxX([button frame]) < maxViewX)
+ break;
+ [buttons_ removeLastObject];
+ [button setDelegate:nil];
+ [button removeFromSuperview];
+ --displayedButtonCount_;
+ }
+
+ // As a result of cutting, deleting and dragging, the bar may now have room
+ // for more buttons.
+ int xOffset = displayedButtonCount_ > 0 ?
+ NSMaxX([[buttons_ lastObject] frame]) +
+ bookmarks::kBookmarkHorizontalPadding : 0;
+ for (int i = displayedButtonCount_; i < barCount; ++i) {
+ const BookmarkNode* child = node->GetChild(i);
+ BookmarkButton* button = [self buttonForNode:child xOffset:&xOffset];
+ // If we're testing against the last possible button then account
+ // for the chevron no longer needing to be shown.
+ if (i == barCount + 1)
+ maxViewX += NSWidth([offTheSideButton_ frame]) +
+ bookmarks::kBookmarkHorizontalPadding;
+ if (NSMaxX([button frame]) >= maxViewX)
+ break;
+ ++displayedButtonCount_;
+ [buttons_ addObject:button];
+ [buttonView_ addSubview:button];
+ }
+
+ // While we're here, adjust the horizontal width and the visibility
+ // of the "For quick access" and "Import bookmarks..." text fields.
+ if (![buttons_ count])
+ [self adjustNoItemContainerWidthsForMaxX:maxViewX];
+}
+
+#pragma mark Private Methods Exposed for Testing
+
+- (BookmarkBarView*)buttonView {
+ return buttonView_;
+}
+
+- (NSMutableArray*)buttons {
+ return buttons_.get();
+}
+
+- (NSButton*)offTheSideButton {
+ return offTheSideButton_;
+}
+
+- (BOOL)offTheSideButtonIsHidden {
+ return [offTheSideButton_ isHidden];
+}
+
+- (BookmarkButton*)otherBookmarksButton {
+ return otherBookmarksButton_.get();
+}
+
+- (BookmarkBarFolderController*)folderController {
+ return folderController_;
+}
+
+- (id)folderTarget {
+ return folderTarget_.get();
+}
+
+- (int)displayedButtonCount {
+ return displayedButtonCount_;
+}
+
+// Delete all buttons (bookmarks, chevron, "other bookmarks") from the
+// bookmark bar; reset knowledge of bookmarks.
+- (void)clearBookmarkBar {
+ for (BookmarkButton* button in buttons_.get()) {
+ [button setDelegate:nil];
+ [button removeFromSuperview];
+ }
+ [buttons_ removeAllObjects];
+ [self clearMenuTagMap];
+ displayedButtonCount_ = 0;
+
+ // Make sure there are no stale pointers in the pasteboard. This
+ // can be important if a bookmark is deleted (via bookmark sync)
+ // while in the middle of a drag. The "drag completed" code
+ // (e.g. [BookmarkBarView performDragOperationForBookmarkButton:]) is
+ // careful enough to bail if there is no data found at "drop" time.
+ //
+ // Unfortunately the clearContents selector is 10.6 only. The best
+ // we can do is make sure something else is present in place of the
+ // stale bookmark.
+ NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
+ [pboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:self];
+ [pboard setString:@"" forType:NSStringPboardType];
+}
+
+// Return an autoreleased NSCell suitable for a bookmark button.
+// TODO(jrg): move much of the cell config into the BookmarkButtonCell class.
+- (BookmarkButtonCell*)cellForBookmarkNode:(const BookmarkNode*)node {
+ NSImage* image = node ? [self favIconForNode:node] : nil;
+ NSMenu* menu = node && node->is_folder() ? buttonFolderContextMenu_ :
+ buttonContextMenu_;
+ BookmarkButtonCell* cell = [BookmarkButtonCell buttonCellForNode:node
+ contextMenu:menu
+ cellText:nil
+ cellImage:image];
+ [cell setTag:kStandardButtonTypeWithLimitedClickFeedback];
+
+ // Note: a quirk of setting a cell's text color is that it won't work
+ // until the cell is associated with a button, so we can't theme the cell yet.
+
+ return cell;
+}
+
+// Returns a frame appropriate for the given bookmark cell, suitable
+// for creating an NSButton that will contain it. |xOffset| is the X
+// offset for the frame; it is increased to be an appropriate X offset
+// for the next button.
+- (NSRect)frameForBookmarkButtonFromCell:(NSCell*)cell
+ xOffset:(int*)xOffset {
+ DCHECK(xOffset);
+ NSRect bounds = [buttonView_ bounds];
+ bounds.size.height = bookmarks::kBookmarkButtonHeight;
+
+ NSRect frame = NSInsetRect(bounds,
+ bookmarks::kBookmarkHorizontalPadding,
+ bookmarks::kBookmarkVerticalPadding);
+ frame.size.width = [self widthForBookmarkButtonCell:cell];
+
+ // Add an X offset based on what we've already done
+ frame.origin.x += *xOffset;
+
+ // And up the X offset for next time.
+ *xOffset = NSMaxX(frame);
+
+ return frame;
+}
+
+// A bookmark button's contents changed. Check for growth
+// (e.g. increase the width up to the maximum). If we grew, move
+// other bookmark buttons over.
+- (void)checkForBookmarkButtonGrowth:(NSButton*)button {
+ NSRect frame = [button frame];
+ CGFloat desiredSize = [self widthForBookmarkButtonCell:[button cell]];
+ CGFloat delta = desiredSize - frame.size.width;
+ if (delta) {
+ frame.size.width = desiredSize;
+ [button setFrame:frame];
+ for (NSButton* button in buttons_.get()) {
+ NSRect buttonFrame = [button frame];
+ if (buttonFrame.origin.x > frame.origin.x) {
+ buttonFrame.origin.x += delta;
+ [button setFrame:buttonFrame];
+ }
+ }
+ }
+ // We may have just crossed a threshold to enable the off-the-side
+ // button.
+ [self configureOffTheSideButtonContentsAndVisibility];
+}
+
+// Called when our controlled frame has changed size.
+- (void)frameDidChange {
+ if (!bookmarkModel_->IsLoaded())
+ return;
+ [self updateTheme:[[[self view] window] themeProvider]];
+ [self reconfigureBookmarkBar];
+}
+
+// Given a NSMenuItem tag, return the appropriate bookmark node id.
+- (int64)nodeIdFromMenuTag:(int32)tag {
+ return menuTagMap_[tag];
+}
+
+// Create and return a new tag for the given node id.
+- (int32)menuTagFromNodeId:(int64)menuid {
+ int tag = seedId_++;
+ menuTagMap_[tag] = menuid;
+ return tag;
+}
+
+// Return the BookmarkNode associated with the given NSMenuItem. Can
+// return NULL which means "do nothing". One case where it would
+// return NULL is if the bookmark model gets modified while you have a
+// context menu open.
+- (const BookmarkNode*)nodeFromMenuItem:(id)sender {
+ const BookmarkNode* node = NULL;
+ BookmarkMenu* menu = (BookmarkMenu*)[sender menu];
+ if ([menu isKindOfClass:[BookmarkMenu class]]) {
+ int64 id = [menu id];
+ node = bookmarkModel_->GetNodeByID(id);
+ }
+ return node;
+}
+
+// Adapt appearance of buttons to the current theme. Called after
+// theme changes, or when our view is added to the view hierarchy.
+// Oddly, the view pings us instead of us pinging our view. This is
+// because our trigger is an [NSView viewWillMoveToWindow:], which the
+// controller doesn't normally know about. Otherwise we don't have
+// access to the theme before we know what window we will be on.
+- (void)updateTheme:(ThemeProvider*)themeProvider {
+ if (!themeProvider)
+ return;
+ NSColor* color =
+ themeProvider->GetNSColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT,
+ true);
+ for (BookmarkButton* button in buttons_.get()) {
+ BookmarkButtonCell* cell = [button cell];
+ [cell setTextColor:color];
+ }
+ [[otherBookmarksButton_ cell] setTextColor:color];
+}
+
+// Return YES if the event indicates an exit from the bookmark bar
+// folder menus. E.g. "click outside" of the area we are watching.
+// At this time we are watching the area that includes all popup
+// bookmark folder windows.
+- (BOOL)isEventAnExitEvent:(NSEvent*)event {
+ NSWindow* eventWindow = [event window];
+ NSWindow* myWindow = [[self view] window];
+ switch ([event type]) {
+ case NSLeftMouseDown:
+ case NSRightMouseDown:
+ // If the click is in my window but NOT in the bookmark bar, consider
+ // it a click 'outside'. Clicks directly on an active button (i.e. one
+ // that is a folder and for which its folder menu is showing) are 'in'.
+ // All other clicks on the bookmarks bar are counted as 'outside'
+ // because they should close any open bookmark folder menu.
+ if (eventWindow == myWindow) {
+ NSView* hitView =
+ [[eventWindow contentView] hitTest:[event locationInWindow]];
+ if (hitView == [folderController_ parentButton])
+ return NO;
+ if (![hitView isDescendantOf:[self view]] || hitView == buttonView_)
+ return YES;
+ }
+ // If a click in a bookmark bar folder window and that isn't
+ // one of my bookmark bar folders, YES is click outside.
+ if (![eventWindow isKindOfClass:[BookmarkBarFolderWindow
+ class]]) {
+ return YES;
+ }
+ break;
+ case NSKeyDown:
+ case NSKeyUp:
+ // Any key press ends things.
+ return YES;
+ case NSLeftMouseDragged:
+ // We can get here with the following sequence:
+ // - open a bookmark folder
+ // - right-click (and unclick) on it to open context menu
+ // - move mouse to window titlebar then click-drag it by the titlebar
+ // http://crbug.com/49333
+ return YES;
+ default:
+ break;
+ }
+ return NO;
+}
+
+#pragma mark Drag & Drop
+
+// Find something like std::is_between<T>? I can't believe one doesn't exist.
+static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) {
+ return ((value >= low) && (value <= high));
+}
+
+// Return the proposed drop target for a hover open button from the
+// given array, or nil if none. We use this for distinguishing
+// between a hover-open candidate or drop-indicator draw.
+// Helper for buttonForDroppingOnAtPoint:.
+// Get UI review on "middle half" ness.
+// http://crbug.com/36276
+- (BookmarkButton*)buttonForDroppingOnAtPoint:(NSPoint)point
+ fromArray:(NSArray*)array {
+ for (BookmarkButton* button in array) {
+ // Break early if we've gone too far.
+ if ((NSMinX([button frame]) > point.x) || (![button superview]))
+ return nil;
+ // Careful -- this only applies to the bar with horiz buttons.
+ // Intentionally NOT using NSPointInRect() so that scrolling into
+ // a submenu doesn't cause it to be closed.
+ if (ValueInRangeInclusive(NSMinX([button frame]),
+ point.x,
+ NSMaxX([button frame]))) {
+ // Over a button but let's be a little more specific (make sure
+ // it's over the middle half, not just over it).
+ NSRect frame = [button frame];
+ NSRect middleHalfOfButton = NSInsetRect(frame, frame.size.width / 4, 0);
+ if (ValueInRangeInclusive(NSMinX(middleHalfOfButton),
+ point.x,
+ NSMaxX(middleHalfOfButton))) {
+ // It makes no sense to drop on a non-folder; there is no hover.
+ if (![button isFolder])
+ return nil;
+ // Got it!
+ return button;
+ } else {
+ // Over a button but not over the middle half.
+ return nil;
+ }
+ }
+ }
+ // Not hovering over a button.
+ return nil;
+}
+
+// Return the proposed drop target for a hover open button, or nil if
+// none. Works with both the bookmark buttons and the "Other
+// Bookmarks" button. Point is in [self view] coordinates.
+- (BookmarkButton*)buttonForDroppingOnAtPoint:(NSPoint)point {
+ point = [[self view] convertPoint:point
+ fromView:[[[self view] window] contentView]];
+ BookmarkButton* button = [self buttonForDroppingOnAtPoint:point
+ fromArray:buttons_.get()];
+ // One more chance -- try "Other Bookmarks" and "off the side" (if visible).
+ // This is different than BookmarkBarFolderController.
+ if (!button) {
+ NSMutableArray* array = [NSMutableArray array];
+ if (![self offTheSideButtonIsHidden])
+ [array addObject:offTheSideButton_];
+ [array addObject:otherBookmarksButton_];
+ button = [self buttonForDroppingOnAtPoint:point
+ fromArray:array];
+ }
+ return button;
+}
+
+- (int)indexForDragToPoint:(NSPoint)point {
+ // TODO(jrg): revisit position info based on UI team feedback.
+ // dropLocation is in bar local coordinates.
+ NSPoint dropLocation =
+ [[self view] convertPoint:point
+ fromView:[[[self view] window] contentView]];
+ BookmarkButton* buttonToTheRightOfDraggedButton = nil;
+ for (BookmarkButton* button in buttons_.get()) {
+ CGFloat midpoint = NSMidX([button frame]);
+ if (dropLocation.x <= midpoint) {
+ buttonToTheRightOfDraggedButton = button;
+ break;
+ }
+ }
+ if (buttonToTheRightOfDraggedButton) {
+ const BookmarkNode* afterNode =
+ [buttonToTheRightOfDraggedButton bookmarkNode];
+ DCHECK(afterNode);
+ int index = afterNode->GetParent()->IndexOfChild(afterNode);
+ // Make sure we don't get confused by buttons which aren't visible.
+ return std::min(index, displayedButtonCount_);
+ }
+
+ // If nothing is to my right I am at the end!
+ return displayedButtonCount_;
+}
+
+// TODO(mrossetti,jrg): Yet more duplicated code.
+// http://crbug.com/35966
+- (BOOL)dragBookmark:(const BookmarkNode*)sourceNode
+ to:(NSPoint)point
+ copy:(BOOL)copy {
+ DCHECK(sourceNode);
+ // Drop destination.
+ const BookmarkNode* destParent = NULL;
+ int destIndex = 0;
+
+ // First check if we're dropping on a button. If we have one, and
+ // it's a folder, drop in it.
+ BookmarkButton* button = [self buttonForDroppingOnAtPoint:point];
+ if ([button isFolder]) {
+ destParent = [button bookmarkNode];
+ // Drop it at the end.
+ destIndex = [button bookmarkNode]->GetChildCount();
+ } else {
+ // Else we're dropping somewhere on the bar, so find the right spot.
+ destParent = bookmarkModel_->GetBookmarkBarNode();
+ destIndex = [self indexForDragToPoint:point];
+ }
+
+ // Be sure we don't try and drop a folder into itself.
+ if (sourceNode != destParent) {
+ if (copy)
+ bookmarkModel_->Copy(sourceNode, destParent, destIndex);
+ else
+ bookmarkModel_->Move(sourceNode, destParent, destIndex);
+ }
+
+ [self closeFolderAndStopTrackingMenus];
+
+ // Movement of a node triggers observers (like us) to rebuild the
+ // bar so we don't have to do so explicitly.
+
+ return YES;
+}
+
+- (void)draggingEnded:(id<NSDraggingInfo>)info {
+ [self closeFolderAndStopTrackingMenus];
+}
+
+#pragma mark Bridge Notification Handlers
+
+// TODO(jrg): for now this is brute force.
+- (void)loaded:(BookmarkModel*)model {
+ DCHECK(model == bookmarkModel_);
+ if (!model->IsLoaded())
+ return;
+
+ // If this is a rebuild request while we have a folder open, close it.
+ // TODO(mrossetti): Eliminate the need for this because it causes the folder
+ // menu to disappear after a cut/copy/paste/delete change.
+ // See: http://crbug.com/36614
+ if (folderController_)
+ [self closeAllBookmarkFolders];
+
+ // Brute force nuke and build.
+ savedFrameWidth_ = NSWidth([[self view] frame]);
+ const BookmarkNode* node = model->GetBookmarkBarNode();
+ [self clearBookmarkBar];
+ [self addNodesToButtonList:node];
+ [self createOtherBookmarksButton];
+ [self updateTheme:[[[self view] window] themeProvider]];
+ [self positionOffTheSideButton];
+ [self addNonBookmarkButtonsToView];
+ [self addButtonsToView];
+ [self configureOffTheSideButtonContentsAndVisibility];
+ [self setNodeForBarMenu];
+}
+
+- (void)beingDeleted:(BookmarkModel*)model {
+ // The browser may be being torn down; little is safe to do. As an
+ // example, it may not be safe to clear the pasteboard.
+ // http://crbug.com/38665
+}
+
+- (void)nodeAdded:(BookmarkModel*)model
+ parent:(const BookmarkNode*)newParent index:(int)newIndex {
+ // If a context menu is open, close it.
+ [self cancelMenuTracking];
+
+ const BookmarkNode* newNode = newParent->GetChild(newIndex);
+ id<BookmarkButtonControllerProtocol> newController =
+ [self controllerForNode:newParent];
+ [newController addButtonForNode:newNode atIndex:newIndex];
+ // If we go from 0 --> 1 bookmarks we may need to hide the
+ // "bookmarks go here" text container.
+ [self showOrHideNoItemContainerForNode:model->GetBookmarkBarNode()];
+}
+
+// TODO(jrg): for now this is brute force.
+- (void)nodeChanged:(BookmarkModel*)model
+ node:(const BookmarkNode*)node {
+ [self loaded:model];
+}
+
+- (void)nodeMoved:(BookmarkModel*)model
+ oldParent:(const BookmarkNode*)oldParent oldIndex:(int)oldIndex
+ newParent:(const BookmarkNode*)newParent newIndex:(int)newIndex {
+ const BookmarkNode* movedNode = newParent->GetChild(newIndex);
+ id<BookmarkButtonControllerProtocol> oldController =
+ [self controllerForNode:oldParent];
+ id<BookmarkButtonControllerProtocol> newController =
+ [self controllerForNode:newParent];
+ if (newController == oldController) {
+ [oldController moveButtonFromIndex:oldIndex toIndex:newIndex];
+ } else {
+ [oldController removeButton:oldIndex animate:NO];
+ [newController addButtonForNode:movedNode atIndex:newIndex];
+ }
+ // If the bar is one of the parents we may need to update the visibility
+ // of the "bookmarks go here" presentation.
+ [self showOrHideNoItemContainerForNode:model->GetBookmarkBarNode()];
+ // If we moved the only item on the "off the side" menu somewhere
+ // else, we may no longer need to show it.
+ [self configureOffTheSideButtonContentsAndVisibility];
+}
+
+- (void)nodeRemoved:(BookmarkModel*)model
+ parent:(const BookmarkNode*)oldParent index:(int)index {
+ // If a context menu is open, close it.
+ [self cancelMenuTracking];
+
+ // Locate the parent node. The parent may not be showing, in which case
+ // we do nothing.
+ id<BookmarkButtonControllerProtocol> parentController =
+ [self controllerForNode:oldParent];
+ [parentController removeButton:index animate:YES];
+ // If we go from 1 --> 0 bookmarks we may need to show the
+ // "bookmarks go here" text container.
+ [self showOrHideNoItemContainerForNode:model->GetBookmarkBarNode()];
+ // If we deleted the only item on the "off the side" menu we no
+ // longer need to show it.
+ [self configureOffTheSideButtonContentsAndVisibility];
+}
+
+// TODO(jrg): linear searching is bad.
+// Need a BookmarkNode-->NSCell mapping.
+//
+// TODO(jrg): if the bookmark bar is open on launch, we see the
+// buttons all placed, then "scooted over" as the favicons load. If
+// this looks bad I may need to change widthForBookmarkButtonCell to
+// add space for an image even if not there on the assumption that
+// favicons will eventually load.
+- (void)nodeFavIconLoaded:(BookmarkModel*)model
+ node:(const BookmarkNode*)node {
+ for (BookmarkButton* button in buttons_.get()) {
+ const BookmarkNode* cellnode = [button bookmarkNode];
+ if (cellnode == node) {
+ [[button cell] setBookmarkCellText:[button title]
+ image:[self favIconForNode:node]];
+ // Adding an image means we might need more room for the
+ // bookmark. Test for it by growing the button (if needed)
+ // and shifting everything else over.
+ [self checkForBookmarkButtonGrowth:button];
+ }
+ }
+}
+
+// TODO(jrg): for now this is brute force.
+- (void)nodeChildrenReordered:(BookmarkModel*)model
+ node:(const BookmarkNode*)node {
+ [self loaded:model];
+}
+
+#pragma mark BookmarkBarState Protocol
+
+// (BookmarkBarState protocol)
+- (BOOL)isVisible {
+ return barIsEnabled_ && (visualState_ == bookmarks::kShowingState ||
+ visualState_ == bookmarks::kDetachedState ||
+ lastVisualState_ == bookmarks::kShowingState ||
+ lastVisualState_ == bookmarks::kDetachedState);
+}
+
+// (BookmarkBarState protocol)
+- (BOOL)isAnimationRunning {
+ return lastVisualState_ != bookmarks::kInvalidState;
+}
+
+// (BookmarkBarState protocol)
+- (BOOL)isInState:(bookmarks::VisualState)state {
+ return visualState_ == state &&
+ lastVisualState_ == bookmarks::kInvalidState;
+}
+
+// (BookmarkBarState protocol)
+- (BOOL)isAnimatingToState:(bookmarks::VisualState)state {
+ return visualState_ == state &&
+ lastVisualState_ != bookmarks::kInvalidState;
+}
+
+// (BookmarkBarState protocol)
+- (BOOL)isAnimatingFromState:(bookmarks::VisualState)state {
+ return lastVisualState_ == state;
+}
+
+// (BookmarkBarState protocol)
+- (BOOL)isAnimatingFromState:(bookmarks::VisualState)fromState
+ toState:(bookmarks::VisualState)toState {
+ return lastVisualState_ == fromState && visualState_ == toState;
+}
+
+// (BookmarkBarState protocol)
+- (BOOL)isAnimatingBetweenState:(bookmarks::VisualState)fromState
+ andState:(bookmarks::VisualState)toState {
+ return (lastVisualState_ == fromState && visualState_ == toState) ||
+ (visualState_ == fromState && lastVisualState_ == toState);
+}
+
+// (BookmarkBarState protocol)
+- (CGFloat)detachedMorphProgress {
+ if ([self isInState:bookmarks::kDetachedState]) {
+ return 1;
+ }
+ if ([self isAnimatingToState:bookmarks::kDetachedState]) {
+ return static_cast<CGFloat>(
+ [[self animatableView] currentAnimationProgress]);
+ }
+ if ([self isAnimatingFromState:bookmarks::kDetachedState]) {
+ return static_cast<CGFloat>(
+ 1 - [[self animatableView] currentAnimationProgress]);
+ }
+ return 0;
+}
+
+#pragma mark BookmarkBarToolbarViewController Protocol
+
+- (int)currentTabContentsHeight {
+ TabContents* tc = browser_->GetSelectedTabContents();
+ return tc ? tc->view()->GetContainerSize().height() : 0;
+}
+
+- (ThemeProvider*)themeProvider {
+ return browser_->profile()->GetThemeProvider();
+}
+
+#pragma mark BookmarkButtonDelegate Protocol
+
+- (void)fillPasteboard:(NSPasteboard*)pboard
+ forDragOfButton:(BookmarkButton*)button {
+ [[self folderTarget] fillPasteboard:pboard forDragOfButton:button];
+}
+
+// BookmarkButtonDelegate protocol implementation. When menus are
+// "active" (e.g. you clicked to open one), moving the mouse over
+// another folder button should close the 1st and open the 2nd (like
+// real menus). We detect and act here.
+- (void)mouseEnteredButton:(id)sender event:(NSEvent*)event {
+ DCHECK([sender isKindOfClass:[BookmarkButton class]]);
+
+ // If folder menus are not being shown, do nothing. This is different from
+ // BookmarkBarFolderController's implementation because the bar should NOT
+ // automatically open folder menus when the mouse passes over a folder
+ // button while the BookmarkBarFolderController DOES automically open
+ // a subfolder menu.
+ if (!showFolderMenus_)
+ return;
+
+ // From here down: same logic as BookmarkBarFolderController.
+ // TODO(jrg): find a way to share these 4 non-comment lines?
+ // http://crbug.com/35966
+ // If already opened, then we exited but re-entered the button, so do nothing.
+ if ([folderController_ parentButton] == sender)
+ return;
+ // Else open a new one if it makes sense to do so.
+ if ([sender bookmarkNode]->is_folder()) {
+ [folderTarget_ openBookmarkFolderFromButton:sender];
+ } else {
+ // We're over a non-folder bookmark so close any old folders.
+ [folderController_ close];
+ folderController_ = nil;
+ }
+}
+
+// BookmarkButtonDelegate protocol implementation.
+- (void)mouseExitedButton:(id)sender event:(NSEvent*)event {
+ // Don't care; do nothing.
+ // This is different behavior that the folder menus.
+}
+
+- (NSWindow*)browserWindow {
+ return [[self view] window];
+}
+
+- (BOOL)canDragBookmarkButtonToTrash:(BookmarkButton*)button {
+ return [self canEditBookmark:[button bookmarkNode]];
+}
+
+- (void)didDragBookmarkToTrash:(BookmarkButton*)button {
+ // TODO(mrossetti): Refactor BookmarkBarFolder common code.
+ // http://crbug.com/35966
+ const BookmarkNode* node = [button bookmarkNode];
+ if (node) {
+ const BookmarkNode* parent = node->GetParent();
+ bookmarkModel_->Remove(parent,
+ parent->IndexOfChild(node));
+ }
+}
+
+#pragma mark BookmarkButtonControllerProtocol
+
+// Close all bookmark folders. "Folder" here is the fake menu for
+// bookmark folders, not a button context menu.
+- (void)closeAllBookmarkFolders {
+ [self watchForExitEvent:NO];
+ [folderController_ close];
+ folderController_ = nil;
+}
+
+- (void)closeBookmarkFolder:(id)sender {
+ // We're the top level, so close one means close them all.
+ [self closeAllBookmarkFolders];
+}
+
+- (BookmarkModel*)bookmarkModel {
+ return bookmarkModel_;
+}
+
+// TODO(jrg): much of this logic is duped with
+// [BookmarkBarFolderController draggingEntered:] except when noted.
+// http://crbug.com/35966
+- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info {
+ NSPoint point = [info draggingLocation];
+ BookmarkButton* button = [self buttonForDroppingOnAtPoint:point];
+
+ // Don't allow drops that would result in cycles.
+ if (button) {
+ NSData* data = [[info draggingPasteboard]
+ dataForType:kBookmarkButtonDragType];
+ if (data && [info draggingSource]) {
+ BookmarkButton* sourceButton = nil;
+ [data getBytes:&sourceButton length:sizeof(sourceButton)];
+ const BookmarkNode* sourceNode = [sourceButton bookmarkNode];
+ const BookmarkNode* destNode = [button bookmarkNode];
+ if (destNode->HasAncestor(sourceNode))
+ button = nil;
+ }
+ }
+
+ if ([button isFolder]) {
+ if (hoverButton_ == button) {
+ return NSDragOperationMove; // already open or timed to open
+ }
+ if (hoverButton_) {
+ // Oops, another one triggered or open.
+ [NSObject cancelPreviousPerformRequestsWithTarget:[hoverButton_
+ target]];
+ // Unlike BookmarkBarFolderController, we do not delay the close
+ // of the previous one. Given the lack of diagonal movement,
+ // there is no need, and it feels awkward to do so. See
+ // comments about kDragHoverCloseDelay in
+ // bookmark_bar_folder_controller.mm for more details.
+ [[hoverButton_ target] closeBookmarkFolder:hoverButton_];
+ hoverButton_.reset();
+ }
+ hoverButton_.reset([button retain]);
+ DCHECK([[hoverButton_ target]
+ respondsToSelector:@selector(openBookmarkFolderFromButton:)]);
+ [[hoverButton_ target]
+ performSelector:@selector(openBookmarkFolderFromButton:)
+ withObject:hoverButton_
+ afterDelay:bookmarks::kDragHoverOpenDelay];
+ }
+ if (!button) {
+ if (hoverButton_) {
+ [NSObject cancelPreviousPerformRequestsWithTarget:[hoverButton_ target]];
+ [[hoverButton_ target] closeBookmarkFolder:hoverButton_];
+ hoverButton_.reset();
+ }
+ }
+
+ // Thrown away but kept to be consistent with the draggingEntered: interface.
+ return NSDragOperationMove;
+}
+
+- (void)draggingExited:(id<NSDraggingInfo>)info {
+ // NOT the same as a cancel --> we may have moved the mouse into the submenu.
+ if (hoverButton_) {
+ [NSObject cancelPreviousPerformRequestsWithTarget:[hoverButton_ target]];
+ hoverButton_.reset();
+ }
+}
+
+- (BOOL)dragShouldLockBarVisibility {
+ return ![self isInState:bookmarks::kDetachedState] &&
+ ![self isAnimatingToState:bookmarks::kDetachedState];
+}
+
+// TODO(mrossetti,jrg): Yet more code dup with BookmarkBarFolderController.
+// http://crbug.com/35966
+- (BOOL)dragButton:(BookmarkButton*)sourceButton
+ to:(NSPoint)point
+ copy:(BOOL)copy {
+ DCHECK([sourceButton isKindOfClass:[BookmarkButton class]]);
+ const BookmarkNode* sourceNode = [sourceButton bookmarkNode];
+ return [self dragBookmark:sourceNode to:point copy:copy];
+}
+
+- (BOOL)dragBookmarkData:(id<NSDraggingInfo>)info {
+ BOOL dragged = NO;
+ std::vector<const BookmarkNode*> nodes([self retrieveBookmarkNodeData]);
+ if (nodes.size()) {
+ BOOL copy = !([info draggingSourceOperationMask] & NSDragOperationMove);
+ NSPoint dropPoint = [info draggingLocation];
+ for (std::vector<const BookmarkNode*>::const_iterator it = nodes.begin();
+ it != nodes.end(); ++it) {
+ const BookmarkNode* sourceNode = *it;
+ dragged = [self dragBookmark:sourceNode to:dropPoint copy:copy];
+ }
+ }
+ return dragged;
+}
+
+- (std::vector<const BookmarkNode*>)retrieveBookmarkNodeData {
+ std::vector<const BookmarkNode*> dragDataNodes;
+ BookmarkNodeData dragData;
+ if(dragData.ReadFromDragClipboard()) {
+ BookmarkModel* bookmarkModel = [self bookmarkModel];
+ Profile* profile = bookmarkModel->profile();
+ std::vector<const BookmarkNode*> nodes(dragData.GetNodes(profile));
+ dragDataNodes.assign(nodes.begin(), nodes.end());
+ }
+ return dragDataNodes;
+}
+
+// Return YES if we should show the drop indicator, else NO.
+- (BOOL)shouldShowIndicatorShownForPoint:(NSPoint)point {
+ return ![self buttonForDroppingOnAtPoint:point];
+}
+
+// Return the x position for a drop indicator.
+- (CGFloat)indicatorPosForDragToPoint:(NSPoint)point {
+ CGFloat x = 0;
+ int destIndex = [self indexForDragToPoint:point];
+ int numButtons = displayedButtonCount_;
+
+ // If it's a drop strictly between existing buttons ...
+ if (destIndex >= 0 && destIndex < numButtons) {
+ // ... put the indicator right between the buttons.
+ BookmarkButton* button =
+ [buttons_ objectAtIndex:static_cast<NSUInteger>(destIndex)];
+ DCHECK(button);
+ NSRect buttonFrame = [button frame];
+ x = buttonFrame.origin.x - 0.5 * bookmarks::kBookmarkHorizontalPadding;
+
+ // If it's a drop at the end (past the last button, if there are any) ...
+ } else if (destIndex == numButtons) {
+ // and if it's past the last button ...
+ if (numButtons > 0) {
+ // ... find the last button, and put the indicator to its right.
+ BookmarkButton* button =
+ [buttons_ objectAtIndex:static_cast<NSUInteger>(destIndex - 1)];
+ DCHECK(button);
+ NSRect buttonFrame = [button frame];
+ x = NSMaxX(buttonFrame) + 0.5 * bookmarks::kBookmarkHorizontalPadding;
+
+ // Otherwise, put it right at the beginning.
+ } else {
+ x = 0.5 * bookmarks::kBookmarkHorizontalPadding;
+ }
+ } else {
+ NOTREACHED();
+ }
+
+ return x;
+}
+
+- (void)childFolderWillShow:(id<BookmarkButtonControllerProtocol>)child {
+ // If the bookmarkbar is not in detached mode, lock bar visibility, forcing
+ // the overlay to stay open when in fullscreen mode.
+ if (![self isInState:bookmarks::kDetachedState] &&
+ ![self isAnimatingToState:bookmarks::kDetachedState]) {
+ BrowserWindowController* browserController =
+ [BrowserWindowController browserWindowControllerForView:[self view]];
+ [browserController lockBarVisibilityForOwner:child
+ withAnimation:NO
+ delay:NO];
+ }
+}
+
+- (void)childFolderWillClose:(id<BookmarkButtonControllerProtocol>)child {
+ // Release bar visibility, allowing the overlay to close if in fullscreen
+ // mode.
+ BrowserWindowController* browserController =
+ [BrowserWindowController browserWindowControllerForView:[self view]];
+ [browserController releaseBarVisibilityForOwner:child
+ withAnimation:NO
+ delay:NO];
+}
+
+// Add a new folder controller as triggered by the given folder button.
+- (void)addNewFolderControllerWithParentButton:(BookmarkButton*)parentButton {
+
+ // If doing a close/open, make sure the fullscreen chrome doesn't
+ // have a chance to begin animating away in the middle of things.
+ BrowserWindowController* browserController =
+ [BrowserWindowController browserWindowControllerForView:[self view]];
+ // Confirm we're not re-locking with ourself as an owner before locking.
+ DCHECK([browserController isBarVisibilityLockedForOwner:self] == NO);
+ [browserController lockBarVisibilityForOwner:self
+ withAnimation:NO
+ delay:NO];
+
+ if (folderController_)
+ [self closeAllBookmarkFolders];
+
+ // Folder controller, like many window controllers, owns itself.
+ folderController_ =
+ [[BookmarkBarFolderController alloc] initWithParentButton:parentButton
+ parentController:nil
+ barController:self];
+ [folderController_ showWindow:self];
+
+ // Only BookmarkBarController has this; the
+ // BookmarkBarFolderController does not.
+ [self watchForExitEvent:YES];
+
+ // No longer need to hold the lock; the folderController_ now owns it.
+ [browserController releaseBarVisibilityForOwner:self
+ withAnimation:NO
+ delay:NO];
+}
+
+- (void)openAll:(const BookmarkNode*)node
+ disposition:(WindowOpenDisposition)disposition {
+ [self closeFolderAndStopTrackingMenus];
+ bookmark_utils::OpenAll([[self view] window],
+ browser_->profile(),
+ browser_,
+ node,
+ disposition);
+}
+
+- (void)addButtonForNode:(const BookmarkNode*)node
+ atIndex:(NSInteger)buttonIndex {
+ int newOffset = 0;
+ if (buttonIndex == -1)
+ buttonIndex = [buttons_ count]; // New button goes at the end.
+ if (buttonIndex <= (NSInteger)[buttons_ count]) {
+ if (buttonIndex) {
+ BookmarkButton* targetButton = [buttons_ objectAtIndex:buttonIndex - 1];
+ NSRect targetFrame = [targetButton frame];
+ newOffset = targetFrame.origin.x + NSWidth(targetFrame) +
+ bookmarks::kBookmarkHorizontalPadding;
+ }
+ BookmarkButton* newButton = [self buttonForNode:node xOffset:&newOffset];
+ CGFloat xOffset =
+ NSWidth([newButton frame]) + bookmarks::kBookmarkHorizontalPadding;
+ NSUInteger buttonCount = [buttons_ count];
+ for (NSUInteger i = buttonIndex; i < buttonCount; ++i) {
+ BookmarkButton* button = [buttons_ objectAtIndex:i];
+ NSPoint buttonOrigin = [button frame].origin;
+ buttonOrigin.x += xOffset;
+ [button setFrameOrigin:buttonOrigin];
+ }
+ ++displayedButtonCount_;
+ [buttons_ insertObject:newButton atIndex:buttonIndex];
+ [buttonView_ addSubview:newButton];
+
+ // See if any buttons need to be pushed off to or brought in from the side.
+ [self reconfigureBookmarkBar];
+ } else {
+ // A button from somewhere else (not the bar) is being moved to the
+ // off-the-side so insure it gets redrawn if its showing.
+ [self reconfigureBookmarkBar];
+ [folderController_ reconfigureMenu];
+ }
+}
+
+// TODO(mrossetti): Duplicate code with BookmarkBarFolderController.
+// http://crbug.com/35966
+- (BOOL)addURLs:(NSArray*)urls withTitles:(NSArray*)titles at:(NSPoint)point {
+ DCHECK([urls count] == [titles count]);
+ BOOL nodesWereAdded = NO;
+ // Figure out where these new bookmarks nodes are to be added.
+ BookmarkButton* button = [self buttonForDroppingOnAtPoint:point];
+ const BookmarkNode* destParent = NULL;
+ int destIndex = 0;
+ if ([button isFolder]) {
+ destParent = [button bookmarkNode];
+ // Drop it at the end.
+ destIndex = [button bookmarkNode]->GetChildCount();
+ } else {
+ // Else we're dropping somewhere on the bar, so find the right spot.
+ destParent = bookmarkModel_->GetBookmarkBarNode();
+ destIndex = [self indexForDragToPoint:point];
+ }
+
+ // Don't add the bookmarks if the destination index shows an error.
+ if (destIndex >= 0) {
+ // Create and add the new bookmark nodes.
+ size_t urlCount = [urls count];
+ for (size_t i = 0; i < urlCount; ++i) {
+ GURL gurl;
+ const char* string = [[urls objectAtIndex:i] UTF8String];
+ if (string)
+ gurl = GURL(string);
+ // We only expect to receive valid URLs.
+ DCHECK(gurl.is_valid());
+ if (gurl.is_valid()) {
+ bookmarkModel_->AddURL(destParent,
+ destIndex++,
+ base::SysNSStringToUTF16(
+ [titles objectAtIndex:i]),
+ gurl);
+ nodesWereAdded = YES;
+ }
+ }
+ }
+ return nodesWereAdded;
+}
+
+// TODO(mrossetti): jrg wants this broken up into smaller functions.
+- (void)moveButtonFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex {
+ if (fromIndex != toIndex) {
+ NSInteger buttonCount = (NSInteger)[buttons_ count];
+ if (toIndex == -1)
+ toIndex = buttonCount;
+ // See if we have a simple move within the bar, which will be the case if
+ // both button indexes are in the visible space.
+ if (fromIndex < buttonCount && toIndex < buttonCount) {
+ BookmarkButton* movedButton = [buttons_ objectAtIndex:fromIndex];
+ NSRect movedFrame = [movedButton frame];
+ NSPoint toOrigin = movedFrame.origin;
+ CGFloat xOffset =
+ NSWidth(movedFrame) + bookmarks::kBookmarkHorizontalPadding;
+ // Hide the button to reduce flickering while drawing the window.
+ [movedButton setHidden:YES];
+ [buttons_ removeObjectAtIndex:fromIndex];
+ if (fromIndex < toIndex) {
+ // Move the button from left to right within the bar.
+ BookmarkButton* targetButton = [buttons_ objectAtIndex:toIndex - 1];
+ NSRect toFrame = [targetButton frame];
+ toOrigin.x = toFrame.origin.x - NSWidth(movedFrame) + NSWidth(toFrame);
+ for (NSInteger i = fromIndex; i < toIndex; ++i) {
+ BookmarkButton* button = [buttons_ objectAtIndex:i];
+ NSRect frame = [button frame];
+ frame.origin.x -= xOffset;
+ [button setFrameOrigin:frame.origin];
+ }
+ } else {
+ // Move the button from right to left within the bar.
+ BookmarkButton* targetButton = [buttons_ objectAtIndex:toIndex];
+ toOrigin = [targetButton frame].origin;
+ for (NSInteger i = fromIndex - 1; i >= toIndex; --i) {
+ BookmarkButton* button = [buttons_ objectAtIndex:i];
+ NSRect buttonFrame = [button frame];
+ buttonFrame.origin.x += xOffset;
+ [button setFrameOrigin:buttonFrame.origin];
+ }
+ }
+ [buttons_ insertObject:movedButton atIndex:toIndex];
+ [movedButton setFrameOrigin:toOrigin];
+ [movedButton setHidden:NO];
+ } else if (fromIndex < buttonCount) {
+ // A button is being removed from the bar and added to off-the-side.
+ // By now the node has already been inserted into the model so the
+ // button to be added is represented by |toIndex|. Things get
+ // complicated because the off-the-side is showing and must be redrawn
+ // while possibly re-laying out the bookmark bar.
+ [self removeButton:fromIndex animate:NO];
+ [self reconfigureBookmarkBar];
+ [folderController_ reconfigureMenu];
+ } else if (toIndex < buttonCount) {
+ // A button is being added to the bar and removed from off-the-side.
+ // By now the node has already been inserted into the model so the
+ // button to be added is represented by |toIndex|.
+ const BookmarkNode* node = bookmarkModel_->GetBookmarkBarNode();
+ const BookmarkNode* movedNode = node->GetChild(toIndex);
+ DCHECK(movedNode);
+ [self addButtonForNode:movedNode atIndex:toIndex];
+ [self reconfigureBookmarkBar];
+ } else {
+ // A button is being moved within the off-the-side.
+ fromIndex -= buttonCount;
+ toIndex -= buttonCount;
+ [folderController_ moveButtonFromIndex:fromIndex toIndex:toIndex];
+ }
+ }
+}
+
+- (void)removeButton:(NSInteger)buttonIndex animate:(BOOL)animate {
+ if (buttonIndex < (NSInteger)[buttons_ count]) {
+ // The button being removed is showing in the bar.
+ BookmarkButton* oldButton = [buttons_ objectAtIndex:buttonIndex];
+ if (oldButton == [folderController_ parentButton]) {
+ // If we are deleting a button whose folder is currently open, close it!
+ [self closeAllBookmarkFolders];
+ }
+ NSPoint poofPoint = [oldButton screenLocationForRemoveAnimation];
+ NSRect oldFrame = [oldButton frame];
+ [oldButton setDelegate:nil];
+ [oldButton removeFromSuperview];
+ if (animate && !ignoreAnimations_ && [self isVisible])
+ NSShowAnimationEffect(NSAnimationEffectDisappearingItemDefault, poofPoint,
+ NSZeroSize, nil, nil, nil);
+ CGFloat xOffset = NSWidth(oldFrame) + bookmarks::kBookmarkHorizontalPadding;
+ [buttons_ removeObjectAtIndex:buttonIndex];
+ NSUInteger buttonCount = [buttons_ count];
+ for (NSUInteger i = buttonIndex; i < buttonCount; ++i) {
+ BookmarkButton* button = [buttons_ objectAtIndex:i];
+ NSRect buttonFrame = [button frame];
+ buttonFrame.origin.x -= xOffset;
+ [button setFrame:buttonFrame];
+ // If this button is showing its menu then we need to move the menu, too.
+ if (button == [folderController_ parentButton])
+ [folderController_ offsetFolderMenuWindow:NSMakeSize(xOffset, 0.0)];
+ }
+ --displayedButtonCount_;
+ [self reconfigureBookmarkBar];
+ } else if (folderController_ &&
+ [folderController_ parentButton] == offTheSideButton_) {
+ // The button being removed is in the OTS (off-the-side) and the OTS
+ // menu is showing so we need to remove the button.
+ NSInteger index = buttonIndex - displayedButtonCount_;
+ [folderController_ removeButton:index animate:YES];
+ }
+}
+
+- (id<BookmarkButtonControllerProtocol>)controllerForNode:
+ (const BookmarkNode*)node {
+ // See if it's in the bar, then if it is in the hierarchy of visible
+ // folder menus.
+ if (bookmarkModel_->GetBookmarkBarNode() == node)
+ return self;
+ return [folderController_ controllerForNode:node];
+}
+
+#pragma mark BookmarkButtonControllerProtocol
+
+// NOT an override of a standard Cocoa call made to NSViewControllers.
+- (void)hookForEvent:(NSEvent*)theEvent {
+ if ([self isEventAnExitEvent:theEvent])
+ [self closeFolderAndStopTrackingMenus];
+}
+
+#pragma mark TestingAPI Only
+
+- (NSMenu*)buttonContextMenu {
+ return buttonContextMenu_;
+}
+
+// Intentionally ignores ownership issues; used for testing and we try
+// to minimize touching the object passed in (likely a mock).
+- (void)setButtonContextMenu:(id)menu {
+ buttonContextMenu_ = menu;
+}
+
+- (void)setIgnoreAnimations:(BOOL)ignore {
+ ignoreAnimations_ = ignore;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller_unittest.mm
new file mode 100644
index 0000000..80f6bc7
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller_unittest.mm
@@ -0,0 +1,2169 @@
+// 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 "app/theme_provider.h"
+#include "base/basictypes.h"
+#include "base/scoped_nsobject.h"
+#include "base/string16.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_unittest_helper.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/test_event_utils.h"
+#import "chrome/browser/ui/cocoa/view_resizer_pong.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/model_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+
+// Just like a BookmarkBarController but openURL: is stubbed out.
+@interface BookmarkBarControllerNoOpen : BookmarkBarController {
+ @public
+ std::vector<GURL> urls_;
+ std::vector<WindowOpenDisposition> dispositions_;
+}
+@end
+
+@implementation BookmarkBarControllerNoOpen
+- (void)openURL:(GURL)url disposition:(WindowOpenDisposition)disposition {
+ urls_.push_back(url);
+ dispositions_.push_back(disposition);
+}
+- (void)clear {
+ urls_.clear();
+ dispositions_.clear();
+}
+@end
+
+
+// NSCell that is pre-provided with a desired size that becomes the
+// return value for -(NSSize)cellSize:.
+@interface CellWithDesiredSize : NSCell {
+ @private
+ NSSize cellSize_;
+}
+@property (nonatomic, readonly) NSSize cellSize;
+@end
+
+@implementation CellWithDesiredSize
+
+@synthesize cellSize = cellSize_;
+
+- (id)initTextCell:(NSString*)string desiredSize:(NSSize)size {
+ if ((self = [super initTextCell:string])) {
+ cellSize_ = size;
+ }
+ return self;
+}
+
+@end
+
+// Remember the number of times we've gotten a frameDidChange notification.
+@interface BookmarkBarControllerTogglePong : BookmarkBarControllerNoOpen {
+ @private
+ int toggles_;
+}
+@property (nonatomic, readonly) int toggles;
+@end
+
+@implementation BookmarkBarControllerTogglePong
+
+@synthesize toggles = toggles_;
+
+- (void)frameDidChange {
+ toggles_++;
+}
+
+@end
+
+// Remembers if a notification callback was called.
+@interface BookmarkBarControllerNotificationPong : BookmarkBarControllerNoOpen {
+ BOOL windowWillCloseReceived_;
+ BOOL windowDidResignKeyReceived_;
+}
+@property (nonatomic, readonly) BOOL windowWillCloseReceived;
+@property (nonatomic, readonly) BOOL windowDidResignKeyReceived;
+@end
+
+@implementation BookmarkBarControllerNotificationPong
+@synthesize windowWillCloseReceived = windowWillCloseReceived_;
+@synthesize windowDidResignKeyReceived = windowDidResignKeyReceived_;
+
+// Override NSNotificationCenter callback.
+- (void)parentWindowWillClose:(NSNotification*)notification {
+ windowWillCloseReceived_ = YES;
+}
+
+// NSNotificationCenter callback.
+- (void)parentWindowDidResignKey:(NSNotification*)notification {
+ windowDidResignKeyReceived_ = YES;
+}
+@end
+
+// Remembers if and what kind of openAll was performed.
+@interface BookmarkBarControllerOpenAllPong : BookmarkBarControllerNoOpen {
+ WindowOpenDisposition dispositionDetected_;
+}
+@property (nonatomic) WindowOpenDisposition dispositionDetected;
+@end
+
+@implementation BookmarkBarControllerOpenAllPong
+@synthesize dispositionDetected = dispositionDetected_;
+
+// Intercede for the openAll:disposition: method.
+- (void)openAll:(const BookmarkNode*)node
+ disposition:(WindowOpenDisposition)disposition {
+ [self setDispositionDetected:disposition];
+}
+
+@end
+
+// Just like a BookmarkBarController but intercedes when providing
+// pasteboard drag data.
+@interface BookmarkBarControllerDragData : BookmarkBarController {
+ const BookmarkNode* dragDataNode_; // Weak
+}
+- (void)setDragDataNode:(const BookmarkNode*)node;
+@end
+
+@implementation BookmarkBarControllerDragData
+
+- (id)initWithBrowser:(Browser*)browser
+ initialWidth:(CGFloat)initialWidth
+ delegate:(id<BookmarkBarControllerDelegate>)delegate
+ resizeDelegate:(id<ViewResizer>)resizeDelegate {
+ if ((self = [super initWithBrowser:browser
+ initialWidth:initialWidth
+ delegate:delegate
+ resizeDelegate:resizeDelegate])) {
+ dragDataNode_ = NULL;
+ }
+ return self;
+}
+
+- (void)setDragDataNode:(const BookmarkNode*)node {
+ dragDataNode_ = node;
+}
+
+- (std::vector<const BookmarkNode*>)retrieveBookmarkNodeData {
+ std::vector<const BookmarkNode*> dragDataNodes;
+ if(dragDataNode_) {
+ dragDataNodes.push_back(dragDataNode_);
+ }
+ return dragDataNodes;
+}
+
+@end
+
+
+class FakeTheme : public ThemeProvider {
+ public:
+ FakeTheme(NSColor* color) : color_(color) { }
+ scoped_nsobject<NSColor> color_;
+
+ virtual void Init(Profile* profile) { }
+ virtual SkBitmap* GetBitmapNamed(int id) const { return nil; }
+ virtual SkColor GetColor(int id) const { return SkColor(); }
+ virtual bool GetDisplayProperty(int id, int* result) const { return false; }
+ virtual bool ShouldUseNativeFrame() const { return false; }
+ virtual bool HasCustomImage(int id) const { return false; }
+ virtual RefCountedMemory* GetRawData(int id) const { return NULL; }
+ virtual NSImage* GetNSImageNamed(int id, bool allow_default) const {
+ return nil;
+ }
+ virtual NSColor* GetNSImageColorNamed(int id, bool allow_default) const {
+ return nil;
+ }
+ virtual NSColor* GetNSColor(int id, bool allow_default) const {
+ return color_.get();
+ }
+ virtual NSColor* GetNSColorTint(int id, bool allow_default) const {
+ return nil;
+ }
+ virtual NSGradient* GetNSGradient(int id) const {
+ return nil;
+ }
+};
+
+
+@interface FakeDragInfo : NSObject {
+ @public
+ NSPoint dropLocation_;
+ NSDragOperation sourceMask_;
+}
+@property (nonatomic, assign) NSPoint dropLocation;
+- (void)setDraggingSourceOperationMask:(NSDragOperation)mask;
+@end
+
+@implementation FakeDragInfo
+
+@synthesize dropLocation = dropLocation_;
+
+- (id)init {
+ if ((self = [super init])) {
+ dropLocation_ = NSZeroPoint;
+ sourceMask_ = NSDragOperationMove;
+ }
+ return self;
+}
+
+// NSDraggingInfo protocol functions.
+
+- (id)draggingPasteboard {
+ return self;
+}
+
+- (id)draggingSource {
+ return self;
+}
+
+- (NSDragOperation)draggingSourceOperationMask {
+ return sourceMask_;
+}
+
+- (NSPoint)draggingLocation {
+ return dropLocation_;
+}
+
+// Other functions.
+
+- (void)setDraggingSourceOperationMask:(NSDragOperation)mask {
+ sourceMask_ = mask;
+}
+
+@end
+
+
+namespace {
+
+class BookmarkBarControllerTestBase : public CocoaTest {
+ public:
+ BrowserTestHelper helper_;
+ scoped_nsobject<NSView> parent_view_;
+ scoped_nsobject<ViewResizerPong> resizeDelegate_;
+
+ BookmarkBarControllerTestBase() {
+ resizeDelegate_.reset([[ViewResizerPong alloc] init]);
+ NSRect parent_frame = NSMakeRect(0, 0, 800, 50);
+ parent_view_.reset([[NSView alloc] initWithFrame:parent_frame]);
+ [parent_view_ setHidden:YES];
+ }
+
+ void InstallAndToggleBar(BookmarkBarController* bar) {
+ // Force loading of the nib.
+ [bar view];
+ // Awkwardness to look like we've been installed.
+ for (NSView* subView in [parent_view_ subviews])
+ [subView removeFromSuperview];
+ [parent_view_ addSubview:[bar view]];
+ NSRect frame = [[[bar view] superview] frame];
+ frame.origin.y = 100;
+ [[[bar view] superview] setFrame:frame];
+
+ // Make sure it's on in a window so viewDidMoveToWindow is called
+ NSView* contentView = [test_window() contentView];
+ if (![parent_view_ isDescendantOf:contentView])
+ [contentView addSubview:parent_view_];
+
+ // Make sure it's open so certain things aren't no-ops.
+ [bar updateAndShowNormalBar:YES
+ showDetachedBar:NO
+ withAnimation:NO];
+ }
+};
+
+class BookmarkBarControllerTest : public BookmarkBarControllerTestBase {
+ public:
+ scoped_nsobject<BookmarkMenu> menu_;
+ scoped_nsobject<NSMenuItem> menu_item_;
+ scoped_nsobject<NSButtonCell> cell_;
+ scoped_nsobject<BookmarkBarControllerNoOpen> bar_;
+
+ BookmarkBarControllerTest() {
+ bar_.reset(
+ [[BookmarkBarControllerNoOpen alloc]
+ initWithBrowser:helper_.browser()
+ initialWidth:NSWidth([parent_view_ frame])
+ delegate:nil
+ resizeDelegate:resizeDelegate_.get()]);
+
+ InstallAndToggleBar(bar_.get());
+
+ // Create a menu/item to act like a sender
+ menu_.reset([[BookmarkMenu alloc] initWithTitle:@"I_dont_care"]);
+ menu_item_.reset([[NSMenuItem alloc]
+ initWithTitle:@"still_dont_care"
+ action:NULL
+ keyEquivalent:@""]);
+ cell_.reset([[NSButtonCell alloc] init]);
+ [menu_item_ setMenu:menu_.get()];
+ [menu_ setDelegate:cell_.get()];
+ }
+
+ // Return a menu item that points to the given URL.
+ NSMenuItem* ItemForBookmarkBarMenu(GURL& gurl) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ const BookmarkNode* node = model->AddURL(parent, parent->GetChildCount(),
+ ASCIIToUTF16("A title"), gurl);
+ [menu_ setRepresentedObject:[NSNumber numberWithLongLong:node->id()]];
+ return menu_item_;
+ }
+
+ // Does NOT take ownership of node.
+ NSMenuItem* ItemForBookmarkBarMenu(const BookmarkNode* node) {
+ [menu_ setRepresentedObject:[NSNumber numberWithLongLong:node->id()]];
+ return menu_item_;
+ }
+
+ BookmarkBarControllerNoOpen* noOpenBar() {
+ return (BookmarkBarControllerNoOpen*)bar_.get();
+ }
+};
+
+TEST_F(BookmarkBarControllerTest, ShowWhenShowBookmarkBarTrue) {
+ [bar_ updateAndShowNormalBar:YES
+ showDetachedBar:NO
+ withAnimation:NO];
+ EXPECT_TRUE([bar_ isInState:bookmarks::kShowingState]);
+ EXPECT_FALSE([bar_ isInState:bookmarks::kDetachedState]);
+ EXPECT_TRUE([bar_ isVisible]);
+ EXPECT_FALSE([bar_ isAnimationRunning]);
+ EXPECT_FALSE([[bar_ view] isHidden]);
+ EXPECT_GT([resizeDelegate_ height], 0);
+ EXPECT_GT([[bar_ view] frame].size.height, 0);
+}
+
+TEST_F(BookmarkBarControllerTest, HideWhenShowBookmarkBarFalse) {
+ [bar_ updateAndShowNormalBar:NO
+ showDetachedBar:NO
+ withAnimation:NO];
+ EXPECT_FALSE([bar_ isInState:bookmarks::kShowingState]);
+ EXPECT_FALSE([bar_ isInState:bookmarks::kDetachedState]);
+ EXPECT_FALSE([bar_ isVisible]);
+ EXPECT_FALSE([bar_ isAnimationRunning]);
+ EXPECT_TRUE([[bar_ view] isHidden]);
+ EXPECT_EQ(0, [resizeDelegate_ height]);
+ EXPECT_EQ(0, [[bar_ view] frame].size.height);
+}
+
+TEST_F(BookmarkBarControllerTest, HideWhenShowBookmarkBarTrueButDisabled) {
+ [bar_ setBookmarkBarEnabled:NO];
+ [bar_ updateAndShowNormalBar:YES
+ showDetachedBar:NO
+ withAnimation:NO];
+ EXPECT_TRUE([bar_ isInState:bookmarks::kShowingState]);
+ EXPECT_FALSE([bar_ isInState:bookmarks::kDetachedState]);
+ EXPECT_FALSE([bar_ isVisible]);
+ EXPECT_FALSE([bar_ isAnimationRunning]);
+ EXPECT_TRUE([[bar_ view] isHidden]);
+ EXPECT_EQ(0, [resizeDelegate_ height]);
+ EXPECT_EQ(0, [[bar_ view] frame].size.height);
+}
+
+TEST_F(BookmarkBarControllerTest, ShowOnNewTabPage) {
+ [bar_ updateAndShowNormalBar:NO
+ showDetachedBar:YES
+ withAnimation:NO];
+ EXPECT_FALSE([bar_ isInState:bookmarks::kShowingState]);
+ EXPECT_TRUE([bar_ isInState:bookmarks::kDetachedState]);
+ EXPECT_TRUE([bar_ isVisible]);
+ EXPECT_FALSE([bar_ isAnimationRunning]);
+ EXPECT_FALSE([[bar_ view] isHidden]);
+ EXPECT_GT([resizeDelegate_ height], 0);
+ EXPECT_GT([[bar_ view] frame].size.height, 0);
+
+ // Make sure no buttons fall off the bar, either now or when resized
+ // bigger or smaller.
+ CGFloat sizes[] = { 300.0, -100.0, 200.0, -420.0 };
+ CGFloat previousX = 0.0;
+ for (unsigned x = 0; x < arraysize(sizes); x++) {
+ // Confirm the buttons moved from the last check (which may be
+ // init but that's fine).
+ CGFloat newX = [[bar_ offTheSideButton] frame].origin.x;
+ EXPECT_NE(previousX, newX);
+ previousX = newX;
+
+ // Confirm the buttons have a reasonable bounds. Recall that |-frame|
+ // returns rectangles in the superview's coordinates.
+ NSRect buttonViewFrame =
+ [[bar_ buttonView] convertRect:[[bar_ buttonView] frame]
+ fromView:[[bar_ buttonView] superview]];
+ EXPECT_EQ([bar_ buttonView], [[bar_ offTheSideButton] superview]);
+ EXPECT_TRUE(NSContainsRect(buttonViewFrame,
+ [[bar_ offTheSideButton] frame]));
+ EXPECT_EQ([bar_ buttonView], [[bar_ otherBookmarksButton] superview]);
+ EXPECT_TRUE(NSContainsRect(buttonViewFrame,
+ [[bar_ otherBookmarksButton] frame]));
+
+ // Now move them implicitly.
+ // We confirm FrameChangeNotification works in the next unit test;
+ // we simply assume it works here to resize or reposition the
+ // buttons above.
+ NSRect frame = [[bar_ view] frame];
+ frame.size.width += sizes[x];
+ [[bar_ view] setFrame:frame];
+ }
+}
+
+// Test whether |-updateAndShowNormalBar:...| sets states as we expect. Make
+// sure things don't crash.
+TEST_F(BookmarkBarControllerTest, StateChanges) {
+ // First, go in one-at-a-time cycle.
+ [bar_ updateAndShowNormalBar:NO
+ showDetachedBar:NO
+ withAnimation:NO];
+ EXPECT_EQ(bookmarks::kHiddenState, [bar_ visualState]);
+ EXPECT_FALSE([bar_ isVisible]);
+ EXPECT_FALSE([bar_ isAnimationRunning]);
+ [bar_ updateAndShowNormalBar:YES
+ showDetachedBar:NO
+ withAnimation:NO];
+ EXPECT_EQ(bookmarks::kShowingState, [bar_ visualState]);
+ EXPECT_TRUE([bar_ isVisible]);
+ EXPECT_FALSE([bar_ isAnimationRunning]);
+ [bar_ updateAndShowNormalBar:YES
+ showDetachedBar:YES
+ withAnimation:NO];
+ EXPECT_EQ(bookmarks::kShowingState, [bar_ visualState]);
+ EXPECT_TRUE([bar_ isVisible]);
+ EXPECT_FALSE([bar_ isAnimationRunning]);
+ [bar_ updateAndShowNormalBar:NO
+ showDetachedBar:YES
+ withAnimation:NO];
+ EXPECT_EQ(bookmarks::kDetachedState, [bar_ visualState]);
+ EXPECT_TRUE([bar_ isVisible]);
+ EXPECT_FALSE([bar_ isAnimationRunning]);
+
+ // Now try some "jumps".
+ for (int i = 0; i < 2; i++) {
+ [bar_ updateAndShowNormalBar:NO
+ showDetachedBar:NO
+ withAnimation:NO];
+ EXPECT_EQ(bookmarks::kHiddenState, [bar_ visualState]);
+ EXPECT_FALSE([bar_ isVisible]);
+ EXPECT_FALSE([bar_ isAnimationRunning]);
+ [bar_ updateAndShowNormalBar:YES
+ showDetachedBar:YES
+ withAnimation:NO];
+ EXPECT_EQ(bookmarks::kShowingState, [bar_ visualState]);
+ EXPECT_TRUE([bar_ isVisible]);
+ EXPECT_FALSE([bar_ isAnimationRunning]);
+ }
+
+ // Now try some "jumps".
+ for (int i = 0; i < 2; i++) {
+ [bar_ updateAndShowNormalBar:YES
+ showDetachedBar:NO
+ withAnimation:NO];
+ EXPECT_EQ(bookmarks::kShowingState, [bar_ visualState]);
+ EXPECT_TRUE([bar_ isVisible]);
+ EXPECT_FALSE([bar_ isAnimationRunning]);
+ [bar_ updateAndShowNormalBar:NO
+ showDetachedBar:YES
+ withAnimation:NO];
+ EXPECT_EQ(bookmarks::kDetachedState, [bar_ visualState]);
+ EXPECT_TRUE([bar_ isVisible]);
+ EXPECT_FALSE([bar_ isAnimationRunning]);
+ }
+}
+
+// Make sure we're watching for frame change notifications.
+TEST_F(BookmarkBarControllerTest, FrameChangeNotification) {
+ scoped_nsobject<BookmarkBarControllerTogglePong> bar;
+ bar.reset(
+ [[BookmarkBarControllerTogglePong alloc]
+ initWithBrowser:helper_.browser()
+ initialWidth:100 // arbitrary
+ delegate:nil
+ resizeDelegate:resizeDelegate_.get()]);
+ InstallAndToggleBar(bar.get());
+
+ // Send a frame did change notification for the pong's view.
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName:NSViewFrameDidChangeNotification
+ object:[bar view]];
+
+ EXPECT_GT([bar toggles], 0);
+}
+
+// Confirm our "no items" container goes away when we add the 1st
+// bookmark, and comes back when we delete the bookmark.
+TEST_F(BookmarkBarControllerTest, NoItemContainerGoesAway) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ const BookmarkNode* bar = model->GetBookmarkBarNode();
+
+ [bar_ loaded:model];
+ BookmarkBarView* view = [bar_ buttonView];
+ DCHECK(view);
+ NSView* noItemContainer = [view noItemContainer];
+ DCHECK(noItemContainer);
+
+ EXPECT_FALSE([noItemContainer isHidden]);
+ const BookmarkNode* node = model->AddURL(bar, bar->GetChildCount(),
+ ASCIIToUTF16("title"),
+ GURL("http://www.google.com"));
+ EXPECT_TRUE([noItemContainer isHidden]);
+ model->Remove(bar, bar->IndexOfChild(node));
+ EXPECT_FALSE([noItemContainer isHidden]);
+
+ // Now try it using a bookmark from the Other Bookmarks.
+ const BookmarkNode* otherBookmarks = model->other_node();
+ node = model->AddURL(otherBookmarks, otherBookmarks->GetChildCount(),
+ ASCIIToUTF16("TheOther"),
+ GURL("http://www.other.com"));
+ EXPECT_FALSE([noItemContainer isHidden]);
+ // Move it from Other Bookmarks to the bar.
+ model->Move(node, bar, 0);
+ EXPECT_TRUE([noItemContainer isHidden]);
+ // Move it back to Other Bookmarks from the bar.
+ model->Move(node, otherBookmarks, 0);
+ EXPECT_FALSE([noItemContainer isHidden]);
+}
+
+// Confirm off the side button only enabled when reasonable.
+TEST_F(BookmarkBarControllerTest, OffTheSideButtonHidden) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ [bar_ setIgnoreAnimations:YES];
+
+ [bar_ loaded:model];
+ EXPECT_TRUE([bar_ offTheSideButtonIsHidden]);
+
+ for (int i = 0; i < 2; i++) {
+ model->SetURLStarred(GURL("http://www.foo.com"), ASCIIToUTF16("small"),
+ true);
+ EXPECT_TRUE([bar_ offTheSideButtonIsHidden]);
+ }
+
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ for (int i = 0; i < 20; i++) {
+ model->AddURL(parent, parent->GetChildCount(),
+ ASCIIToUTF16("super duper wide title"),
+ GURL("http://superfriends.hall-of-justice.edu"));
+ }
+ EXPECT_FALSE([bar_ offTheSideButtonIsHidden]);
+
+ // Open the "off the side" and start deleting nodes. Make sure
+ // deletion of the last node in "off the side" causes the folder to
+ // close.
+ EXPECT_FALSE([bar_ offTheSideButtonIsHidden]);
+ NSButton* offTheSideButton = [bar_ offTheSideButton];
+ // Open "off the side" menu.
+ [bar_ openOffTheSideFolderFromButton:offTheSideButton];
+ BookmarkBarFolderController* bbfc = [bar_ folderController];
+ EXPECT_TRUE(bbfc);
+ [bbfc setIgnoreAnimations:YES];
+ while (parent->GetChildCount()) {
+ // We've completed the job so we're done.
+ if ([bar_ offTheSideButtonIsHidden])
+ break;
+ // Delete the last button.
+ model->Remove(parent, parent->GetChildCount()-1);
+ // If last one make sure the menu is closed and the button is hidden.
+ // Else make sure menu stays open.
+ if ([bar_ offTheSideButtonIsHidden]) {
+ EXPECT_FALSE([bar_ folderController]);
+ } else {
+ EXPECT_TRUE([bar_ folderController]);
+ }
+ }
+}
+
+// http://crbug.com/46175 is a crash when deleting bookmarks from the
+// off-the-side menu while it is open. This test tries to bang hard
+// in this area to reproduce the crash.
+TEST_F(BookmarkBarControllerTest, DeleteFromOffTheSideWhileItIsOpen) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ [bar_ setIgnoreAnimations:YES];
+ [bar_ loaded:model];
+
+ // Add a lot of bookmarks (per the bug).
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ for (int i = 0; i < 100; i++) {
+ std::ostringstream title;
+ title << "super duper wide title " << i;
+ model->AddURL(parent, parent->GetChildCount(), ASCIIToUTF16(title.str()),
+ GURL("http://superfriends.hall-of-justice.edu"));
+ }
+ EXPECT_FALSE([bar_ offTheSideButtonIsHidden]);
+
+ // Open "off the side" menu.
+ NSButton* offTheSideButton = [bar_ offTheSideButton];
+ [bar_ openOffTheSideFolderFromButton:offTheSideButton];
+ BookmarkBarFolderController* bbfc = [bar_ folderController];
+ EXPECT_TRUE(bbfc);
+ [bbfc setIgnoreAnimations:YES];
+
+ // Start deleting items; try and delete randomish ones in case it
+ // makes a difference.
+ int indices[] = { 2, 4, 5, 1, 7, 9, 2, 0, 10, 9 };
+ while (parent->GetChildCount()) {
+ for (unsigned int i = 0; i < arraysize(indices); i++) {
+ if (indices[i] < parent->GetChildCount()) {
+ // First we mouse-enter the button to make things harder.
+ NSArray* buttons = [bbfc buttons];
+ for (BookmarkButton* button in buttons) {
+ if ([button bookmarkNode] == parent->GetChild(indices[i])) {
+ [bbfc mouseEnteredButton:button event:nil];
+ break;
+ }
+ }
+ // Then we remove the node. This triggers the button to get
+ // deleted.
+ model->Remove(parent, indices[i]);
+ // Force visual update which is otherwise delayed.
+ [[bbfc window] displayIfNeeded];
+ }
+ }
+ }
+}
+
+// Test whether |-dragShouldLockBarVisibility| returns NO iff the bar is
+// detached.
+TEST_F(BookmarkBarControllerTest, TestDragShouldLockBarVisibility) {
+ [bar_ updateAndShowNormalBar:NO
+ showDetachedBar:NO
+ withAnimation:NO];
+ EXPECT_TRUE([bar_ dragShouldLockBarVisibility]);
+
+ [bar_ updateAndShowNormalBar:YES
+ showDetachedBar:NO
+ withAnimation:NO];
+ EXPECT_TRUE([bar_ dragShouldLockBarVisibility]);
+
+ [bar_ updateAndShowNormalBar:YES
+ showDetachedBar:YES
+ withAnimation:NO];
+ EXPECT_TRUE([bar_ dragShouldLockBarVisibility]);
+
+ [bar_ updateAndShowNormalBar:NO
+ showDetachedBar:YES
+ withAnimation:NO];
+ EXPECT_FALSE([bar_ dragShouldLockBarVisibility]);
+}
+
+TEST_F(BookmarkBarControllerTest, TagMap) {
+ int64 ids[] = { 1, 3, 4, 40, 400, 4000, 800000000, 2, 123456789 };
+ std::vector<int32> tags;
+
+ // Generate some tags
+ for (unsigned int i = 0; i < arraysize(ids); i++) {
+ tags.push_back([bar_ menuTagFromNodeId:ids[i]]);
+ }
+
+ // Confirm reverse mapping.
+ for (unsigned int i = 0; i < arraysize(ids); i++) {
+ EXPECT_EQ(ids[i], [bar_ nodeIdFromMenuTag:tags[i]]);
+ }
+
+ // Confirm uniqueness.
+ std::sort(tags.begin(), tags.end());
+ for (unsigned int i=0; i<(tags.size()-1); i++) {
+ EXPECT_NE(tags[i], tags[i+1]);
+ }
+}
+
+TEST_F(BookmarkBarControllerTest, MenuForFolderNode) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+
+ // First make sure something (e.g. "(empty)" string) is always present.
+ NSMenu* menu = [bar_ menuForFolderNode:model->GetBookmarkBarNode()];
+ EXPECT_GT([menu numberOfItems], 0);
+
+ // Test two bookmarks.
+ GURL gurl("http://www.foo.com");
+ model->SetURLStarred(gurl, ASCIIToUTF16("small"), true);
+ model->SetURLStarred(GURL("http://www.cnn.com"), ASCIIToUTF16("bigger title"),
+ true);
+ menu = [bar_ menuForFolderNode:model->GetBookmarkBarNode()];
+ EXPECT_EQ([menu numberOfItems], 2);
+ NSMenuItem *item = [menu itemWithTitle:@"bigger title"];
+ EXPECT_TRUE(item);
+ item = [menu itemWithTitle:@"small"];
+ EXPECT_TRUE(item);
+ if (item) {
+ int64 tag = [bar_ nodeIdFromMenuTag:[item tag]];
+ const BookmarkNode* node = model->GetNodeByID(tag);
+ EXPECT_TRUE(node);
+ EXPECT_EQ(gurl, node->GetURL());
+ }
+
+ // Test with an actual folder as well
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ const BookmarkNode* folder = model->AddGroup(parent,
+ parent->GetChildCount(),
+ ASCIIToUTF16("group"));
+ model->AddURL(folder, folder->GetChildCount(),
+ ASCIIToUTF16("f1"), GURL("http://framma-lamma.com"));
+ model->AddURL(folder, folder->GetChildCount(),
+ ASCIIToUTF16("f2"), GURL("http://framma-lamma-ding-dong.com"));
+ menu = [bar_ menuForFolderNode:model->GetBookmarkBarNode()];
+ EXPECT_EQ([menu numberOfItems], 3);
+
+ item = [menu itemWithTitle:@"group"];
+ EXPECT_TRUE(item);
+ EXPECT_TRUE([item hasSubmenu]);
+ NSMenu *submenu = [item submenu];
+ EXPECT_TRUE(submenu);
+ EXPECT_EQ(2, [submenu numberOfItems]);
+ EXPECT_TRUE([submenu itemWithTitle:@"f1"]);
+ EXPECT_TRUE([submenu itemWithTitle:@"f2"]);
+}
+
+// Confirm openBookmark: forwards the request to the controller's delegate
+TEST_F(BookmarkBarControllerTest, OpenBookmark) {
+ GURL gurl("http://walla.walla.ding.dong.com");
+ scoped_ptr<BookmarkNode> node(new BookmarkNode(gurl));
+
+ scoped_nsobject<BookmarkButtonCell> cell([[BookmarkButtonCell alloc] init]);
+ [cell setBookmarkNode:node.get()];
+ scoped_nsobject<BookmarkButton> button([[BookmarkButton alloc] init]);
+ [button setCell:cell.get()];
+ [cell setRepresentedObject:[NSValue valueWithPointer:node.get()]];
+
+ [bar_ openBookmark:button];
+ EXPECT_EQ(noOpenBar()->urls_[0], node->GetURL());
+ EXPECT_EQ(noOpenBar()->dispositions_[0], CURRENT_TAB);
+}
+
+// Confirm opening of bookmarks works from the menus (different
+// dispositions than clicking on the button).
+TEST_F(BookmarkBarControllerTest, OpenBookmarkFromMenus) {
+ const char* urls[] = { "http://walla.walla.ding.dong.com",
+ "http://i_dont_know.com",
+ "http://cee.enn.enn.dot.com" };
+ SEL selectors[] = { @selector(openBookmarkInNewForegroundTab:),
+ @selector(openBookmarkInNewWindow:),
+ @selector(openBookmarkInIncognitoWindow:) };
+ WindowOpenDisposition dispositions[] = { NEW_FOREGROUND_TAB,
+ NEW_WINDOW,
+ OFF_THE_RECORD };
+ for (unsigned int i = 0; i < arraysize(dispositions); i++) {
+ GURL gurl(urls[i]);
+ [bar_ performSelector:selectors[i]
+ withObject:ItemForBookmarkBarMenu(gurl)];
+ EXPECT_EQ(noOpenBar()->urls_[0], gurl);
+ EXPECT_EQ(noOpenBar()->dispositions_[0], dispositions[i]);
+ [bar_ clear];
+ }
+}
+
+TEST_F(BookmarkBarControllerTest, TestAddRemoveAndClear) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ NSView* buttonView = [bar_ buttonView];
+ EXPECT_EQ(0U, [[bar_ buttons] count]);
+ unsigned int initial_subview_count = [[buttonView subviews] count];
+
+ // Make sure a redundant call doesn't choke
+ [bar_ clearBookmarkBar];
+ EXPECT_EQ(0U, [[bar_ buttons] count]);
+ EXPECT_EQ(initial_subview_count, [[buttonView subviews] count]);
+
+ GURL gurl1("http://superfriends.hall-of-justice.edu");
+ // Short titles increase the chances of this test succeeding if the view is
+ // narrow.
+ // TODO(viettrungluu): make the test independent of window/view size, font
+ // metrics, button size and spacing, and everything else.
+ string16 title1(ASCIIToUTF16("x"));
+ model->SetURLStarred(gurl1, title1, true);
+ EXPECT_EQ(1U, [[bar_ buttons] count]);
+ EXPECT_EQ(1+initial_subview_count, [[buttonView subviews] count]);
+
+ GURL gurl2("http://legion-of-doom.gov");
+ string16 title2(ASCIIToUTF16("y"));
+ model->SetURLStarred(gurl2, title2, true);
+ EXPECT_EQ(2U, [[bar_ buttons] count]);
+ EXPECT_EQ(2+initial_subview_count, [[buttonView subviews] count]);
+
+ for (int i = 0; i < 3; i++) {
+ // is_starred=false --> remove the bookmark
+ model->SetURLStarred(gurl2, title2, false);
+ EXPECT_EQ(1U, [[bar_ buttons] count]);
+ EXPECT_EQ(1+initial_subview_count, [[buttonView subviews] count]);
+
+ // and bring it back
+ model->SetURLStarred(gurl2, title2, true);
+ EXPECT_EQ(2U, [[bar_ buttons] count]);
+ EXPECT_EQ(2+initial_subview_count, [[buttonView subviews] count]);
+ }
+
+ [bar_ clearBookmarkBar];
+ EXPECT_EQ(0U, [[bar_ buttons] count]);
+ EXPECT_EQ(initial_subview_count, [[buttonView subviews] count]);
+
+ // Explicit test of loaded: since this is a convenient spot
+ [bar_ loaded:model];
+ EXPECT_EQ(2U, [[bar_ buttons] count]);
+ EXPECT_EQ(2+initial_subview_count, [[buttonView subviews] count]);
+}
+
+// Make sure we don't create too many buttons; we only really need
+// ones that will be visible.
+TEST_F(BookmarkBarControllerTest, TestButtonLimits) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ EXPECT_EQ(0U, [[bar_ buttons] count]);
+ // Add one; make sure we see it.
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ model->AddURL(parent, parent->GetChildCount(),
+ ASCIIToUTF16("title"), GURL("http://www.google.com"));
+ EXPECT_EQ(1U, [[bar_ buttons] count]);
+
+ // Add 30 which we expect to be 'too many'. Make sure we don't see
+ // 30 buttons.
+ model->Remove(parent, 0);
+ EXPECT_EQ(0U, [[bar_ buttons] count]);
+ for (int i=0; i<30; i++) {
+ model->AddURL(parent, parent->GetChildCount(),
+ ASCIIToUTF16("title"), GURL("http://www.google.com"));
+ }
+ int count = [[bar_ buttons] count];
+ EXPECT_LT(count, 30L);
+
+ // Add 10 more (to the front of the list so the on-screen buttons
+ // would change) and make sure the count stays the same.
+ for (int i=0; i<10; i++) {
+ model->AddURL(parent, 0, /* index is 0, so front, not end */
+ ASCIIToUTF16("title"), GURL("http://www.google.com"));
+ }
+
+ // Finally, grow the view and make sure the button count goes up.
+ NSRect frame = [[bar_ view] frame];
+ frame.size.width += 600;
+ [[bar_ view] setFrame:frame];
+ int finalcount = [[bar_ buttons] count];
+ EXPECT_GT(finalcount, count);
+}
+
+// Make sure that each button we add marches to the right and does not
+// overlap with the previous one.
+TEST_F(BookmarkBarControllerTest, TestButtonMarch) {
+ scoped_nsobject<NSMutableArray> cells([[NSMutableArray alloc] init]);
+
+ CGFloat widths[] = { 10, 10, 100, 10, 500, 500, 80000, 60000, 1, 345 };
+ for (unsigned int i = 0; i < arraysize(widths); i++) {
+ NSCell* cell = [[CellWithDesiredSize alloc]
+ initTextCell:@"foo"
+ desiredSize:NSMakeSize(widths[i], 30)];
+ [cells addObject:cell];
+ [cell release];
+ }
+
+ int x_offset = 0;
+ CGFloat x_end = x_offset; // end of the previous button
+ for (unsigned int i = 0; i < arraysize(widths); i++) {
+ NSRect r = [bar_ frameForBookmarkButtonFromCell:[cells objectAtIndex:i]
+ xOffset:&x_offset];
+ EXPECT_GE(r.origin.x, x_end);
+ x_end = NSMaxX(r);
+ }
+}
+
+TEST_F(BookmarkBarControllerTest, CheckForGrowth) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ GURL gurl1("http://www.google.com");
+ string16 title1(ASCIIToUTF16("x"));
+ model->SetURLStarred(gurl1, title1, true);
+
+ GURL gurl2("http://www.google.com/blah");
+ string16 title2(ASCIIToUTF16("y"));
+ model->SetURLStarred(gurl2, title2, true);
+
+ EXPECT_EQ(2U, [[bar_ buttons] count]);
+ CGFloat width_1 = [[[bar_ buttons] objectAtIndex:0] frame].size.width;
+ CGFloat x_2 = [[[bar_ buttons] objectAtIndex:1] frame].origin.x;
+
+ NSButton* first = [[bar_ buttons] objectAtIndex:0];
+ [[first cell] setTitle:@"This is a really big title; watch out mom!"];
+ [bar_ checkForBookmarkButtonGrowth:first];
+
+ // Make sure the 1st button is now wider, the 2nd one is moved over,
+ // and they don't overlap.
+ NSRect frame_1 = [[[bar_ buttons] objectAtIndex:0] frame];
+ NSRect frame_2 = [[[bar_ buttons] objectAtIndex:1] frame];
+ EXPECT_GT(frame_1.size.width, width_1);
+ EXPECT_GT(frame_2.origin.x, x_2);
+ EXPECT_GE(frame_2.origin.x, frame_1.origin.x + frame_1.size.width);
+}
+
+TEST_F(BookmarkBarControllerTest, DeleteBookmark) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+
+ const char* urls[] = { "https://secret.url.com",
+ "http://super.duper.web.site.for.doodz.gov",
+ "http://www.foo-bar-baz.com/" };
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ for (unsigned int i = 0; i < arraysize(urls); i++) {
+ model->AddURL(parent, parent->GetChildCount(),
+ ASCIIToUTF16("title"), GURL(urls[i]));
+ }
+ EXPECT_EQ(3, parent->GetChildCount());
+ const BookmarkNode* middle_node = parent->GetChild(1);
+
+ NSMenuItem* item = ItemForBookmarkBarMenu(middle_node);
+ [bar_ deleteBookmark:item];
+ EXPECT_EQ(2, parent->GetChildCount());
+ EXPECT_EQ(parent->GetChild(0)->GetURL(), GURL(urls[0]));
+ // node 2 moved into spot 1
+ EXPECT_EQ(parent->GetChild(1)->GetURL(), GURL(urls[2]));
+}
+
+// TODO(jrg): write a test to confirm that nodeFavIconLoaded calls
+// checkForBookmarkButtonGrowth:.
+
+TEST_F(BookmarkBarControllerTest, Cell) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ [bar_ loaded:model];
+
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ model->AddURL(parent, parent->GetChildCount(),
+ ASCIIToUTF16("supertitle"),
+ GURL("http://superfriends.hall-of-justice.edu"));
+ const BookmarkNode* node = parent->GetChild(0);
+
+ NSCell* cell = [bar_ cellForBookmarkNode:node];
+ EXPECT_TRUE(cell);
+ EXPECT_NSEQ(@"supertitle", [cell title]);
+ EXPECT_EQ(node, [[cell representedObject] pointerValue]);
+ EXPECT_TRUE([cell menu]);
+
+ // Empty cells have no menu.
+ cell = [bar_ cellForBookmarkNode:nil];
+ EXPECT_FALSE([cell menu]);
+ // Even empty cells have a title (of "(empty)")
+ EXPECT_TRUE([cell title]);
+
+ // cell is autoreleased; no need to release here
+}
+
+// Test drawing, mostly to ensure nothing leaks or crashes.
+TEST_F(BookmarkBarControllerTest, Display) {
+ [[bar_ view] display];
+}
+
+// Test that middle clicking on a bookmark button results in an open action.
+TEST_F(BookmarkBarControllerTest, MiddleClick) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ GURL gurl1("http://www.google.com/");
+ string16 title1(ASCIIToUTF16("x"));
+ model->SetURLStarred(gurl1, title1, true);
+
+ EXPECT_EQ(1U, [[bar_ buttons] count]);
+ NSButton* first = [[bar_ buttons] objectAtIndex:0];
+ EXPECT_TRUE(first);
+
+ [first otherMouseUp:test_event_utils::MakeMouseEvent(NSOtherMouseUp, 0)];
+ EXPECT_EQ(noOpenBar()->urls_.size(), 1U);
+}
+
+TEST_F(BookmarkBarControllerTest, DisplaysHelpMessageOnEmpty) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ [bar_ loaded:model];
+ EXPECT_FALSE([[[bar_ buttonView] noItemContainer] isHidden]);
+}
+
+TEST_F(BookmarkBarControllerTest, HidesHelpMessageWithBookmark) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ model->AddURL(parent, parent->GetChildCount(),
+ ASCIIToUTF16("title"), GURL("http://one.com"));
+
+ [bar_ loaded:model];
+ EXPECT_TRUE([[[bar_ buttonView] noItemContainer] isHidden]);
+}
+
+TEST_F(BookmarkBarControllerTest, BookmarkButtonSizing) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ model->AddURL(parent, parent->GetChildCount(),
+ ASCIIToUTF16("title"), GURL("http://one.com"));
+
+ [bar_ loaded:model];
+
+ // Make sure the internal bookmark button also is the correct height.
+ NSArray* buttons = [bar_ buttons];
+ EXPECT_GT([buttons count], 0u);
+ for (NSButton* button in buttons) {
+ EXPECT_FLOAT_EQ(
+ (bookmarks::kBookmarkBarHeight + bookmarks::kVisualHeightOffset) - 2 *
+ bookmarks::kBookmarkVerticalPadding,
+ [button frame].size.height);
+ }
+}
+
+TEST_F(BookmarkBarControllerTest, DropBookmarks) {
+ const char* urls[] = {
+ "http://qwantz.com",
+ "http://xkcd.com",
+ "javascript:alert('lolwut')",
+ "file://localhost/tmp/local-file.txt" // As if dragged from the desktop.
+ };
+ const char* titles[] = {
+ "Philosophoraptor",
+ "Can't draw",
+ "Inspiration",
+ "Frum stuf"
+ };
+ EXPECT_EQ(arraysize(urls), arraysize(titles));
+
+ NSMutableArray* nsurls = [NSMutableArray array];
+ NSMutableArray* nstitles = [NSMutableArray array];
+ for (size_t i = 0; i < arraysize(urls); ++i) {
+ [nsurls addObject:base::SysUTF8ToNSString(urls[i])];
+ [nstitles addObject:base::SysUTF8ToNSString(titles[i])];
+ }
+
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ [bar_ addURLs:nsurls withTitles:nstitles at:NSZeroPoint];
+ EXPECT_EQ(4, parent->GetChildCount());
+ for (int i = 0; i < parent->GetChildCount(); ++i) {
+ GURL gurl = parent->GetChild(i)->GetURL();
+ if (gurl.scheme() == "http" ||
+ gurl.scheme() == "javascript") {
+ EXPECT_EQ(parent->GetChild(i)->GetURL(), GURL(urls[i]));
+ } else {
+ // Be flexible if the scheme needed to be added.
+ std::string gurl_string = gurl.spec();
+ std::string my_string = parent->GetChild(i)->GetURL().spec();
+ EXPECT_NE(gurl_string.find(my_string), std::string::npos);
+ }
+ EXPECT_EQ(parent->GetChild(i)->GetTitle(), ASCIIToUTF16(titles[i]));
+ }
+}
+
+TEST_F(BookmarkBarControllerTest, TestButtonOrBar) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ GURL gurl1("http://www.google.com");
+ string16 title1(ASCIIToUTF16("x"));
+ model->SetURLStarred(gurl1, title1, true);
+
+ GURL gurl2("http://www.google.com/gurl_power");
+ string16 title2(ASCIIToUTF16("gurl power"));
+ model->SetURLStarred(gurl2, title2, true);
+
+ NSButton* first = [[bar_ buttons] objectAtIndex:0];
+ NSButton* second = [[bar_ buttons] objectAtIndex:1];
+ EXPECT_TRUE(first && second);
+
+ NSMenuItem* menuItem = [[[first cell] menu] itemAtIndex:0];
+ const BookmarkNode* node = [bar_ nodeFromMenuItem:menuItem];
+ EXPECT_TRUE(node);
+ EXPECT_EQ(node, model->GetBookmarkBarNode()->GetChild(0));
+
+ menuItem = [[[second cell] menu] itemAtIndex:0];
+ node = [bar_ nodeFromMenuItem:menuItem];
+ EXPECT_TRUE(node);
+ EXPECT_EQ(node, model->GetBookmarkBarNode()->GetChild(1));
+
+ menuItem = [[[bar_ view] menu] itemAtIndex:0];
+ node = [bar_ nodeFromMenuItem:menuItem];
+ EXPECT_TRUE(node);
+ EXPECT_EQ(node, model->GetBookmarkBarNode());
+}
+
+TEST_F(BookmarkBarControllerTest, TestMenuNodeAndDisable) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ const BookmarkNode* folder = model->AddGroup(parent,
+ parent->GetChildCount(),
+ ASCIIToUTF16("group"));
+ NSButton* button = [[bar_ buttons] objectAtIndex:0];
+ EXPECT_TRUE(button);
+
+ // Confirm the menu knows which node it is talking about
+ BookmarkMenu* menu = static_cast<BookmarkMenu*>([[button cell] menu]);
+ EXPECT_TRUE(menu);
+ EXPECT_TRUE([menu isKindOfClass:[BookmarkMenu class]]);
+ EXPECT_EQ(folder->id(), [menu id]);
+
+ // Make sure "Open All" is disabled (nothing to open -- no children!)
+ // (Assumes "Open All" is the 1st item)
+ NSMenuItem* item = [menu itemAtIndex:0];
+ EXPECT_FALSE([bar_ validateUserInterfaceItem:item]);
+
+ // Now add a child and make sure the item would be enabled.
+ model->AddURL(folder, folder->GetChildCount(),
+ ASCIIToUTF16("super duper wide title"),
+ GURL("http://superfriends.hall-of-justice.edu"));
+ EXPECT_TRUE([bar_ validateUserInterfaceItem:item]);
+}
+
+TEST_F(BookmarkBarControllerTest, TestDragButton) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+
+ GURL gurls[] = { GURL("http://www.google.com/a"),
+ GURL("http://www.google.com/b"),
+ GURL("http://www.google.com/c") };
+ string16 titles[] = { ASCIIToUTF16("a"),
+ ASCIIToUTF16("b"),
+ ASCIIToUTF16("c") };
+ for (unsigned i = 0; i < arraysize(titles); i++) {
+ model->SetURLStarred(gurls[i], titles[i], true);
+ }
+
+ EXPECT_EQ([[bar_ buttons] count], arraysize(titles));
+ EXPECT_NSEQ(@"a", [[[bar_ buttons] objectAtIndex:0] title]);
+
+ [bar_ dragButton:[[bar_ buttons] objectAtIndex:2]
+ to:NSMakePoint(0, 0)
+ copy:NO];
+ EXPECT_NSEQ(@"c", [[[bar_ buttons] objectAtIndex:0] title]);
+ // Make sure a 'copy' did not happen.
+ EXPECT_EQ([[bar_ buttons] count], arraysize(titles));
+
+ [bar_ dragButton:[[bar_ buttons] objectAtIndex:1]
+ to:NSMakePoint(1000, 0)
+ copy:NO];
+ EXPECT_NSEQ(@"c", [[[bar_ buttons] objectAtIndex:0] title]);
+ EXPECT_NSEQ(@"b", [[[bar_ buttons] objectAtIndex:1] title]);
+ EXPECT_NSEQ(@"a", [[[bar_ buttons] objectAtIndex:2] title]);
+ EXPECT_EQ([[bar_ buttons] count], arraysize(titles));
+
+ // A drop of the 1st between the next 2.
+ CGFloat x = NSMinX([[[bar_ buttons] objectAtIndex:2] frame]);
+ x += [[bar_ view] frame].origin.x;
+ [bar_ dragButton:[[bar_ buttons] objectAtIndex:0]
+ to:NSMakePoint(x, 0)
+ copy:NO];
+ EXPECT_NSEQ(@"b", [[[bar_ buttons] objectAtIndex:0] title]);
+ EXPECT_NSEQ(@"c", [[[bar_ buttons] objectAtIndex:1] title]);
+ EXPECT_NSEQ(@"a", [[[bar_ buttons] objectAtIndex:2] title]);
+ EXPECT_EQ([[bar_ buttons] count], arraysize(titles));
+
+ // A drop on a non-folder button. (Shouldn't try and go in it.)
+ x = NSMidX([[[bar_ buttons] objectAtIndex:0] frame]);
+ x += [[bar_ view] frame].origin.x;
+ [bar_ dragButton:[[bar_ buttons] objectAtIndex:2]
+ to:NSMakePoint(x, 0)
+ copy:NO];
+ EXPECT_EQ(arraysize(titles), [[bar_ buttons] count]);
+
+ // A drop on a folder button.
+ const BookmarkNode* folder = model->AddGroup(model->GetBookmarkBarNode(),
+ 0,
+ ASCIIToUTF16("awesome group"));
+ DCHECK(folder);
+ model->AddURL(folder, 0, ASCIIToUTF16("already"),
+ GURL("http://www.google.com"));
+ EXPECT_EQ(arraysize(titles) + 1, [[bar_ buttons] count]);
+ EXPECT_EQ(1, folder->GetChildCount());
+ x = NSMidX([[[bar_ buttons] objectAtIndex:0] frame]);
+ x += [[bar_ view] frame].origin.x;
+ string16 title = [[[bar_ buttons] objectAtIndex:2] bookmarkNode]->GetTitle();
+ [bar_ dragButton:[[bar_ buttons] objectAtIndex:2]
+ to:NSMakePoint(x, 0)
+ copy:NO];
+ // Gone from the bar
+ EXPECT_EQ(arraysize(titles), [[bar_ buttons] count]);
+ // In the folder
+ EXPECT_EQ(2, folder->GetChildCount());
+ // At the end
+ EXPECT_EQ(title, folder->GetChild(1)->GetTitle());
+}
+
+TEST_F(BookmarkBarControllerTest, TestCopyButton) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+
+ GURL gurls[] = { GURL("http://www.google.com/a"),
+ GURL("http://www.google.com/b"),
+ GURL("http://www.google.com/c") };
+ string16 titles[] = { ASCIIToUTF16("a"),
+ ASCIIToUTF16("b"),
+ ASCIIToUTF16("c") };
+ for (unsigned i = 0; i < arraysize(titles); i++) {
+ model->SetURLStarred(gurls[i], titles[i], true);
+ }
+ EXPECT_EQ([[bar_ buttons] count], arraysize(titles));
+ EXPECT_NSEQ(@"a", [[[bar_ buttons] objectAtIndex:0] title]);
+
+ // Drag 'a' between 'b' and 'c'.
+ CGFloat x = NSMinX([[[bar_ buttons] objectAtIndex:2] frame]);
+ x += [[bar_ view] frame].origin.x;
+ [bar_ dragButton:[[bar_ buttons] objectAtIndex:0]
+ to:NSMakePoint(x, 0)
+ copy:YES];
+ EXPECT_NSEQ(@"a", [[[bar_ buttons] objectAtIndex:0] title]);
+ EXPECT_NSEQ(@"b", [[[bar_ buttons] objectAtIndex:1] title]);
+ EXPECT_NSEQ(@"a", [[[bar_ buttons] objectAtIndex:2] title]);
+ EXPECT_NSEQ(@"c", [[[bar_ buttons] objectAtIndex:3] title]);
+ EXPECT_EQ([[bar_ buttons] count], 4U);
+}
+
+// Fake a theme with colored text. Apply it and make sure bookmark
+// buttons have the same colored text. Repeat more than once.
+TEST_F(BookmarkBarControllerTest, TestThemedButton) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ model->SetURLStarred(GURL("http://www.foo.com"), ASCIIToUTF16("small"), true);
+ BookmarkButton* button = [[bar_ buttons] objectAtIndex:0];
+ EXPECT_TRUE(button);
+
+ NSArray* colors = [NSArray arrayWithObjects:[NSColor redColor],
+ [NSColor blueColor],
+ nil];
+ for (NSColor* color in colors) {
+ FakeTheme theme(color);
+ [bar_ updateTheme:&theme];
+ NSAttributedString* astr = [button attributedTitle];
+ EXPECT_TRUE(astr);
+ EXPECT_NSEQ(@"small", [astr string]);
+ // Pick a char in the middle to test (index 3)
+ NSDictionary* attributes = [astr attributesAtIndex:3 effectiveRange:NULL];
+ NSColor* newColor =
+ [attributes objectForKey:NSForegroundColorAttributeName];
+ EXPECT_NSEQ(newColor, color);
+ }
+}
+
+// Test that delegates and targets of buttons are cleared on dealloc.
+TEST_F(BookmarkBarControllerTest, TestClearOnDealloc) {
+ // Make some bookmark buttons.
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ GURL gurls[] = { GURL("http://www.foo.com/"),
+ GURL("http://www.bar.com/"),
+ GURL("http://www.baz.com/") };
+ string16 titles[] = { ASCIIToUTF16("a"),
+ ASCIIToUTF16("b"),
+ ASCIIToUTF16("c") };
+ for (size_t i = 0; i < arraysize(titles); i++)
+ model->SetURLStarred(gurls[i], titles[i], true);
+
+ // Get and retain the buttons so we can examine them after dealloc.
+ scoped_nsobject<NSArray> buttons([[bar_ buttons] retain]);
+ EXPECT_EQ([buttons count], arraysize(titles));
+
+ // Make sure that everything is set.
+ for (BookmarkButton* button in buttons.get()) {
+ ASSERT_TRUE([button isKindOfClass:[BookmarkButton class]]);
+ EXPECT_TRUE([button delegate]);
+ EXPECT_TRUE([button target]);
+ EXPECT_TRUE([button action]);
+ }
+
+ // This will dealloc....
+ bar_.reset();
+
+ // Make sure that everything is cleared.
+ for (BookmarkButton* button in buttons.get()) {
+ EXPECT_FALSE([button delegate]);
+ EXPECT_FALSE([button target]);
+ EXPECT_FALSE([button action]);
+ }
+}
+
+TEST_F(BookmarkBarControllerTest, TestFolders) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+
+ // Create some folder buttons.
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ const BookmarkNode* folder = model->AddGroup(parent,
+ parent->GetChildCount(),
+ ASCIIToUTF16("group"));
+ model->AddURL(folder, folder->GetChildCount(),
+ ASCIIToUTF16("f1"), GURL("http://framma-lamma.com"));
+ folder = model->AddGroup(parent, parent->GetChildCount(),
+ ASCIIToUTF16("empty"));
+
+ EXPECT_EQ([[bar_ buttons] count], 2U);
+
+ // First confirm mouseEntered does nothing if "menus" aren't active.
+ NSEvent* event = test_event_utils::MakeMouseEvent(NSOtherMouseUp, 0);
+ [bar_ mouseEnteredButton:[[bar_ buttons] objectAtIndex:0] event:event];
+ EXPECT_FALSE([bar_ folderController]);
+
+ // Make one active. Entering it is now a no-op.
+ [bar_ openBookmarkFolderFromButton:[[bar_ buttons] objectAtIndex:0]];
+ BookmarkBarFolderController* bbfc = [bar_ folderController];
+ EXPECT_TRUE(bbfc);
+ [bar_ mouseEnteredButton:[[bar_ buttons] objectAtIndex:0] event:event];
+ EXPECT_EQ(bbfc, [bar_ folderController]);
+
+ // Enter a different one; a new folderController is active.
+ [bar_ mouseEnteredButton:[[bar_ buttons] objectAtIndex:1] event:event];
+ EXPECT_NE(bbfc, [bar_ folderController]);
+
+ // Confirm exited is a no-op.
+ [bar_ mouseExitedButton:[[bar_ buttons] objectAtIndex:1] event:event];
+ EXPECT_NE(bbfc, [bar_ folderController]);
+
+ // Clean up.
+ [bar_ closeBookmarkFolder:nil];
+}
+
+// Verify that the folder menu presentation properly tracks mouse movements
+// over the bar. Until there is a click no folder menus should show. After a
+// click on a folder folder menus should show until another click on a folder
+// button, and a click outside the bar and its folder menus.
+TEST_F(BookmarkBarControllerTest, TestFolderButtons) {
+ BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ const std::string model_string("1b 2f:[ 2f1b 2f2b ] 3b 4f:[ 4f1b 4f2b ] ");
+ model_test_utils::AddNodesFromModelString(model, root, model_string);
+
+ // Validate initial model and that we do not have a folder controller.
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(model_string, actualModelString);
+ EXPECT_FALSE([bar_ folderController]);
+
+ // Add a real bookmark so we can click on it.
+ const BookmarkNode* folder = root->GetChild(3);
+ model.AddURL(folder, folder->GetChildCount(), ASCIIToUTF16("CLICK ME"),
+ GURL("http://www.google.com/"));
+
+ // Click on a folder button.
+ BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"4f"];
+ EXPECT_TRUE(button);
+ [bar_ openBookmarkFolderFromButton:button];
+ BookmarkBarFolderController* bbfc = [bar_ folderController];
+ EXPECT_TRUE(bbfc);
+
+ // Make sure a 2nd click on the same button closes things.
+ [bar_ openBookmarkFolderFromButton:button];
+ EXPECT_FALSE([bar_ folderController]);
+
+ // Next open is a different button.
+ button = [bar_ buttonWithTitleEqualTo:@"2f"];
+ EXPECT_TRUE(button);
+ [bar_ openBookmarkFolderFromButton:button];
+ EXPECT_TRUE([bar_ folderController]);
+
+ // Mouse over a non-folder button and confirm controller has gone away.
+ button = [bar_ buttonWithTitleEqualTo:@"1b"];
+ EXPECT_TRUE(button);
+ NSEvent* event = test_event_utils::MouseEventAtPoint([button center],
+ NSMouseMoved, 0);
+ [bar_ mouseEnteredButton:button event:event];
+ EXPECT_FALSE([bar_ folderController]);
+
+ // Mouse over the original folder and confirm a new controller.
+ button = [bar_ buttonWithTitleEqualTo:@"2f"];
+ EXPECT_TRUE(button);
+ [bar_ mouseEnteredButton:button event:event];
+ BookmarkBarFolderController* oldBBFC = [bar_ folderController];
+ EXPECT_TRUE(oldBBFC);
+
+ // 'Jump' over to a different folder and confirm a new controller.
+ button = [bar_ buttonWithTitleEqualTo:@"4f"];
+ EXPECT_TRUE(button);
+ [bar_ mouseEnteredButton:button event:event];
+ BookmarkBarFolderController* newBBFC = [bar_ folderController];
+ EXPECT_TRUE(newBBFC);
+ EXPECT_NE(oldBBFC, newBBFC);
+
+ // A click on a real bookmark should close and stop tracking the folder menus.
+ BookmarkButton* bookmarkButton = [newBBFC buttonWithTitleEqualTo:@"CLICK ME"];
+ EXPECT_TRUE(bookmarkButton);
+ [newBBFC openBookmark:bookmarkButton];
+ EXPECT_FALSE([bar_ folderController]);
+ [bar_ mouseEnteredButton:button event:event];
+ EXPECT_FALSE([bar_ folderController]);
+}
+
+// Make sure the "off the side" folder looks like a bookmark folder
+// but only contains "off the side" items.
+TEST_F(BookmarkBarControllerTest, OffTheSideFolder) {
+
+ // It starts hidden.
+ EXPECT_TRUE([bar_ offTheSideButtonIsHidden]);
+
+ // Create some buttons.
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ for (int x = 0; x < 30; x++) {
+ model->AddURL(parent, parent->GetChildCount(),
+ ASCIIToUTF16("medium-size-title"),
+ GURL("http://framma-lamma.com"));
+ }
+ // Add a couple more so we can delete one and make sure its button goes away.
+ model->AddURL(parent, parent->GetChildCount(),
+ ASCIIToUTF16("DELETE_ME"), GURL("http://ashton-tate.com"));
+ model->AddURL(parent, parent->GetChildCount(),
+ ASCIIToUTF16("medium-size-title"),
+ GURL("http://framma-lamma.com"));
+
+ // Should no longer be hidden.
+ EXPECT_FALSE([bar_ offTheSideButtonIsHidden]);
+
+ // Open it; make sure we have a folder controller.
+ EXPECT_FALSE([bar_ folderController]);
+ [bar_ openOffTheSideFolderFromButton:[bar_ offTheSideButton]];
+ BookmarkBarFolderController* bbfc = [bar_ folderController];
+ EXPECT_TRUE(bbfc);
+
+ // Confirm the contents are only buttons which fell off the side by
+ // making sure that none of the nodes in the off-the-side folder are
+ // found in bar buttons. Be careful since not all the bar buttons
+ // may be currently displayed.
+ NSArray* folderButtons = [bbfc buttons];
+ NSArray* barButtons = [bar_ buttons];
+ for (BookmarkButton* folderButton in folderButtons) {
+ for (BookmarkButton* barButton in barButtons) {
+ if ([barButton superview]) {
+ EXPECT_NE([folderButton bookmarkNode], [barButton bookmarkNode]);
+ }
+ }
+ }
+
+ // Delete a bookmark in the off-the-side and verify it's gone.
+ BookmarkButton* button = [bbfc buttonWithTitleEqualTo:@"DELETE_ME"];
+ EXPECT_TRUE(button);
+ model->Remove(parent, parent->GetChildCount() - 2);
+ button = [bbfc buttonWithTitleEqualTo:@"DELETE_ME"];
+ EXPECT_FALSE(button);
+}
+
+TEST_F(BookmarkBarControllerTest, EventToExitCheck) {
+ NSEvent* event = test_event_utils::MakeMouseEvent(NSMouseMoved, 0);
+ EXPECT_FALSE([bar_ isEventAnExitEvent:event]);
+
+ BookmarkBarFolderWindow* folderWindow = [[[BookmarkBarFolderWindow alloc]
+ init] autorelease];
+ [[[bar_ view] window] addChildWindow:folderWindow
+ ordered:NSWindowAbove];
+ event = test_event_utils::LeftMouseDownAtPointInWindow(NSMakePoint(1,1),
+ folderWindow);
+ EXPECT_FALSE([bar_ isEventAnExitEvent:event]);
+
+ event = test_event_utils::LeftMouseDownAtPointInWindow(NSMakePoint(100,100),
+ test_window());
+ EXPECT_TRUE([bar_ isEventAnExitEvent:event]);
+
+ // Many components are arbitrary (e.g. location, keycode).
+ event = [NSEvent keyEventWithType:NSKeyDown
+ location:NSMakePoint(1,1)
+ modifierFlags:0
+ timestamp:0
+ windowNumber:0
+ context:nil
+ characters:@"x"
+ charactersIgnoringModifiers:@"x"
+ isARepeat:NO
+ keyCode:87];
+ EXPECT_TRUE([bar_ isEventAnExitEvent:event]);
+
+ [[[bar_ view] window] removeChildWindow:folderWindow];
+}
+
+TEST_F(BookmarkBarControllerTest, DropDestination) {
+ // Make some buttons.
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ model->AddGroup(parent, parent->GetChildCount(), ASCIIToUTF16("group 1"));
+ model->AddGroup(parent, parent->GetChildCount(), ASCIIToUTF16("group 2"));
+ EXPECT_EQ([[bar_ buttons] count], 2U);
+
+ // Confirm "off to left" and "off to right" match nothing.
+ NSPoint p = NSMakePoint(-1, 2);
+ EXPECT_FALSE([bar_ buttonForDroppingOnAtPoint:p]);
+ EXPECT_TRUE([bar_ shouldShowIndicatorShownForPoint:p]);
+ p = NSMakePoint(50000, 10);
+ EXPECT_FALSE([bar_ buttonForDroppingOnAtPoint:p]);
+ EXPECT_TRUE([bar_ shouldShowIndicatorShownForPoint:p]);
+
+ // Confirm "right in the center" (give or take a pixel) is a match,
+ // and confirm "just barely in the button" is not. Anything more
+ // specific seems likely to be tweaked.
+ CGFloat viewFrameXOffset = [[bar_ view] frame].origin.x;
+ for (BookmarkButton* button in [bar_ buttons]) {
+ CGFloat x = NSMidX([button frame]) + viewFrameXOffset;
+ // Somewhere near the center: a match
+ EXPECT_EQ(button,
+ [bar_ buttonForDroppingOnAtPoint:NSMakePoint(x-1, 10)]);
+ EXPECT_EQ(button,
+ [bar_ buttonForDroppingOnAtPoint:NSMakePoint(x+1, 10)]);
+ EXPECT_FALSE([bar_ shouldShowIndicatorShownForPoint:NSMakePoint(x, 10)]);;
+
+ // On the very edges: NOT a match
+ x = NSMinX([button frame]) + viewFrameXOffset;
+ EXPECT_NE(button,
+ [bar_ buttonForDroppingOnAtPoint:NSMakePoint(x, 9)]);
+ x = NSMaxX([button frame]) + viewFrameXOffset;
+ EXPECT_NE(button,
+ [bar_ buttonForDroppingOnAtPoint:NSMakePoint(x, 11)]);
+ }
+}
+
+TEST_F(BookmarkBarControllerTest, NodeDeletedWhileMenuIsOpen) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ [bar_ loaded:model];
+
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ const BookmarkNode* initialNode = model->AddURL(
+ parent, parent->GetChildCount(),
+ ASCIIToUTF16("initial"),
+ GURL("http://www.google.com"));
+
+ NSMenuItem* item = ItemForBookmarkBarMenu(initialNode);
+ EXPECT_EQ(0U, noOpenBar()->urls_.size());
+
+ // Basic check of the menu item and an IBOutlet it can call.
+ EXPECT_EQ(initialNode, [bar_ nodeFromMenuItem:item]);
+ [bar_ openBookmarkInNewWindow:item];
+ EXPECT_EQ(1U, noOpenBar()->urls_.size());
+ [bar_ clear];
+
+ // Now delete the node and make sure things are happy (no crash,
+ // NULL node caught).
+ model->Remove(parent, parent->IndexOfChild(initialNode));
+ EXPECT_EQ(nil, [bar_ nodeFromMenuItem:item]);
+ // Should not crash by referencing a deleted node.
+ [bar_ openBookmarkInNewWindow:item];
+ // Confirm the above did nothing in case it somehow didn't crash.
+ EXPECT_EQ(0U, noOpenBar()->urls_.size());
+
+ // Confirm some more non-crashes.
+ [bar_ openBookmarkInNewForegroundTab:item];
+ [bar_ openBookmarkInIncognitoWindow:item];
+ [bar_ editBookmark:item];
+ [bar_ copyBookmark:item];
+ [bar_ deleteBookmark:item];
+ [bar_ openAllBookmarks:item];
+ [bar_ openAllBookmarksNewWindow:item];
+ [bar_ openAllBookmarksIncognitoWindow:item];
+}
+
+TEST_F(BookmarkBarControllerTest, NodeDeletedWhileContextMenuIsOpen) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ [bar_ loaded:model];
+
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ const BookmarkNode* folder = model->AddGroup(parent,
+ parent->GetChildCount(),
+ ASCIIToUTF16("group"));
+ const BookmarkNode* framma = model->AddURL(folder, folder->GetChildCount(),
+ ASCIIToUTF16("f1"),
+ GURL("http://framma-lamma.com"));
+
+ // Mock in a menu
+ id origMenu = [bar_ buttonContextMenu];
+ id fakeMenu = [OCMockObject partialMockForObject:origMenu];
+ [[fakeMenu expect] cancelTracking];
+ [bar_ setButtonContextMenu:fakeMenu];
+
+ // Force a delete which should cancelTracking on the menu.
+ model->Remove(framma->GetParent(), framma->GetParent()->IndexOfChild(framma));
+
+ // Restore, then confirm cancelTracking was called.
+ [bar_ setButtonContextMenu:origMenu];
+ [fakeMenu verify];
+}
+
+TEST_F(BookmarkBarControllerTest, CloseFolderOnAnimate) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ const BookmarkNode* folder = model->AddGroup(parent,
+ parent->GetChildCount(),
+ ASCIIToUTF16("group"));
+ model->AddGroup(parent, parent->GetChildCount(),
+ ASCIIToUTF16("sibbling group"));
+ model->AddURL(folder, folder->GetChildCount(), ASCIIToUTF16("title a"),
+ GURL("http://www.google.com/a"));
+ model->AddURL(folder, folder->GetChildCount(),
+ ASCIIToUTF16("title super duper long long whoa momma title you betcha"),
+ GURL("http://www.google.com/b"));
+ BookmarkButton* button = [[bar_ buttons] objectAtIndex:0];
+ EXPECT_FALSE([bar_ folderController]);
+ [bar_ openBookmarkFolderFromButton:button];
+ BookmarkBarFolderController* bbfc = [bar_ folderController];
+ // The following tells us that the folder menu is showing. We want to make
+ // sure the folder menu goes away if the bookmark bar is hidden.
+ EXPECT_TRUE(bbfc);
+ EXPECT_TRUE([bar_ isVisible]);
+
+ // Hide the bookmark bar.
+ [bar_ updateAndShowNormalBar:NO
+ showDetachedBar:YES
+ withAnimation:YES];
+ EXPECT_TRUE([bar_ isAnimationRunning]);
+
+ // Now that we've closed the bookmark bar (with animation) the folder menu
+ // should have been closed thus releasing the folderController.
+ EXPECT_FALSE([bar_ folderController]);
+}
+
+TEST_F(BookmarkBarControllerTest, MoveRemoveAddButtons) {
+ BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ const std::string model_string("1b 2f:[ 2f1b 2f2b ] 3b ");
+ model_test_utils::AddNodesFromModelString(model, root, model_string);
+
+ // Validate initial model.
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(model_string, actualModelString);
+
+ // Remember how many buttons are showing.
+ int oldDisplayedButtons = [bar_ displayedButtonCount];
+ NSArray* buttons = [bar_ buttons];
+
+ // Move a button around a bit.
+ [bar_ moveButtonFromIndex:0 toIndex:2];
+ EXPECT_NSEQ(@"2f", [[buttons objectAtIndex:0] title]);
+ EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:1] title]);
+ EXPECT_NSEQ(@"1b", [[buttons objectAtIndex:2] title]);
+ EXPECT_EQ(oldDisplayedButtons, [bar_ displayedButtonCount]);
+ [bar_ moveButtonFromIndex:2 toIndex:0];
+ EXPECT_NSEQ(@"1b", [[buttons objectAtIndex:0] title]);
+ EXPECT_NSEQ(@"2f", [[buttons objectAtIndex:1] title]);
+ EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:2] title]);
+ EXPECT_EQ(oldDisplayedButtons, [bar_ displayedButtonCount]);
+
+ // Add a couple of buttons.
+ const BookmarkNode* parent = root->GetChild(1); // Purloin an existing node.
+ const BookmarkNode* node = parent->GetChild(0);
+ [bar_ addButtonForNode:node atIndex:0];
+ EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:0] title]);
+ EXPECT_NSEQ(@"1b", [[buttons objectAtIndex:1] title]);
+ EXPECT_NSEQ(@"2f", [[buttons objectAtIndex:2] title]);
+ EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:3] title]);
+ EXPECT_EQ(oldDisplayedButtons + 1, [bar_ displayedButtonCount]);
+ node = parent->GetChild(1);
+ [bar_ addButtonForNode:node atIndex:-1];
+ EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:0] title]);
+ EXPECT_NSEQ(@"1b", [[buttons objectAtIndex:1] title]);
+ EXPECT_NSEQ(@"2f", [[buttons objectAtIndex:2] title]);
+ EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:3] title]);
+ EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:4] title]);
+ EXPECT_EQ(oldDisplayedButtons + 2, [bar_ displayedButtonCount]);
+
+ // Remove a couple of buttons.
+ [bar_ removeButton:4 animate:NO];
+ [bar_ removeButton:1 animate:NO];
+ EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:0] title]);
+ EXPECT_NSEQ(@"2f", [[buttons objectAtIndex:1] title]);
+ EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:2] title]);
+ EXPECT_EQ(oldDisplayedButtons, [bar_ displayedButtonCount]);
+}
+
+TEST_F(BookmarkBarControllerTest, ShrinkOrHideView) {
+ NSRect viewFrame = NSMakeRect(0.0, 0.0, 500.0, 50.0);
+ NSView* view = [[[NSView alloc] initWithFrame:viewFrame] autorelease];
+ EXPECT_FALSE([view isHidden]);
+ [bar_ shrinkOrHideView:view forMaxX:500.0];
+ EXPECT_EQ(500.0, NSWidth([view frame]));
+ EXPECT_FALSE([view isHidden]);
+ [bar_ shrinkOrHideView:view forMaxX:450.0];
+ EXPECT_EQ(450.0, NSWidth([view frame]));
+ EXPECT_FALSE([view isHidden]);
+ [bar_ shrinkOrHideView:view forMaxX:40.0];
+ EXPECT_EQ(40.0, NSWidth([view frame]));
+ EXPECT_FALSE([view isHidden]);
+ [bar_ shrinkOrHideView:view forMaxX:31.0];
+ EXPECT_EQ(31.0, NSWidth([view frame]));
+ EXPECT_FALSE([view isHidden]);
+ [bar_ shrinkOrHideView:view forMaxX:29.0];
+ EXPECT_TRUE([view isHidden]);
+}
+
+class BookmarkBarControllerOpenAllTest : public BookmarkBarControllerTest {
+public:
+ BookmarkBarControllerOpenAllTest() {
+ resizeDelegate_.reset([[ViewResizerPong alloc] init]);
+ NSRect parent_frame = NSMakeRect(0, 0, 800, 50);
+ bar_.reset(
+ [[BookmarkBarControllerOpenAllPong alloc]
+ initWithBrowser:helper_.browser()
+ initialWidth:NSWidth(parent_frame)
+ delegate:nil
+ resizeDelegate:resizeDelegate_.get()]);
+ [bar_ view];
+ // Awkwardness to look like we've been installed.
+ [parent_view_ addSubview:[bar_ view]];
+ NSRect frame = [[[bar_ view] superview] frame];
+ frame.origin.y = 100;
+ [[[bar_ view] superview] setFrame:frame];
+
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ parent_ = model->GetBookmarkBarNode();
+ // { one, { two-one, two-two }, three }
+ model->AddURL(parent_, parent_->GetChildCount(), ASCIIToUTF16("title"),
+ GURL("http://one.com"));
+ folder_ = model->AddGroup(parent_, parent_->GetChildCount(),
+ ASCIIToUTF16("group"));
+ model->AddURL(folder_, folder_->GetChildCount(),
+ ASCIIToUTF16("title"), GURL("http://two-one.com"));
+ model->AddURL(folder_, folder_->GetChildCount(),
+ ASCIIToUTF16("title"), GURL("http://two-two.com"));
+ model->AddURL(parent_, parent_->GetChildCount(),
+ ASCIIToUTF16("title"), GURL("https://three.com"));
+ }
+ const BookmarkNode* parent_; // Weak
+ const BookmarkNode* folder_; // Weak
+};
+
+TEST_F(BookmarkBarControllerOpenAllTest, OpenAllBookmarks) {
+ // Our first OpenAll... is from the bar itself.
+ [bar_ openAllBookmarks:ItemForBookmarkBarMenu(parent_)];
+ BookmarkBarControllerOpenAllPong* specialBar =
+ (BookmarkBarControllerOpenAllPong*)bar_.get();
+ EXPECT_EQ([specialBar dispositionDetected], NEW_FOREGROUND_TAB);
+
+ // Now try an OpenAll... from a folder node.
+ [specialBar setDispositionDetected:IGNORE_ACTION]; // Reset
+ [bar_ openAllBookmarks:ItemForBookmarkBarMenu(folder_)];
+ EXPECT_EQ([specialBar dispositionDetected], NEW_FOREGROUND_TAB);
+}
+
+TEST_F(BookmarkBarControllerOpenAllTest, OpenAllNewWindow) {
+ // Our first OpenAll... is from the bar itself.
+ [bar_ openAllBookmarksNewWindow:ItemForBookmarkBarMenu(parent_)];
+ BookmarkBarControllerOpenAllPong* specialBar =
+ (BookmarkBarControllerOpenAllPong*)bar_.get();
+ EXPECT_EQ([specialBar dispositionDetected], NEW_WINDOW);
+
+ // Now try an OpenAll... from a folder node.
+ [specialBar setDispositionDetected:IGNORE_ACTION]; // Reset
+ [bar_ openAllBookmarksNewWindow:ItemForBookmarkBarMenu(folder_)];
+ EXPECT_EQ([specialBar dispositionDetected], NEW_WINDOW);
+}
+
+TEST_F(BookmarkBarControllerOpenAllTest, OpenAllIncognito) {
+ // Our first OpenAll... is from the bar itself.
+ [bar_ openAllBookmarksIncognitoWindow:ItemForBookmarkBarMenu(parent_)];
+ BookmarkBarControllerOpenAllPong* specialBar =
+ (BookmarkBarControllerOpenAllPong*)bar_.get();
+ EXPECT_EQ([specialBar dispositionDetected], OFF_THE_RECORD);
+
+ // Now try an OpenAll... from a folder node.
+ [specialBar setDispositionDetected:IGNORE_ACTION]; // Reset
+ [bar_ openAllBookmarksIncognitoWindow:ItemForBookmarkBarMenu(folder_)];
+ EXPECT_EQ([specialBar dispositionDetected], OFF_THE_RECORD);
+}
+
+// Command-click on a folder should open all the bookmarks in it.
+TEST_F(BookmarkBarControllerOpenAllTest, CommandClickOnFolder) {
+ NSButton* first = [[bar_ buttons] objectAtIndex:0];
+ EXPECT_TRUE(first);
+
+ // Create the right kind of event; mock NSApp so [NSApp
+ // currentEvent] finds it.
+ NSEvent* commandClick = test_event_utils::MouseEventAtPoint(NSZeroPoint,
+ NSLeftMouseDown,
+ NSCommandKeyMask);
+ id fakeApp = [OCMockObject partialMockForObject:NSApp];
+ [[[fakeApp stub] andReturn:commandClick] currentEvent];
+ id oldApp = NSApp;
+ NSApp = fakeApp;
+ size_t originalDispositionCount = noOpenBar()->dispositions_.size();
+
+ // Click!
+ [first performClick:first];
+
+ size_t dispositionCount = noOpenBar()->dispositions_.size();
+ EXPECT_EQ(originalDispositionCount+1, dispositionCount);
+ EXPECT_EQ(noOpenBar()->dispositions_[dispositionCount-1], NEW_BACKGROUND_TAB);
+
+ // Replace NSApp
+ NSApp = oldApp;
+}
+
+class BookmarkBarControllerNotificationTest : public CocoaTest {
+ public:
+ BookmarkBarControllerNotificationTest() {
+ resizeDelegate_.reset([[ViewResizerPong alloc] init]);
+ NSRect parent_frame = NSMakeRect(0, 0, 800, 50);
+ parent_view_.reset([[NSView alloc] initWithFrame:parent_frame]);
+ [parent_view_ setHidden:YES];
+ bar_.reset(
+ [[BookmarkBarControllerNotificationPong alloc]
+ initWithBrowser:helper_.browser()
+ initialWidth:NSWidth(parent_frame)
+ delegate:nil
+ resizeDelegate:resizeDelegate_.get()]);
+
+ // Force loading of the nib.
+ [bar_ view];
+ // Awkwardness to look like we've been installed.
+ [parent_view_ addSubview:[bar_ view]];
+ NSRect frame = [[[bar_ view] superview] frame];
+ frame.origin.y = 100;
+ [[[bar_ view] superview] setFrame:frame];
+
+ // Do not add the bar to a window, yet.
+ }
+
+ BrowserTestHelper helper_;
+ scoped_nsobject<NSView> parent_view_;
+ scoped_nsobject<ViewResizerPong> resizeDelegate_;
+ scoped_nsobject<BookmarkBarControllerNotificationPong> bar_;
+};
+
+TEST_F(BookmarkBarControllerNotificationTest, DeregistersForNotifications) {
+ NSWindow* window = [[CocoaTestHelperWindow alloc] init];
+ [window setReleasedWhenClosed:YES];
+
+ // First add the bookmark bar to the temp window, then to another window.
+ [[window contentView] addSubview:parent_view_];
+ [[test_window() contentView] addSubview:parent_view_];
+
+ // Post a fake windowDidResignKey notification for the temp window and make
+ // sure the bookmark bar controller wasn't listening.
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName:NSWindowDidResignKeyNotification
+ object:window];
+ EXPECT_FALSE([bar_ windowDidResignKeyReceived]);
+
+ // Close the temp window and make sure no notification was received.
+ [window close];
+ EXPECT_FALSE([bar_ windowWillCloseReceived]);
+}
+
+
+// TODO(jrg): draggingEntered: and draggingExited: trigger timers so
+// they are hard to test. Factor out "fire timers" into routines
+// which can be overridden to fire immediately to make behavior
+// confirmable.
+
+// TODO(jrg): add unit test to make sure "Other Bookmarks" responds
+// properly to a hover open.
+
+// TODO(viettrungluu): figure out how to test animations.
+
+class BookmarkBarControllerDragDropTest : public BookmarkBarControllerTestBase {
+ public:
+ scoped_nsobject<BookmarkBarControllerDragData> bar_;
+
+ BookmarkBarControllerDragDropTest() {
+ bar_.reset(
+ [[BookmarkBarControllerDragData alloc]
+ initWithBrowser:helper_.browser()
+ initialWidth:NSWidth([parent_view_ frame])
+ delegate:nil
+ resizeDelegate:resizeDelegate_.get()]);
+ InstallAndToggleBar(bar_.get());
+ }
+};
+
+TEST_F(BookmarkBarControllerDragDropTest, DragMoveBarBookmarkToOffTheSide) {
+ BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ const std::string model_string("1bWithLongName 2fWithLongName:[ "
+ "2f1bWithLongName 2f2fWithLongName:[ 2f2f1bWithLongName "
+ "2f2f2bWithLongName 2f2f3bWithLongName 2f4b ] 2f3bWithLongName ] "
+ "3bWithLongName 4bWithLongName 5bWithLongName 6bWithLongName "
+ "7bWithLongName 8bWithLongName 9bWithLongName 10bWithLongName "
+ "11bWithLongName 12bWithLongName 13b ");
+ model_test_utils::AddNodesFromModelString(model, root, model_string);
+
+ // Validate initial model.
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(model_string, actualModelString);
+
+ // Insure that the off-the-side is not showing.
+ ASSERT_FALSE([bar_ offTheSideButtonIsHidden]);
+
+ // Remember how many buttons are showing and are available.
+ int oldDisplayedButtons = [bar_ displayedButtonCount];
+ int oldChildCount = root->GetChildCount();
+
+ // Pop up the off-the-side menu.
+ BookmarkButton* otsButton = (BookmarkButton*)[bar_ offTheSideButton];
+ ASSERT_TRUE(otsButton);
+ [[otsButton target] performSelector:@selector(openOffTheSideFolderFromButton:)
+ withObject:otsButton];
+ BookmarkBarFolderController* otsController = [bar_ folderController];
+ EXPECT_TRUE(otsController);
+ NSWindow* toWindow = [otsController window];
+ EXPECT_TRUE(toWindow);
+ BookmarkButton* draggedButton =
+ [bar_ buttonWithTitleEqualTo:@"3bWithLongName"];
+ ASSERT_TRUE(draggedButton);
+ int oldOTSCount = (int)[[otsController buttons] count];
+ EXPECT_EQ(oldOTSCount, oldChildCount - oldDisplayedButtons);
+ BookmarkButton* targetButton = [[otsController buttons] objectAtIndex:0];
+ ASSERT_TRUE(targetButton);
+ [otsController dragButton:draggedButton
+ to:[targetButton center]
+ copy:YES];
+ // There should still be the same number of buttons in the bar
+ // and off-the-side should have one more.
+ int newDisplayedButtons = [bar_ displayedButtonCount];
+ int newChildCount = root->GetChildCount();
+ int newOTSCount = (int)[[otsController buttons] count];
+ EXPECT_EQ(oldDisplayedButtons, newDisplayedButtons);
+ EXPECT_EQ(oldChildCount + 1, newChildCount);
+ EXPECT_EQ(oldOTSCount + 1, newOTSCount);
+ EXPECT_EQ(newOTSCount, newChildCount - newDisplayedButtons);
+}
+
+TEST_F(BookmarkBarControllerDragDropTest, DragOffTheSideToOther) {
+ BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ const std::string model_string("1bWithLongName 2bWithLongName "
+ "3bWithLongName 4bWithLongName 5bWithLongName 6bWithLongName "
+ "7bWithLongName 8bWithLongName 9bWithLongName 10bWithLongName "
+ "11bWithLongName 12bWithLongName 13bWithLongName 14bWithLongName "
+ "15bWithLongName 16bWithLongName 17bWithLongName 18bWithLongName "
+ "19bWithLongName 20bWithLongName ");
+ model_test_utils::AddNodesFromModelString(model, root, model_string);
+
+ const BookmarkNode* other = model.other_node();
+ const std::string other_string("1other 2other 3other ");
+ model_test_utils::AddNodesFromModelString(model, other, other_string);
+
+ // Validate initial model.
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(model_string, actualModelString);
+ std::string actualOtherString = model_test_utils::ModelStringFromNode(other);
+ EXPECT_EQ(other_string, actualOtherString);
+
+ // Insure that the off-the-side is showing.
+ ASSERT_FALSE([bar_ offTheSideButtonIsHidden]);
+
+ // Remember how many buttons are showing and are available.
+ int oldDisplayedButtons = [bar_ displayedButtonCount];
+ int oldRootCount = root->GetChildCount();
+ int oldOtherCount = other->GetChildCount();
+
+ // Pop up the off-the-side menu.
+ BookmarkButton* otsButton = (BookmarkButton*)[bar_ offTheSideButton];
+ ASSERT_TRUE(otsButton);
+ [[otsButton target] performSelector:@selector(openOffTheSideFolderFromButton:)
+ withObject:otsButton];
+ BookmarkBarFolderController* otsController = [bar_ folderController];
+ EXPECT_TRUE(otsController);
+ int oldOTSCount = (int)[[otsController buttons] count];
+ EXPECT_EQ(oldOTSCount, oldRootCount - oldDisplayedButtons);
+
+ // Pick an off-the-side button and drag it to the other bookmarks.
+ BookmarkButton* draggedButton =
+ [otsController buttonWithTitleEqualTo:@"20bWithLongName"];
+ ASSERT_TRUE(draggedButton);
+ BookmarkButton* targetButton = [bar_ otherBookmarksButton];
+ ASSERT_TRUE(targetButton);
+ [bar_ dragButton:draggedButton to:[targetButton center] copy:NO];
+
+ // There should one less button in the bar, one less in off-the-side,
+ // and one more in other bookmarks.
+ int newRootCount = root->GetChildCount();
+ int newOTSCount = (int)[[otsController buttons] count];
+ int newOtherCount = other->GetChildCount();
+ EXPECT_EQ(oldRootCount - 1, newRootCount);
+ EXPECT_EQ(oldOTSCount - 1, newOTSCount);
+ EXPECT_EQ(oldOtherCount + 1, newOtherCount);
+}
+
+TEST_F(BookmarkBarControllerDragDropTest, DragBookmarkData) {
+ BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
+ "2f3b ] 3b 4b ");
+ model_test_utils::AddNodesFromModelString(model, root, model_string);
+ const BookmarkNode* other = model.other_node();
+ const std::string other_string("O1b O2b O3f:[ O3f1b O3f2f ] "
+ "O4f:[ O4f1b O4f2f ] 05b ");
+ model_test_utils::AddNodesFromModelString(model, other, other_string);
+
+ // Validate initial model.
+ std::string actual = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(model_string, actual);
+ actual = model_test_utils::ModelStringFromNode(other);
+ EXPECT_EQ(other_string, actual);
+
+ // Remember the little ones.
+ int oldChildCount = root->GetChildCount();
+
+ BookmarkButton* targetButton = [bar_ buttonWithTitleEqualTo:@"3b"];
+ ASSERT_TRUE(targetButton);
+
+ // Gen up some dragging data.
+ const BookmarkNode* newNode = other->GetChild(2);
+ [bar_ setDragDataNode:newNode];
+ scoped_nsobject<FakeDragInfo> dragInfo([[FakeDragInfo alloc] init]);
+ [dragInfo setDropLocation:[targetButton center]];
+ [bar_ dragBookmarkData:(id<NSDraggingInfo>)dragInfo.get()];
+
+ // There should one more button in the bar.
+ int newChildCount = root->GetChildCount();
+ EXPECT_EQ(oldChildCount + 1, newChildCount);
+ // Verify the model.
+ const std::string expected("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
+ "2f3b ] O3f:[ O3f1b O3f2f ] 3b 4b ");
+ actual = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(expected, actual);
+ oldChildCount = newChildCount;
+
+ // Now do it over a folder button.
+ targetButton = [bar_ buttonWithTitleEqualTo:@"2f"];
+ ASSERT_TRUE(targetButton);
+ NSPoint targetPoint = [targetButton center];
+ newNode = other->GetChild(2); // Should be O4f.
+ EXPECT_EQ(newNode->GetTitle(), ASCIIToUTF16("O4f"));
+ [bar_ setDragDataNode:newNode];
+ [dragInfo setDropLocation:targetPoint];
+ [bar_ dragBookmarkData:(id<NSDraggingInfo>)dragInfo.get()];
+
+ newChildCount = root->GetChildCount();
+ EXPECT_EQ(oldChildCount, newChildCount);
+ // Verify the model.
+ const std::string expected1("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
+ "2f3b O4f:[ O4f1b O4f2f ] ] O3f:[ O3f1b O3f2f ] "
+ "3b 4b ");
+ actual = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(expected1, actual);
+}
+
+TEST_F(BookmarkBarControllerDragDropTest, AddURLs) {
+ BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
+ "2f3b ] 3b 4b ");
+ model_test_utils::AddNodesFromModelString(model, root, model_string);
+
+ // Validate initial model.
+ std::string actual = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(model_string, actual);
+
+ // Remember the children.
+ int oldChildCount = root->GetChildCount();
+
+ BookmarkButton* targetButton = [bar_ buttonWithTitleEqualTo:@"3b"];
+ ASSERT_TRUE(targetButton);
+
+ NSArray* urls = [NSArray arrayWithObjects: @"http://www.a.com/",
+ @"http://www.b.com/", nil];
+ NSArray* titles = [NSArray arrayWithObjects: @"SiteA", @"SiteB", nil];
+ [bar_ addURLs:urls withTitles:titles at:[targetButton center]];
+
+ // There should two more nodes in the bar.
+ int newChildCount = root->GetChildCount();
+ EXPECT_EQ(oldChildCount + 2, newChildCount);
+ // Verify the model.
+ const std::string expected("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
+ "2f3b ] SiteA SiteB 3b 4b ");
+ actual = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(expected, actual);
+}
+
+TEST_F(BookmarkBarControllerDragDropTest, ControllerForNode) {
+ BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ const std::string model_string("1b 2f:[ 2f1b 2f2b ] 3b ");
+ model_test_utils::AddNodesFromModelString(model, root, model_string);
+
+ // Validate initial model.
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(model_string, actualModelString);
+
+ // Find the main bar controller.
+ const void* expectedController = bar_;
+ const void* actualController = [bar_ controllerForNode:root];
+ EXPECT_EQ(expectedController, actualController);
+}
+
+TEST_F(BookmarkBarControllerDragDropTest, DropPositionIndicator) {
+ BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ const std::string model_string("1b 2f:[ 2f1b 2f2b 2f3b ] 3b 4b ");
+ model_test_utils::AddNodesFromModelString(model, root, model_string);
+
+ // Validate initial model.
+ std::string actualModel = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(model_string, actualModel);
+
+ // Test a series of points starting at the right edge of the bar.
+ BookmarkButton* targetButton = [bar_ buttonWithTitleEqualTo:@"1b"];
+ ASSERT_TRUE(targetButton);
+ NSPoint targetPoint = [targetButton left];
+ const CGFloat xDelta = 0.5 * bookmarks::kBookmarkHorizontalPadding;
+ const CGFloat baseOffset = targetPoint.x;
+ CGFloat expected = xDelta;
+ CGFloat actual = [bar_ indicatorPosForDragToPoint:targetPoint];
+ EXPECT_CGFLOAT_EQ(expected, actual);
+ targetButton = [bar_ buttonWithTitleEqualTo:@"2f"];
+ actual = [bar_ indicatorPosForDragToPoint:[targetButton right]];
+ targetButton = [bar_ buttonWithTitleEqualTo:@"3b"];
+ expected = [targetButton left].x - baseOffset + xDelta;
+ EXPECT_CGFLOAT_EQ(expected, actual);
+ targetButton = [bar_ buttonWithTitleEqualTo:@"4b"];
+ targetPoint = [targetButton right];
+ targetPoint.x += 100; // Somewhere off to the right.
+ expected = NSMaxX([targetButton frame]) + xDelta;
+ actual = [bar_ indicatorPosForDragToPoint:targetPoint];
+ EXPECT_CGFLOAT_EQ(expected, actual);
+}
+
+TEST_F(BookmarkBarControllerDragDropTest, PulseButton) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ const BookmarkNode* root = model->GetBookmarkBarNode();
+ GURL gurl("http://www.google.com");
+ const BookmarkNode* node = model->AddURL(root, root->GetChildCount(),
+ ASCIIToUTF16("title"), gurl);
+
+ BookmarkButton* button = [[bar_ buttons] objectAtIndex:0];
+ EXPECT_FALSE([button isContinuousPulsing]);
+
+ NSValue *value = [NSValue valueWithPointer:node];
+ NSDictionary *dict = [NSDictionary
+ dictionaryWithObjectsAndKeys:value,
+ bookmark_button::kBookmarkKey,
+ [NSNumber numberWithBool:YES],
+ bookmark_button::kBookmarkPulseFlagKey,
+ nil];
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName:bookmark_button::kPulseBookmarkButtonNotification
+ object:nil
+ userInfo:dict];
+ EXPECT_TRUE([button isContinuousPulsing]);
+
+ dict = [NSDictionary dictionaryWithObjectsAndKeys:value,
+ bookmark_button::kBookmarkKey,
+ [NSNumber numberWithBool:NO],
+ bookmark_button::kBookmarkPulseFlagKey,
+ nil];
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName:bookmark_button::kPulseBookmarkButtonNotification
+ object:nil
+ userInfo:dict];
+ EXPECT_FALSE([button isContinuousPulsing]);
+}
+
+TEST_F(BookmarkBarControllerDragDropTest, DragBookmarkDataToTrash) {
+ BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
+ "2f3b ] 3b 4b ");
+ model_test_utils::AddNodesFromModelString(model, root, model_string);
+
+ // Validate initial model.
+ std::string actual = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(model_string, actual);
+
+ int oldChildCount = root->GetChildCount();
+
+ // Drag a button to the trash.
+ BookmarkButton* buttonToDelete = [bar_ buttonWithTitleEqualTo:@"3b"];
+ ASSERT_TRUE(buttonToDelete);
+ EXPECT_TRUE([bar_ canDragBookmarkButtonToTrash:buttonToDelete]);
+ [bar_ didDragBookmarkToTrash:buttonToDelete];
+
+ // There should be one less button in the bar.
+ int newChildCount = root->GetChildCount();
+ EXPECT_EQ(oldChildCount - 1, newChildCount);
+ // Verify the model.
+ const std::string expected("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
+ "2f3b ] 4b ");
+ actual = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(expected, actual);
+
+ // Verify that the other bookmark folder can't be deleted.
+ BookmarkButton *otherButton = [bar_ otherBookmarksButton];
+ EXPECT_FALSE([bar_ canDragBookmarkButtonToTrash:otherButton]);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell.h
new file mode 100644
index 0000000..f599e0a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell.h
@@ -0,0 +1,31 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_FOLDER_BUTTON_CELL_H_
+#define CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_FOLDER_BUTTON_CELL_H_
+#pragma once
+
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h"
+
+class BookmarkNode;
+
+// A button cell that handles drawing/highlighting of buttons in the
+// bookmark bar. This cell forwards mouseEntered/mouseExited events
+// to its control view so that pseudo-menu operations
+// (e.g. hover-over to open) can be implemented.
+@interface BookmarkBarFolderButtonCell : BookmarkButtonCell {
+ @private
+ scoped_nsobject<NSColor> frameColor_;
+}
+
+// Create a button cell which draws without a theme and with a frame
+// color provided by the BrowserThemeProvider defaults.
++ (id)buttonCellForNode:(const BookmarkNode*)node
+ contextMenu:(NSMenu*)contextMenu
+ cellText:(NSString*)cellText
+ cellImage:(NSImage*)cellImage;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_FOLDER_BUTTON_CELL_H_
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell.mm
new file mode 100644
index 0000000..c03500d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell.mm
@@ -0,0 +1,22 @@
+// 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 "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell.h"
+
+@implementation BookmarkBarFolderButtonCell
+
++ (id)buttonCellForNode:(const BookmarkNode*)node
+ contextMenu:(NSMenu*)contextMenu
+ cellText:(NSString*)cellText
+ cellImage:(NSImage*)cellImage {
+ id buttonCell =
+ [[[BookmarkBarFolderButtonCell alloc] initForNode:node
+ contextMenu:contextMenu
+ cellText:cellText
+ cellImage:cellImage]
+ autorelease];
+ return buttonCell;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell_unittest.mm
new file mode 100644
index 0000000..3c20cf7
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell_unittest.mm
@@ -0,0 +1,24 @@
+// 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.
+
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+
+namespace {
+
+class BookmarkBarFolderButtonCellTest : public CocoaTest {
+};
+
+// Basic creation.
+TEST_F(BookmarkBarFolderButtonCellTest, Create) {
+ scoped_nsobject<BookmarkBarFolderButtonCell> cell;
+ cell.reset([[BookmarkBarFolderButtonCell buttonCellForNode:nil
+ contextMenu:nil
+ cellText:nil
+ cellImage:nil] retain]);
+ EXPECT_TRUE(cell);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h
new file mode 100644
index 0000000..083efac
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h
@@ -0,0 +1,182 @@
+// 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 "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
+
+@class BookmarkBarController;
+@class BookmarkBarFolderView;
+@class BookmarkFolderTarget;
+@class BookmarkBarFolderHoverState;
+
+// A controller for the pop-up windows from bookmark folder buttons
+// which look sort of like menus.
+@interface BookmarkBarFolderController :
+ NSWindowController<BookmarkButtonDelegate,
+ BookmarkButtonControllerProtocol> {
+ @private
+ // The button whose click opened us.
+ scoped_nsobject<BookmarkButton> parentButton_;
+
+ // Bookmark bar folder controller chains are torn down in two ways:
+ // 1. Clicking "outside" the folder (see use of
+ // CrApplicationEventHookProtocol in the bookmark bar controller).
+ // 2. Engaging a different folder (via hover over or explicit click).
+ //
+ // In either case, the BookmarkButtonControllerProtocol method
+ // closeAllBookmarkFolders gets called. For bookmark bar folder
+ // controllers, this is passed up the chain so we begin with a top
+ // level "close".
+ // When any bookmark folder window closes, it necessarily tells
+ // subcontroller windows to close (down the chain), and autoreleases
+ // the controller. (Must autorelease since the controller can still
+ // get delegate events such as windowDidClose).
+ //
+ // Bookmark bar folder controllers own their buttons. When doing
+ // drag and drop of a button from one sub-sub-folder to a different
+ // sub-sub-folder, we need to make sure the button's pointers stay
+ // valid until we've dropped (or cancelled). Note that such a drag
+ // causes the source sub-sub-folder (previous parent window) to go
+ // away (windows close, controllers autoreleased) since you're
+ // hovering over a different folder chain for dropping. To keep
+ // things valid (like the button's target, its delegate, the parent
+ // cotroller that we have a pointer to below [below], etc), we heep
+ // strong pointers to our owning controller, so the entire chain
+ // stays owned.
+
+ // Our parent controller, if we are a nested folder, otherwise nil.
+ // Strong to insure the object lives as long as we need it.
+ scoped_nsobject<BookmarkBarFolderController> parentController_;
+
+ // The main bar controller from whence we or a parent sprang.
+ BookmarkBarController* barController_; // WEAK: It owns us.
+
+ // Our buttons. We do not have buttons for nested folders.
+ scoped_nsobject<NSMutableArray> buttons_;
+
+ // The scroll view that contains our main button view (below).
+ IBOutlet NSScrollView* scrollView_;
+
+ // Are we scrollable? If no, the full contents of the folder are
+ // always visible.
+ BOOL scrollable_;
+
+ BOOL scrollUpArrowShown_;
+ BOOL scrollDownArrowShown_;
+
+ // YES if subfolders should grow to the right (the default).
+ // Direction switches if we'd grow off the screen.
+ BOOL subFolderGrowthToRight_;
+
+ // The main view of this window (where the buttons go).
+ IBOutlet BookmarkBarFolderView* mainView_;
+
+ // Weak; we keep track to work around a
+ // setShowsBorderOnlyWhileMouseInside bug.
+ BookmarkButton* buttonThatMouseIsIn_;
+
+ // The context menu for a bookmark button which represents an URL.
+ IBOutlet NSMenu* buttonMenu_;
+
+ // The context menu for a bookmark button which represents a folder.
+ IBOutlet NSMenu* folderMenu_;
+
+ // We model hover state as a state machine with specific allowable
+ // transitions. |hoverState_| is the state of this machine at any
+ // given time.
+ scoped_nsobject<BookmarkBarFolderHoverState> hoverState_;
+
+ // Logic for dealing with a click on a bookmark folder button.
+ scoped_nsobject<BookmarkFolderTarget> folderTarget_;
+
+ // A controller for a pop-up bookmark folder window (custom menu).
+ // We (self) are the parentController_ for our folderController_.
+ // This is not a scoped_nsobject because it owns itself (when its
+ // window closes the controller gets autoreleased).
+ BookmarkBarFolderController* folderController_;
+
+ // Implement basic menu scrolling through this tracking area.
+ scoped_nsobject<NSTrackingArea> scrollTrackingArea_;
+
+ // Timer to continue scrolling as needed. We own the timer but
+ // don't release it when done (we invalidate it).
+ NSTimer* scrollTimer_;
+
+ // Amount to scroll by on each timer fire. Can be + or -.
+ CGFloat verticalScrollDelta_;
+
+ // We need to know the size of the vertical scrolling arrows so we
+ // can obscure/unobscure them.
+ CGFloat verticalScrollArrowHeight_;
+
+ // Set to YES to prevent any node animations. Useful for unit testing so that
+ // incomplete animations do not cause valgrind complaints.
+ BOOL ignoreAnimations_;
+}
+
+// Designated initializer.
+- (id)initWithParentButton:(BookmarkButton*)button
+ parentController:(BookmarkBarFolderController*)parentController
+ barController:(BookmarkBarController*)barController;
+
+// Return the parent button that owns the bookmark folder we represent.
+- (BookmarkButton*)parentButton;
+
+// Offset our folder menu window. This is usually needed in response to a
+// parent folder menu window or the bookmark bar changing position due to
+// the dragging of a bookmark node from the parent into this folder menu.
+- (void)offsetFolderMenuWindow:(NSSize)offset;
+
+// Re-layout the window menu in case some buttons were added or removed,
+// specifically as a result of the bookmark bar changing configuration
+// and altering the contents of the off-the-side folder.
+- (void)reconfigureMenu;
+
+// Actions from a context menu over a button or folder.
+- (IBAction)cutBookmark:(id)sender;
+- (IBAction)copyBookmark:(id)sender;
+- (IBAction)pasteBookmark:(id)sender;
+- (IBAction)deleteBookmark:(id)sender;
+
+// Passed up by a child view to tell us of a desire to scroll.
+- (void)scrollWheel:(NSEvent *)theEvent;
+
+// Forwarded to the associated BookmarkBarController.
+- (IBAction)addFolder:(id)sender;
+- (IBAction)addPage:(id)sender;
+- (IBAction)editBookmark:(id)sender;
+- (IBAction)openBookmark:(id)sender;
+- (IBAction)openAllBookmarks:(id)sender;
+- (IBAction)openAllBookmarksIncognitoWindow:(id)sender;
+- (IBAction)openAllBookmarksNewWindow:(id)sender;
+- (IBAction)openBookmarkInIncognitoWindow:(id)sender;
+- (IBAction)openBookmarkInNewForegroundTab:(id)sender;
+- (IBAction)openBookmarkInNewWindow:(id)sender;
+
+@property (assign, nonatomic) BOOL subFolderGrowthToRight;
+
+@end
+
+@interface BookmarkBarFolderController(TestingAPI)
+- (NSView*)mainView;
+- (NSPoint)windowTopLeftForWidth:(int)windowWidth;
+- (NSArray*)buttons;
+- (BookmarkBarFolderController*)folderController;
+- (id)folderTarget;
+- (void)configureWindowLevel;
+- (void)performOneScroll:(CGFloat)delta;
+- (BookmarkButton*)buttonThatMouseIsIn;
+// Set to YES in order to prevent animations.
+- (void)setIgnoreAnimations:(BOOL)ignore;
+
+// Return YES if we can scroll up or down.
+- (BOOL)canScrollUp;
+- (BOOL)canScrollDown;
+// Return YES if the scrollable_ flag has been set.
+- (BOOL)scrollable;
+
+- (BookmarkButton*)buttonForDroppingOnAtPoint:(NSPoint)point;
+@end
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.mm
new file mode 100644
index 0000000..b86aab9
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.mm
@@ -0,0 +1,1459 @@
+// 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 "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h"
+
+#include "app/mac/nsimage_cache.h"
+#include "base/mac_util.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/bookmarks/bookmark_utils.h"
+#import "chrome/browser/themes/browser_theme_provider.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "chrome/browser/ui/cocoa/event_utils.h"
+
+namespace {
+
+// Frequency of the scrolling timer in seconds.
+const NSTimeInterval kBookmarkBarFolderScrollInterval = 0.1;
+
+// Amount to scroll by per timer fire. We scroll rather slowly; to
+// accomodate we do several at a time.
+const CGFloat kBookmarkBarFolderScrollAmount =
+ 3 * bookmarks::kBookmarkButtonVerticalSpan;
+
+// Amount to scroll for each scroll wheel delta.
+const CGFloat kBookmarkBarFolderScrollWheelAmount =
+ 1 * bookmarks::kBookmarkButtonVerticalSpan;
+
+// When constraining a scrolling bookmark bar folder window to the
+// screen, shrink the "constrain" by this much vertically. Currently
+// this is 0.0 to avoid a problem with tracking areas leaving the
+// window, but should probably be 8.0 or something.
+// TODO(jrg): http://crbug.com/36225
+const CGFloat kScrollWindowVerticalMargin = 0.0;
+
+} // namespace
+
+@interface BookmarkBarFolderController(Private)
+- (void)configureWindow;
+- (void)addOrUpdateScrollTracking;
+- (void)removeScrollTracking;
+- (void)endScroll;
+- (void)addScrollTimerWithDelta:(CGFloat)delta;
+
+// Determine the best button width (which will be the widest button or the
+// maximum allowable button width, whichever is less) and resize all buttons.
+// Return the new width (so that the window can be adjusted, if necessary).
+- (CGFloat)adjustButtonWidths;
+
+// Returns the total menu height needed to display |buttonCount| buttons.
+// Does not do any fancy tricks like trimming the height to fit on the screen.
+- (int)windowHeightForButtonCount:(int)buttonCount;
+
+// Adjust the height and horizontal position of the window such that the
+// scroll arrows are shown as needed and the window appears completely
+// on screen.
+- (void)adjustWindowForHeight:(int)windowHeight;
+
+// Show or hide the scroll arrows at the top/bottom of the window.
+- (void)showOrHideScrollArrows;
+
+// |point| is in the base coordinate system of the destination window;
+// it comes from an id<NSDraggingInfo>. |copy| is YES if a copy is to be
+// made and inserted into the new location while leaving the bookmark in
+// the old location, otherwise move the bookmark by removing from its old
+// location and inserting into the new location.
+- (BOOL)dragBookmark:(const BookmarkNode*)sourceNode
+ to:(NSPoint)point
+ copy:(BOOL)copy;
+
+@end
+
+@interface BookmarkButton (BookmarkBarFolderMenuHighlighting)
+
+// Make the button's border frame always appear when |forceOn| is YES,
+// otherwise only border the button when the mouse is inside the button.
+- (void)forceButtonBorderToStayOnAlways:(BOOL)forceOn;
+
+// On 10.6 event dispatch for an NSButtonCell's
+// showsBorderOnlyWhileMouseInside seems broken if scrolling the
+// view that contains the button. It appears that a mouseExited:
+// gets lost, so the button stays highlit forever. We accomodate
+// here.
+- (void)toggleButtonBorderingWhileMouseInside;
+@end
+
+@implementation BookmarkButton (BookmarkBarFolderMenuHighlighting)
+
+- (void)forceButtonBorderToStayOnAlways:(BOOL)forceOn {
+ [self setShowsBorderOnlyWhileMouseInside:!forceOn];
+ [self setNeedsDisplay];
+}
+
+- (void)toggleButtonBorderingWhileMouseInside {
+ BOOL toggle = [self showsBorderOnlyWhileMouseInside];
+ [self setShowsBorderOnlyWhileMouseInside:!toggle];
+ [self setShowsBorderOnlyWhileMouseInside:toggle];
+}
+
+@end
+
+@implementation BookmarkBarFolderController
+
+@synthesize subFolderGrowthToRight = subFolderGrowthToRight_;
+
+- (id)initWithParentButton:(BookmarkButton*)button
+ parentController:(BookmarkBarFolderController*)parentController
+ barController:(BookmarkBarController*)barController {
+ NSString* nibPath =
+ [mac_util::MainAppBundle() pathForResource:@"BookmarkBarFolderWindow"
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibPath owner:self])) {
+ parentButton_.reset([button retain]);
+
+ // We want the button to remain bordered as part of the menu path.
+ [button forceButtonBorderToStayOnAlways:YES];
+
+ parentController_.reset([parentController retain]);
+ if (!parentController_)
+ [self setSubFolderGrowthToRight:YES];
+ else
+ [self setSubFolderGrowthToRight:[parentController
+ subFolderGrowthToRight]];
+ barController_ = barController; // WEAK
+ buttons_.reset([[NSMutableArray alloc] init]);
+ folderTarget_.reset([[BookmarkFolderTarget alloc] initWithController:self]);
+ NSImage* image = app::mac::GetCachedImageWithName(@"menu_overflow_up.pdf");
+ DCHECK(image);
+ verticalScrollArrowHeight_ = [image size].height;
+ [self configureWindow];
+ hoverState_.reset([[BookmarkBarFolderHoverState alloc] init]);
+ }
+ return self;
+}
+
+- (void)dealloc {
+ // The button is no longer part of the menu path.
+ [parentButton_ forceButtonBorderToStayOnAlways:NO];
+ [parentButton_ setNeedsDisplay];
+
+ [self removeScrollTracking];
+ [self endScroll];
+ [hoverState_ draggingExited];
+
+ // Delegate pattern does not retain; make sure pointers to us are removed.
+ for (BookmarkButton* button in buttons_.get()) {
+ [button setDelegate:nil];
+ [button setTarget:nil];
+ [button setAction:nil];
+ }
+
+ // Note: we don't need to
+ // [NSObject cancelPreviousPerformRequestsWithTarget:self];
+ // Because all of our performSelector: calls use withDelay: which
+ // retains us.
+ [super dealloc];
+}
+
+// Overriden from NSWindowController to call childFolderWillShow: before showing
+// the window.
+- (void)showWindow:(id)sender {
+ [barController_ childFolderWillShow:self];
+ [super showWindow:sender];
+}
+
+- (BookmarkButton*)parentButton {
+ return parentButton_.get();
+}
+
+- (void)offsetFolderMenuWindow:(NSSize)offset {
+ NSWindow* window = [self window];
+ NSRect windowFrame = [window frame];
+ windowFrame.origin.x -= offset.width;
+ windowFrame.origin.y += offset.height; // Yes, in the opposite direction!
+ [window setFrame:windowFrame display:YES];
+ [folderController_ offsetFolderMenuWindow:offset];
+}
+
+- (void)reconfigureMenu {
+ [NSObject cancelPreviousPerformRequestsWithTarget:self];
+ for (BookmarkButton* button in buttons_.get()) {
+ [button setDelegate:nil];
+ [button removeFromSuperview];
+ }
+ [buttons_ removeAllObjects];
+ [self configureWindow];
+}
+
+#pragma mark Private Methods
+
+- (BookmarkButtonCell*)cellForBookmarkNode:(const BookmarkNode*)child {
+ NSImage* image = child ? [barController_ favIconForNode:child] : nil;
+ NSMenu* menu = child ? child->is_folder() ? folderMenu_ : buttonMenu_ : nil;
+ BookmarkBarFolderButtonCell* cell =
+ [BookmarkBarFolderButtonCell buttonCellForNode:child
+ contextMenu:menu
+ cellText:nil
+ cellImage:image];
+ [cell setTag:kStandardButtonTypeWithLimitedClickFeedback];
+ return cell;
+}
+
+// Redirect to our logic shared with BookmarkBarController.
+- (IBAction)openBookmarkFolderFromButton:(id)sender {
+ [folderTarget_ openBookmarkFolderFromButton:sender];
+}
+
+// Create a bookmark button for the given node using frame.
+//
+// If |node| is NULL this is an "(empty)" button.
+// Does NOT add this button to our button list.
+// Returns an autoreleased button.
+// Adjusts the input frame width as appropriate.
+//
+// TODO(jrg): combine with addNodesToButtonList: code from
+// bookmark_bar_controller.mm, and generalize that to use both x and y
+// offsets.
+// http://crbug.com/35966
+- (BookmarkButton*)makeButtonForNode:(const BookmarkNode*)node
+ frame:(NSRect)frame {
+ BookmarkButtonCell* cell = [self cellForBookmarkNode:node];
+ DCHECK(cell);
+
+ // We must decide if we draw the folder arrow before we ask the cell
+ // how big it needs to be.
+ if (node && node->is_folder()) {
+ // Warning when combining code with bookmark_bar_controller.mm:
+ // this call should NOT be made for the bar buttons; only for the
+ // subfolder buttons.
+ [cell setDrawFolderArrow:YES];
+ }
+
+ // The "+2" is needed because, sometimes, Cocoa is off by a tad when
+ // returning the value it thinks it needs.
+ CGFloat desired = [cell cellSize].width + 2;
+ // The width is determined from the maximum of the proposed width
+ // (provided in |frame|) or the natural width of the title, then
+ // limited by the abolute minimum and maximum allowable widths.
+ frame.size.width =
+ std::min(std::max(bookmarks::kBookmarkMenuButtonMinimumWidth,
+ std::max(frame.size.width, desired)),
+ bookmarks::kBookmarkMenuButtonMaximumWidth);
+
+ BookmarkButton* button = [[[BookmarkButton alloc] initWithFrame:frame]
+ autorelease];
+ DCHECK(button);
+
+ [button setCell:cell];
+ [button setDelegate:self];
+ if (node) {
+ if (node->is_folder()) {
+ [button setTarget:self];
+ [button setAction:@selector(openBookmarkFolderFromButton:)];
+ } else {
+ // Make the button do something.
+ [button setTarget:self];
+ [button setAction:@selector(openBookmark:)];
+ // Add a tooltip.
+ NSString* title = base::SysUTF16ToNSString(node->GetTitle());
+ std::string urlString = node->GetURL().possibly_invalid_spec();
+ NSString* tooltip = [NSString stringWithFormat:@"%@\n%s", title,
+ urlString.c_str()];
+ [button setToolTip:tooltip];
+ }
+ } else {
+ [button setEnabled:NO];
+ [button setBordered:NO];
+ }
+ return button;
+}
+
+// Exposed for testing.
+- (NSView*)mainView {
+ return mainView_;
+}
+
+- (id)folderTarget {
+ return folderTarget_.get();
+}
+
+
+// Our parent controller is another BookmarkBarFolderController, so
+// our window is to the right or left of it. We use a little overlap
+// since it looks much more menu-like than with none. If we would
+// grow off the screen, switch growth to the other direction. Growth
+// direction sticks for folder windows which are descendents of us.
+// If we have tried both directions and neither fits, degrade to a
+// default.
+- (CGFloat)childFolderWindowLeftForWidth:(int)windowWidth {
+ // We may legitimately need to try two times (growth to right and
+ // left but not in that order). Limit us to three tries in case
+ // the folder window can't fit on either side of the screen; we
+ // don't want to loop forever.
+ CGFloat x;
+ int tries = 0;
+ while (tries < 2) {
+ // Try to grow right.
+ if ([self subFolderGrowthToRight]) {
+ tries++;
+ x = NSMaxX([[parentButton_ window] frame]) -
+ bookmarks::kBookmarkMenuOverlap;
+ // If off the screen, switch direction.
+ if ((x + windowWidth +
+ bookmarks::kBookmarkHorizontalScreenPadding) >
+ NSMaxX([[[self window] screen] frame])) {
+ [self setSubFolderGrowthToRight:NO];
+ } else {
+ return x;
+ }
+ }
+ // Try to grow left.
+ if (![self subFolderGrowthToRight]) {
+ tries++;
+ x = NSMinX([[parentButton_ window] frame]) +
+ bookmarks::kBookmarkMenuOverlap -
+ windowWidth;
+ // If off the screen, switch direction.
+ if (x < NSMinX([[[self window] screen] frame])) {
+ [self setSubFolderGrowthToRight:YES];
+ } else {
+ return x;
+ }
+ }
+ }
+ // Unhappy; do the best we can.
+ return NSMaxX([[[self window] screen] frame]) - windowWidth;
+}
+
+
+// Compute and return the top left point of our window (screen
+// coordinates). The top left is positioned in a manner similar to
+// cascading menus. Windows may grow to either the right or left of
+// their parent (if a sub-folder) so we need to know |windowWidth|.
+- (NSPoint)windowTopLeftForWidth:(int)windowWidth {
+ NSPoint newWindowTopLeft;
+ if (![parentController_ isKindOfClass:[self class]]) {
+ // If we're not popping up from one of ourselves, we must be
+ // popping up from the bookmark bar itself. In this case, start
+ // BELOW the parent button. Our left is the button left; our top
+ // is bottom of button's parent view.
+ NSPoint buttonBottomLeftInScreen =
+ [[parentButton_ window]
+ convertBaseToScreen:[parentButton_
+ convertPoint:NSZeroPoint toView:nil]];
+ NSPoint bookmarkBarBottomLeftInScreen =
+ [[parentButton_ window]
+ convertBaseToScreen:[[parentButton_ superview]
+ convertPoint:NSZeroPoint toView:nil]];
+ newWindowTopLeft = NSMakePoint(buttonBottomLeftInScreen.x,
+ bookmarkBarBottomLeftInScreen.y);
+ // Make sure the window is on-screen; if not, push left. It is
+ // intentional that top level folders "push left" slightly
+ // different than subfolders.
+ NSRect screenFrame = [[[parentButton_ window] screen] frame];
+ CGFloat spillOff = (newWindowTopLeft.x + windowWidth) - NSMaxX(screenFrame);
+ if (spillOff > 0.0) {
+ newWindowTopLeft.x = std::max(newWindowTopLeft.x - spillOff,
+ NSMinX(screenFrame));
+ }
+ } else {
+ // Parent is a folder; grow right/left.
+ newWindowTopLeft.x = [self childFolderWindowLeftForWidth:windowWidth];
+ NSPoint top = NSMakePoint(0, (NSMaxY([parentButton_ frame]) +
+ bookmarks::kBookmarkVerticalPadding));
+ NSPoint topOfWindow =
+ [[parentButton_ window]
+ convertBaseToScreen:[[parentButton_ superview]
+ convertPoint:top toView:nil]];
+ newWindowTopLeft.y = topOfWindow.y;
+ }
+ return newWindowTopLeft;
+}
+
+// Set our window level to the right spot so we're above the menubar, dock, etc.
+// Factored out so we can override/noop in a unit test.
+- (void)configureWindowLevel {
+ [[self window] setLevel:NSPopUpMenuWindowLevel];
+}
+
+- (int)windowHeightForButtonCount:(int)buttonCount {
+ return (buttonCount * bookmarks::kBookmarkButtonVerticalSpan) +
+ bookmarks::kBookmarkVerticalPadding;
+}
+
+- (void)adjustWindowForHeight:(int)windowHeight {
+ // Adjust all button widths to be consistent, determine the best size for
+ // the window, and set the window frame.
+ CGFloat windowWidth =
+ [self adjustButtonWidths] +
+ (2 * bookmarks::kBookmarkSubMenuHorizontalPadding);
+ NSPoint newWindowTopLeft = [self windowTopLeftForWidth:windowWidth];
+ NSSize windowSize = NSMakeSize(windowWidth, windowHeight);
+ windowSize = [scrollView_ convertSize:windowSize toView:nil];
+ NSWindow* window = [self window];
+ // If the window is already visible then make sure its top remains stable.
+ BOOL windowAlreadyShowing = [window isVisible];
+ CGFloat deltaY = windowHeight - NSHeight([mainView_ frame]);
+ if (windowAlreadyShowing) {
+ NSRect oldFrame = [window frame];
+ newWindowTopLeft.y = oldFrame.origin.y + NSHeight(oldFrame);
+ }
+ NSRect windowFrame = NSMakeRect(newWindowTopLeft.x,
+ newWindowTopLeft.y - windowHeight, windowSize.width, windowHeight);
+ // Make the scrolled content be the right size (full size).
+ NSRect mainViewFrame = NSMakeRect(0, 0, NSWidth(windowFrame) -
+ bookmarks::kScrollViewContentWidthMargin, NSHeight(windowFrame));
+ [mainView_ setFrame:mainViewFrame];
+ // Make sure the window fits on the screen. If not, constrain.
+ // We'll scroll to allow the user to see all the content.
+ NSRect screenFrame = [[[self window] screen] frame];
+ screenFrame = NSInsetRect(screenFrame, 0, kScrollWindowVerticalMargin);
+ BOOL wasScrollable = scrollable_;
+ if (!NSContainsRect(screenFrame, windowFrame)) {
+ scrollable_ = YES;
+ windowFrame = NSIntersectionRect(screenFrame, windowFrame);
+ } else {
+ scrollable_ = NO;
+ }
+ [window setFrame:windowFrame display:NO];
+ if (wasScrollable != scrollable_) {
+ // If scrollability changed then rework visibility of the scroll arrows
+ // and the scroll offset of the menu view.
+ NSSize windowLocalSize =
+ [scrollView_ convertSize:windowFrame.size fromView:nil];
+ CGFloat scrollPointY = NSHeight(mainViewFrame) - windowLocalSize.height +
+ bookmarks::kBookmarkVerticalPadding;
+ [mainView_ scrollPoint:NSMakePoint(0, scrollPointY)];
+ [self showOrHideScrollArrows];
+ [self addOrUpdateScrollTracking];
+ } else if (scrollable_ && windowAlreadyShowing) {
+ // If the window was already showing and is still scrollable then make
+ // sure the main view moves upward, not downward so that the content
+ // at the bottom of the menu, not the top, appears to move.
+ // The edge case is when the menu is scrolled all the way to top (hence
+ // the test of scrollDownArrowShown_) - don't scroll then.
+ NSView* superView = [mainView_ superview];
+ DCHECK([superView isKindOfClass:[NSClipView class]]);
+ NSClipView* clipView = static_cast<NSClipView*>(superView);
+ CGFloat scrollPointY = [clipView bounds].origin.y +
+ bookmarks::kBookmarkVerticalPadding;
+ if (scrollDownArrowShown_ || deltaY > 0.0)
+ scrollPointY += deltaY;
+ [mainView_ scrollPoint:NSMakePoint(0, scrollPointY)];
+ }
+ [window display];
+}
+
+// Determine window size and position.
+// Create buttons for all our nodes.
+// TODO(jrg): break up into more and smaller routines for easier unit testing.
+- (void)configureWindow {
+ const BookmarkNode* node = [parentButton_ bookmarkNode];
+ DCHECK(node);
+ int startingIndex = [[parentButton_ cell] startingChildIndex];
+ DCHECK_LE(startingIndex, node->GetChildCount());
+ // Must have at least 1 button (for "empty")
+ int buttons = std::max(node->GetChildCount() - startingIndex, 1);
+
+ // Prelim height of the window. We'll trim later as needed.
+ int height = [self windowHeightForButtonCount:buttons];
+ // We'll need this soon...
+ [self window];
+
+ // TODO(jrg): combine with frame code in bookmark_bar_controller.mm
+ // http://crbug.com/35966
+ NSRect buttonsOuterFrame = NSMakeRect(
+ bookmarks::kBookmarkSubMenuHorizontalPadding,
+ (height - bookmarks::kBookmarkButtonVerticalSpan),
+ bookmarks::kDefaultBookmarkWidth,
+ bookmarks::kBookmarkButtonHeight);
+
+ // TODO(jrg): combine with addNodesToButtonList: code from
+ // bookmark_bar_controller.mm (but use y offset)
+ // http://crbug.com/35966
+ if (!node->GetChildCount()) {
+ // If no children we are the empty button.
+ BookmarkButton* button = [self makeButtonForNode:nil
+ frame:buttonsOuterFrame];
+ [buttons_ addObject:button];
+ [mainView_ addSubview:button];
+ } else {
+ for (int i = startingIndex;
+ i < node->GetChildCount();
+ i++) {
+ const BookmarkNode* child = node->GetChild(i);
+ BookmarkButton* button = [self makeButtonForNode:child
+ frame:buttonsOuterFrame];
+ [buttons_ addObject:button];
+ [mainView_ addSubview:button];
+ buttonsOuterFrame.origin.y -= bookmarks::kBookmarkButtonVerticalSpan;
+ }
+ }
+
+ [self adjustWindowForHeight:height];
+ // Finally pop me up.
+ [self configureWindowLevel];
+}
+
+// TODO(mrossetti): See if the following can be moved into view's viewWillDraw:.
+- (CGFloat)adjustButtonWidths {
+ CGFloat width = bookmarks::kBookmarkMenuButtonMinimumWidth;
+ // Use the cell's size as the base for determining the desired width of the
+ // button rather than the button's current width. -[cell cellSize] always
+ // returns the 'optimum' size of the cell based on the cell's contents even
+ // if it's less than the current button size. Relying on the button size
+ // would result in buttons that could only get wider but we want to handle
+ // the case where the widest button gets removed from a folder menu.
+ for (BookmarkButton* button in buttons_.get())
+ width = std::max(width, [[button cell] cellSize].width);
+ width = std::min(width, bookmarks::kBookmarkMenuButtonMaximumWidth);
+ // Things look and feel more menu-like if all the buttons are the
+ // full width of the window, especially if there are submenus.
+ for (BookmarkButton* button in buttons_.get()) {
+ NSRect buttonFrame = [button frame];
+ buttonFrame.size.width = width;
+ [button setFrame:buttonFrame];
+ }
+ return width;
+}
+
+- (BOOL)canScrollUp {
+ // If removal of an arrow would make things "finished", state as
+ // such.
+ CGFloat scrollY = [scrollView_ documentVisibleRect].origin.y;
+ if (scrollUpArrowShown_)
+ scrollY -= verticalScrollArrowHeight_;
+
+ if (scrollY <= 0)
+ return NO;
+ return YES;
+}
+
+- (BOOL)canScrollDown {
+ CGFloat arrowAdjustment = 0.0;
+
+ // We do NOT adjust based on the scrollDOWN arrow. This keeps
+ // things from "jumping"; if removal of the down arrow (at the top
+ // of the window) would cause a scroll to end, we'll end.
+ if (scrollUpArrowShown_)
+ arrowAdjustment += verticalScrollArrowHeight_;
+
+ NSPoint scrollPosition = [scrollView_ documentVisibleRect].origin;
+ NSRect documentRect = [[scrollView_ documentView] frame];
+
+ // If we are exactly the right height, return no. We need this
+ // extra conditional in the case where we've just scrolled/grown
+ // into position.
+ if (NSHeight([[self window] frame]) == NSHeight(documentRect))
+ return NO;
+
+ if ((scrollPosition.y + NSHeight([[self window] frame])) >=
+ (NSHeight(documentRect) + arrowAdjustment)) {
+ return NO;
+ }
+ return YES;
+}
+
+- (void)showOrHideScrollArrows {
+ NSRect frame = [scrollView_ frame];
+ CGFloat scrollDelta = 0.0;
+ BOOL canScrollDown = [self canScrollDown];
+ BOOL canScrollUp = [self canScrollUp];
+
+ if (canScrollUp != scrollUpArrowShown_) {
+ if (scrollUpArrowShown_) {
+ frame.origin.y -= verticalScrollArrowHeight_;
+ frame.size.height += verticalScrollArrowHeight_;
+ scrollDelta = verticalScrollArrowHeight_;
+ } else {
+ frame.origin.y += verticalScrollArrowHeight_;
+ frame.size.height -= verticalScrollArrowHeight_;
+ scrollDelta = -verticalScrollArrowHeight_;
+ }
+ }
+ if (canScrollDown != scrollDownArrowShown_) {
+ if (scrollDownArrowShown_) {
+ frame.size.height += verticalScrollArrowHeight_;
+ } else {
+ frame.size.height -= verticalScrollArrowHeight_;
+ }
+ }
+ scrollUpArrowShown_ = canScrollUp;
+ scrollDownArrowShown_ = canScrollDown;
+ [scrollView_ setFrame:frame];
+
+ // Adjust scroll based on new frame. For example, if we make room
+ // for an arrow at the bottom, adjust the scroll so the topmost item
+ // is still fully visible.
+ if (scrollDelta) {
+ NSPoint scrollPosition = [scrollView_ documentVisibleRect].origin;
+ scrollPosition.y -= scrollDelta;
+ [[scrollView_ documentView] scrollPoint:scrollPosition];
+ }
+}
+
+- (BOOL)scrollable {
+ return scrollable_;
+}
+
+// Start a "scroll up" timer.
+- (void)beginScrollWindowUp {
+ [self addScrollTimerWithDelta:kBookmarkBarFolderScrollAmount];
+}
+
+// Start a "scroll down" timer.
+- (void)beginScrollWindowDown {
+ [self addScrollTimerWithDelta:-kBookmarkBarFolderScrollAmount];
+}
+
+// End a scrolling timer. Can be called excessively with no harm.
+- (void)endScroll {
+ if (scrollTimer_) {
+ [scrollTimer_ invalidate];
+ scrollTimer_ = nil;
+ verticalScrollDelta_ = 0;
+ }
+}
+
+// Perform a single scroll of the specified amount.
+// Scroll up:
+// Scroll the documentView by the growth amount.
+// If we cannot grow the window, simply scroll the documentView.
+// If we can grow the window up without falling off the screen, do it.
+// Scroll down:
+// Never change the window size; only scroll the documentView.
+- (void)performOneScroll:(CGFloat)delta {
+ NSRect windowFrame = [[self window] frame];
+ NSRect screenFrame = [[[self window] screen] frame];
+
+ // First scroll the "document" area.
+ NSPoint scrollPosition = [scrollView_ documentVisibleRect].origin;
+ scrollPosition.y -= delta;
+ [[scrollView_ documentView] scrollPoint:scrollPosition];
+
+ if (buttonThatMouseIsIn_)
+ [buttonThatMouseIsIn_ toggleButtonBorderingWhileMouseInside];
+
+ // We update the window size after shifting the scroll to avoid a race.
+ CGFloat screenHeightMinusMargin = (NSHeight(screenFrame) -
+ (2 * kScrollWindowVerticalMargin));
+ if (delta) {
+ // If we can, grow the window (up).
+ if (NSHeight(windowFrame) < screenHeightMinusMargin) {
+ CGFloat growAmount = delta;
+ // Don't scroll more than enough to "finish".
+ if (scrollPosition.y < 0)
+ growAmount += scrollPosition.y;
+ windowFrame.size.height += growAmount;
+ windowFrame.size.height = std::min(NSHeight(windowFrame),
+ screenHeightMinusMargin);
+ // Watch out for a finish that isn't the full height of the screen.
+ // We get here if using the scroll wheel to scroll by small amounts.
+ windowFrame.size.height = std::min(NSHeight(windowFrame),
+ NSHeight([mainView_ frame]));
+ // Don't allow scrolling to make the window smaller, ever. This
+ // conditional is important when processing scrollWheel events.
+ if (windowFrame.size.height > [[self window] frame].size.height) {
+ [[self window] setFrame:windowFrame display:YES];
+ [self addOrUpdateScrollTracking];
+ }
+ }
+ }
+
+ // If we're at either end, happiness.
+ if ((scrollPosition.y <= 0) ||
+ ((scrollPosition.y + NSHeight(windowFrame) >=
+ NSHeight([mainView_ frame])) &&
+ (windowFrame.size.height == screenHeightMinusMargin))) {
+ [self endScroll];
+
+ // If we can't scroll either up or down we are completely done.
+ // For example, perhaps we've scrolled a little and grown the
+ // window on-screen until there is now room for everything.
+ if (![self canScrollUp] && ![self canScrollDown]) {
+ scrollable_ = NO;
+ [self removeScrollTracking];
+ }
+ }
+
+ [self showOrHideScrollArrows];
+}
+
+// Perform a scroll of the window on the screen.
+// Called by a timer when scrolling.
+- (void)performScroll:(NSTimer*)timer {
+ DCHECK(verticalScrollDelta_);
+ [self performOneScroll:verticalScrollDelta_];
+}
+
+
+// Add a timer to fire at a regular interveral which scrolls the
+// window vertically |delta|.
+- (void)addScrollTimerWithDelta:(CGFloat)delta {
+ if (scrollTimer_ && verticalScrollDelta_ == delta)
+ return;
+ [self endScroll];
+ verticalScrollDelta_ = delta;
+ scrollTimer_ =
+ [NSTimer scheduledTimerWithTimeInterval:kBookmarkBarFolderScrollInterval
+ target:self
+ selector:@selector(performScroll:)
+ userInfo:nil
+ repeats:YES];
+}
+
+// Called as a result of our tracking area. Warning: on the main
+// screen (of a single-screened machine), the minimum mouse y value is
+// 1, not 0. Also, we do not get events when the mouse is above the
+// menubar (to be fixed by setting the proper window level; see
+// initializer).
+- (void)mouseMoved:(NSEvent*)theEvent {
+ DCHECK([theEvent window] == [self window]);
+
+ NSPoint eventScreenLocation =
+ [[theEvent window] convertBaseToScreen:[theEvent locationInWindow]];
+
+ // We use frame (not visibleFrame) since our bookmark folder is on
+ // TOP of the menubar.
+ NSRect visibleRect = [[[self window] screen] frame];
+ CGFloat closeToTopOfScreen = NSMaxY(visibleRect) -
+ verticalScrollArrowHeight_;
+ CGFloat closeToBottomOfScreen = NSMinY(visibleRect) +
+ verticalScrollArrowHeight_;
+
+ if (eventScreenLocation.y <= closeToBottomOfScreen) {
+ [self beginScrollWindowUp];
+ } else if (eventScreenLocation.y > closeToTopOfScreen) {
+ [self beginScrollWindowDown];
+ } else {
+ [self endScroll];
+ }
+}
+
+- (void)mouseExited:(NSEvent*)theEvent {
+ [self endScroll];
+}
+
+// Add a tracking area so we know when the mouse is pinned to the top
+// or bottom of the screen. If that happens, and if the mouse
+// position overlaps the window, scroll it.
+- (void)addOrUpdateScrollTracking {
+ [self removeScrollTracking];
+ NSView* view = [[self window] contentView];
+ scrollTrackingArea_.reset([[NSTrackingArea alloc]
+ initWithRect:[view bounds]
+ options:(NSTrackingMouseMoved |
+ NSTrackingMouseEnteredAndExited |
+ NSTrackingActiveAlways)
+ owner:self
+ userInfo:nil]);
+ [view addTrackingArea:scrollTrackingArea_];
+}
+
+// Remove the tracking area associated with scrolling.
+- (void)removeScrollTracking {
+ if (scrollTrackingArea_.get()) {
+ [[[self window] contentView] removeTrackingArea:scrollTrackingArea_];
+ }
+ scrollTrackingArea_.reset();
+}
+
+// Delegate callback.
+- (void)windowWillClose:(NSNotification*)notification {
+ // If a "hover open" is pending when the bookmark bar folder is
+ // closed, be sure it gets cancelled.
+ [NSObject cancelPreviousPerformRequestsWithTarget:self];
+
+ [barController_ childFolderWillClose:self];
+ [self closeBookmarkFolder:self];
+ [self autorelease];
+}
+
+// Close the old hover-open bookmark folder, and open a new one. We
+// do both in one step to allow for a delay in closing the old one.
+// See comments above kDragHoverCloseDelay (bookmark_bar_controller.h)
+// for more details.
+- (void)openBookmarkFolderFromButtonAndCloseOldOne:(id)sender {
+ // If an old submenu exists, close it immediately.
+ [self closeBookmarkFolder:sender];
+
+ // Open a new one if meaningful.
+ if ([sender isFolder])
+ [folderTarget_ openBookmarkFolderFromButton:sender];
+}
+
+- (NSArray*)buttons {
+ return buttons_.get();
+}
+
+- (void)close {
+ [folderController_ close];
+ [super close];
+}
+
+- (void)scrollWheel:(NSEvent *)theEvent {
+ if (scrollable_) {
+ // We go negative since an NSScrollView has a flipped coordinate frame.
+ CGFloat amt = kBookmarkBarFolderScrollWheelAmount * -[theEvent deltaY];
+ [self performOneScroll:amt];
+ }
+}
+
+#pragma mark Actions Forwarded to Parent BookmarkBarController
+
+- (IBAction)openBookmark:(id)sender {
+ [barController_ openBookmark:sender];
+}
+
+- (IBAction)openBookmarkInNewForegroundTab:(id)sender {
+ [barController_ openBookmarkInNewForegroundTab:sender];
+}
+
+- (IBAction)openBookmarkInNewWindow:(id)sender {
+ [barController_ openBookmarkInNewWindow:sender];
+}
+
+- (IBAction)openBookmarkInIncognitoWindow:(id)sender {
+ [barController_ openBookmarkInIncognitoWindow:sender];
+}
+
+- (IBAction)editBookmark:(id)sender {
+ [barController_ editBookmark:sender];
+}
+
+- (IBAction)cutBookmark:(id)sender {
+ [self closeBookmarkFolder:self];
+ [barController_ cutBookmark:sender];
+}
+
+- (IBAction)copyBookmark:(id)sender {
+ [barController_ copyBookmark:sender];
+}
+
+- (IBAction)pasteBookmark:(id)sender {
+ [barController_ pasteBookmark:sender];
+}
+
+- (IBAction)deleteBookmark:(id)sender {
+ [self closeBookmarkFolder:self];
+ [barController_ deleteBookmark:sender];
+}
+
+- (IBAction)openAllBookmarks:(id)sender {
+ [barController_ openAllBookmarks:sender];
+}
+
+- (IBAction)openAllBookmarksNewWindow:(id)sender {
+ [barController_ openAllBookmarksNewWindow:sender];
+}
+
+- (IBAction)openAllBookmarksIncognitoWindow:(id)sender {
+ [barController_ openAllBookmarksIncognitoWindow:sender];
+}
+
+- (IBAction)addPage:(id)sender {
+ [barController_ addPage:sender];
+}
+
+- (IBAction)addFolder:(id)sender {
+ [barController_ addFolder:sender];
+}
+
+#pragma mark Drag & Drop
+
+// Find something like std::is_between<T>? I can't believe one doesn't exist.
+// http://crbug.com/35966
+static BOOL ValueInRangeInclusive(CGFloat low, CGFloat value, CGFloat high) {
+ return ((value >= low) && (value <= high));
+}
+
+// Return the proposed drop target for a hover open button, or nil if none.
+//
+// TODO(jrg): this is just like the version in
+// bookmark_bar_controller.mm, but vertical instead of horizontal.
+// Generalize to be axis independent then share code.
+// http://crbug.com/35966
+- (BookmarkButton*)buttonForDroppingOnAtPoint:(NSPoint)point {
+ for (BookmarkButton* button in buttons_.get()) {
+ // No early break -- makes no assumption about button ordering.
+
+ // Intentionally NOT using NSPointInRect() so that scrolling into
+ // a submenu doesn't cause it to be closed.
+ if (ValueInRangeInclusive(NSMinY([button frame]),
+ point.y,
+ NSMaxY([button frame]))) {
+
+ // Over a button but let's be a little more specific
+ // (e.g. over the middle half).
+ NSRect frame = [button frame];
+ NSRect middleHalfOfButton = NSInsetRect(frame, 0, frame.size.height / 4);
+ if (ValueInRangeInclusive(NSMinY(middleHalfOfButton),
+ point.y,
+ NSMaxY(middleHalfOfButton))) {
+ // It makes no sense to drop on a non-folder; there is no hover.
+ if (![button isFolder])
+ return nil;
+ // Got it!
+ return button;
+ } else {
+ // Over a button but not over the middle half.
+ return nil;
+ }
+ }
+ }
+ // Not hovering over a button.
+ return nil;
+}
+
+// TODO(jrg): again we have code dup, sort of, with
+// bookmark_bar_controller.mm, but the axis is changed. One minor
+// difference is accomodation for the "empty" button (which may not
+// exist in the future).
+// http://crbug.com/35966
+- (int)indexForDragToPoint:(NSPoint)point {
+ // Identify which buttons we are between. For now, assume a button
+ // location is at the center point of its view, and that an exact
+ // match means "place before".
+ // TODO(jrg): revisit position info based on UI team feedback.
+ // dropLocation is in bar local coordinates.
+ // http://crbug.com/36276
+ NSPoint dropLocation =
+ [mainView_ convertPoint:point
+ fromView:[[self window] contentView]];
+ BookmarkButton* buttonToTheTopOfDraggedButton = nil;
+ // Buttons are laid out in this array from top to bottom (screen
+ // wise), which means "biggest y" --> "smallest y".
+ for (BookmarkButton* button in buttons_.get()) {
+ CGFloat midpoint = NSMidY([button frame]);
+ if (dropLocation.y > midpoint) {
+ break;
+ }
+ buttonToTheTopOfDraggedButton = button;
+ }
+
+ // TODO(jrg): On Windows, dropping onto (empty) highlights the
+ // entire drop location and does not use an insertion point.
+ // http://crbug.com/35967
+ if (!buttonToTheTopOfDraggedButton) {
+ // We are at the very top (we broke out of the loop on the first try).
+ return 0;
+ }
+ if ([buttonToTheTopOfDraggedButton isEmpty]) {
+ // There is a button but it's an empty placeholder.
+ // Default to inserting on top of it.
+ return 0;
+ }
+ const BookmarkNode* beforeNode = [buttonToTheTopOfDraggedButton
+ bookmarkNode];
+ DCHECK(beforeNode);
+ // Be careful if the number of buttons != number of nodes.
+ return ((beforeNode->GetParent()->IndexOfChild(beforeNode) + 1) -
+ [[parentButton_ cell] startingChildIndex]);
+}
+
+// TODO(jrg): Yet more code dup.
+// http://crbug.com/35966
+- (BOOL)dragBookmark:(const BookmarkNode*)sourceNode
+ to:(NSPoint)point
+ copy:(BOOL)copy {
+ DCHECK(sourceNode);
+
+ // Drop destination.
+ const BookmarkNode* destParent = NULL;
+ int destIndex = 0;
+
+ // First check if we're dropping on a button. If we have one, and
+ // it's a folder, drop in it.
+ BookmarkButton* button = [self buttonForDroppingOnAtPoint:point];
+ if ([button isFolder]) {
+ destParent = [button bookmarkNode];
+ // Drop it at the end.
+ destIndex = [button bookmarkNode]->GetChildCount();
+ } else {
+ // Else we're dropping somewhere in the folder, so find the right spot.
+ destParent = [parentButton_ bookmarkNode];
+ destIndex = [self indexForDragToPoint:point];
+ // Be careful if the number of buttons != number of nodes.
+ destIndex += [[parentButton_ cell] startingChildIndex];
+ }
+
+ // Prevent cycles.
+ BOOL wasCopiedOrMoved = NO;
+ if (!destParent->HasAncestor(sourceNode)) {
+ if (copy)
+ [self bookmarkModel]->Copy(sourceNode, destParent, destIndex);
+ else
+ [self bookmarkModel]->Move(sourceNode, destParent, destIndex);
+ wasCopiedOrMoved = YES;
+ // Movement of a node triggers observers (like us) to rebuild the
+ // bar so we don't have to do so explicitly.
+ }
+
+ return wasCopiedOrMoved;
+}
+
+#pragma mark BookmarkButtonDelegate Protocol
+
+- (void)fillPasteboard:(NSPasteboard*)pboard
+ forDragOfButton:(BookmarkButton*)button {
+ [[self folderTarget] fillPasteboard:pboard forDragOfButton:button];
+
+ // Close our folder menu and submenus since we know we're going to be dragged.
+ [self closeBookmarkFolder:self];
+}
+
+// Called from BookmarkButton.
+// Unlike bookmark_bar_controller's version, we DO default to being enabled.
+- (void)mouseEnteredButton:(id)sender event:(NSEvent*)event {
+ buttonThatMouseIsIn_ = sender;
+
+ // Cancel a previous hover if needed.
+ [NSObject cancelPreviousPerformRequestsWithTarget:self];
+
+ // If already opened, then we exited but re-entered the button
+ // (without entering another button open), do nothing.
+ if ([folderController_ parentButton] == sender)
+ return;
+
+ [self performSelector:@selector(openBookmarkFolderFromButtonAndCloseOldOne:)
+ withObject:sender
+ afterDelay:bookmarks::kHoverOpenDelay];
+}
+
+// Called from the BookmarkButton
+- (void)mouseExitedButton:(id)sender event:(NSEvent*)event {
+ if (buttonThatMouseIsIn_ == sender)
+ buttonThatMouseIsIn_ = nil;
+
+ // Stop any timer about opening a new hover-open folder.
+
+ // Since a performSelector:withDelay: on self retains self, it is
+ // possible that a cancelPreviousPerformRequestsWithTarget: reduces
+ // the refcount to 0, releasing us. That's a bad thing to do while
+ // this object (or others it may own) is in the event chain. Thus
+ // we have a retain/autorelease.
+ [self retain];
+ [NSObject cancelPreviousPerformRequestsWithTarget:self];
+ [self autorelease];
+}
+
+- (NSWindow*)browserWindow {
+ return [parentController_ browserWindow];
+}
+
+- (BOOL)canDragBookmarkButtonToTrash:(BookmarkButton*)button {
+ return [barController_ canEditBookmark:[button bookmarkNode]];
+}
+
+- (void)didDragBookmarkToTrash:(BookmarkButton*)button {
+ // TODO(mrossetti): Refactor BookmarkBarFolder common code.
+ // http://crbug.com/35966
+ const BookmarkNode* node = [button bookmarkNode];
+ if (node) {
+ const BookmarkNode* parent = node->GetParent();
+ [self bookmarkModel]->Remove(parent,
+ parent->IndexOfChild(node));
+ }
+}
+
+#pragma mark BookmarkButtonControllerProtocol
+
+// Recursively close all bookmark folders.
+- (void)closeAllBookmarkFolders {
+ // Closing the top level implicitly closes all children.
+ [barController_ closeAllBookmarkFolders];
+}
+
+// Close our bookmark folder (a sub-controller) if we have one.
+- (void)closeBookmarkFolder:(id)sender {
+ if (folderController_) {
+ [self setSubFolderGrowthToRight:YES];
+ [[folderController_ window] close];
+ folderController_ = nil;
+ }
+}
+
+- (BookmarkModel*)bookmarkModel {
+ return [barController_ bookmarkModel];
+}
+
+// TODO(jrg): Refactor BookmarkBarFolder common code. http://crbug.com/35966
+// Most of the work (e.g. drop indicator) is taken care of in the
+// folder_view. Here we handle hover open issues for subfolders.
+// Caution: there are subtle differences between this one and
+// bookmark_bar_controller.mm's version.
+- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info {
+ NSPoint currentLocation = [info draggingLocation];
+ BookmarkButton* button = [self buttonForDroppingOnAtPoint:currentLocation];
+
+ // Don't allow drops that would result in cycles.
+ if (button) {
+ NSData* data = [[info draggingPasteboard]
+ dataForType:kBookmarkButtonDragType];
+ if (data && [info draggingSource]) {
+ BookmarkButton* sourceButton = nil;
+ [data getBytes:&sourceButton length:sizeof(sourceButton)];
+ const BookmarkNode* sourceNode = [sourceButton bookmarkNode];
+ const BookmarkNode* destNode = [button bookmarkNode];
+ if (destNode->HasAncestor(sourceNode))
+ button = nil;
+ }
+ }
+ // Delegate handling of dragging over a button to the |hoverState_| member.
+ return [hoverState_ draggingEnteredButton:button];
+}
+
+// Unlike bookmark_bar_controller, we need to keep track of dragging state.
+// We also need to make sure we cancel the delayed hover close.
+- (void)draggingExited:(id<NSDraggingInfo>)info {
+ // NOT the same as a cancel --> we may have moved the mouse into the submenu.
+ // Delegate handling of the hover button to the |hoverState_| member.
+ [hoverState_ draggingExited];
+}
+
+- (BOOL)dragShouldLockBarVisibility {
+ return [parentController_ dragShouldLockBarVisibility];
+}
+
+// TODO(jrg): ARGH more code dup.
+// http://crbug.com/35966
+- (BOOL)dragButton:(BookmarkButton*)sourceButton
+ to:(NSPoint)point
+ copy:(BOOL)copy {
+ DCHECK([sourceButton isKindOfClass:[BookmarkButton class]]);
+ const BookmarkNode* sourceNode = [sourceButton bookmarkNode];
+ return [self dragBookmark:sourceNode to:point copy:copy];
+}
+
+// TODO(mrossetti,jrg): Identical to the same function in BookmarkBarController.
+// http://crbug.com/35966
+- (BOOL)dragBookmarkData:(id<NSDraggingInfo>)info {
+ BOOL dragged = NO;
+ std::vector<const BookmarkNode*> nodes([self retrieveBookmarkNodeData]);
+ if (nodes.size()) {
+ BOOL copy = !([info draggingSourceOperationMask] & NSDragOperationMove);
+ NSPoint dropPoint = [info draggingLocation];
+ for (std::vector<const BookmarkNode*>::const_iterator it = nodes.begin();
+ it != nodes.end(); ++it) {
+ const BookmarkNode* sourceNode = *it;
+ dragged = [self dragBookmark:sourceNode to:dropPoint copy:copy];
+ }
+ }
+ return dragged;
+}
+
+// TODO(mrossetti,jrg): Identical to the same function in BookmarkBarController.
+// http://crbug.com/35966
+- (std::vector<const BookmarkNode*>)retrieveBookmarkNodeData {
+ std::vector<const BookmarkNode*> dragDataNodes;
+ BookmarkNodeData dragData;
+ if(dragData.ReadFromDragClipboard()) {
+ BookmarkModel* bookmarkModel = [self bookmarkModel];
+ Profile* profile = bookmarkModel->profile();
+ std::vector<const BookmarkNode*> nodes(dragData.GetNodes(profile));
+ dragDataNodes.assign(nodes.begin(), nodes.end());
+ }
+ return dragDataNodes;
+}
+
+// Return YES if we should show the drop indicator, else NO.
+// TODO(jrg): ARGH code dup!
+// http://crbug.com/35966
+- (BOOL)shouldShowIndicatorShownForPoint:(NSPoint)point {
+ return ![self buttonForDroppingOnAtPoint:point];
+}
+
+// Return the y position for a drop indicator.
+//
+// TODO(jrg): again we have code dup, sort of, with
+// bookmark_bar_controller.mm, but the axis is changed.
+// http://crbug.com/35966
+- (CGFloat)indicatorPosForDragToPoint:(NSPoint)point {
+ CGFloat y = 0;
+ int destIndex = [self indexForDragToPoint:point];
+ int numButtons = static_cast<int>([buttons_ count]);
+
+ // If it's a drop strictly between existing buttons or at the very beginning
+ if (destIndex >= 0 && destIndex < numButtons) {
+ // ... put the indicator right between the buttons.
+ BookmarkButton* button =
+ [buttons_ objectAtIndex:static_cast<NSUInteger>(destIndex)];
+ DCHECK(button);
+ NSRect buttonFrame = [button frame];
+ y = NSMaxY(buttonFrame) + 0.5 * bookmarks::kBookmarkVerticalPadding;
+
+ // If it's a drop at the end (past the last button, if there are any) ...
+ } else if (destIndex == numButtons) {
+ // and if it's past the last button ...
+ if (numButtons > 0) {
+ // ... find the last button, and put the indicator below it.
+ BookmarkButton* button =
+ [buttons_ objectAtIndex:static_cast<NSUInteger>(destIndex - 1)];
+ DCHECK(button);
+ NSRect buttonFrame = [button frame];
+ y = buttonFrame.origin.y - 0.5 * bookmarks::kBookmarkVerticalPadding;
+
+ }
+ } else {
+ NOTREACHED();
+ }
+
+ return y;
+}
+
+- (ThemeProvider*)themeProvider {
+ return [parentController_ themeProvider];
+}
+
+- (void)childFolderWillShow:(id<BookmarkButtonControllerProtocol>)child {
+ // Do nothing.
+}
+
+- (void)childFolderWillClose:(id<BookmarkButtonControllerProtocol>)child {
+ // Do nothing.
+}
+
+- (BookmarkBarFolderController*)folderController {
+ return folderController_;
+}
+
+// Add a new folder controller as triggered by the given folder button.
+- (void)addNewFolderControllerWithParentButton:(BookmarkButton*)parentButton {
+ if (folderController_)
+ [self closeBookmarkFolder:self];
+
+ // Folder controller, like many window controllers, owns itself.
+ folderController_ =
+ [[BookmarkBarFolderController alloc] initWithParentButton:parentButton
+ parentController:self
+ barController:barController_];
+ [folderController_ showWindow:self];
+}
+
+- (void)openAll:(const BookmarkNode*)node
+ disposition:(WindowOpenDisposition)disposition {
+ [barController_ openAll:node disposition:disposition];
+}
+
+- (void)addButtonForNode:(const BookmarkNode*)node
+ atIndex:(NSInteger)buttonIndex {
+ // Propose the frame for the new button. By default, this will be set to the
+ // topmost button's frame (and there will always be one) offset upward in
+ // anticipation of insertion.
+ NSRect newButtonFrame = [[buttons_ objectAtIndex:0] frame];
+ newButtonFrame.origin.y += bookmarks::kBookmarkButtonVerticalSpan;
+ // When adding a button to an empty folder we must remove the 'empty'
+ // placeholder button. This can be detected by checking for a parent
+ // child count of 1.
+ const BookmarkNode* parentNode = node->GetParent();
+ if (parentNode->GetChildCount() == 1) {
+ BookmarkButton* emptyButton = [buttons_ lastObject];
+ newButtonFrame = [emptyButton frame];
+ [emptyButton setDelegate:nil];
+ [emptyButton removeFromSuperview];
+ [buttons_ removeLastObject];
+ }
+
+ if (buttonIndex == -1 || buttonIndex > (NSInteger)[buttons_ count])
+ buttonIndex = [buttons_ count];
+
+ // Offset upward by one button height all buttons above insertion location.
+ BookmarkButton* button = nil; // Remember so it can be de-highlighted.
+ for (NSInteger i = 0; i < buttonIndex; ++i) {
+ button = [buttons_ objectAtIndex:i];
+ // Remember this location in case it's the last button being moved
+ // which is where the new button will be located.
+ newButtonFrame = [button frame];
+ NSRect buttonFrame = [button frame];
+ buttonFrame.origin.y += bookmarks::kBookmarkButtonVerticalSpan;
+ [button setFrame:buttonFrame];
+ }
+ [[button cell] mouseExited:nil]; // De-highlight.
+ BookmarkButton* newButton = [self makeButtonForNode:node
+ frame:newButtonFrame];
+ [buttons_ insertObject:newButton atIndex:buttonIndex];
+ [mainView_ addSubview:newButton];
+
+ // Close any child folder(s) which may still be open.
+ [self closeBookmarkFolder:self];
+
+ // Prelim height of the window. We'll trim later as needed.
+ int height = [self windowHeightForButtonCount:[buttons_ count]];
+ [self adjustWindowForHeight:height];
+}
+
+// More code which essentially duplicates that of BookmarkBarController.
+// TODO(mrossetti,jrg): http://crbug.com/35966
+- (BOOL)addURLs:(NSArray*)urls withTitles:(NSArray*)titles at:(NSPoint)point {
+ DCHECK([urls count] == [titles count]);
+ BOOL nodesWereAdded = NO;
+ // Figure out where these new bookmarks nodes are to be added.
+ BookmarkButton* button = [self buttonForDroppingOnAtPoint:point];
+ BookmarkModel* bookmarkModel = [self bookmarkModel];
+ const BookmarkNode* destParent = NULL;
+ int destIndex = 0;
+ if ([button isFolder]) {
+ destParent = [button bookmarkNode];
+ // Drop it at the end.
+ destIndex = [button bookmarkNode]->GetChildCount();
+ } else {
+ // Else we're dropping somewhere in the folder, so find the right spot.
+ destParent = [parentButton_ bookmarkNode];
+ destIndex = [self indexForDragToPoint:point];
+ // Be careful if the number of buttons != number of nodes.
+ destIndex += [[parentButton_ cell] startingChildIndex];
+ }
+
+ // Create and add the new bookmark nodes.
+ size_t urlCount = [urls count];
+ for (size_t i = 0; i < urlCount; ++i) {
+ GURL gurl;
+ const char* string = [[urls objectAtIndex:i] UTF8String];
+ if (string)
+ gurl = GURL(string);
+ // We only expect to receive valid URLs.
+ DCHECK(gurl.is_valid());
+ if (gurl.is_valid()) {
+ bookmarkModel->AddURL(destParent,
+ destIndex++,
+ base::SysNSStringToUTF16([titles objectAtIndex:i]),
+ gurl);
+ nodesWereAdded = YES;
+ }
+ }
+ return nodesWereAdded;
+}
+
+- (void)moveButtonFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex {
+ if (fromIndex != toIndex) {
+ if (toIndex == -1)
+ toIndex = [buttons_ count];
+ BookmarkButton* movedButton = [buttons_ objectAtIndex:fromIndex];
+ [buttons_ removeObjectAtIndex:fromIndex];
+ NSRect movedFrame = [movedButton frame];
+ NSPoint toOrigin = movedFrame.origin;
+ [movedButton setHidden:YES];
+ if (fromIndex < toIndex) {
+ BookmarkButton* targetButton = [buttons_ objectAtIndex:toIndex - 1];
+ toOrigin = [targetButton frame].origin;
+ for (NSInteger i = fromIndex; i < toIndex; ++i) {
+ BookmarkButton* button = [buttons_ objectAtIndex:i];
+ NSRect frame = [button frame];
+ frame.origin.y += bookmarks::kBookmarkButtonVerticalSpan;
+ [button setFrameOrigin:frame.origin];
+ }
+ } else {
+ BookmarkButton* targetButton = [buttons_ objectAtIndex:toIndex];
+ toOrigin = [targetButton frame].origin;
+ for (NSInteger i = fromIndex - 1; i >= toIndex; --i) {
+ BookmarkButton* button = [buttons_ objectAtIndex:i];
+ NSRect buttonFrame = [button frame];
+ buttonFrame.origin.y -= bookmarks::kBookmarkButtonVerticalSpan;
+ [button setFrameOrigin:buttonFrame.origin];
+ }
+ }
+ [buttons_ insertObject:movedButton atIndex:toIndex];
+ [movedButton setFrameOrigin:toOrigin];
+ [movedButton setHidden:NO];
+ }
+}
+
+// TODO(jrg): Refactor BookmarkBarFolder common code. http://crbug.com/35966
+- (void)removeButton:(NSInteger)buttonIndex animate:(BOOL)animate {
+ // TODO(mrossetti): Get disappearing animation to work. http://crbug.com/42360
+ BookmarkButton* oldButton = [buttons_ objectAtIndex:buttonIndex];
+ NSPoint poofPoint = [oldButton screenLocationForRemoveAnimation];
+
+ // If a hover-open is pending, cancel it.
+ if (oldButton == buttonThatMouseIsIn_) {
+ [NSObject cancelPreviousPerformRequestsWithTarget:self];
+ buttonThatMouseIsIn_ = nil;
+ }
+
+ // Deleting a button causes rearrangement that enables us to lose a
+ // mouse-exited event. This problem doesn't appear to exist with
+ // other keep-menu-open options (e.g. add folder). Since the
+ // showsBorderOnlyWhileMouseInside uses a tracking area, simple
+ // tricks (e.g. sending an extra mouseExited: to the button) don't
+ // fix the problem.
+ // http://crbug.com/54324
+ for (NSButton* button in buttons_.get()) {
+ if ([button showsBorderOnlyWhileMouseInside]) {
+ [button setShowsBorderOnlyWhileMouseInside:NO];
+ [button setShowsBorderOnlyWhileMouseInside:YES];
+ }
+ }
+
+ [oldButton setDelegate:nil];
+ [oldButton removeFromSuperview];
+ if (animate && !ignoreAnimations_)
+ NSShowAnimationEffect(NSAnimationEffectDisappearingItemDefault, poofPoint,
+ NSZeroSize, nil, nil, nil);
+ [buttons_ removeObjectAtIndex:buttonIndex];
+ for (NSInteger i = 0; i < buttonIndex; ++i) {
+ BookmarkButton* button = [buttons_ objectAtIndex:i];
+ NSRect buttonFrame = [button frame];
+ buttonFrame.origin.y -= bookmarks::kBookmarkButtonVerticalSpan;
+ [button setFrame:buttonFrame];
+ }
+ // Search for and adjust submenus, if necessary.
+ NSInteger buttonCount = [buttons_ count];
+ if (buttonCount) {
+ BookmarkButton* subButton = [folderController_ parentButton];
+ for (NSInteger i = buttonIndex; i < buttonCount; ++i) {
+ BookmarkButton* aButton = [buttons_ objectAtIndex:i];
+ // If this button is showing its menu then we need to move the menu, too.
+ if (aButton == subButton)
+ [folderController_ offsetFolderMenuWindow:NSMakeSize(0.0,
+ bookmarks::kBookmarkBarHeight)];
+ }
+ } else {
+ // If all nodes have been removed from this folder then add in the
+ // 'empty' placeholder button.
+ NSRect buttonFrame =
+ NSMakeRect(bookmarks::kBookmarkSubMenuHorizontalPadding,
+ bookmarks::kBookmarkButtonHeight -
+ (bookmarks::kBookmarkBarHeight -
+ bookmarks::kBookmarkVerticalPadding),
+ bookmarks::kDefaultBookmarkWidth,
+ (bookmarks::kBookmarkBarHeight -
+ 2 * bookmarks::kBookmarkVerticalPadding));
+ BookmarkButton* button = [self makeButtonForNode:nil
+ frame:buttonFrame];
+ [buttons_ addObject:button];
+ [mainView_ addSubview:button];
+ buttonCount = 1;
+ }
+
+ // Propose a height for the window. We'll trim later as needed.
+ [self adjustWindowForHeight:[self windowHeightForButtonCount:buttonCount]];
+}
+
+- (id<BookmarkButtonControllerProtocol>)controllerForNode:
+ (const BookmarkNode*)node {
+ // See if we are holding this node, otherwise see if it is in our
+ // hierarchy of visible folder menus.
+ if ([parentButton_ bookmarkNode] == node)
+ return self;
+ return [folderController_ controllerForNode:node];
+}
+
+#pragma mark TestingAPI Only
+
+- (void)setIgnoreAnimations:(BOOL)ignore {
+ ignoreAnimations_ = ignore;
+}
+
+- (BookmarkButton*)buttonThatMouseIsIn {
+ return buttonThatMouseIsIn_;
+}
+
+@end // BookmarkBarFolderController
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller_unittest.mm
new file mode 100644
index 0000000..cae8766
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller_unittest.mm
@@ -0,0 +1,1552 @@
+// 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 "base/basictypes.h"
+#include "base/scoped_nsobject.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_button_cell.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_unittest_helper.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/view_resizer_pong.h"
+#include "chrome/test/model_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+// Add a redirect to make testing easier.
+@interface BookmarkBarFolderController(MakeTestingEasier)
+- (IBAction)openBookmarkFolderFromButton:(id)sender;
+- (void)validateMenuSpacing;
+@end
+
+@implementation BookmarkBarFolderController(MakeTestingEasier)
+- (IBAction)openBookmarkFolderFromButton:(id)sender {
+ [[self folderTarget] openBookmarkFolderFromButton:sender];
+}
+
+// Utility function to verify that the buttons in this folder are all
+// evenly spaced in a progressive manner.
+- (void)validateMenuSpacing {
+ BOOL firstButton = YES;
+ CGFloat lastVerticalOffset = 0.0;
+ for (BookmarkButton* button in [self buttons]) {
+ if (firstButton) {
+ firstButton = NO;
+ lastVerticalOffset = [button frame].origin.y;
+ } else {
+ CGFloat nextVerticalOffset = [button frame].origin.y;
+ EXPECT_CGFLOAT_EQ(lastVerticalOffset -
+ bookmarks::kBookmarkButtonVerticalSpan,
+ nextVerticalOffset);
+ lastVerticalOffset = nextVerticalOffset;
+ }
+ }
+}
+@end
+
+// Don't use a high window level when running unit tests -- it'll
+// interfere with anything else you are working on.
+// For testing.
+@interface BookmarkBarFolderControllerNoLevel : BookmarkBarFolderController
+@end
+
+@implementation BookmarkBarFolderControllerNoLevel
+- (void)configureWindowLevel {
+ // Intentionally empty.
+}
+@end
+
+// No window level and the ability to fake the "top left" point of the window.
+// For testing.
+@interface BookmarkBarFolderControllerLow : BookmarkBarFolderControllerNoLevel {
+ BOOL realTopLeft_; // Use the real windowTopLeft call?
+}
+@property (nonatomic) BOOL realTopLeft;
+@end
+
+
+@implementation BookmarkBarFolderControllerLow
+
+@synthesize realTopLeft = realTopLeft_;
+
+- (NSPoint)windowTopLeftForWidth:(int)width {
+ return realTopLeft_ ? [super windowTopLeftForWidth:width] :
+ NSMakePoint(200,200);
+}
+
+@end
+
+
+@interface BookmarkBarFolderControllerPong : BookmarkBarFolderControllerLow {
+ BOOL childFolderWillShow_;
+ BOOL childFolderWillClose_;
+}
+@property (nonatomic, readonly) BOOL childFolderWillShow;
+@property (nonatomic, readonly) BOOL childFolderWillClose;
+@end
+
+@implementation BookmarkBarFolderControllerPong
+@synthesize childFolderWillShow = childFolderWillShow_;
+@synthesize childFolderWillClose = childFolderWillClose_;
+
+- (void)childFolderWillShow:(id<BookmarkButtonControllerProtocol>)child {
+ childFolderWillShow_ = YES;
+}
+
+- (void)childFolderWillClose:(id<BookmarkButtonControllerProtocol>)child {
+ childFolderWillClose_ = YES;
+}
+
+// We don't have a real BookmarkBarController as our parent root so
+// we fake this one out.
+- (void)closeAllBookmarkFolders {
+ [self closeBookmarkFolder:self];
+}
+
+@end
+
+namespace {
+const int kLotsOfNodesCount = 150;
+};
+
+
+// Redirect certain calls so they can be seen by tests.
+
+@interface BookmarkBarControllerChildFolderRedirect : BookmarkBarController {
+ BookmarkBarFolderController* childFolderDelegate_;
+}
+@property (nonatomic, assign) BookmarkBarFolderController* childFolderDelegate;
+@end
+
+@implementation BookmarkBarControllerChildFolderRedirect
+
+@synthesize childFolderDelegate = childFolderDelegate_;
+
+- (void)childFolderWillShow:(id<BookmarkButtonControllerProtocol>)child {
+ [childFolderDelegate_ childFolderWillShow:child];
+}
+
+- (void)childFolderWillClose:(id<BookmarkButtonControllerProtocol>)child {
+ [childFolderDelegate_ childFolderWillClose:child];
+}
+
+@end
+
+
+class BookmarkBarFolderControllerTest : public CocoaTest {
+ public:
+ BrowserTestHelper helper_;
+ scoped_nsobject<BookmarkBarControllerChildFolderRedirect> bar_;
+ const BookmarkNode* folderA_; // owned by model
+ const BookmarkNode* longTitleNode_; // owned by model
+
+ BookmarkBarFolderControllerTest() {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ const BookmarkNode* folderA = model->AddGroup(parent,
+ parent->GetChildCount(),
+ ASCIIToUTF16("group"));
+ folderA_ = folderA;
+ model->AddGroup(parent, parent->GetChildCount(),
+ ASCIIToUTF16("sibbling group"));
+ const BookmarkNode* folderB = model->AddGroup(folderA,
+ folderA->GetChildCount(),
+ ASCIIToUTF16("subgroup 1"));
+ model->AddGroup(folderA,
+ folderA->GetChildCount(),
+ ASCIIToUTF16("subgroup 2"));
+ model->AddURL(folderA, folderA->GetChildCount(), ASCIIToUTF16("title a"),
+ GURL("http://www.google.com/a"));
+ longTitleNode_ = model->AddURL(
+ folderA, folderA->GetChildCount(),
+ ASCIIToUTF16("title super duper long long whoa momma title you betcha"),
+ GURL("http://www.google.com/b"));
+ model->AddURL(folderB, folderB->GetChildCount(), ASCIIToUTF16("t"),
+ GURL("http://www.google.com/c"));
+
+ bar_.reset(
+ [[BookmarkBarControllerChildFolderRedirect alloc]
+ initWithBrowser:helper_.browser()
+ initialWidth:300
+ delegate:nil
+ resizeDelegate:nil]);
+ [bar_ loaded:model];
+ // Make parent frame for bookmark bar then open it.
+ NSRect frame = [[test_window() contentView] frame];
+ frame = NSInsetRect(frame, 100, 200);
+ NSView* fakeToolbarView = [[[NSView alloc] initWithFrame:frame]
+ autorelease];
+ [[test_window() contentView] addSubview:fakeToolbarView];
+ [fakeToolbarView addSubview:[bar_ view]];
+ [bar_ setBookmarkBarEnabled:YES];
+ }
+
+ // Remove the bookmark with the long title.
+ void RemoveLongTitleNode() {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ model->Remove(longTitleNode_->GetParent(),
+ longTitleNode_->GetParent()->IndexOfChild(longTitleNode_));
+ }
+
+ // Add LOTS of nodes to our model if needed (e.g. scrolling).
+ // Returns the number of nodes added.
+ int AddLotsOfNodes() {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ for (int i = 0; i < kLotsOfNodesCount; i++) {
+ model->AddURL(folderA_, folderA_->GetChildCount(),
+ ASCIIToUTF16("repeated title"),
+ GURL("http://www.google.com/repeated/url"));
+ }
+ return kLotsOfNodesCount;
+ }
+
+ // Return a simple BookmarkBarFolderController.
+ BookmarkBarFolderControllerPong* SimpleBookmarkBarFolderController() {
+ BookmarkButton* parentButton = [[bar_ buttons] objectAtIndex:0];
+ BookmarkBarFolderControllerPong* c =
+ [[BookmarkBarFolderControllerPong alloc]
+ initWithParentButton:parentButton
+ parentController:nil
+ barController:bar_];
+ [c window]; // Force nib load.
+ return c;
+ }
+};
+
+TEST_F(BookmarkBarFolderControllerTest, InitCreateAndDelete) {
+ scoped_nsobject<BookmarkBarFolderController> bbfc;
+ bbfc.reset(SimpleBookmarkBarFolderController());
+
+ // Make sure none of the buttons overlap, that all are inside
+ // the content frame, and their cells are of the proper class.
+ NSArray* buttons = [bbfc buttons];
+ EXPECT_TRUE([buttons count]);
+ for (unsigned int i = 0; i < ([buttons count]-1); i++) {
+ EXPECT_FALSE(NSContainsRect([[buttons objectAtIndex:i] frame],
+ [[buttons objectAtIndex:i+1] frame]));
+ }
+ Class cellClass = [BookmarkBarFolderButtonCell class];
+ for (BookmarkButton* button in buttons) {
+ NSRect r = [[bbfc mainView] convertRect:[button frame] fromView:button];
+ // TODO(jrg): remove this adjustment.
+ NSRect bigger = NSInsetRect([[bbfc mainView] frame], -2, 0);
+ EXPECT_TRUE(NSContainsRect(bigger, r));
+ EXPECT_TRUE([[button cell] isKindOfClass:cellClass]);
+ }
+
+ // Confirm folder buttons have no tooltip. The important thing
+ // really is that we insure folders and non-folders are treated
+ // differently; not sure of any other generic way to do this.
+ for (BookmarkButton* button in buttons) {
+ if ([button isFolder])
+ EXPECT_FALSE([button toolTip]);
+ else
+ EXPECT_TRUE([button toolTip]);
+ }
+}
+
+// Make sure closing of the window releases the controller.
+// (e.g. valgrind shouldn't complain if we do this).
+TEST_F(BookmarkBarFolderControllerTest, ReleaseOnClose) {
+ scoped_nsobject<BookmarkBarFolderController> bbfc;
+ bbfc.reset(SimpleBookmarkBarFolderController());
+ EXPECT_TRUE(bbfc.get());
+
+ [bbfc retain]; // stop the scoped_nsobject from doing anything
+ [[bbfc window] close]; // trigger an autorelease of bbfc.get()
+}
+
+TEST_F(BookmarkBarFolderControllerTest, BasicPosition) {
+ BookmarkButton* parentButton = [[bar_ buttons] objectAtIndex:0];
+ EXPECT_TRUE(parentButton);
+
+ // If parent is a BookmarkBarController, grow down.
+ scoped_nsobject<BookmarkBarFolderControllerLow> bbfc;
+ bbfc.reset([[BookmarkBarFolderControllerLow alloc]
+ initWithParentButton:parentButton
+ parentController:nil
+ barController:bar_]);
+ [bbfc window];
+ [bbfc setRealTopLeft:YES];
+ NSPoint pt = [bbfc windowTopLeftForWidth:0]; // screen coords
+ NSPoint buttonOriginInScreen =
+ [[parentButton window]
+ convertBaseToScreen:[parentButton
+ convertRectToBase:[parentButton frame]].origin];
+ // Within margin
+ EXPECT_LE(abs(pt.x - buttonOriginInScreen.x),
+ bookmarks::kBookmarkMenuOverlap+1);
+ EXPECT_LE(abs(pt.y - buttonOriginInScreen.y),
+ bookmarks::kBookmarkMenuOverlap+1);
+
+ // Make sure we see the window shift left if it spills off the screen
+ pt = [bbfc windowTopLeftForWidth:0];
+ NSPoint shifted = [bbfc windowTopLeftForWidth:9999999];
+ EXPECT_LT(shifted.x, pt.x);
+
+ // If parent is a BookmarkBarFolderController, grow right.
+ scoped_nsobject<BookmarkBarFolderControllerLow> bbfc2;
+ bbfc2.reset([[BookmarkBarFolderControllerLow alloc]
+ initWithParentButton:[[bbfc buttons] objectAtIndex:0]
+ parentController:bbfc.get()
+ barController:bar_]);
+ [bbfc2 window];
+ [bbfc2 setRealTopLeft:YES];
+ pt = [bbfc2 windowTopLeftForWidth:0];
+ // We're now overlapping the window a bit.
+ EXPECT_EQ(pt.x, NSMaxX([[bbfc.get() window] frame]) -
+ bookmarks::kBookmarkMenuOverlap);
+}
+
+// Confirm we grow right until end of screen, then start growing left
+// until end of screen again, then right.
+TEST_F(BookmarkBarFolderControllerTest, PositionRightLeftRight) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ const BookmarkNode* folder = parent;
+
+ const int count = 100;
+ int i;
+ // Make some super duper deeply nested folders.
+ for (i=0; i<count; i++) {
+ folder = model->AddGroup(folder, 0, ASCIIToUTF16("nested folder"));
+ }
+
+ // Setup initial state for opening all folders.
+ folder = parent;
+ BookmarkButton* parentButton = [[bar_ buttons] objectAtIndex:0];
+ BookmarkBarFolderController* parentController = nil;
+ EXPECT_TRUE(parentButton);
+
+ // Open them all.
+ scoped_nsobject<NSMutableArray> folder_controller_array;
+ folder_controller_array.reset([[NSMutableArray array] retain]);
+ for (i=0; i<count; i++) {
+ BookmarkBarFolderControllerNoLevel* bbfcl =
+ [[BookmarkBarFolderControllerNoLevel alloc]
+ initWithParentButton:parentButton
+ parentController:parentController
+ barController:bar_];
+ [folder_controller_array addObject:bbfcl];
+ [bbfcl autorelease];
+ [bbfcl window];
+ parentController = bbfcl;
+ parentButton = [[bbfcl buttons] objectAtIndex:0];
+ }
+
+ // Make vector of all x positions.
+ std::vector<CGFloat> leftPositions;
+ for (i=0; i<count; i++) {
+ CGFloat x = [[[folder_controller_array objectAtIndex:i] window]
+ frame].origin.x;
+ leftPositions.push_back(x);
+ }
+
+ // Make sure the first few grow right.
+ for (i=0; i<3; i++)
+ EXPECT_TRUE(leftPositions[i+1] > leftPositions[i]);
+
+ // Look for the first "grow left".
+ while (leftPositions[i] > leftPositions[i-1])
+ i++;
+ // Confirm the next few also grow left.
+ int j;
+ for (j=i; j<i+3; j++)
+ EXPECT_TRUE(leftPositions[j+1] < leftPositions[j]);
+ i = j;
+
+ // Finally, confirm we see a "grow right" once more.
+ while (leftPositions[i] < leftPositions[i-1])
+ i++;
+ // (No need to EXPECT a final "grow right"; if we didn't find one
+ // we'd get a C++ array bounds exception).
+}
+
+TEST_F(BookmarkBarFolderControllerTest, DropDestination) {
+ scoped_nsobject<BookmarkBarFolderController> bbfc;
+ bbfc.reset(SimpleBookmarkBarFolderController());
+ EXPECT_TRUE(bbfc.get());
+
+ // Confirm "off the top" and "off the bottom" match no buttons.
+ NSPoint p = NSMakePoint(NSMidX([[bbfc mainView] frame]), 10000);
+ EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:p]);
+ EXPECT_TRUE([bbfc shouldShowIndicatorShownForPoint:p]);
+ p = NSMakePoint(NSMidX([[bbfc mainView] frame]), -1);
+ EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:p]);
+ EXPECT_TRUE([bbfc shouldShowIndicatorShownForPoint:p]);
+
+ // Confirm "right in the center" (give or take a pixel) is a match,
+ // and confirm "just barely in the button" is not. Anything more
+ // specific seems likely to be tweaked. We don't loop over all
+ // buttons because the scroll view makes them not visible.
+ for (BookmarkButton* button in [bbfc buttons]) {
+ CGFloat x = NSMidX([button frame]);
+ CGFloat y = NSMidY([button frame]);
+ // Somewhere near the center: a match (but only if a folder!)
+ if ([button isFolder]) {
+ EXPECT_EQ(button,
+ [bbfc buttonForDroppingOnAtPoint:NSMakePoint(x-1, y+1)]);
+ EXPECT_EQ(button,
+ [bbfc buttonForDroppingOnAtPoint:NSMakePoint(x+1, y-1)]);
+ EXPECT_FALSE([bbfc shouldShowIndicatorShownForPoint:NSMakePoint(x, y)]);;
+ } else {
+ // If not a folder we don't drop into it.
+ EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:NSMakePoint(x-1, y+1)]);
+ EXPECT_FALSE([bbfc buttonForDroppingOnAtPoint:NSMakePoint(x+1, y-1)]);
+ EXPECT_TRUE([bbfc shouldShowIndicatorShownForPoint:NSMakePoint(x, y)]);;
+ }
+ }
+}
+
+TEST_F(BookmarkBarFolderControllerTest, OpenFolder) {
+ scoped_nsobject<BookmarkBarFolderController> bbfc;
+ bbfc.reset(SimpleBookmarkBarFolderController());
+ EXPECT_TRUE(bbfc.get());
+
+ EXPECT_FALSE([bbfc folderController]);
+ BookmarkButton* button = [[bbfc buttons] objectAtIndex:0];
+ [bbfc openBookmarkFolderFromButton:button];
+ id controller = [bbfc folderController];
+ EXPECT_TRUE(controller);
+ EXPECT_EQ([controller parentButton], button);
+
+ // Click the same one --> it gets closed.
+ [bbfc openBookmarkFolderFromButton:[[bbfc buttons] objectAtIndex:0]];
+ EXPECT_FALSE([bbfc folderController]);
+
+ // Open a new one --> change.
+ [bbfc openBookmarkFolderFromButton:[[bbfc buttons] objectAtIndex:1]];
+ EXPECT_NE(controller, [bbfc folderController]);
+ EXPECT_NE([[bbfc folderController] parentButton], button);
+
+ // Close it --> all gone!
+ [bbfc closeBookmarkFolder:nil];
+ EXPECT_FALSE([bbfc folderController]);
+}
+
+TEST_F(BookmarkBarFolderControllerTest, ChildFolderCallbacks) {
+ scoped_nsobject<BookmarkBarFolderControllerPong> bbfc;
+ bbfc.reset(SimpleBookmarkBarFolderController());
+ EXPECT_TRUE(bbfc.get());
+ [bar_ setChildFolderDelegate:bbfc.get()];
+
+ EXPECT_FALSE([bbfc childFolderWillShow]);
+ [bbfc openBookmarkFolderFromButton:[[bbfc buttons] objectAtIndex:0]];
+ EXPECT_TRUE([bbfc childFolderWillShow]);
+
+ EXPECT_FALSE([bbfc childFolderWillClose]);
+ [bbfc closeBookmarkFolder:nil];
+ EXPECT_TRUE([bbfc childFolderWillClose]);
+
+ [bar_ setChildFolderDelegate:nil];
+}
+
+// Make sure bookmark folders have variable widths.
+TEST_F(BookmarkBarFolderControllerTest, ChildFolderWidth) {
+ scoped_nsobject<BookmarkBarFolderController> bbfc;
+
+ bbfc.reset(SimpleBookmarkBarFolderController());
+ EXPECT_TRUE(bbfc.get());
+ [bbfc showWindow:bbfc.get()];
+ CGFloat wideWidth = NSWidth([[bbfc window] frame]);
+
+ RemoveLongTitleNode();
+ bbfc.reset(SimpleBookmarkBarFolderController());
+ EXPECT_TRUE(bbfc.get());
+ CGFloat thinWidth = NSWidth([[bbfc window] frame]);
+
+ // Make sure window size changed as expected.
+ EXPECT_GT(wideWidth, thinWidth);
+}
+
+// Simple scrolling tests.
+TEST_F(BookmarkBarFolderControllerTest, SimpleScroll) {
+ scoped_nsobject<BookmarkBarFolderController> bbfc;
+
+ int nodecount = AddLotsOfNodes();
+ bbfc.reset(SimpleBookmarkBarFolderController());
+ EXPECT_TRUE(bbfc.get());
+ [bbfc showWindow:bbfc.get()];
+
+ // Make sure the window fits on the screen.
+ EXPECT_LT(NSHeight([[bbfc window] frame]),
+ NSHeight([[NSScreen mainScreen] frame]));
+
+ // Verify the logic used by the scroll arrow code.
+ EXPECT_TRUE([bbfc canScrollUp]);
+ EXPECT_FALSE([bbfc canScrollDown]);
+
+ // Scroll it up. Make sure the window has gotten bigger each time.
+ // Also, for each scroll, make sure our hit test finds a new button
+ // (to confirm the content area changed).
+ NSView* savedHit = nil;
+ for (int i=0; i<3; i++) {
+ CGFloat height = NSHeight([[bbfc window] frame]);
+ [bbfc performOneScroll:60];
+ EXPECT_GT(NSHeight([[bbfc window] frame]), height);
+ NSView* hit = [[[bbfc window] contentView] hitTest:NSMakePoint(22, 22)];
+ EXPECT_NE(hit, savedHit);
+ savedHit = hit;
+ }
+
+ // Keep scrolling up; make sure we never get bigger than the screen.
+ // Also confirm we never scroll the window off the screen.
+ bool bothAtOnce = false;
+ NSRect screenFrame = [[NSScreen mainScreen] frame];
+ for (int i = 0; i < nodecount; i++) {
+ [bbfc performOneScroll:60];
+ EXPECT_TRUE(NSContainsRect(screenFrame,
+ [[bbfc window] frame]));
+ // Make sure, sometime during our scroll, we have the ability to
+ // scroll in either direction.
+ if ([bbfc canScrollUp] &&
+ [bbfc canScrollDown])
+ bothAtOnce = true;
+ }
+ EXPECT_TRUE(bothAtOnce);
+
+ // Once we've scrolled to the end, our only option should be to scroll back.
+ EXPECT_FALSE([bbfc canScrollUp]);
+ EXPECT_TRUE([bbfc canScrollDown]);
+
+ // Now scroll down and make sure the window size does not change.
+ // Also confirm we never scroll the window off the screen the other
+ // way.
+ for (int i=0; i<nodecount+50; i++) {
+ CGFloat height = NSHeight([[bbfc window] frame]);
+ [bbfc performOneScroll:-60];
+ EXPECT_EQ(height, NSHeight([[bbfc window] frame]));
+ EXPECT_TRUE(NSContainsRect(screenFrame,
+ [[bbfc window] frame]));
+ }
+}
+
+// Folder menu sizing and placementwhile deleting bookmarks and scrolling tests.
+TEST_F(BookmarkBarFolderControllerTest, MenuPlacementWhileScrollingDeleting) {
+ scoped_nsobject<BookmarkBarFolderController> bbfc;
+ AddLotsOfNodes();
+ bbfc.reset(SimpleBookmarkBarFolderController());
+ [bbfc showWindow:bbfc.get()];
+ NSWindow* menuWindow = [bbfc window];
+ BookmarkBarFolderController* folder = [bar_ folderController];
+ NSArray* buttons = [folder buttons];
+
+ // Before scrolling any, delete a bookmark and make sure the window top has
+ // not moved. Pick a button which is near the top and visible.
+ CGFloat oldTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
+ BookmarkButton* button = [buttons objectAtIndex:3];
+ [folder deleteBookmark:button];
+ CGFloat newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
+ EXPECT_CGFLOAT_EQ(oldTop, newTop);
+
+ // Scroll so that both the top and bottom scroll arrows show, make sure
+ // the top of the window has moved up, then delete a visible button and
+ // make sure the top has not moved.
+ oldTop = newTop;
+ const CGFloat scrollOneBookmark = bookmarks::kBookmarkButtonHeight +
+ bookmarks::kBookmarkVerticalPadding;
+ NSUInteger buttonCounter = 0;
+ NSUInteger extraButtonLimit = 3;
+ while (![bbfc canScrollDown] || extraButtonLimit > 0) {
+ [bbfc performOneScroll:scrollOneBookmark];
+ ++buttonCounter;
+ if ([bbfc canScrollDown])
+ --extraButtonLimit;
+ }
+ newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
+ EXPECT_NE(oldTop, newTop);
+ oldTop = newTop;
+ button = [buttons objectAtIndex:buttonCounter + 3];
+ [folder deleteBookmark:button];
+ newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
+ EXPECT_CGFLOAT_EQ(oldTop, newTop);
+
+ // Scroll so that the top scroll arrow is no longer showing, make sure
+ // the top of the window has not moved, then delete a visible button and
+ // make sure the top has not moved.
+ while ([bbfc canScrollDown]) {
+ [bbfc performOneScroll:-scrollOneBookmark];
+ --buttonCounter;
+ }
+ button = [buttons objectAtIndex:buttonCounter + 3];
+ [folder deleteBookmark:button];
+ newTop = [menuWindow frame].origin.y + NSHeight([menuWindow frame]);
+ EXPECT_CGFLOAT_EQ(oldTop, newTop);
+}
+
+@interface FakedDragInfo : NSObject {
+@public
+ NSPoint dropLocation_;
+ NSDragOperation sourceMask_;
+}
+@property (nonatomic, assign) NSPoint dropLocation;
+- (void)setDraggingSourceOperationMask:(NSDragOperation)mask;
+@end
+
+@implementation FakedDragInfo
+
+@synthesize dropLocation = dropLocation_;
+
+- (id)init {
+ if ((self = [super init])) {
+ dropLocation_ = NSZeroPoint;
+ sourceMask_ = NSDragOperationMove;
+ }
+ return self;
+}
+
+// NSDraggingInfo protocol functions.
+
+- (id)draggingPasteboard {
+ return self;
+}
+
+- (id)draggingSource {
+ return self;
+}
+
+- (NSDragOperation)draggingSourceOperationMask {
+ return sourceMask_;
+}
+
+- (NSPoint)draggingLocation {
+ return dropLocation_;
+}
+
+// Other functions.
+
+- (void)setDraggingSourceOperationMask:(NSDragOperation)mask {
+ sourceMask_ = mask;
+}
+
+@end
+
+
+class BookmarkBarFolderControllerMenuTest : public CocoaTest {
+ public:
+ BrowserTestHelper helper_;
+ scoped_nsobject<NSView> parent_view_;
+ scoped_nsobject<ViewResizerPong> resizeDelegate_;
+ scoped_nsobject<BookmarkBarController> bar_;
+
+ BookmarkBarFolderControllerMenuTest() {
+ resizeDelegate_.reset([[ViewResizerPong alloc] init]);
+ NSRect parent_frame = NSMakeRect(0, 0, 800, 50);
+ parent_view_.reset([[NSView alloc] initWithFrame:parent_frame]);
+ [parent_view_ setHidden:YES];
+ bar_.reset([[BookmarkBarController alloc]
+ initWithBrowser:helper_.browser()
+ initialWidth:NSWidth(parent_frame)
+ delegate:nil
+ resizeDelegate:resizeDelegate_.get()]);
+ InstallAndToggleBar(bar_.get());
+ }
+
+ void InstallAndToggleBar(BookmarkBarController* bar) {
+ // Force loading of the nib.
+ [bar view];
+ // Awkwardness to look like we've been installed.
+ [parent_view_ addSubview:[bar view]];
+ NSRect frame = [[[bar view] superview] frame];
+ frame.origin.y = 100;
+ [[[bar view] superview] setFrame:frame];
+
+ // Make sure it's on in a window so viewDidMoveToWindow is called
+ [[test_window() contentView] addSubview:parent_view_];
+
+ // Make sure it's open so certain things aren't no-ops.
+ [bar updateAndShowNormalBar:YES
+ showDetachedBar:NO
+ withAnimation:NO];
+ }
+};
+
+TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveBarBookmarkToFolder) {
+ BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
+ "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
+ "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
+ model_test_utils::AddNodesFromModelString(model, root, model_string);
+
+ // Validate initial model.
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(model_string, actualModelString);
+
+ // Pop up a folder menu and drag in a button from the bar.
+ BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"2f"];
+ NSRect oldToFolderFrame = [toFolder frame];
+ [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
+ withObject:toFolder];
+ BookmarkBarFolderController* folderController = [bar_ folderController];
+ EXPECT_TRUE(folderController);
+ NSWindow* toWindow = [folderController window];
+ EXPECT_TRUE(toWindow);
+ NSRect oldToWindowFrame = [toWindow frame];
+ // Drag a bar button onto a bookmark (i.e. not a folder) in a folder
+ // so it should end up below the target bookmark.
+ BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"1b"];
+ ASSERT_TRUE(draggedButton);
+ CGFloat horizontalShift =
+ NSWidth([draggedButton frame]) + bookmarks::kBookmarkHorizontalPadding;
+ BookmarkButton* targetButton =
+ [folderController buttonWithTitleEqualTo:@"2f1b"];
+ ASSERT_TRUE(targetButton);
+ [folderController dragButton:draggedButton
+ to:[targetButton center]
+ copy:NO];
+ // The button should have landed just after "2f1b".
+ const std::string expected_string("2f:[ 2f1b 1b 2f2f:[ 2f2f1b "
+ "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
+ "4f2f1b 4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
+ EXPECT_EQ(expected_string, model_test_utils::ModelStringFromNode(root));
+
+ // Verify the window still appears by looking for its controller.
+ EXPECT_TRUE([bar_ folderController]);
+
+ // Gather the new frames.
+ NSRect newToFolderFrame = [toFolder frame];
+ NSRect newToWindowFrame = [toWindow frame];
+ // The toFolder should have shifted left horizontally but not vertically.
+ NSRect expectedToFolderFrame =
+ NSOffsetRect(oldToFolderFrame, -horizontalShift, 0);
+ EXPECT_NSRECT_EQ(expectedToFolderFrame, newToFolderFrame);
+ // The toWindow should have shifted left horizontally, down vertically,
+ // and grown vertically.
+ NSRect expectedToWindowFrame = oldToWindowFrame;
+ expectedToWindowFrame.origin.x -= horizontalShift;
+ CGFloat diff = (bookmarks::kBookmarkBarHeight +
+ 2*bookmarks::kBookmarkVerticalPadding);
+ expectedToWindowFrame.origin.y -= diff;
+ expectedToWindowFrame.size.height += diff;
+ EXPECT_NSRECT_EQ(expectedToWindowFrame, newToWindowFrame);
+
+ // Check button spacing.
+ [folderController validateMenuSpacing];
+
+ // Move the button back to the bar at the beginning.
+ draggedButton = [folderController buttonWithTitleEqualTo:@"1b"];
+ ASSERT_TRUE(draggedButton);
+ targetButton = [bar_ buttonWithTitleEqualTo:@"2f"];
+ ASSERT_TRUE(targetButton);
+ [bar_ dragButton:draggedButton
+ to:[targetButton left]
+ copy:NO];
+ EXPECT_EQ(model_string, model_test_utils::ModelStringFromNode(root));
+ // Don't check the folder window since it's not supposed to be showing.
+}
+
+TEST_F(BookmarkBarFolderControllerMenuTest, DragCopyBarBookmarkToFolder) {
+ BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
+ "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
+ "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
+ model_test_utils::AddNodesFromModelString(model, root, model_string);
+
+ // Validate initial model.
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(model_string, actualModelString);
+
+ // Pop up a folder menu and copy in a button from the bar.
+ BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"2f"];
+ ASSERT_TRUE(toFolder);
+ NSRect oldToFolderFrame = [toFolder frame];
+ [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
+ withObject:toFolder];
+ BookmarkBarFolderController* folderController = [bar_ folderController];
+ EXPECT_TRUE(folderController);
+ NSWindow* toWindow = [folderController window];
+ EXPECT_TRUE(toWindow);
+ NSRect oldToWindowFrame = [toWindow frame];
+ // Drag a bar button onto a bookmark (i.e. not a folder) in a folder
+ // so it should end up below the target bookmark.
+ BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"1b"];
+ ASSERT_TRUE(draggedButton);
+ BookmarkButton* targetButton =
+ [folderController buttonWithTitleEqualTo:@"2f1b"];
+ ASSERT_TRUE(targetButton);
+ [folderController dragButton:draggedButton
+ to:[targetButton center]
+ copy:YES];
+ // The button should have landed just after "2f1b".
+ const std::string expected_1("1b 2f:[ 2f1b 1b 2f2f:[ 2f2f1b "
+ "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
+ "4f2f1b 4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
+ EXPECT_EQ(expected_1, model_test_utils::ModelStringFromNode(root));
+
+ // Gather the new frames.
+ NSRect newToFolderFrame = [toFolder frame];
+ NSRect newToWindowFrame = [toWindow frame];
+ // The toFolder should have shifted.
+ EXPECT_NSRECT_EQ(oldToFolderFrame, newToFolderFrame);
+ // The toWindow should have shifted down vertically and grown vertically.
+ NSRect expectedToWindowFrame = oldToWindowFrame;
+ CGFloat diff = (bookmarks::kBookmarkBarHeight +
+ 2*bookmarks::kBookmarkVerticalPadding);
+ expectedToWindowFrame.origin.y -= diff;
+ expectedToWindowFrame.size.height += diff;
+ EXPECT_NSRECT_EQ(expectedToWindowFrame, newToWindowFrame);
+
+ // Copy the button back to the bar after "3b".
+ draggedButton = [folderController buttonWithTitleEqualTo:@"1b"];
+ ASSERT_TRUE(draggedButton);
+ targetButton = [bar_ buttonWithTitleEqualTo:@"4f"];
+ ASSERT_TRUE(targetButton);
+ [bar_ dragButton:draggedButton
+ to:[targetButton left]
+ copy:YES];
+ const std::string expected_2("1b 2f:[ 2f1b 1b 2f2f:[ 2f2f1b "
+ "2f2f2b 2f2f3b ] 2f3b ] 3b 1b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
+ "4f2f1b 4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
+ EXPECT_EQ(expected_2, model_test_utils::ModelStringFromNode(root));
+}
+
+TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveBarBookmarkToSubfolder) {
+ BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
+ "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
+ "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
+ model_test_utils::AddNodesFromModelString(model, root, model_string);
+
+ // Validate initial model.
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(model_string, actualModelString);
+
+ // Pop up a folder menu and a subfolder menu.
+ BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"4f"];
+ ASSERT_TRUE(toFolder);
+ [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
+ withObject:toFolder];
+ BookmarkBarFolderController* folderController = [bar_ folderController];
+ EXPECT_TRUE(folderController);
+ NSWindow* toWindow = [folderController window];
+ EXPECT_TRUE(toWindow);
+ NSRect oldToWindowFrame = [toWindow frame];
+ BookmarkButton* toSubfolder =
+ [folderController buttonWithTitleEqualTo:@"4f2f"];
+ ASSERT_TRUE(toSubfolder);
+ [[toSubfolder target] performSelector:@selector(openBookmarkFolderFromButton:)
+ withObject:toSubfolder];
+ BookmarkBarFolderController* subfolderController =
+ [folderController folderController];
+ EXPECT_TRUE(subfolderController);
+ NSWindow* toSubwindow = [subfolderController window];
+ EXPECT_TRUE(toSubwindow);
+ NSRect oldToSubwindowFrame = [toSubwindow frame];
+ // Drag a bar button onto a bookmark (i.e. not a folder) in a folder
+ // so it should end up below the target bookmark.
+ BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"5b"];
+ ASSERT_TRUE(draggedButton);
+ BookmarkButton* targetButton =
+ [subfolderController buttonWithTitleEqualTo:@"4f2f3b"];
+ ASSERT_TRUE(targetButton);
+ [subfolderController dragButton:draggedButton
+ to:[targetButton center]
+ copy:NO];
+ // The button should have landed just after "2f".
+ const std::string expected_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b "
+ "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ "
+ "4f2f1b 4f2f2b 4f2f3b 5b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] ");
+ EXPECT_EQ(expected_string, model_test_utils::ModelStringFromNode(root));
+
+ // Check button spacing.
+ [folderController validateMenuSpacing];
+ [subfolderController validateMenuSpacing];
+
+ // Check the window layouts. The folder window should not have changed,
+ // but the subfolder window should have shifted vertically and grown.
+ NSRect newToWindowFrame = [toWindow frame];
+ EXPECT_NSRECT_EQ(oldToWindowFrame, newToWindowFrame);
+ NSRect newToSubwindowFrame = [toSubwindow frame];
+ NSRect expectedToSubwindowFrame = oldToSubwindowFrame;
+ expectedToSubwindowFrame.origin.y -=
+ bookmarks::kBookmarkBarHeight + bookmarks::kVisualHeightOffset;
+ expectedToSubwindowFrame.size.height +=
+ bookmarks::kBookmarkBarHeight + bookmarks::kVisualHeightOffset;
+ EXPECT_NSRECT_EQ(expectedToSubwindowFrame, newToSubwindowFrame);
+}
+
+TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveWithinFolder) {
+ BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
+ "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
+ "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
+ model_test_utils::AddNodesFromModelString(model, root, model_string);
+
+ // Validate initial model.
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(model_string, actualModelString);
+
+ // Pop up a folder menu.
+ BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"4f"];
+ ASSERT_TRUE(toFolder);
+ [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
+ withObject:toFolder];
+ BookmarkBarFolderController* folderController = [bar_ folderController];
+ EXPECT_TRUE(folderController);
+ NSWindow* toWindow = [folderController window];
+ EXPECT_TRUE(toWindow);
+ NSRect oldToWindowFrame = [toWindow frame];
+ // Drag a folder button to the top within the same parent.
+ BookmarkButton* draggedButton =
+ [folderController buttonWithTitleEqualTo:@"4f2f"];
+ ASSERT_TRUE(draggedButton);
+ BookmarkButton* targetButton =
+ [folderController buttonWithTitleEqualTo:@"4f1f"];
+ ASSERT_TRUE(targetButton);
+ [folderController dragButton:draggedButton
+ to:[targetButton top]
+ copy:NO];
+ // The button should have landed above "4f1f".
+ const std::string expected_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b "
+ "2f2f2b 2f2f3b ] 2f3b ] 3b 4f:[ 4f2f:[ 4f2f1b 4f2f2b 4f2f3b ] "
+ "4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
+ EXPECT_EQ(expected_string, model_test_utils::ModelStringFromNode(root));
+
+ // The window should not have gone away.
+ EXPECT_TRUE([bar_ folderController]);
+
+ // The folder window should not have changed.
+ NSRect newToWindowFrame = [toWindow frame];
+ EXPECT_NSRECT_EQ(oldToWindowFrame, newToWindowFrame);
+
+ // Check button spacing.
+ [folderController validateMenuSpacing];
+}
+
+TEST_F(BookmarkBarFolderControllerMenuTest, DragParentOntoChild) {
+ BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
+ "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
+ "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
+ model_test_utils::AddNodesFromModelString(model, root, model_string);
+
+ // Validate initial model.
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(model_string, actualModelString);
+
+ // Pop up a folder menu.
+ BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"4f"];
+ ASSERT_TRUE(toFolder);
+ [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
+ withObject:toFolder];
+ BookmarkBarFolderController* folderController = [bar_ folderController];
+ EXPECT_TRUE(folderController);
+ NSWindow* toWindow = [folderController window];
+ EXPECT_TRUE(toWindow);
+ // Drag a folder button to one of its children.
+ BookmarkButton* draggedButton = [bar_ buttonWithTitleEqualTo:@"4f"];
+ ASSERT_TRUE(draggedButton);
+ BookmarkButton* targetButton =
+ [folderController buttonWithTitleEqualTo:@"4f3f"];
+ ASSERT_TRUE(targetButton);
+ [folderController dragButton:draggedButton
+ to:[targetButton top]
+ copy:NO];
+ // The model should not have changed.
+ EXPECT_EQ(model_string, model_test_utils::ModelStringFromNode(root));
+
+ // Check button spacing.
+ [folderController validateMenuSpacing];
+}
+
+TEST_F(BookmarkBarFolderControllerMenuTest, DragMoveChildToParent) {
+ BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
+ "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f:[ 4f2f1b "
+ "4f2f2b 4f2f3b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
+ model_test_utils::AddNodesFromModelString(model, root, model_string);
+
+ // Validate initial model.
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(model_string, actualModelString);
+
+ // Pop up a folder menu and a subfolder menu.
+ BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"4f"];
+ ASSERT_TRUE(toFolder);
+ [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
+ withObject:toFolder];
+ BookmarkBarFolderController* folderController = [bar_ folderController];
+ EXPECT_TRUE(folderController);
+ BookmarkButton* toSubfolder =
+ [folderController buttonWithTitleEqualTo:@"4f2f"];
+ ASSERT_TRUE(toSubfolder);
+ [[toSubfolder target] performSelector:@selector(openBookmarkFolderFromButton:)
+ withObject:toSubfolder];
+ BookmarkBarFolderController* subfolderController =
+ [folderController folderController];
+ EXPECT_TRUE(subfolderController);
+
+ // Drag a subfolder bookmark to the parent folder.
+ BookmarkButton* draggedButton =
+ [subfolderController buttonWithTitleEqualTo:@"4f2f3b"];
+ ASSERT_TRUE(draggedButton);
+ BookmarkButton* targetButton =
+ [folderController buttonWithTitleEqualTo:@"4f2f"];
+ ASSERT_TRUE(targetButton);
+ [folderController dragButton:draggedButton
+ to:[targetButton top]
+ copy:NO];
+ // The button should have landed above "4f2f".
+ const std::string expected_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b "
+ "2f2f3b ] 2f3b ] 3b 4f:[ 4f1f:[ 4f1f1b 4f1f2b 4f1f3b ] 4f2f3b 4f2f:[ "
+ "4f2f1b 4f2f2b ] 4f3f:[ 4f3f1b 4f3f2b 4f3f3b ] ] 5b ");
+ EXPECT_EQ(expected_string, model_test_utils::ModelStringFromNode(root));
+
+ // Check button spacing.
+ [folderController validateMenuSpacing];
+ // The window should not have gone away.
+ EXPECT_TRUE([bar_ folderController]);
+ // The subfolder should have gone away.
+ EXPECT_FALSE([folderController folderController]);
+}
+
+TEST_F(BookmarkBarFolderControllerMenuTest, DragWindowResizing) {
+ BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ const std::string
+ model_string("a b:[ b1 b2 b3 ] reallyReallyLongBookmarkName c ");
+ model_test_utils::AddNodesFromModelString(model, root, model_string);
+
+ // Validate initial model.
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(model_string, actualModelString);
+
+ // Pop up a folder menu.
+ BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"b"];
+ ASSERT_TRUE(toFolder);
+ [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
+ withObject:toFolder];
+ BookmarkBarFolderController* folderController = [bar_ folderController];
+ EXPECT_TRUE(folderController);
+ NSWindow* toWindow = [folderController window];
+ EXPECT_TRUE(toWindow);
+ CGFloat oldWidth = NSWidth([toWindow frame]);
+ // Drag the bookmark with a long name to the folder.
+ BookmarkButton* draggedButton =
+ [bar_ buttonWithTitleEqualTo:@"reallyReallyLongBookmarkName"];
+ ASSERT_TRUE(draggedButton);
+ BookmarkButton* targetButton =
+ [folderController buttonWithTitleEqualTo:@"b1"];
+ ASSERT_TRUE(targetButton);
+ [folderController dragButton:draggedButton
+ to:[targetButton center]
+ copy:NO];
+ // Verify the model change.
+ const std::string
+ expected_string("a b:[ b1 reallyReallyLongBookmarkName b2 b3 ] c ");
+ EXPECT_EQ(expected_string, model_test_utils::ModelStringFromNode(root));
+ // Verify the window grew. Just test a reasonable width gain.
+ CGFloat newWidth = NSWidth([toWindow frame]);
+ EXPECT_LT(oldWidth + 30.0, newWidth);
+}
+
+TEST_F(BookmarkBarFolderControllerMenuTest, MoveRemoveAddButtons) {
+ BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ const std::string model_string("1b 2f:[ 2f1b 2f2b 2f3b ] 3b 4b ");
+ model_test_utils::AddNodesFromModelString(model, root, model_string);
+
+ // Validate initial model.
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(model_string, actualModelString);
+
+ // Pop up a folder menu.
+ BookmarkButton* toFolder = [bar_ buttonWithTitleEqualTo:@"2f"];
+ ASSERT_TRUE(toFolder);
+ [[toFolder target] performSelector:@selector(openBookmarkFolderFromButton:)
+ withObject:toFolder];
+ BookmarkBarFolderController* folder = [bar_ folderController];
+ EXPECT_TRUE(folder);
+
+ // Remember how many buttons are showing.
+ NSArray* buttons = [folder buttons];
+ NSUInteger oldDisplayedButtons = [buttons count];
+
+ // Move a button around a bit.
+ [folder moveButtonFromIndex:0 toIndex:2];
+ EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:0] title]);
+ EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:1] title]);
+ EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:2] title]);
+ EXPECT_EQ(oldDisplayedButtons, [buttons count]);
+ [folder moveButtonFromIndex:2 toIndex:0];
+ EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:0] title]);
+ EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:1] title]);
+ EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:2] title]);
+ EXPECT_EQ(oldDisplayedButtons, [buttons count]);
+
+ // Add a couple of buttons.
+ const BookmarkNode* node = root->GetChild(2); // Purloin an existing node.
+ [folder addButtonForNode:node atIndex:0];
+ EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:0] title]);
+ EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:1] title]);
+ EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:2] title]);
+ EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:3] title]);
+ EXPECT_EQ(oldDisplayedButtons + 1, [buttons count]);
+ node = root->GetChild(3);
+ [folder addButtonForNode:node atIndex:-1];
+ EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:0] title]);
+ EXPECT_NSEQ(@"2f1b", [[buttons objectAtIndex:1] title]);
+ EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:2] title]);
+ EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:3] title]);
+ EXPECT_NSEQ(@"4b", [[buttons objectAtIndex:4] title]);
+ EXPECT_EQ(oldDisplayedButtons + 2, [buttons count]);
+
+ // Remove a couple of buttons.
+ [folder removeButton:4 animate:NO];
+ [folder removeButton:1 animate:NO];
+ EXPECT_NSEQ(@"3b", [[buttons objectAtIndex:0] title]);
+ EXPECT_NSEQ(@"2f2b", [[buttons objectAtIndex:1] title]);
+ EXPECT_NSEQ(@"2f3b", [[buttons objectAtIndex:2] title]);
+ EXPECT_EQ(oldDisplayedButtons, [buttons count]);
+
+ // Check button spacing.
+ [folder validateMenuSpacing];
+}
+
+TEST_F(BookmarkBarFolderControllerMenuTest, ControllerForNode) {
+ BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ const std::string model_string("1b 2f:[ 2f1b 2f2b ] 3b ");
+ model_test_utils::AddNodesFromModelString(model, root, model_string);
+
+ // Validate initial model.
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(model_string, actualModelString);
+
+ // Find the main bar controller.
+ const void* expectedController = bar_;
+ const void* actualController = [bar_ controllerForNode:root];
+ EXPECT_EQ(expectedController, actualController);
+
+ // Pop up the folder menu.
+ BookmarkButton* targetFolder = [bar_ buttonWithTitleEqualTo:@"2f"];
+ ASSERT_TRUE(targetFolder);
+ [[targetFolder target]
+ performSelector:@selector(openBookmarkFolderFromButton:)
+ withObject:targetFolder];
+ BookmarkBarFolderController* folder = [bar_ folderController];
+ EXPECT_TRUE(folder);
+
+ // Find the folder controller using the folder controller.
+ const BookmarkNode* targetNode = root->GetChild(1);
+ expectedController = folder;
+ actualController = [bar_ controllerForNode:targetNode];
+ EXPECT_EQ(expectedController, actualController);
+
+ // Find the folder controller from the bar.
+ actualController = [folder controllerForNode:targetNode];
+ EXPECT_EQ(expectedController, actualController);
+}
+
+TEST_F(BookmarkBarFolderControllerMenuTest, MenuSizingAndScrollArrows) {
+ BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ const std::string model_string("1b 2b 3b ");
+ model_test_utils::AddNodesFromModelString(model, root, model_string);
+
+ // Validate initial model.
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(model_string, actualModelString);
+
+ const BookmarkNode* parent = model.GetBookmarkBarNode();
+ const BookmarkNode* folder = model.AddGroup(parent,
+ parent->GetChildCount(),
+ ASCIIToUTF16("BIG"));
+
+ // Pop open the new folder window and verify it has one (empty) item.
+ BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"BIG"];
+ [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
+ withObject:button];
+ BookmarkBarFolderController* folderController = [bar_ folderController];
+ EXPECT_TRUE(folderController);
+ NSWindow* folderMenu = [folderController window];
+ EXPECT_TRUE(folderMenu);
+ CGFloat expectedHeight = (CGFloat)bookmarks::kBookmarkButtonHeight +
+ (2*bookmarks::kBookmarkVerticalPadding);
+ NSRect menuFrame = [folderMenu frame];
+ CGFloat menuHeight = NSHeight(menuFrame);
+ EXPECT_CGFLOAT_EQ(expectedHeight, menuHeight);
+ EXPECT_FALSE([folderController scrollable]);
+
+ // Now add a real bookmark and reopen.
+ model.AddURL(folder, folder->GetChildCount(), ASCIIToUTF16("a"),
+ GURL("http://a.com/"));
+ folderController = [bar_ folderController];
+ EXPECT_TRUE(folderController);
+ folderMenu = [folderController window];
+ EXPECT_TRUE(folderMenu);
+ menuFrame = [folderMenu frame];
+ menuHeight = NSHeight(menuFrame);
+ EXPECT_CGFLOAT_EQ(expectedHeight, menuHeight);
+ CGFloat menuWidth = NSWidth(menuFrame);
+ button = [folderController buttonWithTitleEqualTo:@"a"];
+ CGFloat buttonWidth = NSWidth([button frame]);
+ CGFloat expectedWidth =
+ buttonWidth + (2 * bookmarks::kBookmarkSubMenuHorizontalPadding);
+ EXPECT_CGFLOAT_EQ(expectedWidth, menuWidth);
+
+ // Add a wider bookmark and make sure the button widths match.
+ model.AddURL(folder, folder->GetChildCount(),
+ ASCIIToUTF16("A really, really long name"),
+ GURL("http://www.google.com/a"));
+ EXPECT_LT(menuWidth, NSWidth([folderMenu frame]));
+ EXPECT_LT(buttonWidth, NSWidth([button frame]));
+ buttonWidth = NSWidth([button frame]);
+ BookmarkButton* buttonB =
+ [folderController buttonWithTitleEqualTo:@"A really, really long name"];
+ EXPECT_TRUE(buttonB);
+ CGFloat buttonWidthB = NSWidth([buttonB frame]);
+ EXPECT_CGFLOAT_EQ(buttonWidth, buttonWidthB);
+ // Add a bunch of bookmarks until the window grows no more, then check for
+ // a scroll down arrow.
+ CGFloat oldMenuHeight = 0.0; // It just has to be different for first run.
+ menuHeight = NSHeight([folderMenu frame]);
+ NSUInteger tripWire = 0; // Prevent a runaway.
+ while (![folderController scrollable] && ++tripWire < 100) {
+ model.AddURL(folder, folder->GetChildCount(), ASCIIToUTF16("B"),
+ GURL("http://b.com/"));
+ oldMenuHeight = menuHeight;
+ menuHeight = NSHeight([folderMenu frame]);
+ }
+ EXPECT_TRUE([folderController scrollable]);
+ EXPECT_TRUE([folderController canScrollUp]);
+
+ // Remove one bookmark and make sure the scroll down arrow has been removed.
+ // We'll remove the really long node so we can see if the buttons get resized.
+ menuWidth = NSWidth([folderMenu frame]);
+ buttonWidth = NSWidth([button frame]);
+ model.Remove(folder, 1);
+ EXPECT_FALSE([folderController scrollable]);
+ EXPECT_FALSE([folderController canScrollUp]);
+ EXPECT_FALSE([folderController canScrollDown]);
+
+ // Check the size. It should have reduced.
+ EXPECT_GT(menuWidth, NSWidth([folderMenu frame]));
+ EXPECT_GT(buttonWidth, NSWidth([button frame]));
+
+ // Check button spacing.
+ [folderController validateMenuSpacing];
+}
+
+// See http://crbug.com/46101
+TEST_F(BookmarkBarFolderControllerMenuTest, HoverThenDeleteBookmark) {
+ BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ const BookmarkNode* folder = model.AddGroup(root,
+ root->GetChildCount(),
+ ASCIIToUTF16("BIG"));
+ for (int i = 0; i < kLotsOfNodesCount; i++)
+ model.AddURL(folder, folder->GetChildCount(), ASCIIToUTF16("kid"),
+ GURL("http://kid.com/smile"));
+
+ // Pop open the new folder window and hover one of its kids.
+ BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"BIG"];
+ [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
+ withObject:button];
+ BookmarkBarFolderController* bbfc = [bar_ folderController];
+ NSArray* buttons = [bbfc buttons];
+
+ // Hover over a button and verify that it is now known.
+ button = [buttons objectAtIndex:3];
+ BookmarkButton* buttonThatMouseIsIn = [bbfc buttonThatMouseIsIn];
+ EXPECT_FALSE(buttonThatMouseIsIn);
+ [bbfc mouseEnteredButton:button event:nil];
+ buttonThatMouseIsIn = [bbfc buttonThatMouseIsIn];
+ EXPECT_EQ(button, buttonThatMouseIsIn);
+
+ // Delete the bookmark and verify that it is now not known.
+ model.Remove(folder, 3);
+ buttonThatMouseIsIn = [bbfc buttonThatMouseIsIn];
+ EXPECT_FALSE(buttonThatMouseIsIn);
+}
+
+// Just like a BookmarkBarFolderController but intercedes when providing
+// pasteboard drag data.
+@interface BookmarkBarFolderControllerDragData : BookmarkBarFolderController {
+ const BookmarkNode* dragDataNode_; // Weak
+}
+- (void)setDragDataNode:(const BookmarkNode*)node;
+@end
+
+@implementation BookmarkBarFolderControllerDragData
+
+- (id)initWithParentButton:(BookmarkButton*)button
+ parentController:(BookmarkBarFolderController*)parentController
+ barController:(BookmarkBarController*)barController {
+ if ((self = [super initWithParentButton:button
+ parentController:parentController
+ barController:barController])) {
+ dragDataNode_ = NULL;
+ }
+ return self;
+}
+
+- (void)setDragDataNode:(const BookmarkNode*)node {
+ dragDataNode_ = node;
+}
+
+- (std::vector<const BookmarkNode*>)retrieveBookmarkNodeData {
+ std::vector<const BookmarkNode*> dragDataNodes;
+ if(dragDataNode_) {
+ dragDataNodes.push_back(dragDataNode_);
+ }
+ return dragDataNodes;
+}
+
+@end
+
+TEST_F(BookmarkBarFolderControllerMenuTest, DragBookmarkData) {
+ BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
+ "2f3b ] 3b 4b ");
+ model_test_utils::AddNodesFromModelString(model, root, model_string);
+ const BookmarkNode* other = model.other_node();
+ const std::string other_string("O1b O2b O3f:[ O3f1b O3f2f ] "
+ "O4f:[ O4f1b O4f2f ] 05b ");
+ model_test_utils::AddNodesFromModelString(model, other, other_string);
+
+ // Validate initial model.
+ std::string actual = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(model_string, actual);
+ actual = model_test_utils::ModelStringFromNode(other);
+ EXPECT_EQ(other_string, actual);
+
+ // Pop open a folder.
+ BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"];
+ scoped_nsobject<BookmarkBarFolderControllerDragData> folderController;
+ folderController.reset([[BookmarkBarFolderControllerDragData alloc]
+ initWithParentButton:button
+ parentController:nil
+ barController:bar_]);
+ BookmarkButton* targetButton =
+ [folderController buttonWithTitleEqualTo:@"2f1b"];
+ ASSERT_TRUE(targetButton);
+
+ // Gen up some dragging data.
+ const BookmarkNode* newNode = other->GetChild(2);
+ [folderController setDragDataNode:newNode];
+ scoped_nsobject<FakedDragInfo> dragInfo([[FakedDragInfo alloc] init]);
+ [dragInfo setDropLocation:[targetButton top]];
+ [folderController dragBookmarkData:(id<NSDraggingInfo>)dragInfo.get()];
+
+ // Verify the model.
+ const std::string expected("1b 2f:[ O3f:[ O3f1b O3f2f ] 2f1b 2f2f:[ 2f2f1b "
+ "2f2f2b 2f2f3b ] 2f3b ] 3b 4b ");
+ actual = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(expected, actual);
+
+ // Now drag over a folder button.
+ targetButton = [folderController buttonWithTitleEqualTo:@"2f2f"];
+ ASSERT_TRUE(targetButton);
+ newNode = other->GetChild(2); // Should be O4f.
+ EXPECT_EQ(newNode->GetTitle(), ASCIIToUTF16("O4f"));
+ [folderController setDragDataNode:newNode];
+ [dragInfo setDropLocation:[targetButton center]];
+ [folderController dragBookmarkData:(id<NSDraggingInfo>)dragInfo.get()];
+
+ // Verify the model.
+ const std::string expectedA("1b 2f:[ O3f:[ O3f1b O3f2f ] 2f1b 2f2f:[ "
+ "2f2f1b 2f2f2b 2f2f3b O4f:[ O4f1b O4f2f ] ] "
+ "2f3b ] 3b 4b ");
+ actual = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(expectedA, actual);
+
+ // Check button spacing.
+ [folderController validateMenuSpacing];
+}
+
+TEST_F(BookmarkBarFolderControllerMenuTest, DragBookmarkDataToTrash) {
+ BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
+ "2f3b ] 3b 4b ");
+ model_test_utils::AddNodesFromModelString(model, root, model_string);
+
+ // Validate initial model.
+ std::string actual = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(model_string, actual);
+
+ const BookmarkNode* folderNode = root->GetChild(1);
+ int oldFolderChildCount = folderNode->GetChildCount();
+
+ // Pop open a folder.
+ BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"];
+ scoped_nsobject<BookmarkBarFolderControllerDragData> folderController;
+ folderController.reset([[BookmarkBarFolderControllerDragData alloc]
+ initWithParentButton:button
+ parentController:nil
+ barController:bar_]);
+
+ // Drag a button to the trash.
+ BookmarkButton* buttonToDelete =
+ [folderController buttonWithTitleEqualTo:@"2f1b"];
+ ASSERT_TRUE(buttonToDelete);
+ EXPECT_TRUE([folderController canDragBookmarkButtonToTrash:buttonToDelete]);
+ [folderController didDragBookmarkToTrash:buttonToDelete];
+
+ // There should be one less button in the folder.
+ int newFolderChildCount = folderNode->GetChildCount();
+ EXPECT_EQ(oldFolderChildCount - 1, newFolderChildCount);
+ // Verify the model.
+ const std::string expected("1b 2f:[ 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
+ "2f3b ] 3b 4b ");
+ actual = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(expected, actual);
+
+ // Check button spacing.
+ [folderController validateMenuSpacing];
+}
+
+TEST_F(BookmarkBarFolderControllerMenuTest, AddURLs) {
+ BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
+ "2f3b ] 3b 4b ");
+ model_test_utils::AddNodesFromModelString(model, root, model_string);
+
+ // Validate initial model.
+ std::string actual = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(model_string, actual);
+
+ // Pop open a folder.
+ BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"];
+ [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
+ withObject:button];
+ BookmarkBarFolderController* folderController = [bar_ folderController];
+ EXPECT_TRUE(folderController);
+ NSArray* buttons = [folderController buttons];
+ EXPECT_TRUE(buttons);
+
+ // Remember how many buttons are showing.
+ int oldDisplayedButtons = [buttons count];
+
+ BookmarkButton* targetButton =
+ [folderController buttonWithTitleEqualTo:@"2f1b"];
+ ASSERT_TRUE(targetButton);
+
+ NSArray* urls = [NSArray arrayWithObjects: @"http://www.a.com/",
+ @"http://www.b.com/", nil];
+ NSArray* titles = [NSArray arrayWithObjects: @"SiteA", @"SiteB", nil];
+ [folderController addURLs:urls withTitles:titles at:[targetButton top]];
+
+ // There should two more buttons in the folder.
+ int newDisplayedButtons = [buttons count];
+ EXPECT_EQ(oldDisplayedButtons + 2, newDisplayedButtons);
+ // Verify the model.
+ const std::string expected("1b 2f:[ SiteA SiteB 2f1b 2f2f:[ 2f2f1b 2f2f2b "
+ "2f2f3b ] 2f3b ] 3b 4b ");
+ actual = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(expected, actual);
+
+ // Check button spacing.
+ [folderController validateMenuSpacing];
+}
+
+TEST_F(BookmarkBarFolderControllerMenuTest, DropPositionIndicator) {
+ BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b 2f2f3b ] "
+ "2f3b ] 3b 4b ");
+ model_test_utils::AddNodesFromModelString(model, root, model_string);
+
+ // Validate initial model.
+ std::string actual = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(model_string, actual);
+
+ // Pop open the folder.
+ BookmarkButton* button = [bar_ buttonWithTitleEqualTo:@"2f"];
+ [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
+ withObject:button];
+ BookmarkBarFolderController* folder = [bar_ folderController];
+ EXPECT_TRUE(folder);
+
+ // Test a series of points starting at the top of the folder.
+ const CGFloat yOffset = 0.5 * bookmarks::kBookmarkVerticalPadding;
+ BookmarkButton* targetButton = [folder buttonWithTitleEqualTo:@"2f1b"];
+ ASSERT_TRUE(targetButton);
+ NSPoint targetPoint = [targetButton top];
+ CGFloat pos = [folder indicatorPosForDragToPoint:targetPoint];
+ EXPECT_CGFLOAT_EQ(targetPoint.y + yOffset, pos);
+ pos = [folder indicatorPosForDragToPoint:[targetButton bottom]];
+ targetButton = [folder buttonWithTitleEqualTo:@"2f2f"];
+ EXPECT_CGFLOAT_EQ([targetButton top].y + yOffset, pos);
+ pos = [folder indicatorPosForDragToPoint:NSMakePoint(10,0)];
+ targetButton = [folder buttonWithTitleEqualTo:@"2f3b"];
+ EXPECT_CGFLOAT_EQ([targetButton bottom].y - yOffset, pos);
+}
+
+@interface BookmarkBarControllerNoDelete : BookmarkBarController
+- (IBAction)deleteBookmark:(id)sender;
+@end
+
+@implementation BookmarkBarControllerNoDelete
+- (IBAction)deleteBookmark:(id)sender {
+ // NOP
+}
+@end
+
+class BookmarkBarFolderControllerClosingTest : public
+ BookmarkBarFolderControllerMenuTest {
+ public:
+ BookmarkBarFolderControllerClosingTest() {
+ bar_.reset([[BookmarkBarControllerNoDelete alloc]
+ initWithBrowser:helper_.browser()
+ initialWidth:NSWidth([parent_view_ frame])
+ delegate:nil
+ resizeDelegate:resizeDelegate_.get()]);
+ InstallAndToggleBar(bar_.get());
+ }
+};
+
+TEST_F(BookmarkBarFolderControllerClosingTest, DeleteClosesFolder) {
+ BookmarkModel& model(*helper_.profile()->GetBookmarkModel());
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ const std::string model_string("1b 2f:[ 2f1b 2f2f:[ 2f2f1b 2f2f2b ] "
+ "2f3b ] 3b ");
+ model_test_utils::AddNodesFromModelString(model, root, model_string);
+
+ // Validate initial model.
+ std::string actualModelString = model_test_utils::ModelStringFromNode(root);
+ EXPECT_EQ(model_string, actualModelString);
+
+ // Open the folder menu and submenu.
+ BookmarkButton* target = [bar_ buttonWithTitleEqualTo:@"2f"];
+ ASSERT_TRUE(target);
+ [[target target] performSelector:@selector(openBookmarkFolderFromButton:)
+ withObject:target];
+ BookmarkBarFolderController* folder = [bar_ folderController];
+ EXPECT_TRUE(folder);
+ BookmarkButton* subTarget = [folder buttonWithTitleEqualTo:@"2f2f"];
+ ASSERT_TRUE(subTarget);
+ [[subTarget target] performSelector:@selector(openBookmarkFolderFromButton:)
+ withObject:subTarget];
+ BookmarkBarFolderController* subFolder = [folder folderController];
+ EXPECT_TRUE(subFolder);
+
+ // Delete the folder node and verify the window closed down by looking
+ // for its controller again.
+ [folder deleteBookmark:folder];
+ EXPECT_FALSE([folder folderController]);
+}
+
+// TODO(jrg): draggingEntered: and draggingExited: trigger timers so
+// they are hard to test. Factor out "fire timers" into routines
+// which can be overridden to fire immediately to make behavior
+// confirmable.
+// There is a similar problem with mouseEnteredButton: and
+// mouseExitedButton:.
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state.h
new file mode 100644
index 0000000..373e0e6
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state.h
@@ -0,0 +1,78 @@
+// 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 "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
+
+// Hover state machine. Encapsulates the hover state for
+// BookmarkBarFolderController.
+// A strict call order is implied with these calls. It is ONLY valid to make
+// the following state transitions:
+// From: To: Via:
+// closed opening scheduleOpen...:
+// opening closed cancelPendingOpen...: or
+// open scheduleOpen...: completes.
+// open closing scheduleClose...:
+// closing open cancelPendingClose...: or
+// closed scheduleClose...: completes.
+//
+@interface BookmarkBarFolderHoverState : NSObject {
+ @private
+ // Enumeration of the valid states that the |hoverButton_| member can be in.
+ // Because the opening and closing of hover views can be done asyncronously
+ // there are periods where the hover state is in transtion between open and
+ // closed. During those times of transition the opening or closing operation
+ // can be cancelled. We serialize the opening and closing of the
+ // |hoverButton_| using this state information. This serialization is to
+ // avoid race conditions where one hover button is being opened while another
+ // is closing.
+ enum HoverState {
+ kHoverStateClosed = 0,
+ kHoverStateOpening = 1,
+ kHoverStateOpen = 2,
+ kHoverStateClosing = 3
+ };
+
+ // Like normal menus, hovering over a folder button causes it to
+ // open. This variable is set when a hover is initiated (but has
+ // not necessarily fired yet).
+ scoped_nsobject<BookmarkButton> hoverButton_;
+
+ // We model hover state as a state machine with specific allowable
+ // transitions. |hoverState_| is the state of this machine at any
+ // given time.
+ HoverState hoverState_;
+}
+
+// Designated initializer.
+- (id)init;
+
+// The BookmarkBarFolderHoverState decides when it is appropriate to hide
+// and show the button that the BookmarkBarFolderController drags over.
+- (NSDragOperation)draggingEnteredButton:(BookmarkButton*)button;
+
+// The BookmarkBarFolderHoverState decides the fate of the hover button
+// when the BookmarkBarFolderController's view is exited.
+- (void)draggingExited;
+
+@end
+
+// Exposing these for unit testing purposes. They are used privately in the
+// implementation as well.
+@interface BookmarkBarFolderHoverState(PrivateAPI)
+// State change APIs.
+- (void)scheduleCloseBookmarkFolderOnHoverButton;
+- (void)cancelPendingCloseBookmarkFolderOnHoverButton;
+- (void)scheduleOpenBookmarkFolderOnHoverButton:(BookmarkButton*)hoverButton;
+- (void)cancelPendingOpenBookmarkFolderOnHoverButton;
+@end
+
+// Exposing these for unit testing purposes. They are used only in tests.
+@interface BookmarkBarFolderHoverState(TestingAPI)
+// Accessors and setters for button and hover state.
+- (BookmarkButton*)hoverButton;
+- (HoverState)hoverState;
+@end
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state.mm
new file mode 100644
index 0000000..b762bb3
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state.mm
@@ -0,0 +1,171 @@
+// 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 "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
+
+@interface BookmarkBarFolderHoverState(Private)
+- (void)setHoverState:(HoverState)state;
+- (void)closeBookmarkFolderOnHoverButton:(BookmarkButton*)button;
+- (void)openBookmarkFolderOnHoverButton:(BookmarkButton*)button;
+@end
+
+@implementation BookmarkBarFolderHoverState
+
+- (id)init {
+ if ((self = [super init])) {
+ hoverState_ = kHoverStateClosed;
+ }
+ return self;
+}
+
+- (NSDragOperation)draggingEnteredButton:(BookmarkButton*)button {
+ if ([button isFolder]) {
+ if (hoverButton_ == button) {
+ // CASE A: hoverButton_ == button implies we've dragged over
+ // the same folder so no need to open or close anything new.
+ } else if (hoverButton_ &&
+ hoverButton_ != button) {
+ // CASE B: we have a hoverButton_ but it is different from the new button.
+ // This implies we've dragged over a new folder, so we'll close the old
+ // and open the new.
+ // Note that we only schedule the open or close if we have no other tasks
+ // currently pending.
+
+ if (hoverState_ == kHoverStateOpen) {
+ // Close the old.
+ [self scheduleCloseBookmarkFolderOnHoverButton];
+ } else if (hoverState_ == kHoverStateClosed) {
+ // Open the new.
+ [self scheduleOpenBookmarkFolderOnHoverButton:button];
+ }
+ } else if (!hoverButton_) {
+ // CASE C: we don't have a current hoverButton_ but we have dragged onto
+ // a new folder so we open the new one.
+ [self scheduleOpenBookmarkFolderOnHoverButton:button];
+ }
+ } else if (!button) {
+ if (hoverButton_) {
+ // CASE D: We have a hoverButton_ but we've moved onto an area that
+ // requires no hover. We close the hoverButton_ in this case. This
+ // means cancelling if the open is pending (i.e. |kHoverStateOpening|)
+ // or closing if we don't alrealy have once in progress.
+
+ // Intiate close only if we have not already done so.
+ if (hoverState_ == kHoverStateOpening) {
+ // Cancel the pending open.
+ [self cancelPendingOpenBookmarkFolderOnHoverButton];
+ } else if (hoverState_ != kHoverStateClosing) {
+ // Schedule the close.
+ [self scheduleCloseBookmarkFolderOnHoverButton];
+ }
+ } else {
+ // CASE E: We have neither a hoverButton_ nor a new button that requires
+ // a hover. In this case we do nothing.
+ }
+ }
+
+ return NSDragOperationMove;
+}
+
+- (void)draggingExited {
+ if (hoverButton_) {
+ if (hoverState_ == kHoverStateOpening) {
+ [self cancelPendingOpenBookmarkFolderOnHoverButton];
+ } else if (hoverState_ == kHoverStateClosing) {
+ [self cancelPendingCloseBookmarkFolderOnHoverButton];
+ }
+ }
+}
+
+// Schedule close of hover button. Transition to kHoverStateClosing state.
+- (void)scheduleCloseBookmarkFolderOnHoverButton {
+ DCHECK(hoverButton_);
+ [self setHoverState:kHoverStateClosing];
+ [self performSelector:@selector(closeBookmarkFolderOnHoverButton:)
+ withObject:hoverButton_
+ afterDelay:bookmarks::kDragHoverCloseDelay];
+}
+
+// Cancel pending hover close. Transition to kHoverStateOpen state.
+- (void)cancelPendingCloseBookmarkFolderOnHoverButton {
+ [self setHoverState:kHoverStateOpen];
+ [NSObject
+ cancelPreviousPerformRequestsWithTarget:self
+ selector:@selector(closeBookmarkFolderOnHoverButton:)
+ object:hoverButton_];
+}
+
+// Schedule open of hover button. Transition to kHoverStateOpening state.
+- (void)scheduleOpenBookmarkFolderOnHoverButton:(BookmarkButton*)button {
+ DCHECK(button);
+ hoverButton_.reset([button retain]);
+ [self setHoverState:kHoverStateOpening];
+ [self performSelector:@selector(openBookmarkFolderOnHoverButton:)
+ withObject:hoverButton_
+ afterDelay:bookmarks::kDragHoverOpenDelay];
+}
+
+// Cancel pending hover open. Transition to kHoverStateClosed state.
+- (void)cancelPendingOpenBookmarkFolderOnHoverButton {
+ [self setHoverState:kHoverStateClosed];
+ [NSObject
+ cancelPreviousPerformRequestsWithTarget:self
+ selector:@selector(openBookmarkFolderOnHoverButton:)
+ object:hoverButton_];
+ hoverButton_.reset();
+}
+
+// Hover button accessor. For testing only.
+- (BookmarkButton*)hoverButton {
+ return hoverButton_;
+}
+
+// Hover state accessor. For testing only.
+- (HoverState)hoverState {
+ return hoverState_;
+}
+
+// This method encodes the rules of our |hoverButton_| state machine. Only
+// specific state transitions are allowable (encoded in the DCHECK).
+// Note that there is no state for simultaneously opening and closing. A
+// pending open must complete before scheduling a close, and vice versa. And
+// it is not possible to make a transition directly from open to closed, and
+// vice versa.
+- (void)setHoverState:(HoverState)state {
+ DCHECK(
+ (hoverState_ == kHoverStateClosed && state == kHoverStateOpening) ||
+ (hoverState_ == kHoverStateOpening && state == kHoverStateClosed) ||
+ (hoverState_ == kHoverStateOpening && state == kHoverStateOpen) ||
+ (hoverState_ == kHoverStateOpen && state == kHoverStateClosing) ||
+ (hoverState_ == kHoverStateClosing && state == kHoverStateOpen) ||
+ (hoverState_ == kHoverStateClosing && state == kHoverStateClosed)
+ ) << "bad transition: old = " << hoverState_ << " new = " << state;
+
+ hoverState_ = state;
+}
+
+// Called after a delay to close a previously hover-opened folder.
+// Note: this method is not meant to be invoked directly, only through
+// a delayed call to |scheduleCloseBookmarkFolderOnHoverButton:|.
+- (void)closeBookmarkFolderOnHoverButton:(BookmarkButton*)button {
+ [NSObject
+ cancelPreviousPerformRequestsWithTarget:self
+ selector:@selector(closeBookmarkFolderOnHoverButton:)
+ object:hoverButton_];
+ [self setHoverState:kHoverStateClosed];
+ [[button target] closeBookmarkFolder:button];
+ hoverButton_.reset();
+}
+
+// Called after a delay to open a new hover folder.
+// Note: this method is not meant to be invoked directly, only through
+// a delayed call to |scheduleOpenBookmarkFolderOnHoverButton:|.
+- (void)openBookmarkFolderOnHoverButton:(BookmarkButton*)button {
+ [self setHoverState:kHoverStateOpen];
+ [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
+ withObject:button];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state_unittest.mm
new file mode 100644
index 0000000..3d0a50f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state_unittest.mm
@@ -0,0 +1,77 @@
+// 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 "base/message_loop.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state.h"
+#import "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+
+namespace {
+
+typedef CocoaTest BookmarkBarFolderHoverStateTest;
+
+// Hover state machine interface.
+// A strict call order is implied with these calls. It is ONLY valid to make
+// these specific state transitions.
+TEST(BookmarkBarFolderHoverStateTest, HoverState) {
+ BrowserTestHelper helper;
+ scoped_nsobject<BookmarkBarFolderHoverState> bbfhs;
+ bbfhs.reset([[BookmarkBarFolderHoverState alloc] init]);
+
+ // Initial state.
+ EXPECT_FALSE([bbfhs hoverButton]);
+ ASSERT_EQ(kHoverStateClosed, [bbfhs hoverState]);
+
+ scoped_nsobject<BookmarkButton> button;
+ button.reset([[BookmarkButton alloc] initWithFrame:NSMakeRect(0, 0, 20, 20)]);
+
+ // Test transition from closed to opening.
+ ASSERT_EQ(kHoverStateClosed, [bbfhs hoverState]);
+ [bbfhs scheduleOpenBookmarkFolderOnHoverButton:button];
+ ASSERT_EQ(kHoverStateOpening, [bbfhs hoverState]);
+
+ // Test transition from opening to closed (aka cancel open).
+ [bbfhs cancelPendingOpenBookmarkFolderOnHoverButton];
+ ASSERT_EQ(kHoverStateClosed, [bbfhs hoverState]);
+ ASSERT_EQ(nil, [bbfhs hoverButton]);
+
+ // Test transition from closed to opening.
+ ASSERT_EQ(kHoverStateClosed, [bbfhs hoverState]);
+ [bbfhs scheduleOpenBookmarkFolderOnHoverButton:button];
+ ASSERT_EQ(kHoverStateOpening, [bbfhs hoverState]);
+
+ // Test transition from opening to opened.
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ new MessageLoop::QuitTask,
+ bookmarks::kDragHoverOpenDelay * 1000.0 * 1.5);
+ MessageLoop::current()->Run();
+ ASSERT_EQ(kHoverStateOpen, [bbfhs hoverState]);
+ ASSERT_EQ(button, [bbfhs hoverButton]);
+
+ // Test transition from opening to opened.
+ [bbfhs scheduleCloseBookmarkFolderOnHoverButton];
+ ASSERT_EQ(kHoverStateClosing, [bbfhs hoverState]);
+
+ // Test transition from closing to open (aka cancel close).
+ [bbfhs cancelPendingCloseBookmarkFolderOnHoverButton];
+ ASSERT_EQ(kHoverStateOpen, [bbfhs hoverState]);
+ ASSERT_EQ(button, [bbfhs hoverButton]);
+
+ // Test transition from closing to closed.
+ [bbfhs scheduleCloseBookmarkFolderOnHoverButton];
+ ASSERT_EQ(kHoverStateClosing, [bbfhs hoverState]);
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ new MessageLoop::QuitTask,
+ bookmarks::kDragHoverCloseDelay * 1000.0 * 1.5);
+ MessageLoop::current()->Run();
+ ASSERT_EQ(kHoverStateClosed, [bbfhs hoverState]);
+ ASSERT_EQ(nil, [bbfhs hoverButton]);
+}
+
+} // namespace
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_view.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view.h
index 8f60b8e..8f60b8e 100644
--- a/chrome/browser/cocoa/bookmarks/bookmark_bar_folder_view.h
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view.h
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view.mm
new file mode 100644
index 0000000..5a451a8
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view.mm
@@ -0,0 +1,204 @@
+// 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 "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view.h"
+
+#include "chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h"
+#import "third_party/mozilla/NSPasteboard+Utils.h"
+
+@implementation BookmarkBarFolderView
+
+@synthesize dropIndicatorShown = dropIndicatorShown_;
+@synthesize dropIndicatorPosition = dropIndicatorPosition_;
+
+- (void)awakeFromNib {
+ NSArray* types = [NSArray arrayWithObjects:
+ NSStringPboardType,
+ NSHTMLPboardType,
+ NSURLPboardType,
+ kBookmarkButtonDragType,
+ kBookmarkDictionaryListPboardType,
+ nil];
+ [self registerForDraggedTypes:types];
+}
+
+- (void)dealloc {
+ [self unregisterDraggedTypes];
+ [super dealloc];
+}
+
+- (id<BookmarkButtonControllerProtocol>)controller {
+ // When needed for testing, set the local data member |controller_| to
+ // the test controller.
+ return controller_ ? controller_ : [[self window] windowController];
+}
+
+- (void)setController:(id)controller {
+ controller_ = controller;
+}
+
+- (void)drawRect:(NSRect)rect {
+ // TODO(jrg): copied from bookmark_bar_view but orientation changed.
+ // Code dup sucks but I'm not sure I can take 16 lines and make it
+ // generic for horiz vs vertical while keeping things simple.
+ // TODO(jrg): when throwing it all away and using animations, try
+ // hard to make a common routine for both.
+ // http://crbug.com/35966, http://crbug.com/35968
+
+ // Draw the bookmark-button-dragging drop indicator if necessary.
+ if (dropIndicatorShown_) {
+ const CGFloat kBarHeight = 1;
+ const CGFloat kBarHorizPad = 4;
+ const CGFloat kBarOpacity = 0.85;
+
+ NSRect uglyBlackBar =
+ NSMakeRect(kBarHorizPad, dropIndicatorPosition_,
+ NSWidth([self bounds]) - 2*kBarHorizPad,
+ kBarHeight);
+ NSColor* uglyBlackBarColor = [NSColor blackColor];
+ [[uglyBlackBarColor colorWithAlphaComponent:kBarOpacity] setFill];
+ [[NSBezierPath bezierPathWithRect:uglyBlackBar] fill];
+ }
+}
+
+// TODO(mrossetti,jrg): Identical to -[BookmarkBarView
+// dragClipboardContainsBookmarks]. http://crbug.com/35966
+// Shim function to assist in unit testing.
+- (BOOL)dragClipboardContainsBookmarks {
+ return bookmark_pasteboard_helper_mac::DragClipboardContainsBookmarks();
+}
+
+// Virtually identical to [BookmarkBarView draggingEntered:].
+// TODO(jrg): find a way to share code. Lack of multiple inheritance
+// makes things more of a pain but there should be no excuse for laziness.
+// http://crbug.com/35966
+- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info {
+ inDrag_ = YES;
+ if ([[info draggingPasteboard] dataForType:kBookmarkButtonDragType] ||
+ [self dragClipboardContainsBookmarks] ||
+ [[info draggingPasteboard] containsURLData]) {
+ // Find the position of the drop indicator.
+ BOOL showIt = [[self controller]
+ shouldShowIndicatorShownForPoint:[info draggingLocation]];
+ if (!showIt) {
+ if (dropIndicatorShown_) {
+ dropIndicatorShown_ = NO;
+ [self setNeedsDisplay:YES];
+ }
+ } else {
+ CGFloat y =
+ [[self controller]
+ indicatorPosForDragToPoint:[info draggingLocation]];
+
+ // Need an update if the indicator wasn't previously shown or if it has
+ // moved.
+ if (!dropIndicatorShown_ || dropIndicatorPosition_ != y) {
+ dropIndicatorShown_ = YES;
+ dropIndicatorPosition_ = y;
+ [self setNeedsDisplay:YES];
+ }
+ }
+
+ [[self controller] draggingEntered:info]; // allow hover-open to work
+ return [info draggingSource] ? NSDragOperationMove : NSDragOperationCopy;
+ }
+ return NSDragOperationNone;
+}
+
+- (void)draggingExited:(id<NSDraggingInfo>)info {
+ [[self controller] draggingExited:info];
+
+ // Regardless of the type of dragging which ended, we need to get rid of the
+ // drop indicator if one was shown.
+ if (dropIndicatorShown_) {
+ dropIndicatorShown_ = NO;
+ [self setNeedsDisplay:YES];
+ }
+}
+
+- (void)draggingEnded:(id<NSDraggingInfo>)info {
+ // Awkwardness since views open and close out from under us.
+ if (inDrag_) {
+ inDrag_ = NO;
+ }
+
+ [self draggingExited:info];
+}
+
+- (BOOL)wantsPeriodicDraggingUpdates {
+ // TODO(jrg): This should probably return |YES| and the controller should
+ // slide the existing bookmark buttons interactively to the side to make
+ // room for the about-to-be-dropped bookmark.
+ // http://crbug.com/35968
+ return NO;
+}
+
+- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)info {
+ // For now it's the same as draggingEntered:.
+ // TODO(jrg): once we return YES for wantsPeriodicDraggingUpdates,
+ // this should ping the [self controller] to perform animations.
+ // http://crbug.com/35968
+ return [self draggingEntered:info];
+}
+
+- (BOOL)prepareForDragOperation:(id<NSDraggingInfo>)info {
+ return YES;
+}
+
+// This code is practically identical to the same function in BookmarkBarView
+// with the only difference being how the controller is retrieved.
+// TODO(mrossetti,jrg): http://crbug.com/35966
+// Implement NSDraggingDestination protocol method
+// performDragOperation: for URLs.
+- (BOOL)performDragOperationForURL:(id<NSDraggingInfo>)info {
+ NSPasteboard* pboard = [info draggingPasteboard];
+ DCHECK([pboard containsURLData]);
+
+ NSArray* urls = nil;
+ NSArray* titles = nil;
+ [pboard getURLs:&urls andTitles:&titles convertingFilenames:YES];
+
+ return [[self controller] addURLs:urls
+ withTitles:titles
+ at:[info draggingLocation]];
+}
+
+// This code is practically identical to the same function in BookmarkBarView
+// with the only difference being how the controller is retrieved.
+// http://crbug.com/35966
+// Implement NSDraggingDestination protocol method
+// performDragOperation: for bookmark buttons.
+- (BOOL)performDragOperationForBookmarkButton:(id<NSDraggingInfo>)info {
+ BOOL doDrag = NO;
+ NSData* data = [[info draggingPasteboard]
+ dataForType:kBookmarkButtonDragType];
+ // [info draggingSource] is nil if not the same application.
+ if (data && [info draggingSource]) {
+ BookmarkButton* button = nil;
+ [data getBytes:&button length:sizeof(button)];
+ BOOL copy = !([info draggingSourceOperationMask] & NSDragOperationMove);
+ doDrag = [[self controller] dragButton:button
+ to:[info draggingLocation]
+ copy:copy];
+ UserMetrics::RecordAction(UserMetricsAction("BookmarkBarFolder_DragEnd"));
+ }
+ return doDrag;
+}
+
+- (BOOL)performDragOperation:(id<NSDraggingInfo>)info {
+ if ([[self controller] dragBookmarkData:info])
+ return YES;
+ NSPasteboard* pboard = [info draggingPasteboard];
+ if ([pboard dataForType:kBookmarkButtonDragType] &&
+ [self performDragOperationForBookmarkButton:info])
+ return YES;
+ if ([pboard containsURLData] && [self performDragOperationForURL:info])
+ return YES;
+ return NO;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view_unittest.mm
new file mode 100644
index 0000000..07aca2b
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view_unittest.mm
@@ -0,0 +1,211 @@
+// 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.
+
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_view.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/url_drop_target.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+#import "third_party/mozilla/NSPasteboard+Utils.h"
+
+namespace {
+ const CGFloat kFakeIndicatorPos = 7.0;
+};
+
+// Fake DraggingInfo, fake BookmarkBarController, fake NSPasteboard...
+@interface FakeDraggingInfo : NSObject {
+ @public
+ BOOL dragButtonToPong_;
+ BOOL dragURLsPong_;
+ BOOL dragBookmarkDataPong_;
+ BOOL dropIndicatorShown_;
+ BOOL draggingEnteredCalled_;
+ // Only mock one type of drag data at a time.
+ NSString* dragDataType_;
+}
+@property (readwrite) BOOL dropIndicatorShown;
+@property (readwrite) BOOL draggingEnteredCalled;
+@property (copy) NSString* dragDataType;
+@end
+
+@implementation FakeDraggingInfo
+
+@synthesize dropIndicatorShown = dropIndicatorShown_;
+@synthesize draggingEnteredCalled = draggingEnteredCalled_;
+@synthesize dragDataType = dragDataType_;
+
+- (id)init {
+ if ((self = [super init])) {
+ dropIndicatorShown_ = YES;
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [dragDataType_ release];
+ [super dealloc];
+}
+
+- (void)reset {
+ [dragDataType_ release];
+ dragDataType_ = nil;
+ dragButtonToPong_ = NO;
+ dragURLsPong_ = NO;
+ dragBookmarkDataPong_ = NO;
+ dropIndicatorShown_ = YES;
+ draggingEnteredCalled_ = NO;
+}
+
+// NSDragInfo mocking functions.
+
+- (id)draggingPasteboard {
+ return self;
+}
+
+// So we can look local.
+- (id)draggingSource {
+ return self;
+}
+
+- (NSDragOperation)draggingSourceOperationMask {
+ return NSDragOperationCopy | NSDragOperationMove;
+}
+
+- (NSPoint)draggingLocation {
+ return NSMakePoint(10, 10);
+}
+
+// NSPasteboard mocking functions.
+
+- (BOOL)containsURLData {
+ NSArray* urlTypes = [URLDropTargetHandler handledDragTypes];
+ if (dragDataType_)
+ return [urlTypes containsObject:dragDataType_];
+ return NO;
+}
+
+- (NSData*)dataForType:(NSString*)type {
+ if (dragDataType_ && [dragDataType_ isEqualToString:type])
+ return [NSData data]; // Return something, anything.
+ return nil;
+}
+
+// Fake a controller for callback ponging
+
+- (BOOL)dragButton:(BookmarkButton*)button to:(NSPoint)point copy:(BOOL)copy {
+ dragButtonToPong_ = YES;
+ return YES;
+}
+
+- (BOOL)addURLs:(NSArray*)urls withTitles:(NSArray*)titles at:(NSPoint)point {
+ dragURLsPong_ = YES;
+ return YES;
+}
+
+- (void)getURLs:(NSArray**)outUrls
+ andTitles:(NSArray**)outTitles
+ convertingFilenames:(BOOL)convertFilenames {
+}
+
+- (BOOL)dragBookmarkData:(id<NSDraggingInfo>)info {
+ dragBookmarkDataPong_ = YES;
+ return NO;
+}
+
+// Confirm the pongs.
+
+- (BOOL)dragButtonToPong {
+ return dragButtonToPong_;
+}
+
+- (BOOL)dragURLsPong {
+ return dragURLsPong_;
+}
+
+- (BOOL)dragBookmarkDataPong {
+ return dragBookmarkDataPong_;
+}
+
+- (CGFloat)indicatorPosForDragToPoint:(NSPoint)point {
+ return kFakeIndicatorPos;
+}
+
+- (BOOL)shouldShowIndicatorShownForPoint:(NSPoint)point {
+ return dropIndicatorShown_;
+}
+
+- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info {
+ draggingEnteredCalled_ = YES;
+ return NSDragOperationNone;
+}
+
+@end
+
+namespace {
+
+class BookmarkBarFolderViewTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ view_.reset([[BookmarkBarFolderView alloc] init]);
+ }
+
+ scoped_nsobject<BookmarkBarFolderView> view_;
+};
+
+TEST_F(BookmarkBarFolderViewTest, BookmarkButtonDragAndDrop) {
+ [view_ awakeFromNib];
+ scoped_nsobject<FakeDraggingInfo> info([[FakeDraggingInfo alloc] init]);
+ [view_ setController:info.get()];
+ [info reset];
+
+ [info setDragDataType:kBookmarkButtonDragType];
+ EXPECT_EQ([view_ draggingEntered:(id)info.get()], NSDragOperationMove);
+ EXPECT_TRUE([view_ performDragOperation:(id)info.get()]);
+ EXPECT_TRUE([info dragButtonToPong]);
+ EXPECT_FALSE([info dragURLsPong]);
+ EXPECT_TRUE([info dragBookmarkDataPong]);
+}
+
+TEST_F(BookmarkBarFolderViewTest, URLDragAndDrop) {
+ [view_ awakeFromNib];
+ scoped_nsobject<FakeDraggingInfo> info([[FakeDraggingInfo alloc] init]);
+ [view_ setController:info.get()];
+ [info reset];
+
+ NSArray* dragTypes = [URLDropTargetHandler handledDragTypes];
+ for (NSString* type in dragTypes) {
+ [info setDragDataType:type];
+ EXPECT_EQ([view_ draggingEntered:(id)info.get()], NSDragOperationMove);
+ EXPECT_TRUE([view_ performDragOperation:(id)info.get()]);
+ EXPECT_FALSE([info dragButtonToPong]);
+ EXPECT_TRUE([info dragURLsPong]);
+ EXPECT_TRUE([info dragBookmarkDataPong]);
+ [info reset];
+ }
+}
+
+TEST_F(BookmarkBarFolderViewTest, BookmarkButtonDropIndicator) {
+ [view_ awakeFromNib];
+ scoped_nsobject<FakeDraggingInfo> info([[FakeDraggingInfo alloc] init]);
+ [view_ setController:info.get()];
+ [info reset];
+
+ [info setDragDataType:kBookmarkButtonDragType];
+ EXPECT_FALSE([info draggingEnteredCalled]);
+ EXPECT_EQ([view_ draggingEntered:(id)info.get()], NSDragOperationMove);
+ EXPECT_TRUE([info draggingEnteredCalled]); // Ensure controller pinged.
+ EXPECT_TRUE([view_ dropIndicatorShown]);
+ EXPECT_EQ([view_ dropIndicatorPosition], kFakeIndicatorPos);
+
+ [info setDropIndicatorShown:NO];
+ EXPECT_EQ([view_ draggingEntered:(id)info.get()], NSDragOperationMove);
+ EXPECT_FALSE([view_ dropIndicatorShown]);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.h
new file mode 100644
index 0000000..cd97d9e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.h
@@ -0,0 +1,34 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_FOLDER_WINDOW_H_
+#define CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_FOLDER_WINDOW_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_nsobject.h"
+
+
+// Window for a bookmark folder "menu". This menu pops up when you
+// click on a bookmark button that represents a folder of bookmarks.
+// This window is borderless.
+@interface BookmarkBarFolderWindow : NSWindow
+@end
+
+// Content view for the above window. "Stock" other than the drawing
+// of rounded corners. Only used in the nib.
+@interface BookmarkBarFolderWindowContentView : NSView {
+ // Arrows to show ability to scroll up and down as needed.
+ scoped_nsobject<NSImage> arrowUpImage_;
+ scoped_nsobject<NSImage> arrowDownImage_;
+}
+@end
+
+// Scroll view that contains the main view (where the buttons go).
+@interface BookmarkBarFolderWindowScrollView : NSScrollView
+@end
+
+
+#endif // CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_FOLDER_WINDOW_H_
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.mm
new file mode 100644
index 0000000..65cb664
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.mm
@@ -0,0 +1,136 @@
+// 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 "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.h"
+
+#import "base/logging.h"
+#include "app/mac/nsimage_cache.h"
+#import "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h"
+#import "chrome/browser/ui/cocoa/image_utils.h"
+#import "third_party/GTM/AppKit/GTMNSColor+Luminance.h"
+#import "third_party/GTM/AppKit/GTMNSBezierPath+RoundRect.h"
+
+
+@implementation BookmarkBarFolderWindow
+
+- (id)initWithContentRect:(NSRect)contentRect
+ styleMask:(NSUInteger)windowStyle
+ backing:(NSBackingStoreType)bufferingType
+ defer:(BOOL)deferCreation {
+ if ((self = [super initWithContentRect:contentRect
+ styleMask:NSBorderlessWindowMask // override
+ backing:bufferingType
+ defer:deferCreation])) {
+ [self setBackgroundColor:[NSColor clearColor]];
+ [self setOpaque:NO];
+ }
+ return self;
+}
+
+@end
+
+
+namespace {
+// Corner radius for our bookmark bar folder window.
+// Copied from bubble_view.mm.
+const CGFloat kViewCornerRadius = 4.0;
+}
+
+@implementation BookmarkBarFolderWindowContentView
+
+- (void)awakeFromNib {
+ arrowUpImage_.reset(
+ [app::mac::GetCachedImageWithName(@"menu_overflow_up.pdf") retain]);
+ arrowDownImage_.reset(
+ [app::mac::GetCachedImageWithName(@"menu_overflow_down.pdf") retain]);
+}
+
+// Draw the arrows at the top and bottom of the folder window as a
+// visual indication that scrolling is possible. We always draw the
+// scrolling arrows; when not relevant (e.g. when not scrollable), the
+// scroll view overlaps the window and the arrows aren't visible.
+- (void)drawScrollArrows:(NSRect)rect {
+ NSRect visibleRect = [self bounds];
+
+ // On top
+ NSRect imageRect = NSZeroRect;
+ imageRect.size = [arrowUpImage_ size];
+ NSRect drawRect = NSOffsetRect(
+ imageRect,
+ (NSWidth(visibleRect) - NSWidth(imageRect)) / 2,
+ NSHeight(visibleRect) - NSHeight(imageRect));
+ [arrowUpImage_ drawInRect:drawRect
+ fromRect:imageRect
+ operation:NSCompositeSourceOver
+ fraction:1.0
+ neverFlipped:YES];
+
+ // On bottom
+ imageRect = NSZeroRect;
+ imageRect.size = [arrowDownImage_ size];
+ drawRect = NSOffsetRect(imageRect,
+ (NSWidth(visibleRect) - NSWidth(imageRect)) / 2,
+ 0);
+ [arrowDownImage_ drawInRect:drawRect
+ fromRect:imageRect
+ operation:NSCompositeSourceOver
+ fraction:1.0
+ neverFlipped:YES];
+}
+
+- (void)drawRect:(NSRect)rect {
+ NSRect bounds = [self bounds];
+ // Like NSMenus, only the bottom corners are rounded.
+ NSBezierPath* bezier =
+ [NSBezierPath gtm_bezierPathWithRoundRect:bounds
+ topLeftCornerRadius:0
+ topRightCornerRadius:0
+ bottomLeftCornerRadius:kViewCornerRadius
+ bottomRightCornerRadius:kViewCornerRadius];
+ [bezier closePath];
+
+ // TODO(jrg): share code with info_bubble_view.mm? Or bubble_view.mm?
+ NSColor* base_color = [NSColor colorWithCalibratedWhite:0.5 alpha:1.0];
+ NSColor* startColor =
+ [base_color gtm_colorAdjustedFor:GTMColorationLightHighlight
+ faded:YES];
+ NSColor* midColor =
+ [base_color gtm_colorAdjustedFor:GTMColorationLightMidtone
+ faded:YES];
+ NSColor* endColor =
+ [base_color gtm_colorAdjustedFor:GTMColorationLightShadow
+ faded:YES];
+ NSColor* glowColor =
+ [base_color gtm_colorAdjustedFor:GTMColorationLightPenumbra
+ faded:YES];
+
+ scoped_nsobject<NSGradient> gradient(
+ [[NSGradient alloc] initWithColorsAndLocations:startColor, 0.0,
+ midColor, 0.25,
+ endColor, 0.5,
+ glowColor, 0.75,
+ nil]);
+ [gradient drawInBezierPath:bezier angle:0.0];
+
+ [self drawScrollArrows:rect];
+}
+
+@end
+
+
+@implementation BookmarkBarFolderWindowScrollView
+
+// We want "draw background" of the NSScrollView in the xib to be NOT
+// checked. That allows us to round the bottom corners of the folder
+// window. However that also allows some scrollWheel: events to leak
+// into the NSWindow behind it (even in a different application).
+// Better to plug the scroll leak than to round corners for M5.
+- (void)scrollWheel:(NSEvent *)theEvent {
+ DCHECK([[[self window] windowController]
+ respondsToSelector:@selector(scrollWheel:)]);
+ [[[self window] windowController] scrollWheel:theEvent];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window_unittest.mm
new file mode 100644
index 0000000..7dd6c06
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window_unittest.mm
@@ -0,0 +1,49 @@
+// 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.
+
+#include "base/scoped_ptr.h"
+#include "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_window.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+class BookmarkBarFolderWindowTest : public CocoaTest {
+};
+
+TEST_F(BookmarkBarFolderWindowTest, Borderless) {
+ scoped_nsobject<BookmarkBarFolderWindow> window_;
+ window_.reset([[BookmarkBarFolderWindow alloc]
+ initWithContentRect:NSMakeRect(0,0,20,20)
+ styleMask:0
+ backing:NSBackingStoreBuffered
+ defer:NO]);
+ EXPECT_EQ(NSBorderlessWindowMask, [window_ styleMask]);
+}
+
+
+class BookmarkBarFolderWindowContentViewTest : public CocoaTest {
+ public:
+ BookmarkBarFolderWindowContentViewTest() {
+ view_.reset([[BookmarkBarFolderWindowContentView alloc]
+ initWithFrame:NSMakeRect(0, 0, 100, 100)]);
+ [[test_window() contentView] addSubview:view_.get()];
+ }
+ scoped_nsobject<BookmarkBarFolderWindowContentView> view_;
+ scoped_nsobject<BookmarkBarFolderWindowScrollView> scroll_view_;
+};
+
+TEST_VIEW(BookmarkBarFolderWindowContentViewTest, view_);
+
+
+class BookmarkBarFolderWindowScrollViewTest : public CocoaTest {
+ public:
+ BookmarkBarFolderWindowScrollViewTest() {
+ scroll_view_.reset([[BookmarkBarFolderWindowScrollView alloc]
+ initWithFrame:NSMakeRect(0, 0, 100, 100)]);
+ [[test_window() contentView] addSubview:scroll_view_.get()];
+ }
+ scoped_nsobject<BookmarkBarFolderWindowScrollView> scroll_view_;
+};
+
+TEST_VIEW(BookmarkBarFolderWindowScrollViewTest, scroll_view_);
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_state.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_state.h
new file mode 100644
index 0000000..c21c75d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_state.h
@@ -0,0 +1,62 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_STATE_H_
+#define CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_STATE_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+namespace bookmarks {
+
+// States for the bookmark bar.
+enum VisualState {
+ kInvalidState = 0,
+ kHiddenState = 1,
+ kShowingState = 2,
+ kDetachedState = 3,
+};
+
+} // namespace bookmarks
+
+// The interface for controllers (etc.) which can give information about the
+// bookmark bar's state.
+@protocol BookmarkBarState
+
+// Returns YES if the bookmark bar is currently visible (as a normal toolbar or
+// as a detached bar on the NTP), NO otherwise.
+- (BOOL)isVisible;
+
+// Returns YES if an animation is currently running, NO otherwise.
+- (BOOL)isAnimationRunning;
+
+// Returns YES if the bookmark bar is in the given state and not in an
+// animation, NO otherwise.
+- (BOOL)isInState:(bookmarks::VisualState)state;
+
+// Returns YES if the bookmark bar is animating from the given state (to any
+// other state), NO otherwise.
+- (BOOL)isAnimatingToState:(bookmarks::VisualState)state;
+
+// Returns YES if the bookmark bar is animating to the given state (from any
+// other state), NO otherwise.
+- (BOOL)isAnimatingFromState:(bookmarks::VisualState)state;
+
+// Returns YES if the bookmark bar is animating from the first given state to
+// the second given state, NO otherwise.
+- (BOOL)isAnimatingFromState:(bookmarks::VisualState)fromState
+ toState:(bookmarks::VisualState)toState;
+
+// Returns YES if the bookmark bar is animating between the two given states (in
+// either direction), NO otherwise.
+- (BOOL)isAnimatingBetweenState:(bookmarks::VisualState)fromState
+ andState:(bookmarks::VisualState)toState;
+
+// Returns how morphed into the detached bubble the bookmark bar should be (1 =
+// completely detached, 0 = normal).
+- (CGFloat)detachedMorphProgress;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_STATE_H_
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.h
new file mode 100644
index 0000000..1942ebd
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.h
@@ -0,0 +1,44 @@
+// 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.
+
+// The BookmarkBarToolbarView is responsible for drawing the background of the
+// BookmarkBar's toolbar in either of its two display modes - permanently
+// attached (slimline with a stroke at the bottom edge) or New Tab Page style
+// (padded with a round rect border and the New Tab Page theme behind).
+
+#ifndef CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_TOOLBAR_VIEW_H_
+#define CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_TOOLBAR_VIEW_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#import "chrome/browser/ui/cocoa/animatable_view.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_state.h"
+
+@class BookmarkBarView;
+class TabContents;
+class ThemeProvider;
+
+// An interface to allow mocking of a BookmarkBarController by the
+// BookmarkBarToolbarView.
+@protocol BookmarkBarToolbarViewController <BookmarkBarState>
+// Displaying the bookmark toolbar background in bubble (floating) mode requires
+// the size of the currently selected tab to properly calculate where the
+// background image is joined.
+- (int)currentTabContentsHeight;
+
+// Current theme provider, passed to the cross platform NtpBackgroundUtil class.
+- (ThemeProvider*)themeProvider;
+
+@end
+
+@interface BookmarkBarToolbarView : AnimatableView {
+ @private
+ // The controller which tells us how we should be drawing (as normal or as a
+ // floating bar).
+ IBOutlet id<BookmarkBarToolbarViewController> controller_;
+}
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_TOOLBAR_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.mm
new file mode 100644
index 0000000..760de17
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.mm
@@ -0,0 +1,135 @@
+// 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 "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.h"
+
+#include "app/theme_provider.h"
+#include "gfx/rect.h"
+#include "chrome/browser/ntp_background_util.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "chrome/browser/ui/cocoa/themed_window.h"
+#include "gfx/canvas_skia_paint.h"
+
+const CGFloat kBorderRadius = 3.0;
+
+@interface BookmarkBarToolbarView (Private)
+- (void)drawRectAsBubble:(NSRect)rect;
+@end
+
+@implementation BookmarkBarToolbarView
+
+- (BOOL)isOpaque {
+ return [controller_ isInState:bookmarks::kDetachedState];
+}
+
+- (void)drawRect:(NSRect)rect {
+ if ([controller_ isInState:bookmarks::kDetachedState] ||
+ [controller_ isAnimatingToState:bookmarks::kDetachedState] ||
+ [controller_ isAnimatingFromState:bookmarks::kDetachedState]) {
+ [self drawRectAsBubble:rect];
+ } else {
+ NSPoint phase = [[self window] themePatternPhase];
+ [[NSGraphicsContext currentContext] setPatternPhase:phase];
+ [self drawBackground];
+ }
+}
+
+- (void)drawRectAsBubble:(NSRect)rect {
+ // The state of our morph; 1 is total bubble, 0 is the regular bar. We use it
+ // to morph the bubble to a regular bar (shape and colour).
+ CGFloat morph = [controller_ detachedMorphProgress];
+
+ NSRect bounds = [self bounds];
+
+ ThemeProvider* themeProvider = [controller_ themeProvider];
+ if (!themeProvider)
+ return;
+
+ NSGraphicsContext* context = [NSGraphicsContext currentContext];
+ [context saveGraphicsState];
+
+ // Draw the background.
+ {
+ // CanvasSkiaPaint draws to the NSGraphicsContext during its destructor, so
+ // explicitly scope this.
+ //
+ // Paint the entire bookmark bar, even if the damage rect is much smaller
+ // because PaintBackgroundDetachedMode() assumes that area's origin is
+ // (0, 0) and that its size is the size of the bookmark bar.
+ //
+ // In practice, this sounds worse than it is because redraw time is still
+ // minimal compared to the pause between frames of animations. We were
+ // already repainting the rest of the bookmark bar below without setting a
+ // clip area, anyway. Also, the only time we weren't asked to redraw the
+ // whole bookmark bar is when the find bar is drawn over it.
+ gfx::CanvasSkiaPaint canvas(bounds, true);
+ gfx::Rect area(0, 0, NSWidth(bounds), NSHeight(bounds));
+
+ NtpBackgroundUtil::PaintBackgroundDetachedMode(themeProvider, &canvas,
+ area, [controller_ currentTabContentsHeight]);
+ }
+
+ // Draw our bookmark bar border on top of the background.
+ NSRect frameRect =
+ NSMakeRect(
+ morph * bookmarks::kNTPBookmarkBarPadding,
+ morph * bookmarks::kNTPBookmarkBarPadding,
+ NSWidth(bounds) - 2 * morph * bookmarks::kNTPBookmarkBarPadding,
+ NSHeight(bounds) - 2 * morph * bookmarks::kNTPBookmarkBarPadding);
+ // Now draw a bezier path with rounded rectangles around the area.
+ frameRect = NSInsetRect(frameRect, morph * 0.5, morph * 0.5);
+ NSBezierPath* border =
+ [NSBezierPath bezierPathWithRoundedRect:frameRect
+ xRadius:(morph * kBorderRadius)
+ yRadius:(morph * kBorderRadius)];
+
+ // Draw the rounded rectangle.
+ NSColor* toolbarColor =
+ themeProvider->GetNSColor(BrowserThemeProvider::COLOR_TOOLBAR, true);
+ CGFloat alpha = morph * [toolbarColor alphaComponent];
+ [[toolbarColor colorWithAlphaComponent:alpha] set]; // Set with opacity.
+ [border fill];
+
+ // Fade in/out the background.
+ [context saveGraphicsState];
+ [border setClip];
+ CGContextRef cgContext = (CGContextRef)[context graphicsPort];
+ CGContextBeginTransparencyLayer(cgContext, NULL);
+ CGContextSetAlpha(cgContext, 1 - morph);
+ [context setPatternPhase:[[self window] themePatternPhase]];
+ [self drawBackground];
+ CGContextEndTransparencyLayer(cgContext);
+ [context restoreGraphicsState];
+
+ // Draw the border of the rounded rectangle.
+ NSColor* borderColor = themeProvider->GetNSColor(
+ BrowserThemeProvider::COLOR_TOOLBAR_BUTTON_STROKE, true);
+ alpha = morph * [borderColor alphaComponent];
+ [[borderColor colorWithAlphaComponent:alpha] set]; // Set with opacity.
+ [border stroke];
+
+ // Fade in/out the divider.
+ // TODO(viettrungluu): It's not obvious that this divider lines up exactly
+ // with |BackgroundGradientView|'s (in fact, it probably doesn't).
+ NSColor* strokeColor = [self strokeColor];
+ alpha = (1 - morph) * [strokeColor alphaComponent];
+ [[strokeColor colorWithAlphaComponent:alpha] set];
+ NSBezierPath* divider = [NSBezierPath bezierPath];
+ NSPoint dividerStart =
+ NSMakePoint(morph * bookmarks::kNTPBookmarkBarPadding + morph * 0.5,
+ morph * bookmarks::kNTPBookmarkBarPadding + morph * 0.5);
+ CGFloat dividerWidth =
+ NSWidth(bounds) - 2 * morph * bookmarks::kNTPBookmarkBarPadding - 2 * 0.5;
+ [divider moveToPoint:dividerStart];
+ [divider relativeLineToPoint:NSMakePoint(dividerWidth, 0)];
+ [divider stroke];
+
+ // Restore the graphics context.
+ [context restoreGraphicsState];
+}
+
+@end // @implementation BookmarkBarToolbarView
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view_unittest.mm
new file mode 100644
index 0000000..24d971a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view_unittest.mm
@@ -0,0 +1,191 @@
+// 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 "app/theme_provider.h"
+#include "base/scoped_nsobject.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "grit/theme_resources.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::Return;
+using ::testing::SetArgumentPointee;
+
+// When testing the floating drawing, we need to have a source of theme data.
+class MockThemeProvider : public ThemeProvider {
+ public:
+ // Cross platform methods
+ MOCK_METHOD1(Init, void(Profile*));
+ MOCK_CONST_METHOD1(GetBitmapNamed, SkBitmap*(int));
+ MOCK_CONST_METHOD1(GetColor, SkColor(int));
+ MOCK_CONST_METHOD2(GetDisplayProperty, bool(int, int*));
+ MOCK_CONST_METHOD0(ShouldUseNativeFrame, bool());
+ MOCK_CONST_METHOD1(HasCustomImage, bool(int));
+ MOCK_CONST_METHOD1(GetRawData, RefCountedMemory*(int));
+
+ // OSX stuff
+ MOCK_CONST_METHOD2(GetNSImageNamed, NSImage*(int, bool));
+ MOCK_CONST_METHOD2(GetNSImageColorNamed, NSColor*(int, bool));
+ MOCK_CONST_METHOD2(GetNSColor, NSColor*(int, bool));
+ MOCK_CONST_METHOD2(GetNSColorTint, NSColor*(int, bool));
+ MOCK_CONST_METHOD1(GetNSGradient, NSGradient*(int));
+};
+
+// Allows us to inject our fake controller below.
+@interface BookmarkBarToolbarView (TestingAPI)
+-(void)setController:(id<BookmarkBarToolbarViewController>)controller;
+@end
+
+@implementation BookmarkBarToolbarView (TestingAPI)
+-(void)setController:(id<BookmarkBarToolbarViewController>)controller {
+ controller_ = controller;
+}
+@end
+
+// Allows us to control which way the view is rendered.
+@interface DrawDetachedBarFakeController :
+ NSObject<BookmarkBarState, BookmarkBarToolbarViewController> {
+ @private
+ int currentTabContentsHeight_;
+ ThemeProvider* themeProvider_;
+ bookmarks::VisualState visualState_;
+}
+@property (nonatomic, assign) int currentTabContentsHeight;
+@property (nonatomic, assign) ThemeProvider* themeProvider;
+@property (nonatomic, assign) bookmarks::VisualState visualState;
+
+// |BookmarkBarState| protocol:
+- (BOOL)isVisible;
+- (BOOL)isAnimationRunning;
+- (BOOL)isInState:(bookmarks::VisualState)state;
+- (BOOL)isAnimatingToState:(bookmarks::VisualState)state;
+- (BOOL)isAnimatingFromState:(bookmarks::VisualState)state;
+- (BOOL)isAnimatingFromState:(bookmarks::VisualState)fromState
+ toState:(bookmarks::VisualState)toState;
+- (BOOL)isAnimatingBetweenState:(bookmarks::VisualState)fromState
+ andState:(bookmarks::VisualState)toState;
+- (CGFloat)detachedMorphProgress;
+@end
+
+@implementation DrawDetachedBarFakeController
+@synthesize currentTabContentsHeight = currentTabContentsHeight_;
+@synthesize themeProvider = themeProvider_;
+@synthesize visualState = visualState_;
+
+- (id)init {
+ if ((self = [super init])) {
+ [self setVisualState:bookmarks::kHiddenState];
+ }
+ return self;
+}
+
+- (BOOL)isVisible { return YES; }
+- (BOOL)isAnimationRunning { return NO; }
+- (BOOL)isInState:(bookmarks::VisualState)state
+ { return ([self visualState] == state) ? YES : NO; }
+- (BOOL)isAnimatingToState:(bookmarks::VisualState)state { return NO; }
+- (BOOL)isAnimatingFromState:(bookmarks::VisualState)state { return NO; }
+- (BOOL)isAnimatingFromState:(bookmarks::VisualState)fromState
+ toState:(bookmarks::VisualState)toState { return NO; }
+- (BOOL)isAnimatingBetweenState:(bookmarks::VisualState)fromState
+ andState:(bookmarks::VisualState)toState { return NO; }
+- (CGFloat)detachedMorphProgress { return 1; }
+@end
+
+class BookmarkBarToolbarViewTest : public CocoaTest {
+ public:
+ BookmarkBarToolbarViewTest() {
+ controller_.reset([[DrawDetachedBarFakeController alloc] init]);
+ NSRect frame = NSMakeRect(0, 0, 400, 40);
+ scoped_nsobject<BookmarkBarToolbarView> view(
+ [[BookmarkBarToolbarView alloc] initWithFrame:frame]);
+ view_ = view.get();
+ [[test_window() contentView] addSubview:view_];
+ [view_ setController:controller_.get()];
+ }
+
+ scoped_nsobject<DrawDetachedBarFakeController> controller_;
+ BookmarkBarToolbarView* view_;
+};
+
+TEST_VIEW(BookmarkBarToolbarViewTest, view_)
+
+// Test drawing (part 1), mostly to ensure nothing leaks or crashes.
+TEST_F(BookmarkBarToolbarViewTest, DisplayAsNormalBar) {
+ [controller_.get() setVisualState:bookmarks::kShowingState];
+ [view_ display];
+}
+
+// Test drawing (part 2), mostly to ensure nothing leaks or crashes.
+TEST_F(BookmarkBarToolbarViewTest, DisplayAsDetachedBarWithNoImage) {
+ [controller_.get() setVisualState:bookmarks::kDetachedState];
+
+ // Tests where we don't have a background image, only a color.
+ MockThemeProvider provider;
+ EXPECT_CALL(provider, GetColor(BrowserThemeProvider::COLOR_NTP_BACKGROUND))
+ .WillRepeatedly(Return(SK_ColorWHITE));
+ EXPECT_CALL(provider, HasCustomImage(IDR_THEME_NTP_BACKGROUND))
+ .WillRepeatedly(Return(false));
+ [controller_.get() setThemeProvider:&provider];
+
+ [view_ display];
+}
+
+// Actions used in DisplayAsDetachedBarWithBgImage.
+ACTION(SetBackgroundTiling) {
+ *arg1 = BrowserThemeProvider::NO_REPEAT;
+ return true;
+}
+
+ACTION(SetAlignLeft) {
+ *arg1 = BrowserThemeProvider::ALIGN_LEFT;
+ return true;
+}
+
+// Test drawing (part 3), mostly to ensure nothing leaks or crashes.
+TEST_F(BookmarkBarToolbarViewTest, DisplayAsDetachedBarWithBgImage) {
+ [controller_.get() setVisualState:bookmarks::kDetachedState];
+
+ // Tests where we have a background image, with positioning information.
+ MockThemeProvider provider;
+
+ // Advertise having an image.
+ EXPECT_CALL(provider, GetColor(BrowserThemeProvider::COLOR_NTP_BACKGROUND))
+ .WillRepeatedly(Return(SK_ColorRED));
+ EXPECT_CALL(provider, HasCustomImage(IDR_THEME_NTP_BACKGROUND))
+ .WillRepeatedly(Return(true));
+
+ // Return the correct tiling/alignment information.
+ EXPECT_CALL(provider,
+ GetDisplayProperty(BrowserThemeProvider::NTP_BACKGROUND_TILING, _))
+ .WillRepeatedly(SetBackgroundTiling());
+ EXPECT_CALL(provider,
+ GetDisplayProperty(BrowserThemeProvider::NTP_BACKGROUND_ALIGNMENT, _))
+ .WillRepeatedly(SetAlignLeft());
+
+ // Create a dummy bitmap full of not-red to blit with.
+ SkBitmap fake_bg;
+ fake_bg.setConfig(SkBitmap::kARGB_8888_Config, 800, 800);
+ fake_bg.allocPixels();
+ fake_bg.eraseColor(SK_ColorGREEN);
+ EXPECT_CALL(provider, GetBitmapNamed(IDR_THEME_NTP_BACKGROUND))
+ .WillRepeatedly(Return(&fake_bg));
+
+ [controller_.get() setThemeProvider:&provider];
+ [controller_.get() setCurrentTabContentsHeight:200];
+
+ [view_ display];
+}
+
+// TODO(viettrungluu): write more unit tests, especially after my refactoring.
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_unittest_helper.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_unittest_helper.h
new file mode 100644
index 0000000..d0221b2
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_unittest_helper.h
@@ -0,0 +1,57 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_UNITTEST_HELPER_H_
+#define CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_UNITTEST_HELPER_H_
+#pragma once
+
+#import <Foundation/Foundation.h>
+
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
+
+@interface BookmarkBarController (BookmarkBarUnitTestHelper)
+
+// Return the bookmark button from this bar controller with the given
+// |title|, otherwise nil. This does not recurse into folders.
+- (BookmarkButton*)buttonWithTitleEqualTo:(NSString*)title;
+
+@end
+
+
+@interface BookmarkBarFolderController (BookmarkBarUnitTestHelper)
+
+// Return the bookmark button from this folder controller with the given
+// |title|, otherwise nil. This does not recurse into subfolders.
+- (BookmarkButton*)buttonWithTitleEqualTo:(NSString*)title;
+
+@end
+
+
+@interface BookmarkButton (BookmarkBarUnitTestHelper)
+
+// Return the center of the button in the base coordinate system of the
+// containing window. Useful for simulating mouse clicks or drags.
+- (NSPoint)center;
+
+// Return the top of the button in the base coordinate system of the
+// containing window.
+- (NSPoint)top;
+
+// Return the bottom of the button in the base coordinate system of the
+// containing window.
+- (NSPoint)bottom;
+
+// Return the center-left point of the button in the base coordinate system
+// of the containing window.
+- (NSPoint)left;
+
+// Return the center-right point of the button in the base coordinate system
+// of the containing window.
+- (NSPoint)right;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_UNITTEST_HELPER_H_
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_unittest_helper.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_unittest_helper.mm
new file mode 100644
index 0000000..7cddec4
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_unittest_helper.mm
@@ -0,0 +1,81 @@
+// 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 "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_unittest_helper.h"
+
+@interface NSArray (BookmarkBarUnitTestHelper)
+
+// A helper function for scanning an array of buttons looking for the
+// button with the given |title|.
+- (BookmarkButton*)buttonWithTitleEqualTo:(NSString*)title;
+
+@end
+
+
+@implementation NSArray (BookmarkBarUnitTestHelper)
+
+- (BookmarkButton*)buttonWithTitleEqualTo:(NSString*)title {
+ for (BookmarkButton* button in self) {
+ if ([[button title] isEqualToString:title])
+ return button;
+ }
+ return nil;
+}
+
+@end
+
+@implementation BookmarkBarController (BookmarkBarUnitTestHelper)
+
+- (BookmarkButton*)buttonWithTitleEqualTo:(NSString*)title {
+ return [[self buttons] buttonWithTitleEqualTo:title];
+}
+
+@end
+
+@implementation BookmarkBarFolderController(BookmarkBarUnitTestHelper)
+
+- (BookmarkButton*)buttonWithTitleEqualTo:(NSString*)title {
+ return [[self buttons] buttonWithTitleEqualTo:title];
+}
+
+@end
+
+@implementation BookmarkButton(BookmarkBarUnitTestHelper)
+
+- (NSPoint)center {
+ NSRect frame = [self frame];
+ NSPoint center = NSMakePoint(NSMidX(frame), NSMidY(frame));
+ center = [[self superview] convertPoint:center toView:nil];
+ return center;
+}
+
+- (NSPoint)top {
+ NSRect frame = [self frame];
+ NSPoint top = NSMakePoint(NSMidX(frame), NSMaxY(frame));
+ top = [[self superview] convertPoint:top toView:nil];
+ return top;
+}
+
+- (NSPoint)bottom {
+ NSRect frame = [self frame];
+ NSPoint bottom = NSMakePoint(NSMidX(frame), NSMinY(frame));
+ bottom = [[self superview] convertPoint:bottom toView:nil];
+ return bottom;
+}
+
+- (NSPoint)left {
+ NSRect frame = [self frame];
+ NSPoint left = NSMakePoint(NSMinX(frame), NSMidY(frame));
+ left = [[self superview] convertPoint:left toView:nil];
+ return left;
+}
+
+- (NSPoint)right {
+ NSRect frame = [self frame];
+ NSPoint right = NSMakePoint(NSMaxX(frame), NSMidY(frame));
+ right = [[self superview] convertPoint:right toView:nil];
+ return right;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.h
new file mode 100644
index 0000000..abcbdf0
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.h
@@ -0,0 +1,41 @@
+// 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.
+//
+// A simple custom NSView for the bookmark bar used to prevent clicking and
+// dragging from moving the browser window.
+
+#ifndef CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_VIEW_H_
+#define CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_VIEW_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#import "chrome/browser/ui/cocoa/background_gradient_view.h"
+
+@class BookmarkBarController;
+
+@interface BookmarkBarView : BackgroundGradientView {
+ @private
+ BOOL dropIndicatorShown_;
+ CGFloat dropIndicatorPosition_; // x position
+
+ IBOutlet BookmarkBarController* controller_;
+ IBOutlet NSTextField* noItemTextfield_;
+ IBOutlet NSButton* importBookmarksButton_;
+ NSView* noItemContainer_;
+}
+- (NSTextField*)noItemTextfield;
+- (NSButton*)importBookmarksButton;
+- (BookmarkBarController*)controller;
+
+@property (nonatomic, assign) IBOutlet NSView* noItemContainer;
+@end
+
+@interface BookmarkBarView() // TestingOrInternalAPI
+@property (nonatomic, readonly) BOOL dropIndicatorShown;
+@property (nonatomic, readonly) CGFloat dropIndicatorPosition;
+- (void)setController:(id)controller;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BAR_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.mm
new file mode 100644
index 0000000..5083367
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.mm
@@ -0,0 +1,259 @@
+// 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 "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.h"
+
+#include "chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h"
+#import "chrome/browser/ui/cocoa/themed_window.h"
+#import "chrome/browser/ui/cocoa/view_id_util.h"
+#import "chrome/browser/themes/browser_theme_provider.h"
+#import "third_party/mozilla/NSPasteboard+Utils.h"
+
+@interface BookmarkBarView (Private)
+- (void)themeDidChangeNotification:(NSNotification*)aNotification;
+- (void)updateTheme:(ThemeProvider*)themeProvider;
+@end
+
+@implementation BookmarkBarView
+
+@synthesize dropIndicatorShown = dropIndicatorShown_;
+@synthesize dropIndicatorPosition = dropIndicatorPosition_;
+@synthesize noItemContainer = noItemContainer_;
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ // This probably isn't strictly necessary, but can't hurt.
+ [self unregisterDraggedTypes];
+ [super dealloc];
+
+ // To be clear, our controller_ is an IBOutlet and owns us, so we
+ // don't deallocate it explicitly. It is owned by the browser
+ // window controller, so gets deleted with a browser window is
+ // closed.
+}
+
+- (void)awakeFromNib {
+ NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
+ [defaultCenter addObserver:self
+ selector:@selector(themeDidChangeNotification:)
+ name:kBrowserThemeDidChangeNotification
+ object:nil];
+
+ DCHECK(controller_) << "Expected this to be hooked up via Interface Builder";
+ NSArray* types = [NSArray arrayWithObjects:
+ NSStringPboardType,
+ NSHTMLPboardType,
+ NSURLPboardType,
+ kBookmarkButtonDragType,
+ kBookmarkDictionaryListPboardType,
+ nil];
+ [self registerForDraggedTypes:types];
+}
+
+// We need the theme to color the bookmark buttons properly. But our
+// controller desn't have access to it until it's placed in the view
+// hierarchy. This is the spot where we close the loop.
+- (void)viewWillMoveToWindow:(NSWindow*)window {
+ ThemeProvider* themeProvider = [window themeProvider];
+ [self updateTheme:themeProvider];
+ [controller_ updateTheme:themeProvider];
+}
+
+- (void)viewDidMoveToWindow {
+ [controller_ viewDidMoveToWindow];
+}
+
+// Called after the current theme has changed.
+- (void)themeDidChangeNotification:(NSNotification*)aNotification {
+ ThemeProvider* themeProvider =
+ static_cast<ThemeProvider*>([[aNotification object] pointerValue]);
+ [self updateTheme:themeProvider];
+}
+
+// Adapt appearance to the current theme. Called after theme changes and before
+// this is shown for the first time.
+- (void)updateTheme:(ThemeProvider*)themeProvider {
+ if (!themeProvider)
+ return;
+
+ NSColor* color =
+ themeProvider->GetNSColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT,
+ true);
+ [noItemTextfield_ setTextColor:color];
+}
+
+// Mouse down events on the bookmark bar should not allow dragging the parent
+// window around.
+- (BOOL)mouseDownCanMoveWindow {
+ return NO;
+}
+
+-(NSTextField*)noItemTextfield {
+ return noItemTextfield_;
+}
+
+-(NSButton*)importBookmarksButton {
+ return importBookmarksButton_;
+}
+
+- (BookmarkBarController*)controller {
+ return controller_;
+}
+
+-(void)drawRect:(NSRect)dirtyRect {
+ [super drawRect:dirtyRect];
+
+ // Draw the bookmark-button-dragging drop indicator if necessary.
+ if (dropIndicatorShown_) {
+ const CGFloat kBarWidth = 1;
+ const CGFloat kBarHalfWidth = kBarWidth / 2.0;
+ const CGFloat kBarVertPad = 4;
+ const CGFloat kBarOpacity = 0.85;
+
+ // Prevent the indicator from being clipped on the left.
+ CGFloat xLeft = MAX(dropIndicatorPosition_ - kBarHalfWidth, 0);
+
+ NSRect uglyBlackBar =
+ NSMakeRect(xLeft, kBarVertPad,
+ kBarWidth, NSHeight([self bounds]) - 2 * kBarVertPad);
+ NSColor* uglyBlackBarColor = [[self window] themeProvider]->
+ GetNSColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT, true);
+ [[uglyBlackBarColor colorWithAlphaComponent:kBarOpacity] setFill];
+ [[NSBezierPath bezierPathWithRect:uglyBlackBar] fill];
+ }
+}
+
+// Shim function to assist in unit testing.
+- (BOOL)dragClipboardContainsBookmarks {
+ return bookmark_pasteboard_helper_mac::DragClipboardContainsBookmarks();
+}
+
+// NSDraggingDestination methods
+
+- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info {
+ if ([[info draggingPasteboard] dataForType:kBookmarkButtonDragType] ||
+ [self dragClipboardContainsBookmarks] ||
+ [[info draggingPasteboard] containsURLData]) {
+ // We only show the drop indicator if we're not in a position to
+ // perform a hover-open since it doesn't make sense to do both.
+ BOOL showIt = [controller_ shouldShowIndicatorShownForPoint:
+ [info draggingLocation]];
+ if (!showIt) {
+ if (dropIndicatorShown_) {
+ dropIndicatorShown_ = NO;
+ [self setNeedsDisplay:YES];
+ }
+ } else {
+ CGFloat x =
+ [controller_ indicatorPosForDragToPoint:[info draggingLocation]];
+ // Need an update if the indicator wasn't previously shown or if it has
+ // moved.
+ if (!dropIndicatorShown_ || dropIndicatorPosition_ != x) {
+ dropIndicatorShown_ = YES;
+ dropIndicatorPosition_ = x;
+ [self setNeedsDisplay:YES];
+ }
+ }
+
+ [controller_ draggingEntered:info]; // allow hover-open to work.
+ return [info draggingSource] ? NSDragOperationMove : NSDragOperationCopy;
+ }
+ return NSDragOperationNone;
+}
+
+- (void)draggingExited:(id<NSDraggingInfo>)info {
+ // Regardless of the type of dragging which ended, we need to get rid of the
+ // drop indicator if one was shown.
+ if (dropIndicatorShown_) {
+ dropIndicatorShown_ = NO;
+ [self setNeedsDisplay:YES];
+ }
+}
+
+- (void)draggingEnded:(id<NSDraggingInfo>)info {
+ // For now, we just call |-draggingExited:|.
+ [self draggingExited:info];
+}
+
+- (BOOL)wantsPeriodicDraggingUpdates {
+ // TODO(port): This should probably return |YES| and the controller should
+ // slide the existing bookmark buttons interactively to the side to make
+ // room for the about-to-be-dropped bookmark.
+ return NO;
+}
+
+- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)info {
+ // For now it's the same as draggingEntered:.
+ // TODO(jrg): once we return YES for wantsPeriodicDraggingUpdates,
+ // this should ping the controller_ to perform animations.
+ return [self draggingEntered:info];
+}
+
+- (BOOL)prepareForDragOperation:(id<NSDraggingInfo>)info {
+ return YES;
+}
+
+// Implement NSDraggingDestination protocol method
+// performDragOperation: for URLs.
+- (BOOL)performDragOperationForURL:(id<NSDraggingInfo>)info {
+ NSPasteboard* pboard = [info draggingPasteboard];
+ DCHECK([pboard containsURLData]);
+
+ NSArray* urls = nil;
+ NSArray* titles = nil;
+ [pboard getURLs:&urls andTitles:&titles convertingFilenames:YES];
+
+ return [controller_ addURLs:urls
+ withTitles:titles
+ at:[info draggingLocation]];
+}
+
+// Implement NSDraggingDestination protocol method
+// performDragOperation: for bookmark buttons.
+- (BOOL)performDragOperationForBookmarkButton:(id<NSDraggingInfo>)info {
+ BOOL rtn = NO;
+ NSData* data = [[info draggingPasteboard]
+ dataForType:kBookmarkButtonDragType];
+ // [info draggingSource] is nil if not the same application.
+ if (data && [info draggingSource]) {
+ BookmarkButton* button = nil;
+ [data getBytes:&button length:sizeof(button)];
+ BOOL copy = !([info draggingSourceOperationMask] & NSDragOperationMove);
+ rtn = [controller_ dragButton:button
+ to:[info draggingLocation]
+ copy:copy];
+ UserMetrics::RecordAction(UserMetricsAction("BookmarkBar_DragEnd"));
+ }
+ return rtn;
+}
+
+- (BOOL)performDragOperation:(id<NSDraggingInfo>)info {
+ if ([controller_ dragBookmarkData:info])
+ return YES;
+ NSPasteboard* pboard = [info draggingPasteboard];
+ if ([pboard dataForType:kBookmarkButtonDragType]) {
+ if ([self performDragOperationForBookmarkButton:info])
+ return YES;
+ // Fall through....
+ }
+ if ([pboard containsURLData]) {
+ if ([self performDragOperationForURL:info])
+ return YES;
+ }
+ return NO;
+}
+
+- (void)setController:(id)controller {
+ controller_ = controller;
+}
+
+- (ViewID)viewID {
+ return VIEW_ID_BOOKMARK_BAR;
+}
+
+@end // @implementation BookmarkBarView
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_unittest.mm
new file mode 100644
index 0000000..c847a61
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_unittest.mm
@@ -0,0 +1,215 @@
+// 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.
+
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/url_drop_target.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+#import "third_party/mozilla/NSPasteboard+Utils.h"
+
+namespace {
+ const CGFloat kFakeIndicatorPos = 7.0;
+};
+
+// Fake DraggingInfo, fake BookmarkBarController, fake NSPasteboard...
+@interface FakeBookmarkDraggingInfo : NSObject {
+ @public
+ BOOL dragButtonToPong_;
+ BOOL dragURLsPong_;
+ BOOL dragBookmarkDataPong_;
+ BOOL dropIndicatorShown_;
+ BOOL draggingEnteredCalled_;
+ // Only mock one type of drag data at a time.
+ NSString* dragDataType_;
+}
+@property (nonatomic) BOOL dropIndicatorShown;
+@property (nonatomic) BOOL draggingEnteredCalled;
+@property (nonatomic, copy) NSString* dragDataType;
+@end
+
+@implementation FakeBookmarkDraggingInfo
+
+@synthesize dropIndicatorShown = dropIndicatorShown_;
+@synthesize draggingEnteredCalled = draggingEnteredCalled_;
+@synthesize dragDataType = dragDataType_;
+
+- (id)init {
+ if ((self = [super init])) {
+ dropIndicatorShown_ = YES;
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [dragDataType_ release];
+ [super dealloc];
+}
+
+- (void)reset {
+ [dragDataType_ release];
+ dragDataType_ = nil;
+ dragButtonToPong_ = NO;
+ dragURLsPong_ = NO;
+ dragBookmarkDataPong_ = NO;
+ dropIndicatorShown_ = YES;
+ draggingEnteredCalled_ = NO;
+}
+
+// NSDragInfo mocking functions.
+
+- (id)draggingPasteboard {
+ return self;
+}
+
+// So we can look local.
+- (id)draggingSource {
+ return self;
+}
+
+- (NSDragOperation)draggingSourceOperationMask {
+ return NSDragOperationCopy | NSDragOperationMove;
+}
+
+- (NSPoint)draggingLocation {
+ return NSMakePoint(10, 10);
+}
+
+// NSPasteboard mocking functions.
+
+- (BOOL)containsURLData {
+ NSArray* urlTypes = [URLDropTargetHandler handledDragTypes];
+ if (dragDataType_)
+ return [urlTypes containsObject:dragDataType_];
+ return NO;
+}
+
+- (NSData*)dataForType:(NSString*)type {
+ if (dragDataType_ && [dragDataType_ isEqualToString:type])
+ return [NSData data]; // Return something, anything.
+ return nil;
+}
+
+// Fake a controller for callback ponging
+
+- (BOOL)dragButton:(BookmarkButton*)button to:(NSPoint)point copy:(BOOL)copy {
+ dragButtonToPong_ = YES;
+ return YES;
+}
+
+- (BOOL)addURLs:(NSArray*)urls withTitles:(NSArray*)titles at:(NSPoint)point {
+ dragURLsPong_ = YES;
+ return YES;
+}
+
+- (void)getURLs:(NSArray**)outUrls
+ andTitles:(NSArray**)outTitles
+ convertingFilenames:(BOOL)convertFilenames {
+}
+
+- (BOOL)dragBookmarkData:(id<NSDraggingInfo>)info {
+ dragBookmarkDataPong_ = YES;
+ return NO;
+}
+
+// Confirm the pongs.
+
+- (BOOL)dragButtonToPong {
+ return dragButtonToPong_;
+}
+
+- (BOOL)dragURLsPong {
+ return dragURLsPong_;
+}
+
+- (BOOL)dragBookmarkDataPong {
+ return dragBookmarkDataPong_;
+}
+
+- (CGFloat)indicatorPosForDragToPoint:(NSPoint)point {
+ return kFakeIndicatorPos;
+}
+
+- (BOOL)shouldShowIndicatorShownForPoint:(NSPoint)point {
+ return dropIndicatorShown_;
+}
+
+- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info {
+ draggingEnteredCalled_ = YES;
+ return NSDragOperationNone;
+}
+
+@end
+
+namespace {
+
+class BookmarkBarViewTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ view_.reset([[BookmarkBarView alloc] init]);
+ }
+
+ scoped_nsobject<BookmarkBarView> view_;
+};
+
+TEST_F(BookmarkBarViewTest, CanDragWindow) {
+ EXPECT_FALSE([view_ mouseDownCanMoveWindow]);
+}
+
+TEST_F(BookmarkBarViewTest, BookmarkButtonDragAndDrop) {
+ scoped_nsobject<FakeBookmarkDraggingInfo>
+ info([[FakeBookmarkDraggingInfo alloc] init]);
+ [view_ setController:info.get()];
+ [info reset];
+
+ [info setDragDataType:kBookmarkButtonDragType];
+ EXPECT_EQ([view_ draggingEntered:(id)info.get()], NSDragOperationMove);
+ EXPECT_TRUE([view_ performDragOperation:(id)info.get()]);
+ EXPECT_TRUE([info dragButtonToPong]);
+ EXPECT_FALSE([info dragURLsPong]);
+ EXPECT_TRUE([info dragBookmarkDataPong]);
+}
+
+TEST_F(BookmarkBarViewTest, URLDragAndDrop) {
+ scoped_nsobject<FakeBookmarkDraggingInfo>
+ info([[FakeBookmarkDraggingInfo alloc] init]);
+ [view_ setController:info.get()];
+ [info reset];
+
+ NSArray* dragTypes = [URLDropTargetHandler handledDragTypes];
+ for (NSString* type in dragTypes) {
+ [info setDragDataType:type];
+ EXPECT_EQ([view_ draggingEntered:(id)info.get()], NSDragOperationMove);
+ EXPECT_TRUE([view_ performDragOperation:(id)info.get()]);
+ EXPECT_FALSE([info dragButtonToPong]);
+ EXPECT_TRUE([info dragURLsPong]);
+ EXPECT_TRUE([info dragBookmarkDataPong]);
+ [info reset];
+ }
+}
+
+TEST_F(BookmarkBarViewTest, BookmarkButtonDropIndicator) {
+ scoped_nsobject<FakeBookmarkDraggingInfo>
+ info([[FakeBookmarkDraggingInfo alloc] init]);
+ [view_ setController:info.get()];
+
+ [info reset];
+ [info setDragDataType:kBookmarkButtonDragType];
+ EXPECT_FALSE([info draggingEnteredCalled]);
+ EXPECT_EQ([view_ draggingEntered:(id)info.get()], NSDragOperationMove);
+ EXPECT_TRUE([info draggingEnteredCalled]); // Ensure controller pinged.
+ EXPECT_TRUE([view_ dropIndicatorShown]);
+ EXPECT_EQ([view_ dropIndicatorPosition], kFakeIndicatorPos);
+
+ [info setDropIndicatorShown:NO];
+ EXPECT_EQ([view_ draggingEntered:(id)info.get()], NSDragOperationMove);
+ EXPECT_FALSE([view_ dropIndicatorShown]);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.h
new file mode 100644
index 0000000..3ed8f7b
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.h
@@ -0,0 +1,81 @@
+// 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>
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_ptr.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa.h"
+
+class BookmarkBubbleNotificationBridge;
+class BookmarkModel;
+class BookmarkNode;
+@class BookmarkBubbleController;
+@class InfoBubbleView;
+
+
+// Controller for the bookmark bubble. The bookmark bubble is a
+// bubble that pops up when clicking on the STAR next to the URL to
+// add or remove it as a bookmark. This bubble allows for editing of
+// the bookmark in various ways (name, folder, etc.)
+@interface BookmarkBubbleController : NSWindowController<NSWindowDelegate> {
+ @private
+ NSWindow* parentWindow_; // weak
+
+ // Both weak; owned by the current browser's profile
+ BookmarkModel* model_; // weak
+ const BookmarkNode* node_; // weak
+
+ // The bookmark node whose button we asked to pulse.
+ const BookmarkNode* pulsingBookmarkNode_; // weak
+
+ BOOL alreadyBookmarked_;
+
+ // Ping me when the bookmark model changes out from under us.
+ scoped_ptr<BookmarkModelObserverForCocoa> bookmark_observer_;
+
+ // Ping me when other Chrome things change out from under us.
+ scoped_ptr<BookmarkBubbleNotificationBridge> chrome_observer_;
+
+ IBOutlet NSTextField* bigTitle_; // "Bookmark" or "Bookmark Added!"
+ IBOutlet NSTextField* nameTextField_;
+ IBOutlet NSPopUpButton* folderPopUpButton_;
+ IBOutlet InfoBubbleView* bubble_; // to set arrow position
+}
+
+@property (readonly, nonatomic) const BookmarkNode* node;
+
+// |node| is the bookmark node we edit in this bubble.
+// |alreadyBookmarked| tells us if the node was bookmarked before the
+// user clicked on the star. (if NO, this is a brand new bookmark).
+// The owner of this object is responsible for showing the bubble if
+// it desires it to be visible on the screen. It is not shown by the
+// init routine. Closing of the window happens implicitly on dealloc.
+- (id)initWithParentWindow:(NSWindow*)parentWindow
+ model:(BookmarkModel*)model
+ node:(const BookmarkNode*)node
+ alreadyBookmarked:(BOOL)alreadyBookmarked;
+
+// Actions for buttons in the dialog.
+- (IBAction)ok:(id)sender;
+- (IBAction)remove:(id)sender;
+- (IBAction)cancel:(id)sender;
+
+// These actions send a -editBookmarkNode: action up the responder chain.
+- (IBAction)edit:(id)sender;
+- (IBAction)folderChanged:(id)sender;
+
+@end
+
+
+// Exposed only for unit testing.
+@interface BookmarkBubbleController(ExposedForUnitTesting)
+- (void)addFolderNodes:(const BookmarkNode*)parent
+ toPopUpButton:(NSPopUpButton*)button
+ indentation:(int)indentation;
+- (void)setTitle:(NSString*)title parentFolder:(const BookmarkNode*)parent;
+- (void)setParentFolderSelection:(const BookmarkNode*)parent;
++ (NSString*)chooseAnotherFolderString;
+- (NSPopUpButton*)folderPopUpButton;
+@end
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.mm
new file mode 100644
index 0000000..ae66081
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.mm
@@ -0,0 +1,428 @@
+// 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 "chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.h"
+
+#include "app/l10n_util_mac.h"
+#include "base/mac_util.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h" // TODO(viettrungluu): remove
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "chrome/browser/ui/cocoa/info_bubble_view.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_service.h"
+#include "grit/generated_resources.h"
+
+
+// Simple class to watch for tab creation/destruction and close the bubble.
+// Bridge between Chrome-style notifications and ObjC-style notifications.
+class BookmarkBubbleNotificationBridge : public NotificationObserver {
+ public:
+ BookmarkBubbleNotificationBridge(BookmarkBubbleController* controller,
+ SEL selector);
+ virtual ~BookmarkBubbleNotificationBridge() {}
+ void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+ private:
+ NotificationRegistrar registrar_;
+ BookmarkBubbleController* controller_; // weak; owns us.
+ SEL selector_; // SEL sent to controller_ on notification.
+};
+
+BookmarkBubbleNotificationBridge::BookmarkBubbleNotificationBridge(
+ BookmarkBubbleController* controller, SEL selector)
+ : controller_(controller), selector_(selector) {
+ // registrar_ will automatically RemoveAll() when destroyed so we
+ // don't need to do so explicitly.
+ registrar_.Add(this, NotificationType::TAB_CONTENTS_CONNECTED,
+ NotificationService::AllSources());
+ registrar_.Add(this, NotificationType::TAB_CLOSED,
+ NotificationService::AllSources());
+}
+
+// At this time all notifications instigate the same behavior (go
+// away) so we don't bother checking which notification came in.
+void BookmarkBubbleNotificationBridge::Observe(
+ NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ [controller_ performSelector:selector_ withObject:controller_];
+}
+
+
+// An object to represent the ChooseAnotherFolder item in the pop up.
+@interface ChooseAnotherFolder : NSObject
+@end
+
+@implementation ChooseAnotherFolder
+@end
+
+@interface BookmarkBubbleController (PrivateAPI)
+- (void)updateBookmarkNode;
+- (void)fillInFolderList;
+- (void)parentWindowWillClose:(NSNotification*)notification;
+@end
+
+@implementation BookmarkBubbleController
+
+@synthesize node = node_;
+
++ (id)chooseAnotherFolderObject {
+ // Singleton object to act as a representedObject for the "choose another
+ // folder" item in the pop up.
+ static ChooseAnotherFolder* object = nil;
+ if (!object) {
+ object = [[ChooseAnotherFolder alloc] init];
+ }
+ return object;
+}
+
+- (id)initWithParentWindow:(NSWindow*)parentWindow
+ model:(BookmarkModel*)model
+ node:(const BookmarkNode*)node
+ alreadyBookmarked:(BOOL)alreadyBookmarked {
+ NSString* nibPath =
+ [mac_util::MainAppBundle() pathForResource:@"BookmarkBubble"
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibPath owner:self])) {
+ parentWindow_ = parentWindow;
+ model_ = model;
+ node_ = node;
+ alreadyBookmarked_ = alreadyBookmarked;
+
+ // Watch to see if the parent window closes, and if so, close this one.
+ NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+ [center addObserver:self
+ selector:@selector(parentWindowWillClose:)
+ name:NSWindowWillCloseNotification
+ object:parentWindow_];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+// If this is a new bookmark somewhere visible (e.g. on the bookmark
+// bar), pulse it. Else, call ourself recursively with our parent
+// until we find something visible to pulse.
+- (void)startPulsingBookmarkButton:(const BookmarkNode*)node {
+ while (node) {
+ if ((node->GetParent() == model_->GetBookmarkBarNode()) ||
+ (node == model_->other_node())) {
+ pulsingBookmarkNode_ = node;
+ NSValue *value = [NSValue valueWithPointer:node];
+ NSDictionary *dict = [NSDictionary
+ dictionaryWithObjectsAndKeys:value,
+ bookmark_button::kBookmarkKey,
+ [NSNumber numberWithBool:YES],
+ bookmark_button::kBookmarkPulseFlagKey,
+ nil];
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName:bookmark_button::kPulseBookmarkButtonNotification
+ object:self
+ userInfo:dict];
+ return;
+ }
+ node = node->GetParent();
+ }
+}
+
+- (void)stopPulsingBookmarkButton {
+ if (!pulsingBookmarkNode_)
+ return;
+ NSValue *value = [NSValue valueWithPointer:pulsingBookmarkNode_];
+ pulsingBookmarkNode_ = NULL;
+ NSDictionary *dict = [NSDictionary
+ dictionaryWithObjectsAndKeys:value,
+ bookmark_button::kBookmarkKey,
+ [NSNumber numberWithBool:NO],
+ bookmark_button::kBookmarkPulseFlagKey,
+ nil];
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName:bookmark_button::kPulseBookmarkButtonNotification
+ object:self
+ userInfo:dict];
+}
+
+// Close the bookmark bubble without changing anything. Unlike a
+// typical dialog's OK/Cancel, where Cancel is "do nothing", all
+// buttons on the bubble have the capacity to change the bookmark
+// model. This is an IBOutlet-looking entry point to remove the
+// dialog without touching the model.
+- (void)dismissWithoutEditing:(id)sender {
+ [self close];
+}
+
+- (void)parentWindowWillClose:(NSNotification*)notification {
+ [self close];
+}
+
+- (void)windowWillClose:(NSNotification*)notification {
+ // We caught a close so we don't need to watch for the parent closing.
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ bookmark_observer_.reset(NULL);
+ chrome_observer_.reset(NULL);
+ [self stopPulsingBookmarkButton];
+ [self autorelease];
+}
+
+// We want this to be a child of a browser window. addChildWindow:
+// (called from this function) will bring the window on-screen;
+// unfortunately, [NSWindowController showWindow:] will also bring it
+// on-screen (but will cause unexpected changes to the window's
+// position). We cannot have an addChildWindow: and a subsequent
+// showWindow:. Thus, we have our own version.
+- (void)showWindow:(id)sender {
+ BrowserWindowController* bwc =
+ [BrowserWindowController browserWindowControllerForWindow:parentWindow_];
+ [bwc lockBarVisibilityForOwner:self withAnimation:NO delay:NO];
+ NSWindow* window = [self window]; // completes nib load
+ [bubble_ setArrowLocation:info_bubble::kTopRight];
+ // Insure decent positioning even in the absence of a browser controller,
+ // which will occur for some unit tests.
+ NSPoint arrowtip = bwc ? [bwc bookmarkBubblePoint] :
+ NSMakePoint([window frame].size.width, [window frame].size.height);
+ NSPoint origin = [parentWindow_ convertBaseToScreen:arrowtip];
+ NSPoint bubbleArrowtip = [bubble_ arrowTip];
+ bubbleArrowtip = [bubble_ convertPoint:bubbleArrowtip toView:nil];
+ origin.y -= bubbleArrowtip.y;
+ origin.x -= bubbleArrowtip.x;
+ [window setFrameOrigin:origin];
+ [parentWindow_ addChildWindow:window ordered:NSWindowAbove];
+ // Default is IDS_BOOMARK_BUBBLE_PAGE_BOOKMARK; "Bookmark".
+ // If adding for the 1st time the string becomes "Bookmark Added!"
+ if (!alreadyBookmarked_) {
+ NSString* title =
+ l10n_util::GetNSString(IDS_BOOMARK_BUBBLE_PAGE_BOOKMARKED);
+ [bigTitle_ setStringValue:title];
+ }
+
+ [self fillInFolderList];
+
+ // Ping me when things change out from under us. Unlike a normal
+ // dialog, the bookmark bubble's cancel: means "don't add this as a
+ // bookmark", not "cancel editing". We must take extra care to not
+ // touch the bookmark in this selector.
+ bookmark_observer_.reset(new BookmarkModelObserverForCocoa(
+ node_, model_,
+ self,
+ @selector(dismissWithoutEditing:)));
+ chrome_observer_.reset(new BookmarkBubbleNotificationBridge(
+ self, @selector(dismissWithoutEditing:)));
+
+ // Pulse something interesting on the bookmark bar.
+ [self startPulsingBookmarkButton:node_];
+
+ [window makeKeyAndOrderFront:self];
+}
+
+- (void)close {
+ [[BrowserWindowController browserWindowControllerForWindow:parentWindow_]
+ releaseBarVisibilityForOwner:self withAnimation:YES delay:NO];
+ [parentWindow_ removeChildWindow:[self window]];
+
+ // If you quit while the bubble is open, sometimes we get a
+ // DidResignKey before we get our parent's WindowWillClose and
+ // sometimes not. We protect against a multiple close (or reference
+ // to parentWindow_ at a bad time) by clearing it out once we're
+ // done, and by removing ourself from future notifications.
+ [[NSNotificationCenter defaultCenter]
+ removeObserver:self
+ name:NSWindowWillCloseNotification
+ object:parentWindow_];
+ parentWindow_ = nil;
+
+ [super close];
+}
+
+// Shows the bookmark editor sheet for more advanced editing.
+- (void)showEditor {
+ [self ok:self];
+ // Send the action up through the responder chain.
+ [NSApp sendAction:@selector(editBookmarkNode:) to:nil from:self];
+}
+
+- (IBAction)edit:(id)sender {
+ UserMetrics::RecordAction(UserMetricsAction("BookmarkBubble_Edit"),
+ model_->profile());
+ [self showEditor];
+}
+
+- (IBAction)ok:(id)sender {
+ [self stopPulsingBookmarkButton]; // before parent changes
+ [self updateBookmarkNode];
+ [self close];
+}
+
+// By implementing this, ESC causes the window to go away. If clicking the
+// star was what prompted this bubble to appear (i.e., not already bookmarked),
+// remove the bookmark.
+- (IBAction)cancel:(id)sender {
+ if (!alreadyBookmarked_) {
+ // |-remove:| calls |-close| so don't do it.
+ [self remove:sender];
+ } else {
+ [self ok:sender];
+ }
+}
+
+- (IBAction)remove:(id)sender {
+ [self stopPulsingBookmarkButton];
+ // TODO(viettrungluu): get rid of conversion and utf_string_conversions.h.
+ model_->SetURLStarred(node_->GetURL(), node_->GetTitle(), false);
+ UserMetrics::RecordAction(UserMetricsAction("BookmarkBubble_Unstar"),
+ model_->profile());
+ node_ = NULL; // no longer valid
+ [self ok:sender];
+}
+
+// The controller is the target of the pop up button box action so it can
+// handle when "choose another folder" was picked.
+- (IBAction)folderChanged:(id)sender {
+ DCHECK([sender isEqual:folderPopUpButton_]);
+ // It is possible that due to model change our parent window has been closed
+ // but the popup is still showing and able to notify the controller of a
+ // folder change. We ignore the sender in this case.
+ if (!parentWindow_)
+ return;
+ NSMenuItem* selected = [folderPopUpButton_ selectedItem];
+ ChooseAnotherFolder* chooseItem = [[self class] chooseAnotherFolderObject];
+ if ([[selected representedObject] isEqual:chooseItem]) {
+ UserMetrics::RecordAction(
+ UserMetricsAction("BookmarkBubble_EditFromCombobox"),
+ model_->profile());
+ [self showEditor];
+ }
+}
+
+// The controller is the delegate of the window so it receives did resign key
+// notifications. When key is resigned mirror Windows behavior and close the
+// window.
+- (void)windowDidResignKey:(NSNotification*)notification {
+ NSWindow* window = [self window];
+ DCHECK_EQ([notification object], window);
+ if ([window isVisible]) {
+ // If the window isn't visible, it is already closed, and this notification
+ // has been sent as part of the closing operation, so no need to close.
+ [self ok:self];
+ }
+}
+
+// Look at the dialog; if the user has changed anything, update the
+// bookmark node to reflect this.
+- (void)updateBookmarkNode {
+ if (!node_) return;
+
+ // First the title...
+ NSString* oldTitle = base::SysUTF16ToNSString(node_->GetTitle());
+ NSString* newTitle = [nameTextField_ stringValue];
+ if (![oldTitle isEqual:newTitle]) {
+ model_->SetTitle(node_, base::SysNSStringToUTF16(newTitle));
+ UserMetrics::RecordAction(
+ UserMetricsAction("BookmarkBubble_ChangeTitleInBubble"),
+ model_->profile());
+ }
+ // Then the parent folder.
+ const BookmarkNode* oldParent = node_->GetParent();
+ NSMenuItem* selectedItem = [folderPopUpButton_ selectedItem];
+ id representedObject = [selectedItem representedObject];
+ if ([representedObject isEqual:[[self class] chooseAnotherFolderObject]]) {
+ // "Choose another folder..."
+ return;
+ }
+ const BookmarkNode* newParent =
+ static_cast<const BookmarkNode*>([representedObject pointerValue]);
+ DCHECK(newParent);
+ if (oldParent != newParent) {
+ int index = newParent->GetChildCount();
+ model_->Move(node_, newParent, index);
+ UserMetrics::RecordAction(UserMetricsAction("BookmarkBubble_ChangeParent"),
+ model_->profile());
+ }
+}
+
+// Fill in all information related to the folder pop up button.
+- (void)fillInFolderList {
+ [nameTextField_ setStringValue:base::SysUTF16ToNSString(node_->GetTitle())];
+ DCHECK([folderPopUpButton_ numberOfItems] == 0);
+ [self addFolderNodes:model_->root_node()
+ toPopUpButton:folderPopUpButton_
+ indentation:0];
+ NSMenu* menu = [folderPopUpButton_ menu];
+ NSString* title = [[self class] chooseAnotherFolderString];
+ NSMenuItem *item = [menu addItemWithTitle:title
+ action:NULL
+ keyEquivalent:@""];
+ ChooseAnotherFolder* obj = [[self class] chooseAnotherFolderObject];
+ [item setRepresentedObject:obj];
+ // Finally, select the current parent.
+ NSValue* parentValue = [NSValue valueWithPointer:node_->GetParent()];
+ NSInteger idx = [menu indexOfItemWithRepresentedObject:parentValue];
+ [folderPopUpButton_ selectItemAtIndex:idx];
+}
+
+@end // BookmarkBubbleController
+
+
+@implementation BookmarkBubbleController(ExposedForUnitTesting)
+
++ (NSString*)chooseAnotherFolderString {
+ return l10n_util::GetNSStringWithFixup(
+ IDS_BOOMARK_BUBBLE_CHOOSER_ANOTHER_FOLDER);
+}
+
+// For the given folder node, walk the tree and add folder names to
+// the given pop up button.
+- (void)addFolderNodes:(const BookmarkNode*)parent
+ toPopUpButton:(NSPopUpButton*)button
+ indentation:(int)indentation {
+ if (!model_->is_root(parent)) {
+ NSString* title = base::SysUTF16ToNSString(parent->GetTitle());
+ NSMenu* menu = [button menu];
+ NSMenuItem* item = [menu addItemWithTitle:title
+ action:NULL
+ keyEquivalent:@""];
+ [item setRepresentedObject:[NSValue valueWithPointer:parent]];
+ [item setIndentationLevel:indentation];
+ ++indentation;
+ }
+ for (int i = 0; i < parent->GetChildCount(); i++) {
+ const BookmarkNode* child = parent->GetChild(i);
+ if (child->is_folder())
+ [self addFolderNodes:child
+ toPopUpButton:button
+ indentation:indentation];
+ }
+}
+
+- (void)setTitle:(NSString*)title parentFolder:(const BookmarkNode*)parent {
+ [nameTextField_ setStringValue:title];
+ [self setParentFolderSelection:parent];
+}
+
+// Pick a specific parent node in the selection by finding the right
+// pop up button index.
+- (void)setParentFolderSelection:(const BookmarkNode*)parent {
+ // Expectation: There is a parent mapping for all items in the
+ // folderPopUpButton except the last one ("Choose another folder...").
+ NSMenu* menu = [folderPopUpButton_ menu];
+ NSValue* parentValue = [NSValue valueWithPointer:parent];
+ NSInteger idx = [menu indexOfItemWithRepresentedObject:parentValue];
+ DCHECK(idx != -1);
+ [folderPopUpButton_ selectItemAtIndex:idx];
+}
+
+- (NSPopUpButton*)folderPopUpButton {
+ return folderPopUpButton_;
+}
+
+@end // implementation BookmarkBubbleController(ExposedForUnitTesting)
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller_unittest.mm
new file mode 100644
index 0000000..ef3a47a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller_unittest.mm
@@ -0,0 +1,490 @@
+// 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 "base/basictypes.h"
+#include "base/scoped_nsobject.h"
+#include "base/utf_string_conversions.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#include "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/info_bubble_window.h"
+#include "chrome/common/notification_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+// Watch for bookmark pulse notifications so we can confirm they were sent.
+@interface BookmarkPulseObserver : NSObject {
+ int notifications_;
+}
+@property (assign, nonatomic) int notifications;
+@end
+
+
+@implementation BookmarkPulseObserver
+
+@synthesize notifications = notifications_;
+
+- (id)init {
+ if ((self = [super init])) {
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(pulseBookmarkNotification:)
+ name:bookmark_button::kPulseBookmarkButtonNotification
+ object:nil];
+ }
+ return self;
+}
+
+- (void)pulseBookmarkNotification:(NSNotificationCenter *)notification {
+ notifications_++;
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+@end
+
+
+namespace {
+
+class BookmarkBubbleControllerTest : public CocoaTest {
+ public:
+ static int edits_;
+ BrowserTestHelper helper_;
+ BookmarkBubbleController* controller_;
+
+ BookmarkBubbleControllerTest() : controller_(nil) {
+ edits_ = 0;
+ }
+
+ virtual void TearDown() {
+ [controller_ close];
+ CocoaTest::TearDown();
+ }
+
+ // Returns a controller but ownership not transferred.
+ // Only one of these will be valid at a time.
+ BookmarkBubbleController* ControllerForNode(const BookmarkNode* node) {
+ if (controller_ && !IsWindowClosing()) {
+ [controller_ close];
+ controller_ = nil;
+ }
+ controller_ = [[BookmarkBubbleController alloc]
+ initWithParentWindow:test_window()
+ model:helper_.profile()->GetBookmarkModel()
+ node:node
+ alreadyBookmarked:YES];
+ EXPECT_TRUE([controller_ window]);
+ // The window must be gone or we'll fail a unit test with windows left open.
+ [static_cast<InfoBubbleWindow*>([controller_ window]) setDelayOnClose:NO];
+ [controller_ showWindow:nil];
+ return controller_;
+ }
+
+ BookmarkModel* GetBookmarkModel() {
+ return helper_.profile()->GetBookmarkModel();
+ }
+
+ bool IsWindowClosing() {
+ return [static_cast<InfoBubbleWindow*>([controller_ window]) isClosing];
+ }
+};
+
+// static
+int BookmarkBubbleControllerTest::edits_;
+
+// Confirm basics about the bubble window (e.g. that it is inside the
+// parent window)
+TEST_F(BookmarkBubbleControllerTest, TestBubbleWindow) {
+ BookmarkModel* model = GetBookmarkModel();
+ const BookmarkNode* node = model->AddURL(model->GetBookmarkBarNode(),
+ 0,
+ ASCIIToUTF16("Bookie markie title"),
+ GURL("http://www.google.com"));
+ BookmarkBubbleController* controller = ControllerForNode(node);
+ EXPECT_TRUE(controller);
+ NSWindow* window = [controller window];
+ EXPECT_TRUE(window);
+ EXPECT_TRUE(NSContainsRect([test_window() frame],
+ [window frame]));
+}
+
+// Test that we can handle closing the parent window
+TEST_F(BookmarkBubbleControllerTest, TestClosingParentWindow) {
+ BookmarkModel* model = GetBookmarkModel();
+ const BookmarkNode* node = model->AddURL(model->GetBookmarkBarNode(),
+ 0,
+ ASCIIToUTF16("Bookie markie title"),
+ GURL("http://www.google.com"));
+ BookmarkBubbleController* controller = ControllerForNode(node);
+ EXPECT_TRUE(controller);
+ NSWindow* window = [controller window];
+ EXPECT_TRUE(window);
+ base::mac::ScopedNSAutoreleasePool pool;
+ [test_window() performClose:NSApp];
+}
+
+
+// Confirm population of folder list
+TEST_F(BookmarkBubbleControllerTest, TestFillInFolder) {
+ // Create some folders, including a nested folder
+ BookmarkModel* model = GetBookmarkModel();
+ EXPECT_TRUE(model);
+ const BookmarkNode* bookmarkBarNode = model->GetBookmarkBarNode();
+ EXPECT_TRUE(bookmarkBarNode);
+ const BookmarkNode* node1 = model->AddGroup(bookmarkBarNode, 0,
+ ASCIIToUTF16("one"));
+ EXPECT_TRUE(node1);
+ const BookmarkNode* node2 = model->AddGroup(bookmarkBarNode, 1,
+ ASCIIToUTF16("two"));
+ EXPECT_TRUE(node2);
+ const BookmarkNode* node3 = model->AddGroup(bookmarkBarNode, 2,
+ ASCIIToUTF16("three"));
+ EXPECT_TRUE(node3);
+ const BookmarkNode* node4 = model->AddGroup(node2, 0, ASCIIToUTF16("sub"));
+ EXPECT_TRUE(node4);
+ const BookmarkNode* node5 = model->AddURL(node1, 0, ASCIIToUTF16("title1"),
+ GURL("http://www.google.com"));
+ EXPECT_TRUE(node5);
+ const BookmarkNode* node6 = model->AddURL(node3, 0, ASCIIToUTF16("title2"),
+ GURL("http://www.google.com"));
+ EXPECT_TRUE(node6);
+ const BookmarkNode* node7 = model->AddURL(node4, 0, ASCIIToUTF16("title3"),
+ GURL("http://www.google.com/reader"));
+ EXPECT_TRUE(node7);
+
+ BookmarkBubbleController* controller = ControllerForNode(node4);
+ EXPECT_TRUE(controller);
+
+ NSArray* titles =
+ [[[controller folderPopUpButton] itemArray] valueForKey:@"title"];
+ EXPECT_TRUE([titles containsObject:@"one"]);
+ EXPECT_TRUE([titles containsObject:@"two"]);
+ EXPECT_TRUE([titles containsObject:@"three"]);
+ EXPECT_TRUE([titles containsObject:@"sub"]);
+ EXPECT_FALSE([titles containsObject:@"title1"]);
+ EXPECT_FALSE([titles containsObject:@"title2"]);
+}
+
+// Confirm ability to handle folders with blank name.
+TEST_F(BookmarkBubbleControllerTest, TestFolderWithBlankName) {
+ // Create some folders, including a nested folder
+ BookmarkModel* model = GetBookmarkModel();
+ EXPECT_TRUE(model);
+ const BookmarkNode* bookmarkBarNode = model->GetBookmarkBarNode();
+ EXPECT_TRUE(bookmarkBarNode);
+ const BookmarkNode* node1 = model->AddGroup(bookmarkBarNode, 0,
+ ASCIIToUTF16("one"));
+ EXPECT_TRUE(node1);
+ const BookmarkNode* node2 = model->AddGroup(bookmarkBarNode, 1,
+ ASCIIToUTF16(""));
+ EXPECT_TRUE(node2);
+ const BookmarkNode* node3 = model->AddGroup(bookmarkBarNode, 2,
+ ASCIIToUTF16("three"));
+ EXPECT_TRUE(node3);
+ const BookmarkNode* node2_1 = model->AddURL(node2, 0, ASCIIToUTF16("title1"),
+ GURL("http://www.google.com"));
+ EXPECT_TRUE(node2_1);
+
+ BookmarkBubbleController* controller = ControllerForNode(node1);
+ EXPECT_TRUE(controller);
+
+ // One of the items should be blank and its node should be node2.
+ NSArray* items = [[controller folderPopUpButton] itemArray];
+ EXPECT_GT([items count], 4U);
+ BOOL blankFolderFound = NO;
+ for (NSMenuItem* item in [[controller folderPopUpButton] itemArray]) {
+ if ([[item title] length] == 0 &&
+ static_cast<const BookmarkNode*>([[item representedObject]
+ pointerValue]) == node2) {
+ blankFolderFound = YES;
+ break;
+ }
+ }
+ EXPECT_TRUE(blankFolderFound);
+}
+
+
+// Click on edit; bubble gets closed.
+TEST_F(BookmarkBubbleControllerTest, TestEdit) {
+ BookmarkModel* model = GetBookmarkModel();
+ const BookmarkNode* node = model->AddURL(model->GetBookmarkBarNode(),
+ 0,
+ ASCIIToUTF16("Bookie markie title"),
+ GURL("http://www.google.com"));
+ BookmarkBubbleController* controller = ControllerForNode(node);
+ EXPECT_TRUE(controller);
+
+ EXPECT_EQ(edits_, 0);
+ EXPECT_FALSE(IsWindowClosing());
+ [controller edit:controller];
+ EXPECT_EQ(edits_, 1);
+ EXPECT_TRUE(IsWindowClosing());
+}
+
+// CallClose; bubble gets closed.
+// Also confirm pulse notifications get sent.
+TEST_F(BookmarkBubbleControllerTest, TestClose) {
+ BookmarkModel* model = GetBookmarkModel();
+ const BookmarkNode* node = model->AddURL(
+ model->GetBookmarkBarNode(), 0, ASCIIToUTF16("Bookie markie title"),
+ GURL("http://www.google.com"));
+ EXPECT_EQ(edits_, 0);
+
+ scoped_nsobject<BookmarkPulseObserver> observer([[BookmarkPulseObserver alloc]
+ init]);
+ EXPECT_EQ([observer notifications], 0);
+ BookmarkBubbleController* controller = ControllerForNode(node);
+ EXPECT_TRUE(controller);
+ EXPECT_FALSE(IsWindowClosing());
+ EXPECT_EQ([observer notifications], 1);
+ [controller ok:controller];
+ EXPECT_EQ(edits_, 0);
+ EXPECT_TRUE(IsWindowClosing());
+ EXPECT_EQ([observer notifications], 2);
+}
+
+// User changes title and parent folder in the UI
+TEST_F(BookmarkBubbleControllerTest, TestUserEdit) {
+ BookmarkModel* model = GetBookmarkModel();
+ EXPECT_TRUE(model);
+ const BookmarkNode* bookmarkBarNode = model->GetBookmarkBarNode();
+ EXPECT_TRUE(bookmarkBarNode);
+ const BookmarkNode* node = model->AddURL(bookmarkBarNode,
+ 0,
+ ASCIIToUTF16("short-title"),
+ GURL("http://www.google.com"));
+ const BookmarkNode* grandma = model->AddGroup(bookmarkBarNode, 0,
+ ASCIIToUTF16("grandma"));
+ EXPECT_TRUE(grandma);
+ const BookmarkNode* grandpa = model->AddGroup(bookmarkBarNode, 0,
+ ASCIIToUTF16("grandpa"));
+ EXPECT_TRUE(grandpa);
+
+ BookmarkBubbleController* controller = ControllerForNode(node);
+ EXPECT_TRUE(controller);
+
+ // simulate a user edit
+ [controller setTitle:@"oops" parentFolder:grandma];
+ [controller edit:controller];
+
+ // Make sure bookmark has changed
+ EXPECT_EQ(node->GetTitle(), ASCIIToUTF16("oops"));
+ EXPECT_EQ(node->GetParent()->GetTitle(), ASCIIToUTF16("grandma"));
+}
+
+// Confirm happiness with parent nodes that have the same name.
+TEST_F(BookmarkBubbleControllerTest, TestNewParentSameName) {
+ BookmarkModel* model = GetBookmarkModel();
+ EXPECT_TRUE(model);
+ const BookmarkNode* bookmarkBarNode = model->GetBookmarkBarNode();
+ EXPECT_TRUE(bookmarkBarNode);
+ for (int i=0; i<2; i++) {
+ const BookmarkNode* node = model->AddURL(bookmarkBarNode,
+ 0,
+ ASCIIToUTF16("short-title"),
+ GURL("http://www.google.com"));
+ EXPECT_TRUE(node);
+ const BookmarkNode* group = model->AddGroup(bookmarkBarNode, 0,
+ ASCIIToUTF16("NAME"));
+ EXPECT_TRUE(group);
+ group = model->AddGroup(bookmarkBarNode, 0, ASCIIToUTF16("NAME"));
+ EXPECT_TRUE(group);
+ group = model->AddGroup(bookmarkBarNode, 0, ASCIIToUTF16("NAME"));
+ EXPECT_TRUE(group);
+ BookmarkBubbleController* controller = ControllerForNode(node);
+ EXPECT_TRUE(controller);
+
+ // simulate a user edit
+ [controller setParentFolderSelection:bookmarkBarNode->GetChild(i)];
+ [controller edit:controller];
+
+ // Make sure bookmark has changed, and that the parent is what we
+ // expect. This proves nobody did searching based on name.
+ EXPECT_EQ(node->GetParent(), bookmarkBarNode->GetChild(i));
+ }
+}
+
+// Confirm happiness with nodes with the same Name
+TEST_F(BookmarkBubbleControllerTest, TestDuplicateNodeNames) {
+ BookmarkModel* model = GetBookmarkModel();
+ const BookmarkNode* bookmarkBarNode = model->GetBookmarkBarNode();
+ EXPECT_TRUE(bookmarkBarNode);
+ const BookmarkNode* node1 = model->AddGroup(bookmarkBarNode, 0,
+ ASCIIToUTF16("NAME"));
+ EXPECT_TRUE(node1);
+ const BookmarkNode* node2 = model->AddGroup(bookmarkBarNode, 0,
+ ASCIIToUTF16("NAME"));
+ EXPECT_TRUE(node2);
+ BookmarkBubbleController* controller = ControllerForNode(bookmarkBarNode);
+ EXPECT_TRUE(controller);
+
+ NSPopUpButton* button = [controller folderPopUpButton];
+ [controller setParentFolderSelection:node1];
+ NSMenuItem* item = [button selectedItem];
+ id itemObject = [item representedObject];
+ EXPECT_NSEQ([NSValue valueWithPointer:node1], itemObject);
+ [controller setParentFolderSelection:node2];
+ item = [button selectedItem];
+ itemObject = [item representedObject];
+ EXPECT_NSEQ([NSValue valueWithPointer:node2], itemObject);
+}
+
+// Click the "remove" button
+TEST_F(BookmarkBubbleControllerTest, TestRemove) {
+ BookmarkModel* model = GetBookmarkModel();
+ GURL gurl("http://www.google.com");
+ const BookmarkNode* node = model->AddURL(model->GetBookmarkBarNode(),
+ 0,
+ ASCIIToUTF16("Bookie markie title"),
+ gurl);
+ BookmarkBubbleController* controller = ControllerForNode(node);
+ EXPECT_TRUE(controller);
+ EXPECT_TRUE(model->IsBookmarked(gurl));
+
+ [controller remove:controller];
+ EXPECT_FALSE(model->IsBookmarked(gurl));
+ EXPECT_TRUE(IsWindowClosing());
+}
+
+// Confirm picking "choose another folder" caused edit: to be called.
+TEST_F(BookmarkBubbleControllerTest, PopUpSelectionChanged) {
+ BookmarkModel* model = GetBookmarkModel();
+ GURL gurl("http://www.google.com");
+ const BookmarkNode* node = model->AddURL(model->GetBookmarkBarNode(),
+ 0, ASCIIToUTF16("super-title"),
+ gurl);
+ BookmarkBubbleController* controller = ControllerForNode(node);
+ EXPECT_TRUE(controller);
+
+ NSPopUpButton* button = [controller folderPopUpButton];
+ [button selectItemWithTitle:[[controller class] chooseAnotherFolderString]];
+ EXPECT_EQ(edits_, 0);
+ [button sendAction:[button action] to:[button target]];
+ EXPECT_EQ(edits_, 1);
+}
+
+// Create a controller that simulates the bookmark just now being created by
+// the user clicking the star, then sending the "cancel" command to represent
+// them pressing escape. The bookmark should not be there.
+TEST_F(BookmarkBubbleControllerTest, EscapeRemovesNewBookmark) {
+ BookmarkModel* model = GetBookmarkModel();
+ GURL gurl("http://www.google.com");
+ const BookmarkNode* node = model->AddURL(model->GetBookmarkBarNode(),
+ 0,
+ ASCIIToUTF16("Bookie markie title"),
+ gurl);
+ BookmarkBubbleController* controller =
+ [[BookmarkBubbleController alloc]
+ initWithParentWindow:test_window()
+ model:helper_.profile()->GetBookmarkModel()
+ node:node
+ alreadyBookmarked:NO]; // The last param is the key difference.
+ EXPECT_TRUE([controller window]);
+ // Calls release on controller.
+ [controller cancel:nil];
+ EXPECT_FALSE(model->IsBookmarked(gurl));
+}
+
+// Create a controller where the bookmark already existed prior to clicking
+// the star and test that sending a cancel command doesn't change the state
+// of the bookmark.
+TEST_F(BookmarkBubbleControllerTest, EscapeDoesntTouchExistingBookmark) {
+ BookmarkModel* model = GetBookmarkModel();
+ GURL gurl("http://www.google.com");
+ const BookmarkNode* node = model->AddURL(model->GetBookmarkBarNode(),
+ 0,
+ ASCIIToUTF16("Bookie markie title"),
+ gurl);
+ BookmarkBubbleController* controller = ControllerForNode(node);
+ EXPECT_TRUE(controller);
+
+ [(id)controller cancel:nil];
+ EXPECT_TRUE(model->IsBookmarked(gurl));
+}
+
+// Confirm indentation of items in pop-up menu
+TEST_F(BookmarkBubbleControllerTest, TestMenuIndentation) {
+ // Create some folders, including a nested folder
+ BookmarkModel* model = GetBookmarkModel();
+ EXPECT_TRUE(model);
+ const BookmarkNode* bookmarkBarNode = model->GetBookmarkBarNode();
+ EXPECT_TRUE(bookmarkBarNode);
+ const BookmarkNode* node1 = model->AddGroup(bookmarkBarNode, 0,
+ ASCIIToUTF16("one"));
+ EXPECT_TRUE(node1);
+ const BookmarkNode* node2 = model->AddGroup(bookmarkBarNode, 1,
+ ASCIIToUTF16("two"));
+ EXPECT_TRUE(node2);
+ const BookmarkNode* node2_1 = model->AddGroup(node2, 0,
+ ASCIIToUTF16("two dot one"));
+ EXPECT_TRUE(node2_1);
+ const BookmarkNode* node3 = model->AddGroup(bookmarkBarNode, 2,
+ ASCIIToUTF16("three"));
+ EXPECT_TRUE(node3);
+
+ BookmarkBubbleController* controller = ControllerForNode(node1);
+ EXPECT_TRUE(controller);
+
+ // Compare the menu item indents against expectations.
+ static const int kExpectedIndent[] = {0, 1, 1, 2, 1, 0};
+ NSArray* items = [[controller folderPopUpButton] itemArray];
+ ASSERT_GE([items count], 6U);
+ for(int itemNo = 0; itemNo < 6; itemNo++) {
+ NSMenuItem* item = [items objectAtIndex:itemNo];
+ EXPECT_EQ(kExpectedIndent[itemNo], [item indentationLevel])
+ << "Unexpected indent for menu item #" << itemNo;
+ }
+}
+
+// Confirm bubble goes away when a new tab is created.
+TEST_F(BookmarkBubbleControllerTest, BubbleGoesAwayOnNewTab) {
+
+ BookmarkModel* model = GetBookmarkModel();
+ const BookmarkNode* node = model->AddURL(model->GetBookmarkBarNode(),
+ 0,
+ ASCIIToUTF16("Bookie markie title"),
+ GURL("http://www.google.com"));
+ EXPECT_EQ(edits_, 0);
+
+ BookmarkBubbleController* controller = ControllerForNode(node);
+ EXPECT_TRUE(controller);
+ EXPECT_FALSE(IsWindowClosing());
+
+ // We can't actually create a new tab here, e.g.
+ // helper_.browser()->AddTabWithURL(...);
+ // Many of our browser objects (Browser, Profile, RequestContext)
+ // are "just enough" to run tests without being complete. Instead
+ // we fake the notification that would be triggered by a tab
+ // creation.
+ NotificationService::current()->Notify(
+ NotificationType::TAB_CONTENTS_CONNECTED,
+ Source<TabContentsDelegate>(NULL),
+ Details<TabContents>(NULL));
+
+ // Confirm bubble going bye-bye.
+ EXPECT_TRUE(IsWindowClosing());
+}
+
+
+} // namespace
+
+@implementation NSApplication (BookmarkBubbleUnitTest)
+// Add handler for the editBookmarkNode: action to NSApp for testing purposes.
+// Normally this would be sent up the responder tree correctly, but since
+// tests run in the background, key window and main window are never set on
+// NSApplication. Adding it to NSApplication directly removes the need for
+// worrying about what the current window with focus is.
+- (void)editBookmarkNode:(id)sender {
+ EXPECT_TRUE([sender respondsToSelector:@selector(node)]);
+ BookmarkBubbleControllerTest::edits_++;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_button.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_button.h
new file mode 100644
index 0000000..0bea5a5
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_button.h
@@ -0,0 +1,243 @@
+// 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 <vector>
+#import "chrome/browser/ui/cocoa/draggable_button.h"
+#include "webkit/glue/window_open_disposition.h"
+
+@class BookmarkBarFolderController;
+@class BookmarkButton;
+struct BookmarkNodeData;
+class BookmarkModel;
+class BookmarkNode;
+@class BrowserWindowController;
+class ThemeProvider;
+
+// Protocol for a BookmarkButton's delegate, responsible for doing
+// things on behalf of a bookmark button.
+@protocol BookmarkButtonDelegate
+
+// Fill the given pasteboard with appropriate data when the given button is
+// dragged. Since the delegate has no way of providing pasteboard data later,
+// all data must actually be put into the pasteboard and not merely promised.
+- (void)fillPasteboard:(NSPasteboard*)pboard
+ forDragOfButton:(BookmarkButton*)button;
+
+// Bookmark buttons pass mouseEntered: and mouseExited: events to
+// their delegate. This allows the delegate to decide (for example)
+// which one, if any, should perform a hover-open.
+- (void)mouseEnteredButton:(id)button event:(NSEvent*)event;
+- (void)mouseExitedButton:(id)button event:(NSEvent*)event;
+
+// Returns YES if a drag operation should lock the fullscreen overlay bar
+// visibility before starting. For example, dragging a bookmark button should
+// not lock the overlay if the bookmark bar is currently showing in detached
+// mode on the NTP.
+- (BOOL)dragShouldLockBarVisibility;
+
+// Returns the top-level window for this button.
+- (NSWindow*)browserWindow;
+
+// Returns YES if the bookmark button can be dragged to the trash, NO otherwise.
+- (BOOL)canDragBookmarkButtonToTrash:(BookmarkButton*)button;
+
+// This is called after the user has dropped the bookmark button on the trash.
+// The delegate can use this event to delete the bookmark.
+- (void)didDragBookmarkToTrash:(BookmarkButton*)button;
+
+@end
+
+
+// Protocol to be implemented by controllers that logically own
+// bookmark buttons. The controller may be either an NSViewController
+// or NSWindowController. The BookmarkButton doesn't use this
+// protocol directly; it is used when BookmarkButton controllers talk
+// to each other.
+//
+// Other than the top level owner (the bookmark bar), all bookmark
+// button controllers have a parent controller.
+@protocol BookmarkButtonControllerProtocol
+
+// Close all bookmark folders, walking up the ownership chain.
+- (void)closeAllBookmarkFolders;
+
+// Close just my bookmark folder.
+- (void)closeBookmarkFolder:(id)sender;
+
+// Return the bookmark model for this controller.
+- (BookmarkModel*)bookmarkModel;
+
+// Perform drag enter/exit operations, such as hover-open and hover-close.
+- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info;
+- (void)draggingExited:(id<NSDraggingInfo>)info;
+
+// Returns YES if a drag operation should lock the fullscreen overlay bar
+// visibility before starting. For example, dragging a bookmark button should
+// not lock the overlay if the bookmark bar is currently showing in detached
+// mode on the NTP.
+- (BOOL)dragShouldLockBarVisibility;
+
+// Perform the actual DnD of a bookmark or bookmark button.
+
+// |point| is in the base coordinate system of the destination window;
+// |it comes from an id<NSDraggingInfo>. |copy| is YES if a copy is to be
+// made and inserted into the new location while leaving the bookmark in
+// the old location, otherwise move the bookmark by removing from its old
+// location and inserting into the new location.
+- (BOOL)dragButton:(BookmarkButton*)sourceButton
+ to:(NSPoint)point
+ copy:(BOOL)copy;
+
+// Determine if the pasteboard from |info| has dragging data containing
+// bookmark(s) and perform the drag and return YES, otherwise return NO.
+- (BOOL)dragBookmarkData:(id<NSDraggingInfo>)info;
+
+// Determine if the drag pasteboard has any drag data of type
+// kBookmarkDictionaryListPboardType and, if so, return those elements
+// otherwise return an empty vector.
+- (std::vector<const BookmarkNode*>)retrieveBookmarkNodeData;
+
+// Return YES if we should show the drop indicator, else NO. In some
+// cases (e.g. hover open) we don't want to show the drop indicator.
+// |point| is in the base coordinate system of the destination window;
+// |it comes from an id<NSDraggingInfo>.
+- (BOOL)shouldShowIndicatorShownForPoint:(NSPoint)point;
+
+// The x or y coordinate of (the middle of) the indicator to draw for
+// a drag of the source button to the given point (given in window
+// coordinates).
+// |point| is in the base coordinate system of the destination window;
+// |it comes from an id<NSDraggingInfo>.
+// TODO(viettrungluu,jrg): instead of this, make buttons move around.
+// http://crbug.com/35968
+- (CGFloat)indicatorPosForDragToPoint:(NSPoint)point;
+
+// Return the theme provider associated with this browser window.
+- (ThemeProvider*)themeProvider;
+
+// Called just before a child folder puts itself on screen.
+- (void)childFolderWillShow:(id<BookmarkButtonControllerProtocol>)child;
+
+// Called just before a child folder closes.
+- (void)childFolderWillClose:(id<BookmarkButtonControllerProtocol>)child;
+
+// Return a controller's folder controller for a subfolder, or nil.
+- (BookmarkBarFolderController*)folderController;
+
+// Add a new folder controller as triggered by the given folder button.
+// If there is a current folder controller, close it.
+- (void)addNewFolderControllerWithParentButton:(BookmarkButton*)parentButton;
+
+// Open all of the nodes for the given node with disposition.
+- (void)openAll:(const BookmarkNode*)node
+ disposition:(WindowOpenDisposition)disposition;
+
+// There are several operations which may affect the contents of a bookmark
+// button controller after it has been created, primary of which are
+// cut/paste/delete and drag/drop. Such changes may involve coordinating
+// the bookmark button contents of two controllers (such as when a bookmark is
+// dragged from one folder to another). The bookmark bar controller
+// coordinates in response to notifications propogated by the bookmark model
+// through BookmarkBarBridge calls. The following three functions are
+// implemented by the controllers and are dispatched by the bookmark bar
+// controller in response to notifications coming in from the BookmarkBarBridge.
+
+// Add a button for the given node to the bar or folder menu. This is safe
+// to call when a folder menu window is open as that window will be updated.
+// And index of -1 means to append to the end (bottom).
+- (void)addButtonForNode:(const BookmarkNode*)node
+ atIndex:(NSInteger)buttonIndex;
+
+// Given a list or |urls| and |titles|, create new bookmark nodes and add
+// them to the bookmark model such that they will be 1) added to the folder
+// represented by the button at |point| if it is a folder, or 2) inserted
+// into the parent of the non-folder bookmark at |point| in front of that
+// button. Returns YES if at least one bookmark was added.
+// TODO(mrossetti): Change function to use a pair-like structure for
+// URLs and titles. http://crbug.com/44411
+- (BOOL)addURLs:(NSArray*)urls withTitles:(NSArray*)titles at:(NSPoint)point;
+
+// Move a button from one place in the menu to another. This is safe
+// to call when a folder menu window is open as that window will be updated.
+- (void)moveButtonFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex;
+
+// Remove the bookmark button at the given index. Show the poof animation
+// if |animate:| is YES. It may be obvious, but this is safe
+// to call when a folder menu window is open as that window will be updated.
+- (void)removeButton:(NSInteger)buttonIndex animate:(BOOL)poof;
+
+// Determine the controller containing the button representing |node|, if any.
+- (id<BookmarkButtonControllerProtocol>)controllerForNode:
+ (const BookmarkNode*)node;
+
+@end // @protocol BookmarkButtonControllerProtocol
+
+
+// Class for bookmark bar buttons that can be drag sources.
+@interface BookmarkButton : DraggableButton {
+ @private
+ IBOutlet NSObject<BookmarkButtonDelegate>* delegate_; // Weak.
+
+ // Saved pointer to the BWC for the browser window that contains this button.
+ // Used to lock and release bar visibility during a drag. The pointer is
+ // saved because the bookmark button is no longer a part of a window at the
+ // end of a drag operation (or, in fact, can be dragged to a completely
+ // different window), so there is no way to retrieve the same BWC object after
+ // a drag.
+ BrowserWindowController* visibilityDelegate_; // weak
+
+ NSPoint dragMouseOffset_;
+ NSPoint dragEndScreenLocation_;
+ BOOL dragPending_;
+}
+
+@property(assign, nonatomic) NSObject<BookmarkButtonDelegate>* delegate;
+
+// Return the bookmark node associated with this button, or NULL.
+- (const BookmarkNode*)bookmarkNode;
+
+// Return YES if this is a folder button (the node has subnodes).
+- (BOOL)isFolder;
+
+// At this time we represent an empty folder (e.g. the string
+// '(empty)') as a disabled button with no associated node.
+//
+// TODO(jrg): improve; things work but are slightly ugly since "empty"
+// and "one disabled button" are not the same thing.
+// http://crbug.com/35967
+- (BOOL)isEmpty;
+
+// Turn on or off pulsing of a bookmark button.
+// Triggered by the bookmark bubble.
+- (void)setIsContinuousPulsing:(BOOL)flag;
+
+// Return continuous pulse state.
+- (BOOL)isContinuousPulsing;
+
+// Return the location in screen coordinates where the remove animation should
+// be displayed.
+- (NSPoint)screenLocationForRemoveAnimation;
+
+@end // @interface BookmarkButton
+
+
+@interface BookmarkButton(TestingAPI)
+- (void)beginDrag:(NSEvent*)event;
+@end
+
+namespace bookmark_button {
+
+// Notifications for pulsing of bookmarks.
+extern NSString* const kPulseBookmarkButtonNotification;
+
+// Key for userInfo dict of a kPulseBookmarkButtonNotification.
+// Value is a [NSValue valueWithPointer:]; pointer is a (const BookmarkNode*).
+extern NSString* const kBookmarkKey;
+
+// Key for userInfo dict of a kPulseBookmarkButtonNotification.
+// Value is a [NSNumber numberWithBool:] to turn pulsing on or off.
+extern NSString* const kBookmarkPulseFlagKey;
+
+};
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_button.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_button.mm
new file mode 100644
index 0000000..885e5c8
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_button.mm
@@ -0,0 +1,238 @@
+// 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 "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
+
+#include "base/logging.h"
+#import "base/scoped_nsobject.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "chrome/browser/ui/cocoa/view_id_util.h"
+
+// The opacity of the bookmark button drag image.
+static const CGFloat kDragImageOpacity = 0.7;
+
+
+namespace bookmark_button {
+
+NSString* const kPulseBookmarkButtonNotification =
+ @"PulseBookmarkButtonNotification";
+NSString* const kBookmarkKey = @"BookmarkKey";
+NSString* const kBookmarkPulseFlagKey = @"BookmarkPulseFlagKey";
+
+};
+
+@interface BookmarkButton(Private)
+
+// Make a drag image for the button.
+- (NSImage*)dragImage;
+
+@end // @interface BookmarkButton(Private)
+
+
+@implementation BookmarkButton
+
+@synthesize delegate = delegate_;
+
+- (id)initWithFrame:(NSRect)frameRect {
+ // BookmarkButton's ViewID may be changed to VIEW_ID_OTHER_BOOKMARKS in
+ // BookmarkBarController, so we can't just override -viewID method to return
+ // it.
+ if ((self = [super initWithFrame:frameRect]))
+ view_id_util::SetID(self, VIEW_ID_BOOKMARK_BAR_ELEMENT);
+ return self;
+}
+
+- (void)dealloc {
+ if ([[self cell] respondsToSelector:@selector(safelyStopPulsing)])
+ [[self cell] safelyStopPulsing];
+ view_id_util::UnsetID(self);
+ [super dealloc];
+}
+
+- (const BookmarkNode*)bookmarkNode {
+ return [[self cell] bookmarkNode];
+}
+
+- (BOOL)isFolder {
+ const BookmarkNode* node = [self bookmarkNode];
+ return (node && node->is_folder());
+}
+
+- (BOOL)isEmpty {
+ return [self bookmarkNode] ? NO : YES;
+}
+
+- (void)setIsContinuousPulsing:(BOOL)flag {
+ [[self cell] setIsContinuousPulsing:flag];
+}
+
+- (BOOL)isContinuousPulsing {
+ return [[self cell] isContinuousPulsing];
+}
+
+- (NSPoint)screenLocationForRemoveAnimation {
+ NSPoint point;
+
+ if (dragPending_) {
+ // Use the position of the mouse in the drag image as the location.
+ point = dragEndScreenLocation_;
+ point.x += dragMouseOffset_.x;
+ if ([self isFlipped]) {
+ point.y += [self bounds].size.height - dragMouseOffset_.y;
+ } else {
+ point.y += dragMouseOffset_.y;
+ }
+ } else {
+ // Use the middle of this button as the location.
+ NSRect bounds = [self bounds];
+ point = NSMakePoint(NSMidX(bounds), NSMidY(bounds));
+ point = [self convertPoint:point toView:nil];
+ point = [[self window] convertBaseToScreen:point];
+ }
+
+ return point;
+}
+
+// By default, NSButton ignores middle-clicks.
+// But we want them.
+- (void)otherMouseUp:(NSEvent*)event {
+ [self performClick:self];
+}
+
+// Overridden from DraggableButton.
+- (void)beginDrag:(NSEvent*)event {
+ // Don't allow a drag of the empty node.
+ // The empty node is a placeholder for "(empty)", to be revisited.
+ if ([self isEmpty])
+ return;
+
+ if (![self delegate]) {
+ NOTREACHED();
+ return;
+ }
+ // Ask our delegate to fill the pasteboard for us.
+ NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
+ [[self delegate] fillPasteboard:pboard forDragOfButton:self];
+
+ // At the moment, moving bookmarks causes their buttons (like me!)
+ // to be destroyed and rebuilt. Make sure we don't go away while on
+ // the stack.
+ [self retain];
+
+ // Lock bar visibility, forcing the overlay to stay visible if we are in
+ // fullscreen mode.
+ if ([[self delegate] dragShouldLockBarVisibility]) {
+ DCHECK(!visibilityDelegate_);
+ NSWindow* window = [[self delegate] browserWindow];
+ visibilityDelegate_ =
+ [BrowserWindowController browserWindowControllerForWindow:window];
+ [visibilityDelegate_ lockBarVisibilityForOwner:self
+ withAnimation:NO
+ delay:NO];
+ }
+ const BookmarkNode* node = [self bookmarkNode];
+ const BookmarkNode* parent = node ? node->GetParent() : NULL;
+ if (parent && parent->type() == BookmarkNode::FOLDER) {
+ UserMetrics::RecordAction(UserMetricsAction("BookmarkBarFolder_DragStart"));
+ } else {
+ UserMetrics::RecordAction(UserMetricsAction("BookmarkBar_DragStart"));
+ }
+
+ dragMouseOffset_ = [self convertPointFromBase:[event locationInWindow]];
+ dragPending_ = YES;
+
+ CGFloat yAt = [self bounds].size.height;
+ NSSize dragOffset = NSMakeSize(0.0, 0.0);
+ [self dragImage:[self dragImage] at:NSMakePoint(0, yAt) offset:dragOffset
+ event:event pasteboard:pboard source:self slideBack:YES];
+
+ // And we're done.
+ dragPending_ = NO;
+ [self autorelease];
+}
+
+// Overridden to release bar visibility.
+- (void)endDrag {
+ // visibilityDelegate_ can be nil if we're detached, and that's fine.
+ [visibilityDelegate_ releaseBarVisibilityForOwner:self
+ withAnimation:YES
+ delay:YES];
+ visibilityDelegate_ = nil;
+ [super endDrag];
+}
+
+- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal {
+ NSDragOperation operation = NSDragOperationCopy;
+ if (isLocal) {
+ operation |= NSDragOperationMove;
+ }
+ if ([delegate_ canDragBookmarkButtonToTrash:self]) {
+ operation |= NSDragOperationDelete;
+ }
+ return operation;
+}
+
+- (void)draggedImage:(NSImage *)anImage
+ endedAt:(NSPoint)aPoint
+ operation:(NSDragOperation)operation {
+ if (operation & NSDragOperationDelete) {
+ dragEndScreenLocation_ = aPoint;
+ [delegate_ didDragBookmarkToTrash:self];
+ }
+}
+
+// mouseEntered: and mouseExited: are called from our
+// BookmarkButtonCell. We redirect this information to our delegate.
+// The controller can then perform menu-like actions (e.g. "hover over
+// to open menu").
+- (void)mouseEntered:(NSEvent*)event {
+ [delegate_ mouseEnteredButton:self event:event];
+}
+
+// See comments above mouseEntered:.
+- (void)mouseExited:(NSEvent*)event {
+ [delegate_ mouseExitedButton:self event:event];
+}
+
+@end
+
+@implementation BookmarkButton(Private)
+
+- (NSImage*)dragImage {
+ NSRect bounds = [self bounds];
+
+ // Grab the image from the screen and put it in an |NSImage|. We can't use
+ // this directly since we need to clip it and set its opacity. This won't work
+ // if the source view is clipped. Fortunately, we don't display clipped
+ // bookmark buttons.
+ [self lockFocus];
+ scoped_nsobject<NSBitmapImageRep>
+ bitmap([[NSBitmapImageRep alloc] initWithFocusedViewRect:bounds]);
+ [self unlockFocus];
+ scoped_nsobject<NSImage> image([[NSImage alloc] initWithSize:[bitmap size]]);
+ [image addRepresentation:bitmap];
+
+ // Make an autoreleased |NSImage|, which will be returned, and draw into it.
+ // By default, the |NSImage| will be completely transparent.
+ NSImage* dragImage =
+ [[[NSImage alloc] initWithSize:[bitmap size]] autorelease];
+ [dragImage lockFocus];
+
+ // Draw the image with the appropriate opacity, clipping it tightly.
+ GradientButtonCell* cell = static_cast<GradientButtonCell*>([self cell]);
+ DCHECK([cell isKindOfClass:[GradientButtonCell class]]);
+ [[cell clipPathForFrame:bounds inView:self] setClip];
+ [image drawAtPoint:NSMakePoint(0, 0)
+ fromRect:NSMakeRect(0, 0, NSWidth(bounds), NSHeight(bounds))
+ operation:NSCompositeSourceOver
+ fraction:kDragImageOpacity];
+
+ [dragImage unlockFocus];
+ return dragImage;
+}
+
+@end // @implementation BookmarkButton(Private)
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h
new file mode 100644
index 0000000..2e28cf4
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h
@@ -0,0 +1,65 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BUTTON_CELL_H_
+#define CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BUTTON_CELL_H_
+#pragma once
+
+#import "base/mac/cocoa_protocols.h"
+#import "chrome/browser/ui/cocoa/gradient_button_cell.h"
+
+class BookmarkNode;
+
+// A button cell that handles drawing/highlighting of buttons in the
+// bookmark bar. This cell forwards mouseEntered/mouseExited events
+// to its control view so that pseudo-menu operations
+// (e.g. hover-over to open) can be implemented.
+@interface BookmarkButtonCell : GradientButtonCell<NSMenuDelegate> {
+ @private
+ BOOL empty_; // is this an "empty" button placeholder button cell?
+
+ // Starting index of bookmarkFolder children that we care to use.
+ int startingChildIndex_;
+
+ // Should we draw the folder arrow as needed? Not used for the bar
+ // itself but used on the folder windows.
+ BOOL drawFolderArrow_;
+
+ // Arrow for folders
+ scoped_nsobject<NSImage> arrowImage_;
+}
+
+@property (nonatomic, readwrite, assign) const BookmarkNode* bookmarkNode;
+@property (nonatomic, readwrite, assign) int startingChildIndex;
+@property (nonatomic, readwrite, assign) BOOL drawFolderArrow;
+
+// Create a button cell which draws with a theme.
++ (id)buttonCellForNode:(const BookmarkNode*)node
+ contextMenu:(NSMenu*)contextMenu
+ cellText:(NSString*)cellText
+ cellImage:(NSImage*)cellImage;
+
+// Initialize a button cell which draws with a theme.
+// Designated initializer.
+- (id)initForNode:(const BookmarkNode*)node
+ contextMenu:(NSMenu*)contextMenu
+ cellText:(NSString*)cellText
+ cellImage:(NSImage*)cellImage;
+
+- (BOOL)empty; // returns YES if empty.
+- (void)setEmpty:(BOOL)empty;
+
+// |-setBookmarkCellText:image:| is used to set the text and image of
+// a BookmarkButtonCell, and align the image to the left (NSImageLeft)
+// if there is text in the title, and centered (NSImageCenter) if
+// there is not. If |title| is nil, do not reset the title.
+- (void)setBookmarkCellText:(NSString*)title
+ image:(NSImage*)image;
+
+// Set the color of text in this cell.
+- (void)setTextColor:(NSColor*)color;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_BUTTON_CELL_H_
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.mm
new file mode 100644
index 0000000..a78d627
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.mm
@@ -0,0 +1,246 @@
+// 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 "chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h"
+
+#include "app/l10n_util_mac.h"
+#include "app/mac/nsimage_cache.h"
+#include "base/logging.h"
+#include "base/sys_string_conversions.h"
+#import "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
+#import "chrome/browser/ui/cocoa/image_utils.h"
+#include "grit/generated_resources.h"
+
+
+@interface BookmarkButtonCell(Private)
+- (void)configureBookmarkButtonCell;
+@end
+
+
+@implementation BookmarkButtonCell
+
+@synthesize startingChildIndex = startingChildIndex_;
+@synthesize drawFolderArrow = drawFolderArrow_;
+
++ (id)buttonCellForNode:(const BookmarkNode*)node
+ contextMenu:(NSMenu*)contextMenu
+ cellText:(NSString*)cellText
+ cellImage:(NSImage*)cellImage {
+ id buttonCell =
+ [[[BookmarkButtonCell alloc] initForNode:node
+ contextMenu:contextMenu
+ cellText:cellText
+ cellImage:cellImage]
+ autorelease];
+ return buttonCell;
+}
+
+- (id)initForNode:(const BookmarkNode*)node
+ contextMenu:(NSMenu*)contextMenu
+ cellText:(NSString*)cellText
+ cellImage:(NSImage*)cellImage {
+ if ((self = [super initTextCell:cellText])) {
+ [self configureBookmarkButtonCell];
+
+ [self setBookmarkNode:node];
+
+ if (node) {
+ NSString* title = base::SysUTF16ToNSString(node->GetTitle());
+ [self setBookmarkCellText:title image:cellImage];
+ [self setMenu:contextMenu];
+ } else {
+ [self setEmpty:YES];
+ [self setBookmarkCellText:l10n_util::GetNSString(IDS_MENU_EMPTY_SUBMENU)
+ image:nil];
+ }
+ }
+
+ return self;
+}
+
+- (id)initTextCell:(NSString*)string {
+ return [self initForNode:nil contextMenu:nil cellText:string cellImage:nil];
+}
+
+// Used by the off-the-side menu, the only case where a
+// BookmarkButtonCell is loaded from a nib.
+- (void)awakeFromNib {
+ [self configureBookmarkButtonCell];
+}
+
+// Perform all normal init routines specific to the BookmarkButtonCell.
+- (void)configureBookmarkButtonCell {
+ [self setButtonType:NSMomentaryPushInButton];
+ [self setBezelStyle:NSShadowlessSquareBezelStyle];
+ [self setShowsBorderOnlyWhileMouseInside:YES];
+ [self setControlSize:NSSmallControlSize];
+ [self setAlignment:NSLeftTextAlignment];
+ [self setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
+ [self setWraps:NO];
+ // NSLineBreakByTruncatingMiddle seems more common on OSX but let's
+ // try to match Windows for a bit to see what happens.
+ [self setLineBreakMode:NSLineBreakByTruncatingTail];
+
+ // Theming doesn't work for bookmark buttons yet (cell text is chucked).
+ [super setShouldTheme:NO];
+}
+
+- (BOOL)empty {
+ return empty_;
+}
+
+- (void)setEmpty:(BOOL)empty {
+ empty_ = empty;
+ [self setShowsBorderOnlyWhileMouseInside:!empty];
+}
+
+- (NSSize)cellSizeForBounds:(NSRect)aRect {
+ NSSize size = [super cellSizeForBounds:aRect];
+ // Cocoa seems to slightly underestimate how much space we need, so we
+ // compensate here to avoid a clipped rendering.
+ size.width += 2;
+ size.height += 4;
+ return size;
+}
+
+- (void)setBookmarkCellText:(NSString*)title
+ image:(NSImage*)image {
+ title = [title stringByReplacingOccurrencesOfString:@"\n"
+ withString:@" "];
+ title = [title stringByReplacingOccurrencesOfString:@"\r"
+ withString:@" "];
+ // If there is no title, squeeze things tight by displaying only the image; by
+ // default, Cocoa leaves extra space in an attempt to display an empty title.
+ if ([title length]) {
+ [self setImagePosition:NSImageLeft];
+ [self setTitle:title];
+ } else {
+ [self setImagePosition:NSImageOnly];
+ }
+
+ if (image)
+ [self setImage:image];
+}
+
+- (void)setBookmarkNode:(const BookmarkNode*)node {
+ [self setRepresentedObject:[NSValue valueWithPointer:node]];
+}
+
+- (const BookmarkNode*)bookmarkNode {
+ return static_cast<const BookmarkNode*>([[self representedObject]
+ pointerValue]);
+}
+
+// We share the context menu among all bookmark buttons. To allow us
+// to disambiguate when needed (e.g. "open bookmark"), we set the
+// menu's associated bookmark node ID to be our represented object.
+- (NSMenu*)menu {
+ if (empty_)
+ return nil;
+ BookmarkMenu* menu = (BookmarkMenu*)[super menu];
+ const BookmarkNode* node =
+ static_cast<const BookmarkNode*>([[self representedObject] pointerValue]);
+
+ if (node->GetParent() && node->GetParent()->type() == BookmarkNode::FOLDER) {
+ UserMetrics::RecordAction(UserMetricsAction("BookmarkBarFolder_CtxMenu"));
+ } else {
+ UserMetrics::RecordAction(UserMetricsAction("BookmarkBar_CtxMenu"));
+ }
+
+ [menu setRepresentedObject:[NSNumber numberWithLongLong:node->id()]];
+
+ return menu;
+}
+
+// Unfortunately, NSCell doesn't already have something like this.
+// TODO(jrg): consider placing in GTM.
+- (void)setTextColor:(NSColor*)color {
+
+ // We can't properly set the cell's text color without a control.
+ // In theory we could just save the next for later and wait until
+ // the cell is moved to a control, but there is no obvious way to
+ // accomplish that (e.g. no "cellDidMoveToControl" notification.)
+ DCHECK([self controlView]);
+
+ scoped_nsobject<NSMutableParagraphStyle> style([NSMutableParagraphStyle new]);
+ [style setAlignment:NSLeftTextAlignment];
+ NSDictionary* dict = [NSDictionary
+ dictionaryWithObjectsAndKeys:color,
+ NSForegroundColorAttributeName,
+ [self font], NSFontAttributeName,
+ style.get(), NSParagraphStyleAttributeName,
+ nil];
+ scoped_nsobject<NSAttributedString> ats([[NSAttributedString alloc]
+ initWithString:[self title]
+ attributes:dict]);
+ NSButton* button = static_cast<NSButton*>([self controlView]);
+ if (button) {
+ DCHECK([button isKindOfClass:[NSButton class]]);
+ [button setAttributedTitle:ats.get()];
+ }
+}
+
+// To implement "hover open a bookmark button to open the folder"
+// which feels like menus, we override NSButtonCell's mouseEntered:
+// and mouseExited:, then and pass them along to our owning control.
+// Note: as verified in a debugger, mouseEntered: does NOT increase
+// the retainCount of the cell or its owning control.
+- (void)mouseEntered:(NSEvent*)event {
+ [super mouseEntered:event];
+ [[self controlView] mouseEntered:event];
+}
+
+// See comment above mouseEntered:, above.
+- (void)mouseExited:(NSEvent*)event {
+ [[self controlView] mouseExited:event];
+ [super mouseExited:event];
+}
+
+- (void)setDrawFolderArrow:(BOOL)draw {
+ drawFolderArrow_ = draw;
+ if (draw && !arrowImage_) {
+ arrowImage_.reset(
+ [app::mac::GetCachedImageWithName(@"menu_hierarchy_arrow.pdf") retain]);
+ }
+}
+
+// Add extra size for the arrow so it doesn't overlap the text.
+// Does not sanity check to be sure this is actually a folder node.
+- (NSSize)cellSize {
+ NSSize cellSize = [super cellSize];
+ if (drawFolderArrow_) {
+ cellSize.width += [arrowImage_ size].width; // plus margin?
+ }
+ return cellSize;
+}
+
+// Override cell drawing to add a submenu arrow like a real menu.
+- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
+ // First draw "everything else".
+ [super drawInteriorWithFrame:cellFrame inView:controlView];
+
+ // If asked to do so, and if a folder, draw the arrow.
+ if (!drawFolderArrow_)
+ return;
+ BookmarkButton* button = static_cast<BookmarkButton*>([self controlView]);
+ DCHECK([button respondsToSelector:@selector(isFolder)]);
+ if ([button isFolder]) {
+ NSRect imageRect = NSZeroRect;
+ imageRect.size = [arrowImage_ size];
+ NSRect drawRect = NSOffsetRect(imageRect,
+ NSWidth(cellFrame) - NSWidth(imageRect),
+ (NSHeight(cellFrame) / 2.0) -
+ (NSHeight(imageRect) / 2.0));
+ [arrowImage_ drawInRect:drawRect
+ fromRect:imageRect
+ operation:NSCompositeSourceOver
+ fraction:[self isEnabled] ? 1.0 : 0.5
+ neverFlipped:YES];
+ }
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell_unittest.mm
new file mode 100644
index 0000000..ff26512
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell_unittest.mm
@@ -0,0 +1,183 @@
+// 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.
+
+#include "app/resource_bundle.h"
+#include "base/scoped_nsobject.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "grit/app_resources.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+// Simple class to remember how many mouseEntered: and mouseExited:
+// calls it gets. Only used by BookmarkMouseForwarding but placed
+// at the top of the file to keep it outside the anon namespace.
+@interface ButtonRemembersMouseEnterExit : NSButton {
+ @public
+ int enters_;
+ int exits_;
+}
+@end
+
+@implementation ButtonRemembersMouseEnterExit
+- (void)mouseEntered:(NSEvent*)event {
+ enters_++;
+}
+- (void)mouseExited:(NSEvent*)event {
+ exits_++;
+}
+@end
+
+
+namespace {
+
+class BookmarkButtonCellTest : public CocoaTest {
+ public:
+ BrowserTestHelper helper_;
+};
+
+// Make sure it's not totally bogus
+TEST_F(BookmarkButtonCellTest, SizeForBounds) {
+ NSRect frame = NSMakeRect(0, 0, 50, 30);
+ scoped_nsobject<NSButton> view([[NSButton alloc] initWithFrame:frame]);
+ scoped_nsobject<BookmarkButtonCell> cell(
+ [[BookmarkButtonCell alloc] initTextCell:@"Testing"]);
+ [view setCell:cell.get()];
+ [[test_window() contentView] addSubview:view];
+
+ NSRect r = NSMakeRect(0, 0, 100, 100);
+ NSSize size = [cell.get() cellSizeForBounds:r];
+ EXPECT_TRUE(size.width > 0 && size.height > 0);
+ EXPECT_TRUE(size.width < 200 && size.height < 200);
+}
+
+// Make sure icon-only buttons are squeezed tightly.
+TEST_F(BookmarkButtonCellTest, IconOnlySqueeze) {
+ NSRect frame = NSMakeRect(0, 0, 50, 30);
+ scoped_nsobject<NSButton> view([[NSButton alloc] initWithFrame:frame]);
+ scoped_nsobject<BookmarkButtonCell> cell(
+ [[BookmarkButtonCell alloc] initTextCell:@"Testing"]);
+ [view setCell:cell.get()];
+ [[test_window() contentView] addSubview:view];
+
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ scoped_nsobject<NSImage> image([rb.GetNativeImageNamed(IDR_DEFAULT_FAVICON)
+ retain]);
+ EXPECT_TRUE(image.get());
+
+ NSRect r = NSMakeRect(0, 0, 100, 100);
+ [cell setBookmarkCellText:@" " image:image];
+ CGFloat two_space_width = [cell.get() cellSizeForBounds:r].width;
+ [cell setBookmarkCellText:@" " image:image];
+ CGFloat one_space_width = [cell.get() cellSizeForBounds:r].width;
+ [cell setBookmarkCellText:@"" image:image];
+ CGFloat zero_space_width = [cell.get() cellSizeForBounds:r].width;
+
+ // Make sure the switch to "no title" is more significant than we
+ // would otherwise see by decreasing the length of the title.
+ CGFloat delta1 = two_space_width - one_space_width;
+ CGFloat delta2 = one_space_width - zero_space_width;
+ EXPECT_GT(delta2, delta1);
+
+}
+
+// Make sure the default from the base class is overridden.
+TEST_F(BookmarkButtonCellTest, MouseEnterStuff) {
+ scoped_nsobject<BookmarkButtonCell> cell(
+ [[BookmarkButtonCell alloc] initTextCell:@"Testing"]);
+ // Setting the menu should have no affect since we either share or
+ // dynamically compose the menu given a node.
+ [cell setMenu:[[[BookmarkMenu alloc] initWithTitle:@"foo"] autorelease]];
+ EXPECT_FALSE([cell menu]);
+
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ const BookmarkNode* node = model->GetBookmarkBarNode();
+ [cell setEmpty:NO];
+ [cell setBookmarkNode:node];
+ EXPECT_TRUE([cell showsBorderOnlyWhileMouseInside]);
+ EXPECT_TRUE([cell menu]);
+
+ [cell setEmpty:YES];
+ EXPECT_FALSE([cell.get() showsBorderOnlyWhileMouseInside]);
+ EXPECT_FALSE([cell menu]);
+}
+
+TEST_F(BookmarkButtonCellTest, BookmarkNode) {
+ BookmarkModel& model(*(helper_.profile()->GetBookmarkModel()));
+ scoped_nsobject<BookmarkButtonCell> cell(
+ [[BookmarkButtonCell alloc] initTextCell:@"Testing"]);
+
+ const BookmarkNode* node = model.GetBookmarkBarNode();
+ [cell setBookmarkNode:node];
+ EXPECT_EQ(node, [cell bookmarkNode]);
+
+ node = model.other_node();
+ [cell setBookmarkNode:node];
+ EXPECT_EQ(node, [cell bookmarkNode]);
+}
+
+TEST_F(BookmarkButtonCellTest, BookmarkMouseForwarding) {
+ scoped_nsobject<BookmarkButtonCell> cell(
+ [[BookmarkButtonCell alloc] initTextCell:@"Testing"]);
+ scoped_nsobject<ButtonRemembersMouseEnterExit>
+ button([[ButtonRemembersMouseEnterExit alloc]
+ initWithFrame:NSMakeRect(0,0,50,50)]);
+ [button setCell:cell.get()];
+ EXPECT_EQ(0, button.get()->enters_);
+ EXPECT_EQ(0, button.get()->exits_);
+ NSEvent* event = [NSEvent mouseEventWithType:NSMouseMoved
+ location:NSMakePoint(10,10)
+ modifierFlags:0
+ timestamp:0
+ windowNumber:0
+ context:nil
+ eventNumber:0
+ clickCount:0
+ pressure:0];
+ [cell mouseEntered:event];
+ EXPECT_TRUE(button.get()->enters_ && !button.get()->exits_);
+
+ for (int i = 0; i < 3; i++)
+ [cell mouseExited:event];
+ EXPECT_EQ(button.get()->enters_, 1);
+ EXPECT_EQ(button.get()->exits_, 3);
+}
+
+// Confirms a cell created in a nib is initialized properly
+TEST_F(BookmarkButtonCellTest, Awake) {
+ scoped_nsobject<BookmarkButtonCell> cell([[BookmarkButtonCell alloc] init]);
+ [cell awakeFromNib];
+ EXPECT_EQ(NSLeftTextAlignment, [cell alignment]);
+}
+
+// Subfolder arrow details.
+TEST_F(BookmarkButtonCellTest, FolderArrow) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ const BookmarkNode* bar = model->GetBookmarkBarNode();
+ const BookmarkNode* node = model->AddURL(bar, bar->GetChildCount(),
+ ASCIIToUTF16("title"),
+ GURL("http://www.google.com"));
+ scoped_nsobject<BookmarkButtonCell> cell(
+ [[BookmarkButtonCell alloc] initForNode:node
+ contextMenu:nil
+ cellText:@"small"
+ cellImage:nil]);
+ EXPECT_TRUE(cell.get());
+
+ NSSize size = [cell cellSize];
+ // sanity check
+ EXPECT_GE(size.width, 2);
+ EXPECT_GE(size.height, 2);
+
+ // Once we turn on arrow drawing make sure there is now room for it.
+ [cell setDrawFolderArrow:YES];
+ NSSize arrowSize = [cell cellSize];
+ EXPECT_GT(arrowSize.width, size.width);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_button_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_button_unittest.mm
new file mode 100644
index 0000000..93bd769
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_button_unittest.mm
@@ -0,0 +1,174 @@
+// 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.
+
+#include "base/scoped_nsobject.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h"
+#import "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test_event_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+// Fake BookmarkButton delegate to get a pong on mouse entered/exited
+@interface FakeButtonDelegate : NSObject<BookmarkButtonDelegate> {
+ @public
+ int entered_;
+ int exited_;
+ BOOL canDragToTrash_;
+ int didDragToTrashCount_;
+}
+@end
+
+@implementation FakeButtonDelegate
+
+- (void)fillPasteboard:(NSPasteboard*)pboard
+ forDragOfButton:(BookmarkButton*)button {
+}
+
+- (void)mouseEnteredButton:(id)buton event:(NSEvent*)event {
+ entered_++;
+}
+
+- (void)mouseExitedButton:(id)buton event:(NSEvent*)event {
+ exited_++;
+}
+
+- (BOOL)dragShouldLockBarVisibility {
+ return NO;
+}
+
+- (NSWindow*)browserWindow {
+ return nil;
+}
+
+- (BOOL)canDragBookmarkButtonToTrash:(BookmarkButton*)button {
+ return canDragToTrash_;
+}
+
+- (void)didDragBookmarkToTrash:(BookmarkButton*)button {
+ didDragToTrashCount_++;
+}
+
+@end
+
+namespace {
+
+class BookmarkButtonTest : public CocoaTest {
+};
+
+// Make sure nothing leaks
+TEST_F(BookmarkButtonTest, Create) {
+ scoped_nsobject<BookmarkButton> button;
+ button.reset([[BookmarkButton alloc] initWithFrame:NSMakeRect(0,0,500,500)]);
+}
+
+// Test folder and empty node queries.
+TEST_F(BookmarkButtonTest, FolderAndEmptyOrNot) {
+ BrowserTestHelper helper_;
+ scoped_nsobject<BookmarkButton> button;
+ scoped_nsobject<BookmarkButtonCell> cell;
+
+ button.reset([[BookmarkButton alloc] initWithFrame:NSMakeRect(0,0,500,500)]);
+ cell.reset([[BookmarkButtonCell alloc] initTextCell:@"hi mom"]);
+ [button setCell:cell];
+
+ EXPECT_TRUE([button isEmpty]);
+ EXPECT_FALSE([button isFolder]);
+ EXPECT_FALSE([button bookmarkNode]);
+
+ NSEvent* downEvent =
+ test_event_utils::LeftMouseDownAtPoint(NSMakePoint(10,10));
+ // Since this returns (does not actually begin a modal drag), success!
+ [button beginDrag:downEvent];
+
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ const BookmarkNode* node = model->GetBookmarkBarNode();
+ [cell setBookmarkNode:node];
+ EXPECT_FALSE([button isEmpty]);
+ EXPECT_TRUE([button isFolder]);
+ EXPECT_EQ([button bookmarkNode], node);
+
+ node = model->AddURL(node, 0, ASCIIToUTF16("hi mom"),
+ GURL("http://www.google.com"));
+ [cell setBookmarkNode:node];
+ EXPECT_FALSE([button isEmpty]);
+ EXPECT_FALSE([button isFolder]);
+ EXPECT_EQ([button bookmarkNode], node);
+}
+
+TEST_F(BookmarkButtonTest, MouseEnterExitRedirect) {
+ NSEvent* moveEvent =
+ test_event_utils::MouseEventAtPoint(NSMakePoint(10,10), NSMouseMoved, 0);
+ scoped_nsobject<BookmarkButton> button;
+ scoped_nsobject<BookmarkButtonCell> cell;
+ scoped_nsobject<FakeButtonDelegate>
+ delegate([[FakeButtonDelegate alloc] init]);
+ button.reset([[BookmarkButton alloc] initWithFrame:NSMakeRect(0,0,500,500)]);
+ cell.reset([[BookmarkButtonCell alloc] initTextCell:@"hi mom"]);
+ [button setCell:cell];
+ [button setDelegate:delegate];
+
+ EXPECT_EQ(0, delegate.get()->entered_);
+ EXPECT_EQ(0, delegate.get()->exited_);
+
+ [button mouseEntered:moveEvent];
+ EXPECT_EQ(1, delegate.get()->entered_);
+ EXPECT_EQ(0, delegate.get()->exited_);
+
+ [button mouseExited:moveEvent];
+ [button mouseExited:moveEvent];
+ EXPECT_EQ(1, delegate.get()->entered_);
+ EXPECT_EQ(2, delegate.get()->exited_);
+}
+
+TEST_F(BookmarkButtonTest, DragToTrash) {
+ BrowserTestHelper helper_;
+
+ scoped_nsobject<BookmarkButton> button;
+ scoped_nsobject<BookmarkButtonCell> cell;
+ scoped_nsobject<FakeButtonDelegate>
+ delegate([[FakeButtonDelegate alloc] init]);
+ button.reset([[BookmarkButton alloc] initWithFrame:NSMakeRect(0,0,500,500)]);
+ cell.reset([[BookmarkButtonCell alloc] initTextCell:@"hi mom"]);
+ [button setCell:cell];
+ [button setDelegate:delegate];
+
+ // Add a deletable bookmark to the button.
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ const BookmarkNode* barNode = model->GetBookmarkBarNode();
+ const BookmarkNode* node = model->AddURL(barNode, 0, ASCIIToUTF16("hi mom"),
+ GURL("http://www.google.com"));
+ [cell setBookmarkNode:node];
+
+ // Verify that if canDragBookmarkButtonToTrash is NO then the button can't
+ // be dragged to the trash.
+ delegate.get()->canDragToTrash_ = NO;
+ NSDragOperation operation = [button draggingSourceOperationMaskForLocal:NO];
+ EXPECT_EQ(0u, operation & NSDragOperationDelete);
+ operation = [button draggingSourceOperationMaskForLocal:YES];
+ EXPECT_EQ(0u, operation & NSDragOperationDelete);
+
+ // Verify that if canDragBookmarkButtonToTrash is YES then the button can
+ // be dragged to the trash.
+ delegate.get()->canDragToTrash_ = YES;
+ operation = [button draggingSourceOperationMaskForLocal:NO];
+ EXPECT_EQ(NSDragOperationDelete, operation & NSDragOperationDelete);
+ operation = [button draggingSourceOperationMaskForLocal:YES];
+ EXPECT_EQ(NSDragOperationDelete, operation & NSDragOperationDelete);
+
+ // Verify that canDragBookmarkButtonToTrash is called when expected.
+ delegate.get()->canDragToTrash_ = YES;
+ EXPECT_EQ(0, delegate.get()->didDragToTrashCount_);
+ [button draggedImage:nil endedAt:NSZeroPoint operation:NSDragOperationCopy];
+ EXPECT_EQ(0, delegate.get()->didDragToTrashCount_);
+ [button draggedImage:nil endedAt:NSZeroPoint operation:NSDragOperationMove];
+ EXPECT_EQ(0, delegate.get()->didDragToTrashCount_);
+ [button draggedImage:nil endedAt:NSZeroPoint operation:NSDragOperationDelete];
+ EXPECT_EQ(1, delegate.get()->didDragToTrashCount_);
+}
+
+}
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_drag_source.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_drag_source.h
new file mode 100644
index 0000000..53d4361
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_drag_source.h
@@ -0,0 +1,30 @@
+// 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 "chrome/browser/bookmarks/bookmark_node_data.h"
+#include "chrome/browser/ui/cocoa/web_contents_drag_source.h"
+
+// A class that handles tracking and event processing for a drag and drop
+// originating from the content area.
+@interface BookmarkDragSource : WebContentsDragSource {
+ @private
+ // Our drop data. Should only be initialized once.
+ std::vector<BookmarkNodeData::Element> dropData_;
+
+ Profile* profile_;
+}
+
+// Initialize a DragDataSource object for a drag (originating on the given
+// contentsView and with the given dropData and pboard). Fill the pasteboard
+// with data types appropriate for dropData.
+- (id)initWithContentsView:(TabContentsViewCocoa*)contentsView
+ dropData:
+ (const std::vector<BookmarkNodeData::Element>&)dropData
+ profile:(Profile*)profile
+ pasteboard:(NSPasteboard*)pboard
+ dragOperationMask:(NSDragOperation)dragOperationMask;
+
+@end
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_drag_source.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_drag_source.mm
new file mode 100644
index 0000000..85ea1b9
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_drag_source.mm
@@ -0,0 +1,43 @@
+// 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 "chrome/browser/ui/cocoa/bookmarks/bookmark_drag_source.h"
+
+#include "chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents_view_mac.h"
+
+@implementation BookmarkDragSource
+
+- (id)initWithContentsView:(TabContentsViewCocoa*)contentsView
+ dropData:
+ (const std::vector<BookmarkNodeData::Element>&)dropData
+ profile:(Profile*)profile
+ pasteboard:(NSPasteboard*)pboard
+ dragOperationMask:(NSDragOperation)dragOperationMask {
+ self = [super initWithContentsView:contentsView
+ pasteboard:pboard
+ dragOperationMask:dragOperationMask];
+ if (self) {
+ dropData_ = dropData;
+ profile_ = profile;
+ }
+
+ return self;
+}
+
+- (void)fillPasteboard {
+ bookmark_pasteboard_helper_mac::WriteToDragClipboard(dropData_,
+ profile_->GetPath().value());
+}
+
+- (NSImage*)dragImage {
+ // TODO(feldstein): Do something better than this. Should have badging
+ // and a single drag image.
+ // http://crbug.com/37264
+ return [NSImage imageNamed:NSImageNameMultipleDocuments];
+}
+
+@end // @implementation BookmarkDragSource
+
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller.h
new file mode 100644
index 0000000..34e7032
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller.h
@@ -0,0 +1,171 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_EDITOR_BASE_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_EDITOR_BASE_CONTROLLER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_ptr.h"
+#include "base/scoped_nsobject.h"
+#include "chrome/browser/bookmarks/bookmark_editor.h"
+
+class BookmarkEditorBaseControllerBridge;
+class BookmarkModel;
+@class BookmarkTreeBrowserCell;
+
+// A base controller class for bookmark creation and editing dialogs which
+// present the current bookmark folder structure in a tree view. Do not
+// instantiate this controller directly -- use one of its derived classes.
+// NOTE: If a derived class is intended to be dispatched via the
+// BookmarkEditor::Show static function found in the accompanying
+// implementation, that function will need to be update.
+@interface BookmarkEditorBaseController : NSWindowController {
+ @private
+ IBOutlet NSButton* newFolderButton_;
+ IBOutlet NSButton* okButton_; // Used for unit testing only.
+ IBOutlet NSTreeController* folderTreeController_;
+ IBOutlet NSOutlineView* folderTreeView_;
+
+ NSWindow* parentWindow_; // weak
+ Profile* profile_; // weak
+ const BookmarkNode* parentNode_; // weak; owned by the model
+ BookmarkEditor::Configuration configuration_;
+ NSString* initialName_;
+ NSString* displayName_; // Bound to a text field in the dialog.
+ BOOL okEnabled_; // Bound to the OK button.
+ // An array of BookmarkFolderInfo where each item describes a folder in the
+ // BookmarkNode structure.
+ scoped_nsobject<NSArray> folderTreeArray_;
+ // Bound to the table view giving a path to the current selections, of which
+ // there should only ever be one.
+ scoped_nsobject<NSArray> tableSelectionPaths_;
+ // C++ bridge object that observes the BookmarkModel for me.
+ scoped_ptr<BookmarkEditorBaseControllerBridge> observer_;
+}
+
+@property (nonatomic, copy) NSString* initialName;
+@property (nonatomic, copy) NSString* displayName;
+@property (nonatomic, assign) BOOL okEnabled;
+@property (nonatomic, retain, readonly) NSArray* folderTreeArray;
+@property (nonatomic, copy) NSArray* tableSelectionPaths;
+
+// Designated initializer. Derived classes should call through to this init.
+- (id)initWithParentWindow:(NSWindow*)parentWindow
+ nibName:(NSString*)nibName
+ profile:(Profile*)profile
+ parent:(const BookmarkNode*)parent
+ configuration:(BookmarkEditor::Configuration)configuration;
+
+// Run the bookmark editor as a modal sheet. Does not block.
+- (void)runAsModalSheet;
+
+// Create a new folder at the end of the selected parent folder, give it
+// an untitled name, and put it into editing mode.
+- (IBAction)newFolder:(id)sender;
+
+// The cancel action will dismiss the dialog. Derived classes which
+// override cancel:, must call this after accessing any dialog-related
+// data.
+- (IBAction)cancel:(id)sender;
+
+// The OK action will dismiss the dialog. This action is bound
+// to the OK button of a dialog which presents a tree view of a profile's
+// folder hierarchy and allows the creation of new folders within that tree.
+// When the OK button is pressed, this function will: 1) call the derived
+// class's -[willCommit] function, 2) create any new folders created by
+// the user while the dialog is presented, 3) call the derived class's
+// -[didCommit] function, and then 4) dismiss the dialog. At least one
+// of -[willCommit] and -[didCommit] must be provided by the derived class
+// and should return a NSNumber containing a BOOL or nil ('nil' means YES)
+// indicating if the operation should be allowed to continue.
+// Note: A derived class should not override the ok: action.
+- (IBAction)ok:(id)sender;
+
+// Methods for use by derived classes only.
+
+// Determine and returns the rightmost selected/highlighted element (node)
+// in the bookmark tree view if the tree view is showing, otherwise returns
+// the original |parentNode_|. If the tree view is showing but nothing is
+// selected then the root node is returned.
+- (const BookmarkNode*)selectedNode;
+
+// Select/highlight the given node within the browser tree view. If the
+// node is nil then select the bookmark bar node. Exposed for unit test.
+- (void)selectNodeInBrowser:(const BookmarkNode*)node;
+
+// Notifications called when the BookmarkModel changes out from under me.
+- (void)nodeRemoved:(const BookmarkNode*)node
+ fromParent:(const BookmarkNode*)parent;
+- (void)modelChangedPreserveSelection:(BOOL)preserve;
+
+// Accessors
+- (BookmarkModel*)bookmarkModel;
+- (const BookmarkNode*)parentNode;
+
+@end
+
+// Describes the profile's bookmark folder structure: the folder name, the
+// original BookmarkNode pointer (if the folder already exists), a BOOL
+// indicating if the folder is new (meaning: created during this session
+// but not yet committed to the bookmark structure), and an NSArray of
+// child folder BookmarkFolderInfo's following this same structure.
+@interface BookmarkFolderInfo : NSObject {
+ @private
+ NSString* folderName_;
+ const BookmarkNode* folderNode_; // weak
+ NSMutableArray* children_;
+ BOOL newFolder_;
+}
+
+@property (nonatomic, copy) NSString* folderName;
+@property (nonatomic, assign) const BookmarkNode* folderNode;
+@property (nonatomic, retain) NSMutableArray* children;
+@property (nonatomic, assign) BOOL newFolder;
+
+// Convenience creator for adding a new folder to the editor's bookmark
+// structure. This folder will be added to the bookmark model when the
+// user accepts the dialog. |folderName| must be provided.
++ (id)bookmarkFolderInfoWithFolderName:(NSString*)folderName;
+
+// Designated initializer. |folderName| must be provided. For folders which
+// already exist in the bookmark model, |folderNode| and |children| (if any
+// children are already attached to this folder) must be provided and
+// |newFolder| should be NO. For folders which the user has added during
+// this session and which have not been committed yet, |newFolder| should be
+// YES and |folderNode| and |children| should be NULL/nil.
+- (id)initWithFolderName:(NSString*)folderName
+ folderNode:(const BookmarkNode*)folderNode
+ children:(NSMutableArray*)children
+ newFolder:(BOOL)newFolder;
+
+// Convenience creator used during construction of the editor's bookmark
+// structure. |folderName| and |folderNode| must be provided. |children|
+// is optional. Private: exposed here for unit testing purposes.
++ (id)bookmarkFolderInfoWithFolderName:(NSString*)folderName
+ folderNode:(const BookmarkNode*)folderNode
+ children:(NSMutableArray*)children;
+
+@end
+
+@interface BookmarkEditorBaseController(TestingAPI)
+
+@property (nonatomic, readonly) BOOL okButtonEnabled;
+
+// Create any newly added folders. New folders are nodes in folderTreeArray
+// which are marked as being new (i.e. their kFolderTreeNewFolderKey
+// dictionary item is YES). This is called by -[ok:].
+- (void)createNewFolders;
+
+// Select the given bookmark node within the tree view.
+- (void)selectTestNodeInBrowser:(const BookmarkNode*)node;
+
+// Return the dictionary for the folder selected in the tree.
+- (BookmarkFolderInfo*)selectedFolder;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_EDITOR_BASE_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller.mm
new file mode 100644
index 0000000..ffc9d69
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller.mm
@@ -0,0 +1,604 @@
+// 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.
+
+#include <stack>
+
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller.h"
+
+#include "app/l10n_util.h"
+#include "app/l10n_util_mac.h"
+#include "base/logging.h"
+#include "base/mac_util.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/profiles/profile.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_all_tabs_controller.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#include "grit/generated_resources.h"
+
+@interface BookmarkEditorBaseController ()
+
+// Return the folder tree object for the given path.
+- (BookmarkFolderInfo*)folderForIndexPath:(NSIndexPath*)path;
+
+// (Re)build the folder tree from the BookmarkModel's current state.
+- (void)buildFolderTree;
+
+// Notifies the controller that the bookmark model has changed.
+// |selection| specifies if the current selection should be
+// maintained (usually YES).
+- (void)modelChangedPreserveSelection:(BOOL)preserve;
+
+// Notifies the controller that a node has been removed.
+- (void)nodeRemoved:(const BookmarkNode*)node
+ fromParent:(const BookmarkNode*)parent;
+
+// Given a folder node, collect an array containing BookmarkFolderInfos
+// describing its subchildren which are also folders.
+- (NSMutableArray*)addChildFoldersFromNode:(const BookmarkNode*)node;
+
+// Scan the folder tree stemming from the given tree folder and create
+// any newly added folders. Pass down info for the folder which was
+// selected before we began creating folders.
+- (void)createNewFoldersForFolder:(BookmarkFolderInfo*)treeFolder
+ selectedFolderInfo:(BookmarkFolderInfo*)selectedFolderInfo;
+
+// Scan the folder tree looking for the given bookmark node and return
+// the selection path thereto.
+- (NSIndexPath*)selectionPathForNode:(const BookmarkNode*)node;
+
+@end
+
+// static; implemented for each platform. Update this function for new
+// classes derived from BookmarkEditorBaseController.
+void BookmarkEditor::Show(gfx::NativeWindow parent_hwnd,
+ Profile* profile,
+ const BookmarkNode* parent,
+ const EditDetails& details,
+ Configuration configuration) {
+ BookmarkEditorBaseController* controller = nil;
+ if (details.type == EditDetails::NEW_FOLDER) {
+ controller = [[BookmarkAllTabsController alloc]
+ initWithParentWindow:parent_hwnd
+ profile:profile
+ parent:parent
+ configuration:configuration];
+ } else {
+ controller = [[BookmarkEditorController alloc]
+ initWithParentWindow:parent_hwnd
+ profile:profile
+ parent:parent
+ node:details.existing_node
+ configuration:configuration];
+ }
+ [controller runAsModalSheet];
+}
+
+// Adapter to tell BookmarkEditorBaseController when bookmarks change.
+class BookmarkEditorBaseControllerBridge : public BookmarkModelObserver {
+ public:
+ BookmarkEditorBaseControllerBridge(BookmarkEditorBaseController* controller)
+ : controller_(controller),
+ importing_(false)
+ { }
+
+ virtual void Loaded(BookmarkModel* model) {
+ [controller_ modelChangedPreserveSelection:YES];
+ }
+
+ virtual void BookmarkNodeMoved(BookmarkModel* model,
+ const BookmarkNode* old_parent,
+ int old_index,
+ const BookmarkNode* new_parent,
+ int new_index) {
+ if (!importing_ && new_parent->GetChild(new_index)->is_folder())
+ [controller_ modelChangedPreserveSelection:YES];
+ }
+
+ virtual void BookmarkNodeAdded(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int index) {
+ if (!importing_ && parent->GetChild(index)->is_folder())
+ [controller_ modelChangedPreserveSelection:YES];
+ }
+
+ virtual void BookmarkNodeRemoved(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int old_index,
+ const BookmarkNode* node) {
+ [controller_ nodeRemoved:node fromParent:parent];
+ if (node->is_folder())
+ [controller_ modelChangedPreserveSelection:NO];
+ }
+
+ virtual void BookmarkNodeChanged(BookmarkModel* model,
+ const BookmarkNode* node) {
+ if (!importing_ && node->is_folder())
+ [controller_ modelChangedPreserveSelection:YES];
+ }
+
+ virtual void BookmarkNodeChildrenReordered(BookmarkModel* model,
+ const BookmarkNode* node) {
+ if (!importing_)
+ [controller_ modelChangedPreserveSelection:YES];
+ }
+
+ virtual void BookmarkNodeFavIconLoaded(BookmarkModel* model,
+ const BookmarkNode* node) {
+ // I care nothing for these 'favicons': I only show folders.
+ }
+
+ virtual void BookmarkImportBeginning(BookmarkModel* model) {
+ importing_ = true;
+ }
+
+ // Invoked after a batch import finishes. This tells observers to update
+ // themselves if they were waiting for the update to finish.
+ virtual void BookmarkImportEnding(BookmarkModel* model) {
+ importing_ = false;
+ [controller_ modelChangedPreserveSelection:YES];
+ }
+
+ private:
+ BookmarkEditorBaseController* controller_; // weak
+ bool importing_;
+};
+
+
+#pragma mark -
+
+@implementation BookmarkEditorBaseController
+
+@synthesize initialName = initialName_;
+@synthesize displayName = displayName_;
+@synthesize okEnabled = okEnabled_;
+
+- (id)initWithParentWindow:(NSWindow*)parentWindow
+ nibName:(NSString*)nibName
+ profile:(Profile*)profile
+ parent:(const BookmarkNode*)parent
+ configuration:(BookmarkEditor::Configuration)configuration {
+ NSString* nibpath = [mac_util::MainAppBundle()
+ pathForResource:nibName
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
+ parentWindow_ = parentWindow;
+ profile_ = profile;
+ parentNode_ = parent;
+ configuration_ = configuration;
+ initialName_ = [@"" retain];
+ observer_.reset(new BookmarkEditorBaseControllerBridge(self));
+ [self bookmarkModel]->AddObserver(observer_.get());
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [self bookmarkModel]->RemoveObserver(observer_.get());
+ [initialName_ release];
+ [displayName_ release];
+ [super dealloc];
+}
+
+- (void)awakeFromNib {
+ [self setDisplayName:[self initialName]];
+
+ if (configuration_ != BookmarkEditor::SHOW_TREE) {
+ // Remember the tree view's height; we will shrink our frame by that much.
+ NSRect frame = [[self window] frame];
+ CGFloat browserHeight = [folderTreeView_ frame].size.height;
+ frame.size.height -= browserHeight;
+ frame.origin.y += browserHeight;
+ // Remove the folder tree and "new folder" button.
+ [folderTreeView_ removeFromSuperview];
+ [newFolderButton_ removeFromSuperview];
+ // Finally, commit the size change.
+ [[self window] setFrame:frame display:YES];
+ }
+
+ // Build up a tree of the current folder configuration.
+ [self buildFolderTree];
+}
+
+- (void)windowDidLoad {
+ if (configuration_ == BookmarkEditor::SHOW_TREE) {
+ [self selectNodeInBrowser:parentNode_];
+ }
+}
+
+/* TODO(jrg):
+// Implementing this informal protocol allows us to open the sheet
+// somewhere other than at the top of the window. NOTE: this means
+// that I, the controller, am also the window's delegate.
+- (NSRect)window:(NSWindow*)window willPositionSheet:(NSWindow*)sheet
+ usingRect:(NSRect)rect {
+ // adjust rect.origin.y to be the bottom of the toolbar
+ return rect;
+}
+*/
+
+// TODO(jrg): consider NSModalSession.
+- (void)runAsModalSheet {
+ // Lock down floating bar when in full-screen mode. Don't animate
+ // otherwise the pane will be misplaced.
+ [[BrowserWindowController browserWindowControllerForWindow:parentWindow_]
+ lockBarVisibilityForOwner:self withAnimation:NO delay:NO];
+ [NSApp beginSheet:[self window]
+ modalForWindow:parentWindow_
+ modalDelegate:self
+ didEndSelector:@selector(didEndSheet:returnCode:contextInfo:)
+ contextInfo:nil];
+}
+
+- (BOOL)okEnabled {
+ return YES;
+}
+
+- (IBAction)ok:(id)sender {
+ // At least one of these two functions should be provided by derived classes.
+ BOOL hasWillCommit = [self respondsToSelector:@selector(willCommit)];
+ BOOL hasDidCommit = [self respondsToSelector:@selector(didCommit)];
+ DCHECK(hasWillCommit || hasDidCommit);
+ BOOL shouldContinue = YES;
+ if (hasWillCommit) {
+ NSNumber* hasWillContinue = [self performSelector:@selector(willCommit)];
+ if (hasWillContinue && [hasWillContinue isKindOfClass:[NSNumber class]])
+ shouldContinue = [hasWillContinue boolValue];
+ }
+ if (shouldContinue)
+ [self createNewFolders];
+ if (hasDidCommit) {
+ NSNumber* hasDidContinue = [self performSelector:@selector(didCommit)];
+ if (hasDidContinue && [hasDidContinue isKindOfClass:[NSNumber class]])
+ shouldContinue = [hasDidContinue boolValue];
+ }
+ if (shouldContinue)
+ [NSApp endSheet:[self window]];
+}
+
+- (IBAction)cancel:(id)sender {
+ [NSApp endSheet:[self window]];
+}
+
+- (void)didEndSheet:(NSWindow*)sheet
+ returnCode:(int)returnCode
+ contextInfo:(void*)contextInfo {
+ [sheet close];
+ [[BrowserWindowController browserWindowControllerForWindow:parentWindow_]
+ releaseBarVisibilityForOwner:self withAnimation:YES delay:NO];
+}
+
+- (void)windowWillClose:(NSNotification*)notification {
+ [self autorelease];
+}
+
+#pragma mark Folder Tree Management
+
+- (BookmarkModel*)bookmarkModel {
+ return profile_->GetBookmarkModel();
+}
+
+- (const BookmarkNode*)parentNode {
+ return parentNode_;
+}
+
+- (BookmarkFolderInfo*)folderForIndexPath:(NSIndexPath*)indexPath {
+ NSUInteger pathCount = [indexPath length];
+ BookmarkFolderInfo* item = nil;
+ NSArray* treeNode = [self folderTreeArray];
+ for (NSUInteger i = 0; i < pathCount; ++i) {
+ item = [treeNode objectAtIndex:[indexPath indexAtPosition:i]];
+ treeNode = [item children];
+ }
+ return item;
+}
+
+- (NSIndexPath*)selectedIndexPath {
+ NSIndexPath* selectedIndexPath = nil;
+ NSArray* selections = [self tableSelectionPaths];
+ if ([selections count]) {
+ DCHECK([selections count] == 1); // Should be exactly one selection.
+ selectedIndexPath = [selections objectAtIndex:0];
+ }
+ return selectedIndexPath;
+}
+
+- (BookmarkFolderInfo*)selectedFolder {
+ BookmarkFolderInfo* item = nil;
+ NSIndexPath* selectedIndexPath = [self selectedIndexPath];
+ if (selectedIndexPath) {
+ item = [self folderForIndexPath:selectedIndexPath];
+ }
+ return item;
+}
+
+- (const BookmarkNode*)selectedNode {
+ const BookmarkNode* selectedNode = NULL;
+ // Determine a new parent node only if the browser is showing.
+ if (configuration_ == BookmarkEditor::SHOW_TREE) {
+ BookmarkFolderInfo* folderInfo = [self selectedFolder];
+ if (folderInfo)
+ selectedNode = [folderInfo folderNode];
+ } else {
+ // If the tree is not showing then we use the original parent.
+ selectedNode = parentNode_;
+ }
+ return selectedNode;
+}
+
+- (NSArray*)folderTreeArray {
+ return folderTreeArray_.get();
+}
+
+- (NSArray*)tableSelectionPaths {
+ return tableSelectionPaths_.get();
+}
+
+- (void)setTableSelectionPath:(NSIndexPath*)tableSelectionPath {
+ [self setTableSelectionPaths:[NSArray arrayWithObject:tableSelectionPath]];
+}
+
+- (void)setTableSelectionPaths:(NSArray*)tableSelectionPaths {
+ tableSelectionPaths_.reset([tableSelectionPaths retain]);
+}
+
+- (void)selectNodeInBrowser:(const BookmarkNode*)node {
+ DCHECK(configuration_ == BookmarkEditor::SHOW_TREE);
+ NSIndexPath* selectionPath = [self selectionPathForNode:node];
+ [self willChangeValueForKey:@"okEnabled"];
+ [self setTableSelectionPath:selectionPath];
+ [self didChangeValueForKey:@"okEnabled"];
+}
+
+- (NSIndexPath*)selectionPathForNode:(const BookmarkNode*)desiredNode {
+ // Back up the parent chaing for desiredNode, building up a stack
+ // of ancestor nodes. Then crawl down the folderTreeArray looking
+ // for each ancestor in order while building up the selectionPath.
+ std::stack<const BookmarkNode*> nodeStack;
+ BookmarkModel* model = profile_->GetBookmarkModel();
+ const BookmarkNode* rootNode = model->root_node();
+ const BookmarkNode* node = desiredNode;
+ while (node != rootNode) {
+ DCHECK(node);
+ nodeStack.push(node);
+ node = node->GetParent();
+ }
+ NSUInteger stackSize = nodeStack.size();
+
+ NSIndexPath* path = nil;
+ NSArray* folders = [self folderTreeArray];
+ while (!nodeStack.empty()) {
+ node = nodeStack.top();
+ nodeStack.pop();
+ // Find node in the current folders array.
+ NSUInteger i = 0;
+ for (BookmarkFolderInfo *folderInfo in folders) {
+ const BookmarkNode* testNode = [folderInfo folderNode];
+ if (testNode == node) {
+ path = path ? [path indexPathByAddingIndex:i] :
+ [NSIndexPath indexPathWithIndex:i];
+ folders = [folderInfo children];
+ break;
+ }
+ ++i;
+ }
+ }
+ DCHECK([path length] == stackSize);
+ return path;
+}
+
+- (NSMutableArray*)addChildFoldersFromNode:(const BookmarkNode*)node {
+ NSMutableArray* childFolders = nil;
+ int childCount = node->GetChildCount();
+ for (int i = 0; i < childCount; ++i) {
+ const BookmarkNode* childNode = node->GetChild(i);
+ if (childNode->type() != BookmarkNode::URL) {
+ NSString* childName = base::SysUTF16ToNSString(childNode->GetTitle());
+ NSMutableArray* children = [self addChildFoldersFromNode:childNode];
+ BookmarkFolderInfo* folderInfo =
+ [BookmarkFolderInfo bookmarkFolderInfoWithFolderName:childName
+ folderNode:childNode
+ children:children];
+ if (!childFolders)
+ childFolders = [NSMutableArray arrayWithObject:folderInfo];
+ else
+ [childFolders addObject:folderInfo];
+ }
+ }
+ return childFolders;
+}
+
+- (void)buildFolderTree {
+ // Build up a tree of the current folder configuration.
+ BookmarkModel* model = profile_->GetBookmarkModel();
+ const BookmarkNode* rootNode = model->root_node();
+ NSMutableArray* baseArray = [self addChildFoldersFromNode:rootNode];
+ DCHECK(baseArray);
+ [self willChangeValueForKey:@"folderTreeArray"];
+ folderTreeArray_.reset([baseArray retain]);
+ [self didChangeValueForKey:@"folderTreeArray"];
+}
+
+- (void)modelChangedPreserveSelection:(BOOL)preserve {
+ const BookmarkNode* selectedNode = [self selectedNode];
+ [self buildFolderTree];
+ if (preserve &&
+ selectedNode &&
+ configuration_ == BookmarkEditor::SHOW_TREE)
+ [self selectNodeInBrowser:selectedNode];
+}
+
+- (void)nodeRemoved:(const BookmarkNode*)node
+ fromParent:(const BookmarkNode*)parent {
+ if (node->is_folder()) {
+ if (parentNode_ == node || parentNode_->HasAncestor(node)) {
+ parentNode_ = [self bookmarkModel]->GetBookmarkBarNode();
+ if (configuration_ != BookmarkEditor::SHOW_TREE) {
+ // The user can't select a different folder, so just close up shop.
+ [self cancel:self];
+ return;
+ }
+ }
+
+ if (configuration_ == BookmarkEditor::SHOW_TREE) {
+ // For safety's sake, in case deleted node was an ancestor of selection,
+ // go back to a known safe place.
+ [self selectNodeInBrowser:parentNode_];
+ }
+ }
+}
+
+#pragma mark New Folder Handler
+
+- (void)createNewFoldersForFolder:(BookmarkFolderInfo*)folderInfo
+ selectedFolderInfo:(BookmarkFolderInfo*)selectedFolderInfo {
+ NSArray* subfolders = [folderInfo children];
+ const BookmarkNode* parentNode = [folderInfo folderNode];
+ DCHECK(parentNode);
+ NSUInteger i = 0;
+ for (BookmarkFolderInfo* subFolderInfo in subfolders) {
+ if ([subFolderInfo newFolder]) {
+ BookmarkModel* model = [self bookmarkModel];
+ const BookmarkNode* newFolder =
+ model->AddGroup(parentNode, i,
+ base::SysNSStringToUTF16([subFolderInfo folderName]));
+ // Update our dictionary with the actual folder node just created.
+ [subFolderInfo setFolderNode:newFolder];
+ [subFolderInfo setNewFolder:NO];
+ // If the newly created folder was selected, update the selection path.
+ if (subFolderInfo == selectedFolderInfo) {
+ NSIndexPath* selectionPath = [self selectionPathForNode:newFolder];
+ [self setTableSelectionPath:selectionPath];
+ }
+ }
+ [self createNewFoldersForFolder:subFolderInfo
+ selectedFolderInfo:selectedFolderInfo];
+ ++i;
+ }
+}
+
+- (IBAction)newFolder:(id)sender {
+ // Create a new folder off of the selected folder node.
+ BookmarkFolderInfo* parentInfo = [self selectedFolder];
+ if (parentInfo) {
+ NSIndexPath* selection = [self selectedIndexPath];
+ NSString* newFolderName =
+ l10n_util::GetNSStringWithFixup(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME);
+ BookmarkFolderInfo* folderInfo =
+ [BookmarkFolderInfo bookmarkFolderInfoWithFolderName:newFolderName];
+ [self willChangeValueForKey:@"folderTreeArray"];
+ NSMutableArray* children = [parentInfo children];
+ if (children) {
+ [children addObject:folderInfo];
+ } else {
+ children = [NSMutableArray arrayWithObject:folderInfo];
+ [parentInfo setChildren:children];
+ }
+ [self didChangeValueForKey:@"folderTreeArray"];
+
+ // Expose the parent folder children.
+ [folderTreeView_ expandItem:parentInfo];
+
+ // Select the new folder node and put the folder name into edit mode.
+ selection = [selection indexPathByAddingIndex:[children count] - 1];
+ [self setTableSelectionPath:selection];
+ NSInteger row = [folderTreeView_ selectedRow];
+ DCHECK(row >= 0);
+ [folderTreeView_ editColumn:0 row:row withEvent:nil select:YES];
+ }
+}
+
+- (void)createNewFolders {
+ // Turn off notifications while "importing" folders (as created in the sheet).
+ observer_->BookmarkImportBeginning([self bookmarkModel]);
+ // Scan the tree looking for nodes marked 'newFolder' and create those nodes.
+ NSArray* folderTreeArray = [self folderTreeArray];
+ for (BookmarkFolderInfo *folderInfo in folderTreeArray) {
+ [self createNewFoldersForFolder:folderInfo
+ selectedFolderInfo:[self selectedFolder]];
+ }
+ // Notifications back on.
+ observer_->BookmarkImportEnding([self bookmarkModel]);
+}
+
+#pragma mark For Unit Test Use Only
+
+- (BOOL)okButtonEnabled {
+ return [okButton_ isEnabled];
+}
+
+- (void)selectTestNodeInBrowser:(const BookmarkNode*)node {
+ [self selectNodeInBrowser:node];
+}
+
+@end // BookmarkEditorBaseController
+
+@implementation BookmarkFolderInfo
+
+@synthesize folderName = folderName_;
+@synthesize folderNode = folderNode_;
+@synthesize children = children_;
+@synthesize newFolder = newFolder_;
+
++ (id)bookmarkFolderInfoWithFolderName:(NSString*)folderName
+ folderNode:(const BookmarkNode*)folderNode
+ children:(NSMutableArray*)children {
+ return [[[BookmarkFolderInfo alloc] initWithFolderName:folderName
+ folderNode:folderNode
+ children:children
+ newFolder:NO]
+ autorelease];
+}
+
++ (id)bookmarkFolderInfoWithFolderName:(NSString*)folderName {
+ return [[[BookmarkFolderInfo alloc] initWithFolderName:folderName
+ folderNode:NULL
+ children:nil
+ newFolder:YES]
+ autorelease];
+}
+
+- (id)initWithFolderName:(NSString*)folderName
+ folderNode:(const BookmarkNode*)folderNode
+ children:(NSMutableArray*)children
+ newFolder:(BOOL)newFolder {
+ if ((self = [super init])) {
+ // A folderName is always required, and if newFolder is NO then there
+ // should be a folderNode. Children is optional.
+ DCHECK(folderName && (newFolder || folderNode));
+ if (folderName && (newFolder || folderNode)) {
+ folderName_ = [folderName copy];
+ folderNode_ = folderNode;
+ children_ = [children retain];
+ newFolder_ = newFolder;
+ } else {
+ NOTREACHED(); // Invalid init.
+ [self release];
+ self = nil;
+ }
+ }
+ return self;
+}
+
+- (id)init {
+ NOTREACHED(); // Should never be called.
+ return [self initWithFolderName:nil folderNode:nil children:nil newFolder:NO];
+}
+
+- (void)dealloc {
+ [folderName_ release];
+ [children_ release];
+ [super dealloc];
+}
+
+// Implementing isEqual: allows the NSTreeController to preserve the selection
+// and open/shut state of outline items when the data changes.
+- (BOOL)isEqual:(id)other {
+ return [other isKindOfClass:[BookmarkFolderInfo class]] &&
+ folderNode_ == [(BookmarkFolderInfo*)other folderNode];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller_unittest.mm
new file mode 100644
index 0000000..6325346
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller_unittest.mm
@@ -0,0 +1,235 @@
+// 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 "app/l10n_util_mac.h"
+#include "base/scoped_nsobject.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "grit/generated_resources.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+class BookmarkEditorBaseControllerTest : public CocoaTest {
+ public:
+ BrowserTestHelper browser_helper_;
+ BookmarkEditorBaseController* controller_; // weak
+ const BookmarkNode* group_a_;
+ const BookmarkNode* group_b_;
+ const BookmarkNode* group_b_0_;
+ const BookmarkNode* group_b_3_;
+ const BookmarkNode* group_c_;
+
+ BookmarkEditorBaseControllerTest() {
+ // Set up a small bookmark hierarchy, which will look as follows:
+ // a b c d
+ // a-0 b-0 c-0
+ // a-1 b-00 c-1
+ // a-2 b-1 c-2
+ // b-2 c-3
+ // b-3
+ // b-30
+ // b-31
+ // b-4
+ BookmarkModel& model(*(browser_helper_.profile()->GetBookmarkModel()));
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ group_a_ = model.AddGroup(root, 0, ASCIIToUTF16("a"));
+ model.AddURL(group_a_, 0, ASCIIToUTF16("a-0"), GURL("http://a-0.com"));
+ model.AddURL(group_a_, 1, ASCIIToUTF16("a-1"), GURL("http://a-1.com"));
+ model.AddURL(group_a_, 2, ASCIIToUTF16("a-2"), GURL("http://a-2.com"));
+
+ group_b_ = model.AddGroup(root, 1, ASCIIToUTF16("b"));
+ group_b_0_ = model.AddGroup(group_b_, 0, ASCIIToUTF16("b-0"));
+ model.AddURL(group_b_0_, 0, ASCIIToUTF16("bb-0"), GURL("http://bb-0.com"));
+ model.AddURL(group_b_, 1, ASCIIToUTF16("b-1"), GURL("http://b-1.com"));
+ model.AddURL(group_b_, 2, ASCIIToUTF16("b-2"), GURL("http://b-2.com"));
+ group_b_3_ = model.AddGroup(group_b_, 3, ASCIIToUTF16("b-3"));
+ model.AddURL(group_b_3_, 0, ASCIIToUTF16("b-30"), GURL("http://b-30.com"));
+ model.AddURL(group_b_3_, 1, ASCIIToUTF16("b-31"), GURL("http://b-31.com"));
+ model.AddURL(group_b_, 4, ASCIIToUTF16("b-4"), GURL("http://b-4.com"));
+
+ group_c_ = model.AddGroup(root, 2, ASCIIToUTF16("c"));
+ model.AddURL(group_c_, 0, ASCIIToUTF16("c-0"), GURL("http://c-0.com"));
+ model.AddURL(group_c_, 1, ASCIIToUTF16("c-1"), GURL("http://c-1.com"));
+ model.AddURL(group_c_, 2, ASCIIToUTF16("c-2"), GURL("http://c-2.com"));
+ model.AddURL(group_c_, 3, ASCIIToUTF16("c-3"), GURL("http://c-3.com"));
+
+ model.AddURL(root, 3, ASCIIToUTF16("d"), GURL("http://d-0.com"));
+ }
+
+ virtual BookmarkEditorBaseController* CreateController() {
+ return [[BookmarkEditorBaseController alloc]
+ initWithParentWindow:test_window()
+ nibName:@"BookmarkAllTabs"
+ profile:browser_helper_.profile()
+ parent:group_b_0_
+ configuration:BookmarkEditor::SHOW_TREE];
+ }
+
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ controller_ = CreateController();
+ EXPECT_TRUE([controller_ window]);
+ [controller_ runAsModalSheet];
+ }
+
+ virtual void TearDown() {
+ controller_ = NULL;
+ CocoaTest::TearDown();
+ }
+};
+
+TEST_F(BookmarkEditorBaseControllerTest, VerifyBookmarkTestModel) {
+ BookmarkModel& model(*(browser_helper_.profile()->GetBookmarkModel()));
+ const BookmarkNode& root(*model.GetBookmarkBarNode());
+ EXPECT_EQ(4, root.GetChildCount());
+ // a
+ const BookmarkNode* child = root.GetChild(0);
+ EXPECT_EQ(3, child->GetChildCount());
+ const BookmarkNode* subchild = child->GetChild(0);
+ EXPECT_EQ(0, subchild->GetChildCount());
+ subchild = child->GetChild(1);
+ EXPECT_EQ(0, subchild->GetChildCount());
+ subchild = child->GetChild(2);
+ EXPECT_EQ(0, subchild->GetChildCount());
+ // b
+ child = root.GetChild(1);
+ EXPECT_EQ(5, child->GetChildCount());
+ subchild = child->GetChild(0);
+ EXPECT_EQ(1, subchild->GetChildCount());
+ const BookmarkNode* subsubchild = subchild->GetChild(0);
+ EXPECT_EQ(0, subsubchild->GetChildCount());
+ subchild = child->GetChild(1);
+ EXPECT_EQ(0, subchild->GetChildCount());
+ subchild = child->GetChild(2);
+ EXPECT_EQ(0, subchild->GetChildCount());
+ subchild = child->GetChild(3);
+ EXPECT_EQ(2, subchild->GetChildCount());
+ subsubchild = subchild->GetChild(0);
+ EXPECT_EQ(0, subsubchild->GetChildCount());
+ subsubchild = subchild->GetChild(1);
+ EXPECT_EQ(0, subsubchild->GetChildCount());
+ subchild = child->GetChild(4);
+ EXPECT_EQ(0, subchild->GetChildCount());
+ // c
+ child = root.GetChild(2);
+ EXPECT_EQ(4, child->GetChildCount());
+ subchild = child->GetChild(0);
+ EXPECT_EQ(0, subchild->GetChildCount());
+ subchild = child->GetChild(1);
+ EXPECT_EQ(0, subchild->GetChildCount());
+ subchild = child->GetChild(2);
+ EXPECT_EQ(0, subchild->GetChildCount());
+ subchild = child->GetChild(3);
+ EXPECT_EQ(0, subchild->GetChildCount());
+ // d
+ child = root.GetChild(3);
+ EXPECT_EQ(0, child->GetChildCount());
+ [controller_ cancel:nil];
+}
+
+TEST_F(BookmarkEditorBaseControllerTest, NodeSelection) {
+ EXPECT_TRUE([controller_ folderTreeArray]);
+ [controller_ selectTestNodeInBrowser:group_b_3_];
+ const BookmarkNode* node = [controller_ selectedNode];
+ EXPECT_EQ(node, group_b_3_);
+ [controller_ cancel:nil];
+}
+
+TEST_F(BookmarkEditorBaseControllerTest, CreateFolder) {
+ EXPECT_EQ(2, group_b_3_->GetChildCount());
+ [controller_ selectTestNodeInBrowser:group_b_3_];
+ NSString* expectedName =
+ l10n_util::GetNSStringWithFixup(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME);
+ [controller_ setDisplayName:expectedName];
+ [controller_ newFolder:nil];
+ NSArray* selectionPaths = [controller_ tableSelectionPaths];
+ EXPECT_EQ(1U, [selectionPaths count]);
+ NSIndexPath* selectionPath = [selectionPaths objectAtIndex:0];
+ EXPECT_EQ(4U, [selectionPath length]);
+ BookmarkFolderInfo* newFolderInfo = [controller_ selectedFolder];
+ EXPECT_TRUE(newFolderInfo);
+ NSString* newFolderName = [newFolderInfo folderName];
+ EXPECT_NSEQ(expectedName, newFolderName);
+ [controller_ createNewFolders];
+ // Verify that the tab folder was added to the new folder.
+ EXPECT_EQ(3, group_b_3_->GetChildCount());
+ [controller_ cancel:nil];
+}
+
+TEST_F(BookmarkEditorBaseControllerTest, CreateTwoFolders) {
+ BookmarkModel* model = browser_helper_.profile()->GetBookmarkModel();
+ const BookmarkNode* bar = model->GetBookmarkBarNode();
+ // Create 2 folders which are children of the bar.
+ [controller_ selectTestNodeInBrowser:bar];
+ [controller_ newFolder:nil];
+ [controller_ selectTestNodeInBrowser:bar];
+ [controller_ newFolder:nil];
+ // If we do NOT crash on createNewFolders, success!
+ // (e.g. http://crbug.com/47877 is fixed).
+ [controller_ createNewFolders];
+ [controller_ cancel:nil];
+}
+
+TEST_F(BookmarkEditorBaseControllerTest, SelectedFolderDeleted) {
+ BookmarkModel& model(*(browser_helper_.profile()->GetBookmarkModel()));
+ [controller_ selectTestNodeInBrowser:group_b_3_];
+ EXPECT_EQ(group_b_3_, [controller_ selectedNode]);
+
+ // Delete the selected node, and verify it's no longer selected:
+ model.Remove(group_b_, 3);
+ EXPECT_NE(group_b_3_, [controller_ selectedNode]);
+
+ [controller_ cancel:nil];
+}
+
+TEST_F(BookmarkEditorBaseControllerTest, SelectedFoldersParentDeleted) {
+ BookmarkModel& model(*(browser_helper_.profile()->GetBookmarkModel()));
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ [controller_ selectTestNodeInBrowser:group_b_3_];
+ EXPECT_EQ(group_b_3_, [controller_ selectedNode]);
+
+ // Delete the selected node's parent, and verify it's no longer selected:
+ model.Remove(root, 1);
+ EXPECT_NE(group_b_3_, [controller_ selectedNode]);
+
+ [controller_ cancel:nil];
+}
+
+TEST_F(BookmarkEditorBaseControllerTest, FolderAdded) {
+ BookmarkModel& model(*(browser_helper_.profile()->GetBookmarkModel()));
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+
+ // Add a group node to the model, and verify it can be selected in the tree:
+ const BookmarkNode* group_added = model.AddGroup(root, 0,
+ ASCIIToUTF16("added"));
+ [controller_ selectTestNodeInBrowser:group_added];
+ EXPECT_EQ(group_added, [controller_ selectedNode]);
+
+ [controller_ cancel:nil];
+}
+
+
+class BookmarkFolderInfoTest : public CocoaTest { };
+
+TEST_F(BookmarkFolderInfoTest, Construction) {
+ NSMutableArray* children = [NSMutableArray arrayWithObject:@"child"];
+ // We just need a pointer, and any pointer will do.
+ const BookmarkNode* fakeNode =
+ reinterpret_cast<const BookmarkNode*>(&children);
+ BookmarkFolderInfo* info =
+ [BookmarkFolderInfo bookmarkFolderInfoWithFolderName:@"name"
+ folderNode:fakeNode
+ children:children];
+ EXPECT_TRUE(info);
+ EXPECT_EQ([info folderName], @"name");
+ EXPECT_EQ([info children], children);
+ EXPECT_EQ([info folderNode], fakeNode);
+}
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller.h
new file mode 100644
index 0000000..30f1c75
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller.h
@@ -0,0 +1,36 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_EDITOR_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_EDITOR_CONTROLLER_H_
+#pragma once
+
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller.h"
+
+// A controller for the bookmark editor, opened by 1) Edit... from the
+// context menu of a bookmark button, and 2) Bookmark this Page...'s Edit
+// button.
+@interface BookmarkEditorController : BookmarkEditorBaseController {
+ @private
+ const BookmarkNode* node_; // weak; owned by the model
+ scoped_nsobject<NSString> initialUrl_;
+ NSString* displayURL_; // Bound to a text field in the dialog.
+ IBOutlet NSTextField* urlField_;
+}
+
+@property (nonatomic, copy) NSString* displayURL;
+
+- (id)initWithParentWindow:(NSWindow*)parentWindow
+ profile:(Profile*)profile
+ parent:(const BookmarkNode*)parent
+ node:(const BookmarkNode*)node
+ configuration:(BookmarkEditor::Configuration)configuration;
+
+@end
+
+@interface BookmarkEditorController (UnitTesting)
+- (NSColor *)urlFieldColor;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_EDITOR_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller.mm
new file mode 100644
index 0000000..88ed4bf
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller.mm
@@ -0,0 +1,143 @@
+// 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 "chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller.h"
+
+#include "app/l10n_util.h"
+#include "base/string16.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+
+@interface BookmarkEditorController (Private)
+
+// Grab the url from the text field and convert.
+- (GURL)GURLFromUrlField;
+
+@end
+
+@implementation BookmarkEditorController
+
+@synthesize displayURL = displayURL_;
+
++ (NSSet*)keyPathsForValuesAffectingOkEnabled {
+ return [NSSet setWithObject:@"displayURL"];
+}
+
+- (id)initWithParentWindow:(NSWindow*)parentWindow
+ profile:(Profile*)profile
+ parent:(const BookmarkNode*)parent
+ node:(const BookmarkNode*)node
+ configuration:(BookmarkEditor::Configuration)configuration {
+ if ((self = [super initWithParentWindow:parentWindow
+ nibName:@"BookmarkEditor"
+ profile:profile
+ parent:parent
+ configuration:configuration])) {
+ // "Add Page..." has no "node" so this may be NULL.
+ node_ = node;
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [displayURL_ release];
+ [super dealloc];
+}
+
+- (void)awakeFromNib {
+ // Set text fields to match our bookmark. If the node is NULL we
+ // arrived here from an "Add Page..." item in a context menu.
+ if (node_) {
+ [self setInitialName:base::SysUTF16ToNSString(node_->GetTitle())];
+ std::string url_string = node_->GetURL().possibly_invalid_spec();
+ initialUrl_.reset([[NSString stringWithUTF8String:url_string.c_str()]
+ retain]);
+ } else {
+ initialUrl_.reset([@"" retain]);
+ }
+ [self setDisplayURL:initialUrl_];
+ [super awakeFromNib];
+}
+
+- (void)nodeRemoved:(const BookmarkNode*)node
+ fromParent:(const BookmarkNode*)parent
+{
+ // Be conservative; it is needed (e.g. "Add Page...")
+ node_ = NULL;
+ [self cancel:self];
+}
+
+#pragma mark Bookmark Editing
+
+// If possible, return a valid GURL from the URL text field.
+- (GURL)GURLFromUrlField {
+ NSString* url = [self displayURL];
+ GURL newURL = GURL([url UTF8String]);
+ if (!newURL.is_valid()) {
+ // Mimic observed friendliness from Windows
+ newURL = GURL([[NSString stringWithFormat:@"http://%@", url] UTF8String]);
+ }
+ return newURL;
+}
+
+// Enable the OK button if there is a valid URL.
+- (BOOL)okEnabled {
+ BOOL okEnabled = NO;
+ if ([[self displayURL] length]) {
+ GURL newURL = [self GURLFromUrlField];
+ okEnabled = (newURL.is_valid()) ? YES : NO;
+ }
+ if (okEnabled)
+ [urlField_ setBackgroundColor:[NSColor whiteColor]];
+ else
+ [urlField_ setBackgroundColor:[NSColor colorWithCalibratedRed:1.0
+ green:0.67
+ blue:0.67
+ alpha:1.0]];
+ return okEnabled;
+}
+
+// The the bookmark's URL is assumed to be valid (otherwise the OK button
+// should not be enabled). Previously existing bookmarks for which the
+// parent has not changed are updated in-place. Those for which the parent
+// has changed are removed with a new node created under the new parent.
+// Called by -[BookmarkEditorBaseController ok:].
+- (NSNumber*)didCommit {
+ NSString* name = [[self displayName] stringByTrimmingCharactersInSet:
+ [NSCharacterSet newlineCharacterSet]];
+ string16 newTitle = base::SysNSStringToUTF16(name);
+ const BookmarkNode* newParentNode = [self selectedNode];
+ GURL newURL = [self GURLFromUrlField];
+ if (!newURL.is_valid()) {
+ // Shouldn't be reached -- OK button should be disabled if not valid!
+ NOTREACHED();
+ return [NSNumber numberWithBool:NO];
+ }
+
+ // Determine where the new/replacement bookmark is to go.
+ BookmarkModel* model = [self bookmarkModel];
+ // If there was an old node then we update the node, and move it to its new
+ // parent if the parent has changed (rather than deleting it from the old
+ // parent and adding to the new -- which also prevents the 'poofing' that
+ // occurs when a node is deleted).
+ if (node_) {
+ model->SetURL(node_, newURL);
+ model->SetTitle(node_, newTitle);
+ const BookmarkNode* oldParentNode = [self parentNode];
+ if (newParentNode != oldParentNode)
+ model->Move(node_, newParentNode, newParentNode->GetChildCount());
+ } else {
+ // Otherwise, add a new bookmark at the end of the newly selected folder.
+ model->AddURL(newParentNode, newParentNode->GetChildCount(), newTitle,
+ newURL);
+ }
+ return [NSNumber numberWithBool:YES];
+}
+
+- (NSColor *)urlFieldColor {
+ return [urlField_ backgroundColor];
+}
+
+@end // BookmarkEditorController
+
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller_unittest.mm
new file mode 100644
index 0000000..8f49c6d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller_unittest.mm
@@ -0,0 +1,423 @@
+// 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 "base/string16.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+class BookmarkEditorControllerTest : public CocoaTest {
+ public:
+ BrowserTestHelper browser_helper_;
+ const BookmarkNode* default_node_;
+ const BookmarkNode* default_parent_;
+ const char* default_name_;
+ string16 default_title_;
+ BookmarkEditorController* controller_;
+
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ BookmarkModel* model = browser_helper_.profile()->GetBookmarkModel();
+ default_parent_ = model->GetBookmarkBarNode();
+ default_name_ = "http://www.zim-bop-a-dee.com/";
+ default_title_ = ASCIIToUTF16("ooh title");
+ const BookmarkNode* default_node = model->AddURL(default_parent_, 0,
+ default_title_,
+ GURL(default_name_));
+ controller_ = [[BookmarkEditorController alloc]
+ initWithParentWindow:test_window()
+ profile:browser_helper_.profile()
+ parent:default_parent_
+ node:default_node
+ configuration:BookmarkEditor::NO_TREE];
+ [controller_ runAsModalSheet];
+ }
+
+ virtual void TearDown() {
+ controller_ = NULL;
+ CocoaTest::TearDown();
+ }
+};
+
+TEST_F(BookmarkEditorControllerTest, NoEdit) {
+ [controller_ cancel:nil];
+ ASSERT_EQ(default_parent_->GetChildCount(), 1);
+ const BookmarkNode* child = default_parent_->GetChild(0);
+ EXPECT_EQ(child->GetTitle(), default_title_);
+ EXPECT_EQ(child->GetURL(), GURL(default_name_));
+}
+
+TEST_F(BookmarkEditorControllerTest, EditTitle) {
+ [controller_ setDisplayName:@"whamma jamma bamma"];
+ [controller_ ok:nil];
+ ASSERT_EQ(default_parent_->GetChildCount(), 1);
+ const BookmarkNode* child = default_parent_->GetChild(0);
+ EXPECT_EQ(child->GetTitle(), ASCIIToUTF16("whamma jamma bamma"));
+ EXPECT_EQ(child->GetURL(), GURL(default_name_));
+}
+
+TEST_F(BookmarkEditorControllerTest, EditURL) {
+ EXPECT_TRUE([controller_ okButtonEnabled]);
+ [controller_ setDisplayURL:@"http://yellow-sneakers.com/"];
+ EXPECT_TRUE([controller_ okButtonEnabled]);
+ [controller_ ok:nil];
+ ASSERT_EQ(default_parent_->GetChildCount(), 1);
+ const BookmarkNode* child = default_parent_->GetChild(0);
+ EXPECT_EQ(child->GetTitle(), default_title_);
+ EXPECT_EQ(child->GetURL(), GURL("http://yellow-sneakers.com/"));
+}
+
+TEST_F(BookmarkEditorControllerTest, EditAndFixPrefix) {
+ [controller_ setDisplayURL:@"x"];
+ [controller_ ok:nil];
+ ASSERT_EQ(default_parent_->GetChildCount(), 1);
+ const BookmarkNode* child = default_parent_->GetChild(0);
+ EXPECT_TRUE(child->GetURL().is_valid());
+}
+
+TEST_F(BookmarkEditorControllerTest, NodeDeleted) {
+ // Delete the bookmark being edited and verify the sheet cancels itself:
+ ASSERT_TRUE([test_window() attachedSheet]);
+ BookmarkModel* model = browser_helper_.profile()->GetBookmarkModel();
+ model->Remove(default_parent_, 0);
+ ASSERT_FALSE([test_window() attachedSheet]);
+}
+
+TEST_F(BookmarkEditorControllerTest, EditAndConfirmOKButton) {
+ // Confirm OK button enabled/disabled as appropriate:
+ // First test the URL.
+ EXPECT_TRUE([controller_ okButtonEnabled]);
+ [controller_ setDisplayURL:@""];
+ EXPECT_FALSE([controller_ okButtonEnabled]);
+ [controller_ setDisplayURL:@"http://www.cnn.com"];
+ EXPECT_TRUE([controller_ okButtonEnabled]);
+ // Then test the name.
+ [controller_ setDisplayName:@""];
+ EXPECT_TRUE([controller_ okButtonEnabled]);
+ [controller_ setDisplayName:@" "];
+ EXPECT_TRUE([controller_ okButtonEnabled]);
+ // Then little mix of both.
+ [controller_ setDisplayName:@"name"];
+ EXPECT_TRUE([controller_ okButtonEnabled]);
+ [controller_ setDisplayURL:@""];
+ EXPECT_FALSE([controller_ okButtonEnabled]);
+ [controller_ cancel:nil];
+}
+
+TEST_F(BookmarkEditorControllerTest, GoodAndBadURLsChangeColor) {
+ // Confirm that the background color of the URL edit field changes
+ // based on whether it contains a valid or invalid URL.
+ [controller_ setDisplayURL:@"http://www.cnn.com"];
+ NSColor *urlColorA = [controller_ urlFieldColor];
+ EXPECT_TRUE(urlColorA);
+ [controller_ setDisplayURL:@""];
+ NSColor *urlColorB = [controller_ urlFieldColor];
+ EXPECT_TRUE(urlColorB);
+ EXPECT_NSNE(urlColorA, urlColorB);
+ [controller_ setDisplayURL:@"http://www.google.com"];
+ [controller_ cancel:nil];
+ urlColorB = [controller_ urlFieldColor];
+ EXPECT_TRUE(urlColorB);
+ EXPECT_NSEQ(urlColorA, urlColorB);
+}
+
+class BookmarkEditorControllerNoNodeTest : public CocoaTest {
+ public:
+ BrowserTestHelper browser_helper_;
+ BookmarkEditorController* controller_;
+
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ BookmarkModel* model = browser_helper_.profile()->GetBookmarkModel();
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ controller_ = [[BookmarkEditorController alloc]
+ initWithParentWindow:test_window()
+ profile:browser_helper_.profile()
+ parent:parent
+ node:NULL
+ configuration:BookmarkEditor::NO_TREE];
+
+ [controller_ runAsModalSheet];
+ }
+
+ virtual void TearDown() {
+ controller_ = NULL;
+ CocoaTest::TearDown();
+ }
+};
+
+TEST_F(BookmarkEditorControllerNoNodeTest, NoNodeNoTree) {
+ EXPECT_EQ(@"", [controller_ displayName]);
+ EXPECT_EQ(@"", [controller_ displayURL]);
+ EXPECT_FALSE([controller_ okButtonEnabled]);
+ [controller_ cancel:nil];
+}
+
+class BookmarkEditorControllerYesNodeTest : public CocoaTest {
+ public:
+ BrowserTestHelper browser_helper_;
+ string16 default_title_;
+ const char* url_name_;
+ BookmarkEditorController* controller_;
+
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ BookmarkModel* model = browser_helper_.profile()->GetBookmarkModel();
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ default_title_ = ASCIIToUTF16("wooh title");
+ url_name_ = "http://www.zoom-baby-doo-da.com/";
+ const BookmarkNode* node = model->AddURL(parent, 0, default_title_,
+ GURL(url_name_));
+ controller_ = [[BookmarkEditorController alloc]
+ initWithParentWindow:test_window()
+ profile:browser_helper_.profile()
+ parent:parent
+ node:node
+ configuration:BookmarkEditor::NO_TREE];
+
+ [controller_ runAsModalSheet];
+ }
+
+ virtual void TearDown() {
+ controller_ = NULL;
+ CocoaTest::TearDown();
+ }
+};
+
+TEST_F(BookmarkEditorControllerYesNodeTest, YesNodeShowTree) {
+ EXPECT_NSEQ(base::SysUTF16ToNSString(default_title_),
+ [controller_ displayName]);
+ EXPECT_NSEQ([NSString stringWithCString:url_name_
+ encoding:NSUTF8StringEncoding],
+ [controller_ displayURL]);
+ [controller_ cancel:nil];
+}
+
+class BookmarkEditorControllerTreeTest : public CocoaTest {
+
+ public:
+ BrowserTestHelper browser_helper_;
+ BookmarkEditorController* controller_;
+ const BookmarkNode* group_a_;
+ const BookmarkNode* group_b_;
+ const BookmarkNode* group_bb_;
+ const BookmarkNode* group_c_;
+ const BookmarkNode* bookmark_bb_3_;
+ GURL bb3_url_1_;
+ GURL bb3_url_2_;
+
+ BookmarkEditorControllerTreeTest() {
+ // Set up a small bookmark hierarchy, which will look as follows:
+ // a b c d
+ // a-0 b-0 c-0
+ // a-1 bb-0 c-1
+ // a-2 bb-1 c-2
+ // bb-2
+ // bb-3
+ // bb-4
+ // b-1
+ // b-2
+ BookmarkModel& model(*(browser_helper_.profile()->GetBookmarkModel()));
+ const BookmarkNode* root = model.GetBookmarkBarNode();
+ group_a_ = model.AddGroup(root, 0, ASCIIToUTF16("a"));
+ model.AddURL(group_a_, 0, ASCIIToUTF16("a-0"), GURL("http://a-0.com"));
+ model.AddURL(group_a_, 1, ASCIIToUTF16("a-1"), GURL("http://a-1.com"));
+ model.AddURL(group_a_, 2, ASCIIToUTF16("a-2"), GURL("http://a-2.com"));
+
+ group_b_ = model.AddGroup(root, 1, ASCIIToUTF16("b"));
+ model.AddURL(group_b_, 0, ASCIIToUTF16("b-0"), GURL("http://b-0.com"));
+ group_bb_ = model.AddGroup(group_b_, 1, ASCIIToUTF16("bb"));
+ model.AddURL(group_bb_, 0, ASCIIToUTF16("bb-0"), GURL("http://bb-0.com"));
+ model.AddURL(group_bb_, 1, ASCIIToUTF16("bb-1"), GURL("http://bb-1.com"));
+ model.AddURL(group_bb_, 2, ASCIIToUTF16("bb-2"), GURL("http://bb-2.com"));
+
+ // To find it later, this bookmark name must always have a URL
+ // of http://bb-3.com or https://bb-3.com
+ bb3_url_1_ = GURL("http://bb-3.com");
+ bb3_url_2_ = GURL("https://bb-3.com");
+ bookmark_bb_3_ = model.AddURL(group_bb_, 3, ASCIIToUTF16("bb-3"),
+ bb3_url_1_);
+
+ model.AddURL(group_bb_, 4, ASCIIToUTF16("bb-4"), GURL("http://bb-4.com"));
+ model.AddURL(group_b_, 2, ASCIIToUTF16("b-1"), GURL("http://b-2.com"));
+ model.AddURL(group_b_, 3, ASCIIToUTF16("b-2"), GURL("http://b-3.com"));
+
+ group_c_ = model.AddGroup(root, 2, ASCIIToUTF16("c"));
+ model.AddURL(group_c_, 0, ASCIIToUTF16("c-0"), GURL("http://c-0.com"));
+ model.AddURL(group_c_, 1, ASCIIToUTF16("c-1"), GURL("http://c-1.com"));
+ model.AddURL(group_c_, 2, ASCIIToUTF16("c-2"), GURL("http://c-2.com"));
+ model.AddURL(group_c_, 3, ASCIIToUTF16("c-3"), GURL("http://c-3.com"));
+
+ model.AddURL(root, 3, ASCIIToUTF16("d"), GURL("http://d-0.com"));
+ }
+
+ virtual BookmarkEditorController* CreateController() {
+ return [[BookmarkEditorController alloc]
+ initWithParentWindow:test_window()
+ profile:browser_helper_.profile()
+ parent:group_bb_
+ node:bookmark_bb_3_
+ configuration:BookmarkEditor::SHOW_TREE];
+ }
+
+ virtual void SetUp() {
+ controller_ = CreateController();
+ [controller_ runAsModalSheet];
+ }
+
+ virtual void TearDown() {
+ controller_ = NULL;
+ CocoaTest::TearDown();
+ }
+
+ // After changing a node, pointers to the node may be invalid. This
+ // is because the node itself may not be updated; it may removed and
+ // a new one is added in that location. (Implementation detail of
+ // BookmarkEditorController). This method updates the class's
+ // bookmark_bb_3_ so that it points to the new node for testing.
+ void UpdateBB3() {
+ std::vector<const BookmarkNode*> nodes;
+ BookmarkModel* model = browser_helper_.profile()->GetBookmarkModel();
+ model->GetNodesByURL(bb3_url_1_, &nodes);
+ if (nodes.size() == 0)
+ model->GetNodesByURL(bb3_url_2_, &nodes);
+ DCHECK(nodes.size());
+ bookmark_bb_3_ = nodes[0];
+ }
+
+};
+
+TEST_F(BookmarkEditorControllerTreeTest, VerifyBookmarkTestModel) {
+ BookmarkModel& model(*(browser_helper_.profile()->GetBookmarkModel()));
+ model.root_node();
+ const BookmarkNode& root(*model.GetBookmarkBarNode());
+ EXPECT_EQ(4, root.GetChildCount());
+ const BookmarkNode* child = root.GetChild(0);
+ EXPECT_EQ(3, child->GetChildCount());
+ const BookmarkNode* subchild = child->GetChild(0);
+ EXPECT_EQ(0, subchild->GetChildCount());
+ subchild = child->GetChild(1);
+ EXPECT_EQ(0, subchild->GetChildCount());
+ subchild = child->GetChild(2);
+ EXPECT_EQ(0, subchild->GetChildCount());
+
+ child = root.GetChild(1);
+ EXPECT_EQ(4, child->GetChildCount());
+ subchild = child->GetChild(0);
+ EXPECT_EQ(0, subchild->GetChildCount());
+ subchild = child->GetChild(1);
+ EXPECT_EQ(5, subchild->GetChildCount());
+ const BookmarkNode* subsubchild = subchild->GetChild(0);
+ EXPECT_EQ(0, subsubchild->GetChildCount());
+ subsubchild = subchild->GetChild(1);
+ EXPECT_EQ(0, subsubchild->GetChildCount());
+ subsubchild = subchild->GetChild(2);
+ EXPECT_EQ(0, subsubchild->GetChildCount());
+ subsubchild = subchild->GetChild(3);
+ EXPECT_EQ(0, subsubchild->GetChildCount());
+ subsubchild = subchild->GetChild(4);
+ EXPECT_EQ(0, subsubchild->GetChildCount());
+ subchild = child->GetChild(2);
+ EXPECT_EQ(0, subchild->GetChildCount());
+ subchild = child->GetChild(3);
+ EXPECT_EQ(0, subchild->GetChildCount());
+
+ child = root.GetChild(2);
+ EXPECT_EQ(4, child->GetChildCount());
+ subchild = child->GetChild(0);
+ EXPECT_EQ(0, subchild->GetChildCount());
+ subchild = child->GetChild(1);
+ EXPECT_EQ(0, subchild->GetChildCount());
+ subchild = child->GetChild(2);
+ EXPECT_EQ(0, subchild->GetChildCount());
+ subchild = child->GetChild(3);
+ EXPECT_EQ(0, subchild->GetChildCount());
+
+ child = root.GetChild(3);
+ EXPECT_EQ(0, child->GetChildCount());
+ [controller_ cancel:nil];
+}
+
+TEST_F(BookmarkEditorControllerTreeTest, RenameBookmarkInPlace) {
+ const BookmarkNode* oldParent = bookmark_bb_3_->GetParent();
+ [controller_ setDisplayName:@"NEW NAME"];
+ [controller_ ok:nil];
+ UpdateBB3();
+ const BookmarkNode* newParent = bookmark_bb_3_->GetParent();
+ ASSERT_EQ(newParent, oldParent);
+ int childIndex = newParent->IndexOfChild(bookmark_bb_3_);
+ ASSERT_EQ(3, childIndex);
+}
+
+TEST_F(BookmarkEditorControllerTreeTest, ChangeBookmarkURLInPlace) {
+ const BookmarkNode* oldParent = bookmark_bb_3_->GetParent();
+ [controller_ setDisplayURL:@"https://bb-3.com"];
+ [controller_ ok:nil];
+ UpdateBB3();
+ const BookmarkNode* newParent = bookmark_bb_3_->GetParent();
+ ASSERT_EQ(newParent, oldParent);
+ int childIndex = newParent->IndexOfChild(bookmark_bb_3_);
+ ASSERT_EQ(3, childIndex);
+}
+
+TEST_F(BookmarkEditorControllerTreeTest, ChangeBookmarkGroup) {
+ [controller_ selectTestNodeInBrowser:group_c_];
+ [controller_ ok:nil];
+ UpdateBB3();
+ const BookmarkNode* parent = bookmark_bb_3_->GetParent();
+ ASSERT_EQ(parent, group_c_);
+ int childIndex = parent->IndexOfChild(bookmark_bb_3_);
+ ASSERT_EQ(4, childIndex);
+}
+
+TEST_F(BookmarkEditorControllerTreeTest, ChangeNameAndBookmarkGroup) {
+ [controller_ setDisplayName:@"NEW NAME"];
+ [controller_ selectTestNodeInBrowser:group_c_];
+ [controller_ ok:nil];
+ UpdateBB3();
+ const BookmarkNode* parent = bookmark_bb_3_->GetParent();
+ ASSERT_EQ(parent, group_c_);
+ int childIndex = parent->IndexOfChild(bookmark_bb_3_);
+ ASSERT_EQ(4, childIndex);
+ EXPECT_EQ(bookmark_bb_3_->GetTitle(), ASCIIToUTF16("NEW NAME"));
+}
+
+TEST_F(BookmarkEditorControllerTreeTest, AddFolderWithGroupSelected) {
+ // Folders are NOT added unless the OK button is pressed.
+ [controller_ newFolder:nil];
+ [controller_ cancel:nil];
+ EXPECT_EQ(5, group_bb_->GetChildCount());
+}
+
+class BookmarkEditorControllerTreeNoNodeTest :
+ public BookmarkEditorControllerTreeTest {
+ public:
+ virtual BookmarkEditorController* CreateController() {
+ return [[BookmarkEditorController alloc]
+ initWithParentWindow:test_window()
+ profile:browser_helper_.profile()
+ parent:group_bb_
+ node:nil
+ configuration:BookmarkEditor::SHOW_TREE];
+ }
+
+};
+
+TEST_F(BookmarkEditorControllerTreeNoNodeTest, NewBookmarkNoNode) {
+ [controller_ setDisplayName:@"NEW BOOKMARK"];
+ [controller_ setDisplayURL:@"http://NEWURL.com"];
+ [controller_ ok:nil];
+ const BookmarkNode* new_node = group_bb_->GetChild(5);
+ ASSERT_EQ(0, new_node->GetChildCount());
+ EXPECT_EQ(new_node->GetTitle(), ASCIIToUTF16("NEW BOOKMARK"));
+ EXPECT_EQ(new_node->GetURL(), GURL("http://NEWURL.com"));
+}
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h
new file mode 100644
index 0000000..e2af266
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h
@@ -0,0 +1,50 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_FOLDER_TARGET_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_FOLDER_TARGET_CONTROLLER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+@class BookmarkButton;
+@protocol BookmarkButtonControllerProtocol;
+class BookmarkNode;
+
+// Target (in the target/action sense) of a bookmark folder button.
+// Since ObjC doesn't have multiple inheritance we use has-a instead
+// of is-a to share behavior between the BookmarkBarFolderController
+// (NSWindowController) and the BookmarkBarController
+// (NSViewController).
+//
+// This class is unit tested in the context of a BookmarkBarController.
+@interface BookmarkFolderTarget : NSObject {
+ // The owner of the bookmark folder button
+ id<BookmarkButtonControllerProtocol> controller_; // weak
+}
+
+- (id)initWithController:(id<BookmarkButtonControllerProtocol>)controller;
+
+// Main IBAction for a button click.
+- (IBAction)openBookmarkFolderFromButton:(id)sender;
+
+// Copies the given bookmark node to the given pasteboard, declaring appropriate
+// types (to paste a URL with a title).
+- (void)copyBookmarkNode:(const BookmarkNode*)node
+ toPasteboard:(NSPasteboard*)pboard;
+
+// Fill the given pasteboard with appropriate data when the given button is
+// dragged. Since the delegate has no way of providing pasteboard data later,
+// all data must actually be put into the pasteboard and not merely promised.
+- (void)fillPasteboard:(NSPasteboard*)pboard
+ forDragOfButton:(BookmarkButton*)button;
+
+@end
+
+// The (internal) |NSPasteboard| type string for bookmark button drags, used for
+// dragging buttons around the bookmark bar. The data for this type is just a
+// pointer to the |BookmarkButton| being dragged.
+extern NSString* kBookmarkButtonDragType;
+
+#endif // CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_FOLDER_TARGET_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.mm
new file mode 100644
index 0000000..95531b2
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.mm
@@ -0,0 +1,118 @@
+// 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 "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h"
+
+#include "base/logging.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
+#import "chrome/browser/ui/cocoa/event_utils.h"
+#import "third_party/mozilla/NSPasteboard+Utils.h"
+
+NSString* kBookmarkButtonDragType = @"ChromiumBookmarkButtonDragType";
+
+@implementation BookmarkFolderTarget
+
+- (id)initWithController:(id<BookmarkButtonControllerProtocol>)controller {
+ if ((self = [super init])) {
+ controller_ = controller;
+ }
+ return self;
+}
+
+// This IBAction is called when the user clicks (mouseUp, really) on a
+// "folder" bookmark button. (In this context, "Click" does not
+// include right-click to open a context menu which follows a
+// different path). Scenarios when folder X is clicked:
+// *Predicate* *Action*
+// (nothing) Open Folder X
+// Folder X open Close folder X
+// Folder Y open Close Y, open X
+// Cmd-click Open All with proper disposition
+//
+// Note complication in which a click-drag engages drag and drop, not
+// a click-to-open. Thus the path to get here is a little twisted.
+- (IBAction)openBookmarkFolderFromButton:(id)sender {
+ DCHECK(sender);
+ // Watch out for a modifier click. For example, command-click
+ // should open all.
+ //
+ // NOTE: we cannot use [[sender cell] mouseDownFlags] because we
+ // thwart the normal mouse click mechanism to make buttons
+ // draggable. Thus we must use [NSApp currentEvent].
+ //
+ // Holding command while using the scroll wheel (or moving around
+ // over a bookmark folder) can confuse us. Unless we check the
+ // event type, we are not sure if this is an "open folder" due to a
+ // hover-open or "open folder" due to a click. It doesn't matter
+ // (both do the same thing) unless a modifier is held, since
+ // command-click should "open all" but command-move should not.
+ // WindowOpenDispositionFromNSEvent does not consider the event
+ // type; only the modifiers. Thus the need for an extra
+ // event-type-check here.
+ DCHECK([sender bookmarkNode]->is_folder());
+ NSEvent* event = [NSApp currentEvent];
+ WindowOpenDisposition disposition =
+ event_utils::WindowOpenDispositionFromNSEvent(event);
+ if (([event type] != NSMouseEntered) &&
+ ([event type] != NSMouseMoved) &&
+ ([event type] != NSScrollWheel) &&
+ (disposition == NEW_BACKGROUND_TAB)) {
+ [controller_ closeAllBookmarkFolders];
+ [controller_ openAll:[sender bookmarkNode] disposition:disposition];
+ return;
+ }
+
+ // If click on same folder, close it and be done.
+ // Else we clicked on a different folder so more work to do.
+ if ([[controller_ folderController] parentButton] == sender) {
+ [controller_ closeBookmarkFolder:controller_];
+ return;
+ }
+
+ [controller_ addNewFolderControllerWithParentButton:sender];
+}
+
+- (void)copyBookmarkNode:(const BookmarkNode*)node
+ toPasteboard:(NSPasteboard*)pboard {
+ if (!node) {
+ NOTREACHED();
+ return;
+ }
+
+ if (node->is_folder()) {
+ // TODO(viettrungluu): I'm not sure what we should do, so just declare the
+ // "additional" types we're given for now. Maybe we want to add a list of
+ // URLs? Would we then have to recurse if there were subfolders?
+ // In the meanwhile, we *must* set it to a known state. (If this survives to
+ // a 10.6-only release, it can be replaced with |-clearContents|.)
+ [pboard declareTypes:[NSArray array] owner:nil];
+ } else {
+ const std::string spec = node->GetURL().spec();
+ NSString* url = base::SysUTF8ToNSString(spec);
+ NSString* title = base::SysUTF16ToNSString(node->GetTitle());
+ [pboard declareURLPasteboardWithAdditionalTypes:[NSArray array]
+ owner:nil];
+ [pboard setDataForURL:url title:title];
+ }
+}
+
+- (void)fillPasteboard:(NSPasteboard*)pboard
+ forDragOfButton:(BookmarkButton*)button {
+ if (const BookmarkNode* node = [button bookmarkNode]) {
+ // Put the bookmark information into the pasteboard, and then write our own
+ // data for |kBookmarkButtonDragType|.
+ [self copyBookmarkNode:node toPasteboard:pboard];
+ [pboard addTypes:[NSArray arrayWithObject:kBookmarkButtonDragType]
+ owner:nil];
+ [pboard setData:[NSData dataWithBytes:&button length:sizeof(button)]
+ forType:kBookmarkButtonDragType];
+ } else {
+ NOTREACHED();
+ }
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target_unittest.mm
new file mode 100644
index 0000000..0142bfb
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target_unittest.mm
@@ -0,0 +1,125 @@
+// 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.
+
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_folder_target.h"
+#include "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+
+@interface OCMockObject(PreventRetainCycle)
+- (void)clearRecordersAndExpectations;
+@end
+
+@implementation OCMockObject(PreventRetainCycle)
+
+// We need a mechanism to clear the invocation handlers to break a
+// retain cycle (see below; search for "retain cycle").
+- (void)clearRecordersAndExpectations {
+ [recorders removeAllObjects];
+ [expectations removeAllObjects];
+}
+
+@end
+
+
+class BookmarkFolderTargetTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ bmbNode_ = model->GetBookmarkBarNode();
+ }
+ virtual void TearDown() {
+ pool_.Recycle();
+ CocoaTest::TearDown();
+ }
+
+ BrowserTestHelper helper_;
+ const BookmarkNode* bmbNode_;
+ base::mac::ScopedNSAutoreleasePool pool_;
+};
+
+TEST_F(BookmarkFolderTargetTest, StartWithNothing) {
+ // Need a fake "button" which has a bookmark node.
+ id sender = [OCMockObject mockForClass:[BookmarkButton class]];
+ [[[sender stub] andReturnValue:OCMOCK_VALUE(bmbNode_)] bookmarkNode];
+
+ // Fake controller
+ id controller = [OCMockObject mockForClass:[BookmarkBarFolderController
+ class]];
+ // No current folder
+ [[[controller stub] andReturn:nil] folderController];
+
+ // Make sure we get an addNew
+ [[controller expect] addNewFolderControllerWithParentButton:sender];
+
+ scoped_nsobject<BookmarkFolderTarget> target(
+ [[BookmarkFolderTarget alloc] initWithController:controller]);
+
+ [target openBookmarkFolderFromButton:sender];
+ [controller verify];
+}
+
+TEST_F(BookmarkFolderTargetTest, ReopenSameFolder) {
+ // Need a fake "button" which has a bookmark node.
+ id sender = [OCMockObject mockForClass:[BookmarkButton class]];
+ [[[sender stub] andReturnValue:OCMOCK_VALUE(bmbNode_)] bookmarkNode];
+
+ // Fake controller
+ id controller = [OCMockObject mockForClass:[BookmarkBarFolderController
+ class]];
+ // YES a current folder. Self-mock that as well, so "same" will be
+ // true. Note this creates a retain cycle in OCMockObject; we
+ // accomodate at the end of this function.
+ [[[controller stub] andReturn:controller] folderController];
+ [[[controller stub] andReturn:sender] parentButton];
+
+ // The folder is open, so a click should close just that folder (and
+ // any subfolders).
+ [[controller expect] closeBookmarkFolder:controller];
+
+ scoped_nsobject<BookmarkFolderTarget> target(
+ [[BookmarkFolderTarget alloc] initWithController:controller]);
+
+ [target openBookmarkFolderFromButton:sender];
+ [controller verify];
+
+ // Our use of OCMockObject means an object can return itself. This
+ // creates a retain cycle, since OCMock retains all objects used in
+ // mock creation. Clear out the invocation handlers of all
+ // OCMockRecorders we used to break the cycles.
+ [controller clearRecordersAndExpectations];
+}
+
+TEST_F(BookmarkFolderTargetTest, ReopenNotSame) {
+ // Need a fake "button" which has a bookmark node.
+ id sender = [OCMockObject mockForClass:[BookmarkButton class]];
+ [[[sender stub] andReturnValue:OCMOCK_VALUE(bmbNode_)] bookmarkNode];
+
+ // Fake controller
+ id controller = [OCMockObject mockForClass:[BookmarkBarFolderController
+ class]];
+ // YES a current folder but NOT same.
+ [[[controller stub] andReturn:controller] folderController];
+ [[[controller stub] andReturn:nil] parentButton];
+
+ // Insure the controller gets a chance to decide which folders to
+ // close and open.
+ [[controller expect] addNewFolderControllerWithParentButton:sender];
+
+ scoped_nsobject<BookmarkFolderTarget> target(
+ [[BookmarkFolderTarget alloc] initWithController:controller]);
+
+ [target openBookmarkFolderFromButton:sender];
+ [controller verify];
+
+ // Break retain cycles.
+ [controller clearRecordersAndExpectations];
+}
diff --git a/chrome/browser/cocoa/bookmarks/bookmark_menu.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu.h
index d4ac001..d4ac001 100644
--- a/chrome/browser/cocoa/bookmarks/bookmark_menu.h
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu.h
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu.mm
new file mode 100644
index 0000000..274edc7
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu.mm
@@ -0,0 +1,22 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/bookmarks/bookmark_menu.h"
+
+
+@implementation BookmarkMenu
+
+@synthesize id = id_;
+
+// Convention in the bookmark bar controller: the bookmark button
+// cells have a BookmarkNode as their represented object. This object
+// is placed in a BookmarkMenu at the time a cell is asked for its
+// menu.
+- (void)setRepresentedObject:(id)object {
+ if ([object isKindOfClass:[NSNumber class]]) {
+ id_ = static_cast<int64>([object longLongValue]);
+ }
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h
new file mode 100644
index 0000000..db64b2c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h
@@ -0,0 +1,123 @@
+// 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.
+
+// C++ controller for the bookmark menu; one per AppController (which
+// means there is only one). When bookmarks are changed, this class
+// takes care of updating Cocoa bookmark menus. This is not named
+// BookmarkMenuController to help avoid confusion between languages.
+// This class needs to be C++, not ObjC, since it derives from
+// BookmarkModelObserver.
+//
+// Most Chromium Cocoa menu items are static from a nib (e.g. New
+// Tab), but may be enabled/disabled under certain circumstances
+// (e.g. Cut and Paste). In addition, most Cocoa menu items have
+// firstResponder: as a target. Unusually, bookmark menu items are
+// created dynamically. They also have a target of
+// BookmarkMenuCocoaController instead of firstResponder.
+// See BookmarkMenuBridge::AddNodeToMenu()).
+
+#ifndef CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_MENU_BRIDGE_H_
+#define CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_MENU_BRIDGE_H_
+#pragma once
+
+#include <map>
+
+#include "base/scoped_nsobject.h"
+#include "chrome/browser/bookmarks/bookmark_model_observer.h"
+
+class BookmarkNode;
+class Profile;
+@class NSImage;
+@class NSMenu;
+@class NSMenuItem;
+@class BookmarkMenuCocoaController;
+
+class BookmarkMenuBridge : public BookmarkModelObserver {
+ public:
+ BookmarkMenuBridge(Profile* profile);
+ virtual ~BookmarkMenuBridge();
+
+ // Overridden from BookmarkModelObserver
+ virtual void Loaded(BookmarkModel* model);
+ virtual void BookmarkModelBeingDeleted(BookmarkModel* model);
+ virtual void BookmarkNodeMoved(BookmarkModel* model,
+ const BookmarkNode* old_parent,
+ int old_index,
+ const BookmarkNode* new_parent,
+ int new_index);
+ virtual void BookmarkNodeAdded(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int index);
+ virtual void BookmarkNodeRemoved(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int old_index,
+ const BookmarkNode* node);
+ virtual void BookmarkNodeChanged(BookmarkModel* model,
+ const BookmarkNode* node);
+ virtual void BookmarkNodeFavIconLoaded(BookmarkModel* model,
+ const BookmarkNode* node);
+ virtual void BookmarkNodeChildrenReordered(BookmarkModel* model,
+ const BookmarkNode* node);
+
+ // Rebuilds the bookmark menu, if it has been marked invalid.
+ void UpdateMenu(NSMenu* bookmark_menu);
+
+ // I wish I had a "friend @class" construct.
+ BookmarkModel* GetBookmarkModel();
+ Profile* GetProfile();
+
+ protected:
+ // Clear all bookmarks from the given bookmark menu.
+ void ClearBookmarkMenu(NSMenu* menu);
+
+ // Mark the bookmark menu as being invalid.
+ void InvalidateMenu() { menuIsValid_ = false; }
+
+ // Helper for adding the node as a submenu to the menu with the
+ // given title.
+ void AddNodeAsSubmenu(NSMenu* menu,
+ const BookmarkNode* node,
+ NSString* title);
+
+ // Helper for recursively adding items to our bookmark menu
+ // All children of |node| will be added to |menu|.
+ // TODO(jrg): add a counter to enforce maximum nodes added
+ void AddNodeToMenu(const BookmarkNode* node, NSMenu* menu);
+
+ // This configures an NSMenuItem with all the data from a BookmarkNode. This
+ // is used to update existing menu items, as well as to configure newly
+ // created ones, like in AddNodeToMenu().
+ // |set_title| is optional since it is only needed when we get a
+ // node changed notification. On initial build of the menu we set
+ // the title as part of alloc/init.
+ void ConfigureMenuItem(const BookmarkNode* node, NSMenuItem* item,
+ bool set_title);
+
+ // Returns the NSMenuItem for a given BookmarkNode.
+ NSMenuItem* MenuItemForNode(const BookmarkNode* node);
+
+ // Return the Bookmark menu.
+ virtual NSMenu* BookmarkMenu();
+
+ // Start watching the bookmarks for changes.
+ void ObserveBookmarkModel();
+
+ private:
+ friend class BookmarkMenuBridgeTest;
+
+ // True iff the menu is up-to-date with the actual BookmarkModel.
+ bool menuIsValid_;
+
+ Profile* profile_; // weak
+ BookmarkMenuCocoaController* controller_; // strong
+
+ // The folder image so we can use one copy for all.
+ scoped_nsobject<NSImage> folder_image_;
+
+ // In order to appropriately update items in the bookmark menu, without
+ // forcing a rebuild, map the model's nodes to menu items.
+ std::map<const BookmarkNode*, NSMenuItem*> bookmark_nodes_;
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_MENU_BRIDGE_H_
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.mm
new file mode 100644
index 0000000..3792fe3
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.mm
@@ -0,0 +1,253 @@
+// 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 <AppKit/AppKit.h>
+
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "app/mac/nsimage_cache.h"
+#include "base/sys_string_conversions.h"
+#import "chrome/browser/app_controller_mac.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "skia/ext/skia_utils_mac.h"
+
+BookmarkMenuBridge::BookmarkMenuBridge(Profile* profile)
+ : menuIsValid_(false),
+ profile_(profile),
+ controller_([[BookmarkMenuCocoaController alloc] initWithBridge:this]) {
+ if (GetBookmarkModel())
+ ObserveBookmarkModel();
+}
+
+BookmarkMenuBridge::~BookmarkMenuBridge() {
+ BookmarkModel *model = GetBookmarkModel();
+ if (model)
+ model->RemoveObserver(this);
+ [controller_ release];
+}
+
+NSMenu* BookmarkMenuBridge::BookmarkMenu() {
+ return [controller_ menu];
+}
+
+void BookmarkMenuBridge::Loaded(BookmarkModel* model) {
+ InvalidateMenu();
+}
+
+void BookmarkMenuBridge::UpdateMenu(NSMenu* bookmark_menu) {
+ DCHECK(bookmark_menu);
+ if (menuIsValid_)
+ return;
+ BookmarkModel* model = GetBookmarkModel();
+ if (!model || !model->IsLoaded())
+ return;
+
+ if (!folder_image_) {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ folder_image_.reset(
+ [rb.GetNativeImageNamed(IDR_BOOKMARK_BAR_FOLDER) retain]);
+ }
+
+ ClearBookmarkMenu(bookmark_menu);
+
+ // Add bookmark bar items, if any.
+ const BookmarkNode* barNode = model->GetBookmarkBarNode();
+ CHECK(barNode);
+ if (barNode->GetChildCount()) {
+ [bookmark_menu addItem:[NSMenuItem separatorItem]];
+ AddNodeToMenu(barNode, bookmark_menu);
+ }
+
+ // Create a submenu for "other bookmarks", and fill it in.
+ NSString* other_items_title =
+ l10n_util::GetNSString(IDS_BOOMARK_BAR_OTHER_FOLDER_NAME);
+ [bookmark_menu addItem:[NSMenuItem separatorItem]];
+ AddNodeAsSubmenu(bookmark_menu,
+ model->other_node(),
+ other_items_title);
+
+ menuIsValid_ = true;
+}
+
+void BookmarkMenuBridge::BookmarkModelBeingDeleted(BookmarkModel* model) {
+ NSMenu* bookmark_menu = BookmarkMenu();
+ if (bookmark_menu == nil)
+ return;
+
+ ClearBookmarkMenu(bookmark_menu);
+}
+
+void BookmarkMenuBridge::BookmarkNodeMoved(BookmarkModel* model,
+ const BookmarkNode* old_parent,
+ int old_index,
+ const BookmarkNode* new_parent,
+ int new_index) {
+ InvalidateMenu();
+}
+
+void BookmarkMenuBridge::BookmarkNodeAdded(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int index) {
+ InvalidateMenu();
+}
+
+void BookmarkMenuBridge::BookmarkNodeRemoved(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int old_index,
+ const BookmarkNode* node) {
+ InvalidateMenu();
+}
+
+void BookmarkMenuBridge::BookmarkNodeChanged(BookmarkModel* model,
+ const BookmarkNode* node) {
+ NSMenuItem* item = MenuItemForNode(node);
+ if (item)
+ ConfigureMenuItem(node, item, true);
+}
+
+void BookmarkMenuBridge::BookmarkNodeFavIconLoaded(BookmarkModel* model,
+ const BookmarkNode* node) {
+ NSMenuItem* item = MenuItemForNode(node);
+ if (item)
+ ConfigureMenuItem(node, item, false);
+}
+
+void BookmarkMenuBridge::BookmarkNodeChildrenReordered(
+ BookmarkModel* model, const BookmarkNode* node) {
+ InvalidateMenu();
+}
+
+// Watch for changes.
+void BookmarkMenuBridge::ObserveBookmarkModel() {
+ BookmarkModel* model = GetBookmarkModel();
+ model->AddObserver(this);
+ if (model->IsLoaded())
+ Loaded(model);
+}
+
+BookmarkModel* BookmarkMenuBridge::GetBookmarkModel() {
+ if (!profile_)
+ return NULL;
+ return profile_->GetBookmarkModel();
+}
+
+Profile* BookmarkMenuBridge::GetProfile() {
+ return profile_;
+}
+
+void BookmarkMenuBridge::ClearBookmarkMenu(NSMenu* menu) {
+ bookmark_nodes_.clear();
+ // Recursively delete all menus that look like a bookmark. Assume
+ // all items with submenus contain only bookmarks. Also delete all
+ // separator items since we explicirly add them back in. This should
+ // deletes everything except the first item ("Add Bookmark...").
+ NSArray* items = [menu itemArray];
+ for (NSMenuItem* item in items) {
+ // Convention: items in the bookmark list which are bookmarks have
+ // an action of openBookmarkMenuItem:. Also, assume all items
+ // with submenus are submenus of bookmarks.
+ if (([item action] == @selector(openBookmarkMenuItem:)) ||
+ [item hasSubmenu] ||
+ [item isSeparatorItem]) {
+ // This will eventually [obj release] all its kids, if it has
+ // any.
+ [menu removeItem:item];
+ } else {
+ // Leave it alone.
+ }
+ }
+}
+
+void BookmarkMenuBridge::AddNodeAsSubmenu(NSMenu* menu,
+ const BookmarkNode* node,
+ NSString* title) {
+ NSMenuItem* items = [[[NSMenuItem alloc]
+ initWithTitle:title
+ action:nil
+ keyEquivalent:@""] autorelease];
+ [items setImage:folder_image_];
+ [menu addItem:items];
+ NSMenu* other_submenu = [[[NSMenu alloc] initWithTitle:title]
+ autorelease];
+ [menu setSubmenu:other_submenu forItem:items];
+ AddNodeToMenu(node, other_submenu);
+}
+
+// TODO(jrg): limit the number of bookmarks in the menubar?
+void BookmarkMenuBridge::AddNodeToMenu(const BookmarkNode* node, NSMenu* menu) {
+ int child_count = node->GetChildCount();
+ if (!child_count) {
+ NSString* empty_string = l10n_util::GetNSString(IDS_MENU_EMPTY_SUBMENU);
+ NSMenuItem* item = [[[NSMenuItem alloc] initWithTitle:empty_string
+ action:nil
+ keyEquivalent:@""] autorelease];
+ [menu addItem:item];
+ } else for (int i = 0; i < child_count; i++) {
+ const BookmarkNode* child = node->GetChild(i);
+ NSString* title = [BookmarkMenuCocoaController menuTitleForNode:child];
+ NSMenuItem* item = [[[NSMenuItem alloc] initWithTitle:title
+ action:nil
+ keyEquivalent:@""] autorelease];
+ [menu addItem:item];
+ bookmark_nodes_[child] = item;
+ if (child->is_folder()) {
+ [item setImage:folder_image_];
+ NSMenu* submenu = [[[NSMenu alloc] initWithTitle:title] autorelease];
+ [menu setSubmenu:submenu forItem:item];
+ AddNodeToMenu(child, submenu); // recursive call
+ } else {
+ ConfigureMenuItem(child, item, false);
+ }
+ }
+}
+
+void BookmarkMenuBridge::ConfigureMenuItem(const BookmarkNode* node,
+ NSMenuItem* item,
+ bool set_title) {
+ if (set_title) {
+ NSString* title = [BookmarkMenuCocoaController menuTitleForNode:node];
+ [item setTitle:title];
+ }
+ [item setTarget:controller_];
+ [item setAction:@selector(openBookmarkMenuItem:)];
+ [item setTag:node->id()];
+ // Add a tooltip
+ std::string url_string = node->GetURL().possibly_invalid_spec();
+ NSString* tooltip = [NSString stringWithFormat:@"%@\n%s",
+ base::SysUTF16ToNSString(node->GetTitle()),
+ url_string.c_str()];
+ [item setToolTip:tooltip];
+
+ // Check to see if we have a favicon.
+ NSImage* favicon = nil;
+ BookmarkModel* model = GetBookmarkModel();
+ if (model) {
+ const SkBitmap& bitmap = model->GetFavIcon(node);
+ if (!bitmap.isNull())
+ favicon = gfx::SkBitmapToNSImage(bitmap);
+ }
+ // Either we do not have a loaded favicon or the conversion from SkBitmap
+ // failed. Use the default site image instead.
+ if (!favicon)
+ favicon = app::mac::GetCachedImageWithName(@"nav.pdf");
+ [item setImage:favicon];
+}
+
+NSMenuItem* BookmarkMenuBridge::MenuItemForNode(const BookmarkNode* node) {
+ if (!node)
+ return nil;
+ std::map<const BookmarkNode*, NSMenuItem*>::iterator it =
+ bookmark_nodes_.find(node);
+ if (it == bookmark_nodes_.end())
+ return nil;
+ return it->second;
+}
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge_unittest.mm
new file mode 100644
index 0000000..cec14eb
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge_unittest.mm
@@ -0,0 +1,317 @@
+// 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 <AppKit/AppKit.h>
+
+#import "base/scoped_nsobject.h"
+#include "base/string16.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#include "chrome/browser/ui/browser.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+class TestBookmarkMenuBridge : public BookmarkMenuBridge {
+ public:
+ TestBookmarkMenuBridge(Profile* profile)
+ : BookmarkMenuBridge(profile),
+ menu_([[NSMenu alloc] initWithTitle:@"test"]) {
+ }
+ virtual ~TestBookmarkMenuBridge() {}
+
+ scoped_nsobject<NSMenu> menu_;
+
+ protected:
+ // Overridden from BookmarkMenuBridge.
+ virtual NSMenu* BookmarkMenu() {
+ return menu_;
+ }
+};
+
+// TODO(jrg): see refactor comment in bookmark_bar_state_controller_unittest.mm
+class BookmarkMenuBridgeTest : public PlatformTest {
+ public:
+
+ void SetUp() {
+ bridge_.reset(new TestBookmarkMenuBridge(browser_test_helper_.profile()));
+ EXPECT_TRUE(bridge_.get());
+ }
+
+ // We are a friend of BookmarkMenuBridge (and have access to
+ // protected methods), but none of the classes generated by TEST_F()
+ // are. This (and AddNodeToMenu()) are simple wrappers to let
+ // derived test classes have access to protected methods.
+ void ClearBookmarkMenu(BookmarkMenuBridge* bridge, NSMenu* menu) {
+ bridge->ClearBookmarkMenu(menu);
+ }
+
+ void InvalidateMenu() { bridge_->InvalidateMenu(); }
+ bool menu_is_valid() { return bridge_->menuIsValid_; }
+
+ void AddNodeToMenu(BookmarkMenuBridge* bridge, const BookmarkNode* root,
+ NSMenu* menu) {
+ bridge->AddNodeToMenu(root, menu);
+ }
+
+ NSMenuItem* MenuItemForNode(BookmarkMenuBridge* bridge,
+ const BookmarkNode* node) {
+ return bridge->MenuItemForNode(node);
+ }
+
+ NSMenuItem* AddItemToMenu(NSMenu *menu, NSString *title, SEL selector) {
+ NSMenuItem *item = [[[NSMenuItem alloc] initWithTitle:title action:NULL
+ keyEquivalent:@""] autorelease];
+ if (selector)
+ [item setAction:selector];
+ [menu addItem:item];
+ return item;
+ }
+
+ BrowserTestHelper browser_test_helper_;
+ scoped_ptr<TestBookmarkMenuBridge> bridge_;
+};
+
+TEST_F(BookmarkMenuBridgeTest, TestBookmarkMenuAutoSeparator) {
+ BookmarkModel* model = bridge_->GetBookmarkModel();
+ bridge_->Loaded(model);
+ NSMenu* menu = bridge_->menu_.get();
+ bridge_->UpdateMenu(menu);
+ // The bare menu after loading has a separator and an "Other Bookmarks"
+ // submenu.
+ EXPECT_EQ(2, [menu numberOfItems]);
+ // Add a bookmark and reload and there should be 4 items: the previous
+ // menu contents plus a new separator and the new bookmark.
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ const char* url = "http://www.zim-bop-a-dee.com/";
+ model->AddURL(parent, 0, ASCIIToUTF16("Bookmark"), GURL(url));
+ bridge_->UpdateMenu(menu);
+ EXPECT_EQ(4, [menu numberOfItems]);
+ // Remove the new bookmark and reload and we should have 2 items again
+ // because the separator should have been removed as well.
+ model->Remove(parent, 0);
+ bridge_->UpdateMenu(menu);
+ EXPECT_EQ(2, [menu numberOfItems]);
+}
+
+// Test that ClearBookmarkMenu() removes all bookmark menus.
+TEST_F(BookmarkMenuBridgeTest, TestClearBookmarkMenu) {
+ NSMenu* menu = bridge_->menu_.get();
+
+ AddItemToMenu(menu, @"hi mom", nil);
+ AddItemToMenu(menu, @"not", @selector(openBookmarkMenuItem:));
+ NSMenuItem* item = AddItemToMenu(menu, @"hi mom", nil);
+ [item setSubmenu:[[[NSMenu alloc] initWithTitle:@"bar"] autorelease]];
+ AddItemToMenu(menu, @"not", @selector(openBookmarkMenuItem:));
+ AddItemToMenu(menu, @"zippy", @selector(length));
+ [menu addItem:[NSMenuItem separatorItem]];
+
+ ClearBookmarkMenu(bridge_.get(), menu);
+
+ // Make sure all bookmark items are removed, all items with
+ // submenus removed, and all separator items are gone.
+ EXPECT_EQ(2, [menu numberOfItems]);
+ for (NSMenuItem *item in [menu itemArray]) {
+ EXPECT_NSNE(@"not", [item title]);
+ }
+}
+
+// Test invalidation
+TEST_F(BookmarkMenuBridgeTest, TestInvalidation) {
+ BookmarkModel* model = bridge_->GetBookmarkModel();
+ bridge_->Loaded(model);
+
+ EXPECT_FALSE(menu_is_valid());
+ bridge_->UpdateMenu(bridge_->menu_);
+ EXPECT_TRUE(menu_is_valid());
+
+ InvalidateMenu();
+ EXPECT_FALSE(menu_is_valid());
+ InvalidateMenu();
+ EXPECT_FALSE(menu_is_valid());
+ bridge_->UpdateMenu(bridge_->menu_);
+ EXPECT_TRUE(menu_is_valid());
+ bridge_->UpdateMenu(bridge_->menu_);
+ EXPECT_TRUE(menu_is_valid());
+
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ const char* url = "http://www.zim-bop-a-dee.com/";
+ model->AddURL(parent, 0, ASCIIToUTF16("Bookmark"), GURL(url));
+
+ EXPECT_FALSE(menu_is_valid());
+ bridge_->UpdateMenu(bridge_->menu_);
+ EXPECT_TRUE(menu_is_valid());
+}
+
+// Test that AddNodeToMenu() properly adds bookmark nodes as menus,
+// including the recursive case.
+TEST_F(BookmarkMenuBridgeTest, TestAddNodeToMenu) {
+ string16 empty;
+ NSMenu* menu = bridge_->menu_.get();
+
+ BookmarkModel* model = bridge_->GetBookmarkModel();
+ const BookmarkNode* root = model->GetBookmarkBarNode();
+ EXPECT_TRUE(model && root);
+
+ const char* short_url = "http://foo/";
+ const char* long_url = "http://super-duper-long-url--."
+ "that.cannot.possibly.fit.even-in-80-columns"
+ "or.be.reasonably-displayed-in-a-menu"
+ "without.looking-ridiculous.com/"; // 140 chars total
+
+ // 3 nodes; middle one has a child, last one has a HUGE URL
+ // Set their titles to be the same as the URLs
+ const BookmarkNode* node = NULL;
+ model->AddURL(root, 0, ASCIIToUTF16(short_url), GURL(short_url));
+ bridge_->UpdateMenu(menu);
+ int prev_count = [menu numberOfItems] - 1; // "extras" added at this point
+ node = model->AddGroup(root, 1, empty);
+ model->AddURL(root, 2, ASCIIToUTF16(long_url), GURL(long_url));
+
+ // And the submenu fo the middle one
+ model->AddURL(node, 0, empty, GURL("http://sub"));
+ bridge_->UpdateMenu(menu);
+
+ EXPECT_EQ((NSInteger)(prev_count+3), [menu numberOfItems]);
+
+ // Verify the 1st one is there with the right action.
+ NSMenuItem* item = [menu itemWithTitle:[NSString
+ stringWithUTF8String:short_url]];
+ EXPECT_TRUE(item);
+ EXPECT_EQ(@selector(openBookmarkMenuItem:), [item action]);
+ EXPECT_EQ(NO, [item hasSubmenu]);
+ NSMenuItem* short_item = item;
+ NSMenuItem* long_item = nil;
+
+ // Now confirm we have 2 submenus (the one we added, plus "other")
+ int subs = 0;
+ for (item in [menu itemArray]) {
+ if ([item hasSubmenu])
+ subs++;
+ }
+ EXPECT_EQ(2, subs);
+
+ for (item in [menu itemArray]) {
+ if ([[item title] hasPrefix:@"http://super-duper"]) {
+ long_item = item;
+ break;
+ }
+ }
+ EXPECT_TRUE(long_item);
+
+ // Make sure a short title looks fine
+ NSString* s = [short_item title];
+ EXPECT_NSEQ([NSString stringWithUTF8String:short_url], s);
+
+ // Make sure a super-long title gets trimmed
+ s = [long_item title];
+ EXPECT_TRUE([s length] < strlen(long_url));
+
+ // Confirm tooltips and confirm they are not trimmed (like the item
+ // name might be). Add tolerance for URL fixer-upping;
+ // e.g. http://foo becomes http://foo/)
+ EXPECT_GE([[short_item toolTip] length], (2*strlen(short_url) - 5));
+ EXPECT_GE([[long_item toolTip] length], (2*strlen(long_url) - 5));
+
+ // Make sure the favicon is non-nil (should be either the default site
+ // icon or a favicon, if present).
+ EXPECT_TRUE([short_item image]);
+ EXPECT_TRUE([long_item image]);
+}
+
+// Makes sure our internal map of BookmarkNode to NSMenuItem works.
+TEST_F(BookmarkMenuBridgeTest, TestGetMenuItemForNode) {
+ string16 empty;
+ NSMenu* menu = bridge_->menu_.get();
+
+ BookmarkModel* model = bridge_->GetBookmarkModel();
+ const BookmarkNode* bookmark_bar = model->GetBookmarkBarNode();
+ const BookmarkNode* root = model->AddGroup(bookmark_bar, 0, empty);
+ EXPECT_TRUE(model && root);
+
+ model->AddURL(root, 0, ASCIIToUTF16("Test Item"), GURL("http://test"));
+ AddNodeToMenu(bridge_.get(), root, menu);
+ EXPECT_TRUE(MenuItemForNode(bridge_.get(), root->GetChild(0)));
+
+ model->AddURL(root, 1, ASCIIToUTF16("Test 2"), GURL("http://second-test"));
+ AddNodeToMenu(bridge_.get(), root, menu);
+ EXPECT_TRUE(MenuItemForNode(bridge_.get(), root->GetChild(0)));
+ EXPECT_TRUE(MenuItemForNode(bridge_.get(), root->GetChild(1)));
+
+ const BookmarkNode* removed_node = root->GetChild(0);
+ EXPECT_EQ(2, root->GetChildCount());
+ model->Remove(root, 0);
+ EXPECT_EQ(1, root->GetChildCount());
+ bridge_->UpdateMenu(menu);
+ EXPECT_FALSE(MenuItemForNode(bridge_.get(), removed_node));
+ EXPECT_TRUE(MenuItemForNode(bridge_.get(), root->GetChild(0)));
+
+ const BookmarkNode empty_node(GURL("http://no-where/"));
+ EXPECT_FALSE(MenuItemForNode(bridge_.get(), &empty_node));
+ EXPECT_FALSE(MenuItemForNode(bridge_.get(), NULL));
+}
+
+// Test that Loaded() adds both the bookmark bar nodes and the "other" nodes.
+TEST_F(BookmarkMenuBridgeTest, TestAddNodeToOther) {
+ NSMenu* menu = bridge_->menu_.get();
+
+ BookmarkModel* model = bridge_->GetBookmarkModel();
+ const BookmarkNode* root = model->other_node();
+ EXPECT_TRUE(model && root);
+
+ const char* short_url = "http://foo/";
+ model->AddURL(root, 0, ASCIIToUTF16(short_url), GURL(short_url));
+
+ bridge_->UpdateMenu(menu);
+ ASSERT_GT([menu numberOfItems], 0);
+ NSMenuItem* other = [menu itemAtIndex:([menu numberOfItems]-1)];
+ EXPECT_TRUE(other);
+ EXPECT_TRUE([other hasSubmenu]);
+ ASSERT_GT([[other submenu] numberOfItems], 0);
+ EXPECT_NSEQ(@"http://foo/", [[[other submenu] itemAtIndex:0] title]);
+}
+
+TEST_F(BookmarkMenuBridgeTest, TestFavIconLoading) {
+ NSMenu* menu = bridge_->menu_;
+
+ BookmarkModel* model = bridge_->GetBookmarkModel();
+ const BookmarkNode* root = model->GetBookmarkBarNode();
+ EXPECT_TRUE(model && root);
+
+ const BookmarkNode* node =
+ model->AddURL(root, 0, ASCIIToUTF16("Test Item"),
+ GURL("http://favicon-test"));
+ bridge_->UpdateMenu(menu);
+ NSMenuItem* item = [menu itemWithTitle:@"Test Item"];
+ EXPECT_TRUE([item image]);
+ [item setImage:nil];
+ bridge_->BookmarkNodeFavIconLoaded(model, node);
+ EXPECT_TRUE([item image]);
+}
+
+TEST_F(BookmarkMenuBridgeTest, TestChangeTitle) {
+ NSMenu* menu = bridge_->menu_;
+ BookmarkModel* model = bridge_->GetBookmarkModel();
+ const BookmarkNode* root = model->GetBookmarkBarNode();
+ EXPECT_TRUE(model && root);
+
+ const BookmarkNode* node =
+ model->AddURL(root, 0, ASCIIToUTF16("Test Item"),
+ GURL("http://title-test"));
+ bridge_->UpdateMenu(menu);
+ NSMenuItem* item = [menu itemWithTitle:@"Test Item"];
+ EXPECT_TRUE([item image]);
+
+ model->SetTitle(node, ASCIIToUTF16("New Title"));
+
+ item = [menu itemWithTitle:@"Test Item"];
+ EXPECT_FALSE(item);
+ item = [menu itemWithTitle:@"New Title"];
+ EXPECT_TRUE(item);
+}
+
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.h
new file mode 100644
index 0000000..ac7def4
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.h
@@ -0,0 +1,46 @@
+// 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.
+
+// Controller (MVC) for the bookmark menu.
+// All bookmark menu item commands get directed here.
+// Unfortunately there is already a C++ class named BookmarkMenuController.
+
+#ifndef CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_MENU_COCOA_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_MENU_COCOA_CONTROLLER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/mac/cocoa_protocols.h"
+
+class BookmarkNode;
+class BookmarkMenuBridge;
+
+@interface BookmarkMenuCocoaController : NSObject<NSMenuDelegate> {
+ @private
+ BookmarkMenuBridge* bridge_; // weak; owns me
+}
+
+// The Bookmarks menu
+@property (nonatomic, readonly) NSMenu* menu;
+
+// Return an autoreleased string to be used as a menu title for the
+// given bookmark node.
++ (NSString*)menuTitleForNode:(const BookmarkNode*)node;
+
+- (id)initWithBridge:(BookmarkMenuBridge *)bridge;
+
+// Called by any Bookmark menu item.
+// The menu item's tag is the bookmark ID.
+- (IBAction)openBookmarkMenuItem:(id)sender;
+
+@end // BookmarkMenuCocoaController
+
+
+@interface BookmarkMenuCocoaController (ExposedForUnitTests)
+- (const BookmarkNode*)nodeForIdentifier:(int)identifier;
+- (void)openURLForNode:(const BookmarkNode*)node;
+@end // BookmarkMenuCocoaController (ExposedForUnitTests)
+
+#endif // CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_MENU_COCOA_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm
new file mode 100644
index 0000000..1d2fb2d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm
@@ -0,0 +1,96 @@
+// 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 "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.h"
+
+#include "app/text_elider.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h" // IDC_BOOKMARK_MENU
+#import "chrome/browser/app_controller_mac.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/ui/browser.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h"
+#include "chrome/browser/ui/cocoa/event_utils.h"
+#include "webkit/glue/window_open_disposition.h"
+
+namespace {
+
+// Menus more than this many pixels wide will get trimmed
+// TODO(jrg): ask UI dudes what a good value is.
+const NSUInteger kMaximumMenuPixelsWide = 300;
+
+}
+
+@implementation BookmarkMenuCocoaController
+
++ (NSString*)menuTitleForNode:(const BookmarkNode*)node {
+ NSFont* nsfont = [NSFont menuBarFontOfSize:0]; // 0 means "default"
+ gfx::Font font(base::SysNSStringToWide([nsfont fontName]),
+ static_cast<int>([nsfont pointSize]));
+ string16 title = gfx::ElideText(node->GetTitle(),
+ font,
+ kMaximumMenuPixelsWide,
+ false);
+ return base::SysUTF16ToNSString(title);
+}
+
+- (id)initWithBridge:(BookmarkMenuBridge *)bridge {
+ if ((self = [super init])) {
+ bridge_ = bridge;
+ DCHECK(bridge_);
+ [[self menu] setDelegate:self];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [[self menu] setDelegate:nil];
+ [super dealloc];
+}
+
+- (NSMenu*)menu {
+ return [[[NSApp mainMenu] itemWithTag:IDC_BOOKMARK_MENU] submenu];
+}
+
+- (BOOL)validateMenuItem:(NSMenuItem*)menuItem {
+ AppController* controller = [NSApp delegate];
+ return [controller keyWindowIsNotModal];
+}
+
+// NSMenu delegate method: called just before menu is displayed.
+- (void)menuNeedsUpdate:(NSMenu*)menu {
+ bridge_->UpdateMenu(menu);
+}
+
+// Return the a BookmarkNode that has the given id (called
+// "identifier" here to avoid conflict with objc's concept of "id").
+- (const BookmarkNode*)nodeForIdentifier:(int)identifier {
+ return bridge_->GetBookmarkModel()->GetNodeByID(identifier);
+}
+
+// Open the URL of the given BookmarkNode in the current tab.
+- (void)openURLForNode:(const BookmarkNode*)node {
+ Browser* browser = Browser::GetTabbedBrowser(bridge_->GetProfile(), true);
+ if (!browser)
+ browser = Browser::Create(bridge_->GetProfile());
+ WindowOpenDisposition disposition =
+ event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
+ browser->OpenURL(node->GetURL(), GURL(), disposition,
+ PageTransition::AUTO_BOOKMARK);
+}
+
+- (IBAction)openBookmarkMenuItem:(id)sender {
+ NSInteger tag = [sender tag];
+ int identifier = tag;
+ const BookmarkNode* node = [self nodeForIdentifier:identifier];
+ DCHECK(node);
+ if (!node)
+ return; // shouldn't be reached
+
+ [self openURLForNode:node];
+}
+
+@end // BookmarkMenuCocoaController
+
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller_unittest.mm
new file mode 100644
index 0000000..22930bc
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller_unittest.mm
@@ -0,0 +1,66 @@
+// 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.
+
+#include "base/string16.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.h"
+#include "chrome/browser/ui/browser.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+@interface FakeBookmarkMenuController : BookmarkMenuCocoaController {
+ @public
+ BrowserTestHelper* helper_;
+ const BookmarkNode* nodes_[2];
+ BOOL opened_[2];
+}
+@end
+
+@implementation FakeBookmarkMenuController
+
+- (id)init {
+ if ((self = [super init])) {
+ string16 empty;
+ helper_ = new BrowserTestHelper();
+ BookmarkModel* model = helper_->browser()->profile()->GetBookmarkModel();
+ const BookmarkNode* bookmark_bar = model->GetBookmarkBarNode();
+ nodes_[0] = model->AddURL(bookmark_bar, 0, empty, GURL("http://0.com"));
+ nodes_[1] = model->AddURL(bookmark_bar, 1, empty, GURL("http://1.com"));
+ }
+ return self;
+}
+
+- (void)dealloc {
+ delete helper_;
+ [super dealloc];
+}
+
+- (const BookmarkNode*)nodeForIdentifier:(int)identifier {
+ if ((identifier < 0) || (identifier >= 2))
+ return NULL;
+ return nodes_[identifier];
+}
+
+- (void)openURLForNode:(const BookmarkNode*)node {
+ std::string url = node->GetURL().possibly_invalid_spec();
+ if (url.find("http://0.com") != std::string::npos)
+ opened_[0] = YES;
+ if (url.find("http://1.com") != std::string::npos)
+ opened_[1] = YES;
+}
+
+@end // FakeBookmarkMenuController
+
+
+TEST(BookmarkMenuCocoaControllerTest, TestOpenItem) {
+ FakeBookmarkMenuController *c = [[FakeBookmarkMenuController alloc] init];
+ NSMenuItem *item = [[[NSMenuItem alloc] init] autorelease];
+ for (int i = 0; i < 2; i++) {
+ [item setTag:i];
+ ASSERT_EQ(c->opened_[i], NO);
+ [c openBookmarkMenuItem:item];
+ ASSERT_NE(c->opened_[i], NO);
+ }
+ [c release];
+}
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_unittest.mm
new file mode 100644
index 0000000..ef251b0
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_unittest.mm
@@ -0,0 +1,29 @@
+// Copyright (c) 2009 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/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class BookmarkMenuTest : public CocoaTest {
+};
+
+TEST_F(BookmarkMenuTest, Basics) {
+ scoped_nsobject<BookmarkMenu> menu([[BookmarkMenu alloc]
+ initWithTitle:@"title"]);
+ scoped_nsobject<NSMenuItem> item([[NSMenuItem alloc] initWithTitle:@"item"
+ action:NULL
+ keyEquivalent:@""]);
+ [menu addItem:item];
+ long long l = 103849459459598948LL; // arbitrary
+ NSNumber* number = [NSNumber numberWithLongLong:l];
+ [menu setRepresentedObject:number];
+ EXPECT_EQ(l, [menu id]);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa.h
new file mode 100644
index 0000000..0a7da34
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa.h
@@ -0,0 +1,116 @@
+// 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.
+
+// C++ bridge class to send a selector to a Cocoa object when the
+// bookmark model changes. Some Cocoa objects edit the bookmark model
+// and temporarily save a copy of the state (e.g. bookmark button
+// editor). As a fail-safe, these objects want an easy cancel if the
+// model changes out from under them. For example, if you have the
+// bookmark button editor sheet open, then edit the bookmark in the
+// bookmark manager, we'd want to simply cancel the editor.
+//
+// This class is conservative and may result in notifications which
+// aren't strictly necessary. For example, node removal only needs to
+// cancel an edit if the removed node is a folder (editors often have
+// a list of "new parents"). But, just to be sure, notification
+// happens on any removal.
+
+#ifndef CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_MODEL_OBSERVER_FOR_COCOA_H
+#define CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_MODEL_OBSERVER_FOR_COCOA_H
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/basictypes.h"
+#include "base/scoped_nsobject.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/bookmarks/bookmark_model_observer.h"
+
+class BookmarkModelObserverForCocoa : public BookmarkModelObserver {
+ public:
+ // When |node| in |model| changes, send |selector| to |object|.
+ // Assumes |selector| is a selector that takes one arg, like an
+ // IBOutlet. The arg passed is nil.
+ // Many notifications happen independently of node
+ // (e.g. BeingDeleted), so |node| can be nil.
+ //
+ // |object| is NOT retained, since the expected use case is for
+ // ||object| to own the BookmarkModelObserverForCocoa and we don't
+ // want a retain cycle.
+ BookmarkModelObserverForCocoa(const BookmarkNode* node,
+ BookmarkModel* model,
+ NSObject* object,
+ SEL selector) {
+ DCHECK(model);
+ node_ = node;
+ model_ = model;
+ object_ = object;
+ selector_ = selector;
+ model_->AddObserver(this);
+ }
+ virtual ~BookmarkModelObserverForCocoa() {
+ model_->RemoveObserver(this);
+ }
+
+ virtual void BookmarkModelBeingDeleted(BookmarkModel* model) {
+ Notify();
+ }
+ virtual void BookmarkNodeMoved(BookmarkModel* model,
+ const BookmarkNode* old_parent,
+ int old_index,
+ const BookmarkNode* new_parent,
+ int new_index) {
+ // Editors often have a tree of parents, so movement of folders
+ // must cause a cancel.
+ Notify();
+ }
+ virtual void BookmarkNodeRemoved(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int old_index,
+ const BookmarkNode* node) {
+ // See comment in BookmarkNodeMoved.
+ Notify();
+ }
+ virtual void BookmarkNodeChanged(BookmarkModel* model,
+ const BookmarkNode* node) {
+ if ((node_ == node) || (!node_))
+ Notify();
+ }
+ virtual void BookmarkImportBeginning(BookmarkModel* model) {
+ // Be conservative.
+ Notify();
+ }
+
+ // Some notifications we don't care about, but by being pure virtual
+ // in the base class we must implement them.
+ virtual void Loaded(BookmarkModel* model) {
+ }
+ virtual void BookmarkNodeAdded(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int index) {
+ }
+ virtual void BookmarkNodeFavIconLoaded(BookmarkModel* model,
+ const BookmarkNode* node) {
+ }
+ virtual void BookmarkNodeChildrenReordered(BookmarkModel* model,
+ const BookmarkNode* node) {
+ }
+
+ virtual void BookmarkImportEnding(BookmarkModel* model) {
+ }
+
+ private:
+ const BookmarkNode* node_; // Weak; owned by a BookmarkModel.
+ BookmarkModel* model_; // Weak; it is owned by a Profile.
+ NSObject* object_; // Weak, like a delegate.
+ SEL selector_;
+
+ void Notify() {
+ [object_ performSelector:selector_ withObject:nil];
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(BookmarkModelObserverForCocoa);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_MODEL_OBSERVER_FOR_COCOA_H
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa_unittest.mm
new file mode 100644
index 0000000..5ff8687
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa_unittest.mm
@@ -0,0 +1,68 @@
+// 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 "base/scoped_ptr.h"
+#include "base/scoped_nsobject.h"
+#include "base/utf_string_conversions.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa.h"
+#import "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+
+// Keep track of bookmark pings.
+@interface ObserverPingTracker : NSObject {
+ @public
+ int pings;
+}
+@end
+
+@implementation ObserverPingTracker
+- (void)pingMe:(id)sender {
+ pings++;
+}
+@end
+
+namespace {
+
+class BookmarkModelObserverForCocoaTest : public CocoaTest {
+ public:
+ BrowserTestHelper helper_;
+
+ BookmarkModelObserverForCocoaTest() {}
+ virtual ~BookmarkModelObserverForCocoaTest() {}
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BookmarkModelObserverForCocoaTest);
+};
+
+
+TEST_F(BookmarkModelObserverForCocoaTest, TestCallback) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ const BookmarkNode* node = model->AddURL(model->GetBookmarkBarNode(),
+ 0, ASCIIToUTF16("super"),
+ GURL("http://www.google.com"));
+
+ scoped_nsobject<ObserverPingTracker>
+ pingCount([[ObserverPingTracker alloc] init]);
+
+ scoped_ptr<BookmarkModelObserverForCocoa>
+ observer(new BookmarkModelObserverForCocoa(node, model,
+ pingCount,
+ @selector(pingMe:)));
+
+ EXPECT_EQ(0, pingCount.get()->pings);
+
+ model->SetTitle(node, ASCIIToUTF16("duper"));
+ EXPECT_EQ(1, pingCount.get()->pings);
+ model->SetURL(node, GURL("http://www.google.com/reader"));
+ EXPECT_EQ(2, pingCount.get()->pings);
+
+ model->Move(node, model->other_node(), 0);
+ EXPECT_EQ(3, pingCount.get()->pings);
+
+ model->Remove(node->GetParent(), 0);
+ EXPECT_EQ(4, pingCount.get()->pings);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller.h
new file mode 100644
index 0000000..40f1cb1
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller.h
@@ -0,0 +1,64 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_NAME_FOLDER_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_NAME_FOLDER_CONTROLLER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+
+class BookmarkModelObserverForCocoa;
+
+// A controller for dialog to let the user create a new folder or
+// rename an existing folder. Accessible from a context menu on a
+// bookmark button or the bookmark bar.
+@interface BookmarkNameFolderController : NSWindowController {
+ @private
+ IBOutlet NSTextField* nameField_;
+ IBOutlet NSButton* okButton_;
+
+ NSWindow* parentWindow_; // weak
+ Profile* profile_; // weak
+
+ // Weak; owned by the model. Can be NULL (see below). Either node_
+ // is non-NULL (renaming a folder), or parent_ is non-NULL (adding a
+ // new one).
+ const BookmarkNode* node_;
+ const BookmarkNode* parent_;
+ int newIndex_;
+
+ scoped_nsobject<NSString> initialName_;
+
+ // Ping me when things change out from under us.
+ scoped_ptr<BookmarkModelObserverForCocoa> observer_;
+}
+
+// Use the 1st initializer for a "rename existing folder" request.
+//
+// Use the 2nd initializer for an "add folder" request. If creating a
+// new folder |parent| and |newIndex| specify where to put the new
+// node.
+- (id)initWithParentWindow:(NSWindow*)window
+ profile:(Profile*)profile
+ node:(const BookmarkNode*)node;
+- (id)initWithParentWindow:(NSWindow*)window
+ profile:(Profile*)profile
+ parent:(const BookmarkNode*)parent
+ newIndex:(int)newIndex;
+- (void)runAsModalSheet;
+- (IBAction)cancel:(id)sender;
+- (IBAction)ok:(id)sender;
+@end
+
+@interface BookmarkNameFolderController(TestingAPI)
+- (NSString*)folderName;
+- (void)setFolderName:(NSString*)name;
+- (NSButton*)okButton;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_NAME_FOLDER_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller.mm
new file mode 100644
index 0000000..b4f23d2
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller.mm
@@ -0,0 +1,123 @@
+// 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 "chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller.h"
+
+#include "app/l10n_util.h"
+#include "app/l10n_util_mac.h"
+#include "base/mac_util.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa.h"
+#include "grit/generated_resources.h"
+
+@implementation BookmarkNameFolderController
+
+// Common initializer (private).
+- (id)initWithParentWindow:(NSWindow*)window
+ profile:(Profile*)profile
+ node:(const BookmarkNode*)node
+ parent:(const BookmarkNode*)parent
+ newIndex:(int)newIndex {
+ NSString* nibpath = [mac_util::MainAppBundle()
+ pathForResource:@"BookmarkNameFolder"
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
+ parentWindow_ = window;
+ profile_ = profile;
+ node_ = node;
+ parent_ = parent;
+ newIndex_ = newIndex;
+ if (parent) {
+ DCHECK_LE(newIndex, parent->GetChildCount());
+ }
+ if (node_) {
+ initialName_.reset([base::SysUTF16ToNSString(node_->GetTitle()) retain]);
+ } else {
+ NSString* newString =
+ l10n_util::GetNSStringWithFixup(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME);
+ initialName_.reset([newString retain]);
+ }
+ }
+ return self;
+}
+
+- (id)initWithParentWindow:(NSWindow*)window
+ profile:(Profile*)profile
+ node:(const BookmarkNode*)node {
+ DCHECK(node);
+ return [self initWithParentWindow:window
+ profile:profile
+ node:node
+ parent:nil
+ newIndex:0];
+}
+
+- (id)initWithParentWindow:(NSWindow*)window
+ profile:(Profile*)profile
+ parent:(const BookmarkNode*)parent
+ newIndex:(int)newIndex {
+ DCHECK(parent);
+ return [self initWithParentWindow:window
+ profile:profile
+ node:nil
+ parent:parent
+ newIndex:newIndex];
+}
+
+- (void)awakeFromNib {
+ [nameField_ setStringValue:initialName_.get()];
+}
+
+- (void)runAsModalSheet {
+ // Ping me when things change out from under us.
+ observer_.reset(new BookmarkModelObserverForCocoa(
+ node_, profile_->GetBookmarkModel(),
+ self,
+ @selector(cancel:)));
+ [NSApp beginSheet:[self window]
+ modalForWindow:parentWindow_
+ modalDelegate:self
+ didEndSelector:@selector(didEndSheet:returnCode:contextInfo:)
+ contextInfo:nil];
+}
+
+- (IBAction)cancel:(id)sender {
+ [NSApp endSheet:[self window]];
+}
+
+- (IBAction)ok:(id)sender {
+ NSString* name = [nameField_ stringValue];
+ BookmarkModel* model = profile_->GetBookmarkModel();
+ if (node_) {
+ model->SetTitle(node_, base::SysNSStringToUTF16(name));
+ } else {
+ model->AddGroup(parent_,
+ newIndex_,
+ base::SysNSStringToUTF16(name));
+ }
+ [NSApp endSheet:[self window]];
+}
+
+- (void)didEndSheet:(NSWindow*)sheet
+ returnCode:(int)returnCode
+ contextInfo:(void*)contextInfo {
+ [[self window] orderOut:self];
+ observer_.reset(NULL);
+ [self autorelease];
+}
+
+- (NSString*)folderName {
+ return [nameField_ stringValue];
+}
+
+- (void)setFolderName:(NSString*)name {
+ [nameField_ setStringValue:name];
+}
+
+- (NSButton*)okButton {
+ return okButton_;
+}
+
+@end // BookmarkNameFolderController
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller_unittest.mm
new file mode 100644
index 0000000..69fb939
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller_unittest.mm
@@ -0,0 +1,172 @@
+// 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 "base/scoped_nsobject.h"
+#include "base/utf_string_conversions.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_name_folder_controller.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+class BookmarkNameFolderControllerTest : public CocoaTest {
+ public:
+ BrowserTestHelper helper_;
+};
+
+
+// Simple add of a node (at the end).
+TEST_F(BookmarkNameFolderControllerTest, AddNew) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ EXPECT_EQ(0, parent->GetChildCount());
+
+ scoped_nsobject<BookmarkNameFolderController>
+ controller([[BookmarkNameFolderController alloc]
+ initWithParentWindow:test_window()
+ profile:helper_.profile()
+ parent:parent
+ newIndex:0]);
+ [controller window]; // force nib load
+
+ // Do nothing.
+ [controller cancel:nil];
+ EXPECT_EQ(0, parent->GetChildCount());
+
+ // Change name then cancel.
+ [controller setFolderName:@"Bozo"];
+ [controller cancel:nil];
+ EXPECT_EQ(0, parent->GetChildCount());
+
+ // Add a new folder.
+ [controller ok:nil];
+ EXPECT_EQ(1, parent->GetChildCount());
+ EXPECT_TRUE(parent->GetChild(0)->is_folder());
+ EXPECT_EQ(ASCIIToUTF16("Bozo"), parent->GetChild(0)->GetTitle());
+}
+
+// Add new but specify a sibling.
+TEST_F(BookmarkNameFolderControllerTest, AddNewWithSibling) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+
+ // Add 2 nodes. We will place the new folder in the middle of these.
+ model->AddURL(parent, 0, ASCIIToUTF16("title 1"),
+ GURL("http://www.google.com"));
+ model->AddURL(parent, 1, ASCIIToUTF16("title 3"),
+ GURL("http://www.google.com"));
+ EXPECT_EQ(2, parent->GetChildCount());
+
+ scoped_nsobject<BookmarkNameFolderController>
+ controller([[BookmarkNameFolderController alloc]
+ initWithParentWindow:test_window()
+ profile:helper_.profile()
+ parent:parent
+ newIndex:1]);
+ [controller window]; // force nib load
+
+ // Add a new folder.
+ [controller setFolderName:@"middle"];
+ [controller ok:nil];
+
+ // Confirm we now have 3, and that the new one is in the middle.
+ EXPECT_EQ(3, parent->GetChildCount());
+ EXPECT_TRUE(parent->GetChild(1)->is_folder());
+ EXPECT_EQ(ASCIIToUTF16("middle"), parent->GetChild(1)->GetTitle());
+}
+
+// Make sure we are allowed to create a folder named "New Folder".
+TEST_F(BookmarkNameFolderControllerTest, AddNewDefaultName) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ EXPECT_EQ(0, parent->GetChildCount());
+
+ scoped_nsobject<BookmarkNameFolderController>
+ controller([[BookmarkNameFolderController alloc]
+ initWithParentWindow:test_window()
+ profile:helper_.profile()
+ parent:parent
+ newIndex:0]);
+
+ [controller window]; // force nib load
+
+ // Click OK without changing the name
+ [controller ok:nil];
+ EXPECT_EQ(1, parent->GetChildCount());
+ EXPECT_TRUE(parent->GetChild(0)->is_folder());
+}
+
+// Make sure we are allowed to create a folder with an empty name.
+TEST_F(BookmarkNameFolderControllerTest, AddNewBlankName) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ EXPECT_EQ(0, parent->GetChildCount());
+
+ scoped_nsobject<BookmarkNameFolderController>
+ controller([[BookmarkNameFolderController alloc]
+ initWithParentWindow:test_window()
+ profile:helper_.profile()
+ parent:parent
+ newIndex:0]);
+ [controller window]; // force nib load
+
+ // Change the name to blank, click OK.
+ [controller setFolderName:@""];
+ [controller ok:nil];
+ EXPECT_EQ(1, parent->GetChildCount());
+ EXPECT_TRUE(parent->GetChild(0)->is_folder());
+}
+
+TEST_F(BookmarkNameFolderControllerTest, Rename) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ const BookmarkNode* folder = model->AddGroup(parent,
+ parent->GetChildCount(),
+ ASCIIToUTF16("group"));
+
+ // Rename the folder by creating a controller that originates from
+ // the node.
+ scoped_nsobject<BookmarkNameFolderController>
+ controller([[BookmarkNameFolderController alloc]
+ initWithParentWindow:test_window()
+ profile:helper_.profile()
+ node:folder]);
+ [controller window]; // force nib load
+
+ EXPECT_NSEQ(@"group", [controller folderName]);
+ [controller setFolderName:@"Zobo"];
+ [controller ok:nil];
+ EXPECT_EQ(1, parent->GetChildCount());
+ EXPECT_TRUE(parent->GetChild(0)->is_folder());
+ EXPECT_EQ(ASCIIToUTF16("Zobo"), parent->GetChild(0)->GetTitle());
+}
+
+TEST_F(BookmarkNameFolderControllerTest, EditAndConfirmOKButton) {
+ BookmarkModel* model = helper_.profile()->GetBookmarkModel();
+ const BookmarkNode* parent = model->GetBookmarkBarNode();
+ EXPECT_EQ(0, parent->GetChildCount());
+
+ scoped_nsobject<BookmarkNameFolderController>
+ controller([[BookmarkNameFolderController alloc]
+ initWithParentWindow:test_window()
+ profile:helper_.profile()
+ parent:parent
+ newIndex:0]);
+ [controller window]; // force nib load
+
+ // We start enabled since the default "New Folder" is added for us.
+ EXPECT_TRUE([[controller okButton] isEnabled]);
+
+ [controller setFolderName:@"Bozo"];
+ EXPECT_TRUE([[controller okButton] isEnabled]);
+ [controller setFolderName:@" "];
+ EXPECT_TRUE([[controller okButton] isEnabled]);
+
+ [controller setFolderName:@""];
+ EXPECT_TRUE([[controller okButton] isEnabled]);
+}
+
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell.h
new file mode 100644
index 0000000..08b195d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell.h
@@ -0,0 +1,35 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_TREE_BROWSER_CELL_H_
+#define CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_TREE_BROWSER_CELL_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+class BookmarkNode;
+
+// Provides a custom cell as used in the BookmarkEditor.xib's folder tree
+// browser view. This cell customization adds target and action support
+// not provided by the NSBrowserCell as well as contextual information
+// identifying the bookmark node being edited and the column matrix
+// control in which is contained the cell.
+@interface BookmarkTreeBrowserCell : NSBrowserCell {
+ @private
+ const BookmarkNode* bookmarkNode_; // weak
+ NSMatrix* matrix_; // weak
+ id target_; // weak
+ SEL action_;
+}
+
+@property (nonatomic, assign) NSMatrix* matrix;
+@property (nonatomic, assign) id target;
+@property (nonatomic, assign) SEL action;
+
+- (const BookmarkNode*)bookmarkNode;
+- (void)setBookmarkNode:(const BookmarkNode*)bookmarkNode;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_BOOKMARKS_BOOKMARK_TREE_BROWSER_CELL_H_
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell.mm
new file mode 100644
index 0000000..6fe7e6e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell.mm
@@ -0,0 +1,23 @@
+// 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 "chrome/browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell.h"
+
+#include "chrome/browser/bookmarks/bookmark_model.h"
+
+@implementation BookmarkTreeBrowserCell
+
+@synthesize matrix = matrix_;
+@synthesize target = target_;
+@synthesize action = action_;
+
+- (const BookmarkNode*)bookmarkNode {
+ return bookmarkNode_;
+}
+
+- (void)setBookmarkNode:(const BookmarkNode*)bookmarkNode {
+ bookmarkNode_ = bookmarkNode;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell_unittest.mm
new file mode 100644
index 0000000..5171018
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell_unittest.mm
@@ -0,0 +1,43 @@
+// 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 "chrome/browser/bookmarks/bookmark_model.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/platform_test.h"
+
+class BookmarkTreeBrowserCellTest : public PlatformTest {
+ public:
+ BookmarkTreeBrowserCellTest() {
+ // Set up our mocks.
+ GURL gurl;
+ bookmarkNodeMock_.reset(new BookmarkNode(gurl));
+ matrixMock_.reset([[NSMatrix alloc] init]);
+ targetMock_.reset([[NSObject alloc] init]);
+ }
+
+ scoped_ptr<BookmarkNode> bookmarkNodeMock_;
+ scoped_nsobject<NSMatrix> matrixMock_;
+ scoped_nsobject<NSObject> targetMock_;
+};
+
+TEST_F(BookmarkTreeBrowserCellTest, BasicAllocDealloc) {
+ BookmarkTreeBrowserCell* cell = [[[BookmarkTreeBrowserCell alloc]
+ initTextCell:@"TEST STRING"] autorelease];
+ [cell setMatrix:matrixMock_.get()];
+ [cell setTarget:targetMock_.get()];
+ [cell setAction:@selector(mockAction:)];
+ [cell setBookmarkNode:bookmarkNodeMock_.get()];
+
+ NSMatrix* testMatrix = [cell matrix];
+ EXPECT_EQ(testMatrix, matrixMock_.get());
+ id testTarget = [cell target];
+ EXPECT_EQ(testTarget, targetMock_.get());
+ SEL testAction = [cell action];
+ EXPECT_EQ(testAction, @selector(mockAction:));
+ const BookmarkNode* testBookmarkNode = [cell bookmarkNode];
+ EXPECT_EQ(testBookmarkNode, bookmarkNodeMock_.get());
+}
diff --git a/chrome/browser/cocoa/browser_command_executor.h b/chrome/browser/ui/cocoa/browser_command_executor.h
index e6e01cf..e6e01cf 100644
--- a/chrome/browser/cocoa/browser_command_executor.h
+++ b/chrome/browser/ui/cocoa/browser_command_executor.h
diff --git a/chrome/browser/cocoa/browser_frame_view.h b/chrome/browser/ui/cocoa/browser_frame_view.h
index 42faa9b..42faa9b 100644
--- a/chrome/browser/cocoa/browser_frame_view.h
+++ b/chrome/browser/ui/cocoa/browser_frame_view.h
diff --git a/chrome/browser/ui/cocoa/browser_frame_view.mm b/chrome/browser/ui/cocoa/browser_frame_view.mm
new file mode 100644
index 0000000..a966785
--- /dev/null
+++ b/chrome/browser/ui/cocoa/browser_frame_view.mm
@@ -0,0 +1,399 @@
+// 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 "chrome/browser/ui/cocoa/browser_frame_view.h"
+
+#import <objc/runtime.h>
+#import <Carbon/Carbon.h>
+
+#include "base/logging.h"
+#include "base/mac/scoped_nsautorelease_pool.h"
+#import "chrome/browser/themes/browser_theme_provider.h"
+#import "chrome/browser/ui/cocoa/framed_browser_window.h"
+#import "chrome/browser/ui/cocoa/themed_window.h"
+#include "grit/theme_resources.h"
+
+static const CGFloat kBrowserFrameViewPaintHeight = 60.0;
+static const NSPoint kBrowserFrameViewPatternPhaseOffset = { -5, 3 };
+
+static BOOL gCanDrawTitle = NO;
+static BOOL gCanGetCornerRadius = NO;
+
+@interface NSView (Swizzles)
+- (void)drawRectOriginal:(NSRect)rect;
+- (BOOL)_mouseInGroup:(NSButton*)widget;
+- (void)updateTrackingAreas;
+- (NSUInteger)_shadowFlagsOriginal;
+@end
+
+// Undocumented APIs. They are really on NSGrayFrame rather than
+// BrowserFrameView, but we call them from methods swizzled onto NSGrayFrame.
+@interface BrowserFrameView (UndocumentedAPI)
+
+- (float)roundedCornerRadius;
+- (CGRect)_titlebarTitleRect;
+- (void)_drawTitleStringIn:(struct CGRect)arg1 withColor:(id)color;
+- (NSUInteger)_shadowFlags;
+
+@end
+
+@implementation BrowserFrameView
+
++ (void)load {
+ // This is where we swizzle drawRect, and add in two methods that we
+ // need. If any of these fail it shouldn't affect the functionality of the
+ // others. If they all fail, we will lose window frame theming and
+ // roll overs for our close widgets, but things should still function
+ // correctly.
+ base::mac::ScopedNSAutoreleasePool pool;
+ Class grayFrameClass = NSClassFromString(@"NSGrayFrame");
+ DCHECK(grayFrameClass);
+ if (!grayFrameClass) return;
+
+ // Exchange draw rect.
+ Method m0 = class_getInstanceMethod([self class], @selector(drawRect:));
+ DCHECK(m0);
+ if (m0) {
+ BOOL didAdd = class_addMethod(grayFrameClass,
+ @selector(drawRectOriginal:),
+ method_getImplementation(m0),
+ method_getTypeEncoding(m0));
+ DCHECK(didAdd);
+ if (didAdd) {
+ Method m1 = class_getInstanceMethod(grayFrameClass, @selector(drawRect:));
+ Method m2 = class_getInstanceMethod(grayFrameClass,
+ @selector(drawRectOriginal:));
+ DCHECK(m1 && m2);
+ if (m1 && m2) {
+ method_exchangeImplementations(m1, m2);
+ }
+ }
+ }
+
+ // Add _mouseInGroup.
+ m0 = class_getInstanceMethod([self class], @selector(_mouseInGroup:));
+ DCHECK(m0);
+ if (m0) {
+ BOOL didAdd = class_addMethod(grayFrameClass,
+ @selector(_mouseInGroup:),
+ method_getImplementation(m0),
+ method_getTypeEncoding(m0));
+ DCHECK(didAdd);
+ }
+ // Add updateTrackingArea.
+ m0 = class_getInstanceMethod([self class], @selector(updateTrackingAreas));
+ DCHECK(m0);
+ if (m0) {
+ BOOL didAdd = class_addMethod(grayFrameClass,
+ @selector(updateTrackingAreas),
+ method_getImplementation(m0),
+ method_getTypeEncoding(m0));
+ DCHECK(didAdd);
+ }
+
+ gCanDrawTitle =
+ [grayFrameClass
+ instancesRespondToSelector:@selector(_titlebarTitleRect)] &&
+ [grayFrameClass
+ instancesRespondToSelector:@selector(_drawTitleStringIn:withColor:)];
+ gCanGetCornerRadius =
+ [grayFrameClass
+ instancesRespondToSelector:@selector(roundedCornerRadius)];
+
+ // Add _shadowFlags. This is a method on NSThemeFrame, not on NSGrayFrame.
+ // NSThemeFrame is NSGrayFrame's superclass.
+ Class themeFrameClass = NSClassFromString(@"NSThemeFrame");
+ DCHECK(themeFrameClass);
+ if (!themeFrameClass) return;
+ m0 = class_getInstanceMethod([self class], @selector(_shadowFlags));
+ DCHECK(m0);
+ if (m0) {
+ BOOL didAdd = class_addMethod(themeFrameClass,
+ @selector(_shadowFlagsOriginal),
+ method_getImplementation(m0),
+ method_getTypeEncoding(m0));
+ DCHECK(didAdd);
+ if (didAdd) {
+ Method m1 = class_getInstanceMethod(themeFrameClass,
+ @selector(_shadowFlags));
+ Method m2 = class_getInstanceMethod(themeFrameClass,
+ @selector(_shadowFlagsOriginal));
+ DCHECK(m1 && m2);
+ if (m1 && m2) {
+ method_exchangeImplementations(m1, m2);
+ }
+ }
+ }
+}
+
+- (id)initWithFrame:(NSRect)frame {
+ // This class is not for instantiating.
+ [self doesNotRecognizeSelector:_cmd];
+ return nil;
+}
+
+- (id)initWithCoder:(NSCoder*)coder {
+ // This class is not for instantiating.
+ [self doesNotRecognizeSelector:_cmd];
+ return nil;
+}
+
+// Here is our custom drawing for our frame.
+- (void)drawRect:(NSRect)rect {
+ // If this isn't the window class we expect, then pass it on to the
+ // original implementation.
+ if (![[self window] isKindOfClass:[FramedBrowserWindow class]]) {
+ [self drawRectOriginal:rect];
+ return;
+ }
+
+ // WARNING: There is an obvious optimization opportunity here that you DO NOT
+ // want to take. To save painting cycles, you might think it would be a good
+ // idea to call out to -drawRectOriginal: only if no theme were drawn. In
+ // reality, however, if you fail to call -drawRectOriginal:, or if you call it
+ // after a clipping path is set, the rounded corners at the top of the window
+ // will not draw properly. Do not try to be smart here.
+
+ // Only paint the top of the window.
+ NSWindow* window = [self window];
+ NSRect windowRect = [self convertRect:[window frame] fromView:nil];
+ windowRect.origin = NSMakePoint(0, 0);
+
+ NSRect paintRect = windowRect;
+ paintRect.origin.y = NSMaxY(paintRect) - kBrowserFrameViewPaintHeight;
+ paintRect.size.height = kBrowserFrameViewPaintHeight;
+ rect = NSIntersectionRect(paintRect, rect);
+ [self drawRectOriginal:rect];
+
+ // Set up our clip.
+ float cornerRadius = 4.0;
+ if (gCanGetCornerRadius)
+ cornerRadius = [self roundedCornerRadius];
+ [[NSBezierPath bezierPathWithRoundedRect:windowRect
+ xRadius:cornerRadius
+ yRadius:cornerRadius] addClip];
+ [[NSBezierPath bezierPathWithRect:rect] addClip];
+
+ // Do the theming.
+ BOOL themed = [BrowserFrameView drawWindowThemeInDirtyRect:rect
+ forView:self
+ bounds:windowRect
+ offset:NSZeroPoint
+ forceBlackBackground:NO];
+
+ // If the window needs a title and we painted over the title as drawn by the
+ // default window paint, paint it ourselves.
+ if (themed && gCanDrawTitle && ![[self window] _isTitleHidden]) {
+ [self _drawTitleStringIn:[self _titlebarTitleRect]
+ withColor:[BrowserFrameView titleColorForThemeView:self]];
+ }
+
+ // Pinstripe the top.
+ if (themed) {
+ NSSize windowPixel = [self convertSizeFromBase:NSMakeSize(1, 1)];
+
+ windowRect = [self convertRect:[window frame] fromView:nil];
+ windowRect.origin = NSMakePoint(0, 0);
+ windowRect.origin.y -= 0.5 * windowPixel.height;
+ windowRect.origin.x -= 0.5 * windowPixel.width;
+ windowRect.size.width += windowPixel.width;
+ [[NSColor colorWithCalibratedWhite:1.0 alpha:0.5] set];
+ NSBezierPath* path = [NSBezierPath bezierPathWithRoundedRect:windowRect
+ xRadius:cornerRadius
+ yRadius:cornerRadius];
+ [path setLineWidth:windowPixel.width];
+ [path stroke];
+ }
+}
+
++ (BOOL)drawWindowThemeInDirtyRect:(NSRect)dirtyRect
+ forView:(NSView*)view
+ bounds:(NSRect)bounds
+ offset:(NSPoint)offset
+ forceBlackBackground:(BOOL)forceBlackBackground {
+ ThemeProvider* themeProvider = [[view window] themeProvider];
+ if (!themeProvider)
+ return NO;
+
+ ThemedWindowStyle windowStyle = [[view window] themedWindowStyle];
+
+ // Devtools windows don't get themed.
+ if (windowStyle & THEMED_DEVTOOLS)
+ return NO;
+
+ BOOL active = [[view window] isMainWindow];
+ BOOL incognito = windowStyle & THEMED_INCOGNITO;
+ BOOL popup = windowStyle & THEMED_POPUP;
+
+ // Find a theme image.
+ NSColor* themeImageColor = nil;
+ int themeImageID;
+ if (popup && active)
+ themeImageID = IDR_THEME_TOOLBAR;
+ else if (popup && !active)
+ themeImageID = IDR_THEME_TAB_BACKGROUND;
+ else if (!popup && active && incognito)
+ themeImageID = IDR_THEME_FRAME_INCOGNITO;
+ else if (!popup && active && !incognito)
+ themeImageID = IDR_THEME_FRAME;
+ else if (!popup && !active && incognito)
+ themeImageID = IDR_THEME_FRAME_INCOGNITO_INACTIVE;
+ else
+ themeImageID = IDR_THEME_FRAME_INACTIVE;
+ if (themeProvider->HasCustomImage(IDR_THEME_FRAME))
+ themeImageColor = themeProvider->GetNSImageColorNamed(themeImageID, true);
+
+ // If no theme image, use a gradient if incognito.
+ NSGradient* gradient = nil;
+ if (!themeImageColor && incognito)
+ gradient = themeProvider->GetNSGradient(
+ active ? BrowserThemeProvider::GRADIENT_FRAME_INCOGNITO :
+ BrowserThemeProvider::GRADIENT_FRAME_INCOGNITO_INACTIVE);
+
+ BOOL themed = NO;
+ if (themeImageColor) {
+ // The titlebar/tabstrip header on the mac is slightly smaller than on
+ // Windows. To keep the window background lined up with the tab and toolbar
+ // patterns, we have to shift the pattern slightly, rather than simply
+ // drawing it from the top left corner. The offset below was empirically
+ // determined in order to line these patterns up.
+ //
+ // This will make the themes look slightly different than in Windows/Linux
+ // because of the differing heights between window top and tab top, but this
+ // has been approved by UI.
+ NSView* frameView = [[[view window] contentView] superview];
+ NSPoint topLeft = NSMakePoint(NSMinX(bounds), NSMaxY(bounds));
+ NSPoint topLeftInFrameCoordinates =
+ [view convertPoint:topLeft toView:frameView];
+
+ NSPoint phase = kBrowserFrameViewPatternPhaseOffset;
+ phase.x += (offset.x + topLeftInFrameCoordinates.x);
+ phase.y += (offset.y + topLeftInFrameCoordinates.y);
+
+ // Align the phase to physical pixels so resizing the window under HiDPI
+ // doesn't cause wiggling of the theme.
+ phase = [frameView convertPointToBase:phase];
+ phase.x = floor(phase.x);
+ phase.y = floor(phase.y);
+ phase = [frameView convertPointFromBase:phase];
+
+ // Default to replacing any existing pixels with the theme image, but if
+ // asked paint black first and blend the theme with black.
+ NSCompositingOperation operation = NSCompositeCopy;
+ if (forceBlackBackground) {
+ [[NSColor blackColor] set];
+ NSRectFill(dirtyRect);
+ operation = NSCompositeSourceOver;
+ }
+
+ [[NSGraphicsContext currentContext] setPatternPhase:phase];
+ [themeImageColor set];
+ NSRectFillUsingOperation(dirtyRect, operation);
+ themed = YES;
+ } else if (gradient) {
+ NSPoint startPoint = NSMakePoint(NSMinX(bounds), NSMaxY(bounds));
+ NSPoint endPoint = startPoint;
+ endPoint.y -= kBrowserFrameViewPaintHeight;
+ [gradient drawFromPoint:startPoint toPoint:endPoint options:0];
+ themed = YES;
+ }
+
+ // Check to see if we have an overlay image.
+ NSImage* overlayImage = nil;
+ if (themeProvider->HasCustomImage(IDR_THEME_FRAME_OVERLAY)) {
+ overlayImage = themeProvider->
+ GetNSImageNamed(active ? IDR_THEME_FRAME_OVERLAY :
+ IDR_THEME_FRAME_OVERLAY_INACTIVE,
+ true);
+ }
+
+ if (overlayImage) {
+ // Anchor to top-left and don't scale.
+ NSSize overlaySize = [overlayImage size];
+ NSRect imageFrame = NSMakeRect(0, 0, overlaySize.width, overlaySize.height);
+ [overlayImage drawAtPoint:NSMakePoint(offset.x,
+ NSHeight(bounds) + offset.y -
+ overlaySize.height)
+ fromRect:imageFrame
+ operation:NSCompositeSourceOver
+ fraction:1.0];
+ }
+
+ return themed;
+}
+
++ (NSColor*)titleColorForThemeView:(NSView*)view {
+ ThemeProvider* themeProvider = [[view window] themeProvider];
+ if (!themeProvider)
+ return [NSColor windowFrameTextColor];
+
+ ThemedWindowStyle windowStyle = [[view window] themedWindowStyle];
+ BOOL active = [[view window] isMainWindow];
+ BOOL incognito = windowStyle & THEMED_INCOGNITO;
+ BOOL popup = windowStyle & THEMED_POPUP;
+
+ NSColor* titleColor = nil;
+ if (popup && active) {
+ titleColor = themeProvider->GetNSColor(
+ BrowserThemeProvider::COLOR_TAB_TEXT, false);
+ } else if (popup && !active) {
+ titleColor = themeProvider->GetNSColor(
+ BrowserThemeProvider::COLOR_BACKGROUND_TAB_TEXT, false);
+ }
+
+ if (titleColor)
+ return titleColor;
+
+ if (incognito)
+ return [NSColor whiteColor];
+ else
+ return [NSColor windowFrameTextColor];
+}
+
+// Check to see if the mouse is currently in one of our window widgets.
+- (BOOL)_mouseInGroup:(NSButton*)widget {
+ BOOL mouseInGroup = NO;
+ if ([[self window] isKindOfClass:[FramedBrowserWindow class]]) {
+ FramedBrowserWindow* window =
+ static_cast<FramedBrowserWindow*>([self window]);
+ mouseInGroup = [window mouseInGroup:widget];
+ } else if ([super respondsToSelector:@selector(_mouseInGroup:)]) {
+ mouseInGroup = [super _mouseInGroup:widget];
+ }
+ return mouseInGroup;
+}
+
+// Let our window handle updating the window widget tracking area.
+- (void)updateTrackingAreas {
+ [super updateTrackingAreas];
+ if ([[self window] isKindOfClass:[FramedBrowserWindow class]]) {
+ FramedBrowserWindow* window =
+ static_cast<FramedBrowserWindow*>([self window]);
+ [window updateTrackingAreas];
+ }
+}
+
+// When the compositor is active, the whole content area is transparent (with
+// an OpenGL surface behind it), so Cocoa draws the shadow only around the
+// toolbar area.
+// Tell the window server that we want a shadow as if none of the content
+// area is transparent.
+- (NSUInteger)_shadowFlags {
+ // A slightly less intrusive hack would be to call
+ // _setContentHasShadow:NO on the window. That seems to be what Terminal.app
+ // is doing. However, it leads to this function returning 'code | 64', which
+ // doesn't do what we want. For some reason, it does the right thing in
+ // Terminal.app.
+ // TODO(thakis): Figure out why -_setContentHasShadow: works in Terminal.app
+ // and use that technique instead. http://crbug.com/53382
+
+ // If this isn't the window class we expect, then pass it on to the
+ // original implementation.
+ if (![[self window] isKindOfClass:[FramedBrowserWindow class]])
+ return [self _shadowFlagsOriginal];
+
+ return [self _shadowFlagsOriginal] | 128;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/browser_frame_view_unittest.mm b/chrome/browser/ui/cocoa/browser_frame_view_unittest.mm
new file mode 100644
index 0000000..ca2de67
--- /dev/null
+++ b/chrome/browser/ui/cocoa/browser_frame_view_unittest.mm
@@ -0,0 +1,48 @@
+// Copyright (c) 2009 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 <objc/runtime.h>
+
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/browser_frame_view.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+class BrowserFrameViewTest : public PlatformTest {
+ public:
+ BrowserFrameViewTest() {
+ NSRect frame = NSMakeRect(0, 0, 50, 50);
+ // We create NSGrayFrame instead of BrowserFrameView because
+ // we are swizzling into NSGrayFrame.
+ Class browserFrameClass = NSClassFromString(@"NSGrayFrame");
+ view_.reset([[browserFrameClass alloc] initWithFrame:frame]);
+ }
+
+ scoped_nsobject<NSView> view_;
+};
+
+// Test to make sure our class modifications were successful.
+TEST_F(BrowserFrameViewTest, SuccessfulClassModifications) {
+ unsigned int count;
+ BOOL foundMouseInGroup = NO;
+ BOOL foundDrawRectOriginal = NO;
+ BOOL foundUpdateTrackingAreas = NO;
+
+ Method* methods = class_copyMethodList([view_ class], &count);
+ for (unsigned int i = 0; i < count; ++i) {
+ SEL selector = method_getName(methods[i]);
+ if (selector == @selector(_mouseInGroup:)) {
+ foundMouseInGroup = YES;
+ } else if (selector == @selector(drawRectOriginal:)) {
+ foundDrawRectOriginal = YES;
+ } else if (selector == @selector(updateTrackingAreas)) {
+ foundUpdateTrackingAreas = YES;
+ }
+ }
+ EXPECT_TRUE(foundMouseInGroup);
+ EXPECT_TRUE(foundDrawRectOriginal);
+ EXPECT_TRUE(foundUpdateTrackingAreas);
+ free(methods);
+}
diff --git a/chrome/browser/ui/cocoa/browser_test_helper.h b/chrome/browser/ui/cocoa/browser_test_helper.h
new file mode 100644
index 0000000..44cde96
--- /dev/null
+++ b/chrome/browser/ui/cocoa/browser_test_helper.h
@@ -0,0 +1,91 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_BROWSER_TEST_HELPER_H_
+#define CHROME_BROWSER_UI_COCOA_BROWSER_TEST_HELPER_H_
+#pragma once
+
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/testing_profile.h"
+
+// Base class which contains a valid Browser*. Lots of boilerplate to
+// recycle between unit test classes.
+//
+// This class creates fake UI, file, and IO threads because many objects that
+// are attached to the TestingProfile (and other objects) have traits that limit
+// their destruction to certain threads. For example, the URLRequestContext can
+// only be deleted on the IO thread; without this fake IO thread, the object
+// would never be deleted and would report as a leak under Valgrind. Note that
+// these are fake threads and they all share the same MessageLoop.
+//
+// TODO(jrg): move up a level (chrome/browser/ui/cocoa -->
+// chrome/browser), and use in non-Mac unit tests such as
+// back_forward_menu_model_unittest.cc,
+// navigation_controller_unittest.cc, ..
+class BrowserTestHelper {
+ public:
+ BrowserTestHelper()
+ : ui_thread_(BrowserThread::UI, &message_loop_),
+ file_thread_(new BrowserThread(BrowserThread::FILE, &message_loop_)),
+ io_thread_(new BrowserThread(BrowserThread::IO, &message_loop_)) {
+ profile_.reset(new TestingProfile());
+ profile_->CreateBookmarkModel(true);
+ profile_->BlockUntilBookmarkModelLoaded();
+
+ // TODO(shess): These are needed in case someone creates a browser
+ // window off of browser_. pkasting indicates that other
+ // platforms use a stub |BrowserWindow| and thus don't need to do
+ // this.
+ // http://crbug.com/39725
+ profile_->CreateAutocompleteClassifier();
+ profile_->CreateTemplateURLModel();
+
+ browser_.reset(new Browser(Browser::TYPE_NORMAL, profile_.get()));
+ }
+
+ virtual ~BrowserTestHelper() {
+ // Delete the testing profile on the UI thread. But first release the
+ // browser, since it may trigger accesses to the profile upon destruction.
+ browser_.reset();
+
+ // Drop any new tasks for the IO and FILE threads.
+ io_thread_.reset();
+ file_thread_.reset();
+
+ message_loop_.DeleteSoon(FROM_HERE, profile_.release());
+ message_loop_.RunAllPending();
+ }
+
+ virtual TestingProfile* profile() const { return profile_.get(); }
+ Browser* browser() const { return browser_.get(); }
+
+ // Creates the browser window. To close this window call |CloseBrowserWindow|.
+ // Do NOT call close directly on the window.
+ BrowserWindow* CreateBrowserWindow() {
+ browser_->CreateBrowserWindow();
+ return browser_->window();
+ }
+
+ // Closes the window for this browser. This must only be called after
+ // CreateBrowserWindow().
+ void CloseBrowserWindow() {
+ // Check to make sure a window was actually created.
+ DCHECK(browser_->window());
+ browser_->CloseAllTabs();
+ browser_->CloseWindow();
+ // |browser_| will be deleted by its BrowserWindowController.
+ ignore_result(browser_.release());
+ }
+
+ private:
+ scoped_ptr<TestingProfile> profile_;
+ scoped_ptr<Browser> browser_;
+ MessageLoopForUI message_loop_;
+ BrowserThread ui_thread_;
+ scoped_ptr<BrowserThread> file_thread_;
+ scoped_ptr<BrowserThread> io_thread_;
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_BROWSER_TEST_HELPER_H_
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.h b/chrome/browser/ui/cocoa/browser_window_cocoa.h
new file mode 100644
index 0000000..d41afc1
--- /dev/null
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.h
@@ -0,0 +1,144 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_BROWSER_WINDOW_COCOA_H_
+#define CHROME_BROWSER_UI_COCOA_BROWSER_WINDOW_COCOA_H_
+#pragma once
+
+#include "base/scoped_nsobject.h"
+#include "base/task.h"
+#include "chrome/browser/browser_window.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/common/notification_registrar.h"
+
+class Browser;
+@class BrowserWindowController;
+@class FindBarCocoaController;
+@class NSEvent;
+@class NSMenu;
+@class NSWindow;
+
+// An implementation of BrowserWindow for Cocoa. Bridges between C++ and
+// the Cocoa NSWindow. Cross-platform code will interact with this object when
+// it needs to manipulate the window.
+
+class BrowserWindowCocoa : public BrowserWindow,
+ public NotificationObserver {
+ public:
+ BrowserWindowCocoa(Browser* browser,
+ BrowserWindowController* controller,
+ NSWindow* window);
+ virtual ~BrowserWindowCocoa();
+
+ // Overridden from BrowserWindow
+ virtual void Show();
+ virtual void SetBounds(const gfx::Rect& bounds);
+ virtual void Close();
+ virtual void Activate();
+ virtual void Deactivate();
+ virtual bool IsActive() const;
+ virtual void FlashFrame();
+ virtual gfx::NativeWindow GetNativeHandle();
+ virtual BrowserWindowTesting* GetBrowserWindowTesting();
+ virtual StatusBubble* GetStatusBubble();
+ virtual void SelectedTabToolbarSizeChanged(bool is_animating);
+ virtual void UpdateTitleBar();
+ virtual void ShelfVisibilityChanged();
+ virtual void UpdateDevTools();
+ virtual void UpdateLoadingAnimations(bool should_animate);
+ virtual void SetStarredState(bool is_starred);
+ virtual gfx::Rect GetRestoredBounds() const;
+ virtual bool IsMaximized() const;
+ virtual void SetFullscreen(bool fullscreen);
+ virtual bool IsFullscreen() const;
+ virtual bool IsFullscreenBubbleVisible() const;
+ virtual LocationBar* GetLocationBar() const;
+ virtual void SetFocusToLocationBar(bool select_all);
+ virtual void UpdateReloadStopState(bool is_loading, bool force);
+ virtual void UpdateToolbar(TabContentsWrapper* contents,
+ bool should_restore_state);
+ virtual void FocusToolbar();
+ virtual void FocusAppMenu();
+ virtual void FocusBookmarksToolbar();
+ virtual void FocusChromeOSStatus();
+ virtual void RotatePaneFocus(bool forwards);
+ virtual bool IsBookmarkBarVisible() const;
+ virtual bool IsBookmarkBarAnimating() const;
+ virtual bool IsTabStripEditable() const;
+ virtual bool IsToolbarVisible() const;
+ virtual void ConfirmAddSearchProvider(const TemplateURL* template_url,
+ Profile* profile);
+ virtual void ToggleBookmarkBar();
+ virtual views::Window* ShowAboutChromeDialog();
+ virtual void ShowUpdateChromeDialog();
+ virtual void ShowTaskManager();
+ virtual void ShowBookmarkBubble(const GURL& url, bool already_bookmarked);
+ virtual bool IsDownloadShelfVisible() const;
+ virtual DownloadShelf* GetDownloadShelf();
+ virtual void ShowReportBugDialog();
+ virtual void ShowClearBrowsingDataDialog();
+ virtual void ShowImportDialog();
+ virtual void ShowSearchEnginesDialog();
+ virtual void ShowPasswordManager();
+ virtual void ShowRepostFormWarningDialog(TabContents* tab_contents);
+ virtual void ShowContentSettingsWindow(ContentSettingsType content_type,
+ Profile* profile);
+ virtual void ShowCollectedCookiesDialog(TabContents* tab_contents);
+ virtual void ShowProfileErrorDialog(int message_id);
+ virtual void ShowThemeInstallBubble();
+ virtual void ConfirmBrowserCloseWithPendingDownloads();
+ virtual void ShowHTMLDialog(HtmlDialogUIDelegate* delegate,
+ gfx::NativeWindow parent_window);
+ virtual void UserChangedTheme();
+ virtual int GetExtraRenderViewHeight() const;
+ virtual void TabContentsFocused(TabContents* tab_contents);
+ virtual void ShowPageInfo(Profile* profile,
+ const GURL& url,
+ const NavigationEntry::SSLStatus& ssl,
+ bool show_history);
+ virtual void ShowAppMenu();
+ virtual bool PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
+ bool* is_keyboard_shortcut);
+ virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event);
+ virtual void ShowCreateWebAppShortcutsDialog(TabContents* tab_contents);
+ virtual void ShowCreateChromeAppShortcutsDialog(Profile* profile,
+ const Extension* app);
+ virtual void Cut();
+ virtual void Copy();
+ virtual void Paste();
+ virtual void ToggleTabStripMode();
+ virtual void OpenTabpose();
+ virtual void PrepareForInstant();
+ virtual void ShowInstant(TabContents* preview_contents);
+ virtual void HideInstant(bool instant_is_active);
+ virtual gfx::Rect GetInstantBounds();
+
+ // Overridden from NotificationObserver
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // Adds the given FindBar cocoa controller to this browser window.
+ void AddFindBar(FindBarCocoaController* find_bar_cocoa_controller);
+
+ // Returns the cocoa-world BrowserWindowController
+ BrowserWindowController* cocoa_controller() { return controller_; }
+
+ protected:
+ virtual void DestroyBrowser();
+
+ private:
+ int GetCommandId(const NativeWebKeyboardEvent& event);
+ bool HandleKeyboardEventInternal(NSEvent* event);
+ NSWindow* window() const; // Accessor for the (current) |NSWindow|.
+ void UpdateSidebarForContents(TabContents* tab_contents);
+
+ NotificationRegistrar registrar_;
+ Browser* browser_; // weak, owned by controller
+ BrowserWindowController* controller_; // weak, owns us
+ ScopedRunnableMethodFactory<Browser> confirm_close_factory_;
+ scoped_nsobject<NSString> pending_window_title_;
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_BROWSER_WINDOW_COCOA_H_
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.mm b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
new file mode 100644
index 0000000..1d3f512
--- /dev/null
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
@@ -0,0 +1,644 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/browser_window_cocoa.h"
+
+#include "app/l10n_util_mac.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/bookmarks/bookmark_utils.h"
+#include "chrome/browser/download/download_shelf.h"
+#include "chrome/browser/global_keyboard_shortcuts_mac.h"
+#include "chrome/browser/page_info_window.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sidebar/sidebar_container.h"
+#include "chrome/browser/sidebar/sidebar_manager.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "chrome/browser/ui/cocoa/bug_report_window_controller.h"
+#import "chrome/browser/ui/cocoa/chrome_event_processing_window.h"
+#import "chrome/browser/ui/cocoa/clear_browsing_data_controller.h"
+#import "chrome/browser/ui/cocoa/collected_cookies_mac.h"
+#import "chrome/browser/ui/cocoa/content_settings_dialog_controller.h"
+#import "chrome/browser/ui/cocoa/download/download_shelf_controller.h"
+#import "chrome/browser/ui/cocoa/edit_search_engine_cocoa_controller.h"
+#import "chrome/browser/ui/cocoa/html_dialog_window_controller.h"
+#import "chrome/browser/ui/cocoa/import_settings_dialog.h"
+#import "chrome/browser/ui/cocoa/keyword_editor_cocoa_controller.h"
+#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
+#import "chrome/browser/ui/cocoa/nsmenuitem_additions.h"
+#include "chrome/browser/ui/cocoa/repost_form_warning_mac.h"
+#include "chrome/browser/ui/cocoa/restart_browser.h"
+#include "chrome/browser/ui/cocoa/status_bubble_mac.h"
+#include "chrome/browser/ui/cocoa/task_manager_mac.h"
+#import "chrome/browser/ui/cocoa/theme_install_bubble_view.h"
+#import "chrome/browser/ui/cocoa/toolbar_controller.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/native_web_keyboard_event.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/pref_names.h"
+#include "gfx/rect.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+
+BrowserWindowCocoa::BrowserWindowCocoa(Browser* browser,
+ BrowserWindowController* controller,
+ NSWindow* window)
+ : browser_(browser),
+ controller_(controller),
+ confirm_close_factory_(browser) {
+ // This pref applies to all windows, so all must watch for it.
+ registrar_.Add(this, NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED,
+ NotificationService::AllSources());
+ registrar_.Add(this, NotificationType::SIDEBAR_CHANGED,
+ NotificationService::AllSources());
+}
+
+BrowserWindowCocoa::~BrowserWindowCocoa() {
+}
+
+void BrowserWindowCocoa::Show() {
+ // The Browser associated with this browser window must become the active
+ // browser at the time |Show()| is called. This is the natural behaviour under
+ // Windows, but |-makeKeyAndOrderFront:| won't send |-windowDidBecomeMain:|
+ // until we return to the runloop. Therefore any calls to
+ // |BrowserList::GetLastActive()| (for example, in bookmark_util), will return
+ // the previous browser instead if we don't explicitly set it here.
+ BrowserList::SetLastActive(browser_);
+
+ [window() makeKeyAndOrderFront:controller_];
+}
+
+void BrowserWindowCocoa::SetBounds(const gfx::Rect& bounds) {
+ NSRect cocoa_bounds = NSMakeRect(bounds.x(), 0, bounds.width(),
+ bounds.height());
+ // Flip coordinates based on the primary screen.
+ NSScreen* screen = [[NSScreen screens] objectAtIndex:0];
+ cocoa_bounds.origin.y =
+ [screen frame].size.height - bounds.height() - bounds.y();
+
+ [window() setFrame:cocoa_bounds display:YES];
+}
+
+// Callers assume that this doesn't immediately delete the Browser object.
+// The controller implementing the window delegate methods called from
+// |-performClose:| must take precautions to ensure that.
+void BrowserWindowCocoa::Close() {
+ // If there is an overlay window, we contain a tab being dragged between
+ // windows. Don't hide the window as it makes the UI extra confused. We can
+ // still close the window, as that will happen when the drag completes.
+ if ([controller_ overlayWindow]) {
+ [controller_ deferPerformClose];
+ } else {
+ // Make sure we hide the window immediately. Even though performClose:
+ // calls orderOut: eventually, it leaves the window on-screen long enough
+ // that we start to see tabs shutting down. http://crbug.com/23959
+ // TODO(viettrungluu): This is kind of bad, since |-performClose:| calls
+ // |-windowShouldClose:| (on its delegate, which is probably the
+ // controller) which may return |NO| causing the window to not be closed,
+ // thereby leaving a hidden window. In fact, our window-closing procedure
+ // involves a (indirect) recursion on |-performClose:|, which is also bad.
+ [window() orderOut:controller_];
+ [window() performClose:controller_];
+ }
+}
+
+void BrowserWindowCocoa::Activate() {
+ [controller_ activate];
+}
+
+void BrowserWindowCocoa::Deactivate() {
+ // TODO(jcivelli): http://crbug.com/51364 Implement me.
+ NOTIMPLEMENTED();
+}
+
+void BrowserWindowCocoa::FlashFrame() {
+ [NSApp requestUserAttention:NSInformationalRequest];
+}
+
+bool BrowserWindowCocoa::IsActive() const {
+ return [window() isKeyWindow];
+}
+
+gfx::NativeWindow BrowserWindowCocoa::GetNativeHandle() {
+ return window();
+}
+
+BrowserWindowTesting* BrowserWindowCocoa::GetBrowserWindowTesting() {
+ return NULL;
+}
+
+StatusBubble* BrowserWindowCocoa::GetStatusBubble() {
+ return [controller_ statusBubble];
+}
+
+void BrowserWindowCocoa::SelectedTabToolbarSizeChanged(bool is_animating) {
+ // According to beng, this is an ugly method that comes from the days when the
+ // download shelf was a ChromeView attached to the TabContents, and as its
+ // size changed via animation it notified through TCD/etc to the browser view
+ // to relayout for each tick of the animation. We don't need anything of the
+ // sort on Mac.
+}
+
+void BrowserWindowCocoa::UpdateTitleBar() {
+ NSString* newTitle =
+ base::SysUTF16ToNSString(browser_->GetWindowTitleForCurrentTab());
+
+ // Work around Cocoa bug: if a window changes title during the tracking of the
+ // Window menu it doesn't display well and the constant re-sorting of the list
+ // makes it difficult for the user to pick the desired window. Delay window
+ // title updates until the default run-loop mode.
+
+ if (pending_window_title_.get())
+ [[NSRunLoop currentRunLoop]
+ cancelPerformSelector:@selector(setTitle:)
+ target:window()
+ argument:pending_window_title_.get()];
+
+ pending_window_title_.reset([newTitle copy]);
+ [[NSRunLoop currentRunLoop]
+ performSelector:@selector(setTitle:)
+ target:window()
+ argument:newTitle
+ order:0
+ modes:[NSArray arrayWithObject:NSDefaultRunLoopMode]];
+}
+
+void BrowserWindowCocoa::ShelfVisibilityChanged() {
+ // Mac doesn't yet support showing the bookmark bar at a different size on
+ // the new tab page. When it does, this method should attempt to relayout the
+ // bookmark bar/extension shelf as their preferred height may have changed.
+ // http://crbug.com/43346
+}
+
+void BrowserWindowCocoa::UpdateDevTools() {
+ [controller_ updateDevToolsForContents:
+ browser_->GetSelectedTabContents()];
+}
+
+void BrowserWindowCocoa::UpdateLoadingAnimations(bool should_animate) {
+ // Do nothing on Mac.
+}
+
+void BrowserWindowCocoa::SetStarredState(bool is_starred) {
+ [controller_ setStarredState:is_starred ? YES : NO];
+}
+
+gfx::Rect BrowserWindowCocoa::GetRestoredBounds() const {
+ // Flip coordinates based on the primary screen.
+ NSScreen* screen = [[NSScreen screens] objectAtIndex:0];
+ NSRect frame = [controller_ regularWindowFrame];
+ gfx::Rect bounds(frame.origin.x, 0, frame.size.width, frame.size.height);
+ bounds.set_y([screen frame].size.height - frame.origin.y - frame.size.height);
+ return bounds;
+}
+
+bool BrowserWindowCocoa::IsMaximized() const {
+ return [window() isZoomed];
+}
+
+void BrowserWindowCocoa::SetFullscreen(bool fullscreen) {
+ [controller_ setFullscreen:fullscreen];
+}
+
+bool BrowserWindowCocoa::IsFullscreen() const {
+ return !![controller_ isFullscreen];
+}
+
+bool BrowserWindowCocoa::IsFullscreenBubbleVisible() const {
+ return false;
+}
+
+void BrowserWindowCocoa::ConfirmAddSearchProvider(
+ const TemplateURL* template_url,
+ Profile* profile) {
+ // The controller will release itself when the window closes.
+ EditSearchEngineCocoaController* editor =
+ [[EditSearchEngineCocoaController alloc] initWithProfile:profile
+ delegate:NULL
+ templateURL:template_url];
+ [NSApp beginSheet:[editor window]
+ modalForWindow:window()
+ modalDelegate:controller_
+ didEndSelector:@selector(sheetDidEnd:returnCode:context:)
+ contextInfo:NULL];
+}
+
+LocationBar* BrowserWindowCocoa::GetLocationBar() const {
+ return [controller_ locationBarBridge];
+}
+
+void BrowserWindowCocoa::SetFocusToLocationBar(bool select_all) {
+ [controller_ focusLocationBar:select_all ? YES : NO];
+}
+
+void BrowserWindowCocoa::UpdateReloadStopState(bool is_loading, bool force) {
+ [controller_ setIsLoading:is_loading force:force];
+}
+
+void BrowserWindowCocoa::UpdateToolbar(TabContentsWrapper* contents,
+ bool should_restore_state) {
+ [controller_ updateToolbarWithContents:contents->tab_contents()
+ shouldRestoreState:should_restore_state ? YES : NO];
+}
+
+void BrowserWindowCocoa::FocusToolbar() {
+ // Not needed on the Mac.
+}
+
+void BrowserWindowCocoa::FocusAppMenu() {
+ // Chrome uses the standard Mac OS X menu bar, so this isn't needed.
+}
+
+void BrowserWindowCocoa::RotatePaneFocus(bool forwards) {
+ // Not needed on the Mac.
+}
+
+void BrowserWindowCocoa::FocusBookmarksToolbar() {
+ // Not needed on the Mac.
+}
+
+void BrowserWindowCocoa::FocusChromeOSStatus() {
+ // Not needed on the Mac.
+}
+
+bool BrowserWindowCocoa::IsBookmarkBarVisible() const {
+ return browser_->profile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar);
+}
+
+bool BrowserWindowCocoa::IsBookmarkBarAnimating() const {
+ return [controller_ isBookmarkBarAnimating];
+}
+
+bool BrowserWindowCocoa::IsTabStripEditable() const {
+ return ![controller_ isDragSessionActive];
+}
+
+bool BrowserWindowCocoa::IsToolbarVisible() const {
+ return browser_->SupportsWindowFeature(Browser::FEATURE_TOOLBAR) ||
+ browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR);
+}
+
+// This is called from Browser, which in turn is called directly from
+// a menu option. All we do here is set a preference. The act of
+// setting the preference sends notifications to all windows who then
+// know what to do.
+void BrowserWindowCocoa::ToggleBookmarkBar() {
+ bookmark_utils::ToggleWhenVisible(browser_->profile());
+}
+
+void BrowserWindowCocoa::AddFindBar(
+ FindBarCocoaController* find_bar_cocoa_controller) {
+ return [controller_ addFindBar:find_bar_cocoa_controller];
+}
+
+views::Window* BrowserWindowCocoa::ShowAboutChromeDialog() {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+void BrowserWindowCocoa::ShowUpdateChromeDialog() {
+ restart_browser::RequestRestart(nil);
+}
+
+void BrowserWindowCocoa::ShowTaskManager() {
+ TaskManagerMac::Show();
+}
+
+void BrowserWindowCocoa::ShowBookmarkBubble(const GURL& url,
+ bool already_bookmarked) {
+ [controller_ showBookmarkBubbleForURL:url
+ alreadyBookmarked:(already_bookmarked ? YES : NO)];
+}
+
+bool BrowserWindowCocoa::IsDownloadShelfVisible() const {
+ return [controller_ isDownloadShelfVisible] != NO;
+}
+
+DownloadShelf* BrowserWindowCocoa::GetDownloadShelf() {
+ DownloadShelfController* shelfController = [controller_ downloadShelf];
+ return [shelfController bridge];
+}
+
+void BrowserWindowCocoa::ShowReportBugDialog() {
+ TabContents* current_tab = browser_->GetSelectedTabContents();
+ if (current_tab && current_tab->controller().GetActiveEntry()) {
+ browser_->ShowBrokenPageTab(current_tab);
+ }
+}
+
+void BrowserWindowCocoa::ShowClearBrowsingDataDialog() {
+ [ClearBrowsingDataController
+ showClearBrowsingDialogForProfile:browser_->profile()];
+}
+
+void BrowserWindowCocoa::ShowImportDialog() {
+ [ImportSettingsDialogController
+ showImportSettingsDialogForProfile:browser_->profile()];
+}
+
+void BrowserWindowCocoa::ShowSearchEnginesDialog() {
+ [KeywordEditorCocoaController showKeywordEditor:browser_->profile()];
+}
+
+void BrowserWindowCocoa::ShowPasswordManager() {
+ NOTIMPLEMENTED();
+}
+
+void BrowserWindowCocoa::ShowRepostFormWarningDialog(
+ TabContents* tab_contents) {
+ RepostFormWarningMac::Create(GetNativeHandle(), tab_contents);
+}
+
+void BrowserWindowCocoa::ShowContentSettingsWindow(
+ ContentSettingsType settings_type,
+ Profile* profile) {
+ [ContentSettingsDialogController showContentSettingsForType:settings_type
+ profile:profile];
+}
+
+void BrowserWindowCocoa::ShowCollectedCookiesDialog(TabContents* tab_contents) {
+ // Deletes itself on close.
+ new CollectedCookiesMac(GetNativeHandle(), tab_contents);
+}
+
+void BrowserWindowCocoa::ShowProfileErrorDialog(int message_id) {
+ scoped_nsobject<NSAlert> alert([[NSAlert alloc] init]);
+ [alert addButtonWithTitle:l10n_util::GetNSStringWithFixup(IDS_OK)];
+ [alert setMessageText:l10n_util::GetNSStringWithFixup(IDS_PRODUCT_NAME)];
+ [alert setInformativeText:l10n_util::GetNSStringWithFixup(message_id)];
+ [alert setAlertStyle:NSWarningAlertStyle];
+ [alert runModal];
+}
+
+void BrowserWindowCocoa::ShowThemeInstallBubble() {
+ ThemeInstallBubbleView::Show(window());
+}
+
+// We allow closing the window here since the real quit decision on Mac is made
+// in [AppController quit:].
+void BrowserWindowCocoa::ConfirmBrowserCloseWithPendingDownloads() {
+ // Call InProgressDownloadResponse asynchronously to avoid a crash when the
+ // browser window is closed here (http://crbug.com/44454).
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ confirm_close_factory_.NewRunnableMethod(
+ &Browser::InProgressDownloadResponse,
+ true));
+}
+
+void BrowserWindowCocoa::ShowHTMLDialog(HtmlDialogUIDelegate* delegate,
+ gfx::NativeWindow parent_window) {
+ [HtmlDialogWindowController showHtmlDialog:delegate
+ profile:browser_->profile()];
+}
+
+void BrowserWindowCocoa::UserChangedTheme() {
+ [controller_ userChangedTheme];
+}
+
+int BrowserWindowCocoa::GetExtraRenderViewHeight() const {
+ // Currently this is only used on linux.
+ return 0;
+}
+
+void BrowserWindowCocoa::TabContentsFocused(TabContents* tab_contents) {
+ NOTIMPLEMENTED();
+}
+
+void BrowserWindowCocoa::ShowPageInfo(Profile* profile,
+ const GURL& url,
+ const NavigationEntry::SSLStatus& ssl,
+ bool show_history) {
+ browser::ShowPageInfoBubble(window(), profile, url, ssl, show_history);
+}
+
+void BrowserWindowCocoa::ShowAppMenu() {
+ // No-op. Mac doesn't support showing the menus via alt keys.
+}
+
+bool BrowserWindowCocoa::PreHandleKeyboardEvent(
+ const NativeWebKeyboardEvent& event, bool* is_keyboard_shortcut) {
+ if (event.skip_in_browser || event.type == NativeWebKeyboardEvent::Char)
+ return false;
+
+ DCHECK(event.os_event != NULL);
+ int id = GetCommandId(event);
+ if (id == -1)
+ return false;
+
+ if (browser_->IsReservedCommand(id))
+ return HandleKeyboardEventInternal(event.os_event);
+
+ DCHECK(is_keyboard_shortcut != NULL);
+ *is_keyboard_shortcut = true;
+
+ return false;
+}
+
+void BrowserWindowCocoa::HandleKeyboardEvent(
+ const NativeWebKeyboardEvent& event) {
+ if (event.skip_in_browser || event.type == NativeWebKeyboardEvent::Char)
+ return;
+
+ DCHECK(event.os_event != NULL);
+ HandleKeyboardEventInternal(event.os_event);
+}
+
+@interface MenuWalker : NSObject
++ (NSMenuItem*)itemForKeyEquivalent:(NSEvent*)key
+ menu:(NSMenu*)menu;
+@end
+
+@implementation MenuWalker
++ (NSMenuItem*)itemForKeyEquivalent:(NSEvent*)key
+ menu:(NSMenu*)menu {
+ NSMenuItem* result = nil;
+
+ for (NSMenuItem *item in [menu itemArray]) {
+ NSMenu* submenu = [item submenu];
+ if (submenu) {
+ if (submenu != [NSApp servicesMenu])
+ result = [self itemForKeyEquivalent:key
+ menu:submenu];
+ } else if ([item cr_firesForKeyEventIfEnabled:key]) {
+ result = item;
+ }
+
+ if (result)
+ break;
+ }
+
+ return result;
+}
+@end
+
+int BrowserWindowCocoa::GetCommandId(const NativeWebKeyboardEvent& event) {
+ if ([event.os_event type] != NSKeyDown)
+ return -1;
+
+ // Look in menu.
+ NSMenuItem* item = [MenuWalker itemForKeyEquivalent:event.os_event
+ menu:[NSApp mainMenu]];
+
+ if (item && [item action] == @selector(commandDispatch:) && [item tag] > 0)
+ return [item tag];
+
+ // "Close window" doesn't use the |commandDispatch:| mechanism. Menu items
+ // that do not correspond to IDC_ constants need no special treatment however,
+ // as they can't be blacklisted in |Browser::IsReservedCommand()| anyhow.
+ if (item && [item action] == @selector(performClose:))
+ return IDC_CLOSE_WINDOW;
+
+ // "Exit" doesn't use the |commandDispatch:| mechanism either.
+ if (item && [item action] == @selector(terminate:))
+ return IDC_EXIT;
+
+ // Look in secondary keyboard shortcuts.
+ NSUInteger modifiers = [event.os_event modifierFlags];
+ const bool cmdKey = (modifiers & NSCommandKeyMask) != 0;
+ const bool shiftKey = (modifiers & NSShiftKeyMask) != 0;
+ const bool cntrlKey = (modifiers & NSControlKeyMask) != 0;
+ const bool optKey = (modifiers & NSAlternateKeyMask) != 0;
+ const int keyCode = [event.os_event keyCode];
+ const unichar keyChar = KeyCharacterForEvent(event.os_event);
+
+ int cmdNum = CommandForWindowKeyboardShortcut(
+ cmdKey, shiftKey, cntrlKey, optKey, keyCode, keyChar);
+ if (cmdNum != -1)
+ return cmdNum;
+
+ cmdNum = CommandForBrowserKeyboardShortcut(
+ cmdKey, shiftKey, cntrlKey, optKey, keyCode, keyChar);
+ if (cmdNum != -1)
+ return cmdNum;
+
+ return -1;
+}
+
+bool BrowserWindowCocoa::HandleKeyboardEventInternal(NSEvent* event) {
+ ChromeEventProcessingWindow* event_window =
+ static_cast<ChromeEventProcessingWindow*>(window());
+ DCHECK([event_window isKindOfClass:[ChromeEventProcessingWindow class]]);
+
+ // Do not fire shortcuts on key up.
+ if ([event type] == NSKeyDown) {
+ // Send the event to the menu before sending it to the browser/window
+ // shortcut handling, so that if a user configures cmd-left to mean
+ // "previous tab", it takes precedence over the built-in "history back"
+ // binding. Other than that, the |-redispatchKeyEvent:| call would take care
+ // of invoking the original menu item shortcut as well.
+
+ if ([[NSApp mainMenu] performKeyEquivalent:event])
+ return true;
+
+ if ([event_window handleExtraBrowserKeyboardShortcut:event])
+ return true;
+
+ if ([event_window handleExtraWindowKeyboardShortcut:event])
+ return true;
+
+ if ([event_window handleDelayedWindowKeyboardShortcut:event])
+ return true;
+ }
+
+ return [event_window redispatchKeyEvent:event];
+}
+
+void BrowserWindowCocoa::ShowCreateWebAppShortcutsDialog(
+ TabContents* tab_contents) {
+ NOTIMPLEMENTED();
+}
+
+void BrowserWindowCocoa::ShowCreateChromeAppShortcutsDialog(
+ Profile* profile, const Extension* app) {
+ NOTIMPLEMENTED();
+}
+
+void BrowserWindowCocoa::Cut() {
+ [NSApp sendAction:@selector(cut:) to:nil from:nil];
+}
+
+void BrowserWindowCocoa::Copy() {
+ [NSApp sendAction:@selector(copy:) to:nil from:nil];
+}
+
+void BrowserWindowCocoa::Paste() {
+ [NSApp sendAction:@selector(paste:) to:nil from:nil];
+}
+
+void BrowserWindowCocoa::ToggleTabStripMode() {
+ [controller_ toggleTabStripDisplayMode];
+}
+
+void BrowserWindowCocoa::OpenTabpose() {
+ [controller_ openTabpose];
+}
+
+void BrowserWindowCocoa::PrepareForInstant() {
+ // TODO: implement fade as done on windows.
+}
+
+void BrowserWindowCocoa::ShowInstant(TabContents* preview_contents) {
+ [controller_ showInstant:preview_contents];
+}
+
+void BrowserWindowCocoa::HideInstant(bool instant_is_active) {
+ [controller_ hideInstant];
+
+ // TODO: add support for |instant_is_active|.
+}
+
+gfx::Rect BrowserWindowCocoa::GetInstantBounds() {
+ // Flip coordinates based on the primary screen.
+ NSScreen* screen = [[NSScreen screens] objectAtIndex:0];
+ NSRect monitorFrame = [screen frame];
+ NSRect frame = [controller_ instantFrame];
+ gfx::Rect bounds(NSRectToCGRect(frame));
+ bounds.set_y(NSHeight(monitorFrame) - bounds.y() - bounds.height());
+ return bounds;
+}
+
+void BrowserWindowCocoa::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ switch (type.value) {
+ // Only the key window gets a direct toggle from the menu.
+ // Other windows hear about it from the notification.
+ case NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED:
+ [controller_ updateBookmarkBarVisibilityWithAnimation:YES];
+ break;
+ case NotificationType::SIDEBAR_CHANGED:
+ UpdateSidebarForContents(
+ Details<SidebarContainer>(details)->tab_contents());
+ break;
+ default:
+ NOTREACHED(); // we don't ask for anything else!
+ break;
+ }
+}
+
+void BrowserWindowCocoa::DestroyBrowser() {
+ [controller_ destroyBrowser];
+
+ // at this point the controller is dead (autoreleased), so
+ // make sure we don't try to reference it any more.
+}
+
+NSWindow* BrowserWindowCocoa::window() const {
+ return [controller_ window];
+}
+
+void BrowserWindowCocoa::UpdateSidebarForContents(TabContents* tab_contents) {
+ if (tab_contents == browser_->GetSelectedTabContents()) {
+ [controller_ updateSidebarForContents:tab_contents];
+ }
+}
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa_unittest.mm b/chrome/browser/ui/cocoa/browser_window_cocoa_unittest.mm
new file mode 100644
index 0000000..c76d3ee
--- /dev/null
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa_unittest.mm
@@ -0,0 +1,120 @@
+// Copyright (c) 2009 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/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+#include "base/string_util.h"
+#include "chrome/browser/bookmarks/bookmark_utils.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#include "chrome/browser/ui/cocoa/browser_window_cocoa.h"
+#include "chrome/browser/ui/cocoa/browser_window_controller.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/common/notification_type.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// A BrowserWindowCocoa that goes PONG when
+// BOOKMARK_BAR_VISIBILITY_PREF_CHANGED is sent. This is so we can be
+// sure we are observing it.
+class BrowserWindowCocoaPong : public BrowserWindowCocoa {
+ public:
+ BrowserWindowCocoaPong(Browser* browser,
+ BrowserWindowController* controller) :
+ BrowserWindowCocoa(browser, controller, [controller window]) {
+ pong_ = false;
+ }
+ virtual ~BrowserWindowCocoaPong() { }
+
+ void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type.value == NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED)
+ pong_ = true;
+ BrowserWindowCocoa::Observe(type, source, details);
+ }
+
+ bool pong_;
+};
+
+// Main test class.
+class BrowserWindowCocoaTest : public CocoaTest {
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ Browser* browser = browser_helper_.browser();
+ controller_ = [[BrowserWindowController alloc] initWithBrowser:browser
+ takeOwnership:NO];
+ }
+
+ virtual void TearDown() {
+ [controller_ close];
+ CocoaTest::TearDown();
+ }
+
+ public:
+ BrowserTestHelper browser_helper_;
+ BrowserWindowController* controller_;
+};
+
+
+TEST_F(BrowserWindowCocoaTest, TestNotification) {
+ BrowserWindowCocoaPong *bwc =
+ new BrowserWindowCocoaPong(browser_helper_.browser(), controller_);
+
+ EXPECT_FALSE(bwc->pong_);
+ bookmark_utils::ToggleWhenVisible(browser_helper_.profile());
+ // Confirm we are listening
+ EXPECT_TRUE(bwc->pong_);
+ delete bwc;
+ // If this does NOT crash it confirms we stopped listening in the destructor.
+ bookmark_utils::ToggleWhenVisible(browser_helper_.profile());
+}
+
+
+TEST_F(BrowserWindowCocoaTest, TestBookmarkBarVisible) {
+ BrowserWindowCocoaPong *bwc = new BrowserWindowCocoaPong(
+ browser_helper_.browser(),
+ controller_);
+ scoped_ptr<BrowserWindowCocoaPong> scoped_bwc(bwc);
+
+ bool before = bwc->IsBookmarkBarVisible();
+ bookmark_utils::ToggleWhenVisible(browser_helper_.profile());
+ EXPECT_NE(before, bwc->IsBookmarkBarVisible());
+
+ bookmark_utils::ToggleWhenVisible(browser_helper_.profile());
+ EXPECT_EQ(before, bwc->IsBookmarkBarVisible());
+}
+
+@interface FakeController : NSWindowController {
+ BOOL fullscreen_;
+}
+@end
+
+@implementation FakeController
+- (void)setFullscreen:(BOOL)fullscreen {
+ fullscreen_ = fullscreen;
+}
+- (BOOL)isFullscreen {
+ return fullscreen_;
+}
+@end
+
+TEST_F(BrowserWindowCocoaTest, TestFullscreen) {
+ // Wrap the FakeController in a scoped_nsobject instead of autoreleasing in
+ // windowWillClose: because we never actually open a window in this test (so
+ // windowWillClose: never gets called).
+ scoped_nsobject<FakeController> fake_controller(
+ [[FakeController alloc] init]);
+ BrowserWindowCocoaPong *bwc = new BrowserWindowCocoaPong(
+ browser_helper_.browser(),
+ (BrowserWindowController*)fake_controller.get());
+ scoped_ptr<BrowserWindowCocoaPong> scoped_bwc(bwc);
+
+ EXPECT_FALSE(bwc->IsFullscreen());
+ bwc->SetFullscreen(true);
+ EXPECT_TRUE(bwc->IsFullscreen());
+ bwc->SetFullscreen(false);
+ EXPECT_FALSE(bwc->IsFullscreen());
+ [fake_controller close];
+}
+
+// TODO(???): test other methods of BrowserWindowCocoa
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.h b/chrome/browser/ui/cocoa/browser_window_controller.h
new file mode 100644
index 0000000..4ff053e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/browser_window_controller.h
@@ -0,0 +1,397 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_BROWSER_WINDOW_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_BROWSER_WINDOW_CONTROLLER_H_
+#pragma once
+
+// A class acting as the Objective-C controller for the Browser
+// object. Handles interactions between Cocoa and the cross-platform
+// code. Each window has a single toolbar and, by virtue of being a
+// TabWindowController, a tab strip along the top.
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/sync/sync_ui_util.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.h"
+#import "chrome/browser/ui/cocoa/browser_command_executor.h"
+#import "chrome/browser/ui/cocoa/tab_contents_controller.h"
+#import "chrome/browser/ui/cocoa/tab_strip_controller.h"
+#import "chrome/browser/ui/cocoa/tab_window_controller.h"
+#import "chrome/browser/ui/cocoa/themed_window.h"
+#import "chrome/browser/ui/cocoa/url_drop_target.h"
+#import "chrome/browser/ui/cocoa/view_resizer.h"
+
+
+class Browser;
+class BrowserWindow;
+class BrowserWindowCocoa;
+class ConstrainedWindowMac;
+@class DevToolsController;
+@class DownloadShelfController;
+@class FindBarCocoaController;
+@class FullscreenController;
+@class GTMWindowSheetController;
+@class IncognitoImageView;
+@class InfoBarContainerController;
+class LocationBarViewMac;
+@class PreviewableContentsController;
+@class SidebarController;
+class StatusBubbleMac;
+class TabContents;
+@class TabStripController;
+@class TabStripView;
+@class ToolbarController;
+
+
+@interface BrowserWindowController :
+ TabWindowController<NSUserInterfaceValidations,
+ BookmarkBarControllerDelegate,
+ BrowserCommandExecutor,
+ ViewResizer,
+ TabContentsControllerDelegate,
+ TabStripControllerDelegate> {
+ @private
+ // The ordering of these members is important as it determines the order in
+ // which they are destroyed. |browser_| needs to be destroyed last as most of
+ // the other objects hold weak references to it or things it owns
+ // (tab/toolbar/bookmark models, profiles, etc).
+ scoped_ptr<Browser> browser_;
+ NSWindow* savedRegularWindow_;
+ scoped_ptr<BrowserWindowCocoa> windowShim_;
+ scoped_nsobject<ToolbarController> toolbarController_;
+ scoped_nsobject<TabStripController> tabStripController_;
+ scoped_nsobject<FindBarCocoaController> findBarCocoaController_;
+ scoped_nsobject<InfoBarContainerController> infoBarContainerController_;
+ scoped_nsobject<DownloadShelfController> downloadShelfController_;
+ scoped_nsobject<BookmarkBarController> bookmarkBarController_;
+ scoped_nsobject<DevToolsController> devToolsController_;
+ scoped_nsobject<SidebarController> sidebarController_;
+ scoped_nsobject<PreviewableContentsController> previewableContentsController_;
+ scoped_nsobject<FullscreenController> fullscreenController_;
+
+ // Strong. StatusBubble is a special case of a strong reference that
+ // we don't wrap in a scoped_ptr because it is acting the same
+ // as an NSWindowController in that it wraps a window that must
+ // be shut down before our destructors are called.
+ StatusBubbleMac* statusBubble_;
+
+ BookmarkBubbleController* bookmarkBubbleController_; // Weak.
+ BOOL initializing_; // YES while we are currently in initWithBrowser:
+ BOOL ownsBrowser_; // Only ever NO when testing
+
+ // The total amount by which we've grown the window up or down (to display a
+ // bookmark bar and/or download shelf), respectively; reset to 0 when moved
+ // away from the bottom/top or resized (or zoomed).
+ CGFloat windowTopGrowth_;
+ CGFloat windowBottomGrowth_;
+
+ // YES only if we're shrinking the window from an apparent zoomed state (which
+ // we'll only do if we grew it to the zoomed state); needed since we'll then
+ // restrict the amount of shrinking by the amounts specified above. Reset to
+ // NO on growth.
+ BOOL isShrinkingFromZoomed_;
+
+ // The raw accumulated zoom value and the actual zoom increments made for an
+ // an in-progress pinch gesture.
+ CGFloat totalMagnifyGestureAmount_;
+ NSInteger currentZoomStepDelta_;
+
+ // The view which shows the incognito badge (NULL if not an incognito window).
+ // Needed to access the view to move it to/from the fullscreen window.
+ scoped_nsobject<IncognitoImageView> incognitoBadge_;
+
+ // Lazily created view which draws the background for the floating set of bars
+ // in fullscreen mode (for window types having a floating bar; it remains nil
+ // for those which don't).
+ scoped_nsobject<NSView> floatingBarBackingView_;
+
+ // Tracks whether the floating bar is above or below the bookmark bar, in
+ // terms of z-order.
+ BOOL floatingBarAboveBookmarkBar_;
+
+ // The proportion of the floating bar which is shown (in fullscreen mode).
+ CGFloat floatingBarShownFraction_;
+
+ // Various UI elements/events may want to ensure that the floating bar is
+ // visible (in fullscreen mode), e.g., because of where the mouse is or where
+ // keyboard focus is. Whenever an object requires bar visibility, it has
+ // itself added to |barVisibilityLocks_|. When it no longer requires bar
+ // visibility, it has itself removed.
+ scoped_nsobject<NSMutableSet> barVisibilityLocks_;
+
+ // Bar visibility locks and releases only result (when appropriate) in changes
+ // in visible state when the following is |YES|.
+ BOOL barVisibilityUpdatesEnabled_;
+}
+
+// A convenience class method which gets the |BrowserWindowController| for a
+// given window. This method returns nil if no window in the chain has a BWC.
++ (BrowserWindowController*)browserWindowControllerForWindow:(NSWindow*)window;
+
+// A convenience class method which gets the |BrowserWindowController| for a
+// given view. This is the controller for the window containing |view|, if it
+// is a BWC, or the first controller in the parent-window chain that is a
+// BWC. This method returns nil if no window in the chain has a BWC.
++ (BrowserWindowController*)browserWindowControllerForView:(NSView*)view;
+
+// Load the browser window nib and do any Cocoa-specific initialization.
+// Takes ownership of |browser|.
+- (id)initWithBrowser:(Browser*)browser;
+
+// Call to make the browser go away from other places in the cross-platform
+// code.
+- (void)destroyBrowser;
+
+// Access the C++ bridge between the NSWindow and the rest of Chromium.
+- (BrowserWindow*)browserWindow;
+
+// Return a weak pointer to the toolbar controller.
+- (ToolbarController*)toolbarController;
+
+// Return a weak pointer to the tab strip controller.
+- (TabStripController*)tabStripController;
+
+// Access the C++ bridge object representing the status bubble for the window.
+- (StatusBubbleMac*)statusBubble;
+
+// Access the C++ bridge object representing the location bar.
+- (LocationBarViewMac*)locationBarBridge;
+
+// Updates the toolbar (and transitively the location bar) with the states of
+// the specified |tab|. If |shouldRestore| is true, we're switching
+// (back?) to this tab and should restore any previous location bar state
+// (such as user editing) as well.
+- (void)updateToolbarWithContents:(TabContents*)tab
+ shouldRestoreState:(BOOL)shouldRestore;
+
+// Sets whether or not the current page in the frontmost tab is bookmarked.
+- (void)setStarredState:(BOOL)isStarred;
+
+// Called to tell the selected tab to update its loading state.
+// |force| is set if the update is due to changing tabs, as opposed to
+// the page-load finishing. See comment in reload_button.h.
+- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force;
+
+// Brings this controller's window to the front.
+- (void)activate;
+
+// Make the location bar the first responder, if possible.
+- (void)focusLocationBar:(BOOL)selectAll;
+
+// Make the (currently-selected) tab contents the first responder, if possible.
+- (void)focusTabContents;
+
+// Returns the frame of the regular (non-fullscreened) window (even if the
+// window is currently in fullscreen mode). The frame is returned in Cocoa
+// coordinates (origin in bottom-left).
+- (NSRect)regularWindowFrame;
+
+- (BOOL)isBookmarkBarVisible;
+
+// Returns YES if the bookmark bar is currently animating.
+- (BOOL)isBookmarkBarAnimating;
+
+// Called after bookmark bar visibility changes (due to pref change or change in
+// tab/tab contents).
+- (void)updateBookmarkBarVisibilityWithAnimation:(BOOL)animate;
+
+- (BOOL)isDownloadShelfVisible;
+
+// Lazily creates the download shelf in visible state if it doesn't exist yet.
+- (DownloadShelfController*)downloadShelf;
+
+// Retains the given FindBarCocoaController and adds its view to this
+// browser window. Must only be called once per
+// BrowserWindowController.
+- (void)addFindBar:(FindBarCocoaController*)findBarCocoaController;
+
+// The user changed the theme.
+- (void)userChangedTheme;
+
+// Executes the command in the context of the current browser.
+// |command| is an integer value containing one of the constants defined in the
+// "chrome/app/chrome_command_ids.h" file.
+- (void)executeCommand:(int)command;
+
+// Delegate method for the status bubble to query its base frame.
+- (NSRect)statusBubbleBaseFrame;
+
+// Show the bookmark bubble (e.g. user just clicked on the STAR)
+- (void)showBookmarkBubbleForURL:(const GURL&)url
+ alreadyBookmarked:(BOOL)alreadyBookmarked;
+
+// Returns the (lazily created) window sheet controller of this window. Used
+// for the per-tab sheets.
+- (GTMWindowSheetController*)sheetController;
+
+// Requests that |window| is opened as a per-tab sheet to the current tab.
+- (void)attachConstrainedWindow:(ConstrainedWindowMac*)window;
+// Closes the tab sheet |window| and potentially shows the next sheet in the
+// tab's sheet queue.
+- (void)removeConstrainedWindow:(ConstrainedWindowMac*)window;
+// Returns NO if constrained windows cannot be attached to this window.
+- (BOOL)canAttachConstrainedWindow;
+
+// Shows or hides the docked web inspector depending on |contents|'s state.
+- (void)updateDevToolsForContents:(TabContents*)contents;
+
+// Displays the active sidebar linked to the |contents| or hides sidebar UI,
+// if there's no such sidebar.
+- (void)updateSidebarForContents:(TabContents*)contents;
+
+// Gets the current theme provider.
+- (ThemeProvider*)themeProvider;
+
+// Gets the window style.
+- (ThemedWindowStyle)themedWindowStyle;
+
+// Gets the pattern phase for the window.
+- (NSPoint)themePatternPhase;
+
+// Return the point to which a bubble window's arrow should point.
+- (NSPoint)bookmarkBubblePoint;
+
+// Call when the user changes the tab strip display mode, enabling or
+// disabling vertical tabs for this browser. Re-flows the contents of the
+// browser.
+- (void)toggleTabStripDisplayMode;
+
+// Shows or hides the Instant preview contents.
+- (void)showInstant:(TabContents*)previewContents;
+- (void)hideInstant;
+
+// Returns the frame, in Cocoa (unflipped) screen coordinates, of the area where
+// Instant results are. If Instant is not showing, returns the frame of where
+// it would be.
+- (NSRect)instantFrame;
+
+// Called when the Add Search Engine dialog is closed.
+- (void)sheetDidEnd:(NSWindow*)sheet
+ returnCode:(NSInteger)code
+ context:(void*)context;
+
+@end // @interface BrowserWindowController
+
+
+// Methods having to do with the window type (normal/popup/app, and whether the
+// window has various features; fullscreen methods are separate).
+@interface BrowserWindowController(WindowType)
+
+// Determines whether this controller's window supports a given feature (i.e.,
+// whether a given feature is or can be shown in the window).
+// TODO(viettrungluu): |feature| is really should be |Browser::Feature|, but I
+// don't want to include browser.h (and you can't forward declare enums).
+- (BOOL)supportsWindowFeature:(int)feature;
+
+// Called to check whether or not this window has a normal title bar (YES if it
+// does, NO otherwise). (E.g., normal browser windows do not, pop-ups do.)
+- (BOOL)hasTitleBar;
+
+// Called to check whether or not this window has a toolbar (YES if it does, NO
+// otherwise). (E.g., normal browser windows do, pop-ups do not.)
+- (BOOL)hasToolbar;
+
+// Called to check whether or not this window has a location bar (YES if it
+// does, NO otherwise). (E.g., normal browser windows do, pop-ups may or may
+// not.)
+- (BOOL)hasLocationBar;
+
+// Called to check whether or not this window can have bookmark bar (YES if it
+// does, NO otherwise). (E.g., normal browser windows may, pop-ups may not.)
+- (BOOL)supportsBookmarkBar;
+
+// Called to check if this controller's window is a normal window (e.g., not a
+// pop-up window). Returns YES if it is, NO otherwise.
+// Note: The |-has...| methods are usually preferred, so this method is largely
+// deprecated.
+- (BOOL)isNormalWindow;
+
+@end // @interface BrowserWindowController(WindowType)
+
+
+// Methods having to do with fullscreen mode.
+@interface BrowserWindowController(Fullscreen)
+
+// Enters (or exits) fullscreen mode.
+- (void)setFullscreen:(BOOL)fullscreen;
+
+// Returns fullscreen state.
+- (BOOL)isFullscreen;
+
+// Resizes the fullscreen window to fit the screen it's currently on. Called by
+// the FullscreenController when there is a change in monitor placement or
+// resolution.
+- (void)resizeFullscreenWindow;
+
+// Gets or sets the fraction of the floating bar (fullscreen overlay) that is
+// shown. 0 is completely hidden, 1 is fully shown.
+- (CGFloat)floatingBarShownFraction;
+- (void)setFloatingBarShownFraction:(CGFloat)fraction;
+
+// Query/lock/release the requirement that the tab strip/toolbar/attached
+// bookmark bar bar cluster is visible (e.g., when one of its elements has
+// focus). This is required for the floating bar in fullscreen mode, but should
+// also be called when not in fullscreen mode; see the comments for
+// |barVisibilityLocks_| for more details. Double locks/releases by the same
+// owner are ignored. If |animate:| is YES, then an animation may be performed,
+// possibly after a small delay if |delay:| is YES. If |animate:| is NO,
+// |delay:| will be ignored. In the case of multiple calls, later calls have
+// precedence with the rule that |animate:NO| has precedence over |animate:YES|,
+// and |delay:NO| has precedence over |delay:YES|.
+- (BOOL)isBarVisibilityLockedForOwner:(id)owner;
+- (void)lockBarVisibilityForOwner:(id)owner
+ withAnimation:(BOOL)animate
+ delay:(BOOL)delay;
+- (void)releaseBarVisibilityForOwner:(id)owner
+ withAnimation:(BOOL)animate
+ delay:(BOOL)delay;
+
+// Returns YES if any of the views in the floating bar currently has focus.
+- (BOOL)floatingBarHasFocus;
+
+// Opens the tabpose window.
+- (void)openTabpose;
+
+@end // @interface BrowserWindowController(Fullscreen)
+
+
+// Methods which are either only for testing, or only public for testing.
+@interface BrowserWindowController(TestingAPI)
+
+// Put the incognito badge on the browser and adjust the tab strip
+// accordingly.
+- (void)installIncognitoBadge;
+
+// Allows us to initWithBrowser withOUT taking ownership of the browser.
+- (id)initWithBrowser:(Browser*)browser takeOwnership:(BOOL)ownIt;
+
+// Adjusts the window height by the given amount. If the window spans from the
+// top of the current workspace to the bottom of the current workspace, the
+// height is not adjusted. If growing the window by the requested amount would
+// size the window to be taller than the current workspace, the window height is
+// capped to be equal to the height of the current workspace. If the window is
+// partially offscreen, its height is not adjusted at all. This function
+// prefers to grow the window down, but will grow up if needed. Calls to this
+// function should be followed by a call to |layoutSubviews|.
+- (void)adjustWindowHeightBy:(CGFloat)deltaH;
+
+// Return an autoreleased NSWindow suitable for fullscreen use.
+- (NSWindow*)createFullscreenWindow;
+
+// Resets any saved state about window growth (due to showing the bookmark bar
+// or the download shelf), so that future shrinking will occur from the bottom.
+- (void)resetWindowGrowthState;
+
+// Computes by how far in each direction, horizontal and vertical, the
+// |source| rect doesn't fit into |target|.
+- (NSSize)overflowFrom:(NSRect)source
+ to:(NSRect)target;
+@end // @interface BrowserWindowController(TestingAPI)
+
+
+#endif // CHROME_BROWSER_UI_COCOA_BROWSER_WINDOW_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm
new file mode 100644
index 0000000..589ed91
--- /dev/null
+++ b/chrome/browser/ui/cocoa/browser_window_controller.mm
@@ -0,0 +1,2088 @@
+// 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 "chrome/browser/ui/cocoa/browser_window_controller.h"
+
+#include <Carbon/Carbon.h>
+
+#include "app/l10n_util.h"
+#include "app/l10n_util_mac.h"
+#include "app/mac/scoped_nsdisable_screen_updates.h"
+#include "app/mac/nsimage_cache.h"
+#include "base/mac_util.h"
+#import "base/scoped_nsobject.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h" // IDC_*
+#include "chrome/browser/bookmarks/bookmark_editor.h"
+#include "chrome/browser/google/google_util.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/render_widget_host_view.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/sync/sync_ui_util_mac.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_contents_view_mac.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#import "chrome/browser/ui/cocoa/background_gradient_view.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller.h"
+#import "chrome/browser/ui/cocoa/browser_window_cocoa.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller_private.h"
+#import "chrome/browser/ui/cocoa/dev_tools_controller.h"
+#import "chrome/browser/ui/cocoa/download/download_shelf_controller.h"
+#import "chrome/browser/ui/cocoa/event_utils.h"
+#import "chrome/browser/ui/cocoa/fast_resize_view.h"
+#import "chrome/browser/ui/cocoa/find_bar_bridge.h"
+#import "chrome/browser/ui/cocoa/find_bar_cocoa_controller.h"
+#import "chrome/browser/ui/cocoa/focus_tracker.h"
+#import "chrome/browser/ui/cocoa/fullscreen_controller.h"
+#import "chrome/browser/ui/cocoa/fullscreen_window.h"
+#import "chrome/browser/ui/cocoa/image_utils.h"
+#import "chrome/browser/ui/cocoa/infobar_container_controller.h"
+#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h"
+#import "chrome/browser/ui/cocoa/previewable_contents_controller.h"
+#import "chrome/browser/ui/cocoa/nswindow_additions.h"
+#import "chrome/browser/ui/cocoa/sad_tab_controller.h"
+#import "chrome/browser/ui/cocoa/sidebar_controller.h"
+#import "chrome/browser/ui/cocoa/status_bubble_mac.h"
+#import "chrome/browser/ui/cocoa/tab_contents_controller.h"
+#import "chrome/browser/ui/cocoa/tab_strip_controller.h"
+#import "chrome/browser/ui/cocoa/tab_strip_view.h"
+#import "chrome/browser/ui/cocoa/tab_view.h"
+#import "chrome/browser/ui/cocoa/tabpose_window.h"
+#import "chrome/browser/ui/cocoa/toolbar_controller.h"
+#include "chrome/browser/ui/omnibox/location_bar.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "chrome/browser/ui/tabs/dock_info.h"
+#include "chrome/browser/ui/toolbar/encoding_menu_controller.h"
+#include "chrome/browser/ui/window_sizer.h"
+#include "chrome/common/url_constants.h"
+#include "grit/generated_resources.h"
+#include "grit/locale_settings.h"
+
+// ORGANIZATION: This is a big file. It is (in principle) organized as follows
+// (in order):
+// 1. Interfaces. Very short, one-time-use classes may include an implementation
+// immediately after their interface.
+// 2. The general implementation section, ordered as follows:
+// i. Public methods and overrides.
+// ii. Overrides/implementations of undocumented methods.
+// iii. Delegate methods for various protocols, formal and informal, to which
+// |BrowserWindowController| conforms.
+// 3. (temporary) Implementation sections for various categories.
+//
+// Private methods are defined and implemented separately in
+// browser_window_controller_private.{h,mm}.
+//
+// Not all of the above guidelines are followed and more (re-)organization is
+// needed. BUT PLEASE TRY TO KEEP THIS FILE ORGANIZED. I'd rather re-organize as
+// little as possible, since doing so messes up the file's history.
+//
+// TODO(viettrungluu): [crbug.com/35543] on-going re-organization, splitting
+// things into multiple files -- the plan is as follows:
+// - in general, everything stays in browser_window_controller.h, but is split
+// off into categories (see below)
+// - core stuff stays in browser_window_controller.mm
+// - ... overrides also stay (without going into a category, in particular)
+// - private stuff which everyone needs goes into
+// browser_window_controller_private.{h,mm}; if no one else needs them, they
+// can go in individual files (see below)
+// - area/task-specific stuff go in browser_window_controller_<area>.mm
+// - ... in categories called "(<Area>)" or "(<PrivateArea>)"
+// Plan of action:
+// - first re-organize into categories
+// - then split into files
+
+// Notes on self-inflicted (not user-inflicted) window resizing and moving:
+//
+// When the bookmark bar goes from hidden to shown (on a non-NTP) page, or when
+// the download shelf goes from hidden to shown, we grow the window downwards in
+// order to maintain a constant content area size. When either goes from shown
+// to hidden, we consequently shrink the window from the bottom, also to keep
+// the content area size constant. To keep things simple, if the window is not
+// entirely on-screen, we don't grow/shrink the window.
+//
+// The complications come in when there isn't enough room (on screen) below the
+// window to accomodate the growth. In this case, we grow the window first
+// downwards, and then upwards. So, when it comes to shrinking, we do the
+// opposite: shrink from the top by the amount by which we grew at the top, and
+// then from the bottom -- unless the user moved/resized/zoomed the window, in
+// which case we "reset state" and just shrink from the bottom.
+//
+// A further complication arises due to the way in which "zoom" ("maximize")
+// works on Mac OS X. Basically, for our purposes, a window is "zoomed" whenever
+// it occupies the full available vertical space. (Note that the green zoom
+// button does not track zoom/unzoomed state per se, but basically relies on
+// this heuristic.) We don't, in general, want to shrink the window if the
+// window is zoomed (scenario: window is zoomed, download shelf opens -- which
+// doesn't cause window growth, download shelf closes -- shouldn't cause the
+// window to become unzoomed!). However, if we grew the window
+// (upwards/downwards) to become zoomed in the first place, we *should* shrink
+// the window by the amounts by which we grew (scenario: window occupies *most*
+// of vertical space, download shelf opens causing growth so that window
+// occupies all of vertical space -- i.e., window is effectively zoomed,
+// download shelf closes -- should return the window to its previous state).
+//
+// A major complication is caused by the way grows/shrinks are handled and
+// animated. Basically, the BWC doesn't see the global picture, but it sees
+// grows and shrinks in small increments (as dictated by the animation). Thus
+// window growth/shrinkage (at the top/bottom) have to be tracked incrementally.
+// Allowing shrinking from the zoomed state also requires tracking: We check on
+// any shrink whether we're both zoomed and have previously grown -- if so, we
+// set a flag, and constrain any resize by the allowed amounts. On further
+// shrinks, we check the flag (since the size/position of the window will no
+// longer indicate that the window is shrinking from an apparent zoomed state)
+// and if it's set we continue to constrain the resize.
+
+
+@interface NSWindow(NSPrivateApis)
+// Note: These functions are private, use -[NSObject respondsToSelector:]
+// before calling them.
+
+- (void)setBottomCornerRounded:(BOOL)rounded;
+
+- (NSRect)_growBoxRect;
+
+@end
+
+
+// IncognitoImageView subclasses NSView to allow mouse events to pass through it
+// so you can drag the window by dragging on the spy guy.
+@interface IncognitoImageView : NSView {
+ @private
+ scoped_nsobject<NSImage> image_;
+}
+
+- (void)setImage:(NSImage*)image;
+
+@end
+
+@implementation IncognitoImageView
+
+- (BOOL)mouseDownCanMoveWindow {
+ return YES;
+}
+
+- (void)drawRect:(NSRect)rect {
+ [NSGraphicsContext saveGraphicsState];
+
+ scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
+ [shadow.get() setShadowColor:[NSColor colorWithCalibratedWhite:0.0
+ alpha:0.75]];
+ [shadow.get() setShadowOffset:NSMakeSize(0, 0)];
+ [shadow.get() setShadowBlurRadius:3.0];
+ [shadow.get() set];
+
+ [image_.get() drawInRect:[self bounds]
+ fromRect:NSZeroRect
+ operation:NSCompositeSourceOver
+ fraction:1.0
+ neverFlipped:YES];
+ [NSGraphicsContext restoreGraphicsState];
+}
+
+- (void)setImage:(NSImage*)image {
+ image_.reset([image retain]);
+}
+
+@end
+
+
+@implementation BrowserWindowController
+
++ (BrowserWindowController*)browserWindowControllerForWindow:(NSWindow*)window {
+ while (window) {
+ id controller = [window windowController];
+ if ([controller isKindOfClass:[BrowserWindowController class]])
+ return (BrowserWindowController*)controller;
+ window = [window parentWindow];
+ }
+ return nil;
+}
+
++ (BrowserWindowController*)browserWindowControllerForView:(NSView*)view {
+ NSWindow* window = [view window];
+ return [BrowserWindowController browserWindowControllerForWindow:window];
+}
+
+// Load the browser window nib and do any Cocoa-specific initialization.
+// Takes ownership of |browser|. Note that the nib also sets this controller
+// up as the window's delegate.
+- (id)initWithBrowser:(Browser*)browser {
+ return [self initWithBrowser:browser takeOwnership:YES];
+}
+
+// Private(TestingAPI) init routine with testing options.
+- (id)initWithBrowser:(Browser*)browser takeOwnership:(BOOL)ownIt {
+ // Use initWithWindowNibPath:: instead of initWithWindowNibName: so we
+ // can override it in a unit test.
+ NSString* nibpath = [mac_util::MainAppBundle()
+ pathForResource:@"BrowserWindow"
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
+ DCHECK(browser);
+ initializing_ = YES;
+ browser_.reset(browser);
+ ownsBrowser_ = ownIt;
+ NSWindow* window = [self window];
+ windowShim_.reset(new BrowserWindowCocoa(browser, self, window));
+
+ // Create the bar visibility lock set; 10 is arbitrary, but should hopefully
+ // be big enough to hold all locks that'll ever be needed.
+ barVisibilityLocks_.reset([[NSMutableSet setWithCapacity:10] retain]);
+
+ // Sets the window to not have rounded corners, which prevents
+ // the resize control from being inset slightly and looking ugly.
+ if ([window respondsToSelector:@selector(setBottomCornerRounded:)])
+ [window setBottomCornerRounded:NO];
+
+ // Get the most appropriate size for the window, then enforce the
+ // minimum width and height. The window shim will handle flipping
+ // the coordinates for us so we can use it to save some code.
+ // Note that this may leave a significant portion of the window
+ // offscreen, but there will always be enough window onscreen to
+ // drag the whole window back into view.
+ NSSize minSize = [[self window] minSize];
+ gfx::Rect desiredContentRect = browser_->GetSavedWindowBounds();
+ gfx::Rect windowRect = desiredContentRect;
+ if (windowRect.width() < minSize.width)
+ windowRect.set_width(minSize.width);
+ if (windowRect.height() < minSize.height)
+ windowRect.set_height(minSize.height);
+
+ // When we are given x/y coordinates of 0 on a created popup window, assume
+ // none were given by the window.open() command.
+ if (browser_->type() & Browser::TYPE_POPUP &&
+ windowRect.x() == 0 && windowRect.y() == 0) {
+ gfx::Size size = windowRect.size();
+ windowRect.set_origin(WindowSizer::GetDefaultPopupOrigin(size));
+ }
+
+ // Size and position the window. Note that it is not yet onscreen. Popup
+ // windows may get resized later on in this function, once the actual size
+ // of the toolbar/tabstrip is known.
+ windowShim_->SetBounds(windowRect);
+
+ // Puts the incognito badge on the window frame, if necessary.
+ [self installIncognitoBadge];
+
+ // Create a sub-controller for the docked devTools and add its view to the
+ // hierarchy. This must happen before the sidebar controller is
+ // instantiated.
+ devToolsController_.reset(
+ [[DevToolsController alloc] initWithDelegate:self]);
+ [[devToolsController_ view] setFrame:[[self tabContentArea] bounds]];
+ [[self tabContentArea] addSubview:[devToolsController_ view]];
+
+ // Create a sub-controller for the docked sidebar and add its view to the
+ // hierarchy. This must happen before the previewable contents controller
+ // is instantiated.
+ sidebarController_.reset([[SidebarController alloc] initWithDelegate:self]);
+ [[sidebarController_ view] setFrame:[[devToolsController_ view] bounds]];
+ [[devToolsController_ view] addSubview:[sidebarController_ view]];
+
+ // Create the previewable contents controller. This provides the switch
+ // view that TabStripController needs.
+ previewableContentsController_.reset(
+ [[PreviewableContentsController alloc] init]);
+ [[previewableContentsController_ view]
+ setFrame:[[sidebarController_ view] bounds]];
+ [[sidebarController_ view]
+ addSubview:[previewableContentsController_ view]];
+
+ // Create a controller for the tab strip, giving it the model object for
+ // this window's Browser and the tab strip view. The controller will handle
+ // registering for the appropriate tab notifications from the back-end and
+ // managing the creation of new tabs.
+ [self createTabStripController];
+
+ // Create the infobar container view, so we can pass it to the
+ // ToolbarController.
+ infoBarContainerController_.reset(
+ [[InfoBarContainerController alloc] initWithResizeDelegate:self]);
+ [[[self window] contentView] addSubview:[infoBarContainerController_ view]];
+
+ // Create a controller for the toolbar, giving it the toolbar model object
+ // and the toolbar view from the nib. The controller will handle
+ // registering for the appropriate command state changes from the back-end.
+ // Adds the toolbar to the content area.
+ toolbarController_.reset([[ToolbarController alloc]
+ initWithModel:browser->toolbar_model()
+ commands:browser->command_updater()
+ profile:browser->profile()
+ browser:browser
+ resizeDelegate:self]);
+ [toolbarController_ setHasToolbar:[self hasToolbar]
+ hasLocationBar:[self hasLocationBar]];
+ [[[self window] contentView] addSubview:[toolbarController_ view]];
+
+ // Create a sub-controller for the bookmark bar.
+ bookmarkBarController_.reset(
+ [[BookmarkBarController alloc]
+ initWithBrowser:browser_.get()
+ initialWidth:NSWidth([[[self window] contentView] frame])
+ delegate:self
+ resizeDelegate:self]);
+
+ // Add bookmark bar to the view hierarchy, which also triggers the nib load.
+ // The bookmark bar is defined (in the nib) to be bottom-aligned to its
+ // parent view (among other things), so position and resize properties don't
+ // need to be set.
+ [[[self window] contentView] addSubview:[bookmarkBarController_ view]
+ positioned:NSWindowBelow
+ relativeTo:[toolbarController_ view]];
+ [bookmarkBarController_ setBookmarkBarEnabled:[self supportsBookmarkBar]];
+
+ // We don't want to try and show the bar before it gets placed in its parent
+ // view, so this step shoudn't be inside the bookmark bar controller's
+ // |-awakeFromNib|.
+ [self updateBookmarkBarVisibilityWithAnimation:NO];
+
+ // Allow bar visibility to be changed.
+ [self enableBarVisibilityUpdates];
+
+ // Force a relayout of all the various bars.
+ [self layoutSubviews];
+
+ // For a popup window, |desiredContentRect| contains the desired height of
+ // the content, not of the whole window. Now that all the views are laid
+ // out, measure the current content area size and grow if needed. The
+ // window has not been placed onscreen yet, so this extra resize will not
+ // cause visible jank.
+ if (browser_->type() & Browser::TYPE_POPUP) {
+ CGFloat deltaH = desiredContentRect.height() -
+ NSHeight([[self tabContentArea] frame]);
+ // Do not shrink the window, as that may break minimum size invariants.
+ if (deltaH > 0) {
+ // Convert from tabContentArea coordinates to window coordinates.
+ NSSize convertedSize =
+ [[self tabContentArea] convertSize:NSMakeSize(0, deltaH)
+ toView:nil];
+ NSRect frame = [[self window] frame];
+ frame.size.height += convertedSize.height;
+ frame.origin.y -= convertedSize.height;
+ [[self window] setFrame:frame display:NO];
+ }
+ }
+
+ // Create the bridge for the status bubble.
+ statusBubble_ = new StatusBubbleMac([self window], self);
+
+ // 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];
+
+ // This must be done after the view is added to the window since it relies
+ // on the window bounds to determine whether to show buttons or not.
+ if ([self hasToolbar]) // Do not create the buttons in popups.
+ [toolbarController_ createBrowserActionButtons];
+
+ // We are done initializing now.
+ initializing_ = NO;
+ }
+ return self;
+}
+
+- (void)dealloc {
+ browser_->CloseAllTabs();
+ [downloadShelfController_ exiting];
+
+ // Explicitly release |fullscreenController_| here, as it may call back to
+ // this BWC in |-dealloc|. We are required to call |-exitFullscreen| before
+ // releasing the controller.
+ [fullscreenController_ exitFullscreen];
+ fullscreenController_.reset();
+
+ // Under certain testing configurations we may not actually own the browser.
+ if (ownsBrowser_ == NO)
+ ignore_result(browser_.release());
+
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+
+ [super dealloc];
+}
+
+- (BrowserWindow*)browserWindow {
+ return windowShim_.get();
+}
+
+- (ToolbarController*)toolbarController {
+ return toolbarController_.get();
+}
+
+- (TabStripController*)tabStripController {
+ return tabStripController_.get();
+}
+
+- (StatusBubbleMac*)statusBubble {
+ return statusBubble_;
+}
+
+- (LocationBarViewMac*)locationBarBridge {
+ return [toolbarController_ locationBarBridge];
+}
+
+- (void)destroyBrowser {
+ [NSApp removeWindowsItem:[self window]];
+
+ // We need the window to go away now.
+ // We can't actually use |-autorelease| here because there's an embedded
+ // run loop in the |-performClose:| which contains its own autorelease pool.
+ // Instead call it after a zero-length delay, which gets us back to the main
+ // event loop.
+ [self performSelector:@selector(autorelease)
+ withObject:nil
+ afterDelay:0];
+}
+
+// Called when the window meets the criteria to be closed (ie,
+// |-windowShouldClose:| returns YES). We must be careful to preserve the
+// semantics of BrowserWindow::Close() and not call the Browser's dtor directly
+// from this method.
+- (void)windowWillClose:(NSNotification*)notification {
+ DCHECK_EQ([notification object], [self window]);
+ DCHECK(browser_->tabstrip_model()->empty());
+ [savedRegularWindow_ close];
+ // We delete statusBubble here because we need to kill off the dependency
+ // that its window has on our window before our window goes away.
+ delete statusBubble_;
+ statusBubble_ = NULL;
+ // We can't actually use |-autorelease| here because there's an embedded
+ // run loop in the |-performClose:| which contains its own autorelease pool.
+ // Instead call it after a zero-length delay, which gets us back to the main
+ // event loop.
+ [self performSelector:@selector(autorelease)
+ withObject:nil
+ afterDelay:0];
+}
+
+- (void)attachConstrainedWindow:(ConstrainedWindowMac*)window {
+ [tabStripController_ attachConstrainedWindow:window];
+}
+
+- (void)removeConstrainedWindow:(ConstrainedWindowMac*)window {
+ [tabStripController_ removeConstrainedWindow:window];
+}
+
+- (BOOL)canAttachConstrainedWindow {
+ return ![previewableContentsController_ isShowingPreview];
+}
+
+- (void)updateDevToolsForContents:(TabContents*)contents {
+ [devToolsController_ updateDevToolsForTabContents:contents];
+ [devToolsController_ ensureContentsVisible];
+}
+
+- (void)updateSidebarForContents:(TabContents*)contents {
+ [sidebarController_ updateSidebarForTabContents:contents];
+ [sidebarController_ ensureContentsVisible];
+}
+
+// Called when the user wants to close a window or from the shutdown process.
+// The Browser object is in control of whether or not we're allowed to close. It
+// may defer closing due to several states, such as onUnload handlers needing to
+// be fired. If closing is deferred, the Browser will handle the processing
+// required to get us to the closing state and (by watching for all the tabs
+// going away) will again call to close the window when it's finally ready.
+- (BOOL)windowShouldClose:(id)sender {
+ // Disable updates while closing all tabs to avoid flickering.
+ app::mac::ScopedNSDisableScreenUpdates disabler;
+ // Give beforeunload handlers the chance to cancel the close before we hide
+ // the window below.
+ if (!browser_->ShouldCloseWindow())
+ return NO;
+
+ // saveWindowPositionIfNeeded: only works if we are the last active
+ // window, but orderOut: ends up activating another window, so we
+ // have to save the window position before we call orderOut:.
+ [self saveWindowPositionIfNeeded];
+
+ if (!browser_->tabstrip_model()->empty()) {
+ // Tab strip isn't empty. Hide the frame (so it appears to have closed
+ // immediately) and close all the tabs, allowing the renderers to shut
+ // down. When the tab strip is empty we'll be called back again.
+ [[self window] orderOut:self];
+ browser_->OnWindowClosing();
+ return NO;
+ }
+
+ // the tab strip is empty, it's ok to close the window
+ return YES;
+}
+
+// Called right after our window became the main window.
+- (void)windowDidBecomeMain:(NSNotification*)notification {
+ BrowserList::SetLastActive(browser_.get());
+ [self saveWindowPositionIfNeeded];
+
+ // TODO(dmaclach): Instead of redrawing the whole window, views that care
+ // about the active window state should be registering for notifications.
+ [[self window] setViewsNeedDisplay:YES];
+
+ // TODO(viettrungluu): For some reason, the above doesn't suffice.
+ if ([self isFullscreen])
+ [floatingBarBackingView_ setNeedsDisplay:YES]; // Okay even if nil.
+}
+
+- (void)windowDidResignMain:(NSNotification*)notification {
+ // TODO(dmaclach): Instead of redrawing the whole window, views that care
+ // about the active window state should be registering for notifications.
+ [[self window] setViewsNeedDisplay:YES];
+
+ // TODO(viettrungluu): For some reason, the above doesn't suffice.
+ if ([self isFullscreen])
+ [floatingBarBackingView_ setNeedsDisplay:YES]; // Okay even if nil.
+}
+
+// Called when we are activated (when we gain focus).
+- (void)windowDidBecomeKey:(NSNotification*)notification {
+ // We need to activate the controls (in the "WebView"). To do this, get the
+ // selected TabContents's RenderWidgetHostViewMac and tell it to activate.
+ if (TabContents* contents = browser_->GetSelectedTabContents()) {
+ if (RenderWidgetHostView* rwhv = contents->GetRenderWidgetHostView())
+ rwhv->SetActive(true);
+ }
+}
+
+// Called when we are deactivated (when we lose focus).
+- (void)windowDidResignKey:(NSNotification*)notification {
+ // If our app is still active and we're still the key window, ignore this
+ // message, since it just means that a menu extra (on the "system status bar")
+ // was activated; we'll get another |-windowDidResignKey| if we ever really
+ // lose key window status.
+ if ([NSApp isActive] && ([NSApp keyWindow] == [self window]))
+ return;
+
+ // We need to deactivate the controls (in the "WebView"). To do this, get the
+ // selected TabContents's RenderWidgetHostView and tell it to deactivate.
+ if (TabContents* contents = browser_->GetSelectedTabContents()) {
+ if (RenderWidgetHostView* rwhv = contents->GetRenderWidgetHostView())
+ rwhv->SetActive(false);
+ }
+}
+
+// Called when we have been minimized.
+- (void)windowDidMiniaturize:(NSNotification *)notification {
+ // Let the selected RenderWidgetHostView know, so that it can tell plugins.
+ if (TabContents* contents = browser_->GetSelectedTabContents()) {
+ if (RenderWidgetHostView* rwhv = contents->GetRenderWidgetHostView())
+ rwhv->SetWindowVisibility(false);
+ }
+}
+
+// Called when we have been unminimized.
+- (void)windowDidDeminiaturize:(NSNotification *)notification {
+ // Let the selected RenderWidgetHostView know, so that it can tell plugins.
+ if (TabContents* contents = browser_->GetSelectedTabContents()) {
+ if (RenderWidgetHostView* rwhv = contents->GetRenderWidgetHostView())
+ rwhv->SetWindowVisibility(true);
+ }
+}
+
+// Called when the application has been hidden.
+- (void)applicationDidHide:(NSNotification *)notification {
+ // Let the selected RenderWidgetHostView know, so that it can tell plugins
+ // (unless we are minimized, in which case nothing has really changed).
+ if (![[self window] isMiniaturized]) {
+ if (TabContents* contents = browser_->GetSelectedTabContents()) {
+ if (RenderWidgetHostView* rwhv = contents->GetRenderWidgetHostView())
+ rwhv->SetWindowVisibility(false);
+ }
+ }
+}
+
+// Called when the application has been unhidden.
+- (void)applicationDidUnhide:(NSNotification *)notification {
+ // Let the selected RenderWidgetHostView know, so that it can tell plugins
+ // (unless we are minimized, in which case nothing has really changed).
+ if (![[self window] isMiniaturized]) {
+ if (TabContents* contents = browser_->GetSelectedTabContents()) {
+ if (RenderWidgetHostView* rwhv = contents->GetRenderWidgetHostView())
+ rwhv->SetWindowVisibility(true);
+ }
+ }
+}
+
+// Called when the user clicks the zoom button (or selects it from the Window
+// menu) to determine the "standard size" of the window, based on the content
+// and other factors. If the current size/location differs nontrivally from the
+// standard size, Cocoa resizes the window to the standard size, and saves the
+// current size as the "user size". If the current size/location is the same (up
+// to a fudge factor) as the standard size, Cocoa resizes the window to the
+// saved user size. (It is possible for the two to coincide.) In this way, the
+// zoom button acts as a toggle. We determine the standard size based on the
+// content, but enforce a minimum width (calculated using the dimensions of the
+// screen) to ensure websites with small intrinsic width (such as google.com)
+// don't end up with a wee window. Moreover, we always declare the standard
+// width to be at least as big as the current width, i.e., we never want zooming
+// to the standard width to shrink the window. This is consistent with other
+// browsers' behaviour, and is desirable in multi-tab situations. Note, however,
+// that the "toggle" behaviour means that the window can still be "unzoomed" to
+// the user size.
+- (NSRect)windowWillUseStandardFrame:(NSWindow*)window
+ defaultFrame:(NSRect)frame {
+ // Forget that we grew the window up (if we in fact did).
+ [self resetWindowGrowthState];
+
+ // |frame| already fills the current screen. Never touch y and height since we
+ // always want to fill vertically.
+
+ // If the shift key is down, maximize. Hopefully this should make the
+ // "switchers" happy.
+ if ([[NSApp currentEvent] modifierFlags] & NSShiftKeyMask) {
+ return frame;
+ }
+
+ // To prevent strange results on portrait displays, the basic minimum zoomed
+ // width is the larger of: 60% of available width, 60% of available height
+ // (bounded by available width).
+ const CGFloat kProportion = 0.6;
+ CGFloat zoomedWidth =
+ std::max(kProportion * frame.size.width,
+ std::min(kProportion * frame.size.height, frame.size.width));
+
+ TabContents* contents = browser_->GetSelectedTabContents();
+ if (contents) {
+ // If the intrinsic width is bigger, then make it the zoomed width.
+ const int kScrollbarWidth = 16; // TODO(viettrungluu): ugh.
+ TabContentsViewMac* tab_contents_view =
+ static_cast<TabContentsViewMac*>(contents->view());
+ CGFloat intrinsicWidth = static_cast<CGFloat>(
+ tab_contents_view->preferred_width() + kScrollbarWidth);
+ zoomedWidth = std::max(zoomedWidth,
+ std::min(intrinsicWidth, frame.size.width));
+ }
+
+ // Never shrink from the current size on zoom (see above).
+ NSRect currentFrame = [[self window] frame];
+ zoomedWidth = std::max(zoomedWidth, currentFrame.size.width);
+
+ // |frame| determines our maximum extents. We need to set the origin of the
+ // frame -- and only move it left if necessary.
+ if (currentFrame.origin.x + zoomedWidth > frame.origin.x + frame.size.width)
+ frame.origin.x = frame.origin.x + frame.size.width - zoomedWidth;
+ else
+ frame.origin.x = currentFrame.origin.x;
+
+ // Set the width. Don't touch y or height.
+ frame.size.width = zoomedWidth;
+
+ return frame;
+}
+
+- (void)activate {
+ [[self window] makeKeyAndOrderFront:self];
+}
+
+// Determine whether we should let a window zoom/unzoom to the given |newFrame|.
+// We avoid letting unzoom move windows between screens, because it's really
+// strange and unintuitive.
+- (BOOL)windowShouldZoom:(NSWindow*)window toFrame:(NSRect)newFrame {
+ // Figure out which screen |newFrame| is on.
+ NSScreen* newScreen = nil;
+ CGFloat newScreenOverlapArea = 0.0;
+ for (NSScreen* screen in [NSScreen screens]) {
+ NSRect overlap = NSIntersectionRect(newFrame, [screen frame]);
+ CGFloat overlapArea = overlap.size.width * overlap.size.height;
+ if (overlapArea > newScreenOverlapArea) {
+ newScreen = screen;
+ newScreenOverlapArea = overlapArea;
+ }
+ }
+ // If we're somehow not on any screen, allow the zoom.
+ if (!newScreen)
+ return YES;
+
+ // If the new screen is the current screen, we can return a definitive YES.
+ // Note: This check is not strictly necessary, but just short-circuits in the
+ // "no-brainer" case. To test the complicated logic below, comment this out!
+ NSScreen* curScreen = [window screen];
+ if (newScreen == curScreen)
+ return YES;
+
+ // Worry a little: What happens when a window is on two (or more) screens?
+ // E.g., what happens in a 50-50 scenario? Cocoa may reasonably elect to zoom
+ // to the other screen rather than staying on the officially current one. So
+ // we compare overlaps with the current window frame, and see if Cocoa's
+ // choice was reasonable (allowing a small rounding error). This should
+ // hopefully avoid us ever erroneously denying a zoom when a window is on
+ // multiple screens.
+ NSRect curFrame = [window frame];
+ NSRect newScrIntersectCurFr = NSIntersectionRect([newScreen frame], curFrame);
+ NSRect curScrIntersectCurFr = NSIntersectionRect([curScreen frame], curFrame);
+ if (newScrIntersectCurFr.size.width*newScrIntersectCurFr.size.height >=
+ (curScrIntersectCurFr.size.width*curScrIntersectCurFr.size.height - 1.0))
+ return YES;
+
+ // If it wasn't reasonable, return NO.
+ return NO;
+}
+
+// Adjusts the window height by the given amount.
+- (void)adjustWindowHeightBy:(CGFloat)deltaH {
+ // By not adjusting the window height when initializing, we can ensure that
+ // the window opens with the same size that was saved on close.
+ if (initializing_ || [self isFullscreen] || deltaH == 0)
+ return;
+
+ NSWindow* window = [self window];
+ NSRect windowFrame = [window frame];
+ NSRect workarea = [[window screen] visibleFrame];
+
+ // If the window is not already fully in the workarea, do not adjust its frame
+ // at all.
+ if (!NSContainsRect(workarea, windowFrame))
+ return;
+
+ // Record the position of the top/bottom of the window, so we can easily check
+ // whether we grew the window upwards/downwards.
+ CGFloat oldWindowMaxY = NSMaxY(windowFrame);
+ CGFloat oldWindowMinY = NSMinY(windowFrame);
+
+ // We are "zoomed" if we occupy the full vertical space.
+ bool isZoomed = (windowFrame.origin.y == workarea.origin.y &&
+ windowFrame.size.height == workarea.size.height);
+
+ // If we're shrinking the window....
+ if (deltaH < 0) {
+ bool didChange = false;
+
+ // Don't reset if not currently zoomed since shrinking can take several
+ // steps!
+ if (isZoomed)
+ isShrinkingFromZoomed_ = YES;
+
+ // If we previously grew at the top, shrink as much as allowed at the top
+ // first.
+ if (windowTopGrowth_ > 0) {
+ CGFloat shrinkAtTopBy = MIN(-deltaH, windowTopGrowth_);
+ windowFrame.size.height -= shrinkAtTopBy; // Shrink the window.
+ deltaH += shrinkAtTopBy; // Update the amount left to shrink.
+ windowTopGrowth_ -= shrinkAtTopBy; // Update the growth state.
+ didChange = true;
+ }
+
+ // Similarly for the bottom (not an "else if" since we may have to
+ // simultaneously shrink at both the top and at the bottom). Note that
+ // |deltaH| may no longer be nonzero due to the above.
+ if (deltaH < 0 && windowBottomGrowth_ > 0) {
+ CGFloat shrinkAtBottomBy = MIN(-deltaH, windowBottomGrowth_);
+ windowFrame.origin.y += shrinkAtBottomBy; // Move the window up.
+ windowFrame.size.height -= shrinkAtBottomBy; // Shrink the window.
+ deltaH += shrinkAtBottomBy; // Update the amount left....
+ windowBottomGrowth_ -= shrinkAtBottomBy; // Update the growth state.
+ didChange = true;
+ }
+
+ // If we're shrinking from zoomed but we didn't change the top or bottom
+ // (since we've reached the limits imposed by |window...Growth_|), then stop
+ // here. Don't reset |isShrinkingFromZoomed_| since we might get called
+ // again for the same shrink.
+ if (isShrinkingFromZoomed_ && !didChange)
+ return;
+ } else {
+ isShrinkingFromZoomed_ = NO;
+
+ // Don't bother with anything else.
+ if (isZoomed)
+ return;
+ }
+
+ // Shrinking from zoomed is handled above (and is constrained by
+ // |window...Growth_|).
+ if (!isShrinkingFromZoomed_) {
+ // Resize the window down until it hits the bottom of the workarea, then if
+ // needed continue resizing upwards. Do not resize the window to be taller
+ // than the current workarea.
+ // Resize the window as requested, keeping the top left corner fixed.
+ windowFrame.origin.y -= deltaH;
+ windowFrame.size.height += deltaH;
+
+ // If the bottom left corner is now outside the visible frame, move the
+ // window up to make it fit, but make sure not to move the top left corner
+ // out of the visible frame.
+ if (windowFrame.origin.y < workarea.origin.y) {
+ windowFrame.origin.y = workarea.origin.y;
+ windowFrame.size.height =
+ std::min(windowFrame.size.height, workarea.size.height);
+ }
+
+ // Record (if applicable) how much we grew the window in either direction.
+ // (N.B.: These only record growth, not shrinkage.)
+ if (NSMaxY(windowFrame) > oldWindowMaxY)
+ windowTopGrowth_ += NSMaxY(windowFrame) - oldWindowMaxY;
+ if (NSMinY(windowFrame) < oldWindowMinY)
+ windowBottomGrowth_ += oldWindowMinY - NSMinY(windowFrame);
+ }
+
+ // Disable subview resizing while resizing the window, or else we will get
+ // unwanted renderer resizes. The calling code must call layoutSubviews to
+ // make things right again.
+ NSView* contentView = [window contentView];
+ [contentView setAutoresizesSubviews:NO];
+ [window setFrame:windowFrame display:NO];
+ [contentView setAutoresizesSubviews:YES];
+}
+
+// Main method to resize browser window subviews. This method should be called
+// when resizing any child of the content view, rather than resizing the views
+// directly. If the view is already the correct height, does not force a
+// relayout.
+- (void)resizeView:(NSView*)view newHeight:(CGFloat)height {
+ // We should only ever be called for one of the following four views.
+ // |downloadShelfController_| may be nil. If we are asked to size the bookmark
+ // bar directly, its superview must be this controller's content view.
+ DCHECK(view);
+ DCHECK(view == [toolbarController_ view] ||
+ view == [infoBarContainerController_ view] ||
+ view == [downloadShelfController_ view] ||
+ view == [bookmarkBarController_ view]);
+
+ // Change the height of the view and call |-layoutSubViews|. We set the height
+ // here without regard to where the view is on the screen or whether it needs
+ // to "grow up" or "grow down." The below call to |-layoutSubviews| will
+ // position each view correctly.
+ NSRect frame = [view frame];
+ if (NSHeight(frame) == height)
+ return;
+
+ // Grow or shrink the window by the amount of the height change. We adjust
+ // the window height only in two cases:
+ // 1) We are adjusting the height of the bookmark bar and it is currently
+ // animating either open or closed.
+ // 2) We are adjusting the height of the download shelf.
+ //
+ // We do not adjust the window height for bookmark bar changes on the NTP.
+ BOOL shouldAdjustBookmarkHeight =
+ [bookmarkBarController_ isAnimatingBetweenState:bookmarks::kHiddenState
+ andState:bookmarks::kShowingState];
+ if ((shouldAdjustBookmarkHeight && view == [bookmarkBarController_ view]) ||
+ view == [downloadShelfController_ view]) {
+ [[self window] disableScreenUpdatesUntilFlush];
+ CGFloat deltaH = height - frame.size.height;
+ [self adjustWindowHeightBy:deltaH];
+ }
+
+ frame.size.height = height;
+ // TODO(rohitrao): Determine if calling setFrame: twice is bad.
+ [view setFrame:frame];
+ [self layoutSubviews];
+}
+
+- (void)setAnimationInProgress:(BOOL)inProgress {
+ [[self tabContentArea] setFastResizeMode:inProgress];
+}
+
+// Update a toggle state for an NSMenuItem if modified.
+// Take care to ensure |item| looks like a NSMenuItem.
+// Called by validateUserInterfaceItem:.
+- (void)updateToggleStateWithTag:(NSInteger)tag forItem:(id)item {
+ if (![item respondsToSelector:@selector(state)] ||
+ ![item respondsToSelector:@selector(setState:)])
+ return;
+
+ // On Windows this logic happens in bookmark_bar_view.cc. On the
+ // Mac we're a lot more MVC happy so we've moved it into a
+ // controller. To be clear, this simply updates the menu item; it
+ // does not display the bookmark bar itself.
+ if (tag == IDC_SHOW_BOOKMARK_BAR) {
+ bool toggled = windowShim_->IsBookmarkBarVisible();
+ NSInteger oldState = [item state];
+ NSInteger newState = toggled ? NSOnState : NSOffState;
+ if (oldState != newState)
+ [item setState:newState];
+ }
+
+ // Update the checked/Unchecked state of items in the encoding menu.
+ // On Windows, this logic is part of |EncodingMenuModel| in
+ // browser/views/toolbar_view.h.
+ EncodingMenuController encoding_controller;
+ if (encoding_controller.DoesCommandBelongToEncodingMenu(tag)) {
+ DCHECK(browser_.get());
+ Profile* profile = browser_->profile();
+ DCHECK(profile);
+ TabContents* current_tab = browser_->GetSelectedTabContents();
+ if (!current_tab) {
+ return;
+ }
+ const std::string encoding = current_tab->encoding();
+
+ bool toggled = encoding_controller.IsItemChecked(profile, encoding, tag);
+ NSInteger oldState = [item state];
+ NSInteger newState = toggled ? NSOnState : NSOffState;
+ if (oldState != newState)
+ [item setState:newState];
+ }
+}
+
+- (BOOL)supportsFullscreen {
+ // TODO(avi, thakis): GTMWindowSheetController has no api to move
+ // tabsheets between windows. Until then, we have to prevent having to
+ // move a tabsheet between windows, e.g. no fullscreen toggling
+ NSArray* a = [[tabStripController_ sheetController] viewsWithAttachedSheets];
+ return [a count] == 0;
+}
+
+// Called to validate menu and toolbar items when this window is key. All the
+// items we care about have been set with the |-commandDispatch:| or
+// |-commandDispatchUsingKeyModifiers:| actions and a target of FirstResponder
+// in IB. If it's not one of those, let it continue up the responder chain to be
+// handled elsewhere. We pull out the tag as the cross-platform constant to
+// differentiate and dispatch the various commands.
+// NOTE: we might have to handle state for app-wide menu items,
+// although we could cheat and directly ask the app controller if our
+// command_updater doesn't support the command. This may or may not be an issue,
+// too early to tell.
+- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
+ SEL action = [item action];
+ BOOL enable = NO;
+ if (action == @selector(commandDispatch:) ||
+ action == @selector(commandDispatchUsingKeyModifiers:)) {
+ NSInteger tag = [item tag];
+ if (browser_->command_updater()->SupportsCommand(tag)) {
+ // Generate return value (enabled state)
+ enable = browser_->command_updater()->IsCommandEnabled(tag);
+ switch (tag) {
+ case IDC_CLOSE_TAB:
+ // Disable "close tab" if we're not the key window or if there's only
+ // one tab.
+ enable &= [self numberOfTabs] > 1 && [[self window] isKeyWindow];
+ break;
+ case IDC_FULLSCREEN: {
+ enable &= [self supportsFullscreen];
+ if ([static_cast<NSObject*>(item) isKindOfClass:[NSMenuItem class]]) {
+ NSString* menuTitle = l10n_util::GetNSString(
+ [self isFullscreen] ? IDS_EXIT_FULLSCREEN_MAC :
+ IDS_ENTER_FULLSCREEN_MAC);
+ [static_cast<NSMenuItem*>(item) setTitle:menuTitle];
+ }
+ break;
+ }
+ case IDC_SYNC_BOOKMARKS:
+ enable &= browser_->profile()->IsSyncAccessible();
+ sync_ui_util::UpdateSyncItem(item, enable, browser_->profile());
+ break;
+ default:
+ // Special handling for the contents of the Text Encoding submenu. On
+ // Mac OS, instead of enabling/disabling the top-level menu item, we
+ // enable/disable the submenu's contents (per Apple's HIG).
+ EncodingMenuController encoding_controller;
+ if (encoding_controller.DoesCommandBelongToEncodingMenu(tag)) {
+ enable &= browser_->command_updater()->IsCommandEnabled(
+ IDC_ENCODING_MENU) ? YES : NO;
+ }
+ }
+
+ // If the item is toggleable, find its toggle state and
+ // try to update it. This is a little awkward, but the alternative is
+ // to check after a commandDispatch, which seems worse.
+ [self updateToggleStateWithTag:tag forItem:item];
+ }
+ }
+ return enable;
+}
+
+// Called when the user picks a menu or toolbar item when this window is key.
+// Calls through to the browser object to execute the command. This assumes that
+// the command is supported and doesn't check, otherwise it would have been
+// disabled in the UI in validateUserInterfaceItem:.
+- (void)commandDispatch:(id)sender {
+ DCHECK(sender);
+ // Identify the actual BWC to which the command should be dispatched. It might
+ // belong to a background window, yet this controller gets it because it is
+ // the foreground window's controller and thus in the responder chain. Some
+ // senders don't have this problem (for example, menus only operate on the
+ // foreground window), so this is only an issue for senders that are part of
+ // windows.
+ BrowserWindowController* targetController = self;
+ if ([sender respondsToSelector:@selector(window)])
+ targetController = [[sender window] windowController];
+ DCHECK([targetController isKindOfClass:[BrowserWindowController class]]);
+ DCHECK(targetController->browser_.get());
+ targetController->browser_->ExecuteCommand([sender tag]);
+}
+
+// Same as |-commandDispatch:|, but executes commands using a disposition
+// determined by the key flags. If the window is in the background and the
+// command key is down, ignore the command key, but process any other modifiers.
+- (void)commandDispatchUsingKeyModifiers:(id)sender {
+ DCHECK(sender);
+ // See comment above for why we do this.
+ BrowserWindowController* targetController = self;
+ if ([sender respondsToSelector:@selector(window)])
+ targetController = [[sender window] windowController];
+ DCHECK([targetController isKindOfClass:[BrowserWindowController class]]);
+ NSInteger command = [sender tag];
+ NSUInteger modifierFlags = [[NSApp currentEvent] modifierFlags];
+ if ((command == IDC_RELOAD) &&
+ (modifierFlags & (NSShiftKeyMask | NSControlKeyMask))) {
+ command = IDC_RELOAD_IGNORING_CACHE;
+ // Mask off Shift and Control so they don't affect the disposition below.
+ modifierFlags &= ~(NSShiftKeyMask | NSControlKeyMask);
+ }
+ if (![[sender window] isMainWindow]) {
+ // Remove the command key from the flags, it means "keep the window in
+ // the background" in this case.
+ modifierFlags &= ~NSCommandKeyMask;
+ }
+ WindowOpenDisposition disposition =
+ event_utils::WindowOpenDispositionFromNSEventWithFlags(
+ [NSApp currentEvent], modifierFlags);
+ switch (command) {
+ case IDC_BACK:
+ case IDC_FORWARD:
+ case IDC_RELOAD:
+ case IDC_RELOAD_IGNORING_CACHE:
+ if (disposition == CURRENT_TAB) {
+ // Forcibly reset the location bar, since otherwise it won't discard any
+ // ongoing user edits, since it doesn't realize this is a user-initiated
+ // action.
+ [targetController locationBarBridge]->Revert();
+ }
+ }
+ DCHECK(targetController->browser_.get());
+ targetController->browser_->ExecuteCommandWithDisposition(command,
+ disposition);
+}
+
+// Called when another part of the internal codebase needs to execute a
+// command.
+- (void)executeCommand:(int)command {
+ browser_->ExecuteCommandIfEnabled(command);
+}
+
+// StatusBubble delegate method: tell the status bubble the frame it should
+// position itself in.
+- (NSRect)statusBubbleBaseFrame {
+ NSView* view = [previewableContentsController_ view];
+ return [view convertRect:[view bounds] toView:nil];
+}
+
+- (GTMWindowSheetController*)sheetController {
+ return [tabStripController_ sheetController];
+}
+
+- (void)updateToolbarWithContents:(TabContents*)tab
+ shouldRestoreState:(BOOL)shouldRestore {
+ [toolbarController_ updateToolbarWithContents:tab
+ shouldRestoreState:shouldRestore];
+}
+
+- (void)setStarredState:(BOOL)isStarred {
+ [toolbarController_ setStarredState:isStarred];
+}
+
+// Accept tabs from a BrowserWindowController with the same Profile.
+- (BOOL)canReceiveFrom:(TabWindowController*)source {
+ if (![source isKindOfClass:[BrowserWindowController class]]) {
+ return NO;
+ }
+
+ BrowserWindowController* realSource =
+ static_cast<BrowserWindowController*>(source);
+ if (browser_->profile() != realSource->browser_->profile()) {
+ return NO;
+ }
+
+ // Can't drag a tab from a normal browser to a pop-up
+ if (browser_->type() != realSource->browser_->type()) {
+ return NO;
+ }
+
+ return YES;
+}
+
+// Move a given tab view to the location of the current placeholder. If there is
+// no placeholder, it will go at the end. |controller| is the window controller
+// of a tab being dropped from a different window. It will be nil if the drag is
+// within the window, otherwise the tab is removed from that window before being
+// placed into this one. The implementation will call |-removePlaceholder| since
+// the drag is now complete. This also calls |-layoutTabs| internally so
+// clients do not need to call it again.
+- (void)moveTabView:(NSView*)view
+ fromController:(TabWindowController*)dragController {
+ if (dragController) {
+ // Moving between windows. Figure out the TabContents to drop into our tab
+ // model from the source window's model.
+ BOOL isBrowser =
+ [dragController isKindOfClass:[BrowserWindowController class]];
+ DCHECK(isBrowser);
+ if (!isBrowser) return;
+ BrowserWindowController* dragBWC = (BrowserWindowController*)dragController;
+ int index = [dragBWC->tabStripController_ modelIndexForTabView:view];
+ TabContentsWrapper* contents =
+ dragBWC->browser_->GetTabContentsWrapperAt(index);
+ // The tab contents may have gone away if given a window.close() while it
+ // is being dragged. If so, bail, we've got nothing to drop.
+ if (!contents)
+ return;
+
+ // Convert |view|'s frame (which starts in the source tab strip's coordinate
+ // system) to the coordinate system of the destination tab strip. This needs
+ // to be done before being detached so the window transforms can be
+ // performed.
+ NSRect destinationFrame = [view frame];
+ NSPoint tabOrigin = destinationFrame.origin;
+ tabOrigin = [[dragController tabStripView] convertPoint:tabOrigin
+ toView:nil];
+ tabOrigin = [[view window] convertBaseToScreen:tabOrigin];
+ tabOrigin = [[self window] convertScreenToBase:tabOrigin];
+ tabOrigin = [[self tabStripView] convertPoint:tabOrigin fromView:nil];
+ destinationFrame.origin = tabOrigin;
+
+ // Before the tab is detached from its originating tab strip, store the
+ // pinned state so that it can be maintained between the windows.
+ bool isPinned = dragBWC->browser_->tabstrip_model()->IsTabPinned(index);
+
+ // Now that we have enough information about the tab, we can remove it from
+ // the dragging window. We need to do this *before* we add it to the new
+ // window as this will remove the TabContents' delegate.
+ [dragController detachTabView:view];
+
+ // Deposit it into our model at the appropriate location (it already knows
+ // where it should go from tracking the drag). Doing this sets the tab's
+ // delegate to be the Browser.
+ [tabStripController_ dropTabContents:contents
+ withFrame:destinationFrame
+ asPinnedTab:isPinned];
+ } else {
+ // Moving within a window.
+ int index = [tabStripController_ modelIndexForTabView:view];
+ [tabStripController_ moveTabFromIndex:index];
+ }
+
+ // Remove the placeholder since the drag is now complete.
+ [self removePlaceholder];
+}
+
+// Tells the tab strip to forget about this tab in preparation for it being
+// put into a different tab strip, such as during a drop on another window.
+- (void)detachTabView:(NSView*)view {
+ int index = [tabStripController_ modelIndexForTabView:view];
+ browser_->tabstrip_model()->DetachTabContentsAt(index);
+}
+
+- (NSView*)selectedTabView {
+ return [tabStripController_ selectedTabView];
+}
+
+- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force {
+ [toolbarController_ setIsLoading:isLoading force:force];
+}
+
+// Make the location bar the first responder, if possible.
+- (void)focusLocationBar:(BOOL)selectAll {
+ [toolbarController_ focusLocationBar:selectAll];
+}
+
+- (void)focusTabContents {
+ [[self window] makeFirstResponder:[tabStripController_ selectedTabView]];
+}
+
+- (void)layoutTabs {
+ [tabStripController_ layoutTabs];
+}
+
+- (TabWindowController*)detachTabToNewWindow:(TabView*)tabView {
+ // Disable screen updates so that this appears as a single visual change.
+ app::mac::ScopedNSDisableScreenUpdates disabler;
+
+ // Fetch the tab contents for the tab being dragged.
+ int index = [tabStripController_ modelIndexForTabView:tabView];
+ TabContentsWrapper* contents = browser_->GetTabContentsWrapperAt(index);
+
+ // Set the window size. Need to do this before we detach the tab so it's
+ // still in the window. We have to flip the coordinates as that's what
+ // is expected by the Browser code.
+ NSWindow* sourceWindow = [tabView window];
+ NSRect windowRect = [sourceWindow frame];
+ NSScreen* screen = [sourceWindow screen];
+ windowRect.origin.y =
+ [screen frame].size.height - windowRect.size.height -
+ windowRect.origin.y;
+ gfx::Rect browserRect(windowRect.origin.x, windowRect.origin.y,
+ windowRect.size.width, windowRect.size.height);
+
+ NSRect sourceTabRect = [tabView frame];
+ NSView* tabStrip = [self tabStripView];
+
+ // Pushes tabView's frame back inside the tabstrip.
+ NSSize tabOverflow =
+ [self overflowFrom:[tabStrip convertRectToBase:sourceTabRect]
+ to:[tabStrip frame]];
+ NSRect tabRect = NSOffsetRect(sourceTabRect,
+ -tabOverflow.width, -tabOverflow.height);
+
+ // Before detaching the tab, store the pinned state.
+ bool isPinned = browser_->tabstrip_model()->IsTabPinned(index);
+
+ // Detach it from the source window, which just updates the model without
+ // deleting the tab contents. This needs to come before creating the new
+ // Browser because it clears the TabContents' delegate, which gets hooked
+ // up during creation of the new window.
+ browser_->tabstrip_model()->DetachTabContentsAt(index);
+
+ // Create the new window with a single tab in its model, the one being
+ // dragged.
+ DockInfo dockInfo;
+ Browser* newBrowser = browser_->tabstrip_model()->delegate()->
+ CreateNewStripWithContents(contents, browserRect, dockInfo, false);
+
+ // Propagate the tab pinned state of the new tab (which is the only tab in
+ // this new window).
+ newBrowser->tabstrip_model()->SetTabPinned(0, isPinned);
+
+ // Get the new controller by asking the new window for its delegate.
+ BrowserWindowController* controller =
+ reinterpret_cast<BrowserWindowController*>(
+ [newBrowser->window()->GetNativeHandle() delegate]);
+ DCHECK(controller && [controller isKindOfClass:[TabWindowController class]]);
+
+ // Force the added tab to the right size (remove stretching.)
+ tabRect.size.height = [TabStripController defaultTabHeight];
+
+ // And make sure we use the correct frame in the new view.
+ [[controller tabStripController] setFrameOfSelectedTab:tabRect];
+ return controller;
+}
+
+- (void)insertPlaceholderForTab:(TabView*)tab
+ frame:(NSRect)frame
+ yStretchiness:(CGFloat)yStretchiness {
+ [super insertPlaceholderForTab:tab frame:frame yStretchiness:yStretchiness];
+ [tabStripController_ insertPlaceholderForTab:tab
+ frame:frame
+ yStretchiness:yStretchiness];
+}
+
+- (void)removePlaceholder {
+ [super removePlaceholder];
+ [tabStripController_ insertPlaceholderForTab:nil
+ frame:NSZeroRect
+ yStretchiness:0];
+}
+
+- (BOOL)isDragSessionActive {
+ // The tab can be dragged within the existing tab strip or detached
+ // into its own window (then the overlay window will be present).
+ return [[self tabStripController] isDragSessionActive] ||
+ [self overlayWindow] != nil;
+}
+
+- (BOOL)tabDraggingAllowed {
+ return [tabStripController_ tabDraggingAllowed];
+}
+
+- (BOOL)tabTearingAllowed {
+ return ![self isFullscreen];
+}
+
+- (BOOL)windowMovementAllowed {
+ return ![self isFullscreen];
+}
+
+- (BOOL)isTabFullyVisible:(TabView*)tab {
+ return [tabStripController_ isTabFullyVisible:tab];
+}
+
+- (void)showNewTabButton:(BOOL)show {
+ [tabStripController_ showNewTabButton:show];
+}
+
+- (BOOL)isBookmarkBarVisible {
+ return [bookmarkBarController_ isVisible];
+}
+
+- (BOOL)isBookmarkBarAnimating {
+ return [bookmarkBarController_ isAnimationRunning];
+}
+
+- (void)updateBookmarkBarVisibilityWithAnimation:(BOOL)animate {
+ [bookmarkBarController_
+ updateAndShowNormalBar:[self shouldShowBookmarkBar]
+ showDetachedBar:[self shouldShowDetachedBookmarkBar]
+ withAnimation:animate];
+}
+
+- (BOOL)isDownloadShelfVisible {
+ return downloadShelfController_ != nil &&
+ [downloadShelfController_ isVisible];
+}
+
+- (DownloadShelfController*)downloadShelf {
+ if (!downloadShelfController_.get()) {
+ downloadShelfController_.reset([[DownloadShelfController alloc]
+ initWithBrowser:browser_.get() resizeDelegate:self]);
+ [[[self window] contentView] addSubview:[downloadShelfController_ view]];
+ [downloadShelfController_ show:nil];
+ }
+ return downloadShelfController_;
+}
+
+- (void)addFindBar:(FindBarCocoaController*)findBarCocoaController {
+ // Shouldn't call addFindBar twice.
+ DCHECK(!findBarCocoaController_.get());
+
+ // Create a controller for the findbar.
+ findBarCocoaController_.reset([findBarCocoaController retain]);
+ NSView *contentView = [[self window] contentView];
+ [contentView addSubview:[findBarCocoaController_ view]
+ positioned:NSWindowAbove
+ relativeTo:[toolbarController_ view]];
+
+ // Place the find bar immediately below the toolbar/attached bookmark bar. In
+ // fullscreen mode, it hangs off the top of the screen when the bar is hidden.
+ CGFloat maxY = [self placeBookmarkBarBelowInfoBar] ?
+ NSMinY([[toolbarController_ view] frame]) :
+ NSMinY([[bookmarkBarController_ view] frame]);
+ CGFloat maxWidth = NSWidth([contentView frame]);
+ [findBarCocoaController_ positionFindBarViewAtMaxY:maxY maxWidth:maxWidth];
+}
+
+- (NSWindow*)createFullscreenWindow {
+ return [[[FullscreenWindow alloc] initForScreen:[[self window] screen]]
+ autorelease];
+}
+
+- (NSInteger)numberOfTabs {
+ // count() includes pinned tabs.
+ return browser_->tabstrip_model()->count();
+}
+
+- (BOOL)hasLiveTabs {
+ return !browser_->tabstrip_model()->empty();
+}
+
+- (NSString*)selectedTabTitle {
+ TabContents* contents = browser_->GetSelectedTabContents();
+ return base::SysUTF16ToNSString(contents->GetTitle());
+}
+
+- (NSRect)regularWindowFrame {
+ return [self isFullscreen] ? [savedRegularWindow_ frame] :
+ [[self window] frame];
+}
+
+// (Override of |TabWindowController| method.)
+- (BOOL)hasTabStrip {
+ return [self supportsWindowFeature:Browser::FEATURE_TABSTRIP];
+}
+
+// TabContentsControllerDelegate protocol.
+- (void)tabContentsViewFrameWillChange:(TabContentsController*)source
+ frameRect:(NSRect)frameRect {
+ TabContents* contents = [source tabContents];
+ RenderWidgetHostView* render_widget_host_view = contents ?
+ contents->GetRenderWidgetHostView() : NULL;
+ if (!render_widget_host_view)
+ return;
+
+ gfx::Rect reserved_rect;
+
+ NSWindow* window = [self window];
+ if ([window respondsToSelector:@selector(_growBoxRect)]) {
+ NSView* view = [source view];
+ if (view && [view superview]) {
+ NSRect windowGrowBoxRect = [window _growBoxRect];
+ NSRect viewRect = [[view superview] convertRect:frameRect toView:nil];
+ NSRect growBoxRect = NSIntersectionRect(windowGrowBoxRect, viewRect);
+ if (!NSIsEmptyRect(growBoxRect)) {
+ // Before we return a rect, we need to convert it from window
+ // coordinates to content area coordinates and flip the coordinate
+ // system.
+ // Superview is used here because, first, it's a frame rect, so it is
+ // specified in the parent's coordinates and, second, view is not
+ // positioned yet.
+ growBoxRect = [[view superview] convertRect:growBoxRect fromView:nil];
+ growBoxRect.origin.y =
+ NSHeight(frameRect) - NSHeight(growBoxRect);
+ growBoxRect =
+ NSOffsetRect(growBoxRect, -frameRect.origin.x, -frameRect.origin.y);
+
+ reserved_rect =
+ gfx::Rect(growBoxRect.origin.x, growBoxRect.origin.y,
+ growBoxRect.size.width, growBoxRect.size.height);
+ }
+ }
+ }
+
+ render_widget_host_view->set_reserved_contents_rect(reserved_rect);
+}
+
+// TabStripControllerDelegate protocol.
+- (void)onSelectTabWithContents:(TabContents*)contents {
+ // Update various elements that are interested in knowing the current
+ // TabContents.
+
+ // Update all the UI bits.
+ windowShim_->UpdateTitleBar();
+
+ [sidebarController_ updateSidebarForTabContents:contents];
+ [devToolsController_ updateDevToolsForTabContents:contents];
+
+ // Update the bookmark bar.
+ // Must do it after sidebar and devtools update, otherwise bookmark bar might
+ // call resizeView -> layoutSubviews and cause unnecessary relayout.
+ // TODO(viettrungluu): perhaps update to not terminate running animations (if
+ // applicable)?
+ [self updateBookmarkBarVisibilityWithAnimation:NO];
+
+ [infoBarContainerController_ changeTabContents:contents];
+
+ // Update devTools and sidebar contents after size for all views is set.
+ [sidebarController_ ensureContentsVisible];
+ [devToolsController_ ensureContentsVisible];
+}
+
+- (void)onReplaceTabWithContents:(TabContents*)contents {
+ // This is only called when instant results are committed. Simply remove the
+ // preview view; the tab strip controller will reinstall the view as the
+ // active view.
+ [previewableContentsController_ hidePreview];
+ [self updateBookmarkBarVisibilityWithAnimation:NO];
+}
+
+- (void)onSelectedTabChange:(TabStripModelObserver::TabChangeType)change {
+ // Update titles if this is the currently selected tab and if it isn't just
+ // the loading state which changed.
+ if (change != TabStripModelObserver::LOADING_ONLY)
+ windowShim_->UpdateTitleBar();
+
+ // Update the bookmark bar if this is the currently selected tab and if it
+ // isn't just the title which changed. This for transitions between the NTP
+ // (showing its floating bookmark bar) and normal web pages (showing no
+ // bookmark bar).
+ // TODO(viettrungluu): perhaps update to not terminate running animations?
+ if (change != TabStripModelObserver::TITLE_NOT_LOADING)
+ [self updateBookmarkBarVisibilityWithAnimation:NO];
+}
+
+- (void)onTabDetachedWithContents:(TabContents*)contents {
+ [infoBarContainerController_ tabDetachedWithContents:contents];
+}
+
+- (void)userChangedTheme {
+ // TODO(dmaclach): Instead of redrawing the whole window, views that care
+ // about the active window state should be registering for notifications.
+ [[self window] setViewsNeedDisplay:YES];
+}
+
+- (ThemeProvider*)themeProvider {
+ return browser_->profile()->GetThemeProvider();
+}
+
+- (ThemedWindowStyle)themedWindowStyle {
+ ThemedWindowStyle style = 0;
+ if (browser_->profile()->IsOffTheRecord())
+ style |= THEMED_INCOGNITO;
+
+ Browser::Type type = browser_->type();
+ if (type == Browser::TYPE_POPUP)
+ style |= THEMED_POPUP;
+ else if (type == Browser::TYPE_DEVTOOLS)
+ style |= THEMED_DEVTOOLS;
+
+ return style;
+}
+
+- (NSPoint)themePatternPhase {
+ // Our patterns want to be drawn from the upper left hand corner of the view.
+ // Cocoa wants to do it from the lower left of the window.
+ //
+ // Rephase our pattern to fit this view. Some other views (Tabs, Toolbar etc.)
+ // will phase their patterns relative to this so all the views look right.
+ //
+ // To line up the background pattern with the pattern in the browser window
+ // the background pattern for the tabs needs to be moved left by 5 pixels.
+ const CGFloat kPatternHorizontalOffset = -5;
+ NSView* tabStripView = [self tabStripView];
+ NSRect tabStripViewWindowBounds = [tabStripView bounds];
+ NSView* windowChromeView = [[[self window] contentView] superview];
+ tabStripViewWindowBounds =
+ [tabStripView convertRect:tabStripViewWindowBounds
+ toView:windowChromeView];
+ NSPoint phase = NSMakePoint(NSMinX(tabStripViewWindowBounds)
+ + kPatternHorizontalOffset,
+ NSMinY(tabStripViewWindowBounds)
+ + [TabStripController defaultTabHeight]);
+ return phase;
+}
+
+- (NSPoint)bookmarkBubblePoint {
+ return [toolbarController_ bookmarkBubblePoint];
+}
+
+// Show the bookmark bubble (e.g. user just clicked on the STAR).
+- (void)showBookmarkBubbleForURL:(const GURL&)url
+ alreadyBookmarked:(BOOL)alreadyMarked {
+ if (!bookmarkBubbleController_) {
+ BookmarkModel* model = browser_->profile()->GetBookmarkModel();
+ const BookmarkNode* node = model->GetMostRecentlyAddedNodeForURL(url);
+ bookmarkBubbleController_ =
+ [[BookmarkBubbleController alloc] initWithParentWindow:[self window]
+ model:model
+ node:node
+ alreadyBookmarked:alreadyMarked];
+ [bookmarkBubbleController_ showWindow:self];
+ NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+ [center addObserver:self
+ selector:@selector(bubbleWindowWillClose:)
+ name:NSWindowWillCloseNotification
+ object:[bookmarkBubbleController_ window]];
+ }
+}
+
+// Nil out the weak bookmark bubble controller reference.
+- (void)bubbleWindowWillClose:(NSNotification*)notification {
+ DCHECK([notification object] == [bookmarkBubbleController_ window]);
+ NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+ [center removeObserver:self
+ name:NSWindowWillCloseNotification
+ object:[bookmarkBubbleController_ window]];
+ bookmarkBubbleController_ = nil;
+}
+
+// Handle the editBookmarkNode: action sent from bookmark bubble controllers.
+- (void)editBookmarkNode:(id)sender {
+ BOOL responds = [sender respondsToSelector:@selector(node)];
+ DCHECK(responds);
+ if (responds) {
+ const BookmarkNode* node = [sender node];
+ if (node) {
+ // A BookmarkEditorController is a sheet that owns itself, and
+ // deallocates itself when closed.
+ [[[BookmarkEditorController alloc]
+ initWithParentWindow:[self window]
+ profile:browser_->profile()
+ parent:node->GetParent()
+ node:node
+ configuration:BookmarkEditor::SHOW_TREE]
+ runAsModalSheet];
+ }
+ }
+}
+
+// If the browser is in incognito mode, install the image view to decorate
+// the window at the upper right. Use the same base y coordinate as the
+// tab strip.
+- (void)installIncognitoBadge {
+ // Only install if this browser window is OTR and has a tab strip.
+ if (!browser_->profile()->IsOffTheRecord() || ![self hasTabStrip])
+ return;
+
+ // Install the image into the badge view and size the view appropriately.
+ // Hide it for now; positioning and showing will be done by the layout code.
+ NSImage* image = app::mac::GetCachedImageWithName(@"otr_icon.pdf");
+ incognitoBadge_.reset([[IncognitoImageView alloc] init]);
+ [incognitoBadge_ setImage:image];
+ [incognitoBadge_ setFrameSize:[image size]];
+ [incognitoBadge_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
+ [incognitoBadge_ setHidden:YES];
+
+ // Install the view.
+ [[[[self window] contentView] superview] addSubview:incognitoBadge_];
+}
+
+// Documented in 10.6+, but present starting in 10.5. Called when we get a
+// three-finger swipe.
+- (void)swipeWithEvent:(NSEvent*)event {
+ // Map forwards and backwards to history; left is positive, right is negative.
+ unsigned int command = 0;
+ if ([event deltaX] > 0.5) {
+ command = IDC_BACK;
+ } else if ([event deltaX] < -0.5) {
+ command = IDC_FORWARD;
+ } else if ([event deltaY] > 0.5) {
+ // TODO(pinkerton): figure out page-up, http://crbug.com/16305
+ } else if ([event deltaY] < -0.5) {
+ // TODO(pinkerton): figure out page-down, http://crbug.com/16305
+ browser_->ExecuteCommand(IDC_TABPOSE);
+ }
+
+ // Ensure the command is valid first (ExecuteCommand() won't do that) and
+ // then make it so.
+ if (browser_->command_updater()->IsCommandEnabled(command))
+ browser_->ExecuteCommandWithDisposition(command,
+ event_utils::WindowOpenDispositionFromNSEvent(event));
+}
+
+// Documented in 10.6+, but present starting in 10.5. Called repeatedly during
+// a pinch gesture, with incremental change values.
+- (void)magnifyWithEvent:(NSEvent*)event {
+ // The deltaZ difference necessary to trigger a zoom action. Derived from
+ // experimentation to find a value that feels reasonable.
+ const float kZoomStepValue = 150;
+
+ // Find the (absolute) thresholds on either side of the current zoom factor,
+ // then convert those to actual numbers to trigger a zoom in or out.
+ // This logic deliberately makes the range around the starting zoom value for
+ // the gesture twice as large as the other ranges (i.e., the notches are at
+ // ..., -3*step, -2*step, -step, step, 2*step, 3*step, ... but not at 0)
+ // so that it's easier to get back to your starting point than it is to
+ // overshoot.
+ float nextStep = (abs(currentZoomStepDelta_) + 1) * kZoomStepValue;
+ float backStep = abs(currentZoomStepDelta_) * kZoomStepValue;
+ float zoomInThreshold = (currentZoomStepDelta_ >= 0) ? nextStep : -backStep;
+ float zoomOutThreshold = (currentZoomStepDelta_ <= 0) ? -nextStep : backStep;
+
+ unsigned int command = 0;
+ totalMagnifyGestureAmount_ += [event deltaZ];
+ if (totalMagnifyGestureAmount_ > zoomInThreshold) {
+ command = IDC_ZOOM_PLUS;
+ } else if (totalMagnifyGestureAmount_ < zoomOutThreshold) {
+ command = IDC_ZOOM_MINUS;
+ }
+
+ if (command && browser_->command_updater()->IsCommandEnabled(command)) {
+ currentZoomStepDelta_ += (command == IDC_ZOOM_PLUS) ? 1 : -1;
+ browser_->ExecuteCommandWithDisposition(command,
+ event_utils::WindowOpenDispositionFromNSEvent(event));
+ }
+}
+
+// Documented in 10.6+, but present starting in 10.5. Called at the beginning
+// of a gesture.
+- (void)beginGestureWithEvent:(NSEvent*)event {
+ totalMagnifyGestureAmount_ = 0;
+ currentZoomStepDelta_ = 0;
+}
+
+// Delegate method called when window is resized.
+- (void)windowDidResize:(NSNotification*)notification {
+ // Resize (and possibly move) the status bubble. Note that we may get called
+ // when the status bubble does not exist.
+ if (statusBubble_) {
+ statusBubble_->UpdateSizeAndPosition();
+ }
+
+ // Let the selected RenderWidgetHostView know, so that it can tell plugins.
+ if (TabContents* contents = browser_->GetSelectedTabContents()) {
+ if (RenderWidgetHostView* rwhv = contents->GetRenderWidgetHostView())
+ rwhv->WindowFrameChanged();
+ }
+}
+
+// Handle the openLearnMoreAboutCrashLink: action from SadTabController when
+// "Learn more" link in "Aw snap" page (i.e. crash page or sad tab) is
+// clicked. Decoupling the action from its target makes unitestting possible.
+- (void)openLearnMoreAboutCrashLink:(id)sender {
+ if ([sender isKindOfClass:[SadTabController class]]) {
+ SadTabController* sad_tab = static_cast<SadTabController*>(sender);
+ TabContents* tab_contents = [sad_tab tabContents];
+ if (tab_contents) {
+ GURL helpUrl =
+ google_util::AppendGoogleLocaleParam(GURL(chrome::kCrashReasonURL));
+ tab_contents->OpenURL(helpUrl, GURL(), CURRENT_TAB, PageTransition::LINK);
+ }
+ }
+}
+
+// Delegate method called when window did move. (See below for why we don't use
+// |-windowWillMove:|, which is called less frequently than |-windowDidMove|
+// instead.)
+- (void)windowDidMove:(NSNotification*)notification {
+ NSWindow* window = [self window];
+ NSRect windowFrame = [window frame];
+ NSRect workarea = [[window screen] visibleFrame];
+
+ // We reset the window growth state whenever the window is moved out of the
+ // work area or away (up or down) from the bottom or top of the work area.
+ // Unfortunately, Cocoa sends |-windowWillMove:| too frequently (including
+ // when clicking on the title bar to activate), and of course
+ // |-windowWillMove| is called too early for us to apply our heuristic. (The
+ // heuristic we use for detecting window movement is that if |windowTopGrowth_
+ // > 0|, then we should be at the bottom of the work area -- if we're not,
+ // we've moved. Similarly for the other side.)
+ if (!NSContainsRect(workarea, windowFrame) ||
+ (windowTopGrowth_ > 0 && NSMinY(windowFrame) != NSMinY(workarea)) ||
+ (windowBottomGrowth_ > 0 && NSMaxY(windowFrame) != NSMaxY(workarea)))
+ [self resetWindowGrowthState];
+
+ // Let the selected RenderWidgetHostView know, so that it can tell plugins.
+ if (TabContents* contents = browser_->GetSelectedTabContents()) {
+ if (RenderWidgetHostView* rwhv = contents->GetRenderWidgetHostView())
+ rwhv->WindowFrameChanged();
+ }
+}
+
+// Delegate method called when window will be resized; not called for
+// |-setFrame:display:|.
+- (NSSize)windowWillResize:(NSWindow*)sender toSize:(NSSize)frameSize {
+ [self resetWindowGrowthState];
+ return frameSize;
+}
+
+// Delegate method: see |NSWindowDelegate| protocol.
+- (id)windowWillReturnFieldEditor:(NSWindow*)sender toObject:(id)obj {
+ // Ask the toolbar controller if it wants to return a custom field editor
+ // for the specific object.
+ return [toolbarController_ customFieldEditorForObject:obj];
+}
+
+// (Needed for |BookmarkBarControllerDelegate| protocol.)
+- (void)bookmarkBar:(BookmarkBarController*)controller
+ didChangeFromState:(bookmarks::VisualState)oldState
+ toState:(bookmarks::VisualState)newState {
+ [toolbarController_
+ setDividerOpacity:[bookmarkBarController_ toolbarDividerOpacity]];
+ [self adjustToolbarAndBookmarkBarForCompression:
+ [controller getDesiredToolbarHeightCompression]];
+}
+
+// (Needed for |BookmarkBarControllerDelegate| protocol.)
+- (void)bookmarkBar:(BookmarkBarController*)controller
+willAnimateFromState:(bookmarks::VisualState)oldState
+ toState:(bookmarks::VisualState)newState {
+ [toolbarController_
+ setDividerOpacity:[bookmarkBarController_ toolbarDividerOpacity]];
+ [self adjustToolbarAndBookmarkBarForCompression:
+ [controller getDesiredToolbarHeightCompression]];
+}
+
+// (Private/TestingAPI)
+- (void)resetWindowGrowthState {
+ windowTopGrowth_ = 0;
+ windowBottomGrowth_ = 0;
+ isShrinkingFromZoomed_ = NO;
+}
+
+- (NSSize)overflowFrom:(NSRect)source
+ to:(NSRect)target {
+ // If |source|'s boundary is outside of |target|'s, set its distance
+ // to |x|. Note that |source| can overflow to both side, but we
+ // have nothing to do for such case.
+ CGFloat x = 0;
+ if (NSMaxX(target) < NSMaxX(source)) // |source| overflows to right
+ x = NSMaxX(source) - NSMaxX(target);
+ else if (NSMinX(source) < NSMinX(target)) // |source| overflows to left
+ x = NSMinX(source) - NSMinX(target);
+
+ // Same as |x| above.
+ CGFloat y = 0;
+ if (NSMaxY(target) < NSMaxY(source))
+ y = NSMaxY(source) - NSMaxY(target);
+ else if (NSMinY(source) < NSMinY(target))
+ y = NSMinY(source) - NSMinY(target);
+
+ return NSMakeSize(x, y);
+}
+
+// Override to swap in the correct tab strip controller based on the new
+// tab strip mode.
+- (void)toggleTabStripDisplayMode {
+ [super toggleTabStripDisplayMode];
+ [self createTabStripController];
+}
+
+- (BOOL)useVerticalTabs {
+ return browser_->tabstrip_model()->delegate()->UseVerticalTabs();
+}
+
+- (void)showInstant:(TabContents*)previewContents {
+ [previewableContentsController_ showPreview:previewContents];
+ [self updateBookmarkBarVisibilityWithAnimation:NO];
+}
+
+- (void)hideInstant {
+ // TODO(rohitrao): Revisit whether or not this method should be called when
+ // instant isn't showing.
+ if (![previewableContentsController_ isShowingPreview])
+ return;
+
+ [previewableContentsController_ hidePreview];
+ [self updateBookmarkBarVisibilityWithAnimation:NO];
+}
+
+- (NSRect)instantFrame {
+ // The view's bounds are in its own coordinate system. Convert that to the
+ // window base coordinate system, then translate it into the screen's
+ // coordinate system.
+ NSView* view = [previewableContentsController_ view];
+ if (!view)
+ return NSZeroRect;
+
+ NSRect frame = [view convertRect:[view bounds] toView:nil];
+ NSPoint originInScreenCoords =
+ [[view window] convertBaseToScreen:frame.origin];
+ frame.origin = originInScreenCoords;
+ return frame;
+}
+
+- (void)sheetDidEnd:(NSWindow*)sheet
+ returnCode:(NSInteger)code
+ context:(void*)context {
+ [sheet orderOut:self];
+}
+
+@end // @implementation BrowserWindowController
+
+
+@implementation BrowserWindowController(Fullscreen)
+
+- (void)setFullscreen:(BOOL)fullscreen {
+ // The logic in this function is a bit complicated and very carefully
+ // arranged. See the below comments for more details.
+
+ if (fullscreen == [self isFullscreen])
+ return;
+
+ if (![self supportsFullscreen])
+ return;
+
+ // Fade to black.
+ const CGDisplayReservationInterval kFadeDurationSeconds = 0.6;
+ Boolean didFadeOut = NO;
+ CGDisplayFadeReservationToken token;
+ if (CGAcquireDisplayFadeReservation(kFadeDurationSeconds, &token)
+ == kCGErrorSuccess) {
+ didFadeOut = YES;
+ CGDisplayFade(token, kFadeDurationSeconds / 2, kCGDisplayBlendNormal,
+ kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, /*synchronous=*/true);
+ }
+
+ // Close the bookmark bubble, if it's open. We use |-ok:| instead of
+ // |-cancel:| or |-close| because that matches the behavior when the bubble
+ // loses key status.
+ [bookmarkBubbleController_ ok:self];
+
+ // Save the current first responder so we can restore after views are moved.
+ NSWindow* window = [self window];
+ scoped_nsobject<FocusTracker> focusTracker(
+ [[FocusTracker alloc] initWithWindow:window]);
+ BOOL showDropdown = [self floatingBarHasFocus];
+
+ // While we move views (and focus) around, disable any bar visibility changes.
+ [self disableBarVisibilityUpdates];
+
+ // If we're entering fullscreen, create the fullscreen controller. If we're
+ // exiting fullscreen, kill the controller.
+ if (fullscreen) {
+ fullscreenController_.reset([[FullscreenController alloc]
+ initWithBrowserController:self]);
+ } else {
+ [fullscreenController_ exitFullscreen];
+ fullscreenController_.reset();
+ }
+
+ // Destroy the tab strip's sheet controller. We will recreate it in the new
+ // window when needed.
+ [tabStripController_ destroySheetController];
+
+ // Retain the tab strip view while we remove it from its superview.
+ scoped_nsobject<NSView> tabStripView;
+ if ([self hasTabStrip] && ![self useVerticalTabs]) {
+ tabStripView.reset([[self tabStripView] retain]);
+ [tabStripView removeFromSuperview];
+ }
+
+ // Ditto for the content view.
+ scoped_nsobject<NSView> contentView([[window contentView] retain]);
+ // Disable autoresizing of subviews while we move views around. This prevents
+ // spurious renderer resizes.
+ [contentView setAutoresizesSubviews:NO];
+ [contentView removeFromSuperview];
+
+ NSWindow* destWindow = nil;
+ if (fullscreen) {
+ DCHECK(!savedRegularWindow_);
+ savedRegularWindow_ = [window retain];
+ destWindow = [self createFullscreenWindow];
+ } else {
+ DCHECK(savedRegularWindow_);
+ destWindow = [savedRegularWindow_ autorelease];
+ savedRegularWindow_ = nil;
+
+ CGSWorkspaceID workspace;
+ if ([window cr_workspace:&workspace]) {
+ [destWindow cr_moveToWorkspace:workspace];
+ }
+ }
+ DCHECK(destWindow);
+
+ // Have to do this here, otherwise later calls can crash because the window
+ // has no delegate.
+ [window setDelegate:nil];
+ [destWindow setDelegate:self];
+
+ // With this call, valgrind complains that a "Conditional jump or move depends
+ // on uninitialised value(s)". The error happens in -[NSThemeFrame
+ // drawOverlayRect:]. I'm pretty convinced this is an Apple bug, but there is
+ // no visual impact. I have been unable to tickle it away with other window
+ // or view manipulation Cocoa calls. Stack added to suppressions_mac.txt.
+ [contentView setAutoresizesSubviews:YES];
+ [destWindow setContentView:contentView];
+
+ // Move the incognito badge if present.
+ if (incognitoBadge_.get()) {
+ [incognitoBadge_ removeFromSuperview];
+ [incognitoBadge_ setHidden:YES]; // Will be shown in layout.
+ [[[destWindow contentView] superview] addSubview:incognitoBadge_];
+ }
+
+ // Add the tab strip after setting the content view and moving the incognito
+ // badge (if any), so that the tab strip will be on top (in the z-order).
+ if ([self hasTabStrip] && ![self useVerticalTabs])
+ [[[destWindow contentView] superview] addSubview:tabStripView];
+
+ [window setWindowController:nil];
+ [self setWindow:destWindow];
+ [destWindow setWindowController:self];
+ [self adjustUIForFullscreen:fullscreen];
+
+ // When entering fullscreen mode, the controller forces a layout for us. When
+ // exiting, we need to call layoutSubviews manually.
+ if (fullscreen) {
+ [fullscreenController_ enterFullscreenForContentView:contentView
+ showDropdown:showDropdown];
+ } else {
+ [self layoutSubviews];
+ }
+
+ // Move the status bubble over, if we have one.
+ if (statusBubble_)
+ statusBubble_->SwitchParentWindow(destWindow);
+
+ // Move the title over.
+ [destWindow setTitle:[window title]];
+
+ // The window needs to be onscreen before we can set its first responder.
+ [destWindow makeKeyAndOrderFront:self];
+ [focusTracker restoreFocusInWindow:destWindow];
+ [window orderOut:self];
+
+ // We're done moving focus, so re-enable bar visibility changes.
+ [self enableBarVisibilityUpdates];
+
+ // Fade back in.
+ if (didFadeOut) {
+ CGDisplayFade(token, kFadeDurationSeconds / 2, kCGDisplayBlendSolidColor,
+ kCGDisplayBlendNormal, 0.0, 0.0, 0.0, /*synchronous=*/false);
+ CGReleaseDisplayFadeReservation(token);
+ }
+}
+
+- (BOOL)isFullscreen {
+ return fullscreenController_.get() && [fullscreenController_ isFullscreen];
+}
+
+- (void)resizeFullscreenWindow {
+ DCHECK([self isFullscreen]);
+ if (![self isFullscreen])
+ return;
+
+ NSWindow* window = [self window];
+ [window setFrame:[[window screen] frame] display:YES];
+ [self layoutSubviews];
+}
+
+- (CGFloat)floatingBarShownFraction {
+ return floatingBarShownFraction_;
+}
+
+- (void)setFloatingBarShownFraction:(CGFloat)fraction {
+ floatingBarShownFraction_ = fraction;
+ [self layoutSubviews];
+}
+
+- (BOOL)isBarVisibilityLockedForOwner:(id)owner {
+ DCHECK(owner);
+ DCHECK(barVisibilityLocks_);
+ return [barVisibilityLocks_ containsObject:owner];
+}
+
+- (void)lockBarVisibilityForOwner:(id)owner
+ withAnimation:(BOOL)animate
+ delay:(BOOL)delay {
+ if (![self isBarVisibilityLockedForOwner:owner]) {
+ [barVisibilityLocks_ addObject:owner];
+
+ // If enabled, show the overlay if necessary (and if in fullscreen mode).
+ if (barVisibilityUpdatesEnabled_) {
+ [fullscreenController_ ensureOverlayShownWithAnimation:animate
+ delay:delay];
+ }
+ }
+}
+
+- (void)releaseBarVisibilityForOwner:(id)owner
+ withAnimation:(BOOL)animate
+ delay:(BOOL)delay {
+ if ([self isBarVisibilityLockedForOwner:owner]) {
+ [barVisibilityLocks_ removeObject:owner];
+
+ // If enabled, hide the overlay if necessary (and if in fullscreen mode).
+ if (barVisibilityUpdatesEnabled_ &&
+ ![barVisibilityLocks_ count]) {
+ [fullscreenController_ ensureOverlayHiddenWithAnimation:animate
+ delay:delay];
+ }
+ }
+}
+
+- (BOOL)floatingBarHasFocus {
+ NSResponder* focused = [[self window] firstResponder];
+ return [focused isKindOfClass:[AutocompleteTextFieldEditor class]];
+}
+
+- (void)openTabpose {
+ NSUInteger modifierFlags = [[NSApp currentEvent] modifierFlags];
+ BOOL slomo = (modifierFlags & NSShiftKeyMask) != 0;
+
+ // Cover info bars, inspector window, and detached bookmark bar on NTP.
+ // Do not cover download shelf.
+ NSRect activeArea = [[self tabContentArea] frame];
+ activeArea.size.height +=
+ NSHeight([[infoBarContainerController_ view] frame]);
+ if ([self isBookmarkBarVisible] && [self placeBookmarkBarBelowInfoBar]) {
+ NSView* bookmarkBarView = [bookmarkBarController_ view];
+ activeArea.size.height += NSHeight([bookmarkBarView frame]);
+ }
+
+ [TabposeWindow openTabposeFor:[self window]
+ rect:activeArea
+ slomo:slomo
+ tabStripModel:browser_->tabstrip_model()];
+}
+
+@end // @implementation BrowserWindowController(Fullscreen)
+
+
+@implementation BrowserWindowController(WindowType)
+
+- (BOOL)supportsWindowFeature:(int)feature {
+ return browser_->SupportsWindowFeature(
+ static_cast<Browser::WindowFeature>(feature));
+}
+
+- (BOOL)hasTitleBar {
+ return [self supportsWindowFeature:Browser::FEATURE_TITLEBAR];
+}
+
+- (BOOL)hasToolbar {
+ return [self supportsWindowFeature:Browser::FEATURE_TOOLBAR];
+}
+
+- (BOOL)hasLocationBar {
+ return [self supportsWindowFeature:Browser::FEATURE_LOCATIONBAR];
+}
+
+- (BOOL)supportsBookmarkBar {
+ return [self supportsWindowFeature:Browser::FEATURE_BOOKMARKBAR];
+}
+
+- (BOOL)isNormalWindow {
+ return browser_->type() == Browser::TYPE_NORMAL;
+}
+
+@end // @implementation BrowserWindowController(WindowType)
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_private.h b/chrome/browser/ui/cocoa/browser_window_controller_private.h
new file mode 100644
index 0000000..8757126
--- /dev/null
+++ b/chrome/browser/ui/cocoa/browser_window_controller_private.h
@@ -0,0 +1,119 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_BROWSER_WINDOW_CONTROLLER_PRIVATE_H_
+#define CHROME_BROWSER_UI_COCOA_BROWSER_WINDOW_CONTROLLER_PRIVATE_H_
+#pragma once
+
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+
+
+// Private methods for the |BrowserWindowController|. This category should
+// contain the private methods used by different parts of the BWC; private
+// methods used only by single parts should be declared in their own file.
+// TODO(viettrungluu): [crbug.com/35543] work on splitting out stuff from the
+// BWC, and figuring out which methods belong here (need to unravel
+// "dependencies").
+@interface BrowserWindowController(Private)
+
+// Create the appropriate tab strip controller based on whether or not side
+// tabs are enabled. Replaces the current controller.
+- (void)createTabStripController;
+
+// Saves the window's position in the local state preferences.
+- (void)saveWindowPositionIfNeeded;
+
+// Saves the window's position to the given pref service.
+- (void)saveWindowPositionToPrefs:(PrefService*)prefs;
+
+// We need to adjust where sheets come out of the window, as by default they
+// erupt from the omnibox, which is rather weird.
+- (NSRect)window:(NSWindow*)window
+ willPositionSheet:(NSWindow*)sheet
+ usingRect:(NSRect)defaultSheetRect;
+
+// Repositions the window's subviews. From the top down: toolbar, normal
+// bookmark bar (if shown), infobar, NTP detached bookmark bar (if shown),
+// content area, download shelf (if any).
+- (void)layoutSubviews;
+
+// Find the total height of the floating bar (in fullscreen mode). Safe to call
+// even when not in fullscreen mode.
+- (CGFloat)floatingBarHeight;
+
+// Lays out the tab strip at the given maximum y-coordinate, with the given
+// width, possibly for fullscreen mode; returns the new maximum y (below the tab
+// strip). This is safe to call even when there is no tab strip.
+- (CGFloat)layoutTabStripAtMaxY:(CGFloat)maxY
+ width:(CGFloat)width
+ fullscreen:(BOOL)fullscreen;
+
+// Lays out the toolbar (or just location bar for popups) at the given maximum
+// y-coordinate, with the given width; returns the new maximum y (below the
+// toolbar).
+- (CGFloat)layoutToolbarAtMinX:(CGFloat)minX
+ maxY:(CGFloat)maxY
+ width:(CGFloat)width;
+
+// Returns YES if the bookmark bar should be placed below the infobar, NO
+// otherwise.
+- (BOOL)placeBookmarkBarBelowInfoBar;
+
+// Lays out the bookmark bar at the given maximum y-coordinate, with the given
+// width; returns the new maximum y (below the bookmark bar). Note that one must
+// call it with the appropriate |maxY| which depends on whether or not the
+// bookmark bar is shown as the NTP bubble or not (use
+// |-placeBookmarkBarBelowInfoBar|).
+- (CGFloat)layoutBookmarkBarAtMinX:(CGFloat)minX
+ maxY:(CGFloat)maxY
+ width:(CGFloat)width;
+
+// Lay out the view which draws the background for the floating bar when in
+// fullscreen mode, with the given frame and fullscreen-mode-status. Should be
+// called even when not in fullscreen mode to hide the backing view.
+- (void)layoutFloatingBarBackingView:(NSRect)frame
+ fullscreen:(BOOL)fullscreen;
+
+// Lays out the infobar at the given maximum y-coordinate, with the given width;
+// returns the new maximum y (below the infobar).
+- (CGFloat)layoutInfoBarAtMinX:(CGFloat)minX
+ maxY:(CGFloat)maxY
+ width:(CGFloat)width;
+
+// Lays out the download shelf, if there is one, at the given minimum
+// y-coordinate, with the given width; returns the new minimum y (above the
+// download shelf). This is safe to call even if there is no download shelf.
+- (CGFloat)layoutDownloadShelfAtMinX:(CGFloat)minX
+ minY:(CGFloat)minY
+ width:(CGFloat)width;
+
+// Lays out the tab content area in the given frame. If the height changes,
+// sends a message to the renderer to resize.
+- (void)layoutTabContentArea:(NSRect)frame;
+
+// Should we show the normal bookmark bar?
+- (BOOL)shouldShowBookmarkBar;
+
+// Is the current page one for which the bookmark should be shown detached *if*
+// the normal bookmark bar is not shown?
+- (BOOL)shouldShowDetachedBookmarkBar;
+
+// Sets the toolbar's height to a value appropriate for the given compression.
+// Also adjusts the bookmark bar's height by the opposite amount in order to
+// keep the total height of the two views constant.
+- (void)adjustToolbarAndBookmarkBarForCompression:(CGFloat)compression;
+
+// Adjust the UI when entering or leaving fullscreen mode.
+- (void)adjustUIForFullscreen:(BOOL)fullscreen;
+
+// Allows/prevents bar visibility locks and releases from updating the visual
+// state. Enabling makes changes instantaneously; disabling cancels any
+// timers/animation.
+- (void)enableBarVisibilityUpdates;
+- (void)disableBarVisibilityUpdates;
+
+@end // @interface BrowserWindowController(Private)
+
+
+#endif // CHROME_BROWSER_UI_COCOA_BROWSER_WINDOW_CONTROLLER_PRIVATE_H_
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_private.mm b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
new file mode 100644
index 0000000..702c52b
--- /dev/null
+++ b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
@@ -0,0 +1,509 @@
+// 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 "chrome/browser/ui/cocoa/browser_window_controller_private.h"
+
+#include "base/mac_util.h"
+#import "base/scoped_nsobject.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/render_widget_host_view.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_contents_view.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#import "chrome/browser/ui/cocoa/fast_resize_view.h"
+#import "chrome/browser/ui/cocoa/find_bar_cocoa_controller.h"
+#import "chrome/browser/ui/cocoa/floating_bar_backing_view.h"
+#import "chrome/browser/ui/cocoa/framed_browser_window.h"
+#import "chrome/browser/ui/cocoa/fullscreen_controller.h"
+#import "chrome/browser/ui/cocoa/previewable_contents_controller.h"
+#import "chrome/browser/ui/cocoa/side_tab_strip_controller.h"
+#import "chrome/browser/ui/cocoa/tab_strip_controller.h"
+#import "chrome/browser/ui/cocoa/tab_strip_view.h"
+#import "chrome/browser/ui/cocoa/toolbar_controller.h"
+#include "chrome/common/pref_names.h"
+
+namespace {
+
+// Space between the incognito badge and the right edge of the window.
+const CGFloat kIncognitoBadgeOffset = 4;
+
+// Insets for the location bar, used when the full toolbar is hidden.
+// TODO(viettrungluu): We can argue about the "correct" insetting; I like the
+// following best, though arguably 0 inset is better/more correct.
+const CGFloat kLocBarLeftRightInset = 1;
+const CGFloat kLocBarTopInset = 0;
+const CGFloat kLocBarBottomInset = 1;
+
+} // end namespace
+
+
+@implementation BrowserWindowController(Private)
+
+// Create the appropriate tab strip controller based on whether or not side
+// tabs are enabled.
+- (void)createTabStripController {
+ Class factory = [TabStripController class];
+ if ([self useVerticalTabs])
+ factory = [SideTabStripController class];
+
+ DCHECK([previewableContentsController_ activeContainer]);
+ DCHECK([[previewableContentsController_ activeContainer] window]);
+ tabStripController_.reset([[factory alloc]
+ initWithView:[self tabStripView]
+ switchView:[previewableContentsController_ activeContainer]
+ browser:browser_.get()
+ delegate:self]);
+}
+
+- (void)saveWindowPositionIfNeeded {
+ if (browser_ != BrowserList::GetLastActive())
+ return;
+
+ if (!g_browser_process || !g_browser_process->local_state() ||
+ !browser_->ShouldSaveWindowPlacement())
+ return;
+
+ [self saveWindowPositionToPrefs:g_browser_process->local_state()];
+}
+
+- (void)saveWindowPositionToPrefs:(PrefService*)prefs {
+ // If we're in fullscreen mode, save the position of the regular window
+ // instead.
+ NSWindow* window = [self isFullscreen] ? savedRegularWindow_ : [self window];
+
+ // Window positions are stored relative to the origin of the primary monitor.
+ NSRect monitorFrame = [[[NSScreen screens] objectAtIndex:0] frame];
+ NSScreen* windowScreen = [window screen];
+
+ // |windowScreen| can be nil (for example, if the monitor arrangement was
+ // changed while in fullscreen mode). If we see a nil screen, return without
+ // saving.
+ // TODO(rohitrao): We should just not save anything for fullscreen windows.
+ // http://crbug.com/36479.
+ if (!windowScreen)
+ return;
+
+ // Start with the window's frame, which is in virtual coordinates.
+ // Do some y twiddling to flip the coordinate system.
+ gfx::Rect bounds(NSRectToCGRect([window frame]));
+ bounds.set_y(monitorFrame.size.height - bounds.y() - bounds.height());
+
+ // We also need to save the current work area, in flipped coordinates.
+ gfx::Rect workArea(NSRectToCGRect([windowScreen visibleFrame]));
+ workArea.set_y(monitorFrame.size.height - workArea.y() - workArea.height());
+
+ // Browser::SaveWindowPlacement is used for session restore.
+ if (browser_->ShouldSaveWindowPlacement())
+ browser_->SaveWindowPlacement(bounds, /*maximized=*/ false);
+
+ DictionaryValue* windowPreferences = prefs->GetMutableDictionary(
+ browser_->GetWindowPlacementKey().c_str());
+ windowPreferences->SetInteger("left", bounds.x());
+ windowPreferences->SetInteger("top", bounds.y());
+ windowPreferences->SetInteger("right", bounds.right());
+ windowPreferences->SetInteger("bottom", bounds.bottom());
+ windowPreferences->SetBoolean("maximized", false);
+ windowPreferences->SetBoolean("always_on_top", false);
+ windowPreferences->SetInteger("work_area_left", workArea.x());
+ windowPreferences->SetInteger("work_area_top", workArea.y());
+ windowPreferences->SetInteger("work_area_right", workArea.right());
+ windowPreferences->SetInteger("work_area_bottom", workArea.bottom());
+}
+
+- (NSRect)window:(NSWindow*)window
+willPositionSheet:(NSWindow*)sheet
+ usingRect:(NSRect)defaultSheetRect {
+ // Position the sheet as follows:
+ // - If the bookmark bar is hidden or shown as a bubble (on the NTP when the
+ // bookmark bar is disabled), position the sheet immediately below the
+ // normal toolbar.
+ // - If the bookmark bar is shown (attached to the normal toolbar), position
+ // the sheet below the bookmark bar.
+ // - If the bookmark bar is currently animating, position the sheet according
+ // to where the bar will be when the animation ends.
+ switch ([bookmarkBarController_ visualState]) {
+ case bookmarks::kShowingState: {
+ NSRect bookmarkBarFrame = [[bookmarkBarController_ view] frame];
+ defaultSheetRect.origin.y = bookmarkBarFrame.origin.y;
+ break;
+ }
+ case bookmarks::kHiddenState:
+ case bookmarks::kDetachedState: {
+ NSRect toolbarFrame = [[toolbarController_ view] frame];
+ defaultSheetRect.origin.y = toolbarFrame.origin.y;
+ break;
+ }
+ case bookmarks::kInvalidState:
+ default:
+ NOTREACHED();
+ }
+ return defaultSheetRect;
+}
+
+- (void)layoutSubviews {
+ // With the exception of the top tab strip, the subviews which we lay out are
+ // subviews of the content view, so we mainly work in the content view's
+ // coordinate system. Note, however, that the content view's coordinate system
+ // and the window's base coordinate system should coincide.
+ NSWindow* window = [self window];
+ NSView* contentView = [window contentView];
+ NSRect contentBounds = [contentView bounds];
+ CGFloat minX = NSMinX(contentBounds);
+ CGFloat minY = NSMinY(contentBounds);
+ CGFloat width = NSWidth(contentBounds);
+
+ // Suppress title drawing if necessary.
+ if ([window respondsToSelector:@selector(setShouldHideTitle:)])
+ [(id)window setShouldHideTitle:![self hasTitleBar]];
+
+ BOOL isFullscreen = [self isFullscreen];
+ CGFloat floatingBarHeight = [self floatingBarHeight];
+ // In fullscreen mode, |yOffset| accounts for the sliding position of the
+ // floating bar and the extra offset needed to dodge the menu bar.
+ CGFloat yOffset = isFullscreen ?
+ (floor((1 - floatingBarShownFraction_) * floatingBarHeight) -
+ [fullscreenController_ floatingBarVerticalOffset]) : 0;
+ CGFloat maxY = NSMaxY(contentBounds) + yOffset;
+ CGFloat startMaxY = maxY;
+
+ if ([self hasTabStrip] && ![self useVerticalTabs]) {
+ // If we need to lay out the top tab strip, replace |maxY| and |startMaxY|
+ // with higher values, and then lay out the tab strip.
+ NSRect windowFrame = [contentView convertRect:[window frame] fromView:nil];
+ startMaxY = maxY = NSHeight(windowFrame) + yOffset;
+ maxY = [self layoutTabStripAtMaxY:maxY width:width fullscreen:isFullscreen];
+ }
+
+ // Sanity-check |maxY|.
+ DCHECK_GE(maxY, minY);
+ DCHECK_LE(maxY, NSMaxY(contentBounds) + yOffset);
+
+ // The base class already positions the side tab strip on the left side
+ // of the window's content area and sizes it to take the entire vertical
+ // height. All that's needed here is to push everything over to the right,
+ // if necessary.
+ if ([self useVerticalTabs]) {
+ const CGFloat sideTabWidth = [[self tabStripView] bounds].size.width;
+ minX += sideTabWidth;
+ width -= sideTabWidth;
+ }
+
+ // Place the toolbar at the top of the reserved area.
+ maxY = [self layoutToolbarAtMinX:minX maxY:maxY width:width];
+
+ // If we're not displaying the bookmark bar below the infobar, then it goes
+ // immediately below the toolbar.
+ BOOL placeBookmarkBarBelowInfoBar = [self placeBookmarkBarBelowInfoBar];
+ if (!placeBookmarkBarBelowInfoBar)
+ maxY = [self layoutBookmarkBarAtMinX:minX maxY:maxY width:width];
+
+ // The floating bar backing view doesn't actually add any height.
+ NSRect floatingBarBackingRect =
+ NSMakeRect(minX, maxY, width, floatingBarHeight);
+ [self layoutFloatingBarBackingView:floatingBarBackingRect
+ fullscreen:isFullscreen];
+
+ // Place the find bar immediately below the toolbar/attached bookmark bar. In
+ // fullscreen mode, it hangs off the top of the screen when the bar is hidden.
+ // The find bar is unaffected by the side tab positioning.
+ [findBarCocoaController_ positionFindBarViewAtMaxY:maxY maxWidth:width];
+
+ // If in fullscreen mode, reset |maxY| to top of screen, so that the floating
+ // bar slides over the things which appear to be in the content area.
+ if (isFullscreen)
+ maxY = NSMaxY(contentBounds);
+
+ // Also place the infobar container immediate below the toolbar, except in
+ // fullscreen mode in which case it's at the top of the visual content area.
+ maxY = [self layoutInfoBarAtMinX:minX maxY:maxY width:width];
+
+ // If the bookmark bar is detached, place it next in the visual content area.
+ if (placeBookmarkBarBelowInfoBar)
+ maxY = [self layoutBookmarkBarAtMinX:minX maxY:maxY width:width];
+
+ // Place the download shelf, if any, at the bottom of the view.
+ minY = [self layoutDownloadShelfAtMinX:minX minY:minY width:width];
+
+ // Finally, the content area takes up all of the remaining space.
+ NSRect contentAreaRect = NSMakeRect(minX, minY, width, maxY - minY);
+ [self layoutTabContentArea:contentAreaRect];
+
+ // Normally, we don't need to tell the toolbar whether or not to show the
+ // divider, but things break down during animation.
+ [toolbarController_
+ setDividerOpacity:[bookmarkBarController_ toolbarDividerOpacity]];
+}
+
+- (CGFloat)floatingBarHeight {
+ if (![self isFullscreen])
+ return 0;
+
+ CGFloat totalHeight = [fullscreenController_ floatingBarVerticalOffset];
+
+ if ([self hasTabStrip])
+ totalHeight += NSHeight([[self tabStripView] frame]);
+
+ if ([self hasToolbar]) {
+ totalHeight += NSHeight([[toolbarController_ view] frame]);
+ } else if ([self hasLocationBar]) {
+ totalHeight += NSHeight([[toolbarController_ view] frame]) +
+ kLocBarTopInset + kLocBarBottomInset;
+ }
+
+ if (![self placeBookmarkBarBelowInfoBar])
+ totalHeight += NSHeight([[bookmarkBarController_ view] frame]);
+
+ return totalHeight;
+}
+
+- (CGFloat)layoutTabStripAtMaxY:(CGFloat)maxY
+ width:(CGFloat)width
+ fullscreen:(BOOL)fullscreen {
+ // Nothing to do if no tab strip.
+ if (![self hasTabStrip])
+ return maxY;
+
+ NSView* tabStripView = [self tabStripView];
+ CGFloat tabStripHeight = NSHeight([tabStripView frame]);
+ maxY -= tabStripHeight;
+ [tabStripView setFrame:NSMakeRect(0, maxY, width, tabStripHeight)];
+
+ // Set indentation.
+ [tabStripController_ setIndentForControls:(fullscreen ? 0 :
+ [[tabStripController_ class] defaultIndentForControls])];
+
+ // TODO(viettrungluu): Seems kind of bad -- shouldn't |-layoutSubviews| do
+ // this? Moreover, |-layoutTabs| will try to animate....
+ [tabStripController_ layoutTabs];
+
+ // Now lay out incognito badge together with the tab strip.
+ if (incognitoBadge_.get()) {
+ // Actually place the badge *above* |maxY|, by +2 to miss the divider.
+ NSPoint origin = NSMakePoint(width - NSWidth([incognitoBadge_ frame]) -
+ kIncognitoBadgeOffset, maxY + 2);
+ [incognitoBadge_ setFrameOrigin:origin];
+ [incognitoBadge_ setHidden:NO]; // Make sure it's shown.
+ }
+
+ return maxY;
+}
+
+- (CGFloat)layoutToolbarAtMinX:(CGFloat)minX
+ maxY:(CGFloat)maxY
+ width:(CGFloat)width {
+ NSView* toolbarView = [toolbarController_ view];
+ NSRect toolbarFrame = [toolbarView frame];
+ if ([self hasToolbar]) {
+ // The toolbar is present in the window, so we make room for it.
+ DCHECK(![toolbarView isHidden]);
+ toolbarFrame.origin.x = minX;
+ toolbarFrame.origin.y = maxY - NSHeight(toolbarFrame);
+ toolbarFrame.size.width = width;
+ maxY -= NSHeight(toolbarFrame);
+ } else {
+ if ([self hasLocationBar]) {
+ // Location bar is present with no toolbar. Put a border of
+ // |kLocBar...Inset| pixels around the location bar.
+ // TODO(viettrungluu): This is moderately ridiculous. The toolbar should
+ // really be aware of what its height should be (the way the toolbar
+ // compression stuff is currently set up messes things up).
+ DCHECK(![toolbarView isHidden]);
+ toolbarFrame.origin.x = kLocBarLeftRightInset;
+ toolbarFrame.origin.y = maxY - NSHeight(toolbarFrame) - kLocBarTopInset;
+ toolbarFrame.size.width = width - 2 * kLocBarLeftRightInset;
+ maxY -= kLocBarTopInset + NSHeight(toolbarFrame) + kLocBarBottomInset;
+ } else {
+ DCHECK([toolbarView isHidden]);
+ }
+ }
+ [toolbarView setFrame:toolbarFrame];
+ return maxY;
+}
+
+- (BOOL)placeBookmarkBarBelowInfoBar {
+ // If we are currently displaying the NTP detached bookmark bar or animating
+ // to/from it (from/to anything else), we display the bookmark bar below the
+ // infobar.
+ return [bookmarkBarController_ isInState:bookmarks::kDetachedState] ||
+ [bookmarkBarController_ isAnimatingToState:bookmarks::kDetachedState] ||
+ [bookmarkBarController_ isAnimatingFromState:bookmarks::kDetachedState];
+}
+
+- (CGFloat)layoutBookmarkBarAtMinX:(CGFloat)minX
+ maxY:(CGFloat)maxY
+ width:(CGFloat)width {
+ NSView* bookmarkBarView = [bookmarkBarController_ view];
+ NSRect bookmarkBarFrame = [bookmarkBarView frame];
+ BOOL oldHidden = [bookmarkBarView isHidden];
+ BOOL newHidden = ![self isBookmarkBarVisible];
+ if (oldHidden != newHidden)
+ [bookmarkBarView setHidden:newHidden];
+ bookmarkBarFrame.origin.x = minX;
+ bookmarkBarFrame.origin.y = maxY - NSHeight(bookmarkBarFrame);
+ bookmarkBarFrame.size.width = width;
+ [bookmarkBarView setFrame:bookmarkBarFrame];
+ maxY -= NSHeight(bookmarkBarFrame);
+
+ // TODO(viettrungluu): Does this really belong here? Calling it shouldn't be
+ // necessary in the non-NTP case.
+ [bookmarkBarController_ layoutSubviews];
+
+ return maxY;
+}
+
+- (void)layoutFloatingBarBackingView:(NSRect)frame
+ fullscreen:(BOOL)fullscreen {
+ // Only display when in fullscreen mode.
+ if (fullscreen) {
+ // For certain window types such as app windows (e.g., the dev tools
+ // window), there's no actual overlay. (Displaying one would result in an
+ // overly sliding in only under the menu, which gives an ugly effect.)
+ if (floatingBarBackingView_.get()) {
+ BOOL aboveBookmarkBar = [self placeBookmarkBarBelowInfoBar];
+
+ // Insert it into the view hierarchy if necessary.
+ if (![floatingBarBackingView_ superview] ||
+ aboveBookmarkBar != floatingBarAboveBookmarkBar_) {
+ NSView* contentView = [[self window] contentView];
+ // z-order gets messed up unless we explicitly remove the floatingbar
+ // view and re-add it.
+ [floatingBarBackingView_ removeFromSuperview];
+ [contentView addSubview:floatingBarBackingView_
+ positioned:(aboveBookmarkBar ?
+ NSWindowAbove : NSWindowBelow)
+ relativeTo:[bookmarkBarController_ view]];
+ floatingBarAboveBookmarkBar_ = aboveBookmarkBar;
+ }
+
+ // Set its frame.
+ [floatingBarBackingView_ setFrame:frame];
+ }
+
+ // But we want the logic to work as usual (for show/hide/etc. purposes).
+ [fullscreenController_ overlayFrameChanged:frame];
+ } else {
+ // Okay to call even if |floatingBarBackingView_| is nil.
+ if ([floatingBarBackingView_ superview])
+ [floatingBarBackingView_ removeFromSuperview];
+ }
+}
+
+- (CGFloat)layoutInfoBarAtMinX:(CGFloat)minX
+ maxY:(CGFloat)maxY
+ width:(CGFloat)width {
+ NSView* infoBarView = [infoBarContainerController_ view];
+ NSRect infoBarFrame = [infoBarView frame];
+ infoBarFrame.origin.x = minX;
+ infoBarFrame.origin.y = maxY - NSHeight(infoBarFrame);
+ infoBarFrame.size.width = width;
+ [infoBarView setFrame:infoBarFrame];
+ maxY -= NSHeight(infoBarFrame);
+ return maxY;
+}
+
+- (CGFloat)layoutDownloadShelfAtMinX:(CGFloat)minX
+ minY:(CGFloat)minY
+ width:(CGFloat)width {
+ if (downloadShelfController_.get()) {
+ NSView* downloadView = [downloadShelfController_ view];
+ NSRect downloadFrame = [downloadView frame];
+ downloadFrame.origin.x = minX;
+ downloadFrame.origin.y = minY;
+ downloadFrame.size.width = width;
+ [downloadView setFrame:downloadFrame];
+ minY += NSHeight(downloadFrame);
+ }
+ return minY;
+}
+
+- (void)layoutTabContentArea:(NSRect)newFrame {
+ NSView* tabContentView = [self tabContentArea];
+ NSRect tabContentFrame = [tabContentView frame];
+
+ bool contentShifted =
+ NSMaxY(tabContentFrame) != NSMaxY(newFrame) ||
+ NSMinX(tabContentFrame) != NSMinX(newFrame);
+
+ tabContentFrame = newFrame;
+ [tabContentView setFrame:tabContentFrame];
+
+ // If the relayout shifts the content area up or down, let the renderer know.
+ if (contentShifted) {
+ if (TabContents* contents = browser_->GetSelectedTabContents()) {
+ if (RenderWidgetHostView* rwhv = contents->GetRenderWidgetHostView())
+ rwhv->WindowFrameChanged();
+ }
+ }
+}
+
+- (BOOL)shouldShowBookmarkBar {
+ DCHECK(browser_.get());
+ return browser_->profile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar) ?
+ YES : NO;
+}
+
+- (BOOL)shouldShowDetachedBookmarkBar {
+ DCHECK(browser_.get());
+ TabContents* contents = browser_->GetSelectedTabContents();
+ return (contents &&
+ contents->ShouldShowBookmarkBar() &&
+ ![previewableContentsController_ isShowingPreview]);
+}
+
+- (void)adjustToolbarAndBookmarkBarForCompression:(CGFloat)compression {
+ CGFloat newHeight =
+ [toolbarController_ desiredHeightForCompression:compression];
+ NSRect toolbarFrame = [[toolbarController_ view] frame];
+ CGFloat deltaH = newHeight - toolbarFrame.size.height;
+
+ if (deltaH == 0)
+ return;
+
+ toolbarFrame.size.height = newHeight;
+ NSRect bookmarkFrame = [[bookmarkBarController_ view] frame];
+ bookmarkFrame.size.height = bookmarkFrame.size.height - deltaH;
+ [[toolbarController_ view] setFrame:toolbarFrame];
+ [[bookmarkBarController_ view] setFrame:bookmarkFrame];
+ [self layoutSubviews];
+}
+
+// TODO(rohitrao): This function has shrunk into uselessness, and
+// |-setFullscreen:| has grown rather large. Find a good way to break up
+// |-setFullscreen:| into smaller pieces. http://crbug.com/36449
+- (void)adjustUIForFullscreen:(BOOL)fullscreen {
+ // Create the floating bar backing view if necessary.
+ if (fullscreen && !floatingBarBackingView_.get() &&
+ ([self hasTabStrip] || [self hasToolbar] || [self hasLocationBar])) {
+ floatingBarBackingView_.reset(
+ [[FloatingBarBackingView alloc] initWithFrame:NSZeroRect]);
+ }
+}
+
+- (void)enableBarVisibilityUpdates {
+ // Early escape if there's nothing to do.
+ if (barVisibilityUpdatesEnabled_)
+ return;
+
+ barVisibilityUpdatesEnabled_ = YES;
+
+ if ([barVisibilityLocks_ count])
+ [fullscreenController_ ensureOverlayShownWithAnimation:NO delay:NO];
+ else
+ [fullscreenController_ ensureOverlayHiddenWithAnimation:NO delay:NO];
+}
+
+- (void)disableBarVisibilityUpdates {
+ // Early escape if there's nothing to do.
+ if (!barVisibilityUpdatesEnabled_)
+ return;
+
+ barVisibilityUpdatesEnabled_ = NO;
+ [fullscreenController_ cancelAnimationAndTimers];
+}
+
+@end // @implementation BrowserWindowController(Private)
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm b/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm
new file mode 100644
index 0000000..d16401f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm
@@ -0,0 +1,668 @@
+// 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.
+
+#include "app/l10n_util_mac.h"
+#include "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/browser_window.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/sync/sync_ui_util.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#include "chrome/browser/ui/cocoa/browser_window_controller.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/find_bar_bridge.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/testing_profile.h"
+#include "grit/generated_resources.h"
+
+@interface BrowserWindowController (JustForTesting)
+// Already defined in BWC.
+- (void)saveWindowPositionToPrefs:(PrefService*)prefs;
+- (void)layoutSubviews;
+@end
+
+@interface BrowserWindowController (ExposedForTesting)
+// Implementations are below.
+- (NSView*)infoBarContainerView;
+- (NSView*)toolbarView;
+- (NSView*)bookmarkView;
+- (BOOL)bookmarkBarVisible;
+@end
+
+@implementation BrowserWindowController (ExposedForTesting)
+- (NSView*)infoBarContainerView {
+ return [infoBarContainerController_ view];
+}
+
+- (NSView*)toolbarView {
+ return [toolbarController_ view];
+}
+
+- (NSView*)bookmarkView {
+ return [bookmarkBarController_ view];
+}
+
+- (NSView*)findBarView {
+ return [findBarCocoaController_ view];
+}
+
+- (NSSplitView*)devToolsView {
+ return static_cast<NSSplitView*>([devToolsController_ view]);
+}
+
+- (NSView*)sidebarView {
+ return [sidebarController_ view];
+}
+
+- (BOOL)bookmarkBarVisible {
+ return [bookmarkBarController_ isVisible];
+}
+@end
+
+class BrowserWindowControllerTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ Browser* browser = browser_helper_.browser();
+ controller_ = [[BrowserWindowController alloc] initWithBrowser:browser
+ takeOwnership:NO];
+ }
+
+ virtual void TearDown() {
+ [controller_ close];
+ CocoaTest::TearDown();
+ }
+
+ public:
+ BrowserTestHelper browser_helper_;
+ BrowserWindowController* controller_;
+};
+
+TEST_F(BrowserWindowControllerTest, TestSaveWindowPosition) {
+ PrefService* prefs = browser_helper_.profile()->GetPrefs();
+ ASSERT_TRUE(prefs != NULL);
+
+ // Check to make sure there is no existing pref for window placement.
+ ASSERT_TRUE(prefs->GetDictionary(prefs::kBrowserWindowPlacement) == NULL);
+
+ // Ask the window to save its position, then check that a preference
+ // exists. We're technically passing in a pointer to the user prefs
+ // and not the local state prefs, but a PrefService* is a
+ // PrefService*, and this is a unittest.
+ [controller_ saveWindowPositionToPrefs:prefs];
+ EXPECT_TRUE(prefs->GetDictionary(prefs::kBrowserWindowPlacement) != NULL);
+}
+
+TEST_F(BrowserWindowControllerTest, TestFullScreenWindow) {
+ // Confirm that |-createFullscreenWindow| doesn't return nil.
+ // See BrowserWindowFullScreenControllerTest for more fullscreen tests.
+ EXPECT_TRUE([controller_ createFullscreenWindow]);
+}
+
+TEST_F(BrowserWindowControllerTest, TestNormal) {
+ // Force the bookmark bar to be shown.
+ browser_helper_.profile()->GetPrefs()->
+ SetBoolean(prefs::kShowBookmarkBar, true);
+ [controller_ updateBookmarkBarVisibilityWithAnimation:NO];
+
+ // Make sure a normal BrowserWindowController is, uh, normal.
+ EXPECT_TRUE([controller_ isNormalWindow]);
+ EXPECT_TRUE([controller_ hasTabStrip]);
+ EXPECT_FALSE([controller_ hasTitleBar]);
+ EXPECT_TRUE([controller_ isBookmarkBarVisible]);
+
+ // And make sure a controller for a pop-up window is not normal.
+ // popup_browser will be owned by its window.
+ Browser *popup_browser(Browser::CreateForType(Browser::TYPE_POPUP,
+ browser_helper_.profile()));
+ NSWindow *cocoaWindow = popup_browser->window()->GetNativeHandle();
+ BrowserWindowController* controller =
+ static_cast<BrowserWindowController*>([cocoaWindow windowController]);
+ ASSERT_TRUE([controller isKindOfClass:[BrowserWindowController class]]);
+ EXPECT_FALSE([controller isNormalWindow]);
+ EXPECT_FALSE([controller hasTabStrip]);
+ EXPECT_TRUE([controller hasTitleBar]);
+ EXPECT_FALSE([controller isBookmarkBarVisible]);
+ [controller close];
+}
+
+TEST_F(BrowserWindowControllerTest, TestTheme) {
+ [controller_ userChangedTheme];
+}
+
+TEST_F(BrowserWindowControllerTest, BookmarkBarControllerIndirection) {
+ EXPECT_FALSE([controller_ isBookmarkBarVisible]);
+
+ // Explicitly show the bar. Can't use bookmark_utils::ToggleWhenVisible()
+ // because of the notification issues.
+ browser_helper_.profile()->GetPrefs()->
+ SetBoolean(prefs::kShowBookmarkBar, true);
+
+ [controller_ updateBookmarkBarVisibilityWithAnimation:NO];
+ EXPECT_TRUE([controller_ isBookmarkBarVisible]);
+}
+
+#if 0
+// TODO(jrg): This crashes trying to create the BookmarkBarController, adding
+// an observer to the BookmarkModel.
+TEST_F(BrowserWindowControllerTest, TestIncognitoWidthSpace) {
+ scoped_ptr<TestingProfile> incognito_profile(new TestingProfile());
+ incognito_profile->set_off_the_record(true);
+ scoped_ptr<Browser> browser(new Browser(Browser::TYPE_NORMAL,
+ incognito_profile.get()));
+ controller_.reset([[BrowserWindowController alloc]
+ initWithBrowser:browser.get()
+ takeOwnership:NO]);
+
+ NSRect tabFrame = [[controller_ tabStripView] frame];
+ [controller_ installIncognitoBadge];
+ NSRect newTabFrame = [[controller_ tabStripView] frame];
+ EXPECT_GT(tabFrame.size.width, newTabFrame.size.width);
+
+ controller_.release();
+}
+#endif
+
+namespace {
+// Verifies that the toolbar, infobar, tab content area, and download shelf
+// completely fill the area under the tabstrip.
+void CheckViewPositions(BrowserWindowController* controller) {
+ NSRect contentView = [[[controller window] contentView] bounds];
+ NSRect tabstrip = [[controller tabStripView] frame];
+ NSRect toolbar = [[controller toolbarView] frame];
+ NSRect infobar = [[controller infoBarContainerView] frame];
+ NSRect contentArea = [[controller tabContentArea] frame];
+ NSRect download = [[[controller downloadShelf] view] frame];
+
+ EXPECT_EQ(NSMinY(contentView), NSMinY(download));
+ EXPECT_EQ(NSMaxY(download), NSMinY(contentArea));
+ EXPECT_EQ(NSMaxY(contentArea), NSMinY(infobar));
+
+ // Bookmark bar frame is random memory when hidden.
+ if ([controller bookmarkBarVisible]) {
+ NSRect bookmark = [[controller bookmarkView] frame];
+ EXPECT_EQ(NSMaxY(infobar), NSMinY(bookmark));
+ EXPECT_EQ(NSMaxY(bookmark), NSMinY(toolbar));
+ EXPECT_FALSE([[controller bookmarkView] isHidden]);
+ } else {
+ EXPECT_EQ(NSMaxY(infobar), NSMinY(toolbar));
+ EXPECT_TRUE([[controller bookmarkView] isHidden]);
+ }
+
+ // Toolbar should start immediately under the tabstrip, but the tabstrip is
+ // not necessarily fixed with respect to the content view.
+ EXPECT_EQ(NSMinY(tabstrip), NSMaxY(toolbar));
+}
+} // end namespace
+
+TEST_F(BrowserWindowControllerTest, TestAdjustWindowHeight) {
+ NSWindow* window = [controller_ window];
+ NSRect workarea = [[window screen] visibleFrame];
+
+ // Place the window well above the bottom of the screen and try to adjust its
+ // height. It should change appropriately (and only downwards). Then get it to
+ // shrink by the same amount; it should return to its original state.
+ NSRect initialFrame = NSMakeRect(workarea.origin.x, workarea.origin.y + 100,
+ 200, 200);
+ [window setFrame:initialFrame display:YES];
+ [controller_ resetWindowGrowthState];
+ [controller_ adjustWindowHeightBy:40];
+ NSRect finalFrame = [window frame];
+ EXPECT_FALSE(NSEqualRects(finalFrame, initialFrame));
+ EXPECT_FLOAT_EQ(NSMaxY(finalFrame), NSMaxY(initialFrame));
+ EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) + 40);
+ [controller_ adjustWindowHeightBy:-40];
+ finalFrame = [window frame];
+ EXPECT_FLOAT_EQ(NSMaxY(finalFrame), NSMaxY(initialFrame));
+ EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame));
+
+ // Place the window at the bottom of the screen and try again. Its height
+ // should still change, but it should not grow down below the work area; it
+ // should instead move upwards. Then shrink it and make sure it goes back to
+ // the way it was.
+ initialFrame = NSMakeRect(workarea.origin.x, workarea.origin.y, 200, 200);
+ [window setFrame:initialFrame display:YES];
+ [controller_ resetWindowGrowthState];
+ [controller_ adjustWindowHeightBy:40];
+ finalFrame = [window frame];
+ EXPECT_FALSE(NSEqualRects(finalFrame, initialFrame));
+ EXPECT_FLOAT_EQ(NSMinY(finalFrame), NSMinY(initialFrame));
+ EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) + 40);
+ [controller_ adjustWindowHeightBy:-40];
+ finalFrame = [window frame];
+ EXPECT_FLOAT_EQ(NSMinY(finalFrame), NSMinY(initialFrame));
+ EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame));
+
+ // Put the window slightly offscreen and try again. The height should not
+ // change this time.
+ initialFrame = NSMakeRect(workarea.origin.x - 10, 0, 200, 200);
+ [window setFrame:initialFrame display:YES];
+ [controller_ resetWindowGrowthState];
+ [controller_ adjustWindowHeightBy:40];
+ EXPECT_TRUE(NSEqualRects([window frame], initialFrame));
+ [controller_ adjustWindowHeightBy:-40];
+ EXPECT_TRUE(NSEqualRects([window frame], initialFrame));
+
+ // Make the window the same size as the workarea. Resizing both larger and
+ // smaller should have no effect.
+ [window setFrame:workarea display:YES];
+ [controller_ resetWindowGrowthState];
+ [controller_ adjustWindowHeightBy:40];
+ EXPECT_TRUE(NSEqualRects([window frame], workarea));
+ [controller_ adjustWindowHeightBy:-40];
+ EXPECT_TRUE(NSEqualRects([window frame], workarea));
+
+ // Make the window smaller than the workarea and place it near the bottom of
+ // the workarea. The window should grow down until it hits the bottom and
+ // then continue to grow up. Then shrink it, and it should return to where it
+ // was.
+ initialFrame = NSMakeRect(workarea.origin.x, workarea.origin.y + 5,
+ 200, 200);
+ [window setFrame:initialFrame display:YES];
+ [controller_ resetWindowGrowthState];
+ [controller_ adjustWindowHeightBy:40];
+ finalFrame = [window frame];
+ EXPECT_FLOAT_EQ(NSMinY(workarea), NSMinY(finalFrame));
+ EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) + 40);
+ [controller_ adjustWindowHeightBy:-40];
+ finalFrame = [window frame];
+ EXPECT_FLOAT_EQ(NSMinY(initialFrame), NSMinY(finalFrame));
+ EXPECT_FLOAT_EQ(NSHeight(initialFrame), NSHeight(finalFrame));
+
+ // Inset the window slightly from the workarea. It should not grow to be
+ // larger than the workarea. Shrink it; it should return to where it started.
+ initialFrame = NSInsetRect(workarea, 0, 5);
+ [window setFrame:initialFrame display:YES];
+ [controller_ resetWindowGrowthState];
+ [controller_ adjustWindowHeightBy:40];
+ finalFrame = [window frame];
+ EXPECT_FLOAT_EQ(NSMinY(workarea), NSMinY(finalFrame));
+ EXPECT_FLOAT_EQ(NSHeight(workarea), NSHeight(finalFrame));
+ [controller_ adjustWindowHeightBy:-40];
+ finalFrame = [window frame];
+ EXPECT_FLOAT_EQ(NSMinY(initialFrame), NSMinY(finalFrame));
+ EXPECT_FLOAT_EQ(NSHeight(initialFrame), NSHeight(finalFrame));
+
+ // Place the window at the bottom of the screen and grow; it should grow
+ // upwards. Move the window off the bottom, then shrink. It should then shrink
+ // from the bottom.
+ initialFrame = NSMakeRect(workarea.origin.x, workarea.origin.y, 200, 200);
+ [window setFrame:initialFrame display:YES];
+ [controller_ resetWindowGrowthState];
+ [controller_ adjustWindowHeightBy:40];
+ finalFrame = [window frame];
+ EXPECT_FALSE(NSEqualRects(finalFrame, initialFrame));
+ EXPECT_FLOAT_EQ(NSMinY(finalFrame), NSMinY(initialFrame));
+ EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) + 40);
+ NSPoint oldOrigin = initialFrame.origin;
+ NSPoint newOrigin = NSMakePoint(oldOrigin.x, oldOrigin.y + 10);
+ [window setFrameOrigin:newOrigin];
+ initialFrame = [window frame];
+ EXPECT_FLOAT_EQ(NSMinY(initialFrame), oldOrigin.y + 10);
+ [controller_ adjustWindowHeightBy:-40];
+ finalFrame = [window frame];
+ EXPECT_FLOAT_EQ(NSMinY(finalFrame), NSMinY(initialFrame) + 40);
+ EXPECT_FLOAT_EQ(NSHeight(finalFrame), NSHeight(initialFrame) - 40);
+
+ // Do the "inset" test above, but using multiple calls to
+ // |-adjustWindowHeightBy|; the result should be the same.
+ initialFrame = NSInsetRect(workarea, 0, 5);
+ [window setFrame:initialFrame display:YES];
+ [controller_ resetWindowGrowthState];
+ for (int i = 0; i < 8; i++)
+ [controller_ adjustWindowHeightBy:5];
+ finalFrame = [window frame];
+ EXPECT_FLOAT_EQ(NSMinY(workarea), NSMinY(finalFrame));
+ EXPECT_FLOAT_EQ(NSHeight(workarea), NSHeight(finalFrame));
+ for (int i = 0; i < 8; i++)
+ [controller_ adjustWindowHeightBy:-5];
+ finalFrame = [window frame];
+ EXPECT_FLOAT_EQ(NSMinY(initialFrame), NSMinY(finalFrame));
+ EXPECT_FLOAT_EQ(NSHeight(initialFrame), NSHeight(finalFrame));
+}
+
+// Test to make sure resizing and relaying-out subviews works correctly.
+TEST_F(BrowserWindowControllerTest, TestResizeViews) {
+ TabStripView* tabstrip = [controller_ tabStripView];
+ NSView* contentView = [[tabstrip window] contentView];
+ NSView* toolbar = [controller_ toolbarView];
+ NSView* infobar = [controller_ infoBarContainerView];
+
+ // We need to muck with the views a bit to put us in a consistent state before
+ // we start resizing. In particular, we need to move the tab strip to be
+ // immediately above the content area, since we layout views to be directly
+ // under the tab strip.
+ NSRect tabstripFrame = [tabstrip frame];
+ tabstripFrame.origin.y = NSMaxY([contentView frame]);
+ [tabstrip setFrame:tabstripFrame];
+
+ // The download shelf is created lazily. Force-create it and set its initial
+ // height to 0.
+ NSView* download = [[controller_ downloadShelf] view];
+ NSRect downloadFrame = [download frame];
+ downloadFrame.size.height = 0;
+ [download setFrame:downloadFrame];
+
+ // Force a layout and check each view's frame.
+ [controller_ layoutSubviews];
+ CheckViewPositions(controller_);
+
+ // Expand the infobar to 60px and recheck
+ [controller_ resizeView:infobar newHeight:60];
+ CheckViewPositions(controller_);
+
+ // Expand the toolbar to 64px and recheck
+ [controller_ resizeView:toolbar newHeight:64];
+ CheckViewPositions(controller_);
+
+ // Add a 30px download shelf and recheck
+ [controller_ resizeView:download newHeight:30];
+ CheckViewPositions(controller_);
+
+ // Shrink the infobar to 0px and toolbar to 39px and recheck
+ [controller_ resizeView:infobar newHeight:0];
+ [controller_ resizeView:toolbar newHeight:39];
+ CheckViewPositions(controller_);
+}
+
+TEST_F(BrowserWindowControllerTest, TestResizeViewsWithBookmarkBar) {
+ // Force a display of the bookmark bar.
+ browser_helper_.profile()->GetPrefs()->
+ SetBoolean(prefs::kShowBookmarkBar, true);
+ [controller_ updateBookmarkBarVisibilityWithAnimation:NO];
+
+ TabStripView* tabstrip = [controller_ tabStripView];
+ NSView* contentView = [[tabstrip window] contentView];
+ NSView* toolbar = [controller_ toolbarView];
+ NSView* bookmark = [controller_ bookmarkView];
+ NSView* infobar = [controller_ infoBarContainerView];
+
+ // We need to muck with the views a bit to put us in a consistent state before
+ // we start resizing. In particular, we need to move the tab strip to be
+ // immediately above the content area, since we layout views to be directly
+ // under the tab strip.
+ NSRect tabstripFrame = [tabstrip frame];
+ tabstripFrame.origin.y = NSMaxY([contentView frame]);
+ [tabstrip setFrame:tabstripFrame];
+
+ // The download shelf is created lazily. Force-create it and set its initial
+ // height to 0.
+ NSView* download = [[controller_ downloadShelf] view];
+ NSRect downloadFrame = [download frame];
+ downloadFrame.size.height = 0;
+ [download setFrame:downloadFrame];
+
+ // Force a layout and check each view's frame.
+ [controller_ layoutSubviews];
+ CheckViewPositions(controller_);
+
+ // Add the bookmark bar and recheck.
+ [controller_ resizeView:bookmark newHeight:40];
+ CheckViewPositions(controller_);
+
+ // Expand the infobar to 60px and recheck
+ [controller_ resizeView:infobar newHeight:60];
+ CheckViewPositions(controller_);
+
+ // Expand the toolbar to 64px and recheck
+ [controller_ resizeView:toolbar newHeight:64];
+ CheckViewPositions(controller_);
+
+ // Add a 30px download shelf and recheck
+ [controller_ resizeView:download newHeight:30];
+ CheckViewPositions(controller_);
+
+ // Remove the bookmark bar and recheck
+ browser_helper_.profile()->GetPrefs()->
+ SetBoolean(prefs::kShowBookmarkBar, false);
+ [controller_ resizeView:bookmark newHeight:0];
+ CheckViewPositions(controller_);
+
+ // Shrink the infobar to 0px and toolbar to 39px and recheck
+ [controller_ resizeView:infobar newHeight:0];
+ [controller_ resizeView:toolbar newHeight:39];
+ CheckViewPositions(controller_);
+}
+
+// Make sure, by default, the bookmark bar and the toolbar are the same width.
+TEST_F(BrowserWindowControllerTest, BookmarkBarIsSameWidth) {
+ // Set the pref to the bookmark bar is visible when the toolbar is
+ // first created.
+ browser_helper_.profile()->GetPrefs()->SetBoolean(
+ prefs::kShowBookmarkBar, true);
+
+ // Make sure the bookmark bar is the same width as the toolbar
+ NSView* bookmarkBarView = [controller_ bookmarkView];
+ NSView* toolbarView = [controller_ toolbarView];
+ EXPECT_EQ([toolbarView frame].size.width,
+ [bookmarkBarView frame].size.width);
+}
+
+TEST_F(BrowserWindowControllerTest, TestTopRightForBubble) {
+ NSPoint p = [controller_ bookmarkBubblePoint];
+ NSRect all = [[controller_ window] frame];
+
+ // As a sanity check make sure the point is vaguely in the top right
+ // of the window.
+ EXPECT_GT(p.y, all.origin.y + (all.size.height/2));
+ EXPECT_GT(p.x, all.origin.x + (all.size.width/2));
+}
+
+// By the "zoom frame", we mean what Apple calls the "standard frame".
+TEST_F(BrowserWindowControllerTest, TestZoomFrame) {
+ NSWindow* window = [controller_ window];
+ ASSERT_TRUE(window);
+ NSRect screenFrame = [[window screen] visibleFrame];
+ ASSERT_FALSE(NSIsEmptyRect(screenFrame));
+
+ // Minimum zoomed width is the larger of 60% of available horizontal space or
+ // 60% of available vertical space, subject to available horizontal space.
+ CGFloat minZoomWidth =
+ std::min(std::max((CGFloat)0.6 * screenFrame.size.width,
+ (CGFloat)0.6 * screenFrame.size.height),
+ screenFrame.size.width);
+
+ // |testFrame| is the size of the window we start out with, and |zoomFrame| is
+ // the one returned by |-windowWillUseStandardFrame:defaultFrame:|.
+ NSRect testFrame;
+ NSRect zoomFrame;
+
+ // 1. Test a case where it zooms the window both horizontally and vertically,
+ // and only moves it vertically. "+ 32", etc. are just arbitrary constants
+ // used to check that the window is moved properly and not just to the origin;
+ // they should be small enough to not shove windows off the screen.
+ testFrame.size.width = 0.5 * minZoomWidth;
+ testFrame.size.height = 0.5 * screenFrame.size.height;
+ testFrame.origin.x = screenFrame.origin.x + 32; // See above.
+ testFrame.origin.y = screenFrame.origin.y + 23;
+ [window setFrame:testFrame display:NO];
+ zoomFrame = [controller_ windowWillUseStandardFrame:window
+ defaultFrame:screenFrame];
+ EXPECT_LE(minZoomWidth, zoomFrame.size.width);
+ EXPECT_EQ(screenFrame.size.height, zoomFrame.size.height);
+ EXPECT_EQ(testFrame.origin.x, zoomFrame.origin.x);
+ EXPECT_EQ(screenFrame.origin.y, zoomFrame.origin.y);
+
+ // 2. Test a case where it zooms the window only horizontally, and only moves
+ // it horizontally.
+ testFrame.size.width = 0.5 * minZoomWidth;
+ testFrame.size.height = screenFrame.size.height;
+ testFrame.origin.x = screenFrame.origin.x + screenFrame.size.width -
+ testFrame.size.width;
+ testFrame.origin.y = screenFrame.origin.y;
+ [window setFrame:testFrame display:NO];
+ zoomFrame = [controller_ windowWillUseStandardFrame:window
+ defaultFrame:screenFrame];
+ EXPECT_LE(minZoomWidth, zoomFrame.size.width);
+ EXPECT_EQ(screenFrame.size.height, zoomFrame.size.height);
+ EXPECT_EQ(screenFrame.origin.x + screenFrame.size.width -
+ zoomFrame.size.width, zoomFrame.origin.x);
+ EXPECT_EQ(screenFrame.origin.y, zoomFrame.origin.y);
+
+ // 3. Test a case where it zooms the window only vertically, and only moves it
+ // vertically.
+ testFrame.size.width = std::min((CGFloat)1.1 * minZoomWidth,
+ screenFrame.size.width);
+ testFrame.size.height = 0.3 * screenFrame.size.height;
+ testFrame.origin.x = screenFrame.origin.x + 32; // See above (in 1.).
+ testFrame.origin.y = screenFrame.origin.y + 123;
+ [window setFrame:testFrame display:NO];
+ zoomFrame = [controller_ windowWillUseStandardFrame:window
+ defaultFrame:screenFrame];
+ // Use the actual width of the window frame, since it's subject to rounding.
+ EXPECT_EQ([window frame].size.width, zoomFrame.size.width);
+ EXPECT_EQ(screenFrame.size.height, zoomFrame.size.height);
+ EXPECT_EQ(testFrame.origin.x, zoomFrame.origin.x);
+ EXPECT_EQ(screenFrame.origin.y, zoomFrame.origin.y);
+
+ // 4. Test a case where zooming should do nothing (i.e., we're already at a
+ // zoomed frame).
+ testFrame.size.width = std::min((CGFloat)1.1 * minZoomWidth,
+ screenFrame.size.width);
+ testFrame.size.height = screenFrame.size.height;
+ testFrame.origin.x = screenFrame.origin.x + 32; // See above (in 1.).
+ testFrame.origin.y = screenFrame.origin.y;
+ [window setFrame:testFrame display:NO];
+ zoomFrame = [controller_ windowWillUseStandardFrame:window
+ defaultFrame:screenFrame];
+ // Use the actual width of the window frame, since it's subject to rounding.
+ EXPECT_EQ([window frame].size.width, zoomFrame.size.width);
+ EXPECT_EQ(screenFrame.size.height, zoomFrame.size.height);
+ EXPECT_EQ(testFrame.origin.x, zoomFrame.origin.x);
+ EXPECT_EQ(screenFrame.origin.y, zoomFrame.origin.y);
+}
+
+TEST_F(BrowserWindowControllerTest, TestFindBarOnTop) {
+ FindBarBridge bridge;
+ [controller_ addFindBar:bridge.find_bar_cocoa_controller()];
+
+ // Test that the Z-order of the find bar is on top of everything.
+ NSArray* subviews = [[[controller_ window] contentView] subviews];
+ NSUInteger findBar_index =
+ [subviews indexOfObject:[controller_ findBarView]];
+ EXPECT_NE(NSNotFound, findBar_index);
+ NSUInteger toolbar_index =
+ [subviews indexOfObject:[controller_ toolbarView]];
+ EXPECT_NE(NSNotFound, toolbar_index);
+ NSUInteger bookmark_index =
+ [subviews indexOfObject:[controller_ bookmarkView]];
+ EXPECT_NE(NSNotFound, bookmark_index);
+
+ EXPECT_GT(findBar_index, toolbar_index);
+ EXPECT_GT(findBar_index, bookmark_index);
+}
+
+// Tests that the sidebar view and devtools view are both non-opaque.
+TEST_F(BrowserWindowControllerTest, TestSplitViewsAreNotOpaque) {
+ // Add a subview to the sidebar view to mimic what happens when a tab is added
+ // to the window. NSSplitView only marks itself as non-opaque when one of its
+ // subviews is non-opaque, so the test will not pass without this subview.
+ scoped_nsobject<NSView> view(
+ [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 10, 10)]);
+ [[controller_ sidebarView] addSubview:view];
+
+ EXPECT_FALSE([[controller_ tabContentArea] isOpaque]);
+ EXPECT_FALSE([[controller_ devToolsView] isOpaque]);
+ EXPECT_FALSE([[controller_ sidebarView] isOpaque]);
+}
+
+// Tests that status bubble's base frame does move when devTools are docked.
+TEST_F(BrowserWindowControllerTest, TestStatusBubblePositioning) {
+ ASSERT_EQ(1U, [[[controller_ devToolsView] subviews] count]);
+
+ NSPoint bubbleOrigin = [controller_ statusBubbleBaseFrame].origin;
+
+ // Add a fake subview to devToolsView to emulate docked devTools.
+ scoped_nsobject<NSView> view(
+ [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 10, 10)]);
+ [[controller_ devToolsView] addSubview:view];
+ [[controller_ devToolsView] adjustSubviews];
+
+ NSPoint bubbleOriginWithDevTools = [controller_ statusBubbleBaseFrame].origin;
+
+ // Make sure that status bubble frame is moved.
+ EXPECT_FALSE(NSEqualPoints(bubbleOrigin, bubbleOriginWithDevTools));
+}
+
+@interface BrowserWindowControllerFakeFullscreen : BrowserWindowController {
+ @private
+ // We release the window ourselves, so we don't have to rely on the unittest
+ // doing it for us.
+ scoped_nsobject<NSWindow> fullscreenWindow_;
+}
+@end
+
+class BrowserWindowFullScreenControllerTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ Browser* browser = browser_helper_.browser();
+ controller_ =
+ [[BrowserWindowControllerFakeFullscreen alloc] initWithBrowser:browser
+ takeOwnership:NO];
+ }
+
+ virtual void TearDown() {
+ [controller_ close];
+ CocoaTest::TearDown();
+ }
+
+ public:
+ BrowserTestHelper browser_helper_;
+ BrowserWindowController* controller_;
+};
+
+@interface BrowserWindowController (PrivateAPI)
+- (BOOL)supportsFullscreen;
+@end
+
+TEST_F(BrowserWindowFullScreenControllerTest, TestFullscreen) {
+ EXPECT_FALSE([controller_ isFullscreen]);
+ [controller_ setFullscreen:YES];
+ EXPECT_TRUE([controller_ isFullscreen]);
+ [controller_ setFullscreen:NO];
+ EXPECT_FALSE([controller_ isFullscreen]);
+}
+
+// If this test fails, it is usually a sign that the bots have some sort of
+// problem (such as a modal dialog up). This tests is a very useful canary, so
+// please do not mark it as flaky without first verifying that there are no bot
+// problems.
+TEST_F(BrowserWindowFullScreenControllerTest, TestActivate) {
+ EXPECT_FALSE([controller_ isFullscreen]);
+
+ [controller_ activate];
+ NSWindow* frontmostWindow = [[NSApp orderedWindows] objectAtIndex:0];
+ EXPECT_EQ(frontmostWindow, [controller_ window]);
+
+ [controller_ setFullscreen:YES];
+ [controller_ activate];
+ frontmostWindow = [[NSApp orderedWindows] objectAtIndex:0];
+ EXPECT_EQ(frontmostWindow, [controller_ createFullscreenWindow]);
+
+ // We have to cleanup after ourselves by unfullscreening.
+ [controller_ setFullscreen:NO];
+}
+
+@implementation BrowserWindowControllerFakeFullscreen
+// Override |-createFullscreenWindow| to return a dummy window. This isn't
+// needed to pass the test, but because the dummy window is only 100x100, it
+// prevents the real fullscreen window from flashing up and taking over the
+// whole screen. We have to return an actual window because |-layoutSubviews|
+// looks at the window's frame.
+- (NSWindow*)createFullscreenWindow {
+ if (fullscreenWindow_.get())
+ return fullscreenWindow_.get();
+
+ fullscreenWindow_.reset(
+ [[NSWindow alloc] initWithContentRect:NSMakeRect(0,0,400,400)
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO]);
+ return fullscreenWindow_.get();
+}
+@end
+
+/* TODO(???): test other methods of BrowserWindowController */
diff --git a/chrome/browser/ui/cocoa/browser_window_factory.mm b/chrome/browser/ui/cocoa/browser_window_factory.mm
new file mode 100644
index 0000000..e7222e7
--- /dev/null
+++ b/chrome/browser/ui/cocoa/browser_window_factory.mm
@@ -0,0 +1,32 @@
+// 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.
+
+#include "base/basictypes.h"
+#include "chrome/browser/ui/cocoa/browser_window_cocoa.h"
+#include "chrome/browser/ui/cocoa/browser_window_controller.h"
+#include "chrome/browser/ui/cocoa/find_bar_bridge.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
+
+// Create the controller for the Browser, which handles loading the browser
+// window from the nib. The controller takes ownership of |browser|.
+// static
+BrowserWindow* BrowserWindow::CreateBrowserWindow(Browser* browser) {
+ BrowserWindowController* controller =
+ [[BrowserWindowController alloc] initWithBrowser:browser];
+ return [controller browserWindow];
+}
+
+// static
+FindBar* BrowserWindow::CreateFindBar(Browser* browser) {
+ // We could push the AddFindBar() call into the FindBarBridge
+ // constructor or the FindBarCocoaController init, but that makes
+ // unit testing difficult, since we would also require a
+ // BrowserWindow object.
+ BrowserWindowCocoa* window =
+ static_cast<BrowserWindowCocoa*>(browser->window());
+ FindBarBridge* bridge = new FindBarBridge();
+ window->AddFindBar(bridge->find_bar_cocoa_controller());
+ return bridge;
+}
diff --git a/chrome/browser/cocoa/bubble_view.h b/chrome/browser/ui/cocoa/bubble_view.h
index 755c8a4..755c8a4 100644
--- a/chrome/browser/cocoa/bubble_view.h
+++ b/chrome/browser/ui/cocoa/bubble_view.h
diff --git a/chrome/browser/ui/cocoa/bubble_view.mm b/chrome/browser/ui/cocoa/bubble_view.mm
new file mode 100644
index 0000000..a888ebc
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bubble_view.mm
@@ -0,0 +1,120 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/bubble_view.h"
+
+#include "chrome/browser/themes/browser_theme_provider.h"
+#import "chrome/browser/ui/cocoa/themed_window.h"
+#import "third_party/GTM/AppKit/GTMNSBezierPath+RoundRect.h"
+#import "third_party/GTM/AppKit/GTMNSColor+Luminance.h"
+
+// The roundedness of the edges of our bubble.
+const int kBubbleCornerRadius = 4.0f;
+const float kWindowEdge = 0.7f;
+
+@implementation BubbleView
+
+// Designated initializer. |provider| is the window from which we get the
+// current theme to draw text and backgrounds. If nil, the current window will
+// be checked. The caller needs to ensure |provider| can't go away as it will
+// not be retained. Defaults to all corners being rounded.
+- (id)initWithFrame:(NSRect)frame themeProvider:(NSWindow*)provider {
+ if ((self = [super initWithFrame:frame])) {
+ cornerFlags_ = kRoundedAllCorners;
+ themeProvider_ = provider;
+ }
+ return self;
+}
+
+// Sets the string displayed in the bubble. A copy of the string is made.
+- (void)setContent:(NSString*)content {
+ if ([content_ isEqualToString:content])
+ return;
+ content_.reset([content copy]);
+ [self setNeedsDisplay:YES];
+}
+
+// Sets which corners will be rounded.
+- (void)setCornerFlags:(unsigned long)flags {
+ if (cornerFlags_ == flags)
+ return;
+ cornerFlags_ = flags;
+ [self setNeedsDisplay:YES];
+}
+
+- (void)setThemeProvider:(NSWindow*)provider {
+ if (themeProvider_ == provider)
+ return;
+ themeProvider_ = provider;
+ [self setNeedsDisplay:YES];
+}
+
+- (NSString*)content {
+ return content_.get();
+}
+
+- (unsigned long)cornerFlags {
+ return cornerFlags_;
+}
+
+// The font used to display the content string.
+- (NSFont*)font {
+ return [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
+}
+
+// Draws the themed background and the text. Will draw a gray bg if no theme.
+- (void)drawRect:(NSRect)rect {
+ float topLeftRadius =
+ cornerFlags_ & kRoundedTopLeftCorner ? kBubbleCornerRadius : 0;
+ float topRightRadius =
+ cornerFlags_ & kRoundedTopRightCorner ? kBubbleCornerRadius : 0;
+ float bottomLeftRadius =
+ cornerFlags_ & kRoundedBottomLeftCorner ? kBubbleCornerRadius : 0;
+ float bottomRightRadius =
+ cornerFlags_ & kRoundedBottomRightCorner ? kBubbleCornerRadius : 0;
+
+ ThemeProvider* themeProvider =
+ themeProvider_ ? [themeProvider_ themeProvider] :
+ [[self window] themeProvider];
+
+ // Background / Edge
+
+ NSRect bounds = [self bounds];
+ bounds = NSInsetRect(bounds, 0.5, 0.5);
+ NSBezierPath* border =
+ [NSBezierPath gtm_bezierPathWithRoundRect:bounds
+ topLeftCornerRadius:topLeftRadius
+ topRightCornerRadius:topRightRadius
+ bottomLeftCornerRadius:bottomLeftRadius
+ bottomRightCornerRadius:bottomRightRadius];
+
+ if (themeProvider)
+ [themeProvider->GetNSColor(BrowserThemeProvider::COLOR_TOOLBAR, true) set];
+ [border fill];
+
+ [[NSColor colorWithDeviceWhite:kWindowEdge alpha:1.0f] set];
+ [border stroke];
+
+ // Text
+ NSColor* textColor = [NSColor blackColor];
+ if (themeProvider)
+ textColor = themeProvider->GetNSColor(BrowserThemeProvider::COLOR_TAB_TEXT,
+ true);
+ NSFont* textFont = [self font];
+ scoped_nsobject<NSShadow> textShadow([[NSShadow alloc] init]);
+ [textShadow setShadowBlurRadius:0.0f];
+ [textShadow.get() setShadowColor:[textColor gtm_legibleTextColor]];
+ [textShadow.get() setShadowOffset:NSMakeSize(0.0f, -1.0f)];
+
+ NSDictionary* textDict = [NSDictionary dictionaryWithObjectsAndKeys:
+ textColor, NSForegroundColorAttributeName,
+ textFont, NSFontAttributeName,
+ textShadow.get(), NSShadowAttributeName,
+ nil];
+ [content_ drawAtPoint:NSMakePoint(kBubbleViewTextPositionX,
+ kBubbleViewTextPositionY)
+ withAttributes:textDict];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/bubble_view_unittest.mm b/chrome/browser/ui/cocoa/bubble_view_unittest.mm
new file mode 100644
index 0000000..5d788ea
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bubble_view_unittest.mm
@@ -0,0 +1,58 @@
+// Copyright (c) 2009 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/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/bubble_view.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "testing/gtest_mac.h"
+
+class BubbleViewTest : public CocoaTest {
+ public:
+ BubbleViewTest() {
+ NSRect frame = NSMakeRect(0, 0, 50, 50);
+ scoped_nsobject<BubbleView> view(
+ [[BubbleView alloc] initWithFrame:frame themeProvider:test_window()]);
+ view_ = view.get();
+ [[test_window() contentView] addSubview:view_];
+ [view_ setContent:@"Hi there, I'm a bubble view"];
+ }
+
+ BubbleView* view_;
+};
+
+TEST_VIEW(BubbleViewTest, view_);
+
+// Test a nil themeProvider in init.
+TEST_F(BubbleViewTest, NilThemeProvider) {
+ NSRect frame = NSMakeRect(0, 0, 50, 50);
+ scoped_nsobject<BubbleView> view(
+ [[BubbleView alloc] initWithFrame:frame themeProvider:nil]);
+ [[test_window() contentView] addSubview:view.get()];
+ [view display];
+}
+
+// Make sure things don't go haywire when given invalid or long strings.
+TEST_F(BubbleViewTest, SetContent) {
+ [view_ setContent:nil];
+ EXPECT_TRUE([view_ content] == nil);
+ [view_ setContent:@""];
+ EXPECT_NSEQ(@"", [view_ content]);
+ NSString* str = @"This is a really really long string that's just too long";
+ [view_ setContent:str];
+ EXPECT_NSEQ(str, [view_ content]);
+}
+
+TEST_F(BubbleViewTest, CornerFlags) {
+ // Set some random flags just to check.
+ [view_ setCornerFlags:kRoundedTopRightCorner | kRoundedTopLeftCorner];
+ EXPECT_EQ([view_ cornerFlags],
+ (unsigned long)kRoundedTopRightCorner | kRoundedTopLeftCorner);
+ // Set no flags (all 4 draw corners are square).
+ [view_ setCornerFlags:0];
+ EXPECT_EQ([view_ cornerFlags], 0UL);
+ // Set all bits. Meaningless past the first 4, but harmless to set too many.
+ [view_ setCornerFlags:0xFFFFFFFF];
+ EXPECT_EQ([view_ cornerFlags], 0xFFFFFFFF);
+}
diff --git a/chrome/browser/ui/cocoa/bug_report_window_controller.h b/chrome/browser/ui/cocoa/bug_report_window_controller.h
new file mode 100644
index 0000000..15aa707
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bug_report_window_controller.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_BUG_REPORT_WINDOW_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_BUG_REPORT_WINDOW_CONTROLLER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include <vector>
+
+#include "base/scoped_nsobject.h"
+
+class Profile;
+class TabContents;
+
+// A window controller for managing the "Report Bug" feature. Modally
+// presents a dialog that allows the user to either file a bug report on
+// a broken page, or go directly to Google's "Report Phishing" page and
+// file a report there.
+@interface BugReportWindowController : NSWindowController {
+ @private
+ TabContents* currentTab_; // Weak, owned by browser.
+ Profile* profile_; // Weak, owned by browser.
+
+ // Holds screenshot of current tab.
+ std::vector<unsigned char> pngData_;
+ // Width and height of the current tab's screenshot.
+ int pngWidth_;
+ int pngHeight_;
+
+ // Values bound to data in the dialog box. These values cannot be boxed in
+ // scoped_nsobjects because we use them for bindings.
+ NSString* bugDescription_; // Strong.
+ NSUInteger bugTypeIndex_;
+ NSString* pageTitle_; // Strong.
+ NSString* pageURL_; // Strong.
+
+ // We keep a pointer to this button so we can change its title.
+ IBOutlet NSButton* sendReportButton_;
+
+ // This button must be moved when the send report button changes title.
+ IBOutlet NSButton* cancelButton_;
+
+ // The popup button that allows choice of bug type.
+ IBOutlet NSPopUpButton* bugTypePopUpButton_;
+
+ // YES sends a screenshot along with the bug report.
+ BOOL sendScreenshot_;
+
+ // Disable screenshot if no browser window is open.
+ BOOL disableScreenshotCheckbox_;
+
+ // Menu for the bug type popup button. We create it here instead of in
+ // IB so that we can nicely check whether the phishing page is selected,
+ // and so that we can create a menu without "page" options when no browser
+ // window is open.
+ NSMutableArray* bugTypeList_; // Strong.
+
+ // When dialog switches from regular bug reports to phishing page, "save
+ // screenshot" and "description" are disabled. Save the state of this value
+ // to restore if the user switches back to a regular bug report before
+ // sending.
+ BOOL saveSendScreenshot_;
+ scoped_nsobject<NSString> saveBugDescription_; // Strong
+
+ // Maps bug type menu item title strings to BugReportUtil::BugType ints.
+ NSDictionary* bugTypeDictionary_; // Strong
+}
+
+// Initialize with the contents of the tab to be reported as buggy / wrong.
+// If dialog is called without an open window, currentTab may be null; in
+// that case, a dialog is opened with options for reporting a bugs not
+// related to a specific page. Profile is passed to BugReportUtil, who
+// will not send a report if the value is null.
+- (id)initWithTabContents:(TabContents*)currentTab profile:(Profile*)profile;
+
+// Run the dialog with an application-modal event loop. If the user accepts,
+// send the report of the bug or broken web site.
+- (void)runModalDialog;
+
+// IBActions for the dialog buttons.
+- (IBAction)sendReport:(id)sender;
+- (IBAction)cancel:(id)sender;
+
+// YES if the user has selected the phishing report option.
+- (BOOL)isPhishingReport;
+
+// Converts the bug type from the menu into the correct value for the bug type
+// from BugReportUtil::BugType.
+- (int)bugTypeFromIndex;
+
+// Force the description text field to allow "return" to go to the next line
+// within the description field. Without this delegate method, "return" falls
+// back to the "Send Report" action, because this button has been bound to
+// the return key in IB.
+- (BOOL)control:(NSControl*)control textView:(NSTextView*)textView
+ doCommandBySelector:(SEL)commandSelector;
+
+// Properties for bindings.
+@property (nonatomic, copy) NSString* bugDescription;
+@property (nonatomic) NSUInteger bugTypeIndex;
+@property (nonatomic, copy) NSString* pageTitle;
+@property (nonatomic, copy) NSString* pageURL;
+@property (nonatomic) BOOL sendScreenshot;
+@property (nonatomic) BOOL disableScreenshotCheckbox;
+@property (nonatomic, readonly) NSArray* bugTypeList;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_BUG_REPORT_WINDOW_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/bug_report_window_controller.mm b/chrome/browser/ui/cocoa/bug_report_window_controller.mm
new file mode 100644
index 0000000..82b3a36
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bug_report_window_controller.mm
@@ -0,0 +1,231 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/bug_report_window_controller.h"
+
+#include "app/l10n_util_mac.h"
+#include "base/mac_util.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/bug_report_util.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_contents_view.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
+
+@implementation BugReportWindowController
+
+@synthesize bugDescription = bugDescription_;
+@synthesize bugTypeIndex = bugTypeIndex_;
+@synthesize pageURL = pageURL_;
+@synthesize pageTitle = pageTitle_;
+@synthesize sendScreenshot = sendScreenshot_;
+@synthesize disableScreenshotCheckbox = disableScreenshotCheckbox_;
+@synthesize bugTypeList = bugTypeList_;
+
+- (id)initWithTabContents:(TabContents*)currentTab
+ profile:(Profile*)profile {
+ NSString* nibpath = [mac_util::MainAppBundle() pathForResource:@"ReportBug"
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
+ currentTab_ = currentTab;
+ profile_ = profile;
+
+ // The order of strings in this array must match the order of the bug types
+ // declared below in the bugTypeFromIndex function.
+ bugTypeList_ = [[NSMutableArray alloc] initWithObjects:
+ l10n_util::GetNSStringWithFixup(IDS_BUGREPORT_CHROME_MISBEHAVES),
+ l10n_util::GetNSStringWithFixup(IDS_BUGREPORT_SOMETHING_MISSING),
+ l10n_util::GetNSStringWithFixup(IDS_BUGREPORT_BROWSER_CRASH),
+ l10n_util::GetNSStringWithFixup(IDS_BUGREPORT_OTHER_PROBLEM),
+ nil];
+
+ if (currentTab_ != NULL) {
+ // Get data from current tab, if one exists. This dialog could be called
+ // from the main menu with no tab contents, so currentTab_ is not
+ // guaranteed to be non-NULL.
+ // TODO(mirandac): This dialog should be a tab-modal sheet if a browser
+ // window exists.
+ [self setSendScreenshot:YES];
+ [self setDisableScreenshotCheckbox:NO];
+ // Insert menu items about bugs related to specific pages.
+ [bugTypeList_ insertObjects:
+ [NSArray arrayWithObjects:
+ l10n_util::GetNSStringWithFixup(IDS_BUGREPORT_PAGE_WONT_LOAD),
+ l10n_util::GetNSStringWithFixup(IDS_BUGREPORT_PAGE_LOOKS_ODD),
+ l10n_util::GetNSStringWithFixup(IDS_BUGREPORT_PHISHING_PAGE),
+ l10n_util::GetNSStringWithFixup(IDS_BUGREPORT_CANT_SIGN_IN),
+ nil]
+ atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 4)]];
+
+ [self setPageURL:base::SysUTF8ToNSString(
+ currentTab_->controller().GetActiveEntry()->url().spec())];
+ [self setPageTitle:base::SysUTF16ToNSString(currentTab_->GetTitle())];
+ mac_util::GrabWindowSnapshot(
+ currentTab_->view()->GetTopLevelNativeWindow(), &pngData_,
+ &pngWidth_, &pngHeight_);
+ } else {
+ // If no current tab exists, create a menu without the "broken page"
+ // options, with page URL and title empty, and screenshot disabled.
+ [self setSendScreenshot:NO];
+ [self setDisableScreenshotCheckbox:YES];
+ }
+
+ pngHeight_ = 0;
+ pngWidth_ = 0;
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [pageURL_ release];
+ [pageTitle_ release];
+ [bugDescription_ release];
+ [bugTypeList_ release];
+ [bugTypeDictionary_ release];
+ [super dealloc];
+}
+
+// Delegate callback so that closing the window deletes the controller.
+- (void)windowWillClose:(NSNotification*)notification {
+ [self autorelease];
+}
+
+- (void)closeDialog {
+ [NSApp stopModal];
+ [[self window] close];
+}
+
+- (void)runModalDialog {
+ NSWindow* bugReportWindow = [self window];
+ [bugReportWindow center];
+ [NSApp runModalForWindow:bugReportWindow];
+}
+
+- (IBAction)sendReport:(id)sender {
+ if ([self isPhishingReport]) {
+ BugReportUtil::ReportPhishing(currentTab_,
+ pageURL_ ? base::SysNSStringToUTF8(pageURL_) : "");
+ } else {
+ BugReportUtil::SendReport(
+ profile_,
+ base::SysNSStringToUTF8(pageTitle_),
+ [self bugTypeFromIndex],
+ base::SysNSStringToUTF8(pageURL_),
+ base::SysNSStringToUTF8(bugDescription_),
+ sendScreenshot_ && !pngData_.empty() ?
+ reinterpret_cast<const char *>(&(pngData_[0])) : NULL,
+ pngData_.size(), pngWidth_, pngHeight_);
+ }
+ [self closeDialog];
+}
+
+- (IBAction)cancel:(id)sender {
+ [self closeDialog];
+}
+
+- (BOOL)isPhishingReport {
+ return [self bugTypeFromIndex] == BugReportUtil::PHISHING_PAGE;
+}
+
+- (int)bugTypeFromIndex {
+ // The order of these bugs must match the ordering in the bugTypeList_,
+ // and thereby the menu in the popup button in the dialog box.
+ const BugReportUtil::BugType typesForMenuIndices[] = {
+ BugReportUtil::PAGE_WONT_LOAD,
+ BugReportUtil::PAGE_LOOKS_ODD,
+ BugReportUtil::PHISHING_PAGE,
+ BugReportUtil::CANT_SIGN_IN,
+ BugReportUtil::CHROME_MISBEHAVES,
+ BugReportUtil::SOMETHING_MISSING,
+ BugReportUtil::BROWSER_CRASH,
+ BugReportUtil::OTHER_PROBLEM
+ };
+ // The bugs for the shorter menu start at index 4.
+ NSUInteger adjustedBugTypeIndex_ = [bugTypeList_ count] == 8 ? bugTypeIndex_ :
+ bugTypeIndex_ + 4;
+ DCHECK_LT(adjustedBugTypeIndex_, arraysize(typesForMenuIndices));
+ return typesForMenuIndices[adjustedBugTypeIndex_];
+}
+
+// Custom setter to update the UI for different bug types.
+- (void)setBugTypeIndex:(NSUInteger)bugTypeIndex {
+ bugTypeIndex_ = bugTypeIndex;
+
+ // The "send" button's title is based on the type of report.
+ NSString* buttonTitle = [self isPhishingReport] ?
+ l10n_util::GetNSStringWithFixup(IDS_BUGREPORT_SEND_PHISHING_REPORT) :
+ l10n_util::GetNSStringWithFixup(IDS_BUGREPORT_SEND_REPORT);
+ if (![buttonTitle isEqualTo:[sendReportButton_ title]]) {
+ NSRect sendFrame1 = [sendReportButton_ frame];
+ NSRect cancelFrame1 = [cancelButton_ frame];
+
+ [sendReportButton_ setTitle:buttonTitle];
+ CGFloat deltaWidth =
+ [GTMUILocalizerAndLayoutTweaker sizeToFitView:sendReportButton_].width;
+
+ NSRect sendFrame2 = [sendReportButton_ frame];
+ sendFrame2.origin.x -= deltaWidth;
+ NSRect cancelFrame2 = cancelFrame1;
+ cancelFrame2.origin.x -= deltaWidth;
+
+ // Since the buttons get updated/resize, use a quick animation so it is
+ // a little less jarring in the UI.
+ NSDictionary* sendReportButtonResize =
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ sendReportButton_, NSViewAnimationTargetKey,
+ [NSValue valueWithRect:sendFrame1], NSViewAnimationStartFrameKey,
+ [NSValue valueWithRect:sendFrame2], NSViewAnimationEndFrameKey,
+ nil];
+ NSDictionary* cancelButtonResize =
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ cancelButton_, NSViewAnimationTargetKey,
+ [NSValue valueWithRect:cancelFrame1], NSViewAnimationStartFrameKey,
+ [NSValue valueWithRect:cancelFrame2], NSViewAnimationEndFrameKey,
+ nil];
+ NSAnimation* animation =
+ [[[NSViewAnimation alloc] initWithViewAnimations:
+ [NSArray arrayWithObjects:sendReportButtonResize, cancelButtonResize,
+ nil]] autorelease];
+ const NSTimeInterval kQuickTransitionInterval = 0.1;
+ [animation setDuration:kQuickTransitionInterval];
+ [animation startAnimation];
+
+ // Save or reload description when moving between phishing page and other
+ // bug report types.
+ if ([self isPhishingReport]) {
+ saveBugDescription_.reset([[self bugDescription] retain]);
+ [self setBugDescription:nil];
+ saveSendScreenshot_ = sendScreenshot_;
+ [self setSendScreenshot:NO];
+ } else {
+ [self setBugDescription:saveBugDescription_.get()];
+ saveBugDescription_.reset();
+ [self setSendScreenshot:saveSendScreenshot_];
+ }
+ }
+}
+
+- (BOOL)control:(NSControl*)control textView:(NSTextView*)textView
+ doCommandBySelector:(SEL)commandSelector {
+ if (commandSelector == @selector(insertNewline:)) {
+ [textView insertNewlineIgnoringFieldEditor:self];
+ return YES;
+ }
+ return NO;
+}
+
+// BugReportWindowController needs to change the title of the Send Report
+// button when the user chooses the phishing bug type, so we need to bind
+// the function that changes the button title to the bug type key.
++ (NSSet*)keyPathsForValuesAffectingValueForKey:(NSString*)key {
+ NSSet* paths = [super keyPathsForValuesAffectingValueForKey:key];
+ if ([key isEqualToString:@"isPhishingReport"]) {
+ paths = [paths setByAddingObject:@"bugTypeIndex"];
+ }
+ return paths;
+}
+
+@end
+
diff --git a/chrome/browser/ui/cocoa/bug_report_window_controller_unittest.mm b/chrome/browser/ui/cocoa/bug_report_window_controller_unittest.mm
new file mode 100644
index 0000000..9870639
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bug_report_window_controller_unittest.mm
@@ -0,0 +1,78 @@
+// Copyright (c) 2009 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 "base/ref_counted.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/site_instance.h"
+#include "chrome/browser/renderer_host/test/test_render_view_host.h"
+#include "chrome/browser/tab_contents/test_tab_contents.h"
+#import "chrome/browser/ui/cocoa/bug_report_window_controller.h"
+#include "chrome/test/testing_profile.h"
+#import "testing/gtest_mac.h"
+
+namespace {
+
+class BugReportWindowControllerUnittest : public RenderViewHostTestHarness {
+};
+
+// See http://crbug.com/29019 for why it's disabled.
+TEST_F(BugReportWindowControllerUnittest, DISABLED_ReportBugWithNewTabPageOpen) {
+ BrowserThread ui_thread(BrowserThread::UI, MessageLoop::current());
+ // Create a "chrome://newtab" test tab. SiteInstance will be deleted when
+ // tabContents is deleted.
+ SiteInstance* instance =
+ SiteInstance::CreateSiteInstance(profile_.get());
+ TestTabContents* tabContents = new TestTabContents(profile_.get(),
+ instance);
+ tabContents->controller().LoadURL(GURL("chrome://newtab"),
+ GURL(), PageTransition::START_PAGE);
+
+ BugReportWindowController* controller = [[BugReportWindowController alloc]
+ initWithTabContents:tabContents
+ profile:profile_.get()];
+
+ // The phishing report bug is stored at index 2 in the Report Bug dialog.
+ [controller setBugTypeIndex:2];
+ EXPECT_TRUE([controller isPhishingReport]);
+ [controller setBugTypeIndex:1];
+ EXPECT_FALSE([controller isPhishingReport]);
+
+ // Make sure that the tab was correctly recorded.
+ EXPECT_NSEQ(@"chrome://newtab/", [controller pageURL]);
+ EXPECT_NSEQ(@"New Tab", [controller pageTitle]);
+
+ // When we call "report bug" with non-empty tab contents, all menu options
+ // should be available, and we should send screenshot by default.
+ EXPECT_EQ([[controller bugTypeList] count], 8U);
+ EXPECT_TRUE([controller sendScreenshot]);
+
+ delete tabContents;
+ [controller release];
+}
+
+// See http://crbug.com/29019 for why it's disabled.
+TEST_F(BugReportWindowControllerUnittest, DISABLED_ReportBugWithNoWindowOpen) {
+ BugReportWindowController* controller = [[BugReportWindowController alloc]
+ initWithTabContents:NULL
+ profile:profile_.get()];
+
+ // Make sure that no page title or URL are recorded. Note that IB reports
+ // empty textfields as NULL values.
+ EXPECT_FALSE([controller pageURL]);
+ EXPECT_FALSE([controller pageTitle]);
+
+ // When we call "report bug" with empty tab contents, only menu options
+ // that don't refer to a specific page should be available, and the send
+ // screenshot option should be turned off.
+ EXPECT_EQ([[controller bugTypeList] count], 4U);
+ EXPECT_FALSE([controller sendScreenshot]);
+
+ [controller release];
+}
+
+} // namespace
+
diff --git a/chrome/browser/cocoa/certificate_viewer.mm b/chrome/browser/ui/cocoa/certificate_viewer.mm
index 8c5a954..8c5a954 100644
--- a/chrome/browser/cocoa/certificate_viewer.mm
+++ b/chrome/browser/ui/cocoa/certificate_viewer.mm
diff --git a/chrome/browser/ui/cocoa/chrome_browser_window.h b/chrome/browser/ui/cocoa/chrome_browser_window.h
new file mode 100644
index 0000000..64c0123
--- /dev/null
+++ b/chrome/browser/ui/cocoa/chrome_browser_window.h
@@ -0,0 +1,28 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_CHROME_BROWSER_WINDOW_H_
+#define CHROME_BROWSER_UI_COCOA_CHROME_BROWSER_WINDOW_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "chrome/browser/ui/cocoa/chrome_event_processing_window.h"
+
+// Common base class for chrome browser windows. Contains methods relating to
+// theming and hole punching that are shared between framed and fullscreen
+// windows.
+@interface ChromeBrowserWindow : ChromeEventProcessingWindow {
+ @private
+ int underlaySurfaceCount_;
+}
+
+// Informs the window that an underlay surface has been added/removed. The
+// window is non-opaque while underlay surfaces are present.
+- (void)underlaySurfaceAdded;
+- (void)underlaySurfaceRemoved;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_CHROME_BROWSER_WINDOW_H_
diff --git a/chrome/browser/ui/cocoa/chrome_browser_window.mm b/chrome/browser/ui/cocoa/chrome_browser_window.mm
new file mode 100644
index 0000000..abac221
--- /dev/null
+++ b/chrome/browser/ui/cocoa/chrome_browser_window.mm
@@ -0,0 +1,52 @@
+// 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 "chrome/browser/ui/cocoa/chrome_browser_window.h"
+
+#include "base/logging.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
+#import "chrome/browser/ui/cocoa/themed_window.h"
+
+@implementation ChromeBrowserWindow
+
+- (void)underlaySurfaceAdded {
+ DCHECK_GE(underlaySurfaceCount_, 0);
+ ++underlaySurfaceCount_;
+
+ // We're having the OpenGL surface render under the window, so the window
+ // needs to be not opaque.
+ if (underlaySurfaceCount_ == 1)
+ [self setOpaque:NO];
+}
+
+- (void)underlaySurfaceRemoved {
+ --underlaySurfaceCount_;
+ DCHECK_GE(underlaySurfaceCount_, 0);
+
+ if (underlaySurfaceCount_ == 0)
+ [self setOpaque:YES];
+}
+
+- (ThemeProvider*)themeProvider {
+ id delegate = [self delegate];
+ if (![delegate respondsToSelector:@selector(themeProvider)])
+ return NULL;
+ return [delegate themeProvider];
+}
+
+- (ThemedWindowStyle)themedWindowStyle {
+ id delegate = [self delegate];
+ if (![delegate respondsToSelector:@selector(themedWindowStyle)])
+ return THEMED_NORMAL;
+ return [delegate themedWindowStyle];
+}
+
+- (NSPoint)themePatternPhase {
+ id delegate = [self delegate];
+ if (![delegate respondsToSelector:@selector(themePatternPhase)])
+ return NSMakePoint(0, 0);
+ return [delegate themePatternPhase];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/chrome_browser_window_unittest.mm b/chrome/browser/ui/cocoa/chrome_browser_window_unittest.mm
new file mode 100644
index 0000000..196dc74
--- /dev/null
+++ b/chrome/browser/ui/cocoa/chrome_browser_window_unittest.mm
@@ -0,0 +1,45 @@
+// 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 "base/debug/debugger.h"
+#import "chrome/browser/ui/cocoa/chrome_browser_window.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+class ChromeBrowserWindowTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ // Create a window.
+ const NSUInteger mask = NSTitledWindowMask | NSClosableWindowMask |
+ NSMiniaturizableWindowMask | NSResizableWindowMask;
+ window_ = [[ChromeBrowserWindow alloc]
+ initWithContentRect:NSMakeRect(0, 0, 800, 600)
+ styleMask:mask
+ backing:NSBackingStoreBuffered
+ defer:NO];
+ if (base::debug::BeingDebugged()) {
+ [window_ orderFront:nil];
+ } else {
+ [window_ orderBack:nil];
+ }
+ }
+
+ virtual void TearDown() {
+ [window_ close];
+ CocoaTest::TearDown();
+ }
+
+ ChromeBrowserWindow* window_;
+};
+
+// Baseline test that the window creates, displays, closes, and
+// releases.
+TEST_F(ChromeBrowserWindowTest, ShowAndClose) {
+ [window_ display];
+}
diff --git a/chrome/browser/ui/cocoa/chrome_event_processing_window.h b/chrome/browser/ui/cocoa/chrome_event_processing_window.h
new file mode 100644
index 0000000..3524d6f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/chrome_event_processing_window.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_CHROME_EVENT_PROCESSING_WINDOW_H_
+#define CHROME_BROWSER_UI_COCOA_CHROME_EVENT_PROCESSING_WINDOW_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+
+// Override NSWindow to access unhandled keyboard events (for command
+// processing); subclassing NSWindow is the only method to do
+// this.
+@interface ChromeEventProcessingWindow : NSWindow {
+ @private
+ BOOL redispatchingEvent_;
+ BOOL eventHandled_;
+}
+
+// Sends a key event to |NSApp sendEvent:|, but also makes sure that it's not
+// short-circuited to the RWHV. This is used to send keyboard events to the menu
+// and the cmd-` handler if a keyboard event comes back unhandled from the
+// renderer. The event must be of type |NSKeyDown|, |NSKeyUp|, or
+// |NSFlagsChanged|.
+// Returns |YES| if |event| has been handled.
+- (BOOL)redispatchKeyEvent:(NSEvent*)event;
+
+// See global_keyboard_shortcuts_mac.h for details on the next two functions.
+
+// Checks if |event| is a window keyboard shortcut. If so, dispatches it to the
+// window controller's |executeCommand:| and returns |YES|.
+- (BOOL)handleExtraWindowKeyboardShortcut:(NSEvent*)event;
+
+// Checks if |event| is a delayed window keyboard shortcut. If so, dispatches
+// it to the window controller's |executeCommand:| and returns |YES|.
+- (BOOL)handleDelayedWindowKeyboardShortcut:(NSEvent*)event;
+
+// Checks if |event| is a browser keyboard shortcut. If so, dispatches it to the
+// window controller's |executeCommand:| and returns |YES|.
+- (BOOL)handleExtraBrowserKeyboardShortcut:(NSEvent*)event;
+
+// Override, so we can handle global keyboard events.
+- (BOOL)performKeyEquivalent:(NSEvent*)theEvent;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_CHROME_EVENT_PROCESSING_WINDOW_H_
diff --git a/chrome/browser/ui/cocoa/chrome_event_processing_window.mm b/chrome/browser/ui/cocoa/chrome_event_processing_window.mm
new file mode 100644
index 0000000..be6591b
--- /dev/null
+++ b/chrome/browser/ui/cocoa/chrome_event_processing_window.mm
@@ -0,0 +1,164 @@
+// 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 "chrome/browser/ui/cocoa/chrome_event_processing_window.h"
+
+#include "base/logging.h"
+#import "chrome/browser/renderer_host/render_widget_host_view_mac.h"
+#import "chrome/browser/ui/cocoa/browser_command_executor.h"
+#import "chrome/browser/ui/cocoa/browser_frame_view.h"
+#import "chrome/browser/ui/cocoa/tab_strip_controller.h"
+#include "chrome/browser/global_keyboard_shortcuts_mac.h"
+
+typedef int (*KeyToCommandMapper)(bool, bool, bool, bool, int, unichar);
+
+@interface ChromeEventProcessingWindow ()
+// Duplicate the given key event, but changing the associated window.
+- (NSEvent*)keyEventForWindow:(NSWindow*)window fromKeyEvent:(NSEvent*)event;
+@end
+
+@implementation ChromeEventProcessingWindow
+
+- (BOOL)handleExtraKeyboardShortcut:(NSEvent*)event fromTable:
+ (KeyToCommandMapper)commandForKeyboardShortcut {
+ // Extract info from |event|.
+ NSUInteger modifers = [event modifierFlags];
+ const bool cmdKey = modifers & NSCommandKeyMask;
+ const bool shiftKey = modifers & NSShiftKeyMask;
+ const bool cntrlKey = modifers & NSControlKeyMask;
+ const bool optKey = modifers & NSAlternateKeyMask;
+ const unichar keyCode = [event keyCode];
+ const unichar keyChar = KeyCharacterForEvent(event);
+
+ int cmdNum = commandForKeyboardShortcut(cmdKey, shiftKey, cntrlKey, optKey,
+ keyCode, keyChar);
+
+ if (cmdNum != -1) {
+ id executor = [self delegate];
+ // A bit of sanity.
+ DCHECK([executor conformsToProtocol:@protocol(BrowserCommandExecutor)]);
+ DCHECK([executor respondsToSelector:@selector(executeCommand:)]);
+ [executor executeCommand:cmdNum];
+ return YES;
+ }
+ return NO;
+}
+
+- (BOOL)handleExtraWindowKeyboardShortcut:(NSEvent*)event {
+ return [self handleExtraKeyboardShortcut:event
+ fromTable:CommandForWindowKeyboardShortcut];
+}
+
+- (BOOL)handleDelayedWindowKeyboardShortcut:(NSEvent*)event {
+ return [self handleExtraKeyboardShortcut:event
+ fromTable:CommandForDelayedWindowKeyboardShortcut];
+}
+
+- (BOOL)handleExtraBrowserKeyboardShortcut:(NSEvent*)event {
+ return [self handleExtraKeyboardShortcut:event
+ fromTable:CommandForBrowserKeyboardShortcut];
+}
+
+- (BOOL)performKeyEquivalent:(NSEvent*)event {
+ if (redispatchingEvent_)
+ return NO;
+
+ // Give the web site a chance to handle the event. If it doesn't want to
+ // handle it, it will call us back with one of the |handle*| methods above.
+ NSResponder* r = [self firstResponder];
+ if ([r isKindOfClass:[RenderWidgetHostViewCocoa class]])
+ return [r performKeyEquivalent:event];
+
+ // If the delegate does not implement the BrowserCommandExecutor protocol,
+ // then we don't need to handle browser specific shortcut keys.
+ if (![[self delegate] conformsToProtocol:@protocol(BrowserCommandExecutor)])
+ return [super performKeyEquivalent:event];
+
+ // Handle per-window shortcuts like cmd-1, but do not handle browser-level
+ // shortcuts like cmd-left (else, cmd-left would do history navigation even
+ // if e.g. the Omnibox has focus).
+ if ([self handleExtraWindowKeyboardShortcut:event])
+ return YES;
+
+ if ([super performKeyEquivalent:event])
+ return YES;
+
+ // Handle per-window shortcuts like Esc after giving everybody else a chance
+ // to handle them
+ return [self handleDelayedWindowKeyboardShortcut:event];
+}
+
+- (BOOL)redispatchKeyEvent:(NSEvent*)event {
+ DCHECK(event);
+ NSEventType eventType = [event type];
+ if (eventType != NSKeyDown &&
+ eventType != NSKeyUp &&
+ eventType != NSFlagsChanged) {
+ NOTREACHED();
+ return YES; // Pretend it's been handled in an effort to limit damage.
+ }
+
+ // Ordinarily, the event's window should be this window. However, when
+ // switching between normal and fullscreen mode, we switch out the window, and
+ // the event's window might be the previous window (or even an earlier one if
+ // the renderer is running slowly and several mode switches occur). In this
+ // rare case, we synthesize a new key event so that its associate window
+ // (number) is our own.
+ if ([event window] != self)
+ event = [self keyEventForWindow:self fromKeyEvent:event];
+
+ // Redispatch the event.
+ eventHandled_ = YES;
+ redispatchingEvent_ = YES;
+ [NSApp sendEvent:event];
+ redispatchingEvent_ = NO;
+
+ // If the event was not handled by [NSApp sendEvent:], the sendEvent:
+ // method below will be called, and because |redispatchingEvent_| is YES,
+ // |eventHandled_| will be set to NO.
+ return eventHandled_;
+}
+
+- (void)sendEvent:(NSEvent*)event {
+ if (!redispatchingEvent_)
+ [super sendEvent:event];
+ else
+ eventHandled_ = NO;
+}
+
+- (NSEvent*)keyEventForWindow:(NSWindow*)window fromKeyEvent:(NSEvent*)event {
+ NSEventType eventType = [event type];
+
+ // Convert the event's location from the original window's coordinates into
+ // our own.
+ NSPoint eventLoc = [event locationInWindow];
+ eventLoc = [[event window] convertBaseToScreen:eventLoc];
+ eventLoc = [self convertScreenToBase:eventLoc];
+
+ // Various things *only* apply to key down/up.
+ BOOL eventIsARepeat = NO;
+ NSString* eventCharacters = nil;
+ NSString* eventUnmodCharacters = nil;
+ if (eventType == NSKeyDown || eventType == NSKeyUp) {
+ eventIsARepeat = [event isARepeat];
+ eventCharacters = [event characters];
+ eventUnmodCharacters = [event charactersIgnoringModifiers];
+ }
+
+ // This synthesis may be slightly imperfect: we provide nil for the context,
+ // since I (viettrungluu) am sceptical that putting in the original context
+ // (if one is given) is valid.
+ return [NSEvent keyEventWithType:eventType
+ location:eventLoc
+ modifierFlags:[event modifierFlags]
+ timestamp:[event timestamp]
+ windowNumber:[window windowNumber]
+ context:nil
+ characters:eventCharacters
+ charactersIgnoringModifiers:eventUnmodCharacters
+ isARepeat:eventIsARepeat
+ keyCode:[event keyCode]];
+}
+
+@end // ChromeEventProcessingWindow
diff --git a/chrome/browser/ui/cocoa/chrome_event_processing_window_unittest.mm b/chrome/browser/ui/cocoa/chrome_event_processing_window_unittest.mm
new file mode 100644
index 0000000..9cbb8e0
--- /dev/null
+++ b/chrome/browser/ui/cocoa/chrome_event_processing_window_unittest.mm
@@ -0,0 +1,104 @@
+// Copyright (c) 2009 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/debug/debugger.h"
+#include "base/scoped_nsobject.h"
+#include "chrome/app/chrome_command_ids.h"
+#import "chrome/browser/ui/cocoa/chrome_event_processing_window.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "chrome/browser/ui/cocoa/browser_frame_view.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+
+namespace {
+
+NSEvent* KeyEvent(const NSUInteger flags, const NSUInteger keyCode) {
+ return [NSEvent keyEventWithType:NSKeyDown
+ location:NSZeroPoint
+ modifierFlags:flags
+ timestamp:0.0
+ windowNumber:0
+ context:nil
+ characters:@""
+ charactersIgnoringModifiers:@""
+ isARepeat:NO
+ keyCode:keyCode];
+}
+
+class ChromeEventProcessingWindowTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ // Create a window.
+ const NSUInteger mask = NSTitledWindowMask | NSClosableWindowMask |
+ NSMiniaturizableWindowMask | NSResizableWindowMask;
+ window_ = [[ChromeEventProcessingWindow alloc]
+ initWithContentRect:NSMakeRect(0, 0, 800, 600)
+ styleMask:mask
+ backing:NSBackingStoreBuffered
+ defer:NO];
+ if (base::debug::BeingDebugged()) {
+ [window_ orderFront:nil];
+ } else {
+ [window_ orderBack:nil];
+ }
+ }
+
+ virtual void TearDown() {
+ [window_ close];
+ CocoaTest::TearDown();
+ }
+
+ ChromeEventProcessingWindow* window_;
+};
+
+id CreateBrowserWindowControllerMock() {
+ id delegate = [OCMockObject mockForClass:[BrowserWindowController class]];
+ // Make conformsToProtocol return YES for @protocol(BrowserCommandExecutor)
+ // to satisfy the DCHECK() in handleExtraKeyboardShortcut.
+ //
+ // TODO(akalin): Figure out how to replace OCMOCK_ANY below with
+ // @protocol(BrowserCommandExecutor) and have it work.
+ BOOL yes = YES;
+ [[[delegate stub] andReturnValue:OCMOCK_VALUE(yes)]
+ conformsToProtocol:OCMOCK_ANY];
+ return delegate;
+}
+
+// Verify that the window intercepts a particular key event and
+// forwards it to [delegate executeCommand:]. Assume that other
+// CommandForKeyboardShortcut() will work the same for the rest.
+TEST_F(ChromeEventProcessingWindowTest,
+ PerformKeyEquivalentForwardToExecuteCommand) {
+ NSEvent* event = KeyEvent(NSCommandKeyMask, kVK_ANSI_1);
+
+ id delegate = CreateBrowserWindowControllerMock();
+ [[delegate expect] executeCommand:IDC_SELECT_TAB_0];
+
+ [window_ setDelegate:delegate];
+ [window_ performKeyEquivalent:event];
+
+ // Don't wish to mock all the way down...
+ [window_ setDelegate:nil];
+ [delegate verify];
+}
+
+// Verify that an unhandled shortcut does not get forwarded via
+// -executeCommand:.
+// TODO(shess) Think of a way to test that it is sent to the
+// superclass.
+TEST_F(ChromeEventProcessingWindowTest, PerformKeyEquivalentNoForward) {
+ NSEvent* event = KeyEvent(0, 0);
+
+ id delegate = CreateBrowserWindowControllerMock();
+
+ [window_ setDelegate:delegate];
+ [window_ performKeyEquivalent:event];
+
+ // Don't wish to mock all the way down...
+ [window_ setDelegate:nil];
+ [delegate verify];
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/clear_browsing_data_controller.h b/chrome/browser/ui/cocoa/clear_browsing_data_controller.h
new file mode 100644
index 0000000..776841d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/clear_browsing_data_controller.h
@@ -0,0 +1,87 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_CLEAR_BROWSING_DATA_CONTROLLER_
+#define CHROME_BROWSER_UI_COCOA_CLEAR_BROWSING_DATA_CONTROLLER_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_ptr.h"
+
+class BrowsingDataRemover;
+class ClearBrowsingObserver;
+class Profile;
+@class ThrobberView;
+
+// Name of notification that is called when data is cleared.
+extern NSString* const kClearBrowsingDataControllerDidDelete;
+// A key in the above notification's userInfo. Contains a NSNumber with the
+// logically-ored constants defined in BrowsingDataRemover for the removal.
+extern NSString* const kClearBrowsingDataControllerRemoveMask;
+
+// A window controller for managing the "Clear Browsing Data" feature. Modally
+// presents a dialog offering the user a set of choices of what browsing data
+// to delete and does so if the user chooses.
+
+@interface ClearBrowsingDataController : NSWindowController {
+ @private
+ Profile* profile_; // Weak, owned by browser.
+ // If non-null means there is a removal in progress. Member used mainly for
+ // automated tests. The remove deletes itself when it's done, so this is a
+ // weak reference.
+ BrowsingDataRemover* remover_;
+ scoped_ptr<ClearBrowsingObserver> observer_;
+ BOOL isClearing_; // YES while clearing data is ongoing.
+
+ // Values for checkboxes, kept in sync with bindings. These values get
+ // persisted into prefs if the user accepts the dialog.
+ BOOL clearBrowsingHistory_;
+ BOOL clearDownloadHistory_;
+ BOOL emptyCache_;
+ BOOL deleteCookies_;
+ BOOL clearSavedPasswords_;
+ BOOL clearFormData_;
+ NSInteger timePeriod_;
+}
+
+// Show the clear browsing data window. Do not use |-initWithProfile:|,
+// go through this instead so we don't end up with multiple instances.
+// This function does not block, so it can be used from DOMUI calls.
++ (void)showClearBrowsingDialogForProfile:(Profile*)profile;
++ (ClearBrowsingDataController*)controllerForProfile:(Profile*)profile;
+
+// Run the dialog with an application-modal event loop. If the user accepts,
+// performs the deletion of the selected browsing data. The values of the
+// checkboxes will be persisted into prefs for next time.
+- (void)runModalDialog;
+
+// IBActions for the dialog buttons
+- (IBAction)clearData:(id)sender;
+- (IBAction)cancel:(id)sender;
+- (IBAction)openFlashPlayerSettings:(id)sender;
+
+// Properties for bindings
+@property (nonatomic) BOOL clearBrowsingHistory;
+@property (nonatomic) BOOL clearDownloadHistory;
+@property (nonatomic) BOOL emptyCache;
+@property (nonatomic) BOOL deleteCookies;
+@property (nonatomic) BOOL clearSavedPasswords;
+@property (nonatomic) BOOL clearFormData;
+@property (nonatomic) NSInteger timePeriod;
+@property (nonatomic) BOOL isClearing;
+
+@end
+
+
+@interface ClearBrowsingDataController (ExposedForUnitTests)
+// Create the controller with the given profile (which must not be NULL).
+- (id)initWithProfile:(Profile*)profile;
+@property (readonly) int removeMask;
+- (void)persistToPrefs;
+- (void)closeDialog;
+- (void)dataRemoverDidFinish;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_CLEAR_BROWSING_DATA_CONTROLLER_
diff --git a/chrome/browser/ui/cocoa/clear_browsing_data_controller.mm b/chrome/browser/ui/cocoa/clear_browsing_data_controller.mm
new file mode 100644
index 0000000..c0c927e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/clear_browsing_data_controller.mm
@@ -0,0 +1,267 @@
+// 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 "chrome/browser/ui/cocoa/clear_browsing_data_controller.h"
+
+#include "app/l10n_util.h"
+#include "base/lazy_instance.h"
+#include "base/mac_util.h"
+#include "base/scoped_nsobject.h"
+#include "chrome/browser/browsing_data_remover.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/common/pref_names.h"
+#include "grit/locale_settings.h"
+#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
+
+NSString* const kClearBrowsingDataControllerDidDelete =
+ @"kClearBrowsingDataControllerDidDelete";
+NSString* const kClearBrowsingDataControllerRemoveMask =
+ @"kClearBrowsingDataControllerRemoveMask";
+
+@interface ClearBrowsingDataController(Private)
+- (void)initFromPrefs;
+- (void)persistToPrefs;
+- (void)dataRemoverDidFinish;
+@end
+
+class ClearBrowsingObserver : public BrowsingDataRemover::Observer {
+ public:
+ ClearBrowsingObserver(ClearBrowsingDataController* controller)
+ : controller_(controller) { }
+ void OnBrowsingDataRemoverDone() { [controller_ dataRemoverDidFinish]; }
+ private:
+ ClearBrowsingDataController* controller_;
+};
+
+namespace {
+
+typedef std::map<Profile*, ClearBrowsingDataController*> ProfileControllerMap;
+
+static base::LazyInstance<ProfileControllerMap> g_profile_controller_map(
+ base::LINKER_INITIALIZED);
+
+} // namespace
+
+@implementation ClearBrowsingDataController
+
+@synthesize clearBrowsingHistory = clearBrowsingHistory_;
+@synthesize clearDownloadHistory = clearDownloadHistory_;
+@synthesize emptyCache = emptyCache_;
+@synthesize deleteCookies = deleteCookies_;
+@synthesize clearSavedPasswords = clearSavedPasswords_;
+@synthesize clearFormData = clearFormData_;
+@synthesize timePeriod = timePeriod_;
+@synthesize isClearing = isClearing_;
+
++ (void)showClearBrowsingDialogForProfile:(Profile*)profile {
+ ClearBrowsingDataController* controller =
+ [ClearBrowsingDataController controllerForProfile:profile];
+ if (![controller isWindowLoaded]) {
+ // This function needs to return instead of blocking, to match the windows
+ // api call. It caused problems when launching the dialog from the
+ // DomUI history page. See bug and code review for more details.
+ // http://crbug.com/37976
+ [controller performSelector:@selector(runModalDialog)
+ withObject:nil
+ afterDelay:0];
+ }
+}
+
++ (ClearBrowsingDataController *)controllerForProfile:(Profile*)profile {
+ // Get the original profile in case we get here from an incognito window
+ // |GetOriginalProfile()| will return the same profile if it is the original
+ // profile.
+ profile = profile->GetOriginalProfile();
+
+ ProfileControllerMap* map = g_profile_controller_map.Pointer();
+ DCHECK(map != NULL);
+ ProfileControllerMap::iterator it = map->find(profile);
+ if (it == map->end()) {
+ // Since we don't currently support multiple profiles, this class
+ // has not been tested against this case.
+ if (map->size() != 0) {
+ return nil;
+ }
+
+ ClearBrowsingDataController* controller =
+ [[self alloc] initWithProfile:profile];
+ it = map->insert(std::make_pair(profile, controller)).first;
+ }
+ return it->second;
+}
+
+- (id)initWithProfile:(Profile*)profile {
+ DCHECK(profile);
+ // Use initWithWindowNibPath:: instead of initWithWindowNibName: so we
+ // can override it in a unit test.
+ NSString *nibpath = [mac_util::MainAppBundle()
+ pathForResource:@"ClearBrowsingData"
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
+ profile_ = profile;
+ observer_.reset(new ClearBrowsingObserver(self));
+ [self initFromPrefs];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ if (remover_) {
+ // We were destroyed while clearing history was in progress. This can only
+ // occur during automated tests (normally the user can't close the dialog
+ // while clearing is in progress as the dialog is modal and not closeable).
+ remover_->RemoveObserver(observer_.get());
+ }
+
+ [super dealloc];
+}
+
+// Run application modal.
+- (void)runModalDialog {
+ // Check again to make sure there is only one window. Since we use
+ // |performSelector:afterDelay:| it is possible for this to somehow be
+ // triggered twice.
+ DCHECK([NSThread isMainThread]);
+ if (![self isWindowLoaded]) {
+ // The Window size in the nib is a min size, loop over the views collecting
+ // the max they grew by, that is how much the window needs to be widened by.
+ CGFloat maxWidthGrowth = 0.0;
+ NSWindow* window = [self window];
+ NSView* contentView = [window contentView];
+ Class widthBasedTweakerClass = [GTMWidthBasedTweaker class];
+ for (id subView in [contentView subviews]) {
+ if ([subView isKindOfClass:widthBasedTweakerClass]) {
+ GTMWidthBasedTweaker* tweaker = subView;
+ CGFloat delta = [tweaker changedWidth];
+ maxWidthGrowth = std::max(maxWidthGrowth, delta);
+ }
+ }
+ if (maxWidthGrowth > 0.0) {
+ NSRect rect = [contentView convertRect:[window frame] fromView:nil];
+ rect.size.width += maxWidthGrowth;
+ rect = [contentView convertRect:rect toView:nil];
+ [window setFrame:rect display:NO];
+ // For some reason the content view is resizing, but some times not
+ // adjusting its origin, so correct it manually.
+ [contentView setFrameOrigin:NSZeroPoint];
+ }
+ // Now start the modal loop.
+ [NSApp runModalForWindow:window];
+ }
+}
+
+- (int)removeMask {
+ int removeMask = 0L;
+ if (clearBrowsingHistory_)
+ removeMask |= BrowsingDataRemover::REMOVE_HISTORY;
+ if (clearDownloadHistory_)
+ removeMask |= BrowsingDataRemover::REMOVE_DOWNLOADS;
+ if (emptyCache_)
+ removeMask |= BrowsingDataRemover::REMOVE_CACHE;
+ if (deleteCookies_)
+ removeMask |= BrowsingDataRemover::REMOVE_COOKIES;
+ if (clearSavedPasswords_)
+ removeMask |= BrowsingDataRemover::REMOVE_PASSWORDS;
+ if (clearFormData_)
+ removeMask |= BrowsingDataRemover::REMOVE_FORM_DATA;
+ return removeMask;
+}
+
+// Called when the user clicks the "clear" button. Do the work and persist
+// the prefs for next time. We don't stop the modal session until we get
+// the callback from the BrowsingDataRemover so the window stays on the screen.
+// While we're working, dim the buttons so the user can't click them.
+- (IBAction)clearData:(id)sender {
+ // Set that we're working so that the buttons disable.
+ [self setIsClearing:YES];
+
+ [self persistToPrefs];
+
+ // BrowsingDataRemover deletes itself when done.
+ remover_ = new BrowsingDataRemover(profile_,
+ static_cast<BrowsingDataRemover::TimePeriod>(timePeriod_),
+ base::Time());
+ remover_->AddObserver(observer_.get());
+ remover_->Remove([self removeMask]);
+}
+
+// Called when the user clicks the cancel button. All we need to do is stop
+// the modal session.
+- (IBAction)cancel:(id)sender {
+ [self closeDialog];
+}
+
+// Called when the user clicks the "Flash Player storage settings" button.
+- (IBAction)openFlashPlayerSettings:(id)sender {
+ // The "Clear Data" dialog is app-modal on OS X. Hence, close it before
+ // opening a tab with flash settings.
+ [self closeDialog];
+
+ Browser* browser = Browser::Create(profile_);
+ browser->OpenURL(GURL(l10n_util::GetStringUTF8(IDS_FLASH_STORAGE_URL)),
+ GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
+ browser->window()->Show();
+}
+
+- (void)closeDialog {
+ ProfileControllerMap* map = g_profile_controller_map.Pointer();
+ ProfileControllerMap::iterator it = map->find(profile_);
+ if (it != map->end()) {
+ map->erase(it);
+ }
+ [self autorelease];
+ [[self window] orderOut:self];
+ [NSApp stopModal];
+}
+
+// Initialize the bools from prefs using the setters to be KVO-compliant.
+- (void)initFromPrefs {
+ PrefService* prefs = profile_->GetPrefs();
+ [self setClearBrowsingHistory:
+ prefs->GetBoolean(prefs::kDeleteBrowsingHistory)];
+ [self setClearDownloadHistory:
+ prefs->GetBoolean(prefs::kDeleteDownloadHistory)];
+ [self setEmptyCache:prefs->GetBoolean(prefs::kDeleteCache)];
+ [self setDeleteCookies:prefs->GetBoolean(prefs::kDeleteCookies)];
+ [self setClearSavedPasswords:prefs->GetBoolean(prefs::kDeletePasswords)];
+ [self setClearFormData:prefs->GetBoolean(prefs::kDeleteFormData)];
+ [self setTimePeriod:prefs->GetInteger(prefs::kDeleteTimePeriod)];
+}
+
+// Save the checkbox values to the preferences.
+- (void)persistToPrefs {
+ PrefService* prefs = profile_->GetPrefs();
+ prefs->SetBoolean(prefs::kDeleteBrowsingHistory,
+ [self clearBrowsingHistory]);
+ prefs->SetBoolean(prefs::kDeleteDownloadHistory,
+ [self clearDownloadHistory]);
+ prefs->SetBoolean(prefs::kDeleteCache, [self emptyCache]);
+ prefs->SetBoolean(prefs::kDeleteCookies, [self deleteCookies]);
+ prefs->SetBoolean(prefs::kDeletePasswords, [self clearSavedPasswords]);
+ prefs->SetBoolean(prefs::kDeleteFormData, [self clearFormData]);
+ prefs->SetInteger(prefs::kDeleteTimePeriod, [self timePeriod]);
+}
+
+// Called when the data remover object is done with its work. Close the window.
+// The remover will delete itself. End the modal session at this point.
+- (void)dataRemoverDidFinish {
+ NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+ int removeMask = [self removeMask];
+ NSDictionary* userInfo =
+ [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:removeMask]
+ forKey:kClearBrowsingDataControllerRemoveMask];
+ [center postNotificationName:kClearBrowsingDataControllerDidDelete
+ object:self
+ userInfo:userInfo];
+
+ [self closeDialog];
+ [[self window] orderOut:self];
+ [self setIsClearing:NO];
+ remover_ = NULL;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/clear_browsing_data_controller_unittest.mm b/chrome/browser/ui/cocoa/clear_browsing_data_controller_unittest.mm
new file mode 100644
index 0000000..d5f238a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/clear_browsing_data_controller_unittest.mm
@@ -0,0 +1,149 @@
+// 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 "base/scoped_nsobject.h"
+#include "chrome/browser/browsing_data_remover.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/clear_browsing_data_controller.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/common/pref_names.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+
+namespace {
+
+class ClearBrowsingDataControllerTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ // Set up some interesting prefs:
+ PrefService* prefs = helper_.profile()->GetPrefs();
+ prefs->SetBoolean(prefs::kDeleteBrowsingHistory, true);
+ prefs->SetBoolean(prefs::kDeleteDownloadHistory, false);
+ prefs->SetBoolean(prefs::kDeleteCache, true);
+ prefs->SetBoolean(prefs::kDeleteCookies, false);
+ prefs->SetBoolean(prefs::kDeletePasswords, true);
+ prefs->SetBoolean(prefs::kDeleteFormData, false);
+ prefs->SetInteger(prefs::kDeleteTimePeriod,
+ BrowsingDataRemover::FOUR_WEEKS);
+ controller_ =
+ [ClearBrowsingDataController controllerForProfile:helper_.profile()];
+ }
+
+ virtual void TearDown() {
+ [controller_ closeDialog];
+ CocoaTest::TearDown();
+ }
+
+ BrowserTestHelper helper_;
+ ClearBrowsingDataController* controller_;
+};
+
+TEST_F(ClearBrowsingDataControllerTest, InitialState) {
+ // Check properties match the prefs set above:
+ EXPECT_TRUE([controller_ clearBrowsingHistory]);
+ EXPECT_FALSE([controller_ clearDownloadHistory]);
+ EXPECT_TRUE([controller_ emptyCache]);
+ EXPECT_FALSE([controller_ deleteCookies]);
+ EXPECT_TRUE([controller_ clearSavedPasswords]);
+ EXPECT_FALSE([controller_ clearFormData]);
+ EXPECT_EQ(BrowsingDataRemover::FOUR_WEEKS,
+ [controller_ timePeriod]);
+}
+
+TEST_F(ClearBrowsingDataControllerTest, InitialRemoveMask) {
+ // Check that the remove-mask matches the initial properties:
+ EXPECT_EQ(BrowsingDataRemover::REMOVE_HISTORY |
+ BrowsingDataRemover::REMOVE_CACHE |
+ BrowsingDataRemover::REMOVE_PASSWORDS,
+ [controller_ removeMask]);
+}
+
+TEST_F(ClearBrowsingDataControllerTest, ModifiedRemoveMask) {
+ // Invert all properties and check that the remove-mask is still correct:
+ [controller_ setClearBrowsingHistory:false];
+ [controller_ setClearDownloadHistory:true];
+ [controller_ setEmptyCache:false];
+ [controller_ setDeleteCookies:true];
+ [controller_ setClearSavedPasswords:false];
+ [controller_ setClearFormData:true];
+
+ EXPECT_EQ(BrowsingDataRemover::REMOVE_DOWNLOADS |
+ BrowsingDataRemover::REMOVE_COOKIES |
+ BrowsingDataRemover::REMOVE_FORM_DATA,
+ [controller_ removeMask]);
+}
+
+TEST_F(ClearBrowsingDataControllerTest, EmptyRemoveMask) {
+ // Clear all properties and check that the remove-mask is zero:
+ [controller_ setClearBrowsingHistory:false];
+ [controller_ setClearDownloadHistory:false];
+ [controller_ setEmptyCache:false];
+ [controller_ setDeleteCookies:false];
+ [controller_ setClearSavedPasswords:false];
+ [controller_ setClearFormData:false];
+
+ EXPECT_EQ(0,
+ [controller_ removeMask]);
+}
+
+TEST_F(ClearBrowsingDataControllerTest, PersistToPrefs) {
+ // Change some settings and store to prefs:
+ [controller_ setClearBrowsingHistory:false];
+ [controller_ setClearDownloadHistory:true];
+ [controller_ persistToPrefs];
+
+ // Test that the modified settings were stored to prefs:
+ PrefService* prefs = helper_.profile()->GetPrefs();
+ EXPECT_FALSE(prefs->GetBoolean(prefs::kDeleteBrowsingHistory));
+ EXPECT_TRUE(prefs->GetBoolean(prefs::kDeleteDownloadHistory));
+
+ // Make sure the rest of the prefs didn't change:
+ EXPECT_TRUE(prefs->GetBoolean(prefs::kDeleteCache));
+ EXPECT_FALSE(prefs->GetBoolean(prefs::kDeleteCookies));
+ EXPECT_TRUE(prefs->GetBoolean(prefs::kDeletePasswords));
+ EXPECT_FALSE(prefs->GetBoolean(prefs::kDeleteFormData));
+ EXPECT_EQ(BrowsingDataRemover::FOUR_WEEKS,
+ prefs->GetInteger(prefs::kDeleteTimePeriod));
+}
+
+TEST_F(ClearBrowsingDataControllerTest, SameControllerForProfile) {
+ ClearBrowsingDataController* controller =
+ [ClearBrowsingDataController controllerForProfile:helper_.profile()];
+ EXPECT_EQ(controller_, controller);
+}
+
+TEST_F(ClearBrowsingDataControllerTest, DataRemoverDidFinish) {
+ id observer = [OCMockObject observerMock];
+ // Don't use |controller_| as the object because it will free itself twice
+ // because both |-dataRemoverDidFinish| and TearDown() call |-closeDialog|.
+ ClearBrowsingDataController* controller =
+ [[ClearBrowsingDataController alloc] initWithProfile:helper_.profile()];
+
+ NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+ [center addMockObserver:observer
+ name:kClearBrowsingDataControllerDidDelete
+ object:controller];
+
+ int mask = [controller removeMask];
+ NSDictionary* expectedInfo =
+ [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:mask]
+ forKey:kClearBrowsingDataControllerRemoveMask];
+ [[observer expect]
+ notificationWithName:kClearBrowsingDataControllerDidDelete
+ object:controller
+ userInfo:expectedInfo];
+
+ // This calls |-closeDialog| and cleans the controller up.
+ [controller dataRemoverDidFinish];
+
+ [observer verify];
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/clickhold_button_cell.h b/chrome/browser/ui/cocoa/clickhold_button_cell.h
new file mode 100644
index 0000000..89218cf
--- /dev/null
+++ b/chrome/browser/ui/cocoa/clickhold_button_cell.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_CLICKHOLD_BUTTON_CELL_H_
+#define CHROME_BROWSER_UI_COCOA_CLICKHOLD_BUTTON_CELL_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/gradient_button_cell.h"
+
+// A button cell that implements "click hold" behavior after a specified delay
+// or after dragging. If click-hold is never enabled (e.g., if
+// |-setEnableClickHold:| is never called), this behaves like a normal button.
+@interface ClickHoldButtonCell : GradientButtonCell {
+ @private
+ BOOL enableClickHold_;
+ NSTimeInterval clickHoldTimeout_;
+ id clickHoldTarget_; // Weak.
+ SEL clickHoldAction_;
+ BOOL trackOnlyInRect_;
+ BOOL activateOnDrag_;
+}
+
+// Enable click-hold? Default: NO.
+@property(assign, nonatomic) BOOL enableClickHold;
+
+// Timeout is in seconds (at least 0.0, at most 5; 0.0 means that the button
+// will always have its click-hold action activated immediately on press).
+// Default: 0.25 (a guess at a Cocoa-ish value).
+@property(assign, nonatomic) NSTimeInterval clickHoldTimeout;
+
+// Track only in the frame rectangle? Default: NO.
+@property(assign, nonatomic) BOOL trackOnlyInRect;
+
+// Activate (click-hold) immediately on a sufficiently-large drag (if not,
+// always wait for timeout)? Default: YES.
+@property(assign, nonatomic) BOOL activateOnDrag;
+
+// Defines what to do when click-held (as per usual action/target).
+@property(assign, nonatomic) id clickHoldTarget;
+@property(assign, nonatomic) SEL clickHoldAction;
+
+@end // @interface ClickHoldButtonCell
+
+#endif // CHROME_BROWSER_UI_COCOA_CLICKHOLD_BUTTON_CELL_H_
diff --git a/chrome/browser/ui/cocoa/clickhold_button_cell.mm b/chrome/browser/ui/cocoa/clickhold_button_cell.mm
new file mode 100644
index 0000000..9b4424d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/clickhold_button_cell.mm
@@ -0,0 +1,190 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/clickhold_button_cell.h"
+
+#include "base/logging.h"
+
+// Minimum and maximum click-hold timeout.
+static const NSTimeInterval kMinTimeout = 0.0;
+static const NSTimeInterval kMaxTimeout = 5.0;
+
+// Drag distance threshold to activate click-hold; should be >= 0.
+static const CGFloat kDragDistThreshold = 2.5;
+
+// See |-resetToDefaults| (and header file) for other default values.
+
+@interface ClickHoldButtonCell (Private)
+- (void)resetToDefaults;
+@end // @interface ClickHoldButtonCell (Private)
+
+@implementation ClickHoldButtonCell
+
+// Overrides:
+
++ (BOOL)prefersTrackingUntilMouseUp {
+ return NO;
+}
+
+- (id)init {
+ if ((self = [super init]))
+ [self resetToDefaults];
+ return self;
+}
+
+- (id)initWithCoder:(NSCoder*)decoder {
+ if ((self = [super initWithCoder:decoder]))
+ [self resetToDefaults];
+ return self;
+}
+
+- (id)initImageCell:(NSImage*)image {
+ if ((self = [super initImageCell:image]))
+ [self resetToDefaults];
+ return self;
+}
+
+- (id)initTextCell:(NSString*)string {
+ if ((self = [super initTextCell:string]))
+ [self resetToDefaults];
+ return self;
+}
+
+- (BOOL)startTrackingAt:(NSPoint)startPoint
+ inView:(NSView*)controlView {
+ return enableClickHold_ ? YES :
+ [super startTrackingAt:startPoint
+ inView:controlView];
+}
+
+- (BOOL)continueTracking:(NSPoint)lastPoint
+ at:(NSPoint)currentPoint
+ inView:(NSView*)controlView {
+ return enableClickHold_ ? YES :
+ [super continueTracking:lastPoint
+ at:currentPoint
+ inView:controlView];
+}
+
+- (BOOL)trackMouse:(NSEvent*)originalEvent
+ inRect:(NSRect)cellFrame
+ ofView:(NSView*)controlView
+ untilMouseUp:(BOOL)untilMouseUp {
+ if (!enableClickHold_) {
+ return [super trackMouse:originalEvent
+ inRect:cellFrame
+ ofView:controlView
+ untilMouseUp:untilMouseUp];
+ }
+
+ // If doing click-hold, track the mouse ourselves.
+ NSPoint currPoint = [controlView convertPoint:[originalEvent locationInWindow]
+ fromView:nil];
+ NSPoint lastPoint = currPoint;
+ NSPoint firstPoint = currPoint;
+ NSTimeInterval timeout =
+ MAX(MIN(clickHoldTimeout_, kMaxTimeout), kMinTimeout);
+ NSDate* clickHoldBailTime = [NSDate dateWithTimeIntervalSinceNow:timeout];
+
+ if (![self startTrackingAt:currPoint inView:controlView])
+ return NO;
+
+ enum {
+ kContinueTrack, kStopClickHold, kStopMouseUp, kStopLeftRect, kStopNoContinue
+ } state = kContinueTrack;
+ do {
+ NSEvent* event = [NSApp nextEventMatchingMask:(NSLeftMouseDraggedMask |
+ NSLeftMouseUpMask)
+ untilDate:clickHoldBailTime
+ inMode:NSEventTrackingRunLoopMode
+ dequeue:YES];
+ currPoint = [controlView convertPoint:[event locationInWindow]
+ fromView:nil];
+
+ // Time-out.
+ if (!event) {
+ state = kStopClickHold;
+
+ // Drag? (If distance meets threshold.)
+ } else if (activateOnDrag_ && ([event type] == NSLeftMouseDragged)) {
+ CGFloat dx = currPoint.x - firstPoint.x;
+ CGFloat dy = currPoint.y - firstPoint.y;
+ if ((dx*dx + dy*dy) >= (kDragDistThreshold*kDragDistThreshold))
+ state = kStopClickHold;
+
+ // Mouse up.
+ } else if ([event type] == NSLeftMouseUp) {
+ state = kStopMouseUp;
+
+ // Stop tracking if mouse left frame rectangle (if requested to do so).
+ } else if (trackOnlyInRect_ && ![controlView mouse:currPoint
+ inRect:cellFrame]) {
+ state = kStopLeftRect;
+
+ // Stop tracking if instructed to.
+ } else if (![self continueTracking:lastPoint
+ at:currPoint
+ inView:controlView]) {
+ state = kStopNoContinue;
+ }
+
+ lastPoint = currPoint;
+ } while (state == kContinueTrack);
+
+ [self stopTracking:lastPoint
+ at:lastPoint
+ inView:controlView
+ mouseIsUp:NO];
+
+ switch (state) {
+ case kStopClickHold:
+ if (clickHoldAction_) {
+ [static_cast<NSControl*>(controlView) sendAction:clickHoldAction_
+ to:clickHoldTarget_];
+ }
+ return YES;
+
+ case kStopMouseUp:
+ if ([self action]) {
+ [static_cast<NSControl*>(controlView) sendAction:[self action]
+ to:[self target]];
+ }
+ return YES;
+
+ case kStopLeftRect:
+ case kStopNoContinue:
+ return NO;
+
+ default:
+ NOTREACHED() << "Unknown terminating state!";
+ }
+
+ return NO;
+}
+
+// Accessors and mutators:
+
+@synthesize enableClickHold = enableClickHold_;
+@synthesize clickHoldTimeout = clickHoldTimeout_;
+@synthesize trackOnlyInRect = trackOnlyInRect_;
+@synthesize activateOnDrag = activateOnDrag_;
+@synthesize clickHoldTarget = clickHoldTarget_;
+@synthesize clickHoldAction = clickHoldAction_;
+
+@end // @implementation ClickHoldButtonCell
+
+@implementation ClickHoldButtonCell (Private)
+
+// Resets various members to defaults indicated in the header file. (Those
+// without indicated defaults are *not* touched.) Please keep the values below
+// in sync with the header file, and please be aware of side-effects on code
+// which relies on the "published" defaults.
+- (void)resetToDefaults {
+ [self setEnableClickHold:NO];
+ [self setClickHoldTimeout:0.25];
+ [self setTrackOnlyInRect:NO];
+ [self setActivateOnDrag:YES];
+}
+
+@end // @implementation ClickHoldButtonCell (Private)
diff --git a/chrome/browser/ui/cocoa/clickhold_button_cell_unittest.mm b/chrome/browser/ui/cocoa/clickhold_button_cell_unittest.mm
new file mode 100644
index 0000000..7ccc773
--- /dev/null
+++ b/chrome/browser/ui/cocoa/clickhold_button_cell_unittest.mm
@@ -0,0 +1,51 @@
+// Copyright (c) 2009 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 "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/clickhold_button_cell.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class ClickHoldButtonCellTest : public CocoaTest {
+ public:
+ ClickHoldButtonCellTest() {
+ NSRect frame = NSMakeRect(0, 0, 50, 30);
+ scoped_nsobject<NSButton> view([[NSButton alloc] initWithFrame:frame]);
+ view_ = view.get();
+ scoped_nsobject<ClickHoldButtonCell> cell(
+ [[ClickHoldButtonCell alloc] initTextCell:@"Testing"]);
+ [view_ setCell:cell.get()];
+ [[test_window() contentView] addSubview:view_];
+ }
+
+ NSButton* view_;
+};
+
+TEST_VIEW(ClickHoldButtonCellTest, view_)
+
+// Test default values; make sure they are what they should be.
+TEST_F(ClickHoldButtonCellTest, Defaults) {
+ ClickHoldButtonCell* cell = static_cast<ClickHoldButtonCell*>([view_ cell]);
+ ASSERT_TRUE([cell isKindOfClass:[ClickHoldButtonCell class]]);
+
+ EXPECT_FALSE([cell enableClickHold]);
+
+ NSTimeInterval clickHoldTimeout = [cell clickHoldTimeout];
+ EXPECT_GE(clickHoldTimeout, 0.15); // Check for a "Cocoa-ish" value.
+ EXPECT_LE(clickHoldTimeout, 0.35);
+
+ EXPECT_FALSE([cell trackOnlyInRect]);
+ EXPECT_TRUE([cell activateOnDrag]);
+}
+
+// TODO(viettrungluu): (1) Enable click-hold and figure out how to test the
+// tracking loop (i.e., |-trackMouse:...|), which is the nontrivial part.
+// (2) Test various initialization code paths (in particular, loading from nib).
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/cocoa_test_helper.h b/chrome/browser/ui/cocoa/cocoa_test_helper.h
new file mode 100644
index 0000000..0be5903
--- /dev/null
+++ b/chrome/browser/ui/cocoa/cocoa_test_helper.h
@@ -0,0 +1,153 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_COCOA_TEST_HELPER_H_
+#define CHROME_BROWSER_UI_COCOA_COCOA_TEST_HELPER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/debug_util.h"
+#include "base/mac_util.h"
+#include "base/path_service.h"
+#import "base/mac/scoped_nsautorelease_pool.h"
+#import "base/scoped_nsobject.h"
+#import "chrome/common/chrome_application_mac.h"
+#include "chrome/common/chrome_constants.h"
+#include "testing/platform_test.h"
+
+// Background windows normally will not display things such as focus
+// rings. This class allows -isKeyWindow to be manipulated to test
+// such things.
+@interface CocoaTestHelperWindow : NSWindow {
+ @private
+ BOOL pretendIsKeyWindow_;
+}
+
+// Init a borderless non-deferred window with a backing store.
+- (id)initWithContentRect:(NSRect)contentRect;
+
+// Init with a default frame.
+- (id)init;
+
+// Sets the responder passed in as first responder, and sets the window
+// so that it will return "YES" if asked if it key window. It does not actually
+// make the window key.
+- (void)makePretendKeyWindowAndSetFirstResponder:(NSResponder*)responder;
+
+// Clears the first responder duty for the window and returns the window
+// to being non-key.
+- (void)clearPretendKeyWindowAndFirstResponder;
+
+// Set value to return for -isKeyWindow.
+- (void)setPretendIsKeyWindow:(BOOL)isKeyWindow;
+
+- (BOOL)isKeyWindow;
+
+@end
+
+// A test class that all tests that depend on AppKit should inherit from.
+// Sets up NSApplication and paths correctly, and makes sure that any windows
+// created in the test are closed down properly by the test. If you need to
+// inherit from a different test class, but need to set up the AppKit runtime
+// environment, you can call BootstrapCocoa directly from your test class. You
+// will have to deal with windows on your own though.
+class CocoaTest : public PlatformTest {
+ public:
+ // Sets up AppKit and paths correctly for unit tests. If you can't inherit
+ // from CocoaTest but are going to be using any AppKit features directly,
+ // or indirectly, you should be calling this from the c'tor or SetUp methods
+ // of your test class.
+ static void BootstrapCocoa();
+
+ CocoaTest();
+ virtual ~CocoaTest();
+
+ // Must be called by subclasses that override TearDown. We verify that it
+ // is called in our destructor. Takes care of making sure that all windows
+ // are closed off correctly. If your tests open windows, they must be sure
+ // to close them before CocoaTest::TearDown is called. A standard way of doing
+ // this would be to create them in SetUp (after calling CocoaTest::Setup) and
+ // then close them in TearDown before calling CocoaTest::TearDown.
+ virtual void TearDown();
+
+ // Retuns a test window that can be used by views and other UI objects
+ // as part of their tests. Is created lazily, and will be closed correctly
+ // in CocoaTest::TearDown. Note that it is a CocoaTestHelperWindow which
+ // has special handling for being Key.
+ CocoaTestHelperWindow* test_window();
+
+ private:
+ // Return a set of currently open windows. Avoiding NSArray so
+ // contents aren't retained, the pointer values can only be used for
+ // comparison purposes. Using std::set to make progress-checking
+ // convenient.
+ static std::set<NSWindow*> ApplicationWindows();
+
+ // Return a set of windows which are in |ApplicationWindows()| but
+ // not |initial_windows_|.
+ std::set<NSWindow*> WindowsLeft();
+
+ bool called_tear_down_;
+ base::mac::ScopedNSAutoreleasePool pool_;
+
+ // Windows which existed at the beginning of the test.
+ std::set<NSWindow*> initial_windows_;
+
+ // Strong. Lazily created. This isn't wrapped in a scoped_nsobject because
+ // we want to call [close] to destroy it rather than calling [release]. We
+ // want to verify that [close] is actually removing our window and that it's
+ // not hanging around because releaseWhenClosed was set to "no" on the window.
+ // It isn't wrapped in a different wrapper class to close it because we
+ // need to close it at a very specific time; just before we enter our clean
+ // up loop in TearDown.
+ CocoaTestHelperWindow* test_window_;
+};
+
+// A macro defining a standard set of tests to run on a view. Since we can't
+// inherit tests, this macro saves us a lot of duplicate code. Handles simply
+// displaying the view to make sure it won't crash, as well as removing it
+// from a window. All tests that work with NSView subclasses and/or
+// NSViewController subclasses should use it.
+#define TEST_VIEW(test_fixture, test_view) \
+ TEST_F(test_fixture, AddRemove##test_fixture) { \
+ scoped_nsobject<NSView> view([test_view retain]); \
+ EXPECT_EQ([test_window() contentView], [view superview]); \
+ [view removeFromSuperview]; \
+ EXPECT_FALSE([view superview]); \
+ } \
+ TEST_F(test_fixture, Display##test_fixture) { \
+ [test_view display]; \
+ }
+
+// A macro which determines the proper float epsilon for a CGFloat.
+#if CGFLOAT_IS_DOUBLE
+#define CGFLOAT_EPSILON DBL_EPSILON
+#else
+#define CGFLOAT_EPSILON FLT_EPSILON
+#endif
+
+// A macro which which determines if two CGFloats are equal taking a
+// proper epsilon into consideration.
+#define CGFLOAT_EQ(expected, actual) \
+ (actual >= (expected - CGFLOAT_EPSILON) && \
+ actual <= (expected + CGFLOAT_EPSILON))
+
+// A test support macro which ascertains if two CGFloats are equal.
+#define EXPECT_CGFLOAT_EQ(expected, actual) \
+ EXPECT_TRUE(CGFLOAT_EQ(expected, actual)) << \
+ expected << " != " << actual
+
+// A test support macro which compares two NSRects for equality taking
+// the float epsilon into consideration.
+#define EXPECT_NSRECT_EQ(expected, actual) \
+ EXPECT_TRUE(CGFLOAT_EQ(expected.origin.x, actual.origin.x) && \
+ CGFLOAT_EQ(expected.origin.y, actual.origin.y) && \
+ CGFLOAT_EQ(expected.size.width, actual.size.width) && \
+ CGFLOAT_EQ(expected.size.height, actual.size.height)) << \
+ "Rects do not match: " << \
+ [NSStringFromRect(expected) UTF8String] << \
+ " != " << [NSStringFromRect(actual) UTF8String]
+
+#endif // CHROME_BROWSER_UI_COCOA_COCOA_TEST_HELPER_H_
diff --git a/chrome/browser/ui/cocoa/cocoa_test_helper.mm b/chrome/browser/ui/cocoa/cocoa_test_helper.mm
new file mode 100644
index 0000000..2cd2cc0
--- /dev/null
+++ b/chrome/browser/ui/cocoa/cocoa_test_helper.mm
@@ -0,0 +1,205 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+
+#include "base/debug/debugger.h"
+#include "base/logging.h"
+#include "base/test/test_timeouts.h"
+#import "chrome/browser/chrome_browser_application_mac.h"
+
+@implementation CocoaTestHelperWindow
+
+- (id)initWithContentRect:(NSRect)contentRect {
+ return [self initWithContentRect:contentRect
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO];
+}
+
+- (id)init {
+ return [self initWithContentRect:NSMakeRect(0, 0, 800, 600)];
+}
+
+- (void)dealloc {
+ // Just a good place to put breakpoints when having problems with
+ // unittests and CocoaTestHelperWindow.
+ [super dealloc];
+}
+
+- (void)makePretendKeyWindowAndSetFirstResponder:(NSResponder*)responder {
+ EXPECT_TRUE([self makeFirstResponder:responder]);
+ [self setPretendIsKeyWindow:YES];
+}
+
+- (void)clearPretendKeyWindowAndFirstResponder {
+ [self setPretendIsKeyWindow:NO];
+ EXPECT_TRUE([self makeFirstResponder:NSApp]);
+}
+
+- (void)setPretendIsKeyWindow:(BOOL)flag {
+ pretendIsKeyWindow_ = flag;
+}
+
+- (BOOL)isKeyWindow {
+ return pretendIsKeyWindow_;
+}
+
+@end
+
+CocoaTest::CocoaTest() : called_tear_down_(false), test_window_(nil) {
+ BootstrapCocoa();
+
+ // Set the duration of AppKit-evaluated animations (such as frame changes)
+ // to zero for testing purposes. That way they take effect immediately.
+ [[NSAnimationContext currentContext] setDuration:0.0];
+
+ // The above does not affect window-resize time, such as for an
+ // attached sheet dropping in. Set that duration for the current
+ // process (this is not persisted). Empirically, the value of 0.0
+ // is ignored.
+ NSDictionary* dict =
+ [NSDictionary dictionaryWithObject:@"0.01" forKey:@"NSWindowResizeTime"];
+ [[NSUserDefaults standardUserDefaults] registerDefaults:dict];
+
+ // Collect the list of windows that were open when the test started so
+ // that we don't wait for them to close in TearDown. Has to be done
+ // after BootstrapCocoa is called.
+ initial_windows_ = ApplicationWindows();
+}
+
+CocoaTest::~CocoaTest() {
+ // Must call CocoaTest's teardown from your overrides.
+ DCHECK(called_tear_down_);
+}
+
+void CocoaTest::BootstrapCocoa() {
+ // Look in the framework bundle for resources.
+ FilePath path;
+ PathService::Get(base::DIR_EXE, &path);
+ path = path.Append(chrome::kFrameworkName);
+ mac_util::SetOverrideAppBundlePath(path);
+
+ // Bootstrap Cocoa. It's very unhappy without this.
+ [CrApplication sharedApplication];
+}
+
+void CocoaTest::TearDown() {
+ called_tear_down_ = true;
+ // Call close on our test_window to clean it up if one was opened.
+ [test_window_ close];
+ test_window_ = nil;
+
+ // Recycle the pool to clean up any stuff that was put on the
+ // autorelease pool due to window or windowcontroller closures.
+ pool_.Recycle();
+
+ // Some controls (NSTextFields, NSComboboxes etc) use
+ // performSelector:withDelay: to clean up drag handlers and other
+ // things (Radar 5851458 "Closing a window with a NSTextView in it
+ // should get rid of it immediately"). The event loop must be spun
+ // to get everything cleaned up correctly. It normally only takes
+ // one to two spins through the event loop to see a change.
+
+ // NOTE(shess): Under valgrind, -nextEventMatchingMask:* in one test
+ // needed to run twice, once taking .2 seconds, the next time .6
+ // seconds. The loop exit condition attempts to be scalable.
+
+ // Get the set of windows which weren't present when the test
+ // started.
+ std::set<NSWindow*> windows_left(WindowsLeft());
+
+ while (windows_left.size() > 0) {
+ // Cover delayed actions by spinning the loop at least once after
+ // this timeout.
+ const NSTimeInterval kCloseTimeoutSeconds =
+ TestTimeouts::action_timeout_ms() / 1000.0;
+
+ // Cover chains of delayed actions by spinning the loop at least
+ // this many times.
+ const int kCloseSpins = 3;
+
+ // Track the set of remaining windows so that everything can be
+ // reset if progress is made.
+ std::set<NSWindow*> still_left = windows_left;
+
+ NSDate* start_date = [NSDate date];
+ bool one_more_time = true;
+ int spins = 0;
+ while (still_left.size() == windows_left.size() &&
+ (spins < kCloseSpins || one_more_time)) {
+ // Check the timeout before pumping events, so that we'll spin
+ // the loop once after the timeout.
+ one_more_time = ([start_date timeIntervalSinceNow] > -kCloseTimeoutSeconds);
+
+ // Autorelease anything thrown up by the event loop.
+ {
+ base::mac::ScopedNSAutoreleasePool pool;
+ ++spins;
+ NSEvent *next_event = [NSApp nextEventMatchingMask:NSAnyEventMask
+ untilDate:nil
+ inMode:NSDefaultRunLoopMode
+ dequeue:YES];
+ [NSApp sendEvent:next_event];
+ [NSApp updateWindows];
+ }
+
+ // Refresh the outstanding windows.
+ still_left = WindowsLeft();
+ }
+
+ // If no progress is being made, log a failure and continue.
+ if (still_left.size() == windows_left.size()) {
+ // NOTE(shess): Failing this expectation means that the test
+ // opened windows which have not been fully released. Either
+ // there is a leak, or perhaps one of |kCloseTimeoutSeconds| or
+ // |kCloseSpins| needs adjustment.
+ EXPECT_EQ(0U, windows_left.size());
+ for (std::set<NSWindow*>::iterator iter = windows_left.begin();
+ iter != windows_left.end(); ++iter) {
+ const char* desc = [[*iter description] UTF8String];
+ LOG(WARNING) << "Didn't close window " << desc;
+ }
+ break;
+ }
+
+ windows_left = still_left;
+ }
+ PlatformTest::TearDown();
+}
+
+std::set<NSWindow*> CocoaTest::ApplicationWindows() {
+ // This must NOT retain the windows it is returning.
+ std::set<NSWindow*> windows;
+
+ // Must create a pool here because [NSApp windows] has created an array
+ // with retains on all the windows in it.
+ base::mac::ScopedNSAutoreleasePool pool;
+ NSArray *appWindows = [NSApp windows];
+ for (NSWindow *window in appWindows) {
+ windows.insert(window);
+ }
+ return windows;
+}
+
+std::set<NSWindow*> CocoaTest::WindowsLeft() {
+ const std::set<NSWindow*> windows(ApplicationWindows());
+ std::set<NSWindow*> windows_left;
+ std::set_difference(windows.begin(), windows.end(),
+ initial_windows_.begin(), initial_windows_.end(),
+ std::inserter(windows_left, windows_left.begin()));
+ return windows_left;
+}
+
+CocoaTestHelperWindow* CocoaTest::test_window() {
+ if (!test_window_) {
+ test_window_ = [[CocoaTestHelperWindow alloc] init];
+ if (base::debug::BeingDebugged()) {
+ [test_window_ orderFront:nil];
+ } else {
+ [test_window_ orderBack:nil];
+ }
+ }
+ return test_window_;
+}
diff --git a/chrome/browser/ui/cocoa/collected_cookies_mac.h b/chrome/browser/ui/cocoa/collected_cookies_mac.h
new file mode 100644
index 0000000..0329819
--- /dev/null
+++ b/chrome/browser/ui/cocoa/collected_cookies_mac.h
@@ -0,0 +1,123 @@
+// 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>
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/cookies_tree_model.h"
+#include "chrome/browser/ui/cocoa/constrained_window_mac.h"
+#import "chrome/browser/ui/cocoa/cookie_tree_node.h"
+#include "chrome/common/notification_registrar.h"
+
+@class CollectedCookiesWindowController;
+@class VerticalGradientView;
+class TabContents;
+
+// The constrained window delegate reponsible for managing the collected
+// cookies dialog.
+class CollectedCookiesMac : public ConstrainedWindowMacDelegateCustomSheet,
+ public NotificationObserver {
+ public:
+ CollectedCookiesMac(NSWindow* parent, TabContents* tab_contents);
+
+ void OnSheetDidEnd(NSWindow* sheet);
+
+ // ConstrainedWindowMacDelegateCustomSheet implementation.
+ virtual void DeleteDelegate();
+
+ private:
+ virtual ~CollectedCookiesMac();
+
+ // NotificationObserver implementation.
+ void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ NotificationRegistrar registrar_;
+
+ ConstrainedWindow* window_;
+
+ TabContents* tab_contents_;
+
+ CollectedCookiesWindowController* sheet_controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(CollectedCookiesMac);
+};
+
+// Controller for the collected cookies dialog. This class stores an internal
+// copy of the CookiesTreeModel but with Cocoa-converted values (NSStrings and
+// NSImages instead of std::strings and SkBitmaps). Doing this allows us to use
+// bindings for the interface. Changes are pushed to this internal model via a
+// very thin bridge (see cookies_window_controller.h).
+@interface CollectedCookiesWindowController : NSWindowController
+ <NSOutlineViewDelegate,
+ NSWindowDelegate> {
+ @private
+ // Platform-independent model.
+ scoped_ptr<CookiesTreeModel> allowedTreeModel_;
+ scoped_ptr<CookiesTreeModel> blockedTreeModel_;
+
+ // Cached array of icons.
+ scoped_nsobject<NSMutableArray> icons_;
+
+ // Our Cocoa copy of the model.
+ scoped_nsobject<CocoaCookieTreeNode> cocoaAllowedTreeModel_;
+ scoped_nsobject<CocoaCookieTreeNode> cocoaBlockedTreeModel_;
+
+ BOOL allowedCookiesButtonsEnabled_;
+ BOOL blockedCookiesButtonsEnabled_;
+
+ IBOutlet NSTreeController* allowedTreeController_;
+ IBOutlet NSTreeController* blockedTreeController_;
+ IBOutlet NSOutlineView* allowedOutlineView_;
+ IBOutlet NSOutlineView* blockedOutlineView_;
+ IBOutlet VerticalGradientView* infoBar_;
+ IBOutlet NSImageView* infoBarIcon_;
+ IBOutlet NSTextField* infoBarText_;
+ IBOutlet NSSplitView* splitView_;
+ IBOutlet NSScrollView* lowerScrollView_;
+ IBOutlet NSTextField* blockedCookiesText_;
+
+ scoped_nsobject<NSViewAnimation> animation_;
+
+ TabContents* tabContents_; // weak
+
+ BOOL infoBarVisible_;
+}
+@property (readonly, nonatomic) NSTreeController* allowedTreeController;
+@property (readonly, nonatomic) NSTreeController* blockedTreeController;
+
+@property (assign, nonatomic) BOOL allowedCookiesButtonsEnabled;
+@property (assign, nonatomic) BOOL blockedCookiesButtonsEnabled;
+
+// Designated initializer. TabContents cannot be NULL.
+- (id)initWithTabContents:(TabContents*)tabContents;
+
+// Closes the sheet and ends the modal loop. This will also cleanup the memory.
+- (IBAction)closeSheet:(id)sender;
+
+- (IBAction)allowOrigin:(id)sender;
+- (IBAction)allowForSessionFromOrigin:(id)sender;
+- (IBAction)blockOrigin:(id)sender;
+
+// NSSplitView delegate methods:
+- (CGFloat) splitView:(NSSplitView *)sender
+ constrainMinCoordinate:(CGFloat)proposedMin
+ ofSubviewAt:(NSInteger)offset;
+- (BOOL)splitView:(NSSplitView *)sender canCollapseSubview:(NSView *)subview;
+
+// Returns the cocoaAllowedTreeModel_ and cocoaBlockedTreeModel_.
+- (CocoaCookieTreeNode*)cocoaAllowedTreeModel;
+- (CocoaCookieTreeNode*)cocoaBlockedTreeModel;
+- (void)setCocoaAllowedTreeModel:(CocoaCookieTreeNode*)model;
+- (void)setCocoaBlockedTreeModel:(CocoaCookieTreeNode*)model;
+
+// Returns the allowedTreeModel_ and blockedTreeModel_.
+- (CookiesTreeModel*)allowedTreeModel;
+- (CookiesTreeModel*)blockedTreeModel;
+
+- (void)loadTreeModelFromTabContents;
+@end
diff --git a/chrome/browser/ui/cocoa/collected_cookies_mac.mm b/chrome/browser/ui/cocoa/collected_cookies_mac.mm
new file mode 100644
index 0000000..23ff4a5
--- /dev/null
+++ b/chrome/browser/ui/cocoa/collected_cookies_mac.mm
@@ -0,0 +1,500 @@
+// 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 "chrome/browser/ui/cocoa/collected_cookies_mac.h"
+
+#include <vector>
+
+#include "app/l10n_util_mac.h"
+#include "app/resource_bundle.h"
+#import "base/mac_util.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#import "chrome/browser/ui/cocoa/vertical_gradient_view.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "skia/ext/skia_utils_mac.h"
+#include "third_party/apple/ImageAndTextCell.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
+#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
+
+namespace {
+// Colors for the infobar.
+const double kBannerGradientColorTop[3] =
+ {255.0 / 255.0, 242.0 / 255.0, 183.0 / 255.0};
+const double kBannerGradientColorBottom[3] =
+ {250.0 / 255.0, 230.0 / 255.0, 145.0 / 255.0};
+const double kBannerStrokeColor = 135.0 / 255.0;
+
+// Minimal height for the collected cookies dialog.
+const CGFloat kMinCollectedCookiesViewHeight = 116;
+} // namespace
+
+#pragma mark Bridge between the constrained window delegate and the sheet
+
+// The delegate used to forward the events from the sheet to the constrained
+// window delegate.
+@interface CollectedCookiesSheetBridge : NSObject {
+ CollectedCookiesMac* collectedCookies_; // weak
+}
+- (id)initWithCollectedCookiesMac:(CollectedCookiesMac*)collectedCookies;
+- (void)sheetDidEnd:(NSWindow*)sheet
+ returnCode:(int)returnCode
+ contextInfo:(void*)contextInfo;
+@end
+
+@implementation CollectedCookiesSheetBridge
+- (id)initWithCollectedCookiesMac:(CollectedCookiesMac*)collectedCookies {
+ if ((self = [super init])) {
+ collectedCookies_ = collectedCookies;
+ }
+ return self;
+}
+
+- (void)sheetDidEnd:(NSWindow*)sheet
+ returnCode:(int)returnCode
+ contextInfo:(void*)contextInfo {
+ collectedCookies_->OnSheetDidEnd(sheet);
+}
+@end
+
+#pragma mark Constrained window delegate
+
+CollectedCookiesMac::CollectedCookiesMac(NSWindow* parent,
+ TabContents* tab_contents)
+ : ConstrainedWindowMacDelegateCustomSheet(
+ [[[CollectedCookiesSheetBridge alloc]
+ initWithCollectedCookiesMac:this] autorelease],
+ @selector(sheetDidEnd:returnCode:contextInfo:)),
+ tab_contents_(tab_contents) {
+ TabSpecificContentSettings* content_settings =
+ tab_contents->GetTabSpecificContentSettings();
+ registrar_.Add(this, NotificationType::COLLECTED_COOKIES_SHOWN,
+ Source<TabSpecificContentSettings>(content_settings));
+
+ sheet_controller_ = [[CollectedCookiesWindowController alloc]
+ initWithTabContents:tab_contents];
+
+ set_sheet([sheet_controller_ window]);
+
+ window_ = tab_contents->CreateConstrainedDialog(this);
+}
+
+CollectedCookiesMac::~CollectedCookiesMac() {
+ NSWindow* window = [sheet_controller_ window];
+ if (window_ && window && is_sheet_open()) {
+ window_ = NULL;
+ [NSApp endSheet:window];
+ }
+}
+
+void CollectedCookiesMac::DeleteDelegate() {
+ delete this;
+}
+
+void CollectedCookiesMac::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK(type == NotificationType::COLLECTED_COOKIES_SHOWN);
+ DCHECK_EQ(Source<TabSpecificContentSettings>(source).ptr(),
+ tab_contents_->GetTabSpecificContentSettings());
+ window_->CloseConstrainedWindow();
+}
+
+void CollectedCookiesMac::OnSheetDidEnd(NSWindow* sheet) {
+ [sheet orderOut:sheet_controller_];
+ if (window_)
+ window_->CloseConstrainedWindow();
+}
+
+#pragma mark Window Controller
+
+@interface CollectedCookiesWindowController(Private)
+-(void)showInfoBarForDomain:(const string16&)domain
+ setting:(ContentSetting)setting;
+-(void)showInfoBarForMultipleDomainsAndSetting:(ContentSetting)setting;
+-(void)animateInfoBar;
+@end
+
+@implementation CollectedCookiesWindowController
+
+@synthesize allowedCookiesButtonsEnabled =
+ allowedCookiesButtonsEnabled_;
+@synthesize blockedCookiesButtonsEnabled =
+ blockedCookiesButtonsEnabled_;
+
+@synthesize allowedTreeController = allowedTreeController_;
+@synthesize blockedTreeController = blockedTreeController_;
+
+- (id)initWithTabContents:(TabContents*)tabContents {
+ DCHECK(tabContents);
+ infoBarVisible_ = NO;
+ tabContents_ = tabContents;
+
+ NSString* nibpath =
+ [mac_util::MainAppBundle() pathForResource:@"CollectedCookies"
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
+ [self loadTreeModelFromTabContents];
+
+ animation_.reset([[NSViewAnimation alloc] init]);
+ [animation_ setAnimationBlockingMode:NSAnimationNonblocking];
+ }
+ return self;
+}
+
+- (void)awakeFromNib {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ NSImage* infoIcon = rb.GetNativeImageNamed(IDR_INFO);
+ DCHECK(infoIcon);
+ [infoBarIcon_ setImage:infoIcon];
+
+ // Initialize the banner gradient and stroke color.
+ NSColor* bannerStartingColor =
+ [NSColor colorWithCalibratedRed:kBannerGradientColorTop[0]
+ green:kBannerGradientColorTop[1]
+ blue:kBannerGradientColorTop[2]
+ alpha:1.0];
+ NSColor* bannerEndingColor =
+ [NSColor colorWithCalibratedRed:kBannerGradientColorBottom[0]
+ green:kBannerGradientColorBottom[1]
+ blue:kBannerGradientColorBottom[2]
+ alpha:1.0];
+ scoped_nsobject<NSGradient> bannerGradient(
+ [[NSGradient alloc] initWithStartingColor:bannerStartingColor
+ endingColor:bannerEndingColor]);
+ [infoBar_ setGradient:bannerGradient];
+
+ NSColor* bannerStrokeColor =
+ [NSColor colorWithCalibratedWhite:kBannerStrokeColor
+ alpha:1.0];
+ [infoBar_ setStrokeColor:bannerStrokeColor];
+
+ // Change the label of the blocked cookies part if necessary.
+ if (tabContents_->profile()->GetHostContentSettingsMap()->
+ BlockThirdPartyCookies()) {
+ [blockedCookiesText_ setStringValue:l10n_util::GetNSString(
+ IDS_COLLECTED_COOKIES_BLOCKED_THIRD_PARTY_BLOCKING_ENABLED)];
+ CGFloat textDeltaY = [GTMUILocalizerAndLayoutTweaker
+ sizeToFitFixedWidthTextField:blockedCookiesText_];
+
+ // Shrink the upper custom view.
+ NSView* upperContentView = [[splitView_ subviews] objectAtIndex:0];
+ NSRect frame = [upperContentView frame];
+ [splitView_ setPosition:(frame.size.height - textDeltaY/2.0)
+ ofDividerAtIndex:0];
+
+ // Shrink the lower outline view.
+ frame = [lowerScrollView_ frame];
+ frame.size.height -= textDeltaY;
+ [lowerScrollView_ setFrame:frame];
+
+ // Move the label down so it actually fits.
+ frame = [blockedCookiesText_ frame];
+ frame.origin.y -= textDeltaY;
+ [blockedCookiesText_ setFrame:frame];
+ }
+}
+
+- (void)windowWillClose:(NSNotification*)notif {
+ [allowedOutlineView_ setDelegate:nil];
+ [blockedOutlineView_ setDelegate:nil];
+ [animation_ stopAnimation];
+ [self autorelease];
+}
+
+- (IBAction)closeSheet:(id)sender {
+ [NSApp endSheet:[self window]];
+}
+
+- (void)addException:(ContentSetting)setting
+ forTreeController:(NSTreeController*)controller {
+ NSArray* nodes = [controller selectedNodes];
+ BOOL multipleDomainsChanged = NO;
+ string16 lastDomain;
+ for (NSTreeNode* treeNode in nodes) {
+ CocoaCookieTreeNode* node = [treeNode representedObject];
+ CookieTreeNode* cookie = static_cast<CookieTreeNode*>([node treeNode]);
+ if (cookie->GetDetailedInfo().node_type !=
+ CookieTreeNode::DetailedInfo::TYPE_ORIGIN) {
+ continue;
+ }
+ CookieTreeOriginNode* origin_node =
+ static_cast<CookieTreeOriginNode*>(cookie);
+ origin_node->CreateContentException(
+ tabContents_->profile()->GetHostContentSettingsMap(),
+ setting);
+ if (!lastDomain.empty())
+ multipleDomainsChanged = YES;
+ lastDomain = origin_node->GetTitle();
+ }
+ if (multipleDomainsChanged)
+ [self showInfoBarForMultipleDomainsAndSetting:setting];
+ else
+ [self showInfoBarForDomain:lastDomain setting:setting];
+}
+
+- (IBAction)allowOrigin:(id)sender {
+ [self addException:CONTENT_SETTING_ALLOW
+ forTreeController:blockedTreeController_];
+}
+
+- (IBAction)allowForSessionFromOrigin:(id)sender {
+ [self addException:CONTENT_SETTING_SESSION_ONLY
+ forTreeController:blockedTreeController_];
+}
+
+- (IBAction)blockOrigin:(id)sender {
+ [self addException:CONTENT_SETTING_BLOCK
+ forTreeController:allowedTreeController_];
+}
+
+- (CGFloat) splitView:(NSSplitView *)sender
+ constrainMinCoordinate:(CGFloat)proposedMin
+ ofSubviewAt:(NSInteger)offset {
+ return proposedMin + kMinCollectedCookiesViewHeight;
+}
+- (CGFloat) splitView:(NSSplitView *)sender
+ constrainMaxCoordinate:(CGFloat)proposedMax
+ ofSubviewAt:(NSInteger)offset {
+ return proposedMax - kMinCollectedCookiesViewHeight;
+}
+- (BOOL)splitView:(NSSplitView *)sender canCollapseSubview:(NSView *)subview {
+ return YES;
+}
+
+- (CocoaCookieTreeNode*)cocoaAllowedTreeModel {
+ return cocoaAllowedTreeModel_.get();
+}
+- (void)setCocoaAllowedTreeModel:(CocoaCookieTreeNode*)model {
+ cocoaAllowedTreeModel_.reset([model retain]);
+}
+
+- (CookiesTreeModel*)allowedTreeModel {
+ return allowedTreeModel_.get();
+}
+
+- (CocoaCookieTreeNode*)cocoaBlockedTreeModel {
+ return cocoaBlockedTreeModel_.get();
+}
+- (void)setCocoaBlockedTreeModel:(CocoaCookieTreeNode*)model {
+ cocoaBlockedTreeModel_.reset([model retain]);
+}
+
+- (CookiesTreeModel*)blockedTreeModel {
+ return blockedTreeModel_.get();
+}
+
+- (void)outlineView:(NSOutlineView*)outlineView
+ willDisplayCell:(id)cell
+ forTableColumn:(NSTableColumn*)tableColumn
+ item:(id)item {
+ CocoaCookieTreeNode* node = [item representedObject];
+ int index;
+ if (outlineView == allowedOutlineView_)
+ index = allowedTreeModel_->GetIconIndex([node treeNode]);
+ else
+ index = blockedTreeModel_->GetIconIndex([node treeNode]);
+ NSImage* icon = nil;
+ if (index >= 0)
+ icon = [icons_ objectAtIndex:index];
+ else
+ icon = [icons_ lastObject];
+ DCHECK([cell isKindOfClass:[ImageAndTextCell class]]);
+ [static_cast<ImageAndTextCell*>(cell) setImage:icon];
+}
+
+- (void)outlineViewSelectionDidChange:(NSNotification*)notif {
+ BOOL isAllowedOutlineView;
+ if ([notif object] == allowedOutlineView_) {
+ isAllowedOutlineView = YES;
+ } else if ([notif object] == blockedOutlineView_) {
+ isAllowedOutlineView = NO;
+ } else {
+ NOTREACHED();
+ return;
+ }
+ NSTreeController* controller =
+ isAllowedOutlineView ? allowedTreeController_ : blockedTreeController_;
+
+ NSArray* nodes = [controller selectedNodes];
+ for (NSTreeNode* treeNode in nodes) {
+ CocoaCookieTreeNode* node = [treeNode representedObject];
+ CookieTreeNode* cookie = static_cast<CookieTreeNode*>([node treeNode]);
+ if (cookie->GetDetailedInfo().node_type !=
+ CookieTreeNode::DetailedInfo::TYPE_ORIGIN) {
+ continue;
+ }
+ CookieTreeOriginNode* origin_node =
+ static_cast<CookieTreeOriginNode*>(cookie);
+ if (origin_node->CanCreateContentException()) {
+ if (isAllowedOutlineView) {
+ [self setAllowedCookiesButtonsEnabled:YES];
+ } else {
+ [self setBlockedCookiesButtonsEnabled:YES];
+ }
+ return;
+ }
+ }
+ if (isAllowedOutlineView) {
+ [self setAllowedCookiesButtonsEnabled:NO];
+ } else {
+ [self setBlockedCookiesButtonsEnabled:NO];
+ }
+}
+
+// Initializes the |allowedTreeModel_| and |blockedTreeModel_|, and builds
+// the |cocoaAllowedTreeModel_| and |cocoaBlockedTreeModel_|.
+- (void)loadTreeModelFromTabContents {
+ TabSpecificContentSettings* content_settings =
+ tabContents_->GetTabSpecificContentSettings();
+ allowedTreeModel_.reset(content_settings->GetAllowedCookiesTreeModel());
+ blockedTreeModel_.reset(content_settings->GetBlockedCookiesTreeModel());
+
+ // Convert the model's icons from Skia to Cocoa.
+ std::vector<SkBitmap> skiaIcons;
+ allowedTreeModel_->GetIcons(&skiaIcons);
+ icons_.reset([[NSMutableArray alloc] init]);
+ for (std::vector<SkBitmap>::iterator it = skiaIcons.begin();
+ it != skiaIcons.end(); ++it) {
+ [icons_ addObject:gfx::SkBitmapToNSImage(*it)];
+ }
+
+ // Default icon will be the last item in the array.
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ // TODO(rsesek): Rename this resource now that it's in multiple places.
+ [icons_ addObject:rb.GetNativeImageNamed(IDR_BOOKMARK_BAR_FOLDER)];
+
+ // Create the Cocoa model.
+ CookieTreeNode* root =
+ static_cast<CookieTreeNode*>(allowedTreeModel_->GetRoot());
+ scoped_nsobject<CocoaCookieTreeNode> model(
+ [[CocoaCookieTreeNode alloc] initWithNode:root]);
+ [self setCocoaAllowedTreeModel:model.get()]; // Takes ownership.
+ root = static_cast<CookieTreeNode*>(blockedTreeModel_->GetRoot());
+ model.reset(
+ [[CocoaCookieTreeNode alloc] initWithNode:root]);
+ [self setCocoaBlockedTreeModel:model.get()]; // Takes ownership.
+}
+
+-(void)showInfoBarForMultipleDomainsAndSetting:(ContentSetting)setting {
+ NSString* label;
+ switch (setting) {
+ case CONTENT_SETTING_BLOCK:
+ label = l10n_util::GetNSString(
+ IDS_COLLECTED_COOKIES_MULTIPLE_BLOCK_RULES_CREATED);
+ break;
+
+ case CONTENT_SETTING_ALLOW:
+ label = l10n_util::GetNSString(
+ IDS_COLLECTED_COOKIES_MULTIPLE_ALLOW_RULES_CREATED);
+ break;
+
+ case CONTENT_SETTING_SESSION_ONLY:
+ label = l10n_util::GetNSString(
+ IDS_COLLECTED_COOKIES_MULTIPLE_SESSION_RULES_CREATED);
+ break;
+
+ default:
+ NOTREACHED();
+ label = [[[NSString alloc] init] autorelease];
+ }
+ [infoBarText_ setStringValue:label];
+ [self animateInfoBar];
+}
+
+-(void)showInfoBarForDomain:(const string16&)domain
+ setting:(ContentSetting)setting {
+ NSString* label;
+ switch (setting) {
+ case CONTENT_SETTING_BLOCK:
+ label = l10n_util::GetNSStringF(
+ IDS_COLLECTED_COOKIES_BLOCK_RULE_CREATED,
+ domain);
+ break;
+
+ case CONTENT_SETTING_ALLOW:
+ label = l10n_util::GetNSStringF(
+ IDS_COLLECTED_COOKIES_ALLOW_RULE_CREATED,
+ domain);
+ break;
+
+ case CONTENT_SETTING_SESSION_ONLY:
+ label = l10n_util::GetNSStringF(
+ IDS_COLLECTED_COOKIES_SESSION_RULE_CREATED,
+ domain);
+ break;
+
+ default:
+ NOTREACHED();
+ label = [[[NSString alloc] init] autorelease];
+ }
+ [infoBarText_ setStringValue:label];
+ [self animateInfoBar];
+}
+
+-(void)animateInfoBar {
+ if (infoBarVisible_)
+ return;
+
+ infoBarVisible_ = YES;
+
+ NSMutableArray* animations = [NSMutableArray arrayWithCapacity:3];
+
+ NSWindow* sheet = [self window];
+ NSRect sheetFrame = [sheet frame];
+ NSRect infoBarFrame = [infoBar_ frame];
+ NSRect splitViewFrame = [splitView_ frame];
+
+ // Calculate the end position of the info bar and set it to its start
+ // position.
+ infoBarFrame.origin.y = NSHeight(sheetFrame);
+ infoBarFrame.size.width = NSWidth(sheetFrame);
+ NSRect infoBarStartFrame = infoBarFrame;
+ infoBarStartFrame.origin.y += NSHeight(infoBarFrame);
+ infoBarStartFrame.size.height = 0.0;
+ [infoBar_ setFrame:infoBarStartFrame];
+ [[[self window] contentView] addSubview:infoBar_];
+
+ // Calculate the new position of the sheet.
+ sheetFrame.origin.y -= NSHeight(infoBarFrame);
+ sheetFrame.size.height += NSHeight(infoBarFrame);
+
+ // Slide the infobar in.
+ [animations addObject:
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ infoBar_, NSViewAnimationTargetKey,
+ [NSValue valueWithRect:infoBarFrame],
+ NSViewAnimationEndFrameKey,
+ [NSValue valueWithRect:infoBarStartFrame],
+ NSViewAnimationStartFrameKey,
+ nil]];
+ // Make sure the split view ends up in the right position.
+ [animations addObject:
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ splitView_, NSViewAnimationTargetKey,
+ [NSValue valueWithRect:splitViewFrame],
+ NSViewAnimationEndFrameKey,
+ nil]];
+
+ // Grow the sheet.
+ [animations addObject:
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ sheet, NSViewAnimationTargetKey,
+ [NSValue valueWithRect:sheetFrame],
+ NSViewAnimationEndFrameKey,
+ nil]];
+ [animation_ setViewAnimations:animations];
+ // The default duration is 0.5s, which actually feels slow in here, so speed
+ // it up a bit.
+ [animation_ gtm_setDuration:0.2
+ eventMask:NSLeftMouseUpMask];
+ [animation_ startAnimation];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/collected_cookies_mac_unittest.mm b/chrome/browser/ui/cocoa/collected_cookies_mac_unittest.mm
new file mode 100644
index 0000000..a7bc6b7
--- /dev/null
+++ b/chrome/browser/ui/cocoa/collected_cookies_mac_unittest.mm
@@ -0,0 +1,38 @@
+// Copyright (c) 2009 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 "base/ref_counted.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/site_instance.h"
+#include "chrome/browser/renderer_host/test/test_render_view_host.h"
+#include "chrome/browser/tab_contents/test_tab_contents.h"
+#import "chrome/browser/ui/cocoa/collected_cookies_mac.h"
+#include "chrome/test/testing_profile.h"
+
+namespace {
+
+class CollectedCookiesWindowControllerTest : public RenderViewHostTestHarness {
+};
+
+TEST_F(CollectedCookiesWindowControllerTest, Construction) {
+ BrowserThread ui_thread(BrowserThread::UI, MessageLoop::current());
+ // Create a test tab. SiteInstance will be deleted when tabContents is
+ // deleted.
+ SiteInstance* instance =
+ SiteInstance::CreateSiteInstance(profile_.get());
+ TestTabContents* tabContents = new TestTabContents(profile_.get(),
+ instance);
+ CollectedCookiesWindowController* controller =
+ [[CollectedCookiesWindowController alloc]
+ initWithTabContents:tabContents];
+
+ [controller release];
+
+ delete tabContents;
+}
+
+} // namespace
+
diff --git a/chrome/browser/ui/cocoa/command_observer_bridge.h b/chrome/browser/ui/cocoa/command_observer_bridge.h
new file mode 100644
index 0000000..74179dd
--- /dev/null
+++ b/chrome/browser/ui/cocoa/command_observer_bridge.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_COMMAND_OBSERVER_BRIDGE
+#define CHROME_BROWSER_UI_COCOA_COMMAND_OBSERVER_BRIDGE
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "chrome/browser/command_updater.h"
+
+@protocol CommandObserverProtocol;
+
+// A C++ bridge class that handles listening for updates to commands and
+// passing them back to an object that supports the protocol delcared below.
+// The observer will create one of these bridges, call ObserveCommand() on the
+// command ids it cares about, and then wait for update notifications,
+// delivered via -enabledStateChangedForCommand:enabled:. Destroying this
+// bridge will handle automatically unregistering for updates, so there's no
+// need to do that manually.
+
+class CommandObserverBridge : public CommandUpdater::CommandObserver {
+ public:
+ CommandObserverBridge(id<CommandObserverProtocol> observer,
+ CommandUpdater* commands);
+ virtual ~CommandObserverBridge();
+
+ // Register for updates about |command|.
+ void ObserveCommand(int command);
+
+ protected:
+ // Overridden from CommandUpdater::CommandObserver
+ virtual void EnabledStateChangedForCommand(int command, bool enabled);
+
+ private:
+ id<CommandObserverProtocol> observer_; // weak, owns me
+ CommandUpdater* commands_; // weak
+};
+
+// Implemented by the observing Objective-C object, called when there is a
+// state change for the given command.
+@protocol CommandObserverProtocol
+- (void)enabledStateChangedForCommand:(NSInteger)command enabled:(BOOL)enabled;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_COMMAND_OBSERVER_BRIDGE
diff --git a/chrome/browser/ui/cocoa/command_observer_bridge.mm b/chrome/browser/ui/cocoa/command_observer_bridge.mm
new file mode 100644
index 0000000..0ffea97
--- /dev/null
+++ b/chrome/browser/ui/cocoa/command_observer_bridge.mm
@@ -0,0 +1,28 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/command_observer_bridge.h"
+
+#include "base/logging.h"
+
+CommandObserverBridge::CommandObserverBridge(
+ id<CommandObserverProtocol> observer, CommandUpdater* commands)
+ : observer_(observer), commands_(commands) {
+ DCHECK(observer_ && commands_);
+}
+
+CommandObserverBridge::~CommandObserverBridge() {
+ // Unregister the notifications
+ commands_->RemoveCommandObserver(this);
+}
+
+void CommandObserverBridge::ObserveCommand(int command) {
+ commands_->AddCommandObserver(command, this);
+}
+
+void CommandObserverBridge::EnabledStateChangedForCommand(int command,
+ bool enabled) {
+ [observer_ enabledStateChangedForCommand:command
+ enabled:enabled ? YES : NO];
+}
diff --git a/chrome/browser/ui/cocoa/command_observer_bridge_unittest.mm b/chrome/browser/ui/cocoa/command_observer_bridge_unittest.mm
new file mode 100644
index 0000000..371bb2c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/command_observer_bridge_unittest.mm
@@ -0,0 +1,89 @@
+// Copyright (c) 2009 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 "base/scoped_ptr.h"
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/command_observer_bridge.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+// Implements the callback interface. Records the last command id and
+// enabled state it has received so it can be queried by the tests to see
+// if we got a notification or not.
+@interface CommandTestObserver : NSObject<CommandObserverProtocol> {
+ @private
+ int lastCommand_; // id of last received state change
+ bool lastState_; // state of last received state change
+}
+- (int)lastCommand;
+- (bool)lastState;
+@end
+
+@implementation CommandTestObserver
+- (void)enabledStateChangedForCommand:(NSInteger)command enabled:(BOOL)enabled {
+ lastCommand_ = command;
+ lastState_ = enabled;
+}
+- (int)lastCommand {
+ return lastCommand_;
+}
+- (bool)lastState {
+ return lastState_;
+}
+@end
+
+namespace {
+
+class CommandObserverBridgeTest : public PlatformTest {
+ public:
+ CommandObserverBridgeTest()
+ : updater_(new CommandUpdater(NULL)),
+ observer_([[CommandTestObserver alloc] init]) {
+ }
+ scoped_ptr<CommandUpdater> updater_;
+ scoped_nsobject<CommandTestObserver> observer_;
+};
+
+// Tests creation and deletion. NULL arguments aren't allowed.
+TEST_F(CommandObserverBridgeTest, Create) {
+ CommandObserverBridge bridge(observer_.get(), updater_.get());
+}
+
+// Observes state changes on command ids 1 and 2. Ensure we don't get
+// a notification of a state change on a command we're not observing (3).
+// Commands start off enabled in CommandUpdater.
+TEST_F(CommandObserverBridgeTest, Observe) {
+ CommandObserverBridge bridge(observer_.get(), updater_.get());
+ bridge.ObserveCommand(1);
+ bridge.ObserveCommand(2);
+
+ // Validate initial state assumptions.
+ EXPECT_EQ([observer_ lastCommand], 0);
+ EXPECT_EQ([observer_ lastState], false);
+ EXPECT_EQ(updater_->IsCommandEnabled(1), true);
+ EXPECT_EQ(updater_->IsCommandEnabled(2), true);
+
+ updater_->UpdateCommandEnabled(1, false);
+ EXPECT_EQ([observer_ lastCommand], 1);
+ EXPECT_EQ([observer_ lastState], false);
+
+ updater_->UpdateCommandEnabled(2, false);
+ EXPECT_EQ([observer_ lastCommand], 2);
+ EXPECT_EQ([observer_ lastState], false);
+
+ updater_->UpdateCommandEnabled(1, true);
+ EXPECT_EQ([observer_ lastCommand], 1);
+ EXPECT_EQ([observer_ lastState], true);
+
+ // Change something we're not watching and make sure the last state hasn't
+ // changed.
+ updater_->UpdateCommandEnabled(3, false);
+ EXPECT_EQ([observer_ lastCommand], 1);
+ EXPECT_NE([observer_ lastCommand], 3);
+ EXPECT_EQ([observer_ lastState], true);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/confirm_quit_panel_controller.h b/chrome/browser/ui/cocoa/confirm_quit_panel_controller.h
new file mode 100644
index 0000000..b7201e1
--- /dev/null
+++ b/chrome/browser/ui/cocoa/confirm_quit_panel_controller.h
@@ -0,0 +1,25 @@
+// 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>
+
+#import "base/mac/cocoa_protocols.h"
+
+// The ConfirmQuitPanelController manages the black HUD window that tells users
+// to "Hold Cmd+Q to Quit".
+@interface ConfirmQuitPanelController : NSWindowController<NSWindowDelegate> {
+}
+
+// Returns a singleton instance of the Controller. This will create one if it
+// does not currently exist.
++ (ConfirmQuitPanelController*)sharedController;
+
+// Shows the window.
+- (void)showWindow:(id)sender;
+
+// If the user did not confirm quit, send this message to give the user
+// instructions on how to quit.
+- (void)dismissPanel;
+
+@end
diff --git a/chrome/browser/ui/cocoa/confirm_quit_panel_controller.mm b/chrome/browser/ui/cocoa/confirm_quit_panel_controller.mm
new file mode 100644
index 0000000..548b83a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/confirm_quit_panel_controller.mm
@@ -0,0 +1,85 @@
+// 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>
+#import <QuartzCore/QuartzCore.h>
+
+#include "base/logging.h"
+#include "base/mac_util.h"
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/confirm_quit_panel_controller.h"
+
+@interface ConfirmQuitPanelController (Private)
+- (id)initInternal;
+- (void)animateFadeOut;
+@end
+
+ConfirmQuitPanelController* g_confirmQuitPanelController = nil;
+
+@implementation ConfirmQuitPanelController
+
++ (ConfirmQuitPanelController*)sharedController {
+ if (!g_confirmQuitPanelController) {
+ g_confirmQuitPanelController =
+ [[ConfirmQuitPanelController alloc] initInternal];
+ }
+ return g_confirmQuitPanelController;
+}
+
+- (id)initInternal {
+ NSString* nibPath =
+ [mac_util::MainAppBundle() pathForResource:@"ConfirmQuitPanel"
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibPath owner:self])) {
+ }
+ return self;
+}
+
+- (void)awakeFromNib {
+ DCHECK([self window]);
+ DCHECK_EQ(self, [[self window] delegate]);
+}
+
+- (void)windowWillClose:(NSNotification*)notif {
+ // Release all animations because CAAnimation retains its delegate (self),
+ // which will cause a retain cycle. Break it!
+ [[self window] setAnimations:[NSDictionary dictionary]];
+ g_confirmQuitPanelController = nil;
+ [self autorelease];
+}
+
+- (void)showWindow:(id)sender {
+ // If a panel that is fading out is going to be reused here, make sure it
+ // does not get released when the animation finishes.
+ scoped_nsobject<ConfirmQuitPanelController> stayAlive([self retain]);
+ [[self window] setAnimations:[NSDictionary dictionary]];
+ [[self window] center];
+ [[self window] setAlphaValue:1.0];
+ [super showWindow:sender];
+}
+
+- (void)dismissPanel {
+ [self performSelector:@selector(animateFadeOut)
+ withObject:nil
+ afterDelay:1.0];
+}
+
+- (void)animateFadeOut {
+ NSWindow* window = [self window];
+ scoped_nsobject<CAAnimation> animation(
+ [[window animationForKey:@"alphaValue"] copy]);
+ [animation setDelegate:self];
+ [animation setDuration:0.2];
+ NSMutableDictionary* dictionary =
+ [NSMutableDictionary dictionaryWithDictionary:[window animations]];
+ [dictionary setObject:animation forKey:@"alphaValue"];
+ [window setAnimations:dictionary];
+ [[window animator] setAlphaValue:0.0];
+}
+
+- (void)animationDidStop:(CAAnimation*)theAnimation finished:(BOOL)finished {
+ [self close];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/confirm_quit_panel_controller_unittest.mm b/chrome/browser/ui/cocoa/confirm_quit_panel_controller_unittest.mm
new file mode 100644
index 0000000..0426149
--- /dev/null
+++ b/chrome/browser/ui/cocoa/confirm_quit_panel_controller_unittest.mm
@@ -0,0 +1,27 @@
+// 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 "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/confirm_quit_panel_controller.h"
+
+namespace {
+
+class ConfirmQuitPanelControllerTest : public CocoaTest {
+};
+
+
+TEST_F(ConfirmQuitPanelControllerTest, ShowAndDismiss) {
+ ConfirmQuitPanelController* controller =
+ [ConfirmQuitPanelController sharedController];
+ // Test singleton.
+ EXPECT_EQ(controller, [ConfirmQuitPanelController sharedController]);
+ [controller showWindow:nil];
+ [controller dismissPanel]; // Releases self.
+ // The controller should still be the singleton instance until after the
+ // animation runs and the window closes. That will happen after this test body
+ // finishes executing.
+ EXPECT_EQ(controller, [ConfirmQuitPanelController sharedController]);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/constrained_html_delegate_mac.mm b/chrome/browser/ui/cocoa/constrained_html_delegate_mac.mm
new file mode 100644
index 0000000..9e0344e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/constrained_html_delegate_mac.mm
@@ -0,0 +1,153 @@
+// 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.
+
+#include "chrome/browser/dom_ui/constrained_html_ui.h"
+
+#include "base/scoped_nsobject.h"
+#include "chrome/browser/dom_ui/html_dialog_ui.h"
+#include "chrome/browser/dom_ui/html_dialog_tab_contents_delegate.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/cocoa/constrained_window_mac.h"
+#import <Cocoa/Cocoa.h>
+#include "ipc/ipc_message.h"
+
+class ConstrainedHtmlDelegateMac :
+ public ConstrainedWindowMacDelegateCustomSheet,
+ public HtmlDialogTabContentsDelegate,
+ public ConstrainedHtmlUIDelegate {
+
+ public:
+ ConstrainedHtmlDelegateMac(Profile* profile,
+ HtmlDialogUIDelegate* delegate);
+ ~ConstrainedHtmlDelegateMac() {}
+
+ // ConstrainedWindowMacDelegateCustomSheet -----------------------------------
+ virtual void DeleteDelegate() {
+ // From ConstrainedWindowMacDelegate: "you MUST close the sheet belonging to
+ // your delegate in this method."
+ if (is_sheet_open())
+ [NSApp endSheet:sheet()];
+ html_delegate_->OnDialogClosed("");
+ delete this;
+ }
+
+ // ConstrainedHtmlDelegate ---------------------------------------------------
+ virtual HtmlDialogUIDelegate* GetHtmlDialogUIDelegate();
+ virtual void OnDialogClose();
+
+ // HtmlDialogTabContentsDelegate ---------------------------------------------
+ void MoveContents(TabContents* source, const gfx::Rect& pos) {}
+ void ToolbarSizeChanged(TabContents* source, bool is_animating) {}
+ void HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {}
+
+ void set_window(ConstrainedWindow* window) {
+ constrained_window_ = window;
+ }
+
+ private:
+ TabContents tab_contents_; // Holds the HTML to be displayed in the sheet.
+ HtmlDialogUIDelegate* html_delegate_; // weak.
+
+ // The constrained window that owns |this|. Saved here because it needs to be
+ // closed in response to the DOMUI OnDialogClose callback.
+ ConstrainedWindow* constrained_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConstrainedHtmlDelegateMac);
+};
+
+// The delegate used to forward events from the sheet to the constrained
+// window delegate. This bridge needs to be passed into the customsheet
+// to allow the HtmlDialog to know when the sheet closes.
+@interface ConstrainedHtmlDialogSheetCocoa : NSObject {
+ ConstrainedHtmlDelegateMac* constrainedHtmlDelegate_; // weak
+}
+- (id)initWithConstrainedHtmlDelegateMac:
+ (ConstrainedHtmlDelegateMac*)ConstrainedHtmlDelegateMac;
+- (void)sheetDidEnd:(NSWindow*)sheet
+ returnCode:(int)returnCode
+ contextInfo:(void*)contextInfo;
+@end
+
+ConstrainedHtmlDelegateMac::ConstrainedHtmlDelegateMac(
+ Profile* profile,
+ HtmlDialogUIDelegate* delegate)
+ : HtmlDialogTabContentsDelegate(profile),
+ tab_contents_(profile, NULL, MSG_ROUTING_NONE, NULL, NULL),
+ html_delegate_(delegate),
+ constrained_window_(NULL) {
+ tab_contents_.set_delegate(this);
+
+ // Set |this| as a property on the tab contents so that the ConstrainedHtmlUI
+ // can get a reference to |this|.
+ ConstrainedHtmlUI::GetPropertyAccessor().SetProperty(
+ tab_contents_.property_bag(), this);
+
+ tab_contents_.controller().LoadURL(delegate->GetDialogContentURL(),
+ GURL(), PageTransition::START_PAGE);
+
+ // Create NSWindow to hold tab_contents in the constrained sheet:
+ gfx::Size size;
+ delegate->GetDialogSize(&size);
+ NSRect frame = NSMakeRect(0, 0, size.width(), size.height());
+
+ // |window| is retained by the ConstrainedWindowMacDelegateCustomSheet when
+ // the sheet is initialized.
+ scoped_nsobject<NSWindow> window;
+ window.reset(
+ [[NSWindow alloc] initWithContentRect:frame
+ styleMask:NSTitledWindowMask
+ backing:NSBackingStoreBuffered
+ defer:YES]);
+
+ [window.get() setContentView:tab_contents_.GetNativeView()];
+
+ // Set the custom sheet to point to the new window.
+ ConstrainedWindowMacDelegateCustomSheet::init(
+ window.get(),
+ [[[ConstrainedHtmlDialogSheetCocoa alloc]
+ initWithConstrainedHtmlDelegateMac:this] autorelease],
+ @selector(sheetDidEnd:returnCode:contextInfo:));
+}
+
+HtmlDialogUIDelegate* ConstrainedHtmlDelegateMac::GetHtmlDialogUIDelegate() {
+ return html_delegate_;
+}
+
+void ConstrainedHtmlDelegateMac::OnDialogClose() {
+ DCHECK(constrained_window_);
+ if (constrained_window_)
+ constrained_window_->CloseConstrainedWindow();
+}
+
+// static
+void ConstrainedHtmlUI::CreateConstrainedHtmlDialog(
+ Profile* profile,
+ HtmlDialogUIDelegate* delegate,
+ TabContents* overshadowed) {
+ // Deleted when ConstrainedHtmlDelegateMac::DeleteDelegate() runs.
+ ConstrainedHtmlDelegateMac* constrained_delegate =
+ new ConstrainedHtmlDelegateMac(profile, delegate);
+ // Deleted when ConstrainedHtmlDelegateMac::OnDialogClose() runs.
+ ConstrainedWindow* constrained_window =
+ overshadowed->CreateConstrainedDialog(constrained_delegate);
+ constrained_delegate->set_window(constrained_window);
+}
+
+@implementation ConstrainedHtmlDialogSheetCocoa
+
+- (id)initWithConstrainedHtmlDelegateMac:
+ (ConstrainedHtmlDelegateMac*)ConstrainedHtmlDelegateMac {
+ if ((self = [super init]))
+ constrainedHtmlDelegate_ = ConstrainedHtmlDelegateMac;
+ return self;
+}
+
+- (void)sheetDidEnd:(NSWindow*)sheet
+ returnCode:(int)returnCode
+ contextInfo:(void *)contextInfo {
+ [sheet orderOut:self];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/constrained_window_mac.h b/chrome/browser/ui/cocoa/constrained_window_mac.h
new file mode 100644
index 0000000..7c056ed
--- /dev/null
+++ b/chrome/browser/ui/cocoa/constrained_window_mac.h
@@ -0,0 +1,165 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_CONSTRAINED_WINDOW_MAC_H_
+#define CHROME_BROWSER_UI_COCOA_CONSTRAINED_WINDOW_MAC_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "chrome/browser/tab_contents/constrained_window.h"
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/scoped_nsobject.h"
+
+@class BrowserWindowController;
+@class GTMWindowSheetController;
+@class NSView;
+@class NSWindow;
+class TabContents;
+
+// Base class for constrained dialog delegates. Never inherit from this
+// directly.
+class ConstrainedWindowMacDelegate {
+ public:
+ ConstrainedWindowMacDelegate() : is_sheet_open_(false) { }
+ virtual ~ConstrainedWindowMacDelegate();
+
+ // Tells the delegate to either delete itself or set up a task to delete
+ // itself later. Note that you MUST close the sheet belonging to your delegate
+ // in this method.
+ virtual void DeleteDelegate() = 0;
+
+ // Called by the tab controller, you do not need to do anything yourself
+ // with this method.
+ virtual void RunSheet(GTMWindowSheetController* sheetController,
+ NSView* view) = 0;
+ protected:
+ // Returns true if this delegate's sheet is currently showing.
+ bool is_sheet_open() { return is_sheet_open_; }
+
+ private:
+ bool is_sheet_open_;
+ void set_sheet_open(bool is_open) { is_sheet_open_ = is_open; }
+ friend class ConstrainedWindowMac;
+};
+
+// Subclass this for a dialog delegate that displays a system sheet such as
+// an NSAlert, an open or save file panel, etc.
+class ConstrainedWindowMacDelegateSystemSheet
+ : public ConstrainedWindowMacDelegate {
+ public:
+ ConstrainedWindowMacDelegateSystemSheet(id delegate, SEL didEndSelector)
+ : systemSheet_(nil),
+ delegate_([delegate retain]),
+ didEndSelector_(didEndSelector) { }
+
+ protected:
+ void set_sheet(id sheet) { systemSheet_.reset([sheet retain]); }
+ id sheet() { return systemSheet_; }
+
+ // Returns an NSArray to be passed as parameters to GTMWindowSheetController.
+ // Array's contents should be the arguments passed to the system sheet's
+ // beginSheetForWindow:... method. The window argument must be [NSNull null].
+ //
+ // The default implementation returns
+ // [null window, delegate, didEndSelector, null contextInfo]
+ // Subclasses may override this if they show a system sheet which takes
+ // different parameters.
+ virtual NSArray* GetSheetParameters(id delegate, SEL didEndSelector);
+
+ private:
+ virtual void RunSheet(GTMWindowSheetController* sheetController,
+ NSView* view);
+ scoped_nsobject<id> systemSheet_;
+ scoped_nsobject<id> delegate_;
+ SEL didEndSelector_;
+};
+
+// Subclass this for a dialog delegate that displays a custom sheet, e.g. loaded
+// from a nib file.
+class ConstrainedWindowMacDelegateCustomSheet
+ : public ConstrainedWindowMacDelegate {
+ public:
+ ConstrainedWindowMacDelegateCustomSheet()
+ : customSheet_(nil),
+ delegate_(nil),
+ didEndSelector_(NULL) { }
+
+ ConstrainedWindowMacDelegateCustomSheet(id delegate, SEL didEndSelector)
+ : customSheet_(nil),
+ delegate_([delegate retain]),
+ didEndSelector_(didEndSelector) { }
+
+ protected:
+ // For when you need to delay initalization after the constructor call.
+ void init(NSWindow* sheet, id delegate, SEL didEndSelector) {
+ DCHECK(!delegate_.get());
+ DCHECK(!didEndSelector_);
+ customSheet_.reset([sheet retain]);
+ delegate_.reset([delegate retain]);
+ didEndSelector_ = didEndSelector;
+ DCHECK(delegate_.get());
+ DCHECK(didEndSelector_);
+ }
+ void set_sheet(NSWindow* sheet) { customSheet_.reset([sheet retain]); }
+ NSWindow* sheet() { return customSheet_; }
+
+ private:
+ virtual void RunSheet(GTMWindowSheetController* sheetController,
+ NSView* view);
+ scoped_nsobject<NSWindow> customSheet_;
+ scoped_nsobject<id> delegate_;
+ SEL didEndSelector_;
+};
+
+// Constrained window implementation for the Mac port. A constrained window
+// is a per-tab sheet on OS X.
+//
+// Constrained windows work slightly differently on OS X than on the other
+// platforms:
+// 1. A constrained window is bound to both a tab and window on OS X.
+// 2. The delegate is responsible for closing the sheet again when it is
+// deleted.
+class ConstrainedWindowMac : public ConstrainedWindow {
+ public:
+ virtual ~ConstrainedWindowMac();
+
+ // Overridden from ConstrainedWindow:
+ virtual void ShowConstrainedWindow();
+ virtual void CloseConstrainedWindow();
+
+ // Returns the TabContents that constrains this Constrained Window.
+ TabContents* owner() const { return owner_; }
+
+ // Returns the window's delegate.
+ ConstrainedWindowMacDelegate* delegate() { return delegate_; }
+
+ // Makes the constrained window visible, if it is not yet visible.
+ void Realize(BrowserWindowController* controller);
+
+ private:
+ friend class ConstrainedWindow;
+
+ ConstrainedWindowMac(TabContents* owner,
+ ConstrainedWindowMacDelegate* delegate);
+
+ // The TabContents that owns and constrains this ConstrainedWindow.
+ TabContents* owner_;
+
+ // Delegate that provides the contents of this constrained window.
+ ConstrainedWindowMacDelegate* delegate_;
+
+ // Controller of the window that contains this sheet.
+ BrowserWindowController* controller_;
+
+ // Stores if |ShowConstrainedWindow()| was called.
+ bool should_be_visible_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConstrainedWindowMac);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_CONSTRAINED_WINDOW_MAC_H_
+
diff --git a/chrome/browser/ui/cocoa/constrained_window_mac.mm b/chrome/browser/ui/cocoa/constrained_window_mac.mm
new file mode 100644
index 0000000..9c408a0
--- /dev/null
+++ b/chrome/browser/ui/cocoa/constrained_window_mac.mm
@@ -0,0 +1,104 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/constrained_window_mac.h"
+
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_contents_view.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "third_party/GTM/AppKit/GTMWindowSheetController.h"
+
+ConstrainedWindowMacDelegate::~ConstrainedWindowMacDelegate() {}
+
+NSArray* ConstrainedWindowMacDelegateSystemSheet::GetSheetParameters(
+ id delegate,
+ SEL didEndSelector) {
+ return [NSArray arrayWithObjects:
+ [NSNull null], // window, must be [NSNull null]
+ delegate,
+ [NSValue valueWithPointer:didEndSelector],
+ [NSValue valueWithPointer:NULL], // context info for didEndSelector_.
+ nil];
+}
+
+void ConstrainedWindowMacDelegateSystemSheet::RunSheet(
+ GTMWindowSheetController* sheetController,
+ NSView* view) {
+ NSArray* params = GetSheetParameters(delegate_.get(), didEndSelector_);
+ [sheetController beginSystemSheet:systemSheet_
+ modalForView:view
+ withParameters:params];
+}
+
+void ConstrainedWindowMacDelegateCustomSheet::RunSheet(
+ GTMWindowSheetController* sheetController,
+ NSView* view) {
+ [sheetController beginSheet:customSheet_.get()
+ modalForView:view
+ modalDelegate:delegate_.get()
+ didEndSelector:didEndSelector_
+ contextInfo:NULL];
+}
+
+// static
+ConstrainedWindow* ConstrainedWindow::CreateConstrainedDialog(
+ TabContents* parent,
+ ConstrainedWindowMacDelegate* delegate) {
+ return new ConstrainedWindowMac(parent, delegate);
+}
+
+ConstrainedWindowMac::ConstrainedWindowMac(
+ TabContents* owner, ConstrainedWindowMacDelegate* delegate)
+ : owner_(owner),
+ delegate_(delegate),
+ controller_(nil),
+ should_be_visible_(false) {
+ DCHECK(owner);
+ DCHECK(delegate);
+}
+
+ConstrainedWindowMac::~ConstrainedWindowMac() {}
+
+void ConstrainedWindowMac::ShowConstrainedWindow() {
+ should_be_visible_ = true;
+ // The TabContents only has a native window if it is currently visible. In
+ // this case, open the sheet now. Else, Realize() will be called later, when
+ // our tab becomes visible.
+ NSWindow* browserWindow = owner_->view()->GetTopLevelNativeWindow();
+ NSWindowController* controller = [browserWindow windowController];
+ if (controller != nil) {
+ DCHECK([controller isKindOfClass:[BrowserWindowController class]]);
+ BrowserWindowController* browser_controller =
+ static_cast<BrowserWindowController*>(controller);
+ if ([browser_controller canAttachConstrainedWindow])
+ Realize(browser_controller);
+ }
+}
+
+void ConstrainedWindowMac::CloseConstrainedWindow() {
+ // Note: controller_ can be `nil` here if the sheet was never realized. That's
+ // ok.
+ [controller_ removeConstrainedWindow:this];
+ delegate_->DeleteDelegate();
+ owner_->WillClose(this);
+
+ delete this;
+}
+
+void ConstrainedWindowMac::Realize(BrowserWindowController* controller) {
+ if (!should_be_visible_)
+ return;
+
+ if (controller_ != nil) {
+ DCHECK(controller_ == controller);
+ return;
+ }
+ DCHECK(controller != nil);
+
+ // Remember the controller we're adding ourselves to, so that we can later
+ // remove us from it.
+ controller_ = controller;
+ [controller_ attachConstrainedWindow:this];
+ delegate_->set_sheet_open(true);
+}
diff --git a/chrome/browser/ui/cocoa/content_exceptions_window_controller.h b/chrome/browser/ui/cocoa/content_exceptions_window_controller.h
new file mode 100644
index 0000000..e5ce74f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/content_exceptions_window_controller.h
@@ -0,0 +1,74 @@
+// 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>
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
+#include "chrome/common/content_settings_types.h"
+
+class ContentExceptionsTableModel;
+class ContentSettingComboModel;
+class UpdatingContentSettingsObserver;
+
+// Controller for the content exception dialogs.
+@interface ContentExceptionsWindowController : NSWindowController
+ <NSWindowDelegate,
+ NSTableViewDataSource,
+ NSTableViewDelegate> {
+ @private
+ IBOutlet NSTableView* tableView_;
+ IBOutlet NSButton* addButton_;
+ IBOutlet NSButton* removeButton_;
+ IBOutlet NSButton* removeAllButton_;
+ IBOutlet NSButton* doneButton_;
+
+ ContentSettingsType settingsType_;
+ HostContentSettingsMap* settingsMap_; // weak
+ HostContentSettingsMap* otrSettingsMap_; // weak
+ scoped_ptr<ContentExceptionsTableModel> model_;
+ scoped_ptr<ContentSettingComboModel> popup_model_;
+
+ // Is set if adding and editing exceptions for the current OTR session should
+ // be allowed.
+ BOOL otrAllowed_;
+
+ // Listens for changes to the content settings and reloads the data when they
+ // change. See comment in -modelDidChange in the mm file for details.
+ scoped_ptr<UpdatingContentSettingsObserver> tableObserver_;
+
+ // If this is set to NO, notifications by |tableObserver_| are ignored. This
+ // is used to suppress updates at bad times.
+ BOOL updatesEnabled_;
+
+ // This is non-NULL only while a new element is being added and its pattern
+ // is being edited.
+ scoped_ptr<HostContentSettingsMap::PatternSettingPair> newException_;
+}
+
+// Returns the content exceptions window controller for |settingsType|.
+// Changes made by the user in the window are persisted in |settingsMap|.
++ (id)controllerForType:(ContentSettingsType)settingsType
+ settingsMap:(HostContentSettingsMap*)settingsMap
+ otrSettingsMap:(HostContentSettingsMap*)otrSettingsMap;
+
+// Shows the exceptions dialog as a modal sheet attached to |window|.
+- (void)attachSheetTo:(NSWindow*)window;
+
+// Sets the minimum width of the sheet and resizes it if necessary.
+- (void)setMinWidth:(CGFloat)minWidth;
+
+- (IBAction)addException:(id)sender;
+- (IBAction)removeException:(id)sender;
+- (IBAction)removeAllExceptions:(id)sender;
+// Closes the sheet and ends the modal loop.
+- (IBAction)closeSheet:(id)sender;
+
+@end
+
+@interface ContentExceptionsWindowController(VisibleForTesting)
+- (void)cancel:(id)sender;
+- (BOOL)editingNewException;
+@end
diff --git a/chrome/browser/ui/cocoa/content_exceptions_window_controller.mm b/chrome/browser/ui/cocoa/content_exceptions_window_controller.mm
new file mode 100644
index 0000000..e9a426f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/content_exceptions_window_controller.mm
@@ -0,0 +1,489 @@
+// 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 "chrome/browser/ui/cocoa/content_exceptions_window_controller.h"
+
+#include "app/l10n_util.h"
+#include "app/l10n_util_mac.h"
+#include "app/table_model_observer.h"
+#include "base/command_line.h"
+#import "base/mac_util.h"
+#import "base/scoped_nsobject.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/content_exceptions_table_model.h"
+#include "chrome/browser/content_setting_combo_model.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_service.h"
+#include "grit/generated_resources.h"
+#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
+
+@interface ContentExceptionsWindowController (Private)
+- (id)initWithType:(ContentSettingsType)settingsType
+ settingsMap:(HostContentSettingsMap*)settingsMap
+ otrSettingsMap:(HostContentSettingsMap*)otrSettingsMap;
+- (void)updateRow:(NSInteger)row
+ withEntry:(const HostContentSettingsMap::PatternSettingPair&)entry
+ forOtr:(BOOL)isOtr;
+- (void)adjustEditingButtons;
+- (void)modelDidChange;
+- (NSString*)titleForIndex:(size_t)index;
+@end
+
+////////////////////////////////////////////////////////////////////////////////
+// PatternFormatter
+
+// A simple formatter that accepts text that vaguely looks like a pattern.
+@interface PatternFormatter : NSFormatter
+@end
+
+@implementation PatternFormatter
+- (NSString*)stringForObjectValue:(id)object {
+ if (![object isKindOfClass:[NSString class]])
+ return nil;
+ return object;
+}
+
+- (BOOL)getObjectValue:(id*)object
+ forString:(NSString*)string
+ errorDescription:(NSString**)error {
+ if ([string length]) {
+ if (ContentSettingsPattern(
+ base::SysNSStringToUTF8(string)).IsValid()) {
+ *object = string;
+ return YES;
+ }
+ }
+ if (error)
+ *error = @"Invalid pattern";
+ return NO;
+}
+
+- (NSAttributedString*)attributedStringForObjectValue:(id)object
+ withDefaultAttributes:(NSDictionary*)attribs {
+ return nil;
+}
+@end
+
+////////////////////////////////////////////////////////////////////////////////
+// UpdatingContentSettingsObserver
+
+// UpdatingContentSettingsObserver is a notification observer that tells a
+// window controller to update its data on every notification.
+class UpdatingContentSettingsObserver : public NotificationObserver {
+ public:
+ UpdatingContentSettingsObserver(ContentExceptionsWindowController* controller)
+ : controller_(controller) {
+ // One would think one could register a TableModelObserver to be notified of
+ // changes to ContentExceptionsTableModel. One would be wrong: The table
+ // model only sends out changes that are made through the model, not for
+ // changes made directly to its backing HostContentSettings object (that
+ // happens e.g. if the user uses the cookie confirmation dialog). Hence,
+ // observe the CONTENT_SETTINGS_CHANGED notification directly.
+ registrar_.Add(this, NotificationType::CONTENT_SETTINGS_CHANGED,
+ NotificationService::AllSources());
+ }
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+ private:
+ NotificationRegistrar registrar_;
+ ContentExceptionsWindowController* controller_;
+};
+
+void UpdatingContentSettingsObserver::Observe(
+ NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ [controller_ modelDidChange];
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Static functions
+
+namespace {
+
+NSString* GetWindowTitle(ContentSettingsType settingsType) {
+ switch (settingsType) {
+ case CONTENT_SETTINGS_TYPE_COOKIES:
+ return l10n_util::GetNSStringWithFixup(IDS_COOKIE_EXCEPTION_TITLE);
+ case CONTENT_SETTINGS_TYPE_IMAGES:
+ return l10n_util::GetNSStringWithFixup(IDS_IMAGES_EXCEPTION_TITLE);
+ case CONTENT_SETTINGS_TYPE_JAVASCRIPT:
+ return l10n_util::GetNSStringWithFixup(IDS_JS_EXCEPTION_TITLE);
+ case CONTENT_SETTINGS_TYPE_PLUGINS:
+ return l10n_util::GetNSStringWithFixup(IDS_PLUGINS_EXCEPTION_TITLE);
+ case CONTENT_SETTINGS_TYPE_POPUPS:
+ return l10n_util::GetNSStringWithFixup(IDS_POPUP_EXCEPTION_TITLE);
+ default:
+ NOTREACHED();
+ }
+ return @"";
+}
+
+const CGFloat kButtonBarHeight = 35.0;
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// ContentExceptionsWindowController implementation
+
+static ContentExceptionsWindowController*
+ g_exceptionWindows[CONTENT_SETTINGS_NUM_TYPES] = { nil };
+
+@implementation ContentExceptionsWindowController
+
++ (id)controllerForType:(ContentSettingsType)settingsType
+ settingsMap:(HostContentSettingsMap*)settingsMap
+ otrSettingsMap:(HostContentSettingsMap*)otrSettingsMap {
+ if (!g_exceptionWindows[settingsType]) {
+ g_exceptionWindows[settingsType] =
+ [[ContentExceptionsWindowController alloc]
+ initWithType:settingsType
+ settingsMap:settingsMap
+ otrSettingsMap:otrSettingsMap];
+ }
+ return g_exceptionWindows[settingsType];
+}
+
+- (id)initWithType:(ContentSettingsType)settingsType
+ settingsMap:(HostContentSettingsMap*)settingsMap
+ otrSettingsMap:(HostContentSettingsMap*)otrSettingsMap {
+ NSString* nibpath =
+ [mac_util::MainAppBundle() pathForResource:@"ContentExceptionsWindow"
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
+ settingsType_ = settingsType;
+ settingsMap_ = settingsMap;
+ otrSettingsMap_ = otrSettingsMap;
+ model_.reset(new ContentExceptionsTableModel(
+ settingsMap_, otrSettingsMap_, settingsType_));
+ popup_model_.reset(new ContentSettingComboModel(settingsType_));
+ otrAllowed_ = otrSettingsMap != NULL;
+ tableObserver_.reset(new UpdatingContentSettingsObserver(self));
+ updatesEnabled_ = YES;
+
+ // TODO(thakis): autoremember window rect.
+ // TODO(thakis): sorting support.
+ }
+ return self;
+}
+
+- (void)awakeFromNib {
+ DCHECK([self window]);
+ DCHECK_EQ(self, [[self window] delegate]);
+ DCHECK(tableView_);
+ DCHECK_EQ(self, [tableView_ dataSource]);
+ DCHECK_EQ(self, [tableView_ delegate]);
+
+ [[self window] setTitle:GetWindowTitle(settingsType_)];
+
+ CGFloat minWidth = [[addButton_ superview] bounds].size.width +
+ [[doneButton_ superview] bounds].size.width;
+ [self setMinWidth:minWidth];
+
+ [self adjustEditingButtons];
+
+ // Initialize menu for the data cell in the "action" column.
+ scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@"exceptionMenu"]);
+ for (int i = 0; i < popup_model_->GetItemCount(); ++i) {
+ NSString* title =
+ l10n_util::FixUpWindowsStyleLabel(popup_model_->GetItemAt(i));
+ scoped_nsobject<NSMenuItem> allowItem(
+ [[NSMenuItem alloc] initWithTitle:title action:NULL keyEquivalent:@""]);
+ [allowItem.get() setTag:popup_model_->SettingForIndex(i)];
+ [menu.get() addItem:allowItem.get()];
+ }
+ NSCell* menuCell =
+ [[tableView_ tableColumnWithIdentifier:@"action"] dataCell];
+ [menuCell setMenu:menu.get()];
+
+ NSCell* patternCell =
+ [[tableView_ tableColumnWithIdentifier:@"pattern"] dataCell];
+ [patternCell setFormatter:[[[PatternFormatter alloc] init] autorelease]];
+
+ if (!otrAllowed_) {
+ [tableView_
+ removeTableColumn:[tableView_ tableColumnWithIdentifier:@"otr"]];
+ }
+}
+
+- (void)setMinWidth:(CGFloat)minWidth {
+ NSWindow* window = [self window];
+ [window setMinSize:NSMakeSize(minWidth, [window minSize].height)];
+ if ([window frame].size.width < minWidth) {
+ NSRect frame = [window frame];
+ frame.size.width = minWidth;
+ [window setFrame:frame display:NO];
+ }
+}
+
+- (void)windowWillClose:(NSNotification*)notification {
+ // Without this, some of the unit tests fail on 10.6:
+ [tableView_ setDataSource:nil];
+
+ g_exceptionWindows[settingsType_] = nil;
+ [self autorelease];
+}
+
+- (BOOL)editingNewException {
+ return newException_.get() != NULL;
+}
+
+// Let esc cancel editing if the user is currently editing a pattern. Else, let
+// esc close the window.
+- (void)cancel:(id)sender {
+ if ([tableView_ currentEditor] != nil) {
+ [tableView_ abortEditing];
+ [[self window] makeFirstResponder:tableView_]; // Re-gain focus.
+
+ if ([tableView_ selectedRow] == model_->RowCount()) {
+ // Cancel addition of new row.
+ [self removeException:self];
+ }
+ } else {
+ [self closeSheet:self];
+ }
+}
+
+- (void)keyDown:(NSEvent*)event {
+ NSString* chars = [event charactersIgnoringModifiers];
+ if ([chars length] == 1) {
+ switch ([chars characterAtIndex:0]) {
+ case NSDeleteCharacter:
+ case NSDeleteFunctionKey:
+ // Delete deletes.
+ if ([[tableView_ selectedRowIndexes] count] > 0)
+ [self removeException:self];
+ return;
+ case NSCarriageReturnCharacter:
+ case NSEnterCharacter:
+ // Return enters rename mode.
+ if ([[tableView_ selectedRowIndexes] count] == 1) {
+ [tableView_ editColumn:0
+ row:[[tableView_ selectedRowIndexes] lastIndex]
+ withEvent:nil
+ select:YES];
+ }
+ return;
+ }
+ }
+ [super keyDown:event];
+}
+
+- (void)attachSheetTo:(NSWindow*)window {
+ [NSApp beginSheet:[self window]
+ modalForWindow:window
+ modalDelegate:self
+ didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
+ contextInfo:nil];
+}
+
+- (void)sheetDidEnd:(NSWindow*)sheet
+ returnCode:(NSInteger)returnCode
+ contextInfo:(void*)context {
+ [sheet close];
+ [sheet orderOut:self];
+}
+
+- (IBAction)addException:(id)sender {
+ if (newException_.get()) {
+ // The invariant is that |newException_| is non-NULL exactly if the pattern
+ // of a new exception is currently being edited - so there's nothing to do
+ // in that case.
+ return;
+ }
+ newException_.reset(new HostContentSettingsMap::PatternSettingPair);
+ newException_->first = ContentSettingsPattern(
+ l10n_util::GetStringUTF8(IDS_EXCEPTIONS_SAMPLE_PATTERN));
+ newException_->second = CONTENT_SETTING_BLOCK;
+ [tableView_ reloadData];
+
+ [self adjustEditingButtons];
+ int index = model_->RowCount();
+ NSIndexSet* selectedSet = [NSIndexSet indexSetWithIndex:index];
+ [tableView_ selectRowIndexes:selectedSet byExtendingSelection:NO];
+ [tableView_ editColumn:0 row:index withEvent:nil select:YES];
+}
+
+- (IBAction)removeException:(id)sender {
+ updatesEnabled_ = NO;
+ NSIndexSet* selection = [tableView_ selectedRowIndexes];
+ [tableView_ deselectAll:self]; // Else we'll get a -setObjectValue: later.
+ DCHECK_GT([selection count], 0U);
+ NSUInteger index = [selection lastIndex];
+ while (index != NSNotFound) {
+ if (index == static_cast<NSUInteger>(model_->RowCount()))
+ newException_.reset();
+ else
+ model_->RemoveException(index);
+ index = [selection indexLessThanIndex:index];
+ }
+ updatesEnabled_ = YES;
+ [self modelDidChange];
+}
+
+- (IBAction)removeAllExceptions:(id)sender {
+ updatesEnabled_ = NO;
+ [tableView_ deselectAll:self]; // Else we'll get a -setObjectValue: later.
+ newException_.reset();
+ model_->RemoveAll();
+ updatesEnabled_ = YES;
+ [self modelDidChange];
+}
+
+- (IBAction)closeSheet:(id)sender {
+ [NSApp endSheet:[self window]];
+}
+
+// Table View Data Source -----------------------------------------------------
+
+- (NSInteger)numberOfRowsInTableView:(NSTableView*)table {
+ return model_->RowCount() + (newException_.get() ? 1 : 0);
+}
+
+- (id)tableView:(NSTableView*)tv
+ objectValueForTableColumn:(NSTableColumn*)tableColumn
+ row:(NSInteger)row {
+ const HostContentSettingsMap::PatternSettingPair* entry;
+ int isOtr;
+ if (newException_.get() && row >= model_->RowCount()) {
+ entry = newException_.get();
+ isOtr = 0;
+ } else {
+ entry = &model_->entry_at(row);
+ isOtr = model_->entry_is_off_the_record(row) ? 1 : 0;
+ }
+
+ NSObject* result = nil;
+ NSString* identifier = [tableColumn identifier];
+ if ([identifier isEqualToString:@"pattern"]) {
+ result = base::SysUTF8ToNSString(entry->first.AsString());
+ } else if ([identifier isEqualToString:@"action"]) {
+ result =
+ [NSNumber numberWithInt:popup_model_->IndexForSetting(entry->second)];
+ } else if ([identifier isEqualToString:@"otr"]) {
+ result = [NSNumber numberWithInt:isOtr];
+ } else {
+ NOTREACHED();
+ }
+ return result;
+}
+
+// Updates exception at |row| to contain the data in |entry|.
+- (void)updateRow:(NSInteger)row
+ withEntry:(const HostContentSettingsMap::PatternSettingPair&)entry
+ forOtr:(BOOL)isOtr {
+ // TODO(thakis): This apparently moves an edited row to the back of the list.
+ // It's what windows and linux do, but it's kinda sucky. Fix.
+ // http://crbug.com/36904
+ updatesEnabled_ = NO;
+ if (row < model_->RowCount())
+ model_->RemoveException(row);
+ model_->AddException(entry.first, entry.second, isOtr);
+ updatesEnabled_ = YES;
+ [self modelDidChange];
+
+ // For now, at least re-select the edited element.
+ int newIndex = model_->IndexOfExceptionByPattern(entry.first, isOtr);
+ DCHECK(newIndex != -1);
+ [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:newIndex]
+ byExtendingSelection:NO];
+}
+
+- (void) tableView:(NSTableView*)tv
+ setObjectValue:(id)object
+ forTableColumn:(NSTableColumn*)tableColumn
+ row:(NSInteger)row {
+ // -remove: and -removeAll: both call |tableView_|'s -deselectAll:, which
+ // calls this method if a cell is currently being edited. Do not commit edits
+ // of rows that are about to be deleted.
+ if (!updatesEnabled_) {
+ // If this method gets called, the pattern filed of the new exception can no
+ // longer be being edited. Reset |newException_| to keep the invariant true.
+ newException_.reset();
+ return;
+ }
+
+ // Get model object.
+ bool isNewRow = newException_.get() && row >= model_->RowCount();
+ HostContentSettingsMap::PatternSettingPair originalEntry =
+ isNewRow ? *newException_ : model_->entry_at(row);
+ HostContentSettingsMap::PatternSettingPair entry = originalEntry;
+ bool isOtr =
+ isNewRow ? 0 : model_->entry_is_off_the_record(row);
+ bool wasOtr = isOtr;
+
+ // Modify it.
+ NSString* identifier = [tableColumn identifier];
+ if ([identifier isEqualToString:@"pattern"]) {
+ entry.first = ContentSettingsPattern(base::SysNSStringToUTF8(object));
+ }
+ if ([identifier isEqualToString:@"action"]) {
+ int index = [object intValue];
+ entry.second = popup_model_->SettingForIndex(index);
+ }
+ if ([identifier isEqualToString:@"otr"]) {
+ isOtr = [object intValue] != 0;
+ }
+
+ // Commit modification, if any.
+ if (isNewRow) {
+ newException_.reset();
+ if (![identifier isEqualToString:@"pattern"]) {
+ [tableView_ reloadData];
+ [self adjustEditingButtons];
+ return; // Commit new rows only when the pattern has been set.
+ }
+ int newIndex = model_->IndexOfExceptionByPattern(entry.first, false);
+ if (newIndex != -1) {
+ // The new pattern was already in the table. Focus existing row instead of
+ // overwriting it with a new one.
+ [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:newIndex]
+ byExtendingSelection:NO];
+ [tableView_ reloadData];
+ [self adjustEditingButtons];
+ return;
+ }
+ }
+ if (entry != originalEntry || wasOtr != isOtr || isNewRow)
+ [self updateRow:row withEntry:entry forOtr:isOtr];
+}
+
+
+// Table View Delegate --------------------------------------------------------
+
+// When the selection in the table view changes, we need to adjust buttons.
+- (void)tableViewSelectionDidChange:(NSNotification*)notification {
+ [self adjustEditingButtons];
+}
+
+// Private --------------------------------------------------------------------
+
+// This method appropriately sets the enabled states on the table's editing
+// buttons.
+- (void)adjustEditingButtons {
+ NSIndexSet* selection = [tableView_ selectedRowIndexes];
+ [removeButton_ setEnabled:([selection count] > 0)];
+ [removeAllButton_ setEnabled:([tableView_ numberOfRows] > 0)];
+}
+
+- (void)modelDidChange {
+ // Some calls on |model_|, e.g. RemoveException(), change something on the
+ // backing content settings map object (which sends a notification) and then
+ // change more stuff in |model_|. If |model_| is deleted when the notification
+ // is sent, this second access causes a segmentation violation. Hence, disable
+ // resetting |model_| while updates can be in progress.
+ if (!updatesEnabled_)
+ return;
+
+ // The model caches its data, meaning we need to recreate it on every change.
+ model_.reset(new ContentExceptionsTableModel(
+ settingsMap_, otrSettingsMap_, settingsType_));
+
+ [tableView_ reloadData];
+ [self adjustEditingButtons];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/content_exceptions_window_controller_unittest.mm b/chrome/browser/ui/cocoa/content_exceptions_window_controller_unittest.mm
new file mode 100644
index 0000000..d42e171
--- /dev/null
+++ b/chrome/browser/ui/cocoa/content_exceptions_window_controller_unittest.mm
@@ -0,0 +1,252 @@
+// 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 "chrome/browser/ui/cocoa/content_exceptions_window_controller.h"
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/scoped_nsobject.h"
+#include "base/ref_counted.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+void ProcessEvents() {
+ for (;;) {
+ base::mac::ScopedNSAutoreleasePool pool;
+ NSEvent* next_event = [NSApp nextEventMatchingMask:NSAnyEventMask
+ untilDate:nil
+ inMode:NSDefaultRunLoopMode
+ dequeue:YES];
+ if (!next_event)
+ break;
+ [NSApp sendEvent:next_event];
+ }
+}
+
+void SendKeyEvents(NSString* characters) {
+ for (NSUInteger i = 0; i < [characters length]; ++i) {
+ unichar character = [characters characterAtIndex:i];
+ NSString* charString = [NSString stringWithCharacters:&character length:1];
+ NSEvent* event = [NSEvent keyEventWithType:NSKeyDown
+ location:NSZeroPoint
+ modifierFlags:0
+ timestamp:0.0
+ windowNumber:0
+ context:nil
+ characters:charString
+ charactersIgnoringModifiers:charString
+ isARepeat:NO
+ keyCode:0];
+ [NSApp sendEvent:event];
+ }
+}
+
+class ContentExceptionsWindowControllerTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ TestingProfile* profile = browser_helper_.profile();
+ settingsMap_ = new HostContentSettingsMap(profile);
+ }
+
+ ContentExceptionsWindowController* GetController(ContentSettingsType type) {
+ id controller = [ContentExceptionsWindowController
+ controllerForType:type
+ settingsMap:settingsMap_.get()
+ otrSettingsMap:NULL];
+ [controller showWindow:nil];
+ return controller;
+ }
+
+ void ClickAdd(ContentExceptionsWindowController* controller) {
+ [controller addException:nil];
+ ProcessEvents();
+ }
+
+ void ClickRemove(ContentExceptionsWindowController* controller) {
+ [controller removeException:nil];
+ ProcessEvents();
+ }
+
+ void ClickRemoveAll(ContentExceptionsWindowController* controller) {
+ [controller removeAllExceptions:nil];
+ ProcessEvents();
+ }
+
+ void EnterText(NSString* str) {
+ SendKeyEvents(str);
+ ProcessEvents();
+ }
+
+ void HitEscape(ContentExceptionsWindowController* controller) {
+ [controller cancel:nil];
+ ProcessEvents();
+ }
+
+ protected:
+ BrowserTestHelper browser_helper_;
+ scoped_refptr<HostContentSettingsMap> settingsMap_;
+};
+
+TEST_F(ContentExceptionsWindowControllerTest, Construction) {
+ ContentExceptionsWindowController* controller =
+ [ContentExceptionsWindowController
+ controllerForType:CONTENT_SETTINGS_TYPE_PLUGINS
+ settingsMap:settingsMap_.get()
+ otrSettingsMap:NULL];
+ [controller showWindow:nil];
+ [controller close]; // Should autorelease.
+}
+
+// Regression test for http://crbug.com/37137
+TEST_F(ContentExceptionsWindowControllerTest, AddRemove) {
+ ContentExceptionsWindowController* controller =
+ GetController(CONTENT_SETTINGS_TYPE_PLUGINS);
+
+ HostContentSettingsMap::SettingsForOneType settings;
+
+ ClickAdd(controller);
+ settingsMap_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
+ "",
+ &settings);
+ EXPECT_EQ(0u, settings.size());
+
+ ClickRemove(controller);
+
+ EXPECT_FALSE([controller editingNewException]);
+ [controller close];
+
+ settingsMap_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
+ "",
+ &settings);
+ EXPECT_EQ(0u, settings.size());
+}
+
+// Regression test for http://crbug.com/37137
+TEST_F(ContentExceptionsWindowControllerTest, AddRemoveAll) {
+ ContentExceptionsWindowController* controller =
+ GetController(CONTENT_SETTINGS_TYPE_PLUGINS);
+
+ ClickAdd(controller);
+ ClickRemoveAll(controller);
+
+ EXPECT_FALSE([controller editingNewException]);
+ [controller close];
+
+ HostContentSettingsMap::SettingsForOneType settings;
+ settingsMap_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
+ "",
+ &settings);
+ EXPECT_EQ(0u, settings.size());
+}
+
+TEST_F(ContentExceptionsWindowControllerTest, Add) {
+ ContentExceptionsWindowController* controller =
+ GetController(CONTENT_SETTINGS_TYPE_PLUGINS);
+
+ ClickAdd(controller);
+ EnterText(@"addedhost\n");
+
+ EXPECT_FALSE([controller editingNewException]);
+ [controller close];
+
+ HostContentSettingsMap::SettingsForOneType settings;
+ settingsMap_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
+ "",
+ &settings);
+ EXPECT_EQ(1u, settings.size());
+ EXPECT_EQ(ContentSettingsPattern("addedhost"), settings[0].first);
+}
+
+TEST_F(ContentExceptionsWindowControllerTest, AddEscDoesNotAdd) {
+ ContentExceptionsWindowController* controller =
+ GetController(CONTENT_SETTINGS_TYPE_PLUGINS);
+
+ ClickAdd(controller);
+ EnterText(@"addedhost"); // but do not press enter
+ HitEscape(controller);
+
+ HostContentSettingsMap::SettingsForOneType settings;
+ settingsMap_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
+ "",
+ &settings);
+ EXPECT_EQ(0u, settings.size());
+ EXPECT_FALSE([controller editingNewException]);
+
+ [controller close];
+}
+
+// Regression test for http://crbug.com/37208
+TEST_F(ContentExceptionsWindowControllerTest, AddEditAddAdd) {
+ ContentExceptionsWindowController* controller =
+ GetController(CONTENT_SETTINGS_TYPE_PLUGINS);
+
+ ClickAdd(controller);
+ EnterText(@"testtesttest"); // but do not press enter
+ ClickAdd(controller);
+ ClickAdd(controller);
+
+ EXPECT_TRUE([controller editingNewException]);
+ [controller close];
+
+ HostContentSettingsMap::SettingsForOneType settings;
+ settingsMap_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
+ "",
+ &settings);
+ EXPECT_EQ(0u, settings.size());
+}
+
+TEST_F(ContentExceptionsWindowControllerTest, AddExistingEditAdd) {
+ settingsMap_->SetContentSetting(ContentSettingsPattern("myhost"),
+ CONTENT_SETTINGS_TYPE_PLUGINS,
+ "",
+ CONTENT_SETTING_BLOCK);
+
+ ContentExceptionsWindowController* controller =
+ GetController(CONTENT_SETTINGS_TYPE_PLUGINS);
+
+ ClickAdd(controller);
+ EnterText(@"myhost"); // but do not press enter
+ ClickAdd(controller);
+
+ EXPECT_TRUE([controller editingNewException]);
+ [controller close];
+
+
+ HostContentSettingsMap::SettingsForOneType settings;
+ settingsMap_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PLUGINS,
+ "",
+ &settings);
+ EXPECT_EQ(1u, settings.size());
+}
+
+TEST_F(ContentExceptionsWindowControllerTest, AddExistingDoesNotOverwrite) {
+ settingsMap_->SetContentSetting(ContentSettingsPattern("myhost"),
+ CONTENT_SETTINGS_TYPE_COOKIES,
+ "",
+ CONTENT_SETTING_SESSION_ONLY);
+
+ ContentExceptionsWindowController* controller =
+ GetController(CONTENT_SETTINGS_TYPE_COOKIES);
+
+ ClickAdd(controller);
+ EnterText(@"myhost\n");
+
+ EXPECT_FALSE([controller editingNewException]);
+ [controller close];
+
+ HostContentSettingsMap::SettingsForOneType settings;
+ settingsMap_->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_COOKIES,
+ "",
+ &settings);
+ EXPECT_EQ(1u, settings.size());
+ EXPECT_EQ(CONTENT_SETTING_SESSION_ONLY, settings[0].second);
+}
+
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/content_setting_bubble_cocoa.h b/chrome/browser/ui/cocoa/content_setting_bubble_cocoa.h
new file mode 100644
index 0000000..362f3ea
--- /dev/null
+++ b/chrome/browser/ui/cocoa/content_setting_bubble_cocoa.h
@@ -0,0 +1,67 @@
+// 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.
+
+#include <map>
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+#import "chrome/browser/ui/cocoa/base_bubble_controller.h"
+
+class ContentSettingBubbleModel;
+@class InfoBubbleView;
+
+namespace content_setting_bubble {
+// For every "show popup" button, remember the index of the popup tab contents
+// it should open when clicked.
+typedef std::map<NSButton*, int> PopupLinks;
+}
+
+// Manages a "content blocked" bubble.
+@interface ContentSettingBubbleController : BaseBubbleController {
+ @private
+ IBOutlet NSTextField* titleLabel_;
+ IBOutlet NSMatrix* allowBlockRadioGroup_;
+
+ IBOutlet NSButton* manageButton_;
+ IBOutlet NSButton* doneButton_;
+ IBOutlet NSButton* loadAllPluginsButton_;
+
+ // The container for the bubble contents of the geolocation bubble.
+ IBOutlet NSView* contentsContainer_;
+
+ // The info button of the cookies bubble.
+ IBOutlet NSButton* infoButton_;
+
+ IBOutlet NSTextField* blockedResourcesField_;
+
+ scoped_ptr<ContentSettingBubbleModel> contentSettingBubbleModel_;
+ content_setting_bubble::PopupLinks popupLinks_;
+}
+
+// Creates and shows a content blocked bubble. Takes ownership of
+// |contentSettingBubbleModel| but not of the other objects.
++ (ContentSettingBubbleController*)
+ showForModel:(ContentSettingBubbleModel*)contentSettingBubbleModel
+ parentWindow:(NSWindow*)parentWindow
+ anchoredAt:(NSPoint)anchoredAt;
+
+// Callback for the "don't block / continue blocking" radio group.
+- (IBAction)allowBlockToggled:(id)sender;
+
+// Callback for "close" button.
+- (IBAction)closeBubble:(id)sender;
+
+// Callback for "manage" button.
+- (IBAction)manageBlocking:(id)sender;
+
+// Callback for "info" link.
+- (IBAction)showMoreInfo:(id)sender;
+
+// Callback for "load all plugins" button.
+- (IBAction)loadAllPlugins:(id)sender;
+
+@end
diff --git a/chrome/browser/ui/cocoa/content_setting_bubble_cocoa.mm b/chrome/browser/ui/cocoa/content_setting_bubble_cocoa.mm
new file mode 100644
index 0000000..d59a05e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/content_setting_bubble_cocoa.mm
@@ -0,0 +1,490 @@
+// 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 "chrome/browser/ui/cocoa/content_setting_bubble_cocoa.h"
+
+#include "app/l10n_util.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/blocked_content_container.h"
+#include "chrome/browser/content_setting_bubble_model.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
+#include "chrome/browser/plugin_updater.h"
+#import "chrome/browser/ui/cocoa/content_settings_dialog_controller.h"
+#import "chrome/browser/ui/cocoa/hyperlink_button_cell.h"
+#import "chrome/browser/ui/cocoa/info_bubble_view.h"
+#import "chrome/browser/ui/cocoa/l10n_util.h"
+#include "chrome/common/chrome_switches.h"
+#include "grit/generated_resources.h"
+#include "skia/ext/skia_utils_mac.h"
+#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
+#include "webkit/glue/plugins/plugin_list.h"
+
+namespace {
+
+// Must match the tag of the unblock radio button in the xib files.
+const int kAllowTag = 1;
+
+// Must match the tag of the block radio button in the xib files.
+const int kBlockTag = 2;
+
+// Height of one link in the popup list.
+const int kLinkHeight = 16;
+
+// Space between two popup links.
+const int kLinkPadding = 4;
+
+// Space taken in total by one popup link.
+const int kLinkLineHeight = kLinkHeight + kLinkPadding;
+
+// Space between popup list and surrounding UI elements.
+const int kLinkOuterPadding = 8;
+
+// Height of each of the labels in the geolocation bubble.
+const int kGeoLabelHeight = 14;
+
+// Height of the "Clear" button in the geolocation bubble.
+const int kGeoClearButtonHeight = 17;
+
+// Padding between radio buttons and "Load all plugins" button
+// in the plugin bubble.
+const int kLoadAllPluginsButtonVerticalPadding = 8;
+
+// General padding between elements in the geolocation bubble.
+const int kGeoPadding = 8;
+
+// Padding between host names in the geolocation bubble.
+const int kGeoHostPadding = 4;
+
+// Minimal padding between "Manage" and "Done" buttons.
+const int kManageDonePadding = 8;
+
+void SetControlSize(NSControl* control, NSControlSize controlSize) {
+ CGFloat fontSize = [NSFont systemFontSizeForControlSize:controlSize];
+ NSCell* cell = [control cell];
+ NSFont* font = [NSFont fontWithName:[[cell font] fontName] size:fontSize];
+ [cell setFont:font];
+ [cell setControlSize:controlSize];
+}
+
+// Returns an autoreleased NSTextField that is configured to look like a Label
+// looks in Interface Builder.
+NSTextField* LabelWithFrame(NSString* text, const NSRect& frame) {
+ NSTextField* label = [[NSTextField alloc] initWithFrame:frame];
+ [label setStringValue:text];
+ [label setSelectable:NO];
+ [label setBezeled:NO];
+ return [label autorelease];
+}
+
+} // namespace
+
+@interface ContentSettingBubbleController(Private)
+- (id)initWithModel:(ContentSettingBubbleModel*)settingsBubbleModel
+ parentWindow:(NSWindow*)parentWindow
+ anchoredAt:(NSPoint)anchoredAt;
+- (NSButton*)hyperlinkButtonWithFrame:(NSRect)frame
+ title:(NSString*)title
+ icon:(NSImage*)icon
+ referenceFrame:(NSRect)referenceFrame;
+- (void)initializeBlockedPluginsList;
+- (void)initializeTitle;
+- (void)initializeRadioGroup;
+- (void)initializePopupList;
+- (void)initializeGeoLists;
+- (void)sizeToFitLoadPluginsButton;
+- (void)sizeToFitManageDoneButtons;
+- (void)removeInfoButton;
+- (void)popupLinkClicked:(id)sender;
+- (void)clearGeolocationForCurrentHost:(id)sender;
+@end
+
+@implementation ContentSettingBubbleController
+
++ (ContentSettingBubbleController*)
+ showForModel:(ContentSettingBubbleModel*)contentSettingBubbleModel
+ parentWindow:(NSWindow*)parentWindow
+ anchoredAt:(NSPoint)anchor {
+ // Autoreleases itself on bubble close.
+ return [[ContentSettingBubbleController alloc]
+ initWithModel:contentSettingBubbleModel
+ parentWindow:parentWindow
+ anchoredAt:anchor];
+}
+
+- (id)initWithModel:(ContentSettingBubbleModel*)contentSettingBubbleModel
+ parentWindow:(NSWindow*)parentWindow
+ anchoredAt:(NSPoint)anchoredAt {
+ // This method takes ownership of |contentSettingBubbleModel| in all cases.
+ scoped_ptr<ContentSettingBubbleModel> model(contentSettingBubbleModel);
+ DCHECK(model.get());
+
+ NSString* const nibPaths[] = {
+ @"ContentBlockedCookies",
+ @"ContentBlockedImages",
+ @"ContentBlockedJavaScript",
+ @"ContentBlockedPlugins",
+ @"ContentBlockedPopups",
+ @"ContentBubbleGeolocation",
+ @"", // Notifications do not have a bubble.
+ };
+ COMPILE_ASSERT(arraysize(nibPaths) == CONTENT_SETTINGS_NUM_TYPES,
+ nibPaths_requires_an_entry_for_every_setting_type);
+ const int settingsType = model->content_type();
+ // Nofifications do not have a bubble.
+ CHECK_NE(settingsType, CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
+ DCHECK_LT(settingsType, CONTENT_SETTINGS_NUM_TYPES);
+ if ((self = [super initWithWindowNibPath:nibPaths[settingsType]
+ parentWindow:parentWindow
+ anchoredAt:anchoredAt])) {
+ contentSettingBubbleModel_.reset(model.release());
+ [self showWindow:nil];
+ }
+ return self;
+}
+
+- (void)initializeTitle {
+ if (!titleLabel_)
+ return;
+
+ NSString* label = base::SysUTF8ToNSString(
+ contentSettingBubbleModel_->bubble_content().title);
+ [titleLabel_ setStringValue:label];
+
+ // Layout title post-localization.
+ CGFloat deltaY = [GTMUILocalizerAndLayoutTweaker
+ sizeToFitFixedWidthTextField:titleLabel_];
+ NSRect windowFrame = [[self window] frame];
+ windowFrame.size.height += deltaY;
+ [[self window] setFrame:windowFrame display:NO];
+ NSRect titleFrame = [titleLabel_ frame];
+ titleFrame.origin.y -= deltaY;
+ [titleLabel_ setFrame:titleFrame];
+}
+
+- (void)initializeRadioGroup {
+ // Configure the radio group. For now, only deal with the
+ // strictly needed case of group containing 2 radio buttons.
+ const ContentSettingBubbleModel::RadioGroup& radio_group =
+ contentSettingBubbleModel_->bubble_content().radio_group;
+
+ // Select appropriate radio button.
+ [allowBlockRadioGroup_ selectCellWithTag:
+ radio_group.default_item == 0 ? kAllowTag : kBlockTag];
+
+ const ContentSettingBubbleModel::RadioItems& radio_items =
+ radio_group.radio_items;
+ DCHECK_EQ(2u, radio_items.size()) << "Only 2 radio items per group supported";
+ // Set radio group labels from model.
+ NSCell* radioCell = [allowBlockRadioGroup_ cellWithTag:kAllowTag];
+ [radioCell setTitle:base::SysUTF8ToNSString(radio_items[0])];
+
+ radioCell = [allowBlockRadioGroup_ cellWithTag:kBlockTag];
+ [radioCell setTitle:base::SysUTF8ToNSString(radio_items[1])];
+
+ // Layout radio group labels post-localization.
+ [GTMUILocalizerAndLayoutTweaker
+ wrapRadioGroupForWidth:allowBlockRadioGroup_];
+ CGFloat radioDeltaY = [GTMUILocalizerAndLayoutTweaker
+ sizeToFitView:allowBlockRadioGroup_].height;
+ NSRect windowFrame = [[self window] frame];
+ windowFrame.size.height += radioDeltaY;
+ [[self window] setFrame:windowFrame display:NO];
+}
+
+- (NSButton*)hyperlinkButtonWithFrame:(NSRect)frame
+ title:(NSString*)title
+ icon:(NSImage*)icon
+ referenceFrame:(NSRect)referenceFrame {
+ scoped_nsobject<HyperlinkButtonCell> cell([[HyperlinkButtonCell alloc]
+ initTextCell:title]);
+ [cell.get() setAlignment:NSNaturalTextAlignment];
+ if (icon) {
+ [cell.get() setImagePosition:NSImageLeft];
+ [cell.get() setImage:icon];
+ } else {
+ [cell.get() setImagePosition:NSNoImage];
+ }
+ [cell.get() setControlSize:NSSmallControlSize];
+
+ NSButton* button = [[[NSButton alloc] initWithFrame:frame] autorelease];
+ // Cell must be set immediately after construction.
+ [button setCell:cell.get()];
+
+ // If the link text is too long, clamp it.
+ [button sizeToFit];
+ int maxWidth = NSWidth([[self bubble] frame]) - 2 * NSMinX(referenceFrame);
+ NSRect buttonFrame = [button frame];
+ if (NSWidth(buttonFrame) > maxWidth) {
+ buttonFrame.size.width = maxWidth;
+ [button setFrame:buttonFrame];
+ }
+
+ [button setTarget:self];
+ [button setAction:@selector(popupLinkClicked:)];
+ return button;
+}
+
+- (void)initializeBlockedPluginsList {
+ NSMutableArray* pluginArray = [NSMutableArray array];
+ const std::set<std::string>& plugins =
+ contentSettingBubbleModel_->bubble_content().resource_identifiers;
+ if (plugins.empty()) {
+ int delta = NSMinY([titleLabel_ frame]) -
+ NSMinY([blockedResourcesField_ frame]);
+ [blockedResourcesField_ removeFromSuperview];
+ NSRect frame = [[self window] frame];
+ frame.size.height -= delta;
+ [[self window] setFrame:frame display:NO];
+ } else {
+ for (std::set<std::string>::iterator it = plugins.begin();
+ it != plugins.end(); ++it) {
+ NSString* name = SysUTF16ToNSString(
+ NPAPI::PluginList::Singleton()->GetPluginGroupName(*it));
+ if ([name length] == 0)
+ name = base::SysUTF8ToNSString(*it);
+ [pluginArray addObject:name];
+ }
+ [blockedResourcesField_
+ setStringValue:[pluginArray componentsJoinedByString:@"\n"]];
+ [GTMUILocalizerAndLayoutTweaker
+ sizeToFitFixedWidthTextField:blockedResourcesField_];
+ }
+}
+
+- (void)initializePopupList {
+ // I didn't put the buttons into a NSMatrix because then they are only one
+ // entity in the key view loop. This way, one can tab through all of them.
+ const ContentSettingBubbleModel::PopupItems& popupItems =
+ contentSettingBubbleModel_->bubble_content().popup_items;
+
+ // Get the pre-resize frame of the radio group. Its origin is where the
+ // popup list should go.
+ NSRect radioFrame = [allowBlockRadioGroup_ frame];
+
+ // Make room for the popup list. The bubble view and its subviews autosize
+ // themselves when the window is enlarged.
+ // Heading and radio box are already 1 * kLinkOuterPadding apart in the nib,
+ // so only 1 * kLinkOuterPadding more is needed.
+ int delta = popupItems.size() * kLinkLineHeight - kLinkPadding +
+ kLinkOuterPadding;
+ NSSize deltaSize = NSMakeSize(0, delta);
+ deltaSize = [[[self window] contentView] convertSize:deltaSize toView:nil];
+ NSRect windowFrame = [[self window] frame];
+ windowFrame.size.height += deltaSize.height;
+ [[self window] setFrame:windowFrame display:NO];
+
+ // Create popup list.
+ int topLinkY = NSMaxY(radioFrame) + delta - kLinkHeight;
+ int row = 0;
+ for (std::vector<ContentSettingBubbleModel::PopupItem>::const_iterator
+ it(popupItems.begin()); it != popupItems.end(); ++it, ++row) {
+ const SkBitmap& icon = it->bitmap;
+ NSImage* image = nil;
+ if (!icon.empty())
+ image = gfx::SkBitmapToNSImage(icon);
+
+ std::string title(it->title);
+ // The popup may not have committed a load yet, in which case it won't
+ // have a URL or title.
+ if (title.empty())
+ title = l10n_util::GetStringUTF8(IDS_TAB_LOADING_TITLE);
+
+ NSRect linkFrame =
+ NSMakeRect(NSMinX(radioFrame), topLinkY - kLinkLineHeight * row,
+ 200, kLinkHeight);
+ NSButton* button = [self
+ hyperlinkButtonWithFrame:linkFrame
+ title:base::SysUTF8ToNSString(title)
+ icon:image
+ referenceFrame:radioFrame];
+ [[self bubble] addSubview:button];
+ popupLinks_[button] = row;
+ }
+}
+
+- (void)initializeGeoLists {
+ // Cocoa has its origin in the lower left corner. This means elements are
+ // added from bottom to top, which explains why loops run backwards and the
+ // order of operations is the other way than on Linux/Windows.
+ const ContentSettingBubbleModel::BubbleContent& content =
+ contentSettingBubbleModel_->bubble_content();
+ NSRect containerFrame = [contentsContainer_ frame];
+ NSRect frame = NSMakeRect(0, 0, NSWidth(containerFrame), kGeoLabelHeight);
+
+ // "Clear" button / text field.
+ if (!content.custom_link.empty()) {
+ scoped_nsobject<NSControl> control;
+ if(content.custom_link_enabled) {
+ NSRect buttonFrame = NSMakeRect(0, 0,
+ NSWidth(containerFrame),
+ kGeoClearButtonHeight);
+ NSButton* button = [[NSButton alloc] initWithFrame:buttonFrame];
+ control.reset(button);
+ [button setTitle:base::SysUTF8ToNSString(content.custom_link)];
+ [button setTarget:self];
+ [button setAction:@selector(clearGeolocationForCurrentHost:)];
+ [button setBezelStyle:NSRoundRectBezelStyle];
+ SetControlSize(button, NSSmallControlSize);
+ [button sizeToFit];
+ } else {
+ // Add the notification that settings will be cleared on next reload.
+ control.reset([LabelWithFrame(
+ base::SysUTF8ToNSString(content.custom_link), frame) retain]);
+ SetControlSize(control.get(), NSSmallControlSize);
+ }
+
+ // If the new control is wider than the container, widen the window.
+ CGFloat controlWidth = NSWidth([control frame]);
+ if (controlWidth > NSWidth(containerFrame)) {
+ NSRect windowFrame = [[self window] frame];
+ windowFrame.size.width += controlWidth - NSWidth(containerFrame);
+ [[self window] setFrame:windowFrame display:NO];
+ // Fetch the updated sizes.
+ containerFrame = [contentsContainer_ frame];
+ frame = NSMakeRect(0, 0, NSWidth(containerFrame), kGeoLabelHeight);
+ }
+
+ DCHECK(control);
+ [contentsContainer_ addSubview:control];
+ frame.origin.y = NSMaxY([control frame]) + kGeoPadding;
+ }
+
+ typedef
+ std::vector<ContentSettingBubbleModel::DomainList>::const_reverse_iterator
+ GeolocationGroupIterator;
+ for (GeolocationGroupIterator i = content.domain_lists.rbegin();
+ i != content.domain_lists.rend(); ++i) {
+ // Add all hosts in the current domain list.
+ for (std::set<std::string>::const_reverse_iterator j = i->hosts.rbegin();
+ j != i->hosts.rend(); ++j) {
+ NSTextField* title = LabelWithFrame(base::SysUTF8ToNSString(*j), frame);
+ SetControlSize(title, NSSmallControlSize);
+ [contentsContainer_ addSubview:title];
+
+ frame.origin.y = NSMaxY(frame) + kGeoHostPadding +
+ [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:title];
+ }
+ if (!i->hosts.empty())
+ frame.origin.y += kGeoPadding - kGeoHostPadding;
+
+ // Add the domain list's title.
+ NSTextField* title =
+ LabelWithFrame(base::SysUTF8ToNSString(i->title), frame);
+ SetControlSize(title, NSSmallControlSize);
+ [contentsContainer_ addSubview:title];
+
+ frame.origin.y = NSMaxY(frame) + kGeoPadding +
+ [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:title];
+ }
+
+ CGFloat containerHeight = frame.origin.y;
+ // Undo last padding.
+ if (!content.domain_lists.empty())
+ containerHeight -= kGeoPadding;
+
+ // Resize container to fit its subviews, and window to fit the container.
+ NSRect windowFrame = [[self window] frame];
+ windowFrame.size.height += containerHeight - NSHeight(containerFrame);
+ [[self window] setFrame:windowFrame display:NO];
+ containerFrame.size.height = containerHeight;
+ [contentsContainer_ setFrame:containerFrame];
+}
+
+- (void)sizeToFitLoadPluginsButton {
+ const ContentSettingBubbleModel::BubbleContent& content =
+ contentSettingBubbleModel_->bubble_content();
+ [loadAllPluginsButton_ setEnabled:content.custom_link_enabled];
+
+ // Resize horizontally to fit button if necessary.
+ NSRect windowFrame = [[self window] frame];
+ int widthNeeded = NSWidth([loadAllPluginsButton_ frame]) +
+ 2 * NSMinX([loadAllPluginsButton_ frame]);
+ if (NSWidth(windowFrame) < widthNeeded) {
+ windowFrame.size.width = widthNeeded;
+ [[self window] setFrame:windowFrame display:NO];
+ }
+}
+
+- (void)sizeToFitManageDoneButtons {
+ CGFloat actualWidth = NSWidth([[[self window] contentView] frame]);
+ CGFloat requiredWidth = NSMaxX([manageButton_ frame]) + kManageDonePadding +
+ NSWidth([[doneButton_ superview] frame]) - NSMinX([doneButton_ frame]);
+ if (requiredWidth <= actualWidth || !doneButton_ || !manageButton_)
+ return;
+
+ // Resize window, autoresizing takes care of the rest.
+ NSSize size = NSMakeSize(requiredWidth - actualWidth, 0);
+ size = [[[self window] contentView] convertSize:size toView:nil];
+ NSRect frame = [[self window] frame];
+ frame.origin.x -= size.width;
+ frame.size.width += size.width;
+ [[self window] setFrame:frame display:NO];
+}
+
+- (void)awakeFromNib {
+ [super awakeFromNib];
+
+ [[self bubble] setArrowLocation:info_bubble::kTopRight];
+
+ // Adapt window size to bottom buttons. Do this before all other layouting.
+ [self sizeToFitManageDoneButtons];
+
+ [self initializeTitle];
+
+ ContentSettingsType type = contentSettingBubbleModel_->content_type();
+ if (type == CONTENT_SETTINGS_TYPE_PLUGINS) {
+ [self sizeToFitLoadPluginsButton];
+ [self initializeBlockedPluginsList];
+ }
+ if (allowBlockRadioGroup_) // not bound in cookie bubble xib
+ [self initializeRadioGroup];
+
+ if (type == CONTENT_SETTINGS_TYPE_POPUPS)
+ [self initializePopupList];
+ if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION)
+ [self initializeGeoLists];
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Actual application logic
+
+- (IBAction)allowBlockToggled:(id)sender {
+ NSButtonCell *selectedCell = [sender selectedCell];
+ contentSettingBubbleModel_->OnRadioClicked(
+ [selectedCell tag] == kAllowTag ? 0 : 1);
+}
+
+- (void)popupLinkClicked:(id)sender {
+ content_setting_bubble::PopupLinks::iterator i(popupLinks_.find(sender));
+ DCHECK(i != popupLinks_.end());
+ contentSettingBubbleModel_->OnPopupClicked(i->second);
+}
+
+- (void)clearGeolocationForCurrentHost:(id)sender {
+ contentSettingBubbleModel_->OnCustomLinkClicked();
+ [self close];
+}
+
+- (IBAction)showMoreInfo:(id)sender {
+ contentSettingBubbleModel_->OnCustomLinkClicked();
+ [self close];
+}
+
+- (IBAction)loadAllPlugins:(id)sender {
+ contentSettingBubbleModel_->OnCustomLinkClicked();
+ [self close];
+}
+
+- (IBAction)manageBlocking:(id)sender {
+ contentSettingBubbleModel_->OnManageLinkClicked();
+}
+
+- (IBAction)closeBubble:(id)sender {
+ [self close];
+}
+
+@end // ContentSettingBubbleController
diff --git a/chrome/browser/ui/cocoa/content_setting_bubble_cocoa_unittest.mm b/chrome/browser/ui/cocoa/content_setting_bubble_cocoa_unittest.mm
new file mode 100644
index 0000000..e67b0aa
--- /dev/null
+++ b/chrome/browser/ui/cocoa/content_setting_bubble_cocoa_unittest.mm
@@ -0,0 +1,63 @@
+// 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 "chrome/browser/ui/cocoa/content_setting_bubble_cocoa.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/debug/debugger.h"
+#include "base/scoped_nsobject.h"
+#include "chrome/browser/content_setting_bubble_model.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/common/content_settings_types.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class DummyContentSettingBubbleModel : public ContentSettingBubbleModel {
+ public:
+ DummyContentSettingBubbleModel(ContentSettingsType content_type)
+ : ContentSettingBubbleModel(NULL, NULL, content_type) {
+ RadioGroup radio_group;
+ radio_group.default_item = 0;
+ radio_group.radio_items.resize(2);
+ set_radio_group(radio_group);
+ }
+};
+
+class ContentSettingBubbleControllerTest : public CocoaTest {
+};
+
+// Check that the bubble doesn't crash or leak for any settings type
+TEST_F(ContentSettingBubbleControllerTest, Init) {
+ for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
+ if (i == CONTENT_SETTINGS_TYPE_NOTIFICATIONS)
+ continue; // Notifications have no bubble.
+
+ ContentSettingsType settingsType = static_cast<ContentSettingsType>(i);
+
+ scoped_nsobject<NSWindow> parent([[NSWindow alloc]
+ initWithContentRect:NSMakeRect(0, 0, 800, 600)
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO]);
+ [parent setReleasedWhenClosed:NO];
+ if (base::debug::BeingDebugged())
+ [parent.get() orderFront:nil];
+ else
+ [parent.get() orderBack:nil];
+
+ ContentSettingBubbleController* controller = [ContentSettingBubbleController
+ showForModel:new DummyContentSettingBubbleModel(settingsType)
+ parentWindow:parent
+ anchoredAt:NSMakePoint(50, 20)];
+ EXPECT_TRUE(controller != nil);
+ EXPECT_TRUE([[controller window] isVisible]);
+ [parent.get() close];
+ }
+}
+
+} // namespace
+
+
diff --git a/chrome/browser/ui/cocoa/content_settings_dialog_controller.h b/chrome/browser/ui/cocoa/content_settings_dialog_controller.h
new file mode 100644
index 0000000..4fbd59d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/content_settings_dialog_controller.h
@@ -0,0 +1,102 @@
+// 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>
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_ptr.h"
+#include "chrome/common/content_settings_types.h"
+#include "chrome/browser/prefs/pref_change_registrar.h"
+#include "chrome/browser/prefs/pref_member.h"
+
+// Index of the "enabled" and "disabled" radio group settings in all tabs except
+// the ones below.
+const NSInteger kContentSettingsEnabledIndex = 0;
+const NSInteger kContentSettingsDisabledIndex = 1;
+
+// Indices of the various cookie settings in the cookie radio group.
+const NSInteger kCookieEnabledIndex = 0;
+const NSInteger kCookieDisabledIndex = 1;
+
+// Indices of the various plugin settings in the plugins radio group.
+const NSInteger kPluginsAllowIndex = 0;
+const NSInteger kPluginsAskIndex = 1;
+const NSInteger kPluginsBlockIndex = 2;
+
+// Indices of the various geolocation settings in the geolocation radio group.
+const NSInteger kGeolocationEnabledIndex = 0;
+const NSInteger kGeolocationAskIndex = 1;
+const NSInteger kGeolocationDisabledIndex = 2;
+
+// Indices of the various notifications settings in the geolocation radio group.
+const NSInteger kNotificationsEnabledIndex = 0;
+const NSInteger kNotificationsAskIndex = 1;
+const NSInteger kNotificationsDisabledIndex = 2;
+
+namespace ContentSettingsDialogControllerInternal {
+class PrefObserverBridge;
+}
+
+class Profile;
+@class TabViewPickerTable;
+
+// This controller manages a dialog that lets the user manage the content
+// settings for several content setting types.
+@interface ContentSettingsDialogController
+ : NSWindowController<NSWindowDelegate, NSTabViewDelegate> {
+ @private
+ IBOutlet NSTabView* tabView_;
+ IBOutlet TabViewPickerTable* tabViewPicker_;
+ IBOutlet NSMatrix* pluginDefaultSettingMatrix_;
+ Profile* profile_; // weak
+ IntegerPrefMember lastSelectedTab_;
+ BooleanPrefMember clearSiteDataOnExit_;
+ PrefChangeRegistrar registrar_;
+ scoped_ptr<ContentSettingsDialogControllerInternal::PrefObserverBridge>
+ observer_; // Watches for pref changes.
+}
+
+// Show the content settings dialog associated with the given profile (or the
+// original profile if this is an incognito profile). If no content settings
+// dialog exists for this profile, create one and show it. Any resulting
+// editor releases itself when closed.
++(id)showContentSettingsForType:(ContentSettingsType)settingsType
+ profile:(Profile*)profile;
+
+// Closes an exceptions sheet, if one is attached.
+- (void)closeExceptionsSheet;
+
+- (IBAction)showCookies:(id)sender;
+- (IBAction)openFlashPlayerSettings:(id)sender;
+- (IBAction)openPluginsPage:(id)sender;
+
+- (IBAction)showCookieExceptions:(id)sender;
+- (IBAction)showImagesExceptions:(id)sender;
+- (IBAction)showJavaScriptExceptions:(id)sender;
+- (IBAction)showPluginsExceptions:(id)sender;
+- (IBAction)showPopupsExceptions:(id)sender;
+- (IBAction)showGeolocationExceptions:(id)sender;
+- (IBAction)showNotificationsExceptions:(id)sender;
+
+@end
+
+@interface ContentSettingsDialogController (TestingAPI)
+// Properties that the radio groups and checkboxes are bound to.
+@property(nonatomic) NSInteger cookieSettingIndex;
+@property(nonatomic) BOOL blockThirdPartyCookies;
+@property(nonatomic) BOOL clearSiteDataOnExit;
+@property(nonatomic) NSInteger imagesEnabledIndex;
+@property(nonatomic) NSInteger javaScriptEnabledIndex;
+@property(nonatomic) NSInteger popupsEnabledIndex;
+@property(nonatomic) NSInteger pluginsEnabledIndex;
+@property(nonatomic) NSInteger geolocationSettingIndex;
+@property(nonatomic) NSInteger notificationsSettingIndex;
+
+@property(nonatomic, readonly) BOOL blockThirdPartyCookiesManaged;
+@property(nonatomic, readonly) BOOL cookieSettingsManaged;
+@property(nonatomic, readonly) BOOL imagesSettingsManaged;
+@property(nonatomic, readonly) BOOL javaScriptSettingsManaged;
+@property(nonatomic, readonly) BOOL pluginsSettingsManaged;
+@property(nonatomic, readonly) BOOL popupsSettingsManaged;
+@end
diff --git a/chrome/browser/ui/cocoa/content_settings_dialog_controller.mm b/chrome/browser/ui/cocoa/content_settings_dialog_controller.mm
new file mode 100644
index 0000000..f61c77a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/content_settings_dialog_controller.mm
@@ -0,0 +1,646 @@
+// 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 "chrome/browser/ui/cocoa/content_settings_dialog_controller.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "app/l10n_util.h"
+#include "base/command_line.h"
+#include "base/mac_util.h"
+#import "chrome/browser/content_settings/content_settings_details.h"
+#import "chrome/browser/content_settings/host_content_settings_map.h"
+#import "chrome/browser/geolocation/geolocation_content_settings_map.h"
+#import "chrome/browser/geolocation/geolocation_exceptions_table_model.h"
+#import "chrome/browser/notifications/desktop_notification_service.h"
+#import "chrome/browser/notifications/notification_exceptions_table_model.h"
+#include "chrome/browser/plugin_exceptions_table_model.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
+#import "chrome/browser/ui/cocoa/content_exceptions_window_controller.h"
+#import "chrome/browser/ui/cocoa/cookies_window_controller.h"
+#import "chrome/browser/ui/cocoa/l10n_util.h"
+#import "chrome/browser/ui/cocoa/simple_content_exceptions_window_controller.h"
+#import "chrome/browser/ui/cocoa/tab_view_picker_table.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
+#include "grit/locale_settings.h"
+#include "grit/generated_resources.h"
+
+namespace {
+
+// Stores the currently visible content settings dialog, if any.
+ContentSettingsDialogController* g_instance = nil;
+
+} // namespace
+
+
+@interface ContentSettingsDialogController(Private)
+- (id)initWithProfile:(Profile*)profile;
+- (void)selectTab:(ContentSettingsType)settingsType;
+- (void)showExceptionsForType:(ContentSettingsType)settingsType;
+
+// Callback when preferences are changed. |prefName| is the name of the
+// pref that has changed.
+- (void)prefChanged:(const std::string&)prefName;
+
+// Callback when content settings are changed.
+- (void)contentSettingsChanged:(ContentSettingsDetails*)details;
+
+@end
+
+namespace ContentSettingsDialogControllerInternal {
+
+// A C++ class registered for changes in preferences.
+class PrefObserverBridge : public NotificationObserver {
+ public:
+ PrefObserverBridge(ContentSettingsDialogController* controller)
+ : controller_(controller), disabled_(false) {}
+
+ virtual ~PrefObserverBridge() {}
+
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (disabled_)
+ return;
+
+ // This is currently used by most notifications.
+ if (type == NotificationType::PREF_CHANGED) {
+ std::string* detail = Details<std::string>(details).ptr();
+ if (detail)
+ [controller_ prefChanged:*detail];
+ }
+
+ // This is sent when the "is managed" state changes.
+ // TODO(markusheintz): Move all content settings to this notification.
+ if (type == NotificationType::CONTENT_SETTINGS_CHANGED) {
+ ContentSettingsDetails* settings_details =
+ Details<ContentSettingsDetails>(details).ptr();
+ [controller_ contentSettingsChanged:settings_details];
+ }
+ }
+
+ void SetDisabled(bool disabled) {
+ disabled_ = disabled;
+ }
+
+ private:
+ ContentSettingsDialogController* controller_; // weak, owns us
+ bool disabled_; // true if notifications should be ignored.
+};
+
+// A C++ utility class to disable notifications for PrefsObserverBridge.
+// The intended usage is to create this on the stack.
+class PrefObserverDisabler {
+ public:
+ PrefObserverDisabler(PrefObserverBridge *bridge) : bridge_(bridge) {
+ bridge_->SetDisabled(true);
+ }
+
+ ~PrefObserverDisabler() {
+ bridge_->SetDisabled(false);
+ }
+
+ private:
+ PrefObserverBridge *bridge_;
+};
+
+} // ContentSettingsDialogControllerInternal
+
+@implementation ContentSettingsDialogController
+
++ (id)showContentSettingsForType:(ContentSettingsType)settingsType
+ profile:(Profile*)profile {
+ profile = profile->GetOriginalProfile();
+ if (!g_instance)
+ g_instance = [[self alloc] initWithProfile:profile];
+
+ // The code doesn't expect multiple profiles. Check that support for that
+ // hasn't been added.
+ DCHECK(g_instance->profile_ == profile);
+
+ // Select desired tab.
+ if (settingsType == CONTENT_SETTINGS_TYPE_DEFAULT) {
+ // Remember the last visited page from local state.
+ int value = g_instance->lastSelectedTab_.GetValue();
+ if (value >= 0 && value < CONTENT_SETTINGS_NUM_TYPES)
+ settingsType = static_cast<ContentSettingsType>(value);
+ if (settingsType == CONTENT_SETTINGS_TYPE_DEFAULT)
+ settingsType = CONTENT_SETTINGS_TYPE_COOKIES;
+ }
+ // TODO(thakis): Autosave window pos.
+
+ [g_instance selectTab:settingsType];
+ [g_instance showWindow:nil];
+ [g_instance closeExceptionsSheet];
+ return g_instance;
+}
+
+- (id)initWithProfile:(Profile*)profile {
+ DCHECK(profile);
+ NSString* nibpath =
+ [mac_util::MainAppBundle() pathForResource:@"ContentSettings"
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
+ profile_ = profile;
+
+ observer_.reset(
+ new ContentSettingsDialogControllerInternal::PrefObserverBridge(self));
+ clearSiteDataOnExit_.Init(prefs::kClearSiteDataOnExit,
+ profile_->GetPrefs(), observer_.get());
+
+ // Manually observe notifications for preferences that are grouped in
+ // the HostContentSettingsMap or GeolocationContentSettingsMap.
+ PrefService* prefs = profile_->GetPrefs();
+ registrar_.Init(prefs);
+ registrar_.Add(prefs::kBlockThirdPartyCookies, observer_.get());
+ registrar_.Add(prefs::kBlockNonsandboxedPlugins, observer_.get());
+ registrar_.Add(prefs::kDefaultContentSettings, observer_.get());
+ registrar_.Add(prefs::kGeolocationDefaultContentSetting, observer_.get());
+
+ // We don't need to observe changes in this value.
+ lastSelectedTab_.Init(prefs::kContentSettingsWindowLastTabIndex,
+ profile_->GetPrefs(), NULL);
+ }
+ return self;
+}
+
+- (void)closeExceptionsSheet {
+ NSWindow* attachedSheet = [[self window] attachedSheet];
+ if (attachedSheet) {
+ [NSApp endSheet:attachedSheet];
+ }
+}
+
+- (void)awakeFromNib {
+ DCHECK([self window]);
+ DCHECK(tabView_);
+ DCHECK(tabViewPicker_);
+ DCHECK_EQ(self, [[self window] delegate]);
+
+ // Adapt views to potentially long localized strings.
+ CGFloat windowDelta = 0;
+ for (NSTabViewItem* tab in [tabView_ tabViewItems]) {
+ NSArray* subviews = [[tab view] subviews];
+ windowDelta = MAX(windowDelta,
+ cocoa_l10n_util::VerticallyReflowGroup(subviews));
+
+ for (NSView* view in subviews) {
+ // Since the tab pane is in a horizontal resizer in IB, it's convenient
+ // to give all the subviews flexible width so that their sizes are
+ // autoupdated in IB. However, in chrome, the subviews shouldn't have
+ // flexible widths as this looks weird.
+ [view setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
+ }
+ }
+
+ NSString* label =
+ l10n_util::GetNSStringWithFixup(IDS_CONTENT_SETTINGS_FEATURES_LABEL);
+ label = [label stringByReplacingOccurrencesOfString:@":" withString:@""];
+ [tabViewPicker_ setHeading:label];
+
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableClickToPlay)) {
+ // The |pluginsEnabledIndex| property is bound to the selected *tag*,
+ // so we don't have to worry about index shifts when removing a row
+ // from the matrix.
+ [pluginDefaultSettingMatrix_ removeRow:kPluginsAskIndex];
+ NSArray* siblingViews = [[pluginDefaultSettingMatrix_ superview] subviews];
+ for (NSView* view in siblingViews) {
+ NSRect frame = [view frame];
+ if (frame.origin.y < [pluginDefaultSettingMatrix_ frame].origin.y) {
+ frame.origin.y +=
+ ([pluginDefaultSettingMatrix_ cellSize].height +
+ [pluginDefaultSettingMatrix_ intercellSpacing].height);
+ [view setFrame:frame];
+ }
+ }
+ }
+
+ NSRect frame = [[self window] frame];
+ frame.origin.y -= windowDelta;
+ frame.size.height += windowDelta;
+ [[self window] setFrame:frame display:NO];
+}
+
+// NSWindowDelegate method.
+- (void)windowWillClose:(NSNotification*)notification {
+ [self autorelease];
+ g_instance = nil;
+}
+
+- (void)selectTab:(ContentSettingsType)settingsType {
+ [self window]; // Make sure the nib file is loaded.
+ DCHECK(tabView_);
+ [tabView_ selectTabViewItemAtIndex:settingsType];
+}
+
+// NSTabViewDelegate method.
+- (void) tabView:(NSTabView*)tabView
+ didSelectTabViewItem:(NSTabViewItem*)tabViewItem {
+ DCHECK_EQ(tabView_, tabView);
+ NSInteger index = [tabView indexOfTabViewItem:tabViewItem];
+ DCHECK_GT(index, CONTENT_SETTINGS_TYPE_DEFAULT);
+ DCHECK_LT(index, CONTENT_SETTINGS_NUM_TYPES);
+ if (index > CONTENT_SETTINGS_TYPE_DEFAULT &&
+ index < CONTENT_SETTINGS_NUM_TYPES)
+ lastSelectedTab_.SetValue(index);
+}
+
+// Let esc close the window.
+- (void)cancel:(id)sender {
+ [self close];
+}
+
+- (void)setCookieSettingIndex:(NSInteger)value {
+ ContentSetting setting = CONTENT_SETTING_DEFAULT;
+ switch (value) {
+ case kCookieEnabledIndex: setting = CONTENT_SETTING_ALLOW; break;
+ case kCookieDisabledIndex: setting = CONTENT_SETTING_BLOCK; break;
+ default:
+ NOTREACHED();
+ }
+ ContentSettingsDialogControllerInternal::PrefObserverDisabler
+ disabler(observer_.get());
+ profile_->GetHostContentSettingsMap()->SetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_COOKIES,
+ setting);
+}
+
+- (NSInteger)cookieSettingIndex {
+ switch (profile_->GetHostContentSettingsMap()->GetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_COOKIES)) {
+ case CONTENT_SETTING_ALLOW: return kCookieEnabledIndex;
+ case CONTENT_SETTING_BLOCK: return kCookieDisabledIndex;
+ default:
+ NOTREACHED();
+ return kCookieEnabledIndex;
+ }
+}
+
+- (BOOL)cookieSettingsManaged {
+ return profile_->GetHostContentSettingsMap()->IsDefaultContentSettingManaged(
+ CONTENT_SETTINGS_TYPE_COOKIES);
+}
+
+- (BOOL)blockThirdPartyCookies {
+ HostContentSettingsMap* settingsMap = profile_->GetHostContentSettingsMap();
+ return settingsMap->BlockThirdPartyCookies();
+}
+
+- (void)setBlockThirdPartyCookies:(BOOL)value {
+ HostContentSettingsMap* settingsMap = profile_->GetHostContentSettingsMap();
+ ContentSettingsDialogControllerInternal::PrefObserverDisabler
+ disabler(observer_.get());
+ settingsMap->SetBlockThirdPartyCookies(value);
+}
+
+- (BOOL)blockThirdPartyCookiesManaged {
+ HostContentSettingsMap* settingsMap = profile_->GetHostContentSettingsMap();
+ return settingsMap->IsBlockThirdPartyCookiesManaged();
+}
+
+- (BOOL)clearSiteDataOnExit {
+ return clearSiteDataOnExit_.GetValue();
+}
+
+- (void)setClearSiteDataOnExit:(BOOL)value {
+ ContentSettingsDialogControllerInternal::PrefObserverDisabler
+ disabler(observer_.get());
+ clearSiteDataOnExit_.SetValue(value);
+}
+
+// Shows the cookies controller.
+- (IBAction)showCookies:(id)sender {
+ // The cookie controller will autorelease itself when it's closed.
+ BrowsingDataDatabaseHelper* databaseHelper =
+ new BrowsingDataDatabaseHelper(profile_);
+ BrowsingDataLocalStorageHelper* storageHelper =
+ new BrowsingDataLocalStorageHelper(profile_);
+ BrowsingDataAppCacheHelper* appcacheHelper =
+ new BrowsingDataAppCacheHelper(profile_);
+ BrowsingDataIndexedDBHelper* indexedDBHelper =
+ BrowsingDataIndexedDBHelper::Create(profile_);
+ CookiesWindowController* controller =
+ [[CookiesWindowController alloc] initWithProfile:profile_
+ databaseHelper:databaseHelper
+ storageHelper:storageHelper
+ appcacheHelper:appcacheHelper
+ indexedDBHelper:indexedDBHelper];
+ [controller attachSheetTo:[self window]];
+}
+
+// Called when the user clicks the "Flash Player storage settings" button.
+- (IBAction)openFlashPlayerSettings:(id)sender {
+ Browser* browser = Browser::Create(profile_);
+ browser->OpenURL(GURL(l10n_util::GetStringUTF8(IDS_FLASH_STORAGE_URL)),
+ GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
+ browser->window()->Show();
+}
+
+// Called when the user clicks the "Disable individual plug-ins..." button.
+- (IBAction)openPluginsPage:(id)sender {
+ Browser* browser = Browser::Create(profile_);
+ browser->OpenURL(GURL(chrome::kChromeUIPluginsURL),
+ GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
+ browser->window()->Show();
+}
+
+- (IBAction)showCookieExceptions:(id)sender {
+ [self showExceptionsForType:CONTENT_SETTINGS_TYPE_COOKIES];
+}
+
+- (IBAction)showImagesExceptions:(id)sender {
+ [self showExceptionsForType:CONTENT_SETTINGS_TYPE_IMAGES];
+}
+
+- (IBAction)showJavaScriptExceptions:(id)sender {
+ [self showExceptionsForType:CONTENT_SETTINGS_TYPE_JAVASCRIPT];
+}
+
+- (IBAction)showPluginsExceptions:(id)sender {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableResourceContentSettings)) {
+ HostContentSettingsMap* settingsMap = profile_->GetHostContentSettingsMap();
+ HostContentSettingsMap* offTheRecordSettingsMap =
+ profile_->HasOffTheRecordProfile() ?
+ profile_->GetOffTheRecordProfile()->GetHostContentSettingsMap() :
+ NULL;
+ PluginExceptionsTableModel* model =
+ new PluginExceptionsTableModel(settingsMap, offTheRecordSettingsMap);
+ model->LoadSettings();
+ [[SimpleContentExceptionsWindowController controllerWithTableModel:model]
+ attachSheetTo:[self window]];
+ } else {
+ [self showExceptionsForType:CONTENT_SETTINGS_TYPE_PLUGINS];
+ }
+}
+
+- (IBAction)showPopupsExceptions:(id)sender {
+ [self showExceptionsForType:CONTENT_SETTINGS_TYPE_POPUPS];
+}
+
+- (IBAction)showGeolocationExceptions:(id)sender {
+ GeolocationContentSettingsMap* settingsMap =
+ profile_->GetGeolocationContentSettingsMap();
+ GeolocationExceptionsTableModel* model = // Freed by window controller.
+ new GeolocationExceptionsTableModel(settingsMap);
+ [[SimpleContentExceptionsWindowController controllerWithTableModel:model]
+ attachSheetTo:[self window]];
+}
+
+- (IBAction)showNotificationsExceptions:(id)sender {
+ DesktopNotificationService* service =
+ profile_->GetDesktopNotificationService();
+ NotificationExceptionsTableModel* model = // Freed by window controller.
+ new NotificationExceptionsTableModel(service);
+ [[SimpleContentExceptionsWindowController controllerWithTableModel:model]
+ attachSheetTo:[self window]];
+}
+
+- (void)showExceptionsForType:(ContentSettingsType)settingsType {
+ HostContentSettingsMap* settingsMap = profile_->GetHostContentSettingsMap();
+ HostContentSettingsMap* offTheRecordSettingsMap =
+ profile_->HasOffTheRecordProfile() ?
+ profile_->GetOffTheRecordProfile()->GetHostContentSettingsMap() :
+ NULL;
+ [[ContentExceptionsWindowController controllerForType:settingsType
+ settingsMap:settingsMap
+ otrSettingsMap:offTheRecordSettingsMap]
+ attachSheetTo:[self window]];
+}
+
+- (void)setImagesEnabledIndex:(NSInteger)value {
+ ContentSetting setting = value == kContentSettingsEnabledIndex ?
+ CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK;
+ ContentSettingsDialogControllerInternal::PrefObserverDisabler
+ disabler(observer_.get());
+ profile_->GetHostContentSettingsMap()->SetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_IMAGES, setting);
+}
+
+- (NSInteger)imagesEnabledIndex {
+ HostContentSettingsMap* settingsMap = profile_->GetHostContentSettingsMap();
+ bool enabled =
+ settingsMap->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_IMAGES) ==
+ CONTENT_SETTING_ALLOW;
+ return enabled ? kContentSettingsEnabledIndex : kContentSettingsDisabledIndex;
+}
+
+- (BOOL)imagesSettingsManaged {
+ return profile_->GetHostContentSettingsMap()->IsDefaultContentSettingManaged(
+ CONTENT_SETTINGS_TYPE_IMAGES);
+}
+
+- (void)setJavaScriptEnabledIndex:(NSInteger)value {
+ ContentSetting setting = value == kContentSettingsEnabledIndex ?
+ CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK;
+ ContentSettingsDialogControllerInternal::PrefObserverDisabler
+ disabler(observer_.get());
+ profile_->GetHostContentSettingsMap()->SetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_JAVASCRIPT, setting);
+}
+
+- (NSInteger)javaScriptEnabledIndex {
+ HostContentSettingsMap* settingsMap = profile_->GetHostContentSettingsMap();
+ bool enabled =
+ settingsMap->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_JAVASCRIPT) ==
+ CONTENT_SETTING_ALLOW;
+ return enabled ? kContentSettingsEnabledIndex : kContentSettingsDisabledIndex;
+}
+
+- (BOOL)javaScriptSettingsManaged {
+ return profile_->GetHostContentSettingsMap()->IsDefaultContentSettingManaged(
+ CONTENT_SETTINGS_TYPE_JAVASCRIPT);
+}
+
+- (void)setPluginsEnabledIndex:(NSInteger)value {
+ ContentSetting setting = CONTENT_SETTING_DEFAULT;
+ switch (value) {
+ case kPluginsAllowIndex:
+ setting = CONTENT_SETTING_ALLOW;
+ break;
+ case kPluginsAskIndex:
+ setting = CONTENT_SETTING_ASK;
+ break;
+ case kPluginsBlockIndex:
+ setting = CONTENT_SETTING_BLOCK;
+ break;
+ default:
+ NOTREACHED();
+ }
+ ContentSettingsDialogControllerInternal::PrefObserverDisabler
+ disabler(observer_.get());
+ profile_->GetHostContentSettingsMap()->SetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_PLUGINS, setting);
+}
+
+- (NSInteger)pluginsEnabledIndex {
+ HostContentSettingsMap* map = profile_->GetHostContentSettingsMap();
+ ContentSetting setting =
+ map->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS);
+ switch (setting) {
+ case CONTENT_SETTING_ALLOW:
+ return kPluginsAllowIndex;
+ case CONTENT_SETTING_ASK:
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableClickToPlay))
+ return kPluginsAskIndex;
+ // Fall through to the next case.
+ case CONTENT_SETTING_BLOCK:
+ return kPluginsBlockIndex;
+ default:
+ NOTREACHED();
+ return kPluginsAllowIndex;
+ }
+}
+
+- (BOOL)pluginsSettingsManaged {
+ return profile_->GetHostContentSettingsMap()->IsDefaultContentSettingManaged(
+ CONTENT_SETTINGS_TYPE_PLUGINS);
+}
+
+- (void)setPopupsEnabledIndex:(NSInteger)value {
+ ContentSetting setting = value == kContentSettingsEnabledIndex ?
+ CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK;
+ ContentSettingsDialogControllerInternal::PrefObserverDisabler
+ disabler(observer_.get());
+ profile_->GetHostContentSettingsMap()->SetDefaultContentSetting(
+ CONTENT_SETTINGS_TYPE_POPUPS, setting);
+}
+
+- (NSInteger)popupsEnabledIndex {
+ HostContentSettingsMap* settingsMap = profile_->GetHostContentSettingsMap();
+ bool enabled =
+ settingsMap->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_POPUPS) ==
+ CONTENT_SETTING_ALLOW;
+ return enabled ? kContentSettingsEnabledIndex : kContentSettingsDisabledIndex;
+}
+
+- (BOOL)popupsSettingsManaged {
+ return profile_->GetHostContentSettingsMap()->IsDefaultContentSettingManaged(
+ CONTENT_SETTINGS_TYPE_POPUPS);
+}
+
+- (void)setGeolocationSettingIndex:(NSInteger)value {
+ ContentSetting setting = CONTENT_SETTING_DEFAULT;
+ switch (value) {
+ case kGeolocationEnabledIndex: setting = CONTENT_SETTING_ALLOW; break;
+ case kGeolocationAskIndex: setting = CONTENT_SETTING_ASK; break;
+ case kGeolocationDisabledIndex: setting = CONTENT_SETTING_BLOCK; break;
+ default:
+ NOTREACHED();
+ }
+ ContentSettingsDialogControllerInternal::PrefObserverDisabler
+ disabler(observer_.get());
+ profile_->GetGeolocationContentSettingsMap()->SetDefaultContentSetting(
+ setting);
+}
+
+- (NSInteger)geolocationSettingIndex {
+ ContentSetting setting =
+ profile_->GetGeolocationContentSettingsMap()->GetDefaultContentSetting();
+ switch (setting) {
+ case CONTENT_SETTING_ALLOW: return kGeolocationEnabledIndex;
+ case CONTENT_SETTING_ASK: return kGeolocationAskIndex;
+ case CONTENT_SETTING_BLOCK: return kGeolocationDisabledIndex;
+ default:
+ NOTREACHED();
+ return kGeolocationAskIndex;
+ }
+}
+
+- (void)setNotificationsSettingIndex:(NSInteger)value {
+ ContentSetting setting = CONTENT_SETTING_DEFAULT;
+ switch (value) {
+ case kNotificationsEnabledIndex: setting = CONTENT_SETTING_ALLOW; break;
+ case kNotificationsAskIndex: setting = CONTENT_SETTING_ASK; break;
+ case kNotificationsDisabledIndex: setting = CONTENT_SETTING_BLOCK; break;
+ default:
+ NOTREACHED();
+ }
+ ContentSettingsDialogControllerInternal::PrefObserverDisabler
+ disabler(observer_.get());
+ profile_->GetDesktopNotificationService()->SetDefaultContentSetting(
+ setting);
+}
+
+- (NSInteger)notificationsSettingIndex {
+ ContentSetting setting =
+ profile_->GetDesktopNotificationService()->GetDefaultContentSetting();
+ switch (setting) {
+ case CONTENT_SETTING_ALLOW: return kNotificationsEnabledIndex;
+ case CONTENT_SETTING_ASK: return kNotificationsAskIndex;
+ case CONTENT_SETTING_BLOCK: return kNotificationsDisabledIndex;
+ default:
+ NOTREACHED();
+ return kGeolocationAskIndex;
+ }
+}
+
+// Callback when preferences are changed. |prefName| is the name of the
+// pref that has changed and should not be NULL.
+- (void)prefChanged:(const std::string&)prefName {
+ if (prefName == prefs::kClearSiteDataOnExit) {
+ [self willChangeValueForKey:@"clearSiteDataOnExit"];
+ [self didChangeValueForKey:@"clearSiteDataOnExit"];
+ }
+ if (prefName == prefs::kBlockThirdPartyCookies) {
+ [self willChangeValueForKey:@"blockThirdPartyCookies"];
+ [self didChangeValueForKey:@"blockThirdPartyCookies"];
+ [self willChangeValueForKey:@"blockThirdPartyCookiesManaged"];
+ [self didChangeValueForKey:@"blockThirdPartyCookiesManaged"];
+ }
+ if (prefName == prefs::kBlockNonsandboxedPlugins) {
+ [self willChangeValueForKey:@"pluginsEnabledIndex"];
+ [self didChangeValueForKey:@"pluginsEnabledIndex"];
+ }
+ if (prefName == prefs::kDefaultContentSettings) {
+ // We don't know exactly which setting has changed, so we'll tickle all
+ // of the properties that apply to kDefaultContentSettings. This will
+ // keep the UI up-to-date.
+ [self willChangeValueForKey:@"cookieSettingIndex"];
+ [self didChangeValueForKey:@"cookieSettingIndex"];
+ [self willChangeValueForKey:@"imagesEnabledIndex"];
+ [self didChangeValueForKey:@"imagesEnabledIndex"];
+ [self willChangeValueForKey:@"javaScriptEnabledIndex"];
+ [self didChangeValueForKey:@"javaScriptEnabledIndex"];
+ [self willChangeValueForKey:@"pluginsEnabledIndex"];
+ [self didChangeValueForKey:@"pluginsEnabledIndex"];
+ [self willChangeValueForKey:@"popupsEnabledIndex"];
+ [self didChangeValueForKey:@"popupsEnabledIndex"];
+
+ // Updates the "Enable" state of the radio groups and the exception buttons.
+ [self willChangeValueForKey:@"cookieSettingsManaged"];
+ [self didChangeValueForKey:@"cookieSettingsManaged"];
+ [self willChangeValueForKey:@"imagesSettingsManaged"];
+ [self didChangeValueForKey:@"imagesSettingsManaged"];
+ [self willChangeValueForKey:@"javaScriptSettingsManaged"];
+ [self didChangeValueForKey:@"javaScriptSettingsManaged"];
+ [self willChangeValueForKey:@"pluginsSettingsManaged"];
+ [self didChangeValueForKey:@"pluginsSettingsManaged"];
+ [self willChangeValueForKey:@"popupsSettingsManaged"];
+ [self didChangeValueForKey:@"popupsSettingsManaged"];
+ }
+ if (prefName == prefs::kGeolocationDefaultContentSetting) {
+ [self willChangeValueForKey:@"geolocationSettingIndex"];
+ [self didChangeValueForKey:@"geolocationSettingIndex"];
+ }
+ if (prefName == prefs::kDesktopNotificationDefaultContentSetting) {
+ [self willChangeValueForKey:@"notificationsSettingIndex"];
+ [self didChangeValueForKey:@"notificationsSettingIndex"];
+ }
+}
+
+- (void)contentSettingsChanged:(ContentSettingsDetails*)details {
+ [self prefChanged:prefs::kBlockNonsandboxedPlugins];
+ [self prefChanged:prefs::kDefaultContentSettings];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/content_settings_dialog_controller_unittest.mm b/chrome/browser/ui/cocoa/content_settings_dialog_controller_unittest.mm
new file mode 100644
index 0000000..1d48509
--- /dev/null
+++ b/chrome/browser/ui/cocoa/content_settings_dialog_controller_unittest.mm
@@ -0,0 +1,289 @@
+// 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 "chrome/browser/ui/cocoa/content_settings_dialog_controller.h"
+
+#include "base/auto_reset.h"
+#include "base/command_line.h"
+#import "base/scoped_nsobject.h"
+#include "base/ref_counted.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
+#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
+#include "chrome/browser/notifications/desktop_notification_service.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/chrome_switches.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class ContentSettingsDialogControllerTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ TestingProfile* profile = browser_helper_.profile();
+ settingsMap_ = new HostContentSettingsMap(profile);
+ geoSettingsMap_ = new GeolocationContentSettingsMap(profile);
+ notificationsService_.reset(new DesktopNotificationService(profile, NULL));
+ controller_ = [ContentSettingsDialogController
+ showContentSettingsForType:CONTENT_SETTINGS_TYPE_DEFAULT
+ profile:browser_helper_.profile()];
+ }
+
+ virtual void TearDown() {
+ [controller_ close];
+ CocoaTest::TearDown();
+ }
+
+ protected:
+ ContentSettingsDialogController* controller_;
+ BrowserTestHelper browser_helper_;
+ scoped_refptr<HostContentSettingsMap> settingsMap_;
+ scoped_refptr<GeolocationContentSettingsMap> geoSettingsMap_;
+ scoped_ptr<DesktopNotificationService> notificationsService_;
+};
+
+// Test that +showContentSettingsDialogForProfile brings up the existing editor
+// and doesn't leak or crash.
+TEST_F(ContentSettingsDialogControllerTest, CreateDialog) {
+ EXPECT_TRUE(controller_);
+}
+
+TEST_F(ContentSettingsDialogControllerTest, CookieSetting) {
+ // Change setting, check dialog property.
+ settingsMap_->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_COOKIES,
+ CONTENT_SETTING_ALLOW);
+ EXPECT_EQ([controller_ cookieSettingIndex], kCookieEnabledIndex);
+
+ settingsMap_->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_COOKIES,
+ CONTENT_SETTING_BLOCK);
+ EXPECT_EQ([controller_ cookieSettingIndex], kCookieDisabledIndex);
+
+ // Change dialog property, check setting.
+ NSInteger setting;
+ [controller_ setCookieSettingIndex:kCookieEnabledIndex];
+ setting =
+ settingsMap_->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_COOKIES);
+ EXPECT_EQ(setting, CONTENT_SETTING_ALLOW);
+
+ [controller_ setCookieSettingIndex:kCookieDisabledIndex];
+ setting =
+ settingsMap_->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_COOKIES);
+ EXPECT_EQ(setting, CONTENT_SETTING_BLOCK);
+}
+
+TEST_F(ContentSettingsDialogControllerTest, BlockThirdPartyCookiesSetting) {
+ // Change setting, check dialog property.
+ settingsMap_->SetBlockThirdPartyCookies(YES);
+ EXPECT_TRUE([controller_ blockThirdPartyCookies]);
+
+ settingsMap_->SetBlockThirdPartyCookies(NO);
+ EXPECT_FALSE([controller_ blockThirdPartyCookies]);
+
+ // Change dialog property, check setting.
+ [controller_ setBlockThirdPartyCookies:YES];
+ EXPECT_TRUE(settingsMap_->BlockThirdPartyCookies());
+
+ [controller_ setBlockThirdPartyCookies:NO];
+ EXPECT_FALSE(settingsMap_->BlockThirdPartyCookies());
+}
+
+TEST_F(ContentSettingsDialogControllerTest, ClearSiteDataOnExitSetting) {
+ TestingProfile* profile = browser_helper_.profile();
+
+ // Change setting, check dialog property.
+ profile->GetPrefs()->SetBoolean(prefs::kClearSiteDataOnExit, true);
+ EXPECT_TRUE([controller_ clearSiteDataOnExit]);
+
+ profile->GetPrefs()->SetBoolean(prefs::kClearSiteDataOnExit, false);
+ EXPECT_FALSE([controller_ clearSiteDataOnExit]);
+
+ // Change dialog property, check setting.
+ [controller_ setClearSiteDataOnExit:YES];
+ EXPECT_TRUE(profile->GetPrefs()->GetBoolean(prefs::kClearSiteDataOnExit));
+
+ [controller_ setClearSiteDataOnExit:NO];
+ EXPECT_FALSE(profile->GetPrefs()->GetBoolean(prefs::kClearSiteDataOnExit));
+}
+
+TEST_F(ContentSettingsDialogControllerTest, ImagesSetting) {
+ // Change setting, check dialog property.
+ settingsMap_->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_IMAGES,
+ CONTENT_SETTING_ALLOW);
+ EXPECT_EQ([controller_ imagesEnabledIndex], kContentSettingsEnabledIndex);
+
+ settingsMap_->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_IMAGES,
+ CONTENT_SETTING_BLOCK);
+ EXPECT_EQ([controller_ imagesEnabledIndex], kContentSettingsDisabledIndex);
+
+ // Change dialog property, check setting.
+ NSInteger setting;
+ [controller_ setImagesEnabledIndex:kContentSettingsEnabledIndex];
+ setting =
+ settingsMap_->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_IMAGES);
+ EXPECT_EQ(setting, CONTENT_SETTING_ALLOW);
+
+ [controller_ setImagesEnabledIndex:kContentSettingsDisabledIndex];
+ setting =
+ settingsMap_->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_IMAGES);
+ EXPECT_EQ(setting, CONTENT_SETTING_BLOCK);
+}
+
+TEST_F(ContentSettingsDialogControllerTest, JavaScriptSetting) {
+ // Change setting, check dialog property.
+ settingsMap_->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_JAVASCRIPT,
+ CONTENT_SETTING_ALLOW);
+ EXPECT_EQ([controller_ javaScriptEnabledIndex], kContentSettingsEnabledIndex);
+
+ settingsMap_->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_JAVASCRIPT,
+ CONTENT_SETTING_BLOCK);
+ EXPECT_EQ([controller_ javaScriptEnabledIndex],
+ kContentSettingsDisabledIndex);
+
+ // Change dialog property, check setting.
+ NSInteger setting;
+ [controller_ setJavaScriptEnabledIndex:kContentSettingsEnabledIndex];
+ setting =
+ settingsMap_->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_JAVASCRIPT);
+ EXPECT_EQ(setting, CONTENT_SETTING_ALLOW);
+
+ [controller_ setJavaScriptEnabledIndex:kContentSettingsDisabledIndex];
+ setting =
+ settingsMap_->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_JAVASCRIPT);
+ EXPECT_EQ(setting, CONTENT_SETTING_BLOCK);
+}
+
+TEST_F(ContentSettingsDialogControllerTest, PluginsSetting) {
+ // Change setting, check dialog property.
+ settingsMap_->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS,
+ CONTENT_SETTING_ALLOW);
+ EXPECT_EQ(kPluginsAllowIndex, [controller_ pluginsEnabledIndex]);
+
+ settingsMap_->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS,
+ CONTENT_SETTING_BLOCK);
+ EXPECT_EQ(kPluginsBlockIndex, [controller_ pluginsEnabledIndex]);
+
+ {
+ // Click-to-play needs to be enabled to set the content setting to ASK.
+ CommandLine* cmd = CommandLine::ForCurrentProcess();
+ AutoReset<CommandLine> auto_reset(cmd, *cmd);
+ cmd->AppendSwitch(switches::kEnableClickToPlay);
+
+ settingsMap_->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS,
+ CONTENT_SETTING_ASK);
+ EXPECT_EQ(kPluginsAskIndex, [controller_ pluginsEnabledIndex]);
+ }
+
+ // Change dialog property, check setting.
+ NSInteger setting;
+ [controller_ setPluginsEnabledIndex:kPluginsAllowIndex];
+ setting =
+ settingsMap_->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS);
+ EXPECT_EQ(CONTENT_SETTING_ALLOW, setting);
+
+ [controller_ setPluginsEnabledIndex:kPluginsBlockIndex];
+ setting =
+ settingsMap_->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS);
+ EXPECT_EQ(CONTENT_SETTING_BLOCK, setting);
+
+ {
+ CommandLine* cmd = CommandLine::ForCurrentProcess();
+ AutoReset<CommandLine> auto_reset(cmd, *cmd);
+ cmd->AppendSwitch(switches::kEnableClickToPlay);
+
+ [controller_ setPluginsEnabledIndex:kPluginsAskIndex];
+ setting =
+ settingsMap_->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS);
+ EXPECT_EQ(CONTENT_SETTING_ASK, setting);
+ }
+}
+
+TEST_F(ContentSettingsDialogControllerTest, PopupsSetting) {
+ // Change setting, check dialog property.
+ settingsMap_->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_POPUPS,
+ CONTENT_SETTING_ALLOW);
+ EXPECT_EQ([controller_ popupsEnabledIndex], kContentSettingsEnabledIndex);
+
+ settingsMap_->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_POPUPS,
+ CONTENT_SETTING_BLOCK);
+ EXPECT_EQ([controller_ popupsEnabledIndex], kContentSettingsDisabledIndex);
+
+ // Change dialog property, check setting.
+ NSInteger setting;
+ [controller_ setPopupsEnabledIndex:kContentSettingsEnabledIndex];
+ setting =
+ settingsMap_->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_POPUPS);
+ EXPECT_EQ(setting, CONTENT_SETTING_ALLOW);
+
+ [controller_ setPopupsEnabledIndex:kContentSettingsDisabledIndex];
+ setting =
+ settingsMap_->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_POPUPS);
+ EXPECT_EQ(setting, CONTENT_SETTING_BLOCK);
+}
+
+TEST_F(ContentSettingsDialogControllerTest, GeolocationSetting) {
+ // Change setting, check dialog property.
+ geoSettingsMap_->SetDefaultContentSetting(CONTENT_SETTING_ALLOW);
+ EXPECT_EQ([controller_ geolocationSettingIndex], kGeolocationEnabledIndex);
+
+ geoSettingsMap_->SetDefaultContentSetting(CONTENT_SETTING_ASK);
+ EXPECT_EQ([controller_ geolocationSettingIndex], kGeolocationAskIndex);
+
+ geoSettingsMap_->SetDefaultContentSetting(CONTENT_SETTING_BLOCK);
+ EXPECT_EQ([controller_ geolocationSettingIndex], kGeolocationDisabledIndex);
+
+ // Change dialog property, check setting.
+ NSInteger setting;
+ [controller_ setGeolocationSettingIndex:kGeolocationEnabledIndex];
+ setting =
+ geoSettingsMap_->GetDefaultContentSetting();
+ EXPECT_EQ(setting, CONTENT_SETTING_ALLOW);
+
+ [controller_ setGeolocationSettingIndex:kGeolocationAskIndex];
+ setting =
+ geoSettingsMap_->GetDefaultContentSetting();
+ EXPECT_EQ(setting, CONTENT_SETTING_ASK);
+
+ [controller_ setGeolocationSettingIndex:kGeolocationDisabledIndex];
+ setting =
+ geoSettingsMap_->GetDefaultContentSetting();
+ EXPECT_EQ(setting, CONTENT_SETTING_BLOCK);
+}
+
+TEST_F(ContentSettingsDialogControllerTest, NotificationsSetting) {
+ // Change setting, check dialog property.
+ notificationsService_->SetDefaultContentSetting(CONTENT_SETTING_ALLOW);
+ EXPECT_EQ([controller_ notificationsSettingIndex],
+ kNotificationsEnabledIndex);
+
+ notificationsService_->SetDefaultContentSetting(CONTENT_SETTING_ASK);
+ EXPECT_EQ([controller_ notificationsSettingIndex], kNotificationsAskIndex);
+
+ notificationsService_->SetDefaultContentSetting(CONTENT_SETTING_BLOCK);
+ EXPECT_EQ([controller_ notificationsSettingIndex],
+ kNotificationsDisabledIndex);
+
+ // Change dialog property, check setting.
+ NSInteger setting;
+ [controller_ setNotificationsSettingIndex:kNotificationsEnabledIndex];
+ setting =
+ notificationsService_->GetDefaultContentSetting();
+ EXPECT_EQ(setting, CONTENT_SETTING_ALLOW);
+
+ [controller_ setNotificationsSettingIndex:kNotificationsAskIndex];
+ setting =
+ notificationsService_->GetDefaultContentSetting();
+ EXPECT_EQ(setting, CONTENT_SETTING_ASK);
+
+ [controller_ setNotificationsSettingIndex:kNotificationsDisabledIndex];
+ setting =
+ notificationsService_->GetDefaultContentSetting();
+ EXPECT_EQ(setting, CONTENT_SETTING_BLOCK);
+}
+
+} // namespace
+
diff --git a/chrome/browser/cocoa/cookie_details.h b/chrome/browser/ui/cocoa/cookie_details.h
index 614c87c..614c87c 100644
--- a/chrome/browser/cocoa/cookie_details.h
+++ b/chrome/browser/ui/cocoa/cookie_details.h
diff --git a/chrome/browser/ui/cocoa/cookie_details.mm b/chrome/browser/ui/cocoa/cookie_details.mm
new file mode 100644
index 0000000..e88cf27
--- /dev/null
+++ b/chrome/browser/ui/cocoa/cookie_details.mm
@@ -0,0 +1,299 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/cookie_details.h"
+
+#include "app/l10n_util_mac.h"
+#import "base/i18n/time_formatting.h"
+#include "base/sys_string_conversions.h"
+#include "grit/generated_resources.h"
+#include "chrome/browser/cookies_tree_model.h"
+#include "webkit/appcache/appcache_service.h"
+
+#pragma mark Cocoa Cookie Details
+
+@implementation CocoaCookieDetails
+
+@synthesize canEditExpiration = canEditExpiration_;
+@synthesize hasExpiration = hasExpiration_;
+@synthesize type = type_;
+
+- (BOOL)shouldHideCookieDetailsView {
+ return type_ != kCocoaCookieDetailsTypeFolder &&
+ type_ != kCocoaCookieDetailsTypeCookie;
+}
+
+- (BOOL)shouldShowLocalStorageTreeDetailsView {
+ return type_ == kCocoaCookieDetailsTypeTreeLocalStorage;
+}
+
+- (BOOL)shouldShowLocalStoragePromptDetailsView {
+ return type_ == kCocoaCookieDetailsTypePromptLocalStorage;
+}
+
+- (BOOL)shouldShowDatabaseTreeDetailsView {
+ return type_ == kCocoaCookieDetailsTypeTreeDatabase;
+}
+
+- (BOOL)shouldShowAppCacheTreeDetailsView {
+ return type_ == kCocoaCookieDetailsTypeTreeAppCache;
+}
+
+- (BOOL)shouldShowDatabasePromptDetailsView {
+ return type_ == kCocoaCookieDetailsTypePromptDatabase;
+}
+
+- (BOOL)shouldShowAppCachePromptDetailsView {
+ return type_ == kCocoaCookieDetailsTypePromptAppCache;
+}
+
+- (BOOL)shouldShowIndexedDBTreeDetailsView {
+ return type_ == kCocoaCookieDetailsTypeTreeIndexedDB;
+}
+
+- (NSString*)name {
+ return name_.get();
+}
+
+- (NSString*)content {
+ return content_.get();
+}
+
+- (NSString*)domain {
+ return domain_.get();
+}
+
+- (NSString*)path {
+ return path_.get();
+}
+
+- (NSString*)sendFor {
+ return sendFor_.get();
+}
+
+- (NSString*)created {
+ return created_.get();
+}
+
+- (NSString*)expires {
+ return expires_.get();
+}
+
+- (NSString*)fileSize {
+ return fileSize_.get();
+}
+
+- (NSString*)lastModified {
+ return lastModified_.get();
+}
+
+- (NSString*)lastAccessed {
+ return lastAccessed_.get();
+}
+
+- (NSString*)databaseDescription {
+ return databaseDescription_.get();
+}
+
+- (NSString*)localStorageKey {
+ return localStorageKey_.get();
+}
+
+- (NSString*)localStorageValue {
+ return localStorageValue_.get();
+}
+
+- (NSString*)manifestURL {
+ return manifestURL_.get();
+}
+
+- (id)initAsFolder {
+ if ((self = [super init])) {
+ type_ = kCocoaCookieDetailsTypeFolder;
+ }
+ return self;
+}
+
+- (id)initWithCookie:(const net::CookieMonster::CanonicalCookie*)cookie
+ origin:(NSString*)origin
+ canEditExpiration:(BOOL)canEditExpiration {
+ if ((self = [super init])) {
+ type_ = kCocoaCookieDetailsTypeCookie;
+ hasExpiration_ = cookie->DoesExpire();
+ canEditExpiration_ = canEditExpiration && hasExpiration_;
+ name_.reset([base::SysUTF8ToNSString(cookie->Name()) retain]);
+ content_.reset([base::SysUTF8ToNSString(cookie->Value()) retain]);
+ path_.reset([base::SysUTF8ToNSString(cookie->Path()) retain]);
+ domain_.reset([origin retain]);
+
+ if (cookie->DoesExpire()) {
+ expires_.reset([base::SysUTF16ToNSString(
+ base::TimeFormatFriendlyDateAndTime(cookie->ExpiryDate())) retain]);
+ } else {
+ expires_.reset([l10n_util::GetNSStringWithFixup(
+ IDS_COOKIES_COOKIE_EXPIRES_SESSION) retain]);
+ }
+
+ created_.reset([base::SysUTF16ToNSString(
+ base::TimeFormatFriendlyDateAndTime(cookie->CreationDate())) retain]);
+
+ if (cookie->IsSecure()) {
+ sendFor_.reset([l10n_util::GetNSStringWithFixup(
+ IDS_COOKIES_COOKIE_SENDFOR_SECURE) retain]);
+ } else {
+ sendFor_.reset([l10n_util::GetNSStringWithFixup(
+ IDS_COOKIES_COOKIE_SENDFOR_ANY) retain]);
+ }
+ }
+ return self;
+}
+
+- (id)initWithDatabase:(const BrowsingDataDatabaseHelper::DatabaseInfo*)
+ databaseInfo {
+ if ((self = [super init])) {
+ type_ = kCocoaCookieDetailsTypeTreeDatabase;
+ canEditExpiration_ = NO;
+ databaseDescription_.reset([base::SysUTF8ToNSString(
+ databaseInfo->description) retain]);
+ fileSize_.reset([base::SysUTF16ToNSString(FormatBytes(databaseInfo->size,
+ GetByteDisplayUnits(databaseInfo->size), true)) retain]);
+ lastModified_.reset([base::SysUTF16ToNSString(
+ base::TimeFormatFriendlyDateAndTime(
+ databaseInfo->last_modified)) retain]);
+ }
+ return self;
+}
+
+- (id)initWithLocalStorage:(
+ const BrowsingDataLocalStorageHelper::LocalStorageInfo*)storageInfo {
+ if ((self = [super init])) {
+ type_ = kCocoaCookieDetailsTypeTreeLocalStorage;
+ canEditExpiration_ = NO;
+ domain_.reset([base::SysUTF8ToNSString(storageInfo->origin) retain]);
+ fileSize_.reset([base::SysUTF16ToNSString(FormatBytes(storageInfo->size,
+ GetByteDisplayUnits(storageInfo->size), true)) retain]);
+ lastModified_.reset([base::SysUTF16ToNSString(
+ base::TimeFormatFriendlyDateAndTime(
+ storageInfo->last_modified)) retain]);
+ }
+ return self;
+}
+
+- (id)initWithAppCacheInfo:(const appcache::AppCacheInfo*)appcacheInfo {
+ if ((self = [super init])) {
+ type_ = kCocoaCookieDetailsTypeTreeAppCache;
+ canEditExpiration_ = NO;
+ manifestURL_.reset([base::SysUTF8ToNSString(
+ appcacheInfo->manifest_url.spec()) retain]);
+ fileSize_.reset([base::SysUTF16ToNSString(FormatBytes(appcacheInfo->size,
+ GetByteDisplayUnits(appcacheInfo->size), true)) retain]);
+ created_.reset([base::SysUTF16ToNSString(
+ base::TimeFormatFriendlyDateAndTime(
+ appcacheInfo->creation_time)) retain]);
+ lastAccessed_.reset([base::SysUTF16ToNSString(
+ base::TimeFormatFriendlyDateAndTime(
+ appcacheInfo->last_access_time)) retain]);
+ }
+ return self;
+}
+
+- (id)initWithDatabase:(const std::string&)domain
+ databaseName:(const string16&)databaseName
+ databaseDescription:(const string16&)databaseDescription
+ fileSize:(unsigned long)fileSize {
+ if ((self = [super init])) {
+ type_ = kCocoaCookieDetailsTypePromptDatabase;
+ canEditExpiration_ = NO;
+ name_.reset([base::SysUTF16ToNSString(databaseName) retain]);
+ domain_.reset([base::SysUTF8ToNSString(domain) retain]);
+ databaseDescription_.reset(
+ [base::SysUTF16ToNSString(databaseDescription) retain]);
+ fileSize_.reset([base::SysUTF16ToNSString(FormatBytes(fileSize,
+ GetByteDisplayUnits(fileSize), true)) retain]);
+ }
+ return self;
+}
+
+- (id)initWithLocalStorage:(const std::string&)domain
+ key:(const string16&)key
+ value:(const string16&)value {
+ if ((self = [super init])) {
+ type_ = kCocoaCookieDetailsTypePromptLocalStorage;
+ canEditExpiration_ = NO;
+ domain_.reset([base::SysUTF8ToNSString(domain) retain]);
+ localStorageKey_.reset([base::SysUTF16ToNSString(key) retain]);
+ localStorageValue_.reset([base::SysUTF16ToNSString(value) retain]);
+ }
+ return self;
+}
+
+- (id)initWithAppCacheManifestURL:(const std::string&)manifestURL {
+ if ((self = [super init])) {
+ type_ = kCocoaCookieDetailsTypePromptAppCache;
+ canEditExpiration_ = NO;
+ manifestURL_.reset([base::SysUTF8ToNSString(manifestURL) retain]);
+ }
+ return self;
+}
+
+- (id)initWithIndexedDBInfo:
+ (const BrowsingDataIndexedDBHelper::IndexedDBInfo*)indexedDBInfo {
+ if ((self = [super init])) {
+ type_ = kCocoaCookieDetailsTypeTreeIndexedDB;
+ canEditExpiration_ = NO;
+ domain_.reset([base::SysUTF8ToNSString(indexedDBInfo->origin) retain]);
+ fileSize_.reset([base::SysUTF16ToNSString(FormatBytes(indexedDBInfo->size,
+ GetByteDisplayUnits(indexedDBInfo->size), true)) retain]);
+ lastModified_.reset([base::SysUTF16ToNSString(
+ base::TimeFormatFriendlyDateAndTime(
+ indexedDBInfo->last_modified)) retain]);
+ }
+ return self;
+}
+
++ (CocoaCookieDetails*)createFromCookieTreeNode:(CookieTreeNode*)treeNode {
+ CookieTreeNode::DetailedInfo info = treeNode->GetDetailedInfo();
+ CookieTreeNode::DetailedInfo::NodeType nodeType = info.node_type;
+ NSString* origin;
+ switch (nodeType) {
+ case CookieTreeNode::DetailedInfo::TYPE_COOKIE:
+ origin = base::SysWideToNSString(info.origin.c_str());
+ return [[[CocoaCookieDetails alloc] initWithCookie:info.cookie
+ origin:origin
+ canEditExpiration:NO] autorelease];
+ case CookieTreeNode::DetailedInfo::TYPE_DATABASE:
+ return [[[CocoaCookieDetails alloc]
+ initWithDatabase:info.database_info] autorelease];
+ case CookieTreeNode::DetailedInfo::TYPE_LOCAL_STORAGE:
+ return [[[CocoaCookieDetails alloc]
+ initWithLocalStorage:info.local_storage_info] autorelease];
+ case CookieTreeNode::DetailedInfo::TYPE_APPCACHE:
+ return [[[CocoaCookieDetails alloc]
+ initWithAppCacheInfo:info.appcache_info] autorelease];
+ case CookieTreeNode::DetailedInfo::TYPE_INDEXED_DB:
+ return [[[CocoaCookieDetails alloc]
+ initWithIndexedDBInfo:info.indexed_db_info] autorelease];
+ default:
+ return [[[CocoaCookieDetails alloc] initAsFolder] autorelease];
+ }
+}
+
+@end
+
+#pragma mark Content Object Adapter
+
+@implementation CookiePromptContentDetailsAdapter
+
+- (id)initWithDetails:(CocoaCookieDetails*)details {
+ if ((self = [super init])) {
+ details_.reset([details retain]);
+ }
+ return self;
+}
+
+- (CocoaCookieDetails*)details {
+ return details_.get();
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/cookie_details_unittest.mm b/chrome/browser/ui/cocoa/cookie_details_unittest.mm
new file mode 100644
index 0000000..0f7d711
--- /dev/null
+++ b/chrome/browser/ui/cocoa/cookie_details_unittest.mm
@@ -0,0 +1,247 @@
+// 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.
+
+#include "base/sys_string_conversions.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/cookie_details.h"
+#include "googleurl/src/gurl.h"
+#import "testing/gtest_mac.h"
+
+namespace {
+
+class CookiesDetailsTest : public CocoaTest {
+};
+
+TEST_F(CookiesDetailsTest, CreateForFolder) {
+ scoped_nsobject<CocoaCookieDetails> details;
+ details.reset([[CocoaCookieDetails alloc] initAsFolder]);
+
+ EXPECT_EQ([details.get() type], kCocoaCookieDetailsTypeFolder);
+}
+
+TEST_F(CookiesDetailsTest, CreateForCookie) {
+ scoped_nsobject<CocoaCookieDetails> details;
+ GURL url("http://chromium.org");
+ std::string cookieLine(
+ "PHPSESSID=0123456789abcdef0123456789abcdef; path=/");
+ net::CookieMonster::ParsedCookie pc(cookieLine);
+ net::CookieMonster::CanonicalCookie cookie(url, pc);
+ NSString* origin = base::SysUTF8ToNSString("http://chromium.org");
+ details.reset([[CocoaCookieDetails alloc] initWithCookie:&cookie
+ origin:origin
+ canEditExpiration:NO]);
+
+ EXPECT_EQ([details.get() type], kCocoaCookieDetailsTypeCookie);
+ EXPECT_NSEQ(@"PHPSESSID", [details.get() name]);
+ EXPECT_NSEQ(@"0123456789abcdef0123456789abcdef",
+ [details.get() content]);
+ EXPECT_NSEQ(@"http://chromium.org", [details.get() domain]);
+ EXPECT_NSEQ(@"/", [details.get() path]);
+ EXPECT_NSNE(@"", [details.get() lastModified]);
+ EXPECT_NSNE(@"", [details.get() created]);
+ EXPECT_NSNE(@"", [details.get() sendFor]);
+
+ EXPECT_FALSE([details.get() shouldHideCookieDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowLocalStorageTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowDatabaseTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowAppCacheTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowIndexedDBTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowLocalStoragePromptDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowDatabasePromptDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowAppCachePromptDetailsView]);
+}
+
+TEST_F(CookiesDetailsTest, CreateForTreeDatabase) {
+ scoped_nsobject<CocoaCookieDetails> details;
+ std::string host("http://chromium.org");
+ std::string database_name("sassolungo");
+ std::string origin_identifier("dolomites");
+ std::string description("a great place to climb");
+ int64 size = 1234;
+ base::Time last_modified = base::Time::Now();
+ BrowsingDataDatabaseHelper::DatabaseInfo info(host, database_name,
+ origin_identifier, description, host, size, last_modified);
+ details.reset([[CocoaCookieDetails alloc] initWithDatabase:&info]);
+
+ EXPECT_EQ([details.get() type], kCocoaCookieDetailsTypeTreeDatabase);
+ EXPECT_NSEQ(@"a great place to climb", [details.get() databaseDescription]);
+ EXPECT_NSEQ(@"1234 B", [details.get() fileSize]);
+ EXPECT_NSNE(@"", [details.get() lastModified]);
+
+ EXPECT_TRUE([details.get() shouldHideCookieDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowLocalStorageTreeDetailsView]);
+ EXPECT_TRUE([details.get() shouldShowDatabaseTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowAppCacheTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowIndexedDBTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowLocalStoragePromptDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowDatabasePromptDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowAppCachePromptDetailsView]);
+}
+
+TEST_F(CookiesDetailsTest, CreateForTreeLocalStorage) {
+ scoped_nsobject<CocoaCookieDetails> details;
+ std::string protocol("http");
+ std::string host("chromium.org");
+ unsigned short port = 80;
+ std::string database_identifier("id");
+ std::string origin("chromium.org");
+ FilePath file_path(FILE_PATH_LITERAL("/"));
+ int64 size = 1234;
+ base::Time last_modified = base::Time::Now();
+ BrowsingDataLocalStorageHelper::LocalStorageInfo info(protocol, host, port,
+ database_identifier, origin, file_path, size, last_modified);
+ details.reset([[CocoaCookieDetails alloc] initWithLocalStorage:&info]);
+
+ EXPECT_EQ([details.get() type], kCocoaCookieDetailsTypeTreeLocalStorage);
+ EXPECT_NSEQ(@"chromium.org", [details.get() domain]);
+ EXPECT_NSEQ(@"1234 B", [details.get() fileSize]);
+ EXPECT_NSNE(@"", [details.get() lastModified]);
+
+ EXPECT_TRUE([details.get() shouldHideCookieDetailsView]);
+ EXPECT_TRUE([details.get() shouldShowLocalStorageTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowDatabaseTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowAppCacheTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowIndexedDBTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowLocalStoragePromptDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowDatabasePromptDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowAppCachePromptDetailsView]);
+}
+
+TEST_F(CookiesDetailsTest, CreateForTreeAppCache) {
+ scoped_nsobject<CocoaCookieDetails> details;
+
+ GURL url("http://chromium.org/stuff.manifest");
+ appcache::AppCacheInfo info;
+ info.creation_time = base::Time::Now();
+ info.last_update_time = base::Time::Now();
+ info.last_access_time = base::Time::Now();
+ info.size=2678;
+ info.manifest_url = url;
+ details.reset([[CocoaCookieDetails alloc] initWithAppCacheInfo:&info]);
+
+ EXPECT_EQ([details.get() type], kCocoaCookieDetailsTypeTreeAppCache);
+ EXPECT_NSEQ(@"http://chromium.org/stuff.manifest",
+ [details.get() manifestURL]);
+ EXPECT_NSEQ(@"2678 B", [details.get() fileSize]);
+ EXPECT_NSNE(@"", [details.get() lastAccessed]);
+ EXPECT_NSNE(@"", [details.get() created]);
+
+ EXPECT_TRUE([details.get() shouldHideCookieDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowLocalStorageTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowDatabaseTreeDetailsView]);
+ EXPECT_TRUE([details.get() shouldShowAppCacheTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowIndexedDBTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowLocalStoragePromptDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowDatabasePromptDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowAppCachePromptDetailsView]);
+}
+
+TEST_F(CookiesDetailsTest, CreateForTreeIndexedDB) {
+ scoped_nsobject<CocoaCookieDetails> details;
+
+ std::string protocol("http");
+ std::string host("moose.org");
+ unsigned short port = 80;
+ std::string database_identifier("id");
+ std::string origin("moose.org");
+ FilePath file_path(FILE_PATH_LITERAL("/"));
+ int64 size = 1234;
+ base::Time last_modified = base::Time::Now();
+ BrowsingDataIndexedDBHelper::IndexedDBInfo info(protocol,
+ host,
+ port,
+ database_identifier,
+ origin,
+ file_path,
+ size,
+ last_modified);
+
+ details.reset([[CocoaCookieDetails alloc] initWithIndexedDBInfo:&info]);
+
+ EXPECT_EQ([details.get() type], kCocoaCookieDetailsTypeTreeIndexedDB);
+ EXPECT_NSEQ(@"moose.org", [details.get() domain]);
+ EXPECT_NSEQ(@"1234 B", [details.get() fileSize]);
+ EXPECT_NSNE(@"", [details.get() lastModified]);
+
+ EXPECT_TRUE([details.get() shouldHideCookieDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowLocalStorageTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowDatabaseTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowAppCacheTreeDetailsView]);
+ EXPECT_TRUE([details.get() shouldShowIndexedDBTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowLocalStoragePromptDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowDatabasePromptDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowAppCachePromptDetailsView]);
+}
+
+TEST_F(CookiesDetailsTest, CreateForPromptDatabase) {
+ scoped_nsobject<CocoaCookieDetails> details;
+ std::string domain("chromium.org");
+ string16 name(base::SysNSStringToUTF16(@"wicked_name"));
+ string16 desc(base::SysNSStringToUTF16(@"desc"));
+ details.reset([[CocoaCookieDetails alloc] initWithDatabase:domain
+ databaseName:name
+ databaseDescription:desc
+ fileSize:94]);
+
+ EXPECT_EQ([details.get() type], kCocoaCookieDetailsTypePromptDatabase);
+ EXPECT_NSEQ(@"chromium.org", [details.get() domain]);
+ EXPECT_NSEQ(@"wicked_name", [details.get() name]);
+ EXPECT_NSEQ(@"desc", [details.get() databaseDescription]);
+ EXPECT_NSEQ(@"94 B", [details.get() fileSize]);
+
+ EXPECT_TRUE([details.get() shouldHideCookieDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowLocalStorageTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowDatabaseTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowAppCacheTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowIndexedDBTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowLocalStoragePromptDetailsView]);
+ EXPECT_TRUE([details.get() shouldShowDatabasePromptDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowAppCachePromptDetailsView]);
+}
+
+TEST_F(CookiesDetailsTest, CreateForPromptLocalStorage) {
+ scoped_nsobject<CocoaCookieDetails> details;
+ std::string domain("chromium.org");
+ string16 key(base::SysNSStringToUTF16(@"testKey"));
+ string16 value(base::SysNSStringToUTF16(@"testValue"));
+ details.reset([[CocoaCookieDetails alloc] initWithLocalStorage:domain
+ key:key
+ value:value]);
+
+ EXPECT_EQ([details.get() type], kCocoaCookieDetailsTypePromptLocalStorage);
+ EXPECT_NSEQ(@"chromium.org", [details.get() domain]);
+ EXPECT_NSEQ(@"testKey", [details.get() localStorageKey]);
+ EXPECT_NSEQ(@"testValue", [details.get() localStorageValue]);
+
+ EXPECT_TRUE([details.get() shouldHideCookieDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowLocalStorageTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowDatabaseTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowAppCacheTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowIndexedDBTreeDetailsView]);
+ EXPECT_TRUE([details.get() shouldShowLocalStoragePromptDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowDatabasePromptDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowAppCachePromptDetailsView]);
+}
+
+TEST_F(CookiesDetailsTest, CreateForPromptAppCache) {
+ scoped_nsobject<CocoaCookieDetails> details;
+ std::string manifestURL("http://html5demos.com/html5demo.manifest");
+ details.reset([[CocoaCookieDetails alloc]
+ initWithAppCacheManifestURL:manifestURL.c_str()]);
+
+ EXPECT_EQ([details.get() type], kCocoaCookieDetailsTypePromptAppCache);
+ EXPECT_NSEQ(@"http://html5demos.com/html5demo.manifest",
+ [details.get() manifestURL]);
+
+ EXPECT_TRUE([details.get() shouldHideCookieDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowLocalStorageTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowDatabaseTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowAppCacheTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowIndexedDBTreeDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowLocalStoragePromptDetailsView]);
+ EXPECT_FALSE([details.get() shouldShowDatabasePromptDetailsView]);
+ EXPECT_TRUE([details.get() shouldShowAppCachePromptDetailsView]);
+}
+
+}
diff --git a/chrome/browser/ui/cocoa/cookie_details_view_controller.h b/chrome/browser/ui/cocoa/cookie_details_view_controller.h
new file mode 100644
index 0000000..63fff93
--- /dev/null
+++ b/chrome/browser/ui/cocoa/cookie_details_view_controller.h
@@ -0,0 +1,56 @@
+// 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>
+
+#import "base/mac/cocoa_protocols.h"
+#include "net/base/cookie_monster.h"
+
+@class CocoaCookieTreeNode;
+@class GTMUILocalizerAndLayoutTweaker;
+
+// Controller for the view that displays the details of a cookie,
+// used both in the cookie prompt dialog as well as the
+// show cookies preference sheet of content settings preferences.
+@interface CookieDetailsViewController : NSViewController {
+ @private
+ // Allows direct access to the object controller for
+ // the displayed cookie information.
+ IBOutlet NSObjectController* objectController_;
+
+ // This explicit reference to the layout tweaker is
+ // required because it's necessary to reformat the view when
+ // the content object changes, since the content object may
+ // alter the widths of some of the fields displayed in the view.
+ IBOutlet GTMUILocalizerAndLayoutTweaker* tweaker_;
+}
+
+@property (nonatomic, readonly) BOOL hasExpiration;
+
+- (id)init;
+
+// Configures the cookie detail view that is managed by the controller
+// to display the information about a single cookie, the information
+// for which is explicitly passed in the parameter |content|.
+- (void)setContentObject:(id)content;
+
+// Adjust the size of the view to exactly fix the information text fields
+// that are visible inside it.
+- (void)shrinkViewToFit;
+
+// Called by the cookie tree dialog to establish a binding between
+// the the detail view's object controller and the tree controller.
+// This binding allows the cookie tree to use the detail view unmodified.
+- (void)configureBindingsForTreeController:(NSTreeController*)controller;
+
+// Action sent by the expiration date popup when the user
+// selects the menu item "When I close my browser".
+- (IBAction)setCookieDoesntHaveExplicitExpiration:(id)sender;
+
+// Action sent by the expiration date popup when the user
+// selects the menu item with an explicit date/time of expiration.
+- (IBAction)setCookieHasExplicitExpiration:(id)sender;
+
+@end
+
diff --git a/chrome/browser/ui/cocoa/cookie_details_view_controller.mm b/chrome/browser/ui/cocoa/cookie_details_view_controller.mm
new file mode 100644
index 0000000..9f47a54
--- /dev/null
+++ b/chrome/browser/ui/cocoa/cookie_details_view_controller.mm
@@ -0,0 +1,110 @@
+// 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 "chrome/browser/ui/cocoa/cookie_details_view_controller.h"
+
+#include "app/l10n_util_mac.h"
+#include "app/resource_bundle.h"
+#import "base/mac_util.h"
+#include "base/sys_string_conversions.h"
+#import "chrome/browser/ui/cocoa/cookie_tree_node.h"
+#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
+
+namespace {
+static const int kExtraMarginBelowWhenExpirationEditable = 5;
+}
+
+#pragma mark View Controller
+
+@implementation CookieDetailsViewController
+@dynamic hasExpiration;
+
+- (id)init {
+ return [super initWithNibName:@"CookieDetailsView"
+ bundle:mac_util::MainAppBundle()];
+}
+
+- (void)awakeFromNib {
+ DCHECK(objectController_);
+}
+
+// Finds and returns the y offset of the lowest-most non-hidden
+// text field in the view. This is used to shrink the view
+// appropriately so that it just fits its visible content.
+- (void)getLowestLabelVerticalPosition:(NSView*)view
+ lowestLabelPosition:(float&)lowestLabelPosition {
+ if (![view isHidden]) {
+ if ([view isKindOfClass:[NSTextField class]]) {
+ NSRect frame = [view frame];
+ if (frame.origin.y < lowestLabelPosition) {
+ lowestLabelPosition = frame.origin.y;
+ }
+ }
+ for (NSView* subview in [view subviews]) {
+ [self getLowestLabelVerticalPosition:subview
+ lowestLabelPosition:lowestLabelPosition];
+ }
+ }
+}
+
+- (void)setContentObject:(id)content {
+ // Make sure the view is loaded before we set the content object,
+ // otherwise, the KVO notifications to update the content don't
+ // reach the view and all of the detail values are default
+ // strings.
+ NSView* view = [self view];
+
+ [objectController_ setValue:content forKey:@"content"];
+
+ // View needs to be re-tweaked after setting the content object,
+ // since the expiration date may have changed, changing the
+ // size of the expiration popup.
+ [tweaker_ tweakUI:view];
+}
+
+- (void)shrinkViewToFit {
+ // Adjust the information pane to be exactly the right size
+ // to hold the visible text information fields.
+ NSView* view = [self view];
+ NSRect frame = [view frame];
+ float lowestLabelPosition = frame.origin.y + frame.size.height;
+ [self getLowestLabelVerticalPosition:view
+ lowestLabelPosition:lowestLabelPosition];
+ float verticalDelta = lowestLabelPosition - frame.origin.y;
+
+ // Popup menu for the expiration is taller than the plain
+ // text, give it some more room.
+ if ([[[objectController_ content] details] canEditExpiration]) {
+ verticalDelta -= kExtraMarginBelowWhenExpirationEditable;
+ }
+
+ frame.origin.y += verticalDelta;
+ frame.size.height -= verticalDelta;
+ [[self view] setFrame:frame];
+}
+
+- (void)configureBindingsForTreeController:(NSTreeController*)treeController {
+ // There seems to be a bug in the binding logic that it's not possible
+ // to bind to the selection of the tree controller, the bind seems to
+ // require an additional path segment in the key, thus the use of
+ // selection.self rather than just selection below.
+ [objectController_ bind:@"contentObject"
+ toObject:treeController
+ withKeyPath:@"selection.self"
+ options:nil];
+}
+
+- (IBAction)setCookieDoesntHaveExplicitExpiration:(id)sender {
+ [[[objectController_ content] details] setHasExpiration:NO];
+}
+
+- (IBAction)setCookieHasExplicitExpiration:(id)sender {
+ [[[objectController_ content] details] setHasExpiration:YES];
+}
+
+- (BOOL)hasExpiration {
+ return [[[objectController_ content] details] hasExpiration];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/cookie_details_view_controller_unittest.mm b/chrome/browser/ui/cocoa/cookie_details_view_controller_unittest.mm
new file mode 100644
index 0000000..4a7e5da
--- /dev/null
+++ b/chrome/browser/ui/cocoa/cookie_details_view_controller_unittest.mm
@@ -0,0 +1,88 @@
+// 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.
+
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/cookie_details.h"
+#include "chrome/browser/ui/cocoa/cookie_details_view_controller.h"
+
+namespace {
+
+class CookieDetailsViewControllerTest : public CocoaTest {
+};
+
+static CocoaCookieDetails* CreateTestCookieDetails(BOOL canEditExpiration) {
+ GURL url("http://chromium.org");
+ std::string cookieLine(
+ "PHPSESSID=0123456789abcdef0123456789abcdef; path=/");
+ net::CookieMonster::ParsedCookie pc(cookieLine);
+ net::CookieMonster::CanonicalCookie cookie(url, pc);
+ NSString* origin = base::SysUTF8ToNSString("http://chromium.org");
+ CocoaCookieDetails* details = [CocoaCookieDetails alloc];
+ [details initWithCookie:&cookie
+ origin:origin
+ canEditExpiration:canEditExpiration];
+ return [details autorelease];
+}
+
+static CookiePromptContentDetailsAdapter* CreateCookieTestContent(
+ BOOL canEditExpiration) {
+ CocoaCookieDetails* details = CreateTestCookieDetails(canEditExpiration);
+ return [[[CookiePromptContentDetailsAdapter alloc] initWithDetails:details]
+ autorelease];
+}
+
+static CocoaCookieDetails* CreateTestDatabaseDetails() {
+ std::string domain("chromium.org");
+ string16 name(base::SysNSStringToUTF16(@"wicked_name"));
+ string16 desc(base::SysNSStringToUTF16(@"wicked_desc"));
+ CocoaCookieDetails* details = [CocoaCookieDetails alloc];
+ [details initWithDatabase:domain
+ databaseName:name
+ databaseDescription:desc
+ fileSize:2222];
+ return [details autorelease];
+}
+
+static CookiePromptContentDetailsAdapter* CreateDatabaseTestContent() {
+ CocoaCookieDetails* details = CreateTestDatabaseDetails();
+ return [[[CookiePromptContentDetailsAdapter alloc] initWithDetails:details]
+ autorelease];
+}
+
+TEST_F(CookieDetailsViewControllerTest, Create) {
+ scoped_nsobject<CookieDetailsViewController> detailsViewController(
+ [[CookieDetailsViewController alloc] init]);
+}
+
+TEST_F(CookieDetailsViewControllerTest, ShrinkToFit) {
+ scoped_nsobject<CookieDetailsViewController> detailsViewController(
+ [[CookieDetailsViewController alloc] init]);
+ scoped_nsobject<CookiePromptContentDetailsAdapter> adapter(
+ [CreateDatabaseTestContent() retain]);
+ [detailsViewController.get() setContentObject:adapter.get()];
+ NSRect beforeFrame = [[detailsViewController.get() view] frame];
+ [detailsViewController.get() shrinkViewToFit];
+ NSRect afterFrame = [[detailsViewController.get() view] frame];
+
+ EXPECT_TRUE(afterFrame.size.height < beforeFrame.size.width);
+}
+
+TEST_F(CookieDetailsViewControllerTest, ExpirationEditability) {
+ scoped_nsobject<CookieDetailsViewController> detailsViewController(
+ [[CookieDetailsViewController alloc] init]);
+ [detailsViewController view];
+ scoped_nsobject<CookiePromptContentDetailsAdapter> adapter(
+ [CreateCookieTestContent(YES) retain]);
+ [detailsViewController.get() setContentObject:adapter.get()];
+
+ EXPECT_FALSE([detailsViewController.get() hasExpiration]);
+ [detailsViewController.get() setCookieHasExplicitExpiration:adapter.get()];
+ EXPECT_TRUE([detailsViewController.get() hasExpiration]);
+ [detailsViewController.get()
+ setCookieDoesntHaveExplicitExpiration:adapter.get()];
+ EXPECT_FALSE([detailsViewController.get() hasExpiration]);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/cookie_tree_node.h b/chrome/browser/ui/cocoa/cookie_tree_node.h
new file mode 100644
index 0000000..ec1b2d2
--- /dev/null
+++ b/chrome/browser/ui/cocoa/cookie_tree_node.h
@@ -0,0 +1,37 @@
+// 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 "base/scoped_nsobject.h"
+#include "chrome/browser/cookies_tree_model.h"
+#include "chrome/browser/ui/cocoa/cookie_details.h"
+
+@interface CocoaCookieTreeNode : NSObject {
+ scoped_nsobject<NSString> title_;
+ scoped_nsobject<NSMutableArray> children_;
+ scoped_nsobject<CocoaCookieDetails> details_;
+ CookieTreeNode* treeNode_; // weak
+}
+
+// Designated initializer.
+- (id)initWithNode:(CookieTreeNode*)node;
+
+// Re-sets all the members of the node based on |treeNode_|.
+- (void)rebuild;
+
+// Common getters..
+- (NSString*)title;
+- (CocoaCookieDetailsType)nodeType;
+- (TreeModelNode*)treeNode;
+
+// |-mutableChildren| exists so that the CookiesTreeModelObserverBridge can
+// operate on the children. Note that this lazily creates children.
+- (NSMutableArray*)mutableChildren;
+- (NSArray*)children;
+- (BOOL)isLeaf;
+
+- (CocoaCookieDetails*)details;
+
+@end
diff --git a/chrome/browser/ui/cocoa/cookie_tree_node.mm b/chrome/browser/ui/cocoa/cookie_tree_node.mm
new file mode 100644
index 0000000..fa4da84
--- /dev/null
+++ b/chrome/browser/ui/cocoa/cookie_tree_node.mm
@@ -0,0 +1,73 @@
+// 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 "chrome/browser/ui/cocoa/cookie_tree_node.h"
+
+#include "base/sys_string_conversions.h"
+
+@implementation CocoaCookieTreeNode
+
+- (id)initWithNode:(CookieTreeNode*)node {
+ if ((self = [super init])) {
+ DCHECK(node);
+ treeNode_ = node;
+ [self rebuild];
+ }
+ return self;
+}
+
+- (void)rebuild {
+ title_.reset([base::SysUTF16ToNSString(treeNode_->GetTitle()) retain]);
+ children_.reset();
+ // The tree node assumes ownership of the cookie details object
+ details_.reset([[CocoaCookieDetails createFromCookieTreeNode:(treeNode_)]
+ retain]);
+}
+
+- (NSString*)title {
+ return title_.get();
+}
+
+- (CocoaCookieDetailsType)nodeType {
+ return [details_.get() type];
+}
+
+- (TreeModelNode*)treeNode {
+ return treeNode_;
+}
+
+- (NSMutableArray*)mutableChildren {
+ if (!children_.get()) {
+ const int childCount = treeNode_->GetChildCount();
+ children_.reset([[NSMutableArray alloc] initWithCapacity:childCount]);
+ for (int i = 0; i < childCount; ++i) {
+ CookieTreeNode* child = treeNode_->GetChild(i);
+ scoped_nsobject<CocoaCookieTreeNode> childNode(
+ [[CocoaCookieTreeNode alloc] initWithNode:child]);
+ [children_ addObject:childNode.get()];
+ }
+ }
+ return children_.get();
+}
+
+- (NSArray*)children {
+ return [self mutableChildren];
+}
+
+- (BOOL)isLeaf {
+ return [self nodeType] != kCocoaCookieDetailsTypeFolder;
+};
+
+- (NSString*)description {
+ NSString* format =
+ @"<CocoaCookieTreeNode @ %p (title=%@, nodeType=%d, childCount=%u)";
+ return [NSString stringWithFormat:format, self, [self title],
+ [self nodeType], [[self children] count]];
+}
+
+- (CocoaCookieDetails*)details {
+ return details_;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/cookies_window_controller.h b/chrome/browser/ui/cocoa/cookies_window_controller.h
new file mode 100644
index 0000000..658bfa7
--- /dev/null
+++ b/chrome/browser/ui/cocoa/cookies_window_controller.h
@@ -0,0 +1,146 @@
+// 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>
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/cookies_tree_model.h"
+#import "chrome/browser/ui/cocoa/cookie_tree_node.h"
+#include "net/base/cookie_monster.h"
+
+@class CookiesWindowController;
+@class CookieDetailsViewController;
+class Profile;
+class TreeModel;
+class TreeModelNode;
+
+namespace {
+class CookiesWindowControllerTest;
+}
+
+// Thin bridge to the window controller that performs model update actions
+// directly on the treeController_.
+class CookiesTreeModelObserverBridge : public CookiesTreeModel::Observer {
+ public:
+ explicit CookiesTreeModelObserverBridge(CookiesWindowController* controller);
+
+ // Begin TreeModelObserver implementation.
+ virtual void TreeNodesAdded(TreeModel* model,
+ TreeModelNode* parent,
+ int start,
+ int count);
+ virtual void TreeNodesRemoved(TreeModel* model,
+ TreeModelNode* parent,
+ int start,
+ int count);
+ virtual void TreeNodeChanged(TreeModel* model, TreeModelNode* node);
+ // End TreeModelObserver implementation.
+
+ virtual void TreeModelBeginBatch(CookiesTreeModel* model);
+ virtual void TreeModelEndBatch(CookiesTreeModel* model);
+
+ // Invalidates the Cocoa model. This is used to tear down the Cocoa model
+ // when we're about to entirely rebuild it.
+ void InvalidateCocoaModel();
+
+ private:
+ friend class ::CookiesWindowControllerTest;
+
+ // Creates a CocoaCookieTreeNode from a platform-independent one.
+ // Return value is autoreleased. This creates child nodes recusively.
+ CocoaCookieTreeNode* CocoaNodeFromTreeNode(TreeModelNode* node);
+
+ // Finds the Cocoa model node based on a platform-independent one. This is
+ // done by comparing the treeNode pointers. |start| is the node to start
+ // searching at. If |start| is nil, the root is used.
+ CocoaCookieTreeNode* FindCocoaNode(TreeModelNode* node,
+ CocoaCookieTreeNode* start);
+
+ // Returns whether or not the Cocoa tree model is built.
+ bool HasCocoaModel();
+
+ CookiesWindowController* window_controller_; // weak, owns us.
+
+ // If this is true, then the Model has informed us that it is batching
+ // updates. Rather than updating the Cocoa side of the model, we ignore those
+ // small changes and rebuild once at the end.
+ bool batch_update_;
+};
+
+// Controller for the cookies manager. This class stores an internal copy of
+// the CookiesTreeModel but with Cocoa-converted values (NSStrings and NSImages
+// instead of std::strings and SkBitmaps). Doing this allows us to use bindings
+// for the interface. Changes are pushed to this internal model via a very thin
+// bridge (see above).
+@interface CookiesWindowController : NSWindowController
+ <NSOutlineViewDelegate,
+ NSWindowDelegate> {
+ @private
+ // Platform-independent model and C++/Obj-C bridge components.
+ scoped_ptr<CookiesTreeModel> treeModel_;
+ scoped_ptr<CookiesTreeModelObserverBridge> modelObserver_;
+
+ // Cached array of icons.
+ scoped_nsobject<NSMutableArray> icons_;
+
+ // Our Cocoa copy of the model.
+ scoped_nsobject<CocoaCookieTreeNode> cocoaTreeModel_;
+
+ // A flag indicating whether or not the "Remove" button should be enabled.
+ BOOL removeButtonEnabled_;
+
+ IBOutlet NSTreeController* treeController_;
+ IBOutlet NSOutlineView* outlineView_;
+ IBOutlet NSSearchField* searchField_;
+ IBOutlet NSView* cookieDetailsViewPlaceholder_;
+ IBOutlet NSButton* removeButton_;
+
+ scoped_nsobject<CookieDetailsViewController> detailsViewController_;
+ Profile* profile_; // weak
+ BrowsingDataDatabaseHelper* databaseHelper_; // weak
+ BrowsingDataLocalStorageHelper* storageHelper_; // weak
+ BrowsingDataAppCacheHelper* appcacheHelper_; // weak
+ BrowsingDataIndexedDBHelper* indexedDBHelper_; // weak
+}
+@property (assign, nonatomic) BOOL removeButtonEnabled;
+@property (readonly, nonatomic) NSTreeController* treeController;
+
+// Designated initializer. Profile cannot be NULL.
+- (id)initWithProfile:(Profile*)profile
+ databaseHelper:(BrowsingDataDatabaseHelper*)databaseHelper
+ storageHelper:(BrowsingDataLocalStorageHelper*)storageHelper
+ appcacheHelper:(BrowsingDataAppCacheHelper*)appcacheHelper
+ indexedDBHelper:(BrowsingDataIndexedDBHelper*)indexedDBHelper;
+
+// Shows the cookies window as a modal sheet attached to |window|.
+- (void)attachSheetTo:(NSWindow*)window;
+
+// Updates the filter from the search field.
+- (IBAction)updateFilter:(id)sender;
+
+// Delete cookie actions.
+- (IBAction)deleteCookie:(id)sender;
+- (IBAction)deleteAllCookies:(id)sender;
+
+// Closes the sheet and ends the modal loop. This will also cleanup the memory.
+- (IBAction)closeSheet:(id)sender;
+
+// Returns the cocoaTreeModel_.
+- (CocoaCookieTreeNode*)cocoaTreeModel;
+- (void)setCocoaTreeModel:(CocoaCookieTreeNode*)model;
+
+// Returns the treeModel_.
+- (CookiesTreeModel*)treeModel;
+
+@end
+
+@interface CookiesWindowController (UnitTesting)
+- (void)deleteNodeAtIndexPath:(NSIndexPath*)path;
+- (void)clearBrowsingDataNotification:(NSNotification*)notif;
+- (CookiesTreeModelObserverBridge*)modelObserver;
+- (NSArray*)icons;
+- (void)loadTreeModelFromProfile;
+@end
diff --git a/chrome/browser/ui/cocoa/cookies_window_controller.mm b/chrome/browser/ui/cocoa/cookies_window_controller.mm
new file mode 100644
index 0000000..bf1bf68
--- /dev/null
+++ b/chrome/browser/ui/cocoa/cookies_window_controller.mm
@@ -0,0 +1,448 @@
+// 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 "chrome/browser/ui/cocoa/cookies_window_controller.h"
+
+#include <queue>
+#include <vector>
+
+#include "app/l10n_util_mac.h"
+#include "app/resource_bundle.h"
+#import "base/mac_util.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/browsing_data_remover.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/cocoa/clear_browsing_data_controller.h"
+#include "chrome/browser/ui/cocoa/cookie_details_view_controller.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "skia/ext/skia_utils_mac.h"
+#include "third_party/apple/ImageAndTextCell.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+// Key path used for notifying KVO.
+static NSString* const kCocoaTreeModel = @"cocoaTreeModel";
+
+CookiesTreeModelObserverBridge::CookiesTreeModelObserverBridge(
+ CookiesWindowController* controller)
+ : window_controller_(controller),
+ batch_update_(false) {
+}
+
+// Notification that nodes were added to the specified parent.
+void CookiesTreeModelObserverBridge::TreeNodesAdded(TreeModel* model,
+ TreeModelNode* parent,
+ int start,
+ int count) {
+ // We're in for a major rebuild. Ignore this request.
+ if (batch_update_ || !HasCocoaModel())
+ return;
+
+ CocoaCookieTreeNode* cocoa_parent = FindCocoaNode(parent, nil);
+ NSMutableArray* cocoa_children = [cocoa_parent mutableChildren];
+
+ [window_controller_ willChangeValueForKey:kCocoaTreeModel];
+ CookieTreeNode* cookie_parent = static_cast<CookieTreeNode*>(parent);
+ for (int i = 0; i < count; ++i) {
+ CookieTreeNode* cookie_child = cookie_parent->GetChild(start + i);
+ CocoaCookieTreeNode* new_child = CocoaNodeFromTreeNode(cookie_child);
+ [cocoa_children addObject:new_child];
+ }
+ [window_controller_ didChangeValueForKey:kCocoaTreeModel];
+}
+
+// Notification that nodes were removed from the specified parent.
+void CookiesTreeModelObserverBridge::TreeNodesRemoved(TreeModel* model,
+ TreeModelNode* parent,
+ int start,
+ int count) {
+ // We're in for a major rebuild. Ignore this request.
+ if (batch_update_ || !HasCocoaModel())
+ return;
+
+ CocoaCookieTreeNode* cocoa_parent = FindCocoaNode(parent, nil);
+ [window_controller_ willChangeValueForKey:kCocoaTreeModel];
+ NSMutableArray* cocoa_children = [cocoa_parent mutableChildren];
+ for (int i = start + count - 1; i >= start; --i) {
+ [cocoa_children removeObjectAtIndex:i];
+ }
+ [window_controller_ didChangeValueForKey:kCocoaTreeModel];
+}
+
+// Notification that the contents of a node has changed.
+void CookiesTreeModelObserverBridge::TreeNodeChanged(TreeModel* model,
+ TreeModelNode* node) {
+ // If we don't have a Cocoa model, only let the root node change.
+ if (batch_update_ || (!HasCocoaModel() && model->GetRoot() != node))
+ return;
+
+ if (HasCocoaModel()) {
+ // We still have a Cocoa model, so just rebuild the node.
+ [window_controller_ willChangeValueForKey:kCocoaTreeModel];
+ CocoaCookieTreeNode* changed_node = FindCocoaNode(node, nil);
+ [changed_node rebuild];
+ [window_controller_ didChangeValueForKey:kCocoaTreeModel];
+ } else {
+ // Full rebuild.
+ [window_controller_ setCocoaTreeModel:CocoaNodeFromTreeNode(node)];
+ }
+}
+
+void CookiesTreeModelObserverBridge::TreeModelBeginBatch(
+ CookiesTreeModel* model) {
+ batch_update_ = true;
+}
+
+void CookiesTreeModelObserverBridge::TreeModelEndBatch(
+ CookiesTreeModel* model) {
+ DCHECK(batch_update_);
+ CocoaCookieTreeNode* root = CocoaNodeFromTreeNode(model->GetRoot());
+ [window_controller_ setCocoaTreeModel:root];
+ batch_update_ = false;
+}
+
+void CookiesTreeModelObserverBridge::InvalidateCocoaModel() {
+ [[[window_controller_ cocoaTreeModel] mutableChildren] removeAllObjects];
+}
+
+CocoaCookieTreeNode* CookiesTreeModelObserverBridge::CocoaNodeFromTreeNode(
+ TreeModelNode* node) {
+ CookieTreeNode* cookie_node = static_cast<CookieTreeNode*>(node);
+ return [[[CocoaCookieTreeNode alloc] initWithNode:cookie_node] autorelease];
+}
+
+// Does breadth-first search on the tree to find |node|. This method is most
+// commonly used to find origin/folder nodes, which are at the first level off
+// the root (hence breadth-first search).
+CocoaCookieTreeNode* CookiesTreeModelObserverBridge::FindCocoaNode(
+ TreeModelNode* target, CocoaCookieTreeNode* start) {
+ if (!start) {
+ start = [window_controller_ cocoaTreeModel];
+ }
+ if ([start treeNode] == target) {
+ return start;
+ }
+
+ // Enqueue the root node of the search (sub-)tree.
+ std::queue<CocoaCookieTreeNode*> horizon;
+ horizon.push(start);
+
+ // Loop until we've looked at every node or we found the target.
+ while (!horizon.empty()) {
+ // Dequeue the item at the front.
+ CocoaCookieTreeNode* node = horizon.front();
+ horizon.pop();
+
+ // If this is the droid we're looking for, report it.
+ if ([node treeNode] == target)
+ return node;
+
+ // "Move along, move along." by adding all child nodes to the queue.
+ if (![node isLeaf]) {
+ NSArray* children = [node children];
+ for (CocoaCookieTreeNode* child in children) {
+ horizon.push(child);
+ }
+ }
+ }
+
+ return nil; // We couldn't find the node.
+}
+
+// Returns whether or not the Cocoa tree model is built.
+bool CookiesTreeModelObserverBridge::HasCocoaModel() {
+ return ([[[window_controller_ cocoaTreeModel] children] count] > 0U);
+}
+
+#pragma mark Window Controller
+
+@implementation CookiesWindowController
+
+@synthesize removeButtonEnabled = removeButtonEnabled_;
+@synthesize treeController = treeController_;
+
+- (id)initWithProfile:(Profile*)profile
+ databaseHelper:(BrowsingDataDatabaseHelper*)databaseHelper
+ storageHelper:(BrowsingDataLocalStorageHelper*)storageHelper
+ appcacheHelper:(BrowsingDataAppCacheHelper*)appcacheHelper
+ indexedDBHelper:(BrowsingDataIndexedDBHelper*)indexedDBHelper {
+ DCHECK(profile);
+ NSString* nibpath = [mac_util::MainAppBundle() pathForResource:@"Cookies"
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
+ profile_ = profile;
+ databaseHelper_ = databaseHelper;
+ storageHelper_ = storageHelper;
+ appcacheHelper_ = appcacheHelper;
+ indexedDBHelper_ = indexedDBHelper;
+
+ [self loadTreeModelFromProfile];
+
+ // Register for Clear Browsing Data controller so we update appropriately.
+ ClearBrowsingDataController* clearingController =
+ [ClearBrowsingDataController controllerForProfile:profile_];
+ if (clearingController) {
+ NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+ [center addObserver:self
+ selector:@selector(clearBrowsingDataNotification:)
+ name:kClearBrowsingDataControllerDidDelete
+ object:clearingController];
+ }
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+- (void)awakeFromNib {
+ DCHECK([self window]);
+ DCHECK_EQ(self, [[self window] delegate]);
+
+ detailsViewController_.reset([[CookieDetailsViewController alloc] init]);
+
+ NSView* detailView = [detailsViewController_.get() view];
+ NSRect viewFrameRect = [cookieDetailsViewPlaceholder_ frame];
+ [[detailsViewController_.get() view] setFrame:viewFrameRect];
+ [[cookieDetailsViewPlaceholder_ superview]
+ replaceSubview:cookieDetailsViewPlaceholder_
+ with:detailView];
+
+ [detailsViewController_ configureBindingsForTreeController:treeController_];
+}
+
+- (void)windowWillClose:(NSNotification*)notif {
+ [searchField_ setTarget:nil];
+ [outlineView_ setDelegate:nil];
+ [self autorelease];
+}
+
+- (void)attachSheetTo:(NSWindow*)window {
+ [NSApp beginSheet:[self window]
+ modalForWindow:window
+ modalDelegate:self
+ didEndSelector:@selector(sheetEndSheet:returnCode:contextInfo:)
+ contextInfo:nil];
+}
+
+- (void)sheetEndSheet:(NSWindow*)sheet
+ returnCode:(NSInteger)returnCode
+ contextInfo:(void*)context {
+ [sheet close];
+ [sheet orderOut:self];
+}
+
+- (IBAction)updateFilter:(id)sender {
+ DCHECK([sender isKindOfClass:[NSSearchField class]]);
+ NSString* string = [sender stringValue];
+ // Invalidate the model here because all the nodes are going to be removed
+ // in UpdateSearchResults(). This could lead to there temporarily being
+ // invalid pointers in the Cocoa model.
+ modelObserver_->InvalidateCocoaModel();
+ treeModel_->UpdateSearchResults(base::SysNSStringToWide(string));
+}
+
+- (IBAction)deleteCookie:(id)sender {
+ DCHECK_EQ(1U, [[treeController_ selectedObjects] count]);
+ [self deleteNodeAtIndexPath:[treeController_ selectionIndexPath]];
+}
+
+// This will delete the Cocoa model node as well as the backing model object at
+// the specified index path in the Cocoa model. If the node that was deleted
+// was the sole child of the parent node, this will be called recursively to
+// delete empty parents.
+- (void)deleteNodeAtIndexPath:(NSIndexPath*)path {
+ NSTreeNode* treeNode =
+ [[treeController_ arrangedObjects] descendantNodeAtIndexPath:path];
+ if (!treeNode)
+ return;
+
+ CocoaCookieTreeNode* node = [treeNode representedObject];
+ CookieTreeNode* cookie = static_cast<CookieTreeNode*>([node treeNode]);
+ treeModel_->DeleteCookieNode(cookie);
+ // If there is a next cookie, this will select it because items will slide
+ // up. If there is no next cookie, this is a no-op.
+ [treeController_ setSelectionIndexPath:path];
+ // If the above setting of the selection was in fact a no-op, find the next
+ // node to select.
+ if (![[treeController_ selectedObjects] count]) {
+ NSUInteger lastIndex = [path indexAtPosition:[path length] - 1];
+ if (lastIndex != 0) {
+ // If there any nodes remaining, select the node that is in the list
+ // before this one.
+ path = [path indexPathByRemovingLastIndex];
+ path = [path indexPathByAddingIndex:lastIndex - 1];
+ [treeController_ setSelectionIndexPath:path];
+ }
+ }
+}
+
+- (IBAction)deleteAllCookies:(id)sender {
+ // Preemptively delete all cookies in the Cocoa model.
+ modelObserver_->InvalidateCocoaModel();
+ treeModel_->DeleteAllStoredObjects();
+}
+
+- (IBAction)closeSheet:(id)sender {
+ [NSApp endSheet:[self window]];
+}
+
+- (void)clearBrowsingDataNotification:(NSNotification*)notif {
+ NSNumber* removeMask =
+ [[notif userInfo] objectForKey:kClearBrowsingDataControllerRemoveMask];
+ if ([removeMask intValue] & BrowsingDataRemover::REMOVE_COOKIES) {
+ [self loadTreeModelFromProfile];
+ }
+}
+
+// Override keyDown on the controller (which is the first responder) to allow
+// both backspace and delete to be captured by the Remove button.
+- (void)keyDown:(NSEvent*)theEvent {
+ NSString* keys = [theEvent characters];
+ if ([keys length]) {
+ unichar key = [keys characterAtIndex:0];
+ // The button has a key equivalent of backspace, so examine this event for
+ // forward delete.
+ if ((key == NSDeleteCharacter || key == NSDeleteFunctionKey) &&
+ [self removeButtonEnabled]) {
+ [removeButton_ performClick:self];
+ return;
+ }
+ }
+ [super keyDown:theEvent];
+}
+
+#pragma mark Getters and Setters
+
+- (CocoaCookieTreeNode*)cocoaTreeModel {
+ return cocoaTreeModel_.get();
+}
+- (void)setCocoaTreeModel:(CocoaCookieTreeNode*)model {
+ cocoaTreeModel_.reset([model retain]);
+}
+
+- (CookiesTreeModel*)treeModel {
+ return treeModel_.get();
+}
+
+#pragma mark Outline View Delegate
+
+- (void)outlineView:(NSOutlineView*)outlineView
+ willDisplayCell:(id)cell
+ forTableColumn:(NSTableColumn*)tableColumn
+ item:(id)item {
+ CocoaCookieTreeNode* node = [item representedObject];
+ int index = treeModel_->GetIconIndex([node treeNode]);
+ NSImage* icon = nil;
+ if (index >= 0)
+ icon = [icons_ objectAtIndex:index];
+ else
+ icon = [icons_ lastObject];
+ [(ImageAndTextCell*)cell setImage:icon];
+}
+
+- (void)outlineViewItemDidExpand:(NSNotification*)notif {
+ NSTreeNode* item = [[notif userInfo] objectForKey:@"NSObject"];
+ CocoaCookieTreeNode* node = [item representedObject];
+ NSArray* children = [node children];
+ if ([children count] == 1U) {
+ // The node that will expand has one child. Do the user a favor and expand
+ // that node (saving her a click) if it is non-leaf.
+ CocoaCookieTreeNode* child = [children lastObject];
+ if (![child isLeaf]) {
+ NSOutlineView* outlineView = [notif object];
+ // Tell the OutlineView to expand the NSTreeNode, not the model object.
+ children = [item childNodes];
+ DCHECK_EQ([children count], 1U);
+ [outlineView expandItem:[children lastObject]];
+ // Select the first node in that child set.
+ NSTreeNode* folderChild = [children lastObject];
+ if ([[folderChild childNodes] count] > 0) {
+ NSTreeNode* firstCookieChild =
+ [[folderChild childNodes] objectAtIndex:0];
+ [treeController_ setSelectionIndexPath:[firstCookieChild indexPath]];
+ }
+ }
+ }
+}
+
+- (void)outlineViewSelectionDidChange:(NSNotification*)notif {
+ // Multi-selection should be disabled in the UI, but for sanity, double-check
+ // that they can't do it here.
+ NSArray* selectedObjects = [treeController_ selectedObjects];
+ NSUInteger count = [selectedObjects count];
+ if (count != 1U) {
+ DCHECK_LT(count, 1U) << "User was able to select more than 1 cookie node!";
+ [self setRemoveButtonEnabled:NO];
+ return;
+ }
+
+ // Go through the selection's indexPath and make sure that the node that is
+ // being referenced actually exists in the Cocoa model.
+ NSIndexPath* selection = [treeController_ selectionIndexPath];
+ NSUInteger length = [selection length];
+ CocoaCookieTreeNode* node = [self cocoaTreeModel];
+ for (NSUInteger i = 0; i < length; ++i) {
+ NSUInteger childIndex = [selection indexAtPosition:i];
+ if (childIndex >= [[node children] count]) {
+ [self setRemoveButtonEnabled:NO];
+ return;
+ }
+ node = [[node children] objectAtIndex:childIndex];
+ }
+
+ // If there is a valid selection, make sure that the remove
+ // button is enabled.
+ [self setRemoveButtonEnabled:YES];
+}
+
+#pragma mark Unit Testing
+
+- (CookiesTreeModelObserverBridge*)modelObserver {
+ return modelObserver_.get();
+}
+
+- (NSArray*)icons {
+ return icons_.get();
+}
+
+// Re-initializes the |treeModel_|, creates a new observer for it, and re-
+// builds the |cocoaTreeModel_|. We use this to initialize the controller and
+// to rebuild after the user clears browsing data. Because the models get
+// clobbered, we rebuild the icon cache for safety (though they do not change).
+- (void)loadTreeModelFromProfile {
+ treeModel_.reset(new CookiesTreeModel(
+ profile_->GetRequestContext()->GetCookieStore()->GetCookieMonster(),
+ databaseHelper_,
+ storageHelper_,
+ NULL,
+ appcacheHelper_,
+ indexedDBHelper_));
+ modelObserver_.reset(new CookiesTreeModelObserverBridge(self));
+ treeModel_->AddObserver(modelObserver_.get());
+
+ // Convert the model's icons from Skia to Cocoa.
+ std::vector<SkBitmap> skiaIcons;
+ treeModel_->GetIcons(&skiaIcons);
+ icons_.reset([[NSMutableArray alloc] init]);
+ for (std::vector<SkBitmap>::iterator it = skiaIcons.begin();
+ it != skiaIcons.end(); ++it) {
+ [icons_ addObject:gfx::SkBitmapToNSImage(*it)];
+ }
+
+ // Default icon will be the last item in the array.
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ // TODO(rsesek): Rename this resource now that it's in multiple places.
+ [icons_ addObject:rb.GetNativeImageNamed(IDR_BOOKMARK_BAR_FOLDER)];
+
+ // Create the Cocoa model.
+ CookieTreeNode* root = static_cast<CookieTreeNode*>(treeModel_->GetRoot());
+ scoped_nsobject<CocoaCookieTreeNode> model(
+ [[CocoaCookieTreeNode alloc] initWithNode:root]);
+ [self setCocoaTreeModel:model.get()]; // Takes ownership.
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/cookies_window_controller_unittest.mm b/chrome/browser/ui/cocoa/cookies_window_controller_unittest.mm
new file mode 100644
index 0000000..5272cd2
--- /dev/null
+++ b/chrome/browser/ui/cocoa/cookies_window_controller_unittest.mm
@@ -0,0 +1,687 @@
+// 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 "app/l10n_util_mac.h"
+#include "app/tree_model.h"
+#import "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/browsing_data_remover.h"
+#include "chrome/browser/cookies_tree_model.h"
+#include "chrome/browser/mock_browsing_data_database_helper.h"
+#include "chrome/browser/mock_browsing_data_local_storage_helper.h"
+#include "chrome/browser/mock_browsing_data_appcache_helper.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#include "chrome/browser/ui/cocoa/clear_browsing_data_controller.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/cookies_window_controller.h"
+#include "chrome/common/net/url_request_context_getter.h"
+#include "chrome/test/testing_profile.h"
+#include "googleurl/src/gurl.h"
+#include "grit/generated_resources.h"
+#include "net/url_request/url_request_context.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+
+// Used to test FindCocoaNode. This only sets the title and node, without
+// initializing any other members.
+@interface FakeCocoaCookieTreeNode : CocoaCookieTreeNode {
+ TreeModelNode* testNode_;
+}
+- (id)initWithTreeNode:(TreeModelNode*)node;
+@end
+@implementation FakeCocoaCookieTreeNode
+- (id)initWithTreeNode:(TreeModelNode*)node {
+ if ((self = [super init])) {
+ testNode_ = node;
+ children_.reset([[NSMutableArray alloc] init]);
+ }
+ return self;
+}
+- (TreeModelNode*)treeNode {
+ return testNode_;
+}
+@end
+
+namespace {
+
+class CookiesWindowControllerTest : public CocoaTest {
+ public:
+
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ TestingProfile* profile = browser_helper_.profile();
+ profile->CreateRequestContext();
+ database_helper_ = new MockBrowsingDataDatabaseHelper(profile);
+ local_storage_helper_ = new MockBrowsingDataLocalStorageHelper(profile);
+ appcache_helper_ = new MockBrowsingDataAppCacheHelper(profile);
+ controller_.reset(
+ [[CookiesWindowController alloc] initWithProfile:profile
+ databaseHelper:database_helper_
+ storageHelper:local_storage_helper_
+ appcacheHelper:appcache_helper_]
+ );
+ }
+
+ virtual void TearDown() {
+ CocoaTest::TearDown();
+ }
+
+ CocoaCookieTreeNode* CocoaNodeFromTreeNode(TreeModelNode* node) {
+ return [controller_ modelObserver]->CocoaNodeFromTreeNode(node);
+ }
+
+ CocoaCookieTreeNode* FindCocoaNode(TreeModelNode* node,
+ CocoaCookieTreeNode* start) {
+ return [controller_ modelObserver]->FindCocoaNode(node, start);
+ }
+
+ protected:
+ BrowserTestHelper browser_helper_;
+ scoped_nsobject<CookiesWindowController> controller_;
+ MockBrowsingDataDatabaseHelper* database_helper_;
+ MockBrowsingDataLocalStorageHelper* local_storage_helper_;
+ MockBrowsingDataAppCacheHelper* appcache_helper_;
+};
+
+TEST_F(CookiesWindowControllerTest, Construction) {
+ std::vector<SkBitmap> skia_icons;
+ [controller_ treeModel]->GetIcons(&skia_icons);
+
+ EXPECT_EQ([[controller_ icons] count], skia_icons.size() + 1U);
+}
+
+TEST_F(CookiesWindowControllerTest, FindCocoaNodeRoot) {
+ scoped_ptr< TreeNodeWithValue<int> > search(new TreeNodeWithValue<int>(42));
+ scoped_nsobject<FakeCocoaCookieTreeNode> node(
+ [[FakeCocoaCookieTreeNode alloc] initWithTreeNode:search.get()]);
+ EXPECT_EQ(node.get(), FindCocoaNode(search.get(), node.get()));
+}
+
+TEST_F(CookiesWindowControllerTest, FindCocoaNodeImmediateChild) {
+ scoped_ptr< TreeNodeWithValue<int> > parent(new TreeNodeWithValue<int>(100));
+ scoped_ptr< TreeNodeWithValue<int> > child1(new TreeNodeWithValue<int>(10));
+ scoped_ptr< TreeNodeWithValue<int> > child2(new TreeNodeWithValue<int>(20));
+ scoped_nsobject<FakeCocoaCookieTreeNode> cocoaParent(
+ [[FakeCocoaCookieTreeNode alloc] initWithTreeNode:parent.get()]);
+ scoped_nsobject<FakeCocoaCookieTreeNode> cocoaChild1(
+ [[FakeCocoaCookieTreeNode alloc] initWithTreeNode:child1.get()]);
+ scoped_nsobject<FakeCocoaCookieTreeNode> cocoaChild2(
+ [[FakeCocoaCookieTreeNode alloc] initWithTreeNode:child2.get()]);
+ [[cocoaParent mutableChildren] addObject:cocoaChild1.get()];
+ [[cocoaParent mutableChildren] addObject:cocoaChild2.get()];
+
+ EXPECT_EQ(cocoaChild2.get(), FindCocoaNode(child2.get(), cocoaParent.get()));
+}
+
+TEST_F(CookiesWindowControllerTest, FindCocoaNodeRecursive) {
+ scoped_ptr< TreeNodeWithValue<int> > parent(new TreeNodeWithValue<int>(100));
+ scoped_ptr< TreeNodeWithValue<int> > child1(new TreeNodeWithValue<int>(10));
+ scoped_ptr< TreeNodeWithValue<int> > child2(new TreeNodeWithValue<int>(20));
+ scoped_nsobject<FakeCocoaCookieTreeNode> cocoaParent(
+ [[FakeCocoaCookieTreeNode alloc] initWithTreeNode:parent.get()]);
+ scoped_nsobject<FakeCocoaCookieTreeNode> cocoaChild1(
+ [[FakeCocoaCookieTreeNode alloc] initWithTreeNode:child1.get()]);
+ scoped_nsobject<FakeCocoaCookieTreeNode> cocoaChild2(
+ [[FakeCocoaCookieTreeNode alloc] initWithTreeNode:child2.get()]);
+ [[cocoaParent mutableChildren] addObject:cocoaChild1.get()];
+ [[cocoaChild1 mutableChildren] addObject:cocoaChild2.get()];
+
+ EXPECT_EQ(cocoaChild2.get(), FindCocoaNode(child2.get(), cocoaParent.get()));
+}
+
+TEST_F(CookiesWindowControllerTest, CocoaNodeFromTreeNodeCookie) {
+ net::CookieMonster* cm = browser_helper_.profile()->GetCookieMonster();
+ cm->SetCookie(GURL("http://foo.com"), "A=B");
+ CookiesTreeModel model(cm, database_helper_, local_storage_helper_, nil, nil);
+
+ // Root --> foo.com --> Cookies --> A. Create node for 'A'.
+ TreeModelNode* node = model.GetRoot()->GetChild(0)->GetChild(0)->GetChild(0);
+ CocoaCookieTreeNode* cookie = CocoaNodeFromTreeNode(node);
+
+ CocoaCookieDetails* details = [cookie details];
+ EXPECT_NSEQ(@"B", [details content]);
+ EXPECT_NSEQ(l10n_util::GetNSString(IDS_COOKIES_COOKIE_EXPIRES_SESSION),
+ [details expires]);
+ EXPECT_NSEQ(l10n_util::GetNSString(IDS_COOKIES_COOKIE_SENDFOR_ANY),
+ [details sendFor]);
+ EXPECT_NSEQ(@"A", [cookie title]);
+ EXPECT_NSEQ(@"A", [details name]);
+ EXPECT_NSEQ(@"/", [details path]);
+ EXPECT_EQ(0U, [[cookie children] count]);
+ EXPECT_TRUE([details created]);
+ EXPECT_TRUE([cookie isLeaf]);
+ EXPECT_EQ(node, [cookie treeNode]);
+}
+
+TEST_F(CookiesWindowControllerTest, CocoaNodeFromTreeNodeRecursive) {
+ net::CookieMonster* cm = browser_helper_.profile()->GetCookieMonster();
+ cm->SetCookie(GURL("http://foo.com"), "A=B");
+ CookiesTreeModel model(cm, database_helper_, local_storage_helper_, nil, nil);
+
+ // Root --> foo.com --> Cookies --> A. Create node for 'foo.com'.
+ CookieTreeNode* node = model.GetRoot()->GetChild(0);
+ CocoaCookieTreeNode* domain = CocoaNodeFromTreeNode(node);
+ CocoaCookieTreeNode* cookies = [[domain children] objectAtIndex:0];
+ CocoaCookieTreeNode* cookie = [[cookies children] objectAtIndex:0];
+
+ // Test domain-level node.
+ EXPECT_NSEQ(@"foo.com", [domain title]);
+
+ EXPECT_FALSE([domain isLeaf]);
+ EXPECT_EQ(1U, [[domain children] count]);
+ EXPECT_EQ(node, [domain treeNode]);
+
+ // Test "Cookies" folder node.
+ EXPECT_NSEQ(l10n_util::GetNSString(IDS_COOKIES_COOKIES), [cookies title]);
+ EXPECT_FALSE([cookies isLeaf]);
+ EXPECT_EQ(1U, [[cookies children] count]);
+ EXPECT_EQ(node->GetChild(0), [cookies treeNode]);
+
+ // Test cookie node. This is the same as CocoaNodeFromTreeNodeCookie.
+ CocoaCookieDetails* details = [cookie details];
+ EXPECT_NSEQ(@"B", [details content]);
+ EXPECT_NSEQ(l10n_util::GetNSString(IDS_COOKIES_COOKIE_EXPIRES_SESSION),
+ [details expires]);
+ EXPECT_NSEQ(l10n_util::GetNSString(IDS_COOKIES_COOKIE_SENDFOR_ANY),
+ [details sendFor]);
+ EXPECT_NSEQ(@"A", [cookie title]);
+ EXPECT_NSEQ(@"A", [details name]);
+ EXPECT_NSEQ(@"/", [details path]);
+ EXPECT_NSEQ(@"foo.com", [details domain]);
+ EXPECT_EQ(0U, [[cookie children] count]);
+ EXPECT_TRUE([details created]);
+ EXPECT_TRUE([cookie isLeaf]);
+ EXPECT_EQ(node->GetChild(0)->GetChild(0), [cookie treeNode]);
+}
+
+TEST_F(CookiesWindowControllerTest, TreeNodesAdded) {
+ const GURL url = GURL("http://foo.com");
+ TestingProfile* profile = browser_helper_.profile();
+ net::CookieMonster* cm = profile->GetCookieMonster();
+ cm->SetCookie(url, "A=B");
+
+ controller_.reset(
+ [[CookiesWindowController alloc] initWithProfile:profile
+ databaseHelper:database_helper_
+ storageHelper:local_storage_helper_
+ appcacheHelper:appcache_helper_]);
+
+ // Root --> foo.com --> Cookies.
+ NSMutableArray* cocoa_children =
+ [[[[[[controller_ cocoaTreeModel] children] objectAtIndex:0]
+ children] objectAtIndex:0] mutableChildren];
+ EXPECT_EQ(1U, [cocoa_children count]);
+
+ // Create some cookies.
+ cm->SetCookie(url, "C=D");
+ cm->SetCookie(url, "E=F");
+
+ net::CookieList list = cm->GetAllCookies();
+ CookiesTreeModel* model = [controller_ treeModel];
+ // Root --> foo.com --> Cookies.
+ CookieTreeNode* parent = model->GetRoot()->GetChild(0)->GetChild(0);
+
+ ASSERT_EQ(3U, list.size());
+
+ // Add the cookie nodes.
+ CookieTreeCookieNode* cnode = new CookieTreeCookieNode(&list[1]);
+ parent->Add(1, cnode); // |parent| takes ownership.
+ cnode = new CookieTreeCookieNode(&list[2]);
+ parent->Add(2, cnode);
+
+ // Manually notify the observer.
+ [controller_ modelObserver]->TreeNodesAdded(model, parent, 1, 2);
+
+ // Check that we have created 2 more Cocoa nodes.
+ EXPECT_EQ(3U, [cocoa_children count]);
+}
+
+TEST_F(CookiesWindowControllerTest, TreeNodesRemoved) {
+ const GURL url = GURL("http://foo.com");
+ TestingProfile* profile = browser_helper_.profile();
+ net::CookieMonster* cm = profile->GetCookieMonster();
+ cm->SetCookie(url, "A=B");
+ cm->SetCookie(url, "C=D");
+ cm->SetCookie(url, "E=F");
+
+ controller_.reset(
+ [[CookiesWindowController alloc] initWithProfile:profile
+ databaseHelper:database_helper_
+ storageHelper:local_storage_helper_
+ appcacheHelper:appcache_helper_]);
+
+ // Root --> foo.com --> Cookies.
+ NSMutableArray* cocoa_children =
+ [[[[[[controller_ cocoaTreeModel] children] objectAtIndex:0]
+ children] objectAtIndex:0] mutableChildren];
+ EXPECT_EQ(3U, [cocoa_children count]);
+
+ CookiesTreeModel* model = [controller_ treeModel];
+ // Root --> foo.com --> Cookies.
+ CookieTreeNode* parent = model->GetRoot()->GetChild(0)->GetChild(0);
+
+ // Pretend to remove the nodes.
+ [controller_ modelObserver]->TreeNodesRemoved(model, parent, 1, 2);
+
+ EXPECT_EQ(1U, [cocoa_children count]);
+
+ NSString* title = [[[cocoa_children objectAtIndex:0] details] name];
+ EXPECT_NSEQ(@"A", title);
+}
+
+TEST_F(CookiesWindowControllerTest, TreeNodeChanged) {
+ const GURL url = GURL("http://foo.com");
+ TestingProfile* profile = browser_helper_.profile();
+ net::CookieMonster* cm = profile->GetCookieMonster();
+ cm->SetCookie(url, "A=B");
+
+ controller_.reset(
+ [[CookiesWindowController alloc] initWithProfile:profile
+ databaseHelper:database_helper_
+ storageHelper:local_storage_helper_
+ appcacheHelper:appcache_helper_]);
+
+ CookiesTreeModel* model = [controller_ treeModel];
+ // Root --> foo.com --> Cookies.
+ CookieTreeNode* node = model->GetRoot()->GetChild(0)->GetChild(0);
+
+ // Root --> foo.com --> Cookies.
+ CocoaCookieTreeNode* cocoa_node =
+ [[[[[controller_ cocoaTreeModel] children] objectAtIndex:0]
+ children] objectAtIndex:0];
+
+ EXPECT_NSEQ(l10n_util::GetNSString(IDS_COOKIES_COOKIES),
+ [cocoa_node title]);
+
+ // Fake update the cookie folder's title. This would never happen in reality,
+ // but it tests the code path that ultimately calls CocoaNodeFromTreeNode,
+ // which is tested elsewhere.
+ node->SetTitle(ASCIIToUTF16("Silly Change"));
+ [controller_ modelObserver]->TreeNodeChanged(model, node);
+
+ EXPECT_NSEQ(@"Silly Change", [cocoa_node title]);
+}
+
+TEST_F(CookiesWindowControllerTest, DeleteCookie) {
+ const GURL url = GURL("http://foo.com");
+ TestingProfile* profile = browser_helper_.profile();
+ net::CookieMonster* cm = profile->GetCookieMonster();
+ cm->SetCookie(url, "A=B");
+ cm->SetCookie(url, "C=D");
+ cm->SetCookie(GURL("http://google.com"), "E=F");
+
+ // This will clean itself up when we call |-closeSheet:|. If we reset the
+ // scoper, we'd get a double-free.
+ CookiesWindowController* controller =
+ [[CookiesWindowController alloc] initWithProfile:profile
+ databaseHelper:database_helper_
+ storageHelper:local_storage_helper_
+ appcacheHelper:appcache_helper_];
+ [controller attachSheetTo:test_window()];
+ NSTreeController* treeController = [controller treeController];
+
+ // Select cookie A.
+ NSUInteger pathA[3] = {0, 0, 0};
+ NSIndexPath* indexPath = [NSIndexPath indexPathWithIndexes:pathA length:3];
+ [treeController setSelectionIndexPath:indexPath];
+
+ // Press the "Delete" button.
+ [controller deleteCookie:nil];
+
+ // Root --> foo.com --> Cookies.
+ NSArray* cookies = [[[[[[controller cocoaTreeModel] children]
+ objectAtIndex:0] children] objectAtIndex:0] children];
+ EXPECT_EQ(1U, [cookies count]);
+ EXPECT_NSEQ(@"C", [[cookies lastObject] title]);
+ EXPECT_NSEQ(indexPath, [treeController selectionIndexPath]);
+
+ // Select cookie E.
+ NSUInteger pathE[3] = {1, 0, 0};
+ indexPath = [NSIndexPath indexPathWithIndexes:pathE length:3];
+ [treeController setSelectionIndexPath:indexPath];
+
+ // Perform delete.
+ [controller deleteCookie:nil];
+
+ // Make sure that both the domain level node and the Cookies folder node got
+ // deleted because there was only one leaf node.
+ EXPECT_EQ(1U, [[[controller cocoaTreeModel] children] count]);
+
+ // Select cookie C.
+ NSUInteger pathC[3] = {0, 0, 0};
+ indexPath = [NSIndexPath indexPathWithIndexes:pathC length:3];
+ [treeController setSelectionIndexPath:indexPath];
+
+ // Perform delete.
+ [controller deleteCookie:nil];
+
+ // Make sure the world didn't explode and that there's nothing in the tree.
+ EXPECT_EQ(0U, [[[controller cocoaTreeModel] children] count]);
+
+ [controller closeSheet:nil];
+}
+
+TEST_F(CookiesWindowControllerTest, DidExpandItem) {
+ const GURL url = GURL("http://foo.com");
+ TestingProfile* profile = browser_helper_.profile();
+ net::CookieMonster* cm = profile->GetCookieMonster();
+ cm->SetCookie(url, "A=B");
+ cm->SetCookie(url, "C=D");
+
+ controller_.reset(
+ [[CookiesWindowController alloc] initWithProfile:profile
+ databaseHelper:database_helper_
+ storageHelper:local_storage_helper_
+ appcacheHelper:appcache_helper_]);
+
+ // Root --> foo.com.
+ CocoaCookieTreeNode* foo =
+ [[[controller_ cocoaTreeModel] children] objectAtIndex:0];
+
+ // Create the objects we are going to be testing with.
+ id outlineView = [OCMockObject mockForClass:[NSOutlineView class]];
+ id treeNode = [OCMockObject mockForClass:[NSTreeNode class]];
+ NSTreeNode* childTreeNode =
+ [NSTreeNode treeNodeWithRepresentedObject:[[foo children] lastObject]];
+ NSArray* fakeChildren = [NSArray arrayWithObject:childTreeNode];
+
+ // Set up the mock object.
+ [[[treeNode stub] andReturn:foo] representedObject];
+ [[[treeNode stub] andReturn:fakeChildren] childNodes];
+
+ // Create a fake "ItemDidExpand" notification.
+ NSDictionary* userInfo = [NSDictionary dictionaryWithObject:treeNode
+ forKey:@"NSObject"];
+ NSNotification* notif =
+ [NSNotification notificationWithName:@"ItemDidExpandNotification"
+ object:outlineView
+ userInfo:userInfo];
+
+ // Make sure we work correctly.
+ [[outlineView expect] expandItem:childTreeNode];
+ [controller_ outlineViewItemDidExpand:notif];
+ [outlineView verify];
+}
+
+TEST_F(CookiesWindowControllerTest, ClearBrowsingData) {
+ const GURL url = GURL("http://foo.com");
+ TestingProfile* profile = browser_helper_.profile();
+ net::CookieMonster* cm = profile->GetCookieMonster();
+ cm->SetCookie(url, "A=B");
+ cm->SetCookie(url, "C=D");
+ cm->SetCookie(url, "E=F");
+
+ id mock = [OCMockObject partialMockForObject:controller_.get()];
+ [[mock expect] loadTreeModelFromProfile];
+
+ NSNumber* mask =
+ [NSNumber numberWithInt:BrowsingDataRemover::REMOVE_COOKIES];
+ NSDictionary* userInfo =
+ [NSDictionary dictionaryWithObject:mask
+ forKey:kClearBrowsingDataControllerRemoveMask];
+ NSNotification* notif =
+ [NSNotification notificationWithName:kClearBrowsingDataControllerDidDelete
+ object:nil
+ userInfo:userInfo];
+ [controller_ clearBrowsingDataNotification:notif];
+
+ [mock verify];
+}
+
+// This test has been flaky under Valgrind and turns the bot red since r38504.
+// Under Mac Tests 10.5, it occasionally reports:
+// malloc: *** error for object 0x31e0468: Non-aligned pointer being freed
+// *** set a breakpoint in malloc_error_break to debug
+// Attempts to reproduce locally were not successful. This code is likely
+// changing in the future, so it's marked flaky for now. http://crbug.com/35327
+TEST_F(CookiesWindowControllerTest, FLAKY_RemoveButtonEnabled) {
+ const GURL url = GURL("http://foo.com");
+ TestingProfile* profile = browser_helper_.profile();
+ net::CookieMonster* cm = profile->GetCookieMonster();
+ cm->SetCookie(url, "A=B");
+ cm->SetCookie(url, "C=D");
+
+ // This will clean itself up when we call |-closeSheet:|. If we reset the
+ // scoper, we'd get a double-free.
+ database_helper_ = new MockBrowsingDataDatabaseHelper(profile);
+ local_storage_helper_ = new MockBrowsingDataLocalStorageHelper(profile);
+ local_storage_helper_->AddLocalStorageSamples();
+ CookiesWindowController* controller =
+ [[CookiesWindowController alloc] initWithProfile:profile
+ databaseHelper:database_helper_
+ storageHelper:local_storage_helper_
+ appcacheHelper:appcache_helper_];
+ local_storage_helper_->Notify();
+ [controller attachSheetTo:test_window()];
+
+ // Nothing should be selected right now.
+ EXPECT_FALSE([controller removeButtonEnabled]);
+
+ {
+ // Pretend to select cookie A.
+ NSUInteger path[3] = {0, 0, 0};
+ NSIndexPath* indexPath = [NSIndexPath indexPathWithIndexes:path length:3];
+ [[controller treeController] setSelectionIndexPath:indexPath];
+ [controller outlineViewSelectionDidChange:nil];
+ EXPECT_TRUE([controller removeButtonEnabled]);
+ }
+
+ {
+ // Pretend to select cookie C.
+ NSUInteger path[3] = {0, 0, 1};
+ NSIndexPath* indexPath = [NSIndexPath indexPathWithIndexes:path length:3];
+ [[controller treeController] setSelectionIndexPath:indexPath];
+ [controller outlineViewSelectionDidChange:nil];
+ EXPECT_TRUE([controller removeButtonEnabled]);
+ }
+
+ {
+ // Select a local storage node.
+ NSUInteger path[3] = {2, 0, 0};
+ NSIndexPath* indexPath = [NSIndexPath indexPathWithIndexes:path length:3];
+ [[controller treeController] setSelectionIndexPath:indexPath];
+ [controller outlineViewSelectionDidChange:nil];
+ EXPECT_TRUE([controller removeButtonEnabled]);
+ }
+
+ {
+ // Pretend to select something that isn't there!
+ NSUInteger path[3] = {0, 0, 2};
+ NSIndexPath* indexPath = [NSIndexPath indexPathWithIndexes:path length:3];
+ [[controller treeController] setSelectionIndexPath:indexPath];
+ [controller outlineViewSelectionDidChange:nil];
+ EXPECT_FALSE([controller removeButtonEnabled]);
+ }
+
+ {
+ // Try selecting something that doesn't exist again.
+ NSUInteger path[3] = {7, 1, 4};
+ NSIndexPath* indexPath = [NSIndexPath indexPathWithIndexes:path length:3];
+ [[controller treeController] setSelectionIndexPath:indexPath];
+ [controller outlineViewSelectionDidChange:nil];
+ EXPECT_FALSE([controller removeButtonEnabled]);
+ }
+
+ [controller closeSheet:nil];
+}
+
+TEST_F(CookiesWindowControllerTest, UpdateFilter) {
+ const GURL url = GURL("http://foo.com");
+ TestingProfile* profile = browser_helper_.profile();
+ net::CookieMonster* cm = profile->GetCookieMonster();
+ cm->SetCookie(GURL("http://a.com"), "A=B");
+ cm->SetCookie(GURL("http://aa.com"), "C=D");
+ cm->SetCookie(GURL("http://b.com"), "E=F");
+ cm->SetCookie(GURL("http://d.com"), "G=H");
+ cm->SetCookie(GURL("http://dd.com"), "I=J");
+
+ controller_.reset(
+ [[CookiesWindowController alloc] initWithProfile:profile
+ databaseHelper:database_helper_
+ storageHelper:local_storage_helper_
+ appcacheHelper:appcache_helper_]);
+
+ // Make sure we registered all five cookies.
+ EXPECT_EQ(5U, [[[controller_ cocoaTreeModel] children] count]);
+
+ NSSearchField* field =
+ [[NSSearchField alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
+
+ // Make sure we still have five cookies.
+ [field setStringValue:@""];
+ [controller_ updateFilter:field];
+ EXPECT_EQ(5U, [[[controller_ cocoaTreeModel] children] count]);
+
+ // Search for "a".
+ [field setStringValue:@"a"];
+ [controller_ updateFilter:field];
+ EXPECT_EQ(2U, [[[controller_ cocoaTreeModel] children] count]);
+
+ // Search for "b".
+ [field setStringValue:@"b"];
+ [controller_ updateFilter:field];
+ EXPECT_EQ(1U, [[[controller_ cocoaTreeModel] children] count]);
+
+ // Search for "d".
+ [field setStringValue:@"d"];
+ [controller_ updateFilter:field];
+ EXPECT_EQ(2U, [[[controller_ cocoaTreeModel] children] count]);
+
+ // Search for "e".
+ [field setStringValue:@"e"];
+ [controller_ updateFilter:field];
+ EXPECT_EQ(0U, [[[controller_ cocoaTreeModel] children] count]);
+
+ // Search for "aa".
+ [field setStringValue:@"aa"];
+ [controller_ updateFilter:field];
+ EXPECT_EQ(1U, [[[controller_ cocoaTreeModel] children] count]);
+}
+
+TEST_F(CookiesWindowControllerTest, CreateDatabaseStorageNodes) {
+ TestingProfile* profile = browser_helper_.profile();
+ database_helper_ = new MockBrowsingDataDatabaseHelper(profile);
+ local_storage_helper_ = new MockBrowsingDataLocalStorageHelper(profile);
+ database_helper_->AddDatabaseSamples();
+ controller_.reset(
+ [[CookiesWindowController alloc] initWithProfile:profile
+ databaseHelper:database_helper_
+ storageHelper:local_storage_helper_
+ appcacheHelper:appcache_helper_]);
+ database_helper_->Notify();
+
+ ASSERT_EQ(2U, [[[controller_ cocoaTreeModel] children] count]);
+
+ // Root --> gdbhost1.
+ CocoaCookieTreeNode* node =
+ [[[controller_ cocoaTreeModel] children] objectAtIndex:0];
+ EXPECT_NSEQ(@"gdbhost1", [node title]);
+ EXPECT_EQ(kCocoaCookieDetailsTypeFolder, [node nodeType]);
+ EXPECT_EQ(1U, [[node children] count]);
+
+ // host1 --> Web Databases.
+ node = [[node children] lastObject];
+ EXPECT_NSEQ(l10n_util::GetNSString(IDS_COOKIES_WEB_DATABASES), [node title]);
+ EXPECT_EQ(kCocoaCookieDetailsTypeFolder, [node nodeType]);
+ EXPECT_EQ(1U, [[node children] count]);
+
+ // Database Storage --> db1.
+ node = [[node children] lastObject];
+ EXPECT_NSEQ(@"db1", [node title]);
+ EXPECT_EQ(kCocoaCookieDetailsTypeTreeDatabase, [node nodeType]);
+ CocoaCookieDetails* details = [node details];
+ EXPECT_NSEQ(@"description 1", [details databaseDescription]);
+ EXPECT_TRUE([details lastModified]);
+ EXPECT_TRUE([details fileSize]);
+
+ // Root --> gdbhost2.
+ node =
+ [[[controller_ cocoaTreeModel] children] objectAtIndex:1];
+ EXPECT_NSEQ(@"gdbhost2", [node title]);
+ EXPECT_EQ(kCocoaCookieDetailsTypeFolder, [node nodeType]);
+ EXPECT_EQ(1U, [[node children] count]);
+
+ // host1 --> Web Databases.
+ node = [[node children] lastObject];
+ EXPECT_NSEQ(l10n_util::GetNSString(IDS_COOKIES_WEB_DATABASES), [node title]);
+ EXPECT_EQ(kCocoaCookieDetailsTypeFolder, [node nodeType]);
+ EXPECT_EQ(1U, [[node children] count]);
+
+ // Database Storage --> db2.
+ node = [[node children] lastObject];
+ EXPECT_NSEQ(@"db2", [node title]);
+ EXPECT_EQ(kCocoaCookieDetailsTypeTreeDatabase, [node nodeType]);
+ details = [node details];
+ EXPECT_NSEQ(@"description 2", [details databaseDescription]);
+ EXPECT_TRUE([details lastModified]);
+ EXPECT_TRUE([details fileSize]);
+}
+
+TEST_F(CookiesWindowControllerTest, CreateLocalStorageNodes) {
+ TestingProfile* profile = browser_helper_.profile();
+ net::CookieMonster* cm = profile->GetCookieMonster();
+ cm->SetCookie(GURL("http://google.com"), "A=B");
+ cm->SetCookie(GURL("http://dev.chromium.org"), "C=D");
+ database_helper_ = new MockBrowsingDataDatabaseHelper(profile);
+ local_storage_helper_ = new MockBrowsingDataLocalStorageHelper(profile);
+ local_storage_helper_->AddLocalStorageSamples();
+ controller_.reset(
+ [[CookiesWindowController alloc] initWithProfile:profile
+ databaseHelper:database_helper_
+ storageHelper:local_storage_helper_
+ appcacheHelper:appcache_helper_]);
+ local_storage_helper_->Notify();
+
+ ASSERT_EQ(4U, [[[controller_ cocoaTreeModel] children] count]);
+
+ // Root --> host1.
+ CocoaCookieTreeNode* node =
+ [[[controller_ cocoaTreeModel] children] objectAtIndex:2];
+ EXPECT_NSEQ(@"host1", [node title]);
+ EXPECT_EQ(kCocoaCookieDetailsTypeFolder, [node nodeType]);
+ EXPECT_EQ(1U, [[node children] count]);
+
+ // host1 --> Local Storage.
+ node = [[node children] lastObject];
+ EXPECT_NSEQ(l10n_util::GetNSString(IDS_COOKIES_LOCAL_STORAGE), [node title]);
+ EXPECT_EQ(kCocoaCookieDetailsTypeFolder, [node nodeType]);
+ EXPECT_EQ(1U, [[node children] count]);
+
+ // Local Storage --> http://host1:1/.
+ node = [[node children] lastObject];
+ EXPECT_NSEQ(@"http://host1:1/", [node title]);
+ EXPECT_EQ(kCocoaCookieDetailsTypeTreeLocalStorage, [node nodeType]);
+ EXPECT_NSEQ(@"http://host1:1/", [[node details] domain]);
+ EXPECT_TRUE([[node details] lastModified]);
+ EXPECT_TRUE([[node details] fileSize]);
+
+ // Root --> host2.
+ node =
+ [[[controller_ cocoaTreeModel] children] objectAtIndex:3];
+ EXPECT_NSEQ(@"host2", [node title]);
+ EXPECT_EQ(kCocoaCookieDetailsTypeFolder, [node nodeType]);
+ EXPECT_EQ(1U, [[node children] count]);
+
+ // host2 --> Local Storage.
+ node = [[node children] lastObject];
+ EXPECT_NSEQ(l10n_util::GetNSString(IDS_COOKIES_LOCAL_STORAGE), [node title]);
+ EXPECT_EQ(kCocoaCookieDetailsTypeFolder, [node nodeType]);
+ EXPECT_EQ(1U, [[node children] count]);
+
+ // Local Storage --> http://host2:2/.
+ node = [[node children] lastObject];
+ EXPECT_NSEQ(@"http://host2:2/", [node title]);
+ EXPECT_EQ(kCocoaCookieDetailsTypeTreeLocalStorage, [node nodeType]);
+ EXPECT_NSEQ(@"http://host2:2/", [[node details] domain]);
+ EXPECT_TRUE([[node details] lastModified]);
+ EXPECT_TRUE([[node details] fileSize]);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/custom_home_pages_model.h b/chrome/browser/ui/cocoa/custom_home_pages_model.h
new file mode 100644
index 0000000..2bb94d8
--- /dev/null
+++ b/chrome/browser/ui/cocoa/custom_home_pages_model.h
@@ -0,0 +1,91 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_CUSTOM_HOME_PAGES_MODEL_H_
+#define CHROME_BROWSER_UI_COCOA_CUSTOM_HOME_PAGES_MODEL_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include <vector>
+#include "base/scoped_nsobject.h"
+#include "chrome/browser/history/history.h"
+#include "googleurl/src/gurl.h"
+
+class Profile;
+
+// The model for the "custom home pages" table in preferences. Contains a list
+// of CustomHomePageEntry objects. This is intended to be used with Cocoa
+// bindings.
+//
+// The supported binding is |customHomePages|, a to-many relationship which
+// can be observed with an array controller.
+
+@interface CustomHomePagesModel : NSObject {
+ @private
+ scoped_nsobject<NSMutableArray> entries_;
+ Profile* profile_; // weak, used for loading favicons
+}
+
+// Initialize with |profile|, which must not be NULL. The profile is used for
+// loading favicons for urls.
+- (id)initWithProfile:(Profile*)profile;
+
+// Get/set the urls the model currently contains as a group. Only one change
+// notification will be sent.
+- (std::vector<GURL>)URLs;
+- (void)setURLs:(const std::vector<GURL>&)urls;
+
+// Reloads the URLs from their stored state. This will notify using KVO
+// |customHomePages|.
+- (void)reloadURLs;
+
+// Validates the set of URLs stored in the model. The user may have input bad
+// data. This function removes invalid entries from the model, which will result
+// in anyone observing being updated.
+- (void)validateURLs;
+
+// For binding |customHomePages| to a mutable array controller.
+- (NSUInteger)countOfCustomHomePages;
+- (id)objectInCustomHomePagesAtIndex:(NSUInteger)index;
+- (void)insertObject:(id)object inCustomHomePagesAtIndex:(NSUInteger)index;
+- (void)removeObjectFromCustomHomePagesAtIndex:(NSUInteger)index;
+@end
+
+////////////////////////////////////////////////////////////////////////////////
+
+// An entry representing a single item in the custom home page model. Stores
+// a url and a favicon.
+@interface CustomHomePageEntry : NSObject {
+ @private
+ scoped_nsobject<NSString> url_;
+ scoped_nsobject<NSImage> icon_;
+
+ // If non-zero, indicates we're loading the favicon for the page.
+ HistoryService::Handle icon_handle_;
+}
+
+@property(nonatomic, copy) NSString* URL;
+@property(nonatomic, retain) NSImage* image;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////
+
+@interface CustomHomePagesModel (InternalOrTestingAPI)
+
+// Clears the URL string at the specified index. This constitutes bad data. The
+// validator should scrub the entry from the list the next time it is run.
+- (void)setURLStringEmptyAt:(NSUInteger)index;
+
+@end
+
+// A notification that fires when the URL of one of the entries changes.
+// Prevents interested parties from having to observe all model objects in order
+// to persist changes to a single entry. Changes to the number of items in the
+// model can be observed by watching |customHomePages| via KVO so an additional
+// notification is not sent.
+extern NSString* const kHomepageEntryChangedNotification;
+
+#endif // CHROME_BROWSER_UI_COCOA_CUSTOM_HOME_PAGES_MODEL_H_
diff --git a/chrome/browser/ui/cocoa/custom_home_pages_model.mm b/chrome/browser/ui/cocoa/custom_home_pages_model.mm
new file mode 100644
index 0000000..2e0be88
--- /dev/null
+++ b/chrome/browser/ui/cocoa/custom_home_pages_model.mm
@@ -0,0 +1,140 @@
+// 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 "chrome/browser/ui/cocoa/custom_home_pages_model.h"
+
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/net/url_fixer_upper.h"
+#include "chrome/browser/prefs/session_startup_pref.h"
+
+NSString* const kHomepageEntryChangedNotification =
+ @"kHomepageEntryChangedNotification";
+
+@interface CustomHomePagesModel (Private)
+- (void)setURLsInternal:(const std::vector<GURL>&)urls;
+@end
+
+@implementation CustomHomePagesModel
+
+- (id)initWithProfile:(Profile*)profile {
+ if ((self = [super init])) {
+ profile_ = profile;
+ entries_.reset([[NSMutableArray alloc] init]);
+ }
+ return self;
+}
+
+- (NSUInteger)countOfCustomHomePages {
+ return [entries_ count];
+}
+
+- (id)objectInCustomHomePagesAtIndex:(NSUInteger)index {
+ return [entries_ objectAtIndex:index];
+}
+
+- (void)insertObject:(id)object inCustomHomePagesAtIndex:(NSUInteger)index {
+ [entries_ insertObject:object atIndex:index];
+}
+
+- (void)removeObjectFromCustomHomePagesAtIndex:(NSUInteger)index {
+ [entries_ removeObjectAtIndex:index];
+ // Force a save.
+ [self validateURLs];
+}
+
+// Get/set the urls the model currently contains as a group. These will weed
+// out any URLs that are empty and not add them to the model. As a result,
+// the next time they're persisted to the prefs backend, they'll disappear.
+- (std::vector<GURL>)URLs {
+ std::vector<GURL> urls;
+ for (CustomHomePageEntry* entry in entries_.get()) {
+ const char* urlString = [[entry URL] UTF8String];
+ if (urlString && std::strlen(urlString)) {
+ urls.push_back(GURL(std::string(urlString)));
+ }
+ }
+ return urls;
+}
+
+- (void)setURLs:(const std::vector<GURL>&)urls {
+ [self willChangeValueForKey:@"customHomePages"];
+ [self setURLsInternal:urls];
+ SessionStartupPref pref(SessionStartupPref::GetStartupPref(profile_));
+ pref.urls = urls;
+ SessionStartupPref::SetStartupPref(profile_, pref);
+ [self didChangeValueForKey:@"customHomePages"];
+}
+
+// Converts the C++ URLs to Cocoa objects without notifying KVO.
+- (void)setURLsInternal:(const std::vector<GURL>&)urls {
+ [entries_ removeAllObjects];
+ for (size_t i = 0; i < urls.size(); ++i) {
+ scoped_nsobject<CustomHomePageEntry> entry(
+ [[CustomHomePageEntry alloc] init]);
+ const char* urlString = urls[i].spec().c_str();
+ if (urlString && std::strlen(urlString)) {
+ [entry setURL:[NSString stringWithCString:urlString
+ encoding:NSUTF8StringEncoding]];
+ [entries_ addObject:entry];
+ }
+ }
+}
+
+- (void)reloadURLs {
+ [self willChangeValueForKey:@"customHomePages"];
+ SessionStartupPref pref(SessionStartupPref::GetStartupPref(profile_));
+ [self setURLsInternal:pref.urls];
+ [self didChangeValueForKey:@"customHomePages"];
+}
+
+- (void)validateURLs {
+ [self setURLs:[self URLs]];
+}
+
+- (void)setURLStringEmptyAt:(NSUInteger)index {
+ // This replaces the data at |index| with an empty (invalid) URL string.
+ CustomHomePageEntry* entry = [entries_ objectAtIndex:index];
+ [entry setURL:[NSString stringWithString:@""]];
+}
+
+@end
+
+//---------------------------------------------------------------------------
+
+@implementation CustomHomePageEntry
+
+- (void)setURL:(NSString*)url {
+ // |url| can be nil if the user cleared the text from the edit field.
+ if (!url)
+ url = [NSString stringWithString:@""];
+
+ // Make sure the url is valid before setting it by fixing it up.
+ std::string fixedUrl(URLFixerUpper::FixupURL(
+ base::SysNSStringToUTF8(url), std::string()).possibly_invalid_spec());
+ url_.reset([base::SysUTF8ToNSString(fixedUrl) retain]);
+
+ // Broadcast that an individual item has changed.
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName:kHomepageEntryChangedNotification object:nil];
+
+ // TODO(pinkerton): fetch favicon, convert to NSImage http://crbug.com/34642
+}
+
+- (NSString*)URL {
+ return url_.get();
+}
+
+- (void)setImage:(NSImage*)image {
+ icon_.reset(image);
+}
+
+- (NSImage*)image {
+ return icon_.get();
+}
+
+- (NSString*)description {
+ return url_.get();
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/custom_home_pages_model_unittest.mm b/chrome/browser/ui/cocoa/custom_home_pages_model_unittest.mm
new file mode 100644
index 0000000..c744775
--- /dev/null
+++ b/chrome/browser/ui/cocoa/custom_home_pages_model_unittest.mm
@@ -0,0 +1,196 @@
+// 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.
+
+#include "base/scoped_nsobject.h"
+#include "chrome/browser/prefs/session_startup_pref.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/custom_home_pages_model.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+// A helper for KVO and NSNotifications. Makes a note that it's been called
+// back.
+@interface CustomHomePageHelper : NSObject {
+ @public
+ BOOL sawNotification_;
+}
+@end
+
+@implementation CustomHomePageHelper
+- (void)observeValueForKeyPath:(NSString*)keyPath
+ ofObject:(id)object
+ change:(NSDictionary*)change
+ context:(void*)context {
+ sawNotification_ = YES;
+}
+
+- (void)entryChanged:(NSNotification*)notify {
+ sawNotification_ = YES;
+}
+@end
+
+@interface NSObject ()
+- (void)setURL:(NSString*)url;
+@end
+
+namespace {
+
+// Helper that creates an autoreleased entry.
+CustomHomePageEntry* MakeEntry(NSString* url) {
+ CustomHomePageEntry* entry = [[[CustomHomePageEntry alloc] init] autorelease];
+ [entry setURL:url];
+ return entry;
+}
+
+// Helper that casts from |id| to the Entry type and returns the URL string.
+NSString* EntryURL(id entry) {
+ return [static_cast<CustomHomePageEntry*>(entry) URL];
+}
+
+class CustomHomePagesModelTest : public PlatformTest {
+ public:
+ CustomHomePagesModelTest() {
+ model_.reset([[CustomHomePagesModel alloc]
+ initWithProfile:helper_.profile()]);
+ }
+ ~CustomHomePagesModelTest() { }
+
+ BrowserTestHelper helper_;
+ scoped_nsobject<CustomHomePagesModel> model_;
+};
+
+TEST_F(CustomHomePagesModelTest, Init) {
+ scoped_nsobject<CustomHomePagesModel> model(
+ [[CustomHomePagesModel alloc] initWithProfile:helper_.profile()]);
+}
+
+TEST_F(CustomHomePagesModelTest, GetSetURLs) {
+ // Basic test.
+ std::vector<GURL> urls;
+ urls.push_back(GURL("http://www.google.com"));
+ [model_ setURLs:urls];
+ std::vector<GURL> received_urls = [model_.get() URLs];
+ EXPECT_EQ(received_urls.size(), 1U);
+ EXPECT_TRUE(urls[0] == received_urls[0]);
+
+ // Set an empty list, make sure we get back an empty list.
+ std::vector<GURL> empty;
+ [model_ setURLs:empty];
+ received_urls = [model_.get() URLs];
+ EXPECT_EQ(received_urls.size(), 0U);
+
+ // Give it a list with not well-formed URLs and make sure we get back.
+ // only the good ones.
+ std::vector<GURL> poorly_formed;
+ poorly_formed.push_back(GURL("http://www.google.com")); // good
+ poorly_formed.push_back(GURL("www.google.com")); // bad
+ poorly_formed.push_back(GURL("www.yahoo.")); // bad
+ poorly_formed.push_back(GURL("http://www.yahoo.com")); // good
+ [model_ setURLs:poorly_formed];
+ received_urls = [model_.get() URLs];
+ EXPECT_EQ(received_urls.size(), 2U);
+}
+
+// Test that we get a KVO notification when called setURLs.
+TEST_F(CustomHomePagesModelTest, KVOObserveWhenListChanges) {
+ scoped_nsobject<CustomHomePageHelper> kvo_helper(
+ [[CustomHomePageHelper alloc] init]);
+ [model_ addObserver:kvo_helper
+ forKeyPath:@"customHomePages"
+ options:0L
+ context:NULL];
+ EXPECT_FALSE(kvo_helper.get()->sawNotification_);
+
+ std::vector<GURL> urls;
+ urls.push_back(GURL("http://www.google.com"));
+ [model_ setURLs:urls]; // Should send kvo change notification.
+ EXPECT_TRUE(kvo_helper.get()->sawNotification_);
+
+ [model_ removeObserver:kvo_helper forKeyPath:@"customHomePages"];
+}
+
+// Test the KVO "to-many" bindings for |customHomePages| and the KVO
+// notifiation when items are added to and removed from the list.
+TEST_F(CustomHomePagesModelTest, KVO) {
+ EXPECT_EQ([model_ countOfCustomHomePages], 0U);
+
+ scoped_nsobject<CustomHomePageHelper> kvo_helper(
+ [[CustomHomePageHelper alloc] init]);
+ [model_ addObserver:kvo_helper
+ forKeyPath:@"customHomePages"
+ options:0L
+ context:NULL];
+ EXPECT_FALSE(kvo_helper.get()->sawNotification_);
+
+ // Cheat and insert NSString objects into the array. As long as we don't
+ // call -URLs, we'll be ok.
+ [model_ insertObject:MakeEntry(@"www.google.com") inCustomHomePagesAtIndex:0];
+ EXPECT_TRUE(kvo_helper.get()->sawNotification_);
+ [model_ insertObject:MakeEntry(@"www.yahoo.com") inCustomHomePagesAtIndex:1];
+ [model_ insertObject:MakeEntry(@"dev.chromium.org")
+ inCustomHomePagesAtIndex:2];
+ EXPECT_EQ([model_ countOfCustomHomePages], 3U);
+
+ EXPECT_NSEQ(@"http://www.yahoo.com/",
+ EntryURL([model_ objectInCustomHomePagesAtIndex:1]));
+
+ kvo_helper.get()->sawNotification_ = NO;
+ [model_ removeObjectFromCustomHomePagesAtIndex:1];
+ EXPECT_TRUE(kvo_helper.get()->sawNotification_);
+ EXPECT_EQ([model_ countOfCustomHomePages], 2U);
+ EXPECT_NSEQ(@"http://dev.chromium.org/",
+ EntryURL([model_ objectInCustomHomePagesAtIndex:1]));
+ EXPECT_NSEQ(@"http://www.google.com/",
+ EntryURL([model_ objectInCustomHomePagesAtIndex:0]));
+
+ [model_ removeObserver:kvo_helper forKeyPath:@"customHomePages"];
+}
+
+// Test that when individual items are changed that they broadcast a message.
+TEST_F(CustomHomePagesModelTest, ModelChangedNotification) {
+ scoped_nsobject<CustomHomePageHelper> kvo_helper(
+ [[CustomHomePageHelper alloc] init]);
+ [[NSNotificationCenter defaultCenter]
+ addObserver:kvo_helper
+ selector:@selector(entryChanged:)
+ name:kHomepageEntryChangedNotification
+ object:nil];
+
+ std::vector<GURL> urls;
+ urls.push_back(GURL("http://www.google.com"));
+ [model_ setURLs:urls];
+ NSObject* entry = [model_ objectInCustomHomePagesAtIndex:0];
+ [entry setURL:@"http://www.foo.bar"];
+ EXPECT_TRUE(kvo_helper.get()->sawNotification_);
+ [[NSNotificationCenter defaultCenter] removeObserver:kvo_helper];
+}
+
+TEST_F(CustomHomePagesModelTest, ReloadURLs) {
+ scoped_nsobject<CustomHomePageHelper> kvo_helper(
+ [[CustomHomePageHelper alloc] init]);
+ [model_ addObserver:kvo_helper
+ forKeyPath:@"customHomePages"
+ options:0L
+ context:NULL];
+ EXPECT_FALSE(kvo_helper.get()->sawNotification_);
+ EXPECT_EQ([model_ countOfCustomHomePages], 0U);
+
+ std::vector<GURL> urls;
+ urls.push_back(GURL("http://www.google.com"));
+ SessionStartupPref pref;
+ pref.urls = urls;
+ SessionStartupPref::SetStartupPref(helper_.profile(), pref);
+
+ [model_ reloadURLs];
+
+ EXPECT_TRUE(kvo_helper.get()->sawNotification_);
+ EXPECT_EQ([model_ countOfCustomHomePages], 1U);
+ EXPECT_NSEQ(@"http://www.google.com/",
+ EntryURL([model_ objectInCustomHomePagesAtIndex:0]));
+
+ [model_ removeObserver:kvo_helper.get() forKeyPath:@"customHomePages"];
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/delayedmenu_button.h b/chrome/browser/ui/cocoa/delayedmenu_button.h
new file mode 100644
index 0000000..6363d30
--- /dev/null
+++ b/chrome/browser/ui/cocoa/delayedmenu_button.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_DELAYEDMENU_BUTTON_H_
+#define CHROME_BROWSER_UI_COCOA_DELAYEDMENU_BUTTON_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+
+@interface DelayedMenuButton : NSButton {
+ NSMenu* attachedMenu_; // Strong (retained).
+ BOOL attachedMenuEnabled_;
+ scoped_nsobject<NSPopUpButtonCell> popUpCell_;
+}
+
+// The menu to display. Note that it should have no (i.e., a blank) title and
+// that the 0-th entry should be blank (and won't be displayed). (This is
+// because we use a pulldown list, for which Cocoa uses the 0-th item as "title"
+// in the button. This might change if we ever switch to a pop-up. Our direct
+// use of the given NSMenu object means that the one can set and use NSMenu's
+// delegate as usual.)
+@property(retain, nonatomic) NSMenu* attachedMenu;
+
+// Is the menu enabled? (If not, don't act like a click-hold button.)
+@property(assign, nonatomic) BOOL attachedMenuEnabled;
+
+@end // @interface DelayedMenuButton
+
+#endif // CHROME_BROWSER_UI_COCOA_DELAYEDMENU_BUTTON_H_
diff --git a/chrome/browser/ui/cocoa/delayedmenu_button.mm b/chrome/browser/ui/cocoa/delayedmenu_button.mm
new file mode 100644
index 0000000..9a9d73d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/delayedmenu_button.mm
@@ -0,0 +1,137 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/delayedmenu_button.h"
+
+#include "base/logging.h"
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/clickhold_button_cell.h"
+
+@interface DelayedMenuButton (Private)
+
+- (void)setupCell;
+- (void)attachedMenuAction:(id)sender;
+
+@end // @interface DelayedMenuButton (Private)
+
+@implementation DelayedMenuButton
+
+// Overrides:
+
++ (Class)cellClass {
+ return [ClickHoldButtonCell class];
+}
+
+- (id)init {
+ if ((self = [super init]))
+ [self setupCell];
+ return self;
+}
+
+- (id)initWithCoder:(NSCoder*)decoder {
+ if ((self = [super initWithCoder:decoder]))
+ [self setupCell];
+ return self;
+}
+
+- (id)initWithFrame:(NSRect)frameRect {
+ if ((self = [super initWithFrame:frameRect]))
+ [self setupCell];
+ return self;
+}
+
+- (void)dealloc {
+ [attachedMenu_ release];
+ [super dealloc];
+}
+
+- (void)awakeFromNib {
+ [self setupCell];
+}
+
+- (void)setCell:(NSCell*)cell {
+ [super setCell:cell];
+ [self setupCell];
+}
+
+// Accessors and mutators:
+
+@synthesize attachedMenu = attachedMenu_;
+
+// Don't synthesize for attachedMenuEnabled_; its mutator must do other things.
+- (void)setAttachedMenuEnabled:(BOOL)enabled {
+ attachedMenuEnabled_ = enabled;
+ [[self cell] setEnableClickHold:attachedMenuEnabled_];
+}
+
+- (BOOL)attachedMenuEnabled {
+ return attachedMenuEnabled_;
+}
+
+@end // @implementation DelayedMenuButton
+
+@implementation DelayedMenuButton (Private)
+
+// Set up the button's cell if we've reached a point where it's been set.
+- (void)setupCell {
+ ClickHoldButtonCell* cell = [self cell];
+ if (cell) {
+ DCHECK([cell isKindOfClass:[ClickHoldButtonCell class]]);
+ [self setEnabled:NO]; // Make the controller put in a menu and
+ // enable it explicitly. This also takes
+ // care of |[cell setEnableClickHold:]|.
+ [cell setClickHoldAction:@selector(attachedMenuAction:)];
+ [cell setClickHoldTarget:self];
+ }
+}
+
+// Display the menu.
+- (void)attachedMenuAction:(id)sender {
+ // We shouldn't get here unless the menu is enabled.
+ DCHECK(attachedMenuEnabled_);
+
+ // If we don't have a menu (in which case the person using this control is
+ // being bad), just wait for a mouse up.
+ if (!attachedMenu_) {
+ LOG(WARNING) << "No menu available.";
+ [NSApp nextEventMatchingMask:NSLeftMouseUpMask
+ untilDate:[NSDate distantFuture]
+ inMode:NSEventTrackingRunLoopMode
+ dequeue:YES];
+ return;
+ }
+
+ // TODO(viettrungluu): We have some fudge factors below to make things line up
+ // (approximately). I wish I knew how to get rid of them. (Note that our view
+ // is flipped, and that frame should be in our coordinates.) The y/height is
+ // very odd, since it doesn't seem to respond to changes the way that it
+ // should. I don't understand it.
+ NSRect frame = [self convertRect:[self frame]
+ fromView:[self superview]];
+ frame.origin.x -= 2.0;
+ frame.size.height += 10.0;
+
+ // Make our pop-up button cell and set things up. This is, as of 10.5, the
+ // official Apple-recommended hack. Later, perhaps |-[NSMenu
+ // popUpMenuPositioningItem:atLocation:inView:]| may be a better option.
+ // However, using a pulldown has the benefit that Cocoa automatically places
+ // the menu correctly even when we're at the edge of the screen (including
+ // "dragging upwards" when the button is close to the bottom of the screen).
+ // A |scoped_nsobject| local variable cannot be used here because
+ // Accessibility on 10.5 grabs the NSPopUpButtonCell without retaining it, and
+ // uses it later. (This is fixed in 10.6.)
+ if (!popUpCell_.get()) {
+ popUpCell_.reset([[NSPopUpButtonCell alloc] initTextCell:@""
+ pullsDown:YES]);
+ }
+ DCHECK(popUpCell_.get());
+ [popUpCell_ setMenu:attachedMenu_];
+ [popUpCell_ selectItem:nil];
+ [popUpCell_ attachPopUpWithFrame:frame
+ inView:self];
+ [popUpCell_ performClickWithFrame:frame
+ inView:self];
+}
+
+@end // @implementation DelayedMenuButton (Private)
diff --git a/chrome/browser/ui/cocoa/delayedmenu_button_unittest.mm b/chrome/browser/ui/cocoa/delayedmenu_button_unittest.mm
new file mode 100644
index 0000000..d1d7b77
--- /dev/null
+++ b/chrome/browser/ui/cocoa/delayedmenu_button_unittest.mm
@@ -0,0 +1,62 @@
+// Copyright (c) 2009 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 "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/clickhold_button_cell.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/delayedmenu_button.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class DelayedMenuButtonTest : public CocoaTest {
+ public:
+ DelayedMenuButtonTest() {
+ NSRect frame = NSMakeRect(0, 0, 50, 30);
+ scoped_nsobject<DelayedMenuButton>button([[DelayedMenuButton alloc]
+ initWithFrame:frame]);
+ button_ = button.get();
+ scoped_nsobject<ClickHoldButtonCell> cell(
+ [[ClickHoldButtonCell alloc] initTextCell:@"Testing"]);
+ [button_ setCell:cell.get()];
+ [[test_window() contentView] addSubview:button_];
+ }
+
+ DelayedMenuButton* button_;
+};
+
+TEST_VIEW(DelayedMenuButtonTest, button_)
+
+// Test assigning and enabling a menu, again mostly to ensure nothing leaks or
+// crashes.
+TEST_F(DelayedMenuButtonTest, MenuAssign) {
+ scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@""]);
+ ASSERT_TRUE(menu.get());
+
+ [menu insertItemWithTitle:@"" action:nil keyEquivalent:@"" atIndex:0];
+ [menu insertItemWithTitle:@"foo" action:nil keyEquivalent:@"" atIndex:1];
+ [menu insertItemWithTitle:@"bar" action:nil keyEquivalent:@"" atIndex:2];
+ [menu insertItemWithTitle:@"baz" action:nil keyEquivalent:@"" atIndex:3];
+
+ [button_ setAttachedMenu:menu];
+ EXPECT_TRUE([button_ attachedMenu]);
+
+ [button_ setAttachedMenuEnabled:YES];
+ EXPECT_TRUE([button_ attachedMenuEnabled]);
+
+ // TODO(viettrungluu): Display the menu. (Calling DelayedMenuButton's private
+ // |-attachedMenuAction:| method displays it fine, but the problem is
+ // getting rid of the menu. We can catch the
+ // |NSMenuDidBeginTrackingNotification| from |menu| fine, but then
+ // |-cancelTracking| doesn't dismiss it. I don't know why.)
+}
+
+// TODO(viettrungluu): Test the two actions of the button (the normal one and
+// displaying the menu, also making sure the latter drags correctly)? It would
+// require "emulating" a mouse....
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/dev_tools_controller.h b/chrome/browser/ui/cocoa/dev_tools_controller.h
new file mode 100644
index 0000000..c89a9f8
--- /dev/null
+++ b/chrome/browser/ui/cocoa/dev_tools_controller.h
@@ -0,0 +1,51 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_DEV_TOOLS_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_DEV_TOOLS_CONTROLLER_H_
+#pragma once
+
+#import <Foundation/Foundation.h>
+
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/tab_contents_controller.h"
+
+@class NSSplitView;
+@class NSView;
+
+class TabContents;
+
+// A class that handles updates of the devTools view within a browser window.
+// It swaps in the relevant devTools contents for a given TabContents or removes
+// the vew, if there's no devTools contents to show.
+@interface DevToolsController : NSObject {
+ @private
+ // A view hosting docked devTools contents.
+ scoped_nsobject<NSSplitView> splitView_;
+
+ // Manages currently displayed devTools contents.
+ scoped_nsobject<TabContentsController> contentsController_;
+}
+
+- (id)initWithDelegate:(id<TabContentsControllerDelegate>)delegate;
+
+// This controller's view.
+- (NSView*)view;
+
+// The compiler seems to have trouble handling a function named "view" that
+// returns an NSSplitView, so provide a differently-named method.
+- (NSSplitView*)splitView;
+
+// Depending on |contents|'s state, decides whether the docked web inspector
+// should be shown or hidden and adjusts its height (|delegate_| handles
+// the actual resize).
+- (void)updateDevToolsForTabContents:(TabContents*)contents;
+
+// Call when the devTools view is properly sized and the render widget host view
+// should be put into the view hierarchy.
+- (void)ensureContentsVisible;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_DEV_TOOLS_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/dev_tools_controller.mm b/chrome/browser/ui/cocoa/dev_tools_controller.mm
new file mode 100644
index 0000000..596bdae
--- /dev/null
+++ b/chrome/browser/ui/cocoa/dev_tools_controller.mm
@@ -0,0 +1,164 @@
+// 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 "chrome/browser/ui/cocoa/dev_tools_controller.h"
+
+#include <algorithm>
+
+#include <Cocoa/Cocoa.h>
+
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/debugger/devtools_window.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/browser.h"
+#import "chrome/browser/ui/cocoa/view_id_util.h"
+#include "chrome/common/pref_names.h"
+
+namespace {
+
+// Default offset of the contents splitter in pixels.
+const int kDefaultContentsSplitOffset = 400;
+
+// Never make the web part of the tab contents smaller than this (needed if the
+// window is only a few pixels high).
+const int kMinWebHeight = 50;
+
+} // end namespace
+
+
+@interface DevToolsController (Private)
+- (void)showDevToolsContents:(TabContents*)devToolsContents;
+- (void)resizeDevToolsToNewHeight:(CGFloat)height;
+@end
+
+
+@implementation DevToolsController
+
+- (id)initWithDelegate:(id<TabContentsControllerDelegate>)delegate {
+ if ((self = [super init])) {
+ splitView_.reset([[NSSplitView alloc] initWithFrame:NSZeroRect]);
+ [splitView_ setDividerStyle:NSSplitViewDividerStyleThin];
+ [splitView_ setVertical:NO];
+ [splitView_ setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
+ [splitView_ setDelegate:self];
+
+ contentsController_.reset(
+ [[TabContentsController alloc] initWithContents:NULL
+ delegate:delegate]);
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [splitView_ setDelegate:nil];
+ [super dealloc];
+}
+
+- (NSView*)view {
+ return splitView_.get();
+}
+
+- (NSSplitView*)splitView {
+ return splitView_.get();
+}
+
+- (void)updateDevToolsForTabContents:(TabContents*)contents {
+ // Get current devtools content.
+ TabContents* devToolsContents = contents ?
+ DevToolsWindow::GetDevToolsContents(contents) : NULL;
+
+ [self showDevToolsContents:devToolsContents];
+}
+
+- (void)ensureContentsVisible {
+ [contentsController_ ensureContentsVisible];
+}
+
+- (void)showDevToolsContents:(TabContents*)devToolsContents {
+ [contentsController_ ensureContentsSizeDoesNotChange];
+
+ NSArray* subviews = [splitView_ subviews];
+ if (devToolsContents) {
+ DCHECK_GE([subviews count], 1u);
+
+ // |devToolsView| is a TabContentsViewCocoa object, whose ViewID was
+ // set to VIEW_ID_TAB_CONTAINER initially, so we need to change it to
+ // VIEW_ID_DEV_TOOLS_DOCKED here.
+ view_id_util::SetID(
+ devToolsContents->GetNativeView(), VIEW_ID_DEV_TOOLS_DOCKED);
+
+ CGFloat splitOffset = 0;
+ if ([subviews count] == 1) {
+ // Load the default split offset.
+ splitOffset = g_browser_process->local_state()->GetInteger(
+ prefs::kDevToolsSplitLocation);
+ if (splitOffset < 0) {
+ // Initial load, set to default value.
+ splitOffset = kDefaultContentsSplitOffset;
+ }
+ [splitView_ addSubview:[contentsController_ view]];
+ } else {
+ DCHECK_EQ([subviews count], 2u);
+ // If devtools are already visible, keep the current size.
+ splitOffset = NSHeight([[subviews objectAtIndex:1] frame]);
+ }
+
+ // Make sure |splitOffset| isn't too large or too small.
+ splitOffset = std::max(static_cast<CGFloat>(kMinWebHeight), splitOffset);
+ splitOffset =
+ std::min(splitOffset, NSHeight([splitView_ frame]) - kMinWebHeight);
+ DCHECK_GE(splitOffset, 0) << "kMinWebHeight needs to be smaller than "
+ << "smallest available tab contents space.";
+
+ [self resizeDevToolsToNewHeight:splitOffset];
+ } else {
+ if ([subviews count] > 1) {
+ NSView* oldDevToolsContentsView = [subviews objectAtIndex:1];
+ // Store split offset when hiding devtools window only.
+ int splitOffset = NSHeight([oldDevToolsContentsView frame]);
+ g_browser_process->local_state()->SetInteger(
+ prefs::kDevToolsSplitLocation, splitOffset);
+ [oldDevToolsContentsView removeFromSuperview];
+ [splitView_ adjustSubviews];
+ }
+ }
+
+ [contentsController_ changeTabContents:devToolsContents];
+}
+
+- (void)resizeDevToolsToNewHeight:(CGFloat)height {
+ NSArray* subviews = [splitView_ subviews];
+
+ // It seems as if |-setPosition:ofDividerAtIndex:| should do what's needed,
+ // but I can't figure out how to use it. Manually resize web and devtools.
+ // TODO(alekseys): either make setPosition:ofDividerAtIndex: work or to add a
+ // category on NSSplitView to handle manual resizing.
+ NSView* devToolsView = [subviews objectAtIndex:1];
+ NSRect devToolsFrame = [devToolsView frame];
+ devToolsFrame.size.height = height;
+ [devToolsView setFrame:devToolsFrame];
+
+ NSView* webView = [subviews objectAtIndex:0];
+ NSRect webFrame = [webView frame];
+ webFrame.size.height =
+ NSHeight([splitView_ frame]) - ([splitView_ dividerThickness] + height);
+ [webView setFrame:webFrame];
+
+ [splitView_ adjustSubviews];
+}
+
+// NSSplitViewDelegate protocol.
+- (BOOL)splitView:(NSSplitView *)splitView
+ shouldAdjustSizeOfSubview:(NSView *)subview {
+ // Return NO for the devTools view to indicate that it should not be resized
+ // automatically. It preserves the height set by the user and also keeps
+ // view height the same while changing tabs when one of the tabs shows infobar
+ // and others are not.
+ if ([[splitView_ subviews] indexOfObject:subview] == 1)
+ return NO;
+ return YES;
+}
+
+@end
diff --git a/chrome/browser/cocoa/dock_icon.h b/chrome/browser/ui/cocoa/dock_icon.h
index 4a96537..4a96537 100644
--- a/chrome/browser/cocoa/dock_icon.h
+++ b/chrome/browser/ui/cocoa/dock_icon.h
diff --git a/chrome/browser/ui/cocoa/dock_icon.mm b/chrome/browser/ui/cocoa/dock_icon.mm
new file mode 100644
index 0000000..980519a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/dock_icon.mm
@@ -0,0 +1,224 @@
+// 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 "chrome/browser/ui/cocoa/dock_icon.h"
+
+#include "base/scoped_nsobject.h"
+
+// The fraction of the size of the dock icon that the badge is.
+static const float kBadgeFraction = 0.4f;
+
+// The indentation of the badge.
+static const float kBadgeIndent = 5.0f;
+
+// A view that draws our dock tile.
+@interface DockTileView : NSView {
+ @private
+ int downloads_;
+ BOOL indeterminate_;
+ float progress_;
+}
+
+// Indicates how many downloads are in progress.
+@property (nonatomic) int downloads;
+
+// Indicates whether the progress indicator should be in an indeterminate state
+// or not.
+@property (nonatomic) BOOL indeterminate;
+
+// Indicates the amount of progress made of the download. Ranges from [0..1].
+@property (nonatomic) float progress;
+
+@end
+
+@implementation DockTileView
+
+@synthesize downloads = downloads_;
+@synthesize indeterminate = indeterminate_;
+@synthesize progress = progress_;
+
+- (void)drawRect:(NSRect)dirtyRect {
+ // Not -[NSApplication applicationIconImage]; that fails to return a pasted
+ // custom icon.
+ NSString* appPath = [[NSBundle mainBundle] bundlePath];
+ NSImage* appIcon = [[NSWorkspace sharedWorkspace] iconForFile:appPath];
+ [appIcon drawInRect:[self bounds]
+ fromRect:NSZeroRect
+ operation:NSCompositeSourceOver
+ fraction:1.0];
+
+ if (downloads_ == 0)
+ return;
+
+ NSRect badgeRect = [self bounds];
+ badgeRect.size.height = (int)(kBadgeFraction * badgeRect.size.height);
+ int newWidth = kBadgeFraction * badgeRect.size.width;
+ badgeRect.origin.x = badgeRect.size.width - newWidth;
+ badgeRect.size.width = newWidth;
+
+ CGFloat badgeRadius = NSMidY(badgeRect);
+
+ badgeRect.origin.x -= kBadgeIndent;
+ badgeRect.origin.y += kBadgeIndent;
+
+ NSPoint badgeCenter = NSMakePoint(NSMidX(badgeRect),
+ NSMidY(badgeRect));
+
+ // Background
+ NSColor* backgroundColor = [NSColor colorWithCalibratedRed:0.85
+ green:0.85
+ blue:0.85
+ alpha:1.0];
+ NSColor* backgroundHighlight =
+ [backgroundColor blendedColorWithFraction:0.85
+ ofColor:[NSColor whiteColor]];
+ scoped_nsobject<NSGradient> backgroundGradient(
+ [[NSGradient alloc] initWithStartingColor:backgroundHighlight
+ endingColor:backgroundColor]);
+ NSBezierPath* badgeEdge = [NSBezierPath bezierPathWithOvalInRect:badgeRect];
+ [NSGraphicsContext saveGraphicsState];
+ [badgeEdge addClip];
+ [backgroundGradient drawFromCenter:badgeCenter
+ radius:0.0
+ toCenter:badgeCenter
+ radius:badgeRadius
+ options:0];
+ [NSGraphicsContext restoreGraphicsState];
+
+ // Slice
+ if (!indeterminate_) {
+ NSColor* sliceColor = [NSColor colorWithCalibratedRed:0.45
+ green:0.8
+ blue:0.25
+ alpha:1.0];
+ NSColor* sliceHighlight =
+ [sliceColor blendedColorWithFraction:0.4
+ ofColor:[NSColor whiteColor]];
+ scoped_nsobject<NSGradient> sliceGradient(
+ [[NSGradient alloc] initWithStartingColor:sliceHighlight
+ endingColor:sliceColor]);
+ NSBezierPath* progressSlice;
+ if (progress_ >= 1.0) {
+ progressSlice = [NSBezierPath bezierPathWithOvalInRect:badgeRect];
+ } else {
+ CGFloat endAngle = 90.0 - 360.0 * progress_;
+ if (endAngle < 0.0)
+ endAngle += 360.0;
+ progressSlice = [NSBezierPath bezierPath];
+ [progressSlice moveToPoint:badgeCenter];
+ [progressSlice appendBezierPathWithArcWithCenter:badgeCenter
+ radius:badgeRadius
+ startAngle:90.0
+ endAngle:endAngle
+ clockwise:YES];
+ [progressSlice closePath];
+ }
+ [NSGraphicsContext saveGraphicsState];
+ [progressSlice addClip];
+ [sliceGradient drawFromCenter:badgeCenter
+ radius:0.0
+ toCenter:badgeCenter
+ radius:badgeRadius
+ options:0];
+ [NSGraphicsContext restoreGraphicsState];
+ }
+
+ // Edge
+ [NSGraphicsContext saveGraphicsState];
+ [[NSColor whiteColor] set];
+ scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
+ [shadow.get() setShadowOffset:NSMakeSize(0, -2)];
+ [shadow setShadowBlurRadius:2];
+ [shadow set];
+ [badgeEdge setLineWidth:2];
+ [badgeEdge stroke];
+ [NSGraphicsContext restoreGraphicsState];
+
+ // Download count
+ scoped_nsobject<NSNumberFormatter> formatter(
+ [[NSNumberFormatter alloc] init]);
+ NSString* countString =
+ [formatter stringFromNumber:[NSNumber numberWithInt:downloads_]];
+
+ scoped_nsobject<NSShadow> countShadow([[NSShadow alloc] init]);
+ [countShadow setShadowBlurRadius:3.0];
+ [countShadow.get() setShadowColor:[NSColor whiteColor]];
+ [countShadow.get() setShadowOffset:NSMakeSize(0.0, 0.0)];
+ NSMutableDictionary* countAttrsDict =
+ [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ [NSColor blackColor], NSForegroundColorAttributeName,
+ countShadow.get(), NSShadowAttributeName,
+ nil];
+ CGFloat countFontSize = badgeRadius;
+ NSSize countSize = NSZeroSize;
+ scoped_nsobject<NSAttributedString> countAttrString;
+ while (1) {
+ NSFont* countFont = [NSFont fontWithName:@"Helvetica-Bold"
+ size:countFontSize];
+ [countAttrsDict setObject:countFont forKey:NSFontAttributeName];
+ countAttrString.reset(
+ [[NSAttributedString alloc] initWithString:countString
+ attributes:countAttrsDict]);
+ countSize = [countAttrString size];
+ if (countSize.width > badgeRadius * 1.5) {
+ countFontSize -= 1.0;
+ } else {
+ break;
+ }
+ }
+
+ NSPoint countOrigin = badgeCenter;
+ countOrigin.x -= countSize.width / 2;
+ countOrigin.y -= countSize.height / 2.2; // tweak; otherwise too low
+
+ [countAttrString.get() drawAtPoint:countOrigin];
+}
+
+@end
+
+
+@implementation DockIcon
+
++ (DockIcon*)sharedDockIcon {
+ static DockIcon* icon;
+ if (!icon) {
+ NSDockTile* dockTile = [[NSApplication sharedApplication] dockTile];
+
+ scoped_nsobject<DockTileView> dockTileView([[DockTileView alloc] init]);
+ [dockTile setContentView:dockTileView];
+
+ icon = [[DockIcon alloc] init];
+ }
+
+ return icon;
+}
+
+- (void)updateIcon {
+ NSDockTile* dockTile = [[NSApplication sharedApplication] dockTile];
+
+ [dockTile display];
+}
+
+- (void)setDownloads:(int)downloads {
+ NSDockTile* dockTile = [[NSApplication sharedApplication] dockTile];
+ DockTileView* dockTileView = (DockTileView*)([dockTile contentView]);
+
+ [dockTileView setDownloads:downloads];
+}
+
+- (void)setIndeterminate:(BOOL)indeterminate {
+ NSDockTile* dockTile = [[NSApplication sharedApplication] dockTile];
+ DockTileView* dockTileView = (DockTileView*)([dockTile contentView]);
+
+ [dockTileView setIndeterminate:indeterminate];
+}
+
+- (void)setProgress:(float)progress {
+ NSDockTile* dockTile = [[NSApplication sharedApplication] dockTile];
+ DockTileView* dockTileView = (DockTileView*)([dockTile contentView]);
+
+ [dockTileView setProgress:progress];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/download/download_item_button.h b/chrome/browser/ui/cocoa/download/download_item_button.h
new file mode 100644
index 0000000..c064cd8
--- /dev/null
+++ b/chrome/browser/ui/cocoa/download/download_item_button.h
@@ -0,0 +1,27 @@
+// 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>
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/file_path.h"
+#import "chrome/browser/ui/cocoa/draggable_button.h"
+
+@class DownloadItemController;
+
+// A button that is a drag source for a file and that displays a context menu
+// instead of firing an action when clicked in a certain area.
+@interface DownloadItemButton : DraggableButton<NSMenuDelegate> {
+ @private
+ FilePath downloadPath_;
+ DownloadItemController* controller_; // weak
+}
+
+@property(assign, nonatomic) FilePath download;
+@property(assign, nonatomic) DownloadItemController* controller;
+
+// Overridden from DraggableButton.
+- (void)beginDrag:(NSEvent*)event;
+
+@end
diff --git a/chrome/browser/ui/cocoa/download/download_item_button.mm b/chrome/browser/ui/cocoa/download/download_item_button.mm
new file mode 100644
index 0000000..da9f6b4
--- /dev/null
+++ b/chrome/browser/ui/cocoa/download/download_item_button.mm
@@ -0,0 +1,50 @@
+// 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 "chrome/browser/ui/cocoa/download/download_item_button.h"
+
+#include "base/logging.h"
+#include "base/sys_string_conversions.h"
+#import "chrome/browser/ui/cocoa/download/download_item_cell.h"
+#import "chrome/browser/ui/cocoa/download/download_item_controller.h"
+
+@implementation DownloadItemButton
+
+@synthesize download = downloadPath_;
+@synthesize controller = controller_;
+
+// Overridden from DraggableButton.
+- (void)beginDrag:(NSEvent*)event {
+ if (!downloadPath_.empty()) {
+ NSString* filename = base::SysUTF8ToNSString(downloadPath_.value());
+ [self dragFile:filename fromRect:[self bounds] slideBack:YES event:event];
+ }
+}
+
+// Override to show a context menu on mouse down if clicked over the context
+// menu area.
+- (void)mouseDown:(NSEvent*)event {
+ DCHECK(controller_);
+ // Override so that we can pop up a context menu on mouse down.
+ NSCell* cell = [self cell];
+ DCHECK([cell respondsToSelector:@selector(isMouseOverButtonPart)]);
+ if ([reinterpret_cast<DownloadItemCell*>(cell) isMouseOverButtonPart]) {
+ [super mouseDown:event];
+ } else {
+ // Hold a reference to our controller in case the download completes and we
+ // represent a file that's auto-removed (e.g. a theme).
+ scoped_nsobject<DownloadItemController> ref([controller_ retain]);
+ [cell setHighlighted:YES];
+ [[self menu] setDelegate:self];
+ [NSMenu popUpContextMenu:[self menu]
+ withEvent:[NSApp currentEvent]
+ forView:self];
+ }
+}
+
+- (void)menuDidClose:(NSMenu*)menu {
+ [[self cell] setHighlighted:NO];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/download/download_item_button_unittest.mm b/chrome/browser/ui/cocoa/download/download_item_button_unittest.mm
new file mode 100644
index 0000000..bb0279d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/download/download_item_button_unittest.mm
@@ -0,0 +1,21 @@
+// 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.
+
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/download/download_item_button.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+// Make sure nothing leaks.
+TEST(DownloadItemButtonTest, Create) {
+ scoped_nsobject<DownloadItemButton> button;
+ button.reset([[DownloadItemButton alloc]
+ initWithFrame:NSMakeRect(0,0,500,500)]);
+
+ // Test setter
+ FilePath path("foo");
+ [button.get() setDownload:path];
+ EXPECT_EQ(path.value(), [button.get() download].value());
+}
diff --git a/chrome/browser/ui/cocoa/download/download_item_cell.h b/chrome/browser/ui/cocoa/download/download_item_cell.h
new file mode 100644
index 0000000..a5ffaeb
--- /dev/null
+++ b/chrome/browser/ui/cocoa/download/download_item_cell.h
@@ -0,0 +1,61 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_DOWNLOAD_DOWNLOAD_ITEM_CELL_H_
+#define CHROME_BROWSER_UI_COCOA_DOWNLOAD_DOWNLOAD_ITEM_CELL_H_
+#pragma once
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_ptr.h"
+#import "chrome/browser/ui/cocoa/gradient_button_cell.h"
+
+#include "base/file_path.h"
+
+class BaseDownloadItemModel;
+
+// A button cell that implements the weird button/popup button hybrid that is
+// used by the download items.
+
+// The button represented by this cell consists of a button part on the left
+// and a dropdown-menu part on the right. This enum describes which part the
+// mouse cursor is over currently.
+enum DownloadItemMousePosition {
+ kDownloadItemMouseOutside,
+ kDownloadItemMouseOverButtonPart,
+ kDownloadItemMouseOverDropdownPart
+};
+
+@interface DownloadItemCell : GradientButtonCell<NSAnimationDelegate> {
+ @private
+ // Track which part of the button the mouse is over
+ DownloadItemMousePosition mousePosition_;
+ int mouseInsideCount_;
+ scoped_nsobject<NSTrackingArea> trackingAreaButton_;
+ scoped_nsobject<NSTrackingArea> trackingAreaDropdown_;
+
+ FilePath downloadPath_; // stored unelided
+ NSString* secondaryTitle_;
+ NSFont* secondaryFont_;
+ int percentDone_;
+ scoped_nsobject<NSAnimation> completionAnimation_;
+
+ BOOL isStatusTextVisible_;
+ CGFloat titleY_;
+ CGFloat statusAlpha_;
+ scoped_nsobject<NSAnimation> hideStatusAnimation_;
+
+ scoped_ptr<ThemeProvider> themeProvider_;
+}
+
+- (void)setStateFromDownload:(BaseDownloadItemModel*)downloadModel;
+
+@property (nonatomic, copy) NSString* secondaryTitle;
+@property (nonatomic, retain) NSFont* secondaryFont;
+
+// Returns if the mouse is over the button part of the cell.
+- (BOOL)isMouseOverButtonPart;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_DOWNLOAD_DOWNLOAD_ITEM_CELL_H_
diff --git a/chrome/browser/ui/cocoa/download/download_item_cell.mm b/chrome/browser/ui/cocoa/download/download_item_cell.mm
new file mode 100644
index 0000000..b83d6f5
--- /dev/null
+++ b/chrome/browser/ui/cocoa/download/download_item_cell.mm
@@ -0,0 +1,708 @@
+// 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 "chrome/browser/ui/cocoa/download/download_item_cell.h"
+
+#include "app/l10n_util.h"
+#include "app/text_elider.h"
+#include "base/mac_util.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/download/download_item.h"
+#include "chrome/browser/download/download_item_model.h"
+#include "chrome/browser/download/download_manager.h"
+#include "chrome/browser/download/download_util.h"
+#import "chrome/browser/themes/browser_theme_provider.h"
+#import "chrome/browser/ui/cocoa/download/download_item_cell.h"
+#import "chrome/browser/ui/cocoa/image_utils.h"
+#import "chrome/browser/ui/cocoa/themed_window.h"
+#include "gfx/canvas_skia_paint.h"
+#include "grit/theme_resources.h"
+#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
+#import "third_party/GTM/AppKit/GTMNSColor+Luminance.h"
+
+namespace {
+
+// Distance from top border to icon
+const CGFloat kImagePaddingTop = 7;
+
+// Distance from left border to icon
+const CGFloat kImagePaddingLeft = 9;
+
+// Width of icon
+const CGFloat kImageWidth = 16;
+
+// Height of icon
+const CGFloat kImageHeight = 16;
+
+// x coordinate of download name string, in view coords
+const CGFloat kTextPosLeft = kImagePaddingLeft +
+ kImageWidth + download_util::kSmallProgressIconOffset;
+
+// Distance from end of download name string to dropdown area
+const CGFloat kTextPaddingRight = 3;
+
+// y coordinate of download name string, in view coords, when status message
+// is visible
+const CGFloat kPrimaryTextPosTop = 3;
+
+// y coordinate of download name string, in view coords, when status message
+// is not visible
+const CGFloat kPrimaryTextOnlyPosTop = 10;
+
+// y coordinate of status message, in view coords
+const CGFloat kSecondaryTextPosTop = 18;
+
+// Grey value of status text
+const CGFloat kSecondaryTextColor = 0.5;
+
+// Width of dropdown area on the right (includes 1px for the border on each
+// side).
+const CGFloat kDropdownAreaWidth = 14;
+
+// Width of dropdown arrow
+const CGFloat kDropdownArrowWidth = 5;
+
+// Height of dropdown arrow
+const CGFloat kDropdownArrowHeight = 3;
+
+// Vertical displacement of dropdown area, relative to the "centered" position.
+const CGFloat kDropdownAreaY = -2;
+
+// Duration of the two-lines-to-one-line animation, in seconds
+NSTimeInterval kHideStatusDuration = 0.3;
+
+// Duration of the 'download complete' animation, in seconds
+const int kCompleteAnimationDuration = 2.5;
+
+}
+
+// This is a helper class to animate the fading out of the status text.
+@interface DownloadItemCellAnimation : NSAnimation {
+ DownloadItemCell* cell_;
+}
+- (id)initWithDownloadItemCell:(DownloadItemCell*)cell
+ duration:(NSTimeInterval)duration
+ animationCurve:(NSAnimationCurve)animationCurve;
+@end
+
+class BackgroundTheme : public ThemeProvider {
+public:
+ BackgroundTheme(ThemeProvider* provider);
+
+ virtual void Init(Profile* profile) { }
+ virtual SkBitmap* GetBitmapNamed(int id) const { return nil; }
+ virtual SkColor GetColor(int id) const { return SkColor(); }
+ virtual bool GetDisplayProperty(int id, int* result) const { return false; }
+ virtual bool ShouldUseNativeFrame() const { return false; }
+ virtual bool HasCustomImage(int id) const { return false; }
+ virtual RefCountedMemory* GetRawData(int id) const { return NULL; }
+ virtual NSImage* GetNSImageNamed(int id, bool allow_default) const;
+ virtual NSColor* GetNSImageColorNamed(int id, bool allow_default) const;
+ virtual NSColor* GetNSColor(int id, bool allow_default) const;
+ virtual NSColor* GetNSColorTint(int id, bool allow_default) const;
+ virtual NSGradient* GetNSGradient(int id) const;
+
+private:
+ ThemeProvider* provider_;
+ scoped_nsobject<NSGradient> buttonGradient_;
+ scoped_nsobject<NSGradient> buttonPressedGradient_;
+ scoped_nsobject<NSColor> borderColor_;
+};
+
+BackgroundTheme::BackgroundTheme(ThemeProvider* provider) :
+ provider_(provider) {
+ NSColor* bgColor = [NSColor colorWithCalibratedRed:241/255.0
+ green:245/255.0
+ blue:250/255.0
+ alpha:77/255.0];
+ NSColor* clickedColor = [NSColor colorWithCalibratedRed:239/255.0
+ green:245/255.0
+ blue:252/255.0
+ alpha:51/255.0];
+
+ borderColor_.reset(
+ [[NSColor colorWithCalibratedWhite:0 alpha:36/255.0] retain]);
+ buttonGradient_.reset([[NSGradient alloc]
+ initWithColors:[NSArray arrayWithObject:bgColor]]);
+ buttonPressedGradient_.reset([[NSGradient alloc]
+ initWithColors:[NSArray arrayWithObject:clickedColor]]);
+}
+
+NSImage* BackgroundTheme::GetNSImageNamed(int id, bool allow_default) const {
+ return nil;
+}
+
+NSColor* BackgroundTheme::GetNSImageColorNamed(int id,
+ bool allow_default) const {
+ return nil;
+}
+
+NSColor* BackgroundTheme::GetNSColor(int id, bool allow_default) const {
+ return provider_->GetNSColor(id, allow_default);
+}
+
+NSColor* BackgroundTheme::GetNSColorTint(int id, bool allow_default) const {
+ if (id == BrowserThemeProvider::TINT_BUTTONS)
+ return borderColor_.get();
+
+ return provider_->GetNSColorTint(id, allow_default);
+}
+
+NSGradient* BackgroundTheme::GetNSGradient(int id) const {
+ switch (id) {
+ case BrowserThemeProvider::GRADIENT_TOOLBAR_BUTTON:
+ case BrowserThemeProvider::GRADIENT_TOOLBAR_BUTTON_INACTIVE:
+ return buttonGradient_.get();
+ case BrowserThemeProvider::GRADIENT_TOOLBAR_BUTTON_PRESSED:
+ case BrowserThemeProvider::GRADIENT_TOOLBAR_BUTTON_PRESSED_INACTIVE:
+ return buttonPressedGradient_.get();
+ default:
+ return provider_->GetNSGradient(id);
+ }
+}
+
+@interface DownloadItemCell(Private)
+- (void)updateTrackingAreas:(id)sender;
+- (void)hideSecondaryTitle;
+- (void)animation:(NSAnimation*)animation
+ progressed:(NSAnimationProgress)progress;
+- (NSString*)elideTitle:(int)availableWidth;
+- (NSString*)elideStatus:(int)availableWidth;
+- (ThemeProvider*)backgroundThemeWrappingProvider:(ThemeProvider*)provider;
+- (BOOL)pressedWithDefaultThemeOnPart:(DownloadItemMousePosition)part;
+- (NSColor*)titleColorForPart:(DownloadItemMousePosition)part;
+- (void)drawSecondaryTitleInRect:(NSRect)innerFrame;
+@end
+
+@implementation DownloadItemCell
+
+@synthesize secondaryTitle = secondaryTitle_;
+@synthesize secondaryFont = secondaryFont_;
+
+- (void)setInitialState {
+ isStatusTextVisible_ = NO;
+ titleY_ = kPrimaryTextPosTop;
+ statusAlpha_ = 1.0;
+
+ [self setFont:[NSFont systemFontOfSize:
+ [NSFont systemFontSizeForControlSize:NSSmallControlSize]]];
+ [self setSecondaryFont:[NSFont systemFontOfSize:
+ [NSFont systemFontSizeForControlSize:NSSmallControlSize]]];
+
+ [self updateTrackingAreas:self];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(updateTrackingAreas:)
+ name:NSViewFrameDidChangeNotification
+ object:[self controlView]];
+}
+
+// For nib instantiations
+- (id)initWithCoder:(NSCoder*)decoder {
+ if ((self = [super initWithCoder:decoder])) {
+ [self setInitialState];
+ }
+ return self;
+}
+
+// For programmatic instantiations.
+- (id)initTextCell:(NSString *)string {
+ if ((self = [super initTextCell:string])) {
+ [self setInitialState];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ if ([completionAnimation_ isAnimating])
+ [completionAnimation_ stopAnimation];
+ if ([hideStatusAnimation_ isAnimating])
+ [hideStatusAnimation_ stopAnimation];
+ if (trackingAreaButton_) {
+ [[self controlView] removeTrackingArea:trackingAreaButton_];
+ trackingAreaButton_.reset();
+ }
+ if (trackingAreaDropdown_) {
+ [[self controlView] removeTrackingArea:trackingAreaDropdown_];
+ trackingAreaDropdown_.reset();
+ }
+ [secondaryTitle_ release];
+ [secondaryFont_ release];
+ [super dealloc];
+}
+
+- (void)setStateFromDownload:(BaseDownloadItemModel*)downloadModel {
+ // Set the name of the download.
+ downloadPath_ = downloadModel->download()->GetFileNameToReportUser();
+
+ std::wstring statusText = downloadModel->GetStatusText();
+ if (statusText.empty()) {
+ // Remove the status text label.
+ [self hideSecondaryTitle];
+ isStatusTextVisible_ = NO;
+ } else {
+ // Set status text.
+ NSString* statusString = base::SysWideToNSString(statusText);
+ [self setSecondaryTitle:statusString];
+ isStatusTextVisible_ = YES;
+ }
+
+ switch (downloadModel->download()->state()) {
+ case DownloadItem::COMPLETE:
+ // Small downloads may start in a complete state due to asynchronous
+ // notifications. In this case, we'll get a second complete notification
+ // via the observers, so we ignore it and avoid creating a second complete
+ // animation.
+ if (completionAnimation_.get())
+ break;
+ completionAnimation_.reset([[DownloadItemCellAnimation alloc]
+ initWithDownloadItemCell:self
+ duration:kCompleteAnimationDuration
+ animationCurve:NSAnimationLinear]);
+ [completionAnimation_.get() setDelegate:self];
+ [completionAnimation_.get() startAnimation];
+ percentDone_ = -1;
+ break;
+ case DownloadItem::CANCELLED:
+ percentDone_ = -1;
+ break;
+ case DownloadItem::IN_PROGRESS:
+ percentDone_ = downloadModel->download()->is_paused() ?
+ -1 : downloadModel->download()->PercentComplete();
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ [[self controlView] setNeedsDisplay:YES];
+}
+
+- (void)updateTrackingAreas:(id)sender {
+ if (trackingAreaButton_) {
+ [[self controlView] removeTrackingArea:trackingAreaButton_.get()];
+ trackingAreaButton_.reset(nil);
+ }
+ if (trackingAreaDropdown_) {
+ [[self controlView] removeTrackingArea:trackingAreaDropdown_.get()];
+ trackingAreaDropdown_.reset(nil);
+ }
+
+ // Use two distinct tracking rects for left and right parts.
+ // The tracking areas are also used to decide how to handle clicks. They must
+ // always be active, so the click is handled correctly when a download item
+ // is clicked while chrome is not the active app ( http://crbug.com/21916 ).
+ NSRect bounds = [[self controlView] bounds];
+ NSRect buttonRect, dropdownRect;
+ NSDivideRect(bounds, &dropdownRect, &buttonRect,
+ kDropdownAreaWidth, NSMaxXEdge);
+
+ trackingAreaButton_.reset([[NSTrackingArea alloc]
+ initWithRect:buttonRect
+ options:(NSTrackingMouseEnteredAndExited |
+ NSTrackingActiveAlways)
+ owner:self
+ userInfo:nil]);
+ [[self controlView] addTrackingArea:trackingAreaButton_.get()];
+
+ trackingAreaDropdown_.reset([[NSTrackingArea alloc]
+ initWithRect:dropdownRect
+ options:(NSTrackingMouseEnteredAndExited |
+ NSTrackingActiveAlways)
+ owner:self
+ userInfo:nil]);
+ [[self controlView] addTrackingArea:trackingAreaDropdown_.get()];
+}
+
+- (void)setShowsBorderOnlyWhileMouseInside:(BOOL)showOnly {
+ // Override to make sure it doesn't do anything if it's called accidentally.
+}
+
+- (void)mouseEntered:(NSEvent*)theEvent {
+ mouseInsideCount_++;
+ if ([theEvent trackingArea] == trackingAreaButton_.get())
+ mousePosition_ = kDownloadItemMouseOverButtonPart;
+ else if ([theEvent trackingArea] == trackingAreaDropdown_.get())
+ mousePosition_ = kDownloadItemMouseOverDropdownPart;
+ [[self controlView] setNeedsDisplay:YES];
+}
+
+- (void)mouseExited:(NSEvent *)theEvent {
+ mouseInsideCount_--;
+ if (mouseInsideCount_ == 0)
+ mousePosition_ = kDownloadItemMouseOutside;
+ [[self controlView] setNeedsDisplay:YES];
+}
+
+- (BOOL)isMouseInside {
+ return mousePosition_ != kDownloadItemMouseOutside;
+}
+
+- (BOOL)isMouseOverButtonPart {
+ return mousePosition_ == kDownloadItemMouseOverButtonPart;
+}
+
+- (BOOL)isButtonPartPressed {
+ return [self isHighlighted]
+ && mousePosition_ == kDownloadItemMouseOverButtonPart;
+}
+
+- (BOOL)isMouseOverDropdownPart {
+ return mousePosition_ == kDownloadItemMouseOverDropdownPart;
+}
+
+- (BOOL)isDropdownPartPressed {
+ return [self isHighlighted]
+ && mousePosition_ == kDownloadItemMouseOverDropdownPart;
+}
+
+- (NSBezierPath*)leftRoundedPath:(CGFloat)radius inRect:(NSRect)rect {
+
+ NSPoint topLeft = NSMakePoint(NSMinX(rect), NSMaxY(rect));
+ NSPoint topRight = NSMakePoint(NSMaxX(rect), NSMaxY(rect));
+ NSPoint bottomRight = NSMakePoint(NSMaxX(rect) , NSMinY(rect));
+
+ NSBezierPath* path = [NSBezierPath bezierPath];
+ [path moveToPoint:topRight];
+ [path appendBezierPathWithArcFromPoint:topLeft
+ toPoint:rect.origin
+ radius:radius];
+ [path appendBezierPathWithArcFromPoint:rect.origin
+ toPoint:bottomRight
+ radius:radius];
+ [path lineToPoint:bottomRight];
+ return path;
+}
+
+- (NSBezierPath*)rightRoundedPath:(CGFloat)radius inRect:(NSRect)rect {
+
+ NSPoint topLeft = NSMakePoint(NSMinX(rect), NSMaxY(rect));
+ NSPoint topRight = NSMakePoint(NSMaxX(rect), NSMaxY(rect));
+ NSPoint bottomRight = NSMakePoint(NSMaxX(rect), NSMinY(rect));
+
+ NSBezierPath* path = [NSBezierPath bezierPath];
+ [path moveToPoint:rect.origin];
+ [path appendBezierPathWithArcFromPoint:bottomRight
+ toPoint:topRight
+ radius:radius];
+ [path appendBezierPathWithArcFromPoint:topRight
+ toPoint:topLeft
+ radius:radius];
+ [path lineToPoint:topLeft];
+ return path;
+}
+
+- (NSString*)elideTitle:(int)availableWidth {
+ NSFont* font = [self font];
+ gfx::Font font_chr(base::SysNSStringToWide([font fontName]),
+ [font pointSize]);
+
+ return base::SysUTF16ToNSString(
+ ElideFilename(downloadPath_, font_chr, availableWidth));
+}
+
+- (NSString*)elideStatus:(int)availableWidth {
+ NSFont* font = [self secondaryFont];
+ gfx::Font font_chr(base::SysNSStringToWide([font fontName]),
+ [font pointSize]);
+
+ return base::SysUTF16ToNSString(ElideText(
+ base::SysNSStringToUTF16([self secondaryTitle]),
+ font_chr,
+ availableWidth,
+ false));
+}
+
+- (ThemeProvider*)backgroundThemeWrappingProvider:(ThemeProvider*)provider {
+ if (!themeProvider_.get()) {
+ themeProvider_.reset(new BackgroundTheme(provider));
+ }
+
+ return themeProvider_.get();
+}
+
+// Returns if |part| was pressed while the default theme was active.
+- (BOOL)pressedWithDefaultThemeOnPart:(DownloadItemMousePosition)part {
+ ThemeProvider* themeProvider = [[[self controlView] window] themeProvider];
+ bool isDefaultTheme =
+ !themeProvider->HasCustomImage(IDR_THEME_BUTTON_BACKGROUND);
+ return isDefaultTheme && [self isHighlighted] && mousePosition_ == part;
+}
+
+// Returns the text color that should be used to draw text on |part|.
+- (NSColor*)titleColorForPart:(DownloadItemMousePosition)part {
+ ThemeProvider* themeProvider = [[[self controlView] window] themeProvider];
+ NSColor* themeTextColor =
+ themeProvider->GetNSColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT,
+ true);
+ return [self pressedWithDefaultThemeOnPart:part]
+ ? [NSColor alternateSelectedControlTextColor] : themeTextColor;
+}
+
+- (void)drawSecondaryTitleInRect:(NSRect)innerFrame {
+ if (![self secondaryTitle] || statusAlpha_ <= 0)
+ return;
+
+ CGFloat textWidth = innerFrame.size.width -
+ (kTextPosLeft + kTextPaddingRight + kDropdownAreaWidth);
+ NSString* secondaryText = [self elideStatus:textWidth];
+ NSColor* secondaryColor =
+ [self titleColorForPart:kDownloadItemMouseOverButtonPart];
+
+ // If text is light-on-dark, lightening it alone will do nothing.
+ // Therefore we mute luminance a wee bit before drawing in this case.
+ if (![secondaryColor gtm_isDarkColor])
+ secondaryColor = [secondaryColor gtm_colorByAdjustingLuminance:-0.2];
+
+ NSDictionary* secondaryTextAttributes =
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ secondaryColor, NSForegroundColorAttributeName,
+ [self secondaryFont], NSFontAttributeName,
+ nil];
+ NSPoint secondaryPos =
+ NSMakePoint(innerFrame.origin.x + kTextPosLeft, kSecondaryTextPosTop);
+ [secondaryText drawAtPoint:secondaryPos
+ withAttributes:secondaryTextAttributes];
+}
+
+- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
+ // Constants from Cole. Will kConstant them once the feedback loop
+ // is complete.
+ NSRect drawFrame = NSInsetRect(cellFrame, 1.5, 1.5);
+ NSRect innerFrame = NSInsetRect(cellFrame, 2, 2);
+
+ const float radius = 5;
+ NSWindow* window = [controlView window];
+ BOOL active = [window isKeyWindow] || [window isMainWindow];
+
+ // In the default theme, draw download items with the bookmark button
+ // gradient. For some themes, this leads to unreadable text, so draw the item
+ // with a background that looks like windows (some transparent white) if a
+ // theme is used. Use custom theme object with a white color gradient to trick
+ // the superclass into drawing what we want.
+ ThemeProvider* themeProvider = [[[self controlView] window] themeProvider];
+ bool isDefaultTheme =
+ !themeProvider->HasCustomImage(IDR_THEME_BUTTON_BACKGROUND);
+
+ NSGradient* bgGradient = nil;
+ if (!isDefaultTheme) {
+ themeProvider = [self backgroundThemeWrappingProvider:themeProvider];
+ bgGradient = themeProvider->GetNSGradient(
+ active ? BrowserThemeProvider::GRADIENT_TOOLBAR_BUTTON :
+ BrowserThemeProvider::GRADIENT_TOOLBAR_BUTTON_INACTIVE);
+ }
+
+ NSRect buttonDrawRect, dropdownDrawRect;
+ NSDivideRect(drawFrame, &dropdownDrawRect, &buttonDrawRect,
+ kDropdownAreaWidth, NSMaxXEdge);
+
+ NSBezierPath* buttonInnerPath = [self
+ leftRoundedPath:radius inRect:buttonDrawRect];
+ NSBezierPath* dropdownInnerPath = [self
+ rightRoundedPath:radius inRect:dropdownDrawRect];
+
+ // Draw secondary title, if any. Do this before drawing the (transparent)
+ // fill so that the text becomes a bit lighter. The default theme's "pressed"
+ // gradient is not transparent, so only do this if a theme is active.
+ bool drawStatusOnTop =
+ [self pressedWithDefaultThemeOnPart:kDownloadItemMouseOverButtonPart];
+ if (!drawStatusOnTop)
+ [self drawSecondaryTitleInRect:innerFrame];
+
+ // Stroke the borders and appropriate fill gradient.
+ [self drawBorderAndFillForTheme:themeProvider
+ controlView:controlView
+ innerPath:buttonInnerPath
+ showClickedGradient:[self isButtonPartPressed]
+ showHighlightGradient:[self isMouseOverButtonPart]
+ hoverAlpha:0.0
+ active:active
+ cellFrame:cellFrame
+ defaultGradient:bgGradient];
+
+ [self drawBorderAndFillForTheme:themeProvider
+ controlView:controlView
+ innerPath:dropdownInnerPath
+ showClickedGradient:[self isDropdownPartPressed]
+ showHighlightGradient:[self isMouseOverDropdownPart]
+ hoverAlpha:0.0
+ active:active
+ cellFrame:cellFrame
+ defaultGradient:bgGradient];
+
+ [self drawInteriorWithFrame:innerFrame inView:controlView];
+
+ // For the default theme, draw the status text on top of the (opaque) button
+ // gradient.
+ if (drawStatusOnTop)
+ [self drawSecondaryTitleInRect:innerFrame];
+}
+
+- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
+ // Draw title
+ CGFloat textWidth = cellFrame.size.width -
+ (kTextPosLeft + kTextPaddingRight + kDropdownAreaWidth);
+ [self setTitle:[self elideTitle:textWidth]];
+
+ NSColor* color = [self titleColorForPart:kDownloadItemMouseOverButtonPart];
+ NSString* primaryText = [self title];
+
+ NSDictionary* primaryTextAttributes =
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ color, NSForegroundColorAttributeName,
+ [self font], NSFontAttributeName,
+ nil];
+ NSPoint primaryPos = NSMakePoint(
+ cellFrame.origin.x + kTextPosLeft,
+ titleY_);
+
+ [primaryText drawAtPoint:primaryPos withAttributes:primaryTextAttributes];
+
+ // Draw progress disk
+ {
+ // CanvasSkiaPaint draws its content to the current NSGraphicsContext in its
+ // destructor, which needs to be invoked before the icon is drawn below -
+ // hence this nested block.
+
+ // Always repaint the whole disk.
+ NSPoint imagePosition = [self imageRectForBounds:cellFrame].origin;
+ int x = imagePosition.x - download_util::kSmallProgressIconOffset;
+ int y = imagePosition.y - download_util::kSmallProgressIconOffset;
+ NSRect dirtyRect = NSMakeRect(
+ x, y,
+ download_util::kSmallProgressIconSize,
+ download_util::kSmallProgressIconSize);
+
+ gfx::CanvasSkiaPaint canvas(dirtyRect, false);
+ canvas.set_composite_alpha(true);
+ if (completionAnimation_.get()) {
+ if ([completionAnimation_ isAnimating]) {
+ download_util::PaintDownloadComplete(&canvas,
+ x, y,
+ [completionAnimation_ currentValue],
+ download_util::SMALL);
+ }
+ } else if (percentDone_ >= 0) {
+ download_util::PaintDownloadProgress(&canvas,
+ x, y,
+ download_util::kStartAngleDegrees, // TODO(thakis): Animate
+ percentDone_,
+ download_util::SMALL);
+ }
+ }
+
+ // Draw icon
+ NSRect imageRect = NSZeroRect;
+ imageRect.size = [[self image] size];
+ [[self image] drawInRect:[self imageRectForBounds:cellFrame]
+ fromRect:imageRect
+ operation:NSCompositeSourceOver
+ fraction:[self isEnabled] ? 1.0 : 0.5
+ neverFlipped:YES];
+
+ // Separator between button and popup parts
+ CGFloat lx = NSMaxX(cellFrame) - kDropdownAreaWidth + 0.5;
+ [[NSColor colorWithDeviceWhite:0.0 alpha:0.1] set];
+ [NSBezierPath strokeLineFromPoint:NSMakePoint(lx, NSMinY(cellFrame) + 1)
+ toPoint:NSMakePoint(lx, NSMaxY(cellFrame) - 1)];
+ [[NSColor colorWithDeviceWhite:1.0 alpha:0.1] set];
+ [NSBezierPath strokeLineFromPoint:NSMakePoint(lx + 1, NSMinY(cellFrame) + 1)
+ toPoint:NSMakePoint(lx + 1, NSMaxY(cellFrame) - 1)];
+
+ // Popup arrow. Put center of mass of the arrow in the center of the
+ // dropdown area.
+ CGFloat cx = NSMaxX(cellFrame) - kDropdownAreaWidth/2 + 0.5;
+ CGFloat cy = NSMidY(cellFrame);
+ NSPoint p1 = NSMakePoint(cx - kDropdownArrowWidth/2,
+ cy - kDropdownArrowHeight/3 + kDropdownAreaY);
+ NSPoint p2 = NSMakePoint(cx + kDropdownArrowWidth/2,
+ cy - kDropdownArrowHeight/3 + kDropdownAreaY);
+ NSPoint p3 = NSMakePoint(cx, cy + kDropdownArrowHeight*2/3 + kDropdownAreaY);
+ NSBezierPath *triangle = [NSBezierPath bezierPath];
+ [triangle moveToPoint:p1];
+ [triangle lineToPoint:p2];
+ [triangle lineToPoint:p3];
+ [triangle closePath];
+
+ NSGraphicsContext* context = [NSGraphicsContext currentContext];
+ [context saveGraphicsState];
+
+ scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
+ [shadow.get() setShadowColor:[NSColor whiteColor]];
+ [shadow.get() setShadowOffset:NSMakeSize(0, -1)];
+ [shadow setShadowBlurRadius:0.0];
+ [shadow set];
+
+ NSColor* fill = [self titleColorForPart:kDownloadItemMouseOverDropdownPart];
+ [fill setFill];
+
+ [triangle fill];
+
+ [context restoreGraphicsState];
+}
+
+- (NSRect)imageRectForBounds:(NSRect)cellFrame {
+ return NSMakeRect(cellFrame.origin.x + kImagePaddingLeft,
+ cellFrame.origin.y + kImagePaddingTop,
+ kImageWidth,
+ kImageHeight);
+}
+
+- (void)hideSecondaryTitle {
+ if (isStatusTextVisible_) {
+ // No core animation -- text in CA layers is not subpixel antialiased :-/
+ hideStatusAnimation_.reset([[DownloadItemCellAnimation alloc]
+ initWithDownloadItemCell:self
+ duration:kHideStatusDuration
+ animationCurve:NSAnimationEaseIn]);
+ [hideStatusAnimation_.get() setDelegate:self];
+ [hideStatusAnimation_.get() startAnimation];
+ } else {
+ // If the download is done so quickly that the status line is never visible,
+ // don't show an animation
+ [self animation:nil progressed:1.0];
+ }
+}
+
+- (void)animation:(NSAnimation*)animation
+ progressed:(NSAnimationProgress)progress {
+ if (animation == hideStatusAnimation_ || animation == nil) {
+ titleY_ = progress*kPrimaryTextOnlyPosTop +
+ (1 - progress)*kPrimaryTextPosTop;
+ statusAlpha_ = 1 - progress;
+ [[self controlView] setNeedsDisplay:YES];
+ } else if (animation == completionAnimation_) {
+ [[self controlView] setNeedsDisplay:YES];
+ }
+}
+
+- (void)animationDidEnd:(NSAnimation *)animation {
+ if (animation == hideStatusAnimation_)
+ hideStatusAnimation_.reset();
+ else if (animation == completionAnimation_)
+ completionAnimation_.reset();
+}
+
+@end
+
+@implementation DownloadItemCellAnimation
+
+- (id)initWithDownloadItemCell:(DownloadItemCell*)cell
+ duration:(NSTimeInterval)duration
+ animationCurve:(NSAnimationCurve)animationCurve {
+ if ((self = [super gtm_initWithDuration:duration
+ eventMask:NSLeftMouseDownMask
+ animationCurve:animationCurve])) {
+ cell_ = cell;
+ [self setAnimationBlockingMode:NSAnimationNonblocking];
+ }
+ return self;
+}
+
+- (void)setCurrentProgress:(NSAnimationProgress)progress {
+ [super setCurrentProgress:progress];
+ [cell_ animation:self progressed:progress];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/download/download_item_controller.h b/chrome/browser/ui/cocoa/download/download_item_controller.h
new file mode 100644
index 0000000..c41ff43
--- /dev/null
+++ b/chrome/browser/ui/cocoa/download/download_item_controller.h
@@ -0,0 +1,108 @@
+// 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 "base/scoped_ptr.h"
+#include "base/time.h"
+
+class BaseDownloadItemModel;
+@class ChromeUILocalizer;
+@class DownloadItemCell;
+class DownloadItem;
+@class DownloadItemButton;
+class DownloadItemMac;
+class DownloadShelfContextMenuMac;
+@class DownloadShelfController;
+@class GTMWidthBasedTweaker;
+
+// A controller class that manages one download item.
+
+@interface DownloadItemController : NSViewController {
+ @private
+ IBOutlet DownloadItemButton* progressView_;
+ IBOutlet DownloadItemCell* cell_;
+
+ IBOutlet NSMenu* activeDownloadMenu_;
+ IBOutlet NSMenu* completeDownloadMenu_;
+
+ // This is shown instead of progressView_ for dangerous downloads.
+ IBOutlet NSView* dangerousDownloadView_;
+ IBOutlet NSTextField* dangerousDownloadLabel_;
+ IBOutlet NSButton* dangerousDownloadConfirmButton_;
+
+ // Needed to find out how much the tweaker changed sizes to update the
+ // other views.
+ IBOutlet GTMWidthBasedTweaker* buttonTweaker_;
+
+ // Because the confirm text and button for dangerous downloads are determined
+ // at runtime, an outlet to the localizer is needed to construct the layout
+ // tweaker in awakeFromNib in order to adjust the UI after all strings are
+ // determined.
+ IBOutlet ChromeUILocalizer* localizer_;
+
+ IBOutlet NSImageView* image_;
+
+ scoped_ptr<DownloadItemMac> bridge_;
+ scoped_ptr<DownloadShelfContextMenuMac> menuBridge_;
+
+ // Weak pointer to the shelf that owns us.
+ DownloadShelfController* shelf_;
+
+ // The time at which this view was created.
+ base::Time creationTime_;
+
+ // The state of this item.
+ enum DownoadItemState {
+ kNormal,
+ kDangerous
+ } state_;
+};
+
+// Takes ownership of |downloadModel|.
+- (id)initWithModel:(BaseDownloadItemModel*)downloadModel
+ shelf:(DownloadShelfController*)shelf;
+
+// Updates the UI and menu state from |downloadModel|.
+- (void)setStateFromDownload:(BaseDownloadItemModel*)downloadModel;
+
+// Remove ourself from the download UI.
+- (void)remove;
+
+// Update item's visibility depending on if the item is still completely
+// contained in its parent.
+- (void)updateVisibility:(id)sender;
+
+// Called after a download is opened.
+- (void)downloadWasOpened;
+
+// Asynchronous icon loading callback.
+- (void)setIcon:(NSImage*)icon;
+
+// Download item button clicked
+- (IBAction)handleButtonClick:(id)sender;
+
+// Returns the size this item wants to have.
+- (NSSize)preferredSize;
+
+// Returns the DownloadItem model object belonging to this item.
+- (DownloadItem*)download;
+
+// Updates the tooltip with the download's path.
+- (void)updateToolTip;
+
+// Handling of dangerous downloads
+- (void)clearDangerousMode;
+- (BOOL)isDangerousMode;
+- (IBAction)saveDownload:(id)sender;
+- (IBAction)discardDownload:(id)sender;
+
+// Context menu handlers.
+- (IBAction)handleOpen:(id)sender;
+- (IBAction)handleAlwaysOpen:(id)sender;
+- (IBAction)handleReveal:(id)sender;
+- (IBAction)handleCancel:(id)sender;
+- (IBAction)handleTogglePause:(id)sender;
+
+@end
diff --git a/chrome/browser/ui/cocoa/download/download_item_controller.mm b/chrome/browser/ui/cocoa/download/download_item_controller.mm
new file mode 100644
index 0000000..be0be80
--- /dev/null
+++ b/chrome/browser/ui/cocoa/download/download_item_controller.mm
@@ -0,0 +1,401 @@
+// 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 "chrome/browser/ui/cocoa/download/download_item_controller.h"
+
+#include "app/l10n_util_mac.h"
+#include "app/resource_bundle.h"
+#include "app/text_elider.h"
+#include "base/mac_util.h"
+#include "base/metrics/histogram.h"
+#include "base/string16.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/download/download_item.h"
+#include "chrome/browser/download/download_item_model.h"
+#include "chrome/browser/download/download_shelf.h"
+#include "chrome/browser/download/download_util.h"
+#import "chrome/browser/themes/browser_theme_provider.h"
+#import "chrome/browser/ui/cocoa/download/download_item_button.h"
+#import "chrome/browser/ui/cocoa/download/download_item_cell.h"
+#include "chrome/browser/ui/cocoa/download/download_item_mac.h"
+#import "chrome/browser/ui/cocoa/download/download_shelf_controller.h"
+#import "chrome/browser/ui/cocoa/themed_window.h"
+#import "chrome/browser/ui/cocoa/ui_localizer.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
+
+namespace {
+
+// NOTE: Mac currently doesn't use this like Windows does. Mac uses this to
+// control the min size on the dangerous download text. TVL sent a query off to
+// UX to fully spec all the the behaviors of download items and truncations
+// rules so all platforms can get inline in the future.
+const int kTextWidth = 140; // Pixels
+
+// The maximum number of characters we show in a file name when displaying the
+// dangerous download message.
+const int kFileNameMaxLength = 20;
+
+// The maximum width in pixels for the file name tooltip.
+const int kToolTipMaxWidth = 900;
+
+
+// Helper to widen a view.
+void WidenView(NSView* view, CGFloat widthChange) {
+ // If it is an NSBox, the autoresize of the contentView is the issue.
+ NSView* contentView = view;
+ if ([view isKindOfClass:[NSBox class]]) {
+ contentView = [(NSBox*)view contentView];
+ }
+ BOOL autoresizesSubviews = [contentView autoresizesSubviews];
+ if (autoresizesSubviews) {
+ [contentView setAutoresizesSubviews:NO];
+ }
+
+ NSRect frame = [view frame];
+ frame.size.width += widthChange;
+ [view setFrame:frame];
+
+ if (autoresizesSubviews) {
+ [contentView setAutoresizesSubviews:YES];
+ }
+}
+
+} // namespace
+
+// A class for the chromium-side part of the download shelf context menu.
+
+class DownloadShelfContextMenuMac : public DownloadShelfContextMenu {
+ public:
+ DownloadShelfContextMenuMac(BaseDownloadItemModel* model)
+ : DownloadShelfContextMenu(model) { }
+
+ using DownloadShelfContextMenu::ExecuteCommand;
+ using DownloadShelfContextMenu::IsCommandIdChecked;
+ using DownloadShelfContextMenu::IsCommandIdEnabled;
+
+ using DownloadShelfContextMenu::SHOW_IN_FOLDER;
+ using DownloadShelfContextMenu::OPEN_WHEN_COMPLETE;
+ using DownloadShelfContextMenu::ALWAYS_OPEN_TYPE;
+ using DownloadShelfContextMenu::CANCEL;
+ using DownloadShelfContextMenu::TOGGLE_PAUSE;
+};
+
+@interface DownloadItemController (Private)
+- (void)themeDidChangeNotification:(NSNotification*)aNotification;
+- (void)updateTheme:(ThemeProvider*)themeProvider;
+- (void)setState:(DownoadItemState)state;
+@end
+
+// Implementation of DownloadItemController
+
+@implementation DownloadItemController
+
+- (id)initWithModel:(BaseDownloadItemModel*)downloadModel
+ shelf:(DownloadShelfController*)shelf {
+ if ((self = [super initWithNibName:@"DownloadItem"
+ bundle:mac_util::MainAppBundle()])) {
+ // Must be called before [self view], so that bridge_ is set in awakeFromNib
+ bridge_.reset(new DownloadItemMac(downloadModel, self));
+ menuBridge_.reset(new DownloadShelfContextMenuMac(downloadModel));
+
+ NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
+ [defaultCenter addObserver:self
+ selector:@selector(themeDidChangeNotification:)
+ name:kBrowserThemeDidChangeNotification
+ object:nil];
+
+ shelf_ = shelf;
+ state_ = kNormal;
+ creationTime_ = base::Time::Now();
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [progressView_ setController:nil];
+ [[self view] removeFromSuperview];
+ [super dealloc];
+}
+
+- (void)awakeFromNib {
+ [progressView_ setController:self];
+
+ [self setStateFromDownload:bridge_->download_model()];
+
+ GTMUILocalizerAndLayoutTweaker* localizerAndLayoutTweaker =
+ [[[GTMUILocalizerAndLayoutTweaker alloc] init] autorelease];
+ [localizerAndLayoutTweaker applyLocalizer:localizer_ tweakingUI:[self view]];
+
+ // The strings are based on the download item's name, sizing tweaks have to be
+ // manually done.
+ DCHECK(buttonTweaker_ != nil);
+ CGFloat widthChange = [buttonTweaker_ changedWidth];
+ // If it's a dangerous download, size the two lines so the text/filename
+ // is always visible.
+ if ([self isDangerousMode]) {
+ widthChange +=
+ [GTMUILocalizerAndLayoutTweaker
+ sizeToFitFixedHeightTextField:dangerousDownloadLabel_
+ minWidth:kTextWidth];
+ }
+ // Grow the parent views
+ WidenView([self view], widthChange);
+ WidenView(dangerousDownloadView_, widthChange);
+ // Slide the two buttons over.
+ NSPoint frameOrigin = [buttonTweaker_ frame].origin;
+ frameOrigin.x += widthChange;
+ [buttonTweaker_ setFrameOrigin:frameOrigin];
+
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ NSImage* alertIcon = rb.GetNativeImageNamed(IDR_WARNING);
+ DCHECK(alertIcon);
+ [image_ setImage:alertIcon];
+
+ bridge_->LoadIcon();
+ [self updateToolTip];
+}
+
+- (void)setStateFromDownload:(BaseDownloadItemModel*)downloadModel {
+ DCHECK_EQ(bridge_->download_model(), downloadModel);
+
+ // Handle dangerous downloads.
+ if (downloadModel->download()->safety_state() == DownloadItem::DANGEROUS) {
+ [self setState:kDangerous];
+
+ NSString* dangerousWarning;
+ NSString* confirmButtonTitle;
+ // The dangerous download label and button text are different for an
+ // extension file.
+ if (downloadModel->download()->is_extension_install()) {
+ dangerousWarning = l10n_util::GetNSStringWithFixup(
+ IDS_PROMPT_DANGEROUS_DOWNLOAD_EXTENSION);
+ confirmButtonTitle = l10n_util::GetNSStringWithFixup(
+ IDS_CONTINUE_EXTENSION_DOWNLOAD);
+ } else {
+ // This basic fixup copies Windows DownloadItemView::DownloadItemView().
+
+ // Extract the file extension (if any).
+ FilePath filename(downloadModel->download()->target_name());
+ FilePath::StringType extension = filename.Extension();
+
+ // Remove leading '.' from the extension
+ if (extension.length() > 0)
+ extension = extension.substr(1);
+
+ // Elide giant extensions.
+ if (extension.length() > kFileNameMaxLength / 2) {
+ std::wstring wide_extension;
+ gfx::ElideString(UTF8ToWide(extension), kFileNameMaxLength / 2,
+ &wide_extension);
+ extension = WideToUTF8(wide_extension);
+ }
+
+ // Rebuild the filename.extension.
+ std::wstring rootname = UTF8ToWide(filename.RemoveExtension().value());
+ gfx::ElideString(rootname, kFileNameMaxLength - extension.length(),
+ &rootname);
+ std::string new_filename = WideToUTF8(rootname);
+ if (extension.length())
+ new_filename += std::string(".") + extension;
+
+ dangerousWarning = l10n_util::GetNSStringFWithFixup(
+ IDS_PROMPT_DANGEROUS_DOWNLOAD, UTF8ToUTF16(new_filename));
+ confirmButtonTitle = l10n_util::GetNSStringWithFixup(IDS_SAVE_DOWNLOAD);
+ }
+ [dangerousDownloadLabel_ setStringValue:dangerousWarning];
+ [dangerousDownloadConfirmButton_ setTitle:confirmButtonTitle];
+ return;
+ }
+
+ // Set correct popup menu. Also, set draggable download on completion.
+ if (downloadModel->download()->state() == DownloadItem::COMPLETE) {
+ [progressView_ setMenu:completeDownloadMenu_];
+ [progressView_ setDownload:downloadModel->download()->full_path()];
+ } else {
+ [progressView_ setMenu:activeDownloadMenu_];
+ }
+
+ [cell_ setStateFromDownload:downloadModel];
+}
+
+- (void)setIcon:(NSImage*)icon {
+ [cell_ setImage:icon];
+}
+
+- (void)remove {
+ // We are deleted after this!
+ [shelf_ remove:self];
+}
+
+- (void)updateVisibility:(id)sender {
+ if ([[self view] window])
+ [self updateTheme:[[[self view] window] themeProvider]];
+
+ NSView* view = [self view];
+ NSRect containerFrame = [[view superview] frame];
+ [view setHidden:(NSMaxX([view frame]) > NSWidth(containerFrame))];
+}
+
+- (void)downloadWasOpened {
+ [shelf_ downloadWasOpened:self];
+}
+
+- (IBAction)handleButtonClick:(id)sender {
+ NSEvent* event = [NSApp currentEvent];
+ if ([event modifierFlags] & NSCommandKeyMask) {
+ // Let cmd-click show the file in Finder, like e.g. in Safari and Spotlight.
+ menuBridge_->ExecuteCommand(DownloadShelfContextMenuMac::SHOW_IN_FOLDER);
+ } else {
+ DownloadItem* download = bridge_->download_model()->download();
+ download->OpenDownload();
+ }
+}
+
+- (NSSize)preferredSize {
+ if (state_ == kNormal)
+ return [progressView_ frame].size;
+ DCHECK_EQ(kDangerous, state_);
+ return [dangerousDownloadView_ frame].size;
+}
+
+- (DownloadItem*)download {
+ return bridge_->download_model()->download();
+}
+
+- (void)updateToolTip {
+ string16 elidedFilename = gfx::ElideFilename(
+ [self download]->GetFileNameToReportUser(),
+ gfx::Font(), kToolTipMaxWidth);
+ [progressView_ setToolTip:base::SysUTF16ToNSString(elidedFilename)];
+}
+
+- (void)clearDangerousMode {
+ [self setState:kNormal];
+ // The state change hide the dangerouse download view and is now showing the
+ // download progress view. This means the view is likely to be a different
+ // size, so trigger a shelf layout to fix up spacing.
+ [shelf_ layoutItems];
+}
+
+- (BOOL)isDangerousMode {
+ return state_ == kDangerous;
+}
+
+- (void)setState:(DownoadItemState)state {
+ if (state_ == state)
+ return;
+ state_ = state;
+ if (state_ == kNormal) {
+ [progressView_ setHidden:NO];
+ [dangerousDownloadView_ setHidden:YES];
+ } else {
+ DCHECK_EQ(kDangerous, state_);
+ [progressView_ setHidden:YES];
+ [dangerousDownloadView_ setHidden:NO];
+ }
+ // NOTE: Do not relayout the shelf, as this could get called during initial
+ // setup of the the item, so the localized text and sizing might not have
+ // happened yet.
+}
+
+// Called after the current theme has changed.
+- (void)themeDidChangeNotification:(NSNotification*)aNotification {
+ ThemeProvider* themeProvider =
+ static_cast<ThemeProvider*>([[aNotification object] pointerValue]);
+ [self updateTheme:themeProvider];
+}
+
+// Adapt appearance to the current theme. Called after theme changes and before
+// this is shown for the first time.
+- (void)updateTheme:(ThemeProvider*)themeProvider {
+ NSColor* color =
+ themeProvider->GetNSColor(BrowserThemeProvider::COLOR_TAB_TEXT, true);
+ [dangerousDownloadLabel_ setTextColor:color];
+}
+
+- (IBAction)saveDownload:(id)sender {
+ // The user has confirmed a dangerous download. We record how quickly the
+ // user did this to detect whether we're being clickjacked.
+ UMA_HISTOGRAM_LONG_TIMES("clickjacking.save_download",
+ base::Time::Now() - creationTime_);
+ // This will change the state and notify us.
+ bridge_->download_model()->download()->DangerousDownloadValidated();
+}
+
+- (IBAction)discardDownload:(id)sender {
+ UMA_HISTOGRAM_LONG_TIMES("clickjacking.discard_download",
+ base::Time::Now() - creationTime_);
+ if (bridge_->download_model()->download()->state() ==
+ DownloadItem::IN_PROGRESS)
+ bridge_->download_model()->download()->Cancel(true);
+ bridge_->download_model()->download()->Remove(true);
+ // WARNING: we are deleted at this point. Don't access 'this'.
+}
+
+
+// Sets the enabled and checked state of a particular menu item for this
+// download. We translate the NSMenuItem selection to menu selections understood
+// by the non platform specific download context menu.
+- (BOOL)validateMenuItem:(NSMenuItem *)item {
+ SEL action = [item action];
+
+ int actionId = 0;
+ if (action == @selector(handleOpen:)) {
+ actionId = DownloadShelfContextMenuMac::OPEN_WHEN_COMPLETE;
+ } else if (action == @selector(handleAlwaysOpen:)) {
+ actionId = DownloadShelfContextMenuMac::ALWAYS_OPEN_TYPE;
+ } else if (action == @selector(handleReveal:)) {
+ actionId = DownloadShelfContextMenuMac::SHOW_IN_FOLDER;
+ } else if (action == @selector(handleCancel:)) {
+ actionId = DownloadShelfContextMenuMac::CANCEL;
+ } else if (action == @selector(handleTogglePause:)) {
+ actionId = DownloadShelfContextMenuMac::TOGGLE_PAUSE;
+ } else {
+ NOTREACHED();
+ return YES;
+ }
+
+ if (menuBridge_->IsCommandIdChecked(actionId))
+ [item setState:NSOnState];
+ else
+ [item setState:NSOffState];
+
+ return menuBridge_->IsCommandIdEnabled(actionId) ? YES : NO;
+}
+
+- (IBAction)handleOpen:(id)sender {
+ menuBridge_->ExecuteCommand(
+ DownloadShelfContextMenuMac::OPEN_WHEN_COMPLETE);
+}
+
+- (IBAction)handleAlwaysOpen:(id)sender {
+ menuBridge_->ExecuteCommand(
+ DownloadShelfContextMenuMac::ALWAYS_OPEN_TYPE);
+}
+
+- (IBAction)handleReveal:(id)sender {
+ menuBridge_->ExecuteCommand(DownloadShelfContextMenuMac::SHOW_IN_FOLDER);
+}
+
+- (IBAction)handleCancel:(id)sender {
+ menuBridge_->ExecuteCommand(DownloadShelfContextMenuMac::CANCEL);
+}
+
+- (IBAction)handleTogglePause:(id)sender {
+ if([sender state] == NSOnState) {
+ [sender setTitle:l10n_util::GetNSStringWithFixup(
+ IDS_DOWNLOAD_MENU_PAUSE_ITEM)];
+ } else {
+ [sender setTitle:l10n_util::GetNSStringWithFixup(
+ IDS_DOWNLOAD_MENU_RESUME_ITEM)];
+ }
+ menuBridge_->ExecuteCommand(DownloadShelfContextMenuMac::TOGGLE_PAUSE);
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/download/download_item_mac.h b/chrome/browser/ui/cocoa/download/download_item_mac.h
new file mode 100644
index 0000000..6ad83a3
--- /dev/null
+++ b/chrome/browser/ui/cocoa/download/download_item_mac.h
@@ -0,0 +1,63 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_DOWNLOAD_DOWNLOAD_ITEM_MAC_H_
+#define CHROME_BROWSER_UI_COCOA_DOWNLOAD_DOWNLOAD_ITEM_MAC_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/cancelable_request.h"
+#include "chrome/browser/download/download_item.h"
+#include "chrome/browser/download/download_manager.h"
+#include "chrome/browser/icon_manager.h"
+
+class BaseDownloadItemModel;
+@class DownloadItemController;
+
+// A class that bridges the visible mac download items to chromium's download
+// model. The owning object (DownloadItemController) must explicitly call
+// |LoadIcon| if it wants to display the icon associated with this download.
+
+class DownloadItemMac : DownloadItem::Observer {
+ public:
+ // DownloadItemMac takes ownership of |download_model|.
+ DownloadItemMac(BaseDownloadItemModel* download_model,
+ DownloadItemController* controller);
+
+ // Destructor.
+ ~DownloadItemMac();
+
+ // DownloadItem::Observer implementation
+ virtual void OnDownloadUpdated(DownloadItem* download);
+ virtual void OnDownloadOpened(DownloadItem* download);
+ virtual void OnDownloadFileCompleted(DownloadItem* download) { }
+
+ BaseDownloadItemModel* download_model() { return download_model_.get(); }
+
+ // Asynchronous icon loading support.
+ void LoadIcon();
+
+ private:
+ // Callback for asynchronous icon loading.
+ void OnExtractIconComplete(IconManager::Handle handle, SkBitmap* icon_bitmap);
+
+ // The download item model we represent.
+ scoped_ptr<BaseDownloadItemModel> download_model_;
+
+ // The objective-c controller object.
+ DownloadItemController* item_controller_; // weak, owns us.
+
+ // For canceling an in progress icon request.
+ CancelableRequestConsumerT<int, 0> icon_consumer_;
+
+ // Stores the last known path where the file will be saved.
+ FilePath lastFilePath_;
+
+ DISALLOW_COPY_AND_ASSIGN(DownloadItemMac);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_DOWNLOAD_DOWNLOAD_ITEM_MAC_H_
diff --git a/chrome/browser/ui/cocoa/download/download_item_mac.mm b/chrome/browser/ui/cocoa/download/download_item_mac.mm
new file mode 100644
index 0000000..f39cb96
--- /dev/null
+++ b/chrome/browser/ui/cocoa/download/download_item_mac.mm
@@ -0,0 +1,101 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/download/download_item_mac.h"
+
+#include "base/callback.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/download/download_item.h"
+#include "chrome/browser/download/download_item_model.h"
+#import "chrome/browser/ui/cocoa/download/download_item_controller.h"
+#include "chrome/browser/ui/cocoa/download/download_util_mac.h"
+#include "skia/ext/skia_utils_mac.h"
+
+// DownloadItemMac -------------------------------------------------------------
+
+DownloadItemMac::DownloadItemMac(BaseDownloadItemModel* download_model,
+ DownloadItemController* controller)
+ : download_model_(download_model), item_controller_(controller) {
+ download_model_->download()->AddObserver(this);
+}
+
+DownloadItemMac::~DownloadItemMac() {
+ download_model_->download()->RemoveObserver(this);
+ icon_consumer_.CancelAllRequests();
+}
+
+void DownloadItemMac::OnDownloadUpdated(DownloadItem* download) {
+ DCHECK_EQ(download, download_model_->download());
+
+ if ([item_controller_ isDangerousMode] &&
+ download->safety_state() == DownloadItem::DANGEROUS_BUT_VALIDATED) {
+ // We have been approved.
+ [item_controller_ clearDangerousMode];
+ }
+
+ if (download->GetUserVerifiedFilePath() != lastFilePath_) {
+ // Turns out the file path is "unconfirmed %d.crdownload" for dangerous
+ // downloads. When the download is confirmed, the file is renamed on
+ // another thread, so reload the icon if the download filename changes.
+ LoadIcon();
+ lastFilePath_ = download->GetUserVerifiedFilePath();
+
+ [item_controller_ updateToolTip];
+ }
+
+ switch (download->state()) {
+ case DownloadItem::REMOVING:
+ [item_controller_ remove]; // We're deleted now!
+ break;
+ case DownloadItem::COMPLETE:
+ if (download->auto_opened()) {
+ [item_controller_ remove]; // We're deleted now!
+ return;
+ }
+ download_util::NotifySystemOfDownloadComplete(download->full_path());
+ // fall through
+ case DownloadItem::IN_PROGRESS:
+ case DownloadItem::CANCELLED:
+ [item_controller_ setStateFromDownload:download_model_.get()];
+ break;
+ default:
+ NOTREACHED();
+ }
+}
+
+void DownloadItemMac::OnDownloadOpened(DownloadItem* download) {
+ DCHECK_EQ(download, download_model_->download());
+ [item_controller_ downloadWasOpened];
+}
+
+void DownloadItemMac::LoadIcon() {
+ IconManager* icon_manager = g_browser_process->icon_manager();
+ if (!icon_manager) {
+ NOTREACHED();
+ return;
+ }
+
+ // We may already have this particular image cached.
+ FilePath file = download_model_->download()->GetUserVerifiedFilePath();
+ SkBitmap* icon_bitmap = icon_manager->LookupIcon(file, IconLoader::SMALL);
+ if (icon_bitmap) {
+ NSImage* icon = gfx::SkBitmapToNSImage(*icon_bitmap);
+ [item_controller_ setIcon:icon];
+ return;
+ }
+
+ // The icon isn't cached, load it asynchronously.
+ icon_manager->LoadIcon(file, IconLoader::SMALL, &icon_consumer_,
+ NewCallback(this,
+ &DownloadItemMac::OnExtractIconComplete));
+}
+
+void DownloadItemMac::OnExtractIconComplete(IconManager::Handle handle,
+ SkBitmap* icon_bitmap) {
+ if (!icon_bitmap)
+ return;
+
+ NSImage* icon = gfx::SkBitmapToNSImage(*icon_bitmap);
+ [item_controller_ setIcon:icon];
+}
diff --git a/chrome/browser/ui/cocoa/download/download_shelf_controller.h b/chrome/browser/ui/cocoa/download/download_shelf_controller.h
new file mode 100644
index 0000000..e75911f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/download/download_shelf_controller.h
@@ -0,0 +1,103 @@
+// Copyright (c) 2009 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>
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+#import "chrome/browser/ui/cocoa/view_resizer.h"
+
+@class AnimatableView;
+class BaseDownloadItemModel;
+class Browser;
+@class BrowserWindowController;
+@class DownloadItemController;
+class DownloadShelf;
+@class DownloadShelfView;
+@class HyperlinkButtonCell;
+
+// A controller class that manages the download shelf for one window. It is
+// responsible for the behavior of the shelf itself (showing/hiding, handling
+// the link, layout) as well as for managing the download items it contains.
+//
+// All the files in cocoa/downloads_* are related as follows:
+//
+// download_shelf_mac bridges calls from chromium's c++ world to the objc
+// download_shelf_controller for the shelf (this file). The shelf's background
+// is drawn by download_shelf_view. Every item in a shelf is controlled by a
+// download_item_controller.
+//
+// download_item_mac bridges calls from chromium's c++ world to the objc
+// download_item_controller, which is responsible for managing a single item
+// on the shelf. The item controller loads its UI from a xib file, where the
+// UI of an item itself is represented by a button that is drawn by
+// download_item_cell.
+
+@interface DownloadShelfController : NSViewController<NSTextViewDelegate> {
+ @private
+ IBOutlet HyperlinkButtonCell* showAllDownloadsCell_;
+
+ IBOutlet NSImageView* image_;
+
+ BOOL barIsVisible_;
+
+ scoped_ptr<DownloadShelf> bridge_;
+
+ // Height of the shelf when it's fully visible.
+ CGFloat maxShelfHeight_;
+
+ // Current height of the shelf. Changes while the shelf is animating in or
+ // out.
+ CGFloat currentShelfHeight_;
+
+ // Used to autoclose the shelf when the mouse is moved off it. Is non-nil
+ // only when a subsequent mouseExited event can trigger autoclose or when a
+ // subsequent mouseEntered event will cancel autoclose. Is nil otherwise.
+ scoped_nsobject<NSTrackingArea> trackingArea_;
+
+ // The download items we have added to our shelf.
+ scoped_nsobject<NSMutableArray> downloadItemControllers_;
+
+ // The container that contains (and clamps) all the download items.
+ IBOutlet NSView* itemContainerView_;
+
+ // Delegate that handles resizing our view.
+ id<ViewResizer> resizeDelegate_;
+};
+
+- (id)initWithBrowser:(Browser*)browser
+ resizeDelegate:(id<ViewResizer>)resizeDelegate;
+
+- (IBAction)showDownloadsTab:(id)sender;
+
+// Returns our view cast as an AnimatableView.
+- (AnimatableView*)animatableView;
+
+- (DownloadShelf*)bridge;
+- (BOOL)isVisible;
+
+- (IBAction)show:(id)sender;
+
+// Run when the user clicks the close button on the right side of the shelf.
+- (IBAction)hide:(id)sender;
+
+- (void)addDownloadItem:(BaseDownloadItemModel*)model;
+
+// Remove a download, possibly via clearing browser data.
+- (void)remove:(DownloadItemController*)download;
+
+// Called by individual item controllers when their downloads are opened.
+- (void)downloadWasOpened:(DownloadItemController*)download;
+
+// Notification that we are closing and should release our downloads.
+- (void)exiting;
+
+// Return the height of the download shelf.
+- (float)height;
+
+// Re-layouts all download items based on their current state.
+- (void)layoutItems;
+
+@end
diff --git a/chrome/browser/ui/cocoa/download/download_shelf_controller.mm b/chrome/browser/ui/cocoa/download/download_shelf_controller.mm
new file mode 100644
index 0000000..4238b98
--- /dev/null
+++ b/chrome/browser/ui/cocoa/download/download_shelf_controller.mm
@@ -0,0 +1,426 @@
+// 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 "chrome/browser/ui/cocoa/download/download_shelf_controller.h"
+
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/mac_util.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/download/download_item.h"
+#include "chrome/browser/download/download_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/ui/browser.h"
+#import "chrome/browser/ui/cocoa/animatable_view.h"
+#include "chrome/browser/ui/cocoa/browser_window_cocoa.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#include "chrome/browser/ui/cocoa/download/download_item_controller.h"
+#include "chrome/browser/ui/cocoa/download/download_shelf_mac.h"
+#import "chrome/browser/ui/cocoa/download/download_shelf_view.h"
+#import "chrome/browser/ui/cocoa/hyperlink_button_cell.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
+
+// Download shelf autoclose behavior:
+//
+// The download shelf autocloses if all of this is true:
+// 1) An item on the shelf has just been opened.
+// 2) All remaining items on the shelf have been opened in the past.
+// 3) The mouse leaves the shelf and remains off the shelf for 5 seconds.
+//
+// If the mouse re-enters the shelf within the 5 second grace period, the
+// autoclose is canceled. An autoclose can only be scheduled in response to a
+// shelf item being opened or removed. If an item is opened and then the
+// resulting autoclose is canceled, subsequent mouse exited events will NOT
+// trigger an autoclose.
+//
+// If the shelf is manually closed while a download is still in progress, that
+// download is marked as "opened" for these purposes. If the shelf is later
+// reopened, these previously-in-progress download will not block autoclose,
+// even if that download was never actually clicked on and opened.
+
+namespace {
+
+// Max number of download views we'll contain. Any time a view is added and
+// we already have this many download views, one is removed.
+const size_t kMaxDownloadItemCount = 16;
+
+// Horizontal padding between two download items.
+const int kDownloadItemPadding = 0;
+
+// Duration for the open-new-leftmost-item animation, in seconds.
+const NSTimeInterval kDownloadItemOpenDuration = 0.8;
+
+// Duration for download shelf closing animation, in seconds.
+const NSTimeInterval kDownloadShelfCloseDuration = 0.12;
+
+// Amount of time between when the mouse is moved off the shelf and the shelf is
+// autoclosed, in seconds.
+const NSTimeInterval kAutoCloseDelaySeconds = 5;
+
+} // namespace
+
+@interface DownloadShelfController(Private)
+- (void)showDownloadShelf:(BOOL)enable;
+- (void)layoutItems:(BOOL)skipFirst;
+- (void)closed;
+- (BOOL)canAutoClose;
+
+- (void)updateTheme;
+- (void)themeDidChangeNotification:(NSNotification*)notification;
+- (void)viewFrameDidChange:(NSNotification*)notification;
+
+- (void)installTrackingArea;
+- (void)cancelAutoCloseAndRemoveTrackingArea;
+@end
+
+
+@implementation DownloadShelfController
+
+- (id)initWithBrowser:(Browser*)browser
+ resizeDelegate:(id<ViewResizer>)resizeDelegate {
+ if ((self = [super initWithNibName:@"DownloadShelf"
+ bundle:mac_util::MainAppBundle()])) {
+ resizeDelegate_ = resizeDelegate;
+ maxShelfHeight_ = NSHeight([[self view] bounds]);
+ currentShelfHeight_ = maxShelfHeight_;
+
+ // Reset the download shelf's frame height to zero. It will be properly
+ // positioned and sized the first time we try to set its height. (Just
+ // setting the rect to NSZeroRect does not work: it confuses Cocoa's view
+ // layout logic. If the shelf's width is too small, cocoa makes the download
+ // item container view wider than the browser window).
+ NSRect frame = [[self view] frame];
+ frame.size.height = 0;
+ [[self view] setFrame:frame];
+
+ downloadItemControllers_.reset([[NSMutableArray alloc] init]);
+
+ bridge_.reset(new DownloadShelfMac(browser, self));
+ }
+ return self;
+}
+
+- (void)awakeFromNib {
+ NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
+ [defaultCenter addObserver:self
+ selector:@selector(themeDidChangeNotification:)
+ name:kBrowserThemeDidChangeNotification
+ object:nil];
+
+ [[self animatableView] setResizeDelegate:resizeDelegate_];
+ [[self view] setPostsFrameChangedNotifications:YES];
+ [defaultCenter addObserver:self
+ selector:@selector(viewFrameDidChange:)
+ name:NSViewFrameDidChangeNotification
+ object:[self view]];
+
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ NSImage* favicon = rb.GetNativeImageNamed(IDR_DOWNLOADS_FAVICON);
+ DCHECK(favicon);
+ [image_ setImage:favicon];
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [self cancelAutoCloseAndRemoveTrackingArea];
+
+ // The controllers will unregister themselves as observers when they are
+ // deallocated. No need to do that here.
+ [super dealloc];
+}
+
+// Called after the current theme has changed.
+- (void)themeDidChangeNotification:(NSNotification*)notification {
+ [self updateTheme];
+}
+
+// Called after the frame's rect has changed; usually when the height is
+// animated.
+- (void)viewFrameDidChange:(NSNotification*)notification {
+ // Anchor subviews at the top of |view|, so that it looks like the shelf
+ // is sliding out.
+ CGFloat newShelfHeight = NSHeight([[self view] frame]);
+ if (newShelfHeight == currentShelfHeight_)
+ return;
+
+ for (NSView* view in [[self view] subviews]) {
+ NSRect frame = [view frame];
+ frame.origin.y -= currentShelfHeight_ - newShelfHeight;
+ [view setFrame:frame];
+ }
+ currentShelfHeight_ = newShelfHeight;
+}
+
+// Adapt appearance to the current theme. Called after theme changes and before
+// this is shown for the first time.
+- (void)updateTheme {
+ NSColor* color = nil;
+
+ if (bridge_.get() && bridge_->browser() && bridge_->browser()->profile()) {
+ ThemeProvider* provider = bridge_->browser()->profile()->GetThemeProvider();
+
+ color =
+ provider->GetNSColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT, false);
+ }
+
+ if (!color)
+ color = [HyperlinkButtonCell defaultTextColor];
+
+ [showAllDownloadsCell_ setTextColor:color];
+}
+
+- (AnimatableView*)animatableView {
+ return static_cast<AnimatableView*>([self view]);
+}
+
+- (void)showDownloadsTab:(id)sender {
+ bridge_->browser()->ShowDownloadsTab();
+}
+
+- (void)remove:(DownloadItemController*)download {
+ // Look for the download in our controller array and remove it. This will
+ // explicity release it so that it removes itself as an Observer of the
+ // DownloadItem. We don't want to wait for autorelease since the DownloadItem
+ // we are observing will likely be gone by then.
+ [[NSNotificationCenter defaultCenter] removeObserver:download];
+
+ // TODO(dmaclach): Remove -- http://crbug.com/25845
+ [[download view] removeFromSuperview];
+
+ [downloadItemControllers_ removeObject:download];
+
+ [self layoutItems];
+
+ // Check to see if we have any downloads remaining and if not, hide the shelf.
+ if (![downloadItemControllers_ count])
+ [self showDownloadShelf:NO];
+}
+
+- (void)downloadWasOpened:(DownloadItemController*)item_controller {
+ // This should only be called on the main thead.
+ DCHECK([NSThread isMainThread]);
+
+ if ([self canAutoClose])
+ [self installTrackingArea];
+}
+
+// We need to explicitly release our download controllers here since they need
+// to remove themselves as observers before the remaining shutdown happens.
+- (void)exiting {
+ [[self animatableView] stopAnimation];
+ [self cancelAutoCloseAndRemoveTrackingArea];
+ downloadItemControllers_.reset();
+}
+
+// Show or hide the bar based on the value of |enable|. Handles animating the
+// resize of the content view.
+- (void)showDownloadShelf:(BOOL)enable {
+ if ([self isVisible] == enable)
+ return;
+
+ if ([[self view] window])
+ [self updateTheme];
+
+ // Animate the shelf out, but not in.
+ // TODO(rohitrao): We do not animate on the way in because Cocoa is already
+ // doing a lot of work to set up the download arrow animation. I've chosen to
+ // do no animation over janky animation. Find a way to make animating in
+ // smoother.
+ AnimatableView* view = [self animatableView];
+ if (enable)
+ [view setHeight:maxShelfHeight_];
+ else
+ [view animateToNewHeight:0 duration:kDownloadShelfCloseDuration];
+
+ barIsVisible_ = enable;
+}
+
+- (DownloadShelf*)bridge {
+ return bridge_.get();
+}
+
+- (BOOL)isVisible {
+ return barIsVisible_;
+}
+
+- (void)show:(id)sender {
+ [self showDownloadShelf:YES];
+}
+
+- (void)hide:(id)sender {
+ [self cancelAutoCloseAndRemoveTrackingArea];
+
+ // If |sender| isn't nil, then we're being closed from the UI by the user and
+ // we need to tell our shelf implementation to close. Otherwise, we're being
+ // closed programmatically by our shelf implementation.
+ if (sender)
+ bridge_->Close();
+ else
+ [self showDownloadShelf:NO];
+}
+
+- (void)animationDidEnd:(NSAnimation*)animation {
+ if (![self isVisible])
+ [self closed];
+}
+
+- (float)height {
+ return maxShelfHeight_;
+}
+
+// If |skipFirst| is true, the frame of the leftmost item is not set.
+- (void)layoutItems:(BOOL)skipFirst {
+ CGFloat currentX = 0;
+ for (DownloadItemController* itemController
+ in downloadItemControllers_.get()) {
+ NSRect frame = [[itemController view] frame];
+ frame.origin.x = currentX;
+ frame.size.width = [itemController preferredSize].width;
+ if (!skipFirst)
+ [[[itemController view] animator] setFrame:frame];
+ currentX += frame.size.width + kDownloadItemPadding;
+ skipFirst = NO;
+ }
+}
+
+- (void)layoutItems {
+ [self layoutItems:NO];
+}
+
+- (void)addDownloadItem:(BaseDownloadItemModel*)model {
+ DCHECK([NSThread isMainThread]);
+ [self cancelAutoCloseAndRemoveTrackingArea];
+
+ // Insert new item at the left.
+ scoped_nsobject<DownloadItemController> controller(
+ [[DownloadItemController alloc] initWithModel:model shelf:self]);
+
+ // Adding at index 0 in NSMutableArrays is O(1).
+ [downloadItemControllers_ insertObject:controller.get() atIndex:0];
+
+ [itemContainerView_ addSubview:[controller view]];
+
+ // The controller is in charge of removing itself as an observer in its
+ // dealloc.
+ [[NSNotificationCenter defaultCenter]
+ addObserver:controller
+ selector:@selector(updateVisibility:)
+ name:NSViewFrameDidChangeNotification
+ object:[controller view]];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:controller
+ selector:@selector(updateVisibility:)
+ name:NSViewFrameDidChangeNotification
+ object:itemContainerView_];
+
+ // Start at width 0...
+ NSSize size = [controller preferredSize];
+ NSRect frame = NSMakeRect(0, 0, 0, size.height);
+ [[controller view] setFrame:frame];
+
+ // ...then animate in
+ frame.size.width = size.width;
+ [NSAnimationContext beginGrouping];
+ [[NSAnimationContext currentContext]
+ gtm_setDuration:kDownloadItemOpenDuration
+ eventMask:NSLeftMouseUpMask];
+ [[[controller view] animator] setFrame:frame];
+ [NSAnimationContext endGrouping];
+
+ // Keep only a limited number of items in the shelf.
+ if ([downloadItemControllers_ count] > kMaxDownloadItemCount) {
+ DCHECK(kMaxDownloadItemCount > 0);
+
+ // Since no user will ever see the item being removed (needs a horizontal
+ // screen resolution greater than 3200 at 16 items at 200 pixels each),
+ // there's no point in animating the removal.
+ [self remove:[downloadItemControllers_ lastObject]];
+ }
+
+ // Finally, move the remaining items to the right. Skip the first item when
+ // laying out the items, so that the longer animation duration we set up above
+ // is not overwritten.
+ [self layoutItems:YES];
+}
+
+- (void)closed {
+ NSUInteger i = 0;
+ while (i < [downloadItemControllers_ count]) {
+ DownloadItemController* itemController =
+ [downloadItemControllers_ objectAtIndex:i];
+ DownloadItem* download = [itemController download];
+ bool isTransferDone =
+ download->state() == DownloadItem::COMPLETE ||
+ download->state() == DownloadItem::CANCELLED;
+ if (isTransferDone &&
+ download->safety_state() != DownloadItem::DANGEROUS) {
+ [self remove:itemController];
+ } else {
+ // Treat the item as opened when we close. This way if we get shown again
+ // the user need not open this item for the shelf to auto-close.
+ download->set_opened(true);
+ ++i;
+ }
+ }
+}
+
+- (void)mouseEntered:(NSEvent*)event {
+ // If the mouse re-enters the download shelf, cancel the auto-close. Further
+ // mouse exits should not trigger autoclose, so also remove the tracking area.
+ [self cancelAutoCloseAndRemoveTrackingArea];
+}
+
+- (void)mouseExited:(NSEvent*)event {
+ // Cancel any previous hide requests, just to be safe.
+ [NSObject cancelPreviousPerformRequestsWithTarget:self
+ selector:@selector(hide:)
+ object:self];
+
+ // Schedule an autoclose after a delay. If the mouse is moved back into the
+ // view, or if an item is added to the shelf, the timer will be canceled.
+ [self performSelector:@selector(hide:)
+ withObject:self
+ afterDelay:kAutoCloseDelaySeconds];
+}
+
+- (BOOL)canAutoClose {
+ for (NSUInteger i = 0; i < [downloadItemControllers_ count]; ++i) {
+ DownloadItemController* itemController =
+ [downloadItemControllers_ objectAtIndex:i];
+ if (![itemController download]->opened())
+ return NO;
+ }
+ return YES;
+}
+
+- (void)installTrackingArea {
+ // Install the tracking area to listen for mouseExited messages and trigger
+ // the shelf autoclose.
+ if (trackingArea_.get())
+ return;
+
+ trackingArea_.reset([[NSTrackingArea alloc]
+ initWithRect:[[self view] bounds]
+ options:NSTrackingMouseEnteredAndExited |
+ NSTrackingActiveAlways
+ owner:self
+ userInfo:nil]);
+ [[self view] addTrackingArea:trackingArea_];
+}
+
+- (void)cancelAutoCloseAndRemoveTrackingArea {
+ [NSObject cancelPreviousPerformRequestsWithTarget:self
+ selector:@selector(hide:)
+ object:self];
+
+ if (trackingArea_.get()) {
+ [[self view] removeTrackingArea:trackingArea_];
+ trackingArea_.reset(nil);
+ }
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/download/download_shelf_mac.h b/chrome/browser/ui/cocoa/download/download_shelf_mac.h
new file mode 100644
index 0000000..ddfc6f8
--- /dev/null
+++ b/chrome/browser/ui/cocoa/download/download_shelf_mac.h
@@ -0,0 +1,43 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_DOWNLOAD_DOWNLOAD_SHELF_MAC_H_
+#define CHROME_BROWSER_UI_COCOA_DOWNLOAD_DOWNLOAD_SHELF_MAC_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "chrome/browser/download/download_shelf.h"
+
+class BaseDownloadItemModel;
+class CustomDrawButton;
+class DownloadItemMac;
+
+@class ShelfView;
+@class DownloadShelfController;
+
+// A class to bridge the chromium download shelf to mac gui. This is just a
+// wrapper class that forward everything to DownloadShelfController.
+
+class DownloadShelfMac : public DownloadShelf {
+ public:
+ explicit DownloadShelfMac(Browser* browser,
+ DownloadShelfController* controller);
+
+ // DownloadShelf implementation.
+ virtual void AddDownload(BaseDownloadItemModel* download_model);
+ virtual bool IsShowing() const;
+ virtual bool IsClosing() const;
+ virtual void Show();
+ virtual void Close();
+ virtual Browser* browser() const { return browser_; }
+
+ private:
+ // The browser that owns this shelf.
+ Browser* browser_;
+
+ DownloadShelfController* shelf_controller_; // weak, owns us
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_DOWNLOAD_DOWNLOAD_SHELF_MAC_H_
diff --git a/chrome/browser/ui/cocoa/download/download_shelf_mac.mm b/chrome/browser/ui/cocoa/download/download_shelf_mac.mm
new file mode 100644
index 0000000..53c13f4
--- /dev/null
+++ b/chrome/browser/ui/cocoa/download/download_shelf_mac.mm
@@ -0,0 +1,40 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/download/download_shelf_mac.h"
+
+#include "chrome/browser/download/download_item_model.h"
+#include "chrome/browser/ui/browser.h"
+#import "chrome/browser/ui/cocoa/download/download_shelf_controller.h"
+#include "chrome/browser/ui/cocoa/download/download_item_mac.h"
+
+DownloadShelfMac::DownloadShelfMac(Browser* browser,
+ DownloadShelfController* controller)
+ : browser_(browser),
+ shelf_controller_(controller) {
+}
+
+void DownloadShelfMac::AddDownload(BaseDownloadItemModel* download_model) {
+ [shelf_controller_ addDownloadItem:download_model];
+ Show();
+}
+
+bool DownloadShelfMac::IsShowing() const {
+ return [shelf_controller_ isVisible] == YES;
+}
+
+bool DownloadShelfMac::IsClosing() const {
+ // TODO(estade): This is never called. For now just return false.
+ return false;
+}
+
+void DownloadShelfMac::Show() {
+ [shelf_controller_ show:nil];
+ browser_->UpdateDownloadShelfVisibility(true);
+}
+
+void DownloadShelfMac::Close() {
+ [shelf_controller_ hide:nil];
+ browser_->UpdateDownloadShelfVisibility(false);
+}
diff --git a/chrome/browser/ui/cocoa/download/download_shelf_mac_unittest.mm b/chrome/browser/ui/cocoa/download/download_shelf_mac_unittest.mm
new file mode 100644
index 0000000..961d2db
--- /dev/null
+++ b/chrome/browser/ui/cocoa/download/download_shelf_mac_unittest.mm
@@ -0,0 +1,91 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/download/download_shelf_mac.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+// A fake implementation of DownloadShelfController. It implements only the
+// methods that DownloadShelfMac call during the tests in this file. We get this
+// class into the DownloadShelfMac constructor by some questionable casting --
+// Objective C is a dynamic language, so we pretend that's ok.
+
+@interface FakeDownloadShelfController : NSObject {
+ @public
+ int callCountIsVisible;
+ int callCountShow;
+ int callCountHide;
+}
+
+- (BOOL)isVisible;
+- (IBAction)show:(id)sender;
+- (IBAction)hide:(id)sender;
+@end
+
+@implementation FakeDownloadShelfController
+
+- (BOOL)isVisible {
+ ++callCountIsVisible;
+ return YES;
+}
+
+- (IBAction)show:(id)sender {
+ ++callCountShow;
+}
+
+- (IBAction)hide:(id)sender {
+ ++callCountHide;
+}
+
+@end
+
+
+namespace {
+
+class DownloadShelfMacTest : public CocoaTest {
+
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ shelf_controller_.reset([[FakeDownloadShelfController alloc] init]);
+ }
+
+ protected:
+ scoped_nsobject<FakeDownloadShelfController> shelf_controller_;
+ BrowserTestHelper browser_helper_;
+};
+
+TEST_F(DownloadShelfMacTest, CreationDoesNotCallShow) {
+ // Also make sure the DownloadShelfMacTest constructor doesn't crash.
+ DownloadShelfMac shelf(browser_helper_.browser(),
+ (DownloadShelfController*)shelf_controller_.get());
+ EXPECT_EQ(0, shelf_controller_.get()->callCountShow);
+}
+
+TEST_F(DownloadShelfMacTest, ForwardsShow) {
+ DownloadShelfMac shelf(browser_helper_.browser(),
+ (DownloadShelfController*)shelf_controller_.get());
+ EXPECT_EQ(0, shelf_controller_.get()->callCountShow);
+ shelf.Show();
+ EXPECT_EQ(1, shelf_controller_.get()->callCountShow);
+}
+
+TEST_F(DownloadShelfMacTest, ForwardsHide) {
+ DownloadShelfMac shelf(browser_helper_.browser(),
+ (DownloadShelfController*)shelf_controller_.get());
+ EXPECT_EQ(0, shelf_controller_.get()->callCountHide);
+ shelf.Close();
+ EXPECT_EQ(1, shelf_controller_.get()->callCountHide);
+}
+
+TEST_F(DownloadShelfMacTest, ForwardsIsShowing) {
+ DownloadShelfMac shelf(browser_helper_.browser(),
+ (DownloadShelfController*)shelf_controller_.get());
+ EXPECT_EQ(0, shelf_controller_.get()->callCountIsVisible);
+ shelf.IsShowing();
+ EXPECT_EQ(1, shelf_controller_.get()->callCountIsVisible);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/download/download_shelf_view.h b/chrome/browser/ui/cocoa/download/download_shelf_view.h
new file mode 100644
index 0000000..bcd949c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/download/download_shelf_view.h
@@ -0,0 +1,20 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_DOWNLOAD_DOWNLOAD_SHELF_VIEW_H_
+#define CHROME_BROWSER_UI_COCOA_DOWNLOAD_DOWNLOAD_SHELF_VIEW_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#import "chrome/browser/ui/cocoa/animatable_view.h"
+
+// A view that handles any special rendering for the download shelf, painting
+// a gradient and managing a set of DownloadItemViews.
+
+@interface DownloadShelfView : AnimatableView {
+}
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_DOWNLOAD_DOWNLOAD_SHELF_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/download/download_shelf_view.mm b/chrome/browser/ui/cocoa/download/download_shelf_view.mm
new file mode 100644
index 0000000..f3840ef
--- /dev/null
+++ b/chrome/browser/ui/cocoa/download/download_shelf_view.mm
@@ -0,0 +1,71 @@
+// 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 "chrome/browser/ui/cocoa/download/download_shelf_view.h"
+
+#include "base/scoped_nsobject.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
+#import "chrome/browser/ui/cocoa/themed_window.h"
+#import "chrome/browser/ui/cocoa/view_id_util.h"
+#include "grit/theme_resources.h"
+
+@implementation DownloadShelfView
+
+- (NSColor*)strokeColor {
+ BOOL isKey = [[self window] isKeyWindow];
+ ThemeProvider* themeProvider = [[self window] themeProvider];
+ return themeProvider ? themeProvider->GetNSColor(
+ isKey ? BrowserThemeProvider::COLOR_TOOLBAR_STROKE :
+ BrowserThemeProvider::COLOR_TOOLBAR_STROKE_INACTIVE, true) :
+ [NSColor blackColor];
+}
+
+- (void)drawRect:(NSRect)rect {
+ BOOL isKey = [[self window] isKeyWindow];
+ ThemeProvider* themeProvider = [[self window] themeProvider];
+ if (!themeProvider)
+ return;
+
+ NSColor* backgroundImageColor =
+ themeProvider->GetNSImageColorNamed(IDR_THEME_TOOLBAR, false);
+ if (backgroundImageColor) {
+ // We want our backgrounds for the shelf to be phased from the upper
+ // left hand corner of the view.
+ NSPoint phase = NSMakePoint(0, NSHeight([self bounds]));
+ [[NSGraphicsContext currentContext] setPatternPhase:phase];
+ [backgroundImageColor set];
+ NSRectFill([self bounds]);
+ } else {
+ NSGradient* gradient = themeProvider->GetNSGradient(
+ isKey ? BrowserThemeProvider::GRADIENT_TOOLBAR :
+ BrowserThemeProvider::GRADIENT_TOOLBAR_INACTIVE);
+ NSPoint startPoint = [self convertPoint:NSMakePoint(0, 0) fromView:nil];
+ NSPoint endPoint =
+ [self convertPoint:NSMakePoint(0, [self frame].size.height)
+ fromView:nil];
+
+ [gradient drawFromPoint:startPoint
+ toPoint:endPoint
+ options:NSGradientDrawsBeforeStartingLocation |
+ NSGradientDrawsAfterEndingLocation];
+ }
+
+ // Draw top stroke
+ [[self strokeColor] set];
+ NSRect borderRect, contentRect;
+ NSDivideRect([self bounds], &borderRect, &contentRect, 1, NSMaxYEdge);
+ NSRectFillUsingOperation(borderRect, NSCompositeSourceOver);
+}
+
+// Mouse down events on the download shelf should not allow dragging the parent
+// window around.
+- (BOOL)mouseDownCanMoveWindow {
+ return NO;
+}
+
+- (ViewID)viewID {
+ return VIEW_ID_DOWNLOAD_SHELF;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/download/download_shelf_view_unittest.mm b/chrome/browser/ui/cocoa/download/download_shelf_view_unittest.mm
new file mode 100644
index 0000000..926593f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/download/download_shelf_view_unittest.mm
@@ -0,0 +1,23 @@
+// Copyright (c) 2009 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/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/download/download_shelf_view.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class DownloadShelfViewTest : public CocoaTest {
+};
+
+// This class only needs to do one thing: prevent mouse down events from moving
+// the parent window around.
+TEST_F(DownloadShelfViewTest, CanDragWindow) {
+ scoped_nsobject<DownloadShelfView> view([[DownloadShelfView alloc] init]);
+ EXPECT_FALSE([view mouseDownCanMoveWindow]);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/download/download_started_animation_mac.mm b/chrome/browser/ui/cocoa/download/download_started_animation_mac.mm
new file mode 100644
index 0000000..d95b732
--- /dev/null
+++ b/chrome/browser/ui/cocoa/download/download_started_animation_mac.mm
@@ -0,0 +1,196 @@
+// 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.
+//
+// This file contains the Mac implementation the download animation, displayed
+// at the start of a download. The animation produces an arrow pointing
+// downwards and animates towards the bottom of the window where the new
+// download appears in the download shelf.
+
+#include "chrome/browser/download/download_started_animation.h"
+
+#import <QuartzCore/QuartzCore.h>
+
+#include "app/resource_bundle.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_contents_view_mac.h"
+#include "chrome/common/notification_registrar.h"
+#import "chrome/browser/ui/cocoa/animatable_image.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
+#include "grit/theme_resources.h"
+#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
+#include "third_party/skia/include/utils/mac/SkCGUtils.h"
+
+class DownloadAnimationTabObserver;
+
+// A class for managing the Core Animation download animation.
+// Should be instantiated using +startAnimationWithTabContents:.
+@interface DownloadStartedAnimationMac : NSObject {
+ @private
+ // The observer for the TabContents we are drawing on.
+ scoped_ptr<DownloadAnimationTabObserver> observer_;
+ CGFloat imageWidth_;
+ AnimatableImage* animation_;
+};
+
++ (void)startAnimationWithTabContents:(TabContents*)tabContents;
+
+// Called by the Observer if the tab is hidden or closed.
+- (void)closeAnimation;
+
+@end
+
+// A helper class to monitor tab hidden and closed notifications. If we receive
+// such a notification, we stop the animation.
+class DownloadAnimationTabObserver : public NotificationObserver {
+ public:
+ DownloadAnimationTabObserver(DownloadStartedAnimationMac* owner,
+ TabContents* tab_contents)
+ : owner_(owner),
+ tab_contents_(tab_contents) {
+ registrar_.Add(this,
+ NotificationType::TAB_CONTENTS_HIDDEN,
+ Source<TabContents>(tab_contents_));
+ registrar_.Add(this,
+ NotificationType::TAB_CONTENTS_DESTROYED,
+ Source<TabContents>(tab_contents_));
+ }
+
+ // Runs when a tab is hidden or destroyed. Let our owner know we should end
+ // the animation.
+ void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ // This ends up deleting us.
+ [owner_ closeAnimation];
+ }
+
+ private:
+ // The object we need to inform when we get a notification. Weak.
+ DownloadStartedAnimationMac* owner_;
+
+ // The tab we are observing. Weak.
+ TabContents* tab_contents_;
+
+ // Used for registering to receive notifications and automatic clean up.
+ NotificationRegistrar registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(DownloadAnimationTabObserver);
+};
+
+@implementation DownloadStartedAnimationMac
+
+- (id)initWithTabContents:(TabContents*)tabContents {
+ if ((self = [super init])) {
+ // Load the image of the download arrow.
+ ResourceBundle& bundle = ResourceBundle::GetSharedInstance();
+ NSImage* image = bundle.GetNativeImageNamed(IDR_DOWNLOAD_ANIMATION_BEGIN);
+
+ // Figure out the positioning in the current tab. Try to position the layer
+ // against the left edge, and three times the download image's height from
+ // the bottom of the tab, assuming there is enough room. If there isn't
+ // enough, don't show the animation and let the shelf speak for itself.
+ gfx::Rect bounds;
+ tabContents->GetContainerBounds(&bounds);
+ imageWidth_ = [image size].width;
+ CGFloat imageHeight = [image size].height;
+
+ // Sanity check the size in case there's no room to display the animation.
+ if (bounds.height() < imageHeight) {
+ [self release];
+ return nil;
+ }
+
+ NSView* tabContentsView = tabContents->GetNativeView();
+ NSWindow* parentWindow = [tabContentsView window];
+ if (!parentWindow) {
+ // The tab is no longer frontmost.
+ [self release];
+ return nil;
+ }
+
+ NSPoint origin = [tabContentsView frame].origin;
+ origin = [tabContentsView convertPoint:origin toView:nil];
+ origin = [parentWindow convertBaseToScreen:origin];
+
+ // Create the animation object to assist in animating and fading.
+ CGFloat animationHeight = MIN(bounds.height(), 4 * imageHeight);
+ NSRect frame = NSMakeRect(origin.x, origin.y, imageWidth_, animationHeight);
+ animation_ = [[AnimatableImage alloc] initWithImage:image
+ animationFrame:frame];
+ [parentWindow addChildWindow:animation_ ordered:NSWindowAbove];
+
+ animationHeight = MIN(bounds.height(), 3 * imageHeight);
+ [animation_ setStartFrame:CGRectMake(0, animationHeight,
+ imageWidth_, imageHeight)];
+ [animation_ setEndFrame:CGRectMake(0, imageHeight,
+ imageWidth_, imageHeight)];
+ [animation_ setStartOpacity:1.0];
+ [animation_ setEndOpacity:0.4];
+ [animation_ setDuration:0.6];
+
+ observer_.reset(new DownloadAnimationTabObserver(self, tabContents));
+
+ // Set up to get notified about resize events on the parent window.
+ NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+ [center addObserver:self
+ selector:@selector(parentWindowChanged:)
+ name:NSWindowDidResizeNotification
+ object:parentWindow];
+ // When the animation window closes, it needs to be removed from the
+ // parent window.
+ [center addObserver:self
+ selector:@selector(windowWillClose:)
+ name:NSWindowWillCloseNotification
+ object:animation_];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+// Called when the parent window is resized.
+- (void)parentWindowChanged:(NSNotification*)notification {
+ NSWindow* parentWindow = [animation_ parentWindow];
+ DCHECK([[notification object] isEqual:parentWindow]);
+ NSRect parentFrame = [parentWindow frame];
+ NSRect frame = parentFrame;
+ frame.size.width = MIN(imageWidth_, NSWidth(parentFrame));
+ [animation_ setFrame:frame display:YES];
+}
+
+- (void)closeAnimation {
+ [animation_ close];
+}
+
+// When the animation closes, release self.
+- (void)windowWillClose:(NSNotification*)notification {
+ DCHECK([[notification object] isEqual:animation_]);
+ [[animation_ parentWindow] removeChildWindow:animation_];
+ [self release];
+}
+
++ (void)startAnimationWithTabContents:(TabContents*)contents {
+ // Will be deleted when the animation window closes.
+ DownloadStartedAnimationMac* controller =
+ [[self alloc] initWithTabContents:contents];
+ // The initializer can return nil.
+ if (!controller)
+ return;
+
+ // The |animation_| releases itself when done.
+ [controller->animation_ startAnimation];
+}
+
+@end
+
+void DownloadStartedAnimation::Show(TabContents* tab_contents) {
+ DCHECK(tab_contents);
+
+ // Will be deleted when the animation is complete.
+ [DownloadStartedAnimationMac startAnimationWithTabContents:tab_contents];
+}
diff --git a/chrome/browser/ui/cocoa/download/download_util_mac.h b/chrome/browser/ui/cocoa/download/download_util_mac.h
new file mode 100644
index 0000000..8f99c8b
--- /dev/null
+++ b/chrome/browser/ui/cocoa/download/download_util_mac.h
@@ -0,0 +1,25 @@
+// 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.
+//
+// Download utility functions for Mac OS X.
+
+#ifndef CHROME_BROWSER_UI_COCOA_DOWNLOAD_DOWNLOAD_UTIL_MAC_H_
+#define CHROME_BROWSER_UI_COCOA_DOWNLOAD_DOWNLOAD_UTIL_MAC_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+class FilePath;
+
+namespace download_util {
+
+void AddFileToPasteboard(NSPasteboard* pasteboard, const FilePath& path);
+
+// Notify the system that a download completed. This will cause the download
+// folder in the dock to bounce.
+void NotifySystemOfDownloadComplete(const FilePath& path);
+
+} // namespace download_util
+
+#endif // CHROME_BROWSER_UI_COCOA_DOWNLOAD_DOWNLOAD_UTIL_MAC_H_
diff --git a/chrome/browser/ui/cocoa/download/download_util_mac.mm b/chrome/browser/ui/cocoa/download/download_util_mac.mm
new file mode 100644
index 0000000..baafbbf
--- /dev/null
+++ b/chrome/browser/ui/cocoa/download/download_util_mac.mm
@@ -0,0 +1,83 @@
+// 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.
+//
+// Download utility implementation for Mac OS X.
+
+#include "chrome/browser/ui/cocoa/download/download_util_mac.h"
+
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/download/download_item.h"
+#include "chrome/browser/download/download_manager.h"
+#import "chrome/browser/ui/cocoa/dock_icon.h"
+#include "gfx/native_widget_types.h"
+#include "skia/ext/skia_utils_mac.h"
+
+namespace download_util {
+
+void AddFileToPasteboard(NSPasteboard* pasteboard, const FilePath& path) {
+ // Write information about the file being dragged to the pasteboard.
+ NSString* file = base::SysUTF8ToNSString(path.value());
+ NSArray* fileList = [NSArray arrayWithObject:file];
+ [pasteboard declareTypes:[NSArray arrayWithObject:NSFilenamesPboardType]
+ owner:nil];
+ [pasteboard setPropertyList:fileList forType:NSFilenamesPboardType];
+}
+
+void NotifySystemOfDownloadComplete(const FilePath& path) {
+ NSString* filePath = base::SysUTF8ToNSString(path.value());
+ [[NSDistributedNotificationCenter defaultCenter]
+ postNotificationName:@"com.apple.DownloadFileFinished"
+ object:filePath];
+
+ NSString* parentPath = [filePath stringByDeletingLastPathComponent];
+ FNNotifyByPath(
+ reinterpret_cast<const UInt8*>([parentPath fileSystemRepresentation]),
+ kFNDirectoryModifiedMessage,
+ kNilOptions);
+}
+
+void DragDownload(const DownloadItem* download,
+ SkBitmap* icon,
+ gfx::NativeView view) {
+ NSPasteboard* pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard];
+ AddFileToPasteboard(pasteboard, download->full_path());
+
+ // Convert to an NSImage.
+ NSImage* dragImage = gfx::SkBitmapToNSImage(*icon);
+
+ // Synthesize a drag event, since we don't have access to the actual event
+ // that initiated a drag (possibly consumed by the DOM UI, for example).
+ NSPoint position = [[view window] mouseLocationOutsideOfEventStream];
+ NSTimeInterval eventTime = [[NSApp currentEvent] timestamp];
+ NSEvent* dragEvent = [NSEvent mouseEventWithType:NSLeftMouseDragged
+ location:position
+ modifierFlags:NSLeftMouseDraggedMask
+ timestamp:eventTime
+ windowNumber:[[view window] windowNumber]
+ context:nil
+ eventNumber:0
+ clickCount:1
+ pressure:1.0];
+
+ // Run the drag operation.
+ [[view window] dragImage:dragImage
+ at:position
+ offset:NSZeroSize
+ event:dragEvent
+ pasteboard:pasteboard
+ source:view
+ slideBack:YES];
+}
+
+void UpdateAppIconDownloadProgress(int download_count,
+ bool progress_known,
+ float progress) {
+ DockIcon* dock_icon = [DockIcon sharedDockIcon];
+ [dock_icon setDownloads:download_count];
+ [dock_icon setIndeterminate:!progress_known];
+ [dock_icon setProgress:progress];
+ [dock_icon updateIcon];
+}
+
+} // namespace download_util
diff --git a/chrome/browser/ui/cocoa/download/download_util_mac_unittest.mm b/chrome/browser/ui/cocoa/download/download_util_mac_unittest.mm
new file mode 100644
index 0000000..bd99e02
--- /dev/null
+++ b/chrome/browser/ui/cocoa/download/download_util_mac_unittest.mm
@@ -0,0 +1,58 @@
+// 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.
+
+// Download utility test for Mac OS X.
+
+#include "base/path_service.h"
+#include "base/sys_string_conversions.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/download/download_util_mac.h"
+#include "chrome/common/chrome_paths.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class DownloadUtilMacTest : public CocoaTest {
+ public:
+ DownloadUtilMacTest() {
+ pasteboard_ = [NSPasteboard pasteboardWithUniqueName];
+ }
+
+ virtual ~DownloadUtilMacTest() {
+ [pasteboard_ releaseGlobally];
+ }
+
+ NSPasteboard* const pasteboard() { return pasteboard_; }
+
+ private:
+ NSPasteboard* pasteboard_;
+};
+
+// Ensure adding files to the pasteboard methods works as expected.
+TEST_F(DownloadUtilMacTest, AddFileToPasteboardTest) {
+ // Get a download test file for addition to the pasteboard.
+ FilePath testPath;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &testPath));
+ FilePath testFile(FILE_PATH_LITERAL("download-test1.lib"));
+ testPath = testPath.Append(testFile);
+
+ // Add a test file to the pasteboard via the download_util method.
+ download_util::AddFileToPasteboard(pasteboard(), testPath);
+
+ // Test to see that the object type for dragging files is available.
+ NSArray* types = [NSArray arrayWithObject:NSFilenamesPboardType];
+ NSString* available = [pasteboard() availableTypeFromArray:types];
+ EXPECT_TRUE(available != nil);
+
+ // Ensure the path is what we expect.
+ NSArray* files = [pasteboard() propertyListForType:NSFilenamesPboardType];
+ ASSERT_TRUE(files != nil);
+ NSString* expectedPath = [files objectAtIndex:0];
+ NSString* realPath = base::SysWideToNSString(testPath.ToWStringHack());
+ EXPECT_NSEQ(expectedPath, realPath);
+}
+
+} // namespace
diff --git a/chrome/browser/cocoa/draggable_button.h b/chrome/browser/ui/cocoa/draggable_button.h
index 2e166b7..2e166b7 100644
--- a/chrome/browser/cocoa/draggable_button.h
+++ b/chrome/browser/ui/cocoa/draggable_button.h
diff --git a/chrome/browser/ui/cocoa/draggable_button.mm b/chrome/browser/ui/cocoa/draggable_button.mm
new file mode 100644
index 0000000..923476b
--- /dev/null
+++ b/chrome/browser/ui/cocoa/draggable_button.mm
@@ -0,0 +1,150 @@
+// 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 "chrome/browser/ui/cocoa/draggable_button.h"
+
+#include "base/logging.h"
+#import "base/scoped_nsobject.h"
+
+namespace {
+
+// Code taken from <http://codereview.chromium.org/180036/diff/3001/3004>.
+// TODO(viettrungluu): Do we want common, standard code for drag hysteresis?
+const CGFloat kWebDragStartHysteresisX = 5.0;
+const CGFloat kWebDragStartHysteresisY = 5.0;
+const CGFloat kDragExpirationTimeout = 1.0;
+
+}
+
+@implementation DraggableButton
+
+@synthesize draggable = draggable_;
+
+- (id)initWithFrame:(NSRect)frame {
+ if ((self = [super initWithFrame:frame])) {
+ draggable_ = YES;
+ }
+ return self;
+}
+
+- (id)initWithCoder:(NSCoder*)coder {
+ if ((self = [super initWithCoder:coder])) {
+ draggable_ = YES;
+ }
+ return self;
+}
+
+// Determine whether a mouse down should turn into a drag; started as copy of
+// NSTableView code.
+- (BOOL)dragShouldBeginFromMouseDown:(NSEvent*)mouseDownEvent
+ withExpiration:(NSDate*)expiration
+ xHysteresis:(float)xHysteresis
+ yHysteresis:(float)yHysteresis {
+ if ([mouseDownEvent type] != NSLeftMouseDown) {
+ return NO;
+ }
+
+ NSEvent* nextEvent = nil;
+ NSEvent* firstEvent = nil;
+ NSEvent* dragEvent = nil;
+ NSEvent* mouseUp = nil;
+ BOOL dragIt = NO;
+
+ while ((nextEvent = [[self window]
+ nextEventMatchingMask:(NSLeftMouseUpMask | NSLeftMouseDraggedMask)
+ untilDate:expiration
+ inMode:NSEventTrackingRunLoopMode
+ dequeue:YES]) != nil) {
+ if (firstEvent == nil) {
+ firstEvent = nextEvent;
+ }
+ if ([nextEvent type] == NSLeftMouseDragged) {
+ float deltax = ABS([nextEvent locationInWindow].x -
+ [mouseDownEvent locationInWindow].x);
+ float deltay = ABS([nextEvent locationInWindow].y -
+ [mouseDownEvent locationInWindow].y);
+ dragEvent = nextEvent;
+ if (deltax >= xHysteresis) {
+ dragIt = YES;
+ break;
+ }
+ if (deltay >= yHysteresis) {
+ dragIt = YES;
+ break;
+ }
+ } else if ([nextEvent type] == NSLeftMouseUp) {
+ mouseUp = nextEvent;
+ break;
+ }
+ }
+
+ // Since we've been dequeuing the events (If we don't, we'll never see
+ // the mouse up...), we need to push some of the events back on.
+ // It makes sense to put the first and last drag events and the mouse
+ // up if there was one.
+ if (mouseUp != nil) {
+ [NSApp postEvent:mouseUp atStart:YES];
+ }
+ if (dragEvent != nil) {
+ [NSApp postEvent:dragEvent atStart:YES];
+ }
+ if (firstEvent != mouseUp && firstEvent != dragEvent) {
+ [NSApp postEvent:firstEvent atStart:YES];
+ }
+
+ return dragIt;
+}
+
+- (BOOL)dragShouldBeginFromMouseDown:(NSEvent*)mouseDownEvent
+ withExpiration:(NSDate*)expiration {
+ return [self dragShouldBeginFromMouseDown:mouseDownEvent
+ withExpiration:expiration
+ xHysteresis:kWebDragStartHysteresisX
+ yHysteresis:kWebDragStartHysteresisY];
+}
+
+- (void)mouseUp:(NSEvent*)theEvent {
+ if (!draggable_) {
+ [super mouseUp:theEvent];
+ return;
+ }
+
+ // There are non-drag cases where a mouseUp: may happen
+ // (e.g. mouse-down, cmd-tab to another application, move mouse,
+ // mouse-up). So we check.
+ NSPoint viewLocal = [self convertPoint:[theEvent locationInWindow]
+ fromView:[[self window] contentView]];
+ if (NSPointInRect(viewLocal, [self bounds])) {
+ [self performClick:self];
+ }
+}
+
+// Mimic "begin a click" operation visually. Do NOT follow through
+// with normal button event handling.
+- (void)mouseDown:(NSEvent*)theEvent {
+ if (draggable_) {
+ [[self cell] setHighlighted:YES];
+ NSDate* date = [NSDate dateWithTimeIntervalSinceNow:kDragExpirationTimeout];
+ if ([self dragShouldBeginFromMouseDown:theEvent
+ withExpiration:date]) {
+ [self beginDrag:theEvent];
+ [self endDrag];
+ } else {
+ [super mouseDown:theEvent];
+ }
+ } else {
+ [super mouseDown:theEvent];
+ }
+}
+
+- (void)beginDrag:(NSEvent*)dragEvent {
+ // Must be overridden by subclasses.
+ NOTREACHED();
+}
+
+- (void)endDrag {
+ [[self cell] setHighlighted:NO];
+}
+
+@end // @interface DraggableButton
diff --git a/chrome/browser/ui/cocoa/draggable_button_unittest.mm b/chrome/browser/ui/cocoa/draggable_button_unittest.mm
new file mode 100644
index 0000000..2700a49
--- /dev/null
+++ b/chrome/browser/ui/cocoa/draggable_button_unittest.mm
@@ -0,0 +1,137 @@
+// 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.
+
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/draggable_button.h"
+#import "chrome/browser/ui/cocoa/test_event_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+@interface TestableDraggableButton : DraggableButton {
+ NSUInteger dragCount_;
+ BOOL wasTriggered_;
+}
+- (void)trigger:(id)sender;
+- (BOOL)wasTriggered;
+- (NSUInteger)dragCount;
+@end
+
+@implementation TestableDraggableButton
+- (id)initWithFrame:(NSRect)frame {
+ if ((self = [super initWithFrame:frame])) {
+ dragCount_ = 0;
+ wasTriggered_ = NO;
+ }
+ return self;
+}
+- (void)beginDrag:(NSEvent*)theEvent {
+ dragCount_++;
+}
+
+- (void)trigger:(id)sender {
+ wasTriggered_ = YES;
+}
+
+- (BOOL)wasTriggered {
+ return wasTriggered_;
+}
+
+- (NSUInteger)dragCount {
+ return dragCount_;
+}
+@end
+
+class DraggableButtonTest : public CocoaTest {};
+
+// Make sure the basic case of "click" still works.
+TEST_F(DraggableButtonTest, DownUp) {
+ scoped_nsobject<TestableDraggableButton> button(
+ [[TestableDraggableButton alloc] initWithFrame:NSMakeRect(0,0,500,500)]);
+ [[test_window() contentView] addSubview:button.get()];
+ [button setTarget:button];
+ [button setAction:@selector(trigger:)];
+ EXPECT_FALSE([button wasTriggered]);
+ NSEvent* downEvent =
+ test_event_utils::MouseEventAtPoint(NSMakePoint(10,10),
+ NSLeftMouseDown, 0);
+ NSEvent* upEvent =
+ test_event_utils::MouseEventAtPoint(NSMakePoint(10,10),
+ NSLeftMouseUp, 0);
+ [NSApp postEvent:upEvent atStart:YES];
+ [test_window() sendEvent:downEvent];
+ EXPECT_TRUE([button wasTriggered]); // confirms target/action fired
+}
+
+TEST_F(DraggableButtonTest, DraggableHysteresis) {
+ scoped_nsobject<TestableDraggableButton> button(
+ [[TestableDraggableButton alloc] initWithFrame:NSMakeRect(0,0,500,500)]);
+ [[test_window() contentView] addSubview:button.get()];
+ NSEvent* downEvent =
+ test_event_utils::MouseEventAtPoint(NSMakePoint(10,10),
+ NSLeftMouseDown,
+ 0);
+ NSEvent* firstMove =
+ test_event_utils::MouseEventAtPoint(NSMakePoint(11,11),
+ NSLeftMouseDragged,
+ 0);
+ NSEvent* firstUpEvent =
+ test_event_utils::MouseEventAtPoint(NSMakePoint(11,11),
+ NSLeftMouseUp,
+ 0);
+ NSEvent* secondMove =
+ test_event_utils::MouseEventAtPoint(NSMakePoint(100,100),
+ NSLeftMouseDragged,
+ 0);
+ NSEvent* secondUpEvent =
+ test_event_utils::MouseEventAtPoint(NSMakePoint(100,100),
+ NSLeftMouseUp,
+ 0);
+ // If the mouse only moves one pixel in each direction
+ // it should not cause a drag.
+ [NSApp postEvent:firstUpEvent atStart:YES];
+ [NSApp postEvent:firstMove atStart:YES];
+ [button mouseDown:downEvent];
+ EXPECT_EQ(0U, [button dragCount]);
+
+ // If the mouse moves > 5 pixels in either direciton
+ // it should cause a drag.
+ [NSApp postEvent:secondUpEvent atStart:YES];
+ [NSApp postEvent:secondMove atStart:YES];
+ [button mouseDown:downEvent];
+ EXPECT_EQ(1U, [button dragCount]);
+}
+
+TEST_F(DraggableButtonTest, ResetState) {
+ scoped_nsobject<TestableDraggableButton> button(
+ [[TestableDraggableButton alloc] initWithFrame:NSMakeRect(0,0,500,500)]);
+ [[test_window() contentView] addSubview:button.get()];
+ NSEvent* downEvent =
+ test_event_utils::MouseEventAtPoint(NSMakePoint(10,10),
+ NSLeftMouseDown,
+ 0);
+ NSEvent* moveEvent =
+ test_event_utils::MouseEventAtPoint(NSMakePoint(100,100),
+ NSLeftMouseDragged,
+ 0);
+ NSEvent* upEvent =
+ test_event_utils::MouseEventAtPoint(NSMakePoint(100,100),
+ NSLeftMouseUp,
+ 0);
+ // If the mouse moves > 5 pixels in either direciton it should cause a drag.
+ [NSApp postEvent:upEvent atStart:YES];
+ [NSApp postEvent:moveEvent atStart:YES];
+ [button mouseDown:downEvent];
+
+ // The button should not be highlighted after the drag finishes.
+ EXPECT_FALSE([[button cell] isHighlighted]);
+ EXPECT_EQ(1U, [button dragCount]);
+
+ // We should be able to initiate another drag immediately after the first one.
+ [NSApp postEvent:upEvent atStart:YES];
+ [NSApp postEvent:moveEvent atStart:YES];
+ [button mouseDown:downEvent];
+ EXPECT_EQ(2U, [button dragCount]);
+ EXPECT_FALSE([[button cell] isHighlighted]);
+}
diff --git a/chrome/browser/ui/cocoa/edit_search_engine_cocoa_controller.h b/chrome/browser/ui/cocoa/edit_search_engine_cocoa_controller.h
new file mode 100644
index 0000000..9db2a4e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/edit_search_engine_cocoa_controller.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2009 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>
+
+class TemplateURL;
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/search_engines/edit_search_engine_controller.h"
+
+// This controller presents a dialog that allows a user to add or edit a search
+// engine. If constructed with a nil |templateURL| then it is an add operation,
+// otherwise it will modify the passed URL. A |delegate| is necessary to
+// perform the actual database modifications, and should probably be an
+// instance of KeywordEditorModelObserver.
+
+@interface EditSearchEngineCocoaController :
+ NSWindowController<NSWindowDelegate> {
+ IBOutlet NSTextField* nameField_;
+ IBOutlet NSTextField* keywordField_;
+ IBOutlet NSTextField* urlField_;
+ IBOutlet NSImageView* nameImage_;
+ IBOutlet NSImageView* keywordImage_;
+ IBOutlet NSImageView* urlImage_;
+ IBOutlet NSButton* doneButton_;
+ IBOutlet NSTextField* urlDescriptionField_;
+ IBOutlet NSView* labelContainer_;
+ IBOutlet NSBox* fieldAndImageContainer_;
+
+ // Refs to the good and bad images used in the interface validation.
+ scoped_nsobject<NSImage> goodImage_;
+ scoped_nsobject<NSImage> badImage_;
+
+ Profile* profile_; // weak
+ const TemplateURL* templateURL_; // weak
+ scoped_ptr<EditSearchEngineController> controller_;
+}
+
+- (id)initWithProfile:(Profile*)profile
+ delegate:(EditSearchEngineControllerDelegate*)delegate
+ templateURL:(const TemplateURL*)url;
+
+- (IBAction)cancel:(id)sender;
+- (IBAction)save:(id)sender;
+
+@end
+
+@interface EditSearchEngineCocoaController (ExposedForTesting)
+- (BOOL)validateFields;
+@end
diff --git a/chrome/browser/ui/cocoa/edit_search_engine_cocoa_controller.mm b/chrome/browser/ui/cocoa/edit_search_engine_cocoa_controller.mm
new file mode 100644
index 0000000..06fc94b
--- /dev/null
+++ b/chrome/browser/ui/cocoa/edit_search_engine_cocoa_controller.mm
@@ -0,0 +1,187 @@
+// 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 "chrome/browser/ui/cocoa/edit_search_engine_cocoa_controller.h"
+
+#include "app/l10n_util_mac.h"
+#include "app/resource_bundle.h"
+#include "base/logging.h"
+#import "base/mac_util.h"
+#include "base/string16.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/search_engines/template_url.h"
+#include "grit/app_resources.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
+
+namespace {
+
+void ShiftOriginY(NSView* view, CGFloat amount) {
+ NSPoint origin = [view frame].origin;
+ origin.y += amount;
+ [view setFrameOrigin:origin];
+}
+
+} // namespace
+
+@implementation EditSearchEngineCocoaController
+
+- (id)initWithProfile:(Profile*)profile
+ delegate:(EditSearchEngineControllerDelegate*)delegate
+ templateURL:(const TemplateURL*)url {
+ DCHECK(profile);
+ NSString* nibpath = [mac_util::MainAppBundle()
+ pathForResource:@"EditSearchEngine"
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
+ profile_ = profile;
+ templateURL_ = url;
+ controller_.reset(
+ new EditSearchEngineController(templateURL_, delegate, profile_));
+ }
+ return self;
+}
+
+- (void)awakeFromNib {
+ DCHECK([self window]);
+ DCHECK_EQ(self, [[self window] delegate]);
+
+ // Make sure the url description field fits the text in it.
+ CGFloat descriptionShift = [GTMUILocalizerAndLayoutTweaker
+ sizeToFitFixedWidthTextField:urlDescriptionField_];
+
+ // Move the label container above the url description.
+ ShiftOriginY(labelContainer_, descriptionShift);
+ // There was no way via view containment to use a helper view to move all
+ // the textfields and images at once, most move them all on their own so
+ // they stay above the url description.
+ ShiftOriginY(nameField_, descriptionShift);
+ ShiftOriginY(keywordField_, descriptionShift);
+ ShiftOriginY(urlField_, descriptionShift);
+ ShiftOriginY(nameImage_, descriptionShift);
+ ShiftOriginY(keywordImage_, descriptionShift);
+ ShiftOriginY(urlImage_, descriptionShift);
+
+ // Resize the containing box for the name/keyword/url fields/images since it
+ // also contains the url description (which just grew).
+ [[fieldAndImageContainer_ contentView] setAutoresizesSubviews:NO];
+ NSRect rect = [fieldAndImageContainer_ frame];
+ rect.size.height += descriptionShift;
+ [fieldAndImageContainer_ setFrame:rect];
+ [[fieldAndImageContainer_ contentView] setAutoresizesSubviews:YES];
+
+ // Resize the window.
+ NSWindow* window = [self window];
+ NSSize windowDelta = NSMakeSize(0, descriptionShift);
+ [GTMUILocalizerAndLayoutTweaker
+ resizeWindowWithoutAutoResizingSubViews:window
+ delta:windowDelta];
+
+ ResourceBundle& bundle = ResourceBundle::GetSharedInstance();
+ goodImage_.reset([bundle.GetNativeImageNamed(IDR_INPUT_GOOD) retain]);
+ badImage_.reset([bundle.GetNativeImageNamed(IDR_INPUT_ALERT) retain]);
+ if (templateURL_) {
+ // Defaults to |..._NEW_WINDOW_TITLE|.
+ [window setTitle:l10n_util::GetNSString(
+ IDS_SEARCH_ENGINES_EDITOR_EDIT_WINDOW_TITLE)];
+ [nameField_ setStringValue:
+ base::SysWideToNSString(templateURL_->short_name())];
+ [keywordField_ setStringValue:
+ base::SysWideToNSString(templateURL_->keyword())];
+ [urlField_ setStringValue:
+ base::SysWideToNSString(templateURL_->url()->DisplayURL())];
+ [urlField_ setEnabled:(templateURL_->prepopulate_id() == 0)];
+ }
+ // When creating a new keyword, this will mark the fields as "invalid" and
+ // will not let the user save. If this is an edit, then this will set all
+ // the images to the "valid" state.
+ [self validateFields];
+}
+
+// When the window closes, clean ourselves up.
+- (void)windowWillClose:(NSNotification*)notif {
+ [self autorelease];
+}
+
+// Performs the logic of closing the window. If we are a sheet, then it ends the
+// modal session; otherwise, it closes the window.
+- (void)doClose {
+ if ([[self window] isSheet]) {
+ [NSApp endSheet:[self window]];
+ } else {
+ [[self window] close];
+ }
+}
+
+- (IBAction)cancel:(id)sender {
+ [self doClose];
+}
+
+- (IBAction)save:(id)sender {
+ DCHECK([self validateFields]);
+ string16 title = base::SysNSStringToUTF16([nameField_ stringValue]);
+ string16 keyword = base::SysNSStringToUTF16([keywordField_ stringValue]);
+ std::string url = base::SysNSStringToUTF8([urlField_ stringValue]);
+ controller_->AcceptAddOrEdit(title, keyword, url);
+ [self doClose];
+}
+
+// Delegate method for the text fields.
+
+- (void)controlTextDidChange:(NSNotification*)notif {
+ [self validateFields];
+}
+
+- (void)controlTextDidEndEditing:(NSNotification*)notif {
+ [self validateFields];
+}
+
+// Private --------------------------------------------------------------------
+
+// Sets the appropriate image and tooltip based on a boolean |valid|.
+- (void)setIsValid:(BOOL)valid
+ toolTip:(int)messageID
+ forImageView:(NSImageView*)imageView
+ textField:(NSTextField*)textField {
+ NSImage* image = (valid) ? goodImage_ : badImage_;
+ [imageView setImage:image];
+
+ NSString* toolTip = nil;
+ if (!valid)
+ toolTip = l10n_util::GetNSString(messageID);
+ [textField setToolTip:toolTip];
+ [imageView setToolTip:toolTip];
+}
+
+// This sets the image state for all the controls and enables or disables the
+// done button. Returns YES if all the fields are valid.
+- (BOOL)validateFields {
+ string16 title = base::SysNSStringToUTF16([nameField_ stringValue]);
+ BOOL titleValid = controller_->IsTitleValid(title);
+ [self setIsValid:titleValid
+ toolTip:IDS_SEARCH_ENGINES_INVALID_TITLE_TT
+ forImageView:nameImage_
+ textField:nameField_];
+
+ string16 keyword = base::SysNSStringToUTF16([keywordField_ stringValue]);
+ BOOL keywordValid = controller_->IsKeywordValid(keyword);
+ [self setIsValid:keywordValid
+ toolTip:IDS_SEARCH_ENGINES_INVALID_KEYWORD_TT
+ forImageView:keywordImage_
+ textField:keywordField_];
+
+ std::string url = base::SysNSStringToUTF8([urlField_ stringValue]);
+ BOOL urlValid = controller_->IsURLValid(url);
+ [self setIsValid:urlValid
+ toolTip:IDS_SEARCH_ENGINES_INVALID_URL_TT
+ forImageView:urlImage_
+ textField:urlField_];
+
+ BOOL isValid = (titleValid && keywordValid && urlValid);
+ [doneButton_ setEnabled:isValid];
+ return isValid;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/edit_search_engine_cocoa_controller_unittest.mm b/chrome/browser/ui/cocoa/edit_search_engine_cocoa_controller_unittest.mm
new file mode 100644
index 0000000..72bfe7b
--- /dev/null
+++ b/chrome/browser/ui/cocoa/edit_search_engine_cocoa_controller_unittest.mm
@@ -0,0 +1,233 @@
+// Copyright (c) 2009 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 "app/l10n_util_mac.h"
+#include "base/scoped_nsobject.h"
+#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/edit_search_engine_cocoa_controller.h"
+#include "chrome/test/testing_profile.h"
+#include "grit/generated_resources.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+@interface FakeEditSearchEngineController : EditSearchEngineCocoaController {
+}
+@property (nonatomic, readonly) NSTextField* nameField;
+@property (nonatomic, readonly) NSTextField* keywordField;
+@property (nonatomic, readonly) NSTextField* urlField;
+@property (nonatomic, readonly) NSImageView* nameImage;
+@property (nonatomic, readonly) NSImageView* keywordImage;
+@property (nonatomic, readonly) NSImageView* urlImage;
+@property (nonatomic, readonly) NSButton* doneButton;
+@property (nonatomic, readonly) NSImage* goodImage;
+@property (nonatomic, readonly) NSImage* badImage;
+@end
+
+@implementation FakeEditSearchEngineController
+@synthesize nameField = nameField_;
+@synthesize keywordField = keywordField_;
+@synthesize urlField = urlField_;
+@synthesize nameImage = nameImage_;
+@synthesize keywordImage = keywordImage_;
+@synthesize urlImage = urlImage_;
+@synthesize doneButton = doneButton_;
+- (NSImage*)goodImage {
+ return goodImage_.get();
+}
+- (NSImage*)badImage {
+ return badImage_.get();
+}
+@end
+
+namespace {
+
+class EditSearchEngineControllerTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ TestingProfile* profile =
+ static_cast<TestingProfile*>(browser_helper_.profile());
+ profile->CreateTemplateURLModel();
+ controller_ = [[FakeEditSearchEngineController alloc]
+ initWithProfile:profile
+ delegate:nil
+ templateURL:nil];
+ }
+
+ virtual void TearDown() {
+ // Force the window to load so we hit |-awakeFromNib| to register as the
+ // window's delegate so that the controller can clean itself up in
+ // |-windowWillClose:|.
+ ASSERT_TRUE([controller_ window]);
+
+ [controller_ close];
+ CocoaTest::TearDown();
+ }
+
+ BrowserTestHelper browser_helper_;
+ FakeEditSearchEngineController* controller_;
+};
+
+TEST_F(EditSearchEngineControllerTest, ValidImageOriginals) {
+ EXPECT_FALSE([controller_ goodImage]);
+ EXPECT_FALSE([controller_ badImage]);
+
+ EXPECT_TRUE([controller_ window]); // Force the window to load.
+
+ EXPECT_TRUE([[controller_ goodImage] isKindOfClass:[NSImage class]]);
+ EXPECT_TRUE([[controller_ badImage] isKindOfClass:[NSImage class]]);
+
+ // Test window title is set correctly.
+ NSString* title = l10n_util::GetNSString(
+ IDS_SEARCH_ENGINES_EDITOR_NEW_WINDOW_TITLE);
+ EXPECT_NSEQ(title, [[controller_ window] title]);
+}
+
+TEST_F(EditSearchEngineControllerTest, SetImageViews) {
+ EXPECT_TRUE([controller_ window]); // Force the window to load.
+ EXPECT_EQ([controller_ badImage], [[controller_ nameImage] image]);
+ // An empty keyword is not OK.
+ EXPECT_EQ([controller_ badImage], [[controller_ keywordImage] image]);
+ EXPECT_EQ([controller_ badImage], [[controller_ urlImage] image]);
+}
+
+// This test ensures that on creating a new keyword, we are in an "invalid"
+// state that cannot save.
+TEST_F(EditSearchEngineControllerTest, InvalidState) {
+ EXPECT_TRUE([controller_ window]); // Force window to load.
+ NSString* toolTip = nil;
+ EXPECT_FALSE([controller_ validateFields]);
+
+ EXPECT_NSEQ(@"", [[controller_ nameField] stringValue]);
+ EXPECT_EQ([controller_ badImage], [[controller_ nameImage] image]);
+ toolTip = l10n_util::GetNSString(IDS_SEARCH_ENGINES_INVALID_TITLE_TT);
+ EXPECT_NSEQ(toolTip, [[controller_ nameField] toolTip]);
+ EXPECT_NSEQ(toolTip, [[controller_ nameImage] toolTip]);
+
+ // Keywords can not be empty strings.
+ EXPECT_NSEQ(@"", [[controller_ keywordField] stringValue]);
+ EXPECT_EQ([controller_ badImage], [[controller_ keywordImage] image]);
+ EXPECT_TRUE([[controller_ keywordField] toolTip]);
+ EXPECT_TRUE([[controller_ keywordImage] toolTip]);
+
+ EXPECT_NSEQ(@"", [[controller_ urlField] stringValue]);
+ EXPECT_EQ([controller_ badImage], [[controller_ urlImage] image]);
+ toolTip = l10n_util::GetNSString(IDS_SEARCH_ENGINES_INVALID_URL_TT);
+ EXPECT_NSEQ(toolTip, [[controller_ urlField] toolTip]);
+ EXPECT_NSEQ(toolTip, [[controller_ urlImage] toolTip]);
+}
+
+// Tests that the single name field validates.
+TEST_F(EditSearchEngineControllerTest, ValidateName) {
+ EXPECT_TRUE([controller_ window]); // Force window to load.
+
+ EXPECT_EQ([controller_ badImage], [[controller_ nameImage] image]);
+ EXPECT_FALSE([controller_ validateFields]);
+ NSString* toolTip =
+ l10n_util::GetNSString(IDS_SEARCH_ENGINES_INVALID_TITLE_TT);
+ EXPECT_NSEQ(toolTip, [[controller_ nameField] toolTip]);
+ EXPECT_NSEQ(toolTip, [[controller_ nameImage] toolTip]);
+ [[controller_ nameField] setStringValue:@"Test Name"];
+ EXPECT_FALSE([controller_ validateFields]);
+ EXPECT_EQ([controller_ goodImage], [[controller_ nameImage] image]);
+ EXPECT_FALSE([[controller_ nameField] toolTip]);
+ EXPECT_FALSE([[controller_ nameImage] toolTip]);
+ EXPECT_FALSE([[controller_ doneButton] isEnabled]);
+}
+
+// The keyword field is not valid if it is empty.
+TEST_F(EditSearchEngineControllerTest, ValidateKeyword) {
+ EXPECT_TRUE([controller_ window]); // Force window load.
+
+ EXPECT_EQ([controller_ badImage], [[controller_ keywordImage] image]);
+ EXPECT_FALSE([controller_ validateFields]);
+ EXPECT_TRUE([[controller_ keywordField] toolTip]);
+ EXPECT_TRUE([[controller_ keywordImage] toolTip]);
+ [[controller_ keywordField] setStringValue:@"foobar"];
+ EXPECT_FALSE([controller_ validateFields]);
+ EXPECT_EQ([controller_ goodImage], [[controller_ keywordImage] image]);
+ EXPECT_FALSE([[controller_ keywordField] toolTip]);
+ EXPECT_FALSE([[controller_ keywordImage] toolTip]);
+ EXPECT_FALSE([[controller_ doneButton] isEnabled]);
+}
+
+// Tests that the URL field validates.
+TEST_F(EditSearchEngineControllerTest, ValidateURL) {
+ EXPECT_TRUE([controller_ window]); // Force window to load.
+
+ EXPECT_EQ([controller_ badImage], [[controller_ urlImage] image]);
+ EXPECT_FALSE([controller_ validateFields]);
+ NSString* toolTip =
+ l10n_util::GetNSString(IDS_SEARCH_ENGINES_INVALID_URL_TT);
+ EXPECT_NSEQ(toolTip, [[controller_ urlField] toolTip]);
+ EXPECT_NSEQ(toolTip, [[controller_ urlImage] toolTip]);
+ [[controller_ urlField] setStringValue:@"http://foo-bar.com"];
+ EXPECT_FALSE([controller_ validateFields]);
+ EXPECT_EQ([controller_ goodImage], [[controller_ urlImage] image]);
+ EXPECT_FALSE([[controller_ urlField] toolTip]);
+ EXPECT_FALSE([[controller_ urlImage] toolTip]);
+ EXPECT_FALSE([[controller_ doneButton] isEnabled]);
+}
+
+// Tests that if the user enters all valid data that the UI reflects that
+// and that they can save.
+TEST_F(EditSearchEngineControllerTest, ValidateFields) {
+ EXPECT_TRUE([controller_ window]); // Force window to load.
+
+ // State before entering data.
+ EXPECT_EQ([controller_ badImage], [[controller_ nameImage] image]);
+ EXPECT_EQ([controller_ badImage], [[controller_ keywordImage] image]);
+ EXPECT_EQ([controller_ badImage], [[controller_ urlImage] image]);
+ EXPECT_FALSE([[controller_ doneButton] isEnabled]);
+ EXPECT_FALSE([controller_ validateFields]);
+
+ [[controller_ nameField] setStringValue:@"Test Name"];
+ EXPECT_FALSE([controller_ validateFields]);
+ EXPECT_EQ([controller_ goodImage], [[controller_ nameImage] image]);
+ EXPECT_FALSE([[controller_ doneButton] isEnabled]);
+
+ [[controller_ keywordField] setStringValue:@"foobar"];
+ EXPECT_FALSE([controller_ validateFields]);
+ EXPECT_EQ([controller_ goodImage], [[controller_ keywordImage] image]);
+ EXPECT_FALSE([[controller_ doneButton] isEnabled]);
+
+ // Once the URL is entered, we should have all 3 valid fields.
+ [[controller_ urlField] setStringValue:@"http://foo-bar.com"];
+ EXPECT_TRUE([controller_ validateFields]);
+ EXPECT_EQ([controller_ goodImage], [[controller_ urlImage] image]);
+ EXPECT_TRUE([[controller_ doneButton] isEnabled]);
+}
+
+// Tests editing an existing TemplateURL.
+TEST_F(EditSearchEngineControllerTest, EditTemplateURL) {
+ TemplateURL url;
+ url.set_short_name(L"Foobar");
+ url.set_keyword(L"keyword");
+ std::string urlString = TemplateURLRef::DisplayURLToURLRef(
+ L"http://foo-bar.com");
+ url.SetURL(urlString, 0, 1);
+ TestingProfile* profile = browser_helper_.profile();
+ FakeEditSearchEngineController *controller =
+ [[FakeEditSearchEngineController alloc] initWithProfile:profile
+ delegate:nil
+ templateURL:&url];
+ EXPECT_TRUE([controller window]);
+ NSString* title = l10n_util::GetNSString(
+ IDS_SEARCH_ENGINES_EDITOR_EDIT_WINDOW_TITLE);
+ EXPECT_NSEQ(title, [[controller window] title]);
+ NSString* nameString = [[controller nameField] stringValue];
+ EXPECT_NSEQ(@"Foobar", nameString);
+ NSString* keywordString = [[controller keywordField] stringValue];
+ EXPECT_NSEQ(@"keyword", keywordString);
+ NSString* urlValueString = [[controller urlField] stringValue];
+ EXPECT_NSEQ(@"http://foo-bar.com", urlValueString);
+ EXPECT_TRUE([controller validateFields]);
+ [controller close];
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/encoding_menu_controller_delegate_mac.h b/chrome/browser/ui/cocoa/encoding_menu_controller_delegate_mac.h
new file mode 100644
index 0000000..989105c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/encoding_menu_controller_delegate_mac.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_ENCODING_MENU_CONTROLLER_DELEGATE_MAC_H_
+#define CHROME_BROWSER_UI_COCOA_ENCODING_MENU_CONTROLLER_DELEGATE_MAC_H_
+#pragma once
+
+#include "base/basictypes.h" // For DISALLOW_IMPLICIT_CONSTRUCTORS
+
+@class NSMenu;
+class Profile;
+
+// The Windows version of this class manages the Encoding Menu, but since Cocoa
+// does that for us automagically, the only thing left to do is construct
+// the encoding menu.
+class EncodingMenuControllerDelegate {
+ public:
+ static void BuildEncodingMenu(Profile *profile, NSMenu* encoding_menu);
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(EncodingMenuControllerDelegate);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_ENCODING_MENU_CONTROLLER_DELEGATE_MAC_H_
diff --git a/chrome/browser/ui/cocoa/encoding_menu_controller_delegate_mac.mm b/chrome/browser/ui/cocoa/encoding_menu_controller_delegate_mac.mm
new file mode 100644
index 0000000..775ffdc
--- /dev/null
+++ b/chrome/browser/ui/cocoa/encoding_menu_controller_delegate_mac.mm
@@ -0,0 +1,60 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/encoding_menu_controller_delegate_mac.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/string16.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/toolbar/encoding_menu_controller.h"
+
+namespace {
+
+void AddSeparatorToMenu(NSMenu *parent_menu) {
+ NSMenuItem* separator = [NSMenuItem separatorItem];
+ [parent_menu addItem:separator];
+}
+
+void AppendMenuItem(NSMenu *parent_menu, int tag, NSString *title) {
+
+ NSMenuItem* item = [[[NSMenuItem alloc] initWithTitle:title
+ action:nil
+ keyEquivalent:@""] autorelease];
+ [parent_menu addItem:item];
+ [item setAction:@selector(commandDispatch:)];
+ [item setTag:tag];
+}
+
+} // namespace
+
+// static
+void EncodingMenuControllerDelegate::BuildEncodingMenu(Profile *profile,
+ NSMenu* encoding_menu) {
+ DCHECK(profile);
+
+ typedef EncodingMenuController::EncodingMenuItemList EncodingMenuItemList;
+ EncodingMenuItemList menuItems;
+ EncodingMenuController controller;
+ controller.GetEncodingMenuItems(profile, &menuItems);
+
+ for (EncodingMenuItemList::iterator it = menuItems.begin();
+ it != menuItems.end();
+ ++it) {
+ int item_id = it->first;
+ string16 &localized_title_string16 = it->second;
+
+ if (item_id == 0) {
+ AddSeparatorToMenu(encoding_menu);
+ } else {
+ NSString *localized_title =
+ base::SysUTF16ToNSString(localized_title_string16);
+ AppendMenuItem(encoding_menu, item_id, localized_title);
+ }
+ }
+
+}
diff --git a/chrome/browser/ui/cocoa/event_utils.h b/chrome/browser/ui/cocoa/event_utils.h
new file mode 100644
index 0000000..a8f24f8
--- /dev/null
+++ b/chrome/browser/ui/cocoa/event_utils.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_EVENT_UTILS_H_
+#define CHROME_BROWSER_UI_COCOA_EVENT_UTILS_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "webkit/glue/window_open_disposition.h"
+
+namespace event_utils {
+
+// Retrieves the WindowOpenDisposition used to open a link from a user gesture
+// represented by |event|. For example, a Cmd+Click would mean open the
+// associated link in a background tab.
+WindowOpenDisposition WindowOpenDispositionFromNSEvent(NSEvent* event);
+
+// Retrieves the WindowOpenDisposition used to open a link from a user gesture
+// represented by |event|, but instead use the modifier flags given by |flags|,
+// which is the same format as |-NSEvent modifierFlags|. This allows
+// substitution of the modifiers without having to create a new event from
+// scratch.
+WindowOpenDisposition WindowOpenDispositionFromNSEventWithFlags(
+ NSEvent* event, NSUInteger flags);
+
+} // namespace event_utils
+
+#endif // CHROME_BROWSER_UI_COCOA_EVENT_UTILS_H_
diff --git a/chrome/browser/ui/cocoa/event_utils.mm b/chrome/browser/ui/cocoa/event_utils.mm
new file mode 100644
index 0000000..ec475b5
--- /dev/null
+++ b/chrome/browser/ui/cocoa/event_utils.mm
@@ -0,0 +1,21 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/event_utils.h"
+
+namespace event_utils {
+
+WindowOpenDisposition WindowOpenDispositionFromNSEvent(NSEvent* event) {
+ NSUInteger modifiers = [event modifierFlags];
+ return WindowOpenDispositionFromNSEventWithFlags(event, modifiers);
+}
+
+WindowOpenDisposition WindowOpenDispositionFromNSEventWithFlags(
+ NSEvent* event, NSUInteger flags) {
+ if ([event buttonNumber] == 2 || flags & NSCommandKeyMask)
+ return flags & NSShiftKeyMask ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB;
+ return flags & NSShiftKeyMask ? NEW_WINDOW : CURRENT_TAB;
+}
+
+} // namespace event_utils
diff --git a/chrome/browser/ui/cocoa/event_utils_unittest.mm b/chrome/browser/ui/cocoa/event_utils_unittest.mm
new file mode 100644
index 0000000..6f0b7fe
--- /dev/null
+++ b/chrome/browser/ui/cocoa/event_utils_unittest.mm
@@ -0,0 +1,61 @@
+// Copyright (c) 2009 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 <objc/objc-class.h>
+
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/event_utils.h"
+#include "chrome/browser/ui/cocoa/test_event_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+// We provide a donor class with a specially modified |modifierFlags|
+// implementation that we swap with NSEvent's. This is because we can't create a
+// NSEvent that represents a middle click with modifiers.
+@interface TestEvent : NSObject
+@end
+@implementation TestEvent
+- (NSUInteger)modifierFlags { return NSShiftKeyMask; }
+@end
+
+namespace {
+
+class EventUtilsTest : public CocoaTest {
+};
+
+TEST_F(EventUtilsTest, TestWindowOpenDispositionFromNSEvent) {
+ // Left Click = same tab.
+ NSEvent* me = test_event_utils::MakeMouseEvent(NSLeftMouseUp, 0);
+ EXPECT_EQ(CURRENT_TAB, event_utils::WindowOpenDispositionFromNSEvent(me));
+
+ // Middle Click = new background tab.
+ me = test_event_utils::MakeMouseEvent(NSOtherMouseUp, 0);
+ EXPECT_EQ(NEW_BACKGROUND_TAB,
+ event_utils::WindowOpenDispositionFromNSEvent(me));
+
+ // Shift+Middle Click = new foreground tab.
+ {
+ ScopedClassSwizzler swizzler([NSEvent class], [TestEvent class],
+ @selector(modifierFlags));
+ me = test_event_utils::MakeMouseEvent(NSOtherMouseUp, NSShiftKeyMask);
+ EXPECT_EQ(NEW_FOREGROUND_TAB,
+ event_utils::WindowOpenDispositionFromNSEvent(me));
+ }
+
+ // Cmd+Left Click = new background tab.
+ me = test_event_utils::MakeMouseEvent(NSLeftMouseUp, NSCommandKeyMask);
+ EXPECT_EQ(NEW_BACKGROUND_TAB,
+ event_utils::WindowOpenDispositionFromNSEvent(me));
+
+ // Cmd+Shift+Left Click = new foreground tab.
+ me = test_event_utils::MakeMouseEvent(NSLeftMouseUp, NSCommandKeyMask | NSShiftKeyMask);
+ EXPECT_EQ(NEW_FOREGROUND_TAB,
+ event_utils::WindowOpenDispositionFromNSEvent(me));
+
+ // Shift+Left Click = new window
+ me = test_event_utils::MakeMouseEvent(NSLeftMouseUp, NSShiftKeyMask);
+ EXPECT_EQ(NEW_WINDOW, event_utils::WindowOpenDispositionFromNSEvent(me));
+}
+
+} // namespace
diff --git a/chrome/browser/cocoa/extension_install_prompt.mm b/chrome/browser/ui/cocoa/extension_install_prompt.mm
index 3306806..3306806 100644
--- a/chrome/browser/cocoa/extension_install_prompt.mm
+++ b/chrome/browser/ui/cocoa/extension_install_prompt.mm
diff --git a/chrome/browser/ui/cocoa/extension_installed_bubble_bridge.h b/chrome/browser/ui/cocoa/extension_installed_bubble_bridge.h
new file mode 100644
index 0000000..62d72c3
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extension_installed_bubble_bridge.h
@@ -0,0 +1,28 @@
+// 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.
+
+// C++ bridge function to connect ExtensionInstallUI to the Cocoa-based
+// extension installed bubble.
+
+#ifndef CHROME_BROWSER_UI_COCOA_EXTENSION_INSTALLED_BUBBLE_BRIDGE_H_
+#define CHROME_BROWSER_UI_COCOA_EXTENSION_INSTALLED_BUBBLE_BRIDGE_H_
+#pragma once
+
+#include "gfx/native_widget_types.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+class Browser;
+class Extension;
+
+namespace ExtensionInstalledBubbleCocoa {
+
+// This function is called by the ExtensionInstallUI when an extension has been
+// installed.
+void ShowExtensionInstalledBubble(gfx::NativeWindow window,
+ const Extension* extension,
+ Browser* browser,
+ SkBitmap icon);
+}
+
+#endif // CHROME_BROWSER_UI_COCOA_EXTENSION_INSTALLED_BUBBLE_BRIDGE_H_
diff --git a/chrome/browser/ui/cocoa/extension_installed_bubble_bridge.mm b/chrome/browser/ui/cocoa/extension_installed_bubble_bridge.mm
new file mode 100644
index 0000000..d439899
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extension_installed_bubble_bridge.mm
@@ -0,0 +1,25 @@
+// 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>
+
+#import "extension_installed_bubble_bridge.h"
+
+#import "chrome/browser/ui/cocoa/extension_installed_bubble_controller.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/common/extensions/extension.h"
+
+void ExtensionInstalledBubbleCocoa::ShowExtensionInstalledBubble(
+ gfx::NativeWindow window,
+ const Extension* extension,
+ Browser* browser,
+ SkBitmap icon) {
+ // The controller is deallocated when the window is closed, so no need to
+ // worry about it here.
+ [[ExtensionInstalledBubbleController alloc]
+ initWithParentWindow:window
+ extension:extension
+ browser:browser
+ icon:icon];
+}
diff --git a/chrome/browser/ui/cocoa/extension_installed_bubble_controller.h b/chrome/browser/ui/cocoa/extension_installed_bubble_controller.h
new file mode 100644
index 0000000..63dfc22
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extension_installed_bubble_controller.h
@@ -0,0 +1,112 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_EXTENSION_INSTALLED_BUBBLE_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_EXTENSION_INSTALLED_BUBBLE_CONTROLLER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_ptr.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+class Browser;
+class Extension;
+class ExtensionLoadedNotificationObserver;
+@class HoverCloseButton;
+@class InfoBubbleView;
+
+namespace extension_installed_bubble {
+
+// Maximum height or width of extension's icon (corresponds to Windows & GTK).
+const int kIconSize = 43;
+
+// Outer vertical margin for text, icon, and closing x.
+const int kOuterVerticalMargin = 15;
+
+// Inner vertical margin for text messages.
+const int kInnerVerticalMargin = 10;
+
+// We use a different kind of notification for each of these extension types.
+typedef enum {
+ kBrowserAction,
+ kGeneric,
+ kOmniboxKeyword,
+ kPageAction
+} ExtensionType;
+
+}
+
+// Controller for the extension installed bubble. This bubble pops up after
+// an extension has been installed to inform the user that the install happened
+// properly, and to let the user know how to manage this extension in the
+// future.
+@interface ExtensionInstalledBubbleController :
+ NSWindowController<NSWindowDelegate> {
+ @private
+ NSWindow* parentWindow_; // weak
+ const Extension* extension_; // weak
+ Browser* browser_; // weak
+ scoped_nsobject<NSImage> icon_;
+
+ extension_installed_bubble::ExtensionType type_;
+
+ // We need to remove the page action immediately when the browser window
+ // closes while this bubble is still open, so the bubble's closing animation
+ // doesn't overlap browser destruction.
+ BOOL pageActionRemoved_;
+
+ // Lets us register for EXTENSION_LOADED notifications. The actual
+ // notifications are sent to the observer object, which proxies them
+ // back to the controller.
+ scoped_ptr<ExtensionLoadedNotificationObserver> extensionObserver_;
+
+ // References below are weak, being obtained from the nib.
+ IBOutlet InfoBubbleView* infoBubbleView_;
+ IBOutlet HoverCloseButton* closeButton_;
+ IBOutlet NSImageView* iconImage_;
+ IBOutlet NSTextField* extensionInstalledMsg_;
+ // Only shown for page actions and omnibox keywords.
+ IBOutlet NSTextField* extraInfoMsg_;
+ IBOutlet NSTextField* extensionInstalledInfoMsg_;
+}
+
+@property (nonatomic, readonly) const Extension* extension;
+@property (nonatomic) BOOL pageActionRemoved;
+
+// Initialize the window, and then create observers to wait for the extension
+// to complete loading, or the browser window to close.
+- (id)initWithParentWindow:(NSWindow*)parentWindow
+ extension:(const Extension*)extension
+ browser:(Browser*)browser
+ icon:(SkBitmap)icon;
+
+// Action for close button.
+- (IBAction)closeWindow:(id)sender;
+
+// Displays the extension installed bubble. This callback is triggered by
+// the extensionObserver when the extension has completed loading.
+- (void)showWindow:(id)sender;
+
+// Clears our weak pointer to the Extension. This callback is triggered by
+// the extensionObserver when the extension is unloaded.
+- (void)extensionUnloaded:(id)sender;
+
+@end
+
+@interface ExtensionInstalledBubbleController(ExposedForTesting)
+
+- (void)removePageActionPreviewIfNecessary;
+- (NSWindow*)initializeWindow;
+- (int)calculateWindowHeight;
+- (void)setMessageFrames:(int)newWindowHeight;
+- (NSRect)getExtensionInstalledMsgFrame;
+- (NSRect)getExtraInfoMsgFrame;
+- (NSRect)getExtensionInstalledInfoMsgFrame;
+
+@end // ExtensionInstalledBubbleController(ExposedForTesting)
+
+#endif // CHROME_BROWSER_UI_COCOA_EXTENSION_INSTALLED_BUBBLE_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/extension_installed_bubble_controller.mm b/chrome/browser/ui/cocoa/extension_installed_bubble_controller.mm
new file mode 100644
index 0000000..f417ff7
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extension_installed_bubble_controller.mm
@@ -0,0 +1,378 @@
+// 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 "extension_installed_bubble_controller.h"
+
+#include "app/l10n_util.h"
+#include "base/i18n/rtl.h"
+#include "base/mac_util.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/ui/cocoa/browser_window_cocoa.h"
+#include "chrome/browser/ui/cocoa/browser_window_controller.h"
+#include "chrome/browser/ui/cocoa/extensions/browser_actions_controller.h"
+#include "chrome/browser/ui/cocoa/hover_close_button.h"
+#include "chrome/browser/ui/cocoa/info_bubble_view.h"
+#include "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
+#include "chrome/browser/ui/cocoa/toolbar_controller.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_action.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_source.h"
+#include "grit/generated_resources.h"
+#import "skia/ext/skia_utils_mac.h"
+#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
+
+
+// C++ class that receives EXTENSION_LOADED notifications and proxies them back
+// to |controller|.
+class ExtensionLoadedNotificationObserver : public NotificationObserver {
+ public:
+ ExtensionLoadedNotificationObserver(
+ ExtensionInstalledBubbleController* controller, Profile* profile)
+ : controller_(controller) {
+ registrar_.Add(this, NotificationType::EXTENSION_LOADED,
+ Source<Profile>(profile));
+ registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
+ Source<Profile>(profile));
+ }
+
+ private:
+ // NotificationObserver implementation. Tells the controller to start showing
+ // its window on the main thread when the extension has finished loading.
+ void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NotificationType::EXTENSION_LOADED) {
+ const Extension* extension = Details<const Extension>(details).ptr();
+ if (extension == [controller_ extension]) {
+ [controller_ performSelectorOnMainThread:@selector(showWindow:)
+ withObject:controller_
+ waitUntilDone:NO];
+ }
+ } else if (type == NotificationType::EXTENSION_UNLOADED) {
+ const Extension* extension = Details<const Extension>(details).ptr();
+ if (extension == [controller_ extension]) {
+ [controller_ performSelectorOnMainThread:@selector(extensionUnloaded:)
+ withObject:controller_
+ waitUntilDone:NO];
+ }
+ } else {
+ NOTREACHED() << "Received unexpected notification.";
+ }
+ }
+
+ NotificationRegistrar registrar_;
+ ExtensionInstalledBubbleController* controller_; // weak, owns us
+};
+
+@implementation ExtensionInstalledBubbleController
+
+@synthesize extension = extension_;
+@synthesize pageActionRemoved = pageActionRemoved_; // Exposed for unit test.
+
+- (id)initWithParentWindow:(NSWindow*)parentWindow
+ extension:(const Extension*)extension
+ browser:(Browser*)browser
+ icon:(SkBitmap)icon {
+ NSString* nibPath =
+ [mac_util::MainAppBundle() pathForResource:@"ExtensionInstalledBubble"
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibPath owner:self])) {
+ DCHECK(parentWindow);
+ parentWindow_ = parentWindow;
+ DCHECK(extension);
+ extension_ = extension;
+ DCHECK(browser);
+ browser_ = browser;
+ icon_.reset([gfx::SkBitmapToNSImage(icon) retain]);
+ pageActionRemoved_ = NO;
+
+ if (!extension->omnibox_keyword().empty()) {
+ type_ = extension_installed_bubble::kOmniboxKeyword;
+ } else if (extension->browser_action()) {
+ type_ = extension_installed_bubble::kBrowserAction;
+ } else if (extension->page_action() &&
+ !extension->page_action()->default_icon_path().empty()) {
+ type_ = extension_installed_bubble::kPageAction;
+ } else {
+ NOTREACHED(); // kGeneric installs handled in the extension_install_ui.
+ }
+
+ // Start showing window only after extension has fully loaded.
+ extensionObserver_.reset(new ExtensionLoadedNotificationObserver(
+ self, browser->profile()));
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+- (void)close {
+ [parentWindow_ removeChildWindow:[self window]];
+ [super close];
+}
+
+- (void)windowWillClose:(NSNotification*)notification {
+ // Turn off page action icon preview when the window closes, unless we
+ // already removed it when the window resigned key status.
+ [self removePageActionPreviewIfNecessary];
+ extension_ = NULL;
+ browser_ = NULL;
+ parentWindow_ = nil;
+ // We caught a close so we don't need to watch for the parent closing.
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [self autorelease];
+}
+
+// The controller is the delegate of the window, so it receives "did resign
+// key" notifications. When key is resigned, close the window.
+- (void)windowDidResignKey:(NSNotification*)notification {
+ NSWindow* window = [self window];
+ DCHECK_EQ([notification object], window);
+ DCHECK([window isVisible]);
+
+ // If the browser window is closing, we need to remove the page action
+ // immediately, otherwise the closing animation may overlap with
+ // browser destruction.
+ [self removePageActionPreviewIfNecessary];
+ [self close];
+}
+
+- (IBAction)closeWindow:(id)sender {
+ DCHECK([[self window] isVisible]);
+ [self close];
+}
+
+// Extracted to a function here so that it can be overwritten for unit
+// testing.
+- (void)removePageActionPreviewIfNecessary {
+ if (!extension_ || !extension_->page_action() || pageActionRemoved_)
+ return;
+ pageActionRemoved_ = YES;
+
+ BrowserWindowCocoa* window =
+ static_cast<BrowserWindowCocoa*>(browser_->window());
+ LocationBarViewMac* locationBarView =
+ [window->cocoa_controller() locationBarBridge];
+ locationBarView->SetPreviewEnabledPageAction(extension_->page_action(),
+ false); // disables preview.
+}
+
+// The extension installed bubble points at the browser action icon or the
+// page action icon (shown as a preview), depending on the extension type.
+// We need to calculate the location of these icons and the size of the
+// message itself (which varies with the title of the extension) in order
+// to figure out the origin point for the extension installed bubble.
+// TODO(mirandac): add framework to easily test extension UI components!
+- (NSPoint)calculateArrowPoint {
+ BrowserWindowCocoa* window =
+ static_cast<BrowserWindowCocoa*>(browser_->window());
+ NSPoint arrowPoint = NSZeroPoint;
+
+ switch(type_) {
+ case extension_installed_bubble::kOmniboxKeyword: {
+ LocationBarViewMac* locationBarView =
+ [window->cocoa_controller() locationBarBridge];
+ arrowPoint = locationBarView->GetPageInfoBubblePoint();
+ break;
+ }
+ case extension_installed_bubble::kBrowserAction: {
+ BrowserActionsController* controller =
+ [[window->cocoa_controller() toolbarController]
+ browserActionsController];
+ arrowPoint = [controller popupPointForBrowserAction:extension_];
+ break;
+ }
+ case extension_installed_bubble::kPageAction: {
+ LocationBarViewMac* locationBarView =
+ [window->cocoa_controller() locationBarBridge];
+
+ // Tell the location bar to show a preview of the page action icon, which
+ // would ordinarily only be displayed on a page of the appropriate type.
+ // We remove this preview when the extension installed bubble closes.
+ locationBarView->SetPreviewEnabledPageAction(extension_->page_action(),
+ true);
+
+ // Find the center of the bottom of the page action icon.
+ arrowPoint =
+ locationBarView->GetPageActionBubblePoint(extension_->page_action());
+ break;
+ }
+ default: {
+ NOTREACHED() << "Generic extension type not allowed in install bubble.";
+ }
+ }
+ return arrowPoint;
+}
+
+// We want this to be a child of a browser window. addChildWindow:
+// (called from this function) will bring the window on-screen;
+// unfortunately, [NSWindowController showWindow:] will also bring it
+// on-screen (but will cause unexpected changes to the window's
+// position). We cannot have an addChildWindow: and a subsequent
+// showWindow:. Thus, we have our own version.
+- (void)showWindow:(id)sender {
+ // Generic extensions get an infobar rather than a bubble.
+ DCHECK(type_ != extension_installed_bubble::kGeneric);
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // Load nib and calculate height based on messages to be shown.
+ NSWindow* window = [self initializeWindow];
+ int newWindowHeight = [self calculateWindowHeight];
+ [infoBubbleView_ setFrameSize:NSMakeSize(
+ NSWidth([[window contentView] bounds]), newWindowHeight)];
+ NSSize windowDelta = NSMakeSize(
+ 0, newWindowHeight - NSHeight([[window contentView] bounds]));
+ windowDelta = [[window contentView] convertSize:windowDelta toView:nil];
+ NSRect newFrame = [window frame];
+ newFrame.size.height += windowDelta.height;
+ [window setFrame:newFrame display:NO];
+
+ // Now that we have resized the window, adjust y pos of the messages.
+ [self setMessageFrames:newWindowHeight];
+
+ // Find window origin, taking into account bubble size and arrow location.
+ NSPoint origin =
+ [parentWindow_ convertBaseToScreen:[self calculateArrowPoint]];
+ NSSize offsets = NSMakeSize(info_bubble::kBubbleArrowXOffset +
+ info_bubble::kBubbleArrowWidth / 2.0, 0);
+ offsets = [[window contentView] convertSize:offsets toView:nil];
+ if ([infoBubbleView_ arrowLocation] == info_bubble::kTopRight)
+ origin.x -= NSWidth([window frame]) - offsets.width;
+ origin.y -= NSHeight([window frame]);
+ [window setFrameOrigin:origin];
+
+ [parentWindow_ addChildWindow:window
+ ordered:NSWindowAbove];
+ [window makeKeyAndOrderFront:self];
+}
+
+// Finish nib loading, set arrow location and load icon into window. This
+// function is exposed for unit testing.
+- (NSWindow*)initializeWindow {
+ NSWindow* window = [self window]; // completes nib load
+
+ if (type_ == extension_installed_bubble::kOmniboxKeyword) {
+ [infoBubbleView_ setArrowLocation:info_bubble::kTopLeft];
+ } else {
+ [infoBubbleView_ setArrowLocation:info_bubble::kTopRight];
+ }
+
+ // Set appropriate icon, resizing if necessary.
+ if ([icon_ size].width > extension_installed_bubble::kIconSize) {
+ [icon_ setSize:NSMakeSize(extension_installed_bubble::kIconSize,
+ extension_installed_bubble::kIconSize)];
+ }
+ [iconImage_ setImage:icon_];
+ [iconImage_ setNeedsDisplay:YES];
+ return window;
+ }
+
+// Calculate the height of each install message, resizing messages in their
+// frames to fit window width. Return the new window height, based on the
+// total of all message heights.
+- (int)calculateWindowHeight {
+ // Adjust the window height to reflect the sum height of all messages
+ // and vertical padding.
+ int newWindowHeight = 2 * extension_installed_bubble::kOuterVerticalMargin;
+
+ // First part of extension installed message.
+ string16 extension_name = UTF8ToUTF16(extension_->name().c_str());
+ base::i18n::AdjustStringForLocaleDirection(&extension_name);
+ [extensionInstalledMsg_ setStringValue:l10n_util::GetNSStringF(
+ IDS_EXTENSION_INSTALLED_HEADING, extension_name)];
+ [GTMUILocalizerAndLayoutTweaker
+ sizeToFitFixedWidthTextField:extensionInstalledMsg_];
+ newWindowHeight += [extensionInstalledMsg_ frame].size.height +
+ extension_installed_bubble::kInnerVerticalMargin;
+
+ // If type is page action, include a special message about page actions.
+ if (type_ == extension_installed_bubble::kPageAction) {
+ [extraInfoMsg_ setHidden:NO];
+ [[extraInfoMsg_ cell]
+ setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
+ [GTMUILocalizerAndLayoutTweaker
+ sizeToFitFixedWidthTextField:extraInfoMsg_];
+ newWindowHeight += [extraInfoMsg_ frame].size.height +
+ extension_installed_bubble::kInnerVerticalMargin;
+ }
+
+ // If type is omnibox keyword, include a special message about the keyword.
+ if (type_ == extension_installed_bubble::kOmniboxKeyword) {
+ [extraInfoMsg_ setStringValue:l10n_util::GetNSStringF(
+ IDS_EXTENSION_INSTALLED_OMNIBOX_KEYWORD_INFO,
+ UTF8ToUTF16(extension_->omnibox_keyword()))];
+ [extraInfoMsg_ setHidden:NO];
+ [[extraInfoMsg_ cell]
+ setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
+ [GTMUILocalizerAndLayoutTweaker
+ sizeToFitFixedWidthTextField:extraInfoMsg_];
+ newWindowHeight += [extraInfoMsg_ frame].size.height +
+ extension_installed_bubble::kInnerVerticalMargin;
+ }
+
+ // Second part of extension installed message.
+ [[extensionInstalledInfoMsg_ cell]
+ setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
+ [GTMUILocalizerAndLayoutTweaker
+ sizeToFitFixedWidthTextField:extensionInstalledInfoMsg_];
+ newWindowHeight += [extensionInstalledInfoMsg_ frame].size.height;
+
+ return newWindowHeight;
+}
+
+// Adjust y-position of messages to sit properly in new window height.
+- (void)setMessageFrames:(int)newWindowHeight {
+ // The extension messages will always be shown.
+ NSRect extensionMessageFrame1 = [extensionInstalledMsg_ frame];
+ NSRect extensionMessageFrame2 = [extensionInstalledInfoMsg_ frame];
+
+ extensionMessageFrame1.origin.y = newWindowHeight - (
+ extensionMessageFrame1.size.height +
+ extension_installed_bubble::kOuterVerticalMargin);
+ [extensionInstalledMsg_ setFrame:extensionMessageFrame1];
+ if (type_ == extension_installed_bubble::kPageAction ||
+ type_ == extension_installed_bubble::kOmniboxKeyword) {
+ // The extra message is only shown when appropriate.
+ NSRect extraMessageFrame = [extraInfoMsg_ frame];
+ extraMessageFrame.origin.y = extensionMessageFrame1.origin.y - (
+ extraMessageFrame.size.height +
+ extension_installed_bubble::kInnerVerticalMargin);
+ [extraInfoMsg_ setFrame:extraMessageFrame];
+ extensionMessageFrame2.origin.y = extraMessageFrame.origin.y - (
+ extensionMessageFrame2.size.height +
+ extension_installed_bubble::kInnerVerticalMargin);
+ } else {
+ extensionMessageFrame2.origin.y = extensionMessageFrame1.origin.y - (
+ extensionMessageFrame2.size.height +
+ extension_installed_bubble::kInnerVerticalMargin);
+ }
+ [extensionInstalledInfoMsg_ setFrame:extensionMessageFrame2];
+}
+
+// Exposed for unit testing.
+- (NSRect)getExtensionInstalledMsgFrame {
+ return [extensionInstalledMsg_ frame];
+}
+
+- (NSRect)getExtraInfoMsgFrame {
+ return [extraInfoMsg_ frame];
+}
+
+- (NSRect)getExtensionInstalledInfoMsgFrame {
+ return [extensionInstalledInfoMsg_ frame];
+}
+
+- (void)extensionUnloaded:(id)sender {
+ extension_ = NULL;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/extension_installed_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/extension_installed_bubble_controller_unittest.mm
new file mode 100644
index 0000000..f1171d1
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extension_installed_bubble_controller_unittest.mm
@@ -0,0 +1,202 @@
+// 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 "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/scoped_ptr.h"
+#include "base/values.h"
+#import "chrome/browser/browser_window.h"
+#import "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/extension_installed_bubble_controller.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "webkit/glue/image_decoder.h"
+
+// ExtensionInstalledBubbleController with removePageActionPreview overridden
+// to a no-op, because pageActions are not yet hooked up in the test browser.
+@interface ExtensionInstalledBubbleControllerForTest :
+ ExtensionInstalledBubbleController {
+}
+
+// Do nothing, because browser window is not set up with page actions
+// for unit testing.
+- (void)removePageActionPreview;
+
+@end
+
+@implementation ExtensionInstalledBubbleControllerForTest
+
+- (void)removePageActionPreview { }
+
+@end
+
+namespace keys = extension_manifest_keys;
+
+class ExtensionInstalledBubbleControllerTest : public CocoaTest {
+
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ browser_ = helper_.browser();
+ window_ = helper_.CreateBrowserWindow()->GetNativeHandle();
+ icon_ = LoadTestIcon();
+ }
+
+ virtual void TearDown() {
+ helper_.CloseBrowserWindow();
+ CocoaTest::TearDown();
+ }
+
+ // Load test icon from extension test directory.
+ SkBitmap LoadTestIcon() {
+ FilePath path;
+ PathService::Get(chrome::DIR_TEST_DATA, &path);
+ path = path.AppendASCII("extensions").AppendASCII("icon1.png");
+
+ std::string file_contents;
+ file_util::ReadFileToString(path, &file_contents);
+ const unsigned char* data =
+ reinterpret_cast<const unsigned char*>(file_contents.data());
+
+ SkBitmap bitmap;
+ webkit_glue::ImageDecoder decoder;
+ bitmap = decoder.Decode(data, file_contents.length());
+
+ return bitmap;
+ }
+
+ // Create a skeletal framework of either page action or browser action
+ // type. This extension only needs to have a type and a name to initialize
+ // the ExtensionInstalledBubble for unit testing.
+ scoped_refptr<Extension> CreateExtension(
+ extension_installed_bubble::ExtensionType type) {
+ FilePath path;
+ PathService::Get(chrome::DIR_TEST_DATA, &path);
+ path = path.AppendASCII("extensions").AppendASCII("dummy");
+
+ DictionaryValue extension_input_value;
+ extension_input_value.SetString(keys::kVersion, "1.0.0.0");
+ if (type == extension_installed_bubble::kPageAction) {
+ extension_input_value.SetString(keys::kName, "page action extension");
+ DictionaryValue* action = new DictionaryValue;
+ action->SetString(keys::kPageActionId, "ExtensionActionId");
+ action->SetString(keys::kPageActionDefaultTitle, "ExtensionActionTitle");
+ action->SetString(keys::kPageActionDefaultIcon, "image1.png");
+ ListValue* action_list = new ListValue;
+ action_list->Append(action);
+ extension_input_value.Set(keys::kPageActions, action_list);
+ } else {
+ extension_input_value.SetString(keys::kName, "browser action extension");
+ DictionaryValue* browser_action = new DictionaryValue;
+ // An empty dictionary is enough to create a Browser Action.
+ extension_input_value.Set(keys::kBrowserAction, browser_action);
+ }
+
+ std::string error;
+ return Extension::Create(
+ path, Extension::INVALID, extension_input_value, false, &error);
+ }
+
+ // Allows us to create the window and browser for testing.
+ BrowserTestHelper helper_;
+
+ // Required to initialize the extension installed bubble.
+ NSWindow* window_; // weak, owned by BrowserTestHelper.
+
+ // Required to initialize the extension installed bubble.
+ Browser* browser_; // weak, owned by BrowserTestHelper.
+
+ // Skeleton extension to be tested; reinitialized for each test.
+ scoped_refptr<Extension> extension_;
+
+ // The icon_ to be loaded into the bubble window.
+ SkBitmap icon_;
+};
+
+// Confirm that window sizes are set correctly for a page action extension.
+TEST_F(ExtensionInstalledBubbleControllerTest, PageActionTest) {
+ extension_ = CreateExtension(extension_installed_bubble::kPageAction);
+ ExtensionInstalledBubbleControllerForTest* controller =
+ [[ExtensionInstalledBubbleControllerForTest alloc]
+ initWithParentWindow:window_
+ extension:extension_.get()
+ browser:browser_
+ icon:icon_];
+ EXPECT_TRUE(controller);
+
+ // Initialize window without having to calculate tabstrip locations.
+ [controller initializeWindow];
+ EXPECT_TRUE([controller window]);
+
+ int height = [controller calculateWindowHeight];
+ // Height should equal the vertical padding + height of all messages.
+ int correctHeight = 2 * extension_installed_bubble::kOuterVerticalMargin +
+ 2 * extension_installed_bubble::kInnerVerticalMargin +
+ [controller getExtensionInstalledMsgFrame].size.height +
+ [controller getExtensionInstalledInfoMsgFrame].size.height +
+ [controller getExtraInfoMsgFrame].size.height;
+ EXPECT_EQ(height, correctHeight);
+
+ [controller setMessageFrames:height];
+ NSRect msg3Frame = [controller getExtensionInstalledInfoMsgFrame];
+ // Bottom message should be kOuterVerticalMargin pixels above window edge.
+ EXPECT_EQ(msg3Frame.origin.y,
+ extension_installed_bubble::kOuterVerticalMargin);
+ NSRect msg2Frame = [controller getExtraInfoMsgFrame];
+ // Pageaction message should be kInnerVerticalMargin pixels above bottom msg.
+ EXPECT_EQ(msg2Frame.origin.y,
+ msg3Frame.origin.y + msg3Frame.size.height +
+ extension_installed_bubble::kInnerVerticalMargin);
+ NSRect msg1Frame = [controller getExtensionInstalledMsgFrame];
+ // Top message should be kInnerVerticalMargin pixels above Pageaction msg.
+ EXPECT_EQ(msg1Frame.origin.y,
+ msg2Frame.origin.y + msg2Frame.size.height +
+ extension_installed_bubble::kInnerVerticalMargin);
+
+ [controller setPageActionRemoved:YES];
+ [controller close];
+}
+
+TEST_F(ExtensionInstalledBubbleControllerTest, BrowserActionTest) {
+ extension_ = CreateExtension(extension_installed_bubble::kBrowserAction);
+ ExtensionInstalledBubbleControllerForTest* controller =
+ [[ExtensionInstalledBubbleControllerForTest alloc]
+ initWithParentWindow:window_
+ extension:extension_.get()
+ browser:browser_
+ icon:icon_];
+ EXPECT_TRUE(controller);
+
+ // Initialize window without having to calculate tabstrip locations.
+ [controller initializeWindow];
+ EXPECT_TRUE([controller window]);
+
+ int height = [controller calculateWindowHeight];
+ // Height should equal the vertical padding + height of all messages.
+ int correctHeight = 2 * extension_installed_bubble::kOuterVerticalMargin +
+ extension_installed_bubble::kInnerVerticalMargin +
+ [controller getExtensionInstalledMsgFrame].size.height +
+ [controller getExtensionInstalledInfoMsgFrame].size.height;
+ EXPECT_EQ(height, correctHeight);
+
+ [controller setMessageFrames:height];
+ NSRect msg3Frame = [controller getExtensionInstalledInfoMsgFrame];
+ // Bottom message should start kOuterVerticalMargin pixels above window edge.
+ EXPECT_EQ(msg3Frame.origin.y,
+ extension_installed_bubble::kOuterVerticalMargin);
+ NSRect msg1Frame = [controller getExtensionInstalledMsgFrame];
+ // Top message should start kInnerVerticalMargin pixels above top of
+ // extensionInstalled message, because page action message is hidden.
+ EXPECT_EQ(msg1Frame.origin.y,
+ msg3Frame.origin.y + msg3Frame.size.height +
+ extension_installed_bubble::kInnerVerticalMargin);
+
+ [controller close];
+}
diff --git a/chrome/browser/ui/cocoa/extension_view_mac.h b/chrome/browser/ui/cocoa/extension_view_mac.h
new file mode 100644
index 0000000..43e9058
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extension_view_mac.h
@@ -0,0 +1,88 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_EXTENSION_VIEW_MAC_H_
+#define CHROME_BROWSER_UI_COCOA_EXTENSION_VIEW_MAC_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "gfx/native_widget_types.h"
+#include "gfx/size.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+class Browser;
+class ExtensionHost;
+class RenderViewHost;
+class RenderWidgetHostViewMac;
+class SkBitmap;
+
+// This class represents extension views. An extension view internally contains
+// a bridge to an extension process, which draws to the extension view's
+// native view object through IPC.
+class ExtensionViewMac {
+ public:
+ ExtensionViewMac(ExtensionHost* extension_host, Browser* browser);
+ ~ExtensionViewMac();
+
+ // Starts the extension process and creates the native view. You must call
+ // this method before calling any of this class's other methods.
+ void Init();
+
+ // Returns the extension's native view.
+ gfx::NativeView native_view();
+
+ // Returns the browser the extension belongs to.
+ Browser* browser() const { return browser_; }
+
+ // Does this extension live as a toolstrip in an extension shelf?
+ bool is_toolstrip() const { return is_toolstrip_; }
+ void set_is_toolstrip(bool is_toolstrip) { is_toolstrip_ = is_toolstrip; }
+
+ // Sets the extensions's background image.
+ void SetBackground(const SkBitmap& background);
+
+ // Method for the ExtensionHost to notify us about the correct size for
+ // extension contents.
+ void UpdatePreferredSize(const gfx::Size& new_size);
+
+ // Method for the ExtensionHost to notify us when the RenderViewHost has a
+ // connection.
+ void RenderViewCreated();
+
+ // Informs the view that its containing window's frame changed.
+ void WindowFrameChanged();
+
+ // The minimum/maximum dimensions of the popup.
+ // The minimum is just a little larger than the size of the button itself.
+ // The maximum is an arbitrary number that should be smaller than most
+ // screens.
+ static const CGFloat kMinWidth;
+ static const CGFloat kMinHeight;
+ static const CGFloat kMaxWidth;
+ static const CGFloat kMaxHeight;
+
+ private:
+ RenderViewHost* render_view_host() const;
+
+ void CreateWidgetHostView();
+
+ // True if the contents are being displayed inside the extension shelf.
+ bool is_toolstrip_;
+
+ Browser* browser_; // weak
+
+ ExtensionHost* extension_host_; // weak
+
+ // Created by us, but owned by its |native_view()|. We |release| the
+ // rwhv's native view in our destructor, effectively freeing this.
+ RenderWidgetHostViewMac* render_widget_host_view_;
+
+ // The background the view should have once it is initialized. This is set
+ // when the view has a custom background, but hasn't been initialized yet.
+ SkBitmap pending_background_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionViewMac);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_EXTENSION_VIEW_MAC_H_
diff --git a/chrome/browser/ui/cocoa/extension_view_mac.mm b/chrome/browser/ui/cocoa/extension_view_mac.mm
new file mode 100644
index 0000000..d3a10e7
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extension_view_mac.mm
@@ -0,0 +1,112 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/extension_view_mac.h"
+
+#include "chrome/browser/extensions/extension_host.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/renderer_host/render_widget_host_view_mac.h"
+
+// The minimum/maximum dimensions of the popup.
+const CGFloat ExtensionViewMac::kMinWidth = 25.0;
+const CGFloat ExtensionViewMac::kMinHeight = 25.0;
+const CGFloat ExtensionViewMac::kMaxWidth = 800.0;
+const CGFloat ExtensionViewMac::kMaxHeight = 600.0;
+
+ExtensionViewMac::ExtensionViewMac(ExtensionHost* extension_host,
+ Browser* browser)
+ : is_toolstrip_(true),
+ browser_(browser),
+ extension_host_(extension_host),
+ render_widget_host_view_(NULL) {
+ DCHECK(extension_host_);
+}
+
+ExtensionViewMac::~ExtensionViewMac() {
+ if (render_widget_host_view_)
+ [render_widget_host_view_->native_view() release];
+}
+
+void ExtensionViewMac::Init() {
+ CreateWidgetHostView();
+}
+
+gfx::NativeView ExtensionViewMac::native_view() {
+ DCHECK(render_widget_host_view_);
+ return render_widget_host_view_->native_view();
+}
+
+RenderViewHost* ExtensionViewMac::render_view_host() const {
+ return extension_host_->render_view_host();
+}
+
+void ExtensionViewMac::SetBackground(const SkBitmap& background) {
+ DCHECK(render_widget_host_view_);
+ if (render_view_host()->IsRenderViewLive()) {
+ render_widget_host_view_->SetBackground(background);
+ } else {
+ pending_background_ = background;
+ }
+}
+
+void ExtensionViewMac::UpdatePreferredSize(const gfx::Size& new_size) {
+ // TODO(thakis, erikkay): Windows does some tricks to resize the extension
+ // view not before it's visible. Do something similar here.
+
+ // No need to use CA here, our caller calls us repeatedly to animate the
+ // resizing.
+ NSView* view = native_view();
+ NSRect frame = [view frame];
+ frame.size.width = new_size.width();
+ frame.size.height = new_size.height();
+
+ // On first display of some extensions, this function is called with zero
+ // width after the correct size has been set. Bail if zero is seen, assuming
+ // that an extension's view doesn't want any dimensions to ever be zero.
+ // TODO(andybons): Verify this assumption and look into WebCore's
+ // |contentesPreferredWidth| to see why this is occurring.
+ if (NSIsEmptyRect(frame))
+ return;
+
+ DCHECK([view isKindOfClass:[RenderWidgetHostViewCocoa class]]);
+ RenderWidgetHostViewCocoa* hostView = (RenderWidgetHostViewCocoa*)view;
+
+ // RenderWidgetHostViewCocoa overrides setFrame but not setFrameSize.
+ // We need to defer the update back to the RenderWidgetHost so we don't
+ // get the flickering effect on 10.5 of http://crbug.com/31970
+ [hostView setFrameWithDeferredUpdate:frame];
+ [hostView setNeedsDisplay:YES];
+}
+
+void ExtensionViewMac::RenderViewCreated() {
+ // Do not allow webkit to draw scroll bars on views smaller than
+ // the largest size view allowed. The view will be resized to make
+ // scroll bars unnecessary. Scroll bars change the height of the
+ // view, so not drawing them is necessary to avoid infinite resizing.
+ gfx::Size largest_popup_size(
+ CGSizeMake(ExtensionViewMac::kMaxWidth, ExtensionViewMac::kMaxHeight));
+ extension_host_->DisableScrollbarsForSmallWindows(largest_popup_size);
+
+ if (!pending_background_.empty() && render_view_host()->view()) {
+ render_widget_host_view_->SetBackground(pending_background_);
+ pending_background_.reset();
+ }
+}
+
+void ExtensionViewMac::WindowFrameChanged() {
+ if (render_widget_host_view_)
+ render_widget_host_view_->WindowFrameChanged();
+}
+
+void ExtensionViewMac::CreateWidgetHostView() {
+ DCHECK(!render_widget_host_view_);
+ render_widget_host_view_ = new RenderWidgetHostViewMac(render_view_host());
+
+ // The RenderWidgetHostViewMac is owned by its native view, which is created
+ // in an autoreleased state. retain it, so that it doesn't immediately
+ // disappear.
+ [render_widget_host_view_->native_view() retain];
+
+ extension_host_->CreateRenderViewSoon(render_widget_host_view_);
+}
diff --git a/chrome/browser/ui/cocoa/extensions/browser_action_button.h b/chrome/browser/ui/cocoa/extensions/browser_action_button.h
new file mode 100644
index 0000000..a09ce7f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extensions/browser_action_button.h
@@ -0,0 +1,98 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_EXTENSIONS_BROWSER_ACTION_BUTTON_H_
+#define CHROME_BROWSER_UI_COCOA_EXTENSIONS_BROWSER_ACTION_BUTTON_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+#import "chrome/browser/ui/cocoa/gradient_button_cell.h"
+
+class Extension;
+class ExtensionAction;
+class ExtensionImageTrackerBridge;
+class Profile;
+
+// Fired when the Browser Action's state has changed. Usually the image needs to
+// be updated.
+extern NSString* const kBrowserActionButtonUpdatedNotification;
+
+// Fired on each drag event while the user is moving the button.
+extern NSString* const kBrowserActionButtonDraggingNotification;
+// Fired when the user drops the button.
+extern NSString* const kBrowserActionButtonDragEndNotification;
+
+@interface BrowserActionButton : NSButton {
+ @private
+ // Bridge to proxy Chrome notifications to the Obj-C class as well as load the
+ // extension's icon.
+ scoped_ptr<ExtensionImageTrackerBridge> imageLoadingBridge_;
+
+ // The default icon of the Button.
+ scoped_nsobject<NSImage> defaultIcon_;
+
+ // The icon specific to the active tab.
+ scoped_nsobject<NSImage> tabSpecificIcon_;
+
+ // Used to move the button and query whether a button is currently animating.
+ scoped_nsobject<NSViewAnimation> moveAnimation_;
+
+ // The extension for this button. Weak.
+ const Extension* extension_;
+
+ // The ID of the active tab.
+ int tabId_;
+
+ // Whether the button is currently being dragged.
+ BOOL isBeingDragged_;
+
+ // Drag events could be intercepted by other buttons, so to make sure that
+ // this is the only button moving if it ends up being dragged. This is set to
+ // YES upon |mouseDown:|.
+ BOOL dragCouldStart_;
+}
+
+- (id)initWithFrame:(NSRect)frame
+ extension:(const Extension*)extension
+ profile:(Profile*)profile
+ tabId:(int)tabId;
+
+- (void)setFrame:(NSRect)frameRect animate:(BOOL)animate;
+
+- (void)setDefaultIcon:(NSImage*)image;
+
+- (void)setTabSpecificIcon:(NSImage*)image;
+
+- (void)updateState;
+
+- (BOOL)isAnimating;
+
+// Returns a pointer to an autoreleased NSImage with the badge, shadow and
+// cell image drawn into it.
+- (NSImage*)compositedImage;
+
+@property(readonly, nonatomic) BOOL isBeingDragged;
+@property(readonly, nonatomic) const Extension* extension;
+@property(readwrite, nonatomic) int tabId;
+
+@end
+
+@interface BrowserActionCell : GradientButtonCell {
+ @private
+ // The current tab ID used when drawing the cell.
+ int tabId_;
+
+ // The action we're drawing the cell for. Weak.
+ ExtensionAction* extensionAction_;
+}
+
+@property(readwrite, nonatomic) int tabId;
+@property(readwrite, nonatomic) ExtensionAction* extensionAction;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_EXTENSIONS_BROWSER_ACTION_BUTTON_H_
diff --git a/chrome/browser/ui/cocoa/extensions/browser_action_button.mm b/chrome/browser/ui/cocoa/extensions/browser_action_button.mm
new file mode 100644
index 0000000..14701c8
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extensions/browser_action_button.mm
@@ -0,0 +1,333 @@
+// 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 "chrome/browser/ui/cocoa/extensions/browser_action_button.h"
+
+#include <algorithm>
+#include <cmath>
+
+#include "base/logging.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/extensions/image_loading_tracker.h"
+#include "chrome/browser/ui/cocoa/extensions/extension_action_context_menu.h"
+#import "chrome/browser/ui/cocoa/image_utils.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_action.h"
+#include "chrome/common/extensions/extension_resource.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
+#include "gfx/canvas_skia_paint.h"
+#include "gfx/rect.h"
+#include "gfx/size.h"
+#include "skia/ext/skia_utils_mac.h"
+#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
+
+NSString* const kBrowserActionButtonUpdatedNotification =
+ @"BrowserActionButtonUpdatedNotification";
+
+NSString* const kBrowserActionButtonDraggingNotification =
+ @"BrowserActionButtonDraggingNotification";
+NSString* const kBrowserActionButtonDragEndNotification =
+ @"BrowserActionButtonDragEndNotification";
+
+static const CGFloat kBrowserActionBadgeOriginYOffset = 5;
+
+namespace {
+const CGFloat kAnimationDuration = 0.2;
+const CGFloat kShadowOffset = 2.0;
+} // anonymous namespace
+
+// A helper class to bridge the asynchronous Skia bitmap loading mechanism to
+// the extension's button.
+class ExtensionImageTrackerBridge : public NotificationObserver,
+ public ImageLoadingTracker::Observer {
+ public:
+ ExtensionImageTrackerBridge(BrowserActionButton* owner,
+ const Extension* extension)
+ : owner_(owner),
+ tracker_(this) {
+ // The Browser Action API does not allow the default icon path to be
+ // changed at runtime, so we can load this now and cache it.
+ std::string path = extension->browser_action()->default_icon_path();
+ if (!path.empty()) {
+ tracker_.LoadImage(extension, extension->GetResource(path),
+ gfx::Size(Extension::kBrowserActionIconMaxSize,
+ Extension::kBrowserActionIconMaxSize),
+ ImageLoadingTracker::DONT_CACHE);
+ }
+ registrar_.Add(this, NotificationType::EXTENSION_BROWSER_ACTION_UPDATED,
+ Source<ExtensionAction>(extension->browser_action()));
+ }
+
+ ~ExtensionImageTrackerBridge() {}
+
+ // ImageLoadingTracker::Observer implementation.
+ void OnImageLoaded(SkBitmap* image, ExtensionResource resource, int index) {
+ if (image)
+ [owner_ setDefaultIcon:gfx::SkBitmapToNSImage(*image)];
+ [owner_ updateState];
+ }
+
+ // Overridden from NotificationObserver.
+ void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NotificationType::EXTENSION_BROWSER_ACTION_UPDATED)
+ [owner_ updateState];
+ else
+ NOTREACHED();
+ }
+
+ private:
+ // Weak. Owns us.
+ BrowserActionButton* owner_;
+
+ // Loads the button's icons for us on the file thread.
+ ImageLoadingTracker tracker_;
+
+ // Used for registering to receive notifications and automatic clean up.
+ NotificationRegistrar registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionImageTrackerBridge);
+};
+
+@interface BrowserActionCell(Internals)
+- (void)setIconShadow;
+- (void)drawBadgeWithinFrame:(NSRect)frame;
+@end
+
+@interface BrowserActionButton(Private)
+- (void)endDrag;
+@end
+
+@implementation BrowserActionButton
+
+@synthesize isBeingDragged = isBeingDragged_;
+@synthesize extension = extension_;
+@synthesize tabId = tabId_;
+
++ (Class)cellClass {
+ return [BrowserActionCell class];
+}
+
+- (id)initWithFrame:(NSRect)frame
+ extension:(const Extension*)extension
+ profile:(Profile*)profile
+ tabId:(int)tabId {
+ if ((self = [super initWithFrame:frame])) {
+ BrowserActionCell* cell = [[[BrowserActionCell alloc] init] autorelease];
+ // [NSButton setCell:] warns to NOT use setCell: other than in the
+ // initializer of a control. However, we are using a basic
+ // NSButton whose initializer does not take an NSCell as an
+ // object. To honor the assumed semantics, we do nothing with
+ // NSButton between alloc/init and setCell:.
+ [self setCell:cell];
+ [cell setTabId:tabId];
+ [cell setExtensionAction:extension->browser_action()];
+
+ [self setTitle:@""];
+ [self setButtonType:NSMomentaryChangeButton];
+ [self setShowsBorderOnlyWhileMouseInside:YES];
+
+ [self setMenu:[[[ExtensionActionContextMenu alloc]
+ initWithExtension:extension
+ profile:profile
+ extensionAction:extension->browser_action()] autorelease]];
+
+ tabId_ = tabId;
+ extension_ = extension;
+ imageLoadingBridge_.reset(new ExtensionImageTrackerBridge(self, extension));
+
+ moveAnimation_.reset([[NSViewAnimation alloc] init]);
+ [moveAnimation_ gtm_setDuration:kAnimationDuration
+ eventMask:NSLeftMouseUpMask];
+ [moveAnimation_ setAnimationBlockingMode:NSAnimationNonblocking];
+
+ [self updateState];
+ }
+
+ return self;
+}
+
+- (BOOL)acceptsFirstResponder {
+ return YES;
+}
+
+- (void)mouseDown:(NSEvent*)theEvent {
+ [[self cell] setHighlighted:YES];
+ dragCouldStart_ = YES;
+}
+
+- (void)mouseDragged:(NSEvent*)theEvent {
+ if (!dragCouldStart_)
+ return;
+
+ if (!isBeingDragged_) {
+ // The start of a drag. Position the button above all others.
+ [[self superview] addSubview:self positioned:NSWindowAbove relativeTo:nil];
+ }
+ isBeingDragged_ = YES;
+ NSRect buttonFrame = [self frame];
+ // TODO(andybons): Constrain the buttons to be within the container.
+ // Clamp the button to be within its superview along the X-axis.
+ buttonFrame.origin.x += [theEvent deltaX];
+ [self setFrame:buttonFrame];
+ [self setNeedsDisplay:YES];
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName:kBrowserActionButtonDraggingNotification
+ object:self];
+}
+
+- (void)mouseUp:(NSEvent*)theEvent {
+ dragCouldStart_ = NO;
+ // There are non-drag cases where a mouseUp: may happen
+ // (e.g. mouse-down, cmd-tab to another application, move mouse,
+ // mouse-up).
+ NSPoint location = [self convertPoint:[theEvent locationInWindow]
+ fromView:nil];
+ if (NSPointInRect(location, [self bounds]) && !isBeingDragged_) {
+ // Only perform the click if we didn't drag the button.
+ [self performClick:self];
+ } else {
+ // Make sure an ESC to end a drag doesn't trigger 2 endDrags.
+ if (isBeingDragged_) {
+ [self endDrag];
+ } else {
+ [super mouseUp:theEvent];
+ }
+ }
+}
+
+- (void)endDrag {
+ isBeingDragged_ = NO;
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName:kBrowserActionButtonDragEndNotification
+ object:self];
+ [[self cell] setHighlighted:NO];
+}
+
+- (void)setFrame:(NSRect)frameRect animate:(BOOL)animate {
+ if (!animate) {
+ [self setFrame:frameRect];
+ } else {
+ if ([moveAnimation_ isAnimating])
+ [moveAnimation_ stopAnimation];
+
+ NSDictionary* animationDictionary =
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ self, NSViewAnimationTargetKey,
+ [NSValue valueWithRect:[self frame]], NSViewAnimationStartFrameKey,
+ [NSValue valueWithRect:frameRect], NSViewAnimationEndFrameKey,
+ nil];
+ [moveAnimation_ setViewAnimations:
+ [NSArray arrayWithObject:animationDictionary]];
+ [moveAnimation_ startAnimation];
+ }
+}
+
+- (void)setDefaultIcon:(NSImage*)image {
+ defaultIcon_.reset([image retain]);
+}
+
+- (void)setTabSpecificIcon:(NSImage*)image {
+ tabSpecificIcon_.reset([image retain]);
+}
+
+- (void)updateState {
+ if (tabId_ < 0)
+ return;
+
+ std::string tooltip = extension_->browser_action()->GetTitle(tabId_);
+ if (tooltip.empty()) {
+ [self setToolTip:nil];
+ } else {
+ [self setToolTip:base::SysUTF8ToNSString(tooltip)];
+ }
+
+ SkBitmap image = extension_->browser_action()->GetIcon(tabId_);
+ if (!image.isNull()) {
+ [self setTabSpecificIcon:gfx::SkBitmapToNSImage(image)];
+ [self setImage:tabSpecificIcon_];
+ } else if (defaultIcon_) {
+ [self setImage:defaultIcon_];
+ }
+
+ [[self cell] setTabId:tabId_];
+
+ [self setNeedsDisplay:YES];
+
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName:kBrowserActionButtonUpdatedNotification
+ object:self];
+}
+
+- (BOOL)isAnimating {
+ return [moveAnimation_ isAnimating];
+}
+
+- (NSImage*)compositedImage {
+ NSRect bounds = [self bounds];
+ NSImage* image = [[[NSImage alloc] initWithSize:bounds.size] autorelease];
+ [image lockFocus];
+
+ [[NSColor clearColor] set];
+ NSRectFill(bounds);
+ [[self cell] setIconShadow];
+
+ NSImage* actionImage = [self image];
+ const NSSize imageSize = [actionImage size];
+ const NSRect imageRect =
+ NSMakeRect(std::floor((NSWidth(bounds) - imageSize.width) / 2.0),
+ std::floor((NSHeight(bounds) - imageSize.height) / 2.0),
+ imageSize.width, imageSize.height);
+ [actionImage drawInRect:imageRect
+ fromRect:NSZeroRect
+ operation:NSCompositeSourceOver
+ fraction:1.0
+ neverFlipped:YES];
+
+ bounds.origin.y += kShadowOffset - kBrowserActionBadgeOriginYOffset;
+ bounds.origin.x -= kShadowOffset;
+ [[self cell] drawBadgeWithinFrame:bounds];
+
+ [image unlockFocus];
+ return image;
+}
+
+@end
+
+@implementation BrowserActionCell
+
+@synthesize tabId = tabId_;
+@synthesize extensionAction = extensionAction_;
+
+- (void)setIconShadow {
+ // Create the shadow below and to the right of the drawn image.
+ scoped_nsobject<NSShadow> imgShadow([[NSShadow alloc] init]);
+ [imgShadow.get() setShadowOffset:NSMakeSize(kShadowOffset, -kShadowOffset)];
+ [imgShadow setShadowBlurRadius:2.0];
+ [imgShadow.get() setShadowColor:[[NSColor blackColor]
+ colorWithAlphaComponent:0.3]];
+ [imgShadow set];
+}
+
+- (void)drawBadgeWithinFrame:(NSRect)frame {
+ gfx::CanvasSkiaPaint canvas(frame, false);
+ canvas.set_composite_alpha(true);
+ gfx::Rect boundingRect(NSRectToCGRect(frame));
+ extensionAction_->PaintBadge(&canvas, boundingRect, tabId_);
+}
+
+- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
+ [NSGraphicsContext saveGraphicsState];
+ [self setIconShadow];
+ [super drawInteriorWithFrame:cellFrame inView:controlView];
+ cellFrame.origin.y += kBrowserActionBadgeOriginYOffset;
+ [self drawBadgeWithinFrame:cellFrame];
+ [NSGraphicsContext restoreGraphicsState];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h b/chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h
new file mode 100644
index 0000000..d9ebf6e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h
@@ -0,0 +1,84 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_EXTENSIONS_BROWSER_ACTIONS_CONTAINER_VIEW_
+#define CHROME_BROWSER_UI_COCOA_EXTENSIONS_BROWSER_ACTIONS_CONTAINER_VIEW_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+// Sent when a user-initiated drag to resize the container is initiated.
+extern NSString* const kBrowserActionGrippyDragStartedNotification;
+
+// Sent when a user-initiated drag is resizing the container.
+extern NSString* const kBrowserActionGrippyDraggingNotification;
+
+// Sent when a user-initiated drag to resize the container has finished.
+extern NSString* const kBrowserActionGrippyDragFinishedNotification;
+
+// The view that encompasses the Browser Action buttons in the toolbar and
+// provides mechanisms for resizing.
+@interface BrowserActionsContainerView : NSView {
+ @private
+ // The frame encompasing the grippy used for resizing the container.
+ NSRect grippyRect_;
+
+ // The end frame of the animation currently running for this container or
+ // NSZeroRect if none is in progress.
+ NSRect animationEndFrame_;
+
+ // Used to cache the original position within the container that initiated the
+ // drag.
+ NSPoint initialDragPoint_;
+
+ // Used to cache the previous x-pos of the frame rect for resizing purposes.
+ CGFloat lastXPos_;
+
+ // The maximum width of the container.
+ CGFloat maxWidth_;
+
+ // Whether the container is currently being resized by the user.
+ BOOL userIsResizing_;
+
+ // Whether the user can resize this at all. Resizing is disabled in incognito
+ // mode since any changes done in incognito mode are not saved anyway, and
+ // also to avoid a crash. http://crbug.com/42848
+ BOOL resizable_;
+
+ // Whether the user is allowed to drag the grippy to the left. NO if all
+ // extensions are shown or the location bar has hit its minimum width (handled
+ // within toolbar_controller.mm).
+ BOOL canDragLeft_;
+
+ // Whether the user is allowed to drag the grippy to the right. NO if all
+ // extensions are hidden.
+ BOOL canDragRight_;
+
+ // When the left grippy is pinned, resizing the window has no effect on its
+ // position. This prevents it from overlapping with other elements as well
+ // as letting the container expand when the window is going from super small
+ // to large.
+ BOOL grippyPinned_;
+}
+
+// Resizes the container to the given ideal width, adjusting the |lastXPos_| so
+// that |resizeDeltaX| is accurate.
+- (void)resizeToWidth:(CGFloat)width animate:(BOOL)animate;
+
+// Returns the change in the x-pos of the frame rect during resizing. Meant to
+// be queried when a NSViewFrameDidChangeNotification is fired to determine
+// placement of surrounding elements.
+- (CGFloat)resizeDeltaX;
+
+@property(nonatomic, readonly) NSRect animationEndFrame;
+@property(nonatomic) BOOL canDragLeft;
+@property(nonatomic) BOOL canDragRight;
+@property(nonatomic) BOOL grippyPinned;
+@property(nonatomic,getter=isResizable) BOOL resizable;
+@property(nonatomic) CGFloat maxWidth;
+@property(readonly, nonatomic) BOOL userIsResizing;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_EXTENSIONS_BROWSER_ACTIONS_CONTAINER_VIEW_
diff --git a/chrome/browser/ui/cocoa/extensions/browser_actions_container_view.mm b/chrome/browser/ui/cocoa/extensions/browser_actions_container_view.mm
new file mode 100644
index 0000000..3d10e22
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extensions/browser_actions_container_view.mm
@@ -0,0 +1,192 @@
+// 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 "chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h"
+
+#include <algorithm>
+
+#include "base/basictypes.h"
+#import "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/view_id_util.h"
+
+NSString* const kBrowserActionGrippyDragStartedNotification =
+ @"BrowserActionGrippyDragStartedNotification";
+NSString* const kBrowserActionGrippyDraggingNotification =
+ @"BrowserActionGrippyDraggingNotification";
+NSString* const kBrowserActionGrippyDragFinishedNotification =
+ @"BrowserActionGrippyDragFinishedNotification";
+
+namespace {
+const CGFloat kAnimationDuration = 0.2;
+const CGFloat kGrippyWidth = 4.0;
+const CGFloat kMinimumContainerWidth = 10.0;
+} // namespace
+
+@interface BrowserActionsContainerView(Private)
+// Returns the cursor that should be shown when hovering over the grippy based
+// on |canDragLeft_| and |canDragRight_|.
+- (NSCursor*)appropriateCursorForGrippy;
+@end
+
+@implementation BrowserActionsContainerView
+
+@synthesize animationEndFrame = animationEndFrame_;
+@synthesize canDragLeft = canDragLeft_;
+@synthesize canDragRight = canDragRight_;
+@synthesize grippyPinned = grippyPinned_;
+@synthesize maxWidth = maxWidth_;
+@synthesize userIsResizing = userIsResizing_;
+
+#pragma mark -
+#pragma mark Overridden Class Functions
+
+- (id)initWithFrame:(NSRect)frameRect {
+ if ((self = [super initWithFrame:frameRect])) {
+ grippyRect_ = NSMakeRect(0.0, 0.0, kGrippyWidth, NSHeight([self bounds]));
+ canDragLeft_ = YES;
+ canDragRight_ = YES;
+ resizable_ = YES;
+ [self setHidden:YES];
+ }
+ return self;
+}
+
+- (void)setResizable:(BOOL)resizable {
+ if (resizable == resizable_)
+ return;
+ resizable_ = resizable;
+ [self setNeedsDisplay:YES];
+}
+
+- (BOOL)isResizable {
+ return resizable_;
+}
+
+- (void)resetCursorRects {
+ [self discardCursorRects];
+ [self addCursorRect:grippyRect_ cursor:[self appropriateCursorForGrippy]];
+}
+
+- (BOOL)acceptsFirstResponder {
+ return YES;
+}
+
+- (void)mouseDown:(NSEvent*)theEvent {
+ initialDragPoint_ = [self convertPoint:[theEvent locationInWindow]
+ fromView:nil];
+ if (!resizable_ ||
+ !NSMouseInRect(initialDragPoint_, grippyRect_, [self isFlipped]))
+ return;
+
+ lastXPos_ = [self frame].origin.x;
+ userIsResizing_ = YES;
+
+ [[self appropriateCursorForGrippy] push];
+ // Disable cursor rects so that the Omnibox and other UI elements don't push
+ // cursors while the user is dragging. The cursor should be grippy until
+ // the |-mouseUp:| message is received.
+ [[self window] disableCursorRects];
+
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName:kBrowserActionGrippyDragStartedNotification
+ object:self];
+}
+
+- (void)mouseUp:(NSEvent*)theEvent {
+ if (!userIsResizing_)
+ return;
+
+ [NSCursor pop];
+ [[self window] enableCursorRects];
+
+ userIsResizing_ = NO;
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName:kBrowserActionGrippyDragFinishedNotification
+ object:self];
+}
+
+- (void)mouseDragged:(NSEvent*)theEvent {
+ if (!userIsResizing_)
+ return;
+
+ NSPoint location = [self convertPoint:[theEvent locationInWindow]
+ fromView:nil];
+ NSRect containerFrame = [self frame];
+ CGFloat dX = [theEvent deltaX];
+ CGFloat withDelta = location.x - dX;
+ canDragRight_ = (withDelta >= initialDragPoint_.x) &&
+ (NSWidth(containerFrame) > kMinimumContainerWidth);
+ canDragLeft_ = (withDelta <= initialDragPoint_.x) &&
+ (NSWidth(containerFrame) < maxWidth_);
+ if ((dX < 0.0 && !canDragLeft_) || (dX > 0.0 && !canDragRight_))
+ return;
+
+ containerFrame.size.width =
+ std::max(NSWidth(containerFrame) - dX, kMinimumContainerWidth);
+
+ if (NSWidth(containerFrame) == kMinimumContainerWidth)
+ return;
+
+ containerFrame.origin.x += dX;
+
+ [self setFrame:containerFrame];
+ [self setNeedsDisplay:YES];
+
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName:kBrowserActionGrippyDraggingNotification
+ object:self];
+
+ lastXPos_ += dX;
+}
+
+- (ViewID)viewID {
+ return VIEW_ID_BROWSER_ACTION_TOOLBAR;
+}
+
+#pragma mark -
+#pragma mark Public Methods
+
+- (void)resizeToWidth:(CGFloat)width animate:(BOOL)animate {
+ width = std::max(width, kMinimumContainerWidth);
+ NSRect frame = [self frame];
+ lastXPos_ = frame.origin.x;
+ CGFloat dX = frame.size.width - width;
+ frame.size.width = width;
+ NSRect newFrame = NSOffsetRect(frame, dX, 0);
+ if (animate) {
+ [NSAnimationContext beginGrouping];
+ [[NSAnimationContext currentContext] setDuration:kAnimationDuration];
+ [[self animator] setFrame:newFrame];
+ [NSAnimationContext endGrouping];
+ animationEndFrame_ = newFrame;
+ } else {
+ [self setFrame:newFrame];
+ [self setNeedsDisplay:YES];
+ }
+}
+
+- (CGFloat)resizeDeltaX {
+ return [self frame].origin.x - lastXPos_;
+}
+
+#pragma mark -
+#pragma mark Private Methods
+
+// Returns the cursor to display over the grippy hover region depending on the
+// current drag state.
+- (NSCursor*)appropriateCursorForGrippy {
+ NSCursor* retVal;
+ if (!resizable_ || (!canDragLeft_ && !canDragRight_)) {
+ retVal = [NSCursor arrowCursor];
+ } else if (!canDragLeft_) {
+ retVal = [NSCursor resizeRightCursor];
+ } else if (!canDragRight_) {
+ retVal = [NSCursor resizeLeftCursor];
+ } else {
+ retVal = [NSCursor resizeLeftRightCursor];
+ }
+ return retVal;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/extensions/browser_actions_container_view_unittest.mm b/chrome/browser/ui/cocoa/extensions/browser_actions_container_view_unittest.mm
new file mode 100644
index 0000000..002aa05
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extensions/browser_actions_container_view_unittest.mm
@@ -0,0 +1,52 @@
+// 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.
+
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+const CGFloat kContainerHeight = 15.0;
+const CGFloat kMinimumContainerWidth = 10.0;
+
+class BrowserActionsContainerViewTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ view_.reset([[BrowserActionsContainerView alloc]
+ initWithFrame:NSMakeRect(0, 0, 0, kContainerHeight)]);
+ }
+
+ scoped_nsobject<BrowserActionsContainerView> view_;
+};
+
+TEST_F(BrowserActionsContainerViewTest, BasicTests) {
+ EXPECT_TRUE([view_ isResizable]);
+ EXPECT_TRUE([view_ canDragLeft]);
+ EXPECT_TRUE([view_ canDragRight]);
+ EXPECT_TRUE([view_ isHidden]);
+}
+
+TEST_F(BrowserActionsContainerViewTest, SetWidthTests) {
+ // Try setting below the minimum width (10 pixels).
+ [view_ resizeToWidth:5.0 animate:NO];
+ EXPECT_EQ(kMinimumContainerWidth, NSWidth([view_ frame])) << "Frame width is "
+ << "less than the minimum allowed.";
+ // Since the frame expands to the left, the x-position delta value will be
+ // negative.
+ EXPECT_EQ(-kMinimumContainerWidth, [view_ resizeDeltaX]);
+
+ [view_ resizeToWidth:35.0 animate:NO];
+ EXPECT_EQ(35.0, NSWidth([view_ frame]));
+ EXPECT_EQ(-25.0, [view_ resizeDeltaX]);
+
+ [view_ resizeToWidth:20.0 animate:NO];
+ EXPECT_EQ(20.0, NSWidth([view_ frame]));
+ EXPECT_EQ(15.0, [view_ resizeDeltaX]);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/extensions/browser_actions_controller.h b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.h
new file mode 100644
index 0000000..1f19863
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.h
@@ -0,0 +1,117 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_EXTENSIONS_BROWSER_ACTIONS_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_EXTENSIONS_BROWSER_ACTIONS_CONTROLLER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+
+class Browser;
+@class BrowserActionButton;
+@class BrowserActionsContainerView;
+class Extension;
+@class ExtensionPopupController;
+class ExtensionToolbarModel;
+class ExtensionServiceObserverBridge;
+@class MenuButton;
+class PrefService;
+class Profile;
+
+// Sent when the visibility of the Browser Actions changes.
+extern NSString* const kBrowserActionVisibilityChangedNotification;
+
+// Handles state and provides an interface for controlling the Browser Actions
+// container within the Toolbar.
+@interface BrowserActionsController : NSObject {
+ @private
+ // Reference to the current browser. Weak.
+ Browser* browser_;
+
+ // The view from Toolbar.xib we'll be rendering our browser actions in. Weak.
+ BrowserActionsContainerView* containerView_;
+
+ // The current profile. Weak.
+ Profile* profile_;
+
+ // The model that tracks the order of the toolbar icons. Weak.
+ ExtensionToolbarModel* toolbarModel_;
+
+ // The observer for the ExtensionService we're getting events from.
+ scoped_ptr<ExtensionServiceObserverBridge> observer_;
+
+ // A dictionary of Extension ID -> BrowserActionButton pairs representing the
+ // buttons present in the container view. The ID is a string unique to each
+ // extension.
+ scoped_nsobject<NSMutableDictionary> buttons_;
+
+ // Array of hidden buttons in the correct order in which the user specified.
+ scoped_nsobject<NSMutableArray> hiddenButtons_;
+
+ // The currently running chevron animation (fade in/out).
+ scoped_nsobject<NSViewAnimation> chevronAnimation_;
+
+ // The chevron button used when Browser Actions are hidden.
+ scoped_nsobject<MenuButton> chevronMenuButton_;
+
+ // The Browser Actions overflow menu.
+ scoped_nsobject<NSMenu> overflowMenu_;
+}
+
+@property(readonly, nonatomic) BrowserActionsContainerView* containerView;
+
+// Initializes the controller given the current browser and container view that
+// will hold the browser action buttons.
+- (id)initWithBrowser:(Browser*)browser
+ containerView:(BrowserActionsContainerView*)container;
+
+// Update the display of all buttons.
+- (void)update;
+
+// Returns the current number of browser action buttons within the container,
+// whether or not they are displayed.
+- (NSUInteger)buttonCount;
+
+// Returns the current number of browser action buttons displayed in the
+// container.
+- (NSUInteger)visibleButtonCount;
+
+// Returns a pointer to the chevron menu button.
+- (MenuButton*)chevronMenuButton;
+
+// Resizes the container given the number of visible buttons, taking into
+// account the size of the grippy. Also updates the persistent width preference.
+- (void)resizeContainerAndAnimate:(BOOL)animate;
+
+// Returns the NSView for the action button associated with an extension.
+- (NSView*)browserActionViewForExtension:(const Extension*)extension;
+
+// Returns the saved width determined by the number of shown Browser Actions
+// preference property. If no preference is found, then the width for the
+// container is returned as if all buttons are shown.
+- (CGFloat)savedWidth;
+
+// Returns where the popup arrow should point to for a given Browser Action. If
+// it is passed an extension that is not a Browser Action, then it will return
+// NSZeroPoint.
+- (NSPoint)popupPointForBrowserAction:(const Extension*)extension;
+
+// Returns whether the chevron button is currently hidden or in the process of
+// being hidden (fading out). Will return NO if it is not hidden or is in the
+// process of fading in.
+- (BOOL)chevronIsHidden;
+
+// Registers the user preferences used by this class.
++ (void)registerUserPrefs:(PrefService*)prefs;
+
+@end // @interface BrowserActionsController
+
+@interface BrowserActionsController(TestingAPI)
+- (NSButton*)buttonWithIndex:(NSUInteger)index;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_EXTENSIONS_BROWSER_ACTIONS_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm
new file mode 100644
index 0000000..0e68252
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm
@@ -0,0 +1,866 @@
+// 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 "browser_actions_controller.h"
+
+#include <cmath>
+#include <string>
+
+#include "app/mac/nsimage_cache.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/extensions/extension_browser_event_router.h"
+#include "chrome/browser/extensions/extension_host.h"
+#include "chrome/browser/extensions/extension_toolbar_model.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/browser.h"
+#import "chrome/browser/ui/cocoa/extensions/browser_action_button.h"
+#import "chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h"
+#import "chrome/browser/ui/cocoa/extensions/chevron_menu_button.h"
+#import "chrome/browser/ui/cocoa/extensions/extension_popup_controller.h"
+#import "chrome/browser/ui/cocoa/menu_button.h"
+#include "chrome/common/extensions/extension_action.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/pref_names.h"
+#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
+
+NSString* const kBrowserActionVisibilityChangedNotification =
+ @"BrowserActionVisibilityChangedNotification";
+
+namespace {
+const CGFloat kAnimationDuration = 0.2;
+
+const CGFloat kChevronWidth = 14.0;
+
+// Image used for the overflow button.
+NSString* const kOverflowChevronsName =
+ @"browser_actions_overflow_Template.pdf";
+
+// Since the container is the maximum height of the toolbar, we have
+// to move the buttons up by this amount in order to have them look
+// vertically centered within the toolbar.
+const CGFloat kBrowserActionOriginYOffset = 5.0;
+
+// The size of each button on the toolbar.
+const CGFloat kBrowserActionHeight = 29.0;
+const CGFloat kBrowserActionWidth = 29.0;
+
+// The padding between browser action buttons.
+const CGFloat kBrowserActionButtonPadding = 2.0;
+
+// Padding between Omnibox and first button. Since the buttons have a
+// pixel of internal padding, this needs an extra pixel.
+const CGFloat kBrowserActionLeftPadding = kBrowserActionButtonPadding + 1.0;
+
+// How far to inset from the bottom of the view to get the top border
+// of the popup 2px below the bottom of the Omnibox.
+const CGFloat kBrowserActionBubbleYOffset = 3.0;
+
+} // namespace
+
+@interface BrowserActionsController(Private)
+// Used during initialization to create the BrowserActionButton objects from the
+// stored toolbar model.
+- (void)createButtons;
+
+// Creates and then adds the given extension's action button to the container
+// at the given index within the container. It does not affect the toolbar model
+// object since it is called when the toolbar model changes.
+- (void)createActionButtonForExtension:(const Extension*)extension
+ withIndex:(NSUInteger)index;
+
+// Removes an action button for the given extension from the container. This
+// method also does not affect the underlying toolbar model since it is called
+// when the toolbar model changes.
+- (void)removeActionButtonForExtension:(const Extension*)extension;
+
+// Useful in the case of a Browser Action being added/removed from the middle of
+// the container, this method repositions each button according to the current
+// toolbar model.
+- (void)positionActionButtonsAndAnimate:(BOOL)animate;
+
+// During container resizing, buttons become more transparent as they are pushed
+// off the screen. This method updates each button's opacity determined by the
+// position of the button.
+- (void)updateButtonOpacity;
+
+// Returns the existing button with the given extension backing it; nil if it
+// cannot be found or the extension's ID is invalid.
+- (BrowserActionButton*)buttonForExtension:(const Extension*)extension;
+
+// Returns the preferred width of the container given the number of visible
+// buttons |buttonCount|.
+- (CGFloat)containerWidthWithButtonCount:(NSUInteger)buttonCount;
+
+// Returns the number of buttons that can fit in the container according to its
+// current size.
+- (NSUInteger)containerButtonCapacity;
+
+// Notification handlers for events registered by the class.
+
+// Updates each button's opacity, the cursor rects and chevron position.
+- (void)containerFrameChanged:(NSNotification*)notification;
+
+// Hides the chevron and unhides every hidden button so that dragging the
+// container out smoothly shows the Browser Action buttons.
+- (void)containerDragStart:(NSNotification*)notification;
+
+// Sends a notification for the toolbar to reposition surrounding UI elements.
+- (void)containerDragging:(NSNotification*)notification;
+
+// Determines which buttons need to be hidden based on the new size, hides them
+// and updates the chevron overflow menu. Also fires a notification to let the
+// toolbar know that the drag has finished.
+- (void)containerDragFinished:(NSNotification*)notification;
+
+// Updates the image associated with the button should it be within the chevron
+// menu.
+- (void)actionButtonUpdated:(NSNotification*)notification;
+
+// Adjusts the position of the surrounding action buttons depending on where the
+// button is within the container.
+- (void)actionButtonDragging:(NSNotification*)notification;
+
+// Updates the position of the Browser Actions within the container. This fires
+// when _any_ Browser Action button is done dragging to keep all open windows in
+// sync visually.
+- (void)actionButtonDragFinished:(NSNotification*)notification;
+
+// Moves the given button both visually and within the toolbar model to the
+// specified index.
+- (void)moveButton:(BrowserActionButton*)button
+ toIndex:(NSUInteger)index
+ animate:(BOOL)animate;
+
+// Handles when the given BrowserActionButton object is clicked.
+- (void)browserActionClicked:(BrowserActionButton*)button;
+
+// Returns whether the given extension should be displayed. Only displays
+// incognito-enabled extensions in incognito mode. Otherwise returns YES.
+- (BOOL)shouldDisplayBrowserAction:(const Extension*)extension;
+
+// The reason |frame| is specified in these chevron functions is because the
+// container may be animating and the end frame of the animation should be
+// passed instead of the current frame (which may be off and cause the chevron
+// to jump at the end of its animation).
+
+// Shows the overflow chevron button depending on whether there are any hidden
+// extensions within the frame given.
+- (void)showChevronIfNecessaryInFrame:(NSRect)frame animate:(BOOL)animate;
+
+// Moves the chevron to its correct position within |frame|.
+- (void)updateChevronPositionInFrame:(NSRect)frame;
+
+// Shows or hides the chevron, animating as specified by |animate|.
+- (void)setChevronHidden:(BOOL)hidden
+ inFrame:(NSRect)frame
+ animate:(BOOL)animate;
+
+// Handles when a menu item within the chevron overflow menu is selected.
+- (void)chevronItemSelected:(id)menuItem;
+
+// Clears and then populates the overflow menu based on the contents of
+// |hiddenButtons_|.
+- (void)updateOverflowMenu;
+
+// Updates the container's grippy cursor based on the number of hidden buttons.
+- (void)updateGrippyCursors;
+
+// Returns the ID of the currently selected tab or -1 if none exists.
+- (int)currentTabId;
+@end
+
+// A helper class to proxy extension notifications to the view controller's
+// appropriate methods.
+class ExtensionServiceObserverBridge : public NotificationObserver,
+ public ExtensionToolbarModel::Observer {
+ public:
+ ExtensionServiceObserverBridge(BrowserActionsController* owner,
+ Profile* profile) : owner_(owner) {
+ registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE,
+ Source<Profile>(profile));
+ }
+
+ // Overridden from NotificationObserver.
+ void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ switch (type.value) {
+ case NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE: {
+ ExtensionPopupController* popup = [ExtensionPopupController popup];
+ if (popup && ![popup isClosing])
+ [popup close];
+
+ break;
+ }
+ default:
+ NOTREACHED() << L"Unexpected notification";
+ }
+ }
+
+ // ExtensionToolbarModel::Observer implementation.
+ void BrowserActionAdded(const Extension* extension, int index) {
+ [owner_ createActionButtonForExtension:extension withIndex:index];
+ [owner_ resizeContainerAndAnimate:NO];
+ }
+
+ void BrowserActionRemoved(const Extension* extension) {
+ [owner_ removeActionButtonForExtension:extension];
+ [owner_ resizeContainerAndAnimate:NO];
+ }
+
+ private:
+ // The object we need to inform when we get a notification. Weak. Owns us.
+ BrowserActionsController* owner_;
+
+ // Used for registering to receive notifications and automatic clean up.
+ NotificationRegistrar registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionServiceObserverBridge);
+};
+
+@implementation BrowserActionsController
+
+@synthesize containerView = containerView_;
+
+#pragma mark -
+#pragma mark Public Methods
+
+- (id)initWithBrowser:(Browser*)browser
+ containerView:(BrowserActionsContainerView*)container {
+ DCHECK(browser && container);
+
+ if ((self = [super init])) {
+ browser_ = browser;
+ profile_ = browser->profile();
+
+ if (!profile_->GetPrefs()->FindPreference(
+ prefs::kBrowserActionContainerWidth))
+ [BrowserActionsController registerUserPrefs:profile_->GetPrefs()];
+
+ observer_.reset(new ExtensionServiceObserverBridge(self, profile_));
+ ExtensionService* extensionsService = profile_->GetExtensionService();
+ // |extensionsService| can be NULL in Incognito.
+ if (extensionsService) {
+ toolbarModel_ = extensionsService->toolbar_model();
+ toolbarModel_->AddObserver(observer_.get());
+ }
+
+ containerView_ = container;
+ [containerView_ setPostsFrameChangedNotifications:YES];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(containerFrameChanged:)
+ name:NSViewFrameDidChangeNotification
+ object:containerView_];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(containerDragStart:)
+ name:kBrowserActionGrippyDragStartedNotification
+ object:containerView_];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(containerDragging:)
+ name:kBrowserActionGrippyDraggingNotification
+ object:containerView_];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(containerDragFinished:)
+ name:kBrowserActionGrippyDragFinishedNotification
+ object:containerView_];
+ // Listen for a finished drag from any button to make sure each open window
+ // stays in sync.
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(actionButtonDragFinished:)
+ name:kBrowserActionButtonDragEndNotification
+ object:nil];
+
+ chevronAnimation_.reset([[NSViewAnimation alloc] init]);
+ [chevronAnimation_ gtm_setDuration:kAnimationDuration
+ eventMask:NSLeftMouseUpMask];
+ [chevronAnimation_ setAnimationBlockingMode:NSAnimationNonblocking];
+
+ hiddenButtons_.reset([[NSMutableArray alloc] init]);
+ buttons_.reset([[NSMutableDictionary alloc] init]);
+ [self createButtons];
+ [self showChevronIfNecessaryInFrame:[containerView_ frame] animate:NO];
+ [self updateGrippyCursors];
+ [container setResizable:!profile_->IsOffTheRecord()];
+ }
+
+ return self;
+}
+
+- (void)dealloc {
+ if (toolbarModel_)
+ toolbarModel_->RemoveObserver(observer_.get());
+
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+- (void)update {
+ for (BrowserActionButton* button in [buttons_ allValues]) {
+ [button setTabId:[self currentTabId]];
+ [button updateState];
+ }
+}
+
+- (NSUInteger)buttonCount {
+ return [buttons_ count];
+}
+
+- (NSUInteger)visibleButtonCount {
+ return [self buttonCount] - [hiddenButtons_ count];
+}
+
+- (MenuButton*)chevronMenuButton {
+ return chevronMenuButton_.get();
+}
+
+- (void)resizeContainerAndAnimate:(BOOL)animate {
+ int iconCount = toolbarModel_->GetVisibleIconCount();
+ if (iconCount < 0) // If no buttons are hidden.
+ iconCount = [self buttonCount];
+
+ [containerView_ resizeToWidth:[self containerWidthWithButtonCount:iconCount]
+ animate:animate];
+ NSRect frame = animate ? [containerView_ animationEndFrame] :
+ [containerView_ frame];
+
+ [self showChevronIfNecessaryInFrame:frame animate:animate];
+
+ if (!animate) {
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName:kBrowserActionVisibilityChangedNotification
+ object:self];
+ }
+}
+
+- (NSView*)browserActionViewForExtension:(const Extension*)extension {
+ for (BrowserActionButton* button in [buttons_ allValues]) {
+ if ([button extension] == extension)
+ return button;
+ }
+ NOTREACHED();
+ return nil;
+}
+
+- (CGFloat)savedWidth {
+ if (!toolbarModel_)
+ return 0;
+ if (!profile_->GetPrefs()->HasPrefPath(prefs::kExtensionToolbarSize)) {
+ // Migration code to the new VisibleIconCount pref.
+ // TODO(mpcomplete): remove this at some point.
+ double predefinedWidth =
+ profile_->GetPrefs()->GetReal(prefs::kBrowserActionContainerWidth);
+ if (predefinedWidth != 0) {
+ int iconWidth = kBrowserActionWidth + kBrowserActionButtonPadding;
+ int extraWidth = kChevronWidth;
+ toolbarModel_->SetVisibleIconCount(
+ (predefinedWidth - extraWidth) / iconWidth);
+ }
+ }
+
+ int savedButtonCount = toolbarModel_->GetVisibleIconCount();
+ if (savedButtonCount < 0 || // all icons are visible
+ static_cast<NSUInteger>(savedButtonCount) > [self buttonCount])
+ savedButtonCount = [self buttonCount];
+ return [self containerWidthWithButtonCount:savedButtonCount];
+}
+
+- (NSPoint)popupPointForBrowserAction:(const Extension*)extension {
+ if (!extension->browser_action())
+ return NSZeroPoint;
+
+ NSButton* button = [self buttonForExtension:extension];
+ if (!button)
+ return NSZeroPoint;
+
+ if ([hiddenButtons_ containsObject:button])
+ button = chevronMenuButton_.get();
+
+ // Anchor point just above the center of the bottom.
+ const NSRect bounds = [button bounds];
+ DCHECK([button isFlipped]);
+ NSPoint anchor = NSMakePoint(NSMidX(bounds),
+ NSMaxY(bounds) - kBrowserActionBubbleYOffset);
+ return [button convertPoint:anchor toView:nil];
+}
+
+- (BOOL)chevronIsHidden {
+ if (!chevronMenuButton_.get())
+ return YES;
+
+ if (![chevronAnimation_ isAnimating])
+ return [chevronMenuButton_ isHidden];
+
+ DCHECK([[chevronAnimation_ viewAnimations] count] > 0);
+
+ // The chevron is animating in or out. Determine which one and have the return
+ // value reflect where the animation is headed.
+ NSString* effect = [[[chevronAnimation_ viewAnimations] objectAtIndex:0]
+ valueForKey:NSViewAnimationEffectKey];
+ if (effect == NSViewAnimationFadeInEffect) {
+ return NO;
+ } else if (effect == NSViewAnimationFadeOutEffect) {
+ return YES;
+ }
+
+ NOTREACHED();
+ return YES;
+}
+
++ (void)registerUserPrefs:(PrefService*)prefs {
+ prefs->RegisterRealPref(prefs::kBrowserActionContainerWidth, 0);
+}
+
+#pragma mark -
+#pragma mark Private Methods
+
+- (void)createButtons {
+ if (!toolbarModel_)
+ return;
+
+ NSUInteger i = 0;
+ for (ExtensionList::iterator iter = toolbarModel_->begin();
+ iter != toolbarModel_->end(); ++iter) {
+ if (![self shouldDisplayBrowserAction:*iter])
+ continue;
+
+ [self createActionButtonForExtension:*iter withIndex:i++];
+ }
+
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(actionButtonUpdated:)
+ name:kBrowserActionButtonUpdatedNotification
+ object:nil];
+
+ CGFloat width = [self savedWidth];
+ [containerView_ resizeToWidth:width animate:NO];
+}
+
+- (void)createActionButtonForExtension:(const Extension*)extension
+ withIndex:(NSUInteger)index {
+ if (!extension->browser_action())
+ return;
+
+ if (![self shouldDisplayBrowserAction:extension])
+ return;
+
+ if (profile_->IsOffTheRecord())
+ index = toolbarModel_->OriginalIndexToIncognito(index);
+
+ // Show the container if it's the first button. Otherwise it will be shown
+ // already.
+ if ([self buttonCount] == 0)
+ [containerView_ setHidden:NO];
+
+ NSRect buttonFrame = NSMakeRect(0.0, kBrowserActionOriginYOffset,
+ kBrowserActionWidth, kBrowserActionHeight);
+ BrowserActionButton* newButton =
+ [[[BrowserActionButton alloc]
+ initWithFrame:buttonFrame
+ extension:extension
+ profile:profile_
+ tabId:[self currentTabId]] autorelease];
+ [newButton setTarget:self];
+ [newButton setAction:@selector(browserActionClicked:)];
+ NSString* buttonKey = base::SysUTF8ToNSString(extension->id());
+ if (!buttonKey)
+ return;
+ [buttons_ setObject:newButton forKey:buttonKey];
+
+ [self positionActionButtonsAndAnimate:NO];
+
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(actionButtonDragging:)
+ name:kBrowserActionButtonDraggingNotification
+ object:newButton];
+
+
+ [containerView_ setMaxWidth:
+ [self containerWidthWithButtonCount:[self buttonCount]]];
+ [containerView_ setNeedsDisplay:YES];
+}
+
+- (void)removeActionButtonForExtension:(const Extension*)extension {
+ if (!extension->browser_action())
+ return;
+
+ NSString* buttonKey = base::SysUTF8ToNSString(extension->id());
+ if (!buttonKey)
+ return;
+
+ BrowserActionButton* button = [buttons_ objectForKey:buttonKey];
+ // This could be the case in incognito, where only a subset of extensions are
+ // shown.
+ if (!button)
+ return;
+
+ [button removeFromSuperview];
+ // It may or may not be hidden, but it won't matter to NSMutableArray either
+ // way.
+ [hiddenButtons_ removeObject:button];
+ [self updateOverflowMenu];
+
+ [buttons_ removeObjectForKey:buttonKey];
+ if ([self buttonCount] == 0) {
+ // No more buttons? Hide the container.
+ [containerView_ setHidden:YES];
+ } else {
+ [self positionActionButtonsAndAnimate:NO];
+ }
+ [containerView_ setMaxWidth:
+ [self containerWidthWithButtonCount:[self buttonCount]]];
+ [containerView_ setNeedsDisplay:YES];
+}
+
+- (void)positionActionButtonsAndAnimate:(BOOL)animate {
+ NSUInteger i = 0;
+ for (ExtensionList::iterator iter = toolbarModel_->begin();
+ iter != toolbarModel_->end(); ++iter) {
+ if (![self shouldDisplayBrowserAction:*iter])
+ continue;
+ BrowserActionButton* button = [self buttonForExtension:(*iter)];
+ if (!button)
+ continue;
+ if (![button isBeingDragged])
+ [self moveButton:button toIndex:i animate:animate];
+ ++i;
+ }
+}
+
+- (void)updateButtonOpacity {
+ for (BrowserActionButton* button in [buttons_ allValues]) {
+ NSRect buttonFrame = [button frame];
+ if (NSContainsRect([containerView_ bounds], buttonFrame)) {
+ if ([button alphaValue] != 1.0)
+ [button setAlphaValue:1.0];
+
+ continue;
+ }
+ CGFloat intersectionWidth =
+ NSWidth(NSIntersectionRect([containerView_ bounds], buttonFrame));
+ CGFloat alpha = std::max(0.0f, intersectionWidth / NSWidth(buttonFrame));
+ [button setAlphaValue:alpha];
+ [button setNeedsDisplay:YES];
+ }
+}
+
+- (BrowserActionButton*)buttonForExtension:(const Extension*)extension {
+ NSString* extensionId = base::SysUTF8ToNSString(extension->id());
+ DCHECK(extensionId);
+ if (!extensionId)
+ return nil;
+ return [buttons_ objectForKey:extensionId];
+}
+
+- (CGFloat)containerWidthWithButtonCount:(NSUInteger)buttonCount {
+ // Left-side padding which works regardless of whether a button or
+ // chevron leads.
+ CGFloat width = kBrowserActionLeftPadding;
+
+ // Include the buttons and padding between.
+ if (buttonCount > 0) {
+ width += buttonCount * kBrowserActionWidth;
+ width += (buttonCount - 1) * kBrowserActionButtonPadding;
+ }
+
+ // Make room for the chevron if any buttons are hidden.
+ if ([self buttonCount] != [self visibleButtonCount]) {
+ // Chevron and buttons both include 1px padding w/in their bounds,
+ // so this leaves 2px between the last browser action and chevron,
+ // and also works right if the chevron is the only button.
+ width += kChevronWidth;
+ }
+
+ return width;
+}
+
+- (NSUInteger)containerButtonCapacity {
+ // Edge-to-edge span of the browser action buttons.
+ CGFloat actionSpan = [self savedWidth] - kBrowserActionLeftPadding;
+
+ // Add in some padding for the browser action on the end, then
+ // divide out to get the number of action buttons that fit.
+ return (actionSpan + kBrowserActionButtonPadding) /
+ (kBrowserActionWidth + kBrowserActionButtonPadding);
+}
+
+- (void)containerFrameChanged:(NSNotification*)notification {
+ [self updateButtonOpacity];
+ [[containerView_ window] invalidateCursorRectsForView:containerView_];
+ [self updateChevronPositionInFrame:[containerView_ frame]];
+}
+
+- (void)containerDragStart:(NSNotification*)notification {
+ [self setChevronHidden:YES inFrame:[containerView_ frame] animate:YES];
+ while([hiddenButtons_ count] > 0) {
+ [containerView_ addSubview:[hiddenButtons_ objectAtIndex:0]];
+ [hiddenButtons_ removeObjectAtIndex:0];
+ }
+}
+
+- (void)containerDragging:(NSNotification*)notification {
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName:kBrowserActionGrippyDraggingNotification
+ object:self];
+}
+
+- (void)containerDragFinished:(NSNotification*)notification {
+ for (ExtensionList::iterator iter = toolbarModel_->begin();
+ iter != toolbarModel_->end(); ++iter) {
+ BrowserActionButton* button = [self buttonForExtension:(*iter)];
+ NSRect buttonFrame = [button frame];
+ if (NSContainsRect([containerView_ bounds], buttonFrame))
+ continue;
+
+ CGFloat intersectionWidth =
+ NSWidth(NSIntersectionRect([containerView_ bounds], buttonFrame));
+ // Pad the threshold by 5 pixels in order to have the buttons hide more
+ // easily.
+ if (([containerView_ grippyPinned] && intersectionWidth > 0) ||
+ (intersectionWidth <= (NSWidth(buttonFrame) / 2) + 5.0)) {
+ [button setAlphaValue:0.0];
+ [button removeFromSuperview];
+ [hiddenButtons_ addObject:button];
+ }
+ }
+ [self updateOverflowMenu];
+ [self updateGrippyCursors];
+
+ if (!profile_->IsOffTheRecord())
+ toolbarModel_->SetVisibleIconCount([self visibleButtonCount]);
+
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName:kBrowserActionGrippyDragFinishedNotification
+ object:self];
+}
+
+- (void)actionButtonUpdated:(NSNotification*)notification {
+ BrowserActionButton* button = [notification object];
+ if (![hiddenButtons_ containsObject:button])
+ return;
+
+ // +1 item because of the title placeholder. See |updateOverflowMenu|.
+ NSUInteger menuIndex = [hiddenButtons_ indexOfObject:button] + 1;
+ NSMenuItem* item = [[chevronMenuButton_ attachedMenu] itemAtIndex:menuIndex];
+ DCHECK(button == [item representedObject]);
+ [item setImage:[button compositedImage]];
+}
+
+- (void)actionButtonDragging:(NSNotification*)notification {
+ if (![self chevronIsHidden])
+ [self setChevronHidden:YES inFrame:[containerView_ frame] animate:YES];
+
+ // Determine what index the dragged button should lie in, alter the model and
+ // reposition the buttons.
+ CGFloat dragThreshold = std::floor(kBrowserActionWidth / 2);
+ BrowserActionButton* draggedButton = [notification object];
+ NSRect draggedButtonFrame = [draggedButton frame];
+
+ NSUInteger index = 0;
+ for (ExtensionList::iterator iter = toolbarModel_->begin();
+ iter != toolbarModel_->end(); ++iter) {
+ BrowserActionButton* button = [self buttonForExtension:(*iter)];
+ CGFloat intersectionWidth =
+ NSWidth(NSIntersectionRect(draggedButtonFrame, [button frame]));
+
+ if (intersectionWidth > dragThreshold && button != draggedButton &&
+ ![button isAnimating] && index < [self visibleButtonCount]) {
+ toolbarModel_->MoveBrowserAction([draggedButton extension], index);
+ [self positionActionButtonsAndAnimate:YES];
+ return;
+ }
+ ++index;
+ }
+}
+
+- (void)actionButtonDragFinished:(NSNotification*)notification {
+ [self showChevronIfNecessaryInFrame:[containerView_ frame] animate:YES];
+ [self positionActionButtonsAndAnimate:YES];
+}
+
+- (void)moveButton:(BrowserActionButton*)button
+ toIndex:(NSUInteger)index
+ animate:(BOOL)animate {
+ CGFloat xOffset = kBrowserActionLeftPadding +
+ (index * (kBrowserActionWidth + kBrowserActionButtonPadding));
+ NSRect buttonFrame = [button frame];
+ buttonFrame.origin.x = xOffset;
+ [button setFrame:buttonFrame animate:animate];
+
+ if (index < [self containerButtonCapacity]) {
+ // Make sure the button is within the visible container.
+ if ([button superview] != containerView_) {
+ [containerView_ addSubview:button];
+ [button setAlphaValue:1.0];
+ [hiddenButtons_ removeObjectIdenticalTo:button];
+ }
+ } else if (![hiddenButtons_ containsObject:button]) {
+ [hiddenButtons_ addObject:button];
+ [button removeFromSuperview];
+ [button setAlphaValue:0.0];
+ [self updateOverflowMenu];
+ }
+}
+
+- (void)browserActionClicked:(BrowserActionButton*)button {
+ int tabId = [self currentTabId];
+ if (tabId < 0) {
+ NOTREACHED() << "No current tab.";
+ return;
+ }
+
+ ExtensionAction* action = [button extension]->browser_action();
+ if (action->HasPopup(tabId)) {
+ GURL popupUrl = action->GetPopupUrl(tabId);
+ // If a popup is already showing, check if the popup URL is the same. If so,
+ // then close the popup.
+ ExtensionPopupController* popup = [ExtensionPopupController popup];
+ if (popup &&
+ [[popup window] isVisible] &&
+ [popup extensionHost]->GetURL() == popupUrl) {
+ [popup close];
+ return;
+ }
+ NSPoint arrowPoint = [self popupPointForBrowserAction:[button extension]];
+ [ExtensionPopupController showURL:popupUrl
+ inBrowser:browser_
+ anchoredAt:arrowPoint
+ arrowLocation:info_bubble::kTopRight
+ devMode:NO];
+ } else {
+ ExtensionBrowserEventRouter::GetInstance()->BrowserActionExecuted(
+ profile_, action->extension_id(), browser_);
+ }
+}
+
+- (BOOL)shouldDisplayBrowserAction:(const Extension*)extension {
+ // Only display incognito-enabled extensions while in incognito mode.
+ return (!profile_->IsOffTheRecord() ||
+ profile_->GetExtensionService()->IsIncognitoEnabled(extension));
+}
+
+- (void)showChevronIfNecessaryInFrame:(NSRect)frame animate:(BOOL)animate {
+ [self setChevronHidden:([self buttonCount] == [self visibleButtonCount])
+ inFrame:frame
+ animate:animate];
+}
+
+- (void)updateChevronPositionInFrame:(NSRect)frame {
+ CGFloat xPos = NSWidth(frame) - kChevronWidth;
+ NSRect buttonFrame = NSMakeRect(xPos,
+ kBrowserActionOriginYOffset,
+ kChevronWidth,
+ kBrowserActionHeight);
+ [chevronMenuButton_ setFrame:buttonFrame];
+}
+
+- (void)setChevronHidden:(BOOL)hidden
+ inFrame:(NSRect)frame
+ animate:(BOOL)animate {
+ if (hidden == [self chevronIsHidden])
+ return;
+
+ if (!chevronMenuButton_.get()) {
+ chevronMenuButton_.reset([[ChevronMenuButton alloc] init]);
+ [chevronMenuButton_ setBordered:NO];
+ [chevronMenuButton_ setShowsBorderOnlyWhileMouseInside:YES];
+ NSImage* chevronImage =
+ app::mac::GetCachedImageWithName(kOverflowChevronsName);
+ [chevronMenuButton_ setImage:chevronImage];
+ [containerView_ addSubview:chevronMenuButton_];
+ }
+
+ if (!hidden)
+ [self updateOverflowMenu];
+
+ [self updateChevronPositionInFrame:frame];
+
+ // Stop any running animation.
+ [chevronAnimation_ stopAnimation];
+
+ if (!animate) {
+ [chevronMenuButton_ setHidden:hidden];
+ return;
+ }
+
+ NSDictionary* animationDictionary;
+ if (hidden) {
+ animationDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
+ chevronMenuButton_.get(), NSViewAnimationTargetKey,
+ NSViewAnimationFadeOutEffect, NSViewAnimationEffectKey,
+ nil];
+ } else {
+ [chevronMenuButton_ setHidden:NO];
+ animationDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
+ chevronMenuButton_.get(), NSViewAnimationTargetKey,
+ NSViewAnimationFadeInEffect, NSViewAnimationEffectKey,
+ nil];
+ }
+ [chevronAnimation_ setViewAnimations:
+ [NSArray arrayWithObject:animationDictionary]];
+ [chevronAnimation_ startAnimation];
+}
+
+- (void)chevronItemSelected:(id)menuItem {
+ [self browserActionClicked:[menuItem representedObject]];
+}
+
+- (void)updateOverflowMenu {
+ overflowMenu_.reset([[NSMenu alloc] initWithTitle:@""]);
+ // See menu_button.h for documentation on why this is needed.
+ [overflowMenu_ addItemWithTitle:@"" action:nil keyEquivalent:@""];
+
+ for (BrowserActionButton* button in hiddenButtons_.get()) {
+ NSString* name = base::SysUTF8ToNSString([button extension]->name());
+ NSMenuItem* item =
+ [overflowMenu_ addItemWithTitle:name
+ action:@selector(chevronItemSelected:)
+ keyEquivalent:@""];
+ [item setRepresentedObject:button];
+ [item setImage:[button compositedImage]];
+ [item setTarget:self];
+ }
+ [chevronMenuButton_ setAttachedMenu:overflowMenu_];
+}
+
+- (void)updateGrippyCursors {
+ [containerView_ setCanDragLeft:[hiddenButtons_ count] > 0];
+ [containerView_ setCanDragRight:[self visibleButtonCount] > 0];
+ [[containerView_ window] invalidateCursorRectsForView:containerView_];
+}
+
+- (int)currentTabId {
+ TabContents* selected_tab = browser_->GetSelectedTabContents();
+ if (!selected_tab)
+ return -1;
+
+ return selected_tab->controller().session_id().id();
+}
+
+#pragma mark -
+#pragma mark Testing Methods
+
+- (NSButton*)buttonWithIndex:(NSUInteger)index {
+ if (profile_->IsOffTheRecord())
+ index = toolbarModel_->IncognitoIndexToOriginal(index);
+ if (index < toolbarModel_->size()) {
+ const Extension* extension = toolbarModel_->GetExtensionByIndex(index);
+ return [buttons_ objectForKey:base::SysUTF8ToNSString(extension->id())];
+ }
+ return nil;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/extensions/chevron_menu_button.h b/chrome/browser/ui/cocoa/extensions/chevron_menu_button.h
new file mode 100644
index 0000000..86c8209
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extensions/chevron_menu_button.h
@@ -0,0 +1,19 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_EXTENSIONS_CHEVRON_MENU_BUTTON_H_
+#define CHROME_BROWSER_UI_COCOA_EXTENSIONS_CHEVRON_MENU_BUTTON_H_
+#pragma once
+
+#import "chrome/browser/ui/cocoa/menu_button.h"
+
+@interface ChevronMenuButton : MenuButton {
+}
+
+// Overrides cell class with |ChevronMenuButtonCell|.
++ (Class)cellClass;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_EXTENSIONS_CHEVRON_MENU_BUTTON_H_
diff --git a/chrome/browser/ui/cocoa/extensions/chevron_menu_button.mm b/chrome/browser/ui/cocoa/extensions/chevron_menu_button.mm
new file mode 100644
index 0000000..04f1506
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extensions/chevron_menu_button.mm
@@ -0,0 +1,15 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/extensions/chevron_menu_button.h"
+
+#include "chrome/browser/ui/cocoa/extensions/chevron_menu_button_cell.h"
+
+@implementation ChevronMenuButton
+
++ (Class)cellClass {
+ return [ChevronMenuButtonCell class];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/extensions/chevron_menu_button_cell.h b/chrome/browser/ui/cocoa/extensions/chevron_menu_button_cell.h
new file mode 100644
index 0000000..429015c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extensions/chevron_menu_button_cell.h
@@ -0,0 +1,19 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_EXTENSIONS_CHEVRON_MENU_BUTTON_CELL_H_
+#define CHROME_BROWSER_UI_COCOA_EXTENSIONS_CHEVRON_MENU_BUTTON_CELL_H_
+#pragma once
+
+#import "chrome/browser/ui/cocoa/clickhold_button_cell.h"
+
+@interface ChevronMenuButtonCell : ClickHoldButtonCell {
+}
+
+// Adds a gradient border to the RHS of the cell when not hovered.
+- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_EXTENSIONS_CHEVRON_MENU_BUTTON_CELL_H_
diff --git a/chrome/browser/ui/cocoa/extensions/chevron_menu_button_cell.mm b/chrome/browser/ui/cocoa/extensions/chevron_menu_button_cell.mm
new file mode 100644
index 0000000..8d4408a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extensions/chevron_menu_button_cell.mm
@@ -0,0 +1,47 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/extensions/chevron_menu_button_cell.h"
+
+namespace {
+
+// Width of the divider.
+const CGFloat kDividerWidth = 1.0;
+
+// Vertical inset from edge of cell to divider start.
+const CGFloat kDividerInset = 3.0;
+
+// Grayscale for the center of the divider.
+const CGFloat kDividerGrayscale = 0.5;
+
+} // namespace
+
+@implementation ChevronMenuButtonCell
+
+- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
+ [super drawWithFrame:cellFrame inView:controlView];
+
+ if ([self isMouseInside])
+ return;
+
+ NSColor* middleColor =
+ [NSColor colorWithCalibratedWhite:kDividerGrayscale alpha:1.0];
+ NSColor* endPointColor = [middleColor colorWithAlphaComponent:0.0];
+
+ // Blend from background to |kDividerGrayscale| and back to
+ // background.
+ scoped_nsobject<NSGradient> borderGradient([[NSGradient alloc]
+ initWithColorsAndLocations:endPointColor, (CGFloat)0.0,
+ middleColor, (CGFloat)0.5,
+ endPointColor, (CGFloat)1.0,
+ nil]);
+
+ NSRect edgeRect, remainder;
+ NSDivideRect(cellFrame, &edgeRect, &remainder, kDividerWidth, NSMaxXEdge);
+ edgeRect = NSInsetRect(edgeRect, 0.0, kDividerInset);
+
+ [borderGradient drawInRect:edgeRect angle:90.0];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/extensions/chevron_menu_button_unittest.mm b/chrome/browser/ui/cocoa/extensions/chevron_menu_button_unittest.mm
new file mode 100644
index 0000000..71c8929
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extensions/chevron_menu_button_unittest.mm
@@ -0,0 +1,50 @@
+// 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 "chrome/browser/ui/cocoa/extensions/chevron_menu_button.h"
+#import "chrome/browser/ui/cocoa/extensions/chevron_menu_button_cell.h"
+
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+
+namespace {
+
+class ChevronMenuButtonTest : public CocoaTest {
+ public:
+ ChevronMenuButtonTest() {
+ NSRect frame = NSMakeRect(0, 0, 50, 30);
+ scoped_nsobject<ChevronMenuButton> button(
+ [[ChevronMenuButton alloc] initWithFrame:frame]);
+ button_ = button.get();
+ [[test_window() contentView] addSubview:button_];
+ }
+
+ ChevronMenuButton* button_;
+};
+
+// Test basic view operation.
+TEST_VIEW(ChevronMenuButtonTest, button_);
+
+// |ChevronMenuButton exists entirely to override the cell class.
+TEST_F(ChevronMenuButtonTest, CellSubclass) {
+ EXPECT_TRUE([[button_ cell] isKindOfClass:[ChevronMenuButtonCell class]]);
+}
+
+// Test both hovered and non-hovered display.
+TEST_F(ChevronMenuButtonTest, HoverAndNonHoverDisplay) {
+ ChevronMenuButtonCell* cell = [button_ cell];
+ EXPECT_FALSE([cell showsBorderOnlyWhileMouseInside]);
+ EXPECT_FALSE([cell isMouseInside]);
+
+ [cell setShowsBorderOnlyWhileMouseInside:YES];
+ [cell mouseEntered:nil];
+ EXPECT_TRUE([cell isMouseInside]);
+ [button_ display];
+
+ [cell mouseExited:nil];
+ EXPECT_FALSE([cell isMouseInside]);
+ [button_ display];
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/extensions/extension_action_context_menu.h b/chrome/browser/ui/cocoa/extensions/extension_action_context_menu.h
new file mode 100644
index 0000000..e40388f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extensions/extension_action_context_menu.h
@@ -0,0 +1,62 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_EXTENSIONS_EXTENSION_ACTION_CONTEXT_MENU_H_
+#define CHROME_BROWSER_UI_COCOA_EXTENSIONS_EXTENSION_ACTION_CONTEXT_MENU_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_ptr.h"
+#include "base/scoped_nsobject.h"
+
+class AsyncUninstaller;
+class DevmodeObserver;
+class Extension;
+class ExtensionAction;
+class NotificationRegistrar;
+class Profile;
+
+namespace extension_action_context_menu {
+
+class DevmodeObserver;
+
+} // namespace extension_action_context_menu
+
+// A context menu used by any extension UI components that require it.
+@interface ExtensionActionContextMenu : NSMenu {
+ @private
+ // The extension that this menu belongs to. Weak.
+ const Extension* extension_;
+
+ // The extension action this menu belongs to. Weak.
+ ExtensionAction* action_;
+
+ // The browser profile of the window that contains this extension. Weak.
+ Profile* profile_;
+
+ // The inspector menu item. Need to keep this around to add and remove it.
+ scoped_nsobject<NSMenuItem> inspectorItem_;
+
+ // The observer used to listen for pref changed notifications.
+ scoped_ptr<extension_action_context_menu::DevmodeObserver> observer_;
+
+ // Used to load the extension icon asynchronously on the I/O thread then show
+ // the uninstall confirmation dialog.
+ scoped_ptr<AsyncUninstaller> uninstaller_;
+}
+
+// Initializes and returns a context menu for the given extension and profile.
+- (id)initWithExtension:(const Extension*)extension
+ profile:(Profile*)profile
+ extensionAction:(ExtensionAction*)action;
+
+// Show or hide the inspector menu item.
+- (void)updateInspectorItem;
+
+@end
+
+typedef ExtensionActionContextMenu ExtensionActionContextMenuMac;
+
+#endif // CHROME_BROWSER_UI_COCOA_EXTENSIONS_EXTENSION_ACTION_CONTEXT_MENU_H_
diff --git a/chrome/browser/ui/cocoa/extensions/extension_action_context_menu.mm b/chrome/browser/ui/cocoa/extensions/extension_action_context_menu.mm
new file mode 100644
index 0000000..5317f17
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extensions/extension_action_context_menu.mm
@@ -0,0 +1,278 @@
+// 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 "chrome/browser/ui/cocoa/extensions/extension_action_context_menu.h"
+
+#include "app/l10n_util_mac.h"
+#include "base/sys_string_conversions.h"
+#include "base/task.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/extensions/extension_install_ui.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_tabs_module.h"
+#include "chrome/browser/prefs/pref_change_registrar.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/cocoa/browser_window_cocoa.h"
+#include "chrome/browser/ui/cocoa/browser_window_controller.h"
+#include "chrome/browser/ui/cocoa/extensions/browser_actions_controller.h"
+#include "chrome/browser/ui/cocoa/extensions/extension_popup_controller.h"
+#include "chrome/browser/ui/cocoa/info_bubble_view.h"
+#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
+#include "chrome/browser/ui/cocoa/toolbar_controller.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_action.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_type.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
+#include "grit/generated_resources.h"
+
+// A class that loads the extension icon on the I/O thread before showing the
+// confirmation dialog to uninstall the given extension.
+// Also acts as the extension's UI delegate in order to display the dialog.
+class AsyncUninstaller : public ExtensionInstallUI::Delegate {
+ public:
+ AsyncUninstaller(const Extension* extension, Profile* profile)
+ : extension_(extension),
+ profile_(profile) {
+ install_ui_.reset(new ExtensionInstallUI(profile));
+ install_ui_->ConfirmUninstall(this, extension_);
+ }
+
+ ~AsyncUninstaller() {}
+
+ // Overridden by ExtensionInstallUI::Delegate.
+ virtual void InstallUIProceed() {
+ profile_->GetExtensionService()->
+ UninstallExtension(extension_->id(), false);
+ }
+
+ virtual void InstallUIAbort() {}
+
+ private:
+ // The extension that we're loading the icon for. Weak.
+ const Extension* extension_;
+
+ // The current profile. Weak.
+ Profile* profile_;
+
+ scoped_ptr<ExtensionInstallUI> install_ui_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncUninstaller);
+};
+
+namespace extension_action_context_menu {
+
+class DevmodeObserver : public NotificationObserver {
+ public:
+ DevmodeObserver(ExtensionActionContextMenu* menu,
+ PrefService* service)
+ : menu_(menu), pref_service_(service) {
+ registrar_.Init(pref_service_);
+ registrar_.Add(prefs::kExtensionsUIDeveloperMode, this);
+ }
+ virtual ~DevmodeObserver() {}
+
+ void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NotificationType::PREF_CHANGED)
+ [menu_ updateInspectorItem];
+ else
+ NOTREACHED();
+ }
+
+ private:
+ ExtensionActionContextMenu* menu_;
+ PrefService* pref_service_;
+ PrefChangeRegistrar registrar_;
+};
+
+} // namespace extension_action_context_menu
+
+@interface ExtensionActionContextMenu(Private)
+// Callback for the context menu items.
+- (void)dispatch:(id)menuItem;
+@end
+
+@implementation ExtensionActionContextMenu
+
+namespace {
+// Enum of menu item choices to their respective indices.
+// NOTE: You MUST keep this in sync with the |menuItems| NSArray below.
+enum {
+ kExtensionContextName = 0,
+ kExtensionContextOptions = 2,
+ kExtensionContextDisable = 3,
+ kExtensionContextUninstall = 4,
+ kExtensionContextManage = 6,
+ kExtensionContextInspect = 7
+};
+
+int CurrentTabId() {
+ Browser* browser = BrowserList::GetLastActive();
+ if(!browser)
+ return -1;
+ TabContents* contents = browser->GetSelectedTabContents();
+ if (!contents)
+ return -1;
+ return ExtensionTabUtil::GetTabId(contents);
+}
+
+} // namespace
+
+- (id)initWithExtension:(const Extension*)extension
+ profile:(Profile*)profile
+ extensionAction:(ExtensionAction*)action{
+ if ((self = [super initWithTitle:@""])) {
+ action_ = action;
+ extension_ = extension;
+ profile_ = profile;
+
+ NSArray* menuItems = [NSArray arrayWithObjects:
+ base::SysUTF8ToNSString(extension->name()),
+ [NSMenuItem separatorItem],
+ l10n_util::GetNSStringWithFixup(IDS_EXTENSIONS_OPTIONS),
+ l10n_util::GetNSStringWithFixup(IDS_EXTENSIONS_DISABLE),
+ l10n_util::GetNSStringWithFixup(IDS_EXTENSIONS_UNINSTALL),
+ [NSMenuItem separatorItem],
+ l10n_util::GetNSStringWithFixup(IDS_MANAGE_EXTENSIONS),
+ nil];
+
+ for (id item in menuItems) {
+ if ([item isKindOfClass:[NSMenuItem class]]) {
+ [self addItem:item];
+ } else if ([item isKindOfClass:[NSString class]]) {
+ NSMenuItem* itemObj = [self addItemWithTitle:item
+ action:@selector(dispatch:)
+ keyEquivalent:@""];
+ // The tag should correspond to the enum above.
+ // NOTE: The enum and the order of the menu items MUST be in sync.
+ [itemObj setTag:[self indexOfItem:itemObj]];
+
+ // Disable the 'Options' item if there are no options to set.
+ if ([itemObj tag] == kExtensionContextOptions &&
+ extension_->options_url().spec().length() <= 0) {
+ // Setting the target to nil will disable the item. For some reason
+ // setEnabled:NO does not work.
+ [itemObj setTarget:nil];
+ } else {
+ [itemObj setTarget:self];
+ }
+ }
+ }
+
+ NSString* inspectorTitle =
+ l10n_util::GetNSStringWithFixup(IDS_EXTENSION_ACTION_INSPECT_POPUP);
+ inspectorItem_.reset([[NSMenuItem alloc] initWithTitle:inspectorTitle
+ action:@selector(dispatch:)
+ keyEquivalent:@""]);
+ [inspectorItem_.get() setTarget:self];
+ [inspectorItem_.get() setTag:kExtensionContextInspect];
+
+ PrefService* service = profile_->GetPrefs();
+ observer_.reset(
+ new extension_action_context_menu::DevmodeObserver(self, service));
+
+ [self updateInspectorItem];
+ return self;
+ }
+ return nil;
+}
+
+- (void)updateInspectorItem {
+ PrefService* service = profile_->GetPrefs();
+ bool devmode = service->GetBoolean(prefs::kExtensionsUIDeveloperMode);
+ if (devmode) {
+ if ([self indexOfItem:inspectorItem_.get()] == -1)
+ [self addItem:inspectorItem_.get()];
+ } else {
+ if ([self indexOfItem:inspectorItem_.get()] != -1)
+ [self removeItem:inspectorItem_.get()];
+ }
+}
+
+- (void)dispatch:(id)menuItem {
+ Browser* browser = BrowserList::FindBrowserWithProfile(profile_);
+ if (!browser)
+ return;
+
+ NSMenuItem* item = (NSMenuItem*)menuItem;
+ switch ([item tag]) {
+ case kExtensionContextName: {
+ GURL url(std::string(extension_urls::kGalleryBrowsePrefix) +
+ std::string("/detail/") + extension_->id());
+ browser->OpenURL(url, GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
+ break;
+ }
+ case kExtensionContextOptions: {
+ DCHECK(!extension_->options_url().is_empty());
+ profile_->GetExtensionProcessManager()->OpenOptionsPage(extension_,
+ browser);
+ break;
+ }
+ case kExtensionContextDisable: {
+ ExtensionService* extensionService = profile_->GetExtensionService();
+ if (!extensionService)
+ return; // Incognito mode.
+ extensionService->DisableExtension(extension_->id());
+ break;
+ }
+ case kExtensionContextUninstall: {
+ uninstaller_.reset(new AsyncUninstaller(extension_, profile_));
+ break;
+ }
+ case kExtensionContextManage: {
+ browser->OpenURL(GURL(chrome::kChromeUIExtensionsURL), GURL(),
+ NEW_FOREGROUND_TAB, PageTransition::LINK);
+ break;
+ }
+ case kExtensionContextInspect: {
+ BrowserWindowCocoa* window =
+ static_cast<BrowserWindowCocoa*>(browser->window());
+ ToolbarController* toolbarController =
+ [window->cocoa_controller() toolbarController];
+ LocationBarViewMac* locationBarView =
+ [toolbarController locationBarBridge];
+
+ NSPoint popupPoint = NSZeroPoint;
+ if (extension_->page_action() == action_) {
+ popupPoint = locationBarView->GetPageActionBubblePoint(action_);
+
+ } else if (extension_->browser_action() == action_) {
+ BrowserActionsController* controller =
+ [toolbarController browserActionsController];
+ popupPoint = [controller popupPointForBrowserAction:extension_];
+
+ } else {
+ NOTREACHED() << "action_ is not a page action or browser action?";
+ }
+
+ int tabId = CurrentTabId();
+ GURL url = action_->GetPopupUrl(tabId);
+ DCHECK(url.is_valid());
+ [ExtensionPopupController showURL:url
+ inBrowser:BrowserList::GetLastActive()
+ anchoredAt:popupPoint
+ arrowLocation:info_bubble::kTopRight
+ devMode:YES];
+ break;
+ }
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+- (BOOL)validateMenuItem:(NSMenuItem*)menuItem {
+ if([menuItem isEqualTo:inspectorItem_.get()]) {
+ return action_ && action_->HasPopup(CurrentTabId());
+ }
+ return YES;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/extensions/extension_infobar_controller.h b/chrome/browser/ui/cocoa/extensions/extension_infobar_controller.h
new file mode 100644
index 0000000..b2c9a8e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extensions/extension_infobar_controller.h
@@ -0,0 +1,41 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_EXTENSIONS_EXTENSION_INFOBAR_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_EXTENSIONS_EXTENSION_INFOBAR_CONTROLLER_H_
+#pragma once
+
+#import "chrome/browser/ui/cocoa/infobar_controller.h"
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+
+@class ExtensionActionContextMenu;
+class ExtensionInfoBarDelegate;
+class InfobarBridge;
+@class MenuButton;
+
+@interface ExtensionInfoBarController : InfoBarController {
+ // The native extension view retrieved from the extension host. Weak.
+ NSView* extensionView_;
+
+ // The window containing this InfoBar. Weak.
+ NSWindow* window_;
+
+ // The InfoBar's button with the Extension's icon that launches the context
+ // menu.
+ scoped_nsobject<MenuButton> dropdownButton_;
+
+ // The context menu that pops up when the left button is clicked.
+ scoped_nsobject<ExtensionActionContextMenu> contextMenu_;
+
+ // Helper class to bridge C++ and ObjC functionality together for the infobar.
+ scoped_ptr<InfobarBridge> bridge_;
+}
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_EXTENSIONS_EXTENSION_INFOBAR_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/extensions/extension_infobar_controller.mm b/chrome/browser/ui/cocoa/extensions/extension_infobar_controller.mm
new file mode 100644
index 0000000..1214370
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extensions/extension_infobar_controller.mm
@@ -0,0 +1,266 @@
+// 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 "chrome/browser/ui/cocoa/extensions/extension_infobar_controller.h"
+
+#include <cmath>
+
+#include "app/resource_bundle.h"
+#include "chrome/browser/extensions/extension_host.h"
+#include "chrome/browser/extensions/extension_infobar_delegate.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#import "chrome/browser/ui/cocoa/animatable_view.h"
+#import "chrome/browser/ui/cocoa/extensions/extension_action_context_menu.h"
+#import "chrome/browser/ui/cocoa/menu_button.h"
+#include "chrome/browser/ui/cocoa/infobar.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_icon_set.h"
+#include "chrome/common/extensions/extension_resource.h"
+#include "gfx/canvas_skia.h"
+#include "grit/theme_resources.h"
+#include "skia/ext/skia_utils_mac.h"
+
+namespace {
+const CGFloat kAnimationDuration = 0.12;
+const CGFloat kBottomBorderHeightPx = 1.0;
+const CGFloat kButtonHeightPx = 26.0;
+const CGFloat kButtonLeftMarginPx = 2.0;
+const CGFloat kButtonWidthPx = 34.0;
+const CGFloat kDropArrowLeftMarginPx = 3.0;
+const CGFloat kToolbarMinHeightPx = 36.0;
+const CGFloat kToolbarMaxHeightPx = 72.0;
+} // namespace
+
+@interface ExtensionInfoBarController(Private)
+// Called when the extension's hosted NSView has been resized.
+- (void)extensionViewFrameChanged;
+// Returns the clamped height of the extension view to be within the min and max
+// values defined above.
+- (CGFloat)clampedExtensionViewHeight;
+// Adjusts the width of the extension's hosted view to match the window's width
+// and sets the proper height for it as well.
+- (void)adjustExtensionViewSize;
+// Sets the image to be used in the button on the left side of the infobar.
+- (void)setButtonImage:(NSImage*)image;
+@end
+
+// A helper class to bridge the asynchronous Skia bitmap loading mechanism to
+// the extension's button.
+class InfobarBridge : public ExtensionInfoBarDelegate::DelegateObserver,
+ public ImageLoadingTracker::Observer {
+ public:
+ explicit InfobarBridge(ExtensionInfoBarController* owner)
+ : owner_(owner),
+ delegate_([owner delegate]->AsExtensionInfoBarDelegate()),
+ tracker_(this) {
+ delegate_->set_observer(this);
+ LoadIcon();
+ }
+
+ virtual ~InfobarBridge() {
+ if (delegate_)
+ delegate_->set_observer(NULL);
+ }
+
+ // Load the Extension's icon image.
+ void LoadIcon() {
+ const Extension* extension = delegate_->extension_host()->extension();
+ ExtensionResource icon_resource = extension->GetIconResource(
+ Extension::EXTENSION_ICON_BITTY, ExtensionIconSet::MATCH_EXACTLY);
+ if (!icon_resource.relative_path().empty()) {
+ tracker_.LoadImage(extension, icon_resource,
+ gfx::Size(Extension::EXTENSION_ICON_BITTY,
+ Extension::EXTENSION_ICON_BITTY),
+ ImageLoadingTracker::DONT_CACHE);
+ } else {
+ OnImageLoaded(NULL, icon_resource, 0);
+ }
+ }
+
+ // ImageLoadingTracker::Observer implementation.
+ // TODO(andybons): The infobar view implementations share a lot of the same
+ // code. Come up with a strategy to share amongst them.
+ virtual void OnImageLoaded(
+ SkBitmap* image, ExtensionResource resource, int index) {
+ if (!delegate_)
+ return; // The delegate can go away while the image asynchronously loads.
+
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+
+ // Fall back on the default extension icon on failure.
+ SkBitmap* icon;
+ if (!image || image->empty())
+ icon = rb.GetBitmapNamed(IDR_EXTENSIONS_SECTION);
+ else
+ icon = image;
+
+ SkBitmap* drop_image = rb.GetBitmapNamed(IDR_APP_DROPARROW);
+
+ const int image_size = Extension::EXTENSION_ICON_BITTY;
+ scoped_ptr<gfx::CanvasSkia> canvas(
+ new gfx::CanvasSkia(
+ image_size + kDropArrowLeftMarginPx + drop_image->width(),
+ image_size, false));
+ canvas->DrawBitmapInt(*icon,
+ 0, 0, icon->width(), icon->height(),
+ 0, 0, image_size, image_size,
+ false);
+ canvas->DrawBitmapInt(*drop_image,
+ image_size + kDropArrowLeftMarginPx,
+ image_size / 2);
+ [owner_ setButtonImage:gfx::SkBitmapToNSImage(canvas->ExtractBitmap())];
+ }
+
+ // Overridden from ExtensionInfoBarDelegate::DelegateObserver:
+ virtual void OnDelegateDeleted() {
+ delegate_ = NULL;
+ }
+
+ private:
+ // Weak. Owns us.
+ ExtensionInfoBarController* owner_;
+
+ // Weak.
+ ExtensionInfoBarDelegate* delegate_;
+
+ // Loads the extensions's icon on the file thread.
+ ImageLoadingTracker tracker_;
+
+ DISALLOW_COPY_AND_ASSIGN(InfobarBridge);
+};
+
+
+@implementation ExtensionInfoBarController
+
+- (id)initWithDelegate:(InfoBarDelegate*)delegate
+ window:(NSWindow*)window {
+ if ((self = [super initWithDelegate:delegate])) {
+ window_ = window;
+ dropdownButton_.reset([[MenuButton alloc] init]);
+
+ ExtensionHost* extensionHost = delegate_->AsExtensionInfoBarDelegate()->
+ extension_host();
+ contextMenu_.reset([[ExtensionActionContextMenu alloc]
+ initWithExtension:extensionHost->extension()
+ profile:extensionHost->profile()
+ extensionAction:NULL]);
+ // See menu_button.h for documentation on why this is needed.
+ NSMenuItem* dummyItem =
+ [[[NSMenuItem alloc] initWithTitle:@""
+ action:nil
+ keyEquivalent:@""] autorelease];
+ [contextMenu_ insertItem:dummyItem atIndex:0];
+ [dropdownButton_ setAttachedMenu:contextMenu_.get()];
+
+ bridge_.reset(new InfobarBridge(self));
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+- (void)addAdditionalControls {
+ [self removeButtons];
+
+ extensionView_ = delegate_->AsExtensionInfoBarDelegate()->extension_host()->
+ view()->native_view();
+
+ // Add the extension's RenderWidgetHostViewMac to the view hierarchy of the
+ // InfoBar and make sure to place it below the Close button.
+ [infoBarView_ addSubview:extensionView_
+ positioned:NSWindowBelow
+ relativeTo:(NSView*)closeButton_];
+
+ // Add the context menu button to the hierarchy.
+ [dropdownButton_ setShowsBorderOnlyWhileMouseInside:YES];
+ CGFloat buttonY =
+ std::floor(NSMidY([infoBarView_ frame]) - (kButtonHeightPx / 2.0)) +
+ kBottomBorderHeightPx;
+ NSRect buttonFrame = NSMakeRect(
+ kButtonLeftMarginPx, buttonY, kButtonWidthPx, kButtonHeightPx);
+ [dropdownButton_ setFrame:buttonFrame];
+ [dropdownButton_ setAutoresizingMask:NSViewMinYMargin | NSViewMaxYMargin];
+ [infoBarView_ addSubview:dropdownButton_];
+
+ // Because the parent view has a bottom border, account for it during
+ // positioning.
+ NSRect extensionFrame = [extensionView_ frame];
+ extensionFrame.origin.y = kBottomBorderHeightPx;
+
+ [extensionView_ setFrame:extensionFrame];
+ // The extension's native view will only have a height that is non-zero if it
+ // already has been loaded and rendered, which is the case when you switch
+ // back to a tab with an extension infobar within it. The reason this is
+ // needed is because the extension view's frame will not have changed in the
+ // above case, so the NSViewFrameDidChangeNotification registered below will
+ // never fire.
+ if (NSHeight(extensionFrame) > 0.0) {
+ NSSize infoBarSize = [[self view] frame].size;
+ infoBarSize.height = [self clampedExtensionViewHeight] +
+ kBottomBorderHeightPx;
+ [[self view] setFrameSize:infoBarSize];
+ [infoBarView_ setFrameSize:infoBarSize];
+ }
+
+ [self adjustExtensionViewSize];
+
+ // These two notification handlers are here to ensure the width of the
+ // native extension view is the same as the browser window's width and that
+ // the parent infobar view matches the height of the extension's native view.
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(extensionViewFrameChanged)
+ name:NSViewFrameDidChangeNotification
+ object:extensionView_];
+
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(adjustWidthToFitWindow)
+ name:NSWindowDidResizeNotification
+ object:window_];
+}
+
+- (void)extensionViewFrameChanged {
+ [self adjustExtensionViewSize];
+
+ AnimatableView* view = [self animatableView];
+ NSRect infoBarFrame = [view frame];
+ CGFloat newHeight = [self clampedExtensionViewHeight] + kBottomBorderHeightPx;
+ [infoBarView_ setPostsFrameChangedNotifications:NO];
+ infoBarFrame.size.height = newHeight;
+ [infoBarView_ setFrame:infoBarFrame];
+ [infoBarView_ setPostsFrameChangedNotifications:YES];
+ [view animateToNewHeight:newHeight duration:kAnimationDuration];
+}
+
+- (CGFloat)clampedExtensionViewHeight {
+ return std::max(kToolbarMinHeightPx,
+ std::min(NSHeight([extensionView_ frame]), kToolbarMaxHeightPx));
+}
+
+- (void)adjustExtensionViewSize {
+ [extensionView_ setPostsFrameChangedNotifications:NO];
+ NSSize extensionViewSize = [extensionView_ frame].size;
+ extensionViewSize.width = NSWidth([window_ frame]);
+ extensionViewSize.height = [self clampedExtensionViewHeight];
+ [extensionView_ setFrameSize:extensionViewSize];
+ [extensionView_ setPostsFrameChangedNotifications:YES];
+}
+
+- (void)setButtonImage:(NSImage*)image {
+ [dropdownButton_ setImage:image];
+}
+
+@end
+
+InfoBar* ExtensionInfoBarDelegate::CreateInfoBar() {
+ NSWindow* window = [(NSView*)tab_contents_->GetContentNativeView() window];
+ ExtensionInfoBarController* controller =
+ [[ExtensionInfoBarController alloc] initWithDelegate:this
+ window:window];
+ return new InfoBar(controller);
+}
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_prompt_controller.h b/chrome/browser/ui/cocoa/extensions/extension_install_prompt_controller.h
new file mode 100644
index 0000000..6ae5884
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extensions/extension_install_prompt_controller.h
@@ -0,0 +1,62 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_EXTENSION_INSTALL_PROMPT_H_
+#define CHROME_BROWSER_UI_COCOA_EXTENSION_INSTALL_PROMPT_H_
+#pragma once
+
+#include <vector>
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+#include "base/string16.h"
+#include "chrome/browser/extensions/extension_install_ui.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+class Extension;
+class Profile;
+
+// A controller for dialog to let the user install an extension. Created by
+// CrxInstaller.
+@interface ExtensionInstallPromptController : NSWindowController {
+@private
+ IBOutlet NSImageView* iconView_;
+ IBOutlet NSTextField* titleField_;
+ IBOutlet NSTextField* subtitleField_;
+ IBOutlet NSTextField* warningsField_;
+ IBOutlet NSBox* warningsBox_;
+ IBOutlet NSButton* cancelButton_;
+ IBOutlet NSButton* okButton_;
+
+ NSWindow* parentWindow_; // weak
+ Profile* profile_; // weak
+ ExtensionInstallUI::Delegate* delegate_; // weak
+
+ scoped_nsobject<NSString> title_;
+ scoped_nsobject<NSString> warnings_;
+ SkBitmap icon_;
+}
+
+@property (nonatomic, readonly) NSImageView* iconView;
+@property (nonatomic, readonly) NSTextField* titleField;
+@property (nonatomic, readonly) NSTextField* subtitleField;
+@property (nonatomic, readonly) NSTextField* warningsField;
+@property (nonatomic, readonly) NSBox* warningsBox;
+@property (nonatomic, readonly) NSButton* cancelButton;
+@property (nonatomic, readonly) NSButton* okButton;
+
+- (id)initWithParentWindow:(NSWindow*)window
+ profile:(Profile*)profile
+ extension:(const Extension*)extension
+ delegate:(ExtensionInstallUI::Delegate*)delegate
+ icon:(SkBitmap*)bitmap
+ warnings:(const std::vector<string16>&)warnings;
+- (void)runAsModalSheet;
+- (IBAction)cancel:(id)sender;
+- (IBAction)ok:(id)sender;
+
+@end
+
+#endif /* CHROME_BROWSER_UI_COCOA_EXTENSION_INSTALL_PROMPT_H_ */
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_prompt_controller.mm b/chrome/browser/ui/cocoa/extensions/extension_install_prompt_controller.mm
new file mode 100644
index 0000000..e40fcd4
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extensions/extension_install_prompt_controller.mm
@@ -0,0 +1,217 @@
+// 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 "chrome/browser/ui/cocoa/extensions/extension_install_prompt_controller.h"
+
+#include "app/l10n_util.h"
+#include "app/l10n_util_mac.h"
+#include "base/mac_util.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/common/extensions/extension.h"
+#include "grit/generated_resources.h"
+#include "skia/ext/skia_utils_mac.h"
+
+namespace {
+
+// Maximum height we will adjust controls to when trying to accomodate their
+// contents.
+const CGFloat kMaxControlHeight = 400;
+
+// Adjust a control's height so that its content its not clipped. Returns the
+// amount the control's height had to be adjusted.
+CGFloat AdjustControlHeightToFitContent(NSControl* control) {
+ NSRect currentRect = [control frame];
+ NSRect fitRect = currentRect;
+ fitRect.size.height = kMaxControlHeight;
+ CGFloat desiredHeight = [[control cell] cellSizeForBounds:fitRect].height;
+ CGFloat offset = desiredHeight - currentRect.size.height;
+
+ [control setFrameSize:NSMakeSize(currentRect.size.width,
+ currentRect.size.height + offset)];
+ return offset;
+}
+
+// Moves the control vertically by the specified amount.
+void OffsetControlVertically(NSControl* control, CGFloat amount) {
+ NSPoint origin = [control frame].origin;
+ origin.y += amount;
+ [control setFrameOrigin:origin];
+}
+
+}
+
+@implementation ExtensionInstallPromptController
+
+@synthesize iconView = iconView_;
+@synthesize titleField = titleField_;
+@synthesize subtitleField = subtitleField_;
+@synthesize warningsField = warningsField_;
+@synthesize warningsBox= warningsBox_;
+@synthesize cancelButton = cancelButton_;
+@synthesize okButton = okButton_;
+
+- (id)initWithParentWindow:(NSWindow*)window
+ profile:(Profile*)profile
+ extension:(const Extension*)extension
+ delegate:(ExtensionInstallUI::Delegate*)delegate
+ icon:(SkBitmap*)icon
+ warnings:(const std::vector<string16>&)warnings {
+ NSString* nibpath = nil;
+
+ // We use a different XIB in the case of no warnings, that is a little bit
+ // more nicely laid out.
+ if (warnings.empty()) {
+ nibpath = [mac_util::MainAppBundle()
+ pathForResource:@"ExtensionInstallPromptNoWarnings"
+ ofType:@"nib"];
+ } else {
+ nibpath = [mac_util::MainAppBundle()
+ pathForResource:@"ExtensionInstallPrompt"
+ ofType:@"nib"];
+ }
+
+ if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
+ parentWindow_ = window;
+ profile_ = profile;
+ icon_ = *icon;
+ delegate_ = delegate;
+
+ title_.reset(
+ [l10n_util::GetNSStringF(IDS_EXTENSION_INSTALL_PROMPT_HEADING,
+ UTF8ToUTF16(extension->name())) retain]);
+
+ // We display the warnings as a simple text string, separated by newlines.
+ if (!warnings.empty()) {
+ string16 joined_warnings;
+ for (size_t i = 0; i < warnings.size(); ++i) {
+ if (i > 0)
+ joined_warnings += UTF8ToUTF16("\n\n");
+
+ joined_warnings += warnings[i];
+ }
+
+ warnings_.reset(
+ [base::SysUTF16ToNSString(joined_warnings) retain]);
+ }
+ }
+ return self;
+}
+
+- (void)runAsModalSheet {
+ [NSApp beginSheet:[self window]
+ modalForWindow:parentWindow_
+ modalDelegate:self
+ didEndSelector:@selector(didEndSheet:returnCode:contextInfo:)
+ contextInfo:nil];
+}
+
+- (IBAction)cancel:(id)sender {
+ delegate_->InstallUIAbort();
+ [NSApp endSheet:[self window]];
+}
+
+- (IBAction)ok:(id)sender {
+ delegate_->InstallUIProceed();
+ [NSApp endSheet:[self window]];
+}
+
+- (void)awakeFromNib {
+ [titleField_ setStringValue:title_.get()];
+
+ NSImage* image = gfx::SkBitmapToNSImage(icon_);
+ [iconView_ setImage:image];
+
+ // Make sure we're the window's delegate as set in the nib.
+ DCHECK_EQ(self, static_cast<ExtensionInstallPromptController*>(
+ [[self window] delegate]));
+
+ // If there are any warnings, then we have to do some special layout.
+ if ([warnings_.get() length] > 0) {
+ [warningsField_ setStringValue:warnings_.get()];
+
+ // The dialog is laid out in the NIB exactly how we want it assuming that
+ // each label fits on one line. However, for each label, we want to allow
+ // wrapping onto multiple lines. So we accumulate an offset by measuring how
+ // big each label wants to be, and comparing it to how bit it actually is.
+ // Then we shift each label down and resize by the appropriate amount, then
+ // finally resize the window.
+ CGFloat totalOffset = 0.0;
+
+ // Text fields.
+ totalOffset += AdjustControlHeightToFitContent(titleField_);
+ OffsetControlVertically(titleField_, -totalOffset);
+
+ totalOffset += AdjustControlHeightToFitContent(subtitleField_);
+ OffsetControlVertically(subtitleField_, -totalOffset);
+
+ CGFloat warningsOffset = AdjustControlHeightToFitContent(warningsField_);
+ OffsetControlVertically(warningsField_, -warningsOffset);
+ totalOffset += warningsOffset;
+
+ NSRect warningsBoxRect = [warningsBox_ frame];
+ warningsBoxRect.origin.y -= totalOffset;
+ warningsBoxRect.size.height += warningsOffset;
+ [warningsBox_ setFrame:warningsBoxRect];
+
+ // buttons are positioned automatically in the XIB.
+
+ // Finally, adjust the window size.
+ NSRect currentRect = [[self window] frame];
+ [[self window] setFrame:NSMakeRect(currentRect.origin.x,
+ currentRect.origin.y - totalOffset,
+ currentRect.size.width,
+ currentRect.size.height + totalOffset)
+ display:NO];
+ }
+}
+
+- (void)didEndSheet:(NSWindow*)sheet
+ returnCode:(int)returnCode
+ contextInfo:(void*)contextInfo {
+ [sheet close];
+}
+
+- (void)windowWillClose:(NSNotification*)notification {
+ [self autorelease];
+}
+
+@end // ExtensionInstallPromptController
+
+
+void ExtensionInstallUI::ShowExtensionInstallUIPrompt2Impl(
+ Profile* profile,
+ Delegate* delegate,
+ const Extension* extension,
+ SkBitmap* icon,
+ const std::vector<string16>& warnings) {
+ Browser* browser = BrowserList::GetLastActiveWithProfile(profile);
+ if (!browser) {
+ delegate->InstallUIAbort();
+ return;
+ }
+
+ BrowserWindow* window = browser->window();
+ if (!window) {
+ delegate->InstallUIAbort();
+ return;
+ }
+
+ gfx::NativeWindow native_window = window->GetNativeHandle();
+
+ ExtensionInstallPromptController* controller =
+ [[ExtensionInstallPromptController alloc]
+ initWithParentWindow:native_window
+ profile:profile
+ extension:extension
+ delegate:delegate
+ icon:icon
+ warnings:warnings];
+
+ [controller runAsModalSheet];
+}
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_prompt_controller_unittest.mm b/chrome/browser/ui/cocoa/extensions/extension_install_prompt_controller_unittest.mm
new file mode 100644
index 0000000..225aad6
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extensions/extension_install_prompt_controller_unittest.mm
@@ -0,0 +1,286 @@
+// 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 "base/file_path.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#import "chrome/browser/extensions/extension_install_ui.h"
+#import "chrome/browser/ui/cocoa/extensions/extension_install_prompt_controller.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/json_value_serializer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "webkit/glue/image_decoder.h"
+
+
+// Base class for our tests.
+class ExtensionInstallPromptControllerTest : public CocoaTest {
+public:
+ ExtensionInstallPromptControllerTest() {
+ PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_);
+ test_data_dir_ = test_data_dir_.AppendASCII("extensions")
+ .AppendASCII("install_prompt");
+
+ LoadIcon();
+ LoadExtension();
+ }
+
+ protected:
+ void LoadIcon() {
+ std::string file_contents;
+ file_util::ReadFileToString(test_data_dir_.AppendASCII("icon.png"),
+ &file_contents);
+
+ webkit_glue::ImageDecoder decoder;
+ icon_ = decoder.Decode(
+ reinterpret_cast<const unsigned char*>(file_contents.c_str()),
+ file_contents.length());
+ }
+
+ void LoadExtension() {
+ FilePath path = test_data_dir_.AppendASCII("extension.json");
+
+ std::string error;
+ JSONFileValueSerializer serializer(path);
+ scoped_ptr<DictionaryValue> value(static_cast<DictionaryValue*>(
+ serializer.Deserialize(NULL, &error)));
+ if (!value.get()) {
+ LOG(ERROR) << error;
+ return;
+ }
+
+ extension_ = Extension::Create(
+ path.DirName(), Extension::INVALID, *value, false, &error);
+ if (!extension_.get()) {
+ LOG(ERROR) << error;
+ return;
+ }
+ }
+
+ BrowserTestHelper helper_;
+ FilePath test_data_dir_;
+ SkBitmap icon_;
+ scoped_refptr<Extension> extension_;
+};
+
+
+// Mock out the ExtensionInstallUI::Delegate interface so we can ensure the
+// dialog is interacting with it correctly.
+class MockExtensionInstallUIDelegate : public ExtensionInstallUI::Delegate {
+ public:
+ MockExtensionInstallUIDelegate()
+ : proceed_count_(0),
+ abort_count_(0) {}
+
+ // ExtensionInstallUI::Delegate overrides.
+ virtual void InstallUIProceed() {
+ proceed_count_++;
+ }
+
+ virtual void InstallUIAbort() {
+ abort_count_++;
+ }
+
+ int proceed_count() { return proceed_count_; }
+ int abort_count() { return abort_count_; }
+
+ protected:
+ int proceed_count_;
+ int abort_count_;
+};
+
+// Test that we can load the two kinds of prompts correctly, that the outlets
+// are hooked up, and that the dialog calls cancel when cancel is pressed.
+TEST_F(ExtensionInstallPromptControllerTest, BasicsNormalCancel) {
+ scoped_ptr<MockExtensionInstallUIDelegate> delegate(
+ new MockExtensionInstallUIDelegate);
+
+ std::vector<string16> warnings;
+ warnings.push_back(UTF8ToUTF16("warning 1"));
+
+ scoped_nsobject<ExtensionInstallPromptController>
+ controller([[ExtensionInstallPromptController alloc]
+ initWithParentWindow:test_window()
+ profile:helper_.profile()
+ extension:extension_.get()
+ delegate:delegate.get()
+ icon:&icon_
+ warnings:warnings]);
+
+ [controller window]; // force nib load
+
+ // Test the right nib loaded.
+ EXPECT_NSEQ(@"ExtensionInstallPrompt", [controller windowNibName]);
+
+ // Check all the controls.
+ // Make sure everything is non-nil, and that the fields that are
+ // auto-translated don't start with a caret (that would indicate that they
+ // were not translated).
+ EXPECT_TRUE([controller iconView] != nil);
+ EXPECT_TRUE([[controller iconView] image] != nil);
+
+ EXPECT_TRUE([controller titleField] != nil);
+ EXPECT_NE(0u, [[[controller titleField] stringValue] length]);
+
+ EXPECT_TRUE([controller subtitleField] != nil);
+ EXPECT_NE(0u, [[[controller subtitleField] stringValue] length]);
+ EXPECT_NE('^', [[[controller subtitleField] stringValue] characterAtIndex:0]);
+
+ EXPECT_TRUE([controller warningsField] != nil);
+ EXPECT_NSEQ([[controller warningsField] stringValue],
+ base::SysUTF16ToNSString(warnings[0]));
+
+ EXPECT_TRUE([controller warningsBox] != nil);
+
+ EXPECT_TRUE([controller cancelButton] != nil);
+ EXPECT_NE(0u, [[[controller cancelButton] stringValue] length]);
+ EXPECT_NE('^', [[[controller cancelButton] stringValue] characterAtIndex:0]);
+
+ EXPECT_TRUE([controller okButton] != nil);
+ EXPECT_NE(0u, [[[controller okButton] stringValue] length]);
+ EXPECT_NE('^', [[[controller okButton] stringValue] characterAtIndex:0]);
+
+ // Test that cancel calls our delegate.
+ [controller cancel:nil];
+ EXPECT_EQ(1, delegate->abort_count());
+ EXPECT_EQ(0, delegate->proceed_count());
+}
+
+
+TEST_F(ExtensionInstallPromptControllerTest, BasicsNormalOK) {
+ scoped_ptr<MockExtensionInstallUIDelegate> delegate(
+ new MockExtensionInstallUIDelegate);
+
+ std::vector<string16> warnings;
+ warnings.push_back(UTF8ToUTF16("warning 1"));
+
+ scoped_nsobject<ExtensionInstallPromptController>
+ controller([[ExtensionInstallPromptController alloc]
+ initWithParentWindow:test_window()
+ profile:helper_.profile()
+ extension:extension_.get()
+ delegate:delegate.get()
+ icon:&icon_
+ warnings:warnings]);
+
+ [controller window]; // force nib load
+ [controller ok:nil];
+
+ EXPECT_EQ(0, delegate->abort_count());
+ EXPECT_EQ(1, delegate->proceed_count());
+}
+
+// Test that controls get repositioned when there are two warnings vs one
+// warning.
+TEST_F(ExtensionInstallPromptControllerTest, MultipleWarnings) {
+ scoped_ptr<MockExtensionInstallUIDelegate> delegate1(
+ new MockExtensionInstallUIDelegate);
+ scoped_ptr<MockExtensionInstallUIDelegate> delegate2(
+ new MockExtensionInstallUIDelegate);
+
+ std::vector<string16> one_warning;
+ one_warning.push_back(UTF8ToUTF16("warning 1"));
+
+ std::vector<string16> two_warnings;
+ two_warnings.push_back(UTF8ToUTF16("warning 1"));
+ two_warnings.push_back(UTF8ToUTF16("warning 2"));
+
+ scoped_nsobject<ExtensionInstallPromptController>
+ controller1([[ExtensionInstallPromptController alloc]
+ initWithParentWindow:test_window()
+ profile:helper_.profile()
+ extension:extension_.get()
+ delegate:delegate1.get()
+ icon:&icon_
+ warnings:one_warning]);
+
+ [controller1 window]; // force nib load
+
+ scoped_nsobject<ExtensionInstallPromptController>
+ controller2([[ExtensionInstallPromptController alloc]
+ initWithParentWindow:test_window()
+ profile:helper_.profile()
+ extension:extension_.get()
+ delegate:delegate2.get()
+ icon:&icon_
+ warnings:two_warnings]);
+
+ [controller2 window]; // force nib load
+
+ // Test control positioning. We don't test exact positioning because we don't
+ // want this to depend on string details and localization. But we do know the
+ // relative effect that adding a second warning should have on the layout.
+ ASSERT_LT([[controller1 window] frame].size.height,
+ [[controller2 window] frame].size.height);
+
+ ASSERT_LT([[controller1 warningsField] frame].size.height,
+ [[controller2 warningsField] frame].size.height);
+
+ ASSERT_LT([[controller1 warningsBox] frame].size.height,
+ [[controller2 warningsBox] frame].size.height);
+
+ ASSERT_EQ([[controller1 warningsBox] frame].origin.y,
+ [[controller2 warningsBox] frame].origin.y);
+
+ ASSERT_LT([[controller1 subtitleField] frame].origin.y,
+ [[controller2 subtitleField] frame].origin.y);
+
+ ASSERT_LT([[controller1 titleField] frame].origin.y,
+ [[controller2 titleField] frame].origin.y);
+}
+
+// Test that we can load the skinny prompt correctly, and that the outlets are
+// are hooked up.
+TEST_F(ExtensionInstallPromptControllerTest, BasicsSkinny) {
+ scoped_ptr<MockExtensionInstallUIDelegate> delegate(
+ new MockExtensionInstallUIDelegate);
+
+ // No warnings should trigger skinny prompt.
+ std::vector<string16> warnings;
+
+ scoped_nsobject<ExtensionInstallPromptController>
+ controller([[ExtensionInstallPromptController alloc]
+ initWithParentWindow:test_window()
+ profile:helper_.profile()
+ extension:extension_.get()
+ delegate:delegate.get()
+ icon:&icon_
+ warnings:warnings]);
+
+ [controller window]; // force nib load
+
+ // Test the right nib loaded.
+ EXPECT_NSEQ(@"ExtensionInstallPromptNoWarnings", [controller windowNibName]);
+
+ // Check all the controls.
+ // In the skinny prompt, only the icon, title and buttons are non-nill.
+ // Everything else is nil.
+ EXPECT_TRUE([controller iconView] != nil);
+ EXPECT_TRUE([[controller iconView] image] != nil);
+
+ EXPECT_TRUE([controller titleField] != nil);
+ EXPECT_NE(0u, [[[controller titleField] stringValue] length]);
+
+ EXPECT_TRUE([controller cancelButton] != nil);
+ EXPECT_NE(0u, [[[controller cancelButton] stringValue] length]);
+ EXPECT_NE('^', [[[controller cancelButton] stringValue] characterAtIndex:0]);
+
+ EXPECT_TRUE([controller okButton] != nil);
+ EXPECT_NE(0u, [[[controller okButton] stringValue] length]);
+ EXPECT_NE('^', [[[controller okButton] stringValue] characterAtIndex:0]);
+
+ EXPECT_TRUE([controller subtitleField] == nil);
+ EXPECT_TRUE([controller warningsField] == nil);
+ EXPECT_TRUE([controller warningsBox] == nil);
+}
diff --git a/chrome/browser/ui/cocoa/extensions/extension_popup_controller.h b/chrome/browser/ui/cocoa/extensions/extension_popup_controller.h
new file mode 100644
index 0000000..d3fb422
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extensions/extension_popup_controller.h
@@ -0,0 +1,99 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_EXTENSIONS_EXTENSION_POPUP_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_EXTENSIONS_EXTENSION_POPUP_CONTROLLER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/mac/cocoa_protocols.h"
+#import "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/ui/cocoa/info_bubble_view.h"
+#include "googleurl/src/gurl.h"
+
+
+class Browser;
+class DevtoolsNotificationBridge;
+class ExtensionHost;
+@class InfoBubbleWindow;
+class NotificationRegistrar;
+
+// This controller manages a single browser action popup that can appear once a
+// user has clicked on a browser action button. It instantiates the extension
+// popup view showing the content and resizes the window to accomodate any size
+// changes as they occur.
+//
+// There can only be one browser action popup open at a time, so a static
+// variable holds a reference to the current popup.
+@interface ExtensionPopupController : NSWindowController<NSWindowDelegate> {
+ @private
+ // The native extension view retrieved from the extension host. Weak.
+ NSView* extensionView_;
+
+ // The popup's parent window. Weak.
+ NSWindow* parentWindow_;
+
+ // Where the window is anchored. Right now it's the bottom center of the
+ // browser action button.
+ NSPoint anchor_;
+
+ // The current frame of the extension view. Cached to prevent setting the
+ // frame if the size hasn't changed.
+ NSRect extensionFrame_;
+
+ // The extension host object.
+ scoped_ptr<ExtensionHost> host_;
+
+ scoped_ptr<NotificationRegistrar> registrar_;
+ scoped_ptr<DevtoolsNotificationBridge> notificationBridge_;
+
+ // Whether the popup has a devtools window attached to it.
+ BOOL beingInspected_;
+}
+
+// Returns the ExtensionHost object associated with this popup.
+- (ExtensionHost*)extensionHost;
+
+// Starts the process of showing the given popup URL. Instantiates an
+// ExtensionPopupController with the parent window retrieved from |browser|, a
+// host for the popup created by the extension process manager specific to the
+// browser profile and the remaining arguments |anchoredAt| and |arrowLocation|.
+// |anchoredAt| is expected to be in the window's coordinates at the bottom
+// center of the browser action button.
+// The actual display of the popup is delayed until the page contents finish
+// loading in order to minimize UI flashing and resizing.
+// Passing YES to |devMode| will launch the webkit inspector for the popup,
+// and prevent the popup from closing when focus is lost. It will be closed
+// after the inspector is closed, or another popup is opened.
++ (ExtensionPopupController*)showURL:(GURL)url
+ inBrowser:(Browser*)browser
+ anchoredAt:(NSPoint)anchoredAt
+ arrowLocation:(info_bubble::BubbleArrowLocation)
+ arrowLocation
+ devMode:(BOOL)devMode;
+
+// Returns the controller used to display the popup being shown. If no popup is
+// currently open, then nil is returned. Static because only one extension popup
+// window can be open at a time.
++ (ExtensionPopupController*)popup;
+
+// Whether the popup is in the process of closing (via Core Animation).
+- (BOOL)isClosing;
+
+// Show the dev tools attached to the popup.
+- (void)showDevTools;
+@end
+
+@interface ExtensionPopupController(TestingAPI)
+// Returns a weak pointer to the current popup's view.
+- (NSView*)view;
+// Returns the minimum allowed size for an extension popup.
++ (NSSize)minPopupSize;
+// Returns the maximum allowed size for an extension popup.
++ (NSSize)maxPopupSize;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_EXTENSIONS_EXTENSION_POPUP_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/extensions/extension_popup_controller.mm b/chrome/browser/ui/cocoa/extensions/extension_popup_controller.mm
new file mode 100644
index 0000000..7404c3d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extensions/extension_popup_controller.mm
@@ -0,0 +1,338 @@
+// 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 "chrome/browser/ui/cocoa/extensions/extension_popup_controller.h"
+
+#include <algorithm>
+
+#include "chrome/browser/debugger/devtools_manager.h"
+#include "chrome/browser/extensions/extension_host.h"
+#include "chrome/browser/extensions/extension_process_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#import "chrome/browser/ui/cocoa/browser_window_cocoa.h"
+#import "chrome/browser/ui/cocoa/extension_view_mac.h"
+#import "chrome/browser/ui/cocoa/info_bubble_window.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_source.h"
+
+namespace {
+// The duration for any animations that might be invoked by this controller.
+const NSTimeInterval kAnimationDuration = 0.2;
+
+// There should only be one extension popup showing at one time. Keep a
+// reference to it here.
+static ExtensionPopupController* gPopup;
+
+// Given a value and a rage, clamp the value into the range.
+CGFloat Clamp(CGFloat value, CGFloat min, CGFloat max) {
+ return std::max(min, std::min(max, value));
+}
+
+} // namespace
+
+class DevtoolsNotificationBridge : public NotificationObserver {
+ public:
+ explicit DevtoolsNotificationBridge(ExtensionPopupController* controller)
+ : controller_(controller) {}
+
+ void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ switch (type.value) {
+ case NotificationType::EXTENSION_HOST_DID_STOP_LOADING: {
+ if (Details<ExtensionHost>([controller_ extensionHost]) == details)
+ [controller_ showDevTools];
+ break;
+ }
+ case NotificationType::DEVTOOLS_WINDOW_CLOSING: {
+ RenderViewHost* rvh = [controller_ extensionHost]->render_view_host();
+ if (Details<RenderViewHost>(rvh) == details)
+ // Allow the devtools to finish detaching before we close the popup
+ [controller_ performSelector:@selector(close)
+ withObject:nil
+ afterDelay:0.0];
+ break;
+ }
+ default: {
+ NOTREACHED() << "Received unexpected notification";
+ break;
+ }
+ };
+ }
+
+ private:
+ ExtensionPopupController* controller_;
+};
+
+@interface ExtensionPopupController(Private)
+// Callers should be using the public static method for initialization.
+// NOTE: This takes ownership of |host|.
+- (id)initWithHost:(ExtensionHost*)host
+ parentWindow:(NSWindow*)parentWindow
+ anchoredAt:(NSPoint)anchoredAt
+ arrowLocation:(info_bubble::BubbleArrowLocation)arrowLocation
+ devMode:(BOOL)devMode;
+
+// Called when the extension's hosted NSView has been resized.
+- (void)extensionViewFrameChanged;
+@end
+
+@implementation ExtensionPopupController
+
+- (id)initWithHost:(ExtensionHost*)host
+ parentWindow:(NSWindow*)parentWindow
+ anchoredAt:(NSPoint)anchoredAt
+ arrowLocation:(info_bubble::BubbleArrowLocation)arrowLocation
+ devMode:(BOOL)devMode {
+
+ parentWindow_ = parentWindow;
+ anchor_ = [parentWindow convertBaseToScreen:anchoredAt];
+ host_.reset(host);
+ beingInspected_ = devMode;
+
+ scoped_nsobject<InfoBubbleView> view([[InfoBubbleView alloc] init]);
+ if (!view.get())
+ return nil;
+ [view setArrowLocation:arrowLocation];
+
+ host->view()->set_is_toolstrip(NO);
+
+ extensionView_ = host->view()->native_view();
+ NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+ [center addObserver:self
+ selector:@selector(extensionViewFrameChanged)
+ name:NSViewFrameDidChangeNotification
+ object:extensionView_];
+
+ // Watch to see if the parent window closes, and if so, close this one.
+ [center addObserver:self
+ selector:@selector(parentWindowWillClose:)
+ name:NSWindowWillCloseNotification
+ object:parentWindow_];
+
+ [view addSubview:extensionView_];
+ scoped_nsobject<InfoBubbleWindow> window(
+ [[InfoBubbleWindow alloc]
+ initWithContentRect:NSZeroRect
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:YES]);
+ if (!window.get())
+ return nil;
+
+ [window setDelegate:self];
+ [window setContentView:view];
+ self = [super initWithWindow:window];
+ if (beingInspected_) {
+ // Listen for the the devtools window closing.
+ notificationBridge_.reset(new DevtoolsNotificationBridge(self));
+ registrar_.reset(new NotificationRegistrar);
+ registrar_->Add(notificationBridge_.get(),
+ NotificationType::DEVTOOLS_WINDOW_CLOSING,
+ Source<Profile>(host->profile()));
+ registrar_->Add(notificationBridge_.get(),
+ NotificationType::EXTENSION_HOST_DID_STOP_LOADING,
+ Source<Profile>(host->profile()));
+ }
+ return self;
+}
+
+- (void)showDevTools {
+ DevToolsManager::GetInstance()->OpenDevToolsWindow(host_->render_view_host());
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+- (void)parentWindowWillClose:(NSNotification*)notification {
+ [self close];
+}
+
+- (void)windowWillClose:(NSNotification *)notification {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [gPopup autorelease];
+ gPopup = nil;
+}
+
+- (void)windowDidResignKey:(NSNotification *)notification {
+ NSWindow* window = [self window];
+ DCHECK_EQ([notification object], window);
+ // If the window isn't visible, it is already closed, and this notification
+ // has been sent as part of the closing operation, so no need to close.
+ if ([window isVisible] && !beingInspected_) {
+ [self close];
+ }
+}
+
+- (void)close {
+ [parentWindow_ removeChildWindow:[self window]];
+
+ // No longer have a parent window, so nil out the pointer and deregister for
+ // notifications.
+ NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+ [center removeObserver:self
+ name:NSWindowWillCloseNotification
+ object:parentWindow_];
+ parentWindow_ = nil;
+ [super close];
+}
+
+- (BOOL)isClosing {
+ return [static_cast<InfoBubbleWindow*>([self window]) isClosing];
+}
+
+- (ExtensionHost*)extensionHost {
+ return host_.get();
+}
+
++ (ExtensionPopupController*)showURL:(GURL)url
+ inBrowser:(Browser*)browser
+ anchoredAt:(NSPoint)anchoredAt
+ arrowLocation:(info_bubble::BubbleArrowLocation)
+ arrowLocation
+ devMode:(BOOL)devMode {
+ DCHECK([NSThread isMainThread]);
+ DCHECK(browser);
+ if (!browser)
+ return nil;
+
+ ExtensionProcessManager* manager =
+ browser->profile()->GetExtensionProcessManager();
+ DCHECK(manager);
+ if (!manager)
+ return nil;
+
+ ExtensionHost* host = manager->CreatePopup(url, browser);
+ DCHECK(host);
+ if (!host)
+ return nil;
+
+ // Make absolutely sure that no popups are leaked.
+ if (gPopup) {
+ if ([[gPopup window] isVisible])
+ [gPopup close];
+
+ [gPopup autorelease];
+ gPopup = nil;
+ }
+ DCHECK(!gPopup);
+
+ // Takes ownership of |host|. Also will autorelease itself when the popup is
+ // closed, so no need to do that here.
+ gPopup = [[ExtensionPopupController alloc]
+ initWithHost:host
+ parentWindow:browser->window()->GetNativeHandle()
+ anchoredAt:anchoredAt
+ arrowLocation:arrowLocation
+ devMode:devMode];
+ return gPopup;
+}
+
++ (ExtensionPopupController*)popup {
+ return gPopup;
+}
+
+- (void)extensionViewFrameChanged {
+ // If there are no changes in the width or height of the frame, then ignore.
+ if (NSEqualSizes([extensionView_ frame].size, extensionFrame_.size))
+ return;
+
+ extensionFrame_ = [extensionView_ frame];
+ // Constrain the size of the view.
+ [extensionView_ setFrameSize:NSMakeSize(
+ Clamp(NSWidth(extensionFrame_),
+ ExtensionViewMac::kMinWidth,
+ ExtensionViewMac::kMaxWidth),
+ Clamp(NSHeight(extensionFrame_),
+ ExtensionViewMac::kMinHeight,
+ ExtensionViewMac::kMaxHeight))];
+
+ // Pad the window by half of the rounded corner radius to prevent the
+ // extension's view from bleeding out over the corners.
+ CGFloat inset = info_bubble::kBubbleCornerRadius / 2.0;
+ [extensionView_ setFrameOrigin:NSMakePoint(inset, inset)];
+
+ NSRect frame = [extensionView_ frame];
+ frame.size.height += info_bubble::kBubbleArrowHeight +
+ info_bubble::kBubbleCornerRadius;
+ frame.size.width += info_bubble::kBubbleCornerRadius;
+ frame = [extensionView_ convertRectToBase:frame];
+ // Adjust the origin according to the height and width so that the arrow is
+ // positioned correctly at the middle and slightly down from the button.
+ NSPoint windowOrigin = anchor_;
+ NSSize offsets = NSMakeSize(info_bubble::kBubbleArrowXOffset +
+ info_bubble::kBubbleArrowWidth / 2.0,
+ info_bubble::kBubbleArrowHeight / 2.0);
+ offsets = [extensionView_ convertSize:offsets toView:nil];
+ windowOrigin.x -= NSWidth(frame) - offsets.width;
+ windowOrigin.y -= NSHeight(frame) - offsets.height;
+ frame.origin = windowOrigin;
+
+ // Is the window still animating in? If so, then cancel that and create a new
+ // animation setting the opacity and new frame value. Otherwise the current
+ // animation will continue after this frame is set, reverting the frame to
+ // what it was when the animation started.
+ NSWindow* window = [self window];
+ if ([window isVisible] && [[window animator] alphaValue] < 1.0) {
+ [NSAnimationContext beginGrouping];
+ [[NSAnimationContext currentContext] setDuration:kAnimationDuration];
+ [[window animator] setAlphaValue:1.0];
+ [[window animator] setFrame:frame display:YES];
+ [NSAnimationContext endGrouping];
+ } else {
+ [window setFrame:frame display:YES];
+ }
+
+ // A NSViewFrameDidChangeNotification won't be sent until the extension view
+ // content is loaded. The window is hidden on init, so show it the first time
+ // the notification is fired (and consequently the view contents have loaded).
+ if (![window isVisible]) {
+ [self showWindow:self];
+ }
+}
+
+// We want this to be a child of a browser window. addChildWindow: (called from
+// this function) will bring the window on-screen; unfortunately,
+// [NSWindowController showWindow:] will also bring it on-screen (but will cause
+// unexpected changes to the window's position). We cannot have an
+// addChildWindow: and a subsequent showWindow:. Thus, we have our own version.
+- (void)showWindow:(id)sender {
+ [parentWindow_ addChildWindow:[self window] ordered:NSWindowAbove];
+ [[self window] makeKeyAndOrderFront:self];
+}
+
+- (void)windowDidResize:(NSNotification*)notification {
+ // Let the extension view know, so that it can tell plugins.
+ if (host_->view())
+ host_->view()->WindowFrameChanged();
+}
+
+- (void)windowDidMove:(NSNotification*)notification {
+ // Let the extension view know, so that it can tell plugins.
+ if (host_->view())
+ host_->view()->WindowFrameChanged();
+}
+
+// Private (TestingAPI)
+- (NSView*)view {
+ return extensionView_;
+}
+
+// Private (TestingAPI)
++ (NSSize)minPopupSize {
+ NSSize minSize = {ExtensionViewMac::kMinWidth, ExtensionViewMac::kMinHeight};
+ return minSize;
+}
+
+// Private (TestingAPI)
++ (NSSize)maxPopupSize {
+ NSSize maxSize = {ExtensionViewMac::kMaxWidth, ExtensionViewMac::kMaxHeight};
+ return maxSize;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/extensions/extension_popup_controller_unittest.mm b/chrome/browser/ui/cocoa/extensions/extension_popup_controller_unittest.mm
new file mode 100644
index 0000000..992dd2c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/extensions/extension_popup_controller_unittest.mm
@@ -0,0 +1,99 @@
+// Copyright (c) 2009 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/message_loop.h"
+#include "base/scoped_nsobject.h"
+#include "chrome/browser/extensions/extension_pref_store.h"
+#include "chrome/browser/extensions/extension_prefs.h"
+#include "chrome/browser/extensions/extension_process_manager.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/extensions/extension_popup_controller.h"
+#include "chrome/test/testing_profile.h"
+
+namespace {
+
+class ExtensionTestingProfile : public TestingProfile {
+ public:
+ ExtensionTestingProfile() {}
+
+ FilePath GetExtensionsInstallDir() {
+ return GetPath().AppendASCII(ExtensionService::kInstallDirectoryName);
+ }
+
+ void InitExtensionProfile() {
+ DCHECK(!GetExtensionProcessManager());
+ DCHECK(!GetExtensionService());
+
+ manager_.reset(ExtensionProcessManager::Create(this));
+ ExtensionPrefStore* pref_store = new ExtensionPrefStore;
+ extension_prefs_.reset(new ExtensionPrefs(GetPrefs(),
+ GetExtensionsInstallDir(),
+ pref_store));
+ service_ = new ExtensionService(this,
+ CommandLine::ForCurrentProcess(),
+ GetExtensionsInstallDir(),
+ extension_prefs_.get(),
+ false);
+ service_->set_extensions_enabled(true);
+ service_->set_show_extensions_prompts(false);
+ service_->ClearProvidersForTesting();
+ service_->Init();
+ }
+
+ void ShutdownExtensionProfile() {
+ manager_.reset();
+ service_ = NULL;
+ extension_prefs_.reset();
+ }
+
+ virtual ExtensionProcessManager* GetExtensionProcessManager() {
+ return manager_.get();
+ }
+
+ virtual ExtensionService* GetExtensionService() {
+ return service_.get();
+ }
+
+ private:
+ scoped_ptr<ExtensionProcessManager> manager_;
+ scoped_ptr<ExtensionPrefs> extension_prefs_;
+ scoped_refptr<ExtensionService> service_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionTestingProfile);
+};
+
+class ExtensionPopupControllerTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ profile_.reset(new ExtensionTestingProfile());
+ profile_->InitExtensionProfile();
+ browser_.reset(new Browser(Browser::TYPE_NORMAL, profile_.get()));
+ [ExtensionPopupController showURL:GURL("http://google.com")
+ inBrowser:browser_.get()
+ anchoredAt:NSZeroPoint
+ arrowLocation:info_bubble::kTopRight
+ devMode:NO];
+ }
+ virtual void TearDown() {
+ profile_->ShutdownExtensionProfile();
+ [[ExtensionPopupController popup] close];
+ CocoaTest::TearDown();
+ }
+
+ protected:
+ scoped_ptr<Browser> browser_;
+ scoped_ptr<ExtensionTestingProfile> profile_;
+};
+
+TEST_F(ExtensionPopupControllerTest, DISABLED_Basics) {
+ // TODO(andybons): Better mechanisms for mocking out the extensions service
+ // and extensions for easy testing need to be implemented.
+ // http://crbug.com/28316
+ EXPECT_TRUE([ExtensionPopupController popup]);
+}
+
+} // namespace
diff --git a/chrome/browser/cocoa/external_protocol_dialog.h b/chrome/browser/ui/cocoa/external_protocol_dialog.h
index 224c280..224c280 100644
--- a/chrome/browser/cocoa/external_protocol_dialog.h
+++ b/chrome/browser/ui/cocoa/external_protocol_dialog.h
diff --git a/chrome/browser/ui/cocoa/external_protocol_dialog.mm b/chrome/browser/ui/cocoa/external_protocol_dialog.mm
new file mode 100644
index 0000000..e72394b
--- /dev/null
+++ b/chrome/browser/ui/cocoa/external_protocol_dialog.mm
@@ -0,0 +1,153 @@
+// 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 "chrome/browser/ui/cocoa/external_protocol_dialog.h"
+
+#include "app/l10n_util_mac.h"
+#include "app/text_elider.h"
+#include "base/message_loop.h"
+#include "base/metrics/histogram.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/external_protocol_handler.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// ExternalProtocolHandler
+
+// static
+void ExternalProtocolHandler::RunExternalProtocolDialog(
+ const GURL& url, int render_process_host_id, int routing_id) {
+ [[ExternalProtocolDialogController alloc] initWithGURL:&url];
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ExternalProtocolDialogController
+
+@interface ExternalProtocolDialogController(Private)
+- (void)alertEnded:(NSAlert *)alert
+ returnCode:(int)returnCode
+ contextInfo:(void*)contextInfo;
+- (string16)appNameForProtocol;
+@end
+
+@implementation ExternalProtocolDialogController
+- (id)initWithGURL:(const GURL*)url {
+ DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type());
+
+ url_ = *url;
+ creation_time_ = base::Time::Now();
+
+ string16 appName = [self appNameForProtocol];
+ if (appName.length() == 0) {
+ // No registered apps for this protocol; give up and go home.
+ [self autorelease];
+ return nil;
+ }
+
+ alert_ = [[NSAlert alloc] init];
+
+ [alert_ setMessageText:
+ l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_TITLE)];
+
+ NSButton* allowButton = [alert_ addButtonWithTitle:
+ l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_OK_BUTTON_TEXT)];
+ [allowButton setKeyEquivalent:@""]; // disallow as default
+ [alert_ addButtonWithTitle:
+ l10n_util::GetNSStringWithFixup(
+ IDS_EXTERNAL_PROTOCOL_CANCEL_BUTTON_TEXT)];
+
+ const int kMaxUrlWithoutSchemeSize = 256;
+ std::wstring elided_url_without_scheme;
+ gfx::ElideString(ASCIIToWide(url_.possibly_invalid_spec()),
+ kMaxUrlWithoutSchemeSize, &elided_url_without_scheme);
+
+ NSString* urlString = l10n_util::GetNSStringFWithFixup(
+ IDS_EXTERNAL_PROTOCOL_INFORMATION,
+ ASCIIToUTF16(url_.scheme() + ":"),
+ WideToUTF16(elided_url_without_scheme));
+ NSString* appString = l10n_util::GetNSStringFWithFixup(
+ IDS_EXTERNAL_PROTOCOL_APPLICATION_TO_LAUNCH,
+ appName);
+ NSString* warningString =
+ l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_WARNING);
+ NSString* informativeText =
+ [NSString stringWithFormat:@"%@\n\n%@\n\n%@",
+ urlString,
+ appString,
+ warningString];
+
+ [alert_ setInformativeText:informativeText];
+
+ [alert_ setShowsSuppressionButton:YES];
+ [[alert_ suppressionButton] setTitle:
+ l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_CHECKBOX_TEXT)];
+
+ [alert_ beginSheetModalForWindow:nil // nil here makes it app-modal
+ modalDelegate:self
+ didEndSelector:@selector(alertEnded:returnCode:contextInfo:)
+ contextInfo:nil];
+
+ return self;
+}
+
+- (void)dealloc {
+ [alert_ release];
+
+ [super dealloc];
+}
+
+- (void)alertEnded:(NSAlert *)alert
+ returnCode:(int)returnCode
+ contextInfo:(void*)contextInfo {
+ ExternalProtocolHandler::BlockState blockState =
+ ExternalProtocolHandler::UNKNOWN;
+ switch (returnCode) {
+ case NSAlertFirstButtonReturn:
+ blockState = ExternalProtocolHandler::DONT_BLOCK;
+ break;
+ case NSAlertSecondButtonReturn:
+ blockState = ExternalProtocolHandler::BLOCK;
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ // Set the "don't warn me again" info.
+ if ([[alert_ suppressionButton] state] == NSOnState)
+ ExternalProtocolHandler::SetBlockState(url_.scheme(), blockState);
+
+ if (blockState == ExternalProtocolHandler::DONT_BLOCK) {
+ UMA_HISTOGRAM_LONG_TIMES("clickjacking.launch_url",
+ base::Time::Now() - creation_time_);
+
+ ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(url_);
+ }
+
+ [self autorelease];
+}
+
+- (string16)appNameForProtocol {
+ NSURL* url = [NSURL URLWithString:
+ base::SysUTF8ToNSString(url_.possibly_invalid_spec())];
+ CFURLRef openingApp = NULL;
+ OSStatus status = LSGetApplicationForURL((CFURLRef)url,
+ kLSRolesAll,
+ NULL,
+ &openingApp);
+ if (status != noErr) {
+ // likely kLSApplicationNotFoundErr
+ return string16();
+ }
+ NSString* appPath = [(NSURL*)openingApp path];
+ CFRelease(openingApp); // NOT A BUG; LSGetApplicationForURL retains for us
+ NSString* appDisplayName =
+ [[NSFileManager defaultManager] displayNameAtPath:appPath];
+
+ return base::SysNSStringToUTF16(appDisplayName);
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/fast_resize_view.h b/chrome/browser/ui/cocoa/fast_resize_view.h
new file mode 100644
index 0000000..1da6004
--- /dev/null
+++ b/chrome/browser/ui/cocoa/fast_resize_view.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_FAST_RESIZE_VIEW_H_
+#define CHROME_BROWSER_UI_COCOA_FAST_RESIZE_VIEW_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+// A Cocoa view that supports an alternate resizing mode, normally used when
+// animations are in progress. In normal resizing mode, subviews are sized to
+// completely fill this view's bounds. In fast resizing mode, the subviews'
+// size is not changed and the subview is clipped to fit, if necessary. Fast
+// resize mode is useful when animating a view that normally takes a significant
+// amount of time to relayout and redraw when its size is changed.
+@interface FastResizeView : NSView {
+ @private
+ BOOL fastResizeMode_;
+}
+
+// Turns fast resizing mode on or off, which determines how this view resizes
+// its subviews. Turning fast resizing mode off has the effect of immediately
+// resizing subviews to fit; callers do not need to explictly call |setFrame:|
+// to trigger a resize.
+- (void)setFastResizeMode:(BOOL)fastResizeMode;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_FAST_RESIZE_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/fast_resize_view.mm b/chrome/browser/ui/cocoa/fast_resize_view.mm
new file mode 100644
index 0000000..8755bc4
--- /dev/null
+++ b/chrome/browser/ui/cocoa/fast_resize_view.mm
@@ -0,0 +1,65 @@
+// Copyright (c) 2009 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>
+#import "chrome/browser/ui/cocoa/fast_resize_view.h"
+
+#include "base/logging.h"
+
+@interface FastResizeView (PrivateMethods)
+// Lays out this views subviews. If fast resize mode is on, does not resize any
+// subviews and instead pegs them to the top left. If fast resize mode is off,
+// sets the subviews' frame to be equal to this view's bounds.
+- (void)layoutSubviews;
+@end
+
+@implementation FastResizeView
+- (void)setFastResizeMode:(BOOL)fastResizeMode {
+ fastResizeMode_ = fastResizeMode;
+
+ // Force a relayout when coming out of fast resize mode.
+ if (!fastResizeMode_)
+ [self layoutSubviews];
+}
+
+- (void)resizeSubviewsWithOldSize:(NSSize)oldSize {
+ [self layoutSubviews];
+}
+
+- (void)drawRect:(NSRect)dirtyRect {
+ // If we are in fast resize mode, our subviews may not completely cover our
+ // bounds, so we fill with white. If we are not in fast resize mode, we do
+ // not need to draw anything.
+ if (fastResizeMode_) {
+ [[NSColor whiteColor] set];
+ NSRectFill(dirtyRect);
+ }
+}
+
+
+@end
+
+@implementation FastResizeView (PrivateMethods)
+- (void)layoutSubviews {
+ // There should never be more than one subview. There can be zero, if we are
+ // in the process of switching tabs or closing the window. In those cases, no
+ // layout is needed.
+ NSArray* subviews = [self subviews];
+ DCHECK([subviews count] <= 1);
+ if ([subviews count] < 1)
+ return;
+
+ NSView* subview = [subviews objectAtIndex:0];
+ NSRect bounds = [self bounds];
+
+ if (fastResizeMode_) {
+ NSRect frame = [subview frame];
+ frame.origin.x = 0;
+ frame.origin.y = NSHeight(bounds) - NSHeight(frame);
+ [subview setFrame:frame];
+ } else {
+ [subview setFrame:bounds];
+ }
+}
+@end
diff --git a/chrome/browser/ui/cocoa/fast_resize_view_unittest.mm b/chrome/browser/ui/cocoa/fast_resize_view_unittest.mm
new file mode 100644
index 0000000..d64be3f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/fast_resize_view_unittest.mm
@@ -0,0 +1,60 @@
+// Copyright (c) 2009 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/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/fast_resize_view.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+
+namespace {
+
+class FastResizeViewTest : public CocoaTest {
+ public:
+ FastResizeViewTest() {
+ NSRect frame = NSMakeRect(0, 0, 100, 30);
+ scoped_nsobject<FastResizeView> view(
+ [[FastResizeView alloc] initWithFrame:frame]);
+ view_ = view.get();
+ [[test_window() contentView] addSubview:view_];
+
+ scoped_nsobject<NSView> childView([[NSView alloc] initWithFrame:frame]);
+ childView_ = childView.get();
+ [view_ addSubview:childView_];
+ }
+
+ FastResizeView* view_;
+ NSView* childView_;
+};
+
+TEST_VIEW(FastResizeViewTest, view_);
+
+TEST_F(FastResizeViewTest, TestResizingOfChildren) {
+ NSRect squareFrame = NSMakeRect(0, 0, 200, 200);
+ NSRect rectFrame = NSMakeRect(1, 1, 150, 300);
+
+ // Test that changing the view's frame also changes the child's frame.
+ [view_ setFrame:squareFrame];
+ EXPECT_TRUE(NSEqualRects([view_ bounds], [childView_ frame]));
+
+ // Turn fast resize mode on and change the view's frame. This time, the child
+ // should not resize, but it should be anchored to the top left.
+ [view_ setFastResizeMode:YES];
+ [view_ setFrame:NSMakeRect(15, 30, 250, 250)];
+ EXPECT_TRUE(NSEqualSizes([childView_ frame].size, squareFrame.size));
+ EXPECT_EQ(NSMinX([view_ bounds]), NSMinX([childView_ frame]));
+ EXPECT_EQ(NSMaxY([view_ bounds]), NSMaxY([childView_ frame]));
+
+ // Another resize with fast resize mode on.
+ [view_ setFrame:rectFrame];
+ EXPECT_TRUE(NSEqualSizes([childView_ frame].size, squareFrame.size));
+ EXPECT_EQ(NSMinX([view_ bounds]), NSMinX([childView_ frame]));
+ EXPECT_EQ(NSMaxY([view_ bounds]), NSMaxY([childView_ frame]));
+
+ // Turn fast resize mode off. This should initiate an immediate resize, even
+ // though we haven't called setFrame directly.
+ [view_ setFastResizeMode:NO];
+ EXPECT_TRUE(NSEqualRects([view_ frame], rectFrame));
+ EXPECT_TRUE(NSEqualRects([view_ bounds], [childView_ frame]));
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/file_metadata.h b/chrome/browser/ui/cocoa/file_metadata.h
new file mode 100644
index 0000000..2a6cfc5
--- /dev/null
+++ b/chrome/browser/ui/cocoa/file_metadata.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_FILE_METADATA_H_
+#define CHROME_BROWSER_UI_COCOA_FILE_METADATA_H_
+#pragma once
+
+class FilePath;
+class GURL;
+
+namespace file_metadata {
+
+// Adds origin metadata to the file.
+// |source| should be the source URL for the download, and |referrer| should be
+// the URL the user initiated the download from.
+void AddOriginMetadataToFile(const FilePath& file, const GURL& source,
+ const GURL& referrer);
+
+// Adds quarantine metadata to the file, assuming it has already been
+// quarantined by the OS.
+// |source| should be the source URL for the download, and |referrer| should be
+// the URL the user initiated the download from.
+void AddQuarantineMetadataToFile(const FilePath& file, const GURL& source,
+ const GURL& referrer);
+
+} // namespace file_metadata
+
+#endif // CHROME_BROWSER_UI_COCOA_FILE_METADATA_H_
diff --git a/chrome/browser/ui/cocoa/file_metadata.mm b/chrome/browser/ui/cocoa/file_metadata.mm
new file mode 100644
index 0000000..d19e3ac
--- /dev/null
+++ b/chrome/browser/ui/cocoa/file_metadata.mm
@@ -0,0 +1,167 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/file_metadata.h"
+
+#include <ApplicationServices/ApplicationServices.h>
+#include <Foundation/Foundation.h>
+
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/mac_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "googleurl/src/gurl.h"
+
+namespace file_metadata {
+
+// As of Mac OS X 10.4 ("Tiger"), files can be tagged with metadata describing
+// various attributes. Metadata is integrated with the system's Spotlight
+// feature and is searchable. Ordinarily, metadata can only be set by
+// Spotlight importers, which requires that the importer own the target file.
+// However, there's an attribute intended to describe the origin of a
+// file, that can store the source URL and referrer of a downloaded file.
+// It's stored as a "com.apple.metadata:kMDItemWhereFroms" extended attribute,
+// structured as a binary1-format plist containing a list of sources. This
+// attribute can only be populated by the downloader, not a Spotlight importer.
+// Safari on 10.4 and later populates this attribute.
+//
+// With this metadata set, you can locate downloads by performing a Spotlight
+// search for their source or referrer URLs, either from within the Spotlight
+// UI or from the command line:
+// mdfind 'kMDItemWhereFroms == "http://releases.mozilla.org/*"'
+//
+// There is no documented API to set metadata on a file directly as of the
+// 10.5 SDK. The MDSetItemAttribute function does exist to perform this task,
+// but it's undocumented.
+void AddOriginMetadataToFile(const FilePath& file, const GURL& source,
+ const GURL& referrer) {
+ // There's no declaration for MDItemSetAttribute in any known public SDK.
+ // It exists in the 10.4 and 10.5 runtimes. To play it safe, do the lookup
+ // at runtime instead of declaring it ourselves and linking against what's
+ // provided. This has two benefits:
+ // - If Apple relents and declares the function in a future SDK (it's
+ // happened before), our build won't break.
+ // - If Apple removes or renames the function in a future runtime, the
+ // loader won't refuse to let the application launch. Instead, we'll
+ // silently fail to set any metadata.
+ typedef OSStatus (*MDItemSetAttribute_type)(MDItemRef, CFStringRef,
+ CFTypeRef);
+ static MDItemSetAttribute_type md_item_set_attribute_func = NULL;
+
+ static bool did_symbol_lookup = false;
+ if (!did_symbol_lookup) {
+ did_symbol_lookup = true;
+ CFBundleRef metadata_bundle =
+ CFBundleGetBundleWithIdentifier(CFSTR("com.apple.Metadata"));
+ if (!metadata_bundle)
+ return;
+
+ md_item_set_attribute_func = (MDItemSetAttribute_type)
+ CFBundleGetFunctionPointerForName(metadata_bundle,
+ CFSTR("MDItemSetAttribute"));
+ }
+ if (!md_item_set_attribute_func)
+ return;
+
+ NSString* file_path =
+ [NSString stringWithUTF8String:file.value().c_str()];
+ if (!file_path)
+ return;
+
+ base::mac::ScopedCFTypeRef<MDItemRef> md_item(
+ MDItemCreate(NULL, reinterpret_cast<CFStringRef>(file_path)));
+ if (!md_item)
+ return;
+
+ // We won't put any more than 2 items into the attribute.
+ NSMutableArray* list = [NSMutableArray arrayWithCapacity:2];
+
+ // Follow Safari's lead: the first item in the list is the source URL of
+ // the downloaded file. If the referrer is known, store that, too.
+ NSString* origin_url = [NSString stringWithUTF8String:source.spec().c_str()];
+ if (origin_url)
+ [list addObject:origin_url];
+ NSString* referrer_url =
+ [NSString stringWithUTF8String:referrer.spec().c_str()];
+ if (referrer_url)
+ [list addObject:referrer_url];
+
+ md_item_set_attribute_func(md_item, kMDItemWhereFroms,
+ reinterpret_cast<CFArrayRef>(list));
+}
+
+// The OS will automatically quarantine files due to the
+// LSFileQuarantineEnabled entry in our Info.plist, but it knows relatively
+// little about the files. We add more information about the download to
+// improve the UI shown by the OS when the users tries to open the file.
+void AddQuarantineMetadataToFile(const FilePath& file, const GURL& source,
+ const GURL& referrer) {
+ FSRef file_ref;
+ if (!mac_util::FSRefFromPath(file.value(), &file_ref))
+ return;
+
+ NSMutableDictionary* quarantine_properties = nil;
+ CFTypeRef quarantine_properties_base = NULL;
+ if (LSCopyItemAttribute(&file_ref, kLSRolesAll, kLSItemQuarantineProperties,
+ &quarantine_properties_base) == noErr) {
+ if (CFGetTypeID(quarantine_properties_base) ==
+ CFDictionaryGetTypeID()) {
+ // Quarantine properties will already exist if LSFileQuarantineEnabled
+ // is on and the file doesn't match an exclusion.
+ quarantine_properties =
+ [[(NSDictionary*)quarantine_properties_base mutableCopy] autorelease];
+ } else {
+ LOG(WARNING) << "kLSItemQuarantineProperties is not a dictionary on file "
+ << file.value();
+ }
+ CFRelease(quarantine_properties_base);
+ }
+
+ if (!quarantine_properties) {
+ // If there are no quarantine properties, then the file isn't quarantined
+ // (e.g., because the user has set up exclusions for certain file types).
+ // We don't want to add any metadata, because that will cause the file to
+ // be quarantined against the user's wishes.
+ return;
+ }
+
+ // kLSQuarantineAgentNameKey, kLSQuarantineAgentBundleIdentifierKey, and
+ // kLSQuarantineTimeStampKey are set for us (see LSQuarantine.h), so we only
+ // need to set the values that the OS can't infer.
+
+ if (![quarantine_properties valueForKey:(NSString*)kLSQuarantineTypeKey]) {
+ CFStringRef type = (source.SchemeIs("http") || source.SchemeIs("https"))
+ ? kLSQuarantineTypeWebDownload
+ : kLSQuarantineTypeOtherDownload;
+ [quarantine_properties setValue:(NSString*)type
+ forKey:(NSString*)kLSQuarantineTypeKey];
+ }
+
+ if (![quarantine_properties
+ valueForKey:(NSString*)kLSQuarantineOriginURLKey] &&
+ referrer.is_valid()) {
+ NSString* referrer_url =
+ [NSString stringWithUTF8String:referrer.spec().c_str()];
+ [quarantine_properties setValue:referrer_url
+ forKey:(NSString*)kLSQuarantineOriginURLKey];
+ }
+
+ if (![quarantine_properties valueForKey:(NSString*)kLSQuarantineDataURLKey] &&
+ source.is_valid()) {
+ NSString* origin_url =
+ [NSString stringWithUTF8String:source.spec().c_str()];
+ [quarantine_properties setValue:origin_url
+ forKey:(NSString*)kLSQuarantineDataURLKey];
+ }
+
+ OSStatus os_error = LSSetItemAttribute(&file_ref, kLSRolesAll,
+ kLSItemQuarantineProperties,
+ quarantine_properties);
+ if (os_error != noErr) {
+ LOG(WARNING) << "Unable to set quarantine attributes on file "
+ << file.value();
+ }
+}
+
+} // namespace file_metadata
diff --git a/chrome/browser/ui/cocoa/find_bar_bridge.h b/chrome/browser/ui/cocoa/find_bar_bridge.h
new file mode 100644
index 0000000..2b8d83b
--- /dev/null
+++ b/chrome/browser/ui/cocoa/find_bar_bridge.h
@@ -0,0 +1,97 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_FIND_BAR_BRIDGE_H_
+#define CHROME_BROWSER_UI_COCOA_FIND_BAR_BRIDGE_H_
+#pragma once
+
+#include "base/logging.h"
+#include "chrome/browser/ui/find_bar/find_bar.h"
+
+class BrowserWindowCocoa;
+class FindBarController;
+
+// This class is included by find_bar_host_browsertest.cc, so it has to be
+// objc-free.
+#ifdef __OBJC__
+@class FindBarCocoaController;
+#else
+class FindBarCocoaController;
+#endif
+
+// Implementation of FindBar for the Mac. This class simply passes
+// each message along to |cocoa_controller_|.
+//
+// The initialization here is a bit complicated. FindBarBridge is
+// created by a static method in BrowserWindow. The FindBarBridge
+// constructor creates a FindBarCocoaController, which in turn loads a
+// FindBarView from a nib file. All of this is happening outside of
+// the main view hierarchy, so the static method also calls
+// BrowserWindowCocoa::AddFindBar() in order to add its FindBarView to
+// the cocoa views hierarchy.
+//
+// Memory ownership is relatively straightforward. The FindBarBridge
+// object is owned by the Browser. FindBarCocoaController is retained
+// by bother FindBarBridge and BrowserWindowController, since both use it.
+
+class FindBarBridge : public FindBar,
+ public FindBarTesting {
+ public:
+ FindBarBridge();
+ virtual ~FindBarBridge();
+
+ FindBarCocoaController* find_bar_cocoa_controller() {
+ return cocoa_controller_;
+ }
+
+ virtual void SetFindBarController(FindBarController* find_bar_controller) {
+ find_bar_controller_ = find_bar_controller;
+ }
+
+ virtual FindBarController* GetFindBarController() const {
+ DCHECK(find_bar_controller_);
+ return find_bar_controller_;
+ }
+
+ virtual FindBarTesting* GetFindBarTesting() {
+ return this;
+ }
+
+ // Methods from FindBar.
+ virtual void Show(bool animate);
+ virtual void Hide(bool animate);
+ virtual void SetFocusAndSelection();
+ virtual void ClearResults(const FindNotificationDetails& results);
+ virtual void StopAnimation();
+ virtual void SetFindText(const string16& find_text);
+ virtual void UpdateUIForFindResult(const FindNotificationDetails& result,
+ const string16& find_text);
+ virtual void AudibleAlert();
+ virtual bool IsFindBarVisible();
+ virtual void RestoreSavedFocus();
+ virtual void MoveWindowIfNecessary(const gfx::Rect& selection_rect,
+ bool no_redraw);
+
+ // Methods from FindBarTesting.
+ virtual bool GetFindBarWindowInfo(gfx::Point* position,
+ bool* fully_visible);
+ virtual string16 GetFindText();
+ virtual string16 GetFindSelectedText();
+ virtual string16 GetMatchCountText();
+
+ // Used to disable find bar animations when testing.
+ static bool disable_animations_during_testing_;
+
+ private:
+ // Pointer to the cocoa controller which manages the cocoa view. Is
+ // never nil.
+ FindBarCocoaController* cocoa_controller_;
+
+ // Pointer back to the owning controller.
+ FindBarController* find_bar_controller_; // weak, owns us
+
+ DISALLOW_COPY_AND_ASSIGN(FindBarBridge);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_FIND_BAR_BRIDGE_H_
diff --git a/chrome/browser/ui/cocoa/find_bar_bridge.mm b/chrome/browser/ui/cocoa/find_bar_bridge.mm
new file mode 100644
index 0000000..9481b54
--- /dev/null
+++ b/chrome/browser/ui/cocoa/find_bar_bridge.mm
@@ -0,0 +1,114 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/find_bar_bridge.h"
+
+#include "base/sys_string_conversions.h"
+#import "chrome/browser/ui/cocoa/find_bar_cocoa_controller.h"
+
+// static
+bool FindBarBridge::disable_animations_during_testing_ = false;
+
+FindBarBridge::FindBarBridge()
+ : find_bar_controller_(NULL) {
+ cocoa_controller_ = [[FindBarCocoaController alloc] init];
+ [cocoa_controller_ setFindBarBridge:this];
+}
+
+FindBarBridge::~FindBarBridge() {
+ [cocoa_controller_ release];
+}
+
+void FindBarBridge::Show(bool animate) {
+ bool really_animate = animate && !disable_animations_during_testing_;
+ [cocoa_controller_ showFindBar:(really_animate ? YES : NO)];
+}
+
+void FindBarBridge::Hide(bool animate) {
+ bool really_animate = animate && !disable_animations_during_testing_;
+ [cocoa_controller_ hideFindBar:(really_animate ? YES : NO)];
+}
+
+void FindBarBridge::SetFocusAndSelection() {
+ [cocoa_controller_ setFocusAndSelection];
+}
+
+void FindBarBridge::ClearResults(const FindNotificationDetails& results) {
+ [cocoa_controller_ clearResults:results];
+}
+
+void FindBarBridge::SetFindText(const string16& find_text) {
+ [cocoa_controller_ setFindText:base::SysUTF16ToNSString(find_text)];
+}
+
+void FindBarBridge::UpdateUIForFindResult(const FindNotificationDetails& result,
+ const string16& find_text) {
+ [cocoa_controller_ updateUIForFindResult:result withText:find_text];
+}
+
+void FindBarBridge::AudibleAlert() {
+ // Beep beep, beep beep, Yeah!
+ NSBeep();
+}
+
+bool FindBarBridge::IsFindBarVisible() {
+ return [cocoa_controller_ isFindBarVisible] ? true : false;
+}
+
+void FindBarBridge::MoveWindowIfNecessary(const gfx::Rect& selection_rect,
+ bool no_redraw) {
+ // http://crbug.com/11084
+ // http://crbug.com/22036
+}
+
+void FindBarBridge::StopAnimation() {
+ [cocoa_controller_ stopAnimation];
+}
+
+void FindBarBridge::RestoreSavedFocus() {
+ [cocoa_controller_ restoreSavedFocus];
+}
+
+bool FindBarBridge::GetFindBarWindowInfo(gfx::Point* position,
+ bool* fully_visible) {
+ // TODO(rohitrao): Return the proper position. http://crbug.com/22036
+ if (position)
+ *position = gfx::Point(0, 0);
+
+ NSWindow* window = [[cocoa_controller_ view] window];
+ bool window_visible = [window isVisible] ? true : false;
+ if (fully_visible) {
+ *fully_visible = window_visible &&
+ [cocoa_controller_ isFindBarVisible] &&
+ ![cocoa_controller_ isFindBarAnimating];
+ }
+ return window_visible;
+}
+
+string16 FindBarBridge::GetFindText() {
+ // This function is currently only used in Windows and Linux specific browser
+ // tests (testing prepopulate values that Mac's don't rely on), but if we add
+ // more tests that are non-platform specific, we need to flesh out this
+ // function.
+ NOTIMPLEMENTED();
+ return string16();
+}
+
+string16 FindBarBridge::GetFindSelectedText() {
+ // This function is currently only used in Windows and Linux specific browser
+ // tests (testing prepopulate values that Mac's don't rely on), but if we add
+ // more tests that are non-platform specific, we need to flesh out this
+ // function.
+ NOTIMPLEMENTED();
+ return string16();
+}
+
+string16 FindBarBridge::GetMatchCountText() {
+ // This function is currently only used in Windows and Linux specific browser
+ // tests (testing prepopulate values that Mac's don't rely on), but if we add
+ // more tests that are non-platform specific, we need to flesh out this
+ // function.
+ NOTIMPLEMENTED();
+ return string16();
+}
diff --git a/chrome/browser/ui/cocoa/find_bar_bridge_unittest.mm b/chrome/browser/ui/cocoa/find_bar_bridge_unittest.mm
new file mode 100644
index 0000000..421cb80
--- /dev/null
+++ b/chrome/browser/ui/cocoa/find_bar_bridge_unittest.mm
@@ -0,0 +1,30 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/find_bar_bridge.h"
+#include "chrome/browser/ui/find_bar/find_bar_controller.h"
+
+namespace {
+
+class FindBarBridgeTest : public CocoaTest {
+};
+
+TEST_F(FindBarBridgeTest, Creation) {
+ // Make sure the FindBarBridge constructor doesn't crash and
+ // properly initializes its FindBarCocoaController.
+ FindBarBridge bridge;
+ EXPECT_TRUE(bridge.find_bar_cocoa_controller() != NULL);
+}
+
+TEST_F(FindBarBridgeTest, Accessors) {
+ // Get/SetFindBarController are virtual methods implemented in
+ // FindBarBridge, so we test them here.
+ FindBarBridge* bridge = new FindBarBridge();
+ FindBarController controller(bridge); // takes ownership of |bridge|.
+ bridge->SetFindBarController(&controller);
+
+ EXPECT_EQ(&controller, bridge->GetFindBarController());
+}
+} // namespace
diff --git a/chrome/browser/ui/cocoa/find_bar_cocoa_controller.h b/chrome/browser/ui/cocoa/find_bar_cocoa_controller.h
new file mode 100644
index 0000000..289d89c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/find_bar_cocoa_controller.h
@@ -0,0 +1,78 @@
+// Copyright (c) 2009 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>
+
+#import "chrome/browser/ui/cocoa/find_bar_cocoa_controller.h"
+
+#include "base/scoped_nsobject.h"
+#include "base/string16.h"
+
+class BrowserWindowCocoa;
+class FindBarBridge;
+@class FindBarTextField;
+class FindNotificationDetails;
+@class FocusTracker;
+
+// A controller for the find bar in the browser window. Manages
+// updating the state of the find bar and provides a target for the
+// next/previous/close buttons. Certain operations require a pointer
+// to the cross-platform FindBarController, so be sure to call
+// setFindBarBridge: after creating this controller.
+
+@interface FindBarCocoaController : NSViewController {
+ @private
+ IBOutlet NSView* findBarView_;
+ IBOutlet FindBarTextField* findText_;
+ IBOutlet NSButton* nextButton_;
+ IBOutlet NSButton* previousButton_;
+
+ // Needed to call methods on FindBarController.
+ FindBarBridge* findBarBridge_; // weak
+
+ scoped_nsobject<FocusTracker> focusTracker_;
+
+ // The currently-running animation. This is defined to be non-nil if an
+ // animation is running, and is always nil otherwise. The
+ // FindBarCocoaController should not be deallocated while an animation is
+ // running (stopAnimation is currently called before the last tab in a
+ // window is removed).
+ scoped_nsobject<NSViewAnimation> currentAnimation_;
+
+ // If YES, do nothing as a result of find pasteboard update notifications.
+ BOOL suppressPboardUpdateActions_;
+};
+
+// Initializes a new FindBarCocoaController.
+- (id)init;
+
+- (void)setFindBarBridge:(FindBarBridge*)findBar;
+
+- (IBAction)close:(id)sender;
+
+- (IBAction)nextResult:(id)sender;
+
+- (IBAction)previousResult:(id)sender;
+
+// Position the find bar at the given maximum y-coordinate (the min-y of the
+// bar -- toolbar + possibly bookmark bar, but not including the infobars) with
+// the given maximum width (i.e., the find bar should fit between 0 and
+// |maxWidth|).
+- (void)positionFindBarViewAtMaxY:(CGFloat)maxY maxWidth:(CGFloat)maxWidth;
+
+// Methods called from FindBarBridge.
+- (void)showFindBar:(BOOL)animate;
+- (void)hideFindBar:(BOOL)animate;
+- (void)stopAnimation;
+- (void)setFocusAndSelection;
+- (void)restoreSavedFocus;
+- (void)setFindText:(NSString*)findText;
+
+- (void)clearResults:(const FindNotificationDetails&)results;
+- (void)updateUIForFindResult:(const FindNotificationDetails&)results
+ withText:(const string16&)findText;
+- (BOOL)isFindBarVisible;
+- (BOOL)isFindBarAnimating;
+
+@end
diff --git a/chrome/browser/ui/cocoa/find_bar_cocoa_controller.mm b/chrome/browser/ui/cocoa/find_bar_cocoa_controller.mm
new file mode 100644
index 0000000..05e5397
--- /dev/null
+++ b/chrome/browser/ui/cocoa/find_bar_cocoa_controller.mm
@@ -0,0 +1,384 @@
+// Copyright (c) 2009 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 "base/mac_util.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/cocoa/browser_window_cocoa.h"
+#import "chrome/browser/ui/cocoa/find_bar_cocoa_controller.h"
+#import "chrome/browser/ui/cocoa/find_bar_bridge.h"
+#import "chrome/browser/ui/cocoa/find_bar_text_field.h"
+#import "chrome/browser/ui/cocoa/find_bar_text_field_cell.h"
+#import "chrome/browser/ui/cocoa/find_pasteboard.h"
+#import "chrome/browser/ui/cocoa/focus_tracker.h"
+#import "chrome/browser/ui/cocoa/tab_strip_controller.h"
+#include "chrome/browser/ui/find_bar/find_bar_controller.h"
+#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
+
+namespace {
+const float kFindBarOpenDuration = 0.2;
+const float kFindBarCloseDuration = 0.15;
+}
+
+@interface FindBarCocoaController (PrivateMethods)
+// Returns the appropriate frame for a hidden find bar.
+- (NSRect)hiddenFindBarFrame;
+
+// Sets the frame of |findBarView_|. |duration| is ignored if |animate| is NO.
+- (void)setFindBarFrame:(NSRect)endFrame
+ animate:(BOOL)animate
+ duration:(float)duration;
+
+// Optionally stops the current search, puts |text| into the find bar, and
+// enables the buttons, but doesn't start a new search for |text|.
+- (void)prepopulateText:(NSString*)text stopSearch:(BOOL)stopSearch;
+@end
+
+@implementation FindBarCocoaController
+
+- (id)init {
+ if ((self = [super initWithNibName:@"FindBar"
+ bundle:mac_util::MainAppBundle()])) {
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(findPboardUpdated:)
+ name:kFindPasteboardChangedNotification
+ object:[FindPasteboard sharedInstance]];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ // All animations should be explicitly stopped by the TabContents before a tab
+ // is closed.
+ DCHECK(!currentAnimation_.get());
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+- (void)setFindBarBridge:(FindBarBridge*)findBarBridge {
+ DCHECK(!findBarBridge_); // should only be called once.
+ findBarBridge_ = findBarBridge;
+}
+
+- (void)awakeFromNib {
+ [findBarView_ setFrame:[self hiddenFindBarFrame]];
+
+ // Stopping the search requires a findbar controller, which isn't valid yet
+ // during setup. Furthermore, there is no active search yet anyway.
+ [self prepopulateText:[[FindPasteboard sharedInstance] findText]
+ stopSearch:NO];
+}
+
+- (IBAction)close:(id)sender {
+ if (findBarBridge_)
+ findBarBridge_->GetFindBarController()->EndFindSession(
+ FindBarController::kKeepSelection);
+}
+
+- (IBAction)previousResult:(id)sender {
+ if (findBarBridge_)
+ findBarBridge_->GetFindBarController()->tab_contents()->StartFinding(
+ base::SysNSStringToUTF16([findText_ stringValue]),
+ false, false);
+}
+
+- (IBAction)nextResult:(id)sender {
+ if (findBarBridge_)
+ findBarBridge_->GetFindBarController()->tab_contents()->StartFinding(
+ base::SysNSStringToUTF16([findText_ stringValue]),
+ true, false);
+}
+
+- (void)findPboardUpdated:(NSNotification*)notification {
+ if (suppressPboardUpdateActions_)
+ return;
+ [self prepopulateText:[[FindPasteboard sharedInstance] findText]
+ stopSearch:YES];
+}
+
+- (void)positionFindBarViewAtMaxY:(CGFloat)maxY maxWidth:(CGFloat)maxWidth {
+ static const CGFloat kRightEdgeOffset = 25;
+ NSView* containerView = [self view];
+ CGFloat containerHeight = NSHeight([containerView frame]);
+ CGFloat containerWidth = NSWidth([containerView frame]);
+
+ // Adjust where we'll actually place the find bar.
+ CGFloat maxX = maxWidth - kRightEdgeOffset;
+ DLOG_IF(WARNING, maxX < 0) << "Window too narrow for find bar";
+ maxY += 1;
+
+ NSRect newFrame = NSMakeRect(maxX - containerWidth, maxY - containerHeight,
+ containerWidth, containerHeight);
+ [containerView setFrame:newFrame];
+}
+
+// NSControl delegate method.
+- (void)controlTextDidChange:(NSNotification *)aNotification {
+ if (!findBarBridge_)
+ return;
+
+ TabContents* tab_contents =
+ findBarBridge_->GetFindBarController()->tab_contents();
+ if (!tab_contents)
+ return;
+
+ NSString* findText = [findText_ stringValue];
+ suppressPboardUpdateActions_ = YES;
+ [[FindPasteboard sharedInstance] setFindText:findText];
+ suppressPboardUpdateActions_ = NO;
+
+ if ([findText length] > 0) {
+ tab_contents->StartFinding(base::SysNSStringToUTF16(findText), true, false);
+ } else {
+ // The textbox is empty so we reset.
+ tab_contents->StopFinding(FindBarController::kClearSelection);
+ [self updateUIForFindResult:tab_contents->find_result()
+ withText:string16()];
+ }
+}
+
+// NSControl delegate method
+- (BOOL)control:(NSControl*)control
+ textView:(NSTextView*)textView
+ doCommandBySelector:(SEL)command {
+ if (command == @selector(insertNewline:)) {
+ // Pressing Return
+ NSEvent* event = [NSApp currentEvent];
+
+ if ([event modifierFlags] & NSShiftKeyMask)
+ [previousButton_ performClick:nil];
+ else
+ [nextButton_ performClick:nil];
+
+ return YES;
+ } else if (command == @selector(insertLineBreak:)) {
+ // Pressing Ctrl-Return
+ if (findBarBridge_) {
+ findBarBridge_->GetFindBarController()->EndFindSession(
+ FindBarController::kActivateSelection);
+ }
+ return YES;
+ } else if (command == @selector(pageUp:) ||
+ command == @selector(pageUpAndModifySelection:) ||
+ command == @selector(scrollPageUp:) ||
+ command == @selector(pageDown:) ||
+ command == @selector(pageDownAndModifySelection:) ||
+ command == @selector(scrollPageDown:) ||
+ command == @selector(scrollToBeginningOfDocument:) ||
+ command == @selector(scrollToEndOfDocument:) ||
+ command == @selector(moveUp:) ||
+ command == @selector(moveDown:)) {
+ TabContents* contents =
+ findBarBridge_->GetFindBarController()->tab_contents();
+ if (!contents)
+ return NO;
+
+ // Sanity-check to make sure we got a keyboard event.
+ NSEvent* event = [NSApp currentEvent];
+ if ([event type] != NSKeyDown && [event type] != NSKeyUp)
+ return NO;
+
+ // Forward the event to the renderer.
+ // TODO(rohitrao): Should this call -[BaseView keyEvent:]? Is there code in
+ // that function that we want to keep or avoid? Calling
+ // |ForwardKeyboardEvent()| directly ignores edit commands, which breaks
+ // cmd-up/down if we ever decide to include |moveToBeginningOfDocument:| in
+ // the list above.
+ RenderViewHost* render_view_host = contents->render_view_host();
+ render_view_host->ForwardKeyboardEvent(NativeWebKeyboardEvent(event));
+ return YES;
+ }
+
+ return NO;
+}
+
+// Methods from FindBar
+- (void)showFindBar:(BOOL)animate {
+ // Save the currently-focused view. |findBarView_| is in the view
+ // hierarchy by now. showFindBar can be called even when the
+ // findbar is already open, so do not overwrite an already saved
+ // view.
+ if (!focusTracker_.get())
+ focusTracker_.reset(
+ [[FocusTracker alloc] initWithWindow:[findBarView_ window]]);
+
+ // Animate the view into place.
+ NSRect frame = [findBarView_ frame];
+ frame.origin = NSMakePoint(0, 0);
+ [self setFindBarFrame:frame animate:animate duration:kFindBarOpenDuration];
+}
+
+- (void)hideFindBar:(BOOL)animate {
+ NSRect frame = [self hiddenFindBarFrame];
+ [self setFindBarFrame:frame animate:animate duration:kFindBarCloseDuration];
+}
+
+- (void)stopAnimation {
+ if (currentAnimation_.get()) {
+ [currentAnimation_ stopAnimation];
+ currentAnimation_.reset(nil);
+ }
+}
+
+- (void)setFocusAndSelection {
+ [[findText_ window] makeFirstResponder:findText_];
+
+ // Enable the buttons if the find text is non-empty.
+ BOOL buttonsEnabled = ([[findText_ stringValue] length] > 0) ? YES : NO;
+ [previousButton_ setEnabled:buttonsEnabled];
+ [nextButton_ setEnabled:buttonsEnabled];
+}
+
+- (void)restoreSavedFocus {
+ if (!(focusTracker_.get() &&
+ [focusTracker_ restoreFocusInWindow:[findBarView_ window]])) {
+ // Fall back to giving focus to the tab contents.
+ findBarBridge_->GetFindBarController()->tab_contents()->Focus();
+ }
+ focusTracker_.reset(nil);
+}
+
+- (void)setFindText:(NSString*)findText {
+ [findText_ setStringValue:findText];
+
+ // Make sure the text in the find bar always ends up in the find pasteboard
+ // (and, via notifications, in the other find bars too).
+ [[FindPasteboard sharedInstance] setFindText:findText];
+}
+
+- (void)clearResults:(const FindNotificationDetails&)results {
+ // Just call updateUIForFindResult, which will take care of clearing
+ // the search text and the results label.
+ [self updateUIForFindResult:results withText:string16()];
+}
+
+- (void)updateUIForFindResult:(const FindNotificationDetails&)result
+ withText:(const string16&)findText {
+ // If we don't have any results and something was passed in, then
+ // that means someone pressed Cmd-G while the Find box was
+ // closed. In that case we need to repopulate the Find box with what
+ // was passed in.
+ if ([[findText_ stringValue] length] == 0 && !findText.empty()) {
+ [findText_ setStringValue:base::SysUTF16ToNSString(findText)];
+ [findText_ selectText:self];
+ }
+
+ // Make sure Find Next and Find Previous are enabled if we found any matches.
+ BOOL buttonsEnabled = result.number_of_matches() > 0 ? YES : NO;
+ [previousButton_ setEnabled:buttonsEnabled];
+ [nextButton_ setEnabled:buttonsEnabled];
+
+ // Update the results label.
+ BOOL validRange = result.active_match_ordinal() != -1 &&
+ result.number_of_matches() != -1;
+ NSString* searchString = [findText_ stringValue];
+ if ([searchString length] > 0 && validRange) {
+ [[findText_ findBarTextFieldCell]
+ setActiveMatch:result.active_match_ordinal()
+ of:result.number_of_matches()];
+ } else {
+ // If there was no text entered, we don't show anything in the results area.
+ [[findText_ findBarTextFieldCell] clearResults];
+ }
+
+ [findText_ resetFieldEditorFrameIfNeeded];
+
+ // If we found any results, reset the focus tracker, so we always
+ // restore focus to the tab contents.
+ if (result.number_of_matches() > 0)
+ focusTracker_.reset(nil);
+}
+
+- (BOOL)isFindBarVisible {
+ // Find bar is visible if any part of it is on the screen.
+ return NSIntersectsRect([[self view] bounds], [findBarView_ frame]);
+}
+
+- (BOOL)isFindBarAnimating {
+ return (currentAnimation_.get() != nil);
+}
+
+// NSAnimation delegate methods.
+- (void)animationDidEnd:(NSAnimation*)animation {
+ // Autorelease the animation (cannot use release because the animation object
+ // is still on the stack.
+ DCHECK(animation == currentAnimation_.get());
+ [currentAnimation_.release() autorelease];
+
+ // If the find bar is not visible, make it actually hidden, so it'll no longer
+ // respond to key events.
+ [findBarView_ setHidden:![self isFindBarVisible]];
+}
+
+@end
+
+@implementation FindBarCocoaController (PrivateMethods)
+
+- (NSRect)hiddenFindBarFrame {
+ NSRect frame = [findBarView_ frame];
+ NSRect containerBounds = [[self view] bounds];
+ frame.origin = NSMakePoint(NSMinX(containerBounds), NSMaxY(containerBounds));
+ return frame;
+}
+
+- (void)setFindBarFrame:(NSRect)endFrame
+ animate:(BOOL)animate
+ duration:(float)duration {
+ // Save the current frame.
+ NSRect startFrame = [findBarView_ frame];
+
+ // Stop any existing animations.
+ [currentAnimation_ stopAnimation];
+
+ if (!animate) {
+ [findBarView_ setFrame:endFrame];
+ [findBarView_ setHidden:![self isFindBarVisible]];
+ currentAnimation_.reset(nil);
+ return;
+ }
+
+ // If animating, ensure that the find bar is not hidden. Hidden status will be
+ // updated at the end of the animation.
+ [findBarView_ setHidden:NO];
+
+ // Reset the frame to what was saved above.
+ [findBarView_ setFrame:startFrame];
+ NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
+ findBarView_, NSViewAnimationTargetKey,
+ [NSValue valueWithRect:endFrame], NSViewAnimationEndFrameKey, nil];
+
+ currentAnimation_.reset(
+ [[NSViewAnimation alloc]
+ initWithViewAnimations:[NSArray arrayWithObjects:dict, nil]]);
+ [currentAnimation_ gtm_setDuration:duration
+ eventMask:NSLeftMouseUpMask];
+ [currentAnimation_ setDelegate:self];
+ [currentAnimation_ startAnimation];
+}
+
+- (void)prepopulateText:(NSString*)text stopSearch:(BOOL)stopSearch{
+ [self setFindText:text];
+
+ // End the find session, hide the "x of y" text and disable the
+ // buttons, but do not close the find bar or raise the window here.
+ if (stopSearch && findBarBridge_) {
+ TabContents* contents =
+ findBarBridge_->GetFindBarController()->tab_contents();
+ if (contents) {
+ contents->StopFinding(FindBarController::kClearSelection);
+ findBarBridge_->ClearResults(contents->find_result());
+ }
+ }
+
+ // Has to happen after |ClearResults()| above.
+ BOOL buttonsEnabled = [text length] > 0 ? YES : NO;
+ [previousButton_ setEnabled:buttonsEnabled];
+ [nextButton_ setEnabled:buttonsEnabled];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/find_bar_cocoa_controller_unittest.mm b/chrome/browser/ui/cocoa/find_bar_cocoa_controller_unittest.mm
new file mode 100644
index 0000000..d7869c2
--- /dev/null
+++ b/chrome/browser/ui/cocoa/find_bar_cocoa_controller_unittest.mm
@@ -0,0 +1,138 @@
+// Copyright (c) 2009 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/string_util.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/browser_window.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/find_bar_cocoa_controller.h"
+#import "chrome/browser/ui/cocoa/find_pasteboard.h"
+#import "chrome/browser/ui/cocoa/find_bar_text_field.h"
+#include "chrome/browser/ui/find_bar/find_notification_details.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+// Expose private variables to make testing easier.
+@interface FindBarCocoaController(Testing)
+- (NSView*)findBarView;
+- (NSString*)findText;
+- (FindBarTextField*)findTextField;
+@end
+
+@implementation FindBarCocoaController(Testing)
+- (NSView*)findBarView {
+ return findBarView_;
+}
+
+- (NSString*)findText {
+ return [findText_ stringValue];
+}
+
+- (FindBarTextField*)findTextField {
+ return findText_;
+}
+
+- (NSButton*)nextButton {
+ return nextButton_;
+}
+
+- (NSButton*)previousButton {
+ return previousButton_;
+}
+@end
+
+namespace {
+
+class FindBarCocoaControllerTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ controller_.reset([[FindBarCocoaController alloc] init]);
+ [[test_window() contentView] addSubview:[controller_ view]];
+ }
+
+ protected:
+ scoped_nsobject<FindBarCocoaController> controller_;
+};
+
+TEST_VIEW(FindBarCocoaControllerTest, [controller_ view])
+
+TEST_F(FindBarCocoaControllerTest, ImagesLoadedProperly) {
+ EXPECT_TRUE([[[controller_ nextButton] image] isValid]);
+ EXPECT_TRUE([[[controller_ previousButton] image] isValid]);
+}
+
+TEST_F(FindBarCocoaControllerTest, ShowAndHide) {
+ NSView* findBarView = [controller_ findBarView];
+
+ ASSERT_GT([findBarView frame].origin.y, 0);
+ ASSERT_FALSE([controller_ isFindBarVisible]);
+
+ [controller_ showFindBar:NO];
+ EXPECT_EQ([findBarView frame].origin.y, 0);
+ EXPECT_TRUE([controller_ isFindBarVisible]);
+
+ [controller_ hideFindBar:NO];
+ EXPECT_GT([findBarView frame].origin.y, 0);
+ EXPECT_FALSE([controller_ isFindBarVisible]);
+}
+
+TEST_F(FindBarCocoaControllerTest, SetFindText) {
+ NSTextField* findTextField = [controller_ findTextField];
+
+ // Start by making the find bar visible.
+ [controller_ showFindBar:NO];
+ EXPECT_TRUE([controller_ isFindBarVisible]);
+
+ // Set the find text.
+ NSString* const kFindText = @"Google";
+ [controller_ setFindText:kFindText];
+ EXPECT_EQ(
+ NSOrderedSame,
+ [[findTextField stringValue] compare:kFindText]);
+
+ // Call clearResults, which doesn't actually clear the find text but
+ // simply sets it back to what it was before. This is silly, but
+ // matches the behavior on other platforms. |details| isn't used by
+ // our implementation of clearResults, so it's ok to pass in an
+ // empty |details|.
+ FindNotificationDetails details;
+ [controller_ clearResults:details];
+ EXPECT_EQ(
+ NSOrderedSame,
+ [[findTextField stringValue] compare:kFindText]);
+}
+
+TEST_F(FindBarCocoaControllerTest, ResultLabelUpdatesCorrectly) {
+ // TODO(rohitrao): Test this. It may involve creating some dummy
+ // FindNotificationDetails objects.
+}
+
+TEST_F(FindBarCocoaControllerTest, FindTextIsGlobal) {
+ scoped_nsobject<FindBarCocoaController> otherController(
+ [[FindBarCocoaController alloc] init]);
+ [[test_window() contentView] addSubview:[otherController view]];
+
+ // Setting the text in one controller should update the other controller's
+ // text as well.
+ NSString* const kFindText = @"Respect to the man in the ice cream van";
+ [controller_ setFindText:kFindText];
+ EXPECT_EQ(
+ NSOrderedSame,
+ [[controller_ findText] compare:kFindText]);
+ EXPECT_EQ(
+ NSOrderedSame,
+ [[otherController.get() findText] compare:kFindText]);
+}
+
+TEST_F(FindBarCocoaControllerTest, SettingFindTextUpdatesFindPboard) {
+ NSString* const kFindText =
+ @"It's not a bird, it's not a plane, it must be Dave who's on the train";
+ [controller_ setFindText:kFindText];
+ EXPECT_EQ(
+ NSOrderedSame,
+ [[[FindPasteboard sharedInstance] findText] compare:kFindText]);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/find_bar_text_field.h b/chrome/browser/ui/cocoa/find_bar_text_field.h
new file mode 100644
index 0000000..765cc64
--- /dev/null
+++ b/chrome/browser/ui/cocoa/find_bar_text_field.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2009 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>
+#import "chrome/browser/ui/cocoa/styled_text_field.h"
+
+@class FindBarTextFieldCell;
+
+// TODO(rohitrao): This class may not need to exist, since it does not really
+// add any functionality over StyledTextField. See if we can change the nib
+// file to put a FindBarTextFieldCell into a StyledTextField.
+
+// Extends StyledTextField to use a custom cell class (FindBarTextFieldCell).
+@interface FindBarTextField : StyledTextField {
+}
+
+// Convenience method to return the cell, casted appropriately.
+- (FindBarTextFieldCell*)findBarTextFieldCell;
+
+@end
diff --git a/chrome/browser/ui/cocoa/find_bar_text_field.mm b/chrome/browser/ui/cocoa/find_bar_text_field.mm
new file mode 100644
index 0000000..805fca3
--- /dev/null
+++ b/chrome/browser/ui/cocoa/find_bar_text_field.mm
@@ -0,0 +1,40 @@
+// 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 "chrome/browser/ui/cocoa/find_bar_text_field.h"
+
+#include "base/logging.h"
+#import "chrome/browser/ui/cocoa/find_bar_text_field_cell.h"
+#import "chrome/browser/ui/cocoa/view_id_util.h"
+
+@implementation FindBarTextField
+
++ (Class)cellClass {
+ return [FindBarTextFieldCell class];
+}
+
+- (void)awakeFromNib {
+ DCHECK([[self cell] isKindOfClass:[FindBarTextFieldCell class]]);
+
+ [self registerForDraggedTypes:
+ [NSArray arrayWithObjects:NSStringPboardType, nil]];
+}
+
+- (FindBarTextFieldCell*)findBarTextFieldCell {
+ DCHECK([[self cell] isKindOfClass:[FindBarTextFieldCell class]]);
+ return static_cast<FindBarTextFieldCell*>([self cell]);
+}
+
+- (ViewID)viewID {
+ return VIEW_ID_FIND_IN_PAGE_TEXT_FIELD;
+}
+
+- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info {
+ // When a drag enters the text field, focus the field. This will swap in the
+ // field editor, which will then handle the drag itself.
+ [[self window] makeFirstResponder:self];
+ return NSDragOperationNone;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/find_bar_text_field_cell.h b/chrome/browser/ui/cocoa/find_bar_text_field_cell.h
new file mode 100644
index 0000000..ee6785f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/find_bar_text_field_cell.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2009 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>
+
+#import "chrome/browser/ui/cocoa/styled_text_field_cell.h"
+
+#include "base/scoped_nsobject.h"
+
+// FindBarTextFieldCell extends StyledTextFieldCell to provide support for a
+// results label rooted at the right edge of the cell.
+@interface FindBarTextFieldCell : StyledTextFieldCell {
+ @private
+ // Set if there is a results label to display on the right side of the cell.
+ scoped_nsobject<NSAttributedString> resultsString_;
+}
+
+// Sets the results label to the localized equivalent of "X of Y".
+- (void)setActiveMatch:(NSInteger)current of:(NSInteger)total;
+
+- (void)clearResults;
+
+@end
diff --git a/chrome/browser/ui/cocoa/find_bar_text_field_cell.mm b/chrome/browser/ui/cocoa/find_bar_text_field_cell.mm
new file mode 100644
index 0000000..3f93766
--- /dev/null
+++ b/chrome/browser/ui/cocoa/find_bar_text_field_cell.mm
@@ -0,0 +1,119 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/find_bar_text_field_cell.h"
+
+#include "app/l10n_util.h"
+#include "base/logging.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+#include "grit/generated_resources.h"
+
+namespace {
+
+const CGFloat kBaselineAdjust = 1.0;
+
+// How far to offset the keyword token into the field.
+const NSInteger kResultsXOffset = 3;
+
+// How much width (beyond text) to add to the keyword token on each
+// side.
+const NSInteger kResultsTokenInset = 3;
+
+// How far to shift bounding box of hint down from top of field.
+// Assumes -setFlipped:YES.
+const NSInteger kResultsYOffset = 4;
+
+// How far the editor insets itself, for purposes of determining if
+// decorations need to be trimmed.
+const CGFloat kEditorHorizontalInset = 3.0;
+
+// Conveniences to centralize width+offset calculations.
+CGFloat WidthForResults(NSAttributedString* resultsString) {
+ return kResultsXOffset + ceil([resultsString size].width) +
+ 2 * kResultsTokenInset;
+}
+
+} // namespace
+
+@implementation FindBarTextFieldCell
+
+- (CGFloat)baselineAdjust {
+ return kBaselineAdjust;
+}
+
+- (CGFloat)cornerRadius {
+ return 4.0;
+}
+
+- (StyledTextFieldCellRoundedFlags)roundedFlags {
+ return StyledTextFieldCellRoundedLeft;
+}
+
+// @synthesize doesn't seem to compile for this transition.
+- (NSAttributedString*)resultsString {
+ return resultsString_.get();
+}
+
+// Convenience for the attributes used in the right-justified info
+// cells. Sets the background color to red if |foundMatches| is YES.
+- (NSDictionary*)resultsAttributes:(BOOL)foundMatches {
+ scoped_nsobject<NSMutableParagraphStyle> style(
+ [[NSMutableParagraphStyle alloc] init]);
+ [style setAlignment:NSRightTextAlignment];
+
+ return [NSDictionary dictionaryWithObjectsAndKeys:
+ [self font], NSFontAttributeName,
+ [NSColor lightGrayColor], NSForegroundColorAttributeName,
+ [NSColor whiteColor], NSBackgroundColorAttributeName,
+ style.get(), NSParagraphStyleAttributeName,
+ nil];
+}
+
+- (void)setActiveMatch:(NSInteger)current of:(NSInteger)total {
+ NSString* results =
+ base::SysUTF16ToNSString(l10n_util::GetStringFUTF16(
+ IDS_FIND_IN_PAGE_COUNT,
+ base::IntToString16(current),
+ base::IntToString16(total)));
+ resultsString_.reset([[NSAttributedString alloc]
+ initWithString:results
+ attributes:[self resultsAttributes:(total > 0)]]);
+}
+
+- (void)clearResults {
+ resultsString_.reset(nil);
+}
+
+- (NSRect)textFrameForFrame:(NSRect)cellFrame {
+ NSRect textFrame([super textFrameForFrame:cellFrame]);
+ if (resultsString_)
+ textFrame.size.width -= WidthForResults(resultsString_);
+ return textFrame;
+}
+
+// Do not show the I-beam cursor over the results label.
+- (NSRect)textCursorFrameForFrame:(NSRect)cellFrame {
+ return [self textFrameForFrame:cellFrame];
+}
+
+- (void)drawResultsWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
+ DCHECK(resultsString_);
+
+ NSRect textFrame = [self textFrameForFrame:cellFrame];
+ NSRect infoFrame(NSMakeRect(NSMaxX(textFrame),
+ cellFrame.origin.y + kResultsYOffset,
+ ceil([resultsString_ size].width),
+ cellFrame.size.height - kResultsYOffset));
+ [resultsString_.get() drawInRect:infoFrame];
+}
+
+- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
+ if (resultsString_)
+ [self drawResultsWithFrame:cellFrame inView:controlView];
+ [super drawInteriorWithFrame:cellFrame inView:controlView];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/find_bar_text_field_cell_unittest.mm b/chrome/browser/ui/cocoa/find_bar_text_field_cell_unittest.mm
new file mode 100644
index 0000000..1448632
--- /dev/null
+++ b/chrome/browser/ui/cocoa/find_bar_text_field_cell_unittest.mm
@@ -0,0 +1,135 @@
+// Copyright (c) 2009 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 "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/find_bar_text_field_cell.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+@interface FindBarTextFieldCell (ExposedForTesting)
+- (NSAttributedString*)resultsString;
+@end
+
+@implementation FindBarTextFieldCell (ExposedForTesting)
+- (NSAttributedString*)resultsString {
+ return resultsString_.get();
+}
+@end
+
+namespace {
+
+// Width of the field so that we don't have to ask |field_| for it all
+// the time.
+const CGFloat kWidth(300.0);
+
+// A narrow width for tests which test things that don't fit.
+const CGFloat kNarrowWidth(5.0);
+
+class FindBarTextFieldCellTest : public CocoaTest {
+ public:
+ FindBarTextFieldCellTest() {
+ // Make sure this is wide enough to play games with the cell
+ // decorations.
+ const NSRect frame = NSMakeRect(0, 0, kWidth, 30);
+
+ scoped_nsobject<FindBarTextFieldCell> cell(
+ [[FindBarTextFieldCell alloc] initTextCell:@"Testing"]);
+ cell_ = cell;
+ [cell_ setEditable:YES];
+ [cell_ setBordered:YES];
+
+ scoped_nsobject<NSTextField> view(
+ [[NSTextField alloc] initWithFrame:frame]);
+ view_ = view;
+ [view_ setCell:cell_];
+
+ [[test_window() contentView] addSubview:view_];
+ }
+
+ NSTextField* view_;
+ FindBarTextFieldCell* cell_;
+};
+
+// Basic view tests (AddRemove, Display).
+TEST_VIEW(FindBarTextFieldCellTest, view_);
+
+// Test drawing, mostly to ensure nothing leaks or crashes.
+TEST_F(FindBarTextFieldCellTest, FocusedDisplay) {
+ [view_ display];
+
+ // Test focused drawing.
+ [test_window() makePretendKeyWindowAndSetFirstResponder:view_];
+ [view_ display];
+ [test_window() clearPretendKeyWindowAndFirstResponder];
+
+ // Test display of various cell configurations.
+ [cell_ setActiveMatch:4 of:30];
+ [view_ display];
+
+ [cell_ setActiveMatch:0 of:0];
+ [view_ display];
+
+ [cell_ clearResults];
+ [view_ display];
+}
+
+// Verify that setting and clearing the find results changes the results string
+// appropriately.
+TEST_F(FindBarTextFieldCellTest, SetAndClearFindResults) {
+ [cell_ setActiveMatch:10 of:30];
+ scoped_nsobject<NSAttributedString> tenString([[cell_ resultsString] copy]);
+ EXPECT_GT([tenString length], 0U);
+
+ [cell_ setActiveMatch:0 of:0];
+ scoped_nsobject<NSAttributedString> zeroString([[cell_ resultsString] copy]);
+ EXPECT_GT([zeroString length], 0U);
+ EXPECT_FALSE([tenString isEqualToAttributedString:zeroString]);
+
+ [cell_ clearResults];
+ EXPECT_EQ(0U, [[cell_ resultsString] length]);
+}
+
+TEST_F(FindBarTextFieldCellTest, TextFrame) {
+ const NSRect bounds = [view_ bounds];
+ NSRect textFrame = [cell_ textFrameForFrame:bounds];
+ NSRect cursorFrame = [cell_ textCursorFrameForFrame:bounds];
+
+ // At default settings, everything goes to the text area.
+ EXPECT_FALSE(NSIsEmptyRect(textFrame));
+ EXPECT_TRUE(NSContainsRect(bounds, textFrame));
+ EXPECT_EQ(NSMinX(bounds), NSMinX(textFrame));
+ EXPECT_EQ(NSMaxX(bounds), NSMaxX(textFrame));
+ EXPECT_TRUE(NSEqualRects(cursorFrame, textFrame));
+
+ // Setting an active match leaves text frame to left.
+ [cell_ setActiveMatch:4 of:5];
+ textFrame = [cell_ textFrameForFrame:bounds];
+ cursorFrame = [cell_ textCursorFrameForFrame:bounds];
+ EXPECT_FALSE(NSIsEmptyRect(textFrame));
+ EXPECT_TRUE(NSContainsRect(bounds, textFrame));
+ EXPECT_LT(NSMaxX(textFrame), NSMaxX(bounds));
+ EXPECT_TRUE(NSEqualRects(cursorFrame, textFrame));
+
+}
+
+// The editor frame should be slightly inset from the text frame.
+TEST_F(FindBarTextFieldCellTest, DrawingRectForBounds) {
+ const NSRect bounds = [view_ bounds];
+ NSRect textFrame = [cell_ textFrameForFrame:bounds];
+ NSRect drawingRect = [cell_ drawingRectForBounds:bounds];
+
+ EXPECT_FALSE(NSIsEmptyRect(drawingRect));
+ EXPECT_TRUE(NSContainsRect(textFrame, NSInsetRect(drawingRect, 1, 1)));
+
+ [cell_ setActiveMatch:4 of:5];
+ textFrame = [cell_ textFrameForFrame:bounds];
+ drawingRect = [cell_ drawingRectForBounds:bounds];
+ EXPECT_FALSE(NSIsEmptyRect(drawingRect));
+ EXPECT_TRUE(NSContainsRect(textFrame, NSInsetRect(drawingRect, 1, 1)));
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/find_bar_text_field_unittest.mm b/chrome/browser/ui/cocoa/find_bar_text_field_unittest.mm
new file mode 100644
index 0000000..382a870
--- /dev/null
+++ b/chrome/browser/ui/cocoa/find_bar_text_field_unittest.mm
@@ -0,0 +1,92 @@
+// Copyright (c) 2009 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>
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/find_bar_text_field.h"
+#import "chrome/browser/ui/cocoa/find_bar_text_field_cell.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+
+// OCMock wants to mock a concrete class or protocol. This should
+// provide a correct protocol for newer versions of the SDK, while
+// providing something mockable for older versions.
+
+@protocol MockTextEditingDelegate<NSControlTextEditingDelegate>
+- (void)controlTextDidBeginEditing:(NSNotification*)aNotification;
+- (BOOL)control:(NSControl*)control textShouldEndEditing:(NSText*)fieldEditor;
+@end
+
+namespace {
+
+// Width of the field so that we don't have to ask |field_| for it all
+// the time.
+static const CGFloat kWidth(300.0);
+
+class FindBarTextFieldTest : public CocoaTest {
+ public:
+ FindBarTextFieldTest() {
+ // Make sure this is wide enough to play games with the cell
+ // decorations.
+ NSRect frame = NSMakeRect(0, 0, kWidth, 30);
+ scoped_nsobject<FindBarTextField> field(
+ [[FindBarTextField alloc] initWithFrame:frame]);
+ field_ = field.get();
+
+ [field_ setStringValue:@"Test test"];
+ [[test_window() contentView] addSubview:field_];
+ }
+
+ FindBarTextField* field_;
+};
+
+// Basic view tests (AddRemove, Display).
+TEST_VIEW(FindBarTextFieldTest, field_);
+
+// Test that we have the right cell class.
+TEST_F(FindBarTextFieldTest, CellClass) {
+ EXPECT_TRUE([[field_ cell] isKindOfClass:[FindBarTextFieldCell class]]);
+}
+
+// Test that we get the same cell from -cell and
+// -findBarTextFieldCell.
+TEST_F(FindBarTextFieldTest, Cell) {
+ FindBarTextFieldCell* cell = [field_ findBarTextFieldCell];
+ EXPECT_EQ(cell, [field_ cell]);
+ EXPECT_TRUE(cell != nil);
+}
+
+// Test that becoming first responder sets things up correctly.
+TEST_F(FindBarTextFieldTest, FirstResponder) {
+ EXPECT_EQ(nil, [field_ currentEditor]);
+ EXPECT_EQ([[field_ subviews] count], 0U);
+ [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
+ EXPECT_FALSE(nil == [field_ currentEditor]);
+ EXPECT_EQ([[field_ subviews] count], 1U);
+ EXPECT_TRUE([[field_ currentEditor] isDescendantOf:field_]);
+}
+
+// Test drawing, mostly to ensure nothing leaks or crashes.
+TEST_F(FindBarTextFieldTest, Display) {
+ [field_ display];
+
+ // Test focussed drawing.
+ [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
+ [field_ display];
+ [test_window() clearPretendKeyWindowAndFirstResponder];
+
+ // Test display of various cell configurations.
+ FindBarTextFieldCell* cell = [field_ findBarTextFieldCell];
+ [cell setActiveMatch:4 of:5];
+ [field_ display];
+
+ [cell clearResults];
+ [field_ display];
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/find_bar_view.h b/chrome/browser/ui/cocoa/find_bar_view.h
new file mode 100644
index 0000000..ff5753d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/find_bar_view.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_FIND_BAR_VIEW_H_
+#define CHROME_BROWSER_UI_COCOA_FIND_BAR_VIEW_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "chrome/browser/ui/cocoa/background_gradient_view.h"
+
+// A view that handles painting the border for the FindBar.
+
+@interface FindBarView : BackgroundGradientView {
+}
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_FIND_BAR_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/find_bar_view.mm b/chrome/browser/ui/cocoa/find_bar_view.mm
new file mode 100644
index 0000000..5e1ce21
--- /dev/null
+++ b/chrome/browser/ui/cocoa/find_bar_view.mm
@@ -0,0 +1,131 @@
+// 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 "chrome/browser/ui/cocoa/find_bar_view.h"
+
+#import "chrome/browser/ui/cocoa/themed_window.h"
+#import "chrome/browser/ui/cocoa/url_drop_target.h"
+#import "chrome/browser/ui/cocoa/view_id_util.h"
+
+namespace {
+CGFloat kCurveSize = 8;
+} // end namespace
+
+@implementation FindBarView
+
+- (void)awakeFromNib {
+ // Register for all the drag types handled by the RWHVCocoa.
+ [self registerForDraggedTypes:[URLDropTargetHandler handledDragTypes]];
+}
+
+- (void)drawRect:(NSRect)rect {
+ // TODO(rohitrao): Make this prettier.
+ rect = NSInsetRect([self bounds], 0.5, 0.5);
+ rect = NSOffsetRect(rect, 0, 1.0);
+
+ NSPoint topLeft = NSMakePoint(NSMinX(rect), NSMaxY(rect));
+ NSPoint topRight = NSMakePoint(NSMaxX(rect), NSMaxY(rect));
+ NSPoint midLeft1 =
+ NSMakePoint(NSMinX(rect) + kCurveSize, NSMaxY(rect) - kCurveSize);
+ NSPoint midLeft2 =
+ NSMakePoint(NSMinX(rect) + kCurveSize, NSMinY(rect) + kCurveSize);
+ NSPoint midRight1 =
+ NSMakePoint(NSMaxX(rect) - kCurveSize, NSMinY(rect) + kCurveSize);
+ NSPoint midRight2 =
+ NSMakePoint(NSMaxX(rect) - kCurveSize, NSMaxY(rect) - kCurveSize);
+ NSPoint bottomLeft =
+ NSMakePoint(NSMinX(rect) + (2 * kCurveSize), NSMinY(rect));
+ NSPoint bottomRight =
+ NSMakePoint(NSMaxX(rect) - (2 * kCurveSize), NSMinY(rect));
+
+ NSBezierPath* path = [NSBezierPath bezierPath];
+ [path moveToPoint:topLeft];
+ [path curveToPoint:midLeft1
+ controlPoint1:NSMakePoint(midLeft1.x, topLeft.y)
+ controlPoint2:NSMakePoint(midLeft1.x, topLeft.y)];
+ [path lineToPoint:midLeft2];
+ [path curveToPoint:bottomLeft
+ controlPoint1:NSMakePoint(midLeft2.x, bottomLeft.y)
+ controlPoint2:NSMakePoint(midLeft2.x, bottomLeft.y)];
+
+ [path lineToPoint:bottomRight];
+ [path curveToPoint:midRight1
+ controlPoint1:NSMakePoint(midRight1.x, bottomLeft.y)
+ controlPoint2:NSMakePoint(midRight1.x, bottomLeft.y)];
+ [path lineToPoint:midRight2];
+ [path curveToPoint:topRight
+ controlPoint1:NSMakePoint(midRight2.x, topLeft.y)
+ controlPoint2:NSMakePoint(midRight2.x, topLeft.y)];
+ NSGraphicsContext* context = [NSGraphicsContext currentContext];
+ [context saveGraphicsState];
+ [path addClip];
+
+ // Set the pattern phase
+ NSPoint phase = [[self window] themePatternPhase];
+
+ [context setPatternPhase:phase];
+ [super drawBackground];
+ [context restoreGraphicsState];
+
+ [[self strokeColor] set];
+ [path stroke];
+}
+
+// The findbar is mostly opaque, but has an 8px transparent border on the left
+// and right sides (see |kCurveSize|). This is an artifact of the way it is
+// drawn. We override hitTest to return nil for points in this transparent
+// area.
+- (NSView*)hitTest:(NSPoint)point {
+ NSView* hitView = [super hitTest:point];
+ if (hitView == self) {
+ // |rect| is approximately equivalent to the opaque area of the findbar.
+ NSRect rect = NSInsetRect([self bounds], kCurveSize, 0);
+ if (!NSMouseInRect(point, rect, [self isFlipped]))
+ return nil;
+ }
+
+ return hitView;
+}
+
+// Eat all mouse events, to prevent clicks from falling through to views below.
+- (void)mouseDown:(NSEvent *)theEvent {
+}
+
+- (void)rightMouseDown:(NSEvent *)theEvent {
+}
+
+- (void)otherMouseDown:(NSEvent *)theEvent {
+}
+
+- (void)mouseUp:(NSEvent *)theEvent {
+}
+
+- (void)rightMouseUp:(NSEvent *)theEvent {
+}
+
+- (void)otherMouseUp:(NSEvent *)theEvent {
+}
+
+- (void)mouseMoved:(NSEvent *)theEvent {
+}
+
+- (void)mouseDragged:(NSEvent *)theEvent {
+}
+
+- (void)rightMouseDragged:(NSEvent *)theEvent {
+}
+
+- (void)otherMouseDragged:(NSEvent *)theEvent {
+}
+
+// Eat drag operations, to prevent drags from going through to the views below.
+- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info {
+ return NSDragOperationNone;
+}
+
+- (ViewID)viewID {
+ return VIEW_ID_FIND_IN_PAGE;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/find_bar_view_unittest.mm b/chrome/browser/ui/cocoa/find_bar_view_unittest.mm
new file mode 100644
index 0000000..639b5ef
--- /dev/null
+++ b/chrome/browser/ui/cocoa/find_bar_view_unittest.mm
@@ -0,0 +1,90 @@
+// Copyright (c) 2009 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 "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/find_bar_view.h"
+#include "chrome/browser/ui/cocoa/test_event_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+@interface MouseDownViewPong : NSView {
+ BOOL pong_;
+}
+@property (nonatomic, assign) BOOL pong;
+@end
+
+@implementation MouseDownViewPong
+@synthesize pong = pong_;
+- (void)mouseDown:(NSEvent*)event {
+ pong_ = YES;
+}
+@end
+
+
+namespace {
+
+class FindBarViewTest : public CocoaTest {
+ public:
+ FindBarViewTest() {
+ NSRect frame = NSMakeRect(0, 0, 100, 30);
+ scoped_nsobject<FindBarView> view(
+ [[FindBarView alloc] initWithFrame:frame]);
+ view_ = view.get();
+ [[test_window() contentView] addSubview:view_];
+ }
+
+ FindBarView* view_;
+};
+
+TEST_VIEW(FindBarViewTest, view_)
+
+TEST_F(FindBarViewTest, FindBarEatsMouseClicksInBackgroundArea) {
+ scoped_nsobject<MouseDownViewPong> pongView(
+ [[MouseDownViewPong alloc] initWithFrame:NSMakeRect(0, 0, 200, 200)]);
+
+ // Remove all of the subviews of the findbar, to make sure we don't
+ // accidentally hit a subview when trying to simulate a click in the
+ // background area.
+ [view_ setSubviews:[NSArray array]];
+ [view_ setFrame:NSMakeRect(0, 0, 200, 200)];
+
+ // Add the pong view as a sibling of the findbar.
+ [[test_window() contentView] addSubview:pongView.get()
+ positioned:NSWindowBelow
+ relativeTo:view_];
+
+ // Synthesize a mousedown event and send it to the window. The event is
+ // placed in the center of the find bar.
+ NSPoint pointInCenterOfFindBar = NSMakePoint(100, 100);
+ [pongView setPong:NO];
+ [test_window()
+ sendEvent:test_event_utils::LeftMouseDownAtPoint(pointInCenterOfFindBar)];
+ // Click gets eaten by findbar, not passed through to underlying view.
+ EXPECT_FALSE([pongView pong]);
+}
+
+TEST_F(FindBarViewTest, FindBarPassesThroughClicksInTransparentArea) {
+ scoped_nsobject<MouseDownViewPong> pongView(
+ [[MouseDownViewPong alloc] initWithFrame:NSMakeRect(0, 0, 200, 200)]);
+ [view_ setFrame:NSMakeRect(0, 0, 200, 200)];
+
+ // Add the pong view as a sibling of the findbar.
+ [[test_window() contentView] addSubview:pongView.get()
+ positioned:NSWindowBelow
+ relativeTo:view_];
+
+ // Synthesize a mousedown event and send it to the window. The event is inset
+ // a few pixels from the lower left corner of the window, which places it in
+ // the transparent area surrounding the findbar.
+ NSPoint pointInTransparentArea = NSMakePoint(2, 2);
+ [pongView setPong:NO];
+ [test_window()
+ sendEvent:test_event_utils::LeftMouseDownAtPoint(pointInTransparentArea)];
+ // Click is ignored by findbar, passed through to underlying view.
+ EXPECT_TRUE([pongView pong]);
+}
+} // namespace
diff --git a/chrome/browser/ui/cocoa/find_pasteboard.h b/chrome/browser/ui/cocoa/find_pasteboard.h
new file mode 100644
index 0000000..f7153f6
--- /dev/null
+++ b/chrome/browser/ui/cocoa/find_pasteboard.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_FIND_PASTEBOARD_H_
+#define CHROME_BROWSER_UI_COCOA_FIND_PASTEBOARD_H_
+#pragma once
+
+#include "base/string16.h"
+
+#ifdef __OBJC__
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+
+extern NSString* kFindPasteboardChangedNotification;
+
+// Manages the find pasteboard. Use this to copy text to the find pasteboard,
+// to get the text currently on the find pasteboard, and to receive
+// notifications when the text on the find pasteboard has changed. You should
+// always use this class instead of accessing
+// [NSPasteboard pasteboardWithName:NSFindPboard] directly.
+//
+// This is not thread-safe and must be used on the main thread.
+//
+// This is supposed to be a singleton.
+@interface FindPasteboard : NSObject {
+ @private
+ scoped_nsobject<NSString> findText_;
+}
+
+// Returns the singleton instance of this class.
++ (FindPasteboard*)sharedInstance;
+
+// Returns the current find text. This is never nil; if there is no text on the
+// find pasteboard, this returns an empty string.
+- (NSString*)findText;
+
+// Sets the current find text to |newText| and sends a
+// |kFindPasteboardChangedNotification| to the default notification center if
+// it the new text different from the current text. |newText| must not be nil.
+- (void)setFindText:(NSString*)newText;
+@end
+
+@interface FindPasteboard (TestingAPI)
+- (void)loadTextFromPasteboard:(NSNotification*)notification;
+
+// This methods is meant to be overridden in tests.
+- (NSPasteboard*)findPboard;
+@end
+
+#endif // __OBJC__
+
+// Also provide a c++ interface
+string16 GetFindPboardText();
+
+#endif // CHROME_BROWSER_UI_COCOA_FIND_PASTEBOARD_H_
diff --git a/chrome/browser/ui/cocoa/find_pasteboard.mm b/chrome/browser/ui/cocoa/find_pasteboard.mm
new file mode 100644
index 0000000..0e86111
--- /dev/null
+++ b/chrome/browser/ui/cocoa/find_pasteboard.mm
@@ -0,0 +1,82 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/find_pasteboard.h"
+
+#include "base/logging.h"
+#include "base/sys_string_conversions.h"
+
+NSString* kFindPasteboardChangedNotification =
+ @"kFindPasteboardChangedNotification_Chrome";
+
+@implementation FindPasteboard
+
++ (FindPasteboard*)sharedInstance {
+ static FindPasteboard* instance = nil;
+ if (!instance) {
+ instance = [[FindPasteboard alloc] init];
+ }
+ return instance;
+}
+
+- (id)init {
+ if ((self = [super init])) {
+ findText_.reset([[NSString alloc] init]);
+
+ // Check if the text in the findboard has changed on app activate.
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(loadTextFromPasteboard:)
+ name:NSApplicationDidBecomeActiveNotification
+ object:nil];
+ [self loadTextFromPasteboard:nil];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ // Since this is a singleton, this should only be executed in test code.
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+- (NSPasteboard*)findPboard {
+ return [NSPasteboard pasteboardWithName:NSFindPboard];
+}
+
+- (void)loadTextFromPasteboard:(NSNotification*)notification {
+ NSPasteboard* findPboard = [self findPboard];
+ if ([[findPboard types] containsObject:NSStringPboardType])
+ [self setFindText:[findPboard stringForType:NSStringPboardType]];
+}
+
+- (NSString*)findText {
+ return findText_;
+}
+
+- (void)setFindText:(NSString*)newText {
+ DCHECK(newText);
+ if (!newText)
+ return;
+
+ DCHECK([NSThread isMainThread]);
+
+ BOOL needToSendNotification = ![findText_.get() isEqualToString:newText];
+ if (needToSendNotification) {
+ findText_.reset([newText copy]);
+ NSPasteboard* findPboard = [self findPboard];
+ [findPboard declareTypes:[NSArray arrayWithObject:NSStringPboardType]
+ owner:nil];
+ [findPboard setString:findText_.get() forType:NSStringPboardType];
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName:kFindPasteboardChangedNotification
+ object:self];
+ }
+}
+
+@end
+
+string16 GetFindPboardText() {
+ return base::SysNSStringToUTF16([[FindPasteboard sharedInstance] findText]);
+}
diff --git a/chrome/browser/ui/cocoa/find_pasteboard_unittest.mm b/chrome/browser/ui/cocoa/find_pasteboard_unittest.mm
new file mode 100644
index 0000000..739eff3
--- /dev/null
+++ b/chrome/browser/ui/cocoa/find_pasteboard_unittest.mm
@@ -0,0 +1,115 @@
+// Copyright (c) 2009 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 "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/find_pasteboard.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+// A subclass of FindPasteboard that doesn't write to the real find pasteboard.
+@interface FindPasteboardTesting : FindPasteboard {
+ @public
+ int notificationCount_;
+ @private
+ NSPasteboard* pboard_;
+}
+- (NSPasteboard*)findPboard;
+
+- (void)callback:(id)sender;
+
+// These are for checking that pasteboard content is copied to/from the
+// FindPasteboard correctly.
+- (NSString*)findPboardText;
+- (void)setFindPboardText:(NSString*)text;
+@end
+
+@implementation FindPasteboardTesting
+
+- (id)init {
+ if ((self = [super init])) {
+ pboard_ = [NSPasteboard pasteboardWithUniqueName];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [pboard_ releaseGlobally];
+ [super dealloc];
+}
+
+- (NSPasteboard*)findPboard {
+ return pboard_;
+}
+
+- (void)callback:(id)sender {
+ ++notificationCount_;
+}
+
+- (void)setFindPboardText:(NSString*)text {
+ [pboard_ declareTypes:[NSArray arrayWithObject:NSStringPboardType]
+ owner:nil];
+ [pboard_ setString:text forType:NSStringPboardType];
+}
+
+- (NSString*)findPboardText {
+ return [pboard_ stringForType:NSStringPboardType];
+}
+@end
+
+namespace {
+
+class FindPasteboardTest : public CocoaTest {
+ public:
+ FindPasteboardTest() {
+ pboard_.reset([[FindPasteboardTesting alloc] init]);
+ }
+ protected:
+ scoped_nsobject<FindPasteboardTesting> pboard_;
+};
+
+TEST_F(FindPasteboardTest, SettingTextUpdatesPboard) {
+ [pboard_.get() setFindText:@"text"];
+ EXPECT_EQ(
+ NSOrderedSame,
+ [[pboard_.get() findPboardText] compare:@"text"]);
+}
+
+TEST_F(FindPasteboardTest, ReadingFromPboardUpdatesFindText) {
+ [pboard_.get() setFindPboardText:@"text"];
+ [pboard_.get() loadTextFromPasteboard:nil];
+ EXPECT_EQ(
+ NSOrderedSame,
+ [[pboard_.get() findText] compare:@"text"]);
+}
+
+TEST_F(FindPasteboardTest, SendsNotificationWhenTextChanges) {
+ [[NSNotificationCenter defaultCenter]
+ addObserver:pboard_.get()
+ selector:@selector(callback:)
+ name:kFindPasteboardChangedNotification
+ object:pboard_.get()];
+ EXPECT_EQ(0, pboard_.get()->notificationCount_);
+ [pboard_.get() setFindText:@"text"];
+ EXPECT_EQ(1, pboard_.get()->notificationCount_);
+ [pboard_.get() setFindText:@"text"];
+ EXPECT_EQ(1, pboard_.get()->notificationCount_);
+ [pboard_.get() setFindText:@"other text"];
+ EXPECT_EQ(2, pboard_.get()->notificationCount_);
+
+ [pboard_.get() setFindPboardText:@"other text"];
+ [pboard_.get() loadTextFromPasteboard:nil];
+ EXPECT_EQ(2, pboard_.get()->notificationCount_);
+
+ [pboard_.get() setFindPboardText:@"otherer text"];
+ [pboard_.get() loadTextFromPasteboard:nil];
+ EXPECT_EQ(3, pboard_.get()->notificationCount_);
+
+ [[NSNotificationCenter defaultCenter] removeObserver:pboard_.get()];
+}
+
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/first_run_bubble_controller.h b/chrome/browser/ui/cocoa/first_run_bubble_controller.h
new file mode 100644
index 0000000..5c5f768
--- /dev/null
+++ b/chrome/browser/ui/cocoa/first_run_bubble_controller.h
@@ -0,0 +1,24 @@
+// 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>
+
+#import "chrome/browser/ui/cocoa/base_bubble_controller.h"
+
+class Profile;
+
+// Manages the first run bubble.
+@interface FirstRunBubbleController : BaseBubbleController {
+ @private
+ // Header label.
+ IBOutlet NSTextField* header_;
+
+ Profile* profile_;
+}
+
+// Creates and shows a firstRun bubble.
++ (FirstRunBubbleController*) showForView:(NSView*)view
+ offset:(NSPoint)offset
+ profile:(Profile*)profile;
+@end
diff --git a/chrome/browser/ui/cocoa/first_run_bubble_controller.mm b/chrome/browser/ui/cocoa/first_run_bubble_controller.mm
new file mode 100644
index 0000000..d4fa202
--- /dev/null
+++ b/chrome/browser/ui/cocoa/first_run_bubble_controller.mm
@@ -0,0 +1,82 @@
+// 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 "chrome/browser/ui/cocoa/first_run_bubble_controller.h"
+
+#include "app/l10n_util.h"
+#include "base/logging.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/search_engines/util.h"
+#import "chrome/browser/ui/cocoa/l10n_util.h"
+#import "chrome/browser/ui/cocoa/info_bubble_view.h"
+#include "grit/generated_resources.h"
+
+@interface FirstRunBubbleController(Private)
+- (id)initRelativeToView:(NSView*)view
+ offset:(NSPoint)offset
+ profile:(Profile*)profile;
+- (void)closeIfNotKey;
+@end
+
+@implementation FirstRunBubbleController
+
++ (FirstRunBubbleController*) showForView:(NSView*)view
+ offset:(NSPoint)offset
+ profile:(Profile*)profile {
+ // Autoreleases itself on bubble close.
+ return [[FirstRunBubbleController alloc] initRelativeToView:view
+ offset:offset
+ profile:profile];
+}
+
+- (id)initRelativeToView:(NSView*)view
+ offset:(NSPoint)offset
+ profile:(Profile*)profile {
+ if ((self = [super initWithWindowNibPath:@"FirstRunBubble"
+ relativeToView:view
+ offset:offset])) {
+ profile_ = profile;
+ [self showWindow:nil];
+
+ // On 10.5, the first run bubble sometimes does not disappear when clicking
+ // the omnibox. This happens if the bubble never became key, due to it
+ // showing up so early in the startup sequence. As a workaround, close it
+ // automatically after a few seconds if it doesn't become key.
+ // http://crbug.com/52726
+ [self performSelector:@selector(closeIfNotKey) withObject:nil afterDelay:3];
+ }
+ return self;
+}
+
+- (void)awakeFromNib {
+ DCHECK(header_);
+ [header_ setStringValue:cocoa_l10n_util::ReplaceNSStringPlaceholders(
+ [header_ stringValue], GetDefaultSearchEngineName(profile_), NULL)];
+
+ // Adapt window size to bottom buttons. Do this before all other layouting.
+ CGFloat dy = cocoa_l10n_util::VerticallyReflowGroup([[self bubble] subviews]);
+ NSSize ds = NSMakeSize(0, dy);
+ ds = [[self bubble] convertSize:ds toView:nil];
+
+ NSRect frame = [[self window] frame];
+ frame.origin.y -= ds.height;
+ frame.size.height += ds.height;
+ [[self window] setFrame:frame display:YES];
+}
+
+- (void)close {
+ // If the window is closed before the timer is fired, cancel the timer, since
+ // it retains the controller.
+ [NSObject cancelPreviousPerformRequestsWithTarget:self
+ selector:@selector(closeIfNotKey)
+ object:nil];
+ [super close];
+}
+
+- (void)closeIfNotKey {
+ if (![[self window] isKeyWindow])
+ [self close];
+}
+
+@end // FirstRunBubbleController
diff --git a/chrome/browser/ui/cocoa/first_run_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/first_run_bubble_controller_unittest.mm
new file mode 100644
index 0000000..d9f37c9
--- /dev/null
+++ b/chrome/browser/ui/cocoa/first_run_bubble_controller_unittest.mm
@@ -0,0 +1,44 @@
+// 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 "chrome/browser/ui/cocoa/first_run_bubble_controller.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/debug/debugger.h"
+#include "base/scoped_nsobject.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class FirstRunBubbleControllerTest : public CocoaTest {
+ public:
+ BrowserTestHelper helper_;
+};
+
+// Check that the bubble doesn't crash or leak.
+TEST_F(FirstRunBubbleControllerTest, Init) {
+ scoped_nsobject<NSWindow> parent([[NSWindow alloc]
+ initWithContentRect:NSMakeRect(0, 0, 800, 600)
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO]);
+ [parent setReleasedWhenClosed:NO];
+ if (base::debug::BeingDebugged())
+ [parent.get() orderFront:nil];
+ else
+ [parent.get() orderBack:nil];
+
+ FirstRunBubbleController* controller = [FirstRunBubbleController
+ showForView:[parent.get() contentView]
+ offset:NSMakePoint(300, 300)
+ profile:helper_.profile()];
+ EXPECT_TRUE(controller != nil);
+ EXPECT_TRUE([[controller window] isVisible]);
+ [parent.get() close];
+}
+
+} // namespace
diff --git a/chrome/browser/cocoa/first_run_dialog.h b/chrome/browser/ui/cocoa/first_run_dialog.h
index 3e575a3..3e575a3 100644
--- a/chrome/browser/cocoa/first_run_dialog.h
+++ b/chrome/browser/ui/cocoa/first_run_dialog.h
diff --git a/chrome/browser/ui/cocoa/first_run_dialog.mm b/chrome/browser/ui/cocoa/first_run_dialog.mm
new file mode 100644
index 0000000..9590b9b
--- /dev/null
+++ b/chrome/browser/ui/cocoa/first_run_dialog.mm
@@ -0,0 +1,195 @@
+// 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 "chrome/browser/ui/cocoa/first_run_dialog.h"
+
+#include "app/l10n_util_mac.h"
+#include "base/mac_util.h"
+#include "base/message_loop.h"
+#include "base/ref_counted.h"
+#include "grit/locale_settings.h"
+#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
+
+@interface FirstRunDialogController (PrivateMethods)
+// Show the dialog.
+- (void)show;
+@end
+
+namespace {
+
+// Compare function for -[NSArray sortedArrayUsingFunction:context:] that
+// sorts the views in Y order bottom up.
+NSInteger CompareFrameY(id view1, id view2, void* context) {
+ CGFloat y1 = NSMinY([view1 frame]);
+ CGFloat y2 = NSMinY([view2 frame]);
+ if (y1 < y2)
+ return NSOrderedAscending;
+ else if (y1 > y2)
+ return NSOrderedDescending;
+ else
+ return NSOrderedSame;
+}
+
+class FirstRunShowBridge : public base::RefCounted<FirstRunShowBridge> {
+ public:
+ FirstRunShowBridge(FirstRunDialogController* controller);
+
+ void ShowDialog();
+ private:
+ FirstRunDialogController* controller_;
+};
+
+FirstRunShowBridge::FirstRunShowBridge(
+ FirstRunDialogController* controller) : controller_(controller) {
+}
+
+void FirstRunShowBridge::ShowDialog() {
+ [controller_ show];
+ MessageLoop::current()->QuitNow();
+}
+
+};
+
+@implementation FirstRunDialogController
+
+@synthesize statsEnabled = statsEnabled_;
+@synthesize makeDefaultBrowser = makeDefaultBrowser_;
+
+- (id)init {
+ NSString* nibpath =
+ [mac_util::MainAppBundle() pathForResource:@"FirstRunDialog"
+ ofType:@"nib"];
+ self = [super initWithWindowNibPath:nibpath owner:self];
+ if (self != nil) {
+ // Bound to the dialog checkbox, default to true.
+ makeDefaultBrowser_ = YES;
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [super dealloc];
+}
+
+- (IBAction)showWindow:(id)sender {
+ // The main MessageLoop has not yet run, but has been spun. If we call
+ // -[NSApplication runModalForWindow:] we will hang <http://crbug.com/54248>.
+ // Therefore the main MessageLoop is run so things work.
+
+ scoped_refptr<FirstRunShowBridge> bridge(new FirstRunShowBridge(self));
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(bridge.get(),
+ &FirstRunShowBridge::ShowDialog));
+ MessageLoop::current()->Run();
+}
+
+- (void)show {
+ NSWindow* win = [self window];
+
+ // Only support the sizing the window once.
+ DCHECK(!beenSized_) << "ShowWindow was called twice?";
+ if (!beenSized_) {
+ beenSized_ = YES;
+ DCHECK_GT([objectsToSize_ count], 0U);
+
+ // Size everything to fit, collecting the widest growth needed (XIB provides
+ // the min size, i.e.-never shrink, just grow).
+ CGFloat largestWidthChange = 0.0;
+ for (NSView* view in objectsToSize_) {
+ DCHECK_NE(statsCheckbox_, view) << "Stats checkbox shouldn't be in list";
+ if (![view isHidden]) {
+ NSSize delta = [GTMUILocalizerAndLayoutTweaker sizeToFitView:view];
+ DCHECK_EQ(delta.height, 0.0)
+ << "Didn't expect anything to change heights";
+ if (largestWidthChange < delta.width)
+ largestWidthChange = delta.width;
+ }
+ }
+
+ // Make the window wide enough to fit everything.
+ if (largestWidthChange > 0.0) {
+ NSView* contentView = [win contentView];
+ NSRect windowFrame = [contentView convertRect:[win frame] fromView:nil];
+ windowFrame.size.width += largestWidthChange;
+ windowFrame = [contentView convertRect:windowFrame toView:nil];
+ [win setFrame:windowFrame display:NO];
+ }
+
+ // The stats checkbox gets some really long text, so it gets word wrapped
+ // and then sized.
+ DCHECK(statsCheckbox_);
+ CGFloat statsCheckboxHeightChange = 0.0;
+ [GTMUILocalizerAndLayoutTweaker wrapButtonTitleForWidth:statsCheckbox_];
+ statsCheckboxHeightChange =
+ [GTMUILocalizerAndLayoutTweaker sizeToFitView:statsCheckbox_].height;
+
+ // Walk bottom up shuffling for all the hidden views.
+ NSArray* subViews =
+ [[[win contentView] subviews] sortedArrayUsingFunction:CompareFrameY
+ context:NULL];
+ CGFloat moveDown = 0.0;
+ NSUInteger numSubViews = [subViews count];
+ for (NSUInteger idx = 0 ; idx < numSubViews ; ++idx) {
+ NSView* view = [subViews objectAtIndex:idx];
+
+ // If the view is hidden, collect the amount to move everything above it
+ // down, if it's not hidden, apply any shift down.
+ if ([view isHidden]) {
+ DCHECK_GT((numSubViews - 1), idx)
+ << "Don't support top view being hidden";
+ NSView* nextView = [subViews objectAtIndex:(idx + 1)];
+ CGFloat viewBottom = [view frame].origin.y;
+ CGFloat nextViewBottom = [nextView frame].origin.y;
+ moveDown += nextViewBottom - viewBottom;
+ } else {
+ if (moveDown != 0.0) {
+ NSPoint origin = [view frame].origin;
+ origin.y -= moveDown;
+ [view setFrameOrigin:origin];
+ }
+ }
+ // Special case, if this is the stats checkbox, everything above it needs
+ // to get moved up by the amount it changed height.
+ if (view == statsCheckbox_) {
+ moveDown -= statsCheckboxHeightChange;
+ }
+ }
+
+ // Resize the window for any height change from hidden views, etc.
+ if (moveDown != 0.0) {
+ NSView* contentView = [win contentView];
+ [contentView setAutoresizesSubviews:NO];
+ NSRect windowFrame = [contentView convertRect:[win frame] fromView:nil];
+ windowFrame.size.height -= moveDown;
+ windowFrame = [contentView convertRect:windowFrame toView:nil];
+ [win setFrame:windowFrame display:NO];
+ [contentView setAutoresizesSubviews:YES];
+ }
+
+ }
+
+ // Neat weirdness in the below code - the Application menu stays enabled
+ // while the window is open but selecting items from it (e.g. Quit) has
+ // no effect. I'm guessing that this is an artifact of us being a
+ // background-only application at this stage and displaying a modal
+ // window.
+
+ // Display dialog.
+ [win center];
+ [NSApp runModalForWindow:win];
+}
+
+- (IBAction)ok:(id)sender {
+ [[self window] close];
+ [NSApp stopModal];
+}
+
+- (IBAction)learnMore:(id)sender {
+ NSString* urlStr = l10n_util::GetNSString(IDS_LEARN_MORE_REPORTING_URL);
+ NSURL* learnMoreUrl = [NSURL URLWithString:urlStr];
+ [[NSWorkspace sharedWorkspace] openURL:learnMoreUrl];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/floating_bar_backing_view.h b/chrome/browser/ui/cocoa/floating_bar_backing_view.h
new file mode 100644
index 0000000..7cd6b2d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/floating_bar_backing_view.h
@@ -0,0 +1,15 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_FLOATING_BAR_BACKING_VIEW_H_
+#define CHROME_BROWSER_UI_COCOA_FLOATING_BAR_BACKING_VIEW_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+// A custom view that draws the tab strip background for fullscreen windows.
+@interface FloatingBarBackingView : NSView
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_FLOATING_BAR_BACKING_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/floating_bar_backing_view.mm b/chrome/browser/ui/cocoa/floating_bar_backing_view.mm
new file mode 100644
index 0000000..70f785c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/floating_bar_backing_view.mm
@@ -0,0 +1,51 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/floating_bar_backing_view.h"
+
+#include "base/mac_util.h"
+#import "chrome/browser/ui/cocoa/browser_frame_view.h"
+
+@implementation FloatingBarBackingView
+
+- (void)drawRect:(NSRect)rect {
+ NSWindow* window = [self window];
+ BOOL isMainWindow = [window isMainWindow];
+
+ if (isMainWindow)
+ [[NSColor windowFrameColor] set];
+ else
+ [[NSColor windowBackgroundColor] set];
+ NSRectFill(rect);
+
+ // TODO(rohitrao): Don't assume -22 here.
+ [BrowserFrameView drawWindowThemeInDirtyRect:rect
+ forView:self
+ bounds:[self bounds]
+ offset:NSMakePoint(0, -22)
+ forceBlackBackground:YES];
+
+}
+
+// Eat all mouse events (and do *not* pass them on to the next responder!).
+- (void)mouseDown:(NSEvent*)event {}
+- (void)rightMouseDown:(NSEvent*)event {}
+- (void)otherMouseDown:(NSEvent*)event {}
+- (void)rightMouseUp:(NSEvent*)event {}
+- (void)otherMouseUp:(NSEvent*)event {}
+- (void)mouseMoved:(NSEvent*)event {}
+- (void)mouseDragged:(NSEvent*)event {}
+- (void)rightMouseDragged:(NSEvent*)event {}
+- (void)otherMouseDragged:(NSEvent*)event {}
+
+// Eat this too, except that ...
+- (void)mouseUp:(NSEvent*)event {
+ // a double-click in the blank area should try to minimize, to be consistent
+ // with double-clicks on the contiguous tab strip area. (It'll fail and beep.)
+ if ([event clickCount] == 2 &&
+ mac_util::ShouldWindowsMiniaturizeOnDoubleClick())
+ [[self window] performMiniaturize:self];
+}
+
+@end // @implementation FloatingBarBackingView
diff --git a/chrome/browser/ui/cocoa/floating_bar_backing_view_unittest.mm b/chrome/browser/ui/cocoa/floating_bar_backing_view_unittest.mm
new file mode 100644
index 0000000..4753a26
--- /dev/null
+++ b/chrome/browser/ui/cocoa/floating_bar_backing_view_unittest.mm
@@ -0,0 +1,26 @@
+// 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 "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/floating_bar_backing_view.h"
+
+namespace {
+
+class FloatingBarBackingViewTest : public CocoaTest {
+ public:
+ FloatingBarBackingViewTest() {
+ NSRect content_frame = [[test_window() contentView] frame];
+ scoped_nsobject<FloatingBarBackingView> view(
+ [[FloatingBarBackingView alloc] initWithFrame:content_frame]);
+ view_ = view.get();
+ [[test_window() contentView] addSubview:view_];
+ }
+
+ FloatingBarBackingView* view_; // Weak. Owned by the view hierarchy.
+};
+
+// Tests display, add/remove.
+TEST_VIEW(FloatingBarBackingViewTest, view_);
+
+} // namespace
diff --git a/chrome/browser/cocoa/focus_tracker.h b/chrome/browser/ui/cocoa/focus_tracker.h
index f828979..f828979 100644
--- a/chrome/browser/cocoa/focus_tracker.h
+++ b/chrome/browser/ui/cocoa/focus_tracker.h
diff --git a/chrome/browser/ui/cocoa/focus_tracker.mm b/chrome/browser/ui/cocoa/focus_tracker.mm
new file mode 100644
index 0000000..dc52791
--- /dev/null
+++ b/chrome/browser/ui/cocoa/focus_tracker.mm
@@ -0,0 +1,46 @@
+// 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 "chrome/browser/ui/cocoa/focus_tracker.h"
+
+#include "base/basictypes.h"
+
+@implementation FocusTracker
+
+- (id)initWithWindow:(NSWindow*)window {
+ if ((self = [super init])) {
+ NSResponder* current_focus = [window firstResponder];
+
+ // Special case NSTextViews, because they are removed from the
+ // view hierarchy when their text field does not have focus. If
+ // an NSTextView is the current first responder, save a pointer to
+ // its NSTextField delegate instead.
+ if ([current_focus isKindOfClass:[NSTextView class]]) {
+ id delegate = [(NSTextView*)current_focus delegate];
+ if ([delegate isKindOfClass:[NSTextField class]])
+ current_focus = delegate;
+ else
+ current_focus = nil;
+ }
+
+ if ([current_focus isKindOfClass:[NSView class]]) {
+ NSView* current_focus_view = (NSView*)current_focus;
+ focusedView_.reset([current_focus_view retain]);
+ }
+ }
+
+ return self;
+}
+
+- (BOOL)restoreFocusInWindow:(NSWindow*)window {
+ if (!focusedView_.get())
+ return NO;
+
+ if ([focusedView_ window] && [focusedView_ window] == window)
+ return [window makeFirstResponder:focusedView_.get()];
+
+ return NO;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/focus_tracker_unittest.mm b/chrome/browser/ui/cocoa/focus_tracker_unittest.mm
new file mode 100644
index 0000000..9868cbd
--- /dev/null
+++ b/chrome/browser/ui/cocoa/focus_tracker_unittest.mm
@@ -0,0 +1,90 @@
+// Copyright (c) 2009 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 "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/focus_tracker.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class FocusTrackerTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ scoped_nsobject<NSView> view([[NSView alloc] initWithFrame:NSZeroRect]);
+ viewA_ = view.get();
+ [[test_window() contentView] addSubview:viewA_];
+
+ view.reset([[NSView alloc] initWithFrame:NSZeroRect]);
+ viewB_ = view.get();
+ [[test_window() contentView] addSubview:viewB_];
+ }
+
+ protected:
+ NSView* viewA_;
+ NSView* viewB_;
+};
+
+TEST_F(FocusTrackerTest, SaveRestore) {
+ NSWindow* window = test_window();
+ ASSERT_TRUE([window makeFirstResponder:viewA_]);
+ scoped_nsobject<FocusTracker> tracker(
+ [[FocusTracker alloc] initWithWindow:window]);
+ // Give focus to |viewB_|, then try and restore it to view1.
+ ASSERT_TRUE([window makeFirstResponder:viewB_]);
+ EXPECT_TRUE([tracker restoreFocusInWindow:window]);
+ EXPECT_EQ(viewA_, [window firstResponder]);
+}
+
+TEST_F(FocusTrackerTest, SaveRestoreWithTextView) {
+ // Valgrind will complain if the text field has zero size.
+ NSRect frame = NSMakeRect(0, 0, 100, 20);
+ NSWindow* window = test_window();
+ scoped_nsobject<NSTextField> text([[NSTextField alloc] initWithFrame:frame]);
+ [[window contentView] addSubview:text];
+
+ ASSERT_TRUE([window makeFirstResponder:text]);
+ scoped_nsobject<FocusTracker> tracker([[FocusTracker alloc]
+ initWithWindow:window]);
+ // Give focus to |viewB_|, then try and restore it to the text field.
+ ASSERT_TRUE([window makeFirstResponder:viewB_]);
+ EXPECT_TRUE([tracker restoreFocusInWindow:window]);
+ EXPECT_TRUE([[window firstResponder] isKindOfClass:[NSTextView class]]);
+}
+
+TEST_F(FocusTrackerTest, DontRestoreToViewNotInWindow) {
+ NSWindow* window = test_window();
+ scoped_nsobject<NSView> viewC([[NSView alloc] initWithFrame:NSZeroRect]);
+ [[window contentView] addSubview:viewC];
+
+ ASSERT_TRUE([window makeFirstResponder:viewC]);
+ scoped_nsobject<FocusTracker> tracker(
+ [[FocusTracker alloc] initWithWindow:window]);
+
+ // Give focus to |viewB_|, then remove viewC from the hierarchy and try
+ // to restore focus. The restore should fail.
+ ASSERT_TRUE([window makeFirstResponder:viewB_]);
+ [viewC removeFromSuperview];
+ EXPECT_FALSE([tracker restoreFocusInWindow:window]);
+}
+
+TEST_F(FocusTrackerTest, DontRestoreFocusToViewInDifferentWindow) {
+ NSWindow* window = test_window();
+ ASSERT_TRUE([window makeFirstResponder:viewA_]);
+ scoped_nsobject<FocusTracker> tracker(
+ [[FocusTracker alloc] initWithWindow:window]);
+
+ // Give focus to |viewB_|, then try and restore focus in a different
+ // window. It is ok to pass a nil NSWindow here because we only use
+ // it for direct comparison.
+ ASSERT_TRUE([window makeFirstResponder:viewB_]);
+ EXPECT_FALSE([tracker restoreFocusInWindow:nil]);
+}
+
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/font_language_settings_controller.h b/chrome/browser/ui/cocoa/font_language_settings_controller.h
new file mode 100644
index 0000000..3123cd2
--- /dev/null
+++ b/chrome/browser/ui/cocoa/font_language_settings_controller.h
@@ -0,0 +1,94 @@
+// Copyright (c) 2009 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>
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_nsobject.h"
+#include "chrome/browser/prefs/pref_member.h"
+
+class Profile;
+
+// Used to keep track of which type of font the user is currently selecting.
+enum FontSettingType {
+ FontSettingSerif,
+ FontSettingSansSerif,
+ FontSettingFixed
+};
+
+// Keys for the dictionaries in the |encodings_| array.
+extern NSString* const kCharacterInfoEncoding; // NSString value.
+extern NSString* const kCharacterInfoName; // NSString value.
+extern NSString* const kCharacterInfoID; // NSNumber value.
+
+// A window controller that allows the user to change the default WebKit fonts
+// and language encodings for web pages. This window controller is meant to be
+// used as a modal sheet on another window.
+@interface FontLanguageSettingsController : NSWindowController
+ <NSWindowDelegate> {
+ @private
+ // The font that we are currently changing.
+ NSFont* currentFont_; // weak
+ FontSettingType currentType_;
+
+ IBOutlet NSButton* serifButton_;
+ IBOutlet NSTextField* serifField_;
+ scoped_nsobject<NSFont> serifFont_;
+ IBOutlet NSTextField* serifLabel_;
+ BOOL changedSerif_;
+
+ IBOutlet NSButton* sansSerifButton_;
+ IBOutlet NSTextField* sansSerifField_;
+ scoped_nsobject<NSFont> sansSerifFont_;
+ IBOutlet NSTextField* sansSerifLabel_;
+ BOOL changedSansSerif_;
+
+ IBOutlet NSButton* fixedWidthButton_;
+ IBOutlet NSTextField* fixedWidthField_;
+ scoped_nsobject<NSFont> fixedWidthFont_;
+ IBOutlet NSTextField* fixedWidthLabel_;
+ BOOL changedFixedWidth_;
+
+ // The actual preference members.
+ StringPrefMember serifName_;
+ StringPrefMember sansSerifName_;
+ StringPrefMember fixedWidthName_;
+ IntegerPrefMember serifSize_;
+ IntegerPrefMember sansSerifSize_;
+ IntegerPrefMember fixedWidthSize_;
+
+ // Array of dictionaries that contain the canonical encoding name, human-
+ // readable name, and the ID. See the constants defined at the top of this
+ // file for the keys.
+ scoped_nsobject<NSMutableArray> encodings_;
+
+ IBOutlet NSPopUpButton* encodingsMenu_;
+ NSInteger defaultEncodingIndex_;
+ StringPrefMember defaultEncoding_;
+ BOOL changedEncoding_;
+
+ Profile* profile_; // weak
+}
+
+// Profile cannot be NULL. Caller is responsible for showing the window as a
+// modal sheet.
+- (id)initWithProfile:(Profile*)profile;
+
+// Action for all the font changing buttons. This starts the font picker.
+- (IBAction)selectFont:(id)sender;
+
+// Sent by the FontManager after the user has selected a font.
+- (void)changeFont:(id)fontManager;
+
+// Performs the closing of the window. This is used by both the cancel button
+// and |-save:| after it persists the settings.
+- (IBAction)closeSheet:(id)sender;
+
+// Persists the new values into the preferences and closes the sheet.
+- (IBAction)save:(id)sender;
+
+// Returns the |encodings_| array. This is used by bindings for KVO/KVC.
+- (NSArray*)encodings;
+
+@end
diff --git a/chrome/browser/ui/cocoa/font_language_settings_controller.mm b/chrome/browser/ui/cocoa/font_language_settings_controller.mm
new file mode 100644
index 0000000..4beff2a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/font_language_settings_controller.mm
@@ -0,0 +1,280 @@
+// 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 "chrome/browser/ui/cocoa/font_language_settings_controller.h"
+
+#import <Cocoa/Cocoa.h>
+#import "base/mac_util.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/character_encoding.h"
+#include "chrome/browser/fonts_languages_window.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/pref_names.h"
+
+NSString* const kCharacterInfoEncoding = @"encoding";
+NSString* const kCharacterInfoName = @"name";
+NSString* const kCharacterInfoID = @"id";
+
+void ShowFontsLanguagesWindow(gfx::NativeWindow window,
+ FontsLanguagesPage page,
+ Profile* profile) {
+ NOTIMPLEMENTED();
+}
+
+@interface FontLanguageSettingsController (Private)
+- (void)updateDisplayField:(NSTextField*)field
+ withFont:(NSFont*)font
+ withLabel:(NSTextField*)label;
+@end
+
+@implementation FontLanguageSettingsController
+
+- (id)initWithProfile:(Profile*)profile {
+ DCHECK(profile);
+ NSString* nibpath = [mac_util::MainAppBundle()
+ pathForResource:@"FontLanguageSettings"
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
+ profile_ = profile;
+
+ // Convert the name/size preference values to NSFont objects.
+ serifName_.Init(prefs::kWebKitSerifFontFamily, profile->GetPrefs(), NULL);
+ serifSize_.Init(prefs::kWebKitDefaultFontSize, profile->GetPrefs(), NULL);
+ NSString* serif = base::SysUTF8ToNSString(serifName_.GetValue());
+ serifFont_.reset(
+ [[NSFont fontWithName:serif size:serifSize_.GetValue()] retain]);
+
+ sansSerifName_.Init(prefs::kWebKitSansSerifFontFamily, profile->GetPrefs(),
+ NULL);
+ sansSerifSize_.Init(prefs::kWebKitDefaultFontSize, profile->GetPrefs(),
+ NULL);
+ NSString* sansSerif = base::SysUTF8ToNSString(sansSerifName_.GetValue());
+ sansSerifFont_.reset(
+ [[NSFont fontWithName:sansSerif
+ size:sansSerifSize_.GetValue()] retain]);
+
+ fixedWidthName_.Init(prefs::kWebKitFixedFontFamily, profile->GetPrefs(),
+ NULL);
+ fixedWidthSize_.Init(prefs::kWebKitDefaultFixedFontSize,
+ profile->GetPrefs(), NULL);
+ NSString* fixedWidth = base::SysUTF8ToNSString(fixedWidthName_.GetValue());
+ fixedWidthFont_.reset(
+ [[NSFont fontWithName:fixedWidth
+ size:fixedWidthSize_.GetValue()] retain]);
+
+ // Generate a list of encodings.
+ NSInteger count = CharacterEncoding::GetSupportCanonicalEncodingCount();
+ NSMutableArray* encodings = [NSMutableArray arrayWithCapacity:count];
+ for (NSInteger i = 0; i < count; ++i) {
+ int commandId = CharacterEncoding::GetEncodingCommandIdByIndex(i);
+ string16 name = CharacterEncoding::\
+ GetCanonicalEncodingDisplayNameByCommandId(commandId);
+ std::string encoding =
+ CharacterEncoding::GetCanonicalEncodingNameByCommandId(commandId);
+ NSDictionary* strings = [NSDictionary dictionaryWithObjectsAndKeys:
+ base::SysUTF16ToNSString(name), kCharacterInfoName,
+ base::SysUTF8ToNSString(encoding), kCharacterInfoEncoding,
+ [NSNumber numberWithInt:commandId], kCharacterInfoID,
+ nil
+ ];
+ [encodings addObject:strings];
+ }
+
+ // Sort the encodings.
+ scoped_nsobject<NSSortDescriptor> sorter(
+ [[NSSortDescriptor alloc] initWithKey:kCharacterInfoName
+ ascending:YES]);
+ NSArray* sorterArray = [NSArray arrayWithObject:sorter.get()];
+ encodings_.reset(
+ [[encodings sortedArrayUsingDescriptors:sorterArray] retain]);
+
+ // Find and set the default encoding.
+ defaultEncoding_.Init(prefs::kDefaultCharset, profile->GetPrefs(), NULL);
+ NSString* defaultEncoding =
+ base::SysUTF8ToNSString(defaultEncoding_.GetValue());
+ NSUInteger index = 0;
+ for (NSDictionary* entry in encodings_.get()) {
+ NSString* encoding = [entry objectForKey:kCharacterInfoEncoding];
+ if ([encoding isEqualToString:defaultEncoding]) {
+ defaultEncodingIndex_ = index;
+ break;
+ }
+ ++index;
+ }
+
+ // Register as a KVO observer so we can receive updates when the encoding
+ // changes.
+ [self addObserver:self
+ forKeyPath:@"defaultEncodingIndex_"
+ options:NSKeyValueObservingOptionNew
+ context:NULL];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [self removeObserver:self forKeyPath:@"defaultEncodingIndex_"];
+ [super dealloc];
+}
+
+- (void)awakeFromNib {
+ DCHECK([self window]);
+ [[self window] setDelegate:self];
+
+ // Set up the font display.
+ [self updateDisplayField:serifField_
+ withFont:serifFont_.get()
+ withLabel:serifLabel_];
+ [self updateDisplayField:sansSerifField_
+ withFont:sansSerifFont_.get()
+ withLabel:sansSerifLabel_];
+ [self updateDisplayField:fixedWidthField_
+ withFont:fixedWidthFont_.get()
+ withLabel:fixedWidthLabel_];
+}
+
+- (void)windowWillClose:(NSNotification*)notif {
+ [self autorelease];
+}
+
+- (IBAction)selectFont:(id)sender {
+ if (sender == serifButton_) {
+ currentFont_ = serifFont_.get();
+ currentType_ = FontSettingSerif;
+ } else if (sender == sansSerifButton_) {
+ currentFont_ = sansSerifFont_.get();
+ currentType_ = FontSettingSansSerif;
+ } else if (sender == fixedWidthButton_) {
+ currentFont_ = fixedWidthFont_.get();
+ currentType_ = FontSettingFixed;
+ } else {
+ NOTREACHED();
+ }
+
+ // Validate whatever editing is currently happening.
+ if ([[self window] makeFirstResponder:nil]) {
+ NSFontManager* manager = [NSFontManager sharedFontManager];
+ [manager setTarget:self];
+ [manager setSelectedFont:currentFont_ isMultiple:NO];
+ [manager orderFrontFontPanel:self];
+ }
+}
+
+// Called by the font manager when the user has selected a new font. We should
+// then persist those changes into the preference system.
+- (void)changeFont:(id)fontManager {
+ switch (currentType_) {
+ case FontSettingSerif:
+ serifFont_.reset([[fontManager convertFont:serifFont_] retain]);
+ [self updateDisplayField:serifField_
+ withFont:serifFont_.get()
+ withLabel:serifLabel_];
+ changedSerif_ = YES;
+ break;
+ case FontSettingSansSerif:
+ sansSerifFont_.reset([[fontManager convertFont:sansSerifFont_] retain]);
+ [self updateDisplayField:sansSerifField_
+ withFont:sansSerifFont_.get()
+ withLabel:sansSerifLabel_];
+ changedSansSerif_ = YES;
+ break;
+ case FontSettingFixed:
+ fixedWidthFont_.reset(
+ [[fontManager convertFont:fixedWidthFont_] retain]);
+ [self updateDisplayField:fixedWidthField_
+ withFont:fixedWidthFont_.get()
+ withLabel:fixedWidthLabel_];
+ changedFixedWidth_ = YES;
+ break;
+ default:
+ NOTREACHED();
+ }
+}
+
+- (IBAction)closeSheet:(id)sender {
+ NSFontPanel* panel = [[NSFontManager sharedFontManager] fontPanel:NO];
+ [panel close];
+ [NSApp endSheet:[self window]];
+}
+
+- (IBAction)save:(id)sender {
+ if (changedSerif_) {
+ serifName_.SetValue(base::SysNSStringToUTF8([serifFont_ fontName]));
+ serifSize_.SetValue([serifFont_ pointSize]);
+ }
+ if (changedSansSerif_) {
+ sansSerifName_.SetValue(
+ base::SysNSStringToUTF8([sansSerifFont_ fontName]));
+ sansSerifSize_.SetValue([sansSerifFont_ pointSize]);
+ }
+ if (changedFixedWidth_) {
+ fixedWidthName_.SetValue(
+ base::SysNSStringToUTF8([fixedWidthFont_ fontName]));
+ fixedWidthSize_.SetValue([fixedWidthFont_ pointSize]);
+ }
+ if (changedEncoding_) {
+ NSDictionary* object = [encodings_ objectAtIndex:defaultEncodingIndex_];
+ NSString* newEncoding = [object objectForKey:kCharacterInfoEncoding];
+ std::string encoding = base::SysNSStringToUTF8(newEncoding);
+ defaultEncoding_.SetValue(encoding);
+ }
+ [self closeSheet:sender];
+}
+
+- (NSArray*)encodings {
+ return encodings_.get();
+}
+
+// KVO notification.
+- (void)observeValueForKeyPath:(NSString*)keyPath
+ ofObject:(id)object
+ change:(NSDictionary*)change
+ context:(void*)context {
+ // If this is the default encoding, then set the flag to persist the value.
+ if ([keyPath isEqual:@"defaultEncodingIndex_"]) {
+ changedEncoding_ = YES;
+ return;
+ }
+
+ [super observeValueForKeyPath:keyPath
+ ofObject:object
+ change:change
+ context:context];
+}
+
+#pragma mark Private
+
+// Set the baseline for the font field to be aligned with the baseline
+// of its corresponding label.
+- (NSPoint)getFontFieldOrigin:(NSTextField*)field
+ forLabel:(NSTextField*)label {
+ [field sizeToFit];
+ NSRect labelFrame = [label frame];
+ NSPoint newOrigin =
+ [[label superview] convertPoint:labelFrame.origin
+ toView:[field superview]];
+ newOrigin.x = 0; // Left-align font field.
+ newOrigin.y += [[field font] descender] - [[label font] descender];
+ return newOrigin;
+}
+
+// This will set the font on |field| to be |font|, and will set the string
+// value to something human-readable.
+- (void)updateDisplayField:(NSTextField*)field
+ withFont:(NSFont*)font
+ withLabel:(NSTextField*)label {
+ if (!font) {
+ // Something has gone really wrong. Don't make things worse by showing the
+ // user "(null)".
+ return;
+ }
+ [field setFont:font];
+ NSString* value =
+ [NSString stringWithFormat:@"%@, %g", [font fontName], [font pointSize]];
+ [field setStringValue:value];
+ [field setFrameOrigin:[self getFontFieldOrigin:field forLabel:label]];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/font_language_settings_controller_unittest.mm b/chrome/browser/ui/cocoa/font_language_settings_controller_unittest.mm
new file mode 100644
index 0000000..48e4a24
--- /dev/null
+++ b/chrome/browser/ui/cocoa/font_language_settings_controller_unittest.mm
@@ -0,0 +1,91 @@
+// Copyright (c) 2009 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/scoped_nsobject.h"
+#include "chrome/browser/character_encoding.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/font_language_settings_controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+// The FontLanguageSettingsControllerForTest overrides the getFontFieldOrigin
+// method to provide a dummy point, so we don't have to actually display the
+// window to test the controller.
+@interface FontLanguageSettingsControllerForTest :
+ FontLanguageSettingsController {
+}
+
+- (NSPoint)getFontFieldOrigin:(NSTextField*)field
+ forLabel:(NSTextField*)label;
+
+@end
+
+@implementation FontLanguageSettingsControllerForTest
+
+- (NSPoint)getFontFieldOrigin:(NSTextField*)field
+ forLabel:(NSTextField*)label {
+ return NSMakePoint(10, 10);
+}
+
+@end
+
+@interface FontLanguageSettingsController (Testing)
+- (void)updateDisplayField:(NSTextField*)field
+ withFont:(NSFont*)font
+ withLabel:(NSTextField*)label;
+@end
+
+class FontLanguageSettingsControllerTest : public CocoaTest {
+ public:
+ FontLanguageSettingsControllerTest() {
+ Profile* profile = helper_.profile();
+ font_controller_.reset(
+ [[FontLanguageSettingsControllerForTest alloc] initWithProfile:profile]);
+ }
+ ~FontLanguageSettingsControllerTest() {}
+
+ BrowserTestHelper helper_;
+ scoped_nsobject<FontLanguageSettingsController> font_controller_;
+};
+
+TEST_F(FontLanguageSettingsControllerTest, Init) {
+ ASSERT_EQ(CharacterEncoding::GetSupportCanonicalEncodingCount(),
+ static_cast<int>([[font_controller_ encodings] count]));
+}
+
+TEST_F(FontLanguageSettingsControllerTest, UpdateDisplayField) {
+ NSFont* font = [NSFont fontWithName:@"Times-Roman" size:12.0];
+ scoped_nsobject<NSTextField> field(
+ [[NSTextField alloc] initWithFrame:NSMakeRect(100, 100, 100, 100)]);
+ scoped_nsobject<NSTextField> label(
+ [[NSTextField alloc] initWithFrame:NSMakeRect(100, 100, 100, 100)]);
+ [font_controller_ updateDisplayField:field.get()
+ withFont:font
+ withLabel:label];
+
+ ASSERT_NSEQ([font fontName], [[field font] fontName]);
+ ASSERT_NSEQ(@"Times-Roman, 12", [field stringValue]);
+}
+
+TEST_F(FontLanguageSettingsControllerTest, UpdateDisplayFieldNilFont) {
+ scoped_nsobject<NSTextField> field(
+ [[NSTextField alloc] initWithFrame:NSMakeRect(100, 100, 100, 100)]);
+ scoped_nsobject<NSTextField> label(
+ [[NSTextField alloc] initWithFrame:NSMakeRect(100, 100, 100, 100)]);
+ [field setStringValue:@"foo"];
+ [font_controller_ updateDisplayField:field.get()
+ withFont:nil
+ withLabel:label];
+
+ ASSERT_NSEQ(@"foo", [field stringValue]);
+}
+
+TEST_F(FontLanguageSettingsControllerTest, UpdateDisplayFieldNilField) {
+ // Don't crash.
+ NSFont* font = [NSFont fontWithName:@"Times-Roman" size:12.0];
+ [font_controller_ updateDisplayField:nil withFont:font withLabel:nil];
+}
diff --git a/chrome/browser/ui/cocoa/framed_browser_window.h b/chrome/browser/ui/cocoa/framed_browser_window.h
new file mode 100644
index 0000000..40f330c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/framed_browser_window.h
@@ -0,0 +1,65 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_FRAMED_BROWSER_WINDOW_H_
+#define CHROME_BROWSER_UI_COCOA_FRAMED_BROWSER_WINDOW_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+#include "chrome/browser/ui/cocoa/chrome_browser_window.h"
+
+// Offset from the top of the window frame to the top of the window controls
+// (zoom, close, miniaturize) for a window with a tabstrip.
+const NSInteger kFramedWindowButtonsWithTabStripOffsetFromTop = 6;
+
+// Offset from the top of the window frame to the top of the window controls
+// (zoom, close, miniaturize) for a window without a tabstrip.
+const NSInteger kFramedWindowButtonsWithoutTabStripOffsetFromTop = 4;
+
+// Offset from the left of the window frame to the top of the window controls
+// (zoom, close, miniaturize).
+const NSInteger kFramedWindowButtonsOffsetFromLeft = 8;
+
+// Offset between the window controls (zoom, close, miniaturize).
+const NSInteger kFramedWindowButtonsInterButtonSpacing = 7;
+
+// Cocoa class representing a framed browser window.
+// We need to override NSWindow with our own class since we need access to all
+// unhandled keyboard events and subclassing NSWindow is the only method to do
+// this. We also handle our own window controls and custom window frame drawing.
+@interface FramedBrowserWindow : ChromeBrowserWindow {
+ @private
+ BOOL shouldHideTitle_;
+ NSButton* closeButton_;
+ NSButton* miniaturizeButton_;
+ NSButton* zoomButton_;
+ BOOL entered_;
+ scoped_nsobject<NSTrackingArea> widgetTrackingArea_;
+}
+
+// Tells the window to suppress title drawing.
+- (void)setShouldHideTitle:(BOOL)flag;
+
+// Return true if the mouse is currently in our tracking area for our window
+// widgets.
+- (BOOL)mouseInGroup:(NSButton*)widget;
+
+// Update the tracking areas for our window widgets as appropriate.
+- (void)updateTrackingAreas;
+
+@end
+
+@interface NSWindow (UndocumentedAPI)
+
+// Undocumented Cocoa API to suppress drawing of the window's title.
+// -setTitle: still works, but the title set only applies to the
+// miniwindow and menus (and, importantly, Expose). Overridden to
+// return |shouldHideTitle_|.
+-(BOOL)_isTitleHidden;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_FRAMED_BROWSER_WINDOW_H_
diff --git a/chrome/browser/ui/cocoa/framed_browser_window.mm b/chrome/browser/ui/cocoa/framed_browser_window.mm
new file mode 100644
index 0000000..9d63cb7
--- /dev/null
+++ b/chrome/browser/ui/cocoa/framed_browser_window.mm
@@ -0,0 +1,350 @@
+// 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 "chrome/browser/ui/cocoa/framed_browser_window.h"
+
+#include "base/logging.h"
+#include "chrome/browser/global_keyboard_shortcuts_mac.h"
+#import "chrome/browser/ui/cocoa/browser_frame_view.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "chrome/browser/ui/cocoa/tab_strip_controller.h"
+#import "chrome/browser/ui/cocoa/themed_window.h"
+#import "chrome/browser/renderer_host/render_widget_host_view_mac.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
+
+namespace {
+ // Size of the gradient. Empirically determined so that the gradient looks
+ // like what the heuristic does when there are just a few tabs.
+ const CGFloat kWindowGradientHeight = 24.0;
+}
+
+// Our browser window does some interesting things to get the behaviors that
+// we want. We replace the standard window controls (zoom, close, miniaturize)
+// with our own versions, so that we can position them slightly differently than
+// the default window has them. To do this, we hide the ones that Apple provides
+// us with, and create our own. This requires us to handle tracking for the
+// buttons (so that they highlight and activate correctly) as well as implement
+// the private method _mouseInGroup in our frame view class which is required
+// to get the rollover highlight drawing to draw correctly.
+@interface FramedBrowserWindow(PrivateMethods)
+// Return the view that does the "frame" drawing.
+- (NSView*)frameView;
+@end
+
+@implementation FramedBrowserWindow
+
+- (id)initWithContentRect:(NSRect)contentRect
+ styleMask:(NSUInteger)aStyle
+ backing:(NSBackingStoreType)bufferingType
+ defer:(BOOL)flag {
+ if ((self = [super initWithContentRect:contentRect
+ styleMask:aStyle
+ backing:bufferingType
+ defer:flag])) {
+ if (aStyle & NSTexturedBackgroundWindowMask) {
+ // The following two calls fix http://www.crbug.com/25684 by preventing
+ // the window from recalculating the border thickness as the window is
+ // resized.
+ // This was causing the window tint to change for the default system theme
+ // when the window was being resized.
+ [self setAutorecalculatesContentBorderThickness:NO forEdge:NSMaxYEdge];
+ [self setContentBorderThickness:kWindowGradientHeight forEdge:NSMaxYEdge];
+ }
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [[NSDistributedNotificationCenter defaultCenter] removeObserver:self];
+ if (widgetTrackingArea_) {
+ [[self frameView] removeTrackingArea:widgetTrackingArea_];
+ widgetTrackingArea_.reset();
+ }
+ [super dealloc];
+}
+
+- (void)setWindowController:(NSWindowController*)controller {
+ if (controller == [self windowController]) {
+ return;
+ }
+ // Clean up our old stuff.
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [[NSDistributedNotificationCenter defaultCenter] removeObserver:self];
+ [closeButton_ removeFromSuperview];
+ closeButton_ = nil;
+ [miniaturizeButton_ removeFromSuperview];
+ miniaturizeButton_ = nil;
+ [zoomButton_ removeFromSuperview];
+ zoomButton_ = nil;
+
+ [super setWindowController:controller];
+
+ BrowserWindowController* browserController
+ = static_cast<BrowserWindowController*>(controller);
+ if ([browserController isKindOfClass:[BrowserWindowController class]]) {
+ NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
+ [defaultCenter addObserver:self
+ selector:@selector(themeDidChangeNotification:)
+ name:kBrowserThemeDidChangeNotification
+ object:nil];
+
+ // Hook ourselves up to get notified if the user changes the system
+ // theme on us.
+ NSDistributedNotificationCenter* distCenter =
+ [NSDistributedNotificationCenter defaultCenter];
+ [distCenter addObserver:self
+ selector:@selector(systemThemeDidChangeNotification:)
+ name:@"AppleAquaColorVariantChanged"
+ object:nil];
+ // Set up our buttons how we like them.
+ NSView* frameView = [self frameView];
+ NSRect frameViewBounds = [frameView bounds];
+
+ // Find all the "original" buttons, and hide them. We can't use the original
+ // buttons because the OS likes to move them around when we resize windows
+ // and will put them back in what it considers to be their "preferred"
+ // locations.
+ NSButton* oldButton = [self standardWindowButton:NSWindowCloseButton];
+ [oldButton setHidden:YES];
+ oldButton = [self standardWindowButton:NSWindowMiniaturizeButton];
+ [oldButton setHidden:YES];
+ oldButton = [self standardWindowButton:NSWindowZoomButton];
+ [oldButton setHidden:YES];
+
+ // Create and position our new buttons.
+ NSUInteger aStyle = [self styleMask];
+ closeButton_ = [NSWindow standardWindowButton:NSWindowCloseButton
+ forStyleMask:aStyle];
+ NSRect closeButtonFrame = [closeButton_ frame];
+ CGFloat yOffset = [browserController hasTabStrip] ?
+ kFramedWindowButtonsWithTabStripOffsetFromTop :
+ kFramedWindowButtonsWithoutTabStripOffsetFromTop;
+ closeButtonFrame.origin =
+ NSMakePoint(kFramedWindowButtonsOffsetFromLeft,
+ (NSHeight(frameViewBounds) -
+ NSHeight(closeButtonFrame) - yOffset));
+
+ [closeButton_ setFrame:closeButtonFrame];
+ [closeButton_ setTarget:self];
+ [closeButton_ setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
+ [frameView addSubview:closeButton_];
+
+ miniaturizeButton_ =
+ [NSWindow standardWindowButton:NSWindowMiniaturizeButton
+ forStyleMask:aStyle];
+ NSRect miniaturizeButtonFrame = [miniaturizeButton_ frame];
+ miniaturizeButtonFrame.origin =
+ NSMakePoint((NSMaxX(closeButtonFrame) +
+ kFramedWindowButtonsInterButtonSpacing),
+ NSMinY(closeButtonFrame));
+ [miniaturizeButton_ setFrame:miniaturizeButtonFrame];
+ [miniaturizeButton_ setTarget:self];
+ [miniaturizeButton_ setAutoresizingMask:(NSViewMaxXMargin |
+ NSViewMinYMargin)];
+ [frameView addSubview:miniaturizeButton_];
+
+ zoomButton_ = [NSWindow standardWindowButton:NSWindowZoomButton
+ forStyleMask:aStyle];
+ NSRect zoomButtonFrame = [zoomButton_ frame];
+ zoomButtonFrame.origin =
+ NSMakePoint((NSMaxX(miniaturizeButtonFrame) +
+ kFramedWindowButtonsInterButtonSpacing),
+ NSMinY(miniaturizeButtonFrame));
+ [zoomButton_ setFrame:zoomButtonFrame];
+ [zoomButton_ setTarget:self];
+ [zoomButton_ setAutoresizingMask:(NSViewMaxXMargin |
+ NSViewMinYMargin)];
+
+ [frameView addSubview:zoomButton_];
+ }
+
+ // Update our tracking areas. We want to update them even if we haven't
+ // added buttons above as we need to remove the old tracking area. If the
+ // buttons aren't to be shown, updateTrackingAreas won't add new ones.
+ [self updateTrackingAreas];
+}
+
+- (NSView*)frameView {
+ return [[self contentView] superview];
+}
+
+// The tab strip view covers our window buttons. So we add hit testing here
+// to find them properly and return them to the accessibility system.
+- (id)accessibilityHitTest:(NSPoint)point {
+ NSPoint windowPoint = [self convertScreenToBase:point];
+ NSControl* controls[] = { closeButton_, zoomButton_, miniaturizeButton_ };
+ id value = nil;
+ for (size_t i = 0; i < sizeof(controls) / sizeof(controls[0]); ++i) {
+ if (NSPointInRect(windowPoint, [controls[i] frame])) {
+ value = [controls[i] accessibilityHitTest:point];
+ break;
+ }
+ }
+ if (!value) {
+ value = [super accessibilityHitTest:point];
+ }
+ return value;
+}
+
+// Map our custom buttons into the accessibility hierarchy correctly.
+- (id)accessibilityAttributeValue:(NSString*)attribute {
+ id value = nil;
+ struct {
+ NSString* attribute_;
+ id value_;
+ } attributeMap[] = {
+ { NSAccessibilityCloseButtonAttribute, [closeButton_ cell]},
+ { NSAccessibilityZoomButtonAttribute, [zoomButton_ cell]},
+ { NSAccessibilityMinimizeButtonAttribute, [miniaturizeButton_ cell]},
+ };
+
+ for (size_t i = 0; i < sizeof(attributeMap) / sizeof(attributeMap[0]); ++i) {
+ if ([attributeMap[i].attribute_ isEqualToString:attribute]) {
+ value = attributeMap[i].value_;
+ break;
+ }
+ }
+ if (!value) {
+ value = [super accessibilityAttributeValue:attribute];
+ }
+ return value;
+}
+
+- (void)updateTrackingAreas {
+ NSView* frameView = [self frameView];
+ if (widgetTrackingArea_) {
+ [frameView removeTrackingArea:widgetTrackingArea_];
+ }
+ if (closeButton_) {
+ NSRect trackingRect = [closeButton_ frame];
+ trackingRect.size.width = NSMaxX([zoomButton_ frame]) -
+ NSMinX(trackingRect);
+ widgetTrackingArea_.reset(
+ [[NSTrackingArea alloc] initWithRect:trackingRect
+ options:(NSTrackingMouseEnteredAndExited |
+ NSTrackingActiveAlways)
+ owner:self
+ userInfo:nil]);
+ [frameView addTrackingArea:widgetTrackingArea_];
+
+ // Check to see if the cursor is still in trackingRect.
+ NSPoint point = [self mouseLocationOutsideOfEventStream];
+ point = [[self contentView] convertPoint:point fromView:nil];
+ BOOL newEntered = NSPointInRect (point, trackingRect);
+ if (newEntered != entered_) {
+ // Buttons have moved, so update button state.
+ entered_ = newEntered;
+ [closeButton_ setNeedsDisplay];
+ [zoomButton_ setNeedsDisplay];
+ [miniaturizeButton_ setNeedsDisplay];
+ }
+ }
+}
+
+- (void)windowMainStatusChanged {
+ [closeButton_ setNeedsDisplay];
+ [zoomButton_ setNeedsDisplay];
+ [miniaturizeButton_ setNeedsDisplay];
+ NSView* frameView = [self frameView];
+ NSView* contentView = [self contentView];
+ NSRect updateRect = [frameView frame];
+ NSRect contentRect = [contentView frame];
+ CGFloat tabStripHeight = [TabStripController defaultTabHeight];
+ updateRect.size.height -= NSHeight(contentRect) - tabStripHeight;
+ updateRect.origin.y = NSMaxY(contentRect) - tabStripHeight;
+ [[self frameView] setNeedsDisplayInRect:updateRect];
+}
+
+- (void)becomeMainWindow {
+ [self windowMainStatusChanged];
+ [super becomeMainWindow];
+}
+
+- (void)resignMainWindow {
+ [self windowMainStatusChanged];
+ [super resignMainWindow];
+}
+
+// Called after the current theme has changed.
+- (void)themeDidChangeNotification:(NSNotification*)aNotification {
+ [[self frameView] setNeedsDisplay:YES];
+}
+
+- (void)systemThemeDidChangeNotification:(NSNotification*)aNotification {
+ [closeButton_ setNeedsDisplay];
+ [zoomButton_ setNeedsDisplay];
+ [miniaturizeButton_ setNeedsDisplay];
+}
+
+- (void)sendEvent:(NSEvent*)event {
+ // For cocoa windows, clicking on the close and the miniaturize (but not the
+ // zoom buttons) while a window is in the background does NOT bring that
+ // window to the front. We don't get that behavior for free, so we handle
+ // it here. Zoom buttons do bring the window to the front. Note that
+ // Finder windows (in Leopard) behave differently in this regard in that
+ // zoom buttons don't bring the window to the foreground.
+ BOOL eventHandled = NO;
+ if (![self isMainWindow]) {
+ if ([event type] == NSLeftMouseDown) {
+ NSView* frameView = [self frameView];
+ NSPoint mouse = [frameView convertPoint:[event locationInWindow]
+ fromView:nil];
+ if (NSPointInRect(mouse, [closeButton_ frame])) {
+ [closeButton_ mouseDown:event];
+ eventHandled = YES;
+ } else if (NSPointInRect(mouse, [miniaturizeButton_ frame])) {
+ [miniaturizeButton_ mouseDown:event];
+ eventHandled = YES;
+ }
+ }
+ }
+ if (!eventHandled) {
+ [super sendEvent:event];
+ }
+}
+
+// Update our buttons so that they highlight correctly.
+- (void)mouseEntered:(NSEvent*)event {
+ entered_ = YES;
+ [closeButton_ setNeedsDisplay];
+ [zoomButton_ setNeedsDisplay];
+ [miniaturizeButton_ setNeedsDisplay];
+}
+
+// Update our buttons so that they highlight correctly.
+- (void)mouseExited:(NSEvent*)event {
+ entered_ = NO;
+ [closeButton_ setNeedsDisplay];
+ [zoomButton_ setNeedsDisplay];
+ [miniaturizeButton_ setNeedsDisplay];
+}
+
+- (BOOL)mouseInGroup:(NSButton*)widget {
+ return entered_;
+}
+
+- (void)setShouldHideTitle:(BOOL)flag {
+ shouldHideTitle_ = flag;
+}
+
+-(BOOL)_isTitleHidden {
+ return shouldHideTitle_;
+}
+
+// This method is called whenever a window is moved in order to ensure it fits
+// on the screen. We cannot always handle resizes without breaking, so we
+// prevent frame constraining in those cases.
+- (NSRect)constrainFrameRect:(NSRect)frame toScreen:(NSScreen*)screen {
+ // Do not constrain the frame rect if our delegate says no. In this case,
+ // return the original (unconstrained) frame.
+ id delegate = [self delegate];
+ if ([delegate respondsToSelector:@selector(shouldConstrainFrameRect)] &&
+ ![delegate shouldConstrainFrameRect])
+ return frame;
+
+ return [super constrainFrameRect:frame toScreen:screen];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/framed_browser_window_unittest.mm b/chrome/browser/ui/cocoa/framed_browser_window_unittest.mm
new file mode 100644
index 0000000..ad05334
--- /dev/null
+++ b/chrome/browser/ui/cocoa/framed_browser_window_unittest.mm
@@ -0,0 +1,184 @@
+// Copyright (c) 2009 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 "base/debug/debugger.h"
+#include "base/scoped_nsobject.h"
+#include "chrome/app/chrome_command_ids.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "chrome/browser/ui/cocoa/browser_frame_view.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/framed_browser_window.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+
+class FramedBrowserWindowTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ // Create a window.
+ const NSUInteger mask = NSTitledWindowMask | NSClosableWindowMask |
+ NSMiniaturizableWindowMask | NSResizableWindowMask;
+ window_ = [[FramedBrowserWindow alloc]
+ initWithContentRect:NSMakeRect(0, 0, 800, 600)
+ styleMask:mask
+ backing:NSBackingStoreBuffered
+ defer:NO];
+ if (base::debug::BeingDebugged()) {
+ [window_ orderFront:nil];
+ } else {
+ [window_ orderBack:nil];
+ }
+ }
+
+ virtual void TearDown() {
+ [window_ close];
+ CocoaTest::TearDown();
+ }
+
+ // Returns a canonical snapshot of the window.
+ NSData* WindowContentsAsTIFF() {
+ [window_ display];
+
+ NSView* frameView = [window_ contentView];
+ while ([frameView superview]) {
+ frameView = [frameView superview];
+ }
+ const NSRect bounds = [frameView bounds];
+
+ [frameView lockFocus];
+ scoped_nsobject<NSBitmapImageRep> bitmap(
+ [[NSBitmapImageRep alloc] initWithFocusedViewRect:bounds]);
+ [frameView unlockFocus];
+
+ return [bitmap TIFFRepresentation];
+ }
+
+ FramedBrowserWindow* window_;
+};
+
+// Baseline test that the window creates, displays, closes, and
+// releases.
+TEST_F(FramedBrowserWindowTest, ShowAndClose) {
+ [window_ display];
+}
+
+// Test that undocumented title-hiding API we're using does the job.
+TEST_F(FramedBrowserWindowTest, DoesHideTitle) {
+ // The -display calls are not strictly necessary, but they do
+ // make it easier to see what's happening when debugging (without
+ // them the changes are never flushed to the screen).
+
+ [window_ setTitle:@""];
+ [window_ display];
+ NSData* emptyTitleData = WindowContentsAsTIFF();
+
+ [window_ setTitle:@"This is a title"];
+ [window_ display];
+ NSData* thisTitleData = WindowContentsAsTIFF();
+
+ // The default window with a title should look different from the
+ // window with an empty title.
+ EXPECT_FALSE([emptyTitleData isEqualToData:thisTitleData]);
+
+ [window_ setShouldHideTitle:YES];
+ [window_ setTitle:@""];
+ [window_ display];
+ [window_ setTitle:@"This is a title"];
+ [window_ display];
+ NSData* hiddenTitleData = WindowContentsAsTIFF();
+
+ // With our magic setting, the window with a title should look the
+ // same as the window with an empty title.
+ EXPECT_TRUE([window_ _isTitleHidden]);
+ EXPECT_TRUE([emptyTitleData isEqualToData:hiddenTitleData]);
+}
+
+// Test to make sure that our window widgets are in the right place.
+TEST_F(FramedBrowserWindowTest, WindowWidgetLocation) {
+ // First without tabstrip.
+ NSCell* closeBoxCell = [window_ accessibilityAttributeValue:
+ NSAccessibilityCloseButtonAttribute];
+ NSView* closeBoxControl = [closeBoxCell controlView];
+ EXPECT_TRUE(closeBoxControl);
+ NSRect closeBoxFrame = [closeBoxControl frame];
+ NSRect windowBounds = [window_ frame];
+ windowBounds.origin = NSZeroPoint;
+ EXPECT_EQ(NSMaxY(closeBoxFrame),
+ NSMaxY(windowBounds) -
+ kFramedWindowButtonsWithoutTabStripOffsetFromTop);
+ EXPECT_EQ(NSMinX(closeBoxFrame), kFramedWindowButtonsOffsetFromLeft);
+
+ NSCell* miniaturizeCell = [window_ accessibilityAttributeValue:
+ NSAccessibilityMinimizeButtonAttribute];
+ NSView* miniaturizeControl = [miniaturizeCell controlView];
+ EXPECT_TRUE(miniaturizeControl);
+ NSRect miniaturizeFrame = [miniaturizeControl frame];
+ EXPECT_EQ(NSMaxY(miniaturizeFrame),
+ NSMaxY(windowBounds) -
+ kFramedWindowButtonsWithoutTabStripOffsetFromTop);
+ EXPECT_EQ(NSMinX(miniaturizeFrame),
+ NSMaxX(closeBoxFrame) + kFramedWindowButtonsInterButtonSpacing);
+
+ // Then with a tabstrip.
+ id controller = [OCMockObject mockForClass:[BrowserWindowController class]];
+ BOOL yes = YES;
+ BOOL no = NO;
+ [[[controller stub] andReturnValue:OCMOCK_VALUE(yes)]
+ isKindOfClass:[BrowserWindowController class]];
+ [[[controller expect] andReturnValue:OCMOCK_VALUE(yes)] hasTabStrip];
+ [[[controller expect] andReturnValue:OCMOCK_VALUE(no)] hasTitleBar];
+ [[[controller expect] andReturnValue:OCMOCK_VALUE(yes)] isNormalWindow];
+ [window_ setWindowController:controller];
+
+ closeBoxCell = [window_ accessibilityAttributeValue:
+ NSAccessibilityCloseButtonAttribute];
+ closeBoxControl = [closeBoxCell controlView];
+ EXPECT_TRUE(closeBoxControl);
+ closeBoxFrame = [closeBoxControl frame];
+ windowBounds = [window_ frame];
+ windowBounds.origin = NSZeroPoint;
+ EXPECT_EQ(NSMaxY(closeBoxFrame),
+ NSMaxY(windowBounds) -
+ kFramedWindowButtonsWithTabStripOffsetFromTop);
+ EXPECT_EQ(NSMinX(closeBoxFrame), kFramedWindowButtonsOffsetFromLeft);
+
+ miniaturizeCell = [window_ accessibilityAttributeValue:
+ NSAccessibilityMinimizeButtonAttribute];
+ miniaturizeControl = [miniaturizeCell controlView];
+ EXPECT_TRUE(miniaturizeControl);
+ miniaturizeFrame = [miniaturizeControl frame];
+ EXPECT_EQ(NSMaxY(miniaturizeFrame),
+ NSMaxY(windowBounds) -
+ kFramedWindowButtonsWithTabStripOffsetFromTop);
+ EXPECT_EQ(NSMinX(miniaturizeFrame),
+ NSMaxX(closeBoxFrame) + kFramedWindowButtonsInterButtonSpacing);
+ [window_ setWindowController:nil];
+}
+
+// Test that we actually have a tracking area in place.
+TEST_F(FramedBrowserWindowTest, WindowWidgetTrackingArea) {
+ NSCell* closeBoxCell =
+ [window_ accessibilityAttributeValue:NSAccessibilityCloseButtonAttribute];
+ NSView* closeBoxControl = [closeBoxCell controlView];
+ NSView* frameView = [[window_ contentView] superview];
+ NSArray* trackingAreas = [frameView trackingAreas];
+ NSPoint point = [closeBoxControl frame].origin;
+ point.x += 1;
+ point.y += 1;
+ BOOL foundArea = NO;
+ for (NSTrackingArea* area in trackingAreas) {
+ NSRect rect = [area rect];
+ foundArea = NSPointInRect(point, rect);
+ if (foundArea) {
+ EXPECT_NSEQ(frameView, [area owner]);
+ break;
+ }
+ }
+ EXPECT_TRUE(foundArea);
+}
+
diff --git a/chrome/browser/ui/cocoa/fullscreen_controller.h b/chrome/browser/ui/cocoa/fullscreen_controller.h
new file mode 100644
index 0000000..474d699
--- /dev/null
+++ b/chrome/browser/ui/cocoa/fullscreen_controller.h
@@ -0,0 +1,122 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_FULLSCREEN_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_FULLSCREEN_CONTROLLER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/mac_util.h"
+#include "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
+
+@class BrowserWindowController;
+@class DropdownAnimation;
+
+// Provides a controller to manage fullscreen mode for a single browser window.
+// This class handles running animations, showing and hiding the floating
+// dropdown bar, and managing the tracking area associated with the dropdown.
+// This class does not directly manage any views -- the BrowserWindowController
+// is responsible for positioning and z-ordering views.
+//
+// Tracking areas are disabled while animations are running. If
+// |overlayFrameChanged:| is called while an animation is running, the
+// controller saves the new frame and installs the appropriate tracking area
+// when the animation finishes. This is largely done for ease of
+// implementation; it is easier to check the mouse location at each animation
+// step than it is to manage a constantly-changing tracking area.
+@interface FullscreenController : NSObject<NSAnimationDelegate> {
+ @private
+ // Our parent controller.
+ BrowserWindowController* browserController_; // weak
+
+ // The content view for the fullscreen window. This is nil when not in
+ // fullscreen mode.
+ NSView* contentView_; // weak
+
+ // Whether or not we are in fullscreen mode.
+ BOOL isFullscreen_;
+
+ // The tracking area associated with the floating dropdown bar. This tracking
+ // area is attached to |contentView_|, because when the dropdown is completely
+ // hidden, we still need to keep a 1px tall tracking area visible. Attaching
+ // to the content view allows us to do this. |trackingArea_| can be nil if
+ // not in fullscreen mode or during animations.
+ scoped_nsobject<NSTrackingArea> trackingArea_;
+
+ // Pointer to the currently running animation. Is nil if no animation is
+ // running.
+ scoped_nsobject<DropdownAnimation> currentAnimation_;
+
+ // Timers for scheduled showing/hiding of the bar (which are always done with
+ // animation).
+ scoped_nsobject<NSTimer> showTimer_;
+ scoped_nsobject<NSTimer> hideTimer_;
+
+ // Holds the current bounds of |trackingArea_|, even if |trackingArea_| is
+ // currently nil. Used to restore the tracking area when an animation
+ // completes.
+ NSRect trackingAreaBounds_;
+
+ // Tracks the currently requested fullscreen mode. This should be
+ // |kFullScreenModeNormal| when the window is not main or not fullscreen,
+ // |kFullScreenModeHideAll| while the overlay is hidden, and
+ // |kFullScreenModeHideDock| while the overlay is shown. If the window is not
+ // on the primary screen, this should always be |kFullScreenModeNormal|. This
+ // value can get out of sync with the correct state if we miss a notification
+ // (which can happen when a fullscreen window is closed). Used to track the
+ // current state and make sure we properly restore the menu bar when this
+ // controller is destroyed.
+ mac_util::FullScreenMode currentFullscreenMode_;
+}
+
+@property(readonly, nonatomic) BOOL isFullscreen;
+
+// Designated initializer.
+- (id)initWithBrowserController:(BrowserWindowController*)controller;
+
+// Informs the controller that the browser has entered or exited fullscreen
+// mode. |-enterFullscreenForContentView:showDropdown:| should be called after
+// the fullscreen window is setup, just before it is shown. |-exitFullscreen|
+// should be called before any views are moved back to the non-fullscreen
+// window. If |-enterFullscreenForContentView:showDropdown:| is called, it must
+// be followed with a call to |-exitFullscreen| before the controller is
+// released.
+- (void)enterFullscreenForContentView:(NSView*)contentView
+ showDropdown:(BOOL)showDropdown;
+- (void)exitFullscreen;
+
+// Returns the amount by which the floating bar should be offset downwards (to
+// avoid the menu) and by which the overlay view should be enlarged vertically.
+// Generally, this is > 0 when the fullscreen window is on the primary screen
+// and 0 otherwise.
+- (CGFloat)floatingBarVerticalOffset;
+
+// Informs the controller that the overlay's frame has changed. The controller
+// uses this information to update its tracking areas.
+- (void)overlayFrameChanged:(NSRect)frame;
+
+// Informs the controller that the overlay should be shown/hidden, possibly with
+// animation, possibly after a delay (only applicable for the animated case).
+- (void)ensureOverlayShownWithAnimation:(BOOL)animate delay:(BOOL)delay;
+- (void)ensureOverlayHiddenWithAnimation:(BOOL)animate delay:(BOOL)delay;
+
+// Cancels any running animation and timers.
+- (void)cancelAnimationAndTimers;
+
+// Gets the current floating bar shown fraction.
+- (CGFloat)floatingBarShownFraction;
+
+// Sets a new current floating bar shown fraction. NOTE: This function has side
+// effects, such as modifying the fullscreen mode (menu bar shown state).
+- (void)changeFloatingBarShownFraction:(CGFloat)fraction;
+
+@end
+
+// Notification posted when we're about to enter or leave fullscreen.
+extern NSString* const kWillEnterFullscreenNotification;
+extern NSString* const kWillLeaveFullscreenNotification;
+
+#endif // CHROME_BROWSER_UI_COCOA_FULLSCREEN_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/fullscreen_controller.mm b/chrome/browser/ui/cocoa/fullscreen_controller.mm
new file mode 100644
index 0000000..0f06e22
--- /dev/null
+++ b/chrome/browser/ui/cocoa/fullscreen_controller.mm
@@ -0,0 +1,633 @@
+// 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 "chrome/browser/ui/cocoa/fullscreen_controller.h"
+
+#include <algorithm>
+
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
+
+NSString* const kWillEnterFullscreenNotification =
+ @"WillEnterFullscreenNotification";
+NSString* const kWillLeaveFullscreenNotification =
+ @"WillLeaveFullscreenNotification";
+
+namespace {
+// The activation zone for the main menu is 4 pixels high; if we make it any
+// smaller, then the menu can be made to appear without the bar sliding down.
+const CGFloat kDropdownActivationZoneHeight = 4;
+const NSTimeInterval kDropdownAnimationDuration = 0.12;
+const NSTimeInterval kMouseExitCheckDelay = 0.1;
+// This show delay attempts to match the delay for the main menu.
+const NSTimeInterval kDropdownShowDelay = 0.3;
+const NSTimeInterval kDropdownHideDelay = 0.2;
+
+// The amount by which the floating bar is offset downwards (to avoid the menu)
+// in fullscreen mode. (We can't use |-[NSMenu menuBarHeight]| since it returns
+// 0 when the menu bar is hidden.)
+const CGFloat kFloatingBarVerticalOffset = 22;
+
+} // end namespace
+
+
+// Helper class to manage animations for the fullscreen dropdown bar. Calls
+// [FullscreenController changeFloatingBarShownFraction] once per animation
+// step.
+@interface DropdownAnimation : NSAnimation {
+ @private
+ FullscreenController* controller_;
+ CGFloat startFraction_;
+ CGFloat endFraction_;
+}
+
+@property(readonly, nonatomic) CGFloat startFraction;
+@property(readonly, nonatomic) CGFloat endFraction;
+
+// Designated initializer. Asks |controller| for the current shown fraction, so
+// if the bar is already partially shown or partially hidden, the animation
+// duration may be less than |fullDuration|.
+- (id)initWithFraction:(CGFloat)fromFraction
+ fullDuration:(CGFloat)fullDuration
+ animationCurve:(NSInteger)animationCurve
+ controller:(FullscreenController*)controller;
+
+@end
+
+@implementation DropdownAnimation
+
+@synthesize startFraction = startFraction_;
+@synthesize endFraction = endFraction_;
+
+- (id)initWithFraction:(CGFloat)toFraction
+ fullDuration:(CGFloat)fullDuration
+ animationCurve:(NSInteger)animationCurve
+ controller:(FullscreenController*)controller {
+ // Calculate the effective duration, based on the current shown fraction.
+ DCHECK(controller);
+ CGFloat fromFraction = [controller floatingBarShownFraction];
+ CGFloat effectiveDuration = fabs(fullDuration * (fromFraction - toFraction));
+
+ if ((self = [super gtm_initWithDuration:effectiveDuration
+ eventMask:NSLeftMouseDownMask
+ animationCurve:animationCurve])) {
+ startFraction_ = fromFraction;
+ endFraction_ = toFraction;
+ controller_ = controller;
+ }
+ return self;
+}
+
+// Called once per animation step. Overridden to change the floating bar's
+// position based on the animation's progress.
+- (void)setCurrentProgress:(NSAnimationProgress)progress {
+ CGFloat fraction =
+ startFraction_ + (progress * (endFraction_ - startFraction_));
+ [controller_ changeFloatingBarShownFraction:fraction];
+}
+
+@end
+
+
+@interface FullscreenController (PrivateMethods)
+
+// Returns YES if the fullscreen window is on the primary screen.
+- (BOOL)isWindowOnPrimaryScreen;
+
+// Returns YES if it is ok to show and hide the menu bar in response to the
+// overlay opening and closing. Will return NO if the window is not main or not
+// on the primary monitor.
+- (BOOL)shouldToggleMenuBar;
+
+// Returns |kFullScreenModeHideAll| when the overlay is hidden and
+// |kFullScreenModeHideDock| when the overlay is shown.
+- (mac_util::FullScreenMode)desiredFullscreenMode;
+
+// Change the overlay to the given fraction, with or without animation. Only
+// guaranteed to work properly with |fraction == 0| or |fraction == 1|. This
+// performs the show/hide (animation) immediately. It does not touch the timers.
+- (void)changeOverlayToFraction:(CGFloat)fraction
+ withAnimation:(BOOL)animate;
+
+// Schedule the floating bar to be shown/hidden because of mouse position.
+- (void)scheduleShowForMouse;
+- (void)scheduleHideForMouse;
+
+// Set up the tracking area used to activate the sliding bar or keep it active
+// using with the rectangle in |trackingAreaBounds_|, or remove the tracking
+// area if one was previously set up.
+- (void)setupTrackingArea;
+- (void)removeTrackingAreaIfNecessary;
+
+// Returns YES if the mouse is currently in any current tracking rectangle, NO
+// otherwise.
+- (BOOL)mouseInsideTrackingRect;
+
+// The tracking area can "falsely" report exits when the menu slides down over
+// it. In that case, we have to monitor for a "real" mouse exit on a timer.
+// |-setupMouseExitCheck| schedules a check; |-cancelMouseExitCheck| cancels any
+// scheduled check.
+- (void)setupMouseExitCheck;
+- (void)cancelMouseExitCheck;
+
+// Called (after a delay) by |-setupMouseExitCheck|, to check whether the mouse
+// has exited or not; if it hasn't, it will schedule another check.
+- (void)checkForMouseExit;
+
+// Start timers for showing/hiding the floating bar.
+- (void)startShowTimer;
+- (void)startHideTimer;
+- (void)cancelShowTimer;
+- (void)cancelHideTimer;
+- (void)cancelAllTimers;
+
+// Methods called when the show/hide timers fire. Do not call directly.
+- (void)showTimerFire:(NSTimer*)timer;
+- (void)hideTimerFire:(NSTimer*)timer;
+
+// Stops any running animations, removes tracking areas, etc.
+- (void)cleanup;
+
+// Shows and hides the UI associated with this window being active (having main
+// status). This includes hiding the menu bar and displaying the "Exit
+// Fullscreen" button. These functions are called when the window gains or
+// loses main status as well as in |-cleanup|.
+- (void)showActiveWindowUI;
+- (void)hideActiveWindowUI;
+
+@end
+
+
+@implementation FullscreenController
+
+@synthesize isFullscreen = isFullscreen_;
+
+- (id)initWithBrowserController:(BrowserWindowController*)controller {
+ if ((self == [super init])) {
+ browserController_ = controller;
+ currentFullscreenMode_ = mac_util::kFullScreenModeNormal;
+ }
+
+ // Let the world know what we're up to.
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName:kWillEnterFullscreenNotification
+ object:nil];
+
+ return self;
+}
+
+- (void)dealloc {
+ DCHECK(!isFullscreen_);
+ DCHECK(!trackingArea_);
+ [super dealloc];
+}
+
+- (void)enterFullscreenForContentView:(NSView*)contentView
+ showDropdown:(BOOL)showDropdown {
+ DCHECK(!isFullscreen_);
+ isFullscreen_ = YES;
+ contentView_ = contentView;
+ [self changeFloatingBarShownFraction:(showDropdown ? 1 : 0)];
+
+ // Register for notifications. Self is removed as an observer in |-cleanup|.
+ NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
+ NSWindow* window = [browserController_ window];
+ [nc addObserver:self
+ selector:@selector(windowDidChangeScreen:)
+ name:NSWindowDidChangeScreenNotification
+ object:window];
+
+ [nc addObserver:self
+ selector:@selector(windowDidMove:)
+ name:NSWindowDidMoveNotification
+ object:window];
+
+ [nc addObserver:self
+ selector:@selector(windowDidBecomeMain:)
+ name:NSWindowDidBecomeMainNotification
+ object:window];
+
+ [nc addObserver:self
+ selector:@selector(windowDidResignMain:)
+ name:NSWindowDidResignMainNotification
+ object:window];
+}
+
+- (void)exitFullscreen {
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName:kWillLeaveFullscreenNotification
+ object:nil];
+ DCHECK(isFullscreen_);
+ [self cleanup];
+ isFullscreen_ = NO;
+}
+
+- (void)windowDidChangeScreen:(NSNotification*)notification {
+ [browserController_ resizeFullscreenWindow];
+}
+
+- (void)windowDidMove:(NSNotification*)notification {
+ [browserController_ resizeFullscreenWindow];
+}
+
+- (void)windowDidBecomeMain:(NSNotification*)notification {
+ [self showActiveWindowUI];
+}
+
+- (void)windowDidResignMain:(NSNotification*)notification {
+ [self hideActiveWindowUI];
+}
+
+- (CGFloat)floatingBarVerticalOffset {
+ return [self isWindowOnPrimaryScreen] ? kFloatingBarVerticalOffset : 0;
+}
+
+- (void)overlayFrameChanged:(NSRect)frame {
+ if (!isFullscreen_)
+ return;
+
+ // Make sure |trackingAreaBounds_| always reflects either the tracking area or
+ // the desired tracking area.
+ trackingAreaBounds_ = frame;
+ // The tracking area should always be at least the height of activation zone.
+ NSRect contentBounds = [contentView_ bounds];
+ trackingAreaBounds_.origin.y =
+ std::min(trackingAreaBounds_.origin.y,
+ NSMaxY(contentBounds) - kDropdownActivationZoneHeight);
+ trackingAreaBounds_.size.height =
+ NSMaxY(contentBounds) - trackingAreaBounds_.origin.y + 1;
+
+ // If an animation is currently running, do not set up a tracking area now.
+ // Instead, leave it to be created it in |-animationDidEnd:|.
+ if (currentAnimation_)
+ return;
+
+ [self setupTrackingArea];
+}
+
+- (void)ensureOverlayShownWithAnimation:(BOOL)animate delay:(BOOL)delay {
+ if (!isFullscreen_)
+ return;
+
+ if (animate) {
+ if (delay) {
+ [self startShowTimer];
+ } else {
+ [self cancelAllTimers];
+ [self changeOverlayToFraction:1 withAnimation:YES];
+ }
+ } else {
+ DCHECK(!delay);
+ [self cancelAllTimers];
+ [self changeOverlayToFraction:1 withAnimation:NO];
+ }
+}
+
+- (void)ensureOverlayHiddenWithAnimation:(BOOL)animate delay:(BOOL)delay {
+ if (!isFullscreen_)
+ return;
+
+ if (animate) {
+ if (delay) {
+ [self startHideTimer];
+ } else {
+ [self cancelAllTimers];
+ [self changeOverlayToFraction:0 withAnimation:YES];
+ }
+ } else {
+ DCHECK(!delay);
+ [self cancelAllTimers];
+ [self changeOverlayToFraction:0 withAnimation:NO];
+ }
+}
+
+- (void)cancelAnimationAndTimers {
+ [self cancelAllTimers];
+ [currentAnimation_ stopAnimation];
+ currentAnimation_.reset();
+}
+
+- (CGFloat)floatingBarShownFraction {
+ return [browserController_ floatingBarShownFraction];
+}
+
+- (void)changeFloatingBarShownFraction:(CGFloat)fraction {
+ [browserController_ setFloatingBarShownFraction:fraction];
+
+ mac_util::FullScreenMode desiredMode = [self desiredFullscreenMode];
+ if (desiredMode != currentFullscreenMode_ && [self shouldToggleMenuBar]) {
+ if (currentFullscreenMode_ == mac_util::kFullScreenModeNormal)
+ mac_util::RequestFullScreen(desiredMode);
+ else
+ mac_util::SwitchFullScreenModes(currentFullscreenMode_, desiredMode);
+ currentFullscreenMode_ = desiredMode;
+ }
+}
+
+// Used to activate the floating bar in fullscreen mode.
+- (void)mouseEntered:(NSEvent*)event {
+ DCHECK(isFullscreen_);
+
+ // Having gotten a mouse entered, we no longer need to do exit checks.
+ [self cancelMouseExitCheck];
+
+ NSTrackingArea* trackingArea = [event trackingArea];
+ if (trackingArea == trackingArea_) {
+ // The tracking area shouldn't be active during animation.
+ DCHECK(!currentAnimation_);
+ [self scheduleShowForMouse];
+ }
+}
+
+// Used to deactivate the floating bar in fullscreen mode.
+- (void)mouseExited:(NSEvent*)event {
+ DCHECK(isFullscreen_);
+
+ NSTrackingArea* trackingArea = [event trackingArea];
+ if (trackingArea == trackingArea_) {
+ // The tracking area shouldn't be active during animation.
+ DCHECK(!currentAnimation_);
+
+ // We can get a false mouse exit when the menu slides down, so if the mouse
+ // is still actually over the tracking area, we ignore the mouse exit, but
+ // we set up to check the mouse position again after a delay.
+ if ([self mouseInsideTrackingRect]) {
+ [self setupMouseExitCheck];
+ return;
+ }
+
+ [self scheduleHideForMouse];
+ }
+}
+
+- (void)animationDidStop:(NSAnimation*)animation {
+ // Reset the |currentAnimation_| pointer now that the animation is over.
+ currentAnimation_.reset();
+
+ // Invariant says that the tracking area is not installed while animations are
+ // in progress. Ensure this is true.
+ DCHECK(!trackingArea_);
+ [self removeTrackingAreaIfNecessary]; // For paranoia.
+
+ // Don't automatically set up a new tracking area. When explicitly stopped,
+ // either another animation is going to start immediately or the state will be
+ // changed immediately.
+}
+
+- (void)animationDidEnd:(NSAnimation*)animation {
+ [self animationDidStop:animation];
+
+ // |trackingAreaBounds_| contains the correct tracking area bounds, including
+ // |any updates that may have come while the animation was running. Install a
+ // new tracking area with these bounds.
+ [self setupTrackingArea];
+
+ // TODO(viettrungluu): Better would be to check during the animation; doing it
+ // here means that the timing is slightly off.
+ if (![self mouseInsideTrackingRect])
+ [self scheduleHideForMouse];
+}
+
+@end
+
+
+@implementation FullscreenController (PrivateMethods)
+
+- (BOOL)isWindowOnPrimaryScreen {
+ NSScreen* screen = [[browserController_ window] screen];
+ NSScreen* primaryScreen = [[NSScreen screens] objectAtIndex:0];
+ return (screen == primaryScreen);
+}
+
+- (BOOL)shouldToggleMenuBar {
+ return [self isWindowOnPrimaryScreen] &&
+ [[browserController_ window] isMainWindow];
+}
+
+- (mac_util::FullScreenMode)desiredFullscreenMode {
+ if ([browserController_ floatingBarShownFraction] >= 1.0)
+ return mac_util::kFullScreenModeHideDock;
+ return mac_util::kFullScreenModeHideAll;
+}
+
+- (void)changeOverlayToFraction:(CGFloat)fraction
+ withAnimation:(BOOL)animate {
+ // The non-animated case is really simple, so do it and return.
+ if (!animate) {
+ [currentAnimation_ stopAnimation];
+ [self changeFloatingBarShownFraction:fraction];
+ return;
+ }
+
+ // If we're already animating to the given fraction, then there's nothing more
+ // to do.
+ if (currentAnimation_ && [currentAnimation_ endFraction] == fraction)
+ return;
+
+ // In all other cases, we want to cancel any running animation (which may be
+ // to show or to hide).
+ [currentAnimation_ stopAnimation];
+
+ // Now, if it happens to already be in the right state, there's nothing more
+ // to do.
+ if ([browserController_ floatingBarShownFraction] == fraction)
+ return;
+
+ // Create the animation and set it up.
+ currentAnimation_.reset(
+ [[DropdownAnimation alloc] initWithFraction:fraction
+ fullDuration:kDropdownAnimationDuration
+ animationCurve:NSAnimationEaseOut
+ controller:self]);
+ DCHECK(currentAnimation_);
+ [currentAnimation_ setAnimationBlockingMode:NSAnimationNonblocking];
+ [currentAnimation_ setDelegate:self];
+
+ // If there is an existing tracking area, remove it. We do not track mouse
+ // movements during animations (see class comment in the header file).
+ [self removeTrackingAreaIfNecessary];
+
+ [currentAnimation_ startAnimation];
+}
+
+- (void)scheduleShowForMouse {
+ [browserController_ lockBarVisibilityForOwner:self
+ withAnimation:YES
+ delay:YES];
+}
+
+- (void)scheduleHideForMouse {
+ [browserController_ releaseBarVisibilityForOwner:self
+ withAnimation:YES
+ delay:YES];
+}
+
+- (void)setupTrackingArea {
+ if (trackingArea_) {
+ // If the tracking rectangle is already |trackingAreaBounds_|, quit early.
+ NSRect oldRect = [trackingArea_ rect];
+ if (NSEqualRects(trackingAreaBounds_, oldRect))
+ return;
+
+ // Otherwise, remove it.
+ [self removeTrackingAreaIfNecessary];
+ }
+
+ // Create and add a new tracking area for |frame|.
+ trackingArea_.reset(
+ [[NSTrackingArea alloc] initWithRect:trackingAreaBounds_
+ options:NSTrackingMouseEnteredAndExited |
+ NSTrackingActiveInKeyWindow
+ owner:self
+ userInfo:nil]);
+ DCHECK(contentView_);
+ [contentView_ addTrackingArea:trackingArea_];
+}
+
+- (void)removeTrackingAreaIfNecessary {
+ if (trackingArea_) {
+ DCHECK(contentView_); // |contentView_| better be valid.
+ [contentView_ removeTrackingArea:trackingArea_];
+ trackingArea_.reset();
+ }
+}
+
+- (BOOL)mouseInsideTrackingRect {
+ NSWindow* window = [browserController_ window];
+ NSPoint mouseLoc = [window mouseLocationOutsideOfEventStream];
+ NSPoint mousePos = [contentView_ convertPoint:mouseLoc fromView:nil];
+ return NSMouseInRect(mousePos, trackingAreaBounds_, [contentView_ isFlipped]);
+}
+
+- (void)setupMouseExitCheck {
+ [self performSelector:@selector(checkForMouseExit)
+ withObject:nil
+ afterDelay:kMouseExitCheckDelay];
+}
+
+- (void)cancelMouseExitCheck {
+ [NSObject cancelPreviousPerformRequestsWithTarget:self
+ selector:@selector(checkForMouseExit) object:nil];
+}
+
+- (void)checkForMouseExit {
+ if ([self mouseInsideTrackingRect])
+ [self setupMouseExitCheck];
+ else
+ [self scheduleHideForMouse];
+}
+
+- (void)startShowTimer {
+ // If there's already a show timer going, just keep it.
+ if (showTimer_) {
+ DCHECK([showTimer_ isValid]);
+ DCHECK(!hideTimer_);
+ return;
+ }
+
+ // Cancel the hide timer (if necessary) and set up the new show timer.
+ [self cancelHideTimer];
+ showTimer_.reset(
+ [[NSTimer scheduledTimerWithTimeInterval:kDropdownShowDelay
+ target:self
+ selector:@selector(showTimerFire:)
+ userInfo:nil
+ repeats:NO] retain]);
+ DCHECK([showTimer_ isValid]); // This also checks that |showTimer_ != nil|.
+}
+
+- (void)startHideTimer {
+ // If there's already a hide timer going, just keep it.
+ if (hideTimer_) {
+ DCHECK([hideTimer_ isValid]);
+ DCHECK(!showTimer_);
+ return;
+ }
+
+ // Cancel the show timer (if necessary) and set up the new hide timer.
+ [self cancelShowTimer];
+ hideTimer_.reset(
+ [[NSTimer scheduledTimerWithTimeInterval:kDropdownHideDelay
+ target:self
+ selector:@selector(hideTimerFire:)
+ userInfo:nil
+ repeats:NO] retain]);
+ DCHECK([hideTimer_ isValid]); // This also checks that |hideTimer_ != nil|.
+}
+
+- (void)cancelShowTimer {
+ [showTimer_ invalidate];
+ showTimer_.reset();
+}
+
+- (void)cancelHideTimer {
+ [hideTimer_ invalidate];
+ hideTimer_.reset();
+}
+
+- (void)cancelAllTimers {
+ [self cancelShowTimer];
+ [self cancelHideTimer];
+}
+
+- (void)showTimerFire:(NSTimer*)timer {
+ DCHECK_EQ(showTimer_, timer); // This better be our show timer.
+ [showTimer_ invalidate]; // Make sure it doesn't repeat.
+ showTimer_.reset(); // And get rid of it.
+ [self changeOverlayToFraction:1 withAnimation:YES];
+}
+
+- (void)hideTimerFire:(NSTimer*)timer {
+ DCHECK_EQ(hideTimer_, timer); // This better be our hide timer.
+ [hideTimer_ invalidate]; // Make sure it doesn't repeat.
+ hideTimer_.reset(); // And get rid of it.
+ [self changeOverlayToFraction:0 withAnimation:YES];
+}
+
+- (void)cleanup {
+ [self cancelMouseExitCheck];
+ [self cancelAnimationAndTimers];
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+
+ [self removeTrackingAreaIfNecessary];
+ contentView_ = nil;
+
+ // This isn't tracked when not in fullscreen mode.
+ [browserController_ releaseBarVisibilityForOwner:self
+ withAnimation:NO
+ delay:NO];
+
+ // Call the main status resignation code to perform the associated cleanup,
+ // since we will no longer be receiving actual status resignation
+ // notifications.
+ [self hideActiveWindowUI];
+
+ // No more calls back up to the BWC.
+ browserController_ = nil;
+}
+
+- (void)showActiveWindowUI {
+ DCHECK_EQ(currentFullscreenMode_, mac_util::kFullScreenModeNormal);
+ if (currentFullscreenMode_ != mac_util::kFullScreenModeNormal)
+ return;
+
+ if ([self shouldToggleMenuBar]) {
+ mac_util::FullScreenMode desiredMode = [self desiredFullscreenMode];
+ mac_util::RequestFullScreen(desiredMode);
+ currentFullscreenMode_ = desiredMode;
+ }
+
+ // TODO(rohitrao): Insert the Exit Fullscreen button. http://crbug.com/35956
+}
+
+- (void)hideActiveWindowUI {
+ if (currentFullscreenMode_ != mac_util::kFullScreenModeNormal) {
+ mac_util::ReleaseFullScreen(currentFullscreenMode_);
+ currentFullscreenMode_ = mac_util::kFullScreenModeNormal;
+ }
+
+ // TODO(rohitrao): Remove the Exit Fullscreen button. http://crbug.com/35956
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/fullscreen_window.h b/chrome/browser/ui/cocoa/fullscreen_window.h
new file mode 100644
index 0000000..12be00d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/fullscreen_window.h
@@ -0,0 +1,19 @@
+// 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.
+
+#include <Cocoa/Cocoa.h>
+#import "chrome/browser/ui/cocoa/chrome_browser_window.h"
+
+// A FullscreenWindow is a borderless window suitable for going fullscreen. The
+// returned window is NOT release when closed and is not initially visible.
+// FullscreenWindow derives from ChromeBrowserWindow to inherit hole punching,
+// theming methods, and special event handling
+// (e.g. handleExtraKeyboardShortcut).
+@interface FullscreenWindow : ChromeBrowserWindow
+
+// Initialize a FullscreenWindow for the given screen.
+// Designated initializer.
+- (id)initForScreen:(NSScreen*)screen;
+
+@end
diff --git a/chrome/browser/ui/cocoa/fullscreen_window.mm b/chrome/browser/ui/cocoa/fullscreen_window.mm
new file mode 100644
index 0000000..ecbb34c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/fullscreen_window.mm
@@ -0,0 +1,100 @@
+// 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 "chrome/browser/ui/cocoa/fullscreen_window.h"
+
+#include "base/mac_util.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
+#import "chrome/browser/ui/cocoa/themed_window.h"
+
+@implementation FullscreenWindow
+
+// Make sure our designated initializer gets called.
+- (id)init {
+ return [self initForScreen:[NSScreen mainScreen]];
+}
+
+- (id)initForScreen:(NSScreen*)screen {
+ NSRect contentRect;
+ contentRect.origin = NSZeroPoint;
+ contentRect.size = [screen frame].size;
+
+ if ((self = [super initWithContentRect:contentRect
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:YES
+ screen:screen])) {
+ [self setReleasedWhenClosed:NO];
+ // Borderless windows don't usually show up in the Windows menu so whine at
+ // Cocoa until it complies. See -dealloc and -setTitle: as well.
+ [NSApp addWindowsItem:self title:@"" filename:NO];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ // Paranoia; doesn't seem to be necessary but it doesn't hurt.
+ [NSApp removeWindowsItem:self];
+
+ [super dealloc];
+}
+
+- (void)setTitle:(NSString *)title {
+ [NSApp changeWindowsItem:self title:title filename:NO];
+ [super setTitle:title];
+}
+
+// According to
+// http://www.cocoabuilder.com/archive/message/cocoa/2006/6/19/165953 ,
+// NSBorderlessWindowMask windows cannot become key or main.
+// In our case, however, we don't want that behavior, so we override
+// canBecomeKeyWindow and canBecomeMainWindow.
+
+- (BOOL)canBecomeKeyWindow {
+ return YES;
+}
+
+- (BOOL)canBecomeMainWindow {
+ return YES;
+}
+
+// When becoming/resigning main status, explicitly set the background color,
+// which is required by |TabView|.
+- (void)becomeMainWindow {
+ [super becomeMainWindow];
+ [self setBackgroundColor:[NSColor windowFrameColor]];
+}
+
+- (void)resignMainWindow {
+ [super resignMainWindow];
+ [self setBackgroundColor:[NSColor windowBackgroundColor]];
+}
+
+// We need our own version, since the default one wants to flash the close
+// button (and possibly other things), which results in nothing happening.
+- (void)performClose:(id)sender {
+ BOOL shouldClose = YES;
+
+ // If applicable, check if this window should close.
+ id delegate = [self delegate];
+ if ([delegate respondsToSelector:@selector(windowShouldClose:)])
+ shouldClose = [delegate windowShouldClose:self];
+
+ if (shouldClose) {
+ [self close];
+ }
+}
+
+- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
+ SEL action = [item action];
+
+ // Explicitly enable |-performClose:| (see above); otherwise the fact that
+ // this window does not have a close button results in it being disabled.
+ if (action == @selector(performClose:))
+ return YES;
+
+ return [super validateUserInterfaceItem:item];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/fullscreen_window_unittest.mm b/chrome/browser/ui/cocoa/fullscreen_window_unittest.mm
new file mode 100644
index 0000000..7e54581
--- /dev/null
+++ b/chrome/browser/ui/cocoa/fullscreen_window_unittest.mm
@@ -0,0 +1,47 @@
+// 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.
+
+#include "base/scoped_ptr.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/fullscreen_window.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+@interface PerformCloseUIItem : NSObject<NSValidatedUserInterfaceItem>
+@end
+
+@implementation PerformCloseUIItem
+- (SEL)action {
+ return @selector(performClose:);
+}
+
+- (NSInteger)tag {
+ return 0;
+}
+@end
+
+class FullscreenWindowTest : public CocoaTest {
+};
+
+TEST_F(FullscreenWindowTest, Basics) {
+ scoped_nsobject<FullscreenWindow> window;
+ window.reset([[FullscreenWindow alloc] init]);
+
+ EXPECT_EQ([NSScreen mainScreen], [window screen]);
+ EXPECT_TRUE([window canBecomeKeyWindow]);
+ EXPECT_TRUE([window canBecomeMainWindow]);
+ EXPECT_EQ(NSBorderlessWindowMask, [window styleMask]);
+ EXPECT_TRUE(NSEqualRects([[NSScreen mainScreen] frame], [window frame]));
+ EXPECT_FALSE([window isReleasedWhenClosed]);
+}
+
+TEST_F(FullscreenWindowTest, CanPerformClose) {
+ scoped_nsobject<FullscreenWindow> window;
+ window.reset([[FullscreenWindow alloc] init]);
+
+ scoped_nsobject<PerformCloseUIItem> item;
+ item.reset([[PerformCloseUIItem alloc] init]);
+
+ EXPECT_TRUE([window validateUserInterfaceItem:item.get()]);
+}
diff --git a/chrome/browser/ui/cocoa/gradient_button_cell.h b/chrome/browser/ui/cocoa/gradient_button_cell.h
new file mode 100644
index 0000000..a1e905f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/gradient_button_cell.h
@@ -0,0 +1,120 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_GRADIENT_BUTTON_CELL_H_
+#define CHROME_BROWSER_UI_COCOA_GRADIENT_BUTTON_CELL_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+
+class ThemeProvider;
+
+// Base class for button cells for toolbar and bookmark bar.
+//
+// This is a button cell that handles drawing/highlighting of buttons.
+// The appearance is determined by setting the cell's tag (not the
+// view's) to one of the constants below (ButtonType).
+
+// Set this as the cell's tag.
+enum {
+ kLeftButtonType = -1,
+ kLeftButtonWithShadowType = -2,
+ kStandardButtonType = 0,
+ kRightButtonType = 1,
+ kMiddleButtonType = 2,
+ // Draws like a standard button, except when clicked where the interior
+ // doesn't darken using the theme's "pressed" gradient. Instead uses the
+ // normal un-pressed gradient.
+ kStandardButtonTypeWithLimitedClickFeedback = 3,
+};
+typedef NSInteger ButtonType;
+
+namespace gradient_button_cell {
+
+// Pulsing state for this button.
+typedef enum {
+ // Stable states.
+ kPulsedOn,
+ kPulsedOff,
+ // In motion which will end in a stable state.
+ kPulsingOn,
+ kPulsingOff,
+ // In continuous motion.
+ kPulsingContinuous,
+} PulseState;
+
+};
+
+
+@interface GradientButtonCell : NSButtonCell {
+ @private
+ // Custom drawing means we need to perform our own mouse tracking if
+ // the cell is setShowsBorderOnlyWhileMouseInside:YES.
+ BOOL isMouseInside_;
+ scoped_nsobject<NSTrackingArea> trackingArea_;
+ BOOL shouldTheme_;
+ CGFloat hoverAlpha_; // 0-1. Controls the alpha during mouse hover
+ NSTimeInterval lastHoverUpdate_;
+ scoped_nsobject<NSGradient> gradient_;
+ gradient_button_cell::PulseState pulseState_;
+ CGFloat pulseMultiplier_; // for selecting pulse direction when continuous.
+ CGFloat outerStrokeAlphaMult_; // For pulsing.
+ scoped_nsobject<NSImage> overlayImage_;
+}
+
+// Turn off theming. Temporary work-around.
+- (void)setShouldTheme:(BOOL)shouldTheme;
+
+- (void)drawBorderAndFillForTheme:(ThemeProvider*)themeProvider
+ controlView:(NSView*)controlView
+ innerPath:(NSBezierPath*)innerPath
+ showClickedGradient:(BOOL)showClickedGradient
+ showHighlightGradient:(BOOL)showHighlightGradient
+ hoverAlpha:(CGFloat)hoverAlpha
+ active:(BOOL)active
+ cellFrame:(NSRect)cellFrame
+ defaultGradient:(NSGradient*)defaultGradient;
+
+// Let the view know when the mouse moves in and out. A timer will update
+// the current hoverAlpha_ based on these events.
+- (void)setMouseInside:(BOOL)flag animate:(BOOL)animate;
+
+// Gets the path which tightly bounds the outside of the button. This is needed
+// to produce images of clear buttons which only include the area inside, since
+// the background of the button is drawn by someone else.
+- (NSBezierPath*)clipPathForFrame:(NSRect)cellFrame
+ inView:(NSView*)controlView;
+
+// Turn on or off continuous pulsing. When turning off continuous
+// pulsing, leave our pulse state in the correct ending position for
+// our isMouseInside_ property. Public since it's called from the
+// bookmark bubble.
+- (void)setIsContinuousPulsing:(BOOL)continuous;
+
+// Returns continuous pulse state.
+- (BOOL)isContinuousPulsing;
+
+// Safely stop continuous pulsing by turning off all timers.
+// May leave the cell in an odd state.
+// Needed by an owning control's dealloc routine.
+- (void)safelyStopPulsing;
+
+@property(assign, nonatomic) CGFloat hoverAlpha;
+
+// An image that will be drawn after the normal content of the button cell,
+// overlaying it. Never themed.
+@property(retain, nonatomic) NSImage* overlayImage;
+
+@end
+
+@interface GradientButtonCell(TestingAPI)
+- (BOOL)isMouseInside;
+- (BOOL)pulsing;
+- (gradient_button_cell::PulseState)pulseState;
+- (void)setPulseState:(gradient_button_cell::PulseState)pstate;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_GRADIENT_BUTTON_CELL_H_
diff --git a/chrome/browser/ui/cocoa/gradient_button_cell.mm b/chrome/browser/ui/cocoa/gradient_button_cell.mm
new file mode 100644
index 0000000..459aa8e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/gradient_button_cell.mm
@@ -0,0 +1,751 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/gradient_button_cell.h"
+
+#include "base/logging.h"
+#import "base/scoped_nsobject.h"
+#import "chrome/browser/themes/browser_theme_provider.h"
+#import "chrome/browser/ui/cocoa/image_utils.h"
+#import "chrome/browser/ui/cocoa/themed_window.h"
+#include "grit/theme_resources.h"
+#import "third_party/GTM/AppKit/GTMNSColor+Luminance.h"
+
+@interface GradientButtonCell (Private)
+- (void)sharedInit;
+
+// Get drawing parameters for a given cell frame in a given view. The inner
+// frame is the one required by |-drawInteriorWithFrame:inView:|. The inner and
+// outer paths are the ones required by |-drawBorderAndFillForTheme:...|. The
+// outer path also gives the area in which to clip. Any of the |return...|
+// arguments may be NULL (in which case the given parameter won't be returned).
+// If |returnInnerPath| or |returnOuterPath|, |*returnInnerPath| or
+// |*returnOuterPath| should be nil, respectively.
+- (void)getDrawParamsForFrame:(NSRect)cellFrame
+ inView:(NSView*)controlView
+ innerFrame:(NSRect*)returnInnerFrame
+ innerPath:(NSBezierPath**)returnInnerPath
+ clipPath:(NSBezierPath**)returnClipPath;
+
+- (void)updateTrackingAreas;
+
+@end
+
+
+static const NSTimeInterval kAnimationShowDuration = 0.2;
+
+// Note: due to a bug (?), drawWithFrame:inView: does not call
+// drawBorderAndFillForTheme::::: unless the mouse is inside. The net
+// effect is that our "fade out" when the mouse leaves becaumes
+// instantaneous. When I "fixed" it things looked horrible; the
+// hover-overed bookmark button would stay highlit for 0.4 seconds
+// which felt like latency/lag. I'm leaving the "bug" in place for
+// now so we don't suck. -jrg
+static const NSTimeInterval kAnimationHideDuration = 0.4;
+
+static const NSTimeInterval kAnimationContinuousCycleDuration = 0.4;
+
+@implementation GradientButtonCell
+
+@synthesize hoverAlpha = hoverAlpha_;
+
+// For nib instantiations
+- (id)initWithCoder:(NSCoder*)decoder {
+ if ((self = [super initWithCoder:decoder])) {
+ [self sharedInit];
+ }
+ return self;
+}
+
+// For programmatic instantiations
+- (id)initTextCell:(NSString*)string {
+ if ((self = [super initTextCell:string])) {
+ [self sharedInit];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ if (trackingArea_) {
+ [[self controlView] removeTrackingArea:trackingArea_];
+ trackingArea_.reset();
+ }
+ [super dealloc];
+}
+
+// Return YES if we are pulsing (towards another state or continuously).
+- (BOOL)pulsing {
+ if ((pulseState_ == gradient_button_cell::kPulsingOn) ||
+ (pulseState_ == gradient_button_cell::kPulsingOff) ||
+ (pulseState_ == gradient_button_cell::kPulsingContinuous))
+ return YES;
+ return NO;
+}
+
+// Perform one pulse step when animating a pulse.
+- (void)performOnePulseStep {
+ NSTimeInterval thisUpdate = [NSDate timeIntervalSinceReferenceDate];
+ NSTimeInterval elapsed = thisUpdate - lastHoverUpdate_;
+ CGFloat opacity = [self hoverAlpha];
+
+ // Update opacity based on state.
+ // Adjust state if we have finished.
+ switch (pulseState_) {
+ case gradient_button_cell::kPulsingOn:
+ opacity += elapsed / kAnimationShowDuration;
+ if (opacity > 1.0) {
+ [self setPulseState:gradient_button_cell::kPulsedOn];
+ return;
+ }
+ break;
+ case gradient_button_cell::kPulsingOff:
+ opacity -= elapsed / kAnimationHideDuration;
+ if (opacity < 0.0) {
+ [self setPulseState:gradient_button_cell::kPulsedOff];
+ return;
+ }
+ break;
+ case gradient_button_cell::kPulsingContinuous:
+ opacity += elapsed / kAnimationContinuousCycleDuration * pulseMultiplier_;
+ if (opacity > 1.0) {
+ opacity = 1.0;
+ pulseMultiplier_ *= -1.0;
+ } else if (opacity < 0.0) {
+ opacity = 0.0;
+ pulseMultiplier_ *= -1.0;
+ }
+ outerStrokeAlphaMult_ = opacity;
+ break;
+ default:
+ NOTREACHED() << "unknown pulse state";
+ }
+
+ // Update our control.
+ lastHoverUpdate_ = thisUpdate;
+ [self setHoverAlpha:opacity];
+ [[self controlView] setNeedsDisplay:YES];
+
+ // If our state needs it, keep going.
+ if ([self pulsing]) {
+ [self performSelector:_cmd withObject:nil afterDelay:0.02];
+ }
+}
+
+- (gradient_button_cell::PulseState)pulseState {
+ return pulseState_;
+}
+
+// Set the pulsing state. This can either set the pulse to on or off
+// immediately (e.g. kPulsedOn, kPulsedOff) or initiate an animated
+// state change.
+- (void)setPulseState:(gradient_button_cell::PulseState)pstate {
+ pulseState_ = pstate;
+ pulseMultiplier_ = 0.0;
+ [NSObject cancelPreviousPerformRequestsWithTarget:self];
+ lastHoverUpdate_ = [NSDate timeIntervalSinceReferenceDate];
+
+ switch (pstate) {
+ case gradient_button_cell::kPulsedOn:
+ case gradient_button_cell::kPulsedOff:
+ outerStrokeAlphaMult_ = 1.0;
+ [self setHoverAlpha:((pulseState_ == gradient_button_cell::kPulsedOn) ?
+ 1.0 : 0.0)];
+ [[self controlView] setNeedsDisplay:YES];
+ break;
+ case gradient_button_cell::kPulsingOn:
+ case gradient_button_cell::kPulsingOff:
+ outerStrokeAlphaMult_ = 1.0;
+ // Set initial value then engage timer.
+ [self setHoverAlpha:((pulseState_ == gradient_button_cell::kPulsingOn) ?
+ 0.0 : 1.0)];
+ [self performOnePulseStep];
+ break;
+ case gradient_button_cell::kPulsingContinuous:
+ // Semantics of continuous pulsing are that we pulse independent
+ // of mouse position.
+ pulseMultiplier_ = 1.0;
+ [self performOnePulseStep];
+ break;
+ default:
+ CHECK(0);
+ break;
+ }
+}
+
+- (void)safelyStopPulsing {
+ [NSObject cancelPreviousPerformRequestsWithTarget:self];
+}
+
+- (void)setIsContinuousPulsing:(BOOL)continuous {
+ if (!continuous && pulseState_ != gradient_button_cell::kPulsingContinuous)
+ return;
+ if (continuous) {
+ [self setPulseState:gradient_button_cell::kPulsingContinuous];
+ } else {
+ [self setPulseState:(isMouseInside_ ? gradient_button_cell::kPulsedOn :
+ gradient_button_cell::kPulsedOff)];
+ }
+}
+
+- (BOOL)isContinuousPulsing {
+ return (pulseState_ == gradient_button_cell::kPulsingContinuous) ?
+ YES : NO;
+}
+
+#if 1
+// If we are not continuously pulsing, perform a pulse animation to
+// reflect our new state.
+- (void)setMouseInside:(BOOL)flag animate:(BOOL)animated {
+ isMouseInside_ = flag;
+ if (pulseState_ != gradient_button_cell::kPulsingContinuous) {
+ if (animated) {
+ [self setPulseState:(isMouseInside_ ? gradient_button_cell::kPulsingOn :
+ gradient_button_cell::kPulsingOff)];
+ } else {
+ [self setPulseState:(isMouseInside_ ? gradient_button_cell::kPulsedOn :
+ gradient_button_cell::kPulsedOff)];
+ }
+ }
+}
+#else
+
+- (void)adjustHoverValue {
+ NSTimeInterval thisUpdate = [NSDate timeIntervalSinceReferenceDate];
+
+ NSTimeInterval elapsed = thisUpdate - lastHoverUpdate_;
+
+ CGFloat opacity = [self hoverAlpha];
+ if (isMouseInside_) {
+ opacity += elapsed / kAnimationShowDuration;
+ } else {
+ opacity -= elapsed / kAnimationHideDuration;
+ }
+
+ if (!isMouseInside_ && opacity < 0) {
+ opacity = 0;
+ } else if (isMouseInside_ && opacity > 1) {
+ opacity = 1;
+ } else {
+ [self performSelector:_cmd withObject:nil afterDelay:0.02];
+ }
+ lastHoverUpdate_ = thisUpdate;
+ [self setHoverAlpha:opacity];
+
+ [[self controlView] setNeedsDisplay:YES];
+}
+
+- (void)setMouseInside:(BOOL)flag animate:(BOOL)animated {
+ isMouseInside_ = flag;
+ if (animated) {
+ lastHoverUpdate_ = [NSDate timeIntervalSinceReferenceDate];
+ [self adjustHoverValue];
+ } else {
+ [NSObject cancelPreviousPerformRequestsWithTarget:self];
+ [self setHoverAlpha:flag ? 1.0 : 0.0];
+ }
+ [[self controlView] setNeedsDisplay:YES];
+}
+
+
+
+#endif
+
+- (NSGradient*)gradientForHoverAlpha:(CGFloat)hoverAlpha
+ isThemed:(BOOL)themed {
+ CGFloat startAlpha = 0.6 + 0.3 * hoverAlpha;
+ CGFloat endAlpha = 0.333 * hoverAlpha;
+
+ if (themed) {
+ startAlpha = 0.2 + 0.35 * hoverAlpha;
+ endAlpha = 0.333 * hoverAlpha;
+ }
+
+ NSColor* startColor =
+ [NSColor colorWithCalibratedWhite:1.0
+ alpha:startAlpha];
+ NSColor* endColor =
+ [NSColor colorWithCalibratedWhite:1.0 - 0.15 * hoverAlpha
+ alpha:endAlpha];
+ NSGradient* gradient = [[NSGradient alloc] initWithColorsAndLocations:
+ startColor, hoverAlpha * 0.33,
+ endColor, 1.0, nil];
+
+ return [gradient autorelease];
+}
+
+- (void)sharedInit {
+ shouldTheme_ = YES;
+ pulseState_ = gradient_button_cell::kPulsedOff;
+ pulseMultiplier_ = 1.0;
+ outerStrokeAlphaMult_ = 1.0;
+ gradient_.reset([[self gradientForHoverAlpha:0.0 isThemed:NO] retain]);
+}
+
+- (void)setShouldTheme:(BOOL)shouldTheme {
+ shouldTheme_ = shouldTheme;
+}
+
+- (NSImage*)overlayImage {
+ return overlayImage_.get();
+}
+
+- (void)setOverlayImage:(NSImage*)image {
+ overlayImage_.reset([image retain]);
+ [[self controlView] setNeedsDisplay:YES];
+}
+
+- (NSBackgroundStyle)interiorBackgroundStyle {
+ // Never lower the interior, since that just leads to a weird shadow which can
+ // often interact badly with the theme.
+ return NSBackgroundStyleRaised;
+}
+
+- (void)mouseEntered:(NSEvent*)theEvent {
+ [self setMouseInside:YES animate:YES];
+}
+
+- (void)mouseExited:(NSEvent*)theEvent {
+ [self setMouseInside:NO animate:YES];
+}
+
+- (BOOL)isMouseInside {
+ return trackingArea_ && isMouseInside_;
+}
+
+// Since we have our own drawWithFrame:, we need to also have our own
+// logic for determining when the mouse is inside for honoring this
+// request.
+- (void)setShowsBorderOnlyWhileMouseInside:(BOOL)showOnly {
+ [super setShowsBorderOnlyWhileMouseInside:showOnly];
+ if (showOnly) {
+ if (trackingArea_.get()) {
+ [self setShowsBorderOnlyWhileMouseInside:NO];
+ }
+ [self updateTrackingAreas];
+ } else {
+ if (trackingArea_) {
+ [[self controlView] removeTrackingArea:trackingArea_];
+ trackingArea_.reset(nil);
+ if (isMouseInside_) {
+ isMouseInside_ = NO;
+ [[self controlView] setNeedsDisplay:YES];
+ }
+ }
+ }
+}
+
+// TODO(viettrungluu): clean up/reorganize.
+- (void)drawBorderAndFillForTheme:(ThemeProvider*)themeProvider
+ controlView:(NSView*)controlView
+ innerPath:(NSBezierPath*)innerPath
+ showClickedGradient:(BOOL)showClickedGradient
+ showHighlightGradient:(BOOL)showHighlightGradient
+ hoverAlpha:(CGFloat)hoverAlpha
+ active:(BOOL)active
+ cellFrame:(NSRect)cellFrame
+ defaultGradient:(NSGradient*)defaultGradient {
+ BOOL isFlatButton = [self showsBorderOnlyWhileMouseInside];
+
+ // For flat (unbordered when not hovered) buttons, never use the toolbar
+ // button background image, but the modest gradient used for themed buttons.
+ // To make things even more modest, scale the hover alpha down by 40 percent
+ // unless clicked.
+ NSColor* backgroundImageColor;
+ BOOL useThemeGradient;
+ if (isFlatButton) {
+ backgroundImageColor = nil;
+ useThemeGradient = YES;
+ if (!showClickedGradient)
+ hoverAlpha *= 0.6;
+ } else {
+ backgroundImageColor =
+ themeProvider ?
+ themeProvider->GetNSImageColorNamed(IDR_THEME_BUTTON_BACKGROUND,
+ false) :
+ nil;
+ useThemeGradient = backgroundImageColor ? YES : NO;
+ }
+
+ // The basic gradient shown inside; see above.
+ NSGradient* gradient;
+ if (hoverAlpha == 0 && !useThemeGradient) {
+ gradient = defaultGradient ? defaultGradient
+ : gradient_;
+ } else {
+ gradient = [self gradientForHoverAlpha:hoverAlpha
+ isThemed:useThemeGradient];
+ }
+
+ // If we're drawing a background image, show that; else possibly show the
+ // clicked gradient.
+ if (backgroundImageColor) {
+ [backgroundImageColor set];
+ // Set the phase to match window.
+ NSRect trueRect = [controlView convertRect:cellFrame toView:nil];
+ [[NSGraphicsContext currentContext]
+ setPatternPhase:NSMakePoint(NSMinX(trueRect), NSMaxY(trueRect))];
+ [innerPath fill];
+ } else {
+ if (showClickedGradient) {
+ NSGradient* clickedGradient = nil;
+ if (isFlatButton &&
+ [self tag] == kStandardButtonTypeWithLimitedClickFeedback) {
+ clickedGradient = gradient;
+ } else {
+ clickedGradient = themeProvider ? themeProvider->GetNSGradient(
+ active ?
+ BrowserThemeProvider::GRADIENT_TOOLBAR_BUTTON_PRESSED :
+ BrowserThemeProvider::GRADIENT_TOOLBAR_BUTTON_PRESSED_INACTIVE) :
+ nil;
+ }
+ [clickedGradient drawInBezierPath:innerPath angle:90.0];
+ }
+ }
+
+ // Visually indicate unclicked, enabled buttons.
+ if (!showClickedGradient && [self isEnabled]) {
+ [NSGraphicsContext saveGraphicsState];
+ [innerPath addClip];
+
+ // Draw the inner glow.
+ if (hoverAlpha > 0) {
+ [innerPath setLineWidth:2];
+ [[NSColor colorWithCalibratedWhite:1.0 alpha:0.2 * hoverAlpha] setStroke];
+ [innerPath stroke];
+ }
+
+ // Draw the top inner highlight.
+ NSAffineTransform* highlightTransform = [NSAffineTransform transform];
+ [highlightTransform translateXBy:1 yBy:1];
+ scoped_nsobject<NSBezierPath> highlightPath([innerPath copy]);
+ [highlightPath transformUsingAffineTransform:highlightTransform];
+ [[NSColor colorWithCalibratedWhite:1.0 alpha:0.2] setStroke];
+ [highlightPath stroke];
+
+ // Draw the gradient inside.
+ [gradient drawInBezierPath:innerPath angle:90.0];
+
+ [NSGraphicsContext restoreGraphicsState];
+ }
+
+ // Don't draw anything else for disabled flat buttons.
+ if (isFlatButton && ![self isEnabled])
+ return;
+
+ // Draw the outer stroke.
+ NSColor* strokeColor = nil;
+ if (showClickedGradient) {
+ strokeColor = [NSColor
+ colorWithCalibratedWhite:0.0
+ alpha:0.3 * outerStrokeAlphaMult_];
+ } else {
+ strokeColor = themeProvider ? themeProvider->GetNSColor(
+ active ? BrowserThemeProvider::COLOR_TOOLBAR_BUTTON_STROKE :
+ BrowserThemeProvider::COLOR_TOOLBAR_BUTTON_STROKE_INACTIVE,
+ true) : [NSColor colorWithCalibratedWhite:0.0
+ alpha:0.3 * outerStrokeAlphaMult_];
+ }
+ [strokeColor setStroke];
+
+ [innerPath setLineWidth:1];
+ [innerPath stroke];
+}
+
+// TODO(viettrungluu): clean this up.
+// (Private)
+- (void)getDrawParamsForFrame:(NSRect)cellFrame
+ inView:(NSView*)controlView
+ innerFrame:(NSRect*)returnInnerFrame
+ innerPath:(NSBezierPath**)returnInnerPath
+ clipPath:(NSBezierPath**)returnClipPath {
+ // Constants from Cole. Will kConstant them once the feedback loop
+ // is complete.
+ NSRect drawFrame = NSInsetRect(cellFrame, 1.5, 1.5);
+ NSRect innerFrame = NSInsetRect(cellFrame, 2, 1);
+ const CGFloat radius = 3.5;
+
+ ButtonType type = [[(NSControl*)controlView cell] tag];
+ switch (type) {
+ case kMiddleButtonType:
+ drawFrame.size.width += 20;
+ innerFrame.size.width += 2;
+ // Fallthrough
+ case kRightButtonType:
+ drawFrame.origin.x -= 20;
+ innerFrame.origin.x -= 2;
+ // Fallthrough
+ case kLeftButtonType:
+ case kLeftButtonWithShadowType:
+ drawFrame.size.width += 20;
+ innerFrame.size.width += 2;
+ default:
+ break;
+ }
+ if (type == kLeftButtonWithShadowType)
+ innerFrame.size.width -= 1.0;
+
+ // Return results if |return...| not null.
+ if (returnInnerFrame)
+ *returnInnerFrame = innerFrame;
+ if (returnInnerPath) {
+ DCHECK(*returnInnerPath == nil);
+ *returnInnerPath = [NSBezierPath bezierPathWithRoundedRect:drawFrame
+ xRadius:radius
+ yRadius:radius];
+ }
+ if (returnClipPath) {
+ DCHECK(*returnClipPath == nil);
+ NSRect clipPathRect = NSInsetRect(drawFrame, -0.5, -0.5);
+ *returnClipPath = [NSBezierPath bezierPathWithRoundedRect:clipPathRect
+ xRadius:radius + 0.5
+ yRadius:radius + 0.5];
+ }
+}
+
+// TODO(viettrungluu): clean this up.
+- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
+ NSRect innerFrame;
+ NSBezierPath* innerPath = nil;
+ [self getDrawParamsForFrame:cellFrame
+ inView:controlView
+ innerFrame:&innerFrame
+ innerPath:&innerPath
+ clipPath:NULL];
+
+ BOOL pressed = ([((NSControl*)[self controlView]) isEnabled] &&
+ [self isHighlighted]);
+ NSWindow* window = [controlView window];
+ ThemeProvider* themeProvider = [window themeProvider];
+ BOOL active = [window isKeyWindow] || [window isMainWindow];
+
+ // Stroke the borders and appropriate fill gradient. If we're borderless, the
+ // only time we want to draw the inner gradient is if we're highlighted or if
+ // we're the first responder (when "Full Keyboard Access" is turned on).
+ if (([self isBordered] && ![self showsBorderOnlyWhileMouseInside]) ||
+ pressed ||
+ [self isMouseInside] ||
+ [self isContinuousPulsing] ||
+ [self showsFirstResponder]) {
+
+ // When pulsing we want the bookmark to stand out a little more.
+ BOOL showClickedGradient = pressed ||
+ (pulseState_ == gradient_button_cell::kPulsingContinuous);
+
+ // When first responder, turn the hover alpha all the way up.
+ CGFloat hoverAlpha = [self hoverAlpha];
+ if ([self showsFirstResponder])
+ hoverAlpha = 1.0;
+
+ [self drawBorderAndFillForTheme:themeProvider
+ controlView:controlView
+ innerPath:innerPath
+ showClickedGradient:showClickedGradient
+ showHighlightGradient:[self isHighlighted]
+ hoverAlpha:hoverAlpha
+ active:active
+ cellFrame:cellFrame
+ defaultGradient:nil];
+ }
+
+ // If this is the left side of a segmented button, draw a slight shadow.
+ ButtonType type = [[(NSControl*)controlView cell] tag];
+ if (type == kLeftButtonWithShadowType) {
+ NSRect borderRect, contentRect;
+ NSDivideRect(cellFrame, &borderRect, &contentRect, 1.0, NSMaxXEdge);
+ NSColor* stroke = themeProvider ? themeProvider->GetNSColor(
+ active ? BrowserThemeProvider::COLOR_TOOLBAR_BUTTON_STROKE :
+ BrowserThemeProvider::COLOR_TOOLBAR_BUTTON_STROKE_INACTIVE,
+ true) : [NSColor blackColor];
+
+ [[stroke colorWithAlphaComponent:0.2] set];
+ NSRectFillUsingOperation(NSInsetRect(borderRect, 0, 2),
+ NSCompositeSourceOver);
+ }
+ [self drawInteriorWithFrame:innerFrame inView:controlView];
+}
+
+- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
+ if (shouldTheme_) {
+ BOOL isTemplate = [[self image] isTemplate];
+
+ [NSGraphicsContext saveGraphicsState];
+
+ CGContextRef context =
+ (CGContextRef)([[NSGraphicsContext currentContext] graphicsPort]);
+
+ BrowserThemeProvider* themeProvider = static_cast<BrowserThemeProvider*>(
+ [[controlView window] themeProvider]);
+ NSColor* color = themeProvider ?
+ themeProvider->GetNSColorTint(BrowserThemeProvider::TINT_BUTTONS,
+ true) :
+ [NSColor blackColor];
+
+ if (isTemplate && themeProvider && themeProvider->UsingDefaultTheme()) {
+ scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
+ [shadow.get() setShadowColor:themeProvider->GetNSColor(
+ BrowserThemeProvider::COLOR_TOOLBAR_BEZEL, true)];
+ [shadow.get() setShadowOffset:NSMakeSize(0.0, -1.0)];
+ [shadow setShadowBlurRadius:1.0];
+ [shadow set];
+ }
+
+ CGContextBeginTransparencyLayer(context, 0);
+ NSRect imageRect = NSZeroRect;
+ imageRect.size = [[self image] size];
+ NSRect drawRect = [self imageRectForBounds:cellFrame];
+ [[self image] drawInRect:drawRect
+ fromRect:imageRect
+ operation:NSCompositeSourceOver
+ fraction:[self isEnabled] ? 1.0 : 0.5
+ neverFlipped:YES];
+ if (isTemplate && color) {
+ [color set];
+ NSRectFillUsingOperation(cellFrame, NSCompositeSourceAtop);
+ }
+ CGContextEndTransparencyLayer(context);
+
+ [NSGraphicsContext restoreGraphicsState];
+ } else {
+ // NSCell draws these off-center for some reason, probably because of the
+ // positioning of the control in the xib.
+ [super drawInteriorWithFrame:NSOffsetRect(cellFrame, 0, 1)
+ inView:controlView];
+ }
+
+ if (overlayImage_) {
+ NSRect imageRect = NSZeroRect;
+ imageRect.size = [overlayImage_ size];
+ [overlayImage_ drawInRect:[self imageRectForBounds:cellFrame]
+ fromRect:imageRect
+ operation:NSCompositeSourceOver
+ fraction:[self isEnabled] ? 1.0 : 0.5
+ neverFlipped:YES];
+ }
+}
+
+// Overriden from NSButtonCell so we can display a nice fadeout effect for
+// button titles that overflow.
+// This method is copied in the most part from GTMFadeTruncatingTextFieldCell,
+// the only difference is that here we draw the text ourselves rather than
+// calling the super to do the work.
+// We can't use GTMFadeTruncatingTextFieldCell because there's no easy way to
+// get it to work with NSButtonCell.
+// TODO(jeremy): Move this to GTM.
+- (NSRect)drawTitle:(NSAttributedString *)title
+ withFrame:(NSRect)cellFrame
+ inView:(NSView *)controlView {
+ NSSize size = [title size];
+
+ // Empirically, Cocoa will draw an extra 2 pixels past NSWidth(cellFrame)
+ // before it clips the text.
+ const CGFloat kOverflowBeforeClip = 2;
+ // Don't complicate drawing unless we need to clip.
+ if (floor(size.width) <= (NSWidth(cellFrame) + kOverflowBeforeClip)) {
+ return [super drawTitle:title withFrame:cellFrame inView:controlView];
+ }
+
+ // Gradient is about twice our line height long.
+ CGFloat gradientWidth = MIN(size.height * 2, NSWidth(cellFrame) / 4);
+
+ NSRect solidPart, gradientPart;
+ NSDivideRect(cellFrame, &gradientPart, &solidPart, gradientWidth, NSMaxXEdge);
+
+ // Draw non-gradient part without transparency layer, as light text on a dark
+ // background looks bad with a gradient layer.
+ [[NSGraphicsContext currentContext] saveGraphicsState];
+ [NSBezierPath clipRect:solidPart];
+
+ // 11 is the magic number needed to make this match the native NSButtonCell's
+ // label display.
+ CGFloat textLeft = [[self image] size].width + 11;
+
+ // For some reason, the height of cellFrame as passed in is totally bogus.
+ // For vertical centering purposes, we need the bounds of the containing
+ // view.
+ NSRect buttonFrame = [[self controlView] frame];
+
+ // Off-by-one to match native NSButtonCell's version.
+ NSPoint textOffset = NSMakePoint(textLeft,
+ (NSHeight(buttonFrame) - size.height)/2 + 1);
+ [title drawAtPoint:textOffset];
+ [[NSGraphicsContext currentContext] restoreGraphicsState];
+
+ // Draw the gradient part with a transparency layer. This makes the text look
+ // suboptimal, but since it fades out, that's ok.
+ [[NSGraphicsContext currentContext] saveGraphicsState];
+ [NSBezierPath clipRect:gradientPart];
+ CGContextRef context = static_cast<CGContextRef>(
+ [[NSGraphicsContext currentContext] graphicsPort]);
+ CGContextBeginTransparencyLayerWithRect(context,
+ NSRectToCGRect(gradientPart), 0);
+ [title drawAtPoint:textOffset];
+
+ // TODO(alcor): switch this to GTMLinearRGBShading if we ever need on 10.4
+ NSColor *color = [NSColor textColor]; //[self textColor];
+ NSColor *alphaColor = [color colorWithAlphaComponent:0.0];
+ NSGradient *mask = [[NSGradient alloc] initWithStartingColor:color
+ endingColor:alphaColor];
+
+ // Draw the gradient mask
+ CGContextSetBlendMode(context, kCGBlendModeDestinationIn);
+ [mask drawFromPoint:NSMakePoint(NSMaxX(cellFrame) - gradientWidth,
+ NSMinY(cellFrame))
+ toPoint:NSMakePoint(NSMaxX(cellFrame),
+ NSMinY(cellFrame))
+ options:NSGradientDrawsBeforeStartingLocation];
+ [mask release];
+ CGContextEndTransparencyLayer(context);
+ [[NSGraphicsContext currentContext] restoreGraphicsState];
+
+ return cellFrame;
+}
+
+- (NSBezierPath*)clipPathForFrame:(NSRect)cellFrame
+ inView:(NSView*)controlView {
+ NSBezierPath* boundingPath = nil;
+ [self getDrawParamsForFrame:cellFrame
+ inView:controlView
+ innerFrame:NULL
+ innerPath:NULL
+ clipPath:&boundingPath];
+ return boundingPath;
+}
+
+- (void)resetCursorRect:(NSRect)cellFrame inView:(NSView*)controlView {
+ [super resetCursorRect:cellFrame inView:controlView];
+ if (trackingArea_)
+ [self updateTrackingAreas];
+}
+
+- (void)updateTrackingAreas {
+ BOOL mouseInView = NO;
+ NSView* controlView = [self controlView];
+ NSWindow* window = [controlView window];
+ NSRect bounds = [controlView bounds];
+ if (window) {
+ NSPoint mousePoint = [window mouseLocationOutsideOfEventStream];
+ mousePoint = [controlView convertPointFromBase:mousePoint];
+ mouseInView = [controlView mouse:mousePoint inRect:bounds];
+ }
+
+ if (trackingArea_.get())
+ [controlView removeTrackingArea:trackingArea_];
+
+ NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited |
+ NSTrackingActiveInActiveApp;
+ if (mouseInView)
+ options |= NSTrackingAssumeInside;
+
+ trackingArea_.reset([[NSTrackingArea alloc]
+ initWithRect:bounds
+ options:options
+ owner:self
+ userInfo:nil]);
+ if (isMouseInside_ != mouseInView) {
+ isMouseInside_ = mouseInView;
+ [controlView setNeedsDisplay:YES];
+ }
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/gradient_button_cell_unittest.mm b/chrome/browser/ui/cocoa/gradient_button_cell_unittest.mm
new file mode 100644
index 0000000..a9d09da
--- /dev/null
+++ b/chrome/browser/ui/cocoa/gradient_button_cell_unittest.mm
@@ -0,0 +1,112 @@
+// Copyright (c) 2009 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 "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/gradient_button_cell.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+@interface GradientButtonCell (HoverValueTesting)
+- (void)performOnePulseStep;
+@end
+
+namespace {
+
+class GradientButtonCellTest : public CocoaTest {
+ public:
+ GradientButtonCellTest() {
+ NSRect frame = NSMakeRect(0, 0, 50, 30);
+ scoped_nsobject<NSButton>view([[NSButton alloc] initWithFrame:frame]);
+ view_ = view.get();
+ scoped_nsobject<GradientButtonCell> cell([[GradientButtonCell alloc]
+ initTextCell:@"Testing"]);
+ [view_ setCell:cell.get()];
+ [[test_window() contentView] addSubview:view_];
+ }
+
+ NSButton* view_;
+};
+
+TEST_VIEW(GradientButtonCellTest, view_)
+
+// Test drawing, mostly to ensure nothing leaks or crashes.
+TEST_F(GradientButtonCellTest, DisplayWithHover) {
+ [[view_ cell] setHoverAlpha:0.0];
+ [view_ display];
+ [[view_ cell] setHoverAlpha:0.5];
+ [view_ display];
+ [[view_ cell] setHoverAlpha:1.0];
+ [view_ display];
+}
+
+// Test hover, mostly to ensure nothing leaks or crashes.
+TEST_F(GradientButtonCellTest, Hover) {
+ GradientButtonCell* cell = [view_ cell];
+ [cell setMouseInside:YES animate:NO];
+ EXPECT_EQ([[view_ cell] hoverAlpha], 1.0);
+
+ [cell setMouseInside:NO animate:YES];
+ CGFloat alpha1 = [cell hoverAlpha];
+ [cell performOnePulseStep];
+ CGFloat alpha2 = [cell hoverAlpha];
+ EXPECT_TRUE(alpha2 < alpha1);
+}
+
+// Tracking rects
+TEST_F(GradientButtonCellTest, TrackingRects) {
+ GradientButtonCell* cell = [view_ cell];
+ EXPECT_FALSE([cell showsBorderOnlyWhileMouseInside]);
+ EXPECT_FALSE([cell isMouseInside]);
+
+ [cell setShowsBorderOnlyWhileMouseInside:YES];
+ [cell mouseEntered:nil];
+ EXPECT_TRUE([cell isMouseInside]);
+ [cell mouseExited:nil];
+ EXPECT_FALSE([cell isMouseInside]);
+
+ [cell setShowsBorderOnlyWhileMouseInside:NO];
+ EXPECT_FALSE([cell isMouseInside]);
+
+ [cell setShowsBorderOnlyWhileMouseInside:YES];
+ [cell setShowsBorderOnlyWhileMouseInside:YES];
+ [cell setShowsBorderOnlyWhileMouseInside:NO];
+ [cell setShowsBorderOnlyWhileMouseInside:NO];
+}
+
+TEST_F(GradientButtonCellTest, ContinuousPulseOnOff) {
+ GradientButtonCell* cell = [view_ cell];
+
+ // On/off
+ EXPECT_FALSE([cell isContinuousPulsing]);
+ [cell setIsContinuousPulsing:YES];
+ EXPECT_TRUE([cell isContinuousPulsing]);
+ EXPECT_TRUE([cell pulsing]);
+ [cell setIsContinuousPulsing:NO];
+ EXPECT_FALSE([cell isContinuousPulsing]);
+
+ // On/safeOff
+ [cell setIsContinuousPulsing:YES];
+ EXPECT_TRUE([cell isContinuousPulsing]);
+ [cell safelyStopPulsing];
+}
+
+// More for valgrind; we don't confirm state change does anything useful.
+TEST_F(GradientButtonCellTest, PulseState) {
+ GradientButtonCell* cell = [view_ cell];
+
+ [cell setMouseInside:YES animate:YES];
+ // Allow for immediate state changes to keep test unflaky
+ EXPECT_TRUE(([cell pulseState] == gradient_button_cell::kPulsingOn) ||
+ ([cell pulseState] == gradient_button_cell::kPulsedOn));
+
+ [cell setMouseInside:NO animate:YES];
+ // Allow for immediate state changes to keep test unflaky
+ EXPECT_TRUE(([cell pulseState] == gradient_button_cell::kPulsingOff) ||
+ ([cell pulseState] == gradient_button_cell::kPulsedOff));
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/history_menu_bridge.h b/chrome/browser/ui/cocoa/history_menu_bridge.h
new file mode 100644
index 0000000..db4a37b
--- /dev/null
+++ b/chrome/browser/ui/cocoa/history_menu_bridge.h
@@ -0,0 +1,232 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_HISTORY_MENU_BRIDGE_H_
+#define CHROME_BROWSER_UI_COCOA_HISTORY_MENU_BRIDGE_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+#include <map>
+
+#include "base/ref_counted.h"
+#include "base/scoped_nsobject.h"
+#include "chrome/browser/cancelable_request.h"
+#import "chrome/browser/favicon_service.h"
+#include "chrome/browser/history/history.h"
+#include "chrome/browser/sessions/session_id.h"
+#include "chrome/browser/sessions/tab_restore_service.h"
+#include "chrome/browser/sessions/tab_restore_service_observer.h"
+#include "chrome/common/notification_observer.h"
+
+class NavigationEntry;
+class NotificationRegistrar;
+class PageUsageData;
+class Profile;
+class TabNavigationEntry;
+class TabRestoreService;
+@class HistoryMenuCocoaController;
+
+namespace {
+
+class HistoryMenuBridgeTest;
+
+}
+
+// C++ bridge for the history menu; one per AppController (means there
+// is only one). This class observes various data sources, namely the
+// HistoryService and the TabRestoreService, and then updates the NSMenu when
+// there is new data.
+//
+// The history menu is broken up into sections: most visisted and recently
+// closed. The overall menu has a tag of IDC_HISTORY_MENU, with the user content
+// items having the local tags defined in the enum below. Items within a section
+// all share the same tag. The structure of the menu is laid out in MainMenu.xib
+// and the generated content is inserted after the Title elements. The recently
+// closed section is special in that those menu items can have submenus to list
+// all the tabs within that closed window. By convention, these submenu items
+// have a tag that's equal to the parent + 1. Tags within the history menu have
+// a range of [400,500) and do not go through CommandDispatch for their target-
+// action mechanism.
+//
+// These menu items do not use firstResponder as their target. Rather, they are
+// hooked directly up to the HistoryMenuCocoaController that then bridges back
+// to this class. These items are created via the AddItemToMenu() helper. Also,
+// unlike the typical ownership model, this bridge owns its controller. The
+// controller is very thin and only exists to interact with Cocoa, but this
+// class does the bulk of the work.
+class HistoryMenuBridge : public NotificationObserver,
+ public TabRestoreServiceObserver {
+ public:
+ // This is a generalization of the data we store in the history menu because
+ // we pull things from different sources with different data types.
+ struct HistoryItem {
+ public:
+ HistoryItem();
+ // Copy constructor allowed.
+ HistoryItem(const HistoryItem& copy);
+ ~HistoryItem();
+
+ // The title for the menu item.
+ string16 title;
+ // The URL that will be navigated to if the user selects this item.
+ GURL url;
+ // Favicon for the URL.
+ scoped_nsobject<NSImage> icon;
+
+ // If the icon is being requested from the FaviconService, |icon_requested|
+ // will be true and |icon_handle| will be non-NULL. If this is false, then
+ // |icon_handle| will be NULL.
+ bool icon_requested;
+ // The Handle given to us by the FaviconService for the icon fetch request.
+ FaviconService::Handle icon_handle;
+
+ // The pointer to the item after it has been created. Strong; NSMenu also
+ // retains this. During a rebuild flood (if the user closes a lot of tabs
+ // quickly), the NSMenu can release the item before the HistoryItem has
+ // been fully deleted. If this were a weak pointer, it would result in a
+ // zombie.
+ scoped_nsobject<NSMenuItem> menu_item;
+
+ // This ID is unique for a browser session and can be passed to the
+ // TabRestoreService to re-open the closed window or tab that this
+ // references. A non-0 session ID indicates that this is an entry can be
+ // restored that way. Otherwise, the URL will be used to open the item and
+ // this ID will be 0.
+ SessionID::id_type session_id;
+
+ // If the HistoryItem is a window, this will be the vector of tabs. Note
+ // that this is a list of weak references. The |menu_item_map_| is the owner
+ // of all items. If it is not a window, then the entry is a single page and
+ // the vector will be empty.
+ std::vector<HistoryItem*> tabs;
+
+ private:
+ // Copying is explicitly allowed, but assignment is not.
+ void operator=(const HistoryItem&);
+ };
+
+ // These tags are not global view tags and are local to the history menu. The
+ // normal procedure for menu items is to go through CommandDispatch, but since
+ // history menu items are hooked directly up to their target, they do not need
+ // to have the global IDC view tags.
+ enum Tags {
+ kMostVisitedSeparator = 400, // Separator before most visited section.
+ kMostVisitedTitle = 401, // Title of the most visited section.
+ kMostVisited = 420, // Used for all entries in the most visited section.
+ kRecentlyClosedSeparator = 440, // Item before recently closed section.
+ kRecentlyClosedTitle = 441, // Title of recently closed section.
+ kRecentlyClosed = 460, // Used for items in the recently closed section.
+ kShowFullSeparator = 480 // Separator after the recently closed section.
+ };
+
+ explicit HistoryMenuBridge(Profile* profile);
+ virtual ~HistoryMenuBridge();
+
+ // Overriden from NotificationObserver.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // For TabRestoreServiceObserver
+ virtual void TabRestoreServiceChanged(TabRestoreService* service);
+ virtual void TabRestoreServiceDestroyed(TabRestoreService* service);
+
+ // Looks up an NSMenuItem in the |menu_item_map_| and returns the
+ // corresponding HistoryItem.
+ HistoryItem* HistoryItemForMenuItem(NSMenuItem* item);
+
+ // I wish I has a "friend @class" construct. These are used by the HMCC
+ // to access model information when responding to actions.
+ HistoryService* service();
+ Profile* profile();
+
+ protected:
+ // Return the History menu.
+ virtual NSMenu* HistoryMenu();
+
+ // Clear items in the given |menu|. Menu items in the same section are given
+ // the same tag. This will go through the entire history menu, removing all
+ // items with a given tag. Note that this will recurse to submenus, removing
+ // child items from the menu item map. This will only remove items that have
+ // a target hooked up to the |controller_|.
+ void ClearMenuSection(NSMenu* menu, NSInteger tag);
+
+ // Adds a given title and URL to the passed-in menu with a certain tag and
+ // index. This will add |item| and the newly created menu item to the
+ // |menu_item_map_|, which takes ownership. Items are deleted in
+ // ClearMenuSection(). This returns the new menu item that was just added.
+ NSMenuItem* AddItemToMenu(HistoryItem* item,
+ NSMenu* menu,
+ NSInteger tag,
+ NSInteger index);
+
+ // Called by the ctor if |service_| is ready at the time, or by a
+ // notification receiver. Finishes initialization tasks by subscribing for
+ // change notifications and calling CreateMenu().
+ void Init();
+
+ // Does the query for the history information to create the menu.
+ void CreateMenu();
+
+ // Callback method for when HistoryService query results are ready with the
+ // most recently-visited sites.
+ void OnVisitedHistoryResults(CancelableRequestProvider::Handle handle,
+ std::vector<PageUsageData*>* results);
+
+ // Creates a HistoryItem* for the given tab entry. Caller takes ownership of
+ // the result and must delete it when finished.
+ HistoryItem* HistoryItemForTab(const TabRestoreService::Tab& entry);
+
+ // Helper function that sends an async request to the FaviconService to get
+ // an icon. The callback will update the NSMenuItem directly.
+ void GetFaviconForHistoryItem(HistoryItem* item);
+
+ // Callback for the FaviconService to return favicon image data when we
+ // request it. This decodes the raw data, updates the HistoryItem, and then
+ // sets the image on the menu. Called on the same same thread that
+ // GetFaviconForHistoryItem() was called on (UI thread).
+ void GotFaviconData(FaviconService::Handle handle,
+ bool know_favicon,
+ scoped_refptr<RefCountedMemory> data,
+ bool expired,
+ GURL url);
+
+ // Cancels a favicon load request for a given HistoryItem, if one is in
+ // progress.
+ void CancelFaviconRequest(HistoryItem* item);
+
+ private:
+ friend class ::HistoryMenuBridgeTest;
+ friend class HistoryMenuCocoaControllerTest;
+
+ scoped_nsobject<HistoryMenuCocoaController> controller_; // strong
+
+ Profile* profile_; // weak
+ HistoryService* history_service_; // weak
+ TabRestoreService* tab_restore_service_; // weak
+
+ NotificationRegistrar registrar_;
+ CancelableRequestConsumer cancelable_request_consumer_;
+
+ // Mapping of NSMenuItems to HistoryItems. This owns the HistoryItems until
+ // they are removed and deleted via ClearMenuSection().
+ std::map<NSMenuItem*, HistoryItem*> menu_item_map_;
+
+ // Maps HistoryItems to favicon request Handles.
+ CancelableRequestConsumerTSimple<HistoryItem*> favicon_consumer_;
+
+ // Requests to re-create the menu are coalesced. |create_in_progress_| is true
+ // when either waiting for the history service to return query results, or
+ // when the menu is rebuilding. |need_recreate_| is true whenever a rebuild
+ // has been scheduled but is waiting for the current one to finish.
+ bool create_in_progress_;
+ bool need_recreate_;
+
+ // The default favicon if a HistoryItem does not have one.
+ scoped_nsobject<NSImage> default_favicon_;
+
+ DISALLOW_COPY_AND_ASSIGN(HistoryMenuBridge);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_HISTORY_MENU_BRIDGE_H_
diff --git a/chrome/browser/ui/cocoa/history_menu_bridge.mm b/chrome/browser/ui/cocoa/history_menu_bridge.mm
new file mode 100644
index 0000000..8e34024
--- /dev/null
+++ b/chrome/browser/ui/cocoa/history_menu_bridge.mm
@@ -0,0 +1,469 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/history_menu_bridge.h"
+
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/callback.h"
+#include "base/stl_util-inl.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h" // IDC_HISTORY_MENU
+#import "chrome/browser/app_controller_mac.h"
+#include "chrome/browser/history/page_usage_data.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sessions/session_types.h"
+#import "chrome/browser/ui/cocoa/history_menu_cocoa_controller.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/url_constants.h"
+#include "gfx/codec/png_codec.h"
+#include "grit/app_resources.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "skia/ext/skia_utils_mac.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace {
+
+// Menus more than this many chars long will get trimmed.
+const NSUInteger kMaximumMenuWidthInChars = 50;
+
+// When trimming, use this many chars from each side.
+const NSUInteger kMenuTrimSizeInChars = 25;
+
+// Number of days to consider when getting the number of most visited items.
+const int kMostVisitedScope = 90;
+
+// The number of most visisted results to get.
+const int kMostVisitedCount = 9;
+
+// The number of recently closed items to get.
+const unsigned int kRecentlyClosedCount = 10;
+
+} // namespace
+
+HistoryMenuBridge::HistoryItem::HistoryItem()
+ : icon_requested(false),
+ menu_item(nil),
+ session_id(0) {
+}
+
+HistoryMenuBridge::HistoryItem::HistoryItem(const HistoryItem& copy)
+ : title(copy.title),
+ url(copy.url),
+ icon_requested(false),
+ menu_item(nil),
+ session_id(copy.session_id) {
+}
+
+HistoryMenuBridge::HistoryItem::~HistoryItem() {
+}
+
+HistoryMenuBridge::HistoryMenuBridge(Profile* profile)
+ : controller_([[HistoryMenuCocoaController alloc] initWithBridge:this]),
+ profile_(profile),
+ history_service_(NULL),
+ tab_restore_service_(NULL),
+ create_in_progress_(false),
+ need_recreate_(false) {
+ // If we don't have a profile, do not bother initializing our data sources.
+ // This shouldn't happen except in unit tests.
+ if (profile_) {
+ // Check to see if the history service is ready. Because it loads async, it
+ // may not be ready when the Bridge is created. If this happens, register
+ // for a notification that tells us the HistoryService is ready.
+ HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ if (hs != NULL && hs->BackendLoaded()) {
+ history_service_ = hs;
+ Init();
+ }
+
+ tab_restore_service_ = profile_->GetTabRestoreService();
+ if (tab_restore_service_) {
+ tab_restore_service_->AddObserver(this);
+ tab_restore_service_->LoadTabsFromLastSession();
+ }
+ }
+
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ default_favicon_.reset([rb.GetNativeImageNamed(IDR_DEFAULT_FAVICON) retain]);
+
+ // Set the static icons in the menu.
+ NSMenuItem* item = [HistoryMenu() itemWithTag:IDC_SHOW_HISTORY];
+ [item setImage:rb.GetNativeImageNamed(IDR_HISTORY_FAVICON)];
+
+ // The service is not ready for use yet, so become notified when it does.
+ if (!history_service_) {
+ registrar_.Add(this,
+ NotificationType::HISTORY_LOADED,
+ NotificationService::AllSources());
+ }
+}
+
+// Note that all requests sent to either the history service or the favicon
+// service will be automatically cancelled by their respective Consumers, so
+// task cancellation is not done manually here in the dtor.
+HistoryMenuBridge::~HistoryMenuBridge() {
+ // Unregister ourselves as observers and notifications.
+ const NotificationSource& src = NotificationService::AllSources();
+ if (history_service_) {
+ registrar_.Remove(this, NotificationType::HISTORY_TYPED_URLS_MODIFIED, src);
+ registrar_.Remove(this, NotificationType::HISTORY_URL_VISITED, src);
+ registrar_.Remove(this, NotificationType::HISTORY_URLS_DELETED, src);
+ } else {
+ registrar_.Remove(this, NotificationType::HISTORY_LOADED, src);
+ }
+
+ if (tab_restore_service_)
+ tab_restore_service_->RemoveObserver(this);
+
+ // Since the map owns the HistoryItems, delete anything that still exists.
+ std::map<NSMenuItem*, HistoryItem*>::iterator it = menu_item_map_.begin();
+ while (it != menu_item_map_.end()) {
+ HistoryItem* item = it->second;
+ menu_item_map_.erase(it++);
+ delete item;
+ }
+}
+
+void HistoryMenuBridge::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ // A history service is now ready. Check to see if it's the one for the main
+ // profile. If so, perform final initialization.
+ if (type == NotificationType::HISTORY_LOADED) {
+ HistoryService* hs =
+ profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ if (hs != NULL && hs->BackendLoaded()) {
+ history_service_ = hs;
+ Init();
+
+ // Found our HistoryService, so stop listening for this notification.
+ registrar_.Remove(this,
+ NotificationType::HISTORY_LOADED,
+ NotificationService::AllSources());
+ }
+ }
+
+ // All other notification types that we observe indicate that the history has
+ // changed and we need to rebuild.
+ need_recreate_ = true;
+ CreateMenu();
+}
+
+void HistoryMenuBridge::TabRestoreServiceChanged(TabRestoreService* service) {
+ const TabRestoreService::Entries& entries = service->entries();
+
+ // Clear the history menu before rebuilding.
+ NSMenu* menu = HistoryMenu();
+ ClearMenuSection(menu, kRecentlyClosed);
+
+ // Index for the next menu item.
+ NSInteger index = [menu indexOfItemWithTag:kRecentlyClosedTitle] + 1;
+ NSUInteger added_count = 0;
+
+ for (TabRestoreService::Entries::const_iterator it = entries.begin();
+ it != entries.end() && added_count < kRecentlyClosedCount; ++it) {
+ TabRestoreService::Entry* entry = *it;
+
+ // If this is a window, create a submenu for all of its tabs.
+ if (entry->type == TabRestoreService::WINDOW) {
+ TabRestoreService::Window* entry_win = (TabRestoreService::Window*)entry;
+ std::vector<TabRestoreService::Tab>& tabs = entry_win->tabs;
+ if (!tabs.size())
+ continue;
+
+ // Create the item for the parent/window. Do not set the title yet because
+ // the actual number of items that are in the menu will not be known until
+ // things like the NTP are filtered out, which is done when the tab items
+ // are actually created.
+ HistoryItem* item = new HistoryItem();
+ item->session_id = entry_win->id;
+
+ // Create the submenu.
+ scoped_nsobject<NSMenu> submenu([[NSMenu alloc] init]);
+
+ // Create standard items within the window submenu.
+ NSString* restore_title = l10n_util::GetNSString(
+ IDS_HISTORY_CLOSED_RESTORE_WINDOW_MAC);
+ scoped_nsobject<NSMenuItem> restore_item(
+ [[NSMenuItem alloc] initWithTitle:restore_title
+ action:@selector(openHistoryMenuItem:)
+ keyEquivalent:@""]);
+ [restore_item setTarget:controller_.get()];
+ // Duplicate the HistoryItem otherwise the different NSMenuItems will
+ // point to the same HistoryItem, which would then be double-freed when
+ // removing the items from the map or in the dtor.
+ HistoryItem* dup_item = new HistoryItem(*item);
+ menu_item_map_.insert(std::make_pair(restore_item.get(), dup_item));
+ [submenu addItem:restore_item.get()];
+ [submenu addItem:[NSMenuItem separatorItem]];
+
+ // Loop over the window's tabs and add them to the submenu.
+ NSInteger subindex = [[submenu itemArray] count];
+ std::vector<TabRestoreService::Tab>::const_iterator it;
+ for (it = tabs.begin(); it != tabs.end(); ++it) {
+ TabRestoreService::Tab tab = *it;
+ HistoryItem* tab_item = HistoryItemForTab(tab);
+ if (tab_item) {
+ item->tabs.push_back(tab_item);
+ AddItemToMenu(tab_item, submenu.get(), kRecentlyClosed + 1,
+ subindex++);
+ }
+ }
+
+ // Now that the number of tabs that has been added is known, set the title
+ // of the parent menu item.
+ if (item->tabs.size() == 1) {
+ item->title = l10n_util::GetStringUTF16(
+ IDS_NEW_TAB_RECENTLY_CLOSED_WINDOW_SINGLE);
+ } else {
+ item->title =l10n_util::GetStringFUTF16(
+ IDS_NEW_TAB_RECENTLY_CLOSED_WINDOW_MULTIPLE,
+ base::IntToString16(item->tabs.size()));
+ }
+
+ // Sometimes it is possible for there to not be any subitems for a given
+ // window; if that is the case, do not add the entry to the main menu.
+ if ([[submenu itemArray] count] > 2) {
+ // Create the menu item parent.
+ NSMenuItem* parent_item =
+ AddItemToMenu(item, menu, kRecentlyClosed, index++);
+ [parent_item setSubmenu:submenu.get()];
+ ++added_count;
+ }
+ } else if (entry->type == TabRestoreService::TAB) {
+ TabRestoreService::Tab* tab =
+ static_cast<TabRestoreService::Tab*>(entry);
+ HistoryItem* item = HistoryItemForTab(*tab);
+ if (item) {
+ AddItemToMenu(item, menu, kRecentlyClosed, index++);
+ ++added_count;
+ }
+ }
+ }
+}
+
+void HistoryMenuBridge::TabRestoreServiceDestroyed(
+ TabRestoreService* service) {
+ // Intentionally left blank. We hold a weak reference to the service.
+}
+
+HistoryMenuBridge::HistoryItem* HistoryMenuBridge::HistoryItemForMenuItem(
+ NSMenuItem* item) {
+ std::map<NSMenuItem*, HistoryItem*>::iterator it = menu_item_map_.find(item);
+ if (it != menu_item_map_.end()) {
+ return it->second;
+ }
+ return NULL;
+}
+
+HistoryService* HistoryMenuBridge::service() {
+ return history_service_;
+}
+
+Profile* HistoryMenuBridge::profile() {
+ return profile_;
+}
+
+NSMenu* HistoryMenuBridge::HistoryMenu() {
+ NSMenu* history_menu = [[[NSApp mainMenu] itemWithTag:IDC_HISTORY_MENU]
+ submenu];
+ return history_menu;
+}
+
+void HistoryMenuBridge::ClearMenuSection(NSMenu* menu, NSInteger tag) {
+ for (NSMenuItem* menu_item in [menu itemArray]) {
+ if ([menu_item tag] == tag && [menu_item target] == controller_.get()) {
+ // This is an item that should be removed, so find the corresponding model
+ // item.
+ HistoryItem* item = HistoryItemForMenuItem(menu_item);
+
+ // Cancel favicon requests that could hold onto stale pointers. Also
+ // remove the item from the mapping.
+ if (item) {
+ CancelFaviconRequest(item);
+ menu_item_map_.erase(menu_item);
+ delete item;
+ }
+
+ // If this menu item has a submenu, recurse.
+ if ([menu_item hasSubmenu]) {
+ ClearMenuSection([menu_item submenu], tag + 1);
+ }
+
+ // Now actually remove the item from the menu.
+ [menu removeItem:menu_item];
+ }
+ }
+}
+
+NSMenuItem* HistoryMenuBridge::AddItemToMenu(HistoryItem* item,
+ NSMenu* menu,
+ NSInteger tag,
+ NSInteger index) {
+ NSString* title = base::SysUTF16ToNSString(item->title);
+ std::string url_string = item->url.possibly_invalid_spec();
+
+ // If we don't have a title, use the URL.
+ if ([title isEqualToString:@""])
+ title = base::SysUTF8ToNSString(url_string);
+ NSString* full_title = title;
+ if ([title length] > kMaximumMenuWidthInChars) {
+ // TODO(rsesek): use app/text_elider.h once it uses string16 and can
+ // take out the middle of strings.
+ title = [NSString stringWithFormat:@"%@…%@",
+ [title substringToIndex:kMenuTrimSizeInChars],
+ [title substringFromIndex:([title length] -
+ kMenuTrimSizeInChars)]];
+ }
+ item->menu_item.reset(
+ [[NSMenuItem alloc] initWithTitle:title
+ action:nil
+ keyEquivalent:@""]);
+ [item->menu_item setTarget:controller_];
+ [item->menu_item setAction:@selector(openHistoryMenuItem:)];
+ [item->menu_item setTag:tag];
+ if (item->icon.get())
+ [item->menu_item setImage:item->icon.get()];
+ else if (!item->tabs.size())
+ [item->menu_item setImage:default_favicon_.get()];
+
+ // Add a tooltip.
+ NSString* tooltip = [NSString stringWithFormat:@"%@\n%s", full_title,
+ url_string.c_str()];
+ [item->menu_item setToolTip:tooltip];
+
+ [menu insertItem:item->menu_item.get() atIndex:index];
+ menu_item_map_.insert(std::make_pair(item->menu_item.get(), item));
+
+ return item->menu_item.get();
+}
+
+void HistoryMenuBridge::Init() {
+ const NotificationSource& source = NotificationService::AllSources();
+ registrar_.Add(this, NotificationType::HISTORY_TYPED_URLS_MODIFIED, source);
+ registrar_.Add(this, NotificationType::HISTORY_URL_VISITED, source);
+ registrar_.Add(this, NotificationType::HISTORY_URLS_DELETED, source);
+}
+
+void HistoryMenuBridge::CreateMenu() {
+ // If we're currently running CreateMenu(), wait until it finishes.
+ if (create_in_progress_)
+ return;
+ create_in_progress_ = true;
+ need_recreate_ = false;
+
+ history_service_->QuerySegmentUsageSince(
+ &cancelable_request_consumer_,
+ base::Time::Now() - base::TimeDelta::FromDays(kMostVisitedScope),
+ kMostVisitedCount,
+ NewCallback(this, &HistoryMenuBridge::OnVisitedHistoryResults));
+}
+
+void HistoryMenuBridge::OnVisitedHistoryResults(
+ CancelableRequestProvider::Handle handle,
+ std::vector<PageUsageData*>* results) {
+ NSMenu* menu = HistoryMenu();
+ ClearMenuSection(menu, kMostVisited);
+ NSInteger top_item = [menu indexOfItemWithTag:kMostVisitedTitle] + 1;
+
+ size_t count = results->size();
+ for (size_t i = 0; i < count; ++i) {
+ PageUsageData* history_item = (*results)[i];
+
+ HistoryItem* item = new HistoryItem();
+ item->title = history_item->GetTitle();
+ item->url = history_item->GetURL();
+ if (history_item->HasFavIcon()) {
+ const SkBitmap* icon = history_item->GetFavIcon();
+ item->icon.reset([gfx::SkBitmapToNSImage(*icon) retain]);
+ } else {
+ GetFaviconForHistoryItem(item);
+ }
+ // This will add |item| to the |menu_item_map_|, which takes ownership.
+ AddItemToMenu(item, HistoryMenu(), kMostVisited, top_item + i);
+ }
+
+ // We are already invalid by the time we finished, darn.
+ if (need_recreate_)
+ CreateMenu();
+
+ create_in_progress_ = false;
+}
+
+HistoryMenuBridge::HistoryItem* HistoryMenuBridge::HistoryItemForTab(
+ const TabRestoreService::Tab& entry) {
+ if (entry.navigations.empty())
+ return NULL;
+
+ const TabNavigation& current_navigation =
+ entry.navigations.at(entry.current_navigation_index);
+ if (current_navigation.virtual_url() == GURL(chrome::kChromeUINewTabURL))
+ return NULL;
+
+ HistoryItem* item = new HistoryItem();
+ item->title = current_navigation.title();
+ item->url = current_navigation.virtual_url();
+ item->session_id = entry.id;
+
+ // Tab navigations don't come with icons, so we always have to request them.
+ GetFaviconForHistoryItem(item);
+
+ return item;
+}
+
+void HistoryMenuBridge::GetFaviconForHistoryItem(HistoryItem* item) {
+ FaviconService* service =
+ profile_->GetFaviconService(Profile::EXPLICIT_ACCESS);
+ FaviconService::Handle handle = service->GetFaviconForURL(item->url,
+ &favicon_consumer_,
+ NewCallback(this, &HistoryMenuBridge::GotFaviconData));
+ favicon_consumer_.SetClientData(service, handle, item);
+ item->icon_handle = handle;
+ item->icon_requested = true;
+}
+
+void HistoryMenuBridge::GotFaviconData(FaviconService::Handle handle,
+ bool know_favicon,
+ scoped_refptr<RefCountedMemory> data,
+ bool expired,
+ GURL url) {
+ // Since we're going to do Cocoa-y things, make sure this is the main thread.
+ DCHECK([NSThread isMainThread]);
+
+ HistoryItem* item =
+ favicon_consumer_.GetClientData(
+ profile_->GetFaviconService(Profile::EXPLICIT_ACCESS), handle);
+ DCHECK(item);
+ item->icon_requested = false;
+ item->icon_handle = NULL;
+
+ // Convert the raw data to Skia and then to a NSImage.
+ // TODO(rsesek): Is there an easier way to do this?
+ SkBitmap icon;
+ if (know_favicon && data.get() && data->size() &&
+ gfx::PNGCodec::Decode(data->front(), data->size(), &icon)) {
+ NSImage* image = gfx::SkBitmapToNSImage(icon);
+ if (image) {
+ // The conversion was successful.
+ item->icon.reset([image retain]);
+ [item->menu_item setImage:item->icon.get()];
+ }
+ }
+}
+
+void HistoryMenuBridge::CancelFaviconRequest(HistoryItem* item) {
+ DCHECK(item);
+ if (item->icon_requested) {
+ FaviconService* service =
+ profile_->GetFaviconService(Profile::EXPLICIT_ACCESS);
+ service->CancelRequest(item->icon_handle);
+ item->icon_requested = false;
+ item->icon_handle = NULL;
+ }
+}
diff --git a/chrome/browser/ui/cocoa/history_menu_bridge_unittest.mm b/chrome/browser/ui/cocoa/history_menu_bridge_unittest.mm
new file mode 100644
index 0000000..843e964
--- /dev/null
+++ b/chrome/browser/ui/cocoa/history_menu_bridge_unittest.mm
@@ -0,0 +1,386 @@
+// 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 <vector>
+
+#include "base/ref_counted_memory.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/cancelable_request.h"
+#include "chrome/browser/sessions/tab_restore_service.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/history_menu_bridge.h"
+#include "gfx/codec/png_codec.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+
+namespace {
+
+class MockTRS : public TabRestoreService {
+ public:
+ MockTRS(Profile* profile) : TabRestoreService(profile, NULL) {}
+ MOCK_CONST_METHOD0(entries, const TabRestoreService::Entries&());
+};
+
+class MockBridge : public HistoryMenuBridge {
+ public:
+ MockBridge(Profile* profile)
+ : HistoryMenuBridge(profile),
+ menu_([[NSMenu alloc] initWithTitle:@"History"]) {}
+
+ virtual NSMenu* HistoryMenu() {
+ return menu_.get();
+ }
+
+ private:
+ scoped_nsobject<NSMenu> menu_;
+};
+
+class HistoryMenuBridgeTest : public CocoaTest {
+ public:
+
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ browser_test_helper_.profile()->CreateFaviconService();
+ bridge_.reset(new MockBridge(browser_test_helper_.profile()));
+ }
+
+ // We are a friend of HistoryMenuBridge (and have access to
+ // protected methods), but none of the classes generated by TEST_F()
+ // are. Wraps common commands.
+ void ClearMenuSection(NSMenu* menu,
+ NSInteger tag) {
+ bridge_->ClearMenuSection(menu, tag);
+ }
+
+ void AddItemToBridgeMenu(HistoryMenuBridge::HistoryItem* item,
+ NSMenu* menu,
+ NSInteger tag,
+ NSInteger index) {
+ bridge_->AddItemToMenu(item, menu, tag, index);
+ }
+
+ NSMenuItem* AddItemToMenu(NSMenu* menu,
+ NSString* title,
+ SEL selector,
+ int tag) {
+ NSMenuItem* item = [[[NSMenuItem alloc] initWithTitle:title action:NULL
+ keyEquivalent:@""] autorelease];
+ [item setTag:tag];
+ if (selector) {
+ [item setAction:selector];
+ [item setTarget:bridge_->controller_.get()];
+ }
+ [menu addItem:item];
+ return item;
+ }
+
+ HistoryMenuBridge::HistoryItem* CreateItem(const string16& title) {
+ HistoryMenuBridge::HistoryItem* item =
+ new HistoryMenuBridge::HistoryItem();
+ item->title = title;
+ item->url = GURL(title);
+ return item;
+ }
+
+ MockTRS::Tab CreateSessionTab(const GURL& url, const string16& title) {
+ MockTRS::Tab tab;
+ tab.current_navigation_index = 0;
+ tab.navigations.push_back(
+ TabNavigation(0, url, GURL(), title, std::string(),
+ PageTransition::LINK));
+ return tab;
+ }
+
+ void GetFaviconForHistoryItem(HistoryMenuBridge::HistoryItem* item) {
+ bridge_->GetFaviconForHistoryItem(item);
+ }
+
+ void GotFaviconData(FaviconService::Handle handle,
+ bool know_favicon,
+ scoped_refptr<RefCountedBytes> data,
+ bool expired,
+ GURL url) {
+ bridge_->GotFaviconData(handle, know_favicon, data, expired, url);
+ }
+
+ CancelableRequestConsumerTSimple<HistoryMenuBridge::HistoryItem*>&
+ favicon_consumer() {
+ return bridge_->favicon_consumer_;
+ }
+
+ BrowserTestHelper browser_test_helper_;
+ scoped_ptr<MockBridge> bridge_;
+};
+
+// Edge case test for clearing until the end of a menu.
+TEST_F(HistoryMenuBridgeTest, ClearHistoryMenuUntilEnd) {
+ NSMenu* menu = [[[NSMenu alloc] initWithTitle:@"history foo"] autorelease];
+ AddItemToMenu(menu, @"HEADER", NULL, HistoryMenuBridge::kMostVisitedTitle);
+
+ NSInteger tag = HistoryMenuBridge::kMostVisited;
+ AddItemToMenu(menu, @"alpha", @selector(openHistoryMenuItem:), tag);
+ AddItemToMenu(menu, @"bravo", @selector(openHistoryMenuItem:), tag);
+ AddItemToMenu(menu, @"charlie", @selector(openHistoryMenuItem:), tag);
+ AddItemToMenu(menu, @"delta", @selector(openHistoryMenuItem:), tag);
+
+ ClearMenuSection(menu, HistoryMenuBridge::kMostVisited);
+
+ EXPECT_EQ(1, [menu numberOfItems]);
+ EXPECT_NSEQ(@"HEADER",
+ [[menu itemWithTag:HistoryMenuBridge::kMostVisitedTitle] title]);
+}
+
+// Skip menu items that are not hooked up to |-openHistoryMenuItem:|.
+TEST_F(HistoryMenuBridgeTest, ClearHistoryMenuSkipping) {
+ NSMenu* menu = [[[NSMenu alloc] initWithTitle:@"history foo"] autorelease];
+ AddItemToMenu(menu, @"HEADER", NULL, HistoryMenuBridge::kMostVisitedTitle);
+
+ NSInteger tag = HistoryMenuBridge::kMostVisited;
+ AddItemToMenu(menu, @"alpha", @selector(openHistoryMenuItem:), tag);
+ AddItemToMenu(menu, @"bravo", @selector(openHistoryMenuItem:), tag);
+ AddItemToMenu(menu, @"TITLE", NULL, HistoryMenuBridge::kRecentlyClosedTitle);
+ AddItemToMenu(menu, @"charlie", @selector(openHistoryMenuItem:), tag);
+
+ ClearMenuSection(menu, tag);
+
+ EXPECT_EQ(2, [menu numberOfItems]);
+ EXPECT_NSEQ(@"HEADER",
+ [[menu itemWithTag:HistoryMenuBridge::kMostVisitedTitle] title]);
+ EXPECT_NSEQ(@"TITLE",
+ [[menu itemAtIndex:1] title]);
+}
+
+// Edge case test for clearing an empty menu.
+TEST_F(HistoryMenuBridgeTest, ClearHistoryMenuEmpty) {
+ NSMenu* menu = [[[NSMenu alloc] initWithTitle:@"history foo"] autorelease];
+ AddItemToMenu(menu, @"HEADER", NULL, HistoryMenuBridge::kMostVisited);
+
+ ClearMenuSection(menu, HistoryMenuBridge::kMostVisited);
+
+ EXPECT_EQ(1, [menu numberOfItems]);
+ EXPECT_NSEQ(@"HEADER",
+ [[menu itemWithTag:HistoryMenuBridge::kMostVisited] title]);
+}
+
+// Test that AddItemToMenu() properly adds HistoryItem objects as menus.
+TEST_F(HistoryMenuBridgeTest, AddItemToMenu) {
+ NSMenu* menu = [[[NSMenu alloc] initWithTitle:@"history foo"] autorelease];
+
+ const string16 short_url = ASCIIToUTF16("http://foo/");
+ const string16 long_url = ASCIIToUTF16("http://super-duper-long-url--."
+ "that.cannot.possibly.fit.even-in-80-columns"
+ "or.be.reasonably-displayed-in-a-menu"
+ "without.looking-ridiculous.com/"); // 140 chars total
+
+ // HistoryItems are owned by the HistoryMenuBridge when AddItemToBridgeMenu()
+ // is called, which places them into the |menu_item_map_|, which owns them.
+ HistoryMenuBridge::HistoryItem* item1 = CreateItem(short_url);
+ AddItemToBridgeMenu(item1, menu, 100, 0);
+
+ HistoryMenuBridge::HistoryItem* item2 = CreateItem(long_url);
+ AddItemToBridgeMenu(item2, menu, 101, 1);
+
+ EXPECT_EQ(2, [menu numberOfItems]);
+
+ EXPECT_EQ(@selector(openHistoryMenuItem:), [[menu itemAtIndex:0] action]);
+ EXPECT_EQ(@selector(openHistoryMenuItem:), [[menu itemAtIndex:1] action]);
+
+ EXPECT_EQ(100, [[menu itemAtIndex:0] tag]);
+ EXPECT_EQ(101, [[menu itemAtIndex:1] tag]);
+
+ // Make sure a short title looks fine
+ NSString* s = [[menu itemAtIndex:0] title];
+ EXPECT_EQ(base::SysNSStringToUTF16(s), short_url);
+
+ // Make sure a super-long title gets trimmed
+ s = [[menu itemAtIndex:0] title];
+ EXPECT_TRUE([s length] < long_url.length());
+
+ // Confirm tooltips and confirm they are not trimmed (like the item
+ // name might be). Add tolerance for URL fixer-upping;
+ // e.g. http://foo becomes http://foo/)
+ EXPECT_GE([[[menu itemAtIndex:0] toolTip] length], (2*short_url.length()-5));
+ EXPECT_GE([[[menu itemAtIndex:1] toolTip] length], (2*long_url.length()-5));
+}
+
+// Test that the menu is created for a set of simple tabs.
+TEST_F(HistoryMenuBridgeTest, RecentlyClosedTabs) {
+ scoped_refptr<MockTRS> trs(new MockTRS(browser_test_helper_.profile()));
+ MockTRS::Entries entries;
+
+ MockTRS::Tab tab1 = CreateSessionTab(GURL("http://google.com"),
+ ASCIIToUTF16("Google"));
+ tab1.id = 24;
+ entries.push_back(&tab1);
+
+ MockTRS::Tab tab2 = CreateSessionTab(GURL("http://apple.com"),
+ ASCIIToUTF16("Apple"));
+ tab2.id = 42;
+ entries.push_back(&tab2);
+
+ using ::testing::ReturnRef;
+ EXPECT_CALL(*trs.get(), entries()).WillOnce(ReturnRef(entries));
+
+ bridge_->TabRestoreServiceChanged(trs.get());
+
+ NSMenu* menu = bridge_->HistoryMenu();
+ ASSERT_EQ(2U, [[menu itemArray] count]);
+
+ NSMenuItem* item1 = [menu itemAtIndex:0];
+ MockBridge::HistoryItem* hist1 = bridge_->HistoryItemForMenuItem(item1);
+ EXPECT_TRUE(hist1);
+ EXPECT_EQ(24, hist1->session_id);
+ EXPECT_NSEQ(@"Google", [item1 title]);
+
+ NSMenuItem* item2 = [menu itemAtIndex:1];
+ MockBridge::HistoryItem* hist2 = bridge_->HistoryItemForMenuItem(item2);
+ EXPECT_TRUE(hist2);
+ EXPECT_EQ(42, hist2->session_id);
+ EXPECT_NSEQ(@"Apple", [item2 title]);
+}
+
+// Test that the menu is created for a mix of windows and tabs.
+TEST_F(HistoryMenuBridgeTest, RecentlyClosedTabsAndWindows) {
+ scoped_refptr<MockTRS> trs(new MockTRS(browser_test_helper_.profile()));
+ MockTRS::Entries entries;
+
+ MockTRS::Tab tab1 = CreateSessionTab(GURL("http://google.com"),
+ ASCIIToUTF16("Google"));
+ tab1.id = 24;
+ entries.push_back(&tab1);
+
+ MockTRS::Window win1;
+ win1.id = 30;
+ win1.tabs.push_back(
+ CreateSessionTab(GURL("http://foo.com"), ASCIIToUTF16("foo")));
+ win1.tabs[0].id = 31;
+ win1.tabs.push_back(
+ CreateSessionTab(GURL("http://bar.com"), ASCIIToUTF16("bar")));
+ win1.tabs[1].id = 32;
+ entries.push_back(&win1);
+
+ MockTRS::Tab tab2 = CreateSessionTab(GURL("http://apple.com"),
+ ASCIIToUTF16("Apple"));
+ tab2.id = 42;
+ entries.push_back(&tab2);
+
+ MockTRS::Window win2;
+ win2.id = 50;
+ win2.tabs.push_back(
+ CreateSessionTab(GURL("http://magic.com"), ASCIIToUTF16("magic")));
+ win2.tabs[0].id = 51;
+ win2.tabs.push_back(
+ CreateSessionTab(GURL("http://goats.com"), ASCIIToUTF16("goats")));
+ win2.tabs[1].id = 52;
+ win2.tabs.push_back(
+ CreateSessionTab(GURL("http://teleporter.com"),
+ ASCIIToUTF16("teleporter")));
+ win2.tabs[1].id = 53;
+ entries.push_back(&win2);
+
+ using ::testing::ReturnRef;
+ EXPECT_CALL(*trs.get(), entries()).WillOnce(ReturnRef(entries));
+
+ bridge_->TabRestoreServiceChanged(trs.get());
+
+ NSMenu* menu = bridge_->HistoryMenu();
+ ASSERT_EQ(4U, [[menu itemArray] count]);
+
+ NSMenuItem* item1 = [menu itemAtIndex:0];
+ MockBridge::HistoryItem* hist1 = bridge_->HistoryItemForMenuItem(item1);
+ EXPECT_TRUE(hist1);
+ EXPECT_EQ(24, hist1->session_id);
+ EXPECT_NSEQ(@"Google", [item1 title]);
+
+ NSMenuItem* item2 = [menu itemAtIndex:1];
+ MockBridge::HistoryItem* hist2 = bridge_->HistoryItemForMenuItem(item2);
+ EXPECT_TRUE(hist2);
+ EXPECT_EQ(30, hist2->session_id);
+ EXPECT_EQ(2U, hist2->tabs.size());
+ // Do not test menu item title because it is localized.
+ NSMenu* submenu1 = [item2 submenu];
+ EXPECT_EQ(4U, [[submenu1 itemArray] count]);
+ // Do not test Restore All Tabs because it is localiced.
+ EXPECT_TRUE([[submenu1 itemAtIndex:1] isSeparatorItem]);
+ EXPECT_NSEQ(@"foo", [[submenu1 itemAtIndex:2] title]);
+ EXPECT_NSEQ(@"bar", [[submenu1 itemAtIndex:3] title]);
+
+ NSMenuItem* item3 = [menu itemAtIndex:2];
+ MockBridge::HistoryItem* hist3 = bridge_->HistoryItemForMenuItem(item3);
+ EXPECT_TRUE(hist3);
+ EXPECT_EQ(42, hist3->session_id);
+ EXPECT_NSEQ(@"Apple", [item3 title]);
+
+ NSMenuItem* item4 = [menu itemAtIndex:3];
+ MockBridge::HistoryItem* hist4 = bridge_->HistoryItemForMenuItem(item4);
+ EXPECT_TRUE(hist4);
+ EXPECT_EQ(50, hist4->session_id);
+ EXPECT_EQ(3U, hist4->tabs.size());
+ // Do not test menu item title because it is localized.
+ NSMenu* submenu2 = [item4 submenu];
+ EXPECT_EQ(5U, [[submenu2 itemArray] count]);
+ // Do not test Restore All Tabs because it is localiced.
+ EXPECT_TRUE([[submenu2 itemAtIndex:1] isSeparatorItem]);
+ EXPECT_NSEQ(@"magic", [[submenu2 itemAtIndex:2] title]);
+ EXPECT_NSEQ(@"goats", [[submenu2 itemAtIndex:3] title]);
+ EXPECT_NSEQ(@"teleporter", [[submenu2 itemAtIndex:4] title]);
+}
+
+// Tests that we properly request an icon from the FaviconService.
+TEST_F(HistoryMenuBridgeTest, GetFaviconForHistoryItem) {
+ // Create a fake item.
+ HistoryMenuBridge::HistoryItem item;
+ item.title = ASCIIToUTF16("Title");
+ item.url = GURL("http://google.com");
+
+ // Request the icon.
+ GetFaviconForHistoryItem(&item);
+
+ // Make sure that there is ClientData for the request.
+ std::vector<HistoryMenuBridge::HistoryItem*> data;
+ favicon_consumer().GetAllClientData(&data);
+ ASSERT_EQ(data.size(), 1U);
+ EXPECT_EQ(&item, data[0]);
+
+ // Make sure the item was modified properly.
+ EXPECT_TRUE(item.icon_requested);
+ EXPECT_GT(item.icon_handle, 0);
+}
+
+TEST_F(HistoryMenuBridgeTest, GotFaviconData) {
+ // Create a dummy bitmap.
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, 25, 25);
+ bitmap.allocPixels();
+ bitmap.eraseRGB(255, 0, 0);
+
+ // Convert it to raw PNG bytes. We totally ignore color order here because
+ // we just want to test the roundtrip through the Bridge, not that we can
+ // make icons look pretty.
+ std::vector<unsigned char> raw;
+ gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, true, &raw);
+ scoped_refptr<RefCountedBytes> bytes(new RefCountedBytes(raw));
+
+ // Set up the HistoryItem.
+ HistoryMenuBridge::HistoryItem item;
+ item.menu_item.reset([[NSMenuItem alloc] init]);
+ GetFaviconForHistoryItem(&item);
+
+ // Pretend to be called back.
+ GotFaviconData(item.icon_handle, true, bytes, false, GURL());
+
+ // Make sure the callback works.
+ EXPECT_FALSE(item.icon_requested);
+ EXPECT_TRUE(item.icon.get());
+ EXPECT_TRUE([item.menu_item image]);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/history_menu_cocoa_controller.h b/chrome/browser/ui/cocoa/history_menu_cocoa_controller.h
new file mode 100644
index 0000000..d91409e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/history_menu_cocoa_controller.h
@@ -0,0 +1,32 @@
+// 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.
+
+// Controller (MVC) for the history menu. All history menu item commands get
+// directed here. This class only responds to menu events, but the actual
+// creation and maintenance of the menu happens in the Bridge.
+
+#ifndef CHROME_BROWSER_UI_COCOA_HISTORY_MENU_COCOA_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_HISTORY_MENU_COCOA_CONTROLLER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+#import "chrome/browser/ui/cocoa/history_menu_bridge.h"
+
+@interface HistoryMenuCocoaController : NSObject {
+ @private
+ HistoryMenuBridge* bridge_; // weak; owns us
+}
+
+- (id)initWithBridge:(HistoryMenuBridge*)bridge;
+
+// Called by any history menu item.
+- (IBAction)openHistoryMenuItem:(id)sender;
+
+@end // HistoryMenuCocoaController
+
+@interface HistoryMenuCocoaController (ExposedForUnitTests)
+- (void)openURLForItem:(const HistoryMenuBridge::HistoryItem*)node;
+@end // HistoryMenuCocoaController (ExposedForUnitTests)
+
+#endif // CHROME_BROWSER_UI_COCOA_HISTORY_MENU_COCOA_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/history_menu_cocoa_controller.mm b/chrome/browser/ui/cocoa/history_menu_cocoa_controller.mm
new file mode 100644
index 0000000..f3662a4
--- /dev/null
+++ b/chrome/browser/ui/cocoa/history_menu_cocoa_controller.mm
@@ -0,0 +1,56 @@
+// 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 "chrome/browser/ui/cocoa/history_menu_cocoa_controller.h"
+
+#include "base/scoped_vector.h"
+#include "chrome/app/chrome_command_ids.h" // IDC_HISTORY_MENU
+#import "chrome/browser/app_controller_mac.h"
+#include "chrome/browser/history/history.h"
+#include "chrome/browser/history/history_types.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/cocoa/event_utils.h"
+#include "webkit/glue/window_open_disposition.h"
+
+@implementation HistoryMenuCocoaController
+
+- (id)initWithBridge:(HistoryMenuBridge*)bridge {
+ if ((self = [super init])) {
+ bridge_ = bridge;
+ DCHECK(bridge_);
+ }
+ return self;
+}
+
+- (BOOL)validateMenuItem:(NSMenuItem*)menuItem {
+ AppController* controller = [NSApp delegate];
+ return [controller keyWindowIsNotModal];
+}
+
+// Open the URL of the given history item in the current tab.
+- (void)openURLForItem:(const HistoryMenuBridge::HistoryItem*)node {
+ Browser* browser = Browser::GetOrCreateTabbedBrowser(bridge_->profile());
+ WindowOpenDisposition disposition =
+ event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
+
+ // If this item can be restored using TabRestoreService, do so. Otherwise,
+ // just load the URL.
+ TabRestoreService* service = bridge_->profile()->GetTabRestoreService();
+ if (node->session_id && service) {
+ service->RestoreEntryById(browser, node->session_id, false);
+ } else {
+ DCHECK(node->url.is_valid());
+ browser->OpenURL(node->url, GURL(), disposition,
+ PageTransition::AUTO_BOOKMARK);
+ }
+}
+
+- (IBAction)openHistoryMenuItem:(id)sender {
+ const HistoryMenuBridge::HistoryItem* item =
+ bridge_->HistoryItemForMenuItem(sender);
+ [self openURLForItem:item];
+}
+
+@end // HistoryMenuCocoaController
diff --git a/chrome/browser/ui/cocoa/history_menu_cocoa_controller_unittest.mm b/chrome/browser/ui/cocoa/history_menu_cocoa_controller_unittest.mm
new file mode 100644
index 0000000..26f7388
--- /dev/null
+++ b/chrome/browser/ui/cocoa/history_menu_cocoa_controller_unittest.mm
@@ -0,0 +1,91 @@
+// 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.
+
+#include "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/history_menu_bridge.h"
+#include "chrome/browser/ui/cocoa/history_menu_cocoa_controller.h"
+#include "chrome/browser/ui/browser.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+@interface FakeHistoryMenuController : HistoryMenuCocoaController {
+ @public
+ BOOL opened_[2];
+}
+@end
+
+@implementation FakeHistoryMenuController
+
+- (id)initTest {
+ if ((self = [super init])) {
+ opened_[0] = NO;
+ opened_[1] = NO;
+ }
+ return self;
+}
+
+- (void)openURLForItem:(HistoryMenuBridge::HistoryItem*)item {
+ opened_[item->session_id] = YES;
+}
+
+@end // FakeHistoryMenuController
+
+class HistoryMenuCocoaControllerTest : public CocoaTest {
+ public:
+
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ bridge_.reset(new HistoryMenuBridge(browser_test_helper_.profile()));
+ bridge_->controller_.reset(
+ [[FakeHistoryMenuController alloc] initWithBridge:bridge_.get()]);
+ [controller() initTest];
+ }
+
+ void CreateItems(NSMenu* menu) {
+ HistoryMenuBridge::HistoryItem* item = new HistoryMenuBridge::HistoryItem();
+ item->url = GURL("http://google.com");
+ item->session_id = 0;
+ bridge_->AddItemToMenu(item, menu, HistoryMenuBridge::kMostVisited, 0);
+
+ item = new HistoryMenuBridge::HistoryItem();
+ item->url = GURL("http://apple.com");
+ item->session_id = 1;
+ bridge_->AddItemToMenu(item, menu, HistoryMenuBridge::kMostVisited, 1);
+ }
+
+ std::map<NSMenuItem*, HistoryMenuBridge::HistoryItem*>& menu_item_map() {
+ return bridge_->menu_item_map_;
+ }
+
+ FakeHistoryMenuController* controller() {
+ return static_cast<FakeHistoryMenuController*>(bridge_->controller_.get());
+ }
+
+ private:
+ BrowserTestHelper browser_test_helper_;
+ scoped_ptr<HistoryMenuBridge> bridge_;
+};
+
+TEST_F(HistoryMenuCocoaControllerTest, OpenURLForItem) {
+
+ scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@"History"]);
+ CreateItems(menu.get());
+
+ std::map<NSMenuItem*, HistoryMenuBridge::HistoryItem*>& items =
+ menu_item_map();
+ std::map<NSMenuItem*, HistoryMenuBridge::HistoryItem*>::iterator it =
+ items.begin();
+
+ for ( ; it != items.end(); ++it) {
+ HistoryMenuBridge::HistoryItem* item = it->second;
+ EXPECT_FALSE(controller()->opened_[item->session_id]);
+ [controller() openHistoryMenuItem:it->first];
+ EXPECT_TRUE(controller()->opened_[item->session_id]);
+ }
+}
diff --git a/chrome/browser/cocoa/hover_button.h b/chrome/browser/ui/cocoa/hover_button.h
index e411434..e411434 100644
--- a/chrome/browser/cocoa/hover_button.h
+++ b/chrome/browser/ui/cocoa/hover_button.h
diff --git a/chrome/browser/ui/cocoa/hover_button.mm b/chrome/browser/ui/cocoa/hover_button.mm
new file mode 100644
index 0000000..9d7a412
--- /dev/null
+++ b/chrome/browser/ui/cocoa/hover_button.mm
@@ -0,0 +1,97 @@
+// 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 "chrome/browser/ui/cocoa/hover_button.h"
+
+@implementation HoverButton
+
+- (id)initWithFrame:(NSRect)frameRect {
+ if ((self = [super initWithFrame:frameRect])) {
+ [self setTrackingEnabled:YES];
+ hoverState_ = kHoverStateNone;
+ [self updateTrackingAreas];
+ }
+ return self;
+}
+
+- (void)awakeFromNib {
+ [self setTrackingEnabled:YES];
+ hoverState_ = kHoverStateNone;
+ [self updateTrackingAreas];
+}
+
+- (void)dealloc {
+ [self setTrackingEnabled:NO];
+ [super dealloc];
+}
+
+- (void)mouseEntered:(NSEvent*)theEvent {
+ hoverState_ = kHoverStateMouseOver;
+ [self setNeedsDisplay:YES];
+}
+
+- (void)mouseExited:(NSEvent*)theEvent {
+ hoverState_ = kHoverStateNone;
+ [self setNeedsDisplay:YES];
+}
+
+- (void)mouseDown:(NSEvent*)theEvent {
+ hoverState_ = kHoverStateMouseDown;
+ [self setNeedsDisplay:YES];
+ // The hover button needs to hold onto itself here for a bit. Otherwise,
+ // it can be freed while |super mouseDown:| is in it's loop, and the
+ // |checkImageState| call will crash.
+ // http://crbug.com/28220
+ scoped_nsobject<HoverButton> myself([self retain]);
+
+ [super mouseDown:theEvent];
+ // We need to check the image state after the mouseDown event loop finishes.
+ // It's possible that we won't get a mouseExited event if the button was
+ // moved under the mouse during tab resize, instead of the mouse moving over
+ // the button.
+ // http://crbug.com/31279
+ [self checkImageState];
+}
+
+- (void)setTrackingEnabled:(BOOL)enabled {
+ if (enabled) {
+ trackingArea_.reset(
+ [[NSTrackingArea alloc] initWithRect:[self bounds]
+ options:NSTrackingMouseEnteredAndExited |
+ NSTrackingActiveAlways
+ owner:self
+ userInfo:nil]);
+ [self addTrackingArea:trackingArea_.get()];
+
+ // If you have a separate window that overlaps the close button, and you
+ // move the mouse directly over the close button without entering another
+ // part of the tab strip, we don't get any mouseEntered event since the
+ // tracking area was disabled when we entered.
+ [self checkImageState];
+ } else {
+ if (trackingArea_.get()) {
+ [self removeTrackingArea:trackingArea_.get()];
+ trackingArea_.reset(nil);
+ }
+ }
+}
+
+- (void)updateTrackingAreas {
+ [super updateTrackingAreas];
+ [self checkImageState];
+}
+
+- (void)checkImageState {
+ if (!trackingArea_.get())
+ return;
+
+ // Update the button's state if the button has moved.
+ NSPoint mouseLoc = [[self window] mouseLocationOutsideOfEventStream];
+ mouseLoc = [self convertPoint:mouseLoc fromView:nil];
+ hoverState_ = NSPointInRect(mouseLoc, [self bounds]) ?
+ kHoverStateMouseOver : kHoverStateNone;
+ [self setNeedsDisplay:YES];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/hover_close_button.h b/chrome/browser/ui/cocoa/hover_close_button.h
new file mode 100644
index 0000000..372582c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/hover_close_button.h
@@ -0,0 +1,26 @@
+// 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 "base/scoped_nsobject.h"
+#include "chrome/browser/ui/cocoa/hover_button.h"
+
+// The standard close button for our Mac UI which is the "x" that changes to a
+// dark circle with the "x" when you hover over it. At this time it is used by
+// the popup blocker, download bar, info bar and tabs.
+@interface HoverCloseButton : HoverButton {
+ @private
+ // Bezier path for drawing the 'x' within the button.
+ scoped_nsobject<NSBezierPath> xPath_;
+
+ // Bezier path for drawing the hover state circle behind the 'x'.
+ scoped_nsobject<NSBezierPath> circlePath_;
+}
+
+// Sets up the button's tracking areas and accessibility info when instantiated
+// via initWithFrame or awakeFromNib.
+- (void)commonInit;
+
+@end
diff --git a/chrome/browser/ui/cocoa/hover_close_button.mm b/chrome/browser/ui/cocoa/hover_close_button.mm
new file mode 100644
index 0000000..f8e29e2
--- /dev/null
+++ b/chrome/browser/ui/cocoa/hover_close_button.mm
@@ -0,0 +1,108 @@
+// 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 "chrome/browser/ui/cocoa/hover_close_button.h"
+
+#include "app/l10n_util.h"
+#include "base/scoped_nsobject.h"
+#include "grit/generated_resources.h"
+#import "third_party/molokocacao/NSBezierPath+MCAdditions.h"
+
+namespace {
+// Convenience function to return the middle point of the given |rect|.
+static NSPoint MidRect(NSRect rect) {
+ return NSMakePoint(NSMidX(rect), NSMidY(rect));
+}
+
+const CGFloat kCircleRadiusPercentage = 0.415;
+const CGFloat kCircleHoverWhite = 0.565;
+const CGFloat kCircleClickWhite = 0.396;
+const CGFloat kXShadowAlpha = 0.75;
+const CGFloat kXShadowCircleAlpha = 0.1;
+} // namespace
+
+@interface HoverCloseButton(Private)
+- (void)setUpDrawingPaths;
+@end
+
+@implementation HoverCloseButton
+
+- (id)initWithFrame:(NSRect)frameRect {
+ if ((self = [super initWithFrame:frameRect])) {
+ [self commonInit];
+ }
+ return self;
+}
+
+- (void)awakeFromNib {
+ [super awakeFromNib];
+ [self commonInit];
+}
+
+- (void)drawRect:(NSRect)rect {
+ if (!circlePath_.get() || !xPath_.get())
+ [self setUpDrawingPaths];
+
+ // If the user is hovering over the button, a light/dark gray circle is drawn
+ // behind the 'x'.
+ if (hoverState_ != kHoverStateNone) {
+ // Adjust the darkness of the circle depending on whether it is being
+ // clicked.
+ CGFloat white = (hoverState_ == kHoverStateMouseOver) ?
+ kCircleHoverWhite : kCircleClickWhite;
+ [[NSColor colorWithCalibratedWhite:white alpha:1.0] set];
+ [circlePath_ fill];
+ }
+
+ [[NSColor whiteColor] set];
+ [xPath_ fill];
+
+ // Give the 'x' an inner shadow for depth. If the button is in a hover state
+ // (circle behind it), then adjust the shadow accordingly (not as harsh).
+ NSShadow* shadow = [[[NSShadow alloc] init] autorelease];
+ CGFloat alpha = (hoverState_ != kHoverStateNone) ?
+ kXShadowCircleAlpha : kXShadowAlpha;
+ [shadow setShadowColor:[NSColor colorWithCalibratedWhite:0.15
+ alpha:alpha]];
+ [shadow setShadowOffset:NSMakeSize(0.0, 0.0)];
+ [shadow setShadowBlurRadius:2.5];
+ [xPath_ fillWithInnerShadow:shadow];
+}
+
+- (void)commonInit {
+ // Set accessibility description.
+ NSString* description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_CLOSE);
+ [[self cell]
+ accessibilitySetOverrideValue:description
+ forAttribute:NSAccessibilityDescriptionAttribute];
+}
+
+- (void)setUpDrawingPaths {
+ NSPoint viewCenter = MidRect([self bounds]);
+
+ circlePath_.reset([[NSBezierPath bezierPath] retain]);
+ [circlePath_ moveToPoint:viewCenter];
+ CGFloat radius = kCircleRadiusPercentage * NSWidth([self bounds]);
+ [circlePath_ appendBezierPathWithArcWithCenter:viewCenter
+ radius:radius
+ startAngle:0.0
+ endAngle:365.0];
+
+ // Construct an 'x' by drawing two intersecting rectangles in the shape of a
+ // cross and then rotating the path by 45 degrees.
+ xPath_.reset([[NSBezierPath bezierPath] retain]);
+ [xPath_ appendBezierPathWithRect:NSMakeRect(3.5, 7.0, 9.0, 2.0)];
+ [xPath_ appendBezierPathWithRect:NSMakeRect(7.0, 3.5, 2.0, 9.0)];
+
+ NSPoint pathCenter = MidRect([xPath_ bounds]);
+
+ NSAffineTransform* transform = [NSAffineTransform transform];
+ [transform translateXBy:viewCenter.x yBy:viewCenter.y];
+ [transform rotateByDegrees:45.0];
+ [transform translateXBy:-pathCenter.x yBy:-pathCenter.y];
+
+ [xPath_ transformUsingAffineTransform:transform];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/hover_image_button.h b/chrome/browser/ui/cocoa/hover_image_button.h
new file mode 100644
index 0000000..76a702d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/hover_image_button.h
@@ -0,0 +1,40 @@
+// 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 "base/scoped_nsobject.h"
+#include "chrome/browser/ui/cocoa/hover_button.h"
+
+// A button that changes images when you hover over it and click it.
+@interface HoverImageButton : HoverButton {
+ @private
+ float defaultOpacity_;
+ float hoverOpacity_;
+ float pressedOpacity_;
+
+ scoped_nsobject<NSImage> defaultImage_;
+ scoped_nsobject<NSImage> hoverImage_;
+ scoped_nsobject<NSImage> pressedImage_;
+}
+
+// Sets the default image.
+- (void)setDefaultImage:(NSImage*)image;
+
+// Sets the hover image.
+- (void)setHoverImage:(NSImage*)image;
+
+// Sets the pressed image.
+- (void)setPressedImage:(NSImage*)image;
+
+// Sets the default opacity.
+- (void)setDefaultOpacity:(float)opacity;
+
+// Sets the opacity on hover.
+- (void)setHoverOpacity:(float)opacity;
+
+// Sets the opacity when pressed.
+- (void)setPressedOpacity:(float)opacity;
+
+@end
diff --git a/chrome/browser/ui/cocoa/hover_image_button.mm b/chrome/browser/ui/cocoa/hover_image_button.mm
new file mode 100644
index 0000000..c5bdbf4
--- /dev/null
+++ b/chrome/browser/ui/cocoa/hover_image_button.mm
@@ -0,0 +1,52 @@
+// 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 "chrome/browser/ui/cocoa/hover_image_button.h"
+
+#include "app/l10n_util.h"
+#include "base/scoped_nsobject.h"
+#include "grit/generated_resources.h"
+
+@implementation HoverImageButton
+
+- (void)drawRect:(NSRect)rect {
+ if (hoverState_ == kHoverStateMouseDown && pressedImage_) {
+ [super setImage:pressedImage_.get()];
+ [super setAlphaValue:pressedOpacity_];
+ } else if (hoverState_ == kHoverStateMouseOver && hoverImage_) {
+ [super setImage:hoverImage_.get()];
+ [super setAlphaValue:hoverOpacity_];
+ } else {
+ [super setImage:defaultImage_.get()];
+ [super setAlphaValue:defaultOpacity_];
+ }
+
+ [super drawRect:rect];
+}
+
+- (void)setDefaultImage:(NSImage*)image {
+ defaultImage_.reset([image retain]);
+}
+
+- (void)setDefaultOpacity:(float)opacity {
+ defaultOpacity_ = opacity;
+}
+
+- (void)setHoverImage:(NSImage*)image {
+ hoverImage_.reset([image retain]);
+}
+
+- (void)setHoverOpacity:(float)opacity {
+ hoverOpacity_ = opacity;
+}
+
+- (void)setPressedImage:(NSImage*)image {
+ pressedImage_.reset([image retain]);
+}
+
+- (void)setPressedOpacity:(float)opacity {
+ pressedOpacity_ = opacity;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/hover_image_button_unittest.mm b/chrome/browser/ui/cocoa/hover_image_button_unittest.mm
new file mode 100644
index 0000000..d2db766
--- /dev/null
+++ b/chrome/browser/ui/cocoa/hover_image_button_unittest.mm
@@ -0,0 +1,67 @@
+// Copyright (c) 2009 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 "app/resource_bundle.h"
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/hover_image_button.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+#include "grit/theme_resources.h"
+
+namespace {
+
+class HoverImageButtonTest : public CocoaTest {
+ public:
+ HoverImageButtonTest() {
+ NSRect content_frame = [[test_window() contentView] frame];
+ scoped_nsobject<HoverImageButton> button(
+ [[HoverImageButton alloc] initWithFrame:content_frame]);
+ button_ = button.get();
+ [[test_window() contentView] addSubview:button_];
+ }
+
+ virtual void SetUp() {
+ CocoaTest::BootstrapCocoa();
+ }
+
+ HoverImageButton* button_;
+};
+
+// Test mouse events.
+TEST_F(HoverImageButtonTest, ImageSwap) {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ NSImage* image = rb.GetNativeImageNamed(IDR_HOME);
+ NSImage* hover = rb.GetNativeImageNamed(IDR_BACK);
+ [button_ setDefaultImage:image];
+ [button_ setHoverImage:hover];
+
+ [button_ mouseEntered:nil];
+ [button_ drawRect:[button_ frame]];
+ EXPECT_EQ([button_ image], hover);
+ [button_ mouseExited:nil];
+ [button_ drawRect:[button_ frame]];
+ EXPECT_EQ([button_ image], image);
+}
+
+// Test mouse events.
+TEST_F(HoverImageButtonTest, Opacity) {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ NSImage* image = rb.GetNativeImageNamed(IDR_HOME);
+ [button_ setDefaultImage:image];
+ [button_ setDefaultOpacity:0.5];
+ [button_ setHoverImage:image];
+ [button_ setHoverOpacity:1.0];
+
+ [button_ mouseEntered:nil];
+ [button_ drawRect:[button_ frame]];
+ EXPECT_EQ([button_ alphaValue], 1.0);
+ [button_ mouseExited:nil];
+ [button_ drawRect:[button_ frame]];
+ EXPECT_EQ([button_ alphaValue], 0.5);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/html_dialog_window_controller.h b/chrome/browser/ui/cocoa/html_dialog_window_controller.h
new file mode 100644
index 0000000..3fa41a3
--- /dev/null
+++ b/chrome/browser/ui/cocoa/html_dialog_window_controller.h
@@ -0,0 +1,55 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_HTML_DIALOG_WINDOW_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_HTML_DIALOG_WINDOW_CONTROLLER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/dom_ui/html_dialog_ui.h"
+
+class HtmlDialogWindowDelegateBridge;
+class Profile;
+class TabContents;
+
+// This controller manages a dialog box with properties and HTML content taken
+// from a HTMLDialogUIDelegate object.
+@interface HtmlDialogWindowController : NSWindowController {
+ @private
+ // Order here is important, as tab_contents_ may send messages to
+ // delegate_ when it gets destroyed.
+ scoped_ptr<HtmlDialogWindowDelegateBridge> delegate_;
+ scoped_ptr<TabContents> tabContents_;
+}
+
+// Creates and shows an HtmlDialogWindowController with the given
+// delegate and profile. The window is automatically destroyed when
+// it is closed. Returns the created window.
+//
+// Make sure to use the returned window only when you know it is safe
+// to do so, i.e. before OnDialogClosed() is called on the delegate.
++ (NSWindow*)showHtmlDialog:(HtmlDialogUIDelegate*)delegate
+ profile:(Profile*)profile;
+
+@end
+
+@interface HtmlDialogWindowController (TestingAPI)
+
+// This is the designated initializer. However, this is exposed only
+// for testing; use showHtmlDialog instead.
+- (id)initWithDelegate:(HtmlDialogUIDelegate*)delegate
+ profile:(Profile*)profile;
+
+// Loads the HTML content from the delegate; this is not a lightweight
+// process which is why it is not part of the constructor. Must be
+// called before showWindow.
+- (void)loadDialogContents;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_HTML_DIALOG_WINDOW_CONTROLLER_H_
+
diff --git a/chrome/browser/ui/cocoa/html_dialog_window_controller.mm b/chrome/browser/ui/cocoa/html_dialog_window_controller.mm
new file mode 100644
index 0000000..611ecdd
--- /dev/null
+++ b/chrome/browser/ui/cocoa/html_dialog_window_controller.mm
@@ -0,0 +1,293 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/html_dialog_window_controller.h"
+
+#include "app/keyboard_codes.h"
+#include "base/logging.h"
+#include "base/scoped_nsobject.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/dom_ui/html_dialog_ui.h"
+#include "chrome/browser/dom_ui/html_dialog_tab_contents_delegate.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#import "chrome/browser/ui/cocoa/browser_command_executor.h"
+#import "chrome/browser/ui/cocoa/chrome_event_processing_window.h"
+#include "chrome/common/native_web_keyboard_event.h"
+#include "gfx/size.h"
+#include "ipc/ipc_message.h"
+
+// Thin bridge that routes notifications to
+// HtmlDialogWindowController's member variables.
+class HtmlDialogWindowDelegateBridge : public HtmlDialogUIDelegate,
+ public HtmlDialogTabContentsDelegate {
+public:
+ // All parameters must be non-NULL/non-nil.
+ HtmlDialogWindowDelegateBridge(HtmlDialogWindowController* controller,
+ Profile* profile,
+ HtmlDialogUIDelegate* delegate);
+
+ virtual ~HtmlDialogWindowDelegateBridge();
+
+ // Called when the window is directly closed, e.g. from the close
+ // button or from an accelerator.
+ void WindowControllerClosed();
+
+ // HtmlDialogUIDelegate declarations.
+ virtual bool IsDialogModal() const;
+ virtual std::wstring GetDialogTitle() const;
+ virtual GURL GetDialogContentURL() const;
+ virtual void GetDOMMessageHandlers(
+ std::vector<DOMMessageHandler*>* handlers) const;
+ virtual void GetDialogSize(gfx::Size* size) const;
+ virtual std::string GetDialogArgs() const;
+ virtual void OnDialogClosed(const std::string& json_retval);
+ virtual void OnCloseContents(TabContents* source, bool* out_close_dialog) { }
+ virtual bool ShouldShowDialogTitle() const { return true; }
+
+ // HtmlDialogTabContentsDelegate declarations.
+ virtual void MoveContents(TabContents* source, const gfx::Rect& pos);
+ virtual void ToolbarSizeChanged(TabContents* source, bool is_animating);
+ virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event);
+
+private:
+ HtmlDialogWindowController* controller_; // weak
+ HtmlDialogUIDelegate* delegate_; // weak, owned by controller_
+
+ // Calls delegate_'s OnDialogClosed() exactly once, nulling it out
+ // afterwards so that no other HtmlDialogUIDelegate calls are sent
+ // to it. Returns whether or not the OnDialogClosed() was actually
+ // called on the delegate.
+ bool DelegateOnDialogClosed(const std::string& json_retval);
+
+ DISALLOW_COPY_AND_ASSIGN(HtmlDialogWindowDelegateBridge);
+};
+
+// ChromeEventProcessingWindow expects its controller to implement the
+// BrowserCommandExecutor protocol.
+@interface HtmlDialogWindowController (InternalAPI) <BrowserCommandExecutor>
+
+// BrowserCommandExecutor methods.
+- (void)executeCommand:(int)command;
+
+@end
+
+namespace html_dialog_window_controller {
+
+gfx::NativeWindow ShowHtmlDialog(
+ HtmlDialogUIDelegate* delegate, Profile* profile) {
+ return [HtmlDialogWindowController showHtmlDialog:delegate profile:profile];
+}
+
+} // namespace html_dialog_window_controller
+
+HtmlDialogWindowDelegateBridge::HtmlDialogWindowDelegateBridge(
+ HtmlDialogWindowController* controller, Profile* profile,
+ HtmlDialogUIDelegate* delegate)
+ : HtmlDialogTabContentsDelegate(profile),
+ controller_(controller), delegate_(delegate) {
+ DCHECK(controller_);
+ DCHECK(delegate_);
+}
+
+HtmlDialogWindowDelegateBridge::~HtmlDialogWindowDelegateBridge() {}
+
+void HtmlDialogWindowDelegateBridge::WindowControllerClosed() {
+ Detach();
+ controller_ = nil;
+ DelegateOnDialogClosed("");
+}
+
+bool HtmlDialogWindowDelegateBridge::DelegateOnDialogClosed(
+ const std::string& json_retval) {
+ if (delegate_) {
+ HtmlDialogUIDelegate* real_delegate = delegate_;
+ delegate_ = NULL;
+ real_delegate->OnDialogClosed(json_retval);
+ return true;
+ }
+ return false;
+}
+
+// HtmlDialogUIDelegate definitions.
+
+// All of these functions check for NULL first since delegate_ is set
+// to NULL when the window is closed.
+
+bool HtmlDialogWindowDelegateBridge::IsDialogModal() const {
+ // TODO(akalin): Support modal dialog boxes.
+ if (delegate_ && delegate_->IsDialogModal()) {
+ LOG(WARNING) << "Modal HTML dialogs are not supported yet";
+ }
+ return false;
+}
+
+std::wstring HtmlDialogWindowDelegateBridge::GetDialogTitle() const {
+ return delegate_ ? delegate_->GetDialogTitle() : L"";
+}
+
+GURL HtmlDialogWindowDelegateBridge::GetDialogContentURL() const {
+ return delegate_ ? delegate_->GetDialogContentURL() : GURL();
+}
+
+void HtmlDialogWindowDelegateBridge::GetDOMMessageHandlers(
+ std::vector<DOMMessageHandler*>* handlers) const {
+ if (delegate_) {
+ delegate_->GetDOMMessageHandlers(handlers);
+ } else {
+ // TODO(akalin): Add this clause in the windows version. Also
+ // make sure that everything expects handlers to be non-NULL and
+ // document it.
+ handlers->clear();
+ }
+}
+
+void HtmlDialogWindowDelegateBridge::GetDialogSize(gfx::Size* size) const {
+ if (delegate_) {
+ delegate_->GetDialogSize(size);
+ } else {
+ *size = gfx::Size();
+ }
+}
+
+std::string HtmlDialogWindowDelegateBridge::GetDialogArgs() const {
+ return delegate_ ? delegate_->GetDialogArgs() : "";
+}
+
+void HtmlDialogWindowDelegateBridge::OnDialogClosed(
+ const std::string& json_retval) {
+ Detach();
+ // [controller_ close] should be called at most once, too.
+ if (DelegateOnDialogClosed(json_retval)) {
+ [controller_ close];
+ }
+ controller_ = nil;
+}
+
+void HtmlDialogWindowDelegateBridge::MoveContents(TabContents* source,
+ const gfx::Rect& pos) {
+ // TODO(akalin): Actually set the window bounds.
+}
+
+void HtmlDialogWindowDelegateBridge::ToolbarSizeChanged(
+ TabContents* source, bool is_animating) {
+ // TODO(akalin): Figure out what to do here.
+}
+
+// A simplified version of BrowserWindowCocoa::HandleKeyboardEvent().
+// We don't handle global keyboard shortcuts here, but that's fine since
+// they're all browser-specific. (This may change in the future.)
+void HtmlDialogWindowDelegateBridge::HandleKeyboardEvent(
+ const NativeWebKeyboardEvent& event) {
+ if (event.skip_in_browser || event.type == NativeWebKeyboardEvent::Char)
+ return;
+
+ // Close ourselves if the user hits Esc or Command-. . The normal
+ // way to do this is to implement (void)cancel:(int)sender, but
+ // since we handle keyboard events ourselves we can't do that.
+ //
+ // According to experiments, hitting Esc works regardless of the
+ // presence of other modifiers (as long as it's not an app-level
+ // shortcut, e.g. Commmand-Esc for Front Row) but no other modifiers
+ // can be present for Command-. to work.
+ //
+ // TODO(thakis): It would be nice to get cancel: to work somehow.
+ // Bug: http://code.google.com/p/chromium/issues/detail?id=32828 .
+ if (event.type == NativeWebKeyboardEvent::RawKeyDown &&
+ ((event.windowsKeyCode == app::VKEY_ESCAPE) ||
+ (event.windowsKeyCode == app::VKEY_OEM_PERIOD &&
+ event.modifiers == NativeWebKeyboardEvent::MetaKey))) {
+ [controller_ close];
+ return;
+ }
+
+ ChromeEventProcessingWindow* event_window =
+ static_cast<ChromeEventProcessingWindow*>([controller_ window]);
+ DCHECK([event_window isKindOfClass:[ChromeEventProcessingWindow class]]);
+ [event_window redispatchKeyEvent:event.os_event];
+}
+
+@implementation HtmlDialogWindowController (InternalAPI)
+
+// This gets called whenever a chrome-specific keyboard shortcut is performed
+// in the HTML dialog window. We simply swallow all those events.
+- (void)executeCommand:(int)command {}
+
+@end
+
+@implementation HtmlDialogWindowController
+
+// NOTE(akalin): We'll probably have to add the parentWindow parameter back
+// in once we implement modal dialogs.
+
++ (NSWindow*)showHtmlDialog:(HtmlDialogUIDelegate*)delegate
+ profile:(Profile*)profile {
+ HtmlDialogWindowController* htmlDialogWindowController =
+ [[HtmlDialogWindowController alloc] initWithDelegate:delegate
+ profile:profile];
+ [htmlDialogWindowController loadDialogContents];
+ [htmlDialogWindowController showWindow:nil];
+ return [htmlDialogWindowController window];
+}
+
+- (id)initWithDelegate:(HtmlDialogUIDelegate*)delegate
+ profile:(Profile*)profile {
+ DCHECK(delegate);
+ DCHECK(profile);
+
+ gfx::Size dialogSize;
+ delegate->GetDialogSize(&dialogSize);
+ NSRect dialogRect = NSMakeRect(0, 0, dialogSize.width(), dialogSize.height());
+ // TODO(akalin): Make the window resizable (but with the minimum size being
+ // dialog_size and always on top (but not modal) to match the Windows
+ // behavior. On the other hand, the fact that HTML dialogs on Windows
+ // are resizable could just be an accident. Investigate futher...
+ NSUInteger style = NSTitledWindowMask | NSClosableWindowMask;
+ scoped_nsobject<ChromeEventProcessingWindow> window(
+ [[ChromeEventProcessingWindow alloc]
+ initWithContentRect:dialogRect
+ styleMask:style
+ backing:NSBackingStoreBuffered
+ defer:YES]);
+ if (!window.get()) {
+ return nil;
+ }
+ self = [super initWithWindow:window];
+ if (!self) {
+ return nil;
+ }
+ [window setWindowController:self];
+ [window setDelegate:self];
+ [window setTitle:base::SysWideToNSString(delegate->GetDialogTitle())];
+ [window center];
+ delegate_.reset(new HtmlDialogWindowDelegateBridge(self, profile, delegate));
+ return self;
+}
+
+- (void)loadDialogContents {
+ tabContents_.reset(new TabContents(
+ delegate_->profile(), NULL, MSG_ROUTING_NONE, NULL, NULL));
+ [[self window] setContentView:tabContents_->GetNativeView()];
+ tabContents_->set_delegate(delegate_.get());
+
+ // This must be done before loading the page; see the comments in
+ // HtmlDialogUI.
+ HtmlDialogUI::GetPropertyAccessor().SetProperty(tabContents_->property_bag(),
+ delegate_.get());
+
+ tabContents_->controller().LoadURL(delegate_->GetDialogContentURL(),
+ GURL(), PageTransition::START_PAGE);
+
+ // TODO(akalin): add accelerator for ESC to close the dialog box.
+ //
+ // TODO(akalin): Figure out why implementing (void)cancel:(id)sender
+ // to do the above doesn't work.
+}
+
+- (void)windowWillClose:(NSNotification*)notification {
+ delegate_->WindowControllerClosed();
+ [self autorelease];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/html_dialog_window_controller_cppsafe.h b/chrome/browser/ui/cocoa/html_dialog_window_controller_cppsafe.h
new file mode 100644
index 0000000..dd3b809
--- /dev/null
+++ b/chrome/browser/ui/cocoa/html_dialog_window_controller_cppsafe.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_HTML_DIALOG_WINDOW_CONTROLLER_CPPSAFE_H_
+#define CHROME_BROWSER_UI_COCOA_HTML_DIALOG_WINDOW_CONTROLLER_CPPSAFE_H_
+#pragma once
+
+#include "gfx/native_widget_types.h"
+
+// We declare this in a separate file that is safe for including in C++ code.
+
+// TODO(akalin): It would be nice if there were a platform-agnostic way to
+// create a browser-independent HTML dialog. However, this would require
+// some invasive changes on the Windows/Linux side. Remove this file once
+// We have this platform-agnostic API.
+
+namespace html_dialog_window_controller {
+
+// Creates and shows an HtmlDialogWindowController with the given
+// delegate and profile. The window is automatically destroyed when it is
+// closed. Returns the created window.
+//
+// Make sure to use the returned window only when you know it is safe
+// to do so, i.e. before OnDialogClosed() is called on the delegate.
+gfx::NativeWindow ShowHtmlDialog(
+ HtmlDialogUIDelegate* delegate, Profile* profile);
+
+} // namespace html_dialog_window_controller
+
+#endif // CHROME_BROWSER_UI_COCOA_HTML_DIALOG_WINDOW_CONTROLLER_CPPSAFE_H_
+
diff --git a/chrome/browser/ui/cocoa/html_dialog_window_controller_unittest.mm b/chrome/browser/ui/cocoa/html_dialog_window_controller_unittest.mm
new file mode 100644
index 0000000..7bbeb31
--- /dev/null
+++ b/chrome/browser/ui/cocoa/html_dialog_window_controller_unittest.mm
@@ -0,0 +1,94 @@
+// 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 "chrome/browser/ui/cocoa/html_dialog_window_controller.h"
+
+#include <string>
+#include <vector>
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/mac/scoped_nsautorelease_pool.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/dom_ui/dom_ui.h"
+#include "chrome/browser/dom_ui/html_dialog_ui.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/test/browser_with_test_window_test.h"
+#include "chrome/test/testing_profile.h"
+#include "gfx/size.h"
+#include "googleurl/src/gurl.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class MockDelegate : public HtmlDialogUIDelegate {
+public:
+ MOCK_CONST_METHOD0(IsDialogModal, bool());
+ MOCK_CONST_METHOD0(GetDialogTitle, std::wstring());
+ MOCK_CONST_METHOD0(GetDialogContentURL, GURL());
+ MOCK_CONST_METHOD1(GetDOMMessageHandlers,
+ void(std::vector<DOMMessageHandler*>*));
+ MOCK_CONST_METHOD1(GetDialogSize, void(gfx::Size*));
+ MOCK_CONST_METHOD0(GetDialogArgs, std::string());
+ MOCK_METHOD1(OnDialogClosed, void(const std::string& json_retval));
+ MOCK_METHOD2(OnCloseContents,
+ void(TabContents* source, bool* out_close_dialog));
+ MOCK_CONST_METHOD0(ShouldShowDialogTitle, bool());
+};
+
+class HtmlDialogWindowControllerTest : public BrowserWithTestWindowTest {
+ public:
+ virtual void SetUp() {
+ BrowserWithTestWindowTest::SetUp();
+ CocoaTest::BootstrapCocoa();
+ title_ = L"Mock Title";
+ size_ = gfx::Size(50, 100);
+ gurl_ = GURL("");
+ }
+
+ protected:
+ std::wstring title_;
+ gfx::Size size_;
+ GURL gurl_;
+
+ // Order here is important.
+ MockDelegate delegate_;
+};
+
+using ::testing::_;
+using ::testing::Return;
+using ::testing::SetArgumentPointee;
+
+// TODO(akalin): We can't test much more than the below without a real browser.
+// In particular, GetDOMMessageHandlers() and GetDialogArgs() are never called.
+// This should be fixed.
+
+TEST_F(HtmlDialogWindowControllerTest, showDialog) {
+ // We want to make sure html_dialog_window_controller below gets
+ // destroyed before delegate_, so we specify our own autorelease pool.
+ //
+ // TODO(dmaclach): Remove this once
+ // http://code.google.com/p/chromium/issues/detail?id=26133 is fixed.
+ base::mac::ScopedNSAutoreleasePool release_pool;
+
+ EXPECT_CALL(delegate_, GetDialogTitle())
+ .WillOnce(Return(title_));
+ EXPECT_CALL(delegate_, GetDialogSize(_))
+ .WillOnce(SetArgumentPointee<0>(size_));
+ EXPECT_CALL(delegate_, GetDialogContentURL())
+ .WillOnce(Return(gurl_));
+ EXPECT_CALL(delegate_, OnDialogClosed(_))
+ .Times(1);
+
+ HtmlDialogWindowController* html_dialog_window_controller =
+ [[HtmlDialogWindowController alloc] initWithDelegate:&delegate_
+ profile:profile()];
+
+ [html_dialog_window_controller loadDialogContents];
+ [html_dialog_window_controller showWindow:nil];
+ [html_dialog_window_controller close];
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/hung_renderer_controller.h b/chrome/browser/ui/cocoa/hung_renderer_controller.h
new file mode 100644
index 0000000..584feb8
--- /dev/null
+++ b/chrome/browser/ui/cocoa/hung_renderer_controller.h
@@ -0,0 +1,76 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_HUNG_RENDERER_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_HUNG_RENDERER_CONTROLLER_H_
+#pragma once
+
+// A controller for the Mac hung renderer dialog window. Only one
+// instance of this controller can exist at any time, although a given
+// controller is destroyed when its window is closed.
+//
+// The dialog itself displays a list of frozen tabs, all of which
+// share a render process. Since there can only be a single dialog
+// open at a time, if showForTabContents is called for a different
+// tab, the dialog is repurposed to show a warning for the new tab.
+//
+// The caller is required to call endForTabContents before deleting
+// any TabContents object.
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/mac/cocoa_protocols.h"
+#import "base/scoped_nsobject.h"
+
+@class MultiKeyEquivalentButton;
+class TabContents;
+
+@interface HungRendererController : NSWindowController<NSTableViewDataSource> {
+ @private
+ IBOutlet MultiKeyEquivalentButton* waitButton_;
+ IBOutlet NSButton* killButton_;
+ IBOutlet NSTableView* tableView_;
+ IBOutlet NSImageView* imageView_;
+ IBOutlet NSTextField* messageView_;
+
+ // The TabContents for which this dialog is open. Should never be
+ // NULL while this dialog is open.
+ TabContents* hungContents_;
+
+ // Backing data for |tableView_|. Titles of each TabContents that
+ // shares a renderer process with |hungContents_|.
+ scoped_nsobject<NSArray> hungTitles_;
+
+ // Favicons of each TabContents that shares a renderer process with
+ // |hungContents_|.
+ scoped_nsobject<NSArray> hungFavicons_;
+}
+
+// Kills the hung renderers.
+- (IBAction)kill:(id)sender;
+
+// Waits longer for the renderers to respond.
+- (IBAction)wait:(id)sender;
+
+// Modifies the dialog to show a warning for the given tab contents.
+// The dialog will contain a list of all tabs that share a renderer
+// process with |contents|. The caller must not delete any tab
+// contents without first calling endForTabContents.
+- (void)showForTabContents:(TabContents*)contents;
+
+// Notifies the dialog that |contents| is either responsive or closed.
+// If |contents| shares the same render process as the tab contents
+// this dialog was created for, this function will close the dialog.
+// If |contents| has a different process, this function does nothing.
+- (void)endForTabContents:(TabContents*)contents;
+
+@end // HungRendererController
+
+
+@interface HungRendererController (JustForTesting)
+- (NSButton*)killButton;
+- (MultiKeyEquivalentButton*)waitButton;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_HUNG_RENDERER_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/hung_renderer_controller.mm b/chrome/browser/ui/cocoa/hung_renderer_controller.mm
new file mode 100644
index 0000000..130a3f7
--- /dev/null
+++ b/chrome/browser/ui/cocoa/hung_renderer_controller.mm
@@ -0,0 +1,203 @@
+// 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 "chrome/browser/ui/cocoa/hung_renderer_controller.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "app/resource_bundle.h"
+#include "app/l10n_util_mac.h"
+#include "base/mac_util.h"
+#include "base/process_util.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/hung_renderer_dialog.h"
+#include "chrome/browser/renderer_host/render_process_host.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#import "chrome/browser/ui/cocoa/multi_key_equivalent_button.h"
+#include "chrome/common/logging_chrome.h"
+#include "chrome/common/result_codes.h"
+#include "grit/chromium_strings.h"
+#include "grit/app_resources.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "skia/ext/skia_utils_mac.h"
+#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
+
+namespace {
+// We only support showing one of these at a time per app. The
+// controller owns itself and is released when its window is closed.
+HungRendererController* g_instance = NULL;
+} // end namespace
+
+@implementation HungRendererController
+
+- (id)initWithWindowNibName:(NSString*)nibName {
+ NSString* nibpath = [mac_util::MainAppBundle() pathForResource:nibName
+ ofType:@"nib"];
+ self = [super initWithWindowNibPath:nibpath owner:self];
+ if (self) {
+ [tableView_ setDataSource:self];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ DCHECK(!g_instance);
+ [tableView_ setDataSource:nil];
+ [super dealloc];
+}
+
+- (void)awakeFromNib {
+ // Load in the image
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ NSImage* backgroundImage = rb.GetNativeImageNamed(IDR_FROZEN_TAB_ICON);
+ DCHECK(backgroundImage);
+ [imageView_ setImage:backgroundImage];
+
+ // Make the message fit.
+ CGFloat messageShift =
+ [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:messageView_];
+
+ // Move the graphic up to be top even with the message.
+ NSRect graphicFrame = [imageView_ frame];
+ graphicFrame.origin.y += messageShift;
+ [imageView_ setFrame:graphicFrame];
+
+ // Make the window taller to fit everything.
+ NSSize windowDelta = NSMakeSize(0, messageShift);
+ [GTMUILocalizerAndLayoutTweaker
+ resizeWindowWithoutAutoResizingSubViews:[self window]
+ delta:windowDelta];
+
+ // Make the "wait" button respond to additional keys. By setting this to
+ // @"\e", it will respond to both Esc and Command-. (period).
+ KeyEquivalentAndModifierMask key;
+ key.charCode = @"\e";
+ [waitButton_ addKeyEquivalent:key];
+}
+
+- (IBAction)kill:(id)sender {
+ if (hungContents_)
+ base::KillProcess(hungContents_->GetRenderProcessHost()->GetHandle(),
+ ResultCodes::HUNG, false);
+ // Cannot call performClose:, because the close button is disabled.
+ [self close];
+}
+
+- (IBAction)wait:(id)sender {
+ if (hungContents_ && hungContents_->render_view_host())
+ hungContents_->render_view_host()->RestartHangMonitorTimeout();
+ // Cannot call performClose:, because the close button is disabled.
+ [self close];
+}
+
+- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView {
+ return [hungTitles_ count];
+}
+
+- (id)tableView:(NSTableView*)aTableView
+ objectValueForTableColumn:(NSTableColumn*)column
+ row:(NSInteger)rowIndex {
+ return [NSNumber numberWithInt:NSOffState];
+}
+
+- (NSCell*)tableView:(NSTableView*)tableView
+ dataCellForTableColumn:(NSTableColumn*)tableColumn
+ row:(NSInteger)rowIndex {
+ NSCell* cell = [tableColumn dataCellForRow:rowIndex];
+
+ if ([[tableColumn identifier] isEqualToString:@"title"]) {
+ DCHECK([cell isKindOfClass:[NSButtonCell class]]);
+ NSButtonCell* buttonCell = static_cast<NSButtonCell*>(cell);
+ [buttonCell setTitle:[hungTitles_ objectAtIndex:rowIndex]];
+ [buttonCell setImage:[hungFavicons_ objectAtIndex:rowIndex]];
+ [buttonCell setRefusesFirstResponder:YES]; // Don't push in like a button.
+ [buttonCell setHighlightsBy:NSNoCellMask];
+ }
+ return cell;
+}
+
+- (void)windowWillClose:(NSNotification*)notification {
+ // We have to reset g_instance before autoreleasing the window,
+ // because we want to avoid reusing the same dialog if someone calls
+ // hung_renderer_dialog::ShowForTabContents() between the autorelease
+ // call and the actual dealloc.
+ g_instance = nil;
+
+ [self autorelease];
+}
+
+- (void)showForTabContents:(TabContents*)contents {
+ DCHECK(contents);
+ hungContents_ = contents;
+ scoped_nsobject<NSMutableArray> titles([[NSMutableArray alloc] init]);
+ scoped_nsobject<NSMutableArray> favicons([[NSMutableArray alloc] init]);
+ for (TabContentsIterator it; !it.done(); ++it) {
+ if (it->GetRenderProcessHost() == hungContents_->GetRenderProcessHost()) {
+ string16 title = (*it)->GetTitle();
+ if (title.empty())
+ title = TabContents::GetDefaultTitle();
+ [titles addObject:base::SysUTF16ToNSString(title)];
+
+ // TabContents can return a null SkBitmap if it has no favicon. If this
+ // happens, use the default favicon.
+ const SkBitmap& bitmap = it->GetFavIcon();
+ if (!bitmap.isNull()) {
+ [favicons addObject:gfx::SkBitmapToNSImage(bitmap)];
+ } else {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ [favicons addObject:rb.GetNativeImageNamed(IDR_DEFAULT_FAVICON)];
+ }
+ }
+ }
+ hungTitles_.reset([titles copy]);
+ hungFavicons_.reset([favicons copy]);
+ [tableView_ reloadData];
+
+ [[self window] center];
+ [self showWindow:self];
+}
+
+- (void)endForTabContents:(TabContents*)contents {
+ DCHECK(contents);
+ DCHECK(hungContents_);
+ if (hungContents_ && hungContents_->GetRenderProcessHost() ==
+ contents->GetRenderProcessHost()) {
+ // Cannot call performClose:, because the close button is disabled.
+ [self close];
+ }
+}
+
+@end
+
+@implementation HungRendererController (JustForTesting)
+- (NSButton*)killButton {
+ return killButton_;
+}
+
+- (MultiKeyEquivalentButton*)waitButton {
+ return waitButton_;
+}
+@end
+
+namespace hung_renderer_dialog {
+
+void ShowForTabContents(TabContents* contents) {
+ if (!logging::DialogsAreSuppressed()) {
+ if (!g_instance)
+ g_instance = [[HungRendererController alloc]
+ initWithWindowNibName:@"HungRendererDialog"];
+ [g_instance showForTabContents:contents];
+ }
+}
+
+// static
+void HideForTabContents(TabContents* contents) {
+ if (!logging::DialogsAreSuppressed() && g_instance)
+ [g_instance endForTabContents:contents];
+}
+
+} // namespace hung_renderer_dialog
diff --git a/chrome/browser/ui/cocoa/hung_renderer_controller_unittest.mm b/chrome/browser/ui/cocoa/hung_renderer_controller_unittest.mm
new file mode 100644
index 0000000..e03becf
--- /dev/null
+++ b/chrome/browser/ui/cocoa/hung_renderer_controller_unittest.mm
@@ -0,0 +1,51 @@
+// Copyright (c) 2009 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>
+
+#import "base/scoped_nsobject.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/hung_renderer_controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class HungRendererControllerTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ hung_renderer_controller_ = [[HungRendererController alloc]
+ initWithWindowNibName:@"HungRendererDialog"];
+ }
+ HungRendererController* hung_renderer_controller_; // owned by its window
+};
+
+TEST_F(HungRendererControllerTest, TestShowAndClose) {
+ // Doesn't test much functionality-wise, but makes sure we can
+ // display and tear down a window.
+ [hung_renderer_controller_ showWindow:nil];
+ // Cannot call performClose:, because the close button is disabled.
+ [hung_renderer_controller_ close];
+}
+
+TEST_F(HungRendererControllerTest, TestKillButton) {
+ // We can't test killing a process because we have no running
+ // process to kill, but we can make sure that pressing the kill
+ // button closes the window.
+ [hung_renderer_controller_ showWindow:nil];
+ [[hung_renderer_controller_ killButton] performClick:nil];
+}
+
+TEST_F(HungRendererControllerTest, TestWaitButton) {
+ // We can't test waiting because we have no running process to wait
+ // for, but we can make sure that pressing the wait button closes
+ // the window.
+ [hung_renderer_controller_ showWindow:nil];
+ [[hung_renderer_controller_ waitButton] performClick:nil];
+}
+
+} // namespace
+
diff --git a/chrome/browser/cocoa/hyperlink_button_cell.h b/chrome/browser/ui/cocoa/hyperlink_button_cell.h
index c4d27ff..c4d27ff 100644
--- a/chrome/browser/cocoa/hyperlink_button_cell.h
+++ b/chrome/browser/ui/cocoa/hyperlink_button_cell.h
diff --git a/chrome/browser/ui/cocoa/hyperlink_button_cell.mm b/chrome/browser/ui/cocoa/hyperlink_button_cell.mm
new file mode 100644
index 0000000..4bb9049
--- /dev/null
+++ b/chrome/browser/ui/cocoa/hyperlink_button_cell.mm
@@ -0,0 +1,115 @@
+// 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 "chrome/browser/ui/cocoa/hyperlink_button_cell.h"
+
+@interface HyperlinkButtonCell (Private)
+- (NSDictionary*)linkAttributres;
+- (void)customizeButtonCell;
+@end
+
+@implementation HyperlinkButtonCell
+@dynamic textColor;
+
++ (NSColor*)defaultTextColor {
+ return [NSColor blueColor];
+}
+
+// Designated initializer.
+- (id)init {
+ if ((self = [super init])) {
+ [self customizeButtonCell];
+ }
+ return self;
+}
+
+// Initializer called when the cell is loaded from the NIB.
+- (id)initWithCoder:(NSCoder*)aDecoder {
+ if ((self = [super initWithCoder:aDecoder])) {
+ [self customizeButtonCell];
+ }
+ return self;
+}
+
+// Initializer for code-based creation.
+- (id)initTextCell:(NSString*)title {
+ if ((self = [super initTextCell:title])) {
+ [self customizeButtonCell];
+ }
+ return self;
+}
+
+// Because an NSButtonCell has multiple initializers, this method performs the
+// common cell customization code.
+- (void)customizeButtonCell {
+ [self setBordered:NO];
+ [self setTextColor:[HyperlinkButtonCell defaultTextColor]];
+
+ CGFloat fontSize = [NSFont systemFontSizeForControlSize:[self controlSize]];
+ NSFont* font = [NSFont controlContentFontOfSize:fontSize];
+ [self setFont:font];
+
+ // Do not change button appearance when we are pushed.
+ [self setHighlightsBy:NSNoCellMask];
+
+ // We need to set this so that we can override |-mouseEntered:| and
+ // |-mouseExited:| to change the cursor style on hover states.
+ [self setShowsBorderOnlyWhileMouseInside:YES];
+}
+
+- (void)setControlSize:(NSControlSize)size {
+ [super setControlSize:size];
+ [self customizeButtonCell]; // recompute |font|.
+}
+
+// Creates the NSDictionary of attributes for the attributed string.
+- (NSDictionary*)linkAttributes {
+ NSUInteger underlineMask = NSUnderlinePatternSolid | NSUnderlineStyleSingle;
+ scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
+ [[NSParagraphStyle defaultParagraphStyle] mutableCopy]);
+ [paragraphStyle setAlignment:[self alignment]];
+
+ return [NSDictionary dictionaryWithObjectsAndKeys:
+ [self textColor], NSForegroundColorAttributeName,
+ [NSNumber numberWithInt:underlineMask], NSUnderlineStyleAttributeName,
+ [self font], NSFontAttributeName,
+ [NSCursor pointingHandCursor], NSCursorAttributeName,
+ paragraphStyle.get(), NSParagraphStyleAttributeName,
+ nil
+ ];
+}
+
+// Override the drawing for the cell so that the custom style attributes
+// can always be applied and so that ellipses will appear when appropriate.
+- (NSRect)drawTitle:(NSAttributedString*)title
+ withFrame:(NSRect)frame
+ inView:(NSView*)controlView {
+ NSDictionary* linkAttributes = [self linkAttributes];
+ NSString* plainTitle = [title string];
+ [plainTitle drawWithRect:frame
+ options:(NSStringDrawingUsesLineFragmentOrigin |
+ NSStringDrawingTruncatesLastVisibleLine)
+ attributes:linkAttributes];
+ return frame;
+}
+
+// Override the default behavior to draw the border. Instead, change the cursor.
+- (void)mouseEntered:(NSEvent*)event {
+ [[NSCursor pointingHandCursor] push];
+}
+
+- (void)mouseExited:(NSEvent*)event {
+ [NSCursor pop];
+}
+
+// Setters and getters.
+- (NSColor*)textColor {
+ return textColor_.get();
+}
+
+- (void)setTextColor:(NSColor*)color {
+ textColor_.reset([color retain]);
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/hyperlink_button_cell_unittest.mm b/chrome/browser/ui/cocoa/hyperlink_button_cell_unittest.mm
new file mode 100644
index 0000000..0adae14
--- /dev/null
+++ b/chrome/browser/ui/cocoa/hyperlink_button_cell_unittest.mm
@@ -0,0 +1,75 @@
+// Copyright (c) 2009 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 "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/hyperlink_button_cell.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class HyperlinkButtonCellTest : public CocoaTest {
+ public:
+ HyperlinkButtonCellTest() {
+ NSRect frame = NSMakeRect(0, 0, 50, 30);
+ scoped_nsobject<NSButton> view([[NSButton alloc] initWithFrame:frame]);
+ view_ = view.get();
+ scoped_nsobject<HyperlinkButtonCell> cell(
+ [[HyperlinkButtonCell alloc] initTextCell:@"Testing"]);
+ cell_ = cell.get();
+ [view_ setCell:cell_];
+ [[test_window() contentView] addSubview:view_];
+ }
+
+ void TestCellCustomization(HyperlinkButtonCell* cell) {
+ EXPECT_FALSE([cell isBordered]);
+ EXPECT_EQ(NSNoCellMask, [cell_ highlightsBy]);
+ EXPECT_TRUE([cell showsBorderOnlyWhileMouseInside]);
+ EXPECT_TRUE([cell textColor]);
+ }
+
+ NSButton* view_;
+ HyperlinkButtonCell* cell_;
+};
+
+TEST_VIEW(HyperlinkButtonCellTest, view_)
+
+// Tests the three designated intializers.
+TEST_F(HyperlinkButtonCellTest, Initializers) {
+ TestCellCustomization(cell_); // |-initTextFrame:|
+ scoped_nsobject<HyperlinkButtonCell> cell([[HyperlinkButtonCell alloc] init]);
+ TestCellCustomization(cell.get());
+
+ // Need to create a dummy archiver to test |-initWithCoder:|.
+ NSData* emptyData = [NSKeyedArchiver archivedDataWithRootObject:@""];
+ NSCoder* coder =
+ [[[NSKeyedUnarchiver alloc] initForReadingWithData:emptyData] autorelease];
+ cell.reset([[HyperlinkButtonCell alloc] initWithCoder:coder]);
+ TestCellCustomization(cell);
+}
+
+// Test set color.
+TEST_F(HyperlinkButtonCellTest, SetTextColor) {
+ NSColor* textColor = [NSColor redColor];
+ EXPECT_NE(textColor, [cell_ textColor]);
+ [cell_ setTextColor:textColor];
+ EXPECT_EQ(textColor, [cell_ textColor]);
+}
+
+// Test mouse events.
+// TODO(rsesek): See if we can synthesize mouse events to more accurately
+// test this.
+TEST_F(HyperlinkButtonCellTest, MouseHover) {
+ [[NSCursor disappearingItemCursor] push]; // Set a known state.
+ [cell_ mouseEntered:nil];
+ EXPECT_EQ([NSCursor pointingHandCursor], [NSCursor currentCursor]);
+ [cell_ mouseExited:nil];
+ EXPECT_EQ([NSCursor disappearingItemCursor], [NSCursor currentCursor]);
+ [NSCursor pop];
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/image_utils.h b/chrome/browser/ui/cocoa/image_utils.h
new file mode 100644
index 0000000..5c43828
--- /dev/null
+++ b/chrome/browser/ui/cocoa/image_utils.h
@@ -0,0 +1,26 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_IMAGE_UTILS_H_
+#define CHROME_BROWSER_UI_COCOA_IMAGE_UTILS_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+@interface NSImage (FlippedAdditions)
+
+// Works like |-drawInRect:fromRect:operation:fraction:|, except that
+// if |neverFlipped| is |YES|, and the context is flipped, the a
+// transform is applied to flip it again before drawing the image.
+//
+// Compare to the 10.6 method
+// |-drawInRect:fromRect:operation:fraction:respectFlipped:hints:|.
+- (void)drawInRect:(NSRect)dstRect
+ fromRect:(NSRect)srcRect
+ operation:(NSCompositingOperation)op
+ fraction:(CGFloat)requestedAlpha
+ neverFlipped:(BOOL)neverFlipped;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_IMAGE_UTILS_H_
diff --git a/chrome/browser/ui/cocoa/image_utils.mm b/chrome/browser/ui/cocoa/image_utils.mm
new file mode 100644
index 0000000..b2883ff
--- /dev/null
+++ b/chrome/browser/ui/cocoa/image_utils.mm
@@ -0,0 +1,37 @@
+// 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 "chrome/browser/ui/cocoa/image_utils.h"
+
+@implementation NSImage (FlippedAdditions)
+
+- (void)drawInRect:(NSRect)dstRect
+ fromRect:(NSRect)srcRect
+ operation:(NSCompositingOperation)op
+ fraction:(CGFloat)requestedAlpha
+ neverFlipped:(BOOL)neverFlipped {
+ NSAffineTransform *transform = nil;
+
+ // Flip drawing and adjust the origin to make the image come out
+ // right.
+ if (neverFlipped && [[NSGraphicsContext currentContext] isFlipped]) {
+ transform = [NSAffineTransform transform];
+ [transform scaleXBy:1.0 yBy:-1.0];
+ [transform concat];
+
+ // The lower edge of the image is as far from the origin as the
+ // upper edge was, plus it's on the other side of the origin.
+ dstRect.origin.y -= NSMaxY(dstRect) + NSMinY(dstRect);
+ }
+
+ [self drawInRect:dstRect
+ fromRect:srcRect
+ operation:op
+ fraction:requestedAlpha];
+
+ // Flip drawing back, if needed.
+ [transform concat];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/image_utils_unittest.mm b/chrome/browser/ui/cocoa/image_utils_unittest.mm
new file mode 100644
index 0000000..d13b33b
--- /dev/null
+++ b/chrome/browser/ui/cocoa/image_utils_unittest.mm
@@ -0,0 +1,138 @@
+// 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 "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/image_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+@interface ImageUtilsTestView : NSView {
+ @private
+ // Determine whether the view is flipped.
+ BOOL isFlipped_;
+
+ // Determines whether to draw using the new method with
+ // |neverFlipped:|.
+ BOOL useNeverFlipped_;
+
+ // Passed to |neverFlipped:| when drawing |image_|.
+ BOOL neverFlipped_;
+
+ scoped_nsobject<NSImage> image_;
+}
+@property(assign, nonatomic) BOOL isFlipped;
+@property(assign, nonatomic) BOOL useNeverFlipped;
+@property(assign, nonatomic) BOOL neverFlipped;
+@end
+
+@implementation ImageUtilsTestView
+@synthesize isFlipped = isFlipped_;
+@synthesize useNeverFlipped = useNeverFlipped_;
+@synthesize neverFlipped = neverFlipped_;
+
+- (id)initWithFrame:(NSRect)rect {
+ self = [super initWithFrame:rect];
+ if (self) {
+ rect = NSInsetRect(rect, 5.0, 5.0);
+ rect.origin = NSZeroPoint;
+ const NSSize imageSize = NSInsetRect(rect, 5.0, 5.0).size;
+ image_.reset([[NSImage alloc] initWithSize:imageSize]);
+
+ NSBezierPath* path = [NSBezierPath bezierPath];
+ [path moveToPoint:NSMakePoint(NSMinX(rect), NSMinY(rect))];
+ [path lineToPoint:NSMakePoint(NSMinX(rect), NSMaxY(rect))];
+ [path lineToPoint:NSMakePoint(NSMaxX(rect), NSMinY(rect))];
+ [path closePath];
+
+ [image_ lockFocus];
+ [[NSColor blueColor] setFill];
+ [path fill];
+ [image_ unlockFocus];
+ }
+ return self;
+}
+
+- (void)drawRect:(NSRect)rect {
+ NSBezierPath* path = [NSBezierPath bezierPath];
+ [path moveToPoint:NSMakePoint(NSMinX(rect), NSMinY(rect))];
+ [path lineToPoint:NSMakePoint(NSMinX(rect), NSMaxY(rect))];
+ [path lineToPoint:NSMakePoint(NSMaxX(rect), NSMinY(rect))];
+ [path closePath];
+
+ [[NSColor redColor] setFill];
+ [path fill];
+
+ rect = NSInsetRect(rect, 5.0, 5.0);
+ rect = NSOffsetRect(rect, 2.0, 2.0);
+
+ if (useNeverFlipped_) {
+ [image_ drawInRect:rect
+ fromRect:NSZeroRect
+ operation:NSCompositeCopy
+ fraction:1.0
+ neverFlipped:neverFlipped_];
+ } else {
+ [image_ drawInRect:rect
+ fromRect:NSZeroRect
+ operation:NSCompositeCopy
+ fraction:1.0];
+ }
+}
+
+@end
+
+namespace {
+
+class ImageUtilTest : public CocoaTest {
+ public:
+ ImageUtilTest() {
+ const NSRect frame = NSMakeRect(0, 0, 300, 100);
+ scoped_nsobject<ImageUtilsTestView> view(
+ [[ImageUtilsTestView alloc] initWithFrame: frame]);
+ view_ = view.get();
+ [[test_window() contentView] addSubview:view_];
+ }
+
+ NSData* SnapshotView() {
+ [view_ display];
+
+ const NSRect bounds = [view_ bounds];
+
+ [view_ lockFocus];
+ scoped_nsobject<NSBitmapImageRep> bitmap(
+ [[NSBitmapImageRep alloc] initWithFocusedViewRect:bounds]);
+ [view_ unlockFocus];
+
+ return [bitmap TIFFRepresentation];
+ }
+
+ NSData* SnapshotViewBase() {
+ [view_ setUseNeverFlipped:NO];
+ return SnapshotView();
+ }
+
+ NSData* SnapshotViewNeverFlipped(BOOL neverFlipped) {
+ [view_ setUseNeverFlipped:YES];
+ [view_ setNeverFlipped:neverFlipped];
+ return SnapshotView();
+ }
+
+ ImageUtilsTestView* view_;
+};
+
+TEST_F(ImageUtilTest, Test) {
+ // When not flipped, both drawing methods return the same data.
+ [view_ setIsFlipped:NO];
+ NSData* baseSnapshotData = SnapshotViewBase();
+ EXPECT_TRUE([baseSnapshotData isEqualToData:SnapshotViewNeverFlipped(YES)]);
+ EXPECT_TRUE([baseSnapshotData isEqualToData:SnapshotViewNeverFlipped(NO)]);
+
+ // When flipped, there's only a difference when the context flip is
+ // not being respected.
+ [view_ setIsFlipped:YES];
+ baseSnapshotData = SnapshotViewBase();
+ EXPECT_FALSE([baseSnapshotData isEqualToData:SnapshotViewNeverFlipped(YES)]);
+ EXPECT_TRUE([baseSnapshotData isEqualToData:SnapshotViewNeverFlipped(NO)]);
+}
+
+} // namespace
diff --git a/chrome/browser/cocoa/import_progress_dialog.h b/chrome/browser/ui/cocoa/import_progress_dialog.h
index c1b405b..c1b405b 100644
--- a/chrome/browser/cocoa/import_progress_dialog.h
+++ b/chrome/browser/ui/cocoa/import_progress_dialog.h
diff --git a/chrome/browser/ui/cocoa/import_progress_dialog.mm b/chrome/browser/ui/cocoa/import_progress_dialog.mm
new file mode 100644
index 0000000..6ec0ed5
--- /dev/null
+++ b/chrome/browser/ui/cocoa/import_progress_dialog.mm
@@ -0,0 +1,192 @@
+// 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 "chrome/browser/ui/cocoa/import_progress_dialog.h"
+
+#include "app/l10n_util.h"
+#include "app/l10n_util_mac.h"
+#include "base/logging.h"
+#include "base/mac_util.h"
+#include "base/message_loop.h"
+#import "base/scoped_nsobject.h"
+#import "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+
+namespace {
+
+// Convert ImportItem enum into the name of the ImportProgressDialogController
+// property corresponding to the text for that item, this makes the code to
+// change the values for said properties much more readable.
+NSString* keyForImportItem(importer::ImportItem item) {
+ switch(item) {
+ case importer::HISTORY:
+ return @"historyStatusText";
+ case importer::FAVORITES:
+ return @"favoritesStatusText";
+ case importer::PASSWORDS:
+ return @"savedPasswordStatusText";
+ case importer::SEARCH_ENGINES:
+ return @"searchStatusText";
+ default:
+ DCHECK(false);
+ break;
+ }
+ return nil;
+}
+
+} // namespace
+
+@implementation ImportProgressDialogController
+
+@synthesize explanatoryText = explanatory_text_;
+@synthesize favoritesStatusText = favorites_status_text_;
+@synthesize searchStatusText = search_status_text_;
+@synthesize savedPasswordStatusText = saved_password_status_text_;
+@synthesize historyStatusText = history_status_text_;
+
+@synthesize favoritesImportEnabled = favorites_import_enabled_;
+@synthesize searchImportEnabled = search_import_enabled_;
+@synthesize passwordImportEnabled = password_import_enabled_;
+@synthesize historyImportEnabled = history_import_enabled_;
+
+- (id)initWithImporterHost:(ImporterHost*)host
+ browserName:(string16)browserName
+ observer:(ImportObserver*)observer
+ itemsEnabled:(int16)items {
+ NSString* nib_path =
+ [mac_util::MainAppBundle() pathForResource:@"ImportProgressDialog"
+ ofType:@"nib"];
+ self = [super initWithWindowNibPath:nib_path owner:self];
+ if (self != nil) {
+ importer_host_ = host;
+ observer_ = observer;
+ import_host_observer_bridge_.reset(new ImporterObserverBridge(self));
+ importer_host_->SetObserver(import_host_observer_bridge_.get());
+
+ string16 productName = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
+ NSString* explanatory_text = l10n_util::GetNSStringF(
+ IDS_IMPORT_PROGRESS_EXPLANATORY_TEXT_MAC,
+ productName,
+ browserName);
+ [self setExplanatoryText:explanatory_text];
+
+ progress_text_ =
+ [l10n_util::GetNSStringWithFixup(IDS_IMPORT_IMPORTING_PROGRESS_TEXT_MAC)
+ retain];
+ done_text_ =
+ [l10n_util::GetNSStringWithFixup(IDS_IMPORT_IMPORTING_DONE_TEXT_MAC)
+ retain];
+
+ // Enable/disable item titles.
+ NSColor* disabled = [NSColor disabledControlTextColor];
+ NSColor* active = [NSColor textColor];
+ [self setFavoritesImportEnabled:items & importer::FAVORITES ? active :
+ disabled];
+ [self setSearchImportEnabled:items & importer::SEARCH_ENGINES ? active :
+ disabled];
+ [self setPasswordImportEnabled:items & importer::PASSWORDS ? active :
+ disabled];
+ [self setHistoryImportEnabled:items & importer::HISTORY ? active :
+ disabled];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [explanatory_text_ release];
+ [favorites_status_text_ release];
+ [search_status_text_ release];
+ [saved_password_status_text_ release];
+ [history_status_text_ release];
+
+ [favorites_import_enabled_ release];
+ [search_import_enabled_ release];
+ [password_import_enabled_ release];
+ [history_import_enabled_ release];
+
+ [progress_text_ release];
+ [done_text_ release];
+
+ [super dealloc];
+}
+
+- (IBAction)showWindow:(id)sender {
+ NSWindow* win = [self window];
+ [win center];
+ [super showWindow:nil];
+}
+
+- (void)closeDialog {
+ if ([[self window] isVisible]) {
+ [[self window] close];
+ }
+}
+
+- (IBAction)cancel:(id)sender {
+ // The ImporterHost will notify import_host_observer_bridge_ that import has
+ // ended, which will trigger the ImportEnded method, in which this object is
+ // released.
+ importer_host_->Cancel();
+}
+
+- (void)ImportItemStarted:(importer::ImportItem)item {
+ [self setValue:progress_text_ forKey:keyForImportItem(item)];
+}
+
+- (void)ImportItemEnded:(importer::ImportItem)item {
+ [self setValue:done_text_ forKey:keyForImportItem(item)];
+}
+
+- (void)ImportEnded {
+ importer_host_->SetObserver(NULL);
+ if (observer_)
+ observer_->ImportComplete();
+ [self closeDialog];
+ [self release];
+
+ // Break out of modal event loop.
+ [NSApp stopModal];
+}
+
+@end
+
+void StartImportingWithUI(gfx::NativeWindow parent_window,
+ uint16 items,
+ ImporterHost* coordinator,
+ const importer::ProfileInfo& source_profile,
+ Profile* target_profile,
+ ImportObserver* observer,
+ bool first_run) {
+ DCHECK(items != 0);
+
+ // Retrieve name of browser we're importing from and do a little dance to
+ // convert wstring -> string16.
+ string16 import_browser_name = WideToUTF16Hack(source_profile.description);
+
+ // progress_dialog_ is responsible for deleting itself.
+ ImportProgressDialogController* progress_dialog_ =
+ [[ImportProgressDialogController alloc]
+ initWithImporterHost:coordinator
+ browserName:import_browser_name
+ observer:observer
+ itemsEnabled:items];
+ // Call is async.
+ coordinator->StartImportSettings(source_profile, target_profile, items,
+ new ProfileWriter(target_profile),
+ first_run);
+
+ // Display the window while spinning a message loop.
+ // For details on why we need a modal message loop see http://crbug.com/19169
+ NSWindow* progress_window = [progress_dialog_ window];
+ NSModalSession session = [NSApp beginModalSessionForWindow:progress_window];
+ [progress_dialog_ showWindow:nil];
+ while (true) {
+ if ([NSApp runModalSession:session] != NSRunContinuesResponse)
+ break;
+ MessageLoop::current()->RunAllPending();
+ }
+ [NSApp endModalSession:session];
+}
diff --git a/chrome/browser/ui/cocoa/import_settings_dialog.h b/chrome/browser/ui/cocoa/import_settings_dialog.h
new file mode 100644
index 0000000..a9ff7f4
--- /dev/null
+++ b/chrome/browser/ui/cocoa/import_settings_dialog.h
@@ -0,0 +1,98 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_IMPORT_SETTINGS_DIALOG_H_
+#define CHROME_BROWSER_UI_COCOA_IMPORT_SETTINGS_DIALOG_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+#include "chrome/browser/importer/importer.h"
+
+class Profile;
+
+// Controller for the Import Bookmarks and Settings dialog. This controller
+// automatically autoreleases itself when its associated dialog is dismissed.
+@interface ImportSettingsDialogController : NSWindowController {
+ @private
+ NSWindow* parentWindow_; // weak
+ Profile* profile_; // weak
+ scoped_refptr<ImporterList> importerList_;
+ scoped_nsobject<NSArray> sourceBrowsersList_;
+ NSUInteger sourceBrowserIndex_;
+ // The following are all bound via the properties below.
+ BOOL importHistory_;
+ BOOL importFavorites_;
+ BOOL importPasswords_;
+ BOOL importSearchEngines_;
+ BOOL historyAvailable_;
+ BOOL favoritesAvailable_;
+ BOOL passwordsAvailable_;
+ BOOL searchEnginesAvailable_;
+}
+
+// Show the import settings window. Window is displayed as an app modal dialog.
+// If the dialog is already being displayed, this method whill return with
+// no error.
++ (void)showImportSettingsDialogForProfile:(Profile*)profile;
+
+// Called when the "Import" button is pressed.
+- (IBAction)ok:(id)sender;
+
+// Cancel button calls this.
+- (IBAction)cancel:(id)sender;
+
+// An array of ImportSettingsProfiles, provide the list of browser profiles
+// available for importing. Bound to the Browser List array controller.
+- (NSArray*)sourceBrowsersList;
+
+// Properties for bindings.
+@property(assign, nonatomic) NSUInteger sourceBrowserIndex;
+@property(assign, readonly, nonatomic) BOOL importSomething;
+// Bindings for the value of the import checkboxes.
+@property(assign, nonatomic) BOOL importHistory;
+@property(assign, nonatomic) BOOL importFavorites;
+@property(assign, nonatomic) BOOL importPasswords;
+@property(assign, nonatomic) BOOL importSearchEngines;
+// Bindings for enabling/disabling the checkboxes.
+@property(assign, readonly, nonatomic) BOOL historyAvailable;
+@property(assign, readonly, nonatomic) BOOL favoritesAvailable;
+@property(assign, readonly, nonatomic) BOOL passwordsAvailable;
+@property(assign, readonly, nonatomic) BOOL searchEnginesAvailable;
+
+@end
+
+@interface ImportSettingsDialogController (TestingAPI)
+
+// Initialize by providing an array of profile dictionaries. Exposed for
+// unit testing but also called by -[initWithProfile:].
+- (id)initWithProfiles:(NSArray*)profiles;
+
+// Return selected services to import as mapped by the ImportItem enum.
+- (uint16)servicesToImport;
+
+@end
+
+// Utility class used as array elements for sourceBrowsersList, above.
+@interface ImportSettingsProfile : NSObject {
+ @private
+ NSString* browserName_;
+ uint16 services_; // Services as defined by enum ImportItem.
+}
+
+// Convenience creator. |services| is a bitfield of enum ImportItems.
++ (id)importSettingsProfileWithBrowserName:(NSString*)browserName
+ services:(uint16)services;
+
+// Designated initializer. |services| is a bitfield of enum ImportItems.
+- (id)initWithBrowserName:(NSString*)browserName
+ services:(uint16)services; // Bitfield of enum ImportItems.
+
+@property(copy, nonatomic) NSString* browserName;
+@property(assign, nonatomic) uint16 services; // Bitfield of enum ImportItems.
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_IMPORT_SETTINGS_DIALOG_H_
diff --git a/chrome/browser/ui/cocoa/import_settings_dialog.mm b/chrome/browser/ui/cocoa/import_settings_dialog.mm
new file mode 100644
index 0000000..5e6da7a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/import_settings_dialog.mm
@@ -0,0 +1,245 @@
+// 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 "chrome/browser/ui/cocoa/import_settings_dialog.h"
+
+#include "base/mac_util.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/importer/importer_data_types.h"
+#include "chrome/browser/importer/importer_list.h"
+#include "chrome/browser/profiles/profile.h"
+
+namespace {
+
+bool importSettingsDialogVisible = false;
+
+} // namespace
+
+@interface ImportSettingsDialogController ()
+
+@property(assign, readwrite, nonatomic) BOOL historyAvailable;
+@property(assign, readwrite, nonatomic) BOOL favoritesAvailable;
+@property(assign, readwrite, nonatomic) BOOL passwordsAvailable;
+@property(assign, readwrite, nonatomic) BOOL searchEnginesAvailable;
+
+@end
+
+@implementation ImportSettingsProfile
+
+@synthesize browserName = browserName_;
+@synthesize services = services_;
+
++ (id)importSettingsProfileWithBrowserName:(NSString*)browserName
+ services:(uint16)services {
+ id settingsProfile = [[[ImportSettingsProfile alloc]
+ initWithBrowserName:browserName
+ services:services] autorelease];
+ return settingsProfile;
+}
+
+- (id)initWithBrowserName:(NSString*)browserName
+ services:(uint16)services {
+ DCHECK(browserName && services);
+ if ((self = [super init])) {
+ if (browserName && services != 0) {
+ browserName_ = [browserName retain];
+ services_ = services;
+ } else {
+ [self release];
+ self = nil;
+ }
+ }
+ return self;
+}
+
+- (id)init {
+ NOTREACHED(); // Should never be called.
+ return [self initWithBrowserName:NULL services:0];
+}
+
+- (void)dealloc {
+ [browserName_ release];
+ [super dealloc];
+}
+
+@end
+
+@interface ImportSettingsDialogController (Private)
+
+// Initialize the dialog controller with either the default profile or
+// the profile for the current browser.
+- (id)initWithProfile:(Profile*)profile;
+
+// Present the app modal dialog.
+- (void)runModalDialog;
+
+// Close the modal dialog.
+- (void)closeDialog;
+
+@end
+
+@implementation ImportSettingsDialogController
+
+@synthesize sourceBrowserIndex = sourceBrowserIndex_;
+@synthesize importHistory = importHistory_;
+@synthesize importFavorites = importFavorites_;
+@synthesize importPasswords = importPasswords_;
+@synthesize importSearchEngines = importSearchEngines_;
+@synthesize historyAvailable = historyAvailable_;
+@synthesize favoritesAvailable = favoritesAvailable_;
+@synthesize passwordsAvailable = passwordsAvailable_;
+@synthesize searchEnginesAvailable = searchEnginesAvailable_;
+
+// Set bindings dependencies for importSomething property.
++ (NSSet*)keyPathsForValuesAffectingImportSomething {
+ return [NSSet setWithObjects:@"importHistory", @"importFavorites",
+ @"importPasswords", @"importSearchEngines", nil];
+}
+
++ (void)showImportSettingsDialogForProfile:(Profile*)profile {
+ // Don't display if already visible.
+ if (importSettingsDialogVisible)
+ return;
+ ImportSettingsDialogController* controller =
+ [[ImportSettingsDialogController alloc] initWithProfile:profile];
+ [controller runModalDialog];
+}
+
+- (id)initWithProfile:(Profile*)profile {
+ // Collect profile information (profile name and the services which can
+ // be imported from each) into an array of ImportSettingsProfile which
+ // are bound to the Browser List array controller and the popup name
+ // presentation. The services element is used to indirectly control
+ // checkbox enabling.
+ importerList_ = new ImporterList;
+ ImporterList& importerList(*(importerList_.get()));
+ importerList.DetectSourceProfilesHack();
+ int profilesCount = importerList.GetAvailableProfileCount();
+ // There shoule be at least the default profile so this should never be zero.
+ DCHECK(profilesCount > 0);
+ NSMutableArray* browserProfiles =
+ [NSMutableArray arrayWithCapacity:profilesCount];
+ for (int i = 0; i < profilesCount; ++i) {
+ const importer::ProfileInfo& sourceProfile =
+ importerList.GetSourceProfileInfoAt(i);
+ NSString* browserName =
+ base::SysWideToNSString(sourceProfile.description);
+ uint16 browserServices = sourceProfile.services_supported;
+ ImportSettingsProfile* settingsProfile =
+ [ImportSettingsProfile
+ importSettingsProfileWithBrowserName:browserName
+ services:browserServices];
+ [browserProfiles addObject:settingsProfile];
+ }
+ if ((self = [self initWithProfiles:browserProfiles])) {
+ profile_ = profile;
+ }
+ return self;
+}
+
+- (id)initWithProfiles:(NSArray*)profiles {
+ NSString* nibpath =
+ [mac_util::MainAppBundle() pathForResource:@"ImportSettingsDialog"
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
+ sourceBrowsersList_.reset([profiles retain]);
+ // Create and initialize an importerList_ when running unit tests.
+ if (!importerList_.get()) {
+ importerList_ = new ImporterList;
+ ImporterList& importerList(*(importerList_.get()));
+ importerList.DetectSourceProfilesHack();
+ }
+ }
+ return self;
+}
+
+- (id)init {
+ return [self initWithProfile:NULL];
+}
+
+- (void)awakeFromNib {
+ // Force an update of the checkbox enabled states.
+ [self setSourceBrowserIndex:0];
+}
+
+// Run application modal.
+- (void)runModalDialog {
+ importSettingsDialogVisible = true;
+ [NSApp runModalForWindow:[self window]];
+}
+
+- (IBAction)ok:(id)sender {
+ [self closeDialog];
+ const importer::ProfileInfo& sourceProfile =
+ importerList_.get()->GetSourceProfileInfoAt([self sourceBrowserIndex]);
+ uint16 items = sourceProfile.services_supported;
+ uint16 servicesToImport = items & [self servicesToImport];
+ if (servicesToImport) {
+ if (profile_) {
+ ImporterHost* importerHost = new ExternalProcessImporterHost;
+ // Note that a side effect of the following call is to cause the
+ // importerHost to be disposed once the import has completed.
+ StartImportingWithUI(nil, servicesToImport, importerHost,
+ sourceProfile, profile_, nil, false);
+ }
+ } else {
+ LOG(WARNING) << "There were no settings to import from '"
+ << sourceProfile.description << "'.";
+ }
+}
+
+- (IBAction)cancel:(id)sender {
+ [self closeDialog];
+}
+
+- (void)closeDialog {
+ importSettingsDialogVisible = false;
+ [[self window] orderOut:self];
+ [NSApp stopModal];
+ [self autorelease];
+}
+
+#pragma mark Accessors
+
+- (NSArray*)sourceBrowsersList {
+ return sourceBrowsersList_.get();
+}
+
+// Accessor which cascades selected-browser changes into a re-evaluation of the
+// available services and the associated checkbox enable and checked states.
+- (void)setSourceBrowserIndex:(NSUInteger)browserIndex {
+ sourceBrowserIndex_ = browserIndex;
+ ImportSettingsProfile* profile =
+ [sourceBrowsersList_.get() objectAtIndex:browserIndex];
+ uint16 items = [profile services];
+ [self setHistoryAvailable:(items & importer::HISTORY) ? YES : NO];
+ [self setImportHistory:[self historyAvailable]];
+ [self setFavoritesAvailable:(items & importer::FAVORITES) ? YES : NO];
+ [self setImportFavorites:[self favoritesAvailable]];
+ [self setPasswordsAvailable:(items & importer::PASSWORDS) ? YES : NO];
+ [self setImportPasswords:[self passwordsAvailable]];
+ [self setSearchEnginesAvailable:(items & importer::SEARCH_ENGINES) ?
+ YES : NO];
+ [self setImportSearchEngines:[self searchEnginesAvailable]];
+}
+
+- (uint16)servicesToImport {
+ uint16 servicesToImport = 0;
+ if ([self importHistory]) servicesToImport |= importer::HISTORY;
+ if ([self importFavorites]) servicesToImport |= importer::FAVORITES;
+ if ([self importPasswords]) servicesToImport |= importer::PASSWORDS;
+ if ([self importSearchEngines]) servicesToImport |=
+ importer::SEARCH_ENGINES;
+ return servicesToImport;
+}
+
+// KVO accessor which returns YES if at least one of the services
+// provided by the selected profile has been marked for importing
+// and bound to the OK button's enable property.
+- (BOOL)importSomething {
+ return [self importHistory] || [self importFavorites] ||
+ [self importPasswords] || [self importSearchEngines];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/import_settings_dialog_unittest.mm b/chrome/browser/ui/cocoa/import_settings_dialog_unittest.mm
new file mode 100644
index 0000000..f9399c2
--- /dev/null
+++ b/chrome/browser/ui/cocoa/import_settings_dialog_unittest.mm
@@ -0,0 +1,130 @@
+// 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 "base/scoped_nsobject.h"
+#include "chrome/browser/importer/importer.h"
+#import "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/import_settings_dialog.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+using importer::HISTORY;
+using importer::FAVORITES;
+using importer::COOKIES;
+using importer::PASSWORDS;
+using importer::SEARCH_ENGINES;
+using importer::NONE;
+
+class ImportSettingsDialogTest : public CocoaTest {
+ public:
+ ImportSettingsDialogController* controller_;
+
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ unsigned int safariServices =
+ HISTORY | FAVORITES | COOKIES | PASSWORDS | SEARCH_ENGINES;
+ ImportSettingsProfile* mockSafari =
+ [ImportSettingsProfile
+ importSettingsProfileWithBrowserName:@"MockSafari"
+ services:safariServices];
+ unsigned int firefoxServices = HISTORY | FAVORITES | COOKIES | PASSWORDS;
+ ImportSettingsProfile* mockFirefox =
+ [ImportSettingsProfile
+ importSettingsProfileWithBrowserName:@"MockFirefox"
+ services:firefoxServices];
+ unsigned int caminoServices = HISTORY | COOKIES | SEARCH_ENGINES;
+ ImportSettingsProfile* mockCamino =
+ [ImportSettingsProfile
+ importSettingsProfileWithBrowserName:@"MockCamino"
+ services:caminoServices];
+ NSArray* browsers = [NSArray arrayWithObjects:
+ mockSafari, mockFirefox, mockCamino, nil];
+ controller_ = [[ImportSettingsDialogController alloc]
+ initWithProfiles:browsers];
+ }
+
+ virtual void TearDown() {
+ controller_ = NULL;
+ CocoaTest::TearDown();
+ }
+};
+
+TEST_F(ImportSettingsDialogTest, CancelDialog) {
+ [controller_ cancel:nil];
+}
+
+TEST_F(ImportSettingsDialogTest, ChooseVariousBrowsers) {
+ // Initial choice should already be MockSafari with all items enabled.
+ [controller_ setSourceBrowserIndex:0];
+ EXPECT_TRUE([controller_ importHistory]);
+ EXPECT_TRUE([controller_ historyAvailable]);
+ EXPECT_TRUE([controller_ importFavorites]);
+ EXPECT_TRUE([controller_ favoritesAvailable]);
+ EXPECT_TRUE([controller_ importPasswords]);
+ EXPECT_TRUE([controller_ passwordsAvailable]);
+ EXPECT_TRUE([controller_ importSearchEngines]);
+ EXPECT_TRUE([controller_ searchEnginesAvailable]);
+ EXPECT_EQ(HISTORY | FAVORITES | PASSWORDS | SEARCH_ENGINES,
+ [controller_ servicesToImport]);
+
+ // Next choice we test is MockCamino.
+ [controller_ setSourceBrowserIndex:2];
+ EXPECT_TRUE([controller_ importHistory]);
+ EXPECT_TRUE([controller_ historyAvailable]);
+ EXPECT_FALSE([controller_ importFavorites]);
+ EXPECT_FALSE([controller_ favoritesAvailable]);
+ EXPECT_FALSE([controller_ importPasswords]);
+ EXPECT_FALSE([controller_ passwordsAvailable]);
+ EXPECT_TRUE([controller_ importSearchEngines]);
+ EXPECT_TRUE([controller_ searchEnginesAvailable]);
+ EXPECT_EQ(HISTORY | SEARCH_ENGINES, [controller_ servicesToImport]);
+
+ // Next choice we test is MockFirefox.
+ [controller_ setSourceBrowserIndex:1];
+ EXPECT_TRUE([controller_ importHistory]);
+ EXPECT_TRUE([controller_ historyAvailable]);
+ EXPECT_TRUE([controller_ importFavorites]);
+ EXPECT_TRUE([controller_ favoritesAvailable]);
+ EXPECT_TRUE([controller_ importPasswords]);
+ EXPECT_TRUE([controller_ passwordsAvailable]);
+ EXPECT_FALSE([controller_ importSearchEngines]);
+ EXPECT_FALSE([controller_ searchEnginesAvailable]);
+ EXPECT_EQ(HISTORY | FAVORITES | PASSWORDS, [controller_ servicesToImport]);
+
+ [controller_ cancel:nil];
+}
+
+TEST_F(ImportSettingsDialogTest, SetVariousSettings) {
+ // Leave the choice MockSafari, but toggle the settings.
+ [controller_ setImportHistory:NO];
+ [controller_ setImportFavorites:NO];
+ [controller_ setImportPasswords:NO];
+ [controller_ setImportSearchEngines:NO];
+ EXPECT_EQ(NONE, [controller_ servicesToImport]);
+ EXPECT_FALSE([controller_ importSomething]);
+
+ [controller_ setImportHistory:YES];
+ EXPECT_EQ(HISTORY, [controller_ servicesToImport]);
+ EXPECT_TRUE([controller_ importSomething]);
+
+ [controller_ setImportHistory:NO];
+ [controller_ setImportFavorites:YES];
+ EXPECT_EQ(FAVORITES, [controller_ servicesToImport]);
+ EXPECT_TRUE([controller_ importSomething]);
+ [controller_ setImportFavorites:NO];
+
+ [controller_ setImportPasswords:YES];
+ EXPECT_EQ(PASSWORDS, [controller_ servicesToImport]);
+ EXPECT_TRUE([controller_ importSomething]);
+
+ [controller_ setImportPasswords:NO];
+ [controller_ setImportSearchEngines:YES];
+ EXPECT_EQ(SEARCH_ENGINES, [controller_ servicesToImport]);
+ EXPECT_TRUE([controller_ importSomething]);
+
+ [controller_ cancel:nil];
+}
diff --git a/chrome/browser/ui/cocoa/importer_lock_dialog.h b/chrome/browser/ui/cocoa/importer_lock_dialog.h
new file mode 100644
index 0000000..ade74e2
--- /dev/null
+++ b/chrome/browser/ui/cocoa/importer_lock_dialog.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_IMPORTER_LOCK_DIALOG_H_
+#define CHROME_BROWSER_UI_COCOA_IMPORTER_LOCK_DIALOG_H_
+#pragma once
+
+class ImporterHost;
+
+namespace ImportLockDialogCocoa {
+
+// This function is called by an ImporterHost, and displays the Firefox profile
+// locked warning by creating a modal NSAlert. On the closing of the alert
+// box, the ImportHost receives a callback with the message either to skip the
+// import, or to try again.
+void ShowWarning(ImporterHost* importer);
+
+}
+
+#endif // CHROME_BROWSER_UI_COCOA_IMPORTER_LOCK_DIALOG_H_
diff --git a/chrome/browser/cocoa/importer_lock_dialog.mm b/chrome/browser/ui/cocoa/importer_lock_dialog.mm
index cc94ce5..cc94ce5 100644
--- a/chrome/browser/cocoa/importer_lock_dialog.mm
+++ b/chrome/browser/ui/cocoa/importer_lock_dialog.mm
diff --git a/chrome/browser/ui/cocoa/info_bubble_view.h b/chrome/browser/ui/cocoa/info_bubble_view.h
new file mode 100644
index 0000000..e1238d2
--- /dev/null
+++ b/chrome/browser/ui/cocoa/info_bubble_view.h
@@ -0,0 +1,39 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_INFO_BUBBLE_VIEW_H_
+#define CHROME_BROWSER_UI_COCOA_INFO_BUBBLE_VIEW_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+namespace info_bubble {
+
+const CGFloat kBubbleArrowHeight = 8.0;
+const CGFloat kBubbleArrowWidth = 15.0;
+const CGFloat kBubbleCornerRadius = 8.0;
+const CGFloat kBubbleArrowXOffset = kBubbleArrowWidth + kBubbleCornerRadius;
+
+enum BubbleArrowLocation {
+ kTopLeft,
+ kTopRight,
+};
+
+} // namespace info_bubble
+
+// Content view for a bubble with an arrow showing arbitrary content.
+// This is where nonrectangular drawing happens.
+@interface InfoBubbleView : NSView {
+ @private
+ info_bubble::BubbleArrowLocation arrowLocation_;
+}
+
+@property (assign, nonatomic) info_bubble::BubbleArrowLocation arrowLocation;
+
+// Returns the point location in view coordinates of the tip of the arrow.
+- (NSPoint)arrowTip;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_INFO_BUBBLE_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/info_bubble_view.mm b/chrome/browser/ui/cocoa/info_bubble_view.mm
new file mode 100644
index 0000000..209857a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/info_bubble_view.mm
@@ -0,0 +1,72 @@
+// 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 "chrome/browser/ui/cocoa/info_bubble_view.h"
+
+#include "base/logging.h"
+#include "base/scoped_nsobject.h"
+
+@implementation InfoBubbleView
+
+@synthesize arrowLocation = arrowLocation_;
+
+- (id)initWithFrame:(NSRect)frameRect {
+ if ((self = [super initWithFrame:frameRect])) {
+ arrowLocation_ = info_bubble::kTopLeft;
+ }
+ return self;
+}
+
+- (void)drawRect:(NSRect)rect {
+ // Make room for the border to be seen.
+ NSRect bounds = [self bounds];
+ bounds.size.height -= info_bubble::kBubbleArrowHeight;
+ NSBezierPath* bezier = [NSBezierPath bezierPath];
+ rect.size.height -= info_bubble::kBubbleArrowHeight;
+
+ // Start with a rounded rectangle.
+ [bezier appendBezierPathWithRoundedRect:bounds
+ xRadius:info_bubble::kBubbleCornerRadius
+ yRadius:info_bubble::kBubbleCornerRadius];
+
+ // Add the bubble arrow.
+ CGFloat dX = 0;
+ switch (arrowLocation_) {
+ case info_bubble::kTopLeft:
+ dX = info_bubble::kBubbleArrowXOffset;
+ break;
+ case info_bubble::kTopRight:
+ dX = NSWidth(bounds) - info_bubble::kBubbleArrowXOffset -
+ info_bubble::kBubbleArrowWidth;
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ NSPoint arrowStart = NSMakePoint(NSMinX(bounds), NSMaxY(bounds));
+ arrowStart.x += dX;
+ [bezier moveToPoint:NSMakePoint(arrowStart.x, arrowStart.y)];
+ [bezier lineToPoint:NSMakePoint(arrowStart.x +
+ info_bubble::kBubbleArrowWidth / 2.0,
+ arrowStart.y +
+ info_bubble::kBubbleArrowHeight)];
+ [bezier lineToPoint:NSMakePoint(arrowStart.x + info_bubble::kBubbleArrowWidth,
+ arrowStart.y)];
+ [bezier closePath];
+ [[NSColor whiteColor] set];
+ [bezier fill];
+}
+
+- (NSPoint)arrowTip {
+ NSRect bounds = [self bounds];
+ CGFloat tipXOffset =
+ info_bubble::kBubbleArrowXOffset + info_bubble::kBubbleArrowWidth / 2.0;
+ CGFloat xOffset =
+ (arrowLocation_ == info_bubble::kTopRight) ? NSMaxX(bounds) - tipXOffset :
+ NSMinX(bounds) + tipXOffset;
+ NSPoint arrowTip = NSMakePoint(xOffset, NSMaxY(bounds));
+ return arrowTip;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/info_bubble_view_unittest.mm b/chrome/browser/ui/cocoa/info_bubble_view_unittest.mm
new file mode 100644
index 0000000..c3c438d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/info_bubble_view_unittest.mm
@@ -0,0 +1,26 @@
+// Copyright (c) 2009 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/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/info_bubble_view.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+
+namespace {
+
+class InfoBubbleViewTest : public CocoaTest {
+ public:
+ InfoBubbleViewTest() {
+ NSRect frame = NSMakeRect(0, 0, 100, 30);
+ scoped_nsobject<InfoBubbleView> view(
+ [[InfoBubbleView alloc] initWithFrame:frame]);
+ view_ = view.get();
+ [[test_window() contentView] addSubview:view_];
+ }
+
+ InfoBubbleView* view_;
+};
+
+TEST_VIEW(InfoBubbleViewTest, view_);
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/info_bubble_window.h b/chrome/browser/ui/cocoa/info_bubble_window.h
new file mode 100644
index 0000000..38ae44d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/info_bubble_window.h
@@ -0,0 +1,32 @@
+// 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 "base/scoped_ptr.h"
+#import "chrome/browser/ui/cocoa/chrome_event_processing_window.h"
+
+class AppNotificationBridge;
+
+// A rounded window with an arrow used for example when you click on the STAR
+// button or that pops up within our first-run UI.
+@interface InfoBubbleWindow : ChromeEventProcessingWindow {
+ @private
+ // Is self in the process of closing.
+ BOOL closing_;
+ // If NO the window will close immediately instead of fading out.
+ // Default YES.
+ BOOL delayOnClose_;
+ // Bridge to proxy Chrome notifications to the window.
+ scoped_ptr<AppNotificationBridge> notificationBridge_;
+}
+
+// Returns YES if the window is in the process of closing.
+// Can't use "windowWillClose" notification because that will be sent
+// after the closing animation has completed.
+- (BOOL)isClosing;
+
+@property (nonatomic) BOOL delayOnClose;
+
+@end
diff --git a/chrome/browser/ui/cocoa/info_bubble_window.mm b/chrome/browser/ui/cocoa/info_bubble_window.mm
new file mode 100644
index 0000000..183cf8a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/info_bubble_window.mm
@@ -0,0 +1,222 @@
+// 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 "chrome/browser/ui/cocoa/info_bubble_window.h"
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/scoped_nsobject.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
+#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
+
+namespace {
+const CGFloat kOrderInSlideOffset = 10;
+const NSTimeInterval kOrderInAnimationDuration = 0.2;
+const NSTimeInterval kOrderOutAnimationDuration = 0.15;
+// The minimum representable time interval. This can be used as the value
+// passed to +[NSAnimationContext setDuration:] to stop an in-progress
+// animation as quickly as possible.
+const NSTimeInterval kMinimumTimeInterval =
+ std::numeric_limits<NSTimeInterval>::min();
+}
+
+@interface InfoBubbleWindow(Private)
+- (void)appIsTerminating;
+- (void)finishCloseAfterAnimation;
+@end
+
+// A helper class to proxy app notifications to the window.
+class AppNotificationBridge : public NotificationObserver {
+ public:
+ explicit AppNotificationBridge(InfoBubbleWindow* owner) : owner_(owner) {
+ registrar_.Add(this, NotificationType::APP_TERMINATING,
+ NotificationService::AllSources());
+ }
+
+ // Overridden from NotificationObserver.
+ void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ switch (type.value) {
+ case NotificationType::APP_TERMINATING:
+ [owner_ appIsTerminating];
+ break;
+ default:
+ NOTREACHED() << L"Unexpected notification";
+ }
+ }
+
+ private:
+ // The object we need to inform when we get a notification. Weak. Owns us.
+ InfoBubbleWindow* owner_;
+
+ // Used for registering to receive notifications and automatic clean up.
+ NotificationRegistrar registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(AppNotificationBridge);
+};
+
+// A delegate object for watching the alphaValue animation on InfoBubbleWindows.
+// An InfoBubbleWindow instance cannot be the delegate for its own animation
+// because CAAnimations retain their delegates, and since the InfoBubbleWindow
+// retains its animations a retain loop would be formed.
+@interface InfoBubbleWindowCloser : NSObject {
+ @private
+ InfoBubbleWindow* window_; // Weak. Window to close.
+}
+- (id)initWithWindow:(InfoBubbleWindow*)window;
+@end
+
+@implementation InfoBubbleWindowCloser
+
+- (id)initWithWindow:(InfoBubbleWindow*)window {
+ if ((self = [super init])) {
+ window_ = window;
+ }
+ return self;
+}
+
+// Callback for the alpha animation. Closes window_ if appropriate.
+- (void)animationDidStop:(CAAnimation*)anim finished:(BOOL)flag {
+ // When alpha reaches zero, close window_.
+ if ([window_ alphaValue] == 0.0) {
+ [window_ finishCloseAfterAnimation];
+ }
+}
+
+@end
+
+
+@implementation InfoBubbleWindow
+
+@synthesize delayOnClose = delayOnClose_;
+
+- (id)initWithContentRect:(NSRect)contentRect
+ styleMask:(NSUInteger)aStyle
+ backing:(NSBackingStoreType)bufferingType
+ defer:(BOOL)flag {
+ if ((self = [super initWithContentRect:contentRect
+ styleMask:NSBorderlessWindowMask
+ backing:bufferingType
+ defer:flag])) {
+ [self setBackgroundColor:[NSColor clearColor]];
+ [self setExcludedFromWindowsMenu:YES];
+ [self setOpaque:NO];
+ [self setHasShadow:YES];
+ delayOnClose_ = YES;
+ notificationBridge_.reset(new AppNotificationBridge(self));
+
+ // Start invisible. Will be made visible when ordered front.
+ [self setAlphaValue:0.0];
+
+ // Set up alphaValue animation so that self is delegate for the animation.
+ // Setting up the delegate is required so that the
+ // animationDidStop:finished: callback can be handled.
+ // Notice that only the alphaValue Animation is replaced in case
+ // superclasses set up animations.
+ CAAnimation* alphaAnimation = [CABasicAnimation animation];
+ scoped_nsobject<InfoBubbleWindowCloser> delegate(
+ [[InfoBubbleWindowCloser alloc] initWithWindow:self]);
+ [alphaAnimation setDelegate:delegate];
+ NSMutableDictionary* animations =
+ [NSMutableDictionary dictionaryWithDictionary:[self animations]];
+ [animations setObject:alphaAnimation forKey:@"alphaValue"];
+ [self setAnimations:animations];
+ }
+ return self;
+}
+
+// According to
+// http://www.cocoabuilder.com/archive/message/cocoa/2006/6/19/165953,
+// NSBorderlessWindowMask windows cannot become key or main. In this
+// case, this is not a desired behavior. As an example, the bubble could have
+// buttons.
+- (BOOL)canBecomeKeyWindow {
+ return YES;
+}
+
+- (void)close {
+ // Block the window from receiving events while it fades out.
+ closing_ = YES;
+
+ if (!delayOnClose_) {
+ [self finishCloseAfterAnimation];
+ } else {
+ // Apply animations to hide self.
+ [NSAnimationContext beginGrouping];
+ [[NSAnimationContext currentContext]
+ gtm_setDuration:kOrderOutAnimationDuration
+ eventMask:NSLeftMouseUpMask];
+ [[self animator] setAlphaValue:0.0];
+ [NSAnimationContext endGrouping];
+ }
+}
+
+// If the app is terminating but the window is still fading out, cancel the
+// animation and close the window to prevent it from leaking.
+// See http://crbug.com/37717
+- (void)appIsTerminating {
+ if (!delayOnClose_)
+ return; // The close has already happened with no Core Animation.
+
+ // Cancel the current animation so that it closes immediately, triggering
+ // |finishCloseAfterAnimation|.
+ [NSAnimationContext beginGrouping];
+ [[NSAnimationContext currentContext] setDuration:kMinimumTimeInterval];
+ [[self animator] setAlphaValue:0.0];
+ [NSAnimationContext endGrouping];
+}
+
+// Called by InfoBubbleWindowCloser when the window is to be really closed
+// after the fading animation is complete.
+- (void)finishCloseAfterAnimation {
+ if (closing_)
+ [super close];
+}
+
+// Adds animation for info bubbles being ordered to the front.
+- (void)orderWindow:(NSWindowOrderingMode)orderingMode
+ relativeTo:(NSInteger)otherWindowNumber {
+ // According to the documentation '0' is the otherWindowNumber when the window
+ // is ordered front.
+ if (orderingMode == NSWindowAbove && otherWindowNumber == 0) {
+ // Order self appropriately assuming that its alpha is zero as set up
+ // in the designated initializer.
+ [super orderWindow:orderingMode relativeTo:otherWindowNumber];
+
+ // Set up frame so it can be adjust down by a few pixels.
+ NSRect frame = [self frame];
+ NSPoint newOrigin = frame.origin;
+ newOrigin.y += kOrderInSlideOffset;
+ [self setFrameOrigin:newOrigin];
+
+ // Apply animations to show and move self.
+ [NSAnimationContext beginGrouping];
+ // The star currently triggers on mouse down, not mouse up.
+ [[NSAnimationContext currentContext]
+ gtm_setDuration:kOrderInAnimationDuration
+ eventMask:NSLeftMouseUpMask|NSLeftMouseDownMask];
+ [[self animator] setAlphaValue:1.0];
+ [[self animator] setFrame:frame display:YES];
+ [NSAnimationContext endGrouping];
+ } else {
+ [super orderWindow:orderingMode relativeTo:otherWindowNumber];
+ }
+}
+
+// If the window is currently animating a close, block all UI events to the
+// window.
+- (void)sendEvent:(NSEvent*)theEvent {
+ if (!closing_)
+ [super sendEvent:theEvent];
+}
+
+- (BOOL)isClosing {
+ return closing_;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/info_bubble_window_unittest.mm b/chrome/browser/ui/cocoa/info_bubble_window_unittest.mm
new file mode 100644
index 0000000..aed5c0a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/info_bubble_window_unittest.mm
@@ -0,0 +1,22 @@
+// Copyright (c) 2009 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/scoped_ptr.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/info_bubble_window.h"
+
+class InfoBubbleWindowTest : public CocoaTest {};
+
+TEST_F(InfoBubbleWindowTest, Basics) {
+ InfoBubbleWindow* window =
+ [[InfoBubbleWindow alloc] initWithContentRect:NSMakeRect(0, 0, 10, 10)
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO];
+ EXPECT_TRUE([window canBecomeKeyWindow]);
+ EXPECT_FALSE([window canBecomeMainWindow]);
+
+ EXPECT_TRUE([window isExcludedFromWindowsMenu]);
+ [window close];
+}
diff --git a/chrome/browser/ui/cocoa/infobar.h b/chrome/browser/ui/cocoa/infobar.h
new file mode 100644
index 0000000..fc51da7
--- /dev/null
+++ b/chrome/browser/ui/cocoa/infobar.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_INFOBAR_H_
+#define CHROME_BROWSER_UI_COCOA_INFOBAR_H_
+#pragma once
+
+#include "base/logging.h" // for DCHECK
+
+@class InfoBarController;
+
+// A C++ wrapper around an Objective-C InfoBarController. This class
+// exists solely to be the return value for InfoBarDelegate::CreateInfoBar(),
+// as defined in chrome/browser/tab_contents/infobar_delegate.h. This
+// class would be analogous to the various bridge classes we already
+// have, but since there is no pre-defined InfoBar interface, it is
+// easier to simply throw away this object and deal with the
+// controller directly rather than pass messages through a bridge.
+//
+// Callers should delete the returned InfoBar immediately after
+// calling CreateInfoBar(), as the returned InfoBar* object is not
+// pointed to by anyone. Expected usage:
+//
+// scoped_ptr<InfoBar> infobar(delegate->CreateInfoBar());
+// InfoBarController* controller = infobar->controller();
+// // Do something with the controller, and save a pointer so it can be
+// // deleted later. |infobar| will be deleted automatically.
+
+class InfoBar {
+ public:
+ InfoBar(InfoBarController* controller) {
+ DCHECK(controller);
+ controller_ = controller;
+ }
+
+ InfoBarController* controller() {
+ return controller_;
+ }
+
+ private:
+ // Pointer to the infobar controller. Is never null.
+ InfoBarController* controller_; // weak
+
+ DISALLOW_COPY_AND_ASSIGN(InfoBar);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_INFOBAR_H_
diff --git a/chrome/browser/ui/cocoa/infobar_container_controller.h b/chrome/browser/ui/cocoa/infobar_container_controller.h
new file mode 100644
index 0000000..82a7e52
--- /dev/null
+++ b/chrome/browser/ui/cocoa/infobar_container_controller.h
@@ -0,0 +1,113 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_INFOBAR_CONTAINER_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_INFOBAR_CONTAINER_CONTROLLER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+#import "chrome/browser/ui/cocoa/view_resizer.h"
+#include "chrome/common/notification_registrar.h"
+
+@class InfoBarController;
+class InfoBarDelegate;
+class InfoBarNotificationObserver;
+class TabContents;
+class TabStripModel;
+
+// Protocol for basic container methods, as needed by an InfoBarController.
+// This protocol exists to make mocking easier in unittests.
+@protocol InfoBarContainer
+- (void)removeDelegate:(InfoBarDelegate*)delegate;
+- (void)removeController:(InfoBarController*)controller;
+@end
+
+// Controller for the infobar container view, which is the superview
+// of all the infobar views. This class owns zero or more
+// InfoBarControllers, which manage the infobar views. This class
+// also receives tab strip model notifications and handles
+// adding/removing infobars when needed.
+@interface InfoBarContainerController : NSViewController <ViewResizer,
+ InfoBarContainer> {
+ @private
+ // Needed to send resize messages when infobars are added or removed.
+ id<ViewResizer> resizeDelegate_; // weak
+
+ // The TabContents we are currently showing infobars for.
+ TabContents* currentTabContents_; // weak
+
+ // Holds the InfoBarControllers currently owned by this container.
+ scoped_nsobject<NSMutableArray> infobarControllers_;
+
+ // Lets us registers for INFOBAR_ADDED/INFOBAR_REMOVED
+ // notifications. The actual notifications are sent to the
+ // InfoBarNotificationObserver object, which proxies them back to us.
+ NotificationRegistrar registrar_;
+ scoped_ptr<InfoBarNotificationObserver> infoBarObserver_;
+}
+
+- (id)initWithResizeDelegate:(id<ViewResizer>)resizeDelegate;
+
+// Informs the selected TabContents that the infobars for the given
+// |delegate| need to be removed. Does not remove any infobar views
+// directly, as they will be removed when handling the subsequent
+// INFOBAR_REMOVED notification. Does not notify |delegate| that the
+// infobar was closed.
+- (void)removeDelegate:(InfoBarDelegate*)delegate;
+
+// Removes |controller| from the list of controllers in this container and
+// removes its view from the view hierarchy. This method is safe to call while
+// |controller| is still on the call stack.
+- (void)removeController:(InfoBarController*)controller;
+
+// Modifies this container to display infobars for the given
+// |contents|. Registers for INFOBAR_ADDED and INFOBAR_REMOVED
+// notifications for |contents|. If we are currently showing any
+// infobars, removes them first and deregisters for any
+// notifications. |contents| can be NULL, in which case no infobars
+// are shown and no notifications are registered for.
+- (void)changeTabContents:(TabContents*)contents;
+
+// Stripped down version of TabStripModelObserverBridge:tabDetachedWithContents.
+// Forwarded by BWC. Removes all infobars and deregisters for any notifications
+// if |contents| is the current tab contents.
+- (void)tabDetachedWithContents:(TabContents*)contents;
+
+@end
+
+
+@interface InfoBarContainerController (ForTheObserverAndTesting)
+
+// Adds an infobar view for the given delegate.
+- (void)addInfoBar:(InfoBarDelegate*)delegate animate:(BOOL)animate;
+
+// Closes all the infobar views for a given delegate, either immediately or by
+// starting a close animation.
+- (void)closeInfoBarsForDelegate:(InfoBarDelegate*)delegate
+ animate:(BOOL)animate;
+
+// Replaces all info bars for the delegate with a new info bar.
+// This simply calls closeInfoBarsForDelegate: and then addInfoBar:.
+- (void)replaceInfoBarsForDelegate:(InfoBarDelegate*)old_delegate
+ with:(InfoBarDelegate*)new_delegate;
+
+// Positions the infobar views in the container view and notifies
+// |browser_controller_| that it needs to resize the container view.
+- (void)positionInfoBarsAndRedraw;
+
+@end
+
+
+@interface InfoBarContainerController (JustForTesting)
+
+// Removes all infobar views. Callers must call
+// positionInfoBarsAndRedraw() after calling this method.
+- (void)removeAllInfoBars;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_INFOBAR_CONTAINER_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/infobar_container_controller.mm b/chrome/browser/ui/cocoa/infobar_container_controller.mm
new file mode 100644
index 0000000..adca3e7
--- /dev/null
+++ b/chrome/browser/ui/cocoa/infobar_container_controller.mm
@@ -0,0 +1,229 @@
+// 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.
+
+#include "base/logging.h"
+#include "base/mac_util.h"
+#include "chrome/browser/tab_contents/infobar_delegate.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#import "chrome/browser/ui/cocoa/animatable_view.h"
+#include "chrome/browser/ui/cocoa/infobar.h"
+#import "chrome/browser/ui/cocoa/infobar_container_controller.h"
+#import "chrome/browser/ui/cocoa/infobar_controller.h"
+#import "chrome/browser/ui/cocoa/view_id_util.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
+#include "skia/ext/skia_utils_mac.h"
+
+// C++ class that receives INFOBAR_ADDED and INFOBAR_REMOVED
+// notifications and proxies them back to |controller|.
+class InfoBarNotificationObserver : public NotificationObserver {
+ public:
+ InfoBarNotificationObserver(InfoBarContainerController* controller)
+ : controller_(controller) {
+ }
+
+ private:
+ // NotificationObserver implementation
+ void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ switch (type.value) {
+ case NotificationType::TAB_CONTENTS_INFOBAR_ADDED:
+ [controller_ addInfoBar:Details<InfoBarDelegate>(details).ptr()
+ animate:YES];
+ break;
+ case NotificationType::TAB_CONTENTS_INFOBAR_REMOVED:
+ [controller_
+ closeInfoBarsForDelegate:Details<InfoBarDelegate>(details).ptr()
+ animate:YES];
+ break;
+ case NotificationType::TAB_CONTENTS_INFOBAR_REPLACED: {
+ typedef std::pair<InfoBarDelegate*, InfoBarDelegate*>
+ InfoBarDelegatePair;
+ InfoBarDelegatePair* delegates =
+ Details<InfoBarDelegatePair>(details).ptr();
+ [controller_
+ replaceInfoBarsForDelegate:delegates->first with:delegates->second];
+ break;
+ }
+ default:
+ NOTREACHED(); // we don't ask for anything else!
+ break;
+ }
+
+ [controller_ positionInfoBarsAndRedraw];
+ }
+
+ InfoBarContainerController* controller_; // weak, owns us.
+};
+
+
+@interface InfoBarContainerController (PrivateMethods)
+// Returns the desired height of the container view, computed by
+// adding together the heights of all its subviews.
+- (CGFloat)desiredHeight;
+
+@end
+
+
+@implementation InfoBarContainerController
+- (id)initWithResizeDelegate:(id<ViewResizer>)resizeDelegate {
+ DCHECK(resizeDelegate);
+ if ((self = [super initWithNibName:@"InfoBarContainer"
+ bundle:mac_util::MainAppBundle()])) {
+ resizeDelegate_ = resizeDelegate;
+ infoBarObserver_.reset(new InfoBarNotificationObserver(self));
+
+ // NSMutableArray needs an initial capacity, and we rarely ever see
+ // more than two infobars at a time, so that seems like a good choice.
+ infobarControllers_.reset([[NSMutableArray alloc] initWithCapacity:2]);
+ }
+ return self;
+}
+
+- (void)dealloc {
+ DCHECK([infobarControllers_ count] == 0);
+ view_id_util::UnsetID([self view]);
+ [super dealloc];
+}
+
+- (void)awakeFromNib {
+ // The info bar container view is an ordinary NSView object, so we set its
+ // ViewID here.
+ view_id_util::SetID([self view], VIEW_ID_INFO_BAR_CONTAINER);
+}
+
+- (void)removeDelegate:(InfoBarDelegate*)delegate {
+ DCHECK(currentTabContents_);
+ currentTabContents_->RemoveInfoBar(delegate);
+}
+
+- (void)removeController:(InfoBarController*)controller {
+ if (![infobarControllers_ containsObject:controller])
+ return;
+
+ // This code can be executed while InfoBarController is still on the stack, so
+ // we retain and autorelease the controller to prevent it from being
+ // dealloc'ed too early.
+ [[controller retain] autorelease];
+ [[controller view] removeFromSuperview];
+ [infobarControllers_ removeObject:controller];
+ [self positionInfoBarsAndRedraw];
+}
+
+- (void)changeTabContents:(TabContents*)contents {
+ registrar_.RemoveAll();
+ [self removeAllInfoBars];
+
+ currentTabContents_ = contents;
+ if (currentTabContents_) {
+ for (int i = 0; i < currentTabContents_->infobar_delegate_count(); ++i) {
+ [self addInfoBar:currentTabContents_->GetInfoBarDelegateAt(i)
+ animate:NO];
+ }
+
+ Source<TabContents> source(currentTabContents_);
+ registrar_.Add(infoBarObserver_.get(),
+ NotificationType::TAB_CONTENTS_INFOBAR_ADDED, source);
+ registrar_.Add(infoBarObserver_.get(),
+ NotificationType::TAB_CONTENTS_INFOBAR_REMOVED, source);
+ registrar_.Add(infoBarObserver_.get(),
+ NotificationType::TAB_CONTENTS_INFOBAR_REPLACED, source);
+ }
+
+ [self positionInfoBarsAndRedraw];
+}
+
+- (void)tabDetachedWithContents:(TabContents*)contents {
+ if (currentTabContents_ == contents)
+ [self changeTabContents:NULL];
+}
+
+- (void)resizeView:(NSView*)view newHeight:(CGFloat)height {
+ NSRect frame = [view frame];
+ frame.size.height = height;
+ [view setFrame:frame];
+ [self positionInfoBarsAndRedraw];
+}
+
+- (void)setAnimationInProgress:(BOOL)inProgress {
+ if ([resizeDelegate_ respondsToSelector:@selector(setAnimationInProgress:)])
+ [resizeDelegate_ setAnimationInProgress:inProgress];
+}
+
+@end
+
+@implementation InfoBarContainerController (PrivateMethods)
+
+- (CGFloat)desiredHeight {
+ CGFloat height = 0;
+ for (InfoBarController* controller in infobarControllers_.get())
+ height += NSHeight([[controller view] frame]);
+ return height;
+}
+
+- (void)addInfoBar:(InfoBarDelegate*)delegate animate:(BOOL)animate {
+ scoped_ptr<InfoBar> infobar(delegate->CreateInfoBar());
+ InfoBarController* controller = infobar->controller();
+ [controller setContainerController:self];
+ [[controller animatableView] setResizeDelegate:self];
+ [[self view] addSubview:[controller view]];
+ [infobarControllers_ addObject:[controller autorelease]];
+
+ if (animate)
+ [controller animateOpen];
+ else
+ [controller open];
+}
+
+- (void)closeInfoBarsForDelegate:(InfoBarDelegate*)delegate
+ animate:(BOOL)animate {
+ for (InfoBarController* controller in
+ [NSArray arrayWithArray:infobarControllers_.get()]) {
+ if ([controller delegate] == delegate) {
+ if (animate)
+ [controller animateClosed];
+ else
+ [controller close];
+ }
+ }
+}
+
+- (void)replaceInfoBarsForDelegate:(InfoBarDelegate*)old_delegate
+ with:(InfoBarDelegate*)new_delegate {
+ [self closeInfoBarsForDelegate:old_delegate animate:NO];
+ [self addInfoBar:new_delegate animate:NO];
+}
+
+- (void)removeAllInfoBars {
+ for (InfoBarController* controller in infobarControllers_.get()) {
+ [[controller animatableView] stopAnimation];
+ [[controller view] removeFromSuperview];
+ }
+ [infobarControllers_ removeAllObjects];
+}
+
+- (void)positionInfoBarsAndRedraw {
+ NSRect containerBounds = [[self view] bounds];
+ int minY = 0;
+
+ // Stack the infobars at the bottom of the view, starting with the
+ // last infobar and working our way to the front of the array. This
+ // way we ensure that the first infobar added shows up on top, with
+ // the others below.
+ for (InfoBarController* controller in
+ [infobarControllers_ reverseObjectEnumerator]) {
+ NSView* view = [controller view];
+ NSRect frame = [view frame];
+ frame.origin.x = NSMinX(containerBounds);
+ frame.size.width = NSWidth(containerBounds);
+ frame.origin.y = minY;
+ minY += frame.size.height;
+ [view setFrame:frame];
+ }
+
+ [resizeDelegate_ resizeView:[self view] newHeight:[self desiredHeight]];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/infobar_container_controller_unittest.mm b/chrome/browser/ui/cocoa/infobar_container_controller_unittest.mm
new file mode 100644
index 0000000..f04b1c1
--- /dev/null
+++ b/chrome/browser/ui/cocoa/infobar_container_controller_unittest.mm
@@ -0,0 +1,95 @@
+// Copyright (c) 2009 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 "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/infobar_container_controller.h"
+#include "chrome/browser/ui/cocoa/infobar_test_helper.h"
+#import "chrome/browser/ui/cocoa/view_resizer_pong.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class InfoBarContainerControllerTest : public CocoaTest {
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ resizeDelegate_.reset([[ViewResizerPong alloc] init]);
+ ViewResizerPong *viewResizer = resizeDelegate_.get();
+ controller_ =
+ [[InfoBarContainerController alloc] initWithResizeDelegate:viewResizer];
+ NSView* view = [controller_ view];
+ [[test_window() contentView] addSubview:view];
+ }
+
+ virtual void TearDown() {
+ [[controller_ view] removeFromSuperviewWithoutNeedingDisplay];
+ [controller_ release];
+ CocoaTest::TearDown();
+ }
+
+ public:
+ scoped_nsobject<ViewResizerPong> resizeDelegate_;
+ InfoBarContainerController* controller_;
+};
+
+TEST_VIEW(InfoBarContainerControllerTest, [controller_ view])
+
+TEST_F(InfoBarContainerControllerTest, BWCPong) {
+ // Call positionInfoBarsAndResize and check that |resizeDelegate_| got a
+ // resize message.
+ [resizeDelegate_ setHeight:-1];
+ [controller_ positionInfoBarsAndRedraw];
+ EXPECT_NE(-1, [resizeDelegate_ height]);
+}
+
+TEST_F(InfoBarContainerControllerTest, AddAndRemoveInfoBars) {
+ NSView* view = [controller_ view];
+
+ // Add three infobars, one of each type, and then remove them.
+ // After each step check to make sure we have the correct number of
+ // infobar subviews.
+ MockAlertInfoBarDelegate alertDelegate;
+ MockLinkInfoBarDelegate linkDelegate;
+ MockConfirmInfoBarDelegate confirmDelegate;
+
+ [controller_ addInfoBar:&alertDelegate animate:NO];
+ EXPECT_EQ(1U, [[view subviews] count]);
+
+ [controller_ addInfoBar:&linkDelegate animate:NO];
+ EXPECT_EQ(2U, [[view subviews] count]);
+
+ [controller_ addInfoBar:&confirmDelegate animate:NO];
+ EXPECT_EQ(3U, [[view subviews] count]);
+
+ // Just to mix things up, remove them in a different order.
+ [controller_ closeInfoBarsForDelegate:&linkDelegate animate:NO];
+ EXPECT_EQ(2U, [[view subviews] count]);
+
+ [controller_ closeInfoBarsForDelegate:&confirmDelegate animate:NO];
+ EXPECT_EQ(1U, [[view subviews] count]);
+
+ [controller_ closeInfoBarsForDelegate:&alertDelegate animate:NO];
+ EXPECT_EQ(0U, [[view subviews] count]);
+}
+
+TEST_F(InfoBarContainerControllerTest, RemoveAllInfoBars) {
+ NSView* view = [controller_ view];
+
+ // Add three infobars and then remove them all.
+ MockAlertInfoBarDelegate alertDelegate;
+ MockLinkInfoBarDelegate linkDelegate;
+ MockConfirmInfoBarDelegate confirmDelegate;
+
+ [controller_ addInfoBar:&alertDelegate animate:NO];
+ [controller_ addInfoBar:&linkDelegate animate:NO];
+ [controller_ addInfoBar:&confirmDelegate animate:NO];
+ EXPECT_EQ(3U, [[view subviews] count]);
+
+ [controller_ removeAllInfoBars];
+ EXPECT_EQ(0U, [[view subviews] count]);
+}
+} // namespace
diff --git a/chrome/browser/ui/cocoa/infobar_controller.h b/chrome/browser/ui/cocoa/infobar_controller.h
new file mode 100644
index 0000000..e13d211
--- /dev/null
+++ b/chrome/browser/ui/cocoa/infobar_controller.h
@@ -0,0 +1,106 @@
+// 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>
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_nsobject.h"
+
+@class AnimatableView;
+@class HoverCloseButton;
+@protocol InfoBarContainer;
+class InfoBarDelegate;
+@class InfoBarGradientView;
+
+// A controller for an infobar in the browser window. There is one
+// controller per infobar view. The base InfoBarController is able to
+// draw an icon, a text message, and a close button. Subclasses can
+// override addAdditionalControls to customize the UI.
+@interface InfoBarController : NSViewController<NSTextViewDelegate> {
+ @private
+ id<InfoBarContainer> containerController_; // weak, owns us
+ BOOL infoBarClosing_;
+
+ @protected
+ IBOutlet InfoBarGradientView* infoBarView_;
+ IBOutlet NSImageView* image_;
+ IBOutlet NSTextField* labelPlaceholder_;
+ IBOutlet NSButton* okButton_;
+ IBOutlet NSButton* cancelButton_;
+ IBOutlet HoverCloseButton* closeButton_;
+
+ // In rare instances, it can be possible for |delegate_| to delete itself
+ // while this controller is still alive. Always check |delegate_| against
+ // NULL before using it.
+ InfoBarDelegate* delegate_; // weak, can be NULL
+
+ // Text fields don't work as well with embedded links as text views, but
+ // text views cannot conveniently be created in IB. The xib file contains
+ // a text field |labelPlaceholder_| that's replaced by this text view |label_|
+ // in -awakeFromNib.
+ scoped_nsobject<NSTextView> label_;
+};
+
+// Initializes a new InfoBarController.
+- (id)initWithDelegate:(InfoBarDelegate*)delegate;
+
+// Called when someone clicks on the OK or Cancel buttons. Subclasses
+// must override if they do not hide the buttons.
+- (void)ok:(id)sender;
+- (void)cancel:(id)sender;
+
+// Called when someone clicks on the close button. Dismisses the
+// infobar without taking any action.
+- (IBAction)dismiss:(id)sender;
+
+// Returns a pointer to this controller's view, cast as an AnimatableView.
+- (AnimatableView*)animatableView;
+
+// Open or animate open the infobar.
+- (void)open;
+- (void)animateOpen;
+
+// Close or animate close the infobar.
+- (void)close;
+- (void)animateClosed;
+
+// Subclasses can override this method to add additional controls to
+// the infobar view. This method is called by awakeFromNib. The
+// default implementation does nothing.
+- (void)addAdditionalControls;
+
+// Sets the info bar message to the specified |message|.
+- (void)setLabelToMessage:(NSString*)message;
+
+// Removes the OK and Cancel buttons and resizes the textfield to use the
+// space.
+- (void)removeButtons;
+
+@property(nonatomic, assign) id<InfoBarContainer> containerController;
+@property(nonatomic, readonly) InfoBarDelegate* delegate;
+
+@end
+
+/////////////////////////////////////////////////////////////////////////
+// InfoBarController subclasses, one for each InfoBarDelegate
+// subclass. Each of these subclasses overrides addAdditionalControls to
+// configure its view as necessary.
+
+@interface AlertInfoBarController : InfoBarController
+@end
+
+
+@interface LinkInfoBarController : InfoBarController
+// Called when there is a click on the link in the infobar.
+- (void)linkClicked;
+@end
+
+
+@interface ConfirmInfoBarController : InfoBarController
+// Called when the OK and Cancel buttons are clicked.
+- (IBAction)ok:(id)sender;
+- (IBAction)cancel:(id)sender;
+// Called when there is a click on the link in the infobar.
+- (void)linkClicked;
+@end
diff --git a/chrome/browser/ui/cocoa/infobar_controller.mm b/chrome/browser/ui/cocoa/infobar_controller.mm
new file mode 100644
index 0000000..ae1414c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/infobar_controller.mm
@@ -0,0 +1,533 @@
+// 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 "base/logging.h" // for NOTREACHED()
+#include "base/mac_util.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/tab_contents/infobar_delegate.h"
+#import "chrome/browser/ui/cocoa/animatable_view.h"
+#include "chrome/browser/ui/cocoa/event_utils.h"
+#include "chrome/browser/ui/cocoa/infobar.h"
+#import "chrome/browser/ui/cocoa/infobar_container_controller.h"
+#import "chrome/browser/ui/cocoa/infobar_controller.h"
+#include "skia/ext/skia_utils_mac.h"
+#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
+#include "webkit/glue/window_open_disposition.h"
+
+namespace {
+// Durations set to match the default SlideAnimation duration.
+const float kAnimateOpenDuration = 0.12;
+const float kAnimateCloseDuration = 0.12;
+}
+
+// This simple subclass of |NSTextView| just doesn't show the (text) cursor
+// (|NSTextView| displays the cursor with full keyboard accessibility enabled).
+@interface InfoBarTextView : NSTextView
+- (void)fixupCursor;
+@end
+
+@implementation InfoBarTextView
+
+// Never draw the insertion point (otherwise, it shows up without any user
+// action if full keyboard accessibility is enabled).
+- (BOOL)shouldDrawInsertionPoint {
+ return NO;
+}
+
+- (NSRange)selectionRangeForProposedRange:(NSRange)proposedSelRange
+ granularity:(NSSelectionGranularity)granularity {
+ // Do not allow selections.
+ return NSMakeRange(0, 0);
+}
+
+// Convince NSTextView to not show an I-Beam cursor when the cursor is over the
+// text view but not over actual text.
+//
+// http://www.mail-archive.com/cocoa-dev@lists.apple.com/msg10791.html
+// "NSTextView sets the cursor over itself dynamically, based on considerations
+// including the text under the cursor. It does so in -mouseEntered:,
+// -mouseMoved:, and -cursorUpdate:, so those would be points to consider
+// overriding."
+- (void)mouseMoved:(NSEvent*)e {
+ [super mouseMoved:e];
+ [self fixupCursor];
+}
+
+- (void)mouseEntered:(NSEvent*)e {
+ [super mouseEntered:e];
+ [self fixupCursor];
+}
+
+- (void)cursorUpdate:(NSEvent*)e {
+ [super cursorUpdate:e];
+ [self fixupCursor];
+}
+
+- (void)fixupCursor {
+ if ([[NSCursor currentCursor] isEqual:[NSCursor IBeamCursor]])
+ [[NSCursor arrowCursor] set];
+}
+
+@end
+
+@interface InfoBarController (PrivateMethods)
+// Sets |label_| based on |labelPlaceholder_|, sets |labelPlaceholder_| to nil.
+- (void)initializeLabel;
+
+// Asks the container controller to remove the infobar for this delegate. This
+// call will trigger a notification that starts the infobar animating closed.
+- (void)removeInfoBar;
+
+// Performs final cleanup after an animation is finished or stopped, including
+// notifying the InfoBarDelegate that the infobar was closed and removing the
+// infobar from its container, if necessary.
+- (void)cleanUpAfterAnimation:(BOOL)finished;
+
+// Sets the info bar message to the specified |message|, with a hypertext
+// style link. |link| will be inserted into message at |linkOffset|.
+- (void)setLabelToMessage:(NSString*)message
+ withLink:(NSString*)link
+ atOffset:(NSUInteger)linkOffset;
+@end
+
+@implementation InfoBarController
+
+@synthesize containerController = containerController_;
+@synthesize delegate = delegate_;
+
+- (id)initWithDelegate:(InfoBarDelegate*)delegate {
+ DCHECK(delegate);
+ if ((self = [super initWithNibName:@"InfoBar"
+ bundle:mac_util::MainAppBundle()])) {
+ delegate_ = delegate;
+ }
+ return self;
+}
+
+// All infobars have an icon, so we set up the icon in the base class
+// awakeFromNib.
+- (void)awakeFromNib {
+ DCHECK(delegate_);
+ if (delegate_->GetIcon()) {
+ [image_ setImage:gfx::SkBitmapToNSImage(*(delegate_->GetIcon()))];
+ } else {
+ // No icon, remove it from the view and grow the textfield to include the
+ // space.
+ NSRect imageFrame = [image_ frame];
+ NSRect labelFrame = [labelPlaceholder_ frame];
+ labelFrame.size.width += NSMinX(imageFrame) - NSMinX(labelFrame);
+ labelFrame.origin.x = imageFrame.origin.x;
+ [image_ removeFromSuperview];
+ [labelPlaceholder_ setFrame:labelFrame];
+ }
+ [self initializeLabel];
+
+ [self addAdditionalControls];
+}
+
+// Called when someone clicks on the embedded link.
+- (BOOL) textView:(NSTextView*)textView
+ clickedOnLink:(id)link
+ atIndex:(NSUInteger)charIndex {
+ if ([self respondsToSelector:@selector(linkClicked)])
+ [self performSelector:@selector(linkClicked)];
+ return YES;
+}
+
+// Called when someone clicks on the ok button.
+- (void)ok:(id)sender {
+ // Subclasses must override this method if they do not hide the ok button.
+ NOTREACHED();
+}
+
+// Called when someone clicks on the cancel button.
+- (void)cancel:(id)sender {
+ // Subclasses must override this method if they do not hide the cancel button.
+ NOTREACHED();
+}
+
+// Called when someone clicks on the close button.
+- (void)dismiss:(id)sender {
+ [self removeInfoBar];
+}
+
+- (AnimatableView*)animatableView {
+ return static_cast<AnimatableView*>([self view]);
+}
+
+- (void)open {
+ // Simply reset the frame size to its opened size, forcing a relayout.
+ CGFloat finalHeight = [[self view] frame].size.height;
+ [[self animatableView] setHeight:finalHeight];
+}
+
+- (void)animateOpen {
+ // Force the frame size to be 0 and then start an animation.
+ NSRect frame = [[self view] frame];
+ CGFloat finalHeight = frame.size.height;
+ frame.size.height = 0;
+ [[self view] setFrame:frame];
+ [[self animatableView] animateToNewHeight:finalHeight
+ duration:kAnimateOpenDuration];
+}
+
+- (void)close {
+ // Stop any running animations.
+ [[self animatableView] stopAnimation];
+ infoBarClosing_ = YES;
+ [self cleanUpAfterAnimation:YES];
+}
+
+- (void)animateClosed {
+ // Start animating closed. We will receive a notification when the animation
+ // is done, at which point we can remove our view from the hierarchy and
+ // notify the delegate that the infobar was closed.
+ [[self animatableView] animateToNewHeight:0 duration:kAnimateCloseDuration];
+
+ // The above call may trigger an animationDidStop: notification for any
+ // currently-running animations, so do not set |infoBarClosing_| until after
+ // starting the animation.
+ infoBarClosing_ = YES;
+}
+
+- (void)addAdditionalControls {
+ // Default implementation does nothing.
+}
+
+- (void)setLabelToMessage:(NSString*)message {
+ NSMutableDictionary* attributes = [NSMutableDictionary dictionary];
+ NSFont* font = [NSFont labelFontOfSize:
+ [NSFont systemFontSizeForControlSize:NSRegularControlSize]];
+ [attributes setObject:font
+ forKey:NSFontAttributeName];
+ [attributes setObject:[NSCursor arrowCursor]
+ forKey:NSCursorAttributeName];
+ scoped_nsobject<NSAttributedString> attributedString(
+ [[NSAttributedString alloc] initWithString:message
+ attributes:attributes]);
+ [[label_.get() textStorage] setAttributedString:attributedString];
+}
+
+- (void)removeButtons {
+ // Extend the label all the way across.
+ NSRect labelFrame = [label_.get() frame];
+ labelFrame.size.width = NSMaxX([cancelButton_ frame]) - NSMinX(labelFrame);
+ [okButton_ removeFromSuperview];
+ [cancelButton_ removeFromSuperview];
+ [label_.get() setFrame:labelFrame];
+}
+
+@end
+
+@implementation InfoBarController (PrivateMethods)
+
+- (void)initializeLabel {
+ // Replace the label placeholder NSTextField with the real label NSTextView.
+ // The former doesn't show links in a nice way, but the latter can't be added
+ // in IB without a containing scroll view, so create the NSTextView
+ // programmatically.
+ label_.reset([[InfoBarTextView alloc]
+ initWithFrame:[labelPlaceholder_ frame]]);
+ [label_.get() setAutoresizingMask:[labelPlaceholder_ autoresizingMask]];
+ [[labelPlaceholder_ superview]
+ replaceSubview:labelPlaceholder_ with:label_.get()];
+ labelPlaceholder_ = nil; // Now released.
+ [label_.get() setDelegate:self];
+ [label_.get() setEditable:NO];
+ [label_.get() setDrawsBackground:NO];
+ [label_.get() setHorizontallyResizable:NO];
+ [label_.get() setVerticallyResizable:NO];
+}
+
+- (void)removeInfoBar {
+ // TODO(rohitrao): This method can be called even if the infobar has already
+ // been removed and |delegate_| is NULL. Is there a way to rewrite the code
+ // so that inner event loops don't cause us to try and remove the infobar
+ // twice? http://crbug.com/54253
+ [containerController_ removeDelegate:delegate_];
+}
+
+- (void)cleanUpAfterAnimation:(BOOL)finished {
+ // Don't need to do any cleanup if the bar was animating open.
+ if (!infoBarClosing_)
+ return;
+
+ // Notify the delegate that the infobar was closed. The delegate may delete
+ // itself as a result of InfoBarClosed(), so we null out its pointer.
+ if (delegate_) {
+ delegate_->InfoBarClosed();
+ delegate_ = NULL;
+ }
+
+ // If the animation ran to completion, then we need to remove ourselves from
+ // the container. If the animation was interrupted, then the container will
+ // take care of removing us.
+ // TODO(rohitrao): UGH! This works for now, but should be cleaner.
+ if (finished)
+ [containerController_ removeController:self];
+}
+
+- (void)animationDidStop:(NSAnimation*)animation {
+ [self cleanUpAfterAnimation:NO];
+}
+
+- (void)animationDidEnd:(NSAnimation*)animation {
+ [self cleanUpAfterAnimation:YES];
+}
+
+// TODO(joth): This method factors out some common functionality between the
+// various derived infobar classes, however the class hierarchy itself could
+// use refactoring to reduce this duplication. http://crbug.com/38924
+- (void)setLabelToMessage:(NSString*)message
+ withLink:(NSString*)link
+ atOffset:(NSUInteger)linkOffset {
+ if (linkOffset == std::wstring::npos) {
+ // linkOffset == std::wstring::npos means the link should be right-aligned,
+ // which is not supported on Mac (http://crbug.com/47728).
+ NOTIMPLEMENTED();
+ linkOffset = [message length];
+ }
+ // Create an attributes dictionary for the entire message. We have
+ // to expicitly set the font the control's font. We also override
+ // the cursor to give us the normal cursor rather than the text
+ // insertion cursor.
+ NSMutableDictionary* linkAttributes = [NSMutableDictionary dictionary];
+ [linkAttributes setObject:[NSCursor arrowCursor]
+ forKey:NSCursorAttributeName];
+ NSFont* font = [NSFont labelFontOfSize:
+ [NSFont systemFontSizeForControlSize:NSRegularControlSize]];
+ [linkAttributes setObject:font
+ forKey:NSFontAttributeName];
+
+ // Create the attributed string for the main message text.
+ scoped_nsobject<NSMutableAttributedString> infoText(
+ [[NSMutableAttributedString alloc] initWithString:message]);
+ [infoText.get() addAttributes:linkAttributes
+ range:NSMakeRange(0, [infoText.get() length])];
+ // Add additional attributes to style the link text appropriately as
+ // well as linkify it.
+ [linkAttributes setObject:[NSColor blueColor]
+ forKey:NSForegroundColorAttributeName];
+ [linkAttributes setObject:[NSNumber numberWithBool:YES]
+ forKey:NSUnderlineStyleAttributeName];
+ [linkAttributes setObject:[NSCursor pointingHandCursor]
+ forKey:NSCursorAttributeName];
+ [linkAttributes setObject:[NSNumber numberWithInt:NSSingleUnderlineStyle]
+ forKey:NSUnderlineStyleAttributeName];
+ [linkAttributes setObject:[NSString string] // dummy value
+ forKey:NSLinkAttributeName];
+
+ // Insert the link text into the string at the appropriate offset.
+ scoped_nsobject<NSAttributedString> attributedString(
+ [[NSAttributedString alloc] initWithString:link
+ attributes:linkAttributes]);
+ [infoText.get() insertAttributedString:attributedString.get()
+ atIndex:linkOffset];
+ // Update the label view with the new text.
+ [[label_.get() textStorage] setAttributedString:infoText];
+}
+
+@end
+
+
+/////////////////////////////////////////////////////////////////////////
+// AlertInfoBarController implementation
+
+@implementation AlertInfoBarController
+
+// Alert infobars have a text message.
+- (void)addAdditionalControls {
+ // No buttons.
+ [self removeButtons];
+
+ // Insert the text.
+ AlertInfoBarDelegate* delegate = delegate_->AsAlertInfoBarDelegate();
+ DCHECK(delegate);
+ [self setLabelToMessage:base::SysUTF16ToNSString(delegate->GetMessageText())];
+}
+
+@end
+
+
+/////////////////////////////////////////////////////////////////////////
+// LinkInfoBarController implementation
+
+@implementation LinkInfoBarController
+
+// Link infobars have a text message, of which part is linkified. We
+// use an NSAttributedString to display styled text, and we set a
+// NSLink attribute on the hyperlink portion of the message. Infobars
+// use a custom NSTextField subclass, which allows us to override
+// textView:clickedOnLink:atIndex: and intercept clicks.
+//
+- (void)addAdditionalControls {
+ // No buttons.
+ [self removeButtons];
+
+ LinkInfoBarDelegate* delegate = delegate_->AsLinkInfoBarDelegate();
+ DCHECK(delegate);
+ size_t offset = std::wstring::npos;
+ string16 message = delegate->GetMessageTextWithOffset(&offset);
+ [self setLabelToMessage:base::SysUTF16ToNSString(message)
+ withLink:base::SysUTF16ToNSString(delegate->GetLinkText())
+ atOffset:offset];
+}
+
+// Called when someone clicks on the link in the infobar. This method
+// is called by the InfobarTextField on its delegate (the
+// LinkInfoBarController).
+- (void)linkClicked {
+ WindowOpenDisposition disposition =
+ event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
+ if (delegate_ && delegate_->AsLinkInfoBarDelegate()->LinkClicked(disposition))
+ [self removeInfoBar];
+}
+
+@end
+
+
+/////////////////////////////////////////////////////////////////////////
+// ConfirmInfoBarController implementation
+
+@implementation ConfirmInfoBarController
+
+// Called when someone clicks on the "OK" button.
+- (IBAction)ok:(id)sender {
+ if (delegate_ && delegate_->AsConfirmInfoBarDelegate()->Accept())
+ [self removeInfoBar];
+}
+
+// Called when someone clicks on the "Cancel" button.
+- (IBAction)cancel:(id)sender {
+ if (delegate_ && delegate_->AsConfirmInfoBarDelegate()->Cancel())
+ [self removeInfoBar];
+}
+
+// Confirm infobars can have OK and/or cancel buttons, depending on
+// the return value of GetButtons(). We create each button if
+// required and position them to the left of the close button.
+- (void)addAdditionalControls {
+ ConfirmInfoBarDelegate* delegate = delegate_->AsConfirmInfoBarDelegate();
+ DCHECK(delegate);
+ int visibleButtons = delegate->GetButtons();
+
+ NSRect okButtonFrame = [okButton_ frame];
+ NSRect cancelButtonFrame = [cancelButton_ frame];
+
+ DCHECK(NSMaxX(okButtonFrame) < NSMinX(cancelButtonFrame))
+ << "Cancel button expected to be on the right of the Ok button in nib";
+
+ CGFloat rightEdge = NSMaxX(cancelButtonFrame);
+ CGFloat spaceBetweenButtons =
+ NSMinX(cancelButtonFrame) - NSMaxX(okButtonFrame);
+ CGFloat spaceBeforeButtons =
+ NSMinX(okButtonFrame) - NSMaxX([label_.get() frame]);
+
+ // Update and position the Cancel button if needed. Otherwise, hide it.
+ if (visibleButtons & ConfirmInfoBarDelegate::BUTTON_CANCEL) {
+ [cancelButton_ setTitle:base::SysUTF16ToNSString(
+ delegate->GetButtonLabel(ConfirmInfoBarDelegate::BUTTON_CANCEL))];
+ [GTMUILocalizerAndLayoutTweaker sizeToFitView:cancelButton_];
+ cancelButtonFrame = [cancelButton_ frame];
+
+ // Position the cancel button to the left of the Close button.
+ cancelButtonFrame.origin.x = rightEdge - cancelButtonFrame.size.width;
+ [cancelButton_ setFrame:cancelButtonFrame];
+
+ // Update the rightEdge
+ rightEdge = NSMinX(cancelButtonFrame);
+ } else {
+ [cancelButton_ removeFromSuperview];
+ }
+
+ // Update and position the OK button if needed. Otherwise, hide it.
+ if (visibleButtons & ConfirmInfoBarDelegate::BUTTON_OK) {
+ [okButton_ setTitle:base::SysUTF16ToNSString(
+ delegate->GetButtonLabel(ConfirmInfoBarDelegate::BUTTON_OK))];
+ [GTMUILocalizerAndLayoutTweaker sizeToFitView:okButton_];
+ okButtonFrame = [okButton_ frame];
+
+ // If we had a Cancel button, leave space between the buttons.
+ if (visibleButtons & ConfirmInfoBarDelegate::BUTTON_CANCEL) {
+ rightEdge -= spaceBetweenButtons;
+ }
+
+ // Position the OK button on our current right edge.
+ okButtonFrame.origin.x = rightEdge - okButtonFrame.size.width;
+ [okButton_ setFrame:okButtonFrame];
+
+
+ // Update the rightEdge
+ rightEdge = NSMinX(okButtonFrame);
+ } else {
+ [okButton_ removeFromSuperview];
+ }
+
+ // If we had either button, leave space before the edge of the textfield.
+ if ((visibleButtons & ConfirmInfoBarDelegate::BUTTON_CANCEL) ||
+ (visibleButtons & ConfirmInfoBarDelegate::BUTTON_OK)) {
+ rightEdge -= spaceBeforeButtons;
+ }
+
+ NSRect frame = [label_.get() frame];
+ DCHECK(rightEdge > NSMinX(frame))
+ << "Need to make the xib larger to handle buttons with text this long";
+ frame.size.width = rightEdge - NSMinX(frame);
+ [label_.get() setFrame:frame];
+
+ // Set the text and link.
+ NSString* message = base::SysUTF16ToNSString(delegate->GetMessageText());
+ string16 link = delegate->GetLinkText();
+ if (link.empty()) {
+ // Simple case: no link, so just set the message directly.
+ [self setLabelToMessage:message];
+ } else {
+ // Inserting the link unintentionally causes the text to have a slightly
+ // different result to the simple case above: text is truncated on word
+ // boundaries (if needed) rather than elided with ellipses.
+
+ // Add spacing between the label and the link.
+ message = [message stringByAppendingString:@" "];
+ [self setLabelToMessage:message
+ withLink:base::SysUTF16ToNSString(link)
+ atOffset:[message length]];
+ }
+}
+
+// Called when someone clicks on the link in the infobar. This method
+// is called by the InfobarTextField on its delegate (the
+// LinkInfoBarController).
+- (void)linkClicked {
+ WindowOpenDisposition disposition =
+ event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
+ if (delegate_ &&
+ delegate_->AsConfirmInfoBarDelegate()->LinkClicked(disposition))
+ [self removeInfoBar];
+}
+
+@end
+
+
+//////////////////////////////////////////////////////////////////////////
+// CreateInfoBar() implementations
+
+InfoBar* AlertInfoBarDelegate::CreateInfoBar() {
+ AlertInfoBarController* controller =
+ [[AlertInfoBarController alloc] initWithDelegate:this];
+ return new InfoBar(controller);
+}
+
+InfoBar* LinkInfoBarDelegate::CreateInfoBar() {
+ LinkInfoBarController* controller =
+ [[LinkInfoBarController alloc] initWithDelegate:this];
+ return new InfoBar(controller);
+}
+
+InfoBar* ConfirmInfoBarDelegate::CreateInfoBar() {
+ ConfirmInfoBarController* controller =
+ [[ConfirmInfoBarController alloc] initWithDelegate:this];
+ return new InfoBar(controller);
+}
diff --git a/chrome/browser/ui/cocoa/infobar_controller_unittest.mm b/chrome/browser/ui/cocoa/infobar_controller_unittest.mm
new file mode 100644
index 0000000..4dfcd51
--- /dev/null
+++ b/chrome/browser/ui/cocoa/infobar_controller_unittest.mm
@@ -0,0 +1,284 @@
+// Copyright (c) 2009 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 "base/scoped_nsobject.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/tab_contents/infobar_delegate.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/infobar_container_controller.h"
+#import "chrome/browser/ui/cocoa/infobar_controller.h"
+#include "chrome/browser/ui/cocoa/infobar_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+@interface InfoBarController (ExposedForTesting)
+- (NSString*)labelString;
+- (NSRect)labelFrame;
+@end
+
+@implementation InfoBarController (ExposedForTesting)
+- (NSString*)labelString {
+ return [label_.get() string];
+}
+- (NSRect)labelFrame {
+ return [label_.get() frame];
+}
+@end
+
+
+// Calls to removeDelegate: normally start an animation, which removes the
+// infobar completely when finished. For unittesting purposes, we create a mock
+// container which calls close: immediately, rather than kicking off an
+// animation.
+@interface InfoBarContainerTest : NSObject <InfoBarContainer> {
+ InfoBarController* controller_;
+}
+- (id)initWithController:(InfoBarController*)controller;
+- (void)removeDelegate:(InfoBarDelegate*)delegate;
+- (void)removeController:(InfoBarController*)controller;
+@end
+
+@implementation InfoBarContainerTest
+- (id)initWithController:(InfoBarController*)controller {
+ if ((self = [super init])) {
+ controller_ = controller;
+ }
+ return self;
+}
+
+- (void)removeDelegate:(InfoBarDelegate*)delegate {
+ [controller_ close];
+}
+
+- (void)removeController:(InfoBarController*)controller {
+ DCHECK(controller_ == controller);
+ controller_ = nil;
+}
+@end
+
+namespace {
+
+///////////////////////////////////////////////////////////////////////////
+// Test fixtures
+
+class AlertInfoBarControllerTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+
+ controller_.reset(
+ [[AlertInfoBarController alloc] initWithDelegate:&delegate_]);
+ container_.reset(
+ [[InfoBarContainerTest alloc] initWithController:controller_]);
+ [controller_ setContainerController:container_];
+ [[test_window() contentView] addSubview:[controller_ view]];
+ }
+
+ protected:
+ MockAlertInfoBarDelegate delegate_;
+ scoped_nsobject<id> container_;
+ scoped_nsobject<AlertInfoBarController> controller_;
+};
+
+class LinkInfoBarControllerTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+
+ controller_.reset(
+ [[LinkInfoBarController alloc] initWithDelegate:&delegate_]);
+ container_.reset(
+ [[InfoBarContainerTest alloc] initWithController:controller_]);
+ [controller_ setContainerController:container_];
+ [[test_window() contentView] addSubview:[controller_ view]];
+ }
+
+ protected:
+ MockLinkInfoBarDelegate delegate_;
+ scoped_nsobject<id> container_;
+ scoped_nsobject<LinkInfoBarController> controller_;
+};
+
+class ConfirmInfoBarControllerTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+
+ controller_.reset(
+ [[ConfirmInfoBarController alloc] initWithDelegate:&delegate_]);
+ container_.reset(
+ [[InfoBarContainerTest alloc] initWithController:controller_]);
+ [controller_ setContainerController:container_];
+ [[test_window() contentView] addSubview:[controller_ view]];
+ }
+
+ protected:
+ MockConfirmInfoBarDelegate delegate_;
+ scoped_nsobject<id> container_;
+ scoped_nsobject<ConfirmInfoBarController> controller_;
+};
+
+
+////////////////////////////////////////////////////////////////////////////
+// Tests
+
+TEST_VIEW(AlertInfoBarControllerTest, [controller_ view]);
+
+TEST_F(AlertInfoBarControllerTest, ShowAndDismiss) {
+ // Make sure someone looked at the message and icon.
+ EXPECT_TRUE(delegate_.message_text_accessed);
+ EXPECT_TRUE(delegate_.icon_accessed);
+
+ // Check to make sure the infobar message was set properly.
+ EXPECT_EQ(kMockAlertInfoBarMessage,
+ base::SysNSStringToUTF8([controller_.get() labelString]));
+
+ // Check that dismissing the infobar calls InfoBarClosed() on the delegate.
+ [controller_ dismiss:nil];
+ EXPECT_TRUE(delegate_.closed);
+}
+
+TEST_F(AlertInfoBarControllerTest, DeallocController) {
+ // Test that dealloc'ing the controller does not send an
+ // InfoBarClosed() message to the delegate.
+ controller_.reset(nil);
+ EXPECT_FALSE(delegate_.closed);
+}
+
+TEST_F(AlertInfoBarControllerTest, ResizeView) {
+ NSRect originalLabelFrame = [controller_ labelFrame];
+
+ // Expand the view by 20 pixels and make sure the label frame changes
+ // accordingly.
+ const CGFloat width = 20;
+ NSRect newViewFrame = [[controller_ view] frame];
+ newViewFrame.size.width += width;
+ [[controller_ view] setFrame:newViewFrame];
+
+ NSRect newLabelFrame = [controller_ labelFrame];
+ EXPECT_EQ(NSWidth(newLabelFrame), NSWidth(originalLabelFrame) + width);
+}
+
+TEST_VIEW(LinkInfoBarControllerTest, [controller_ view]);
+
+TEST_F(LinkInfoBarControllerTest, ShowAndDismiss) {
+ // Make sure someone looked at the message, link, and icon.
+ EXPECT_TRUE(delegate_.message_text_accessed);
+ EXPECT_TRUE(delegate_.link_text_accessed);
+ EXPECT_TRUE(delegate_.icon_accessed);
+
+ // Check that dismissing the infobar calls InfoBarClosed() on the delegate.
+ [controller_ dismiss:nil];
+ EXPECT_FALSE(delegate_.link_clicked);
+ EXPECT_TRUE(delegate_.closed);
+}
+
+TEST_F(LinkInfoBarControllerTest, ShowAndClickLink) {
+ // Check that clicking on the link calls LinkClicked() on the
+ // delegate. It should also close the infobar.
+ [controller_ linkClicked];
+ EXPECT_TRUE(delegate_.link_clicked);
+ EXPECT_TRUE(delegate_.closed);
+}
+
+TEST_F(LinkInfoBarControllerTest, ShowAndClickLinkWithoutClosing) {
+ delegate_.closes_on_action = false;
+
+ // Check that clicking on the link calls LinkClicked() on the
+ // delegate. It should not close the infobar.
+ [controller_ linkClicked];
+ EXPECT_TRUE(delegate_.link_clicked);
+ EXPECT_FALSE(delegate_.closed);
+}
+
+TEST_VIEW(ConfirmInfoBarControllerTest, [controller_ view]);
+
+TEST_F(ConfirmInfoBarControllerTest, ShowAndDismiss) {
+ // Make sure someone looked at the message, link, and icon.
+ EXPECT_TRUE(delegate_.message_text_accessed);
+ EXPECT_TRUE(delegate_.link_text_accessed);
+ EXPECT_TRUE(delegate_.icon_accessed);
+
+ // Check to make sure the infobar message was set properly.
+ EXPECT_EQ(kMockConfirmInfoBarMessage,
+ base::SysNSStringToUTF8([controller_.get() labelString]));
+
+ // Check that dismissing the infobar calls InfoBarClosed() on the delegate.
+ [controller_ dismiss:nil];
+ EXPECT_FALSE(delegate_.ok_clicked);
+ EXPECT_FALSE(delegate_.cancel_clicked);
+ EXPECT_FALSE(delegate_.link_clicked);
+ EXPECT_TRUE(delegate_.closed);
+}
+
+TEST_F(ConfirmInfoBarControllerTest, ShowAndClickOK) {
+ // Check that clicking the OK button calls Accept() and then closes
+ // the infobar.
+ [controller_ ok:nil];
+ EXPECT_TRUE(delegate_.ok_clicked);
+ EXPECT_FALSE(delegate_.cancel_clicked);
+ EXPECT_FALSE(delegate_.link_clicked);
+ EXPECT_TRUE(delegate_.closed);
+}
+
+TEST_F(ConfirmInfoBarControllerTest, ShowAndClickOKWithoutClosing) {
+ delegate_.closes_on_action = false;
+
+ // Check that clicking the OK button calls Accept() but does not close
+ // the infobar.
+ [controller_ ok:nil];
+ EXPECT_TRUE(delegate_.ok_clicked);
+ EXPECT_FALSE(delegate_.cancel_clicked);
+ EXPECT_FALSE(delegate_.link_clicked);
+ EXPECT_FALSE(delegate_.closed);
+}
+
+TEST_F(ConfirmInfoBarControllerTest, ShowAndClickCancel) {
+ // Check that clicking the cancel button calls Cancel() and closes
+ // the infobar.
+ [controller_ cancel:nil];
+ EXPECT_FALSE(delegate_.ok_clicked);
+ EXPECT_TRUE(delegate_.cancel_clicked);
+ EXPECT_FALSE(delegate_.link_clicked);
+ EXPECT_TRUE(delegate_.closed);
+}
+
+TEST_F(ConfirmInfoBarControllerTest, ShowAndClickCancelWithoutClosing) {
+ delegate_.closes_on_action = false;
+
+ // Check that clicking the cancel button calls Cancel() but does not close
+ // the infobar.
+ [controller_ cancel:nil];
+ EXPECT_FALSE(delegate_.ok_clicked);
+ EXPECT_TRUE(delegate_.cancel_clicked);
+ EXPECT_FALSE(delegate_.link_clicked);
+ EXPECT_FALSE(delegate_.closed);
+}
+
+TEST_F(ConfirmInfoBarControllerTest, ShowAndClickLink) {
+ // Check that clicking on the link calls LinkClicked() on the
+ // delegate. It should also close the infobar.
+ [controller_ linkClicked];
+ EXPECT_FALSE(delegate_.ok_clicked);
+ EXPECT_FALSE(delegate_.cancel_clicked);
+ EXPECT_TRUE(delegate_.link_clicked);
+ EXPECT_TRUE(delegate_.closed);
+}
+
+TEST_F(ConfirmInfoBarControllerTest, ShowAndClickLinkWithoutClosing) {
+ delegate_.closes_on_action = false;
+
+ // Check that clicking on the link calls LinkClicked() on the
+ // delegate. It should not close the infobar.
+ [controller_ linkClicked];
+ EXPECT_FALSE(delegate_.ok_clicked);
+ EXPECT_FALSE(delegate_.cancel_clicked);
+ EXPECT_TRUE(delegate_.link_clicked);
+ EXPECT_FALSE(delegate_.closed);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/infobar_gradient_view.h b/chrome/browser/ui/cocoa/infobar_gradient_view.h
new file mode 100644
index 0000000..e0e0037
--- /dev/null
+++ b/chrome/browser/ui/cocoa/infobar_gradient_view.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_INFOBAR_GRADIENT_VIEW_H_
+#define CHROME_BROWSER_UI_COCOA_INFOBAR_GRADIENT_VIEW_H_
+#pragma once
+
+#import "chrome/browser/ui/cocoa/vertical_gradient_view.h"
+
+#import <Cocoa/Cocoa.h>
+
+// A custom view that draws the background gradient for an infobar.
+@interface InfoBarGradientView : VerticalGradientView {
+}
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_INFOBAR_GRADIENT_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/infobar_gradient_view.mm b/chrome/browser/ui/cocoa/infobar_gradient_view.mm
new file mode 100644
index 0000000..cd2b1ee
--- /dev/null
+++ b/chrome/browser/ui/cocoa/infobar_gradient_view.mm
@@ -0,0 +1,70 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/infobar_gradient_view.h"
+
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/themes/browser_theme_provider.h"
+#import "chrome/browser/ui/cocoa/themed_window.h"
+
+namespace {
+
+const double kBackgroundColorTop[3] =
+ {255.0 / 255.0, 242.0 / 255.0, 183.0 / 255.0};
+const double kBackgroundColorBottom[3] =
+ {250.0 / 255.0, 230.0 / 255.0, 145.0 / 255.0};
+}
+
+@implementation InfoBarGradientView
+
+- (id)initWithFrame:(NSRect)frameRect {
+ if ((self = [super initWithFrame:frameRect])) {
+ NSColor* startingColor =
+ [NSColor colorWithCalibratedRed:kBackgroundColorTop[0]
+ green:kBackgroundColorTop[1]
+ blue:kBackgroundColorTop[2]
+ alpha:1.0];
+ NSColor* endingColor =
+ [NSColor colorWithCalibratedRed:kBackgroundColorBottom[0]
+ green:kBackgroundColorBottom[1]
+ blue:kBackgroundColorBottom[2]
+ alpha:1.0];
+ scoped_nsobject<NSGradient> gradient(
+ [[NSGradient alloc] initWithStartingColor:startingColor
+ endingColor:endingColor]);
+ [self setGradient:gradient];
+ }
+ return self;
+}
+
+- (NSColor*)strokeColor {
+ ThemeProvider* themeProvider = [[self window] themeProvider];
+ if (!themeProvider)
+ return [NSColor blackColor];
+
+ BOOL active = [[self window] isMainWindow];
+ return themeProvider->GetNSColor(
+ active ? BrowserThemeProvider::COLOR_TOOLBAR_STROKE :
+ BrowserThemeProvider::COLOR_TOOLBAR_STROKE_INACTIVE,
+ true);
+}
+
+- (BOOL)mouseDownCanMoveWindow {
+ return NO;
+}
+
+// This view is intentionally not opaque because it overlaps with the findbar.
+
+- (BOOL)accessibilityIsIgnored {
+ return NO;
+}
+
+- (id)accessibilityAttributeValue:(NSString*)attribute {
+ if ([attribute isEqual:NSAccessibilityRoleAttribute])
+ return NSAccessibilityGroupRole;
+
+ return [super accessibilityAttributeValue:attribute];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/infobar_gradient_view_unittest.mm b/chrome/browser/ui/cocoa/infobar_gradient_view_unittest.mm
new file mode 100644
index 0000000..2e4d01b
--- /dev/null
+++ b/chrome/browser/ui/cocoa/infobar_gradient_view_unittest.mm
@@ -0,0 +1,32 @@
+// Copyright (c) 2009 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/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/infobar_gradient_view.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+
+namespace {
+
+class InfoBarGradientViewTest : public CocoaTest {
+ public:
+ InfoBarGradientViewTest() {
+ NSRect frame = NSMakeRect(0, 0, 100, 30);
+ scoped_nsobject<InfoBarGradientView> view(
+ [[InfoBarGradientView alloc] initWithFrame:frame]);
+ view_ = view.get();
+ [[test_window() contentView] addSubview:view_];
+ }
+
+ InfoBarGradientView* view_; // Weak. Retained by view hierarchy.
+};
+
+TEST_VIEW(InfoBarGradientViewTest, view_);
+
+// Assert that the view is non-opaque, because otherwise we will end
+// up with findbar painting issues.
+TEST_F(InfoBarGradientViewTest, AssertViewNonOpaque) {
+ EXPECT_FALSE([view_ isOpaque]);
+}
+
+} // namespace
diff --git a/chrome/browser/cocoa/infobar_test_helper.h b/chrome/browser/ui/cocoa/infobar_test_helper.h
index d01a71b..d01a71b 100644
--- a/chrome/browser/cocoa/infobar_test_helper.h
+++ b/chrome/browser/ui/cocoa/infobar_test_helper.h
diff --git a/chrome/browser/cocoa/install.sh b/chrome/browser/ui/cocoa/install.sh
index dc73fae..dc73fae 100755
--- a/chrome/browser/cocoa/install.sh
+++ b/chrome/browser/ui/cocoa/install.sh
diff --git a/chrome/browser/ui/cocoa/install_from_dmg.h b/chrome/browser/ui/cocoa/install_from_dmg.h
new file mode 100644
index 0000000..0343cd0
--- /dev/null
+++ b/chrome/browser/ui/cocoa/install_from_dmg.h
@@ -0,0 +1,15 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_INSTALL_FROM_DMG_H_
+#define CHROME_BROWSER_UI_COCOA_INSTALL_FROM_DMG_H_
+#pragma once
+
+// If the application is running from a read-only disk image, prompts the user
+// to install it to the hard drive. If the user approves, the application
+// will be installed and launched, and MaybeInstallFromDiskImage will return
+// true. In that case, the caller must exit expeditiously.
+bool MaybeInstallFromDiskImage();
+
+#endif // CHROME_BROWSER_UI_COCOA_INSTALL_FROM_DMG_H_
diff --git a/chrome/browser/ui/cocoa/install_from_dmg.mm b/chrome/browser/ui/cocoa/install_from_dmg.mm
new file mode 100644
index 0000000..d18e257
--- /dev/null
+++ b/chrome/browser/ui/cocoa/install_from_dmg.mm
@@ -0,0 +1,438 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/install_from_dmg.h"
+
+#include <ApplicationServices/ApplicationServices.h>
+#import <AppKit/AppKit.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreServices/CoreServices.h>
+#include <IOKit/IOKitLib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+
+#include "app/l10n_util.h"
+#import "app/l10n_util_mac.h"
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#import "base/mac_util.h"
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "chrome/browser/ui/cocoa/authorization_util.h"
+#include "chrome/browser/ui/cocoa/scoped_authorizationref.h"
+#import "chrome/browser/ui/cocoa/keystone_glue.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+
+// When C++ exceptions are disabled, the C++ library defines |try| and
+// |catch| so as to allow exception-expecting C++ code to build properly when
+// language support for exceptions is not present. These macros interfere
+// with the use of |@try| and |@catch| in Objective-C files such as this one.
+// Undefine these macros here, after everything has been #included, since
+// there will be no C++ uses and only Objective-C uses from this point on.
+#undef try
+#undef catch
+
+namespace {
+
+// Just like ScopedCFTypeRef but for io_object_t and subclasses.
+template<typename IOT>
+class scoped_ioobject {
+ public:
+ typedef IOT element_type;
+
+ explicit scoped_ioobject(IOT object = NULL)
+ : object_(object) {
+ }
+
+ ~scoped_ioobject() {
+ if (object_)
+ IOObjectRelease(object_);
+ }
+
+ void reset(IOT object = NULL) {
+ if (object_)
+ IOObjectRelease(object_);
+ object_ = object;
+ }
+
+ bool operator==(IOT that) const {
+ return object_ == that;
+ }
+
+ bool operator!=(IOT that) const {
+ return object_ != that;
+ }
+
+ operator IOT() const {
+ return object_;
+ }
+
+ IOT get() const {
+ return object_;
+ }
+
+ void swap(scoped_ioobject& that) {
+ IOT temp = that.object_;
+ that.object_ = object_;
+ object_ = temp;
+ }
+
+ IOT release() {
+ IOT temp = object_;
+ object_ = NULL;
+ return temp;
+ }
+
+ private:
+ IOT object_;
+
+ DISALLOW_COPY_AND_ASSIGN(scoped_ioobject);
+};
+
+// Returns true if |path| is located on a read-only filesystem of a disk
+// image. Returns false if not, or in the event of an error.
+bool IsPathOnReadOnlyDiskImage(const char path[]) {
+ struct statfs statfs_buf;
+ if (statfs(path, &statfs_buf) != 0) {
+ PLOG(ERROR) << "statfs " << path;
+ return false;
+ }
+
+ if (!(statfs_buf.f_flags & MNT_RDONLY)) {
+ // Not on a read-only filesystem.
+ return false;
+ }
+
+ const char dev_root[] = "/dev/";
+ const int dev_root_length = arraysize(dev_root) - 1;
+ if (strncmp(statfs_buf.f_mntfromname, dev_root, dev_root_length) != 0) {
+ // Not rooted at dev_root, no BSD name to search on.
+ return false;
+ }
+
+ // BSD names in IOKit don't include dev_root.
+ const char* bsd_device_name = statfs_buf.f_mntfromname + dev_root_length;
+
+ const mach_port_t master_port = kIOMasterPortDefault;
+
+ // IOBSDNameMatching gives ownership of match_dict to the caller, but
+ // IOServiceGetMatchingServices will assume that reference.
+ CFMutableDictionaryRef match_dict = IOBSDNameMatching(master_port,
+ 0,
+ bsd_device_name);
+ if (!match_dict) {
+ LOG(ERROR) << "IOBSDNameMatching " << bsd_device_name;
+ return false;
+ }
+
+ io_iterator_t iterator_ref;
+ kern_return_t kr = IOServiceGetMatchingServices(master_port,
+ match_dict,
+ &iterator_ref);
+ if (kr != KERN_SUCCESS) {
+ LOG(ERROR) << "IOServiceGetMatchingServices " << bsd_device_name
+ << ": kernel error " << kr;
+ return false;
+ }
+ scoped_ioobject<io_iterator_t> iterator(iterator_ref);
+ iterator_ref = NULL;
+
+ // There needs to be exactly one matching service.
+ scoped_ioobject<io_service_t> filesystem_service(IOIteratorNext(iterator));
+ if (!filesystem_service) {
+ LOG(ERROR) << "IOIteratorNext " << bsd_device_name << ": no service";
+ return false;
+ }
+ scoped_ioobject<io_service_t> unexpected_service(IOIteratorNext(iterator));
+ if (unexpected_service) {
+ LOG(ERROR) << "IOIteratorNext " << bsd_device_name << ": too many services";
+ return false;
+ }
+
+ iterator.reset();
+
+ const char disk_image_class[] = "IOHDIXController";
+
+ // This is highly unlikely. The filesystem service is expected to be of
+ // class IOMedia. Since the filesystem service's entire ancestor chain
+ // will be checked, though, check the filesystem service's class itself.
+ if (IOObjectConformsTo(filesystem_service, disk_image_class)) {
+ return true;
+ }
+
+ kr = IORegistryEntryCreateIterator(filesystem_service,
+ kIOServicePlane,
+ kIORegistryIterateRecursively |
+ kIORegistryIterateParents,
+ &iterator_ref);
+ if (kr != KERN_SUCCESS) {
+ LOG(ERROR) << "IORegistryEntryCreateIterator " << bsd_device_name
+ << ": kernel error " << kr;
+ return false;
+ }
+ iterator.reset(iterator_ref);
+ iterator_ref = NULL;
+
+ // Look at each of the filesystem service's ancestor services, beginning
+ // with the parent, iterating all the way up to the device tree's root. If
+ // any ancestor service matches the class used for disk images, the
+ // filesystem resides on a disk image.
+ for(scoped_ioobject<io_service_t> ancestor_service(IOIteratorNext(iterator));
+ ancestor_service;
+ ancestor_service.reset(IOIteratorNext(iterator))) {
+ if (IOObjectConformsTo(ancestor_service, disk_image_class)) {
+ return true;
+ }
+ }
+
+ // The filesystem does not reside on a disk image.
+ return false;
+}
+
+// Returns true if the application is located on a read-only filesystem of a
+// disk image. Returns false if not, or in the event of an error.
+bool IsAppRunningFromReadOnlyDiskImage() {
+ return IsPathOnReadOnlyDiskImage(
+ [[[NSBundle mainBundle] bundlePath] fileSystemRepresentation]);
+}
+
+// Shows a dialog asking the user whether or not to install from the disk
+// image. Returns true if the user approves installation.
+bool ShouldInstallDialog() {
+ NSString* title = l10n_util::GetNSStringFWithFixup(
+ IDS_INSTALL_FROM_DMG_TITLE, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
+ NSString* prompt = l10n_util::GetNSStringFWithFixup(
+ IDS_INSTALL_FROM_DMG_PROMPT, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
+ NSString* yes = l10n_util::GetNSStringWithFixup(IDS_INSTALL_FROM_DMG_YES);
+ NSString* no = l10n_util::GetNSStringWithFixup(IDS_INSTALL_FROM_DMG_NO);
+
+ NSAlert* alert = [[[NSAlert alloc] init] autorelease];
+
+ [alert setAlertStyle:NSInformationalAlertStyle];
+ [alert setMessageText:title];
+ [alert setInformativeText:prompt];
+ [alert addButtonWithTitle:yes];
+ NSButton* cancel_button = [alert addButtonWithTitle:no];
+ [cancel_button setKeyEquivalent:@"\e"];
+
+ NSInteger result = [alert runModal];
+
+ return result == NSAlertFirstButtonReturn;
+}
+
+// Potentially shows an authorization dialog to request authentication to
+// copy. If application_directory appears to be unwritable, attempts to
+// obtain authorization, which may result in the display of the dialog.
+// Returns NULL if authorization is not performed because it does not appear
+// to be necessary because the user has permission to write to
+// application_directory. Returns NULL if authorization fails.
+AuthorizationRef MaybeShowAuthorizationDialog(NSString* application_directory) {
+ NSFileManager* file_manager = [NSFileManager defaultManager];
+ if ([file_manager isWritableFileAtPath:application_directory]) {
+ return NULL;
+ }
+
+ NSString* prompt = l10n_util::GetNSStringFWithFixup(
+ IDS_INSTALL_FROM_DMG_AUTHENTICATION_PROMPT,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
+ return authorization_util::AuthorizationCreateToRunAsRoot(
+ reinterpret_cast<CFStringRef>(prompt));
+}
+
+// Invokes the installer program at installer_path to copy source_path to
+// target_path and perform any additional on-disk bookkeeping needed to be
+// able to launch target_path properly. If authorization_arg is non-NULL,
+// function will assume ownership of it, will invoke the installer with that
+// authorization reference, and will attempt Keystone ticket promotion.
+bool InstallFromDiskImage(AuthorizationRef authorization_arg,
+ NSString* installer_path,
+ NSString* source_path,
+ NSString* target_path) {
+ scoped_AuthorizationRef authorization(authorization_arg);
+ authorization_arg = NULL;
+ int exit_status;
+ if (authorization) {
+ const char* installer_path_c = [installer_path fileSystemRepresentation];
+ const char* source_path_c = [source_path fileSystemRepresentation];
+ const char* target_path_c = [target_path fileSystemRepresentation];
+ const char* arguments[] = {source_path_c, target_path_c, NULL};
+
+ OSStatus status = authorization_util::ExecuteWithPrivilegesAndWait(
+ authorization,
+ installer_path_c,
+ kAuthorizationFlagDefaults,
+ arguments,
+ NULL, // pipe
+ &exit_status);
+ if (status != errAuthorizationSuccess) {
+ LOG(ERROR) << "AuthorizationExecuteWithPrivileges install: " << status;
+ return false;
+ }
+ } else {
+ NSArray* arguments = [NSArray arrayWithObjects:source_path,
+ target_path,
+ nil];
+
+ NSTask* task;
+ @try {
+ task = [NSTask launchedTaskWithLaunchPath:installer_path
+ arguments:arguments];
+ } @catch(NSException* exception) {
+ LOG(ERROR) << "+[NSTask launchedTaskWithLaunchPath:arguments:]: "
+ << [[exception description] UTF8String];
+ return false;
+ }
+
+ [task waitUntilExit];
+ exit_status = [task terminationStatus];
+ }
+
+ if (exit_status != 0) {
+ LOG(ERROR) << "install.sh: exit status " << exit_status;
+ return false;
+ }
+
+ if (authorization) {
+ // As long as an AuthorizationRef is available, promote the Keystone
+ // ticket. Inform KeystoneGlue of the new path to use.
+ KeystoneGlue* keystone_glue = [KeystoneGlue defaultKeystoneGlue];
+ [keystone_glue setAppPath:target_path];
+ [keystone_glue promoteTicketWithAuthorization:authorization.release()
+ synchronous:YES];
+ }
+
+ return true;
+}
+
+// Launches the application at app_path. The arguments passed to app_path
+// will be the same as the arguments used to invoke this process, except any
+// arguments beginning with -psn_ will be stripped.
+bool LaunchInstalledApp(NSString* app_path) {
+ const UInt8* app_path_c =
+ reinterpret_cast<const UInt8*>([app_path fileSystemRepresentation]);
+ FSRef app_fsref;
+ OSStatus err = FSPathMakeRef(app_path_c, &app_fsref, NULL);
+ if (err != noErr) {
+ LOG(ERROR) << "FSPathMakeRef: " << err;
+ return false;
+ }
+
+ const std::vector<std::string>& argv =
+ CommandLine::ForCurrentProcess()->argv();
+ NSMutableArray* arguments =
+ [NSMutableArray arrayWithCapacity:argv.size() - 1];
+ // Start at argv[1]. LSOpenApplication adds its own argv[0] as the path of
+ // the launched executable.
+ for (size_t index = 1; index < argv.size(); ++index) {
+ std::string argument = argv[index];
+ const char psn_flag[] = "-psn_";
+ const int psn_flag_length = arraysize(psn_flag) - 1;
+ if (argument.compare(0, psn_flag_length, psn_flag) != 0) {
+ // Strip any -psn_ arguments, as they apply to a specific process.
+ [arguments addObject:[NSString stringWithUTF8String:argument.c_str()]];
+ }
+ }
+
+ struct LSApplicationParameters parameters = {0};
+ parameters.flags = kLSLaunchDefaults;
+ parameters.application = &app_fsref;
+ parameters.argv = reinterpret_cast<CFArrayRef>(arguments);
+
+ err = LSOpenApplication(&parameters, NULL);
+ if (err != noErr) {
+ LOG(ERROR) << "LSOpenApplication: " << err;
+ return false;
+ }
+
+ return true;
+}
+
+void ShowErrorDialog() {
+ NSString* title = l10n_util::GetNSStringWithFixup(
+ IDS_INSTALL_FROM_DMG_ERROR_TITLE);
+ NSString* error = l10n_util::GetNSStringFWithFixup(
+ IDS_INSTALL_FROM_DMG_ERROR, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
+ NSString* ok = l10n_util::GetNSStringWithFixup(IDS_OK);
+
+ NSAlert* alert = [[[NSAlert alloc] init] autorelease];
+
+ [alert setAlertStyle:NSWarningAlertStyle];
+ [alert setMessageText:title];
+ [alert setInformativeText:error];
+ [alert addButtonWithTitle:ok];
+
+ [alert runModal];
+}
+
+} // namespace
+
+bool MaybeInstallFromDiskImage() {
+ base::mac::ScopedNSAutoreleasePool autorelease_pool;
+
+ if (!IsAppRunningFromReadOnlyDiskImage()) {
+ return false;
+ }
+
+ NSArray* application_directories =
+ NSSearchPathForDirectoriesInDomains(NSApplicationDirectory,
+ NSLocalDomainMask,
+ YES);
+ if ([application_directories count] == 0) {
+ LOG(ERROR) << "NSSearchPathForDirectoriesInDomains: "
+ << "no local application directories";
+ return false;
+ }
+ NSString* application_directory = [application_directories objectAtIndex:0];
+
+ NSFileManager* file_manager = [NSFileManager defaultManager];
+
+ BOOL is_directory;
+ if (![file_manager fileExistsAtPath:application_directory
+ isDirectory:&is_directory] ||
+ !is_directory) {
+ VLOG(1) << "No application directory at "
+ << [application_directory UTF8String];
+ return false;
+ }
+
+ NSString* source_path = [[NSBundle mainBundle] bundlePath];
+ NSString* application_name = [source_path lastPathComponent];
+ NSString* target_path =
+ [application_directory stringByAppendingPathComponent:application_name];
+
+ if ([file_manager fileExistsAtPath:target_path]) {
+ VLOG(1) << "Something already exists at " << [target_path UTF8String];
+ return false;
+ }
+
+ NSString* installer_path =
+ [mac_util::MainAppBundle() pathForResource:@"install" ofType:@"sh"];
+ if (!installer_path) {
+ VLOG(1) << "Could not locate install.sh";
+ return false;
+ }
+
+ if (!ShouldInstallDialog()) {
+ return false;
+ }
+
+ scoped_AuthorizationRef authorization(
+ MaybeShowAuthorizationDialog(application_directory));
+ // authorization will be NULL if it's deemed unnecessary or if
+ // authentication fails. In either case, try to install without privilege
+ // escalation.
+
+ if (!InstallFromDiskImage(authorization.release(),
+ installer_path,
+ source_path,
+ target_path) ||
+ !LaunchInstalledApp(target_path)) {
+ ShowErrorDialog();
+ return false;
+ }
+
+ return true;
+}
diff --git a/chrome/browser/ui/cocoa/instant_confirm_window_controller.h b/chrome/browser/ui/cocoa/instant_confirm_window_controller.h
new file mode 100644
index 0000000..a0f0c2f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/instant_confirm_window_controller.h
@@ -0,0 +1,43 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_INSTANT_CONFIRM_WINDOW_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_INSTANT_CONFIRM_WINDOW_CONTROLLER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/mac/cocoa_protocols.h"
+
+class Profile;
+
+// This controller manages a dialog that informs the user about Instant search.
+// The recommended API is to not use this class directly, but instead to use
+// the functions in //chrome/browser/instant/instant_confirm_dialog.h:
+// void ShowInstantConfirmDialog[IfNecessary](gfx::NativeWindow* parent, ...)
+// Which will attach the window to |parent| as a sheet.
+@interface InstantConfirmWindowController : NSWindowController<NSWindowDelegate>
+{
+ @private
+ // The long description about Instant that needs to be sized-to-fit.
+ IBOutlet NSTextField* description_;
+
+ Profile* profile_; // weak
+}
+
+// Designated initializer. The controller will release itself on window close.
+- (id)initWithProfile:(Profile*)profile;
+
+// Action for the "Learn more" link.
+- (IBAction)learnMore:(id)sender;
+
+// The user has opted in to Instant. This enables the Instant preference.
+- (IBAction)ok:(id)sender;
+
+// Closes the sheet without altering the preference value.
+- (IBAction)cancel:(id)sender;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_INSTANT_CONFIRM_WINDOW_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/instant_confirm_window_controller.mm b/chrome/browser/ui/cocoa/instant_confirm_window_controller.mm
new file mode 100644
index 0000000..299fd35
--- /dev/null
+++ b/chrome/browser/ui/cocoa/instant_confirm_window_controller.mm
@@ -0,0 +1,76 @@
+// 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 "chrome/browser/ui/cocoa/instant_confirm_window_controller.h"
+
+#include "base/logging.h"
+#include "base/mac_util.h"
+#include "chrome/browser/instant/instant_confirm_dialog.h"
+#include "chrome/browser/instant/instant_controller.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/options/show_options_url.h"
+#include "gfx/native_widget_types.h"
+#include "googleurl/src/gurl.h"
+#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
+
+namespace browser {
+
+void ShowInstantConfirmDialog(gfx::NativeWindow parent, Profile* profile) {
+ InstantConfirmWindowController* controller =
+ [[InstantConfirmWindowController alloc] initWithProfile:profile];
+ [NSApp beginSheet:[controller window]
+ modalForWindow:parent
+ modalDelegate:nil
+ didEndSelector:NULL
+ contextInfo:NULL];
+}
+
+} // namespace browser
+
+@implementation InstantConfirmWindowController
+
+- (id)initWithProfile:(Profile*)profile {
+ NSString* nibPath = [mac_util::MainAppBundle()
+ pathForResource:@"InstantConfirm"
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibPath owner:self])) {
+ profile_ = profile;
+ }
+ return self;
+}
+
+- (void)awakeFromNib {
+ DCHECK([self window]);
+ DCHECK_EQ(self, [[self window] delegate]);
+
+ CGFloat delta = [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:
+ description_];
+ NSRect descriptionFrame = [description_ frame];
+ descriptionFrame.origin.y -= delta;
+ [description_ setFrame:descriptionFrame];
+
+ NSRect frame = [[self window] frame];
+ frame.size.height += delta;
+ [[self window] setFrame:frame display:YES];
+}
+
+- (void)windowWillClose:(NSNotification*)notif {
+ [self autorelease];
+}
+
+- (IBAction)learnMore:(id)sender {
+ browser::ShowOptionsURL(profile_, browser::InstantLearnMoreURL());
+}
+
+- (IBAction)ok:(id)sender {
+ InstantController::Enable(profile_);
+ [self cancel:sender];
+}
+
+- (IBAction)cancel:(id)sender {
+ [NSApp endSheet:[self window]];
+ [[self window] close];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/instant_confirm_window_controller_unittest.mm b/chrome/browser/ui/cocoa/instant_confirm_window_controller_unittest.mm
new file mode 100644
index 0000000..71d8c9e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/instant_confirm_window_controller_unittest.mm
@@ -0,0 +1,36 @@
+// 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 "chrome/browser/ui/cocoa/instant_confirm_window_controller.h"
+
+#include "chrome/browser/instant/instant_confirm_dialog.h"
+#import "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+
+namespace {
+
+class InstantConfirmWindowControllerTest : public CocoaTest {
+ public:
+ InstantConfirmWindowControllerTest() : controller_(nil) {}
+
+ BrowserTestHelper helper_;
+ InstantConfirmWindowController* controller_; // Weak. Owns self.
+};
+
+TEST_F(InstantConfirmWindowControllerTest, Init) {
+ controller_ =
+ [[InstantConfirmWindowController alloc] initWithProfile:
+ helper_.profile()];
+ EXPECT_TRUE([controller_ window]);
+ [controller_ release];
+}
+
+TEST_F(InstantConfirmWindowControllerTest, Show) {
+ browser::ShowInstantConfirmDialog(test_window(), helper_.profile());
+ controller_ = [[test_window() attachedSheet] windowController];
+ EXPECT_TRUE(controller_);
+ [controller_ cancel:nil];
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/js_modal_dialog_cocoa.h b/chrome/browser/ui/cocoa/js_modal_dialog_cocoa.h
new file mode 100644
index 0000000..9179b04
--- /dev/null
+++ b/chrome/browser/ui/cocoa/js_modal_dialog_cocoa.h
@@ -0,0 +1,48 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_JS_MODAL_DIALOG_COCOA_H_
+#define CHROME_BROWSER_UI_COCOA_JS_MODAL_DIALOG_COCOA_H_
+#pragma once
+
+#include "chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h"
+
+#include "base/logging.h"
+#include "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+
+#if __OBJC__
+@class NSAlert;
+@class JavaScriptAppModalDialogHelper;
+#else
+class NSAlert;
+class JavaScriptAppModalDialogHelper;
+#endif
+
+class JSModalDialogCocoa : public NativeAppModalDialog {
+ public:
+ explicit JSModalDialogCocoa(JavaScriptAppModalDialog* dialog);
+ virtual ~JSModalDialogCocoa();
+
+ // Overridden from NativeAppModalDialog:
+ virtual int GetAppModalDialogButtons() const;
+ virtual void ShowAppModalDialog();
+ virtual void ActivateAppModalDialog();
+ virtual void CloseAppModalDialog();
+ virtual void AcceptAppModalDialog();
+ virtual void CancelAppModalDialog();
+
+ JavaScriptAppModalDialog* dialog() const { return dialog_.get(); }
+
+ private:
+ scoped_ptr<JavaScriptAppModalDialog> dialog_;
+
+ scoped_nsobject<JavaScriptAppModalDialogHelper> helper_;
+ NSAlert* alert_; // weak, owned by |helper_|.
+
+ DISALLOW_COPY_AND_ASSIGN(JSModalDialogCocoa);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_JS_MODAL_DIALOG_COCOA_H_
+
diff --git a/chrome/browser/ui/cocoa/js_modal_dialog_cocoa.mm b/chrome/browser/ui/cocoa/js_modal_dialog_cocoa.mm
new file mode 100644
index 0000000..5568d70
--- /dev/null
+++ b/chrome/browser/ui/cocoa/js_modal_dialog_cocoa.mm
@@ -0,0 +1,219 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/js_modal_dialog_cocoa.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "app/l10n_util_mac.h"
+#include "app/message_box_flags.h"
+#include "base/logging.h"
+#import "base/mac/cocoa_protocols.h"
+#include "base/sys_string_conversions.h"
+#import "chrome/browser/chrome_browser_application_mac.h"
+#include "chrome/browser/ui/app_modal_dialogs/js_modal_dialog.h"
+#include "grit/app_strings.h"
+#include "grit/generated_resources.h"
+
+// Helper object that receives the notification that the dialog/sheet is
+// going away. Is responsible for cleaning itself up.
+@interface JavaScriptAppModalDialogHelper : NSObject<NSAlertDelegate> {
+ @private
+ NSAlert* alert_;
+ NSTextField* textField_; // WEAK; owned by alert_
+}
+
+- (NSAlert*)alert;
+- (NSTextField*)textField;
+- (void)alertDidEnd:(NSAlert *)alert
+ returnCode:(int)returnCode
+ contextInfo:(void*)contextInfo;
+
+@end
+
+@implementation JavaScriptAppModalDialogHelper
+
+- (NSAlert*)alert {
+ alert_ = [[NSAlert alloc] init];
+ return alert_;
+}
+
+- (NSTextField*)textField {
+ textField_ = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 300, 22)];
+ [alert_ setAccessoryView:textField_];
+ [textField_ release];
+
+ return textField_;
+}
+
+- (void)dealloc {
+ [alert_ release];
+ [super dealloc];
+}
+
+// |contextInfo| is the JSModalDialogCocoa that owns us.
+- (void)alertDidEnd:(NSAlert*)alert
+ returnCode:(int)returnCode
+ contextInfo:(void*)contextInfo {
+ scoped_ptr<JSModalDialogCocoa> native_dialog(
+ reinterpret_cast<JSModalDialogCocoa*>(contextInfo));
+ std::wstring input;
+ if (textField_)
+ input = base::SysNSStringToWide([textField_ stringValue]);
+ bool shouldSuppress = false;
+ if ([alert showsSuppressionButton])
+ shouldSuppress = [[alert suppressionButton] state] == NSOnState;
+ switch (returnCode) {
+ case NSAlertFirstButtonReturn: { // OK
+ native_dialog->dialog()->OnAccept(input, shouldSuppress);
+ break;
+ }
+ case NSAlertSecondButtonReturn: { // Cancel
+ // If the user wants to stay on this page, stop quitting (if a quit is in
+ // progress).
+ if (native_dialog->dialog()->is_before_unload_dialog())
+ chrome_browser_application_mac::CancelTerminate();
+ native_dialog->dialog()->OnCancel(shouldSuppress);
+ break;
+ }
+ case NSRunStoppedResponse: { // Window was closed underneath us
+ // Need to call OnCancel() because there is some cleanup that needs
+ // to be done. It won't call back to the javascript since the
+ // JavaScriptAppModalDialog knows that the TabContents was destroyed.
+ native_dialog->dialog()->OnCancel(shouldSuppress);
+ break;
+ }
+ default: {
+ NOTREACHED();
+ }
+ }
+}
+@end
+
+////////////////////////////////////////////////////////////////////////////////
+// JSModalDialogCocoa, public:
+
+JSModalDialogCocoa::JSModalDialogCocoa(JavaScriptAppModalDialog* dialog)
+ : dialog_(dialog),
+ helper_(NULL) {
+ // Determine the names of the dialog buttons based on the flags. "Default"
+ // is the OK button. "Other" is the cancel button. We don't use the
+ // "Alternate" button in NSRunAlertPanel.
+ NSString* default_button = l10n_util::GetNSStringWithFixup(IDS_APP_OK);
+ NSString* other_button = l10n_util::GetNSStringWithFixup(IDS_APP_CANCEL);
+ bool text_field = false;
+ bool one_button = false;
+ switch (dialog_->dialog_flags()) {
+ case MessageBoxFlags::kIsJavascriptAlert:
+ one_button = true;
+ break;
+ case MessageBoxFlags::kIsJavascriptConfirm:
+ if (dialog_->is_before_unload_dialog()) {
+ default_button = l10n_util::GetNSStringWithFixup(
+ IDS_BEFOREUNLOAD_MESSAGEBOX_OK_BUTTON_LABEL);
+ other_button = l10n_util::GetNSStringWithFixup(
+ IDS_BEFOREUNLOAD_MESSAGEBOX_CANCEL_BUTTON_LABEL);
+ }
+ break;
+ case MessageBoxFlags::kIsJavascriptPrompt:
+ text_field = true;
+ break;
+
+ default:
+ NOTREACHED();
+ }
+
+ // Create a helper which will receive the sheet ended selector. It will
+ // delete itself when done. It doesn't need anything passed to its init
+ // as it will get a contextInfo parameter.
+ helper_.reset([[JavaScriptAppModalDialogHelper alloc] init]);
+
+ // Show the modal dialog.
+ alert_ = [helper_ alert];
+ NSTextField* field = nil;
+ if (text_field) {
+ field = [helper_ textField];
+ [field setStringValue:base::SysWideToNSString(
+ dialog_->default_prompt_text())];
+ }
+ [alert_ setDelegate:helper_];
+ [alert_ setInformativeText:base::SysWideToNSString(dialog_->message_text())];
+ [alert_ setMessageText:base::SysWideToNSString(dialog_->title())];
+ [alert_ addButtonWithTitle:default_button];
+ if (!one_button) {
+ NSButton* other = [alert_ addButtonWithTitle:other_button];
+ [other setKeyEquivalent:@"\e"];
+ }
+ if (dialog_->display_suppress_checkbox()) {
+ [alert_ setShowsSuppressionButton:YES];
+ NSString* suppression_title = l10n_util::GetNSStringWithFixup(
+ IDS_JAVASCRIPT_MESSAGEBOX_SUPPRESS_OPTION);
+ [[alert_ suppressionButton] setTitle:suppression_title];
+ }
+}
+
+JSModalDialogCocoa::~JSModalDialogCocoa() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// JSModalDialogCocoa, NativeAppModalDialog implementation:
+
+int JSModalDialogCocoa::GetAppModalDialogButtons() const {
+ // From the above, it is the case that if there is 1 button, it is always the
+ // OK button. The second button, if it exists, is always the Cancel button.
+ int num_buttons = [[alert_ buttons] count];
+ switch (num_buttons) {
+ case 1:
+ return MessageBoxFlags::DIALOGBUTTON_OK;
+ case 2:
+ return MessageBoxFlags::DIALOGBUTTON_OK |
+ MessageBoxFlags::DIALOGBUTTON_CANCEL;
+ default:
+ NOTREACHED();
+ return 0;
+ }
+}
+
+void JSModalDialogCocoa::ShowAppModalDialog() {
+ [alert_
+ beginSheetModalForWindow:nil // nil here makes it app-modal
+ modalDelegate:helper_.get()
+ didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
+ contextInfo:this];
+
+ if ([alert_ accessoryView])
+ [[alert_ window] makeFirstResponder:[alert_ accessoryView]];
+}
+
+void JSModalDialogCocoa::ActivateAppModalDialog() {
+}
+
+void JSModalDialogCocoa::CloseAppModalDialog() {
+ DCHECK([alert_ isKindOfClass:[NSAlert class]]);
+
+ // Note: the call below will delete |this|,
+ // see JavaScriptAppModalDialogHelper's alertDidEnd.
+ [NSApp endSheet:[alert_ window]];
+}
+
+void JSModalDialogCocoa::AcceptAppModalDialog() {
+ NSButton* first = [[alert_ buttons] objectAtIndex:0];
+ [first performClick:nil];
+}
+
+void JSModalDialogCocoa::CancelAppModalDialog() {
+ DCHECK([[alert_ buttons] count] >= 2);
+ NSButton* second = [[alert_ buttons] objectAtIndex:1];
+ [second performClick:nil];
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeAppModalDialog, public:
+
+// static
+NativeAppModalDialog* NativeAppModalDialog::CreateNativeJavaScriptPrompt(
+ JavaScriptAppModalDialog* dialog,
+ gfx::NativeWindow parent_window) {
+ return new JSModalDialogCocoa(dialog);
+}
diff --git a/chrome/browser/ui/cocoa/keystone_glue.h b/chrome/browser/ui/cocoa/keystone_glue.h
new file mode 100644
index 0000000..c20bdb4
--- /dev/null
+++ b/chrome/browser/ui/cocoa/keystone_glue.h
@@ -0,0 +1,209 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_KEYSTONE_GLUE_H_
+#define CHROME_BROWSER_UI_COCOA_KEYSTONE_GLUE_H_
+#pragma once
+
+#include "base/string16.h"
+
+#if defined(__OBJC__)
+
+#import <Foundation/Foundation.h>
+
+#import "base/scoped_nsobject.h"
+#include "chrome/browser/ui/cocoa/scoped_authorizationref.h"
+
+// Possible outcomes of various operations. A version may accompany some of
+// these, but beware: a version is never required. For statuses that can be
+// accompanied by a version, the comment indicates what version is referenced.
+// A notification posted containing an asynchronous status will always be
+// followed by a notification with a terminal status.
+enum AutoupdateStatus {
+ kAutoupdateNone = 0, // no version (initial state only)
+ kAutoupdateRegistering, // no version (asynchronous operation in progress)
+ kAutoupdateRegistered, // no version
+ kAutoupdateChecking, // no version (asynchronous operation in progress)
+ kAutoupdateCurrent, // version of the running application
+ kAutoupdateAvailable, // version of the update that is available
+ kAutoupdateInstalling, // no version (asynchronous operation in progress)
+ kAutoupdateInstalled, // version of the update that was installed
+ kAutoupdatePromoting, // no version (asynchronous operation in progress)
+ kAutoupdatePromoted, // no version
+ kAutoupdateRegisterFailed, // no version
+ kAutoupdateCheckFailed, // no version
+ kAutoupdateInstallFailed, // no version
+ kAutoupdatePromoteFailed, // no version
+};
+
+// kAutoupdateStatusNotification is the name of the notification posted when
+// -checkForUpdate and -installUpdate complete. This notification will be
+// sent with with its sender object set to the KeystoneGlue instance sending
+// the notification. Its userInfo dictionary will contain an AutoupdateStatus
+// value as an intValue at key kAutoupdateStatusStatus. If a version is
+// available (see AutoupdateStatus), it will be present at key
+// kAutoupdateStatusVersion.
+extern NSString* const kAutoupdateStatusNotification;
+extern NSString* const kAutoupdateStatusStatus;
+extern NSString* const kAutoupdateStatusVersion;
+
+namespace {
+
+enum BrandFileType {
+ kBrandFileTypeNotDetermined = 0,
+ kBrandFileTypeNone,
+ kBrandFileTypeUser,
+ kBrandFileTypeSystem,
+};
+
+} // namespace
+
+// KeystoneGlue is an adapter around the KSRegistration class, allowing it to
+// be used without linking directly against its containing KeystoneRegistration
+// framework. This is used in an environment where most builds (such as
+// developer builds) don't want or need Keystone support and might not even
+// have the framework available. Enabling Keystone support in an application
+// that uses KeystoneGlue is as simple as dropping
+// KeystoneRegistration.framework in the application's Frameworks directory
+// and providing the relevant information in its Info.plist. KeystoneGlue
+// requires that the KSUpdateURL key be set in the application's Info.plist,
+// and that it contain a string identifying the update URL to be used by
+// Keystone.
+
+@class KSRegistration;
+
+@interface KeystoneGlue : NSObject {
+ @protected
+
+ // Data for Keystone registration
+ NSString* productID_;
+ NSString* appPath_;
+ NSString* url_;
+ NSString* version_;
+ NSString* channel_; // Logically: Dev, Beta, or Stable.
+ BrandFileType brandFileType_;
+
+ // And the Keystone registration itself, with the active timer
+ KSRegistration* registration_; // strong
+ NSTimer* timer_; // strong
+
+ // The most recent kAutoupdateStatusNotification notification posted.
+ scoped_nsobject<NSNotification> recentNotification_;
+
+ // The authorization object, when it needs to persist because it's being
+ // carried across threads.
+ scoped_AuthorizationRef authorization_;
+
+ // YES if a synchronous promotion operation is in progress (promotion during
+ // installation).
+ BOOL synchronousPromotion_;
+
+ // YES if an update was ever successfully installed by -installUpdate.
+ BOOL updateSuccessfullyInstalled_;
+}
+
+// Return the default Keystone Glue object.
++ (id)defaultKeystoneGlue;
+
+// Load KeystoneRegistration.framework if present, call into it to register
+// with Keystone, and set up periodic activity pings.
+- (void)registerWithKeystone;
+
+// -checkForUpdate launches a check for updates, and -installUpdate begins
+// installing an available update. For each, status will be communicated via
+// a kAutoupdateStatusNotification notification, and will also be available
+// through -recentNotification.
+- (void)checkForUpdate;
+- (void)installUpdate;
+
+// Accessor for recentNotification_. Returns an autoreleased NSNotification.
+- (NSNotification*)recentNotification;
+
+// Accessor for the kAutoupdateStatusStatus field of recentNotification_'s
+// userInfo dictionary.
+- (AutoupdateStatus)recentStatus;
+
+// Returns YES if an asynchronous operation is pending: if an update check or
+// installation attempt is currently in progress.
+- (BOOL)asyncOperationPending;
+
+// Returns YES if the application is running from a read-only filesystem,
+// such as a disk image.
+- (BOOL)isOnReadOnlyFilesystem;
+
+// -needsPromotion is YES if the application needs its ticket promoted to
+// a system ticket. This will be YES when the application is on a user
+// ticket and determines that the current user does not have sufficient
+// permission to perform the update.
+//
+// -wantsPromotion is YES if the application wants its ticket promoted to
+// a system ticket, even if it doesn't need it as determined by
+// -needsPromotion. -wantsPromotion will always be YES if -needsPromotion is,
+// and it will additionally be YES when the application is on a user ticket
+// and appears to be installed in a system-wide location such as
+// /Applications.
+//
+// Use -needsPromotion to decide whether to show any update UI at all. If
+// it's YES, there's no sense in asking the user to "update now" because it
+// will fail given the rights and permissions involved. On the other hand,
+// when -needsPromotion is YES, the application can encourage the user to
+// promote the ticket so that updates will work properly.
+//
+// Use -wantsPromotion to decide whether to allow the user to promote. The
+// user shouldn't be nagged about promotion on the basis of -wantsPromotion,
+// but if it's YES, the user should be allowed to promote the ticket.
+- (BOOL)needsPromotion;
+- (BOOL)wantsPromotion;
+
+// Promotes the Keystone ticket into the system store. System Keystone will
+// be installed if necessary. If synchronous is NO, the promotion may occur
+// in the background. synchronous should be YES for promotion during
+// installation. The KeystoneGlue object assumes ownership of
+// authorization_arg.
+- (void)promoteTicketWithAuthorization:(AuthorizationRef)authorization_arg
+ synchronous:(BOOL)synchronous;
+
+// Requests authorization and calls -promoteTicketWithAuthorization: in
+// asynchronous mode.
+- (void)promoteTicket;
+
+// Sets a new value for appPath. Used during installation to point a ticket
+// at the installed copy.
+- (void)setAppPath:(NSString*)appPath;
+
+@end // @interface KeystoneGlue
+
+@interface KeystoneGlue(ExposedForTesting)
+
+// Load any params we need for configuring Keystone.
+- (void)loadParameters;
+
+// Load the Keystone registration object.
+// Return NO on failure.
+- (BOOL)loadKeystoneRegistration;
+
+- (void)stopTimer;
+
+// Called when a checkForUpdate: notification completes.
+- (void)checkForUpdateComplete:(NSNotification*)notification;
+
+// Called when an installUpdate: notification completes.
+- (void)installUpdateComplete:(NSNotification*)notification;
+
+@end // @interface KeystoneGlue(ExposedForTesting)
+
+#endif // __OBJC__
+
+// Functions that may be accessed from non-Objective-C C/C++ code.
+namespace keystone_glue {
+
+// True if Keystone is enabled.
+bool KeystoneEnabled();
+
+// The version of the application currently installed on disk.
+string16 CurrentlyInstalledVersion();
+
+} // namespace keystone_glue
+
+#endif // CHROME_BROWSER_UI_COCOA_KEYSTONE_GLUE_H_
diff --git a/chrome/browser/ui/cocoa/keystone_glue.mm b/chrome/browser/ui/cocoa/keystone_glue.mm
new file mode 100644
index 0000000..b42375a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/keystone_glue.mm
@@ -0,0 +1,957 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/keystone_glue.h"
+
+#include <sys/param.h>
+#include <sys/mount.h>
+
+#include <vector>
+
+#include "app/l10n_util.h"
+#import "app/l10n_util_mac.h"
+#include "base/logging.h"
+#include "base/mac_util.h"
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/sys_string_conversions.h"
+#include "base/ref_counted.h"
+#include "base/task.h"
+#include "base/worker_pool.h"
+#include "chrome/browser/ui/cocoa/authorization_util.h"
+#include "chrome/common/chrome_constants.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+
+namespace {
+
+// Provide declarations of the Keystone registration bits needed here. From
+// KSRegistration.h.
+typedef enum {
+ kKSPathExistenceChecker,
+} KSExistenceCheckerType;
+
+typedef enum {
+ kKSRegistrationUserTicket,
+ kKSRegistrationSystemTicket,
+ kKSRegistrationDontKnowWhatKindOfTicket,
+} KSRegistrationTicketType;
+
+NSString* const KSRegistrationVersionKey = @"Version";
+NSString* const KSRegistrationExistenceCheckerTypeKey = @"ExistenceCheckerType";
+NSString* const KSRegistrationExistenceCheckerStringKey =
+ @"ExistenceCheckerString";
+NSString* const KSRegistrationServerURLStringKey = @"URLString";
+NSString* const KSRegistrationPreserveTrustedTesterTokenKey = @"PreserveTTT";
+NSString* const KSRegistrationTagKey = @"Tag";
+NSString* const KSRegistrationTagPathKey = @"TagPath";
+NSString* const KSRegistrationTagKeyKey = @"TagKey";
+NSString* const KSRegistrationBrandPathKey = @"BrandPath";
+NSString* const KSRegistrationBrandKeyKey = @"BrandKey";
+
+NSString* const KSRegistrationDidCompleteNotification =
+ @"KSRegistrationDidCompleteNotification";
+NSString* const KSRegistrationPromotionDidCompleteNotification =
+ @"KSRegistrationPromotionDidCompleteNotification";
+
+NSString* const KSRegistrationCheckForUpdateNotification =
+ @"KSRegistrationCheckForUpdateNotification";
+NSString* KSRegistrationStatusKey = @"Status";
+NSString* KSRegistrationUpdateCheckErrorKey = @"Error";
+
+NSString* const KSRegistrationStartUpdateNotification =
+ @"KSRegistrationStartUpdateNotification";
+NSString* const KSUpdateCheckSuccessfulKey = @"CheckSuccessful";
+NSString* const KSUpdateCheckSuccessfullyInstalledKey =
+ @"SuccessfullyInstalled";
+
+NSString* const KSRegistrationRemoveExistingTag = @"";
+#define KSRegistrationPreserveExistingTag nil
+
+// Constants for the brand file (uses an external file so it can survive updates
+// to Chrome.
+
+#if defined(GOOGLE_CHROME_BUILD)
+#define kBrandFileName @"Google Chrome Brand.plist";
+#elif defined(CHROMIUM_BUILD)
+#define kBrandFileName @"Chromium Brand.plist";
+#else
+#error Unknown branding
+#endif
+
+// These directories are hardcoded in Keystone promotion preflight and the
+// Keystone install script, so NSSearchPathForDirectoriesInDomains isn't used
+// since the scripts couldn't use anything like that.
+NSString* kBrandUserFile = @"~/Library/Google/" kBrandFileName;
+NSString* kBrandSystemFile = @"/Library/Google/" kBrandFileName;
+
+NSString* UserBrandFilePath() {
+ return [kBrandUserFile stringByStandardizingPath];
+}
+NSString* SystemBrandFilePath() {
+ return [kBrandSystemFile stringByStandardizingPath];
+}
+
+// Adaptor for scheduling an Objective-C method call on a |WorkerPool|
+// thread.
+class PerformBridge : public base::RefCountedThreadSafe<PerformBridge> {
+ public:
+
+ // Call |sel| on |target| with |arg| in a WorkerPool thread.
+ // |target| and |arg| are retained, |arg| may be |nil|.
+ static void PostPerform(id target, SEL sel, id arg) {
+ DCHECK(target);
+ DCHECK(sel);
+
+ scoped_refptr<PerformBridge> op = new PerformBridge(target, sel, arg);
+ WorkerPool::PostTask(
+ FROM_HERE, NewRunnableMethod(op.get(), &PerformBridge::Run), true);
+ }
+
+ // Convenience for the no-argument case.
+ static void PostPerform(id target, SEL sel) {
+ PostPerform(target, sel, nil);
+ }
+
+ private:
+ // Allow RefCountedThreadSafe<> to delete.
+ friend class base::RefCountedThreadSafe<PerformBridge>;
+
+ PerformBridge(id target, SEL sel, id arg)
+ : target_([target retain]),
+ sel_(sel),
+ arg_([arg retain]) {
+ }
+
+ ~PerformBridge() {}
+
+ // Happens on a WorkerPool thread.
+ void Run() {
+ base::mac::ScopedNSAutoreleasePool pool;
+ [target_ performSelector:sel_ withObject:arg_];
+ }
+
+ scoped_nsobject<id> target_;
+ SEL sel_;
+ scoped_nsobject<id> arg_;
+};
+
+} // namespace
+
+@interface KSRegistration : NSObject
+
++ (id)registrationWithProductID:(NSString*)productID;
+
+- (BOOL)registerWithParameters:(NSDictionary*)args;
+
+- (BOOL)promoteWithParameters:(NSDictionary*)args
+ authorization:(AuthorizationRef)authorization;
+
+- (void)setActive;
+- (void)checkForUpdate;
+- (void)startUpdate;
+- (KSRegistrationTicketType)ticketType;
+
+@end // @interface KSRegistration
+
+@interface KeystoneGlue(Private)
+
+// Returns the path to the application's Info.plist file. This returns the
+// outer application bundle's Info.plist, not the framework's Info.plist.
+- (NSString*)appInfoPlistPath;
+
+// Returns a dictionary containing parameters to be used for a KSRegistration
+// -registerWithParameters: or -promoteWithParameters:authorization: call.
+- (NSDictionary*)keystoneParameters;
+
+// Called when Keystone registration completes.
+- (void)registrationComplete:(NSNotification*)notification;
+
+// Called periodically to announce activity by pinging the Keystone server.
+- (void)markActive:(NSTimer*)timer;
+
+// Called when an update check or update installation is complete. Posts the
+// kAutoupdateStatusNotification notification to the default notification
+// center.
+- (void)updateStatus:(AutoupdateStatus)status version:(NSString*)version;
+
+// Returns the version of the currently-installed application on disk.
+- (NSString*)currentlyInstalledVersion;
+
+// These three methods are used to determine the version of the application
+// currently installed on disk, compare that to the currently-running version,
+// decide whether any updates have been installed, and call
+// -updateStatus:version:.
+//
+// In order to check the version on disk, the installed application's
+// Info.plist dictionary must be read; in order to see changes as updates are
+// applied, the dictionary must be read each time, bypassing any caches such
+// as the one that NSBundle might be maintaining. Reading files can be a
+// blocking operation, and blocking operations are to be avoided on the main
+// thread. I'm not quite sure what jank means, but I bet that a blocked main
+// thread would cause some of it.
+//
+// -determineUpdateStatusAsync is called on the main thread to initiate the
+// operation. It performs initial set-up work that must be done on the main
+// thread and arranges for -determineUpdateStatus to be called on a work queue
+// thread managed by WorkerPool.
+// -determineUpdateStatus then reads the Info.plist, gets the version from the
+// CFBundleShortVersionString key, and performs
+// -determineUpdateStatusForVersion: on the main thread.
+// -determineUpdateStatusForVersion: does the actual comparison of the version
+// on disk with the running version and calls -updateStatus:version: with the
+// results of its analysis.
+- (void)determineUpdateStatusAsync;
+- (void)determineUpdateStatus;
+- (void)determineUpdateStatusForVersion:(NSString*)version;
+
+// Returns YES if registration_ is definitely on a user ticket. If definitely
+// on a system ticket, or uncertain of ticket type (due to an older version
+// of Keystone being used), returns NO.
+- (BOOL)isUserTicket;
+
+// Called when ticket promotion completes.
+- (void)promotionComplete:(NSNotification*)notification;
+
+// Changes the application's ownership and permissions so that all files are
+// owned by root:wheel and all files and directories are writable only by
+// root, but readable and executable as needed by everyone.
+// -changePermissionsForPromotionAsync is called on the main thread by
+// -promotionComplete. That routine calls
+// -changePermissionsForPromotionWithTool: on a work queue thread. When done,
+// -changePermissionsForPromotionComplete is called on the main thread.
+- (void)changePermissionsForPromotionAsync;
+- (void)changePermissionsForPromotionWithTool:(NSString*)toolPath;
+- (void)changePermissionsForPromotionComplete;
+
+// Returns the brand file path to use for Keystone.
+- (NSString*)brandFilePath;
+
+@end // @interface KeystoneGlue(Private)
+
+NSString* const kAutoupdateStatusNotification = @"AutoupdateStatusNotification";
+NSString* const kAutoupdateStatusStatus = @"status";
+NSString* const kAutoupdateStatusVersion = @"version";
+
+namespace {
+
+NSString* const kChannelKey = @"KSChannelID";
+NSString* const kBrandKey = @"KSBrandID";
+
+} // namespace
+
+@implementation KeystoneGlue
+
++ (id)defaultKeystoneGlue {
+ static bool sTriedCreatingDefaultKeystoneGlue = false;
+ // TODO(jrg): use base::SingletonObjC<KeystoneGlue>
+ static KeystoneGlue* sDefaultKeystoneGlue = nil; // leaked
+
+ if (!sTriedCreatingDefaultKeystoneGlue) {
+ sTriedCreatingDefaultKeystoneGlue = true;
+
+ sDefaultKeystoneGlue = [[KeystoneGlue alloc] init];
+ [sDefaultKeystoneGlue loadParameters];
+ if (![sDefaultKeystoneGlue loadKeystoneRegistration]) {
+ [sDefaultKeystoneGlue release];
+ sDefaultKeystoneGlue = nil;
+ }
+ }
+ return sDefaultKeystoneGlue;
+}
+
+- (id)init {
+ if ((self = [super init])) {
+ NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+
+ [center addObserver:self
+ selector:@selector(registrationComplete:)
+ name:KSRegistrationDidCompleteNotification
+ object:nil];
+
+ [center addObserver:self
+ selector:@selector(promotionComplete:)
+ name:KSRegistrationPromotionDidCompleteNotification
+ object:nil];
+
+ [center addObserver:self
+ selector:@selector(checkForUpdateComplete:)
+ name:KSRegistrationCheckForUpdateNotification
+ object:nil];
+
+ [center addObserver:self
+ selector:@selector(installUpdateComplete:)
+ name:KSRegistrationStartUpdateNotification
+ object:nil];
+ }
+
+ return self;
+}
+
+- (void)dealloc {
+ [productID_ release];
+ [appPath_ release];
+ [url_ release];
+ [version_ release];
+ [channel_ release];
+ [registration_ release];
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+- (NSDictionary*)infoDictionary {
+ // Use [NSBundle mainBundle] to get the application's own bundle identifier
+ // and path, not the framework's. For auto-update, the application is
+ // what's significant here: it's used to locate the outermost part of the
+ // application for the existence checker and other operations that need to
+ // see the entire application bundle.
+ return [[NSBundle mainBundle] infoDictionary];
+}
+
+- (void)loadParameters {
+ NSBundle* appBundle = [NSBundle mainBundle];
+ NSDictionary* infoDictionary = [self infoDictionary];
+
+ NSString* productID = [infoDictionary objectForKey:@"KSProductID"];
+ if (productID == nil) {
+ productID = [appBundle bundleIdentifier];
+ }
+
+ NSString* appPath = [appBundle bundlePath];
+ NSString* url = [infoDictionary objectForKey:@"KSUpdateURL"];
+ NSString* version = [infoDictionary objectForKey:@"KSVersion"];
+
+ if (!productID || !appPath || !url || !version) {
+ // If parameters required for Keystone are missing, don't use it.
+ return;
+ }
+
+ NSString* channel = [infoDictionary objectForKey:kChannelKey];
+ // The stable channel has no tag. If updating to stable, remove the
+ // dev and beta tags since we've been "promoted".
+ if (channel == nil)
+ channel = KSRegistrationRemoveExistingTag;
+
+ productID_ = [productID retain];
+ appPath_ = [appPath retain];
+ url_ = [url retain];
+ version_ = [version retain];
+ channel_ = [channel retain];
+}
+
+- (NSString*)brandFilePath {
+ DCHECK(version_ != nil) << "-loadParameters must be called first";
+
+ if (brandFileType_ == kBrandFileTypeNotDetermined) {
+
+ // Default to none.
+ brandFileType_ = kBrandFileTypeNone;
+
+ // Having a channel means Dev/Beta, so there is no brand code to go with
+ // those.
+ if ([channel_ length] == 0) {
+
+ NSString* userBrandFile = UserBrandFilePath();
+ NSString* systemBrandFile = SystemBrandFilePath();
+
+ NSFileManager* fm = [NSFileManager defaultManager];
+
+ // If there is a system brand file, use it.
+ if ([fm fileExistsAtPath:systemBrandFile]) {
+ // System
+
+ // Use the system file that is there.
+ brandFileType_ = kBrandFileTypeSystem;
+
+ // Clean up any old user level file.
+ if ([fm fileExistsAtPath:userBrandFile]) {
+ [fm removeItemAtPath:userBrandFile error:NULL];
+ }
+
+ } else {
+ // User
+
+ NSDictionary* infoDictionary = [self infoDictionary];
+ NSString* appBundleBrandID = [infoDictionary objectForKey:kBrandKey];
+
+ NSString* storedBrandID = nil;
+ if ([fm fileExistsAtPath:userBrandFile]) {
+ NSDictionary* storedBrandDict =
+ [NSDictionary dictionaryWithContentsOfFile:userBrandFile];
+ storedBrandID = [storedBrandDict objectForKey:kBrandKey];
+ }
+
+ if ((appBundleBrandID != nil) &&
+ (![storedBrandID isEqualTo:appBundleBrandID])) {
+ // App and store don't match, update store and use it.
+ NSDictionary* storedBrandDict =
+ [NSDictionary dictionaryWithObject:appBundleBrandID
+ forKey:kBrandKey];
+ // If Keystone hasn't been installed yet, the location the brand file
+ // is written to won't exist, so manually create the directory.
+ NSString *userBrandFileDirectory =
+ [userBrandFile stringByDeletingLastPathComponent];
+ if (![fm fileExistsAtPath:userBrandFileDirectory]) {
+ if (![fm createDirectoryAtPath:userBrandFileDirectory
+ withIntermediateDirectories:YES
+ attributes:nil
+ error:NULL]) {
+ LOG(ERROR) << "Failed to create the directory for the brand file";
+ }
+ }
+ if ([storedBrandDict writeToFile:userBrandFile atomically:YES]) {
+ brandFileType_ = kBrandFileTypeUser;
+ }
+ } else if (storedBrandID) {
+ // Had stored brand, use it.
+ brandFileType_ = kBrandFileTypeUser;
+ }
+ }
+ }
+
+ }
+
+ NSString* result = nil;
+ switch (brandFileType_) {
+ case kBrandFileTypeUser:
+ result = UserBrandFilePath();
+ break;
+
+ case kBrandFileTypeSystem:
+ result = SystemBrandFilePath();
+ break;
+
+ case kBrandFileTypeNotDetermined:
+ NOTIMPLEMENTED();
+ // Fall through
+ case kBrandFileTypeNone:
+ // Clear the value.
+ result = @"";
+ break;
+
+ }
+ return result;
+}
+
+- (BOOL)loadKeystoneRegistration {
+ if (!productID_ || !appPath_ || !url_ || !version_)
+ return NO;
+
+ // Load the KeystoneRegistration framework bundle if present. It lives
+ // inside the framework, so use mac_util::MainAppBundle();
+ NSString* ksrPath =
+ [[mac_util::MainAppBundle() privateFrameworksPath]
+ stringByAppendingPathComponent:@"KeystoneRegistration.framework"];
+ NSBundle* ksrBundle = [NSBundle bundleWithPath:ksrPath];
+ [ksrBundle load];
+
+ // Harness the KSRegistration class.
+ Class ksrClass = [ksrBundle classNamed:@"KSRegistration"];
+ KSRegistration* ksr = [ksrClass registrationWithProductID:productID_];
+ if (!ksr)
+ return NO;
+
+ registration_ = [ksr retain];
+ return YES;
+}
+
+- (NSString*)appInfoPlistPath {
+ // NSBundle ought to have a way to access this path directly, but it
+ // doesn't.
+ return [[appPath_ stringByAppendingPathComponent:@"Contents"]
+ stringByAppendingPathComponent:@"Info.plist"];
+}
+
+- (NSDictionary*)keystoneParameters {
+ NSNumber* xcType = [NSNumber numberWithInt:kKSPathExistenceChecker];
+ NSNumber* preserveTTToken = [NSNumber numberWithBool:YES];
+ NSString* tagPath = [self appInfoPlistPath];
+
+ NSString* brandKey = kBrandKey;
+ NSString* brandPath = [self brandFilePath];
+
+ if ([brandPath length] == 0) {
+ // Brand path and brand key must be cleared together or ksadmin seems
+ // to throw an error.
+ brandKey = @"";
+ }
+
+ return [NSDictionary dictionaryWithObjectsAndKeys:
+ version_, KSRegistrationVersionKey,
+ xcType, KSRegistrationExistenceCheckerTypeKey,
+ appPath_, KSRegistrationExistenceCheckerStringKey,
+ url_, KSRegistrationServerURLStringKey,
+ preserveTTToken, KSRegistrationPreserveTrustedTesterTokenKey,
+ channel_, KSRegistrationTagKey,
+ tagPath, KSRegistrationTagPathKey,
+ kChannelKey, KSRegistrationTagKeyKey,
+ brandPath, KSRegistrationBrandPathKey,
+ brandKey, KSRegistrationBrandKeyKey,
+ nil];
+}
+
+- (void)registerWithKeystone {
+ [self updateStatus:kAutoupdateRegistering version:nil];
+
+ NSDictionary* parameters = [self keystoneParameters];
+ if (![registration_ registerWithParameters:parameters]) {
+ [self updateStatus:kAutoupdateRegisterFailed version:nil];
+ return;
+ }
+
+ // Upon completion, KSRegistrationDidCompleteNotification will be posted,
+ // and -registrationComplete: will be called.
+
+ // Mark an active RIGHT NOW; don't wait an hour for the first one.
+ [registration_ setActive];
+
+ // Set up hourly activity pings.
+ timer_ = [NSTimer scheduledTimerWithTimeInterval:60 * 60 // One hour
+ target:self
+ selector:@selector(markActive:)
+ userInfo:registration_
+ repeats:YES];
+}
+
+- (void)registrationComplete:(NSNotification*)notification {
+ NSDictionary* userInfo = [notification userInfo];
+ if ([[userInfo objectForKey:KSRegistrationStatusKey] boolValue]) {
+ [self updateStatus:kAutoupdateRegistered version:nil];
+ } else {
+ // Dump registration_?
+ [self updateStatus:kAutoupdateRegisterFailed version:nil];
+ }
+}
+
+- (void)stopTimer {
+ [timer_ invalidate];
+}
+
+- (void)markActive:(NSTimer*)timer {
+ KSRegistration* ksr = [timer userInfo];
+ [ksr setActive];
+}
+
+- (void)checkForUpdate {
+ DCHECK(![self asyncOperationPending]);
+
+ if (!registration_) {
+ [self updateStatus:kAutoupdateCheckFailed version:nil];
+ return;
+ }
+
+ [self updateStatus:kAutoupdateChecking version:nil];
+
+ [registration_ checkForUpdate];
+
+ // Upon completion, KSRegistrationCheckForUpdateNotification will be posted,
+ // and -checkForUpdateComplete: will be called.
+}
+
+- (void)checkForUpdateComplete:(NSNotification*)notification {
+ NSDictionary* userInfo = [notification userInfo];
+
+ if ([[userInfo objectForKey:KSRegistrationUpdateCheckErrorKey] boolValue]) {
+ [self updateStatus:kAutoupdateCheckFailed version:nil];
+ } else if ([[userInfo objectForKey:KSRegistrationStatusKey] boolValue]) {
+ // If an update is known to be available, go straight to
+ // -updateStatus:version:. It doesn't matter what's currently on disk.
+ NSString* version = [userInfo objectForKey:KSRegistrationVersionKey];
+ [self updateStatus:kAutoupdateAvailable version:version];
+ } else {
+ // If no updates are available, check what's on disk, because an update
+ // may have already been installed. This check happens on another thread,
+ // and -updateStatus:version: will be called on the main thread when done.
+ [self determineUpdateStatusAsync];
+ }
+}
+
+- (void)installUpdate {
+ DCHECK(![self asyncOperationPending]);
+
+ if (!registration_) {
+ [self updateStatus:kAutoupdateInstallFailed version:nil];
+ return;
+ }
+
+ [self updateStatus:kAutoupdateInstalling version:nil];
+
+ [registration_ startUpdate];
+
+ // Upon completion, KSRegistrationStartUpdateNotification will be posted,
+ // and -installUpdateComplete: will be called.
+}
+
+- (void)installUpdateComplete:(NSNotification*)notification {
+ NSDictionary* userInfo = [notification userInfo];
+
+ if (![[userInfo objectForKey:KSUpdateCheckSuccessfulKey] boolValue] ||
+ ![[userInfo objectForKey:KSUpdateCheckSuccessfullyInstalledKey]
+ intValue]) {
+ [self updateStatus:kAutoupdateInstallFailed version:nil];
+ } else {
+ updateSuccessfullyInstalled_ = YES;
+
+ // Nothing in the notification dictionary reports the version that was
+ // installed. Figure it out based on what's on disk.
+ [self determineUpdateStatusAsync];
+ }
+}
+
+- (NSString*)currentlyInstalledVersion {
+ NSString* appInfoPlistPath = [self appInfoPlistPath];
+ NSDictionary* infoPlist =
+ [NSDictionary dictionaryWithContentsOfFile:appInfoPlistPath];
+ return [infoPlist objectForKey:@"CFBundleShortVersionString"];
+}
+
+// Runs on the main thread.
+- (void)determineUpdateStatusAsync {
+ DCHECK([NSThread isMainThread]);
+
+ PerformBridge::PostPerform(self, @selector(determineUpdateStatus));
+}
+
+// Runs on a thread managed by WorkerPool.
+- (void)determineUpdateStatus {
+ DCHECK(![NSThread isMainThread]);
+
+ NSString* version = [self currentlyInstalledVersion];
+
+ [self performSelectorOnMainThread:@selector(determineUpdateStatusForVersion:)
+ withObject:version
+ waitUntilDone:NO];
+}
+
+// Runs on the main thread.
+- (void)determineUpdateStatusForVersion:(NSString*)version {
+ DCHECK([NSThread isMainThread]);
+
+ AutoupdateStatus status;
+ if (updateSuccessfullyInstalled_) {
+ // If an update was successfully installed and this object saw it happen,
+ // then don't even bother comparing versions.
+ status = kAutoupdateInstalled;
+ } else {
+ NSString* currentVersion =
+ [NSString stringWithUTF8String:chrome::kChromeVersion];
+ if (!version) {
+ // If the version on disk could not be determined, assume that
+ // whatever's running is current.
+ version = currentVersion;
+ status = kAutoupdateCurrent;
+ } else if ([version isEqualToString:currentVersion]) {
+ status = kAutoupdateCurrent;
+ } else {
+ // If the version on disk doesn't match what's currently running, an
+ // update must have been applied in the background, without this app's
+ // direct participation. Leave updateSuccessfullyInstalled_ alone
+ // because there's no direct knowledge of what actually happened.
+ status = kAutoupdateInstalled;
+ }
+ }
+
+ [self updateStatus:status version:version];
+}
+
+- (void)updateStatus:(AutoupdateStatus)status version:(NSString*)version {
+ NSNumber* statusNumber = [NSNumber numberWithInt:status];
+ NSMutableDictionary* dictionary =
+ [NSMutableDictionary dictionaryWithObject:statusNumber
+ forKey:kAutoupdateStatusStatus];
+ if (version) {
+ [dictionary setObject:version forKey:kAutoupdateStatusVersion];
+ }
+
+ NSNotification* notification =
+ [NSNotification notificationWithName:kAutoupdateStatusNotification
+ object:self
+ userInfo:dictionary];
+ recentNotification_.reset([notification retain]);
+
+ [[NSNotificationCenter defaultCenter] postNotification:notification];
+}
+
+- (NSNotification*)recentNotification {
+ return [[recentNotification_ retain] autorelease];
+}
+
+- (AutoupdateStatus)recentStatus {
+ NSDictionary* dictionary = [recentNotification_ userInfo];
+ return static_cast<AutoupdateStatus>(
+ [[dictionary objectForKey:kAutoupdateStatusStatus] intValue]);
+}
+
+- (BOOL)asyncOperationPending {
+ AutoupdateStatus status = [self recentStatus];
+ return status == kAutoupdateRegistering ||
+ status == kAutoupdateChecking ||
+ status == kAutoupdateInstalling ||
+ status == kAutoupdatePromoting;
+}
+
+- (BOOL)isUserTicket {
+ return [registration_ ticketType] == kKSRegistrationUserTicket;
+}
+
+- (BOOL)isOnReadOnlyFilesystem {
+ const char* appPathC = [appPath_ fileSystemRepresentation];
+ struct statfs statfsBuf;
+
+ if (statfs(appPathC, &statfsBuf) != 0) {
+ PLOG(ERROR) << "statfs";
+ // Be optimistic about the filesystem's writability.
+ return NO;
+ }
+
+ return (statfsBuf.f_flags & MNT_RDONLY) != 0;
+}
+
+- (BOOL)needsPromotion {
+ if (![self isUserTicket] || [self isOnReadOnlyFilesystem]) {
+ return NO;
+ }
+
+ // Check the outermost bundle directory, the main executable path, and the
+ // framework directory. It may be enough to just look at the outermost
+ // bundle directory, but checking an interior file and directory can be
+ // helpful in case permissions are set differently only on the outermost
+ // directory. An interior file and directory are both checked because some
+ // file operations, such as Snow Leopard's Finder's copy operation when
+ // authenticating, may actually result in different ownership being applied
+ // to files and directories.
+ NSFileManager* fileManager = [NSFileManager defaultManager];
+ NSString* executablePath = [[NSBundle mainBundle] executablePath];
+ NSString* frameworkPath = [mac_util::MainAppBundle() bundlePath];
+ return ![fileManager isWritableFileAtPath:appPath_] ||
+ ![fileManager isWritableFileAtPath:executablePath] ||
+ ![fileManager isWritableFileAtPath:frameworkPath];
+}
+
+- (BOOL)wantsPromotion {
+ // -needsPromotion checks these too, but this method doesn't necessarily
+ // return NO just becuase -needsPromotion returns NO, so another check is
+ // needed here.
+ if (![self isUserTicket] || [self isOnReadOnlyFilesystem]) {
+ return NO;
+ }
+
+ if ([self needsPromotion]) {
+ return YES;
+ }
+
+ return [appPath_ hasPrefix:@"/Applications/"];
+}
+
+- (void)promoteTicket {
+ if ([self asyncOperationPending] || ![self wantsPromotion]) {
+ // Because there are multiple ways of reaching promoteTicket that might
+ // not lock each other out, it may be possible to arrive here while an
+ // asynchronous operation is pending, or even after promotion has already
+ // occurred. Just quietly return without doing anything.
+ return;
+ }
+
+ NSString* prompt = l10n_util::GetNSStringFWithFixup(
+ IDS_PROMOTE_AUTHENTICATION_PROMPT,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
+ scoped_AuthorizationRef authorization(
+ authorization_util::AuthorizationCreateToRunAsRoot(
+ reinterpret_cast<CFStringRef>(prompt)));
+ if (!authorization.get()) {
+ return;
+ }
+
+ [self promoteTicketWithAuthorization:authorization.release() synchronous:NO];
+}
+
+- (void)promoteTicketWithAuthorization:(AuthorizationRef)authorization_arg
+ synchronous:(BOOL)synchronous {
+ scoped_AuthorizationRef authorization(authorization_arg);
+ authorization_arg = NULL;
+
+ if ([self asyncOperationPending]) {
+ // Starting a synchronous operation while an asynchronous one is pending
+ // could be trouble.
+ return;
+ }
+ if (!synchronous && ![self wantsPromotion]) {
+ // If operating synchronously, the call came from the installer, which
+ // means that a system ticket is required. Otherwise, only allow
+ // promotion if it's wanted.
+ return;
+ }
+
+ synchronousPromotion_ = synchronous;
+
+ [self updateStatus:kAutoupdatePromoting version:nil];
+
+ // TODO(mark): Remove when able!
+ //
+ // keystone_promote_preflight will copy the current brand information out to
+ // the system level so all users can share the data as part of the ticket
+ // promotion.
+ //
+ // It will also ensure that the Keystone system ticket store is in a usable
+ // state for all users on the system. Ideally, Keystone's installer or
+ // another part of Keystone would handle this. The underlying problem is
+ // http://b/2285921, and it causes http://b/2289908, which this workaround
+ // addresses.
+ //
+ // This is run synchronously, which isn't optimal, but
+ // -[KSRegistration promoteWithParameters:authorization:] is currently
+ // synchronous too, and this operation needs to happen before that one.
+ //
+ // TODO(mark): Make asynchronous. That only makes sense if the promotion
+ // operation itself is asynchronous too. http://b/2290009. Hopefully,
+ // the Keystone promotion code will just be changed to do what preflight
+ // now does, and then the preflight script can be removed instead.
+ // However, preflight operation (and promotion) should only be asynchronous
+ // if the synchronous parameter is NO.
+ NSString* preflightPath =
+ [mac_util::MainAppBundle() pathForResource:@"keystone_promote_preflight"
+ ofType:@"sh"];
+ const char* preflightPathC = [preflightPath fileSystemRepresentation];
+ const char* userBrandFile = NULL;
+ const char* systemBrandFile = NULL;
+ if (brandFileType_ == kBrandFileTypeUser) {
+ // Running with user level brand file, promote to the system level.
+ userBrandFile = [UserBrandFilePath() fileSystemRepresentation];
+ systemBrandFile = [SystemBrandFilePath() fileSystemRepresentation];
+ }
+ const char* arguments[] = {userBrandFile, systemBrandFile, NULL};
+
+ int exit_status;
+ OSStatus status = authorization_util::ExecuteWithPrivilegesAndWait(
+ authorization,
+ preflightPathC,
+ kAuthorizationFlagDefaults,
+ arguments,
+ NULL, // pipe
+ &exit_status);
+ if (status != errAuthorizationSuccess) {
+ LOG(ERROR) << "AuthorizationExecuteWithPrivileges preflight: " << status;
+ [self updateStatus:kAutoupdatePromoteFailed version:nil];
+ return;
+ }
+ if (exit_status != 0) {
+ LOG(ERROR) << "keystone_promote_preflight status " << exit_status;
+ [self updateStatus:kAutoupdatePromoteFailed version:nil];
+ return;
+ }
+
+ // Hang on to the AuthorizationRef so that it can be used once promotion is
+ // complete. Do this before asking Keystone to promote the ticket, because
+ // -promotionComplete: may be called from inside the Keystone promotion
+ // call.
+ authorization_.swap(authorization);
+
+ NSDictionary* parameters = [self keystoneParameters];
+
+ // If the brand file is user level, update parameters to point to the new
+ // system level file during promotion.
+ if (brandFileType_ == kBrandFileTypeUser) {
+ NSMutableDictionary* temp_parameters =
+ [[parameters mutableCopy] autorelease];
+ [temp_parameters setObject:SystemBrandFilePath()
+ forKey:KSRegistrationBrandPathKey];
+ parameters = temp_parameters;
+ }
+
+ if (![registration_ promoteWithParameters:parameters
+ authorization:authorization_]) {
+ [self updateStatus:kAutoupdatePromoteFailed version:nil];
+ authorization_.reset();
+ return;
+ }
+
+ // Upon completion, KSRegistrationPromotionDidCompleteNotification will be
+ // posted, and -promotionComplete: will be called.
+}
+
+- (void)promotionComplete:(NSNotification*)notification {
+ NSDictionary* userInfo = [notification userInfo];
+ if ([[userInfo objectForKey:KSRegistrationStatusKey] boolValue]) {
+ if (synchronousPromotion_) {
+ // Short-circuit: if performing a synchronous promotion, the promotion
+ // came from the installer, which already set the permissions properly.
+ // Rather than run a duplicate permission-changing operation, jump
+ // straight to "done."
+ [self changePermissionsForPromotionComplete];
+ } else {
+ [self changePermissionsForPromotionAsync];
+ }
+ } else {
+ authorization_.reset();
+ [self updateStatus:kAutoupdatePromoteFailed version:nil];
+ }
+}
+
+- (void)changePermissionsForPromotionAsync {
+ // NSBundle is not documented as being thread-safe. Do NSBundle operations
+ // on the main thread before jumping over to a WorkerPool-managed
+ // thread to run the tool.
+ DCHECK([NSThread isMainThread]);
+
+ SEL selector = @selector(changePermissionsForPromotionWithTool:);
+ NSString* toolPath =
+ [mac_util::MainAppBundle() pathForResource:@"keystone_promote_postflight"
+ ofType:@"sh"];
+
+ PerformBridge::PostPerform(self, selector, toolPath);
+}
+
+- (void)changePermissionsForPromotionWithTool:(NSString*)toolPath {
+ const char* toolPathC = [toolPath fileSystemRepresentation];
+
+ const char* appPathC = [appPath_ fileSystemRepresentation];
+ const char* arguments[] = {appPathC, NULL};
+
+ int exit_status;
+ OSStatus status = authorization_util::ExecuteWithPrivilegesAndWait(
+ authorization_,
+ toolPathC,
+ kAuthorizationFlagDefaults,
+ arguments,
+ NULL, // pipe
+ &exit_status);
+ if (status != errAuthorizationSuccess) {
+ LOG(ERROR) << "AuthorizationExecuteWithPrivileges postflight: " << status;
+ } else if (exit_status != 0) {
+ LOG(ERROR) << "keystone_promote_postflight status " << exit_status;
+ }
+
+ SEL selector = @selector(changePermissionsForPromotionComplete);
+ [self performSelectorOnMainThread:selector
+ withObject:nil
+ waitUntilDone:NO];
+}
+
+- (void)changePermissionsForPromotionComplete {
+ authorization_.reset();
+
+ [self updateStatus:kAutoupdatePromoted version:nil];
+}
+
+- (void)setAppPath:(NSString*)appPath {
+ if (appPath != appPath_) {
+ [appPath_ release];
+ appPath_ = [appPath copy];
+ }
+}
+
+@end // @implementation KeystoneGlue
+
+namespace keystone_glue {
+
+bool KeystoneEnabled() {
+ return [KeystoneGlue defaultKeystoneGlue] != nil;
+}
+
+string16 CurrentlyInstalledVersion() {
+ KeystoneGlue* keystoneGlue = [KeystoneGlue defaultKeystoneGlue];
+ NSString* version = [keystoneGlue currentlyInstalledVersion];
+ return base::SysNSStringToUTF16(version);
+}
+
+} // namespace keystone_glue
diff --git a/chrome/browser/ui/cocoa/keystone_glue_unittest.mm b/chrome/browser/ui/cocoa/keystone_glue_unittest.mm
new file mode 100644
index 0000000..c4a26f4
--- /dev/null
+++ b/chrome/browser/ui/cocoa/keystone_glue_unittest.mm
@@ -0,0 +1,184 @@
+// Copyright (c) 2009 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 <Foundation/Foundation.h>
+#import <objc/objc-class.h>
+
+#import "chrome/browser/ui/cocoa/keystone_glue.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+@interface FakeGlueRegistration : NSObject
+@end
+
+
+@implementation FakeGlueRegistration
+
+// Send the notifications that a real KeystoneGlue object would send.
+
+- (void)checkForUpdate {
+ NSNumber* yesNumber = [NSNumber numberWithBool:YES];
+ NSString* statusKey = @"Status";
+ NSDictionary* dictionary = [NSDictionary dictionaryWithObject:yesNumber
+ forKey:statusKey];
+ NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+ [center postNotificationName:@"KSRegistrationCheckForUpdateNotification"
+ object:nil
+ userInfo:dictionary];
+}
+
+- (void)startUpdate {
+ NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+ [center postNotificationName:@"KSRegistrationStartUpdateNotification"
+ object:nil];
+}
+
+@end
+
+
+@interface FakeKeystoneGlue : KeystoneGlue {
+ @public
+ BOOL upToDate_;
+ NSString *latestVersion_;
+ BOOL successful_;
+ int installs_;
+}
+
+- (void)fakeAboutWindowCallback:(NSNotification*)notification;
+@end
+
+
+@implementation FakeKeystoneGlue
+
+- (id)init {
+ if ((self = [super init])) {
+ // some lies
+ upToDate_ = YES;
+ latestVersion_ = @"foo bar";
+ successful_ = YES;
+ installs_ = 1010101010;
+
+ // Set up an observer that takes the notification that the About window
+ // listens for.
+ NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+ [center addObserver:self
+ selector:@selector(fakeAboutWindowCallback:)
+ name:kAutoupdateStatusNotification
+ object:nil];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+// For mocking
+- (NSDictionary*)infoDictionary {
+ NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
+ @"http://foo.bar", @"KSUpdateURL",
+ @"com.google.whatever", @"KSProductID",
+ @"0.0.0.1", @"KSVersion",
+ nil];
+ return dict;
+}
+
+// For mocking
+- (BOOL)loadKeystoneRegistration {
+ return YES;
+}
+
+// Confirms certain things are happy
+- (BOOL)dictReadCorrectly {
+ return ([url_ isEqual:@"http://foo.bar"] &&
+ [productID_ isEqual:@"com.google.whatever"] &&
+ [version_ isEqual:@"0.0.0.1"]);
+}
+
+// Confirms certain things are happy
+- (BOOL)hasATimer {
+ return timer_ ? YES : NO;
+}
+
+- (void)addFakeRegistration {
+ registration_ = [[FakeGlueRegistration alloc] init];
+}
+
+- (void)fakeAboutWindowCallback:(NSNotification*)notification {
+ NSDictionary* dictionary = [notification userInfo];
+ AutoupdateStatus status = static_cast<AutoupdateStatus>(
+ [[dictionary objectForKey:kAutoupdateStatusStatus] intValue]);
+
+ if (status == kAutoupdateAvailable) {
+ upToDate_ = NO;
+ latestVersion_ = [dictionary objectForKey:kAutoupdateStatusVersion];
+ } else if (status == kAutoupdateInstallFailed) {
+ successful_ = NO;
+ installs_ = 0;
+ }
+}
+
+// Confirm we look like callbacks with nil NSNotifications
+- (BOOL)confirmCallbacks {
+ return (!upToDate_ &&
+ (latestVersion_ == nil) &&
+ !successful_ &&
+ (installs_ == 0));
+}
+
+@end
+
+
+namespace {
+
+class KeystoneGlueTest : public PlatformTest {
+};
+
+// DISABLED because the mocking isn't currently working.
+TEST_F(KeystoneGlueTest, DISABLED_BasicGlobalCreate) {
+ // Allow creation of a KeystoneGlue by mocking out a few calls
+ SEL ids = @selector(infoDictionary);
+ IMP oldInfoImp_ = [[KeystoneGlue class] instanceMethodForSelector:ids];
+ IMP newInfoImp_ = [[FakeKeystoneGlue class] instanceMethodForSelector:ids];
+ Method infoMethod_ = class_getInstanceMethod([KeystoneGlue class], ids);
+ method_setImplementation(infoMethod_, newInfoImp_);
+
+ SEL lks = @selector(loadKeystoneRegistration);
+ IMP oldLoadImp_ = [[KeystoneGlue class] instanceMethodForSelector:lks];
+ IMP newLoadImp_ = [[FakeKeystoneGlue class] instanceMethodForSelector:lks];
+ Method loadMethod_ = class_getInstanceMethod([KeystoneGlue class], lks);
+ method_setImplementation(loadMethod_, newLoadImp_);
+
+ KeystoneGlue *glue = [KeystoneGlue defaultKeystoneGlue];
+ ASSERT_TRUE(glue);
+
+ // Fix back up the class to the way we found it.
+ method_setImplementation(infoMethod_, oldInfoImp_);
+ method_setImplementation(loadMethod_, oldLoadImp_);
+}
+
+// DISABLED because the mocking isn't currently working.
+TEST_F(KeystoneGlueTest, DISABLED_BasicUse) {
+ FakeKeystoneGlue* glue = [[[FakeKeystoneGlue alloc] init] autorelease];
+ [glue loadParameters];
+ ASSERT_TRUE([glue dictReadCorrectly]);
+
+ // Likely returns NO in the unit test, but call it anyway to make
+ // sure it doesn't crash.
+ [glue loadKeystoneRegistration];
+
+ // Confirm we start up an active timer
+ [glue registerWithKeystone];
+ ASSERT_TRUE([glue hasATimer]);
+ [glue stopTimer];
+
+ // Brief exercise of callbacks
+ [glue addFakeRegistration];
+ [glue checkForUpdate];
+ [glue installUpdate];
+ ASSERT_TRUE([glue confirmCallbacks]);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/keystone_infobar.h b/chrome/browser/ui/cocoa/keystone_infobar.h
new file mode 100644
index 0000000..61596ac
--- /dev/null
+++ b/chrome/browser/ui/cocoa/keystone_infobar.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_KEYSTONE_INFOBAR_H_
+#define CHROME_BROWSER_UI_COCOA_KEYSTONE_INFOBAR_H_
+#pragma once
+
+class Profile;
+
+class KeystoneInfoBar {
+ public:
+ // If the application is Keystone-enabled and not on a read-only filesystem
+ // (capable of being auto-updated), and Keystone indicates that it needs
+ // ticket promotion, PromotionInfoBar displays an info bar asking the user
+ // to promote the ticket. The user will need to authenticate in order to
+ // gain authorization to perform the promotion. The info bar is not shown
+ // if its "don't ask" button was ever clicked, if the "don't check default
+ // browser" command-line flag is present, on the very first launch, or if
+ // another info bar is already showing in the active tab.
+ static void PromotionInfoBar(Profile* profile);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_KEYSTONE_INFOBAR_H_
diff --git a/chrome/browser/ui/cocoa/keystone_infobar.mm b/chrome/browser/ui/cocoa/keystone_infobar.mm
new file mode 100644
index 0000000..09c0d8c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/keystone_infobar.mm
@@ -0,0 +1,212 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/keystone_infobar.h"
+
+#import <AppKit/AppKit.h>
+
+#include <string>
+
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/command_line.h"
+#include "base/message_loop.h"
+#include "base/task.h"
+#include "chrome/browser/first_run/first_run.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/infobar_delegate.h"
+#include "chrome/browser/tab_contents/navigation_controller.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#import "chrome/browser/ui/cocoa/keystone_glue.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+
+class SkBitmap;
+
+namespace {
+
+class KeystonePromotionInfoBarDelegate : public ConfirmInfoBarDelegate {
+ public:
+ KeystonePromotionInfoBarDelegate(TabContents* tab_contents)
+ : ConfirmInfoBarDelegate(tab_contents),
+ profile_(tab_contents->profile()),
+ can_expire_(false),
+ ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
+ const int kCanExpireOnNavigationAfterMilliseconds = 8 * 1000;
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &KeystonePromotionInfoBarDelegate::SetCanExpire),
+ kCanExpireOnNavigationAfterMilliseconds);
+ }
+
+ virtual ~KeystonePromotionInfoBarDelegate() {}
+
+ // Inherited from InfoBarDelegate and overridden.
+
+ virtual bool ShouldExpire(
+ const NavigationController::LoadCommittedDetails& details) {
+ return can_expire_;
+ }
+
+ virtual void InfoBarClosed() {
+ delete this;
+ }
+
+ // Inherited from AlertInfoBarDelegate and overridden.
+
+ virtual string16 GetMessageText() const {
+ return l10n_util::GetStringFUTF16(IDS_PROMOTE_INFOBAR_TEXT,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
+ }
+
+ virtual SkBitmap* GetIcon() const {
+ return ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_PRODUCT_ICON_32);
+ }
+
+ // Inherited from ConfirmInfoBarDelegate and overridden.
+
+ virtual int GetButtons() const {
+ return BUTTON_OK | BUTTON_CANCEL | BUTTON_OK_DEFAULT;
+ }
+
+ virtual string16 GetButtonLabel(InfoBarButton button) const {
+ return button == BUTTON_OK ?
+ l10n_util::GetStringUTF16(IDS_PROMOTE_INFOBAR_PROMOTE_BUTTON) :
+ l10n_util::GetStringUTF16(IDS_PROMOTE_INFOBAR_DONT_ASK_BUTTON);
+ }
+
+ virtual bool Accept() {
+ [[KeystoneGlue defaultKeystoneGlue] promoteTicket];
+ return true;
+ }
+
+ virtual bool Cancel() {
+ profile_->GetPrefs()->SetBoolean(prefs::kShowUpdatePromotionInfoBar, false);
+ return true;
+ }
+
+ private:
+ // Sets this info bar to be able to expire. Called a predetermined amount
+ // of time after this object is created.
+ void SetCanExpire() {
+ can_expire_ = true;
+ }
+
+ // The TabContents' profile.
+ Profile* profile_; // weak
+
+ // Whether the info bar should be dismissed on the next navigation.
+ bool can_expire_;
+
+ // Used to delay the expiration of the info bar.
+ ScopedRunnableMethodFactory<KeystonePromotionInfoBarDelegate> method_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(KeystonePromotionInfoBarDelegate);
+};
+
+} // namespace
+
+@interface KeystonePromotionInfoBar : NSObject
+- (void)checkAndShowInfoBarForProfile:(Profile*)profile;
+- (void)updateStatus:(NSNotification*)notification;
+- (void)removeObserver;
+@end // @interface KeystonePromotionInfoBar
+
+@implementation KeystonePromotionInfoBar
+
+- (void)dealloc {
+ [self removeObserver];
+ [super dealloc];
+}
+
+- (void)checkAndShowInfoBarForProfile:(Profile*)profile {
+ // If this is the first run, the user clicked the "don't ask again" button
+ // at some point in the past, or if the "don't ask about the default
+ // browser" command-line switch is present, bail out. That command-line
+ // switch is recycled here because it's likely that the set of users that
+ // don't want to be nagged about the default browser also don't want to be
+ // nagged about the update check. (Automated testers, I'm thinking of
+ // you...)
+ CommandLine* commandLine = CommandLine::ForCurrentProcess();
+ if (FirstRun::IsChromeFirstRun() ||
+ !profile->GetPrefs()->GetBoolean(prefs::kShowUpdatePromotionInfoBar) ||
+ commandLine->HasSwitch(switches::kNoDefaultBrowserCheck)) {
+ return;
+ }
+
+ // If there is no Keystone glue (maybe because this application isn't
+ // Keystone-enabled) or the application is on a read-only filesystem,
+ // doing anything related to auto-update is pointless. Bail out.
+ KeystoneGlue* keystoneGlue = [KeystoneGlue defaultKeystoneGlue];
+ if (!keystoneGlue || [keystoneGlue isOnReadOnlyFilesystem]) {
+ return;
+ }
+
+ // Stay alive as long as needed. This is balanced by a release in
+ // -updateStatus:.
+ [self retain];
+
+ AutoupdateStatus recentStatus = [keystoneGlue recentStatus];
+ if (recentStatus == kAutoupdateNone ||
+ recentStatus == kAutoupdateRegistering) {
+ NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+ [center addObserver:self
+ selector:@selector(updateStatus:)
+ name:kAutoupdateStatusNotification
+ object:nil];
+ } else {
+ [self updateStatus:[keystoneGlue recentNotification]];
+ }
+}
+
+- (void)updateStatus:(NSNotification*)notification {
+ NSDictionary* dictionary = [notification userInfo];
+ AutoupdateStatus status = static_cast<AutoupdateStatus>(
+ [[dictionary objectForKey:kAutoupdateStatusStatus] intValue]);
+
+ if (status == kAutoupdateNone || status == kAutoupdateRegistering) {
+ return;
+ }
+
+ [self removeObserver];
+
+ if (status != kAutoupdateRegisterFailed &&
+ [[KeystoneGlue defaultKeystoneGlue] needsPromotion]) {
+ Browser* browser = BrowserList::GetLastActive();
+ if (browser) {
+ TabContents* tabContents = browser->GetSelectedTabContents();
+
+ // Only show if no other info bars are showing, because that's how the
+ // default browser info bar works.
+ if (tabContents && tabContents->infobar_delegate_count() == 0) {
+ tabContents->AddInfoBar(
+ new KeystonePromotionInfoBarDelegate(tabContents));
+ }
+ }
+ }
+
+ [self release];
+}
+
+- (void)removeObserver {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+@end // @implementation KeystonePromotionInfoBar
+
+// static
+void KeystoneInfoBar::PromotionInfoBar(Profile* profile) {
+ KeystonePromotionInfoBar* promotionInfoBar =
+ [[[KeystonePromotionInfoBar alloc] init] autorelease];
+
+ [promotionInfoBar checkAndShowInfoBarForProfile:profile];
+}
diff --git a/chrome/browser/ui/cocoa/keystone_promote_postflight.sh b/chrome/browser/ui/cocoa/keystone_promote_postflight.sh
new file mode 100755
index 0000000..44799f8
--- /dev/null
+++ b/chrome/browser/ui/cocoa/keystone_promote_postflight.sh
@@ -0,0 +1,55 @@
+#!/bin/bash -p
+
+# Copyright (c) 2009 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.
+
+# Called as root after Keystone ticket promotion to change the owner, group,
+# and permissions on the application. The application bundle and its contents
+# are set to owner root, group wheel, and to be writable only by root, but
+# readable and executable (when appropriate) by everyone.
+#
+# Note that this script will be invoked with the real user ID set to the
+# user's ID, but the effective user ID set to 0 (root). bash -p is used on
+# the first line to prevent bash from setting the effective user ID to the
+# real user ID (dropping root privileges).
+#
+# WARNING: This script is NOT currently run when the Keystone ticket is
+# promoted during application installation directly from the disk image,
+# because the installation process itself handles the same permission fix-ups
+# that this script normally would.
+
+set -e
+
+# This script runs as root, so be paranoid about things like ${PATH}.
+export PATH="/usr/bin:/usr/sbin:/bin:/sbin"
+
+# Output the pid to stdout before doing anything else. See
+# chrome/browser/ui/cocoa/authorization_util.h.
+echo "${$}"
+
+if [ ${#} -ne 1 ] ; then
+ echo "usage: ${0} APP" >& 2
+ exit 2
+fi
+
+APP="${1}"
+
+# Make sure that APP is an absolute path and that it exists.
+if [ -z "${APP}" ] || [ "${APP:0:1}" != "/" ] || [ ! -d "${APP}" ] ; then
+ echo "${0}: must provide an absolute path naming an extant directory" >& 2
+ exit 3
+fi
+
+OWNER_GROUP="root:wheel"
+chown -Rh "${OWNER_GROUP}" "${APP}" >& /dev/null
+
+CHMOD_MODE="a+rX,u+w,go-w"
+chmod -R "${CHMOD_MODE}" "${APP}" >& /dev/null
+
+# On the Mac, or at least on HFS+, symbolic link permissions are significant,
+# but chmod -R and -h can't be used together. Do another pass to fix the
+# permissions on any symbolic links.
+find "${APP}" -type l -exec chmod -h "${CHMOD_MODE}" {} + >& /dev/null
+
+exit 0
diff --git a/chrome/browser/cocoa/keystone_promote_preflight.sh b/chrome/browser/ui/cocoa/keystone_promote_preflight.sh
index 4bf31e8..4bf31e8 100755
--- a/chrome/browser/cocoa/keystone_promote_preflight.sh
+++ b/chrome/browser/ui/cocoa/keystone_promote_preflight.sh
diff --git a/chrome/browser/ui/cocoa/keyword_editor_cocoa_controller.h b/chrome/browser/ui/cocoa/keyword_editor_cocoa_controller.h
new file mode 100644
index 0000000..6acc829
--- /dev/null
+++ b/chrome/browser/ui/cocoa/keyword_editor_cocoa_controller.h
@@ -0,0 +1,117 @@
+// Copyright (c) 2009 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 "app/table_model_observer.h"
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_ptr.h"
+#include "base/string16.h"
+#include "chrome/browser/search_engines/edit_search_engine_controller.h"
+#include "chrome/browser/search_engines/keyword_editor_controller.h"
+#include "chrome/browser/search_engines/template_url_model_observer.h"
+#include "chrome/browser/ui/cocoa/table_row_nsimage_cache.h"
+
+class EditSearchEngineControllerDelegate;
+@class KeywordEditorCocoaController;
+class Profile;
+@class WindowSizeAutosaver;
+
+// Very thin bridge that simply pushes notifications from C++ to ObjC.
+class KeywordEditorModelObserver : public TemplateURLModelObserver,
+ public EditSearchEngineControllerDelegate,
+ public TableModelObserver,
+ public TableRowNSImageCache::Table {
+ public:
+ explicit KeywordEditorModelObserver(KeywordEditorCocoaController* controller);
+ virtual ~KeywordEditorModelObserver();
+
+ // Notification that the template url model has changed in some way.
+ virtual void OnTemplateURLModelChanged();
+
+ // Invoked from the EditSearchEngineController when the user accepts the
+ // edits. NOTE: |template_url| is the value supplied to
+ // EditSearchEngineController's constructor, and may be NULL. A NULL value
+ // indicates a new TemplateURL should be created rather than modifying an
+ // existing TemplateURL.
+ virtual void OnEditedKeyword(const TemplateURL* template_url,
+ const string16& title,
+ const string16& keyword,
+ const std::string& url);
+
+ // TableModelObserver overrides. Invalidate icon cache.
+ virtual void OnModelChanged();
+ virtual void OnItemsChanged(int start, int length);
+ virtual void OnItemsAdded(int start, int length);
+ virtual void OnItemsRemoved(int start, int length);
+
+ // TableRowNSImageCache::Table
+ virtual int RowCount() const;
+ virtual SkBitmap GetIcon(int row) const;
+
+ // Lazily converts the image at the given row and caches it in |icon_cache_|.
+ NSImage* GetImageForRow(int row);
+
+ private:
+ KeywordEditorCocoaController* controller_;
+
+ TableRowNSImageCache icon_cache_;
+
+ DISALLOW_COPY_AND_ASSIGN(KeywordEditorModelObserver);
+};
+
+// This controller manages a window with a table view of search engines. It
+// acts as |tableView_|'s data source and delegate, feeding it data from the
+// KeywordEditorController's |table_model()|.
+
+@interface KeywordEditorCocoaController : NSWindowController
+ <NSWindowDelegate,
+ NSTableViewDataSource,
+ NSTableViewDelegate> {
+ IBOutlet NSTableView* tableView_;
+ IBOutlet NSButton* addButton_;
+ IBOutlet NSButton* removeButton_;
+ IBOutlet NSButton* makeDefaultButton_;
+
+ scoped_nsobject<NSTextFieldCell> groupCell_;
+
+ Profile* profile_; // weak
+ scoped_ptr<KeywordEditorController> controller_;
+ scoped_ptr<KeywordEditorModelObserver> observer_;
+
+ scoped_nsobject<WindowSizeAutosaver> sizeSaver_;
+}
+@property (nonatomic, readonly) KeywordEditorController* controller;
+
+// Show the keyword editor associated with the given profile (or the
+// original profile if this is an incognito profile). If no keyword
+// editor exists for this profile, create one and show it. Any
+// resulting editor releases itself when closed.
++ (void)showKeywordEditor:(Profile*)profile;
+
+- (KeywordEditorController*)controller;
+
+// Message forwarded by KeywordEditorModelObserver.
+- (void)modelChanged;
+
+- (IBAction)addKeyword:(id)sender;
+- (IBAction)deleteKeyword:(id)sender;
+- (IBAction)makeDefault:(id)sender;
+
+@end
+
+@interface KeywordEditorCocoaController (TestingAPI)
+
+// Instances of this class are managed, use +showKeywordEditor:.
+- (id)initWithProfile:(Profile*)profile;
+
+// Returns a reference to the shared instance for the given profile,
+// or nil if there is none.
++ (KeywordEditorCocoaController*)sharedInstanceForProfile:(Profile*)profile;
+
+// Converts a row index in our table view (which has group header rows) into
+// one in the |controller_|'s model, which does not have them.
+- (int)indexInModelForRow:(NSUInteger)row;
+
+@end
diff --git a/chrome/browser/ui/cocoa/keyword_editor_cocoa_controller.mm b/chrome/browser/ui/cocoa/keyword_editor_cocoa_controller.mm
new file mode 100644
index 0000000..1a0819f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/keyword_editor_cocoa_controller.mm
@@ -0,0 +1,425 @@
+// Copyright (c) 2009 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>
+
+#import "chrome/browser/ui/cocoa/keyword_editor_cocoa_controller.h"
+
+#import "base/mac_util.h"
+#include "base/lazy_instance.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/search_engines/template_url_table_model.h"
+#import "chrome/browser/ui/cocoa/edit_search_engine_cocoa_controller.h"
+#import "chrome/browser/ui/cocoa/window_size_autosaver.h"
+#include "chrome/common/pref_names.h"
+#include "grit/generated_resources.h"
+#include "skia/ext/skia_utils_mac.h"
+#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace {
+
+const CGFloat kButtonBarHeight = 35.0;
+
+} // namespace
+
+@interface KeywordEditorCocoaController (Private)
+- (void)adjustEditingButtons;
+- (void)editKeyword:(id)sender;
+- (int)indexInModelForRow:(NSUInteger)row;
+@end
+
+// KeywordEditorModelObserver -------------------------------------------------
+
+KeywordEditorModelObserver::KeywordEditorModelObserver(
+ KeywordEditorCocoaController* controller)
+ : controller_(controller),
+ icon_cache_(this) {
+}
+
+KeywordEditorModelObserver::~KeywordEditorModelObserver() {
+}
+
+// Notification that the template url model has changed in some way.
+void KeywordEditorModelObserver::OnTemplateURLModelChanged() {
+ [controller_ modelChanged];
+}
+
+void KeywordEditorModelObserver::OnEditedKeyword(
+ const TemplateURL* template_url,
+ const string16& title,
+ const string16& keyword,
+ const std::string& url) {
+ KeywordEditorController* controller = [controller_ controller];
+ if (template_url) {
+ controller->ModifyTemplateURL(template_url, title, keyword, url);
+ } else {
+ controller->AddTemplateURL(title, keyword, url);
+ }
+}
+
+void KeywordEditorModelObserver::OnModelChanged() {
+ icon_cache_.OnModelChanged();
+ [controller_ modelChanged];
+}
+
+void KeywordEditorModelObserver::OnItemsChanged(int start, int length) {
+ icon_cache_.OnItemsChanged(start, length);
+ [controller_ modelChanged];
+}
+
+void KeywordEditorModelObserver::OnItemsAdded(int start, int length) {
+ icon_cache_.OnItemsAdded(start, length);
+ [controller_ modelChanged];
+}
+
+void KeywordEditorModelObserver::OnItemsRemoved(int start, int length) {
+ icon_cache_.OnItemsRemoved(start, length);
+ [controller_ modelChanged];
+}
+
+int KeywordEditorModelObserver::RowCount() const {
+ return [controller_ controller]->table_model()->RowCount();
+}
+
+SkBitmap KeywordEditorModelObserver::GetIcon(int row) const {
+ return [controller_ controller]->table_model()->GetIcon(row);
+}
+
+NSImage* KeywordEditorModelObserver::GetImageForRow(int row) {
+ return icon_cache_.GetImageForRow(row);
+}
+
+// KeywordEditorCocoaController -----------------------------------------------
+
+namespace {
+
+typedef std::map<Profile*,KeywordEditorCocoaController*> ProfileControllerMap;
+
+static base::LazyInstance<ProfileControllerMap> g_profile_controller_map(
+ base::LINKER_INITIALIZED);
+
+} // namespace
+
+@implementation KeywordEditorCocoaController
+
++ (KeywordEditorCocoaController*)sharedInstanceForProfile:(Profile*)profile {
+ ProfileControllerMap* map = g_profile_controller_map.Pointer();
+ DCHECK(map != NULL);
+ ProfileControllerMap::iterator it = map->find(profile);
+ if (it != map->end()) {
+ return it->second;
+ }
+ return nil;
+}
+
+// TODO(shess): The Windows code watches a single global window which
+// is not distinguished by profile. This code could distinguish by
+// profile by checking the controller's class and profile.
++ (void)showKeywordEditor:(Profile*)profile {
+ // http://crbug.com/23359 describes a case where this panel is
+ // opened from an incognito window, which can leave the panel
+ // holding onto a stale profile. Since the same panel is used
+ // either way, arrange to use the original profile instead.
+ profile = profile->GetOriginalProfile();
+
+ ProfileControllerMap* map = g_profile_controller_map.Pointer();
+ DCHECK(map != NULL);
+ ProfileControllerMap::iterator it = map->find(profile);
+ if (it == map->end()) {
+ // Since we don't currently support multiple profiles, this class
+ // has not been tested against them, so document that assumption.
+ DCHECK_EQ(map->size(), 0U);
+
+ KeywordEditorCocoaController* controller =
+ [[self alloc] initWithProfile:profile];
+ it = map->insert(std::make_pair(profile, controller)).first;
+ }
+
+ [it->second showWindow:nil];
+}
+
+- (id)initWithProfile:(Profile*)profile {
+ DCHECK(profile);
+ NSString* nibpath = [mac_util::MainAppBundle()
+ pathForResource:@"KeywordEditor"
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
+ profile_ = profile;
+ controller_.reset(new KeywordEditorController(profile_));
+ observer_.reset(new KeywordEditorModelObserver(self));
+ controller_->table_model()->SetObserver(observer_.get());
+ controller_->url_model()->AddObserver(observer_.get());
+ groupCell_.reset([[NSTextFieldCell alloc] init]);
+
+ if (g_browser_process && g_browser_process->local_state()) {
+ sizeSaver_.reset([[WindowSizeAutosaver alloc]
+ initWithWindow:[self window]
+ prefService:g_browser_process->local_state()
+ path:prefs::kKeywordEditorWindowPlacement]);
+ }
+ }
+ return self;
+}
+
+- (void)dealloc {
+ controller_->table_model()->SetObserver(NULL);
+ controller_->url_model()->RemoveObserver(observer_.get());
+ [tableView_ setDataSource:nil];
+ observer_.reset();
+ [super dealloc];
+}
+
+- (void)awakeFromNib {
+ // Make sure the button fits its label, but keep it the same height as the
+ // other two buttons.
+ [GTMUILocalizerAndLayoutTweaker sizeToFitView:makeDefaultButton_];
+ NSSize size = [makeDefaultButton_ frame].size;
+ size.height = NSHeight([addButton_ frame]);
+ [makeDefaultButton_ setFrameSize:size];
+
+ [[self window] setAutorecalculatesContentBorderThickness:NO
+ forEdge:NSMinYEdge];
+ [[self window] setContentBorderThickness:kButtonBarHeight
+ forEdge:NSMinYEdge];
+
+ [self adjustEditingButtons];
+ [tableView_ setDoubleAction:@selector(editKeyword:)];
+ [tableView_ setTarget:self];
+}
+
+// When the window closes, clean ourselves up.
+- (void)windowWillClose:(NSNotification*)notif {
+ [self autorelease];
+
+ ProfileControllerMap* map = g_profile_controller_map.Pointer();
+ ProfileControllerMap::iterator it = map->find(profile_);
+ // It should not be possible for this to be missing.
+ // TODO(shess): Except that the unit test reaches in directly.
+ // Consider circling around and refactoring that.
+ //DCHECK(it != map->end());
+ if (it != map->end()) {
+ map->erase(it);
+ }
+}
+
+- (void)modelChanged {
+ [tableView_ reloadData];
+ [self adjustEditingButtons];
+}
+
+- (KeywordEditorController*)controller {
+ return controller_.get();
+}
+
+- (void)sheetDidEnd:(NSWindow*)sheet
+ returnCode:(NSInteger)code
+ context:(void*)context {
+ [sheet orderOut:self];
+}
+
+- (IBAction)addKeyword:(id)sender {
+ // The controller will release itself when the window closes.
+ EditSearchEngineCocoaController* editor =
+ [[EditSearchEngineCocoaController alloc] initWithProfile:profile_
+ delegate:observer_.get()
+ templateURL:NULL];
+ [NSApp beginSheet:[editor window]
+ modalForWindow:[self window]
+ modalDelegate:self
+ didEndSelector:@selector(sheetDidEnd:returnCode:context:)
+ contextInfo:NULL];
+}
+
+- (void)editKeyword:(id)sender {
+ const NSInteger clickedRow = [tableView_ clickedRow];
+ if (clickedRow < 0 || [self tableView:tableView_ isGroupRow:clickedRow])
+ return;
+ const TemplateURL* url = controller_->GetTemplateURL(
+ [self indexInModelForRow:clickedRow]);
+ // The controller will release itself when the window closes.
+ EditSearchEngineCocoaController* editor =
+ [[EditSearchEngineCocoaController alloc] initWithProfile:profile_
+ delegate:observer_.get()
+ templateURL:url];
+ [NSApp beginSheet:[editor window]
+ modalForWindow:[self window]
+ modalDelegate:self
+ didEndSelector:@selector(sheetDidEnd:returnCode:context:)
+ contextInfo:NULL];
+}
+
+- (IBAction)deleteKeyword:(id)sender {
+ NSIndexSet* selection = [tableView_ selectedRowIndexes];
+ DCHECK_GT([selection count], 0U);
+ NSUInteger index = [selection lastIndex];
+ while (index != NSNotFound) {
+ controller_->RemoveTemplateURL([self indexInModelForRow:index]);
+ index = [selection indexLessThanIndex:index];
+ }
+}
+
+- (IBAction)makeDefault:(id)sender {
+ NSIndexSet* selection = [tableView_ selectedRowIndexes];
+ DCHECK_EQ([selection count], 1U);
+ int row = [self indexInModelForRow:[selection firstIndex]];
+ controller_->MakeDefaultTemplateURL(row);
+}
+
+// Called when the user hits the escape key. Closes the window.
+- (void)cancel:(id)sender {
+ [[self window] performClose:self];
+}
+
+// Table View Data Source -----------------------------------------------------
+
+- (NSInteger)numberOfRowsInTableView:(NSTableView*)table {
+ int rowCount = controller_->table_model()->RowCount();
+ int numGroups = controller_->table_model()->GetGroups().size();
+ if ([self tableView:table isGroupRow:rowCount + numGroups - 1]) {
+ // Don't show a group header with no rows underneath it.
+ --numGroups;
+ }
+ return rowCount + numGroups;
+}
+
+- (id)tableView:(NSTableView*)tv
+ objectValueForTableColumn:(NSTableColumn*)tableColumn
+ row:(NSInteger)row {
+ if ([self tableView:tv isGroupRow:row]) {
+ DCHECK(!tableColumn);
+ TableModel::Groups groups = controller_->table_model()->GetGroups();
+ if (row == 0) {
+ return base::SysWideToNSString(groups[0].title);
+ } else {
+ return base::SysWideToNSString(groups[1].title);
+ }
+ }
+
+ NSString* identifier = [tableColumn identifier];
+ if ([identifier isEqualToString:@"name"]) {
+ // The name column is an NSButtonCell so we can have text and image in the
+ // same cell. As such, the "object value" for a button cell is either on
+ // or off, so we always return off so we don't act like a button.
+ return [NSNumber numberWithInt:NSOffState];
+ }
+ if ([identifier isEqualToString:@"keyword"]) {
+ // The keyword object value is a normal string.
+ int index = [self indexInModelForRow:row];
+ int columnID = IDS_SEARCH_ENGINES_EDITOR_KEYWORD_COLUMN;
+ std::wstring text = controller_->table_model()->GetText(index, columnID);
+ return base::SysWideToNSString(text);
+ }
+
+ // And we shouldn't have any other columns...
+ NOTREACHED();
+ return nil;
+}
+
+// Table View Delegate --------------------------------------------------------
+
+// When the selection in the table view changes, we need to adjust buttons.
+- (void)tableViewSelectionDidChange:(NSNotification*)aNotification {
+ [self adjustEditingButtons];
+}
+
+// Disallow selection of the group header rows.
+- (BOOL)tableView:(NSTableView*)table shouldSelectRow:(NSInteger)row {
+ return ![self tableView:table isGroupRow:row];
+}
+
+- (BOOL)tableView:(NSTableView*)table isGroupRow:(NSInteger)row {
+ int otherGroupRow =
+ controller_->table_model()->last_search_engine_index() + 1;
+ return (row == 0 || row == otherGroupRow);
+}
+
+- (NSCell*)tableView:(NSTableView*)tableView
+ dataCellForTableColumn:(NSTableColumn*)tableColumn
+ row:(NSInteger)row {
+ static const CGFloat kCellFontSize = 12.0;
+
+ // Check to see if we are a grouped row.
+ if ([self tableView:tableView isGroupRow:row]) {
+ DCHECK(!tableColumn); // This would violate the group row contract.
+ return groupCell_.get();
+ }
+
+ NSCell* cell = [tableColumn dataCellForRow:row];
+ int offsetRow = [self indexInModelForRow:row];
+
+ // Set the favicon and title for the search engine in the name column.
+ if ([[tableColumn identifier] isEqualToString:@"name"]) {
+ DCHECK([cell isKindOfClass:[NSButtonCell class]]);
+ NSButtonCell* buttonCell = static_cast<NSButtonCell*>(cell);
+ std::wstring title = controller_->table_model()->GetText(offsetRow,
+ IDS_SEARCH_ENGINES_EDITOR_DESCRIPTION_COLUMN);
+ [buttonCell setTitle:base::SysWideToNSString(title)];
+ [buttonCell setImage:observer_->GetImageForRow(offsetRow)];
+ [buttonCell setRefusesFirstResponder:YES]; // Don't push in like a button.
+ [buttonCell setHighlightsBy:NSNoCellMask];
+ }
+
+ // The default search engine should be in bold font.
+ const TemplateURL* defaultEngine =
+ controller_->url_model()->GetDefaultSearchProvider();
+ int rowIndex = controller_->table_model()->IndexOfTemplateURL(defaultEngine);
+ if (rowIndex == offsetRow) {
+ [cell setFont:[NSFont boldSystemFontOfSize:kCellFontSize]];
+ } else {
+ [cell setFont:[NSFont systemFontOfSize:kCellFontSize]];
+ }
+ return cell;
+}
+
+// Private --------------------------------------------------------------------
+
+// This function appropriately sets the enabled states on the table's editing
+// buttons.
+- (void)adjustEditingButtons {
+ NSIndexSet* selection = [tableView_ selectedRowIndexes];
+ BOOL canRemove = ([selection count] > 0);
+ NSUInteger index = [selection firstIndex];
+
+ // Delete button.
+ while (canRemove && index != NSNotFound) {
+ int modelIndex = [self indexInModelForRow:index];
+ const TemplateURL& url =
+ controller_->table_model()->GetTemplateURL(modelIndex);
+ if (!controller_->CanRemove(&url))
+ canRemove = NO;
+ index = [selection indexGreaterThanIndex:index];
+ }
+ [removeButton_ setEnabled:canRemove];
+
+ // Make default button.
+ if ([selection count] != 1) {
+ [makeDefaultButton_ setEnabled:NO];
+ } else {
+ int row = [self indexInModelForRow:[selection firstIndex]];
+ const TemplateURL& url =
+ controller_->table_model()->GetTemplateURL(row);
+ [makeDefaultButton_ setEnabled:controller_->CanMakeDefault(&url)];
+ }
+}
+
+// This converts a row index in our table view to an index in the model by
+// computing the group offsets.
+- (int)indexInModelForRow:(NSUInteger)row {
+ DCHECK_GT(row, 0U);
+ unsigned otherGroupId =
+ controller_->table_model()->last_search_engine_index() + 1;
+ DCHECK_NE(row, otherGroupId);
+ if (row >= otherGroupId) {
+ return row - 2; // Other group.
+ } else {
+ return row - 1; // Default group.
+ }
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/keyword_editor_cocoa_controller_unittest.mm b/chrome/browser/ui/cocoa/keyword_editor_cocoa_controller_unittest.mm
new file mode 100644
index 0000000..eb5c264
--- /dev/null
+++ b/chrome/browser/ui/cocoa/keyword_editor_cocoa_controller_unittest.mm
@@ -0,0 +1,227 @@
+// Copyright (c) 2009 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/mac/scoped_nsautorelease_pool.h"
+#include "base/scoped_nsobject.h"
+#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/keyword_editor_cocoa_controller.h"
+#include "chrome/test/testing_profile.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+@interface FakeKeywordEditorController : KeywordEditorCocoaController {
+ @public
+ BOOL modelChanged_;
+}
+- (void)modelChanged;
+- (BOOL)hasModelChanged;
+- (KeywordEditorModelObserver*)observer;
+@end
+
+@implementation FakeKeywordEditorController
+
+- (void)modelChanged {
+ modelChanged_ = YES;
+}
+
+- (BOOL)hasModelChanged {
+ return modelChanged_;
+}
+
+- (KeywordEditorModelObserver*)observer {
+ return observer_.get();
+}
+
+- (NSTableView*)tableView {
+ return tableView_;
+}
+
+@end
+
+// TODO(rsesek): Figure out a good way to test this class (crbug.com/21640).
+
+namespace {
+
+class KeywordEditorCocoaControllerTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ TestingProfile* profile =
+ static_cast<TestingProfile*>(browser_helper_.profile());
+ profile->CreateTemplateURLModel();
+
+ controller_ =
+ [[FakeKeywordEditorController alloc] initWithProfile:profile];
+ }
+
+ virtual void TearDown() {
+ // Force the window to load so we hit |-awakeFromNib| to register as the
+ // window's delegate so that the controller can clean itself up in
+ // |-windowWillClose:|.
+ ASSERT_TRUE([controller_ window]);
+
+ [controller_ close];
+ CocoaTest::TearDown();
+ }
+
+ // Helper to count the keyword editors.
+ NSUInteger CountKeywordEditors() {
+ base::mac::ScopedNSAutoreleasePool pool;
+ NSUInteger count = 0;
+ for (NSWindow* window in [NSApp windows]) {
+ id controller = [window windowController];
+ if ([controller isKindOfClass:[KeywordEditorCocoaController class]]) {
+ ++count;
+ }
+ }
+ return count;
+ }
+
+ BrowserTestHelper browser_helper_;
+ FakeKeywordEditorController* controller_;
+};
+
+TEST_F(KeywordEditorCocoaControllerTest, TestModelChanged) {
+ EXPECT_FALSE([controller_ hasModelChanged]);
+ KeywordEditorModelObserver* observer = [controller_ observer];
+ observer->OnTemplateURLModelChanged();
+ EXPECT_TRUE([controller_ hasModelChanged]);
+}
+
+// Test that +showKeywordEditor brings up the existing editor and
+// creates one if needed.
+TEST_F(KeywordEditorCocoaControllerTest, ShowKeywordEditor) {
+ // No outstanding editors.
+ Profile* profile(browser_helper_.profile());
+ KeywordEditorCocoaController* sharedInstance =
+ [KeywordEditorCocoaController sharedInstanceForProfile:profile];
+ EXPECT_TRUE(nil == sharedInstance);
+ EXPECT_EQ(CountKeywordEditors(), 0U);
+
+ const NSUInteger initial_window_count([[NSApp windows] count]);
+
+ // The window unwinds using -autorelease, so we need to introduce an
+ // autorelease pool to really test whether it went away or not.
+ {
+ base::mac::ScopedNSAutoreleasePool pool;
+
+ // +showKeywordEditor: creates a new controller.
+ [KeywordEditorCocoaController showKeywordEditor:profile];
+ sharedInstance =
+ [KeywordEditorCocoaController sharedInstanceForProfile:profile];
+ EXPECT_TRUE(sharedInstance);
+ EXPECT_EQ(CountKeywordEditors(), 1U);
+
+ // Another call doesn't create another controller.
+ [KeywordEditorCocoaController showKeywordEditor:profile];
+ EXPECT_TRUE(sharedInstance ==
+ [KeywordEditorCocoaController sharedInstanceForProfile:profile]);
+ EXPECT_EQ(CountKeywordEditors(), 1U);
+
+ [sharedInstance close];
+ }
+
+ // No outstanding editors.
+ sharedInstance =
+ [KeywordEditorCocoaController sharedInstanceForProfile:profile];
+ EXPECT_TRUE(nil == sharedInstance);
+ EXPECT_EQ(CountKeywordEditors(), 0U);
+
+ // Windows we created should be gone.
+ EXPECT_EQ([[NSApp windows] count], initial_window_count);
+
+ // Get a new editor, should be different from the previous one.
+ [KeywordEditorCocoaController showKeywordEditor:profile];
+ KeywordEditorCocoaController* newSharedInstance =
+ [KeywordEditorCocoaController sharedInstanceForProfile:profile];
+ EXPECT_TRUE(sharedInstance != newSharedInstance);
+ EXPECT_EQ(CountKeywordEditors(), 1U);
+ [newSharedInstance close];
+}
+
+TEST_F(KeywordEditorCocoaControllerTest, IndexInModelForRowMixed) {
+ [controller_ window]; // Force |-awakeFromNib|.
+ TemplateURLModel* template_model = [controller_ controller]->url_model();
+
+ // Add a default engine.
+ TemplateURL* t_url = new TemplateURL();
+ t_url->SetURL("http://test1/{searchTerms}", 0, 0);
+ t_url->set_keyword(L"test1");
+ t_url->set_short_name(L"Test1");
+ t_url->set_show_in_default_list(true);
+ template_model->Add(t_url);
+
+ // Add a non-default engine.
+ t_url = new TemplateURL();
+ t_url->SetURL("http://test2/{searchTerms}", 0, 0);
+ t_url->set_keyword(L"test2");
+ t_url->set_short_name(L"Test2");
+ t_url->set_show_in_default_list(false);
+ template_model->Add(t_url);
+
+ // Two headers with a single row underneath each.
+ NSTableView* table = [controller_ tableView];
+ [table reloadData];
+ ASSERT_EQ(4, [[controller_ tableView] numberOfRows]);
+
+ // Index 0 is the group header, index 1 should be the first engine.
+ ASSERT_EQ(0, [controller_ indexInModelForRow:1]);
+
+ // Index 2 should be the group header, so index 3 should be the non-default
+ // engine.
+ ASSERT_EQ(1, [controller_ indexInModelForRow:3]);
+
+ ASSERT_TRUE([controller_ tableView:table isGroupRow:0]);
+ ASSERT_FALSE([controller_ tableView:table isGroupRow:1]);
+ ASSERT_TRUE([controller_ tableView:table isGroupRow:2]);
+ ASSERT_FALSE([controller_ tableView:table isGroupRow:3]);
+
+ ASSERT_FALSE([controller_ tableView:table shouldSelectRow:0]);
+ ASSERT_TRUE([controller_ tableView:table shouldSelectRow:1]);
+ ASSERT_FALSE([controller_ tableView:table shouldSelectRow:2]);
+ ASSERT_TRUE([controller_ tableView:table shouldSelectRow:3]);
+}
+
+TEST_F(KeywordEditorCocoaControllerTest, IndexInModelForDefault) {
+ [controller_ window]; // Force |-awakeFromNib|.
+ TemplateURLModel* template_model = [controller_ controller]->url_model();
+
+ // Add 2 default engines.
+ TemplateURL* t_url = new TemplateURL();
+ t_url->SetURL("http://test1/{searchTerms}", 0, 0);
+ t_url->set_keyword(L"test1");
+ t_url->set_short_name(L"Test1");
+ t_url->set_show_in_default_list(true);
+ template_model->Add(t_url);
+
+ t_url = new TemplateURL();
+ t_url->SetURL("http://test2/{searchTerms}", 0, 0);
+ t_url->set_keyword(L"test2");
+ t_url->set_short_name(L"Test2");
+ t_url->set_show_in_default_list(true);
+ template_model->Add(t_url);
+
+ // One header and two rows.
+ NSTableView* table = [controller_ tableView];
+ [table reloadData];
+ ASSERT_EQ(3, [[controller_ tableView] numberOfRows]);
+
+ // Index 0 is the group header, index 1 should be the first engine.
+ ASSERT_EQ(0, [controller_ indexInModelForRow:1]);
+ ASSERT_EQ(1, [controller_ indexInModelForRow:2]);
+
+ ASSERT_TRUE([controller_ tableView:table isGroupRow:0]);
+ ASSERT_FALSE([controller_ tableView:table isGroupRow:1]);
+ ASSERT_FALSE([controller_ tableView:table isGroupRow:2]);
+
+ ASSERT_FALSE([controller_ tableView:table shouldSelectRow:0]);
+ ASSERT_TRUE([controller_ tableView:table shouldSelectRow:1]);
+ ASSERT_TRUE([controller_ tableView:table shouldSelectRow:2]);
+}
+
+} // namespace
diff --git a/chrome/browser/cocoa/l10n_util.h b/chrome/browser/ui/cocoa/l10n_util.h
index bb26327..bb26327 100644
--- a/chrome/browser/cocoa/l10n_util.h
+++ b/chrome/browser/ui/cocoa/l10n_util.h
diff --git a/chrome/browser/ui/cocoa/l10n_util.mm b/chrome/browser/ui/cocoa/l10n_util.mm
new file mode 100644
index 0000000..5ebb8c7
--- /dev/null
+++ b/chrome/browser/ui/cocoa/l10n_util.mm
@@ -0,0 +1,78 @@
+// 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 "chrome/browser/ui/cocoa/l10n_util.h"
+
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
+
+namespace cocoa_l10n_util {
+
+NSInteger CompareFrameY(id view1, id view2, void* context) {
+ CGFloat y1 = NSMinY([view1 frame]);
+ CGFloat y2 = NSMinY([view2 frame]);
+ if (y1 < y2)
+ return NSOrderedAscending;
+ else if (y1 > y2)
+ return NSOrderedDescending;
+ else
+ return NSOrderedSame;
+}
+
+NSSize WrapOrSizeToFit(NSView* view) {
+ if ([view isKindOfClass:[NSTextField class]]) {
+ NSTextField* textField = static_cast<NSTextField*>(view);
+ if ([textField isEditable])
+ return NSZeroSize;
+ CGFloat heightChange =
+ [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:textField];
+ return NSMakeSize(0.0, heightChange);
+ }
+ if ([view isKindOfClass:[NSMatrix class]]) {
+ NSMatrix* radioGroup = static_cast<NSMatrix*>(view);
+ [GTMUILocalizerAndLayoutTweaker wrapRadioGroupForWidth:radioGroup];
+ return [GTMUILocalizerAndLayoutTweaker sizeToFitView:view];
+ }
+ if ([view isKindOfClass:[NSButton class]]) {
+ NSButton* button = static_cast<NSButton*>(view);
+ NSButtonCell* buttonCell = [button cell];
+ // Decide it's a checkbox via showsStateBy and highlightsBy.
+ if (([buttonCell showsStateBy] == NSCellState) &&
+ ([buttonCell highlightsBy] == NSCellState)) {
+ [GTMUILocalizerAndLayoutTweaker wrapButtonTitleForWidth:button];
+ return [GTMUILocalizerAndLayoutTweaker sizeToFitView:view];
+ }
+ }
+ return [GTMUILocalizerAndLayoutTweaker sizeToFitView:view];
+}
+
+CGFloat VerticallyReflowGroup(NSArray* views) {
+ views = [views sortedArrayUsingFunction:CompareFrameY
+ context:NULL];
+ CGFloat localVerticalShift = 0;
+ for (NSInteger index = [views count] - 1; index >= 0; --index) {
+ NSView* view = [views objectAtIndex:index];
+
+ NSSize delta = WrapOrSizeToFit(view);
+ localVerticalShift += delta.height;
+ if (localVerticalShift) {
+ NSPoint origin = [view frame].origin;
+ origin.y -= localVerticalShift;
+ [view setFrameOrigin:origin];
+ }
+ }
+ return localVerticalShift;
+}
+
+NSString* ReplaceNSStringPlaceholders(NSString* formatString,
+ const string16& a,
+ size_t* offset) {
+ return base::SysUTF16ToNSString(
+ ReplaceStringPlaceholders(base::SysNSStringToUTF16(formatString),
+ a,
+ offset));
+}
+
+} // namespace cocoa_l10n_util
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h
new file mode 100644
index 0000000..fa8bd42
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h
@@ -0,0 +1,147 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_AUTOCOMPLETE_TEXT_FIELD_H_
+#define CHROME_BROWSER_UI_COCOA_AUTOCOMPLETE_TEXT_FIELD_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/styled_text_field.h"
+#import "chrome/browser/ui/cocoa/url_drop_target.h"
+
+@class AutocompleteTextFieldCell;
+
+// AutocompleteTextField intercepts UI actions for forwarding to
+// AutocompleteEditViewMac (*), and provides a custom look. It works
+// together with AutocompleteTextFieldEditor (mostly for intercepting
+// user actions) and AutocompleteTextFieldCell (mostly for custom
+// drawing).
+//
+// For historical reasons, chrome/browser/autocomplete is the core
+// implementation of the Omnibox. Chrome code seems to vary between
+// autocomplete and Omnibox in describing this.
+//
+// (*) AutocompleteEditViewMac is a view in the MVC sense for the
+// Chrome internals, though it's really more of a mish-mash of model,
+// view, and controller.
+
+// Provides a hook so that we can call directly down to
+// AutocompleteEditViewMac rather than traversing the delegate chain.
+class AutocompleteTextFieldObserver {
+ public:
+ // Called before changing the selected range of the field.
+ virtual NSRange SelectionRangeForProposedRange(NSRange proposed_range) = 0;
+
+ // Called when the control-key state changes while the field is
+ // first responder.
+ virtual void OnControlKeyChanged(bool pressed) = 0;
+
+ // Called when the user pastes into the field.
+ virtual void OnPaste() = 0;
+
+ // Return |true| if there is a selection to copy.
+ virtual bool CanCopy() = 0;
+
+ // Clears the |pboard| and adds the field's current selection.
+ // Called when the user does a copy or drag.
+ virtual void CopyToPasteboard(NSPasteboard* pboard) = 0;
+
+ // Returns true if the current clipboard text supports paste and go
+ // (or paste and search).
+ virtual bool CanPasteAndGo() = 0;
+
+ // Returns the appropriate "Paste and Go" or "Paste and Search"
+ // context menu string, depending on what is currently in the
+ // clipboard. Must not be called unless CanPasteAndGo() returns
+ // true.
+ virtual int GetPasteActionStringId() = 0;
+
+ // Called when the user initiates a "paste and go" or "paste and
+ // search" into the field.
+ virtual void OnPasteAndGo() = 0;
+
+ // Called when the field's frame changes.
+ virtual void OnFrameChanged() = 0;
+
+ // Called when the popup is no longer appropriate, such as when the
+ // field's window loses focus or a page action is clicked.
+ virtual void ClosePopup() = 0;
+
+ // Called when the user begins editing the field, for every edit,
+ // and when the user is done editing the field.
+ virtual void OnDidBeginEditing() = 0;
+ virtual void OnDidChange() = 0;
+ virtual void OnDidEndEditing() = 0;
+
+ // Called before input methods sets composition text in the field.
+ virtual void OnStartingIME() = 0;
+
+ // NSResponder translates certain keyboard actions into selectors
+ // passed to -doCommandBySelector:. The selector is forwarded here,
+ // return true if |cmd| is handled, false if the caller should
+ // handle it.
+ // TODO(shess): For now, I think having the code which makes these
+ // decisions closer to the other autocomplete code is worthwhile,
+ // since it calls a wide variety of methods which otherwise aren't
+ // clearly relevent to expose here. But consider pulling more of
+ // the AutocompleteEditViewMac calls up to here.
+ virtual bool OnDoCommandBySelector(SEL cmd) = 0;
+
+ // Called whenever the autocomplete text field gets focused.
+ virtual void OnSetFocus(bool control_down) = 0;
+
+ // Called whenever the autocomplete text field is losing focus.
+ virtual void OnKillFocus() = 0;
+
+ protected:
+ virtual ~AutocompleteTextFieldObserver() {}
+};
+
+@interface AutocompleteTextField : StyledTextField<NSTextViewDelegate,
+ URLDropTarget> {
+ @private
+ // Undo manager for this text field. We use a specific instance rather than
+ // the standard undo manager in order to let us clear the undo stack at will.
+ scoped_nsobject<NSUndoManager> undoManager_;
+
+ AutocompleteTextFieldObserver* observer_; // weak, owned by location bar.
+
+ // Handles being a drag-and-drop target.
+ scoped_nsobject<URLDropTargetHandler> dropHandler_;
+
+ // Holds current tooltip strings, to keep them from being dealloced.
+ scoped_nsobject<NSMutableArray> currentToolTips_;
+}
+
+@property (nonatomic) AutocompleteTextFieldObserver* observer;
+
+// Convenience method to return the cell, casted appropriately.
+- (AutocompleteTextFieldCell*)cell;
+
+// Superclass aborts editing before changing the string, which causes
+// problems for undo. This version modifies the field editor's
+// contents if the control is already being edited.
+- (void)setAttributedStringValue:(NSAttributedString*)aString;
+
+// Clears the undo chain for this text field.
+- (void)clearUndoChain;
+
+// Updates cursor and tooltip rects depending on the contents of the text field
+// e.g. the security icon should have a default pointer shown on hover instead
+// of an I-beam.
+- (void)updateCursorAndToolTipRects;
+
+// Return the appropriate menu for any decoration under |event|.
+- (NSMenu*)decorationMenuForEvent:(NSEvent*)event;
+
+// Retains |tooltip| (in |currentToolTips_|) and adds this tooltip
+// via -[NSView addToolTipRect:owner:userData:].
+- (void)addToolTip:(NSString*)tooltip forRect:(NSRect)aRect;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_AUTOCOMPLETE_TEXT_FIELD_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm
new file mode 100644
index 0000000..33c34cf
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm
@@ -0,0 +1,385 @@
+// 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 "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
+
+#include "base/logging.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
+#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h"
+#import "chrome/browser/ui/cocoa/toolbar_controller.h"
+#import "chrome/browser/ui/cocoa/url_drop_target.h"
+#import "chrome/browser/ui/cocoa/view_id_util.h"
+
+@implementation AutocompleteTextField
+
+@synthesize observer = observer_;
+
++ (Class)cellClass {
+ return [AutocompleteTextFieldCell class];
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+- (void)awakeFromNib {
+ DCHECK([[self cell] isKindOfClass:[AutocompleteTextFieldCell class]]);
+ [[self cell] setTruncatesLastVisibleLine:YES];
+ [[self cell] setLineBreakMode:NSLineBreakByTruncatingTail];
+ currentToolTips_.reset([[NSMutableArray alloc] init]);
+}
+
+- (void)flagsChanged:(NSEvent*)theEvent {
+ if (observer_) {
+ const bool controlFlag = ([theEvent modifierFlags]&NSControlKeyMask) != 0;
+ observer_->OnControlKeyChanged(controlFlag);
+ }
+}
+
+- (AutocompleteTextFieldCell*)cell {
+ NSCell* cell = [super cell];
+ if (!cell)
+ return nil;
+
+ DCHECK([cell isKindOfClass:[AutocompleteTextFieldCell class]]);
+ return static_cast<AutocompleteTextFieldCell*>(cell);
+}
+
+// Reroute events for the decoration area to the field editor. This
+// will cause the cursor to be moved as close to the edge where the
+// event was seen as possible.
+//
+// The reason for this code's existence is subtle. NSTextField
+// implements text selection and editing in terms of a "field editor".
+// This is an NSTextView which is installed as a subview of the
+// control when the field becomes first responder. When the field
+// editor is installed, it will get -mouseDown: events and handle
+// them, rather than the text field - EXCEPT for the event which
+// caused the change in first responder, or events which fall in the
+// decorations outside the field editor's area. In that case, the
+// default NSTextField code will setup the field editor all over
+// again, which has the side effect of doing "select all" on the text.
+// This effect can be observed with a normal NSTextField if you click
+// in the narrow border area, and is only really a problem because in
+// our case the focus ring surrounds decorations which look clickable.
+//
+// When the user first clicks on the field, after installing the field
+// editor the default NSTextField code detects if the hit is in the
+// field editor area, and if so sets the selection to {0,0} to clear
+// the selection before forwarding the event to the field editor for
+// processing (it will set the cursor position). This also starts the
+// click-drag selection machinery.
+//
+// This code does the same thing for cases where the click was in the
+// decoration area. This allows the user to click-drag starting from
+// a decoration area and get the expected selection behaviour,
+// likewise for multiple clicks in those areas.
+- (void)mouseDown:(NSEvent*)theEvent {
+ // Close the popup before processing the event. This prevents the
+ // popup from being visible while a right-click context menu or
+ // page-action menu is visible. Also, it matches other platforms.
+ if (observer_)
+ observer_->ClosePopup();
+
+ // If the click was a Control-click, bring up the context menu.
+ // |NSTextField| handles these cases inconsistently if the field is
+ // not already first responder.
+ if (([theEvent modifierFlags] & NSControlKeyMask) != 0) {
+ NSText* editor = [self currentEditor];
+ NSMenu* menu = [editor menuForEvent:theEvent];
+ [NSMenu popUpContextMenu:menu withEvent:theEvent forView:editor];
+ return;
+ }
+
+ const NSPoint location =
+ [self convertPoint:[theEvent locationInWindow] fromView:nil];
+ const NSRect bounds([self bounds]);
+
+ AutocompleteTextFieldCell* cell = [self cell];
+ const NSRect textFrame([cell textFrameForFrame:bounds]);
+
+ // A version of the textFrame which extends across the field's
+ // entire width.
+
+ const NSRect fullFrame(NSMakeRect(bounds.origin.x, textFrame.origin.y,
+ bounds.size.width, textFrame.size.height));
+
+ // If the mouse is in the editing area, or above or below where the
+ // editing area would be if we didn't add decorations, forward to
+ // NSTextField -mouseDown: because it does the right thing. The
+ // above/below test is needed because NSTextView treats mouse events
+ // above/below as select-to-end-in-that-direction, which makes
+ // things janky.
+ BOOL flipped = [self isFlipped];
+ if (NSMouseInRect(location, textFrame, flipped) ||
+ !NSMouseInRect(location, fullFrame, flipped)) {
+ [super mouseDown:theEvent];
+
+ // After the event has been handled, if the current event is a
+ // mouse up and no selection was created (the mouse didn't move),
+ // select the entire field.
+ // NOTE(shess): This does not interfere with single-clicking to
+ // place caret after a selection is made. An NSTextField only has
+ // a selection when it has a field editor. The field editor is an
+ // NSText subview, which will receive the -mouseDown: in that
+ // case, and this code will never fire.
+ NSText* editor = [self currentEditor];
+ if (editor) {
+ NSEvent* currentEvent = [NSApp currentEvent];
+ if ([currentEvent type] == NSLeftMouseUp &&
+ ![editor selectedRange].length) {
+ [editor selectAll:nil];
+ }
+ }
+
+ return;
+ }
+
+ // Give the cell a chance to intercept clicks in page-actions and
+ // other decorative items.
+ if ([cell mouseDown:theEvent inRect:bounds ofView:self]) {
+ return;
+ }
+
+ NSText* editor = [self currentEditor];
+
+ // We should only be here if we accepted first-responder status and
+ // have a field editor. If one of these fires, it means some
+ // assumptions are being broken.
+ DCHECK(editor != nil);
+ DCHECK([editor isDescendantOf:self]);
+
+ // -becomeFirstResponder does a select-all, which we don't want
+ // because it can lead to a dragged-text situation. Clear the
+ // selection (any valid empty selection will do).
+ [editor setSelectedRange:NSMakeRange(0, 0)];
+
+ // If the event is to the right of the editing area, scroll the
+ // field editor to the end of the content so that the selection
+ // doesn't initiate from somewhere in the middle of the text.
+ if (location.x > NSMaxX(textFrame)) {
+ [editor scrollRangeToVisible:NSMakeRange([[self stringValue] length], 0)];
+ }
+
+ [editor mouseDown:theEvent];
+}
+
+// Overridden to pass OnFrameChanged() notifications to |observer_|.
+// Additionally, cursor and tooltip rects need to be updated.
+- (void)setFrame:(NSRect)frameRect {
+ [super setFrame:frameRect];
+ if (observer_) {
+ observer_->OnFrameChanged();
+ }
+ [self updateCursorAndToolTipRects];
+}
+
+// Due to theming, parts of the field are transparent.
+- (BOOL)isOpaque {
+ return NO;
+}
+
+- (void)setAttributedStringValue:(NSAttributedString*)aString {
+ AutocompleteTextFieldEditor* editor =
+ static_cast<AutocompleteTextFieldEditor*>([self currentEditor]);
+
+ if (!editor) {
+ [super setAttributedStringValue:aString];
+ } else {
+ // The type of the field editor must be AutocompleteTextFieldEditor,
+ // otherwise things won't work.
+ DCHECK([editor isKindOfClass:[AutocompleteTextFieldEditor class]]);
+
+ [editor setAttributedString:aString];
+ }
+}
+
+- (NSUndoManager*)undoManagerForTextView:(NSTextView*)textView {
+ if (!undoManager_.get())
+ undoManager_.reset([[NSUndoManager alloc] init]);
+ return undoManager_.get();
+}
+
+- (void)clearUndoChain {
+ [undoManager_ removeAllActions];
+}
+
+- (NSRange)textView:(NSTextView *)aTextView
+ willChangeSelectionFromCharacterRange:(NSRange)oldRange
+ toCharacterRange:(NSRange)newRange {
+ if (observer_)
+ return observer_->SelectionRangeForProposedRange(newRange);
+ return newRange;
+}
+
+- (void)addToolTip:(NSString*)tooltip forRect:(NSRect)aRect {
+ [currentToolTips_ addObject:tooltip];
+ [self addToolTipRect:aRect owner:tooltip userData:nil];
+}
+
+// TODO(shess): -resetFieldEditorFrameIfNeeded is the place where
+// changes to the cell layout should be flushed. LocationBarViewMac
+// and ToolbarController are calling this routine directly, and I
+// think they are probably wrong.
+// http://crbug.com/40053
+- (void)updateCursorAndToolTipRects {
+ // This will force |resetCursorRects| to be called, as it is not to be called
+ // directly.
+ [[self window] invalidateCursorRectsForView:self];
+
+ // |removeAllToolTips| only removes those set on the current NSView, not any
+ // subviews. Unless more tooltips are added to this view, this should suffice
+ // in place of managing a set of NSToolTipTag objects.
+ [self removeAllToolTips];
+
+ // Reload the decoration tooltips.
+ [currentToolTips_ removeAllObjects];
+ [[self cell] updateToolTipsInRect:[self bounds] ofView:self];
+}
+
+// NOTE(shess): http://crbug.com/19116 describes a weird bug which
+// happens when the user runs a Print panel on Leopard. After that,
+// spurious -controlTextDidBeginEditing notifications are sent when an
+// NSTextField is firstResponder, even though -currentEditor on that
+// field returns nil. That notification caused significant problems
+// in AutocompleteEditViewMac. -textDidBeginEditing: was NOT being
+// sent in those cases, so this approach doesn't have the problem.
+- (void)textDidBeginEditing:(NSNotification*)aNotification {
+ [super textDidBeginEditing:aNotification];
+ if (observer_) {
+ observer_->OnDidBeginEditing();
+ }
+}
+
+- (void)textDidEndEditing:(NSNotification *)aNotification {
+ [super textDidEndEditing:aNotification];
+ if (observer_) {
+ observer_->OnDidEndEditing();
+ }
+}
+
+// When the window resigns, make sure the autocomplete popup is no
+// longer visible, since the user's focus is elsewhere.
+- (void)windowDidResignKey:(NSNotification*)notification {
+ DCHECK_EQ([self window], [notification object]);
+ if (observer_)
+ observer_->ClosePopup();
+}
+
+- (void)viewWillMoveToWindow:(NSWindow*)newWindow {
+ if ([self window]) {
+ NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
+ [nc removeObserver:self
+ name:NSWindowDidResignKeyNotification
+ object:[self window]];
+ }
+}
+
+- (void)viewDidMoveToWindow {
+ if ([self window]) {
+ NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
+ [nc addObserver:self
+ selector:@selector(windowDidResignKey:)
+ name:NSWindowDidResignKeyNotification
+ object:[self window]];
+ // Only register for drops if not in a popup window. Lazily create the
+ // drop handler when the type of window is known.
+ BrowserWindowController* windowController =
+ [BrowserWindowController browserWindowControllerForView:self];
+ if ([windowController isNormalWindow])
+ dropHandler_.reset([[URLDropTargetHandler alloc] initWithView:self]);
+ }
+}
+
+// NSTextField becomes first responder by installing a "field editor"
+// subview. Clicks outside the field editor (such as a decoration)
+// will attempt to make the field the first-responder again, which
+// causes a select-all, even if the decoration handles the click. If
+// the field editor is already in place, don't accept first responder
+// again. This allows the selection to be unmodified if the click is
+// handled by a decoration or context menu (|-mouseDown:| will still
+// change it if appropriate).
+- (BOOL)acceptsFirstResponder {
+ if ([self currentEditor]) {
+ DCHECK_EQ([self currentEditor], [[self window] firstResponder]);
+ return NO;
+ }
+ return [super acceptsFirstResponder];
+}
+
+// (Overridden from NSResponder)
+- (BOOL)becomeFirstResponder {
+ BOOL doAccept = [super becomeFirstResponder];
+ if (doAccept) {
+ [[BrowserWindowController browserWindowControllerForView:self]
+ lockBarVisibilityForOwner:self withAnimation:YES delay:NO];
+
+ // Tells the observer that we get the focus.
+ // But we can't call observer_->OnKillFocus() in resignFirstResponder:,
+ // because the first responder will be immediately set to the field editor
+ // when calling [super becomeFirstResponder], thus we won't receive
+ // resignFirstResponder: anymore when losing focus.
+ if (observer_) {
+ NSEvent* theEvent = [NSApp currentEvent];
+ const bool controlDown = ([theEvent modifierFlags]&NSControlKeyMask) != 0;
+ observer_->OnSetFocus(controlDown);
+ }
+ }
+ return doAccept;
+}
+
+// (Overridden from NSResponder)
+- (BOOL)resignFirstResponder {
+ BOOL doResign = [super resignFirstResponder];
+ if (doResign) {
+ [[BrowserWindowController browserWindowControllerForView:self]
+ releaseBarVisibilityForOwner:self withAnimation:YES delay:YES];
+ }
+ return doResign;
+}
+
+// (URLDropTarget protocol)
+- (id<URLDropTargetController>)urlDropController {
+ BrowserWindowController* windowController =
+ [BrowserWindowController browserWindowControllerForView:self];
+ return [windowController toolbarController];
+}
+
+// (URLDropTarget protocol)
+- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
+ // Make ourself the first responder, which will select the text to indicate
+ // that our contents would be replaced by a drop.
+ // TODO(viettrungluu): crbug.com/30809 -- this is a hack since it steals focus
+ // and doesn't return it.
+ [[self window] makeFirstResponder:self];
+ return [dropHandler_ draggingEntered:sender];
+}
+
+// (URLDropTarget protocol)
+- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender {
+ return [dropHandler_ draggingUpdated:sender];
+}
+
+// (URLDropTarget protocol)
+- (void)draggingExited:(id<NSDraggingInfo>)sender {
+ return [dropHandler_ draggingExited:sender];
+}
+
+// (URLDropTarget protocol)
+- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
+ return [dropHandler_ performDragOperation:sender];
+}
+
+- (NSMenu*)decorationMenuForEvent:(NSEvent*)event {
+ AutocompleteTextFieldCell* cell = [self cell];
+ return [cell decorationMenuForEvent:event inRect:[self bounds] ofView:self];
+}
+
+- (ViewID)viewID {
+ return VIEW_ID_LOCATION_BAR;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h
new file mode 100644
index 0000000..1306253
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h
@@ -0,0 +1,76 @@
+// 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.
+
+#include <vector>
+
+#import <Cocoa/Cocoa.h>
+
+#import "chrome/browser/ui/cocoa/styled_text_field_cell.h"
+
+@class AutocompleteTextField;
+class LocationBarDecoration;
+
+// AutocompleteTextFieldCell extends StyledTextFieldCell to provide support for
+// certain decorations to be applied to the field. These are the search hint
+// ("Type to search" on the right-hand side), the keyword hint ("Press [Tab] to
+// search Engine" on the right-hand side), and keyword mode ("Search Engine:" in
+// a button-like token on the left-hand side).
+@interface AutocompleteTextFieldCell : StyledTextFieldCell {
+ @private
+ // Decorations which live to the left and right of the text, ordered
+ // from outside in. Decorations are owned by |LocationBarViewMac|.
+ std::vector<LocationBarDecoration*> leftDecorations_;
+ std::vector<LocationBarDecoration*> rightDecorations_;
+}
+
+// Clear |leftDecorations_| and |rightDecorations_|.
+- (void)clearDecorations;
+
+// Add a new left-side decoration to the right of the existing
+// left-side decorations.
+- (void)addLeftDecoration:(LocationBarDecoration*)decoration;
+
+// Add a new right-side decoration to the left of the existing
+// right-side decorations.
+- (void)addRightDecoration:(LocationBarDecoration*)decoration;
+
+// The width available after accounting for decorations.
+- (CGFloat)availableWidthInFrame:(const NSRect)frame;
+
+// Return the frame for |aDecoration| if the cell is in |cellFrame|.
+// Returns |NSZeroRect| for decorations which are not currently
+// visible.
+- (NSRect)frameForDecoration:(const LocationBarDecoration*)aDecoration
+ inFrame:(NSRect)cellFrame;
+
+// Find the decoration under the event. |NULL| if |theEvent| is not
+// over anything.
+- (LocationBarDecoration*)decorationForEvent:(NSEvent*)theEvent
+ inRect:(NSRect)cellFrame
+ ofView:(AutocompleteTextField*)field;
+
+// Return the appropriate menu for any decorations under event.
+// Returns nil if no menu is present for the decoration, or if the
+// event is not over a decoration.
+- (NSMenu*)decorationMenuForEvent:(NSEvent*)theEvent
+ inRect:(NSRect)cellFrame
+ ofView:(AutocompleteTextField*)controlView;
+
+// Called by |AutocompleteTextField| to let page actions intercept
+// clicks. Returns |YES| if the click has been intercepted.
+- (BOOL)mouseDown:(NSEvent*)theEvent
+ inRect:(NSRect)cellFrame
+ ofView:(AutocompleteTextField*)controlView;
+
+// Overridden from StyledTextFieldCell to include decorations adjacent
+// to the text area which don't handle mouse clicks themselves.
+// Keyword-search bubble, for instance.
+- (NSRect)textCursorFrameForFrame:(NSRect)cellFrame;
+
+// Setup decoration tooltips on |controlView| by calling
+// |-addToolTip:forRect:|.
+- (void)updateToolTipsInRect:(NSRect)cellFrame
+ ofView:(AutocompleteTextField*)controlView;
+
+@end
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm
new file mode 100644
index 0000000..02c8a66
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm
@@ -0,0 +1,402 @@
+// 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 "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
+
+#include "base/logging.h"
+#import "chrome/browser/ui/cocoa/image_utils.h"
+#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
+#import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
+
+namespace {
+
+const CGFloat kBaselineAdjust = 3.0;
+
+// Matches the clipping radius of |GradientButtonCell|.
+const CGFloat kCornerRadius = 4.0;
+
+// How far to inset the left-hand decorations from the field's bounds.
+const CGFloat kLeftDecorationXOffset = 5.0;
+
+// How far to inset the right-hand decorations from the field's bounds.
+// TODO(shess): Why is this different from |kLeftDecorationXOffset|?
+// |kDecorationOuterXOffset|?
+const CGFloat kRightDecorationXOffset = 5.0;
+
+// The amount of padding on either side reserved for drawing
+// decorations. [Views has |kItemPadding| == 3.]
+const CGFloat kDecorationHorizontalPad = 3.0;
+
+// How long to wait for mouse-up on the location icon before assuming
+// that the user wants to drag.
+const NSTimeInterval kLocationIconDragTimeout = 0.25;
+
+// Calculate the positions for a set of decorations. |frame| is the
+// overall frame to do layout in, |remaining_frame| will get the
+// left-over space. |all_decorations| is the set of decorations to
+// lay out, |decorations| will be set to the decorations which are
+// visible and which fit, in the same order as |all_decorations|,
+// while |decoration_frames| will be the corresponding frames.
+// |x_edge| describes the edge to layout the decorations against
+// (|NSMinXEdge| or |NSMaxXEdge|). |initial_padding| is the padding
+// from the edge of |cell_frame| (|kDecorationHorizontalPad| is used
+// between decorations).
+void CalculatePositionsHelper(
+ NSRect frame,
+ const std::vector<LocationBarDecoration*>& all_decorations,
+ NSRectEdge x_edge,
+ CGFloat initial_padding,
+ std::vector<LocationBarDecoration*>* decorations,
+ std::vector<NSRect>* decoration_frames,
+ NSRect* remaining_frame) {
+ DCHECK(x_edge == NSMinXEdge || x_edge == NSMaxXEdge);
+ DCHECK_EQ(decorations->size(), decoration_frames->size());
+
+ // The outer-most decoration will be inset a bit further from the
+ // edge.
+ CGFloat padding = initial_padding;
+
+ for (size_t i = 0; i < all_decorations.size(); ++i) {
+ if (all_decorations[i]->IsVisible()) {
+ NSRect padding_rect, available;
+
+ // Peel off the outside padding.
+ NSDivideRect(frame, &padding_rect, &available, padding, x_edge);
+
+ // Find out how large the decoration will be in the remaining
+ // space.
+ const CGFloat used_width =
+ all_decorations[i]->GetWidthForSpace(NSWidth(available));
+
+ if (used_width != LocationBarDecoration::kOmittedWidth) {
+ DCHECK_GT(used_width, 0.0);
+ NSRect decoration_frame;
+
+ // Peel off the desired width, leaving the remainder in
+ // |frame|.
+ NSDivideRect(available, &decoration_frame, &frame,
+ used_width, x_edge);
+
+ decorations->push_back(all_decorations[i]);
+ decoration_frames->push_back(decoration_frame);
+ DCHECK_EQ(decorations->size(), decoration_frames->size());
+
+ // Adjust padding for between decorations.
+ padding = kDecorationHorizontalPad;
+ }
+ }
+ }
+
+ DCHECK_EQ(decorations->size(), decoration_frames->size());
+ *remaining_frame = frame;
+}
+
+// Helper function for calculating placement of decorations w/in the
+// cell. |frame| is the cell's boundary rectangle, |remaining_frame|
+// will get any space left after decorations are laid out (for text).
+// |left_decorations| is a set of decorations for the left-hand side
+// of the cell, |right_decorations| for the right-hand side.
+// |decorations| will contain the resulting visible decorations, and
+// |decoration_frames| will contain their frames in the same
+// coordinates as |frame|. Decorations will be ordered left to right.
+// As a convenience returns the index of the first right-hand
+// decoration.
+size_t CalculatePositionsInFrame(
+ NSRect frame,
+ const std::vector<LocationBarDecoration*>& left_decorations,
+ const std::vector<LocationBarDecoration*>& right_decorations,
+ std::vector<LocationBarDecoration*>* decorations,
+ std::vector<NSRect>* decoration_frames,
+ NSRect* remaining_frame) {
+ decorations->clear();
+ decoration_frames->clear();
+
+ // Layout |left_decorations| against the LHS.
+ CalculatePositionsHelper(frame, left_decorations,
+ NSMinXEdge, kLeftDecorationXOffset,
+ decorations, decoration_frames, &frame);
+ DCHECK_EQ(decorations->size(), decoration_frames->size());
+
+ // Capture the number of visible left-hand decorations.
+ const size_t left_count = decorations->size();
+
+ // Layout |right_decorations| against the RHS.
+ CalculatePositionsHelper(frame, right_decorations,
+ NSMaxXEdge, kRightDecorationXOffset,
+ decorations, decoration_frames, &frame);
+ DCHECK_EQ(decorations->size(), decoration_frames->size());
+
+ // Reverse the right-hand decorations so that overall everything is
+ // sorted left to right.
+ std::reverse(decorations->begin() + left_count, decorations->end());
+ std::reverse(decoration_frames->begin() + left_count,
+ decoration_frames->end());
+
+ *remaining_frame = frame;
+ return left_count;
+}
+
+} // namespace
+
+@implementation AutocompleteTextFieldCell
+
+- (CGFloat)baselineAdjust {
+ return kBaselineAdjust;
+}
+
+- (CGFloat)cornerRadius {
+ return kCornerRadius;
+}
+
+- (BOOL)shouldDrawBezel {
+ return YES;
+}
+
+- (void)clearDecorations {
+ leftDecorations_.clear();
+ rightDecorations_.clear();
+}
+
+- (void)addLeftDecoration:(LocationBarDecoration*)decoration {
+ leftDecorations_.push_back(decoration);
+}
+
+- (void)addRightDecoration:(LocationBarDecoration*)decoration {
+ rightDecorations_.push_back(decoration);
+}
+
+- (CGFloat)availableWidthInFrame:(const NSRect)frame {
+ std::vector<LocationBarDecoration*> decorations;
+ std::vector<NSRect> decorationFrames;
+ NSRect textFrame;
+ CalculatePositionsInFrame(frame, leftDecorations_, rightDecorations_,
+ &decorations, &decorationFrames, &textFrame);
+
+ return NSWidth(textFrame);
+}
+
+- (NSRect)frameForDecoration:(const LocationBarDecoration*)aDecoration
+ inFrame:(NSRect)cellFrame {
+ // Short-circuit if the decoration is known to be not visible.
+ if (aDecoration && !aDecoration->IsVisible())
+ return NSZeroRect;
+
+ // Layout the decorations.
+ std::vector<LocationBarDecoration*> decorations;
+ std::vector<NSRect> decorationFrames;
+ NSRect textFrame;
+ CalculatePositionsInFrame(cellFrame, leftDecorations_, rightDecorations_,
+ &decorations, &decorationFrames, &textFrame);
+
+ // Find our decoration and return the corresponding frame.
+ std::vector<LocationBarDecoration*>::const_iterator iter =
+ std::find(decorations.begin(), decorations.end(), aDecoration);
+ if (iter != decorations.end()) {
+ const size_t index = iter - decorations.begin();
+ return decorationFrames[index];
+ }
+
+ // Decorations which are not visible should have been filtered out
+ // at the top, but return |NSZeroRect| rather than a 0-width rect
+ // for consistency.
+ NOTREACHED();
+ return NSZeroRect;
+}
+
+// Overriden to account for the decorations.
+- (NSRect)textFrameForFrame:(NSRect)cellFrame {
+ // Get the frame adjusted for decorations.
+ std::vector<LocationBarDecoration*> decorations;
+ std::vector<NSRect> decorationFrames;
+ NSRect textFrame = [super textFrameForFrame:cellFrame];
+ CalculatePositionsInFrame(textFrame, leftDecorations_, rightDecorations_,
+ &decorations, &decorationFrames, &textFrame);
+
+ // NOTE: This function must closely match the logic in
+ // |-drawInteriorWithFrame:inView:|.
+
+ return textFrame;
+}
+
+- (NSRect)textCursorFrameForFrame:(NSRect)cellFrame {
+ std::vector<LocationBarDecoration*> decorations;
+ std::vector<NSRect> decorationFrames;
+ NSRect textFrame;
+ size_t left_count =
+ CalculatePositionsInFrame(cellFrame, leftDecorations_, rightDecorations_,
+ &decorations, &decorationFrames, &textFrame);
+
+ // Determine the left-most extent for the i-beam cursor.
+ CGFloat minX = NSMinX(textFrame);
+ for (size_t index = left_count; index--; ) {
+ if (decorations[index]->AcceptsMousePress())
+ break;
+
+ // If at leftmost decoration, expand to edge of cell.
+ if (!index) {
+ minX = NSMinX(cellFrame);
+ } else {
+ minX = NSMinX(decorationFrames[index]) - kDecorationHorizontalPad;
+ }
+ }
+
+ // Determine the right-most extent for the i-beam cursor.
+ CGFloat maxX = NSMaxX(textFrame);
+ for (size_t index = left_count; index < decorations.size(); ++index) {
+ if (decorations[index]->AcceptsMousePress())
+ break;
+
+ // If at rightmost decoration, expand to edge of cell.
+ if (index == decorations.size() - 1) {
+ maxX = NSMaxX(cellFrame);
+ } else {
+ maxX = NSMaxX(decorationFrames[index]) + kDecorationHorizontalPad;
+ }
+ }
+
+ // I-beam cursor covers left-most to right-most.
+ return NSMakeRect(minX, NSMinY(textFrame), maxX - minX, NSHeight(textFrame));
+}
+
+- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
+ std::vector<LocationBarDecoration*> decorations;
+ std::vector<NSRect> decorationFrames;
+ NSRect workingFrame;
+ CalculatePositionsInFrame(cellFrame, leftDecorations_, rightDecorations_,
+ &decorations, &decorationFrames, &workingFrame);
+
+ // Draw the decorations.
+ for (size_t i = 0; i < decorations.size(); ++i) {
+ if (decorations[i])
+ decorations[i]->DrawInFrame(decorationFrames[i], controlView);
+ }
+
+ // NOTE: This function must closely match the logic in
+ // |-textFrameForFrame:|.
+
+ // Superclass draws text portion WRT original |cellFrame|.
+ [super drawInteriorWithFrame:cellFrame inView:controlView];
+}
+
+- (LocationBarDecoration*)decorationForEvent:(NSEvent*)theEvent
+ inRect:(NSRect)cellFrame
+ ofView:(AutocompleteTextField*)controlView
+{
+ const BOOL flipped = [controlView isFlipped];
+ const NSPoint location =
+ [controlView convertPoint:[theEvent locationInWindow] fromView:nil];
+
+ std::vector<LocationBarDecoration*> decorations;
+ std::vector<NSRect> decorationFrames;
+ NSRect textFrame;
+ CalculatePositionsInFrame(cellFrame, leftDecorations_, rightDecorations_,
+ &decorations, &decorationFrames, &textFrame);
+
+ for (size_t i = 0; i < decorations.size(); ++i) {
+ if (NSMouseInRect(location, decorationFrames[i], flipped))
+ return decorations[i];
+ }
+
+ return NULL;
+}
+
+- (NSMenu*)decorationMenuForEvent:(NSEvent*)theEvent
+ inRect:(NSRect)cellFrame
+ ofView:(AutocompleteTextField*)controlView {
+ LocationBarDecoration* decoration =
+ [self decorationForEvent:theEvent inRect:cellFrame ofView:controlView];
+ if (decoration)
+ return decoration->GetMenu();
+ return nil;
+}
+
+- (BOOL)mouseDown:(NSEvent*)theEvent
+ inRect:(NSRect)cellFrame
+ ofView:(AutocompleteTextField*)controlView {
+ LocationBarDecoration* decoration =
+ [self decorationForEvent:theEvent inRect:cellFrame ofView:controlView];
+ if (!decoration || !decoration->AcceptsMousePress())
+ return NO;
+
+ NSRect decorationRect =
+ [self frameForDecoration:decoration inFrame:cellFrame];
+
+ // If the decoration is draggable, then initiate a drag if the user
+ // drags or holds the mouse down for awhile.
+ if (decoration->IsDraggable()) {
+ NSDate* timeout =
+ [NSDate dateWithTimeIntervalSinceNow:kLocationIconDragTimeout];
+ NSEvent* event = [NSApp nextEventMatchingMask:(NSLeftMouseDraggedMask |
+ NSLeftMouseUpMask)
+ untilDate:timeout
+ inMode:NSEventTrackingRunLoopMode
+ dequeue:YES];
+ if (!event || [event type] == NSLeftMouseDragged) {
+ NSPasteboard* pboard = decoration->GetDragPasteboard();
+ DCHECK(pboard);
+
+ NSImage* image = decoration->GetDragImage();
+ DCHECK(image);
+
+ NSRect dragImageRect = decoration->GetDragImageFrame(decorationRect);
+
+ // If the original click is not within |dragImageRect|, then
+ // center the image under the mouse. Otherwise, will drag from
+ // where the click was on the image.
+ const NSPoint mousePoint =
+ [controlView convertPoint:[theEvent locationInWindow] fromView:nil];
+ if (!NSMouseInRect(mousePoint, dragImageRect, [controlView isFlipped])) {
+ dragImageRect.origin =
+ NSMakePoint(mousePoint.x - NSWidth(dragImageRect) / 2.0,
+ mousePoint.y - NSHeight(dragImageRect) / 2.0);
+ }
+
+ // -[NSView dragImage:at:*] wants the images lower-left point,
+ // regardless of -isFlipped. Converting the rect to window base
+ // coordinates doesn't require any special-casing. Note that
+ // -[NSView dragFile:fromRect:*] takes a rect rather than a
+ // point, likely for this exact reason.
+ const NSPoint dragPoint =
+ [controlView convertRect:dragImageRect toView:nil].origin;
+ [[controlView window] dragImage:image
+ at:dragPoint
+ offset:NSZeroSize
+ event:theEvent
+ pasteboard:pboard
+ source:self
+ slideBack:YES];
+
+ return YES;
+ }
+
+ // On mouse-up fall through to mouse-pressed case.
+ DCHECK_EQ([event type], NSLeftMouseUp);
+ }
+
+ if (!decoration->OnMousePressed(decorationRect))
+ return NO;
+
+ return YES;
+}
+
+- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal {
+ return NSDragOperationCopy;
+}
+
+- (void)updateToolTipsInRect:(NSRect)cellFrame
+ ofView:(AutocompleteTextField*)controlView {
+ std::vector<LocationBarDecoration*> decorations;
+ std::vector<NSRect> decorationFrames;
+ NSRect textFrame;
+ CalculatePositionsInFrame(cellFrame, leftDecorations_, rightDecorations_,
+ &decorations, &decorationFrames, &textFrame);
+
+ for (size_t i = 0; i < decorations.size(); ++i) {
+ NSString* tooltip = decorations[i]->GetToolTip();
+ if ([tooltip length] > 0)
+ [controlView addToolTip:tooltip forRect:decorationFrames[i]];
+ }
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm
new file mode 100644
index 0000000..1598cad
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm
@@ -0,0 +1,300 @@
+// 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 "app/resource_bundle.h"
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
+#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
+#import "chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration.h"
+#import "chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.h"
+#import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
+#import "chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h"
+#import "chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.h"
+#import "chrome/browser/ui/cocoa/location_bar/star_decoration.h"
+#include "grit/theme_resources.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+
+using ::testing::Return;
+using ::testing::StrictMock;
+using ::testing::_;
+
+namespace {
+
+// Width of the field so that we don't have to ask |field_| for it all
+// the time.
+const CGFloat kWidth(300.0);
+
+// A narrow width for tests which test things that don't fit.
+const CGFloat kNarrowWidth(5.0);
+
+class MockDecoration : public LocationBarDecoration {
+ public:
+ virtual CGFloat GetWidthForSpace(CGFloat width) { return 20.0; }
+
+ MOCK_METHOD2(DrawInFrame, void(NSRect frame, NSView* control_view));
+ MOCK_METHOD0(GetToolTip, NSString*());
+};
+
+class AutocompleteTextFieldCellTest : public CocoaTest {
+ public:
+ AutocompleteTextFieldCellTest() {
+ // Make sure this is wide enough to play games with the cell
+ // decorations.
+ const NSRect frame = NSMakeRect(0, 0, kWidth, 30);
+
+ scoped_nsobject<NSTextField> view(
+ [[NSTextField alloc] initWithFrame:frame]);
+ view_ = view.get();
+
+ scoped_nsobject<AutocompleteTextFieldCell> cell(
+ [[AutocompleteTextFieldCell alloc] initTextCell:@"Testing"]);
+ [cell setEditable:YES];
+ [cell setBordered:YES];
+
+ [cell clearDecorations];
+ mock_left_decoration_.SetVisible(false);
+ [cell addLeftDecoration:&mock_left_decoration_];
+ mock_right_decoration0_.SetVisible(false);
+ mock_right_decoration1_.SetVisible(false);
+ [cell addRightDecoration:&mock_right_decoration0_];
+ [cell addRightDecoration:&mock_right_decoration1_];
+
+ [view_ setCell:cell.get()];
+
+ [[test_window() contentView] addSubview:view_];
+ }
+
+ NSTextField* view_;
+ MockDecoration mock_left_decoration_;
+ MockDecoration mock_right_decoration0_;
+ MockDecoration mock_right_decoration1_;
+};
+
+// Basic view tests (AddRemove, Display).
+TEST_VIEW(AutocompleteTextFieldCellTest, view_);
+
+// Test drawing, mostly to ensure nothing leaks or crashes.
+// Flaky, disabled. Bug http://crbug.com/49522
+TEST_F(AutocompleteTextFieldCellTest, DISABLED_FocusedDisplay) {
+ [view_ display];
+
+ // Test focused drawing.
+ [test_window() makePretendKeyWindowAndSetFirstResponder:view_];
+ [view_ display];
+ [test_window() clearPretendKeyWindowAndFirstResponder];
+
+ // Test display of various cell configurations.
+ AutocompleteTextFieldCell* cell =
+ static_cast<AutocompleteTextFieldCell*>([view_ cell]);
+
+ // Load available decorations and try drawing. To make sure that
+ // they are actually drawn, check that |GetWidthForSpace()| doesn't
+ // indicate that they should be omitted.
+ const CGFloat kVeryWide = 1000.0;
+
+ SelectedKeywordDecoration selected_keyword_decoration([view_ font]);
+ selected_keyword_decoration.SetVisible(true);
+ selected_keyword_decoration.SetKeyword(std::wstring(L"Google"), false);
+ [cell addLeftDecoration:&selected_keyword_decoration];
+ EXPECT_NE(selected_keyword_decoration.GetWidthForSpace(kVeryWide),
+ LocationBarDecoration::kOmittedWidth);
+
+ // TODO(shess): This really wants a |LocationBarViewMac|, but only a
+ // few methods reference it, so this works well enough. But
+ // something better would be nice.
+ LocationIconDecoration location_icon_decoration(NULL);
+ location_icon_decoration.SetVisible(true);
+ location_icon_decoration.SetImage([NSImage imageNamed:@"NSApplicationIcon"]);
+ [cell addLeftDecoration:&location_icon_decoration];
+ EXPECT_NE(location_icon_decoration.GetWidthForSpace(kVeryWide),
+ LocationBarDecoration::kOmittedWidth);
+
+ EVBubbleDecoration ev_bubble_decoration(&location_icon_decoration,
+ [view_ font]);
+ ev_bubble_decoration.SetVisible(true);
+ ev_bubble_decoration.SetImage([NSImage imageNamed:@"NSApplicationIcon"]);
+ ev_bubble_decoration.SetLabel(@"Application");
+ [cell addLeftDecoration:&ev_bubble_decoration];
+ EXPECT_NE(ev_bubble_decoration.GetWidthForSpace(kVeryWide),
+ LocationBarDecoration::kOmittedWidth);
+
+ StarDecoration star_decoration(NULL);
+ star_decoration.SetVisible(true);
+ [cell addRightDecoration:&star_decoration];
+ EXPECT_NE(star_decoration.GetWidthForSpace(kVeryWide),
+ LocationBarDecoration::kOmittedWidth);
+
+ KeywordHintDecoration keyword_hint_decoration([view_ font]);
+ keyword_hint_decoration.SetVisible(true);
+ keyword_hint_decoration.SetKeyword(std::wstring(L"google"), false);
+ [cell addRightDecoration:&keyword_hint_decoration];
+ EXPECT_NE(keyword_hint_decoration.GetWidthForSpace(kVeryWide),
+ LocationBarDecoration::kOmittedWidth);
+
+ // Make sure we're actually calling |DrawInFrame()|.
+ StrictMock<MockDecoration> mock_decoration;
+ mock_decoration.SetVisible(true);
+ [cell addLeftDecoration:&mock_decoration];
+ EXPECT_CALL(mock_decoration, DrawInFrame(_, _));
+ EXPECT_NE(mock_decoration.GetWidthForSpace(kVeryWide),
+ LocationBarDecoration::kOmittedWidth);
+
+ [view_ display];
+
+ [cell clearDecorations];
+}
+
+TEST_F(AutocompleteTextFieldCellTest, TextFrame) {
+ AutocompleteTextFieldCell* cell =
+ static_cast<AutocompleteTextFieldCell*>([view_ cell]);
+ const NSRect bounds([view_ bounds]);
+ NSRect textFrame;
+
+ // The cursor frame should stay the same throughout.
+ const NSRect cursorFrame([cell textCursorFrameForFrame:bounds]);
+ EXPECT_TRUE(NSEqualRects(cursorFrame, bounds));
+
+ // At default settings, everything goes to the text area.
+ textFrame = [cell textFrameForFrame:bounds];
+ EXPECT_FALSE(NSIsEmptyRect(textFrame));
+ EXPECT_TRUE(NSContainsRect(bounds, textFrame));
+ EXPECT_EQ(NSMinX(bounds), NSMinX(textFrame));
+ EXPECT_EQ(NSMaxX(bounds), NSMaxX(textFrame));
+ EXPECT_TRUE(NSContainsRect(cursorFrame, textFrame));
+
+ // Decoration on the left takes up space.
+ mock_left_decoration_.SetVisible(true);
+ textFrame = [cell textFrameForFrame:bounds];
+ EXPECT_FALSE(NSIsEmptyRect(textFrame));
+ EXPECT_TRUE(NSContainsRect(bounds, textFrame));
+ EXPECT_GT(NSMinX(textFrame), NSMinX(bounds));
+ EXPECT_TRUE(NSContainsRect(cursorFrame, textFrame));
+}
+
+// The editor frame should be slightly inset from the text frame.
+TEST_F(AutocompleteTextFieldCellTest, DrawingRectForBounds) {
+ AutocompleteTextFieldCell* cell =
+ static_cast<AutocompleteTextFieldCell*>([view_ cell]);
+ const NSRect bounds([view_ bounds]);
+ NSRect textFrame, drawingRect;
+
+ textFrame = [cell textFrameForFrame:bounds];
+ drawingRect = [cell drawingRectForBounds:bounds];
+ EXPECT_FALSE(NSIsEmptyRect(drawingRect));
+ EXPECT_TRUE(NSContainsRect(textFrame, NSInsetRect(drawingRect, 1, 1)));
+
+ // Save the starting frame for after clear.
+ const NSRect originalDrawingRect = drawingRect;
+
+ mock_left_decoration_.SetVisible(true);
+ textFrame = [cell textFrameForFrame:bounds];
+ drawingRect = [cell drawingRectForBounds:bounds];
+ EXPECT_FALSE(NSIsEmptyRect(drawingRect));
+ EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect));
+
+ mock_right_decoration0_.SetVisible(true);
+ textFrame = [cell textFrameForFrame:bounds];
+ drawingRect = [cell drawingRectForBounds:bounds];
+ EXPECT_FALSE(NSIsEmptyRect(drawingRect));
+ EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect));
+
+ mock_left_decoration_.SetVisible(false);
+ mock_right_decoration0_.SetVisible(false);
+ drawingRect = [cell drawingRectForBounds:bounds];
+ EXPECT_FALSE(NSIsEmptyRect(drawingRect));
+ EXPECT_TRUE(NSEqualRects(drawingRect, originalDrawingRect));
+}
+
+// Test that left decorations are at the correct edge of the cell.
+TEST_F(AutocompleteTextFieldCellTest, LeftDecorationFrame) {
+ AutocompleteTextFieldCell* cell =
+ static_cast<AutocompleteTextFieldCell*>([view_ cell]);
+ const NSRect bounds = [view_ bounds];
+
+ mock_left_decoration_.SetVisible(true);
+ const NSRect decorationRect =
+ [cell frameForDecoration:&mock_left_decoration_ inFrame:bounds];
+ EXPECT_FALSE(NSIsEmptyRect(decorationRect));
+ EXPECT_TRUE(NSContainsRect(bounds, decorationRect));
+
+ // Decoration should be left of |drawingRect|.
+ const NSRect drawingRect = [cell drawingRectForBounds:bounds];
+ EXPECT_GT(NSMinX(drawingRect), NSMinX(decorationRect));
+
+ // Decoration should be left of |textFrame|.
+ const NSRect textFrame = [cell textFrameForFrame:bounds];
+ EXPECT_GT(NSMinX(textFrame), NSMinX(decorationRect));
+}
+
+// Test that right decorations are at the correct edge of the cell.
+TEST_F(AutocompleteTextFieldCellTest, RightDecorationFrame) {
+ AutocompleteTextFieldCell* cell =
+ static_cast<AutocompleteTextFieldCell*>([view_ cell]);
+ const NSRect bounds = [view_ bounds];
+
+ mock_right_decoration0_.SetVisible(true);
+ mock_right_decoration1_.SetVisible(true);
+
+ const NSRect decoration0Rect =
+ [cell frameForDecoration:&mock_right_decoration0_ inFrame:bounds];
+ EXPECT_FALSE(NSIsEmptyRect(decoration0Rect));
+ EXPECT_TRUE(NSContainsRect(bounds, decoration0Rect));
+
+ // Right-side decorations are ordered from rightmost to leftmost.
+ // Outer decoration (0) to right of inner decoration (1).
+ const NSRect decoration1Rect =
+ [cell frameForDecoration:&mock_right_decoration1_ inFrame:bounds];
+ EXPECT_FALSE(NSIsEmptyRect(decoration1Rect));
+ EXPECT_TRUE(NSContainsRect(bounds, decoration1Rect));
+ EXPECT_LT(NSMinX(decoration1Rect), NSMinX(decoration0Rect));
+
+ // Decoration should be right of |drawingRect|.
+ const NSRect drawingRect = [cell drawingRectForBounds:bounds];
+ EXPECT_LT(NSMinX(drawingRect), NSMinX(decoration1Rect));
+
+ // Decoration should be right of |textFrame|.
+ const NSRect textFrame = [cell textFrameForFrame:bounds];
+ EXPECT_LT(NSMinX(textFrame), NSMinX(decoration1Rect));
+}
+
+// Verify -[AutocompleteTextFieldCell updateToolTipsInRect:ofView:].
+TEST_F(AutocompleteTextFieldCellTest, UpdateToolTips) {
+ NSString* tooltip = @"tooltip";
+
+ // Left decoration returns a tooltip, make sure it is called at
+ // least once.
+ mock_left_decoration_.SetVisible(true);
+ EXPECT_CALL(mock_left_decoration_, GetToolTip())
+ .WillOnce(Return(tooltip))
+ .WillRepeatedly(Return(tooltip));
+
+ // Right decoration returns no tooltip, make sure it is called at
+ // least once.
+ mock_right_decoration0_.SetVisible(true);
+ EXPECT_CALL(mock_right_decoration0_, GetToolTip())
+ .WillOnce(Return((NSString*)nil))
+ .WillRepeatedly(Return((NSString*)nil));
+
+ AutocompleteTextFieldCell* cell =
+ static_cast<AutocompleteTextFieldCell*>([view_ cell]);
+ const NSRect bounds = [view_ bounds];
+ const NSRect leftDecorationRect =
+ [cell frameForDecoration:&mock_left_decoration_ inFrame:bounds];
+
+ // |controlView| gets the tooltip for the left decoration.
+ id controlView = [OCMockObject mockForClass:[AutocompleteTextField class]];
+ [[controlView expect] addToolTip:tooltip forRect:leftDecorationRect];
+
+ [cell updateToolTipsInRect:bounds ofView:controlView];
+
+ [controlView verify];
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h
new file mode 100644
index 0000000..905bc84
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h
@@ -0,0 +1,56 @@
+// 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 "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/url_drop_target.h"
+
+@class AutocompleteTextField;
+class AutocompleteTextFieldObserver;
+
+// AutocompleteTextFieldEditor customized the AutocompletTextField
+// field editor (helper text-view used in editing). It intercepts UI
+// events for forwarding to the core Omnibox code. It also undoes
+// some of the effects of using styled text in the Omnibox (the text
+// is styled but should not appear that way when copied to the
+// pasteboard).
+
+// Field editor used for the autocomplete field.
+@interface AutocompleteTextFieldEditor : NSTextView<URLDropTarget> {
+ // Handles being a drag-and-drop target. We handle DnD directly instead
+ // allowing the |AutocompletTextField| to handle it (by making an empty
+ // |-updateDragTypeRegistration|), since the latter results in a weird
+ // start-up time regression.
+ scoped_nsobject<URLDropTargetHandler> dropHandler_;
+
+ scoped_nsobject<NSCharacterSet> forbiddenCharacters_;
+
+ // Indicates if the field editor's interpretKeyEvents: method is being called.
+ // If it's YES, then we should postpone the call to the observer's
+ // OnDidChange() method after the field editor's interpretKeyEvents: method
+ // is finished, rather than calling it in textDidChange: method. Because the
+ // input method may update the marked text after inserting some text, but we
+ // need the observer be aware of the marked text as well.
+ BOOL interpretingKeyEvents_;
+
+ // Indicates if the text has been changed by key events.
+ BOOL textChangedByKeyEvents_;
+}
+
+// The delegate is always an AutocompleteTextField*. Override the superclass
+// implementations to allow for proper typing.
+- (AutocompleteTextField*)delegate;
+- (void)setDelegate:(AutocompleteTextField*)delegate;
+
+// Sets attributed string programatically through the field editor's text
+// storage object.
+- (void)setAttributedString:(NSAttributedString*)aString;
+
+@end
+
+@interface AutocompleteTextFieldEditor(PrivateTestMethods)
+- (AutocompleteTextFieldObserver*)observer;
+- (void)pasteAndGo:sender;
+@end
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.mm
new file mode 100644
index 0000000..37b6029
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.mm
@@ -0,0 +1,380 @@
+// 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 "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h"
+
+#include "app/l10n_util_mac.h"
+#include "base/string_util.h"
+#include "grit/generated_resources.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h" // IDC_*
+#include "chrome/browser/browser_list.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
+#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
+#import "chrome/browser/ui/cocoa/toolbar_controller.h"
+
+@implementation AutocompleteTextFieldEditor
+
+- (id)initWithFrame:(NSRect)frameRect {
+ if ((self = [super initWithFrame:frameRect])) {
+ dropHandler_.reset([[URLDropTargetHandler alloc] initWithView:self]);
+
+ forbiddenCharacters_.reset([[NSCharacterSet controlCharacterSet] retain]);
+ }
+ return self;
+}
+
+// If the entire field is selected, drag the same data as would be
+// dragged from the field's location icon. In some cases the textual
+// contents will not contain relevant data (for instance, "http://" is
+// stripped from URLs).
+- (BOOL)dragSelectionWithEvent:(NSEvent *)event
+ offset:(NSSize)mouseOffset
+ slideBack:(BOOL)slideBack {
+ AutocompleteTextFieldObserver* observer = [self observer];
+ DCHECK(observer);
+ if (observer && observer->CanCopy()) {
+ NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
+ observer->CopyToPasteboard(pboard);
+
+ NSPoint p;
+ NSImage* image = [self dragImageForSelectionWithEvent:event origin:&p];
+
+ [self dragImage:image
+ at:p
+ offset:mouseOffset
+ event:event
+ pasteboard:pboard
+ source:self
+ slideBack:slideBack];
+ return YES;
+ }
+ return [super dragSelectionWithEvent:event
+ offset:mouseOffset
+ slideBack:slideBack];
+}
+
+- (void)copy:(id)sender {
+ AutocompleteTextFieldObserver* observer = [self observer];
+ DCHECK(observer);
+ if (observer && observer->CanCopy())
+ observer->CopyToPasteboard([NSPasteboard generalPasteboard]);
+}
+
+- (void)cut:(id)sender {
+ [self copy:sender];
+ [self delete:nil];
+}
+
+// This class assumes that the delegate is an AutocompleteTextField.
+// Enforce that assumption.
+- (AutocompleteTextField*)delegate {
+ AutocompleteTextField* delegate =
+ static_cast<AutocompleteTextField*>([super delegate]);
+ DCHECK(delegate == nil ||
+ [delegate isKindOfClass:[AutocompleteTextField class]]);
+ return delegate;
+}
+
+- (void)setDelegate:(AutocompleteTextField*)delegate {
+ DCHECK(delegate == nil ||
+ [delegate isKindOfClass:[AutocompleteTextField class]]);
+ [super setDelegate:delegate];
+}
+
+// Convenience method for retrieving the observer from the delegate.
+- (AutocompleteTextFieldObserver*)observer {
+ return [[self delegate] observer];
+}
+
+- (void)paste:(id)sender {
+ AutocompleteTextFieldObserver* observer = [self observer];
+ DCHECK(observer);
+ if (observer) {
+ observer->OnPaste();
+ }
+}
+
+- (void)pasteAndGo:sender {
+ AutocompleteTextFieldObserver* observer = [self observer];
+ DCHECK(observer);
+ if (observer) {
+ observer->OnPasteAndGo();
+ }
+}
+
+// We have rich text, but it shouldn't be modified by the user, so
+// don't update the font panel. In theory, -setUsesFontPanel: should
+// accomplish this, but that gets called frequently with YES when
+// NSTextField and NSTextView synchronize their contents. That is
+// probably unavoidable because in most cases having rich text in the
+// field you probably would expect it to update the font panel.
+- (void)updateFontPanel {}
+
+// No ruler bar, so don't update any of that state, either.
+- (void)updateRuler {}
+
+- (NSMenu*)menuForEvent:(NSEvent*)event {
+ // Give the control a chance to provide page-action menus.
+ // NOTE: Note that page actions aren't even in the editor's
+ // boundaries! The Cocoa control implementation seems to do a
+ // blanket forward to here if nothing more specific is returned from
+ // the control and cell calls.
+ // TODO(shess): Determine if the page-action part of this can be
+ // moved to the cell.
+ NSMenu* actionMenu = [[self delegate] decorationMenuForEvent:event];
+ if (actionMenu)
+ return actionMenu;
+
+ NSMenu* menu = [[[NSMenu alloc] initWithTitle:@"TITLE"] autorelease];
+ [menu addItemWithTitle:l10n_util::GetNSStringWithFixup(IDS_CUT)
+ action:@selector(cut:)
+ keyEquivalent:@""];
+ [menu addItemWithTitle:l10n_util::GetNSStringWithFixup(IDS_COPY)
+ action:@selector(copy:)
+ keyEquivalent:@""];
+ [menu addItemWithTitle:l10n_util::GetNSStringWithFixup(IDS_PASTE)
+ action:@selector(paste:)
+ keyEquivalent:@""];
+
+ // TODO(shess): If the control is not editable, should we show a
+ // greyed-out "Paste and Go"?
+ if ([self isEditable]) {
+ // Paste and go/search.
+ AutocompleteTextFieldObserver* observer = [self observer];
+ DCHECK(observer);
+ if (observer && observer->CanPasteAndGo()) {
+ const int string_id = observer->GetPasteActionStringId();
+ NSString* label = l10n_util::GetNSStringWithFixup(string_id);
+
+ // TODO(rohitrao): If the clipboard is empty, should we show a
+ // greyed-out "Paste and Go" or nothing at all?
+ if ([label length]) {
+ [menu addItemWithTitle:label
+ action:@selector(pasteAndGo:)
+ keyEquivalent:@""];
+ }
+ }
+
+ NSString* label = l10n_util::GetNSStringWithFixup(IDS_EDIT_SEARCH_ENGINES);
+ DCHECK([label length]);
+ if ([label length]) {
+ [menu addItem:[NSMenuItem separatorItem]];
+ NSMenuItem* item = [menu addItemWithTitle:label
+ action:@selector(commandDispatch:)
+ keyEquivalent:@""];
+ [item setTag:IDC_EDIT_SEARCH_ENGINES];
+ }
+ }
+
+ return menu;
+}
+
+// (Overridden from NSResponder)
+- (BOOL)becomeFirstResponder {
+ BOOL doAccept = [super becomeFirstResponder];
+ AutocompleteTextField* field = [self delegate];
+ // Only lock visibility if we've been set up with a delegate (the text field).
+ if (doAccept && field) {
+ // Give the text field ownership of the visibility lock. (The first
+ // responder dance between the field and the field editor is a little
+ // weird.)
+ [[BrowserWindowController browserWindowControllerForView:field]
+ lockBarVisibilityForOwner:field withAnimation:YES delay:NO];
+ }
+ return doAccept;
+}
+
+// (Overridden from NSResponder)
+- (BOOL)resignFirstResponder {
+ BOOL doResign = [super resignFirstResponder];
+ AutocompleteTextField* field = [self delegate];
+ // Only lock visibility if we've been set up with a delegate (the text field).
+ if (doResign && field) {
+ // Give the text field ownership of the visibility lock.
+ [[BrowserWindowController browserWindowControllerForView:field]
+ releaseBarVisibilityForOwner:field withAnimation:YES delay:YES];
+
+ AutocompleteTextFieldObserver* observer = [self observer];
+ if (observer)
+ observer->OnKillFocus();
+ }
+ return doResign;
+}
+
+// (URLDropTarget protocol)
+- (id<URLDropTargetController>)urlDropController {
+ BrowserWindowController* windowController =
+ [BrowserWindowController browserWindowControllerForView:self];
+ return [windowController toolbarController];
+}
+
+// (URLDropTarget protocol)
+- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
+ // Make ourself the first responder (even though we're presumably already the
+ // first responder), which will select the text to indicate that our contents
+ // would be replaced by a drop.
+ [[self window] makeFirstResponder:self];
+ return [dropHandler_ draggingEntered:sender];
+}
+
+// (URLDropTarget protocol)
+- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender {
+ return [dropHandler_ draggingUpdated:sender];
+}
+
+// (URLDropTarget protocol)
+- (void)draggingExited:(id<NSDraggingInfo>)sender {
+ return [dropHandler_ draggingExited:sender];
+}
+
+// (URLDropTarget protocol)
+- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
+ return [dropHandler_ performDragOperation:sender];
+}
+
+// Prevent control characters from being entered into the Omnibox.
+// This is invoked for keyboard entry, not for pasting.
+- (void)insertText:(id)aString {
+ // This method is documented as received either |NSString| or
+ // |NSAttributedString|. The autocomplete code will restyle the
+ // results in any case, so simplify by always using |NSString|.
+ if ([aString isKindOfClass:[NSAttributedString class]])
+ aString = [aString string];
+
+ // Repeatedly remove control characters. The loop will only ever
+ // execute at allwhen the user enters control characters (using
+ // Ctrl-Alt- or Ctrl-Q). Making this generally efficient would
+ // probably be a loss, since the input always seems to be a single
+ // character.
+ NSRange range = [aString rangeOfCharacterFromSet:forbiddenCharacters_];
+ while (range.location != NSNotFound) {
+ aString = [aString stringByReplacingCharactersInRange:range withString:@""];
+ range = [aString rangeOfCharacterFromSet:forbiddenCharacters_];
+ }
+ DCHECK_EQ(range.length, 0U);
+
+ // NOTE: If |aString| is empty, this intentionally replaces the
+ // selection with empty. This seems consistent with the case where
+ // the input contained a mixture of characters and the string ended
+ // up not empty.
+ [super insertText:aString];
+}
+
+- (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange {
+ if (![self hasMarkedText]) {
+ // Before input methods set composition text in the omnibox, we need to
+ // examine whether the autocompletion controller accepts the keyword to
+ // avoid committing the current composition text wrongly.
+ AutocompleteTextFieldObserver* observer = [self observer];
+ if (observer)
+ observer->OnStartingIME();
+ }
+
+ [super setMarkedText:aString selectedRange:selRange];
+
+ // Because the AutocompleteEditViewMac class treats marked text as content,
+ // we need to treat the change to marked text as content change as well.
+ [self didChangeText];
+}
+
+- (NSRange)selectionRangeForProposedRange:(NSRange)proposedSelRange
+ granularity:(NSSelectionGranularity)granularity {
+ AutocompleteTextFieldObserver* observer = [self observer];
+ NSRange modifiedRange = [super selectionRangeForProposedRange:proposedSelRange
+ granularity:granularity];
+ if (observer)
+ return observer->SelectionRangeForProposedRange(modifiedRange);
+ return modifiedRange;
+}
+
+
+
+
+- (void)setSelectedRange:(NSRange)charRange
+ affinity:(NSSelectionAffinity)affinity
+ stillSelecting:(BOOL)flag {
+ [super setSelectedRange:charRange affinity:affinity stillSelecting:flag];
+
+ // We're only interested in selection changes directly caused by keyboard
+ // input from the user.
+ if (interpretingKeyEvents_)
+ textChangedByKeyEvents_ = YES;
+}
+
+- (void)interpretKeyEvents:(NSArray *)eventArray {
+ DCHECK(!interpretingKeyEvents_);
+ interpretingKeyEvents_ = YES;
+ textChangedByKeyEvents_ = NO;
+ [super interpretKeyEvents:eventArray];
+
+ AutocompleteTextFieldObserver* observer = [self observer];
+ if (textChangedByKeyEvents_ && observer)
+ observer->OnDidChange();
+
+ DCHECK(interpretingKeyEvents_);
+ interpretingKeyEvents_ = NO;
+}
+
+- (void)didChangeText {
+ [super didChangeText];
+
+ AutocompleteTextFieldObserver* observer = [self observer];
+ if (observer) {
+ if (!interpretingKeyEvents_)
+ observer->OnDidChange();
+ else
+ textChangedByKeyEvents_ = YES;
+ }
+}
+
+- (void)doCommandBySelector:(SEL)cmd {
+ // TODO(shess): Review code for cases where we're fruitlessly attempting to
+ // work in spite of not having an observer.
+ AutocompleteTextFieldObserver* observer = [self observer];
+
+ if (observer && observer->OnDoCommandBySelector(cmd)) {
+ // The observer should already be aware of any changes to the text, so
+ // setting |textChangedByKeyEvents_| to NO to prevent its OnDidChange()
+ // method from being called unnecessarily.
+ textChangedByKeyEvents_ = NO;
+ return;
+ }
+
+ // If the escape key was pressed and no revert happened and we're in
+ // fullscreen mode, make it resign key.
+ if (cmd == @selector(cancelOperation:)) {
+ BrowserWindowController* windowController =
+ [BrowserWindowController browserWindowControllerForView:self];
+ if ([windowController isFullscreen]) {
+ [windowController focusTabContents];
+ return;
+ }
+ }
+
+ [super doCommandBySelector:cmd];
+}
+
+- (void)setAttributedString:(NSAttributedString*)aString {
+ NSTextStorage* textStorage = [self textStorage];
+ DCHECK(textStorage);
+ [textStorage setAttributedString:aString];
+
+ // The text has been changed programmatically. The observer should know
+ // this change, so setting |textChangedByKeyEvents_| to NO to
+ // prevent its OnDidChange() method from being called unnecessarily.
+ textChangedByKeyEvents_ = NO;
+}
+
+- (void)mouseDown:(NSEvent*)theEvent {
+ // Close the popup before processing the event.
+ AutocompleteTextFieldObserver* observer = [self observer];
+ if (observer)
+ observer->ClosePopup();
+
+ [super mouseDown:theEvent];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm
new file mode 100644
index 0000000..e43b734
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm
@@ -0,0 +1,297 @@
+// 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 "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h"
+
+#include "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+#include "base/string_util.h"
+#include "chrome/app/chrome_command_ids.h" // IDC_*
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h"
+#import "chrome/browser/ui/cocoa/test_event_utils.h"
+#include "grit/generated_resources.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+
+using ::testing::Return;
+using ::testing::ReturnArg;
+using ::testing::StrictMock;
+using ::testing::A;
+
+namespace {
+
+// TODO(shess): Very similar to AutocompleteTextFieldTest. Maybe
+// those can be shared.
+
+class AutocompleteTextFieldEditorTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ NSRect frame = NSMakeRect(0, 0, 50, 30);
+ scoped_nsobject<AutocompleteTextField> field(
+ [[AutocompleteTextField alloc] initWithFrame:frame]);
+ field_ = field.get();
+ [field_ setStringValue:@"Testing"];
+ [[test_window() contentView] addSubview:field_];
+
+ // Arrange for |field_| to get the right field editor.
+ window_delegate_.reset(
+ [[AutocompleteTextFieldWindowTestDelegate alloc] init]);
+ [test_window() setDelegate:window_delegate_.get()];
+
+ // Get the field editor setup.
+ [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
+ editor_ = static_cast<AutocompleteTextFieldEditor*>([field_ currentEditor]);
+
+ EXPECT_TRUE(editor_);
+ EXPECT_TRUE([editor_ isKindOfClass:[AutocompleteTextFieldEditor class]]);
+ }
+
+ AutocompleteTextFieldEditor* editor_;
+ AutocompleteTextField* field_;
+ scoped_nsobject<AutocompleteTextFieldWindowTestDelegate> window_delegate_;
+};
+
+// Disabled because it crashes sometimes. http://crbug.com/49522
+// Can't rename DISABLED_ because the TEST_VIEW macro prepends.
+// http://crbug.com/53621
+#if 0
+TEST_VIEW(AutocompleteTextFieldEditorTest, field_);
+#endif
+
+// Test that control characters are stripped from insertions.
+TEST_F(AutocompleteTextFieldEditorTest, InsertStripsControlChars) {
+ // Sets a string in the field.
+ NSString* test_string = @"astring";
+ [field_ setStringValue:test_string];
+ [editor_ selectAll:nil];
+
+ [editor_ insertText:@"t"];
+ EXPECT_NSEQ(@"t", [field_ stringValue]);
+
+ [editor_ insertText:@"h"];
+ EXPECT_NSEQ(@"th", [field_ stringValue]);
+
+ // TAB doesn't get inserted.
+ [editor_ insertText:[NSString stringWithFormat:@"%c", 7]];
+ EXPECT_NSEQ(@"th", [field_ stringValue]);
+
+ // Newline doesn't get inserted.
+ [editor_ insertText:[NSString stringWithFormat:@"%c", 12]];
+ EXPECT_NSEQ(@"th", [field_ stringValue]);
+
+ // Multi-character strings get through.
+ [editor_ insertText:[NSString stringWithFormat:@"i%cs%c", 8, 127]];
+ EXPECT_NSEQ(@"this", [field_ stringValue]);
+
+ // Attempting to insert newline when everything is selected clears
+ // the field.
+ [editor_ selectAll:nil];
+ [editor_ insertText:[NSString stringWithFormat:@"%c", 12]];
+ EXPECT_NSEQ(@"", [field_ stringValue]);
+}
+
+// Test that |delegate| can provide page action menus.
+TEST_F(AutocompleteTextFieldEditorTest, PageActionMenus) {
+ // The event just needs to be something the mock can recognize.
+ NSEvent* event =
+ test_event_utils::MouseEventAtPoint(NSZeroPoint, NSRightMouseDown, 0);
+
+ // Trivial menu which we can recognize and which doesn't look like
+ // the default editor context menu.
+ scoped_nsobject<id> menu([[NSMenu alloc] initWithTitle:@"Menu"]);
+ [menu addItemWithTitle:@"Go Fish"
+ action:@selector(goFish:)
+ keyEquivalent:@""];
+
+ // For OCMOCK_VALUE().
+ BOOL yes = YES;
+
+ // So that we don't have to mock the observer.
+ [editor_ setEditable:NO];
+
+ // The delegate's intercept point gets called, and results are
+ // propagated back.
+ {
+ id delegate = [OCMockObject mockForClass:[AutocompleteTextField class]];
+ [[[delegate stub] andReturnValue:OCMOCK_VALUE(yes)]
+ isKindOfClass:[AutocompleteTextField class]];
+ [[[delegate expect] andReturn:menu.get()] decorationMenuForEvent:event];
+ [editor_ setDelegate:delegate];
+ NSMenu* contextMenu = [editor_ menuForEvent:event];
+ [delegate verify];
+ [editor_ setDelegate:nil];
+
+ EXPECT_EQ(contextMenu, menu.get());
+ }
+
+ // If the delegate does not return any menu, the default menu is
+ // returned.
+ {
+ id delegate = [OCMockObject mockForClass:[AutocompleteTextField class]];
+ [[[delegate stub] andReturnValue:OCMOCK_VALUE(yes)]
+ isKindOfClass:[AutocompleteTextField class]];
+ [[[delegate expect] andReturn:nil] decorationMenuForEvent:event];
+ [editor_ setDelegate:delegate];
+ NSMenu* contextMenu = [editor_ menuForEvent:event];
+ [delegate verify];
+ [editor_ setDelegate:nil];
+
+ EXPECT_NE(contextMenu, menu.get());
+ NSArray* items = [contextMenu itemArray];
+ ASSERT_GT([items count], 0U);
+ EXPECT_EQ(@selector(cut:), [[items objectAtIndex:0] action])
+ << "action is: " << sel_getName([[items objectAtIndex:0] action]);
+ }
+}
+
+// Base class for testing AutocompleteTextFieldObserver messages.
+class AutocompleteTextFieldEditorObserverTest
+ : public AutocompleteTextFieldEditorTest {
+ public:
+ virtual void SetUp() {
+ AutocompleteTextFieldEditorTest::SetUp();
+ [field_ setObserver:&field_observer_];
+ }
+
+ virtual void TearDown() {
+ // Clear the observer so that we don't show output for
+ // uninteresting messages to the mock (for instance, if |field_| has
+ // focus at the end of the test).
+ [field_ setObserver:NULL];
+
+ AutocompleteTextFieldEditorTest::TearDown();
+ }
+
+ StrictMock<MockAutocompleteTextFieldObserver> field_observer_;
+};
+
+// Test that the field editor is linked in correctly.
+TEST_F(AutocompleteTextFieldEditorTest, FirstResponder) {
+ EXPECT_EQ(editor_, [field_ currentEditor]);
+ EXPECT_TRUE([editor_ isDescendantOf:field_]);
+ EXPECT_EQ([editor_ delegate], field_);
+ EXPECT_EQ([editor_ observer], [field_ observer]);
+}
+
+// Test drawing, mostly to ensure nothing leaks or crashes.
+TEST_F(AutocompleteTextFieldEditorTest, Display) {
+ [field_ display];
+ [editor_ display];
+}
+
+// Test that -paste: is correctly delegated to the observer.
+TEST_F(AutocompleteTextFieldEditorObserverTest, Paste) {
+ EXPECT_CALL(field_observer_, OnPaste());
+ [editor_ paste:nil];
+}
+
+// Test that -copy: is correctly delegated to the observer.
+TEST_F(AutocompleteTextFieldEditorObserverTest, Copy) {
+ EXPECT_CALL(field_observer_, CanCopy())
+ .WillOnce(Return(true));
+ EXPECT_CALL(field_observer_, CopyToPasteboard(A<NSPasteboard*>()))
+ .Times(1);
+ [editor_ copy:nil];
+}
+
+// Test that -cut: is correctly delegated to the observer and clears
+// the text field.
+TEST_F(AutocompleteTextFieldEditorObserverTest, Cut) {
+ // Sets a string in the field.
+ NSString* test_string = @"astring";
+ EXPECT_CALL(field_observer_, OnDidBeginEditing());
+ EXPECT_CALL(field_observer_, OnDidChange());
+ EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(A<NSRange>()))
+ .WillRepeatedly(ReturnArg<0>());
+ [editor_ setString:test_string];
+ [editor_ selectAll:nil];
+
+ // Calls cut.
+ EXPECT_CALL(field_observer_, CanCopy())
+ .WillOnce(Return(true));
+ EXPECT_CALL(field_observer_, CopyToPasteboard(A<NSPasteboard*>()))
+ .Times(1);
+ [editor_ cut:nil];
+
+ // Check if the field is cleared.
+ ASSERT_EQ([[editor_ textStorage] length], 0U);
+}
+
+// Test that -pasteAndGo: is correctly delegated to the observer.
+TEST_F(AutocompleteTextFieldEditorObserverTest, PasteAndGo) {
+ EXPECT_CALL(field_observer_, OnPasteAndGo());
+ [editor_ pasteAndGo:nil];
+}
+
+// Test that the menu is constructed correctly when CanPasteAndGo().
+TEST_F(AutocompleteTextFieldEditorObserverTest, CanPasteAndGoMenu) {
+ EXPECT_CALL(field_observer_, CanPasteAndGo())
+ .WillOnce(Return(true));
+ EXPECT_CALL(field_observer_, GetPasteActionStringId())
+ .WillOnce(Return(IDS_PASTE_AND_GO));
+
+ NSMenu* menu = [editor_ menuForEvent:nil];
+ NSArray* items = [menu itemArray];
+ ASSERT_EQ([items count], 6U);
+ // TODO(shess): Check the titles, too?
+ NSUInteger i = 0; // Use an index to make future changes easier.
+ EXPECT_EQ([[items objectAtIndex:i++] action], @selector(cut:));
+ EXPECT_EQ([[items objectAtIndex:i++] action], @selector(copy:));
+ EXPECT_EQ([[items objectAtIndex:i++] action], @selector(paste:));
+ EXPECT_EQ([[items objectAtIndex:i++] action], @selector(pasteAndGo:));
+ EXPECT_TRUE([[items objectAtIndex:i++] isSeparatorItem]);
+
+ EXPECT_EQ([[items objectAtIndex:i] action], @selector(commandDispatch:));
+ EXPECT_EQ([[items objectAtIndex:i] tag], IDC_EDIT_SEARCH_ENGINES);
+ i++;
+}
+
+// Test that the menu is constructed correctly when !CanPasteAndGo().
+TEST_F(AutocompleteTextFieldEditorObserverTest, CannotPasteAndGoMenu) {
+ EXPECT_CALL(field_observer_, CanPasteAndGo())
+ .WillOnce(Return(false));
+
+ NSMenu* menu = [editor_ menuForEvent:nil];
+ NSArray* items = [menu itemArray];
+ ASSERT_EQ([items count], 5U);
+ // TODO(shess): Check the titles, too?
+ NSUInteger i = 0; // Use an index to make future changes easier.
+ EXPECT_EQ([[items objectAtIndex:i++] action], @selector(cut:));
+ EXPECT_EQ([[items objectAtIndex:i++] action], @selector(copy:));
+ EXPECT_EQ([[items objectAtIndex:i++] action], @selector(paste:));
+ EXPECT_TRUE([[items objectAtIndex:i++] isSeparatorItem]);
+
+ EXPECT_EQ([[items objectAtIndex:i] action], @selector(commandDispatch:));
+ EXPECT_EQ([[items objectAtIndex:i] tag], IDC_EDIT_SEARCH_ENGINES);
+ i++;
+}
+
+// Test that the menu is constructed correctly when field isn't
+// editable.
+TEST_F(AutocompleteTextFieldEditorObserverTest, CanPasteAndGoMenuNotEditable) {
+ [field_ setEditable:NO];
+ [editor_ setEditable:NO];
+
+ // Never call these when not editable.
+ EXPECT_CALL(field_observer_, CanPasteAndGo())
+ .Times(0);
+ EXPECT_CALL(field_observer_, GetPasteActionStringId())
+ .Times(0);
+
+ NSMenu* menu = [editor_ menuForEvent:nil];
+ NSArray* items = [menu itemArray];
+ ASSERT_EQ([items count], 3U);
+ // TODO(shess): Check the titles, too?
+ NSUInteger i = 0; // Use an index to make future changes easier.
+ EXPECT_EQ([[items objectAtIndex:i++] action], @selector(cut:));
+ EXPECT_EQ([[items objectAtIndex:i++] action], @selector(copy:));
+ EXPECT_EQ([[items objectAtIndex:i++] action], @selector(paste:));
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm
new file mode 100644
index 0000000..c85c738
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm
@@ -0,0 +1,792 @@
+// 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 "app/resource_bundle.h"
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
+#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
+#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h"
+#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h"
+#import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "grit/theme_resources.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+using ::testing::A;
+using ::testing::InSequence;
+using ::testing::Return;
+using ::testing::ReturnArg;
+using ::testing::StrictMock;
+using ::testing::_;
+
+namespace {
+
+class MockDecoration : public LocationBarDecoration {
+ public:
+ virtual CGFloat GetWidthForSpace(CGFloat width) { return 20.0; }
+
+ virtual void DrawInFrame(NSRect frame, NSView* control_view) { ; }
+ MOCK_METHOD0(AcceptsMousePress, bool());
+ MOCK_METHOD1(OnMousePressed, bool(NSRect frame));
+ MOCK_METHOD0(GetMenu, NSMenu*());
+};
+
+// Mock up an incrementing event number.
+NSUInteger eventNumber = 0;
+
+// Create an event of the indicated |type| at |point| within |view|.
+// TODO(shess): Would be nice to have a MockApplication which provided
+// nifty accessors to create these things and inject them. It could
+// even provide functions for "Click and drag mouse from point A to
+// point B".
+NSEvent* Event(NSView* view, const NSPoint point, const NSEventType type,
+ const NSUInteger clickCount) {
+ NSWindow* window([view window]);
+ const NSPoint locationInWindow([view convertPoint:point toView:nil]);
+ const NSPoint location([window convertBaseToScreen:locationInWindow]);
+ return [NSEvent mouseEventWithType:type
+ location:location
+ modifierFlags:0
+ timestamp:0
+ windowNumber:[window windowNumber]
+ context:nil
+ eventNumber:eventNumber++
+ clickCount:clickCount
+ pressure:0.0];
+}
+NSEvent* Event(NSView* view, const NSPoint point, const NSEventType type) {
+ return Event(view, point, type, 1);
+}
+
+// Width of the field so that we don't have to ask |field_| for it all
+// the time.
+static const CGFloat kWidth(300.0);
+
+class AutocompleteTextFieldTest : public CocoaTest {
+ public:
+ AutocompleteTextFieldTest() {
+ // Make sure this is wide enough to play games with the cell
+ // decorations.
+ NSRect frame = NSMakeRect(0, 0, kWidth, 30);
+ scoped_nsobject<AutocompleteTextField> field(
+ [[AutocompleteTextField alloc] initWithFrame:frame]);
+ field_ = field.get();
+ [field_ setStringValue:@"Test test"];
+ [[test_window() contentView] addSubview:field_];
+
+ AutocompleteTextFieldCell* cell = [field_ cell];
+ [cell clearDecorations];
+
+ mock_left_decoration_.SetVisible(false);
+ [cell addLeftDecoration:&mock_left_decoration_];
+
+ mock_right_decoration_.SetVisible(false);
+ [cell addRightDecoration:&mock_right_decoration_];
+
+ window_delegate_.reset(
+ [[AutocompleteTextFieldWindowTestDelegate alloc] init]);
+ [test_window() setDelegate:window_delegate_.get()];
+ }
+
+ NSEvent* KeyDownEventWithFlags(NSUInteger flags) {
+ return [NSEvent keyEventWithType:NSKeyDown
+ location:NSZeroPoint
+ modifierFlags:flags
+ timestamp:0.0
+ windowNumber:[test_window() windowNumber]
+ context:nil
+ characters:@"a"
+ charactersIgnoringModifiers:@"a"
+ isARepeat:NO
+ keyCode:'a'];
+ }
+
+ // Helper to return the field-editor frame being used w/in |field_|.
+ NSRect EditorFrame() {
+ EXPECT_TRUE([field_ currentEditor]);
+ EXPECT_EQ([[field_ subviews] count], 1U);
+ if ([[field_ subviews] count] > 0) {
+ return [[[field_ subviews] objectAtIndex:0] frame];
+ } else {
+ // Return something which won't work so the caller can soldier
+ // on.
+ return NSZeroRect;
+ }
+ }
+
+ AutocompleteTextField* field_;
+ MockDecoration mock_left_decoration_;
+ MockDecoration mock_right_decoration_;
+ scoped_nsobject<AutocompleteTextFieldWindowTestDelegate> window_delegate_;
+};
+
+TEST_VIEW(AutocompleteTextFieldTest, field_);
+
+// Base class for testing AutocompleteTextFieldObserver messages.
+class AutocompleteTextFieldObserverTest : public AutocompleteTextFieldTest {
+ public:
+ virtual void SetUp() {
+ AutocompleteTextFieldTest::SetUp();
+ [field_ setObserver:&field_observer_];
+ }
+
+ virtual void TearDown() {
+ // Clear the observer so that we don't show output for
+ // uninteresting messages to the mock (for instance, if |field_| has
+ // focus at the end of the test).
+ [field_ setObserver:NULL];
+
+ AutocompleteTextFieldTest::TearDown();
+ }
+
+ StrictMock<MockAutocompleteTextFieldObserver> field_observer_;
+};
+
+// Test that we have the right cell class.
+TEST_F(AutocompleteTextFieldTest, CellClass) {
+ EXPECT_TRUE([[field_ cell] isKindOfClass:[AutocompleteTextFieldCell class]]);
+}
+
+// Test that becoming first responder sets things up correctly.
+TEST_F(AutocompleteTextFieldTest, FirstResponder) {
+ EXPECT_EQ(nil, [field_ currentEditor]);
+ EXPECT_EQ([[field_ subviews] count], 0U);
+ [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
+ EXPECT_FALSE(nil == [field_ currentEditor]);
+ EXPECT_EQ([[field_ subviews] count], 1U);
+ EXPECT_TRUE([[field_ currentEditor] isDescendantOf:field_]);
+
+ // Check that the window delegate is providing the right editor.
+ Class c = [AutocompleteTextFieldEditor class];
+ EXPECT_TRUE([[field_ currentEditor] isKindOfClass:c]);
+}
+
+TEST_F(AutocompleteTextFieldTest, AvailableDecorationWidth) {
+ // A fudge factor to account for how much space the border takes up.
+ // The test shouldn't be too dependent on the field's internals, but
+ // it also shouldn't let deranged cases fall through the cracks
+ // (like nothing available with no text, or everything available
+ // with some text).
+ const CGFloat kBorderWidth = 20.0;
+
+ // With no contents, almost the entire width is available for
+ // decorations.
+ [field_ setStringValue:@""];
+ CGFloat availableWidth = [field_ availableDecorationWidth];
+ EXPECT_LE(availableWidth, kWidth);
+ EXPECT_GT(availableWidth, kWidth - kBorderWidth);
+
+ // With minor contents, most of the remaining width is available for
+ // decorations.
+ NSDictionary* attributes =
+ [NSDictionary dictionaryWithObject:[field_ font]
+ forKey:NSFontAttributeName];
+ NSString* string = @"Hello world";
+ const NSSize size([string sizeWithAttributes:attributes]);
+ [field_ setStringValue:string];
+ availableWidth = [field_ availableDecorationWidth];
+ EXPECT_LE(availableWidth, kWidth - size.width);
+ EXPECT_GT(availableWidth, kWidth - size.width - kBorderWidth);
+
+ // With huge contents, nothing at all is left for decorations.
+ string = @"A long string which is surely wider than field_ can hold.";
+ [field_ setStringValue:string];
+ availableWidth = [field_ availableDecorationWidth];
+ EXPECT_LT(availableWidth, 0.0);
+}
+
+// Test drawing, mostly to ensure nothing leaks or crashes.
+TEST_F(AutocompleteTextFieldTest, Display) {
+ [field_ display];
+
+ // Test focussed drawing.
+ [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
+ [field_ display];
+ [test_window() clearPretendKeyWindowAndFirstResponder];
+}
+
+TEST_F(AutocompleteTextFieldObserverTest, FlagsChanged) {
+ InSequence dummy; // Call mock in exactly the order specified.
+
+ // Test without Control key down, but some other modifier down.
+ EXPECT_CALL(field_observer_, OnControlKeyChanged(false));
+ [field_ flagsChanged:KeyDownEventWithFlags(NSShiftKeyMask)];
+
+ // Test with Control key down.
+ EXPECT_CALL(field_observer_, OnControlKeyChanged(true));
+ [field_ flagsChanged:KeyDownEventWithFlags(NSControlKeyMask)];
+}
+
+// This test is here rather than in the editor's tests because the
+// field catches -flagsChanged: because it's on the responder chain,
+// the field editor doesn't implement it.
+TEST_F(AutocompleteTextFieldObserverTest, FieldEditorFlagsChanged) {
+ // Many of these methods try to change the selection.
+ EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(A<NSRange>()))
+ .WillRepeatedly(ReturnArg<0>());
+
+ InSequence dummy; // Call mock in exactly the order specified.
+ EXPECT_CALL(field_observer_, OnSetFocus(false));
+ [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
+ NSResponder* firstResponder = [[field_ window] firstResponder];
+ EXPECT_EQ(firstResponder, [field_ currentEditor]);
+
+ // Test without Control key down, but some other modifier down.
+ EXPECT_CALL(field_observer_, OnControlKeyChanged(false));
+ [firstResponder flagsChanged:KeyDownEventWithFlags(NSShiftKeyMask)];
+
+ // Test with Control key down.
+ EXPECT_CALL(field_observer_, OnControlKeyChanged(true));
+ [firstResponder flagsChanged:KeyDownEventWithFlags(NSControlKeyMask)];
+}
+
+// Frame size changes are propagated to |observer_|.
+TEST_F(AutocompleteTextFieldObserverTest, FrameChanged) {
+ EXPECT_CALL(field_observer_, OnFrameChanged());
+ NSRect frame = [field_ frame];
+ frame.size.width += 10.0;
+ [field_ setFrame:frame];
+}
+
+// Test that the field editor gets the same bounds when focus is
+// delivered by the standard focusing machinery, or by
+// -resetFieldEditorFrameIfNeeded.
+TEST_F(AutocompleteTextFieldTest, ResetFieldEditorBase) {
+ // Capture the editor frame resulting from the standard focus
+ // machinery.
+ [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
+ const NSRect baseEditorFrame = EditorFrame();
+
+ // A decoration should result in a strictly smaller editor frame.
+ mock_left_decoration_.SetVisible(true);
+ [field_ resetFieldEditorFrameIfNeeded];
+ EXPECT_FALSE(NSEqualRects(baseEditorFrame, EditorFrame()));
+ EXPECT_TRUE(NSContainsRect(baseEditorFrame, EditorFrame()));
+
+ // Removing the decoration and using -resetFieldEditorFrameIfNeeded
+ // should result in the same frame as the standard focus machinery.
+ mock_left_decoration_.SetVisible(false);
+ [field_ resetFieldEditorFrameIfNeeded];
+ EXPECT_TRUE(NSEqualRects(baseEditorFrame, EditorFrame()));
+}
+
+// Test that the field editor gets the same bounds when focus is
+// delivered by the standard focusing machinery, or by
+// -resetFieldEditorFrameIfNeeded, this time with a decoration
+// pre-loaded.
+TEST_F(AutocompleteTextFieldTest, ResetFieldEditorWithDecoration) {
+ AutocompleteTextFieldCell* cell = [field_ cell];
+
+ // Make sure decoration isn't already visible, then make it visible.
+ EXPECT_TRUE(NSIsEmptyRect([cell frameForDecoration:&mock_left_decoration_
+ inFrame:[field_ bounds]]));
+ mock_left_decoration_.SetVisible(true);
+ EXPECT_FALSE(NSIsEmptyRect([cell frameForDecoration:&mock_left_decoration_
+ inFrame:[field_ bounds]]));
+
+ // Capture the editor frame resulting from the standard focus
+ // machinery.
+
+ [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
+ const NSRect baseEditorFrame = EditorFrame();
+
+ // When the decoration is not visible the frame should be strictly larger.
+ mock_left_decoration_.SetVisible(false);
+ EXPECT_TRUE(NSIsEmptyRect([cell frameForDecoration:&mock_left_decoration_
+ inFrame:[field_ bounds]]));
+ [field_ resetFieldEditorFrameIfNeeded];
+ EXPECT_FALSE(NSEqualRects(baseEditorFrame, EditorFrame()));
+ EXPECT_TRUE(NSContainsRect(EditorFrame(), baseEditorFrame));
+
+ // When the decoration is visible, -resetFieldEditorFrameIfNeeded
+ // should result in the same frame as the standard focus machinery.
+ mock_left_decoration_.SetVisible(true);
+ EXPECT_FALSE(NSIsEmptyRect([cell frameForDecoration:&mock_left_decoration_
+ inFrame:[field_ bounds]]));
+
+ [field_ resetFieldEditorFrameIfNeeded];
+ EXPECT_TRUE(NSEqualRects(baseEditorFrame, EditorFrame()));
+}
+
+// Test that resetting the field editor bounds does not cause untoward
+// messages to the field's observer.
+TEST_F(AutocompleteTextFieldObserverTest, ResetFieldEditorContinuesEditing) {
+ // Many of these methods try to change the selection.
+ EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(A<NSRange>()))
+ .WillRepeatedly(ReturnArg<0>());
+
+ EXPECT_CALL(field_observer_, OnSetFocus(false));
+ // Becoming first responder doesn't begin editing.
+ [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
+ const NSRect baseEditorFrame = EditorFrame();
+ NSTextView* editor = static_cast<NSTextView*>([field_ currentEditor]);
+ EXPECT_TRUE(nil != editor);
+
+ // This should begin editing and indicate a change.
+ EXPECT_CALL(field_observer_, OnDidBeginEditing());
+ EXPECT_CALL(field_observer_, OnDidChange());
+ [editor shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:@""];
+ [editor didChangeText];
+
+ // No messages to |field_observer_| when the frame actually changes.
+ mock_left_decoration_.SetVisible(true);
+ [field_ resetFieldEditorFrameIfNeeded];
+ EXPECT_FALSE(NSEqualRects(baseEditorFrame, EditorFrame()));
+}
+
+// Clicking in a right-hand decoration which does not handle the mouse
+// puts the caret rightmost.
+TEST_F(AutocompleteTextFieldTest, ClickRightDecorationPutsCaretRightmost) {
+ // Decoration does not handle the mouse event, so the cell should
+ // process it. Called at least once.
+ EXPECT_CALL(mock_right_decoration_, AcceptsMousePress())
+ .WillOnce(Return(false))
+ .WillRepeatedly(Return(false));
+
+ // Set the decoration before becoming responder.
+ EXPECT_FALSE([field_ currentEditor]);
+ mock_right_decoration_.SetVisible(true);
+
+ // Make first responder should select all.
+ [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
+ EXPECT_TRUE([field_ currentEditor]);
+ const NSRange allRange = NSMakeRange(0, [[field_ stringValue] length]);
+ EXPECT_TRUE(NSEqualRanges(allRange, [[field_ currentEditor] selectedRange]));
+
+ // Generate a click on the decoration.
+ AutocompleteTextFieldCell* cell = [field_ cell];
+ const NSRect bounds = [field_ bounds];
+ const NSRect iconFrame =
+ [cell frameForDecoration:&mock_right_decoration_ inFrame:bounds];
+ const NSPoint point = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame));
+ NSEvent* downEvent = Event(field_, point, NSLeftMouseDown);
+ NSEvent* upEvent = Event(field_, point, NSLeftMouseUp);
+ [NSApp postEvent:upEvent atStart:YES];
+ [field_ mouseDown:downEvent];
+
+ // Selection should be a right-hand-side caret.
+ EXPECT_TRUE(NSEqualRanges(NSMakeRange([[field_ stringValue] length], 0),
+ [[field_ currentEditor] selectedRange]));
+}
+
+// Clicking in a left-side decoration which doesn't handle the event
+// puts the selection in the leftmost position.
+TEST_F(AutocompleteTextFieldTest, ClickLeftDecorationPutsCaretLeftmost) {
+ // Decoration does not handle the mouse event, so the cell should
+ // process it. Called at least once.
+ EXPECT_CALL(mock_left_decoration_, AcceptsMousePress())
+ .WillOnce(Return(false))
+ .WillRepeatedly(Return(false));
+
+ // Set the decoration before becoming responder.
+ EXPECT_FALSE([field_ currentEditor]);
+ mock_left_decoration_.SetVisible(true);
+
+ // Make first responder should select all.
+ [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
+ EXPECT_TRUE([field_ currentEditor]);
+ const NSRange allRange = NSMakeRange(0, [[field_ stringValue] length]);
+ EXPECT_TRUE(NSEqualRanges(allRange, [[field_ currentEditor] selectedRange]));
+
+ // Generate a click on the decoration.
+ AutocompleteTextFieldCell* cell = [field_ cell];
+ const NSRect bounds = [field_ bounds];
+ const NSRect iconFrame =
+ [cell frameForDecoration:&mock_left_decoration_ inFrame:bounds];
+ const NSPoint point = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame));
+ NSEvent* downEvent = Event(field_, point, NSLeftMouseDown);
+ NSEvent* upEvent = Event(field_, point, NSLeftMouseUp);
+ [NSApp postEvent:upEvent atStart:YES];
+ [field_ mouseDown:downEvent];
+
+ // Selection should be a left-hand-side caret.
+ EXPECT_TRUE(NSEqualRanges(NSMakeRange(0, 0),
+ [[field_ currentEditor] selectedRange]));
+}
+
+// Clicks not in the text area or the cell's decorations fall through
+// to the editor.
+TEST_F(AutocompleteTextFieldTest, ClickBorderSelectsAll) {
+ // Can't rely on the window machinery to make us first responder,
+ // here.
+ [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
+ EXPECT_TRUE([field_ currentEditor]);
+
+ const NSPoint point(NSMakePoint(20.0, 1.0));
+ NSEvent* downEvent(Event(field_, point, NSLeftMouseDown));
+ NSEvent* upEvent(Event(field_, point, NSLeftMouseUp));
+ [NSApp postEvent:upEvent atStart:YES];
+ [field_ mouseDown:downEvent];
+
+ // Clicking in the narrow border area around a Cocoa NSTextField
+ // does a select-all. Regardless of whether this is a good call, it
+ // works as a test that things get passed down to the editor.
+ const NSRange selectedRange([[field_ currentEditor] selectedRange]);
+ EXPECT_EQ(selectedRange.location, 0U);
+ EXPECT_EQ(selectedRange.length, [[field_ stringValue] length]);
+}
+
+// Single-click with no drag should setup a field editor and
+// select all.
+TEST_F(AutocompleteTextFieldTest, ClickSelectsAll) {
+ EXPECT_FALSE([field_ currentEditor]);
+
+ const NSPoint point = NSMakePoint(20.0, NSMidY([field_ bounds]));
+ NSEvent* downEvent(Event(field_, point, NSLeftMouseDown));
+ NSEvent* upEvent(Event(field_, point, NSLeftMouseUp));
+ [NSApp postEvent:upEvent atStart:YES];
+ [field_ mouseDown:downEvent];
+ EXPECT_TRUE([field_ currentEditor]);
+ const NSRange selectedRange([[field_ currentEditor] selectedRange]);
+ EXPECT_EQ(selectedRange.location, 0U);
+ EXPECT_EQ(selectedRange.length, [[field_ stringValue] length]);
+}
+
+// Click-drag selects text, not select all.
+TEST_F(AutocompleteTextFieldTest, ClickDragSelectsText) {
+ EXPECT_FALSE([field_ currentEditor]);
+
+ NSEvent* downEvent(Event(field_, NSMakePoint(20.0, 5.0), NSLeftMouseDown));
+ NSEvent* upEvent(Event(field_, NSMakePoint(0.0, 5.0), NSLeftMouseUp));
+ [NSApp postEvent:upEvent atStart:YES];
+ [field_ mouseDown:downEvent];
+ EXPECT_TRUE([field_ currentEditor]);
+
+ // Expect this to have selected a prefix of the content. Mostly
+ // just don't want the select-all behavior.
+ const NSRange selectedRange([[field_ currentEditor] selectedRange]);
+ EXPECT_EQ(selectedRange.location, 0U);
+ EXPECT_LT(selectedRange.length, [[field_ stringValue] length]);
+}
+
+// TODO(shess): Test that click/pause/click allows cursor placement.
+// In this case the first click goes to the field, but the second
+// click goes to the field editor, so the current testing pattern
+// can't work. What really needs to happen is to push through the
+// NSWindow event machinery so that we can say "two independent clicks
+// at the same location have the right effect". Once that is done, it
+// might make sense to revise the other tests to use the same
+// machinery.
+
+// Double-click selects word, not select all.
+TEST_F(AutocompleteTextFieldTest, DoubleClickSelectsWord) {
+ EXPECT_FALSE([field_ currentEditor]);
+
+ const NSPoint point = NSMakePoint(20.0, NSMidY([field_ bounds]));
+ NSEvent* downEvent(Event(field_, point, NSLeftMouseDown, 1));
+ NSEvent* upEvent(Event(field_, point, NSLeftMouseUp, 1));
+ NSEvent* downEvent2(Event(field_, point, NSLeftMouseDown, 2));
+ NSEvent* upEvent2(Event(field_, point, NSLeftMouseUp, 2));
+ [NSApp postEvent:upEvent atStart:YES];
+ [field_ mouseDown:downEvent];
+ [NSApp postEvent:upEvent2 atStart:YES];
+ [field_ mouseDown:downEvent2];
+ EXPECT_TRUE([field_ currentEditor]);
+
+ // Selected the first word.
+ const NSRange selectedRange([[field_ currentEditor] selectedRange]);
+ const NSRange spaceRange([[field_ stringValue] rangeOfString:@" "]);
+ EXPECT_GT(spaceRange.location, 0U);
+ EXPECT_LT(spaceRange.length, [[field_ stringValue] length]);
+ EXPECT_EQ(selectedRange.location, 0U);
+ EXPECT_EQ(selectedRange.length, spaceRange.location);
+}
+
+TEST_F(AutocompleteTextFieldTest, TripleClickSelectsAll) {
+ EXPECT_FALSE([field_ currentEditor]);
+
+ const NSPoint point(NSMakePoint(20.0, 5.0));
+ NSEvent* downEvent(Event(field_, point, NSLeftMouseDown, 1));
+ NSEvent* upEvent(Event(field_, point, NSLeftMouseUp, 1));
+ NSEvent* downEvent2(Event(field_, point, NSLeftMouseDown, 2));
+ NSEvent* upEvent2(Event(field_, point, NSLeftMouseUp, 2));
+ NSEvent* downEvent3(Event(field_, point, NSLeftMouseDown, 3));
+ NSEvent* upEvent3(Event(field_, point, NSLeftMouseUp, 3));
+ [NSApp postEvent:upEvent atStart:YES];
+ [field_ mouseDown:downEvent];
+ [NSApp postEvent:upEvent2 atStart:YES];
+ [field_ mouseDown:downEvent2];
+ [NSApp postEvent:upEvent3 atStart:YES];
+ [field_ mouseDown:downEvent3];
+ EXPECT_TRUE([field_ currentEditor]);
+
+ // Selected the first word.
+ const NSRange selectedRange([[field_ currentEditor] selectedRange]);
+ EXPECT_EQ(selectedRange.location, 0U);
+ EXPECT_EQ(selectedRange.length, [[field_ stringValue] length]);
+}
+
+// Clicking a decoration should call decoration's OnMousePressed.
+TEST_F(AutocompleteTextFieldTest, LeftDecorationMouseDown) {
+ // At this point, not focussed.
+ EXPECT_FALSE([field_ currentEditor]);
+
+ mock_left_decoration_.SetVisible(true);
+ EXPECT_CALL(mock_left_decoration_, AcceptsMousePress())
+ .WillRepeatedly(Return(true));
+
+ AutocompleteTextFieldCell* cell = [field_ cell];
+ const NSRect iconFrame =
+ [cell frameForDecoration:&mock_left_decoration_ inFrame:[field_ bounds]];
+ const NSPoint location = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame));
+ NSEvent* downEvent = Event(field_, location, NSLeftMouseDown, 1);
+ NSEvent* upEvent = Event(field_, location, NSLeftMouseUp, 1);
+
+ // Since decorations can be dragged, the mouse-press is sent on
+ // mouse-up.
+ [NSApp postEvent:upEvent atStart:YES];
+
+ EXPECT_CALL(mock_left_decoration_, OnMousePressed(_))
+ .WillOnce(Return(true));
+ [field_ mouseDown:downEvent];
+
+ // Focus the field and test that handled clicks don't affect selection.
+ [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
+ EXPECT_TRUE([field_ currentEditor]);
+ const NSRange allRange = NSMakeRange(0, [[field_ stringValue] length]);
+ EXPECT_TRUE(NSEqualRanges(allRange, [[field_ currentEditor] selectedRange]));
+
+ // Generate another click on the decoration.
+ downEvent = Event(field_, location, NSLeftMouseDown, 1);
+ upEvent = Event(field_, location, NSLeftMouseUp, 1);
+ [NSApp postEvent:upEvent atStart:YES];
+ EXPECT_CALL(mock_left_decoration_, OnMousePressed(_))
+ .WillOnce(Return(true));
+ [field_ mouseDown:downEvent];
+
+ // The selection should not have changed.
+ EXPECT_TRUE(NSEqualRanges(allRange, [[field_ currentEditor] selectedRange]));
+
+ // TODO(shess): Test that mouse drags are initiated if the next
+ // event is a drag, or if the mouse-up takes too long to arrive.
+ // IDEA: mock decoration to return a pasteboard which a mock
+ // AutocompleteTextField notes in -dragImage:*.
+}
+
+// Clicking a decoration should call decoration's OnMousePressed.
+TEST_F(AutocompleteTextFieldTest, RightDecorationMouseDown) {
+ // At this point, not focussed.
+ EXPECT_FALSE([field_ currentEditor]);
+
+ mock_right_decoration_.SetVisible(true);
+ EXPECT_CALL(mock_right_decoration_, AcceptsMousePress())
+ .WillRepeatedly(Return(true));
+
+ AutocompleteTextFieldCell* cell = [field_ cell];
+ const NSRect bounds = [field_ bounds];
+ const NSRect iconFrame =
+ [cell frameForDecoration:&mock_right_decoration_ inFrame:bounds];
+ const NSPoint location = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame));
+ NSEvent* downEvent = Event(field_, location, NSLeftMouseDown, 1);
+ NSEvent* upEvent = Event(field_, location, NSLeftMouseUp, 1);
+
+ // Since decorations can be dragged, the mouse-press is sent on
+ // mouse-up.
+ [NSApp postEvent:upEvent atStart:YES];
+
+ EXPECT_CALL(mock_right_decoration_, OnMousePressed(_))
+ .WillOnce(Return(true));
+ [field_ mouseDown:downEvent];
+}
+
+// Test that page action menus are properly returned.
+// TODO(shess): Really, this should test that things are forwarded to
+// the cell, and the cell tests should test that the right things are
+// selected. It's easier to mock the event here, though. This code's
+// event-mockers might be worth promoting to |test_event_utils.h| or
+// |cocoa_test_helper.h|.
+TEST_F(AutocompleteTextFieldTest, DecorationMenu) {
+ AutocompleteTextFieldCell* cell = [field_ cell];
+ const NSRect bounds([field_ bounds]);
+
+ const CGFloat edge = NSHeight(bounds) - 4.0;
+ const NSSize size = NSMakeSize(edge, edge);
+ scoped_nsobject<NSImage> image([[NSImage alloc] initWithSize:size]);
+
+ scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@"Menu"]);
+
+ mock_left_decoration_.SetVisible(true);
+ mock_right_decoration_.SetVisible(true);
+
+ // The item with a menu returns it.
+ NSRect actionFrame = [cell frameForDecoration:&mock_right_decoration_
+ inFrame:bounds];
+ NSPoint location = NSMakePoint(NSMidX(actionFrame), NSMidY(actionFrame));
+ NSEvent* event = Event(field_, location, NSRightMouseDown, 1);
+
+ // Check that the decoration is called, and the field returns the
+ // menu.
+ EXPECT_CALL(mock_right_decoration_, GetMenu())
+ .WillOnce(Return(menu.get()));
+ NSMenu *decorationMenu = [field_ decorationMenuForEvent:event];
+ EXPECT_EQ(decorationMenu, menu);
+
+ // The item without a menu returns nil.
+ EXPECT_CALL(mock_left_decoration_, GetMenu())
+ .WillOnce(Return(static_cast<NSMenu*>(nil)));
+ actionFrame = [cell frameForDecoration:&mock_left_decoration_
+ inFrame:bounds];
+ location = NSMakePoint(NSMidX(actionFrame), NSMidY(actionFrame));
+ event = Event(field_, location, NSRightMouseDown, 1);
+ EXPECT_FALSE([field_ decorationMenuForEvent:event]);
+
+ // Something not in an action returns nil.
+ location = NSMakePoint(NSMidX(bounds), NSMidY(bounds));
+ event = Event(field_, location, NSRightMouseDown, 1);
+ EXPECT_FALSE([field_ decorationMenuForEvent:event]);
+}
+
+// Verify that -setAttributedStringValue: works as expected when
+// focussed or when not focussed. Our code mostly depends on about
+// whether -stringValue works right.
+TEST_F(AutocompleteTextFieldTest, SetAttributedStringBaseline) {
+ EXPECT_EQ(nil, [field_ currentEditor]);
+
+ // So that we can set rich text.
+ [field_ setAllowsEditingTextAttributes:YES];
+
+ // Set an attribute different from the field's default so we can
+ // tell we got the same string out as we put in.
+ NSFont* font = [NSFont fontWithDescriptor:[[field_ font] fontDescriptor]
+ size:[[field_ font] pointSize] + 2];
+ NSDictionary* attributes =
+ [NSDictionary dictionaryWithObject:font
+ forKey:NSFontAttributeName];
+ NSString* const kString = @"This is a test";
+ scoped_nsobject<NSAttributedString> attributedString(
+ [[NSAttributedString alloc] initWithString:kString
+ attributes:attributes]);
+
+ // Check that what we get back looks like what we put in.
+ EXPECT_NSNE(kString, [field_ stringValue]);
+ [field_ setAttributedStringValue:attributedString];
+ EXPECT_TRUE([[field_ attributedStringValue]
+ isEqualToAttributedString:attributedString]);
+ EXPECT_NSEQ(kString, [field_ stringValue]);
+
+ // Try that again with focus.
+ [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
+
+ EXPECT_TRUE([field_ currentEditor]);
+
+ // Check that what we get back looks like what we put in.
+ [field_ setStringValue:@""];
+ EXPECT_NSNE(kString, [field_ stringValue]);
+ [field_ setAttributedStringValue:attributedString];
+ EXPECT_TRUE([[field_ attributedStringValue]
+ isEqualToAttributedString:attributedString]);
+ EXPECT_NSEQ(kString, [field_ stringValue]);
+}
+
+// -setAttributedStringValue: shouldn't reset the undo state if things
+// are being editted.
+TEST_F(AutocompleteTextFieldTest, SetAttributedStringUndo) {
+ NSColor* redColor = [NSColor redColor];
+ NSDictionary* attributes =
+ [NSDictionary dictionaryWithObject:redColor
+ forKey:NSForegroundColorAttributeName];
+ NSString* const kString = @"This is a test";
+ scoped_nsobject<NSAttributedString> attributedString(
+ [[NSAttributedString alloc] initWithString:kString
+ attributes:attributes]);
+ [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
+ EXPECT_TRUE([field_ currentEditor]);
+ NSTextView* editor = static_cast<NSTextView*>([field_ currentEditor]);
+ NSUndoManager* undoManager = [editor undoManager];
+ EXPECT_TRUE(undoManager);
+
+ // Nothing to undo, yet.
+ EXPECT_FALSE([undoManager canUndo]);
+
+ // Starting an editing action creates an undoable item.
+ [editor shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:@""];
+ [editor didChangeText];
+ EXPECT_TRUE([undoManager canUndo]);
+
+ // -setStringValue: resets the editor's undo chain.
+ [field_ setStringValue:kString];
+ EXPECT_FALSE([undoManager canUndo]);
+
+ // Verify that -setAttributedStringValue: does not reset the
+ // editor's undo chain.
+ [field_ setStringValue:@""];
+ [editor shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:@""];
+ [editor didChangeText];
+ EXPECT_TRUE([undoManager canUndo]);
+ [field_ setAttributedStringValue:attributedString];
+ EXPECT_TRUE([undoManager canUndo]);
+
+ // Verify that calling -clearUndoChain clears the undo chain.
+ [field_ clearUndoChain];
+ EXPECT_FALSE([undoManager canUndo]);
+}
+
+TEST_F(AutocompleteTextFieldTest, EditorGetsCorrectUndoManager) {
+ [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
+
+ NSTextView* editor = static_cast<NSTextView*>([field_ currentEditor]);
+ EXPECT_TRUE(editor);
+ EXPECT_EQ([field_ undoManagerForTextView:editor], [editor undoManager]);
+}
+
+TEST_F(AutocompleteTextFieldObserverTest, SendsEditingMessages) {
+ // Many of these methods try to change the selection.
+ EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(A<NSRange>()))
+ .WillRepeatedly(ReturnArg<0>());
+
+ EXPECT_CALL(field_observer_, OnSetFocus(false));
+ // Becoming first responder doesn't begin editing.
+ [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
+ NSTextView* editor = static_cast<NSTextView*>([field_ currentEditor]);
+ EXPECT_TRUE(nil != editor);
+
+ // This should begin editing and indicate a change.
+ EXPECT_CALL(field_observer_, OnDidBeginEditing());
+ EXPECT_CALL(field_observer_, OnDidChange());
+ [editor shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:@""];
+ [editor didChangeText];
+
+ // Further changes don't send the begin message.
+ EXPECT_CALL(field_observer_, OnDidChange());
+ [editor shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:@""];
+ [editor didChangeText];
+
+ // -doCommandBySelector: should forward to observer via |field_|.
+ // TODO(shess): Test with a fake arrow-key event?
+ const SEL cmd = @selector(moveDown:);
+ EXPECT_CALL(field_observer_, OnDoCommandBySelector(cmd))
+ .WillOnce(Return(true));
+ [editor doCommandBySelector:cmd];
+
+ // Finished with the changes.
+ EXPECT_CALL(field_observer_, OnKillFocus());
+ EXPECT_CALL(field_observer_, OnDidEndEditing());
+ [test_window() clearPretendKeyWindowAndFirstResponder];
+}
+
+// Test that the resign-key notification is forwarded right, and that
+// the notification is registered and unregistered when the view moves
+// in and out of the window.
+// TODO(shess): Should this test the key window for realz? That would
+// be really annoying to whoever is running the tests.
+TEST_F(AutocompleteTextFieldObserverTest, ClosePopupOnResignKey) {
+ EXPECT_CALL(field_observer_, ClosePopup());
+ [test_window() resignKeyWindow];
+
+ scoped_nsobject<AutocompleteTextField> pin([field_ retain]);
+ [field_ removeFromSuperview];
+ [test_window() resignKeyWindow];
+
+ [[test_window() contentView] addSubview:field_];
+ EXPECT_CALL(field_observer_, ClosePopup());
+ [test_window() resignKeyWindow];
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h
new file mode 100644
index 0000000..321ec61
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_AUTOCOMPLETE_TEXT_FIELD_UNITTEST_HELPER_H_
+#define CHROME_BROWSER_UI_COCOA_AUTOCOMPLETE_TEXT_FIELD_UNITTEST_HELPER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+@class AutocompleteTextFieldEditor;
+
+// Return the right field editor for AutocompleteTextField instance.
+
+@interface AutocompleteTextFieldWindowTestDelegate :
+ NSObject<NSWindowDelegate> {
+ scoped_nsobject<AutocompleteTextFieldEditor> editor_;
+}
+- (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)anObject;
+@end
+
+namespace {
+
+// Allow monitoring calls into AutocompleteTextField's observer.
+// Being in a .h file with an anonymous namespace is strange, but this
+// is here so the mock interface doesn't have to change in multiple
+// places.
+
+// Any method you add here needs a unit test. You knew that.
+
+class MockAutocompleteTextFieldObserver : public AutocompleteTextFieldObserver {
+ public:
+ MOCK_METHOD1(SelectionRangeForProposedRange, NSRange(NSRange range));
+ MOCK_METHOD1(OnControlKeyChanged, void(bool pressed));
+ MOCK_METHOD0(CanCopy, bool());
+ MOCK_METHOD1(CopyToPasteboard, void(NSPasteboard* pboard));
+ MOCK_METHOD0(OnPaste, void());
+ MOCK_METHOD0(CanPasteAndGo, bool());
+ MOCK_METHOD0(GetPasteActionStringId, int());
+ MOCK_METHOD0(OnPasteAndGo, void());
+ MOCK_METHOD0(OnFrameChanged, void());
+ MOCK_METHOD0(ClosePopup, void());
+ MOCK_METHOD0(OnDidBeginEditing, void());
+ MOCK_METHOD0(OnDidChange, void());
+ MOCK_METHOD0(OnDidEndEditing, void());
+ MOCK_METHOD0(OnStartingIME, void());
+ MOCK_METHOD1(OnDoCommandBySelector, bool(SEL cmd));
+ MOCK_METHOD1(OnSetFocus, void(bool control_down));
+ MOCK_METHOD0(OnKillFocus, void());
+};
+
+} // namespace
+
+#endif // CHROME_BROWSER_UI_COCOA_AUTOCOMPLETE_TEXT_FIELD_UNITTEST_HELPER_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.mm
new file mode 100644
index 0000000..a2c5194
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.mm
@@ -0,0 +1,29 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h"
+
+#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
+#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+@implementation AutocompleteTextFieldWindowTestDelegate
+
+- (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)anObject {
+ id editor = nil;
+ if ([anObject isKindOfClass:[AutocompleteTextField class]]) {
+ if (editor_ == nil) {
+ editor_.reset([[AutocompleteTextFieldEditor alloc] init]);
+ }
+ EXPECT_TRUE(editor_ != nil);
+
+ // This needs to be called every time, otherwise notifications
+ // aren't sent correctly.
+ [editor_ setFieldEditor:YES];
+ editor = editor_.get();
+ }
+ return editor;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/location_bar/bubble_decoration.h b/chrome/browser/ui/cocoa/location_bar/bubble_decoration.h
new file mode 100644
index 0000000..234c254
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/bubble_decoration.h
@@ -0,0 +1,67 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_LOCATION_BAR_BUBBLE_DECORATION_H_
+#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_BUBBLE_DECORATION_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/gtest_prod_util.h"
+#include "base/scoped_nsobject.h"
+#include "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
+
+// Draws an outlined rounded rect, with an optional image to the left
+// and an optional text label to the right.
+
+class BubbleDecoration : public LocationBarDecoration {
+ public:
+ // |font| will be used when drawing the label, and cannot be |nil|.
+ BubbleDecoration(NSFont* font);
+ ~BubbleDecoration();
+
+ // Setup the drawing parameters.
+ NSImage* GetImage();
+ void SetImage(NSImage* image);
+ void SetLabel(NSString* label);
+ void SetColors(NSColor* border_color,
+ NSColor* background_color,
+ NSColor* text_color);
+
+ // Implement |LocationBarDecoration|.
+ virtual void DrawInFrame(NSRect frame, NSView* control_view);
+ virtual CGFloat GetWidthForSpace(CGFloat width);
+
+ protected:
+ // Helper returning bubble width for the given |image| and |label|
+ // assuming |font_| (for sizing text). Arguments can be nil.
+ CGFloat GetWidthForImageAndLabel(NSImage* image, NSString* label);
+
+ // Helper to return where the image is drawn, for subclasses to drag
+ // from. |frame| is the decoration's frame in the containing cell.
+ NSRect GetImageRectInFrame(NSRect frame);
+
+ private:
+ friend class SelectedKeywordDecorationTest;
+ FRIEND_TEST_ALL_PREFIXES(SelectedKeywordDecorationTest,
+ UsesPartialKeywordIfNarrow);
+
+ // Contains font and color attribute for drawing |label_|.
+ scoped_nsobject<NSDictionary> attributes_;
+
+ // Image drawn in the left side of the bubble.
+ scoped_nsobject<NSImage> image_;
+
+ // Label to draw to right of image. Can be |nil|.
+ scoped_nsobject<NSString> label_;
+
+ // Colors used to draw the bubble, should be set by the subclass
+ // constructor.
+ scoped_nsobject<NSColor> background_color_;
+ scoped_nsobject<NSColor> border_color_;
+
+ DISALLOW_COPY_AND_ASSIGN(BubbleDecoration);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_BUBBLE_DECORATION_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/bubble_decoration.mm b/chrome/browser/ui/cocoa/location_bar/bubble_decoration.mm
new file mode 100644
index 0000000..b568639
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/bubble_decoration.mm
@@ -0,0 +1,158 @@
+// 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.
+
+#include <cmath>
+
+#import "chrome/browser/ui/cocoa/location_bar/bubble_decoration.h"
+
+#include "base/logging.h"
+#import "chrome/browser/ui/cocoa/image_utils.h"
+
+namespace {
+
+// Padding between the icon/label and bubble edges.
+const CGFloat kBubblePadding = 3.0;
+
+// The image needs to be in the same position as for the location
+// icon, which implies that the bubble's padding in the Omnibox needs
+// to differ from the location icon's. Indeed, that's how the views
+// implementation handles the problem. This draws the bubble edge a
+// little bit further left, which is easier but no less hacky.
+const CGFloat kLeftSideOverdraw = 2.0;
+
+// Omnibox corner radius is |4.0|, this needs to look tight WRT that.
+const CGFloat kBubbleCornerRadius = 2.0;
+
+// How far to inset the bubble from the top and bottom of the drawing
+// frame.
+// TODO(shess): Would be nicer to have the drawing code factor out the
+// space outside the border, and perhaps the border. Then this could
+// reflect the single pixel space w/in that.
+const CGFloat kBubbleYInset = 4.0;
+
+} // namespace
+
+BubbleDecoration::BubbleDecoration(NSFont* font) {
+ DCHECK(font);
+ if (font) {
+ NSDictionary* attributes =
+ [NSDictionary dictionaryWithObject:font
+ forKey:NSFontAttributeName];
+ attributes_.reset([attributes retain]);
+ }
+}
+
+BubbleDecoration::~BubbleDecoration() {
+}
+
+CGFloat BubbleDecoration::GetWidthForImageAndLabel(NSImage* image,
+ NSString* label) {
+ if (!image && !label)
+ return kOmittedWidth;
+
+ const CGFloat image_width = image ? [image size].width : 0.0;
+ if (!label)
+ return kBubblePadding + image_width;
+
+ // The bubble needs to take up an integral number of pixels.
+ // Generally -sizeWithAttributes: seems to overestimate rather than
+ // underestimate, so floor() seems to work better.
+ const CGFloat label_width =
+ std::floor([label sizeWithAttributes:attributes_].width);
+ return kBubblePadding + image_width + label_width;
+}
+
+NSRect BubbleDecoration::GetImageRectInFrame(NSRect frame) {
+ NSRect imageRect = NSInsetRect(frame, 0.0, kBubbleYInset);
+ if (image_) {
+ // Center the image vertically.
+ const NSSize imageSize = [image_ size];
+ imageRect.origin.y +=
+ std::floor((NSHeight(frame) - imageSize.height) / 2.0);
+ imageRect.size = imageSize;
+ }
+ return imageRect;
+}
+
+CGFloat BubbleDecoration::GetWidthForSpace(CGFloat width) {
+ const CGFloat all_width = GetWidthForImageAndLabel(image_, label_);
+ if (all_width <= width)
+ return all_width;
+
+ const CGFloat image_width = GetWidthForImageAndLabel(image_, nil);
+ if (image_width <= width)
+ return image_width;
+
+ return kOmittedWidth;
+}
+
+void BubbleDecoration::DrawInFrame(NSRect frame, NSView* control_view) {
+ const NSRect decorationFrame = NSInsetRect(frame, 0.0, kBubbleYInset);
+
+ // The inset is to put the border down the middle of the pixel.
+ NSRect bubbleFrame = NSInsetRect(decorationFrame, 0.5, 0.5);
+ bubbleFrame.origin.x -= kLeftSideOverdraw;
+ bubbleFrame.size.width += kLeftSideOverdraw;
+ NSBezierPath* path =
+ [NSBezierPath bezierPathWithRoundedRect:bubbleFrame
+ xRadius:kBubbleCornerRadius
+ yRadius:kBubbleCornerRadius];
+
+ [background_color_ setFill];
+ [path fill];
+
+ [border_color_ setStroke];
+ [path setLineWidth:1.0];
+ [path stroke];
+
+ NSRect imageRect = decorationFrame;
+ if (image_) {
+ // Center the image vertically.
+ const NSSize imageSize = [image_ size];
+ imageRect.origin.y +=
+ std::floor((NSHeight(decorationFrame) - imageSize.height) / 2.0);
+ imageRect.size = imageSize;
+ [image_ drawInRect:imageRect
+ fromRect:NSZeroRect // Entire image
+ operation:NSCompositeSourceOver
+ fraction:1.0
+ neverFlipped:YES];
+ } else {
+ imageRect.size = NSZeroSize;
+ }
+
+ if (label_) {
+ NSRect textRect = decorationFrame;
+ textRect.origin.x = NSMaxX(imageRect);
+ textRect.size.width = NSMaxX(decorationFrame) - NSMinX(textRect);
+ [label_ drawInRect:textRect withAttributes:attributes_];
+ }
+}
+
+NSImage* BubbleDecoration::GetImage() {
+ return image_;
+}
+
+void BubbleDecoration::SetImage(NSImage* image) {
+ image_.reset([image retain]);
+}
+
+void BubbleDecoration::SetLabel(NSString* label) {
+ // If the initializer was called with |nil|, then the code cannot
+ // process a label.
+ DCHECK(attributes_);
+ if (attributes_)
+ label_.reset([label copy]);
+}
+
+void BubbleDecoration::SetColors(NSColor* border_color,
+ NSColor* background_color,
+ NSColor* text_color) {
+ border_color_.reset([border_color retain]);
+ background_color_.reset([background_color retain]);
+
+ scoped_nsobject<NSMutableDictionary> attributes([attributes_ mutableCopy]);
+ [attributes setObject:text_color forKey:NSForegroundColorAttributeName];
+ attributes_.reset([attributes copy]);
+}
diff --git a/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.h b/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.h
new file mode 100644
index 0000000..7f47aa9
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.h
@@ -0,0 +1,75 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_LOCATION_BAR_CONTENT_SETTING_DECORATION_H_
+#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_CONTENT_SETTING_DECORATION_H_
+#pragma once
+
+#include "base/scoped_ptr.h"
+#import "chrome/browser/ui/cocoa/location_bar/image_decoration.h"
+#include "chrome/common/content_settings_types.h"
+
+// ContentSettingDecoration is used to display the content settings
+// images on the current page.
+
+@class ContentSettingAnimationState;
+class ContentSettingImageModel;
+class LocationBarViewMac;
+class Profile;
+class TabContents;
+
+class ContentSettingDecoration : public ImageDecoration {
+ public:
+ ContentSettingDecoration(ContentSettingsType settings_type,
+ LocationBarViewMac* owner,
+ Profile* profile);
+ virtual ~ContentSettingDecoration();
+
+ // Updates the image and visibility state based on the supplied TabContents.
+ // Returns true if the decoration's visible state changed.
+ bool UpdateFromTabContents(TabContents* tab_contents);
+
+ // Overridden from |LocationBarDecoration|
+ virtual bool AcceptsMousePress() { return true; }
+ virtual bool OnMousePressed(NSRect frame);
+ virtual NSString* GetToolTip();
+ virtual CGFloat GetWidthForSpace(CGFloat width);
+ virtual void DrawInFrame(NSRect frame, NSView* control_view);
+
+ // Called from internal animator. Only public because ObjC objects can't
+ // be friends.
+ virtual void AnimationTimerFired();
+
+ private:
+ // Helper to get where the bubble point should land. Similar to
+ // |PageActionDecoration| or |StarDecoration| (|LocationBarViewMac|
+ // calls those).
+ NSPoint GetBubblePointInFrame(NSRect frame);
+
+ void SetToolTip(NSString* tooltip);
+
+ // Returns an attributed string with the animated text. Caller is responsible
+ // for releasing.
+ NSAttributedString* CreateAnimatedText();
+
+ // Measure the width of the animated text.
+ CGFloat MeasureTextWidth();
+
+ scoped_ptr<ContentSettingImageModel> content_setting_image_model_;
+
+ LocationBarViewMac* owner_; // weak
+ Profile* profile_; // weak
+
+ scoped_nsobject<NSString> tooltip_;
+
+ // Used when the decoration has animated text.
+ scoped_nsobject<ContentSettingAnimationState> animation_;
+ CGFloat text_width_;
+ scoped_nsobject<NSAttributedString> animated_text_;
+ scoped_nsobject<NSGradient> gradient_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContentSettingDecoration);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_CONTENT_SETTING_DECORATION_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.mm b/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.mm
new file mode 100644
index 0000000..523eb6f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.mm
@@ -0,0 +1,376 @@
+// 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 "chrome/browser/ui/cocoa/location_bar/content_setting_decoration.h"
+
+#include <algorithm>
+
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/command_line.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/content_setting_image_model.h"
+#include "chrome/browser/content_setting_bubble_model.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#import "chrome/browser/ui/cocoa/content_setting_bubble_cocoa.h"
+#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
+#include "net/base/net_util.h"
+
+namespace {
+
+// How far to offset up from the bottom of the view to get the top
+// border of the popup 2px below the bottom of the Omnibox.
+const CGFloat kPopupPointYOffset = 2.0;
+
+// Duration of animation, 3 seconds. The ContentSettingAnimationState breaks
+// this up into different states of varying lengths.
+const NSTimeInterval kAnimationDuration = 3.0;
+
+// Interval of the animation timer, 60Hz.
+const NSTimeInterval kAnimationInterval = 1.0 / 60.0;
+
+// The % of time it takes to open or close the animating text, ie at 0.2, the
+// opening takes 20% of the whole animation and the closing takes 20%. The
+// remainder of the animation is with the text at full width.
+const double kInMotionInterval = 0.2;
+
+// Used to create a % complete of the "in motion" part of the animation, eg
+// it should be 1.0 (100%) when the progress is 0.2.
+const double kInMotionMultiplier = 1.0 / kInMotionInterval;
+
+// Padding for the animated text with respect to the image.
+const CGFloat kTextMarginPadding = 4;
+const CGFloat kIconMarginPadding = 2;
+const CGFloat kBorderPadding = 3;
+
+// Different states in which the animation can be. In |kOpening|, the text
+// is getting larger. In |kOpen|, the text should be displayed at full size.
+// In |kClosing|, the text is again getting smaller. The durations in which
+// the animation remains in each state are internal to
+// |ContentSettingAnimationState|.
+enum AnimationState {
+ kNoAnimation,
+ kOpening,
+ kOpen,
+ kClosing
+};
+
+} // namespace
+
+
+// An ObjC class that handles the multiple states of the text animation and
+// bridges NSTimer calls back to the ContentSettingDecoration that owns it.
+// Should be lazily instantiated to only exist when the decoration requires
+// animation.
+// NOTE: One could make this class more generic, but this class only exists
+// because CoreAnimation cannot be used (there are no views to work with).
+@interface ContentSettingAnimationState : NSObject {
+ @private
+ ContentSettingDecoration* owner_; // Weak, owns this.
+ double progress_; // Counter, [0..1], with aninmation progress.
+ NSTimer* timer_; // Animation timer. Owns this, owned by the run loop.
+}
+
+// [0..1], the current progress of the animation. -animationState will return
+// |kNoAnimation| when progress is <= 0 or >= 1. Useful when state is
+// |kOpening| or |kClosing| as a multiplier for displaying width. Don't use
+// to track state transitions, use -animationState instead.
+@property (readonly, nonatomic) double progress;
+
+// Designated initializer. |owner| must not be nil. Animation timer will start
+// as soon as the object is created.
+- (id)initWithOwner:(ContentSettingDecoration*)owner;
+
+// Returns the current animation state based on how much time has elapsed.
+- (AnimationState)animationState;
+
+// Call when |owner| is going away or the animation needs to be stopped.
+// Ensures that any dangling references are cleared. Can be called multiple
+// times.
+- (void)stopAnimation;
+
+@end
+
+@implementation ContentSettingAnimationState
+
+@synthesize progress = progress_;
+
+- (id)initWithOwner:(ContentSettingDecoration*)owner {
+ self = [super init];
+ if (self) {
+ owner_ = owner;
+ timer_ = [NSTimer scheduledTimerWithTimeInterval:kAnimationInterval
+ target:self
+ selector:@selector(timerFired:)
+ userInfo:nil
+ repeats:YES];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [self stopAnimation];
+ [super dealloc];
+}
+
+// Clear weak references and stop the timer.
+- (void)stopAnimation {
+ owner_ = nil;
+ [timer_ invalidate];
+ timer_ = nil;
+}
+
+// Returns the current state based on how much time has elapsed.
+- (AnimationState)animationState {
+ if (progress_ <= 0.0 || progress_ >= 1.0)
+ return kNoAnimation;
+ if (progress_ <= kInMotionInterval)
+ return kOpening;
+ if (progress_ >= 1.0 - kInMotionInterval)
+ return kClosing;
+ return kOpen;
+}
+
+- (void)timerFired:(NSTimer*)timer {
+ // Increment animation progress, normalized to [0..1].
+ progress_ += kAnimationInterval / kAnimationDuration;
+ progress_ = std::min(progress_, 1.0);
+ owner_->AnimationTimerFired();
+ // Stop timer if it has reached the end of its life.
+ if (progress_ >= 1.0)
+ [self stopAnimation];
+}
+
+@end
+
+
+ContentSettingDecoration::ContentSettingDecoration(
+ ContentSettingsType settings_type,
+ LocationBarViewMac* owner,
+ Profile* profile)
+ : content_setting_image_model_(
+ ContentSettingImageModel::CreateContentSettingImageModel(
+ settings_type)),
+ owner_(owner),
+ profile_(profile),
+ text_width_(0.0) {
+}
+
+ContentSettingDecoration::~ContentSettingDecoration() {
+ // Just in case the timer is still holding onto the animation object, force
+ // cleanup so it can't get back to |this|.
+ [animation_ stopAnimation];
+}
+
+bool ContentSettingDecoration::UpdateFromTabContents(
+ TabContents* tab_contents) {
+ bool was_visible = IsVisible();
+ int old_icon = content_setting_image_model_->get_icon();
+ content_setting_image_model_->UpdateFromTabContents(tab_contents);
+ SetVisible(content_setting_image_model_->is_visible());
+ bool decoration_changed = was_visible != IsVisible() ||
+ old_icon != content_setting_image_model_->get_icon();
+ if (IsVisible()) {
+ // TODO(thakis): We should use pdfs for these icons on OSX.
+ // http://crbug.com/35847
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ SetImage(rb.GetNativeImageNamed(content_setting_image_model_->get_icon()));
+ SetToolTip(base::SysUTF8ToNSString(
+ content_setting_image_model_->get_tooltip()));
+ // Check if there is an animation and start it if it hasn't yet started.
+ bool has_animated_text =
+ content_setting_image_model_->explanatory_string_id();
+ // Check if the animation is enabled.
+ bool animation_enabled = CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBlockContentAnimation);
+ if (has_animated_text && animation_enabled && !animation_) {
+ // Start animation, its timer will drive reflow. Note the text is
+ // cached so it is not allowed to change during the animation.
+ animation_.reset(
+ [[ContentSettingAnimationState alloc] initWithOwner:this]);
+ animated_text_.reset(CreateAnimatedText());
+ text_width_ = MeasureTextWidth();
+ } else if (!has_animated_text) {
+ // Decoration no longer has animation, stop it (ok to always do this).
+ [animation_ stopAnimation];
+ animation_.reset(nil);
+ }
+ } else {
+ // Decoration no longer visible, stop/clear animation.
+ [animation_ stopAnimation];
+ animation_.reset(nil);
+ }
+ return decoration_changed;
+}
+
+CGFloat ContentSettingDecoration::MeasureTextWidth() {
+ return [animated_text_ size].width;
+}
+
+// Returns an attributed string with the animated text. Caller is responsible
+// for releasing.
+NSAttributedString* ContentSettingDecoration::CreateAnimatedText() {
+ NSString* text =
+ l10n_util::GetNSString(
+ content_setting_image_model_->explanatory_string_id());
+ NSDictionary* attributes =
+ [NSDictionary dictionaryWithObject:[NSFont labelFontOfSize:14]
+ forKey:NSFontAttributeName];
+ NSAttributedString* attr_string =
+ [[NSAttributedString alloc] initWithString:text attributes:attributes];
+ return attr_string;
+}
+
+NSPoint ContentSettingDecoration::GetBubblePointInFrame(NSRect frame) {
+ // Compute the frame as if there is no animation pill in the Omnibox. Place
+ // the bubble where the icon would be without animation, so when the animation
+ // ends, the bubble is pointing in the right place.
+ NSSize image_size = [GetImage() size];
+ frame.origin.x += frame.size.width - image_size.width;
+ frame.size = image_size;
+
+ const NSRect draw_frame = GetDrawRectInFrame(frame);
+ return NSMakePoint(NSMidX(draw_frame),
+ NSMaxY(draw_frame) - kPopupPointYOffset);
+}
+
+bool ContentSettingDecoration::OnMousePressed(NSRect frame) {
+ // Get host. This should be shared on linux/win/osx medium-term.
+ TabContents* tabContents =
+ BrowserList::GetLastActive()->GetSelectedTabContents();
+ if (!tabContents)
+ return true;
+
+ GURL url = tabContents->GetURL();
+ std::wstring displayHost;
+ net::AppendFormattedHost(
+ url,
+ UTF8ToWide(profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)),
+ &displayHost, NULL, NULL);
+
+ // Find point for bubble's arrow in screen coordinates.
+ // TODO(shess): |owner_| is only being used to fetch |field|.
+ // Consider passing in |control_view|. Or refactoring to be
+ // consistent with other decorations (which don't currently bring up
+ // their bubble directly).
+ AutocompleteTextField* field = owner_->GetAutocompleteTextField();
+ NSPoint anchor = GetBubblePointInFrame(frame);
+ anchor = [field convertPoint:anchor toView:nil];
+ anchor = [[field window] convertBaseToScreen:anchor];
+
+ // Open bubble.
+ ContentSettingBubbleModel* model =
+ ContentSettingBubbleModel::CreateContentSettingBubbleModel(
+ tabContents, profile_,
+ content_setting_image_model_->get_content_settings_type());
+ [ContentSettingBubbleController showForModel:model
+ parentWindow:[field window]
+ anchoredAt:anchor];
+ return true;
+}
+
+NSString* ContentSettingDecoration::GetToolTip() {
+ return tooltip_.get();
+}
+
+void ContentSettingDecoration::SetToolTip(NSString* tooltip) {
+ tooltip_.reset([tooltip retain]);
+}
+
+// Override to handle the case where there is text to display during the
+// animation. The width is based on the animator's progress.
+CGFloat ContentSettingDecoration::GetWidthForSpace(CGFloat width) {
+ CGFloat preferred_width = ImageDecoration::GetWidthForSpace(width);
+ if (animation_.get()) {
+ AnimationState state = [animation_ animationState];
+ if (state != kNoAnimation) {
+ CGFloat progress = [animation_ progress];
+ // Add the margins, fixed for all animation states.
+ preferred_width += kIconMarginPadding + kTextMarginPadding;
+ // Add the width of the text based on the state of the animation.
+ switch (state) {
+ case kOpening:
+ preferred_width += text_width_ * kInMotionMultiplier * progress;
+ break;
+ case kOpen:
+ preferred_width += text_width_;
+ break;
+ case kClosing:
+ preferred_width += text_width_ * kInMotionMultiplier * (1 - progress);
+ break;
+ default:
+ // Do nothing.
+ break;
+ }
+ }
+ }
+ return preferred_width;
+}
+
+void ContentSettingDecoration::DrawInFrame(NSRect frame, NSView* control_view) {
+ if ([animation_ animationState] != kNoAnimation) {
+ // Draw the background. Cache the gradient.
+ if (!gradient_) {
+ // Colors chosen to match Windows code.
+ NSColor* start_color =
+ [NSColor colorWithCalibratedRed:1.0 green:0.97 blue:0.83 alpha:1.0];
+ NSColor* end_color =
+ [NSColor colorWithCalibratedRed:1.0 green:0.90 blue:0.68 alpha:1.0];
+ NSArray* color_array =
+ [NSArray arrayWithObjects:start_color, end_color, nil];
+ gradient_.reset([[NSGradient alloc] initWithColors:color_array]);
+ }
+
+ NSGraphicsContext* context = [NSGraphicsContext currentContext];
+ [context saveGraphicsState];
+
+ NSRectClip(frame);
+
+ frame = NSInsetRect(frame, 0.0, kBorderPadding);
+ [gradient_ drawInRect:frame angle:90.0];
+ NSColor* border_color =
+ [NSColor colorWithCalibratedRed:0.91 green:0.73 blue:0.4 alpha:1.0];
+ [border_color set];
+ NSFrameRect(frame);
+
+ // Draw the icon.
+ NSImage* icon = GetImage();
+ NSRect icon_rect = frame;
+ if (icon) {
+ icon_rect.origin.x += kIconMarginPadding;
+ icon_rect.size.width = [icon size].width;
+ ImageDecoration::DrawInFrame(icon_rect, control_view);
+ }
+
+ // Draw the text, clipped to fit on the right. While handling clipping,
+ // NSAttributedString's drawInRect: won't draw a word if it doesn't fit
+ // in the bounding box so instead use drawAtPoint: with a manual clip
+ // rect.
+ NSRect remainder = frame;
+ remainder.origin.x = NSMaxX(icon_rect);
+ NSInsetRect(remainder, kTextMarginPadding, kTextMarginPadding);
+ // .get() needed to fix compiler warning (confusion with NSImageRep).
+ [animated_text_.get() drawAtPoint:remainder.origin];
+
+ [context restoreGraphicsState];
+ } else {
+ // No animation, draw the image as normal.
+ ImageDecoration::DrawInFrame(frame, control_view);
+ }
+}
+
+void ContentSettingDecoration::AnimationTimerFired() {
+ owner_->Layout();
+ // Even after the animation completes, the |animator_| object should be kept
+ // alive to prevent the animation from re-appearing if the page opens
+ // additional popups later. The animator will be cleared when the decoration
+ // hides, indicating something has changed with the TabContents (probably
+ // navigation).
+}
diff --git a/chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration.h b/chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration.h
new file mode 100644
index 0000000..fb13de1
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration.h
@@ -0,0 +1,59 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_LOCATION_BAR_EV_BUBBLE_DECORATION_H_
+#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_EV_BUBBLE_DECORATION_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "chrome/browser/ui/cocoa/location_bar/bubble_decoration.h"
+
+// Draws the "Extended Validation SSL" bubble. This will be a lock
+// icon plus a label from the certification, and will replace the
+// location icon for URLs which have an EV cert. The |location_icon|
+// is used to fulfill drag-related calls.
+
+// TODO(shess): Refactor to pull the |location_icon| functionality out
+// into a distinct class like views |ClickHandler|.
+// http://crbug.com/48866
+
+class LocationIconDecoration;
+
+class EVBubbleDecoration : public BubbleDecoration {
+ public:
+ EVBubbleDecoration(LocationIconDecoration* location_icon, NSFont* font);
+
+ // |GetWidthForSpace()| will set |full_label| as the label, if it
+ // fits, else it will set an elided version.
+ void SetFullLabel(NSString* full_label);
+
+ // Get the point where the page info bubble should point within the
+ // decoration's frame, in the cell's coordinates.
+ NSPoint GetBubblePointInFrame(NSRect frame);
+
+ // Implement |LocationBarDecoration|.
+ virtual CGFloat GetWidthForSpace(CGFloat width);
+ virtual bool IsDraggable();
+ virtual NSPasteboard* GetDragPasteboard();
+ virtual NSImage* GetDragImage();
+ virtual NSRect GetDragImageFrame(NSRect frame) {
+ return GetImageRectInFrame(frame);
+ }
+ virtual bool OnMousePressed(NSRect frame);
+ virtual bool AcceptsMousePress() { return true; }
+
+ private:
+ // Keeps a reference to the font for use when eliding.
+ scoped_nsobject<NSFont> font_;
+
+ // The real label. BubbleDecoration's label may be elided.
+ scoped_nsobject<NSString> full_label_;
+
+ LocationIconDecoration* location_icon_; // weak, owned by location bar.
+
+ DISALLOW_COPY_AND_ASSIGN(EVBubbleDecoration);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_EV_BUBBLE_DECORATION_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration.mm b/chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration.mm
new file mode 100644
index 0000000..ad384f9
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration.mm
@@ -0,0 +1,117 @@
+// 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 "chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration.h"
+
+#include "app/text_elider.h"
+#import "base/logging.h"
+#include "base/sys_string_conversions.h"
+#import "chrome/browser/ui/cocoa/image_utils.h"
+#import "chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h"
+#include "gfx/font.h"
+
+namespace {
+
+// TODO(shess): In general, decorations that don't fit in the
+// available space are omitted. This one never goes to omitted, it
+// sticks at 150px, which AFAICT follows the Windows code. Since the
+// Layout() code doesn't take this into account, it's possible the
+// control could end up with display artifacts, though things still
+// work (and don't crash).
+// http://crbug.com/49822
+
+// Minimum acceptable width for the ev bubble.
+const CGFloat kMinElidedBubbleWidth = 150.0;
+
+// Maximum amount of available space to make the bubble, subject to
+// |kMinElidedBubbleWidth|.
+const float kMaxBubbleFraction = 0.5;
+
+// The info-bubble point should look like it points to the bottom of the lock
+// icon. Determined with Pixie.app.
+const CGFloat kPageInfoBubblePointYOffset = 6.0;
+
+// TODO(shess): This is ugly, find a better way. Using it right now
+// so that I can crib from gtk and still be able to see that I'm using
+// the same values easily.
+NSColor* ColorWithRGBBytes(int rr, int gg, int bb) {
+ DCHECK_LE(rr, 255);
+ DCHECK_LE(bb, 255);
+ DCHECK_LE(gg, 255);
+ return [NSColor colorWithCalibratedRed:static_cast<float>(rr)/255.0
+ green:static_cast<float>(gg)/255.0
+ blue:static_cast<float>(bb)/255.0
+ alpha:1.0];
+}
+
+} // namespace
+
+EVBubbleDecoration::EVBubbleDecoration(
+ LocationIconDecoration* location_icon,
+ NSFont* font)
+ : BubbleDecoration(font),
+ font_([font retain]),
+ location_icon_(location_icon) {
+ // Color tuples stolen from location_bar_view_gtk.cc.
+ NSColor* border_color = ColorWithRGBBytes(0x90, 0xc3, 0x90);
+ NSColor* background_color = ColorWithRGBBytes(0xef, 0xfc, 0xef);
+ NSColor* text_color = ColorWithRGBBytes(0x07, 0x95, 0x00);
+ SetColors(border_color, background_color, text_color);
+}
+
+void EVBubbleDecoration::SetFullLabel(NSString* label) {
+ full_label_.reset([label retain]);
+ SetLabel(full_label_);
+}
+
+NSPoint EVBubbleDecoration::GetBubblePointInFrame(NSRect frame) {
+ NSRect image_rect = GetImageRectInFrame(frame);
+ return NSMakePoint(NSMidX(image_rect),
+ NSMaxY(image_rect) - kPageInfoBubblePointYOffset);
+}
+
+CGFloat EVBubbleDecoration::GetWidthForSpace(CGFloat width) {
+ // Limit with to not take up too much of the available width, but
+ // also don't let it shrink too much.
+ width = std::max(width * kMaxBubbleFraction, kMinElidedBubbleWidth);
+
+ // Use the full label if it fits.
+ NSImage* image = GetImage();
+ const CGFloat all_width = GetWidthForImageAndLabel(image, full_label_);
+ if (all_width <= width) {
+ SetLabel(full_label_);
+ return all_width;
+ }
+
+ // Width left for laying out the label.
+ const CGFloat width_left = width - GetWidthForImageAndLabel(image, @"");
+
+ // Middle-elide the label to fit |width_left|. This leaves the
+ // prefix and the trailing country code in place.
+ gfx::Font font(base::SysNSStringToWide([font_ fontName]),
+ [font_ pointSize]);
+ NSString* elided_label = base::SysUTF16ToNSString(
+ ElideText(base::SysNSStringToUTF16(full_label_), font, width_left, true));
+
+ // Use the elided label.
+ SetLabel(elided_label);
+ return GetWidthForImageAndLabel(image, elided_label);
+}
+
+// Pass mouse operations through to location icon.
+bool EVBubbleDecoration::IsDraggable() {
+ return location_icon_->IsDraggable();
+}
+
+NSPasteboard* EVBubbleDecoration::GetDragPasteboard() {
+ return location_icon_->GetDragPasteboard();
+}
+
+NSImage* EVBubbleDecoration::GetDragImage() {
+ return location_icon_->GetDragImage();
+}
+
+bool EVBubbleDecoration::OnMousePressed(NSRect frame) {
+ return location_icon_->OnMousePressed(frame);
+}
diff --git a/chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration_unittest.mm b/chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration_unittest.mm
new file mode 100644
index 0000000..0506a72
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration_unittest.mm
@@ -0,0 +1,55 @@
+// 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>
+
+#import "chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration.h"
+
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class EVBubbleDecorationTest : public CocoaTest {
+ public:
+ EVBubbleDecorationTest()
+ : decoration_(NULL, [NSFont userFontOfSize:12]) {
+ }
+
+ EVBubbleDecoration decoration_;
+};
+
+// Test that the decoration gets smaller when there's not enough space
+// to fit, within bounds.
+TEST_F(EVBubbleDecorationTest, MiddleElide) {
+ NSString* kLongString = @"A very long string with spaces";
+ const CGFloat kWide = 1000.0; // Wide enough to fit everything.
+ const CGFloat kNarrow = 10.0; // Too narrow for anything.
+ const CGFloat kMinimumWidth = 100.0; // Never should get this small.
+
+ const NSSize kImageSize = NSMakeSize(20.0, 20.0);
+ scoped_nsobject<NSImage> image([[NSImage alloc] initWithSize:kImageSize]);
+
+ decoration_.SetImage(image);
+ decoration_.SetFullLabel(kLongString);
+
+ // Lots of space, decoration not omitted.
+ EXPECT_NE(decoration_.GetWidthForSpace(kWide),
+ LocationBarDecoration::kOmittedWidth);
+
+ // If the available space is of the same magnitude as the required
+ // space, the decoration doesn't eat it all up.
+ const CGFloat long_width = decoration_.GetWidthForSpace(kWide);
+ EXPECT_NE(decoration_.GetWidthForSpace(long_width + 20.0),
+ LocationBarDecoration::kOmittedWidth);
+ EXPECT_LT(decoration_.GetWidthForSpace(long_width + 20.0), long_width);
+
+ // If there is very little space, the decoration is still relatively
+ // big.
+ EXPECT_NE(decoration_.GetWidthForSpace(kNarrow),
+ LocationBarDecoration::kOmittedWidth);
+ EXPECT_GT(decoration_.GetWidthForSpace(kNarrow), kMinimumWidth);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/location_bar/image_decoration.h b/chrome/browser/ui/cocoa/location_bar/image_decoration.h
new file mode 100644
index 0000000..c0bcfbf
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/image_decoration.h
@@ -0,0 +1,36 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_LOCATION_BAR_IMAGE_DECORATION_H_
+#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_IMAGE_DECORATION_H_
+#pragma once
+
+#import "base/scoped_nsobject.h"
+#include "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
+
+// |LocationBarDecoration| which sizes and draws itself according to
+// an |NSImage|.
+
+class ImageDecoration : public LocationBarDecoration {
+ public:
+ ImageDecoration();
+ virtual ~ImageDecoration();
+
+ NSImage* GetImage();
+ void SetImage(NSImage* image);
+
+ // Returns the part of |frame| the image is drawn in.
+ NSRect GetDrawRectInFrame(NSRect frame);
+
+ // Implement |LocationBarDecoration|.
+ virtual CGFloat GetWidthForSpace(CGFloat width);
+ virtual void DrawInFrame(NSRect frame, NSView* control_view);
+
+ private:
+ scoped_nsobject<NSImage> image_;
+
+ DISALLOW_COPY_AND_ASSIGN(ImageDecoration);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_IMAGE_DECORATION_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/image_decoration.mm b/chrome/browser/ui/cocoa/location_bar/image_decoration.mm
new file mode 100644
index 0000000..8056a4e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/image_decoration.mm
@@ -0,0 +1,54 @@
+// 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.
+
+#include <cmath>
+
+#import "chrome/browser/ui/cocoa/location_bar/image_decoration.h"
+
+#import "chrome/browser/ui/cocoa/image_utils.h"
+
+ImageDecoration::ImageDecoration() {
+}
+
+ImageDecoration::~ImageDecoration() {
+}
+
+NSImage* ImageDecoration::GetImage() {
+ return image_;
+}
+
+void ImageDecoration::SetImage(NSImage* image) {
+ image_.reset([image retain]);
+}
+
+NSRect ImageDecoration::GetDrawRectInFrame(NSRect frame) {
+ NSImage* image = GetImage();
+ if (!image)
+ return frame;
+
+ // Center the image within the frame.
+ const CGFloat delta_height = NSHeight(frame) - [image size].height;
+ const CGFloat y_inset = std::floor(delta_height / 2.0);
+ const CGFloat delta_width = NSWidth(frame) - [image size].width;
+ const CGFloat x_inset = std::floor(delta_width / 2.0);
+ return NSInsetRect(frame, x_inset, y_inset);
+}
+
+CGFloat ImageDecoration::GetWidthForSpace(CGFloat width) {
+ NSImage* image = GetImage();
+ if (image) {
+ const CGFloat image_width = [image size].width;
+ if (image_width <= width)
+ return image_width;
+ }
+ return kOmittedWidth;
+}
+
+void ImageDecoration::DrawInFrame(NSRect frame, NSView* control_view) {
+ [GetImage() drawInRect:GetDrawRectInFrame(frame)
+ fromRect:NSZeroRect // Entire image
+ operation:NSCompositeSourceOver
+ fraction:1.0
+ neverFlipped:YES];
+}
diff --git a/chrome/browser/ui/cocoa/location_bar/image_decoration_unittest.mm b/chrome/browser/ui/cocoa/location_bar/image_decoration_unittest.mm
new file mode 100644
index 0000000..db69b0d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/image_decoration_unittest.mm
@@ -0,0 +1,55 @@
+// 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>
+
+#import "chrome/browser/ui/cocoa/location_bar/image_decoration.h"
+
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class ImageDecorationTest : public CocoaTest {
+ public:
+ ImageDecoration decoration_;
+};
+
+TEST_F(ImageDecorationTest, SetGetImage) {
+ EXPECT_FALSE(decoration_.GetImage());
+
+ const NSSize kImageSize = NSMakeSize(20.0, 20.0);
+ scoped_nsobject<NSImage> image([[NSImage alloc] initWithSize:kImageSize]);
+
+ decoration_.SetImage(image);
+ EXPECT_EQ(decoration_.GetImage(), image);
+
+ decoration_.SetImage(nil);
+ EXPECT_FALSE(decoration_.GetImage());
+}
+
+TEST_F(ImageDecorationTest, GetWidthForSpace) {
+ const CGFloat kWide = 100.0;
+ const CGFloat kNarrow = 10.0;
+
+ // Decoration with no image is omitted.
+ EXPECT_EQ(decoration_.GetWidthForSpace(kWide),
+ LocationBarDecoration::kOmittedWidth);
+
+ const NSSize kImageSize = NSMakeSize(20.0, 20.0);
+ scoped_nsobject<NSImage> image([[NSImage alloc] initWithSize:kImageSize]);
+
+ // Decoration takes up the space of the image.
+ decoration_.SetImage(image);
+ EXPECT_EQ(decoration_.GetWidthForSpace(kWide), kImageSize.width);
+
+ // If the image doesn't fit, decoration is omitted.
+ EXPECT_EQ(decoration_.GetWidthForSpace(kNarrow),
+ LocationBarDecoration::kOmittedWidth);
+}
+
+// TODO(shess): It would be nice to test mouse clicks and dragging,
+// but those are hard because they require a real |owner|.
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/location_bar/instant_opt_in_controller.h b/chrome/browser/ui/cocoa/location_bar/instant_opt_in_controller.h
new file mode 100644
index 0000000..97a6b3e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/instant_opt_in_controller.h
@@ -0,0 +1,43 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_LOCATION_BAR_INSTANT_OPT_IN_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_INSTANT_OPT_IN_CONTROLLER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+class Profile;
+
+// This delegate receives callbacks from the InstantOptInController when the OK
+// and Cancel buttons are pushed.
+class InstantOptInControllerDelegate {
+ public:
+ virtual void UserPressedOptIn(bool opt_in) = 0;
+
+ protected:
+ virtual ~InstantOptInControllerDelegate() {}
+};
+
+// Manages an instant opt-in view, which is part of the omnibox popup.
+@interface InstantOptInController : NSViewController {
+ @private
+ InstantOptInControllerDelegate* delegate_; // weak
+
+ // Needed in order to localize text and resize to fit.
+ IBOutlet NSButton* okButton_;
+ IBOutlet NSButton* cancelButton_;
+ IBOutlet NSTextField* label_;
+}
+
+// Designated initializer.
+- (id)initWithDelegate:(InstantOptInControllerDelegate*)delegate;
+
+// Button actions.
+- (IBAction)ok:(id)sender;
+- (IBAction)cancel:(id)sender;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_INSTANT_OPT_IN_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/instant_opt_in_controller.mm b/chrome/browser/ui/cocoa/location_bar/instant_opt_in_controller.mm
new file mode 100644
index 0000000..17b0d15
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/instant_opt_in_controller.mm
@@ -0,0 +1,31 @@
+// 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 "chrome/browser/ui/cocoa/location_bar/instant_opt_in_controller.h"
+
+#include "base/mac_util.h"
+
+@implementation InstantOptInController
+
+- (id)initWithDelegate:(InstantOptInControllerDelegate*)delegate {
+ if ((self = [super initWithNibName:@"InstantOptIn"
+ bundle:mac_util::MainAppBundle()])) {
+ delegate_ = delegate;
+ }
+ return self;
+}
+
+- (void)awakeFromNib {
+ // TODO(rohitrao): Translate and resize strings.
+}
+
+- (IBAction)ok:(id)sender {
+ delegate_->UserPressedOptIn(true);
+}
+
+- (IBAction)cancel:(id)sender {
+ delegate_->UserPressedOptIn(false);
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/location_bar/instant_opt_in_controller_unittest.mm b/chrome/browser/ui/cocoa/location_bar/instant_opt_in_controller_unittest.mm
new file mode 100644
index 0000000..81ef513
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/instant_opt_in_controller_unittest.mm
@@ -0,0 +1,62 @@
+// 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.
+
+#include "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/location_bar/instant_opt_in_controller.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+@interface InstantOptInController (ExposedForTesting)
+- (NSButton*)okButton;
+- (NSButton*)cancelButton;
+@end
+
+@implementation InstantOptInController (ExposedForTesting)
+- (NSButton*)okButton {
+ return okButton_;
+}
+
+- (NSButton*)cancelButton {
+ return cancelButton_;
+}
+@end
+
+
+namespace {
+
+class MockDelegate : public InstantOptInControllerDelegate {
+ public:
+ MOCK_METHOD1(UserPressedOptIn, void(bool opt_in));
+};
+
+class InstantOptInControllerTest : public CocoaTest {
+ public:
+ void SetUp() {
+ CocoaTest::SetUp();
+
+ controller_.reset(
+ [[InstantOptInController alloc] initWithDelegate:&delegate_]);
+
+ NSView* parent = [test_window() contentView];
+ [parent addSubview:[controller_ view]];
+ }
+
+ MockDelegate delegate_;
+ scoped_nsobject<InstantOptInController> controller_;
+};
+
+TEST_F(InstantOptInControllerTest, OkButtonCallback) {
+ EXPECT_CALL(delegate_, UserPressedOptIn(true));
+ [[controller_ okButton] performClick:nil];
+}
+
+TEST_F(InstantOptInControllerTest, CancelButtonCallback) {
+ EXPECT_CALL(delegate_, UserPressedOptIn(false));
+ [[controller_ cancelButton] performClick:nil];
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/location_bar/instant_opt_in_view.h b/chrome/browser/ui/cocoa/location_bar/instant_opt_in_view.h
new file mode 100644
index 0000000..b9ef6bd
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/instant_opt_in_view.h
@@ -0,0 +1,16 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_LOCATION_BAR_INSTANT_OPT_IN_VIEW_H_
+#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_INSTANT_OPT_IN_VIEW_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+// The instant opt in view that is embedded in the omnibox. Draws rounded
+// bottom corners and a horizontal gray line at the top.
+@interface InstantOptInView : NSView
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_INSTANT_OPT_IN_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/instant_opt_in_view.mm b/chrome/browser/ui/cocoa/location_bar/instant_opt_in_view.mm
new file mode 100644
index 0000000..06ca79d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/instant_opt_in_view.mm
@@ -0,0 +1,54 @@
+// 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.
+
+#include <algorithm>
+
+#import "chrome/browser/ui/cocoa/location_bar/instant_opt_in_view.h"
+#import "third_party/GTM/AppKit/GTMNSBezierPath+RoundRect.h"
+
+namespace {
+// How to round off the popup's corners. Goal is to match star and go
+// buttons.
+const CGFloat kPopupRoundingRadius = 3.5;
+
+// How far from the top of the view to place the horizontal line.
+const CGFloat kHorizontalLineTopOffset = 2;
+
+// How far from the sides to inset the horizontal line.
+const CGFloat kHorizontalLineInset = 2;
+}
+
+@implementation InstantOptInView
+
+- (void)drawRect:(NSRect)rect {
+ // Round off the bottom corners only.
+ NSBezierPath* path =
+ [NSBezierPath gtm_bezierPathWithRoundRect:[self bounds]
+ topLeftCornerRadius:0
+ topRightCornerRadius:0
+ bottomLeftCornerRadius:kPopupRoundingRadius
+ bottomRightCornerRadius:kPopupRoundingRadius];
+
+ [NSGraphicsContext saveGraphicsState];
+ [path addClip];
+
+ // Background is white.
+ [[NSColor whiteColor] set];
+ NSRectFill(rect);
+
+ // Draw a horizontal line 2 px down from the top of the view, inset at the
+ // sides by 2 px.
+ CGFloat lineY = NSMaxY([self bounds]) - kHorizontalLineTopOffset;
+ CGFloat minX = std::min(NSMinX([self bounds]) + kHorizontalLineInset,
+ NSMaxX([self bounds]));
+ CGFloat maxX = std::max(NSMaxX([self bounds]) - kHorizontalLineInset,
+ NSMinX([self bounds]));
+
+ [[NSColor lightGrayColor] set];
+ NSRectFill(NSMakeRect(minX, lineY, maxX - minX, 1));
+
+ [NSGraphicsContext restoreGraphicsState];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/location_bar/instant_opt_in_view_unittest.mm b/chrome/browser/ui/cocoa/location_bar/instant_opt_in_view_unittest.mm
new file mode 100644
index 0000000..ce5ff48
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/instant_opt_in_view_unittest.mm
@@ -0,0 +1,26 @@
+// 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 "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/location_bar/instant_opt_in_view.h"
+
+namespace {
+
+class InstantOptInViewTest : public CocoaTest {
+ public:
+ InstantOptInViewTest() {
+ NSRect content_frame = [[test_window() contentView] frame];
+ scoped_nsobject<InstantOptInView> view(
+ [[InstantOptInView alloc] initWithFrame:content_frame]);
+ view_ = view.get();
+ [[test_window() contentView] addSubview:view_];
+ }
+
+ InstantOptInView* view_; // Weak. Owned by the view hierarchy.
+};
+
+// Tests display, add/remove.
+TEST_VIEW(InstantOptInViewTest, view_);
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.h b/chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.h
new file mode 100644
index 0000000..3b8c607
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.h
@@ -0,0 +1,47 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_LOCATION_BAR_KEYWORD_HINT_DECORATION_H_
+#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_KEYWORD_HINT_DECORATION_H_
+#pragma once
+
+#include <string>
+
+#import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
+
+#import "base/scoped_nsobject.h"
+
+// Draws the keyword hint, "Press [tab] to search <site>".
+
+class KeywordHintDecoration : public LocationBarDecoration {
+ public:
+ KeywordHintDecoration(NSFont* font);
+ virtual ~KeywordHintDecoration();
+
+ // Calculates the message to display and where to place the [tab]
+ // image.
+ void SetKeyword(const std::wstring& keyword, bool is_extension_keyword);
+
+ // Implement |LocationBarDecoration|.
+ virtual void DrawInFrame(NSRect frame, NSView* control_view);
+ virtual CGFloat GetWidthForSpace(CGFloat width);
+
+ private:
+ // Fetch and cache the [tab] image.
+ NSImage* GetHintImage();
+
+ // Attributes for drawing the hint string, such as font and color.
+ scoped_nsobject<NSDictionary> attributes_;
+
+ // Cache for the [tab] image.
+ scoped_nsobject<NSImage> hint_image_;
+
+ // The text to display to the left and right of the hint image.
+ scoped_nsobject<NSString> hint_prefix_;
+ scoped_nsobject<NSString> hint_suffix_;
+
+ DISALLOW_COPY_AND_ASSIGN(KeywordHintDecoration);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_KEYWORD_HINT_DECORATION_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.mm b/chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.mm
new file mode 100644
index 0000000..0b08031
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.mm
@@ -0,0 +1,160 @@
+// 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.
+
+#include <cmath>
+
+#import "chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.h"
+
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+#import "chrome/browser/ui/cocoa/image_utils.h"
+#include "grit/theme_resources.h"
+#include "grit/generated_resources.h"
+#include "skia/ext/skia_utils_mac.h"
+
+namespace {
+
+// How far to inset the hint text area from sides.
+const CGFloat kHintTextYInset = 4.0;
+
+// How far to inset the hint image from sides. Lines baseline of text
+// in image with baseline of prefix and suffix.
+const CGFloat kHintImageYInset = 4.0;
+
+// Extra padding right and left of the image.
+const CGFloat kHintImagePadding = 1.0;
+
+// Maxmimum of the available space to allow the hint to take over.
+// Should leave enough so that the user has space to edit things.
+const CGFloat kHintAvailableRatio = 2.0 / 3.0;
+
+// Helper to convert |s| to an |NSString|, trimming whitespace at
+// ends.
+NSString* TrimAndConvert(const std::wstring& s) {
+ std::wstring output;
+ TrimWhitespace(s, TRIM_ALL, &output);
+ return base::SysWideToNSString(output);
+}
+
+} // namespace
+
+KeywordHintDecoration::KeywordHintDecoration(NSFont* font) {
+ NSColor* text_color = [NSColor lightGrayColor];
+ NSDictionary* attributes =
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ font, NSFontAttributeName,
+ text_color, NSForegroundColorAttributeName,
+ nil];
+ attributes_.reset([attributes retain]);
+}
+
+KeywordHintDecoration::~KeywordHintDecoration() {
+}
+
+NSImage* KeywordHintDecoration::GetHintImage() {
+ if (!hint_image_) {
+ SkBitmap* skiaBitmap = ResourceBundle::GetSharedInstance().
+ GetBitmapNamed(IDR_LOCATION_BAR_KEYWORD_HINT_TAB);
+ if (skiaBitmap)
+ hint_image_.reset([gfx::SkBitmapToNSImage(*skiaBitmap) retain]);
+ }
+ return hint_image_;
+}
+
+void KeywordHintDecoration::SetKeyword(const std::wstring& short_name,
+ bool is_extension_keyword) {
+ // KEYWORD_HINT is a message like "Press [tab] to search <site>".
+ // [tab] is a parameter to be replaced by an image. "<site>" is
+ // derived from |short_name|.
+ std::vector<size_t> content_param_offsets;
+ int message_id = is_extension_keyword ?
+ IDS_OMNIBOX_EXTENSION_KEYWORD_HINT : IDS_OMNIBOX_KEYWORD_HINT;
+ const std::wstring keyword_hint(
+ l10n_util::GetStringF(message_id,
+ std::wstring(), short_name,
+ &content_param_offsets));
+
+ // Should always be 2 offsets, see the comment in
+ // location_bar_view.cc after IDS_OMNIBOX_KEYWORD_HINT fetch.
+ DCHECK_EQ(content_param_offsets.size(), 2U);
+
+ // Where to put the [tab] image.
+ const size_t split = content_param_offsets.front();
+
+ // Trim the spaces from the edges (there is space in the image) and
+ // convert to |NSString|.
+ hint_prefix_.reset([TrimAndConvert(keyword_hint.substr(0, split)) retain]);
+ hint_suffix_.reset([TrimAndConvert(keyword_hint.substr(split)) retain]);
+}
+
+CGFloat KeywordHintDecoration::GetWidthForSpace(CGFloat width) {
+ NSImage* image = GetHintImage();
+ const CGFloat image_width = image ? [image size].width : 0.0;
+
+ // AFAICT, on Windows the choices are "everything" if it fits, then
+ // "image only" if it fits.
+
+ // Entirely too small to fit, omit.
+ if (width < image_width)
+ return kOmittedWidth;
+
+ // Show the full hint if it won't take up too much space. The image
+ // needs to be placed at a pixel boundary, round the text widths so
+ // that any partially-drawn pixels don't look too close (or too
+ // far).
+ CGFloat full_width =
+ std::floor([hint_prefix_ sizeWithAttributes:attributes_].width + 0.5) +
+ kHintImagePadding + image_width + kHintImagePadding +
+ std::floor([hint_suffix_ sizeWithAttributes:attributes_].width + 0.5);
+ if (full_width <= width * kHintAvailableRatio)
+ return full_width;
+
+ return image_width;
+}
+
+void KeywordHintDecoration::DrawInFrame(NSRect frame, NSView* control_view) {
+ NSImage* image = GetHintImage();
+ const CGFloat image_width = image ? [image size].width : 0.0;
+
+ const bool draw_full = NSWidth(frame) > image_width;
+
+ if (draw_full) {
+ NSRect prefix_rect = NSInsetRect(frame, 0.0, kHintTextYInset);
+ const CGFloat prefix_width =
+ [hint_prefix_ sizeWithAttributes:attributes_].width;
+ DCHECK_GE(NSWidth(prefix_rect), prefix_width);
+ [hint_prefix_ drawInRect:prefix_rect withAttributes:attributes_];
+
+ // The image should be drawn at a pixel boundary, round the prefix
+ // so that partial pixels aren't oddly close (or distant).
+ frame.origin.x += std::floor(prefix_width + 0.5) + kHintImagePadding;
+ frame.size.width -= std::floor(prefix_width + 0.5) + kHintImagePadding;
+ }
+
+ NSRect image_rect = NSInsetRect(frame, 0.0, kHintImageYInset);
+ image_rect.size = [image size];
+ [image drawInRect:image_rect
+ fromRect:NSZeroRect // Entire image
+ operation:NSCompositeSourceOver
+ fraction:1.0
+ neverFlipped:YES];
+ frame.origin.x += NSWidth(image_rect);
+ frame.size.width -= NSWidth(image_rect);
+
+ if (draw_full) {
+ NSRect suffix_rect = NSInsetRect(frame, 0.0, kHintTextYInset);
+ const CGFloat suffix_width =
+ [hint_suffix_ sizeWithAttributes:attributes_].width;
+
+ // Right-justify the text within the remaining space, so it
+ // doesn't get too close to the image relative to a following
+ // decoration.
+ suffix_rect.origin.x = NSMaxX(suffix_rect) - suffix_width;
+ DCHECK_GE(NSWidth(suffix_rect), suffix_width);
+ [hint_suffix_ drawInRect:suffix_rect withAttributes:attributes_];
+ }
+}
diff --git a/chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration_unittest.mm b/chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration_unittest.mm
new file mode 100644
index 0000000..bfcf454
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration_unittest.mm
@@ -0,0 +1,57 @@
+// 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>
+
+#import "chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.h"
+
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class KeywordHintDecorationTest : public CocoaTest {
+ public:
+ KeywordHintDecorationTest()
+ : decoration_(NULL) {
+ }
+
+ KeywordHintDecoration decoration_;
+};
+
+TEST_F(KeywordHintDecorationTest, GetWidthForSpace) {
+ decoration_.SetVisible(true);
+ decoration_.SetKeyword(std::wstring(L"Google"), false);
+
+ const CGFloat kVeryWide = 1000.0;
+ const CGFloat kFairlyWide = 100.0; // Estimate for full hint space.
+ const CGFloat kEditingSpace = 50.0;
+
+ // Wider than the [tab] image when we have lots of space.
+ EXPECT_NE(decoration_.GetWidthForSpace(kVeryWide),
+ LocationBarDecoration::kOmittedWidth);
+ EXPECT_GE(decoration_.GetWidthForSpace(kVeryWide), kFairlyWide);
+
+ // When there's not enough space for the text, trims to something
+ // narrower.
+ const CGFloat full_width = decoration_.GetWidthForSpace(kVeryWide);
+ const CGFloat not_wide_enough = full_width - 10.0;
+ EXPECT_NE(decoration_.GetWidthForSpace(not_wide_enough),
+ LocationBarDecoration::kOmittedWidth);
+ EXPECT_LT(decoration_.GetWidthForSpace(not_wide_enough), full_width);
+
+ // Even trims when there's enough space for everything, but it would
+ // eat "too much".
+ EXPECT_NE(decoration_.GetWidthForSpace(full_width + kEditingSpace),
+ LocationBarDecoration::kOmittedWidth);
+ EXPECT_LT(decoration_.GetWidthForSpace(full_width + kEditingSpace),
+ full_width);
+
+ // Omitted when not wide enough to fit even the image.
+ const CGFloat image_width = decoration_.GetWidthForSpace(not_wide_enough);
+ EXPECT_EQ(decoration_.GetWidthForSpace(image_width - 1.0),
+ LocationBarDecoration::kOmittedWidth);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h b/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h
new file mode 100644
index 0000000..5947edc
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h
@@ -0,0 +1,89 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_LOCATION_BAR_LOCATION_BAR_DECORATION_H_
+#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_LOCATION_BAR_DECORATION_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/basictypes.h"
+
+// Base class for decorations at the left and right of the location
+// bar. For instance, the location icon.
+
+// |LocationBarDecoration| and subclasses should approximately
+// parallel the classes provided under views/location_bar/. The term
+// "decoration" is used because "view" has strong connotations in
+// Cocoa, and while these are view-like, they aren't views at all.
+// Decorations are more like Cocoa cells, except implemented in C++ to
+// allow more similarity to the other platform implementations.
+
+class LocationBarDecoration {
+ public:
+ LocationBarDecoration()
+ : visible_(false) {
+ }
+ virtual ~LocationBarDecoration() {}
+
+ // Determines whether the decoration is visible.
+ virtual bool IsVisible() const {
+ return visible_;
+ }
+ virtual void SetVisible(bool visible) {
+ visible_ = visible;
+ }
+
+ // Decorations can change their size to fit the available space.
+ // Returns the width the decoration will use in the space allotted,
+ // or |kOmittedWidth| if it should be omitted.
+ virtual CGFloat GetWidthForSpace(CGFloat width);
+
+ // Draw the decoration in the frame provided. The frame will be
+ // generated from an earlier call to |GetWidthForSpace()|.
+ virtual void DrawInFrame(NSRect frame, NSView* control_view);
+
+ // Returns the tooltip for this decoration, return |nil| for no tooltip.
+ virtual NSString* GetToolTip() { return nil; }
+
+ // Decorations which do not accept mouse events are treated like the
+ // field's background for purposes of selecting text. When such
+ // decorations are adjacent to the text area, they will show the
+ // I-beam cursor. Decorations which do accept mouse events will get
+ // an arrow cursor when the mouse is over them.
+ virtual bool AcceptsMousePress() { return false; }
+
+ // Determine if the item can act as a drag source.
+ virtual bool IsDraggable() { return false; }
+
+ // The image to drag.
+ virtual NSImage* GetDragImage() { return nil; }
+
+ // Return the place within the decoration's frame where the
+ // |GetDragImage()| comes from. This is used to make sure the image
+ // appears correctly under the mouse while dragging. |frame|
+ // matches the frame passed to |DrawInFrame()|.
+ virtual NSRect GetDragImageFrame(NSRect frame) { return NSZeroRect; }
+
+ // The pasteboard to drag.
+ virtual NSPasteboard* GetDragPasteboard() { return nil; }
+
+ // Called on mouse down. Return |false| to indicate that the press
+ // was not processed and should be handled by the cell.
+ virtual bool OnMousePressed(NSRect frame) { return false; }
+
+ // Called to get the right-click menu, return |nil| for no menu.
+ virtual NSMenu* GetMenu() { return nil; }
+
+ // Width returned by |GetWidthForSpace()| when the item should be
+ // omitted for this width;
+ static const CGFloat kOmittedWidth;
+
+ private:
+ bool visible_;
+
+ DISALLOW_COPY_AND_ASSIGN(LocationBarDecoration);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_LOCATION_BAR_DECORATION_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.mm b/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.mm
new file mode 100644
index 0000000..bbd9b0b
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.mm
@@ -0,0 +1,18 @@
+// 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 "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
+
+#include "base/logging.h"
+
+const CGFloat LocationBarDecoration::kOmittedWidth = 0.0;
+
+CGFloat LocationBarDecoration::GetWidthForSpace(CGFloat width) {
+ NOTREACHED();
+ return kOmittedWidth;
+}
+
+void LocationBarDecoration::DrawInFrame(NSRect frame, NSView* control_view) {
+ NOTREACHED();
+}
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h
new file mode 100644
index 0000000..f492aeb
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h
@@ -0,0 +1,238 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_LOCATION_BAR_VIEW_MAC_H_
+#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_VIEW_MAC_H_
+#pragma once
+
+#include <string>
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+#include "base/scoped_vector.h"
+#include "chrome/browser/autocomplete/autocomplete_edit.h"
+#include "chrome/browser/autocomplete/autocomplete_edit_view_mac.h"
+#include "chrome/browser/extensions/image_loading_tracker.h"
+#include "chrome/browser/first_run/first_run.h"
+#include "chrome/browser/ui/omnibox/location_bar.h"
+#include "chrome/browser/ui/toolbar/toolbar_model.h"
+#include "chrome/common/content_settings_types.h"
+
+@class AutocompleteTextField;
+class CommandUpdater;
+class ContentSettingDecoration;
+class ContentSettingImageModel;
+class EVBubbleDecoration;
+@class ExtensionPopupController;
+class KeywordHintDecoration;
+class LocationIconDecoration;
+class PageActionDecoration;
+class Profile;
+class SelectedKeywordDecoration;
+class SkBitmap;
+class StarDecoration;
+class ToolbarModel;
+
+// A C++ bridge class that represents the location bar UI element to
+// the portable code. Wires up an AutocompleteEditViewMac instance to
+// the location bar text field, which handles most of the work.
+
+class LocationBarViewMac : public AutocompleteEditController,
+ public LocationBar,
+ public LocationBarTesting,
+ public NotificationObserver {
+ public:
+ LocationBarViewMac(AutocompleteTextField* field,
+ CommandUpdater* command_updater,
+ ToolbarModel* toolbar_model,
+ Profile* profile,
+ Browser* browser);
+ virtual ~LocationBarViewMac();
+
+ // Overridden from LocationBar:
+ virtual void ShowFirstRunBubble(FirstRun::BubbleType bubble_type);
+ virtual void SetSuggestedText(const string16& text);
+ virtual std::wstring GetInputString() const;
+ virtual WindowOpenDisposition GetWindowOpenDisposition() const;
+ virtual PageTransition::Type GetPageTransition() const;
+ virtual void AcceptInput();
+ virtual void FocusLocation(bool select_all);
+ virtual void FocusSearch();
+ virtual void UpdateContentSettingsIcons();
+ virtual void UpdatePageActions();
+ virtual void InvalidatePageActions();
+ virtual void SaveStateToContents(TabContents* contents);
+ virtual void Revert();
+ virtual const AutocompleteEditView* location_entry() const {
+ return edit_view_.get();
+ }
+ virtual AutocompleteEditView* location_entry() {
+ return edit_view_.get();
+ }
+ virtual LocationBarTesting* GetLocationBarForTesting() { return this; }
+
+ // Overridden from LocationBarTesting:
+ virtual int PageActionCount();
+ virtual int PageActionVisibleCount();
+ virtual ExtensionAction* GetPageAction(size_t index);
+ virtual ExtensionAction* GetVisiblePageAction(size_t index);
+ virtual void TestPageActionPressed(size_t index);
+
+ // Set/Get the editable state of the field.
+ void SetEditable(bool editable);
+ bool IsEditable();
+
+ // Set the starred state of the bookmark star.
+ void SetStarred(bool starred);
+
+ // Get the point on the star for the bookmark bubble to aim at.
+ NSPoint GetBookmarkBubblePoint() const;
+
+ // Get the point in the security icon at which the page info bubble aims.
+ NSPoint GetPageInfoBubblePoint() const;
+
+ // Get the point in the omnibox at which the first run bubble aims.
+ NSPoint GetFirstRunBubblePoint() const;
+
+ // Updates the location bar. Resets the bar's permanent text and
+ // security style, and if |should_restore_state| is true, restores
+ // saved state from the tab (for tab switching).
+ void Update(const TabContents* tab, bool should_restore_state);
+
+ // Layout the various decorations which live in the field.
+ void Layout();
+
+ // Returns the current TabContents.
+ TabContents* GetTabContents() const;
+
+ // Sets preview_enabled_ for the PageActionImageView associated with this
+ // |page_action|. If |preview_enabled|, the location bar will display the
+ // PageAction icon even if it has not been activated by the extension.
+ // This is used by the ExtensionInstalledBubble to preview what the icon
+ // will look like for the user upon installation of the extension.
+ void SetPreviewEnabledPageAction(ExtensionAction* page_action,
+ bool preview_enabled);
+
+ // Return |page_action|'s info-bubble point in window coordinates.
+ // This function should always be called with a visible page action.
+ // If |page_action| is not a page action or not visible, NOTREACHED()
+ // is called and this function returns |NSZeroPoint|.
+ NSPoint GetPageActionBubblePoint(ExtensionAction* page_action);
+
+ // Get the blocked-popup content setting's frame in window
+ // coordinates. Used by the blocked-popup animation. Returns
+ // |NSZeroRect| if the relevant content setting decoration is not
+ // visible.
+ NSRect GetBlockedPopupRect() const;
+
+ // AutocompleteEditController implementation.
+ virtual void OnAutocompleteWillClosePopup();
+ virtual void OnAutocompleteLosingFocus(gfx::NativeView unused);
+ virtual void OnAutocompleteWillAccept();
+ virtual bool OnCommitSuggestedText(const std::wstring& typed_text);
+ virtual bool AcceptCurrentInstantPreview();
+ virtual void OnSetSuggestedSearchText(const string16& suggested_text);
+ virtual void OnPopupBoundsChanged(const gfx::Rect& bounds);
+ virtual void OnAutocompleteAccept(const GURL& url,
+ WindowOpenDisposition disposition,
+ PageTransition::Type transition,
+ const GURL& alternate_nav_url);
+ virtual void OnChanged();
+ virtual void OnSelectionBoundsChanged();
+ virtual void OnInputInProgress(bool in_progress);
+ virtual void OnKillFocus();
+ virtual void OnSetFocus();
+ virtual SkBitmap GetFavIcon() const;
+ virtual std::wstring GetTitle() const;
+
+ NSImage* GetKeywordImage(const std::wstring& keyword);
+
+ AutocompleteTextField* GetAutocompleteTextField() { return field_; }
+
+
+ // Overridden from NotificationObserver.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ private:
+ // Posts |notification| to the default notification center.
+ void PostNotification(NSString* notification);
+
+ // Return the decoration for |page_action|.
+ PageActionDecoration* GetPageActionDecoration(ExtensionAction* page_action);
+
+ // Clear the page-action decorations.
+ void DeletePageActionDecorations();
+
+ // Re-generate the page-action decorations from the profile's
+ // extension service.
+ void RefreshPageActionDecorations();
+
+ // Updates visibility of the content settings icons based on the current
+ // tab contents state.
+ bool RefreshContentSettingsDecorations();
+
+ void ShowFirstRunBubbleInternal(FirstRun::BubbleType bubble_type);
+
+ scoped_ptr<AutocompleteEditViewMac> edit_view_;
+
+ CommandUpdater* command_updater_; // Weak, owned by Browser.
+
+ AutocompleteTextField* field_; // owned by tab controller
+
+ // When we get an OnAutocompleteAccept notification from the autocomplete
+ // edit, we save the input string so we can give it back to the browser on
+ // the LocationBar interface via GetInputString().
+ std::wstring location_input_;
+
+ // The user's desired disposition for how their input should be opened.
+ WindowOpenDisposition disposition_;
+
+ // A decoration that shows an icon to the left of the address.
+ scoped_ptr<LocationIconDecoration> location_icon_decoration_;
+
+ // A decoration that shows the keyword-search bubble on the left.
+ scoped_ptr<SelectedKeywordDecoration> selected_keyword_decoration_;
+
+ // A decoration that shows a lock icon and ev-cert label in a bubble
+ // on the left.
+ scoped_ptr<EVBubbleDecoration> ev_bubble_decoration_;
+
+ // Bookmark star right of page actions.
+ scoped_ptr<StarDecoration> star_decoration_;
+
+ // Any installed Page Actions.
+ ScopedVector<PageActionDecoration> page_action_decorations_;
+
+ // The content blocked decorations.
+ ScopedVector<ContentSettingDecoration> content_setting_decorations_;
+
+ // Keyword hint decoration displayed on the right-hand side.
+ scoped_ptr<KeywordHintDecoration> keyword_hint_decoration_;
+
+ Profile* profile_;
+
+ Browser* browser_;
+
+ ToolbarModel* toolbar_model_; // Weak, owned by Browser.
+
+ // Whether or not to update the instant preview.
+ bool update_instant_;
+
+ // The transition type to use for the navigation.
+ PageTransition::Type transition_;
+
+ // Used to register for notifications received by NotificationObserver.
+ NotificationRegistrar registrar_;
+
+ // Used to schedule a task for the first run info bubble.
+ ScopedRunnableMethodFactory<LocationBarViewMac> first_run_bubble_;
+
+ DISALLOW_COPY_AND_ASSIGN(LocationBarViewMac);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_VIEW_MAC_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
new file mode 100644
index 0000000..d433822
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
@@ -0,0 +1,695 @@
+// 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 "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
+
+#include "app/l10n_util_mac.h"
+#include "app/resource_bundle.h"
+#include "base/stl_util-inl.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/alternate_nav_url_fetcher.h"
+#import "chrome/browser/app_controller_mac.h"
+#import "chrome/browser/autocomplete/autocomplete_edit_view_mac.h"
+#import "chrome/browser/autocomplete/autocomplete_popup_model.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/command_updater.h"
+#include "chrome/browser/content_setting_image_model.h"
+#include "chrome/browser/content_setting_bubble_model.h"
+#include "chrome/browser/defaults.h"
+#include "chrome/browser/extensions/extension_browser_event_router.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_tabs_module.h"
+#include "chrome/browser/instant/instant_controller.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/tab_contents/navigation_entry.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#import "chrome/browser/ui/cocoa/content_setting_bubble_cocoa.h"
+#include "chrome/browser/ui/cocoa/event_utils.h"
+#import "chrome/browser/ui/cocoa/extensions/extension_action_context_menu.h"
+#import "chrome/browser/ui/cocoa/extensions/extension_popup_controller.h"
+#import "chrome/browser/ui/cocoa/first_run_bubble_controller.h"
+#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
+#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
+#import "chrome/browser/ui/cocoa/location_bar/content_setting_decoration.h"
+#import "chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration.h"
+#import "chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.h"
+#import "chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h"
+#import "chrome/browser/ui/cocoa/location_bar/page_action_decoration.h"
+#import "chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.h"
+#import "chrome/browser/ui/cocoa/location_bar/star_decoration.h"
+#include "chrome/browser/ui/omnibox/location_bar_util.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_action.h"
+#include "chrome/common/extensions/extension_resource.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/pref_names.h"
+#include "net/base/net_util.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "skia/ext/skia_utils_mac.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace {
+
+// Vertical space between the bottom edge of the location_bar and the first run
+// bubble arrow point.
+const static int kFirstRunBubbleYOffset = 1;
+
+}
+
+// TODO(shess): This code is mostly copied from the gtk
+// implementation. Make sure it's all appropriate and flesh it out.
+
+LocationBarViewMac::LocationBarViewMac(
+ AutocompleteTextField* field,
+ CommandUpdater* command_updater,
+ ToolbarModel* toolbar_model,
+ Profile* profile,
+ Browser* browser)
+ : edit_view_(new AutocompleteEditViewMac(this, toolbar_model, profile,
+ command_updater, field)),
+ command_updater_(command_updater),
+ field_(field),
+ disposition_(CURRENT_TAB),
+ location_icon_decoration_(new LocationIconDecoration(this)),
+ selected_keyword_decoration_(
+ new SelectedKeywordDecoration(
+ AutocompleteEditViewMac::GetFieldFont())),
+ ev_bubble_decoration_(
+ new EVBubbleDecoration(location_icon_decoration_.get(),
+ AutocompleteEditViewMac::GetFieldFont())),
+ star_decoration_(new StarDecoration(command_updater)),
+ keyword_hint_decoration_(
+ new KeywordHintDecoration(AutocompleteEditViewMac::GetFieldFont())),
+ profile_(profile),
+ browser_(browser),
+ toolbar_model_(toolbar_model),
+ update_instant_(true),
+ transition_(PageTransition::TYPED),
+ first_run_bubble_(this) {
+ for (size_t i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
+ DCHECK_EQ(i, content_setting_decorations_.size());
+ ContentSettingsType type = static_cast<ContentSettingsType>(i);
+ content_setting_decorations_.push_back(
+ new ContentSettingDecoration(type, this, profile_));
+ }
+
+ registrar_.Add(this,
+ NotificationType::EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED,
+ NotificationService::AllSources());
+}
+
+LocationBarViewMac::~LocationBarViewMac() {
+ // Disconnect from cell in case it outlives us.
+ [[field_ cell] clearDecorations];
+}
+
+void LocationBarViewMac::ShowFirstRunBubble(FirstRun::BubbleType bubble_type) {
+ // We need the browser window to be shown before we can show the bubble, but
+ // we get called before that's happened.
+ Task* task = first_run_bubble_.NewRunnableMethod(
+ &LocationBarViewMac::ShowFirstRunBubbleInternal, bubble_type);
+ MessageLoop::current()->PostTask(FROM_HERE, task);
+}
+
+void LocationBarViewMac::ShowFirstRunBubbleInternal(
+ FirstRun::BubbleType bubble_type) {
+ if (!field_ || ![field_ window])
+ return;
+
+ // The first run bubble's left edge should line up with the left edge of the
+ // omnibox. This is different from other bubbles, which line up at a point
+ // set by their top arrow. Because the BaseBubbleController adjusts the
+ // window origin left to account for the arrow spacing, the first run bubble
+ // moves the window origin right by this spacing, so that the
+ // BaseBubbleController will move it back to the correct position.
+ const NSPoint kOffset = NSMakePoint(
+ info_bubble::kBubbleArrowXOffset + info_bubble::kBubbleArrowWidth/2.0,
+ kFirstRunBubbleYOffset);
+ [FirstRunBubbleController showForView:field_ offset:kOffset profile:profile_];
+}
+
+std::wstring LocationBarViewMac::GetInputString() const {
+ return location_input_;
+}
+
+void LocationBarViewMac::SetSuggestedText(const string16& text) {
+ edit_view_->SetSuggestText(
+ edit_view_->model()->UseVerbatimInstant() ? string16() : text);
+}
+
+WindowOpenDisposition LocationBarViewMac::GetWindowOpenDisposition() const {
+ return disposition_;
+}
+
+PageTransition::Type LocationBarViewMac::GetPageTransition() const {
+ return transition_;
+}
+
+void LocationBarViewMac::AcceptInput() {
+ WindowOpenDisposition disposition =
+ event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
+ edit_view_->model()->AcceptInput(disposition, false);
+}
+
+void LocationBarViewMac::FocusLocation(bool select_all) {
+ edit_view_->FocusLocation(select_all);
+}
+
+void LocationBarViewMac::FocusSearch() {
+ edit_view_->SetForcedQuery();
+}
+
+void LocationBarViewMac::UpdateContentSettingsIcons() {
+ if (RefreshContentSettingsDecorations()) {
+ [field_ updateCursorAndToolTipRects];
+ [field_ setNeedsDisplay:YES];
+ }
+}
+
+void LocationBarViewMac::UpdatePageActions() {
+ size_t count_before = page_action_decorations_.size();
+ RefreshPageActionDecorations();
+ Layout();
+ if (page_action_decorations_.size() != count_before) {
+ NotificationService::current()->Notify(
+ NotificationType::EXTENSION_PAGE_ACTION_COUNT_CHANGED,
+ Source<LocationBar>(this),
+ NotificationService::NoDetails());
+ }
+}
+
+void LocationBarViewMac::InvalidatePageActions() {
+ size_t count_before = page_action_decorations_.size();
+ DeletePageActionDecorations();
+ Layout();
+ if (page_action_decorations_.size() != count_before) {
+ NotificationService::current()->Notify(
+ NotificationType::EXTENSION_PAGE_ACTION_COUNT_CHANGED,
+ Source<LocationBar>(this),
+ NotificationService::NoDetails());
+ }
+}
+
+void LocationBarViewMac::SaveStateToContents(TabContents* contents) {
+ // TODO(shess): Why SaveStateToContents vs SaveStateToTab?
+ edit_view_->SaveStateToTab(contents);
+}
+
+void LocationBarViewMac::Update(const TabContents* contents,
+ bool should_restore_state) {
+ bool star_enabled = browser_defaults::bookmarks_enabled &&
+ [field_ isEditable] && !toolbar_model_->input_in_progress();
+ command_updater_->UpdateCommandEnabled(IDC_BOOKMARK_PAGE, star_enabled);
+ star_decoration_->SetVisible(star_enabled);
+ RefreshPageActionDecorations();
+ RefreshContentSettingsDecorations();
+ // AutocompleteEditView restores state if the tab is non-NULL.
+ edit_view_->Update(should_restore_state ? contents : NULL);
+ OnChanged();
+}
+
+void LocationBarViewMac::OnAutocompleteWillClosePopup() {
+ if (!update_instant_)
+ return;
+
+ InstantController* controller = browser_->instant();
+ if (controller && !controller->commit_on_mouse_up())
+ controller->DestroyPreviewContents();
+ SetSuggestedText(string16());
+}
+
+void LocationBarViewMac::OnAutocompleteLosingFocus(gfx::NativeView unused) {
+ SetSuggestedText(string16());
+
+ InstantController* instant = browser_->instant();
+ if (!instant)
+ return;
+
+ // If |IsMouseDownFromActivate()| returns false, the RenderWidgetHostView did
+ // not receive a mouseDown event. Therefore, we should destroy the preview.
+ // Otherwise, the RWHV was clicked, so we commit the preview.
+ if (!instant->is_displayable() || !instant->GetPreviewContents() ||
+ !instant->IsMouseDownFromActivate()) {
+ instant->DestroyPreviewContents();
+ } else if (instant->IsShowingInstant()) {
+ instant->SetCommitOnMouseUp();
+ } else {
+ instant->CommitCurrentPreview(INSTANT_COMMIT_FOCUS_LOST);
+ }
+}
+
+void LocationBarViewMac::OnAutocompleteWillAccept() {
+ update_instant_ = false;
+}
+
+bool LocationBarViewMac::OnCommitSuggestedText(const std::wstring& typed_text) {
+ return edit_view_->CommitSuggestText();
+}
+
+bool LocationBarViewMac::AcceptCurrentInstantPreview() {
+ return InstantController::CommitIfCurrent(browser_->instant());
+}
+
+void LocationBarViewMac::OnSetSuggestedSearchText(
+ const string16& suggested_text) {
+ SetSuggestedText(suggested_text);
+}
+
+void LocationBarViewMac::OnPopupBoundsChanged(const gfx::Rect& bounds) {
+ InstantController* instant = browser_->instant();
+ if (instant)
+ instant->SetOmniboxBounds(bounds);
+}
+
+void LocationBarViewMac::OnAutocompleteAccept(const GURL& url,
+ WindowOpenDisposition disposition,
+ PageTransition::Type transition,
+ const GURL& alternate_nav_url) {
+ // WARNING: don't add an early return here. The calls after the if must
+ // happen.
+ if (url.is_valid()) {
+ location_input_ = UTF8ToWide(url.spec());
+ disposition_ = disposition;
+ transition_ = transition;
+
+ if (command_updater_) {
+ if (!alternate_nav_url.is_valid()) {
+ command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL);
+ } else {
+ AlternateNavURLFetcher* fetcher =
+ new AlternateNavURLFetcher(alternate_nav_url);
+ // The AlternateNavURLFetcher will listen for the pending navigation
+ // notification that will be issued as a result of the "open URL." It
+ // will automatically install itself into that navigation controller.
+ command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL);
+ if (fetcher->state() == AlternateNavURLFetcher::NOT_STARTED) {
+ // I'm not sure this should be reachable, but I'm not also sure enough
+ // that it shouldn't to stick in a NOTREACHED(). In any case, this is
+ // harmless.
+ delete fetcher;
+ } else {
+ // The navigation controller will delete the fetcher.
+ }
+ }
+ }
+ }
+
+ if (browser_->instant())
+ browser_->instant()->DestroyPreviewContents();
+
+ update_instant_ = true;
+}
+
+void LocationBarViewMac::OnChanged() {
+ // Update the location-bar icon.
+ const int resource_id = edit_view_->GetIcon();
+ NSImage* image = AutocompleteEditViewMac::ImageForResource(resource_id);
+ location_icon_decoration_->SetImage(image);
+ ev_bubble_decoration_->SetImage(image);
+ Layout();
+
+ InstantController* instant = browser_->instant();
+ string16 suggested_text;
+ if (update_instant_ && instant && GetTabContents()) {
+ if (edit_view_->model()->user_input_in_progress() &&
+ edit_view_->model()->popup_model()->IsOpen()) {
+ instant->Update
+ (browser_->GetSelectedTabContentsWrapper(),
+ edit_view_->model()->CurrentMatch(),
+ WideToUTF16(edit_view_->GetText()),
+ edit_view_->model()->UseVerbatimInstant(),
+ &suggested_text);
+ if (!instant->MightSupportInstant()) {
+ edit_view_->model()->FinalizeInstantQuery(std::wstring(),
+ std::wstring());
+ }
+ } else {
+ instant->DestroyPreviewContents();
+ edit_view_->model()->FinalizeInstantQuery(std::wstring(),
+ std::wstring());
+ }
+ }
+
+ SetSuggestedText(suggested_text);
+}
+
+void LocationBarViewMac::OnSelectionBoundsChanged() {
+ NOTIMPLEMENTED();
+}
+
+void LocationBarViewMac::OnInputInProgress(bool in_progress) {
+ toolbar_model_->set_input_in_progress(in_progress);
+ Update(NULL, false);
+}
+
+void LocationBarViewMac::OnSetFocus() {
+ // Update the keyword and search hint states.
+ OnChanged();
+}
+
+void LocationBarViewMac::OnKillFocus() {
+ // Do nothing.
+}
+
+SkBitmap LocationBarViewMac::GetFavIcon() const {
+ NOTIMPLEMENTED();
+ return SkBitmap();
+}
+
+std::wstring LocationBarViewMac::GetTitle() const {
+ NOTIMPLEMENTED();
+ return std::wstring();
+}
+
+void LocationBarViewMac::Revert() {
+ edit_view_->RevertAll();
+}
+
+// TODO(pamg): Change all these, here and for other platforms, to size_t.
+int LocationBarViewMac::PageActionCount() {
+ return static_cast<int>(page_action_decorations_.size());
+}
+
+int LocationBarViewMac::PageActionVisibleCount() {
+ int result = 0;
+ for (size_t i = 0; i < page_action_decorations_.size(); ++i) {
+ if (page_action_decorations_[i]->IsVisible())
+ ++result;
+ }
+ return result;
+}
+
+TabContents* LocationBarViewMac::GetTabContents() const {
+ return browser_->GetSelectedTabContents();
+}
+
+PageActionDecoration* LocationBarViewMac::GetPageActionDecoration(
+ ExtensionAction* page_action) {
+ DCHECK(page_action);
+ for (size_t i = 0; i < page_action_decorations_.size(); ++i) {
+ if (page_action_decorations_[i]->page_action() == page_action)
+ return page_action_decorations_[i];
+ }
+ // If |page_action| is the browser action of an extension, no element in
+ // |page_action_decorations_| will match.
+ NOTREACHED();
+ return NULL;
+}
+
+void LocationBarViewMac::SetPreviewEnabledPageAction(
+ ExtensionAction* page_action, bool preview_enabled) {
+ DCHECK(page_action);
+ TabContents* contents = GetTabContents();
+ if (!contents)
+ return;
+ RefreshPageActionDecorations();
+ Layout();
+
+ PageActionDecoration* decoration = GetPageActionDecoration(page_action);
+ DCHECK(decoration);
+ if (!decoration)
+ return;
+
+ decoration->set_preview_enabled(preview_enabled);
+ decoration->UpdateVisibility(contents,
+ GURL(WideToUTF8(toolbar_model_->GetText())));
+}
+
+NSPoint LocationBarViewMac::GetPageActionBubblePoint(
+ ExtensionAction* page_action) {
+ PageActionDecoration* decoration = GetPageActionDecoration(page_action);
+ if (!decoration)
+ return NSZeroPoint;
+
+ AutocompleteTextFieldCell* cell = [field_ cell];
+ NSRect frame = [cell frameForDecoration:decoration inFrame:[field_ bounds]];
+ DCHECK(!NSIsEmptyRect(frame));
+ if (NSIsEmptyRect(frame))
+ return NSZeroPoint;
+
+ NSPoint bubble_point = decoration->GetBubblePointInFrame(frame);
+ return [field_ convertPoint:bubble_point toView:nil];
+}
+
+NSRect LocationBarViewMac::GetBlockedPopupRect() const {
+ const size_t kPopupIndex = CONTENT_SETTINGS_TYPE_POPUPS;
+ const LocationBarDecoration* decoration =
+ content_setting_decorations_[kPopupIndex];
+ if (!decoration || !decoration->IsVisible())
+ return NSZeroRect;
+
+ AutocompleteTextFieldCell* cell = [field_ cell];
+ const NSRect frame = [cell frameForDecoration:decoration
+ inFrame:[field_ bounds]];
+ return [field_ convertRect:frame toView:nil];
+}
+
+ExtensionAction* LocationBarViewMac::GetPageAction(size_t index) {
+ if (index < page_action_decorations_.size())
+ return page_action_decorations_[index]->page_action();
+ NOTREACHED();
+ return NULL;
+}
+
+ExtensionAction* LocationBarViewMac::GetVisiblePageAction(size_t index) {
+ size_t current = 0;
+ for (size_t i = 0; i < page_action_decorations_.size(); ++i) {
+ if (page_action_decorations_[i]->IsVisible()) {
+ if (current == index)
+ return page_action_decorations_[i]->page_action();
+
+ ++current;
+ }
+ }
+
+ NOTREACHED();
+ return NULL;
+}
+
+void LocationBarViewMac::TestPageActionPressed(size_t index) {
+ DCHECK_LT(index, page_action_decorations_.size());
+ if (index < page_action_decorations_.size())
+ page_action_decorations_[index]->OnMousePressed(NSZeroRect);
+}
+
+void LocationBarViewMac::SetEditable(bool editable) {
+ [field_ setEditable:editable ? YES : NO];
+ star_decoration_->SetVisible(browser_defaults::bookmarks_enabled &&
+ editable && !toolbar_model_->input_in_progress());
+ UpdatePageActions();
+ Layout();
+}
+
+bool LocationBarViewMac::IsEditable() {
+ return [field_ isEditable] ? true : false;
+}
+
+void LocationBarViewMac::SetStarred(bool starred) {
+ star_decoration_->SetStarred(starred);
+
+ // TODO(shess): The field-editor frame and cursor rects should not
+ // change, here.
+ [field_ updateCursorAndToolTipRects];
+ [field_ resetFieldEditorFrameIfNeeded];
+ [field_ setNeedsDisplay:YES];
+}
+
+NSPoint LocationBarViewMac::GetBookmarkBubblePoint() const {
+ AutocompleteTextFieldCell* cell = [field_ cell];
+ const NSRect frame = [cell frameForDecoration:star_decoration_.get()
+ inFrame:[field_ bounds]];
+ const NSPoint point = star_decoration_->GetBubblePointInFrame(frame);
+ return [field_ convertPoint:point toView:nil];
+}
+
+NSPoint LocationBarViewMac::GetPageInfoBubblePoint() const {
+ AutocompleteTextFieldCell* cell = [field_ cell];
+ if (ev_bubble_decoration_->IsVisible()) {
+ const NSRect frame = [cell frameForDecoration:ev_bubble_decoration_.get()
+ inFrame:[field_ bounds]];
+ const NSPoint point = ev_bubble_decoration_->GetBubblePointInFrame(frame);
+ return [field_ convertPoint:point toView:nil];
+ } else {
+ const NSRect frame =
+ [cell frameForDecoration:location_icon_decoration_.get()
+ inFrame:[field_ bounds]];
+ const NSPoint point =
+ location_icon_decoration_->GetBubblePointInFrame(frame);
+ return [field_ convertPoint:point toView:nil];
+ }
+}
+
+NSImage* LocationBarViewMac::GetKeywordImage(const std::wstring& keyword) {
+ const TemplateURL* template_url =
+ profile_->GetTemplateURLModel()->GetTemplateURLForKeyword(keyword);
+ if (template_url && template_url->IsExtensionKeyword()) {
+ const SkBitmap& bitmap = profile_->GetExtensionService()->
+ GetOmniboxIcon(template_url->GetExtensionId());
+ return gfx::SkBitmapToNSImage(bitmap);
+ }
+
+ return AutocompleteEditViewMac::ImageForResource(IDR_OMNIBOX_SEARCH);
+}
+
+void LocationBarViewMac::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ switch (type.value) {
+ case NotificationType::EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED: {
+ TabContents* contents = GetTabContents();
+ if (Details<TabContents>(contents) != details)
+ return;
+
+ [field_ updateCursorAndToolTipRects];
+ [field_ setNeedsDisplay:YES];
+ break;
+ }
+ default:
+ NOTREACHED() << "Unexpected notification";
+ break;
+ }
+}
+
+void LocationBarViewMac::PostNotification(NSString* notification) {
+ [[NSNotificationCenter defaultCenter] postNotificationName:notification
+ object:[NSValue valueWithPointer:this]];
+}
+
+bool LocationBarViewMac::RefreshContentSettingsDecorations() {
+ const bool input_in_progress = toolbar_model_->input_in_progress();
+ TabContents* tab_contents =
+ input_in_progress ? NULL : browser_->GetSelectedTabContents();
+ bool icons_updated = false;
+ for (size_t i = 0; i < content_setting_decorations_.size(); ++i) {
+ icons_updated |=
+ content_setting_decorations_[i]->UpdateFromTabContents(tab_contents);
+ }
+ return icons_updated;
+}
+
+void LocationBarViewMac::DeletePageActionDecorations() {
+ // TODO(shess): Deleting these decorations could result in the cell
+ // refering to them before things are laid out again. Meanwhile, at
+ // least fail safe.
+ [[field_ cell] clearDecorations];
+
+ page_action_decorations_.reset();
+}
+
+void LocationBarViewMac::RefreshPageActionDecorations() {
+ if (!IsEditable()) {
+ DeletePageActionDecorations();
+ return;
+ }
+
+ ExtensionService* service = profile_->GetExtensionService();
+ if (!service)
+ return;
+
+ std::vector<ExtensionAction*> page_actions;
+ for (size_t i = 0; i < service->extensions()->size(); ++i) {
+ if (service->extensions()->at(i)->page_action())
+ page_actions.push_back(service->extensions()->at(i)->page_action());
+ }
+
+ // On startup we sometimes haven't loaded any extensions. This makes sure
+ // we catch up when the extensions (and any Page Actions) load.
+ if (page_actions.size() != page_action_decorations_.size()) {
+ DeletePageActionDecorations(); // Delete the old views (if any).
+
+ for (size_t i = 0; i < page_actions.size(); ++i) {
+ page_action_decorations_.push_back(
+ new PageActionDecoration(this, profile_, page_actions[i]));
+ }
+ }
+
+ if (page_action_decorations_.empty())
+ return;
+
+ TabContents* contents = GetTabContents();
+ if (!contents)
+ return;
+
+ GURL url = GURL(WideToUTF8(toolbar_model_->GetText()));
+ for (size_t i = 0; i < page_action_decorations_.size(); ++i) {
+ page_action_decorations_[i]->UpdateVisibility(
+ toolbar_model_->input_in_progress() ? NULL : contents, url);
+ }
+}
+
+// TODO(shess): This function should over time grow to closely match
+// the views Layout() function.
+void LocationBarViewMac::Layout() {
+ AutocompleteTextFieldCell* cell = [field_ cell];
+
+ // Reset the left-hand decorations.
+ // TODO(shess): Shortly, this code will live somewhere else, like in
+ // the constructor. I am still wrestling with how best to deal with
+ // right-hand decorations, which are not a static set.
+ [cell clearDecorations];
+ [cell addLeftDecoration:location_icon_decoration_.get()];
+ [cell addLeftDecoration:selected_keyword_decoration_.get()];
+ [cell addLeftDecoration:ev_bubble_decoration_.get()];
+ [cell addRightDecoration:star_decoration_.get()];
+
+ // Note that display order is right to left.
+ for (size_t i = 0; i < page_action_decorations_.size(); ++i) {
+ [cell addRightDecoration:page_action_decorations_[i]];
+ }
+ for (size_t i = 0; i < content_setting_decorations_.size(); ++i) {
+ [cell addRightDecoration:content_setting_decorations_[i]];
+ }
+
+ [cell addRightDecoration:keyword_hint_decoration_.get()];
+
+ // By default only the location icon is visible.
+ location_icon_decoration_->SetVisible(true);
+ selected_keyword_decoration_->SetVisible(false);
+ ev_bubble_decoration_->SetVisible(false);
+ keyword_hint_decoration_->SetVisible(false);
+
+ // Get the keyword to use for keyword-search and hinting.
+ const std::wstring keyword(edit_view_->model()->keyword());
+ std::wstring short_name;
+ bool is_extension_keyword = false;
+ if (!keyword.empty()) {
+ short_name = profile_->GetTemplateURLModel()->
+ GetKeywordShortName(keyword, &is_extension_keyword);
+ }
+
+ const bool is_keyword_hint = edit_view_->model()->is_keyword_hint();
+
+ if (!keyword.empty() && !is_keyword_hint) {
+ // Switch from location icon to keyword mode.
+ location_icon_decoration_->SetVisible(false);
+ selected_keyword_decoration_->SetVisible(true);
+ selected_keyword_decoration_->SetKeyword(short_name, is_extension_keyword);
+ selected_keyword_decoration_->SetImage(GetKeywordImage(keyword));
+ } else if (toolbar_model_->GetSecurityLevel() == ToolbarModel::EV_SECURE) {
+ // Switch from location icon to show the EV bubble instead.
+ location_icon_decoration_->SetVisible(false);
+ ev_bubble_decoration_->SetVisible(true);
+
+ std::wstring label(toolbar_model_->GetEVCertName());
+ ev_bubble_decoration_->SetFullLabel(base::SysWideToNSString(label));
+ } else if (!keyword.empty() && is_keyword_hint) {
+ keyword_hint_decoration_->SetKeyword(short_name, is_extension_keyword);
+ keyword_hint_decoration_->SetVisible(true);
+ }
+
+ // These need to change anytime the layout changes.
+ // TODO(shess): Anytime the field editor might have changed, the
+ // cursor rects almost certainly should have changed. The tooltips
+ // might change even when the rects don't change.
+ [field_ resetFieldEditorFrameIfNeeded];
+ [field_ updateCursorAndToolTipRects];
+
+ [field_ setNeedsDisplay:YES];
+}
diff --git a/chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h b/chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h
new file mode 100644
index 0000000..920d4d3
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h
@@ -0,0 +1,46 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_LOCATION_BAR_LOCATION_ICON_DECORATION_H_
+#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_LOCATION_ICON_DECORATION_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "chrome/browser/ui/cocoa/location_bar/image_decoration.h"
+
+class LocationBarViewMac;
+
+// LocationIconDecoration is used to display an icon to the left of
+// the address.
+
+class LocationIconDecoration : public ImageDecoration {
+ public:
+ explicit LocationIconDecoration(LocationBarViewMac* owner);
+ virtual ~LocationIconDecoration();
+
+ // Allow dragging the current URL.
+ virtual bool IsDraggable();
+ virtual NSPasteboard* GetDragPasteboard();
+ virtual NSImage* GetDragImage() { return GetImage(); }
+ virtual NSRect GetDragImageFrame(NSRect frame) {
+ return GetDrawRectInFrame(frame);
+ }
+
+ // Get the point where the page info bubble should point within the
+ // decoration's frame, in the |owner_|'s coordinates.
+ NSPoint GetBubblePointInFrame(NSRect frame);
+
+ // Show the page info panel on click.
+ virtual bool OnMousePressed(NSRect frame);
+ virtual bool AcceptsMousePress() { return true; }
+
+ private:
+ // The location bar view that owns us.
+ LocationBarViewMac* owner_;
+
+ DISALLOW_COPY_AND_ASSIGN(LocationIconDecoration);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_LOCATION_ICON_DECORATION_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/location_icon_decoration.mm b/chrome/browser/ui/cocoa/location_bar/location_icon_decoration.mm
new file mode 100644
index 0000000..808a45f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/location_icon_decoration.mm
@@ -0,0 +1,72 @@
+// 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.
+
+#include <cmath>
+
+#import "chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h"
+
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
+#import "third_party/mozilla/NSPasteboard+Utils.h"
+
+// The info-bubble point should look like it points to the bottom of the lock
+// icon. Determined with Pixie.app.
+const CGFloat kBubblePointYOffset = 2.0;
+
+LocationIconDecoration::LocationIconDecoration(LocationBarViewMac* owner)
+ : owner_(owner) {
+}
+LocationIconDecoration::~LocationIconDecoration() {
+}
+
+bool LocationIconDecoration::IsDraggable() {
+ // Without a tab it will be impossible to get the information needed
+ // to perform a drag.
+ if (!owner_->GetTabContents())
+ return false;
+
+ // Do not drag if the user has been editing the location bar, or the
+ // location bar is at the NTP.
+ if (owner_->location_entry()->IsEditingOrEmpty())
+ return false;
+
+ return true;
+}
+
+NSPasteboard* LocationIconDecoration::GetDragPasteboard() {
+ TabContents* tab = owner_->GetTabContents();
+ DCHECK(tab); // See |IsDraggable()|.
+
+ NSString* url = base::SysUTF8ToNSString(tab->GetURL().spec());
+ NSString* title = base::SysUTF16ToNSString(tab->GetTitle());
+
+ NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
+ [pboard declareURLPasteboardWithAdditionalTypes:[NSArray array]
+ owner:nil];
+ [pboard setDataForURL:url title:title];
+ return pboard;
+}
+
+NSPoint LocationIconDecoration::GetBubblePointInFrame(NSRect frame) {
+ const NSRect draw_frame = GetDrawRectInFrame(frame);
+ return NSMakePoint(NSMidX(draw_frame),
+ NSMaxY(draw_frame) - kBubblePointYOffset);
+}
+
+bool LocationIconDecoration::OnMousePressed(NSRect frame) {
+ // Do not show page info if the user has been editing the location
+ // bar, or the location bar is at the NTP.
+ if (owner_->location_entry()->IsEditingOrEmpty())
+ return true;
+
+ TabContents* tab = owner_->GetTabContents();
+ NavigationEntry* nav_entry = tab->controller().GetActiveEntry();
+ if (!nav_entry) {
+ NOTREACHED();
+ return true;
+ }
+ tab->ShowPageInfo(nav_entry->url(), nav_entry->ssl(), true);
+ return true;
+}
diff --git a/chrome/browser/ui/cocoa/location_bar/omnibox_popup_view.h b/chrome/browser/ui/cocoa/location_bar/omnibox_popup_view.h
new file mode 100644
index 0000000..c549a49
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/omnibox_popup_view.h
@@ -0,0 +1,17 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_LOCATION_BAR_OMNIBOX_POPUP_VIEW_H_
+#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_OMNIBOX_POPUP_VIEW_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+// The content view for the omnibox popup. Supports up to two subviews (the
+// AutocompleteMatrix containing autocomplete results and (optionally) an
+// InstantOptInView.
+@interface OmniboxPopupView : NSView
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_OMNIBOX_POPUP_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/omnibox_popup_view.mm b/chrome/browser/ui/cocoa/location_bar/omnibox_popup_view.mm
new file mode 100644
index 0000000..ef479e1
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/omnibox_popup_view.mm
@@ -0,0 +1,43 @@
+// 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 "chrome/browser/ui/cocoa/location_bar/omnibox_popup_view.h"
+
+#include "base/logging.h"
+
+@implementation OmniboxPopupView
+
+// If there is only one subview, it is sized to fill all available space. If
+// there are two subviews, the second subview is placed at the bottom of the
+// view, and the first subview is sized to fill all remaining space.
+- (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize {
+ NSArray* subviews = [self subviews];
+ if ([subviews count] == 0)
+ return;
+
+ DCHECK_LE([subviews count], 2U);
+
+ NSRect availableSpace = [self bounds];
+
+ if ([subviews count] >= 2) {
+ NSView* instantView = [subviews objectAtIndex:1];
+ CGFloat height = NSHeight([instantView frame]);
+ NSRect instantFrame = availableSpace;
+ instantFrame.size.height = height;
+
+ availableSpace.origin.y = height;
+ availableSpace.size.height -= height;
+ [instantView setFrame:instantFrame];
+ }
+
+ if ([subviews count] >= 1) {
+ NSView* matrixView = [subviews objectAtIndex:0];
+ if (NSHeight(availableSpace) < 0)
+ availableSpace.size.height = 0;
+
+ [matrixView setFrame:availableSpace];
+ }
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/location_bar/omnibox_popup_view_unittest.mm b/chrome/browser/ui/cocoa/location_bar/omnibox_popup_view_unittest.mm
new file mode 100644
index 0000000..ac4be55
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/omnibox_popup_view_unittest.mm
@@ -0,0 +1,68 @@
+// 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 "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/location_bar/omnibox_popup_view.h"
+
+namespace {
+
+class OmniboxPopupViewTest : public CocoaTest {
+ public:
+ OmniboxPopupViewTest() {
+ NSRect content_frame = [[test_window() contentView] frame];
+ scoped_nsobject<OmniboxPopupView> view(
+ [[OmniboxPopupView alloc] initWithFrame:content_frame]);
+ view_ = view.get();
+ [[test_window() contentView] addSubview:view_];
+ }
+
+ OmniboxPopupView* view_; // Weak. Owned by the view hierarchy.
+};
+
+// Tests display, add/remove.
+TEST_VIEW(OmniboxPopupViewTest, view_);
+
+// A single subview should completely fill the popup view.
+TEST_F(OmniboxPopupViewTest, ResizeWithOneSubview) {
+ scoped_nsobject<NSView> subview1([[NSView alloc] initWithFrame:NSZeroRect]);
+
+ // Adding the subview should not change its frame.
+ [view_ addSubview:subview1];
+ EXPECT_TRUE(NSEqualRects(NSZeroRect, [subview1 frame]));
+
+ // Resizing the popup view should also resize the subview.
+ [view_ setFrame:NSMakeRect(0, 0, 100, 100)];
+ EXPECT_TRUE(NSEqualRects([view_ bounds], [subview1 frame]));
+}
+
+TEST_F(OmniboxPopupViewTest, ResizeWithTwoSubviews) {
+ const CGFloat height = 50;
+ NSRect initial = NSMakeRect(0, 0, 100, height);
+
+ scoped_nsobject<NSView> subview1([[NSView alloc] initWithFrame:NSZeroRect]);
+ scoped_nsobject<NSView> subview2([[NSView alloc] initWithFrame:initial]);
+ [view_ addSubview:subview1];
+ [view_ addSubview:subview2];
+
+ // Resize the popup view to be much larger than height. |subview2|'s height
+ // should stay the same, and |subview1| should resize to fill all available
+ // space.
+ [view_ setFrame:NSMakeRect(0, 0, 300, 4 * height)];
+ EXPECT_EQ(NSWidth([view_ frame]), NSWidth([subview1 frame]));
+ EXPECT_EQ(NSWidth([view_ frame]), NSWidth([subview2 frame]));
+ EXPECT_EQ(height, NSHeight([subview2 frame]));
+ EXPECT_EQ(NSHeight([view_ frame]),
+ NSHeight([subview1 frame]) + NSHeight([subview2 frame]));
+
+ // Now resize the popup view to be smaller than height. |subview2|'s height
+ // should stay the same, and |subview1|'s height should be zero, not negative.
+ [view_ setFrame:NSMakeRect(0, 0, 300, height - 10)];
+ EXPECT_EQ(NSWidth([view_ frame]), NSWidth([subview1 frame]));
+ EXPECT_EQ(NSWidth([view_ frame]), NSWidth([subview2 frame]));
+ EXPECT_EQ(0, NSHeight([subview1 frame]));
+ EXPECT_EQ(height, NSHeight([subview2 frame]));
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/location_bar/page_action_decoration.h b/chrome/browser/ui/cocoa/location_bar/page_action_decoration.h
new file mode 100644
index 0000000..07cd94d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/page_action_decoration.h
@@ -0,0 +1,119 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_LOCATION_BAR_PAGE_ACTION_DECORATION_H_
+#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_PAGE_ACTION_DECORATION_H_
+#pragma once
+
+#include "chrome/browser/extensions/image_loading_tracker.h"
+#import "chrome/browser/ui/cocoa/location_bar/image_decoration.h"
+#include "googleurl/src/gurl.h"
+
+class ExtensionAction;
+@class ExtensionActionContextMenu;
+class LocationBarViewMac;
+class Profile;
+class TabContents;
+
+// PageActionDecoration is used to display the icon for a given Page
+// Action and notify the extension when the icon is clicked.
+
+class PageActionDecoration : public ImageDecoration,
+ public ImageLoadingTracker::Observer,
+ public NotificationObserver {
+ public:
+ PageActionDecoration(LocationBarViewMac* owner,
+ Profile* profile,
+ ExtensionAction* page_action);
+ virtual ~PageActionDecoration();
+
+ ExtensionAction* page_action() { return page_action_; }
+ int current_tab_id() { return current_tab_id_; }
+ void set_preview_enabled(bool enabled) { preview_enabled_ = enabled; }
+ bool preview_enabled() const { return preview_enabled_; }
+
+ // Overridden from |ImageLoadingTracker::Observer|.
+ virtual void OnImageLoaded(
+ SkBitmap* image, ExtensionResource resource, int index);
+
+ // Called to notify the Page Action that it should determine whether
+ // to be visible or hidden. |contents| is the TabContents that is
+ // active, |url| is the current page URL.
+ void UpdateVisibility(TabContents* contents, const GURL& url);
+
+ // Sets the tooltip for this Page Action image.
+ void SetToolTip(NSString* tooltip);
+ void SetToolTip(std::string tooltip);
+
+ // Get the point where extension info bubbles should point within
+ // the given decoration frame.
+ NSPoint GetBubblePointInFrame(NSRect frame);
+
+ // Overridden from |LocationBarDecoration|
+ virtual CGFloat GetWidthForSpace(CGFloat width);
+ virtual bool AcceptsMousePress() { return true; }
+ virtual bool OnMousePressed(NSRect frame);
+ virtual NSString* GetToolTip();
+ virtual NSMenu* GetMenu();
+
+ protected:
+ // For unit testing only.
+ PageActionDecoration() : owner_(NULL),
+ profile_(NULL),
+ page_action_(NULL),
+ tracker_(this),
+ current_tab_id_(-1),
+ preview_enabled_(false) {}
+
+ private:
+ // Overridden from NotificationObserver:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // The location bar view that owns us.
+ LocationBarViewMac* owner_;
+
+ // The current profile (not owned by us).
+ Profile* profile_;
+
+ // The Page Action that this view represents. The Page Action is not
+ // owned by us, it resides in the extension of this particular
+ // profile.
+ ExtensionAction* page_action_;
+
+ // A cache of images the Page Actions might need to show, mapped by
+ // path.
+ typedef std::map<std::string, SkBitmap> PageActionMap;
+ PageActionMap page_action_icons_;
+
+ // The object that is waiting for the image loading to complete
+ // asynchronously.
+ ImageLoadingTracker tracker_;
+
+ // The tab id we are currently showing the icon for.
+ int current_tab_id_;
+
+ // The URL we are currently showing the icon for.
+ GURL current_url_;
+
+ // The string to show for a tooltip.
+ scoped_nsobject<NSString> tooltip_;
+
+ // The context menu for the Page Action.
+ scoped_nsobject<ExtensionActionContextMenu> menu_;
+
+ // This is used for post-install visual feedback. The page_action
+ // icon is briefly shown even if it hasn't been enabled by its
+ // extension.
+ bool preview_enabled_;
+
+ // Used to register for notifications received by
+ // NotificationObserver.
+ NotificationRegistrar registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(PageActionDecoration);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_PAGE_ACTION_DECORATION_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/page_action_decoration.mm b/chrome/browser/ui/cocoa/location_bar/page_action_decoration.mm
new file mode 100644
index 0000000..5ab186b
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/page_action_decoration.mm
@@ -0,0 +1,252 @@
+// 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.
+
+#include <cmath>
+
+#import "chrome/browser/ui/cocoa/location_bar/page_action_decoration.h"
+
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/extensions/extension_browser_event_router.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#import "chrome/browser/ui/cocoa/extensions/extension_action_context_menu.h"
+#import "chrome/browser/ui/cocoa/extensions/extension_popup_controller.h"
+#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
+#include "chrome/common/extensions/extension_action.h"
+#include "chrome/common/extensions/extension_resource.h"
+#include "chrome/common/notification_service.h"
+#include "skia/ext/skia_utils_mac.h"
+
+namespace {
+
+// Distance to offset the bubble pointer from the bottom of the max
+// icon area of the decoration. This makes the popup's upper border
+// 2px away from the omnibox's lower border (matches omnibox popup
+// upper border).
+const CGFloat kBubblePointYOffset = 2.0;
+
+} // namespace
+
+PageActionDecoration::PageActionDecoration(
+ LocationBarViewMac* owner,
+ Profile* profile,
+ ExtensionAction* page_action)
+ : owner_(NULL),
+ profile_(profile),
+ page_action_(page_action),
+ tracker_(this),
+ current_tab_id_(-1),
+ preview_enabled_(false) {
+ DCHECK(profile);
+ const Extension* extension = profile->GetExtensionService()->
+ GetExtensionById(page_action->extension_id(), false);
+ DCHECK(extension);
+
+ // Load all the icons declared in the manifest. This is the contents of the
+ // icons array, plus the default_icon property, if any.
+ std::vector<std::string> icon_paths(*page_action->icon_paths());
+ if (!page_action_->default_icon_path().empty())
+ icon_paths.push_back(page_action_->default_icon_path());
+
+ for (std::vector<std::string>::iterator iter = icon_paths.begin();
+ iter != icon_paths.end(); ++iter) {
+ tracker_.LoadImage(extension, extension->GetResource(*iter),
+ gfx::Size(Extension::kPageActionIconMaxSize,
+ Extension::kPageActionIconMaxSize),
+ ImageLoadingTracker::DONT_CACHE);
+ }
+
+ registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE,
+ Source<Profile>(profile_));
+
+ // We set the owner last of all so that we can determine whether we are in
+ // the process of initializing this class or not.
+ owner_ = owner;
+}
+
+PageActionDecoration::~PageActionDecoration() {}
+
+// Always |kPageActionIconMaxSize| wide. |ImageDecoration| draws the
+// image centered.
+CGFloat PageActionDecoration::GetWidthForSpace(CGFloat width) {
+ return Extension::kPageActionIconMaxSize;
+}
+
+// Either notify listeners or show a popup depending on the Page
+// Action.
+bool PageActionDecoration::OnMousePressed(NSRect frame) {
+ if (current_tab_id_ < 0) {
+ NOTREACHED() << "No current tab.";
+ // We don't want other code to try and handle this click. Returning true
+ // prevents this by indicating that we handled it.
+ return true;
+ }
+
+ if (page_action_->HasPopup(current_tab_id_)) {
+ // Anchor popup at the bottom center of the page action icon.
+ AutocompleteTextField* field = owner_->GetAutocompleteTextField();
+ NSPoint anchor = GetBubblePointInFrame(frame);
+ anchor = [field convertPoint:anchor toView:nil];
+
+ const GURL popup_url(page_action_->GetPopupUrl(current_tab_id_));
+ [ExtensionPopupController showURL:popup_url
+ inBrowser:BrowserList::GetLastActive()
+ anchoredAt:anchor
+ arrowLocation:info_bubble::kTopRight
+ devMode:NO];
+ } else {
+ ExtensionBrowserEventRouter::GetInstance()->PageActionExecuted(
+ profile_, page_action_->extension_id(), page_action_->id(),
+ current_tab_id_, current_url_.spec(),
+ 1);
+ }
+ return true;
+}
+
+void PageActionDecoration::OnImageLoaded(
+ SkBitmap* image, ExtensionResource resource, int index) {
+ // We loaded icons()->size() icons, plus one extra if the Page Action had
+ // a default icon.
+ int total_icons = static_cast<int>(page_action_->icon_paths()->size());
+ if (!page_action_->default_icon_path().empty())
+ total_icons++;
+ DCHECK(index < total_icons);
+
+ // Map the index of the loaded image back to its name. If we ever get an
+ // index greater than the number of icons, it must be the default icon.
+ if (image) {
+ if (index < static_cast<int>(page_action_->icon_paths()->size()))
+ page_action_icons_[page_action_->icon_paths()->at(index)] = *image;
+ else
+ page_action_icons_[page_action_->default_icon_path()] = *image;
+ }
+
+ // If we have no owner, that means this class is still being constructed and
+ // we should not UpdatePageActions, since it leads to the PageActions being
+ // destroyed again and new ones recreated (causing an infinite loop).
+ if (owner_)
+ owner_->UpdatePageActions();
+}
+
+void PageActionDecoration::UpdateVisibility(TabContents* contents,
+ const GURL& url) {
+ // Save this off so we can pass it back to the extension when the action gets
+ // executed. See PageActionDecoration::OnMousePressed.
+ current_tab_id_ = contents ? ExtensionTabUtil::GetTabId(contents) : -1;
+ current_url_ = url;
+
+ bool visible = contents &&
+ (preview_enabled_ || page_action_->GetIsVisible(current_tab_id_));
+ if (visible) {
+ SetToolTip(page_action_->GetTitle(current_tab_id_));
+
+ // Set the image.
+ // It can come from three places. In descending order of priority:
+ // - The developer can set it dynamically by path or bitmap. It will be in
+ // page_action_->GetIcon().
+ // - The developer can set it dynamically by index. It will be in
+ // page_action_->GetIconIndex().
+ // - It can be set in the manifest by path. It will be in page_action_->
+ // default_icon_path().
+
+ // First look for a dynamically set bitmap.
+ SkBitmap skia_icon = page_action_->GetIcon(current_tab_id_);
+ if (skia_icon.isNull()) {
+ int icon_index = page_action_->GetIconIndex(current_tab_id_);
+ std::string icon_path = (icon_index < 0) ?
+ page_action_->default_icon_path() :
+ page_action_->icon_paths()->at(icon_index);
+ if (!icon_path.empty()) {
+ PageActionMap::iterator iter = page_action_icons_.find(icon_path);
+ if (iter != page_action_icons_.end())
+ skia_icon = iter->second;
+ }
+ }
+ if (!skia_icon.isNull()) {
+ SetImage(gfx::SkBitmapToNSImage(skia_icon));
+ } else if (!GetImage()) {
+ // During install the action can be displayed before the icons
+ // have come in. Rather than deal with this in multiple places,
+ // provide a placeholder image. This will be replaced when an
+ // icon comes in.
+ const NSSize default_size = NSMakeSize(Extension::kPageActionIconMaxSize,
+ Extension::kPageActionIconMaxSize);
+ SetImage([[NSImage alloc] initWithSize:default_size]);
+ }
+ }
+
+ if (IsVisible() != visible) {
+ SetVisible(visible);
+ NotificationService::current()->Notify(
+ NotificationType::EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED,
+ Source<ExtensionAction>(page_action_),
+ Details<TabContents>(contents));
+ }
+}
+
+void PageActionDecoration::SetToolTip(NSString* tooltip) {
+ tooltip_.reset([tooltip retain]);
+}
+
+void PageActionDecoration::SetToolTip(std::string tooltip) {
+ SetToolTip(tooltip.empty() ? nil : base::SysUTF8ToNSString(tooltip));
+}
+
+NSString* PageActionDecoration::GetToolTip() {
+ return tooltip_.get();
+}
+
+NSPoint PageActionDecoration::GetBubblePointInFrame(NSRect frame) {
+ // This is similar to |ImageDecoration::GetDrawRectInFrame()|,
+ // except that code centers the image, which can differ in size
+ // between actions. This centers the maximum image size, so the
+ // point will consistently be at the same y position. x position is
+ // easier (the middle of the centered image is the middle of the
+ // frame).
+ const CGFloat delta_height =
+ NSHeight(frame) - Extension::kPageActionIconMaxSize;
+ const CGFloat bottom_inset = std::ceil(delta_height / 2.0);
+
+ // Return a point just below the bottom of the maximal drawing area.
+ return NSMakePoint(NSMidX(frame),
+ NSMaxY(frame) - bottom_inset + kBubblePointYOffset);
+}
+
+NSMenu* PageActionDecoration::GetMenu() {
+ if (!profile_)
+ return nil;
+ ExtensionService* service = profile_->GetExtensionService();
+ if (!service)
+ return nil;
+ const Extension* extension = service->GetExtensionById(
+ page_action_->extension_id(), false);
+ DCHECK(extension);
+ if (!extension)
+ return nil;
+ menu_.reset([[ExtensionActionContextMenu alloc]
+ initWithExtension:extension
+ profile:profile_
+ extensionAction:page_action_]);
+
+ return menu_.get();
+}
+
+void PageActionDecoration::Observe(
+ NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ switch (type.value) {
+ case NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE: {
+ ExtensionPopupController* popup = [ExtensionPopupController popup];
+ if (popup && ![popup isClosing])
+ [popup close];
+
+ break;
+ }
+ default:
+ NOTREACHED() << "Unexpected notification";
+ break;
+ }
+}
diff --git a/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.h b/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.h
new file mode 100644
index 0000000..3c9cf30
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.h
@@ -0,0 +1,42 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_LOCATION_BAR_SELECTED_KEYWORD_DECORATION_H_
+#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_SELECTED_KEYWORD_DECORATION_H_
+#pragma once
+
+#include <string>
+
+#import <Cocoa/Cocoa.h>
+
+#include "chrome/browser/ui/cocoa/location_bar/bubble_decoration.h"
+
+class SelectedKeywordDecoration : public BubbleDecoration {
+ public:
+ SelectedKeywordDecoration(NSFont* font);
+
+ // Calculates appropriate full and partial label strings based on
+ // inputs.
+ void SetKeyword(const std::wstring& keyword, bool is_extension_keyword);
+
+ // Determines what combination of labels and image will best fit
+ // within |width|, makes those current for |BubbleDecoration|, and
+ // return the resulting width.
+ virtual CGFloat GetWidthForSpace(CGFloat width);
+
+ void SetImage(NSImage* image);
+
+ private:
+ friend class SelectedKeywordDecorationTest;
+ FRIEND_TEST_ALL_PREFIXES(SelectedKeywordDecorationTest,
+ UsesPartialKeywordIfNarrow);
+
+ scoped_nsobject<NSImage> search_image_;
+ scoped_nsobject<NSString> full_string_;
+ scoped_nsobject<NSString> partial_string_;
+
+ DISALLOW_COPY_AND_ASSIGN(SelectedKeywordDecoration);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_SELECTED_KEYWORD_DECORATION_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.mm b/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.mm
new file mode 100644
index 0000000..6aa6505
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.mm
@@ -0,0 +1,73 @@
+// 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 "chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.h"
+
+#include "app/l10n_util_mac.h"
+#include "base/utf_string_conversions.h"
+#import "chrome/browser/autocomplete/autocomplete_edit_view_mac.h"
+#import "chrome/browser/ui/cocoa/image_utils.h"
+#include "chrome/browser/ui/omnibox/location_bar_util.h"
+#include "grit/theme_resources.h"
+#include "grit/generated_resources.h"
+
+SelectedKeywordDecoration::SelectedKeywordDecoration(NSFont* font)
+ : BubbleDecoration(font) {
+ search_image_.reset([AutocompleteEditViewMac::ImageForResource(
+ IDR_KEYWORD_SEARCH_MAGNIFIER) retain]);
+
+ // Matches the color of the highlighted line in the popup.
+ NSColor* background_color = [NSColor selectedControlColor];
+
+ // Match focus ring's inner color.
+ NSColor* border_color =
+ [[NSColor keyboardFocusIndicatorColor] colorWithAlphaComponent:0.5];
+ SetColors(border_color, background_color, [NSColor blackColor]);
+}
+
+CGFloat SelectedKeywordDecoration::GetWidthForSpace(CGFloat width) {
+ const CGFloat full_width =
+ GetWidthForImageAndLabel(search_image_, full_string_);
+ if (full_width <= width) {
+ BubbleDecoration::SetImage(search_image_);
+ SetLabel(full_string_);
+ return full_width;
+ }
+
+ BubbleDecoration::SetImage(nil);
+ const CGFloat no_image_width = GetWidthForImageAndLabel(nil, full_string_);
+ if (no_image_width <= width || !partial_string_) {
+ SetLabel(full_string_);
+ return no_image_width;
+ }
+
+ SetLabel(partial_string_);
+ return GetWidthForImageAndLabel(nil, partial_string_);
+}
+
+void SelectedKeywordDecoration::SetKeyword(const std::wstring& short_name,
+ bool is_extension_keyword) {
+ const std::wstring min_name(
+ location_bar_util::CalculateMinString(short_name));
+ const int message_id = is_extension_keyword ?
+ IDS_OMNIBOX_EXTENSION_KEYWORD_TEXT : IDS_OMNIBOX_KEYWORD_TEXT;
+
+ // The text will be like "Search <name>:". "<name>" is a parameter
+ // derived from |short_name|.
+ full_string_.reset(
+ [l10n_util::GetNSStringF(message_id, WideToUTF16(short_name)) copy]);
+
+ if (min_name.empty()) {
+ partial_string_.reset();
+ } else {
+ partial_string_.reset(
+ [l10n_util::GetNSStringF(message_id, WideToUTF16(min_name)) copy]);
+ }
+}
+
+void SelectedKeywordDecoration::SetImage(NSImage* image) {
+ if (image != search_image_)
+ search_image_.reset([image retain]);
+ BubbleDecoration::SetImage(image);
+}
diff --git a/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration_unittest.mm b/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration_unittest.mm
new file mode 100644
index 0000000..5536fda
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration_unittest.mm
@@ -0,0 +1,64 @@
+// 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>
+
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+
+namespace {
+
+// A wide width which should fit everything.
+const CGFloat kWidth(300.0);
+
+// A narrow width for tests which test things that don't fit.
+const CGFloat kNarrowWidth(5.0);
+
+} // namespace
+
+class SelectedKeywordDecorationTest : public CocoaTest {
+ public:
+ SelectedKeywordDecorationTest()
+ : decoration_([NSFont userFontOfSize:12]) {
+ }
+
+ SelectedKeywordDecoration decoration_;
+};
+
+// Test that the cell correctly chooses the partial keyword if there's
+// not enough room.
+TEST_F(SelectedKeywordDecorationTest, UsesPartialKeywordIfNarrow) {
+
+ const std::wstring kKeyword(L"Engine");
+ NSString* const kFullString = @"Search Engine:";
+ NSString* const kPartialString = @"Search En\u2026:"; // ellipses
+
+ decoration_.SetKeyword(kKeyword, false);
+
+ // Wide width chooses the full string and image.
+ const CGFloat all_width = decoration_.GetWidthForSpace(kWidth);
+ EXPECT_TRUE(decoration_.image_);
+ EXPECT_NSEQ(kFullString, decoration_.label_);
+
+ // If not enough space to include the image, uses exactly the full
+ // string.
+ const CGFloat full_width = decoration_.GetWidthForSpace(all_width - 5.0);
+ EXPECT_LT(full_width, all_width);
+ EXPECT_FALSE(decoration_.image_);
+ EXPECT_NSEQ(kFullString, decoration_.label_);
+
+ // Narrow width chooses the partial string.
+ const CGFloat partial_width = decoration_.GetWidthForSpace(kNarrowWidth);
+ EXPECT_LT(partial_width, full_width);
+ EXPECT_FALSE(decoration_.image_);
+ EXPECT_NSEQ(kPartialString, decoration_.label_);
+
+ // Narrow doesn't choose partial string if there is not one.
+ decoration_.partial_string_.reset();
+ decoration_.GetWidthForSpace(kNarrowWidth);
+ EXPECT_FALSE(decoration_.image_);
+ EXPECT_NSEQ(kFullString, decoration_.label_);
+}
diff --git a/chrome/browser/ui/cocoa/location_bar/star_decoration.h b/chrome/browser/ui/cocoa/location_bar/star_decoration.h
new file mode 100644
index 0000000..0d12104
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/star_decoration.h
@@ -0,0 +1,44 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_LOCATION_BAR_STAR_DECORATION_H_
+#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_STAR_DECORATION_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "chrome/browser/ui/cocoa/location_bar/image_decoration.h"
+
+class CommandUpdater;
+
+// Star icon on the right side of the field.
+
+class StarDecoration : public ImageDecoration {
+ public:
+ explicit StarDecoration(CommandUpdater* command_updater);
+ virtual ~StarDecoration();
+
+ // Sets the image and tooltip based on |starred|.
+ void SetStarred(bool starred);
+
+ // Get the point where the bookmark bubble should point within the
+ // decoration's frame.
+ NSPoint GetBubblePointInFrame(NSRect frame);
+
+ // Implement |LocationBarDecoration|.
+ virtual bool AcceptsMousePress() { return true; }
+ virtual bool OnMousePressed(NSRect frame);
+ virtual NSString* GetToolTip();
+
+ private:
+ // For bringing up bookmark bar.
+ CommandUpdater* command_updater_; // Weak, owned by Browser.
+
+ // The string to show for a tooltip.
+ scoped_nsobject<NSString> tooltip_;
+
+ DISALLOW_COPY_AND_ASSIGN(StarDecoration);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_STAR_DECORATION_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/star_decoration.mm b/chrome/browser/ui/cocoa/location_bar/star_decoration.mm
new file mode 100644
index 0000000..2ac3450
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/star_decoration.mm
@@ -0,0 +1,53 @@
+// 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 "chrome/browser/ui/cocoa/location_bar/star_decoration.h"
+
+#include "app/l10n_util_mac.h"
+#include "chrome/app/chrome_command_ids.h"
+#import "chrome/browser/autocomplete/autocomplete_edit_view_mac.h"
+#include "chrome/browser/command_updater.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+
+namespace {
+
+// The info-bubble point should look like it points to the point
+// between the star's lower tips. The popup should be where the
+// Omnibox popup ends up (2px below field). Determined via Pixie.app
+// magnification.
+const CGFloat kStarPointYOffset = 2.0;
+
+} // namespace
+
+StarDecoration::StarDecoration(CommandUpdater* command_updater)
+ : command_updater_(command_updater) {
+ SetVisible(true);
+ SetStarred(false);
+}
+
+StarDecoration::~StarDecoration() {
+}
+
+void StarDecoration::SetStarred(bool starred) {
+ const int image_id = starred ? IDR_STAR_LIT : IDR_STAR;
+ const int tip_id = starred ? IDS_TOOLTIP_STARRED : IDS_TOOLTIP_STAR;
+ SetImage(AutocompleteEditViewMac::ImageForResource(image_id));
+ tooltip_.reset([l10n_util::GetNSStringWithFixup(tip_id) retain]);
+}
+
+NSPoint StarDecoration::GetBubblePointInFrame(NSRect frame) {
+ const NSRect draw_frame = GetDrawRectInFrame(frame);
+ return NSMakePoint(NSMidX(draw_frame),
+ NSMaxY(draw_frame) - kStarPointYOffset);
+}
+
+bool StarDecoration::OnMousePressed(NSRect frame) {
+ command_updater_->ExecuteCommand(IDC_BOOKMARK_PAGE);
+ return true;
+}
+
+NSString* StarDecoration::GetToolTip() {
+ return tooltip_.get();
+}
diff --git a/chrome/browser/ui/cocoa/menu_button.h b/chrome/browser/ui/cocoa/menu_button.h
new file mode 100644
index 0000000..d7b00f5
--- /dev/null
+++ b/chrome/browser/ui/cocoa/menu_button.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_MENU_BUTTON_H_
+#define CHROME_BROWSER_UI_COCOA_MENU_BUTTON_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+
+// This a button which displays a user-provided menu "attached" below it upon
+// being clicked or dragged (or clicked and held). It expects a
+// |ClickHoldButtonCell| as cell.
+@interface MenuButton : NSButton {
+ @private
+ IBOutlet NSMenu* attachedMenu_;
+ scoped_nsobject<NSPopUpButtonCell> popUpCell_;
+}
+
+// The menu to display. Note that it should have no (i.e., a blank) title and
+// that the 0-th entry should be blank (and won't be displayed). (This is
+// because we use a pulldown list, for which Cocoa uses the 0-th item as "title"
+// in the button. This might change if we ever switch to a pop-up. Our direct
+// use of the given NSMenu object means that the one can set and use NSMenu's
+// delegate as usual.)
+@property(assign, nonatomic) NSMenu* attachedMenu;
+
+@end // @interface MenuButton
+
+#endif // CHROME_BROWSER_UI_COCOA_MENU_BUTTON_H_
diff --git a/chrome/browser/ui/cocoa/menu_button.mm b/chrome/browser/ui/cocoa/menu_button.mm
new file mode 100644
index 0000000..d1b9e88
--- /dev/null
+++ b/chrome/browser/ui/cocoa/menu_button.mm
@@ -0,0 +1,122 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/menu_button.h"
+
+#include "base/logging.h"
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/clickhold_button_cell.h"
+
+@interface MenuButton (Private)
+
+- (void)resetToDefaults;
+- (void)showMenu:(BOOL)isDragging;
+- (void)clickShowMenu:(id)sender;
+- (void)dragShowMenu:(id)sender;
+
+@end // @interface MenuButton (Private)
+
+@implementation MenuButton
+
+// Overrides:
+
++ (Class)cellClass {
+ return [ClickHoldButtonCell class];
+}
+
+- (id)init {
+ if ((self = [super init]))
+ [self resetToDefaults];
+ return self;
+}
+
+- (id)initWithCoder:(NSCoder*)decoder {
+ if ((self = [super initWithCoder:decoder]))
+ [self resetToDefaults];
+ return self;
+}
+
+- (id)initWithFrame:(NSRect)frameRect {
+ if ((self = [super initWithFrame:frameRect]))
+ [self resetToDefaults];
+ return self;
+}
+
+// Accessors and mutators:
+
+@synthesize attachedMenu = attachedMenu_;
+
+@end // @implementation MenuButton
+
+@implementation MenuButton (Private)
+
+// Reset various settings of the button and its associated |ClickHoldButtonCell|
+// to the standard state which provides reasonable defaults.
+- (void)resetToDefaults {
+ ClickHoldButtonCell* cell = [self cell];
+ DCHECK([cell isKindOfClass:[ClickHoldButtonCell class]]);
+ [cell setEnableClickHold:YES];
+ [cell setClickHoldTimeout:0.0]; // Make menu trigger immediately.
+ [cell setAction:@selector(clickShowMenu:)];
+ [cell setTarget:self];
+ [cell setClickHoldAction:@selector(dragShowMenu:)];
+ [cell setClickHoldTarget:self];
+}
+
+// Actually show the menu (in the correct location). |isDragging| indicates
+// whether the mouse button is still down or not.
+- (void)showMenu:(BOOL)isDragging {
+ if (![self attachedMenu]) {
+ LOG(WARNING) << "No menu available.";
+ if (isDragging) {
+ // If we're dragging, wait for mouse up.
+ [NSApp nextEventMatchingMask:NSLeftMouseUpMask
+ untilDate:[NSDate distantFuture]
+ inMode:NSEventTrackingRunLoopMode
+ dequeue:YES];
+ }
+ return;
+ }
+
+ // TODO(viettrungluu): Remove silly fudge factors (same ones as in
+ // delayedmenu_button.mm).
+ NSRect frame = [self convertRect:[self frame]
+ fromView:[self superview]];
+ frame.origin.x -= 2.0;
+ frame.size.height += 10.0;
+
+ // Make our pop-up button cell and set things up. This is, as of 10.5, the
+ // official Apple-recommended hack. Later, perhaps |-[NSMenu
+ // popUpMenuPositioningItem:atLocation:inView:]| may be a better option.
+ // However, using a pulldown has the benefit that Cocoa automatically places
+ // the menu correctly even when we're at the edge of the screen (including
+ // "dragging upwards" when the button is close to the bottom of the screen).
+ // A |scoped_nsobject| local variable cannot be used here because
+ // Accessibility on 10.5 grabs the NSPopUpButtonCell without retaining it, and
+ // uses it later. (This is fixed in 10.6.)
+ if (!popUpCell_.get()) {
+ popUpCell_.reset([[NSPopUpButtonCell alloc] initTextCell:@""
+ pullsDown:YES]);
+ }
+ DCHECK(popUpCell_.get());
+ [popUpCell_ setMenu:[self attachedMenu]];
+ [popUpCell_ selectItem:nil];
+ [popUpCell_ attachPopUpWithFrame:frame
+ inView:self];
+ [popUpCell_ performClickWithFrame:frame
+ inView:self];
+}
+
+// Called when the button is clicked and released. (Shouldn't happen with
+// timeout of 0, though there may be some strange pointing devices out there.)
+- (void)clickShowMenu:(id)sender {
+ [self showMenu:NO];
+}
+
+// Called when the button is clicked and dragged/held.
+- (void)dragShowMenu:(id)sender {
+ [self showMenu:YES];
+}
+
+@end // @implementation MenuButton (Private)
diff --git a/chrome/browser/ui/cocoa/menu_button_unittest.mm b/chrome/browser/ui/cocoa/menu_button_unittest.mm
new file mode 100644
index 0000000..ccfcb2c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/menu_button_unittest.mm
@@ -0,0 +1,50 @@
+// Copyright (c) 2009 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/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/clickhold_button_cell.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/menu_button.h"
+
+namespace {
+
+class MenuButtonTest : public CocoaTest {
+ public:
+ MenuButtonTest() {
+ NSRect frame = NSMakeRect(0, 0, 50, 30);
+ scoped_nsobject<MenuButton> button(
+ [[MenuButton alloc] initWithFrame:frame]);
+ button_ = button.get();
+ scoped_nsobject<ClickHoldButtonCell> cell(
+ [[ClickHoldButtonCell alloc] initTextCell:@"Testing"]);
+ [button_ setCell:cell.get()];
+ [[test_window() contentView] addSubview:button_];
+ }
+
+ MenuButton* button_;
+};
+
+TEST_VIEW(MenuButtonTest, button_);
+
+// Test assigning a menu, again mostly to ensure nothing leaks or crashes.
+TEST_F(MenuButtonTest, MenuAssign) {
+ scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@""]);
+ ASSERT_TRUE(menu.get());
+
+ [menu insertItemWithTitle:@"" action:nil keyEquivalent:@"" atIndex:0];
+ [menu insertItemWithTitle:@"foo" action:nil keyEquivalent:@"" atIndex:1];
+ [menu insertItemWithTitle:@"bar" action:nil keyEquivalent:@"" atIndex:2];
+ [menu insertItemWithTitle:@"baz" action:nil keyEquivalent:@"" atIndex:3];
+
+ [button_ setAttachedMenu:menu];
+ EXPECT_TRUE([button_ attachedMenu]);
+
+ // TODO(viettrungluu): Display the menu. (The tough part is closing the menu,
+ // not opening it!)
+
+ // Since |button_| doesn't retain menu, we should probably unset it here.
+ [button_ setAttachedMenu:nil];
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/menu_controller.h b/chrome/browser/ui/cocoa/menu_controller.h
new file mode 100644
index 0000000..c198c70
--- /dev/null
+++ b/chrome/browser/ui/cocoa/menu_controller.h
@@ -0,0 +1,67 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_MENU_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_MENU_CONTROLLER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+
+namespace menus {
+class MenuModel;
+}
+
+// A controller for the cross-platform menu model. The menu that's created
+// has the tag and represented object set for each menu item. The object is a
+// NSValue holding a pointer to the model for that level of the menu (to
+// allow for hierarchical menus). The tag is the index into that model for
+// that particular item. It is important that the model outlives this object
+// as it only maintains weak references.
+@interface MenuController : NSObject {
+ @protected
+ menus::MenuModel* model_; // weak
+ scoped_nsobject<NSMenu> menu_;
+ BOOL useWithPopUpButtonCell_; // If YES, 0th item is blank
+}
+
+@property (nonatomic, assign) menus::MenuModel* model;
+// Note that changing this will have no effect if you use
+// |-initWithModel:useWithPopUpButtonCell:| or after the first call to |-menu|.
+@property (nonatomic) BOOL useWithPopUpButtonCell;
+
+// NIB-based initializer. This does not create a menu. Clients can set the
+// properties of the object and the menu will be created upon the first call to
+// |-menu|. Note that the menu will be immutable after creation.
+- (id)init;
+
+// Builds a NSMenu from the pre-built model (must not be nil). Changes made
+// to the contents of the model after calling this will not be noticed. If
+// the menu will be displayed by a NSPopUpButtonCell, it needs to be of a
+// slightly different form (0th item is empty). Note this attribute of the menu
+// cannot be changed after it has been created.
+- (id)initWithModel:(menus::MenuModel*)model
+ useWithPopUpButtonCell:(BOOL)useWithCell;
+
+// Access to the constructed menu if the complex initializer was used. If the
+// default initializer was used, then this will create the menu on first call.
+- (NSMenu*)menu;
+
+@end
+
+// Exposed only for unit testing, do not call directly.
+@interface MenuController (PrivateExposedForTesting)
+- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item;
+@end
+
+// Protected methods that subclassers can override.
+@interface MenuController (Protected)
+- (void)addItemToMenu:(NSMenu*)menu
+ atIndex:(NSInteger)index
+ fromModel:(menus::MenuModel*)model
+ modelIndex:(int)modelIndex;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_MENU_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/menu_controller.mm b/chrome/browser/ui/cocoa/menu_controller.mm
new file mode 100644
index 0000000..a6d314d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/menu_controller.mm
@@ -0,0 +1,191 @@
+// 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 "chrome/browser/ui/cocoa/menu_controller.h"
+
+#include "app/l10n_util_mac.h"
+#include "app/menus/accelerator_cocoa.h"
+#include "app/menus/simple_menu_model.h"
+#include "base/logging.h"
+#include "base/sys_string_conversions.h"
+#include "skia/ext/skia_utils_mac.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+@interface MenuController (Private)
+- (NSMenu*)menuFromModel:(menus::MenuModel*)model;
+- (void)addSeparatorToMenu:(NSMenu*)menu
+ atIndex:(int)index;
+@end
+
+@implementation MenuController
+
+@synthesize model = model_;
+@synthesize useWithPopUpButtonCell = useWithPopUpButtonCell_;
+
+- (id)init {
+ self = [super init];
+ return self;
+}
+
+- (id)initWithModel:(menus::MenuModel*)model
+ useWithPopUpButtonCell:(BOOL)useWithCell {
+ if ((self = [super init])) {
+ model_ = model;
+ useWithPopUpButtonCell_ = useWithCell;
+ [self menu];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ model_ = NULL;
+ [super dealloc];
+}
+
+// Creates a NSMenu from the given model. If the model has submenus, this can
+// be invoked recursively.
+- (NSMenu*)menuFromModel:(menus::MenuModel*)model {
+ NSMenu* menu = [[[NSMenu alloc] initWithTitle:@""] autorelease];
+
+ // The indices may not always start at zero (the windows system menu is one
+ // example where this is used) so just make sure we can handle it.
+ // SimpleMenuModel currently always starts at 0.
+ int firstItemIndex = model->GetFirstItemIndex(menu);
+ DCHECK(firstItemIndex == 0);
+ const int count = model->GetItemCount();
+ for (int index = firstItemIndex; index < firstItemIndex + count; index++) {
+ int modelIndex = index - firstItemIndex;
+ if (model->GetTypeAt(modelIndex) == menus::MenuModel::TYPE_SEPARATOR) {
+ [self addSeparatorToMenu:menu atIndex:index];
+ } else {
+ [self addItemToMenu:menu atIndex:index fromModel:model
+ modelIndex:modelIndex];
+ }
+ }
+
+ return menu;
+}
+
+// Adds a separator item at the given index. As the separator doesn't need
+// anything from the model, this method doesn't need the model index as the
+// other method below does.
+- (void)addSeparatorToMenu:(NSMenu*)menu
+ atIndex:(int)index {
+ NSMenuItem* separator = [NSMenuItem separatorItem];
+ [menu insertItem:separator atIndex:index];
+}
+
+// Adds an item or a hierarchical menu to the item at the |index|,
+// associated with the entry in the model indentifed by |modelIndex|.
+- (void)addItemToMenu:(NSMenu*)menu
+ atIndex:(NSInteger)index
+ fromModel:(menus::MenuModel*)model
+ modelIndex:(int)modelIndex {
+ NSString* label =
+ l10n_util::FixUpWindowsStyleLabel(model->GetLabelAt(modelIndex));
+ scoped_nsobject<NSMenuItem> item(
+ [[NSMenuItem alloc] initWithTitle:label
+ action:@selector(itemSelected:)
+ keyEquivalent:@""]);
+
+ // If the menu item has an icon, set it.
+ SkBitmap skiaIcon;
+ if (model->GetIconAt(modelIndex, &skiaIcon) && !skiaIcon.isNull()) {
+ NSImage* icon = gfx::SkBitmapToNSImage(skiaIcon);
+ if (icon) {
+ [item setImage:icon];
+ }
+ }
+
+ menus::MenuModel::ItemType type = model->GetTypeAt(modelIndex);
+ if (type == menus::MenuModel::TYPE_SUBMENU) {
+ // Recursively build a submenu from the sub-model at this index.
+ [item setTarget:nil];
+ [item setAction:nil];
+ menus::MenuModel* submenuModel = model->GetSubmenuModelAt(modelIndex);
+ NSMenu* submenu =
+ [self menuFromModel:(menus::SimpleMenuModel*)submenuModel];
+ [item setSubmenu:submenu];
+ } else {
+ // The MenuModel works on indexes so we can't just set the command id as the
+ // tag like we do in other menus. Also set the represented object to be
+ // the model so hierarchical menus check the correct index in the correct
+ // model. Setting the target to |self| allows this class to participate
+ // in validation of the menu items.
+ [item setTag:modelIndex];
+ [item setTarget:self];
+ NSValue* modelObject = [NSValue valueWithPointer:model];
+ [item setRepresentedObject:modelObject]; // Retains |modelObject|.
+ menus::AcceleratorCocoa accelerator;
+ if (model->GetAcceleratorAt(modelIndex, &accelerator)) {
+ [item setKeyEquivalent:accelerator.characters()];
+ [item setKeyEquivalentModifierMask:accelerator.modifiers()];
+ }
+ }
+ [menu insertItem:item atIndex:index];
+}
+
+// Called before the menu is to be displayed to update the state (enabled,
+// radio, etc) of each item in the menu. Also will update the title if
+// the item is marked as "dynamic".
+- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
+ SEL action = [item action];
+ if (action != @selector(itemSelected:))
+ return NO;
+
+ NSInteger modelIndex = [item tag];
+ menus::MenuModel* model =
+ static_cast<menus::MenuModel*>(
+ [[(id)item representedObject] pointerValue]);
+ DCHECK(model);
+ if (model) {
+ BOOL checked = model->IsItemCheckedAt(modelIndex);
+ DCHECK([(id)item isKindOfClass:[NSMenuItem class]]);
+ [(id)item setState:(checked ? NSOnState : NSOffState)];
+ [(id)item setHidden:(!model->IsVisibleAt(modelIndex))];
+ if (model->IsItemDynamicAt(modelIndex)) {
+ // Update the label and the icon.
+ NSString* label =
+ l10n_util::FixUpWindowsStyleLabel(model->GetLabelAt(modelIndex));
+ [(id)item setTitle:label];
+ SkBitmap skiaIcon;
+ NSImage* icon = nil;
+ if (model->GetIconAt(modelIndex, &skiaIcon) && !skiaIcon.isNull())
+ icon = gfx::SkBitmapToNSImage(skiaIcon);
+ [(id)item setImage:icon];
+ }
+ return model->IsEnabledAt(modelIndex);
+ }
+ return NO;
+}
+
+// Called when the user chooses a particular menu item. |sender| is the menu
+// item chosen.
+- (void)itemSelected:(id)sender {
+ NSInteger modelIndex = [sender tag];
+ menus::MenuModel* model =
+ static_cast<menus::MenuModel*>(
+ [[sender representedObject] pointerValue]);
+ DCHECK(model);
+ if (model)
+ model->ActivatedAt(modelIndex);
+}
+
+- (NSMenu*)menu {
+ if (!menu_ && model_) {
+ menu_.reset([[self menuFromModel:model_] retain]);
+ // If this is to be used with a NSPopUpButtonCell, add an item at the 0th
+ // position that's empty. Doing it after the menu has been constructed won't
+ // complicate creation logic, and since the tags are model indexes, they
+ // are unaffected by the extra item.
+ if (useWithPopUpButtonCell_) {
+ scoped_nsobject<NSMenuItem> blankItem(
+ [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]);
+ [menu_ insertItem:blankItem atIndex:0];
+ }
+ }
+ return menu_.get();
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/menu_controller_unittest.mm b/chrome/browser/ui/cocoa/menu_controller_unittest.mm
new file mode 100644
index 0000000..8e00c53
--- /dev/null
+++ b/chrome/browser/ui/cocoa/menu_controller_unittest.mm
@@ -0,0 +1,262 @@
+// 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 "app/menus/simple_menu_model.h"
+#include "app/resource_bundle.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/menu_controller.h"
+#include "grit/app_resources.h"
+#include "grit/generated_resources.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+class MenuControllerTest : public CocoaTest {
+};
+
+// A menu delegate that counts the number of times certain things are called
+// to make sure things are hooked up properly.
+class Delegate : public menus::SimpleMenuModel::Delegate {
+ public:
+ Delegate() : execute_count_(0), enable_count_(0) { }
+
+ virtual bool IsCommandIdChecked(int command_id) const { return false; }
+ virtual bool IsCommandIdEnabled(int command_id) const {
+ ++enable_count_;
+ return true;
+ }
+ virtual bool GetAcceleratorForCommandId(
+ int command_id,
+ menus::Accelerator* accelerator) { return false; }
+ virtual void ExecuteCommand(int command_id) { ++execute_count_; }
+
+ int execute_count_;
+ mutable int enable_count_;
+};
+
+// Just like Delegate, except the items are treated as "dynamic" so updates to
+// the label/icon in the model are reflected in the menu.
+class DynamicDelegate : public Delegate {
+ public:
+ DynamicDelegate() : icon_(NULL) {}
+ virtual bool IsItemForCommandIdDynamic(int command_id) const { return true; }
+ virtual string16 GetLabelForCommandId(int command_id) const { return label_; }
+ virtual bool GetIconForCommandId(int command_id, SkBitmap* icon) const {
+ if (icon_) {
+ *icon = *icon_;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ void SetDynamicLabel(string16 label) { label_ = label; }
+ void SetDynamicIcon(SkBitmap* icon) { icon_ = icon; }
+
+ private:
+ string16 label_;
+ SkBitmap* icon_;
+};
+
+TEST_F(MenuControllerTest, EmptyMenu) {
+ Delegate delegate;
+ menus::SimpleMenuModel model(&delegate);
+ scoped_nsobject<MenuController> menu(
+ [[MenuController alloc] initWithModel:&model useWithPopUpButtonCell:NO]);
+ EXPECT_EQ([[menu menu] numberOfItems], 0);
+}
+
+TEST_F(MenuControllerTest, BasicCreation) {
+ Delegate delegate;
+ menus::SimpleMenuModel model(&delegate);
+ model.AddItem(1, ASCIIToUTF16("one"));
+ model.AddItem(2, ASCIIToUTF16("two"));
+ model.AddItem(3, ASCIIToUTF16("three"));
+ model.AddSeparator();
+ model.AddItem(4, ASCIIToUTF16("four"));
+ model.AddItem(5, ASCIIToUTF16("five"));
+
+ scoped_nsobject<MenuController> menu(
+ [[MenuController alloc] initWithModel:&model useWithPopUpButtonCell:NO]);
+ EXPECT_EQ([[menu menu] numberOfItems], 6);
+
+ // Check the title, tag, and represented object are correct for a random
+ // element.
+ NSMenuItem* itemTwo = [[menu menu] itemAtIndex:2];
+ NSString* title = [itemTwo title];
+ EXPECT_EQ(ASCIIToUTF16("three"), base::SysNSStringToUTF16(title));
+ EXPECT_EQ([itemTwo tag], 2);
+ EXPECT_EQ([[itemTwo representedObject] pointerValue], &model);
+
+ EXPECT_TRUE([[[menu menu] itemAtIndex:3] isSeparatorItem]);
+}
+
+TEST_F(MenuControllerTest, Submenus) {
+ Delegate delegate;
+ menus::SimpleMenuModel model(&delegate);
+ model.AddItem(1, ASCIIToUTF16("one"));
+ menus::SimpleMenuModel submodel(&delegate);
+ submodel.AddItem(2, ASCIIToUTF16("sub-one"));
+ submodel.AddItem(3, ASCIIToUTF16("sub-two"));
+ submodel.AddItem(4, ASCIIToUTF16("sub-three"));
+ model.AddSubMenuWithStringId(5, IDS_ZOOM_MENU, &submodel);
+ model.AddItem(6, ASCIIToUTF16("three"));
+
+ scoped_nsobject<MenuController> menu(
+ [[MenuController alloc] initWithModel:&model useWithPopUpButtonCell:NO]);
+ EXPECT_EQ([[menu menu] numberOfItems], 3);
+
+ // Inspect the submenu to ensure it has correct properties.
+ NSMenu* submenu = [[[menu menu] itemAtIndex:1] submenu];
+ EXPECT_TRUE(submenu);
+ EXPECT_EQ([submenu numberOfItems], 3);
+
+ // Inspect one of the items to make sure it has the correct model as its
+ // represented object and the proper tag.
+ NSMenuItem* submenuItem = [submenu itemAtIndex:1];
+ NSString* title = [submenuItem title];
+ EXPECT_EQ(ASCIIToUTF16("sub-two"), base::SysNSStringToUTF16(title));
+ EXPECT_EQ([submenuItem tag], 1);
+ EXPECT_EQ([[submenuItem representedObject] pointerValue], &submodel);
+
+ // Make sure the item after the submenu is correct and its represented
+ // object is back to the top model.
+ NSMenuItem* item = [[menu menu] itemAtIndex:2];
+ title = [item title];
+ EXPECT_EQ(ASCIIToUTF16("three"), base::SysNSStringToUTF16(title));
+ EXPECT_EQ([item tag], 2);
+ EXPECT_EQ([[item representedObject] pointerValue], &model);
+}
+
+TEST_F(MenuControllerTest, EmptySubmenu) {
+ Delegate delegate;
+ menus::SimpleMenuModel model(&delegate);
+ model.AddItem(1, ASCIIToUTF16("one"));
+ menus::SimpleMenuModel submodel(&delegate);
+ model.AddSubMenuWithStringId(2, IDS_ZOOM_MENU, &submodel);
+
+ scoped_nsobject<MenuController> menu(
+ [[MenuController alloc] initWithModel:&model useWithPopUpButtonCell:NO]);
+ EXPECT_EQ([[menu menu] numberOfItems], 2);
+}
+
+TEST_F(MenuControllerTest, PopUpButton) {
+ Delegate delegate;
+ menus::SimpleMenuModel model(&delegate);
+ model.AddItem(1, ASCIIToUTF16("one"));
+ model.AddItem(2, ASCIIToUTF16("two"));
+ model.AddItem(3, ASCIIToUTF16("three"));
+
+ // Menu should have an extra item inserted at position 0 that has an empty
+ // title.
+ scoped_nsobject<MenuController> menu(
+ [[MenuController alloc] initWithModel:&model useWithPopUpButtonCell:YES]);
+ EXPECT_EQ([[menu menu] numberOfItems], 4);
+ EXPECT_EQ(base::SysNSStringToUTF16([[[menu menu] itemAtIndex:0] title]),
+ string16());
+
+ // Make sure the tags are still correct (the index no longer matches the tag).
+ NSMenuItem* itemTwo = [[menu menu] itemAtIndex:2];
+ EXPECT_EQ([itemTwo tag], 1);
+}
+
+TEST_F(MenuControllerTest, Execute) {
+ Delegate delegate;
+ menus::SimpleMenuModel model(&delegate);
+ model.AddItem(1, ASCIIToUTF16("one"));
+ scoped_nsobject<MenuController> menu(
+ [[MenuController alloc] initWithModel:&model useWithPopUpButtonCell:NO]);
+ EXPECT_EQ([[menu menu] numberOfItems], 1);
+
+ // Fake selecting the menu item, we expect the delegate to be told to execute
+ // a command.
+ NSMenuItem* item = [[menu menu] itemAtIndex:0];
+ [[item target] performSelector:[item action] withObject:item];
+ EXPECT_EQ(delegate.execute_count_, 1);
+}
+
+void Validate(MenuController* controller, NSMenu* menu) {
+ for (int i = 0; i < [menu numberOfItems]; ++i) {
+ NSMenuItem* item = [menu itemAtIndex:i];
+ [controller validateUserInterfaceItem:item];
+ if ([item hasSubmenu])
+ Validate(controller, [item submenu]);
+ }
+}
+
+TEST_F(MenuControllerTest, Validate) {
+ Delegate delegate;
+ menus::SimpleMenuModel model(&delegate);
+ model.AddItem(1, ASCIIToUTF16("one"));
+ model.AddItem(2, ASCIIToUTF16("two"));
+ menus::SimpleMenuModel submodel(&delegate);
+ submodel.AddItem(2, ASCIIToUTF16("sub-one"));
+ model.AddSubMenuWithStringId(3, IDS_ZOOM_MENU, &submodel);
+
+ scoped_nsobject<MenuController> menu(
+ [[MenuController alloc] initWithModel:&model useWithPopUpButtonCell:NO]);
+ EXPECT_EQ([[menu menu] numberOfItems], 3);
+
+ Validate(menu.get(), [menu menu]);
+}
+
+TEST_F(MenuControllerTest, DefaultInitializer) {
+ Delegate delegate;
+ menus::SimpleMenuModel model(&delegate);
+ model.AddItem(1, ASCIIToUTF16("one"));
+ model.AddItem(2, ASCIIToUTF16("two"));
+ model.AddItem(3, ASCIIToUTF16("three"));
+
+ scoped_nsobject<MenuController> menu([[MenuController alloc] init]);
+ EXPECT_FALSE([menu menu]);
+
+ [menu setModel:&model];
+ [menu setUseWithPopUpButtonCell:NO];
+ EXPECT_TRUE([menu menu]);
+ EXPECT_EQ(3, [[menu menu] numberOfItems]);
+
+ // Check immutability.
+ model.AddItem(4, ASCIIToUTF16("four"));
+ EXPECT_EQ(3, [[menu menu] numberOfItems]);
+}
+
+// Test that menus with dynamic labels actually get updated.
+TEST_F(MenuControllerTest, Dynamic) {
+ DynamicDelegate delegate;
+
+ // Create a menu containing a single item whose label is "initial" and who has
+ // no icon.
+ string16 initial = ASCIIToUTF16("initial");
+ delegate.SetDynamicLabel(initial);
+ menus::SimpleMenuModel model(&delegate);
+ model.AddItem(1, ASCIIToUTF16("foo"));
+ scoped_nsobject<MenuController> menu(
+ [[MenuController alloc] initWithModel:&model useWithPopUpButtonCell:NO]);
+ EXPECT_EQ([[menu menu] numberOfItems], 1);
+ // Validate() simulates opening the menu - the item label/icon should be
+ // initialized after this so we can validate the menu contents.
+ Validate(menu.get(), [menu menu]);
+ NSMenuItem* item = [[menu menu] itemAtIndex:0];
+ // Item should have the "initial" label and no icon.
+ EXPECT_EQ(initial, base::SysNSStringToUTF16([item title]));
+ EXPECT_EQ(nil, [item image]);
+
+ // Now update the item to have a label of "second" and an icon.
+ string16 second = ASCIIToUTF16("second");
+ delegate.SetDynamicLabel(second);
+ SkBitmap* bitmap =
+ ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_THROBBER);
+ delegate.SetDynamicIcon(bitmap);
+ // Simulate opening the menu and validate that the item label + icon changes.
+ Validate(menu.get(), [menu menu]);
+ EXPECT_EQ(second, base::SysNSStringToUTF16([item title]));
+ EXPECT_TRUE([item image] != nil);
+
+ // Now get rid of the icon and make sure it goes away.
+ delegate.SetDynamicIcon(NULL);
+ Validate(menu.get(), [menu menu]);
+ EXPECT_EQ(second, base::SysNSStringToUTF16([item title]));
+ EXPECT_EQ(nil, [item image]);
+}
diff --git a/chrome/browser/ui/cocoa/menu_tracked_button.h b/chrome/browser/ui/cocoa/menu_tracked_button.h
new file mode 100644
index 0000000..3ac9bd0
--- /dev/null
+++ b/chrome/browser/ui/cocoa/menu_tracked_button.h
@@ -0,0 +1,43 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_MENU_TRACKED_BUTTON_H_
+#define CHROME_BROWSER_UI_COCOA_MENU_TRACKED_BUTTON_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+// A MenuTrackedButton is meant to be used whenever a button is placed inside
+// the custom view of an NSMenuItem. If the user opens the menu in a non-sticky
+// fashion (i.e. clicks, holds, and drags) and then releases the mouse over
+// a MenuTrackedButton, it will |-performClick:| itself.
+//
+// To create the hover state effects, there are two code paths. When the menu
+// is opened sticky, a tracking rect produces mouse entered/exit events that
+// allow for setting the cell's highlight property. When in a drag cycle,
+// however, the only event received is |-mouseDragged:|. Therefore, a
+// delayed selector is scheduled to poll the mouse location after each drag
+// event. This checks if the user is still over the button after the drag
+// events stop being sent, indicating either the user is hovering without
+// movement or that the mouse is no longer over the receiver.
+@interface MenuTrackedButton : NSButton {
+ @private
+ // If the button received a |-mouseEntered:| event. This short-circuits the
+ // custom drag tracking logic.
+ BOOL didEnter_;
+
+ // Whether or not the user is in a click-drag-release event sequence. If so
+ // and this receives a |-mouseUp:|, then this will click itself.
+ BOOL tracking_;
+
+ // In order to get hover effects when the menu is sticky-opened, a tracking
+ // rect needs to be installed on the button.
+ NSTrackingRectTag trackingTag_;
+}
+
+@property (nonatomic, readonly, getter=isTracking) BOOL tracking;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_MENU_TRACKED_BUTTON_H_
diff --git a/chrome/browser/ui/cocoa/menu_tracked_button.mm b/chrome/browser/ui/cocoa/menu_tracked_button.mm
new file mode 100644
index 0000000..37a79bb
--- /dev/null
+++ b/chrome/browser/ui/cocoa/menu_tracked_button.mm
@@ -0,0 +1,118 @@
+// 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 "chrome/browser/ui/cocoa/menu_tracked_button.h"
+
+#include <cmath>
+
+@interface MenuTrackedButton (Private)
+- (void)doHighlight:(BOOL)highlight;
+- (void)checkMouseInRect;
+- (NSRect)insetBounds;
+- (BOOL)shouldHighlightOnHover;
+@end
+
+@implementation MenuTrackedButton
+
+@synthesize tracking = tracking_;
+
+- (void)updateTrackingAreas {
+ [super updateTrackingAreas];
+ [self removeTrackingRect:trackingTag_];
+ trackingTag_ = [self addTrackingRect:NSInsetRect([self bounds], 1, 1)
+ owner:self
+ userData:NULL
+ assumeInside:NO];
+}
+
+- (void)viewDidMoveToWindow {
+ [self updateTrackingAreas];
+ [self doHighlight:NO];
+}
+
+- (void)mouseEntered:(NSEvent*)theEvent {
+ if (!tracking_) {
+ didEnter_ = YES;
+ }
+ [self doHighlight:YES];
+ [super mouseEntered:theEvent];
+}
+
+- (void)mouseExited:(NSEvent*)theEvent {
+ didEnter_ = NO;
+ tracking_ = NO;
+ [self doHighlight:NO];
+ [super mouseExited:theEvent];
+}
+
+- (void)mouseDragged:(NSEvent*)theEvent {
+ tracking_ = !didEnter_;
+
+ NSPoint point = [self convertPoint:[theEvent locationInWindow] fromView:nil];
+ BOOL highlight = NSPointInRect(point, [self insetBounds]);
+ [self doHighlight:highlight];
+
+ // If tracking in non-sticky mode, poll the mouse cursor to see if it is still
+ // over the button and thus needs to be highlighted. The delay is the
+ // smallest that still produces the effect while minimizing jank. Smaller
+ // values make the selector fire too close to immediately/now for the mouse to
+ // have moved off the receiver, and larger values produce lag.
+ if (tracking_ && [self shouldHighlightOnHover]) {
+ [self performSelector:@selector(checkMouseInRect)
+ withObject:nil
+ afterDelay:0.05
+ inModes:[NSArray arrayWithObject:NSEventTrackingRunLoopMode]];
+ }
+ [super mouseDragged:theEvent];
+}
+
+- (void)mouseUp:(NSEvent*)theEvent {
+ [self doHighlight:NO];
+ if (!tracking_) {
+ return [super mouseUp:theEvent];
+ }
+ [self performClick:self];
+ tracking_ = NO;
+}
+
+- (void)doHighlight:(BOOL)highlight {
+ if (![self shouldHighlightOnHover]) {
+ return;
+ }
+ [[self cell] setHighlighted:highlight];
+ [self setNeedsDisplay];
+}
+
+// Checks if the user's current mouse location is over this button. If it is,
+// the user is merely hovering here. If it is not, then disable the highlight.
+// If the menu is opened in non-sticky mode, the button does not receive enter/
+// exit mouse events and thus polling is necessary.
+- (void)checkMouseInRect {
+ NSPoint point = [NSEvent mouseLocation];
+ point = [[self window] convertScreenToBase:point];
+ point = [self convertPoint:point fromView:nil];
+ if (!NSPointInRect(point, [self insetBounds])) {
+ [self doHighlight:NO];
+ }
+}
+
+// Returns the bounds of the receiver slightly inset to avoid highlighting both
+// buttons in a pair that overlap.
+- (NSRect)insetBounds {
+ return NSInsetRect([self bounds], 2, 1);
+}
+
+- (BOOL)shouldHighlightOnHover {
+ // Apple does not define NSAppKitVersionNumber10_5 when using the 10.5 SDK.
+ // The Internets have come up with this solution.
+ #ifndef NSAppKitVersionNumber10_5
+ #define NSAppKitVersionNumber10_5 949
+ #endif
+
+ // There's a cell drawing bug in 10.5 that was fixed on 10.6. Hover states
+ // look terrible due to this, so disable highlighting on 10.5.
+ return std::floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/menu_tracked_button_unittest.mm b/chrome/browser/ui/cocoa/menu_tracked_button_unittest.mm
new file mode 100644
index 0000000..9b6f77a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/menu_tracked_button_unittest.mm
@@ -0,0 +1,117 @@
+// 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 "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/menu_tracked_button.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+// This test does not test what you'd think it does. Testing around event
+// tracking run loops is probably not worh the effort when the size of the
+// helper MakeEvent() is larger than the class being tested. If we ever figure
+// out a good way to test event tracking, this should be revisited.
+
+@interface MenuTrackedButtonTestReceiver : NSObject {
+ @public
+ BOOL didThat_;
+}
+- (void)doThat:(id)sender;
+@end
+@implementation MenuTrackedButtonTestReceiver
+- (void)doThat:(id)sender {
+ didThat_ = YES;
+}
+@end
+
+
+class MenuTrackedButtonTest : public CocoaTest {
+ public:
+ MenuTrackedButtonTest() : event_number_(0) {}
+
+ void SetUp() {
+ listener_.reset([[MenuTrackedButtonTestReceiver alloc] init]);
+ button_.reset(
+ [[MenuTrackedButton alloc] initWithFrame:NSMakeRect(10, 10, 50, 50)]);
+ [[test_window() contentView] addSubview:button()];
+ [button_ setTarget:listener()];
+ [button_ setAction:@selector(doThat:)];
+ }
+
+ // Creates an event of |type|, with |location| in test_window()'s coordinates.
+ NSEvent* MakeEvent(NSEventType type, NSPoint location) {
+ NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
+ location = [test_window() convertBaseToScreen:location];
+ if (type == NSMouseEntered || type == NSMouseExited) {
+ return [NSEvent enterExitEventWithType:type
+ location:location
+ modifierFlags:0
+ timestamp:now
+ windowNumber:[test_window() windowNumber]
+ context:nil
+ eventNumber:event_number_++
+ trackingNumber:0
+ userData:nil];
+ } else {
+ return [NSEvent mouseEventWithType:type
+ location:location
+ modifierFlags:0
+ timestamp:now
+ windowNumber:[test_window() windowNumber]
+ context:nil
+ eventNumber:event_number_++
+ clickCount:1
+ pressure:1.0];
+ }
+ }
+
+ MenuTrackedButtonTestReceiver* listener() { return listener_.get(); }
+ NSButton* button() { return button_.get(); }
+
+ scoped_nsobject<MenuTrackedButtonTestReceiver> listener_;
+ scoped_nsobject<MenuTrackedButton> button_;
+ NSInteger event_number_;
+};
+
+// User mouses over and then off.
+TEST_F(MenuTrackedButtonTest, DISABLED_EnterExit) {
+ [NSApp postEvent:MakeEvent(NSMouseEntered, NSMakePoint(11, 11)) atStart:YES];
+ [NSApp postEvent:MakeEvent(NSMouseExited, NSMakePoint(9, 9)) atStart:YES];
+ EXPECT_FALSE(listener()->didThat_);
+}
+
+// User mouses over, clicks, drags, and exits.
+TEST_F(MenuTrackedButtonTest, DISABLED_EnterDragExit) {
+ [NSApp postEvent:MakeEvent(NSMouseEntered, NSMakePoint(11, 11)) atStart:YES];
+ [NSApp postEvent:MakeEvent(NSLeftMouseDown, NSMakePoint(12, 12)) atStart:YES];
+ [NSApp postEvent:MakeEvent(NSLeftMouseDragged, NSMakePoint(13, 11))
+ atStart:YES];
+ [NSApp postEvent:MakeEvent(NSLeftMouseDragged, NSMakePoint(13, 10))
+ atStart:YES];
+ [NSApp postEvent:MakeEvent(NSMouseExited, NSMakePoint(13, 9)) atStart:YES];
+ EXPECT_FALSE(listener()->didThat_);
+}
+
+// User mouses over, clicks, drags, and releases.
+TEST_F(MenuTrackedButtonTest, DISABLED_EnterDragUp) {
+ [NSApp postEvent:MakeEvent(NSMouseEntered, NSMakePoint(11, 11)) atStart:YES];
+ [NSApp postEvent:MakeEvent(NSLeftMouseDown, NSMakePoint(12, 12)) atStart:YES];
+ [NSApp postEvent:MakeEvent(NSLeftMouseDragged, NSMakePoint(13, 13))
+ atStart:YES];
+ [NSApp postEvent:MakeEvent(NSLeftMouseUp, NSMakePoint(14, 14)) atStart:YES];
+ EXPECT_TRUE(listener()->didThat_);
+}
+
+// User drags in and releases.
+TEST_F(MenuTrackedButtonTest, DISABLED_DragUp) {
+ [NSApp postEvent:MakeEvent(NSLeftMouseDragged, NSMakePoint(11, 11))
+ atStart:YES];
+ [NSApp postEvent:MakeEvent(NSLeftMouseDragged, NSMakePoint(12, 12))
+ atStart:YES];
+ [NSApp postEvent:MakeEvent(NSLeftMouseUp, NSMakePoint(13, 13))
+ atStart:YES];
+ EXPECT_TRUE(listener()->didThat_);
+}
diff --git a/chrome/browser/ui/cocoa/menu_tracked_root_view.h b/chrome/browser/ui/cocoa/menu_tracked_root_view.h
new file mode 100644
index 0000000..c475783
--- /dev/null
+++ b/chrome/browser/ui/cocoa/menu_tracked_root_view.h
@@ -0,0 +1,25 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_MENU_TRACKED_ROOT_VIEW_H_
+#define CHROME_BROWSER_UI_COCOA_MENU_TRACKED_ROOT_VIEW_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+// An instance of MenuTrackedRootView should be the root of the view hierarchy
+// of the custom view of NSMenuItems. If the user opens the menu in a non-
+// sticky fashion (i.e. clicks, holds, and drags) and then releases the mouse
+// over the menu item, it will cancel tracking on the |[menuItem_ menu]|.
+@interface MenuTrackedRootView : NSView {
+ @private
+ // The menu item whose custom view's root view is an instance of this class.
+ NSMenuItem* menuItem_; // weak
+}
+
+@property (assign, nonatomic) NSMenuItem* menuItem;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_MENU_TRACKED_ROOT_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/menu_tracked_root_view.mm b/chrome/browser/ui/cocoa/menu_tracked_root_view.mm
new file mode 100644
index 0000000..29dd93d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/menu_tracked_root_view.mm
@@ -0,0 +1,15 @@
+// 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 "chrome/browser/ui/cocoa/menu_tracked_root_view.h"
+
+@implementation MenuTrackedRootView
+
+@synthesize menuItem = menuItem_;
+
+- (void)mouseUp:(NSEvent*)theEvent {
+ [[menuItem_ menu] cancelTracking];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/menu_tracked_root_view_unittest.mm b/chrome/browser/ui/cocoa/menu_tracked_root_view_unittest.mm
new file mode 100644
index 0000000..cb3eab1
--- /dev/null
+++ b/chrome/browser/ui/cocoa/menu_tracked_root_view_unittest.mm
@@ -0,0 +1,45 @@
+// 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 "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/menu_tracked_root_view.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+
+class MenuTrackedRootViewTest : public CocoaTest {
+ public:
+ void SetUp() {
+ CocoaTest::SetUp();
+ view_.reset([[MenuTrackedRootView alloc] init]);
+ }
+
+ scoped_nsobject<MenuTrackedRootView> view_;
+};
+
+TEST_F(MenuTrackedRootViewTest, MouseUp) {
+ id menu = [OCMockObject mockForClass:[NSMenu class]];
+ [[menu expect] cancelTracking];
+
+ id menuItem = [OCMockObject mockForClass:[NSMenuItem class]];
+ [[[menuItem stub] andReturn:menu] menu];
+
+ [view_ setMenuItem:menuItem];
+ NSEvent* event = [NSEvent mouseEventWithType:NSLeftMouseUp
+ location:NSMakePoint(42, 42)
+ modifierFlags:0
+ timestamp:0
+ windowNumber:[test_window() windowNumber]
+ context:nil
+ eventNumber:1
+ clickCount:1
+ pressure:1.0];
+ [view_ mouseUp:event];
+
+ [menu verify];
+ [menuItem verify];
+}
diff --git a/chrome/browser/ui/cocoa/multi_key_equivalent_button.h b/chrome/browser/ui/cocoa/multi_key_equivalent_button.h
new file mode 100644
index 0000000..d87c739
--- /dev/null
+++ b/chrome/browser/ui/cocoa/multi_key_equivalent_button.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_MULTI_KEY_EQUIVALENT_BUTTON_H_
+#define CHROME_BROWSER_UI_COCOA_MULTI_KEY_EQUIVALENT_BUTTON_H_
+#pragma once
+
+#import <AppKit/AppKit.h>
+
+#include <vector>
+
+struct KeyEquivalentAndModifierMask {
+ public:
+ KeyEquivalentAndModifierMask() : charCode(nil), mask(0) {}
+ NSString* charCode;
+ NSUInteger mask;
+};
+
+// MultiKeyEquivalentButton is an NSButton subclass that is capable of
+// responding to additional key equivalents. It will respond to the ordinary
+// NSButton key equivalent set by -setKeyEquivalent: and
+// -setKeyEquivalentModifierMask:, and it will also respond to any additional
+// equivalents provided to it in a KeyEquivalentAndModifierMask structure
+// passed to -addKeyEquivalent:.
+
+@interface MultiKeyEquivalentButton : NSButton {
+ @private
+ std::vector<KeyEquivalentAndModifierMask> extraKeys_;
+}
+
+- (void)addKeyEquivalent:(KeyEquivalentAndModifierMask)key;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_MULTI_KEY_EQUIVALENT_BUTTON_H_
diff --git a/chrome/browser/ui/cocoa/multi_key_equivalent_button.mm b/chrome/browser/ui/cocoa/multi_key_equivalent_button.mm
new file mode 100644
index 0000000..cfe0a69
--- /dev/null
+++ b/chrome/browser/ui/cocoa/multi_key_equivalent_button.mm
@@ -0,0 +1,33 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/multi_key_equivalent_button.h"
+
+@implementation MultiKeyEquivalentButton
+
+- (void)addKeyEquivalent:(KeyEquivalentAndModifierMask)key {
+ extraKeys_.push_back(key);
+}
+
+- (BOOL)performKeyEquivalent:(NSEvent*)event {
+ NSWindow* modalWindow = [NSApp modalWindow];
+ NSWindow* window = [self window];
+
+ if ([self isEnabled] &&
+ (!modalWindow || modalWindow == window || [window worksWhenModal])) {
+ for (size_t index = 0; index < extraKeys_.size(); ++index) {
+ KeyEquivalentAndModifierMask key = extraKeys_[index];
+ if (key.charCode &&
+ [key.charCode isEqualToString:[event charactersIgnoringModifiers]] &&
+ ([event modifierFlags] & key.mask) == key.mask) {
+ [self performClick:self];
+ return YES;
+ }
+ }
+ }
+
+ return [super performKeyEquivalent:event];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/new_tab_button.h b/chrome/browser/ui/cocoa/new_tab_button.h
new file mode 100644
index 0000000..9578cbf
--- /dev/null
+++ b/chrome/browser/ui/cocoa/new_tab_button.h
@@ -0,0 +1,28 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_NEW_TAB_BUTTON
+#define CHROME_BROWSER_UI_COCOA_NEW_TAB_BUTTON
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+
+// Overrides hit-test behavior to only accept clicks inside the image of the
+// button, not just inside the bounding box. This could be abstracted to general
+// use, but no other buttons are so irregularly shaped with respect to their
+// bounding box.
+
+@interface NewTabButton : NSButton {
+ @private
+ scoped_nsobject<NSBezierPath> imagePath_;
+}
+
+// Returns YES if the given point is over the button. |point| is in the
+// superview's coordinate system.
+- (BOOL)pointIsOverButton:(NSPoint)point;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_NEW_TAB_BUTTON
diff --git a/chrome/browser/ui/cocoa/new_tab_button.mm b/chrome/browser/ui/cocoa/new_tab_button.mm
new file mode 100644
index 0000000..6a97d3b
--- /dev/null
+++ b/chrome/browser/ui/cocoa/new_tab_button.mm
@@ -0,0 +1,42 @@
+// 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 "chrome/browser/ui/cocoa/new_tab_button.h"
+
+@implementation NewTabButton
+
+// Approximate the shape. It doesn't need to be perfect. This will need to be
+// updated if the size or shape of the icon ever changes.
+// TODO(pinkerton): use a click mask image instead of hard-coding points.
+- (NSBezierPath*)pathForButton {
+ if (imagePath_.get())
+ return imagePath_.get();
+
+ // Cache the path as it doesn't change (the coordinates are local to this
+ // view). There's not much point making constants for these, as they are
+ // custom.
+ imagePath_.reset([[NSBezierPath bezierPath] retain]);
+ [imagePath_ moveToPoint:NSMakePoint(9, 7)];
+ [imagePath_ lineToPoint:NSMakePoint(26, 7)];
+ [imagePath_ lineToPoint:NSMakePoint(33, 23)];
+ [imagePath_ lineToPoint:NSMakePoint(14, 23)];
+ [imagePath_ lineToPoint:NSMakePoint(9, 7)];
+ return imagePath_;
+}
+
+- (BOOL)pointIsOverButton:(NSPoint)point {
+ NSPoint localPoint = [self convertPoint:point fromView:[self superview]];
+ NSBezierPath* buttonPath = [self pathForButton];
+ return [buttonPath containsPoint:localPoint];
+}
+
+// Override to only accept clicks within the bounds of the defined path, not
+// the entire bounding box. |aPoint| is in the superview's coordinate system.
+- (NSView*)hitTest:(NSPoint)aPoint {
+ if ([self pointIsOverButton:aPoint])
+ return [super hitTest:aPoint];
+ return nil;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/notifications/balloon_controller.h b/chrome/browser/ui/cocoa/notifications/balloon_controller.h
new file mode 100644
index 0000000..61376b4
--- /dev/null
+++ b/chrome/browser/ui/cocoa/notifications/balloon_controller.h
@@ -0,0 +1,98 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_NOTIFICATIONS_BALLOON_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_NOTIFICATIONS_BALLOON_CONTROLLER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+
+class Balloon;
+@class BalloonContentViewCocoa;
+@class BalloonShelfViewCocoa;
+class BalloonViewHost;
+@class HoverImageButton;
+@class MenuController;
+class NotificationOptionsMenuModel;
+
+// The Balloon controller creates the view elements to display a
+// notification balloon, resize it if the HTML contents of that
+// balloon change, and move it when the collection of balloons is
+// modified.
+@interface BalloonController : NSWindowController<NSWindowDelegate> {
+ @private
+ // The balloon which represents the contents of this view. Weak pointer
+ // owned by the browser's NotificationUIManager.
+ Balloon* balloon_;
+
+ // The view that contains the contents of the notification
+ IBOutlet BalloonContentViewCocoa* htmlContainer_;
+
+ // The view that contains the controls of the notification
+ IBOutlet BalloonShelfViewCocoa* shelf_;
+
+ // The close button.
+ IBOutlet NSButton* closeButton_;
+
+ // Tracking region for the close button.
+ int closeButtonTrackingTag_;
+
+ // The origin label.
+ IBOutlet NSTextField* originLabel_;
+
+ // The options menu that appears when "options" is pressed.
+ IBOutlet HoverImageButton* optionsButton_;
+ scoped_ptr<NotificationOptionsMenuModel> menuModel_;
+ scoped_nsobject<MenuController> menuController_;
+
+ // The host for the renderer of the HTML contents.
+ scoped_ptr<BalloonViewHost> htmlContents_;
+
+ // The psn of the front application process.
+ ProcessSerialNumber frontProcessNum_;
+}
+
+// Initialize with a balloon object containing the notification data.
+- (id)initWithBalloon:(Balloon*)balloon;
+
+// Callback function for the close button.
+- (IBAction)closeButtonPressed:(id)sender;
+
+// Callback function for the options button.
+- (IBAction)optionsButtonPressed:(id)sender;
+
+// Callback function for the "revoke" option in the menu.
+- (IBAction)permissionRevoked:(id)sender;
+
+// Closes the balloon. Can be called by the bridge or by the close
+// button handler.
+- (void)closeBalloon:(bool)byUser;
+
+// Update the contents of the balloon to match the notification.
+- (void)updateContents;
+
+// Repositions the view to match the position and size of the balloon.
+// Called by the bridge when the size changes.
+- (void)repositionToBalloon;
+
+// The current size of the view, possibly subject to an animation completing.
+- (int)desiredTotalWidth;
+- (int)desiredTotalHeight;
+
+// The BalloonHost
+- (BalloonViewHost*)getHost;
+
+// Handle the event if it is for the balloon.
+- (BOOL)handleEvent:(NSEvent*)event;
+@end
+
+@interface BalloonController (UnitTesting)
+- (void)initializeHost;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_NOTIFICATIONS_BALLOON_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/notifications/balloon_controller.mm b/chrome/browser/ui/cocoa/notifications/balloon_controller.mm
new file mode 100644
index 0000000..f0d914e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/notifications/balloon_controller.mm
@@ -0,0 +1,241 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/notifications/balloon_controller.h"
+
+#include "app/l10n_util.h"
+#include "app/mac/nsimage_cache.h"
+#include "app/resource_bundle.h"
+#import "base/mac/cocoa_protocols.h"
+#include "base/mac_util.h"
+#import "base/scoped_nsobject.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/notifications/balloon.h"
+#include "chrome/browser/notifications/desktop_notification_service.h"
+#include "chrome/browser/notifications/notification.h"
+#include "chrome/browser/notifications/notification_options_menu_model.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#import "chrome/browser/ui/cocoa/hover_image_button.h"
+#import "chrome/browser/ui/cocoa/menu_controller.h"
+#import "chrome/browser/ui/cocoa/notifications/balloon_view.h"
+#include "chrome/browser/ui/cocoa/notifications/balloon_view_host_mac.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+
+namespace {
+
+// Margin, in pixels, between the notification frame and the contents
+// of the notification.
+const int kTopMargin = 1;
+const int kBottomMargin = 2;
+const int kLeftMargin = 2;
+const int kRightMargin = 2;
+
+} // namespace
+
+@interface BalloonController (Private)
+- (void)updateTrackingRect;
+@end
+
+@implementation BalloonController
+
+- (id)initWithBalloon:(Balloon*)balloon {
+ NSString* nibpath =
+ [mac_util::MainAppBundle() pathForResource:@"Notification"
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
+ balloon_ = balloon;
+ [self initializeHost];
+ menuModel_.reset(new NotificationOptionsMenuModel(balloon));
+ menuController_.reset([[MenuController alloc] initWithModel:menuModel_.get()
+ useWithPopUpButtonCell:NO]);
+ }
+ return self;
+}
+
+- (void)awakeFromNib {
+ DCHECK([self window]);
+ DCHECK_EQ(self, [[self window] delegate]);
+
+ NSImage* image = app::mac::GetCachedImageWithName(@"balloon_wrench.pdf");
+ [optionsButton_ setDefaultImage:image];
+ [optionsButton_ setDefaultOpacity:0.6];
+ [optionsButton_ setHoverImage:image];
+ [optionsButton_ setHoverOpacity:0.9];
+ [optionsButton_ setPressedImage:image];
+ [optionsButton_ setPressedOpacity:1.0];
+ [[optionsButton_ cell] setHighlightsBy:NSNoCellMask];
+
+ NSString* sourceLabelText = l10n_util::GetNSStringF(
+ IDS_NOTIFICATION_BALLOON_SOURCE_LABEL,
+ balloon_->notification().display_source());
+ [originLabel_ setStringValue:sourceLabelText];
+
+ // This condition is false in unit tests which have no RVH.
+ if (htmlContents_.get()) {
+ gfx::NativeView contents = htmlContents_->native_view();
+ [contents setFrame:NSMakeRect(kLeftMargin, kTopMargin, 0, 0)];
+ [[htmlContainer_ superview] addSubview:contents
+ positioned:NSWindowBelow
+ relativeTo:nil];
+ }
+
+ // Use the standard close button for a utility window.
+ closeButton_ = [NSWindow standardWindowButton:NSWindowCloseButton
+ forStyleMask:NSUtilityWindowMask];
+ NSRect frame = [closeButton_ frame];
+ [closeButton_ setFrame:NSMakeRect(6, 1, frame.size.width, frame.size.height)];
+ [closeButton_ setTarget:self];
+ [closeButton_ setAction:@selector(closeButtonPressed:)];
+ [shelf_ addSubview:closeButton_];
+ [self updateTrackingRect];
+
+ // Set the initial position without animating (the balloon should not
+ // yet be visible).
+ DCHECK(![[self window] isVisible]);
+ NSRect balloon_frame = NSMakeRect(balloon_->GetPosition().x(),
+ balloon_->GetPosition().y(),
+ [self desiredTotalWidth],
+ [self desiredTotalHeight]);
+ [[self window] setFrame:balloon_frame
+ display:NO];
+}
+
+- (void)updateTrackingRect {
+ if (closeButtonTrackingTag_)
+ [shelf_ removeTrackingRect:closeButtonTrackingTag_];
+
+ closeButtonTrackingTag_ = [shelf_ addTrackingRect:[closeButton_ frame]
+ owner:self
+ userData:nil
+ assumeInside:NO];
+}
+
+- (BOOL)handleEvent:(NSEvent*)event {
+ BOOL eventHandled = NO;
+ if ([event type] == NSLeftMouseDown) {
+ NSPoint mouse = [shelf_ convertPoint:[event locationInWindow]
+ fromView:nil];
+ if (NSPointInRect(mouse, [closeButton_ frame])) {
+ [closeButton_ mouseDown:event];
+
+ // Bring back the front process that is deactivated when we click the
+ // close button.
+ if (frontProcessNum_.highLongOfPSN || frontProcessNum_.lowLongOfPSN) {
+ SetFrontProcessWithOptions(&frontProcessNum_,
+ kSetFrontProcessFrontWindowOnly);
+ frontProcessNum_.highLongOfPSN = 0;
+ frontProcessNum_.lowLongOfPSN = 0;
+ }
+
+ eventHandled = YES;
+ } else if (NSPointInRect(mouse, [optionsButton_ frame])) {
+ [optionsButton_ mouseDown:event];
+ eventHandled = YES;
+ }
+ }
+ return eventHandled;
+}
+
+- (void) mouseEntered:(NSEvent*)event {
+ [[closeButton_ cell] setHighlighted:YES];
+
+ // Remember the current front process so that we can bring it back later.
+ if (!frontProcessNum_.highLongOfPSN && !frontProcessNum_.lowLongOfPSN)
+ GetFrontProcess(&frontProcessNum_);
+}
+
+- (void) mouseExited:(NSEvent*)event {
+ [[closeButton_ cell] setHighlighted:NO];
+
+ frontProcessNum_.highLongOfPSN = 0;
+ frontProcessNum_.lowLongOfPSN = 0;
+}
+
+- (IBAction)optionsButtonPressed:(id)sender {
+ [NSMenu popUpContextMenu:[menuController_ menu]
+ withEvent:[NSApp currentEvent]
+ forView:optionsButton_];
+}
+
+- (IBAction)permissionRevoked:(id)sender {
+ DesktopNotificationService* service =
+ balloon_->profile()->GetDesktopNotificationService();
+ service->DenyPermission(balloon_->notification().origin_url());
+}
+
+- (IBAction)closeButtonPressed:(id)sender {
+ [self closeBalloon:YES];
+ [self close];
+}
+
+- (void)close {
+ if (closeButtonTrackingTag_)
+ [shelf_ removeTrackingRect:closeButtonTrackingTag_];
+
+ [super close];
+}
+
+- (void)closeBalloon:(bool)byUser {
+ if (!balloon_)
+ return;
+ [self close];
+ if (htmlContents_.get())
+ htmlContents_->Shutdown();
+ if (balloon_)
+ balloon_->OnClose(byUser);
+ balloon_ = NULL;
+}
+
+- (void)updateContents {
+ DCHECK(htmlContents_.get()) << "BalloonView::Update called before Show";
+ if (htmlContents_->render_view_host())
+ htmlContents_->render_view_host()->NavigateToURL(
+ balloon_->notification().content_url());
+}
+
+- (void)repositionToBalloon {
+ DCHECK(balloon_);
+ int x = balloon_->GetPosition().x();
+ int y = balloon_->GetPosition().y();
+ int w = [self desiredTotalWidth];
+ int h = [self desiredTotalHeight];
+
+ if (htmlContents_.get())
+ htmlContents_->UpdateActualSize(balloon_->content_size());
+
+ [[[self window] animator] setFrame:NSMakeRect(x, y, w, h)
+ display:YES];
+}
+
+// Returns the total width the view should be to accommodate the balloon.
+- (int)desiredTotalWidth {
+ return (balloon_ ? balloon_->content_size().width() : 0) +
+ kLeftMargin + kRightMargin;
+}
+
+// Returns the total height the view should be to accommodate the balloon.
+- (int)desiredTotalHeight {
+ return (balloon_ ? balloon_->content_size().height() : 0) +
+ kTopMargin + kBottomMargin + [shelf_ frame].size.height;
+}
+
+// Returns the BalloonHost {
+- (BalloonViewHost*) getHost {
+ return htmlContents_.get();
+}
+
+// Initializes the renderer host showing the HTML contents.
+- (void)initializeHost {
+ htmlContents_.reset(new BalloonViewHost(balloon_));
+ htmlContents_->Init();
+}
+
+// NSWindowDelegate notification.
+- (void)windowWillClose:(NSNotification*)notif {
+ [self autorelease];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/notifications/balloon_controller_unittest.mm b/chrome/browser/ui/cocoa/notifications/balloon_controller_unittest.mm
new file mode 100644
index 0000000..a63a327
--- /dev/null
+++ b/chrome/browser/ui/cocoa/notifications/balloon_controller_unittest.mm
@@ -0,0 +1,113 @@
+// 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.
+
+#include "base/scoped_nsobject.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/notifications/balloon.h"
+#include "chrome/browser/notifications/balloon_collection.h"
+#include "chrome/browser/notifications/notification.h"
+#include "chrome/browser/renderer_host/test/test_render_view_host.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/notifications/balloon_controller.h"
+#include "chrome/test/testing_profile.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+
+// Subclass balloon controller and mock out the initialization of the RVH.
+@interface TestBalloonController : BalloonController {
+}
+- (void)initializeHost;
+@end
+
+@implementation TestBalloonController
+- (void)initializeHost {}
+@end
+
+namespace {
+
+// Use a dummy balloon collection for testing.
+class MockBalloonCollection : public BalloonCollection {
+ virtual void Add(const Notification& notification,
+ Profile* profile) {}
+ virtual bool RemoveById(const std::string& id) { return false; }
+ virtual bool RemoveBySourceOrigin(const GURL& origin) { return false; }
+ virtual void RemoveAll() {}
+ virtual bool HasSpace() const { return true; }
+ virtual void ResizeBalloon(Balloon* balloon, const gfx::Size& size) {};
+ virtual void DisplayChanged() {}
+ virtual void OnBalloonClosed(Balloon* source) {};
+ virtual const Balloons& GetActiveBalloons() {
+ NOTREACHED();
+ return balloons_;
+ }
+ private:
+ Balloons balloons_;
+};
+
+class BalloonControllerTest : public RenderViewHostTestHarness {
+ public:
+ BalloonControllerTest() :
+ ui_thread_(BrowserThread::UI, MessageLoop::current()),
+ io_thread_(BrowserThread::IO, MessageLoop::current()) {
+ }
+
+ virtual void SetUp() {
+ RenderViewHostTestHarness::SetUp();
+ CocoaTest::BootstrapCocoa();
+ profile_.reset(new TestingProfile());
+ profile_->CreateRequestContext();
+ browser_.reset(new Browser(Browser::TYPE_NORMAL, profile_.get()));
+ collection_.reset(new MockBalloonCollection());
+ }
+
+ virtual void TearDown() {
+ MessageLoop::current()->RunAllPending();
+ RenderViewHostTestHarness::TearDown();
+ }
+
+ protected:
+ BrowserThread ui_thread_;
+ BrowserThread io_thread_;
+ scoped_ptr<TestingProfile> profile_;
+ scoped_ptr<Browser> browser_;
+ scoped_ptr<BalloonCollection> collection_;
+};
+
+TEST_F(BalloonControllerTest, ShowAndCloseTest) {
+ Notification n(GURL("http://www.google.com"), GURL("http://www.google.com"),
+ ASCIIToUTF16("http://www.google.com"), string16(),
+ new NotificationObjectProxy(-1, -1, -1, false));
+ scoped_ptr<Balloon> balloon(
+ new Balloon(n, profile_.get(), collection_.get()));
+ balloon->SetPosition(gfx::Point(1, 1), false);
+ balloon->set_content_size(gfx::Size(100, 100));
+
+ BalloonController* controller =
+ [[TestBalloonController alloc] initWithBalloon:balloon.get()];
+
+ [controller showWindow:nil];
+ [controller closeBalloon:YES];
+}
+
+TEST_F(BalloonControllerTest, SizesTest) {
+ Notification n(GURL("http://www.google.com"), GURL("http://www.google.com"),
+ ASCIIToUTF16("http://www.google.com"), string16(),
+ new NotificationObjectProxy(-1, -1, -1, false));
+ scoped_ptr<Balloon> balloon(
+ new Balloon(n, profile_.get(), collection_.get()));
+ balloon->SetPosition(gfx::Point(1, 1), false);
+ balloon->set_content_size(gfx::Size(100, 100));
+
+ BalloonController* controller =
+ [[TestBalloonController alloc] initWithBalloon:balloon.get()];
+
+ [controller showWindow:nil];
+
+ EXPECT_TRUE([controller desiredTotalWidth] > 100);
+ EXPECT_TRUE([controller desiredTotalHeight] > 100);
+
+ [controller closeBalloon:YES];
+}
+
+}
diff --git a/chrome/browser/ui/cocoa/notifications/balloon_view.h b/chrome/browser/ui/cocoa/notifications/balloon_view.h
new file mode 100644
index 0000000..b742eaf
--- /dev/null
+++ b/chrome/browser/ui/cocoa/notifications/balloon_view.h
@@ -0,0 +1,28 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_NOTIFICATIONS_BALLOON_VIEW_H_
+#define CHROME_BROWSER_UI_COCOA_NOTIFICATIONS_BALLOON_VIEW_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+@interface BalloonWindow : NSWindow {
+}
+@end
+
+// This view class draws a frame around the HTML contents of a
+// notification balloon.
+@interface BalloonContentViewCocoa : NSView {
+}
+@end
+
+// This view class draws the shelf of a notification balloon,
+// containing the controls.
+@interface BalloonShelfViewCocoa : NSView {
+}
+@end
+
+
+#endif // CHROME_BROWSER_UI_COCOA_NOTIFICATIONS_BALLOON_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/notifications/balloon_view.mm b/chrome/browser/ui/cocoa/notifications/balloon_view.mm
new file mode 100644
index 0000000..e88331a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/notifications/balloon_view.mm
@@ -0,0 +1,84 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/notifications/balloon_view.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/basictypes.h"
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/notifications/balloon_controller.h"
+#import "third_party/GTM/AppKit/GTMNSBezierPath+RoundRect.h"
+
+namespace {
+
+const int kRoundedCornerSize = 6;
+
+} // namespace
+
+@implementation BalloonWindow
+- (id)initWithContentRect:(NSRect)contentRect
+ styleMask:(unsigned int)aStyle
+ backing:(NSBackingStoreType)bufferingType
+ defer:(BOOL)flag {
+ self = [super initWithContentRect:contentRect
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO];
+ if (self) {
+ [self setLevel:NSStatusWindowLevel];
+ [self setOpaque:NO];
+ [self setBackgroundColor:[NSColor clearColor]];
+ }
+ return self;
+}
+
+- (BOOL)canBecomeMainWindow {
+ return NO;
+}
+
+- (void)sendEvent:(NSEvent*)event {
+ // We do not want to bring chrome window to foreground when we click on close
+ // or option button. To do this, we have to intercept the event.
+ BalloonController* delegate =
+ static_cast<BalloonController*>([self delegate]);
+ if (![delegate handleEvent:event]) {
+ [super sendEvent:event];
+ }
+}
+@end
+
+@implementation BalloonShelfViewCocoa
+- (void)drawRect:(NSRect)rect {
+ NSBezierPath* path =
+ [NSBezierPath gtm_bezierPathWithRoundRect:[self bounds]
+ topLeftCornerRadius:kRoundedCornerSize
+ topRightCornerRadius:kRoundedCornerSize
+ bottomLeftCornerRadius:0.0
+ bottomRightCornerRadius:0.0];
+
+ [[NSColor colorWithCalibratedWhite:0.957 alpha:1.0] set];
+ [path fill];
+
+ [[NSColor colorWithCalibratedWhite:0.8 alpha:1.0] set];
+ NSPoint origin = [self bounds].origin;
+ [NSBezierPath strokeLineFromPoint:origin
+ toPoint:NSMakePoint(origin.x + NSWidth([self bounds]), origin.y)];
+}
+@end
+
+@implementation BalloonContentViewCocoa
+- (void)drawRect:(NSRect)rect {
+ rect = NSInsetRect([self bounds], 0.5, 0.5);
+ NSBezierPath* path =
+ [NSBezierPath gtm_bezierPathWithRoundRect:rect
+ topLeftCornerRadius:0.0
+ topRightCornerRadius:0.0
+ bottomLeftCornerRadius:kRoundedCornerSize
+ bottomRightCornerRadius:kRoundedCornerSize];
+ [[NSColor whiteColor] set];
+ [path setLineWidth:3];
+ [path stroke];
+}
+@end
diff --git a/chrome/browser/ui/cocoa/notifications/balloon_view_bridge.h b/chrome/browser/ui/cocoa/notifications/balloon_view_bridge.h
new file mode 100644
index 0000000..3dff871
--- /dev/null
+++ b/chrome/browser/ui/cocoa/notifications/balloon_view_bridge.h
@@ -0,0 +1,40 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_NOTIFICATIONS_BALLOON_VIEW_BRIDGE_H_
+#define CHROME_BROWSER_UI_COCOA_NOTIFICATIONS_BALLOON_VIEW_BRIDGE_H_
+#pragma once
+
+#include "chrome/browser/notifications/balloon.h"
+
+@class BalloonController;
+class BalloonHost;
+namespace gfx {
+class Size;
+}
+
+// Bridges from the cross-platform BalloonView interface to the Cocoa
+// controller which will draw the view on screen.
+class BalloonViewBridge : public BalloonView {
+ public:
+ BalloonViewBridge();
+ ~BalloonViewBridge();
+
+ // BalloonView interface.
+ virtual void Show(Balloon* balloon);
+ virtual void Update();
+ virtual void RepositionToBalloon();
+ virtual void Close(bool by_user);
+ virtual gfx::Size GetSize() const;
+ virtual BalloonHost* GetHost() const;
+
+ private:
+ // Weak pointer to the balloon controller which manages the UI.
+ // This object cleans itself up when its windows close.
+ BalloonController* controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(BalloonViewBridge);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_NOTIFICATIONS_BALLOON_VIEW_BRIDGE_H_
diff --git a/chrome/browser/ui/cocoa/notifications/balloon_view_bridge.mm b/chrome/browser/ui/cocoa/notifications/balloon_view_bridge.mm
new file mode 100644
index 0000000..cea53b1
--- /dev/null
+++ b/chrome/browser/ui/cocoa/notifications/balloon_view_bridge.mm
@@ -0,0 +1,48 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/notifications/balloon_view_bridge.h"
+
+#include "chrome/browser/ui/cocoa/notifications/balloon_controller.h"
+#import "chrome/browser/ui/cocoa/notifications/balloon_view_host_mac.h"
+#include "gfx/size.h"
+
+#import <Cocoa/Cocoa.h>
+
+BalloonViewBridge::BalloonViewBridge() :
+ controller_(NULL) {
+}
+
+BalloonViewBridge::~BalloonViewBridge() {
+}
+
+void BalloonViewBridge::Close(bool by_user) {
+ [controller_ closeBalloon:by_user];
+}
+
+gfx::Size BalloonViewBridge::GetSize() const {
+ if (controller_)
+ return gfx::Size([controller_ desiredTotalWidth],
+ [controller_ desiredTotalHeight]);
+ else
+ return gfx::Size();
+}
+
+void BalloonViewBridge::RepositionToBalloon() {
+ [controller_ repositionToBalloon];
+}
+
+void BalloonViewBridge::Show(Balloon* balloon) {
+ controller_ = [[BalloonController alloc] initWithBalloon:balloon];
+ [controller_ setShouldCascadeWindows:NO];
+ [controller_ showWindow:nil];
+}
+
+BalloonHost* BalloonViewBridge::GetHost() const {
+ return [controller_ getHost];
+}
+
+void BalloonViewBridge::Update() {
+ [controller_ updateContents];
+}
diff --git a/chrome/browser/ui/cocoa/notifications/balloon_view_host_mac.h b/chrome/browser/ui/cocoa/notifications/balloon_view_host_mac.h
new file mode 100644
index 0000000..a7bff8f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/notifications/balloon_view_host_mac.h
@@ -0,0 +1,42 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_NOTIFICATIONS_BALLOON_VIEW_HOST_MAC_H_
+#define CHROME_BROWSER_UI_COCOA_NOTIFICATIONS_BALLOON_VIEW_HOST_MAC_H_
+#pragma once
+
+#include "chrome/browser/notifications/balloon_host.h"
+
+class RenderWidgetHostView;
+class RenderWidgetHostViewMac;
+
+// BalloonViewHost class is a delegate to the renderer host for the HTML
+// notification. When initialized it creates a new RenderViewHost and loads
+// the contents of the toast into it. It also handles links within the toast,
+// loading them into a new tab.
+class BalloonViewHost : public BalloonHost {
+ public:
+ explicit BalloonViewHost(Balloon* balloon);
+
+ ~BalloonViewHost();
+
+ // Changes the size of the balloon.
+ void UpdateActualSize(const gfx::Size& new_size);
+
+ // Accessors.
+ gfx::NativeView native_view() const;
+
+ protected:
+ virtual void InitRenderWidgetHostView();
+ virtual RenderWidgetHostView* render_widget_host_view() const;
+
+ private:
+ // The Mac-specific widget host view. This is owned by its native view,
+ // which this class frees in its destructor.
+ RenderWidgetHostViewMac* render_widget_host_view_;
+
+ DISALLOW_COPY_AND_ASSIGN(BalloonViewHost);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_NOTIFICATIONS_BALLOON_VIEW_HOST_MAC_H_
diff --git a/chrome/browser/ui/cocoa/notifications/balloon_view_host_mac.mm b/chrome/browser/ui/cocoa/notifications/balloon_view_host_mac.mm
new file mode 100644
index 0000000..1f2c916
--- /dev/null
+++ b/chrome/browser/ui/cocoa/notifications/balloon_view_host_mac.mm
@@ -0,0 +1,39 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/notifications/balloon_view_host_mac.h"
+
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/renderer_host/render_widget_host_view_mac.h"
+
+BalloonViewHost::BalloonViewHost(Balloon* balloon)
+ : BalloonHost(balloon) {
+}
+
+BalloonViewHost::~BalloonViewHost() {
+ Shutdown();
+}
+
+void BalloonViewHost::UpdateActualSize(const gfx::Size& new_size) {
+ NSView* view = render_widget_host_view_->native_view();
+ NSRect frame = [view frame];
+ frame.size.width = new_size.width();
+ frame.size.height = new_size.height();
+
+ [view setFrame:frame];
+ [view setNeedsDisplay:YES];
+}
+
+gfx::NativeView BalloonViewHost::native_view() const {
+ return render_widget_host_view_->native_view();
+}
+
+void BalloonViewHost::InitRenderWidgetHostView() {
+ DCHECK(render_view_host_);
+ render_widget_host_view_ = new RenderWidgetHostViewMac(render_view_host_);
+}
+
+RenderWidgetHostView* BalloonViewHost::render_widget_host_view() const {
+ return render_widget_host_view_;
+}
diff --git a/chrome/browser/ui/cocoa/nsimage_cache_unittest.mm b/chrome/browser/ui/cocoa/nsimage_cache_unittest.mm
new file mode 100644
index 0000000..b00fb5b
--- /dev/null
+++ b/chrome/browser/ui/cocoa/nsimage_cache_unittest.mm
@@ -0,0 +1,77 @@
+// 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 "app/mac/nsimage_cache.h"
+#include "base/file_path.h"
+#include "base/mac_util.h"
+#include "base/path_service.h"
+#include "chrome/common/chrome_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+// This tests nsimage_cache, which lives in base/. The unit test is in
+// chrome/ because it depends on having a built-up Chrome present.
+
+namespace {
+
+class NSImageCacheTest : public PlatformTest {
+ public:
+ NSImageCacheTest() {
+ // Look in the framework bundle for resources.
+ FilePath path;
+ PathService::Get(base::DIR_EXE, &path);
+ path = path.Append(chrome::kFrameworkName);
+ mac_util::SetOverrideAppBundlePath(path);
+ }
+ virtual ~NSImageCacheTest() {
+ mac_util::SetOverrideAppBundle(nil);
+ }
+};
+
+TEST_F(NSImageCacheTest, LookupFound) {
+ EXPECT_TRUE(app::mac::GetCachedImageWithName(@"back_Template.pdf") != nil)
+ << "Failed to find the toolbar image?";
+}
+
+TEST_F(NSImageCacheTest, LookupCached) {
+ EXPECT_EQ(app::mac::GetCachedImageWithName(@"back_Template.pdf"),
+ app::mac::GetCachedImageWithName(@"back_Template.pdf"))
+ << "Didn't get the same NSImage back?";
+}
+
+TEST_F(NSImageCacheTest, LookupMiss) {
+ EXPECT_TRUE(app::mac::GetCachedImageWithName(@"should_not.exist") == nil)
+ << "There shouldn't be an image with this name?";
+}
+
+TEST_F(NSImageCacheTest, LookupFoundAndClear) {
+ NSImage *first = app::mac::GetCachedImageWithName(@"back_Template.pdf");
+ // Hang on to the first image so that the second one doesn't get allocated
+ // in the same location by (bad) luck.
+ [[first retain] autorelease];
+ EXPECT_TRUE(first != nil)
+ << "Failed to find the toolbar image?";
+ app::mac::ClearCachedImages();
+ NSImage *second = app::mac::GetCachedImageWithName(@"back_Template.pdf");
+ EXPECT_TRUE(second != nil)
+ << "Failed to find the toolbar image...again?";
+ EXPECT_NE(second, first)
+ << "how'd we get the same image after a cache clear?";
+}
+
+TEST_F(NSImageCacheTest, AutoTemplating) {
+ NSImage *templateImage =
+ app::mac::GetCachedImageWithName(@"back_Template.pdf");
+ EXPECT_TRUE([templateImage isTemplate] == YES)
+ << "Image ending in 'Template' should be marked as being a template";
+ NSImage *nonTemplateImage =
+ app::mac::GetCachedImageWithName(@"aliasCursor.png");
+ EXPECT_FALSE([nonTemplateImage isTemplate] == YES)
+ << "Image not ending in 'Template' should not be marked as being a "
+ "template";
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/nsmenuitem_additions.h b/chrome/browser/ui/cocoa/nsmenuitem_additions.h
new file mode 100644
index 0000000..289926a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/nsmenuitem_additions.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_NSMENUITEM_ADDITIONS_H_
+#define CHROME_BROWSER_UI_COCOA_NSMENUITEM_ADDITIONS_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+@interface NSMenuItem(ChromeAdditions)
+
+// Returns true exactly if the menu item would fire if it would be put into
+// a menu and then |menu performKeyEquivalent:event| was called.
+// This method always returns NO if the menu item is not enabled.
+- (BOOL)cr_firesForKeyEvent:(NSEvent*)event;
+
+// Like above method, but this method matches the key equivalent regardless of
+// the menu item's enable state.
+- (BOOL)cr_firesForKeyEventIfEnabled:(NSEvent*)event;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_NSMENUITEM_ADDITIONS_H_
diff --git a/chrome/browser/ui/cocoa/nsmenuitem_additions.mm b/chrome/browser/ui/cocoa/nsmenuitem_additions.mm
new file mode 100644
index 0000000..1799eb0
--- /dev/null
+++ b/chrome/browser/ui/cocoa/nsmenuitem_additions.mm
@@ -0,0 +1,106 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/nsmenuitem_additions.h"
+
+#include <Carbon/Carbon.h>
+
+#include "base/logging.h"
+
+@implementation NSMenuItem(ChromeAdditions)
+
+- (BOOL)cr_firesForKeyEvent:(NSEvent*)event {
+ if (![self isEnabled])
+ return NO;
+ return [self cr_firesForKeyEventIfEnabled:event];
+}
+
+- (BOOL)cr_firesForKeyEventIfEnabled:(NSEvent*)event {
+ DCHECK([event type] == NSKeyDown);
+ // In System Preferences->Keyboard->Keyboard Shortcuts, it is possible to add
+ // arbitrary keyboard shortcuts to applications. It is not documented how this
+ // works in detail, but |NSMenuItem| has a method |userKeyEquivalent| that
+ // sounds related.
+ // However, it looks like |userKeyEquivalent| is equal to |keyEquivalent| when
+ // a user shortcut is set in system preferences, i.e. Cocoa automatically
+ // sets/overwrites |keyEquivalent| as well. Hence, this method can ignore
+ // |userKeyEquivalent| and check |keyEquivalent| only.
+
+ // Menu item key equivalents are nearly all stored without modifiers. The
+ // exception is shift, which is included in the key and not in the modifiers
+ // for printable characters (but not for stuff like arrow keys etc).
+ NSString* eventString = [event charactersIgnoringModifiers];
+ NSUInteger eventModifiers =
+ [event modifierFlags] & NSDeviceIndependentModifierFlagsMask;
+
+ if ([eventString length] == 0 || [[self keyEquivalent] length] == 0)
+ return NO;
+
+ // Turns out esc never fires unless cmd or ctrl is down.
+ if ([event keyCode] == kVK_Escape &&
+ (eventModifiers & (NSControlKeyMask | NSCommandKeyMask)) == 0)
+ return NO;
+
+ // From the |NSMenuItem setKeyEquivalent:| documentation:
+ //
+ // If you want to specify the Backspace key as the key equivalent for a menu
+ // item, use a single character string with NSBackspaceCharacter (defined in
+ // NSText.h as 0x08) and for the Forward Delete key, use NSDeleteCharacter
+ // (defined in NSText.h as 0x7F). Note that these are not the same characters
+ // you get from an NSEvent key-down event when pressing those keys.
+ if ([[self keyEquivalent] characterAtIndex:0] == NSBackspaceCharacter
+ && [eventString characterAtIndex:0] == NSDeleteCharacter) {
+ unichar chr = NSBackspaceCharacter;
+ eventString = [NSString stringWithCharacters:&chr length:1];
+
+ // Make sure "shift" is not removed from modifiers below.
+ eventModifiers |= NSFunctionKeyMask;
+ }
+ if ([[self keyEquivalent] characterAtIndex:0] == NSDeleteCharacter &&
+ [eventString characterAtIndex:0] == NSDeleteFunctionKey) {
+ unichar chr = NSDeleteCharacter;
+ eventString = [NSString stringWithCharacters:&chr length:1];
+
+ // Make sure "shift" is not removed from modifiers below.
+ eventModifiers |= NSFunctionKeyMask;
+ }
+
+ // cmd-opt-a gives some weird char as characters and "a" as
+ // charactersWithoutModifiers with an US layout, but an "a" as characters and
+ // a weird char as "charactersWithoutModifiers" with a cyrillic layout. Oh,
+ // Cocoa! Instead of getting the current layout from Text Input Services,
+ // and then requesting the kTISPropertyUnicodeKeyLayoutData and looking in
+ // there, let's try a pragmatic hack.
+ if ([eventString characterAtIndex:0] > 0x7f &&
+ [[event characters] length] > 0 &&
+ [[event characters] characterAtIndex:0] <= 0x7f)
+ eventString = [event characters];
+
+ // When both |characters| and |charactersIgnoringModifiers| are ascii, we
+ // want to use |characters| if it's a character and
+ // |charactersIgnoringModifiers| else (on dvorak, cmd-shift-z should fire
+ // "cmd-:" instead of "cmd-;", but on dvorak-qwerty, cmd-shift-z should fire
+ // cmd-shift-z instead of cmd-:).
+ if ([eventString characterAtIndex:0] <= 0x7f &&
+ [[event characters] length] > 0 &&
+ [[event characters] characterAtIndex:0] <= 0x7f &&
+ isalpha([[event characters] characterAtIndex:0]))
+ eventString = [event characters];
+
+ // Clear shift key for printable characters.
+ if ((eventModifiers & (NSNumericPadKeyMask | NSFunctionKeyMask)) == 0 &&
+ [[self keyEquivalent] characterAtIndex:0] != '\r')
+ eventModifiers &= ~NSShiftKeyMask;
+
+ // Clear all non-interesting modifiers
+ eventModifiers &= NSCommandKeyMask |
+ NSControlKeyMask |
+ NSAlternateKeyMask |
+ NSShiftKeyMask;
+
+ return [eventString isEqualToString:[self keyEquivalent]]
+ && eventModifiers == [self keyEquivalentModifierMask];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/nsmenuitem_additions_unittest.mm b/chrome/browser/ui/cocoa/nsmenuitem_additions_unittest.mm
new file mode 100644
index 0000000..ecbf07d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/nsmenuitem_additions_unittest.mm
@@ -0,0 +1,351 @@
+// 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 "chrome/browser/ui/cocoa/nsmenuitem_additions.h"
+
+#include <Carbon/Carbon.h>
+
+#include <ostream>
+
+#include "base/scoped_nsobject.h"
+#include "base/sys_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+NSEvent* KeyEvent(const NSUInteger modifierFlags,
+ NSString* chars,
+ NSString* charsNoMods,
+ const NSUInteger keyCode) {
+ return [NSEvent keyEventWithType:NSKeyDown
+ location:NSZeroPoint
+ modifierFlags:modifierFlags
+ timestamp:0.0
+ windowNumber:0
+ context:nil
+ characters:chars
+ charactersIgnoringModifiers:charsNoMods
+ isARepeat:NO
+ keyCode:keyCode];
+}
+
+NSMenuItem* MenuItem(NSString* equiv, NSUInteger mask) {
+ NSMenuItem* item = [[[NSMenuItem alloc] initWithTitle:@""
+ action:NULL
+ keyEquivalent:@""] autorelease];
+ [item setKeyEquivalent:equiv];
+ [item setKeyEquivalentModifierMask:mask];
+ return item;
+}
+
+std::ostream& operator<<(std::ostream& out, NSObject* obj) {
+ return out << base::SysNSStringToUTF8([obj description]);
+}
+
+std::ostream& operator<<(std::ostream& out, NSMenuItem* item) {
+ return out << "NSMenuItem " << base::SysNSStringToUTF8([item keyEquivalent]);
+}
+
+void ExpectKeyFiresItemEq(bool result, NSEvent* key, NSMenuItem* item,
+ bool compareCocoa) {
+ EXPECT_EQ(result, [item cr_firesForKeyEvent:key]) << key << '\n' << item;
+
+ // Make sure that Cocoa does in fact agree with our expectations. However,
+ // in some cases cocoa behaves weirdly (if you create e.g. a new event that
+ // contains all fields of the event that you get when hitting cmd-a with a
+ // russion keyboard layout, the copy won't fire a menu item that has cmd-a as
+ // key equivalent, even though the original event would) and isn't a good
+ // oracle function.
+ if (compareCocoa) {
+ scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@"Menu!"]);
+ [menu setAutoenablesItems:NO];
+ EXPECT_FALSE([menu performKeyEquivalent:key]);
+ [menu addItem:item];
+ EXPECT_EQ(result, [menu performKeyEquivalent:key]) << key << '\n' << item;
+ }
+}
+
+void ExpectKeyFiresItem(
+ NSEvent* key, NSMenuItem* item, bool compareCocoa = true) {
+ ExpectKeyFiresItemEq(true, key, item, compareCocoa);
+}
+
+void ExpectKeyDoesntFireItem(
+ NSEvent* key, NSMenuItem* item, bool compareCocoa = true) {
+ ExpectKeyFiresItemEq(false, key, item, compareCocoa);
+}
+
+TEST(NSMenuItemAdditionsTest, TestFiresForKeyEvent) {
+ // These test cases were built by writing a small test app that has a
+ // MainMenu.xib with a given key equivalent set in Interface Builder and a
+ // some code that prints both the key equivalent that fires a menu item and
+ // the menu item's key equivalent and modifier masks. I then pasted those
+ // below. This was done with a US layout, unless otherwise noted. In the
+ // comments, "z" always means the physical "z" key on a US layout no matter
+ // what character that key produces.
+
+ NSMenuItem* item;
+ NSEvent* key;
+ unichar ch;
+ NSString* s;
+
+ // Sanity
+ item = MenuItem(@"", 0);
+ EXPECT_TRUE([item isEnabled]);
+
+ // a
+ key = KeyEvent(0x100, @"a", @"a", 0);
+ item = MenuItem(@"a", 0);
+ ExpectKeyFiresItem(key, item);
+ ExpectKeyDoesntFireItem(KeyEvent(0x20102, @"A", @"A", 0), item);
+
+ // Disabled menu item
+ key = KeyEvent(0x100, @"a", @"a", 0);
+ item = MenuItem(@"a", 0);
+ [item setEnabled:NO];
+ ExpectKeyDoesntFireItem(key, item, false);
+
+ // shift-a
+ key = KeyEvent(0x20102, @"A", @"A", 0);
+ item = MenuItem(@"A", 0);
+ ExpectKeyFiresItem(key, item);
+ ExpectKeyDoesntFireItem(KeyEvent(0x100, @"a", @"a", 0), item);
+
+ // cmd-opt-shift-a
+ key = KeyEvent(0x1a012a, @"\u00c5", @"A", 0);
+ item = MenuItem(@"A", 0x180000);
+ ExpectKeyFiresItem(key, item);
+
+ // cmd-opt-a
+ key = KeyEvent(0x18012a, @"\u00e5", @"a", 0);
+ item = MenuItem(@"a", 0x180000);
+ ExpectKeyFiresItem(key, item);
+
+ // cmd-=
+ key = KeyEvent(0x100110, @"=", @"=", 0x18);
+ item = MenuItem(@"=", 0x100000);
+ ExpectKeyFiresItem(key, item);
+
+ // cmd-shift-=
+ key = KeyEvent(0x12010a, @"=", @"+", 0x18);
+ item = MenuItem(@"+", 0x100000);
+ ExpectKeyFiresItem(key, item);
+
+ // Turns out Cocoa fires "+ 100108 + 18" if you hit cmd-= and the menu only
+ // has a cmd-+ shortcut. But that's transparent for |cr_firesForKeyEvent:|.
+
+ // ctrl-3
+ key = KeyEvent(0x40101, @"3", @"3", 0x14);
+ item = MenuItem(@"3", 0x40000);
+ ExpectKeyFiresItem(key, item);
+
+ // return
+ key = KeyEvent(0, @"\r", @"\r", 0x24);
+ item = MenuItem(@"\r", 0);
+ ExpectKeyFiresItem(key, item);
+
+ // shift-return
+ key = KeyEvent(0x20102, @"\r", @"\r", 0x24);
+ item = MenuItem(@"\r", 0x20000);
+ ExpectKeyFiresItem(key, item);
+
+ // shift-left
+ ch = NSLeftArrowFunctionKey;
+ s = [NSString stringWithCharacters:&ch length:1];
+ key = KeyEvent(0xa20102, s, s, 0x7b);
+ item = MenuItem(s, 0x20000);
+ ExpectKeyFiresItem(key, item);
+
+ // shift-f1 (with a layout that needs the fn key down for f1)
+ ch = NSF1FunctionKey;
+ s = [NSString stringWithCharacters:&ch length:1];
+ key = KeyEvent(0x820102, s, s, 0x7a);
+ item = MenuItem(s, 0x20000);
+ ExpectKeyFiresItem(key, item);
+
+ // esc
+ // Turns out this doesn't fire.
+ key = KeyEvent(0x100, @"\e", @"\e", 0x35);
+ item = MenuItem(@"\e", 0);
+ ExpectKeyDoesntFireItem(key,item, false);
+
+ // shift-esc
+ // Turns out this doesn't fire.
+ key = KeyEvent(0x20102, @"\e", @"\e", 0x35);
+ item = MenuItem(@"\e", 0x20000);
+ ExpectKeyDoesntFireItem(key,item, false);
+
+ // cmd-esc
+ key = KeyEvent(0x100108, @"\e", @"\e", 0x35);
+ item = MenuItem(@"\e", 0x100000);
+ ExpectKeyFiresItem(key, item);
+
+ // ctrl-esc
+ key = KeyEvent(0x40101, @"\e", @"\e", 0x35);
+ item = MenuItem(@"\e", 0x40000);
+ ExpectKeyFiresItem(key, item);
+
+ // delete ("backspace")
+ key = KeyEvent(0x100, @"\x7f", @"\x7f", 0x33);
+ item = MenuItem(@"\x08", 0);
+ ExpectKeyFiresItem(key, item, false);
+
+ // shift-delete
+ key = KeyEvent(0x20102, @"\x7f", @"\x7f", 0x33);
+ item = MenuItem(@"\x08", 0x20000);
+ ExpectKeyFiresItem(key, item, false);
+
+ // forwarddelete (fn-delete / fn-backspace)
+ ch = NSDeleteFunctionKey;
+ s = [NSString stringWithCharacters:&ch length:1];
+ key = KeyEvent(0x800100, s, s, 0x75);
+ item = MenuItem(@"\x7f", 0);
+ ExpectKeyFiresItem(key, item, false);
+
+ // shift-forwarddelete (shift-fn-delete / shift-fn-backspace)
+ ch = NSDeleteFunctionKey;
+ s = [NSString stringWithCharacters:&ch length:1];
+ key = KeyEvent(0x820102, s, s, 0x75);
+ item = MenuItem(@"\x7f", 0x20000);
+ ExpectKeyFiresItem(key, item, false);
+
+ // fn-left
+ ch = NSHomeFunctionKey;
+ s = [NSString stringWithCharacters:&ch length:1];
+ key = KeyEvent(0x800100, s, s, 0x73);
+ item = MenuItem(s, 0);
+ ExpectKeyFiresItem(key, item);
+
+ // cmd-left
+ ch = NSLeftArrowFunctionKey;
+ s = [NSString stringWithCharacters:&ch length:1];
+ key = KeyEvent(0xb00108, s, s, 0x7b);
+ item = MenuItem(s, 0x100000);
+ ExpectKeyFiresItem(key, item);
+
+ // Hitting the "a" key with a russian keyboard layout -- does not fire
+ // a menu item that has "a" as key equiv.
+ key = KeyEvent(0x100, @"\u0444", @"\u0444", 0);
+ item = MenuItem(@"a", 0);
+ ExpectKeyDoesntFireItem(key,item);
+
+ // cmd-a on a russion layout -- fires for a menu item with cmd-a as key equiv.
+ key = KeyEvent(0x100108, @"a", @"\u0444", 0);
+ item = MenuItem(@"a", 0x100000);
+ ExpectKeyFiresItem(key, item, false);
+
+ // cmd-z on US layout
+ key = KeyEvent(0x100108, @"z", @"z", 6);
+ item = MenuItem(@"z", 0x100000);
+ ExpectKeyFiresItem(key, item);
+
+ // cmd-y on german layout (has same keycode as cmd-z on us layout, shouldn't
+ // fire).
+ key = KeyEvent(0x100108, @"y", @"y", 6);
+ item = MenuItem(@"z", 0x100000);
+ ExpectKeyDoesntFireItem(key,item);
+
+ // cmd-z on german layout
+ key = KeyEvent(0x100108, @"z", @"z", 0x10);
+ item = MenuItem(@"z", 0x100000);
+ ExpectKeyFiresItem(key, item);
+
+ // fn-return (== enter)
+ key = KeyEvent(0x800100, @"\x3", @"\x3", 0x4c);
+ item = MenuItem(@"\r", 0);
+ ExpectKeyDoesntFireItem(key,item);
+
+ // cmd-z on dvorak layout (so that the key produces ';')
+ key = KeyEvent(0x100108, @";", @";", 6);
+ ExpectKeyDoesntFireItem(key, MenuItem(@"z", 0x100000));
+ ExpectKeyFiresItem(key, MenuItem(@";", 0x100000));
+
+ // cmd-z on dvorak qwerty layout (so that the key produces ';', but 'z' if
+ // cmd is down)
+ key = KeyEvent(0x100108, @"z", @";", 6);
+ ExpectKeyFiresItem(key, MenuItem(@"z", 0x100000), false);
+ ExpectKeyDoesntFireItem(key, MenuItem(@";", 0x100000), false);
+
+ // cmd-shift-z on dvorak layout (so that we get a ':')
+ key = KeyEvent(0x12010a, @";", @":", 6);
+ ExpectKeyFiresItem(key, MenuItem(@":", 0x100000));
+ ExpectKeyDoesntFireItem(key, MenuItem(@";", 0x100000));
+
+ // cmd-s with a serbian layout (just "s" produces something that looks a lot
+ // like "c" in some fonts, but is actually \u0441. cmd-s activates a menu item
+ // with key equivalent "s", not "c")
+ key = KeyEvent(0x100108, @"s", @"\u0441", 1);
+ ExpectKeyFiresItem(key, MenuItem(@"s", 0x100000), false);
+ ExpectKeyDoesntFireItem(key, MenuItem(@"c", 0x100000));
+}
+
+NSString* keyCodeToCharacter(NSUInteger keyCode,
+ EventModifiers modifiers,
+ TISInputSourceRef layout) {
+ CFDataRef uchr = (CFDataRef)TISGetInputSourceProperty(
+ layout, kTISPropertyUnicodeKeyLayoutData);
+ UCKeyboardLayout* keyLayout = (UCKeyboardLayout*)CFDataGetBytePtr(uchr);
+
+ UInt32 deadKeyState = 0;
+ OSStatus err = noErr;
+ UniCharCount maxStringLength = 4, actualStringLength;
+ UniChar unicodeString[4];
+ err = UCKeyTranslate(keyLayout,
+ (UInt16)keyCode,
+ kUCKeyActionDown,
+ modifiers,
+ LMGetKbdType(),
+ kUCKeyTranslateNoDeadKeysBit,
+ &deadKeyState,
+ maxStringLength,
+ &actualStringLength,
+ unicodeString);
+ assert(err == noErr);
+
+ CFStringRef temp = CFStringCreateWithCharacters(
+ kCFAllocatorDefault, unicodeString, 1);
+ return [(NSString*)temp autorelease];
+}
+
+TEST(NSMenuItemAdditionsTest, TestMOnDifferentLayouts) {
+ // There's one key -- "m" -- that has the same keycode on most keyboard
+ // layouts. This function tests a menu item with cmd-m as key equivalent
+ // can be fired on all layouts.
+ NSMenuItem* item = MenuItem(@"m", 0x100000);
+
+ NSDictionary* filter = [NSDictionary
+ dictionaryWithObject:(NSString*)kTISTypeKeyboardLayout
+ forKey:(NSString*)kTISPropertyInputSourceType];
+
+ // Docs say that including all layouts instead of just the active ones is
+ // slow, but there's no way around that.
+ NSArray* list = (NSArray*)TISCreateInputSourceList(
+ (CFDictionaryRef)filter, true);
+ for (id layout in list) {
+ TISInputSourceRef ref = (TISInputSourceRef)layout;
+
+ NSUInteger keyCode = 0x2e; // "m" on a US layout and most other layouts.
+
+ // On a few layouts, "m" has a different key code.
+ NSString* layoutId = (NSString*)TISGetInputSourceProperty(
+ ref, kTISPropertyInputSourceID);
+ if ([layoutId isEqualToString:@"com.apple.keylayout.Belgian"] ||
+ [layoutId isEqualToString:@"com.apple.keylayout.French"] ||
+ [layoutId isEqualToString:@"com.apple.keylayout.French-numerical"] ||
+ [layoutId isEqualToString:@"com.apple.keylayout.Italian"]) {
+ keyCode = 0x29;
+ } else if ([layoutId isEqualToString:@"com.apple.keylayout.Turkish"]) {
+ keyCode = 0x28;
+ } else if ([layoutId isEqualToString:@"com.apple.keylayout.Dvorak-Left"]) {
+ keyCode = 0x16;
+ } else if ([layoutId isEqualToString:@"com.apple.keylayout.Dvorak-Right"]) {
+ keyCode = 0x1a;
+ }
+
+ EventModifiers modifiers = cmdKey >> 8;
+ NSString* chars = keyCodeToCharacter(keyCode, modifiers, ref);
+ NSString* charsIgnoringMods = keyCodeToCharacter(keyCode, 0, ref);
+ NSEvent* key = KeyEvent(0x100000, chars, charsIgnoringMods, keyCode);
+ ExpectKeyFiresItem(key, item, false);
+ }
+ CFRelease(list);
+}
diff --git a/chrome/browser/ui/cocoa/nswindow_additions.h b/chrome/browser/ui/cocoa/nswindow_additions.h
new file mode 100644
index 0000000..9d79464
--- /dev/null
+++ b/chrome/browser/ui/cocoa/nswindow_additions.h
@@ -0,0 +1,25 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_NSWINDOW_ADDITIONS_H_
+#define CHROME_BROWSER_UI_COCOA_NSWINDOW_ADDITIONS_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+// ID of a Space. Starts at 1.
+typedef int CGSWorkspaceID;
+
+@interface NSWindow(ChromeAdditions)
+
+// Gets the Space that the window is currently on. YES on success, NO on
+// failure.
+- (BOOL)cr_workspace:(CGSWorkspaceID*)outWorkspace;
+
+// Moves the window to the given Space. YES on success, NO on failure.
+- (BOOL)cr_moveToWorkspace:(CGSWorkspaceID)workspace;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_NSWINDOW_ADDITIONS_H_
diff --git a/chrome/browser/ui/cocoa/nswindow_additions.mm b/chrome/browser/ui/cocoa/nswindow_additions.mm
new file mode 100644
index 0000000..f06af0d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/nswindow_additions.mm
@@ -0,0 +1,104 @@
+// 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 "chrome/browser/ui/cocoa/nswindow_additions.h"
+
+#include <dlfcn.h>
+
+#include "base/logging.h"
+
+typedef void* CGSConnectionID;
+typedef int CGSWindowID;
+typedef int CGSError;
+typedef int CGSWorkspaceID;
+
+// These are private APIs we look up at run time.
+typedef CGSConnectionID (*CGSDefaultConnectionFunc)(void);
+typedef CGSError (*CGSGetWindowWorkspaceFunc)(const CGSConnectionID cid,
+ CGSWindowID wid,
+ CGSWorkspaceID* workspace);
+typedef CGSError (*CGSMoveWorkspaceWindowListFunc)(const CGSConnectionID cid,
+ CGSWindowID* wids,
+ int count,
+ CGSWorkspaceID workspace);
+
+static CGSDefaultConnectionFunc sCGSDefaultConnection;
+static CGSGetWindowWorkspaceFunc sCGSGetWindowWorkspace;
+static CGSMoveWorkspaceWindowListFunc sCGSMoveWorkspaceWindowList;
+
+@implementation NSWindow(ChromeAdditions)
+
+// Looks up private Spaces APIs using dlsym.
+- (BOOL)cr_initializeWorkspaceAPIs {
+ static BOOL shouldInitialize = YES;
+ if (shouldInitialize) {
+ shouldInitialize = NO;
+
+ NSBundle* coreGraphicsBundle =
+ [NSBundle bundleWithIdentifier:@"com.apple.CoreGraphics"];
+ NSString* coreGraphicsPath = [[coreGraphicsBundle bundlePath]
+ stringByAppendingPathComponent:@"CoreGraphics"];
+ void* coreGraphicsLibrary = dlopen([coreGraphicsPath UTF8String],
+ RTLD_GLOBAL | RTLD_LAZY);
+
+ if (coreGraphicsLibrary) {
+ sCGSDefaultConnection =
+ (CGSDefaultConnectionFunc)dlsym(coreGraphicsLibrary,
+ "_CGSDefaultConnection");
+ if (!sCGSDefaultConnection) {
+ LOG(ERROR) << "Failed to lookup _CGSDefaultConnection API" << dlerror();
+ }
+ sCGSGetWindowWorkspace =
+ (CGSGetWindowWorkspaceFunc)dlsym(coreGraphicsLibrary,
+ "CGSGetWindowWorkspace");
+ if (!sCGSGetWindowWorkspace) {
+ LOG(ERROR) << "Failed to lookup CGSGetWindowWorkspace API" << dlerror();
+ }
+ sCGSMoveWorkspaceWindowList =
+ (CGSMoveWorkspaceWindowListFunc)dlsym(coreGraphicsLibrary,
+ "CGSMoveWorkspaceWindowList");
+ if (!sCGSMoveWorkspaceWindowList) {
+ LOG(ERROR) << "Failed to lookup CGSMoveWorkspaceWindowList API"
+ << dlerror();
+ }
+ } else {
+ LOG(ERROR) << "Failed to load CoreGraphics lib" << dlerror();
+ }
+ }
+
+ return sCGSDefaultConnection != NULL &&
+ sCGSGetWindowWorkspace != NULL &&
+ sCGSMoveWorkspaceWindowList != NULL;
+}
+
+- (BOOL)cr_workspace:(CGSWorkspaceID*)outWorkspace {
+ if (![self cr_initializeWorkspaceAPIs]) {
+ return NO;
+ }
+
+ // If this ASSERT fails then consider using CGSDefaultConnectionForThread()
+ // instead of CGSDefaultConnection().
+ DCHECK([NSThread isMainThread]);
+ CGSConnectionID cid = sCGSDefaultConnection();
+ CGSWindowID wid = [self windowNumber];
+ CGSError err = sCGSGetWindowWorkspace(cid, wid, outWorkspace);
+ return err == 0;
+}
+
+- (BOOL)cr_moveToWorkspace:(CGSWorkspaceID)workspace {
+ if (![self cr_initializeWorkspaceAPIs]) {
+ return NO;
+ }
+
+ // If this ASSERT fails then consider using CGSDefaultConnectionForThread()
+ // instead of CGSDefaultConnection().
+ DCHECK([NSThread isMainThread]);
+ CGSConnectionID cid = sCGSDefaultConnection();
+ CGSWindowID wid = [self windowNumber];
+ // CGSSetWorkspaceForWindow doesn't seem to work for some reason.
+ CGSError err = sCGSMoveWorkspaceWindowList(cid, &wid, 1, workspace);
+ return err == 0;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/objc_method_swizzle.h b/chrome/browser/ui/cocoa/objc_method_swizzle.h
new file mode 100644
index 0000000..2b94832
--- /dev/null
+++ b/chrome/browser/ui/cocoa/objc_method_swizzle.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_OBJC_METHOD_SWIZZLE_H_
+#define CHROME_BROWSER_UI_COCOA_OBJC_METHOD_SWIZZLE_H_
+#pragma once
+
+#import <objc/objc-class.h>
+
+// You should think twice every single time you use anything from this
+// namespace.
+namespace ObjcEvilDoers {
+
+// This is similar to class_getInstanceMethod(), except that it
+// returns NULL if |aClass| does not directly implement |aSelector|.
+Method GetImplementedInstanceMethod(Class aClass, SEL aSelector);
+
+// Exchanges the implementation of |originalSelector| and
+// |alternateSelector| within |aClass|. Both selectors must be
+// implemented directly by |aClass|, not inherited. The IMP returned
+// is for |originalSelector| (for purposes of forwarding).
+IMP SwizzleImplementedInstanceMethods(
+ Class aClass, const SEL originalSelector, const SEL alternateSelector);
+
+} // namespace ObjcEvilDoers
+
+#endif // CHROME_BROWSER_UI_COCOA_OBJC_METHOD_SWIZZLE_H_
diff --git a/chrome/browser/ui/cocoa/objc_method_swizzle.mm b/chrome/browser/ui/cocoa/objc_method_swizzle.mm
new file mode 100644
index 0000000..34f88a5
--- /dev/null
+++ b/chrome/browser/ui/cocoa/objc_method_swizzle.mm
@@ -0,0 +1,59 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/objc_method_swizzle.h"
+
+#import "base/logging.h"
+#import "base/scoped_nsobject.h"
+#import "chrome/app/breakpad_mac.h"
+
+namespace ObjcEvilDoers {
+
+Method GetImplementedInstanceMethod(Class aClass, SEL aSelector) {
+ Method method = NULL;
+ unsigned int methodCount = 0;
+ Method* methodList = class_copyMethodList(aClass, &methodCount);
+ if (methodList) {
+ for (unsigned int i = 0; i < methodCount; ++i) {
+ if (method_getName(methodList[i]) == aSelector) {
+ method = methodList[i];
+ break;
+ }
+ }
+ free(methodList);
+ }
+ return method;
+}
+
+IMP SwizzleImplementedInstanceMethods(
+ Class aClass, const SEL originalSelector, const SEL alternateSelector) {
+ // The methods must both be implemented by the target class, not
+ // inherited from a superclass.
+ Method original = GetImplementedInstanceMethod(aClass, originalSelector);
+ Method alternate = GetImplementedInstanceMethod(aClass, alternateSelector);
+ DCHECK(original);
+ DCHECK(alternate);
+ if (!original || !alternate) {
+ return NULL;
+ }
+
+ // The argument and return types must match exactly.
+ const char* originalTypes = method_getTypeEncoding(original);
+ const char* alternateTypes = method_getTypeEncoding(alternate);
+ DCHECK(originalTypes);
+ DCHECK(alternateTypes);
+ DCHECK(0 == strcmp(originalTypes, alternateTypes));
+ if (!originalTypes || !alternateTypes ||
+ strcmp(originalTypes, alternateTypes)) {
+ return NULL;
+ }
+
+ IMP ret = method_getImplementation(original);
+ if (ret) {
+ method_exchangeImplementations(original, alternate);
+ }
+ return ret;
+}
+
+} // namespace ObjcEvilDoers
diff --git a/chrome/browser/ui/cocoa/objc_method_swizzle_unittest.mm b/chrome/browser/ui/cocoa/objc_method_swizzle_unittest.mm
new file mode 100644
index 0000000..1641741
--- /dev/null
+++ b/chrome/browser/ui/cocoa/objc_method_swizzle_unittest.mm
@@ -0,0 +1,76 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/objc_method_swizzle.h"
+
+#include "base/scoped_nsobject.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+@interface ObjcMethodSwizzleTest : NSObject
+- (id)self;
+
+- (NSInteger)one;
+- (NSInteger)two;
+@end
+
+@implementation ObjcMethodSwizzleTest : NSObject
+- (id)self {
+ return [super self];
+}
+
+- (NSInteger)one {
+ return 1;
+}
+- (NSInteger)two {
+ return 2;
+}
+@end
+
+@interface ObjcMethodSwizzleTest (ObjcMethodSwizzleTestCategory)
+- (NSUInteger)hash;
+@end
+
+@implementation ObjcMethodSwizzleTest (ObjcMethodSwizzleTestCategory)
+- (NSUInteger)hash {
+ return [super hash];
+}
+@end
+
+namespace ObjcEvilDoers {
+
+TEST(ObjcMethodSwizzleTest, GetImplementedInstanceMethod) {
+ EXPECT_EQ(class_getInstanceMethod([NSObject class], @selector(dealloc)),
+ GetImplementedInstanceMethod([NSObject class], @selector(dealloc)));
+ EXPECT_EQ(class_getInstanceMethod([NSObject class], @selector(self)),
+ GetImplementedInstanceMethod([NSObject class], @selector(self)));
+ EXPECT_EQ(class_getInstanceMethod([NSObject class], @selector(hash)),
+ GetImplementedInstanceMethod([NSObject class], @selector(hash)));
+
+ Class testClass = [ObjcMethodSwizzleTest class];
+ EXPECT_EQ(class_getInstanceMethod(testClass, @selector(self)),
+ GetImplementedInstanceMethod(testClass, @selector(self)));
+ EXPECT_NE(class_getInstanceMethod([NSObject class], @selector(self)),
+ class_getInstanceMethod(testClass, @selector(self)));
+
+ EXPECT_TRUE(class_getInstanceMethod(testClass, @selector(dealloc)));
+ EXPECT_FALSE(GetImplementedInstanceMethod(testClass, @selector(dealloc)));
+}
+
+TEST(ObjcMethodSwizzleTest, SwizzleImplementedInstanceMethods) {
+ scoped_nsobject<ObjcMethodSwizzleTest> object(
+ [[ObjcMethodSwizzleTest alloc] init]);
+ EXPECT_EQ([object one], 1);
+ EXPECT_EQ([object two], 2);
+
+ Class testClass = [object class];
+ SwizzleImplementedInstanceMethods(testClass, @selector(one), @selector(two));
+ EXPECT_EQ([object one], 2);
+ EXPECT_EQ([object two], 1);
+
+ SwizzleImplementedInstanceMethods(testClass, @selector(one), @selector(two));
+ EXPECT_EQ([object one], 1);
+ EXPECT_EQ([object two], 2);
+}
+
+} // namespace ObjcEvilDoers
diff --git a/chrome/browser/ui/cocoa/objc_zombie.h b/chrome/browser/ui/cocoa/objc_zombie.h
new file mode 100644
index 0000000..714409e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/objc_zombie.h
@@ -0,0 +1,39 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_NSOBJECT_ZOMBIE_H_
+#define CHROME_BROWSER_UI_COCOA_NSOBJECT_ZOMBIE_H_
+#pragma once
+
+#import <Foundation/Foundation.h>
+
+// You should think twice every single time you use anything from this
+// namespace.
+namespace ObjcEvilDoers {
+
+// Enable zombie object debugging. This implements a variant of Apple's
+// NSZombieEnabled which can help expose use-after-free errors where messages
+// are sent to freed Objective-C objects in production builds.
+//
+// Returns NO if it fails to enable.
+//
+// When |zombieAllObjects| is YES, all objects inheriting from
+// NSObject become zombies on -dealloc. If NO, -shouldBecomeCrZombie
+// is queried to determine whether to make the object a zombie.
+//
+// |zombieCount| controls how many zombies to store before freeing the
+// oldest. Set to 0 to free objects immediately after making them
+// zombies.
+BOOL ZombieEnable(BOOL zombieAllObjects, size_t zombieCount);
+
+// Disable zombies.
+void ZombieDisable();
+
+} // namespace ObjcEvilDoers
+
+@interface NSObject (CrZombie)
+- (BOOL)shouldBecomeCrZombie;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_NSOBJECT_ZOMBIE_H_
diff --git a/chrome/browser/ui/cocoa/objc_zombie.mm b/chrome/browser/ui/cocoa/objc_zombie.mm
new file mode 100644
index 0000000..6802fd2
--- /dev/null
+++ b/chrome/browser/ui/cocoa/objc_zombie.mm
@@ -0,0 +1,414 @@
+// 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 "chrome/browser/ui/cocoa/objc_zombie.h"
+
+#include <dlfcn.h>
+#include <mach-o/dyld.h>
+#include <mach-o/nlist.h>
+
+#import <objc/objc-class.h>
+
+#include "base/lock.h"
+#include "base/logging.h"
+#import "chrome/app/breakpad_mac.h"
+#import "chrome/browser/ui/cocoa/objc_method_swizzle.h"
+
+// Deallocated objects are re-classed as |CrZombie|. No superclass
+// because then the class would have to override many/most of the
+// inherited methods (|NSObject| is like a category magnet!).
+@interface CrZombie {
+ Class isa;
+}
+@end
+
+// Objects with enough space are made into "fat" zombies, which
+// directly remember which class they were until reallocated.
+@interface CrFatZombie : CrZombie {
+ @public
+ Class wasa;
+}
+@end
+
+namespace {
+
+// |object_cxxDestruct()| is an Objective-C runtime function which
+// traverses the object's class tree for ".cxxdestruct" methods which
+// are run to call C++ destructors as part of |-dealloc|. The
+// function is not public, so must be looked up using nlist.
+typedef void DestructFn(id obj);
+DestructFn* g_object_cxxDestruct = NULL;
+
+// The original implementation for |-[NSObject dealloc]|.
+IMP g_originalDeallocIMP = NULL;
+
+// Classes which freed objects become. |g_fatZombieSize| is the
+// minimum object size which can be made into a fat zombie (which can
+// remember which class it was before free, even after falling off the
+// treadmill).
+Class g_zombieClass = Nil; // cached [CrZombie class]
+Class g_fatZombieClass = Nil; // cached [CrFatZombie class]
+size_t g_fatZombieSize = 0;
+
+// Whether to zombie all freed objects, or only those which return YES
+// from |-shouldBecomeCrZombie|.
+BOOL g_zombieAllObjects = NO;
+
+// Protects |g_zombieCount|, |g_zombieIndex|, and |g_zombies|.
+Lock lock_;
+
+// How many zombies to keep before freeing, and the current head of
+// the circular buffer.
+size_t g_zombieCount = 0;
+size_t g_zombieIndex = 0;
+
+typedef struct {
+ id object; // The zombied object.
+ Class wasa; // Value of |object->isa| before we replaced it.
+} ZombieRecord;
+
+ZombieRecord* g_zombies = NULL;
+
+// Lookup the private |object_cxxDestruct| function and return a
+// pointer to it. Returns |NULL| on failure.
+DestructFn* LookupObjectCxxDestruct() {
+#if ARCH_CPU_64_BITS
+ // TODO(shess): Port to 64-bit. I believe using struct nlist_64
+ // will suffice. http://crbug.com/44021 .
+ NOTIMPLEMENTED();
+ return NULL;
+#endif
+
+ struct nlist nl[3];
+ bzero(&nl, sizeof(nl));
+
+ nl[0].n_un.n_name = (char*)"_object_cxxDestruct";
+
+ // My ability to calculate the base for offsets is apparently poor.
+ // Use |class_addIvar| as a known reference point.
+ nl[1].n_un.n_name = (char*)"_class_addIvar";
+
+ if (nlist("/usr/lib/libobjc.dylib", nl) < 0 ||
+ nl[0].n_type == N_UNDF || nl[1].n_type == N_UNDF)
+ return NULL;
+
+ return (DestructFn*)((char*)&class_addIvar - nl[1].n_value + nl[0].n_value);
+}
+
+// Replacement |-dealloc| which turns objects into zombies and places
+// them into |g_zombies| to be freed later.
+void ZombieDealloc(id self, SEL _cmd) {
+ // This code should only be called when it is implementing |-dealloc|.
+ DCHECK_EQ(_cmd, @selector(dealloc));
+
+ // Use the original |-dealloc| if the object doesn't wish to be
+ // zombied.
+ if (!g_zombieAllObjects && ![self shouldBecomeCrZombie]) {
+ g_originalDeallocIMP(self, _cmd);
+ return;
+ }
+
+ // Use the original |-dealloc| if |object_cxxDestruct| was never
+ // initialized, because otherwise C++ destructors won't be called.
+ // This case should be impossible, but doing it wrong would cause
+ // terrible problems.
+ DCHECK(g_object_cxxDestruct);
+ if (!g_object_cxxDestruct) {
+ g_originalDeallocIMP(self, _cmd);
+ return;
+ }
+
+ Class wasa = object_getClass(self);
+ const size_t size = class_getInstanceSize(wasa);
+
+ // Destroy the instance by calling C++ destructors and clearing it
+ // to something unlikely to work well if someone references it.
+ (*g_object_cxxDestruct)(self);
+ memset(self, '!', size);
+
+ // If the instance is big enough, make it into a fat zombie and have
+ // it remember the old |isa|. Otherwise make it a regular zombie.
+ // Setting |isa| rather than using |object_setClass()| because that
+ // function is implemented with a memory barrier. The runtime's
+ // |_internal_object_dispose()| (in objc-class.m) does this, so it
+ // should be safe (messaging free'd objects shouldn't be expected to
+ // be thread-safe in the first place).
+ if (size >= g_fatZombieSize) {
+ self->isa = g_fatZombieClass;
+ static_cast<CrFatZombie*>(self)->wasa = wasa;
+ } else {
+ self->isa = g_zombieClass;
+ }
+
+ // The new record to swap into |g_zombies|. If |g_zombieCount| is
+ // zero, then |self| will be freed immediately.
+ ZombieRecord zombieToFree = {self, wasa};
+
+ // Don't involve the lock when creating zombies without a treadmill.
+ if (g_zombieCount > 0) {
+ AutoLock pin(lock_);
+
+ // Check the count again in a thread-safe manner.
+ if (g_zombieCount > 0) {
+ // Put the current object on the treadmill and keep the previous
+ // occupant.
+ std::swap(zombieToFree, g_zombies[g_zombieIndex]);
+
+ // Bump the index forward.
+ g_zombieIndex = (g_zombieIndex + 1) % g_zombieCount;
+ }
+ }
+
+ // Do the free out here to prevent any chance of deadlock.
+ if (zombieToFree.object)
+ free(zombieToFree.object);
+}
+
+// Attempt to determine the original class of zombie |object|.
+Class ZombieWasa(id object) {
+ // Fat zombies can hold onto their |wasa| past the point where the
+ // object was actually freed. Note that to arrive here at all,
+ // |object|'s memory must still be accessible.
+ if (object_getClass(object) == g_fatZombieClass)
+ return static_cast<CrFatZombie*>(object)->wasa;
+
+ // For instances which weren't big enough to store |wasa|, check if
+ // the object is still on the treadmill.
+ AutoLock pin(lock_);
+ for (size_t i=0; i < g_zombieCount; ++i) {
+ if (g_zombies[i].object == object)
+ return g_zombies[i].wasa;
+ }
+
+ return Nil;
+}
+
+// Log a message to a freed object. |wasa| is the object's original
+// class. |aSelector| is the selector which the calling code was
+// attempting to send. |viaSelector| is the selector of the
+// dispatch-related method which is being invoked to send |aSelector|
+// (for instance, -respondsToSelector:).
+void ZombieObjectCrash(id object, SEL aSelector, SEL viaSelector) {
+ Class wasa = ZombieWasa(object);
+ const char* wasaName = (wasa ? class_getName(wasa) : "<unknown>");
+ NSString* aString =
+ [NSString stringWithFormat:@"Zombie <%s: %p> received -%s",
+ wasaName, object, sel_getName(aSelector)];
+ if (viaSelector != NULL) {
+ const char* viaName = sel_getName(viaSelector);
+ aString = [aString stringByAppendingFormat:@" (via -%s)", viaName];
+ }
+
+ // Set a value for breakpad to report, then crash.
+ SetCrashKeyValue(@"zombie", aString);
+ LOG(ERROR) << [aString UTF8String];
+
+ // This is how about:crash is implemented. Using instead of
+ // |DebugUtil::BreakDebugger()| or |LOG(FATAL)| to make the top of
+ // stack more immediately obvious in crash dumps.
+ int* zero = NULL;
+ *zero = 0;
+}
+
+// Initialize our globals, returning YES on success.
+BOOL ZombieInit() {
+ static BOOL initialized = NO;
+ if (initialized)
+ return YES;
+
+ Class rootClass = [NSObject class];
+
+ g_object_cxxDestruct = LookupObjectCxxDestruct();
+ g_originalDeallocIMP =
+ class_getMethodImplementation(rootClass, @selector(dealloc));
+ // objc_getClass() so CrZombie doesn't need +class.
+ g_zombieClass = objc_getClass("CrZombie");
+ g_fatZombieClass = objc_getClass("CrFatZombie");
+ g_fatZombieSize = class_getInstanceSize(g_fatZombieClass);
+
+ if (!g_object_cxxDestruct || !g_originalDeallocIMP ||
+ !g_zombieClass || !g_fatZombieClass)
+ return NO;
+
+ initialized = YES;
+ return YES;
+}
+
+} // namespace
+
+@implementation CrZombie
+
+// The Objective-C runtime needs to be able to call this successfully.
++ (void)initialize {
+}
+
+// Any method not explicitly defined will end up here, forcing a
+// crash.
+- (id)forwardingTargetForSelector:(SEL)aSelector {
+ ZombieObjectCrash(self, aSelector, NULL);
+ return nil;
+}
+
+// Override a few methods often used for dynamic dispatch to log the
+// message the caller is attempting to send, rather than the utility
+// method being used to send it.
+- (BOOL)respondsToSelector:(SEL)aSelector {
+ ZombieObjectCrash(self, aSelector, _cmd);
+ return NO;
+}
+
+- (id)performSelector:(SEL)aSelector {
+ ZombieObjectCrash(self, aSelector, _cmd);
+ return nil;
+}
+
+- (id)performSelector:(SEL)aSelector withObject:(id)anObject {
+ ZombieObjectCrash(self, aSelector, _cmd);
+ return nil;
+}
+
+- (id)performSelector:(SEL)aSelector
+ withObject:(id)anObject
+ withObject:(id)anotherObject {
+ ZombieObjectCrash(self, aSelector, _cmd);
+ return nil;
+}
+
+- (void)performSelector:(SEL)aSelector
+ withObject:(id)anArgument
+ afterDelay:(NSTimeInterval)delay {
+ ZombieObjectCrash(self, aSelector, _cmd);
+}
+
+@end
+
+@implementation CrFatZombie
+
+// This implementation intentionally left empty.
+
+@end
+
+@implementation NSObject (CrZombie)
+
+- (BOOL)shouldBecomeCrZombie {
+ return NO;
+}
+
+@end
+
+namespace ObjcEvilDoers {
+
+BOOL ZombieEnable(BOOL zombieAllObjects,
+ size_t zombieCount) {
+ // Only allow enable/disable on the main thread, just to keep things
+ // simple.
+ CHECK([NSThread isMainThread]);
+
+ if (!ZombieInit())
+ return NO;
+
+ g_zombieAllObjects = zombieAllObjects;
+
+ // Replace the implementation of -[NSObject dealloc].
+ Method m = class_getInstanceMethod([NSObject class], @selector(dealloc));
+ if (!m)
+ return NO;
+
+ const IMP prevDeallocIMP = method_setImplementation(m, (IMP)ZombieDealloc);
+ DCHECK(prevDeallocIMP == g_originalDeallocIMP ||
+ prevDeallocIMP == (IMP)ZombieDealloc);
+
+ // Grab the current set of zombies. This is thread-safe because
+ // only the main thread can change these.
+ const size_t oldCount = g_zombieCount;
+ ZombieRecord* oldZombies = g_zombies;
+
+ {
+ AutoLock pin(lock_);
+
+ // Save the old index in case zombies need to be transferred.
+ size_t oldIndex = g_zombieIndex;
+
+ // Create the new zombie treadmill, disabling zombies in case of
+ // failure.
+ g_zombieIndex = 0;
+ g_zombieCount = zombieCount;
+ g_zombies = NULL;
+ if (g_zombieCount) {
+ g_zombies =
+ static_cast<ZombieRecord*>(calloc(g_zombieCount, sizeof(*g_zombies)));
+ if (!g_zombies) {
+ NOTREACHED();
+ g_zombies = oldZombies;
+ g_zombieCount = oldCount;
+ g_zombieIndex = oldIndex;
+ ZombieDisable();
+ return NO;
+ }
+ }
+
+ // If the count is changing, allow some of the zombies to continue
+ // shambling forward.
+ const size_t sharedCount = std::min(oldCount, zombieCount);
+ if (sharedCount) {
+ // Get index of the first shared zombie.
+ oldIndex = (oldIndex + oldCount - sharedCount) % oldCount;
+
+ for (; g_zombieIndex < sharedCount; ++ g_zombieIndex) {
+ DCHECK_LT(g_zombieIndex, g_zombieCount);
+ DCHECK_LT(oldIndex, oldCount);
+ std::swap(g_zombies[g_zombieIndex], oldZombies[oldIndex]);
+ oldIndex = (oldIndex + 1) % oldCount;
+ }
+ g_zombieIndex %= g_zombieCount;
+ }
+ }
+
+ // Free the old treadmill and any remaining zombies.
+ if (oldZombies) {
+ for (size_t i = 0; i < oldCount; ++i) {
+ if (oldZombies[i].object)
+ free(oldZombies[i].object);
+ }
+ free(oldZombies);
+ }
+
+ return YES;
+}
+
+void ZombieDisable() {
+ // Only allow enable/disable on the main thread, just to keep things
+ // simple.
+ CHECK([NSThread isMainThread]);
+
+ // |ZombieInit()| was never called.
+ if (!g_originalDeallocIMP)
+ return;
+
+ // Put back the original implementation of -[NSObject dealloc].
+ Method m = class_getInstanceMethod([NSObject class], @selector(dealloc));
+ CHECK(m);
+ method_setImplementation(m, g_originalDeallocIMP);
+
+ // Can safely grab this because it only happens on the main thread.
+ const size_t oldCount = g_zombieCount;
+ ZombieRecord* oldZombies = g_zombies;
+
+ {
+ AutoLock pin(lock_); // In case any |-dealloc| are in-progress.
+ g_zombieCount = 0;
+ g_zombies = NULL;
+ }
+
+ // Free any remaining zombies.
+ if (oldZombies) {
+ for (size_t i = 0; i < oldCount; ++i) {
+ if (oldZombies[i].object)
+ free(oldZombies[i].object);
+ }
+ free(oldZombies);
+ }
+}
+
+} // namespace ObjcEvilDoers
diff --git a/chrome/browser/ui/cocoa/page_info_bubble_controller.h b/chrome/browser/ui/cocoa/page_info_bubble_controller.h
new file mode 100644
index 0000000..10909c6
--- /dev/null
+++ b/chrome/browser/ui/cocoa/page_info_bubble_controller.h
@@ -0,0 +1,47 @@
+// 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 "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/page_info_model.h"
+#import "chrome/browser/ui/cocoa/base_bubble_controller.h"
+
+// This NSWindowController subclass manages the InfoBubbleWindow and view that
+// are displayed when the user clicks the security lock icon.
+@interface PageInfoBubbleController : BaseBubbleController {
+ @private
+ // The model that generates the content displayed by the controller.
+ scoped_ptr<PageInfoModel> model_;
+
+ // Thin bridge that pushes model-changed notifications from C++ to Cocoa.
+ scoped_ptr<PageInfoModel::PageInfoModelObserver> bridge_;
+
+ // The certificate ID for the page, 0 if the page is not over HTTPS.
+ int certID_;
+}
+
+@property (nonatomic, assign) int certID;
+
+// Designated initializer. The new instance will take ownership of |model| and
+// |bridge|. There should be a 1:1 mapping of models to bridges. The
+// controller will release itself when the bubble is closed.
+- (id)initWithPageInfoModel:(PageInfoModel*)model
+ modelObserver:(PageInfoModel::PageInfoModelObserver*)bridge
+ parentWindow:(NSWindow*)parentWindow;
+
+// Shows the certificate display window. Note that this will implicitly close
+// the bubble because the certificate window will become key. The certificate
+// information attaches itself as a sheet to the |parentWindow|.
+- (IBAction)showCertWindow:(id)sender;
+
+// Opens the help center link that explains the contents of the page info.
+- (IBAction)showHelpPage:(id)sender;
+
+@end
+
+@interface PageInfoBubbleController (ExposedForUnitTesting)
+- (void)performLayout;
+@end
diff --git a/chrome/browser/ui/cocoa/page_info_bubble_controller.mm b/chrome/browser/ui/cocoa/page_info_bubble_controller.mm
new file mode 100644
index 0000000..e0a13f6
--- /dev/null
+++ b/chrome/browser/ui/cocoa/page_info_bubble_controller.mm
@@ -0,0 +1,461 @@
+// 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 "chrome/browser/ui/cocoa/page_info_bubble_controller.h"
+
+#include "app/l10n_util.h"
+#include "app/l10n_util_mac.h"
+#include "base/message_loop.h"
+#include "base/sys_string_conversions.h"
+#include "base/task.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/cert_store.h"
+#include "chrome/browser/certificate_viewer.h"
+#include "chrome/browser/google/google_util.h"
+#include "chrome/browser/profiles/profile.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "chrome/browser/ui/cocoa/hyperlink_button_cell.h"
+#import "chrome/browser/ui/cocoa/info_bubble_view.h"
+#import "chrome/browser/ui/cocoa/info_bubble_window.h"
+#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
+#include "chrome/common/url_constants.h"
+#include "grit/generated_resources.h"
+#include "grit/locale_settings.h"
+#include "net/base/cert_status_flags.h"
+#include "net/base/x509_certificate.h"
+#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
+
+@interface PageInfoBubbleController (Private)
+- (PageInfoModel*)model;
+- (NSButton*)certificateButtonWithFrame:(NSRect)frame;
+- (void)configureTextFieldAsLabel:(NSTextField*)textField;
+- (CGFloat)addHeadlineViewForInfo:(const PageInfoModel::SectionInfo&)info
+ toSubviews:(NSMutableArray*)subviews
+ atPoint:(NSPoint)point;
+- (CGFloat)addDescriptionViewForInfo:(const PageInfoModel::SectionInfo&)info
+ toSubviews:(NSMutableArray*)subviews
+ atPoint:(NSPoint)point;
+- (CGFloat)addCertificateButtonToSubviews:(NSMutableArray*)subviews
+ atOffset:(CGFloat)offset;
+- (void)addImageViewForInfo:(const PageInfoModel::SectionInfo&)info
+ toSubviews:(NSMutableArray*)subviews
+ atOffset:(CGFloat)offset;
+- (CGFloat)addHelpButtonToSubviews:(NSMutableArray*)subviews
+ atOffset:(CGFloat)offset;
+- (CGFloat)addSeparatorToSubviews:(NSMutableArray*)subviews
+ atOffset:(CGFloat)offset;
+- (NSPoint)anchorPointForWindowWithHeight:(CGFloat)bubbleHeight
+ parentWindow:(NSWindow*)parent;
+@end
+
+// This simple NSView subclass is used as the single subview of the page info
+// bubble's window's contentView. Drawing is flipped so that layout of the
+// sections is easier. Apple recommends flipping the coordinate origin when
+// doing a lot of text layout because it's more natural.
+@interface PageInfoContentView : NSView {
+}
+@end
+@implementation PageInfoContentView
+- (BOOL)isFlipped {
+ return YES;
+}
+@end
+
+namespace {
+
+// The width of the window, in view coordinates. The height will be determined
+// by the content.
+const NSInteger kWindowWidth = 380;
+
+// Spacing in between sections.
+const NSInteger kVerticalSpacing = 10;
+
+// Padding along on the X-axis between the window frame and content.
+const NSInteger kFramePadding = 10;
+
+// Spacing between the optional headline and description text views.
+const NSInteger kHeadlineSpacing = 2;
+
+// Spacing between the image and the text.
+const NSInteger kImageSpacing = 10;
+
+// Square size of the image.
+const CGFloat kImageSize = 30;
+
+// The X position of the text fields. Variants for with and without an image.
+const CGFloat kTextXPositionNoImage = kFramePadding;
+const CGFloat kTextXPosition = kTextXPositionNoImage + kImageSize +
+ kImageSpacing;
+
+// Width of the text fields.
+const CGFloat kTextWidth = kWindowWidth - (kImageSize + kImageSpacing +
+ kFramePadding * 2);
+
+// Bridge that listens for change notifications from the model.
+class PageInfoModelBubbleBridge : public PageInfoModel::PageInfoModelObserver {
+ public:
+ PageInfoModelBubbleBridge()
+ : controller_(nil),
+ ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)) {
+ }
+
+ // PageInfoModelObserver implementation.
+ virtual void ModelChanged() {
+ // Check to see if a layout has already been scheduled.
+ if (!task_factory_.empty())
+ return;
+
+ // Delay performing layout by a second so that all the animations from
+ // InfoBubbleWindow and origin updates from BaseBubbleController finish, so
+ // that we don't all race trying to change the frame's origin.
+ //
+ // Using ScopedRunnableMethodFactory is superior here to |-performSelector:|
+ // because it will not retain its target; if the child outlives its parent,
+ // zombies get left behind (http://crbug.com/59619). This will also cancel
+ // the scheduled Tasks if the controller (and thus this bridge) get
+ // destroyed before the message can be delivered.
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ task_factory_.NewRunnableMethod(
+ &PageInfoModelBubbleBridge::PerformLayout),
+ 1000 /* milliseconds */);
+ }
+
+ // Sets the controller.
+ void set_controller(PageInfoBubbleController* controller) {
+ controller_ = controller;
+ }
+
+ private:
+ void PerformLayout() {
+ [controller_ performLayout];
+ }
+
+ PageInfoBubbleController* controller_; // weak
+
+ // Factory that vends RunnableMethod tasks for scheduling layout.
+ ScopedRunnableMethodFactory<PageInfoModelBubbleBridge> task_factory_;
+};
+
+} // namespace
+
+namespace browser {
+
+void ShowPageInfoBubble(gfx::NativeWindow parent,
+ Profile* profile,
+ const GURL& url,
+ const NavigationEntry::SSLStatus& ssl,
+ bool show_history) {
+ PageInfoModelBubbleBridge* bridge = new PageInfoModelBubbleBridge();
+ PageInfoModel* model =
+ new PageInfoModel(profile, url, ssl, show_history, bridge);
+ PageInfoBubbleController* controller =
+ [[PageInfoBubbleController alloc] initWithPageInfoModel:model
+ modelObserver:bridge
+ parentWindow:parent];
+ bridge->set_controller(controller);
+ [controller setCertID:ssl.cert_id()];
+ [controller showWindow:nil];
+}
+
+} // namespace browser
+
+@implementation PageInfoBubbleController
+
+@synthesize certID = certID_;
+
+- (id)initWithPageInfoModel:(PageInfoModel*)model
+ modelObserver:(PageInfoModel::PageInfoModelObserver*)bridge
+ parentWindow:(NSWindow*)parentWindow {
+ // Use an arbitrary height because it will be changed by the bridge.
+ NSRect contentRect = NSMakeRect(0, 0, kWindowWidth, 0);
+ // Create an empty window into which content is placed.
+ scoped_nsobject<InfoBubbleWindow> window(
+ [[InfoBubbleWindow alloc] initWithContentRect:contentRect
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO]);
+
+ if ((self = [super initWithWindow:window.get()
+ parentWindow:parentWindow
+ anchoredAt:NSZeroPoint])) {
+ model_.reset(model);
+ bridge_.reset(bridge);
+ [[self bubble] setArrowLocation:info_bubble::kTopLeft];
+ [self performLayout];
+ }
+ return self;
+}
+
+- (PageInfoModel*)model {
+ return model_.get();
+}
+
+- (IBAction)showCertWindow:(id)sender {
+ DCHECK(certID_ != 0);
+ ShowCertificateViewerByID([self parentWindow], certID_);
+}
+
+- (IBAction)showHelpPage:(id)sender {
+ GURL url = google_util::AppendGoogleLocaleParam(
+ GURL(chrome::kPageInfoHelpCenterURL));
+ Browser* browser = BrowserList::GetLastActive();
+ browser->OpenURL(url, GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
+}
+
+// This will create the subviews for the page info window. The general layout
+// is 2 or 3 boxed and titled sections, each of which has a status image to
+// provide visual feedback and a description that explains it. The description
+// text is usually only 1 or 2 lines, but can be much longer. At the bottom of
+// the window is a button to view the SSL certificate, which is disabled if
+// not using HTTPS.
+- (void)performLayout {
+ // |offset| is the Y position that should be drawn at next.
+ CGFloat offset = kFramePadding + info_bubble::kBubbleArrowHeight;
+
+ // Keep the new subviews in an array that gets replaced at the end.
+ NSMutableArray* subviews = [NSMutableArray array];
+
+ // The subviews will be attached to the PageInfoContentView, which has a
+ // flipped origin. This allows the code to build top-to-bottom.
+ const int sectionCount = model_->GetSectionCount();
+ for (int i = 0; i < sectionCount; ++i) {
+ PageInfoModel::SectionInfo info = model_->GetSectionInfo(i);
+
+ // Only certain sections have images. This affects the X position.
+ BOOL hasImage = model_->GetIconImage(info.icon_id) != nil;
+ CGFloat xPosition = (hasImage ? kTextXPosition : kTextXPositionNoImage);
+
+ // Insert the image subview for sections that are appropriate.
+ CGFloat imageBaseline = offset + kImageSize;
+ if (hasImage) {
+ [self addImageViewForInfo:info toSubviews:subviews atOffset:offset];
+ }
+
+ // Add the title.
+ if (!info.headline.empty()) {
+ offset += [self addHeadlineViewForInfo:info
+ toSubviews:subviews
+ atPoint:NSMakePoint(xPosition, offset)];
+ offset += kHeadlineSpacing;
+ }
+
+ // Create the description of the state.
+ offset += [self addDescriptionViewForInfo:info
+ toSubviews:subviews
+ atPoint:NSMakePoint(xPosition, offset)];
+
+ if (info.type == PageInfoModel::SECTION_INFO_IDENTITY && certID_) {
+ offset += kVerticalSpacing;
+ offset += [self addCertificateButtonToSubviews:subviews atOffset:offset];
+ }
+
+ // If at this point the description and optional headline and button are
+ // not as tall as the image, adjust the offset by the difference.
+ CGFloat imageBaselineDelta = imageBaseline - offset;
+ if (imageBaselineDelta > 0)
+ offset += imageBaselineDelta;
+
+ // Add the separators.
+ offset += kVerticalSpacing;
+ offset += [self addSeparatorToSubviews:subviews atOffset:offset];
+ }
+
+ // The last item at the bottom of the window is the help center link.
+ offset += [self addHelpButtonToSubviews:subviews atOffset:offset];
+ offset += kVerticalSpacing;
+
+ // Create the dummy view that uses flipped coordinates.
+ NSRect contentFrame = NSMakeRect(0, 0, kWindowWidth, offset);
+ scoped_nsobject<PageInfoContentView> contentView(
+ [[PageInfoContentView alloc] initWithFrame:contentFrame]);
+ [contentView setSubviews:subviews];
+
+ // Replace the window's content.
+ [[[self window] contentView] setSubviews:
+ [NSArray arrayWithObject:contentView]];
+
+ NSRect windowFrame = NSMakeRect(0, 0, kWindowWidth, offset);
+ windowFrame.size = [[[self window] contentView] convertSize:windowFrame.size
+ toView:nil];
+ // Adjust the origin by the difference in height.
+ windowFrame.origin = [[self window] frame].origin;
+ windowFrame.origin.y -= NSHeight(windowFrame) -
+ NSHeight([[self window] frame]);
+
+ // Resize the window. Only animate if the window is visible, otherwise it
+ // could be "growing" while it's opening, looking awkward.
+ [[self window] setFrame:windowFrame
+ display:YES
+ animate:[[self window] isVisible]];
+
+ NSPoint anchorPoint =
+ [self anchorPointForWindowWithHeight:NSHeight(windowFrame)
+ parentWindow:[self parentWindow]];
+ [self setAnchorPoint:anchorPoint];
+}
+
+// Creates the button with a given |frame| that, when clicked, will show the
+// SSL certificate information.
+- (NSButton*)certificateButtonWithFrame:(NSRect)frame {
+ NSButton* certButton = [[[NSButton alloc] initWithFrame:frame] autorelease];
+ [certButton setTitle:
+ l10n_util::GetNSStringWithFixup(IDS_PAGEINFO_CERT_INFO_BUTTON)];
+ [certButton setButtonType:NSMomentaryPushInButton];
+ [certButton setBezelStyle:NSRoundRectBezelStyle];
+ [certButton setTarget:self];
+ [certButton setAction:@selector(showCertWindow:)];
+ [[certButton cell] setControlSize:NSSmallControlSize];
+ NSFont* font = [NSFont systemFontOfSize:
+ [NSFont systemFontSizeForControlSize:NSSmallControlSize]];
+ [[certButton cell] setFont:font];
+ return certButton;
+}
+
+// Sets proprties on the given |field| to act as the title or description labels
+// in the bubble.
+- (void)configureTextFieldAsLabel:(NSTextField*)textField {
+ [textField setEditable:NO];
+ [textField setDrawsBackground:NO];
+ [textField setBezeled:NO];
+}
+
+// Adds the title text field at the given x,y position, and returns the y
+// position for the next element.
+- (CGFloat)addHeadlineViewForInfo:(const PageInfoModel::SectionInfo&)info
+ toSubviews:(NSMutableArray*)subviews
+ atPoint:(NSPoint)point {
+ NSRect frame = NSMakeRect(point.x, point.y, kTextWidth, kImageSpacing);
+ scoped_nsobject<NSTextField> textField(
+ [[NSTextField alloc] initWithFrame:frame]);
+ [self configureTextFieldAsLabel:textField.get()];
+ [textField setStringValue:base::SysUTF16ToNSString(info.headline)];
+ NSFont* font = [NSFont boldSystemFontOfSize:[NSFont smallSystemFontSize]];
+ [textField setFont:font];
+ frame.size.height +=
+ [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:
+ textField];
+ [textField setFrame:frame];
+ [subviews addObject:textField.get()];
+ return NSHeight(frame);
+}
+
+// Adds the description text field at the given x,y position, and returns the y
+// position for the next element.
+- (CGFloat)addDescriptionViewForInfo:(const PageInfoModel::SectionInfo&)info
+ toSubviews:(NSMutableArray*)subviews
+ atPoint:(NSPoint)point {
+ NSRect frame = NSMakeRect(point.x, point.y, kTextWidth, kImageSize);
+ scoped_nsobject<NSTextField> textField(
+ [[NSTextField alloc] initWithFrame:frame]);
+ [self configureTextFieldAsLabel:textField.get()];
+ [textField setStringValue:base::SysUTF16ToNSString(info.description)];
+ [textField setFont:[NSFont labelFontOfSize:[NSFont smallSystemFontSize]]];
+
+ // If the text is oversized, resize the text field.
+ frame.size.height +=
+ [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:
+ textField];
+ [subviews addObject:textField.get()];
+ return NSHeight(frame);
+}
+
+// Adds the certificate button at a pre-determined x position and the given y.
+// Returns the y position for the next element.
+- (CGFloat)addCertificateButtonToSubviews:(NSMutableArray*)subviews
+ atOffset:(CGFloat)offset {
+ // The certificate button should only be added if there is SSL information.
+ DCHECK(certID_);
+
+ // Create the certificate button. The frame will be fixed up by GTM, so
+ // use arbitrary values.
+ NSRect frame = NSMakeRect(kTextXPosition, offset, 100, 14);
+ NSButton* certButton = [self certificateButtonWithFrame:frame];
+ [subviews addObject:certButton];
+ [GTMUILocalizerAndLayoutTweaker sizeToFitView:certButton];
+
+ // By default, assume that we don't have certificate information to show.
+ scoped_refptr<net::X509Certificate> cert;
+ CertStore::GetInstance()->RetrieveCert(certID_, &cert);
+
+ // Don't bother showing certificates if there isn't one. Gears runs
+ // with no OS root certificate.
+ if (!cert.get() || !cert->os_cert_handle()) {
+ // This should only ever happen in unit tests.
+ [certButton setEnabled:NO];
+ }
+
+ return NSHeight([certButton frame]);
+}
+
+// Adds the state image at a pre-determined x position and the given y. This
+// does not affect the next Y position because the image is placed next to
+// a text field that is larger and accounts for the image's size.
+- (void)addImageViewForInfo:(const PageInfoModel::SectionInfo&)info
+ toSubviews:(NSMutableArray*)subviews
+ atOffset:(CGFloat)offset {
+ NSRect frame = NSMakeRect(kFramePadding, offset, kImageSize,
+ kImageSize);
+ scoped_nsobject<NSImageView> imageView(
+ [[NSImageView alloc] initWithFrame:frame]);
+ [imageView setImageFrameStyle:NSImageFrameNone];
+ [imageView setImage:model_->GetIconImage(info.icon_id)];
+ [subviews addObject:imageView.get()];
+}
+
+// Adds the help center button that explains the icons. Returns the y position
+// delta for the next offset.
+- (CGFloat)addHelpButtonToSubviews:(NSMutableArray*)subviews
+ atOffset:(CGFloat)offset {
+ NSRect frame = NSMakeRect(kFramePadding, offset, 100, 10);
+ scoped_nsobject<NSButton> button([[NSButton alloc] initWithFrame:frame]);
+ NSString* string =
+ l10n_util::GetNSStringWithFixup(IDS_PAGE_INFO_HELP_CENTER_LINK);
+ scoped_nsobject<HyperlinkButtonCell> cell(
+ [[HyperlinkButtonCell alloc] initTextCell:string]);
+ [cell setControlSize:NSSmallControlSize];
+ [button setCell:cell.get()];
+ [button setButtonType:NSMomentaryPushInButton];
+ [button setBezelStyle:NSRegularSquareBezelStyle];
+ [button setTarget:self];
+ [button setAction:@selector(showHelpPage:)];
+ [subviews addObject:button.get()];
+
+ // Call size-to-fit to fixup for the localized string.
+ [GTMUILocalizerAndLayoutTweaker sizeToFitView:button.get()];
+ return NSHeight([button frame]);
+}
+
+// Adds a 1px separator between sections. Returns the y position delta for the
+// next offset.
+- (CGFloat)addSeparatorToSubviews:(NSMutableArray*)subviews
+ atOffset:(CGFloat)offset {
+ const CGFloat kSpacerHeight = 1.0;
+ NSRect frame = NSMakeRect(kFramePadding, offset,
+ kWindowWidth - 2 * kFramePadding, kSpacerHeight);
+ scoped_nsobject<NSBox> spacer([[NSBox alloc] initWithFrame:frame]);
+ [spacer setBoxType:NSBoxSeparator];
+ [spacer setBorderType:NSLineBorder];
+ [spacer setAlphaValue:0.2];
+ [subviews addObject:spacer.get()];
+ return kVerticalSpacing + kSpacerHeight;
+}
+
+// Takes in the bubble's height and the parent window, which should be a
+// BrowserWindow, and gets the proper anchor point for the bubble. The returned
+// point is in screen coordinates.
+- (NSPoint)anchorPointForWindowWithHeight:(CGFloat)bubbleHeight
+ parentWindow:(NSWindow*)parent {
+ BrowserWindowController* controller = [parent windowController];
+ NSPoint origin = NSZeroPoint;
+ if ([controller isKindOfClass:[BrowserWindowController class]]) {
+ LocationBarViewMac* locationBar = [controller locationBarBridge];
+ if (locationBar) {
+ NSPoint bubblePoint = locationBar->GetPageInfoBubblePoint();
+ origin = [parent convertBaseToScreen:bubblePoint];
+ }
+ }
+ return origin;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/page_info_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/page_info_bubble_controller_unittest.mm
new file mode 100644
index 0000000..50281fe
--- /dev/null
+++ b/chrome/browser/ui/cocoa/page_info_bubble_controller_unittest.mm
@@ -0,0 +1,210 @@
+// 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.
+
+#include "app/l10n_util.h"
+#include "base/scoped_nsobject.h"
+#include "base/string_util.h"
+#include "base/string_number_conversions.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/page_info_model.h"
+#import "chrome/browser/ui/cocoa/hyperlink_button_cell.h"
+#import "chrome/browser/ui/cocoa/page_info_bubble_controller.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "grit/generated_resources.h"
+
+namespace {
+
+class FakeModel : public PageInfoModel {
+ public:
+ FakeModel() : PageInfoModel() {}
+
+ void AddSection(SectionStateIcon icon_id,
+ const string16& headline,
+ const string16& description,
+ SectionInfoType type) {
+ sections_.push_back(SectionInfo(
+ icon_id, headline, description, type));
+ }
+};
+
+class FakeBridge : public PageInfoModel::PageInfoModelObserver {
+ public:
+ void ModelChanged() {}
+};
+
+class PageInfoBubbleControllerTest : public CocoaTest {
+ public:
+ PageInfoBubbleControllerTest() {
+ controller_ = nil;
+ model_ = new FakeModel();
+ }
+
+ virtual void TearDown() {
+ [controller_ close];
+ CocoaTest::TearDown();
+ }
+
+ void CreateBubble() {
+ // The controller cleans up after itself when the window closes.
+ controller_ =
+ [[PageInfoBubbleController alloc] initWithPageInfoModel:model_
+ modelObserver:NULL
+ parentWindow:test_window()];
+ window_ = [controller_ window];
+ [controller_ showWindow:nil];
+ }
+
+ // Checks the controller's window for the requisite subviews in the given
+ // numbers.
+ void CheckWindow(int text_count,
+ int image_count,
+ int spacer_count,
+ int button_count) {
+ // All windows have the help center link and a spacer for it.
+ int link_count = 1;
+ ++spacer_count;
+
+ // The window's only immediate child is an invisible view that has a flipped
+ // coordinate origin. It is into this that all views get placed.
+ NSArray* windowSubviews = [[window_ contentView] subviews];
+ EXPECT_EQ(1U, [windowSubviews count]);
+ NSArray* subviews = [[windowSubviews lastObject] subviews];
+
+ for (NSView* view in subviews) {
+ if ([view isKindOfClass:[NSTextField class]]) {
+ --text_count;
+ } else if ([view isKindOfClass:[NSImageView class]]) {
+ --image_count;
+ } else if ([view isKindOfClass:[NSBox class]]) {
+ --spacer_count;
+ } else if ([view isKindOfClass:[NSButton class]]) {
+ NSButton* button = static_cast<NSButton*>(view);
+ // Every window should have a single link button to the help page.
+ if ([[button cell] isKindOfClass:[HyperlinkButtonCell class]]) {
+ --link_count;
+ CheckButton(button, @selector(showHelpPage:));
+ } else {
+ --button_count;
+ CheckButton(button, @selector(showCertWindow:));
+ }
+ } else {
+ ADD_FAILURE() << "Unknown subview: " << [[view description] UTF8String];
+ }
+ }
+ EXPECT_EQ(0, text_count);
+ EXPECT_EQ(0, image_count);
+ EXPECT_EQ(0, spacer_count);
+ EXPECT_EQ(0, button_count);
+ EXPECT_EQ(0, link_count);
+ EXPECT_EQ([window_ delegate], controller_);
+ }
+
+ // Checks that a button is hooked up correctly.
+ void CheckButton(NSButton* button, SEL action) {
+ EXPECT_EQ(action, [button action]);
+ EXPECT_EQ(controller_, [button target]);
+ EXPECT_TRUE([button stringValue]);
+ }
+
+ BrowserTestHelper helper_;
+
+ PageInfoBubbleController* controller_; // Weak, owns self.
+ FakeModel* model_; // Weak, owned by controller.
+ NSWindow* window_; // Weak, owned by controller.
+};
+
+
+TEST_F(PageInfoBubbleControllerTest, NoHistoryNoSecurity) {
+ model_->AddSection(PageInfoModel::ICON_STATE_ERROR,
+ string16(),
+ l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY),
+ PageInfoModel::SECTION_INFO_IDENTITY);
+ model_->AddSection(PageInfoModel::ICON_STATE_ERROR,
+ string16(),
+ l10n_util::GetStringFUTF16(
+ IDS_PAGE_INFO_SECURITY_TAB_NOT_ENCRYPTED_CONNECTION_TEXT,
+ ASCIIToUTF16("google.com")),
+ PageInfoModel::SECTION_INFO_CONNECTION);
+
+ CreateBubble();
+ CheckWindow(/*text=*/2, /*image=*/2, /*spacer=*/1, /*button=*/0);
+}
+
+
+TEST_F(PageInfoBubbleControllerTest, HistoryNoSecurity) {
+ model_->AddSection(PageInfoModel::ICON_STATE_ERROR,
+ string16(),
+ l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY),
+ PageInfoModel::SECTION_INFO_IDENTITY);
+ model_->AddSection(PageInfoModel::ICON_STATE_ERROR,
+ string16(),
+ l10n_util::GetStringFUTF16(
+ IDS_PAGE_INFO_SECURITY_TAB_NOT_ENCRYPTED_CONNECTION_TEXT,
+ ASCIIToUTF16("google.com")),
+ PageInfoModel::SECTION_INFO_CONNECTION);
+
+ // In practice, the history information comes later because it's queried
+ // asynchronously, so replicate the double-build here.
+ CreateBubble();
+
+ model_->AddSection(PageInfoModel::ICON_STATE_ERROR,
+ l10n_util::GetStringUTF16(IDS_PAGE_INFO_SITE_INFO_TITLE),
+ l10n_util::GetStringUTF16(
+ IDS_PAGE_INFO_SECURITY_TAB_FIRST_VISITED_TODAY),
+ PageInfoModel::SECTION_INFO_FIRST_VISIT);
+
+ [controller_ performLayout];
+
+ CheckWindow(/*text=*/4, /*image=*/3, /*spacer=*/2, /*button=*/0);
+}
+
+
+TEST_F(PageInfoBubbleControllerTest, NoHistoryMixedSecurity) {
+ model_->AddSection(PageInfoModel::ICON_STATE_OK,
+ string16(),
+ l10n_util::GetStringFUTF16(
+ IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY,
+ ASCIIToUTF16("Goat Security Systems")),
+ PageInfoModel::SECTION_INFO_IDENTITY);
+
+ // This string is super long and the text should overflow the default clip
+ // region (kImageSize).
+ string16 description = l10n_util::GetStringFUTF16(
+ IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_SENTENCE_LINK,
+ l10n_util::GetStringFUTF16(
+ IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_CONNECTION_TEXT,
+ ASCIIToUTF16("chrome.google.com"),
+ base::IntToString16(1024)),
+ l10n_util::GetStringUTF16(
+ IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_INSECURE_CONTENT_WARNING));
+
+ model_->AddSection(PageInfoModel::ICON_STATE_OK,
+ string16(),
+ description,
+ PageInfoModel::SECTION_INFO_CONNECTION);
+
+
+ CreateBubble();
+ [controller_ setCertID:1];
+ [controller_ performLayout];
+
+ CheckWindow(/*text=*/2, /*image=*/2, /*spacer=*/1, /*button=*/1);
+
+ // Look for the over-sized box.
+ NSString* targetDesc = base::SysUTF16ToNSString(description);
+ NSArray* subviews = [[window_ contentView] subviews];
+ for (NSView* subview in subviews) {
+ if ([subview isKindOfClass:[NSTextField class]]) {
+ NSTextField* desc = static_cast<NSTextField*>(subview);
+ if ([[desc stringValue] isEqualToString:targetDesc]) {
+ // Typical box frame is ~55px, make sure this is extra large.
+ EXPECT_LT(75, NSHeight([desc frame]));
+ }
+ }
+ }
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/preferences_window_controller.h b/chrome/browser/ui/cocoa/preferences_window_controller.h
new file mode 100644
index 0000000..eed4af6
--- /dev/null
+++ b/chrome/browser/ui/cocoa/preferences_window_controller.h
@@ -0,0 +1,240 @@
+// 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 "base/scoped_ptr.h"
+#include "base/scoped_nsobject.h"
+#include "chrome/browser/prefs/pref_member.h"
+#include "chrome/browser/prefs/pref_set_observer.h"
+#include "chrome/browser/prefs/pref_change_registrar.h"
+#include "chrome/browser/ui/options/options_window.h"
+
+namespace PreferencesWindowControllerInternal {
+class PrefObserverBridge;
+class ManagedPrefsBannerState;
+}
+
+@class CustomHomePagesModel;
+@class FontLanguageSettingsController;
+class PrefService;
+class Profile;
+class ProfileSyncService;
+@class SearchEngineListModel;
+@class VerticalGradientView;
+@class WindowSizeAutosaver;
+
+// A window controller that handles the preferences window. The bulk of the
+// work is handled via Cocoa Bindings and getter/setter methods that wrap
+// cross-platform PrefMember objects. When prefs change in the back-end
+// (that is, outside of this UI), our observer receives a notification and can
+// tickle the KVO to update the UI so we are always in sync. The bindings are
+// specified in the nib file. Preferences are persisted into the back-end
+// as they are changed in the UI, and are thus immediately available even while
+// the window is still open. When the window closes, a notification is sent
+// via the system NotificationCenter. This can be used as a signal to
+// release this controller, as it's likely the client wants to enforce there
+// only being one (we don't do that internally as it makes it very difficult
+// to unit test).
+@interface PreferencesWindowController : NSWindowController {
+ @private
+ Profile* profile_; // weak ref
+ OptionsPage initialPage_;
+ PrefService* prefs_; // weak ref - Obtained from profile_ for convenience.
+ // weak ref - Also obtained from profile_ for convenience. May be NULL.
+ ProfileSyncService* syncService_;
+ scoped_ptr<PreferencesWindowControllerInternal::PrefObserverBridge>
+ observer_; // Watches for pref changes.
+ PrefChangeRegistrar registrar_; // Manages pref change observer registration.
+ scoped_nsobject<WindowSizeAutosaver> sizeSaver_;
+ NSView* currentPrefsView_; // weak ref - current prefs page view.
+ scoped_ptr<PreferencesWindowControllerInternal::ManagedPrefsBannerState>
+ bannerState_;
+ BOOL managedPrefsBannerVisible_;
+
+ IBOutlet NSToolbar* toolbar_;
+ IBOutlet VerticalGradientView* managedPrefsBannerView_;
+ IBOutlet NSImageView* managedPrefsBannerWarningImage_;
+
+ // The views we'll rotate through
+ IBOutlet NSView* basicsView_;
+ IBOutlet NSView* personalStuffView_;
+ IBOutlet NSView* underTheHoodView_;
+ // The last page the user was on when they opened the Options window.
+ IntegerPrefMember lastSelectedPage_;
+
+ // The groups of the Basics view for layout fixup.
+ IBOutlet NSArray* basicsGroupStartup_;
+ IBOutlet NSArray* basicsGroupHomePage_;
+ IBOutlet NSArray* basicsGroupToolbar_;
+ IBOutlet NSArray* basicsGroupSearchEngine_;
+ IBOutlet NSArray* basicsGroupDefaultBrowser_;
+
+ // The groups of the Personal Stuff view for layout fixup.
+ IBOutlet NSArray* personalStuffGroupSync_;
+ IBOutlet NSArray* personalStuffGroupPasswords_;
+ IBOutlet NSArray* personalStuffGroupAutofill_;
+ IBOutlet NSArray* personalStuffGroupBrowserData_;
+ IBOutlet NSArray* personalStuffGroupThemes_;
+
+ // Having two animations around is bad (they fight), so just use one.
+ scoped_nsobject<NSViewAnimation> animation_;
+
+ IBOutlet NSArrayController* customPagesArrayController_;
+
+ // Basics panel
+ IntegerPrefMember restoreOnStartup_;
+ scoped_nsobject<CustomHomePagesModel> customPagesSource_;
+ BooleanPrefMember newTabPageIsHomePage_;
+ StringPrefMember homepage_;
+ BooleanPrefMember showHomeButton_;
+ BooleanPrefMember instantEnabled_;
+ IBOutlet NSButton* instantCheckbox_;
+ scoped_nsobject<SearchEngineListModel> searchEngineModel_;
+ // Used when creating a new home page url to make the new cell editable.
+ BOOL pendingSelectForEdit_;
+ BOOL restoreButtonsEnabled_;
+ BOOL restoreURLsEnabled_;
+ BOOL showHomeButtonEnabled_;
+ BOOL defaultSearchEngineEnabled_;
+
+ // User Data panel
+ BooleanPrefMember askSavePasswords_;
+ BooleanPrefMember autoFillEnabled_;
+ IBOutlet NSButton* autoFillSettingsButton_;
+ IBOutlet NSButton* syncButton_;
+ IBOutlet NSButton* syncCustomizeButton_;
+ IBOutlet NSTextField* syncStatus_;
+ IBOutlet NSButton* syncLink_;
+ IBOutlet NSButton* privacyDashboardLink_;
+ scoped_nsobject<NSColor> syncStatusNoErrorBackgroundColor_;
+ scoped_nsobject<NSColor> syncLinkNoErrorBackgroundColor_;
+ scoped_nsobject<NSColor> syncErrorBackgroundColor_;
+ BOOL passwordManagerChoiceEnabled_;
+ BOOL passwordManagerButtonEnabled_;
+ BOOL autoFillSettingsButtonEnabled_;
+
+ // Under the hood panel
+ IBOutlet NSView* underTheHoodContentView_;
+ IBOutlet NSScrollView* underTheHoodScroller_;
+ IBOutlet NSButton* contentSettingsButton_;
+ IBOutlet NSButton* clearDataButton_;
+ BooleanPrefMember alternateErrorPages_;
+ BooleanPrefMember useSuggest_;
+ BooleanPrefMember dnsPrefetch_;
+ BooleanPrefMember safeBrowsing_;
+ BooleanPrefMember metricsReporting_;
+ IBOutlet NSPathControl* downloadLocationControl_;
+ IBOutlet NSButton* downloadLocationButton_;
+ StringPrefMember defaultDownloadLocation_;
+ BooleanPrefMember askForSaveLocation_;
+ IBOutlet NSButton* resetFileHandlersButton_;
+ StringPrefMember autoOpenFiles_;
+ BooleanPrefMember translateEnabled_;
+ BooleanPrefMember tabsToLinks_;
+ FontLanguageSettingsController* fontLanguageSettings_;
+ StringPrefMember currentTheme_;
+ IBOutlet NSButton* enableLoggingCheckbox_;
+ scoped_ptr<PrefSetObserver> proxyPrefs_;
+ BOOL showAlternateErrorPagesEnabled_;
+ BOOL useSuggestEnabled_;
+ BOOL dnsPrefetchEnabled_;
+ BOOL safeBrowsingEnabled_;
+ BOOL metricsReportingEnabled_;
+ BOOL proxiesConfigureButtonEnabled_;
+}
+
+// Designated initializer. |profile| should not be NULL.
+- (id)initWithProfile:(Profile*)profile initialPage:(OptionsPage)initialPage;
+
+// Show the preferences window.
+- (void)showPreferences:(id)sender;
+
+// Switch to the given preference page.
+- (void)switchToPage:(OptionsPage)page animate:(BOOL)animate;
+
+// Enables or disables the restoreOnStartup elements
+- (void) setEnabledStateOfRestoreOnStartup;
+
+// IBAction methods for responding to user actions.
+
+// Basics panel
+- (IBAction)addHomepage:(id)sender;
+- (IBAction)removeSelectedHomepages:(id)sender;
+- (IBAction)useCurrentPagesAsHomepage:(id)sender;
+- (IBAction)manageSearchEngines:(id)sender;
+- (IBAction)toggleInstant:(id)sender;
+- (IBAction)learnMoreAboutInstant:(id)sender;
+- (IBAction)makeDefaultBrowser:(id)sender;
+
+// User Data panel
+- (IBAction)doSyncAction:(id)sender;
+- (IBAction)doSyncCustomize:(id)sender;
+- (IBAction)doSyncReauthentication:(id)sender;
+- (IBAction)showPrivacyDashboard:(id)sender;
+- (IBAction)showSavedPasswords:(id)sender;
+- (IBAction)showAutoFillSettings:(id)sender;
+- (IBAction)importData:(id)sender;
+- (IBAction)resetThemeToDefault:(id)sender;
+- (IBAction)themesGallery:(id)sender;
+
+// Under the hood
+- (IBAction)showContentSettings:(id)sender;
+- (IBAction)clearData:(id)sender;
+- (IBAction)privacyLearnMore:(id)sender;
+- (IBAction)browseDownloadLocation:(id)sender;
+- (IBAction)resetAutoOpenFiles:(id)sender;
+- (IBAction)changeFontAndLanguageSettings:(id)sender;
+- (IBAction)openProxyPreferences:(id)sender;
+- (IBAction)showCertificates:(id)sender;
+- (IBAction)resetToDefaults:(id)sender;
+
+// When a toolbar button is clicked
+- (IBAction)toolbarButtonSelected:(id)sender;
+
+// Usable from cocoa bindings to hook up the custom home pages table.
+@property (nonatomic, readonly) CustomHomePagesModel* customPagesSource;
+
+// Properties for the enabled state of various UI elements. Keep these ordered
+// by occurrence on the dialog.
+@property (nonatomic) BOOL restoreButtonsEnabled;
+@property (nonatomic) BOOL restoreURLsEnabled;
+@property (nonatomic) BOOL showHomeButtonEnabled;
+@property (nonatomic) BOOL defaultSearchEngineEnabled;
+@property (nonatomic) BOOL passwordManagerChoiceEnabled;
+@property (nonatomic) BOOL passwordManagerButtonEnabled;
+@property (nonatomic) BOOL autoFillSettingsButtonEnabled;
+@property (nonatomic) BOOL showAlternateErrorPagesEnabled;
+@property (nonatomic) BOOL useSuggestEnabled;
+@property (nonatomic) BOOL dnsPrefetchEnabled;
+@property (nonatomic) BOOL safeBrowsingEnabled;
+@property (nonatomic) BOOL metricsReportingEnabled;
+@property (nonatomic) BOOL proxiesConfigureButtonEnabled;
+@end
+
+@interface PreferencesWindowController(Testing)
+
+- (IntegerPrefMember*)lastSelectedPage;
+- (NSToolbar*)toolbar;
+- (NSView*)basicsView;
+- (NSView*)personalStuffView;
+- (NSView*)underTheHoodView;
+
+// Converts the given OptionsPage value (which may be OPTIONS_PAGE_DEFAULT)
+// into a concrete OptionsPage value.
+- (OptionsPage)normalizePage:(OptionsPage)page;
+
+// Returns the toolbar item corresponding to the given page. Should be
+// called only after awakeFromNib is.
+- (NSToolbarItem*)getToolbarItemForPage:(OptionsPage)page;
+
+// Returns the (normalized) page corresponding to the given toolbar item.
+// Should be called only after awakeFromNib is.
+- (OptionsPage)getPageForToolbarItem:(NSToolbarItem*)toolbarItem;
+
+// Returns the view corresponding to the given page. Should be called
+// only after awakeFromNib is.
+- (NSView*)getPrefsViewForPage:(OptionsPage)page;
+
+@end
diff --git a/chrome/browser/ui/cocoa/preferences_window_controller.mm b/chrome/browser/ui/cocoa/preferences_window_controller.mm
new file mode 100644
index 0000000..d582680
--- /dev/null
+++ b/chrome/browser/ui/cocoa/preferences_window_controller.mm
@@ -0,0 +1,2171 @@
+// 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 "chrome/browser/ui/cocoa/preferences_window_controller.h"
+
+#include <algorithm>
+
+#include "app/l10n_util.h"
+#include "app/l10n_util_mac.h"
+#include "app/resource_bundle.h"
+#include "base/logging.h"
+#include "base/mac_util.h"
+#include "base/mac/scoped_aedesc.h"
+#include "base/string16.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/autofill/autofill_dialog.h"
+#include "chrome/browser/autofill/autofill_type.h"
+#include "chrome/browser/autofill/personal_data_manager.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/download/download_manager.h"
+#include "chrome/browser/download/download_prefs.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/google/google_util.h"
+#include "chrome/browser/instant/instant_confirm_dialog.h"
+#include "chrome/browser/instant/instant_controller.h"
+#include "chrome/browser/metrics/metrics_service.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/net/url_fixer_upper.h"
+#include "chrome/browser/policy/managed_prefs_banner_base.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/prefs/session_startup_pref.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
+#include "chrome/browser/shell_integration.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/sync/sync_ui_util.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#import "chrome/browser/ui/cocoa/clear_browsing_data_controller.h"
+#import "chrome/browser/ui/cocoa/content_settings_dialog_controller.h"
+#import "chrome/browser/ui/cocoa/custom_home_pages_model.h"
+#import "chrome/browser/ui/cocoa/font_language_settings_controller.h"
+#import "chrome/browser/ui/cocoa/import_settings_dialog.h"
+#import "chrome/browser/ui/cocoa/keyword_editor_cocoa_controller.h"
+#import "chrome/browser/ui/cocoa/l10n_util.h"
+#import "chrome/browser/ui/cocoa/search_engine_list_model.h"
+#import "chrome/browser/ui/cocoa/vertical_gradient_view.h"
+#import "chrome/browser/ui/cocoa/window_size_autosaver.h"
+#include "chrome/browser/ui/options/options_util.h"
+#include "chrome/browser/ui/options/options_window.h"
+#include "chrome/browser/ui/options/show_options_url.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_type.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/installer/util/google_update_settings.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/locale_settings.h"
+#include "grit/theme_resources.h"
+#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
+#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
+
+namespace {
+
+// Colors for the managed preferences warning banner.
+static const double kBannerGradientColorTop[3] =
+ {255.0 / 255.0, 242.0 / 255.0, 183.0 / 255.0};
+static const double kBannerGradientColorBottom[3] =
+ {250.0 / 255.0, 230.0 / 255.0, 145.0 / 255.0};
+static const double kBannerStrokeColor = 135.0 / 255.0;
+
+// Tag id for retrieval via viewWithTag in NSView (from IB).
+static const uint32 kBasicsStartupPageTableTag = 1000;
+
+bool IsNewTabUIURLString(const GURL& url) {
+ return url == GURL(chrome::kChromeUINewTabURL);
+}
+
+// Helper that sizes two buttons to fit in a row keeping their spacing, returns
+// the total horizontal size change.
+CGFloat SizeToFitButtonPair(NSButton* leftButton, NSButton* rightButton) {
+ CGFloat widthShift = 0.0;
+
+ NSSize delta = [GTMUILocalizerAndLayoutTweaker sizeToFitView:leftButton];
+ DCHECK_EQ(delta.height, 0.0) << "Height changes unsupported";
+ widthShift += delta.width;
+
+ if (widthShift != 0.0) {
+ NSPoint origin = [rightButton frame].origin;
+ origin.x += widthShift;
+ [rightButton setFrameOrigin:origin];
+ }
+ delta = [GTMUILocalizerAndLayoutTweaker sizeToFitView:rightButton];
+ DCHECK_EQ(delta.height, 0.0) << "Height changes unsupported";
+ widthShift += delta.width;
+
+ return widthShift;
+}
+
+// The different behaviors for the "pref group" auto sizing.
+enum AutoSizeGroupBehavior {
+ kAutoSizeGroupBehaviorVerticalToFit,
+ kAutoSizeGroupBehaviorVerticalFirstToFit,
+ kAutoSizeGroupBehaviorHorizontalToFit,
+ kAutoSizeGroupBehaviorHorizontalFirstGrows,
+ kAutoSizeGroupBehaviorFirstTwoAsRowVerticalToFit
+};
+
+// Helper to tweak the layout of the "pref groups" and also ripple any height
+// changes from one group to the next groups' origins.
+// |views| is an ordered list of views with first being the label for the
+// group and the rest being top down or left to right ordering of the views.
+// The label is assumed to already be the same height as all the views it is
+// next too.
+CGFloat AutoSizeGroup(NSArray* views, AutoSizeGroupBehavior behavior,
+ CGFloat verticalShift) {
+ DCHECK_GE([views count], 2U) << "Should be at least a label and a control";
+ NSTextField* label = [views objectAtIndex:0];
+ DCHECK([label isKindOfClass:[NSTextField class]])
+ << "First view should be the label for the group";
+
+ // Auto size the label to see if we need more vertical space for its localized
+ // string.
+ CGFloat labelHeightChange =
+ [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:label];
+
+ CGFloat localVerticalShift = 0.0;
+ switch (behavior) {
+ case kAutoSizeGroupBehaviorVerticalToFit: {
+ // Walk bottom up doing the sizing and moves.
+ for (NSUInteger index = [views count] - 1; index > 0; --index) {
+ NSView* view = [views objectAtIndex:index];
+ NSSize delta = cocoa_l10n_util::WrapOrSizeToFit(view);
+ DCHECK_GE(delta.height, 0.0) << "Should NOT shrink in height";
+ if (localVerticalShift) {
+ NSPoint origin = [view frame].origin;
+ origin.y += localVerticalShift;
+ [view setFrameOrigin:origin];
+ }
+ localVerticalShift += delta.height;
+ }
+ break;
+ }
+ case kAutoSizeGroupBehaviorVerticalFirstToFit: {
+ // Just size the top one.
+ NSView* view = [views objectAtIndex:1];
+ NSSize delta = cocoa_l10n_util::WrapOrSizeToFit(view);
+ DCHECK_GE(delta.height, 0.0) << "Should NOT shrink in height";
+ localVerticalShift += delta.height;
+ break;
+ }
+ case kAutoSizeGroupBehaviorHorizontalToFit: {
+ // Walk left to right doing the sizing and moves.
+ // NOTE: Don't worry about vertical, assume it always fits.
+ CGFloat horizontalShift = 0.0;
+ NSUInteger count = [views count];
+ for (NSUInteger index = 1; index < count; ++index) {
+ NSView* view = [views objectAtIndex:index];
+ NSSize delta = cocoa_l10n_util::WrapOrSizeToFit(view);
+ DCHECK_GE(delta.height, 0.0) << "Should NOT shrink in height";
+ if (horizontalShift) {
+ NSPoint origin = [view frame].origin;
+ origin.x += horizontalShift;
+ [view setFrameOrigin:origin];
+ }
+ horizontalShift += delta.width;
+ }
+ break;
+ }
+ case kAutoSizeGroupBehaviorHorizontalFirstGrows: {
+ // Walk right to left doing the sizing and moves, then apply the space
+ // collected into the first.
+ // NOTE: Don't worry about vertical, assume it always all fits.
+ CGFloat horizontalShift = 0.0;
+ for (NSUInteger index = [views count] - 1; index > 1; --index) {
+ NSView* view = [views objectAtIndex:index];
+ NSSize delta = cocoa_l10n_util::WrapOrSizeToFit(view);
+ DCHECK_GE(delta.height, 0.0) << "Should NOT shrink in height";
+ horizontalShift -= delta.width;
+ NSPoint origin = [view frame].origin;
+ origin.x += horizontalShift;
+ [view setFrameOrigin:origin];
+ }
+ if (horizontalShift) {
+ NSView* view = [views objectAtIndex:1];
+ NSSize delta = NSMakeSize(horizontalShift, 0.0);
+ [GTMUILocalizerAndLayoutTweaker
+ resizeViewWithoutAutoResizingSubViews:view
+ delta:delta];
+ }
+ break;
+ }
+ case kAutoSizeGroupBehaviorFirstTwoAsRowVerticalToFit: {
+ // Start out like kAutoSizeGroupBehaviorVerticalToFit but don't do
+ // the first two. Then handle the two as a row, but apply any
+ // vertical shift.
+ // All but the first two (in the row); walk bottom up.
+ for (NSUInteger index = [views count] - 1; index > 2; --index) {
+ NSView* view = [views objectAtIndex:index];
+ NSSize delta = cocoa_l10n_util::WrapOrSizeToFit(view);
+ DCHECK_GE(delta.height, 0.0) << "Should NOT shrink in height";
+ if (localVerticalShift) {
+ NSPoint origin = [view frame].origin;
+ origin.y += localVerticalShift;
+ [view setFrameOrigin:origin];
+ }
+ localVerticalShift += delta.height;
+ }
+ // Deal with the two for the horizontal row. Size the second one.
+ CGFloat horizontalShift = 0.0;
+ NSView* view = [views objectAtIndex:2];
+ NSSize delta = cocoa_l10n_util::WrapOrSizeToFit(view);
+ DCHECK_GE(delta.height, 0.0) << "Should NOT shrink in height";
+ horizontalShift -= delta.width;
+ NSPoint origin = [view frame].origin;
+ origin.x += horizontalShift;
+ if (localVerticalShift) {
+ origin.y += localVerticalShift;
+ }
+ [view setFrameOrigin:origin];
+ // Now expand the first item in the row to consume the space opened up.
+ view = [views objectAtIndex:1];
+ if (horizontalShift) {
+ NSSize delta = NSMakeSize(horizontalShift, 0.0);
+ [GTMUILocalizerAndLayoutTweaker
+ resizeViewWithoutAutoResizingSubViews:view
+ delta:delta];
+ }
+ // And move it up by any amount needed from the previous items.
+ if (localVerticalShift) {
+ NSPoint origin = [view frame].origin;
+ origin.y += localVerticalShift;
+ [view setFrameOrigin:origin];
+ }
+ break;
+ }
+ default:
+ NOTREACHED();
+ break;
+ }
+
+ // If the label grew more then the views, the other views get an extra shift.
+ // Otherwise, move the label to its top is aligned with the other views.
+ CGFloat nonLabelShift = 0.0;
+ if (labelHeightChange > localVerticalShift) {
+ // Since the lable is taller, centering the other views looks best, just
+ // shift the views by 1/2 of the size difference.
+ nonLabelShift = (labelHeightChange - localVerticalShift) / 2.0;
+ } else {
+ NSPoint origin = [label frame].origin;
+ origin.y += localVerticalShift - labelHeightChange;
+ [label setFrameOrigin:origin];
+ }
+
+ // Apply the input shift requested along with any the shift from label being
+ // taller then the rest of the group.
+ for (NSView* view in views) {
+ NSPoint origin = [view frame].origin;
+ origin.y += verticalShift;
+ if (view != label) {
+ origin.y += nonLabelShift;
+ }
+ [view setFrameOrigin:origin];
+ }
+
+ // Return how much the group grew.
+ return localVerticalShift + nonLabelShift;
+}
+
+// Helper to remove a view and move everything above it down to take over the
+// space.
+void RemoveViewFromView(NSView* view, NSView* toRemove) {
+ // Sort bottom up so we can spin over what is above it.
+ NSArray* views =
+ [[view subviews] sortedArrayUsingFunction:cocoa_l10n_util::CompareFrameY
+ context:NULL];
+
+ // Find where |toRemove| was.
+ NSUInteger index = [views indexOfObject:toRemove];
+ DCHECK_NE(index, NSNotFound);
+ NSUInteger count = [views count];
+ CGFloat shrinkHeight = 0;
+ if (index < (count - 1)) {
+ // If we're not the topmost control, the amount to shift is the bottom of
+ // |toRemove| to the bottom of the view above it.
+ CGFloat shiftDown =
+ NSMinY([[views objectAtIndex:index + 1] frame]) -
+ NSMinY([toRemove frame]);
+
+ // Now cycle over the views above it moving them down.
+ for (++index; index < count; ++index) {
+ NSView* view = [views objectAtIndex:index];
+ NSPoint origin = [view frame].origin;
+ origin.y -= shiftDown;
+ [view setFrameOrigin:origin];
+ }
+
+ shrinkHeight = shiftDown;
+ } else if (index > 0) {
+ // If we're the topmost control, there's nothing to shift but we want to
+ // shrink until the top edge of the second-topmost control, unless it is
+ // actually higher than the topmost control (since we're sorting by the
+ // bottom edge).
+ shrinkHeight = std::max(0.f,
+ NSMaxY([toRemove frame]) -
+ NSMaxY([[views objectAtIndex:index - 1] frame]));
+ }
+ // If we only have one control, don't do any resizing (for now).
+
+ // Remove |toRemove|.
+ [toRemove removeFromSuperview];
+
+ [GTMUILocalizerAndLayoutTweaker
+ resizeViewWithoutAutoResizingSubViews:view
+ delta:NSMakeSize(0, -shrinkHeight)];
+}
+
+// Simply removes all the views in |toRemove|.
+void RemoveGroupFromView(NSView* view, NSArray* toRemove) {
+ for (NSView* viewToRemove in toRemove) {
+ RemoveViewFromView(view, viewToRemove);
+ }
+}
+
+// Helper to tweak the layout of the "Under the Hood" content by autosizing all
+// the views and moving things up vertically. Special case the two controls for
+// download location as they are horizontal, and should fill the row. Special
+// case "Content Settings" and "Clear browsing data" as they are horizontal as
+// well.
+CGFloat AutoSizeUnderTheHoodContent(NSView* view,
+ NSPathControl* downloadLocationControl,
+ NSButton* downloadLocationButton) {
+ CGFloat verticalShift = 0.0;
+
+ // Loop bottom up through the views sizing and shifting.
+ NSArray* views =
+ [[view subviews] sortedArrayUsingFunction:cocoa_l10n_util::CompareFrameY
+ context:NULL];
+ for (NSView* view in views) {
+ NSSize delta = cocoa_l10n_util::WrapOrSizeToFit(view);
+ DCHECK_GE(delta.height, 0.0) << "Should NOT shrink in height";
+ if (verticalShift) {
+ NSPoint origin = [view frame].origin;
+ origin.y += verticalShift;
+ [view setFrameOrigin:origin];
+ }
+ verticalShift += delta.height;
+
+ // The Download Location controls go in a row with the button aligned to the
+ // right edge and the path control using all the rest of the space.
+ if (view == downloadLocationButton) {
+ NSPoint origin = [downloadLocationButton frame].origin;
+ origin.x -= delta.width;
+ [downloadLocationButton setFrameOrigin:origin];
+ NSSize controlSize = [downloadLocationControl frame].size;
+ controlSize.width -= delta.width;
+ [downloadLocationControl setFrameSize:controlSize];
+ }
+ }
+
+ return verticalShift;
+}
+
+} // namespace
+
+//-------------------------------------------------------------------------
+
+@interface PreferencesWindowController(Private)
+// Callback when preferences are changed. |prefName| is the name of the
+// pref that has changed.
+- (void)prefChanged:(std::string*)prefName;
+// Callback when sync state has changed. syncService_ needs to be
+// queried to find out what happened.
+- (void)syncStateChanged;
+// Record the user performed a certain action and save the preferences.
+- (void)recordUserAction:(const UserMetricsAction&) action;
+- (void)registerPrefObservers;
+- (void)configureInstant;
+
+// KVC setter methods.
+- (void)setNewTabPageIsHomePageIndex:(NSInteger)val;
+- (void)setHomepageURL:(NSString*)urlString;
+- (void)setRestoreOnStartupIndex:(NSInteger)type;
+- (void)setShowHomeButton:(BOOL)value;
+- (void)setPasswordManagerEnabledIndex:(NSInteger)value;
+- (void)setIsUsingDefaultTheme:(BOOL)value;
+- (void)setShowAlternateErrorPages:(BOOL)value;
+- (void)setUseSuggest:(BOOL)value;
+- (void)setDnsPrefetch:(BOOL)value;
+- (void)setSafeBrowsing:(BOOL)value;
+- (void)setMetricsReporting:(BOOL)value;
+- (void)setAskForSaveLocation:(BOOL)value;
+- (void)setFileHandlerUIEnabled:(BOOL)value;
+- (void)setTranslateEnabled:(BOOL)value;
+- (void)setTabsToLinks:(BOOL)value;
+- (void)displayPreferenceViewForPage:(OptionsPage)page
+ animate:(BOOL)animate;
+- (void)resetSubViews;
+- (void)initBannerStateForPage:(OptionsPage)page;
+
+// KVC getter methods.
+- (BOOL)fileHandlerUIEnabled;
+@end
+
+namespace PreferencesWindowControllerInternal {
+
+// A C++ class registered for changes in preferences. Bridges the
+// notification back to the PWC.
+class PrefObserverBridge : public NotificationObserver,
+ public ProfileSyncServiceObserver {
+ public:
+ PrefObserverBridge(PreferencesWindowController* controller)
+ : controller_(controller) {}
+
+ virtual ~PrefObserverBridge() {}
+
+ // Overridden from NotificationObserver:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NotificationType::PREF_CHANGED)
+ [controller_ prefChanged:Details<std::string>(details).ptr()];
+ }
+
+ // Overridden from ProfileSyncServiceObserver.
+ virtual void OnStateChanged() {
+ [controller_ syncStateChanged];
+ }
+
+ private:
+ PreferencesWindowController* controller_; // weak, owns us
+};
+
+// Tracks state for a managed prefs banner and triggers UI updates through the
+// PreferencesWindowController as appropriate.
+class ManagedPrefsBannerState : public policy::ManagedPrefsBannerBase {
+ public:
+ virtual ~ManagedPrefsBannerState() { }
+
+ explicit ManagedPrefsBannerState(PreferencesWindowController* controller,
+ OptionsPage page,
+ PrefService* local_state,
+ PrefService* prefs)
+ : policy::ManagedPrefsBannerBase(local_state, prefs, page),
+ controller_(controller),
+ page_(page) { }
+
+ BOOL IsVisible() {
+ return DetermineVisibility();
+ }
+
+ protected:
+ // Overridden from ManagedPrefsBannerBase.
+ virtual void OnUpdateVisibility() {
+ [controller_ switchToPage:page_ animate:YES];
+ }
+
+ private:
+ PreferencesWindowController* controller_; // weak, owns us
+ OptionsPage page_; // current options page
+};
+
+} // namespace PreferencesWindowControllerInternal
+
+@implementation PreferencesWindowController
+
+@synthesize restoreButtonsEnabled = restoreButtonsEnabled_;
+@synthesize restoreURLsEnabled = restoreURLsEnabled_;
+@synthesize showHomeButtonEnabled = showHomeButtonEnabled_;
+@synthesize defaultSearchEngineEnabled = defaultSearchEngineEnabled_;
+@synthesize passwordManagerChoiceEnabled = passwordManagerChoiceEnabled_;
+@synthesize passwordManagerButtonEnabled = passwordManagerButtonEnabled_;
+@synthesize autoFillSettingsButtonEnabled = autoFillSettingsButtonEnabled_;
+@synthesize showAlternateErrorPagesEnabled = showAlternateErrorPagesEnabled_;
+@synthesize useSuggestEnabled = useSuggestEnabled_;
+@synthesize dnsPrefetchEnabled = dnsPrefetchEnabled_;
+@synthesize safeBrowsingEnabled = safeBrowsingEnabled_;
+@synthesize metricsReportingEnabled = metricsReportingEnabled_;
+@synthesize proxiesConfigureButtonEnabled = proxiesConfigureButtonEnabled_;
+
+- (id)initWithProfile:(Profile*)profile initialPage:(OptionsPage)initialPage {
+ DCHECK(profile);
+ // Use initWithWindowNibPath:: instead of initWithWindowNibName: so we
+ // can override it in a unit test.
+ NSString* nibPath = [mac_util::MainAppBundle()
+ pathForResource:@"Preferences"
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibPath owner:self])) {
+ profile_ = profile->GetOriginalProfile();
+ initialPage_ = initialPage;
+ prefs_ = profile->GetPrefs();
+ DCHECK(prefs_);
+ observer_.reset(
+ new PreferencesWindowControllerInternal::PrefObserverBridge(self));
+
+ // Set up the model for the custom home page table. The KVO observation
+ // tells us when the number of items in the array changes. The normal
+ // observation tells us when one of the URLs of an item changes.
+ customPagesSource_.reset([[CustomHomePagesModel alloc]
+ initWithProfile:profile_]);
+ const SessionStartupPref startupPref =
+ SessionStartupPref::GetStartupPref(prefs_);
+ [customPagesSource_ setURLs:startupPref.urls];
+
+ // Set up the model for the default search popup. Register for notifications
+ // about when the model changes so we can update the selection in the view.
+ searchEngineModel_.reset(
+ [[SearchEngineListModel alloc]
+ initWithModel:profile->GetTemplateURLModel()]);
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(searchEngineModelChanged:)
+ name:kSearchEngineListModelChangedNotification
+ object:searchEngineModel_.get()];
+
+ // This needs to be done before awakeFromNib: because the bindings set up
+ // in the nib rely on it.
+ [self registerPrefObservers];
+
+ // Use one animation so we can stop it if the user clicks quickly, and
+ // start the new animation.
+ animation_.reset([[NSViewAnimation alloc] init]);
+ // Make this the delegate so it can remove the old view at the end of the
+ // animation (once it is faded out).
+ [animation_ setDelegate:self];
+ [animation_ setAnimationBlockingMode:NSAnimationNonblocking];
+
+ // TODO(akalin): handle incognito profiles? The windows version of this
+ // (in chrome/browser/views/options/content_page_view.cc) just does what
+ // we do below.
+ syncService_ = profile_->GetProfileSyncService();
+
+ // TODO(akalin): This color is taken from kSyncLabelErrorBgColor in
+ // content_page_view.cc. Either decomp that color out into a
+ // function/variable that is referenced by both this file and
+ // content_page_view.cc, or maybe pick a more suitable color.
+ syncErrorBackgroundColor_.reset(
+ [[NSColor colorWithDeviceRed:0xff/255.0
+ green:0x9a/255.0
+ blue:0x9a/255.0
+ alpha:1.0] retain]);
+
+ // Disable the |autoFillSettingsButton_| if we have no
+ // |personalDataManager|.
+ PersonalDataManager* personalDataManager =
+ profile_->GetPersonalDataManager();
+ [autoFillSettingsButton_ setHidden:(personalDataManager == NULL)];
+ bool autofill_disabled_by_policy =
+ autoFillEnabled_.IsManaged() && !autoFillEnabled_.GetValue();
+ [self setAutoFillSettingsButtonEnabled:!autofill_disabled_by_policy];
+ [self setPasswordManagerChoiceEnabled:!askSavePasswords_.IsManaged()];
+ [self setPasswordManagerButtonEnabled:
+ !askSavePasswords_.IsManaged() || askSavePasswords_.GetValue()];
+
+ // Initialize the enabled state of the elements on the general tab.
+ [self setShowHomeButtonEnabled:!showHomeButton_.IsManaged()];
+ [self setEnabledStateOfRestoreOnStartup];
+ [self setDefaultSearchEngineEnabled:![searchEngineModel_ isDefaultManaged]];
+
+ // Initialize UI state for the advanced page.
+ [self setShowAlternateErrorPagesEnabled:!alternateErrorPages_.IsManaged()];
+ [self setUseSuggestEnabled:!useSuggest_.IsManaged()];
+ [self setDnsPrefetchEnabled:!dnsPrefetch_.IsManaged()];
+ [self setSafeBrowsingEnabled:!safeBrowsing_.IsManaged()];
+ [self setMetricsReportingEnabled:!metricsReporting_.IsManaged()];
+ proxyPrefs_.reset(
+ PrefSetObserver::CreateProxyPrefSetObserver(prefs_, observer_.get()));
+ [self setProxiesConfigureButtonEnabled:!proxyPrefs_->IsManaged()];
+ }
+ return self;
+}
+
+- (void)awakeFromNib {
+
+ // Validate some assumptions in debug builds.
+
+ // "Basics", "Personal Stuff", and "Under the Hood" views should be the same
+ // width. They should be the same width so they are laid out to look as good
+ // as possible at that width with controls just having to wrap if their text
+ // is too long.
+ DCHECK_EQ(NSWidth([basicsView_ frame]), NSWidth([personalStuffView_ frame]))
+ << "Basics and Personal Stuff should be the same widths";
+ DCHECK_EQ(NSWidth([basicsView_ frame]), NSWidth([underTheHoodView_ frame]))
+ << "Basics and Under the Hood should be the same widths";
+ // "Under the Hood" content should always be skinnier than the scroller it
+ // goes into (we resize it).
+ DCHECK_LE(NSWidth([underTheHoodContentView_ frame]),
+ [underTheHoodScroller_ contentSize].width)
+ << "The Under the Hood content should be narrower than the content "
+ "of the scroller it goes into";
+
+#if !defined(GOOGLE_CHROME_BUILD)
+ // "Enable logging" (breakpad and stats) is only in Google Chrome builds,
+ // remove the checkbox and slide everything above it down.
+ RemoveViewFromView(underTheHoodContentView_, enableLoggingCheckbox_);
+#endif // !defined(GOOGLE_CHROME_BUILD)
+
+ // There are four problem children within the groups:
+ // Basics - Default Browser
+ // Personal Stuff - Sync
+ // Personal Stuff - Themes
+ // Personal Stuff - Browser Data
+ // These four have buttons that with some localizations are wider then the
+ // view. So the four get manually laid out before doing the general work so
+ // the views/window can be made wide enough to fit them. The layout in the
+ // general pass is a noop for these buttons (since they are already sized).
+
+ // Size the default browser button.
+ const NSUInteger kDefaultBrowserGroupCount = 3;
+ const NSUInteger kDefaultBrowserButtonIndex = 1;
+ DCHECK_EQ([basicsGroupDefaultBrowser_ count], kDefaultBrowserGroupCount)
+ << "Expected only two items in Default Browser group";
+ NSButton* defaultBrowserButton =
+ [basicsGroupDefaultBrowser_ objectAtIndex:kDefaultBrowserButtonIndex];
+ NSSize defaultBrowserChange =
+ [GTMUILocalizerAndLayoutTweaker sizeToFitView:defaultBrowserButton];
+ DCHECK_EQ(defaultBrowserChange.height, 0.0)
+ << "Button should have been right height in nib";
+
+ [self configureInstant];
+
+ // Size the sync row.
+ CGFloat syncRowChange = SizeToFitButtonPair(syncButton_,
+ syncCustomizeButton_);
+
+ // Size the themes row.
+ const NSUInteger kThemeGroupCount = 3;
+ const NSUInteger kThemeResetButtonIndex = 1;
+ const NSUInteger kThemeThemesButtonIndex = 2;
+ DCHECK_EQ([personalStuffGroupThemes_ count], kThemeGroupCount)
+ << "Expected only two items in Themes group";
+ CGFloat themeRowChange = SizeToFitButtonPair(
+ [personalStuffGroupThemes_ objectAtIndex:kThemeResetButtonIndex],
+ [personalStuffGroupThemes_ objectAtIndex:kThemeThemesButtonIndex]);
+
+ // Size the Privacy and Clear buttons that make a row in Under the Hood.
+ CGFloat privacyRowChange = SizeToFitButtonPair(contentSettingsButton_,
+ clearDataButton_);
+ // Under the Hood view is narrower (then the other panes) in the nib, subtract
+ // out the amount it was already going to grow to match the other panes when
+ // calculating how much the row needs things to grow.
+ privacyRowChange -=
+ ([underTheHoodScroller_ contentSize].width -
+ NSWidth([underTheHoodContentView_ frame]));
+
+ // Find the most any row changed in size.
+ CGFloat maxWidthChange = std::max(defaultBrowserChange.width, syncRowChange);
+ maxWidthChange = std::max(maxWidthChange, themeRowChange);
+ maxWidthChange = std::max(maxWidthChange, privacyRowChange);
+
+ // If any grew wider, make the views wider. If they all shrank, they fit the
+ // existing view widths, so no change is needed//.
+ if (maxWidthChange > 0.0) {
+ NSSize viewSize = [basicsView_ frame].size;
+ viewSize.width += maxWidthChange;
+ [basicsView_ setFrameSize:viewSize];
+ viewSize = [personalStuffView_ frame].size;
+ viewSize.width += maxWidthChange;
+ [personalStuffView_ setFrameSize:viewSize];
+ }
+
+ // Now that we have the width needed for Basics and Personal Stuff, lay out
+ // those pages bottom up making sure the strings fit and moving things up as
+ // needed.
+
+ CGFloat newWidth = NSWidth([basicsView_ frame]);
+ CGFloat verticalShift = 0.0;
+ verticalShift += AutoSizeGroup(basicsGroupDefaultBrowser_,
+ kAutoSizeGroupBehaviorVerticalFirstToFit,
+ verticalShift);
+ verticalShift += AutoSizeGroup(basicsGroupSearchEngine_,
+ kAutoSizeGroupBehaviorFirstTwoAsRowVerticalToFit,
+ verticalShift);
+ verticalShift += AutoSizeGroup(basicsGroupToolbar_,
+ kAutoSizeGroupBehaviorVerticalToFit,
+ verticalShift);
+ verticalShift += AutoSizeGroup(basicsGroupHomePage_,
+ kAutoSizeGroupBehaviorVerticalToFit,
+ verticalShift);
+ verticalShift += AutoSizeGroup(basicsGroupStartup_,
+ kAutoSizeGroupBehaviorVerticalFirstToFit,
+ verticalShift);
+ [GTMUILocalizerAndLayoutTweaker
+ resizeViewWithoutAutoResizingSubViews:basicsView_
+ delta:NSMakeSize(0.0, verticalShift)];
+
+ verticalShift = 0.0;
+ verticalShift += AutoSizeGroup(personalStuffGroupThemes_,
+ kAutoSizeGroupBehaviorHorizontalToFit,
+ verticalShift);
+ verticalShift += AutoSizeGroup(personalStuffGroupBrowserData_,
+ kAutoSizeGroupBehaviorVerticalToFit,
+ verticalShift);
+ verticalShift += AutoSizeGroup(personalStuffGroupAutofill_,
+ kAutoSizeGroupBehaviorVerticalToFit,
+ verticalShift);
+ verticalShift += AutoSizeGroup(personalStuffGroupPasswords_,
+ kAutoSizeGroupBehaviorVerticalToFit,
+ verticalShift);
+ // TODO(akalin): Here we rely on the initial contents of the sync
+ // group's text field/link field to be large enough to hold all
+ // possible messages so that we don't have to re-layout when sync
+ // state changes. This isn't perfect, since e.g. some sync messages
+ // use the user's e-mail address (which may be really long), and the
+ // link field is usually not shown (leaving a big empty space).
+ // Rethink sync preferences UI for Mac.
+ verticalShift += AutoSizeGroup(personalStuffGroupSync_,
+ kAutoSizeGroupBehaviorVerticalToFit,
+ verticalShift);
+ [GTMUILocalizerAndLayoutTweaker
+ resizeViewWithoutAutoResizingSubViews:personalStuffView_
+ delta:NSMakeSize(0.0, verticalShift)];
+
+ if (syncService_) {
+ syncService_->AddObserver(observer_.get());
+ // Update the controls according to the initial state.
+ [self syncStateChanged];
+ } else {
+ // If sync is disabled we don't want to show the sync controls at all.
+ RemoveGroupFromView(personalStuffView_, personalStuffGroupSync_);
+ }
+
+ // Make the window as wide as the views.
+ NSWindow* prefsWindow = [self window];
+ NSView* prefsContentView = [prefsWindow contentView];
+ NSRect frame = [prefsContentView convertRect:[prefsWindow frame]
+ fromView:nil];
+ frame.size.width = newWidth;
+ frame = [prefsContentView convertRect:frame toView:nil];
+ [prefsWindow setFrame:frame display:NO];
+
+ // The Under the Hood prefs is a scroller, it shouldn't get any border, so it
+ // gets resized to be as wide as the window ended up.
+ NSSize underTheHoodSize = [underTheHoodView_ frame].size;
+ underTheHoodSize.width = newWidth;
+ [underTheHoodView_ setFrameSize:underTheHoodSize];
+
+ // Widen the Under the Hood content so things can rewrap to the full width.
+ NSSize underTheHoodContentSize = [underTheHoodContentView_ frame].size;
+ underTheHoodContentSize.width = [underTheHoodScroller_ contentSize].width;
+ [underTheHoodContentView_ setFrameSize:underTheHoodContentSize];
+
+ // Now that Under the Hood is the right width, auto-size to the new width to
+ // get the final height.
+ verticalShift = AutoSizeUnderTheHoodContent(underTheHoodContentView_,
+ downloadLocationControl_,
+ downloadLocationButton_);
+ [GTMUILocalizerAndLayoutTweaker
+ resizeViewWithoutAutoResizingSubViews:underTheHoodContentView_
+ delta:NSMakeSize(0.0, verticalShift)];
+ underTheHoodContentSize = [underTheHoodContentView_ frame].size;
+
+ // Put the Under the Hood content view into the scroller and scroll it to the
+ // top.
+ [underTheHoodScroller_ setDocumentView:underTheHoodContentView_];
+ [underTheHoodContentView_ scrollPoint:
+ NSMakePoint(0, underTheHoodContentSize.height)];
+
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ NSImage* alertIcon = rb.GetNativeImageNamed(IDR_WARNING);
+ DCHECK(alertIcon);
+ [managedPrefsBannerWarningImage_ setImage:alertIcon];
+
+ [self initBannerStateForPage:initialPage_];
+ [self switchToPage:initialPage_ animate:NO];
+
+ // Save/restore position based on prefs.
+ if (g_browser_process && g_browser_process->local_state()) {
+ sizeSaver_.reset([[WindowSizeAutosaver alloc]
+ initWithWindow:[self window]
+ prefService:g_browser_process->local_state()
+ path:prefs::kPreferencesWindowPlacement]);
+ }
+
+ // Initialize the banner gradient and stroke color.
+ NSColor* bannerStartingColor =
+ [NSColor colorWithCalibratedRed:kBannerGradientColorTop[0]
+ green:kBannerGradientColorTop[1]
+ blue:kBannerGradientColorTop[2]
+ alpha:1.0];
+ NSColor* bannerEndingColor =
+ [NSColor colorWithCalibratedRed:kBannerGradientColorBottom[0]
+ green:kBannerGradientColorBottom[1]
+ blue:kBannerGradientColorBottom[2]
+ alpha:1.0];
+ scoped_nsobject<NSGradient> bannerGradient(
+ [[NSGradient alloc] initWithStartingColor:bannerStartingColor
+ endingColor:bannerEndingColor]);
+ [managedPrefsBannerView_ setGradient:bannerGradient];
+
+ NSColor* bannerStrokeColor =
+ [NSColor colorWithCalibratedWhite:kBannerStrokeColor
+ alpha:1.0];
+ [managedPrefsBannerView_ setStrokeColor:bannerStrokeColor];
+
+ // Set accessibility related attributes.
+ NSTableView* tableView = [basicsView_ viewWithTag:kBasicsStartupPageTableTag];
+ NSString* description =
+ l10n_util::GetNSStringWithFixup(IDS_OPTIONS_STARTUP_SHOW_PAGES);
+ [tableView accessibilitySetOverrideValue:description
+ forAttribute:NSAccessibilityDescriptionAttribute];
+}
+
+- (void)dealloc {
+ if (syncService_) {
+ syncService_->RemoveObserver(observer_.get());
+ }
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [animation_ setDelegate:nil];
+ [animation_ stopAnimation];
+ [super dealloc];
+}
+
+// Xcode 3.1.x version of Interface Builder doesn't do a lot for editing
+// toolbars in XIB. So the toolbar's delegate is set to the controller so it
+// can tell the toolbar what items are selectable.
+- (NSArray*)toolbarSelectableItemIdentifiers:(NSToolbar*)toolbar {
+ DCHECK(toolbar == toolbar_);
+ return [[toolbar_ items] valueForKey:@"itemIdentifier"];
+}
+
+// Register our interest in the preferences we're displaying so if anything
+// else in the UI changes them we will be updated.
+- (void)registerPrefObservers {
+ if (!prefs_) return;
+
+ // Basics panel
+ registrar_.Init(prefs_);
+ registrar_.Add(prefs::kURLsToRestoreOnStartup, observer_.get());
+ restoreOnStartup_.Init(prefs::kRestoreOnStartup, prefs_, observer_.get());
+ newTabPageIsHomePage_.Init(prefs::kHomePageIsNewTabPage,
+ prefs_, observer_.get());
+ homepage_.Init(prefs::kHomePage, prefs_, observer_.get());
+ showHomeButton_.Init(prefs::kShowHomeButton, prefs_, observer_.get());
+ instantEnabled_.Init(prefs::kInstantEnabled, prefs_, observer_.get());
+
+ // Personal Stuff panel
+ askSavePasswords_.Init(prefs::kPasswordManagerEnabled,
+ prefs_, observer_.get());
+ autoFillEnabled_.Init(prefs::kAutoFillEnabled, prefs_, observer_.get());
+ currentTheme_.Init(prefs::kCurrentThemeID, prefs_, observer_.get());
+
+ // Under the hood panel
+ alternateErrorPages_.Init(prefs::kAlternateErrorPagesEnabled,
+ prefs_, observer_.get());
+ useSuggest_.Init(prefs::kSearchSuggestEnabled, prefs_, observer_.get());
+ dnsPrefetch_.Init(prefs::kDnsPrefetchingEnabled, prefs_, observer_.get());
+ safeBrowsing_.Init(prefs::kSafeBrowsingEnabled, prefs_, observer_.get());
+ autoOpenFiles_.Init(
+ prefs::kDownloadExtensionsToOpen, prefs_, observer_.get());
+ translateEnabled_.Init(prefs::kEnableTranslate, prefs_, observer_.get());
+ tabsToLinks_.Init(prefs::kWebkitTabsToLinks, prefs_, observer_.get());
+
+ // During unit tests, there is no local state object, so we fall back to
+ // the prefs object (where we've explicitly registered this pref so we
+ // know it's there).
+ PrefService* local = g_browser_process->local_state();
+ if (!local)
+ local = prefs_;
+ metricsReporting_.Init(prefs::kMetricsReportingEnabled,
+ local, observer_.get());
+ defaultDownloadLocation_.Init(prefs::kDownloadDefaultDirectory, prefs_,
+ observer_.get());
+ askForSaveLocation_.Init(prefs::kPromptForDownload, prefs_, observer_.get());
+
+ // We don't need to observe changes in this value.
+ lastSelectedPage_.Init(prefs::kOptionsWindowLastTabIndex, local, NULL);
+}
+
+// Called when the window wants to be closed.
+- (BOOL)windowShouldClose:(id)sender {
+ // Stop any animation and clear the delegate to avoid stale pointers.
+ [animation_ setDelegate:nil];
+ [animation_ stopAnimation];
+
+ return YES;
+}
+
+// Called when the user hits the escape key. Closes the window.
+- (void)cancel:(id)sender {
+ [[self window] performClose:self];
+}
+
+// Record the user performed a certain action and save the preferences.
+- (void)recordUserAction:(const UserMetricsAction &)action {
+ UserMetrics::RecordAction(action, profile_);
+ if (prefs_)
+ prefs_->ScheduleSavePersistentPrefs();
+}
+
+// Returns the set of keys that |key| depends on for its value so it can be
+// re-computed when any of those change as well.
++ (NSSet*)keyPathsForValuesAffectingValueForKey:(NSString*)key {
+ NSSet* paths = [super keyPathsForValuesAffectingValueForKey:key];
+ if ([key isEqualToString:@"isHomepageURLEnabled"]) {
+ paths = [paths setByAddingObject:@"newTabPageIsHomePageIndex"];
+ paths = [paths setByAddingObject:@"homepageURL"];
+ } else if ([key isEqualToString:@"restoreURLsEnabled"]) {
+ paths = [paths setByAddingObject:@"restoreOnStartupIndex"];
+ } else if ([key isEqualToString:@"isHomepageChoiceEnabled"]) {
+ paths = [paths setByAddingObject:@"newTabPageIsHomePageIndex"];
+ paths = [paths setByAddingObject:@"homepageURL"];
+ } else if ([key isEqualToString:@"newTabPageIsHomePageIndex"]) {
+ paths = [paths setByAddingObject:@"homepageURL"];
+ } else if ([key isEqualToString:@"hompageURL"]) {
+ paths = [paths setByAddingObject:@"newTabPageIsHomePageIndex"];
+ } else if ([key isEqualToString:@"isDefaultBrowser"]) {
+ paths = [paths setByAddingObject:@"defaultBrowser"];
+ } else if ([key isEqualToString:@"defaultBrowserTextColor"]) {
+ paths = [paths setByAddingObject:@"defaultBrowser"];
+ } else if ([key isEqualToString:@"defaultBrowserText"]) {
+ paths = [paths setByAddingObject:@"defaultBrowser"];
+ }
+ return paths;
+}
+
+// Launch the Keychain Access app.
+- (void)launchKeychainAccess {
+ NSString* const kKeychainBundleId = @"com.apple.keychainaccess";
+ [[NSWorkspace sharedWorkspace]
+ launchAppWithBundleIdentifier:kKeychainBundleId
+ options:0L
+ additionalEventParamDescriptor:nil
+ launchIdentifier:nil];
+}
+
+//-------------------------------------------------------------------------
+// Basics panel
+
+// Sets the home page preferences for kNewTabPageIsHomePage and kHomePage. If a
+// blank or null-host URL is passed in we revert to using NewTab page
+// as the Home page. Note: using SetValue() causes the observers not to fire,
+// which is actually a good thing as we could end up in a state where setting
+// the homepage to an empty url would automatically reset the prefs back to
+// using the NTP, so we'd be never be able to change it.
+- (void)setHomepage:(const GURL&)homepage {
+ if (IsNewTabUIURLString(homepage)) {
+ newTabPageIsHomePage_.SetValueIfNotManaged(true);
+ homepage_.SetValueIfNotManaged(std::string());
+ } else if (!homepage.is_valid()) {
+ newTabPageIsHomePage_.SetValueIfNotManaged(true);
+ if (!homepage.has_host())
+ homepage_.SetValueIfNotManaged(std::string());
+ } else {
+ homepage_.SetValueIfNotManaged(homepage.spec());
+ }
+}
+
+// Callback when preferences are changed by someone modifying the prefs backend
+// externally. |prefName| is the name of the pref that has changed. Unlike on
+// Windows, we don't need to use this method for initializing, that's handled by
+// Cocoa Bindings.
+// Handles prefs for the "Basics" panel.
+- (void)basicsPrefChanged:(std::string*)prefName {
+ if (*prefName == prefs::kRestoreOnStartup) {
+ const SessionStartupPref startupPref =
+ SessionStartupPref::GetStartupPref(prefs_);
+ [self setRestoreOnStartupIndex:startupPref.type];
+ [self setEnabledStateOfRestoreOnStartup];
+ } else if (*prefName == prefs::kURLsToRestoreOnStartup) {
+ [customPagesSource_ reloadURLs];
+ [self setEnabledStateOfRestoreOnStartup];
+ } else if (*prefName == prefs::kHomePageIsNewTabPage) {
+ NSInteger useNewTabPage = newTabPageIsHomePage_.GetValue() ? 0 : 1;
+ [self setNewTabPageIsHomePageIndex:useNewTabPage];
+ } else if (*prefName == prefs::kHomePage) {
+ NSString* value = base::SysUTF8ToNSString(homepage_.GetValue());
+ [self setHomepageURL:value];
+ } else if (*prefName == prefs::kShowHomeButton) {
+ [self setShowHomeButton:showHomeButton_.GetValue() ? YES : NO];
+ [self setShowHomeButtonEnabled:!showHomeButton_.IsManaged()];
+ } else if (*prefName == prefs::kInstantEnabled) {
+ [self configureInstant];
+ }
+}
+
+// Returns the index of the selected cell in the "on startup" matrix based
+// on the "restore on startup" pref. The ordering of the cells is in the
+// same order as the pref.
+- (NSInteger)restoreOnStartupIndex {
+ const SessionStartupPref pref = SessionStartupPref::GetStartupPref(prefs_);
+ return pref.type;
+}
+
+// A helper function that takes the startup session type, grabs the URLs to
+// restore, and saves it all in prefs.
+- (void)saveSessionStartupWithType:(SessionStartupPref::Type)type {
+ SessionStartupPref pref;
+ pref.type = type;
+ pref.urls = [customPagesSource_.get() URLs];
+ SessionStartupPref::SetStartupPref(prefs_, pref);
+}
+
+// Sets the pref based on the index of the selected cell in the matrix and
+// marks the appropriate user metric.
+- (void)setRestoreOnStartupIndex:(NSInteger)type {
+ SessionStartupPref::Type startupType =
+ static_cast<SessionStartupPref::Type>(type);
+ switch (startupType) {
+ case SessionStartupPref::DEFAULT:
+ [self recordUserAction:UserMetricsAction("Options_Startup_Homepage")];
+ break;
+ case SessionStartupPref::LAST:
+ [self recordUserAction:UserMetricsAction("Options_Startup_LastSession")];
+ break;
+ case SessionStartupPref::URLS:
+ [self recordUserAction:UserMetricsAction("Options_Startup_Custom")];
+ break;
+ default:
+ NOTREACHED();
+ }
+ [self saveSessionStartupWithType:startupType];
+}
+
+// Enables or disables the restoreOnStartup elements
+- (void) setEnabledStateOfRestoreOnStartup {
+ const SessionStartupPref startupPref =
+ SessionStartupPref::GetStartupPref(prefs_);
+ [self setRestoreButtonsEnabled:!SessionStartupPref::TypeIsManaged(prefs_)];
+ [self setRestoreURLsEnabled:!SessionStartupPref::URLsAreManaged(prefs_) &&
+ [self restoreOnStartupIndex] == SessionStartupPref::URLS];
+}
+
+// Getter for the |customPagesSource| property for bindings.
+- (CustomHomePagesModel*)customPagesSource {
+ return customPagesSource_.get();
+}
+
+// Called when the selection in the table changes. If a flag is set indicating
+// that we're waiting for a special select message, edit the cell. Otherwise
+// just ignore it, we don't normally care.
+- (void)tableViewSelectionDidChange:(NSNotification*)aNotification {
+ if (pendingSelectForEdit_) {
+ NSTableView* table = [aNotification object];
+ NSUInteger selectedRow = [table selectedRow];
+ [table editColumn:0 row:selectedRow withEvent:nil select:YES];
+ pendingSelectForEdit_ = NO;
+ }
+}
+
+// Called when the user hits the (+) button for adding a new homepage to the
+// list. This will also attempt to make the new item editable so the user can
+// just start typing.
+- (IBAction)addHomepage:(id)sender {
+ [customPagesArrayController_ add:sender];
+
+ // When the new item is added to the model, the array controller will select
+ // it. We'll watch for that notification (because we are the table view's
+ // delegate) and then make the cell editable. Note that this can't be
+ // accomplished simply by subclassing the array controller's add method (I
+ // did try). The update of the table is asynchronous with the controller
+ // updating the model.
+ pendingSelectForEdit_ = YES;
+}
+
+// Called when the user hits the (-) button for removing the selected items in
+// the homepage table. The controller does all the work.
+- (IBAction)removeSelectedHomepages:(id)sender {
+ [customPagesArrayController_ remove:sender];
+}
+
+// Add all entries for all open browsers with our profile.
+- (IBAction)useCurrentPagesAsHomepage:(id)sender {
+ std::vector<GURL> urls;
+ for (BrowserList::const_iterator browserIter = BrowserList::begin();
+ browserIter != BrowserList::end(); ++browserIter) {
+ Browser* browser = *browserIter;
+ if (browser->profile() != profile_)
+ continue; // Only want entries for open profile.
+
+ for (int tabIndex = 0; tabIndex < browser->tab_count(); ++tabIndex) {
+ TabContents* tab = browser->GetTabContentsAt(tabIndex);
+ if (tab->ShouldDisplayURL()) {
+ const GURL url = browser->GetTabContentsAt(tabIndex)->GetURL();
+ if (!url.is_empty())
+ urls.push_back(url);
+ }
+ }
+ }
+ [customPagesSource_ setURLs:urls];
+}
+
+enum { kHomepageNewTabPage, kHomepageURL };
+
+// Here's a table describing the desired characteristics of the homepage choice
+// radio value, it's enabled state and the URL field enabled state. They depend
+// on the values of the managed bits for homepage (m_hp) and
+// homepageIsNewTabPage (m_ntp) preferences, as well as the value of the
+// homepageIsNewTabPage preference (ntp) and whether the homepage preference
+// is equal to the new tab page URL (hpisntp).
+//
+// m_hp m_ntp ntp hpisntp | choice value | choice enabled | URL field enabled
+// --------------------------------------------------------------------------
+// 0 0 0 0 | homepage | 1 | 1
+// 0 0 0 1 | new tab page | 1 | 0
+// 0 0 1 0 | new tab page | 1 | 0
+// 0 0 1 1 | new tab page | 1 | 0
+// 0 1 0 0 | homepage | 0 | 1
+// 0 1 0 1 | homepage | 0 | 1
+// 0 1 1 0 | new tab page | 0 | 0
+// 0 1 1 1 | new tab page | 0 | 0
+// 1 0 0 0 | homepage | 1 | 0
+// 1 0 0 1 | new tab page | 0 | 0
+// 1 0 1 0 | new tab page | 1 | 0
+// 1 0 1 1 | new tab page | 0 | 0
+// 1 1 0 0 | homepage | 0 | 0
+// 1 1 0 1 | new tab page | 0 | 0
+// 1 1 1 0 | new tab page | 0 | 0
+// 1 1 1 1 | new tab page | 0 | 0
+//
+// thus, we have:
+//
+// choice value is new tab page === ntp || (hpisntp && (m_hp || !m_ntp))
+// choice enabled === !m_ntp && !(m_hp && hpisntp)
+// URL field enabled === !ntp && !mhp && !(hpisntp && !m_ntp)
+//
+// which also make sense if you think about them.
+
+// Checks whether the homepage URL refers to the new tab page.
+- (BOOL)isHomepageNewTabUIURL {
+ return IsNewTabUIURLString(GURL(homepage_.GetValue().c_str()));
+}
+
+// Returns the index of the selected cell in the "home page" marix based on
+// the "new tab is home page" pref. Sadly, the ordering is reversed from the
+// pref value.
+- (NSInteger)newTabPageIsHomePageIndex {
+ return newTabPageIsHomePage_.GetValue() ||
+ ([self isHomepageNewTabUIURL] &&
+ (homepage_.IsManaged() || !newTabPageIsHomePage_.IsManaged())) ?
+ kHomepageNewTabPage : kHomepageURL;
+}
+
+// Sets the pref based on the given index into the matrix and marks the
+// appropriate user metric.
+- (void)setNewTabPageIsHomePageIndex:(NSInteger)index {
+ bool useNewTabPage = index == kHomepageNewTabPage ? true : false;
+ if (useNewTabPage) {
+ [self recordUserAction:UserMetricsAction("Options_Homepage_UseNewTab")];
+ } else {
+ [self recordUserAction:UserMetricsAction("Options_Homepage_UseURL")];
+ if ([self isHomepageNewTabUIURL])
+ homepage_.SetValueIfNotManaged(std::string());
+ }
+ newTabPageIsHomePage_.SetValueIfNotManaged(useNewTabPage);
+}
+
+// Check whether the new tab and URL homepage radios should be enabled, i.e. if
+// the corresponding preference is not managed through configuration policy.
+- (BOOL)isHomepageChoiceEnabled {
+ return !newTabPageIsHomePage_.IsManaged() &&
+ !(homepage_.IsManaged() && [self isHomepageNewTabUIURL]);
+}
+
+// Returns whether or not the homepage URL text field should be enabled
+// based on if the new tab page is the home page.
+- (BOOL)isHomepageURLEnabled {
+ return !newTabPageIsHomePage_.GetValue() && !homepage_.IsManaged() &&
+ !([self isHomepageNewTabUIURL] && !newTabPageIsHomePage_.IsManaged());
+}
+
+// Returns the homepage URL.
+- (NSString*)homepageURL {
+ NSString* value = base::SysUTF8ToNSString(homepage_.GetValue());
+ return [self isHomepageNewTabUIURL] ? nil : value;
+}
+
+// Sets the homepage URL to |urlString| with some fixing up.
+- (void)setHomepageURL:(NSString*)urlString {
+ // If the text field contains a valid URL, sync it to prefs. We run it
+ // through the fixer upper to allow input like "google.com" to be converted
+ // to something valid ("http://google.com").
+ std::string unfixedURL = urlString ? base::SysNSStringToUTF8(urlString) :
+ chrome::kChromeUINewTabURL;
+ [self setHomepage:URLFixerUpper::FixupURL(unfixedURL, std::string())];
+}
+
+// Returns whether the home button should be checked based on the preference.
+- (BOOL)showHomeButton {
+ return showHomeButton_.GetValue() ? YES : NO;
+}
+
+// Sets the backend pref for whether or not the home button should be displayed
+// based on |value|.
+- (void)setShowHomeButton:(BOOL)value {
+ if (value)
+ [self recordUserAction:UserMetricsAction(
+ "Options_Homepage_ShowHomeButton")];
+ else
+ [self recordUserAction:UserMetricsAction(
+ "Options_Homepage_HideHomeButton")];
+ showHomeButton_.SetValueIfNotManaged(value ? true : false);
+}
+
+// Getter for the |searchEngineModel| property for bindings.
+- (id)searchEngineModel {
+ return searchEngineModel_.get();
+}
+
+// Bindings for the search engine popup. We not binding directly to the model
+// in order to siphon off the setter so we can record the metric. If we're
+// doing it with one, might as well do it with both.
+- (NSUInteger)searchEngineSelectedIndex {
+ return [searchEngineModel_ defaultIndex];
+}
+
+- (void)setSearchEngineSelectedIndex:(NSUInteger)index {
+ [self recordUserAction:UserMetricsAction("Options_SearchEngineChanged")];
+ [searchEngineModel_ setDefaultIndex:index];
+}
+
+// Called when the search engine model changes. Update the selection in the
+// popup by tickling the bindings with the new value.
+- (void)searchEngineModelChanged:(NSNotification*)notify {
+ [self setSearchEngineSelectedIndex:[self searchEngineSelectedIndex]];
+ [self setDefaultSearchEngineEnabled:![searchEngineModel_ isDefaultManaged]];
+
+}
+
+- (IBAction)manageSearchEngines:(id)sender {
+ [KeywordEditorCocoaController showKeywordEditor:profile_];
+}
+
+- (IBAction)toggleInstant:(id)sender {
+ if (instantEnabled_.GetValue()) {
+ InstantController::Disable(profile_);
+ } else {
+ [instantCheckbox_ setState:NSOffState];
+ browser::ShowInstantConfirmDialogIfNecessary([self window], profile_);
+ }
+}
+
+// Sets the state of the Instant checkbox and adds the type information to the
+// label.
+- (void)configureInstant {
+ bool enabled = instantEnabled_.GetValue();
+ NSInteger state = enabled ? NSOnState : NSOffState;
+ [instantCheckbox_ setState:state];
+}
+
+- (IBAction)learnMoreAboutInstant:(id)sender {
+ browser::ShowOptionsURL(profile_, browser::InstantLearnMoreURL());
+}
+
+// Called when the user clicks the button to make Chromium the default
+// browser. Registers http and https.
+- (IBAction)makeDefaultBrowser:(id)sender {
+ [self willChangeValueForKey:@"defaultBrowser"];
+
+ ShellIntegration::SetAsDefaultBrowser();
+ [self recordUserAction:UserMetricsAction("Options_SetAsDefaultBrowser")];
+ // If the user made Chrome the default browser, then he/she arguably wants
+ // to be notified when that changes.
+ prefs_->SetBoolean(prefs::kCheckDefaultBrowser, true);
+
+ // Tickle KVO so that the UI updates.
+ [self didChangeValueForKey:@"defaultBrowser"];
+}
+
+// Returns the Chromium default browser state.
+- (ShellIntegration::DefaultBrowserState)isDefaultBrowser {
+ return ShellIntegration::IsDefaultBrowser();
+}
+
+// Returns the text color of the "chromium is your default browser" text (green
+// for yes, red for no).
+- (NSColor*)defaultBrowserTextColor {
+ ShellIntegration::DefaultBrowserState state = [self isDefaultBrowser];
+ return (state == ShellIntegration::IS_DEFAULT_BROWSER) ?
+ [NSColor colorWithCalibratedRed:0.0 green:135.0/255.0 blue:0 alpha:1.0] :
+ [NSColor colorWithCalibratedRed:135.0/255.0 green:0 blue:0 alpha:1.0];
+}
+
+// Returns the text for the "chromium is your default browser" string dependent
+// on if Chromium actually is or not.
+- (NSString*)defaultBrowserText {
+ ShellIntegration::DefaultBrowserState state = [self isDefaultBrowser];
+ int stringId;
+ if (state == ShellIntegration::IS_DEFAULT_BROWSER)
+ stringId = IDS_OPTIONS_DEFAULTBROWSER_DEFAULT;
+ else if (state == ShellIntegration::NOT_DEFAULT_BROWSER)
+ stringId = IDS_OPTIONS_DEFAULTBROWSER_NOTDEFAULT;
+ else
+ stringId = IDS_OPTIONS_DEFAULTBROWSER_UNKNOWN;
+ string16 text =
+ l10n_util::GetStringFUTF16(stringId,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
+ return base::SysUTF16ToNSString(text);
+}
+
+//-------------------------------------------------------------------------
+// User Data panel
+
+// Since passwords and forms are radio groups, 'enabled' is index 0 and
+// 'disabled' is index 1. Yay.
+const int kEnabledIndex = 0;
+const int kDisabledIndex = 1;
+
+// Callback when preferences are changed. |prefName| is the name of the pref
+// that has changed. Unlike on Windows, we don't need to use this method for
+// initializing, that's handled by Cocoa Bindings.
+// Handles prefs for the "Personal Stuff" panel.
+- (void)userDataPrefChanged:(std::string*)prefName {
+ if (*prefName == prefs::kPasswordManagerEnabled) {
+ [self setPasswordManagerEnabledIndex:askSavePasswords_.GetValue() ?
+ kEnabledIndex : kDisabledIndex];
+ [self setPasswordManagerChoiceEnabled:!askSavePasswords_.IsManaged()];
+ [self setPasswordManagerButtonEnabled:
+ !askSavePasswords_.IsManaged() || askSavePasswords_.GetValue()];
+ }
+ if (*prefName == prefs::kAutoFillEnabled) {
+ bool autofill_disabled_by_policy =
+ autoFillEnabled_.IsManaged() && !autoFillEnabled_.GetValue();
+ [self setAutoFillSettingsButtonEnabled:!autofill_disabled_by_policy];
+ }
+ if (*prefName == prefs::kCurrentThemeID) {
+ [self setIsUsingDefaultTheme:currentTheme_.GetValue().length() == 0];
+ }
+}
+
+// Called to launch the Keychain Access app to show the user's stored
+// passwords.
+- (IBAction)showSavedPasswords:(id)sender {
+ [self recordUserAction:UserMetricsAction("Options_ShowPasswordsExceptions")];
+ [self launchKeychainAccess];
+}
+
+// Called to show the Auto Fill Settings dialog.
+- (IBAction)showAutoFillSettings:(id)sender {
+ [self recordUserAction:UserMetricsAction("Options_ShowAutoFillSettings")];
+
+ PersonalDataManager* personalDataManager = profile_->GetPersonalDataManager();
+ if (!personalDataManager) {
+ // Should not reach here because button is disabled when
+ // |personalDataManager| is NULL.
+ NOTREACHED();
+ return;
+ }
+
+ ShowAutoFillDialog(NULL, personalDataManager, profile_);
+}
+
+// Called to import data from other browsers (Safari, Firefox, etc).
+- (IBAction)importData:(id)sender {
+ UserMetrics::RecordAction(UserMetricsAction("Import_ShowDlg"), profile_);
+ [ImportSettingsDialogController showImportSettingsDialogForProfile:profile_];
+}
+
+- (IBAction)resetThemeToDefault:(id)sender {
+ [self recordUserAction:UserMetricsAction("Options_ThemesReset")];
+ profile_->ClearTheme();
+}
+
+- (IBAction)themesGallery:(id)sender {
+ [self recordUserAction:UserMetricsAction("Options_ThemesGallery")];
+ Browser* browser = BrowserList::GetLastActive();
+
+ if (!browser || !browser->GetSelectedTabContents())
+ browser = Browser::Create(profile_);
+ browser->OpenThemeGalleryTabAndActivate();
+}
+
+// Called when the "stop syncing" confirmation dialog started by
+// doSyncAction is finished. Stop syncing only If the user clicked
+// OK.
+- (void)stopSyncAlertDidEnd:(NSAlert*)alert
+ returnCode:(int)returnCode
+ contextInfo:(void*)contextInfo {
+ DCHECK(syncService_ && !syncService_->IsManaged());
+ if (returnCode == NSAlertFirstButtonReturn) {
+ syncService_->DisableForUser();
+ ProfileSyncService::SyncEvent(ProfileSyncService::STOP_FROM_OPTIONS);
+ }
+}
+
+// Called when the user clicks the multi-purpose sync button in the
+// "Personal Stuff" pane.
+- (IBAction)doSyncAction:(id)sender {
+ DCHECK(syncService_ && !syncService_->IsManaged());
+ if (syncService_->HasSyncSetupCompleted()) {
+ // If sync setup has completed that means the sync button was a
+ // "stop syncing" button. Bring up a confirmation dialog before
+ // actually stopping syncing (see stopSyncAlertDidEnd).
+ scoped_nsobject<NSAlert> alert([[NSAlert alloc] init]);
+ [alert addButtonWithTitle:l10n_util::GetNSStringWithFixup(
+ IDS_SYNC_STOP_SYNCING_CONFIRM_BUTTON_LABEL)];
+ [alert addButtonWithTitle:l10n_util::GetNSStringWithFixup(
+ IDS_CANCEL)];
+ [alert setMessageText:l10n_util::GetNSStringWithFixup(
+ IDS_SYNC_STOP_SYNCING_DIALOG_TITLE)];
+ [alert setInformativeText:l10n_util::GetNSStringFWithFixup(
+ IDS_SYNC_STOP_SYNCING_EXPLANATION_LABEL,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME))];
+ [alert setAlertStyle:NSWarningAlertStyle];
+ const SEL kEndSelector =
+ @selector(stopSyncAlertDidEnd:returnCode:contextInfo:);
+ [alert beginSheetModalForWindow:[self window]
+ modalDelegate:self
+ didEndSelector:kEndSelector
+ contextInfo:NULL];
+ } else {
+ // Otherwise, the sync button was a "sync my bookmarks" button.
+ // Kick off the sync setup process.
+ syncService_->ShowLoginDialog(NULL);
+ ProfileSyncService::SyncEvent(ProfileSyncService::START_FROM_OPTIONS);
+ }
+}
+
+// Called when the user clicks on the link to the privacy dashboard.
+- (IBAction)showPrivacyDashboard:(id)sender {
+ Browser* browser = BrowserList::GetLastActive();
+
+ if (!browser || !browser->GetSelectedTabContents())
+ browser = Browser::Create(profile_);
+ browser->OpenPrivacyDashboardTabAndActivate();
+}
+
+// Called when the user clicks the "Customize Sync" button in the
+// "Personal Stuff" pane. Spawns a dialog-modal sheet that cleans
+// itself up on close.
+- (IBAction)doSyncCustomize:(id)sender {
+ syncService_->ShowConfigure(NULL);
+}
+
+- (IBAction)doSyncReauthentication:(id)sender {
+ DCHECK(syncService_ && !syncService_->IsManaged());
+ syncService_->ShowLoginDialog(NULL);
+}
+
+- (void)setPasswordManagerEnabledIndex:(NSInteger)value {
+ if (value == kEnabledIndex)
+ [self recordUserAction:UserMetricsAction(
+ "Options_PasswordManager_Enable")];
+ else
+ [self recordUserAction:UserMetricsAction(
+ "Options_PasswordManager_Disable")];
+ askSavePasswords_.SetValueIfNotManaged(value == kEnabledIndex ? true : false);
+}
+
+- (NSInteger)passwordManagerEnabledIndex {
+ return askSavePasswords_.GetValue() ? kEnabledIndex : kDisabledIndex;
+}
+
+- (void)setIsUsingDefaultTheme:(BOOL)value {
+ if (value)
+ [self recordUserAction:UserMetricsAction(
+ "Options_IsUsingDefaultTheme_Enable")];
+ else
+ [self recordUserAction:UserMetricsAction(
+ "Options_IsUsingDefaultTheme_Disable")];
+}
+
+- (BOOL)isUsingDefaultTheme {
+ return currentTheme_.GetValue().length() == 0;
+}
+
+//-------------------------------------------------------------------------
+// Under the hood panel
+
+// Callback when preferences are changed. |prefName| is the name of the pref
+// that has changed. Unlike on Windows, we don't need to use this method for
+// initializing, that's handled by Cocoa Bindings.
+// Handles prefs for the "Under the hood" panel.
+- (void)underHoodPrefChanged:(std::string*)prefName {
+ if (*prefName == prefs::kAlternateErrorPagesEnabled) {
+ [self setShowAlternateErrorPages:
+ alternateErrorPages_.GetValue() ? YES : NO];
+ [self setShowAlternateErrorPagesEnabled:!alternateErrorPages_.IsManaged()];
+ }
+ else if (*prefName == prefs::kSearchSuggestEnabled) {
+ [self setUseSuggest:useSuggest_.GetValue() ? YES : NO];
+ [self setUseSuggestEnabled:!useSuggest_.IsManaged()];
+ }
+ else if (*prefName == prefs::kDnsPrefetchingEnabled) {
+ [self setDnsPrefetch:dnsPrefetch_.GetValue() ? YES : NO];
+ [self setDnsPrefetchEnabled:!dnsPrefetch_.IsManaged()];
+ }
+ else if (*prefName == prefs::kSafeBrowsingEnabled) {
+ [self setSafeBrowsing:safeBrowsing_.GetValue() ? YES : NO];
+ [self setSafeBrowsingEnabled:!safeBrowsing_.IsManaged()];
+ }
+ else if (*prefName == prefs::kMetricsReportingEnabled) {
+ [self setMetricsReporting:metricsReporting_.GetValue() ? YES : NO];
+ [self setMetricsReportingEnabled:!metricsReporting_.IsManaged()];
+ }
+ else if (*prefName == prefs::kDownloadDefaultDirectory) {
+ // Poke KVO.
+ [self willChangeValueForKey:@"defaultDownloadLocation"];
+ [self didChangeValueForKey:@"defaultDownloadLocation"];
+ }
+ else if (*prefName == prefs::kPromptForDownload) {
+ [self setAskForSaveLocation:askForSaveLocation_.GetValue() ? YES : NO];
+ }
+ else if (*prefName == prefs::kEnableTranslate) {
+ [self setTranslateEnabled:translateEnabled_.GetValue() ? YES : NO];
+ }
+ else if (*prefName == prefs::kWebkitTabsToLinks) {
+ [self setTabsToLinks:tabsToLinks_.GetValue() ? YES : NO];
+ }
+ else if (*prefName == prefs::kDownloadExtensionsToOpen) {
+ // Poke KVC.
+ [self setFileHandlerUIEnabled:[self fileHandlerUIEnabled]];
+ }
+ else if (proxyPrefs_->IsObserved(*prefName)) {
+ [self setProxiesConfigureButtonEnabled:!proxyPrefs_->IsManaged()];
+ }
+}
+
+// Set the new download path and notify the UI via KVO.
+- (void)downloadPathPanelDidEnd:(NSOpenPanel*)panel
+ code:(NSInteger)returnCode
+ context:(void*)context {
+ if (returnCode == NSOKButton) {
+ [self recordUserAction:UserMetricsAction("Options_SetDownloadDirectory")];
+ NSURL* path = [[panel URLs] lastObject]; // We only allow 1 item.
+ [self willChangeValueForKey:@"defaultDownloadLocation"];
+ defaultDownloadLocation_.SetValue(base::SysNSStringToUTF8([path path]));
+ [self didChangeValueForKey:@"defaultDownloadLocation"];
+ }
+}
+
+// Bring up an open panel to allow the user to set a new downloads location.
+- (void)browseDownloadLocation:(id)sender {
+ NSOpenPanel* panel = [NSOpenPanel openPanel];
+ [panel setAllowsMultipleSelection:NO];
+ [panel setCanChooseFiles:NO];
+ [panel setCanChooseDirectories:YES];
+ NSString* path = base::SysUTF8ToNSString(defaultDownloadLocation_.GetValue());
+ [panel beginSheetForDirectory:path
+ file:nil
+ types:nil
+ modalForWindow:[self window]
+ modalDelegate:self
+ didEndSelector:@selector(downloadPathPanelDidEnd:code:context:)
+ contextInfo:NULL];
+}
+
+// Called to clear user's browsing data. This puts up an application-modal
+// dialog to guide the user through clearing the data.
+- (IBAction)clearData:(id)sender {
+ [ClearBrowsingDataController
+ showClearBrowsingDialogForProfile:profile_];
+}
+
+// Opens the "Content Settings" dialog.
+- (IBAction)showContentSettings:(id)sender {
+ [ContentSettingsDialogController
+ showContentSettingsForType:CONTENT_SETTINGS_TYPE_DEFAULT
+ profile:profile_];
+}
+
+- (IBAction)privacyLearnMore:(id)sender {
+ GURL url = google_util::AppendGoogleLocaleParam(
+ GURL(chrome::kPrivacyLearnMoreURL));
+ // We open a new browser window so the Options dialog doesn't get lost
+ // behind other windows.
+ browser::ShowOptionsURL(profile_, url);
+}
+
+- (IBAction)resetAutoOpenFiles:(id)sender {
+ profile_->GetDownloadManager()->download_prefs()->ResetAutoOpen();
+ [self recordUserAction:UserMetricsAction("Options_ResetAutoOpenFiles")];
+}
+
+- (IBAction)openProxyPreferences:(id)sender {
+ NSArray* itemsToOpen = [NSArray arrayWithObject:[NSURL fileURLWithPath:
+ @"/System/Library/PreferencePanes/Network.prefPane"]];
+
+ const char* proxyPrefCommand = "Proxies";
+ base::mac::ScopedAEDesc<> openParams;
+ OSStatus status = AECreateDesc('ptru',
+ proxyPrefCommand,
+ strlen(proxyPrefCommand),
+ openParams.OutPointer());
+ LOG_IF(ERROR, status != noErr) << "Failed to create open params: " << status;
+
+ LSLaunchURLSpec launchSpec = { 0 };
+ launchSpec.itemURLs = (CFArrayRef)itemsToOpen;
+ launchSpec.passThruParams = openParams;
+ launchSpec.launchFlags = kLSLaunchAsync | kLSLaunchDontAddToRecents;
+ LSOpenFromURLSpec(&launchSpec, NULL);
+}
+
+// Returns whether the alternate error page checkbox should be checked based
+// on the preference.
+- (BOOL)showAlternateErrorPages {
+ return alternateErrorPages_.GetValue() ? YES : NO;
+}
+
+// Sets the backend pref for whether or not the alternate error page checkbox
+// should be displayed based on |value|.
+- (void)setShowAlternateErrorPages:(BOOL)value {
+ if (value)
+ [self recordUserAction:UserMetricsAction(
+ "Options_LinkDoctorCheckbox_Enable")];
+ else
+ [self recordUserAction:UserMetricsAction(
+ "Options_LinkDoctorCheckbox_Disable")];
+ alternateErrorPages_.SetValueIfNotManaged(value ? true : false);
+}
+
+// Returns whether the suggest checkbox should be checked based on the
+// preference.
+- (BOOL)useSuggest {
+ return useSuggest_.GetValue() ? YES : NO;
+}
+
+// Sets the backend pref for whether or not the suggest checkbox should be
+// displayed based on |value|.
+- (void)setUseSuggest:(BOOL)value {
+ if (value)
+ [self recordUserAction:UserMetricsAction(
+ "Options_UseSuggestCheckbox_Enable")];
+ else
+ [self recordUserAction:UserMetricsAction(
+ "Options_UseSuggestCheckbox_Disable")];
+ useSuggest_.SetValueIfNotManaged(value ? true : false);
+}
+
+// Returns whether the DNS prefetch checkbox should be checked based on the
+// preference.
+- (BOOL)dnsPrefetch {
+ return dnsPrefetch_.GetValue() ? YES : NO;
+}
+
+// Sets the backend pref for whether or not the DNS prefetch checkbox should be
+// displayed based on |value|.
+- (void)setDnsPrefetch:(BOOL)value {
+ if (value)
+ [self recordUserAction:UserMetricsAction(
+ "Options_DnsPrefetchCheckbox_Enable")];
+ else
+ [self recordUserAction:UserMetricsAction(
+ "Options_DnsPrefetchCheckbox_Disable")];
+ dnsPrefetch_.SetValueIfNotManaged(value ? true : false);
+}
+
+// Returns whether the safe browsing checkbox should be checked based on the
+// preference.
+- (BOOL)safeBrowsing {
+ return safeBrowsing_.GetValue() ? YES : NO;
+}
+
+// Sets the backend pref for whether or not the safe browsing checkbox should be
+// displayed based on |value|.
+- (void)setSafeBrowsing:(BOOL)value {
+ if (value)
+ [self recordUserAction:UserMetricsAction(
+ "Options_SafeBrowsingCheckbox_Enable")];
+ else
+ [self recordUserAction:UserMetricsAction(
+ "Options_SafeBrowsingCheckbox_Disable")];
+ safeBrowsing_.SetValueIfNotManaged(value ? true : false);
+ SafeBrowsingService* safeBrowsingService =
+ g_browser_process->resource_dispatcher_host()->safe_browsing_service();
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(safeBrowsingService,
+ &SafeBrowsingService::OnEnable,
+ safeBrowsing_.GetValue()));
+}
+
+// Returns whether the metrics reporting checkbox should be checked based on the
+// preference.
+- (BOOL)metricsReporting {
+ return metricsReporting_.GetValue() ? YES : NO;
+}
+
+// Sets the backend pref for whether or not the metrics reporting checkbox
+// should be displayed based on |value|.
+- (void)setMetricsReporting:(BOOL)value {
+ if (value)
+ [self recordUserAction:UserMetricsAction(
+ "Options_MetricsReportingCheckbox_Enable")];
+ else
+ [self recordUserAction:UserMetricsAction(
+ "Options_MetricsReportingCheckbox_Disable")];
+
+ // TODO(pinkerton): windows shows a dialog here telling the user they need to
+ // restart for this to take effect. http://crbug.com/34653
+ metricsReporting_.SetValueIfNotManaged(value ? true : false);
+
+ bool enabled = metricsReporting_.GetValue();
+ GoogleUpdateSettings::SetCollectStatsConsent(enabled);
+ bool update_pref = GoogleUpdateSettings::GetCollectStatsConsent();
+ if (enabled != update_pref) {
+ DVLOG(1) << "GENERAL SECTION: Unable to set crash report status to "
+ << enabled;
+ }
+ // Only change the pref if GoogleUpdateSettings::GetCollectStatsConsent
+ // succeeds.
+ enabled = update_pref;
+
+ MetricsService* metrics = g_browser_process->metrics_service();
+ DCHECK(metrics);
+ if (metrics) {
+ metrics->SetUserPermitsUpload(enabled);
+ if (enabled)
+ metrics->Start();
+ else
+ metrics->Stop();
+ }
+}
+
+- (NSURL*)defaultDownloadLocation {
+ NSString* pathString =
+ base::SysUTF8ToNSString(defaultDownloadLocation_.GetValue());
+ return [NSURL fileURLWithPath:pathString];
+}
+
+- (BOOL)askForSaveLocation {
+ return askForSaveLocation_.GetValue();
+}
+
+- (void)setAskForSaveLocation:(BOOL)value {
+ if (value) {
+ [self recordUserAction:UserMetricsAction(
+ "Options_AskForSaveLocation_Enable")];
+ } else {
+ [self recordUserAction:UserMetricsAction(
+ "Options_AskForSaveLocation_Disable")];
+ }
+ askForSaveLocation_.SetValue(value);
+}
+
+- (BOOL)fileHandlerUIEnabled {
+ if (!profile_->GetDownloadManager()) // Not set in unit tests.
+ return NO;
+ return profile_->GetDownloadManager()->download_prefs()->IsAutoOpenUsed();
+}
+
+- (void)setFileHandlerUIEnabled:(BOOL)value {
+ [resetFileHandlersButton_ setEnabled:value];
+}
+
+- (BOOL)translateEnabled {
+ return translateEnabled_.GetValue();
+}
+
+- (void)setTranslateEnabled:(BOOL)value {
+ if (value) {
+ [self recordUserAction:UserMetricsAction("Options_Translate_Enable")];
+ } else {
+ [self recordUserAction:UserMetricsAction("Options_Translate_Disable")];
+ }
+ translateEnabled_.SetValue(value);
+}
+
+- (BOOL)tabsToLinks {
+ return tabsToLinks_.GetValue();
+}
+
+- (void)setTabsToLinks:(BOOL)value {
+ if (value) {
+ [self recordUserAction:UserMetricsAction("Options_TabsToLinks_Enable")];
+ } else {
+ [self recordUserAction:UserMetricsAction("Options_TabsToLinks_Disable")];
+ }
+ tabsToLinks_.SetValue(value);
+}
+
+- (void)fontAndLanguageEndSheet:(NSWindow*)sheet
+ returnCode:(NSInteger)returnCode
+ contextInfo:(void*)context {
+ [sheet close];
+ [sheet orderOut:self];
+ fontLanguageSettings_ = nil;
+}
+
+- (IBAction)changeFontAndLanguageSettings:(id)sender {
+ // Intentionally leak the controller as it will clean itself up when the
+ // sheet closes.
+ fontLanguageSettings_ =
+ [[FontLanguageSettingsController alloc] initWithProfile:profile_];
+ [NSApp beginSheet:[fontLanguageSettings_ window]
+ modalForWindow:[self window]
+ modalDelegate:self
+ didEndSelector:@selector(fontAndLanguageEndSheet:returnCode:contextInfo:)
+ contextInfo:nil];
+}
+
+// Called to launch the Keychain Access app to show the user's stored
+// certificates. Note there's no way to script the app to auto-select the
+// certificates.
+- (IBAction)showCertificates:(id)sender {
+ [self recordUserAction:UserMetricsAction("Options_ManagerCerts")];
+ [self launchKeychainAccess];
+}
+
+- (IBAction)resetToDefaults:(id)sender {
+ // The alert will clean itself up in the did-end selector.
+ NSAlert* alert = [[NSAlert alloc] init];
+ [alert setMessageText:l10n_util::GetNSString(IDS_OPTIONS_RESET_MESSAGE)];
+ NSButton* resetButton = [alert addButtonWithTitle:
+ l10n_util::GetNSString(IDS_OPTIONS_RESET_OKLABEL)];
+ [resetButton setKeyEquivalent:@""];
+ NSButton* cancelButton = [alert addButtonWithTitle:
+ l10n_util::GetNSString(IDS_OPTIONS_RESET_CANCELLABEL)];
+ [cancelButton setKeyEquivalent:@"\r"];
+
+ [alert beginSheetModalForWindow:[self window]
+ modalDelegate:self
+ didEndSelector:@selector(resetToDefaults:returned:context:)
+ contextInfo:nil];
+}
+
+- (void)resetToDefaults:(NSAlert*)alert
+ returned:(NSInteger)code
+ context:(void*)context {
+ if (code == NSAlertFirstButtonReturn) {
+ OptionsUtil::ResetToDefaults(profile_);
+ }
+ [alert autorelease];
+}
+
+//-------------------------------------------------------------------------
+
+// Callback when preferences are changed. |prefName| is the name of the
+// pref that has changed and should not be NULL.
+- (void)prefChanged:(std::string*)prefName {
+ DCHECK(prefName);
+ if (!prefName) return;
+ [self basicsPrefChanged:prefName];
+ [self userDataPrefChanged:prefName];
+ [self underHoodPrefChanged:prefName];
+}
+
+// Callback when sync service state has changed.
+//
+// TODO(akalin): Decomp this out since a lot of it is copied from the
+// Windows version.
+// TODO(akalin): Change the background of the status label/link on error.
+- (void)syncStateChanged {
+ DCHECK(syncService_);
+
+ string16 statusLabel, linkLabel;
+ sync_ui_util::MessageType status =
+ sync_ui_util::GetStatusLabels(syncService_, &statusLabel, &linkLabel);
+ bool managed = syncService_->IsManaged();
+
+ [syncButton_ setEnabled:!syncService_->WizardIsVisible()];
+ NSString* buttonLabel;
+ if (syncService_->HasSyncSetupCompleted()) {
+ buttonLabel = l10n_util::GetNSStringWithFixup(
+ IDS_SYNC_STOP_SYNCING_BUTTON_LABEL);
+ [syncCustomizeButton_ setHidden:false];
+ } else if (syncService_->SetupInProgress()) {
+ buttonLabel = l10n_util::GetNSStringWithFixup(
+ IDS_SYNC_NTP_SETUP_IN_PROGRESS);
+ [syncCustomizeButton_ setHidden:true];
+ } else {
+ buttonLabel = l10n_util::GetNSStringWithFixup(
+ IDS_SYNC_START_SYNC_BUTTON_LABEL);
+ [syncCustomizeButton_ setHidden:true];
+ }
+ [syncCustomizeButton_ setEnabled:!managed];
+ [syncButton_ setTitle:buttonLabel];
+ [syncButton_ setEnabled:!managed];
+
+ [syncStatus_ setStringValue:base::SysUTF16ToNSString(statusLabel)];
+ [syncLink_ setHidden:linkLabel.empty()];
+ [syncLink_ setTitle:base::SysUTF16ToNSString(linkLabel)];
+ [syncLink_ setEnabled:!managed];
+
+ NSButtonCell* syncLinkCell = static_cast<NSButtonCell*>([syncLink_ cell]);
+ if (!syncStatusNoErrorBackgroundColor_) {
+ DCHECK(!syncLinkNoErrorBackgroundColor_);
+ // We assume that the sync controls start off in a non-error
+ // state.
+ syncStatusNoErrorBackgroundColor_.reset(
+ [[syncStatus_ backgroundColor] retain]);
+ syncLinkNoErrorBackgroundColor_.reset(
+ [[syncLinkCell backgroundColor] retain]);
+ }
+ if (status == sync_ui_util::SYNC_ERROR) {
+ [syncStatus_ setBackgroundColor:syncErrorBackgroundColor_];
+ [syncLinkCell setBackgroundColor:syncErrorBackgroundColor_];
+ } else {
+ [syncStatus_ setBackgroundColor:syncStatusNoErrorBackgroundColor_];
+ [syncLinkCell setBackgroundColor:syncLinkNoErrorBackgroundColor_];
+ }
+}
+
+// Show the preferences window.
+- (IBAction)showPreferences:(id)sender {
+ [self showWindow:sender];
+}
+
+- (IBAction)toolbarButtonSelected:(id)sender {
+ DCHECK([sender isKindOfClass:[NSToolbarItem class]]);
+ OptionsPage page = [self getPageForToolbarItem:sender];
+ [self displayPreferenceViewForPage:page animate:YES];
+}
+
+// Helper to update the window to display a preferences view for a page.
+- (void)displayPreferenceViewForPage:(OptionsPage)page
+ animate:(BOOL)animate {
+ NSWindow* prefsWindow = [self window];
+
+ // Needs to go *after* the call to [self window], which triggers
+ // awakeFromNib if necessary.
+ NSView* prefsView = [self getPrefsViewForPage:page];
+ NSView* contentView = [prefsWindow contentView];
+
+ // Make sure we aren't being told to display the same thing again.
+ if (currentPrefsView_ == prefsView &&
+ managedPrefsBannerVisible_ == bannerState_->IsVisible()) {
+ return;
+ }
+
+ // Remember new options page as current page.
+ if (page != OPTIONS_PAGE_DEFAULT)
+ lastSelectedPage_.SetValue(page);
+
+ // Stop any running animation, and reset the subviews to the new state. We
+ // re-add any views we need for animation later.
+ [animation_ stopAnimation];
+ NSView* oldPrefsView = currentPrefsView_;
+ currentPrefsView_ = prefsView;
+ [self resetSubViews];
+
+ // Update the banner state.
+ [self initBannerStateForPage:page];
+ BOOL showBanner = bannerState_->IsVisible();
+
+ // Update the window title.
+ NSToolbarItem* toolbarItem = [self getToolbarItemForPage:page];
+ [prefsWindow setTitle:[toolbarItem label]];
+
+ // Calculate new frames for the subviews.
+ NSRect prefsViewFrame = [prefsView frame];
+ NSRect contentViewFrame = [contentView frame];
+ NSRect bannerViewFrame = [managedPrefsBannerView_ frame];
+
+ // Determine what height the managed prefs banner will use.
+ CGFloat bannerViewHeight = showBanner ? NSHeight(bannerViewFrame) : 0.0;
+
+ if (animate) {
+ // NSViewAnimation doesn't seem to honor subview resizing as it animates the
+ // Window's frame. So instead of trying to get the top in the right place,
+ // just set the origin where it should be at the end, and let the fade/size
+ // slide things into the right spot.
+ prefsViewFrame.origin.y = 0.0;
+ } else {
+ // The prefView is anchored to the top of its parent, so set its origin so
+ // that the top is where it should be. When the window's frame is set, the
+ // origin will be adjusted to keep it in the right spot.
+ prefsViewFrame.origin.y = NSHeight(contentViewFrame) -
+ NSHeight(prefsViewFrame) - bannerViewHeight;
+ }
+ bannerViewFrame.origin.y = NSHeight(prefsViewFrame);
+ bannerViewFrame.size.width = NSWidth(contentViewFrame);
+ [prefsView setFrame:prefsViewFrame];
+
+ // Figure out the size of the window.
+ NSRect windowFrame = [contentView convertRect:[prefsWindow frame]
+ fromView:nil];
+ CGFloat titleToolbarHeight =
+ NSHeight(windowFrame) - NSHeight(contentViewFrame);
+ windowFrame.size.height =
+ NSHeight(prefsViewFrame) + titleToolbarHeight + bannerViewHeight;
+ DCHECK_GE(NSWidth(windowFrame), NSWidth(prefsViewFrame))
+ << "Initial width set wasn't wide enough.";
+ windowFrame = [contentView convertRect:windowFrame toView:nil];
+ windowFrame.origin.y = NSMaxY([prefsWindow frame]) - NSHeight(windowFrame);
+
+ // Now change the size.
+ if (animate) {
+ NSMutableArray* animations = [NSMutableArray arrayWithCapacity:4];
+ if (oldPrefsView != prefsView) {
+ // Fade between prefs views if they change.
+ [contentView addSubview:oldPrefsView
+ positioned:NSWindowBelow
+ relativeTo:nil];
+ [animations addObject:
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ oldPrefsView, NSViewAnimationTargetKey,
+ NSViewAnimationFadeOutEffect, NSViewAnimationEffectKey,
+ nil]];
+ [animations addObject:
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ prefsView, NSViewAnimationTargetKey,
+ NSViewAnimationFadeInEffect, NSViewAnimationEffectKey,
+ nil]];
+ } else {
+ // Make sure the prefs pane ends up in the right position in case we
+ // manipulate the banner.
+ [animations addObject:
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ prefsView, NSViewAnimationTargetKey,
+ [NSValue valueWithRect:prefsViewFrame],
+ NSViewAnimationEndFrameKey,
+ nil]];
+ }
+ if (showBanner != managedPrefsBannerVisible_) {
+ // Slide the warning banner in or out of view.
+ [animations addObject:
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ managedPrefsBannerView_, NSViewAnimationTargetKey,
+ [NSValue valueWithRect:bannerViewFrame],
+ NSViewAnimationEndFrameKey,
+ nil]];
+ }
+ // Window resize animation.
+ [animations addObject:
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ prefsWindow, NSViewAnimationTargetKey,
+ [NSValue valueWithRect:windowFrame], NSViewAnimationEndFrameKey,
+ nil]];
+ [animation_ setViewAnimations:animations];
+ // The default duration is 0.5s, which actually feels slow in here, so speed
+ // it up a bit.
+ [animation_ gtm_setDuration:0.2
+ eventMask:NSLeftMouseUpMask];
+ [animation_ startAnimation];
+ } else {
+ // If not animating, odds are we don't want to display either (because it
+ // is initial window setup).
+ [prefsWindow setFrame:windowFrame display:NO];
+ [managedPrefsBannerView_ setFrame:bannerViewFrame];
+ }
+
+ managedPrefsBannerVisible_ = showBanner;
+}
+
+- (void)resetSubViews {
+ // Reset subviews to current prefs view and banner, remove any views that
+ // might have been left over from previous state or animation.
+ NSArray* subviews = [NSArray arrayWithObjects:
+ currentPrefsView_, managedPrefsBannerView_, nil];
+ [[[self window] contentView] setSubviews:subviews];
+ [[self window] setInitialFirstResponder:currentPrefsView_];
+}
+
+- (void)animationDidEnd:(NSAnimation*)animation {
+ DCHECK_EQ(animation_.get(), animation);
+ // Animation finished, reset subviews to current prefs view and the banner.
+ [self resetSubViews];
+}
+
+// Reinitializes the banner state tracker object to watch for managed bits of
+// preferences relevant to the given options |page|.
+- (void)initBannerStateForPage:(OptionsPage)page {
+ page = [self normalizePage:page];
+
+ // During unit tests, there is no local state object, so we fall back to
+ // the prefs object (where we've explicitly registered this pref so we
+ // know it's there).
+ PrefService* local = g_browser_process->local_state();
+ if (!local)
+ local = prefs_;
+ bannerState_.reset(
+ new PreferencesWindowControllerInternal::ManagedPrefsBannerState(
+ self, page, local, prefs_));
+}
+
+- (void)switchToPage:(OptionsPage)page animate:(BOOL)animate {
+ [self displayPreferenceViewForPage:page animate:animate];
+ NSToolbarItem* toolbarItem = [self getToolbarItemForPage:page];
+ [toolbar_ setSelectedItemIdentifier:[toolbarItem itemIdentifier]];
+}
+
+// Called when the window is being closed. Send out a notification that the user
+// is done editing preferences. Make sure there are no pending field editors
+// by clearing the first responder.
+- (void)windowWillClose:(NSNotification*)notification {
+ // Setting the first responder to the window ends any in-progress field
+ // editor. This will update the model appropriately so there's nothing left
+ // to do.
+ if (![[self window] makeFirstResponder:[self window]]) {
+ // We've hit a recalcitrant field editor, force it to go away.
+ [[self window] endEditingFor:nil];
+ }
+ [self autorelease];
+}
+
+- (void)controlTextDidEndEditing:(NSNotification*)notification {
+ [customPagesSource_ validateURLs];
+}
+
+@end
+
+@implementation PreferencesWindowController(Testing)
+
+- (IntegerPrefMember*)lastSelectedPage {
+ return &lastSelectedPage_;
+}
+
+- (NSToolbar*)toolbar {
+ return toolbar_;
+}
+
+- (NSView*)basicsView {
+ return basicsView_;
+}
+
+- (NSView*)personalStuffView {
+ return personalStuffView_;
+}
+
+- (NSView*)underTheHoodView {
+ return underTheHoodView_;
+}
+
+- (OptionsPage)normalizePage:(OptionsPage)page {
+ if (page == OPTIONS_PAGE_DEFAULT) {
+ // Get the last visited page from local state.
+ page = static_cast<OptionsPage>(lastSelectedPage_.GetValue());
+ if (page == OPTIONS_PAGE_DEFAULT) {
+ page = OPTIONS_PAGE_GENERAL;
+ }
+ }
+ return page;
+}
+
+- (NSToolbarItem*)getToolbarItemForPage:(OptionsPage)page {
+ NSUInteger pageIndex = (NSUInteger)[self normalizePage:page];
+ NSArray* items = [toolbar_ items];
+ NSUInteger itemCount = [items count];
+ DCHECK_GE(pageIndex, 0U);
+ if (pageIndex >= itemCount) {
+ NOTIMPLEMENTED();
+ pageIndex = 0;
+ }
+ DCHECK_GT(itemCount, 0U);
+ return [items objectAtIndex:pageIndex];
+}
+
+- (OptionsPage)getPageForToolbarItem:(NSToolbarItem*)toolbarItem {
+ // Tags are set in the nib file.
+ switch ([toolbarItem tag]) {
+ case 0: // Basics
+ return OPTIONS_PAGE_GENERAL;
+ case 1: // Personal Stuff
+ return OPTIONS_PAGE_CONTENT;
+ case 2: // Under the Hood
+ return OPTIONS_PAGE_ADVANCED;
+ default:
+ NOTIMPLEMENTED();
+ return OPTIONS_PAGE_GENERAL;
+ }
+}
+
+- (NSView*)getPrefsViewForPage:(OptionsPage)page {
+ // The views will be NULL if this is mistakenly called before awakeFromNib.
+ DCHECK(basicsView_);
+ DCHECK(personalStuffView_);
+ DCHECK(underTheHoodView_);
+ page = [self normalizePage:page];
+ switch (page) {
+ case OPTIONS_PAGE_GENERAL:
+ return basicsView_;
+ case OPTIONS_PAGE_CONTENT:
+ return personalStuffView_;
+ case OPTIONS_PAGE_ADVANCED:
+ return underTheHoodView_;
+ case OPTIONS_PAGE_DEFAULT:
+ case OPTIONS_PAGE_COUNT:
+ LOG(DFATAL) << "Invalid page value " << page;
+ }
+ return basicsView_;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/preferences_window_controller_unittest.mm b/chrome/browser/ui/cocoa/preferences_window_controller_unittest.mm
new file mode 100644
index 0000000..bbb1746
--- /dev/null
+++ b/chrome/browser/ui/cocoa/preferences_window_controller_unittest.mm
@@ -0,0 +1,240 @@
+// Copyright (c) 2009 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>
+
+#import "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/preferences_window_controller.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/custom_home_pages_model.h"
+#include "chrome/browser/ui/options/options_window.h"
+#include "chrome/common/pref_names.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+// Helper Objective-C object that sets a BOOL when we get a particular
+// callback from the prefs window.
+@interface PrefsClosedObserver : NSObject {
+ @public
+ BOOL gotNotification_;
+}
+- (void)prefsWindowClosed:(NSNotification*)notify;
+@end
+
+@implementation PrefsClosedObserver
+- (void)prefsWindowClosed:(NSNotification*)notify {
+ gotNotification_ = YES;
+}
+@end
+
+namespace {
+
+class PrefsControllerTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ // The metrics reporting pref is registerd on the local state object in
+ // real builds, but we don't have one of those for unit tests. Register
+ // it on prefs so we'll find it when we go looking.
+ PrefService* prefs = browser_helper_.profile()->GetPrefs();
+ prefs->RegisterBooleanPref(prefs::kMetricsReportingEnabled, false);
+
+ pref_controller_ = [[PreferencesWindowController alloc]
+ initWithProfile:browser_helper_.profile()
+ initialPage:OPTIONS_PAGE_DEFAULT];
+ EXPECT_TRUE(pref_controller_);
+ }
+
+ virtual void TearDown() {
+ [pref_controller_ close];
+ CocoaTest::TearDown();
+ }
+
+ BrowserTestHelper browser_helper_;
+ PreferencesWindowController* pref_controller_;
+};
+
+// Test showing the preferences window and making sure it's visible, then
+// making sure we get the notification when it's closed.
+TEST_F(PrefsControllerTest, ShowAndClose) {
+ [pref_controller_ showPreferences:nil];
+ EXPECT_TRUE([[pref_controller_ window] isVisible]);
+
+ scoped_nsobject<PrefsClosedObserver> observer(
+ [[PrefsClosedObserver alloc] init]);
+ NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
+ [defaultCenter addObserver:observer.get()
+ selector:@selector(prefsWindowClosed:)
+ name:NSWindowWillCloseNotification
+ object:[pref_controller_ window]];
+ [[pref_controller_ window] performClose:observer];
+ EXPECT_TRUE(observer.get()->gotNotification_);
+ [defaultCenter removeObserver:observer.get()];
+
+ // Prevent pref_controller_ from being closed again in TearDown()
+ pref_controller_ = nil;
+}
+
+TEST_F(PrefsControllerTest, ValidateCustomHomePagesTable) {
+ // First, insert two valid URLs into the CustomHomePagesModel.
+ GURL url1("http://www.google.com/");
+ GURL url2("http://maps.google.com/");
+ std::vector<GURL> urls;
+ urls.push_back(url1);
+ urls.push_back(url2);
+ [[pref_controller_ customPagesSource] setURLs:urls];
+ EXPECT_EQ(2U, [[pref_controller_ customPagesSource] countOfCustomHomePages]);
+
+ // Now insert a bad (empty) URL into the model.
+ [[pref_controller_ customPagesSource] setURLStringEmptyAt:1];
+
+ // Send a notification to simulate the end of editing on a cell in the table
+ // which should trigger validation.
+ [pref_controller_ controlTextDidEndEditing:[NSNotification
+ notificationWithName:NSControlTextDidEndEditingNotification
+ object:nil]];
+ EXPECT_EQ(1U, [[pref_controller_ customPagesSource] countOfCustomHomePages]);
+}
+
+TEST_F(PrefsControllerTest, NormalizePage) {
+ EXPECT_EQ(OPTIONS_PAGE_GENERAL,
+ [pref_controller_ normalizePage:OPTIONS_PAGE_GENERAL]);
+ EXPECT_EQ(OPTIONS_PAGE_CONTENT,
+ [pref_controller_ normalizePage:OPTIONS_PAGE_CONTENT]);
+ EXPECT_EQ(OPTIONS_PAGE_ADVANCED,
+ [pref_controller_ normalizePage:OPTIONS_PAGE_ADVANCED]);
+
+ [pref_controller_ lastSelectedPage]->SetValue(OPTIONS_PAGE_ADVANCED);
+ EXPECT_EQ(OPTIONS_PAGE_ADVANCED,
+ [pref_controller_ normalizePage:OPTIONS_PAGE_DEFAULT]);
+
+ [pref_controller_ lastSelectedPage]->SetValue(OPTIONS_PAGE_DEFAULT);
+ EXPECT_EQ(OPTIONS_PAGE_GENERAL,
+ [pref_controller_ normalizePage:OPTIONS_PAGE_DEFAULT]);
+}
+
+TEST_F(PrefsControllerTest, GetToolbarItemForPage) {
+ // Trigger awakeFromNib.
+ [pref_controller_ window];
+
+ NSArray* toolbarItems = [[pref_controller_ toolbar] items];
+ EXPECT_EQ([toolbarItems objectAtIndex:0],
+ [pref_controller_ getToolbarItemForPage:OPTIONS_PAGE_GENERAL]);
+ EXPECT_EQ([toolbarItems objectAtIndex:1],
+ [pref_controller_ getToolbarItemForPage:OPTIONS_PAGE_CONTENT]);
+ EXPECT_EQ([toolbarItems objectAtIndex:2],
+ [pref_controller_ getToolbarItemForPage:OPTIONS_PAGE_ADVANCED]);
+
+ [pref_controller_ lastSelectedPage]->SetValue(OPTIONS_PAGE_ADVANCED);
+ EXPECT_EQ([toolbarItems objectAtIndex:2],
+ [pref_controller_ getToolbarItemForPage:OPTIONS_PAGE_DEFAULT]);
+
+ // Out-of-range argument.
+ EXPECT_EQ([toolbarItems objectAtIndex:0],
+ [pref_controller_ getToolbarItemForPage:OPTIONS_PAGE_COUNT]);
+}
+
+TEST_F(PrefsControllerTest, GetPageForToolbarItem) {
+ scoped_nsobject<NSToolbarItem> toolbarItem(
+ [[NSToolbarItem alloc] initWithItemIdentifier:@""]);
+ [toolbarItem setTag:0];
+ EXPECT_EQ(OPTIONS_PAGE_GENERAL,
+ [pref_controller_ getPageForToolbarItem:toolbarItem]);
+ [toolbarItem setTag:1];
+ EXPECT_EQ(OPTIONS_PAGE_CONTENT,
+ [pref_controller_ getPageForToolbarItem:toolbarItem]);
+ [toolbarItem setTag:2];
+ EXPECT_EQ(OPTIONS_PAGE_ADVANCED,
+ [pref_controller_ getPageForToolbarItem:toolbarItem]);
+
+ // Out-of-range argument.
+ [toolbarItem setTag:3];
+ EXPECT_EQ(OPTIONS_PAGE_GENERAL,
+ [pref_controller_ getPageForToolbarItem:toolbarItem]);
+}
+
+TEST_F(PrefsControllerTest, GetPrefsViewForPage) {
+ // Trigger awakeFromNib.
+ [pref_controller_ window];
+
+ EXPECT_EQ([pref_controller_ basicsView],
+ [pref_controller_ getPrefsViewForPage:OPTIONS_PAGE_GENERAL]);
+ EXPECT_EQ([pref_controller_ personalStuffView],
+ [pref_controller_ getPrefsViewForPage:OPTIONS_PAGE_CONTENT]);
+ EXPECT_EQ([pref_controller_ underTheHoodView],
+ [pref_controller_ getPrefsViewForPage:OPTIONS_PAGE_ADVANCED]);
+
+ [pref_controller_ lastSelectedPage]->SetValue(OPTIONS_PAGE_ADVANCED);
+ EXPECT_EQ([pref_controller_ underTheHoodView],
+ [pref_controller_ getPrefsViewForPage:OPTIONS_PAGE_DEFAULT]);
+}
+
+TEST_F(PrefsControllerTest, SwitchToPage) {
+ // Trigger awakeFromNib.
+ NSWindow* window = [pref_controller_ window];
+
+ NSView* contentView = [window contentView];
+ NSView* basicsView = [pref_controller_ basicsView];
+ NSView* personalStuffView = [pref_controller_ personalStuffView];
+ NSView* underTheHoodView = [pref_controller_ underTheHoodView];
+ NSToolbar* toolbar = [pref_controller_ toolbar];
+ NSToolbarItem* basicsToolbarItem =
+ [pref_controller_ getToolbarItemForPage:OPTIONS_PAGE_GENERAL];
+ NSToolbarItem* personalStuffToolbarItem =
+ [pref_controller_ getToolbarItemForPage:OPTIONS_PAGE_CONTENT];
+ NSToolbarItem* underTheHoodToolbarItem =
+ [pref_controller_ getToolbarItemForPage:OPTIONS_PAGE_ADVANCED];
+ NSString* basicsIdentifier = [basicsToolbarItem itemIdentifier];
+ NSString* personalStuffIdentifier = [personalStuffToolbarItem itemIdentifier];
+ NSString* underTheHoodIdentifier = [underTheHoodToolbarItem itemIdentifier];
+ IntegerPrefMember* lastSelectedPage = [pref_controller_ lastSelectedPage];
+
+ // Test without animation.
+
+ [pref_controller_ switchToPage:OPTIONS_PAGE_GENERAL animate:NO];
+ EXPECT_TRUE([basicsView isDescendantOf:contentView]);
+ EXPECT_FALSE([personalStuffView isDescendantOf:contentView]);
+ EXPECT_FALSE([underTheHoodView isDescendantOf:contentView]);
+ EXPECT_NSEQ(basicsIdentifier, [toolbar selectedItemIdentifier]);
+ EXPECT_EQ(OPTIONS_PAGE_GENERAL, lastSelectedPage->GetValue());
+ EXPECT_NSEQ([basicsToolbarItem label], [window title]);
+
+ [pref_controller_ switchToPage:OPTIONS_PAGE_CONTENT animate:NO];
+ EXPECT_FALSE([basicsView isDescendantOf:contentView]);
+ EXPECT_TRUE([personalStuffView isDescendantOf:contentView]);
+ EXPECT_FALSE([underTheHoodView isDescendantOf:contentView]);
+ EXPECT_NSEQ([toolbar selectedItemIdentifier], personalStuffIdentifier);
+ EXPECT_EQ(OPTIONS_PAGE_CONTENT, lastSelectedPage->GetValue());
+ EXPECT_NSEQ([personalStuffToolbarItem label], [window title]);
+
+ [pref_controller_ switchToPage:OPTIONS_PAGE_ADVANCED animate:NO];
+ EXPECT_FALSE([basicsView isDescendantOf:contentView]);
+ EXPECT_FALSE([personalStuffView isDescendantOf:contentView]);
+ EXPECT_TRUE([underTheHoodView isDescendantOf:contentView]);
+ EXPECT_NSEQ([toolbar selectedItemIdentifier], underTheHoodIdentifier);
+ EXPECT_EQ(OPTIONS_PAGE_ADVANCED, lastSelectedPage->GetValue());
+ EXPECT_NSEQ([underTheHoodToolbarItem label], [window title]);
+
+ // Test OPTIONS_PAGE_DEFAULT.
+
+ lastSelectedPage->SetValue(OPTIONS_PAGE_CONTENT);
+ [pref_controller_ switchToPage:OPTIONS_PAGE_DEFAULT animate:NO];
+ EXPECT_FALSE([basicsView isDescendantOf:contentView]);
+ EXPECT_TRUE([personalStuffView isDescendantOf:contentView]);
+ EXPECT_FALSE([underTheHoodView isDescendantOf:contentView]);
+ EXPECT_NSEQ(personalStuffIdentifier, [toolbar selectedItemIdentifier]);
+ EXPECT_EQ(OPTIONS_PAGE_CONTENT, lastSelectedPage->GetValue());
+ EXPECT_NSEQ([personalStuffToolbarItem label], [window title]);
+
+ // TODO(akalin): Figure out how to test animation; we'll need everything
+ // to stick around until the animation finishes.
+}
+
+// TODO(akalin): Figure out how to test sync controls.
+// TODO(akalin): Figure out how to test that sync controls are not shown
+// when there isn't a sync service.
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/previewable_contents_controller.h b/chrome/browser/ui/cocoa/previewable_contents_controller.h
new file mode 100644
index 0000000..01643f0
--- /dev/null
+++ b/chrome/browser/ui/cocoa/previewable_contents_controller.h
@@ -0,0 +1,47 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_PREVIEWABLE_CONTENTS_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_PREVIEWABLE_CONTENTS_CONTROLLER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+class TabContents;
+
+// PreviewableContentsController manages the display of up to two tab contents
+// views. It is primarily for use with Instant results. This class supports
+// the notion of an "active" view vs. a "preview" tab contents view.
+//
+// The "active" view is a container view that can be retrieved using
+// |-activeContainer|. Its contents are meant to be managed by an external
+// class.
+//
+// The "preview" can be set using |-showPreview:| and |-hidePreview|. When a
+// preview is set, the active view is hidden (but stays in the view hierarchy).
+// When the preview is removed, the active view is reshown.
+@interface PreviewableContentsController : NSViewController {
+ @private
+ // Container view for the "active" contents.
+ IBOutlet NSView* activeContainer_;
+
+ // The preview TabContents. Will be NULL if no preview is currently showing.
+ TabContents* previewContents_; // weak
+}
+
+@property(readonly, nonatomic) NSView* activeContainer;
+
+// Sets the current preview and installs its TabContentsView into the view
+// hierarchy. Hides the active view. |preview| must not be NULL.
+- (void)showPreview:(TabContents*)preview;
+
+// Closes the current preview and shows the active view.
+- (void)hidePreview;
+
+// Returns YES if the preview contents is currently showing.
+- (BOOL)isShowingPreview;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_PREVIEWABLE_CONTENTS_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/previewable_contents_controller.mm b/chrome/browser/ui/cocoa/previewable_contents_controller.mm
new file mode 100644
index 0000000..2dfa146
--- /dev/null
+++ b/chrome/browser/ui/cocoa/previewable_contents_controller.mm
@@ -0,0 +1,52 @@
+// 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 "chrome/browser/ui/cocoa/previewable_contents_controller.h"
+
+#include "base/logging.h"
+#include "base/mac_util.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+
+@implementation PreviewableContentsController
+
+@synthesize activeContainer = activeContainer_;
+
+- (id)init {
+ if ((self = [super initWithNibName:@"PreviewableContents"
+ bundle:mac_util::MainAppBundle()])) {
+ }
+ return self;
+}
+
+- (void)showPreview:(TabContents*)preview {
+ DCHECK(preview);
+
+ // Remove any old preview contents before showing the new one.
+ if (previewContents_)
+ [previewContents_->GetNativeView() removeFromSuperview];
+
+ previewContents_ = preview;
+ NSView* previewView = previewContents_->GetNativeView();
+ [previewView setFrame:[[self view] bounds]];
+
+ // Hide the active container and add the preview contents.
+ [activeContainer_ setHidden:YES];
+ [[self view] addSubview:previewView];
+}
+
+- (void)hidePreview {
+ DCHECK(previewContents_);
+
+ // Remove the preview contents and reshow the active container.
+ [previewContents_->GetNativeView() removeFromSuperview];
+ [activeContainer_ setHidden:NO];
+
+ previewContents_ = nil;
+}
+
+- (BOOL)isShowingPreview {
+ return previewContents_ != nil;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/previewable_contents_controller_unittest.mm b/chrome/browser/ui/cocoa/previewable_contents_controller_unittest.mm
new file mode 100644
index 0000000..a2d9263
--- /dev/null
+++ b/chrome/browser/ui/cocoa/previewable_contents_controller_unittest.mm
@@ -0,0 +1,34 @@
+// 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>
+
+#import "base/scoped_nsobject.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/previewable_contents_controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class PreviewableContentsControllerTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ controller_.reset([[PreviewableContentsController alloc] init]);
+ [[test_window() contentView] addSubview:[controller_ view]];
+ }
+
+ scoped_nsobject<PreviewableContentsController> controller_;
+};
+
+TEST_VIEW(PreviewableContentsControllerTest, [controller_ view])
+
+// TODO(rohitrao): Test showing and hiding the preview. This may require
+// changing the interface to take in a TabContentsView* instead of a
+// TabContents*.
+
+} // namespace
+
diff --git a/chrome/browser/ui/cocoa/reload_button.h b/chrome/browser/ui/cocoa/reload_button.h
new file mode 100644
index 0000000..f955590
--- /dev/null
+++ b/chrome/browser/ui/cocoa/reload_button.h
@@ -0,0 +1,50 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_RELOAD_BUTTON_H_
+#define CHROME_BROWSER_UI_COCOA_RELOAD_BUTTON_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/scoped_nsobject.h"
+
+// NSButton subclass which defers certain state changes when the mouse
+// is hovering over it.
+
+@interface ReloadButton : NSButton {
+ @private
+ // Tracks whether the mouse is hovering for purposes of not making
+ // unexpected state changes.
+ BOOL isMouseInside_;
+ scoped_nsobject<NSTrackingArea> trackingArea_;
+
+ // Timer used when setting reload mode while the mouse is hovered.
+ scoped_nsobject<NSTimer> pendingReloadTimer_;
+}
+
+// Returns YES if the mouse is currently inside the bounds.
+- (BOOL)isMouseInside;
+
+// Update the tag, and the image and tooltip to match. If |anInt|
+// matches the current tag, no action is taken. |anInt| must be
+// either |IDC_STOP| or |IDC_RELOAD|.
+- (void)updateTag:(NSInteger)anInt;
+
+// Update the button to be a reload button or stop button depending on
+// |isLoading|. If |force|, always sets the indicated mode. If
+// |!force|, and the mouse is over the button, defer the transition
+// from stop button to reload button until the mouse has left the
+// button, or until |pendingReloadTimer_| fires. This prevents an
+// inadvertent click _just_ as the state changes.
+- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force;
+
+@end
+
+@interface ReloadButton (PrivateTestingMethods)
++ (void)setPendingReloadTimeout:(NSTimeInterval)seconds;
+- (NSTrackingArea*)trackingArea;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_RELOAD_BUTTON_H_
diff --git a/chrome/browser/ui/cocoa/reload_button.mm b/chrome/browser/ui/cocoa/reload_button.mm
new file mode 100644
index 0000000..a2a60af
--- /dev/null
+++ b/chrome/browser/ui/cocoa/reload_button.mm
@@ -0,0 +1,168 @@
+// 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 "chrome/browser/ui/cocoa/reload_button.h"
+
+#include "app/l10n_util.h"
+#include "app/l10n_util_mac.h"
+#include "app/mac/nsimage_cache.h"
+#include "chrome/app/chrome_command_ids.h"
+#import "chrome/browser/ui/cocoa/gradient_button_cell.h"
+#import "chrome/browser/ui/cocoa/view_id_util.h"
+#include "grit/generated_resources.h"
+
+namespace {
+
+NSString* const kReloadImageName = @"reload_Template.pdf";
+NSString* const kStopImageName = @"stop_Template.pdf";
+
+// Constant matches Windows.
+NSTimeInterval kPendingReloadTimeout = 1.35;
+
+} // namespace
+
+@implementation ReloadButton
+
+- (void)dealloc {
+ if (trackingArea_) {
+ [self removeTrackingArea:trackingArea_];
+ trackingArea_.reset();
+ }
+ [super dealloc];
+}
+
+- (void)updateTrackingAreas {
+ // If the mouse is hovering when the tracking area is updated, the
+ // control could end up locked into inappropriate behavior for
+ // awhile, so unwind state.
+ if (isMouseInside_)
+ [self mouseExited:nil];
+
+ if (trackingArea_) {
+ [self removeTrackingArea:trackingArea_];
+ trackingArea_.reset();
+ }
+ trackingArea_.reset([[NSTrackingArea alloc]
+ initWithRect:[self bounds]
+ options:(NSTrackingMouseEnteredAndExited |
+ NSTrackingActiveInActiveApp)
+ owner:self
+ userInfo:nil]);
+ [self addTrackingArea:trackingArea_];
+}
+
+- (void)awakeFromNib {
+ [self updateTrackingAreas];
+
+ // Don't allow multi-clicks, because the user probably wouldn't ever
+ // want to stop+reload or reload+stop.
+ [self setIgnoresMultiClick:YES];
+}
+
+- (void)updateTag:(NSInteger)anInt {
+ if ([self tag] == anInt)
+ return;
+
+ // Forcibly remove any stale tooltip which is being displayed.
+ [self removeAllToolTips];
+
+ [self setTag:anInt];
+ if (anInt == IDC_RELOAD) {
+ [self setImage:app::mac::GetCachedImageWithName(kReloadImageName)];
+ [self setToolTip:l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_RELOAD)];
+ } else if (anInt == IDC_STOP) {
+ [self setImage:app::mac::GetCachedImageWithName(kStopImageName)];
+ [self setToolTip:l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_STOP)];
+ } else {
+ NOTREACHED();
+ }
+}
+
+- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force {
+ // Can always transition to stop mode. Only transition to reload
+ // mode if forced or if the mouse isn't hovering. Otherwise, note
+ // that reload mode is desired and disable the button.
+ if (isLoading) {
+ pendingReloadTimer_.reset();
+ [self updateTag:IDC_STOP];
+ [self setEnabled:YES];
+ } else if (force || ![self isMouseInside]) {
+ pendingReloadTimer_.reset();
+ [self updateTag:IDC_RELOAD];
+
+ // This button's cell may not have received a mouseExited event, and
+ // therefore it could still think that the mouse is inside the button. Make
+ // sure the cell's sense of mouse-inside matches the local sense, to prevent
+ // drawing artifacts.
+ id cell = [self cell];
+ if ([cell respondsToSelector:@selector(setMouseInside:animate:)])
+ [cell setMouseInside:[self isMouseInside] animate:NO];
+ [self setEnabled:YES];
+ } else if ([self tag] == IDC_STOP && !pendingReloadTimer_) {
+ [self setEnabled:NO];
+ pendingReloadTimer_.reset(
+ [[NSTimer scheduledTimerWithTimeInterval:kPendingReloadTimeout
+ target:self
+ selector:@selector(forceReloadState)
+ userInfo:nil
+ repeats:NO] retain]);
+ }
+}
+
+- (void)forceReloadState {
+ [self setIsLoading:NO force:YES];
+}
+
+- (BOOL)sendAction:(SEL)theAction to:(id)theTarget {
+ if ([self tag] == IDC_STOP) {
+ // When the timer is started, the button is disabled, so this
+ // should not be possible.
+ DCHECK(!pendingReloadTimer_.get());
+
+ // When the stop is processed, immediately change to reload mode,
+ // even though the IPC still has to bounce off the renderer and
+ // back before the regular |-setIsLoaded:force:| will be called.
+ // [This is how views and gtk do it.]
+ const BOOL ret = [super sendAction:theAction to:theTarget];
+ if (ret)
+ [self forceReloadState];
+ return ret;
+ }
+
+ return [super sendAction:theAction to:theTarget];
+}
+
+- (void)mouseEntered:(NSEvent*)theEvent {
+ isMouseInside_ = YES;
+}
+
+- (void)mouseExited:(NSEvent*)theEvent {
+ isMouseInside_ = NO;
+
+ // Reload mode was requested during the hover.
+ if (pendingReloadTimer_)
+ [self forceReloadState];
+}
+
+- (BOOL)isMouseInside {
+ return isMouseInside_;
+}
+
+- (ViewID)viewID {
+ return VIEW_ID_RELOAD_BUTTON;
+}
+
+@end // ReloadButton
+
+@implementation ReloadButton (Testing)
+
++ (void)setPendingReloadTimeout:(NSTimeInterval)seconds {
+ kPendingReloadTimeout = seconds;
+}
+
+- (NSTrackingArea*)trackingArea {
+ return trackingArea_;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/reload_button_unittest.mm b/chrome/browser/ui/cocoa/reload_button_unittest.mm
new file mode 100644
index 0000000..386a503
--- /dev/null
+++ b/chrome/browser/ui/cocoa/reload_button_unittest.mm
@@ -0,0 +1,259 @@
+// 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>
+
+#import "chrome/browser/ui/cocoa/reload_button.h"
+
+#include "base/scoped_nsobject.h"
+#include "chrome/app/chrome_command_ids.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test_event_utils.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+
+@protocol TargetActionMock <NSObject>
+- (void)anAction:(id)sender;
+@end
+
+namespace {
+
+class ReloadButtonTest : public CocoaTest {
+ public:
+ ReloadButtonTest() {
+ NSRect frame = NSMakeRect(0, 0, 20, 20);
+ scoped_nsobject<ReloadButton> button(
+ [[ReloadButton alloc] initWithFrame:frame]);
+ button_ = button.get();
+
+ // Set things up so unit tests have a reliable baseline.
+ [button_ setTag:IDC_RELOAD];
+ [button_ awakeFromNib];
+
+ [[test_window() contentView] addSubview:button_];
+ }
+
+ ReloadButton* button_;
+};
+
+TEST_VIEW(ReloadButtonTest, button_)
+
+// Test that mouse-tracking is setup and does the right thing.
+TEST_F(ReloadButtonTest, IsMouseInside) {
+ EXPECT_TRUE([[button_ trackingAreas] containsObject:[button_ trackingArea]]);
+
+ EXPECT_FALSE([button_ isMouseInside]);
+ [button_ mouseEntered:nil];
+ EXPECT_TRUE([button_ isMouseInside]);
+ [button_ mouseExited:nil];
+}
+
+// Verify that multiple clicks do not result in multiple messages to
+// the target.
+TEST_F(ReloadButtonTest, IgnoredMultiClick) {
+ id mock_target = [OCMockObject mockForProtocol:@protocol(TargetActionMock)];
+ [button_ setTarget:mock_target];
+ [button_ setAction:@selector(anAction:)];
+
+ // Expect the action once.
+ [[mock_target expect] anAction:button_];
+
+ const std::pair<NSEvent*,NSEvent*> click_one =
+ test_event_utils::MouseClickInView(button_, 1);
+ const std::pair<NSEvent*,NSEvent*> click_two =
+ test_event_utils::MouseClickInView(button_, 2);
+ [NSApp postEvent:click_one.second atStart:YES];
+ [button_ mouseDown:click_one.first];
+ [NSApp postEvent:click_two.second atStart:YES];
+ [button_ mouseDown:click_two.first];
+
+ [button_ setTarget:nil];
+}
+
+TEST_F(ReloadButtonTest, UpdateTag) {
+ [button_ setTag:IDC_STOP];
+
+ [button_ updateTag:IDC_RELOAD];
+ EXPECT_EQ(IDC_RELOAD, [button_ tag]);
+ NSImage* reloadImage = [button_ image];
+ NSString* const reloadToolTip = [button_ toolTip];
+
+ [button_ updateTag:IDC_STOP];
+ EXPECT_EQ(IDC_STOP, [button_ tag]);
+ NSImage* stopImage = [button_ image];
+ NSString* const stopToolTip = [button_ toolTip];
+ EXPECT_NSNE(reloadImage, stopImage);
+ EXPECT_NSNE(reloadToolTip, stopToolTip);
+
+ [button_ updateTag:IDC_RELOAD];
+ EXPECT_EQ(IDC_RELOAD, [button_ tag]);
+ EXPECT_NSEQ(reloadImage, [button_ image]);
+ EXPECT_NSEQ(reloadToolTip, [button_ toolTip]);
+}
+
+// Test that when forcing the mode, it takes effect immediately,
+// regardless of whether the mouse is hovering.
+TEST_F(ReloadButtonTest, SetIsLoadingForce) {
+ EXPECT_FALSE([button_ isMouseInside]);
+ EXPECT_EQ(IDC_RELOAD, [button_ tag]);
+
+ // Changes to stop immediately.
+ [button_ setIsLoading:YES force:YES];
+ EXPECT_EQ(IDC_STOP, [button_ tag]);
+
+ // Changes to reload immediately.
+ [button_ setIsLoading:NO force:YES];
+ EXPECT_EQ(IDC_RELOAD, [button_ tag]);
+
+ // Changes to stop immediately when the mouse is hovered, and
+ // doesn't change when the mouse exits.
+ [button_ mouseEntered:nil];
+ EXPECT_TRUE([button_ isMouseInside]);
+ [button_ setIsLoading:YES force:YES];
+ EXPECT_EQ(IDC_STOP, [button_ tag]);
+ [button_ mouseExited:nil];
+ EXPECT_FALSE([button_ isMouseInside]);
+ EXPECT_EQ(IDC_STOP, [button_ tag]);
+
+ // Changes to reload immediately when the mouse is hovered, and
+ // doesn't change when the mouse exits.
+ [button_ mouseEntered:nil];
+ EXPECT_TRUE([button_ isMouseInside]);
+ [button_ setIsLoading:NO force:YES];
+ EXPECT_EQ(IDC_RELOAD, [button_ tag]);
+ [button_ mouseExited:nil];
+ EXPECT_FALSE([button_ isMouseInside]);
+ EXPECT_EQ(IDC_RELOAD, [button_ tag]);
+}
+
+// Test that without force, stop mode is set immediately, but reload
+// is affected by the hover status.
+TEST_F(ReloadButtonTest, SetIsLoadingNoForceUnHover) {
+ EXPECT_FALSE([button_ isMouseInside]);
+ EXPECT_EQ(IDC_RELOAD, [button_ tag]);
+
+ // Changes to stop immediately when the mouse is not hovering.
+ [button_ setIsLoading:YES force:NO];
+ EXPECT_EQ(IDC_STOP, [button_ tag]);
+
+ // Changes to reload immediately when the mouse is not hovering.
+ [button_ setIsLoading:NO force:NO];
+ EXPECT_EQ(IDC_RELOAD, [button_ tag]);
+
+ // Changes to stop immediately when the mouse is hovered, and
+ // doesn't change when the mouse exits.
+ [button_ mouseEntered:nil];
+ EXPECT_TRUE([button_ isMouseInside]);
+ [button_ setIsLoading:YES force:NO];
+ EXPECT_EQ(IDC_STOP, [button_ tag]);
+ [button_ mouseExited:nil];
+ EXPECT_FALSE([button_ isMouseInside]);
+ EXPECT_EQ(IDC_STOP, [button_ tag]);
+
+ // Does not change to reload immediately when the mouse is hovered,
+ // changes when the mouse exits.
+ [button_ mouseEntered:nil];
+ EXPECT_TRUE([button_ isMouseInside]);
+ [button_ setIsLoading:NO force:NO];
+ EXPECT_EQ(IDC_STOP, [button_ tag]);
+ [button_ mouseExited:nil];
+ EXPECT_FALSE([button_ isMouseInside]);
+ EXPECT_EQ(IDC_RELOAD, [button_ tag]);
+}
+
+// Test that without force, stop mode is set immediately, and reload
+// will be set after a timeout.
+// TODO(shess): Reenable, http://crbug.com/61485
+TEST_F(ReloadButtonTest, DISABLED_SetIsLoadingNoForceTimeout) {
+ // When the event loop first spins, some delayed tracking-area setup
+ // is done, which causes -mouseExited: to be called. Spin it at
+ // least once, and dequeue any pending events.
+ // TODO(shess): It would be more reasonable to have an MockNSTimer
+ // factory for the class to use, which this code could fire
+ // directly.
+ while ([NSApp nextEventMatchingMask:NSAnyEventMask
+ untilDate:nil
+ inMode:NSDefaultRunLoopMode
+ dequeue:YES]) {
+ }
+
+ const NSTimeInterval kShortTimeout = 0.1;
+ [ReloadButton setPendingReloadTimeout:kShortTimeout];
+
+ EXPECT_FALSE([button_ isMouseInside]);
+ EXPECT_EQ(IDC_RELOAD, [button_ tag]);
+
+ // Move the mouse into the button and press it.
+ [button_ mouseEntered:nil];
+ EXPECT_TRUE([button_ isMouseInside]);
+ [button_ setIsLoading:YES force:NO];
+ EXPECT_EQ(IDC_STOP, [button_ tag]);
+
+ // Does not change to reload immediately when the mouse is hovered.
+ EXPECT_TRUE([button_ isMouseInside]);
+ [button_ setIsLoading:NO force:NO];
+ EXPECT_TRUE([button_ isMouseInside]);
+ EXPECT_EQ(IDC_STOP, [button_ tag]);
+ EXPECT_TRUE([button_ isMouseInside]);
+
+ // Spin event loop until the timeout passes.
+ NSDate* pastTimeout = [NSDate dateWithTimeIntervalSinceNow:2 * kShortTimeout];
+ [NSApp nextEventMatchingMask:NSAnyEventMask
+ untilDate:pastTimeout
+ inMode:NSDefaultRunLoopMode
+ dequeue:NO];
+
+ // Mouse is still hovered, button is in reload mode. If the mouse
+ // is no longer hovered, see comment at top of function.
+ EXPECT_TRUE([button_ isMouseInside]);
+ EXPECT_EQ(IDC_RELOAD, [button_ tag]);
+}
+
+// Test that pressing stop after reload mode has been requested
+// doesn't forward the stop message.
+TEST_F(ReloadButtonTest, StopAfterReloadSet) {
+ id mock_target = [OCMockObject mockForProtocol:@protocol(TargetActionMock)];
+ [button_ setTarget:mock_target];
+ [button_ setAction:@selector(anAction:)];
+
+ EXPECT_FALSE([button_ isMouseInside]);
+
+ // Get to stop mode.
+ [button_ setIsLoading:YES force:YES];
+ EXPECT_EQ(IDC_STOP, [button_ tag]);
+ EXPECT_TRUE([button_ isEnabled]);
+
+ // Expect the action once.
+ [[mock_target expect] anAction:button_];
+
+ // Clicking in stop mode should send the action and transition to
+ // reload mode.
+ const std::pair<NSEvent*,NSEvent*> click =
+ test_event_utils::MouseClickInView(button_, 1);
+ [NSApp postEvent:click.second atStart:YES];
+ [button_ mouseDown:click.first];
+ EXPECT_EQ(IDC_RELOAD, [button_ tag]);
+ EXPECT_TRUE([button_ isEnabled]);
+
+ // Get back to stop mode.
+ [button_ setIsLoading:YES force:YES];
+ EXPECT_EQ(IDC_STOP, [button_ tag]);
+ EXPECT_TRUE([button_ isEnabled]);
+
+ // If hover prevented reload mode immediately taking effect, clicks should do
+ // nothing, because the button should be disabled.
+ [button_ mouseEntered:nil];
+ EXPECT_TRUE([button_ isMouseInside]);
+ [button_ setIsLoading:NO force:NO];
+ EXPECT_EQ(IDC_STOP, [button_ tag]);
+ EXPECT_FALSE([button_ isEnabled]);
+ [NSApp postEvent:click.second atStart:YES];
+ [button_ mouseDown:click.first];
+ EXPECT_EQ(IDC_STOP, [button_ tag]);
+
+ [button_ setTarget:nil];
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/repost_form_warning_mac.h b/chrome/browser/ui/cocoa/repost_form_warning_mac.h
new file mode 100644
index 0000000..a7ca8b2
--- /dev/null
+++ b/chrome/browser/ui/cocoa/repost_form_warning_mac.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_REPOST_FORM_WARNING_MAC_H_
+#define CHROME_BROWSER_UI_COCOA_REPOST_FORM_WARNING_MAC_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_ptr.h"
+#include "chrome/browser/ui/cocoa/constrained_window_mac.h"
+
+class RepostFormWarningController;
+
+// Displays a dialog that warns the user that they are about to resubmit
+// a form. To show the dialog, call the |Create| method. It will open the
+// dialog and then delete itself when the user dismisses the dialog.
+class RepostFormWarningMac : public ConstrainedDialogDelegate {
+ public:
+ // Convenience method that creates a new |RepostFormWarningController| and
+ // then a new |RepostFormWarningMac| from that.
+ static RepostFormWarningMac* Create(NSWindow* parent,
+ TabContents* tab_contents);
+
+ RepostFormWarningMac(NSWindow* parent,
+ RepostFormWarningController* controller);
+
+ // ConstrainedWindowDelegateMacSystemSheet methods:
+ virtual void DeleteDelegate();
+
+ private:
+ virtual ~RepostFormWarningMac();
+
+ scoped_ptr<RepostFormWarningController> controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(RepostFormWarningMac);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_REPOST_FORM_WARNING_MAC_H_
diff --git a/chrome/browser/ui/cocoa/repost_form_warning_mac.mm b/chrome/browser/ui/cocoa/repost_form_warning_mac.mm
new file mode 100644
index 0000000..71f292b
--- /dev/null
+++ b/chrome/browser/ui/cocoa/repost_form_warning_mac.mm
@@ -0,0 +1,82 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/repost_form_warning_mac.h"
+
+#include "app/l10n_util_mac.h"
+#include "base/scoped_nsobject.h"
+#include "chrome/browser/repost_form_warning_controller.h"
+#include "grit/generated_resources.h"
+
+// The delegate of the NSAlert used to display the dialog. Forwards the alert's
+// completion event to the C++ class |RepostFormWarningController|.
+@interface RepostDelegate : NSObject {
+ RepostFormWarningController* warning_; // weak
+}
+- (id)initWithWarning:(RepostFormWarningController*)warning;
+- (void)alertDidEnd:(NSAlert*)alert
+ returnCode:(int)returnCode
+ contextInfo:(void*)contextInfo;
+@end
+
+@implementation RepostDelegate
+- (id)initWithWarning:(RepostFormWarningController*)warning {
+ if ((self = [super init])) {
+ warning_ = warning;
+ }
+ return self;
+}
+
+- (void)alertDidEnd:(NSAlert*)alert
+ returnCode:(int)returnCode
+ contextInfo:(void*)contextInfo {
+ if (returnCode == NSAlertFirstButtonReturn) {
+ warning_->Continue();
+ } else {
+ warning_->Cancel();
+ }
+}
+@end
+
+RepostFormWarningMac* RepostFormWarningMac::Create(NSWindow* parent,
+ TabContents* tab_contents) {
+ return new RepostFormWarningMac(
+ parent,
+ new RepostFormWarningController(tab_contents));
+}
+
+RepostFormWarningMac::RepostFormWarningMac(
+ NSWindow* parent,
+ RepostFormWarningController* controller)
+ : ConstrainedWindowMacDelegateSystemSheet(
+ [[[RepostDelegate alloc] initWithWarning:controller]
+ autorelease],
+ @selector(alertDidEnd:returnCode:contextInfo:)),
+ controller_(controller) {
+ scoped_nsobject<NSAlert> alert([[NSAlert alloc] init]);
+ [alert setMessageText:
+ l10n_util::GetNSStringWithFixup(IDS_HTTP_POST_WARNING_TITLE)];
+ [alert setInformativeText:
+ l10n_util::GetNSStringWithFixup(IDS_HTTP_POST_WARNING)];
+ [alert addButtonWithTitle:
+ l10n_util::GetNSStringWithFixup(IDS_HTTP_POST_WARNING_RESEND)];
+ [alert addButtonWithTitle:
+ l10n_util::GetNSStringWithFixup(IDS_CANCEL)];
+
+ set_sheet(alert);
+
+ controller->Show(this);
+}
+
+RepostFormWarningMac::~RepostFormWarningMac() {
+ NSWindow* window = [(NSAlert*)sheet() window];
+ if (window && is_sheet_open()) {
+ [NSApp endSheet:window
+ returnCode:NSAlertSecondButtonReturn];
+ }
+}
+
+void RepostFormWarningMac::DeleteDelegate() {
+ delete this;
+}
diff --git a/chrome/browser/ui/cocoa/restart_browser.h b/chrome/browser/ui/cocoa/restart_browser.h
new file mode 100644
index 0000000..27bdd35
--- /dev/null
+++ b/chrome/browser/ui/cocoa/restart_browser.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_RESTART_BROWSER_H_
+#define CHROME_BROWSER_UI_COCOA_RESTART_BROWSER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+// This is a functional match for chrome/browser/views/restart_message_box
+// so any code that needs to ask for a browser restart has something like what
+// the Windows code has.
+namespace restart_browser {
+
+// Puts up an alert telling the user to restart their browser. The alert
+// will be hung off |parent| or global otherise.
+void RequestRestart(NSWindow* parent);
+
+} // namespace restart_browser
+
+#endif // CHROME_BROWSER_UI_COCOA_RESTART_BROWSER_H_
diff --git a/chrome/browser/ui/cocoa/restart_browser.mm b/chrome/browser/ui/cocoa/restart_browser.mm
new file mode 100644
index 0000000..c88715a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/restart_browser.mm
@@ -0,0 +1,86 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/restart_browser.h"
+
+#include "app/l10n_util.h"
+#include "app/l10n_util_mac.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/common/pref_names.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/app_strings.h"
+
+// Helper to clean up after the notification that the alert was dismissed.
+@interface RestartHelper : NSObject {
+ @private
+ NSAlert* alert_;
+}
+- (NSAlert*)alert;
+- (void)alertDidEnd:(NSAlert*)alert
+ returnCode:(int)returnCode
+ contextInfo:(void*)contextInfo;
+@end
+
+@implementation RestartHelper
+
+- (NSAlert*)alert {
+ alert_ = [[NSAlert alloc] init];
+ return alert_;
+}
+
+- (void)dealloc {
+ [alert_ release];
+ [super dealloc];
+}
+
+- (void)alertDidEnd:(NSAlert*)alert
+ returnCode:(int)returnCode
+ contextInfo:(void*)contextInfo {
+ if (returnCode == NSAlertFirstButtonReturn) {
+ // Nothing to do. User will restart later.
+ } else if (returnCode == NSAlertSecondButtonReturn) {
+ // Set the flag to restore state after the restart.
+ PrefService* pref_service = g_browser_process->local_state();
+ pref_service->SetBoolean(prefs::kRestartLastSessionOnShutdown, true);
+ BrowserList::CloseAllBrowsersAndExit();
+ } else {
+ NOTREACHED();
+ }
+ [self autorelease];
+}
+
+@end
+
+namespace restart_browser {
+
+void RequestRestart(NSWindow* parent) {
+ NSString* title =
+ l10n_util::GetNSStringFWithFixup(IDS_PLEASE_RESTART_BROWSER,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
+ NSString* text =
+ l10n_util::GetNSStringFWithFixup(IDS_UPDATE_RECOMMENDED,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
+ NSString* notNowButtin = l10n_util::GetNSStringWithFixup(IDS_NOT_NOW);
+ NSString* restartButton =
+ l10n_util::GetNSStringWithFixup(IDS_RESTART_AND_UPDATE);
+
+ RestartHelper* helper = [[RestartHelper alloc] init];
+
+ NSAlert* alert = [helper alert];
+ [alert setAlertStyle:NSInformationalAlertStyle];
+ [alert setMessageText:title];
+ [alert setInformativeText:text];
+ [alert addButtonWithTitle:notNowButtin];
+ [alert addButtonWithTitle:restartButton];
+
+ [alert beginSheetModalForWindow:parent
+ modalDelegate:helper
+ didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
+ contextInfo:nil];
+}
+
+} // namespace restart_browser
diff --git a/chrome/browser/ui/cocoa/rwhvm_editcommand_helper.h b/chrome/browser/ui/cocoa/rwhvm_editcommand_helper.h
new file mode 100644
index 0000000..92935a4
--- /dev/null
+++ b/chrome/browser/ui/cocoa/rwhvm_editcommand_helper.h
@@ -0,0 +1,72 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_RWHVM_EDITCOMMAND_HELPER_H_
+#define CHROME_BROWSER_UI_COCOA_RWHVM_EDITCOMMAND_HELPER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/basictypes.h"
+#include "base/hash_tables.h"
+#include "base/gtest_prod_util.h"
+#include "chrome/browser/renderer_host/render_widget_host_view_mac.h"
+
+// RenderWidgetHostViewMacEditCommandHelper is the real name of this class
+// but that's too long, so we use a shorter version.
+//
+// This class mimics the behavior of WebKit's WebView class in a way that makes
+// sense for Chrome.
+//
+// WebCore has the concept of "core commands", basically named actions such as
+// "Select All" and "Move Cursor Left". The commands are executed using their
+// string value by WebCore.
+//
+// This class is responsible for 2 things:
+// 1. Provide an abstraction to determine the enabled/disabled state of menu
+// items that correspond to edit commands.
+// 2. Hook up a bunch of objc selectors to the RenderWidgetHostViewCocoa object.
+// (note that this is not a misspelling of RenderWidgetHostViewMac, it's in
+// fact a distinct object) When these selectors are called, the relevant
+// edit command is executed in WebCore.
+class RWHVMEditCommandHelper {
+ FRIEND_TEST_ALL_PREFIXES(RWHVMEditCommandHelperTest,
+ TestAddEditingSelectorsToClass);
+ FRIEND_TEST_ALL_PREFIXES(RWHVMEditCommandHelperTest,
+ TestEditingCommandDelivery);
+
+ public:
+ RWHVMEditCommandHelper();
+
+ // Adds editing selectors to the objc class using the objc runtime APIs.
+ // Each selector is connected to a single c method which forwards the message
+ // to WebCore's ExecuteEditCommand() function.
+ // This method is idempotent.
+ // The class passed in must conform to the RenderWidgetHostViewMacOwner
+ // protocol.
+ void AddEditingSelectorsToClass(Class klass);
+
+ // Is a given menu item currently enabled?
+ // SEL - the objc selector currently associated with an NSMenuItem.
+ // owner - An object we can retrieve a RenderWidgetHostViewMac from to
+ // determine the command states.
+ bool IsMenuItemEnabled(SEL item_action,
+ id<RenderWidgetHostViewMacOwner> owner);
+
+ // Converts an editing selector into a command name that can be sent to
+ // webkit.
+ static NSString* CommandNameForSelector(SEL selector);
+
+ protected:
+ // Gets a list of all the selectors that AddEditingSelectorsToClass adds to
+ // the aforementioned class.
+ // returns an array of NSStrings WITHOUT the trailing ':'s.
+ NSArray* GetEditSelectorNames();
+
+ private:
+ base::hash_set<std::string> edit_command_set_;
+ DISALLOW_COPY_AND_ASSIGN(RWHVMEditCommandHelper);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_RWHVM_EDITCOMMAND_HELPER_H_
diff --git a/chrome/browser/ui/cocoa/rwhvm_editcommand_helper.mm b/chrome/browser/ui/cocoa/rwhvm_editcommand_helper.mm
new file mode 100644
index 0000000..0aec09e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/rwhvm_editcommand_helper.mm
@@ -0,0 +1,227 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/rwhvm_editcommand_helper.h"
+
+#import <objc/runtime.h>
+
+#include "chrome/browser/renderer_host/render_widget_host.h"
+#import "chrome/browser/renderer_host/render_widget_host_view_mac.h"
+
+namespace {
+// The names of all the objc selectors w/o ':'s added to an object by
+// AddEditingSelectorsToClass().
+//
+// This needs to be kept in Sync with WEB_COMMAND list in the WebKit tree at:
+// WebKit/mac/WebView/WebHTMLView.mm .
+const char* kEditCommands[] = {
+ "alignCenter",
+ "alignJustified",
+ "alignLeft",
+ "alignRight",
+ "copy",
+ "cut",
+ "delete",
+ "deleteBackward",
+ "deleteBackwardByDecomposingPreviousCharacter",
+ "deleteForward",
+ "deleteToBeginningOfLine",
+ "deleteToBeginningOfParagraph",
+ "deleteToEndOfLine",
+ "deleteToEndOfParagraph",
+ "deleteToMark",
+ "deleteWordBackward",
+ "deleteWordForward",
+ "ignoreSpelling",
+ "indent",
+ "insertBacktab",
+ "insertLineBreak",
+ "insertNewline",
+ "insertNewlineIgnoringFieldEditor",
+ "insertParagraphSeparator",
+ "insertTab",
+ "insertTabIgnoringFieldEditor",
+ "makeTextWritingDirectionLeftToRight",
+ "makeTextWritingDirectionNatural",
+ "makeTextWritingDirectionRightToLeft",
+ "moveBackward",
+ "moveBackwardAndModifySelection",
+ "moveDown",
+ "moveDownAndModifySelection",
+ "moveForward",
+ "moveForwardAndModifySelection",
+ "moveLeft",
+ "moveLeftAndModifySelection",
+ "moveParagraphBackwardAndModifySelection",
+ "moveParagraphForwardAndModifySelection",
+ "moveRight",
+ "moveRightAndModifySelection",
+ "moveToBeginningOfDocument",
+ "moveToBeginningOfDocumentAndModifySelection",
+ "moveToBeginningOfLine",
+ "moveToBeginningOfLineAndModifySelection",
+ "moveToBeginningOfParagraph",
+ "moveToBeginningOfParagraphAndModifySelection",
+ "moveToBeginningOfSentence",
+ "moveToBeginningOfSentenceAndModifySelection",
+ "moveToEndOfDocument",
+ "moveToEndOfDocumentAndModifySelection",
+ "moveToEndOfLine",
+ "moveToEndOfLineAndModifySelection",
+ "moveToEndOfParagraph",
+ "moveToEndOfParagraphAndModifySelection",
+ "moveToEndOfSentence",
+ "moveToEndOfSentenceAndModifySelection",
+ "moveUp",
+ "moveUpAndModifySelection",
+ "moveWordBackward",
+ "moveWordBackwardAndModifySelection",
+ "moveWordForward",
+ "moveWordForwardAndModifySelection",
+ "moveWordLeft",
+ "moveWordLeftAndModifySelection",
+ "moveWordRight",
+ "moveWordRightAndModifySelection",
+ "outdent",
+ "pageDown",
+ "pageDownAndModifySelection",
+ "pageUp",
+ "pageUpAndModifySelection",
+ "selectAll",
+ "selectLine",
+ "selectParagraph",
+ "selectSentence",
+ "selectToMark",
+ "selectWord",
+ "setMark",
+ "showGuessPanel",
+ "subscript",
+ "superscript",
+ "swapWithMark",
+ "transpose",
+ "underline",
+ "unscript",
+ "yank",
+ "yankAndSelect"};
+
+
+// This function is installed via the objc runtime as the implementation of all
+// the various editing selectors.
+// The objc runtime hookup occurs in
+// RWHVMEditCommandHelper::AddEditingSelectorsToClass().
+//
+// self - the object we're attached to; it must implement the
+// RenderWidgetHostViewMacOwner protocol.
+// _cmd - the selector that fired.
+// sender - the id of the object that sent the message.
+//
+// The selector is translated into an edit comand and then forwarded down the
+// pipeline to WebCore.
+// The route the message takes is:
+// RenderWidgetHostViewMac -> RenderViewHost ->
+// | IPC | ->
+// RenderView -> currently focused WebFrame.
+// The WebFrame is in the Chrome glue layer and forwards the message to WebCore.
+void EditCommandImp(id self, SEL _cmd, id sender) {
+ // Make sure |self| is the right type.
+ DCHECK([self conformsToProtocol:@protocol(RenderWidgetHostViewMacOwner)]);
+
+ // SEL -> command name string.
+ NSString* command_name_ns =
+ RWHVMEditCommandHelper::CommandNameForSelector(_cmd);
+ std::string edit_command([command_name_ns UTF8String]);
+
+ // Forward the edit command string down the pipeline.
+ RenderWidgetHostViewMac* rwhv = [(id<RenderWidgetHostViewMacOwner>)self
+ renderWidgetHostViewMac];
+ DCHECK(rwhv);
+
+ // The second parameter is the core command value which isn't used here.
+ rwhv->GetRenderWidgetHost()->ForwardEditCommand(edit_command, "");
+}
+
+} // namespace
+
+// Maps an objc-selector to a core command name.
+//
+// Returns the core command name (which is the selector name with the trailing
+// ':' stripped in most cases).
+//
+// Adapted from a function by the same name in
+// WebKit/mac/WebView/WebHTMLView.mm .
+// Capitalized names are returned from this function, but that's simply
+// matching WebHTMLView.mm.
+NSString* RWHVMEditCommandHelper::CommandNameForSelector(SEL selector) {
+ if (selector == @selector(insertParagraphSeparator:) ||
+ selector == @selector(insertNewlineIgnoringFieldEditor:))
+ return @"InsertNewline";
+ if (selector == @selector(insertTabIgnoringFieldEditor:))
+ return @"InsertTab";
+ if (selector == @selector(pageDown:))
+ return @"MovePageDown";
+ if (selector == @selector(pageDownAndModifySelection:))
+ return @"MovePageDownAndModifySelection";
+ if (selector == @selector(pageUp:))
+ return @"MovePageUp";
+ if (selector == @selector(pageUpAndModifySelection:))
+ return @"MovePageUpAndModifySelection";
+
+ // Remove the trailing colon.
+ NSString* selector_str = NSStringFromSelector(selector);
+ int selector_len = [selector_str length];
+ return [selector_str substringToIndex:selector_len - 1];
+}
+
+RWHVMEditCommandHelper::RWHVMEditCommandHelper() {
+ for (size_t i = 0; i < arraysize(kEditCommands); ++i) {
+ edit_command_set_.insert(kEditCommands[i]);
+ }
+}
+
+// Dynamically adds Selectors to the aformentioned class.
+void RWHVMEditCommandHelper::AddEditingSelectorsToClass(Class klass) {
+ for (size_t i = 0; i < arraysize(kEditCommands); ++i) {
+ // Append trailing ':' to command name to get selector name.
+ NSString* sel_str = [NSString stringWithFormat: @"%s:", kEditCommands[i]];
+
+ SEL edit_selector = NSSelectorFromString(sel_str);
+ // May want to use @encode() for the last parameter to this method.
+ // If class_addMethod fails we assume that all the editing selectors where
+ // added to the class.
+ // If a certain class already implements a method then class_addMethod
+ // returns NO, which we can safely ignore.
+ class_addMethod(klass, edit_selector, (IMP)EditCommandImp, "v@:@");
+ }
+}
+
+bool RWHVMEditCommandHelper::IsMenuItemEnabled(SEL item_action,
+ id<RenderWidgetHostViewMacOwner> owner) {
+ const char* selector_name = sel_getName(item_action);
+ // TODO(jeremy): The final form of this function will check state
+ // associated with the Browser.
+
+ // For now just mark all edit commands as enabled.
+ NSString* selector_name_ns = [NSString stringWithUTF8String:selector_name];
+
+ // Remove trailing ':'
+ size_t str_len = [selector_name_ns length];
+ selector_name_ns = [selector_name_ns substringToIndex:str_len - 1];
+ std::string edit_command_name([selector_name_ns UTF8String]);
+
+ // search for presence in set and return.
+ bool ret = edit_command_set_.find(edit_command_name) !=
+ edit_command_set_.end();
+ return ret;
+}
+
+NSArray* RWHVMEditCommandHelper::GetEditSelectorNames() {
+ size_t num_edit_commands = arraysize(kEditCommands);
+ NSMutableArray* ret = [NSMutableArray arrayWithCapacity:num_edit_commands];
+
+ for (size_t i = 0; i < num_edit_commands; ++i) {
+ [ret addObject:[NSString stringWithUTF8String:kEditCommands[i]]];
+ }
+
+ return ret;
+}
diff --git a/chrome/browser/ui/cocoa/rwhvm_editcommand_helper_unittest.mm b/chrome/browser/ui/cocoa/rwhvm_editcommand_helper_unittest.mm
new file mode 100644
index 0000000..776c400
--- /dev/null
+++ b/chrome/browser/ui/cocoa/rwhvm_editcommand_helper_unittest.mm
@@ -0,0 +1,172 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/rwhvm_editcommand_helper.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "chrome/browser/renderer_host/mock_render_process_host.h"
+#include "chrome/browser/renderer_host/render_widget_host.h"
+#include "chrome/test/testing_profile.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+class RWHVMEditCommandHelperTest : public PlatformTest {
+};
+
+// Bare bones obj-c class for testing purposes.
+@interface RWHVMEditCommandHelperTestClass : NSObject
+@end
+
+@implementation RWHVMEditCommandHelperTestClass
+@end
+
+// Class that owns a RenderWidgetHostViewMac.
+@interface RenderWidgetHostViewMacOwner :
+ NSObject<RenderWidgetHostViewMacOwner> {
+ RenderWidgetHostViewMac* rwhvm_;
+}
+
+- (id) initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)rwhvm;
+@end
+
+@implementation RenderWidgetHostViewMacOwner
+
+- (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)rwhvm {
+ if ((self = [super init])) {
+ rwhvm_ = rwhvm;
+ }
+ return self;
+}
+
+- (RenderWidgetHostViewMac*)renderWidgetHostViewMac {
+ return rwhvm_;
+}
+
+@end
+
+
+namespace {
+ // Returns true if all the edit command names in the array are present
+ // in test_obj.
+ // edit_commands is a list of NSStrings, selector names are formed by
+ // appending a trailing ':' to the string.
+ bool CheckObjectRespondsToEditCommands(NSArray* edit_commands, id test_obj) {
+ for (NSString* edit_command_name in edit_commands) {
+ NSString* sel_str = [edit_command_name stringByAppendingString:@":"];
+ if (![test_obj respondsToSelector:NSSelectorFromString(sel_str)]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+} // namespace
+
+// Create a Mock RenderWidget
+class MockRenderWidgetHostEditCommandCounter : public RenderWidgetHost {
+ public:
+ MockRenderWidgetHostEditCommandCounter(RenderProcessHost* process,
+ int routing_id) :
+ RenderWidgetHost(process, routing_id) {}
+
+ MOCK_METHOD2(ForwardEditCommand, void(const std::string&,
+ const std::string&));
+};
+
+
+// Tests that editing commands make it through the pipeline all the way to
+// RenderWidgetHost.
+TEST_F(RWHVMEditCommandHelperTest, TestEditingCommandDelivery) {
+ RWHVMEditCommandHelper helper;
+ NSArray* edit_command_strings = helper.GetEditSelectorNames();
+
+ // Set up a mock render widget and set expectations.
+ MessageLoopForUI message_loop;
+ TestingProfile profile;
+ MockRenderProcessHost mock_process(&profile);
+ MockRenderWidgetHostEditCommandCounter mock_render_widget(&mock_process, 0);
+
+ size_t num_edit_commands = [edit_command_strings count];
+ EXPECT_CALL(mock_render_widget,
+ ForwardEditCommand(testing::_, testing::_)).Times(num_edit_commands);
+
+// TODO(jeremy): Figure this out and reenable this test.
+// For some bizarre reason this code doesn't work, running the code in the
+// debugger confirms that the function is called with the correct parameters
+// however gmock appears not to be able to match up parameters correctly.
+// Disable for now till we can figure this out.
+#if 0
+ // Tell Mock object that we expect to recieve each edit command once.
+ std::string empty_str;
+ for (NSString* edit_command_name in edit_command_strings) {
+ std::string command([edit_command_name UTF8String]);
+ EXPECT_CALL(mock_render_widget,
+ ForwardEditCommand(command, empty_str)).Times(1);
+ }
+#endif // 0
+
+ // RenderWidgetHostViewMac self destructs (RenderWidgetHostViewMacCocoa
+ // takes ownership) so no need to delete it ourselves.
+ RenderWidgetHostViewMac* rwhvm = new RenderWidgetHostViewMac(
+ &mock_render_widget);
+
+ RenderWidgetHostViewMacOwner* rwhwvm_owner =
+ [[[RenderWidgetHostViewMacOwner alloc]
+ initWithRenderWidgetHostViewMac:rwhvm] autorelease];
+
+ helper.AddEditingSelectorsToClass([rwhwvm_owner class]);
+
+ for (NSString* edit_command_name in edit_command_strings) {
+ NSString* sel_str = [edit_command_name stringByAppendingString:@":"];
+ [rwhwvm_owner performSelector:NSSelectorFromString(sel_str) withObject:nil];
+ }
+}
+
+// Test RWHVMEditCommandHelper::AddEditingSelectorsToClass
+TEST_F(RWHVMEditCommandHelperTest, TestAddEditingSelectorsToClass) {
+ RWHVMEditCommandHelper helper;
+ NSArray* edit_command_strings = helper.GetEditSelectorNames();
+ ASSERT_GT([edit_command_strings count], 0U);
+
+ // Create a class instance and add methods to the class.
+ RWHVMEditCommandHelperTestClass* test_obj =
+ [[[RWHVMEditCommandHelperTestClass alloc] init] autorelease];
+
+ // Check that edit commands aren't already attached to the object.
+ ASSERT_FALSE(CheckObjectRespondsToEditCommands(edit_command_strings,
+ test_obj));
+
+ helper.AddEditingSelectorsToClass([test_obj class]);
+
+ // Check that all edit commands where added.
+ ASSERT_TRUE(CheckObjectRespondsToEditCommands(edit_command_strings,
+ test_obj));
+
+ // AddEditingSelectorsToClass() should be idempotent.
+ helper.AddEditingSelectorsToClass([test_obj class]);
+
+ // Check that all edit commands are still there.
+ ASSERT_TRUE(CheckObjectRespondsToEditCommands(edit_command_strings,
+ test_obj));
+}
+
+// Test RWHVMEditCommandHelper::IsMenuItemEnabled.
+TEST_F(RWHVMEditCommandHelperTest, TestMenuItemEnabling) {
+ RWHVMEditCommandHelper helper;
+ RenderWidgetHostViewMacOwner* rwhvm_owner =
+ [[[RenderWidgetHostViewMacOwner alloc] init] autorelease];
+
+ // The select all menu should always be enabled.
+ SEL select_all = NSSelectorFromString(@"selectAll:");
+ ASSERT_TRUE(helper.IsMenuItemEnabled(select_all, rwhvm_owner));
+
+ // Random selectors should be enabled by the function.
+ SEL garbage_selector = NSSelectorFromString(@"randomGarbageSelector:");
+ ASSERT_FALSE(helper.IsMenuItemEnabled(garbage_selector, rwhvm_owner));
+
+ // TODO(jeremy): Currently IsMenuItemEnabled just returns true for all edit
+ // selectors. Once we go past that we should do more extensive testing here.
+}
diff --git a/chrome/browser/ui/cocoa/sad_tab_controller.h b/chrome/browser/ui/cocoa/sad_tab_controller.h
new file mode 100644
index 0000000..35e9aaf
--- /dev/null
+++ b/chrome/browser/ui/cocoa/sad_tab_controller.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_SAD_TAB_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_SAD_TAB_CONTROLLER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+class TabContents;
+
+// A controller class that manages the SadTabView (aka "Aw Snap" or crash page).
+@interface SadTabController : NSViewController {
+ @private
+ TabContents* tabContents_; // Weak reference.
+}
+
+// Designated initializer is initWithTabContents.
+- (id)initWithTabContents:(TabContents*)someTabContents
+ superview:(NSView*)superview;
+
+// This action just calls the NSApp sendAction to get it into the standard
+// Cocoa action processing.
+- (IBAction)openLearnMoreAboutCrashLink:(id)sender;
+
+// Returns a weak reference to the TabContents whose TabContentsView created
+// this SadTabController.
+- (TabContents*)tabContents;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_SAD_TAB_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/sad_tab_controller.mm b/chrome/browser/ui/cocoa/sad_tab_controller.mm
new file mode 100644
index 0000000..ba0b102
--- /dev/null
+++ b/chrome/browser/ui/cocoa/sad_tab_controller.mm
@@ -0,0 +1,48 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/sad_tab_controller.h"
+
+#include "base/mac_util.h"
+#import "chrome/browser/ui/cocoa/sad_tab_view.h"
+
+@implementation SadTabController
+
+- (id)initWithTabContents:(TabContents*)someTabContents
+ superview:(NSView*)superview {
+ if ((self = [super initWithNibName:@"SadTab"
+ bundle:mac_util::MainAppBundle()])) {
+ tabContents_ = someTabContents;
+
+ NSView* view = [self view];
+ [superview addSubview:view];
+ [view setFrame:[superview bounds]];
+ }
+
+ return self;
+}
+
+- (void)awakeFromNib {
+ // If tab_contents_ is nil, ask view to remove link.
+ if (!tabContents_) {
+ SadTabView* sad_view = static_cast<SadTabView*>([self view]);
+ [sad_view removeLinkButton];
+ }
+}
+
+- (void)dealloc {
+ [[self view] removeFromSuperview];
+ [super dealloc];
+}
+
+- (TabContents*)tabContents {
+ return tabContents_;
+}
+
+- (void)openLearnMoreAboutCrashLink:(id)sender {
+ // Send the action up through the responder chain.
+ [NSApp sendAction:@selector(openLearnMoreAboutCrashLink:) to:nil from:self];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/sad_tab_controller_unittest.mm b/chrome/browser/ui/cocoa/sad_tab_controller_unittest.mm
new file mode 100644
index 0000000..15839a8
--- /dev/null
+++ b/chrome/browser/ui/cocoa/sad_tab_controller_unittest.mm
@@ -0,0 +1,113 @@
+// Copyright (c) 2009 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/debug/debugger.h"
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/sad_tab_controller.h"
+#import "chrome/browser/ui/cocoa/sad_tab_view.h"
+#include "chrome/browser/renderer_host/test/test_render_view_host.h"
+#include "chrome/browser/tab_contents/test_tab_contents.h"
+#include "chrome/test/testing_profile.h"
+
+@interface SadTabView (ExposedForTesting)
+// Implementation is below.
+- (NSButton*)linkButton;
+@end
+
+@implementation SadTabView (ExposedForTesting)
+- (NSButton*)linkButton {
+ return linkButton_;
+}
+@end
+
+namespace {
+
+class SadTabControllerTest : public RenderViewHostTestHarness {
+ public:
+ SadTabControllerTest() : test_window_(nil) {
+ link_clicked_ = false;
+ }
+
+ virtual void SetUp() {
+ RenderViewHostTestHarness::SetUp();
+ // Inherting from RenderViewHostTestHarness means we can't inherit from
+ // from CocoaTest, so do a bootstrap and create test window.
+ CocoaTest::BootstrapCocoa();
+ test_window_ = [[CocoaTestHelperWindow alloc] init];
+ if (base::debug::BeingDebugged()) {
+ [test_window_ orderFront:nil];
+ } else {
+ [test_window_ orderBack:nil];
+ }
+ }
+
+ virtual void TearDown() {
+ [test_window_ close];
+ test_window_ = nil;
+ RenderViewHostTestHarness::TearDown();
+ }
+
+ // Creates the controller and adds its view to contents, caller has ownership.
+ SadTabController* CreateController() {
+ NSView* contentView = [test_window_ contentView];
+ SadTabController* controller =
+ [[SadTabController alloc] initWithTabContents:contents()
+ superview:contentView];
+ EXPECT_TRUE(controller);
+ NSView* view = [controller view];
+ EXPECT_TRUE(view);
+
+ return controller;
+ }
+
+ NSButton* GetLinkButton(SadTabController* controller) {
+ SadTabView* view = static_cast<SadTabView*>([controller view]);
+ return ([view linkButton]);
+ }
+
+ static bool link_clicked_;
+ CocoaTestHelperWindow* test_window_;
+};
+
+// static
+bool SadTabControllerTest::link_clicked_;
+
+TEST_F(SadTabControllerTest, WithTabContents) {
+ scoped_nsobject<SadTabController> controller(CreateController());
+ EXPECT_TRUE(controller);
+ NSButton* link = GetLinkButton(controller);
+ EXPECT_TRUE(link);
+}
+
+TEST_F(SadTabControllerTest, WithoutTabContents) {
+ contents_.reset();
+ scoped_nsobject<SadTabController> controller(CreateController());
+ EXPECT_TRUE(controller);
+ NSButton* link = GetLinkButton(controller);
+ EXPECT_FALSE(link);
+}
+
+TEST_F(SadTabControllerTest, ClickOnLink) {
+ scoped_nsobject<SadTabController> controller(CreateController());
+ NSButton* link = GetLinkButton(controller);
+ EXPECT_TRUE(link);
+ EXPECT_FALSE(link_clicked_);
+ [link performClick:link];
+ EXPECT_TRUE(link_clicked_);
+}
+
+} // namespace
+
+@implementation NSApplication (SadTabControllerUnitTest)
+// Add handler for the openLearnMoreAboutCrashLink: action to NSApp for testing
+// purposes. Normally this would be sent up the responder tree correctly, but
+// since tests run in the background, key window and main window are never set
+// on NSApplication. Adding it to NSApplication directly removes the need for
+// worrying about what the current window with focus is.
+- (void)openLearnMoreAboutCrashLink:(id)sender {
+ SadTabControllerTest::link_clicked_ = true;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/sad_tab_view.h b/chrome/browser/ui/cocoa/sad_tab_view.h
new file mode 100644
index 0000000..0f304eb
--- /dev/null
+++ b/chrome/browser/ui/cocoa/sad_tab_view.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_SAD_TAB_VIEW_H_
+#define CHROME_BROWSER_UI_COCOA_SAD_TAB_VIEW_H_
+#pragma once
+
+#include "base/scoped_nsobject.h"
+#include "chrome/browser/ui/cocoa/base_view.h"
+
+#import <Cocoa/Cocoa.h>
+
+@class HyperlinkButtonCell;
+
+// A view that displays the "sad tab" (aka crash page).
+@interface SadTabView : BaseView {
+ @private
+ IBOutlet NSImageView* image_;
+ IBOutlet NSTextField* title_;
+ IBOutlet NSTextField* message_;
+ IBOutlet NSButton* linkButton_;
+ IBOutlet HyperlinkButtonCell* linkCell_;
+
+ scoped_nsobject<NSColor> backgroundColor_;
+ NSSize messageSize_;
+}
+
+// Designated initializer is -initWithFrame: .
+
+// Called by SadTabController to remove link button.
+- (void)removeLinkButton;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_SAD_TAB_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/sad_tab_view.mm b/chrome/browser/ui/cocoa/sad_tab_view.mm
new file mode 100644
index 0000000..2c9f9e2
--- /dev/null
+++ b/chrome/browser/ui/cocoa/sad_tab_view.mm
@@ -0,0 +1,127 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/sad_tab_view.h"
+
+#include "app/resource_bundle.h"
+#include "base/logging.h"
+#import "chrome/browser/ui/cocoa/hyperlink_button_cell.h"
+#include "grit/theme_resources.h"
+#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
+
+// Offset above vertical middle of page where contents of page start.
+static const CGFloat kSadTabOffset = -64;
+// Padding between icon and title.
+static const CGFloat kIconTitleSpacing = 20;
+// Padding between title and message.
+static const CGFloat kTitleMessageSpacing = 15;
+// Padding between message and link.
+static const CGFloat kMessageLinkSpacing = 15;
+// Paddings on left and right of page.
+static const CGFloat kTabHorzMargin = 13;
+
+@implementation SadTabView
+
+- (void)awakeFromNib {
+ // Load resource for image and set it.
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ NSImage* image = rb.GetNativeImageNamed(IDR_SAD_TAB);
+ DCHECK(image);
+ [image_ setImage:image];
+
+ // Set font for title.
+ NSFont* titleFont = [NSFont boldSystemFontOfSize:[NSFont systemFontSize]];
+ [title_ setFont:titleFont];
+
+ // Set font for message.
+ NSFont* messageFont = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
+ [message_ setFont:messageFont];
+
+ // If necessary, set font and color for link.
+ if (linkButton_) {
+ [linkButton_ setFont:messageFont];
+ [linkCell_ setTextColor:[NSColor whiteColor]];
+ }
+
+ // Initialize background color.
+ NSColor* backgroundColor = [[NSColor colorWithCalibratedRed:(35.0f/255.0f)
+ green:(48.0f/255.0f)
+ blue:(64.0f/255.0f)
+ alpha:1.0] retain];
+ backgroundColor_.reset(backgroundColor);
+}
+
+- (void)drawRect:(NSRect)dirtyRect {
+ // Paint background.
+ [backgroundColor_ set];
+ NSRectFill(dirtyRect);
+}
+
+- (void)resizeSubviewsWithOldSize:(NSSize)oldSize {
+ NSRect newBounds = [self bounds];
+ CGFloat maxWidth = NSWidth(newBounds) - (kTabHorzMargin * 2);
+ BOOL callSizeToFit = (messageSize_.width == 0);
+
+ // Set new frame origin for image.
+ NSRect iconFrame = [image_ frame];
+ CGFloat iconX = (maxWidth - NSWidth(iconFrame)) / 2;
+ CGFloat iconY =
+ MIN(((NSHeight(newBounds) - NSHeight(iconFrame)) / 2) - kSadTabOffset,
+ NSHeight(newBounds) - NSHeight(iconFrame));
+ iconX = floor(iconX);
+ iconY = floor(iconY);
+ [image_ setFrameOrigin:NSMakePoint(iconX, iconY)];
+
+ // Set new frame origin for title.
+ if (callSizeToFit)
+ [title_ sizeToFit];
+ NSRect titleFrame = [title_ frame];
+ CGFloat titleX = (maxWidth - NSWidth(titleFrame)) / 2;
+ CGFloat titleY = iconY - kIconTitleSpacing - NSHeight(titleFrame);
+ [title_ setFrameOrigin:NSMakePoint(titleX, titleY)];
+
+ // Set new frame for message, wrapping or unwrapping the text if necessary.
+ if (callSizeToFit) {
+ [message_ sizeToFit];
+ messageSize_ = [message_ frame].size;
+ }
+ NSRect messageFrame = [message_ frame];
+ if (messageSize_.width > maxWidth) { // Need to wrap message.
+ [message_ setFrameSize:NSMakeSize(maxWidth, messageSize_.height)];
+ CGFloat heightChange =
+ [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:message_];
+ messageFrame.size.width = maxWidth;
+ messageFrame.size.height = messageSize_.height + heightChange;
+ messageFrame.origin.x = kTabHorzMargin;
+ } else {
+ if (!callSizeToFit) {
+ [message_ sizeToFit];
+ messageFrame = [message_ frame];
+ }
+ messageFrame.origin.x = (maxWidth - NSWidth(messageFrame)) / 2;
+ }
+ messageFrame.origin.y =
+ titleY - kTitleMessageSpacing - NSHeight(messageFrame);
+ [message_ setFrame:messageFrame];
+
+ if (linkButton_) {
+ if (callSizeToFit)
+ [linkButton_ sizeToFit];
+ // Set new frame origin for link.
+ NSRect linkFrame = [linkButton_ frame];
+ CGFloat linkX = (maxWidth - NSWidth(linkFrame)) / 2;
+ CGFloat linkY =
+ NSMinY(messageFrame) - kMessageLinkSpacing - NSHeight(linkFrame);
+ [linkButton_ setFrameOrigin:NSMakePoint(linkX, linkY)];
+ }
+}
+
+- (void)removeLinkButton {
+ if (linkButton_) {
+ [linkButton_ removeFromSuperview];
+ linkButton_ = nil;
+ }
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/sad_tab_view_unittest.mm b/chrome/browser/ui/cocoa/sad_tab_view_unittest.mm
new file mode 100644
index 0000000..2321dd3
--- /dev/null
+++ b/chrome/browser/ui/cocoa/sad_tab_view_unittest.mm
@@ -0,0 +1,25 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/sad_tab_view.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+
+namespace {
+
+class SadTabViewTest : public CocoaTest {
+ public:
+ SadTabViewTest() {
+ NSRect content_frame = [[test_window() contentView] frame];
+ scoped_nsobject<SadTabView> view([[SadTabView alloc]
+ initWithFrame:content_frame]);
+ view_ = view.get();
+ [[test_window() contentView] addSubview:view_];
+ }
+
+ SadTabView* view_; // Weak. Owned by the view hierarchy.
+};
+
+TEST_VIEW(SadTabViewTest, view_);
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/scoped_authorizationref.h b/chrome/browser/ui/cocoa/scoped_authorizationref.h
new file mode 100644
index 0000000..ae7edb3
--- /dev/null
+++ b/chrome/browser/ui/cocoa/scoped_authorizationref.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_SCOPED_AUTHORIZATIONREF_H_
+#define CHROME_BROWSER_UI_COCOA_SCOPED_AUTHORIZATIONREF_H_
+#pragma once
+
+#include <Security/Authorization.h>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+// scoped_AuthorizationRef maintains ownership of an AuthorizationRef. It is
+// patterned after the scoped_ptr interface.
+
+class scoped_AuthorizationRef {
+ public:
+ explicit scoped_AuthorizationRef(AuthorizationRef authorization = NULL)
+ : authorization_(authorization) {
+ }
+
+ ~scoped_AuthorizationRef() {
+ if (authorization_) {
+ AuthorizationFree(authorization_, kAuthorizationFlagDestroyRights);
+ }
+ }
+
+ void reset(AuthorizationRef authorization = NULL) {
+ if (authorization_ != authorization) {
+ if (authorization_) {
+ AuthorizationFree(authorization_, kAuthorizationFlagDestroyRights);
+ }
+ authorization_ = authorization;
+ }
+ }
+
+ bool operator==(AuthorizationRef that) const {
+ return authorization_ == that;
+ }
+
+ bool operator!=(AuthorizationRef that) const {
+ return authorization_ != that;
+ }
+
+ operator AuthorizationRef() const {
+ return authorization_;
+ }
+
+ AuthorizationRef* operator&() {
+ return &authorization_;
+ }
+
+ AuthorizationRef get() const {
+ return authorization_;
+ }
+
+ void swap(scoped_AuthorizationRef& that) {
+ AuthorizationRef temp = that.authorization_;
+ that.authorization_ = authorization_;
+ authorization_ = temp;
+ }
+
+ // scoped_AuthorizationRef::release() is like scoped_ptr<>::release. It is
+ // NOT a wrapper for AuthorizationFree(). To force a
+ // scoped_AuthorizationRef object to call AuthorizationFree(), use
+ // scoped_AuthorizaitonRef::reset().
+ AuthorizationRef release() WARN_UNUSED_RESULT {
+ AuthorizationRef temp = authorization_;
+ authorization_ = NULL;
+ return temp;
+ }
+
+ private:
+ AuthorizationRef authorization_;
+
+ DISALLOW_COPY_AND_ASSIGN(scoped_AuthorizationRef);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_SCOPED_AUTHORIZATIONREF_H_
diff --git a/chrome/browser/cocoa/search_engine_dialog_controller.h b/chrome/browser/ui/cocoa/search_engine_dialog_controller.h
index 0cc06f2..0cc06f2 100644
--- a/chrome/browser/cocoa/search_engine_dialog_controller.h
+++ b/chrome/browser/ui/cocoa/search_engine_dialog_controller.h
diff --git a/chrome/browser/ui/cocoa/search_engine_dialog_controller.mm b/chrome/browser/ui/cocoa/search_engine_dialog_controller.mm
new file mode 100644
index 0000000..2a79e09
--- /dev/null
+++ b/chrome/browser/ui/cocoa/search_engine_dialog_controller.mm
@@ -0,0 +1,284 @@
+// 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 "chrome/browser/ui/cocoa/search_engine_dialog_controller.h"
+
+#include <algorithm>
+
+#include "app/l10n_util_mac.h"
+#include "app/resource_bundle.h"
+#include "base/mac_util.h"
+#include "base/sys_string_conversions.h"
+#include "base/time.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/search_engines/template_url_model_observer.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
+
+// Horizontal spacing between search engine choices.
+const int kSearchEngineSpacing = 20;
+
+// Vertical spacing between the search engine logo and the button underneath.
+const int kLogoButtonSpacing = 10;
+
+// Width of a label used in place of a logo.
+const int kLogoLabelWidth = 170;
+
+// Height of a label used in place of a logo.
+const int kLogoLabelHeight = 25;
+
+@interface SearchEngineDialogController (Private)
+- (void)onTemplateURLModelChanged;
+- (void)buildSearchEngineView;
+- (NSView*)viewForSearchEngine:(const TemplateURL*)engine
+ atIndex:(size_t)index;
+- (IBAction)searchEngineSelected:(id)sender;
+@end
+
+class SearchEngineDialogControllerBridge :
+ public base::RefCounted<SearchEngineDialogControllerBridge>,
+ public TemplateURLModelObserver {
+ public:
+ SearchEngineDialogControllerBridge(SearchEngineDialogController* controller);
+
+ // TemplateURLModelObserver
+ virtual void OnTemplateURLModelChanged();
+
+ private:
+ SearchEngineDialogController* controller_;
+};
+
+SearchEngineDialogControllerBridge::SearchEngineDialogControllerBridge(
+ SearchEngineDialogController* controller) : controller_(controller) {
+}
+
+void SearchEngineDialogControllerBridge::OnTemplateURLModelChanged() {
+ [controller_ onTemplateURLModelChanged];
+ MessageLoop::current()->QuitNow();
+}
+
+@implementation SearchEngineDialogController
+
+@synthesize profile = profile_;
+@synthesize randomize = randomize_;
+
+- (id)init {
+ NSString* nibpath =
+ [mac_util::MainAppBundle() pathForResource:@"SearchEngineDialog"
+ ofType:@"nib"];
+ self = [super initWithWindowNibPath:nibpath owner:self];
+ if (self != nil) {
+ bridge_ = new SearchEngineDialogControllerBridge(self);
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [super dealloc];
+}
+
+- (IBAction)showWindow:(id)sender {
+ searchEnginesModel_ = profile_->GetTemplateURLModel();
+ searchEnginesModel_->AddObserver(bridge_.get());
+
+ if (searchEnginesModel_->loaded()) {
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(
+ bridge_.get(),
+ &SearchEngineDialogControllerBridge::OnTemplateURLModelChanged));
+ } else {
+ searchEnginesModel_->Load();
+ }
+ MessageLoop::current()->Run();
+}
+
+- (void)onTemplateURLModelChanged {
+ searchEnginesModel_->RemoveObserver(bridge_.get());
+
+ // Add the search engines in the search_engines_model_ to the buttons list.
+ // The first three will always be from prepopulated data.
+ std::vector<const TemplateURL*> templateUrls =
+ searchEnginesModel_->GetTemplateURLs();
+
+ // If we have fewer than two search engines, end the search engine dialog
+ // immediately, leaving the imported default search engine setting intact.
+ if (templateUrls.size() < 2) {
+ return;
+ }
+
+ NSWindow* win = [self window];
+
+ [win setBackgroundColor:[NSColor whiteColor]];
+
+ NSImage* headerImage = ResourceBundle::GetSharedInstance().
+ GetNativeImageNamed(IDR_SEARCH_ENGINE_DIALOG_TOP);
+ [headerImageView_ setImage:headerImage];
+
+ // Is the user's default search engine included in the first three
+ // prepopulated set? If not, we need to expand the dialog to include a fourth
+ // engine.
+ const TemplateURL* defaultSearchEngine =
+ searchEnginesModel_->GetDefaultSearchProvider();
+
+ std::vector<const TemplateURL*>::iterator engineIter =
+ templateUrls.begin();
+ for (int i = 0; engineIter != templateUrls.end(); ++i, ++engineIter) {
+ if (i < 3) {
+ choices_.push_back(*engineIter);
+ } else {
+ if (*engineIter == defaultSearchEngine)
+ choices_.push_back(*engineIter);
+ }
+ }
+
+ // Randomize the order of the logos if the option has been set.
+ if (randomize_) {
+ int seed = static_cast<int>(base::Time::Now().ToInternalValue());
+ srand(seed);
+ std::random_shuffle(choices_.begin(), choices_.end());
+ }
+
+ [self buildSearchEngineView];
+
+ // Display the dialog.
+ NSInteger choice = [NSApp runModalForWindow:win];
+ searchEnginesModel_->SetDefaultSearchProvider(choices_.at(choice));
+}
+
+- (void)buildSearchEngineView {
+ scoped_nsobject<NSMutableArray> searchEngineViews
+ ([[NSMutableArray alloc] init]);
+
+ for (size_t i = 0; i < choices_.size(); ++i)
+ [searchEngineViews addObject:[self viewForSearchEngine:choices_.at(i)
+ atIndex:i]];
+
+ NSSize newOverallSize = NSZeroSize;
+ for (NSView* view in searchEngineViews.get()) {
+ NSRect engineFrame = [view frame];
+ engineFrame.origin = NSMakePoint(newOverallSize.width, 0);
+ [searchEngineView_ addSubview:view];
+ [view setFrame:engineFrame];
+ newOverallSize = NSMakeSize(
+ newOverallSize.width + NSWidth(engineFrame) + kSearchEngineSpacing,
+ std::max(newOverallSize.height, NSHeight(engineFrame)));
+ }
+ newOverallSize.width -= kSearchEngineSpacing;
+
+ // Resize the window to fit (and because it's bound on all sides it will
+ // resize the search engine view).
+ NSSize currentOverallSize = [searchEngineView_ bounds].size;
+ NSSize deltaSize = NSMakeSize(
+ newOverallSize.width - currentOverallSize.width,
+ newOverallSize.height - currentOverallSize.height);
+ NSSize windowDeltaSize = [searchEngineView_ convertSize:deltaSize toView:nil];
+ NSRect windowFrame = [[self window] frame];
+ windowFrame.size.width += windowDeltaSize.width;
+ windowFrame.size.height += windowDeltaSize.height;
+ [[self window] setFrame:windowFrame display:NO];
+}
+
+- (NSView*)viewForSearchEngine:(const TemplateURL*)engine
+ atIndex:(size_t)index {
+ bool useImages = false;
+#if defined(GOOGLE_CHROME_BUILD)
+ useImages = true;
+#endif
+
+ // Make the engine identifier.
+ NSView* engineIdentifier = nil; // either the logo or the text label
+
+ int logoId = engine->logo_id();
+ if (useImages && logoId > 0) {
+ NSImage* logoImage =
+ ResourceBundle::GetSharedInstance().GetNativeImageNamed(logoId);
+ NSRect logoBounds = NSZeroRect;
+ logoBounds.size = [logoImage size];
+ NSImageView* logoView =
+ [[[NSImageView alloc] initWithFrame:logoBounds] autorelease];
+ [logoView setImage:logoImage];
+ [logoView setEditable:NO];
+
+ // Tooltip text provides accessibility.
+ [logoView setToolTip:base::SysWideToNSString(engine->short_name())];
+ engineIdentifier = logoView;
+ } else {
+ // No logo -- we must show a text label.
+ NSRect labelBounds = NSMakeRect(0, 0, kLogoLabelWidth, kLogoLabelHeight);
+ NSTextField* labelField =
+ [[[NSTextField alloc] initWithFrame:labelBounds] autorelease];
+ [labelField setBezeled:NO];
+ [labelField setEditable:NO];
+ [labelField setSelectable:NO];
+
+ scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
+ [[NSMutableParagraphStyle alloc] init]);
+ [paragraphStyle setAlignment:NSCenterTextAlignment];
+ NSDictionary* attrs = [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSFont boldSystemFontOfSize:13], NSFontAttributeName,
+ paragraphStyle.get(), NSParagraphStyleAttributeName,
+ nil];
+
+ NSString* value = base::SysWideToNSString(engine->short_name());
+ scoped_nsobject<NSAttributedString> attrValue(
+ [[NSAttributedString alloc] initWithString:value
+ attributes:attrs]);
+
+ [labelField setAttributedStringValue:attrValue.get()];
+
+ engineIdentifier = labelField;
+ }
+
+ // Make the "Choose" button.
+ scoped_nsobject<NSButton> chooseButton(
+ [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 34)]);
+ [chooseButton setBezelStyle:NSRoundedBezelStyle];
+ [[chooseButton cell] setFont:[NSFont systemFontOfSize:
+ [NSFont systemFontSizeForControlSize:NSRegularControlSize]]];
+ [chooseButton setTitle:l10n_util::GetNSStringWithFixup(IDS_FR_SEARCH_CHOOSE)];
+ [GTMUILocalizerAndLayoutTweaker sizeToFitView:chooseButton.get()];
+ [chooseButton setTag:index];
+ [chooseButton setTarget:self];
+ [chooseButton setAction:@selector(searchEngineSelected:)];
+
+ // Put 'em together.
+ NSRect engineIdentifierFrame = [engineIdentifier frame];
+ NSRect chooseButtonFrame = [chooseButton frame];
+
+ NSRect containingViewFrame = NSZeroRect;
+ containingViewFrame.size.width += engineIdentifierFrame.size.width;
+ containingViewFrame.size.height += engineIdentifierFrame.size.height;
+ containingViewFrame.size.height += kLogoButtonSpacing;
+ containingViewFrame.size.height += chooseButtonFrame.size.height;
+
+ NSView* containingView =
+ [[[NSView alloc] initWithFrame:containingViewFrame] autorelease];
+
+ [containingView addSubview:engineIdentifier];
+ engineIdentifierFrame.origin.y =
+ chooseButtonFrame.size.height + kLogoButtonSpacing;
+ [engineIdentifier setFrame:engineIdentifierFrame];
+
+ [containingView addSubview:chooseButton];
+ chooseButtonFrame.origin.x =
+ int((containingViewFrame.size.width - chooseButtonFrame.size.width) / 2);
+ [chooseButton setFrame:chooseButtonFrame];
+
+ return containingView;
+}
+
+- (NSFont*)mainLabelFont {
+ return [NSFont boldSystemFontOfSize:13];
+}
+
+- (IBAction)searchEngineSelected:(id)sender {
+ [[self window] close];
+ [NSApp stopModalWithCode:[sender tag]];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/search_engine_list_model.h b/chrome/browser/ui/cocoa/search_engine_list_model.h
new file mode 100644
index 0000000..f42fe35
--- /dev/null
+++ b/chrome/browser/ui/cocoa/search_engine_list_model.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_SEARCH_ENGINE_LIST_MODEL_H_
+#define CHROME_BROWSER_UI_COCOA_SEARCH_ENGINE_LIST_MODEL_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+
+class TemplateURLModel;
+class SearchEngineObserver;
+
+// The model for the "default search engine" combobox in preferences. Bridges
+// between the cross-platform TemplateURLModel and Cocoa while watching for
+// changes to the cross-platform model.
+
+@interface SearchEngineListModel : NSObject {
+ @private
+ TemplateURLModel* model_; // weak, owned by Profile
+ scoped_ptr<SearchEngineObserver> observer_; // watches for model changes
+ scoped_nsobject<NSArray> engines_;
+}
+
+// Initialize with the given template model.
+- (id)initWithModel:(TemplateURLModel*)model;
+
+// Returns an array of NSString's corresponding to the user-visible names of the
+// search engines.
+- (NSArray*)searchEngines;
+
+// The index into |-searchEngines| of the current default search engine. If
+// there is no default search engine, the value is -1. The setter changes the
+// back-end preference.
+- (NSInteger)defaultIndex;
+- (void)setDefaultIndex:(NSInteger)index;
+// Return TRUE if the default is managed via policy.
+- (BOOL)isDefaultManaged;
+@end
+
+// Broadcast when the cross-platform model changes. This can be used to update
+// any view state that may rely on the position of items in the list.
+extern NSString* const kSearchEngineListModelChangedNotification;
+
+#endif // CHROME_BROWSER_UI_COCOA_SEARCH_ENGINE_LIST_MODEL_H_
diff --git a/chrome/browser/ui/cocoa/search_engine_list_model.mm b/chrome/browser/ui/cocoa/search_engine_list_model.mm
new file mode 100644
index 0000000..b79c882
--- /dev/null
+++ b/chrome/browser/ui/cocoa/search_engine_list_model.mm
@@ -0,0 +1,136 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/search_engine_list_model.h"
+
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/search_engines/template_url_model_observer.h"
+
+NSString* const kSearchEngineListModelChangedNotification =
+ @"kSearchEngineListModelChangedNotification";
+
+@interface SearchEngineListModel(Private)
+- (void)buildEngineList;
+@end
+
+// C++ bridge from TemplateURLModel to our Obj-C model. When it's told about
+// model changes, notifies us to rebuild the list.
+class SearchEngineObserver : public TemplateURLModelObserver {
+ public:
+ SearchEngineObserver(SearchEngineListModel* notify)
+ : notify_(notify) { }
+ virtual ~SearchEngineObserver() { };
+
+ private:
+ // TemplateURLModelObserver methods.
+ virtual void OnTemplateURLModelChanged() { [notify_ buildEngineList]; }
+
+ SearchEngineListModel* notify_; // weak, owns us
+};
+
+@implementation SearchEngineListModel
+
+// The windows code allows for a NULL |model| and checks for it throughout
+// the code, though I'm not sure why. We follow suit.
+- (id)initWithModel:(TemplateURLModel*)model {
+ if ((self = [super init])) {
+ model_ = model;
+ if (model_) {
+ observer_.reset(new SearchEngineObserver(self));
+ model_->Load();
+ model_->AddObserver(observer_.get());
+ [self buildEngineList];
+ }
+ }
+ return self;
+}
+
+- (void)dealloc {
+ if (model_)
+ model_->RemoveObserver(observer_.get());
+ [super dealloc];
+}
+
+// Returns an array of NSString's corresponding to the user-visible names of the
+// search engines.
+- (NSArray*)searchEngines {
+ return engines_.get();
+}
+
+- (void)setSearchEngines:(NSArray*)engines {
+ engines_.reset([engines retain]);
+
+ // Tell anyone who's listening that something has changed so they need to
+ // adjust the UI.
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName:kSearchEngineListModelChangedNotification
+ object:nil];
+}
+
+// Walks the model and builds an array of NSStrings to display to the user.
+// Assumes there is a non-NULL model.
+- (void)buildEngineList {
+ scoped_nsobject<NSMutableArray> engines([[NSMutableArray alloc] init]);
+
+ typedef std::vector<const TemplateURL*> TemplateURLs;
+ TemplateURLs modelURLs = model_->GetTemplateURLs();
+ for (size_t i = 0; i < modelURLs.size(); ++i) {
+ if (modelURLs[i]->ShowInDefaultList())
+ [engines addObject:base::SysWideToNSString(modelURLs[i]->short_name())];
+ }
+
+ [self setSearchEngines:engines.get()];
+}
+
+// The index into |-searchEngines| of the current default search engine.
+// -1 if there is no default.
+- (NSInteger)defaultIndex {
+ if (!model_) return -1;
+
+ NSInteger index = 0;
+ const TemplateURL* defaultSearchProvider = model_->GetDefaultSearchProvider();
+ if (defaultSearchProvider) {
+ typedef std::vector<const TemplateURL*> TemplateURLs;
+ TemplateURLs urls = model_->GetTemplateURLs();
+ for (std::vector<const TemplateURL*>::iterator it = urls.begin();
+ it != urls.end(); ++it) {
+ const TemplateURL* url = *it;
+ // Skip all the URLs not shown on the default list.
+ if (!url->ShowInDefaultList())
+ continue;
+ if (url->id() == defaultSearchProvider->id())
+ return index;
+ ++index;
+ }
+ }
+ return -1;
+}
+
+- (void)setDefaultIndex:(NSInteger)index {
+ if (model_) {
+ typedef std::vector<const TemplateURL*> TemplateURLs;
+ TemplateURLs urls = model_->GetTemplateURLs();
+ for (std::vector<const TemplateURL*>::iterator it = urls.begin();
+ it != urls.end(); ++it) {
+ const TemplateURL* url = *it;
+ // Skip all the URLs not shown on the default list.
+ if (!url->ShowInDefaultList())
+ continue;
+ if (0 == index) {
+ model_->SetDefaultSearchProvider(url);
+ return;
+ }
+ --index;
+ }
+ DCHECK(false);
+ }
+}
+
+// Return TRUE if the default is managed via policy.
+- (BOOL)isDefaultManaged {
+ return model_->is_default_search_managed();
+}
+@end
diff --git a/chrome/browser/ui/cocoa/search_engine_list_model_unittest.mm b/chrome/browser/ui/cocoa/search_engine_list_model_unittest.mm
new file mode 100644
index 0000000..a59bcec
--- /dev/null
+++ b/chrome/browser/ui/cocoa/search_engine_list_model_unittest.mm
@@ -0,0 +1,152 @@
+// Copyright (c) 2009 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/scoped_nsobject.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/search_engine_list_model.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+// A helper for NSNotifications. Makes a note that it's been called back.
+@interface SearchEngineListHelper : NSObject {
+ @public
+ BOOL sawNotification_;
+}
+@end
+
+@implementation SearchEngineListHelper
+- (void)entryChanged:(NSNotification*)notify {
+ sawNotification_ = YES;
+}
+@end
+
+class SearchEngineListModelTest : public PlatformTest {
+ public:
+ SearchEngineListModelTest() {
+ // Build a fake set of template urls.
+ template_model_.reset(new TemplateURLModel(helper_.profile()));
+ TemplateURL* t_url = new TemplateURL();
+ t_url->SetURL("http://www.google.com/?q={searchTerms}", 0, 0);
+ t_url->set_keyword(L"keyword");
+ t_url->set_short_name(L"google");
+ t_url->set_show_in_default_list(true);
+ template_model_->Add(t_url);
+ t_url = new TemplateURL();
+ t_url->SetURL("http://www.google2.com/?q={searchTerms}", 0, 0);
+ t_url->set_keyword(L"keyword2");
+ t_url->set_short_name(L"google2");
+ t_url->set_show_in_default_list(true);
+ template_model_->Add(t_url);
+ EXPECT_EQ(template_model_->GetTemplateURLs().size(), 2U);
+
+ model_.reset([[SearchEngineListModel alloc]
+ initWithModel:template_model_.get()]);
+ notification_helper_.reset([[SearchEngineListHelper alloc] init]);
+ [[NSNotificationCenter defaultCenter]
+ addObserver:notification_helper_.get()
+ selector:@selector(entryChanged:)
+ name:kSearchEngineListModelChangedNotification
+ object:nil];
+ }
+ ~SearchEngineListModelTest() {
+ [[NSNotificationCenter defaultCenter]
+ removeObserver:notification_helper_.get()];
+ }
+
+ BrowserTestHelper helper_;
+ scoped_ptr<TemplateURLModel> template_model_;
+ scoped_nsobject<SearchEngineListModel> model_;
+ scoped_nsobject<SearchEngineListHelper> notification_helper_;
+};
+
+TEST_F(SearchEngineListModelTest, Init) {
+ scoped_nsobject<SearchEngineListModel> model(
+ [[SearchEngineListModel alloc] initWithModel:template_model_.get()]);
+}
+
+TEST_F(SearchEngineListModelTest, Engines) {
+ NSArray* engines = [model_ searchEngines];
+ EXPECT_EQ([engines count], 2U);
+}
+
+TEST_F(SearchEngineListModelTest, Default) {
+ EXPECT_EQ([model_ defaultIndex], -1);
+
+ [model_ setDefaultIndex:1];
+ EXPECT_EQ([model_ defaultIndex], 1);
+
+ // Add two more URLs, neither of which are shown in the default list.
+ TemplateURL* t_url = new TemplateURL();
+ t_url->SetURL("http://www.google3.com/?q={searchTerms}", 0, 0);
+ t_url->set_keyword(L"keyword3");
+ t_url->set_short_name(L"google3 not eligible");
+ t_url->set_show_in_default_list(false);
+ template_model_->Add(t_url);
+ t_url = new TemplateURL();
+ t_url->SetURL("http://www.google4.com/?q={searchTerms}", 0, 0);
+ t_url->set_keyword(L"keyword4");
+ t_url->set_short_name(L"google4");
+ t_url->set_show_in_default_list(false);
+ template_model_->Add(t_url);
+
+ // Still should only have 2 engines and not these newly added ones.
+ EXPECT_EQ([[model_ searchEngines] count], 2U);
+
+ // Since keyword3 is not in the default list, the 2nd index in the default
+ // keyword list should be keyword4. Test for http://crbug.com/21898.
+ template_model_->SetDefaultSearchProvider(t_url);
+ EXPECT_EQ([[model_ searchEngines] count], 3U);
+ EXPECT_EQ([model_ defaultIndex], 2);
+
+ NSString* defaultString = [[model_ searchEngines] objectAtIndex:2];
+ EXPECT_NSEQ(@"google4", defaultString);
+}
+
+TEST_F(SearchEngineListModelTest, DefaultChosenFromUI) {
+ EXPECT_EQ([model_ defaultIndex], -1);
+
+ [model_ setDefaultIndex:1];
+ EXPECT_EQ([model_ defaultIndex], 1);
+
+ // Add two more URLs, the first one not shown in the default list.
+ TemplateURL* t_url = new TemplateURL();
+ t_url->SetURL("http://www.google3.com/?q={searchTerms}", 0, 0);
+ t_url->set_keyword(L"keyword3");
+ t_url->set_short_name(L"google3 not eligible");
+ t_url->set_show_in_default_list(false);
+ template_model_->Add(t_url);
+ t_url = new TemplateURL();
+ t_url->SetURL("http://www.google4.com/?q={searchTerms}", 0, 0);
+ t_url->set_keyword(L"keyword4");
+ t_url->set_short_name(L"google4");
+ t_url->set_show_in_default_list(true);
+ template_model_->Add(t_url);
+
+ // We should have 3 engines.
+ EXPECT_EQ([[model_ searchEngines] count], 3U);
+
+ // Simulate the UI setting the default to the third entry.
+ [model_ setDefaultIndex:2];
+ EXPECT_EQ([model_ defaultIndex], 2);
+
+ // The default search provider should be google4.
+ EXPECT_EQ(template_model_->GetDefaultSearchProvider(), t_url);
+}
+
+// Make sure that when the back-end model changes that we get a notification.
+TEST_F(SearchEngineListModelTest, Notification) {
+ // Add one more item to force a notification.
+ TemplateURL* t_url = new TemplateURL();
+ t_url->SetURL("http://www.google3.com/foo/bar", 0, 0);
+ t_url->set_keyword(L"keyword3");
+ t_url->set_short_name(L"google3");
+ t_url->set_show_in_default_list(true);
+ template_model_->Add(t_url);
+
+ EXPECT_TRUE(notification_helper_.get()->sawNotification_);
+}
diff --git a/chrome/browser/ui/cocoa/shell_dialogs_mac.mm b/chrome/browser/ui/cocoa/shell_dialogs_mac.mm
new file mode 100644
index 0000000..257bb62
--- /dev/null
+++ b/chrome/browser/ui/cocoa/shell_dialogs_mac.mm
@@ -0,0 +1,417 @@
+// 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.
+
+#include "chrome/browser/shell_dialogs.h"
+
+#import <Cocoa/Cocoa.h>
+#include <CoreServices/CoreServices.h>
+
+#include <map>
+#include <set>
+#include <vector>
+
+#include "app/l10n_util_mac.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#import "base/mac/cocoa_protocols.h"
+#include "base/mac_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#import "base/scoped_nsobject.h"
+#include "base/sys_string_conversions.h"
+#include "base/thread_restrictions.h"
+#include "grit/generated_resources.h"
+
+static const int kFileTypePopupTag = 1234;
+
+class SelectFileDialogImpl;
+
+// A bridge class to act as the modal delegate to the save/open sheet and send
+// the results to the C++ class.
+@interface SelectFileDialogBridge : NSObject<NSOpenSavePanelDelegate> {
+ @private
+ SelectFileDialogImpl* selectFileDialogImpl_; // WEAK; owns us
+}
+
+- (id)initWithSelectFileDialogImpl:(SelectFileDialogImpl*)s;
+- (void)endedPanel:(NSSavePanel*)panel
+ withReturn:(int)returnCode
+ context:(void *)context;
+
+// NSSavePanel delegate method
+- (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename;
+
+@end
+
+// Implementation of SelectFileDialog that shows Cocoa dialogs for choosing a
+// file or folder.
+class SelectFileDialogImpl : public SelectFileDialog {
+ public:
+ explicit SelectFileDialogImpl(Listener* listener);
+ virtual ~SelectFileDialogImpl();
+
+ // BaseShellDialog implementation.
+ virtual bool IsRunning(gfx::NativeWindow parent_window) const;
+ virtual void ListenerDestroyed();
+
+ // SelectFileDialog implementation.
+ // |params| is user data we pass back via the Listener interface.
+ virtual void SelectFile(Type type,
+ const string16& title,
+ const FilePath& default_path,
+ const FileTypeInfo* file_types,
+ int file_type_index,
+ const FilePath::StringType& default_extension,
+ gfx::NativeWindow owning_window,
+ void* params);
+
+ // Callback from ObjC bridge.
+ void FileWasSelected(NSSavePanel* dialog,
+ NSWindow* parent_window,
+ bool was_cancelled,
+ bool is_multi,
+ const std::vector<FilePath>& files,
+ int index);
+
+ bool ShouldEnableFilename(NSSavePanel* dialog, NSString* filename);
+
+ struct SheetContext {
+ Type type;
+ NSWindow* owning_window;
+ };
+
+ private:
+ // Gets the accessory view for the save dialog.
+ NSView* GetAccessoryView(const FileTypeInfo* file_types,
+ int file_type_index);
+
+ // The listener to be notified of selection completion.
+ Listener* listener_;
+
+ // The bridge for results from Cocoa to return to us.
+ scoped_nsobject<SelectFileDialogBridge> bridge_;
+
+ // A map from file dialogs to the |params| user data associated with them.
+ std::map<NSSavePanel*, void*> params_map_;
+
+ // The set of all parent windows for which we are currently running dialogs.
+ std::set<NSWindow*> parents_;
+
+ // A map from file dialogs to their types.
+ std::map<NSSavePanel*, Type> type_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(SelectFileDialogImpl);
+};
+
+// static
+SelectFileDialog* SelectFileDialog::Create(Listener* listener) {
+ return new SelectFileDialogImpl(listener);
+}
+
+SelectFileDialogImpl::SelectFileDialogImpl(Listener* listener)
+ : listener_(listener),
+ bridge_([[SelectFileDialogBridge alloc]
+ initWithSelectFileDialogImpl:this]) {
+}
+
+SelectFileDialogImpl::~SelectFileDialogImpl() {
+ // Walk through the open dialogs and close them all. Use a temporary vector
+ // to hold the pointers, since we can't delete from the map as we're iterating
+ // through it.
+ std::vector<NSSavePanel*> panels;
+ for (std::map<NSSavePanel*, void*>::iterator it = params_map_.begin();
+ it != params_map_.end(); ++it) {
+ panels.push_back(it->first);
+ }
+
+ for (std::vector<NSSavePanel*>::iterator it = panels.begin();
+ it != panels.end(); ++it) {
+ [(*it) cancel:nil];
+ }
+}
+
+bool SelectFileDialogImpl::IsRunning(gfx::NativeWindow parent_window) const {
+ return parents_.find(parent_window) != parents_.end();
+}
+
+void SelectFileDialogImpl::ListenerDestroyed() {
+ listener_ = NULL;
+}
+
+void SelectFileDialogImpl::SelectFile(
+ Type type,
+ const string16& title,
+ const FilePath& default_path,
+ const FileTypeInfo* file_types,
+ int file_type_index,
+ const FilePath::StringType& default_extension,
+ gfx::NativeWindow owning_window,
+ void* params) {
+ DCHECK(type == SELECT_FOLDER ||
+ type == SELECT_OPEN_FILE ||
+ type == SELECT_OPEN_MULTI_FILE ||
+ type == SELECT_SAVEAS_FILE);
+ parents_.insert(owning_window);
+
+ // Note: we need to retain the dialog as owning_window can be null.
+ // (see http://crbug.com/29213)
+ NSSavePanel* dialog;
+ if (type == SELECT_SAVEAS_FILE)
+ dialog = [[NSSavePanel savePanel] retain];
+ else
+ dialog = [[NSOpenPanel openPanel] retain];
+
+ if (!title.empty())
+ [dialog setTitle:base::SysUTF16ToNSString(title)];
+
+ NSString* default_dir = nil;
+ NSString* default_filename = nil;
+ if (!default_path.empty()) {
+ // The file dialog is going to do a ton of stats anyway. Not much
+ // point in eliminating this one.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+ if (file_util::DirectoryExists(default_path)) {
+ default_dir = base::SysUTF8ToNSString(default_path.value());
+ } else {
+ default_dir = base::SysUTF8ToNSString(default_path.DirName().value());
+ default_filename =
+ base::SysUTF8ToNSString(default_path.BaseName().value());
+ }
+ }
+
+ NSMutableArray* allowed_file_types = nil;
+ if (file_types) {
+ if (!file_types->extensions.empty()) {
+ allowed_file_types = [NSMutableArray array];
+ for (size_t i=0; i < file_types->extensions.size(); ++i) {
+ const std::vector<FilePath::StringType>& ext_list =
+ file_types->extensions[i];
+ for (size_t j=0; j < ext_list.size(); ++j) {
+ [allowed_file_types addObject:base::SysUTF8ToNSString(ext_list[j])];
+ }
+ }
+ }
+ if (type == SELECT_SAVEAS_FILE)
+ [dialog setAllowedFileTypes:allowed_file_types];
+ // else we'll pass it in when we run the open panel
+
+ if (file_types->include_all_files)
+ [dialog setAllowsOtherFileTypes:YES];
+
+ if (!file_types->extension_description_overrides.empty()) {
+ NSView* accessory_view = GetAccessoryView(file_types, file_type_index);
+ [dialog setAccessoryView:accessory_view];
+ }
+ } else {
+ // If no type info is specified, anything goes.
+ [dialog setAllowsOtherFileTypes:YES];
+ }
+
+ if (!default_extension.empty())
+ [dialog setRequiredFileType:base::SysUTF8ToNSString(default_extension)];
+
+ params_map_[dialog] = params;
+ type_map_[dialog] = type;
+
+ SheetContext* context = new SheetContext;
+
+ // |context| should never be NULL, but we are seeing indications otherwise.
+ // |This CHECK is here to confirm if we are actually getting NULL
+ // ||context|s. http://crbug.com/58959
+ CHECK(context);
+ context->type = type;
+ context->owning_window = owning_window;
+
+ if (type == SELECT_SAVEAS_FILE) {
+ [dialog beginSheetForDirectory:default_dir
+ file:default_filename
+ modalForWindow:owning_window
+ modalDelegate:bridge_.get()
+ didEndSelector:@selector(endedPanel:withReturn:context:)
+ contextInfo:context];
+ } else {
+ NSOpenPanel* open_dialog = (NSOpenPanel*)dialog;
+
+ if (type == SELECT_OPEN_MULTI_FILE)
+ [open_dialog setAllowsMultipleSelection:YES];
+ else
+ [open_dialog setAllowsMultipleSelection:NO];
+
+ if (type == SELECT_FOLDER) {
+ [open_dialog setCanChooseFiles:NO];
+ [open_dialog setCanChooseDirectories:YES];
+ [open_dialog setCanCreateDirectories:YES];
+ NSString *prompt = l10n_util::GetNSString(IDS_SELECT_FOLDER_BUTTON_TITLE);
+ [open_dialog setPrompt:prompt];
+ } else {
+ [open_dialog setCanChooseFiles:YES];
+ [open_dialog setCanChooseDirectories:NO];
+ }
+
+ [open_dialog setDelegate:bridge_.get()];
+ [open_dialog beginSheetForDirectory:default_dir
+ file:default_filename
+ types:allowed_file_types
+ modalForWindow:owning_window
+ modalDelegate:bridge_.get()
+ didEndSelector:@selector(endedPanel:withReturn:context:)
+ contextInfo:context];
+ }
+}
+
+void SelectFileDialogImpl::FileWasSelected(NSSavePanel* dialog,
+ NSWindow* parent_window,
+ bool was_cancelled,
+ bool is_multi,
+ const std::vector<FilePath>& files,
+ int index) {
+ void* params = params_map_[dialog];
+ params_map_.erase(dialog);
+ parents_.erase(parent_window);
+ type_map_.erase(dialog);
+
+ if (!listener_)
+ return;
+
+ if (was_cancelled) {
+ listener_->FileSelectionCanceled(params);
+ } else {
+ if (is_multi) {
+ listener_->MultiFilesSelected(files, params);
+ } else {
+ listener_->FileSelected(files[0], index, params);
+ }
+ }
+}
+
+NSView* SelectFileDialogImpl::GetAccessoryView(const FileTypeInfo* file_types,
+ int file_type_index) {
+ DCHECK(file_types);
+ scoped_nsobject<NSNib> nib (
+ [[NSNib alloc] initWithNibNamed:@"SaveAccessoryView"
+ bundle:mac_util::MainAppBundle()]);
+ if (!nib)
+ return nil;
+
+ NSArray* objects;
+ BOOL success = [nib instantiateNibWithOwner:nil
+ topLevelObjects:&objects];
+ if (!success)
+ return nil;
+ [objects makeObjectsPerformSelector:@selector(release)];
+
+ // This is a one-object nib, but IB insists on creating a second object, the
+ // NSApplication. I don't know why.
+ size_t view_index = 0;
+ while (view_index < [objects count] &&
+ ![[objects objectAtIndex:view_index] isKindOfClass:[NSView class]])
+ ++view_index;
+ DCHECK(view_index < [objects count]);
+ NSView* accessory_view = [objects objectAtIndex:view_index];
+
+ NSPopUpButton* popup = [accessory_view viewWithTag:kFileTypePopupTag];
+ DCHECK(popup);
+
+ size_t type_count = file_types->extensions.size();
+ for (size_t type = 0; type<type_count; ++type) {
+ NSString* type_description;
+ if (type < file_types->extension_description_overrides.size()) {
+ type_description = base::SysUTF16ToNSString(
+ file_types->extension_description_overrides[type]);
+ } else {
+ const std::vector<FilePath::StringType>& ext_list =
+ file_types->extensions[type];
+ DCHECK(!ext_list.empty());
+ NSString* type_extension = base::SysUTF8ToNSString(ext_list[0]);
+ base::mac::ScopedCFTypeRef<CFStringRef> uti(
+ UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension,
+ (CFStringRef)type_extension,
+ NULL));
+ base::mac::ScopedCFTypeRef<CFStringRef> description(
+ UTTypeCopyDescription(uti.get()));
+
+ type_description =
+ [NSString stringWithString:(NSString*)description.get()];
+ }
+ [popup addItemWithTitle:type_description];
+ }
+
+ [popup selectItemAtIndex:file_type_index-1]; // 1-based
+ return accessory_view;
+}
+
+bool SelectFileDialogImpl::ShouldEnableFilename(NSSavePanel* dialog,
+ NSString* filename) {
+ // If this is a single open file dialog, disable selecting packages.
+ if (type_map_[dialog] != SELECT_OPEN_FILE)
+ return true;
+
+ return ![[NSWorkspace sharedWorkspace] isFilePackageAtPath:filename];
+}
+
+@implementation SelectFileDialogBridge
+
+- (id)initWithSelectFileDialogImpl:(SelectFileDialogImpl*)s {
+ self = [super init];
+ if (self != nil) {
+ selectFileDialogImpl_ = s;
+ }
+ return self;
+}
+
+- (void)endedPanel:(NSSavePanel*)panel
+ withReturn:(int)returnCode
+ context:(void *)context {
+ // |context| should never be NULL, but we are seeing indications otherwise.
+ // |This CHECK is here to confirm if we are actually getting NULL
+ // ||context|s. http://crbug.com/58959
+ CHECK(context);
+
+ int index = 0;
+ SelectFileDialogImpl::SheetContext* context_struct =
+ (SelectFileDialogImpl::SheetContext*)context;
+
+ SelectFileDialog::Type type = context_struct->type;
+ NSWindow* parentWindow = context_struct->owning_window;
+ delete context_struct;
+
+ bool isMulti = type == SelectFileDialog::SELECT_OPEN_MULTI_FILE;
+
+ std::vector<FilePath> paths;
+ bool did_cancel = returnCode == NSCancelButton;
+ if (!did_cancel) {
+ if (type == SelectFileDialog::SELECT_SAVEAS_FILE) {
+ paths.push_back(FilePath(base::SysNSStringToUTF8([panel filename])));
+
+ NSView* accessoryView = [panel accessoryView];
+ if (accessoryView) {
+ NSPopUpButton* popup = [accessoryView viewWithTag:kFileTypePopupTag];
+ if (popup) {
+ // File type indexes are 1-based.
+ index = [popup indexOfSelectedItem] + 1;
+ }
+ } else {
+ index = 1;
+ }
+ } else {
+ CHECK([panel isKindOfClass:[NSOpenPanel class]]);
+ NSArray* filenames = [static_cast<NSOpenPanel*>(panel) filenames];
+ for (NSString* filename in filenames)
+ paths.push_back(FilePath(base::SysNSStringToUTF8(filename)));
+ }
+ }
+
+ selectFileDialogImpl_->FileWasSelected(panel,
+ parentWindow,
+ did_cancel,
+ isMulti,
+ paths,
+ index);
+ [panel release];
+}
+
+- (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename {
+ return selectFileDialogImpl_->ShouldEnableFilename(sender, filename);
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/side_tab_strip_controller.h b/chrome/browser/ui/cocoa/side_tab_strip_controller.h
new file mode 100644
index 0000000..07f5551
--- /dev/null
+++ b/chrome/browser/ui/cocoa/side_tab_strip_controller.h
@@ -0,0 +1,19 @@
+// 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>
+
+#import "chrome/browser/ui/cocoa/tab_strip_controller.h"
+
+// A controller for the tab strip when side tabs are enabled.
+//
+// TODO(pinkerton): I'm expecting there are more things here that need
+// overriding rather than just tweaking a couple of settings, so I'm creating
+// a full-blown subclass. Clearly, very little is actually necessary at this
+// point for it to work.
+
+@interface SideTabStripController : TabStripController {
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/side_tab_strip_controller.mm b/chrome/browser/ui/cocoa/side_tab_strip_controller.mm
new file mode 100644
index 0000000..16a835f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/side_tab_strip_controller.mm
@@ -0,0 +1,33 @@
+// 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 "chrome/browser/ui/cocoa/side_tab_strip_controller.h"
+
+@implementation SideTabStripController
+
+// TODO(pinkerton): Still need to figure out several things:
+// - new tab button placement and layout
+// - animating tabs in and out
+// - being able to drop a tab elsewhere besides the 1st position
+// - how to load a different tab view nib for each tab.
+
+- (id)initWithView:(TabStripView*)view
+ switchView:(NSView*)switchView
+ browser:(Browser*)browser
+ delegate:(id<TabStripControllerDelegate>)delegate {
+ self = [super initWithView:view
+ switchView:switchView
+ browser:browser
+ delegate:delegate];
+ if (self) {
+ // Side tabs have no indent since they are not sharing space with the
+ // window controls.
+ [self setIndentForControls:0.0];
+ verticalLayout_ = YES;
+ }
+ return self;
+}
+
+@end
+
diff --git a/chrome/browser/ui/cocoa/side_tab_strip_view.h b/chrome/browser/ui/cocoa/side_tab_strip_view.h
new file mode 100644
index 0000000..9f8d056
--- /dev/null
+++ b/chrome/browser/ui/cocoa/side_tab_strip_view.h
@@ -0,0 +1,15 @@
+// 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>
+
+#import "chrome/browser/ui/cocoa/tab_strip_view.h"
+
+// A class that handles drawing the background of the tab strip when side tabs
+// are enabled.
+
+@interface SideTabStripView : TabStripView {
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/side_tab_strip_view.mm b/chrome/browser/ui/cocoa/side_tab_strip_view.mm
new file mode 100644
index 0000000..2c60604
--- /dev/null
+++ b/chrome/browser/ui/cocoa/side_tab_strip_view.mm
@@ -0,0 +1,43 @@
+// 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 "chrome/browser/ui/cocoa/side_tab_strip_view.h"
+
+#include "base/scoped_nsobject.h"
+#import "third_party/GTM/AppKit/GTMNSColor+Luminance.h"
+
+@implementation SideTabStripView
+
+- (void)drawBorder:(NSRect)bounds {
+ // Draw a border on the right side.
+ NSRect borderRect, contentRect;
+ NSDivideRect(bounds, &borderRect, &contentRect, 1, NSMaxXEdge);
+ [[NSColor colorWithCalibratedWhite:0.0 alpha:0.2] set];
+ NSRectFillUsingOperation(borderRect, NSCompositeSourceOver);
+}
+
+// Override to prevent double-clicks from minimizing the window. The side
+// tab strip doesn't have that behavior (since it's in the window content
+// area).
+- (BOOL)doubleClickMinimizesWindow {
+ return NO;
+}
+
+- (void)drawRect:(NSRect)rect {
+ // BOOL isKey = [[self window] isKeyWindow];
+ NSColor* aColor =
+ [NSColor colorWithCalibratedRed:0.506 green:0.660 blue:0.985 alpha:1.000];
+ NSColor* bColor =
+ [NSColor colorWithCalibratedRed:0.099 green:0.140 blue:0.254 alpha:1.000];
+ scoped_nsobject<NSGradient> gradient(
+ [[NSGradient alloc] initWithStartingColor:aColor endingColor:bColor]);
+
+ NSRect gradientRect = [self bounds];
+ [gradient drawInRect:gradientRect angle:270.0];
+
+ // Draw borders and any drop feedback.
+ [super drawRect:rect];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/side_tab_strip_view_unittest.mm b/chrome/browser/ui/cocoa/side_tab_strip_view_unittest.mm
new file mode 100644
index 0000000..ba7acc2
--- /dev/null
+++ b/chrome/browser/ui/cocoa/side_tab_strip_view_unittest.mm
@@ -0,0 +1,30 @@
+// 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 "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/side_tab_strip_view.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class SideTabStripViewTest : public CocoaTest {
+ public:
+ SideTabStripViewTest() {
+ NSRect frame = NSMakeRect(0, 0, 100, 30);
+ scoped_nsobject<SideTabStripView> view(
+ [[SideTabStripView alloc] initWithFrame:frame]);
+ view_ = view.get();
+ [[test_window() contentView] addSubview:view_];
+ }
+
+ SideTabStripView* view_;
+};
+
+TEST_VIEW(SideTabStripViewTest, view_)
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/sidebar_controller.h b/chrome/browser/ui/cocoa/sidebar_controller.h
new file mode 100644
index 0000000..dcafddb
--- /dev/null
+++ b/chrome/browser/ui/cocoa/sidebar_controller.h
@@ -0,0 +1,51 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_SIDEBAR_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_SIDEBAR_CONTROLLER_H_
+#pragma once
+
+#import <Foundation/Foundation.h>
+
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/tab_contents_controller.h"
+
+@class NSSplitView;
+@class NSView;
+
+class TabContents;
+
+// A class that handles updates of the sidebar view within a browser window.
+// It swaps in the relevant sidebar contents for a given TabContents or removes
+// the vew, if there's no sidebar contents to show.
+@interface SidebarController : NSObject {
+ @private
+ // A view hosting sidebar contents.
+ scoped_nsobject<NSSplitView> splitView_;
+
+ // Manages currently displayed sidebar contents.
+ scoped_nsobject<TabContentsController> contentsController_;
+}
+
+- (id)initWithDelegate:(id<TabContentsControllerDelegate>)delegate;
+
+// This controller's view.
+- (NSSplitView*)view;
+
+// The compiler seems to have trouble handling a function named "view" that
+// returns an NSSplitView, so provide a differently-named method.
+- (NSSplitView*)splitView;
+
+// Depending on |contents|'s state, decides whether the sidebar
+// should be shown or hidden and adjusts its width (|delegate_| handles
+// the actual resize).
+- (void)updateSidebarForTabContents:(TabContents*)contents;
+
+// Call when the sidebar view is properly sized and the render widget host view
+// should be put into the view hierarchy.
+- (void)ensureContentsVisible;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_SIDEBAR_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/sidebar_controller.mm b/chrome/browser/ui/cocoa/sidebar_controller.mm
new file mode 100644
index 0000000..f20deaa
--- /dev/null
+++ b/chrome/browser/ui/cocoa/sidebar_controller.mm
@@ -0,0 +1,179 @@
+// 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 "chrome/browser/ui/cocoa/sidebar_controller.h"
+
+#include <algorithm>
+
+#include <Cocoa/Cocoa.h>
+
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/sidebar/sidebar_manager.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/browser.h"
+#import "chrome/browser/ui/cocoa/view_id_util.h"
+#include "chrome/common/pref_names.h"
+
+namespace {
+
+// By default sidebar width is 1/7th of the current page content width.
+const CGFloat kDefaultSidebarWidthRatio = 1.0 / 7;
+
+// Never make the web part of the tab contents smaller than this (needed if the
+// window is only a few pixels wide).
+const int kMinWebWidth = 50;
+
+} // end namespace
+
+
+@interface SidebarController (Private)
+- (void)showSidebarContents:(TabContents*)sidebarContents;
+- (void)resizeSidebarToNewWidth:(CGFloat)width;
+@end
+
+
+@implementation SidebarController
+
+- (id)initWithDelegate:(id<TabContentsControllerDelegate>)delegate {
+ if ((self = [super init])) {
+ splitView_.reset([[NSSplitView alloc] initWithFrame:NSZeroRect]);
+ [splitView_ setDividerStyle:NSSplitViewDividerStyleThin];
+ [splitView_ setVertical:YES];
+ [splitView_ setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
+ [splitView_ setDelegate:self];
+
+ contentsController_.reset(
+ [[TabContentsController alloc] initWithContents:NULL
+ delegate:delegate]);
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [splitView_ setDelegate:nil];
+ [super dealloc];
+}
+
+- (NSSplitView*)view {
+ return splitView_.get();
+}
+
+- (NSSplitView*)splitView {
+ return splitView_.get();
+}
+
+- (void)updateSidebarForTabContents:(TabContents*)contents {
+ // Get the active sidebar content.
+ if (SidebarManager::GetInstance() == NULL) // Happens in tests.
+ return;
+
+ TabContents* sidebarContents = NULL;
+ if (contents && SidebarManager::IsSidebarAllowed()) {
+ SidebarContainer* activeSidebar =
+ SidebarManager::GetInstance()->GetActiveSidebarContainerFor(contents);
+ if (activeSidebar)
+ sidebarContents = activeSidebar->sidebar_contents();
+ }
+
+ TabContents* oldSidebarContents = [contentsController_ tabContents];
+ if (oldSidebarContents == sidebarContents)
+ return;
+
+ // Adjust sidebar view.
+ [self showSidebarContents:sidebarContents];
+
+ // Notify extensions.
+ SidebarManager::GetInstance()->NotifyStateChanges(
+ oldSidebarContents, sidebarContents);
+}
+
+- (void)ensureContentsVisible {
+ [contentsController_ ensureContentsVisible];
+}
+
+- (void)showSidebarContents:(TabContents*)sidebarContents {
+ [contentsController_ ensureContentsSizeDoesNotChange];
+
+ NSArray* subviews = [splitView_ subviews];
+ if (sidebarContents) {
+ DCHECK_GE([subviews count], 1u);
+
+ // Native view is a TabContentsViewCocoa object, whose ViewID was
+ // set to VIEW_ID_TAB_CONTAINER initially, so change it to
+ // VIEW_ID_SIDE_BAR_CONTAINER here.
+ view_id_util::SetID(
+ sidebarContents->GetNativeView(), VIEW_ID_SIDE_BAR_CONTAINER);
+
+ CGFloat sidebarWidth = 0;
+ if ([subviews count] == 1) {
+ // Load the default split offset.
+ sidebarWidth = g_browser_process->local_state()->GetInteger(
+ prefs::kExtensionSidebarWidth);
+ if (sidebarWidth < 0) {
+ // Initial load, set to default value.
+ sidebarWidth =
+ NSWidth([splitView_ frame]) * kDefaultSidebarWidthRatio;
+ }
+ [splitView_ addSubview:[contentsController_ view]];
+ } else {
+ DCHECK_EQ([subviews count], 2u);
+ sidebarWidth = NSWidth([[subviews objectAtIndex:1] frame]);
+ }
+
+ // Make sure |sidebarWidth| isn't too large or too small.
+ sidebarWidth = std::min(sidebarWidth,
+ NSWidth([splitView_ frame]) - kMinWebWidth);
+ DCHECK_GE(sidebarWidth, 0) << "kMinWebWidth needs to be smaller than "
+ << "smallest available tab contents space.";
+ sidebarWidth = std::max(static_cast<CGFloat>(0), sidebarWidth);
+
+ [self resizeSidebarToNewWidth:sidebarWidth];
+ } else {
+ if ([subviews count] > 1) {
+ NSView* oldSidebarContentsView = [subviews objectAtIndex:1];
+ // Store split offset when hiding sidebar window only.
+ int sidebarWidth = NSWidth([oldSidebarContentsView frame]);
+ g_browser_process->local_state()->SetInteger(
+ prefs::kExtensionSidebarWidth, sidebarWidth);
+ [oldSidebarContentsView removeFromSuperview];
+ [splitView_ adjustSubviews];
+ }
+ }
+
+ [contentsController_ changeTabContents:sidebarContents];
+}
+
+- (void)resizeSidebarToNewWidth:(CGFloat)width {
+ NSArray* subviews = [splitView_ subviews];
+
+ // It seems as if |-setPosition:ofDividerAtIndex:| should do what's needed,
+ // but I can't figure out how to use it. Manually resize web and sidebar.
+ // TODO(alekseys): either make setPosition:ofDividerAtIndex: work or to add a
+ // category on NSSplitView to handle manual resizing.
+ NSView* sidebarView = [subviews objectAtIndex:1];
+ NSRect sidebarFrame = [sidebarView frame];
+ sidebarFrame.size.width = width;
+ [sidebarView setFrame:sidebarFrame];
+
+ NSView* webView = [subviews objectAtIndex:0];
+ NSRect webFrame = [webView frame];
+ webFrame.size.width =
+ NSWidth([splitView_ frame]) - ([splitView_ dividerThickness] + width);
+ [webView setFrame:webFrame];
+
+ [splitView_ adjustSubviews];
+}
+
+// NSSplitViewDelegate protocol.
+- (BOOL)splitView:(NSSplitView *)splitView
+ shouldAdjustSizeOfSubview:(NSView *)subview {
+ // Return NO for the sidebar view to indicate that it should not be resized
+ // automatically. The sidebar keeps the width set by the user.
+ if ([[splitView_ subviews] indexOfObject:subview] == 1)
+ return NO;
+ return YES;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/simple_content_exceptions_window_controller.h b/chrome/browser/ui/cocoa/simple_content_exceptions_window_controller.h
new file mode 100644
index 0000000..61fd48c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/simple_content_exceptions_window_controller.h
@@ -0,0 +1,38 @@
+// 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>
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/remove_rows_table_model.h"
+#import "chrome/browser/ui/cocoa/table_model_array_controller.h"
+
+class RemoveRowsObserverBridge;
+
+// Controller for the geolocation exception dialog.
+@interface SimpleContentExceptionsWindowController : NSWindowController
+ <NSWindowDelegate> {
+ @private
+ IBOutlet NSTableView* tableView_;
+ IBOutlet NSButton* removeButton_;
+ IBOutlet NSButton* removeAllButton_;
+ IBOutlet NSButton* doneButton_;
+ IBOutlet TableModelArrayController* arrayController_;
+
+ scoped_ptr<RemoveRowsTableModel> model_;
+}
+
+// Shows or makes frontmost the exceptions window.
+// Changes made by the user in the window are persisted in |model|.
+// Takes ownership of |model|.
++ (id)controllerWithTableModel:(RemoveRowsTableModel*)model;
+
+// Sets the minimum width of the sheet and resizes it if necessary.
+- (void)setMinWidth:(CGFloat)minWidth;
+
+- (void)attachSheetTo:(NSWindow*)window;
+- (IBAction)closeSheet:(id)sender;
+
+@end
diff --git a/chrome/browser/ui/cocoa/simple_content_exceptions_window_controller.mm b/chrome/browser/ui/cocoa/simple_content_exceptions_window_controller.mm
new file mode 100644
index 0000000..7beac9c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/simple_content_exceptions_window_controller.mm
@@ -0,0 +1,125 @@
+// 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 "chrome/browser/ui/cocoa/simple_content_exceptions_window_controller.h"
+
+#include "app/l10n_util_mac.h"
+#include "app/table_model_observer.h"
+#include "base/logging.h"
+#import "base/mac_util.h"
+#import "base/scoped_nsobject.h"
+#include "base/sys_string_conversions.h"
+#include "grit/generated_resources.h"
+#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
+
+@interface SimpleContentExceptionsWindowController (Private)
+- (id)initWithTableModel:(RemoveRowsTableModel*)model;
+@end
+
+namespace {
+
+const CGFloat kButtonBarHeight = 35.0;
+
+SimpleContentExceptionsWindowController* g_exceptionWindow = nil;
+
+} // namespace
+
+@implementation SimpleContentExceptionsWindowController
+
++ (id)controllerWithTableModel:(RemoveRowsTableModel*)model {
+ if (!g_exceptionWindow) {
+ g_exceptionWindow = [[SimpleContentExceptionsWindowController alloc]
+ initWithTableModel:model];
+ }
+ return g_exceptionWindow;
+}
+
+- (id)initWithTableModel:(RemoveRowsTableModel*)model {
+ NSString* nibpath = [mac_util::MainAppBundle()
+ pathForResource:@"SimpleContentExceptionsWindow"
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
+ model_.reset(model);
+
+ // TODO(thakis): autoremember window rect.
+ // TODO(thakis): sorting support.
+ }
+ return self;
+}
+
+- (void)awakeFromNib {
+ DCHECK([self window]);
+ DCHECK_EQ(self, [[self window] delegate]);
+ DCHECK(tableView_);
+ DCHECK(arrayController_);
+
+ CGFloat minWidth = [[removeButton_ superview] bounds].size.width +
+ [[doneButton_ superview] bounds].size.width;
+ [[self window] setMinSize:NSMakeSize(minWidth,
+ [[self window] minSize].height)];
+ NSDictionary* columns = [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSNumber numberWithInt:IDS_EXCEPTIONS_HOSTNAME_HEADER], @"hostname",
+ [NSNumber numberWithInt:IDS_EXCEPTIONS_ACTION_HEADER], @"action",
+ nil];
+ [arrayController_ bindToTableModel:model_.get()
+ withColumns:columns
+ groupTitleColumn:@"hostname"];
+}
+
+- (void)setMinWidth:(CGFloat)minWidth {
+ NSWindow* window = [self window];
+ [window setMinSize:NSMakeSize(minWidth, [window minSize].height)];
+ if ([window frame].size.width < minWidth) {
+ NSRect frame = [window frame];
+ frame.size.width = minWidth;
+ [window setFrame:frame display:NO];
+ }
+}
+
+- (void)windowWillClose:(NSNotification*)notification {
+ g_exceptionWindow = nil;
+ [self autorelease];
+}
+
+// Let esc close the window.
+- (void)cancel:(id)sender {
+ [self closeSheet:self];
+}
+
+- (void)keyDown:(NSEvent*)event {
+ NSString* chars = [event charactersIgnoringModifiers];
+ if ([chars length] == 1) {
+ switch ([chars characterAtIndex:0]) {
+ case NSDeleteCharacter:
+ case NSDeleteFunctionKey:
+ // Delete deletes.
+ if ([[tableView_ selectedRowIndexes] count] > 0)
+ [arrayController_ remove:event];
+ return;
+ }
+ }
+ [super keyDown:event];
+}
+
+- (void)attachSheetTo:(NSWindow*)window {
+ [NSApp beginSheet:[self window]
+ modalForWindow:window
+ modalDelegate:self
+ didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
+ contextInfo:nil];
+}
+
+- (void)sheetDidEnd:(NSWindow*)sheet
+ returnCode:(NSInteger)returnCode
+ contextInfo:(void*)context {
+ [sheet close];
+ [sheet orderOut:self];
+}
+
+- (IBAction)closeSheet:(id)sender {
+ [NSApp endSheet:[self window]];
+}
+
+
+@end
diff --git a/chrome/browser/ui/cocoa/simple_content_exceptions_window_controller_unittest.mm b/chrome/browser/ui/cocoa/simple_content_exceptions_window_controller_unittest.mm
new file mode 100644
index 0000000..58d1c84
--- /dev/null
+++ b/chrome/browser/ui/cocoa/simple_content_exceptions_window_controller_unittest.mm
@@ -0,0 +1,94 @@
+// 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 "chrome/browser/ui/cocoa/simple_content_exceptions_window_controller.h"
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/scoped_nsobject.h"
+#include "base/ref_counted.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
+#include "chrome/browser/geolocation/geolocation_exceptions_table_model.h"
+#include "chrome/browser/plugin_exceptions_table_model.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+@interface SimpleContentExceptionsWindowController (Testing)
+
+@property(readonly, nonatomic) TableModelArrayController* arrayController;
+
+@end
+
+@implementation SimpleContentExceptionsWindowController (Testing)
+
+- (TableModelArrayController*)arrayController {
+ return arrayController_;
+}
+
+@end
+
+
+namespace {
+
+class SimpleContentExceptionsWindowControllerTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ TestingProfile* profile = browser_helper_.profile();
+ geolocation_settings_ = new GeolocationContentSettingsMap(profile);
+ content_settings_ = new HostContentSettingsMap(profile);
+ }
+
+ SimpleContentExceptionsWindowController* GetController() {
+ GeolocationExceptionsTableModel* model = // Freed by window controller.
+ new GeolocationExceptionsTableModel(geolocation_settings_.get());
+ id controller = [SimpleContentExceptionsWindowController
+ controllerWithTableModel:model];
+ [controller showWindow:nil];
+ return controller;
+ }
+
+ void ClickRemoveAll(SimpleContentExceptionsWindowController* controller) {
+ [controller.arrayController removeAll:nil];
+ }
+
+ protected:
+ BrowserTestHelper browser_helper_;
+ scoped_refptr<GeolocationContentSettingsMap> geolocation_settings_;
+ scoped_refptr<HostContentSettingsMap> content_settings_;
+};
+
+TEST_F(SimpleContentExceptionsWindowControllerTest, Construction) {
+ GeolocationExceptionsTableModel* model = // Freed by window controller.
+ new GeolocationExceptionsTableModel(geolocation_settings_.get());
+ SimpleContentExceptionsWindowController* controller =
+ [SimpleContentExceptionsWindowController controllerWithTableModel:model];
+ [controller showWindow:nil];
+ [controller close]; // Should autorelease.
+}
+
+TEST_F(SimpleContentExceptionsWindowControllerTest, ShowPluginExceptions) {
+ PluginExceptionsTableModel* model = // Freed by window controller.
+ new PluginExceptionsTableModel(content_settings_.get(), NULL);
+ SimpleContentExceptionsWindowController* controller =
+ [SimpleContentExceptionsWindowController controllerWithTableModel:model];
+ [controller showWindow:nil];
+ [controller close]; // Should autorelease.
+}
+
+TEST_F(SimpleContentExceptionsWindowControllerTest, AddExistingEditAdd) {
+ geolocation_settings_->SetContentSetting(
+ GURL("http://myhost"), GURL(), CONTENT_SETTING_BLOCK);
+
+ SimpleContentExceptionsWindowController* controller = GetController();
+ ClickRemoveAll(controller);
+
+ [controller close];
+
+ EXPECT_EQ(0u, geolocation_settings_->GetAllOriginsSettings().size());
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/speech_input_window_controller.h b/chrome/browser/ui/cocoa/speech_input_window_controller.h
new file mode 100644
index 0000000..d68a30c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/speech_input_window_controller.h
@@ -0,0 +1,57 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_SPEECH_INPUT_WINDOW_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_SPEECH_INPUT_WINDOW_CONTROLLER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "chrome/browser/speech/speech_input_bubble.h"
+#include "chrome/browser/ui/cocoa/base_bubble_controller.h"
+
+// Controller for the speech input bubble window. This bubble window gets
+// displayed when the user starts speech input in a html input element.
+@interface SpeechInputWindowController : BaseBubbleController {
+ @private
+ SpeechInputBubble::Delegate* delegate_; // weak.
+
+ // References below are weak, being obtained from the nib.
+ IBOutlet NSImageView* iconImage_;
+ IBOutlet NSTextField* instructionLabel_;
+ IBOutlet NSButton* cancelButton_;
+ IBOutlet NSButton* tryAgainButton_;
+}
+
+// Initialize the window. |anchoredAt| is in screen coordinates.
+- (id)initWithParentWindow:(NSWindow*)parentWindow
+ delegate:(SpeechInputBubbleDelegate*)delegate
+ anchoredAt:(NSPoint)anchoredAt;
+
+// Handler for the cancel button.
+- (IBAction)cancel:(id)sender;
+
+// Handler for the try again button.
+- (IBAction)tryAgain:(id)sender;
+
+// Updates the UI with data related to the given display mode.
+- (void)updateLayout:(SpeechInputBubbleBase::DisplayMode)mode
+ messageText:(const string16&)messageText;
+
+// Makes the speech input bubble visible on screen.
+- (void)show;
+
+// Hides the speech input bubble away from screen. This does NOT release the
+// controller and the window.
+- (void)hide;
+
+// Sets the image to be displayed in the bubble's status ImageView. A future
+// call to updateLayout may change the image.
+// TODO(satish): Clean that up and move it into the platform independent
+// SpeechInputBubbleBase class.
+- (void)setImage:(NSImage*)image;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_SPEECH_INPUT_WINDOW_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/speech_input_window_controller.mm b/chrome/browser/ui/cocoa/speech_input_window_controller.mm
new file mode 100644
index 0000000..c490bc1
--- /dev/null
+++ b/chrome/browser/ui/cocoa/speech_input_window_controller.mm
@@ -0,0 +1,188 @@
+// 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 "speech_input_window_controller.h"
+
+#include "app/l10n_util_mac.h"
+#include "app/resource_bundle.h"
+#include "base/logging.h"
+#include "base/mac_util.h"
+#include "base/sys_string_conversions.h"
+
+#include "chrome/browser/ui/cocoa/info_bubble_view.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#import "skia/ext/skia_utils_mac.h"
+#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
+
+const int kBubbleControlVerticalSpacing = 10; // Space between controls.
+const int kBubbleHorizontalMargin = 5; // Space on either sides of controls.
+
+@interface SpeechInputWindowController (Private)
+- (NSSize)calculateContentSize;
+- (void)layout:(NSSize)size;
+@end
+
+@implementation SpeechInputWindowController
+
+- (id)initWithParentWindow:(NSWindow*)parentWindow
+ delegate:(SpeechInputBubbleDelegate*)delegate
+ anchoredAt:(NSPoint)anchoredAt {
+ anchoredAt.y += info_bubble::kBubbleArrowHeight / 2.0;
+ if ((self = [super initWithWindowNibPath:@"SpeechInputBubble"
+ parentWindow:parentWindow
+ anchoredAt:anchoredAt])) {
+ DCHECK(delegate);
+ delegate_ = delegate;
+
+ [self showWindow:nil];
+ }
+ return self;
+}
+
+- (void)awakeFromNib {
+ [super awakeFromNib];
+
+ NSWindow* window = [self window];
+ [[self bubble] setArrowLocation:info_bubble::kTopLeft];
+
+ NSSize newSize = [self calculateContentSize];
+ [[self bubble] setFrameSize:newSize];
+ NSSize windowDelta = NSMakeSize(
+ newSize.width - NSWidth([[window contentView] bounds]),
+ newSize.height - NSHeight([[window contentView] bounds]));
+ windowDelta = [[window contentView] convertSize:windowDelta toView:nil];
+ NSRect newFrame = [window frame];
+ newFrame.size.width += windowDelta.width;
+ newFrame.size.height += windowDelta.height;
+ [window setFrame:newFrame display:NO];
+
+ [self layout:newSize]; // Layout all the child controls.
+}
+
+- (IBAction)cancel:(id)sender {
+ delegate_->InfoBubbleButtonClicked(SpeechInputBubble::BUTTON_CANCEL);
+}
+
+- (IBAction)tryAgain:(id)sender {
+ delegate_->InfoBubbleButtonClicked(SpeechInputBubble::BUTTON_TRY_AGAIN);
+}
+
+// Calculate the window dimensions to reflect the sum height and max width of
+// all controls, with appropriate spacing between and around them. The returned
+// size is in view coordinates.
+- (NSSize)calculateContentSize {
+ [GTMUILocalizerAndLayoutTweaker sizeToFitView:cancelButton_];
+ [GTMUILocalizerAndLayoutTweaker sizeToFitView:tryAgainButton_];
+ NSSize cancelSize = [cancelButton_ bounds].size;
+ NSSize tryAgainSize = [tryAgainButton_ bounds].size;
+ int newHeight = cancelSize.height + kBubbleControlVerticalSpacing;
+ int newWidth = cancelSize.width + tryAgainSize.width;
+
+ if (![iconImage_ isHidden]) {
+ NSImage* icon = ResourceBundle::GetSharedInstance().GetNativeImageNamed(
+ IDR_SPEECH_INPUT_MIC_EMPTY);
+ NSSize size = [icon size];
+ newHeight += size.height + kBubbleControlVerticalSpacing;
+ if (newWidth < size.width)
+ newWidth = size.width;
+ } else {
+ newHeight += kBubbleControlVerticalSpacing;
+ }
+
+ [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:
+ instructionLabel_];
+ NSSize size = [instructionLabel_ bounds].size;
+ newHeight += size.height;
+ if (newWidth < size.width)
+ newWidth = size.width;
+
+ return NSMakeSize(newWidth + 2 * kBubbleHorizontalMargin,
+ newHeight + 2 * kBubbleControlVerticalSpacing);
+}
+
+// Position the controls within the given content area bounds.
+- (void)layout:(NSSize)size {
+ int y = kBubbleControlVerticalSpacing;
+
+ NSRect cancelRect = [cancelButton_ bounds];
+
+ if ([tryAgainButton_ isHidden]) {
+ cancelRect.origin.x = (size.width - NSWidth(cancelRect)) / 2;
+ } else {
+ NSRect tryAgainRect = [tryAgainButton_ bounds];
+ cancelRect.origin.x = (size.width - NSWidth(cancelRect) -
+ NSWidth(tryAgainRect)) / 2;
+ tryAgainRect.origin.x = cancelRect.origin.x + NSWidth(cancelRect);
+ tryAgainRect.origin.y = y;
+ [tryAgainButton_ setFrame:tryAgainRect];
+ }
+ cancelRect.origin.y = y;
+ [cancelButton_ setFrame:cancelRect];
+
+ y += NSHeight(cancelRect) + kBubbleControlVerticalSpacing;
+
+ NSRect rect;
+ if (![iconImage_ isHidden]) {
+ rect = [iconImage_ bounds];
+ rect.origin.x = (size.width - NSWidth(rect)) / 2;
+ rect.origin.y = y;
+ [iconImage_ setFrame:rect];
+ y += rect.size.height + kBubbleControlVerticalSpacing;
+ }
+
+ rect = [instructionLabel_ bounds];
+ rect.origin.x = (size.width - NSWidth(rect)) / 2;
+ rect.origin.y = y;
+ [instructionLabel_ setFrame:rect];
+}
+
+- (void)updateLayout:(SpeechInputBubbleBase::DisplayMode)mode
+ messageText:(const string16&)messageText {
+ // Get the right set of controls to be visible.
+ if (mode == SpeechInputBubbleBase::DISPLAY_MODE_MESSAGE) {
+ [instructionLabel_ setStringValue:base::SysUTF16ToNSString(messageText)];
+ [iconImage_ setHidden:YES];
+ [tryAgainButton_ setHidden:NO];
+ } else {
+ if (mode == SpeechInputBubbleBase::DISPLAY_MODE_RECORDING) {
+ [instructionLabel_ setStringValue:l10n_util::GetNSString(
+ IDS_SPEECH_INPUT_BUBBLE_HEADING)];
+ NSImage* icon = ResourceBundle::GetSharedInstance().GetNativeImageNamed(
+ IDR_SPEECH_INPUT_MIC_EMPTY);
+ [iconImage_ setImage:icon];
+ } else {
+ [instructionLabel_ setStringValue:l10n_util::GetNSString(
+ IDS_SPEECH_INPUT_BUBBLE_WORKING)];
+ }
+ [iconImage_ setHidden:NO];
+ [iconImage_ setNeedsDisplay:YES];
+ [tryAgainButton_ setHidden:YES];
+ }
+
+ NSSize newSize = [self calculateContentSize];
+ NSRect rect = [[self bubble] frame];
+ rect.origin.y -= newSize.height - rect.size.height;
+ rect.size = newSize;
+ [[self bubble] setFrame:rect];
+ [self layout:newSize];
+}
+
+- (void)windowWillClose:(NSNotification*)notification {
+ delegate_->InfoBubbleFocusChanged();
+}
+
+- (void)show {
+ [self showWindow:nil];
+}
+
+- (void)hide {
+ [[self window] orderOut:nil];
+}
+
+- (void)setImage:(NSImage*)image {
+ [iconImage_ setImage:image];
+}
+
+@end // implementation SpeechInputWindowController
diff --git a/chrome/browser/ui/cocoa/ssl_client_certificate_selector.mm b/chrome/browser/ui/cocoa/ssl_client_certificate_selector.mm
new file mode 100644
index 0000000..3f0a2f5
--- /dev/null
+++ b/chrome/browser/ui/cocoa/ssl_client_certificate_selector.mm
@@ -0,0 +1,195 @@
+// 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.
+
+#include "chrome/browser/ssl_client_certificate_selector.h"
+
+#import <SecurityInterface/SFChooseIdentityPanel.h>
+
+#include <vector>
+
+#import "app/l10n_util_mac.h"
+#include "base/logging.h"
+#include "base/ref_counted.h"
+#import "base/scoped_nsobject.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/ssl/ssl_client_auth_handler.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#import "chrome/browser/ui/cocoa/constrained_window_mac.h"
+#include "grit/generated_resources.h"
+#include "net/base/x509_certificate.h"
+
+namespace {
+
+class ConstrainedSFChooseIdentityPanel
+ : public ConstrainedWindowMacDelegateSystemSheet {
+ public:
+ ConstrainedSFChooseIdentityPanel(SFChooseIdentityPanel* panel,
+ id delegate, SEL didEndSelector,
+ NSArray* identities, NSString* message)
+ : ConstrainedWindowMacDelegateSystemSheet(delegate, didEndSelector),
+ identities_([identities retain]),
+ message_([message retain]) {
+ set_sheet(panel);
+ }
+
+ virtual ~ConstrainedSFChooseIdentityPanel() {
+ // As required by ConstrainedWindowMacDelegate, close the sheet if
+ // it's still open.
+ if (is_sheet_open()) {
+ [NSApp endSheet:sheet()
+ returnCode:NSFileHandlingPanelCancelButton];
+ }
+ }
+
+ // ConstrainedWindowMacDelegateSystemSheet implementation:
+ virtual void DeleteDelegate() {
+ delete this;
+ }
+
+ // SFChooseIdentityPanel's beginSheetForWindow: method has more arguments
+ // than the usual one. Also pass the panel through contextInfo argument
+ // because the callback has the wrong signature.
+ virtual NSArray* GetSheetParameters(id delegate, SEL didEndSelector) {
+ return [NSArray arrayWithObjects:
+ [NSNull null], // window, must be [NSNull null]
+ delegate,
+ [NSValue valueWithPointer:didEndSelector],
+ [NSValue valueWithPointer:sheet()],
+ identities_.get(),
+ message_.get(),
+ nil];
+ }
+
+ private:
+ scoped_nsobject<NSArray> identities_;
+ scoped_nsobject<NSString> message_;
+ DISALLOW_COPY_AND_ASSIGN(ConstrainedSFChooseIdentityPanel);
+};
+
+} // namespace
+
+@interface SSLClientCertificateSelectorCocoa : NSObject {
+ @private
+ // The handler to report back to.
+ scoped_refptr<SSLClientAuthHandler> handler_;
+ // The certificate request we serve.
+ scoped_refptr<net::SSLCertRequestInfo> certRequestInfo_;
+ // The list of identities offered to the user.
+ scoped_nsobject<NSMutableArray> identities_;
+ // The corresponding list of certificates.
+ std::vector<scoped_refptr<net::X509Certificate> > certificates_;
+ // The currently open dialog.
+ ConstrainedWindow* window_;
+}
+
+- (id)initWithHandler:(SSLClientAuthHandler*)handler
+ certRequestInfo:(net::SSLCertRequestInfo*)certRequestInfo;
+- (void)displayDialog:(TabContents*)parent;
+@end
+
+namespace browser {
+
+void ShowSSLClientCertificateSelector(
+ TabContents* parent,
+ net::SSLCertRequestInfo* cert_request_info,
+ SSLClientAuthHandler* delegate) {
+ // TODO(davidben): Implement a tab-modal dialog.
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ SSLClientCertificateSelectorCocoa* selector =
+ [[[SSLClientCertificateSelectorCocoa alloc]
+ initWithHandler:delegate
+ certRequestInfo:cert_request_info] autorelease];
+ [selector displayDialog:parent];
+}
+
+} // namespace browser
+
+@implementation SSLClientCertificateSelectorCocoa
+
+- (id)initWithHandler:(SSLClientAuthHandler*)handler
+ certRequestInfo:(net::SSLCertRequestInfo*)certRequestInfo {
+ DCHECK(handler);
+ DCHECK(certRequestInfo);
+ if ((self = [super init])) {
+ handler_ = handler;
+ certRequestInfo_ = certRequestInfo;
+ window_ = NULL;
+ }
+ return self;
+}
+
+- (void)sheetDidEnd:(NSWindow*)parent
+ returnCode:(NSInteger)returnCode
+ context:(void*)context {
+ DCHECK(context);
+ SFChooseIdentityPanel* panel = static_cast<SFChooseIdentityPanel*>(context);
+
+ net::X509Certificate* cert = NULL;
+ if (returnCode == NSFileHandlingPanelOKButton) {
+ NSUInteger index = [identities_ indexOfObject:(id)[panel identity]];
+ if (index != NSNotFound)
+ cert = certificates_[index];
+ else
+ NOTREACHED();
+ }
+
+ // Finally, tell the backend which identity (or none) the user selected.
+ handler_->CertificateSelected(cert);
+ // Close the constrained window.
+ DCHECK(window_);
+ window_->CloseConstrainedWindow();
+
+ // Now that the panel has closed, release it. Note that the autorelease is
+ // needed. After this callback returns, the panel is still accessed, so a
+ // normal release crashes.
+ [panel autorelease];
+}
+
+- (void)displayDialog:(TabContents*)parent {
+ DCHECK(!window_);
+ // Create an array of CFIdentityRefs for the certificates:
+ size_t numCerts = certRequestInfo_->client_certs.size();
+ identities_.reset([[NSMutableArray alloc] initWithCapacity:numCerts]);
+ for (size_t i = 0; i < numCerts; ++i) {
+ SecCertificateRef cert;
+ cert = certRequestInfo_->client_certs[i]->os_cert_handle();
+ SecIdentityRef identity;
+ if (SecIdentityCreateWithCertificate(NULL, cert, &identity) == noErr) {
+ [identities_ addObject:(id)identity];
+ CFRelease(identity);
+ certificates_.push_back(certRequestInfo_->client_certs[i]);
+ }
+ }
+
+ // Get the message to display:
+ NSString* title = l10n_util::GetNSString(IDS_CLIENT_CERT_DIALOG_TITLE);
+ NSString* message = l10n_util::GetNSStringF(
+ IDS_CLIENT_CERT_DIALOG_TEXT,
+ ASCIIToUTF16(certRequestInfo_->host_and_port));
+
+ // Create and set up a system choose-identity panel.
+ SFChooseIdentityPanel* panel = [[SFChooseIdentityPanel alloc] init];
+ [panel setInformativeText:message];
+ [panel setDefaultButtonTitle:l10n_util::GetNSString(IDS_OK)];
+ [panel setAlternateButtonTitle:l10n_util::GetNSString(IDS_CANCEL)];
+ SecPolicyRef sslPolicy;
+ if (net::X509Certificate::CreateSSLClientPolicy(&sslPolicy) == noErr) {
+ [panel setPolicies:(id)sslPolicy];
+ CFRelease(sslPolicy);
+ }
+
+ window_ =
+ parent->CreateConstrainedDialog(new ConstrainedSFChooseIdentityPanel(
+ panel, self,
+ @selector(sheetDidEnd:returnCode:context:),
+ identities_, title));
+ // Note: SFChooseIdentityPanel does not take a reference to itself while the
+ // sheet is open. Don't release the ownership claim until the sheet has ended
+ // in |-sheetDidEnd:returnCode:context:|.
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/status_bubble_mac.h b/chrome/browser/ui/cocoa/status_bubble_mac.h
new file mode 100644
index 0000000..091fdc1
--- /dev/null
+++ b/chrome/browser/ui/cocoa/status_bubble_mac.h
@@ -0,0 +1,172 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_STATUS_BUBBLE_MAC_H_
+#define CHROME_BROWSER_UI_COCOA_STATUS_BUBBLE_MAC_H_
+#pragma once
+
+#include <string>
+
+#import <Cocoa/Cocoa.h>
+#import <QuartzCore/QuartzCore.h>
+
+#include "base/string16.h"
+#include "base/task.h"
+#include "chrome/browser/ui/status_bubble.h"
+#include "googleurl/src/gurl.h"
+
+class GURL;
+class StatusBubbleMacTest;
+
+class StatusBubbleMac : public StatusBubble {
+ public:
+ // The various states that a status bubble may be in. Public for delegate
+ // access (for testing).
+ enum StatusBubbleState {
+ kBubbleHidden, // Fully hidden
+ kBubbleShowingTimer, // Waiting to fade in
+ kBubbleShowingFadeIn, // In a fade-in transition
+ kBubbleShown, // Fully visible
+ kBubbleHidingTimer, // Waiting to fade out
+ kBubbleHidingFadeOut // In a fade-out transition
+ };
+
+ StatusBubbleMac(NSWindow* parent, id delegate);
+ virtual ~StatusBubbleMac();
+
+ // StatusBubble implementation.
+ virtual void SetStatus(const string16& status);
+ virtual void SetURL(const GURL& url, const string16& languages);
+ virtual void Hide();
+ virtual void MouseMoved(const gfx::Point& location, bool left_content);
+ virtual void UpdateDownloadShelfVisibility(bool visible);
+
+ // Mac-specific method: Update the size and position of the status bubble to
+ // match the parent window. Safe to call even when the status bubble does not
+ // exist.
+ void UpdateSizeAndPosition();
+
+ // Mac-specific method: Change the parent window of the status bubble. Safe to
+ // call even when the status bubble does not exist.
+ void SwitchParentWindow(NSWindow* parent);
+
+ // Delegate method called when a fade-in or fade-out transition has
+ // completed. This is public so that it may be visible to the CAAnimation
+ // delegate, which is an Objective-C object.
+ void AnimationDidStop(CAAnimation* animation, bool finished);
+
+ // Expand the bubble to fit a URL too long for the standard bubble size.
+ void ExpandBubble();
+
+ private:
+ friend class StatusBubbleMacTest;
+
+ // Setter for state_. Use this instead of writing to state_ directly so
+ // that state changes can be observed by unit tests.
+ void SetState(StatusBubbleState state);
+
+ // Sets the bubble text for SetStatus and SetURL.
+ void SetText(const string16& text, bool is_url);
+
+ // Construct the window/widget if it does not already exist. (Safe to call if
+ // it does.)
+ void Create();
+
+ // Attaches the status bubble window to its parent window. Safe to call even
+ // when already attached.
+ void Attach();
+
+ // Detaches the status bubble window from its parent window.
+ void Detach();
+
+ // Is the status bubble attached to the browser window? It should be attached
+ // when shown and during any fades, but should be detached when hidden.
+ bool is_attached() { return [window_ parentWindow] != nil; }
+
+ // Begins fading the status bubble window in or out depending on the value
+ // of |show|. This must be called from the appropriate fade state,
+ // kBubbleShowingFadeIn or kBubbleHidingFadeOut, or from the appropriate
+ // fully-shown/hidden state, kBubbleShown or kBubbleHidden. This may be
+ // called at any point during a fade-in or fade-out; it is even possible to
+ // reverse a transition before it has completed.
+ void Fade(bool show);
+
+ // One-shot timer operations to manage the delays associated with the
+ // kBubbleShowingTimer and kBubbleHidingTimer states. StartTimer and
+ // TimerFired must be called from one of these states. StartTimer may be
+ // called while the timer is still running; in that case, the timer will be
+ // reset. CancelTimer may be called from any state.
+ void StartTimer(int64 time_ms);
+ void CancelTimer();
+ void TimerFired();
+
+ // Begin the process of showing or hiding the status bubble. These may be
+ // called from any state, and will take the appropriate action to initiate
+ // any state changes that may be needed.
+ void StartShowing();
+ void StartHiding();
+
+ // Cancel the expansion timer.
+ void CancelExpandTimer();
+
+ // The timer factory used for show and hide delay timers.
+ ScopedRunnableMethodFactory<StatusBubbleMac> timer_factory_;
+
+ // The timer factory used for the expansion delay timer.
+ ScopedRunnableMethodFactory<StatusBubbleMac> expand_timer_factory_;
+
+ // Calculate the appropriate frame for the status bubble window. If
+ // |expanded_width|, use entire width of parent frame.
+ NSRect CalculateWindowFrame(bool expanded_width);
+
+ // The window we attach ourselves to.
+ NSWindow* parent_; // WEAK
+
+ // The object that we query about our vertical offset for positioning.
+ id delegate_; // WEAK
+
+ // The window we own.
+ NSWindow* window_;
+
+ // The status text we want to display when there are no URLs to display.
+ NSString* status_text_;
+
+ // The url we want to display when there is no status text to display.
+ NSString* url_text_;
+
+ // The status bubble's current state. Do not write to this field directly;
+ // use SetState().
+ StatusBubbleState state_;
+
+ // True if operations are to be performed immediately rather than waiting
+ // for delays and transitions. Normally false, this should only be set to
+ // true for testing.
+ bool immediate_;
+
+ // True if the status bubble has been expanded. If the bubble is in the
+ // expanded state and encounters a new URL, change size immediately,
+ // with no hover delay.
+ bool is_expanded_;
+
+ // The original, non-elided URL.
+ GURL url_;
+
+ // Needs to be passed to ElideURL if the original URL string is wider than
+ // the standard bubble width.
+ string16 languages_;
+
+ DISALLOW_COPY_AND_ASSIGN(StatusBubbleMac);
+};
+
+// Delegate interface
+@interface NSObject(StatusBubbleDelegate)
+// Called to query the delegate about the frame StatusBubble should position
+// itself in. Frame is returned in the parent window coordinates.
+- (NSRect)statusBubbleBaseFrame;
+
+// Called from SetState to notify the delegate of state changes.
+- (void)statusBubbleWillEnterState:(StatusBubbleMac::StatusBubbleState)state;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_STATUS_BUBBLE_MAC_H_
diff --git a/chrome/browser/ui/cocoa/status_bubble_mac.mm b/chrome/browser/ui/cocoa/status_bubble_mac.mm
new file mode 100644
index 0000000..6231e5d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/status_bubble_mac.mm
@@ -0,0 +1,705 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/status_bubble_mac.h"
+
+#include <limits>
+
+#include "app/text_elider.h"
+#include "base/compiler_specific.h"
+#include "base/message_loop.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#import "chrome/browser/ui/cocoa/bubble_view.h"
+#include "gfx/point.h"
+#include "net/base/net_util.h"
+#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
+#import "third_party/GTM/AppKit/GTMNSBezierPath+RoundRect.h"
+#import "third_party/GTM/AppKit/GTMNSColor+Luminance.h"
+
+namespace {
+
+const int kWindowHeight = 18;
+
+// The width of the bubble in relation to the width of the parent window.
+const CGFloat kWindowWidthPercent = 1.0 / 3.0;
+
+// How close the mouse can get to the infobubble before it starts sliding
+// off-screen.
+const int kMousePadding = 20;
+
+const int kTextPadding = 3;
+
+// The animation key used for fade-in and fade-out transitions.
+NSString* const kFadeAnimationKey = @"alphaValue";
+
+// The status bubble's maximum opacity, when fully faded in.
+const CGFloat kBubbleOpacity = 1.0;
+
+// Delay before showing or hiding the bubble after a SetStatus or SetURL call.
+const int64 kShowDelayMilliseconds = 80;
+const int64 kHideDelayMilliseconds = 250;
+
+// How long each fade should last.
+const NSTimeInterval kShowFadeInDurationSeconds = 0.120;
+const NSTimeInterval kHideFadeOutDurationSeconds = 0.200;
+
+// The minimum representable time interval. This can be used as the value
+// passed to +[NSAnimationContext setDuration:] to stop an in-progress
+// animation as quickly as possible.
+const NSTimeInterval kMinimumTimeInterval =
+ std::numeric_limits<NSTimeInterval>::min();
+
+// How quickly the status bubble should expand, in seconds.
+const CGFloat kExpansionDuration = 0.125;
+
+} // namespace
+
+@interface StatusBubbleAnimationDelegate : NSObject {
+ @private
+ StatusBubbleMac* statusBubble_; // weak; owns us indirectly
+}
+
+- (id)initWithStatusBubble:(StatusBubbleMac*)statusBubble;
+
+// Invalidates this object so that no further calls will be made to
+// statusBubble_. This should be called when statusBubble_ is released, to
+// prevent attempts to call into the released object.
+- (void)invalidate;
+
+// CAAnimation delegate method
+- (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)finished;
+@end
+
+@implementation StatusBubbleAnimationDelegate
+
+- (id)initWithStatusBubble:(StatusBubbleMac*)statusBubble {
+ if ((self = [super init])) {
+ statusBubble_ = statusBubble;
+ }
+
+ return self;
+}
+
+- (void)invalidate {
+ statusBubble_ = NULL;
+}
+
+- (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)finished {
+ if (statusBubble_)
+ statusBubble_->AnimationDidStop(animation, finished ? true : false);
+}
+
+@end
+
+StatusBubbleMac::StatusBubbleMac(NSWindow* parent, id delegate)
+ : ALLOW_THIS_IN_INITIALIZER_LIST(timer_factory_(this)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(expand_timer_factory_(this)),
+ parent_(parent),
+ delegate_(delegate),
+ window_(nil),
+ status_text_(nil),
+ url_text_(nil),
+ state_(kBubbleHidden),
+ immediate_(false),
+ is_expanded_(false) {
+}
+
+StatusBubbleMac::~StatusBubbleMac() {
+ Hide();
+
+ if (window_) {
+ [[[window_ animationForKey:kFadeAnimationKey] delegate] invalidate];
+ Detach();
+ [window_ release];
+ window_ = nil;
+ }
+}
+
+void StatusBubbleMac::SetStatus(const string16& status) {
+ Create();
+
+ SetText(status, false);
+}
+
+void StatusBubbleMac::SetURL(const GURL& url, const string16& languages) {
+ url_ = url;
+ languages_ = languages;
+
+ Create();
+
+ NSRect frame = [window_ frame];
+
+ // Reset frame size when bubble is hidden.
+ if (state_ == kBubbleHidden) {
+ is_expanded_ = false;
+ frame.size.width = NSWidth(CalculateWindowFrame(/*expand=*/false));
+ [window_ setFrame:frame display:NO];
+ }
+
+ int text_width = static_cast<int>(NSWidth(frame) -
+ kBubbleViewTextPositionX -
+ kTextPadding);
+
+ // Scale from view to window coordinates before eliding URL string.
+ NSSize scaled_width = NSMakeSize(text_width, 0);
+ scaled_width = [[parent_ contentView] convertSize:scaled_width fromView:nil];
+ text_width = static_cast<int>(scaled_width.width);
+ NSFont* font = [[window_ contentView] font];
+ gfx::Font font_chr(base::SysNSStringToWide([font fontName]),
+ [font pointSize]);
+
+ string16 original_url_text = net::FormatUrl(url, UTF16ToUTF8(languages));
+ string16 status = gfx::ElideUrl(url, font_chr, text_width,
+ UTF16ToWideHack(languages));
+
+ SetText(status, true);
+
+ // In testing, don't use animation. When ExpandBubble is tested, it is
+ // called explicitly.
+ if (immediate_)
+ return;
+ else
+ CancelExpandTimer();
+
+ // If the bubble has been expanded, the user has already hovered over a link
+ // to trigger the expanded state. Don't wait to change the bubble in this
+ // case -- immediately expand or contract to fit the URL.
+ if (is_expanded_ && !url.is_empty()) {
+ ExpandBubble();
+ } else if (original_url_text.length() > status.length()) {
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ expand_timer_factory_.NewRunnableMethod(
+ &StatusBubbleMac::ExpandBubble), kExpandHoverDelay);
+ }
+}
+
+void StatusBubbleMac::SetText(const string16& text, bool is_url) {
+ // The status bubble allows the status and URL strings to be set
+ // independently. Whichever was set non-empty most recently will be the
+ // value displayed. When both are empty, the status bubble hides.
+
+ NSString* text_ns = base::SysUTF16ToNSString(text);
+
+ NSString** main;
+ NSString** backup;
+
+ if (is_url) {
+ main = &url_text_;
+ backup = &status_text_;
+ } else {
+ main = &status_text_;
+ backup = &url_text_;
+ }
+
+ // Don't return from this function early. It's important to make sure that
+ // all calls to StartShowing and StartHiding are made, so that all delays
+ // are observed properly. Specifically, if the state is currently
+ // kBubbleShowingTimer, the timer will need to be restarted even if
+ // [text_ns isEqualToString:*main] is true.
+
+ [*main autorelease];
+ *main = [text_ns retain];
+
+ bool show = true;
+ if ([*main length] > 0)
+ [[window_ contentView] setContent:*main];
+ else if ([*backup length] > 0)
+ [[window_ contentView] setContent:*backup];
+ else
+ show = false;
+
+ if (show)
+ StartShowing();
+ else
+ StartHiding();
+}
+
+void StatusBubbleMac::Hide() {
+ CancelTimer();
+ CancelExpandTimer();
+ is_expanded_ = false;
+
+ bool fade_out = false;
+ if (state_ == kBubbleHidingFadeOut || state_ == kBubbleShowingFadeIn) {
+ SetState(kBubbleHidingFadeOut);
+
+ if (!immediate_) {
+ // An animation is in progress. Cancel it by starting a new animation.
+ // Use kMinimumTimeInterval to set the opacity as rapidly as possible.
+ fade_out = true;
+ [NSAnimationContext beginGrouping];
+ [[NSAnimationContext currentContext] setDuration:kMinimumTimeInterval];
+ [[window_ animator] setAlphaValue:0.0];
+ [NSAnimationContext endGrouping];
+ }
+ }
+
+ if (!fade_out) {
+ // No animation is in progress, so the opacity can be set directly.
+ [window_ setAlphaValue:0.0];
+ SetState(kBubbleHidden);
+ }
+
+ // Stop any width animation and reset the bubble size.
+ if (!immediate_) {
+ [NSAnimationContext beginGrouping];
+ [[NSAnimationContext currentContext] setDuration:kMinimumTimeInterval];
+ [[window_ animator] setFrame:CalculateWindowFrame(/*expand=*/false)
+ display:NO];
+ [NSAnimationContext endGrouping];
+ } else {
+ [window_ setFrame:CalculateWindowFrame(/*expand=*/false) display:NO];
+ }
+
+ [status_text_ release];
+ status_text_ = nil;
+ [url_text_ release];
+ url_text_ = nil;
+}
+
+void StatusBubbleMac::MouseMoved(
+ const gfx::Point& location, bool left_content) {
+ if (left_content)
+ return;
+
+ if (!window_)
+ return;
+
+ // TODO(thakis): Use 'location' here instead of NSEvent.
+ NSPoint cursor_location = [NSEvent mouseLocation];
+ --cursor_location.y; // docs say the y coord starts at 1 not 0; don't ask why
+
+ // Bubble's base frame in |parent_| coordinates.
+ NSRect baseFrame;
+ if ([delegate_ respondsToSelector:@selector(statusBubbleBaseFrame)])
+ baseFrame = [delegate_ statusBubbleBaseFrame];
+ else
+ baseFrame = [[parent_ contentView] frame];
+
+ // Get the normal position of the frame.
+ NSRect window_frame = [window_ frame];
+ window_frame.origin = [parent_ convertBaseToScreen:baseFrame.origin];
+
+ // Get the cursor position relative to the popup.
+ cursor_location.x -= NSMaxX(window_frame);
+ cursor_location.y -= NSMaxY(window_frame);
+
+
+ // If the mouse is in a position where we think it would move the
+ // status bubble, figure out where and how the bubble should be moved.
+ if (cursor_location.y < kMousePadding &&
+ cursor_location.x < kMousePadding) {
+ int offset = kMousePadding - cursor_location.y;
+
+ // Make the movement non-linear.
+ offset = offset * offset / kMousePadding;
+
+ // When the mouse is entering from the right, we want the offset to be
+ // scaled by how horizontally far away the cursor is from the bubble.
+ if (cursor_location.x > 0) {
+ offset = offset * ((kMousePadding - cursor_location.x) / kMousePadding);
+ }
+
+ bool isOnScreen = true;
+ NSScreen* screen = [window_ screen];
+ if (screen &&
+ NSMinY([screen visibleFrame]) > NSMinY(window_frame) - offset) {
+ isOnScreen = false;
+ }
+
+ // If something is shown below tab contents (devtools, download shelf etc.),
+ // adjust the position to sit on top of it.
+ bool isAnyShelfVisible = NSMinY(baseFrame) > 0;
+
+ if (isOnScreen && !isAnyShelfVisible) {
+ // Cap the offset and change the visual presentation of the bubble
+ // depending on where it ends up (so that rounded corners square off
+ // and mate to the edges of the tab content).
+ if (offset >= NSHeight(window_frame)) {
+ offset = NSHeight(window_frame);
+ [[window_ contentView] setCornerFlags:
+ kRoundedBottomLeftCorner | kRoundedBottomRightCorner];
+ } else if (offset > 0) {
+ [[window_ contentView] setCornerFlags:
+ kRoundedTopRightCorner | kRoundedBottomLeftCorner |
+ kRoundedBottomRightCorner];
+ } else {
+ [[window_ contentView] setCornerFlags:kRoundedTopRightCorner];
+ }
+ window_frame.origin.y -= offset;
+ } else {
+ // Cannot move the bubble down without obscuring other content.
+ // Move it to the right instead.
+ [[window_ contentView] setCornerFlags:kRoundedTopLeftCorner];
+
+ // Subtract border width + bubble width.
+ window_frame.origin.x += NSWidth(baseFrame) - NSWidth(window_frame);
+ }
+ } else {
+ [[window_ contentView] setCornerFlags:kRoundedTopRightCorner];
+ }
+
+ [window_ setFrame:window_frame display:YES];
+}
+
+void StatusBubbleMac::UpdateDownloadShelfVisibility(bool visible) {
+}
+
+void StatusBubbleMac::Create() {
+ if (window_)
+ return;
+
+ // TODO(avi):fix this for RTL
+ NSRect window_rect = CalculateWindowFrame(/*expand=*/false);
+ // initWithContentRect has origin in screen coords and size in scaled window
+ // coordinates.
+ window_rect.size =
+ [[parent_ contentView] convertSize:window_rect.size fromView:nil];
+ window_ = [[NSWindow alloc] initWithContentRect:window_rect
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:YES];
+ [window_ setMovableByWindowBackground:NO];
+ [window_ setBackgroundColor:[NSColor clearColor]];
+ [window_ setLevel:NSNormalWindowLevel];
+ [window_ setOpaque:NO];
+ [window_ setHasShadow:NO];
+
+ // We do not need to worry about the bubble outliving |parent_| because our
+ // teardown sequence in BWC guarantees that |parent_| outlives the status
+ // bubble and that the StatusBubble is torn down completely prior to the
+ // window going away.
+ scoped_nsobject<BubbleView> view(
+ [[BubbleView alloc] initWithFrame:NSZeroRect themeProvider:parent_]);
+ [window_ setContentView:view];
+
+ [window_ setAlphaValue:0.0];
+
+ // Set a delegate for the fade-in and fade-out transitions to be notified
+ // when fades are complete. The ownership model is for window_ to own
+ // animation_dictionary, which owns animation, which owns
+ // animation_delegate.
+ CAAnimation* animation = [[window_ animationForKey:kFadeAnimationKey] copy];
+ [animation autorelease];
+ StatusBubbleAnimationDelegate* animation_delegate =
+ [[StatusBubbleAnimationDelegate alloc] initWithStatusBubble:this];
+ [animation_delegate autorelease];
+ [animation setDelegate:animation_delegate];
+ NSMutableDictionary* animation_dictionary =
+ [NSMutableDictionary dictionaryWithDictionary:[window_ animations]];
+ [animation_dictionary setObject:animation forKey:kFadeAnimationKey];
+ [window_ setAnimations:animation_dictionary];
+
+ // Don't |Attach()| since we don't know the appropriate state; let the
+ // |SetState()| call do that.
+
+ [view setCornerFlags:kRoundedTopRightCorner];
+ MouseMoved(gfx::Point(), false);
+}
+
+void StatusBubbleMac::Attach() {
+ // This method may be called several times during the process of creating or
+ // showing a status bubble to attach the bubble to its parent window.
+ if (!is_attached()) {
+ [parent_ addChildWindow:window_ ordered:NSWindowAbove];
+ UpdateSizeAndPosition();
+ }
+}
+
+void StatusBubbleMac::Detach() {
+ // This method may be called several times in the process of hiding or
+ // destroying a status bubble.
+ if (is_attached()) {
+ // Magic setFrame: See crbug.com/58506, and codereview.chromium.org/3573014
+ [window_ setFrame:CalculateWindowFrame(/*expand=*/false) display:NO];
+ [parent_ removeChildWindow:window_]; // See crbug.com/28107 ...
+ [window_ orderOut:nil]; // ... and crbug.com/29054.
+ }
+}
+
+void StatusBubbleMac::AnimationDidStop(CAAnimation* animation, bool finished) {
+ DCHECK([NSThread isMainThread]);
+ DCHECK(state_ == kBubbleShowingFadeIn || state_ == kBubbleHidingFadeOut);
+ DCHECK(is_attached());
+
+ if (finished) {
+ // Because of the mechanism used to interrupt animations, this is never
+ // actually called with finished set to false. If animations ever become
+ // directly interruptible, the check will ensure that state_ remains
+ // properly synchronized.
+ if (state_ == kBubbleShowingFadeIn) {
+ DCHECK_EQ([[window_ animator] alphaValue], kBubbleOpacity);
+ SetState(kBubbleShown);
+ } else {
+ DCHECK_EQ([[window_ animator] alphaValue], 0.0);
+ SetState(kBubbleHidden);
+ }
+ }
+}
+
+void StatusBubbleMac::SetState(StatusBubbleState state) {
+ // We must be hidden or attached, but not both.
+ DCHECK((state_ == kBubbleHidden) ^ is_attached());
+
+ if (state == state_)
+ return;
+
+ if (state == kBubbleHidden)
+ Detach();
+ else
+ Attach();
+
+ if ([delegate_ respondsToSelector:@selector(statusBubbleWillEnterState:)])
+ [delegate_ statusBubbleWillEnterState:state];
+
+ state_ = state;
+}
+
+void StatusBubbleMac::Fade(bool show) {
+ DCHECK([NSThread isMainThread]);
+
+ StatusBubbleState fade_state = kBubbleShowingFadeIn;
+ StatusBubbleState target_state = kBubbleShown;
+ NSTimeInterval full_duration = kShowFadeInDurationSeconds;
+ CGFloat opacity = kBubbleOpacity;
+
+ if (!show) {
+ fade_state = kBubbleHidingFadeOut;
+ target_state = kBubbleHidden;
+ full_duration = kHideFadeOutDurationSeconds;
+ opacity = 0.0;
+ }
+
+ DCHECK(state_ == fade_state || state_ == target_state);
+
+ if (state_ == target_state)
+ return;
+
+ if (immediate_) {
+ [window_ setAlphaValue:opacity];
+ SetState(target_state);
+ return;
+ }
+
+ // If an incomplete transition has left the opacity somewhere between 0 and
+ // kBubbleOpacity, the fade rate is kept constant by shortening the duration.
+ NSTimeInterval duration =
+ full_duration *
+ fabs(opacity - [[window_ animator] alphaValue]) / kBubbleOpacity;
+
+ // 0.0 will not cancel an in-progress animation.
+ if (duration == 0.0)
+ duration = kMinimumTimeInterval;
+
+ // This will cancel an in-progress transition and replace it with this fade.
+ [NSAnimationContext beginGrouping];
+ // Don't use the GTM additon for the "Steve" slowdown because this can happen
+ // async from user actions and the effects could be a surprise.
+ [[NSAnimationContext currentContext] setDuration:duration];
+ [[window_ animator] setAlphaValue:opacity];
+ [NSAnimationContext endGrouping];
+}
+
+void StatusBubbleMac::StartTimer(int64 delay_ms) {
+ DCHECK([NSThread isMainThread]);
+ DCHECK(state_ == kBubbleShowingTimer || state_ == kBubbleHidingTimer);
+
+ if (immediate_) {
+ TimerFired();
+ return;
+ }
+
+ // There can only be one running timer.
+ CancelTimer();
+
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ timer_factory_.NewRunnableMethod(&StatusBubbleMac::TimerFired),
+ delay_ms);
+}
+
+void StatusBubbleMac::CancelTimer() {
+ DCHECK([NSThread isMainThread]);
+
+ if (!timer_factory_.empty())
+ timer_factory_.RevokeAll();
+}
+
+void StatusBubbleMac::TimerFired() {
+ DCHECK(state_ == kBubbleShowingTimer || state_ == kBubbleHidingTimer);
+ DCHECK([NSThread isMainThread]);
+
+ if (state_ == kBubbleShowingTimer) {
+ SetState(kBubbleShowingFadeIn);
+ Fade(true);
+ } else {
+ SetState(kBubbleHidingFadeOut);
+ Fade(false);
+ }
+}
+
+void StatusBubbleMac::StartShowing() {
+ // Note that |SetState()| will |Attach()| or |Detach()| as required.
+
+ if (state_ == kBubbleHidden) {
+ // Arrange to begin fading in after a delay.
+ SetState(kBubbleShowingTimer);
+ StartTimer(kShowDelayMilliseconds);
+ } else if (state_ == kBubbleHidingFadeOut) {
+ // Cancel the fade-out in progress and replace it with a fade in.
+ SetState(kBubbleShowingFadeIn);
+ Fade(true);
+ } else if (state_ == kBubbleHidingTimer) {
+ // The bubble was already shown but was waiting to begin fading out. It's
+ // given a stay of execution.
+ SetState(kBubbleShown);
+ CancelTimer();
+ } else if (state_ == kBubbleShowingTimer) {
+ // The timer was already running but nothing was showing yet. Reaching
+ // this point means that there is a new request to show something. Start
+ // over again by resetting the timer, effectively invalidating the earlier
+ // request.
+ StartTimer(kShowDelayMilliseconds);
+ }
+
+ // If the state is kBubbleShown or kBubbleShowingFadeIn, leave everything
+ // alone.
+}
+
+void StatusBubbleMac::StartHiding() {
+ if (state_ == kBubbleShown) {
+ // Arrange to begin fading out after a delay.
+ SetState(kBubbleHidingTimer);
+ StartTimer(kHideDelayMilliseconds);
+ } else if (state_ == kBubbleShowingFadeIn) {
+ // Cancel the fade-in in progress and replace it with a fade out.
+ SetState(kBubbleHidingFadeOut);
+ Fade(false);
+ } else if (state_ == kBubbleShowingTimer) {
+ // The bubble was already hidden but was waiting to begin fading in. Too
+ // bad, it won't get the opportunity now.
+ SetState(kBubbleHidden);
+ CancelTimer();
+ }
+
+ // If the state is kBubbleHidden, kBubbleHidingFadeOut, or
+ // kBubbleHidingTimer, leave everything alone. The timer is not reset as
+ // with kBubbleShowingTimer in StartShowing() because a subsequent request
+ // to hide something while one is already in flight does not invalidate the
+ // earlier request.
+}
+
+void StatusBubbleMac::CancelExpandTimer() {
+ DCHECK([NSThread isMainThread]);
+ expand_timer_factory_.RevokeAll();
+}
+
+void StatusBubbleMac::ExpandBubble() {
+ // Calculate the width available for expanded and standard bubbles.
+ NSRect window_frame = CalculateWindowFrame(/*expand=*/true);
+ CGFloat max_bubble_width = NSWidth(window_frame);
+ CGFloat standard_bubble_width =
+ NSWidth(CalculateWindowFrame(/*expand=*/false));
+
+ // Generate the URL string that fits in the expanded bubble.
+ NSFont* font = [[window_ contentView] font];
+ gfx::Font font_chr(base::SysNSStringToWide([font fontName]),
+ [font pointSize]);
+ string16 expanded_url = gfx::ElideUrl(url_, font_chr,
+ max_bubble_width, UTF16ToWideHack(languages_));
+
+ // Scale width from gfx::Font in view coordinates to window coordinates.
+ int required_width_for_string =
+ font_chr.GetStringWidth(UTF16ToWide(expanded_url)) +
+ kTextPadding * 2 + kBubbleViewTextPositionX;
+ NSSize scaled_width = NSMakeSize(required_width_for_string, 0);
+ scaled_width = [[parent_ contentView] convertSize:scaled_width toView:nil];
+ required_width_for_string = scaled_width.width;
+
+ // The expanded width must be at least as wide as the standard width, but no
+ // wider than the maximum width for its parent frame.
+ int expanded_bubble_width =
+ std::max(standard_bubble_width,
+ std::min(max_bubble_width,
+ static_cast<CGFloat>(required_width_for_string)));
+
+ SetText(expanded_url, true);
+ is_expanded_ = true;
+ window_frame.size.width = expanded_bubble_width;
+
+ // In testing, don't do any animation.
+ if (immediate_) {
+ [window_ setFrame:window_frame display:YES];
+ return;
+ }
+
+ NSRect actual_window_frame = [window_ frame];
+ // Adjust status bubble origin if bubble was moved to the right.
+ // TODO(alekseys): fix for RTL.
+ if (NSMinX(actual_window_frame) > NSMinX(window_frame)) {
+ actual_window_frame.origin.x =
+ NSMaxX(actual_window_frame) - NSWidth(window_frame);
+ }
+ actual_window_frame.size.width = NSWidth(window_frame);
+
+ // Do not expand if it's going to cover mouse location.
+ if (NSPointInRect([NSEvent mouseLocation], actual_window_frame))
+ return;
+
+ [NSAnimationContext beginGrouping];
+ [[NSAnimationContext currentContext] setDuration:kExpansionDuration];
+ [[window_ animator] setFrame:actual_window_frame display:YES];
+ [NSAnimationContext endGrouping];
+}
+
+void StatusBubbleMac::UpdateSizeAndPosition() {
+ if (!window_)
+ return;
+
+ [window_ setFrame:CalculateWindowFrame(/*expand=*/false) display:YES];
+}
+
+void StatusBubbleMac::SwitchParentWindow(NSWindow* parent) {
+ DCHECK(parent);
+
+ // If not attached, just update our member variable and position.
+ if (!is_attached()) {
+ parent_ = parent;
+ [[window_ contentView] setThemeProvider:parent];
+ UpdateSizeAndPosition();
+ return;
+ }
+
+ Detach();
+ parent_ = parent;
+ [[window_ contentView] setThemeProvider:parent];
+ Attach();
+ UpdateSizeAndPosition();
+}
+
+NSRect StatusBubbleMac::CalculateWindowFrame(bool expanded_width) {
+ DCHECK(parent_);
+
+ NSRect screenRect;
+ if ([delegate_ respondsToSelector:@selector(statusBubbleBaseFrame)]) {
+ screenRect = [delegate_ statusBubbleBaseFrame];
+ screenRect.origin = [parent_ convertBaseToScreen:screenRect.origin];
+ } else {
+ screenRect = [parent_ frame];
+ }
+
+ NSSize size = NSMakeSize(0, kWindowHeight);
+ size = [[parent_ contentView] convertSize:size toView:nil];
+
+ if (expanded_width) {
+ size.width = screenRect.size.width;
+ } else {
+ size.width = kWindowWidthPercent * screenRect.size.width;
+ }
+
+ screenRect.size = size;
+ return screenRect;
+}
diff --git a/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm b/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm
new file mode 100644
index 0000000..5aa895a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm
@@ -0,0 +1,584 @@
+// 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.
+
+#include <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+#include "base/utf_string_conversions.h"
+#import "chrome/browser/ui/cocoa/bubble_view.h"
+#import "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/status_bubble_mac.h"
+#include "googleurl/src/gurl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+// The test delegate records all of the status bubble object's state
+// transitions.
+@interface StatusBubbleMacTestDelegate : NSObject {
+ @private
+ NSWindow* window_; // Weak.
+ NSPoint baseFrameOffset_;
+ std::vector<StatusBubbleMac::StatusBubbleState> states_;
+}
+- (id)initWithWindow:(NSWindow*)window;
+- (void)forceBaseFrameOffset:(NSPoint)baseFrameOffset;
+- (NSRect)statusBubbleBaseFrame;
+- (void)statusBubbleWillEnterState:(StatusBubbleMac::StatusBubbleState)state;
+@end
+@implementation StatusBubbleMacTestDelegate
+- (id)initWithWindow:(NSWindow*)window {
+ if ((self = [super init])) {
+ window_ = window;
+ baseFrameOffset_ = NSMakePoint(0, 0);
+ }
+ return self;
+}
+- (void)forceBaseFrameOffset:(NSPoint)baseFrameOffset {
+ baseFrameOffset_ = baseFrameOffset;
+}
+- (NSRect)statusBubbleBaseFrame {
+ NSView* contentView = [window_ contentView];
+ NSRect baseFrame = [contentView convertRect:[contentView frame] toView:nil];
+ if (baseFrameOffset_.x > 0 || baseFrameOffset_.y > 0) {
+ baseFrame = NSOffsetRect(baseFrame, baseFrameOffset_.x, baseFrameOffset_.y);
+ baseFrame.size.width -= baseFrameOffset_.x;
+ baseFrame.size.height -= baseFrameOffset_.y;
+ }
+ return baseFrame;
+}
+- (void)statusBubbleWillEnterState:(StatusBubbleMac::StatusBubbleState)state {
+ states_.push_back(state);
+}
+- (std::vector<StatusBubbleMac::StatusBubbleState>*)states {
+ return &states_;
+}
+@end
+
+// This class implements, for testing purposes, a subclass of |StatusBubbleMac|
+// whose |MouseMoved()| method does nothing. (Ideally, we'd have a way of
+// controlling the "mouse" location, but the current implementation of
+// |StatusBubbleMac| uses |[NSEvent mouseLocation]| directly.) Without this,
+// tests can be flaky since results may depend on the mouse location.
+class StatusBubbleMacIgnoreMouseMoved : public StatusBubbleMac {
+ public:
+ StatusBubbleMacIgnoreMouseMoved(NSWindow* parent, id delegate)
+ : StatusBubbleMac(parent, delegate) {}
+
+ virtual void MouseMoved(const gfx::Point& location, bool left_content) {}
+};
+
+class StatusBubbleMacTest : public CocoaTest {
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ NSWindow* window = test_window();
+ EXPECT_TRUE(window);
+ delegate_.reset(
+ [[StatusBubbleMacTestDelegate alloc] initWithWindow: window]);
+ EXPECT_TRUE(delegate_.get());
+ bubble_ = new StatusBubbleMacIgnoreMouseMoved(window, delegate_);
+ EXPECT_TRUE(bubble_);
+
+ // Turn off delays and transitions for test mode. This doesn't just speed
+ // things along, it's actually required to get StatusBubbleMac to behave
+ // synchronously, because the tests here don't know how to wait for
+ // results. This allows these tests to be much more complete with a
+ // minimal loss of coverage and without any heinous rearchitecting.
+ bubble_->immediate_ = true;
+
+ EXPECT_FALSE(bubble_->window_); // lazily creates window
+ }
+
+ virtual void TearDown() {
+ // Not using a scoped_ptr because bubble must be deleted before calling
+ // TearDown to get rid of bubble's window.
+ delete bubble_;
+ CocoaTest::TearDown();
+ }
+
+ bool IsVisible() {
+ if (![bubble_->window_ isVisible])
+ return false;
+ return [bubble_->window_ alphaValue] > 0.0;
+ }
+ NSString* GetText() {
+ return bubble_->status_text_;
+ }
+ NSString* GetURLText() {
+ return bubble_->url_text_;
+ }
+ NSString* GetBubbleViewText() {
+ BubbleView* bubbleView = [bubble_->window_ contentView];
+ return [bubbleView content];
+ }
+ NSWindow* GetWindow() {
+ return bubble_->window_;
+ }
+ NSWindow* GetParent() {
+ return bubble_->parent_;
+ }
+ StatusBubbleMac::StatusBubbleState GetState() {
+ return bubble_->state_;
+ }
+ void SetState(StatusBubbleMac::StatusBubbleState state) {
+ bubble_->SetState(state);
+ }
+ std::vector<StatusBubbleMac::StatusBubbleState>* States() {
+ return [delegate_ states];
+ }
+ StatusBubbleMac::StatusBubbleState StateAt(int index) {
+ return (*States())[index];
+ }
+ BrowserTestHelper browser_helper_;
+ scoped_nsobject<StatusBubbleMacTestDelegate> delegate_;
+ StatusBubbleMac* bubble_; // Strong.
+};
+
+TEST_F(StatusBubbleMacTest, SetStatus) {
+ bubble_->SetStatus(string16());
+ bubble_->SetStatus(UTF8ToUTF16("This is a test"));
+ EXPECT_NSEQ(@"This is a test", GetText());
+ EXPECT_TRUE(IsVisible());
+
+ // Set the status to the exact same thing again
+ bubble_->SetStatus(UTF8ToUTF16("This is a test"));
+ EXPECT_NSEQ(@"This is a test", GetText());
+
+ // Hide it
+ bubble_->SetStatus(string16());
+ EXPECT_FALSE(IsVisible());
+}
+
+TEST_F(StatusBubbleMacTest, SetURL) {
+ bubble_->SetURL(GURL(), string16());
+ EXPECT_FALSE(IsVisible());
+ bubble_->SetURL(GURL("bad url"), string16());
+ EXPECT_FALSE(IsVisible());
+ bubble_->SetURL(GURL("http://"), string16());
+ EXPECT_TRUE(IsVisible());
+ EXPECT_NSEQ(@"http:", GetURLText());
+ bubble_->SetURL(GURL("about:blank"), string16());
+ EXPECT_TRUE(IsVisible());
+ EXPECT_NSEQ(@"about:blank", GetURLText());
+ bubble_->SetURL(GURL("foopy://"), string16());
+ EXPECT_TRUE(IsVisible());
+ EXPECT_NSEQ(@"foopy://", GetURLText());
+ bubble_->SetURL(GURL("http://www.cnn.com"), string16());
+ EXPECT_TRUE(IsVisible());
+ EXPECT_NSEQ(@"www.cnn.com", GetURLText());
+}
+
+// Test hiding bubble that's already hidden.
+TEST_F(StatusBubbleMacTest, Hides) {
+ bubble_->SetStatus(UTF8ToUTF16("Showing"));
+ EXPECT_TRUE(IsVisible());
+ bubble_->Hide();
+ EXPECT_FALSE(IsVisible());
+ bubble_->Hide();
+ EXPECT_FALSE(IsVisible());
+}
+
+// Test the "main"/"backup" behavior in StatusBubbleMac::SetText().
+TEST_F(StatusBubbleMacTest, SetStatusAndURL) {
+ EXPECT_FALSE(IsVisible());
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
+ EXPECT_TRUE(IsVisible());
+ EXPECT_NSEQ(@"Status", GetBubbleViewText());
+ bubble_->SetURL(GURL("http://www.nytimes.com"), string16());
+ EXPECT_TRUE(IsVisible());
+ EXPECT_NSEQ(@"www.nytimes.com", GetBubbleViewText());
+ bubble_->SetURL(GURL(), string16());
+ EXPECT_TRUE(IsVisible());
+ EXPECT_NSEQ(@"Status", GetBubbleViewText());
+ bubble_->SetStatus(string16());
+ EXPECT_FALSE(IsVisible());
+ bubble_->SetURL(GURL("http://www.nytimes.com"), string16());
+ EXPECT_TRUE(IsVisible());
+ EXPECT_NSEQ(@"www.nytimes.com", GetBubbleViewText());
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
+ EXPECT_TRUE(IsVisible());
+ EXPECT_NSEQ(@"Status", GetBubbleViewText());
+ bubble_->SetStatus(string16());
+ EXPECT_TRUE(IsVisible());
+ EXPECT_NSEQ(@"www.nytimes.com", GetBubbleViewText());
+ bubble_->SetURL(GURL(), string16());
+ EXPECT_FALSE(IsVisible());
+}
+
+// Test that the status bubble goes through the correct delay and fade states.
+// The delay and fade duration are simulated and not actually experienced
+// during the test because StatusBubbleMacTest sets immediate_ mode.
+TEST_F(StatusBubbleMacTest, StateTransitions) {
+ // First, some sanity
+
+ EXPECT_FALSE(IsVisible());
+ EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
+
+ States()->clear();
+ EXPECT_TRUE(States()->empty());
+
+ bubble_->SetStatus(string16());
+ EXPECT_FALSE(IsVisible());
+ EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
+ EXPECT_TRUE(States()->empty()); // no change from initial kBubbleHidden state
+
+ // Next, a few ordinary cases
+
+ // Test StartShowing from kBubbleHidden
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
+ EXPECT_TRUE(IsVisible());
+ // Check GetState before checking States to make sure that all state
+ // transitions have been flushed to States.
+ EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState());
+ EXPECT_EQ(3u, States()->size());
+ EXPECT_EQ(StatusBubbleMac::kBubbleShowingTimer, StateAt(0));
+ EXPECT_EQ(StatusBubbleMac::kBubbleShowingFadeIn, StateAt(1));
+ EXPECT_EQ(StatusBubbleMac::kBubbleShown, StateAt(2));
+
+ // Test StartShowing from kBubbleShown with the same message
+ States()->clear();
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
+ EXPECT_TRUE(IsVisible());
+ EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState());
+ EXPECT_TRUE(States()->empty());
+
+ // Test StartShowing from kBubbleShown with a different message
+ bubble_->SetStatus(UTF8ToUTF16("New Status"));
+ EXPECT_TRUE(IsVisible());
+ EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState());
+ EXPECT_TRUE(States()->empty());
+
+ // Test StartHiding from kBubbleShown
+ bubble_->SetStatus(string16());
+ EXPECT_FALSE(IsVisible());
+ // Check GetState before checking States to make sure that all state
+ // transitions have been flushed to States.
+ EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
+ EXPECT_EQ(3u, States()->size());
+ EXPECT_EQ(StatusBubbleMac::kBubbleHidingTimer, StateAt(0));
+ EXPECT_EQ(StatusBubbleMac::kBubbleHidingFadeOut, StateAt(1));
+ EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(2));
+
+ // Test StartHiding from kBubbleHidden
+ States()->clear();
+ bubble_->SetStatus(string16());
+ EXPECT_FALSE(IsVisible());
+ EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
+ EXPECT_TRUE(States()->empty());
+
+ // Now, the edge cases
+
+ // Test StartShowing from kBubbleShowingTimer
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
+ SetState(StatusBubbleMac::kBubbleShowingTimer);
+ [GetWindow() setAlphaValue:0.0];
+ States()->clear();
+ EXPECT_TRUE(States()->empty());
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
+ EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState());
+ EXPECT_EQ(2u, States()->size());
+ EXPECT_EQ(StatusBubbleMac::kBubbleShowingFadeIn, StateAt(0));
+ EXPECT_EQ(StatusBubbleMac::kBubbleShown, StateAt(1));
+
+ // Test StartShowing from kBubbleShowingFadeIn
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
+ SetState(StatusBubbleMac::kBubbleShowingFadeIn);
+ [GetWindow() setAlphaValue:0.5];
+ States()->clear();
+ EXPECT_TRUE(States()->empty());
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
+ // The actual state values can't be tested in immediate_ mode because
+ // the window wasn't actually fading in. Without immediate_ mode,
+ // expect kBubbleShown.
+ bubble_->SetStatus(string16()); // Go back to a deterministic state.
+
+ // Test StartShowing from kBubbleHidingTimer
+ bubble_->SetStatus(string16());
+ SetState(StatusBubbleMac::kBubbleHidingTimer);
+ [GetWindow() setAlphaValue:1.0];
+ States()->clear();
+ EXPECT_TRUE(States()->empty());
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
+ EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState());
+ EXPECT_EQ(1u, States()->size());
+ EXPECT_EQ(StatusBubbleMac::kBubbleShown, StateAt(0));
+
+ // Test StartShowing from kBubbleHidingFadeOut
+ bubble_->SetStatus(string16());
+ SetState(StatusBubbleMac::kBubbleHidingFadeOut);
+ [GetWindow() setAlphaValue:0.5];
+ States()->clear();
+ EXPECT_TRUE(States()->empty());
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
+ EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState());
+ EXPECT_EQ(2u, States()->size());
+ EXPECT_EQ(StatusBubbleMac::kBubbleShowingFadeIn, StateAt(0));
+ EXPECT_EQ(StatusBubbleMac::kBubbleShown, StateAt(1));
+
+ // Test StartHiding from kBubbleShowingTimer
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
+ SetState(StatusBubbleMac::kBubbleShowingTimer);
+ [GetWindow() setAlphaValue:0.0];
+ States()->clear();
+ EXPECT_TRUE(States()->empty());
+ bubble_->SetStatus(string16());
+ EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
+ EXPECT_EQ(1u, States()->size());
+ EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0));
+
+ // Test StartHiding from kBubbleShowingFadeIn
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
+ SetState(StatusBubbleMac::kBubbleShowingFadeIn);
+ [GetWindow() setAlphaValue:0.5];
+ States()->clear();
+ EXPECT_TRUE(States()->empty());
+ bubble_->SetStatus(string16());
+ EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
+ EXPECT_EQ(2u, States()->size());
+ EXPECT_EQ(StatusBubbleMac::kBubbleHidingFadeOut, StateAt(0));
+ EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(1));
+
+ // Test StartHiding from kBubbleHidingTimer
+ bubble_->SetStatus(string16());
+ SetState(StatusBubbleMac::kBubbleHidingTimer);
+ [GetWindow() setAlphaValue:1.0];
+ States()->clear();
+ EXPECT_TRUE(States()->empty());
+ bubble_->SetStatus(string16());
+ // The actual state values can't be tested in immediate_ mode because
+ // the timer wasn't actually running. Without immediate_ mode, expect
+ // kBubbleHidingFadeOut and kBubbleHidden.
+ // Go back to a deterministic state.
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
+
+ // Test StartHiding from kBubbleHidingFadeOut
+ bubble_->SetStatus(string16());
+ SetState(StatusBubbleMac::kBubbleHidingFadeOut);
+ [GetWindow() setAlphaValue:0.5];
+ States()->clear();
+ EXPECT_TRUE(States()->empty());
+ bubble_->SetStatus(string16());
+ // The actual state values can't be tested in immediate_ mode because
+ // the window wasn't actually fading out. Without immediate_ mode, expect
+ // kBubbleHidden.
+ // Go back to a deterministic state.
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
+
+ // Test Hide from kBubbleHidden
+ bubble_->SetStatus(string16());
+ EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
+ States()->clear();
+ EXPECT_TRUE(States()->empty());
+ bubble_->Hide();
+ EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
+ EXPECT_TRUE(States()->empty());
+
+ // Test Hide from kBubbleShowingTimer
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
+ SetState(StatusBubbleMac::kBubbleShowingTimer);
+ [GetWindow() setAlphaValue:0.0];
+ States()->clear();
+ EXPECT_TRUE(States()->empty());
+ bubble_->Hide();
+ EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
+ EXPECT_EQ(1u, States()->size());
+ EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0));
+
+ // Test Hide from kBubbleShowingFadeIn
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
+ SetState(StatusBubbleMac::kBubbleShowingFadeIn);
+ [GetWindow() setAlphaValue:0.5];
+ States()->clear();
+ EXPECT_TRUE(States()->empty());
+ bubble_->Hide();
+ EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
+ EXPECT_EQ(2u, States()->size());
+ EXPECT_EQ(StatusBubbleMac::kBubbleHidingFadeOut, StateAt(0));
+ EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(1));
+
+ // Test Hide from kBubbleShown
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
+ States()->clear();
+ EXPECT_TRUE(States()->empty());
+ bubble_->Hide();
+ EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
+ EXPECT_EQ(1u, States()->size());
+ EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0));
+
+ // Test Hide from kBubbleHidingTimer
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
+ SetState(StatusBubbleMac::kBubbleHidingTimer);
+ States()->clear();
+ EXPECT_TRUE(States()->empty());
+ bubble_->Hide();
+ EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
+ EXPECT_EQ(1u, States()->size());
+ EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0));
+
+ // Test Hide from kBubbleHidingFadeOut
+ bubble_->SetStatus(UTF8ToUTF16("Status"));
+ SetState(StatusBubbleMac::kBubbleHidingFadeOut);
+ [GetWindow() setAlphaValue:0.5];
+ States()->clear();
+ EXPECT_TRUE(States()->empty());
+ bubble_->Hide();
+ EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
+ EXPECT_EQ(1u, States()->size());
+ EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0));
+}
+
+TEST_F(StatusBubbleMacTest, Delete) {
+ NSWindow* window = test_window();
+ // Create and delete immediately.
+ StatusBubbleMac* bubble = new StatusBubbleMac(window, nil);
+ delete bubble;
+
+ // Create then delete while visible.
+ bubble = new StatusBubbleMac(window, nil);
+ bubble->SetStatus(UTF8ToUTF16("showing"));
+ delete bubble;
+}
+
+TEST_F(StatusBubbleMacTest, UpdateSizeAndPosition) {
+ // Test |UpdateSizeAndPosition()| when status bubble does not exist (shouldn't
+ // crash; shouldn't create window).
+ EXPECT_FALSE(GetWindow());
+ bubble_->UpdateSizeAndPosition();
+ EXPECT_FALSE(GetWindow());
+
+ // Create a status bubble (with contents) and call resize (without actually
+ // resizing); the frame size shouldn't change.
+ bubble_->SetStatus(UTF8ToUTF16("UpdateSizeAndPosition test"));
+ ASSERT_TRUE(GetWindow());
+ NSRect rect_before = [GetWindow() frame];
+ bubble_->UpdateSizeAndPosition();
+ NSRect rect_after = [GetWindow() frame];
+ EXPECT_TRUE(NSEqualRects(rect_before, rect_after));
+
+ // Move the window and call resize; only the origin should change.
+ NSWindow* window = test_window();
+ ASSERT_TRUE(window);
+ NSRect frame = [window frame];
+ rect_before = [GetWindow() frame];
+ frame.origin.x += 10.0; // (fairly arbitrary nonzero value)
+ frame.origin.y += 10.0; // (fairly arbitrary nonzero value)
+ [window setFrame:frame display:YES];
+ bubble_->UpdateSizeAndPosition();
+ rect_after = [GetWindow() frame];
+ EXPECT_NE(rect_before.origin.x, rect_after.origin.x);
+ EXPECT_NE(rect_before.origin.y, rect_after.origin.y);
+ EXPECT_EQ(rect_before.size.width, rect_after.size.width);
+ EXPECT_EQ(rect_before.size.height, rect_after.size.height);
+
+ // Resize the window (without moving). The origin shouldn't change. The width
+ // should change (in the current implementation), but not the height.
+ frame = [window frame];
+ rect_before = [GetWindow() frame];
+ frame.size.width += 50.0; // (fairly arbitrary nonzero value)
+ frame.size.height += 50.0; // (fairly arbitrary nonzero value)
+ [window setFrame:frame display:YES];
+ bubble_->UpdateSizeAndPosition();
+ rect_after = [GetWindow() frame];
+ EXPECT_EQ(rect_before.origin.x, rect_after.origin.x);
+ EXPECT_EQ(rect_before.origin.y, rect_after.origin.y);
+ EXPECT_NE(rect_before.size.width, rect_after.size.width);
+ EXPECT_EQ(rect_before.size.height, rect_after.size.height);
+}
+
+TEST_F(StatusBubbleMacTest, MovingWindowUpdatesPosition) {
+ NSWindow* window = test_window();
+
+ // Show the bubble and make sure it has the same origin as |window|.
+ bubble_->SetStatus(UTF8ToUTF16("Showing"));
+ NSWindow* child = GetWindow();
+ EXPECT_TRUE(NSEqualPoints([window frame].origin, [child frame].origin));
+
+ // Hide the bubble, move the window, and show it again.
+ bubble_->Hide();
+ NSRect frame = [window frame];
+ frame.origin.x += 50;
+ [window setFrame:frame display:YES];
+ bubble_->SetStatus(UTF8ToUTF16("Reshowing"));
+
+ // The bubble should reattach in the correct location.
+ child = GetWindow();
+ EXPECT_TRUE(NSEqualPoints([window frame].origin, [child frame].origin));
+}
+
+TEST_F(StatusBubbleMacTest, StatuBubbleRespectsBaseFrameLimits) {
+ NSWindow* window = test_window();
+
+ // Show the bubble and make sure it has the same origin as |window|.
+ bubble_->SetStatus(UTF8ToUTF16("Showing"));
+ NSWindow* child = GetWindow();
+ EXPECT_TRUE(NSEqualPoints([window frame].origin, [child frame].origin));
+
+ // Hide the bubble, change base frame offset, and show it again.
+ bubble_->Hide();
+
+ NSPoint baseFrameOffset = NSMakePoint(0, [window frame].size.height / 3);
+ EXPECT_GT(baseFrameOffset.y, 0);
+ [delegate_ forceBaseFrameOffset:baseFrameOffset];
+
+ bubble_->SetStatus(UTF8ToUTF16("Reshowing"));
+
+ // The bubble should reattach in the correct location.
+ child = GetWindow();
+ NSPoint expectedOrigin = [window frame].origin;
+ expectedOrigin.x += baseFrameOffset.x;
+ expectedOrigin.y += baseFrameOffset.y;
+ EXPECT_TRUE(NSEqualPoints(expectedOrigin, [child frame].origin));
+}
+
+TEST_F(StatusBubbleMacTest, ExpandBubble) {
+ NSWindow* window = test_window();
+ ASSERT_TRUE(window);
+ NSRect window_frame = [window frame];
+ window_frame.size.width = 600.0;
+ [window setFrame:window_frame display:YES];
+
+ // Check basic expansion
+ bubble_->SetStatus(UTF8ToUTF16("Showing"));
+ EXPECT_TRUE(IsVisible());
+ bubble_->SetURL(GURL("http://www.battersbox.com/peter_paul_and_mary.html"),
+ string16());
+ EXPECT_TRUE([GetURLText() hasSuffix:@"\u2026"]);
+ bubble_->ExpandBubble();
+ EXPECT_TRUE(IsVisible());
+ EXPECT_NSEQ(@"www.battersbox.com/peter_paul_and_mary.html", GetURLText());
+ bubble_->Hide();
+
+ // Make sure bubble resets after hide.
+ bubble_->SetStatus(UTF8ToUTF16("Showing"));
+ bubble_->SetURL(GURL("http://www.snickersnee.com/pioneer_fishstix.html"),
+ string16());
+ EXPECT_TRUE([GetURLText() hasSuffix:@"\u2026"]);
+ // ...and that it expands again properly.
+ bubble_->ExpandBubble();
+ EXPECT_NSEQ(@"www.snickersnee.com/pioneer_fishstix.html", GetURLText());
+ // ...again, again!
+ bubble_->SetURL(GURL("http://www.battersbox.com/peter_paul_and_mary.html"),
+ string16());
+ bubble_->ExpandBubble();
+ EXPECT_NSEQ(@"www.battersbox.com/peter_paul_and_mary.html", GetURLText());
+ bubble_->Hide();
+
+ window_frame = [window frame];
+ window_frame.size.width = 300.0;
+ [window setFrame:window_frame display:YES];
+
+ // Very long URL's will be cut off even in the expanded state.
+ bubble_->SetStatus(UTF8ToUTF16("Showing"));
+ const char veryLongUrl[] =
+ "http://www.diewahrscheinlichlaengstepralinederwelt.com/duuuuplo.html";
+ bubble_->SetURL(GURL(veryLongUrl), string16());
+ EXPECT_TRUE([GetURLText() hasSuffix:@"\u2026"]);
+ bubble_->ExpandBubble();
+ EXPECT_TRUE([GetURLText() hasSuffix:@"\u2026"]);
+}
+
+
diff --git a/chrome/browser/ui/cocoa/status_icons/status_icon_mac.h b/chrome/browser/ui/cocoa/status_icons/status_icon_mac.h
new file mode 100644
index 0000000..c414ec9
--- /dev/null
+++ b/chrome/browser/ui/cocoa/status_icons/status_icon_mac.h
@@ -0,0 +1,44 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_STATUS_ICONS_STATUS_ICON_MAC_H_
+#define CHROME_BROWSER_UI_COCOA_STATUS_ICONS_STATUS_ICON_MAC_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+#include "base/string16.h"
+#include "chrome/browser/status_icons/status_icon.h"
+
+class SkBitmap;
+@class NSStatusItem;
+@class StatusItemController;
+
+class StatusIconMac : public StatusIcon {
+ public:
+ StatusIconMac();
+ virtual ~StatusIconMac();
+
+ // Overridden from StatusIcon
+ virtual void SetImage(const SkBitmap& image);
+ virtual void SetPressedImage(const SkBitmap& image);
+ virtual void SetToolTip(const string16& tool_tip);
+
+ protected:
+ // Overridden from StatusIcon.
+ virtual void UpdatePlatformContextMenu(menus::MenuModel* menu);
+
+ private:
+ // Getter for item_ that allows lazy initialization.
+ NSStatusItem* item();
+ scoped_nsobject<NSStatusItem> item_;
+
+ scoped_nsobject<StatusItemController> controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(StatusIconMac);
+};
+
+
+#endif // CHROME_BROWSER_UI_COCOA_STATUS_ICONS_STATUS_ICON_MAC_H_
diff --git a/chrome/browser/ui/cocoa/status_icons/status_icon_mac.mm b/chrome/browser/ui/cocoa/status_icons/status_icon_mac.mm
new file mode 100644
index 0000000..3f3d5a1
--- /dev/null
+++ b/chrome/browser/ui/cocoa/status_icons/status_icon_mac.mm
@@ -0,0 +1,82 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/status_icons/status_icon_mac.h"
+
+#include "base/logging.h"
+#include "base/sys_string_conversions.h"
+#include "skia/ext/skia_utils_mac.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+@interface StatusItemController : NSObject {
+ StatusIconMac* statusIcon_; // weak
+}
+- initWithIcon:(StatusIconMac*)icon;
+- (void)handleClick:(id)sender;
+
+@end // @interface StatusItemController
+
+@implementation StatusItemController
+
+- (id)initWithIcon:(StatusIconMac*)icon {
+ statusIcon_ = icon;
+ return self;
+}
+
+- (void)handleClick:(id)sender {
+ // Pass along the click notification to our owner.
+ DCHECK(statusIcon_);
+ statusIcon_->DispatchClickEvent();
+}
+
+@end
+
+StatusIconMac::StatusIconMac()
+ : item_(NULL) {
+ controller_.reset([[StatusItemController alloc] initWithIcon:this]);
+}
+
+StatusIconMac::~StatusIconMac() {
+ // Remove the status item from the status bar.
+ if (item_)
+ [[NSStatusBar systemStatusBar] removeStatusItem:item_];
+}
+
+NSStatusItem* StatusIconMac::item() {
+ if (!item_.get()) {
+ // Create a new status item.
+ item_.reset([[[NSStatusBar systemStatusBar]
+ statusItemWithLength:NSSquareStatusItemLength] retain]);
+ [item_ setEnabled:YES];
+ [item_ setTarget:controller_];
+ [item_ setAction:@selector(handleClick:)];
+ [item_ setHighlightMode:YES];
+ }
+ return item_.get();
+}
+
+void StatusIconMac::SetImage(const SkBitmap& bitmap) {
+ if (!bitmap.isNull()) {
+ NSImage* image = gfx::SkBitmapToNSImage(bitmap);
+ if (image)
+ [item() setImage:image];
+ }
+}
+
+void StatusIconMac::SetPressedImage(const SkBitmap& bitmap) {
+ if (!bitmap.isNull()) {
+ NSImage* image = gfx::SkBitmapToNSImage(bitmap);
+ if (image)
+ [item() setAlternateImage:image];
+ }
+}
+
+void StatusIconMac::SetToolTip(const string16& tool_tip) {
+ [item() setToolTip:base::SysUTF16ToNSString(tool_tip)];
+}
+
+void StatusIconMac::UpdatePlatformContextMenu(menus::MenuModel* menu) {
+ // TODO(atwilson): Add support for context menus for Mac when actually needed
+ // (not yet used by anything) - http://crbug.com/37375.
+}
diff --git a/chrome/browser/ui/cocoa/status_icons/status_icon_mac_unittest.mm b/chrome/browser/ui/cocoa/status_icons/status_icon_mac_unittest.mm
new file mode 100644
index 0000000..45d1950
--- /dev/null
+++ b/chrome/browser/ui/cocoa/status_icons/status_icon_mac_unittest.mm
@@ -0,0 +1,30 @@
+// 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.
+
+#include "app/resource_bundle.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/cocoa/status_icons/status_icon_mac.h"
+#include "grit/browser_resources.h"
+#include "grit/theme_resources.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class SkBitmap;
+
+class StatusIconMacTest : public CocoaTest {
+};
+
+TEST_F(StatusIconMacTest, Create) {
+ // Create an icon, set the tool tip, then shut it down (checks for leaks).
+ scoped_ptr<StatusIcon> icon(new StatusIconMac());
+ SkBitmap* bitmap = ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_STATUS_TRAY_ICON);
+ icon->SetImage(*bitmap);
+ SkBitmap* pressed = ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_STATUS_TRAY_ICON_PRESSED);
+ icon->SetPressedImage(*pressed);
+ icon->SetToolTip(ASCIIToUTF16("tool tip"));
+}
diff --git a/chrome/browser/ui/cocoa/status_icons/status_tray_mac.h b/chrome/browser/ui/cocoa/status_icons/status_tray_mac.h
new file mode 100644
index 0000000..0b8326f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/status_icons/status_tray_mac.h
@@ -0,0 +1,24 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_STATUS_ICONS_STATUS_TRAY_MAC_H_
+#define CHROME_BROWSER_UI_COCOA_STATUS_ICONS_STATUS_TRAY_MAC_H_
+#pragma once
+
+#include "chrome/browser/status_icons/status_tray.h"
+
+class StatusTrayMac : public StatusTray {
+ public:
+ StatusTrayMac();
+
+ protected:
+ // Factory method for creating a status icon.
+ virtual StatusIcon* CreatePlatformStatusIcon();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(StatusTrayMac);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_STATUS_ICONS_STATUS_TRAY_MAC_H_
+
diff --git a/chrome/browser/ui/cocoa/status_icons/status_tray_mac.mm b/chrome/browser/ui/cocoa/status_icons/status_tray_mac.mm
new file mode 100644
index 0000000..5d6c3e2
--- /dev/null
+++ b/chrome/browser/ui/cocoa/status_icons/status_tray_mac.mm
@@ -0,0 +1,18 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/status_icons/status_tray_mac.h"
+
+#include "chrome/browser/ui/cocoa/status_icons/status_icon_mac.h"
+
+StatusTray* StatusTray::Create() {
+ return new StatusTrayMac();
+}
+
+StatusTrayMac::StatusTrayMac() {
+}
+
+StatusIcon* StatusTrayMac::CreatePlatformStatusIcon() {
+ return new StatusIconMac();
+}
diff --git a/chrome/browser/cocoa/styled_text_field.h b/chrome/browser/ui/cocoa/styled_text_field.h
index 68a65b7..68a65b7 100644
--- a/chrome/browser/cocoa/styled_text_field.h
+++ b/chrome/browser/ui/cocoa/styled_text_field.h
diff --git a/chrome/browser/ui/cocoa/styled_text_field.mm b/chrome/browser/ui/cocoa/styled_text_field.mm
new file mode 100644
index 0000000..31dd3a7
--- /dev/null
+++ b/chrome/browser/ui/cocoa/styled_text_field.mm
@@ -0,0 +1,61 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/styled_text_field.h"
+
+#include "base/logging.h"
+#import "chrome/browser/ui/cocoa/styled_text_field_cell.h"
+
+@implementation StyledTextField
+
+- (StyledTextFieldCell*)styledTextFieldCell {
+ DCHECK([[self cell] isKindOfClass:[StyledTextFieldCell class]]);
+ return static_cast<StyledTextFieldCell*>([self cell]);
+}
+
+// Cocoa text fields are edited by placing an NSTextView as subview,
+// positioned by the cell's -editWithFrame:inView:... method. Using
+// the standard -makeFirstResponder: machinery to reposition the field
+// editor results in resetting the field editor's editing state, which
+// AutocompleteEditViewMac monitors. This causes problems because
+// editing can require the field editor to be repositioned, which
+// could disrupt editing. This code repositions the subview directly,
+// which causes no editing-state changes.
+- (void)resetFieldEditorFrameIfNeeded {
+ // No action if not editing.
+ NSText* editor = [self currentEditor];
+ if (!editor) {
+ return;
+ }
+
+ // When editing, we should have exactly one subview, which is a
+ // clipview containing the editor (for purposes of scrolling).
+ NSArray* subviews = [self subviews];
+ DCHECK_EQ([subviews count], 1U);
+ DCHECK([editor isDescendantOf:self]);
+ if ([subviews count] == 0) {
+ return;
+ }
+
+ // If the frame is already right, don't make any visible changes.
+ StyledTextFieldCell* cell = [self styledTextFieldCell];
+ const NSRect frame([cell drawingRectForBounds:[self bounds]]);
+ NSView* subview = [subviews objectAtIndex:0];
+ if (NSEqualRects(frame, [subview frame])) {
+ return;
+ }
+
+ [subview setFrame:frame];
+
+ // Make sure the selection remains visible.
+ [editor scrollRangeToVisible:[editor selectedRange]];
+}
+
+- (CGFloat)availableDecorationWidth {
+ NSAttributedString* as = [self attributedStringValue];
+ const NSSize size([as size]);
+ const NSRect bounds([self bounds]);
+ return NSWidth(bounds) - size.width;
+}
+@end
diff --git a/chrome/browser/ui/cocoa/styled_text_field_cell.h b/chrome/browser/ui/cocoa/styled_text_field_cell.h
new file mode 100644
index 0000000..55fed3c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/styled_text_field_cell.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_STYLED_TEXT_FIELD_CELL_H_
+#define CHROME_BROWSER_UI_COCOA_STYLED_TEXT_FIELD_CELL_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+typedef enum {
+ StyledTextFieldCellRoundedAll = 0,
+ StyledTextFieldCellRoundedLeft = 1
+} StyledTextFieldCellRoundedFlags;
+
+// StyledTextFieldCell customizes the look of the standard Cocoa text field.
+// The border and focus ring are modified, as is the font baseline. Subclasses
+// can override |drawInteriorWithFrame:inView:| to provide custom drawing for
+// decorations, but they must make sure to call the superclass' implementation
+// with a modified frame after performing any custom drawing.
+
+@interface StyledTextFieldCell : NSTextFieldCell {
+}
+
+@end
+
+// Methods intended to be overridden by subclasses, not part of the public API
+// and should not be called outside of subclasses.
+@interface StyledTextFieldCell (ProtectedMethods)
+
+// Return the portion of the cell to show the text cursor over. The default
+// implementation returns the full |cellFrame|. Subclasses should override this
+// method if they add any decorations.
+- (NSRect)textCursorFrameForFrame:(NSRect)cellFrame;
+
+// Return the portion of the cell to use for text display. This corresponds to
+// the frame with our added decorations sliced off. The default implementation
+// returns the full |cellFrame|, as by default there are no decorations.
+// Subclasses should override this method if they add any decorations.
+- (NSRect)textFrameForFrame:(NSRect)cellFrame;
+
+// Baseline adjust for the text in this cell. Defaults to 0. Subclasses should
+// override as needed.
+- (CGFloat)baselineAdjust;
+
+// Radius of the corners of the field. Defaults to square corners (0.0).
+- (CGFloat)cornerRadius;
+
+// Which corners of the field to round. Defaults to RoundedAll.
+- (StyledTextFieldCellRoundedFlags)roundedFlags;
+
+// Returns YES if a light themed bezel should be drawn under the text field.
+// Default implementation returns NO.
+- (BOOL)shouldDrawBezel;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_STYLED_TEXT_FIELD_CELL_H_
diff --git a/chrome/browser/ui/cocoa/styled_text_field_cell.mm b/chrome/browser/ui/cocoa/styled_text_field_cell.mm
new file mode 100644
index 0000000..56b0cf3
--- /dev/null
+++ b/chrome/browser/ui/cocoa/styled_text_field_cell.mm
@@ -0,0 +1,217 @@
+// 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 "chrome/browser/ui/cocoa/styled_text_field_cell.h"
+
+#include "app/resource_bundle.h"
+#include "base/logging.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
+#import "chrome/browser/ui/cocoa/themed_window.h"
+#include "gfx/font.h"
+#include "grit/theme_resources.h"
+#import "third_party/GTM/AppKit/GTMNSBezierPath+RoundRect.h"
+
+namespace {
+
+NSBezierPath* RectPathWithInset(StyledTextFieldCellRoundedFlags roundedFlags,
+ const NSRect frame,
+ const CGFloat inset,
+ const CGFloat outerRadius) {
+ NSRect insetFrame = NSInsetRect(frame, inset, inset);
+
+ if (outerRadius > 0.0) {
+ CGFloat leftRadius = outerRadius - inset;
+ CGFloat rightRadius =
+ (roundedFlags == StyledTextFieldCellRoundedLeft) ? 0 : leftRadius;
+
+ return [NSBezierPath gtm_bezierPathWithRoundRect:insetFrame
+ topLeftCornerRadius:leftRadius
+ topRightCornerRadius:rightRadius
+ bottomLeftCornerRadius:leftRadius
+ bottomRightCornerRadius:rightRadius];
+ } else {
+ return [NSBezierPath bezierPathWithRect:insetFrame];
+ }
+}
+
+// Similar to |NSRectFill()|, additionally sets |color| as the fill
+// color. |outerRadius| greater than 0.0 uses rounded corners, with
+// inset backed out of the radius.
+void FillRectWithInset(StyledTextFieldCellRoundedFlags roundedFlags,
+ const NSRect frame,
+ const CGFloat inset,
+ const CGFloat outerRadius,
+ NSColor* color) {
+ NSBezierPath* path =
+ RectPathWithInset(roundedFlags, frame, inset, outerRadius);
+ [color setFill];
+ [path fill];
+}
+
+// Similar to |NSFrameRectWithWidth()|, additionally sets |color| as
+// the stroke color (as opposed to the fill color). |outerRadius|
+// greater than 0.0 uses rounded corners, with inset backed out of the
+// radius.
+void FrameRectWithInset(StyledTextFieldCellRoundedFlags roundedFlags,
+ const NSRect frame,
+ const CGFloat inset,
+ const CGFloat outerRadius,
+ const CGFloat lineWidth,
+ NSColor* color) {
+ const CGFloat finalInset = inset + (lineWidth / 2.0);
+ NSBezierPath* path =
+ RectPathWithInset(roundedFlags, frame, finalInset, outerRadius);
+ [color setStroke];
+ [path setLineWidth:lineWidth];
+ [path stroke];
+}
+
+// TODO(shess): Maybe we need a |cocoa_util.h|?
+class ScopedSaveGraphicsState {
+ public:
+ ScopedSaveGraphicsState()
+ : context_([NSGraphicsContext currentContext]) {
+ [context_ saveGraphicsState];
+ }
+ explicit ScopedSaveGraphicsState(NSGraphicsContext* context)
+ : context_(context) {
+ [context_ saveGraphicsState];
+ }
+ ~ScopedSaveGraphicsState() {
+ [context_ restoreGraphicsState];
+ }
+
+private:
+ NSGraphicsContext* context_;
+};
+
+} // namespace
+
+@implementation StyledTextFieldCell
+
+- (CGFloat)baselineAdjust {
+ return 0.0;
+}
+
+- (CGFloat)cornerRadius {
+ return 0.0;
+}
+
+- (StyledTextFieldCellRoundedFlags)roundedFlags {
+ return StyledTextFieldCellRoundedAll;
+}
+
+- (BOOL)shouldDrawBezel {
+ return NO;
+}
+
+// Returns the same value as textCursorFrameForFrame, but does not call it
+// directly to avoid potential infinite loops.
+- (NSRect)textFrameForFrame:(NSRect)cellFrame {
+ return NSInsetRect(cellFrame, 0, [self baselineAdjust]);
+}
+
+// Returns the same value as textFrameForFrame, but does not call it directly to
+// avoid potential infinite loops.
+- (NSRect)textCursorFrameForFrame:(NSRect)cellFrame {
+ return NSInsetRect(cellFrame, 0, [self baselineAdjust]);
+}
+
+// Override to show the I-beam cursor only in the area given by
+// |textCursorFrameForFrame:|.
+- (void)resetCursorRect:(NSRect)cellFrame inView:(NSView *)controlView {
+ [super resetCursorRect:[self textCursorFrameForFrame:cellFrame]
+ inView:controlView];
+}
+
+// For NSTextFieldCell this is the area within the borders. For our
+// purposes, we count the info decorations as being part of the
+// border.
+- (NSRect)drawingRectForBounds:(NSRect)theRect {
+ return [super drawingRectForBounds:[self textFrameForFrame:theRect]];
+}
+
+// TODO(shess): This code is manually drawing the cell's border area,
+// but otherwise the cell assumes -setBordered:YES for purposes of
+// calculating things like the editing area. This is probably
+// incorrect. I know that this affects -drawingRectForBounds:.
+- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
+ DCHECK([controlView isFlipped]);
+ StyledTextFieldCellRoundedFlags roundedFlags = [self roundedFlags];
+
+ // TODO(shess): This inset is also reflected by |kFieldVisualInset|
+ // in autocomplete_popup_view_mac.mm.
+ const NSRect frame = NSInsetRect(cellFrame, 0, 1);
+ const CGFloat radius = [self cornerRadius];
+
+ // Paint button background image if there is one (otherwise the border won't
+ // look right).
+ BrowserThemeProvider* themeProvider =
+ static_cast<BrowserThemeProvider*>([[controlView window] themeProvider]);
+ if (themeProvider) {
+ NSColor* backgroundImageColor =
+ themeProvider->GetNSImageColorNamed(IDR_THEME_BUTTON_BACKGROUND, false);
+ if (backgroundImageColor) {
+ // Set the phase to match window.
+ NSRect trueRect = [controlView convertRect:cellFrame toView:nil];
+ NSPoint midPoint = NSMakePoint(NSMinX(trueRect), NSMaxY(trueRect));
+ [[NSGraphicsContext currentContext] setPatternPhase:midPoint];
+
+ // NOTE(shess): This seems like it should be using a 0.0 inset,
+ // but AFAICT using a 0.5 inset is important in mixing the
+ // toolbar background and the omnibox background.
+ FillRectWithInset(roundedFlags, frame, 0.5, radius, backgroundImageColor);
+ }
+
+ // Draw the outer stroke (over the background).
+ BOOL active = [[controlView window] isMainWindow];
+ NSColor* strokeColor = themeProvider->GetNSColor(
+ active ? BrowserThemeProvider::COLOR_TOOLBAR_BUTTON_STROKE :
+ BrowserThemeProvider::COLOR_TOOLBAR_BUTTON_STROKE_INACTIVE,
+ true);
+ FrameRectWithInset(roundedFlags, frame, 0.0, radius, 1.0, strokeColor);
+ }
+
+ // Fill interior with background color.
+ FillRectWithInset(roundedFlags, frame, 1.0, radius, [self backgroundColor]);
+
+ // Draw the shadow. For the rounded-rect case, the shadow needs to
+ // slightly turn in at the corners. |shadowFrame| is at the same
+ // midline as the inner border line on the top and left, but at the
+ // outer border line on the bottom and right. The clipping change
+ // will clip the bottom and right edges (and corner).
+ {
+ ScopedSaveGraphicsState state;
+ [RectPathWithInset(roundedFlags, frame, 1.0, radius) addClip];
+ const NSRect shadowFrame = NSOffsetRect(frame, 0.5, 0.5);
+ NSColor* shadowShade = [NSColor colorWithCalibratedWhite:0.0 alpha:0.05];
+ FrameRectWithInset(roundedFlags, shadowFrame, 0.5, radius - 0.5,
+ 1.0, shadowShade);
+ }
+
+ // Draw optional bezel below bottom stroke.
+ if ([self shouldDrawBezel] && themeProvider &&
+ themeProvider->UsingDefaultTheme()) {
+
+ [themeProvider->GetNSColor(
+ BrowserThemeProvider::COLOR_TOOLBAR_BEZEL, true) set];
+ NSRect bezelRect = NSMakeRect(cellFrame.origin.x,
+ NSMaxY(cellFrame) - 0.5,
+ NSWidth(cellFrame),
+ 1.0);
+ bezelRect = NSInsetRect(bezelRect, radius - 0.5, 0.0);
+ NSRectFill(bezelRect);
+ }
+
+ // Draw the focus ring if needed.
+ if ([self showsFirstResponder]) {
+ NSColor* color =
+ [[NSColor keyboardFocusIndicatorColor] colorWithAlphaComponent:0.5];
+ FrameRectWithInset(roundedFlags, frame, 0.0, radius, 2.0, color);
+ }
+
+ [self drawInteriorWithFrame:cellFrame inView:controlView];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/styled_text_field_cell_unittest.mm b/chrome/browser/ui/cocoa/styled_text_field_cell_unittest.mm
new file mode 100644
index 0000000..2df3c65
--- /dev/null
+++ b/chrome/browser/ui/cocoa/styled_text_field_cell_unittest.mm
@@ -0,0 +1,93 @@
+// Copyright (c) 2009 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 "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/styled_text_field_cell.h"
+#import "chrome/browser/ui/cocoa/styled_text_field_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+// Width of the field so that we don't have to ask |field_| for it all
+// the time.
+const CGFloat kWidth(300.0);
+
+class StyledTextFieldCellTest : public CocoaTest {
+ public:
+ StyledTextFieldCellTest() {
+ // Make sure this is wide enough to play games with the cell
+ // decorations.
+ const NSRect frame = NSMakeRect(0, 0, kWidth, 30);
+
+ scoped_nsobject<StyledTextFieldTestCell> cell(
+ [[StyledTextFieldTestCell alloc] initTextCell:@"Testing"]);
+ cell_ = cell.get();
+ [cell_ setEditable:YES];
+ [cell_ setBordered:YES];
+
+ scoped_nsobject<NSTextField> view(
+ [[NSTextField alloc] initWithFrame:frame]);
+ view_ = view.get();
+ [view_ setCell:cell_];
+
+ [[test_window() contentView] addSubview:view_];
+ }
+
+ NSTextField* view_;
+ StyledTextFieldTestCell* cell_;
+};
+
+// Basic view tests (AddRemove, Display).
+TEST_VIEW(StyledTextFieldCellTest, view_);
+
+// Test drawing, mostly to ensure nothing leaks or crashes.
+TEST_F(StyledTextFieldCellTest, FocusedDisplay) {
+ [view_ display];
+
+ // Test focused drawing.
+ [test_window() makePretendKeyWindowAndSetFirstResponder:view_];
+ [view_ display];
+ [test_window() clearPretendKeyWindowAndFirstResponder];
+
+ // Test display of various cell configurations.
+ [cell_ setLeftMargin:5];
+ [view_ display];
+
+ [cell_ setRightMargin:15];
+ [view_ display];
+}
+
+// The editor frame should be slightly inset from the text frame.
+TEST_F(StyledTextFieldCellTest, DrawingRectForBounds) {
+ const NSRect bounds = [view_ bounds];
+ NSRect textFrame = [cell_ textFrameForFrame:bounds];
+ NSRect drawingRect = [cell_ drawingRectForBounds:bounds];
+
+ EXPECT_FALSE(NSIsEmptyRect(drawingRect));
+ EXPECT_TRUE(NSContainsRect(textFrame, NSInsetRect(drawingRect, 1, 1)));
+
+ [cell_ setLeftMargin:10];
+ textFrame = [cell_ textFrameForFrame:bounds];
+ drawingRect = [cell_ drawingRectForBounds:bounds];
+ EXPECT_FALSE(NSIsEmptyRect(drawingRect));
+ EXPECT_TRUE(NSContainsRect(textFrame, NSInsetRect(drawingRect, 1, 1)));
+
+ [cell_ setRightMargin:20];
+ textFrame = [cell_ textFrameForFrame:bounds];
+ drawingRect = [cell_ drawingRectForBounds:bounds];
+ EXPECT_FALSE(NSIsEmptyRect(drawingRect));
+ EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect));
+
+ [cell_ setLeftMargin:0];
+ textFrame = [cell_ textFrameForFrame:bounds];
+ drawingRect = [cell_ drawingRectForBounds:bounds];
+ EXPECT_FALSE(NSIsEmptyRect(drawingRect));
+ EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect));
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/styled_text_field_test_helper.h b/chrome/browser/ui/cocoa/styled_text_field_test_helper.h
new file mode 100644
index 0000000..eb90cbf
--- /dev/null
+++ b/chrome/browser/ui/cocoa/styled_text_field_test_helper.h
@@ -0,0 +1,16 @@
+// Copyright (c) 2009 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>
+#import "chrome/browser/ui/cocoa/styled_text_field_cell.h"
+
+// Subclass of StyledTextFieldCell that allows you to slice off sections on the
+// left and right of the cell.
+@interface StyledTextFieldTestCell : StyledTextFieldCell {
+ CGFloat leftMargin_;
+ CGFloat rightMargin_;
+}
+@property (nonatomic, assign) CGFloat leftMargin;
+@property (nonatomic, assign) CGFloat rightMargin;
+@end
diff --git a/chrome/browser/ui/cocoa/styled_text_field_test_helper.mm b/chrome/browser/ui/cocoa/styled_text_field_test_helper.mm
new file mode 100644
index 0000000..20f566d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/styled_text_field_test_helper.mm
@@ -0,0 +1,18 @@
+// Copyright (c) 2009 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>
+#import "chrome/browser/ui/cocoa/styled_text_field_test_helper.h"
+
+@implementation StyledTextFieldTestCell
+@synthesize leftMargin = leftMargin_;
+@synthesize rightMargin = rightMargin_;
+
+- (NSRect)textFrameForFrame:(NSRect)frame {
+ NSRect textFrame = [super textFrameForFrame:frame];
+ textFrame.origin.x += leftMargin_;
+ textFrame.size.width -= (leftMargin_ + rightMargin_);
+ return textFrame;
+}
+@end
diff --git a/chrome/browser/ui/cocoa/styled_text_field_unittest.mm b/chrome/browser/ui/cocoa/styled_text_field_unittest.mm
new file mode 100644
index 0000000..6ca36bc
--- /dev/null
+++ b/chrome/browser/ui/cocoa/styled_text_field_unittest.mm
@@ -0,0 +1,198 @@
+// Copyright (c) 2009 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>
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/styled_text_field.h"
+#import "chrome/browser/ui/cocoa/styled_text_field_cell.h"
+#import "chrome/browser/ui/cocoa/styled_text_field_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+
+namespace {
+
+// Width of the field so that we don't have to ask |field_| for it all
+// the time.
+static const CGFloat kWidth(300.0);
+
+class StyledTextFieldTest : public CocoaTest {
+ public:
+ StyledTextFieldTest() {
+ // Make sure this is wide enough to play games with the cell
+ // decorations.
+ NSRect frame = NSMakeRect(0, 0, kWidth, 30);
+
+ scoped_nsobject<StyledTextFieldTestCell> cell(
+ [[StyledTextFieldTestCell alloc] initTextCell:@"Testing"]);
+ cell_ = cell.get();
+ [cell_ setEditable:YES];
+ [cell_ setBordered:YES];
+
+ scoped_nsobject<StyledTextField> field(
+ [[StyledTextField alloc] initWithFrame:frame]);
+ field_ = field.get();
+ [field_ setCell:cell_];
+
+ [[test_window() contentView] addSubview:field_];
+ }
+
+ // Helper to return the field-editor frame being used w/in |field_|.
+ NSRect EditorFrame() {
+ EXPECT_TRUE([field_ currentEditor]);
+ EXPECT_EQ([[field_ subviews] count], 1U);
+ if ([[field_ subviews] count] > 0) {
+ return [[[field_ subviews] objectAtIndex:0] frame];
+ } else {
+ // Return something which won't work so the caller can soldier
+ // on.
+ return NSZeroRect;
+ }
+ }
+
+ StyledTextField* field_;
+ StyledTextFieldTestCell* cell_;
+};
+
+// Basic view tests (AddRemove, Display).
+TEST_VIEW(StyledTextFieldTest, field_);
+
+// Test that we get the same cell from -cell and
+// -styledTextFieldCell.
+TEST_F(StyledTextFieldTest, Cell) {
+ StyledTextFieldCell* cell = [field_ styledTextFieldCell];
+ EXPECT_EQ(cell, [field_ cell]);
+ EXPECT_TRUE(cell != nil);
+}
+
+// Test that becoming first responder sets things up correctly.
+TEST_F(StyledTextFieldTest, FirstResponder) {
+ EXPECT_EQ(nil, [field_ currentEditor]);
+ EXPECT_EQ([[field_ subviews] count], 0U);
+ [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
+ EXPECT_FALSE(nil == [field_ currentEditor]);
+ EXPECT_EQ([[field_ subviews] count], 1U);
+ EXPECT_TRUE([[field_ currentEditor] isDescendantOf:field_]);
+}
+
+TEST_F(StyledTextFieldTest, AvailableDecorationWidth) {
+ // A fudge factor to account for how much space the border takes up.
+ // The test shouldn't be too dependent on the field's internals, but
+ // it also shouldn't let deranged cases fall through the cracks
+ // (like nothing available with no text, or everything available
+ // with some text).
+ const CGFloat kBorderWidth = 20.0;
+
+ // With no contents, almost the entire width is available for
+ // decorations.
+ [field_ setStringValue:@""];
+ CGFloat availableWidth = [field_ availableDecorationWidth];
+ EXPECT_LE(availableWidth, kWidth);
+ EXPECT_GT(availableWidth, kWidth - kBorderWidth);
+
+ // With minor contents, most of the remaining width is available for
+ // decorations.
+ NSDictionary* attributes =
+ [NSDictionary dictionaryWithObject:[field_ font]
+ forKey:NSFontAttributeName];
+ NSString* string = @"Hello world";
+ const NSSize size([string sizeWithAttributes:attributes]);
+ [field_ setStringValue:string];
+ availableWidth = [field_ availableDecorationWidth];
+ EXPECT_LE(availableWidth, kWidth - size.width);
+ EXPECT_GT(availableWidth, kWidth - size.width - kBorderWidth);
+
+ // With huge contents, nothing at all is left for decorations.
+ string = @"A long string which is surely wider than field_ can hold.";
+ [field_ setStringValue:string];
+ availableWidth = [field_ availableDecorationWidth];
+ EXPECT_LT(availableWidth, 0.0);
+}
+
+// Test drawing, mostly to ensure nothing leaks or crashes.
+TEST_F(StyledTextFieldTest, Display) {
+ [field_ display];
+
+ // Test focused drawing.
+ [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
+ [field_ display];
+}
+
+// Test that the field editor gets the same bounds when focus is delivered by
+// the standard focusing machinery, or by -resetFieldEditorFrameIfNeeded.
+TEST_F(StyledTextFieldTest, ResetFieldEditorBase) {
+ // Capture the editor frame resulting from the standard focus machinery.
+ [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
+ const NSRect baseEditorFrame(EditorFrame());
+
+ // Setting a hint should result in a strictly smaller editor frame.
+ EXPECT_EQ(0, [cell_ leftMargin]);
+ EXPECT_EQ(0, [cell_ rightMargin]);
+ [cell_ setLeftMargin:10];
+ [field_ resetFieldEditorFrameIfNeeded];
+ EXPECT_FALSE(NSEqualRects(baseEditorFrame, EditorFrame()));
+ EXPECT_TRUE(NSContainsRect(baseEditorFrame, EditorFrame()));
+
+ // Resetting the margin and using -resetFieldEditorFrameIfNeeded should result
+ // in the same frame as the standard focus machinery.
+ [cell_ setLeftMargin:0];
+ [field_ resetFieldEditorFrameIfNeeded];
+ EXPECT_TRUE(NSEqualRects(baseEditorFrame, EditorFrame()));
+}
+
+// Test that the field editor gets the same bounds when focus is delivered by
+// the standard focusing machinery, or by -resetFieldEditorFrameIfNeeded.
+TEST_F(StyledTextFieldTest, ResetFieldEditorLeftMargin) {
+ const CGFloat kLeftMargin = 20;
+
+ // Start the cell off with a non-zero left margin.
+ [cell_ setLeftMargin:kLeftMargin];
+ [cell_ setRightMargin:0];
+
+ // Capture the editor frame resulting from the standard focus machinery.
+ [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
+ const NSRect baseEditorFrame(EditorFrame());
+
+ // Clearing the margin should result in a strictly larger editor frame.
+ [cell_ setLeftMargin:0];
+ [field_ resetFieldEditorFrameIfNeeded];
+ EXPECT_FALSE(NSEqualRects(baseEditorFrame, EditorFrame()));
+ EXPECT_TRUE(NSContainsRect(EditorFrame(), baseEditorFrame));
+
+ // Setting the same margin and using -resetFieldEditorFrameIfNeeded should
+ // result in the same frame as the standard focus machinery.
+ [cell_ setLeftMargin:kLeftMargin];
+ [field_ resetFieldEditorFrameIfNeeded];
+ EXPECT_TRUE(NSEqualRects(baseEditorFrame, EditorFrame()));
+}
+
+// Test that the field editor gets the same bounds when focus is delivered by
+// the standard focusing machinery, or by -resetFieldEditorFrameIfNeeded.
+TEST_F(StyledTextFieldTest, ResetFieldEditorRightMargin) {
+ const CGFloat kRightMargin = 20;
+
+ // Start the cell off with a non-zero right margin.
+ [cell_ setLeftMargin:0];
+ [cell_ setRightMargin:kRightMargin];
+
+ // Capture the editor frame resulting from the standard focus machinery.
+ [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
+ const NSRect baseEditorFrame(EditorFrame());
+
+ // Clearing the margin should result in a strictly larger editor frame.
+ [cell_ setRightMargin:0];
+ [field_ resetFieldEditorFrameIfNeeded];
+ EXPECT_FALSE(NSEqualRects(baseEditorFrame, EditorFrame()));
+ EXPECT_TRUE(NSContainsRect(EditorFrame(), baseEditorFrame));
+
+ // Setting the same margin and using -resetFieldEditorFrameIfNeeded should
+ // result in the same frame as the standard focus machinery.
+ [cell_ setRightMargin:kRightMargin];
+ [field_ resetFieldEditorFrameIfNeeded];
+ EXPECT_TRUE(NSEqualRects(baseEditorFrame, EditorFrame()));
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/tab_contents_controller.h b/chrome/browser/ui/cocoa/tab_contents_controller.h
new file mode 100644
index 0000000..f821ea4
--- /dev/null
+++ b/chrome/browser/ui/cocoa/tab_contents_controller.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_TAB_CONTENTS_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_TAB_CONTENTS_CONTROLLER_H_
+#pragma once
+
+#include <Cocoa/Cocoa.h>
+
+#include "base/scoped_ptr.h"
+
+class TabContents;
+class TabContentsNotificationBridge;
+@class TabContentsController;
+
+// The interface for the tab contents view controller's delegate.
+
+@protocol TabContentsControllerDelegate
+
+// Tells the delegate when the tab contents view's frame is about to change.
+- (void)tabContentsViewFrameWillChange:(TabContentsController*)source
+ frameRect:(NSRect)frameRect;
+
+@end
+
+// A class that controls the TabContents view. It manages displaying the
+// native view for a given TabContents.
+// Note that just creating the class does not display the view. We defer
+// inserting it until the box is the correct size to avoid multiple resize
+// messages to the renderer. You must call |-ensureContentsVisible| to display
+// the render widget host view.
+
+@interface TabContentsController : NSViewController {
+ @private
+ TabContents* contents_; // weak
+ // Delegate to be notified about size changes.
+ id<TabContentsControllerDelegate> delegate_; // weak
+ scoped_ptr<TabContentsNotificationBridge> tabContentsBridge_;
+}
+@property(readonly, nonatomic) TabContents* tabContents;
+
+- (id)initWithContents:(TabContents*)contents
+ delegate:(id<TabContentsControllerDelegate>)delegate;
+
+// Call when the tab contents is about to be replaced with the currently
+// selected tab contents to do not trigger unnecessary content relayout.
+- (void)ensureContentsSizeDoesNotChange;
+
+// Call when the tab view is properly sized and the render widget host view
+// should be put into the view hierarchy.
+- (void)ensureContentsVisible;
+
+// Call to change the underlying tab contents object. View is not changed,
+// call |-ensureContentsVisible| to display the |newContents|'s render widget
+// host view.
+- (void)changeTabContents:(TabContents*)newContents;
+
+// Called when the tab contents is the currently selected tab and is about to be
+// removed from the view hierarchy.
+- (void)willBecomeUnselectedTab;
+
+// Called when the tab contents is about to be put into the view hierarchy as
+// the selected tab. Handles things such as ensuring the toolbar is correctly
+// enabled.
+- (void)willBecomeSelectedTab;
+
+// Called when the tab contents is updated in some non-descript way (the
+// notification from the model isn't specific). |updatedContents| could reflect
+// an entirely new tab contents object.
+- (void)tabDidChange:(TabContents*)updatedContents;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_TAB_CONTENTS_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/tab_contents_controller.mm b/chrome/browser/ui/cocoa/tab_contents_controller.mm
new file mode 100644
index 0000000..c7b5cf8
--- /dev/null
+++ b/chrome/browser/ui/cocoa/tab_contents_controller.mm
@@ -0,0 +1,212 @@
+// 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 "chrome/browser/ui/cocoa/tab_contents_controller.h"
+
+#include "base/mac_util.h"
+#include "base/scoped_nsobject.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/renderer_host/render_widget_host_view.h"
+#include "chrome/browser/tab_contents/navigation_controller.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
+
+
+@interface TabContentsController(Private)
+// Forwards frame update to |delegate_| (ResizeNotificationView calls it).
+- (void)tabContentsViewFrameWillChange:(NSRect)frameRect;
+// Notification from TabContents (forwarded by TabContentsNotificationBridge).
+- (void)tabContentsRenderViewHostChanged:(RenderViewHost*)oldHost
+ newHost:(RenderViewHost*)newHost;
+@end
+
+
+// A supporting C++ bridge object to register for TabContents notifications.
+
+class TabContentsNotificationBridge : public NotificationObserver {
+ public:
+ explicit TabContentsNotificationBridge(TabContentsController* controller);
+
+ // Overriden from NotificationObserver.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+ // Register for |contents|'s notifications, remove all prior registrations.
+ void ChangeTabContents(TabContents* contents);
+ private:
+ NotificationRegistrar registrar_;
+ TabContentsController* controller_; // weak, owns us
+};
+
+TabContentsNotificationBridge::TabContentsNotificationBridge(
+ TabContentsController* controller)
+ : controller_(controller) {
+}
+
+void TabContentsNotificationBridge::Observe(
+ NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NotificationType::RENDER_VIEW_HOST_CHANGED) {
+ RenderViewHostSwitchedDetails* switched_details =
+ Details<RenderViewHostSwitchedDetails>(details).ptr();
+ [controller_ tabContentsRenderViewHostChanged:switched_details->old_host
+ newHost:switched_details->new_host];
+ } else {
+ NOTREACHED();
+ }
+}
+
+void TabContentsNotificationBridge::ChangeTabContents(TabContents* contents) {
+ registrar_.RemoveAll();
+ if (contents) {
+ registrar_.Add(this,
+ NotificationType::RENDER_VIEW_HOST_CHANGED,
+ Source<NavigationController>(&contents->controller()));
+ }
+}
+
+
+// A custom view that notifies |controller| that view's frame is changing.
+
+@interface ResizeNotificationView : NSView {
+ TabContentsController* controller_;
+}
+- (id)initWithController:(TabContentsController*)controller;
+@end
+
+@implementation ResizeNotificationView
+
+- (id)initWithController:(TabContentsController*)controller {
+ if ((self = [super initWithFrame:NSZeroRect])) {
+ controller_ = controller;
+ }
+ return self;
+}
+
+- (void)setFrame:(NSRect)frameRect {
+ [controller_ tabContentsViewFrameWillChange:frameRect];
+ [super setFrame:frameRect];
+}
+
+@end
+
+
+@implementation TabContentsController
+@synthesize tabContents = contents_;
+
+- (id)initWithContents:(TabContents*)contents
+ delegate:(id<TabContentsControllerDelegate>)delegate {
+ if ((self = [super initWithNibName:nil bundle:nil])) {
+ contents_ = contents;
+ delegate_ = delegate;
+ tabContentsBridge_.reset(new TabContentsNotificationBridge(self));
+ tabContentsBridge_->ChangeTabContents(contents);
+ }
+ return self;
+}
+
+- (void)dealloc {
+ // make sure our contents have been removed from the window
+ [[self view] removeFromSuperview];
+ [super dealloc];
+}
+
+- (void)loadView {
+ scoped_nsobject<ResizeNotificationView> view(
+ [[ResizeNotificationView alloc] initWithController:self]);
+ [view setAutoresizingMask:NSViewHeightSizable|NSViewWidthSizable];
+ [self setView:view];
+}
+
+- (void)ensureContentsSizeDoesNotChange {
+ if (contents_) {
+ NSView* contentsContainer = [self view];
+ NSArray* subviews = [contentsContainer subviews];
+ if ([subviews count] > 0)
+ [contents_->GetNativeView() setAutoresizingMask:NSViewNotSizable];
+ }
+}
+
+// Call when the tab view is properly sized and the render widget host view
+// should be put into the view hierarchy.
+- (void)ensureContentsVisible {
+ if (!contents_)
+ return;
+ NSView* contentsContainer = [self view];
+ NSArray* subviews = [contentsContainer subviews];
+ NSView* contentsNativeView = contents_->GetNativeView();
+
+ NSRect contentsNativeViewFrame = [contentsContainer frame];
+ contentsNativeViewFrame.origin = NSZeroPoint;
+
+ [delegate_ tabContentsViewFrameWillChange:self
+ frameRect:contentsNativeViewFrame];
+
+ // Native view is resized to the actual size before it becomes visible
+ // to avoid flickering.
+ [contentsNativeView setFrame:contentsNativeViewFrame];
+ if ([subviews count] == 0) {
+ [contentsContainer addSubview:contentsNativeView];
+ } else if ([subviews objectAtIndex:0] != contentsNativeView) {
+ [contentsContainer replaceSubview:[subviews objectAtIndex:0]
+ with:contentsNativeView];
+ }
+ // Restore autoresizing properties possibly stripped by
+ // ensureContentsSizeDoesNotChange call.
+ [contentsNativeView setAutoresizingMask:NSViewWidthSizable|
+ NSViewHeightSizable];
+}
+
+- (void)changeTabContents:(TabContents*)newContents {
+ contents_ = newContents;
+ tabContentsBridge_->ChangeTabContents(contents_);
+}
+
+- (void)tabContentsViewFrameWillChange:(NSRect)frameRect {
+ [delegate_ tabContentsViewFrameWillChange:self frameRect:frameRect];
+}
+
+- (void)tabContentsRenderViewHostChanged:(RenderViewHost*)oldHost
+ newHost:(RenderViewHost*)newHost {
+ if (oldHost && newHost && oldHost->view() && newHost->view()) {
+ newHost->view()->set_reserved_contents_rect(
+ oldHost->view()->reserved_contents_rect());
+ } else {
+ [delegate_ tabContentsViewFrameWillChange:self
+ frameRect:[[self view] frame]];
+ }
+}
+
+- (void)willBecomeUnselectedTab {
+ // The RWHV is ripped out of the view hierarchy on tab switches, so it never
+ // formally resigns first responder status. Handle this by explicitly sending
+ // a Blur() message to the renderer, but only if the RWHV currently has focus.
+ RenderViewHost* rvh = [self tabContents]->render_view_host();
+ if (rvh && rvh->view() && rvh->view()->HasFocus())
+ rvh->Blur();
+}
+
+- (void)willBecomeSelectedTab {
+ // Do not explicitly call Focus() here, as the RWHV may not actually have
+ // focus (for example, if the omnibox has focus instead). The TabContents
+ // logic will restore focus to the appropriate view.
+}
+
+- (void)tabDidChange:(TabContents*)updatedContents {
+ // Calling setContentView: here removes any first responder status
+ // the view may have, so avoid changing the view hierarchy unless
+ // the view is different.
+ if ([self tabContents] != updatedContents) {
+ [self changeTabContents:updatedContents];
+ if ([self tabContents])
+ [self ensureContentsVisible];
+ }
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/tab_controller.h b/chrome/browser/ui/cocoa/tab_controller.h
new file mode 100644
index 0000000..8ed49eb
--- /dev/null
+++ b/chrome/browser/ui/cocoa/tab_controller.h
@@ -0,0 +1,115 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_TAB_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_TAB_CONTROLLER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+#import "chrome/browser/ui/cocoa/hover_close_button.h"
+#include "chrome/browser/ui/tabs/tab_menu_model.h"
+
+// The loading/waiting state of the tab.
+enum TabLoadingState {
+ kTabDone,
+ kTabLoading,
+ kTabWaiting,
+ kTabCrashed,
+};
+
+@class MenuController;
+namespace TabControllerInternal {
+class MenuDelegate;
+}
+@class TabView;
+@protocol TabControllerTarget;
+
+// A class that manages a single tab in the tab strip. Set its target/action
+// to be sent a message when the tab is selected by the user clicking. Setting
+// the |loading| property to YES visually indicates that this tab is currently
+// loading content via a spinner.
+//
+// The tab has the notion of an "icon view" which can be used to display
+// identifying characteristics such as a favicon, or since it's a full-fledged
+// view, something with state and animation such as a throbber for illustrating
+// progress. The default in the nib is an image view so nothing special is
+// required if that's all you need.
+
+@interface TabController : NSViewController {
+ @private
+ IBOutlet NSView* iconView_;
+ IBOutlet NSTextField* titleView_;
+ IBOutlet HoverCloseButton* closeButton_;
+
+ NSRect originalIconFrame_; // frame of iconView_ as loaded from nib
+ BOOL isIconShowing_; // last state of iconView_ in updateVisibility
+
+ BOOL app_;
+ BOOL mini_;
+ BOOL pinned_;
+ BOOL selected_;
+ TabLoadingState loadingState_;
+ CGFloat iconTitleXOffset_; // between left edges of icon and title
+ id<TabControllerTarget> target_; // weak, where actions are sent
+ SEL action_; // selector sent when tab is selected by clicking
+ scoped_ptr<TabMenuModel> contextMenuModel_;
+ scoped_ptr<TabControllerInternal::MenuDelegate> contextMenuDelegate_;
+ scoped_nsobject<MenuController> contextMenuController_;
+}
+
+@property(assign, nonatomic) TabLoadingState loadingState;
+
+@property(assign, nonatomic) SEL action;
+@property(assign, nonatomic) BOOL app;
+@property(assign, nonatomic) BOOL mini;
+@property(assign, nonatomic) BOOL pinned;
+@property(assign, nonatomic) BOOL selected;
+@property(assign, nonatomic) id target;
+@property(assign, nonatomic) NSView* iconView;
+@property(assign, nonatomic) NSTextField* titleView;
+@property(assign, nonatomic) HoverCloseButton* closeButton;
+
+// Minimum and maximum allowable tab width. The minimum width does not show
+// the icon or the close button. The selected tab always has at least a close
+// button so it has a different minimum width.
++ (CGFloat)minTabWidth;
++ (CGFloat)maxTabWidth;
++ (CGFloat)minSelectedTabWidth;
++ (CGFloat)miniTabWidth;
++ (CGFloat)appTabWidth;
+
+// The view associated with this controller, pre-casted as a TabView
+- (TabView*)tabView;
+
+// Closes the associated TabView by relaying the message to |target_| to
+// perform the close.
+- (IBAction)closeTab:(id)sender;
+
+// Replace the current icon view with the given view. |iconView| will be
+// resized to the size of the current icon view.
+- (void)setIconView:(NSView*)iconView;
+- (NSView*)iconView;
+
+// Called by the tabs to determine whether we are in rapid (tab) closure mode.
+// In this mode, we handle clicks slightly differently due to animation.
+// Ideally, tabs would know about their own animation and wouldn't need this.
+- (BOOL)inRapidClosureMode;
+
+// Updates the visibility of certain subviews, such as the icon and close
+// button, based on criteria such as the tab's selected state and its current
+// width.
+- (void)updateVisibility;
+
+// Update the title color to match the tabs current state.
+- (void)updateTitleColor;
+@end
+
+@interface TabController(TestingAPI)
+- (NSString*)toolTip;
+- (int)iconCapacity;
+- (BOOL)shouldShowIcon;
+- (BOOL)shouldShowCloseButton;
+@end // TabController(TestingAPI)
+
+#endif // CHROME_BROWSER_UI_COCOA_TAB_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/tab_controller.mm b/chrome/browser/ui/cocoa/tab_controller.mm
new file mode 100644
index 0000000..2ae2454
--- /dev/null
+++ b/chrome/browser/ui/cocoa/tab_controller.mm
@@ -0,0 +1,306 @@
+// 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.
+
+#include "app/l10n_util_mac.h"
+#include "base/mac_util.h"
+#import "chrome/browser/themes/browser_theme_provider.h"
+#import "chrome/browser/ui/cocoa/menu_controller.h"
+#import "chrome/browser/ui/cocoa/tab_controller.h"
+#import "chrome/browser/ui/cocoa/tab_controller_target.h"
+#import "chrome/browser/ui/cocoa/tab_view.h"
+#import "chrome/browser/ui/cocoa/themed_window.h"
+#import "chrome/common/extensions/extension.h"
+#include "grit/generated_resources.h"
+
+@implementation TabController
+
+@synthesize action = action_;
+@synthesize app = app_;
+@synthesize loadingState = loadingState_;
+@synthesize mini = mini_;
+@synthesize pinned = pinned_;
+@synthesize target = target_;
+@synthesize iconView = iconView_;
+@synthesize titleView = titleView_;
+@synthesize closeButton = closeButton_;
+
+namespace TabControllerInternal {
+
+// A C++ delegate that handles enabling/disabling menu items and handling when
+// a menu command is chosen. Also fixes up the menu item label for "pin/unpin
+// tab".
+class MenuDelegate : public menus::SimpleMenuModel::Delegate {
+ public:
+ explicit MenuDelegate(id<TabControllerTarget> target, TabController* owner)
+ : target_(target),
+ owner_(owner) {}
+
+ // Overridden from menus::SimpleMenuModel::Delegate
+ virtual bool IsCommandIdChecked(int command_id) const { return false; }
+ virtual bool IsCommandIdEnabled(int command_id) const {
+ TabStripModel::ContextMenuCommand command =
+ static_cast<TabStripModel::ContextMenuCommand>(command_id);
+ return [target_ isCommandEnabled:command forController:owner_];
+ }
+ virtual bool GetAcceleratorForCommandId(
+ int command_id,
+ menus::Accelerator* accelerator) { return false; }
+ virtual void ExecuteCommand(int command_id) {
+ TabStripModel::ContextMenuCommand command =
+ static_cast<TabStripModel::ContextMenuCommand>(command_id);
+ [target_ commandDispatch:command forController:owner_];
+ }
+
+ private:
+ id<TabControllerTarget> target_; // weak
+ TabController* owner_; // weak, owns me
+};
+
+} // TabControllerInternal namespace
+
+// The min widths match the windows values and are sums of left + right
+// padding, of which we have no comparable constants (we draw using paths, not
+// images). The selected tab width includes the close button width.
++ (CGFloat)minTabWidth { return 31; }
++ (CGFloat)minSelectedTabWidth { return 46; }
++ (CGFloat)maxTabWidth { return 220; }
++ (CGFloat)miniTabWidth { return 53; }
++ (CGFloat)appTabWidth { return 66; }
+
+- (TabView*)tabView {
+ return static_cast<TabView*>([self view]);
+}
+
+- (id)init {
+ self = [super initWithNibName:@"TabView" bundle:mac_util::MainAppBundle()];
+ if (self != nil) {
+ isIconShowing_ = YES;
+ NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
+ [defaultCenter addObserver:self
+ selector:@selector(viewResized:)
+ name:NSViewFrameDidChangeNotification
+ object:[self view]];
+ [defaultCenter addObserver:self
+ selector:@selector(themeChangedNotification:)
+ name:kBrowserThemeDidChangeNotification
+ object:nil];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [[self tabView] setController:nil];
+ [super dealloc];
+}
+
+// The internals of |-setSelected:| but doesn't check if we're already set
+// to |selected|. Pass the selection change to the subviews that need it and
+// mark ourselves as needing a redraw.
+- (void)internalSetSelected:(BOOL)selected {
+ selected_ = selected;
+ TabView* tabView = static_cast<TabView*>([self view]);
+ DCHECK([tabView isKindOfClass:[TabView class]]);
+ [tabView setState:selected];
+ [tabView cancelAlert];
+ [self updateVisibility];
+ [self updateTitleColor];
+}
+
+// Called when the tab's nib is done loading and all outlets are hooked up.
+- (void)awakeFromNib {
+ // Remember the icon's frame, so that if the icon is ever removed, a new
+ // one can later replace it in the proper location.
+ originalIconFrame_ = [iconView_ frame];
+
+ // When the icon is removed, the title expands to the left to fill the space
+ // left by the icon. When the close button is removed, the title expands to
+ // the right to fill its space. These are the amounts to expand and contract
+ // titleView_ under those conditions. We don't have to explicilty save the
+ // offset between the title and the close button since we can just get that
+ // value for the close button's frame.
+ NSRect titleFrame = [titleView_ frame];
+ iconTitleXOffset_ = NSMinX(titleFrame) - NSMinX(originalIconFrame_);
+
+ [self internalSetSelected:selected_];
+}
+
+// Called when Cocoa wants to display the context menu. Lazily instantiate
+// the menu based off of the cross-platform model. Re-create the menu and
+// model every time to get the correct labels and enabling.
+- (NSMenu*)menu {
+ contextMenuDelegate_.reset(
+ new TabControllerInternal::MenuDelegate(target_, self));
+ contextMenuModel_.reset(new TabMenuModel(contextMenuDelegate_.get(),
+ [self pinned]));
+ contextMenuController_.reset(
+ [[MenuController alloc] initWithModel:contextMenuModel_.get()
+ useWithPopUpButtonCell:NO]);
+ return [contextMenuController_ menu];
+}
+
+- (IBAction)closeTab:(id)sender {
+ if ([[self target] respondsToSelector:@selector(closeTab:)]) {
+ [[self target] performSelector:@selector(closeTab:)
+ withObject:[self view]];
+ }
+}
+
+- (void)setTitle:(NSString*)title {
+ [[self view] setToolTip:title];
+ if ([self mini] && ![self selected]) {
+ TabView* tabView = static_cast<TabView*>([self view]);
+ DCHECK([tabView isKindOfClass:[TabView class]]);
+ [tabView startAlert];
+ }
+ [super setTitle:title];
+}
+
+- (void)setSelected:(BOOL)selected {
+ if (selected_ != selected)
+ [self internalSetSelected:selected];
+}
+
+- (BOOL)selected {
+ return selected_;
+}
+
+- (void)setIconView:(NSView*)iconView {
+ [iconView_ removeFromSuperview];
+ iconView_ = iconView;
+ if ([self app]) {
+ NSRect appIconFrame = [iconView frame];
+ appIconFrame.origin = originalIconFrame_.origin;
+ // Center the icon.
+ appIconFrame.origin.x = ([TabController appTabWidth] -
+ NSWidth(appIconFrame)) / 2.0;
+ [iconView setFrame:appIconFrame];
+ } else {
+ [iconView_ setFrame:originalIconFrame_];
+ }
+ // Ensure that the icon is suppressed if no icon is set or if the tab is too
+ // narrow to display one.
+ [self updateVisibility];
+
+ if (iconView_)
+ [[self view] addSubview:iconView_];
+}
+
+- (NSString*)toolTip {
+ return [[self view] toolTip];
+}
+
+// Return a rough approximation of the number of icons we could fit in the
+// tab. We never actually do this, but it's a helpful guide for determining
+// how much space we have available.
+- (int)iconCapacity {
+ CGFloat width = NSMaxX([closeButton_ frame]) - NSMinX(originalIconFrame_);
+ CGFloat iconWidth = NSWidth(originalIconFrame_);
+
+ return width / iconWidth;
+}
+
+// Returns YES if we should show the icon. When tabs get too small, we clip
+// the favicon before the close button for selected tabs, and prefer the
+// favicon for unselected tabs. The icon can also be suppressed more directly
+// by clearing iconView_.
+- (BOOL)shouldShowIcon {
+ if (!iconView_)
+ return NO;
+
+ if ([self mini])
+ return YES;
+
+ int iconCapacity = [self iconCapacity];
+ if ([self selected])
+ return iconCapacity >= 2;
+ return iconCapacity >= 1;
+}
+
+// Returns YES if we should be showing the close button. The selected tab
+// always shows the close button.
+- (BOOL)shouldShowCloseButton {
+ if ([self mini])
+ return NO;
+ return ([self selected] || [self iconCapacity] >= 3);
+}
+
+- (void)updateVisibility {
+ // iconView_ may have been replaced or it may be nil, so [iconView_ isHidden]
+ // won't work. Instead, the state of the icon is tracked separately in
+ // isIconShowing_.
+ BOOL newShowIcon = [self shouldShowIcon];
+
+ [iconView_ setHidden:!newShowIcon];
+ isIconShowing_ = newShowIcon;
+
+ // If the tab is a mini-tab, hide the title.
+ [titleView_ setHidden:[self mini]];
+
+ BOOL newShowCloseButton = [self shouldShowCloseButton];
+
+ [closeButton_ setHidden:!newShowCloseButton];
+
+ // Adjust the title view based on changes to the icon's and close button's
+ // visibility.
+ NSRect oldTitleFrame = [titleView_ frame];
+ NSRect newTitleFrame;
+ newTitleFrame.size.height = oldTitleFrame.size.height;
+ newTitleFrame.origin.y = oldTitleFrame.origin.y;
+
+ if (newShowIcon) {
+ newTitleFrame.origin.x = originalIconFrame_.origin.x + iconTitleXOffset_;
+ } else {
+ newTitleFrame.origin.x = originalIconFrame_.origin.x;
+ }
+
+ if (newShowCloseButton) {
+ newTitleFrame.size.width = NSMinX([closeButton_ frame]) -
+ newTitleFrame.origin.x;
+ } else {
+ newTitleFrame.size.width = NSMaxX([closeButton_ frame]) -
+ newTitleFrame.origin.x;
+ }
+
+ [titleView_ setFrame:newTitleFrame];
+}
+
+- (void)updateTitleColor {
+ NSColor* titleColor = nil;
+ ThemeProvider* theme = [[[self view] window] themeProvider];
+ if (theme && ![self selected]) {
+ titleColor =
+ theme->GetNSColor(BrowserThemeProvider::COLOR_BACKGROUND_TAB_TEXT,
+ true);
+ }
+ // Default to the selected text color unless told otherwise.
+ if (theme && !titleColor) {
+ titleColor = theme->GetNSColor(BrowserThemeProvider::COLOR_TAB_TEXT,
+ true);
+ }
+ [titleView_ setTextColor:titleColor ? titleColor : [NSColor textColor]];
+}
+
+// Called when our view is resized. If it gets too small, start by hiding
+// the close button and only show it if tab is selected. Eventually, hide the
+// icon as well. We know that this is for our view because we only registered
+// for notifications from our specific view.
+- (void)viewResized:(NSNotification*)info {
+ [self updateVisibility];
+}
+
+- (void)themeChangedNotification:(NSNotification*)notification {
+ [self updateTitleColor];
+}
+
+// Called by the tabs to determine whether we are in rapid (tab) closure mode.
+- (BOOL)inRapidClosureMode {
+ if ([[self target] respondsToSelector:@selector(inRapidClosureMode)]) {
+ return [[self target] performSelector:@selector(inRapidClosureMode)] ?
+ YES : NO;
+ }
+ return NO;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/tab_controller_target.h b/chrome/browser/ui/cocoa/tab_controller_target.h
new file mode 100644
index 0000000..6eec01a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/tab_controller_target.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_TAB_CONTROLLER_TARGET_H_
+#define CHROME_BROWSER_UI_COCOA_TAB_CONTROLLER_TARGET_H_
+#pragma once
+
+#include "chrome/browser/tabs/tab_strip_model.h"
+
+@class TabController;
+
+// A protocol to be implemented by a TabController's target.
+@protocol TabControllerTarget
+- (void)selectTab:(id)sender;
+- (void)closeTab:(id)sender;
+
+// Dispatch context menu commands for the given tab controller.
+- (void)commandDispatch:(TabStripModel::ContextMenuCommand)command
+ forController:(TabController*)controller;
+// Returns YES if the specificed command should be enabled for the given
+// controller.
+- (BOOL)isCommandEnabled:(TabStripModel::ContextMenuCommand)command
+ forController:(TabController*)controller;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_TAB_CONTROLLER_TARGET_H_
diff --git a/chrome/browser/ui/cocoa/tab_controller_unittest.mm b/chrome/browser/ui/cocoa/tab_controller_unittest.mm
new file mode 100644
index 0000000..93331ac
--- /dev/null
+++ b/chrome/browser/ui/cocoa/tab_controller_unittest.mm
@@ -0,0 +1,333 @@
+// Copyright (c) 2009 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>
+
+#import "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/tab_controller.h"
+#import "chrome/browser/ui/cocoa/tab_controller_target.h"
+#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+// Implements the target interface for the tab, which gets sent messages when
+// the tab is clicked on by the user and when its close box is clicked.
+@interface TabControllerTestTarget : NSObject<TabControllerTarget> {
+ @private
+ bool selected_;
+ bool closed_;
+}
+- (bool)selected;
+- (bool)closed;
+@end
+
+@implementation TabControllerTestTarget
+- (bool)selected {
+ return selected_;
+}
+- (bool)closed {
+ return closed_;
+}
+- (void)selectTab:(id)sender {
+ selected_ = true;
+}
+- (void)closeTab:(id)sender {
+ closed_ = true;
+}
+- (void)mouseTimer:(NSTimer*)timer {
+ // Fire the mouseUp to break the TabView drag loop.
+ NSEvent* current = [NSApp currentEvent];
+ NSWindow* window = [timer userInfo];
+ NSEvent* up = [NSEvent mouseEventWithType:NSLeftMouseUp
+ location:[current locationInWindow]
+ modifierFlags:0
+ timestamp:[current timestamp]
+ windowNumber:[window windowNumber]
+ context:nil
+ eventNumber:0
+ clickCount:1
+ pressure:1.0];
+ [window postEvent:up atStart:YES];
+}
+- (void)commandDispatch:(TabStripModel::ContextMenuCommand)command
+ forController:(TabController*)controller {
+}
+- (BOOL)isCommandEnabled:(TabStripModel::ContextMenuCommand)command
+ forController:(TabController*)controller {
+ return NO;
+}
+@end
+
+namespace {
+
+CGFloat LeftMargin(NSRect superFrame, NSRect subFrame) {
+ return NSMinX(subFrame) - NSMinX(superFrame);
+}
+
+CGFloat RightMargin(NSRect superFrame, NSRect subFrame) {
+ return NSMaxX(superFrame) - NSMaxX(subFrame);
+}
+
+// The dragging code in TabView makes heavy use of autorelease pools so
+// inherit from CocoaTest to have one created for us.
+class TabControllerTest : public CocoaTest {
+ public:
+ TabControllerTest() { }
+};
+
+// Tests creating the controller, sticking it in a window, and removing it.
+TEST_F(TabControllerTest, Creation) {
+ NSWindow* window = test_window();
+ scoped_nsobject<TabController> controller([[TabController alloc] init]);
+ [[window contentView] addSubview:[controller view]];
+ EXPECT_TRUE([controller tabView]);
+ EXPECT_EQ([[controller view] window], window);
+ [[controller view] display]; // Test drawing to ensure nothing leaks/crashes.
+ [[controller view] removeFromSuperview];
+}
+
+// Tests sending it a close message and ensuring that the target/action get
+// called. Mimics the user clicking on the close button in the tab.
+TEST_F(TabControllerTest, Close) {
+ NSWindow* window = test_window();
+ scoped_nsobject<TabController> controller([[TabController alloc] init]);
+ [[window contentView] addSubview:[controller view]];
+
+ scoped_nsobject<TabControllerTestTarget> target(
+ [[TabControllerTestTarget alloc] init]);
+ EXPECT_FALSE([target closed]);
+ [controller setTarget:target];
+ EXPECT_EQ(target.get(), [controller target]);
+
+ [controller closeTab:nil];
+ EXPECT_TRUE([target closed]);
+
+ [[controller view] removeFromSuperview];
+}
+
+// Tests setting the |selected| property via code.
+TEST_F(TabControllerTest, APISelection) {
+ NSWindow* window = test_window();
+ scoped_nsobject<TabController> controller([[TabController alloc] init]);
+ [[window contentView] addSubview:[controller view]];
+
+ EXPECT_FALSE([controller selected]);
+ [controller setSelected:YES];
+ EXPECT_TRUE([controller selected]);
+
+ [[controller view] removeFromSuperview];
+}
+
+// Tests that setting the title of a tab sets the tooltip as well.
+TEST_F(TabControllerTest, ToolTip) {
+ NSWindow* window = test_window();
+
+ scoped_nsobject<TabController> controller([[TabController alloc] init]);
+ [[window contentView] addSubview:[controller view]];
+
+ EXPECT_TRUE([[controller toolTip] length] == 0);
+ NSString *tooltip_string = @"Some text to use as a tab title";
+ [controller setTitle:tooltip_string];
+ EXPECT_NSEQ(tooltip_string, [controller toolTip]);
+}
+
+// Tests setting the |loading| property via code.
+TEST_F(TabControllerTest, Loading) {
+ NSWindow* window = test_window();
+ scoped_nsobject<TabController> controller([[TabController alloc] init]);
+ [[window contentView] addSubview:[controller view]];
+
+ EXPECT_EQ(kTabDone, [controller loadingState]);
+ [controller setLoadingState:kTabWaiting];
+ EXPECT_EQ(kTabWaiting, [controller loadingState]);
+ [controller setLoadingState:kTabLoading];
+ EXPECT_EQ(kTabLoading, [controller loadingState]);
+ [controller setLoadingState:kTabDone];
+ EXPECT_EQ(kTabDone, [controller loadingState]);
+
+ [[controller view] removeFromSuperview];
+}
+
+// Tests selecting the tab with the mouse click and ensuring the target/action
+// get called.
+TEST_F(TabControllerTest, UserSelection) {
+ NSWindow* window = test_window();
+
+ // Create a tab at a known location in the window that we can click on
+ // to activate selection.
+ scoped_nsobject<TabController> controller([[TabController alloc] init]);
+ [[window contentView] addSubview:[controller view]];
+ NSRect frame = [[controller view] frame];
+ frame.size.width = [TabController minTabWidth];
+ frame.origin = NSMakePoint(0, 0);
+ [[controller view] setFrame:frame];
+
+ // Set the target and action.
+ scoped_nsobject<TabControllerTestTarget> target(
+ [[TabControllerTestTarget alloc] init]);
+ EXPECT_FALSE([target selected]);
+ [controller setTarget:target];
+ [controller setAction:@selector(selectTab:)];
+ EXPECT_EQ(target.get(), [controller target]);
+ EXPECT_EQ(@selector(selectTab:), [controller action]);
+
+ // In order to track a click, we have to fake a mouse down and a mouse
+ // up, but the down goes into a tight drag loop. To break the loop, we have
+ // to fire a timer that sends a mouse up event while the "drag" is ongoing.
+ [NSTimer scheduledTimerWithTimeInterval:0.1
+ target:target.get()
+ selector:@selector(mouseTimer:)
+ userInfo:window
+ repeats:NO];
+ NSEvent* current = [NSApp currentEvent];
+ NSPoint click_point = NSMakePoint(frame.size.width / 2,
+ frame.size.height / 2);
+ NSEvent* down = [NSEvent mouseEventWithType:NSLeftMouseDown
+ location:click_point
+ modifierFlags:0
+ timestamp:[current timestamp]
+ windowNumber:[window windowNumber]
+ context:nil
+ eventNumber:0
+ clickCount:1
+ pressure:1.0];
+ [[controller view] mouseDown:down];
+
+ // Check our target was told the tab got selected.
+ EXPECT_TRUE([target selected]);
+
+ [[controller view] removeFromSuperview];
+}
+
+TEST_F(TabControllerTest, IconCapacity) {
+ NSWindow* window = test_window();
+ scoped_nsobject<TabController> controller([[TabController alloc] init]);
+ [[window contentView] addSubview:[controller view]];
+ int cap = [controller iconCapacity];
+ EXPECT_GE(cap, 1);
+
+ NSRect frame = [[controller view] frame];
+ frame.size.width += 500;
+ [[controller view] setFrame:frame];
+ int newcap = [controller iconCapacity];
+ EXPECT_GT(newcap, cap);
+}
+
+TEST_F(TabControllerTest, ShouldShowIcon) {
+ NSWindow* window = test_window();
+ scoped_nsobject<TabController> controller([[TabController alloc] init]);
+ [[window contentView] addSubview:[controller view]];
+ int cap = [controller iconCapacity];
+ EXPECT_GT(cap, 0);
+
+ // Tab is minimum width, both icon and close box should be hidden.
+ NSRect frame = [[controller view] frame];
+ frame.size.width = [TabController minTabWidth];
+ [[controller view] setFrame:frame];
+ EXPECT_FALSE([controller shouldShowIcon]);
+ EXPECT_FALSE([controller shouldShowCloseButton]);
+
+ // Setting the icon when tab is at min width should not show icon (bug 18359).
+ scoped_nsobject<NSView> newIcon(
+ [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 16, 16)]);
+ [controller setIconView:newIcon.get()];
+ EXPECT_TRUE([newIcon isHidden]);
+
+ // Tab is at selected minimum width. Since it's selected, the close box
+ // should be visible.
+ [controller setSelected:YES];
+ frame = [[controller view] frame];
+ frame.size.width = [TabController minSelectedTabWidth];
+ [[controller view] setFrame:frame];
+ EXPECT_FALSE([controller shouldShowIcon]);
+ EXPECT_TRUE([newIcon isHidden]);
+ EXPECT_TRUE([controller shouldShowCloseButton]);
+
+ // Test expanding the tab to max width and ensure the icon and close box
+ // get put back, even when de-selected.
+ frame.size.width = [TabController maxTabWidth];
+ [[controller view] setFrame:frame];
+ EXPECT_TRUE([controller shouldShowIcon]);
+ EXPECT_FALSE([newIcon isHidden]);
+ EXPECT_TRUE([controller shouldShowCloseButton]);
+ [controller setSelected:NO];
+ EXPECT_TRUE([controller shouldShowIcon]);
+ EXPECT_TRUE([controller shouldShowCloseButton]);
+
+ cap = [controller iconCapacity];
+ EXPECT_GT(cap, 0);
+}
+
+TEST_F(TabControllerTest, Menu) {
+ NSWindow* window = test_window();
+ scoped_nsobject<TabController> controller([[TabController alloc] init]);
+ [[window contentView] addSubview:[controller view]];
+ int cap = [controller iconCapacity];
+ EXPECT_GT(cap, 0);
+
+ // Asking the view for its menu should yield a valid menu.
+ NSMenu* menu = [[controller view] menu];
+ EXPECT_TRUE(menu);
+ EXPECT_GT([menu numberOfItems], 0);
+}
+
+// Tests that the title field is correctly positioned and sized when the
+// view is resized.
+TEST_F(TabControllerTest, TitleViewLayout) {
+ NSWindow* window = test_window();
+
+ scoped_nsobject<TabController> controller([[TabController alloc] init]);
+ [[window contentView] addSubview:[controller view]];
+ NSRect tabFrame = [[controller view] frame];
+ tabFrame.size.width = [TabController maxTabWidth];
+ [[controller view] setFrame:tabFrame];
+
+ const NSRect originalTabFrame = [[controller view] frame];
+ const NSRect originalIconFrame = [[controller iconView] frame];
+ const NSRect originalCloseFrame = [[controller closeButton] frame];
+ const NSRect originalTitleFrame = [[controller titleView] frame];
+
+ // Sanity check the start state.
+ EXPECT_FALSE([[controller iconView] isHidden]);
+ EXPECT_FALSE([[controller closeButton] isHidden]);
+ EXPECT_GT(NSWidth([[controller view] frame]),
+ NSWidth([[controller titleView] frame]));
+
+ // Resize the tab so that that the it shrinks.
+ tabFrame.size.width = [TabController minTabWidth];
+ [[controller view] setFrame:tabFrame];
+
+ // The icon view and close button should be hidden and the title view should
+ // be resize to take up their space.
+ EXPECT_TRUE([[controller iconView] isHidden]);
+ EXPECT_TRUE([[controller closeButton] isHidden]);
+ EXPECT_GT(NSWidth([[controller view] frame]),
+ NSWidth([[controller titleView] frame]));
+ EXPECT_EQ(LeftMargin(originalTabFrame, originalIconFrame),
+ LeftMargin([[controller view] frame],
+ [[controller titleView] frame]));
+ EXPECT_EQ(RightMargin(originalTabFrame, originalCloseFrame),
+ RightMargin([[controller view] frame],
+ [[controller titleView] frame]));
+
+ // Resize the tab so that that the it grows.
+ tabFrame.size.width = [TabController maxTabWidth] * 0.75;
+ [[controller view] setFrame:tabFrame];
+
+ // The icon view and close button should be visible again and the title view
+ // should be resized to make room for them.
+ EXPECT_FALSE([[controller iconView] isHidden]);
+ EXPECT_FALSE([[controller closeButton] isHidden]);
+ EXPECT_GT(NSWidth([[controller view] frame]),
+ NSWidth([[controller titleView] frame]));
+ EXPECT_EQ(LeftMargin(originalTabFrame, originalTitleFrame),
+ LeftMargin([[controller view] frame],
+ [[controller titleView] frame]));
+ EXPECT_EQ(RightMargin(originalTabFrame, originalTitleFrame),
+ RightMargin([[controller view] frame],
+ [[controller titleView] frame]));
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/tab_strip_controller.h b/chrome/browser/ui/cocoa/tab_strip_controller.h
new file mode 100644
index 0000000..1dda86c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/tab_strip_controller.h
@@ -0,0 +1,262 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_TAB_STRIP_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_TAB_STRIP_CONTROLLER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+#import "chrome/browser/ui/cocoa/tab_contents_controller.h"
+#import "chrome/browser/ui/cocoa/tab_controller_target.h"
+#import "chrome/browser/ui/cocoa/url_drop_target.h"
+#import "third_party/GTM/AppKit/GTMWindowSheetController.h"
+
+@class NewTabButton;
+@class TabContentsController;
+@class TabView;
+@class TabStripView;
+
+class Browser;
+class ConstrainedWindowMac;
+class TabStripModelObserverBridge;
+class TabStripModel;
+class TabContents;
+class ToolbarModel;
+
+// The interface for the tab strip controller's delegate.
+// Delegating TabStripModelObserverBridge's events (in lieu of directly
+// subscribing to TabStripModelObserverBridge events, as TabStripController
+// does) is necessary to guarantee a proper order of subviews layout updates,
+// otherwise it might trigger unnesessary content relayout, UI flickering etc.
+@protocol TabStripControllerDelegate
+
+// Stripped down version of TabStripModelObserverBridge:selectTabWithContents.
+- (void)onSelectTabWithContents:(TabContents*)contents;
+
+// Stripped down version of TabStripModelObserverBridge:tabReplacedWithContents.
+- (void)onReplaceTabWithContents:(TabContents*)contents;
+
+// Stripped down version of TabStripModelObserverBridge:tabChangedWithContents.
+- (void)onSelectedTabChange:(TabStripModelObserver::TabChangeType)change;
+
+// Stripped down version of TabStripModelObserverBridge:tabDetachedWithContents.
+- (void)onTabDetachedWithContents:(TabContents*)contents;
+
+@end
+
+// A class that handles managing the tab strip in a browser window. It uses
+// a supporting C++ bridge object to register for notifications from the
+// TabStripModel. The Obj-C part of this class handles drag and drop and all
+// the other Cocoa-y aspects.
+//
+// For a full description of the design, see
+// http://www.chromium.org/developers/design-documents/tab-strip-mac
+@interface TabStripController :
+ NSObject<TabControllerTarget,
+ URLDropTargetController,
+ GTMWindowSheetControllerDelegate,
+ TabContentsControllerDelegate> {
+ @protected
+ // YES if tabs are to be laid out vertically instead of horizontally.
+ BOOL verticalLayout_;
+
+ @private
+ scoped_nsobject<TabStripView> tabStripView_;
+ NSView* switchView_; // weak
+ scoped_nsobject<NSView> dragBlockingView_; // avoid bad window server drags
+ NewTabButton* newTabButton_; // weak, obtained from the nib.
+
+ // Tracks the newTabButton_ for rollovers.
+ scoped_nsobject<NSTrackingArea> newTabTrackingArea_;
+ scoped_ptr<TabStripModelObserverBridge> bridge_;
+ Browser* browser_; // weak
+ TabStripModel* tabStripModel_; // weak
+ // Delegate that is informed about tab state changes.
+ id<TabStripControllerDelegate> delegate_; // weak
+
+ // YES if the new tab button is currently displaying the hover image (if the
+ // mouse is currently over the button).
+ BOOL newTabButtonShowingHoverImage_;
+
+ // Access to the TabContentsControllers (which own the parent view
+ // for the toolbar and associated tab contents) given an index. Call
+ // |indexFromModelIndex:| to convert a |tabStripModel_| index to a
+ // |tabContentsArray_| index. Do NOT assume that the indices of
+ // |tabStripModel_| and this array are identical, this is e.g. not true while
+ // tabs are animating closed (closed tabs are removed from |tabStripModel_|
+ // immediately, but from |tabContentsArray_| only after their close animation
+ // has completed).
+ scoped_nsobject<NSMutableArray> tabContentsArray_;
+ // An array of TabControllers which manage the actual tab views. See note
+ // above |tabContentsArray_|. |tabContentsArray_| and |tabArray_| always
+ // contain objects belonging to the same tabs at the same indices.
+ scoped_nsobject<NSMutableArray> tabArray_;
+
+ // Set of TabControllers that are currently animating closed.
+ scoped_nsobject<NSMutableSet> closingControllers_;
+
+ // These values are only used during a drag, and override tab positioning.
+ TabView* placeholderTab_; // weak. Tab being dragged
+ NSRect placeholderFrame_; // Frame to use
+ CGFloat placeholderStretchiness_; // Vertical force shown by streching tab.
+ NSRect droppedTabFrame_; // Initial frame of a dropped tab, for animation.
+ // Frame targets for all the current views.
+ // target frames are used because repeated requests to [NSView animator].
+ // aren't coalesced, so we store frames to avoid redundant calls.
+ scoped_nsobject<NSMutableDictionary> targetFrames_;
+ NSRect newTabTargetFrame_;
+ // If YES, do not show the new tab button during layout.
+ BOOL forceNewTabButtonHidden_;
+ // YES if we've successfully completed the initial layout. When this is
+ // NO, we probably don't want to do any animation because we're just coming
+ // into being.
+ BOOL initialLayoutComplete_;
+
+ // Width available for resizing the tabs (doesn't include the new tab
+ // button). Used to restrict the available width when closing many tabs at
+ // once to prevent them from resizing to fit the full width. If the entire
+ // width should be used, this will have a value of |kUseFullAvailableWidth|.
+ float availableResizeWidth_;
+ // A tracking area that's the size of the tab strip used to be notified
+ // when the mouse moves in the tab strip
+ scoped_nsobject<NSTrackingArea> trackingArea_;
+ TabView* hoveredTab_; // weak. Tab that the mouse is hovering over
+
+ // Array of subviews which are permanent (and which should never be removed),
+ // such as the new-tab button, but *not* the tabs themselves.
+ scoped_nsobject<NSMutableArray> permanentSubviews_;
+
+ // The default favicon, so we can use one copy for all buttons.
+ scoped_nsobject<NSImage> defaultFavIcon_;
+
+ // The amount by which to indent the tabs on the left (to make room for the
+ // red/yellow/green buttons).
+ CGFloat indentForControls_;
+
+ // Manages per-tab sheets.
+ scoped_nsobject<GTMWindowSheetController> sheetController_;
+
+ // Is the mouse currently inside the strip;
+ BOOL mouseInside_;
+}
+
+@property(nonatomic) CGFloat indentForControls;
+
+// Initialize the controller with a view and browser that contains
+// everything else we'll need. |switchView| is the view whose contents get
+// "switched" every time the user switches tabs. The children of this view
+// will be released, so if you want them to stay around, make sure
+// you have retained them.
+// |delegate| is the one listening to filtered TabStripModelObserverBridge's
+// events (see TabStripControllerDelegate for more details).
+- (id)initWithView:(TabStripView*)view
+ switchView:(NSView*)switchView
+ browser:(Browser*)browser
+ delegate:(id<TabStripControllerDelegate>)delegate;
+
+// Return the view for the currently selected tab.
+- (NSView*)selectedTabView;
+
+// Set the frame of the selected tab, also updates the internal frame dict.
+- (void)setFrameOfSelectedTab:(NSRect)frame;
+
+// Move the given tab at index |from| in this window to the location of the
+// current placeholder.
+- (void)moveTabFromIndex:(NSInteger)from;
+
+// Drop a given TabContents at the location of the current placeholder. If there
+// is no placeholder, it will go at the end. Used when dragging from another
+// window when we don't have access to the TabContents as part of our strip.
+// |frame| is in the coordinate system of the tab strip view and represents
+// where the user dropped the new tab so it can be animated into its correct
+// location when the tab is added to the model. If the tab was pinned in its
+// previous window, setting |pinned| to YES will propagate that state to the
+// new window. Mini-tabs are either app or pinned tabs; the app state is stored
+// by the |contents|, but the |pinned| state is the caller's responsibility.
+- (void)dropTabContents:(TabContentsWrapper*)contents
+ withFrame:(NSRect)frame
+ asPinnedTab:(BOOL)pinned;
+
+// Returns the index of the subview |view|. Returns -1 if not present. Takes
+// closing tabs into account such that this index will correctly match the tab
+// model. If |view| is in the process of closing, returns -1, as closing tabs
+// are no longer in the model.
+- (NSInteger)modelIndexForTabView:(NSView*)view;
+
+// Return the view at a given index.
+- (NSView*)viewAtIndex:(NSUInteger)index;
+
+// Return the number of tab views in the tab strip. It's same as number of tabs
+// in the model, except when a tab is closing, which will be counted in views
+// count, but no longer in the model.
+- (NSUInteger)viewsCount;
+
+// Set the placeholder for a dragged tab, allowing the |frame| and |strechiness|
+// to be specified. This causes this tab to be rendered in an arbitrary position
+- (void)insertPlaceholderForTab:(TabView*)tab
+ frame:(NSRect)frame
+ yStretchiness:(CGFloat)yStretchiness;
+
+// Returns whether a tab is being dragged within the tab strip.
+- (BOOL)isDragSessionActive;
+
+// Returns whether or not |tab| can still be fully seen in the tab strip or if
+// its current position would cause it be obscured by things such as the edge
+// of the window or the window decorations. Returns YES only if the entire tab
+// is visible.
+- (BOOL)isTabFullyVisible:(TabView*)tab;
+
+// Show or hide the new tab button. The button is hidden immediately, but
+// waits until the next call to |-layoutTabs| to show it again.
+- (void)showNewTabButton:(BOOL)show;
+
+// Force the tabs to rearrange themselves to reflect the current model.
+- (void)layoutTabs;
+
+// Are we in rapid (tab) closure mode? I.e., is a full layout deferred (while
+// the user closes tabs)? Needed to overcome missing clicks during rapid tab
+// closure.
+- (BOOL)inRapidClosureMode;
+
+// Returns YES if the user is allowed to drag tabs on the strip at this moment.
+// For example, this returns NO if there are any pending tab close animtations.
+- (BOOL)tabDraggingAllowed;
+
+// Default height for tabs.
++ (CGFloat)defaultTabHeight;
+
+// Default indentation for tabs (see |indentForControls_|).
++ (CGFloat)defaultIndentForControls;
+
+// Returns the (lazily created) window sheet controller of this window. Used
+// for the per-tab sheets.
+- (GTMWindowSheetController*)sheetController;
+
+// Destroys the window sheet controller of this window, if it exists. The sheet
+// controller can be recreated by a subsequent call to |-sheetController|. Must
+// not be called if any sheets are currently open.
+// TODO(viettrungluu): This is temporary code needed to allow sheets to work
+// (read: not crash) in fullscreen mode. Once GTMWindowSheetController is
+// modified to support moving sheets between windows, this code can go away.
+// http://crbug.com/19093.
+- (void)destroySheetController;
+
+// Returns the currently active TabContentsController.
+- (TabContentsController*)activeTabContentsController;
+
+ // See comments in browser_window_controller.h for documentation about these
+ // functions.
+- (void)attachConstrainedWindow:(ConstrainedWindowMac*)window;
+- (void)removeConstrainedWindow:(ConstrainedWindowMac*)window;
+
+@end
+
+// Notification sent when the number of tabs changes. The object will be this
+// controller.
+extern NSString* const kTabStripNumberOfTabsChanged;
+
+#endif // CHROME_BROWSER_UI_COCOA_TAB_STRIP_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/tab_strip_controller.mm b/chrome/browser/ui/cocoa/tab_strip_controller.mm
new file mode 100644
index 0000000..876067c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/tab_strip_controller.mm
@@ -0,0 +1,1905 @@
+// 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 "chrome/browser/ui/cocoa/tab_strip_controller.h"
+
+#import <QuartzCore/QuartzCore.h>
+
+#include <limits>
+#include <string>
+
+#include "app/l10n_util.h"
+#include "app/mac/nsimage_cache.h"
+#include "app/resource_bundle.h"
+#include "base/mac_util.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/autocomplete/autocomplete.h"
+#include "chrome/browser/autocomplete/autocomplete_classifier.h"
+#include "chrome/browser/autocomplete/autocomplete_match.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/debugger/devtools_window.h"
+#include "chrome/browser/net/url_fixer_upper.h"
+#include "chrome/browser/sidebar/sidebar_container.h"
+#include "chrome/browser/sidebar/sidebar_manager.h"
+#include "chrome/browser/tab_contents/navigation_controller.h"
+#include "chrome/browser/tab_contents/navigation_entry.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_contents_view.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_navigator.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "chrome/browser/ui/cocoa/constrained_window_mac.h"
+#import "chrome/browser/ui/cocoa/new_tab_button.h"
+#import "chrome/browser/ui/cocoa/tab_strip_view.h"
+#import "chrome/browser/ui/cocoa/tab_contents_controller.h"
+#import "chrome/browser/ui/cocoa/tab_controller.h"
+#import "chrome/browser/ui/cocoa/tab_strip_model_observer_bridge.h"
+#import "chrome/browser/ui/cocoa/tab_view.h"
+#import "chrome/browser/ui/cocoa/throbber_view.h"
+#include "chrome/browser/ui/find_bar/find_bar.h"
+#include "chrome/browser/ui/find_bar/find_bar_controller.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "grit/app_resources.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "skia/ext/skia_utils_mac.h"
+#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
+
+NSString* const kTabStripNumberOfTabsChanged = @"kTabStripNumberOfTabsChanged";
+
+namespace {
+
+// The images names used for different states of the new tab button.
+NSString* const kNewTabHoverImage = @"newtab_h.pdf";
+NSString* const kNewTabImage = @"newtab.pdf";
+NSString* const kNewTabPressedImage = @"newtab_p.pdf";
+
+// A value to indicate tab layout should use the full available width of the
+// view.
+const CGFloat kUseFullAvailableWidth = -1.0;
+
+// The amount by which tabs overlap.
+const CGFloat kTabOverlap = 20.0;
+
+// The width and height for a tab's icon.
+const CGFloat kIconWidthAndHeight = 16.0;
+
+// The amount by which the new tab button is offset (from the tabs).
+const CGFloat kNewTabButtonOffset = 8.0;
+
+// The amount by which to shrink the tab strip (on the right) when the
+// incognito badge is present.
+const CGFloat kIncognitoBadgeTabStripShrink = 18;
+
+// Time (in seconds) in which tabs animate to their final position.
+const NSTimeInterval kAnimationDuration = 0.125;
+
+// Helper class for doing NSAnimationContext calls that takes a bool to disable
+// all the work. Useful for code that wants to conditionally animate.
+class ScopedNSAnimationContextGroup {
+ public:
+ explicit ScopedNSAnimationContextGroup(bool animate)
+ : animate_(animate) {
+ if (animate_) {
+ [NSAnimationContext beginGrouping];
+ }
+ }
+
+ ~ScopedNSAnimationContextGroup() {
+ if (animate_) {
+ [NSAnimationContext endGrouping];
+ }
+ }
+
+ void SetCurrentContextDuration(NSTimeInterval duration) {
+ if (animate_) {
+ [[NSAnimationContext currentContext] gtm_setDuration:duration
+ eventMask:NSLeftMouseUpMask];
+ }
+ }
+
+ void SetCurrentContextShortestDuration() {
+ if (animate_) {
+ // The minimum representable time interval. This used to stop an
+ // in-progress animation as quickly as possible.
+ const NSTimeInterval kMinimumTimeInterval =
+ std::numeric_limits<NSTimeInterval>::min();
+ // Directly set the duration to be short, avoiding the Steve slowmotion
+ // ettect the gtm_setDuration: provides.
+ [[NSAnimationContext currentContext] setDuration:kMinimumTimeInterval];
+ }
+ }
+
+private:
+ bool animate_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedNSAnimationContextGroup);
+};
+
+} // namespace
+
+@interface TabStripController (Private)
+- (void)installTrackingArea;
+- (void)addSubviewToPermanentList:(NSView*)aView;
+- (void)regenerateSubviewList;
+- (NSInteger)indexForContentsView:(NSView*)view;
+- (void)updateFavIconForContents:(TabContents*)contents
+ atIndex:(NSInteger)modelIndex;
+- (void)layoutTabsWithAnimation:(BOOL)animate
+ regenerateSubviews:(BOOL)doUpdate;
+- (void)animationDidStopForController:(TabController*)controller
+ finished:(BOOL)finished;
+- (NSInteger)indexFromModelIndex:(NSInteger)index;
+- (NSInteger)numberOfOpenTabs;
+- (NSInteger)numberOfOpenMiniTabs;
+- (NSInteger)numberOfOpenNonMiniTabs;
+- (void)mouseMoved:(NSEvent*)event;
+- (void)setTabTrackingAreasEnabled:(BOOL)enabled;
+- (void)droppingURLsAt:(NSPoint)point
+ givesIndex:(NSInteger*)index
+ disposition:(WindowOpenDisposition*)disposition;
+- (void)setNewTabButtonHoverState:(BOOL)showHover;
+@end
+
+// A simple view class that prevents the Window Server from dragging the area
+// behind tabs. Sometimes core animation confuses it. Unfortunately, it can also
+// falsely pick up clicks during rapid tab closure, so we have to account for
+// that.
+@interface TabStripControllerDragBlockingView : NSView {
+ TabStripController* controller_; // weak; owns us
+}
+
+- (id)initWithFrame:(NSRect)frameRect
+ controller:(TabStripController*)controller;
+@end
+
+@implementation TabStripControllerDragBlockingView
+- (BOOL)mouseDownCanMoveWindow {return NO;}
+- (void)drawRect:(NSRect)rect {}
+
+- (id)initWithFrame:(NSRect)frameRect
+ controller:(TabStripController*)controller {
+ if ((self = [super initWithFrame:frameRect]))
+ controller_ = controller;
+ return self;
+}
+
+// In "rapid tab closure" mode (i.e., the user is clicking close tab buttons in
+// rapid succession), the animations confuse Cocoa's hit testing (which appears
+// to use cached results, among other tricks), so this view can somehow end up
+// getting a mouse down event. Thus we do an explicit hit test during rapid tab
+// closure, and if we find that we got a mouse down we shouldn't have, we send
+// it off to the appropriate view.
+- (void)mouseDown:(NSEvent*)event {
+ if ([controller_ inRapidClosureMode]) {
+ NSView* superview = [self superview];
+ NSPoint hitLocation =
+ [[superview superview] convertPoint:[event locationInWindow]
+ fromView:nil];
+ NSView* hitView = [superview hitTest:hitLocation];
+ if (hitView != self) {
+ [hitView mouseDown:event];
+ return;
+ }
+ }
+ [super mouseDown:event];
+}
+@end
+
+#pragma mark -
+
+// A delegate, owned by the CAAnimation system, that is alerted when the
+// animation to close a tab is completed. Calls back to the given tab strip
+// to let it know that |controller_| is ready to be removed from the model.
+// Since we only maintain weak references, the tab strip must call -invalidate:
+// to prevent the use of dangling pointers.
+@interface TabCloseAnimationDelegate : NSObject {
+ @private
+ TabStripController* strip_; // weak; owns us indirectly
+ TabController* controller_; // weak
+}
+
+// Will tell |strip| when the animation for |controller|'s view has completed.
+// These should not be nil, and will not be retained.
+- (id)initWithTabStrip:(TabStripController*)strip
+ tabController:(TabController*)controller;
+
+// Invalidates this object so that no further calls will be made to
+// |strip_|. This should be called when |strip_| is released, to
+// prevent attempts to call into the released object.
+- (void)invalidate;
+
+// CAAnimation delegate method
+- (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)finished;
+
+@end
+
+@implementation TabCloseAnimationDelegate
+
+- (id)initWithTabStrip:(TabStripController*)strip
+ tabController:(TabController*)controller {
+ if ((self == [super init])) {
+ DCHECK(strip && controller);
+ strip_ = strip;
+ controller_ = controller;
+ }
+ return self;
+}
+
+- (void)invalidate {
+ strip_ = nil;
+ controller_ = nil;
+}
+
+- (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)finished {
+ [strip_ animationDidStopForController:controller_ finished:finished];
+}
+
+@end
+
+#pragma mark -
+
+// In general, there is a one-to-one correspondence between TabControllers,
+// TabViews, TabContentsControllers, and the TabContents in the TabStripModel.
+// In the steady-state, the indices line up so an index coming from the model
+// is directly mapped to the same index in the parallel arrays holding our
+// views and controllers. This is also true when new tabs are created (even
+// though there is a small period of animation) because the tab is present
+// in the model while the TabView is animating into place. As a result, nothing
+// special need be done to handle "new tab" animation.
+//
+// This all goes out the window with the "close tab" animation. The animation
+// kicks off in |-tabDetachedWithContents:atIndex:| with the notification that
+// the tab has been removed from the model. The simplest solution at this
+// point would be to remove the views and controllers as well, however once
+// the TabView is removed from the view list, the tab z-order code takes care of
+// removing it from the tab strip and we'll get no animation. That means if
+// there is to be any visible animation, the TabView needs to stay around until
+// its animation is complete. In order to maintain consistency among the
+// internal parallel arrays, this means all structures are kept around until
+// the animation completes. At this point, though, the model and our internal
+// structures are out of sync: the indices no longer line up. As a result,
+// there is a concept of a "model index" which represents an index valid in
+// the TabStripModel. During steady-state, the "model index" is just the same
+// index as our parallel arrays (as above), but during tab close animations,
+// it is different, offset by the number of tabs preceding the index which
+// are undergoing tab closing animation. As a result, the caller needs to be
+// careful to use the available conversion routines when accessing the internal
+// parallel arrays (e.g., -indexFromModelIndex:). Care also needs to be taken
+// during tab layout to ignore closing tabs in the total width calculations and
+// in individual tab positioning (to avoid moving them right back to where they
+// were).
+//
+// In order to prevent actions being taken on tabs which are closing, the tab
+// itself gets marked as such so it no longer will send back its select action
+// or allow itself to be dragged. In addition, drags on the tab strip as a
+// whole are disabled while there are tabs closing.
+
+@implementation TabStripController
+
+@synthesize indentForControls = indentForControls_;
+
+- (id)initWithView:(TabStripView*)view
+ switchView:(NSView*)switchView
+ browser:(Browser*)browser
+ delegate:(id<TabStripControllerDelegate>)delegate {
+ DCHECK(view && switchView && browser && delegate);
+ if ((self = [super init])) {
+ tabStripView_.reset([view retain]);
+ switchView_ = switchView;
+ browser_ = browser;
+ tabStripModel_ = browser_->tabstrip_model();
+ delegate_ = delegate;
+ bridge_.reset(new TabStripModelObserverBridge(tabStripModel_, self));
+ tabContentsArray_.reset([[NSMutableArray alloc] init]);
+ tabArray_.reset([[NSMutableArray alloc] init]);
+
+ // Important note: any non-tab subviews not added to |permanentSubviews_|
+ // (see |-addSubviewToPermanentList:|) will be wiped out.
+ permanentSubviews_.reset([[NSMutableArray alloc] init]);
+
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ defaultFavIcon_.reset([rb.GetNativeImageNamed(IDR_DEFAULT_FAVICON) retain]);
+
+ [self setIndentForControls:[[self class] defaultIndentForControls]];
+
+ // TODO(viettrungluu): WTF? "For some reason, if the view is present in the
+ // nib a priori, it draws correctly. If we create it in code and add it to
+ // the tab view, it draws with all sorts of crazy artifacts."
+ newTabButton_ = [view newTabButton];
+ [self addSubviewToPermanentList:newTabButton_];
+ [newTabButton_ setTarget:nil];
+ [newTabButton_ setAction:@selector(commandDispatch:)];
+ [newTabButton_ setTag:IDC_NEW_TAB];
+ // Set the images from code because Cocoa fails to find them in our sub
+ // bundle during tests.
+ [newTabButton_ setImage:app::mac::GetCachedImageWithName(kNewTabImage)];
+ [newTabButton_ setAlternateImage:
+ app::mac::GetCachedImageWithName(kNewTabPressedImage)];
+ newTabButtonShowingHoverImage_ = NO;
+ newTabTrackingArea_.reset(
+ [[NSTrackingArea alloc] initWithRect:[newTabButton_ bounds]
+ options:(NSTrackingMouseEnteredAndExited |
+ NSTrackingActiveAlways)
+ owner:self
+ userInfo:nil]);
+ [newTabButton_ addTrackingArea:newTabTrackingArea_.get()];
+ targetFrames_.reset([[NSMutableDictionary alloc] init]);
+
+ dragBlockingView_.reset(
+ [[TabStripControllerDragBlockingView alloc] initWithFrame:NSZeroRect
+ controller:self]);
+ [self addSubviewToPermanentList:dragBlockingView_];
+
+ newTabTargetFrame_ = NSMakeRect(0, 0, 0, 0);
+ availableResizeWidth_ = kUseFullAvailableWidth;
+
+ closingControllers_.reset([[NSMutableSet alloc] init]);
+
+ // Install the permanent subviews.
+ [self regenerateSubviewList];
+
+ // Watch for notifications that the tab strip view has changed size so
+ // we can tell it to layout for the new size.
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(tabViewFrameChanged:)
+ name:NSViewFrameDidChangeNotification
+ object:tabStripView_];
+
+ trackingArea_.reset([[NSTrackingArea alloc]
+ initWithRect:NSZeroRect // Ignored by NSTrackingInVisibleRect
+ options:NSTrackingMouseEnteredAndExited |
+ NSTrackingMouseMoved |
+ NSTrackingActiveAlways |
+ NSTrackingInVisibleRect
+ owner:self
+ userInfo:nil]);
+ [tabStripView_ addTrackingArea:trackingArea_.get()];
+
+ // Check to see if the mouse is currently in our bounds so we can
+ // enable the tracking areas. Otherwise we won't get hover states
+ // or tab gradients if we load the window up under the mouse.
+ NSPoint mouseLoc = [[view window] mouseLocationOutsideOfEventStream];
+ mouseLoc = [view convertPoint:mouseLoc fromView:nil];
+ if (NSPointInRect(mouseLoc, [view bounds])) {
+ [self setTabTrackingAreasEnabled:YES];
+ mouseInside_ = YES;
+ }
+
+ // Set accessibility descriptions. http://openradar.appspot.com/7496255
+ NSString* description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_NEWTAB);
+ [[newTabButton_ cell]
+ accessibilitySetOverrideValue:description
+ forAttribute:NSAccessibilityDescriptionAttribute];
+
+ // Controller may have been (re-)created by switching layout modes, which
+ // means the tab model is already fully formed with tabs. Need to walk the
+ // list and create the UI for each.
+ const int existingTabCount = tabStripModel_->count();
+ const TabContentsWrapper* selection =
+ tabStripModel_->GetSelectedTabContents();
+ for (int i = 0; i < existingTabCount; ++i) {
+ TabContentsWrapper* currentContents = tabStripModel_->GetTabContentsAt(i);
+ [self insertTabWithContents:currentContents
+ atIndex:i
+ inForeground:NO];
+ if (selection == currentContents) {
+ // Must manually force a selection since the model won't send
+ // selection messages in this scenario.
+ [self selectTabWithContents:currentContents
+ previousContents:NULL
+ atIndex:i
+ userGesture:NO];
+ }
+ }
+ // Don't lay out the tabs until after the controller has been fully
+ // constructed. The |verticalLayout_| flag has not been initialized by
+ // subclasses at this point, which would cause layout to potentially use
+ // the wrong mode.
+ if (existingTabCount) {
+ [self performSelectorOnMainThread:@selector(layoutTabs)
+ withObject:nil
+ waitUntilDone:NO];
+ }
+ }
+ return self;
+}
+
+- (void)dealloc {
+ if (trackingArea_.get())
+ [tabStripView_ removeTrackingArea:trackingArea_.get()];
+
+ [newTabButton_ removeTrackingArea:newTabTrackingArea_.get()];
+ // Invalidate all closing animations so they don't call back to us after
+ // we're gone.
+ for (TabController* controller in closingControllers_.get()) {
+ NSView* view = [controller view];
+ [[[view animationForKey:@"frameOrigin"] delegate] invalidate];
+ }
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
++ (CGFloat)defaultTabHeight {
+ return 25.0;
+}
+
++ (CGFloat)defaultIndentForControls {
+ // Default indentation leaves enough room so tabs don't overlap with the
+ // window controls.
+ return 64.0;
+}
+
+// Finds the TabContentsController associated with the given index into the tab
+// model and swaps out the sole child of the contentArea to display its
+// contents.
+- (void)swapInTabAtIndex:(NSInteger)modelIndex {
+ DCHECK(modelIndex >= 0 && modelIndex < tabStripModel_->count());
+ NSInteger index = [self indexFromModelIndex:modelIndex];
+ TabContentsController* controller = [tabContentsArray_ objectAtIndex:index];
+
+ // Resize the new view to fit the window. Calling |view| may lazily
+ // instantiate the TabContentsController from the nib. Until we call
+ // |-ensureContentsVisible|, the controller doesn't install the RWHVMac into
+ // the view hierarchy. This is in order to avoid sending the renderer a
+ // spurious default size loaded from the nib during the call to |-view|.
+ NSView* newView = [controller view];
+
+ // Turns content autoresizing off, so removing and inserting views won't
+ // trigger unnecessary content relayout.
+ [controller ensureContentsSizeDoesNotChange];
+
+ // Remove the old view from the view hierarchy. We know there's only one
+ // child of |switchView_| because we're the one who put it there. There
+ // may not be any children in the case of a tab that's been closed, in
+ // which case there's no swapping going on.
+ NSArray* subviews = [switchView_ subviews];
+ if ([subviews count]) {
+ NSView* oldView = [subviews objectAtIndex:0];
+ // Set newView frame to the oldVew frame to prevent NSSplitView hosting
+ // sidebar and tab content from resizing sidebar's content view.
+ // ensureContentsVisible (see below) sets content size and autoresizing
+ // properties.
+ [newView setFrame:[oldView frame]];
+ [switchView_ replaceSubview:oldView with:newView];
+ } else {
+ [newView setFrame:[switchView_ bounds]];
+ [switchView_ addSubview:newView];
+ }
+
+ // New content is in place, delegate should adjust itself accordingly.
+ [delegate_ onSelectTabWithContents:[controller tabContents]];
+
+ // It also restores content autoresizing properties.
+ [controller ensureContentsVisible];
+
+ // Make sure the new tabs's sheets are visible (necessary when a background
+ // tab opened a sheet while it was in the background and now becomes active).
+ TabContentsWrapper* newTab = tabStripModel_->GetTabContentsAt(modelIndex);
+ DCHECK(newTab);
+ if (newTab) {
+ TabContents::ConstrainedWindowList::iterator it, end;
+ end = newTab->tab_contents()->constrained_window_end();
+ NSWindowController* controller = [[newView window] windowController];
+ DCHECK([controller isKindOfClass:[BrowserWindowController class]]);
+
+ for (it = newTab->tab_contents()->constrained_window_begin();
+ it != end;
+ ++it) {
+ ConstrainedWindow* constrainedWindow = *it;
+ static_cast<ConstrainedWindowMac*>(constrainedWindow)->Realize(
+ static_cast<BrowserWindowController*>(controller));
+ }
+ }
+
+ // Tell per-tab sheet manager about currently selected tab.
+ if (sheetController_.get()) {
+ [sheetController_ setActiveView:newView];
+ }
+}
+
+// Create a new tab view and set its cell correctly so it draws the way we want
+// it to. It will be sized and positioned by |-layoutTabs| so there's no need to
+// set the frame here. This also creates the view as hidden, it will be
+// shown during layout.
+- (TabController*)newTab {
+ TabController* controller = [[[TabController alloc] init] autorelease];
+ [controller setTarget:self];
+ [controller setAction:@selector(selectTab:)];
+ [[controller view] setHidden:YES];
+
+ return controller;
+}
+
+// (Private) Returns the number of open tabs in the tab strip. This is the
+// number of TabControllers we know about (as there's a 1-to-1 mapping from
+// these controllers to a tab) less the number of closing tabs.
+- (NSInteger)numberOfOpenTabs {
+ return static_cast<NSInteger>(tabStripModel_->count());
+}
+
+// (Private) Returns the number of open, mini-tabs.
+- (NSInteger)numberOfOpenMiniTabs {
+ // Ask the model for the number of mini tabs. Note that tabs which are in
+ // the process of closing (i.e., whose controllers are in
+ // |closingControllers_|) have already been removed from the model.
+ return tabStripModel_->IndexOfFirstNonMiniTab();
+}
+
+// (Private) Returns the number of open, non-mini tabs.
+- (NSInteger)numberOfOpenNonMiniTabs {
+ NSInteger number = [self numberOfOpenTabs] - [self numberOfOpenMiniTabs];
+ DCHECK_GE(number, 0);
+ return number;
+}
+
+// Given an index into the tab model, returns the index into the tab controller
+// or tab contents controller array accounting for tabs that are currently
+// closing. For example, if there are two tabs in the process of closing before
+// |index|, this returns |index| + 2. If there are no closing tabs, this will
+// return |index|.
+- (NSInteger)indexFromModelIndex:(NSInteger)index {
+ DCHECK(index >= 0);
+ if (index < 0)
+ return index;
+
+ NSInteger i = 0;
+ for (TabController* controller in tabArray_.get()) {
+ if ([closingControllers_ containsObject:controller]) {
+ DCHECK([(TabView*)[controller view] isClosing]);
+ ++index;
+ }
+ if (i == index) // No need to check anything after, it has no effect.
+ break;
+ ++i;
+ }
+ return index;
+}
+
+
+// Returns the index of the subview |view|. Returns -1 if not present. Takes
+// closing tabs into account such that this index will correctly match the tab
+// model. If |view| is in the process of closing, returns -1, as closing tabs
+// are no longer in the model.
+- (NSInteger)modelIndexForTabView:(NSView*)view {
+ NSInteger index = 0;
+ for (TabController* current in tabArray_.get()) {
+ // If |current| is closing, skip it.
+ if ([closingControllers_ containsObject:current])
+ continue;
+ else if ([current view] == view)
+ return index;
+ ++index;
+ }
+ return -1;
+}
+
+// Returns the index of the contents subview |view|. Returns -1 if not present.
+// Takes closing tabs into account such that this index will correctly match the
+// tab model. If |view| is in the process of closing, returns -1, as closing
+// tabs are no longer in the model.
+- (NSInteger)modelIndexForContentsView:(NSView*)view {
+ NSInteger index = 0;
+ NSInteger i = 0;
+ for (TabContentsController* current in tabContentsArray_.get()) {
+ // If the TabController corresponding to |current| is closing, skip it.
+ TabController* controller = [tabArray_ objectAtIndex:i];
+ if ([closingControllers_ containsObject:controller]) {
+ ++i;
+ continue;
+ } else if ([current view] == view) {
+ return index;
+ }
+ ++index;
+ ++i;
+ }
+ return -1;
+}
+
+
+// Returns the view at the given index, using the array of TabControllers to
+// get the associated view. Returns nil if out of range.
+- (NSView*)viewAtIndex:(NSUInteger)index {
+ if (index >= [tabArray_ count])
+ return NULL;
+ return [[tabArray_ objectAtIndex:index] view];
+}
+
+- (NSUInteger)viewsCount {
+ return [tabArray_ count];
+}
+
+// Called when the user clicks a tab. Tell the model the selection has changed,
+// which feeds back into us via a notification.
+- (void)selectTab:(id)sender {
+ DCHECK([sender isKindOfClass:[NSView class]]);
+ int index = [self modelIndexForTabView:sender];
+ if (tabStripModel_->ContainsIndex(index))
+ tabStripModel_->SelectTabContentsAt(index, true);
+}
+
+// Called when the user closes a tab. Asks the model to close the tab. |sender|
+// is the TabView that is potentially going away.
+- (void)closeTab:(id)sender {
+ DCHECK([sender isKindOfClass:[TabView class]]);
+ if ([hoveredTab_ isEqual:sender]) {
+ hoveredTab_ = nil;
+ }
+
+ NSInteger index = [self modelIndexForTabView:sender];
+ if (!tabStripModel_->ContainsIndex(index))
+ return;
+
+ TabContentsWrapper* contents = tabStripModel_->GetTabContentsAt(index);
+ if (contents)
+ UserMetrics::RecordAction(UserMetricsAction("CloseTab_Mouse"),
+ contents->tab_contents()->profile());
+ const NSInteger numberOfOpenTabs = [self numberOfOpenTabs];
+ if (numberOfOpenTabs > 1) {
+ bool isClosingLastTab = index == numberOfOpenTabs - 1;
+ if (!isClosingLastTab) {
+ // Limit the width available for laying out tabs so that tabs are not
+ // resized until a later time (when the mouse leaves the tab strip).
+ // However, if the tab being closed is a pinned tab, break out of
+ // rapid-closure mode since the mouse is almost guaranteed not to be over
+ // the closebox of the adjacent tab (due to the difference in widths).
+ // TODO(pinkerton): re-visit when handling tab overflow.
+ // http://crbug.com/188
+ if (tabStripModel_->IsTabPinned(index)) {
+ availableResizeWidth_ = kUseFullAvailableWidth;
+ } else {
+ NSView* penultimateTab = [self viewAtIndex:numberOfOpenTabs - 2];
+ availableResizeWidth_ = NSMaxX([penultimateTab frame]);
+ }
+ } else {
+ // If the rightmost tab is closed, change the available width so that
+ // another tab's close button lands below the cursor (assuming the tabs
+ // are currently below their maximum width and can grow).
+ NSView* lastTab = [self viewAtIndex:numberOfOpenTabs - 1];
+ availableResizeWidth_ = NSMaxX([lastTab frame]);
+ }
+ tabStripModel_->CloseTabContentsAt(
+ index,
+ TabStripModel::CLOSE_USER_GESTURE |
+ TabStripModel::CLOSE_CREATE_HISTORICAL_TAB);
+ } else {
+ // Use the standard window close if this is the last tab
+ // this prevents the tab from being removed from the model until after
+ // the window dissapears
+ [[tabStripView_ window] performClose:nil];
+ }
+}
+
+// Dispatch context menu commands for the given tab controller.
+- (void)commandDispatch:(TabStripModel::ContextMenuCommand)command
+ forController:(TabController*)controller {
+ int index = [self modelIndexForTabView:[controller view]];
+ if (tabStripModel_->ContainsIndex(index))
+ tabStripModel_->ExecuteContextMenuCommand(index, command);
+}
+
+// Returns YES if the specificed command should be enabled for the given
+// controller.
+- (BOOL)isCommandEnabled:(TabStripModel::ContextMenuCommand)command
+ forController:(TabController*)controller {
+ int index = [self modelIndexForTabView:[controller view]];
+ if (!tabStripModel_->ContainsIndex(index))
+ return NO;
+ return tabStripModel_->IsContextMenuCommandEnabled(index, command) ? YES : NO;
+}
+
+- (void)insertPlaceholderForTab:(TabView*)tab
+ frame:(NSRect)frame
+ yStretchiness:(CGFloat)yStretchiness {
+ placeholderTab_ = tab;
+ placeholderFrame_ = frame;
+ placeholderStretchiness_ = yStretchiness;
+ [self layoutTabsWithAnimation:initialLayoutComplete_ regenerateSubviews:NO];
+}
+
+- (BOOL)isDragSessionActive {
+ return placeholderTab_ != nil;
+}
+
+- (BOOL)isTabFullyVisible:(TabView*)tab {
+ NSRect frame = [tab frame];
+ return NSMinX(frame) >= [self indentForControls] &&
+ NSMaxX(frame) <= NSMaxX([tabStripView_ frame]);
+}
+
+- (void)showNewTabButton:(BOOL)show {
+ forceNewTabButtonHidden_ = show ? NO : YES;
+ if (forceNewTabButtonHidden_)
+ [newTabButton_ setHidden:YES];
+}
+
+// Lay out all tabs in the order of their TabContentsControllers, which matches
+// the ordering in the TabStripModel. This call isn't that expensive, though
+// it is O(n) in the number of tabs. Tabs will animate to their new position
+// if the window is visible and |animate| is YES.
+// TODO(pinkerton): Note this doesn't do too well when the number of min-sized
+// tabs would cause an overflow. http://crbug.com/188
+- (void)layoutTabsWithAnimation:(BOOL)animate
+ regenerateSubviews:(BOOL)doUpdate {
+ DCHECK([NSThread isMainThread]);
+ if (![tabArray_ count])
+ return;
+
+ const CGFloat kMaxTabWidth = [TabController maxTabWidth];
+ const CGFloat kMinTabWidth = [TabController minTabWidth];
+ const CGFloat kMinSelectedTabWidth = [TabController minSelectedTabWidth];
+ const CGFloat kMiniTabWidth = [TabController miniTabWidth];
+ const CGFloat kAppTabWidth = [TabController appTabWidth];
+
+ NSRect enclosingRect = NSZeroRect;
+ ScopedNSAnimationContextGroup mainAnimationGroup(animate);
+ mainAnimationGroup.SetCurrentContextDuration(kAnimationDuration);
+
+ // Update the current subviews and their z-order if requested.
+ if (doUpdate)
+ [self regenerateSubviewList];
+
+ // Compute the base width of tabs given how much room we're allowed. Note that
+ // mini-tabs have a fixed width. We may not be able to use the entire width
+ // if the user is quickly closing tabs. This may be negative, but that's okay
+ // (taken care of by |MAX()| when calculating tab sizes).
+ CGFloat availableSpace = 0;
+ if (verticalLayout_) {
+ availableSpace = NSHeight([tabStripView_ bounds]);
+ } else {
+ if ([self inRapidClosureMode]) {
+ availableSpace = availableResizeWidth_;
+ } else {
+ availableSpace = NSWidth([tabStripView_ frame]);
+ // Account for the new tab button and the incognito badge.
+ availableSpace -= NSWidth([newTabButton_ frame]) + kNewTabButtonOffset;
+ if (browser_->profile()->IsOffTheRecord())
+ availableSpace -= kIncognitoBadgeTabStripShrink;
+ }
+ availableSpace -= [self indentForControls];
+ }
+
+ // This may be negative, but that's okay (taken care of by |MAX()| when
+ // calculating tab sizes). "mini" tabs in horizontal mode just get a special
+ // section, they don't change size.
+ CGFloat availableSpaceForNonMini = availableSpace;
+ if (!verticalLayout_) {
+ availableSpaceForNonMini -=
+ [self numberOfOpenMiniTabs] * (kMiniTabWidth - kTabOverlap);
+ }
+
+ // Initialize |nonMiniTabWidth| in case there aren't any non-mini-tabs; this
+ // value shouldn't actually be used.
+ CGFloat nonMiniTabWidth = kMaxTabWidth;
+ const NSInteger numberOfOpenNonMiniTabs = [self numberOfOpenNonMiniTabs];
+ if (!verticalLayout_ && numberOfOpenNonMiniTabs) {
+ // Find the width of a non-mini-tab. This only applies to horizontal
+ // mode. Add in the amount we "get back" from the tabs overlapping.
+ availableSpaceForNonMini += (numberOfOpenNonMiniTabs - 1) * kTabOverlap;
+
+ // Divide up the space between the non-mini-tabs.
+ nonMiniTabWidth = availableSpaceForNonMini / numberOfOpenNonMiniTabs;
+
+ // Clamp the width between the max and min.
+ nonMiniTabWidth = MAX(MIN(nonMiniTabWidth, kMaxTabWidth), kMinTabWidth);
+ }
+
+ BOOL visible = [[tabStripView_ window] isVisible];
+
+ CGFloat offset = [self indentForControls];
+ NSUInteger i = 0;
+ bool hasPlaceholderGap = false;
+ for (TabController* tab in tabArray_.get()) {
+ // Ignore a tab that is going through a close animation.
+ if ([closingControllers_ containsObject:tab])
+ continue;
+
+ BOOL isPlaceholder = [[tab view] isEqual:placeholderTab_];
+ NSRect tabFrame = [[tab view] frame];
+ tabFrame.size.height = [[self class] defaultTabHeight] + 1;
+ if (verticalLayout_) {
+ tabFrame.origin.y = availableSpace - tabFrame.size.height - offset;
+ tabFrame.origin.x = 0;
+ } else {
+ tabFrame.origin.y = 0;
+ tabFrame.origin.x = offset;
+ }
+ // If the tab is hidden, we consider it a new tab. We make it visible
+ // and animate it in.
+ BOOL newTab = [[tab view] isHidden];
+ if (newTab) {
+ [[tab view] setHidden:NO];
+ }
+
+ if (isPlaceholder) {
+ // Move the current tab to the correct location instantly.
+ // We need a duration or else it doesn't cancel an inflight animation.
+ ScopedNSAnimationContextGroup localAnimationGroup(animate);
+ localAnimationGroup.SetCurrentContextShortestDuration();
+ if (verticalLayout_)
+ tabFrame.origin.y = availableSpace - tabFrame.size.height - offset;
+ else
+ tabFrame.origin.x = placeholderFrame_.origin.x;
+ // TODO(alcor): reenable this
+ //tabFrame.size.height += 10.0 * placeholderStretchiness_;
+ id target = animate ? [[tab view] animator] : [tab view];
+ [target setFrame:tabFrame];
+
+ // Store the frame by identifier to aviod redundant calls to animator.
+ NSValue* identifier = [NSValue valueWithPointer:[tab view]];
+ [targetFrames_ setObject:[NSValue valueWithRect:tabFrame]
+ forKey:identifier];
+ continue;
+ }
+
+ if (placeholderTab_ && !hasPlaceholderGap) {
+ const CGFloat placeholderMin =
+ verticalLayout_ ? NSMinY(placeholderFrame_) :
+ NSMinX(placeholderFrame_);
+ if (verticalLayout_) {
+ if (NSMidY(tabFrame) > placeholderMin) {
+ hasPlaceholderGap = true;
+ offset += NSHeight(placeholderFrame_);
+ tabFrame.origin.y = availableSpace - tabFrame.size.height - offset;
+ }
+ } else {
+ // If the left edge is to the left of the placeholder's left, but the
+ // mid is to the right of it slide over to make space for it.
+ if (NSMidX(tabFrame) > placeholderMin) {
+ hasPlaceholderGap = true;
+ offset += NSWidth(placeholderFrame_);
+ offset -= kTabOverlap;
+ tabFrame.origin.x = offset;
+ }
+ }
+ }
+
+ // Set the width. Selected tabs are slightly wider when things get really
+ // small and thus we enforce a different minimum width.
+ tabFrame.size.width = [tab mini] ?
+ ([tab app] ? kAppTabWidth : kMiniTabWidth) : nonMiniTabWidth;
+ if ([tab selected])
+ tabFrame.size.width = MAX(tabFrame.size.width, kMinSelectedTabWidth);
+
+ // Animate a new tab in by putting it below the horizon unless told to put
+ // it in a specific location (i.e., from a drop).
+ // TODO(pinkerton): figure out vertical tab animations.
+ if (newTab && visible && animate) {
+ if (NSEqualRects(droppedTabFrame_, NSZeroRect)) {
+ [[tab view] setFrame:NSOffsetRect(tabFrame, 0, -NSHeight(tabFrame))];
+ } else {
+ [[tab view] setFrame:droppedTabFrame_];
+ droppedTabFrame_ = NSZeroRect;
+ }
+ }
+
+ // Check the frame by identifier to avoid redundant calls to animator.
+ id frameTarget = visible && animate ? [[tab view] animator] : [tab view];
+ NSValue* identifier = [NSValue valueWithPointer:[tab view]];
+ NSValue* oldTargetValue = [targetFrames_ objectForKey:identifier];
+ if (!oldTargetValue ||
+ !NSEqualRects([oldTargetValue rectValue], tabFrame)) {
+ [frameTarget setFrame:tabFrame];
+ [targetFrames_ setObject:[NSValue valueWithRect:tabFrame]
+ forKey:identifier];
+ }
+
+ enclosingRect = NSUnionRect(tabFrame, enclosingRect);
+
+ if (verticalLayout_) {
+ offset += NSHeight(tabFrame);
+ } else {
+ offset += NSWidth(tabFrame);
+ offset -= kTabOverlap;
+ }
+ i++;
+ }
+
+ // Hide the new tab button if we're explicitly told to. It may already
+ // be hidden, doing it again doesn't hurt. Otherwise position it
+ // appropriately, showing it if necessary.
+ if (forceNewTabButtonHidden_) {
+ [newTabButton_ setHidden:YES];
+ } else {
+ NSRect newTabNewFrame = [newTabButton_ frame];
+ // We've already ensured there's enough space for the new tab button
+ // so we don't have to check it against the available space. We do need
+ // to make sure we put it after any placeholder.
+ newTabNewFrame.origin = NSMakePoint(offset, 0);
+ newTabNewFrame.origin.x = MAX(newTabNewFrame.origin.x,
+ NSMaxX(placeholderFrame_)) +
+ kNewTabButtonOffset;
+ if ([tabContentsArray_ count])
+ [newTabButton_ setHidden:NO];
+
+ if (!NSEqualRects(newTabTargetFrame_, newTabNewFrame)) {
+ // Set the new tab button image correctly based on where the cursor is.
+ NSWindow* window = [tabStripView_ window];
+ NSPoint currentMouse = [window mouseLocationOutsideOfEventStream];
+ currentMouse = [tabStripView_ convertPoint:currentMouse fromView:nil];
+
+ BOOL shouldShowHover = [newTabButton_ pointIsOverButton:currentMouse];
+ [self setNewTabButtonHoverState:shouldShowHover];
+
+ // Move the new tab button into place. We want to animate the new tab
+ // button if it's moving to the left (closing a tab), but not when it's
+ // moving to the right (inserting a new tab). If moving right, we need
+ // to use a very small duration to make sure we cancel any in-flight
+ // animation to the left.
+ if (visible && animate) {
+ ScopedNSAnimationContextGroup localAnimationGroup(true);
+ BOOL movingLeft = NSMinX(newTabNewFrame) < NSMinX(newTabTargetFrame_);
+ if (!movingLeft) {
+ localAnimationGroup.SetCurrentContextShortestDuration();
+ }
+ [[newTabButton_ animator] setFrame:newTabNewFrame];
+ newTabTargetFrame_ = newTabNewFrame;
+ } else {
+ [newTabButton_ setFrame:newTabNewFrame];
+ newTabTargetFrame_ = newTabNewFrame;
+ }
+ }
+ }
+
+ [dragBlockingView_ setFrame:enclosingRect];
+
+ // Mark that we've successfully completed layout of at least one tab.
+ initialLayoutComplete_ = YES;
+}
+
+// When we're told to layout from the public API we usually want to animate,
+// except when it's the first time.
+- (void)layoutTabs {
+ [self layoutTabsWithAnimation:initialLayoutComplete_ regenerateSubviews:YES];
+}
+
+// Handles setting the title of the tab based on the given |contents|. Uses
+// a canned string if |contents| is NULL.
+- (void)setTabTitle:(NSViewController*)tab withContents:(TabContents*)contents {
+ NSString* titleString = nil;
+ if (contents)
+ titleString = base::SysUTF16ToNSString(contents->GetTitle());
+ if (![titleString length]) {
+ titleString = l10n_util::GetNSString(IDS_BROWSER_WINDOW_MAC_TAB_UNTITLED);
+ }
+ [tab setTitle:titleString];
+}
+
+// Called when a notification is received from the model to insert a new tab
+// at |modelIndex|.
+- (void)insertTabWithContents:(TabContentsWrapper*)contents
+ atIndex:(NSInteger)modelIndex
+ inForeground:(bool)inForeground {
+ DCHECK(contents);
+ DCHECK(modelIndex == TabStripModel::kNoTab ||
+ tabStripModel_->ContainsIndex(modelIndex));
+
+ // Take closing tabs into account.
+ NSInteger index = [self indexFromModelIndex:modelIndex];
+
+ // Make a new tab. Load the contents of this tab from the nib and associate
+ // the new controller with |contents| so it can be looked up later.
+ scoped_nsobject<TabContentsController> contentsController(
+ [[TabContentsController alloc] initWithContents:contents->tab_contents()
+ delegate:self]);
+ [tabContentsArray_ insertObject:contentsController atIndex:index];
+
+ // Make a new tab and add it to the strip. Keep track of its controller.
+ TabController* newController = [self newTab];
+ [newController setMini:tabStripModel_->IsMiniTab(modelIndex)];
+ [newController setPinned:tabStripModel_->IsTabPinned(modelIndex)];
+ [newController setApp:tabStripModel_->IsAppTab(modelIndex)];
+ [tabArray_ insertObject:newController atIndex:index];
+ NSView* newView = [newController view];
+
+ // Set the originating frame to just below the strip so that it animates
+ // upwards as it's being initially layed out. Oddly, this works while doing
+ // something similar in |-layoutTabs| confuses the window server.
+ [newView setFrame:NSOffsetRect([newView frame],
+ 0, -[[self class] defaultTabHeight])];
+
+ [self setTabTitle:newController withContents:contents->tab_contents()];
+
+ // If a tab is being inserted, we can again use the entire tab strip width
+ // for layout.
+ availableResizeWidth_ = kUseFullAvailableWidth;
+
+ // We don't need to call |-layoutTabs| if the tab will be in the foreground
+ // because it will get called when the new tab is selected by the tab model.
+ // Whenever |-layoutTabs| is called, it'll also add the new subview.
+ if (!inForeground) {
+ [self layoutTabs];
+ }
+
+ // During normal loading, we won't yet have a favicon and we'll get
+ // subsequent state change notifications to show the throbber, but when we're
+ // dragging a tab out into a new window, we have to put the tab's favicon
+ // into the right state up front as we won't be told to do it from anywhere
+ // else.
+ [self updateFavIconForContents:contents->tab_contents() atIndex:modelIndex];
+
+ // Send a broadcast that the number of tabs have changed.
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName:kTabStripNumberOfTabsChanged
+ object:self];
+}
+
+// Called when a notification is received from the model to select a particular
+// tab. Swaps in the toolbar and content area associated with |newContents|.
+- (void)selectTabWithContents:(TabContentsWrapper*)newContents
+ previousContents:(TabContentsWrapper*)oldContents
+ atIndex:(NSInteger)modelIndex
+ userGesture:(bool)wasUserGesture {
+ // Take closing tabs into account.
+ NSInteger index = [self indexFromModelIndex:modelIndex];
+
+ if (oldContents) {
+ int oldModelIndex =
+ browser_->GetIndexOfController(&(oldContents->controller()));
+ if (oldModelIndex != -1) { // When closing a tab, the old tab may be gone.
+ NSInteger oldIndex = [self indexFromModelIndex:oldModelIndex];
+ TabContentsController* oldController =
+ [tabContentsArray_ objectAtIndex:oldIndex];
+ [oldController willBecomeUnselectedTab];
+ oldContents->view()->StoreFocus();
+ oldContents->tab_contents()->WasHidden();
+ }
+ }
+
+ // De-select all other tabs and select the new tab.
+ int i = 0;
+ for (TabController* current in tabArray_.get()) {
+ [current setSelected:(i == index) ? YES : NO];
+ ++i;
+ }
+
+ // Tell the new tab contents it is about to become the selected tab. Here it
+ // can do things like make sure the toolbar is up to date.
+ TabContentsController* newController =
+ [tabContentsArray_ objectAtIndex:index];
+ [newController willBecomeSelectedTab];
+
+ // Relayout for new tabs and to let the selected tab grow to be larger in
+ // size than surrounding tabs if the user has many. This also raises the
+ // selected tab to the top.
+ [self layoutTabs];
+
+ // Swap in the contents for the new tab.
+ [self swapInTabAtIndex:modelIndex];
+
+ if (newContents) {
+ newContents->tab_contents()->DidBecomeSelected();
+ newContents->view()->RestoreFocus();
+
+ if (newContents->tab_contents()->find_ui_active())
+ browser_->GetFindBarController()->find_bar()->SetFocusAndSelection();
+ }
+}
+
+- (void)tabReplacedWithContents:(TabContentsWrapper*)newContents
+ previousContents:(TabContentsWrapper*)oldContents
+ atIndex:(NSInteger)modelIndex {
+ NSInteger index = [self indexFromModelIndex:modelIndex];
+ TabContentsController* oldController =
+ [tabContentsArray_ objectAtIndex:index];
+ DCHECK_EQ(oldContents->tab_contents(), [oldController tabContents]);
+
+ // Simply create a new TabContentsController for |newContents| and place it
+ // into the array, replacing |oldContents|. A TabSelectedAt notification will
+ // follow, at which point we will install the new view.
+ scoped_nsobject<TabContentsController> newController(
+ [[TabContentsController alloc]
+ initWithContents:newContents->tab_contents()
+ delegate:self]);
+
+ // Bye bye, |oldController|.
+ [tabContentsArray_ replaceObjectAtIndex:index withObject:newController];
+
+ [delegate_ onReplaceTabWithContents:newContents->tab_contents()];
+
+ // Fake a tab changed notification to force tab titles and favicons to update.
+ [self tabChangedWithContents:newContents
+ atIndex:modelIndex
+ changeType:TabStripModelObserver::ALL];
+}
+
+// Remove all knowledge about this tab and its associated controller, and remove
+// the view from the strip.
+- (void)removeTab:(TabController*)controller {
+ NSUInteger index = [tabArray_ indexOfObject:controller];
+
+ // Release the tab contents controller so those views get destroyed. This
+ // will remove all the tab content Cocoa views from the hierarchy. A
+ // subsequent "select tab" notification will follow from the model. To
+ // tell us what to swap in in its absence.
+ [tabContentsArray_ removeObjectAtIndex:index];
+
+ // Remove the view from the tab strip.
+ NSView* tab = [controller view];
+ [tab removeFromSuperview];
+
+ // Remove ourself as an observer.
+ [[NSNotificationCenter defaultCenter]
+ removeObserver:self
+ name:NSViewDidUpdateTrackingAreasNotification
+ object:tab];
+
+ // Clear the tab controller's target.
+ // TODO(viettrungluu): [crbug.com/23829] Find a better way to handle the tab
+ // controller's target.
+ [controller setTarget:nil];
+
+ if ([hoveredTab_ isEqual:tab])
+ hoveredTab_ = nil;
+
+ NSValue* identifier = [NSValue valueWithPointer:tab];
+ [targetFrames_ removeObjectForKey:identifier];
+
+ // Once we're totally done with the tab, delete its controller
+ [tabArray_ removeObjectAtIndex:index];
+}
+
+// Called by the CAAnimation delegate when the tab completes the closing
+// animation.
+- (void)animationDidStopForController:(TabController*)controller
+ finished:(BOOL)finished {
+ [closingControllers_ removeObject:controller];
+ [self removeTab:controller];
+}
+
+// Save off which TabController is closing and tell its view's animator
+// where to move the tab to. Registers a delegate to call back when the
+// animation is complete in order to remove the tab from the model.
+- (void)startClosingTabWithAnimation:(TabController*)closingTab {
+ DCHECK([NSThread isMainThread]);
+ // Save off the controller into the set of animating tabs. This alerts
+ // the layout method to not do anything with it and allows us to correctly
+ // calculate offsets when working with indices into the model.
+ [closingControllers_ addObject:closingTab];
+
+ // Mark the tab as closing. This prevents it from generating any drags or
+ // selections while it's animating closed.
+ [(TabView*)[closingTab view] setClosing:YES];
+
+ // Register delegate (owned by the animation system).
+ NSView* tabView = [closingTab view];
+ CAAnimation* animation = [[tabView animationForKey:@"frameOrigin"] copy];
+ [animation autorelease];
+ scoped_nsobject<TabCloseAnimationDelegate> delegate(
+ [[TabCloseAnimationDelegate alloc] initWithTabStrip:self
+ tabController:closingTab]);
+ [animation setDelegate:delegate.get()]; // Retains delegate.
+ NSMutableDictionary* animationDictionary =
+ [NSMutableDictionary dictionaryWithDictionary:[tabView animations]];
+ [animationDictionary setObject:animation forKey:@"frameOrigin"];
+ [tabView setAnimations:animationDictionary];
+
+ // Periscope down! Animate the tab.
+ NSRect newFrame = [tabView frame];
+ newFrame = NSOffsetRect(newFrame, 0, -newFrame.size.height);
+ ScopedNSAnimationContextGroup animationGroup(true);
+ animationGroup.SetCurrentContextDuration(kAnimationDuration);
+ [[tabView animator] setFrame:newFrame];
+}
+
+// Called when a notification is received from the model that the given tab
+// has gone away. Start an animation then force a layout to put everything
+// in motion.
+- (void)tabDetachedWithContents:(TabContentsWrapper*)contents
+ atIndex:(NSInteger)modelIndex {
+ // Take closing tabs into account.
+ NSInteger index = [self indexFromModelIndex:modelIndex];
+
+ TabController* tab = [tabArray_ objectAtIndex:index];
+ if (tabStripModel_->count() > 0) {
+ [self startClosingTabWithAnimation:tab];
+ [self layoutTabs];
+ } else {
+ [self removeTab:tab];
+ }
+
+ // Send a broadcast that the number of tabs have changed.
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName:kTabStripNumberOfTabsChanged
+ object:self];
+
+ [delegate_ onTabDetachedWithContents:contents->tab_contents()];
+}
+
+// A helper routine for creating an NSImageView to hold the fav icon or app icon
+// for |contents|.
+- (NSImageView*)iconImageViewForContents:(TabContents*)contents {
+ BOOL isApp = contents->is_app();
+ NSImage* image = nil;
+ if (isApp) {
+ SkBitmap* icon = contents->GetExtensionAppIcon();
+ if (icon)
+ image = gfx::SkBitmapToNSImage(*icon);
+ } else {
+ image = gfx::SkBitmapToNSImage(contents->GetFavIcon());
+ }
+
+ // Either we don't have a valid favicon or there was some issue converting it
+ // from an SkBitmap. Either way, just show the default.
+ if (!image)
+ image = defaultFavIcon_.get();
+ NSRect frame = NSMakeRect(0, 0, kIconWidthAndHeight, kIconWidthAndHeight);
+ NSImageView* view = [[[NSImageView alloc] initWithFrame:frame] autorelease];
+ [view setImage:image];
+ return view;
+}
+
+// Updates the current loading state, replacing the icon view with a favicon,
+// a throbber, the default icon, or nothing at all.
+- (void)updateFavIconForContents:(TabContents*)contents
+ atIndex:(NSInteger)modelIndex {
+ if (!contents)
+ return;
+
+ static NSImage* throbberWaitingImage =
+ [ResourceBundle::GetSharedInstance().GetNativeImageNamed(
+ IDR_THROBBER_WAITING) retain];
+ static NSImage* throbberLoadingImage =
+ [ResourceBundle::GetSharedInstance().GetNativeImageNamed(IDR_THROBBER)
+ retain];
+ static NSImage* sadFaviconImage =
+ [ResourceBundle::GetSharedInstance().GetNativeImageNamed(IDR_SAD_FAVICON)
+ retain];
+
+ // Take closing tabs into account.
+ NSInteger index = [self indexFromModelIndex:modelIndex];
+ TabController* tabController = [tabArray_ objectAtIndex:index];
+
+ bool oldHasIcon = [tabController iconView] != nil;
+ bool newHasIcon = contents->ShouldDisplayFavIcon() ||
+ tabStripModel_->IsMiniTab(modelIndex); // Always show icon if mini.
+
+ TabLoadingState oldState = [tabController loadingState];
+ TabLoadingState newState = kTabDone;
+ NSImage* throbberImage = nil;
+ if (contents->is_crashed()) {
+ newState = kTabCrashed;
+ newHasIcon = true;
+ } else if (contents->waiting_for_response()) {
+ newState = kTabWaiting;
+ throbberImage = throbberWaitingImage;
+ } else if (contents->is_loading()) {
+ newState = kTabLoading;
+ throbberImage = throbberLoadingImage;
+ }
+
+ if (oldState != newState)
+ [tabController setLoadingState:newState];
+
+ // While loading, this function is called repeatedly with the same state.
+ // To avoid expensive unnecessary view manipulation, only make changes when
+ // the state is actually changing. When loading is complete (kTabDone),
+ // every call to this function is significant.
+ if (newState == kTabDone || oldState != newState ||
+ oldHasIcon != newHasIcon) {
+ NSView* iconView = nil;
+ if (newHasIcon) {
+ if (newState == kTabDone) {
+ iconView = [self iconImageViewForContents:contents];
+ } else if (newState == kTabCrashed) {
+ NSImage* oldImage = [[self iconImageViewForContents:contents] image];
+ NSRect frame =
+ NSMakeRect(0, 0, kIconWidthAndHeight, kIconWidthAndHeight);
+ iconView = [ThrobberView toastThrobberViewWithFrame:frame
+ beforeImage:oldImage
+ afterImage:sadFaviconImage];
+ } else {
+ NSRect frame =
+ NSMakeRect(0, 0, kIconWidthAndHeight, kIconWidthAndHeight);
+ iconView = [ThrobberView filmstripThrobberViewWithFrame:frame
+ image:throbberImage];
+ }
+ }
+
+ [tabController setIconView:iconView];
+ }
+}
+
+// Called when a notification is received from the model that the given tab
+// has been updated. |loading| will be YES when we only want to update the
+// throbber state, not anything else about the (partially) loading tab.
+- (void)tabChangedWithContents:(TabContentsWrapper*)contents
+ atIndex:(NSInteger)modelIndex
+ changeType:(TabStripModelObserver::TabChangeType)change {
+ // Take closing tabs into account.
+ NSInteger index = [self indexFromModelIndex:modelIndex];
+
+ if (modelIndex == tabStripModel_->selected_index())
+ [delegate_ onSelectedTabChange:change];
+
+ if (change == TabStripModelObserver::TITLE_NOT_LOADING) {
+ // TODO(sky): make this work.
+ // We'll receive another notification of the change asynchronously.
+ return;
+ }
+
+ TabController* tabController = [tabArray_ objectAtIndex:index];
+
+ if (change != TabStripModelObserver::LOADING_ONLY)
+ [self setTabTitle:tabController withContents:contents->tab_contents()];
+
+ [self updateFavIconForContents:contents->tab_contents() atIndex:modelIndex];
+
+ TabContentsController* updatedController =
+ [tabContentsArray_ objectAtIndex:index];
+ [updatedController tabDidChange:contents->tab_contents()];
+}
+
+// Called when a tab is moved (usually by drag&drop). Keep our parallel arrays
+// in sync with the tab strip model. It can also be pinned/unpinned
+// simultaneously, so we need to take care of that.
+- (void)tabMovedWithContents:(TabContentsWrapper*)contents
+ fromIndex:(NSInteger)modelFrom
+ toIndex:(NSInteger)modelTo {
+ // Take closing tabs into account.
+ NSInteger from = [self indexFromModelIndex:modelFrom];
+ NSInteger to = [self indexFromModelIndex:modelTo];
+
+ scoped_nsobject<TabContentsController> movedTabContentsController(
+ [[tabContentsArray_ objectAtIndex:from] retain]);
+ [tabContentsArray_ removeObjectAtIndex:from];
+ [tabContentsArray_ insertObject:movedTabContentsController.get()
+ atIndex:to];
+ scoped_nsobject<TabController> movedTabController(
+ [[tabArray_ objectAtIndex:from] retain]);
+ DCHECK([movedTabController isKindOfClass:[TabController class]]);
+ [tabArray_ removeObjectAtIndex:from];
+ [tabArray_ insertObject:movedTabController.get() atIndex:to];
+
+ // The tab moved, which means that the mini-tab state may have changed.
+ if (tabStripModel_->IsMiniTab(modelTo) != [movedTabController mini])
+ [self tabMiniStateChangedWithContents:contents atIndex:modelTo];
+
+ [self layoutTabs];
+}
+
+// Called when a tab is pinned or unpinned without moving.
+- (void)tabMiniStateChangedWithContents:(TabContentsWrapper*)contents
+ atIndex:(NSInteger)modelIndex {
+ // Take closing tabs into account.
+ NSInteger index = [self indexFromModelIndex:modelIndex];
+
+ TabController* tabController = [tabArray_ objectAtIndex:index];
+ DCHECK([tabController isKindOfClass:[TabController class]]);
+
+ // Don't do anything if the change was already picked up by the move event.
+ if (tabStripModel_->IsMiniTab(modelIndex) == [tabController mini])
+ return;
+
+ [tabController setMini:tabStripModel_->IsMiniTab(modelIndex)];
+ [tabController setPinned:tabStripModel_->IsTabPinned(modelIndex)];
+ [tabController setApp:tabStripModel_->IsAppTab(modelIndex)];
+ [self updateFavIconForContents:contents->tab_contents() atIndex:modelIndex];
+ // If the tab is being restored and it's pinned, the mini state is set after
+ // the tab has already been rendered, so re-layout the tabstrip. In all other
+ // cases, the state is set before the tab is rendered so this isn't needed.
+ [self layoutTabs];
+}
+
+- (void)setFrameOfSelectedTab:(NSRect)frame {
+ NSView* view = [self selectedTabView];
+ NSValue* identifier = [NSValue valueWithPointer:view];
+ [targetFrames_ setObject:[NSValue valueWithRect:frame]
+ forKey:identifier];
+ [view setFrame:frame];
+}
+
+- (NSView*)selectedTabView {
+ int selectedIndex = tabStripModel_->selected_index();
+ // Take closing tabs into account. They can't ever be selected.
+ selectedIndex = [self indexFromModelIndex:selectedIndex];
+ return [self viewAtIndex:selectedIndex];
+}
+
+// Find the model index based on the x coordinate of the placeholder. If there
+// is no placeholder, this returns the end of the tab strip. Closing tabs are
+// not considered in computing the index.
+- (int)indexOfPlaceholder {
+ double placeholderX = placeholderFrame_.origin.x;
+ int index = 0;
+ int location = 0;
+ // Use |tabArray_| here instead of the tab strip count in order to get the
+ // correct index when there are closing tabs to the left of the placeholder.
+ const int count = [tabArray_ count];
+ while (index < count) {
+ // Ignore closing tabs for simplicity. The only drawback of this is that
+ // if the placeholder is placed right before one or several contiguous
+ // currently closing tabs, the associated TabController will start at the
+ // end of the closing tabs.
+ if ([closingControllers_ containsObject:[tabArray_ objectAtIndex:index]]) {
+ index++;
+ continue;
+ }
+ NSView* curr = [self viewAtIndex:index];
+ // The placeholder tab works by changing the frame of the tab being dragged
+ // to be the bounds of the placeholder, so we need to skip it while we're
+ // iterating, otherwise we'll end up off by one. Note This only effects
+ // dragging to the right, not to the left.
+ if (curr == placeholderTab_) {
+ index++;
+ continue;
+ }
+ if (placeholderX <= NSMinX([curr frame]))
+ break;
+ index++;
+ location++;
+ }
+ return location;
+}
+
+// Move the given tab at index |from| in this window to the location of the
+// current placeholder.
+- (void)moveTabFromIndex:(NSInteger)from {
+ int toIndex = [self indexOfPlaceholder];
+ tabStripModel_->MoveTabContentsAt(from, toIndex, true);
+}
+
+// Drop a given TabContents at the location of the current placeholder. If there
+// is no placeholder, it will go at the end. Used when dragging from another
+// window when we don't have access to the TabContents as part of our strip.
+// |frame| is in the coordinate system of the tab strip view and represents
+// where the user dropped the new tab so it can be animated into its correct
+// location when the tab is added to the model. If the tab was pinned in its
+// previous window, setting |pinned| to YES will propagate that state to the
+// new window. Mini-tabs are either app or pinned tabs; the app state is stored
+// by the |contents|, but the |pinned| state is the caller's responsibility.
+- (void)dropTabContents:(TabContentsWrapper*)contents
+ withFrame:(NSRect)frame
+ asPinnedTab:(BOOL)pinned {
+ int modelIndex = [self indexOfPlaceholder];
+
+ // Mark that the new tab being created should start at |frame|. It will be
+ // reset as soon as the tab has been positioned.
+ droppedTabFrame_ = frame;
+
+ // Insert it into this tab strip. We want it in the foreground and to not
+ // inherit the current tab's group.
+ tabStripModel_->InsertTabContentsAt(
+ modelIndex, contents,
+ TabStripModel::ADD_SELECTED | (pinned ? TabStripModel::ADD_PINNED : 0));
+}
+
+// Called when the tab strip view changes size. As we only registered for
+// changes on our view, we know it's only for our view. Layout w/out
+// animations since they are blocked by the resize nested runloop. We need
+// the views to adjust immediately. Neither the tabs nor their z-order are
+// changed, so we don't need to update the subviews.
+- (void)tabViewFrameChanged:(NSNotification*)info {
+ [self layoutTabsWithAnimation:NO regenerateSubviews:NO];
+}
+
+// Called when the tracking areas for any given tab are updated. This allows
+// the individual tabs to update their hover states correctly.
+// Only generates the event if the cursor is in the tab strip.
+- (void)tabUpdateTracking:(NSNotification*)notification {
+ DCHECK([[notification object] isKindOfClass:[TabView class]]);
+ DCHECK(mouseInside_);
+ NSWindow* window = [tabStripView_ window];
+ NSPoint location = [window mouseLocationOutsideOfEventStream];
+ if (NSPointInRect(location, [tabStripView_ frame])) {
+ NSEvent* mouseEvent = [NSEvent mouseEventWithType:NSMouseMoved
+ location:location
+ modifierFlags:0
+ timestamp:0
+ windowNumber:[window windowNumber]
+ context:nil
+ eventNumber:0
+ clickCount:0
+ pressure:0];
+ [self mouseMoved:mouseEvent];
+ }
+}
+
+- (BOOL)inRapidClosureMode {
+ return availableResizeWidth_ != kUseFullAvailableWidth;
+}
+
+// Disable tab dragging when there are any pending animations.
+- (BOOL)tabDraggingAllowed {
+ return [closingControllers_ count] == 0;
+}
+
+- (void)mouseMoved:(NSEvent*)event {
+ // Use hit test to figure out what view we are hovering over.
+ NSView* targetView = [tabStripView_ hitTest:[event locationInWindow]];
+
+ // Set the new tab button hover state iff the mouse is over the button.
+ BOOL shouldShowHoverImage = [targetView isKindOfClass:[NewTabButton class]];
+ [self setNewTabButtonHoverState:shouldShowHoverImage];
+
+ TabView* tabView = (TabView*)targetView;
+ if (![tabView isKindOfClass:[TabView class]]) {
+ if ([[tabView superview] isKindOfClass:[TabView class]]) {
+ tabView = (TabView*)[targetView superview];
+ } else {
+ tabView = nil;
+ }
+ }
+
+ if (hoveredTab_ != tabView) {
+ [hoveredTab_ mouseExited:nil]; // We don't pass event because moved events
+ [tabView mouseEntered:nil]; // don't have valid tracking areas
+ hoveredTab_ = tabView;
+ } else {
+ [hoveredTab_ mouseMoved:event];
+ }
+}
+
+- (void)mouseEntered:(NSEvent*)event {
+ NSTrackingArea* area = [event trackingArea];
+ if ([area isEqual:trackingArea_]) {
+ mouseInside_ = YES;
+ [self setTabTrackingAreasEnabled:YES];
+ [self mouseMoved:event];
+ }
+}
+
+// Called when the tracking area is in effect which means we're tracking to
+// see if the user leaves the tab strip with their mouse. When they do,
+// reset layout to use all available width.
+- (void)mouseExited:(NSEvent*)event {
+ NSTrackingArea* area = [event trackingArea];
+ if ([area isEqual:trackingArea_]) {
+ mouseInside_ = NO;
+ [self setTabTrackingAreasEnabled:NO];
+ availableResizeWidth_ = kUseFullAvailableWidth;
+ [hoveredTab_ mouseExited:event];
+ hoveredTab_ = nil;
+ [self layoutTabs];
+ } else if ([area isEqual:newTabTrackingArea_]) {
+ // If the mouse is moved quickly enough, it is possible for the mouse to
+ // leave the tabstrip without sending any mouseMoved: messages at all.
+ // Since this would result in the new tab button incorrectly staying in the
+ // hover state, disable the hover image on every mouse exit.
+ [self setNewTabButtonHoverState:NO];
+ }
+}
+
+// Enable/Disable the tracking areas for the tabs. They are only enabled
+// when the mouse is in the tabstrip.
+- (void)setTabTrackingAreasEnabled:(BOOL)enabled {
+ NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
+ for (TabController* controller in tabArray_.get()) {
+ TabView* tabView = [controller tabView];
+ if (enabled) {
+ // Set self up to observe tabs so hover states will be correct.
+ [defaultCenter addObserver:self
+ selector:@selector(tabUpdateTracking:)
+ name:NSViewDidUpdateTrackingAreasNotification
+ object:tabView];
+ } else {
+ [defaultCenter removeObserver:self
+ name:NSViewDidUpdateTrackingAreasNotification
+ object:tabView];
+ }
+ [tabView setTrackingEnabled:enabled];
+ }
+}
+
+// Sets the new tab button's image based on the current hover state. Does
+// nothing if the hover state is already correct.
+- (void)setNewTabButtonHoverState:(BOOL)shouldShowHover {
+ if (shouldShowHover && !newTabButtonShowingHoverImage_) {
+ newTabButtonShowingHoverImage_ = YES;
+ [newTabButton_ setImage:
+ app::mac::GetCachedImageWithName(kNewTabHoverImage)];
+ } else if (!shouldShowHover && newTabButtonShowingHoverImage_) {
+ newTabButtonShowingHoverImage_ = NO;
+ [newTabButton_ setImage:app::mac::GetCachedImageWithName(kNewTabImage)];
+ }
+}
+
+// Adds the given subview to (the end of) the list of permanent subviews
+// (specified from bottom up). These subviews will always be below the
+// transitory subviews (tabs). |-regenerateSubviewList| must be called to
+// effectuate the addition.
+- (void)addSubviewToPermanentList:(NSView*)aView {
+ if (aView)
+ [permanentSubviews_ addObject:aView];
+}
+
+// Update the subviews, keeping the permanent ones (or, more correctly, putting
+// in the ones listed in permanentSubviews_), and putting in the current tabs in
+// the correct z-order. Any current subviews which is neither in the permanent
+// list nor a (current) tab will be removed. So if you add such a subview, you
+// should call |-addSubviewToPermanentList:| (or better yet, call that and then
+// |-regenerateSubviewList| to actually add it).
+- (void)regenerateSubviewList {
+ // Remove self as an observer from all the old tabs before a new set of
+ // potentially different tabs is put in place.
+ [self setTabTrackingAreasEnabled:NO];
+
+ // Subviews to put in (in bottom-to-top order), beginning with the permanent
+ // ones.
+ NSMutableArray* subviews = [NSMutableArray arrayWithArray:permanentSubviews_];
+
+ NSView* selectedTabView = nil;
+ // Go through tabs in reverse order, since |subviews| is bottom-to-top.
+ for (TabController* tab in [tabArray_ reverseObjectEnumerator]) {
+ NSView* tabView = [tab view];
+ if ([tab selected]) {
+ DCHECK(!selectedTabView);
+ selectedTabView = tabView;
+ } else {
+ [subviews addObject:tabView];
+ }
+ }
+ if (selectedTabView) {
+ [subviews addObject:selectedTabView];
+ }
+ [tabStripView_ setSubviews:subviews];
+ [self setTabTrackingAreasEnabled:mouseInside_];
+}
+
+// Get the index and disposition for a potential URL(s) drop given a point (in
+// the |TabStripView|'s coordinates). It considers only the x-coordinate of the
+// given point. If it's in the "middle" of a tab, it drops on that tab. If it's
+// to the left, it inserts to the left, and similarly for the right.
+- (void)droppingURLsAt:(NSPoint)point
+ givesIndex:(NSInteger*)index
+ disposition:(WindowOpenDisposition*)disposition {
+ // Proportion of the tab which is considered the "middle" (and causes things
+ // to drop on that tab).
+ const double kMiddleProportion = 0.5;
+ const double kLRProportion = (1.0 - kMiddleProportion) / 2.0;
+
+ DCHECK(index && disposition);
+ NSInteger i = 0;
+ for (TabController* tab in tabArray_.get()) {
+ NSView* view = [tab view];
+ DCHECK([view isKindOfClass:[TabView class]]);
+
+ // Recall that |-[NSView frame]| is in its superview's coordinates, so a
+ // |TabView|'s frame is in the coordinates of the |TabStripView| (which
+ // matches the coordinate system of |point|).
+ NSRect frame = [view frame];
+
+ // Modify the frame to make it "unoverlapped".
+ frame.origin.x += kTabOverlap / 2.0;
+ frame.size.width -= kTabOverlap;
+ if (frame.size.width < 1.0)
+ frame.size.width = 1.0; // try to avoid complete failure
+
+ // Drop in a new tab to the left of tab |i|?
+ if (point.x < (frame.origin.x + kLRProportion * frame.size.width)) {
+ *index = i;
+ *disposition = NEW_FOREGROUND_TAB;
+ return;
+ }
+
+ // Drop on tab |i|?
+ if (point.x <= (frame.origin.x +
+ (1.0 - kLRProportion) * frame.size.width)) {
+ *index = i;
+ *disposition = CURRENT_TAB;
+ return;
+ }
+
+ // (Dropping in a new tab to the right of tab |i| will be taken care of in
+ // the next iteration.)
+ i++;
+ }
+
+ // If we've made it here, we want to append a new tab to the end.
+ *index = -1;
+ *disposition = NEW_FOREGROUND_TAB;
+}
+
+- (void)openURL:(GURL*)url inView:(NSView*)view at:(NSPoint)point {
+ // Get the index and disposition.
+ NSInteger index;
+ WindowOpenDisposition disposition;
+ [self droppingURLsAt:point
+ givesIndex:&index
+ disposition:&disposition];
+
+ // Either insert a new tab or open in a current tab.
+ switch (disposition) {
+ case NEW_FOREGROUND_TAB: {
+ UserMetrics::RecordAction(UserMetricsAction("Tab_DropURLBetweenTabs"),
+ browser_->profile());
+ browser::NavigateParams params(browser_, *url, PageTransition::TYPED);
+ params.disposition = disposition;
+ params.tabstrip_index = index;
+ params.tabstrip_add_types =
+ TabStripModel::ADD_SELECTED | TabStripModel::ADD_FORCE_INDEX;
+ browser::Navigate(&params);
+ break;
+ }
+ case CURRENT_TAB:
+ UserMetrics::RecordAction(UserMetricsAction("Tab_DropURLOnTab"),
+ browser_->profile());
+ tabStripModel_->GetTabContentsAt(index)
+ ->tab_contents()->OpenURL(*url, GURL(), CURRENT_TAB,
+ PageTransition::TYPED);
+ tabStripModel_->SelectTabContentsAt(index, true);
+ break;
+ default:
+ NOTIMPLEMENTED();
+ }
+}
+
+// (URLDropTargetController protocol)
+- (void)dropURLs:(NSArray*)urls inView:(NSView*)view at:(NSPoint)point {
+ DCHECK_EQ(view, tabStripView_.get());
+
+ if ([urls count] < 1) {
+ NOTREACHED();
+ return;
+ }
+
+ //TODO(viettrungluu): dropping multiple URLs.
+ if ([urls count] > 1)
+ NOTIMPLEMENTED();
+
+ // Get the first URL and fix it up.
+ GURL url(GURL(URLFixerUpper::FixupURL(
+ base::SysNSStringToUTF8([urls objectAtIndex:0]), std::string())));
+
+ [self openURL:&url inView:view at:point];
+}
+
+// (URLDropTargetController protocol)
+- (void)dropText:(NSString*)text inView:(NSView*)view at:(NSPoint)point {
+ DCHECK_EQ(view, tabStripView_.get());
+
+ // If the input is plain text, classify the input and make the URL.
+ AutocompleteMatch match;
+ browser_->profile()->GetAutocompleteClassifier()->Classify(
+ base::SysNSStringToWide(text),
+ std::wstring(), false, &match, NULL);
+ GURL url(match.destination_url);
+
+ [self openURL:&url inView:view at:point];
+}
+
+// (URLDropTargetController protocol)
+- (void)indicateDropURLsInView:(NSView*)view at:(NSPoint)point {
+ DCHECK_EQ(view, tabStripView_.get());
+
+ // The minimum y-coordinate at which one should consider place the arrow.
+ const CGFloat arrowBaseY = 25;
+
+ NSInteger index;
+ WindowOpenDisposition disposition;
+ [self droppingURLsAt:point
+ givesIndex:&index
+ disposition:&disposition];
+
+ NSPoint arrowPos = NSMakePoint(0, arrowBaseY);
+ if (index == -1) {
+ // Append a tab at the end.
+ DCHECK(disposition == NEW_FOREGROUND_TAB);
+ NSInteger lastIndex = [tabArray_ count] - 1;
+ NSRect overRect = [[[tabArray_ objectAtIndex:lastIndex] view] frame];
+ arrowPos.x = overRect.origin.x + overRect.size.width - kTabOverlap / 2.0;
+ } else {
+ NSRect overRect = [[[tabArray_ objectAtIndex:index] view] frame];
+ switch (disposition) {
+ case NEW_FOREGROUND_TAB:
+ // Insert tab (to the left of the given tab).
+ arrowPos.x = overRect.origin.x + kTabOverlap / 2.0;
+ break;
+ case CURRENT_TAB:
+ // Overwrite the given tab.
+ arrowPos.x = overRect.origin.x + overRect.size.width / 2.0;
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+
+ [tabStripView_ setDropArrowPosition:arrowPos];
+ [tabStripView_ setDropArrowShown:YES];
+ [tabStripView_ setNeedsDisplay:YES];
+}
+
+// (URLDropTargetController protocol)
+- (void)hideDropURLsIndicatorInView:(NSView*)view {
+ DCHECK_EQ(view, tabStripView_.get());
+
+ if ([tabStripView_ dropArrowShown]) {
+ [tabStripView_ setDropArrowShown:NO];
+ [tabStripView_ setNeedsDisplay:YES];
+ }
+}
+
+- (GTMWindowSheetController*)sheetController {
+ if (!sheetController_.get())
+ sheetController_.reset([[GTMWindowSheetController alloc]
+ initWithWindow:[switchView_ window] delegate:self]);
+ return sheetController_.get();
+}
+
+- (void)destroySheetController {
+ // Make sure there are no open sheets.
+ DCHECK_EQ(0U, [[sheetController_ viewsWithAttachedSheets] count]);
+ sheetController_.reset();
+}
+
+// TabContentsControllerDelegate protocol.
+- (void)tabContentsViewFrameWillChange:(TabContentsController*)source
+ frameRect:(NSRect)frameRect {
+ id<TabContentsControllerDelegate> controller =
+ [[switchView_ window] windowController];
+ [controller tabContentsViewFrameWillChange:source frameRect:frameRect];
+}
+
+- (TabContentsController*)activeTabContentsController {
+ int modelIndex = tabStripModel_->selected_index();
+ if (modelIndex < 0)
+ return nil;
+ NSInteger index = [self indexFromModelIndex:modelIndex];
+ if (index < 0 ||
+ index >= (NSInteger)[tabContentsArray_ count])
+ return nil;
+ return [tabContentsArray_ objectAtIndex:index];
+}
+
+- (void)gtm_systemRequestsVisibilityForView:(NSView*)view {
+ // This implementation is required by GTMWindowSheetController.
+
+ // Raise window...
+ [[switchView_ window] makeKeyAndOrderFront:self];
+
+ // ...and raise a tab with a sheet.
+ NSInteger index = [self modelIndexForContentsView:view];
+ DCHECK(index >= 0);
+ if (index >= 0)
+ tabStripModel_->SelectTabContentsAt(index, false /* not a user gesture */);
+}
+
+- (void)attachConstrainedWindow:(ConstrainedWindowMac*)window {
+ // TODO(thakis, avi): Figure out how to make this work when tabs are dragged
+ // out or if fullscreen mode is toggled.
+
+ // View hierarchy of the contents view:
+ // NSView -- switchView, same for all tabs
+ // +- NSView -- TabContentsController's view
+ // +- TabContentsViewCocoa
+ // Changing it? Do not forget to modify removeConstrainedWindow too.
+ // We use the TabContentsController's view in |swapInTabAtIndex|, so we have
+ // to pass it to the sheet controller here.
+ NSView* tabContentsView = [window->owner()->GetNativeView() superview];
+ window->delegate()->RunSheet([self sheetController], tabContentsView);
+
+ // TODO(avi, thakis): GTMWindowSheetController has no api to move tabsheets
+ // between windows. Until then, we have to prevent having to move a tabsheet
+ // between windows, e.g. no tearing off of tabs.
+ NSInteger modelIndex = [self modelIndexForContentsView:tabContentsView];
+ NSInteger index = [self indexFromModelIndex:modelIndex];
+ BrowserWindowController* controller =
+ (BrowserWindowController*)[[switchView_ window] windowController];
+ DCHECK(controller != nil);
+ DCHECK(index >= 0);
+ if (index >= 0) {
+ [controller setTab:[self viewAtIndex:index] isDraggable:NO];
+ }
+}
+
+- (void)removeConstrainedWindow:(ConstrainedWindowMac*)window {
+ NSView* tabContentsView = [window->owner()->GetNativeView() superview];
+
+ // TODO(avi, thakis): GTMWindowSheetController has no api to move tabsheets
+ // between windows. Until then, we have to prevent having to move a tabsheet
+ // between windows, e.g. no tearing off of tabs.
+ NSInteger modelIndex = [self modelIndexForContentsView:tabContentsView];
+ NSInteger index = [self indexFromModelIndex:modelIndex];
+ BrowserWindowController* controller =
+ (BrowserWindowController*)[[switchView_ window] windowController];
+ DCHECK(index >= 0);
+ if (index >= 0) {
+ [controller setTab:[self viewAtIndex:index] isDraggable:YES];
+ }
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/tab_strip_controller_unittest.mm b/chrome/browser/ui/cocoa/tab_strip_controller_unittest.mm
new file mode 100644
index 0000000..189e57b
--- /dev/null
+++ b/chrome/browser/ui/cocoa/tab_strip_controller_unittest.mm
@@ -0,0 +1,177 @@
+// 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>
+
+#import "chrome/browser/browser_window.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/renderer_host/site_instance.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/new_tab_button.h"
+#import "chrome/browser/ui/cocoa/tab_strip_controller.h"
+#import "chrome/browser/ui/cocoa/tab_strip_view.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+@interface TestTabStripControllerDelegate :
+ NSObject<TabStripControllerDelegate> {
+}
+@end
+
+@implementation TestTabStripControllerDelegate
+- (void)onSelectTabWithContents:(TabContents*)contents {
+}
+- (void)onReplaceTabWithContents:(TabContents*)contents {
+}
+- (void)onSelectedTabChange:(TabStripModelObserver::TabChangeType)change {
+}
+- (void)onTabDetachedWithContents:(TabContents*)contents {
+}
+@end
+
+namespace {
+
+// Stub model delegate
+class TestTabStripDelegate : public TabStripModelDelegate {
+ public:
+ virtual TabContentsWrapper* AddBlankTab(bool foreground) {
+ return NULL;
+ }
+ virtual TabContentsWrapper* AddBlankTabAt(int index, bool foreground) {
+ return NULL;
+ }
+ virtual Browser* CreateNewStripWithContents(TabContentsWrapper* contents,
+ const gfx::Rect& window_bounds,
+ const DockInfo& dock_info,
+ bool maximize) {
+ return NULL;
+ }
+ virtual void ContinueDraggingDetachedTab(TabContentsWrapper* contents,
+ const gfx::Rect& window_bounds,
+ const gfx::Rect& tab_bounds) {
+ }
+ virtual int GetDragActions() const {
+ return 0;
+ }
+ virtual TabContentsWrapper* CreateTabContentsForURL(
+ const GURL& url,
+ const GURL& referrer,
+ Profile* profile,
+ PageTransition::Type transition,
+ bool defer_load,
+ SiteInstance* instance) const {
+ return NULL;
+ }
+ virtual bool CanDuplicateContentsAt(int index) { return true; }
+ virtual void DuplicateContentsAt(int index) { }
+ virtual void CloseFrameAfterDragSession() { }
+ virtual void CreateHistoricalTab(TabContentsWrapper* contents) { }
+ virtual bool RunUnloadListenerBeforeClosing(TabContentsWrapper* contents) {
+ return true;
+ }
+ virtual bool CanRestoreTab() {
+ return true;
+ }
+ virtual void RestoreTab() {}
+
+ virtual bool CanCloseContentsAt(int index) { return true; }
+
+ virtual bool CanBookmarkAllTabs() const { return false; }
+
+ virtual bool CanCloseTab() const { return true; }
+
+ virtual void BookmarkAllTabs() {}
+
+ virtual bool UseVerticalTabs() const { return false; }
+
+ virtual void ToggleUseVerticalTabs() {}
+
+ virtual bool LargeIconsPermitted() const { return true; }
+};
+
+class TabStripControllerTest : public CocoaTest {
+ public:
+ TabStripControllerTest() {
+ Browser* browser = browser_helper_.browser();
+ BrowserWindow* browser_window = browser_helper_.CreateBrowserWindow();
+ NSWindow* window = browser_window->GetNativeHandle();
+ NSView* parent = [window contentView];
+ NSRect content_frame = [parent frame];
+
+ // Create the "switch view" (view that gets changed out when a tab
+ // switches).
+ NSRect switch_frame = NSMakeRect(0, 0, content_frame.size.width, 500);
+ scoped_nsobject<NSView> switch_view(
+ [[NSView alloc] initWithFrame:switch_frame]);
+ [parent addSubview:switch_view.get()];
+
+ // Create the tab strip view. It's expected to have a child button in it
+ // already as the "new tab" button so create that too.
+ NSRect strip_frame = NSMakeRect(0, NSMaxY(switch_frame),
+ content_frame.size.width, 30);
+ scoped_nsobject<TabStripView> tab_strip(
+ [[TabStripView alloc] initWithFrame:strip_frame]);
+ [parent addSubview:tab_strip.get()];
+ NSRect button_frame = NSMakeRect(0, 0, 15, 15);
+ scoped_nsobject<NewTabButton> new_tab_button(
+ [[NewTabButton alloc] initWithFrame:button_frame]);
+ [tab_strip addSubview:new_tab_button.get()];
+ [tab_strip setNewTabButton:new_tab_button.get()];
+
+ delegate_.reset(new TestTabStripDelegate());
+ model_ = browser->tabstrip_model();
+ controller_delegate_.reset([TestTabStripControllerDelegate alloc]);
+ controller_.reset([[TabStripController alloc]
+ initWithView:static_cast<TabStripView*>(tab_strip.get())
+ switchView:switch_view.get()
+ browser:browser
+ delegate:controller_delegate_.get()]);
+ }
+
+ virtual void TearDown() {
+ browser_helper_.CloseBrowserWindow();
+ // The call to CocoaTest::TearDown() deletes the Browser and TabStripModel
+ // objects, so we first have to delete the controller, which refers to them.
+ controller_.reset(nil);
+ model_ = NULL;
+ CocoaTest::TearDown();
+ }
+
+ BrowserTestHelper browser_helper_;
+ scoped_ptr<TestTabStripDelegate> delegate_;
+ TabStripModel* model_;
+ scoped_nsobject<TestTabStripControllerDelegate> controller_delegate_;
+ scoped_nsobject<TabStripController> controller_;
+};
+
+// Test adding and removing tabs and making sure that views get added to
+// the tab strip.
+TEST_F(TabStripControllerTest, AddRemoveTabs) {
+ EXPECT_TRUE(model_->empty());
+ SiteInstance* instance =
+ SiteInstance::CreateSiteInstance(browser_helper_.profile());
+ TabContentsWrapper* tab_contents =
+ Browser::TabContentsFactory(browser_helper_.profile(), instance,
+ MSG_ROUTING_NONE, NULL, NULL);
+ model_->AppendTabContents(tab_contents, true);
+ EXPECT_EQ(model_->count(), 1);
+}
+
+TEST_F(TabStripControllerTest, SelectTab) {
+ // TODO(pinkerton): Implement http://crbug.com/10899
+}
+
+TEST_F(TabStripControllerTest, RearrangeTabs) {
+ // TODO(pinkerton): Implement http://crbug.com/10899
+}
+
+// Test that changing the number of tabs broadcasts a
+// kTabStripNumberOfTabsChanged notifiction.
+TEST_F(TabStripControllerTest, Notifications) {
+ // TODO(pinkerton): Implement http://crbug.com/10899
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/tab_strip_model_observer_bridge.h b/chrome/browser/ui/cocoa/tab_strip_model_observer_bridge.h
new file mode 100644
index 0000000..534fcfb
--- /dev/null
+++ b/chrome/browser/ui/cocoa/tab_strip_model_observer_bridge.h
@@ -0,0 +1,85 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_TAB_STRIP_MODEL_OBSERVER_BRIDGE_H_
+#define CHROME_BROWSER_UI_COCOA_TAB_STRIP_MODEL_OBSERVER_BRIDGE_H_
+#pragma once
+
+#import <Foundation/Foundation.h>
+
+#include "chrome/browser/tabs/tab_strip_model_observer.h"
+
+class TabContentsWrapper;
+class TabStripModel;
+
+// A C++ bridge class to handle receiving notifications from the C++ tab strip
+// model. When the caller allocates a bridge, it automatically registers for
+// notifications from |model| and passes messages to |controller| via the
+// informal protocol below. The owner of this object is responsible for deleting
+// it (and thus unhooking notifications) before |controller| is destroyed.
+class TabStripModelObserverBridge : public TabStripModelObserver {
+ public:
+ TabStripModelObserverBridge(TabStripModel* model, id controller);
+ virtual ~TabStripModelObserverBridge();
+
+ // Overridden from TabStripModelObserver
+ virtual void TabInsertedAt(TabContentsWrapper* contents,
+ int index,
+ bool foreground);
+ virtual void TabClosingAt(TabStripModel* tab_strip_model,
+ TabContentsWrapper* contents,
+ int index);
+ virtual void TabDetachedAt(TabContentsWrapper* contents, int index);
+ virtual void TabSelectedAt(TabContentsWrapper* old_contents,
+ TabContentsWrapper* new_contents,
+ int index,
+ bool user_gesture);
+ virtual void TabMoved(TabContentsWrapper* contents,
+ int from_index,
+ int to_index);
+ virtual void TabChangedAt(TabContentsWrapper* contents, int index,
+ TabChangeType change_type);
+ virtual void TabReplacedAt(TabContentsWrapper* old_contents,
+ TabContentsWrapper* new_contents,
+ int index);
+ virtual void TabMiniStateChanged(TabContentsWrapper* contents, int index);
+ virtual void TabStripEmpty();
+ virtual void TabStripModelDeleted();
+
+ private:
+ id controller_; // weak, owns me
+ TabStripModel* model_; // weak, owned by Browser
+};
+
+// A collection of methods which can be selectively implemented by any
+// Cocoa object to receive updates about changes to a tab strip model. It is
+// ok to not implement them, the calling code checks before calling.
+@interface NSObject(TabStripModelBridge)
+- (void)insertTabWithContents:(TabContentsWrapper*)contents
+ atIndex:(NSInteger)index
+ inForeground:(bool)inForeground;
+- (void)tabClosingWithContents:(TabContentsWrapper*)contents
+ atIndex:(NSInteger)index;
+- (void)tabDetachedWithContents:(TabContentsWrapper*)contents
+ atIndex:(NSInteger)index;
+- (void)selectTabWithContents:(TabContentsWrapper*)newContents
+ previousContents:(TabContentsWrapper*)oldContents
+ atIndex:(NSInteger)index
+ userGesture:(bool)wasUserGesture;
+- (void)tabMovedWithContents:(TabContentsWrapper*)contents
+ fromIndex:(NSInteger)from
+ toIndex:(NSInteger)to;
+- (void)tabChangedWithContents:(TabContentsWrapper*)contents
+ atIndex:(NSInteger)index
+ changeType:(TabStripModelObserver::TabChangeType)change;
+- (void)tabReplacedWithContents:(TabContentsWrapper*)newContents
+ previousContents:(TabContentsWrapper*)oldContents
+ atIndex:(NSInteger)index;
+- (void)tabMiniStateChangedWithContents:(TabContentsWrapper*)contents
+ atIndex:(NSInteger)index;
+- (void)tabStripEmpty;
+- (void)tabStripModelDeleted;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_TAB_STRIP_MODEL_OBSERVER_BRIDGE_H_
diff --git a/chrome/browser/ui/cocoa/tab_strip_model_observer_bridge.mm b/chrome/browser/ui/cocoa/tab_strip_model_observer_bridge.mm
new file mode 100644
index 0000000..a998d23
--- /dev/null
+++ b/chrome/browser/ui/cocoa/tab_strip_model_observer_bridge.mm
@@ -0,0 +1,118 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/tab_strip_model_observer_bridge.h"
+
+#include "chrome/browser/tabs/tab_strip_model.h"
+
+TabStripModelObserverBridge::TabStripModelObserverBridge(TabStripModel* model,
+ id controller)
+ : controller_(controller), model_(model) {
+ DCHECK(model && controller);
+ // Register to be a listener on the model so we can get updates and tell
+ // |controller_| about them in the future.
+ model_->AddObserver(this);
+}
+
+TabStripModelObserverBridge::~TabStripModelObserverBridge() {
+ // Remove ourselves from receiving notifications.
+ model_->RemoveObserver(this);
+}
+
+void TabStripModelObserverBridge::TabInsertedAt(TabContentsWrapper* contents,
+ int index,
+ bool foreground) {
+ if ([controller_ respondsToSelector:
+ @selector(insertTabWithContents:atIndex:inForeground:)]) {
+ [controller_ insertTabWithContents:contents
+ atIndex:index
+ inForeground:foreground];
+ }
+}
+
+void TabStripModelObserverBridge::TabClosingAt(TabStripModel* tab_strip_model,
+ TabContentsWrapper* contents,
+ int index) {
+ if ([controller_ respondsToSelector:
+ @selector(tabClosingWithContents:atIndex:)]) {
+ [controller_ tabClosingWithContents:contents atIndex:index];
+ }
+}
+
+void TabStripModelObserverBridge::TabDetachedAt(TabContentsWrapper* contents,
+ int index) {
+ if ([controller_ respondsToSelector:
+ @selector(tabDetachedWithContents:atIndex:)]) {
+ [controller_ tabDetachedWithContents:contents atIndex:index];
+ }
+}
+
+void TabStripModelObserverBridge::TabSelectedAt(
+ TabContentsWrapper* old_contents,
+ TabContentsWrapper* new_contents,
+ int index,
+ bool user_gesture) {
+ if ([controller_ respondsToSelector:
+ @selector(selectTabWithContents:previousContents:atIndex:
+ userGesture:)]) {
+ [controller_ selectTabWithContents:new_contents
+ previousContents:old_contents
+ atIndex:index
+ userGesture:user_gesture];
+ }
+}
+
+void TabStripModelObserverBridge::TabMoved(TabContentsWrapper* contents,
+ int from_index,
+ int to_index) {
+ if ([controller_ respondsToSelector:
+ @selector(tabMovedWithContents:fromIndex:toIndex:)]) {
+ [controller_ tabMovedWithContents:contents
+ fromIndex:from_index
+ toIndex:to_index];
+ }
+}
+
+void TabStripModelObserverBridge::TabChangedAt(TabContentsWrapper* contents,
+ int index,
+ TabChangeType change_type) {
+ if ([controller_ respondsToSelector:
+ @selector(tabChangedWithContents:atIndex:changeType:)]) {
+ [controller_ tabChangedWithContents:contents
+ atIndex:index
+ changeType:change_type];
+ }
+}
+
+void TabStripModelObserverBridge::TabReplacedAt(
+ TabContentsWrapper* old_contents,
+ TabContentsWrapper* new_contents,
+ int index) {
+ if ([controller_ respondsToSelector:
+ @selector(tabReplacedWithContents:previousContents:atIndex:)]) {
+ [controller_ tabReplacedWithContents:new_contents
+ previousContents:old_contents
+ atIndex:index];
+ } else {
+ TabChangedAt(new_contents, index, ALL);
+ }
+}
+
+void TabStripModelObserverBridge::TabMiniStateChanged(
+ TabContentsWrapper* contents, int index) {
+ if ([controller_ respondsToSelector:
+ @selector(tabMiniStateChangedWithContents:atIndex:)]) {
+ [controller_ tabMiniStateChangedWithContents:contents atIndex:index];
+ }
+}
+
+void TabStripModelObserverBridge::TabStripEmpty() {
+ if ([controller_ respondsToSelector:@selector(tabStripEmpty)])
+ [controller_ tabStripEmpty];
+}
+
+void TabStripModelObserverBridge::TabStripModelDeleted() {
+ if ([controller_ respondsToSelector:@selector(tabStripModelDeleted)])
+ [controller_ tabStripModelDeleted];
+}
diff --git a/chrome/browser/ui/cocoa/tab_strip_view.h b/chrome/browser/ui/cocoa/tab_strip_view.h
new file mode 100644
index 0000000..f504ff4
--- /dev/null
+++ b/chrome/browser/ui/cocoa/tab_strip_view.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_TAB_STRIP_VIEW_H_
+#define CHROME_BROWSER_UI_COCOA_TAB_STRIP_VIEW_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/url_drop_target.h"
+
+@class NewTabButton;
+
+// A view class that handles rendering the tab strip and drops of URLS with
+// a positioning locator for drop feedback.
+
+@interface TabStripView : NSView<URLDropTarget> {
+ @private
+ NSTimeInterval lastMouseUp_;
+
+ // Handles being a drag-and-drop target.
+ scoped_nsobject<URLDropTargetHandler> dropHandler_;
+
+ // Weak; the following come from the nib.
+ NewTabButton* newTabButton_;
+
+ // Whether the drop-indicator arrow is shown, and if it is, the coordinate of
+ // its tip.
+ BOOL dropArrowShown_;
+ NSPoint dropArrowPosition_;
+}
+
+@property(assign, nonatomic) IBOutlet NewTabButton* newTabButton;
+@property(assign, nonatomic) BOOL dropArrowShown;
+@property(assign, nonatomic) NSPoint dropArrowPosition;
+
+@end
+
+// Protected methods subclasses can override to alter behavior. Clients should
+// not call these directly.
+@interface TabStripView(Protected)
+- (void)drawBottomBorder:(NSRect)bounds;
+- (BOOL)doubleClickMinimizesWindow;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_TAB_STRIP_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/tab_strip_view.mm b/chrome/browser/ui/cocoa/tab_strip_view.mm
new file mode 100644
index 0000000..2456362
--- /dev/null
+++ b/chrome/browser/ui/cocoa/tab_strip_view.mm
@@ -0,0 +1,211 @@
+// 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 "chrome/browser/ui/cocoa/tab_strip_view.h"
+
+#include "base/logging.h"
+#include "base/mac_util.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "chrome/browser/ui/cocoa/tab_strip_controller.h"
+#import "chrome/browser/ui/cocoa/view_id_util.h"
+
+@implementation TabStripView
+
+@synthesize newTabButton = newTabButton_;
+@synthesize dropArrowShown = dropArrowShown_;
+@synthesize dropArrowPosition = dropArrowPosition_;
+
+- (id)initWithFrame:(NSRect)frame {
+ self = [super initWithFrame:frame];
+ if (self) {
+ // Set lastMouseUp_ = -1000.0 so that timestamp-lastMouseUp_ is big unless
+ // lastMouseUp_ has been reset.
+ lastMouseUp_ = -1000.0;
+
+ // Register to be an URL drop target.
+ dropHandler_.reset([[URLDropTargetHandler alloc] initWithView:self]);
+ }
+ return self;
+}
+
+// Draw bottom border (a dark border and light highlight). Each tab is
+// responsible for mimicking this bottom border, unless it's the selected
+// tab.
+- (void)drawBorder:(NSRect)bounds {
+ NSRect borderRect, contentRect;
+
+ borderRect = bounds;
+ borderRect.origin.y = 1;
+ borderRect.size.height = 1;
+ [[NSColor colorWithCalibratedWhite:0.0 alpha:0.2] set];
+ NSRectFillUsingOperation(borderRect, NSCompositeSourceOver);
+ NSDivideRect(bounds, &borderRect, &contentRect, 1, NSMinYEdge);
+
+ BrowserThemeProvider* themeProvider =
+ static_cast<BrowserThemeProvider*>([[self window] themeProvider]);
+ if (!themeProvider)
+ return;
+
+ NSColor* bezelColor = themeProvider->GetNSColor(
+ themeProvider->UsingDefaultTheme() ?
+ BrowserThemeProvider::COLOR_TOOLBAR_BEZEL :
+ BrowserThemeProvider::COLOR_TOOLBAR, true);
+ [bezelColor set];
+ NSRectFill(borderRect);
+ NSRectFillUsingOperation(borderRect, NSCompositeSourceOver);
+}
+
+- (void)drawRect:(NSRect)rect {
+ NSRect boundsRect = [self bounds];
+
+ [self drawBorder:boundsRect];
+
+ // Draw drop-indicator arrow (if appropriate).
+ // TODO(viettrungluu): this is all a stop-gap measure.
+ if ([self dropArrowShown]) {
+ // Programmer art: an arrow parametrized by many knobs. Note that the arrow
+ // points downwards (so understand "width" and "height" accordingly).
+
+ // How many (pixels) to inset on the top/bottom.
+ const CGFloat kArrowTopInset = 1.5;
+ const CGFloat kArrowBottomInset = 1;
+
+ // What proportion of the vertical space is dedicated to the arrow tip,
+ // i.e., (arrow tip height)/(amount of vertical space).
+ const CGFloat kArrowTipProportion = 0.5;
+
+ // This is a slope, i.e., (arrow tip height)/(0.5 * arrow tip width).
+ const CGFloat kArrowTipSlope = 1.2;
+
+ // What proportion of the arrow tip width is the stem, i.e., (stem
+ // width)/(arrow tip width).
+ const CGFloat kArrowStemProportion = 0.33;
+
+ NSPoint arrowTipPos = [self dropArrowPosition];
+ arrowTipPos.y += kArrowBottomInset; // Inset on the bottom.
+
+ // Height we have to work with (insetting on the top).
+ CGFloat availableHeight =
+ NSMaxY(boundsRect) - arrowTipPos.y - kArrowTopInset;
+ DCHECK(availableHeight >= 5);
+
+ // Based on the knobs above, calculate actual dimensions which we'll need
+ // for drawing.
+ CGFloat arrowTipHeight = kArrowTipProportion * availableHeight;
+ CGFloat arrowTipWidth = 2 * arrowTipHeight / kArrowTipSlope;
+ CGFloat arrowStemHeight = availableHeight - arrowTipHeight;
+ CGFloat arrowStemWidth = kArrowStemProportion * arrowTipWidth;
+ CGFloat arrowStemInset = (arrowTipWidth - arrowStemWidth) / 2;
+
+ // The line width is arbitrary, but our path really should be mitered.
+ NSBezierPath* arrow = [NSBezierPath bezierPath];
+ [arrow setLineJoinStyle:NSMiterLineJoinStyle];
+ [arrow setLineWidth:1];
+
+ // Define the arrow's shape! We start from the tip and go clockwise.
+ [arrow moveToPoint:arrowTipPos];
+ [arrow relativeLineToPoint:NSMakePoint(-arrowTipWidth / 2, arrowTipHeight)];
+ [arrow relativeLineToPoint:NSMakePoint(arrowStemInset, 0)];
+ [arrow relativeLineToPoint:NSMakePoint(0, arrowStemHeight)];
+ [arrow relativeLineToPoint:NSMakePoint(arrowStemWidth, 0)];
+ [arrow relativeLineToPoint:NSMakePoint(0, -arrowStemHeight)];
+ [arrow relativeLineToPoint:NSMakePoint(arrowStemInset, 0)];
+ [arrow closePath];
+
+ // Draw and fill the arrow.
+ [[NSColor colorWithCalibratedWhite:0 alpha:0.67] set];
+ [arrow stroke];
+ [[NSColor colorWithCalibratedWhite:1 alpha:0.67] setFill];
+ [arrow fill];
+ }
+}
+
+// YES if a double-click in the background of the tab strip minimizes the
+// window.
+- (BOOL)doubleClickMinimizesWindow {
+ return YES;
+}
+
+// We accept first mouse so clicks onto close/zoom/miniaturize buttons and
+// title bar double-clicks are properly detected even when the window is in the
+// background.
+- (BOOL)acceptsFirstMouse:(NSEvent*)event {
+ return YES;
+}
+
+// Trap double-clicks and make them miniaturize the browser window.
+- (void)mouseUp:(NSEvent*)event {
+ // Bail early if double-clicks are disabled.
+ if (![self doubleClickMinimizesWindow]) {
+ [super mouseUp:event];
+ return;
+ }
+
+ NSInteger clickCount = [event clickCount];
+ NSTimeInterval timestamp = [event timestamp];
+
+ // Double-clicks on Zoom/Close/Mininiaturize buttons shouldn't cause
+ // miniaturization. For those, we miss the first click but get the second
+ // (with clickCount == 2!). We thus check that we got a first click shortly
+ // before (measured up-to-up) a double-click. Cocoa doesn't have a documented
+ // way of getting the proper interval (= (double-click-threshold) +
+ // (drag-threshold); the former is Carbon GetDblTime()/60.0 or
+ // com.apple.mouse.doubleClickThreshold [undocumented]). So we hard-code
+ // "short" as 0.8 seconds. (Measuring up-to-up isn't enough to properly
+ // detect double-clicks, but we're actually using Cocoa for that.)
+ if (clickCount == 2 && (timestamp - lastMouseUp_) < 0.8) {
+ if (mac_util::ShouldWindowsMiniaturizeOnDoubleClick())
+ [[self window] performMiniaturize:self];
+ } else {
+ [super mouseUp:event];
+ }
+
+ // If clickCount is 0, the drag threshold was passed.
+ lastMouseUp_ = (clickCount == 1) ? timestamp : -1000.0;
+}
+
+// (URLDropTarget protocol)
+- (id<URLDropTargetController>)urlDropController {
+ BrowserWindowController* windowController = [[self window] windowController];
+ DCHECK([windowController isKindOfClass:[BrowserWindowController class]]);
+ return [windowController tabStripController];
+}
+
+// (URLDropTarget protocol)
+- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
+ return [dropHandler_ draggingEntered:sender];
+}
+
+// (URLDropTarget protocol)
+- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender {
+ return [dropHandler_ draggingUpdated:sender];
+}
+
+// (URLDropTarget protocol)
+- (void)draggingExited:(id<NSDraggingInfo>)sender {
+ return [dropHandler_ draggingExited:sender];
+}
+
+// (URLDropTarget protocol)
+- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
+ return [dropHandler_ performDragOperation:sender];
+}
+
+- (BOOL)accessibilityIsIgnored {
+ return NO;
+}
+
+- (id)accessibilityAttributeValue:(NSString*)attribute {
+ if ([attribute isEqual:NSAccessibilityRoleAttribute])
+ return NSAccessibilityGroupRole;
+
+ return [super accessibilityAttributeValue:attribute];
+}
+
+- (ViewID)viewID {
+ return VIEW_ID_TAB_STRIP;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/tab_strip_view_unittest.mm b/chrome/browser/ui/cocoa/tab_strip_view_unittest.mm
new file mode 100644
index 0000000..2fde99c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/tab_strip_view_unittest.mm
@@ -0,0 +1,30 @@
+// Copyright (c) 2009 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 "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/tab_strip_view.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class TabStripViewTest : public CocoaTest {
+ public:
+ TabStripViewTest() {
+ NSRect frame = NSMakeRect(0, 0, 100, 30);
+ scoped_nsobject<TabStripView> view(
+ [[TabStripView alloc] initWithFrame:frame]);
+ view_ = view.get();
+ [[test_window() contentView] addSubview:view_];
+ }
+
+ TabStripView* view_;
+};
+
+TEST_VIEW(TabStripViewTest, view_)
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/tab_view.h b/chrome/browser/ui/cocoa/tab_view.h
new file mode 100644
index 0000000..f351650
--- /dev/null
+++ b/chrome/browser/ui/cocoa/tab_view.h
@@ -0,0 +1,134 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_TAB_VIEW_H_
+#define CHROME_BROWSER_UI_COCOA_TAB_VIEW_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+#include <ApplicationServices/ApplicationServices.h>
+
+#include <map>
+
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/background_gradient_view.h"
+#import "chrome/browser/ui/cocoa/hover_close_button.h"
+
+namespace tabs {
+
+// Nomenclature:
+// Tabs _glow_ under two different circumstances, when they are _hovered_ (by
+// the mouse) and when they are _alerted_ (to show that the tab's title has
+// changed).
+
+// The state of alerting (to show a title change on an unselected, pinned tab).
+// This is more complicated than a simple on/off since we want to allow the
+// alert glow to go through a full rise-hold-fall cycle to avoid flickering (or
+// always holding).
+enum AlertState {
+ kAlertNone = 0, // Obj-C initializes to this.
+ kAlertRising,
+ kAlertHolding,
+ kAlertFalling
+};
+
+} // namespace tabs
+
+@class TabController, TabWindowController;
+
+// A view that handles the event tracking (clicking and dragging) for a tab
+// on the tab strip. Relies on an associated TabController to provide a
+// target/action for selecting the tab.
+
+@interface TabView : BackgroundGradientView {
+ @private
+ IBOutlet TabController* controller_;
+ // TODO(rohitrao): Add this button to a CoreAnimation layer so we can fade it
+ // in and out on mouseovers.
+ IBOutlet HoverCloseButton* closeButton_;
+
+ // See awakeFromNib for purpose.
+ scoped_nsobject<HoverCloseButton> closeButtonRetainer_;
+
+ BOOL closing_;
+
+ // Tracking area for close button mouseover images.
+ scoped_nsobject<NSTrackingArea> closeTrackingArea_;
+
+ BOOL isMouseInside_; // Is the mouse hovering over?
+ tabs::AlertState alertState_;
+
+ CGFloat hoverAlpha_; // How strong the hover glow is.
+ NSTimeInterval hoverHoldEndTime_; // When the hover glow will begin dimming.
+
+ CGFloat alertAlpha_; // How strong the alert glow is.
+ NSTimeInterval alertHoldEndTime_; // When the hover glow will begin dimming.
+
+ NSTimeInterval lastGlowUpdate_; // Time either glow was last updated.
+
+ NSPoint hoverPoint_; // Current location of hover in view coords.
+
+ // All following variables are valid for the duration of a drag.
+ // These are released on mouseUp:
+ BOOL moveWindowOnDrag_; // Set if the only tab of a window is dragged.
+ BOOL tabWasDragged_; // Has the tab been dragged?
+ BOOL draggingWithinTabStrip_; // Did drag stay in the current tab strip?
+ BOOL chromeIsVisible_;
+
+ NSTimeInterval tearTime_; // Time since tear happened
+ NSPoint tearOrigin_; // Origin of the tear rect
+ NSPoint dragOrigin_; // Origin point of the drag
+ // TODO(alcor): these references may need to be strong to avoid crashes
+ // due to JS closing windows
+ TabWindowController* sourceController_; // weak. controller starting the drag
+ NSWindow* sourceWindow_; // weak. The window starting the drag
+ NSRect sourceWindowFrame_;
+ NSRect sourceTabFrame_;
+
+ TabWindowController* draggedController_; // weak. Controller being dragged.
+ NSWindow* dragWindow_; // weak. The window being dragged
+ NSWindow* dragOverlay_; // weak. The overlay being dragged
+ // Cache workspace IDs per-drag because computing them on 10.5 with
+ // CGWindowListCreateDescriptionFromArray is expensive.
+ // resetDragControllers clears this cache.
+ //
+ // TODO(davidben): When 10.5 becomes unsupported, remove this.
+ std::map<CGWindowID, int> workspaceIDCache_;
+
+ TabWindowController* targetController_; // weak. Controller being targeted
+ NSCellStateValue state_;
+}
+
+@property(assign, nonatomic) NSCellStateValue state;
+@property(assign, nonatomic) CGFloat hoverAlpha;
+@property(assign, nonatomic) CGFloat alertAlpha;
+
+// Determines if the tab is in the process of animating closed. It may still
+// be visible on-screen, but should not respond to/initiate any events. Upon
+// setting to NO, clears the target/action of the close button to prevent
+// clicks inside it from sending messages.
+@property(assign, nonatomic, getter=isClosing) BOOL closing;
+
+// Enables/Disables tracking regions for the tab.
+- (void)setTrackingEnabled:(BOOL)enabled;
+
+// Begin showing an "alert" glow (shown to call attention to an unselected
+// pinned tab whose title changed).
+- (void)startAlert;
+
+// Stop showing the "alert" glow; this won't immediately wipe out any glow, but
+// will make it fade away.
+- (void)cancelAlert;
+
+@end
+
+// The TabController |controller_| is not the only owner of this view. If the
+// controller is released before this view, then we could be hanging onto a
+// garbage pointer. To prevent this, the TabController uses this interface to
+// clear the |controller_| pointer when it is dying.
+@interface TabView (TabControllerInterface)
+- (void)setController:(TabController*)controller;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_TAB_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/tab_view.mm b/chrome/browser/ui/cocoa/tab_view.mm
new file mode 100644
index 0000000..128b83f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/tab_view.mm
@@ -0,0 +1,1056 @@
+// 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 "chrome/browser/ui/cocoa/tab_view.h"
+
+#include "base/logging.h"
+#import "base/mac_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "chrome/browser/accessibility/browser_accessibility_state.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
+#import "chrome/browser/ui/cocoa/tab_controller.h"
+#import "chrome/browser/ui/cocoa/tab_window_controller.h"
+#import "chrome/browser/ui/cocoa/themed_window.h"
+#import "chrome/browser/ui/cocoa/view_id_util.h"
+#include "grit/theme_resources.h"
+
+namespace {
+
+// Constants for inset and control points for tab shape.
+const CGFloat kInsetMultiplier = 2.0/3.0;
+const CGFloat kControlPoint1Multiplier = 1.0/3.0;
+const CGFloat kControlPoint2Multiplier = 3.0/8.0;
+
+// The amount of time in seconds during which each type of glow increases, holds
+// steady, and decreases, respectively.
+const NSTimeInterval kHoverShowDuration = 0.2;
+const NSTimeInterval kHoverHoldDuration = 0.02;
+const NSTimeInterval kHoverHideDuration = 0.4;
+const NSTimeInterval kAlertShowDuration = 0.4;
+const NSTimeInterval kAlertHoldDuration = 0.4;
+const NSTimeInterval kAlertHideDuration = 0.4;
+
+// The default time interval in seconds between glow updates (when
+// increasing/decreasing).
+const NSTimeInterval kGlowUpdateInterval = 0.025;
+
+const CGFloat kTearDistance = 36.0;
+const NSTimeInterval kTearDuration = 0.333;
+
+// This is used to judge whether the mouse has moved during rapid closure; if it
+// has moved less than the threshold, we want to close the tab.
+const CGFloat kRapidCloseDist = 2.5;
+
+} // namespace
+
+@interface TabView(Private)
+
+- (void)resetLastGlowUpdateTime;
+- (NSTimeInterval)timeElapsedSinceLastGlowUpdate;
+- (void)adjustGlowValue;
+// TODO(davidben): When we stop supporting 10.5, this can be removed.
+- (int)getWorkspaceID:(NSWindow*)window useCache:(BOOL)useCache;
+- (NSBezierPath*)bezierPathForRect:(NSRect)rect;
+
+@end // TabView(Private)
+
+@implementation TabView
+
+@synthesize state = state_;
+@synthesize hoverAlpha = hoverAlpha_;
+@synthesize alertAlpha = alertAlpha_;
+@synthesize closing = closing_;
+
+- (id)initWithFrame:(NSRect)frame {
+ self = [super initWithFrame:frame];
+ if (self) {
+ [self setShowsDivider:NO];
+ // TODO(alcor): register for theming
+ }
+ return self;
+}
+
+- (void)awakeFromNib {
+ [self setShowsDivider:NO];
+
+ // It is desirable for us to remove the close button from the cocoa hierarchy,
+ // so that VoiceOver does not encounter it.
+ // TODO(dtseng): crbug.com/59978.
+ // Retain in case we remove it from its superview.
+ closeButtonRetainer_.reset([closeButton_ retain]);
+ if (BrowserAccessibilityState::GetInstance()->IsAccessibleBrowser()) {
+ // The superview gives up ownership of the closeButton here.
+ [closeButton_ removeFromSuperview];
+ }
+}
+
+- (void)dealloc {
+ // Cancel any delayed requests that may still be pending (drags or hover).
+ [NSObject cancelPreviousPerformRequestsWithTarget:self];
+ [super dealloc];
+}
+
+// Called to obtain the context menu for when the user hits the right mouse
+// button (or control-clicks). (Note that -rightMouseDown: is *not* called for
+// control-click.)
+- (NSMenu*)menu {
+ if ([self isClosing])
+ return nil;
+
+ // Sheets, being window-modal, should block contextual menus. For some reason
+ // they do not. Disallow them ourselves.
+ if ([[self window] attachedSheet])
+ return nil;
+
+ return [controller_ menu];
+}
+
+// Overridden so that mouse clicks come to this view (the parent of the
+// hierarchy) first. We want to handle clicks and drags in this class and
+// leave the background button for display purposes only.
+- (BOOL)acceptsFirstMouse:(NSEvent*)theEvent {
+ return YES;
+}
+
+- (void)mouseEntered:(NSEvent*)theEvent {
+ isMouseInside_ = YES;
+ [self resetLastGlowUpdateTime];
+ [self adjustGlowValue];
+}
+
+- (void)mouseMoved:(NSEvent*)theEvent {
+ hoverPoint_ = [self convertPoint:[theEvent locationInWindow]
+ fromView:nil];
+ [self setNeedsDisplay:YES];
+}
+
+- (void)mouseExited:(NSEvent*)theEvent {
+ isMouseInside_ = NO;
+ hoverHoldEndTime_ =
+ [NSDate timeIntervalSinceReferenceDate] + kHoverHoldDuration;
+ [self resetLastGlowUpdateTime];
+ [self adjustGlowValue];
+}
+
+- (void)setTrackingEnabled:(BOOL)enabled {
+ [closeButton_ setTrackingEnabled:enabled];
+}
+
+// Determines which view a click in our frame actually hit. It's either this
+// view or our child close button.
+- (NSView*)hitTest:(NSPoint)aPoint {
+ NSPoint viewPoint = [self convertPoint:aPoint fromView:[self superview]];
+ NSRect frame = [self frame];
+
+ // Reduce the width of the hit rect slightly to remove the overlap
+ // between adjacent tabs. The drawing code in TabCell has the top
+ // corners of the tab inset by height*2/3, so we inset by half of
+ // that here. This doesn't completely eliminate the overlap, but it
+ // works well enough.
+ NSRect hitRect = NSInsetRect(frame, frame.size.height / 3.0f, 0);
+ if (![closeButton_ isHidden])
+ if (NSPointInRect(viewPoint, [closeButton_ frame])) return closeButton_;
+ if (NSPointInRect(aPoint, hitRect)) return self;
+ return nil;
+}
+
+// Returns |YES| if this tab can be torn away into a new window.
+- (BOOL)canBeDragged {
+ if ([self isClosing])
+ return NO;
+ NSWindowController* controller = [sourceWindow_ windowController];
+ if ([controller isKindOfClass:[TabWindowController class]]) {
+ TabWindowController* realController =
+ static_cast<TabWindowController*>(controller);
+ return [realController isTabDraggable:self];
+ }
+ return YES;
+}
+
+// Returns an array of controllers that could be a drop target, ordered front to
+// back. It has to be of the appropriate class, and visible (obviously). Note
+// that the window cannot be a target for itself.
+- (NSArray*)dropTargetsForController:(TabWindowController*)dragController {
+ NSMutableArray* targets = [NSMutableArray array];
+ NSWindow* dragWindow = [dragController window];
+ for (NSWindow* window in [NSApp orderedWindows]) {
+ if (window == dragWindow) continue;
+ if (![window isVisible]) continue;
+ // Skip windows on the wrong space.
+ if ([window respondsToSelector:@selector(isOnActiveSpace)]) {
+ if (![window performSelector:@selector(isOnActiveSpace)])
+ continue;
+ } else {
+ // TODO(davidben): When we stop supporting 10.5, this can be
+ // removed.
+ //
+ // We don't cache the workspace of |dragWindow| because it may
+ // move around spaces.
+ if ([self getWorkspaceID:dragWindow useCache:NO] !=
+ [self getWorkspaceID:window useCache:YES])
+ continue;
+ }
+ NSWindowController* controller = [window windowController];
+ if ([controller isKindOfClass:[TabWindowController class]]) {
+ TabWindowController* realController =
+ static_cast<TabWindowController*>(controller);
+ if ([realController canReceiveFrom:dragController])
+ [targets addObject:controller];
+ }
+ }
+ return targets;
+}
+
+// Call to clear out transient weak references we hold during drags.
+- (void)resetDragControllers {
+ draggedController_ = nil;
+ dragWindow_ = nil;
+ dragOverlay_ = nil;
+ sourceController_ = nil;
+ sourceWindow_ = nil;
+ targetController_ = nil;
+ workspaceIDCache_.clear();
+}
+
+// Sets whether the window background should be visible or invisible when
+// dragging a tab. The background should be invisible when the mouse is over a
+// potential drop target for the tab (the tab strip). It should be visible when
+// there's no drop target so the window looks more fully realized and ready to
+// become a stand-alone window.
+- (void)setWindowBackgroundVisibility:(BOOL)shouldBeVisible {
+ if (chromeIsVisible_ == shouldBeVisible)
+ return;
+
+ // There appears to be a race-condition in CoreAnimation where if we use
+ // animators to set the alpha values, we can't guarantee that we cancel them.
+ // This has the side effect of sometimes leaving the dragged window
+ // translucent or invisible. As a result, don't animate the alpha change.
+ [[draggedController_ overlayWindow] setAlphaValue:1.0];
+ if (targetController_) {
+ [dragWindow_ setAlphaValue:0.0];
+ [[draggedController_ overlayWindow] setHasShadow:YES];
+ [[targetController_ window] makeMainWindow];
+ } else {
+ [dragWindow_ setAlphaValue:0.5];
+ [[draggedController_ overlayWindow] setHasShadow:NO];
+ [[draggedController_ window] makeMainWindow];
+ }
+ chromeIsVisible_ = shouldBeVisible;
+}
+
+// Handle clicks and drags in this button. We get here because we have
+// overridden acceptsFirstMouse: and the click is within our bounds.
+- (void)mouseDown:(NSEvent*)theEvent {
+ if ([self isClosing])
+ return;
+
+ NSPoint downLocation = [theEvent locationInWindow];
+
+ // Record the state of the close button here, because selecting the tab will
+ // unhide it.
+ BOOL closeButtonActive = [closeButton_ isHidden] ? NO : YES;
+
+ // During the tab closure animation (in particular, during rapid tab closure),
+ // we may get incorrectly hit with a mouse down. If it should have gone to the
+ // close button, we send it there -- it should then track the mouse, so we
+ // don't have to worry about mouse ups.
+ if (closeButtonActive && [controller_ inRapidClosureMode]) {
+ NSPoint hitLocation = [[self superview] convertPoint:downLocation
+ fromView:nil];
+ if ([self hitTest:hitLocation] == closeButton_) {
+ [closeButton_ mouseDown:theEvent];
+ return;
+ }
+ }
+
+ // Fire the action to select the tab.
+ if ([[controller_ target] respondsToSelector:[controller_ action]])
+ [[controller_ target] performSelector:[controller_ action]
+ withObject:self];
+
+ [self resetDragControllers];
+
+ // Resolve overlay back to original window.
+ sourceWindow_ = [self window];
+ if ([sourceWindow_ isKindOfClass:[NSPanel class]]) {
+ sourceWindow_ = [sourceWindow_ parentWindow];
+ }
+
+ sourceWindowFrame_ = [sourceWindow_ frame];
+ sourceTabFrame_ = [self frame];
+ sourceController_ = [sourceWindow_ windowController];
+ tabWasDragged_ = NO;
+ tearTime_ = 0.0;
+ draggingWithinTabStrip_ = YES;
+ chromeIsVisible_ = NO;
+
+ // If there's more than one potential window to be a drop target, we want to
+ // treat a drag of a tab just like dragging around a tab that's already
+ // detached. Note that unit tests might have |-numberOfTabs| reporting zero
+ // since the model won't be fully hooked up. We need to be prepared for that
+ // and not send them into the "magnetic" codepath.
+ NSArray* targets = [self dropTargetsForController:sourceController_];
+ moveWindowOnDrag_ =
+ ([sourceController_ numberOfTabs] < 2 && ![targets count]) ||
+ ![self canBeDragged] ||
+ ![sourceController_ tabDraggingAllowed];
+ // If we are dragging a tab, a window with a single tab should immediately
+ // snap off and not drag within the tab strip.
+ if (!moveWindowOnDrag_)
+ draggingWithinTabStrip_ = [sourceController_ numberOfTabs] > 1;
+
+ dragOrigin_ = [NSEvent mouseLocation];
+
+ // If the tab gets torn off, the tab controller will be removed from the tab
+ // strip and then deallocated. This will also result in *us* being
+ // deallocated. Both these are bad, so we prevent this by retaining the
+ // controller.
+ scoped_nsobject<TabController> controller([controller_ retain]);
+
+ // Because we move views between windows, we need to handle the event loop
+ // ourselves. Ideally we should use the standard event loop.
+ while (1) {
+ theEvent =
+ [NSApp nextEventMatchingMask:NSLeftMouseUpMask | NSLeftMouseDraggedMask
+ untilDate:[NSDate distantFuture]
+ inMode:NSDefaultRunLoopMode dequeue:YES];
+ NSEventType type = [theEvent type];
+ if (type == NSLeftMouseDragged) {
+ [self mouseDragged:theEvent];
+ } else if (type == NSLeftMouseUp) {
+ NSPoint upLocation = [theEvent locationInWindow];
+ CGFloat dx = upLocation.x - downLocation.x;
+ CGFloat dy = upLocation.y - downLocation.y;
+
+ // During rapid tab closure (mashing tab close buttons), we may get hit
+ // with a mouse down. As long as the mouse up is over the close button,
+ // and the mouse hasn't moved too much, we close the tab.
+ if (closeButtonActive &&
+ (dx*dx + dy*dy) <= kRapidCloseDist*kRapidCloseDist &&
+ [controller inRapidClosureMode]) {
+ NSPoint hitLocation =
+ [[self superview] convertPoint:[theEvent locationInWindow]
+ fromView:nil];
+ if ([self hitTest:hitLocation] == closeButton_) {
+ [controller closeTab:self];
+ break;
+ }
+ }
+
+ [self mouseUp:theEvent];
+ break;
+ } else {
+ // TODO(viettrungluu): [crbug.com/23830] We can receive right-mouse-ups
+ // (and maybe even others?) for reasons I don't understand. So we
+ // explicitly check for both events we're expecting, and log others. We
+ // should figure out what's going on.
+ LOG(WARNING) << "Spurious event received of type " << type << ".";
+ }
+ }
+}
+
+- (void)mouseDragged:(NSEvent*)theEvent {
+ // Special-case this to keep the logic below simpler.
+ if (moveWindowOnDrag_) {
+ if ([sourceController_ windowMovementAllowed]) {
+ NSPoint thisPoint = [NSEvent mouseLocation];
+ NSPoint origin = sourceWindowFrame_.origin;
+ origin.x += (thisPoint.x - dragOrigin_.x);
+ origin.y += (thisPoint.y - dragOrigin_.y);
+ [sourceWindow_ setFrameOrigin:NSMakePoint(origin.x, origin.y)];
+ } // else do nothing.
+ return;
+ }
+
+ // First, go through the magnetic drag cycle. We break out of this if
+ // "stretchiness" ever exceeds a set amount.
+ tabWasDragged_ = YES;
+
+ if (draggingWithinTabStrip_) {
+ NSPoint thisPoint = [NSEvent mouseLocation];
+ CGFloat stretchiness = thisPoint.y - dragOrigin_.y;
+ stretchiness = copysign(sqrtf(fabs(stretchiness))/sqrtf(kTearDistance),
+ stretchiness) / 2.0;
+ CGFloat offset = thisPoint.x - dragOrigin_.x;
+ if (fabsf(offset) > 100) stretchiness = 0;
+ [sourceController_ insertPlaceholderForTab:self
+ frame:NSOffsetRect(sourceTabFrame_,
+ offset, 0)
+ yStretchiness:stretchiness];
+ // Check that we haven't pulled the tab too far to start a drag. This
+ // can include either pulling it too far down, or off the side of the tab
+ // strip that would cause it to no longer be fully visible.
+ BOOL stillVisible = [sourceController_ isTabFullyVisible:self];
+ CGFloat tearForce = fabs(thisPoint.y - dragOrigin_.y);
+ if ([sourceController_ tabTearingAllowed] &&
+ (tearForce > kTearDistance || !stillVisible)) {
+ draggingWithinTabStrip_ = NO;
+ // When you finally leave the strip, we treat that as the origin.
+ dragOrigin_.x = thisPoint.x;
+ } else {
+ // Still dragging within the tab strip, wait for the next drag event.
+ return;
+ }
+ }
+
+ // Do not start dragging until the user has "torn" the tab off by
+ // moving more than 3 pixels.
+ NSDate* targetDwellDate = nil; // The date this target was first chosen.
+
+ NSPoint thisPoint = [NSEvent mouseLocation];
+
+ // Iterate over possible targets checking for the one the mouse is in.
+ // If the tab is just in the frame, bring the window forward to make it
+ // easier to drop something there. If it's in the tab strip, set the new
+ // target so that it pops into that window. We can't cache this because we
+ // need the z-order to be correct.
+ NSArray* targets = [self dropTargetsForController:draggedController_];
+ TabWindowController* newTarget = nil;
+ for (TabWindowController* target in targets) {
+ NSRect windowFrame = [[target window] frame];
+ if (NSPointInRect(thisPoint, windowFrame)) {
+ [[target window] orderFront:self];
+ NSRect tabStripFrame = [[target tabStripView] frame];
+ tabStripFrame.origin = [[target window]
+ convertBaseToScreen:tabStripFrame.origin];
+ if (NSPointInRect(thisPoint, tabStripFrame)) {
+ newTarget = target;
+ }
+ break;
+ }
+ }
+
+ // If we're now targeting a new window, re-layout the tabs in the old
+ // target and reset how long we've been hovering over this new one.
+ if (targetController_ != newTarget) {
+ targetDwellDate = [NSDate date];
+ [targetController_ removePlaceholder];
+ targetController_ = newTarget;
+ if (!newTarget) {
+ tearTime_ = [NSDate timeIntervalSinceReferenceDate];
+ tearOrigin_ = [dragWindow_ frame].origin;
+ }
+ }
+
+ // Create or identify the dragged controller.
+ if (!draggedController_) {
+ // Get rid of any placeholder remaining in the original source window.
+ [sourceController_ removePlaceholder];
+
+ // Detach from the current window and put it in a new window. If there are
+ // no more tabs remaining after detaching, the source window is about to
+ // go away (it's been autoreleased) so we need to ensure we don't reference
+ // it any more. In that case the new controller becomes our source
+ // controller.
+ draggedController_ = [sourceController_ detachTabToNewWindow:self];
+ dragWindow_ = [draggedController_ window];
+ [dragWindow_ setAlphaValue:0.0];
+ if (![sourceController_ hasLiveTabs]) {
+ sourceController_ = draggedController_;
+ sourceWindow_ = dragWindow_;
+ }
+
+ // If dragging the tab only moves the current window, do not show overlay
+ // so that sheets stay on top of the window.
+ // Bring the target window to the front and make sure it has a border.
+ [dragWindow_ setLevel:NSFloatingWindowLevel];
+ [dragWindow_ setHasShadow:YES];
+ [dragWindow_ orderFront:nil];
+ [dragWindow_ makeMainWindow];
+ [draggedController_ showOverlay];
+ dragOverlay_ = [draggedController_ overlayWindow];
+ // Force the new tab button to be hidden. We'll reset it on mouse up.
+ [draggedController_ showNewTabButton:NO];
+ tearTime_ = [NSDate timeIntervalSinceReferenceDate];
+ tearOrigin_ = sourceWindowFrame_.origin;
+ }
+
+ // TODO(pinkerton): http://crbug.com/25682 demonstrates a way to get here by
+ // some weird circumstance that doesn't first go through mouseDown:. We
+ // really shouldn't go any farther.
+ if (!draggedController_ || !sourceController_)
+ return;
+
+ // When the user first tears off the window, we want slide the window to
+ // the current mouse location (to reduce the jarring appearance). We do this
+ // by calling ourselves back with additional mouseDragged calls (not actual
+ // events). |tearProgress| is a normalized measure of how far through this
+ // tear "animation" (of length kTearDuration) we are and has values [0..1].
+ // We use sqrt() so the animation is non-linear (slow down near the end
+ // point).
+ NSTimeInterval tearProgress =
+ [NSDate timeIntervalSinceReferenceDate] - tearTime_;
+ tearProgress /= kTearDuration; // Normalize.
+ tearProgress = sqrtf(MAX(MIN(tearProgress, 1.0), 0.0));
+
+ // Move the dragged window to the right place on the screen.
+ NSPoint origin = sourceWindowFrame_.origin;
+ origin.x += (thisPoint.x - dragOrigin_.x);
+ origin.y += (thisPoint.y - dragOrigin_.y);
+
+ if (tearProgress < 1) {
+ // If the tear animation is not complete, call back to ourself with the
+ // same event to animate even if the mouse isn't moving. We need to make
+ // sure these get cancelled in mouseUp:.
+ [NSObject cancelPreviousPerformRequestsWithTarget:self];
+ [self performSelector:@selector(mouseDragged:)
+ withObject:theEvent
+ afterDelay:1.0f/30.0f];
+
+ // Set the current window origin based on how far we've progressed through
+ // the tear animation.
+ origin.x = (1 - tearProgress) * tearOrigin_.x + tearProgress * origin.x;
+ origin.y = (1 - tearProgress) * tearOrigin_.y + tearProgress * origin.y;
+ }
+
+ if (targetController_) {
+ // In order to "snap" two windows of different sizes together at their
+ // toolbar, we can't just use the origin of the target frame. We also have
+ // to take into consideration the difference in height.
+ NSRect targetFrame = [[targetController_ window] frame];
+ NSRect sourceFrame = [dragWindow_ frame];
+ origin.y = NSMinY(targetFrame) +
+ (NSHeight(targetFrame) - NSHeight(sourceFrame));
+ }
+ [dragWindow_ setFrameOrigin:NSMakePoint(origin.x, origin.y)];
+
+ // If we're not hovering over any window, make the window fully
+ // opaque. Otherwise, find where the tab might be dropped and insert
+ // a placeholder so it appears like it's part of that window.
+ if (targetController_) {
+ if (![[targetController_ window] isKeyWindow]) {
+ // && ([targetDwellDate timeIntervalSinceNow] < -REQUIRED_DWELL)) {
+ [[targetController_ window] orderFront:nil];
+ targetDwellDate = nil;
+ }
+
+ // Compute where placeholder should go and insert it into the
+ // destination tab strip.
+ TabView* draggedTabView = (TabView*)[draggedController_ selectedTabView];
+ NSRect tabFrame = [draggedTabView frame];
+ tabFrame.origin = [dragWindow_ convertBaseToScreen:tabFrame.origin];
+ tabFrame.origin = [[targetController_ window]
+ convertScreenToBase:tabFrame.origin];
+ tabFrame = [[targetController_ tabStripView]
+ convertRect:tabFrame fromView:nil];
+ [targetController_ insertPlaceholderForTab:self
+ frame:tabFrame
+ yStretchiness:0];
+ [targetController_ layoutTabs];
+ } else {
+ [dragWindow_ makeKeyAndOrderFront:nil];
+ }
+
+ // Adjust the visibility of the window background. If there is a drop target,
+ // we want to hide the window background so the tab stands out for
+ // positioning. If not, we want to show it so it looks like a new window will
+ // be realized.
+ BOOL chromeShouldBeVisible = targetController_ == nil;
+ [self setWindowBackgroundVisibility:chromeShouldBeVisible];
+}
+
+- (void)mouseUp:(NSEvent*)theEvent {
+ // The drag/click is done. If the user dragged the mouse, finalize the drag
+ // and clean up.
+
+ // Special-case this to keep the logic below simpler.
+ if (moveWindowOnDrag_)
+ return;
+
+ // Cancel any delayed -mouseDragged: requests that may still be pending.
+ [NSObject cancelPreviousPerformRequestsWithTarget:self];
+
+ // TODO(pinkerton): http://crbug.com/25682 demonstrates a way to get here by
+ // some weird circumstance that doesn't first go through mouseDown:. We
+ // really shouldn't go any farther.
+ if (!sourceController_)
+ return;
+
+ // We are now free to re-display the new tab button in the window we're
+ // dragging. It will show when the next call to -layoutTabs (which happens
+ // indrectly by several of the calls below, such as removing the placeholder).
+ [draggedController_ showNewTabButton:YES];
+
+ if (draggingWithinTabStrip_) {
+ if (tabWasDragged_) {
+ // Move tab to new location.
+ DCHECK([sourceController_ numberOfTabs]);
+ TabWindowController* dropController = sourceController_;
+ [dropController moveTabView:[dropController selectedTabView]
+ fromController:nil];
+ }
+ } else if (targetController_) {
+ // Move between windows. If |targetController_| is nil, we're not dropping
+ // into any existing window.
+ NSView* draggedTabView = [draggedController_ selectedTabView];
+ [targetController_ moveTabView:draggedTabView
+ fromController:draggedController_];
+ // Force redraw to avoid flashes of old content before returning to event
+ // loop.
+ [[targetController_ window] display];
+ [targetController_ showWindow:nil];
+ [draggedController_ removeOverlay];
+ } else {
+ // Only move the window around on screen. Make sure it's set back to
+ // normal state (fully opaque, has shadow, has key, etc).
+ [draggedController_ removeOverlay];
+ // Don't want to re-show the window if it was closed during the drag.
+ if ([dragWindow_ isVisible]) {
+ [dragWindow_ setAlphaValue:1.0];
+ [dragOverlay_ setHasShadow:NO];
+ [dragWindow_ setHasShadow:YES];
+ [dragWindow_ makeKeyAndOrderFront:nil];
+ }
+ [[draggedController_ window] setLevel:NSNormalWindowLevel];
+ [draggedController_ removePlaceholder];
+ }
+ [sourceController_ removePlaceholder];
+ chromeIsVisible_ = YES;
+
+ [self resetDragControllers];
+}
+
+- (void)otherMouseUp:(NSEvent*)theEvent {
+ if ([self isClosing])
+ return;
+
+ // Support middle-click-to-close.
+ if ([theEvent buttonNumber] == 2) {
+ // |-hitTest:| takes a location in the superview's coordinates.
+ NSPoint upLocation =
+ [[self superview] convertPoint:[theEvent locationInWindow]
+ fromView:nil];
+ // If the mouse up occurred in our view or over the close button, then
+ // close.
+ if ([self hitTest:upLocation])
+ [controller_ closeTab:self];
+ }
+}
+
+- (void)drawRect:(NSRect)dirtyRect {
+ NSGraphicsContext* context = [NSGraphicsContext currentContext];
+ [context saveGraphicsState];
+
+ BrowserThemeProvider* themeProvider =
+ static_cast<BrowserThemeProvider*>([[self window] themeProvider]);
+ [context setPatternPhase:[[self window] themePatternPhase]];
+
+ NSRect rect = [self bounds];
+ NSBezierPath* path = [self bezierPathForRect:rect];
+
+ BOOL selected = [self state];
+ // Don't draw the window/tab bar background when selected, since the tab
+ // background overlay drawn over it (see below) will be fully opaque.
+ BOOL hasBackgroundImage = NO;
+ if (!selected) {
+ // ThemeProvider::HasCustomImage is true only if the theme provides the
+ // image. However, even if the theme doesn't provide a tab background, the
+ // theme machinery will make one if given a frame image. See
+ // BrowserThemePack::GenerateTabBackgroundImages for details.
+ hasBackgroundImage = themeProvider &&
+ (themeProvider->HasCustomImage(IDR_THEME_TAB_BACKGROUND) ||
+ themeProvider->HasCustomImage(IDR_THEME_FRAME));
+
+ NSColor* backgroundImageColor = hasBackgroundImage ?
+ themeProvider->GetNSImageColorNamed(IDR_THEME_TAB_BACKGROUND, true) :
+ nil;
+
+ if (backgroundImageColor) {
+ [backgroundImageColor set];
+ [path fill];
+ } else {
+ // Use the window's background color rather than |[NSColor
+ // windowBackgroundColor]|, which gets confused by the fullscreen window.
+ // (The result is the same for normal, non-fullscreen windows.)
+ [[[self window] backgroundColor] set];
+ [path fill];
+ [[NSColor colorWithCalibratedWhite:1.0 alpha:0.3] set];
+ [path fill];
+ }
+ }
+
+ [context saveGraphicsState];
+ [path addClip];
+
+ // Use the same overlay for the selected state and for hover and alert glows;
+ // for the selected state, it's fully opaque.
+ CGFloat hoverAlpha = [self hoverAlpha];
+ CGFloat alertAlpha = [self alertAlpha];
+ if (selected || hoverAlpha > 0 || alertAlpha > 0) {
+ // Draw the selected background / glow overlay.
+ [context saveGraphicsState];
+ CGContextRef cgContext = static_cast<CGContextRef>([context graphicsPort]);
+ CGContextBeginTransparencyLayer(cgContext, 0);
+ if (!selected) {
+ // The alert glow overlay is like the selected state but at most at most
+ // 80% opaque. The hover glow brings up the overlay's opacity at most 50%.
+ CGFloat backgroundAlpha = 0.8 * alertAlpha;
+ backgroundAlpha += (1 - backgroundAlpha) * 0.5 * hoverAlpha;
+ CGContextSetAlpha(cgContext, backgroundAlpha);
+ }
+ [path addClip];
+ [context saveGraphicsState];
+ [super drawBackground];
+ [context restoreGraphicsState];
+
+ // Draw a mouse hover gradient for the default themes.
+ if (!selected && hoverAlpha > 0) {
+ if (themeProvider && !hasBackgroundImage) {
+ scoped_nsobject<NSGradient> glow([NSGradient alloc]);
+ [glow initWithStartingColor:[NSColor colorWithCalibratedWhite:1.0
+ alpha:1.0 * hoverAlpha]
+ endingColor:[NSColor colorWithCalibratedWhite:1.0
+ alpha:0.0]];
+
+ NSPoint point = hoverPoint_;
+ point.y = NSHeight(rect);
+ [glow drawFromCenter:point
+ radius:0.0
+ toCenter:point
+ radius:NSWidth(rect) / 3.0
+ options:NSGradientDrawsBeforeStartingLocation];
+
+ [glow drawInBezierPath:path relativeCenterPosition:hoverPoint_];
+ }
+ }
+
+ CGContextEndTransparencyLayer(cgContext);
+ [context restoreGraphicsState];
+ }
+
+ BOOL active = [[self window] isKeyWindow] || [[self window] isMainWindow];
+ CGFloat borderAlpha = selected ? (active ? 0.3 : 0.2) : 0.2;
+ NSColor* borderColor = [NSColor colorWithDeviceWhite:0.0 alpha:borderAlpha];
+ NSColor* highlightColor = themeProvider ? themeProvider->GetNSColor(
+ themeProvider->UsingDefaultTheme() ?
+ BrowserThemeProvider::COLOR_TOOLBAR_BEZEL :
+ BrowserThemeProvider::COLOR_TOOLBAR, true) : nil;
+
+ // Draw the top inner highlight within the currently selected tab if using
+ // the default theme.
+ if (selected && themeProvider && themeProvider->UsingDefaultTheme()) {
+ NSAffineTransform* highlightTransform = [NSAffineTransform transform];
+ [highlightTransform translateXBy:1.0 yBy:-1.0];
+ scoped_nsobject<NSBezierPath> highlightPath([path copy]);
+ [highlightPath transformUsingAffineTransform:highlightTransform];
+ [highlightColor setStroke];
+ [highlightPath setLineWidth:1.0];
+ [highlightPath stroke];
+ highlightTransform = [NSAffineTransform transform];
+ [highlightTransform translateXBy:-2.0 yBy:0.0];
+ [highlightPath transformUsingAffineTransform:highlightTransform];
+ [highlightPath stroke];
+ }
+
+ [context restoreGraphicsState];
+
+ // Draw the top stroke.
+ [context saveGraphicsState];
+ [borderColor set];
+ [path setLineWidth:1.0];
+ [path stroke];
+ [context restoreGraphicsState];
+
+ // Mimic the tab strip's bottom border, which consists of a dark border
+ // and light highlight.
+ if (!selected) {
+ [path addClip];
+ NSRect borderRect = rect;
+ borderRect.origin.y = 1;
+ borderRect.size.height = 1;
+ [borderColor set];
+ NSRectFillUsingOperation(borderRect, NSCompositeSourceOver);
+
+ borderRect.origin.y = 0;
+ [highlightColor set];
+ NSRectFillUsingOperation(borderRect, NSCompositeSourceOver);
+ }
+
+ [context restoreGraphicsState];
+}
+
+- (void)viewDidMoveToWindow {
+ [super viewDidMoveToWindow];
+ if ([self window]) {
+ [controller_ updateTitleColor];
+ }
+}
+
+- (void)setClosing:(BOOL)closing {
+ closing_ = closing; // Safe because the property is nonatomic.
+ // When closing, ensure clicks to the close button go nowhere.
+ if (closing) {
+ [closeButton_ setTarget:nil];
+ [closeButton_ setAction:nil];
+ }
+}
+
+- (void)startAlert {
+ // Do not start a new alert while already alerting or while in a decay cycle.
+ if (alertState_ == tabs::kAlertNone) {
+ alertState_ = tabs::kAlertRising;
+ [self resetLastGlowUpdateTime];
+ [self adjustGlowValue];
+ }
+}
+
+- (void)cancelAlert {
+ if (alertState_ != tabs::kAlertNone) {
+ alertState_ = tabs::kAlertFalling;
+ alertHoldEndTime_ =
+ [NSDate timeIntervalSinceReferenceDate] + kGlowUpdateInterval;
+ [self resetLastGlowUpdateTime];
+ [self adjustGlowValue];
+ }
+}
+
+- (BOOL)accessibilityIsIgnored {
+ return NO;
+}
+
+- (NSArray*)accessibilityActionNames {
+ NSArray* parentActions = [super accessibilityActionNames];
+
+ return [parentActions arrayByAddingObject:NSAccessibilityPressAction];
+}
+
+- (NSArray*)accessibilityAttributeNames {
+ NSMutableArray* attributes =
+ [[super accessibilityAttributeNames] mutableCopy];
+ [attributes addObject:NSAccessibilityTitleAttribute];
+ [attributes addObject:NSAccessibilityEnabledAttribute];
+
+ return attributes;
+}
+
+- (BOOL)accessibilityIsAttributeSettable:(NSString*)attribute {
+ if ([attribute isEqual:NSAccessibilityTitleAttribute])
+ return NO;
+
+ if ([attribute isEqual:NSAccessibilityEnabledAttribute])
+ return NO;
+
+ return [super accessibilityIsAttributeSettable:attribute];
+}
+
+- (id)accessibilityAttributeValue:(NSString*)attribute {
+ if ([attribute isEqual:NSAccessibilityRoleAttribute])
+ return NSAccessibilityButtonRole;
+
+ if ([attribute isEqual:NSAccessibilityTitleAttribute])
+ return [controller_ title];
+
+ if ([attribute isEqual:NSAccessibilityEnabledAttribute])
+ return [NSNumber numberWithBool:YES];
+
+ if ([attribute isEqual:NSAccessibilityChildrenAttribute]) {
+ // The subviews (icon and text) are clutter; filter out everything but
+ // useful controls.
+ NSArray* children = [super accessibilityAttributeValue:attribute];
+ NSMutableArray* okChildren = [NSMutableArray array];
+ for (id child in children) {
+ if ([child isKindOfClass:[NSButtonCell class]])
+ [okChildren addObject:child];
+ }
+
+ return okChildren;
+ }
+
+ return [super accessibilityAttributeValue:attribute];
+}
+
+- (ViewID)viewID {
+ return VIEW_ID_TAB;
+}
+
+@end // @implementation TabView
+
+@implementation TabView (TabControllerInterface)
+
+- (void)setController:(TabController*)controller {
+ controller_ = controller;
+}
+
+@end // @implementation TabView (TabControllerInterface)
+
+@implementation TabView(Private)
+
+- (void)resetLastGlowUpdateTime {
+ lastGlowUpdate_ = [NSDate timeIntervalSinceReferenceDate];
+}
+
+- (NSTimeInterval)timeElapsedSinceLastGlowUpdate {
+ return [NSDate timeIntervalSinceReferenceDate] - lastGlowUpdate_;
+}
+
+- (void)adjustGlowValue {
+ // A time interval long enough to represent no update.
+ const NSTimeInterval kNoUpdate = 1000000;
+
+ // Time until next update for either glow.
+ NSTimeInterval nextUpdate = kNoUpdate;
+
+ NSTimeInterval elapsed = [self timeElapsedSinceLastGlowUpdate];
+ NSTimeInterval currentTime = [NSDate timeIntervalSinceReferenceDate];
+
+ // TODO(viettrungluu): <http://crbug.com/30617> -- split off the stuff below
+ // into a pure function and add a unit test.
+
+ CGFloat hoverAlpha = [self hoverAlpha];
+ if (isMouseInside_) {
+ // Increase hover glow until it's 1.
+ if (hoverAlpha < 1) {
+ hoverAlpha = MIN(hoverAlpha + elapsed / kHoverShowDuration, 1);
+ [self setHoverAlpha:hoverAlpha];
+ nextUpdate = MIN(kGlowUpdateInterval, nextUpdate);
+ } // Else already 1 (no update needed).
+ } else {
+ if (currentTime >= hoverHoldEndTime_) {
+ // No longer holding, so decrease hover glow until it's 0.
+ if (hoverAlpha > 0) {
+ hoverAlpha = MAX(hoverAlpha - elapsed / kHoverHideDuration, 0);
+ [self setHoverAlpha:hoverAlpha];
+ nextUpdate = MIN(kGlowUpdateInterval, nextUpdate);
+ } // Else already 0 (no update needed).
+ } else {
+ // Schedule update for end of hold time.
+ nextUpdate = MIN(hoverHoldEndTime_ - currentTime, nextUpdate);
+ }
+ }
+
+ CGFloat alertAlpha = [self alertAlpha];
+ if (alertState_ == tabs::kAlertRising) {
+ // Increase alert glow until it's 1 ...
+ alertAlpha = MIN(alertAlpha + elapsed / kAlertShowDuration, 1);
+ [self setAlertAlpha:alertAlpha];
+
+ // ... and having reached 1, switch to holding.
+ if (alertAlpha >= 1) {
+ alertState_ = tabs::kAlertHolding;
+ alertHoldEndTime_ = currentTime + kAlertHoldDuration;
+ nextUpdate = MIN(kAlertHoldDuration, nextUpdate);
+ } else {
+ nextUpdate = MIN(kGlowUpdateInterval, nextUpdate);
+ }
+ } else if (alertState_ != tabs::kAlertNone) {
+ if (alertAlpha > 0) {
+ if (currentTime >= alertHoldEndTime_) {
+ // Stop holding, then decrease alert glow (until it's 0).
+ if (alertState_ == tabs::kAlertHolding) {
+ alertState_ = tabs::kAlertFalling;
+ nextUpdate = MIN(kGlowUpdateInterval, nextUpdate);
+ } else {
+ DCHECK_EQ(tabs::kAlertFalling, alertState_);
+ alertAlpha = MAX(alertAlpha - elapsed / kAlertHideDuration, 0);
+ [self setAlertAlpha:alertAlpha];
+ nextUpdate = MIN(kGlowUpdateInterval, nextUpdate);
+ }
+ } else {
+ // Schedule update for end of hold time.
+ nextUpdate = MIN(alertHoldEndTime_ - currentTime, nextUpdate);
+ }
+ } else {
+ // Done the alert decay cycle.
+ alertState_ = tabs::kAlertNone;
+ }
+ }
+
+ if (nextUpdate < kNoUpdate)
+ [self performSelector:_cmd withObject:nil afterDelay:nextUpdate];
+
+ [self resetLastGlowUpdateTime];
+ [self setNeedsDisplay:YES];
+}
+
+// Returns the workspace id of |window|. If |useCache|, then lookup
+// and remember the value in |workspaceIDCache_| until the end of the
+// current drag.
+- (int)getWorkspaceID:(NSWindow*)window useCache:(BOOL)useCache {
+ CGWindowID windowID = [window windowNumber];
+ if (useCache) {
+ std::map<CGWindowID, int>::iterator iter =
+ workspaceIDCache_.find(windowID);
+ if (iter != workspaceIDCache_.end())
+ return iter->second;
+ }
+
+ int workspace = -1;
+ // It's possible to query in bulk, but probably not necessary.
+ base::mac::ScopedCFTypeRef<CFArrayRef> windowIDs(CFArrayCreate(
+ NULL, reinterpret_cast<const void **>(&windowID), 1, NULL));
+ base::mac::ScopedCFTypeRef<CFArrayRef> descriptions(
+ CGWindowListCreateDescriptionFromArray(windowIDs));
+ DCHECK(CFArrayGetCount(descriptions.get()) <= 1);
+ if (CFArrayGetCount(descriptions.get()) > 0) {
+ CFDictionaryRef dict = static_cast<CFDictionaryRef>(
+ CFArrayGetValueAtIndex(descriptions.get(), 0));
+ DCHECK(CFGetTypeID(dict) == CFDictionaryGetTypeID());
+
+ // Sanity check the ID.
+ CFNumberRef otherIDRef = (CFNumberRef)mac_util::GetValueFromDictionary(
+ dict, kCGWindowNumber, CFNumberGetTypeID());
+ CGWindowID otherID;
+ if (otherIDRef &&
+ CFNumberGetValue(otherIDRef, kCGWindowIDCFNumberType, &otherID) &&
+ otherID == windowID) {
+ // And then get the workspace.
+ CFNumberRef workspaceRef = (CFNumberRef)mac_util::GetValueFromDictionary(
+ dict, kCGWindowWorkspace, CFNumberGetTypeID());
+ if (!workspaceRef ||
+ !CFNumberGetValue(workspaceRef, kCFNumberIntType, &workspace)) {
+ workspace = -1;
+ }
+ } else {
+ NOTREACHED();
+ }
+ }
+ if (useCache) {
+ workspaceIDCache_[windowID] = workspace;
+ }
+ return workspace;
+}
+
+// Returns the bezier path used to draw the tab given the bounds to draw it in.
+- (NSBezierPath*)bezierPathForRect:(NSRect)rect {
+ // Outset by 0.5 in order to draw on pixels rather than on borders (which
+ // would cause blurry pixels). Subtract 1px of height to compensate, otherwise
+ // clipping will occur.
+ rect = NSInsetRect(rect, -0.5, -0.5);
+ rect.size.height -= 1.0;
+
+ NSPoint bottomLeft = NSMakePoint(NSMinX(rect), NSMinY(rect) + 2);
+ NSPoint bottomRight = NSMakePoint(NSMaxX(rect), NSMinY(rect) + 2);
+ NSPoint topRight =
+ NSMakePoint(NSMaxX(rect) - kInsetMultiplier * NSHeight(rect),
+ NSMaxY(rect));
+ NSPoint topLeft =
+ NSMakePoint(NSMinX(rect) + kInsetMultiplier * NSHeight(rect),
+ NSMaxY(rect));
+
+ CGFloat baseControlPointOutset = NSHeight(rect) * kControlPoint1Multiplier;
+ CGFloat bottomControlPointInset = NSHeight(rect) * kControlPoint2Multiplier;
+
+ // Outset many of these values by 1 to cause the fill to bleed outside the
+ // clip area.
+ NSBezierPath* path = [NSBezierPath bezierPath];
+ [path moveToPoint:NSMakePoint(bottomLeft.x - 1, bottomLeft.y - 2)];
+ [path lineToPoint:NSMakePoint(bottomLeft.x - 1, bottomLeft.y)];
+ [path lineToPoint:bottomLeft];
+ [path curveToPoint:topLeft
+ controlPoint1:NSMakePoint(bottomLeft.x + baseControlPointOutset,
+ bottomLeft.y)
+ controlPoint2:NSMakePoint(topLeft.x - bottomControlPointInset,
+ topLeft.y)];
+ [path lineToPoint:topRight];
+ [path curveToPoint:bottomRight
+ controlPoint1:NSMakePoint(topRight.x + bottomControlPointInset,
+ topRight.y)
+ controlPoint2:NSMakePoint(bottomRight.x - baseControlPointOutset,
+ bottomRight.y)];
+ [path lineToPoint:NSMakePoint(bottomRight.x + 1, bottomRight.y)];
+ [path lineToPoint:NSMakePoint(bottomRight.x + 1, bottomRight.y - 2)];
+ return path;
+}
+
+@end // @implementation TabView(Private)
diff --git a/chrome/browser/ui/cocoa/tab_view_picker_table.h b/chrome/browser/ui/cocoa/tab_view_picker_table.h
new file mode 100644
index 0000000..b6b80b0
--- /dev/null
+++ b/chrome/browser/ui/cocoa/tab_view_picker_table.h
@@ -0,0 +1,29 @@
+// 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>
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_nsobject.h"
+
+// TabViewPickerTable is an NSOutlineView that can be used to switch between the
+// NSTabViewItems of an NSTabView. To use this, just create a
+// TabViewPickerTable in Interface Builder and connect the |tabView_| outlet
+// to an NSTabView. Now the table is automatically populated with the tab labels
+// of the tab view, clicking the table updates the tab view, and switching
+// tab view items updates the selection of the table.
+@interface TabViewPickerTable : NSOutlineView <NSTabViewDelegate,
+ NSOutlineViewDelegate,
+ NSOutlineViewDataSource> {
+ @public
+ IBOutlet NSTabView* tabView_; // Visible for testing.
+
+ @private
+ id oldTabViewDelegate_;
+
+ // Shown above all the tab names. May be |nil|.
+ scoped_nsobject<NSString> heading_;
+}
+@property (nonatomic, copy) NSString* heading;
+@end
diff --git a/chrome/browser/cocoa/tab_view_picker_table.mm b/chrome/browser/ui/cocoa/tab_view_picker_table.mm
index 95dec3b..95dec3b 100644
--- a/chrome/browser/cocoa/tab_view_picker_table.mm
+++ b/chrome/browser/ui/cocoa/tab_view_picker_table.mm
diff --git a/chrome/browser/ui/cocoa/tab_view_picker_table_unittest.mm b/chrome/browser/ui/cocoa/tab_view_picker_table_unittest.mm
new file mode 100644
index 0000000..daf1340
--- /dev/null
+++ b/chrome/browser/ui/cocoa/tab_view_picker_table_unittest.mm
@@ -0,0 +1,138 @@
+// 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>
+
+#import "chrome/browser/ui/cocoa/tab_view_picker_table.h"
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+@interface TabViewPickerTableTestPing : NSObject <NSTabViewDelegate> {
+ @public
+ BOOL didSelectItemCalled_;
+}
+@end
+
+@implementation TabViewPickerTableTestPing
+- (void) tabView:(NSTabView*)tabView
+ didSelectTabViewItem:(NSTabViewItem*)tabViewItem {
+ didSelectItemCalled_ = YES;
+}
+@end
+
+namespace {
+
+class TabViewPickerTableTest : public CocoaTest {
+ public:
+ TabViewPickerTableTest() {
+ // Initialize picker table.
+ NSRect frame = NSMakeRect(0, 0, 30, 50);
+ scoped_nsobject<TabViewPickerTable> view(
+ [[TabViewPickerTable alloc] initWithFrame:frame]);
+ view_ = view.get();
+ [view_ setAllowsEmptySelection:NO];
+ [view_ setAllowsMultipleSelection:NO];
+ [view_ addTableColumn:
+ [[[NSTableColumn alloc] initWithIdentifier:nil] autorelease]];
+ [[test_window() contentView] addSubview:view_];
+
+ // Initialize source tab view, with delegate.
+ frame = NSMakeRect(30, 0, 50, 50);
+ scoped_nsobject<NSTabView> tabView(
+ [[NSTabView alloc] initWithFrame:frame]);
+ tabView_ = tabView.get();
+
+ scoped_nsobject<NSTabViewItem> item1(
+ [[NSTabViewItem alloc] initWithIdentifier:nil]);
+ [item1 setLabel:@"label 1"];
+ [tabView_ addTabViewItem:item1];
+
+ scoped_nsobject<NSTabViewItem> item2(
+ [[NSTabViewItem alloc] initWithIdentifier:nil]);
+ [item2 setLabel:@"label 2"];
+ [tabView_ addTabViewItem:item2];
+
+ [tabView_ selectTabViewItemAtIndex:1];
+ [[test_window() contentView] addSubview:tabView_];
+
+ ping_.reset([TabViewPickerTableTestPing new]);
+ [tabView_ setDelegate:ping_.get()];
+
+ // Simulate nib loading.
+ view_->tabView_ = tabView_;
+ [view_ awakeFromNib];
+ }
+
+ TabViewPickerTable* view_;
+ NSTabView* tabView_;
+ scoped_nsobject<TabViewPickerTableTestPing> ping_;
+};
+
+TEST_VIEW(TabViewPickerTableTest, view_)
+
+TEST_F(TabViewPickerTableTest, TestInitialSelectionCorrect) {
+ EXPECT_EQ(1, [view_ selectedRow]);
+}
+
+TEST_F(TabViewPickerTableTest, TestSelectionUpdates) {
+ [tabView_ selectTabViewItemAtIndex:0];
+ EXPECT_EQ(0, [view_ selectedRow]);
+
+ [tabView_ selectTabViewItemAtIndex:1];
+ EXPECT_EQ(1, [view_ selectedRow]);
+}
+
+TEST_F(TabViewPickerTableTest, TestDelegateStillWorks) {
+ EXPECT_FALSE(ping_.get()->didSelectItemCalled_);
+ [tabView_ selectTabViewItemAtIndex:0];
+ EXPECT_TRUE(ping_.get()->didSelectItemCalled_);
+}
+
+TEST_F(TabViewPickerTableTest, RowsCorrect) {
+ EXPECT_EQ(2, [view_ numberOfRows]);
+ EXPECT_EQ(2,
+ [[view_ dataSource] outlineView:view_ numberOfChildrenOfItem:nil]);
+
+ id item;
+ item = [[view_ dataSource] outlineView:view_ child:0 ofItem:nil];
+ EXPECT_NSEQ(@"label 1",
+ [[view_ dataSource] outlineView:view_
+ objectValueForTableColumn:nil // ignored
+ byItem:item]);
+ item = [[view_ dataSource] outlineView:view_ child:1 ofItem:nil];
+ EXPECT_NSEQ(@"label 2",
+ [[view_ dataSource] outlineView:view_
+ objectValueForTableColumn:nil // ignored
+ byItem:item]);
+}
+
+TEST_F(TabViewPickerTableTest, TestListUpdatesTabView) {
+ [view_ selectRowIndexes:[NSIndexSet indexSetWithIndex:0]
+ byExtendingSelection:NO];
+ EXPECT_EQ(0, [view_ selectedRow]); // sanity
+ EXPECT_EQ(0, [tabView_ indexOfTabViewItem:[tabView_ selectedTabViewItem]]);
+}
+
+TEST_F(TabViewPickerTableTest, TestWithHeadingNotEmpty) {
+ [view_ setHeading:@"disregard this"];
+
+ EXPECT_EQ(2, [view_ selectedRow]);
+
+ [tabView_ selectTabViewItemAtIndex:0];
+ EXPECT_EQ(1, [view_ selectedRow]);
+ [tabView_ selectTabViewItemAtIndex:1];
+ EXPECT_EQ(2, [view_ selectedRow]);
+
+ [view_ selectRowIndexes:[NSIndexSet indexSetWithIndex:1]
+ byExtendingSelection:NO];
+ EXPECT_EQ(1, [view_ selectedRow]); // sanity
+ EXPECT_EQ(0, [tabView_ indexOfTabViewItem:[tabView_ selectedTabViewItem]]);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/tab_view_unittest.mm b/chrome/browser/ui/cocoa/tab_view_unittest.mm
new file mode 100644
index 0000000..961c3a6
--- /dev/null
+++ b/chrome/browser/ui/cocoa/tab_view_unittest.mm
@@ -0,0 +1,60 @@
+// Copyright (c) 2009 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 "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/tab_view.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class TabViewTest : public CocoaTest {
+ public:
+ TabViewTest() {
+ NSRect frame = NSMakeRect(0, 0, 50, 30);
+ scoped_nsobject<TabView> view([[TabView alloc] initWithFrame:frame]);
+ view_ = view.get();
+ [[test_window() contentView] addSubview:view_];
+ }
+
+ TabView* view_;
+};
+
+TEST_VIEW(TabViewTest, view_)
+
+// Test drawing, mostly to ensure nothing leaks or crashes.
+TEST_F(TabViewTest, Display) {
+ for (int i = 0; i < 5; i++) {
+ for (int j = 0; j < 5; j++) {
+ [view_ setHoverAlpha:i*0.2];
+ [view_ setAlertAlpha:j*0.2];
+ [view_ display];
+ }
+ }
+}
+
+// Test it doesn't crash when asked for its menu with no TabController set.
+TEST_F(TabViewTest, Menu) {
+ EXPECT_FALSE([view_ menu]);
+}
+
+TEST_F(TabViewTest, Glow) {
+ // TODO(viettrungluu): Figure out how to test this, which is timing-sensitive
+ // and which moreover uses |-performSelector:withObject:afterDelay:|.
+
+ // Call |-startAlert|/|-cancelAlert| and make sure it doesn't crash.
+ for (int i = 0; i < 5; i++) {
+ [view_ startAlert];
+ [view_ cancelAlert];
+ }
+ [view_ startAlert];
+ [view_ startAlert];
+ [view_ cancelAlert];
+ [view_ cancelAlert];
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/tab_window_controller.h b/chrome/browser/ui/cocoa/tab_window_controller.h
new file mode 100644
index 0000000..ea3527c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/tab_window_controller.h
@@ -0,0 +1,180 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_TAB_WINDOW_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_TAB_WINDOW_CONTROLLER_H_
+#pragma once
+
+// A class acting as the Objective-C window controller for a window that has
+// tabs which can be dragged around. Tabs can be re-arranged within the same
+// window or dragged into other TabWindowController windows. This class doesn't
+// know anything about the actual tab implementation or model, as that is fairly
+// application-specific. It only provides an API to be overridden by subclasses
+// to fill in the details.
+//
+// This assumes that there will be a view in the nib, connected to
+// |tabContentArea_|, that indicates the content that it switched when switching
+// between tabs. It needs to be a regular NSView, not something like an NSBox
+// because the TabStripController makes certain assumptions about how it can
+// swap out subviews.
+//
+// The tab strip can exist in different orientations and window locations,
+// depending on the return value of -usesVerticalTabs. If NO (the default),
+// the tab strip is placed outside the window's content area, overlapping the
+// title area and window controls and will be stretched to fill the width
+// of the window. If YES, the tab strip is vertical and lives within the
+// window's content area. It will be stretched to fill the window's height.
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_nsobject.h"
+
+@class FastResizeView;
+@class FocusTracker;
+@class TabStripView;
+@class TabView;
+
+@interface TabWindowController : NSWindowController<NSWindowDelegate> {
+ @private
+ IBOutlet FastResizeView* tabContentArea_;
+ // TODO(pinkerton): Figure out a better way to initialize one or the other
+ // w/out needing both to be in the nib.
+ IBOutlet TabStripView* topTabStripView_;
+ IBOutlet TabStripView* sideTabStripView_;
+ NSWindow* overlayWindow_; // Used during dragging for window opacity tricks
+ NSView* cachedContentView_; // Used during dragging for identifying which
+ // view is the proper content area in the overlay
+ // (weak)
+ scoped_nsobject<FocusTracker> focusBeforeOverlay_;
+ scoped_nsobject<NSMutableSet> lockedTabs_;
+ BOOL closeDeferred_; // If YES, call performClose: in removeOverlay:.
+ // Difference between height of window content area and height of the
+ // |tabContentArea_|. Calculated when the window is loaded from the nib and
+ // cached in order to restore the delta when switching tab modes.
+ CGFloat contentAreaHeightDelta_;
+}
+@property(readonly, nonatomic) TabStripView* tabStripView;
+@property(readonly, nonatomic) FastResizeView* tabContentArea;
+
+// Used during tab dragging to turn on/off the overlay window when a tab
+// is torn off. If -deferPerformClose (below) is used, -removeOverlay will
+// cause the controller to be autoreleased before returning.
+- (void)showOverlay;
+- (void)removeOverlay;
+- (NSWindow*)overlayWindow;
+
+// Returns YES if it is ok to constrain the window's frame to fit the screen.
+- (BOOL)shouldConstrainFrameRect;
+
+// A collection of methods, stubbed out in this base class, that provide
+// the implementation of tab dragging based on whatever model is most
+// appropriate.
+
+// Layout the tabs based on the current ordering of the model.
+- (void)layoutTabs;
+
+// Creates a new window by pulling the given tab out and placing it in
+// the new window. Returns the controller for the new window. The size of the
+// new window will be the same size as this window.
+- (TabWindowController*)detachTabToNewWindow:(TabView*)tabView;
+
+// Make room in the tab strip for |tab| at the given x coordinate. Will hide the
+// new tab button while there's a placeholder. Subclasses need to call the
+// superclass implementation.
+- (void)insertPlaceholderForTab:(TabView*)tab
+ frame:(NSRect)frame
+ yStretchiness:(CGFloat)yStretchiness;
+
+// Removes the placeholder installed by |-insertPlaceholderForTab:atLocation:|
+// and restores the new tab button. Subclasses need to call the superclass
+// implementation.
+- (void)removePlaceholder;
+
+// Returns whether one of the window's tabs is being dragged.
+- (BOOL)isDragSessionActive;
+
+// The follow return YES if tab dragging/tab tearing (off the tab strip)/window
+// movement is currently allowed. Any number of things can choose to disable it,
+// such as pending animations. The default implementations always return YES.
+// Subclasses should override as appropriate.
+- (BOOL)tabDraggingAllowed;
+- (BOOL)tabTearingAllowed;
+- (BOOL)windowMovementAllowed;
+
+// Show or hide the new tab button. The button is hidden immediately, but
+// waits until the next call to |-layoutTabs| to show it again.
+- (void)showNewTabButton:(BOOL)show;
+
+// Returns whether or not |tab| can still be fully seen in the tab strip or if
+// its current position would cause it be obscured by things such as the edge
+// of the window or the window decorations. Returns YES only if the entire tab
+// is visible. The default implementation always returns YES.
+- (BOOL)isTabFullyVisible:(TabView*)tab;
+
+// Called to check if the receiver can receive dragged tabs from
+// source. Return YES if so. The default implementation returns NO.
+- (BOOL)canReceiveFrom:(TabWindowController*)source;
+
+// Move a given tab view to the location of the current placeholder. If there is
+// no placeholder, it will go at the end. |controller| is the window controller
+// of a tab being dropped from a different window. It will be nil if the drag is
+// within the window, otherwise the tab is removed from that window before being
+// placed into this one. The implementation will call |-removePlaceholder| since
+// the drag is now complete. This also calls |-layoutTabs| internally so
+// clients do not need to call it again.
+- (void)moveTabView:(NSView*)view
+ fromController:(TabWindowController*)controller;
+
+// Number of tabs in the tab strip. Useful, for example, to know if we're
+// dragging the only tab in the window. This includes pinned tabs (both live
+// and not).
+- (NSInteger)numberOfTabs;
+
+// YES if there are tabs in the tab strip which have content, allowing for
+// the notion of tabs in the tab strip that are placeholders but currently have
+// no content.
+- (BOOL)hasLiveTabs;
+
+// Return the view of the selected tab.
+- (NSView *)selectedTabView;
+
+// The title of the selected tab.
+- (NSString*)selectedTabTitle;
+
+// Called to check whether or not this controller's window has a tab strip (YES
+// if it does, NO otherwise). The default implementation returns YES.
+- (BOOL)hasTabStrip;
+
+// Returns YES if the tab strip lives in the window content area alongside the
+// tab contents. Returns NO if the tab strip is outside the window content
+// area, along the top of the window.
+- (BOOL)useVerticalTabs;
+
+// Get/set whether a particular tab is draggable between windows.
+- (BOOL)isTabDraggable:(NSView*)tabView;
+- (void)setTab:(NSView*)tabView isDraggable:(BOOL)draggable;
+
+// Tell the window that it needs to call performClose: as soon as the current
+// drag is complete. This prevents a window (and its overlay) from going away
+// during a drag.
+- (void)deferPerformClose;
+
+@end
+
+@interface TabWindowController(ProtectedMethods)
+// Tells the tab strip to forget about this tab in preparation for it being
+// put into a different tab strip, such as during a drop on another window.
+- (void)detachTabView:(NSView*)view;
+
+// Toggles from one display mode of the tab strip to another. Will automatically
+// call -layoutSubviews to reposition other content.
+- (void)toggleTabStripDisplayMode;
+
+// Called when the size of the window content area has changed. Override to
+// position specific views. Base class implementation does nothing.
+- (void)layoutSubviews;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_TAB_WINDOW_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/tab_window_controller.mm b/chrome/browser/ui/cocoa/tab_window_controller.mm
new file mode 100644
index 0000000..c3de82f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/tab_window_controller.mm
@@ -0,0 +1,356 @@
+// 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 "chrome/browser/ui/cocoa/tab_window_controller.h"
+
+#include "app/theme_provider.h"
+#include "base/logging.h"
+#import "chrome/browser/ui/cocoa/focus_tracker.h"
+#import "chrome/browser/ui/cocoa/tab_strip_view.h"
+#import "chrome/browser/ui/cocoa/themed_window.h"
+
+@interface TabWindowController(PRIVATE)
+- (void)setUseOverlay:(BOOL)useOverlay;
+@end
+
+@interface TabWindowOverlayWindow : NSWindow
+@end
+
+@implementation TabWindowOverlayWindow
+
+- (ThemeProvider*)themeProvider {
+ if ([self parentWindow])
+ return [[[self parentWindow] windowController] themeProvider];
+ return NULL;
+}
+
+- (ThemedWindowStyle)themedWindowStyle {
+ if ([self parentWindow])
+ return [[[self parentWindow] windowController] themedWindowStyle];
+ return NO;
+}
+
+- (NSPoint)themePatternPhase {
+ if ([self parentWindow])
+ return [[[self parentWindow] windowController] themePatternPhase];
+ return NSZeroPoint;
+}
+
+@end
+
+@implementation TabWindowController
+@synthesize tabContentArea = tabContentArea_;
+
+- (id)initWithWindow:(NSWindow*)window {
+ if ((self = [super initWithWindow:window]) != nil) {
+ lockedTabs_.reset([[NSMutableSet alloc] initWithCapacity:10]);
+ }
+ return self;
+}
+
+// Add the side tab strip to the left side of the window's content area,
+// making it fill the full height of the content area.
+- (void)addSideTabStripToWindow {
+ NSView* contentView = [[self window] contentView];
+ NSRect contentFrame = [contentView frame];
+ NSRect sideStripFrame =
+ NSMakeRect(0, 0,
+ NSWidth([sideTabStripView_ frame]),
+ NSHeight(contentFrame));
+ [sideTabStripView_ setFrame:sideStripFrame];
+ [contentView addSubview:sideTabStripView_];
+}
+
+// Add the top tab strop to the window, above the content box and add it to the
+// view hierarchy as a sibling of the content view so it can overlap with the
+// window frame.
+- (void)addTopTabStripToWindow {
+ NSRect contentFrame = [tabContentArea_ frame];
+ NSRect tabFrame =
+ NSMakeRect(0, NSMaxY(contentFrame),
+ NSWidth(contentFrame),
+ NSHeight([topTabStripView_ frame]));
+ [topTabStripView_ setFrame:tabFrame];
+ NSView* contentParent = [[[self window] contentView] superview];
+ [contentParent addSubview:topTabStripView_];
+}
+
+- (void)windowDidLoad {
+ // Cache the difference in height between the window content area and the
+ // tab content area.
+ NSRect tabFrame = [tabContentArea_ frame];
+ NSRect contentFrame = [[[self window] contentView] frame];
+ contentAreaHeightDelta_ = NSHeight(contentFrame) - NSHeight(tabFrame);
+
+ if ([self hasTabStrip]) {
+ if ([self useVerticalTabs]) {
+ // No top tabstrip so remove the tabContentArea offset.
+ tabFrame.size.height = contentFrame.size.height;
+ [tabContentArea_ setFrame:tabFrame];
+ [self addSideTabStripToWindow];
+ } else {
+ [self addTopTabStripToWindow];
+ }
+ } else {
+ // No top tabstrip so remove the tabContentArea offset.
+ tabFrame.size.height = contentFrame.size.height;
+ [tabContentArea_ setFrame:tabFrame];
+ }
+}
+
+// Toggles from one display mode of the tab strip to another. Will automatically
+// call -layoutSubviews to reposition other content.
+- (void)toggleTabStripDisplayMode {
+ // Adjust the size of the tab contents to either use more or less space,
+ // depending on the direction of the toggle. This needs to be done prior to
+ // adding back in the top tab strip as its position is based off the MaxY
+ // of the tab content area.
+ BOOL useVertical = [self useVerticalTabs];
+ NSRect tabContentsFrame = [tabContentArea_ frame];
+ tabContentsFrame.size.height += useVertical ?
+ contentAreaHeightDelta_ : -contentAreaHeightDelta_;
+ [tabContentArea_ setFrame:tabContentsFrame];
+
+ if (useVertical) {
+ // Remove the top tab strip and add the sidebar in.
+ [topTabStripView_ removeFromSuperview];
+ [self addSideTabStripToWindow];
+ } else {
+ // Remove the side tab strip and add the top tab strip as a sibling of the
+ // window's content area.
+ [sideTabStripView_ removeFromSuperview];
+ NSRect tabContentsFrame = [tabContentArea_ frame];
+ tabContentsFrame.size.height -= contentAreaHeightDelta_;
+ [tabContentArea_ setFrame:tabContentsFrame];
+ [self addTopTabStripToWindow];
+ }
+
+ [self layoutSubviews];
+}
+
+// Return the appropriate tab strip based on whether or not side tabs are
+// enabled.
+- (TabStripView*)tabStripView {
+ if ([self useVerticalTabs])
+ return sideTabStripView_;
+ return topTabStripView_;
+}
+
+- (void)removeOverlay {
+ [self setUseOverlay:NO];
+ if (closeDeferred_) {
+ // See comment in BrowserWindowCocoa::Close() about orderOut:.
+ [[self window] orderOut:self];
+ [[self window] performClose:self]; // Autoreleases the controller.
+ }
+}
+
+- (void)showOverlay {
+ [self setUseOverlay:YES];
+}
+
+// if |useOverlay| is true, we're moving views into the overlay's content
+// area. If false, we're moving out of the overlay back into the window's
+// content.
+- (void)moveViewsBetweenWindowAndOverlay:(BOOL)useOverlay {
+ if (useOverlay) {
+ [[[overlayWindow_ contentView] superview] addSubview:[self tabStripView]];
+ // Add the original window's content view as a subview of the overlay
+ // window's content view. We cannot simply use setContentView: here because
+ // the overlay window has a different content size (due to it being
+ // borderless).
+ [[overlayWindow_ contentView] addSubview:cachedContentView_];
+ } else {
+ [[self window] setContentView:cachedContentView_];
+ // The TabStripView always needs to be in front of the window's content
+ // view and therefore it should always be added after the content view is
+ // set.
+ [[[[self window] contentView] superview] addSubview:[self tabStripView]];
+ [[[[self window] contentView] superview] updateTrackingAreas];
+ }
+}
+
+// If |useOverlay| is YES, creates a new overlay window and puts the tab strip
+// and the content area inside of it. This allows it to have a different opacity
+// from the title bar. If NO, returns everything to the previous state and
+// destroys the overlay window until it's needed again. The tab strip and window
+// contents are returned to the original window.
+- (void)setUseOverlay:(BOOL)useOverlay {
+ [NSObject cancelPreviousPerformRequestsWithTarget:self
+ selector:@selector(removeOverlay)
+ object:nil];
+ NSWindow* window = [self window];
+ if (useOverlay && !overlayWindow_) {
+ DCHECK(!cachedContentView_);
+ overlayWindow_ = [[TabWindowOverlayWindow alloc]
+ initWithContentRect:[window frame]
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:YES];
+ [overlayWindow_ setTitle:@"overlay"];
+ [overlayWindow_ setBackgroundColor:[NSColor clearColor]];
+ [overlayWindow_ setOpaque:NO];
+ [overlayWindow_ setDelegate:self];
+ cachedContentView_ = [window contentView];
+ [window addChildWindow:overlayWindow_ ordered:NSWindowAbove];
+ // Sets explictly nil to the responder and then restores it.
+ // Leaving the first responder non-null here
+ // causes [RenderWidgethostViewCocoa resignFirstResponder] and
+ // following RenderWidgetHost::Blur(), which results unexpected
+ // focus lost.
+ focusBeforeOverlay_.reset([[FocusTracker alloc] initWithWindow:window]);
+ [window makeFirstResponder:nil];
+ [self moveViewsBetweenWindowAndOverlay:useOverlay];
+ [overlayWindow_ orderFront:nil];
+ } else if (!useOverlay && overlayWindow_) {
+ DCHECK(cachedContentView_);
+ [window setContentView:cachedContentView_];
+ [self moveViewsBetweenWindowAndOverlay:useOverlay];
+ [focusBeforeOverlay_ restoreFocusInWindow:window];
+ focusBeforeOverlay_.reset(nil);
+ [window display];
+ [window removeChildWindow:overlayWindow_];
+ [overlayWindow_ orderOut:nil];
+ [overlayWindow_ release];
+ overlayWindow_ = nil;
+ cachedContentView_ = nil;
+ } else {
+ NOTREACHED();
+ }
+}
+
+- (NSWindow*)overlayWindow {
+ return overlayWindow_;
+}
+
+- (BOOL)shouldConstrainFrameRect {
+ // If we currently have an overlay window, do not attempt to change the
+ // window's size, as our overlay window doesn't know how to resize properly.
+ return overlayWindow_ == nil;
+}
+
+- (BOOL)canReceiveFrom:(TabWindowController*)source {
+ // subclass must implement
+ NOTIMPLEMENTED();
+ return NO;
+}
+
+- (void)moveTabView:(NSView*)view
+ fromController:(TabWindowController*)dragController {
+ NOTIMPLEMENTED();
+}
+
+- (NSView*)selectedTabView {
+ NOTIMPLEMENTED();
+ return nil;
+}
+
+- (void)layoutTabs {
+ // subclass must implement
+ NOTIMPLEMENTED();
+}
+
+- (TabWindowController*)detachTabToNewWindow:(TabView*)tabView {
+ // subclass must implement
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+- (void)insertPlaceholderForTab:(TabView*)tab
+ frame:(NSRect)frame
+ yStretchiness:(CGFloat)yStretchiness {
+ [self showNewTabButton:NO];
+}
+
+- (void)removePlaceholder {
+ [self showNewTabButton:YES];
+}
+
+- (BOOL)isDragSessionActive {
+ NOTIMPLEMENTED();
+ return NO;
+}
+
+- (BOOL)tabDraggingAllowed {
+ return YES;
+}
+
+- (BOOL)tabTearingAllowed {
+ return YES;
+}
+
+- (BOOL)windowMovementAllowed {
+ return YES;
+}
+
+- (BOOL)isTabFullyVisible:(TabView*)tab {
+ // Subclasses should implement this, but it's not necessary.
+ return YES;
+}
+
+- (void)showNewTabButton:(BOOL)show {
+ // subclass must implement
+ NOTIMPLEMENTED();
+}
+
+- (void)detachTabView:(NSView*)view {
+ // subclass must implement
+ NOTIMPLEMENTED();
+}
+
+- (NSInteger)numberOfTabs {
+ // subclass must implement
+ NOTIMPLEMENTED();
+ return 0;
+}
+
+- (BOOL)hasLiveTabs {
+ // subclass must implement
+ NOTIMPLEMENTED();
+ return NO;
+}
+
+- (NSString*)selectedTabTitle {
+ // subclass must implement
+ NOTIMPLEMENTED();
+ return @"";
+}
+
+- (BOOL)hasTabStrip {
+ // Subclasses should implement this.
+ NOTIMPLEMENTED();
+ return YES;
+}
+
+- (BOOL)useVerticalTabs {
+ // Subclasses should implement this.
+ NOTIMPLEMENTED();
+ return NO;
+}
+
+- (BOOL)isTabDraggable:(NSView*)tabView {
+ return ![lockedTabs_ containsObject:tabView];
+}
+
+- (void)setTab:(NSView*)tabView isDraggable:(BOOL)draggable {
+ if (draggable)
+ [lockedTabs_ removeObject:tabView];
+ else
+ [lockedTabs_ addObject:tabView];
+}
+
+// Tell the window that it needs to call performClose: as soon as the current
+// drag is complete. This prevents a window (and its overlay) from going away
+// during a drag.
+- (void)deferPerformClose {
+ closeDeferred_ = YES;
+}
+
+// Called when the size of the window content area has changed. Override to
+// position specific views. Base class implementation does nothing.
+- (void)layoutSubviews {
+ NOTIMPLEMENTED();
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/table_model_array_controller.h b/chrome/browser/ui/cocoa/table_model_array_controller.h
new file mode 100644
index 0000000..b9b227e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/table_model_array_controller.h
@@ -0,0 +1,54 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_TABLE_MODEL_ARRAY_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_TABLE_MODEL_ARRAY_CONTROLLER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "app/table_model_observer.h"
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+
+class RemoveRowsObserverBridge;
+class RemoveRowsTableModel;
+@class TableModelArrayController;
+
+// This class functions as an adapter from a RemoveRowsTableModel to a Cocoa
+// NSArrayController, to be used with bindings.
+// It maps the CanRemoveRows method to its canRemove property, and exposes
+// RemoveRows and RemoveAll as actions (remove: and removeAll:).
+// If the table model has groups, these are inserted into the list of arranged
+// objects as group rows.
+// The designated initializer is the same as for NSArrayController,
+// initWithContent:, but usually this class is instantiated from a nib file.
+// Clicking on a group row selects all rows belonging to that group, like it
+// does in a Windows table_view.
+// In order to show group rows, this class must be the delegate of the
+// NSTableView.
+@interface TableModelArrayController : NSArrayController<NSTableViewDelegate> {
+ @private
+ RemoveRowsTableModel* model_; // weak
+ scoped_ptr<RemoveRowsObserverBridge> tableObserver_;
+ scoped_nsobject<NSDictionary> columns_;
+ scoped_nsobject<NSString> groupTitle_;
+}
+
+// Bind this controller to the given model.
+// |columns| is a dictionary mapping table column bindings to NSNumbers
+// containing the column identifier in the TableModel.
+// |groupTitleColumn| is the column in the table that should display the group
+// title for a group row, usually the first column. If the model doesn't have
+// groups, it can be nil.
+- (void)bindToTableModel:(RemoveRowsTableModel*)model
+ withColumns:(NSDictionary*)columns
+ groupTitleColumn:(NSString*)groupTitleColumn;
+
+- (IBAction)removeAll:(id)sender;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_TABLE_MODEL_ARRAY_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/table_model_array_controller.mm b/chrome/browser/ui/cocoa/table_model_array_controller.mm
new file mode 100644
index 0000000..e732127
--- /dev/null
+++ b/chrome/browser/ui/cocoa/table_model_array_controller.mm
@@ -0,0 +1,246 @@
+// 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 "chrome/browser/ui/cocoa/table_model_array_controller.h"
+
+#include "app/table_model.h"
+#include "base/logging.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/remove_rows_table_model.h"
+
+@interface TableModelArrayController (PrivateMethods)
+
+- (NSUInteger)offsetForGroupID:(int)groupID;
+- (NSUInteger)offsetForGroupID:(int)groupID startingOffset:(NSUInteger)offset;
+- (NSIndexSet*)controllerRowsForModelRowsInRange:(NSRange)range;
+- (void)setModelRows:(RemoveRowsTableModel::Rows*)modelRows
+ fromControllerRows:(NSIndexSet*)rows;
+- (void)modelDidChange;
+- (void)modelDidAddItemsInRange:(NSRange)range;
+- (void)modelDidRemoveItemsInRange:(NSRange)range;
+- (NSDictionary*)columnValuesForRow:(NSInteger)row;
+
+@end
+
+// Observer for a RemoveRowsTableModel.
+class RemoveRowsObserverBridge : public TableModelObserver {
+ public:
+ RemoveRowsObserverBridge(TableModelArrayController* controller)
+ : controller_(controller) {}
+ virtual ~RemoveRowsObserverBridge() {}
+
+ // TableModelObserver methods
+ virtual void OnModelChanged();
+ virtual void OnItemsChanged(int start, int length);
+ virtual void OnItemsAdded(int start, int length);
+ virtual void OnItemsRemoved(int start, int length);
+
+ private:
+ TableModelArrayController* controller_; // weak
+};
+
+void RemoveRowsObserverBridge::OnModelChanged() {
+ [controller_ modelDidChange];
+}
+
+void RemoveRowsObserverBridge::OnItemsChanged(int start, int length) {
+ OnItemsRemoved(start, length);
+ OnItemsAdded(start, length);
+}
+
+void RemoveRowsObserverBridge::OnItemsAdded(int start, int length) {
+ [controller_ modelDidAddItemsInRange:NSMakeRange(start, length)];
+}
+
+void RemoveRowsObserverBridge::OnItemsRemoved(int start, int length) {
+ [controller_ modelDidRemoveItemsInRange:NSMakeRange(start, length)];
+}
+
+@implementation TableModelArrayController
+
+static NSString* const kIsGroupRow = @"_is_group_row";
+static NSString* const kGroupID = @"_group_id";
+
+- (void)bindToTableModel:(RemoveRowsTableModel*)model
+ withColumns:(NSDictionary*)columns
+ groupTitleColumn:(NSString*)groupTitleColumn {
+ model_ = model;
+ tableObserver_.reset(new RemoveRowsObserverBridge(self));
+ columns_.reset([columns copy]);
+ groupTitle_.reset([groupTitleColumn copy]);
+ model_->SetObserver(tableObserver_.get());
+ [self modelDidChange];
+}
+
+- (void)modelDidChange {
+ NSIndexSet* indexes = [NSIndexSet indexSetWithIndexesInRange:
+ NSMakeRange(0, [[self arrangedObjects] count])];
+ [self removeObjectsAtArrangedObjectIndexes:indexes];
+ if (model_->HasGroups()) {
+ const TableModel::Groups& groups = model_->GetGroups();
+ DCHECK(groupTitle_.get());
+ for (TableModel::Groups::const_iterator it = groups.begin();
+ it != groups.end(); ++it) {
+ NSDictionary* group = [NSDictionary dictionaryWithObjectsAndKeys:
+ base::SysWideToNSString(it->title), groupTitle_.get(),
+ [NSNumber numberWithBool:YES], kIsGroupRow,
+ nil];
+ [self addObject:group];
+ }
+ }
+ [self modelDidAddItemsInRange:NSMakeRange(0, model_->RowCount())];
+}
+
+- (NSUInteger)offsetForGroupID:(int)groupID startingOffset:(NSUInteger)offset {
+ const TableModel::Groups& groups = model_->GetGroups();
+ DCHECK_GT(offset, 0u);
+ for (NSUInteger i = offset - 1; i < groups.size(); ++i) {
+ if (groups[i].id == groupID)
+ return i + 1;
+ }
+ NOTREACHED();
+ return NSNotFound;
+}
+
+- (NSUInteger)offsetForGroupID:(int)groupID {
+ return [self offsetForGroupID:groupID startingOffset:1];
+}
+
+- (int)groupIDForControllerRow:(NSUInteger)row {
+ NSDictionary* values = [[self arrangedObjects] objectAtIndex:row];
+ return [[values objectForKey:kGroupID] intValue];
+}
+
+- (void)setModelRows:(RemoveRowsTableModel::Rows*)modelRows
+ fromControllerRows:(NSIndexSet*)rows {
+ if ([rows count] == 0)
+ return;
+
+ if (!model_->HasGroups()) {
+ for (NSUInteger i = [rows firstIndex];
+ i != NSNotFound;
+ i = [rows indexGreaterThanIndex:i]) {
+ modelRows->insert(i);
+ }
+ return;
+ }
+
+ NSUInteger offset = 1;
+ for (NSUInteger i = [rows firstIndex];
+ i != NSNotFound;
+ i = [rows indexGreaterThanIndex:i]) {
+ int group = [self groupIDForControllerRow:i];
+ offset = [self offsetForGroupID:group startingOffset:offset];
+ modelRows->insert(i - offset);
+ }
+}
+
+- (NSIndexSet*)controllerRowsForModelRowsInRange:(NSRange)range {
+ if (!model_->HasGroups())
+ return [NSIndexSet indexSetWithIndexesInRange:range];
+ NSMutableIndexSet* indexes = [NSMutableIndexSet indexSet];
+ NSUInteger offset = 1;
+ for (NSUInteger i = range.location; i < NSMaxRange(range); ++i) {
+ int group = model_->GetGroupID(i);
+ offset = [self offsetForGroupID:group startingOffset:offset];
+ [indexes addIndex:i + offset];
+ }
+ return indexes;
+}
+
+- (void)modelDidAddItemsInRange:(NSRange)range {
+ NSMutableArray* rows = [NSMutableArray arrayWithCapacity:range.length];
+ for (NSUInteger i=range.location; i<NSMaxRange(range); ++i)
+ [rows addObject:[self columnValuesForRow:i]];
+ [self insertObjects:rows
+ atArrangedObjectIndexes:[self controllerRowsForModelRowsInRange:range]];
+}
+
+- (void)modelDidRemoveItemsInRange:(NSRange)range {
+ NSMutableIndexSet* indexes =
+ [NSMutableIndexSet indexSetWithIndexesInRange:range];
+ if (model_->HasGroups()) {
+ // When this method is called, the model has already removed items, so
+ // accessing items in the model from |range.location| on may not be possible
+ // anymore. Therefore we use the item right before that, if it exists.
+ NSUInteger offset = 0;
+ if (range.location > 0) {
+ int last_group = model_->GetGroupID(range.location - 1);
+ offset = [self offsetForGroupID:last_group];
+ }
+ [indexes shiftIndexesStartingAtIndex:0 by:offset];
+ for (NSUInteger row = range.location + offset;
+ row < NSMaxRange(range) + offset;
+ ++row) {
+ if ([self tableView:nil isGroupRow:row]) {
+ // Skip over group rows.
+ [indexes shiftIndexesStartingAtIndex:row by:1];
+ offset++;
+ }
+ }
+ }
+ [self removeObjectsAtArrangedObjectIndexes:indexes];
+}
+
+- (NSDictionary*)columnValuesForRow:(NSInteger)row {
+ NSMutableDictionary* dict = [NSMutableDictionary dictionary];
+ if (model_->HasGroups()) {
+ [dict setObject:[NSNumber numberWithInt:model_->GetGroupID(row)]
+ forKey:kGroupID];
+ }
+ for (NSString* identifier in columns_.get()) {
+ int column_id = [[columns_ objectForKey:identifier] intValue];
+ std::wstring text = model_->GetText(row, column_id);
+ [dict setObject:base::SysWideToNSString(text) forKey:identifier];
+ }
+ return dict;
+}
+
+// Overridden from NSArrayController -----------------------------------------
+
+- (BOOL)canRemove {
+ if (!model_)
+ return NO;
+ RemoveRowsTableModel::Rows rows;
+ [self setModelRows:&rows fromControllerRows:[self selectionIndexes]];
+ return model_->CanRemoveRows(rows);
+}
+
+- (IBAction)remove:(id)sender {
+ RemoveRowsTableModel::Rows rows;
+ [self setModelRows:&rows fromControllerRows:[self selectionIndexes]];
+ model_->RemoveRows(rows);
+}
+
+// Table View Delegate --------------------------------------------------------
+
+- (BOOL)tableView:(NSTableView*)tv isGroupRow:(NSInteger)row {
+ NSDictionary* values = [[self arrangedObjects] objectAtIndex:row];
+ return [[values objectForKey:kIsGroupRow] boolValue];
+}
+
+- (NSIndexSet*)tableView:(NSTableView*)tableView
+ selectionIndexesForProposedSelection:(NSIndexSet*)proposedIndexes {
+ NSMutableIndexSet* indexes = [proposedIndexes mutableCopy];
+ for (NSUInteger i = [proposedIndexes firstIndex];
+ i != NSNotFound;
+ i = [proposedIndexes indexGreaterThanIndex:i]) {
+ if ([self tableView:tableView isGroupRow:i]) {
+ [indexes removeIndex:i];
+ NSUInteger row = i + 1;
+ while (row < [[self arrangedObjects] count] &&
+ ![self tableView:tableView isGroupRow:row])
+ [indexes addIndex:row++];
+ }
+ }
+ return indexes;
+}
+
+// Actions --------------------------------------------------------------------
+
+- (IBAction)removeAll:(id)sender {
+ model_->RemoveAll();
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/table_model_array_controller_unittest.mm b/chrome/browser/ui/cocoa/table_model_array_controller_unittest.mm
new file mode 100644
index 0000000..746d8a1
--- /dev/null
+++ b/chrome/browser/ui/cocoa/table_model_array_controller_unittest.mm
@@ -0,0 +1,171 @@
+// 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 "chrome/browser/ui/cocoa/table_model_array_controller.h"
+
+#include "base/auto_reset.h"
+#include "base/command_line.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/mock_plugin_exceptions_table_model.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/testing_profile.h"
+#include "grit/generated_resources.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gtest_mac.h"
+#include "webkit/plugins/npapi/plugin_list.h"
+#include "webkit/plugins/npapi/webplugininfo.h"
+
+class TableModelArrayControllerTest : public CocoaTest {
+ public:
+ TableModelArrayControllerTest()
+ : command_line_(CommandLine::ForCurrentProcess(),
+ *CommandLine::ForCurrentProcess()) {}
+
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableResourceContentSettings);
+
+ TestingProfile* profile = browser_helper_.profile();
+ HostContentSettingsMap* map = profile->GetHostContentSettingsMap();
+
+ ContentSettingsPattern example_com("[*.]example.com");
+ ContentSettingsPattern moose_org("[*.]moose.org");
+ map->SetContentSetting(example_com,
+ CONTENT_SETTINGS_TYPE_PLUGINS,
+ "a-foo",
+ CONTENT_SETTING_ALLOW);
+ map->SetContentSetting(moose_org,
+ CONTENT_SETTINGS_TYPE_PLUGINS,
+ "b-bar",
+ CONTENT_SETTING_BLOCK);
+ map->SetContentSetting(example_com,
+ CONTENT_SETTINGS_TYPE_PLUGINS,
+ "b-bar",
+ CONTENT_SETTING_ALLOW);
+
+ model_.reset(new MockPluginExceptionsTableModel(map, NULL));
+
+ std::vector<webkit::npapi::PluginGroup> plugins;
+ webkit::npapi::WebPluginInfo foo_plugin;
+ foo_plugin.path = FilePath(FILE_PATH_LITERAL("a-foo"));
+ foo_plugin.name = ASCIIToUTF16("FooPlugin");
+ foo_plugin.enabled = true;
+ scoped_ptr<webkit::npapi::PluginGroup> foo_group(
+ webkit::npapi::PluginGroup::FromWebPluginInfo(foo_plugin));
+ plugins.push_back(*foo_group);
+ webkit::npapi::WebPluginInfo bar_plugin;
+ bar_plugin.path = FilePath(FILE_PATH_LITERAL("b-bar"));
+ bar_plugin.name = ASCIIToUTF16("BarPlugin");
+ bar_plugin.enabled = true;
+ scoped_ptr<webkit::npapi::PluginGroup> bar_group(
+ webkit::npapi::PluginGroup::FromWebPluginInfo(bar_plugin));
+ plugins.push_back(*bar_group);
+ webkit::npapi::WebPluginInfo blurp_plugin;
+ blurp_plugin.path = FilePath(FILE_PATH_LITERAL("c-blurp"));
+ blurp_plugin.name = ASCIIToUTF16("BlurpPlugin");
+ blurp_plugin.enabled = true;
+ scoped_ptr<webkit::npapi::PluginGroup> blurp_group(
+ webkit::npapi::PluginGroup::FromWebPluginInfo(blurp_plugin));
+ plugins.push_back(*blurp_group);
+
+ model_->set_plugins(plugins);
+ model_->LoadSettings();
+
+ id content = [NSMutableArray array];
+ controller_.reset(
+ [[TableModelArrayController alloc] initWithContent:content]);
+ NSDictionary* columns = [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSNumber numberWithInt:IDS_EXCEPTIONS_HOSTNAME_HEADER], @"title",
+ [NSNumber numberWithInt:IDS_EXCEPTIONS_ACTION_HEADER], @"action",
+ nil];
+ [controller_.get() bindToTableModel:model_.get()
+ withColumns:columns
+ groupTitleColumn:@"title"];
+ }
+
+ protected:
+ BrowserTestHelper browser_helper_;
+ scoped_ptr<MockPluginExceptionsTableModel> model_;
+ scoped_nsobject<TableModelArrayController> controller_;
+
+ private:
+ AutoReset<CommandLine> command_line_;
+};
+
+TEST_F(TableModelArrayControllerTest, CheckTitles) {
+ NSArray* titles = [[controller_.get() arrangedObjects] valueForKey:@"title"];
+ EXPECT_NSEQ(@"(\n"
+ @" FooPlugin,\n"
+ @" \"[*.]example.com\",\n"
+ @" BarPlugin,\n"
+ @" \"[*.]example.com\",\n"
+ @" \"[*.]moose.org\"\n"
+ @")",
+ [titles description]);
+}
+
+TEST_F(TableModelArrayControllerTest, RemoveRows) {
+ NSArrayController* controller = controller_.get();
+ [controller setSelectionIndex:1];
+ [controller remove:nil];
+ NSArray* titles = [[controller arrangedObjects] valueForKey:@"title"];
+ EXPECT_NSEQ(@"(\n"
+ @" BarPlugin,\n"
+ @" \"[*.]example.com\",\n"
+ @" \"[*.]moose.org\"\n"
+ @")",
+ [titles description]);
+
+ [controller setSelectionIndex:2];
+ [controller remove:nil];
+ titles = [[controller arrangedObjects] valueForKey:@"title"];
+ EXPECT_NSEQ(@"(\n"
+ @" BarPlugin,\n"
+ @" \"[*.]example.com\"\n"
+ @")",
+ [titles description]);
+}
+
+TEST_F(TableModelArrayControllerTest, RemoveAll) {
+ [controller_.get() removeAll:nil];
+ EXPECT_EQ(0u, [[controller_.get() arrangedObjects] count]);
+}
+
+TEST_F(TableModelArrayControllerTest, AddException) {
+ TestingProfile* profile = browser_helper_.profile();
+ HostContentSettingsMap* map = profile->GetHostContentSettingsMap();
+ ContentSettingsPattern example_com("[*.]example.com");
+ map->SetContentSetting(example_com,
+ CONTENT_SETTINGS_TYPE_PLUGINS,
+ "c-blurp",
+ CONTENT_SETTING_BLOCK);
+
+ NSArrayController* controller = controller_.get();
+ NSArray* titles = [[controller arrangedObjects] valueForKey:@"title"];
+ EXPECT_NSEQ(@"(\n"
+ @" FooPlugin,\n"
+ @" \"[*.]example.com\",\n"
+ @" BarPlugin,\n"
+ @" \"[*.]example.com\",\n"
+ @" \"[*.]moose.org\",\n"
+ @" BlurpPlugin,\n"
+ @" \"[*.]example.com\"\n"
+ @")",
+ [titles description]);
+ NSMutableIndexSet* indexes = [NSMutableIndexSet indexSetWithIndex:1];
+ [indexes addIndex:6];
+ [controller setSelectionIndexes:indexes];
+ [controller remove:nil];
+ titles = [[controller arrangedObjects] valueForKey:@"title"];
+ EXPECT_NSEQ(@"(\n"
+ @" BarPlugin,\n"
+ @" \"[*.]example.com\",\n"
+ @" \"[*.]moose.org\"\n"
+ @")",
+ [titles description]);
+}
diff --git a/chrome/browser/ui/cocoa/table_row_nsimage_cache.h b/chrome/browser/ui/cocoa/table_row_nsimage_cache.h
new file mode 100644
index 0000000..c42107f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/table_row_nsimage_cache.h
@@ -0,0 +1,55 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_TABLE_ROW_NSIMAGE_CACHE_H_
+#define CHROME_BROWSER_UI_COCOA_TABLE_ROW_NSIMAGE_CACHE_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+
+class SkBitmap;
+
+// There are several dialogs that display tabular data with one SkBitmap
+// per row. This class converts these SkBitmaps to NSImages on demand, and
+// caches the results.
+class TableRowNSImageCache {
+ public:
+ // Interface this cache expects for its table model.
+ class Table {
+ public:
+ // Returns the number of rows in the table.
+ virtual int RowCount() const = 0;
+
+ // Returns the icon of the |row|th row.
+ virtual SkBitmap GetIcon(int row) const = 0;
+
+ protected:
+ virtual ~Table() {}
+ };
+
+ // |model| must outlive the cache.
+ explicit TableRowNSImageCache(Table* model);
+
+ // Lazily converts the image at the given row and caches it in |icon_images_|.
+ NSImage* GetImageForRow(int row);
+
+ // Call these functions every time the table changes, to update the cache.
+ void OnModelChanged();
+ void OnItemsChanged(int start, int length);
+ void OnItemsAdded(int start, int length);
+ void OnItemsRemoved(int start, int length);
+
+ private:
+ // The table model we query for row count and icons.
+ Table* model_; // weak
+
+ // Stores strong NSImage refs for icons. If an entry is NULL, it will be
+ // created in GetImageForRow().
+ scoped_nsobject<NSPointerArray> icon_images_;
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_TABLE_ROW_NSIMAGE_CACHE_H_
+
diff --git a/chrome/browser/ui/cocoa/table_row_nsimage_cache.mm b/chrome/browser/ui/cocoa/table_row_nsimage_cache.mm
new file mode 100644
index 0000000..ae60dd6
--- /dev/null
+++ b/chrome/browser/ui/cocoa/table_row_nsimage_cache.mm
@@ -0,0 +1,79 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/table_row_nsimage_cache.h"
+
+#include "base/logging.h"
+#include "skia/ext/skia_utils_mac.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+TableRowNSImageCache::TableRowNSImageCache(Table* model)
+ : model_(model),
+ icon_images_([[NSPointerArray alloc] initWithOptions:
+ NSPointerFunctionsStrongMemory |
+ NSPointerFunctionsObjectPersonality]) {
+ int count = model_->RowCount();
+ [icon_images_ setCount:count];
+}
+
+void TableRowNSImageCache::OnModelChanged() {
+ int count = model_->RowCount();
+ [icon_images_ setCount:0];
+ [icon_images_ setCount:count];
+}
+
+void TableRowNSImageCache::OnItemsChanged(int start, int length) {
+ DCHECK_LE(start + length, static_cast<int>([icon_images_ count]));
+ for (int i = start; i < (start + length); ++i) {
+ [icon_images_ replacePointerAtIndex:i withPointer:NULL];
+ }
+ DCHECK_EQ(model_->RowCount(),
+ static_cast<int>([icon_images_ count]));
+}
+
+void TableRowNSImageCache::OnItemsAdded(int start, int length) {
+ DCHECK_LE(start, static_cast<int>([icon_images_ count]));
+
+ // -[NSPointerArray insertPointer:atIndex:] throws if index == count.
+ // Instead expand the array with NULLs.
+ if (start == static_cast<int>([icon_images_ count])) {
+ [icon_images_ setCount:start + length];
+ } else {
+ for (int i = 0; i < length; ++i) {
+ [icon_images_ insertPointer:NULL atIndex:start]; // Values slide up.
+ }
+ }
+ DCHECK_EQ(model_->RowCount(),
+ static_cast<int>([icon_images_ count]));
+}
+
+void TableRowNSImageCache::OnItemsRemoved(int start, int length) {
+ DCHECK_LE(start + length, static_cast<int>([icon_images_ count]));
+ for (int i = 0; i < length; ++i) {
+ [icon_images_ removePointerAtIndex:start]; // Values slide down.
+ }
+ DCHECK_EQ(model_->RowCount(),
+ static_cast<int>([icon_images_ count]));
+}
+
+NSImage* TableRowNSImageCache::GetImageForRow(int row) {
+ DCHECK_EQ(model_->RowCount(),
+ static_cast<int>([icon_images_ count]));
+ DCHECK_GE(row, 0);
+ DCHECK_LT(row, static_cast<int>([icon_images_ count]));
+ NSImage* image = static_cast<NSImage*>([icon_images_ pointerAtIndex:row]);
+ if (!image) {
+ const SkBitmap bitmap_icon =
+ model_->GetIcon(row);
+ // This means GetIcon() will get called until it returns a non-empty bitmap.
+ // Empty bitmaps are intentionally not cached.
+ if (!bitmap_icon.isNull()) {
+ image = gfx::SkBitmapToNSImage(bitmap_icon);
+ DCHECK(image);
+ [icon_images_ replacePointerAtIndex:row withPointer:image];
+ }
+ }
+ return image;
+}
+
diff --git a/chrome/browser/ui/cocoa/table_row_nsimage_cache_unittest.mm b/chrome/browser/ui/cocoa/table_row_nsimage_cache_unittest.mm
new file mode 100644
index 0000000..ecca71e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/table_row_nsimage_cache_unittest.mm
@@ -0,0 +1,200 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/table_row_nsimage_cache.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace {
+
+class TestTable : public TableRowNSImageCache::Table {
+ public:
+
+ std::vector<SkBitmap>* rows() {
+ return &rows_;
+ }
+
+ // TableRowNSImageCache::Table overrides.
+ virtual int RowCount() const {
+ return rows_.size();
+ }
+ virtual SkBitmap GetIcon(int index) const {
+ return rows_[index];
+ }
+
+ private:
+ std::vector<SkBitmap> rows_;
+};
+
+SkBitmap MakeImage(int width, int height) {
+ SkBitmap image;
+ image.setConfig(SkBitmap::kARGB_8888_Config, width, height);
+ EXPECT_TRUE(image.allocPixels());
+ image.eraseRGB(255, 0, 0);
+ return image;
+}
+
+// Define this as a macro so that the original variable names can be used in
+// test output.
+#define COMPARE_SK_NS_IMG_SIZES(skia, cocoa) \
+ EXPECT_EQ(skia.width(), [cocoa size].width); \
+ EXPECT_EQ(skia.height(), [cocoa size].height);
+
+TEST(TableRowNSImageCacheTest, ModelChanged) {
+ TestTable table;
+ std::vector<SkBitmap>* rows = table.rows();
+ rows->push_back(MakeImage(10, 10));
+ rows->push_back(MakeImage(20, 20));
+ rows->push_back(MakeImage(30, 30));
+ TableRowNSImageCache cache(&table);
+
+ NSImage* image0 = cache.GetImageForRow(0);
+ NSImage* image1 = cache.GetImageForRow(1);
+ NSImage* image2 = cache.GetImageForRow(2);
+
+ COMPARE_SK_NS_IMG_SIZES(rows->at(0), image0);
+ COMPARE_SK_NS_IMG_SIZES(rows->at(1), image1);
+ COMPARE_SK_NS_IMG_SIZES(rows->at(2), image2);
+
+ rows->clear();
+
+ rows->push_back(MakeImage(15, 15));
+ rows->push_back(MakeImage(25, 25));
+ rows->push_back(MakeImage(35, 35));
+ rows->push_back(MakeImage(45, 45));
+
+ // Invalidate the entire model.
+ cache.OnModelChanged();
+
+ EXPECT_NE(image0, cache.GetImageForRow(0));
+ image0 = cache.GetImageForRow(0);
+
+ EXPECT_NE(image1, cache.GetImageForRow(1));
+ image1 = cache.GetImageForRow(1);
+
+ EXPECT_NE(image2, cache.GetImageForRow(2));
+ image2 = cache.GetImageForRow(2);
+
+ NSImage* image3 = cache.GetImageForRow(3);
+
+ COMPARE_SK_NS_IMG_SIZES(rows->at(0), image0);
+ COMPARE_SK_NS_IMG_SIZES(rows->at(1), image1);
+ COMPARE_SK_NS_IMG_SIZES(rows->at(2), image2);
+ COMPARE_SK_NS_IMG_SIZES(rows->at(3), image3);
+}
+
+
+TEST(TableRowNSImageCacheTest, ItemsChanged) {
+ TestTable table;
+ std::vector<SkBitmap>* rows = table.rows();
+ rows->push_back(MakeImage(10, 10));
+ rows->push_back(MakeImage(20, 20));
+ rows->push_back(MakeImage(30, 30));
+ TableRowNSImageCache cache(&table);
+
+ NSImage* image0 = cache.GetImageForRow(0);
+ NSImage* image1 = cache.GetImageForRow(1);
+ NSImage* image2 = cache.GetImageForRow(2);
+
+ COMPARE_SK_NS_IMG_SIZES(rows->at(0), image0);
+ COMPARE_SK_NS_IMG_SIZES(rows->at(1), image1);
+ COMPARE_SK_NS_IMG_SIZES(rows->at(2), image2);
+
+ // Update the middle image.
+ (*rows)[1] = MakeImage(25, 25);
+ cache.OnItemsChanged(/* start=*/1, /* count=*/1);
+
+ // Make sure the other items remained the same.
+ EXPECT_EQ(image0, cache.GetImageForRow(0));
+ EXPECT_EQ(image2, cache.GetImageForRow(2));
+
+ image1 = cache.GetImageForRow(1);
+ COMPARE_SK_NS_IMG_SIZES(rows->at(1), image1);
+
+ // Update more than one image.
+ (*rows)[0] = MakeImage(15, 15);
+ (*rows)[1] = MakeImage(27, 27);
+ EXPECT_EQ(3U, rows->size());
+ cache.OnItemsChanged(0, 2);
+
+ image0 = cache.GetImageForRow(0);
+ image1 = cache.GetImageForRow(1);
+
+ COMPARE_SK_NS_IMG_SIZES(rows->at(0), image0);
+ COMPARE_SK_NS_IMG_SIZES(rows->at(1), image1);
+}
+
+
+TEST(TableRowNSImageCacheTest, ItemsAdded) {
+ TestTable table;
+ std::vector<SkBitmap>* rows = table.rows();
+ rows->push_back(MakeImage(10, 10));
+ rows->push_back(MakeImage(20, 20));
+ TableRowNSImageCache cache(&table);
+
+ NSImage* image0 = cache.GetImageForRow(0);
+ NSImage* image1 = cache.GetImageForRow(1);
+
+ COMPARE_SK_NS_IMG_SIZES(rows->at(0), image0);
+ COMPARE_SK_NS_IMG_SIZES(rows->at(1), image1);
+
+ // Add an item to the end.
+ rows->push_back(MakeImage(30, 30));
+ cache.OnItemsAdded(2, 1);
+
+ // Make sure image 1 stayed the same.
+ EXPECT_EQ(image1, cache.GetImageForRow(1));
+ COMPARE_SK_NS_IMG_SIZES(rows->at(1), image1);
+
+ // Check that image 2 got added correctly.
+ NSImage* image2 = cache.GetImageForRow(2);
+ COMPARE_SK_NS_IMG_SIZES(rows->at(2), image2);
+
+ // Add two items to the begging.
+ rows->insert(rows->begin(), MakeImage(7, 7));
+ rows->insert(rows->begin(), MakeImage(3, 3));
+ cache.OnItemsAdded(0, 2);
+
+ NSImage* image00 = cache.GetImageForRow(0);
+ NSImage* image01 = cache.GetImageForRow(1);
+
+ COMPARE_SK_NS_IMG_SIZES(rows->at(0), image00);
+ COMPARE_SK_NS_IMG_SIZES(rows->at(1), image01);
+}
+
+
+TEST(TableRowNSImageCacheTest, ItemsRemoved) {
+ TestTable table;
+ std::vector<SkBitmap>* rows = table.rows();
+ rows->push_back(MakeImage(10, 10));
+ rows->push_back(MakeImage(20, 20));
+ rows->push_back(MakeImage(30, 30));
+ rows->push_back(MakeImage(40, 40));
+ rows->push_back(MakeImage(50, 50));
+ TableRowNSImageCache cache(&table);
+
+ NSImage* image0 = cache.GetImageForRow(0);
+ NSImage* image1 = cache.GetImageForRow(1);
+ NSImage* image2 = cache.GetImageForRow(2);
+ NSImage* image3 = cache.GetImageForRow(3);
+ NSImage* image4 = cache.GetImageForRow(4);
+
+ COMPARE_SK_NS_IMG_SIZES(rows->at(0), image0);
+ COMPARE_SK_NS_IMG_SIZES(rows->at(1), image1);
+ COMPARE_SK_NS_IMG_SIZES(rows->at(2), image2);
+ COMPARE_SK_NS_IMG_SIZES(rows->at(3), image3);
+ COMPARE_SK_NS_IMG_SIZES(rows->at(4), image4);
+
+ rows->erase(rows->begin() + 1, rows->begin() + 4); // [20x20, 50x50)
+ cache.OnItemsRemoved(1, 3);
+
+ image0 = cache.GetImageForRow(0);
+ image1 = cache.GetImageForRow(1);
+
+ COMPARE_SK_NS_IMG_SIZES(rows->at(0), image0);
+ COMPARE_SK_NS_IMG_SIZES(rows->at(1), image1);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/tabpose_window.h b/chrome/browser/ui/cocoa/tabpose_window.h
new file mode 100644
index 0000000..b798bcc
--- /dev/null
+++ b/chrome/browser/ui/cocoa/tabpose_window.h
@@ -0,0 +1,94 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_TABPOSE_WINDOW_H_
+#define CHROME_BROWSER_UI_COCOA_TABPOSE_WINDOW_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/mac/scoped_cftyperef.h"
+
+#include "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+#include "base/scoped_vector.h"
+
+namespace tabpose {
+
+class Tile;
+class TileSet;
+
+}
+
+namespace tabpose {
+
+enum WindowState {
+ kFadingIn,
+ kFadedIn,
+ kFadingOut,
+};
+
+} // namespace tabpose
+
+class TabStripModel;
+class TabStripModelObserverBridge;
+
+// A TabposeWindow shows an overview of open tabs and lets the user select a new
+// active tab. The window blocks clicks on the tab strip and the download
+// shelf. Every open browser window has its own overlay, and they are
+// independent of each other.
+@interface TabposeWindow : NSWindow {
+ @private
+ tabpose::WindowState state_;
+
+ // The root layer added to the content view. Covers the whole window.
+ CALayer* rootLayer_; // weak
+
+ // The layer showing the background layer. Covers the whole visible area.
+ CALayer* bgLayer_; // weak
+
+ // The layer drawn behind the currently selected tile.
+ CALayer* selectionHighlight_; // weak
+
+ // Colors used by the layers.
+ base::mac::ScopedCFTypeRef<CGColorRef> gray_;
+ base::mac::ScopedCFTypeRef<CGColorRef> darkBlue_;
+
+ TabStripModel* tabStripModel_; // weak
+
+ // Stores all preview layers. The order in here matches the order in
+ // the tabstrip model.
+ scoped_nsobject<NSMutableArray> allThumbnailLayers_;
+
+ scoped_nsobject<NSMutableArray> allFaviconLayers_;
+ scoped_nsobject<NSMutableArray> allTitleLayers_;
+
+ // Manages the state of all layers.
+ scoped_ptr<tabpose::TileSet> tileSet_;
+
+ // The rectangle of the window that contains all layers. This is the
+ // rectangle occupied by |bgLayer_|.
+ NSRect containingRect_;
+
+ // Informs us of added/removed/updated tabs.
+ scoped_ptr<TabStripModelObserverBridge> tabStripModelObserverBridge_;
+}
+
+// Shows a TabposeWindow on top of |parent|, with |rect| being the active area.
+// If |slomo| is YES, then the appearance animation is shown in slow motion.
+// The window blocks all keyboard and mouse events and releases itself when
+// closed.
++ (id)openTabposeFor:(NSWindow*)parent
+ rect:(NSRect)rect
+ slomo:(BOOL)slomo
+ tabStripModel:(TabStripModel*)tabStripModel;
+@end
+
+@interface TabposeWindow (TestingAPI)
+- (void)selectTileAtIndexWithoutAnimation:(int)newIndex;
+- (NSUInteger)thumbnailLayerCount;
+- (int)selectedIndex;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_TABPOSE_WINDOW_H_
diff --git a/chrome/browser/ui/cocoa/tabpose_window.mm b/chrome/browser/ui/cocoa/tabpose_window.mm
new file mode 100644
index 0000000..7f96f59
--- /dev/null
+++ b/chrome/browser/ui/cocoa/tabpose_window.mm
@@ -0,0 +1,1554 @@
+// 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 "chrome/browser/ui/cocoa/tabpose_window.h"
+
+#import <QuartzCore/QuartzCore.h>
+
+#include "app/resource_bundle.h"
+#include "base/mac_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/scoped_callback_factory.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/browser_process.h"
+#import "chrome/browser/debugger/devtools_window.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/backing_store_mac.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/renderer_host/render_widget_host_view_mac.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/thumbnail_generator.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "chrome/browser/ui/cocoa/tab_strip_controller.h"
+#import "chrome/browser/ui/cocoa/tab_strip_model_observer_bridge.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "chrome/common/pref_names.h"
+#include "gfx/scoped_cg_context_state_mac.h"
+#include "grit/app_resources.h"
+#include "skia/ext/skia_utils_mac.h"
+#include "third_party/skia/include/utils/mac/SkCGUtils.h"
+
+const int kTopGradientHeight = 15;
+
+NSString* const kAnimationIdKey = @"AnimationId";
+NSString* const kAnimationIdFadeIn = @"FadeIn";
+NSString* const kAnimationIdFadeOut = @"FadeOut";
+
+const CGFloat kDefaultAnimationDuration = 0.25; // In seconds.
+const CGFloat kSlomoFactor = 4;
+const CGFloat kObserverChangeAnimationDuration = 0.75; // In seconds.
+
+// CAGradientLayer is 10.6-only -- roll our own.
+@interface DarkGradientLayer : CALayer
+- (void)drawInContext:(CGContextRef)context;
+@end
+
+@implementation DarkGradientLayer
+- (void)drawInContext:(CGContextRef)context {
+ base::mac::ScopedCFTypeRef<CGColorSpaceRef> grayColorSpace(
+ CGColorSpaceCreateWithName(kCGColorSpaceGenericGray));
+ CGFloat grays[] = { 0.277, 1.0, 0.39, 1.0 };
+ CGFloat locations[] = { 0, 1 };
+ base::mac::ScopedCFTypeRef<CGGradientRef> gradient(
+ CGGradientCreateWithColorComponents(
+ grayColorSpace.get(), grays, locations, arraysize(locations)));
+ CGPoint topLeft = CGPointMake(0.0, kTopGradientHeight);
+ CGContextDrawLinearGradient(context, gradient.get(), topLeft, CGPointZero, 0);
+}
+@end
+
+namespace tabpose {
+class ThumbnailLoader;
+}
+
+// A CALayer that draws a thumbnail for a TabContents object. The layer tries
+// to draw the TabContents's backing store directly if possible, and requests
+// a thumbnail bitmap from the TabContents's renderer process if not.
+@interface ThumbnailLayer : CALayer {
+ // The TabContents the thumbnail is for.
+ TabContents* contents_; // weak
+
+ // The size the thumbnail is drawn at when zoomed in.
+ NSSize fullSize_;
+
+ // Used to load a thumbnail, if required.
+ scoped_refptr<tabpose::ThumbnailLoader> loader_;
+
+ // If the backing store couldn't be used and a thumbnail was returned from a
+ // renderer process, it's stored in |thumbnail_|.
+ base::mac::ScopedCFTypeRef<CGImageRef> thumbnail_;
+
+ // True if the layer already sent a thumbnail request to a renderer.
+ BOOL didSendLoad_;
+}
+- (id)initWithTabContents:(TabContents*)contents fullSize:(NSSize)fullSize;
+- (void)drawInContext:(CGContextRef)context;
+- (void)setThumbnail:(const SkBitmap&)bitmap;
+@end
+
+namespace tabpose {
+
+// ThumbnailLoader talks to the renderer process to load a thumbnail of a given
+// RenderWidgetHost, and sends the thumbnail back to a ThumbnailLayer once it
+// comes back from the renderer.
+class ThumbnailLoader : public base::RefCountedThreadSafe<ThumbnailLoader> {
+ public:
+ ThumbnailLoader(gfx::Size size, RenderWidgetHost* rwh, ThumbnailLayer* layer)
+ : size_(size), rwh_(rwh), layer_(layer), factory_(this) {}
+
+ // Starts the fetch.
+ void LoadThumbnail();
+
+ private:
+ friend class base::RefCountedThreadSafe<ThumbnailLoader>;
+ ~ThumbnailLoader() {
+ ResetPaintingObserver();
+ }
+
+ void DidReceiveBitmap(const SkBitmap& bitmap) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ ResetPaintingObserver();
+ [layer_ setThumbnail:bitmap];
+ }
+
+ void ResetPaintingObserver() {
+ if (rwh_->painting_observer() != NULL) {
+ DCHECK(rwh_->painting_observer() ==
+ g_browser_process->GetThumbnailGenerator());
+ rwh_->set_painting_observer(NULL);
+ }
+ }
+
+ gfx::Size size_;
+ RenderWidgetHost* rwh_; // weak
+ ThumbnailLayer* layer_; // weak, owns us
+ base::ScopedCallbackFactory<ThumbnailLoader> factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThumbnailLoader);
+};
+
+void ThumbnailLoader::LoadThumbnail() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ ThumbnailGenerator* generator = g_browser_process->GetThumbnailGenerator();
+ if (!generator) // In unit tests.
+ return;
+
+ // As mentioned in ThumbnailLayer's -drawInContext:, it's sufficient to have
+ // thumbnails at the zoomed-out pixel size for all but the thumbnail the user
+ // clicks on in the end. But we don't don't which thumbnail that will be, so
+ // keep it simple and request full thumbnails for everything.
+ // TODO(thakis): Request smaller thumbnails for users with many tabs.
+ gfx::Size page_size(size_); // Logical size the renderer renders at.
+ gfx::Size pixel_size(size_); // Physical pixel size the image is rendered at.
+
+ DCHECK(rwh_->painting_observer() == NULL ||
+ rwh_->painting_observer() == generator);
+ rwh_->set_painting_observer(generator);
+
+ // Will send an IPC to the renderer on the IO thread.
+ generator->AskForSnapshot(
+ rwh_,
+ /*prefer_backing_store=*/false,
+ factory_.NewCallback(&ThumbnailLoader::DidReceiveBitmap),
+ page_size,
+ pixel_size);
+}
+
+} // namespace tabpose
+
+@implementation ThumbnailLayer
+
+- (id)initWithTabContents:(TabContents*)contents fullSize:(NSSize)fullSize {
+ CHECK(contents);
+ if ((self = [super init])) {
+ contents_ = contents;
+ fullSize_ = fullSize;
+ }
+ return self;
+}
+
+- (void)setTabContents:(TabContents*)contents {
+ contents_ = contents;
+}
+
+- (void)setThumbnail:(const SkBitmap&)bitmap {
+ // SkCreateCGImageRef() holds on to |bitmaps|'s memory, so this doesn't
+ // create a copy.
+ thumbnail_.reset(SkCreateCGImageRef(bitmap));
+ loader_ = NULL;
+ [self setNeedsDisplay];
+}
+
+- (int)topOffset {
+ int topOffset = 0;
+
+ // Medium term, we want to show thumbs of the actual info bar views, which
+ // means I need to create InfoBarControllers here. At that point, we can get
+ // the height from that controller. Until then, hardcode. :-/
+ const int kInfoBarHeight = 31;
+ topOffset += contents_->infobar_delegate_count() * kInfoBarHeight;
+
+ bool always_show_bookmark_bar =
+ contents_->profile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar);
+ bool has_detached_bookmark_bar =
+ contents_->ShouldShowBookmarkBar() && !always_show_bookmark_bar;
+ if (has_detached_bookmark_bar)
+ topOffset += bookmarks::kNTPBookmarkBarHeight;
+
+ return topOffset;
+}
+
+- (int)bottomOffset {
+ int bottomOffset = 0;
+ TabContents* devToolsContents =
+ DevToolsWindow::GetDevToolsContents(contents_);
+ if (devToolsContents && devToolsContents->render_view_host() &&
+ devToolsContents->render_view_host()->view()) {
+ // The devtool's size might not be up-to-date, but since its height doesn't
+ // change on window resize, and since most users don't use devtools, this is
+ // good enough.
+ bottomOffset +=
+ devToolsContents->render_view_host()->view()->GetViewBounds().height();
+ bottomOffset += 1; // :-( Divider line between web contents and devtools.
+ }
+ return bottomOffset;
+}
+
+- (void)drawBackingStore:(BackingStoreMac*)backing_store
+ inRect:(CGRect)destRect
+ context:(CGContextRef)context {
+ // TODO(thakis): Add a sublayer for each accelerated surface in the rwhv.
+ // Until then, accelerated layers (CoreAnimation NPAPI plugins, compositor)
+ // won't show up in tabpose.
+ gfx::ScopedCGContextSaveGState CGContextSaveGState(context);
+ CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
+ if (backing_store->cg_layer()) {
+ CGContextDrawLayerInRect(context, destRect, backing_store->cg_layer());
+ } else {
+ base::mac::ScopedCFTypeRef<CGImageRef> image(
+ CGBitmapContextCreateImage(backing_store->cg_bitmap()));
+ CGContextDrawImage(context, destRect, image);
+ }
+}
+
+- (void)drawInContext:(CGContextRef)context {
+ RenderWidgetHost* rwh = contents_->render_view_host();
+ // NULL if renderer crashed.
+ RenderWidgetHostView* rwhv = rwh ? rwh->view() : NULL;
+ if (!rwhv) {
+ // TODO(thakis): Maybe draw a sad tab layer?
+ [super drawInContext:context];
+ return;
+ }
+
+ // The size of the TabContent's RenderWidgetHost might not fit to the
+ // current browser window at all, for example if the window was resized while
+ // this TabContents object was not an active tab.
+ // Compute the required size ourselves. Leave room for eventual infobars and
+ // a detached bookmarks bar on the top, and for the devtools on the bottom.
+ // Download shelf is not included in the |fullSize| rect, so no need to
+ // correct for it here.
+ // TODO(thakis): This is not resolution-independent.
+ int topOffset = [self topOffset];
+ int bottomOffset = [self bottomOffset];
+ gfx::Size desiredThumbSize(fullSize_.width,
+ fullSize_.height - topOffset - bottomOffset);
+
+ // We need to ask the renderer for a thumbnail if
+ // a) there's no backing store or
+ // b) the backing store's size doesn't match our required size and
+ // c) we didn't already send a thumbnail request to the renderer.
+ BackingStoreMac* backing_store =
+ (BackingStoreMac*)rwh->GetBackingStore(/*force_create=*/false);
+ bool draw_backing_store =
+ backing_store && backing_store->size() == desiredThumbSize;
+
+ // Next weirdness: The destination rect. If the layer is |fullSize_| big, the
+ // destination rect is (0, bottomOffset), (fullSize_.width, topOffset). But we
+ // might be amidst an animation, so interpolate that rect.
+ CGRect destRect = [self bounds];
+ CGFloat scale = destRect.size.width / fullSize_.width;
+ destRect.origin.y += bottomOffset * scale;
+ destRect.size.height -= (bottomOffset + topOffset) * scale;
+
+ // TODO(thakis): Draw infobars, detached bookmark bar as well.
+
+ // If we haven't already, sent a thumbnail request to the renderer.
+ if (!draw_backing_store && !didSendLoad_) {
+ // Either the tab was never visible, or its backing store got evicted, or
+ // the size of the backing store is wrong.
+
+ // We only need a thumbnail the size of the zoomed-out layer for all
+ // layers except the one the user clicks on. But since we can't know which
+ // layer that is, request full-resolution layers for all tabs. This is
+ // simple and seems to work in practice.
+ loader_ = new tabpose::ThumbnailLoader(desiredThumbSize, rwh, self);
+ loader_->LoadThumbnail();
+ didSendLoad_ = YES;
+
+ // Fill with bg color.
+ [super drawInContext:context];
+ }
+
+ if (draw_backing_store) {
+ // Backing store 'cache' hit!
+ [self drawBackingStore:backing_store inRect:destRect context:context];
+ } else if (thumbnail_) {
+ // No cache hit, but the renderer returned a thumbnail to us.
+ gfx::ScopedCGContextSaveGState CGContextSaveGState(context);
+ CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
+ CGContextDrawImage(context, destRect, thumbnail_.get());
+ }
+}
+
+@end
+
+namespace {
+
+class ScopedCAActionDisabler {
+ public:
+ ScopedCAActionDisabler() {
+ [CATransaction begin];
+ [CATransaction setValue:[NSNumber numberWithBool:YES]
+ forKey:kCATransactionDisableActions];
+ }
+
+ ~ScopedCAActionDisabler() {
+ [CATransaction commit];
+ }
+};
+
+class ScopedCAActionSetDuration {
+ public:
+ explicit ScopedCAActionSetDuration(CGFloat duration) {
+ [CATransaction begin];
+ [CATransaction setValue:[NSNumber numberWithFloat:duration]
+ forKey:kCATransactionAnimationDuration];
+ }
+
+ ~ScopedCAActionSetDuration() {
+ [CATransaction commit];
+ }
+};
+
+} // namespace
+
+// Given the number |n| of tiles with a desired aspect ratio of |a| and a
+// desired distance |dx|, |dy| between tiles, returns how many tiles fit
+// vertically into a rectangle with the dimensions |w_c|, |h_c|. This returns
+// an exact solution, which is usually a fractional number.
+static float FitNRectsWithAspectIntoBoundingSizeWithConstantPadding(
+ int n, double a, int w_c, int h_c, int dx, int dy) {
+ // We want to have the small rects have the same aspect ratio a as a full
+ // tab. Let w, h be the size of a small rect, and w_c, h_c the size of the
+ // container. dx, dy are the distances between small rects in x, y direction.
+
+ // Geometry yields:
+ // w_c = nx * (w + dx) - dx <=> w = (w_c + d_x) / nx - d_x
+ // h_c = ny * (h + dy) - dy <=> h = (h_c + d_y) / ny - d_t
+ // Plugging this into
+ // a := tab_width / tab_height = w / h
+ // yields
+ // a = ((w_c - (nx - 1)*d_x)*ny) / (nx*(h_c - (ny - 1)*d_y))
+ // Plugging in nx = n/ny and pen and paper (or wolfram alpha:
+ // http://www.wolframalpha.com/input/?i=(-sqrt((d+n-a+f+n)^2-4+(a+f%2Ba+h)+(-d+n-n+w))%2Ba+f+n-d+n)/(2+a+(f%2Bh)) , (solution for nx)
+ // http://www.wolframalpha.com/input/?i=+(-sqrt((a+f+n-d+n)^2-4+(d%2Bw)+(-a+f+n-a+h+n))-a+f+n%2Bd+n)/(2+(d%2Bw)) , (solution for ny)
+ // ) gives us nx and ny (but the wrong root -- s/-sqrt(FOO)/sqrt(FOO)/.
+
+ // This function returns ny.
+ return (sqrt(pow(n * (a * dy - dx), 2) +
+ 4 * n * a * (dx + w_c) * (dy + h_c)) -
+ n * (a * dy - dx))
+ /
+ (2 * (dx + w_c));
+}
+
+namespace tabpose {
+
+CGFloat ScaleWithOrigin(CGFloat x, CGFloat origin, CGFloat scale) {
+ return (x - origin) * scale + origin;
+}
+
+NSRect ScaleRectWithOrigin(NSRect r, NSPoint p, CGFloat scale) {
+ return NSMakeRect(ScaleWithOrigin(NSMinX(r), p.x, scale),
+ ScaleWithOrigin(NSMinY(r), p.y, scale),
+ NSWidth(r) * scale,
+ NSHeight(r) * scale);
+}
+
+// A tile is what is shown for a single tab in tabpose mode. It consists of a
+// title, favicon, thumbnail image, and pre- and postanimation rects.
+class Tile {
+ public:
+ Tile() {}
+
+ // Returns the rectangle this thumbnail is at at the beginning of the zoom-in
+ // animation. |tile| is the rectangle that's covering the whole tab area when
+ // the animation starts.
+ NSRect GetStartRectRelativeTo(const Tile& tile) const;
+ NSRect thumb_rect() const { return thumb_rect_; }
+
+ NSRect GetFaviconStartRectRelativeTo(const Tile& tile) const;
+ NSRect favicon_rect() const { return NSIntegralRect(favicon_rect_); }
+ SkBitmap favicon() const;
+
+ // This changes |title_rect| and |favicon_rect| such that the favicon is on
+ // the font's baseline and that the minimum distance between thumb rect and
+ // favicon and title rects doesn't change.
+ // The view code
+ // 1. queries desired font size by calling |title_font_size()|
+ // 2. loads that font
+ // 3. calls |set_font_metrics()| which updates the title rect
+ // 4. receives the title rect and puts the title on it with the font from 2.
+ void set_font_metrics(CGFloat ascender, CGFloat descender);
+ CGFloat title_font_size() const { return title_font_size_; }
+
+ NSRect GetTitleStartRectRelativeTo(const Tile& tile) const;
+ NSRect title_rect() const { return NSIntegralRect(title_rect_); }
+
+ // Returns an unelided title. The view logic is responsible for eliding.
+ const string16& title() const { return contents_->GetTitle(); }
+
+ TabContents* tab_contents() const { return contents_; }
+ void set_tab_contents(TabContents* new_contents) { contents_ = new_contents; }
+
+ private:
+ friend class TileSet;
+
+ // The thumb rect includes infobars, detached thumbnail bar, web contents,
+ // and devtools.
+ NSRect thumb_rect_;
+ NSRect start_thumb_rect_;
+
+ NSRect favicon_rect_;
+
+ CGFloat title_font_size_;
+ NSRect title_rect_;
+
+ TabContents* contents_; // weak
+
+ DISALLOW_COPY_AND_ASSIGN(Tile);
+};
+
+NSRect Tile::GetStartRectRelativeTo(const Tile& tile) const {
+ NSRect rect = start_thumb_rect_;
+ rect.origin.x -= tile.start_thumb_rect_.origin.x;
+ rect.origin.y -= tile.start_thumb_rect_.origin.y;
+ return rect;
+}
+
+NSRect Tile::GetFaviconStartRectRelativeTo(const Tile& tile) const {
+ NSRect thumb_start = GetStartRectRelativeTo(tile);
+ CGFloat scale_to_start = NSWidth(thumb_start) / NSWidth(thumb_rect_);
+ NSRect rect =
+ ScaleRectWithOrigin(favicon_rect_, thumb_rect_.origin, scale_to_start);
+ rect.origin.x += NSMinX(thumb_start) - NSMinX(thumb_rect_);
+ rect.origin.y += NSMinY(thumb_start) - NSMinY(thumb_rect_);
+ return rect;
+}
+
+SkBitmap Tile::favicon() const {
+ if (contents_->is_app()) {
+ SkBitmap* icon = contents_->GetExtensionAppIcon();
+ if (icon)
+ return *icon;
+ }
+ return contents_->GetFavIcon();
+}
+
+NSRect Tile::GetTitleStartRectRelativeTo(const Tile& tile) const {
+ NSRect thumb_start = GetStartRectRelativeTo(tile);
+ CGFloat scale_to_start = NSWidth(thumb_start) / NSWidth(thumb_rect_);
+ NSRect rect =
+ ScaleRectWithOrigin(title_rect_, thumb_rect_.origin, scale_to_start);
+ rect.origin.x += NSMinX(thumb_start) - NSMinX(thumb_rect_);
+ rect.origin.y += NSMinY(thumb_start) - NSMinY(thumb_rect_);
+ return rect;
+}
+
+// Changes |title_rect| and |favicon_rect| such that the favicon's and the
+// title's vertical center is aligned and that the minimum distance between
+// the thumb rect and favicon and title rects doesn't change.
+void Tile::set_font_metrics(CGFloat ascender, CGFloat descender) {
+ // Make the title height big enough to fit the font, and adopt the title
+ // position to keep its distance from the thumb rect.
+ title_rect_.origin.y -= ascender + descender - NSHeight(title_rect_);
+ title_rect_.size.height = ascender + descender;
+
+ // Align vertical center. Both rects are currently aligned on their top edge.
+ CGFloat delta_y = NSMidY(title_rect_) - NSMidY(favicon_rect_);
+ if (delta_y > 0) {
+ // Title is higher: Move favicon down to align the centers.
+ favicon_rect_.origin.y += delta_y;
+ } else {
+ // Favicon is higher: Move title down to align the centers.
+ title_rect_.origin.y -= delta_y;
+ }
+}
+
+// A tileset is responsible for owning and laying out all |Tile|s shown in a
+// tabpose window.
+class TileSet {
+ public:
+ TileSet() {}
+
+ // Fills in |tiles_|.
+ void Build(TabStripModel* source_model);
+
+ // Computes coordinates for |tiles_|.
+ void Layout(NSRect containing_rect);
+
+ int selected_index() const { return selected_index_; }
+ void set_selected_index(int index);
+
+ const Tile& selected_tile() const { return *tiles_[selected_index()]; }
+ Tile& tile_at(int index) { return *tiles_[index]; }
+ const Tile& tile_at(int index) const { return *tiles_[index]; }
+
+ // These return which index needs to be selected when the user presses
+ // up, down, left, or right respectively.
+ int up_index() const;
+ int down_index() const;
+ int left_index() const;
+ int right_index() const;
+
+ // These return which index needs to be selected on tab / shift-tab.
+ int next_index() const;
+ int previous_index() const;
+
+ // Inserts a new Tile object containing |contents| at |index|. Does no
+ // relayout.
+ void InsertTileAt(int index, TabContents* contents);
+
+ // Removes the Tile object at |index|. Does no relayout.
+ void RemoveTileAt(int index);
+
+ // Moves the Tile object at |from_index| to |to_index|. Since this doesn't
+ // change the number of tiles, relayout can be done just by swapping the
+ // tile rectangles in the index interval [from_index, to_index], so this does
+ // layout.
+ void MoveTileFromTo(int from_index, int to_index);
+
+ private:
+ int count_x() const {
+ return ceilf(tiles_.size() / static_cast<float>(count_y_));
+ }
+ int count_y() const {
+ return count_y_;
+ }
+ int last_row_count_x() const {
+ return tiles_.size() - count_x() * (count_y() - 1);
+ }
+ int tiles_in_row(int row) const {
+ return row != count_y() - 1 ? count_x() : last_row_count_x();
+ }
+ void index_to_tile_xy(int index, int* tile_x, int* tile_y) const {
+ *tile_x = index % count_x();
+ *tile_y = index / count_x();
+ }
+ int tile_xy_to_index(int tile_x, int tile_y) const {
+ return tile_y * count_x() + tile_x;
+ }
+
+ ScopedVector<Tile> tiles_;
+ int selected_index_;
+ int count_y_;
+
+ DISALLOW_COPY_AND_ASSIGN(TileSet);
+};
+
+void TileSet::Build(TabStripModel* source_model) {
+ selected_index_ = source_model->selected_index();
+ tiles_.resize(source_model->count());
+ for (size_t i = 0; i < tiles_.size(); ++i) {
+ tiles_[i] = new Tile;
+ tiles_[i]->contents_ = source_model->GetTabContentsAt(i)->tab_contents();
+ }
+}
+
+void TileSet::Layout(NSRect containing_rect) {
+ int tile_count = tiles_.size();
+ if (tile_count == 0) // Happens e.g. during test shutdown.
+ return;
+
+ // Room around the tiles insde of |containing_rect|.
+ const int kSmallPaddingTop = 30;
+ const int kSmallPaddingLeft = 30;
+ const int kSmallPaddingRight = 30;
+ const int kSmallPaddingBottom = 30;
+
+ // Favicon / title area.
+ const int kThumbTitlePaddingY = 6;
+ const int kFaviconSize = 16;
+ const int kTitleHeight = 14; // Font size.
+ const int kTitleExtraHeight = kThumbTitlePaddingY + kTitleHeight;
+ const int kFaviconExtraHeight = kThumbTitlePaddingY + kFaviconSize;
+ const int kFaviconTitleDistanceX = 6;
+ const int kFooterExtraHeight =
+ std::max(kFaviconExtraHeight, kTitleExtraHeight);
+
+ // Room between the tiles.
+ const int kSmallPaddingX = 15;
+ const int kSmallPaddingY = kFooterExtraHeight;
+
+ // Aspect ratio of the containing rect.
+ CGFloat aspect = NSWidth(containing_rect) / NSHeight(containing_rect);
+
+ // Room left in container after the outer padding is removed.
+ double container_width =
+ NSWidth(containing_rect) - kSmallPaddingLeft - kSmallPaddingRight;
+ double container_height =
+ NSHeight(containing_rect) - kSmallPaddingTop - kSmallPaddingBottom;
+
+ // The tricky part is figuring out the size of a tab thumbnail, or since the
+ // size of the containing rect is known, the number of tiles in x and y
+ // direction.
+ // Given are the size of the containing rect, and the number of thumbnails
+ // that need to fit into that rect. The aspect ratio of the thumbnails needs
+ // to be the same as that of |containing_rect|, else they will look distorted.
+ // The thumbnails need to be distributed such that
+ // |count_x * count_y >= tile_count|, and such that wasted space is minimized.
+ // See the comments in
+ // |FitNRectsWithAspectIntoBoundingSizeWithConstantPadding()| for a more
+ // detailed discussion.
+ // TODO(thakis): It might be good enough to choose |count_x| and |count_y|
+ // such that count_x / count_y is roughly equal to |aspect|?
+ double fny = FitNRectsWithAspectIntoBoundingSizeWithConstantPadding(
+ tile_count, aspect,
+ container_width, container_height - kFooterExtraHeight,
+ kSmallPaddingX, kSmallPaddingY + kFooterExtraHeight);
+ count_y_ = roundf(fny);
+
+ // Now that |count_x()| and |count_y_| are known, it's straightforward to
+ // compute thumbnail width/height. See comment in
+ // |FitNRectsWithAspectIntoBoundingSizeWithConstantPadding| for the derivation
+ // of these two formulas.
+ int small_width =
+ floor((container_width + kSmallPaddingX) / static_cast<float>(count_x()) -
+ kSmallPaddingX);
+ int small_height =
+ floor((container_height + kSmallPaddingY) / static_cast<float>(count_y_) -
+ (kSmallPaddingY + kFooterExtraHeight));
+
+ // |small_width / small_height| has only roughly an aspect ratio of |aspect|.
+ // Shrink the thumbnail rect to make the aspect ratio fit exactly, and add
+ // the extra space won by shrinking to the outer padding.
+ int smallExtraPaddingLeft = 0;
+ int smallExtraPaddingTop = 0;
+ if (aspect > small_width/static_cast<float>(small_height)) {
+ small_height = small_width / aspect;
+ CGFloat all_tiles_height =
+ (small_height + kSmallPaddingY + kFooterExtraHeight) * count_y() -
+ (kSmallPaddingY + kFooterExtraHeight);
+ smallExtraPaddingTop = (container_height - all_tiles_height)/2;
+ } else {
+ small_width = small_height * aspect;
+ CGFloat all_tiles_width =
+ (small_width + kSmallPaddingX) * count_x() - kSmallPaddingX;
+ smallExtraPaddingLeft = (container_width - all_tiles_width)/2;
+ }
+
+ // Compute inter-tile padding in the zoomed-out view.
+ CGFloat scale_small_to_big =
+ NSWidth(containing_rect) / static_cast<float>(small_width);
+ CGFloat big_padding_x = kSmallPaddingX * scale_small_to_big;
+ CGFloat big_padding_y =
+ (kSmallPaddingY + kFooterExtraHeight) * scale_small_to_big;
+
+ // Now all dimensions are known. Lay out all tiles on a regular grid:
+ // X X X X
+ // X X X X
+ // X X
+ for (int row = 0, i = 0; i < tile_count; ++row) {
+ for (int col = 0; col < count_x() && i < tile_count; ++col, ++i) {
+ // Compute the smalled, zoomed-out thumbnail rect.
+ tiles_[i]->thumb_rect_.size = NSMakeSize(small_width, small_height);
+
+ int small_x = col * (small_width + kSmallPaddingX) +
+ kSmallPaddingLeft + smallExtraPaddingLeft;
+ int small_y = row * (small_height + kSmallPaddingY + kFooterExtraHeight) +
+ kSmallPaddingTop + smallExtraPaddingTop;
+
+ tiles_[i]->thumb_rect_.origin = NSMakePoint(
+ small_x, NSHeight(containing_rect) - small_y - small_height);
+
+ tiles_[i]->favicon_rect_.size = NSMakeSize(kFaviconSize, kFaviconSize);
+ tiles_[i]->favicon_rect_.origin = NSMakePoint(
+ small_x,
+ NSHeight(containing_rect) -
+ (small_y + small_height + kFaviconExtraHeight));
+
+ // Align lower left corner of title rect with lower left corner of favicon
+ // for now. The final position is computed later by
+ // |Tile::set_font_metrics()|.
+ tiles_[i]->title_font_size_ = kTitleHeight;
+ tiles_[i]->title_rect_.origin = NSMakePoint(
+ NSMaxX(tiles_[i]->favicon_rect()) + kFaviconTitleDistanceX,
+ NSMinY(tiles_[i]->favicon_rect()));
+ tiles_[i]->title_rect_.size = NSMakeSize(
+ small_width -
+ NSWidth(tiles_[i]->favicon_rect()) - kFaviconTitleDistanceX,
+ kTitleHeight);
+
+ // Compute the big, pre-zoom thumbnail rect.
+ tiles_[i]->start_thumb_rect_.size = containing_rect.size;
+
+ int big_x = col * (NSWidth(containing_rect) + big_padding_x);
+ int big_y = row * (NSHeight(containing_rect) + big_padding_y);
+ tiles_[i]->start_thumb_rect_.origin = NSMakePoint(big_x, -big_y);
+ }
+ }
+
+ // Go through last row and center it:
+ // X X X X
+ // X X X X
+ // X X
+ int last_row_empty_tiles_x = count_x() - last_row_count_x();
+ CGFloat small_last_row_shift_x =
+ last_row_empty_tiles_x * (small_width + kSmallPaddingX) / 2;
+ CGFloat big_last_row_shift_x =
+ last_row_empty_tiles_x * (NSWidth(containing_rect) + big_padding_x) / 2;
+ for (int i = tile_count - last_row_count_x(); i < tile_count; ++i) {
+ tiles_[i]->thumb_rect_.origin.x += small_last_row_shift_x;
+ tiles_[i]->start_thumb_rect_.origin.x += big_last_row_shift_x;
+ tiles_[i]->favicon_rect_.origin.x += small_last_row_shift_x;
+ tiles_[i]->title_rect_.origin.x += small_last_row_shift_x;
+ }
+}
+
+void TileSet::set_selected_index(int index) {
+ CHECK_GE(index, 0);
+ CHECK_LT(index, static_cast<int>(tiles_.size()));
+ selected_index_ = index;
+}
+
+// Given a |value| in [0, from_scale), map it into [0, to_scale) such that:
+// * [0, from_scale) ends up in the middle of [0, to_scale) if the latter is
+// a bigger range
+// * The middle of [0, from_scale) is mapped to [0, to_scale), and the parts
+// of the former that don't fit are mapped to 0 and to_scale - respectively
+// if the former is a bigger range.
+static int rescale(int value, int from_scale, int to_scale) {
+ int left = (to_scale - from_scale) / 2;
+ int result = value + left;
+ if (result < 0)
+ return 0;
+ if (result >= to_scale)
+ return to_scale - 1;
+ return result;
+}
+
+int TileSet::up_index() const {
+ int tile_x, tile_y;
+ index_to_tile_xy(selected_index(), &tile_x, &tile_y);
+ tile_y -= 1;
+ if (tile_y == count_y() - 2) {
+ // Transition from last row to second-to-last row.
+ tile_x = rescale(tile_x, last_row_count_x(), count_x());
+ } else if (tile_y < 0) {
+ // Transition from first row to last row.
+ tile_x = rescale(tile_x, count_x(), last_row_count_x());
+ tile_y = count_y() - 1;
+ }
+ return tile_xy_to_index(tile_x, tile_y);
+}
+
+int TileSet::down_index() const {
+ int tile_x, tile_y;
+ index_to_tile_xy(selected_index(), &tile_x, &tile_y);
+ tile_y += 1;
+ if (tile_y == count_y() - 1) {
+ // Transition from second-to-last row to last row.
+ tile_x = rescale(tile_x, count_x(), last_row_count_x());
+ } else if (tile_y >= count_y()) {
+ // Transition from last row to first row.
+ tile_x = rescale(tile_x, last_row_count_x(), count_x());
+ tile_y = 0;
+ }
+ return tile_xy_to_index(tile_x, tile_y);
+}
+
+int TileSet::left_index() const {
+ int tile_x, tile_y;
+ index_to_tile_xy(selected_index(), &tile_x, &tile_y);
+ tile_x -= 1;
+ if (tile_x < 0)
+ tile_x = tiles_in_row(tile_y) - 1;
+ return tile_xy_to_index(tile_x, tile_y);
+}
+
+int TileSet::right_index() const {
+ int tile_x, tile_y;
+ index_to_tile_xy(selected_index(), &tile_x, &tile_y);
+ tile_x += 1;
+ if (tile_x >= tiles_in_row(tile_y))
+ tile_x = 0;
+ return tile_xy_to_index(tile_x, tile_y);
+}
+
+int TileSet::next_index() const {
+ int new_index = selected_index() + 1;
+ if (new_index >= static_cast<int>(tiles_.size()))
+ new_index = 0;
+ return new_index;
+}
+
+int TileSet::previous_index() const {
+ int new_index = selected_index() - 1;
+ if (new_index < 0)
+ new_index = tiles_.size() - 1;
+ return new_index;
+}
+
+void TileSet::InsertTileAt(int index, TabContents* contents) {
+ tiles_.insert(tiles_.begin() + index, new Tile);
+ tiles_[index]->contents_ = contents;
+}
+
+void TileSet::RemoveTileAt(int index) {
+ tiles_.erase(tiles_.begin() + index);
+}
+
+// Moves the Tile object at |from_index| to |to_index|. Also updates rectangles
+// so that the tiles stay in a left-to-right, top-to-bottom layout when walked
+// in sequential order.
+void TileSet::MoveTileFromTo(int from_index, int to_index) {
+ NSRect thumb = tiles_[from_index]->thumb_rect_;
+ NSRect start_thumb = tiles_[from_index]->start_thumb_rect_;
+ NSRect favicon = tiles_[from_index]->favicon_rect_;
+ NSRect title = tiles_[from_index]->title_rect_;
+
+ scoped_ptr<Tile> tile(tiles_[from_index]);
+ tiles_.weak_erase(tiles_.begin() + from_index);
+ tiles_.insert(tiles_.begin() + to_index, tile.release());
+
+ int step = from_index < to_index ? -1 : 1;
+ for (int i = to_index; (i - from_index) * step < 0; i += step) {
+ tiles_[i]->thumb_rect_ = tiles_[i + step]->thumb_rect_;
+ tiles_[i]->start_thumb_rect_ = tiles_[i + step]->start_thumb_rect_;
+ tiles_[i]->favicon_rect_ = tiles_[i + step]->favicon_rect_;
+ tiles_[i]->title_rect_ = tiles_[i + step]->title_rect_;
+ }
+ tiles_[from_index]->thumb_rect_ = thumb;
+ tiles_[from_index]->start_thumb_rect_ = start_thumb;
+ tiles_[from_index]->favicon_rect_ = favicon;
+ tiles_[from_index]->title_rect_ = title;
+}
+
+} // namespace tabpose
+
+void AnimateScaledCALayerFrameFromTo(
+ CALayer* layer,
+ const NSRect& from, CGFloat from_scale,
+ const NSRect& to, CGFloat to_scale,
+ NSTimeInterval duration, id boundsAnimationDelegate) {
+ // http://developer.apple.com/mac/library/qa/qa2008/qa1620.html
+ CABasicAnimation* animation;
+
+ animation = [CABasicAnimation animationWithKeyPath:@"bounds"];
+ animation.fromValue = [NSValue valueWithRect:from];
+ animation.toValue = [NSValue valueWithRect:to];
+ animation.duration = duration;
+ animation.timingFunction =
+ [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
+ animation.delegate = boundsAnimationDelegate;
+
+ // Update the layer's bounds so the layer doesn't snap back when the animation
+ // completes.
+ layer.bounds = NSRectToCGRect(to);
+
+ // Add the animation, overriding the implicit animation.
+ [layer addAnimation:animation forKey:@"bounds"];
+
+ // Prepare the animation from the current position to the new position.
+ NSPoint opoint = from.origin;
+ NSPoint point = to.origin;
+
+ // Adapt to anchorPoint.
+ opoint.x += NSWidth(from) * from_scale * layer.anchorPoint.x;
+ opoint.y += NSHeight(from) * from_scale * layer.anchorPoint.y;
+ point.x += NSWidth(to) * to_scale * layer.anchorPoint.x;
+ point.y += NSHeight(to) * to_scale * layer.anchorPoint.y;
+
+ animation = [CABasicAnimation animationWithKeyPath:@"position"];
+ animation.fromValue = [NSValue valueWithPoint:opoint];
+ animation.toValue = [NSValue valueWithPoint:point];
+ animation.duration = duration;
+ animation.timingFunction =
+ [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
+
+ // Update the layer's position so that the layer doesn't snap back when the
+ // animation completes.
+ layer.position = NSPointToCGPoint(point);
+
+ // Add the animation, overriding the implicit animation.
+ [layer addAnimation:animation forKey:@"position"];
+}
+
+void AnimateCALayerFrameFromTo(
+ CALayer* layer, const NSRect& from, const NSRect& to,
+ NSTimeInterval duration, id boundsAnimationDelegate) {
+ AnimateScaledCALayerFrameFromTo(
+ layer, from, 1.0, to, 1.0, duration, boundsAnimationDelegate);
+}
+
+void AnimateCALayerOpacityFromTo(
+ CALayer* layer, double from, double to, NSTimeInterval duration) {
+ CABasicAnimation* animation;
+ animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
+ animation.fromValue = [NSNumber numberWithFloat:from];
+ animation.toValue = [NSNumber numberWithFloat:to];
+ animation.duration = duration;
+
+ layer.opacity = to;
+ // Add the animation, overriding the implicit animation.
+ [layer addAnimation:animation forKey:@"opacity"];
+}
+
+@interface TabposeWindow (Private)
+- (id)initForWindow:(NSWindow*)parent
+ rect:(NSRect)rect
+ slomo:(BOOL)slomo
+ tabStripModel:(TabStripModel*)tabStripModel;
+- (void)setUpLayersInSlomo:(BOOL)slomo;
+- (void)fadeAway:(BOOL)slomo;
+- (void)selectTileAtIndex:(int)newIndex;
+@end
+
+@implementation TabposeWindow
+
++ (id)openTabposeFor:(NSWindow*)parent
+ rect:(NSRect)rect
+ slomo:(BOOL)slomo
+ tabStripModel:(TabStripModel*)tabStripModel {
+ // Releases itself when closed.
+ return [[TabposeWindow alloc]
+ initForWindow:parent rect:rect slomo:slomo tabStripModel:tabStripModel];
+}
+
+- (id)initForWindow:(NSWindow*)parent
+ rect:(NSRect)rect
+ slomo:(BOOL)slomo
+ tabStripModel:(TabStripModel*)tabStripModel {
+ NSRect frame = [parent frame];
+ if ((self = [super initWithContentRect:frame
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO])) {
+ containingRect_ = rect;
+ tabStripModel_ = tabStripModel;
+ state_ = tabpose::kFadingIn;
+ tileSet_.reset(new tabpose::TileSet);
+ tabStripModelObserverBridge_.reset(
+ new TabStripModelObserverBridge(tabStripModel_, self));
+ [self setReleasedWhenClosed:YES];
+ [self setOpaque:NO];
+ [self setBackgroundColor:[NSColor clearColor]];
+ [self setUpLayersInSlomo:slomo];
+ [self setAcceptsMouseMovedEvents:YES];
+ [parent addChildWindow:self ordered:NSWindowAbove];
+ [self makeKeyAndOrderFront:self];
+ }
+ return self;
+}
+
+- (CALayer*)selectedLayer {
+ return [allThumbnailLayers_ objectAtIndex:tileSet_->selected_index()];
+}
+
+- (void)selectTileAtIndex:(int)newIndex {
+ const tabpose::Tile& tile = tileSet_->tile_at(newIndex);
+ selectionHighlight_.frame =
+ NSRectToCGRect(NSInsetRect(tile.thumb_rect(), -5, -5));
+ tileSet_->set_selected_index(newIndex);
+}
+
+- (void)selectTileAtIndexWithoutAnimation:(int)newIndex {
+ ScopedCAActionDisabler disabler;
+ [self selectTileAtIndex:newIndex];
+}
+
+- (void)addLayersForTile:(tabpose::Tile&)tile
+ showZoom:(BOOL)showZoom
+ slomo:(BOOL)slomo
+ animationDelegate:(id)animationDelegate {
+ scoped_nsobject<CALayer> layer([[ThumbnailLayer alloc]
+ initWithTabContents:tile.tab_contents()
+ fullSize:tile.GetStartRectRelativeTo(
+ tileSet_->selected_tile()).size]);
+ [layer setNeedsDisplay];
+
+ NSTimeInterval interval =
+ kDefaultAnimationDuration * (slomo ? kSlomoFactor : 1);
+
+ // Background color as placeholder for now.
+ layer.get().backgroundColor = CGColorGetConstantColor(kCGColorWhite);
+ if (showZoom) {
+ AnimateCALayerFrameFromTo(
+ layer,
+ tile.GetStartRectRelativeTo(tileSet_->selected_tile()),
+ tile.thumb_rect(),
+ interval,
+ animationDelegate);
+ } else {
+ layer.get().frame = NSRectToCGRect(tile.thumb_rect());
+ }
+
+ layer.get().shadowRadius = 10;
+ layer.get().shadowOffset = CGSizeMake(0, -10);
+ if (state_ == tabpose::kFadedIn)
+ layer.get().shadowOpacity = 0.5;
+
+ [bgLayer_ addSublayer:layer];
+ [allThumbnailLayers_ addObject:layer];
+
+ // Favicon and title.
+ NSFont* font = [NSFont systemFontOfSize:tile.title_font_size()];
+ tile.set_font_metrics([font ascender], -[font descender]);
+
+ NSImage* nsFavicon = gfx::SkBitmapToNSImage(tile.favicon());
+ // Either we don't have a valid favicon or there was some issue converting
+ // it from an SkBitmap. Either way, just show the default.
+ if (!nsFavicon) {
+ NSImage* defaultFavIcon =
+ ResourceBundle::GetSharedInstance().GetNativeImageNamed(
+ IDR_DEFAULT_FAVICON);
+ nsFavicon = defaultFavIcon;
+ }
+ base::mac::ScopedCFTypeRef<CGImageRef> favicon(
+ mac_util::CopyNSImageToCGImage(nsFavicon));
+
+ CALayer* faviconLayer = [CALayer layer];
+ if (showZoom) {
+ AnimateCALayerFrameFromTo(
+ faviconLayer,
+ tile.GetFaviconStartRectRelativeTo(tileSet_->selected_tile()),
+ tile.favicon_rect(),
+ interval,
+ nil);
+ AnimateCALayerOpacityFromTo(faviconLayer, 0.0, 1.0, interval);
+ } else {
+ faviconLayer.frame = NSRectToCGRect(tile.favicon_rect());
+ }
+ faviconLayer.contents = (id)favicon.get();
+ faviconLayer.zPosition = 1; // On top of the thumb shadow.
+ [bgLayer_ addSublayer:faviconLayer];
+ [allFaviconLayers_ addObject:faviconLayer];
+
+ // CATextLayers can't animate their fontSize property, at least on 10.5.
+ // Animate transform.scale instead.
+
+ // The scaling should have its origin in the layer's upper left corner.
+ // This needs to be set before |AnimateCALayerFrameFromTo()| is called.
+ CATextLayer* titleLayer = [CATextLayer layer];
+ titleLayer.anchorPoint = CGPointMake(0, 1);
+ if (showZoom) {
+ NSRect fromRect =
+ tile.GetTitleStartRectRelativeTo(tileSet_->selected_tile());
+ NSRect toRect = tile.title_rect();
+ CGFloat scale = NSWidth(fromRect) / NSWidth(toRect);
+ fromRect.size = toRect.size;
+
+ // Add scale animation.
+ CABasicAnimation* scaleAnimation =
+ [CABasicAnimation animationWithKeyPath:@"transform.scale"];
+ scaleAnimation.fromValue = [NSNumber numberWithDouble:scale];
+ scaleAnimation.toValue = [NSNumber numberWithDouble:1.0];
+ scaleAnimation.duration = interval;
+ scaleAnimation.timingFunction =
+ [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
+ [titleLayer addAnimation:scaleAnimation forKey:@"transform.scale"];
+
+ // Add the position and opacity animations.
+ AnimateScaledCALayerFrameFromTo(
+ titleLayer, fromRect, scale, toRect, 1.0, interval, nil);
+ AnimateCALayerOpacityFromTo(faviconLayer, 0.0, 1.0, interval);
+ } else {
+ titleLayer.frame = NSRectToCGRect(tile.title_rect());
+ }
+ titleLayer.string = base::SysUTF16ToNSString(tile.title());
+ titleLayer.fontSize = [font pointSize];
+ titleLayer.truncationMode = kCATruncationEnd;
+ titleLayer.font = font;
+ titleLayer.zPosition = 1; // On top of the thumb shadow.
+ [bgLayer_ addSublayer:titleLayer];
+ [allTitleLayers_ addObject:titleLayer];
+}
+
+- (void)setUpLayersInSlomo:(BOOL)slomo {
+ // Root layer -- covers whole window.
+ rootLayer_ = [CALayer layer];
+
+ // In a block so that the layers don't fade in.
+ {
+ ScopedCAActionDisabler disabler;
+ // Background layer -- the visible part of the window.
+ gray_.reset(CGColorCreateGenericGray(0.39, 1.0));
+ bgLayer_ = [CALayer layer];
+ bgLayer_.backgroundColor = gray_;
+ bgLayer_.frame = NSRectToCGRect(containingRect_);
+ bgLayer_.masksToBounds = YES;
+ [rootLayer_ addSublayer:bgLayer_];
+
+ // Selection highlight layer.
+ darkBlue_.reset(CGColorCreateGenericRGB(0.25, 0.34, 0.86, 1.0));
+ selectionHighlight_ = [CALayer layer];
+ selectionHighlight_.backgroundColor = darkBlue_;
+ selectionHighlight_.cornerRadius = 5.0;
+ selectionHighlight_.zPosition = -1; // Behind other layers.
+ selectionHighlight_.hidden = YES;
+ [bgLayer_ addSublayer:selectionHighlight_];
+
+ // Top gradient.
+ CALayer* gradientLayer = [DarkGradientLayer layer];
+ gradientLayer.frame = CGRectMake(
+ 0,
+ NSHeight(containingRect_) - kTopGradientHeight,
+ NSWidth(containingRect_),
+ kTopGradientHeight);
+ [gradientLayer setNeedsDisplay]; // Draw once.
+ [bgLayer_ addSublayer:gradientLayer];
+ }
+
+ // Layers for the tab thumbnails.
+ tileSet_->Build(tabStripModel_);
+ tileSet_->Layout(containingRect_);
+ allThumbnailLayers_.reset(
+ [[NSMutableArray alloc] initWithCapacity:tabStripModel_->count()]);
+ allFaviconLayers_.reset(
+ [[NSMutableArray alloc] initWithCapacity:tabStripModel_->count()]);
+ allTitleLayers_.reset(
+ [[NSMutableArray alloc] initWithCapacity:tabStripModel_->count()]);
+
+ for (int i = 0; i < tabStripModel_->count(); ++i) {
+ // Add a delegate to one of the animations to get a notification once the
+ // animations are done.
+ [self addLayersForTile:tileSet_->tile_at(i)
+ showZoom:YES
+ slomo:slomo
+ animationDelegate:i == tileSet_->selected_index() ? self : nil];
+ if (i == tileSet_->selected_index()) {
+ CALayer* layer = [allThumbnailLayers_ objectAtIndex:i];
+ CAAnimation* animation = [layer animationForKey:@"bounds"];
+ DCHECK(animation);
+ [animation setValue:kAnimationIdFadeIn forKey:kAnimationIdKey];
+ }
+ }
+ [self selectTileAtIndexWithoutAnimation:tileSet_->selected_index()];
+
+ // Needs to happen after all layers have been added to |rootLayer_|, else
+ // there's a one frame flash of grey at the beginning of the animation
+ // (|bgLayer_| showing through with none of its children visible yet).
+ [[self contentView] setLayer:rootLayer_];
+ [[self contentView] setWantsLayer:YES];
+}
+
+- (BOOL)canBecomeKeyWindow {
+ return YES;
+}
+
+// Handle key events that should be executed repeatedly while the key is down.
+- (void)keyDown:(NSEvent*)event {
+ if (state_ == tabpose::kFadingOut)
+ return;
+ NSString* characters = [event characters];
+ if ([characters length] < 1)
+ return;
+
+ unichar character = [characters characterAtIndex:0];
+ int newIndex = -1;
+ switch (character) {
+ case NSUpArrowFunctionKey:
+ newIndex = tileSet_->up_index();
+ break;
+ case NSDownArrowFunctionKey:
+ newIndex = tileSet_->down_index();
+ break;
+ case NSLeftArrowFunctionKey:
+ newIndex = tileSet_->left_index();
+ break;
+ case NSRightArrowFunctionKey:
+ newIndex = tileSet_->right_index();
+ break;
+ case NSTabCharacter:
+ newIndex = tileSet_->next_index();
+ break;
+ case NSBackTabCharacter:
+ newIndex = tileSet_->previous_index();
+ break;
+ }
+ if (newIndex != -1)
+ [self selectTileAtIndexWithoutAnimation:newIndex];
+}
+
+// Handle keyboard events that should be executed once when the key is released.
+- (void)keyUp:(NSEvent*)event {
+ if (state_ == tabpose::kFadingOut)
+ return;
+ NSString* characters = [event characters];
+ if ([characters length] < 1)
+ return;
+
+ unichar character = [characters characterAtIndex:0];
+ switch (character) {
+ case NSEnterCharacter:
+ case NSNewlineCharacter:
+ case NSCarriageReturnCharacter:
+ case ' ':
+ [self fadeAway:([event modifierFlags] & NSShiftKeyMask) != 0];
+ break;
+ case '\e': // Escape
+ tileSet_->set_selected_index(tabStripModel_->selected_index());
+ [self fadeAway:([event modifierFlags] & NSShiftKeyMask) != 0];
+ break;
+ }
+}
+
+// Handle keyboard events that contain cmd or ctrl.
+- (BOOL)performKeyEquivalent:(NSEvent*)event {
+ if (state_ == tabpose::kFadingOut)
+ return NO;
+ NSString* characters = [event characters];
+ if ([characters length] < 1)
+ return NO;
+ unichar character = [characters characterAtIndex:0];
+ if ([event modifierFlags] & NSCommandKeyMask) {
+ if (character >= '1' && character <= '9') {
+ int index =
+ character == '9' ? tabStripModel_->count() - 1 : character - '1';
+ if (index < tabStripModel_->count()) {
+ tileSet_->set_selected_index(index);
+ [self fadeAway:([event modifierFlags] & NSShiftKeyMask) != 0];
+ return YES;
+ }
+ }
+ }
+ return NO;
+}
+
+-(void)selectTileFromMouseEvent:(NSEvent*)event {
+ int newIndex = -1;
+ CGPoint p = NSPointToCGPoint([event locationInWindow]);
+ for (NSUInteger i = 0; i < [allThumbnailLayers_ count]; ++i) {
+ CALayer* layer = [allThumbnailLayers_ objectAtIndex:i];
+ CGPoint lp = [layer convertPoint:p fromLayer:rootLayer_];
+ if ([static_cast<CALayer*>([layer presentationLayer]) containsPoint:lp])
+ newIndex = i;
+ }
+ if (newIndex >= 0)
+ [self selectTileAtIndexWithoutAnimation:newIndex];
+}
+
+- (void)mouseMoved:(NSEvent*)event {
+ [self selectTileFromMouseEvent:event];
+}
+
+- (void)mouseDown:(NSEvent*)event {
+ // Just in case the user clicked without ever moving the mouse.
+ [self selectTileFromMouseEvent:event];
+
+ [self fadeAway:([event modifierFlags] & NSShiftKeyMask) != 0];
+}
+
+- (void)swipeWithEvent:(NSEvent*)event {
+ if (abs([event deltaY]) > 0.5) // Swipe up or down.
+ [self fadeAway:([event modifierFlags] & NSShiftKeyMask) != 0];
+}
+
+- (void)close {
+ // Prevent parent window from disappearing.
+ [[self parentWindow] removeChildWindow:self];
+
+ // We're dealloc'd in an autorelease pool – by then the observer registry
+ // might be dead, so explicitly reset the observer now.
+ tabStripModelObserverBridge_.reset();
+
+ [super close];
+}
+
+- (void)commandDispatch:(id)sender {
+ if ([sender tag] == IDC_TABPOSE)
+ [self fadeAway:NO];
+}
+
+- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
+ // Disable all browser-related menu items except the tab overview toggle.
+ SEL action = [item action];
+ NSInteger tag = [item tag];
+ return action == @selector(commandDispatch:) && tag == IDC_TABPOSE;
+}
+
+- (void)fadeAwayTileAtIndex:(int)index {
+ const tabpose::Tile& tile = tileSet_->tile_at(index);
+ CALayer* layer = [allThumbnailLayers_ objectAtIndex:index];
+ // Add a delegate to one of the implicit animations to get a notification
+ // once the animations are done.
+ if (static_cast<int>(index) == tileSet_->selected_index()) {
+ CAAnimation* animation = [CAAnimation animation];
+ animation.delegate = self;
+ [animation setValue:kAnimationIdFadeOut forKey:kAnimationIdKey];
+ [layer addAnimation:animation forKey:@"frame"];
+ }
+
+ // Thumbnail.
+ layer.frame = NSRectToCGRect(
+ tile.GetStartRectRelativeTo(tileSet_->selected_tile()));
+
+ if (static_cast<int>(index) == tileSet_->selected_index()) {
+ // Redraw layer at big resolution, so that zoom-in isn't blocky.
+ [layer setNeedsDisplay];
+ }
+
+ // Title.
+ CALayer* faviconLayer = [allFaviconLayers_ objectAtIndex:index];
+ faviconLayer.frame = NSRectToCGRect(
+ tile.GetFaviconStartRectRelativeTo(tileSet_->selected_tile()));
+ faviconLayer.opacity = 0;
+
+ // Favicon.
+ // The |fontSize| cannot be animated directly, animate the layer's scale
+ // instead. |transform.scale| affects the rendered width, so keep the small
+ // bounds.
+ CALayer* titleLayer = [allTitleLayers_ objectAtIndex:index];
+ NSRect titleRect = tile.title_rect();
+ NSRect titleToRect =
+ tile.GetTitleStartRectRelativeTo(tileSet_->selected_tile());
+ CGFloat scale = NSWidth(titleToRect) / NSWidth(titleRect);
+ titleToRect.origin.x +=
+ NSWidth(titleRect) * scale * titleLayer.anchorPoint.x;
+ titleToRect.origin.y +=
+ NSHeight(titleRect) * scale * titleLayer.anchorPoint.y;
+ titleLayer.position = NSPointToCGPoint(titleToRect.origin);
+ [titleLayer setValue:[NSNumber numberWithDouble:scale]
+ forKeyPath:@"transform.scale"];
+ titleLayer.opacity = 0;
+}
+
+- (void)fadeAway:(BOOL)slomo {
+ if (state_ == tabpose::kFadingOut)
+ return;
+
+ state_ = tabpose::kFadingOut;
+ [self setAcceptsMouseMovedEvents:NO];
+
+ // Select chosen tab.
+ if (tileSet_->selected_index() < tabStripModel_->count()) {
+ tabStripModel_->SelectTabContentsAt(tileSet_->selected_index(),
+ /*user_gesture=*/true);
+ } else {
+ DCHECK_EQ(tileSet_->selected_index(), 0);
+ }
+
+ {
+ ScopedCAActionDisabler disableCAActions;
+
+ // Move the selected layer on top of all other layers.
+ [self selectedLayer].zPosition = 1;
+
+ selectionHighlight_.hidden = YES;
+ // Running animations with shadows is slow, so turn shadows off before
+ // running the exit animation.
+ for (CALayer* layer in allThumbnailLayers_.get())
+ layer.shadowOpacity = 0.0;
+ }
+
+ // Animate layers out, all in one transaction.
+ CGFloat duration =
+ 1.3 * kDefaultAnimationDuration * (slomo ? kSlomoFactor : 1);
+ ScopedCAActionSetDuration durationSetter(duration);
+ for (int i = 0; i < tabStripModel_->count(); ++i)
+ [self fadeAwayTileAtIndex:i];
+}
+
+- (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)finished {
+ NSString* animationId = [animation valueForKey:kAnimationIdKey];
+ if ([animationId isEqualToString:kAnimationIdFadeIn]) {
+ if (finished && state_ == tabpose::kFadingIn) {
+ // If the user clicks while the fade in animation is still running,
+ // |state_| is already kFadingOut. In that case, don't do anything.
+ state_ = tabpose::kFadedIn;
+
+ selectionHighlight_.hidden = NO;
+
+ // Running animations with shadows is slow, so turn shadows on only after
+ // the animation is done.
+ ScopedCAActionDisabler disableCAActions;
+ for (CALayer* layer in allThumbnailLayers_.get())
+ layer.shadowOpacity = 0.5;
+ }
+ } else if ([animationId isEqualToString:kAnimationIdFadeOut]) {
+ DCHECK_EQ(tabpose::kFadingOut, state_);
+ [self close];
+ }
+}
+
+- (NSUInteger)thumbnailLayerCount {
+ return [allThumbnailLayers_ count];
+}
+
+- (int)selectedIndex {
+ return tileSet_->selected_index();
+}
+
+#pragma mark TabStripModelBridge
+
+- (void)refreshLayerFramesAtIndex:(int)i {
+ const tabpose::Tile& tile = tileSet_->tile_at(i);
+
+ CALayer* faviconLayer = [allFaviconLayers_ objectAtIndex:i];
+ faviconLayer.frame = NSRectToCGRect(tile.favicon_rect());
+ CALayer* titleLayer = [allTitleLayers_ objectAtIndex:i];
+ titleLayer.frame = NSRectToCGRect(tile.title_rect());
+ CALayer* thumbLayer = [allThumbnailLayers_ objectAtIndex:i];
+ thumbLayer.frame = NSRectToCGRect(tile.thumb_rect());
+}
+
+- (void)insertTabWithContents:(TabContentsWrapper*)contents
+ atIndex:(NSInteger)index
+ inForeground:(bool)inForeground {
+ // This happens if you cmd-click a link and then immediately open tabpose
+ // on a slowish machine.
+ ScopedCAActionSetDuration durationSetter(kObserverChangeAnimationDuration);
+
+ // Insert new layer and relayout.
+ tileSet_->InsertTileAt(index, contents->tab_contents());
+ tileSet_->Layout(containingRect_);
+ [self addLayersForTile:tileSet_->tile_at(index)
+ showZoom:NO
+ slomo:NO
+ animationDelegate:nil];
+
+ // Update old layers.
+ DCHECK_EQ(tabStripModel_->count(),
+ static_cast<int>([allThumbnailLayers_ count]));
+ DCHECK_EQ(tabStripModel_->count(),
+ static_cast<int>([allTitleLayers_ count]));
+ DCHECK_EQ(tabStripModel_->count(),
+ static_cast<int>([allFaviconLayers_ count]));
+
+ for (int i = 0; i < tabStripModel_->count(); ++i) {
+ if (i == index) // The new layer.
+ continue;
+ [self refreshLayerFramesAtIndex:i];
+ }
+
+ // Update selection.
+ int selectedIndex = tileSet_->selected_index();
+ if (selectedIndex >= index)
+ selectedIndex++;
+ [self selectTileAtIndex:selectedIndex];
+}
+
+- (void)tabClosingWithContents:(TabContentsWrapper*)contents
+ atIndex:(NSInteger)index {
+ // We will also get a -tabDetachedWithContents:atIndex: notification for
+ // closing tabs, so do nothing here.
+}
+
+- (void)tabDetachedWithContents:(TabContentsWrapper*)contents
+ atIndex:(NSInteger)index {
+ ScopedCAActionSetDuration durationSetter(kObserverChangeAnimationDuration);
+
+ // Remove layer and relayout.
+ tileSet_->RemoveTileAt(index);
+ tileSet_->Layout(containingRect_);
+
+ [[allThumbnailLayers_ objectAtIndex:index] removeFromSuperlayer];
+ [allThumbnailLayers_ removeObjectAtIndex:index];
+ [[allTitleLayers_ objectAtIndex:index] removeFromSuperlayer];
+ [allTitleLayers_ removeObjectAtIndex:index];
+ [[allFaviconLayers_ objectAtIndex:index] removeFromSuperlayer];
+ [allFaviconLayers_ removeObjectAtIndex:index];
+
+ // Update old layers.
+ DCHECK_EQ(tabStripModel_->count(),
+ static_cast<int>([allThumbnailLayers_ count]));
+ DCHECK_EQ(tabStripModel_->count(),
+ static_cast<int>([allTitleLayers_ count]));
+ DCHECK_EQ(tabStripModel_->count(),
+ static_cast<int>([allFaviconLayers_ count]));
+
+ if (tabStripModel_->count() == 0)
+ [self close];
+
+ for (int i = 0; i < tabStripModel_->count(); ++i)
+ [self refreshLayerFramesAtIndex:i];
+
+ // Update selection.
+ int selectedIndex = tileSet_->selected_index();
+ if (selectedIndex >= index)
+ selectedIndex--;
+ if (selectedIndex >= 0)
+ [self selectTileAtIndex:selectedIndex];
+}
+
+- (void)tabMovedWithContents:(TabContentsWrapper*)contents
+ fromIndex:(NSInteger)from
+ toIndex:(NSInteger)to {
+ ScopedCAActionSetDuration durationSetter(kObserverChangeAnimationDuration);
+
+ // Move tile from |from| to |to|.
+ tileSet_->MoveTileFromTo(from, to);
+
+ // Move corresponding layers from |from| to |to|.
+ scoped_nsobject<CALayer> thumbLayer(
+ [[allThumbnailLayers_ objectAtIndex:from] retain]);
+ [allThumbnailLayers_ removeObjectAtIndex:from];
+ [allThumbnailLayers_ insertObject:thumbLayer.get() atIndex:to];
+ scoped_nsobject<CALayer> faviconLayer(
+ [[allFaviconLayers_ objectAtIndex:from] retain]);
+ [allFaviconLayers_ removeObjectAtIndex:from];
+ [allFaviconLayers_ insertObject:faviconLayer.get() atIndex:to];
+ scoped_nsobject<CALayer> titleLayer(
+ [[allTitleLayers_ objectAtIndex:from] retain]);
+ [allTitleLayers_ removeObjectAtIndex:from];
+ [allTitleLayers_ insertObject:titleLayer.get() atIndex:to];
+
+ // Update frames of the layers.
+ for (int i = std::min(from, to); i <= std::max(from, to); ++i)
+ [self refreshLayerFramesAtIndex:i];
+
+ // Update selection.
+ int selectedIndex = tileSet_->selected_index();
+ if (from == selectedIndex)
+ selectedIndex = to;
+ else if (from < selectedIndex && selectedIndex <= to)
+ selectedIndex--;
+ else if (to <= selectedIndex && selectedIndex < from)
+ selectedIndex++;
+ [self selectTileAtIndex:selectedIndex];
+}
+
+- (void)tabChangedWithContents:(TabContentsWrapper*)contents
+ atIndex:(NSInteger)index
+ changeType:(TabStripModelObserver::TabChangeType)change {
+ // Tell the window to update text, title, and thumb layers at |index| to get
+ // their data from |contents|. |contents| can be different from the old
+ // contents at that index!
+ // While a tab is loading, this is unfortunately called quite often for
+ // both the "loading" and the "all" change types, so we don't really want to
+ // send thumb requests to the corresponding renderer when this is called.
+ // For now, just make sure that we don't hold on to an invalid TabContents
+ // object.
+ tabpose::Tile& tile = tileSet_->tile_at(index);
+ if (contents->tab_contents() == tile.tab_contents()) {
+ // TODO(thakis): Install a timer to send a thumb request/update title/update
+ // favicon after 20ms or so, and reset the timer every time this is called
+ // to make sure we get an updated thumb, without requesting them all over.
+ return;
+ }
+
+ tile.set_tab_contents(contents->tab_contents());
+ ThumbnailLayer* thumbLayer = [allThumbnailLayers_ objectAtIndex:index];
+ [thumbLayer setTabContents:contents->tab_contents()];
+}
+
+- (void)tabStripModelDeleted {
+ [self close];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/tabpose_window_unittest.mm b/chrome/browser/ui/cocoa/tabpose_window_unittest.mm
new file mode 100644
index 0000000..97ba095
--- /dev/null
+++ b/chrome/browser/ui/cocoa/tabpose_window_unittest.mm
@@ -0,0 +1,119 @@
+// 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 "chrome/browser/ui/cocoa/tabpose_window.h"
+
+#import "chrome/browser/browser_window.h"
+#include "chrome/browser/renderer_host/site_instance.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
+#import "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class TabposeWindowTest : public CocoaTest {
+ public:
+ TabposeWindowTest() {
+ site_instance_ =
+ SiteInstance::CreateSiteInstance(browser_helper_.profile());
+ }
+
+ void AppendTabToStrip() {
+ TabContentsWrapper* tab_contents = Browser::TabContentsFactory(
+ browser_helper_.profile(), site_instance_, MSG_ROUTING_NONE,
+ NULL, NULL);
+ browser_helper_.browser()->tabstrip_model()->AppendTabContents(
+ tab_contents, /*foreground=*/true);
+ }
+
+ BrowserTestHelper browser_helper_;
+ scoped_refptr<SiteInstance> site_instance_;
+};
+
+// Check that this doesn't leak.
+TEST_F(TabposeWindowTest, TestShow) {
+ BrowserWindow* browser_window = browser_helper_.CreateBrowserWindow();
+ NSWindow* parent = browser_window->GetNativeHandle();
+
+ [parent orderFront:nil];
+ EXPECT_TRUE([parent isVisible]);
+
+ // Add a few tabs to the tab strip model.
+ for (int i = 0; i < 3; ++i)
+ AppendTabToStrip();
+
+ base::mac::ScopedNSAutoreleasePool pool;
+ TabposeWindow* window =
+ [TabposeWindow openTabposeFor:parent
+ rect:NSMakeRect(10, 20, 250, 160)
+ slomo:NO
+ tabStripModel:browser_helper_.browser()->tabstrip_model()];
+
+ // Should release the window.
+ [window mouseDown:nil];
+
+ browser_helper_.CloseBrowserWindow();
+}
+
+TEST_F(TabposeWindowTest, TestModelObserver) {
+ BrowserWindow* browser_window = browser_helper_.CreateBrowserWindow();
+ NSWindow* parent = browser_window->GetNativeHandle();
+ [parent orderFront:nil];
+
+ // Add a few tabs to the tab strip model.
+ for (int i = 0; i < 3; ++i)
+ AppendTabToStrip();
+
+ base::mac::ScopedNSAutoreleasePool pool;
+ TabposeWindow* window =
+ [TabposeWindow openTabposeFor:parent
+ rect:NSMakeRect(10, 20, 250, 160)
+ slomo:NO
+ tabStripModel:browser_helper_.browser()->tabstrip_model()];
+
+ // Exercise all the model change events.
+ TabStripModel* model = browser_helper_.browser()->tabstrip_model();
+ DCHECK_EQ([window thumbnailLayerCount], 3u);
+ DCHECK_EQ([window selectedIndex], 2);
+
+ model->MoveTabContentsAt(0, 2, /*select_after_move=*/false);
+ DCHECK_EQ([window thumbnailLayerCount], 3u);
+ DCHECK_EQ([window selectedIndex], 1);
+
+ model->MoveTabContentsAt(2, 0, /*select_after_move=*/false);
+ DCHECK_EQ([window thumbnailLayerCount], 3u);
+ DCHECK_EQ([window selectedIndex], 2);
+
+ [window selectTileAtIndexWithoutAnimation:0];
+ DCHECK_EQ([window selectedIndex], 0);
+
+ model->MoveTabContentsAt(0, 2, /*select_after_move=*/false);
+ DCHECK_EQ([window selectedIndex], 2);
+
+ model->MoveTabContentsAt(2, 0, /*select_after_move=*/false);
+ DCHECK_EQ([window selectedIndex], 0);
+
+ delete model->DetachTabContentsAt(0);
+ DCHECK_EQ([window thumbnailLayerCount], 2u);
+ DCHECK_EQ([window selectedIndex], 0);
+
+ AppendTabToStrip();
+ DCHECK_EQ([window thumbnailLayerCount], 3u);
+ DCHECK_EQ([window selectedIndex], 0);
+
+ model->CloseTabContentsAt(0, TabStripModel::CLOSE_NONE);
+ DCHECK_EQ([window thumbnailLayerCount], 2u);
+ DCHECK_EQ([window selectedIndex], 0);
+
+ [window selectTileAtIndexWithoutAnimation:1];
+ model->CloseTabContentsAt(0, TabStripModel::CLOSE_NONE);
+ DCHECK_EQ([window thumbnailLayerCount], 1u);
+ DCHECK_EQ([window selectedIndex], 0);
+
+ // Should release the window.
+ [window mouseDown:nil];
+
+ browser_helper_.CloseBrowserWindow();
+}
diff --git a/chrome/browser/ui/cocoa/task_helpers.h b/chrome/browser/ui/cocoa/task_helpers.h
new file mode 100644
index 0000000..e29c068
--- /dev/null
+++ b/chrome/browser/ui/cocoa/task_helpers.h
@@ -0,0 +1,29 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_TASK_HELPERS_H_
+#define CHROME_BROWSER_UI_COCOA_TASK_HELPERS_H_
+#pragma once
+
+class Task;
+
+namespace tracked_objects {
+class Location;
+} // namespace tracked_objects
+
+namespace cocoa_utils {
+
+// This can be used in place of BrowserThread::PostTask(BrowserThread::UI, ...).
+// The purpose of this function is to be able to execute Task work alongside
+// native work when a MessageLoop is blocked by a nested run loop. This function
+// will run the Task in both NSEventTrackingRunLoopMode and NSDefaultRunLoopMode
+// for the purpose of executing work while a menu is open. See
+// http://crbug.com/48679 for the full rationale.
+bool PostTaskInEventTrackingRunLoopMode(
+ const tracked_objects::Location& from_here,
+ Task* task);
+
+} // namespace cocoa_utils
+
+#endif // CHROME_BROWSER_UI_COCOA_TASK_HELPERS_H_
diff --git a/chrome/browser/ui/cocoa/task_helpers.mm b/chrome/browser/ui/cocoa/task_helpers.mm
new file mode 100644
index 0000000..2f8df18
--- /dev/null
+++ b/chrome/browser/ui/cocoa/task_helpers.mm
@@ -0,0 +1,57 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/task_helpers.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_ptr.h"
+#include "base/task.h"
+
+// This is a wrapper for running Task objects from within a native run loop.
+// This can run specific tasks in that nested loop. This owns the task and will
+// delete it and itself when done.
+@interface NativeTaskRunner : NSObject {
+ @private
+ scoped_ptr<Task> task_;
+}
+- (id)initWithTask:(Task*)task;
+- (void)runTask;
+@end
+
+@implementation NativeTaskRunner
+- (id)initWithTask:(Task*)task {
+ if ((self = [super init])) {
+ task_.reset(task);
+ }
+ return self;
+}
+
+- (void)runTask {
+ task_->Run();
+ [self autorelease];
+}
+@end
+
+namespace cocoa_utils {
+
+bool PostTaskInEventTrackingRunLoopMode(
+ const tracked_objects::Location& from_here,
+ Task* task) {
+ // This deletes itself and the task after the task runs.
+ NativeTaskRunner* runner = [[NativeTaskRunner alloc] initWithTask:task];
+
+ // Schedule the selector in multiple modes in case this was called while a
+ // menu was not running.
+ NSArray* modes = [NSArray arrayWithObjects:NSEventTrackingRunLoopMode,
+ NSDefaultRunLoopMode,
+ nil];
+ [runner performSelectorOnMainThread:@selector(runTask)
+ withObject:nil
+ waitUntilDone:NO
+ modes:modes];
+ return true;
+}
+
+} // namespace cocoa_utils
diff --git a/chrome/browser/ui/cocoa/task_manager_mac.h b/chrome/browser/ui/cocoa/task_manager_mac.h
new file mode 100644
index 0000000..75c9811
--- /dev/null
+++ b/chrome/browser/ui/cocoa/task_manager_mac.h
@@ -0,0 +1,118 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_TASK_MANAGER_MAC_H_
+#define CHROME_BROWSER_UI_COCOA_TASK_MANAGER_MAC_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+#include <vector>
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_nsobject.h"
+#include "chrome/browser/task_manager/task_manager.h"
+#include "chrome/browser/ui/cocoa/table_row_nsimage_cache.h"
+
+@class WindowSizeAutosaver;
+class SkBitmap;
+class TaskManagerMac;
+
+// This class is responsible for loading the task manager window and for
+// managing it.
+@interface TaskManagerWindowController :
+ NSWindowController<NSTableViewDataSource,
+ NSTableViewDelegate> {
+ @private
+ IBOutlet NSTableView* tableView_;
+ IBOutlet NSButton* endProcessButton_;
+ TaskManagerMac* taskManagerObserver_; // weak
+ TaskManager* taskManager_; // weak
+ TaskManagerModel* model_; // weak
+
+ scoped_nsobject<WindowSizeAutosaver> size_saver_;
+
+ // These contain a permutation of [0..|model_->ResourceCount() - 1|]. Used to
+ // implement sorting.
+ std::vector<int> viewToModelMap_;
+ std::vector<int> modelToViewMap_;
+
+ // Descriptor of the current sort column.
+ scoped_nsobject<NSSortDescriptor> currentSortDescriptor_;
+}
+
+// Creates and shows the task manager's window.
+- (id)initWithTaskManagerObserver:(TaskManagerMac*)taskManagerObserver;
+
+// Refreshes all data in the task manager table.
+- (void)reloadData;
+
+// Callback for "Stats for nerds" link.
+- (IBAction)statsLinkClicked:(id)sender;
+
+// Callback for "End process" button.
+- (IBAction)killSelectedProcesses:(id)sender;
+
+// Callback for double clicks on the table.
+- (void)selectDoubleClickedTab:(id)sender;
+@end
+
+@interface TaskManagerWindowController (TestingAPI)
+- (NSTableView*)tableView;
+@end
+
+// This class listens to task changed events sent by chrome.
+class TaskManagerMac : public TaskManagerModelObserver,
+ public TableRowNSImageCache::Table {
+ public:
+ TaskManagerMac(TaskManager* task_manager);
+ virtual ~TaskManagerMac();
+
+ // TaskManagerModelObserver
+ virtual void OnModelChanged();
+ virtual void OnItemsChanged(int start, int length);
+ virtual void OnItemsAdded(int start, int length);
+ virtual void OnItemsRemoved(int start, int length);
+
+ // Called by the cocoa window controller when its window closes and the
+ // controller destroyed itself. Informs the model to stop updating.
+ void WindowWasClosed();
+
+ // TableRowNSImageCache::Table
+ virtual int RowCount() const;
+ virtual SkBitmap GetIcon(int r) const;
+
+ // Creates the task manager if it doesn't exist; otherwise, it activates the
+ // existing task manager window.
+ static void Show();
+
+ // Returns the TaskManager observed by |this|.
+ TaskManager* task_manager() { return task_manager_; }
+
+ // Lazily converts the image at the given row and caches it in |icon_cache_|.
+ NSImage* GetImageForRow(int row);
+
+ // Returns the cocoa object. Used for testing.
+ TaskManagerWindowController* cocoa_controller() { return window_controller_; }
+ private:
+ // The task manager.
+ TaskManager* const task_manager_; // weak
+
+ // Our model.
+ TaskManagerModel* const model_; // weak
+
+ // Controller of our window, destroys itself when the task manager window
+ // is closed.
+ TaskManagerWindowController* window_controller_; // weak
+
+ // Caches favicons for all rows. Needs to be initalized after |model_|.
+ TableRowNSImageCache icon_cache_;
+
+ // An open task manager window. There can only be one open at a time. This
+ // is reset to NULL when the window is closed.
+ static TaskManagerMac* instance_;
+
+ DISALLOW_COPY_AND_ASSIGN(TaskManagerMac);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_TASK_MANAGER_MAC_H_
diff --git a/chrome/browser/ui/cocoa/task_manager_mac.mm b/chrome/browser/ui/cocoa/task_manager_mac.mm
new file mode 100644
index 0000000..c11564c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/task_manager_mac.mm
@@ -0,0 +1,582 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/task_manager_mac.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "app/l10n_util_mac.h"
+#include "base/mac_util.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/browser_process.h"
+#import "chrome/browser/ui/cocoa/window_size_autosaver.h"
+#include "chrome/common/pref_names.h"
+#include "grit/generated_resources.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace {
+
+// Width of "a" and most other letters/digits in "small" table views.
+const int kCharWidth = 6;
+
+// Some of the strings below have spaces at the end or are missing letters, to
+// make the columns look nicer, and to take potentially longer localized strings
+// into account.
+const struct ColumnWidth {
+ int columnId;
+ int minWidth;
+ int maxWidth; // If this is -1, 1.5*minColumWidth is used as max width.
+} columnWidths[] = {
+ // Note that arraysize includes the trailing \0. That's intended.
+ { IDS_TASK_MANAGER_PAGE_COLUMN, 120, 600 },
+ { IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN,
+ arraysize("800 MiB") * kCharWidth, -1 },
+ { IDS_TASK_MANAGER_SHARED_MEM_COLUMN,
+ arraysize("800 MiB") * kCharWidth, -1 },
+ { IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN,
+ arraysize("800 MiB") * kCharWidth, -1 },
+ { IDS_TASK_MANAGER_CPU_COLUMN,
+ arraysize("99.9") * kCharWidth, -1 },
+ { IDS_TASK_MANAGER_NET_COLUMN,
+ arraysize("150 kiB/s") * kCharWidth, -1 },
+ { IDS_TASK_MANAGER_PROCESS_ID_COLUMN,
+ arraysize("73099 ") * kCharWidth, -1 },
+ { IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN,
+ arraysize("2000.0K (2000.0 live)") * kCharWidth, -1 },
+ { IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN,
+ arraysize("2000.0K (2000.0 live)") * kCharWidth, -1 },
+ { IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN,
+ arraysize("2000.0K (2000.0 live)") * kCharWidth, -1 },
+ { IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN,
+ arraysize("800 kB") * kCharWidth, -1 },
+ { IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN,
+ arraysize("2000.0K (2000.0 live)") * kCharWidth, -1 },
+ { IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN,
+ arraysize("15 ") * kCharWidth, -1 },
+};
+
+class SortHelper {
+ public:
+ SortHelper(TaskManagerModel* model, NSSortDescriptor* column)
+ : sort_column_([[column key] intValue]),
+ ascending_([column ascending]),
+ model_(model) {}
+
+ bool operator()(int a, int b) {
+ std::pair<int, int> group_range1 = model_->GetGroupRangeForResource(a);
+ std::pair<int, int> group_range2 = model_->GetGroupRangeForResource(b);
+ if (group_range1 == group_range2) {
+ // The two rows are in the same group, sort so that items in the same
+ // group always appear in the same order. |ascending_| is intentionally
+ // ignored.
+ return a < b;
+ }
+ // Sort by the first entry of each of the groups.
+ int cmp_result = model_->CompareValues(
+ group_range1.first, group_range2.first, sort_column_);
+ if (!ascending_)
+ cmp_result = -cmp_result;
+ return cmp_result < 0;
+ }
+ private:
+ int sort_column_;
+ bool ascending_;
+ TaskManagerModel* model_; // weak;
+};
+
+} // namespace
+
+@interface TaskManagerWindowController (Private)
+- (NSTableColumn*)addColumnWithId:(int)columnId visible:(BOOL)isVisible;
+- (void)setUpTableColumns;
+- (void)setUpTableHeaderContextMenu;
+- (void)toggleColumn:(id)sender;
+- (void)adjustSelectionAndEndProcessButton;
+- (void)deselectRows;
+@end
+
+////////////////////////////////////////////////////////////////////////////////
+// TaskManagerWindowController implementation:
+
+@implementation TaskManagerWindowController
+
+- (id)initWithTaskManagerObserver:(TaskManagerMac*)taskManagerObserver {
+ NSString* nibpath = [mac_util::MainAppBundle()
+ pathForResource:@"TaskManager"
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
+ taskManagerObserver_ = taskManagerObserver;
+ taskManager_ = taskManagerObserver_->task_manager();
+ model_ = taskManager_->model();
+
+ if (g_browser_process && g_browser_process->local_state()) {
+ size_saver_.reset([[WindowSizeAutosaver alloc]
+ initWithWindow:[self window]
+ prefService:g_browser_process->local_state()
+ path:prefs::kTaskManagerWindowPlacement]);
+ }
+ [self showWindow:self];
+ }
+ return self;
+}
+
+- (void)sortShuffleArray {
+ viewToModelMap_.resize(model_->ResourceCount());
+ for (size_t i = 0; i < viewToModelMap_.size(); ++i)
+ viewToModelMap_[i] = i;
+
+ std::sort(viewToModelMap_.begin(), viewToModelMap_.end(),
+ SortHelper(model_, currentSortDescriptor_.get()));
+
+ modelToViewMap_.resize(viewToModelMap_.size());
+ for (size_t i = 0; i < viewToModelMap_.size(); ++i)
+ modelToViewMap_[viewToModelMap_[i]] = i;
+}
+
+- (void)reloadData {
+ // Store old view indices, and the model indices they map to.
+ NSIndexSet* viewSelection = [tableView_ selectedRowIndexes];
+ std::vector<int> modelSelection;
+ for (NSUInteger i = [viewSelection lastIndex];
+ i != NSNotFound;
+ i = [viewSelection indexLessThanIndex:i]) {
+ modelSelection.push_back(viewToModelMap_[i]);
+ }
+
+ // Sort.
+ [self sortShuffleArray];
+
+ // Use the model indices to get the new view indices of the selection, and
+ // set selection to that. This assumes that no rows were added or removed
+ // (in that case, the selection is cleared before -reloadData is called).
+ if (modelSelection.size() > 0)
+ DCHECK_EQ([tableView_ numberOfRows], model_->ResourceCount());
+ NSMutableIndexSet* indexSet = [NSMutableIndexSet indexSet];
+ for (size_t i = 0; i < modelSelection.size(); ++i)
+ [indexSet addIndex:modelToViewMap_[modelSelection[i]]];
+ [tableView_ selectRowIndexes:indexSet byExtendingSelection:NO];
+
+ [tableView_ reloadData];
+ [self adjustSelectionAndEndProcessButton];
+}
+
+- (IBAction)statsLinkClicked:(id)sender {
+ TaskManager::GetInstance()->OpenAboutMemory();
+}
+
+- (IBAction)killSelectedProcesses:(id)sender {
+ NSIndexSet* selection = [tableView_ selectedRowIndexes];
+ for (NSUInteger i = [selection lastIndex];
+ i != NSNotFound;
+ i = [selection indexLessThanIndex:i]) {
+ taskManager_->KillProcess(viewToModelMap_[i]);
+ }
+}
+
+- (void)selectDoubleClickedTab:(id)sender {
+ NSInteger row = [tableView_ clickedRow];
+ if (row < 0)
+ return; // Happens e.g. if the table header is double-clicked.
+ taskManager_->ActivateProcess(viewToModelMap_[row]);
+}
+
+- (NSTableView*)tableView {
+ return tableView_;
+}
+
+- (void)awakeFromNib {
+ [self setUpTableColumns];
+ [self setUpTableHeaderContextMenu];
+ [self adjustSelectionAndEndProcessButton];
+
+ [tableView_ setDoubleAction:@selector(selectDoubleClickedTab:)];
+ [tableView_ sizeToFit];
+}
+
+- (void)dealloc {
+ [tableView_ setDelegate:nil];
+ [tableView_ setDataSource:nil];
+ [super dealloc];
+}
+
+// Adds a column which has the given string id as title. |isVisible| specifies
+// if the column is initially visible.
+- (NSTableColumn*)addColumnWithId:(int)columnId visible:(BOOL)isVisible {
+ scoped_nsobject<NSTableColumn> column([[NSTableColumn alloc]
+ initWithIdentifier:[NSNumber numberWithInt:columnId]]);
+
+ NSTextAlignment textAlignment = columnId == IDS_TASK_MANAGER_PAGE_COLUMN ?
+ NSLeftTextAlignment : NSRightTextAlignment;
+
+ [[column.get() headerCell]
+ setStringValue:l10n_util::GetNSStringWithFixup(columnId)];
+ [[column.get() headerCell] setAlignment:textAlignment];
+ [[column.get() dataCell] setAlignment:textAlignment];
+
+ NSFont* font = [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
+ [[column.get() dataCell] setFont:font];
+
+ [column.get() setHidden:!isVisible];
+ [column.get() setEditable:NO];
+
+ // The page column should by default be sorted ascending.
+ BOOL ascending = columnId == IDS_TASK_MANAGER_PAGE_COLUMN;
+
+ scoped_nsobject<NSSortDescriptor> sortDescriptor([[NSSortDescriptor alloc]
+ initWithKey:[NSString stringWithFormat:@"%d", columnId]
+ ascending:ascending]);
+ [column.get() setSortDescriptorPrototype:sortDescriptor.get()];
+
+ // Default values, only used in release builds if nobody notices the DCHECK
+ // during development when adding new columns.
+ int minWidth = 200, maxWidth = 400;
+
+ size_t i;
+ for (i = 0; i < arraysize(columnWidths); ++i) {
+ if (columnWidths[i].columnId == columnId) {
+ minWidth = columnWidths[i].minWidth;
+ maxWidth = columnWidths[i].maxWidth;
+ if (maxWidth < 0)
+ maxWidth = 3 * minWidth / 2; // *1.5 for ints.
+ break;
+ }
+ }
+ DCHECK(i < arraysize(columnWidths)) << "Could not find " << columnId;
+ [column.get() setMinWidth:minWidth];
+ [column.get() setMaxWidth:maxWidth];
+ [column.get() setResizingMask:NSTableColumnAutoresizingMask |
+ NSTableColumnUserResizingMask];
+
+ [tableView_ addTableColumn:column.get()];
+ return column.get(); // Now retained by |tableView_|.
+}
+
+// Adds all the task manager's columns to the table.
+- (void)setUpTableColumns {
+ for (NSTableColumn* column in [tableView_ tableColumns])
+ [tableView_ removeTableColumn:column];
+ NSTableColumn* nameColumn = [self addColumnWithId:IDS_TASK_MANAGER_PAGE_COLUMN
+ visible:YES];
+ // |nameColumn| displays an icon for every row -- this is done by an
+ // NSButtonCell.
+ scoped_nsobject<NSButtonCell> nameCell(
+ [[NSButtonCell alloc] initTextCell:@""]);
+ [nameCell.get() setImagePosition:NSImageLeft];
+ [nameCell.get() setButtonType:NSSwitchButton];
+ [nameCell.get() setAlignment:[[nameColumn dataCell] alignment]];
+ [nameCell.get() setFont:[[nameColumn dataCell] font]];
+ [nameColumn setDataCell:nameCell.get()];
+
+ // Initially, sort on the tab name.
+ [tableView_ setSortDescriptors:
+ [NSArray arrayWithObject:[nameColumn sortDescriptorPrototype]]];
+
+ [self addColumnWithId:IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN visible:YES];
+ [self addColumnWithId:IDS_TASK_MANAGER_SHARED_MEM_COLUMN visible:NO];
+ [self addColumnWithId:IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN visible:NO];
+ [self addColumnWithId:IDS_TASK_MANAGER_CPU_COLUMN visible:YES];
+ [self addColumnWithId:IDS_TASK_MANAGER_NET_COLUMN visible:YES];
+ [self addColumnWithId:IDS_TASK_MANAGER_PROCESS_ID_COLUMN visible:NO];
+ [self addColumnWithId:IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN
+ visible:NO];
+ [self addColumnWithId:IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN
+ visible:NO];
+ [self addColumnWithId:IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN visible:NO];
+ [self addColumnWithId:IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN visible:NO];
+ [self addColumnWithId:IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN
+ visible:NO];
+ [self addColumnWithId:IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN visible:NO];
+}
+
+// Creates a context menu for the table header that allows the user to toggle
+// which columns should be shown and which should be hidden (like e.g.
+// Task Manager.app's table header context menu).
+- (void)setUpTableHeaderContextMenu {
+ scoped_nsobject<NSMenu> contextMenu(
+ [[NSMenu alloc] initWithTitle:@"Task Manager context menu"]);
+ for (NSTableColumn* column in [tableView_ tableColumns]) {
+ NSMenuItem* item = [contextMenu.get()
+ addItemWithTitle:[[column headerCell] stringValue]
+ action:@selector(toggleColumn:)
+ keyEquivalent:@""];
+ [item setTarget:self];
+ [item setRepresentedObject:column];
+ [item setState:[column isHidden] ? NSOffState : NSOnState];
+ }
+ [[tableView_ headerView] setMenu:contextMenu.get()];
+}
+
+// Callback for the table header context menu. Toggles visibility of the table
+// column associated with the clicked menu item.
+- (void)toggleColumn:(id)item {
+ DCHECK([item isKindOfClass:[NSMenuItem class]]);
+ if (![item isKindOfClass:[NSMenuItem class]])
+ return;
+
+ NSTableColumn* column = [item representedObject];
+ DCHECK(column);
+ NSInteger oldState = [item state];
+ NSInteger newState = oldState == NSOnState ? NSOffState : NSOnState;
+ [column setHidden:newState == NSOffState];
+ [item setState:newState];
+ [tableView_ sizeToFit];
+ [tableView_ setNeedsDisplay];
+}
+
+// This function appropriately sets the enabled states on the table's editing
+// buttons.
+- (void)adjustSelectionAndEndProcessButton {
+ bool selectionContainsBrowserProcess = false;
+
+ // If a row is selected, make sure that all rows belonging to the same process
+ // are selected as well. Also, check if the selection contains the browser
+ // process.
+ NSIndexSet* selection = [tableView_ selectedRowIndexes];
+ for (NSUInteger i = [selection lastIndex];
+ i != NSNotFound;
+ i = [selection indexLessThanIndex:i]) {
+ int modelIndex = viewToModelMap_[i];
+ if (taskManager_->IsBrowserProcess(modelIndex))
+ selectionContainsBrowserProcess = true;
+
+ std::pair<int, int> rangePair =
+ model_->GetGroupRangeForResource(modelIndex);
+ NSMutableIndexSet* indexSet = [NSMutableIndexSet indexSet];
+ for (int j = 0; j < rangePair.second; ++j)
+ [indexSet addIndex:modelToViewMap_[rangePair.first + j]];
+ [tableView_ selectRowIndexes:indexSet byExtendingSelection:YES];
+ }
+
+ bool enabled = [selection count] > 0 && !selectionContainsBrowserProcess;
+ [endProcessButton_ setEnabled:enabled];
+}
+
+- (void)deselectRows {
+ [tableView_ deselectAll:self];
+}
+
+// Table view delegate method.
+- (void)tableViewSelectionIsChanging:(NSNotification*)aNotification {
+ [self adjustSelectionAndEndProcessButton];
+}
+
+- (void)windowWillClose:(NSNotification*)notification {
+ if (taskManagerObserver_) {
+ taskManagerObserver_->WindowWasClosed();
+ taskManagerObserver_ = nil;
+ }
+ [self autorelease];
+}
+
+@end
+
+@implementation TaskManagerWindowController (NSTableDataSource)
+
+- (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView {
+ DCHECK(tableView == tableView_ || tableView_ == nil);
+ return model_->ResourceCount();
+}
+
+- (NSString*)modelTextForRow:(int)row column:(int)columnId {
+ DCHECK_LT(static_cast<size_t>(row), viewToModelMap_.size());
+ row = viewToModelMap_[row];
+ switch (columnId) {
+ case IDS_TASK_MANAGER_PAGE_COLUMN: // Process
+ return base::SysUTF16ToNSString(model_->GetResourceTitle(row));
+
+ case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN: // Memory
+ if (!model_->IsResourceFirstInGroup(row))
+ return @"";
+ return base::SysUTF16ToNSString(model_->GetResourcePrivateMemory(row));
+
+ case IDS_TASK_MANAGER_SHARED_MEM_COLUMN: // Memory
+ if (!model_->IsResourceFirstInGroup(row))
+ return @"";
+ return base::SysUTF16ToNSString(model_->GetResourceSharedMemory(row));
+
+ case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN: // Memory
+ if (!model_->IsResourceFirstInGroup(row))
+ return @"";
+ return base::SysUTF16ToNSString(model_->GetResourcePhysicalMemory(row));
+
+ case IDS_TASK_MANAGER_CPU_COLUMN: // CPU
+ if (!model_->IsResourceFirstInGroup(row))
+ return @"";
+ return base::SysUTF16ToNSString(model_->GetResourceCPUUsage(row));
+
+ case IDS_TASK_MANAGER_NET_COLUMN: // Net
+ return base::SysUTF16ToNSString(model_->GetResourceNetworkUsage(row));
+
+ case IDS_TASK_MANAGER_PROCESS_ID_COLUMN: // Process ID
+ if (!model_->IsResourceFirstInGroup(row))
+ return @"";
+ return base::SysUTF16ToNSString(model_->GetResourceProcessId(row));
+
+ case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN: // WebCore image cache
+ if (!model_->IsResourceFirstInGroup(row))
+ return @"";
+ return base::SysUTF16ToNSString(
+ model_->GetResourceWebCoreImageCacheSize(row));
+
+ case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN: // WebCore script cache
+ if (!model_->IsResourceFirstInGroup(row))
+ return @"";
+ return base::SysUTF16ToNSString(
+ model_->GetResourceWebCoreScriptsCacheSize(row));
+
+ case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN: // WebCore CSS cache
+ if (!model_->IsResourceFirstInGroup(row))
+ return @"";
+ return base::SysUTF16ToNSString(
+ model_->GetResourceWebCoreCSSCacheSize(row));
+
+ case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN:
+ if (!model_->IsResourceFirstInGroup(row))
+ return @"";
+ return base::SysUTF16ToNSString(
+ model_->GetResourceSqliteMemoryUsed(row));
+
+ case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN:
+ if (!model_->IsResourceFirstInGroup(row))
+ return @"";
+ return base::SysUTF16ToNSString(
+ model_->GetResourceV8MemoryAllocatedSize(row));
+
+ case IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN: // Goats Teleported!
+ return base::SysUTF16ToNSString(model_->GetResourceGoatsTeleported(row));
+
+ default:
+ NOTREACHED();
+ return @"";
+ }
+}
+
+- (id)tableView:(NSTableView*)tableView
+ objectValueForTableColumn:(NSTableColumn*)tableColumn
+ row:(NSInteger)rowIndex {
+ // NSButtonCells expect an on/off state as objectValue. Their title is set
+ // in |tableView:dataCellForTableColumn:row:| below.
+ if ([[tableColumn identifier] intValue] == IDS_TASK_MANAGER_PAGE_COLUMN) {
+ return [NSNumber numberWithInt:NSOffState];
+ }
+
+ return [self modelTextForRow:rowIndex
+ column:[[tableColumn identifier] intValue]];
+}
+
+- (NSCell*)tableView:(NSTableView*)tableView
+ dataCellForTableColumn:(NSTableColumn*)tableColumn
+ row:(NSInteger)rowIndex {
+ NSCell* cell = [tableColumn dataCellForRow:rowIndex];
+
+ // Set the favicon and title for the task in the name column.
+ if ([[tableColumn identifier] intValue] == IDS_TASK_MANAGER_PAGE_COLUMN) {
+ DCHECK([cell isKindOfClass:[NSButtonCell class]]);
+ NSButtonCell* buttonCell = static_cast<NSButtonCell*>(cell);
+ NSString* title = [self modelTextForRow:rowIndex
+ column:[[tableColumn identifier] intValue]];
+ [buttonCell setTitle:title];
+ [buttonCell setImage:
+ taskManagerObserver_->GetImageForRow(viewToModelMap_[rowIndex])];
+ [buttonCell setRefusesFirstResponder:YES]; // Don't push in like a button.
+ [buttonCell setHighlightsBy:NSNoCellMask];
+ }
+
+ return cell;
+}
+
+- (void) tableView:(NSTableView*)tableView
+ sortDescriptorsDidChange:(NSArray*)oldDescriptors {
+ NSArray* newDescriptors = [tableView sortDescriptors];
+ if ([newDescriptors count] < 1)
+ return;
+
+ currentSortDescriptor_.reset([[newDescriptors objectAtIndex:0] retain]);
+ [self reloadData]; // Sorts.
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////
+// TaskManagerMac implementation:
+
+TaskManagerMac::TaskManagerMac(TaskManager* task_manager)
+ : task_manager_(task_manager),
+ model_(task_manager->model()),
+ icon_cache_(this) {
+ window_controller_ =
+ [[TaskManagerWindowController alloc] initWithTaskManagerObserver:this];
+ model_->AddObserver(this);
+}
+
+// static
+TaskManagerMac* TaskManagerMac::instance_ = NULL;
+
+TaskManagerMac::~TaskManagerMac() {
+ if (this == instance_) {
+ // Do not do this when running in unit tests: |StartUpdating()| never got
+ // called in that case.
+ task_manager_->OnWindowClosed();
+ }
+ model_->RemoveObserver(this);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TaskManagerMac, TaskManagerModelObserver implementation:
+
+void TaskManagerMac::OnModelChanged() {
+ icon_cache_.OnModelChanged();
+ [window_controller_ deselectRows];
+ [window_controller_ reloadData];
+}
+
+void TaskManagerMac::OnItemsChanged(int start, int length) {
+ icon_cache_.OnItemsChanged(start, length);
+ [window_controller_ reloadData];
+}
+
+void TaskManagerMac::OnItemsAdded(int start, int length) {
+ icon_cache_.OnItemsAdded(start, length);
+ [window_controller_ deselectRows];
+ [window_controller_ reloadData];
+}
+
+void TaskManagerMac::OnItemsRemoved(int start, int length) {
+ icon_cache_.OnItemsRemoved(start, length);
+ [window_controller_ deselectRows];
+ [window_controller_ reloadData];
+}
+
+NSImage* TaskManagerMac::GetImageForRow(int row) {
+ return icon_cache_.GetImageForRow(row);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TaskManagerMac, public:
+
+void TaskManagerMac::WindowWasClosed() {
+ delete this;
+ instance_ = NULL;
+}
+
+int TaskManagerMac::RowCount() const {
+ return model_->ResourceCount();
+}
+
+SkBitmap TaskManagerMac::GetIcon(int r) const {
+ return model_->GetResourceIcon(r);
+}
+
+// static
+void TaskManagerMac::Show() {
+ if (instance_) {
+ // If there's a Task manager window open already, just activate it.
+ [[instance_->window_controller_ window]
+ makeKeyAndOrderFront:instance_->window_controller_];
+ } else {
+ instance_ = new TaskManagerMac(TaskManager::GetInstance());
+ instance_->model_->StartUpdating();
+ }
+}
diff --git a/chrome/browser/ui/cocoa/task_manager_mac_unittest.mm b/chrome/browser/ui/cocoa/task_manager_mac_unittest.mm
new file mode 100644
index 0000000..2a7aae3
--- /dev/null
+++ b/chrome/browser/ui/cocoa/task_manager_mac_unittest.mm
@@ -0,0 +1,115 @@
+// Copyright (c) 2009 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 "base/scoped_nsobject.h"
+#include "base/utf_string_conversions.h"
+#import "chrome/browser/ui/cocoa/task_manager_mac.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "grit/generated_resources.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace {
+
+class TestResource : public TaskManager::Resource {
+ public:
+ TestResource(const string16& title, pid_t pid) : title_(title), pid_(pid) {}
+ virtual std::wstring GetTitle() const { return UTF16ToWide(title_); }
+ virtual SkBitmap GetIcon() const { return SkBitmap(); }
+ virtual base::ProcessHandle GetProcess() const { return pid_; }
+ virtual Type GetType() const { return RENDERER; }
+ virtual bool SupportNetworkUsage() const { return false; }
+ virtual void SetSupportNetworkUsage() { NOTREACHED(); }
+ virtual void Refresh() {}
+ string16 title_;
+ pid_t pid_;
+};
+
+} // namespace
+
+class TaskManagerWindowControllerTest : public CocoaTest {
+};
+
+// Test creation, to ensure nothing leaks or crashes.
+TEST_F(TaskManagerWindowControllerTest, Init) {
+ TaskManager task_manager;
+ TaskManagerMac* bridge(new TaskManagerMac(&task_manager));
+ TaskManagerWindowController* controller = bridge->cocoa_controller();
+
+ // Releases the controller, which in turn deletes |bridge|.
+ [controller close];
+}
+
+TEST_F(TaskManagerWindowControllerTest, Sort) {
+ TaskManager task_manager;
+
+ TestResource resource1(UTF8ToUTF16("zzz"), 1);
+ TestResource resource2(UTF8ToUTF16("zzb"), 2);
+ TestResource resource3(UTF8ToUTF16("zza"), 2);
+
+ task_manager.AddResource(&resource1);
+ task_manager.AddResource(&resource2);
+ task_manager.AddResource(&resource3); // Will be in the same group as 2.
+
+ TaskManagerMac* bridge(new TaskManagerMac(&task_manager));
+ TaskManagerWindowController* controller = bridge->cocoa_controller();
+ NSTableView* table = [controller tableView];
+ ASSERT_EQ(3, [controller numberOfRowsInTableView:table]);
+
+ // Test that table is sorted on title.
+ NSTableColumn* title_column = [table tableColumnWithIdentifier:
+ [NSNumber numberWithInt:IDS_TASK_MANAGER_PAGE_COLUMN]];
+ NSCell* cell;
+ cell = [controller tableView:table dataCellForTableColumn:title_column row:0];
+ EXPECT_NSEQ(@"zzb", [cell title]);
+ cell = [controller tableView:table dataCellForTableColumn:title_column row:1];
+ EXPECT_NSEQ(@"zza", [cell title]);
+ cell = [controller tableView:table dataCellForTableColumn:title_column row:2];
+ EXPECT_NSEQ(@"zzz", [cell title]);
+
+ // Releases the controller, which in turn deletes |bridge|.
+ [controller close];
+
+ task_manager.RemoveResource(&resource1);
+ task_manager.RemoveResource(&resource2);
+ task_manager.RemoveResource(&resource3);
+}
+
+TEST_F(TaskManagerWindowControllerTest, SelectionAdaptsToSorting) {
+ TaskManager task_manager;
+
+ TestResource resource1(UTF8ToUTF16("yyy"), 1);
+ TestResource resource2(UTF8ToUTF16("aaa"), 2);
+
+ task_manager.AddResource(&resource1);
+ task_manager.AddResource(&resource2);
+
+ TaskManagerMac* bridge(new TaskManagerMac(&task_manager));
+ TaskManagerWindowController* controller = bridge->cocoa_controller();
+ NSTableView* table = [controller tableView];
+ ASSERT_EQ(2, [controller numberOfRowsInTableView:table]);
+
+ // Select row 0 in the table (corresponds to row 1 in the model).
+ [table selectRowIndexes:[NSIndexSet indexSetWithIndex:0]
+ byExtendingSelection:NO];
+
+ // Change the name of resource2 so that it becomes row 1 in the table.
+ resource2.title_ = UTF8ToUTF16("zzz");
+ bridge->OnItemsChanged(1, 1);
+
+ // Check that the selection has moved to row 1.
+ NSIndexSet* selection = [table selectedRowIndexes];
+ ASSERT_EQ(1u, [selection count]);
+ EXPECT_EQ(1u, [selection firstIndex]);
+
+ // Releases the controller, which in turn deletes |bridge|.
+ [controller close];
+
+ task_manager.RemoveResource(&resource1);
+ task_manager.RemoveResource(&resource2);
+}
diff --git a/chrome/browser/ui/cocoa/test_event_utils.h b/chrome/browser/ui/cocoa/test_event_utils.h
new file mode 100644
index 0000000..43bc78f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/test_event_utils.h
@@ -0,0 +1,48 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_TEST_EVENT_UTILS_H_
+#define CHROME_BROWSER_UI_COCOA_TEST_EVENT_UTILS_H_
+#pragma once
+
+#include <utility>
+
+#import <objc/objc-class.h>
+
+#include "base/basictypes.h"
+
+// Within a given scope, replace the selector |selector| on |target| with that
+// from |source|.
+class ScopedClassSwizzler {
+ public:
+ ScopedClassSwizzler(Class target, Class source, SEL selector);
+ ~ScopedClassSwizzler();
+
+ private:
+ Method old_selector_impl_;
+ Method new_selector_impl_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedClassSwizzler);
+};
+
+namespace test_event_utils {
+
+// Create synthetic mouse events for testing. Currently these are very
+// basic, flesh out as needed. Points are all in window coordinates;
+// where the window is not specified, coordinate system is undefined
+// (but will be repeated when the event is queried).
+NSEvent* MakeMouseEvent(NSEventType type, NSUInteger modifiers);
+NSEvent* MouseEventAtPoint(NSPoint point, NSEventType type,
+ NSUInteger modifiers);
+NSEvent* LeftMouseDownAtPoint(NSPoint point);
+NSEvent* LeftMouseDownAtPointInWindow(NSPoint point, NSWindow* window);
+
+// Return a mouse down and an up event with the given |clickCount| at
+// |view|'s midpoint.
+std::pair<NSEvent*, NSEvent*> MouseClickInView(NSView* view,
+ NSUInteger clickCount);
+
+} // namespace test_event_utils
+
+#endif // CHROME_BROWSER_UI_COCOA_TEST_EVENT_UTILS_H_
diff --git a/chrome/browser/ui/cocoa/test_event_utils.mm b/chrome/browser/ui/cocoa/test_event_utils.mm
new file mode 100644
index 0000000..9675db6
--- /dev/null
+++ b/chrome/browser/ui/cocoa/test_event_utils.mm
@@ -0,0 +1,86 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/test_event_utils.h"
+
+ScopedClassSwizzler::ScopedClassSwizzler(Class target, Class source,
+ SEL selector) {
+ old_selector_impl_ = class_getInstanceMethod(target, selector);
+ new_selector_impl_ = class_getInstanceMethod(source, selector);
+ method_exchangeImplementations(old_selector_impl_, new_selector_impl_);
+}
+
+ScopedClassSwizzler::~ScopedClassSwizzler() {
+ method_exchangeImplementations(old_selector_impl_, new_selector_impl_);
+}
+
+namespace test_event_utils {
+
+NSEvent* MouseEventAtPoint(NSPoint point, NSEventType type,
+ NSUInteger modifiers) {
+ if (type == NSOtherMouseUp) {
+ // To synthesize middle clicks we need to create a CGEvent with the
+ // "center" button flags so that our resulting NSEvent will have the
+ // appropriate buttonNumber field. NSEvent provides no way to create a
+ // mouse event with a buttonNumber directly.
+ CGPoint location = { point.x, point.y };
+ CGEventRef cg_event = CGEventCreateMouseEvent(NULL, kCGEventOtherMouseUp,
+ location,
+ kCGMouseButtonCenter);
+ NSEvent* event = [NSEvent eventWithCGEvent:cg_event];
+ CFRelease(cg_event);
+ return event;
+ }
+ return [NSEvent mouseEventWithType:type
+ location:point
+ modifierFlags:modifiers
+ timestamp:0
+ windowNumber:0
+ context:nil
+ eventNumber:0
+ clickCount:1
+ pressure:1.0];
+}
+
+NSEvent* MakeMouseEvent(NSEventType type, NSUInteger modifiers) {
+ return MouseEventAtPoint(NSMakePoint(0, 0), type, modifiers);
+}
+
+static NSEvent* MouseEventAtPointInWindow(NSPoint point,
+ NSEventType type,
+ NSWindow* window,
+ NSUInteger clickCount) {
+ return [NSEvent mouseEventWithType:type
+ location:point
+ modifierFlags:0
+ timestamp:0
+ windowNumber:[window windowNumber]
+ context:nil
+ eventNumber:0
+ clickCount:clickCount
+ pressure:1.0];
+}
+
+NSEvent* LeftMouseDownAtPointInWindow(NSPoint point, NSWindow* window) {
+ return MouseEventAtPointInWindow(point, NSLeftMouseDown, window, 1);
+}
+
+NSEvent* LeftMouseDownAtPoint(NSPoint point) {
+ return LeftMouseDownAtPointInWindow(point, nil);
+}
+
+std::pair<NSEvent*,NSEvent*> MouseClickInView(NSView* view,
+ NSUInteger clickCount) {
+ const NSRect bounds = [view convertRect:[view bounds] toView:nil];
+ const NSPoint mid_point = NSMakePoint(NSMidX(bounds), NSMidY(bounds));
+ NSEvent* down = MouseEventAtPointInWindow(mid_point, NSLeftMouseDown,
+ [view window], clickCount);
+ NSEvent* up = MouseEventAtPointInWindow(mid_point, NSLeftMouseUp,
+ [view window], clickCount);
+ return std::make_pair(down, up);
+}
+
+} // namespace test_event_utils
diff --git a/chrome/browser/ui/cocoa/theme_install_bubble_view.h b/chrome/browser/ui/cocoa/theme_install_bubble_view.h
new file mode 100644
index 0000000..f2a8a4a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/theme_install_bubble_view.h
@@ -0,0 +1,62 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_THEME_INSTALL_BUBBLE_VIEW_H_
+#define CHROME_BROWSER_UI_COCOA_THEME_INSTALL_BUBBLE_VIEW_H_
+#pragma once
+
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+
+@class NSWindow;
+@class ThemeInstallBubbleViewCocoa;
+
+// ThemeInstallBubbleView is a view that provides a "Loading..." bubble in the
+// center of a browser window for use when an extension or theme is loaded.
+// (The Browser class only calls it to install itself into the currently active
+// browser window.) If an extension is being applied, the bubble goes away
+// immediately. If a theme is being applied, it disappears when the theme has
+// been loaded. The purpose of this bubble is to warn the user that the browser
+// may be unresponsive while the theme is being installed.
+//
+// Edge case: note that if one installs a theme in one window and then switches
+// rapidly to another window to install a theme there as well (in the short time
+// between install begin and theme caching seizing the UI thread), the loading
+// bubble will only appear over the first window, as there is only ever one
+// instance of the bubble.
+class ThemeInstallBubbleView : public NotificationObserver {
+ public:
+ ~ThemeInstallBubbleView();
+
+ // NotificationObserver
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // Show the loading bubble.
+ static void Show(NSWindow* window);
+
+ private:
+ explicit ThemeInstallBubbleView(NSWindow* window);
+
+ // The one copy of the loading bubble.
+ static ThemeInstallBubbleView* view_;
+
+ // A scoped container for notification registries.
+ NotificationRegistrar registrar_;
+
+ // Shut down the popup and remove our notifications.
+ void Close();
+
+ // The actual Cocoa view implementing the bubble.
+ ThemeInstallBubbleViewCocoa* cocoa_view_;
+
+ // Multiple loads can be started at once. Only show one bubble, and keep
+ // track of number of loads happening. Close bubble when num_loads < 1.
+ int num_loads_extant_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThemeInstallBubbleView);
+};
+
+#endif // CHROME_BROWSER_UI_COCOA_THEME_INSTALL_BUBBLE_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/theme_install_bubble_view.mm b/chrome/browser/ui/cocoa/theme_install_bubble_view.mm
new file mode 100644
index 0000000..9841230
--- /dev/null
+++ b/chrome/browser/ui/cocoa/theme_install_bubble_view.mm
@@ -0,0 +1,187 @@
+// Copyright (c) 2009 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>
+
+#import "chrome/browser/ui/cocoa/theme_install_bubble_view.h"
+
+#include "app/l10n_util_mac.h"
+#include "base/scoped_nsobject.h"
+#include "chrome/common/notification_service.h"
+#include "grit/generated_resources.h"
+
+namespace {
+
+// The alpha of the bubble.
+static const float kBubbleAlpha = 0.75;
+
+// The roundedness of the edges of our bubble.
+static const int kBubbleCornerRadius = 4;
+
+// Padding around text in popup box.
+static const int kTextHorizPadding = 90;
+static const int kTextVertPadding = 45;
+
+// Point size of the text in the box.
+static const int kLoadingTextSize = 24;
+
+}
+
+// static
+ThemeInstallBubbleView* ThemeInstallBubbleView::view_ = NULL;
+
+// The Cocoa view to draw a gray rounded rect with "Loading..." in it.
+@interface ThemeInstallBubbleViewCocoa : NSView {
+ @private
+ scoped_nsobject<NSAttributedString> message_;
+
+ NSRect grayRect_;
+ NSRect textRect_;
+}
+
+- (id)init;
+
+// The size of the gray rect that will be drawn.
+- (NSSize)preferredSize;
+// Forces size calculations of where everything will be drawn.
+- (void)layout;
+
+@end
+
+ThemeInstallBubbleView::ThemeInstallBubbleView(NSWindow* window)
+ : cocoa_view_([[ThemeInstallBubbleViewCocoa alloc] init]),
+ num_loads_extant_(1) {
+ DCHECK(window);
+
+ NSView* parent_view = [window contentView];
+ NSRect parent_bounds = [parent_view bounds];
+ if (parent_bounds.size.height < [cocoa_view_ preferredSize].height)
+ Close();
+
+ // Close when theme has been installed.
+ registrar_.Add(
+ this,
+ NotificationType::BROWSER_THEME_CHANGED,
+ NotificationService::AllSources());
+
+ // Close when we are installing an extension, not a theme.
+ registrar_.Add(
+ this,
+ NotificationType::NO_THEME_DETECTED,
+ NotificationService::AllSources());
+ registrar_.Add(
+ this,
+ NotificationType::EXTENSION_INSTALLED,
+ NotificationService::AllSources());
+ registrar_.Add(
+ this,
+ NotificationType::EXTENSION_INSTALL_ERROR,
+ NotificationService::AllSources());
+
+ // Don't let the bubble overlap the confirm dialog.
+ registrar_.Add(
+ this,
+ NotificationType::EXTENSION_WILL_SHOW_CONFIRM_DIALOG,
+ NotificationService::AllSources());
+
+ // Add the view.
+ [cocoa_view_ setFrame:parent_bounds];
+ [cocoa_view_ setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+ [parent_view addSubview:cocoa_view_
+ positioned:NSWindowAbove
+ relativeTo:nil];
+ [cocoa_view_ layout];
+}
+
+ThemeInstallBubbleView::~ThemeInstallBubbleView() {
+ // Need to delete self; the real work happens in Close().
+}
+
+void ThemeInstallBubbleView::Close() {
+ --num_loads_extant_;
+ if (num_loads_extant_ < 1) {
+ registrar_.RemoveAll();
+ if (cocoa_view_ && [cocoa_view_ superview]) {
+ [cocoa_view_ removeFromSuperview];
+ [cocoa_view_ release];
+ }
+ view_ = NULL;
+ delete this;
+ // this is deleted; nothing more!
+ }
+}
+
+void ThemeInstallBubbleView::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ Close();
+}
+
+// static
+void ThemeInstallBubbleView::Show(NSWindow* window) {
+ if (view_)
+ ++view_->num_loads_extant_;
+ else
+ view_ = new ThemeInstallBubbleView(window);
+}
+
+@implementation ThemeInstallBubbleViewCocoa
+
+- (id)init {
+ self = [super initWithFrame:NSZeroRect];
+ if (self) {
+ NSString* loadingString =
+ l10n_util::GetNSStringWithFixup(IDS_THEME_LOADING_TITLE);
+ NSFont* loadingFont = [NSFont systemFontOfSize:kLoadingTextSize];
+ NSColor* textColor = [NSColor whiteColor];
+ NSDictionary* loadingAttrs = [NSDictionary dictionaryWithObjectsAndKeys:
+ loadingFont, NSFontAttributeName,
+ textColor, NSForegroundColorAttributeName,
+ nil];
+ message_.reset([[NSAttributedString alloc] initWithString:loadingString
+ attributes:loadingAttrs]);
+
+ // TODO(avi): find a white-on-black spinner
+ }
+ return self;
+}
+
+- (NSSize)preferredSize {
+ NSSize size = [message_.get() size];
+ size.width += kTextHorizPadding;
+ size.height += kTextVertPadding;
+ return size;
+}
+
+// Update the layout to keep the view centered when the window is resized.
+- (void)resizeWithOldSuperviewSize:(NSSize)oldBoundsSize {
+ [super resizeWithOldSuperviewSize:oldBoundsSize];
+ [self layout];
+}
+
+- (void)layout {
+ NSRect bounds = [self bounds];
+
+ grayRect_.size = [self preferredSize];
+ grayRect_.origin.x = (bounds.size.width - grayRect_.size.width) / 2;
+ grayRect_.origin.y = bounds.size.height / 2;
+
+ textRect_.size = [message_.get() size];
+ textRect_.origin.x = (bounds.size.width - [message_.get() size].width) / 2;
+ textRect_.origin.y = (bounds.size.height + kTextVertPadding) / 2;
+}
+
+- (void)drawRect:(NSRect)dirtyRect {
+ [[NSColor clearColor] set];
+ NSRectFillUsingOperation([self bounds], NSCompositeSourceOver);
+
+ [[[NSColor blackColor] colorWithAlphaComponent:kBubbleAlpha] set];
+ [[NSBezierPath bezierPathWithRoundedRect:grayRect_
+ xRadius:kBubbleCornerRadius
+ yRadius:kBubbleCornerRadius] fill];
+
+ [message_.get() drawInRect:textRect_];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/themed_window.h b/chrome/browser/ui/cocoa/themed_window.h
new file mode 100644
index 0000000..d35bfa3
--- /dev/null
+++ b/chrome/browser/ui/cocoa/themed_window.h
@@ -0,0 +1,30 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_THEMED_WINDOW_H_
+#define CHROME_BROWSER_UI_COCOA_THEMED_WINDOW_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+class ThemeProvider;
+
+// Bit flags; mix-and-match as necessary.
+enum {
+ THEMED_NORMAL = 0,
+ THEMED_INCOGNITO = 1 << 0,
+ THEMED_POPUP = 1 << 1,
+ THEMED_DEVTOOLS = 1 << 2
+};
+typedef NSUInteger ThemedWindowStyle;
+
+// Implemented by windows that support theming.
+
+@interface NSWindow (ThemeProvider)
+- (ThemeProvider*)themeProvider;
+- (ThemedWindowStyle)themedWindowStyle;
+- (NSPoint)themePatternPhase;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_THEMED_WINDOW_H_
diff --git a/chrome/browser/ui/cocoa/themed_window.mm b/chrome/browser/ui/cocoa/themed_window.mm
new file mode 100644
index 0000000..911bf8a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/themed_window.mm
@@ -0,0 +1,23 @@
+// 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 "chrome/browser/ui/cocoa/themed_window.h"
+
+// Default implementations; used mostly for tests so that the hosting windows
+// don't needs to know about the theming machinery.
+@implementation NSWindow (ThemeProvider)
+
+- (ThemeProvider*)themeProvider {
+ return NULL;
+}
+
+- (ThemedWindowStyle)themedWindowStyle {
+ return THEMED_NORMAL;
+}
+
+- (NSPoint)themePatternPhase {
+ return NSZeroPoint;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/throbber_view.h b/chrome/browser/ui/cocoa/throbber_view.h
new file mode 100644
index 0000000..a680222
--- /dev/null
+++ b/chrome/browser/ui/cocoa/throbber_view.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_THROBBER_VIEW_H_
+#define CHROME_BROWSER_UI_COCOA_THROBBER_VIEW_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+
+@protocol ThrobberDataDelegate;
+
+// A class that knows how to draw an animated state to indicate progress.
+// Creating the class starts the animation, destroying it stops it. There are
+// two types:
+//
+// - Filmstrip: Draws via a sequence of frames in an image. There is no state
+// where the class is frozen on an image and not animating. The image needs to
+// be made of squares such that the height divides evenly into the width.
+//
+// - Toast: Draws an image animating down to the bottom and then another image
+// animating up from the bottom. Stops once the animation is complete.
+
+@interface ThrobberView : NSView {
+ @private
+ id<ThrobberDataDelegate> dataDelegate_;
+}
+
+// Creates a filmstrip view with |frame| and image |image|.
++ (id)filmstripThrobberViewWithFrame:(NSRect)frame
+ image:(NSImage*)image;
+
+// Creates a toast view with |frame| and specified images.
++ (id)toastThrobberViewWithFrame:(NSRect)frame
+ beforeImage:(NSImage*)beforeImage
+ afterImage:(NSImage*)afterImage;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_THROBBER_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/throbber_view.mm b/chrome/browser/ui/cocoa/throbber_view.mm
new file mode 100644
index 0000000..c0e5dd3
--- /dev/null
+++ b/chrome/browser/ui/cocoa/throbber_view.mm
@@ -0,0 +1,372 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/throbber_view.h"
+
+#include <set>
+
+#include "base/logging.h"
+
+static const float kAnimationIntervalSeconds = 0.03; // 30ms, same as windows
+
+@interface ThrobberView(PrivateMethods)
+- (id)initWithFrame:(NSRect)frame delegate:(id<ThrobberDataDelegate>)delegate;
+- (void)maintainTimer;
+- (void)animate;
+@end
+
+@protocol ThrobberDataDelegate <NSObject>
+// Is the current frame the last frame of the animation?
+- (BOOL)animationIsComplete;
+
+// Draw the current frame into the current graphics context.
+- (void)drawFrameInRect:(NSRect)rect;
+
+// Update the frame counter.
+- (void)advanceFrame;
+@end
+
+@interface ThrobberFilmstripDelegate : NSObject
+ <ThrobberDataDelegate> {
+ scoped_nsobject<NSImage> image_;
+ unsigned int numFrames_; // Number of frames in this animation.
+ unsigned int animationFrame_; // Current frame of the animation,
+ // [0..numFrames_)
+}
+
+- (id)initWithImage:(NSImage*)image;
+
+@end
+
+@implementation ThrobberFilmstripDelegate
+
+- (id)initWithImage:(NSImage*)image {
+ if ((self = [super init])) {
+ // Reset the animation counter so there's no chance we are off the end.
+ animationFrame_ = 0;
+
+ // Ensure that the height divides evenly into the width. Cache the
+ // number of frames in the animation for later.
+ NSSize imageSize = [image size];
+ DCHECK(imageSize.height && imageSize.width);
+ if (!imageSize.height)
+ return nil;
+ DCHECK((int)imageSize.width % (int)imageSize.height == 0);
+ numFrames_ = (int)imageSize.width / (int)imageSize.height;
+ DCHECK(numFrames_);
+ image_.reset([image retain]);
+ }
+ return self;
+}
+
+- (BOOL)animationIsComplete {
+ return NO;
+}
+
+- (void)drawFrameInRect:(NSRect)rect {
+ float imageDimension = [image_ size].height;
+ float xOffset = animationFrame_ * imageDimension;
+ NSRect sourceImageRect =
+ NSMakeRect(xOffset, 0, imageDimension, imageDimension);
+ [image_ drawInRect:rect
+ fromRect:sourceImageRect
+ operation:NSCompositeSourceOver
+ fraction:1.0];
+}
+
+- (void)advanceFrame {
+ animationFrame_ = ++animationFrame_ % numFrames_;
+}
+
+@end
+
+@interface ThrobberToastDelegate : NSObject
+ <ThrobberDataDelegate> {
+ scoped_nsobject<NSImage> image1_;
+ scoped_nsobject<NSImage> image2_;
+ NSSize image1Size_;
+ NSSize image2Size_;
+ int animationFrame_; // Current frame of the animation,
+}
+
+- (id)initWithImage1:(NSImage*)image1 image2:(NSImage*)image2;
+
+@end
+
+@implementation ThrobberToastDelegate
+
+- (id)initWithImage1:(NSImage*)image1 image2:(NSImage*)image2 {
+ if ((self = [super init])) {
+ image1_.reset([image1 retain]);
+ image2_.reset([image2 retain]);
+ image1Size_ = [image1 size];
+ image2Size_ = [image2 size];
+ animationFrame_ = 0;
+ }
+ return self;
+}
+
+- (BOOL)animationIsComplete {
+ if (animationFrame_ >= image1Size_.height + image2Size_.height)
+ return YES;
+
+ return NO;
+}
+
+// From [0..image1Height) we draw image1, at image1Height we draw nothing, and
+// from [image1Height+1..image1Hight+image2Height] we draw the second image.
+- (void)drawFrameInRect:(NSRect)rect {
+ NSImage* image = nil;
+ NSSize srcSize;
+ NSRect destRect;
+
+ if (animationFrame_ < image1Size_.height) {
+ image = image1_.get();
+ srcSize = image1Size_;
+ destRect = NSMakeRect(0, -animationFrame_,
+ image1Size_.width, image1Size_.height);
+ } else if (animationFrame_ == image1Size_.height) {
+ // nothing; intermediate blank frame
+ } else {
+ image = image2_.get();
+ srcSize = image2Size_;
+ destRect = NSMakeRect(0, animationFrame_ -
+ (image1Size_.height + image2Size_.height),
+ image2Size_.width, image2Size_.height);
+ }
+
+ if (image) {
+ NSRect sourceImageRect =
+ NSMakeRect(0, 0, srcSize.width, srcSize.height);
+ [image drawInRect:destRect
+ fromRect:sourceImageRect
+ operation:NSCompositeSourceOver
+ fraction:1.0];
+ }
+}
+
+- (void)advanceFrame {
+ ++animationFrame_;
+}
+
+@end
+
+typedef std::set<ThrobberView*> ThrobberSet;
+
+// ThrobberTimer manages the animation of a set of ThrobberViews. It allows
+// a single timer instance to be shared among as many ThrobberViews as needed.
+@interface ThrobberTimer : NSObject {
+ @private
+ // A set of weak references to each ThrobberView that should be notified
+ // whenever the timer fires.
+ ThrobberSet throbbers_;
+
+ // Weak reference to the timer that calls back to this object. The timer
+ // retains this object.
+ NSTimer* timer_;
+
+ // Whether the timer is actively running. To avoid timer construction
+ // and destruction overhead, the timer is not invalidated when it is not
+ // needed, but its next-fire date is set to [NSDate distantFuture].
+ // It is not possible to determine whether the timer has been suspended by
+ // comparing its fireDate to [NSDate distantFuture], though, so a separate
+ // variable is used to track this state.
+ BOOL timerRunning_;
+
+ // The thread that created this object. Used to validate that ThrobberViews
+ // are only added and removed on the same thread that the fire action will
+ // be performed on.
+ NSThread* validThread_;
+}
+
+// Returns a shared ThrobberTimer. Everyone is expected to use the same
+// instance.
++ (ThrobberTimer*)sharedThrobberTimer;
+
+// Invalidates the timer, which will cause it to remove itself from the run
+// loop. This causes the timer to be released, and it should then release
+// this object.
+- (void)invalidate;
+
+// Adds or removes ThrobberView objects from the throbbers_ set.
+- (void)addThrobber:(ThrobberView*)throbber;
+- (void)removeThrobber:(ThrobberView*)throbber;
+@end
+
+@interface ThrobberTimer(PrivateMethods)
+// Starts or stops the timer as needed as ThrobberViews are added and removed
+// from the throbbers_ set.
+- (void)maintainTimer;
+
+// Calls animate on each ThrobberView in the throbbers_ set.
+- (void)fire:(NSTimer*)timer;
+@end
+
+@implementation ThrobberTimer
+- (id)init {
+ if ((self = [super init])) {
+ // Start out with a timer that fires at the appropriate interval, but
+ // prevent it from firing by setting its next-fire date to the distant
+ // future. Once a ThrobberView is added, the timer will be allowed to
+ // start firing.
+ timer_ = [NSTimer scheduledTimerWithTimeInterval:kAnimationIntervalSeconds
+ target:self
+ selector:@selector(fire:)
+ userInfo:nil
+ repeats:YES];
+ [timer_ setFireDate:[NSDate distantFuture]];
+ timerRunning_ = NO;
+
+ validThread_ = [NSThread currentThread];
+ }
+ return self;
+}
+
++ (ThrobberTimer*)sharedThrobberTimer {
+ // Leaked. That's OK, it's scoped to the lifetime of the application.
+ static ThrobberTimer* sharedInstance = [[ThrobberTimer alloc] init];
+ return sharedInstance;
+}
+
+- (void)invalidate {
+ [timer_ invalidate];
+}
+
+- (void)addThrobber:(ThrobberView*)throbber {
+ DCHECK([NSThread currentThread] == validThread_);
+ throbbers_.insert(throbber);
+ [self maintainTimer];
+}
+
+- (void)removeThrobber:(ThrobberView*)throbber {
+ DCHECK([NSThread currentThread] == validThread_);
+ throbbers_.erase(throbber);
+ [self maintainTimer];
+}
+
+- (void)maintainTimer {
+ BOOL oldRunning = timerRunning_;
+ BOOL newRunning = throbbers_.empty() ? NO : YES;
+
+ if (oldRunning == newRunning)
+ return;
+
+ // To start the timer, set its next-fire date to an appropriate interval from
+ // now. To suspend the timer, set its next-fire date to a preposterous time
+ // in the future.
+ NSDate* fireDate;
+ if (newRunning)
+ fireDate = [NSDate dateWithTimeIntervalSinceNow:kAnimationIntervalSeconds];
+ else
+ fireDate = [NSDate distantFuture];
+
+ [timer_ setFireDate:fireDate];
+ timerRunning_ = newRunning;
+}
+
+- (void)fire:(NSTimer*)timer {
+ // The call to [throbber animate] may result in the ThrobberView calling
+ // removeThrobber: if it decides it's done animating. That would invalidate
+ // the iterator, making it impossible to correctly get to the next element
+ // in the set. To prevent that from happening, a second iterator is used
+ // and incremented before calling [throbber animate].
+ ThrobberSet::const_iterator current = throbbers_.begin();
+ ThrobberSet::const_iterator next = current;
+ while (current != throbbers_.end()) {
+ ++next;
+ ThrobberView* throbber = *current;
+ [throbber animate];
+ current = next;
+ }
+}
+@end
+
+@implementation ThrobberView
+
++ (id)filmstripThrobberViewWithFrame:(NSRect)frame
+ image:(NSImage*)image {
+ ThrobberFilmstripDelegate* delegate =
+ [[[ThrobberFilmstripDelegate alloc] initWithImage:image] autorelease];
+ if (!delegate)
+ return nil;
+
+ return [[[ThrobberView alloc] initWithFrame:frame
+ delegate:delegate] autorelease];
+}
+
++ (id)toastThrobberViewWithFrame:(NSRect)frame
+ beforeImage:(NSImage*)beforeImage
+ afterImage:(NSImage*)afterImage {
+ ThrobberToastDelegate* delegate =
+ [[[ThrobberToastDelegate alloc] initWithImage1:beforeImage
+ image2:afterImage] autorelease];
+ if (!delegate)
+ return nil;
+
+ return [[[ThrobberView alloc] initWithFrame:frame
+ delegate:delegate] autorelease];
+}
+
+- (id)initWithFrame:(NSRect)frame delegate:(id<ThrobberDataDelegate>)delegate {
+ if ((self = [super initWithFrame:frame])) {
+ dataDelegate_ = [delegate retain];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [dataDelegate_ release];
+ [[ThrobberTimer sharedThrobberTimer] removeThrobber:self];
+
+ [super dealloc];
+}
+
+// Manages this ThrobberView's membership in the shared throbber timer set on
+// the basis of its visibility and whether its animation needs to continue
+// running.
+- (void)maintainTimer {
+ ThrobberTimer* throbberTimer = [ThrobberTimer sharedThrobberTimer];
+
+ if ([self window] && ![self isHidden] && ![dataDelegate_ animationIsComplete])
+ [throbberTimer addThrobber:self];
+ else
+ [throbberTimer removeThrobber:self];
+}
+
+// A ThrobberView added to a window may need to begin animating; a ThrobberView
+// removed from a window should stop.
+- (void)viewDidMoveToWindow {
+ [self maintainTimer];
+ [super viewDidMoveToWindow];
+}
+
+// A hidden ThrobberView should stop animating.
+- (void)viewDidHide {
+ [self maintainTimer];
+ [super viewDidHide];
+}
+
+// A visible ThrobberView may need to start animating.
+- (void)viewDidUnhide {
+ [self maintainTimer];
+ [super viewDidUnhide];
+}
+
+// Called when the timer fires. Advance the frame, dirty the display, and remove
+// the throbber if it's no longer needed.
+- (void)animate {
+ [dataDelegate_ advanceFrame];
+ [self setNeedsDisplay:YES];
+
+ if ([dataDelegate_ animationIsComplete]) {
+ [[ThrobberTimer sharedThrobberTimer] removeThrobber:self];
+ }
+}
+
+// Overridden to draw the appropriate frame in the image strip.
+- (void)drawRect:(NSRect)rect {
+ [dataDelegate_ drawFrameInRect:[self bounds]];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/throbber_view_unittest.mm b/chrome/browser/ui/cocoa/throbber_view_unittest.mm
new file mode 100644
index 0000000..b1a2ce4
--- /dev/null
+++ b/chrome/browser/ui/cocoa/throbber_view_unittest.mm
@@ -0,0 +1,32 @@
+// Copyright (c) 2009 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 "app/resource_bundle.h"
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/throbber_view.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+#include "grit/app_resources.h"
+
+namespace {
+
+class ThrobberViewTest : public CocoaTest {
+ public:
+ ThrobberViewTest() {
+ NSRect frame = NSMakeRect(10, 10, 16, 16);
+ NSImage* image =
+ ResourceBundle::GetSharedInstance().GetNativeImageNamed(IDR_THROBBER);
+ view_ = [ThrobberView filmstripThrobberViewWithFrame:frame image:image];
+ [[test_window() contentView] addSubview:view_];
+ }
+
+ ThrobberView* view_;
+};
+
+TEST_VIEW(ThrobberViewTest, view_)
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/toolbar_controller.h b/chrome/browser/ui/cocoa/toolbar_controller.h
new file mode 100644
index 0000000..029f89d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/toolbar_controller.h
@@ -0,0 +1,189 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_TOOLBAR_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_TOOLBAR_CONTROLLER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_ptr.h"
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/command_observer_bridge.h"
+#import "chrome/browser/ui/cocoa/delayedmenu_button.h"
+#import "chrome/browser/ui/cocoa/url_drop_target.h"
+#import "chrome/browser/ui/cocoa/view_resizer.h"
+#include "chrome/browser/prefs/pref_member.h"
+
+@class AutocompleteTextField;
+@class AutocompleteTextFieldEditor;
+@class BrowserActionsContainerView;
+@class BackForwardMenuController;
+class Browser;
+@class BrowserActionsController;
+class CommandUpdater;
+@class DelayedMenuButton;
+class LocationBar;
+class LocationBarViewMac;
+@class MenuButton;
+namespace ToolbarControllerInternal {
+class NotificationBridge;
+class WrenchAcceleratorDelegate;
+} // namespace ToolbarControllerInternal
+class Profile;
+@class ReloadButton;
+class TabContents;
+class ToolbarModel;
+@class WrenchMenuController;
+class WrenchMenuModel;
+
+// A controller for the toolbar in the browser window. Manages
+// updating the state for location bar and back/fwd/reload/go buttons.
+// Manages the bookmark bar and its position in the window relative to
+// the web content view.
+
+@interface ToolbarController : NSViewController<CommandObserverProtocol,
+ URLDropTargetController> {
+ @protected
+ // The ordering is important for unit tests. If new items are added or the
+ // ordering is changed, make sure to update |-toolbarViews| and the
+ // corresponding enum in the unit tests.
+ IBOutlet DelayedMenuButton* backButton_;
+ IBOutlet DelayedMenuButton* forwardButton_;
+ IBOutlet ReloadButton* reloadButton_;
+ IBOutlet NSButton* homeButton_;
+ IBOutlet MenuButton* wrenchButton_;
+ IBOutlet AutocompleteTextField* locationBar_;
+ IBOutlet BrowserActionsContainerView* browserActionsContainerView_;
+ IBOutlet WrenchMenuController* wrenchMenuController_;
+
+ @private
+ ToolbarModel* toolbarModel_; // weak, one per window
+ CommandUpdater* commands_; // weak, one per window
+ Profile* profile_; // weak, one per window
+ Browser* browser_; // weak, one per window
+ scoped_ptr<CommandObserverBridge> commandObserver_;
+ scoped_ptr<LocationBarViewMac> locationBarView_;
+ scoped_nsobject<AutocompleteTextFieldEditor> autocompleteTextFieldEditor_;
+ id<ViewResizer> resizeDelegate_; // weak
+ scoped_nsobject<BackForwardMenuController> backMenuController_;
+ scoped_nsobject<BackForwardMenuController> forwardMenuController_;
+ scoped_nsobject<BrowserActionsController> browserActionsController_;
+
+ // Lazily-instantiated model and delegate for the menu on the
+ // wrench button. Once visible, it will be non-null, but will not
+ // reaped when the menu is hidden once it is initially shown.
+ scoped_ptr<ToolbarControllerInternal::WrenchAcceleratorDelegate>
+ acceleratorDelegate_;
+ scoped_ptr<WrenchMenuModel> wrenchMenuModel_;
+
+ // Used for monitoring the optional toolbar button prefs.
+ scoped_ptr<ToolbarControllerInternal::NotificationBridge> notificationBridge_;
+ BooleanPrefMember showHomeButton_;
+ BooleanPrefMember showPageOptionButtons_;
+ BOOL hasToolbar_; // If NO, we may have only the location bar.
+ BOOL hasLocationBar_; // If |hasToolbar_| is YES, this must also be YES.
+ BOOL locationBarAtMinSize_; // If the location bar is at the minimum size.
+
+ // We have an extra retain in the locationBar_.
+ // See comments in awakeFromNib for more info.
+ scoped_nsobject<AutocompleteTextField> locationBarRetainer_;
+
+ // Tracking area for mouse enter/exit/moved in the toolbar.
+ scoped_nsobject<NSTrackingArea> trackingArea_;
+
+ // We retain/release the hover button since interaction with the
+ // button may make it go away (e.g. delete menu option over a
+ // bookmark button). Thus this variable is not weak. The
+ // hoveredButton_ is required to have an NSCell that responds to
+ // setMouseInside:animate:.
+ NSButton* hoveredButton_;
+}
+
+// Initialize the toolbar and register for command updates. The profile is
+// needed for initializing the location bar. The browser is needed for
+// initializing the back/forward menus.
+- (id)initWithModel:(ToolbarModel*)model
+ commands:(CommandUpdater*)commands
+ profile:(Profile*)profile
+ browser:(Browser*)browser
+ resizeDelegate:(id<ViewResizer>)resizeDelegate;
+
+// Get the C++ bridge object representing the location bar for this tab.
+- (LocationBarViewMac*)locationBarBridge;
+
+// Called by the Window delegate so we can provide a custom field editor if
+// needed.
+// Note that this may be called for objects unrelated to the toolbar.
+// returns nil if we don't want to override the custom field editor for |obj|.
+- (id)customFieldEditorForObject:(id)obj;
+
+// Make the location bar the first responder, if possible.
+- (void)focusLocationBar:(BOOL)selectAll;
+
+// Updates the toolbar (and transitively the location bar) with the states of
+// the specified |tab|. If |shouldRestore| is true, we're switching
+// (back?) to this tab and should restore any previous location bar state
+// (such as user editing) as well.
+- (void)updateToolbarWithContents:(TabContents*)tabForRestoring
+ shouldRestoreState:(BOOL)shouldRestore;
+
+// Sets whether or not the current page in the frontmost tab is bookmarked.
+- (void)setStarredState:(BOOL)isStarred;
+
+// Called to update the loading state. Handles updating the go/stop
+// button state. |force| is set if the update is due to changing
+// tabs, as opposed to the page-load finishing. See comment in
+// reload_button.h.
+- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force;
+
+// Allow turning off the toolbar (but we may keep the location bar without a
+// surrounding toolbar). If |toolbar| is YES, the value of |hasLocationBar| is
+// ignored. This changes the behavior of other methods, like |-view|.
+- (void)setHasToolbar:(BOOL)toolbar hasLocationBar:(BOOL)locBar;
+
+// Point on the star icon for the bookmark bubble to be - in the
+// associated window's coordinate system.
+- (NSPoint)bookmarkBubblePoint;
+
+// Returns the desired toolbar height for the given compression factor.
+- (CGFloat)desiredHeightForCompression:(CGFloat)compressByHeight;
+
+// Set the opacity of the divider (the line at the bottom) *if* we have a
+// |ToolbarView| (0 means don't show it); no-op otherwise.
+- (void)setDividerOpacity:(CGFloat)opacity;
+
+// Create and add the Browser Action buttons to the toolbar view.
+- (void)createBrowserActionButtons;
+
+// Return the BrowserActionsController for this toolbar.
+- (BrowserActionsController*)browserActionsController;
+
+@end
+
+// A set of private methods used by subclasses. Do not call these directly
+// unless a subclass of ToolbarController.
+@interface ToolbarController(ProtectedMethods)
+// Designated initializer which takes a nib name in order to allow subclasses
+// to load a different nib file.
+- (id)initWithModel:(ToolbarModel*)model
+ commands:(CommandUpdater*)commands
+ profile:(Profile*)profile
+ browser:(Browser*)browser
+ resizeDelegate:(id<ViewResizer>)resizeDelegate
+ nibFileNamed:(NSString*)nibName;
+@end
+
+// A set of private methods used by tests, in the absence of "friends" in ObjC.
+@interface ToolbarController(PrivateTestMethods)
+// Returns an array of views in the order of the outlets above.
+- (NSArray*)toolbarViews;
+- (void)showOptionalHomeButton;
+- (void)installWrenchMenu;
+- (WrenchMenuController*)wrenchMenuController;
+// Return a hover button for the current event.
+- (NSButton*)hoverButtonForEvent:(NSEvent*)theEvent;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_TOOLBAR_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/toolbar_controller.mm b/chrome/browser/ui/cocoa/toolbar_controller.mm
new file mode 100644
index 0000000..1b953fd
--- /dev/null
+++ b/chrome/browser/ui/cocoa/toolbar_controller.mm
@@ -0,0 +1,806 @@
+// 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 "chrome/browser/ui/cocoa/toolbar_controller.h"
+
+#include <algorithm>
+
+#include "app/l10n_util.h"
+#include "app/l10n_util_mac.h"
+#include "app/mac/nsimage_cache.h"
+#include "app/menus/accelerator_cocoa.h"
+#include "app/menus/menu_model.h"
+#include "app/resource_bundle.h"
+#include "base/mac_util.h"
+#include "base/singleton.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/autocomplete/autocomplete.h"
+#include "chrome/browser/autocomplete/autocomplete_classifier.h"
+#include "chrome/browser/autocomplete/autocomplete_edit_view.h"
+#include "chrome/browser/autocomplete/autocomplete_match.h"
+#include "chrome/browser/background_page_tracker.h"
+#include "chrome/browser/net/url_fixer_upper.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/upgrade_detector.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
+#import "chrome/browser/ui/cocoa/accelerators_cocoa.h"
+#import "chrome/browser/ui/cocoa/back_forward_menu_controller.h"
+#import "chrome/browser/ui/cocoa/background_gradient_view.h"
+#import "chrome/browser/ui/cocoa/encoding_menu_controller_delegate_mac.h"
+#import "chrome/browser/ui/cocoa/extensions/browser_action_button.h"
+#import "chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h"
+#import "chrome/browser/ui/cocoa/extensions/browser_actions_controller.h"
+#import "chrome/browser/ui/cocoa/gradient_button_cell.h"
+#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h"
+#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
+#import "chrome/browser/ui/cocoa/menu_button.h"
+#import "chrome/browser/ui/cocoa/menu_controller.h"
+#import "chrome/browser/ui/cocoa/reload_button.h"
+#import "chrome/browser/ui/cocoa/toolbar_view.h"
+#import "chrome/browser/ui/cocoa/view_id_util.h"
+#import "chrome/browser/ui/cocoa/wrench_menu_controller.h"
+#include "chrome/browser/ui/toolbar/toolbar_model.h"
+#include "chrome/browser/ui/toolbar/wrench_menu_model.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
+#include "chrome/common/pref_names.h"
+#include "gfx/rect.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+
+namespace {
+
+// Names of images in the bundle for buttons.
+NSString* const kBackButtonImageName = @"back_Template.pdf";
+NSString* const kForwardButtonImageName = @"forward_Template.pdf";
+NSString* const kReloadButtonReloadImageName = @"reload_Template.pdf";
+NSString* const kReloadButtonStopImageName = @"stop_Template.pdf";
+NSString* const kHomeButtonImageName = @"home_Template.pdf";
+NSString* const kWrenchButtonImageName = @"tools_Template.pdf";
+
+// Height of the toolbar in pixels when the bookmark bar is closed.
+const CGFloat kBaseToolbarHeight = 35.0;
+
+// The minimum width of the location bar in pixels.
+const CGFloat kMinimumLocationBarWidth = 100.0;
+
+// The duration of any animation that occurs within the toolbar in seconds.
+const CGFloat kAnimationDuration = 0.2;
+
+// The amount of left padding that the wrench menu should have.
+const CGFloat kWrenchMenuLeftPadding = 3.0;
+
+} // namespace
+
+@interface ToolbarController(Private)
+- (void)addAccessibilityDescriptions;
+- (void)initCommandStatus:(CommandUpdater*)commands;
+- (void)prefChanged:(std::string*)prefName;
+- (BackgroundGradientView*)backgroundGradientView;
+- (void)toolbarFrameChanged;
+- (void)pinLocationBarToLeftOfBrowserActionsContainerAndAnimate:(BOOL)animate;
+- (void)maintainMinimumLocationBarWidth;
+- (void)adjustBrowserActionsContainerForNewWindow:(NSNotification*)notification;
+- (void)browserActionsContainerDragged:(NSNotification*)notification;
+- (void)browserActionsContainerDragFinished:(NSNotification*)notification;
+- (void)browserActionsVisibilityChanged:(NSNotification*)notification;
+- (void)adjustLocationSizeBy:(CGFloat)dX animate:(BOOL)animate;
+- (void)badgeWrenchMenuIfNeeded;
+@end
+
+namespace ToolbarControllerInternal {
+
+// A C++ delegate that handles the accelerators in the wrench menu.
+class WrenchAcceleratorDelegate : public menus::AcceleratorProvider {
+ public:
+ virtual bool GetAcceleratorForCommandId(int command_id,
+ menus::Accelerator* accelerator_generic) {
+ // Downcast so that when the copy constructor is invoked below, the key
+ // string gets copied, too.
+ menus::AcceleratorCocoa* out_accelerator =
+ static_cast<menus::AcceleratorCocoa*>(accelerator_generic);
+ AcceleratorsCocoa* keymap = AcceleratorsCocoa::GetInstance();
+ const menus::AcceleratorCocoa* accelerator =
+ keymap->GetAcceleratorForCommand(command_id);
+ if (accelerator) {
+ *out_accelerator = *accelerator;
+ return true;
+ }
+ return false;
+ }
+};
+
+// A class registered for C++ notifications. This is used to detect changes in
+// preferences and upgrade available notifications. Bridges the notification
+// back to the ToolbarController.
+class NotificationBridge : public NotificationObserver {
+ public:
+ explicit NotificationBridge(ToolbarController* controller)
+ : controller_(controller) {
+ registrar_.Add(this, NotificationType::UPGRADE_RECOMMENDED,
+ NotificationService::AllSources());
+ registrar_.Add(this,
+ NotificationType::BACKGROUND_PAGE_TRACKER_CHANGED,
+ NotificationService::AllSources());
+ }
+
+ // Overridden from NotificationObserver:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ switch (type.value) {
+ case NotificationType::PREF_CHANGED:
+ [controller_ prefChanged:Details<std::string>(details).ptr()];
+ break;
+ case NotificationType::BACKGROUND_PAGE_TRACKER_CHANGED:
+ // fall-through
+ case NotificationType::UPGRADE_RECOMMENDED:
+ [controller_ badgeWrenchMenuIfNeeded];
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+
+ private:
+ ToolbarController* controller_; // weak, owns us
+
+ NotificationRegistrar registrar_;
+};
+
+} // namespace ToolbarControllerInternal
+
+@implementation ToolbarController
+
+- (id)initWithModel:(ToolbarModel*)model
+ commands:(CommandUpdater*)commands
+ profile:(Profile*)profile
+ browser:(Browser*)browser
+ resizeDelegate:(id<ViewResizer>)resizeDelegate
+ nibFileNamed:(NSString*)nibName {
+ DCHECK(model && commands && profile && [nibName length]);
+ if ((self = [super initWithNibName:nibName
+ bundle:mac_util::MainAppBundle()])) {
+ toolbarModel_ = model;
+ commands_ = commands;
+ profile_ = profile;
+ browser_ = browser;
+ resizeDelegate_ = resizeDelegate;
+ hasToolbar_ = YES;
+ hasLocationBar_ = YES;
+
+ // Register for notifications about state changes for the toolbar buttons
+ commandObserver_.reset(new CommandObserverBridge(self, commands));
+ commandObserver_->ObserveCommand(IDC_BACK);
+ commandObserver_->ObserveCommand(IDC_FORWARD);
+ commandObserver_->ObserveCommand(IDC_RELOAD);
+ commandObserver_->ObserveCommand(IDC_HOME);
+ commandObserver_->ObserveCommand(IDC_BOOKMARK_PAGE);
+ }
+ return self;
+}
+
+- (id)initWithModel:(ToolbarModel*)model
+ commands:(CommandUpdater*)commands
+ profile:(Profile*)profile
+ browser:(Browser*)browser
+ resizeDelegate:(id<ViewResizer>)resizeDelegate {
+ if ((self = [self initWithModel:model
+ commands:commands
+ profile:profile
+ browser:browser
+ resizeDelegate:resizeDelegate
+ nibFileNamed:@"Toolbar"])) {
+ }
+ return self;
+}
+
+
+- (void)dealloc {
+ // Unset ViewIDs of toolbar elements.
+ // ViewIDs of |toolbarView|, |reloadButton_|, |locationBar_| and
+ // |browserActionsContainerView_| are handled by themselves.
+ view_id_util::UnsetID(backButton_);
+ view_id_util::UnsetID(forwardButton_);
+ view_id_util::UnsetID(homeButton_);
+ view_id_util::UnsetID(wrenchButton_);
+
+ // Make sure any code in the base class which assumes [self view] is
+ // the "parent" view continues to work.
+ hasToolbar_ = YES;
+ hasLocationBar_ = YES;
+
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+
+ if (trackingArea_.get())
+ [[self view] removeTrackingArea:trackingArea_.get()];
+ [super dealloc];
+}
+
+// Called after the view is done loading and the outlets have been hooked up.
+// Now we can hook up bridges that rely on UI objects such as the location
+// bar and button state.
+- (void)awakeFromNib {
+ // A bug in AppKit (<rdar://7298597>, <http://openradar.me/7298597>) causes
+ // images loaded directly from nibs in a framework to not get their "template"
+ // flags set properly. Thus, despite the images being set on the buttons in
+ // the xib, we must set them in code.
+ [backButton_ setImage:app::mac::GetCachedImageWithName(kBackButtonImageName)];
+ [forwardButton_ setImage:
+ app::mac::GetCachedImageWithName(kForwardButtonImageName)];
+ [reloadButton_ setImage:
+ app::mac::GetCachedImageWithName(kReloadButtonReloadImageName)];
+ [homeButton_ setImage:
+ app::mac::GetCachedImageWithName(kHomeButtonImageName)];
+ [wrenchButton_ setImage:
+ app::mac::GetCachedImageWithName(kWrenchButtonImageName)];
+ [self badgeWrenchMenuIfNeeded];
+
+ [backButton_ setShowsBorderOnlyWhileMouseInside:YES];
+ [forwardButton_ setShowsBorderOnlyWhileMouseInside:YES];
+ [reloadButton_ setShowsBorderOnlyWhileMouseInside:YES];
+ [homeButton_ setShowsBorderOnlyWhileMouseInside:YES];
+ [wrenchButton_ setShowsBorderOnlyWhileMouseInside:YES];
+
+ [self initCommandStatus:commands_];
+ locationBarView_.reset(new LocationBarViewMac(locationBar_,
+ commands_, toolbarModel_,
+ profile_, browser_));
+ [locationBar_ setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]];
+ // Register pref observers for the optional home and page/options buttons
+ // and then add them to the toolbar based on those prefs.
+ notificationBridge_.reset(
+ new ToolbarControllerInternal::NotificationBridge(self));
+ PrefService* prefs = profile_->GetPrefs();
+ showHomeButton_.Init(prefs::kShowHomeButton, prefs,
+ notificationBridge_.get());
+ showPageOptionButtons_.Init(prefs::kShowPageOptionsButtons, prefs,
+ notificationBridge_.get());
+ [self showOptionalHomeButton];
+ [self installWrenchMenu];
+
+ // Create the controllers for the back/forward menus.
+ backMenuController_.reset([[BackForwardMenuController alloc]
+ initWithBrowser:browser_
+ modelType:BACK_FORWARD_MENU_TYPE_BACK
+ button:backButton_]);
+ forwardMenuController_.reset([[BackForwardMenuController alloc]
+ initWithBrowser:browser_
+ modelType:BACK_FORWARD_MENU_TYPE_FORWARD
+ button:forwardButton_]);
+
+ // For a popup window, the toolbar is really just a location bar
+ // (see override for [ToolbarController view], below). When going
+ // fullscreen, we remove the toolbar controller's view from the view
+ // hierarchy. Calling [locationBar_ removeFromSuperview] when going
+ // fullscreen causes it to get released, making us unhappy
+ // (http://crbug.com/18551). We avoid the problem by incrementing
+ // the retain count of the location bar; use of the scoped object
+ // helps us remember to release it.
+ locationBarRetainer_.reset([locationBar_ retain]);
+ trackingArea_.reset(
+ [[NSTrackingArea alloc] initWithRect:NSZeroRect // Ignored
+ options:NSTrackingMouseMoved |
+ NSTrackingInVisibleRect |
+ NSTrackingMouseEnteredAndExited |
+ NSTrackingActiveAlways
+ owner:self
+ userInfo:nil]);
+ NSView* toolbarView = [self view];
+ [toolbarView addTrackingArea:trackingArea_.get()];
+
+ // If the user has any Browser Actions installed, the container view for them
+ // may have to be resized depending on the width of the toolbar frame.
+ [toolbarView setPostsFrameChangedNotifications:YES];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(toolbarFrameChanged)
+ name:NSViewFrameDidChangeNotification
+ object:toolbarView];
+
+ // Set ViewIDs for toolbar elements which don't have their dedicated class.
+ // ViewIDs of |toolbarView|, |reloadButton_|, |locationBar_| and
+ // |browserActionsContainerView_| are handled by themselves.
+ view_id_util::SetID(backButton_, VIEW_ID_BACK_BUTTON);
+ view_id_util::SetID(forwardButton_, VIEW_ID_FORWARD_BUTTON);
+ view_id_util::SetID(homeButton_, VIEW_ID_HOME_BUTTON);
+ view_id_util::SetID(wrenchButton_, VIEW_ID_APP_MENU);
+
+ [self addAccessibilityDescriptions];
+}
+
+- (void)addAccessibilityDescriptions {
+ // Set accessibility descriptions. http://openradar.appspot.com/7496255
+ NSString* description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_BACK);
+ [[backButton_ cell]
+ accessibilitySetOverrideValue:description
+ forAttribute:NSAccessibilityDescriptionAttribute];
+ description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_FORWARD);
+ [[forwardButton_ cell]
+ accessibilitySetOverrideValue:description
+ forAttribute:NSAccessibilityDescriptionAttribute];
+ description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_RELOAD);
+ [[reloadButton_ cell]
+ accessibilitySetOverrideValue:description
+ forAttribute:NSAccessibilityDescriptionAttribute];
+ description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_HOME);
+ [[homeButton_ cell]
+ accessibilitySetOverrideValue:description
+ forAttribute:NSAccessibilityDescriptionAttribute];
+ description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_LOCATION);
+ [[locationBar_ cell]
+ accessibilitySetOverrideValue:description
+ forAttribute:NSAccessibilityDescriptionAttribute];
+ description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_APP);
+ [[wrenchButton_ cell]
+ accessibilitySetOverrideValue:description
+ forAttribute:NSAccessibilityDescriptionAttribute];
+}
+
+- (void)mouseExited:(NSEvent*)theEvent {
+ [[hoveredButton_ cell] setMouseInside:NO animate:YES];
+ [hoveredButton_ release];
+ hoveredButton_ = nil;
+}
+
+- (NSButton*)hoverButtonForEvent:(NSEvent*)theEvent {
+ NSButton* targetView = (NSButton*)[[self view]
+ hitTest:[theEvent locationInWindow]];
+
+ // Only interpret the view as a hoverButton_ if it's both button and has a
+ // button cell that cares. GradientButtonCell derived cells care.
+ if (([targetView isKindOfClass:[NSButton class]]) &&
+ ([[targetView cell]
+ respondsToSelector:@selector(setMouseInside:animate:)]))
+ return targetView;
+ return nil;
+}
+
+- (void)mouseMoved:(NSEvent*)theEvent {
+ NSButton* targetView = [self hoverButtonForEvent:theEvent];
+ if (hoveredButton_ != targetView) {
+ [[hoveredButton_ cell] setMouseInside:NO animate:YES];
+ [[targetView cell] setMouseInside:YES animate:YES];
+ [hoveredButton_ release];
+ hoveredButton_ = [targetView retain];
+ }
+}
+
+- (void)mouseEntered:(NSEvent*)event {
+ [self mouseMoved:event];
+}
+
+- (LocationBarViewMac*)locationBarBridge {
+ return locationBarView_.get();
+}
+
+- (void)focusLocationBar:(BOOL)selectAll {
+ if (locationBarView_.get())
+ locationBarView_->FocusLocation(selectAll ? true : false);
+}
+
+// Called when the state for a command changes to |enabled|. Update the
+// corresponding UI element.
+- (void)enabledStateChangedForCommand:(NSInteger)command enabled:(BOOL)enabled {
+ NSButton* button = nil;
+ switch (command) {
+ case IDC_BACK:
+ button = backButton_;
+ break;
+ case IDC_FORWARD:
+ button = forwardButton_;
+ break;
+ case IDC_HOME:
+ button = homeButton_;
+ break;
+ }
+ [button setEnabled:enabled];
+}
+
+// Init the enabled state of the buttons on the toolbar to match the state in
+// the controller.
+- (void)initCommandStatus:(CommandUpdater*)commands {
+ [backButton_ setEnabled:commands->IsCommandEnabled(IDC_BACK) ? YES : NO];
+ [forwardButton_
+ setEnabled:commands->IsCommandEnabled(IDC_FORWARD) ? YES : NO];
+ [reloadButton_ setEnabled:YES];
+ [homeButton_ setEnabled:commands->IsCommandEnabled(IDC_HOME) ? YES : NO];
+}
+
+- (void)updateToolbarWithContents:(TabContents*)tab
+ shouldRestoreState:(BOOL)shouldRestore {
+ locationBarView_->Update(tab, shouldRestore ? true : false);
+
+ [locationBar_ updateCursorAndToolTipRects];
+
+ if (browserActionsController_.get()) {
+ [browserActionsController_ update];
+ }
+}
+
+- (void)setStarredState:(BOOL)isStarred {
+ locationBarView_->SetStarred(isStarred ? true : false);
+}
+
+- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force {
+ [reloadButton_ setIsLoading:isLoading force:force];
+}
+
+- (void)setHasToolbar:(BOOL)toolbar hasLocationBar:(BOOL)locBar {
+ [self view]; // Force nib loading.
+
+ hasToolbar_ = toolbar;
+
+ // If there's a toolbar, there must be a location bar.
+ DCHECK((toolbar && locBar) || !toolbar);
+ hasLocationBar_ = toolbar ? YES : locBar;
+
+ // Decide whether to hide/show based on whether there's a location bar.
+ [[self view] setHidden:!hasLocationBar_];
+
+ // Make location bar not editable when in a pop-up.
+ locationBarView_->SetEditable(toolbar);
+}
+
+- (NSView*)view {
+ if (hasToolbar_)
+ return [super view];
+ return locationBar_;
+}
+
+// (Private) Returns the backdrop to the toolbar.
+- (BackgroundGradientView*)backgroundGradientView {
+ // We really do mean |[super view]|; see our override of |-view|.
+ DCHECK([[super view] isKindOfClass:[BackgroundGradientView class]]);
+ return (BackgroundGradientView*)[super view];
+}
+
+- (id)customFieldEditorForObject:(id)obj {
+ if (obj == locationBar_) {
+ // Lazilly construct Field editor, Cocoa UI code always runs on the
+ // same thread, so there shoudn't be a race condition here.
+ if (autocompleteTextFieldEditor_.get() == nil) {
+ autocompleteTextFieldEditor_.reset(
+ [[AutocompleteTextFieldEditor alloc] init]);
+ }
+
+ // This needs to be called every time, otherwise notifications
+ // aren't sent correctly.
+ DCHECK(autocompleteTextFieldEditor_.get());
+ [autocompleteTextFieldEditor_.get() setFieldEditor:YES];
+ return autocompleteTextFieldEditor_.get();
+ }
+ return nil;
+}
+
+// Returns an array of views in the order of the outlets above.
+- (NSArray*)toolbarViews {
+ return [NSArray arrayWithObjects:backButton_, forwardButton_, reloadButton_,
+ homeButton_, wrenchButton_, locationBar_,
+ browserActionsContainerView_, nil];
+}
+
+// Moves |rect| to the right by |delta|, keeping the right side fixed by
+// shrinking the width to compensate. Passing a negative value for |deltaX|
+// moves to the left and increases the width.
+- (NSRect)adjustRect:(NSRect)rect byAmount:(CGFloat)deltaX {
+ NSRect frame = NSOffsetRect(rect, deltaX, 0);
+ frame.size.width -= deltaX;
+ return frame;
+}
+
+// Show or hide the home button based on the pref.
+- (void)showOptionalHomeButton {
+ // Ignore this message if only showing the URL bar.
+ if (!hasToolbar_)
+ return;
+ BOOL hide = showHomeButton_.GetValue() ? NO : YES;
+ if (hide == [homeButton_ isHidden])
+ return; // Nothing to do, view state matches pref state.
+
+ // Always shift the text field by the width of the home button minus one pixel
+ // since the frame edges of each button are right on top of each other. When
+ // hiding the button, reverse the direction of the movement (to the left).
+ CGFloat moveX = [homeButton_ frame].size.width - 1.0;
+ if (hide)
+ moveX *= -1; // Reverse the direction of the move.
+
+ [locationBar_ setFrame:[self adjustRect:[locationBar_ frame]
+ byAmount:moveX]];
+ [homeButton_ setHidden:hide];
+}
+
+// Install the menu wrench buttons. Calling this repeatedly is inexpensive so it
+// can be done every time the buttons are shown.
+- (void)installWrenchMenu {
+ if (wrenchMenuModel_.get())
+ return;
+ acceleratorDelegate_.reset(
+ new ToolbarControllerInternal::WrenchAcceleratorDelegate());
+
+ wrenchMenuModel_.reset(new WrenchMenuModel(
+ acceleratorDelegate_.get(), browser_));
+ [wrenchMenuController_ setModel:wrenchMenuModel_.get()];
+ [wrenchMenuController_ setUseWithPopUpButtonCell:YES];
+ [wrenchButton_ setAttachedMenu:[wrenchMenuController_ menu]];
+}
+
+- (WrenchMenuController*)wrenchMenuController {
+ return wrenchMenuController_;
+}
+
+- (void)badgeWrenchMenuIfNeeded {
+
+ int badgeResource = 0;
+ if (UpgradeDetector::GetInstance()->notify_upgrade()) {
+ badgeResource = IDR_UPDATE_BADGE;
+ } else if (BackgroundPageTracker::GetInstance()->
+ GetUnacknowledgedBackgroundPageCount() > 0) {
+ badgeResource = IDR_BACKGROUND_BADGE;
+ } else {
+ // No badge - clear the badge if one is already set.
+ if ([[wrenchButton_ cell] overlayImage])
+ [[wrenchButton_ cell] setOverlayImage:nil];
+ return;
+ }
+
+ NSImage* badge =
+ ResourceBundle::GetSharedInstance().GetNativeImageNamed(badgeResource);
+ NSImage* wrenchImage =
+ app::mac::GetCachedImageWithName(kWrenchButtonImageName);
+ NSSize wrenchImageSize = [wrenchImage size];
+ NSSize badgeSize = [badge size];
+
+ scoped_nsobject<NSImage> overlayImage(
+ [[NSImage alloc] initWithSize:wrenchImageSize]);
+
+ // Draw badge in the upper right corner of the button.
+ NSPoint overlayPosition =
+ NSMakePoint(wrenchImageSize.width - badgeSize.width,
+ wrenchImageSize.height - badgeSize.height);
+
+ [overlayImage lockFocus];
+ [badge drawAtPoint:overlayPosition
+ fromRect:NSZeroRect
+ operation:NSCompositeSourceOver
+ fraction:1.0];
+ [overlayImage unlockFocus];
+
+ [[wrenchButton_ cell] setOverlayImage:overlayImage];
+}
+
+- (void)prefChanged:(std::string*)prefName {
+ if (!prefName) return;
+ if (*prefName == prefs::kShowHomeButton) {
+ [self showOptionalHomeButton];
+ }
+}
+
+- (void)createBrowserActionButtons {
+ if (!browserActionsController_.get()) {
+ browserActionsController_.reset([[BrowserActionsController alloc]
+ initWithBrowser:browser_
+ containerView:browserActionsContainerView_]);
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(browserActionsContainerDragged:)
+ name:kBrowserActionGrippyDraggingNotification
+ object:browserActionsController_];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(browserActionsContainerDragFinished:)
+ name:kBrowserActionGrippyDragFinishedNotification
+ object:browserActionsController_];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(browserActionsVisibilityChanged:)
+ name:kBrowserActionVisibilityChangedNotification
+ object:browserActionsController_];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(adjustBrowserActionsContainerForNewWindow:)
+ name:NSWindowDidBecomeKeyNotification
+ object:[[self view] window]];
+ }
+ CGFloat containerWidth = [browserActionsContainerView_ isHidden] ? 0.0 :
+ NSWidth([browserActionsContainerView_ frame]);
+ if (containerWidth > 0.0)
+ [self adjustLocationSizeBy:(containerWidth * -1) animate:NO];
+}
+
+- (void)adjustBrowserActionsContainerForNewWindow:
+ (NSNotification*)notification {
+ [self toolbarFrameChanged];
+ [[NSNotificationCenter defaultCenter]
+ removeObserver:self
+ name:NSWindowDidBecomeKeyNotification
+ object:[[self view] window]];
+}
+
+- (void)browserActionsContainerDragged:(NSNotification*)notification {
+ CGFloat locationBarWidth = NSWidth([locationBar_ frame]);
+ locationBarAtMinSize_ = locationBarWidth <= kMinimumLocationBarWidth;
+ [browserActionsContainerView_ setCanDragLeft:!locationBarAtMinSize_];
+ [browserActionsContainerView_ setGrippyPinned:locationBarAtMinSize_];
+ [self adjustLocationSizeBy:
+ [browserActionsContainerView_ resizeDeltaX] animate:NO];
+}
+
+- (void)browserActionsContainerDragFinished:(NSNotification*)notification {
+ [browserActionsController_ resizeContainerAndAnimate:YES];
+ [self pinLocationBarToLeftOfBrowserActionsContainerAndAnimate:YES];
+}
+
+- (void)browserActionsVisibilityChanged:(NSNotification*)notification {
+ [self pinLocationBarToLeftOfBrowserActionsContainerAndAnimate:NO];
+}
+
+- (void)pinLocationBarToLeftOfBrowserActionsContainerAndAnimate:(BOOL)animate {
+ CGFloat locationBarXPos = NSMaxX([locationBar_ frame]);
+ CGFloat leftDistance;
+
+ if ([browserActionsContainerView_ isHidden]) {
+ CGFloat edgeXPos = [wrenchButton_ frame].origin.x;
+ leftDistance = edgeXPos - locationBarXPos - kWrenchMenuLeftPadding;
+ } else {
+ NSRect containerFrame = animate ?
+ [browserActionsContainerView_ animationEndFrame] :
+ [browserActionsContainerView_ frame];
+
+ leftDistance = containerFrame.origin.x - locationBarXPos;
+ }
+ if (leftDistance != 0.0)
+ [self adjustLocationSizeBy:leftDistance animate:animate];
+}
+
+- (void)maintainMinimumLocationBarWidth {
+ CGFloat locationBarWidth = NSWidth([locationBar_ frame]);
+ locationBarAtMinSize_ = locationBarWidth <= kMinimumLocationBarWidth;
+ if (locationBarAtMinSize_) {
+ CGFloat dX = kMinimumLocationBarWidth - locationBarWidth;
+ [self adjustLocationSizeBy:dX animate:NO];
+ }
+}
+
+- (void)toolbarFrameChanged {
+ // Do nothing if the frame changes but no Browser Action Controller is
+ // present.
+ if (!browserActionsController_.get())
+ return;
+
+ [self maintainMinimumLocationBarWidth];
+
+ if (locationBarAtMinSize_) {
+ // Once the grippy is pinned, leave it until it is explicity un-pinned.
+ [browserActionsContainerView_ setGrippyPinned:YES];
+ NSRect containerFrame = [browserActionsContainerView_ frame];
+ // Determine how much the container needs to move in case it's overlapping
+ // with the location bar.
+ CGFloat dX = NSMaxX([locationBar_ frame]) - containerFrame.origin.x;
+ containerFrame = NSOffsetRect(containerFrame, dX, 0);
+ containerFrame.size.width -= dX;
+ [browserActionsContainerView_ setFrame:containerFrame];
+ } else if (!locationBarAtMinSize_ &&
+ [browserActionsContainerView_ grippyPinned]) {
+ // Expand out the container until it hits the saved size, then unpin the
+ // grippy.
+ // Add 0.1 pixel so that it doesn't hit the minimum width codepath above.
+ CGFloat dX = NSWidth([locationBar_ frame]) -
+ (kMinimumLocationBarWidth + 0.1);
+ NSRect containerFrame = [browserActionsContainerView_ frame];
+ containerFrame = NSOffsetRect(containerFrame, -dX, 0);
+ containerFrame.size.width += dX;
+ CGFloat savedContainerWidth = [browserActionsController_ savedWidth];
+ if (NSWidth(containerFrame) >= savedContainerWidth) {
+ containerFrame = NSOffsetRect(containerFrame,
+ NSWidth(containerFrame) - savedContainerWidth, 0);
+ containerFrame.size.width = savedContainerWidth;
+ [browserActionsContainerView_ setGrippyPinned:NO];
+ }
+ [browserActionsContainerView_ setFrame:containerFrame];
+ [self pinLocationBarToLeftOfBrowserActionsContainerAndAnimate:NO];
+ }
+}
+
+- (void)adjustLocationSizeBy:(CGFloat)dX animate:(BOOL)animate {
+ // Ensure that the location bar is in its proper place.
+ NSRect locationFrame = [locationBar_ frame];
+ locationFrame.size.width += dX;
+
+ if (!animate) {
+ [locationBar_ setFrame:locationFrame];
+ return;
+ }
+
+ [NSAnimationContext beginGrouping];
+ [[NSAnimationContext currentContext] setDuration:kAnimationDuration];
+ [[locationBar_ animator] setFrame:locationFrame];
+ [NSAnimationContext endGrouping];
+}
+
+- (NSPoint)bookmarkBubblePoint {
+ return locationBarView_->GetBookmarkBubblePoint();
+}
+
+- (CGFloat)desiredHeightForCompression:(CGFloat)compressByHeight {
+ // With no toolbar, just ignore the compression.
+ return hasToolbar_ ? kBaseToolbarHeight - compressByHeight :
+ NSHeight([locationBar_ frame]);
+}
+
+- (void)setDividerOpacity:(CGFloat)opacity {
+ BackgroundGradientView* view = [self backgroundGradientView];
+ [view setShowsDivider:(opacity > 0 ? YES : NO)];
+
+ // We may not have a toolbar view (e.g., popup windows only have a location
+ // bar).
+ if ([view isKindOfClass:[ToolbarView class]]) {
+ ToolbarView* toolbarView = (ToolbarView*)view;
+ [toolbarView setDividerOpacity:opacity];
+ }
+}
+
+- (BrowserActionsController*)browserActionsController {
+ return browserActionsController_.get();
+}
+
+// (URLDropTargetController protocol)
+- (void)dropURLs:(NSArray*)urls inView:(NSView*)view at:(NSPoint)point {
+ // TODO(viettrungluu): This code is more or less copied from the code in
+ // |TabStripController|. I'll refactor this soon to make it common and expand
+ // its capabilities (e.g., allow text DnD).
+ if ([urls count] < 1) {
+ NOTREACHED();
+ return;
+ }
+
+ // TODO(viettrungluu): dropping multiple URLs?
+ if ([urls count] > 1)
+ NOTIMPLEMENTED();
+
+ // Get the first URL and fix it up.
+ GURL url(URLFixerUpper::FixupURL(
+ base::SysNSStringToUTF8([urls objectAtIndex:0]), std::string()));
+
+ browser_->GetSelectedTabContents()->OpenURL(url, GURL(), CURRENT_TAB,
+ PageTransition::TYPED);
+}
+
+// (URLDropTargetController protocol)
+- (void)dropText:(NSString*)text inView:(NSView*)view at:(NSPoint)point {
+ // TODO(viettrungluu): This code is more or less copied from the code in
+ // |TabStripController|. I'll refactor this soon to make it common and expand
+ // its capabilities (e.g., allow text DnD).
+
+ // If the input is plain text, classify the input and make the URL.
+ AutocompleteMatch match;
+ browser_->profile()->GetAutocompleteClassifier()->Classify(
+ base::SysNSStringToWide(text),
+ std::wstring(), false, &match, NULL);
+ GURL url(match.destination_url);
+
+ browser_->GetSelectedTabContents()->OpenURL(url, GURL(), CURRENT_TAB,
+ PageTransition::TYPED);
+}
+
+// (URLDropTargetController protocol)
+- (void)indicateDropURLsInView:(NSView*)view at:(NSPoint)point {
+ // Do nothing.
+}
+
+// (URLDropTargetController protocol)
+- (void)hideDropURLsIndicatorInView:(NSView*)view {
+ // Do nothing.
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/toolbar_controller_unittest.mm b/chrome/browser/ui/cocoa/toolbar_controller_unittest.mm
new file mode 100644
index 0000000..b57fdf8
--- /dev/null
+++ b/chrome/browser/ui/cocoa/toolbar_controller_unittest.mm
@@ -0,0 +1,237 @@
+// 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>
+
+#import "base/scoped_nsobject.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/gradient_button_cell.h"
+#import "chrome/browser/ui/cocoa/toolbar_controller.h"
+#import "chrome/browser/ui/cocoa/view_resizer_pong.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/common/pref_names.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+// An NSView that fakes out hitTest:.
+@interface HitView : NSView {
+ id hitTestReturn_;
+}
+@end
+
+@implementation HitView
+
+- (void)setHitTestReturn:(id)rtn {
+ hitTestReturn_ = rtn;
+}
+
+- (NSView *)hitTest:(NSPoint)aPoint {
+ return hitTestReturn_;
+}
+
+@end
+
+
+namespace {
+
+class ToolbarControllerTest : public CocoaTest {
+ public:
+
+ // Indexes that match the ordering returned by the private ToolbarController
+ // |-toolbarViews| method.
+ enum {
+ kBackIndex, kForwardIndex, kReloadIndex, kHomeIndex,
+ kWrenchIndex, kLocationIndex, kBrowserActionContainerViewIndex
+ };
+
+ ToolbarControllerTest() {
+ Browser* browser = helper_.browser();
+ CommandUpdater* updater = browser->command_updater();
+ // The default state for the commands is true, set a couple to false to
+ // ensure they get picked up correct on initialization
+ updater->UpdateCommandEnabled(IDC_BACK, false);
+ updater->UpdateCommandEnabled(IDC_FORWARD, false);
+ resizeDelegate_.reset([[ViewResizerPong alloc] init]);
+ bar_.reset(
+ [[ToolbarController alloc] initWithModel:browser->toolbar_model()
+ commands:browser->command_updater()
+ profile:helper_.profile()
+ browser:browser
+ resizeDelegate:resizeDelegate_.get()]);
+ EXPECT_TRUE([bar_ view]);
+ NSView* parent = [test_window() contentView];
+ [parent addSubview:[bar_ view]];
+ }
+
+ // Make sure the enabled state of the view is the same as the corresponding
+ // command in the updater. The views are in the declaration order of outlets.
+ void CompareState(CommandUpdater* updater, NSArray* views) {
+ EXPECT_EQ(updater->IsCommandEnabled(IDC_BACK),
+ [[views objectAtIndex:kBackIndex] isEnabled] ? true : false);
+ EXPECT_EQ(updater->IsCommandEnabled(IDC_FORWARD),
+ [[views objectAtIndex:kForwardIndex] isEnabled] ? true : false);
+ EXPECT_EQ(updater->IsCommandEnabled(IDC_RELOAD),
+ [[views objectAtIndex:kReloadIndex] isEnabled] ? true : false);
+ EXPECT_EQ(updater->IsCommandEnabled(IDC_HOME),
+ [[views objectAtIndex:kHomeIndex] isEnabled] ? true : false);
+ }
+
+ BrowserTestHelper helper_;
+ scoped_nsobject<ViewResizerPong> resizeDelegate_;
+ scoped_nsobject<ToolbarController> bar_;
+};
+
+TEST_VIEW(ToolbarControllerTest, [bar_ view])
+
+// Test the initial state that everything is sync'd up
+TEST_F(ToolbarControllerTest, InitialState) {
+ CommandUpdater* updater = helper_.browser()->command_updater();
+ CompareState(updater, [bar_ toolbarViews]);
+}
+
+// Make sure a "titlebar only" toolbar with location bar works.
+TEST_F(ToolbarControllerTest, TitlebarOnly) {
+ NSView* view = [bar_ view];
+
+ [bar_ setHasToolbar:NO hasLocationBar:YES];
+ EXPECT_NE(view, [bar_ view]);
+
+ // Simulate a popup going fullscreen and back by performing the reparenting
+ // that happens during fullscreen transitions
+ NSView* superview = [view superview];
+ [view removeFromSuperview];
+ [superview addSubview:view];
+
+ [bar_ setHasToolbar:YES hasLocationBar:YES];
+ EXPECT_EQ(view, [bar_ view]);
+
+ // Leave it off to make sure that's fine
+ [bar_ setHasToolbar:NO hasLocationBar:YES];
+}
+
+// Make sure it works in the completely undecorated case.
+TEST_F(ToolbarControllerTest, NoLocationBar) {
+ NSView* view = [bar_ view];
+
+ [bar_ setHasToolbar:NO hasLocationBar:NO];
+ EXPECT_NE(view, [bar_ view]);
+ EXPECT_TRUE([[bar_ view] isHidden]);
+
+ // Simulate a popup going fullscreen and back by performing the reparenting
+ // that happens during fullscreen transitions
+ NSView* superview = [view superview];
+ [view removeFromSuperview];
+ [superview addSubview:view];
+}
+
+// Make some changes to the enabled state of a few of the buttons and ensure
+// that we're still in sync.
+TEST_F(ToolbarControllerTest, UpdateEnabledState) {
+ CommandUpdater* updater = helper_.browser()->command_updater();
+ EXPECT_FALSE(updater->IsCommandEnabled(IDC_BACK));
+ EXPECT_FALSE(updater->IsCommandEnabled(IDC_FORWARD));
+ updater->UpdateCommandEnabled(IDC_BACK, true);
+ updater->UpdateCommandEnabled(IDC_FORWARD, true);
+ CompareState(updater, [bar_ toolbarViews]);
+}
+
+// Focus the location bar and make sure that it's the first responder.
+TEST_F(ToolbarControllerTest, FocusLocation) {
+ NSWindow* window = test_window();
+ [window makeFirstResponder:[window contentView]];
+ EXPECT_EQ([window firstResponder], [window contentView]);
+ [bar_ focusLocationBar:YES];
+ EXPECT_NE([window firstResponder], [window contentView]);
+ NSView* locationBar = [[bar_ toolbarViews] objectAtIndex:kLocationIndex];
+ EXPECT_EQ([window firstResponder], [(id)locationBar currentEditor]);
+}
+
+TEST_F(ToolbarControllerTest, LoadingState) {
+ // In its initial state, the reload button has a tag of
+ // IDC_RELOAD. When loading, it should be IDC_STOP.
+ NSButton* reload = [[bar_ toolbarViews] objectAtIndex:kReloadIndex];
+ EXPECT_EQ([reload tag], IDC_RELOAD);
+ [bar_ setIsLoading:YES force:YES];
+ EXPECT_EQ([reload tag], IDC_STOP);
+ [bar_ setIsLoading:NO force:YES];
+ EXPECT_EQ([reload tag], IDC_RELOAD);
+}
+
+// Check that toggling the state of the home button changes the visible
+// state of the home button and moves the other items accordingly.
+TEST_F(ToolbarControllerTest, ToggleHome) {
+ PrefService* prefs = helper_.profile()->GetPrefs();
+ bool showHome = prefs->GetBoolean(prefs::kShowHomeButton);
+ NSView* homeButton = [[bar_ toolbarViews] objectAtIndex:kHomeIndex];
+ EXPECT_EQ(showHome, ![homeButton isHidden]);
+
+ NSView* locationBar = [[bar_ toolbarViews] objectAtIndex:kLocationIndex];
+ NSRect originalLocationBarFrame = [locationBar frame];
+
+ // Toggle the pref and make sure the button changed state and the other
+ // views moved.
+ prefs->SetBoolean(prefs::kShowHomeButton, !showHome);
+ EXPECT_EQ(showHome, [homeButton isHidden]);
+ EXPECT_NE(NSMinX(originalLocationBarFrame), NSMinX([locationBar frame]));
+ EXPECT_NE(NSWidth(originalLocationBarFrame), NSWidth([locationBar frame]));
+}
+
+// Ensure that we don't toggle the buttons when we have a strip marked as not
+// having the full toolbar. Also ensure that the location bar doesn't change
+// size.
+TEST_F(ToolbarControllerTest, DontToggleWhenNoToolbar) {
+ [bar_ setHasToolbar:NO hasLocationBar:YES];
+ NSView* homeButton = [[bar_ toolbarViews] objectAtIndex:kHomeIndex];
+ NSView* locationBar = [[bar_ toolbarViews] objectAtIndex:kLocationIndex];
+ NSRect locationBarFrame = [locationBar frame];
+ EXPECT_EQ([homeButton isHidden], YES);
+ [bar_ showOptionalHomeButton];
+ EXPECT_EQ([homeButton isHidden], YES);
+ NSRect newLocationBarFrame = [locationBar frame];
+ EXPECT_TRUE(NSEqualRects(locationBarFrame, newLocationBarFrame));
+ newLocationBarFrame = [locationBar frame];
+ EXPECT_TRUE(NSEqualRects(locationBarFrame, newLocationBarFrame));
+}
+
+TEST_F(ToolbarControllerTest, BookmarkBubblePoint) {
+ const NSPoint starPoint = [bar_ bookmarkBubblePoint];
+ const NSRect barFrame =
+ [[bar_ view] convertRect:[[bar_ view] bounds] toView:nil];
+
+ // Make sure the star is completely inside the location bar.
+ EXPECT_TRUE(NSPointInRect(starPoint, barFrame));
+}
+
+TEST_F(ToolbarControllerTest, HoverButtonForEvent) {
+ scoped_nsobject<HitView> view([[HitView alloc]
+ initWithFrame:NSMakeRect(0,0,100,100)]);
+ [bar_ setView:view];
+ NSEvent* event = [NSEvent mouseEventWithType:NSMouseMoved
+ location:NSMakePoint(10,10)
+ modifierFlags:0
+ timestamp:0
+ windowNumber:0
+ context:nil
+ eventNumber:0
+ clickCount:0
+ pressure:0.0];
+
+ // NOT a match.
+ [view setHitTestReturn:bar_.get()];
+ EXPECT_FALSE([bar_ hoverButtonForEvent:event]);
+
+ // Not yet...
+ scoped_nsobject<NSButton> button([[NSButton alloc] init]);
+ [view setHitTestReturn:button];
+ EXPECT_FALSE([bar_ hoverButtonForEvent:event]);
+
+ // Now!
+ scoped_nsobject<GradientButtonCell> cell([[GradientButtonCell alloc] init]);
+ [button setCell:cell.get()];
+ EXPECT_TRUE([bar_ hoverButtonForEvent:nil]);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/toolbar_view.h b/chrome/browser/ui/cocoa/toolbar_view.h
new file mode 100644
index 0000000..54f3135
--- /dev/null
+++ b/chrome/browser/ui/cocoa/toolbar_view.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_TOOLBAR_VIEW_H_
+#define CHROME_BROWSER_UI_COCOA_TOOLBAR_VIEW_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+#import "chrome/browser/ui/cocoa/background_gradient_view.h"
+
+// A view that handles any special rendering of the toolbar bar. At
+// this time it only draws a gradient. Future changes (e.g. themes)
+// may require new functionality here.
+
+@interface ToolbarView : BackgroundGradientView {
+ @private
+ // The opacity of the divider line (at the bottom of the toolbar); used when
+ // the detached bookmark bar is morphing to the normal bar and vice versa.
+ CGFloat dividerOpacity_;
+}
+
+@property(assign, nonatomic) CGFloat dividerOpacity;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_TOOLBAR_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/toolbar_view.mm b/chrome/browser/ui/cocoa/toolbar_view.mm
new file mode 100644
index 0000000..fb4bbdd
--- /dev/null
+++ b/chrome/browser/ui/cocoa/toolbar_view.mm
@@ -0,0 +1,47 @@
+ // Copyright (c) 2009 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 "chrome/browser/ui/cocoa/toolbar_view.h"
+
+#import "chrome/browser/ui/cocoa/themed_window.h"
+#import "chrome/browser/ui/cocoa/view_id_util.h"
+
+@implementation ToolbarView
+
+@synthesize dividerOpacity = dividerOpacity_;
+
+// Prevent mouse down events from moving the parent window around.
+- (BOOL)mouseDownCanMoveWindow {
+ return NO;
+}
+
+- (void)drawRect:(NSRect)rect {
+ // The toolbar's background pattern is phased relative to the
+ // tab strip view's background pattern.
+ NSPoint phase = [[self window] themePatternPhase];
+ [[NSGraphicsContext currentContext] setPatternPhase:phase];
+ [self drawBackground];
+}
+
+// Override of |-[BackgroundGradientView strokeColor]|; make it respect opacity.
+- (NSColor*)strokeColor {
+ return [[super strokeColor] colorWithAlphaComponent:[self dividerOpacity]];
+}
+
+- (BOOL)accessibilityIsIgnored {
+ return NO;
+}
+
+- (id)accessibilityAttributeValue:(NSString*)attribute {
+ if ([attribute isEqual:NSAccessibilityRoleAttribute])
+ return NSAccessibilityToolbarRole;
+
+ return [super accessibilityAttributeValue:attribute];
+}
+
+- (ViewID)viewID {
+ return VIEW_ID_TOOLBAR;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/toolbar_view_unittest.mm b/chrome/browser/ui/cocoa/toolbar_view_unittest.mm
new file mode 100644
index 0000000..242b618
--- /dev/null
+++ b/chrome/browser/ui/cocoa/toolbar_view_unittest.mm
@@ -0,0 +1,23 @@
+// Copyright (c) 2009 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/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/toolbar_view.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class ToolbarViewTest : public CocoaTest {
+};
+
+// This class only needs to do one thing: prevent mouse down events from moving
+// the parent window around.
+TEST_F(ToolbarViewTest, CanDragWindow) {
+ scoped_nsobject<ToolbarView> view([[ToolbarView alloc] init]);
+ EXPECT_FALSE([view mouseDownCanMoveWindow]);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/translate/after_translate_infobar_controller.h b/chrome/browser/ui/cocoa/translate/after_translate_infobar_controller.h
new file mode 100644
index 0000000..80a5091
--- /dev/null
+++ b/chrome/browser/ui/cocoa/translate/after_translate_infobar_controller.h
@@ -0,0 +1,11 @@
+// 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 "chrome/browser/ui/cocoa/translate/translate_infobar_base.h"
+
+@interface AfterTranslateInfobarController : TranslateInfoBarControllerBase {
+ bool swappedLanugageButtons_;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/translate/after_translate_infobar_controller.mm b/chrome/browser/ui/cocoa/translate/after_translate_infobar_controller.mm
new file mode 100644
index 0000000..54ab77f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/translate/after_translate_infobar_controller.mm
@@ -0,0 +1,60 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/translate/after_translate_infobar_controller.h"
+#include "base/sys_string_conversions.h"
+
+using TranslateInfoBarUtilities::MoveControl;
+using TranslateInfoBarUtilities::VerifyControlOrderAndSpacing;
+
+@implementation AfterTranslateInfobarController
+
+- (void)loadLabelText {
+ std::vector<string16> strings;
+ TranslateInfoBarDelegate::GetAfterTranslateStrings(
+ &strings, &swappedLanugageButtons_);
+ DCHECK(strings.size() == 3U);
+ NSString* string1 = base::SysUTF16ToNSString(strings[0]);
+ NSString* string2 = base::SysUTF16ToNSString(strings[1]);
+ NSString* string3 = base::SysUTF16ToNSString(strings[2]);
+
+ [label1_ setStringValue:string1];
+ [label2_ setStringValue:string2];
+ [label3_ setStringValue:string3];
+}
+
+- (void)layout {
+ [self removeOkCancelButtons];
+ [optionsPopUp_ setHidden:NO];
+ NSView* firstPopup = fromLanguagePopUp_;
+ NSView* lastPopup = toLanguagePopUp_;
+ if (swappedLanugageButtons_) {
+ firstPopup = toLanguagePopUp_;
+ lastPopup = fromLanguagePopUp_;
+ }
+ NSView* lastControl = lastPopup;
+
+ MoveControl(label1_, firstPopup, spaceBetweenControls_ / 2, true);
+ MoveControl(firstPopup, label2_, spaceBetweenControls_ / 2, true);
+ MoveControl(label2_, lastPopup, spaceBetweenControls_ / 2, true);
+ MoveControl(lastPopup, label3_, 0, true);
+ lastControl = label3_;
+
+ MoveControl(lastControl, showOriginalButton_, spaceBetweenControls_ * 2,
+ true);
+}
+
+- (NSArray*)visibleControls {
+ return [NSArray arrayWithObjects:label1_.get(), fromLanguagePopUp_.get(),
+ label2_.get(), toLanguagePopUp_.get(), label3_.get(),
+ showOriginalButton_.get(), nil];
+}
+
+- (bool)verifyLayout {
+ if ([optionsPopUp_ isHidden])
+ return false;
+ return [super verifyLayout];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/translate/before_translate_infobar_controller.h b/chrome/browser/ui/cocoa/translate/before_translate_infobar_controller.h
new file mode 100644
index 0000000..a96f9af
--- /dev/null
+++ b/chrome/browser/ui/cocoa/translate/before_translate_infobar_controller.h
@@ -0,0 +1,23 @@
+// 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 "chrome/browser/ui/cocoa/translate/translate_infobar_base.h"
+
+@interface BeforeTranslateInfobarController : TranslateInfoBarControllerBase {
+ scoped_nsobject<NSButton> alwaysTranslateButton_;
+ scoped_nsobject<NSButton> neverTranslateButton_;
+}
+
+// Creates and initializes the alwaysTranslate and neverTranslate buttons.
+- (void)initializeExtraControls;
+
+@end
+
+@interface BeforeTranslateInfobarController (TestingAPI)
+
+- (NSButton*)alwaysTranslateButton;
+- (NSButton*)neverTranslateButton;
+
+@end
+
diff --git a/chrome/browser/ui/cocoa/translate/before_translate_infobar_controller.mm b/chrome/browser/ui/cocoa/translate/before_translate_infobar_controller.mm
new file mode 100644
index 0000000..0beedad
--- /dev/null
+++ b/chrome/browser/ui/cocoa/translate/before_translate_infobar_controller.mm
@@ -0,0 +1,123 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/translate/before_translate_infobar_controller.h"
+
+#include "app/l10n_util.h"
+#include "base/sys_string_conversions.h"
+#include "grit/generated_resources.h"
+
+using TranslateInfoBarUtilities::MoveControl;
+using TranslateInfoBarUtilities::VerifyControlOrderAndSpacing;
+
+namespace {
+
+NSButton* CreateNSButtonWithResourceIDAndParameter(
+ int resourceId, const string16& param) {
+ string16 title = l10n_util::GetStringFUTF16(resourceId, param);
+ NSButton* button = [[NSButton alloc] init];
+ [button setTitle:base::SysUTF16ToNSString(title)];
+ [button setBezelStyle:NSTexturedRoundedBezelStyle];
+ return button;
+}
+
+} // namespace
+
+@implementation BeforeTranslateInfobarController
+
+- (id) initWithDelegate:(InfoBarDelegate *)delegate {
+ if ((self = [super initWithDelegate:delegate])) {
+ [self initializeExtraControls];
+ }
+ return self;
+}
+
+- (void)initializeExtraControls {
+ TranslateInfoBarDelegate* delegate = [self delegate];
+ const string16& language = delegate->GetLanguageDisplayableNameAt(
+ delegate->original_language_index());
+ neverTranslateButton_.reset(
+ CreateNSButtonWithResourceIDAndParameter(
+ IDS_TRANSLATE_INFOBAR_NEVER_TRANSLATE, language));
+ [neverTranslateButton_ setTarget:self];
+ [neverTranslateButton_ setAction:@selector(neverTranslate:)];
+
+ alwaysTranslateButton_.reset(
+ CreateNSButtonWithResourceIDAndParameter(
+ IDS_TRANSLATE_INFOBAR_ALWAYS_TRANSLATE, language));
+ [alwaysTranslateButton_ setTarget:self];
+ [alwaysTranslateButton_ setAction:@selector(alwaysTranslate:)];
+}
+
+- (void)layout {
+ MoveControl(label1_, fromLanguagePopUp_, spaceBetweenControls_ / 2, true);
+ MoveControl(fromLanguagePopUp_, label2_, spaceBetweenControls_, true);
+ MoveControl(label2_, okButton_, spaceBetweenControls_, true);
+ MoveControl(okButton_, cancelButton_, spaceBetweenControls_, true);
+ NSView* lastControl = cancelButton_;
+ if (neverTranslateButton_.get()) {
+ MoveControl(lastControl, neverTranslateButton_.get(),
+ spaceBetweenControls_, true);
+ lastControl = neverTranslateButton_.get();
+ }
+ if (alwaysTranslateButton_.get()) {
+ MoveControl(lastControl, alwaysTranslateButton_.get(),
+ spaceBetweenControls_, true);
+ }
+}
+
+- (void)loadLabelText {
+ size_t offset = 0;
+ string16 text =
+ l10n_util::GetStringFUTF16(IDS_TRANSLATE_INFOBAR_BEFORE_MESSAGE,
+ string16(), &offset);
+ NSString* string1 = base::SysUTF16ToNSString(text.substr(0, offset));
+ NSString* string2 = base::SysUTF16ToNSString(text.substr(offset));
+ [label1_ setStringValue:string1];
+ [label2_ setStringValue:string2];
+ [label3_ setStringValue:@""];
+}
+
+- (NSArray*)visibleControls {
+ NSMutableArray* visibleControls = [NSMutableArray arrayWithObjects:
+ label1_.get(), fromLanguagePopUp_.get(), label2_.get(),
+ okButton_, cancelButton_, nil];
+
+ if ([self delegate]->ShouldShowNeverTranslateButton())
+ [visibleControls addObject:neverTranslateButton_.get()];
+
+ if ([self delegate]->ShouldShowAlwaysTranslateButton())
+ [visibleControls addObject:alwaysTranslateButton_.get()];
+
+ return visibleControls;
+}
+
+// This is called when the "Never Translate [language]" button is pressed.
+- (void)neverTranslate:(id)sender {
+ [self delegate]->NeverTranslatePageLanguage();
+}
+
+// This is called when the "Always Translate [language]" button is pressed.
+- (void)alwaysTranslate:(id)sender {
+ [self delegate]->AlwaysTranslatePageLanguage();
+}
+
+- (bool)verifyLayout {
+ if ([optionsPopUp_ isHidden])
+ return false;
+ return [super verifyLayout];
+}
+
+@end
+
+@implementation BeforeTranslateInfobarController (TestingAPI)
+
+- (NSButton*)alwaysTranslateButton {
+ return alwaysTranslateButton_.get();
+}
+- (NSButton*)neverTranslateButton {
+ return neverTranslateButton_.get();
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/translate/translate_infobar_base.h b/chrome/browser/ui/cocoa/translate/translate_infobar_base.h
new file mode 100644
index 0000000..1dff159
--- /dev/null
+++ b/chrome/browser/ui/cocoa/translate/translate_infobar_base.h
@@ -0,0 +1,163 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_TRANSLATE_INFOBAR_BASE_H_
+#define CHROME_BROWSER_UI_COCOA_TRANSLATE_INFOBAR_BASE_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+#import "chrome/browser/ui/cocoa/infobar_controller.h"
+
+#import "base/mac/cocoa_protocols.h"
+#import "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/translate/languages_menu_model.h"
+#include "chrome/browser/translate/options_menu_model.h"
+#include "chrome/browser/translate/translate_infobar_delegate.h"
+#include "chrome/common/translate_errors.h"
+
+class TranslateInfoBarMenuModel;
+
+#pragma mark TranslateInfoBarUtilities helper functions.
+namespace TranslateInfoBarUtilities {
+
+// Move the |toMove| view |spacing| pixels before/after the |anchor| view.
+// |after| signifies the side of |anchor| on which to place |toMove|.
+void MoveControl(NSView* anchor, NSView* toMove, int spacing, bool after);
+
+// Vertically center |toMove| in its container.
+void VerticallyCenterView(NSView *toMove);
+// Check that the control |before| is ordered visually before the |after|
+// control.
+// Also, check that there is space between them.
+bool VerifyControlOrderAndSpacing(id before, id after);
+
+// Creates a label control in the style we need for the translate infobar's
+// labels within |bounds|.
+NSTextField* CreateLabel(NSRect bounds);
+
+// Adds an item with the specified properties to |menu|.
+void AddMenuItem(NSMenu *menu, id target, SEL selector, NSString* title,
+ int tag, bool enabled, bool checked);
+
+} // namespace
+
+// The base class for the three translate infobars. This class does all of the
+// heavy UI lifting, while deferring to the subclass to tell it what views
+// should be shown and where. Subclasses need to implement:
+// - (void)layout;
+// - (void)loadLabelText;
+// - (void)visibleControls;
+// - (bool)verifyLayout; // For testing.
+@interface TranslateInfoBarControllerBase : InfoBarController<NSMenuDelegate> {
+ @protected
+ scoped_nsobject<NSTextField> label1_;
+ scoped_nsobject<NSTextField> label2_;
+ scoped_nsobject<NSTextField> label3_;
+ scoped_nsobject<NSPopUpButton> fromLanguagePopUp_;
+ scoped_nsobject<NSPopUpButton> toLanguagePopUp_;
+ scoped_nsobject<NSPopUpButton> optionsPopUp_;
+ scoped_nsobject<NSButton> showOriginalButton_;
+ // This is the button used in the translate message infobar. It can either be
+ // a "Try Again" button, or a "Show Original" button in the case that the
+ // page was translated from an unknown language.
+ scoped_nsobject<NSButton> translateMessageButton_;
+
+ // In the current locale, are the "from" and "to" language popup menu
+ // flipped from what they'd appear in English.
+ bool swappedLanguagePlaceholders_;
+
+ // Space between controls in pixels - read from the NIB.
+ CGFloat spaceBetweenControls_;
+
+ scoped_ptr<LanguagesMenuModel> originalLanguageMenuModel_;
+ scoped_ptr<LanguagesMenuModel> targetLanguageMenuModel_;
+ scoped_ptr<OptionsMenuModel> optionsMenuModel_;
+}
+
+// Returns the delegate as a TranslateInfoBarDelegate.
+- (TranslateInfoBarDelegate*)delegate;
+
+// Called when the "Show Original" button is pressed.
+- (IBAction)showOriginal:(id)sender;
+
+@end
+
+@interface TranslateInfoBarControllerBase (ProtectedAPI)
+
+// Resizes or hides the options button based on how much space is available
+// so that it doesn't overlap other buttons.
+// lastView is the rightmost view, the first one that the options button
+// would overlap with.
+- (void)adjustOptionsButtonSizeAndVisibilityForView:(NSView*)lastView;
+
+// Move all the currently visible views into the correct place for the
+// current mode.
+// Must be implemented by the subclass.
+- (void)layout;
+
+// Loads the text for the 3 labels. There is only one message, but since
+// it has controls separating parts of it, it is separated into 3 separate
+// labels.
+// Must be implemented by the subclass.
+- (void)loadLabelText;
+
+// Returns the controls that are visible in the subclasses infobar. The
+// default implementation returns an empty array. The controls should
+// be returned in the order they are displayed, otherwise the layout test
+// will fail.
+// Must be implemented by the subclass.
+- (NSArray*)visibleControls;
+
+// Shows the array of controls provided by the subclass.
+- (void)showVisibleControls:(NSArray*)visibleControls;
+
+// Hides the OK and Cancel buttons.
+- (void)removeOkCancelButtons;
+
+// Called when the source or target language selection changes in a menu.
+// |newLanguageIdx| is the index of the newly selected item in the appropriate
+// menu.
+- (void)sourceLanguageModified:(NSInteger)newLanguageIdx;
+- (void)targetLanguageModified:(NSInteger)newLanguageIdx;
+
+// Called when an item in one of the toolbar's language or options
+// menus is selected.
+- (void)languageMenuChanged:(id)item;
+- (void)optionsMenuChanged:(id)item;
+
+// Teardown and rebuild the options menu. When the infobar is small, the
+// options menu is shrunk to just a drop down arrow, so the title needs
+// to be empty.
+- (void)rebuildOptionsMenu:(BOOL)hideTitle;
+
+// Whether or not this infobar should show the options popup.
+- (BOOL)shouldShowOptionsPopUp;
+
+@end // TranslateInfoBarControllerBase (ProtectedAPI)
+
+#pragma mark TestingAPI
+
+@interface TranslateInfoBarControllerBase (TestingAPI)
+
+// All the controls used in any of the translate states.
+// This is used for verifying layout and for setting the
+// correct styles on each button.
+- (NSArray*)allControls;
+
+// Verifies that the layout of the infobar is correct.
+// Must be implmented by the subclass.
+- (bool)verifyLayout;
+
+// Returns the underlying options menu.
+- (NSMenu*)optionsMenu;
+
+// Returns |translateMessageButton_|, see declaration of member
+// variable for a full description.
+- (NSButton*)translateMessageButton;
+
+@end // TranslateInfoBarControllerBase (TestingAPI)
+
+
+#endif // CHROME_BROWSER_UI_COCOA_TRANSLATE_INFOBAR_BASE_H_
diff --git a/chrome/browser/ui/cocoa/translate/translate_infobar_base.mm b/chrome/browser/ui/cocoa/translate/translate_infobar_base.mm
new file mode 100644
index 0000000..4a08895
--- /dev/null
+++ b/chrome/browser/ui/cocoa/translate/translate_infobar_base.mm
@@ -0,0 +1,642 @@
+// 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>
+#import "chrome/browser/ui/cocoa/translate/translate_infobar_base.h"
+
+#include "app/l10n_util.h"
+#include "base/logging.h"
+#include "base/mac_util.h"
+#include "base/metrics/histogram.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/translate/translate_infobar_delegate.h"
+#import "chrome/browser/ui/cocoa/hover_close_button.h"
+#include "chrome/browser/ui/cocoa/infobar.h"
+#import "chrome/browser/ui/cocoa/infobar_controller.h"
+#import "chrome/browser/ui/cocoa/infobar_gradient_view.h"
+#include "chrome/browser/ui/cocoa/translate/after_translate_infobar_controller.h"
+#import "chrome/browser/ui/cocoa/translate/before_translate_infobar_controller.h"
+#include "chrome/browser/ui/cocoa/translate/translate_message_infobar_controller.h"
+#include "grit/generated_resources.h"
+#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
+
+using TranslateInfoBarUtilities::MoveControl;
+using TranslateInfoBarUtilities::VerticallyCenterView;
+using TranslateInfoBarUtilities::VerifyControlOrderAndSpacing;
+using TranslateInfoBarUtilities::CreateLabel;
+using TranslateInfoBarUtilities::AddMenuItem;
+
+#pragma mark TranslateInfoBarUtilities helper functions.
+
+namespace TranslateInfoBarUtilities {
+
+// Move the |toMove| view |spacing| pixels before/after the |anchor| view.
+// |after| signifies the side of |anchor| on which to place |toMove|.
+void MoveControl(NSView* anchor, NSView* toMove, int spacing, bool after) {
+ NSRect anchorFrame = [anchor frame];
+ NSRect toMoveFrame = [toMove frame];
+
+ // At the time of this writing, OS X doesn't natively support BiDi UIs, but
+ // it doesn't hurt to be forward looking.
+ bool toRight = after;
+
+ if (toRight) {
+ toMoveFrame.origin.x = NSMaxX(anchorFrame) + spacing;
+ } else {
+ // Place toMove to theleft of anchor.
+ toMoveFrame.origin.x = NSMinX(anchorFrame) -
+ spacing - NSWidth(toMoveFrame);
+ }
+ [toMove setFrame:toMoveFrame];
+}
+
+// Check that the control |before| is ordered visually before the |after|
+// control.
+// Also, check that there is space between them.
+bool VerifyControlOrderAndSpacing(id before, id after) {
+ NSRect beforeFrame = [before frame];
+ NSRect afterFrame = [after frame];
+ return NSMinX(afterFrame) >= NSMaxX(beforeFrame);
+}
+
+// Vertically center |toMove| in its container.
+void VerticallyCenterView(NSView *toMove) {
+ NSRect superViewFrame = [[toMove superview] frame];
+ NSRect viewFrame = [toMove frame];
+ viewFrame.origin.y =
+ floor((NSHeight(superViewFrame) - NSHeight(viewFrame))/2.0);
+ [toMove setFrame:viewFrame];
+}
+
+// Creates a label control in the style we need for the translate infobar's
+// labels within |bounds|.
+NSTextField* CreateLabel(NSRect bounds) {
+ NSTextField* ret = [[NSTextField alloc] initWithFrame:bounds];
+ [ret setEditable:NO];
+ [ret setDrawsBackground:NO];
+ [ret setBordered:NO];
+ return ret;
+}
+
+// Adds an item with the specified properties to |menu|.
+void AddMenuItem(NSMenu *menu, id target, SEL selector, NSString* title,
+ int tag, bool enabled, bool checked) {
+ if (tag == -1) {
+ [menu addItem:[NSMenuItem separatorItem]];
+ } else {
+ NSMenuItem* item = [[[NSMenuItem alloc]
+ initWithTitle:title
+ action:selector
+ keyEquivalent:@""] autorelease];
+ [item setTag:tag];
+ [menu addItem:item];
+ [item setTarget:target];
+ if (checked)
+ [item setState:NSOnState];
+ if (!enabled)
+ [item setEnabled:NO];
+ }
+}
+
+} // namespace TranslateInfoBarUtilities
+
+// TranslateInfoBarDelegate views specific method:
+InfoBar* TranslateInfoBarDelegate::CreateInfoBar() {
+ TranslateInfoBarControllerBase* infobar_controller = NULL;
+ switch (type_) {
+ case BEFORE_TRANSLATE:
+ infobar_controller =
+ [[BeforeTranslateInfobarController alloc] initWithDelegate:this];
+ break;
+ case AFTER_TRANSLATE:
+ infobar_controller =
+ [[AfterTranslateInfobarController alloc] initWithDelegate:this];
+ break;
+ case TRANSLATING:
+ case TRANSLATION_ERROR:
+ infobar_controller =
+ [[TranslateMessageInfobarController alloc] initWithDelegate:this];
+ break;
+ default:
+ NOTREACHED();
+ }
+ return new InfoBar(infobar_controller);
+}
+
+@implementation TranslateInfoBarControllerBase (FrameChangeObserver)
+
+// Triggered when the frame changes. This will figure out what size and
+// visibility the options popup should be.
+- (void)didChangeFrame:(NSNotification*)notification {
+ [self adjustOptionsButtonSizeAndVisibilityForView:
+ [[self visibleControls] lastObject]];
+}
+
+@end
+
+
+@interface TranslateInfoBarControllerBase (Private)
+
+// Removes all controls so that layout can add in only the controls
+// required.
+- (void)clearAllControls;
+
+// Create all the various controls we need for the toolbar.
+- (void)constructViews;
+
+// Reloads text for all labels for the current state.
+- (void)loadLabelText:(TranslateErrors::Type)error;
+
+// Set the infobar background gradient.
+- (void)setInfoBarGradientColor;
+
+// Main function to update the toolbar graphic state and data model after
+// the state has changed.
+// Controls are moved around as needed and visibility changed to match the
+// current state.
+- (void)updateState;
+
+// Called when the source or target language selection changes in a menu.
+// |newLanguageIdx| is the index of the newly selected item in the appropriate
+// menu.
+- (void)sourceLanguageModified:(NSInteger)newLanguageIdx;
+- (void)targetLanguageModified:(NSInteger)newLanguageIdx;
+
+// Completely rebuild "from" and "to" language menus from the data model.
+- (void)populateLanguageMenus;
+
+@end
+
+#pragma mark TranslateInfoBarController class
+
+@implementation TranslateInfoBarControllerBase
+
+- (id)initWithDelegate:(InfoBarDelegate*)delegate {
+ if ((self = [super initWithDelegate:delegate])) {
+ originalLanguageMenuModel_.reset(
+ new LanguagesMenuModel([self delegate],
+ LanguagesMenuModel::ORIGINAL));
+
+ targetLanguageMenuModel_.reset(
+ new LanguagesMenuModel([self delegate],
+ LanguagesMenuModel::TARGET));
+ }
+ return self;
+}
+
+- (TranslateInfoBarDelegate*)delegate {
+ return reinterpret_cast<TranslateInfoBarDelegate*>(delegate_);
+}
+
+- (void)constructViews {
+ // Using a zero or very large frame causes GTMUILocalizerAndLayoutTweaker
+ // to not resize the view properly so we take the bounds of the first label
+ // which is contained in the nib.
+ NSRect bogusFrame = [label_ frame];
+ label1_.reset(CreateLabel(bogusFrame));
+ label2_.reset(CreateLabel(bogusFrame));
+ label3_.reset(CreateLabel(bogusFrame));
+
+ optionsPopUp_.reset([[NSPopUpButton alloc] initWithFrame:bogusFrame
+ pullsDown:YES]);
+ fromLanguagePopUp_.reset([[NSPopUpButton alloc] initWithFrame:bogusFrame
+ pullsDown:NO]);
+ toLanguagePopUp_.reset([[NSPopUpButton alloc] initWithFrame:bogusFrame
+ pullsDown:NO]);
+ showOriginalButton_.reset([[NSButton alloc] init]);
+ translateMessageButton_.reset([[NSButton alloc] init]);
+}
+
+- (void)sourceLanguageModified:(NSInteger)newLanguageIdx {
+ DCHECK_GT(newLanguageIdx, -1);
+ if (newLanguageIdx == [self delegate]->original_language_index())
+ return;
+ [self delegate]->SetOriginalLanguage(newLanguageIdx);
+ int commandId = IDC_TRANSLATE_ORIGINAL_LANGUAGE_BASE + newLanguageIdx;
+ int newMenuIdx = [fromLanguagePopUp_ indexOfItemWithTag:commandId];
+ [fromLanguagePopUp_ selectItemAtIndex:newMenuIdx];
+}
+
+- (void)targetLanguageModified:(NSInteger)newLanguageIdx {
+ DCHECK_GT(newLanguageIdx, -1);
+ if (newLanguageIdx == [self delegate]->target_language_index())
+ return;
+ [self delegate]->SetTargetLanguage(newLanguageIdx);
+ int commandId = IDC_TRANSLATE_TARGET_LANGUAGE_BASE + newLanguageIdx;
+ int newMenuIdx = [toLanguagePopUp_ indexOfItemWithTag:commandId];
+ [toLanguagePopUp_ selectItemAtIndex:newMenuIdx];
+}
+
+- (void)loadLabelText {
+ // Do nothing by default, should be implemented by subclasses.
+}
+
+- (void)updateState {
+ [self loadLabelText];
+ [self clearAllControls];
+ [self showVisibleControls:[self visibleControls]];
+ [optionsPopUp_ setHidden:![self shouldShowOptionsPopUp]];
+ [self layout];
+ [self adjustOptionsButtonSizeAndVisibilityForView:
+ [[self visibleControls] lastObject]];
+}
+
+- (void)setInfoBarGradientColor {
+ NSColor* startingColor = [NSColor colorWithCalibratedWhite:0.93 alpha:1.0];
+ NSColor* endingColor = [NSColor colorWithCalibratedWhite:0.85 alpha:1.0];
+ NSGradient* translateInfoBarGradient =
+ [[[NSGradient alloc] initWithStartingColor:startingColor
+ endingColor:endingColor] autorelease];
+
+ [infoBarView_ setGradient:translateInfoBarGradient];
+ [infoBarView_
+ setStrokeColor:[NSColor colorWithCalibratedWhite:0.75 alpha:1.0]];
+}
+
+- (void)removeOkCancelButtons {
+ // Removing okButton_ & cancelButton_ from the view may cause them
+ // to be released and since we can still access them from other areas
+ // in the code later, we need them to be nil when this happens.
+ [okButton_ removeFromSuperview];
+ okButton_ = nil;
+ [cancelButton_ removeFromSuperview];
+ cancelButton_ = nil;
+}
+
+- (void)clearAllControls {
+ // Step 1: remove all controls from the infobar so we have a clean slate.
+ NSArray *allControls = [self allControls];
+
+ for (NSControl* control in allControls) {
+ if ([control superview])
+ [control removeFromSuperview];
+ }
+}
+
+- (void)showVisibleControls:(NSArray*)visibleControls {
+ NSRect optionsFrame = [optionsPopUp_ frame];
+ for (NSControl* control in visibleControls) {
+ [GTMUILocalizerAndLayoutTweaker sizeToFitView:control];
+ [control setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin |
+ NSViewMaxYMargin];
+
+ // Need to check if a view is already attached since |label1_| is always
+ // parented and we don't want to add it again.
+ if (![control superview])
+ [infoBarView_ addSubview:control];
+
+ if ([control isKindOfClass:[NSButton class]])
+ VerticallyCenterView(control);
+
+ // Make "from" and "to" language popup menus the same size as the options
+ // menu.
+ // We don't autosize since some languages names are really long causing
+ // the toolbar to overflow.
+ if ([control isKindOfClass:[NSPopUpButton class]])
+ [control setFrame:optionsFrame];
+ }
+}
+
+- (void)layout {
+
+}
+
+- (NSArray*)visibleControls {
+ return [NSArray array];
+}
+
+- (void)rebuildOptionsMenu:(BOOL)hideTitle {
+ if (![self shouldShowOptionsPopUp])
+ return;
+
+ // The options model doesn't know how to handle state transitions, so rebuild
+ // it each time through here.
+ optionsMenuModel_.reset(
+ new OptionsMenuModel([self delegate]));
+
+ [optionsPopUp_ removeAllItems];
+ // Set title.
+ NSString* optionsLabel = hideTitle ? @"" :
+ l10n_util::GetNSString(IDS_TRANSLATE_INFOBAR_OPTIONS);
+ [optionsPopUp_ addItemWithTitle:optionsLabel];
+
+ // Populate options menu.
+ NSMenu* optionsMenu = [optionsPopUp_ menu];
+ [optionsMenu setAutoenablesItems:NO];
+ for (int i = 0; i < optionsMenuModel_->GetItemCount(); ++i) {
+ NSString* title = base::SysUTF16ToNSString(
+ optionsMenuModel_->GetLabelAt(i));
+ int cmd = optionsMenuModel_->GetCommandIdAt(i);
+ bool checked = optionsMenuModel_->IsItemCheckedAt(i);
+ bool enabled = optionsMenuModel_->IsEnabledAt(i);
+ AddMenuItem(optionsMenu,
+ self,
+ @selector(optionsMenuChanged:),
+ title,
+ cmd,
+ enabled,
+ checked);
+ }
+}
+
+- (BOOL)shouldShowOptionsPopUp {
+ return YES;
+}
+
+- (void)populateLanguageMenus {
+ NSMenu* originalLanguageMenu = [fromLanguagePopUp_ menu];
+ [originalLanguageMenu setAutoenablesItems:NO];
+ int selectedMenuIndex = 0;
+ int selectedLangIndex = [self delegate]->original_language_index();
+ for (int i = 0; i < originalLanguageMenuModel_->GetItemCount(); ++i) {
+ NSString* title = base::SysUTF16ToNSString(
+ originalLanguageMenuModel_->GetLabelAt(i));
+ int cmd = originalLanguageMenuModel_->GetCommandIdAt(i);
+ bool checked = (cmd == selectedLangIndex);
+ if (checked)
+ selectedMenuIndex = i;
+ bool enabled = originalLanguageMenuModel_->IsEnabledAt(i);
+ cmd += IDC_TRANSLATE_ORIGINAL_LANGUAGE_BASE;
+ AddMenuItem(originalLanguageMenu,
+ self,
+ @selector(languageMenuChanged:),
+ title,
+ cmd,
+ enabled,
+ checked);
+ }
+ [fromLanguagePopUp_ selectItemAtIndex:selectedMenuIndex];
+
+ NSMenu* targetLanguageMenu = [toLanguagePopUp_ menu];
+ [targetLanguageMenu setAutoenablesItems:NO];
+ selectedLangIndex = [self delegate]->target_language_index();
+ for (int i = 0; i < targetLanguageMenuModel_->GetItemCount(); ++i) {
+ NSString* title = base::SysUTF16ToNSString(
+ targetLanguageMenuModel_->GetLabelAt(i));
+ int cmd = targetLanguageMenuModel_->GetCommandIdAt(i);
+ bool checked = (cmd == selectedLangIndex);
+ if (checked)
+ selectedMenuIndex = i;
+ bool enabled = targetLanguageMenuModel_->IsEnabledAt(i);
+ cmd += IDC_TRANSLATE_TARGET_LANGUAGE_BASE;
+ AddMenuItem(targetLanguageMenu,
+ self,
+ @selector(languageMenuChanged:),
+ title,
+ cmd,
+ enabled,
+ checked);
+ }
+ [toLanguagePopUp_ selectItemAtIndex:selectedMenuIndex];
+}
+
+- (void)addAdditionalControls {
+ using l10n_util::GetNSString;
+ using l10n_util::GetNSStringWithFixup;
+
+ // Get layout information from the NIB.
+ NSRect okButtonFrame = [okButton_ frame];
+ NSRect cancelButtonFrame = [cancelButton_ frame];
+ spaceBetweenControls_ = NSMinX(cancelButtonFrame) - NSMaxX(okButtonFrame);
+
+ // Set infobar background color.
+ [self setInfoBarGradientColor];
+
+ // Instantiate additional controls.
+ [self constructViews];
+
+ // Set ourselves as the delegate for the options menu so we can populate it
+ // dynamically.
+ [[optionsPopUp_ menu] setDelegate:self];
+
+ // Replace label_ with label1_ so we get a consistent look between all the
+ // labels we display in the translate view.
+ [[label_ superview] replaceSubview:label_ with:label1_.get()];
+ label_.reset(); // Now released.
+
+ // Populate contextual menus.
+ [self rebuildOptionsMenu:NO];
+ [self populateLanguageMenus];
+
+ // Set OK & Cancel text.
+ [okButton_ setTitle:GetNSStringWithFixup(IDS_TRANSLATE_INFOBAR_ACCEPT)];
+ [cancelButton_ setTitle:GetNSStringWithFixup(IDS_TRANSLATE_INFOBAR_DENY)];
+
+ // Set up "Show original" and "Try again" buttons.
+ [showOriginalButton_ setFrame:okButtonFrame];
+
+ // Set each of the buttons and popups to the NSTexturedRoundedBezelStyle
+ // (metal-looking) style.
+ NSArray* allControls = [self allControls];
+ for (NSControl* control in allControls) {
+ if (![control isKindOfClass:[NSButton class]])
+ continue;
+ NSButton* button = (NSButton*)control;
+ [button setBezelStyle:NSTexturedRoundedBezelStyle];
+ if ([button isKindOfClass:[NSPopUpButton class]]) {
+ [[button cell] setArrowPosition:NSPopUpArrowAtBottom];
+ }
+ }
+ // The options button is handled differently than the rest as it floats
+ // to the right.
+ [optionsPopUp_ setBezelStyle:NSTexturedRoundedBezelStyle];
+ [[optionsPopUp_ cell] setArrowPosition:NSPopUpArrowAtBottom];
+
+ [showOriginalButton_ setTarget:self];
+ [showOriginalButton_ setAction:@selector(showOriginal:)];
+ [translateMessageButton_ setTarget:self];
+ [translateMessageButton_ setAction:@selector(messageButtonPressed:)];
+
+ [showOriginalButton_
+ setTitle:GetNSStringWithFixup(IDS_TRANSLATE_INFOBAR_REVERT)];
+
+ // Add and configure controls that are visible in all modes.
+ [optionsPopUp_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin |
+ NSViewMaxYMargin];
+ // Add "options" popup z-ordered below all other controls so when we
+ // resize the toolbar it doesn't hide them.
+ [infoBarView_ addSubview:optionsPopUp_
+ positioned:NSWindowBelow
+ relativeTo:nil];
+ [GTMUILocalizerAndLayoutTweaker sizeToFitView:optionsPopUp_];
+ MoveControl(closeButton_, optionsPopUp_, spaceBetweenControls_, false);
+ VerticallyCenterView(optionsPopUp_);
+
+ [infoBarView_ setPostsFrameChangedNotifications:YES];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(didChangeFrame:)
+ name:NSViewFrameDidChangeNotification
+ object:infoBarView_];
+ // Show and place GUI elements.
+ [self updateState];
+}
+
+- (void)adjustOptionsButtonSizeAndVisibilityForView:(NSView*)lastView {
+ [optionsPopUp_ setHidden:NO];
+ [self rebuildOptionsMenu:NO];
+ [[optionsPopUp_ cell] setArrowPosition:NSPopUpArrowAtBottom];
+ [optionsPopUp_ sizeToFit];
+
+ MoveControl(closeButton_, optionsPopUp_, spaceBetweenControls_, false);
+ if (!VerifyControlOrderAndSpacing(lastView, optionsPopUp_)) {
+ [self rebuildOptionsMenu:YES];
+ NSRect oldFrame = [optionsPopUp_ frame];
+ oldFrame.size.width = NSHeight(oldFrame);
+ [optionsPopUp_ setFrame:oldFrame];
+ [[optionsPopUp_ cell] setArrowPosition:NSPopUpArrowAtCenter];
+ MoveControl(closeButton_, optionsPopUp_, spaceBetweenControls_, false);
+ if (!VerifyControlOrderAndSpacing(lastView, optionsPopUp_)) {
+ [optionsPopUp_ setHidden:YES];
+ }
+ }
+}
+
+// Called when "Translate" button is clicked.
+- (IBAction)ok:(id)sender {
+ TranslateInfoBarDelegate* delegate = [self delegate];
+ TranslateInfoBarDelegate::Type state = delegate->type();
+ DCHECK(state == TranslateInfoBarDelegate::BEFORE_TRANSLATE ||
+ state == TranslateInfoBarDelegate::TRANSLATION_ERROR);
+ delegate->Translate();
+ UMA_HISTOGRAM_COUNTS("Translate.Translate", 1);
+}
+
+// Called when someone clicks on the "Nope" button.
+- (IBAction)cancel:(id)sender {
+ DCHECK(
+ [self delegate]->type() == TranslateInfoBarDelegate::BEFORE_TRANSLATE);
+ [self delegate]->TranslationDeclined();
+ UMA_HISTOGRAM_COUNTS("Translate.DeclineTranslate", 1);
+ [super dismiss:nil];
+}
+
+- (void)messageButtonPressed:(id)sender {
+ [self delegate]->MessageInfoBarButtonPressed();
+}
+
+- (IBAction)showOriginal:(id)sender {
+ [self delegate]->RevertTranslation();
+}
+
+// Called when any of the language drop down menus are changed.
+- (void)languageMenuChanged:(id)item {
+ if ([item respondsToSelector:@selector(tag)]) {
+ int cmd = [item tag];
+ if (cmd >= IDC_TRANSLATE_TARGET_LANGUAGE_BASE) {
+ cmd -= IDC_TRANSLATE_TARGET_LANGUAGE_BASE;
+ [self targetLanguageModified:cmd];
+ return;
+ } else if (cmd >= IDC_TRANSLATE_ORIGINAL_LANGUAGE_BASE) {
+ cmd -= IDC_TRANSLATE_ORIGINAL_LANGUAGE_BASE;
+ [self sourceLanguageModified:cmd];
+ return;
+ }
+ }
+ NOTREACHED() << "Language menu was changed with a bad language ID";
+}
+
+// Called when the options menu is changed.
+- (void)optionsMenuChanged:(id)item {
+ if ([item respondsToSelector:@selector(tag)]) {
+ int cmd = [item tag];
+ // Danger Will Robinson! : This call can release the infobar (e.g. invoking
+ // "About Translate" can open a new tab).
+ // Do not access member variables after this line!
+ optionsMenuModel_->ExecuteCommand(cmd);
+ } else {
+ NOTREACHED();
+ }
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+#pragma mark NSMenuDelegate
+
+// Invoked by virtue of us being set as the delegate for the options menu.
+- (void)menuNeedsUpdate:(NSMenu *)menu {
+ [self adjustOptionsButtonSizeAndVisibilityForView:
+ [[self visibleControls] lastObject]];
+}
+
+@end
+
+@implementation TranslateInfoBarControllerBase (TestingAPI)
+
+- (NSArray*)allControls {
+ return [NSArray arrayWithObjects:label1_.get(),fromLanguagePopUp_.get(),
+ label2_.get(), toLanguagePopUp_.get(), label3_.get(), okButton_,
+ cancelButton_, showOriginalButton_.get(), translateMessageButton_.get(),
+ nil];
+}
+
+- (NSMenu*)optionsMenu {
+ return [optionsPopUp_ menu];
+}
+
+- (NSButton*)translateMessageButton {
+ return translateMessageButton_.get();
+}
+
+- (bool)verifyLayout {
+ // All the controls available to translate infobars, except the options popup.
+ // The options popup is shown/hidden instead of actually removed. This gets
+ // checked in the subclasses.
+ NSArray* allControls = [self allControls];
+ NSArray* visibleControls = [self visibleControls];
+
+ // Step 1: Make sure control visibility is what we expect.
+ for (NSUInteger i = 0; i < [allControls count]; ++i) {
+ id control = [allControls objectAtIndex:i];
+ bool hasSuperView = [control superview];
+ bool expectedVisibility = [visibleControls containsObject:control];
+
+ if (expectedVisibility != hasSuperView) {
+ NSString *title = @"";
+ if ([control isKindOfClass:[NSPopUpButton class]]) {
+ title = [[[control menu] itemAtIndex:0] title];
+ }
+
+ LOG(ERROR) <<
+ "State: " << [self description] <<
+ " Control @" << i << (hasSuperView ? " has" : " doesn't have") <<
+ " a superview" << [[control description] UTF8String] <<
+ " Title=" << [title UTF8String];
+ return false;
+ }
+ }
+
+ // Step 2: Check that controls are ordered correctly with no overlap.
+ id previousControl = nil;
+ for (NSUInteger i = 0; i < [visibleControls count]; ++i) {
+ id control = [visibleControls objectAtIndex:i];
+ // The options pop up doesn't lay out like the rest of the controls as
+ // it floats to the right. It has some known issues shown in
+ // http://crbug.com/47941.
+ if (control == optionsPopUp_.get())
+ continue;
+ if (previousControl &&
+ !VerifyControlOrderAndSpacing(previousControl, control)) {
+ NSString *title = @"";
+ if ([control isKindOfClass:[NSPopUpButton class]]) {
+ title = [[[control menu] itemAtIndex:0] title];
+ }
+ LOG(ERROR) <<
+ "State: " << [self description] <<
+ " Control @" << i << " not ordered correctly: " <<
+ [[control description] UTF8String] <<[title UTF8String];
+ return false;
+ }
+ previousControl = control;
+ }
+
+ return true;
+}
+
+@end // TranslateInfoBarControllerBase (TestingAPI)
+
diff --git a/chrome/browser/ui/cocoa/translate/translate_infobar_unittest.mm b/chrome/browser/ui/cocoa/translate/translate_infobar_unittest.mm
new file mode 100644
index 0000000..9ee57a4
--- /dev/null
+++ b/chrome/browser/ui/cocoa/translate/translate_infobar_unittest.mm
@@ -0,0 +1,254 @@
+// Copyright (c) 2009 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>
+
+#import "base/scoped_nsobject.h"
+#import "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#import "chrome/app/chrome_command_ids.h" // For translate menu command ids.
+#import "chrome/browser/renderer_host/site_instance.h"
+#import "chrome/browser/tab_contents/tab_contents.h"
+#import "chrome/browser/translate/translate_infobar_delegate.h"
+#import "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/infobar.h"
+#import "chrome/browser/ui/cocoa/translate/translate_infobar_base.h"
+#import "chrome/browser/ui/cocoa/translate/before_translate_infobar_controller.h"
+#import "testing/gmock/include/gmock/gmock.h"
+#import "testing/gtest/include/gtest/gtest.h"
+#import "testing/platform_test.h"
+
+namespace {
+
+// All states the translate toolbar can assume.
+TranslateInfoBarDelegate::Type kTranslateToolbarStates[] = {
+ TranslateInfoBarDelegate::BEFORE_TRANSLATE,
+ TranslateInfoBarDelegate::AFTER_TRANSLATE,
+ TranslateInfoBarDelegate::TRANSLATING,
+ TranslateInfoBarDelegate::TRANSLATION_ERROR
+};
+
+class MockTranslateInfoBarDelegate : public TranslateInfoBarDelegate {
+ public:
+ MockTranslateInfoBarDelegate(TranslateInfoBarDelegate::Type type,
+ TranslateErrors::Type error,
+ TabContents* contents)
+ : TranslateInfoBarDelegate(type, error, contents, "en", "es"){
+ // Start out in the "Before Translate" state.
+ type_ = type;
+
+ }
+
+ virtual string16 GetDisplayNameForLocale(const std::string& language_code) {
+ return ASCIIToUTF16("Foo");
+ }
+
+ virtual bool IsLanguageBlacklisted() {
+ return false;
+ }
+
+ virtual bool IsSiteBlacklisted() {
+ return false;
+ }
+
+ virtual bool ShouldAlwaysTranslate() {
+ return false;
+ }
+
+ MOCK_METHOD0(Translate, void());
+ MOCK_METHOD0(RevertTranslation, void());
+ MOCK_METHOD0(TranslationDeclined, void());
+ MOCK_METHOD0(ToggleLanguageBlacklist, void());
+ MOCK_METHOD0(ToggleSiteBlacklist, void());
+ MOCK_METHOD0(ToggleAlwaysTranslate, void());
+};
+
+class TranslationInfoBarTest : public CocoaTest {
+ public:
+ BrowserTestHelper browser_helper_;
+ scoped_ptr<TabContents> tab_contents;
+ scoped_ptr<MockTranslateInfoBarDelegate> infobar_delegate;
+ scoped_nsobject<TranslateInfoBarControllerBase> infobar_controller;
+
+ public:
+ // Each test gets a single Mock translate delegate for the lifetime of
+ // the test.
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ tab_contents.reset(
+ new TabContents(browser_helper_.profile(),
+ NULL,
+ MSG_ROUTING_NONE,
+ NULL,
+ NULL));
+ CreateInfoBar();
+ }
+
+ void CreateInfoBar() {
+ CreateInfoBar(TranslateInfoBarDelegate::BEFORE_TRANSLATE);
+ }
+
+ void CreateInfoBar(TranslateInfoBarDelegate::Type type) {
+ TranslateErrors::Type error = TranslateErrors::NONE;
+ if (type == TranslateInfoBarDelegate::TRANSLATION_ERROR)
+ error = TranslateErrors::NETWORK;
+ infobar_delegate.reset(
+ new MockTranslateInfoBarDelegate(type, error, tab_contents.get()));
+ [[infobar_controller view] removeFromSuperview];
+ scoped_ptr<InfoBar> infobar(infobar_delegate->CreateInfoBar());
+ infobar_controller.reset(
+ reinterpret_cast<TranslateInfoBarControllerBase*>(
+ infobar->controller()));
+ // We need to set the window to be wide so that the options button
+ // doesn't overlap the other buttons.
+ [test_window() setContentSize:NSMakeSize(2000, 500)];
+ [[infobar_controller view] setFrame:NSMakeRect(0, 0, 2000, 500)];
+ [[test_window() contentView] addSubview:[infobar_controller view]];
+ }
+};
+
+// Check that we can instantiate a Translate Infobar correctly.
+TEST_F(TranslationInfoBarTest, Instantiate) {
+ CreateInfoBar();
+ ASSERT_TRUE(infobar_controller.get());
+}
+
+// Check that clicking the Translate button calls Translate().
+TEST_F(TranslationInfoBarTest, TranslateCalledOnButtonPress) {
+ CreateInfoBar();
+
+ EXPECT_CALL(*infobar_delegate, Translate()).Times(1);
+ [infobar_controller ok:nil];
+}
+
+// Check that clicking the "Retry" button calls Translate() when we're
+// in the error mode - http://crbug.com/41315 .
+TEST_F(TranslationInfoBarTest, TranslateCalledInErrorMode) {
+ CreateInfoBar(TranslateInfoBarDelegate::TRANSLATION_ERROR);
+
+ EXPECT_CALL(*infobar_delegate, Translate()).Times(1);
+
+ [infobar_controller ok:nil];
+}
+
+// Check that clicking the "Show Original button calls RevertTranslation().
+TEST_F(TranslationInfoBarTest, RevertCalledOnButtonPress) {
+ CreateInfoBar();
+
+ EXPECT_CALL(*infobar_delegate, RevertTranslation()).Times(1);
+ [infobar_controller showOriginal:nil];
+}
+
+// Check that items in the options menu are hooked up correctly.
+TEST_F(TranslationInfoBarTest, OptionsMenuItemsHookedUp) {
+ EXPECT_CALL(*infobar_delegate, Translate())
+ .Times(0);
+
+ [infobar_controller rebuildOptionsMenu:NO];
+ NSMenu* optionsMenu = [infobar_controller optionsMenu];
+ NSArray* optionsMenuItems = [optionsMenu itemArray];
+
+ EXPECT_EQ(7U, [optionsMenuItems count]);
+
+ // First item is the options menu button's title, so there's no need to test
+ // that the target on that is setup correctly.
+ for (NSUInteger i = 1; i < [optionsMenuItems count]; ++i) {
+ NSMenuItem* item = [optionsMenuItems objectAtIndex:i];
+ if (![item isSeparatorItem])
+ EXPECT_EQ([item target], infobar_controller.get());
+ }
+ NSMenuItem* alwaysTranslateLanguateItem = [optionsMenuItems objectAtIndex:1];
+ NSMenuItem* neverTranslateLanguateItem = [optionsMenuItems objectAtIndex:2];
+ NSMenuItem* neverTranslateSiteItem = [optionsMenuItems objectAtIndex:3];
+ // Separator at 4.
+ NSMenuItem* reportBadLanguageItem = [optionsMenuItems objectAtIndex:5];
+ NSMenuItem* aboutTranslateItem = [optionsMenuItems objectAtIndex:6];
+
+ {
+ EXPECT_CALL(*infobar_delegate, ToggleAlwaysTranslate())
+ .Times(1);
+ [infobar_controller optionsMenuChanged:alwaysTranslateLanguateItem];
+ }
+
+ {
+ EXPECT_CALL(*infobar_delegate, ToggleLanguageBlacklist())
+ .Times(1);
+ [infobar_controller optionsMenuChanged:neverTranslateLanguateItem];
+ }
+
+ {
+ EXPECT_CALL(*infobar_delegate, ToggleSiteBlacklist())
+ .Times(1);
+ [infobar_controller optionsMenuChanged:neverTranslateSiteItem];
+ }
+
+ {
+ // Can't mock these effectively, so just check that the tag is set
+ // correctly.
+ EXPECT_EQ(IDC_TRANSLATE_REPORT_BAD_LANGUAGE_DETECTION,
+ [reportBadLanguageItem tag]);
+ EXPECT_EQ(IDC_TRANSLATE_OPTIONS_ABOUT, [aboutTranslateItem tag]);
+ }
+}
+
+// Check that selecting a new item from the "Source Language" popup in "before
+// translate" mode doesn't trigger a translation or change state.
+// http://crbug.com/36666
+TEST_F(TranslationInfoBarTest, Bug36666) {
+ EXPECT_CALL(*infobar_delegate, Translate())
+ .Times(0);
+
+ CreateInfoBar();
+ int arbitrary_index = 2;
+ [infobar_controller sourceLanguageModified:arbitrary_index];
+ EXPECT_CALL(*infobar_delegate, Translate())
+ .Times(0);
+}
+
+// Check that the infobar lays itself out correctly when instantiated in
+// each of the states.
+// http://crbug.com/36895
+TEST_F(TranslationInfoBarTest, Bug36895) {
+ EXPECT_CALL(*infobar_delegate, Translate())
+ .Times(0);
+
+ for (size_t i = 0; i < arraysize(kTranslateToolbarStates); ++i) {
+ CreateInfoBar(kTranslateToolbarStates[i]);
+ EXPECT_TRUE(
+ [infobar_controller verifyLayout]) << "Layout wrong, for state #" << i;
+ }
+}
+
+// Verify that the infobar shows the "Always translate this language" button
+// after doing 3 translations.
+TEST_F(TranslationInfoBarTest, TriggerShowAlwaysTranslateButton) {
+ TranslatePrefs translate_prefs(browser_helper_.profile()->GetPrefs());
+ translate_prefs.ResetTranslationAcceptedCount("en");
+ for (int i = 0; i < 4; ++i) {
+ translate_prefs.IncrementTranslationAcceptedCount("en");
+ }
+ CreateInfoBar(TranslateInfoBarDelegate::BEFORE_TRANSLATE);
+ BeforeTranslateInfobarController* controller =
+ (BeforeTranslateInfobarController*)infobar_controller.get();
+ EXPECT_TRUE([[controller alwaysTranslateButton] superview] != nil);
+ EXPECT_TRUE([[controller neverTranslateButton] superview] == nil);
+}
+
+// Verify that the infobar shows the "Never translate this language" button
+// after denying 3 translations.
+TEST_F(TranslationInfoBarTest, TriggerShowNeverTranslateButton) {
+ TranslatePrefs translate_prefs(browser_helper_.profile()->GetPrefs());
+ translate_prefs.ResetTranslationDeniedCount("en");
+ for (int i = 0; i < 4; ++i) {
+ translate_prefs.IncrementTranslationDeniedCount("en");
+ }
+ CreateInfoBar(TranslateInfoBarDelegate::BEFORE_TRANSLATE);
+ BeforeTranslateInfobarController* controller =
+ (BeforeTranslateInfobarController*)infobar_controller.get();
+ EXPECT_TRUE([[controller alwaysTranslateButton] superview] == nil);
+ EXPECT_TRUE([[controller neverTranslateButton] superview] != nil);
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/translate/translate_message_infobar_controller.h b/chrome/browser/ui/cocoa/translate/translate_message_infobar_controller.h
new file mode 100644
index 0000000..8a85403
--- /dev/null
+++ b/chrome/browser/ui/cocoa/translate/translate_message_infobar_controller.h
@@ -0,0 +1,10 @@
+// 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 "chrome/browser/ui/cocoa/translate/translate_infobar_base.h"
+
+@interface TranslateMessageInfobarController : TranslateInfoBarControllerBase {
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/translate/translate_message_infobar_controller.mm b/chrome/browser/ui/cocoa/translate/translate_message_infobar_controller.mm
new file mode 100644
index 0000000..00ffe2e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/translate/translate_message_infobar_controller.mm
@@ -0,0 +1,53 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/translate/translate_message_infobar_controller.h"
+
+#include "base/sys_string_conversions.h"
+
+using TranslateInfoBarUtilities::MoveControl;
+
+@implementation TranslateMessageInfobarController
+
+- (void)layout {
+ [self removeOkCancelButtons];
+ MoveControl(label1_, translateMessageButton_, spaceBetweenControls_ * 2, true);
+ TranslateInfoBarDelegate* delegate = [self delegate];
+ if ([self delegate]->ShouldShowMessageInfoBarButton()) {
+ string16 buttonText = delegate->GetMessageInfoBarButtonText();
+ [translateMessageButton_ setTitle:base::SysUTF16ToNSString(buttonText)];
+ [translateMessageButton_ sizeToFit];
+ }
+}
+
+- (void)adjustOptionsButtonSizeAndVisibilityForView:(NSView*)lastView {
+ // Do nothing, but stop the options button from showing up.
+}
+
+- (NSArray*)visibleControls {
+ NSMutableArray* visibleControls =
+ [NSMutableArray arrayWithObjects:label1_.get(), nil];
+ if ([self delegate]->ShouldShowMessageInfoBarButton())
+ [visibleControls addObject:translateMessageButton_];
+ return visibleControls;
+}
+
+- (void)loadLabelText {
+ TranslateInfoBarDelegate* delegate = [self delegate];
+ string16 messageText = delegate->GetMessageInfoBarText();
+ NSString* string1 = base::SysUTF16ToNSString(messageText);
+ [label1_ setStringValue:string1];
+}
+
+- (bool)verifyLayout {
+ if (![optionsPopUp_ isHidden])
+ return false;
+ return [super verifyLayout];
+}
+
+- (BOOL)shouldShowOptionsPopUp {
+ return NO;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/ui_localizer.h b/chrome/browser/ui/cocoa/ui_localizer.h
new file mode 100644
index 0000000..6e426c4
--- /dev/null
+++ b/chrome/browser/ui/cocoa/ui_localizer.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_UI_LOCALIZER_H_
+#define CHROME_BROWSER_UI_COCOA_UI_LOCALIZER_H_
+#pragma once
+
+#import "third_party/GTM/AppKit/GTMUILocalizer.h"
+
+@class NSString;
+
+// A base class for generated localizers.
+//
+// To use this, include your xib file in the list generate_localizer scans (see
+// chrome.gyp). Then add an instance of ChromeUILocalizer to the xib.
+// Connect the owner_ outlet of the instance to the "File's Owner" of the xib.
+// It expects the owner_ outlet to be an instance or subclass of
+// NSWindowController or NSViewController. It will then localize any items in
+// the NSWindowController's window and subviews, or the NSViewController's view
+// and subviews, when awakeFromNib is called on the instance. You can
+// optionally hook up otherObjectToLocalize_ and yetAnotherObjectToLocalize_ and
+// those will also be localized. Strings in the xib that you want localized must
+// start with ^IDS. The value must be a valid resource constant.
+// Things that will be localized are:
+// - Titles and altTitles (for menus, buttons, windows, menuitems, -tabViewItem)
+// - -stringValue (for labels)
+// - tooltips
+// - accessibility help
+// - accessibility descriptions
+// - menus
+@interface ChromeUILocalizer : GTMUILocalizer
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_UI_LOCALIZER_H_
diff --git a/chrome/browser/ui/cocoa/ui_localizer.mm b/chrome/browser/ui/cocoa/ui_localizer.mm
new file mode 100644
index 0000000..fc2e97e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/ui_localizer.mm
@@ -0,0 +1,98 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/cocoa/ui_localizer.h"
+
+#import <Foundation/Foundation.h>
+
+#include <stdlib.h>
+#include "app/l10n_util.h"
+#include "app/l10n_util_mac.h"
+#include "base/sys_string_conversions.h"
+#include "base/logging.h"
+#include "grit/app_strings.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+
+struct UILocalizerResourceMap {
+ const char* const name;
+ unsigned int label_id;
+ unsigned int label_arg_id;
+};
+
+
+namespace {
+
+// Utility function for bsearch on a ResourceMap table
+int ResourceMapCompare(const void* utf8Void,
+ const void* resourceMapVoid) {
+ const char* utf8_key = reinterpret_cast<const char*>(utf8Void);
+ const UILocalizerResourceMap* res_map =
+ reinterpret_cast<const UILocalizerResourceMap*> (resourceMapVoid);
+ return strcmp(utf8_key, res_map->name);
+}
+
+} // namespace
+
+@interface GTMUILocalizer (PrivateAdditions)
+- (void)localizedObjects;
+@end
+
+@implementation GTMUILocalizer (PrivateAdditions)
+- (void)localizedObjects {
+ // The ivars are private, so this method lets us trigger the localization
+ // from -[ChromeUILocalizer awakeFromNib].
+ [self localizeObject:owner_ recursively:YES];
+ [self localizeObject:otherObjectToLocalize_ recursively:YES];
+ [self localizeObject:yetAnotherObjectToLocalize_ recursively:YES];
+}
+ @end
+
+@implementation ChromeUILocalizer
+
+- (void)awakeFromNib {
+ // The GTM base is bundle based, since don't need the bundle, use this
+ // override to bypass the bundle lookup and directly do the localization
+ // calls.
+ [self localizedObjects];
+}
+
+- (NSString *)localizedStringForString:(NSString *)string {
+
+ // Include the table here so it is a local static. This header provides
+ // kUIResources and kUIResourcesSize.
+#include "ui_localizer_table.h"
+
+ // Look up the string for the resource id to fetch.
+ const char* utf8_key = [string UTF8String];
+ if (utf8_key) {
+ const void* valVoid = bsearch(utf8_key,
+ kUIResources,
+ kUIResourcesSize,
+ sizeof(UILocalizerResourceMap),
+ ResourceMapCompare);
+ const UILocalizerResourceMap* val =
+ reinterpret_cast<const UILocalizerResourceMap*>(valVoid);
+ if (val) {
+ // Do we need to build the string, or just fetch it?
+ if (val->label_arg_id != 0) {
+ const string16 label_arg(l10n_util::GetStringUTF16(val->label_arg_id));
+ return l10n_util::GetNSStringFWithFixup(val->label_id,
+ label_arg);
+ }
+
+ return l10n_util::GetNSStringWithFixup(val->label_id);
+ }
+
+ // Sanity check, there shouldn't be any strings with this id that aren't
+ // in our map.
+ DLOG_IF(WARNING, [string hasPrefix:@"^ID"]) << "Key '" << utf8_key
+ << "' wasn't in the resource map?";
+ }
+
+ // If we didn't find anything, this string doesn't need localizing.
+ return nil;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/url_drop_target.h b/chrome/browser/ui/cocoa/url_drop_target.h
new file mode 100644
index 0000000..ea57026
--- /dev/null
+++ b/chrome/browser/ui/cocoa/url_drop_target.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_URL_DROP_TARGET_H_
+#define CHROME_BROWSER_UI_COCOA_URL_DROP_TARGET_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+@protocol URLDropTarget;
+@protocol URLDropTargetController;
+
+// Object which coordinates the dropping of URLs on a given view, sending data
+// and updates to a controller.
+@interface URLDropTargetHandler : NSObject {
+ @private
+ NSView<URLDropTarget>* view_; // weak
+}
+
+// Returns an array of drag types that can be handled.
++ (NSArray*)handledDragTypes;
+
+// Initialize the given view, which must implement the |URLDropTarget| (below),
+// to accept drops of URLs.
+- (id)initWithView:(NSView<URLDropTarget>*)view;
+
+// The owner view should implement the following methods by calling the
+// |URLDropTargetHandler|'s version, and leave the others to the default
+// implementation provided by |NSView|/|NSWindow|.
+- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender;
+- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender;
+- (void)draggingExited:(id<NSDraggingInfo>)sender;
+- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender;
+
+@end // @interface URLDropTargetHandler
+
+// Protocol which views that are URL drop targets and use |URLDropTargetHandler|
+// must implement.
+@protocol URLDropTarget
+
+// Returns the controller which handles the drop.
+- (id<URLDropTargetController>)urlDropController;
+
+// The following, which come from |NSDraggingDestination|, must be implemented
+// by calling the |URLDropTargetHandler|'s implementations.
+- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender;
+- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender;
+- (void)draggingExited:(id<NSDraggingInfo>)sender;
+- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender;
+
+@end // @protocol URLDropTarget
+
+// Protocol for the controller which handles the actual drop data/drop updates.
+@protocol URLDropTargetController
+
+// The given URLs (an |NSArray| of |NSString|s) were dropped in the given view
+// at the given point (in that view's coordinates).
+- (void)dropURLs:(NSArray*)urls inView:(NSView*)view at:(NSPoint)point;
+
+// The given text was dropped in the given view at the given point (in that
+// view's coordinates).
+- (void)dropText:(NSString*)text inView:(NSView*)view at:(NSPoint)point;
+
+// Dragging is in progress over the owner view (at the given point, in view
+// coordinates) and any indicator of location -- e.g., an arrow -- should be
+// updated/shown.
+- (void)indicateDropURLsInView:(NSView*)view at:(NSPoint)point;
+
+// Dragging is over, and any indicator should be hidden.
+- (void)hideDropURLsIndicatorInView:(NSView*)view;
+
+@end // @protocol URLDropTargetController
+
+#endif // CHROME_BROWSER_UI_COCOA_URL_DROP_TARGET_H_
diff --git a/chrome/browser/ui/cocoa/url_drop_target.mm b/chrome/browser/ui/cocoa/url_drop_target.mm
new file mode 100644
index 0000000..ceca7d2
--- /dev/null
+++ b/chrome/browser/ui/cocoa/url_drop_target.mm
@@ -0,0 +1,109 @@
+// 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 "chrome/browser/ui/cocoa/url_drop_target.h"
+
+#include "base/basictypes.h"
+#import "third_party/mozilla/NSPasteboard+Utils.h"
+
+@interface URLDropTargetHandler(Private)
+
+// Gets the appropriate drag operation given the |NSDraggingInfo|.
+- (NSDragOperation)getDragOperation:(id<NSDraggingInfo>)sender;
+
+// Tell the window controller to hide the drop indicator.
+- (void)hideIndicator;
+
+@end // @interface URLDropTargetHandler(Private)
+
+@implementation URLDropTargetHandler
+
++ (NSArray*)handledDragTypes {
+ return [NSArray arrayWithObjects:kWebURLsWithTitlesPboardType,
+ NSURLPboardType,
+ NSStringPboardType,
+ NSFilenamesPboardType,
+ nil];
+}
+
+- (id)initWithView:(NSView<URLDropTarget>*)view {
+ if ((self = [super init])) {
+ view_ = view;
+ [view_ registerForDraggedTypes:[URLDropTargetHandler handledDragTypes]];
+ }
+ return self;
+}
+
+// The following four methods implement parts of the |NSDraggingDestination|
+// protocol, which the owner should "forward" to its |URLDropTargetHandler|
+// (us).
+
+- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
+ return [self getDragOperation:sender];
+}
+
+- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender {
+ NSDragOperation dragOp = [self getDragOperation:sender];
+ if (dragOp == NSDragOperationCopy) {
+ // Just tell the window controller to update the indicator.
+ NSPoint hoverPoint = [view_ convertPoint:[sender draggingLocation]
+ fromView:nil];
+ [[view_ urlDropController] indicateDropURLsInView:view_ at:hoverPoint];
+ }
+ return dragOp;
+}
+
+- (void)draggingExited:(id<NSDraggingInfo>)sender {
+ [self hideIndicator];
+}
+
+- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
+ [self hideIndicator];
+
+ NSPasteboard* pboard = [sender draggingPasteboard];
+ NSArray* supportedTypes = [NSArray arrayWithObjects:NSStringPboardType, nil];
+ NSString* bestType = [pboard availableTypeFromArray:supportedTypes];
+
+ NSPoint dropPoint =
+ [view_ convertPoint:[sender draggingLocation] fromView:nil];
+ // Tell the window controller about the dropped URL(s).
+ if ([pboard containsURLData]) {
+ NSArray* urls = nil;
+ NSArray* titles; // discarded
+ [pboard getURLs:&urls andTitles:&titles convertingFilenames:YES];
+
+ if ([urls count]) {
+ [[view_ urlDropController] dropURLs:urls inView:view_ at:dropPoint];
+ return YES;
+ }
+ } else if (NSString* text = [pboard stringForType:bestType]) {
+ // This does not include any URLs, so treat it as plain text if we can
+ // get NSString.
+ [[view_ urlDropController] dropText:text inView:view_ at:dropPoint];
+ return YES;
+ }
+
+ return NO;
+}
+
+@end // @implementation URLDropTargetHandler
+
+@implementation URLDropTargetHandler(Private)
+
+- (NSDragOperation)getDragOperation:(id<NSDraggingInfo>)sender {
+ NSPasteboard* pboard = [sender draggingPasteboard];
+ NSArray *supportedTypes = [NSArray arrayWithObjects:NSStringPboardType, nil];
+ NSString *bestType = [pboard availableTypeFromArray:supportedTypes];
+ if (![pboard containsURLData] && ![pboard stringForType:bestType])
+ return NSDragOperationNone;
+
+ // Only allow the copy operation.
+ return [sender draggingSourceOperationMask] & NSDragOperationCopy;
+}
+
+- (void)hideIndicator {
+ [[view_ urlDropController] hideDropURLsIndicatorInView:view_];
+}
+
+@end // @implementation URLDropTargetHandler(Private)
diff --git a/chrome/browser/ui/cocoa/vertical_gradient_view.h b/chrome/browser/ui/cocoa/vertical_gradient_view.h
new file mode 100644
index 0000000..98a3a2b
--- /dev/null
+++ b/chrome/browser/ui/cocoa/vertical_gradient_view.h
@@ -0,0 +1,36 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_VERTICAL_GRADIENT_VIEW_H_
+#define CHROME_BROWSER_UI_COCOA_VERTICAL_GRADIENT_VIEW_H_
+#pragma once
+
+#include "base/scoped_nsobject.h"
+
+#import <Cocoa/Cocoa.h>
+
+// Draws a vertical background gradient with a bottom stroke. The gradient and
+// stroke colors can be defined by calling |setGradient| and |setStrokeColor|,
+// respectively. Alternatively, you may override the |gradient| and
+// |strokeColor| accessors in order to provide colors dynamically. If the
+// gradient or color is |nil|, the respective element will not be drawn.
+@interface VerticalGradientView : NSView {
+ @private
+ // The gradient to draw.
+ scoped_nsobject<NSGradient> gradient_;
+ // Color for bottom stroke.
+ scoped_nsobject<NSColor> strokeColor_;
+}
+
+// Gets and sets the gradient to paint as background.
+- (NSGradient*)gradient;
+- (void)setGradient:(NSGradient*)gradient;
+
+// Gets and sets the color of the stroke drawn at the bottom of the view.
+- (NSColor*)strokeColor;
+- (void)setStrokeColor:(NSColor*)gradient;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_VERTICAL_GRADIENT_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/vertical_gradient_view.mm b/chrome/browser/ui/cocoa/vertical_gradient_view.mm
new file mode 100644
index 0000000..30b9e2f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/vertical_gradient_view.mm
@@ -0,0 +1,39 @@
+// 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.
+
+#include "chrome/browser/ui/cocoa/vertical_gradient_view.h"
+
+@implementation VerticalGradientView
+
+- (NSGradient*)gradient {
+ return gradient_;
+}
+
+- (void)setGradient:(NSGradient*)gradient {
+ gradient_.reset([gradient retain]);
+}
+
+- (NSColor*)strokeColor {
+ return strokeColor_;
+}
+
+- (void)setStrokeColor:(NSColor*)strokeColor {
+ strokeColor_.reset([strokeColor retain]);
+}
+
+- (void)drawRect:(NSRect)rect {
+ // Draw gradient.
+ [[self gradient] drawInRect:[self bounds] angle:270];
+
+ // Draw bottom stroke.
+ NSColor* strokeColor = [self strokeColor];
+ if (strokeColor) {
+ [[self strokeColor] set];
+ NSRect borderRect, contentRect;
+ NSDivideRect([self bounds], &borderRect, &contentRect, 1, NSMinYEdge);
+ NSRectFillUsingOperation(borderRect, NSCompositeSourceOver);
+ }
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/vertical_gradient_view_unittest.mm b/chrome/browser/ui/cocoa/vertical_gradient_view_unittest.mm
new file mode 100644
index 0000000..e574a69
--- /dev/null
+++ b/chrome/browser/ui/cocoa/vertical_gradient_view_unittest.mm
@@ -0,0 +1,27 @@
+// 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.
+
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/vertical_gradient_view.h"
+
+namespace {
+
+class VerticalGradientViewTest : public CocoaTest {
+ public:
+ VerticalGradientViewTest() {
+ NSRect frame = NSMakeRect(0, 0, 50, 27);
+ scoped_nsobject<VerticalGradientView> view(
+ [[VerticalGradientView alloc] initWithFrame:frame]);
+ view_ = view.get();
+ [[test_window() contentView] addSubview:view_];
+ }
+
+ VerticalGradientView* view_;
+};
+
+TEST_VIEW(VerticalGradientViewTest, view_);
+
+} // namespace
+
diff --git a/chrome/browser/ui/cocoa/view_id_util.h b/chrome/browser/ui/cocoa/view_id_util.h
new file mode 100644
index 0000000..6ea9524
--- /dev/null
+++ b/chrome/browser/ui/cocoa/view_id_util.h
@@ -0,0 +1,52 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_VIEW_ID_UTIL_H_
+#define CHROME_BROWSER_UI_COCOA_VIEW_ID_UTIL_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "gfx/native_widget_types.h"
+#include "chrome/browser/ui/view_ids.h"
+
+// ViewIDs are a system that indexes important views in the browser window by a
+// ViewID identifier (integer). This is a useful compatibility for finding a
+// view object in cross-platform tests. See BrowserFocusTest.* for an example
+// of how ViewIDs are used.
+
+// For views with fixed ViewIDs, we add a -viewID method to them to return their
+// ViewIDs directly. But for views with changeable ViewIDs, as NSView itself
+// doesn't provide a facility to store its ViewID, to avoid modifying each
+// individual classes for adding ViewID support, we use an internal map to store
+// ViewIDs of each view and provide some utility functions for NSView to
+// set/unset the ViewID and lookup a view with a specified ViewID.
+
+namespace view_id_util {
+
+// Associates the given ViewID with the view. It shall be called upon the view's
+// initialization.
+void SetID(NSView* view, ViewID viewID);
+
+// Removes the association between the view and its ViewID. It shall be called
+// just before the view's destruction.
+void UnsetID(NSView* view);
+
+// Returns the view with a specific ViewID in a window, or nil if no view in the
+// window has that ViewID.
+NSView* GetView(NSWindow* window, ViewID viewID);
+
+} // namespace view_id_util
+
+
+@interface NSView (ViewID)
+
+// Returns the ViewID associated to the receiver. The default implementation
+// looks up the view's ViewID in the internal view to ViewID map. A subclass may
+// override this method to return its fixed ViewID.
+- (ViewID)viewID;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_VIEW_ID_UTIL_H_
diff --git a/chrome/browser/ui/cocoa/view_id_util.mm b/chrome/browser/ui/cocoa/view_id_util.mm
new file mode 100644
index 0000000..ea0e859
--- /dev/null
+++ b/chrome/browser/ui/cocoa/view_id_util.mm
@@ -0,0 +1,89 @@
+// 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 "chrome/browser/ui/cocoa/view_id_util.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include <map>
+#include <utility>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "chrome/browser/ui/cocoa/tab_strip_controller.h"
+
+namespace {
+
+// TODO(suzhe): After migrating to Mac OS X 10.6, we may use Objective-C's new
+// "Associative References" feature to attach the ViewID to the view directly
+// rather than using a separated map.
+typedef std::map<NSView*, ViewID> ViewIDMap;
+
+static base::LazyInstance<ViewIDMap> g_view_id_map(base::LINKER_INITIALIZED);
+
+// Returns the view's nearest descendant (including itself) with a specific
+// ViewID, or nil if no subview has that ViewID.
+NSView* FindViewWithID(NSView* view, ViewID viewID) {
+ if ([view viewID] == viewID)
+ return view;
+
+ for (NSView* subview in [view subviews]) {
+ NSView* result = FindViewWithID(subview, viewID);
+ if (result != nil)
+ return result;
+ }
+ return nil;
+}
+
+} // anonymous namespace
+
+namespace view_id_util {
+
+void SetID(NSView* view, ViewID viewID) {
+ DCHECK(view);
+ DCHECK(viewID != VIEW_ID_NONE);
+ // We handle VIEW_ID_TAB_0 to VIEW_ID_TAB_LAST in GetView() function directly.
+ DCHECK(!((viewID >= VIEW_ID_TAB_0) && (viewID <= VIEW_ID_TAB_LAST)));
+ g_view_id_map.Get()[view] = viewID;
+}
+
+void UnsetID(NSView* view) {
+ DCHECK(view);
+ g_view_id_map.Get().erase(view);
+}
+
+NSView* GetView(NSWindow* window, ViewID viewID) {
+ DCHECK(viewID != VIEW_ID_NONE);
+ DCHECK(window);
+
+ // As tabs can be created, destroyed or rearranged dynamically, we handle them
+ // here specially.
+ if (viewID >= VIEW_ID_TAB_0 && viewID <= VIEW_ID_TAB_LAST) {
+ BrowserWindowController* windowController = [window windowController];
+ DCHECK([windowController isKindOfClass:[BrowserWindowController class]]);
+ TabStripController* tabStripController =
+ [windowController tabStripController];
+ DCHECK(tabStripController);
+ NSUInteger count = [tabStripController viewsCount];
+ DCHECK(count);
+ NSUInteger index =
+ (viewID == VIEW_ID_TAB_LAST ? count - 1 : viewID - VIEW_ID_TAB_0);
+ return index < count ? [tabStripController viewAtIndex:index] : nil;
+ }
+
+ return FindViewWithID([[window contentView] superview], viewID);
+}
+
+} // namespace view_id_util
+
+@implementation NSView (ViewID)
+
+- (ViewID)viewID {
+ ViewIDMap* map = g_view_id_map.Pointer();
+ ViewIDMap::const_iterator iter = map->find(self);
+ return iter != map->end() ? iter->second : VIEW_ID_NONE;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/view_id_util_browsertest.mm b/chrome/browser/ui/cocoa/view_id_util_browsertest.mm
new file mode 100644
index 0000000..8d10b4c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/view_id_util_browsertest.mm
@@ -0,0 +1,118 @@
+// 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.
+
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/download/download_shelf.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sidebar/sidebar_manager.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/cocoa/view_id_util.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/test/in_process_browser_test.h"
+#include "chrome/test/ui_test_utils.h"
+
+// Basic sanity check of ViewID use on the mac.
+class ViewIDTest : public InProcessBrowserTest {
+ public:
+ ViewIDTest() : root_window_(nil) {
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableExperimentalExtensionApis);
+ }
+
+ void CheckViewID(ViewID view_id, bool should_have) {
+ if (!root_window_)
+ root_window_ = browser()->window()->GetNativeHandle();
+
+ ASSERT_TRUE(root_window_);
+ NSView* view = view_id_util::GetView(root_window_, view_id);
+ EXPECT_EQ(should_have, !!view) << " Failed id=" << view_id;
+ }
+
+ void DoTest() {
+ // Make sure FindBar is created to test
+ // VIEW_ID_FIND_IN_PAGE_TEXT_FIELD and VIEW_ID_FIND_IN_PAGE.
+ browser()->ShowFindBar();
+
+ // Make sure sidebar is created to test VIEW_ID_SIDE_BAR_CONTAINER.
+ const char sidebar_content_id[] = "test_content_id";
+ SidebarManager::GetInstance()->ShowSidebar(
+ browser()->GetSelectedTabContents(), sidebar_content_id);
+ SidebarManager::GetInstance()->ExpandSidebar(
+ browser()->GetSelectedTabContents(), sidebar_content_id);
+
+ // Make sure docked devtools is created to test VIEW_ID_DEV_TOOLS_DOCKED
+ browser()->profile()->GetPrefs()->SetBoolean(prefs::kDevToolsOpenDocked,
+ true);
+ browser()->ToggleDevToolsWindow(DEVTOOLS_TOGGLE_ACTION_INSPECT);
+
+ // Make sure download shelf is created to test VIEW_ID_DOWNLOAD_SHELF
+ browser()->window()->GetDownloadShelf()->Show();
+
+ // Create a bookmark to test VIEW_ID_BOOKMARK_BAR_ELEMENT
+ BookmarkModel* bookmark_model = browser()->profile()->GetBookmarkModel();
+ if (bookmark_model) {
+ if (!bookmark_model->IsLoaded())
+ ui_test_utils::WaitForBookmarkModelToLoad(bookmark_model);
+
+ bookmark_model->SetURLStarred(GURL(chrome::kAboutBlankURL),
+ UTF8ToUTF16("about"), true);
+ }
+
+ for (int i = VIEW_ID_TOOLBAR; i < VIEW_ID_PREDEFINED_COUNT; ++i) {
+ // Mac implementation does not support following ids yet.
+ if (i == VIEW_ID_STAR_BUTTON ||
+ i == VIEW_ID_AUTOCOMPLETE ||
+ i == VIEW_ID_CONTENTS_SPLIT ||
+ i == VIEW_ID_SIDE_BAR_SPLIT ||
+ i == VIEW_ID_FEEDBACK_BUTTON) {
+ continue;
+ }
+
+ CheckViewID(static_cast<ViewID>(i), true);
+ }
+
+ CheckViewID(VIEW_ID_TAB, true);
+ CheckViewID(VIEW_ID_TAB_STRIP, true);
+ CheckViewID(VIEW_ID_PREDEFINED_COUNT, false);
+ }
+
+ private:
+ NSWindow* root_window_;
+};
+
+IN_PROC_BROWSER_TEST_F(ViewIDTest, Basic) {
+ ASSERT_NO_FATAL_FAILURE(DoTest());
+}
+
+IN_PROC_BROWSER_TEST_F(ViewIDTest, Fullscreen) {
+ browser()->window()->SetFullscreen(true);
+ ASSERT_NO_FATAL_FAILURE(DoTest());
+}
+
+IN_PROC_BROWSER_TEST_F(ViewIDTest, Tab) {
+ CheckViewID(VIEW_ID_TAB_0, true);
+ CheckViewID(VIEW_ID_TAB_LAST, true);
+
+ // Open 9 new tabs.
+ for (int i = 1; i <= 9; ++i) {
+ CheckViewID(static_cast<ViewID>(VIEW_ID_TAB_0 + i), false);
+ browser()->OpenURL(GURL(chrome::kAboutBlankURL), GURL(),
+ NEW_BACKGROUND_TAB, PageTransition::TYPED);
+ CheckViewID(static_cast<ViewID>(VIEW_ID_TAB_0 + i), true);
+ // VIEW_ID_TAB_LAST should always be available.
+ CheckViewID(VIEW_ID_TAB_LAST, true);
+ }
+
+ // Open the 11th tab.
+ browser()->OpenURL(GURL(chrome::kAboutBlankURL), GURL(),
+ NEW_BACKGROUND_TAB, PageTransition::TYPED);
+ CheckViewID(VIEW_ID_TAB_LAST, true);
+}
diff --git a/chrome/browser/ui/cocoa/view_resizer.h b/chrome/browser/ui/cocoa/view_resizer.h
new file mode 100644
index 0000000..f27373f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/view_resizer.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_VIEW_RESIZER_H_
+#define CHROME_BROWSER_UI_COCOA_VIEW_RESIZER_H_
+#pragma once
+
+#include "chrome/browser/tabs/tab_strip_model.h"
+
+#import <Cocoa/Cocoa.h>
+
+// Defines a protocol that allows controllers to delegate resizing their views
+// to their parents. When a controller needs to change a view's height, rather
+// than resizing it directly, it sends a message to its parent asking the parent
+// to perform the resize. This allows the parent to do any re-layout that may
+// become necessary due to the resize.
+@protocol ViewResizer <NSObject>
+- (void)resizeView:(NSView*)view newHeight:(CGFloat)height;
+
+@optional
+// Optional method called when an animation is beginning or ending. Resize
+// delegates can implement this method if they need to modify their behavior
+// while an animation is running.
+- (void)setAnimationInProgress:(BOOL)inProgress;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_VIEW_RESIZER_H_
diff --git a/chrome/browser/ui/cocoa/view_resizer_pong.h b/chrome/browser/ui/cocoa/view_resizer_pong.h
new file mode 100644
index 0000000..628c0d5
--- /dev/null
+++ b/chrome/browser/ui/cocoa/view_resizer_pong.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_VIEW_RESIZER_PONG_H_
+#define CHROME_BROWSER_UI_COCOA_VIEW_RESIZER_PONG_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#import "chrome/browser/ui/cocoa/view_resizer.h"
+
+@interface ViewResizerPong : NSObject<ViewResizer> {
+ @private
+ CGFloat height_;
+}
+@property (nonatomic) CGFloat height;
+
+- (void)resizeView:(NSView*)view newHeight:(CGFloat)height;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_VIEW_RESIZER_PONG_H_
diff --git a/chrome/browser/ui/cocoa/view_resizer_pong.mm b/chrome/browser/ui/cocoa/view_resizer_pong.mm
new file mode 100644
index 0000000..f063dbf
--- /dev/null
+++ b/chrome/browser/ui/cocoa/view_resizer_pong.mm
@@ -0,0 +1,20 @@
+// Copyright (c) 2009 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>
+
+#import "chrome/browser/ui/cocoa/view_resizer_pong.h"
+
+@implementation ViewResizerPong
+
+@synthesize height = height_;
+
+- (void)resizeView:(NSView*)view newHeight:(CGFloat)height {
+ [self setHeight:height];
+
+ // Set the view's height and width, in case it uses that as important state.
+ [view setFrame:NSMakeRect(100, 50,
+ NSWidth([[view superview] frame]) - 50, height)];
+}
+@end
diff --git a/chrome/browser/ui/cocoa/web_contents_drag_source.h b/chrome/browser/ui/cocoa/web_contents_drag_source.h
new file mode 100644
index 0000000..aa9dd73
--- /dev/null
+++ b/chrome/browser/ui/cocoa/web_contents_drag_source.h
@@ -0,0 +1,62 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_WEB_CONTENTS_DRAG_SOURCE_H_
+#define CHROME_BROWSER_UI_COCOA_WEB_CONTENTS_DRAG_SOURCE_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+#include "chrome/browser/bookmarks/bookmark_node_data.h"
+
+@class TabContentsViewCocoa;
+
+// A class that handles tracking and event processing for a drag and drop
+// originating from the content area. Subclasses should implement
+// fillClipboard and dragImage.
+@interface WebContentsDragSource : NSObject {
+ @private
+ // Our tab. Weak reference (owns or co-owns us).
+ TabContentsViewCocoa* contentsView_;
+
+ // Our pasteboard.
+ scoped_nsobject<NSPasteboard> pasteboard_;
+
+ // A mask of the allowed drag operations.
+ NSDragOperation dragOperationMask_;
+}
+
+// Initialize a DragDataSource object for a drag (originating on the given
+// contentsView and with the given dropData and pboard). Fill the pasteboard
+// with data types appropriate for dropData.
+- (id)initWithContentsView:(TabContentsViewCocoa*)contentsView
+ pasteboard:(NSPasteboard*)pboard
+ dragOperationMask:(NSDragOperation)dragOperationMask;
+
+// Creates the drag image. Implemented by the subclass.
+- (NSImage*)dragImage;
+
+// Put the data being dragged onto the pasteboard. Implemented by the
+// subclass.
+- (void)fillPasteboard;
+
+// Returns a mask of the allowed drag operations.
+- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal;
+
+// Start the drag (on the originally provided contentsView); can do this right
+// after -initWithContentsView:....
+- (void)startDrag;
+
+// End the drag and clear the pasteboard; hook up to
+// -draggedImage:endedAt:operation:.
+- (void)endDragAt:(NSPoint)screenPoint
+ operation:(NSDragOperation)operation;
+
+// Drag moved; hook up to -draggedImage:movedTo:.
+- (void)moveDragTo:(NSPoint)screenPoint;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_WEB_CONTENTS_DRAG_SOURCE_H_
diff --git a/chrome/browser/ui/cocoa/web_contents_drag_source.mm b/chrome/browser/ui/cocoa/web_contents_drag_source.mm
new file mode 100644
index 0000000..68cfcfd
--- /dev/null
+++ b/chrome/browser/ui/cocoa/web_contents_drag_source.mm
@@ -0,0 +1,130 @@
+// 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 "chrome/browser/ui/cocoa/web_contents_drag_source.h"
+
+#include "app/mac/nsimage_cache.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_contents_view_mac.h"
+
+namespace {
+
+// Make a drag image from the drop data.
+// TODO(feldstein): Make this work
+NSImage* MakeDragImage() {
+ // TODO(feldstein): Just a stub for now. Make it do something (see, e.g.,
+ // WebKit/WebKit/mac/Misc/WebNSViewExtras.m: |-_web_DragImageForElement:...|).
+
+ // Default to returning a generic image.
+ return app::mac::GetCachedImageWithName(@"nav.pdf");
+}
+
+// Flips screen and point coordinates over the y axis to work with webkit
+// coordinate systems.
+void FlipPointCoordinates(NSPoint& screenPoint,
+ NSPoint& localPoint,
+ NSView* view) {
+ NSRect viewFrame = [view frame];
+ localPoint.y = NSHeight(viewFrame) - localPoint.y;
+ // Flip |screenPoint|.
+ NSRect screenFrame = [[[view window] screen] frame];
+ screenPoint.y = NSHeight(screenFrame) - screenPoint.y;
+}
+
+} // namespace
+
+
+@implementation WebContentsDragSource
+
+- (id)initWithContentsView:(TabContentsViewCocoa*)contentsView
+ pasteboard:(NSPasteboard*)pboard
+ dragOperationMask:(NSDragOperation)dragOperationMask {
+ if ((self = [super init])) {
+ contentsView_ = contentsView;
+ DCHECK(contentsView_);
+
+ pasteboard_.reset([pboard retain]);
+ DCHECK(pasteboard_.get());
+
+ dragOperationMask_ = dragOperationMask;
+ }
+
+ return self;
+}
+
+- (NSImage*)dragImage {
+ return MakeDragImage();
+}
+
+- (void)fillPasteboard {
+ NOTIMPLEMENTED() << "Subclasses should implement fillPasteboard";
+}
+
+- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal {
+ return dragOperationMask_;
+}
+
+- (void)startDrag {
+ [self fillPasteboard];
+ NSEvent* currentEvent = [NSApp currentEvent];
+
+ // Synthesize an event for dragging, since we can't be sure that
+ // [NSApp currentEvent] will return a valid dragging event.
+ NSWindow* window = [contentsView_ window];
+ NSPoint position = [window mouseLocationOutsideOfEventStream];
+ NSTimeInterval eventTime = [currentEvent timestamp];
+ NSEvent* dragEvent = [NSEvent mouseEventWithType:NSLeftMouseDragged
+ location:position
+ modifierFlags:NSLeftMouseDraggedMask
+ timestamp:eventTime
+ windowNumber:[window windowNumber]
+ context:nil
+ eventNumber:0
+ clickCount:1
+ pressure:1.0];
+ [window dragImage:[self dragImage]
+ at:position
+ offset:NSZeroSize
+ event:dragEvent
+ pasteboard:pasteboard_
+ source:self
+ slideBack:YES];
+}
+
+- (void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint
+ operation:(NSDragOperation)operation {
+}
+
+- (void)endDragAt:(NSPoint)screenPoint
+ operation:(NSDragOperation)operation {
+ RenderViewHost* rvh = [contentsView_ tabContents]->render_view_host();
+ if (rvh) {
+ rvh->DragSourceSystemDragEnded();
+
+ NSPoint localPoint = [contentsView_ convertPoint:screenPoint fromView: nil];
+ FlipPointCoordinates(screenPoint, localPoint, contentsView_);
+ rvh->DragSourceEndedAt(localPoint.x, localPoint.y,
+ screenPoint.x, screenPoint.y,
+ static_cast<WebKit::WebDragOperation>(operation));
+ }
+
+ // Make sure the pasteboard owner isn't us.
+ [pasteboard_ declareTypes:[NSArray array] owner:nil];
+}
+
+- (void)moveDragTo:(NSPoint)screenPoint {
+ RenderViewHost* rvh = [contentsView_ tabContents]->render_view_host();
+ if (rvh) {
+ NSPoint localPoint = [contentsView_ convertPoint:screenPoint fromView:nil];
+ FlipPointCoordinates(screenPoint, localPoint, contentsView_);
+ rvh->DragSourceMovedTo(localPoint.x, localPoint.y,
+ screenPoint.x, screenPoint.y);
+ }
+}
+
+@end // @implementation WebContentsDragSource
+
diff --git a/chrome/browser/cocoa/web_drag_source.h b/chrome/browser/ui/cocoa/web_drag_source.h
index 9cfcba5..9cfcba5 100644
--- a/chrome/browser/cocoa/web_drag_source.h
+++ b/chrome/browser/ui/cocoa/web_drag_source.h
diff --git a/chrome/browser/ui/cocoa/web_drag_source.mm b/chrome/browser/ui/cocoa/web_drag_source.mm
new file mode 100644
index 0000000..1fb4c7f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/web_drag_source.mm
@@ -0,0 +1,412 @@
+// 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 "chrome/browser/ui/cocoa/web_drag_source.h"
+
+#include "app/mac/nsimage_cache.h"
+#include "base/file_path.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+#include "base/task.h"
+#include "base/thread.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/download/download_manager.h"
+#include "chrome/browser/download/download_util.h"
+#include "chrome/browser/download/drag_download_file.h"
+#include "chrome/browser/download/drag_download_util.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_contents_view_mac.h"
+#include "net/base/file_stream.h"
+#include "net/base/net_util.h"
+#import "third_party/mozilla/NSPasteboard+Utils.h"
+#include "webkit/glue/webdropdata.h"
+
+using base::SysNSStringToUTF8;
+using base::SysUTF8ToNSString;
+using base::SysUTF16ToNSString;
+using net::FileStream;
+
+
+namespace {
+
+// An unofficial standard pasteboard title type to be provided alongside the
+// |NSURLPboardType|.
+NSString* const kNSURLTitlePboardType = @"public.url-name";
+
+// Returns a filename appropriate for the drop data
+// TODO(viettrungluu): Refactor to make it common across platforms,
+// and move it somewhere sensible.
+FilePath GetFileNameFromDragData(const WebDropData& drop_data) {
+ // Images without ALT text will only have a file extension so we need to
+ // synthesize one from the provided extension and URL.
+ FilePath file_name([SysUTF16ToNSString(drop_data.file_description_filename)
+ fileSystemRepresentation]);
+ file_name = file_name.BaseName().RemoveExtension();
+
+ if (file_name.empty()) {
+ // Retrieve the name from the URL.
+ file_name = net::GetSuggestedFilename(drop_data.url, "", "", FilePath());
+ }
+
+ file_name = file_name.ReplaceExtension([SysUTF16ToNSString(
+ drop_data.file_extension) fileSystemRepresentation]);
+
+ return file_name;
+}
+
+// This class's sole task is to write out data for a promised file; the caller
+// is responsible for opening the file.
+class PromiseWriterTask : public Task {
+ public:
+ // Assumes ownership of file_stream.
+ PromiseWriterTask(const WebDropData& drop_data,
+ FileStream* file_stream);
+ virtual ~PromiseWriterTask();
+ virtual void Run();
+
+ private:
+ WebDropData drop_data_;
+
+ // This class takes ownership of file_stream_ and will close and delete it.
+ scoped_ptr<FileStream> file_stream_;
+};
+
+// Takes the drop data and an open file stream (which it takes ownership of and
+// will close and delete).
+PromiseWriterTask::PromiseWriterTask(const WebDropData& drop_data,
+ FileStream* file_stream) :
+ drop_data_(drop_data) {
+ file_stream_.reset(file_stream);
+ DCHECK(file_stream_.get());
+}
+
+PromiseWriterTask::~PromiseWriterTask() {
+ DCHECK(file_stream_.get());
+ if (file_stream_.get())
+ file_stream_->Close();
+}
+
+void PromiseWriterTask::Run() {
+ CHECK(file_stream_.get());
+ file_stream_->Write(drop_data_.file_contents.data(),
+ drop_data_.file_contents.length(),
+ NULL);
+
+ // Let our destructor take care of business.
+}
+
+} // namespace
+
+
+@interface WebDragSource(Private)
+
+- (void)fillPasteboard;
+- (NSImage*)dragImage;
+
+@end // @interface WebDragSource(Private)
+
+
+@implementation WebDragSource
+
+- (id)initWithContentsView:(TabContentsViewCocoa*)contentsView
+ dropData:(const WebDropData*)dropData
+ image:(NSImage*)image
+ offset:(NSPoint)offset
+ pasteboard:(NSPasteboard*)pboard
+ dragOperationMask:(NSDragOperation)dragOperationMask {
+ if ((self = [super init])) {
+ contentsView_ = contentsView;
+ DCHECK(contentsView_);
+
+ dropData_.reset(new WebDropData(*dropData));
+ DCHECK(dropData_.get());
+
+ dragImage_.reset([image retain]);
+ imageOffset_ = offset;
+
+ pasteboard_.reset([pboard retain]);
+ DCHECK(pasteboard_.get());
+
+ dragOperationMask_ = dragOperationMask;
+
+ [self fillPasteboard];
+ }
+
+ return self;
+}
+
+- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal {
+ return dragOperationMask_;
+}
+
+- (void)lazyWriteToPasteboard:(NSPasteboard*)pboard forType:(NSString*)type {
+ // NSHTMLPboardType requires the character set to be declared. Otherwise, it
+ // assumes US-ASCII. Awesome.
+ static const string16 kHtmlHeader =
+ ASCIIToUTF16("<meta http-equiv=\"Content-Type\" "
+ "content=\"text/html;charset=UTF-8\">");
+
+ // Be extra paranoid; avoid crashing.
+ if (!dropData_.get()) {
+ NOTREACHED() << "No drag-and-drop data available for lazy write.";
+ return;
+ }
+
+ // HTML.
+ if ([type isEqualToString:NSHTMLPboardType]) {
+ DCHECK(!dropData_->text_html.empty());
+ // See comment on |kHtmlHeader| above.
+ [pboard setString:SysUTF16ToNSString(kHtmlHeader + dropData_->text_html)
+ forType:NSHTMLPboardType];
+
+ // URL.
+ } else if ([type isEqualToString:NSURLPboardType]) {
+ DCHECK(dropData_->url.is_valid());
+ NSURL* url = [NSURL URLWithString:SysUTF8ToNSString(dropData_->url.spec())];
+ [url writeToPasteboard:pboard];
+
+ // URL title.
+ } else if ([type isEqualToString:kNSURLTitlePboardType]) {
+ [pboard setString:SysUTF16ToNSString(dropData_->url_title)
+ forType:kNSURLTitlePboardType];
+
+ // File contents.
+ } else if ([type isEqualToString:NSFileContentsPboardType] ||
+ [type isEqualToString:NSCreateFileContentsPboardType(
+ SysUTF16ToNSString(dropData_->file_extension))]) {
+ // TODO(viettrungluu: find something which is known to accept
+ // NSFileContentsPboardType to check that this actually works!
+ scoped_nsobject<NSFileWrapper> file_wrapper(
+ [[NSFileWrapper alloc] initRegularFileWithContents:[NSData
+ dataWithBytes:dropData_->file_contents.data()
+ length:dropData_->file_contents.length()]]);
+ [file_wrapper setPreferredFilename:SysUTF8ToNSString(
+ GetFileNameFromDragData(*dropData_).value())];
+ [pboard writeFileWrapper:file_wrapper];
+
+ // TIFF.
+ } else if ([type isEqualToString:NSTIFFPboardType]) {
+ // TODO(viettrungluu): This is a bit odd since we rely on Cocoa to render
+ // our image into a TIFF. This is also suboptimal since this is all done
+ // synchronously. I'm not sure there's much we can easily do about it.
+ scoped_nsobject<NSImage> image(
+ [[NSImage alloc] initWithData:[NSData
+ dataWithBytes:dropData_->file_contents.data()
+ length:dropData_->file_contents.length()]]);
+ [pboard setData:[image TIFFRepresentation] forType:NSTIFFPboardType];
+
+ // Plain text.
+ } else if ([type isEqualToString:NSStringPboardType]) {
+ DCHECK(!dropData_->plain_text.empty());
+ [pboard setString:SysUTF16ToNSString(dropData_->plain_text)
+ forType:NSStringPboardType];
+
+ // Oops!
+ } else {
+ NOTREACHED() << "Asked for a drag pasteboard type we didn't offer.";
+ }
+}
+
+- (NSPoint)convertScreenPoint:(NSPoint)screenPoint {
+ DCHECK([contentsView_ window]);
+ NSPoint basePoint = [[contentsView_ window] convertScreenToBase:screenPoint];
+ return [contentsView_ convertPoint:basePoint fromView:nil];
+}
+
+- (void)startDrag {
+ NSEvent* currentEvent = [NSApp currentEvent];
+
+ // Synthesize an event for dragging, since we can't be sure that
+ // [NSApp currentEvent] will return a valid dragging event.
+ NSWindow* window = [contentsView_ window];
+ NSPoint position = [window mouseLocationOutsideOfEventStream];
+ NSTimeInterval eventTime = [currentEvent timestamp];
+ NSEvent* dragEvent = [NSEvent mouseEventWithType:NSLeftMouseDragged
+ location:position
+ modifierFlags:NSLeftMouseDraggedMask
+ timestamp:eventTime
+ windowNumber:[window windowNumber]
+ context:nil
+ eventNumber:0
+ clickCount:1
+ pressure:1.0];
+
+ if (dragImage_) {
+ position.x -= imageOffset_.x;
+ // Deal with Cocoa's flipped coordinate system.
+ position.y -= [dragImage_.get() size].height - imageOffset_.y;
+ }
+ // Per kwebster, offset arg is ignored, see -_web_DragImageForElement: in
+ // third_party/WebKit/WebKit/mac/Misc/WebNSViewExtras.m.
+ [window dragImage:[self dragImage]
+ at:position
+ offset:NSZeroSize
+ event:dragEvent
+ pasteboard:pasteboard_
+ source:contentsView_
+ slideBack:YES];
+}
+
+- (void)endDragAt:(NSPoint)screenPoint
+ operation:(NSDragOperation)operation {
+ RenderViewHost* rvh = [contentsView_ tabContents]->render_view_host();
+ if (rvh) {
+ rvh->DragSourceSystemDragEnded();
+
+ // Convert |screenPoint| to view coordinates and flip it.
+ NSPoint localPoint = [self convertScreenPoint:screenPoint];
+ NSRect viewFrame = [contentsView_ frame];
+ localPoint.y = viewFrame.size.height - localPoint.y;
+ // Flip |screenPoint|.
+ NSRect screenFrame = [[[contentsView_ window] screen] frame];
+ screenPoint.y = screenFrame.size.height - screenPoint.y;
+
+ rvh->DragSourceEndedAt(localPoint.x, localPoint.y,
+ screenPoint.x, screenPoint.y,
+ static_cast<WebKit::WebDragOperation>(operation));
+ }
+
+ // Make sure the pasteboard owner isn't us.
+ [pasteboard_ declareTypes:[NSArray array] owner:nil];
+}
+
+- (void)moveDragTo:(NSPoint)screenPoint {
+ RenderViewHost* rvh = [contentsView_ tabContents]->render_view_host();
+ if (rvh) {
+ // Convert |screenPoint| to view coordinates and flip it.
+ NSPoint localPoint = [self convertScreenPoint:screenPoint];
+ NSRect viewFrame = [contentsView_ frame];
+ localPoint.y = viewFrame.size.height - localPoint.y;
+ // Flip |screenPoint|.
+ NSRect screenFrame = [[[contentsView_ window] screen] frame];
+ screenPoint.y = screenFrame.size.height - screenPoint.y;
+
+ rvh->DragSourceMovedTo(localPoint.x, localPoint.y,
+ screenPoint.x, screenPoint.y);
+ }
+}
+
+- (NSString*)dragPromisedFileTo:(NSString*)path {
+ // Be extra paranoid; avoid crashing.
+ if (!dropData_.get()) {
+ NOTREACHED() << "No drag-and-drop data available for promised file.";
+ return nil;
+ }
+
+ FilePath fileName = downloadFileName_.empty() ?
+ GetFileNameFromDragData(*dropData_) : downloadFileName_;
+ FilePath filePath(SysNSStringToUTF8(path));
+ filePath = filePath.Append(fileName);
+ FileStream* fileStream =
+ drag_download_util::CreateFileStreamForDrop(&filePath);
+ if (!fileStream)
+ return nil;
+
+ if (downloadURL_.is_valid()) {
+ TabContents* tabContents = [contentsView_ tabContents];
+ scoped_refptr<DragDownloadFile> dragFileDownloader(new DragDownloadFile(
+ filePath,
+ linked_ptr<net::FileStream>(fileStream),
+ downloadURL_,
+ tabContents->GetURL(),
+ tabContents->encoding(),
+ tabContents));
+
+ // The finalizer will take care of closing and deletion.
+ dragFileDownloader->Start(
+ new drag_download_util::PromiseFileFinalizer(dragFileDownloader));
+ } else {
+ // The writer will take care of closing and deletion.
+ g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE,
+ new PromiseWriterTask(*dropData_, fileStream));
+ }
+
+ // Once we've created the file, we should return the file name.
+ return SysUTF8ToNSString(filePath.BaseName().value());
+}
+
+@end // @implementation WebDragSource
+
+
+@implementation WebDragSource (Private)
+
+- (void)fillPasteboard {
+ DCHECK(pasteboard_.get());
+
+ [pasteboard_ declareTypes:[NSArray array] owner:contentsView_];
+
+ // HTML.
+ if (!dropData_->text_html.empty())
+ [pasteboard_ addTypes:[NSArray arrayWithObject:NSHTMLPboardType]
+ owner:contentsView_];
+
+ // URL (and title).
+ if (dropData_->url.is_valid())
+ [pasteboard_ addTypes:[NSArray arrayWithObjects:NSURLPboardType,
+ kNSURLTitlePboardType, nil]
+ owner:contentsView_];
+
+ // File.
+ if (!dropData_->file_contents.empty() ||
+ !dropData_->download_metadata.empty()) {
+ NSString* fileExtension = 0;
+
+ if (dropData_->download_metadata.empty()) {
+ // |dropData_->file_extension| comes with the '.', which we must strip.
+ fileExtension = (dropData_->file_extension.length() > 0) ?
+ SysUTF16ToNSString(dropData_->file_extension.substr(1)) : @"";
+ } else {
+ string16 mimeType;
+ FilePath fileName;
+ if (drag_download_util::ParseDownloadMetadata(
+ dropData_->download_metadata,
+ &mimeType,
+ &fileName,
+ &downloadURL_)) {
+ std::string contentDisposition =
+ "attachment; filename=" + fileName.value();
+ download_util::GenerateFileName(downloadURL_,
+ contentDisposition,
+ std::string(),
+ UTF16ToUTF8(mimeType),
+ &downloadFileName_);
+ fileExtension = SysUTF8ToNSString(downloadFileName_.Extension());
+ }
+ }
+
+ if (fileExtension) {
+ // File contents (with and without specific type), file (HFS) promise,
+ // TIFF.
+ // TODO(viettrungluu): others?
+ [pasteboard_ addTypes:[NSArray arrayWithObjects:
+ NSFileContentsPboardType,
+ NSCreateFileContentsPboardType(fileExtension),
+ NSFilesPromisePboardType,
+ NSTIFFPboardType,
+ nil]
+ owner:contentsView_];
+
+ // For the file promise, we need to specify the extension.
+ [pasteboard_ setPropertyList:[NSArray arrayWithObject:fileExtension]
+ forType:NSFilesPromisePboardType];
+ }
+ }
+
+ // Plain text.
+ if (!dropData_->plain_text.empty())
+ [pasteboard_ addTypes:[NSArray arrayWithObject:NSStringPboardType]
+ owner:contentsView_];
+}
+
+- (NSImage*)dragImage {
+ if (dragImage_)
+ return dragImage_;
+
+ // Default to returning a generic image.
+ return app::mac::GetCachedImageWithName(@"nav.pdf");
+}
+
+@end // @implementation WebDragSource (Private)
diff --git a/chrome/browser/cocoa/web_drop_target.h b/chrome/browser/ui/cocoa/web_drop_target.h
index 7f18ccf..7f18ccf 100644
--- a/chrome/browser/cocoa/web_drop_target.h
+++ b/chrome/browser/ui/cocoa/web_drop_target.h
diff --git a/chrome/browser/ui/cocoa/web_drop_target.mm b/chrome/browser/ui/cocoa/web_drop_target.mm
new file mode 100644
index 0000000..08174b5
--- /dev/null
+++ b/chrome/browser/ui/cocoa/web_drop_target.mm
@@ -0,0 +1,283 @@
+// 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 "chrome/browser/ui/cocoa/web_drop_target.h"
+
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/bookmarks/bookmark_node_data.h"
+#include "chrome/browser/bookmarks/bookmark_pasteboard_helper_mac.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#import "third_party/mozilla/NSPasteboard+Utils.h"
+#include "webkit/glue/webdropdata.h"
+#include "webkit/glue/window_open_disposition.h"
+
+using WebKit::WebDragOperationsMask;
+
+@implementation WebDropTarget
+
+// |contents| is the TabContents representing this tab, used to communicate
+// drag&drop messages to WebCore and handle navigation on a successful drop
+// (if necessary).
+- (id)initWithTabContents:(TabContents*)contents {
+ if ((self = [super init])) {
+ tabContents_ = contents;
+ }
+ return self;
+}
+
+// Call to set whether or not we should allow the drop. Takes effect the
+// next time |-draggingUpdated:| is called.
+- (void)setCurrentOperation: (NSDragOperation)operation {
+ current_operation_ = operation;
+}
+
+// Given a point in window coordinates and a view in that window, return a
+// flipped point in the coordinate system of |view|.
+- (NSPoint)flipWindowPointToView:(const NSPoint&)windowPoint
+ view:(NSView*)view {
+ DCHECK(view);
+ NSPoint viewPoint = [view convertPoint:windowPoint fromView:nil];
+ NSRect viewFrame = [view frame];
+ viewPoint.y = viewFrame.size.height - viewPoint.y;
+ return viewPoint;
+}
+
+// Given a point in window coordinates and a view in that window, return a
+// flipped point in screen coordinates.
+- (NSPoint)flipWindowPointToScreen:(const NSPoint&)windowPoint
+ view:(NSView*)view {
+ DCHECK(view);
+ NSPoint screenPoint = [[view window] convertBaseToScreen:windowPoint];
+ NSScreen* screen = [[view window] screen];
+ NSRect screenFrame = [screen frame];
+ screenPoint.y = screenFrame.size.height - screenPoint.y;
+ return screenPoint;
+}
+
+// Return YES if the drop site only allows drops that would navigate. If this
+// is the case, we don't want to pass messages to the renderer because there's
+// really no point (i.e., there's nothing that cares about the mouse position or
+// entering and exiting). One example is an interstitial page (e.g., safe
+// browsing warning).
+- (BOOL)onlyAllowsNavigation {
+ return tabContents_->showing_interstitial_page();
+}
+
+// Messages to send during the tracking of a drag, ususally upon recieving
+// calls from the view system. Communicates the drag messages to WebCore.
+
+- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info
+ view:(NSView*)view {
+ // Save off the RVH so we can tell if it changes during a drag. If it does,
+ // we need to send a new enter message in draggingUpdated:.
+ currentRVH_ = tabContents_->render_view_host();
+
+ if ([self onlyAllowsNavigation]) {
+ if ([[info draggingPasteboard] containsURLData])
+ return NSDragOperationCopy;
+ return NSDragOperationNone;
+ }
+
+ // If the tab is showing the boomark manager, send BookmarkDrag events
+ RenderViewHostDelegate::BookmarkDrag* dragDelegate =
+ tabContents_->GetBookmarkDragDelegate();
+ BookmarkNodeData dragData;
+ if(dragDelegate && dragData.ReadFromDragClipboard())
+ dragDelegate->OnDragEnter(dragData);
+
+ // Fill out a WebDropData from pasteboard.
+ WebDropData data;
+ [self populateWebDropData:&data fromPasteboard:[info draggingPasteboard]];
+
+ // Create the appropriate mouse locations for WebCore. The draggingLocation
+ // is in window coordinates. Both need to be flipped.
+ NSPoint windowPoint = [info draggingLocation];
+ NSPoint viewPoint = [self flipWindowPointToView:windowPoint view:view];
+ NSPoint screenPoint = [self flipWindowPointToScreen:windowPoint view:view];
+ NSDragOperation mask = [info draggingSourceOperationMask];
+ tabContents_->render_view_host()->DragTargetDragEnter(data,
+ gfx::Point(viewPoint.x, viewPoint.y),
+ gfx::Point(screenPoint.x, screenPoint.y),
+ static_cast<WebDragOperationsMask>(mask));
+
+ // We won't know the true operation (whether the drag is allowed) until we
+ // hear back from the renderer. For now, be optimistic:
+ current_operation_ = NSDragOperationCopy;
+ return current_operation_;
+}
+
+- (void)draggingExited:(id<NSDraggingInfo>)info {
+ DCHECK(currentRVH_);
+ if (currentRVH_ != tabContents_->render_view_host())
+ return;
+
+ // Nothing to do in the interstitial case.
+
+ tabContents_->render_view_host()->DragTargetDragLeave();
+}
+
+- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)info
+ view:(NSView*)view {
+ DCHECK(currentRVH_);
+ if (currentRVH_ != tabContents_->render_view_host())
+ [self draggingEntered:info view:view];
+
+ if ([self onlyAllowsNavigation]) {
+ if ([[info draggingPasteboard] containsURLData])
+ return NSDragOperationCopy;
+ return NSDragOperationNone;
+ }
+
+ // Create the appropriate mouse locations for WebCore. The draggingLocation
+ // is in window coordinates.
+ NSPoint windowPoint = [info draggingLocation];
+ NSPoint viewPoint = [self flipWindowPointToView:windowPoint view:view];
+ NSPoint screenPoint = [self flipWindowPointToScreen:windowPoint view:view];
+ NSDragOperation mask = [info draggingSourceOperationMask];
+ tabContents_->render_view_host()->DragTargetDragOver(
+ gfx::Point(viewPoint.x, viewPoint.y),
+ gfx::Point(screenPoint.x, screenPoint.y),
+ static_cast<WebDragOperationsMask>(mask));
+
+ // If the tab is showing the boomark manager, send BookmarkDrag events
+ RenderViewHostDelegate::BookmarkDrag* dragDelegate =
+ tabContents_->GetBookmarkDragDelegate();
+ BookmarkNodeData dragData;
+ if(dragDelegate && dragData.ReadFromDragClipboard())
+ dragDelegate->OnDragOver(dragData);
+ return current_operation_;
+}
+
+- (BOOL)performDragOperation:(id<NSDraggingInfo>)info
+ view:(NSView*)view {
+ if (currentRVH_ != tabContents_->render_view_host())
+ [self draggingEntered:info view:view];
+
+ // Check if we only allow navigation and navigate to a url on the pasteboard.
+ if ([self onlyAllowsNavigation]) {
+ NSPasteboard* pboard = [info draggingPasteboard];
+ if ([pboard containsURLData]) {
+ GURL url;
+ [self populateURL:&url
+ andTitle:NULL
+ fromPasteboard:pboard
+ convertingFilenames:YES];
+ tabContents_->OpenURL(url, GURL(), CURRENT_TAB,
+ PageTransition::AUTO_BOOKMARK);
+ return YES;
+ }
+ return NO;
+ }
+
+ // If the tab is showing the boomark manager, send BookmarkDrag events
+ RenderViewHostDelegate::BookmarkDrag* dragDelegate =
+ tabContents_->GetBookmarkDragDelegate();
+ BookmarkNodeData dragData;
+ if(dragDelegate && dragData.ReadFromDragClipboard())
+ dragDelegate->OnDrop(dragData);
+
+ currentRVH_ = NULL;
+
+ // Create the appropriate mouse locations for WebCore. The draggingLocation
+ // is in window coordinates. Both need to be flipped.
+ NSPoint windowPoint = [info draggingLocation];
+ NSPoint viewPoint = [self flipWindowPointToView:windowPoint view:view];
+ NSPoint screenPoint = [self flipWindowPointToScreen:windowPoint view:view];
+ tabContents_->render_view_host()->DragTargetDrop(
+ gfx::Point(viewPoint.x, viewPoint.y),
+ gfx::Point(screenPoint.x, screenPoint.y));
+
+ return YES;
+}
+
+// Populate the |url| and |title| with URL data in |pboard|. There may be more
+// than one, but we only handle dropping the first. |url| must not be |NULL|;
+// |title| is an optional parameter. Returns |YES| if URL data was obtained from
+// the pasteboard, |NO| otherwise. If |convertFilenames| is |YES|, the function
+// will also attempt to convert filenames in |pboard| to file URLs.
+- (BOOL)populateURL:(GURL*)url
+ andTitle:(string16*)title
+ fromPasteboard:(NSPasteboard*)pboard
+ convertingFilenames:(BOOL)convertFilenames {
+ DCHECK(url);
+ DCHECK(title);
+
+ // Bail out early if there's no URL data.
+ if (![pboard containsURLData])
+ return NO;
+
+ // |-getURLs:andTitles:convertingFilenames:| will already validate URIs so we
+ // don't need to again. The arrays returned are both of NSString's.
+ NSArray* urls = nil;
+ NSArray* titles = nil;
+ [pboard getURLs:&urls andTitles:&titles convertingFilenames:convertFilenames];
+ DCHECK_EQ([urls count], [titles count]);
+ // It's possible that no URLs were actually provided!
+ if (![urls count])
+ return NO;
+ NSString* urlString = [urls objectAtIndex:0];
+ if ([urlString length]) {
+ // Check again just to make sure to not assign NULL into a std::string,
+ // which throws an exception.
+ const char* utf8Url = [urlString UTF8String];
+ if (utf8Url) {
+ *url = GURL(utf8Url);
+ // Extra paranoia check.
+ if (title && [titles count])
+ *title = base::SysNSStringToUTF16([titles objectAtIndex:0]);
+ }
+ }
+ return YES;
+}
+
+// Given |data|, which should not be nil, fill it in using the contents of the
+// given pasteboard.
+- (void)populateWebDropData:(WebDropData*)data
+ fromPasteboard:(NSPasteboard*)pboard {
+ DCHECK(data);
+ DCHECK(pboard);
+ NSArray* types = [pboard types];
+
+ // Get URL if possible. To avoid exposing file system paths to web content,
+ // filenames in the drag are not converted to file URLs.
+ [self populateURL:&data->url
+ andTitle:&data->url_title
+ fromPasteboard:pboard
+ convertingFilenames:NO];
+
+ // Get plain text.
+ if ([types containsObject:NSStringPboardType]) {
+ data->plain_text =
+ base::SysNSStringToUTF16([pboard stringForType:NSStringPboardType]);
+ }
+
+ // Get HTML. If there's no HTML, try RTF.
+ if ([types containsObject:NSHTMLPboardType]) {
+ data->text_html =
+ base::SysNSStringToUTF16([pboard stringForType:NSHTMLPboardType]);
+ } else if ([types containsObject:NSRTFPboardType]) {
+ NSString* html = [pboard htmlFromRtf];
+ data->text_html = base::SysNSStringToUTF16(html);
+ }
+
+ // 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 isDir = NO;
+ BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:filename
+ isDirectory:&isDir];
+ if (exists && !isDir)
+ data->filenames.push_back(base::SysNSStringToUTF16(filename));
+ }
+ }
+ }
+
+ // TODO(pinkerton): Get file contents. http://crbug.com/34661
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/web_drop_target_unittest.mm b/chrome/browser/ui/cocoa/web_drop_target_unittest.mm
new file mode 100644
index 0000000..0261e89
--- /dev/null
+++ b/chrome/browser/ui/cocoa/web_drop_target_unittest.mm
@@ -0,0 +1,166 @@
+// 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.
+
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/renderer_host/test/test_render_view_host.h"
+#include "chrome/browser/tab_contents/test_tab_contents.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/web_drop_target.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "third_party/mozilla/NSPasteboard+Utils.h"
+#include "webkit/glue/webdropdata.h"
+
+class WebDropTargetTest : public RenderViewHostTestHarness {
+ public:
+ virtual void SetUp() {
+ RenderViewHostTestHarness::SetUp();
+ CocoaTest::BootstrapCocoa();
+ drop_target_.reset([[WebDropTarget alloc] initWithTabContents:contents()]);
+ }
+
+ void PutURLOnPasteboard(NSString* urlString, NSPasteboard* pboard) {
+ [pboard declareTypes:[NSArray arrayWithObject:NSURLPboardType]
+ owner:nil];
+ NSURL* url = [NSURL URLWithString:urlString];
+ EXPECT_TRUE(url);
+ [url writeToPasteboard:pboard];
+ }
+
+ void PutCoreURLAndTitleOnPasteboard(NSString* urlString, NSString* title,
+ NSPasteboard* pboard) {
+ [pboard
+ declareTypes:[NSArray arrayWithObjects:kCorePasteboardFlavorType_url,
+ kCorePasteboardFlavorType_urln,
+ nil]
+ owner:nil];
+ [pboard setString:urlString
+ forType:kCorePasteboardFlavorType_url];
+ [pboard setString:title
+ forType:kCorePasteboardFlavorType_urln];
+ }
+
+ base::mac::ScopedNSAutoreleasePool pool_;
+ scoped_nsobject<WebDropTarget> drop_target_;
+};
+
+// Make sure nothing leaks.
+TEST_F(WebDropTargetTest, Init) {
+ EXPECT_TRUE(drop_target_);
+}
+
+// Test flipping of coordinates given a point in window coordinates.
+TEST_F(WebDropTargetTest, Flip) {
+ NSPoint windowPoint = NSZeroPoint;
+ scoped_nsobject<NSWindow> window([[CocoaTestHelperWindow alloc] init]);
+ NSPoint viewPoint =
+ [drop_target_ flipWindowPointToView:windowPoint
+ view:[window contentView]];
+ NSPoint screenPoint =
+ [drop_target_ flipWindowPointToScreen:windowPoint
+ view:[window contentView]];
+ EXPECT_EQ(0, viewPoint.x);
+ EXPECT_EQ(600, viewPoint.y);
+ EXPECT_EQ(0, screenPoint.x);
+ // We can't put a value on the screen size since everyone will have a
+ // different one.
+ EXPECT_NE(0, screenPoint.y);
+}
+
+TEST_F(WebDropTargetTest, URL) {
+ NSPasteboard* pboard = nil;
+ NSString* url = nil;
+ NSString* title = nil;
+ GURL result_url;
+ string16 result_title;
+
+ // Put a URL on the pasteboard and check it.
+ pboard = [NSPasteboard pasteboardWithUniqueName];
+ url = @"http://www.google.com/";
+ PutURLOnPasteboard(url, pboard);
+ EXPECT_TRUE([drop_target_ populateURL:&result_url
+ andTitle:&result_title
+ fromPasteboard:pboard
+ convertingFilenames:NO]);
+ EXPECT_EQ(base::SysNSStringToUTF8(url), result_url.spec());
+ [pboard releaseGlobally];
+
+ // Put a 'url ' and 'urln' on the pasteboard and check it.
+ pboard = [NSPasteboard pasteboardWithUniqueName];
+ url = @"http://www.google.com/";
+ title = @"Title of Awesomeness!",
+ PutCoreURLAndTitleOnPasteboard(url, title, pboard);
+ EXPECT_TRUE([drop_target_ populateURL:&result_url
+ andTitle:&result_title
+ fromPasteboard:pboard
+ convertingFilenames:NO]);
+ EXPECT_EQ(base::SysNSStringToUTF8(url), result_url.spec());
+ EXPECT_EQ(base::SysNSStringToUTF16(title), result_title);
+ [pboard releaseGlobally];
+
+ // Also check that it passes file:// via 'url '/'urln' properly.
+ pboard = [NSPasteboard pasteboardWithUniqueName];
+ url = @"file:///tmp/dont_delete_me.txt";
+ title = @"very important";
+ PutCoreURLAndTitleOnPasteboard(url, title, pboard);
+ EXPECT_TRUE([drop_target_ populateURL:&result_url
+ andTitle:&result_title
+ fromPasteboard:pboard
+ convertingFilenames:NO]);
+ EXPECT_EQ(base::SysNSStringToUTF8(url), result_url.spec());
+ EXPECT_EQ(base::SysNSStringToUTF16(title), result_title);
+ [pboard releaseGlobally];
+
+ // And javascript:.
+ pboard = [NSPasteboard pasteboardWithUniqueName];
+ url = @"javascript:open('http://www.youtube.com/')";
+ title = @"kill some time";
+ PutCoreURLAndTitleOnPasteboard(url, title, pboard);
+ EXPECT_TRUE([drop_target_ populateURL:&result_url
+ andTitle:&result_title
+ fromPasteboard:pboard
+ convertingFilenames:NO]);
+ EXPECT_EQ(base::SysNSStringToUTF8(url), result_url.spec());
+ EXPECT_EQ(base::SysNSStringToUTF16(title), result_title);
+ [pboard releaseGlobally];
+
+ pboard = [NSPasteboard pasteboardWithUniqueName];
+ url = @"/bin/sh";
+ [pboard declareTypes:[NSArray arrayWithObject:NSFilenamesPboardType]
+ owner:nil];
+ [pboard setPropertyList:[NSArray arrayWithObject:url]
+ forType:NSFilenamesPboardType];
+ EXPECT_FALSE([drop_target_ populateURL:&result_url
+ andTitle:&result_title
+ fromPasteboard:pboard
+ convertingFilenames:NO]);
+ EXPECT_TRUE([drop_target_ populateURL:&result_url
+ andTitle:&result_title
+ fromPasteboard:pboard
+ convertingFilenames:YES]);
+ EXPECT_EQ("file://localhost/bin/sh", result_url.spec());
+ EXPECT_EQ("sh", UTF16ToUTF8(result_title));
+ [pboard releaseGlobally];
+}
+
+TEST_F(WebDropTargetTest, Data) {
+ WebDropData data;
+ NSPasteboard* pboard = [NSPasteboard pasteboardWithUniqueName];
+
+ PutURLOnPasteboard(@"http://www.google.com", pboard);
+ [pboard addTypes:[NSArray arrayWithObjects:NSHTMLPboardType,
+ NSStringPboardType, nil]
+ owner:nil];
+ NSString* htmlString = @"<html><body><b>hi there</b></body></html>";
+ NSString* textString = @"hi there";
+ [pboard setString:htmlString forType:NSHTMLPboardType];
+ [pboard setString:textString forType:NSStringPboardType];
+ [drop_target_ populateWebDropData:&data fromPasteboard:pboard];
+ EXPECT_EQ(data.url.spec(), "http://www.google.com/");
+ EXPECT_EQ(base::SysNSStringToUTF16(textString), data.plain_text);
+ EXPECT_EQ(base::SysNSStringToUTF16(htmlString), data.text_html);
+
+ [pboard releaseGlobally];
+}
diff --git a/chrome/browser/ui/cocoa/window_size_autosaver.h b/chrome/browser/ui/cocoa/window_size_autosaver.h
new file mode 100644
index 0000000..5dbcff4
--- /dev/null
+++ b/chrome/browser/ui/cocoa/window_size_autosaver.h
@@ -0,0 +1,35 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_WINDOW_SIZE_AUTOSAVER_H_
+#define CHROME_BROWSER_UI_COCOA_WINDOW_SIZE_AUTOSAVER_H_
+#pragma once
+
+class PrefService;
+@class NSWindow;
+
+// WindowSizeAutosaver is a helper class that makes it easy to let windows
+// autoremember their position or position and size in a PrefService object.
+// To use this, add a |scoped_nsobject<WindowSizeAutosaver>| to your window
+// controller and initialize it in the window controller's init method, passing
+// a window and an autosave name. The autosaver will register for "window moved"
+// and "window resized" notifications and write the current window state to the
+// prefs service every time they fire. The window's size is automatically
+// restored when the autosaver's |initWithWindow:...| method is called.
+//
+// Note: Your xib file should have "Visible at launch" UNCHECKED, so that the
+// initial repositioning is not visible.
+@interface WindowSizeAutosaver : NSObject {
+ NSWindow* window_; // weak
+ PrefService* prefService_; // weak
+ const char* path_;
+}
+
+- (id)initWithWindow:(NSWindow*)window
+ prefService:(PrefService*)prefs
+ path:(const char*)path;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_WINDOW_SIZE_AUTOSAVER_H_
+
diff --git a/chrome/browser/ui/cocoa/window_size_autosaver.mm b/chrome/browser/ui/cocoa/window_size_autosaver.mm
new file mode 100644
index 0000000..5ca9878
--- /dev/null
+++ b/chrome/browser/ui/cocoa/window_size_autosaver.mm
@@ -0,0 +1,108 @@
+// 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>
+
+#import "chrome/browser/ui/cocoa/window_size_autosaver.h"
+
+#include "chrome/browser/prefs/pref_service.h"
+
+// If the window width stored in the prefs is smaller than this, the size is
+// not restored but instead cleared from the profile -- to protect users from
+// accidentally making their windows very small and then not finding them again.
+const int kMinWindowWidth = 101;
+
+// Minimum restored window height, see |kMinWindowWidth|.
+const int kMinWindowHeight = 17;
+
+@interface WindowSizeAutosaver (Private)
+- (void)save:(NSNotification*)notification;
+- (void)restore;
+@end
+
+@implementation WindowSizeAutosaver
+
+- (id)initWithWindow:(NSWindow*)window
+ prefService:(PrefService*)prefs
+ path:(const char*)path {
+ if ((self = [super init])) {
+ window_ = window;
+ prefService_ = prefs;
+ path_ = path;
+
+ [self restore];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(save:)
+ name:NSWindowDidMoveNotification
+ object:window_];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(save:)
+ name:NSWindowDidResizeNotification
+ object:window_];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+- (void)save:(NSNotification*)notification {
+ DictionaryValue* windowPrefs = prefService_->GetMutableDictionary(path_);
+ NSRect frame = [window_ frame];
+ if ([window_ styleMask] & NSResizableWindowMask) {
+ // Save the origin of the window.
+ windowPrefs->SetInteger("left", NSMinX(frame));
+ windowPrefs->SetInteger("right", NSMaxX(frame));
+ // windows's and linux's profiles have top < bottom due to having their
+ // screen origin in the upper left, while cocoa's is in the lower left. To
+ // keep the top < bottom invariant, store top in bottom and vice versa.
+ windowPrefs->SetInteger("top", NSMinY(frame));
+ windowPrefs->SetInteger("bottom", NSMaxY(frame));
+ } else {
+ // Save the origin of the window.
+ windowPrefs->SetInteger("x", frame.origin.x);
+ windowPrefs->SetInteger("y", frame.origin.y);
+ }
+}
+
+- (void)restore {
+ // Get the positioning information.
+ DictionaryValue* windowPrefs = prefService_->GetMutableDictionary(path_);
+ if ([window_ styleMask] & NSResizableWindowMask) {
+ int x1, x2, y1, y2;
+ if (!windowPrefs->GetInteger("left", &x1) ||
+ !windowPrefs->GetInteger("right", &x2) ||
+ !windowPrefs->GetInteger("top", &y1) ||
+ !windowPrefs->GetInteger("bottom", &y2)) {
+ return;
+ }
+ if (x2 - x1 < kMinWindowWidth || y2 - y1 < kMinWindowHeight) {
+ // Windows should never be very small.
+ windowPrefs->Remove("left", NULL);
+ windowPrefs->Remove("right", NULL);
+ windowPrefs->Remove("top", NULL);
+ windowPrefs->Remove("bottom", NULL);
+ } else {
+ [window_ setFrame:NSMakeRect(x1, y1, x2 - x1, y2 - y1) display:YES];
+
+ // Make sure the window is on-screen.
+ [window_ cascadeTopLeftFromPoint:NSZeroPoint];
+ }
+ } else {
+ int x, y;
+ if (!windowPrefs->GetInteger("x", &x) ||
+ !windowPrefs->GetInteger("y", &y))
+ return; // Nothing stored.
+ // Turn the origin (lower-left) into an upper-left window point.
+ NSPoint upperLeft = NSMakePoint(x, y + NSHeight([window_ frame]));
+ [window_ cascadeTopLeftFromPoint:upperLeft];
+ }
+}
+
+@end
+
diff --git a/chrome/browser/ui/cocoa/window_size_autosaver_unittest.mm b/chrome/browser/ui/cocoa/window_size_autosaver_unittest.mm
new file mode 100644
index 0000000..c3b33ed
--- /dev/null
+++ b/chrome/browser/ui/cocoa/window_size_autosaver_unittest.mm
@@ -0,0 +1,201 @@
+// Copyright (c) 2009 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>
+
+#import "chrome/browser/ui/cocoa/window_size_autosaver.h"
+
+#include "base/scoped_nsobject.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class WindowSizeAutosaverTest : public CocoaTest {
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ path_ = "WindowSizeAutosaverTest";
+ window_ =
+ [[NSWindow alloc] initWithContentRect:NSMakeRect(100, 101, 150, 151)
+ styleMask:NSTitledWindowMask|
+ NSResizableWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO];
+ browser_helper_.profile()->GetPrefs()->RegisterDictionaryPref(path_);
+ }
+
+ virtual void TearDown() {
+ [window_ close];
+ CocoaTest::TearDown();
+ }
+
+ public:
+ BrowserTestHelper browser_helper_;
+ NSWindow* window_;
+ const char* path_;
+};
+
+TEST_F(WindowSizeAutosaverTest, RestoresAndSavesPos) {
+ PrefService* pref = browser_helper_.profile()->GetPrefs();
+ ASSERT_TRUE(pref != NULL);
+
+ // Check to make sure there is no existing pref for window placement.
+ ASSERT_TRUE(pref->GetDictionary(path_) == NULL);
+
+ // Replace the window with one that doesn't have resize controls.
+ [window_ close];
+ window_ =
+ [[NSWindow alloc] initWithContentRect:NSMakeRect(100, 101, 150, 151)
+ styleMask:NSTitledWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO];
+
+ // Ask the window to save its position, then check that a preference
+ // exists. We're technically passing in a pointer to the user prefs
+ // and not the local state prefs, but a PrefService* is a
+ // PrefService*, and this is a unittest.
+
+ {
+ NSRect frame = [window_ frame];
+ // Empty state, shouldn't restore:
+ scoped_nsobject<WindowSizeAutosaver> sizeSaver([[WindowSizeAutosaver alloc]
+ initWithWindow:window_
+ prefService:pref
+ path:path_]);
+ EXPECT_EQ(NSMinX(frame), NSMinX([window_ frame]));
+ EXPECT_EQ(NSMinY(frame), NSMinY([window_ frame]));
+ EXPECT_EQ(NSWidth(frame), NSWidth([window_ frame]));
+ EXPECT_EQ(NSHeight(frame), NSHeight([window_ frame]));
+
+ // Move and resize window, should store position but not size.
+ [window_ setFrame:NSMakeRect(300, 310, 250, 252) display:NO];
+ }
+
+ // Another window movement -- shouldn't be recorded.
+ [window_ setFrame:NSMakeRect(400, 420, 160, 162) display:NO];
+
+ {
+ // Should restore last stored position, but not size.
+ scoped_nsobject<WindowSizeAutosaver> sizeSaver([[WindowSizeAutosaver alloc]
+ initWithWindow:window_
+ prefService:pref
+ path:path_]);
+ EXPECT_EQ(300, NSMinX([window_ frame]));
+ EXPECT_EQ(310, NSMinY([window_ frame]));
+ EXPECT_EQ(160, NSWidth([window_ frame]));
+ EXPECT_EQ(162, NSHeight([window_ frame]));
+ }
+
+ // ...and it should be in the profile, too.
+ EXPECT_TRUE(pref->GetDictionary(path_) != NULL);
+ int x, y;
+ DictionaryValue* windowPref = pref->GetMutableDictionary(path_);
+ EXPECT_FALSE(windowPref->GetInteger("left", &x));
+ EXPECT_FALSE(windowPref->GetInteger("right", &x));
+ EXPECT_FALSE(windowPref->GetInteger("top", &x));
+ EXPECT_FALSE(windowPref->GetInteger("bottom", &x));
+ ASSERT_TRUE(windowPref->GetInteger("x", &x));
+ ASSERT_TRUE(windowPref->GetInteger("y", &y));
+ EXPECT_EQ(300, x);
+ EXPECT_EQ(310, y);
+}
+
+TEST_F(WindowSizeAutosaverTest, RestoresAndSavesRect) {
+ PrefService* pref = browser_helper_.profile()->GetPrefs();
+ ASSERT_TRUE(pref != NULL);
+
+ // Check to make sure there is no existing pref for window placement.
+ ASSERT_TRUE(pref->GetDictionary(path_) == NULL);
+
+ // Ask the window to save its position, then check that a preference
+ // exists. We're technically passing in a pointer to the user prefs
+ // and not the local state prefs, but a PrefService* is a
+ // PrefService*, and this is a unittest.
+
+ {
+ NSRect frame = [window_ frame];
+ // Empty state, shouldn't restore:
+ scoped_nsobject<WindowSizeAutosaver> sizeSaver([[WindowSizeAutosaver alloc]
+ initWithWindow:window_
+ prefService:pref
+ path:path_]);
+ EXPECT_EQ(NSMinX(frame), NSMinX([window_ frame]));
+ EXPECT_EQ(NSMinY(frame), NSMinY([window_ frame]));
+ EXPECT_EQ(NSWidth(frame), NSWidth([window_ frame]));
+ EXPECT_EQ(NSHeight(frame), NSHeight([window_ frame]));
+
+ // Move and resize window, should store
+ [window_ setFrame:NSMakeRect(300, 310, 250, 252) display:NO];
+ }
+
+ // Another window movement -- shouldn't be recorded.
+ [window_ setFrame:NSMakeRect(400, 420, 160, 162) display:NO];
+
+ {
+ // Should restore last stored size
+ scoped_nsobject<WindowSizeAutosaver> sizeSaver([[WindowSizeAutosaver alloc]
+ initWithWindow:window_
+ prefService:pref
+ path:path_]);
+ EXPECT_EQ(300, NSMinX([window_ frame]));
+ EXPECT_EQ(310, NSMinY([window_ frame]));
+ EXPECT_EQ(250, NSWidth([window_ frame]));
+ EXPECT_EQ(252, NSHeight([window_ frame]));
+ }
+
+ // ...and it should be in the profile, too.
+ EXPECT_TRUE(pref->GetDictionary(path_) != NULL);
+ int x1, y1, x2, y2;
+ DictionaryValue* windowPref = pref->GetMutableDictionary(path_);
+ EXPECT_FALSE(windowPref->GetInteger("x", &x1));
+ EXPECT_FALSE(windowPref->GetInteger("y", &x1));
+ ASSERT_TRUE(windowPref->GetInteger("left", &x1));
+ ASSERT_TRUE(windowPref->GetInteger("right", &x2));
+ ASSERT_TRUE(windowPref->GetInteger("top", &y1));
+ ASSERT_TRUE(windowPref->GetInteger("bottom", &y2));
+ EXPECT_EQ(300, x1);
+ EXPECT_EQ(310, y1);
+ EXPECT_EQ(300 + 250, x2);
+ EXPECT_EQ(310 + 252, y2);
+}
+
+// http://crbug.com/39625
+TEST_F(WindowSizeAutosaverTest, DoesNotRestoreButClearsEmptyRect) {
+ PrefService* pref = browser_helper_.profile()->GetPrefs();
+ ASSERT_TRUE(pref != NULL);
+
+ DictionaryValue* windowPref = pref->GetMutableDictionary(path_);
+ windowPref->SetInteger("left", 50);
+ windowPref->SetInteger("right", 50);
+ windowPref->SetInteger("top", 60);
+ windowPref->SetInteger("bottom", 60);
+
+ {
+ // Window rect shouldn't change...
+ NSRect frame = [window_ frame];
+ scoped_nsobject<WindowSizeAutosaver> sizeSaver([[WindowSizeAutosaver alloc]
+ initWithWindow:window_
+ prefService:pref
+ path:path_]);
+ EXPECT_EQ(NSMinX(frame), NSMinX([window_ frame]));
+ EXPECT_EQ(NSMinY(frame), NSMinY([window_ frame]));
+ EXPECT_EQ(NSWidth(frame), NSWidth([window_ frame]));
+ EXPECT_EQ(NSHeight(frame), NSHeight([window_ frame]));
+ }
+
+ // ...and it should be gone from the profile, too.
+ EXPECT_TRUE(pref->GetDictionary(path_) != NULL);
+ int x1, y1, x2, y2;
+ EXPECT_FALSE(windowPref->GetInteger("x", &x1));
+ EXPECT_FALSE(windowPref->GetInteger("y", &x1));
+ ASSERT_FALSE(windowPref->GetInteger("left", &x1));
+ ASSERT_FALSE(windowPref->GetInteger("right", &x2));
+ ASSERT_FALSE(windowPref->GetInteger("top", &y1));
+ ASSERT_FALSE(windowPref->GetInteger("bottom", &y2));
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/wrench_menu_button_cell.h b/chrome/browser/ui/cocoa/wrench_menu_button_cell.h
new file mode 100644
index 0000000..c2d3432
--- /dev/null
+++ b/chrome/browser/ui/cocoa/wrench_menu_button_cell.h
@@ -0,0 +1,19 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_WRENCH_MENU_BUTTON_CELL_H_
+#define CHROME_BROWSER_UI_COCOA_WRENCH_MENU_BUTTON_CELL_H_
+
+#import <Cocoa/Cocoa.h>
+
+// The WrenchMenuButtonCell overrides drawing the background gradient to use
+// the same colors as NSSmallSquareBezelStyle but as a smooth gradient, rather
+// than two blocks of colors. This also uses the blue menu highlight color for
+// the pressed state.
+@interface WrenchMenuButtonCell : NSButtonCell {
+}
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_WRENCH_MENU_BUTTON_CELL_H_
diff --git a/chrome/browser/ui/cocoa/wrench_menu_button_cell.mm b/chrome/browser/ui/cocoa/wrench_menu_button_cell.mm
new file mode 100644
index 0000000..c2a15b7
--- /dev/null
+++ b/chrome/browser/ui/cocoa/wrench_menu_button_cell.mm
@@ -0,0 +1,48 @@
+// 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 "chrome/browser/ui/cocoa/wrench_menu_button_cell.h"
+
+#include "base/scoped_nsobject.h"
+
+@implementation WrenchMenuButtonCell
+
+- (void)drawBezelWithFrame:(NSRect)frame inView:(NSView*)controlView {
+ [NSGraphicsContext saveGraphicsState];
+
+ // Inset the rect to match the appearance of the layout of interface builder.
+ // The bounding rect of buttons is actually larger than the display rect shown
+ // there.
+ frame = NSInsetRect(frame, 0.0, 1.0);
+
+ // Stroking the rect gives a weak stroke. Filling and insetting gives a
+ // strong, un-anti-aliased border.
+ [[NSColor colorWithDeviceWhite:0.663 alpha:1.0] set];
+ NSRectFill(frame);
+ frame = NSInsetRect(frame, 1.0, 1.0);
+
+ // The default state should be a subtle gray gradient.
+ if (![self isHighlighted]) {
+ NSColor* end = [NSColor colorWithDeviceWhite:0.922 alpha:1.0];
+ scoped_nsobject<NSGradient> gradient(
+ [[NSGradient alloc] initWithStartingColor:[NSColor whiteColor]
+ endingColor:end]);
+ [gradient drawInRect:frame angle:90.0];
+ } else {
+ // |+selectedMenuItemColor| appears to be a gradient, so just filling the
+ // rect with that color produces the desired effect.
+ [[NSColor selectedMenuItemColor] set];
+ NSRectFill(frame);
+ }
+
+ [NSGraphicsContext restoreGraphicsState];
+}
+
+- (NSBackgroundStyle)interiorBackgroundStyle {
+ if ([self isHighlighted])
+ return NSBackgroundStyleDark;
+ return [super interiorBackgroundStyle];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/wrench_menu_button_cell_unittest.mm b/chrome/browser/ui/cocoa/wrench_menu_button_cell_unittest.mm
new file mode 100644
index 0000000..7ab1588
--- /dev/null
+++ b/chrome/browser/ui/cocoa/wrench_menu_button_cell_unittest.mm
@@ -0,0 +1,51 @@
+// 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.
+
+#include "base/scoped_nsobject.h"
+#include "chrome/app/chrome_command_ids.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/wrench_menu_button_cell.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+@interface TestWrenchMenuButton : NSButton
+@end
+@implementation TestWrenchMenuButton
++ (Class)cellClass {
+ return [WrenchMenuButtonCell class];
+}
+@end
+
+namespace {
+
+class WrenchMenuButtonCellTest : public CocoaTest {
+ public:
+ void SetUp() {
+ CocoaTest::SetUp();
+
+ NSRect frame = NSMakeRect(10, 10, 50, 19);
+ button_.reset([[TestWrenchMenuButton alloc] initWithFrame:frame]);
+ [button_ setBezelStyle:NSSmallSquareBezelStyle];
+ [[button_ cell] setControlSize:NSSmallControlSize];
+ [button_ setTitle:@"Allays"];
+ [button_ setButtonType:NSMomentaryPushInButton];
+ }
+
+ scoped_nsobject<NSButton> button_;
+};
+
+TEST_F(WrenchMenuButtonCellTest, Draw) {
+ ASSERT_TRUE(button_.get());
+ [[test_window() contentView] addSubview:button_.get()];
+ [button_ setNeedsDisplay:YES];
+}
+
+TEST_F(WrenchMenuButtonCellTest, DrawHighlight) {
+ ASSERT_TRUE(button_.get());
+ [[test_window() contentView] addSubview:button_.get()];
+ [button_ highlight:YES];
+ [button_ setNeedsDisplay:YES];
+}
+
+} // namespace
diff --git a/chrome/browser/ui/cocoa/wrench_menu_controller.h b/chrome/browser/ui/cocoa/wrench_menu_controller.h
new file mode 100644
index 0000000..f2dea7a
--- /dev/null
+++ b/chrome/browser/ui/cocoa/wrench_menu_controller.h
@@ -0,0 +1,72 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_WRENCH_MENU_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_WRENCH_MENU_CONTROLLER_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/mac/cocoa_protocols.h"
+#include "base/scoped_ptr.h"
+#import "chrome/browser/ui/cocoa/menu_controller.h"
+
+@class MenuTrackedRootView;
+@class ToolbarController;
+class WrenchMenuModel;
+
+namespace WrenchMenuControllerInternal {
+class ZoomLevelObserver;
+} // namespace WrenchMenuControllerInternal
+
+// The Wrench menu has a creative layout, with buttons in menu items. There is
+// a cross-platform model for this special menu, but on the Mac it's easier to
+// get spacing and alignment precisely right using a NIB. To do that, we
+// subclass the generic MenuController implementation and special-case the two
+// items that require specific layout and load them from the NIB.
+//
+// This object is instantiated in Toolbar.xib and is configured by the
+// ToolbarController.
+@interface WrenchMenuController : MenuController<NSMenuDelegate> {
+ IBOutlet MenuTrackedRootView* editItem_;
+ IBOutlet NSButton* editCut_;
+ IBOutlet NSButton* editCopy_;
+ IBOutlet NSButton* editPaste_;
+
+ IBOutlet MenuTrackedRootView* zoomItem_;
+ IBOutlet NSButton* zoomPlus_;
+ IBOutlet NSButton* zoomDisplay_;
+ IBOutlet NSButton* zoomMinus_;
+ IBOutlet NSButton* zoomFullScreen_;
+
+ scoped_ptr<WrenchMenuControllerInternal::ZoomLevelObserver> observer_;
+}
+
+// Designated initializer; called within the NIB.
+- (id)init;
+
+// Used to dispatch commands from the Wrench menu. The custom items within the
+// menu cannot be hooked up directly to First Responder because the window in
+// which the controls reside is not the BrowserWindowController, but a
+// NSCarbonMenuWindow; this screws up the typical |-commandDispatch:| system.
+- (IBAction)dispatchWrenchMenuCommand:(id)sender;
+
+// Returns the weak reference to the WrenchMenuModel.
+- (WrenchMenuModel*)wrenchMenuModel;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////
+
+@interface WrenchMenuController (UnitTesting)
+// |-dispatchWrenchMenuCommand:| calls this after it has determined the tag of
+// the sender. The default implementation executes the command on the outermost
+// run loop using |-performSelector...withDelay:|. This is not desirable in
+// unit tests because it's hard to test around run loops in a deterministic
+// manner. To avoid those headaches, tests should provide an alternative
+// implementation.
+- (void)dispatchCommandInternal:(NSInteger)tag;
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_WRENCH_MENU_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/wrench_menu_controller.mm b/chrome/browser/ui/cocoa/wrench_menu_controller.mm
new file mode 100644
index 0000000..fcbada6
--- /dev/null
+++ b/chrome/browser/ui/cocoa/wrench_menu_controller.mm
@@ -0,0 +1,220 @@
+// 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 "chrome/browser/ui/cocoa/wrench_menu_controller.h"
+
+#include "app/l10n_util.h"
+#include "app/menus/menu_model.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/background_page_tracker.h"
+#import "chrome/browser/ui/cocoa/menu_tracked_root_view.h"
+#import "chrome/browser/ui/cocoa/toolbar_controller.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/toolbar/wrench_menu_model.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+
+@interface WrenchMenuController (Private)
+- (void)adjustPositioning;
+- (void)performCommandDispatch:(NSNumber*)tag;
+- (NSButton*)zoomDisplay;
+@end
+
+namespace WrenchMenuControllerInternal {
+
+class ZoomLevelObserver : public NotificationObserver {
+ public:
+ explicit ZoomLevelObserver(WrenchMenuController* controller)
+ : controller_(controller) {
+ registrar_.Add(this, NotificationType::ZOOM_LEVEL_CHANGED,
+ NotificationService::AllSources());
+ }
+
+ void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK_EQ(type.value, NotificationType::ZOOM_LEVEL_CHANGED);
+ WrenchMenuModel* wrenchMenuModel = [controller_ wrenchMenuModel];
+ wrenchMenuModel->UpdateZoomControls();
+ const string16 level =
+ wrenchMenuModel->GetLabelForCommandId(IDC_ZOOM_PERCENT_DISPLAY);
+ [[controller_ zoomDisplay] setTitle:SysUTF16ToNSString(level)];
+ }
+
+ private:
+ NotificationRegistrar registrar_;
+ WrenchMenuController* controller_; // Weak; owns this.
+};
+
+} // namespace WrenchMenuControllerInternal
+
+@implementation WrenchMenuController
+
+- (id)init {
+ if ((self = [super init])) {
+ observer_.reset(new WrenchMenuControllerInternal::ZoomLevelObserver(self));
+ }
+ return self;
+}
+
+- (void)addItemToMenu:(NSMenu*)menu
+ atIndex:(NSInteger)index
+ fromModel:(menus::MenuModel*)model
+ modelIndex:(int)modelIndex {
+ // Non-button item types should be built as normal items.
+ menus::MenuModel::ItemType type = model->GetTypeAt(modelIndex);
+ if (type != menus::MenuModel::TYPE_BUTTON_ITEM) {
+ [super addItemToMenu:menu
+ atIndex:index
+ fromModel:model
+ modelIndex:modelIndex];
+ return;
+ }
+
+ // Handle the special-cased menu items.
+ int command_id = model->GetCommandIdAt(modelIndex);
+ scoped_nsobject<NSMenuItem> customItem(
+ [[NSMenuItem alloc] initWithTitle:@""
+ action:nil
+ keyEquivalent:@""]);
+ switch (command_id) {
+ case IDC_EDIT_MENU:
+ DCHECK(editItem_);
+ [customItem setView:editItem_];
+ [editItem_ setMenuItem:customItem];
+ break;
+ case IDC_ZOOM_MENU:
+ DCHECK(zoomItem_);
+ [customItem setView:zoomItem_];
+ [zoomItem_ setMenuItem:customItem];
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ [self adjustPositioning];
+ [menu insertItem:customItem.get() atIndex:index];
+}
+
+- (NSMenu*)menu {
+ NSMenu* menu = [super menu];
+ if (![menu delegate]) {
+ [menu setDelegate:self];
+ }
+ return menu;
+}
+
+- (void)menuWillOpen:(NSMenu*)menu {
+ NSString* title = base::SysUTF16ToNSString(
+ [self wrenchMenuModel]->GetLabelForCommandId(IDC_ZOOM_PERCENT_DISPLAY));
+ [[zoomItem_ viewWithTag:IDC_ZOOM_PERCENT_DISPLAY] setTitle:title];
+
+ NSImage* icon = [self wrenchMenuModel]->browser()->window()->IsFullscreen() ?
+ [NSImage imageNamed:NSImageNameExitFullScreenTemplate] :
+ [NSImage imageNamed:NSImageNameEnterFullScreenTemplate];
+ [zoomFullScreen_ setImage:icon];
+}
+
+- (void)menuDidClose:(NSMenu*)menu {
+ // When the menu is closed, acknowledge the background pages so the badges go
+ // away.
+ BackgroundPageTracker::GetInstance()->AcknowledgeBackgroundPages();
+}
+
+// Used to dispatch commands from the Wrench menu. The custom items within the
+// menu cannot be hooked up directly to First Responder because the window in
+// which the controls reside is not the BrowserWindowController, but a
+// NSCarbonMenuWindow; this screws up the typical |-commandDispatch:| system.
+- (IBAction)dispatchWrenchMenuCommand:(id)sender {
+ NSInteger tag = [sender tag];
+ if (sender == zoomPlus_ || sender == zoomMinus_) {
+ // Do a direct dispatch rather than scheduling on the outermost run loop,
+ // which would not get hit until after the menu had closed.
+ [self performCommandDispatch:[NSNumber numberWithInt:tag]];
+
+ // The zoom buttons should not close the menu if opened sticky.
+ if ([sender respondsToSelector:@selector(isTracking)] &&
+ [sender performSelector:@selector(isTracking)]) {
+ [menu_ cancelTracking];
+ }
+ } else {
+ // The custom views within the Wrench menu are abnormal and keep the menu
+ // open after a target-action. Close the menu manually.
+ [menu_ cancelTracking];
+ [self dispatchCommandInternal:tag];
+ }
+}
+
+- (void)dispatchCommandInternal:(NSInteger)tag {
+ // Executing certain commands from the nested run loop of the menu can lead
+ // to wonky behavior (e.g. http://crbug.com/49716). To avoid this, schedule
+ // the dispatch on the outermost run loop.
+ [self performSelector:@selector(performCommandDispatch:)
+ withObject:[NSNumber numberWithInt:tag]
+ afterDelay:0.0];
+}
+
+// Used to perform the actual dispatch on the outermost runloop.
+- (void)performCommandDispatch:(NSNumber*)tag {
+ [self wrenchMenuModel]->ExecuteCommand([tag intValue]);
+}
+
+- (WrenchMenuModel*)wrenchMenuModel {
+ return static_cast<WrenchMenuModel*>(model_);
+}
+
+// Fit the localized strings into the Cut/Copy/Paste control, then resize the
+// whole menu item accordingly.
+- (void)adjustPositioning {
+ const CGFloat kButtonPadding = 12;
+ CGFloat delta = 0;
+
+ // Go through the three buttons from right-to-left, adjusting the size to fit
+ // the localized strings while keeping them all aligned on their horizontal
+ // edges.
+ const size_t kAdjustViewCount = 3;
+ NSButton* views[kAdjustViewCount] = { editPaste_, editCopy_, editCut_ };
+ for (size_t i = 0; i < kAdjustViewCount; ++i) {
+ NSButton* button = views[i];
+ CGFloat originalWidth = NSWidth([button frame]);
+
+ // Do not let |-sizeToFit| change the height of the button.
+ NSSize size = [button frame].size;
+ [button sizeToFit];
+ size.width = [button frame].size.width + kButtonPadding;
+ [button setFrameSize:size];
+
+ CGFloat newWidth = size.width;
+ delta += newWidth - originalWidth;
+
+ NSRect frame = [button frame];
+ frame.origin.x -= delta;
+ [button setFrame:frame];
+ }
+
+ // Resize the menu item by the total amound the buttons changed so that the
+ // spacing between the buttons and the title remains the same.
+ NSRect itemFrame = [editItem_ frame];
+ itemFrame.size.width += delta;
+ [editItem_ setFrame:itemFrame];
+
+ // Also resize the superview of the buttons, which is an NSView used to slide
+ // when the item title is too big and GTM resizes it.
+ NSRect parentFrame = [[editCut_ superview] frame];
+ parentFrame.size.width += delta;
+ parentFrame.origin.x -= delta;
+ [[editCut_ superview] setFrame:parentFrame];
+}
+
+- (NSButton*)zoomDisplay {
+ return zoomDisplay_;
+}
+
+@end // @implementation WrenchMenuController
diff --git a/chrome/browser/ui/cocoa/wrench_menu_controller_unittest.mm b/chrome/browser/ui/cocoa/wrench_menu_controller_unittest.mm
new file mode 100644
index 0000000..42be865
--- /dev/null
+++ b/chrome/browser/ui/cocoa/wrench_menu_controller_unittest.mm
@@ -0,0 +1,84 @@
+// 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.
+
+#include "base/scoped_nsobject.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/ui/cocoa/browser_test_helper.h"
+#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/toolbar_controller.h"
+#import "chrome/browser/ui/cocoa/wrench_menu_controller.h"
+#import "chrome/browser/ui/cocoa/view_resizer_pong.h"
+#include "chrome/browser/ui/toolbar/wrench_menu_model.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+// Override to avoid dealing with run loops in the testing environment.
+@implementation WrenchMenuController (UnitTesting)
+- (void)dispatchCommandInternal:(NSInteger)tag {
+ [self wrenchMenuModel]->ExecuteCommand(tag);
+}
+@end
+
+
+namespace {
+
+class MockWrenchMenuModel : public WrenchMenuModel {
+ public:
+ MockWrenchMenuModel() : WrenchMenuModel() {}
+ ~MockWrenchMenuModel() {
+ // This dirty, ugly hack gets around a bug in the test. In
+ // ~WrenchMenuModel(), there's a call to TabstripModel::RemoveObserver(this)
+ // which mysteriously leads to this crash: http://crbug.com/49206 . It
+ // seems that the vector of observers is getting hosed somewhere between
+ // |-[ToolbarController dealloc]| and ~MockWrenchMenuModel(). This line
+ // short-circuits the parent destructor to avoid this crash.
+ tabstrip_model_ = NULL;
+ }
+ MOCK_METHOD1(ExecuteCommand, void(int command_id));
+};
+
+class WrenchMenuControllerTest : public CocoaTest {
+ public:
+ void SetUp() {
+ Browser* browser = helper_.browser();
+ resize_delegate_.reset([[ViewResizerPong alloc] init]);
+ toolbar_controller_.reset(
+ [[ToolbarController alloc] initWithModel:browser->toolbar_model()
+ commands:browser->command_updater()
+ profile:helper_.profile()
+ browser:browser
+ resizeDelegate:resize_delegate_.get()]);
+ EXPECT_TRUE([toolbar_controller_ view]);
+ NSView* parent = [test_window() contentView];
+ [parent addSubview:[toolbar_controller_ view]];
+ }
+
+ WrenchMenuController* controller() {
+ return [toolbar_controller_ wrenchMenuController];
+ }
+
+ BrowserTestHelper helper_;
+ scoped_nsobject<ViewResizerPong> resize_delegate_;
+ MockWrenchMenuModel fake_model_;
+ scoped_nsobject<ToolbarController> toolbar_controller_;
+};
+
+TEST_F(WrenchMenuControllerTest, Initialized) {
+ EXPECT_TRUE([controller() menu]);
+ EXPECT_GE([[controller() menu] numberOfItems], 5);
+}
+
+TEST_F(WrenchMenuControllerTest, DispatchSimple) {
+ scoped_nsobject<NSButton> button([[NSButton alloc] init]);
+ [button setTag:IDC_ZOOM_PLUS];
+
+ // Set fake model to test dispatching.
+ EXPECT_CALL(fake_model_, ExecuteCommand(IDC_ZOOM_PLUS));
+ [controller() setModel:&fake_model_];
+
+ [controller() dispatchWrenchMenuCommand:button.get()];
+}
+
+} // namespace
diff --git a/chrome/browser/ui/find_bar/find_backend_unittest.cc b/chrome/browser/ui/find_bar/find_backend_unittest.cc
new file mode 100644
index 0000000..c4ec58b
--- /dev/null
+++ b/chrome/browser/ui/find_bar/find_backend_unittest.cc
@@ -0,0 +1,76 @@
+// Copyright (c) 2009 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/string16.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/renderer_host/test/test_render_view_host.h"
+#include "chrome/browser/tab_contents/test_tab_contents.h"
+#include "chrome/browser/ui/find_bar/find_bar_state.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/test/testing_profile.h"
+
+typedef RenderViewHostTestHarness FindBackendTest;
+
+namespace {
+
+string16 FindPrepopulateText(TabContents* contents) {
+ return FindBarState::GetLastPrepopulateText(contents->profile());
+}
+
+} // end namespace
+
+// This test takes two TabContents objects, searches in both of them and
+// tests the internal state for find_text and find_prepopulate_text.
+TEST_F(FindBackendTest, InternalState) {
+ // Initial state for the TabContents is blank strings.
+ EXPECT_EQ(string16(), FindPrepopulateText(contents()));
+ EXPECT_EQ(string16(), contents()->find_text());
+
+ // Get another TabContents object ready.
+ TestTabContents contents2(profile_.get(), NULL);
+
+ // No search has still been issued, strings should be blank.
+ EXPECT_EQ(string16(), FindPrepopulateText(contents()));
+ EXPECT_EQ(string16(), contents()->find_text());
+ EXPECT_EQ(string16(), FindPrepopulateText(&contents2));
+ EXPECT_EQ(string16(), contents2.find_text());
+
+ string16 search_term1 = ASCIIToUTF16(" I had a 401K ");
+ string16 search_term2 = ASCIIToUTF16(" but the economy ");
+ string16 search_term3 = ASCIIToUTF16(" eated it. ");
+
+ // Start searching in the first TabContents, searching forwards but not case
+ // sensitive (as indicated by the last two params).
+ contents()->StartFinding(search_term1, true, false);
+
+ // Pre-populate string should always match between the two, but find_text
+ // should not.
+ EXPECT_EQ(search_term1, FindPrepopulateText(contents()));
+ EXPECT_EQ(search_term1, contents()->find_text());
+ EXPECT_EQ(search_term1, FindPrepopulateText(&contents2));
+ EXPECT_EQ(string16(), contents2.find_text());
+
+ // Now search in the other TabContents, searching forwards but not case
+ // sensitive (as indicated by the last two params).
+ contents2.StartFinding(search_term2, true, false);
+
+ // Again, pre-populate string should always match between the two, but
+ // find_text should not.
+ EXPECT_EQ(search_term2, FindPrepopulateText(contents()));
+ EXPECT_EQ(search_term1, contents()->find_text());
+ EXPECT_EQ(search_term2, FindPrepopulateText(&contents2));
+ EXPECT_EQ(search_term2, contents2.find_text());
+
+ // Search again in the first TabContents, searching forwards but not case
+ // sensitive (as indicated by the last two params).
+ contents()->StartFinding(search_term3, true, false);
+
+ // Once more, pre-populate string should always match between the two, but
+ // find_text should not.
+ EXPECT_EQ(search_term3, FindPrepopulateText(contents()));
+ EXPECT_EQ(search_term3, contents()->find_text());
+ EXPECT_EQ(search_term3, FindPrepopulateText(&contents2));
+ EXPECT_EQ(search_term2, contents2.find_text());
+}
diff --git a/chrome/browser/ui/find_bar/find_bar.h b/chrome/browser/ui/find_bar/find_bar.h
new file mode 100644
index 0000000..66d6618
--- /dev/null
+++ b/chrome/browser/ui/find_bar/find_bar.h
@@ -0,0 +1,101 @@
+// 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.
+//
+// This is an interface for the platform specific FindBar. It is responsible
+// for drawing the FindBar bar on the platform and is owned by the
+// FindBarController.
+
+#ifndef CHROME_BROWSER_UI_FIND_BAR_FIND_BAR_H_
+#define CHROME_BROWSER_UI_FIND_BAR_FIND_BAR_H_
+#pragma once
+
+#include "base/string16.h"
+#include "gfx/rect.h"
+
+class FindBarController;
+class FindBarTesting;
+class FindNotificationDetails;
+
+class FindBar {
+ public:
+ virtual ~FindBar() { }
+
+ // Accessor and setter for the FindBarController.
+ virtual FindBarController* GetFindBarController() const = 0;
+ virtual void SetFindBarController(
+ FindBarController* find_bar_controller) = 0;
+
+ // Shows the find bar. Any previous search string will again be visible.
+ // If |animate| is true, we try to slide the find bar in.
+ virtual void Show(bool animate) = 0;
+
+ // Hide the find bar. If |animate| is true, we try to slide the find bar
+ // away.
+ virtual void Hide(bool animate) = 0;
+
+ // Restore the selected text in the find box and focus it.
+ virtual void SetFocusAndSelection() = 0;
+
+ // Clear the text in the find box.
+ virtual void ClearResults(const FindNotificationDetails& results) = 0;
+
+ // Stop the animation.
+ virtual void StopAnimation() = 0;
+
+ // If the find bar obscures the search results we need to move the window. To
+ // do that we need to know what is selected on the page. We simply calculate
+ // where it would be if we place it on the left of the selection and if it
+ // doesn't fit on the screen we try the right side. The parameter
+ // |selection_rect| is expected to have coordinates relative to the top of
+ // the web page area. If |no_redraw| is true, the window will be moved without
+ // redrawing siblings.
+ virtual void MoveWindowIfNecessary(const gfx::Rect& selection_rect,
+ bool no_redraw) = 0;
+
+ // Set the text in the find box.
+ virtual void SetFindText(const string16& find_text) = 0;
+
+ // Updates the FindBar with the find result details contained within the
+ // specified |result|.
+ virtual void UpdateUIForFindResult(const FindNotificationDetails& result,
+ const string16& find_text) = 0;
+
+ // No match was found; play an audible alert.
+ virtual void AudibleAlert() = 0;
+
+ virtual bool IsFindBarVisible() = 0;
+
+ // Upon dismissing the window, restore focus to the last focused view which is
+ // not FindBarView or any of its children.
+ virtual void RestoreSavedFocus() = 0;
+
+ // Returns a pointer to the testing interface to the FindBar, or NULL
+ // if there is none.
+ virtual FindBarTesting* GetFindBarTesting() = 0;
+};
+
+class FindBarTesting {
+ public:
+ virtual ~FindBarTesting() { }
+
+ // Computes the location of the find bar and whether it is fully visible in
+ // its parent window. The return value indicates if the window is visible at
+ // all. Both out arguments are optional.
+ //
+ // This is used for UI tests of the find bar. If the find bar is not currently
+ // shown (return value of false), the out params will be {(0, 0), false}.
+ virtual bool GetFindBarWindowInfo(gfx::Point* position,
+ bool* fully_visible) = 0;
+
+ // Gets the search string currently visible in the Find box.
+ virtual string16 GetFindText() = 0;
+
+ // Gets the search string currently selected in the Find box.
+ virtual string16 GetFindSelectedText() = 0;
+
+ // Gets the match count text (ie. 1 of 3) visible in the Find box.
+ virtual string16 GetMatchCountText() = 0;
+};
+
+#endif // CHROME_BROWSER_UI_FIND_BAR_FIND_BAR_H_
diff --git a/chrome/browser/ui/find_bar/find_bar_controller.cc b/chrome/browser/ui/find_bar/find_bar_controller.cc
new file mode 100644
index 0000000..4f637e8
--- /dev/null
+++ b/chrome/browser/ui/find_bar/find_bar_controller.cc
@@ -0,0 +1,228 @@
+// 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.
+
+#include "chrome/browser/ui/find_bar/find_bar_controller.h"
+
+#include <algorithm>
+
+#include "base/i18n/rtl.h"
+#include "build/build_config.h"
+#include "chrome/browser/tab_contents/navigation_entry.h"
+#include "chrome/browser/ui/find_bar/find_bar.h"
+#include "chrome/browser/ui/find_bar/find_bar_state.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
+#include "gfx/rect.h"
+
+// The minimum space between the FindInPage window and the search result.
+static const int kMinFindWndDistanceFromSelection = 5;
+
+FindBarController::FindBarController(FindBar* find_bar)
+ : find_bar_(find_bar),
+ tab_contents_(NULL),
+ last_reported_matchcount_(0) {
+}
+
+FindBarController::~FindBarController() {
+ DCHECK(!tab_contents_);
+}
+
+void FindBarController::Show() {
+ // Only show the animation if we're not already showing a find bar for the
+ // selected TabContents.
+ if (!tab_contents_->find_ui_active()) {
+ MaybeSetPrepopulateText();
+
+ tab_contents_->set_find_ui_active(true);
+ find_bar_->Show(true);
+ }
+ find_bar_->SetFocusAndSelection();
+}
+
+void FindBarController::EndFindSession(SelectionAction action) {
+ find_bar_->Hide(true);
+
+ // |tab_contents_| can be NULL for a number of reasons, for example when the
+ // tab is closing. We must guard against that case. See issue 8030.
+ if (tab_contents_) {
+ // When we hide the window, we need to notify the renderer that we are done
+ // for now, so that we can abort the scoping effort and clear all the
+ // tickmarks and highlighting.
+ tab_contents_->StopFinding(action);
+
+ if (action != kKeepSelection)
+ find_bar_->ClearResults(tab_contents_->find_result());
+
+ // When we get dismissed we restore the focus to where it belongs.
+ find_bar_->RestoreSavedFocus();
+ }
+}
+
+void FindBarController::ChangeTabContents(TabContents* contents) {
+ if (tab_contents_) {
+ registrar_.RemoveAll();
+ find_bar_->StopAnimation();
+ }
+
+ tab_contents_ = contents;
+
+ // Hide any visible find window from the previous tab if NULL |tab_contents|
+ // is passed in or if the find UI is not active in the new tab.
+ if (find_bar_->IsFindBarVisible() &&
+ (!tab_contents_ || !tab_contents_->find_ui_active())) {
+ find_bar_->Hide(false);
+ }
+
+ if (!tab_contents_)
+ return;
+
+ registrar_.Add(this, NotificationType::FIND_RESULT_AVAILABLE,
+ Source<TabContents>(tab_contents_));
+ registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
+ Source<NavigationController>(&tab_contents_->controller()));
+
+ MaybeSetPrepopulateText();
+
+ if (tab_contents_->find_ui_active()) {
+ // A tab with a visible find bar just got selected and we need to show the
+ // find bar but without animation since it was already animated into its
+ // visible state. We also want to reset the window location so that
+ // we don't surprise the user by popping up to the left for no apparent
+ // reason.
+ find_bar_->Show(false);
+ }
+
+ UpdateFindBarForCurrentResult();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// FindBarHost, NotificationObserver implementation:
+
+void FindBarController::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NotificationType::FIND_RESULT_AVAILABLE) {
+ // Don't update for notifications from TabContentses other than the one we
+ // are actively tracking.
+ if (Source<TabContents>(source).ptr() == tab_contents_) {
+ UpdateFindBarForCurrentResult();
+ if (tab_contents_->find_result().final_update() &&
+ tab_contents_->find_result().number_of_matches() == 0) {
+ const string16& last_search = tab_contents_->previous_find_text();
+ const string16& current_search = tab_contents_->find_text();
+ if (last_search.find(current_search) != 0)
+ find_bar_->AudibleAlert();
+ }
+ }
+ } else if (type == NotificationType::NAV_ENTRY_COMMITTED) {
+ NavigationController* source_controller =
+ Source<NavigationController>(source).ptr();
+ if (source_controller == &tab_contents_->controller()) {
+ NavigationController::LoadCommittedDetails* commit_details =
+ Details<NavigationController::LoadCommittedDetails>(details).ptr();
+ PageTransition::Type transition_type =
+ commit_details->entry->transition_type();
+ // We hide the FindInPage window when the user navigates away, except on
+ // reload.
+ if (find_bar_->IsFindBarVisible()) {
+ if (PageTransition::StripQualifier(transition_type) !=
+ PageTransition::RELOAD) {
+ EndFindSession(kKeepSelection);
+ } else {
+ // On Reload we want to make sure FindNext is converted to a full Find
+ // to make sure highlights for inactive matches are repainted.
+ tab_contents_->set_find_op_aborted(true);
+ }
+ }
+ }
+ }
+}
+
+// static
+gfx::Rect FindBarController::GetLocationForFindbarView(
+ gfx::Rect view_location,
+ const gfx::Rect& dialog_bounds,
+ const gfx::Rect& avoid_overlapping_rect) {
+ if (base::i18n::IsRTL()) {
+ int boundary = dialog_bounds.width() - view_location.width();
+ view_location.set_x(std::min(view_location.x(), boundary));
+ } else {
+ view_location.set_x(std::max(view_location.x(), dialog_bounds.x()));
+ }
+
+ gfx::Rect new_pos = view_location;
+
+ // If the selection rectangle intersects the current position on screen then
+ // we try to move our dialog to the left (right for RTL) of the selection
+ // rectangle.
+ if (!avoid_overlapping_rect.IsEmpty() &&
+ avoid_overlapping_rect.Intersects(new_pos)) {
+ if (base::i18n::IsRTL()) {
+ new_pos.set_x(avoid_overlapping_rect.x() +
+ avoid_overlapping_rect.width() +
+ (2 * kMinFindWndDistanceFromSelection));
+
+ // If we moved it off-screen to the right, we won't move it at all.
+ if (new_pos.x() + new_pos.width() > dialog_bounds.width())
+ new_pos = view_location; // Reset.
+ } else {
+ new_pos.set_x(avoid_overlapping_rect.x() - new_pos.width() -
+ kMinFindWndDistanceFromSelection);
+
+ // If we moved it off-screen to the left, we won't move it at all.
+ if (new_pos.x() < 0)
+ new_pos = view_location; // Reset.
+ }
+ }
+
+ return new_pos;
+}
+
+void FindBarController::UpdateFindBarForCurrentResult() {
+ const FindNotificationDetails& find_result = tab_contents_->find_result();
+
+ // Avoid bug 894389: When a new search starts (and finds something) it reports
+ // an interim match count result of 1 before the scoping effort starts. This
+ // is to provide feedback as early as possible that we will find something.
+ // As you add letters to the search term, this creates a flashing effect when
+ // we briefly show "1 of 1" matches because there is a slight delay until
+ // the scoping effort starts updating the match count. We avoid this flash by
+ // ignoring interim results of 1 if we already have a positive number.
+ if (find_result.number_of_matches() > -1) {
+ if (last_reported_matchcount_ > 0 &&
+ find_result.number_of_matches() == 1 &&
+ !find_result.final_update())
+ return; // Don't let interim result override match count.
+ last_reported_matchcount_ = find_result.number_of_matches();
+ }
+
+ find_bar_->UpdateUIForFindResult(find_result, tab_contents_->find_text());
+}
+
+void FindBarController::MaybeSetPrepopulateText() {
+#if !defined(OS_MACOSX)
+ // Find out what we should show in the find text box. Usually, this will be
+ // the last search in this tab, but if no search has been issued in this tab
+ // we use the last search string (from any tab).
+ string16 find_string = tab_contents_->find_text();
+ if (find_string.empty())
+ find_string = tab_contents_->previous_find_text();
+ if (find_string.empty()) {
+ find_string =
+ FindBarState::GetLastPrepopulateText(tab_contents_->profile());
+ }
+
+ // Update the find bar with existing results and search text, regardless of
+ // whether or not the find bar is visible, so that if it's subsequently
+ // shown it is showing the right state for this tab. We update the find text
+ // _first_ since the FindBarView checks its emptiness to see if it should
+ // clear the result count display when there's nothing in the box.
+ find_bar_->SetFindText(find_string);
+#else
+ // Having a per-tab find_string is not compatible with OS X's find pasteboard,
+ // so we always have the same find text in all find bars. This is done through
+ // the find pasteboard mechanism, so don't set the text here.
+#endif
+}
diff --git a/chrome/browser/ui/find_bar/find_bar_controller.h b/chrome/browser/ui/find_bar/find_bar_controller.h
new file mode 100644
index 0000000..1c3a1d6
--- /dev/null
+++ b/chrome/browser/ui/find_bar/find_bar_controller.h
@@ -0,0 +1,89 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_FIND_BAR_FIND_BAR_CONTROLLER_H_
+#define CHROME_BROWSER_UI_FIND_BAR_FIND_BAR_CONTROLLER_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+
+namespace gfx {
+class Rect;
+}
+
+class FindBar;
+class TabContents;
+
+class FindBarController : public NotificationObserver {
+ public:
+ // An enum listing the possible actions to take on a find-in-page selection.
+ enum SelectionAction {
+ kKeepSelection, // Translate the find selection into a normal selection.
+ kClearSelection, // Clear the find selection.
+ kActivateSelection // Focus and click the selected node (for links).
+ };
+
+ // FindBar takes ownership of |find_bar_view|.
+ explicit FindBarController(FindBar* find_bar);
+
+ virtual ~FindBarController();
+
+ // Shows the find bar. Any previous search string will again be visible.
+ void Show();
+
+ // Ends the current session.
+ void EndFindSession(SelectionAction action);
+
+ // Accessor for the attached TabContents.
+ TabContents* tab_contents() const { return tab_contents_; }
+
+ // Changes the TabContents that this FindBar is attached to. This occurs when
+ // the user switches tabs in the Browser window. |contents| can be NULL.
+ void ChangeTabContents(TabContents* contents);
+
+ // Overridden from NotificationObserver:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ FindBar* find_bar() const { return find_bar_.get(); }
+
+ // Reposition |view_location| such that it avoids |avoid_overlapping_rect|,
+ // and return the new location.
+ static gfx::Rect GetLocationForFindbarView(
+ gfx::Rect view_location,
+ const gfx::Rect& dialog_bounds,
+ const gfx::Rect& avoid_overlapping_rect);
+
+ private:
+ // Sents an update to the find bar with the tab contents' current result. The
+ // tab_contents_ must be non-NULL before this call. Theis handles
+ // de-flickering in addition to just calling the update function.
+ void UpdateFindBarForCurrentResult();
+
+ // For Windows and Linux this function sets the prepopulate text for the
+ // Find text box. The propopulate value is the last value the user searched
+ // for in the current tab, or (if blank) the last value searched for in any
+ // tab. Mac has a global value for search, so this function does nothing on
+ // Mac.
+ void MaybeSetPrepopulateText();
+
+ NotificationRegistrar registrar_;
+
+ scoped_ptr<FindBar> find_bar_;
+
+ // The TabContents we are currently associated with. Can be NULL.
+ TabContents* tab_contents_;
+
+ // The last match count we reported to the user. This is used by
+ // UpdateFindBarForCurrentResult to avoid flickering.
+ int last_reported_matchcount_;
+
+ DISALLOW_COPY_AND_ASSIGN(FindBarController);
+};
+
+#endif // CHROME_BROWSER_UI_FIND_BAR_FIND_BAR_CONTROLLER_H_
diff --git a/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc b/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc
new file mode 100644
index 0000000..4923ea7
--- /dev/null
+++ b/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc
@@ -0,0 +1,1084 @@
+// 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.
+
+#include "app/keyboard_codes.h"
+#include "base/message_loop.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_contents_view.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_navigator.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/find_bar/find_bar.h"
+#include "chrome/browser/ui/find_bar/find_bar_controller.h"
+#include "chrome/browser/ui/find_bar/find_notification_details.h"
+#include "chrome/test/in_process_browser_test.h"
+#include "chrome/test/ui_test_utils.h"
+#include "net/test/test_server.h"
+
+#if defined(TOOLKIT_VIEWS)
+#include "chrome/browser/views/find_bar_host.h"
+#include "views/focus/focus_manager.h"
+#elif defined(TOOLKIT_GTK)
+#include "chrome/browser/gtk/slide_animator_gtk.h"
+#elif defined(OS_MACOSX)
+#include "chrome/browser/ui/cocoa/find_bar_bridge.h"
+#endif
+
+const std::string kSimplePage = "404_is_enough_for_us.html";
+const std::string kFramePage = "files/find_in_page/frames.html";
+const std::string kFrameData = "files/find_in_page/framedata_general.html";
+const std::string kUserSelectPage = "files/find_in_page/user-select.html";
+const std::string kCrashPage = "files/find_in_page/crash_1341577.html";
+const std::string kTooFewMatchesPage = "files/find_in_page/bug_1155639.html";
+const std::string kEndState = "files/find_in_page/end_state.html";
+const std::string kPrematureEnd = "files/find_in_page/premature_end.html";
+const std::string kMoveIfOver = "files/find_in_page/move_if_obscuring.html";
+const std::string kBitstackCrash = "files/find_in_page/crash_14491.html";
+const std::string kSelectChangesOrdinal =
+ "files/find_in_page/select_changes_ordinal.html";
+const std::string kSimple = "files/find_in_page/simple.html";
+const std::string kLinkPage = "files/find_in_page/link.html";
+
+const bool kBack = false;
+const bool kFwd = true;
+
+const bool kIgnoreCase = false;
+const bool kCaseSensitive = true;
+
+const int kMoveIterations = 30;
+
+class FindInPageControllerTest : public InProcessBrowserTest {
+ public:
+ FindInPageControllerTest() {
+ EnableDOMAutomation();
+
+#if defined(TOOLKIT_VIEWS)
+ DropdownBarHost::disable_animations_during_testing_ = true;
+#elif defined(TOOLKIT_GTK)
+ SlideAnimatorGtk::SetAnimationsForTesting(false);
+#elif defined(OS_MACOSX)
+ FindBarBridge::disable_animations_during_testing_ = true;
+#endif
+ }
+
+ protected:
+ bool GetFindBarWindowInfoForBrowser(
+ Browser* browser, gfx::Point* position, bool* fully_visible) {
+ FindBarTesting* find_bar =
+ browser->GetFindBarController()->find_bar()->GetFindBarTesting();
+ return find_bar->GetFindBarWindowInfo(position, fully_visible);
+ }
+
+ bool GetFindBarWindowInfo(gfx::Point* position, bool* fully_visible) {
+ return GetFindBarWindowInfoForBrowser(browser(), position, fully_visible);
+ }
+
+ string16 GetFindBarTextForBrowser(Browser* browser) {
+ FindBarTesting* find_bar =
+ browser->GetFindBarController()->find_bar()->GetFindBarTesting();
+ return find_bar->GetFindText();
+ }
+
+ string16 GetFindBarText() {
+ return GetFindBarTextForBrowser(browser());
+ }
+
+ string16 GetFindBarMatchCountTextForBrowser(Browser* browser) {
+ FindBarTesting* find_bar =
+ browser->GetFindBarController()->find_bar()->GetFindBarTesting();
+ return find_bar->GetMatchCountText();
+ }
+
+ string16 GetMatchCountText() {
+ return GetFindBarMatchCountTextForBrowser(browser());
+ }
+
+ void EnsureFindBoxOpenForBrowser(Browser* browser) {
+ browser->ShowFindBar();
+ gfx::Point position;
+ bool fully_visible = false;
+ EXPECT_TRUE(GetFindBarWindowInfoForBrowser(
+ browser, &position, &fully_visible));
+ EXPECT_TRUE(fully_visible);
+ }
+
+ void EnsureFindBoxOpen() {
+ EnsureFindBoxOpenForBrowser(browser());
+ }
+};
+
+// Platform independent FindInPage that takes |const wchar_t*|
+// as an input.
+int FindInPageWchar(TabContents* tab,
+ const wchar_t* search_str,
+ bool forward,
+ bool case_sensitive,
+ int* ordinal) {
+ return ui_test_utils::FindInPage(
+ tab, WideToUTF16(std::wstring(search_str)),
+ forward, case_sensitive, ordinal);
+}
+
+// This test loads a page with frames and starts FindInPage requests.
+IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindInPageFrames) {
+ ASSERT_TRUE(test_server()->Start());
+
+ // First we navigate to our frames page.
+ GURL url = test_server()->GetURL(kFramePage);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ // Try incremental search (mimicking user typing in).
+ int ordinal = 0;
+ TabContents* tab = browser()->GetSelectedTabContents();
+ EXPECT_EQ(18, FindInPageWchar(tab, L"g",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(1, ordinal);
+ EXPECT_EQ(11, FindInPageWchar(tab, L"go",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(1, ordinal);
+ EXPECT_EQ(04, FindInPageWchar(tab, L"goo",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(1, ordinal);
+ EXPECT_EQ(03, FindInPageWchar(tab, L"goog",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(1, ordinal);
+ EXPECT_EQ(02, FindInPageWchar(tab, L"googl",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(1, ordinal);
+ EXPECT_EQ(01, FindInPageWchar(tab, L"google",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(1, ordinal);
+ EXPECT_EQ(00, FindInPageWchar(tab, L"google!",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(0, ordinal);
+
+ // Negative test (no matches should be found).
+ EXPECT_EQ(0, FindInPageWchar(tab, L"Non-existing string",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(0, ordinal);
+
+ // 'horse' only exists in the three right frames.
+ EXPECT_EQ(3, FindInPageWchar(tab, L"horse",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(1, ordinal);
+
+ // 'cat' only exists in the first frame.
+ EXPECT_EQ(1, FindInPageWchar(tab, L"cat",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(1, ordinal);
+
+ // Try searching again, should still come up with 1 match.
+ EXPECT_EQ(1, FindInPageWchar(tab, L"cat",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(1, ordinal);
+
+ // Try searching backwards, ignoring case, should still come up with 1 match.
+ EXPECT_EQ(1, FindInPageWchar(tab, L"CAT",
+ kBack, kIgnoreCase, &ordinal));
+ EXPECT_EQ(1, ordinal);
+
+ // Try case sensitive, should NOT find it.
+ EXPECT_EQ(0, FindInPageWchar(tab, L"CAT",
+ kFwd, kCaseSensitive, &ordinal));
+ EXPECT_EQ(0, ordinal);
+
+ // Try again case sensitive, but this time with right case.
+ EXPECT_EQ(1, FindInPageWchar(tab, L"dog",
+ kFwd, kCaseSensitive, &ordinal));
+ EXPECT_EQ(1, ordinal);
+
+ // Try non-Latin characters ('Hreggvidur' with 'eth' for 'd' in left frame).
+ EXPECT_EQ(1, FindInPageWchar(tab, L"Hreggvi\u00F0ur",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(1, ordinal);
+ EXPECT_EQ(1, FindInPageWchar(tab, L"Hreggvi\u00F0ur",
+ kFwd, kCaseSensitive, &ordinal));
+ EXPECT_EQ(1, ordinal);
+ EXPECT_EQ(0, FindInPageWchar(tab, L"hreggvi\u00F0ur",
+ kFwd, kCaseSensitive, &ordinal));
+ EXPECT_EQ(0, ordinal);
+}
+
+// Specifying a prototype so that we can add the WARN_UNUSED_RESULT attribute.
+bool FocusedOnPage(TabContents* tab_contents, std::string* result)
+ WARN_UNUSED_RESULT;
+
+bool FocusedOnPage(TabContents* tab_contents, std::string* result) {
+ return ui_test_utils::ExecuteJavaScriptAndExtractString(
+ tab_contents->render_view_host(),
+ L"",
+ L"window.domAutomationController.send(getFocusedElement());",
+ result);
+}
+
+// This tests the FindInPage end-state, in other words: what is focused when you
+// close the Find box (ie. if you find within a link the link should be
+// focused).
+IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindInPageEndState) {
+ ASSERT_TRUE(test_server()->Start());
+
+ // First we navigate to our special focus tracking page.
+ GURL url = test_server()->GetURL(kEndState);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ TabContents* tab_contents = browser()->GetSelectedTabContents();
+ ASSERT_TRUE(NULL != tab_contents);
+
+ // Verify that nothing has focus.
+ std::string result;
+ ASSERT_TRUE(FocusedOnPage(tab_contents, &result));
+ ASSERT_STREQ("{nothing focused}", result.c_str());
+
+ // Search for a text that exists within a link on the page.
+ int ordinal = 0;
+ EXPECT_EQ(1, FindInPageWchar(tab_contents, L"nk",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(1, ordinal);
+
+ // End the find session, which should set focus to the link.
+ tab_contents->StopFinding(FindBarController::kKeepSelection);
+
+ // Verify that the link is focused.
+ ASSERT_TRUE(FocusedOnPage(tab_contents, &result));
+ EXPECT_STREQ("link1", result.c_str());
+
+ // Search for a text that exists within a link on the page.
+ EXPECT_EQ(1, FindInPageWchar(tab_contents, L"Google",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(1, ordinal);
+
+ // Move the selection to link 1, after searching.
+ ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString(
+ tab_contents->render_view_host(),
+ L"",
+ L"window.domAutomationController.send(selectLink1());",
+ &result));
+
+ // End the find session.
+ tab_contents->StopFinding(FindBarController::kKeepSelection);
+
+ // Verify that link2 is not focused.
+ ASSERT_TRUE(FocusedOnPage(tab_contents, &result));
+ EXPECT_STREQ("", result.c_str());
+}
+
+// This test loads a single-frame page and makes sure the ordinal returned makes
+// sense as we FindNext over all the items.
+IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindInPageOrdinal) {
+ ASSERT_TRUE(test_server()->Start());
+
+ // First we navigate to our page.
+ GURL url = test_server()->GetURL(kFrameData);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ // Search for 'o', which should make the first item active and return
+ // '1 in 3' (1st ordinal of a total of 3 matches).
+ TabContents* tab = browser()->GetSelectedTabContents();
+ int ordinal = 0;
+ EXPECT_EQ(3, FindInPageWchar(tab, L"o",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(1, ordinal);
+ EXPECT_EQ(3, FindInPageWchar(tab, L"o",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(2, ordinal);
+ EXPECT_EQ(3, FindInPageWchar(tab, L"o",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(3, ordinal);
+ // Go back one match.
+ EXPECT_EQ(3, FindInPageWchar(tab, L"o",
+ kBack, kIgnoreCase, &ordinal));
+ EXPECT_EQ(2, ordinal);
+ EXPECT_EQ(3, FindInPageWchar(tab, L"o",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(3, ordinal);
+ // This should wrap to the top.
+ EXPECT_EQ(3, FindInPageWchar(tab, L"o",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(1, ordinal);
+ // This should go back to the end.
+ EXPECT_EQ(3, FindInPageWchar(tab, L"o",
+ kBack, kIgnoreCase, &ordinal));
+ EXPECT_EQ(3, ordinal);
+}
+
+// This tests that the ordinal is correctly adjusted after a selection
+IN_PROC_BROWSER_TEST_F(FindInPageControllerTest,
+ SelectChangesOrdinal_Issue20883) {
+ ASSERT_TRUE(test_server()->Start());
+
+ // First we navigate to our test content.
+ GURL url = test_server()->GetURL(kSelectChangesOrdinal);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ TabContents* tab_contents = browser()->GetSelectedTabContents();
+ ASSERT_TRUE(NULL != tab_contents);
+
+ // Search for a text that exists within a link on the page.
+ TabContents* tab = browser()->GetSelectedTabContents();
+ int ordinal = 0;
+ EXPECT_EQ(4, FindInPageWchar(tab_contents,
+ L"google",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(1, ordinal);
+
+ // Move the selection to link 1, after searching.
+ std::string result;
+ ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString(
+ tab_contents->render_view_host(),
+ L"",
+ L"window.domAutomationController.send(selectLink1());",
+ &result));
+
+ // Do a find-next after the selection. This should move forward
+ // from there to the 3rd instance of 'google'.
+ EXPECT_EQ(4, FindInPageWchar(tab,
+ L"google",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(3, ordinal);
+
+ // End the find session.
+ tab_contents->StopFinding(FindBarController::kKeepSelection);
+}
+
+// This test loads a page with frames and makes sure the ordinal returned makes
+// sense.
+IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindInPageMultiFramesOrdinal) {
+ ASSERT_TRUE(test_server()->Start());
+
+ // First we navigate to our page.
+ GURL url = test_server()->GetURL(kFramePage);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ // Search for 'a', which should make the first item active and return
+ // '1 in 7' (1st ordinal of a total of 7 matches).
+ TabContents* tab = browser()->GetSelectedTabContents();
+ int ordinal = 0;
+ EXPECT_EQ(7,
+ FindInPageWchar(tab, L"a", kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(1, ordinal);
+ EXPECT_EQ(7,
+ FindInPageWchar(tab, L"a", kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(2, ordinal);
+ EXPECT_EQ(7,
+ FindInPageWchar(tab, L"a", kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(3, ordinal);
+ EXPECT_EQ(7,
+ FindInPageWchar(tab, L"a", kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(4, ordinal);
+ // Go back one, which should go back one frame.
+ EXPECT_EQ(7,
+ FindInPageWchar(tab, L"a", kBack, kIgnoreCase, &ordinal));
+ EXPECT_EQ(3, ordinal);
+ EXPECT_EQ(7,
+ FindInPageWchar(tab, L"a", kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(4, ordinal);
+ EXPECT_EQ(7,
+ FindInPageWchar(tab, L"a", kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(5, ordinal);
+ EXPECT_EQ(7,
+ FindInPageWchar(tab, L"a", kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(6, ordinal);
+ EXPECT_EQ(7,
+ FindInPageWchar(tab, L"a", kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(7, ordinal);
+ // Now we should wrap back to frame 1.
+ EXPECT_EQ(7,
+ FindInPageWchar(tab, L"a", kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(1, ordinal);
+ // Now we should wrap back to frame last frame.
+ EXPECT_EQ(7,
+ FindInPageWchar(tab, L"a", kBack, kIgnoreCase, &ordinal));
+ EXPECT_EQ(7, ordinal);
+}
+
+// We could get ordinals out of whack when restarting search in subframes.
+// See http://crbug.com/5132.
+IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindInPage_Issue5132) {
+ ASSERT_TRUE(test_server()->Start());
+
+ // First we navigate to our page.
+ GURL url = test_server()->GetURL(kFramePage);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ // Search for 'goa' three times (6 matches on page).
+ int ordinal = 0;
+ TabContents* tab = browser()->GetSelectedTabContents();
+ EXPECT_EQ(6, FindInPageWchar(tab, L"goa",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(1, ordinal);
+ EXPECT_EQ(6, FindInPageWchar(tab, L"goa",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(2, ordinal);
+ EXPECT_EQ(6, FindInPageWchar(tab, L"goa",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(3, ordinal);
+ // Add space to search (should result in no matches).
+ EXPECT_EQ(0, FindInPageWchar(tab, L"goa ",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(0, ordinal);
+ // Remove the space, should be back to '3 out of 6')
+ EXPECT_EQ(6, FindInPageWchar(tab, L"goa",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(3, ordinal);
+}
+
+// Load a page with no selectable text and make sure we don't crash.
+IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindUnSelectableText) {
+ ASSERT_TRUE(test_server()->Start());
+
+ // First we navigate to our page.
+ GURL url = test_server()->GetURL(kUserSelectPage);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ int ordinal = 0;
+ TabContents* tab = browser()->GetSelectedTabContents();
+ // The search string is present but doesn't qualify to be found
+ EXPECT_EQ(0, FindInPageWchar(tab, L"text",
+ kFwd, kIgnoreCase, &ordinal));
+ // With zero results there should be no current selection.
+ EXPECT_EQ(0, ordinal);
+}
+
+// Try to reproduce the crash seen in issue 1341577.
+IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindCrash_Issue1341577) {
+ ASSERT_TRUE(test_server()->Start());
+
+ // First we navigate to our page.
+ GURL url = test_server()->GetURL(kCrashPage);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ // This would crash the tab. These must be the first two find requests issued
+ // against the frame, otherwise an active frame pointer is set and it wont
+ // produce the crash.
+ // We used to check the return value and |ordinal|. With ICU 4.2, FiP does
+ // not find a stand-alone dependent vowel sign of Indic scripts. So, the
+ // exptected values are all 0. To make this test pass regardless of
+ // ICU version, we just call FiP and see if there's any crash.
+ // TODO(jungshik): According to a native Malayalam speaker, it's ok not
+ // to find U+0D4C. Still need to investigate further this issue.
+ int ordinal = 0;
+ TabContents* tab = browser()->GetSelectedTabContents();
+ FindInPageWchar(tab, L"\u0D4C", kFwd, kIgnoreCase, &ordinal);
+ FindInPageWchar(tab, L"\u0D4C", kFwd, kIgnoreCase, &ordinal);
+
+ // This should work fine.
+ EXPECT_EQ(1, FindInPageWchar(tab, L"\u0D24\u0D46",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(1, ordinal);
+ EXPECT_EQ(0, FindInPageWchar(tab, L"nostring",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(0, ordinal);
+}
+
+// Try to reproduce the crash seen in http://crbug.com/14491, where an assert
+// hits in the BitStack size comparison in WebKit.
+IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindCrash_Issue14491) {
+ ASSERT_TRUE(test_server()->Start());
+
+ // First we navigate to our page.
+ GURL url = test_server()->GetURL(kBitstackCrash);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ // This used to crash the tab.
+ int ordinal = 0;
+ EXPECT_EQ(0, FindInPageWchar(browser()->GetSelectedTabContents(),
+ L"s", kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(0, ordinal);
+}
+
+// Test to make sure Find does the right thing when restarting from a timeout.
+// We used to have a problem where we'd stop finding matches when all of the
+// following conditions were true:
+// 1) The page has a lot of text to search.
+// 2) The page contains more than one match.
+// 3) It takes longer than the time-slice given to each Find operation (100
+// ms) to find one or more of those matches (so Find times out and has to try
+// again from where it left off).
+IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindRestarts_Issue1155639) {
+ ASSERT_TRUE(test_server()->Start());
+
+ // First we navigate to our page.
+ GURL url = test_server()->GetURL(kTooFewMatchesPage);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ // This string appears 5 times at the bottom of a long page. If Find restarts
+ // properly after a timeout, it will find 5 matches, not just 1.
+ int ordinal = 0;
+ EXPECT_EQ(5, FindInPageWchar(browser()->GetSelectedTabContents(),
+ L"008.xml",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(1, ordinal);
+}
+
+// This tests bug 11761: FindInPage terminates search prematurely.
+// This test is not expected to pass until bug 11761 is fixed.
+IN_PROC_BROWSER_TEST_F(FindInPageControllerTest,
+ DISABLED_FindInPagePrematureEnd) {
+ ASSERT_TRUE(test_server()->Start());
+
+ // First we navigate to our special focus tracking page.
+ GURL url = test_server()->GetURL(kPrematureEnd);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ TabContents* tab_contents = browser()->GetSelectedTabContents();
+ ASSERT_TRUE(NULL != tab_contents);
+
+ // Search for a text that exists within a link on the page.
+ int ordinal = 0;
+ EXPECT_EQ(2, FindInPageWchar(tab_contents, L"html ",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(1, ordinal);
+}
+
+IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FindDisappearOnNavigate) {
+ ASSERT_TRUE(test_server()->Start());
+
+ // First we navigate to our special focus tracking page.
+ GURL url = test_server()->GetURL(kSimplePage);
+ GURL url2 = test_server()->GetURL(kFramePage);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ browser()->ShowFindBar();
+
+ gfx::Point position;
+ bool fully_visible = false;
+
+ // Make sure it is open.
+ EXPECT_TRUE(GetFindBarWindowInfo(&position, &fully_visible));
+ EXPECT_TRUE(fully_visible);
+
+ // Reload the tab and make sure Find window doesn't go away.
+ browser()->Reload(CURRENT_TAB);
+ ui_test_utils::WaitForNavigationInCurrentTab(browser());
+
+ EXPECT_TRUE(GetFindBarWindowInfo(&position, &fully_visible));
+ EXPECT_TRUE(fully_visible);
+
+ // Navigate and make sure the Find window goes away.
+ ui_test_utils::NavigateToURL(browser(), url2);
+
+ EXPECT_TRUE(GetFindBarWindowInfo(&position, &fully_visible));
+ EXPECT_FALSE(fully_visible);
+}
+
+#if defined(OS_MACOSX)
+// FindDisappearOnNewTabAndHistory is flaky, at least on Mac.
+// See http://crbug.com/43072
+#define FindDisappearOnNewTabAndHistory FLAKY_FindDisappearOnNewTabAndHistory
+#endif
+
+// Make sure Find box disappears when History/Downloads page is opened, and
+// when a New Tab is opened.
+IN_PROC_BROWSER_TEST_F(FindInPageControllerTest,
+ FindDisappearOnNewTabAndHistory) {
+ ASSERT_TRUE(test_server()->Start());
+
+ // First we navigate to our special focus tracking page.
+ GURL url = test_server()->GetURL(kSimplePage);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ browser()->ShowFindBar();
+
+ gfx::Point position;
+ bool fully_visible = false;
+
+ // Make sure it is open.
+ EXPECT_TRUE(GetFindBarWindowInfo(&position, &fully_visible));
+ EXPECT_TRUE(fully_visible);
+
+ // Open another tab (tab B).
+ browser()->NewTab();
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ // Make sure Find box is closed.
+ EXPECT_TRUE(GetFindBarWindowInfo(&position, &fully_visible));
+ EXPECT_FALSE(fully_visible);
+
+ // Close tab B.
+ browser()->CloseTab();
+
+ // Make sure Find window appears again.
+ EXPECT_TRUE(GetFindBarWindowInfo(&position, &fully_visible));
+ EXPECT_TRUE(fully_visible);
+
+ browser()->ShowHistoryTab();
+
+ // Make sure Find box is closed.
+ EXPECT_TRUE(GetFindBarWindowInfo(&position, &fully_visible));
+ EXPECT_FALSE(fully_visible);
+}
+
+// TODO(rohitrao): The FindMovesWhenObscuring test does not pass on mac.
+// http://crbug.com/22036
+#if defined(OS_MACOSX)
+#define MAYBE_FindMovesWhenObscuring FAILS_FindMovesWhenObscuring
+#else
+#define MAYBE_FindMovesWhenObscuring FindMovesWhenObscuring
+#endif
+
+// Make sure Find box moves out of the way if it is obscuring the active match.
+IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, MAYBE_FindMovesWhenObscuring) {
+ ASSERT_TRUE(test_server()->Start());
+
+ GURL url = test_server()->GetURL(kMoveIfOver);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ browser()->ShowFindBar();
+
+ // This is needed on GTK because the reposition operation is asynchronous.
+ MessageLoop::current()->RunAllPending();
+
+ gfx::Point start_position;
+ gfx::Point position;
+ bool fully_visible = false;
+
+ // Make sure it is open.
+ EXPECT_TRUE(GetFindBarWindowInfo(&start_position, &fully_visible));
+ EXPECT_TRUE(fully_visible);
+
+ // Search for 'Chromium' which the Find box is obscuring.
+ int ordinal = 0;
+ TabContents* tab = browser()->GetSelectedTabContents();
+ int index = 0;
+ for (; index < kMoveIterations; ++index) {
+ EXPECT_EQ(kMoveIterations, FindInPageWchar(tab, L"Chromium",
+ kFwd, kIgnoreCase, &ordinal));
+
+ // Check the position.
+ EXPECT_TRUE(GetFindBarWindowInfo(&position, &fully_visible));
+ EXPECT_TRUE(fully_visible);
+
+ // If the Find box has moved then we are done.
+ if (position.x() != start_position.x())
+ break;
+ }
+
+ // We should not have reached the end.
+ ASSERT_GT(kMoveIterations, index);
+
+ // Search for something guaranteed not to be obscured by the Find box.
+ EXPECT_EQ(1, FindInPageWchar(tab, L"Done",
+ kFwd, kIgnoreCase, &ordinal));
+ // Check the position.
+ EXPECT_TRUE(GetFindBarWindowInfo(&position, &fully_visible));
+ EXPECT_TRUE(fully_visible);
+
+ // Make sure Find box has moved back to its original location.
+ EXPECT_EQ(position.x(), start_position.x());
+}
+
+#if defined(OS_MACOSX)
+// FindNextInNewTabUsesPrepopulate times-out, at least on Mac.
+// See http://crbug.com/43070
+#define FindNextInNewTabUsesPrepopulate DISABLED_FindNextInNewTabUsesPrepopulate
+#endif
+
+// Make sure F3 in a new tab works if Find has previous string to search for.
+IN_PROC_BROWSER_TEST_F(FindInPageControllerTest,
+ FindNextInNewTabUsesPrepopulate) {
+ ASSERT_TRUE(test_server()->Start());
+
+ // First we navigate to any page.
+ GURL url = test_server()->GetURL(kSimplePage);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ // Search for 'no_match'. No matches should be found.
+ int ordinal = 0;
+ TabContents* tab = browser()->GetSelectedTabContents();
+ EXPECT_EQ(0, FindInPageWchar(tab, L"no_match",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(0, ordinal);
+
+ // Open another tab (tab B).
+ browser()->NewTab();
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ // Simulate what happens when you press F3 for FindNext. We should get a
+ // response here (a hang means search was aborted).
+ EXPECT_EQ(0, ui_test_utils::FindInPage(tab, string16(),
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(0, ordinal);
+
+ // Open another tab (tab C).
+ browser()->NewTab();
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ // Simulate what happens when you press F3 for FindNext. We should get a
+ // response here (a hang means search was aborted).
+ EXPECT_EQ(0, ui_test_utils::FindInPage(tab, string16(),
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(0, ordinal);
+}
+
+#if defined(TOOLKIT_VIEWS)
+// Make sure Find box grabs the Esc accelerator and restores it again.
+#if defined(OS_LINUX)
+// TODO(oshima): On Gtk/Linux, a focus out event is asynchronous and
+// hiding a find bar does not immediately update the target
+// accelerator. The last condition fails in most cases due to this
+// behavior. See http://crbug.com/26870.
+IN_PROC_BROWSER_TEST_F(FindInPageControllerTest,
+ DISABLED_AcceleratorRestoring) {
+#else
+ IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, AcceleratorRestoring) {
+#endif
+ ASSERT_TRUE(test_server()->Start());
+
+ // First we navigate to any page.
+ GURL url = test_server()->GetURL(kSimplePage);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ views::FocusManager* focus_manager =
+ views::FocusManager::GetFocusManagerForNativeWindow(
+ browser()->window()->GetNativeHandle());
+
+ // See where Escape is registered.
+ views::Accelerator escape(app::VKEY_ESCAPE, false, false, false);
+ views::AcceleratorTarget* old_target =
+ focus_manager->GetCurrentTargetForAccelerator(escape);
+ EXPECT_TRUE(old_target != NULL);
+
+ browser()->ShowFindBar();
+
+ // Our Find bar should be the new target.
+ views::AcceleratorTarget* new_target =
+ focus_manager->GetCurrentTargetForAccelerator(escape);
+
+ EXPECT_TRUE(new_target != NULL);
+ EXPECT_NE(new_target, old_target);
+
+ // Close the Find box.
+ browser()->GetFindBarController()->EndFindSession(
+ FindBarController::kKeepSelection);
+
+ // The accelerator for Escape should be back to what it was before.
+ EXPECT_EQ(old_target,
+ focus_manager->GetCurrentTargetForAccelerator(escape));
+}
+#endif // TOOLKIT_VIEWS
+
+// Make sure Find box does not become UI-inactive when no text is in the box as
+// we switch to a tab contents with an empty find string. See issue 13570.
+IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, StayActive) {
+ ASSERT_TRUE(test_server()->Start());
+
+ // First we navigate to any page.
+ GURL url = test_server()->GetURL(kSimplePage);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ browser()->ShowFindBar();
+
+ // Simulate a user clearing the search string. Ideally, we should be
+ // simulating keypresses here for searching for something and pressing
+ // backspace, but that's been proven flaky in the past, so we go straight to
+ // tab_contents.
+ TabContents* tab_contents = browser()->GetSelectedTabContents();
+ // Stop the (non-existing) find operation, and clear the selection (which
+ // signals the UI is still active).
+ tab_contents->StopFinding(FindBarController::kClearSelection);
+ // Make sure the Find UI flag hasn't been cleared, it must be so that the UI
+ // still responds to browser window resizing.
+ ASSERT_TRUE(tab_contents->find_ui_active());
+}
+
+// Make sure F3 works after you FindNext a couple of times and end the Find
+// session. See issue http://crbug.com/28306.
+IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, RestartSearchFromF3) {
+ ASSERT_TRUE(test_server()->Start());
+
+ // First we navigate to a simple page.
+ GURL url = test_server()->GetURL(kSimple);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ // Search for 'page'. Should have 1 match.
+ int ordinal = 0;
+ TabContents* tab = browser()->GetSelectedTabContents();
+ EXPECT_EQ(1, FindInPageWchar(tab, L"page", kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(1, ordinal);
+
+ // Simulate what happens when you press F3 for FindNext. Still should show
+ // one match. This cleared the pre-populate string at one point (see bug).
+ EXPECT_EQ(1, ui_test_utils::FindInPage(tab, string16(),
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(1, ordinal);
+
+ // End the Find session, thereby making the next F3 start afresh.
+ browser()->GetFindBarController()->EndFindSession(
+ FindBarController::kKeepSelection);
+
+ // Simulate F3 while Find box is closed. Should have 1 match.
+ EXPECT_EQ(1, FindInPageWchar(tab, L"", kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(1, ordinal);
+}
+
+// When re-opening the find bar with F3, the find bar should be re-populated
+// with the last search from the same tab rather than the last overall search.
+// http://crbug.com/30006
+IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, PreferPreviousSearch) {
+ ASSERT_TRUE(test_server()->Start());
+
+ // First we navigate to any page.
+ GURL url = test_server()->GetURL(kSimplePage);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ // Find "Default".
+ int ordinal = 0;
+ TabContents* tab1 = browser()->GetSelectedTabContents();
+ EXPECT_EQ(1, FindInPageWchar(tab1, L"Default", kFwd, kIgnoreCase, &ordinal));
+
+ // Create a second tab.
+ // For some reason we can't use AddSelectedTabWithURL here on ChromeOS. It
+ // could be some delicate assumption about the tab starting off unselected or
+ // something relating to user gesture.
+ browser::NavigateParams params(browser(), url, PageTransition::TYPED);
+ params.disposition = NEW_BACKGROUND_TAB;
+ params.tabstrip_add_types = TabStripModel::ADD_NONE;
+ browser::Navigate(&params);
+ browser()->SelectTabContentsAt(1, false);
+ TabContents* tab2 = browser()->GetSelectedTabContents();
+ EXPECT_NE(tab1, tab2);
+
+ // Find "given".
+ FindInPageWchar(tab2, L"given", kFwd, kIgnoreCase, &ordinal);
+
+ // Switch back to first tab.
+ browser()->SelectTabContentsAt(0, false);
+ browser()->GetFindBarController()->EndFindSession(
+ FindBarController::kKeepSelection);
+ // Simulate F3.
+ ui_test_utils::FindInPage(tab1, string16(), kFwd, kIgnoreCase, &ordinal);
+ EXPECT_EQ(tab1->find_text(), WideToUTF16(L"Default"));
+}
+
+// This tests that whenever you close and reopen the Find bar, it should show
+// the last search entered in that tab. http://crbug.com/40121.
+IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, PrepopulateSameTab) {
+#if defined(OS_MACOSX)
+ // FindInPage on Mac doesn't use prepopulated values. Search there is global.
+ return;
+#endif
+
+ ASSERT_TRUE(test_server()->Start());
+
+ // First we navigate to any page.
+ GURL url = test_server()->GetURL(kSimple);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ // Search for the word "page".
+ int ordinal = 0;
+ TabContents* tab1 = browser()->GetSelectedTabContents();
+ EXPECT_EQ(1, FindInPageWchar(tab1, L"page", kFwd, kIgnoreCase, &ordinal));
+
+ // Open the Find box.
+ EnsureFindBoxOpen();
+
+ EXPECT_EQ(ASCIIToUTF16("page"), GetFindBarText());
+ EXPECT_EQ(ASCIIToUTF16("1 of 1"), GetMatchCountText());
+
+ // Close the Find box.
+ browser()->GetFindBarController()->EndFindSession(
+ FindBarController::kKeepSelection);
+
+ // Open the Find box again.
+ EnsureFindBoxOpen();
+
+ // After the Find box has been reopened, it should have been prepopulated with
+ // the word "page" again.
+ EXPECT_EQ(ASCIIToUTF16("page"), GetFindBarText());
+ EXPECT_EQ(ASCIIToUTF16("1 of 1"), GetMatchCountText());
+}
+
+// This tests that whenever you open Find in a new tab it should prepopulate
+// with a previous search term (in any tab), if a search has not been issued in
+// this tab before.
+IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, PrepopulateInNewTab) {
+#if defined(OS_MACOSX)
+ // FindInPage on Mac doesn't use prepopulated values. Search there is global.
+ return;
+#endif
+
+ ASSERT_TRUE(test_server()->Start());
+
+ // First we navigate to any page.
+ GURL url = test_server()->GetURL(kSimple);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ // Search for the word "page".
+ int ordinal = 0;
+ TabContents* tab1 = browser()->GetSelectedTabContents();
+ EXPECT_EQ(1, FindInPageWchar(tab1, L"page", kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(ASCIIToUTF16("1 of 1"), GetMatchCountText());
+
+ // Now create a second tab and load the same page.
+ browser()->AddSelectedTabWithURL(url, PageTransition::TYPED);
+ TabContents* tab2 = browser()->GetSelectedTabContents();
+ EXPECT_NE(tab1, tab2);
+
+ // Open the Find box.
+ EnsureFindBoxOpen();
+
+ // The new tab should have "page" prepopulated, since that was the last search
+ // in the first tab.
+ EXPECT_EQ(ASCIIToUTF16("page"), GetFindBarText());
+ // But it should not seem like a search has been issued.
+ EXPECT_EQ(ASCIIToUTF16(""), GetMatchCountText());
+}
+
+// This makes sure that we can search for A in tabA, then for B in tabB and
+// when we come back to tabA we should still see A (because that was the last
+// search in that tab).
+IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, PrepopulatePreserveLast) {
+#if defined(OS_MACOSX)
+ // FindInPage on Mac doesn't use prepopulated values. Search there is global.
+ return;
+#endif
+
+ ASSERT_TRUE(test_server()->Start());
+
+ // First we navigate to any page.
+ GURL url = test_server()->GetURL(kSimple);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ // Search for the word "page".
+ int ordinal = 0;
+ TabContents* tab1 = browser()->GetSelectedTabContents();
+ EXPECT_EQ(1, FindInPageWchar(tab1, L"page", kFwd, kIgnoreCase, &ordinal));
+
+ // Open the Find box.
+ EnsureFindBoxOpen();
+
+ EXPECT_EQ(ASCIIToUTF16("page"), GetFindBarText());
+
+ // Close the Find box.
+ browser()->GetFindBarController()->EndFindSession(
+ FindBarController::kKeepSelection);
+
+ // Now create a second tab and load the same page.
+ browser::NavigateParams params(browser(), url, PageTransition::TYPED);
+ params.disposition = NEW_BACKGROUND_TAB;
+ params.tabstrip_add_types = TabStripModel::ADD_NONE;
+ browser::Navigate(&params);
+ browser()->SelectTabContentsAt(1, false);
+ TabContents* tab2 = browser()->GetSelectedTabContents();
+ EXPECT_NE(tab1, tab2);
+
+ // Search for the word "text".
+ FindInPageWchar(tab2, L"text", kFwd, kIgnoreCase, &ordinal);
+
+ // Go back to the first tab and make sure we have NOT switched the prepopulate
+ // text to "text".
+ browser()->SelectTabContentsAt(0, false);
+
+ // Open the Find box.
+ EnsureFindBoxOpen();
+
+ // After the Find box has been reopened, it should have been prepopulated with
+ // the word "page" again, since that was the last search in that tab.
+ EXPECT_EQ(ASCIIToUTF16("page"), GetFindBarText());
+
+ // Close the Find box.
+ browser()->GetFindBarController()->EndFindSession(
+ FindBarController::kKeepSelection);
+
+ // Re-open the Find box.
+ // This is a special case: previous search in TabContents used to get cleared
+ // if you opened and closed the FindBox, which would cause the global
+ // prepopulate value to show instead of last search in this tab.
+ EnsureFindBoxOpen();
+
+ // After the Find box has been reopened, it should have been prepopulated with
+ // the word "page" again, since that was the last search in that tab.
+ EXPECT_EQ(ASCIIToUTF16("page"), GetFindBarText());
+}
+
+// TODO(rohitrao): Searching in incognito tabs does not work in browser tests in
+// Linux views. Investigate and fix. http://crbug.com/40948
+#if defined(OS_LINUX) && defined(TOOLKIT_VIEWS)
+#define MAYBE_NoIncognitoPrepopulate DISABLED_NoIncognitoPrepopulate
+#else
+#define MAYBE_NoIncognitoPrepopulate NoIncognitoPrepopulate
+#endif
+
+// This tests that search terms entered into an incognito find bar are not used
+// as prepopulate terms for non-incognito windows.
+IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, MAYBE_NoIncognitoPrepopulate) {
+#if defined(OS_MACOSX)
+ // FindInPage on Mac doesn't use prepopulated values. Search there is global.
+ return;
+#endif
+
+ ASSERT_TRUE(test_server()->Start());
+
+ // First we navigate to the "simple" test page.
+ GURL url = test_server()->GetURL(kSimple);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ // Search for the word "page" in the normal browser tab.
+ int ordinal = 0;
+ TabContents* tab1 = browser()->GetSelectedTabContents();
+ EXPECT_EQ(1, FindInPageWchar(tab1, L"page", kFwd, kIgnoreCase, &ordinal));
+
+ // Open the Find box.
+ EnsureFindBoxOpenForBrowser(browser());
+ EXPECT_EQ(ASCIIToUTF16("page"), GetFindBarTextForBrowser(browser()));
+
+ // Close the Find box.
+ browser()->GetFindBarController()->EndFindSession(
+ FindBarController::kKeepSelection);
+
+ // Open a new incognito window and navigate to the same page.
+ Profile* incognito_profile = browser()->profile()->GetOffTheRecordProfile();
+ Browser* incognito_browser = Browser::Create(incognito_profile);
+ incognito_browser->AddSelectedTabWithURL(url, PageTransition::START_PAGE);
+ ui_test_utils::WaitForNavigation(
+ &incognito_browser->GetSelectedTabContents()->controller());
+ incognito_browser->window()->Show();
+
+ // Open the find box and make sure that it is prepopulated with "page".
+ EnsureFindBoxOpenForBrowser(incognito_browser);
+ EXPECT_EQ(ASCIIToUTF16("page"), GetFindBarTextForBrowser(incognito_browser));
+
+ // Search for the word "text" in the incognito tab.
+ TabContents* incognito_tab = incognito_browser->GetSelectedTabContents();
+ EXPECT_EQ(1, FindInPageWchar(incognito_tab, L"text",
+ kFwd, kIgnoreCase, &ordinal));
+ EXPECT_EQ(ASCIIToUTF16("text"), GetFindBarTextForBrowser(incognito_browser));
+
+ // Close the Find box.
+ incognito_browser->GetFindBarController()->EndFindSession(
+ FindBarController::kKeepSelection);
+
+ // Now open a new tab in the original (non-incognito) browser.
+ browser()->AddSelectedTabWithURL(url, PageTransition::TYPED);
+ TabContents* tab2 = browser()->GetSelectedTabContents();
+ EXPECT_NE(tab1, tab2);
+
+ // Open the Find box and make sure it is prepopulated with the search term
+ // from the original browser, not the search term from the incognito window.
+ EnsureFindBoxOpenForBrowser(browser());
+ EXPECT_EQ(ASCIIToUTF16("page"), GetFindBarTextForBrowser(browser()));
+}
+
+// This makes sure that dismissing the find bar with kActivateSelection works.
+IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, ActivateLinkNavigatesPage) {
+ ASSERT_TRUE(test_server()->Start());
+
+ // First we navigate to our test content.
+ GURL url = test_server()->GetURL(kLinkPage);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ TabContents* tab = browser()->GetSelectedTabContents();
+ int ordinal = 0;
+ FindInPageWchar(tab, L"link", kFwd, kIgnoreCase, &ordinal);
+ EXPECT_EQ(ordinal, 1);
+
+ // End the find session, click on the link.
+ tab->StopFinding(FindBarController::kActivateSelection);
+ EXPECT_TRUE(ui_test_utils::WaitForNavigationInCurrentTab(browser()));
+}
diff --git a/chrome/browser/ui/find_bar/find_bar_state.cc b/chrome/browser/ui/find_bar/find_bar_state.cc
new file mode 100644
index 0000000..d4f2cc1
--- /dev/null
+++ b/chrome/browser/ui/find_bar/find_bar_state.cc
@@ -0,0 +1,20 @@
+// 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.
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/find_bar/find_bar_state.h"
+
+// static
+string16 FindBarState::GetLastPrepopulateText(Profile* p) {
+ FindBarState* state = p->GetFindBarState();
+ string16 text = state->last_prepopulate_text();
+
+ if (text.empty() && p->IsOffTheRecord()) {
+ // Fall back to the original profile.
+ state = p->GetOriginalProfile()->GetFindBarState();
+ text = state->last_prepopulate_text();
+ }
+
+ return text;
+}
diff --git a/chrome/browser/ui/find_bar/find_bar_state.h b/chrome/browser/ui/find_bar/find_bar_state.h
new file mode 100644
index 0000000..57f2d2e
--- /dev/null
+++ b/chrome/browser/ui/find_bar/find_bar_state.h
@@ -0,0 +1,41 @@
+// 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.
+
+// Stores per-profile state needed for find in page. This includes the most
+// recently searched for term.
+
+#ifndef CHROME_BROWSER_UI_FIND_BAR_FIND_BAR_STATE_H_
+#define CHROME_BROWSER_UI_FIND_BAR_FIND_BAR_STATE_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/string16.h"
+
+class Profile;
+
+class FindBarState {
+ public:
+ FindBarState() {}
+ ~FindBarState() {}
+
+ string16 last_prepopulate_text() const {
+ return last_prepopulate_text_;
+ }
+
+ void set_last_prepopulate_text(const string16& text) {
+ last_prepopulate_text_ = text;
+ }
+
+ // Retrieves the last prepopulate text for a given Profile. If the profile is
+ // off the record and has an empty prepopulate text, falls back to the
+ // prepopulate text from the normal profile.
+ static string16 GetLastPrepopulateText(Profile* profile);
+
+ private:
+ string16 last_prepopulate_text_;
+
+ DISALLOW_COPY_AND_ASSIGN(FindBarState);
+};
+
+#endif // CHROME_BROWSER_UI_FIND_BAR_FIND_BAR_STATE_H_
diff --git a/chrome/browser/ui/find_bar/find_notification_details.h b/chrome/browser/ui/find_bar/find_notification_details.h
new file mode 100644
index 0000000..d553782
--- /dev/null
+++ b/chrome/browser/ui/find_bar/find_notification_details.h
@@ -0,0 +1,51 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_FIND_BAR_FIND_NOTIFICATION_DETAILS_H_
+#define CHROME_BROWSER_UI_FIND_BAR_FIND_NOTIFICATION_DETAILS_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "gfx/rect.h"
+
+class FindNotificationDetails {
+ public:
+ FindNotificationDetails(int request_id,
+ int number_of_matches,
+ const gfx::Rect& selection_rect,
+ int active_match_ordinal,
+ bool final_update)
+ : request_id_(request_id),
+ number_of_matches_(number_of_matches),
+ selection_rect_(selection_rect),
+ active_match_ordinal_(active_match_ordinal),
+ final_update_(final_update) {}
+
+ FindNotificationDetails()
+ : request_id_(0),
+ number_of_matches_(-1),
+ active_match_ordinal_(-1),
+ final_update_(false) {}
+
+ ~FindNotificationDetails() {}
+
+ int request_id() const { return request_id_; }
+
+ int number_of_matches() const { return number_of_matches_; }
+
+ gfx::Rect selection_rect() const { return selection_rect_; }
+
+ int active_match_ordinal() const { return active_match_ordinal_; }
+
+ bool final_update() const { return final_update_; }
+
+ private:
+ int request_id_; // The find-in-page request whose results we're returning.
+ int number_of_matches_; // How many matches were found.
+ gfx::Rect selection_rect_; // Where selection occurred (screen coordinate).
+ int active_match_ordinal_; // The ordinal of the currently selected match.
+ bool final_update_; // Whether this is the last Find Result update.
+};
+
+#endif // CHROME_BROWSER_UI_FIND_BAR_FIND_NOTIFICATION_DETAILS_H_
diff --git a/chrome/browser/ui/input_window_dialog.h b/chrome/browser/ui/input_window_dialog.h
new file mode 100644
index 0000000..aa7455a
--- /dev/null
+++ b/chrome/browser/ui/input_window_dialog.h
@@ -0,0 +1,53 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_INPUT_WINDOW_DIALOG_H_
+#define CHROME_BROWSER_UI_INPUT_WINDOW_DIALOG_H_
+#pragma once
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "gfx/native_widget_types.h"
+
+// Cross platform access to a modal input window.
+class InputWindowDialog {
+ public:
+ class Delegate {
+ public:
+ virtual ~Delegate() {}
+
+ // Checks whether |text| is a valid input string.
+ virtual bool IsValid(const std::wstring& text) = 0;
+
+ // Callback for when the user clicks the OK button.
+ virtual void InputAccepted(const std::wstring& text) = 0;
+
+ // Callback for when the user clicks the Cancel button.
+ virtual void InputCanceled() = 0;
+ };
+
+ // Creates a new input window dialog parented to |parent|. Ownership of
+ // |delegate| is taken by InputWindowDialog or InputWindowDialog's owner.
+ static InputWindowDialog* Create(gfx::NativeWindow parent,
+ const std::wstring& window_title,
+ const std::wstring& label,
+ const std::wstring& contents,
+ Delegate* delegate);
+
+ // Displays the window.
+ virtual void Show() = 0;
+
+ // Closes the window.
+ virtual void Close() = 0;
+
+ protected:
+ InputWindowDialog() {}
+ virtual ~InputWindowDialog() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(InputWindowDialog);
+};
+
+#endif // CHROME_BROWSER_UI_INPUT_WINDOW_DIALOG_H_
diff --git a/chrome/browser/ui/input_window_dialog_gtk.cc b/chrome/browser/ui/input_window_dialog_gtk.cc
new file mode 100644
index 0000000..1530701
--- /dev/null
+++ b/chrome/browser/ui/input_window_dialog_gtk.cc
@@ -0,0 +1,146 @@
+// 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.
+
+#include "chrome/browser/ui/input_window_dialog.h"
+
+#include <gtk/gtk.h>
+
+#include "app/gtk_signal.h"
+#include "base/message_loop.h"
+#include "base/scoped_ptr.h"
+#include "base/string_piece.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/gtk/gtk_util.h"
+
+class InputWindowDialogGtk : public InputWindowDialog {
+ public:
+ // Creates a dialog. Takes ownership of |delegate|.
+ InputWindowDialogGtk(GtkWindow* parent,
+ const std::string& window_title,
+ const std::string& label,
+ const std::string& contents,
+ Delegate* delegate);
+ virtual ~InputWindowDialogGtk();
+
+ virtual void Show();
+ virtual void Close();
+
+ private:
+ CHROMEG_CALLBACK_0(InputWindowDialogGtk, void, OnEntryChanged, GtkEditable*);
+ CHROMEGTK_CALLBACK_1(InputWindowDialogGtk, void, OnResponse, int);
+ CHROMEGTK_CALLBACK_1(InputWindowDialogGtk, gboolean,
+ OnWindowDeleteEvent, GdkEvent*);
+ CHROMEGTK_CALLBACK_0(InputWindowDialogGtk, void, OnWindowDestroy);
+
+ // The underlying gtk dialog window.
+ GtkWidget* dialog_;
+
+ // The GtkEntry in this form.
+ GtkWidget* input_;
+
+ // Our delegate. Consumes the window's output.
+ scoped_ptr<InputWindowDialog::Delegate> delegate_;
+};
+
+
+InputWindowDialogGtk::InputWindowDialogGtk(GtkWindow* parent,
+ const std::string& window_title,
+ const std::string& label,
+ const std::string& contents,
+ Delegate* delegate)
+ : dialog_(gtk_dialog_new_with_buttons(
+ window_title.c_str(),
+ parent,
+ GTK_DIALOG_MODAL,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
+ GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+ NULL)),
+ delegate_(delegate) {
+ gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_ACCEPT);
+ gtk_dialog_set_has_separator(GTK_DIALOG(dialog_), FALSE);
+
+ GtkWidget* content_area = GTK_DIALOG(dialog_)->vbox;
+ gtk_box_set_spacing(GTK_BOX(content_area), 18);
+
+ GtkWidget* hbox = gtk_hbox_new(FALSE, 6);
+ GtkWidget* label_widget = gtk_label_new(label.c_str());
+ gtk_box_pack_start(GTK_BOX(hbox), label_widget, FALSE, FALSE, 0);
+
+ input_ = gtk_entry_new();
+ gtk_entry_set_text(GTK_ENTRY(input_), contents.c_str());
+ g_signal_connect(input_, "changed",
+ G_CALLBACK(OnEntryChangedThunk), this);
+ g_object_set(G_OBJECT(input_), "activates-default", TRUE, NULL);
+ gtk_box_pack_start(GTK_BOX(hbox), input_, TRUE, TRUE, 0);
+
+ gtk_widget_show_all(hbox);
+
+ gtk_box_pack_start(GTK_BOX(content_area), hbox, FALSE, FALSE, 0);
+
+ g_signal_connect(dialog_, "response",
+ G_CALLBACK(OnResponseThunk), this);
+ g_signal_connect(dialog_, "delete-event",
+ G_CALLBACK(OnWindowDeleteEventThunk), this);
+ g_signal_connect(dialog_, "destroy",
+ G_CALLBACK(OnWindowDestroyThunk), this);
+}
+
+InputWindowDialogGtk::~InputWindowDialogGtk() {
+}
+
+void InputWindowDialogGtk::Show() {
+ gtk_util::ShowDialog(dialog_);
+}
+
+void InputWindowDialogGtk::Close() {
+ // Under the model that we've inherited from Windows, dialogs can receive
+ // more than one Close() call inside the current message loop event.
+ if (dialog_) {
+ gtk_widget_destroy(GTK_WIDGET(dialog_));
+ dialog_ = NULL;
+ }
+}
+
+void InputWindowDialogGtk::OnEntryChanged(GtkEditable* entry) {
+ std::wstring value(UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(entry))));
+ gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog_),
+ GTK_RESPONSE_ACCEPT,
+ delegate_->IsValid(value));
+}
+
+void InputWindowDialogGtk::OnResponse(GtkWidget* dialog, int response_id) {
+ if (response_id == GTK_RESPONSE_ACCEPT) {
+ std::wstring value(UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(input_))));
+ delegate_->InputAccepted(value);
+ } else {
+ delegate_->InputCanceled();
+ }
+ Close();
+}
+
+gboolean InputWindowDialogGtk::OnWindowDeleteEvent(GtkWidget* widget,
+ GdkEvent* event) {
+ Close();
+
+ // Return true to prevent the gtk dialog from being destroyed. Close will
+ // destroy it for us and the default gtk_dialog_delete_event_handler() will
+ // force the destruction without us being able to stop it.
+ return TRUE;
+}
+
+void InputWindowDialogGtk::OnWindowDestroy(GtkWidget* widget) {
+ MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+}
+
+InputWindowDialog* InputWindowDialog::Create(gfx::NativeWindow parent,
+ const std::wstring& window_title,
+ const std::wstring& label,
+ const std::wstring& contents,
+ Delegate* delegate) {
+ return new InputWindowDialogGtk(parent,
+ WideToUTF8(window_title),
+ WideToUTF8(label),
+ WideToUTF8(contents),
+ delegate);
+}
diff --git a/chrome/browser/ui/input_window_dialog_win.cc b/chrome/browser/ui/input_window_dialog_win.cc
new file mode 100644
index 0000000..f6b8511
--- /dev/null
+++ b/chrome/browser/ui/input_window_dialog_win.cc
@@ -0,0 +1,235 @@
+// 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.
+
+#include "chrome/browser/ui/input_window_dialog.h"
+
+#include "base/compiler_specific.h"
+#include "base/message_loop.h"
+#include "base/task.h"
+#include "views/grid_layout.h"
+#include "views/controls/label.h"
+#include "views/controls/textfield/textfield.h"
+#include "views/standard_layout.h"
+#include "views/window/dialog_delegate.h"
+#include "views/window/window.h"
+#include "grit/generated_resources.h"
+
+// Width to make the text field, in pixels.
+static const int kTextfieldWidth = 200;
+
+class ContentView;
+
+// The Windows implementation of the cross platform input dialog interface.
+class WinInputWindowDialog : public InputWindowDialog {
+ public:
+ WinInputWindowDialog(HWND parent,
+ const std::wstring& window_title,
+ const std::wstring& label,
+ const std::wstring& contents,
+ Delegate* delegate);
+ virtual ~WinInputWindowDialog();
+
+ virtual void Show();
+ virtual void Close();
+
+ const std::wstring& window_title() const { return window_title_; }
+ const std::wstring& label() const { return label_; }
+ const std::wstring& contents() const { return contents_; }
+
+ InputWindowDialog::Delegate* delegate() { return delegate_.get(); }
+
+ private:
+ // Our chrome views window.
+ views::Window* window_;
+
+ // Strings to feed to the on screen window.
+ std::wstring window_title_;
+ std::wstring label_;
+ std::wstring contents_;
+
+ // Our delegate. Consumes the window's output.
+ scoped_ptr<InputWindowDialog::Delegate> delegate_;
+};
+
+// ContentView, as the name implies, is the content view for the InputWindow.
+// It registers accelerators that accept/cancel the input.
+class ContentView : public views::View,
+ public views::DialogDelegate,
+ public views::Textfield::Controller {
+ public:
+ explicit ContentView(WinInputWindowDialog* delegate)
+ : delegate_(delegate),
+ ALLOW_THIS_IN_INITIALIZER_LIST(focus_grabber_factory_(this)) {
+ DCHECK(delegate_);
+ }
+
+ // views::DialogDelegate overrides:
+ virtual bool IsDialogButtonEnabled(
+ MessageBoxFlags::DialogButton button) const;
+ virtual bool Accept();
+ virtual bool Cancel();
+ virtual void DeleteDelegate();
+ virtual std::wstring GetWindowTitle() const;
+ virtual bool IsModal() const { return true; }
+ virtual views::View* GetContentsView();
+
+ // views::Textfield::Controller overrides:
+ virtual void ContentsChanged(views::Textfield* sender,
+ const std::wstring& new_contents);
+ virtual bool HandleKeystroke(views::Textfield*,
+ const views::Textfield::Keystroke&) {
+ return false;
+ }
+
+ protected:
+ // views::View overrides:
+ virtual void ViewHierarchyChanged(bool is_add, views::View* parent,
+ views::View* child);
+
+ private:
+ // Set up dialog controls and layout.
+ void InitControlLayout();
+
+ // Sets focus to the first focusable element within the dialog.
+ void FocusFirstFocusableControl();
+
+ // The Textfield that the user can type into.
+ views::Textfield* text_field_;
+
+ // The delegate that the ContentView uses to communicate changes to the
+ // caller.
+ WinInputWindowDialog* delegate_;
+
+ // Helps us set focus to the first Textfield in the window.
+ ScopedRunnableMethodFactory<ContentView> focus_grabber_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContentView);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// ContentView, views::DialogDelegate implementation:
+
+bool ContentView::IsDialogButtonEnabled(
+ MessageBoxFlags::DialogButton button) const {
+ if (button == MessageBoxFlags::DIALOGBUTTON_OK &&
+ !delegate_->delegate()->IsValid(text_field_->text())) {
+ return false;
+ }
+ return true;
+}
+
+bool ContentView::Accept() {
+ delegate_->delegate()->InputAccepted(text_field_->text());
+ return true;
+}
+
+bool ContentView::Cancel() {
+ delegate_->delegate()->InputCanceled();
+ return true;
+}
+
+void ContentView::DeleteDelegate() {
+ delete delegate_;
+}
+
+std::wstring ContentView::GetWindowTitle() const {
+ return delegate_->window_title();
+}
+
+views::View* ContentView::GetContentsView() {
+ return this;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ContentView, views::Textfield::Controller implementation:
+
+void ContentView::ContentsChanged(views::Textfield* sender,
+ const std::wstring& new_contents) {
+ GetDialogClientView()->UpdateDialogButtons();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ContentView, protected:
+
+void ContentView::ViewHierarchyChanged(bool is_add,
+ views::View* parent,
+ views::View* child) {
+ if (is_add && child == this)
+ InitControlLayout();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ContentView, private:
+
+void ContentView::InitControlLayout() {
+ text_field_ = new views::Textfield;
+ text_field_->SetText(delegate_->contents());
+ text_field_->SetController(this);
+
+ using views::ColumnSet;
+ using views::GridLayout;
+
+ // TODO(sky): Vertical alignment should be baseline.
+ GridLayout* layout = CreatePanelGridLayout(this);
+ SetLayoutManager(layout);
+
+ ColumnSet* c1 = layout->AddColumnSet(0);
+ c1->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0,
+ GridLayout::USE_PREF, 0, 0);
+ c1->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
+ c1->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
+ GridLayout::USE_PREF, kTextfieldWidth, kTextfieldWidth);
+
+ layout->StartRow(0, 0);
+ views::Label* label = new views::Label(delegate_->label());
+ layout->AddView(label);
+ layout->AddView(text_field_);
+
+ MessageLoop::current()->PostTask(FROM_HERE,
+ focus_grabber_factory_.NewRunnableMethod(
+ &ContentView::FocusFirstFocusableControl));
+}
+
+void ContentView::FocusFirstFocusableControl() {
+ text_field_->SelectAll();
+ text_field_->RequestFocus();
+}
+
+WinInputWindowDialog::WinInputWindowDialog(HWND parent,
+ const std::wstring& window_title,
+ const std::wstring& label,
+ const std::wstring& contents,
+ Delegate* delegate)
+ : window_title_(window_title),
+ label_(label),
+ contents_(contents),
+ delegate_(delegate) {
+ window_ = views::Window::CreateChromeWindow(parent, gfx::Rect(),
+ new ContentView(this));
+ window_->GetClientView()->AsDialogClientView()->UpdateDialogButtons();
+}
+
+WinInputWindowDialog::~WinInputWindowDialog() {
+}
+
+void WinInputWindowDialog::Show() {
+ window_->Show();
+}
+
+void WinInputWindowDialog::Close() {
+ window_->Close();
+}
+
+// static
+InputWindowDialog* InputWindowDialog::Create(HWND parent,
+ const std::wstring& window_title,
+ const std::wstring& label,
+ const std::wstring& contents,
+ Delegate* delegate) {
+ return new WinInputWindowDialog(parent,
+ window_title,
+ label,
+ contents,
+ delegate);
+}
diff --git a/chrome/browser/ui/login/login_model.h b/chrome/browser/ui/login/login_model.h
new file mode 100644
index 0000000..94d3478
--- /dev/null
+++ b/chrome/browser/ui/login/login_model.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_LOGIN_LOGIN_MODEL_H_
+#define CHROME_BROWSER_UI_LOGIN_LOGIN_MODEL_H_
+#pragma once
+
+#include <string>
+
+// Simple Model & Observer interfaces for a LoginView to facilitate exchanging
+// information.
+class LoginModelObserver {
+ public:
+ // Called by the model when a username,password pair has been identified
+ // as a match for the pending login prompt.
+ virtual void OnAutofillDataAvailable(const std::wstring& username,
+ const std::wstring& password) = 0;
+
+ protected:
+ virtual ~LoginModelObserver() {}
+};
+
+class LoginModel {
+ public:
+ // Set the observer interested in the data from the model.
+ // observer can be null, signifying there is no longer any observer
+ // interested in the data.
+ virtual void SetObserver(LoginModelObserver* observer) = 0;
+
+ protected:
+ virtual ~LoginModel() {}
+};
+
+#endif // CHROME_BROWSER_UI_LOGIN_LOGIN_MODEL_H_
diff --git a/chrome/browser/ui/login/login_prompt.cc b/chrome/browser/ui/login/login_prompt.cc
new file mode 100644
index 0000000..d653457
--- /dev/null
+++ b/chrome/browser/ui/login/login_prompt.cc
@@ -0,0 +1,453 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/login/login_prompt.h"
+
+#include <vector>
+
+#include "app/l10n_util.h"
+#include "base/command_line.h"
+#include "base/lock.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/password_manager/password_manager.h"
+#include "chrome/browser/renderer_host/render_process_host.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
+#include "chrome/browser/tab_contents/constrained_window.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_util.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/notification_service.h"
+#include "grit/generated_resources.h"
+#include "net/base/auth.h"
+#include "net/base/net_util.h"
+#include "net/url_request/url_request.h"
+
+using webkit_glue::PasswordForm;
+
+class LoginHandlerImpl;
+
+// Helper to remove the ref from an net::URLRequest to the LoginHandler.
+// Should only be called from the IO thread, since it accesses an
+// net::URLRequest.
+void ResetLoginHandlerForRequest(net::URLRequest* request) {
+ ResourceDispatcherHostRequestInfo* info =
+ ResourceDispatcherHost::InfoForRequest(request);
+ if (!info)
+ return;
+
+ info->set_login_handler(NULL);
+}
+
+// Get the signon_realm under which this auth info should be stored.
+//
+// The format of the signon_realm for proxy auth is:
+// proxy-host/auth-realm
+// The format of the signon_realm for server auth is:
+// url-scheme://url-host[:url-port]/auth-realm
+//
+// Be careful when changing this function, since you could make existing
+// saved logins un-retrievable.
+std::string GetSignonRealm(const GURL& url,
+ const net::AuthChallengeInfo& auth_info) {
+ std::string signon_realm;
+ if (auth_info.is_proxy) {
+ signon_realm = WideToASCII(auth_info.host_and_port);
+ signon_realm.append("/");
+ } else {
+ // Take scheme, host, and port from the url.
+ signon_realm = url.GetOrigin().spec();
+ // This ends with a "/".
+ }
+ signon_realm.append(WideToUTF8(auth_info.realm));
+ return signon_realm;
+}
+
+// ----------------------------------------------------------------------------
+// LoginHandler
+
+LoginHandler::LoginHandler(net::AuthChallengeInfo* auth_info,
+ net::URLRequest* request)
+ : handled_auth_(false),
+ dialog_(NULL),
+ auth_info_(auth_info),
+ request_(request),
+ password_manager_(NULL),
+ login_model_(NULL) {
+ // This constructor is called on the I/O thread, so we cannot load the nib
+ // here. BuildViewForPasswordManager() will be invoked on the UI thread
+ // later, so wait with loading the nib until then.
+ DCHECK(request_) << "LoginHandler constructed with NULL request";
+ DCHECK(auth_info_) << "LoginHandler constructed with NULL auth info";
+
+ AddRef(); // matched by LoginHandler::ReleaseSoon().
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(this, &LoginHandler::AddObservers));
+
+ if (!ResourceDispatcherHost::RenderViewForRequest(
+ request_, &render_process_host_id_, &tab_contents_id_)) {
+ NOTREACHED();
+ }
+}
+
+LoginHandler::~LoginHandler() {
+ SetModel(NULL);
+}
+
+void LoginHandler::SetPasswordForm(const webkit_glue::PasswordForm& form) {
+ password_form_ = form;
+}
+
+void LoginHandler::SetPasswordManager(PasswordManager* password_manager) {
+ password_manager_ = password_manager;
+}
+
+TabContents* LoginHandler::GetTabContentsForLogin() const {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ return tab_util::GetTabContentsByID(render_process_host_id_,
+ tab_contents_id_);
+}
+
+void LoginHandler::SetAuth(const std::wstring& username,
+ const std::wstring& password) {
+ if (WasAuthHandled(true))
+ return;
+
+ // Tell the password manager the credentials were submitted / accepted.
+ if (password_manager_) {
+ password_form_.username_value = WideToUTF16Hack(username);
+ password_form_.password_value = WideToUTF16Hack(password);
+ password_manager_->ProvisionallySavePassword(password_form_);
+ }
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(this, &LoginHandler::CloseContentsDeferred));
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ this, &LoginHandler::NotifyAuthSupplied, username, password));
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(
+ this, &LoginHandler::SetAuthDeferred, username, password));
+}
+
+void LoginHandler::CancelAuth() {
+ if (WasAuthHandled(true))
+ return;
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(this, &LoginHandler::CloseContentsDeferred));
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(this, &LoginHandler::NotifyAuthCancelled));
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(this, &LoginHandler::CancelAuthDeferred));
+}
+
+void LoginHandler::OnRequestCancelled() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)) <<
+ "Why is OnRequestCancelled called from the UI thread?";
+
+ // Reference is no longer valid.
+ request_ = NULL;
+
+ // Give up on auth if the request was cancelled.
+ CancelAuth();
+}
+
+void LoginHandler::AddObservers() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ registrar_.Add(this, NotificationType::AUTH_SUPPLIED,
+ NotificationService::AllSources());
+ registrar_.Add(this, NotificationType::AUTH_CANCELLED,
+ NotificationService::AllSources());
+}
+
+void LoginHandler::RemoveObservers() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ registrar_.Remove(this, NotificationType::AUTH_SUPPLIED,
+ NotificationService::AllSources());
+ registrar_.Remove(this, NotificationType::AUTH_CANCELLED,
+ NotificationService::AllSources());
+
+ DCHECK(registrar_.IsEmpty());
+}
+
+void LoginHandler::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(type == NotificationType::AUTH_SUPPLIED ||
+ type == NotificationType::AUTH_CANCELLED);
+
+ TabContents* requesting_contents = GetTabContentsForLogin();
+ if (!requesting_contents)
+ return;
+
+ NavigationController* this_controller = &requesting_contents->controller();
+ NavigationController* that_controller =
+ Source<NavigationController>(source).ptr();
+
+ // Only handle notifications from other handlers.
+ if (this_controller == that_controller)
+ return;
+
+ LoginNotificationDetails* login_details =
+ Details<LoginNotificationDetails>(details).ptr();
+
+ // Only handle notification for the identical auth info.
+ if (*login_details->handler()->auth_info() != *auth_info())
+ return;
+
+ // Set or cancel the auth in this handler.
+ if (type == NotificationType::AUTH_SUPPLIED) {
+ AuthSuppliedLoginNotificationDetails* supplied_details =
+ Details<AuthSuppliedLoginNotificationDetails>(details).ptr();
+ SetAuth(supplied_details->username(), supplied_details->password());
+ } else {
+ DCHECK(type == NotificationType::AUTH_CANCELLED);
+ CancelAuth();
+ }
+}
+
+void LoginHandler::SetModel(LoginModel* model) {
+ if (login_model_)
+ login_model_->SetObserver(NULL);
+ login_model_ = model;
+ if (login_model_)
+ login_model_->SetObserver(this);
+}
+
+void LoginHandler::SetDialog(ConstrainedWindow* dialog) {
+ dialog_ = dialog;
+}
+
+void LoginHandler::NotifyAuthNeeded() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (WasAuthHandled(false))
+ return;
+
+ TabContents* requesting_contents = GetTabContentsForLogin();
+ if (!requesting_contents)
+ return;
+
+ NotificationService* service = NotificationService::current();
+ NavigationController* controller = &requesting_contents->controller();
+ LoginNotificationDetails details(this);
+
+ service->Notify(NotificationType::AUTH_NEEDED,
+ Source<NavigationController>(controller),
+ Details<LoginNotificationDetails>(&details));
+}
+
+void LoginHandler::NotifyAuthCancelled() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(WasAuthHandled(false));
+
+ TabContents* requesting_contents = GetTabContentsForLogin();
+ if (!requesting_contents)
+ return;
+
+ NotificationService* service = NotificationService::current();
+ NavigationController* controller = &requesting_contents->controller();
+ LoginNotificationDetails details(this);
+
+ service->Notify(NotificationType::AUTH_CANCELLED,
+ Source<NavigationController>(controller),
+ Details<LoginNotificationDetails>(&details));
+}
+
+void LoginHandler::NotifyAuthSupplied(const std::wstring& username,
+ const std::wstring& password) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(WasAuthHandled(false));
+
+ TabContents* requesting_contents = GetTabContentsForLogin();
+ if (!requesting_contents)
+ return;
+
+ NotificationService* service = NotificationService::current();
+ NavigationController* controller = &requesting_contents->controller();
+ AuthSuppliedLoginNotificationDetails details(this, username, password);
+
+ service->Notify(NotificationType::AUTH_SUPPLIED,
+ Source<NavigationController>(controller),
+ Details<AuthSuppliedLoginNotificationDetails>(&details));
+}
+
+void LoginHandler::ReleaseSoon() {
+ if (!WasAuthHandled(true)) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(this, &LoginHandler::CancelAuthDeferred));
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(this, &LoginHandler::NotifyAuthCancelled));
+ }
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(this, &LoginHandler::RemoveObservers));
+
+ // Delete this object once all InvokeLaters have been called.
+ BrowserThread::ReleaseSoon(BrowserThread::IO, FROM_HERE, this);
+}
+
+// Returns whether authentication had been handled (SetAuth or CancelAuth).
+// If |set_handled| is true, it will mark authentication as handled.
+bool LoginHandler::WasAuthHandled(bool set_handled) {
+ AutoLock lock(handled_auth_lock_);
+ bool was_handled = handled_auth_;
+ if (set_handled)
+ handled_auth_ = true;
+ return was_handled;
+}
+
+// Calls SetAuth from the IO loop.
+void LoginHandler::SetAuthDeferred(const std::wstring& username,
+ const std::wstring& password) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ if (request_) {
+ request_->SetAuth(WideToUTF16Hack(username), WideToUTF16Hack(password));
+ ResetLoginHandlerForRequest(request_);
+ }
+}
+
+// Calls CancelAuth from the IO loop.
+void LoginHandler::CancelAuthDeferred() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ if (request_) {
+ request_->CancelAuth();
+ // Verify that CancelAuth doesn't destroy the request via our delegate.
+ DCHECK(request_ != NULL);
+ ResetLoginHandlerForRequest(request_);
+ }
+}
+
+// Closes the view_contents from the UI loop.
+void LoginHandler::CloseContentsDeferred() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // The hosting ConstrainedWindow may have been freed.
+ if (dialog_)
+ dialog_->CloseConstrainedWindow();
+}
+
+// ----------------------------------------------------------------------------
+// LoginDialogTask
+
+// This task is run on the UI thread and creates a constrained window with
+// a LoginView to prompt the user. The response will be sent to LoginHandler,
+// which then routes it to the net::URLRequest on the I/O thread.
+class LoginDialogTask : public Task {
+ public:
+ LoginDialogTask(const GURL& request_url,
+ net::AuthChallengeInfo* auth_info,
+ LoginHandler* handler)
+ : request_url_(request_url), auth_info_(auth_info), handler_(handler) {
+ }
+ virtual ~LoginDialogTask() {
+ }
+
+ void Run() {
+ TabContents* parent_contents = handler_->GetTabContentsForLogin();
+ if (!parent_contents) {
+ // The request may have been cancelled, or it may be for a renderer
+ // not hosted by a tab (e.g. an extension). Cancel just in case
+ // (cancelling twice is a no-op).
+ handler_->CancelAuth();
+ return;
+ }
+
+ // Tell the password manager to look for saved passwords.
+ TabContentsWrapper** wrapper =
+ TabContentsWrapper::property_accessor()->GetProperty(
+ parent_contents->property_bag());
+ if (!wrapper)
+ return;
+ PasswordManager* password_manager = (*wrapper)->GetPasswordManager();
+ std::vector<PasswordForm> v;
+ MakeInputForPasswordManager(&v);
+ password_manager->PasswordFormsFound(v);
+ handler_->SetPasswordManager(password_manager);
+
+ std::wstring explanation = auth_info_->realm.empty() ?
+ l10n_util::GetStringF(IDS_LOGIN_DIALOG_DESCRIPTION_NO_REALM,
+ auth_info_->host_and_port) :
+ l10n_util::GetStringF(IDS_LOGIN_DIALOG_DESCRIPTION,
+ auth_info_->host_and_port,
+ auth_info_->realm);
+ handler_->BuildViewForPasswordManager(password_manager,
+ explanation);
+ }
+
+ private:
+ // Helper to create a PasswordForm and stuff it into a vector as input
+ // for PasswordManager::PasswordFormsFound, the hook into PasswordManager.
+ void MakeInputForPasswordManager(
+ std::vector<PasswordForm>* password_manager_input) {
+ PasswordForm dialog_form;
+ if (LowerCaseEqualsASCII(auth_info_->scheme, "basic")) {
+ dialog_form.scheme = PasswordForm::SCHEME_BASIC;
+ } else if (LowerCaseEqualsASCII(auth_info_->scheme, "digest")) {
+ dialog_form.scheme = PasswordForm::SCHEME_DIGEST;
+ } else {
+ dialog_form.scheme = PasswordForm::SCHEME_OTHER;
+ }
+ std::string host_and_port(WideToASCII(auth_info_->host_and_port));
+ if (auth_info_->is_proxy) {
+ std::string origin = host_and_port;
+ // We don't expect this to already start with http:// or https://.
+ DCHECK(origin.find("http://") != 0 && origin.find("https://") != 0);
+ origin = std::string("http://") + origin;
+ dialog_form.origin = GURL(origin);
+ } else if (net::GetHostAndPort(request_url_) != host_and_port) {
+ dialog_form.origin = GURL();
+ NOTREACHED(); // crbug.com/32718
+ } else {
+ dialog_form.origin = GURL(request_url_.scheme() + "://" + host_and_port);
+ }
+ dialog_form.signon_realm = GetSignonRealm(dialog_form.origin, *auth_info_);
+ password_manager_input->push_back(dialog_form);
+ // Set the password form for the handler (by copy).
+ handler_->SetPasswordForm(dialog_form);
+ }
+
+ // The url from the net::URLRequest initiating the auth challenge.
+ GURL request_url_;
+
+ // Info about who/where/what is asking for authentication.
+ scoped_refptr<net::AuthChallengeInfo> auth_info_;
+
+ // Where to send the authentication when obtained.
+ // This is owned by the ResourceDispatcherHost that invoked us.
+ LoginHandler* handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(LoginDialogTask);
+};
+
+// ----------------------------------------------------------------------------
+// Public API
+
+LoginHandler* CreateLoginPrompt(net::AuthChallengeInfo* auth_info,
+ net::URLRequest* request) {
+ LoginHandler* handler = LoginHandler::Create(auth_info, request);
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE, new LoginDialogTask(
+ request->url(), auth_info, handler));
+ return handler;
+}
diff --git a/chrome/browser/ui/login/login_prompt.h b/chrome/browser/ui/login/login_prompt.h
new file mode 100644
index 0000000..8e3d15e
--- /dev/null
+++ b/chrome/browser/ui/login/login_prompt.h
@@ -0,0 +1,214 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_LOGIN_LOGIN_PROMPT_H_
+#define CHROME_BROWSER_UI_LOGIN_LOGIN_PROMPT_H_
+#pragma once
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/lock.h"
+#include "base/ref_counted.h"
+#include "chrome/browser/password_manager/password_manager.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+
+namespace net {
+class AuthChallengeInfo;
+class URLRequest;
+} // namespace net
+
+class ConstrainedWindow;
+class GURL;
+
+// This is the base implementation for the OS-specific classes that route
+// authentication info to the net::URLRequest that needs it. These functions
+// must be implemented in a thread safe manner.
+class LoginHandler : public base::RefCountedThreadSafe<LoginHandler>,
+ public LoginModelObserver,
+ public NotificationObserver {
+ public:
+ LoginHandler(net::AuthChallengeInfo* auth_info, net::URLRequest* request);
+ virtual ~LoginHandler();
+
+ // Builds the platform specific LoginHandler. Used from within
+ // CreateLoginPrompt() which creates tasks.
+ static LoginHandler* Create(net::AuthChallengeInfo* auth_info,
+ net::URLRequest* request);
+
+ // Initializes the underlying platform specific view.
+ virtual void BuildViewForPasswordManager(PasswordManager* manager,
+ std::wstring explanation) = 0;
+
+ // Sets information about the authentication type (|form|) and the
+ // |password_manager| for this profile.
+ void SetPasswordForm(const webkit_glue::PasswordForm& form);
+ void SetPasswordManager(PasswordManager* password_manager);
+
+ // Returns the TabContents that needs authentication.
+ TabContents* GetTabContentsForLogin() const;
+
+ // Resend the request with authentication credentials.
+ // This function can be called from either thread.
+ void SetAuth(const std::wstring& username, const std::wstring& password);
+
+ // Display the error page without asking for credentials again.
+ // This function can be called from either thread.
+ void CancelAuth();
+
+ // Notify the handler that the request was cancelled.
+ // This function can only be called from the IO thread.
+ void OnRequestCancelled();
+
+ // Implements the NotificationObserver interface.
+ // Listens for AUTH_SUPPLIED and AUTH_CANCELLED notifications from other
+ // LoginHandlers so that this LoginHandler has the chance to dismiss itself
+ // if it was waiting for the same authentication.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ protected:
+ void SetModel(LoginModel* model);
+
+ void SetDialog(ConstrainedWindow* dialog);
+
+ // Notify observers that authentication is needed.
+ void NotifyAuthNeeded();
+
+ // Performs necessary cleanup before deletion.
+ void ReleaseSoon();
+
+ // Who/where/what asked for the authentication.
+ net::AuthChallengeInfo* auth_info() const { return auth_info_.get(); }
+
+ private:
+ // Starts observing notifications from other LoginHandlers.
+ void AddObservers();
+
+ // Stops observing notifications from other LoginHandlers.
+ void RemoveObservers();
+
+ // Notify observers that authentication is supplied.
+ void NotifyAuthSupplied(const std::wstring& username,
+ const std::wstring& password);
+
+ // Notify observers that authentication is cancelled.
+ void NotifyAuthCancelled();
+
+ // Returns whether authentication had been handled (SetAuth or CancelAuth).
+ // If |set_handled| is true, it will mark authentication as handled.
+ bool WasAuthHandled(bool set_handled);
+
+ // Calls SetAuth from the IO loop.
+ void SetAuthDeferred(const std::wstring& username,
+ const std::wstring& password);
+
+ // Calls CancelAuth from the IO loop.
+ void CancelAuthDeferred();
+
+ // Closes the view_contents from the UI loop.
+ void CloseContentsDeferred();
+
+ // True if we've handled auth (SetAuth or CancelAuth has been called).
+ bool handled_auth_;
+ Lock handled_auth_lock_;
+
+ // The ConstrainedWindow that is hosting our LoginView.
+ // This should only be accessed on the UI loop.
+ ConstrainedWindow* dialog_;
+
+ // Who/where/what asked for the authentication.
+ scoped_refptr<net::AuthChallengeInfo> auth_info_;
+
+ // The request that wants login data.
+ // This should only be accessed on the IO loop.
+ net::URLRequest* request_;
+
+ // The PasswordForm sent to the PasswordManager. This is so we can refer to it
+ // when later notifying the password manager if the credentials were accepted
+ // or rejected.
+ // This should only be accessed on the UI loop.
+ webkit_glue::PasswordForm password_form_;
+
+ // Points to the password manager owned by the TabContents requesting auth.
+ // Can be null if the TabContents is not a TabContents.
+ // This should only be accessed on the UI loop.
+ PasswordManager* password_manager_;
+
+ // Cached from the net::URLRequest, in case it goes NULL on us.
+ int render_process_host_id_;
+ int tab_contents_id_;
+
+ // If not null, points to a model we need to notify of our own destruction
+ // so it doesn't try and access this when its too late.
+ LoginModel* login_model_;
+
+ // Observes other login handlers so this login handler can respond.
+ NotificationRegistrar registrar_;
+};
+
+// Details to provide the NotificationObserver. Used by the automation proxy
+// for testing.
+class LoginNotificationDetails {
+ public:
+ explicit LoginNotificationDetails(LoginHandler* handler)
+ : handler_(handler) {}
+ LoginHandler* handler() const { return handler_; }
+
+ private:
+ LoginNotificationDetails() {}
+
+ LoginHandler* handler_; // Where to send the response.
+
+ DISALLOW_COPY_AND_ASSIGN(LoginNotificationDetails);
+};
+
+// Details to provide the NotificationObserver. Used by the automation proxy
+// for testing and by other LoginHandlers to dismiss themselves when an
+// identical auth is supplied.
+class AuthSuppliedLoginNotificationDetails : public LoginNotificationDetails {
+ public:
+ AuthSuppliedLoginNotificationDetails(LoginHandler* handler,
+ const std::wstring& username,
+ const std::wstring& password)
+ : LoginNotificationDetails(handler),
+ username_(username),
+ password_(password) {}
+ const std::wstring& username() const { return username_; }
+ const std::wstring& password() const { return password_; }
+
+ private:
+ // The username that was used for the authentication.
+ const std::wstring username_;
+
+ // The password that was used for the authentication.
+ const std::wstring password_;
+
+ DISALLOW_COPY_AND_ASSIGN(AuthSuppliedLoginNotificationDetails);
+};
+
+// Prompts the user for their username and password. This is designed to
+// be called on the background (I/O) thread, in response to
+// net::URLRequest::Delegate::OnAuthRequired. The prompt will be created
+// on the main UI thread via a call to UI loop's InvokeLater, and will send the
+// credentials back to the net::URLRequest on the calling thread.
+// A LoginHandler object (which lives on the calling thread) is returned,
+// which can be used to set or cancel authentication programmatically. The
+// caller must invoke OnRequestCancelled() on this LoginHandler before
+// destroying the net::URLRequest.
+LoginHandler* CreateLoginPrompt(net::AuthChallengeInfo* auth_info,
+ net::URLRequest* request);
+
+// Helper to remove the ref from an net::URLRequest to the LoginHandler.
+// Should only be called from the IO thread, since it accesses an
+// net::URLRequest.
+void ResetLoginHandlerForRequest(net::URLRequest* request);
+
+// Get the signon_realm under which the identity should be saved.
+std::string GetSignonRealm(const GURL& url,
+ const net::AuthChallengeInfo& auth_info);
+
+#endif // CHROME_BROWSER_UI_LOGIN_LOGIN_PROMPT_H_
diff --git a/chrome/browser/ui/login/login_prompt_gtk.cc b/chrome/browser/ui/login/login_prompt_gtk.cc
new file mode 100644
index 0000000..8cdd6e0
--- /dev/null
+++ b/chrome/browser/ui/login/login_prompt_gtk.cc
@@ -0,0 +1,198 @@
+// 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.
+
+#include "chrome/browser/ui/login/login_prompt.h"
+
+#include <gtk/gtk.h>
+
+#include "app/l10n_util.h"
+#include "app/gtk_signal.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/gtk/constrained_window_gtk.h"
+#include "chrome/browser/gtk/gtk_util.h"
+#include "chrome/browser/password_manager/password_manager.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+#include "chrome/browser/tab_contents/navigation_controller.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_contents_delegate.h"
+#include "chrome/browser/tab_contents/tab_contents_view_gtk.h"
+#include "chrome/browser/tab_contents/tab_util.h"
+#include "chrome/browser/ui/login/login_model.h"
+#include "grit/generated_resources.h"
+#include "net/url_request/url_request.h"
+
+using webkit_glue::PasswordForm;
+
+// ----------------------------------------------------------------------------
+// LoginHandlerGtk
+
+// This class simply forwards the authentication from the LoginView (on
+// the UI thread) to the net::URLRequest (on the I/O thread).
+// This class uses ref counting to ensure that it lives until all InvokeLaters
+// have been called.
+class LoginHandlerGtk : public LoginHandler,
+ public ConstrainedWindowGtkDelegate {
+ public:
+ LoginHandlerGtk(net::AuthChallengeInfo* auth_info, net::URLRequest* request)
+ : LoginHandler(auth_info, request),
+ username_entry_(NULL),
+ password_entry_(NULL),
+ ok_(NULL) {
+ }
+
+ virtual ~LoginHandlerGtk() {
+ root_.Destroy();
+ }
+
+ // LoginModelObserver implementation.
+ virtual void OnAutofillDataAvailable(const std::wstring& username,
+ const std::wstring& password) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // NOTE: Would be nice to use gtk_entry_get_text_length, but it is fairly
+ // new and not always in our GTK version.
+ if (strlen(gtk_entry_get_text(GTK_ENTRY(username_entry_))) == 0) {
+ gtk_entry_set_text(GTK_ENTRY(username_entry_),
+ WideToUTF8(username).c_str());
+ gtk_entry_set_text(GTK_ENTRY(password_entry_),
+ WideToUTF8(password).c_str());
+ gtk_editable_select_region(GTK_EDITABLE(username_entry_), 0, -1);
+ }
+ }
+
+ // LoginHandler:
+ virtual void BuildViewForPasswordManager(PasswordManager* manager,
+ std::wstring explanation) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ root_.Own(gtk_vbox_new(FALSE, gtk_util::kContentAreaBorder));
+ GtkWidget* label = gtk_label_new(WideToUTF8(explanation).c_str());
+ gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+ gtk_box_pack_start(GTK_BOX(root_.get()), label, FALSE, FALSE, 0);
+
+ username_entry_ = gtk_entry_new();
+ gtk_entry_set_activates_default(GTK_ENTRY(username_entry_), TRUE);
+
+ password_entry_ = gtk_entry_new();
+ gtk_entry_set_activates_default(GTK_ENTRY(password_entry_), TRUE);
+ gtk_entry_set_visibility(GTK_ENTRY(password_entry_), FALSE);
+
+ GtkWidget* table = gtk_util::CreateLabeledControlsGroup(NULL,
+ l10n_util::GetStringUTF8(IDS_LOGIN_DIALOG_USERNAME_FIELD).c_str(),
+ username_entry_,
+ l10n_util::GetStringUTF8(IDS_LOGIN_DIALOG_PASSWORD_FIELD).c_str(),
+ password_entry_,
+ NULL);
+ gtk_box_pack_start(GTK_BOX(root_.get()), table, FALSE, FALSE, 0);
+
+ GtkWidget* hbox = gtk_hbox_new(FALSE, 12);
+ gtk_box_pack_start(GTK_BOX(root_.get()), hbox, FALSE, FALSE, 0);
+
+ ok_ = gtk_button_new_from_stock(GTK_STOCK_OK);
+ gtk_button_set_label(
+ GTK_BUTTON(ok_),
+ l10n_util::GetStringUTF8(IDS_LOGIN_DIALOG_OK_BUTTON_LABEL).c_str());
+ g_signal_connect(ok_, "clicked", G_CALLBACK(OnOKClickedThunk), this);
+ gtk_box_pack_end(GTK_BOX(hbox), ok_, FALSE, FALSE, 0);
+
+ GtkWidget* cancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
+ g_signal_connect(cancel, "clicked", G_CALLBACK(OnCancelClickedThunk), this);
+ gtk_box_pack_end(GTK_BOX(hbox), cancel, FALSE, FALSE, 0);
+
+ g_signal_connect(root_.get(), "hierarchy-changed",
+ G_CALLBACK(OnPromptHierarchyChangedThunk), this);
+
+ SetModel(manager);
+
+ // Scary thread safety note: This can potentially be called *after* SetAuth
+ // or CancelAuth (say, if the request was cancelled before the UI thread got
+ // control). However, that's OK since any UI interaction in those functions
+ // will occur via an InvokeLater on the UI thread, which is guaranteed
+ // to happen after this is called (since this was InvokeLater'd first).
+ SetDialog(GetTabContentsForLogin()->CreateConstrainedDialog(this));
+
+ NotifyAuthNeeded();
+ }
+
+ // Overridden from ConstrainedWindowGtkDelegate:
+ virtual GtkWidget* GetWidgetRoot() {
+ return root_.get();
+ }
+
+ virtual void DeleteDelegate() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // The constrained window is going to delete itself; clear our pointer.
+ SetDialog(NULL);
+ SetModel(NULL);
+
+ ReleaseSoon();
+ }
+
+ private:
+ friend class LoginPrompt;
+
+ CHROMEGTK_CALLBACK_0(LoginHandlerGtk, void, OnOKClicked);
+ CHROMEGTK_CALLBACK_0(LoginHandlerGtk, void, OnCancelClicked);
+ CHROMEGTK_CALLBACK_1(LoginHandlerGtk, void, OnPromptHierarchyChanged,
+ GtkWidget*);
+
+ // The GtkWidgets that form our visual hierarchy:
+ // The root container we pass to our parent.
+ OwnedWidgetGtk root_;
+
+ // GtkEntry widgets that the user types into.
+ GtkWidget* username_entry_;
+ GtkWidget* password_entry_;
+ GtkWidget* ok_;
+
+ DISALLOW_COPY_AND_ASSIGN(LoginHandlerGtk);
+};
+
+void LoginHandlerGtk::OnOKClicked(GtkWidget* sender) {
+ SetAuth(
+ UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(username_entry_))),
+ UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(password_entry_))));
+}
+
+void LoginHandlerGtk::OnCancelClicked(GtkWidget* sender) {
+ CancelAuth();
+}
+
+void LoginHandlerGtk::OnPromptHierarchyChanged(GtkWidget* sender,
+ GtkWidget* previous_toplevel) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (!GTK_WIDGET_TOPLEVEL(gtk_widget_get_toplevel(ok_)))
+ return;
+
+ // Now that we have attached ourself to the window, we can make our OK
+ // button the default action and mess with the focus.
+ GTK_WIDGET_SET_FLAGS(ok_, GTK_CAN_DEFAULT);
+ gtk_widget_grab_default(ok_);
+
+ TabContents* contents = GetTabContentsForLogin();
+
+ // The user may have focused another tab. In this case do not grab focus
+ // until this tab is refocused.
+ if ((!contents->delegate() ||
+ contents->delegate()->ShouldFocusConstrainedWindow()) &&
+ gtk_util::IsWidgetAncestryVisible(username_entry_)) {
+ gtk_widget_grab_focus(username_entry_);
+ } else {
+ // TODO(estade): this define should not need to be here because this class
+ // should not be used on linux/views.
+#if defined(TOOLKIT_GTK)
+ static_cast<TabContentsViewGtk*>(contents->view())->
+ SetFocusedWidget(username_entry_);
+#endif
+ }
+}
+
+// static
+LoginHandler* LoginHandler::Create(net::AuthChallengeInfo* auth_info,
+ net::URLRequest* request) {
+ return new LoginHandlerGtk(auth_info, request);
+}
diff --git a/chrome/browser/ui/login/login_prompt_mac.h b/chrome/browser/ui/login/login_prompt_mac.h
new file mode 100644
index 0000000..bf0677d
--- /dev/null
+++ b/chrome/browser/ui/login/login_prompt_mac.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_LOGIN_LOGIN_PROMPT_MAC_H_
+#define CHROME_BROWSER_UI_LOGIN_LOGIN_PROMPT_MAC_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+
+class LoginHandlerMac;
+
+// Controller of the sheet used by LoginHandlerMac. Interface Builder wants
+// this to be in a .h file.
+@interface LoginHandlerSheet : NSWindowController {
+ @private
+ IBOutlet NSTextField* nameField_;
+ IBOutlet NSSecureTextField* passwordField_;
+ IBOutlet NSTextField* explanationField_;
+ IBOutlet NSButton* loginButton_;
+ IBOutlet NSButton* cancelButton_;
+ LoginHandlerMac* handler_; // weak, owns us
+}
+- (id)initWithLoginHandler:(LoginHandlerMac*)handler;
+- (IBAction)loginPressed:(id)sender;
+- (IBAction)cancelPressed:(id)sender;
+- (void)sheetDidEnd:(NSWindow*)sheet
+ returnCode:(int)returnCode
+ contextInfo:(void*)contextInfo;
+- (void)autofillLogin:(NSString*)login password:(NSString*)password;
+- (void)setExplanation:(NSString*)explanation;
+@end
+
+#endif // CHROME_BROWSER_UI_LOGIN_LOGIN_PROMPT_MAC_H_
diff --git a/chrome/browser/ui/login/login_prompt_mac.mm b/chrome/browser/ui/login/login_prompt_mac.mm
new file mode 100644
index 0000000..2ee0252
--- /dev/null
+++ b/chrome/browser/ui/login/login_prompt_mac.mm
@@ -0,0 +1,190 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/login/login_prompt.h"
+#import "chrome/browser/ui/login/login_prompt_mac.h"
+
+#include "app/l10n_util.h"
+#include "base/mac_util.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/password_manager/password_manager.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+#include "chrome/browser/tab_contents/navigation_controller.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_util.h"
+#include "chrome/browser/ui/cocoa/constrained_window_mac.h"
+#include "chrome/browser/ui/login/login_model.h"
+#include "grit/generated_resources.h"
+#include "net/url_request/url_request.h"
+#include "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
+
+using webkit_glue::PasswordForm;
+
+// ----------------------------------------------------------------------------
+// LoginHandlerMac
+
+// This class simply forwards the authentication from the LoginView (on
+// the UI thread) to the net::URLRequest (on the I/O thread).
+// This class uses ref counting to ensure that it lives until all InvokeLaters
+// have been called.
+class LoginHandlerMac : public LoginHandler,
+ public ConstrainedWindowMacDelegateCustomSheet {
+ public:
+ LoginHandlerMac(net::AuthChallengeInfo* auth_info, net::URLRequest* request)
+ : LoginHandler(auth_info, request),
+ sheet_controller_(nil) {
+ }
+
+ virtual ~LoginHandlerMac() {
+ }
+
+ // LoginModelObserver implementation.
+ virtual void OnAutofillDataAvailable(const std::wstring& username,
+ const std::wstring& password) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ [sheet_controller_ autofillLogin:base::SysWideToNSString(username)
+ password:base::SysWideToNSString(password)];
+ }
+
+ // LoginHandler:
+ virtual void BuildViewForPasswordManager(PasswordManager* manager,
+ std::wstring explanation) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // Load nib here instead of in constructor.
+ sheet_controller_ = [[[LoginHandlerSheet alloc]
+ initWithLoginHandler:this] autorelease];
+ init([sheet_controller_ window], sheet_controller_,
+ @selector(sheetDidEnd:returnCode:contextInfo:));
+
+ SetModel(manager);
+
+ [sheet_controller_ setExplanation:base::SysWideToNSString(explanation)];
+
+ // Scary thread safety note: This can potentially be called *after* SetAuth
+ // or CancelAuth (say, if the request was cancelled before the UI thread got
+ // control). However, that's OK since any UI interaction in those functions
+ // will occur via an InvokeLater on the UI thread, which is guaranteed
+ // to happen after this is called (since this was InvokeLater'd first).
+ SetDialog(GetTabContentsForLogin()->CreateConstrainedDialog(this));
+
+ NotifyAuthNeeded();
+ }
+
+ // Overridden from ConstrainedWindowMacDelegate:
+ virtual void DeleteDelegate() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // The constrained window is going to delete itself; clear our pointer.
+ SetDialog(NULL);
+ SetModel(NULL);
+
+ // Close sheet if it's still open, as required by
+ // ConstrainedWindowMacDelegate.
+ if (is_sheet_open())
+ [NSApp endSheet:sheet()];
+
+ ReleaseSoon();
+ }
+
+ void OnLoginPressed(const std::wstring& username,
+ const std::wstring& password) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ SetAuth(username, password);
+ }
+
+ void OnCancelPressed() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ CancelAuth();
+ }
+
+ private:
+ friend class LoginPrompt;
+
+ // The Cocoa controller of the GUI.
+ LoginHandlerSheet* sheet_controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(LoginHandlerMac);
+};
+
+// static
+LoginHandler* LoginHandler::Create(net::AuthChallengeInfo* auth_info,
+ net::URLRequest* request) {
+ return new LoginHandlerMac(auth_info, request);
+}
+
+// ----------------------------------------------------------------------------
+// LoginHandlerSheet
+
+@implementation LoginHandlerSheet
+
+- (id)initWithLoginHandler:(LoginHandlerMac*)handler {
+ NSString* nibPath =
+ [mac_util::MainAppBundle() pathForResource:@"HttpAuthLoginSheet"
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibPath
+ owner:self])) {
+ handler_ = handler;
+ }
+ return self;
+}
+
+- (void)dealloc {
+ // The buttons could be in a modal loop, so disconnect them so they cannot
+ // call back to us after we're dead.
+ [loginButton_ setTarget:nil];
+ [cancelButton_ setTarget:nil];
+ [super dealloc];
+}
+
+- (IBAction)loginPressed:(id)sender {
+ using base::SysNSStringToWide;
+ [NSApp endSheet:[self window]];
+ handler_->OnLoginPressed(SysNSStringToWide([nameField_ stringValue]),
+ SysNSStringToWide([passwordField_ stringValue]));
+}
+
+- (IBAction)cancelPressed:(id)sender {
+ [NSApp endSheet:[self window]];
+ handler_->OnCancelPressed();
+}
+
+- (void)sheetDidEnd:(NSWindow*)sheet
+ returnCode:(int)returnCode
+ contextInfo:(void *)contextInfo {
+ [sheet orderOut:self];
+ // Also called when user navigates to another page while the sheet is open.
+}
+
+- (void)autofillLogin:(NSString*)login password:(NSString*)password {
+ if ([[nameField_ stringValue] length] == 0) {
+ [nameField_ setStringValue:login];
+ [passwordField_ setStringValue:password];
+ [nameField_ selectText:self];
+ }
+}
+
+- (void)setExplanation:(NSString*)explanation {
+ // Put in the text.
+ [explanationField_ setStringValue:explanation];
+
+ // Resize the TextField.
+ CGFloat explanationShift =
+ [GTMUILocalizerAndLayoutTweaker
+ sizeToFitFixedWidthTextField:explanationField_];
+
+ // Resize the window (no shifting needed due to window layout).
+ NSSize windowDelta = NSMakeSize(0, explanationShift);
+ [GTMUILocalizerAndLayoutTweaker
+ resizeWindowWithoutAutoResizingSubViews:[self window]
+ delta:windowDelta];
+}
+
+@end
diff --git a/chrome/browser/login_prompt_uitest.cc b/chrome/browser/ui/login/login_prompt_uitest.cc
index bdda3fd..bdda3fd 100644
--- a/chrome/browser/login_prompt_uitest.cc
+++ b/chrome/browser/ui/login/login_prompt_uitest.cc
diff --git a/chrome/browser/ui/login/login_prompt_unittest.cc b/chrome/browser/ui/login/login_prompt_unittest.cc
new file mode 100644
index 0000000..9454e13
--- /dev/null
+++ b/chrome/browser/ui/login/login_prompt_unittest.cc
@@ -0,0 +1,42 @@
+// 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.
+
+#include "chrome/browser/ui/login/login_prompt.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/auth.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+
+TEST(LoginPromptTest, GetSignonRealm) {
+ scoped_refptr<net::AuthChallengeInfo> auth_info = new net::AuthChallengeInfo;
+ auth_info->is_proxy = false; // server auth
+ // auth_info->host is intentionally left empty.
+ auth_info->scheme = L"Basic";
+ auth_info->realm = L"WallyWorld";
+
+ std::string url[] = {
+ "https://www.nowhere.org/dir/index.html",
+ "https://www.nowhere.org:443/dir/index.html", // default port
+ "https://www.nowhere.org:8443/dir/index.html", // non-default port
+ "https://www.nowhere.org", // no trailing slash
+ "https://foo:bar@www.nowhere.org/dir/index.html", // username:password
+ "https://www.nowhere.org/dir/index.html?id=965362", // query
+ "https://www.nowhere.org/dir/index.html#toc", // reference
+ };
+
+ std::string expected[] = {
+ "https://www.nowhere.org/WallyWorld",
+ "https://www.nowhere.org/WallyWorld",
+ "https://www.nowhere.org:8443/WallyWorld",
+ "https://www.nowhere.org/WallyWorld",
+ "https://www.nowhere.org/WallyWorld",
+ "https://www.nowhere.org/WallyWorld",
+ "https://www.nowhere.org/WallyWorld"
+ };
+
+ for (size_t i = 0; i < arraysize(url); i++) {
+ std::string key = GetSignonRealm(GURL(url[i]), *auth_info);
+ EXPECT_EQ(expected[i], key);
+ }
+}
diff --git a/chrome/browser/ui/login/login_prompt_win.cc b/chrome/browser/ui/login/login_prompt_win.cc
new file mode 100644
index 0000000..a167885
--- /dev/null
+++ b/chrome/browser/ui/login/login_prompt_win.cc
@@ -0,0 +1,146 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/login/login_prompt.h"
+
+#include "app/l10n_util.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/password_manager/password_manager.h"
+#include "chrome/browser/renderer_host/render_process_host.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+#include "chrome/browser/tab_contents/navigation_controller.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_contents_delegate.h"
+#include "chrome/browser/tab_contents/tab_util.h"
+#include "chrome/browser/ui/views/login_view.h"
+#include "grit/generated_resources.h"
+#include "net/url_request/url_request.h"
+#include "views/window/dialog_delegate.h"
+
+using webkit_glue::PasswordForm;
+
+// ----------------------------------------------------------------------------
+// LoginHandlerWin
+
+// This class simply forwards the authentication from the LoginView (on
+// the UI thread) to the net::URLRequest (on the I/O thread).
+// This class uses ref counting to ensure that it lives until all InvokeLaters
+// have been called.
+class LoginHandlerWin : public LoginHandler,
+ public ConstrainedDialogDelegate {
+ public:
+ LoginHandlerWin(net::AuthChallengeInfo* auth_info, net::URLRequest* request)
+ : LoginHandler(auth_info, request) {
+ }
+
+ // LoginModelObserver implementation.
+ virtual void OnAutofillDataAvailable(const std::wstring& username,
+ const std::wstring& password) {
+ // Nothing to do here since LoginView takes care of autofil for win.
+ }
+
+ void set_login_view(LoginView* login_view) {
+ login_view_ = login_view;
+ }
+
+ // views::DialogDelegate methods:
+ virtual std::wstring GetDialogButtonLabel(
+ MessageBoxFlags::DialogButton button) const {
+ if (button == MessageBoxFlags::DIALOGBUTTON_OK)
+ return l10n_util::GetString(IDS_LOGIN_DIALOG_OK_BUTTON_LABEL);
+ return DialogDelegate::GetDialogButtonLabel(button);
+ }
+
+ virtual std::wstring GetWindowTitle() const {
+ return l10n_util::GetString(IDS_LOGIN_DIALOG_TITLE);
+ }
+
+ virtual void WindowClosing() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ TabContents* tab = GetTabContentsForLogin();
+ if (tab)
+ tab->render_view_host()->set_ignore_input_events(false);
+
+ // Reference is no longer valid.
+ SetDialog(NULL);
+
+ CancelAuth();
+ }
+
+ virtual void DeleteDelegate() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // The constrained window is going to delete itself; clear our pointer.
+ SetDialog(NULL);
+ SetModel(NULL);
+
+ ReleaseSoon();
+ }
+
+ virtual bool Cancel() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ CancelAuth();
+ return true;
+ }
+
+ virtual bool Accept() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ SetAuth(login_view_->GetUsername(), login_view_->GetPassword());
+ return true;
+ }
+
+ virtual views::View* GetContentsView() {
+ return login_view_;
+ }
+
+ // LoginHandler:
+
+ virtual void BuildViewForPasswordManager(PasswordManager* manager,
+ std::wstring explanation) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ TabContents* tab_contents = GetTabContentsForLogin();
+ bool should_focus_view = !tab_contents->delegate() ||
+ tab_contents->delegate()->ShouldFocusConstrainedWindow();
+
+ LoginView* view = new LoginView(explanation, should_focus_view);
+
+ // Set the model for the login view. The model (password manager) is owned
+ // by the view's parent TabContents, so natural destruction order means we
+ // don't have to worry about calling SetModel(NULL), because the view will
+ // be deleted before the password manager.
+ view->SetModel(manager);
+
+ set_login_view(view);
+
+ // Scary thread safety note: This can potentially be called *after* SetAuth
+ // or CancelAuth (say, if the request was cancelled before the UI thread got
+ // control). However, that's OK since any UI interaction in those functions
+ // will occur via an InvokeLater on the UI thread, which is guaranteed
+ // to happen after this is called (since this was InvokeLater'd first).
+ SetDialog(GetTabContentsForLogin()->CreateConstrainedDialog(this));
+ NotifyAuthNeeded();
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<LoginHandlerWin>;
+ friend class LoginPrompt;
+
+ ~LoginHandlerWin() {}
+
+ // The LoginView that contains the user's login information
+ LoginView* login_view_;
+
+ DISALLOW_COPY_AND_ASSIGN(LoginHandlerWin);
+};
+
+// static
+LoginHandler* LoginHandler::Create(net::AuthChallengeInfo* auth_info,
+ net::URLRequest* request) {
+ return new LoginHandlerWin(auth_info, request);
+}
diff --git a/chrome/browser/ui/omnibox/location_bar.h b/chrome/browser/ui/omnibox/location_bar.h
new file mode 100644
index 0000000..87a6fa8
--- /dev/null
+++ b/chrome/browser/ui/omnibox/location_bar.h
@@ -0,0 +1,106 @@
+// 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.
+
+// The LocationBar class is a virtual interface, defining access to the
+// window's location bar component. This class exists so that cross-platform
+// components like the browser command system can talk to the platform
+// specific implementations of the location bar control. It also allows the
+// location bar to be mocked for testing.
+
+#ifndef CHROME_BROWSER_UI_OMNIBOX_LOCATION_BAR_H_
+#define CHROME_BROWSER_UI_OMNIBOX_LOCATION_BAR_H_
+#pragma once
+
+#include <string>
+
+#include "base/string16.h"
+#include "chrome/browser/first_run/first_run.h"
+#include "chrome/common/page_transition_types.h"
+#include "webkit/glue/window_open_disposition.h"
+
+class AutocompleteEditView;
+class ExtensionAction;
+class LocationBarTesting;
+class TabContents;
+
+class LocationBar {
+ public:
+ // Shows the first run information bubble anchored to the location bar.
+ virtual void ShowFirstRunBubble(FirstRun::BubbleType bubble_type) = 0;
+
+ // Sets the suggested text to show in the omnibox. This is shown in addition
+ // to the current text of the omnibox.
+ virtual void SetSuggestedText(const string16& text) = 0;
+
+ // Returns the string of text entered in the location bar.
+ virtual std::wstring GetInputString() const = 0;
+
+ // Returns the WindowOpenDisposition that should be used to determine where
+ // to open a URL entered in the location bar.
+ virtual WindowOpenDisposition GetWindowOpenDisposition() const = 0;
+
+ // Returns the PageTransition that should be recorded in history when the URL
+ // entered in the location bar is loaded.
+ virtual PageTransition::Type GetPageTransition() const = 0;
+
+ // Accepts the current string of text entered in the location bar.
+ virtual void AcceptInput() = 0;
+
+ // Focuses the location bar. Optionally also selects its contents.
+ virtual void FocusLocation(bool select_all) = 0;
+
+ // Clears the location bar, inserts an annoying little "?" turd and sets
+ // focus to it.
+ virtual void FocusSearch() = 0;
+
+ // Updates the state of the images showing the content settings status.
+ virtual void UpdateContentSettingsIcons() = 0;
+
+ // Updates the state of the page actions.
+ virtual void UpdatePageActions() = 0;
+
+ // Called when the page-action data needs to be refreshed, e.g. when an
+ // extension is unloaded or crashes.
+ virtual void InvalidatePageActions() = 0;
+
+ // Saves the state of the location bar to the specified TabContents, so that
+ // it can be restored later. (Done when switching tabs).
+ virtual void SaveStateToContents(TabContents* contents) = 0;
+
+ // Reverts the location bar. The bar's permanent text will be shown.
+ virtual void Revert() = 0;
+
+ // Returns a pointer to the text entry view.
+ virtual const AutocompleteEditView* location_entry() const = 0;
+ virtual AutocompleteEditView* location_entry() = 0;
+
+ // Returns a pointer to the testing interface.
+ virtual LocationBarTesting* GetLocationBarForTesting() = 0;
+
+ protected:
+ virtual ~LocationBar() {}
+};
+
+class LocationBarTesting {
+ public:
+ // Returns the total number of page actions in the Omnibox.
+ virtual int PageActionCount() = 0;
+
+ // Returns the number of visible page actions in the Omnibox.
+ virtual int PageActionVisibleCount() = 0;
+
+ // Returns the ExtensionAction at |index|.
+ virtual ExtensionAction* GetPageAction(size_t index) = 0;
+
+ // Returns the visible ExtensionAction at |index|.
+ virtual ExtensionAction* GetVisiblePageAction(size_t index) = 0;
+
+ // Simulates a left mouse pressed on the visible page action at |index|.
+ virtual void TestPageActionPressed(size_t index) = 0;
+
+ protected:
+ virtual ~LocationBarTesting() {}
+};
+
+#endif // CHROME_BROWSER_UI_OMNIBOX_LOCATION_BAR_H_
diff --git a/chrome/browser/ui/omnibox/location_bar_util.cc b/chrome/browser/ui/omnibox/location_bar_util.cc
new file mode 100644
index 0000000..a5e9404
--- /dev/null
+++ b/chrome/browser/ui/omnibox/location_bar_util.cc
@@ -0,0 +1,44 @@
+// 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.
+
+#include "chrome/browser/ui/omnibox/location_bar_util.h"
+
+#include "app/l10n_util.h"
+#include "base/i18n/rtl.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/search_engines/template_url_model.h"
+
+namespace location_bar_util {
+
+std::wstring GetKeywordName(Profile* profile, const std::wstring& keyword) {
+// Make sure the TemplateURL still exists.
+// TODO(sky): Once LocationBarView adds a listener to the TemplateURLModel
+// to track changes to the model, this should become a DCHECK.
+ const TemplateURL* template_url =
+ profile->GetTemplateURLModel()->GetTemplateURLForKeyword(keyword);
+ if (template_url)
+ return template_url->AdjustedShortNameForLocaleDirection();
+ return std::wstring();
+}
+
+std::wstring CalculateMinString(const std::wstring& description) {
+ // Chop at the first '.' or whitespace.
+ const size_t dot_index = description.find(L'.');
+ const size_t ws_index = description.find_first_of(kWhitespaceWide);
+ size_t chop_index = std::min(dot_index, ws_index);
+ std::wstring min_string;
+ if (chop_index == std::wstring::npos) {
+ // No dot or whitespace, truncate to at most 3 chars.
+ min_string = UTF16ToWideHack(
+ l10n_util::TruncateString(WideToUTF16Hack(description), 3));
+ } else {
+ min_string = description.substr(0, chop_index);
+ }
+ base::i18n::AdjustStringForLocaleDirection(&min_string);
+ return min_string;
+}
+
+} // namespace location_bar_util
diff --git a/chrome/browser/ui/omnibox/location_bar_util.h b/chrome/browser/ui/omnibox/location_bar_util.h
new file mode 100644
index 0000000..ca6a214
--- /dev/null
+++ b/chrome/browser/ui/omnibox/location_bar_util.h
@@ -0,0 +1,24 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_OMNIBOX_LOCATION_BAR_UTIL_H_
+#define CHROME_BROWSER_UI_OMNIBOX_LOCATION_BAR_UTIL_H_
+#pragma once
+
+#include <string>
+
+class Profile;
+
+namespace location_bar_util {
+
+// Returns the short name for a keyword.
+std::wstring GetKeywordName(Profile* profile, const std::wstring& keyword);
+
+// Build a short string to use in keyword-search when the field isn't
+// very big.
+std::wstring CalculateMinString(const std::wstring& description);
+
+} // namespace location_bar_util
+
+#endif // CHROME_BROWSER_UI_OMNIBOX_LOCATION_BAR_UTIL_H_
diff --git a/chrome/browser/ui/options/options_page_base.cc b/chrome/browser/ui/options/options_page_base.cc
new file mode 100644
index 0000000..32a21f7
--- /dev/null
+++ b/chrome/browser/ui/options/options_page_base.cc
@@ -0,0 +1,38 @@
+// 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.
+
+#include "chrome/browser/ui/options/options_page_base.h"
+
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// OptionsPageBase
+
+OptionsPageBase::OptionsPageBase(Profile* profile)
+ : profile_(profile) {
+}
+
+OptionsPageBase::~OptionsPageBase() {
+}
+
+void OptionsPageBase::UserMetricsRecordAction(const UserMetricsAction& action,
+ PrefService* prefs) {
+ UserMetrics::RecordAction(action, profile());
+ if (prefs)
+ prefs->ScheduleSavePersistentPrefs();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// OptionsPageBase, NotificationObserver implementation:
+
+void OptionsPageBase::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NotificationType::PREF_CHANGED)
+ NotifyPrefChanged(Details<std::string>(details).ptr());
+}
diff --git a/chrome/browser/ui/options/options_page_base.h b/chrome/browser/ui/options/options_page_base.h
new file mode 100644
index 0000000..695df1c
--- /dev/null
+++ b/chrome/browser/ui/options/options_page_base.h
@@ -0,0 +1,62 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_OPTIONS_OPTIONS_PAGE_BASE_H_
+#define CHROME_BROWSER_UI_OPTIONS_OPTIONS_PAGE_BASE_H_
+#pragma once
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/ui/options/options_window.h"
+#include "chrome/common/notification_observer.h"
+
+class PrefService;
+class Profile;
+struct UserMetricsAction;
+
+///////////////////////////////////////////////////////////////////////////////
+// OptionsPageBase
+//
+// A base class for Options dialog pages that handles observing preferences
+//
+class OptionsPageBase : public NotificationObserver {
+ public:
+ virtual ~OptionsPageBase();
+
+ // Highlights the specified group to attract the user's attention.
+ virtual void HighlightGroup(OptionsGroup highlight_group) { }
+
+ // Overridden from NotificationObserver:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ protected:
+ // This class cannot be instantiated directly, but its constructor must be
+ // called by derived classes.
+ explicit OptionsPageBase(Profile* profile);
+
+ // Returns the Profile associated with this page.
+ Profile* profile() const { return profile_; }
+
+ // Records a user action and schedules the prefs file to be saved.
+ void UserMetricsRecordAction(const UserMetricsAction &action,
+ PrefService* prefs);
+
+ // Allows the UI to update when a preference value changes. The parameter is
+ // the specific pref that changed, or NULL if all pref UI should be
+ // validated. This should be called during setup, but with NULL as the
+ // parameter to allow initial state to be set.
+ virtual void NotifyPrefChanged(const std::string* pref_name) {}
+
+ private:
+ // The Profile associated with this page.
+ Profile* profile_;
+
+ DISALLOW_COPY_AND_ASSIGN(OptionsPageBase);
+};
+
+#endif // CHROME_BROWSER_UI_OPTIONS_OPTIONS_PAGE_BASE_H_
diff --git a/chrome/browser/ui/options/options_util.cc b/chrome/browser/ui/options/options_util.cc
new file mode 100644
index 0000000..0c8ba36
--- /dev/null
+++ b/chrome/browser/ui/options/options_util.cc
@@ -0,0 +1,134 @@
+// 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.
+
+#include "chrome/browser/ui/options/options_util.h"
+
+#include "base/thread_restrictions.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/download/download_manager.h"
+#include "chrome/browser/download/download_prefs.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
+#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
+#include "chrome/browser/host_zoom_map.h"
+#include "chrome/browser/metrics/metrics_service.h"
+#include "chrome/browser/notifications/desktop_notification_service.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/installer/util/google_update_settings.h"
+
+// static
+void OptionsUtil::ResetToDefaults(Profile* profile) {
+ // TODO(tc): It would be nice if we could generate this list automatically so
+ // changes to any of the options pages doesn't require updating this list
+ // manually.
+ PrefService* prefs = profile->GetPrefs();
+ const char* kUserPrefs[] = {
+ prefs::kAcceptLanguages,
+ prefs::kAlternateErrorPagesEnabled,
+ prefs::kClearPluginLSODataOnExit,
+ prefs::kClearSiteDataOnExit,
+ prefs::kCookieBehavior,
+ prefs::kDefaultCharset,
+ prefs::kDefaultZoomLevel,
+ prefs::kDeleteBrowsingHistory,
+ prefs::kDeleteCache,
+ prefs::kDeleteCookies,
+ prefs::kDeleteDownloadHistory,
+ prefs::kDeleteFormData,
+ prefs::kDeleteLSOData,
+ prefs::kDeletePasswords,
+ prefs::kDnsPrefetchingEnabled,
+#if defined(OS_LINUX) || defined(OS_FREEBSD) || defined(OS_OPENBSD)
+ prefs::kCertRevocationCheckingEnabled,
+ prefs::kSSL3Enabled,
+ prefs::kTLS1Enabled,
+#endif
+#if defined(OS_CHROMEOS)
+ prefs::kTapToClickEnabled,
+ prefs::kTouchpadSensitivity,
+#endif
+ prefs::kDownloadDefaultDirectory,
+ prefs::kDownloadExtensionsToOpen,
+ prefs::kSavingBrowserHistoryDisabled,
+ prefs::kEnableSpellCheck,
+ prefs::kEnableTranslate,
+ prefs::kAutoFillEnabled,
+ prefs::kAutoFillAuxiliaryProfilesEnabled,
+ prefs::kHomePage,
+ prefs::kHomePageIsNewTabPage,
+ prefs::kPromptForDownload,
+ prefs::kPasswordManagerEnabled,
+ prefs::kRestoreOnStartup,
+ prefs::kSafeBrowsingEnabled,
+ prefs::kSafeBrowsingReportingEnabled,
+ prefs::kSearchSuggestEnabled,
+ prefs::kShowHomeButton,
+ prefs::kSpellCheckDictionary,
+ prefs::kURLsToRestoreOnStartup,
+ prefs::kWebKitDefaultFixedFontSize,
+ prefs::kWebKitDefaultFontSize,
+ prefs::kWebKitFixedFontFamily,
+ prefs::kWebKitJavaEnabled,
+ prefs::kWebKitJavascriptEnabled,
+ prefs::kWebKitLoadsImagesAutomatically,
+ prefs::kWebKitPluginsEnabled,
+ prefs::kWebKitSansSerifFontFamily,
+ prefs::kWebKitSerifFontFamily,
+ prefs::kWebKitMinimumFontSize,
+ prefs::kWebKitMinimumLogicalFontSize,
+ prefs::kWebkitTabsToLinks,
+ };
+ profile->GetDownloadManager()->download_prefs()->ResetToDefaults();
+ profile->GetHostContentSettingsMap()->ResetToDefaults();
+ profile->GetGeolocationContentSettingsMap()->ResetToDefault();
+ profile->GetHostZoomMap()->ResetToDefaults();
+ profile->GetDesktopNotificationService()->ResetToDefaultContentSetting();
+ for (size_t i = 0; i < arraysize(kUserPrefs); ++i)
+ prefs->ClearPref(kUserPrefs[i]);
+
+ PrefService* local_state = g_browser_process->local_state();
+ // Note that we don't reset the kMetricsReportingEnabled preference here
+ // because the reset will reset it to the default setting specified in Chrome
+ // source, not the default setting selected by the user on the web page where
+ // they downloaded Chrome. This means that if the user ever resets their
+ // settings they'll either inadvertedly enable this logging or disable it.
+ // One is undesirable for them, one is undesirable for us. For now, we just
+ // don't reset it.
+ const char* kLocalStatePrefs[] = {
+ prefs::kApplicationLocale,
+ };
+ for (size_t i = 0; i < arraysize(kLocalStatePrefs); ++i)
+ local_state->ClearPref(kLocalStatePrefs[i]);
+}
+
+// static
+bool OptionsUtil::ResolveMetricsReportingEnabled(bool enabled) {
+ // GoogleUpdateSettings touches the disk from the UI thread. MetricsService
+ // also calls GoogleUpdateSettings below. http://crbug/62626
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+ GoogleUpdateSettings::SetCollectStatsConsent(enabled);
+ bool update_pref = GoogleUpdateSettings::GetCollectStatsConsent();
+
+ if (enabled != update_pref) {
+ DVLOG(1) << "OptionsUtil: Unable to set crash report status to " << enabled;
+ }
+
+ // Only change the pref if GoogleUpdateSettings::GetCollectStatsConsent
+ // succeeds.
+ enabled = update_pref;
+
+ MetricsService* metrics = g_browser_process->metrics_service();
+ DCHECK(metrics);
+ if (metrics) {
+ metrics->SetUserPermitsUpload(enabled);
+ if (enabled)
+ metrics->Start();
+ else
+ metrics->Stop();
+ }
+
+ return enabled;
+}
diff --git a/chrome/browser/ui/options/options_util.h b/chrome/browser/ui/options/options_util.h
new file mode 100644
index 0000000..fb2b183
--- /dev/null
+++ b/chrome/browser/ui/options/options_util.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_OPTIONS_OPTIONS_UTIL_H_
+#define CHROME_BROWSER_UI_OPTIONS_OPTIONS_UTIL_H_
+#pragma once
+
+#include "base/basictypes.h"
+
+class Profile;
+
+class OptionsUtil {
+ public:
+ // TODO(kmadhusu): Remove "ResetToDefaults" function after platform-specific
+ // dialogs are removed.
+ // Resets all prefs to their default values.
+ static void ResetToDefaults(Profile* profile);
+
+ // Try to make the the crash stats consent and the metrics upload
+ // permission match |enabled|, returns the actual enabled setting.
+ static bool ResolveMetricsReportingEnabled(bool enabled);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(OptionsUtil);
+};
+
+#endif // CHROME_BROWSER_UI_OPTIONS_OPTIONS_UTIL_H_
diff --git a/chrome/browser/ui/options/options_window.h b/chrome/browser/ui/options/options_window.h
new file mode 100644
index 0000000..f088f1a
--- /dev/null
+++ b/chrome/browser/ui/options/options_window.h
@@ -0,0 +1,40 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_OPTIONS_OPTIONS_WINDOW_H_
+#define CHROME_BROWSER_UI_OPTIONS_OPTIONS_WINDOW_H_
+#pragma once
+
+class Profile;
+
+// An identifier for a Options Tab page. These are treated as indices into
+// the list of available tabs to be displayed. PAGE_DEFAULT means select the
+// last tab viewed when the Options window was opened, or PAGE_GENERAL if the
+// Options was never opened.
+enum OptionsPage {
+ OPTIONS_PAGE_DEFAULT = -1,
+#if defined(OS_CHROMEOS)
+ OPTIONS_PAGE_SYSTEM,
+ OPTIONS_PAGE_INTERNET,
+#endif
+ OPTIONS_PAGE_GENERAL,
+ OPTIONS_PAGE_CONTENT,
+ OPTIONS_PAGE_ADVANCED,
+ OPTIONS_PAGE_COUNT
+};
+
+// These are some well known groups within the Options dialog box that we may
+// wish to highlight to attract the user's attention to.
+enum OptionsGroup {
+ OPTIONS_GROUP_NONE,
+ OPTIONS_GROUP_DEFAULT_SEARCH
+};
+
+// Show the Options window selecting the specified page. If an Options window
+// is currently open, this just activates it instead of opening a new one.
+void ShowOptionsWindow(OptionsPage page,
+ OptionsGroup highlight_group,
+ Profile* profile);
+
+#endif // CHROME_BROWSER_UI_OPTIONS_OPTIONS_WINDOW_H_
diff --git a/chrome/browser/ui/options/show_options_url.cc b/chrome/browser/ui/options/show_options_url.cc
new file mode 100644
index 0000000..2b4818f
--- /dev/null
+++ b/chrome/browser/ui/options/show_options_url.cc
@@ -0,0 +1,21 @@
+// 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.
+
+#include "chrome/browser/ui/options/show_options_url.h"
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
+
+namespace browser {
+
+void ShowOptionsURL(Profile* profile, const GURL& url) {
+ // We open a new browser window so the Options dialog doesn't get lost behind
+ // other windows.
+ Browser* browser = Browser::Create(profile);
+ browser->AddSelectedTabWithURL(url, PageTransition::LINK);
+ browser->window()->Show();
+}
+
+} // namespace browser
diff --git a/chrome/browser/ui/options/show_options_url.h b/chrome/browser/ui/options/show_options_url.h
new file mode 100644
index 0000000..e849169
--- /dev/null
+++ b/chrome/browser/ui/options/show_options_url.h
@@ -0,0 +1,20 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_OPTIONS_SHOW_OPTIONS_URL_H_
+#define CHROME_BROWSER_UI_OPTIONS_SHOW_OPTIONS_URL_H_
+#pragma once
+
+class GURL;
+class Profile;
+
+namespace browser {
+
+// Opens a tab showing the specified url. This is intended for use any place
+// we show a URL in the options dialogs.
+void ShowOptionsURL(Profile* profile, const GURL& url);
+
+} // namespace browser
+
+#endif // CHROME_BROWSER_UI_OPTIONS_SHOW_OPTIONS_URL_H_
diff --git a/chrome/browser/status_bubble.h b/chrome/browser/ui/status_bubble.h
index e7ddc15..e7ddc15 100644
--- a/chrome/browser/status_bubble.h
+++ b/chrome/browser/ui/status_bubble.h
diff --git a/chrome/browser/ui/tab_contents/tab_contents_wrapper.cc b/chrome/browser/ui/tab_contents/tab_contents_wrapper.cc
new file mode 100644
index 0000000..b44c346
--- /dev/null
+++ b/chrome/browser/ui/tab_contents/tab_contents_wrapper.cc
@@ -0,0 +1,66 @@
+// 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.
+
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+
+#include "base/lazy_instance.h"
+#include "chrome/browser/password_manager/password_manager.h"
+#include "chrome/browser/password_manager_delegate_impl.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+
+static base::LazyInstance<PropertyAccessor<TabContentsWrapper*> >
+ g_tab_contents_wrapper_property_accessor(base::LINKER_INITIALIZED);
+
+////////////////////////////////////////////////////////////////////////////////
+// TabContentsWrapper, public:
+
+TabContentsWrapper::TabContentsWrapper(TabContents* contents)
+ : tab_contents_(contents) {
+ DCHECK(contents);
+ // Stash this in the property bag so it can be retrieved without having to
+ // go to a Browser.
+ property_accessor()->SetProperty(contents->property_bag(), this);
+
+ // Needed so that we initialize the password manager on first navigation.
+ tab_contents()->AddNavigationObserver(this);
+}
+
+TabContentsWrapper::~TabContentsWrapper() {
+ // Unregister observers (TabContents outlives supporting objects).
+ tab_contents()->RemoveNavigationObserver(password_manager_.get());
+}
+
+PropertyAccessor<TabContentsWrapper*>* TabContentsWrapper::property_accessor() {
+ return g_tab_contents_wrapper_property_accessor.Pointer();
+}
+
+TabContentsWrapper* TabContentsWrapper::Clone() {
+ TabContents* new_contents = tab_contents()->Clone();
+ TabContentsWrapper* new_wrapper = new TabContentsWrapper(new_contents);
+ // Instantiate the passowrd manager if it has been instantiated here.
+ if (password_manager_.get())
+ new_wrapper->GetPasswordManager();
+ return new_wrapper;
+}
+
+PasswordManager* TabContentsWrapper::GetPasswordManager() {
+ if (!password_manager_.get()) {
+ // Create the delegate then create the manager.
+ password_manager_delegate_.reset(
+ new PasswordManagerDelegateImpl(tab_contents()));
+ password_manager_.reset(
+ new PasswordManager(password_manager_delegate_.get()));
+ // Register the manager to receive navigation notifications.
+ tab_contents()->AddNavigationObserver(password_manager_.get());
+ }
+ return password_manager_.get();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TabContentsWrapper, WebNavigationObserver implementation:
+
+void TabContentsWrapper::NavigateToPendingEntry() {
+ GetPasswordManager();
+ tab_contents()->RemoveNavigationObserver(this);
+}
diff --git a/chrome/browser/ui/tab_contents/tab_contents_wrapper.h b/chrome/browser/ui/tab_contents/tab_contents_wrapper.h
new file mode 100644
index 0000000..f47a6ad
--- /dev/null
+++ b/chrome/browser/ui/tab_contents/tab_contents_wrapper.h
@@ -0,0 +1,79 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_TAB_CONTENTS_TAB_CONTENTS_WRAPPER_H_
+#define CHROME_BROWSER_UI_TAB_CONTENTS_TAB_CONTENTS_WRAPPER_H_
+#pragma once
+
+#include "base/scoped_ptr.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/web_navigation_observer.h"
+
+class Extension;
+class NavigationController;
+class PasswordManager;
+class PasswordManagerDelegate;
+class TabContentsDelegate;
+
+// Wraps TabContents and all of its supporting objetcs in order to control
+// their ownership and lifetime, while allowing TabContents to remain generic
+// and re-usable in other projects.
+// TODO(pinkerton): Eventually, this class will become TabContents as far as
+// the browser front-end is concerned, and the current TabContents will be
+// renamed to something like WebPage or WebView (ben's suggestions).
+class TabContentsWrapper : public WebNavigationObserver {
+ public:
+ // Takes ownership of |contents|, which must be heap-allocated (as it lives
+ // in a scoped_ptr) and can not be NULL.
+ explicit TabContentsWrapper(TabContents* contents);
+ ~TabContentsWrapper();
+
+ // Used to retrieve this object from |tab_contents_|, which is placed in
+ // its property bag to avoid adding additional interfaces.
+ static PropertyAccessor<TabContentsWrapper*>* property_accessor();
+
+ // Create a TabContentsWrapper with the same state as this one. The returned
+ // heap-allocated pointer is owned by the caller.
+ TabContentsWrapper* Clone();
+
+ TabContents* tab_contents() const { return tab_contents_.get(); }
+ NavigationController& controller() const {
+ return tab_contents()->controller();
+ }
+ TabContentsView* view() const { return tab_contents()->view(); }
+ RenderViewHost* render_view_host() const {
+ return tab_contents()->render_view_host();
+ }
+ Profile* profile() const { return tab_contents()->profile(); }
+ TabContentsDelegate* delegate() const { return tab_contents()->delegate(); }
+ void set_delegate(TabContentsDelegate* d) { tab_contents()->set_delegate(d); }
+
+ // Convenience methods until extensions are removed from TabContents.
+ void SetExtensionAppById(const std::string& extension_app_id) {
+ tab_contents()->SetExtensionAppById(extension_app_id);
+ }
+ const Extension* extension_app() const {
+ return tab_contents()->extension_app();
+ }
+ bool is_app() const { return tab_contents()->is_app(); }
+
+ // Returns the PasswordManager, creating it if necessary.
+ PasswordManager* GetPasswordManager();
+
+ // WebNavigationObserver overrides:
+ virtual void NavigateToPendingEntry();
+
+ private:
+ // PasswordManager and its delegate, lazily created. The delegate must
+ // outlive the manager, per documentation in password_manager.h.
+ scoped_ptr<PasswordManagerDelegate> password_manager_delegate_;
+ scoped_ptr<PasswordManager> password_manager_;
+
+ // The supporting objects need to outlive the TabContents dtor (as they may
+ // be called upon during its execution). As a result, this must come last
+ // in the list.
+ scoped_ptr<TabContents> tab_contents_;
+};
+
+#endif // CHROME_BROWSER_UI_TAB_CONTENTS_TAB_CONTENTS_WRAPPER_H_
diff --git a/chrome/browser/ui/tabs/dock_info.cc b/chrome/browser/ui/tabs/dock_info.cc
new file mode 100644
index 0000000..97fe29d
--- /dev/null
+++ b/chrome/browser/ui/tabs/dock_info.cc
@@ -0,0 +1,268 @@
+// 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.
+
+#include "chrome/browser/ui/tabs/dock_info.h"
+
+#if defined(TOOLKIT_VIEWS)
+#include "chrome/browser/views/tabs/tab.h"
+#else
+#include "chrome/browser/gtk/tabs/tab_gtk.h"
+#endif
+
+namespace {
+
+// Distance in pixels between the hotspot and when the hint should be shown.
+const int kHotSpotDeltaX = 120;
+const int kHotSpotDeltaY = 120;
+
+// Size of the popup window.
+const int kPopupWidth = 70;
+const int kPopupHeight = 70;
+
+} // namespace
+
+// static
+DockInfo::Factory* DockInfo::factory_ = NULL;
+
+// static
+bool DockInfo::IsCloseToPoint(const gfx::Point& screen_loc,
+ int x,
+ int y,
+ bool* in_enable_area) {
+ int delta_x = abs(x - screen_loc.x());
+ int delta_y = abs(y - screen_loc.y());
+ *in_enable_area = (delta_x < kPopupWidth / 2 && delta_y < kPopupHeight / 2);
+ return *in_enable_area || (delta_x < kHotSpotDeltaX &&
+ delta_y < kHotSpotDeltaY);
+}
+
+// static
+bool DockInfo::IsCloseToMonitorPoint(const gfx::Point& screen_loc,
+ int x,
+ int y,
+ DockInfo::Type type,
+ bool* in_enable_area) {
+ // Because the monitor relative positions are aligned with the edge of the
+ // monitor these need to be handled differently.
+ int delta_x = abs(x - screen_loc.x());
+ int delta_y = abs(y - screen_loc.y());
+
+ int enable_delta_x = kPopupWidth / 2;
+ int enable_delta_y = kPopupHeight / 2;
+ int hot_spot_delta_x = kHotSpotDeltaX;
+ int hot_spot_delta_y = kHotSpotDeltaY;
+
+ switch (type) {
+ case DockInfo::LEFT_HALF:
+ case DockInfo::RIGHT_HALF:
+ enable_delta_x += enable_delta_x;
+ hot_spot_delta_x += hot_spot_delta_x;
+ break;
+
+
+ case DockInfo::MAXIMIZE: {
+ // Make the maximize height smaller than the tab height to avoid showing
+ // the dock indicator when close to maximized browser.
+#if defined(TOOLKIT_VIEWS)
+ hot_spot_delta_y = Tab::GetMinimumUnselectedSize().height() - 1;
+#else
+ hot_spot_delta_y = TabGtk::GetMinimumUnselectedSize().height() - 1;
+#endif
+ enable_delta_y = hot_spot_delta_y / 2;
+ break;
+ }
+ case DockInfo::BOTTOM_HALF:
+ enable_delta_y += enable_delta_y;
+ hot_spot_delta_y += hot_spot_delta_y;
+ break;
+
+ default:
+ NOTREACHED();
+ return false;
+ }
+ *in_enable_area = (delta_x < enable_delta_x && delta_y < enable_delta_y);
+ bool result = (*in_enable_area || (delta_x < hot_spot_delta_x &&
+ delta_y < hot_spot_delta_y));
+ if (type != DockInfo::MAXIMIZE)
+ return result;
+
+ // Make the hot spot/enable spot for maximized windows the whole top of the
+ // monitor.
+ int max_delta_y = abs(screen_loc.y() - y);
+ *in_enable_area = (*in_enable_area || (max_delta_y < enable_delta_y));
+ return *in_enable_area || (max_delta_y < hot_spot_delta_y);
+}
+
+// static
+int DockInfo::popup_width() {
+ return kPopupWidth;
+}
+
+// static
+int DockInfo::popup_height() {
+ return kPopupHeight;
+}
+
+bool DockInfo::IsValidForPoint(const gfx::Point& screen_point) {
+ if (type_ == NONE)
+ return false;
+
+ if (window_) {
+ return IsCloseToPoint(screen_point, hot_spot_.x(), hot_spot_.y(),
+ &in_enable_area_);
+ }
+
+ return monitor_bounds_.Contains(screen_point) &&
+ IsCloseToMonitorPoint(screen_point, hot_spot_.x(),
+ hot_spot_.y(), type_, &in_enable_area_);
+}
+
+bool DockInfo::GetNewWindowBounds(gfx::Rect* new_window_bounds,
+ bool* maximize_new_window) const {
+ if (type_ == NONE || !in_enable_area_)
+ return false;
+
+ gfx::Rect window_bounds;
+ if (window_ && !GetWindowBounds(&window_bounds))
+ return false;
+
+ int half_m_width = (monitor_bounds_.right() - monitor_bounds_.x()) / 2;
+ int half_m_height = (monitor_bounds_.bottom() - monitor_bounds_.y()) / 2;
+
+ *maximize_new_window = false;
+
+ switch (type_) {
+ case LEFT_OF_WINDOW:
+ new_window_bounds->SetRect(monitor_bounds_.x(), window_bounds.y(),
+ half_m_width, window_bounds.height());
+ break;
+
+ case RIGHT_OF_WINDOW:
+ new_window_bounds->SetRect(monitor_bounds_.x() + half_m_width,
+ window_bounds.y(), half_m_width,
+ window_bounds.height());
+ break;
+
+ case TOP_OF_WINDOW:
+ new_window_bounds->SetRect(window_bounds.x(), monitor_bounds_.y(),
+ window_bounds.width(), half_m_height);
+ break;
+
+ case BOTTOM_OF_WINDOW:
+ new_window_bounds->SetRect(window_bounds.x(),
+ monitor_bounds_.y() + half_m_height,
+ window_bounds.width(), half_m_height);
+ break;
+
+ case LEFT_HALF:
+ new_window_bounds->SetRect(monitor_bounds_.x(), monitor_bounds_.y(),
+ half_m_width, monitor_bounds_.height());
+ break;
+
+ case RIGHT_HALF:
+ new_window_bounds->SetRect(monitor_bounds_.right() - half_m_width,
+ monitor_bounds_.y(), half_m_width, monitor_bounds_.height());
+ break;
+
+ case BOTTOM_HALF:
+ new_window_bounds->SetRect(monitor_bounds_.x(),
+ monitor_bounds_.y() + half_m_height,
+ monitor_bounds_.width(), half_m_height);
+ break;
+
+ case MAXIMIZE:
+ *maximize_new_window = true;
+ break;
+
+ default:
+ NOTREACHED();
+ }
+ return true;
+}
+
+void DockInfo::AdjustOtherWindowBounds() const {
+ if (!in_enable_area_)
+ return;
+
+ gfx::Rect window_bounds;
+ if (!window_ || !GetWindowBounds(&window_bounds))
+ return;
+
+ gfx::Rect other_window_bounds;
+ int half_m_width = (monitor_bounds_.right() - monitor_bounds_.x()) / 2;
+ int half_m_height = (monitor_bounds_.bottom() - monitor_bounds_.y()) / 2;
+
+ switch (type_) {
+ case LEFT_OF_WINDOW:
+ other_window_bounds.SetRect(monitor_bounds_.x() + half_m_width,
+ window_bounds.y(), half_m_width,
+ window_bounds.height());
+ break;
+
+ case RIGHT_OF_WINDOW:
+ other_window_bounds.SetRect(monitor_bounds_.x(), window_bounds.y(),
+ half_m_width, window_bounds.height());
+ break;
+
+ case TOP_OF_WINDOW:
+ other_window_bounds.SetRect(window_bounds.x(),
+ monitor_bounds_.y() + half_m_height,
+ window_bounds.width(), half_m_height);
+ break;
+
+ case BOTTOM_OF_WINDOW:
+ other_window_bounds.SetRect(window_bounds.x(), monitor_bounds_.y(),
+ window_bounds.width(), half_m_height);
+ break;
+
+ default:
+ return;
+ }
+
+ SizeOtherWindowTo(other_window_bounds);
+}
+
+gfx::Rect DockInfo::GetPopupRect() const {
+ int x = hot_spot_.x() - popup_width() / 2;
+ int y = hot_spot_.y() - popup_height() / 2;
+ switch (type_) {
+ case LEFT_OF_WINDOW:
+ case RIGHT_OF_WINDOW:
+ case TOP_OF_WINDOW:
+ case BOTTOM_OF_WINDOW: {
+ // Constrain the popup to the monitor's bounds.
+ gfx::Rect ideal_bounds(x, y, popup_width(), popup_height());
+ ideal_bounds = ideal_bounds.AdjustToFit(monitor_bounds_);
+ return ideal_bounds;
+ }
+ case DockInfo::MAXIMIZE:
+ y += popup_height() / 2;
+ break;
+ case DockInfo::LEFT_HALF:
+ x += popup_width() / 2;
+ break;
+ case DockInfo::RIGHT_HALF:
+ x -= popup_width() / 2;
+ break;
+ case DockInfo::BOTTOM_HALF:
+ y -= popup_height() / 2;
+ break;
+
+ default:
+ NOTREACHED();
+ }
+ return gfx::Rect(x, y, popup_width(), popup_height());
+}
+
+bool DockInfo::CheckMonitorPoint(const gfx::Point& screen_loc,
+ int x,
+ int y,
+ Type type) {
+ if (IsCloseToMonitorPoint(screen_loc, x, y, type, &in_enable_area_)) {
+ hot_spot_.SetPoint(x, y);
+ type_ = type;
+ return true;
+ }
+ return false;
+}
diff --git a/chrome/browser/ui/tabs/dock_info.h b/chrome/browser/ui/tabs/dock_info.h
new file mode 100644
index 0000000..fa45b1a
--- /dev/null
+++ b/chrome/browser/ui/tabs/dock_info.h
@@ -0,0 +1,190 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_UI_TABS_DOCK_INFO_H_
+#define CHROME_BROWSER_UI_TABS_DOCK_INFO_H_
+#pragma once
+
+#include <set>
+
+#include "gfx/native_widget_types.h"
+#include "gfx/point.h"
+#include "gfx/rect.h"
+
+// DockInfo is used to do determine possible dock locations for a dragged
+// tab. To use DockInfo invoke GetDockInfoAtPoint. This returns a new
+// DockInfo whose type indicates the type of dock that should occur based
+// on the screen location. As the user drags the mouse around invoke
+// IsValidForPoint, this returns true if the DockInfo is still valid for the
+// new location. If the DockInfo is not valid, invoke GetDockInfoAtPoint to
+// get the new DockInfo. Use GetNewWindowBounds to get the position to place
+// the new window at.
+//
+// DockInfos are cheap and explicitly allow copy and assignment operators.
+class DockInfo {
+ public:
+ class Factory {
+ public:
+ virtual DockInfo GetDockInfoAtPoint(
+ const gfx::Point& screen_point,
+ const std::set<gfx::NativeView>& ignore) = 0;
+
+ virtual gfx::NativeWindow GetLocalProcessWindowAtPoint(
+ const gfx::Point& screen_point,
+ const std::set<gfx::NativeView>& ignore) = 0;
+
+ protected:
+ virtual ~Factory() {}
+ };
+
+ // Possible dock positions.
+ enum Type {
+ // Indicates there is no valid dock position for the current location.
+ NONE,
+
+ // Indicates the new window should be positioned relative to the window
+ // identified by window().
+ LEFT_OF_WINDOW,
+ RIGHT_OF_WINDOW,
+ BOTTOM_OF_WINDOW,
+ TOP_OF_WINDOW,
+
+ // Indicates the window should be maximized on the monitor at hot_spot.
+ MAXIMIZE,
+
+ // Indicates the window should be docked to a specific side of the monitor.
+ LEFT_HALF,
+ RIGHT_HALF,
+ BOTTOM_HALF
+ };
+
+ DockInfo() : type_(NONE), window_(NULL), in_enable_area_(false) {}
+
+ // Returns true if |screen_loc| is close to the hotspot at |x|, |y|. If the
+ // point is close enough to the hotspot true is returned and |in_enable_area|
+ // is set appropriately.
+ static bool IsCloseToPoint(const gfx::Point& screen_loc,
+ int x,
+ int y,
+ bool* in_enable_area);
+
+ // Variant of IsCloseToPoint used for monitor relative positions.
+ static bool IsCloseToMonitorPoint(const gfx::Point& screen_loc,
+ int x,
+ int y,
+ DockInfo::Type type,
+ bool* in_enable_area);
+
+ // Sets the factory.
+ static void set_factory(Factory* factory) { factory_ = factory; }
+
+ // Size of the popup window shown to indicate a valid dock location.
+ static int popup_width();
+ static int popup_height();
+
+ // Returns the DockInfo for the specified point |screen_point|. |ignore|
+ // contains the set of windows to ignore from consideration. This contains the
+ // dragged window as well as any windows showing possible dock locations.
+ //
+ // If there is no docking position for the specified location the returned
+ // DockInfo has a type of NONE.
+ //
+ // If a Factory has been set, the method of the same name is invoked on the
+ // Factory to determine the DockInfo.
+ static DockInfo GetDockInfoAtPoint(const gfx::Point& screen_point,
+ const std::set<gfx::NativeView>& ignore);
+
+ // Returns the top most window from the current process at |screen_point|.
+ // See GetDockInfoAtPoint for a description of |ignore|. This returns NULL if
+ // there is no window from the current process at |screen_point|, or another
+ // window obscures the topmost window from our process at |screen_point|.
+ //
+ // If a Factory has been set, the method of the same name is invoked on the
+ // Factory to determine the DockInfo.
+ static gfx::NativeWindow GetLocalProcessWindowAtPoint(
+ const gfx::Point& screen_point,
+ const std::set<gfx::NativeView>& ignore);
+
+ // Returns true if this DockInfo is valid for the specified point. This
+ // resets in_enable_area based on the new location.
+ bool IsValidForPoint(const gfx::Point& screen_point);
+
+ // Returns the bounds for the new window in |new_window_bounds|. If the new
+ // window is to be maximized, |maximize_new_window| is set to true.
+ // This returns true if type is other than NONE or the mouse isn't in the
+ // enable area, false otherwise.
+ bool GetNewWindowBounds(gfx::Rect* new_window_bounds,
+ bool* maximize_new_window) const;
+
+ // Adjust the bounds of the other window during docking. Does nothing if type
+ // is NONE, in_enable_are is false, or the type is not window relative.
+ void AdjustOtherWindowBounds() const;
+
+ // Type of docking to occur.
+ void set_type(Type type) { type_ = type; }
+ Type type() const { return type_; }
+
+ // The window to dock too. Is null for dock types that are relative to the
+ // monitor.
+ void set_window(gfx::NativeWindow window) { window_ = window; }
+ gfx::NativeWindow window() const { return window_; }
+
+ // The location of the hotspot.
+ void set_hot_spot(const gfx::Point& hot_spot) { hot_spot_ = hot_spot; }
+ const gfx::Point& hot_spot() const { return hot_spot_; }
+
+ // Bounds of the monitor.
+ void set_monitor_bounds(const gfx::Rect& monitor_bounds) {
+ monitor_bounds_ = monitor_bounds;
+ }
+ const gfx::Rect& monitor_bounds() const { return monitor_bounds_; }
+
+ // Returns the bounds of the window to show the indicator for.
+ gfx::Rect GetPopupRect() const;
+
+ // Returns true if the drop should result in docking. DockInfo maintains two
+ // states (as indicated by this boolean):
+ // 1. The mouse is close enough to the hot spot such that a visual indicator
+ // should be shown, but if the user releases the mouse docking shouldn't
+ // result. This corresponds to a value of false for in_enable_area.
+ // 2. The mouse is close enough to the hot spot such that releasing the mouse
+ // should result in docking. This corresponds to a value of true for
+ // in_enable_area.
+ void set_in_enable_area(bool in_enable_area) {
+ in_enable_area_ = in_enable_area;
+ }
+ bool in_enable_area() const { return in_enable_area_; }
+
+ // Returns true if |other| is considered equal to this. Two DockInfos are
+ // considered equal if they have the same type and same window.
+ bool equals(const DockInfo& other) const {
+ return type_ == other.type_ && window_ == other.window_ &&
+ monitor_bounds_ == other.monitor_bounds_;
+ }
+
+ // If screen_loc is close enough to the hot spot given by |x| and |y|, the
+ // type and hot_spot are set from the supplied parameters. This is used
+ // internally, there is no need to invoke this otherwise.
+ bool CheckMonitorPoint(const gfx::Point& screen_loc,
+ int x,
+ int y,
+ Type type);
+
+ private:
+ // Returns the bounds of the window.
+ bool GetWindowBounds(gfx::Rect* bounds) const;
+ void SizeOtherWindowTo(const gfx::Rect& bounds) const;
+
+ Type type_;
+ gfx::NativeWindow window_;
+ gfx::Point hot_spot_;
+ gfx::Rect monitor_bounds_;
+ bool in_enable_area_;
+
+ // Factory that creates DockInfos. By default this is NULL, which gives the
+ // default behavior.
+ static Factory* factory_;
+};
+
+#endif // CHROME_BROWSER_UI_TABS_DOCK_INFO_H_
diff --git a/chrome/browser/ui/tabs/dock_info_gtk.cc b/chrome/browser/ui/tabs/dock_info_gtk.cc
new file mode 100644
index 0000000..3fb2778
--- /dev/null
+++ b/chrome/browser/ui/tabs/dock_info_gtk.cc
@@ -0,0 +1,219 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/tabs/dock_info.h"
+
+#include <gtk/gtk.h>
+
+#include "base/logging.h"
+#include "base/task.h"
+#include "chrome/browser/gtk/browser_window_gtk.h"
+#include "chrome/browser/gtk/gtk_util.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "gfx/native_widget_types.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// BaseWindowFinder
+//
+// Base class used to locate a window. A subclass need only override
+// ShouldStopIterating to determine when iteration should stop.
+class BaseWindowFinder : public x11_util::EnumerateWindowsDelegate {
+ public:
+ explicit BaseWindowFinder(const std::set<GtkWidget*>& ignore) {
+ std::set<GtkWidget*>::iterator iter;
+ for (iter = ignore.begin(); iter != ignore.end(); iter++) {
+ XID xid = x11_util::GetX11WindowFromGtkWidget(*iter);
+ ignore_.insert(xid);
+ }
+ }
+
+ virtual ~BaseWindowFinder() {}
+
+ protected:
+ // Returns true if |window| is in the ignore list.
+ bool ShouldIgnoreWindow(XID window) {
+ return (ignore_.find(window) != ignore_.end());
+ }
+
+ // Returns true if iteration should stop, false otherwise.
+ virtual bool ShouldStopIterating(XID window) {
+ return false;
+ }
+
+ private:
+ std::set<XID> ignore_;
+
+ DISALLOW_COPY_AND_ASSIGN(BaseWindowFinder);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// TopMostFinder
+//
+// Helper class to determine if a particular point of a window is not obscured
+// by another window.
+class TopMostFinder : public BaseWindowFinder {
+ public:
+ // Returns true if |window| is not obscured by another window at the
+ // location |screen_loc|, not including the windows in |ignore|.
+ static bool IsTopMostWindowAtPoint(XID window,
+ const gfx::Point& screen_loc,
+ const std::set<GtkWidget*>& ignore) {
+ TopMostFinder finder(window, screen_loc, ignore);
+ return finder.is_top_most_;
+ }
+
+ protected:
+ virtual bool ShouldStopIterating(XID window) {
+ if (BaseWindowFinder::ShouldIgnoreWindow(window))
+ return false;
+
+ if (window == target_) {
+ // Window is topmost, stop iterating.
+ is_top_most_ = true;
+ return true;
+ }
+
+ if (!x11_util::IsWindowVisible(window)) {
+ // The window isn't visible, keep iterating.
+ return false;
+ }
+
+ gfx::Rect rect;
+ if (x11_util::GetWindowRect(window, &rect) && rect.Contains(screen_loc_)) {
+ // At this point we haven't found our target window, so this window is
+ // higher in the z-order than the target window. If this window contains
+ // the point, then we can stop the search now because this window is
+ // obscuring the target window at this point.
+ return true;
+ }
+
+ return false;
+ }
+
+ private:
+ TopMostFinder(XID window,
+ const gfx::Point& screen_loc,
+ const std::set<GtkWidget*>& ignore)
+ : BaseWindowFinder(ignore),
+ target_(window),
+ screen_loc_(screen_loc),
+ is_top_most_(false) {
+ gtk_util::EnumerateTopLevelWindows(this);
+ }
+
+ // The window we're looking for.
+ XID target_;
+
+ // Location of window to find.
+ gfx::Point screen_loc_;
+
+ // Is target_ the top most window? This is initially false but set to true
+ // in ShouldStopIterating if target_ is passed in.
+ bool is_top_most_;
+
+ DISALLOW_COPY_AND_ASSIGN(TopMostFinder);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// LocalProcessWindowFinder
+//
+// Helper class to determine if a particular point of a window from our process
+// is not obscured by another window.
+class LocalProcessWindowFinder : public BaseWindowFinder {
+ public:
+ // Returns the XID from our process at screen_loc that is not obscured by
+ // another window. Returns 0 otherwise.
+ static XID GetProcessWindowAtPoint(const gfx::Point& screen_loc,
+ const std::set<GtkWidget*>& ignore) {
+ LocalProcessWindowFinder finder(screen_loc, ignore);
+ if (finder.result_ &&
+ TopMostFinder::IsTopMostWindowAtPoint(finder.result_, screen_loc,
+ ignore)) {
+ return finder.result_;
+ }
+ return 0;
+ }
+
+ protected:
+ virtual bool ShouldStopIterating(XID window) {
+ if (BaseWindowFinder::ShouldIgnoreWindow(window))
+ return false;
+
+ // Check if this window is in our process.
+ if (!BrowserWindowGtk::GetBrowserWindowForXID(window))
+ return false;
+
+ if (!x11_util::IsWindowVisible(window))
+ return false;
+
+ gfx::Rect rect;
+ if (x11_util::GetWindowRect(window, &rect) && rect.Contains(screen_loc_)) {
+ result_ = window;
+ return true;
+ }
+
+ return false;
+ }
+
+ private:
+ LocalProcessWindowFinder(const gfx::Point& screen_loc,
+ const std::set<GtkWidget*>& ignore)
+ : BaseWindowFinder(ignore),
+ screen_loc_(screen_loc),
+ result_(0) {
+ gtk_util::EnumerateTopLevelWindows(this);
+ }
+
+ // Position of the mouse.
+ gfx::Point screen_loc_;
+
+ // The resulting window. This is initially null but set to true in
+ // ShouldStopIterating if an appropriate window is found.
+ XID result_;
+
+ DISALLOW_COPY_AND_ASSIGN(LocalProcessWindowFinder);
+};
+
+// static
+DockInfo DockInfo::GetDockInfoAtPoint(const gfx::Point& screen_point,
+ const std::set<GtkWidget*>& ignore) {
+ if (factory_)
+ return factory_->GetDockInfoAtPoint(screen_point, ignore);
+
+ NOTIMPLEMENTED();
+ return DockInfo();
+}
+
+// static
+GtkWindow* DockInfo::GetLocalProcessWindowAtPoint(
+ const gfx::Point& screen_point,
+ const std::set<GtkWidget*>& ignore) {
+ if (factory_)
+ return factory_->GetLocalProcessWindowAtPoint(screen_point, ignore);
+
+#if defined(OS_CHROMEOS) || defined(TOOLKIT_VIEWS)
+ return NULL;
+#else
+ XID xid =
+ LocalProcessWindowFinder::GetProcessWindowAtPoint(screen_point, ignore);
+ return BrowserWindowGtk::GetBrowserWindowForXID(xid);
+#endif
+}
+
+bool DockInfo::GetWindowBounds(gfx::Rect* bounds) const {
+ if (!window())
+ return false;
+
+ int x, y, w, h;
+ gtk_window_get_position(window(), &x, &y);
+ gtk_window_get_size(window(), &w, &h);
+ bounds->SetRect(x, y, w, h);
+ return true;
+}
+
+void DockInfo::SizeOtherWindowTo(const gfx::Rect& bounds) const {
+ gtk_window_move(window(), bounds.x(), bounds.y());
+ gtk_window_resize(window(), bounds.width(), bounds.height());
+}
diff --git a/chrome/browser/ui/tabs/dock_info_mac.cc b/chrome/browser/ui/tabs/dock_info_mac.cc
new file mode 100644
index 0000000..4954d05
--- /dev/null
+++ b/chrome/browser/ui/tabs/dock_info_mac.cc
@@ -0,0 +1,15 @@
+// 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.
+
+#include "chrome/browser/ui/tabs/dock_info.h"
+
+bool DockInfo::GetNewWindowBounds(gfx::Rect* new_window_bounds,
+ bool* maximize_new_window) const {
+ // TODO(pinkerton): Implement DockInfo, http://crbug.com/9427.
+ return true;
+}
+
+void DockInfo::AdjustOtherWindowBounds() const {
+ // TODO(pinkerton): Implement DockInfo, http://crbug.com/9427.
+}
diff --git a/chrome/browser/ui/tabs/dock_info_unittest.cc b/chrome/browser/ui/tabs/dock_info_unittest.cc
new file mode 100644
index 0000000..ee4557e
--- /dev/null
+++ b/chrome/browser/ui/tabs/dock_info_unittest.cc
@@ -0,0 +1,191 @@
+// 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.
+
+#include "base/basictypes.h"
+#include "chrome/browser/ui/tabs/dock_info.h"
+#include "gfx/point.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+// Distance in pixels between the hotspot and when the hint should be shown.
+const int kHotSpotDeltaX = 120;
+const int kHotSpotDeltaY = 120;
+// Size of the popup window.
+const int kPopupWidth = 70;
+const int kPopupHeight = 70;
+} // namespace
+
+TEST(DockInfoTest, IsCloseToPoint) {
+ bool in_enable_area;
+ gfx::Point screen_loc[] = {
+ gfx::Point(0, 0),
+ gfx::Point(kPopupWidth/2 - 1, kPopupHeight/2 - 1),
+ gfx::Point(kPopupWidth/2, kPopupHeight/2),
+ gfx::Point(kHotSpotDeltaX - 1, kHotSpotDeltaY - 1),
+ gfx::Point(kHotSpotDeltaX, kHotSpotDeltaY),
+ gfx::Point(-kHotSpotDeltaX, -kHotSpotDeltaY)
+ };
+ gfx::Point hotspot[] = {
+ gfx::Point(0, 0),
+ gfx::Point(0, 0),
+ gfx::Point(kPopupWidth, kPopupHeight),
+ gfx::Point(0, 0),
+ gfx::Point(2*kHotSpotDeltaX, 2*kHotSpotDeltaY),
+ gfx::Point(0, 0)
+ };
+ bool expected_results[] = {
+ true, true, true, true, false, false
+ };
+ bool expected_in_enable_area[] = {
+ true, true, false, false, false, false
+ };
+
+ for (size_t i = 0; i < arraysize(expected_results); ++i) {
+ bool result = DockInfo::IsCloseToPoint(
+ screen_loc[i], hotspot[i].x(), hotspot[i].y(), &in_enable_area);
+ EXPECT_EQ(expected_results[i], result);
+ EXPECT_EQ(expected_in_enable_area[i], in_enable_area);
+ }
+}
+
+TEST(DockInfoTest, IsCloseToMonitorPoint) {
+ bool in_enable_area;
+ gfx::Point screen_loc[] = {
+ gfx::Point(0, 0),
+ gfx::Point(kPopupWidth - 1, kPopupHeight/2 -1),
+ gfx::Point(kPopupWidth, kPopupHeight/2 - 1),
+ gfx::Point(kPopupWidth - 1, kPopupHeight),
+ gfx::Point(2*kHotSpotDeltaX, kHotSpotDeltaY - 1),
+ gfx::Point(2*kHotSpotDeltaX - 1, kHotSpotDeltaY),
+ gfx::Point(2*kHotSpotDeltaX - 1, kHotSpotDeltaY),
+ gfx::Point(0, 0),
+ gfx::Point(kPopupWidth/2 - 1, kPopupHeight - 1),
+ gfx::Point(kPopupWidth/2 - 1, kPopupHeight),
+ gfx::Point(kPopupWidth/2, kPopupHeight - 1),
+ gfx::Point(kHotSpotDeltaX - 1, 2*kHotSpotDeltaY),
+ gfx::Point(kHotSpotDeltaX, 2*kHotSpotDeltaY - 1),
+ };
+ gfx::Point hotspot = gfx::Point(0, 0);
+ DockInfo::Type type[] = {
+ DockInfo::LEFT_HALF,
+ DockInfo::LEFT_HALF,
+ DockInfo::LEFT_HALF,
+ DockInfo::LEFT_HALF,
+ DockInfo::LEFT_HALF,
+ DockInfo::LEFT_HALF,
+ DockInfo::RIGHT_HALF,
+ DockInfo::BOTTOM_HALF,
+ DockInfo::BOTTOM_HALF,
+ DockInfo::BOTTOM_HALF,
+ DockInfo::BOTTOM_HALF,
+ DockInfo::BOTTOM_HALF,
+ DockInfo::BOTTOM_HALF,
+ };
+ bool expected_results[] = {
+ true, true, true, true, false, false, false,
+ true, true, true, true, false, false
+ };
+ bool expected_in_enable_area[] = {
+ true, true, false, false, false, false, false,
+ true, true, false, false, false, false
+ };
+
+ for (size_t i = 0; i < arraysize(expected_results); ++i) {
+ bool result = DockInfo::IsCloseToMonitorPoint(
+ screen_loc[i], hotspot.x(), hotspot.y(), type[i], &in_enable_area);
+ EXPECT_EQ(expected_results[i], result);
+ EXPECT_EQ(expected_in_enable_area[i], in_enable_area);
+ }
+}
+
+TEST(DockInfoTest, IsValidForPoint) {
+ DockInfo d;
+ EXPECT_EQ(false, d.IsValidForPoint(gfx::Point(0, 0)));
+ d.set_monitor_bounds(gfx::Rect(0, 0, kPopupWidth, kPopupHeight));
+ d.set_hot_spot(gfx::Point(0, 0));
+ d.set_type(DockInfo::LEFT_HALF);
+
+ gfx::Point screen_point[] = {
+ gfx::Point(0, 0),
+ gfx::Point(kPopupWidth + 1, kPopupHeight + 1),
+ gfx::Point(2 * kHotSpotDeltaX, kHotSpotDeltaY),
+ };
+
+ bool expected_result[] = {
+ true, false, false
+ };
+
+ for (size_t i = 0; i < arraysize(expected_result); ++i) {
+ EXPECT_EQ(expected_result[i], d.IsValidForPoint(screen_point[i]));
+ }
+}
+
+TEST(DockInfoTest, equals) {
+ DockInfo d;
+ DockInfo dd;
+ EXPECT_EQ(true, d.equals(dd));
+ d.set_type(DockInfo::MAXIMIZE);
+ EXPECT_EQ(false, d.equals(dd));
+}
+
+TEST(DockInfoTest, CheckMonitorPoint) {
+ DockInfo d;
+ gfx::Point screen_loc[] = {
+ gfx::Point(0, 0),
+ gfx::Point(2 * kHotSpotDeltaX, kHotSpotDeltaY),
+ gfx::Point(2 * kHotSpotDeltaX, kHotSpotDeltaY),
+ };
+
+ DockInfo::Type type[] = {
+ DockInfo::LEFT_HALF,
+ DockInfo::RIGHT_HALF,
+ DockInfo::MAXIMIZE
+ };
+
+ bool expected_result[] = {
+ true, false, false
+ };
+
+ for (size_t i = 0; i < arraysize(expected_result); ++i) {
+ bool result = d.CheckMonitorPoint(screen_loc[i], 0, 0, type[i]);
+ EXPECT_EQ(result, expected_result[i]);
+ if (result == true) {
+ EXPECT_EQ(0, d.hot_spot().x());
+ EXPECT_EQ(0, d.hot_spot().y());
+ EXPECT_EQ(type[i], d.type());
+ }
+ }
+}
+
+TEST(DockInfoTest, GetPopupRect) {
+ DockInfo d;
+ d.set_hot_spot(gfx::Point(kPopupWidth, kPopupHeight));
+ DockInfo::Type type[] = {
+ DockInfo::MAXIMIZE,
+ DockInfo::LEFT_HALF,
+ DockInfo::RIGHT_HALF,
+ DockInfo::BOTTOM_HALF,
+ };
+ int expected_x[] = {
+ kPopupWidth/2,
+ kPopupWidth,
+ 0,
+ kPopupWidth/2
+ };
+ int expected_y[] = {
+ kPopupHeight,
+ kPopupHeight/2,
+ kPopupHeight/2,
+ 0
+ };
+
+ for (size_t i = 0; i < arraysize(type); ++i) {
+ d.set_type(type[i]);
+ gfx::Rect result = d.GetPopupRect();
+ EXPECT_EQ(expected_x[i], result.x());
+ EXPECT_EQ(expected_y[i], result.y());
+ EXPECT_EQ(kPopupWidth, result.width());
+ EXPECT_EQ(kPopupHeight, result.height());
+ }
+}
diff --git a/chrome/browser/ui/tabs/dock_info_win.cc b/chrome/browser/ui/tabs/dock_info_win.cc
new file mode 100644
index 0000000..dee78cf
--- /dev/null
+++ b/chrome/browser/ui/tabs/dock_info_win.cc
@@ -0,0 +1,325 @@
+// 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.
+
+#include "chrome/browser/ui/tabs/dock_info.h"
+
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/views/frame/browser_view.h"
+#include "chrome/browser/views/tabs/tab.h"
+
+namespace {
+
+// BaseWindowFinder -----------------------------------------------------------
+
+// Base class used to locate a window. This is intended to be used with the
+// various win32 functions that iterate over windows.
+//
+// A subclass need only override ShouldStopIterating to determine when
+// iteration should stop.
+class BaseWindowFinder {
+ public:
+ // Creates a BaseWindowFinder with the specified set of HWNDs to ignore.
+ explicit BaseWindowFinder(const std::set<HWND>& ignore) : ignore_(ignore) {}
+ virtual ~BaseWindowFinder() {}
+
+ protected:
+ // Returns true if iteration should stop, false if iteration should continue.
+ virtual bool ShouldStopIterating(HWND window) = 0;
+
+ static BOOL CALLBACK WindowCallbackProc(HWND hwnd, LPARAM lParam) {
+ BaseWindowFinder* finder = reinterpret_cast<BaseWindowFinder*>(lParam);
+ if (finder->ignore_.find(hwnd) != finder->ignore_.end())
+ return TRUE;
+
+ return finder->ShouldStopIterating(hwnd) ? FALSE : TRUE;
+ }
+
+ private:
+ const std::set<HWND>& ignore_;
+
+ DISALLOW_COPY_AND_ASSIGN(BaseWindowFinder);
+};
+
+// TopMostFinder --------------------------------------------------------------
+
+// Helper class to determine if a particular point of a window is not obscured
+// by another window.
+class TopMostFinder : public BaseWindowFinder {
+ public:
+ // Returns true if |window| is the topmost window at the location
+ // |screen_loc|, not including the windows in |ignore|.
+ static bool IsTopMostWindowAtPoint(HWND window,
+ const gfx::Point& screen_loc,
+ const std::set<HWND>& ignore) {
+ TopMostFinder finder(window, screen_loc, ignore);
+ return finder.is_top_most_;
+ }
+
+ virtual bool ShouldStopIterating(HWND hwnd) {
+ if (hwnd == target_) {
+ // Window is topmost, stop iterating.
+ is_top_most_ = true;
+ return true;
+ }
+
+ if (!IsWindowVisible(hwnd)) {
+ // The window isn't visible, keep iterating.
+ return false;
+ }
+
+ RECT r;
+ if (!GetWindowRect(hwnd, &r) || !PtInRect(&r, screen_loc_.ToPOINT())) {
+ // The window doesn't contain the point, keep iterating.
+ return false;
+ }
+
+ LONG ex_styles = GetWindowLong(hwnd, GWL_EXSTYLE);
+ if (ex_styles & WS_EX_TRANSPARENT || ex_styles & WS_EX_LAYERED) {
+ // Mouse events fall through WS_EX_TRANSPARENT windows, so we ignore them.
+ //
+ // WS_EX_LAYERED is trickier. Apps like Switcher create a totally
+ // transparent WS_EX_LAYERED window that is always on top. If we don't
+ // ignore WS_EX_LAYERED windows and there are totally transparent
+ // WS_EX_LAYERED windows then there are effectively holes on the screen
+ // that the user can't reattach tabs to. So we ignore them. This is a bit
+ // problematic in so far as WS_EX_LAYERED windows need not be totally
+ // transparent in which case we treat chrome windows as not being obscured
+ // when they really are, but this is better than not being able to
+ // reattach tabs.
+ return false;
+ }
+
+ // hwnd is at the point. Make sure the point is within the windows region.
+ if (GetWindowRgn(hwnd, tmp_region_.Get()) == ERROR) {
+ // There's no region on the window and the window contains the point. Stop
+ // iterating.
+ return true;
+ }
+
+ // The region is relative to the window's rect.
+ BOOL is_point_in_region = PtInRegion(tmp_region_.Get(),
+ screen_loc_.x() - r.left, screen_loc_.y() - r.top);
+ tmp_region_ = CreateRectRgn(0, 0, 0, 0);
+ // Stop iterating if the region contains the point.
+ return !!is_point_in_region;
+ }
+
+ private:
+ TopMostFinder(HWND window,
+ const gfx::Point& screen_loc,
+ const std::set<HWND>& ignore)
+ : BaseWindowFinder(ignore),
+ target_(window),
+ screen_loc_(screen_loc),
+ is_top_most_(false),
+ tmp_region_(CreateRectRgn(0, 0, 0, 0)) {
+ EnumWindows(WindowCallbackProc, reinterpret_cast<LPARAM>(this));
+ }
+
+ // The window we're looking for.
+ HWND target_;
+
+ // Location of window to find.
+ gfx::Point screen_loc_;
+
+ // Is target_ the top most window? This is initially false but set to true
+ // in ShouldStopIterating if target_ is passed in.
+ bool is_top_most_;
+
+ ScopedRegion tmp_region_;
+
+ DISALLOW_COPY_AND_ASSIGN(TopMostFinder);
+};
+
+// WindowFinder ---------------------------------------------------------------
+
+// Helper class to determine if a particular point contains a window from our
+// process.
+class LocalProcessWindowFinder : public BaseWindowFinder {
+ public:
+ // Returns the hwnd from our process at screen_loc that is not obscured by
+ // another window. Returns NULL otherwise.
+ static HWND GetProcessWindowAtPoint(const gfx::Point& screen_loc,
+ const std::set<HWND>& ignore) {
+ LocalProcessWindowFinder finder(screen_loc, ignore);
+ if (finder.result_ &&
+ TopMostFinder::IsTopMostWindowAtPoint(finder.result_, screen_loc,
+ ignore)) {
+ return finder.result_;
+ }
+ return NULL;
+ }
+
+ protected:
+ virtual bool ShouldStopIterating(HWND hwnd) {
+ RECT r;
+ if (IsWindowVisible(hwnd) && GetWindowRect(hwnd, &r) &&
+ PtInRect(&r, screen_loc_.ToPOINT())) {
+ result_ = hwnd;
+ return true;
+ }
+ return false;
+ }
+
+ private:
+ LocalProcessWindowFinder(const gfx::Point& screen_loc,
+ const std::set<HWND>& ignore)
+ : BaseWindowFinder(ignore),
+ screen_loc_(screen_loc),
+ result_(NULL) {
+ EnumThreadWindows(GetCurrentThreadId(), WindowCallbackProc,
+ reinterpret_cast<LPARAM>(this));
+ }
+
+ // Position of the mouse.
+ gfx::Point screen_loc_;
+
+ // The resulting window. This is initially null but set to true in
+ // ShouldStopIterating if an appropriate window is found.
+ HWND result_;
+
+ DISALLOW_COPY_AND_ASSIGN(LocalProcessWindowFinder);
+};
+
+// DockToWindowFinder ---------------------------------------------------------
+
+// Helper class for creating a DockInfo from a specified point.
+class DockToWindowFinder : public BaseWindowFinder {
+ public:
+ // Returns the DockInfo for the specified point. If there is no docking
+ // position for the specified point the returned DockInfo has a type of NONE.
+ static DockInfo GetDockInfoAtPoint(const gfx::Point& screen_loc,
+ const std::set<HWND>& ignore) {
+ DockToWindowFinder finder(screen_loc, ignore);
+ if (!finder.result_.window() ||
+ !TopMostFinder::IsTopMostWindowAtPoint(finder.result_.window(),
+ finder.result_.hot_spot(),
+ ignore)) {
+ finder.result_.set_type(DockInfo::NONE);
+ }
+ return finder.result_;
+ }
+
+ protected:
+ virtual bool ShouldStopIterating(HWND hwnd) {
+ BrowserView* window = BrowserView::GetBrowserViewForNativeWindow(hwnd);
+ RECT bounds;
+ if (!window || !IsWindowVisible(hwnd) ||
+ !GetWindowRect(hwnd, &bounds)) {
+ return false;
+ }
+
+ // Check the three corners we allow docking to. We don't currently allow
+ // docking to top of window as it conflicts with docking to the tab strip.
+ if (CheckPoint(hwnd, bounds.left, (bounds.top + bounds.bottom) / 2,
+ DockInfo::LEFT_OF_WINDOW) ||
+ CheckPoint(hwnd, bounds.right - 1, (bounds.top + bounds.bottom) / 2,
+ DockInfo::RIGHT_OF_WINDOW) ||
+ CheckPoint(hwnd, (bounds.left + bounds.right) / 2, bounds.bottom - 1,
+ DockInfo::BOTTOM_OF_WINDOW)) {
+ return true;
+ }
+ return false;
+ }
+
+ private:
+ DockToWindowFinder(const gfx::Point& screen_loc,
+ const std::set<HWND>& ignore)
+ : BaseWindowFinder(ignore),
+ screen_loc_(screen_loc) {
+ HMONITOR monitor = MonitorFromPoint(screen_loc.ToPOINT(),
+ MONITOR_DEFAULTTONULL);
+ MONITORINFO monitor_info = {0};
+ monitor_info.cbSize = sizeof(MONITORINFO);
+ if (monitor && GetMonitorInfo(monitor, &monitor_info)) {
+ result_.set_monitor_bounds(gfx::Rect(monitor_info.rcWork));
+ EnumThreadWindows(GetCurrentThreadId(), WindowCallbackProc,
+ reinterpret_cast<LPARAM>(this));
+ }
+ }
+
+ bool CheckPoint(HWND hwnd, int x, int y, DockInfo::Type type) {
+ bool in_enable_area;
+ if (DockInfo::IsCloseToPoint(screen_loc_, x, y, &in_enable_area)) {
+ result_.set_in_enable_area(in_enable_area);
+ result_.set_window(hwnd);
+ result_.set_type(type);
+ result_.set_hot_spot(gfx::Point(x, y));
+ // Only show the hotspot if the monitor contains the bounds of the popup
+ // window. Otherwise we end with a weird situation where the popup window
+ // isn't completely visible.
+ return result_.monitor_bounds().Contains(result_.GetPopupRect());
+ }
+ return false;
+ }
+
+ // The location to look for.
+ gfx::Point screen_loc_;
+
+ // The resulting DockInfo.
+ DockInfo result_;
+
+ DISALLOW_COPY_AND_ASSIGN(DockToWindowFinder);
+};
+
+} // namespace
+
+// DockInfo -------------------------------------------------------------------
+
+// static
+DockInfo DockInfo::GetDockInfoAtPoint(const gfx::Point& screen_point,
+ const std::set<HWND>& ignore) {
+ if (factory_)
+ return factory_->GetDockInfoAtPoint(screen_point, ignore);
+
+ // Try docking to a window first.
+ DockInfo info = DockToWindowFinder::GetDockInfoAtPoint(screen_point, ignore);
+ if (info.type() != DockInfo::NONE)
+ return info;
+
+ // No window relative positions. Try monitor relative positions.
+ const gfx::Rect& m_bounds = info.monitor_bounds();
+ int mid_x = m_bounds.x() + m_bounds.width() / 2;
+ int mid_y = m_bounds.y() + m_bounds.height() / 2;
+
+ bool result =
+ info.CheckMonitorPoint(screen_point, mid_x, m_bounds.y(),
+ DockInfo::MAXIMIZE) ||
+ info.CheckMonitorPoint(screen_point, mid_x, m_bounds.bottom(),
+ DockInfo::BOTTOM_HALF) ||
+ info.CheckMonitorPoint(screen_point, m_bounds.x(), mid_y,
+ DockInfo::LEFT_HALF) ||
+ info.CheckMonitorPoint(screen_point, m_bounds.right(), mid_y,
+ DockInfo::RIGHT_HALF);
+
+ return info;
+}
+
+HWND DockInfo::GetLocalProcessWindowAtPoint(const gfx::Point& screen_point,
+ const std::set<HWND>& ignore) {
+ if (factory_)
+ return factory_->GetLocalProcessWindowAtPoint(screen_point, ignore);
+ return
+ LocalProcessWindowFinder::GetProcessWindowAtPoint(screen_point, ignore);
+}
+
+bool DockInfo::GetWindowBounds(gfx::Rect* bounds) const {
+ RECT window_rect;
+ if (!window() || !GetWindowRect(window(), &window_rect))
+ return false;
+ *bounds = gfx::Rect(window_rect);
+ return true;
+}
+
+void DockInfo::SizeOtherWindowTo(const gfx::Rect& bounds) const {
+ if (IsZoomed(window())) {
+ // We're docking relative to another window, we need to make sure the
+ // window we're docking to isn't maximized.
+ ShowWindow(window(), SW_RESTORE | SW_SHOWNA);
+ }
+ SetWindowPos(window(), HWND_TOP, bounds.x(), bounds.y(), bounds.width(),
+ bounds.height(), SWP_NOACTIVATE | SWP_NOOWNERZORDER);
+}
diff --git a/chrome/browser/ui/tabs/tab_menu_model.cc b/chrome/browser/ui/tabs/tab_menu_model.cc
new file mode 100644
index 0000000..6d96adb
--- /dev/null
+++ b/chrome/browser/ui/tabs/tab_menu_model.cc
@@ -0,0 +1,54 @@
+// 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.
+
+#include "chrome/browser/ui/tabs/tab_menu_model.h"
+
+#include "base/command_line.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
+#include "grit/generated_resources.h"
+
+TabMenuModel::TabMenuModel(menus::SimpleMenuModel::Delegate* delegate,
+ bool is_pinned)
+ : menus::SimpleMenuModel(delegate) {
+ Build(is_pinned);
+}
+
+// static
+bool TabMenuModel::AreVerticalTabsEnabled() {
+#if defined(TOOLKIT_VIEWS) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
+ return CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableVerticalTabs);
+#else
+ return false;
+#endif
+}
+
+void TabMenuModel::Build(bool is_pinned) {
+ AddItemWithStringId(TabStripModel::CommandNewTab, IDS_TAB_CXMENU_NEWTAB);
+ AddSeparator();
+ AddItemWithStringId(TabStripModel::CommandReload, IDS_TAB_CXMENU_RELOAD);
+ AddItemWithStringId(TabStripModel::CommandDuplicate,
+ IDS_TAB_CXMENU_DUPLICATE);
+ AddItemWithStringId(
+ TabStripModel::CommandTogglePinned,
+ is_pinned ? IDS_TAB_CXMENU_UNPIN_TAB : IDS_TAB_CXMENU_PIN_TAB);
+ AddSeparator();
+ AddItemWithStringId(TabStripModel::CommandCloseTab,
+ IDS_TAB_CXMENU_CLOSETAB);
+ AddItemWithStringId(TabStripModel::CommandCloseOtherTabs,
+ IDS_TAB_CXMENU_CLOSEOTHERTABS);
+ AddItemWithStringId(TabStripModel::CommandCloseTabsToRight,
+ IDS_TAB_CXMENU_CLOSETABSTORIGHT);
+ AddSeparator();
+ AddItemWithStringId(TabStripModel::CommandRestoreTab, IDS_RESTORE_TAB);
+ AddItemWithStringId(TabStripModel::CommandBookmarkAllTabs,
+ IDS_TAB_CXMENU_BOOKMARK_ALL_TABS);
+ if (AreVerticalTabsEnabled()) {
+ AddSeparator();
+ AddCheckItemWithStringId(TabStripModel::CommandUseVerticalTabs,
+ IDS_TAB_CXMENU_USE_VERTICAL_TABS);
+ }
+}
diff --git a/chrome/browser/ui/tabs/tab_menu_model.h b/chrome/browser/ui/tabs/tab_menu_model.h
new file mode 100644
index 0000000..aeff953
--- /dev/null
+++ b/chrome/browser/ui/tabs/tab_menu_model.h
@@ -0,0 +1,29 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_TABS_TAB_MENU_MODEL_H_
+#define CHROME_BROWSER_UI_TABS_TAB_MENU_MODEL_H_
+#pragma once
+
+#include "app/menus/simple_menu_model.h"
+
+// A menu model that builds the contents of the tab context menu. This menu has
+// only one level (no submenus). TabMenuModel caches local state from the
+// tab (such as the pinned state). To make sure the menu reflects the real state
+// of the tab a new TabMenuModel should be created each time the menu is shown.
+class TabMenuModel : public menus::SimpleMenuModel {
+ public:
+ TabMenuModel(menus::SimpleMenuModel::Delegate* delegate, bool is_pinned);
+ virtual ~TabMenuModel() {}
+
+ // Returns true if vertical tabs are enabled.
+ static bool AreVerticalTabsEnabled();
+
+ private:
+ void Build(bool is_pinned);
+
+ DISALLOW_COPY_AND_ASSIGN(TabMenuModel);
+};
+
+#endif // CHROME_BROWSER_UI_TABS_TAB_MENU_MODEL_H_
diff --git a/chrome/browser/ui/tabs/tab_menu_model_unittest.cc b/chrome/browser/ui/tabs/tab_menu_model_unittest.cc
new file mode 100644
index 0000000..9f30412
--- /dev/null
+++ b/chrome/browser/ui/tabs/tab_menu_model_unittest.cc
@@ -0,0 +1,26 @@
+// 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.
+
+#include "chrome/browser/ui/tabs/tab_menu_model.h"
+
+#include "chrome/test/menu_model_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+class TabMenuModelTest : public PlatformTest, public MenuModelTest {
+};
+
+TEST_F(TabMenuModelTest, Basics) {
+ TabMenuModel model(&delegate_, true);
+
+ // Verify it has items. The number varies by platform, so we don't check
+ // the exact number.
+ EXPECT_GT(model.GetItemCount(), 5);
+
+ int item_count = 0;
+ CountEnabledExecutable(&model, &item_count);
+ EXPECT_GT(item_count, 0);
+ EXPECT_EQ(item_count, delegate_.execute_count_);
+ EXPECT_EQ(item_count, delegate_.enable_count_);
+}
diff --git a/chrome/browser/browser_uitest.cc b/chrome/browser/ui/tests/browser_uitest.cc
index 6b8c735..6b8c735 100644
--- a/chrome/browser/browser_uitest.cc
+++ b/chrome/browser/ui/tests/browser_uitest.cc
diff --git a/chrome/browser/ui/toolbar/back_forward_menu_model.cc b/chrome/browser/ui/toolbar/back_forward_menu_model.cc
new file mode 100644
index 0000000..390dce0
--- /dev/null
+++ b/chrome/browser/ui/toolbar/back_forward_menu_model.cc
@@ -0,0 +1,379 @@
+// 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.
+
+#include "build/build_config.h"
+
+#include "chrome/browser/ui/toolbar/back_forward_menu_model.h"
+
+#include "app/l10n_util.h"
+#include "app/text_elider.h"
+#include "app/resource_bundle.h"
+#include "base/string_number_conversions.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/tab_contents/navigation_controller.h"
+#include "chrome/browser/tab_contents/navigation_entry.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/common/url_constants.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "net/base/registry_controlled_domain.h"
+
+const int BackForwardMenuModel::kMaxHistoryItems = 12;
+const int BackForwardMenuModel::kMaxChapterStops = 5;
+static const int kMaxWidth = 700;
+
+BackForwardMenuModel::BackForwardMenuModel(Browser* browser,
+ ModelType model_type)
+ : browser_(browser),
+ test_tab_contents_(NULL),
+ model_type_(model_type) {
+}
+
+bool BackForwardMenuModel::HasIcons() const {
+ return true;
+}
+
+int BackForwardMenuModel::GetItemCount() const {
+ int items = GetHistoryItemCount();
+
+ if (items > 0) {
+ int chapter_stops = 0;
+
+ // Next, we count ChapterStops, if any.
+ if (items == kMaxHistoryItems)
+ chapter_stops = GetChapterStopCount(items);
+
+ if (chapter_stops)
+ items += chapter_stops + 1; // Chapter stops also need a separator.
+
+ // If the menu is not empty, add two positions in the end
+ // for a separator and a "Show Full History" item.
+ items += 2;
+ }
+
+ return items;
+}
+
+menus::MenuModel::ItemType BackForwardMenuModel::GetTypeAt(int index) const {
+ return IsSeparator(index) ? TYPE_SEPARATOR : TYPE_COMMAND;
+}
+
+int BackForwardMenuModel::GetCommandIdAt(int index) const {
+ return index;
+}
+
+string16 BackForwardMenuModel::GetLabelAt(int index) const {
+ // Return label "Show Full History" for the last item of the menu.
+ if (index == GetItemCount() - 1)
+ return l10n_util::GetStringUTF16(IDS_SHOWFULLHISTORY_LINK);
+
+ // Return an empty string for a separator.
+ if (IsSeparator(index))
+ return string16();
+
+ // Return the entry title, escaping any '&' characters and eliding it if it's
+ // super long.
+ NavigationEntry* entry = GetNavigationEntry(index);
+ string16 menu_text(entry->GetTitleForDisplay(
+ &GetTabContents()->controller()));
+ menu_text = gfx::ElideText(menu_text, gfx::Font(), kMaxWidth, false);
+
+ for (size_t i = menu_text.find('&'); i != string16::npos;
+ i = menu_text.find('&', i + 2)) {
+ menu_text.insert(i, 1, '&');
+ }
+ return menu_text;
+}
+
+bool BackForwardMenuModel::IsItemDynamicAt(int index) const {
+ // This object is only used for a single showing of a menu.
+ return false;
+}
+
+bool BackForwardMenuModel::GetAcceleratorAt(
+ int index,
+ menus::Accelerator* accelerator) const {
+ return false;
+}
+
+bool BackForwardMenuModel::IsItemCheckedAt(int index) const {
+ return false;
+}
+
+int BackForwardMenuModel::GetGroupIdAt(int index) const {
+ return false;
+}
+
+bool BackForwardMenuModel::GetIconAt(int index, SkBitmap* icon) const {
+ if (!ItemHasIcon(index))
+ return false;
+
+ if (index == GetItemCount() - 1) {
+ *icon = *ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_HISTORY_FAVICON);
+ } else {
+ NavigationEntry* entry = GetNavigationEntry(index);
+ *icon = entry->favicon().bitmap();
+ }
+
+ return true;
+}
+
+menus::ButtonMenuItemModel* BackForwardMenuModel::GetButtonMenuItemAt(
+ int index) const {
+ return NULL;
+}
+
+bool BackForwardMenuModel::IsEnabledAt(int index) const {
+ return index < GetItemCount() && !IsSeparator(index);
+}
+
+menus::MenuModel* BackForwardMenuModel::GetSubmenuModelAt(int index) const {
+ return NULL;
+}
+
+void BackForwardMenuModel::HighlightChangedTo(int index) {
+}
+
+void BackForwardMenuModel::ActivatedAt(int index) {
+ ActivatedAtWithDisposition(index, CURRENT_TAB);
+}
+
+void BackForwardMenuModel::ActivatedAtWithDisposition(
+ int index, int disposition) {
+ Profile* profile = browser_->profile();
+
+ DCHECK(!IsSeparator(index));
+
+ // Execute the command for the last item: "Show Full History".
+ if (index == GetItemCount() - 1) {
+ UserMetrics::RecordComputedAction(BuildActionName("ShowFullHistory", -1),
+ profile);
+ browser_->ShowSingletonTab(GURL(chrome::kChromeUIHistoryURL), false);
+ return;
+ }
+
+ // Log whether it was a history or chapter click.
+ if (index < GetHistoryItemCount()) {
+ UserMetrics::RecordComputedAction(
+ BuildActionName("HistoryClick", index), profile);
+ } else {
+ UserMetrics::RecordComputedAction(
+ BuildActionName("ChapterClick", index - GetHistoryItemCount() - 1),
+ profile);
+ }
+
+ int controller_index = MenuIndexToNavEntryIndex(index);
+ if (!browser_->NavigateToIndexWithDisposition(
+ controller_index, static_cast<WindowOpenDisposition>(disposition))) {
+ NOTREACHED();
+ }
+}
+
+void BackForwardMenuModel::MenuWillShow() {
+ UserMetrics::RecordComputedAction(BuildActionName("Popup", -1),
+ browser_->profile());
+}
+
+bool BackForwardMenuModel::IsSeparator(int index) const {
+ int history_items = GetHistoryItemCount();
+ // If the index is past the number of history items + separator,
+ // we then consider if it is a chapter-stop entry.
+ if (index > history_items) {
+ // We either are in ChapterStop area, or at the end of the list (the "Show
+ // Full History" link).
+ int chapter_stops = GetChapterStopCount(history_items);
+ if (chapter_stops == 0)
+ return false; // We must have reached the "Show Full History" link.
+ // Otherwise, look to see if we have reached the separator for the
+ // chapter-stops. If not, this is a chapter stop.
+ return (index == history_items + 1 + chapter_stops);
+ }
+
+ // Look to see if we have reached the separator for the history items.
+ return index == history_items;
+}
+
+int BackForwardMenuModel::GetHistoryItemCount() const {
+ TabContents* contents = GetTabContents();
+ int items = 0;
+
+ if (model_type_ == FORWARD_MENU) {
+ // Only count items from n+1 to end (if n is current entry)
+ items = contents->controller().entry_count() -
+ contents->controller().GetCurrentEntryIndex() - 1;
+ } else {
+ items = contents->controller().GetCurrentEntryIndex();
+ }
+
+ if (items > kMaxHistoryItems)
+ items = kMaxHistoryItems;
+ else if (items < 0)
+ items = 0;
+
+ return items;
+}
+
+int BackForwardMenuModel::GetChapterStopCount(int history_items) const {
+ TabContents* contents = GetTabContents();
+
+ int chapter_stops = 0;
+ int current_entry = contents->controller().GetCurrentEntryIndex();
+
+ if (history_items == kMaxHistoryItems) {
+ int chapter_id = current_entry;
+ if (model_type_ == FORWARD_MENU) {
+ chapter_id += history_items;
+ } else {
+ chapter_id -= history_items;
+ }
+
+ do {
+ chapter_id = GetIndexOfNextChapterStop(chapter_id,
+ model_type_ == FORWARD_MENU);
+ if (chapter_id != -1)
+ ++chapter_stops;
+ } while (chapter_id != -1 && chapter_stops < kMaxChapterStops);
+ }
+
+ return chapter_stops;
+}
+
+int BackForwardMenuModel::GetIndexOfNextChapterStop(int start_from,
+ bool forward) const {
+ TabContents* contents = GetTabContents();
+ NavigationController& controller = contents->controller();
+
+ int max_count = controller.entry_count();
+ if (start_from < 0 || start_from >= max_count)
+ return -1; // Out of bounds.
+
+ if (forward) {
+ if (start_from < max_count - 1) {
+ // We want to advance over the current chapter stop, so we add one.
+ // We don't need to do this when direction is backwards.
+ start_from++;
+ } else {
+ return -1;
+ }
+ }
+
+ NavigationEntry* start_entry = controller.GetEntryAtIndex(start_from);
+ const GURL& url = start_entry->url();
+
+ if (!forward) {
+ // When going backwards we return the first entry we find that has a
+ // different domain.
+ for (int i = start_from - 1; i >= 0; --i) {
+ if (!net::RegistryControlledDomainService::SameDomainOrHost(url,
+ controller.GetEntryAtIndex(i)->url()))
+ return i;
+ }
+ // We have reached the beginning without finding a chapter stop.
+ return -1;
+ } else {
+ // When going forwards we return the entry before the entry that has a
+ // different domain.
+ for (int i = start_from + 1; i < max_count; ++i) {
+ if (!net::RegistryControlledDomainService::SameDomainOrHost(url,
+ controller.GetEntryAtIndex(i)->url()))
+ return i - 1;
+ }
+ // Last entry is always considered a chapter stop.
+ return max_count - 1;
+ }
+}
+
+int BackForwardMenuModel::FindChapterStop(int offset,
+ bool forward,
+ int skip) const {
+ if (offset < 0 || skip < 0)
+ return -1;
+
+ if (!forward)
+ offset *= -1;
+
+ TabContents* contents = GetTabContents();
+ int entry = contents->controller().GetCurrentEntryIndex() + offset;
+ for (int i = 0; i < skip + 1; i++)
+ entry = GetIndexOfNextChapterStop(entry, forward);
+
+ return entry;
+}
+
+bool BackForwardMenuModel::ItemHasCommand(int index) const {
+ return index < GetItemCount() && !IsSeparator(index);
+}
+
+bool BackForwardMenuModel::ItemHasIcon(int index) const {
+ return index < GetItemCount() && !IsSeparator(index);
+}
+
+string16 BackForwardMenuModel::GetShowFullHistoryLabel() const {
+ return l10n_util::GetStringUTF16(IDS_SHOWFULLHISTORY_LINK);
+}
+
+TabContents* BackForwardMenuModel::GetTabContents() const {
+ // We use the test tab contents if the unit test has specified it.
+ return test_tab_contents_ ? test_tab_contents_ :
+ browser_->GetSelectedTabContents();
+}
+
+int BackForwardMenuModel::MenuIndexToNavEntryIndex(int index) const {
+ TabContents* contents = GetTabContents();
+ int history_items = GetHistoryItemCount();
+
+ DCHECK_GE(index, 0);
+
+ // Convert anything above the History items separator.
+ if (index < history_items) {
+ if (model_type_ == FORWARD_MENU) {
+ index += contents->controller().GetCurrentEntryIndex() + 1;
+ } else {
+ // Back menu is reverse.
+ index = contents->controller().GetCurrentEntryIndex() - (index + 1);
+ }
+ return index;
+ }
+ if (index == history_items)
+ return -1; // Don't translate the separator for history items.
+
+ if (index >= history_items + 1 + GetChapterStopCount(history_items))
+ return -1; // This is beyond the last chapter stop so we abort.
+
+ // This menu item is a chapter stop located between the two separators.
+ index = FindChapterStop(history_items,
+ model_type_ == FORWARD_MENU,
+ index - history_items - 1);
+
+ return index;
+}
+
+NavigationEntry* BackForwardMenuModel::GetNavigationEntry(int index) const {
+ int controller_index = MenuIndexToNavEntryIndex(index);
+ NavigationController& controller = GetTabContents()->controller();
+ if (controller_index >= 0 && controller_index < controller.entry_count())
+ return controller.GetEntryAtIndex(controller_index);
+
+ NOTREACHED();
+ return NULL;
+}
+
+std::string BackForwardMenuModel::BuildActionName(
+ const std::string& action, int index) const {
+ DCHECK(!action.empty());
+ DCHECK(index >= -1);
+ std::string metric_string;
+ if (model_type_ == FORWARD_MENU)
+ metric_string += "ForwardMenu_";
+ else
+ metric_string += "BackMenu_";
+ metric_string += action;
+ if (index != -1) {
+ // +1 is for historical reasons (indices used to start at 1).
+ metric_string += base::IntToString(index + 1);
+ }
+ return metric_string;
+}
diff --git a/chrome/browser/ui/toolbar/back_forward_menu_model.h b/chrome/browser/ui/toolbar/back_forward_menu_model.h
new file mode 100644
index 0000000..1d669a0
--- /dev/null
+++ b/chrome/browser/ui/toolbar/back_forward_menu_model.h
@@ -0,0 +1,171 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_TOOLBAR_BACK_FORWARD_MENU_MODEL_H_
+#define CHROME_BROWSER_UI_TOOLBAR_BACK_FORWARD_MENU_MODEL_H_
+#pragma once
+
+#include <string>
+
+#include "app/menus/menu_model.h"
+#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
+#include "base/string16.h"
+#include "webkit/glue/window_open_disposition.h"
+
+class Browser;
+class SkBitmap;
+class TabContents;
+class NavigationEntry;
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// BackForwardMenuModel
+//
+// Interface for the showing of the dropdown menu for the Back/Forward buttons.
+// Actual implementations are platform-specific.
+///////////////////////////////////////////////////////////////////////////////
+class BackForwardMenuModel : public menus::MenuModel {
+ public:
+ // These are IDs used to identify individual UI elements within the
+ // browser window using View::GetViewByID.
+ enum ModelType {
+ FORWARD_MENU = 1,
+ BACKWARD_MENU = 2
+ };
+
+ BackForwardMenuModel(Browser* browser, ModelType model_type);
+ virtual ~BackForwardMenuModel() { }
+
+ // MenuModel implementation.
+ virtual bool HasIcons() const;
+ // Returns how many items the menu should show, including history items,
+ // chapter-stops, separators and the Show Full History link. This function
+ // uses GetHistoryItemCount() and GetChapterStopCount() internally to figure
+ // out the total number of items to show.
+ virtual int GetItemCount() const;
+ virtual ItemType GetTypeAt(int index) const;
+ virtual int GetCommandIdAt(int index) const;
+ virtual string16 GetLabelAt(int index) const;
+ virtual bool IsItemDynamicAt(int index) const;
+ virtual bool GetAcceleratorAt(int index,
+ menus::Accelerator* accelerator) const;
+ virtual bool IsItemCheckedAt(int index) const;
+ virtual int GetGroupIdAt(int index) const;
+ virtual bool GetIconAt(int index, SkBitmap* icon) const;
+ virtual menus::ButtonMenuItemModel* GetButtonMenuItemAt(int index) const;
+ virtual bool IsEnabledAt(int index) const;
+ virtual MenuModel* GetSubmenuModelAt(int index) const;
+ virtual void HighlightChangedTo(int index);
+ virtual void ActivatedAt(int index);
+ virtual void ActivatedAtWithDisposition(int index, int disposition);
+ virtual void MenuWillShow();
+
+ // Is the item at |index| a separator?
+ bool IsSeparator(int index) const;
+
+ private:
+ // Allows the unit test to use its own dummy tab contents.
+ void set_test_tab_contents(TabContents* test_tab_contents) {
+ test_tab_contents_ = test_tab_contents;
+ }
+
+ // Returns how many history items the menu should show. For example, if the
+ // navigation controller of the current tab has a current entry index of 5 and
+ // forward_direction_ is false (we are the back button delegate) then this
+ // function will return 5 (representing 0-4). If forward_direction_ is
+ // true (we are the forward button delegate), then this function will return
+ // the number of entries after 5. Note, though, that in either case it will
+ // not report more than kMaxHistoryItems. The number returned also does not
+ // include the separator line after the history items (nor the separator for
+ // the "Show Full History" link).
+ int GetHistoryItemCount() const;
+
+ // Returns how many chapter-stop items the menu should show. For the
+ // definition of a chapter-stop, see GetIndexOfNextChapterStop(). The number
+ // returned does not include the separator lines before and after the
+ // chapter-stops.
+ int GetChapterStopCount(int history_items) const;
+
+ // Finds the next chapter-stop in the NavigationEntryList starting from
+ // the index specified in |start_from| and continuing in the direction
+ // specified (|forward|) until either a chapter-stop is found or we reach the
+ // end, in which case -1 is returned. If |start_from| is out of bounds, -1
+ // will also be returned. A chapter-stop is defined as the last page the user
+ // browsed to within the same domain. For example, if the user's homepage is
+ // Google and she navigates to Google pages G1, G2 and G3 before heading over
+ // to WikiPedia for pages W1 and W2 and then back to Google for pages G4 and
+ // G5 then G3, W2 and G5 are considered chapter-stops. The return value from
+ // this function is an index into the NavigationEntryList vector.
+ int GetIndexOfNextChapterStop(int start_from, bool forward) const;
+
+ // Finds a given chapter-stop starting at the currently active entry in the
+ // NavigationEntryList vector advancing first forward or backward by |offset|
+ // (depending on the direction specified in parameter |forward|). It also
+ // allows you to skip chapter-stops by specifying a positive value for |skip|.
+ // Example: FindChapterStop(5, false, 3) starts with the currently active
+ // index, subtracts 5 from it and then finds the fourth chapter-stop before
+ // that index (skipping the first 3 it finds).
+ // Example: FindChapterStop(0, true, 0) is functionally equivalent to
+ // calling GetIndexOfNextChapterStop(GetCurrentEntryIndex(), true).
+ //
+ // NOTE: Both |offset| and |skip| must be non-negative. The return value from
+ // this function is an index into the NavigationEntryList vector. If |offset|
+ // is out of bounds or if we skip too far (run out of chapter-stops) this
+ // function returns -1.
+ int FindChapterStop(int offset, bool forward, int skip) const;
+
+ // How many items (max) to show in the back/forward history menu dropdown.
+ static const int kMaxHistoryItems;
+
+ // How many chapter-stops (max) to show in the back/forward dropdown list.
+ static const int kMaxChapterStops;
+
+ // Takes a menu item index as passed in through one of the menu delegate
+ // functions and converts it into an index into the NavigationEntryList
+ // vector. |index| can point to a separator, or the
+ // "Show Full History" link in which case this function returns -1.
+ int MenuIndexToNavEntryIndex(int index) const;
+
+ // Does the item have a command associated with it?
+ bool ItemHasCommand(int index) const;
+
+ // Returns true if there is an icon for this menu item.
+ bool ItemHasIcon(int index) const;
+
+ // Allow the unit test to use the "Show Full History" label.
+ string16 GetShowFullHistoryLabel() const;
+
+ // Looks up a NavigationEntry by menu id.
+ NavigationEntry* GetNavigationEntry(int index) const;
+
+ // Retrieves the TabContents pointer to use, which is either the one that
+ // the unit test sets (using SetTabContentsForUnitTest) or the one from
+ // the browser window.
+ TabContents* GetTabContents() const;
+
+ // Build a string version of a user action on this menu, used as an
+ // identifier for logging user behavior.
+ // E.g. BuildActionName("Click", 2) returns "BackMenu_Click2".
+ // An index of -1 means no index.
+ std::string BuildActionName(const std::string& name, int index) const;
+
+ Browser* browser_;
+
+ // The unit tests will provide their own TabContents to use.
+ TabContents* test_tab_contents_;
+
+ // Represents whether this is the delegate for the forward button or the
+ // back button.
+ ModelType model_type_;
+
+ friend class BackFwdMenuModelTest;
+ FRIEND_TEST_ALL_PREFIXES(BackFwdMenuModelTest, BasicCase);
+ FRIEND_TEST_ALL_PREFIXES(BackFwdMenuModelTest, MaxItemsTest);
+ FRIEND_TEST_ALL_PREFIXES(BackFwdMenuModelTest, ChapterStops);
+
+ DISALLOW_COPY_AND_ASSIGN(BackForwardMenuModel);
+};
+
+#endif // CHROME_BROWSER_UI_TOOLBAR_BACK_FORWARD_MENU_MODEL_H_
diff --git a/chrome/browser/ui/toolbar/back_forward_menu_model_unittest.cc b/chrome/browser/ui/toolbar/back_forward_menu_model_unittest.cc
new file mode 100644
index 0000000..2e4b988
--- /dev/null
+++ b/chrome/browser/ui/toolbar/back_forward_menu_model_unittest.cc
@@ -0,0 +1,422 @@
+// 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.
+
+#include "chrome/browser/ui/toolbar/back_forward_menu_model.h"
+
+#include "base/path_service.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/renderer_host/test/test_render_view_host.h"
+#include "chrome/browser/tab_contents/navigation_controller.h"
+#include "chrome/browser/tab_contents/navigation_entry.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/test_tab_contents.h"
+#include "chrome/common/url_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class BackFwdMenuModelTest : public RenderViewHostTestHarness {
+ public:
+ void ValidateModel(BackForwardMenuModel* model, int history_items,
+ int chapter_stops) {
+ int h = std::min(BackForwardMenuModel::kMaxHistoryItems, history_items);
+ int c = std::min(BackForwardMenuModel::kMaxChapterStops, chapter_stops);
+ EXPECT_EQ(h, model->GetHistoryItemCount());
+ EXPECT_EQ(c, model->GetChapterStopCount(h));
+ if (h > 0)
+ h += 2; // Separator and View History link.
+ if (c > 0)
+ ++c;
+ EXPECT_EQ(h + c, model->GetItemCount());
+ }
+
+ void LoadURLAndUpdateState(const char* url, const char* title) {
+ NavigateAndCommit(GURL(url));
+ controller().GetLastCommittedEntry()->set_title(UTF8ToUTF16(title));
+ }
+
+ // Navigate back or forward the given amount and commits the entry (which
+ // will be pending after we ask to navigate there).
+ void NavigateToOffset(int offset) {
+ controller().GoToOffset(offset);
+ contents()->CommitPendingNavigation();
+ }
+
+ // Same as NavigateToOffset but goes to an absolute index.
+ void NavigateToIndex(int index) {
+ controller().GoToIndex(index);
+ contents()->CommitPendingNavigation();
+ }
+
+ // Goes back/forward and commits the load.
+ void GoBack() {
+ controller().GoBack();
+ contents()->CommitPendingNavigation();
+ }
+ void GoForward() {
+ controller().GoForward();
+ contents()->CommitPendingNavigation();
+ }
+};
+
+TEST_F(BackFwdMenuModelTest, BasicCase) {
+ scoped_ptr<BackForwardMenuModel> back_model(new BackForwardMenuModel(
+ NULL, BackForwardMenuModel::BACKWARD_MENU));
+ back_model->set_test_tab_contents(contents());
+
+ scoped_ptr<BackForwardMenuModel> forward_model(new BackForwardMenuModel(
+ NULL, BackForwardMenuModel::FORWARD_MENU));
+ forward_model->set_test_tab_contents(contents());
+
+ EXPECT_EQ(0, back_model->GetItemCount());
+ EXPECT_EQ(0, forward_model->GetItemCount());
+ EXPECT_FALSE(back_model->ItemHasCommand(1));
+
+ // Seed the controller with a few URLs
+ LoadURLAndUpdateState("http://www.a.com/1", "A1");
+ LoadURLAndUpdateState("http://www.a.com/2", "A2");
+ LoadURLAndUpdateState("http://www.a.com/3", "A3");
+ LoadURLAndUpdateState("http://www.b.com/1", "B1");
+ LoadURLAndUpdateState("http://www.b.com/2", "B2");
+ LoadURLAndUpdateState("http://www.c.com/1", "C1");
+ LoadURLAndUpdateState("http://www.c.com/2", "C2");
+ LoadURLAndUpdateState("http://www.c.com/3", "C3");
+
+ // There're two more items here: a separator and a "Show Full History".
+ EXPECT_EQ(9, back_model->GetItemCount());
+ EXPECT_EQ(0, forward_model->GetItemCount());
+ EXPECT_EQ(ASCIIToUTF16("C2"), back_model->GetLabelAt(0));
+ EXPECT_EQ(ASCIIToUTF16("A1"), back_model->GetLabelAt(6));
+ EXPECT_EQ(back_model->GetShowFullHistoryLabel(),
+ back_model->GetLabelAt(8));
+
+ EXPECT_TRUE(back_model->ItemHasCommand(0));
+ EXPECT_TRUE(back_model->ItemHasCommand(6));
+ EXPECT_TRUE(back_model->IsSeparator(7));
+ EXPECT_TRUE(back_model->ItemHasCommand(8));
+ EXPECT_FALSE(back_model->ItemHasCommand(9));
+ EXPECT_FALSE(back_model->ItemHasCommand(9));
+
+ NavigateToOffset(-7);
+
+ EXPECT_EQ(0, back_model->GetItemCount());
+ EXPECT_EQ(9, forward_model->GetItemCount());
+ EXPECT_EQ(ASCIIToUTF16("A2"), forward_model->GetLabelAt(0));
+ EXPECT_EQ(ASCIIToUTF16("C3"), forward_model->GetLabelAt(6));
+ EXPECT_EQ(forward_model->GetShowFullHistoryLabel(),
+ forward_model->GetLabelAt(8));
+
+ EXPECT_TRUE(forward_model->ItemHasCommand(0));
+ EXPECT_TRUE(forward_model->ItemHasCommand(6));
+ EXPECT_TRUE(forward_model->IsSeparator(7));
+ EXPECT_TRUE(forward_model->ItemHasCommand(8));
+ EXPECT_FALSE(forward_model->ItemHasCommand(7));
+ EXPECT_FALSE(forward_model->ItemHasCommand(9));
+
+ NavigateToOffset(4);
+
+ EXPECT_EQ(6, back_model->GetItemCount());
+ EXPECT_EQ(5, forward_model->GetItemCount());
+ EXPECT_EQ(ASCIIToUTF16("B1"), back_model->GetLabelAt(0));
+ EXPECT_EQ(ASCIIToUTF16("A1"), back_model->GetLabelAt(3));
+ EXPECT_EQ(back_model->GetShowFullHistoryLabel(),
+ back_model->GetLabelAt(5));
+ EXPECT_EQ(ASCIIToUTF16("C1"), forward_model->GetLabelAt(0));
+ EXPECT_EQ(ASCIIToUTF16("C3"), forward_model->GetLabelAt(2));
+ EXPECT_EQ(forward_model->GetShowFullHistoryLabel(),
+ forward_model->GetLabelAt(4));
+}
+
+TEST_F(BackFwdMenuModelTest, MaxItemsTest) {
+ scoped_ptr<BackForwardMenuModel> back_model(new BackForwardMenuModel(
+ NULL, BackForwardMenuModel::BACKWARD_MENU));
+ back_model->set_test_tab_contents(contents());
+
+ scoped_ptr<BackForwardMenuModel> forward_model(new BackForwardMenuModel(
+ NULL, BackForwardMenuModel::FORWARD_MENU));
+ forward_model->set_test_tab_contents(contents());
+
+ // Seed the controller with 32 URLs
+ LoadURLAndUpdateState("http://www.a.com/1", "A1");
+ LoadURLAndUpdateState("http://www.a.com/2", "A2");
+ LoadURLAndUpdateState("http://www.a.com/3", "A3");
+ LoadURLAndUpdateState("http://www.b.com/1", "B1");
+ LoadURLAndUpdateState("http://www.b.com/2", "B2");
+ LoadURLAndUpdateState("http://www.b.com/3", "B3");
+ LoadURLAndUpdateState("http://www.c.com/1", "C1");
+ LoadURLAndUpdateState("http://www.c.com/2", "C2");
+ LoadURLAndUpdateState("http://www.c.com/3", "C3");
+ LoadURLAndUpdateState("http://www.d.com/1", "D1");
+ LoadURLAndUpdateState("http://www.d.com/2", "D2");
+ LoadURLAndUpdateState("http://www.d.com/3", "D3");
+ LoadURLAndUpdateState("http://www.e.com/1", "E1");
+ LoadURLAndUpdateState("http://www.e.com/2", "E2");
+ LoadURLAndUpdateState("http://www.e.com/3", "E3");
+ LoadURLAndUpdateState("http://www.f.com/1", "F1");
+ LoadURLAndUpdateState("http://www.f.com/2", "F2");
+ LoadURLAndUpdateState("http://www.f.com/3", "F3");
+ LoadURLAndUpdateState("http://www.g.com/1", "G1");
+ LoadURLAndUpdateState("http://www.g.com/2", "G2");
+ LoadURLAndUpdateState("http://www.g.com/3", "G3");
+ LoadURLAndUpdateState("http://www.h.com/1", "H1");
+ LoadURLAndUpdateState("http://www.h.com/2", "H2");
+ LoadURLAndUpdateState("http://www.h.com/3", "H3");
+ LoadURLAndUpdateState("http://www.i.com/1", "I1");
+ LoadURLAndUpdateState("http://www.i.com/2", "I2");
+ LoadURLAndUpdateState("http://www.i.com/3", "I3");
+ LoadURLAndUpdateState("http://www.j.com/1", "J1");
+ LoadURLAndUpdateState("http://www.j.com/2", "J2");
+ LoadURLAndUpdateState("http://www.j.com/3", "J3");
+ LoadURLAndUpdateState("http://www.k.com/1", "K1");
+ LoadURLAndUpdateState("http://www.k.com/2", "K2");
+
+ // Also there're two more for a separator and a "Show Full History".
+ int chapter_stop_offset = 6;
+ EXPECT_EQ(BackForwardMenuModel::kMaxHistoryItems + 2 + chapter_stop_offset,
+ back_model->GetItemCount());
+ EXPECT_EQ(0, forward_model->GetItemCount());
+ EXPECT_EQ(ASCIIToUTF16("K1"), back_model->GetLabelAt(0));
+ EXPECT_EQ(back_model->GetShowFullHistoryLabel(),
+ back_model->GetLabelAt(BackForwardMenuModel::kMaxHistoryItems + 1 +
+ chapter_stop_offset));
+
+ // Test for out of bounds (beyond Show Full History).
+ EXPECT_FALSE(back_model->ItemHasCommand(
+ BackForwardMenuModel::kMaxHistoryItems + chapter_stop_offset + 2));
+
+ EXPECT_TRUE(back_model->ItemHasCommand(
+ BackForwardMenuModel::kMaxHistoryItems - 1));
+ EXPECT_TRUE(back_model->IsSeparator(
+ BackForwardMenuModel::kMaxHistoryItems));
+
+ NavigateToIndex(0);
+
+ EXPECT_EQ(BackForwardMenuModel::kMaxHistoryItems + 2 + chapter_stop_offset,
+ forward_model->GetItemCount());
+ EXPECT_EQ(0, back_model->GetItemCount());
+ EXPECT_EQ(ASCIIToUTF16("A2"), forward_model->GetLabelAt(0));
+ EXPECT_EQ(forward_model->GetShowFullHistoryLabel(),
+ forward_model->GetLabelAt(BackForwardMenuModel::kMaxHistoryItems + 1 +
+ chapter_stop_offset));
+
+ // Out of bounds
+ EXPECT_FALSE(forward_model->ItemHasCommand(
+ BackForwardMenuModel::kMaxHistoryItems + 2 + chapter_stop_offset));
+
+ EXPECT_TRUE(forward_model->ItemHasCommand(
+ BackForwardMenuModel::kMaxHistoryItems - 1));
+ EXPECT_TRUE(forward_model->IsSeparator(
+ BackForwardMenuModel::kMaxHistoryItems));
+}
+
+TEST_F(BackFwdMenuModelTest, ChapterStops) {
+ scoped_ptr<BackForwardMenuModel> back_model(new BackForwardMenuModel(
+ NULL, BackForwardMenuModel::BACKWARD_MENU));
+ back_model->set_test_tab_contents(contents());
+
+ scoped_ptr<BackForwardMenuModel> forward_model(new BackForwardMenuModel(
+ NULL, BackForwardMenuModel::FORWARD_MENU));
+ forward_model->set_test_tab_contents(contents());
+
+ // Seed the controller with 32 URLs.
+ int i = 0;
+ LoadURLAndUpdateState("http://www.a.com/1", "A1");
+ ValidateModel(back_model.get(), i++, 0);
+ LoadURLAndUpdateState("http://www.a.com/2", "A2");
+ ValidateModel(back_model.get(), i++, 0);
+ LoadURLAndUpdateState("http://www.a.com/3", "A3");
+ ValidateModel(back_model.get(), i++, 0);
+ LoadURLAndUpdateState("http://www.b.com/1", "B1");
+ ValidateModel(back_model.get(), i++, 0);
+ LoadURLAndUpdateState("http://www.b.com/2", "B2");
+ ValidateModel(back_model.get(), i++, 0);
+ // i = 5
+ LoadURLAndUpdateState("http://www.b.com/3", "B3");
+ ValidateModel(back_model.get(), i++, 0);
+ LoadURLAndUpdateState("http://www.c.com/1", "C1");
+ ValidateModel(back_model.get(), i++, 0);
+ LoadURLAndUpdateState("http://www.c.com/2", "C2");
+ ValidateModel(back_model.get(), i++, 0);
+ LoadURLAndUpdateState("http://www.c.com/3", "C3");
+ ValidateModel(back_model.get(), i++, 0);
+ LoadURLAndUpdateState("http://www.d.com/1", "D1");
+ ValidateModel(back_model.get(), i++, 0);
+ // i = 10
+ LoadURLAndUpdateState("http://www.d.com/2", "D2");
+ ValidateModel(back_model.get(), i++, 0);
+ LoadURLAndUpdateState("http://www.d.com/3", "D3");
+ ValidateModel(back_model.get(), i++, 0);
+ LoadURLAndUpdateState("http://www.e.com/1", "E1");
+ ValidateModel(back_model.get(), i++, 0);
+ LoadURLAndUpdateState("http://www.e.com/2", "E2");
+ ValidateModel(back_model.get(), i++, 0);
+ LoadURLAndUpdateState("http://www.e.com/3", "E3");
+ ValidateModel(back_model.get(), i++, 0);
+ // i = 15
+ LoadURLAndUpdateState("http://www.f.com/1", "F1");
+ ValidateModel(back_model.get(), i++, 1);
+ LoadURLAndUpdateState("http://www.f.com/2", "F2");
+ ValidateModel(back_model.get(), i++, 1);
+ LoadURLAndUpdateState("http://www.f.com/3", "F3");
+ ValidateModel(back_model.get(), i++, 1);
+ LoadURLAndUpdateState("http://www.g.com/1", "G1");
+ ValidateModel(back_model.get(), i++, 2);
+ LoadURLAndUpdateState("http://www.g.com/2", "G2");
+ ValidateModel(back_model.get(), i++, 2);
+ // i = 20
+ LoadURLAndUpdateState("http://www.g.com/3", "G3");
+ ValidateModel(back_model.get(), i++, 2);
+ LoadURLAndUpdateState("http://www.h.com/1", "H1");
+ ValidateModel(back_model.get(), i++, 3);
+ LoadURLAndUpdateState("http://www.h.com/2", "H2");
+ ValidateModel(back_model.get(), i++, 3);
+ LoadURLAndUpdateState("http://www.h.com/3", "H3");
+ ValidateModel(back_model.get(), i++, 3);
+ LoadURLAndUpdateState("http://www.i.com/1", "I1");
+ ValidateModel(back_model.get(), i++, 4);
+ // i = 25
+ LoadURLAndUpdateState("http://www.i.com/2", "I2");
+ ValidateModel(back_model.get(), i++, 4);
+ LoadURLAndUpdateState("http://www.i.com/3", "I3");
+ ValidateModel(back_model.get(), i++, 4);
+ LoadURLAndUpdateState("http://www.j.com/1", "J1");
+ ValidateModel(back_model.get(), i++, 5);
+ LoadURLAndUpdateState("http://www.j.com/2", "J2");
+ ValidateModel(back_model.get(), i++, 5);
+ LoadURLAndUpdateState("http://www.j.com/3", "J3");
+ ValidateModel(back_model.get(), i++, 5);
+ // i = 30
+ LoadURLAndUpdateState("http://www.k.com/1", "K1");
+ ValidateModel(back_model.get(), i++, 6);
+ LoadURLAndUpdateState("http://www.k.com/2", "K2");
+ ValidateModel(back_model.get(), i++, 6);
+ // i = 32
+ LoadURLAndUpdateState("http://www.k.com/3", "K3");
+ ValidateModel(back_model.get(), i++, 6);
+
+ // A chapter stop is defined as the last page the user
+ // browsed to within the same domain.
+
+ // Check to see if the chapter stops have the right labels.
+ int index = BackForwardMenuModel::kMaxHistoryItems;
+ // Empty string indicates item is a separator.
+ EXPECT_EQ(ASCIIToUTF16(""), back_model->GetLabelAt(index++));
+ EXPECT_EQ(ASCIIToUTF16("F3"), back_model->GetLabelAt(index++));
+ EXPECT_EQ(ASCIIToUTF16("E3"), back_model->GetLabelAt(index++));
+ EXPECT_EQ(ASCIIToUTF16("D3"), back_model->GetLabelAt(index++));
+ EXPECT_EQ(ASCIIToUTF16("C3"), back_model->GetLabelAt(index++));
+ // The menu should only show a maximum of 5 chapter stops.
+ EXPECT_EQ(ASCIIToUTF16("B3"), back_model->GetLabelAt(index));
+ // Empty string indicates item is a separator.
+ EXPECT_EQ(ASCIIToUTF16(""), back_model->GetLabelAt(index + 1));
+ EXPECT_EQ(back_model->GetShowFullHistoryLabel(),
+ back_model->GetLabelAt(index + 2));
+
+ // If we go back two we should still see the same chapter stop at the end.
+ GoBack();
+ EXPECT_EQ(ASCIIToUTF16("B3"), back_model->GetLabelAt(index));
+ GoBack();
+ EXPECT_EQ(ASCIIToUTF16("B3"), back_model->GetLabelAt(index));
+ // But if we go back again, it should change.
+ GoBack();
+ EXPECT_EQ(ASCIIToUTF16("A3"), back_model->GetLabelAt(index));
+ GoBack();
+ EXPECT_EQ(ASCIIToUTF16("A3"), back_model->GetLabelAt(index));
+ GoBack();
+ EXPECT_EQ(ASCIIToUTF16("A3"), back_model->GetLabelAt(index));
+ GoBack();
+ // It is now a separator.
+ EXPECT_EQ(ASCIIToUTF16(""), back_model->GetLabelAt(index));
+ // Undo our position change.
+ NavigateToOffset(6);
+
+ // Go back enough to make sure no chapter stops should appear.
+ NavigateToOffset(-BackForwardMenuModel::kMaxHistoryItems);
+ ValidateModel(forward_model.get(), BackForwardMenuModel::kMaxHistoryItems, 0);
+ // Go forward (still no chapter stop)
+ GoForward();
+ ValidateModel(forward_model.get(),
+ BackForwardMenuModel::kMaxHistoryItems - 1, 0);
+ // Go back two (one chapter stop should show up)
+ GoBack();
+ GoBack();
+ ValidateModel(forward_model.get(),
+ BackForwardMenuModel::kMaxHistoryItems, 1);
+
+ // Go to beginning.
+ NavigateToIndex(0);
+
+ // Check to see if the chapter stops have the right labels.
+ index = BackForwardMenuModel::kMaxHistoryItems;
+ // Empty string indicates item is a separator.
+ EXPECT_EQ(ASCIIToUTF16(""), forward_model->GetLabelAt(index++));
+ EXPECT_EQ(ASCIIToUTF16("E3"), forward_model->GetLabelAt(index++));
+ EXPECT_EQ(ASCIIToUTF16("F3"), forward_model->GetLabelAt(index++));
+ EXPECT_EQ(ASCIIToUTF16("G3"), forward_model->GetLabelAt(index++));
+ EXPECT_EQ(ASCIIToUTF16("H3"), forward_model->GetLabelAt(index++));
+ // The menu should only show a maximum of 5 chapter stops.
+ EXPECT_EQ(ASCIIToUTF16("I3"), forward_model->GetLabelAt(index));
+ // Empty string indicates item is a separator.
+ EXPECT_EQ(ASCIIToUTF16(""), forward_model->GetLabelAt(index + 1));
+ EXPECT_EQ(forward_model->GetShowFullHistoryLabel(),
+ forward_model->GetLabelAt(index + 2));
+
+ // If we advance one we should still see the same chapter stop at the end.
+ GoForward();
+ EXPECT_EQ(ASCIIToUTF16("I3"), forward_model->GetLabelAt(index));
+ // But if we advance one again, it should change.
+ GoForward();
+ EXPECT_EQ(ASCIIToUTF16("J3"), forward_model->GetLabelAt(index));
+ GoForward();
+ EXPECT_EQ(ASCIIToUTF16("J3"), forward_model->GetLabelAt(index));
+ GoForward();
+ EXPECT_EQ(ASCIIToUTF16("J3"), forward_model->GetLabelAt(index));
+ GoForward();
+ EXPECT_EQ(ASCIIToUTF16("K3"), forward_model->GetLabelAt(index));
+
+ // Now test the boundary cases by using the chapter stop function directly.
+ // Out of bounds, first too far right (incrementing), then too far left.
+ EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(33, false));
+ EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(-1, true));
+ // Test being at end and going right, then at beginning going left.
+ EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(32, true));
+ EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(0, false));
+ // Test success: beginning going right and end going left.
+ EXPECT_EQ(2, back_model->GetIndexOfNextChapterStop(0, true));
+ EXPECT_EQ(29, back_model->GetIndexOfNextChapterStop(32, false));
+ // Now see when the chapter stops begin to show up.
+ EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(1, false));
+ EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(2, false));
+ EXPECT_EQ(2, back_model->GetIndexOfNextChapterStop(3, false));
+ // Now see when the chapter stops end.
+ EXPECT_EQ(32, back_model->GetIndexOfNextChapterStop(30, true));
+ EXPECT_EQ(32, back_model->GetIndexOfNextChapterStop(31, true));
+ EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(32, true));
+
+ // Bug found during review (two different sites, but first wasn't considered
+ // a chapter-stop).
+ // Go to A1;
+ NavigateToIndex(0);
+ LoadURLAndUpdateState("http://www.b.com/1", "B1");
+ EXPECT_EQ(0, back_model->GetIndexOfNextChapterStop(1, false));
+ EXPECT_EQ(1, back_model->GetIndexOfNextChapterStop(0, true));
+
+ // Now see if it counts 'www.x.com' and 'mail.x.com' as same domain, which
+ // it should.
+ // Go to A1.
+ NavigateToIndex(0);
+ LoadURLAndUpdateState("http://mail.a.com/2", "A2-mai");
+ LoadURLAndUpdateState("http://www.b.com/1", "B1");
+ LoadURLAndUpdateState("http://mail.b.com/2", "B2-mai");
+ LoadURLAndUpdateState("http://new.site.com", "new");
+ EXPECT_EQ(1, back_model->GetIndexOfNextChapterStop(0, true));
+ EXPECT_EQ(3, back_model->GetIndexOfNextChapterStop(1, true));
+ EXPECT_EQ(3, back_model->GetIndexOfNextChapterStop(2, true));
+ EXPECT_EQ(4, back_model->GetIndexOfNextChapterStop(3, true));
+ // And try backwards as well.
+ EXPECT_EQ(3, back_model->GetIndexOfNextChapterStop(4, false));
+ EXPECT_EQ(1, back_model->GetIndexOfNextChapterStop(3, false));
+ EXPECT_EQ(1, back_model->GetIndexOfNextChapterStop(2, false));
+ EXPECT_EQ(-1, back_model->GetIndexOfNextChapterStop(1, false));
+}
diff --git a/chrome/browser/ui/toolbar/encoding_menu_controller.cc b/chrome/browser/ui/toolbar/encoding_menu_controller.cc
new file mode 100644
index 0000000..c93fb1e
--- /dev/null
+++ b/chrome/browser/ui/toolbar/encoding_menu_controller.cc
@@ -0,0 +1,141 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/toolbar/encoding_menu_controller.h"
+
+#include "app/l10n_util.h"
+#include "base/i18n/rtl.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/character_encoding.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/pref_names.h"
+#include "grit/generated_resources.h"
+
+const int EncodingMenuController::kValidEncodingIds[] = {
+ IDC_ENCODING_UTF8,
+ IDC_ENCODING_UTF16LE,
+ IDC_ENCODING_ISO88591,
+ IDC_ENCODING_WINDOWS1252,
+ IDC_ENCODING_GBK,
+ IDC_ENCODING_GB18030,
+ IDC_ENCODING_BIG5,
+ IDC_ENCODING_BIG5HKSCS,
+ IDC_ENCODING_KOREAN,
+ IDC_ENCODING_SHIFTJIS,
+ IDC_ENCODING_ISO2022JP,
+ IDC_ENCODING_EUCJP,
+ IDC_ENCODING_THAI,
+ IDC_ENCODING_ISO885915,
+ IDC_ENCODING_MACINTOSH,
+ IDC_ENCODING_ISO88592,
+ IDC_ENCODING_WINDOWS1250,
+ IDC_ENCODING_ISO88595,
+ IDC_ENCODING_WINDOWS1251,
+ IDC_ENCODING_KOI8R,
+ IDC_ENCODING_KOI8U,
+ IDC_ENCODING_ISO88597,
+ IDC_ENCODING_WINDOWS1253,
+ IDC_ENCODING_ISO88594,
+ IDC_ENCODING_ISO885913,
+ IDC_ENCODING_WINDOWS1257,
+ IDC_ENCODING_ISO88593,
+ IDC_ENCODING_ISO885910,
+ IDC_ENCODING_ISO885914,
+ IDC_ENCODING_ISO885916,
+ IDC_ENCODING_WINDOWS1254,
+ IDC_ENCODING_ISO88596,
+ IDC_ENCODING_WINDOWS1256,
+ IDC_ENCODING_ISO88598,
+ IDC_ENCODING_WINDOWS1255,
+ IDC_ENCODING_WINDOWS1258,
+ IDC_ENCODING_ISO88598I,
+};
+
+bool EncodingMenuController::DoesCommandBelongToEncodingMenu(int id) {
+ if (id == IDC_ENCODING_AUTO_DETECT) {
+ return true;
+ }
+
+ for (size_t i = 0; i < arraysize(kValidEncodingIds); ++i) {
+ if (id == kValidEncodingIds[i]) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+const int* EncodingMenuController::ValidGUIEncodingIDs() {
+ return kValidEncodingIds;
+}
+
+int EncodingMenuController::NumValidGUIEncodingIDs() {
+ return arraysize(kValidEncodingIds);
+}
+
+bool EncodingMenuController::IsItemChecked(
+ Profile* browser_profile,
+ const std::string& current_tab_encoding,
+ int item_id) {
+ if (!DoesCommandBelongToEncodingMenu(item_id))
+ return false;
+
+ std::string encoding = current_tab_encoding;
+ if (encoding.empty())
+ encoding = browser_profile->GetPrefs()->GetString(prefs::kDefaultCharset);
+
+ if (item_id == IDC_ENCODING_AUTO_DETECT) {
+ return browser_profile->GetPrefs()->GetBoolean(
+ prefs::kWebKitUsesUniversalDetector);
+ }
+
+ if (!encoding.empty()) {
+ return encoding ==
+ CharacterEncoding::GetCanonicalEncodingNameByCommandId(item_id);
+ }
+
+ return false;
+}
+
+void EncodingMenuController::GetEncodingMenuItems(Profile* profile,
+ EncodingMenuItemList* menuItems) {
+
+ DCHECK(menuItems);
+ EncodingMenuItem separator(0, string16());
+
+ menuItems->clear();
+ menuItems->push_back(
+ EncodingMenuItem(IDC_ENCODING_AUTO_DETECT,
+ l10n_util::GetStringUTF16(IDS_ENCODING_AUTO_DETECT)));
+ menuItems->push_back(separator);
+
+ // Create current display encoding list.
+ const std::vector<CharacterEncoding::EncodingInfo>* encodings;
+
+ // Build the list of encoding ids : It is made of the
+ // locale-dependent short list, the cache of recently selected
+ // encodings and other encodings.
+ encodings = CharacterEncoding::GetCurrentDisplayEncodings(
+ g_browser_process->GetApplicationLocale(),
+ profile->GetPrefs()->GetString(prefs::kStaticEncodings),
+ profile->GetPrefs()->GetString(prefs::kRecentlySelectedEncoding));
+ DCHECK(encodings);
+ DCHECK(!encodings->empty());
+
+ // Build up output list for menu.
+ std::vector<CharacterEncoding::EncodingInfo>::const_iterator it;
+ for (it = encodings->begin(); it != encodings->end(); ++it) {
+ if (it->encoding_id) {
+ std::wstring encoding = it->encoding_display_name;
+ base::i18n::AdjustStringForLocaleDirection(&encoding);
+ menuItems->push_back(EncodingMenuItem(it->encoding_id,
+ WideToUTF16(encoding)));
+ } else {
+ menuItems->push_back(separator);
+ }
+ }
+}
diff --git a/chrome/browser/ui/toolbar/encoding_menu_controller.h b/chrome/browser/ui/toolbar/encoding_menu_controller.h
new file mode 100644
index 0000000..bfa8c57
--- /dev/null
+++ b/chrome/browser/ui/toolbar/encoding_menu_controller.h
@@ -0,0 +1,56 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_TOOLBAR_ENCODING_MENU_CONTROLLER_H_
+#define CHROME_BROWSER_UI_TOOLBAR_ENCODING_MENU_CONTROLLER_H_
+#pragma once
+
+#include <utility>
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h" // For DISALLOW_COPY_AND_ASSIGN
+#include "base/gtest_prod_util.h"
+#include "base/string16.h"
+
+class Profile;
+
+// Cross-platform logic needed for the encoding menu.
+// For now, we don't need to track state so all methods are static.
+class EncodingMenuController {
+ FRIEND_TEST_ALL_PREFIXES(EncodingMenuControllerTest, EncodingIDsBelongTest);
+ FRIEND_TEST_ALL_PREFIXES(EncodingMenuControllerTest, IsItemChecked);
+
+ public:
+ typedef std::pair<int, string16> EncodingMenuItem;
+ typedef std::vector<EncodingMenuItem> EncodingMenuItemList;
+
+ public:
+ EncodingMenuController() {}
+
+ // Given a command ID, does this command belong to the encoding menu?
+ bool DoesCommandBelongToEncodingMenu(int id);
+
+ // Returns true if the given encoding menu item (specified by item_id)
+ // is checked. Note that this header is included from objc, where the name
+ // "id" is reserved.
+ bool IsItemChecked(Profile* browser_profile,
+ const std::string& current_tab_encoding,
+ int item_id);
+
+ // Fills in a list of menu items in the order they should appear in the menu.
+ // Items whose ids are 0 are separators.
+ void GetEncodingMenuItems(Profile* profile,
+ EncodingMenuItemList* menuItems);
+
+ private:
+ // List of all valid encoding GUI IDs.
+ static const int kValidEncodingIds[];
+ const int* ValidGUIEncodingIDs();
+ int NumValidGUIEncodingIDs();
+
+ DISALLOW_COPY_AND_ASSIGN(EncodingMenuController);
+};
+
+#endif // CHROME_BROWSER_UI_TOOLBAR_ENCODING_MENU_CONTROLLER_H_
diff --git a/chrome/browser/ui/toolbar/encoding_menu_controller_unittest.cc b/chrome/browser/ui/toolbar/encoding_menu_controller_unittest.cc
new file mode 100644
index 0000000..13fa63c
--- /dev/null
+++ b/chrome/browser/ui/toolbar/encoding_menu_controller_unittest.cc
@@ -0,0 +1,93 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/toolbar/encoding_menu_controller.h"
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/testing_profile.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+
+class EncodingMenuControllerTest : public testing::Test {
+};
+
+TEST_F(EncodingMenuControllerTest, EncodingIDsBelongTest) {
+ EncodingMenuController controller;
+
+ // Check some bogus ids to make sure they're never valid.
+ ASSERT_FALSE(controller.DoesCommandBelongToEncodingMenu(0));
+ ASSERT_FALSE(controller.DoesCommandBelongToEncodingMenu(-1));
+
+ int num_valid_encoding_ids = controller.NumValidGUIEncodingIDs();
+ const int* valid_encodings = controller.ValidGUIEncodingIDs();
+ ASSERT_TRUE(controller.DoesCommandBelongToEncodingMenu(
+ IDC_ENCODING_AUTO_DETECT));
+ // Check that all valid encodings are accepted.
+ for (int i = 0; i < num_valid_encoding_ids; ++i) {
+ ASSERT_TRUE(controller.DoesCommandBelongToEncodingMenu(valid_encodings[i]));
+ }
+
+ // This test asserts that we haven't added a new valid ID without including it
+ // in the kValidEncodingIds test list above.
+ // The premise is that new encodings will be added directly after the current
+ // ones so we'll catch such cases.
+ int one_past_largest_id = valid_encodings[num_valid_encoding_ids - 1] + 1;
+ ASSERT_FALSE(controller.DoesCommandBelongToEncodingMenu(one_past_largest_id));
+}
+
+TEST_F(EncodingMenuControllerTest, ListEncodingMenuItems) {
+ typedef EncodingMenuController::EncodingMenuItemList EncodingMenuItemList;
+ EncodingMenuController controller;
+
+ EncodingMenuItemList english_items;
+ TestingProfile profile_en;
+
+ controller.GetEncodingMenuItems(&profile_en, &english_items);
+
+ // Make sure there are items in the lists.
+ ASSERT_TRUE(english_items.size() > 0);
+ // Make sure that autodetect is the first item on both menus
+ ASSERT_EQ(english_items[0].first, IDC_ENCODING_AUTO_DETECT);
+}
+
+TEST_F(EncodingMenuControllerTest, IsItemChecked) {
+ TestingProfile profile_en;
+ std::string encoding("UTF-8");
+
+ // Check that enabling and disabling autodetect works.
+ bool autodetect_enabed[] = {true, false};
+ PrefService* prefs = profile_en.GetPrefs();
+ EncodingMenuController controller;
+ for (size_t i = 0; i < arraysize(autodetect_enabed); ++i) {
+ bool enabled = autodetect_enabed[i];
+ prefs->SetBoolean(prefs::kWebKitUsesUniversalDetector, enabled);
+ ASSERT_TRUE(controller.IsItemChecked(&profile_en,
+ encoding,
+ IDC_ENCODING_AUTO_DETECT) == enabled);
+ }
+
+ // Check all valid encodings, make sure only one is enabled when autodetection
+ // is turned off.
+ prefs->SetBoolean(prefs::kWebKitUsesUniversalDetector, false);
+ bool encoding_is_enabled = false;
+ size_t num_valid_encoding_ids = controller.NumValidGUIEncodingIDs();
+ const int* valid_encodings = controller.ValidGUIEncodingIDs();
+ for (size_t i = 0; i < num_valid_encoding_ids; ++i) {
+ bool on = controller.IsItemChecked(&profile_en,
+ encoding,
+ valid_encodings[i]);
+ // Only one item in the encoding menu can be selected at a time.
+ ASSERT_FALSE(on && encoding_is_enabled);
+ encoding_is_enabled |= on;
+ }
+
+ // Make sure at least one encoding is enabled.
+ ASSERT_TRUE(encoding_is_enabled);
+}
diff --git a/chrome/browser/ui/toolbar/toolbar_model.cc b/chrome/browser/ui/toolbar/toolbar_model.cc
new file mode 100644
index 0000000..5a6a97c
--- /dev/null
+++ b/chrome/browser/ui/toolbar/toolbar_model.cc
@@ -0,0 +1,129 @@
+// 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.
+
+#include "chrome/browser/ui/toolbar/toolbar_model.h"
+
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/autocomplete/autocomplete.h"
+#include "chrome/browser/autocomplete/autocomplete_edit.h"
+#include "chrome/browser/cert_store.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ssl/ssl_error_info.h"
+#include "chrome/browser/tab_contents/navigation_controller.h"
+#include "chrome/browser/tab_contents/navigation_entry.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "net/base/cert_status_flags.h"
+#include "net/base/net_util.h"
+
+ToolbarModel::ToolbarModel(Browser* browser)
+ : browser_(browser),
+ input_in_progress_(false) {
+}
+
+ToolbarModel::~ToolbarModel() {
+}
+
+// ToolbarModel Implementation.
+std::wstring ToolbarModel::GetText() const {
+ GURL url(chrome::kAboutBlankURL);
+ std::string languages; // Empty if we don't have a |navigation_controller|.
+
+ NavigationController* navigation_controller = GetNavigationController();
+ if (navigation_controller) {
+ languages = navigation_controller->profile()->GetPrefs()->GetString(
+ prefs::kAcceptLanguages);
+ NavigationEntry* entry = navigation_controller->GetActiveEntry();
+ if (!navigation_controller->tab_contents()->ShouldDisplayURL()) {
+ // Explicitly hide the URL for this tab.
+ url = GURL();
+ } else if (entry) {
+ url = entry->virtual_url();
+ }
+ }
+ if (url.spec().length() > chrome::kMaxURLDisplayChars)
+ url = url.IsStandard() ? url.GetOrigin() : GURL(url.scheme() + ":");
+ // Note that we can't unescape spaces here, because if the user copies this
+ // and pastes it into another program, that program may think the URL ends at
+ // the space.
+ return AutocompleteInput::FormattedStringWithEquivalentMeaning(url,
+ UTF16ToWideHack(net::FormatUrl(url, languages, net::kFormatUrlOmitAll,
+ UnescapeRule::NORMAL, NULL, NULL, NULL)));
+}
+
+ToolbarModel::SecurityLevel ToolbarModel::GetSecurityLevel() const {
+ if (input_in_progress_) // When editing, assume no security style.
+ return NONE;
+
+ NavigationController* navigation_controller = GetNavigationController();
+ if (!navigation_controller) // We might not have a controller on init.
+ return NONE;
+
+ NavigationEntry* entry = navigation_controller->GetActiveEntry();
+ if (!entry)
+ return NONE;
+
+ const NavigationEntry::SSLStatus& ssl = entry->ssl();
+ switch (ssl.security_style()) {
+ case SECURITY_STYLE_UNKNOWN:
+ case SECURITY_STYLE_UNAUTHENTICATED:
+ return NONE;
+
+ case SECURITY_STYLE_AUTHENTICATION_BROKEN:
+ return SECURITY_ERROR;
+
+ case SECURITY_STYLE_AUTHENTICATED:
+ if (ssl.displayed_insecure_content())
+ return SECURITY_WARNING;
+ if (net::IsCertStatusError(ssl.cert_status())) {
+ DCHECK_EQ(ssl.cert_status() & net::CERT_STATUS_ALL_ERRORS,
+ net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION);
+ return SECURITY_WARNING;
+ }
+ if ((ssl.cert_status() & net::CERT_STATUS_IS_EV) &&
+ CertStore::GetInstance()->RetrieveCert(ssl.cert_id(), NULL))
+ return EV_SECURE;
+ return SECURE;
+
+ default:
+ NOTREACHED();
+ return NONE;
+ }
+}
+
+int ToolbarModel::GetIcon() const {
+ static int icon_ids[NUM_SECURITY_LEVELS] = {
+ IDR_OMNIBOX_HTTP,
+ IDR_OMNIBOX_HTTPS_VALID,
+ IDR_OMNIBOX_HTTPS_VALID,
+ IDR_OMNIBOX_HTTPS_WARNING,
+ IDR_OMNIBOX_HTTPS_INVALID,
+ };
+ DCHECK(arraysize(icon_ids) == NUM_SECURITY_LEVELS);
+ return icon_ids[GetSecurityLevel()];
+}
+
+std::wstring ToolbarModel::GetEVCertName() const {
+ DCHECK_EQ(GetSecurityLevel(), EV_SECURE);
+ scoped_refptr<net::X509Certificate> cert;
+ // Note: Navigation controller and active entry are guaranteed non-NULL or
+ // the security level would be NONE.
+ CertStore::GetInstance()->RetrieveCert(
+ GetNavigationController()->GetActiveEntry()->ssl().cert_id(), &cert);
+ return SSLManager::GetEVCertName(*cert);
+}
+
+NavigationController* ToolbarModel::GetNavigationController() const {
+ // This |current_tab| can be NULL during the initialization of the
+ // toolbar during window creation (i.e. before any tabs have been added
+ // to the window).
+ TabContents* current_tab = browser_->GetSelectedTabContents();
+ return current_tab ? &current_tab->controller() : NULL;
+}
diff --git a/chrome/browser/ui/toolbar/toolbar_model.h b/chrome/browser/ui/toolbar/toolbar_model.h
new file mode 100644
index 0000000..d9ebec5
--- /dev/null
+++ b/chrome/browser/ui/toolbar/toolbar_model.h
@@ -0,0 +1,71 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_MODEL_H_
+#define CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_MODEL_H_
+#pragma once
+
+#include <string>
+
+#include "base/basictypes.h"
+
+class Browser;
+class NavigationController;
+
+// This class is the model used by the toolbar, location bar and autocomplete
+// edit. It populates its states from the current navigation entry retrieved
+// from the navigation controller returned by GetNavigationController().
+class ToolbarModel {
+ public:
+ // TODO(wtc): unify ToolbarModel::SecurityLevel with SecurityStyle. We
+ // don't need two sets of security UI levels. SECURITY_STYLE_AUTHENTICATED
+ // needs to be refined into three levels: warning, standard, and EV.
+ enum SecurityLevel {
+ NONE = 0, // HTTP/no URL/user is editing
+ EV_SECURE, // HTTPS with valid EV cert
+ SECURE, // HTTPS (non-EV)
+ SECURITY_WARNING, // HTTPS, but unable to check certificate revocation
+ // status or with insecure content on the page
+ SECURITY_ERROR, // Attempted HTTPS and failed, page not authenticated
+ NUM_SECURITY_LEVELS,
+ };
+
+ explicit ToolbarModel(Browser* browser);
+ ~ToolbarModel();
+
+ // Returns the text that should be displayed in the location bar.
+ std::wstring GetText() const;
+
+ // Returns the security level that the toolbar should display.
+ SecurityLevel GetSecurityLevel() const;
+
+ // Returns the resource_id of the icon to show to the left of the address,
+ // based on the current URL. This doesn't cover specialized icons while the
+ // user is editing; see AutocompleteEditView::GetIcon().
+ int GetIcon() const;
+
+ // Returns the name of the EV cert holder. Only call this when the security
+ // level is EV_SECURE.
+ std::wstring GetEVCertName() const;
+
+ // Getter/setter of whether the text in location bar is currently being
+ // edited.
+ void set_input_in_progress(bool value) { input_in_progress_ = value; }
+ bool input_in_progress() const { return input_in_progress_; }
+
+ private:
+ // Returns the navigation controller used to retrieve the navigation entry
+ // from which the states are retrieved.
+ // If this returns NULL, default values are used.
+ NavigationController* GetNavigationController() const;
+
+ Browser* browser_;
+
+ // Whether the text in the location bar is currently being edited.
+ bool input_in_progress_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ToolbarModel);
+};
+
+#endif // CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_MODEL_H_
diff --git a/chrome/browser/ui/toolbar/wrench_menu_model.cc b/chrome/browser/ui/toolbar/wrench_menu_model.cc
new file mode 100644
index 0000000..cd8a114
--- /dev/null
+++ b/chrome/browser/ui/toolbar/wrench_menu_model.cc
@@ -0,0 +1,536 @@
+// 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.
+
+#include "chrome/browser/ui/toolbar/wrench_menu_model.h"
+
+#include <algorithm>
+#include <cmath>
+
+#include "app/l10n_util.h"
+#include "app/menus/button_menu_item_model.h"
+#include "app/resource_bundle.h"
+#include "base/command_line.h"
+#include "base/i18n/number_formatting.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/background_page_tracker.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/defaults.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/sync/sync_ui_util.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/toolbar/encoding_menu_controller.h"
+#include "chrome/browser/upgrade_detector.h"
+#include "chrome/common/badge_util.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
+#include "chrome/common/pref_names.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+
+#if defined(OS_LINUX)
+#include <gtk/gtk.h>
+#include "chrome/browser/gtk/gtk_util.h"
+#endif
+
+#if defined(OS_MACOSX)
+#include "chrome/browser/ui/browser_window.h"
+#endif
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/cros/cros_library.h"
+#include "chrome/browser/chromeos/cros/update_library.h"
+#endif
+
+#if defined(OS_WIN)
+#include "chrome/browser/enumerate_modules_model_win.h"
+#endif
+
+// The size of the font used for dynamic text overlays on menu items.
+const float kMenuBadgeFontSize = 12.0;
+
+namespace {
+SkBitmap GetBackgroundPageIcon() {
+ string16 pages = base::FormatNumber(
+ BackgroundPageTracker::GetInstance()->GetBackgroundPageCount());
+ return badge_util::DrawBadgeIconOverlay(
+ *ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_BACKGROUND_MENU),
+ kMenuBadgeFontSize,
+ pages,
+ l10n_util::GetStringUTF16(IDS_BACKGROUND_PAGE_BADGE_OVERFLOW));
+}
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// EncodingMenuModel
+
+EncodingMenuModel::EncodingMenuModel(Browser* browser)
+ : ALLOW_THIS_IN_INITIALIZER_LIST(menus::SimpleMenuModel(this)),
+ browser_(browser) {
+ Build();
+}
+
+EncodingMenuModel::~EncodingMenuModel() {
+}
+
+void EncodingMenuModel::Build() {
+ EncodingMenuController::EncodingMenuItemList encoding_menu_items;
+ EncodingMenuController encoding_menu_controller;
+ encoding_menu_controller.GetEncodingMenuItems(browser_->profile(),
+ &encoding_menu_items);
+
+ int group_id = 0;
+ EncodingMenuController::EncodingMenuItemList::iterator it =
+ encoding_menu_items.begin();
+ for (; it != encoding_menu_items.end(); ++it) {
+ int id = it->first;
+ string16& label = it->second;
+ if (id == 0) {
+ AddSeparator();
+ } else {
+ if (id == IDC_ENCODING_AUTO_DETECT) {
+ AddCheckItem(id, label);
+ } else {
+ // Use the id of the first radio command as the id of the group.
+ if (group_id <= 0)
+ group_id = id;
+ AddRadioItem(id, label, group_id);
+ }
+ }
+ }
+}
+
+bool EncodingMenuModel::IsCommandIdChecked(int command_id) const {
+ TabContents* current_tab = browser_->GetSelectedTabContents();
+ if (!current_tab)
+ return false;
+ EncodingMenuController controller;
+ return controller.IsItemChecked(browser_->profile(),
+ current_tab->encoding(), command_id);
+}
+
+bool EncodingMenuModel::IsCommandIdEnabled(int command_id) const {
+ bool enabled = browser_->command_updater()->IsCommandEnabled(command_id);
+ // Special handling for the contents of the Encoding submenu. On Mac OS,
+ // instead of enabling/disabling the top-level menu item, the submenu's
+ // contents get disabled, per Apple's HIG.
+#if defined(OS_MACOSX)
+ enabled &= browser_->command_updater()->IsCommandEnabled(IDC_ENCODING_MENU);
+#endif
+ return enabled;
+}
+
+bool EncodingMenuModel::GetAcceleratorForCommandId(
+ int command_id,
+ menus::Accelerator* accelerator) {
+ return false;
+}
+
+void EncodingMenuModel::ExecuteCommand(int command_id) {
+ browser_->ExecuteCommand(command_id);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ZoomMenuModel
+
+ZoomMenuModel::ZoomMenuModel(menus::SimpleMenuModel::Delegate* delegate)
+ : SimpleMenuModel(delegate) {
+ Build();
+}
+
+ZoomMenuModel::~ZoomMenuModel() {
+}
+
+void ZoomMenuModel::Build() {
+ AddItemWithStringId(IDC_ZOOM_PLUS, IDS_ZOOM_PLUS);
+ AddItemWithStringId(IDC_ZOOM_NORMAL, IDS_ZOOM_NORMAL);
+ AddItemWithStringId(IDC_ZOOM_MINUS, IDS_ZOOM_MINUS);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ToolsMenuModel
+
+ToolsMenuModel::ToolsMenuModel(menus::SimpleMenuModel::Delegate* delegate,
+ Browser* browser)
+ : SimpleMenuModel(delegate) {
+ Build(browser);
+}
+
+ToolsMenuModel::~ToolsMenuModel() {}
+
+void ToolsMenuModel::Build(Browser* browser) {
+ AddCheckItemWithStringId(IDC_SHOW_BOOKMARK_BAR, IDS_SHOW_BOOKMARK_BAR);
+
+ AddSeparator();
+
+#if !defined(OS_CHROMEOS)
+#if defined(OS_MACOSX)
+ AddItemWithStringId(IDC_CREATE_SHORTCUTS, IDS_CREATE_APPLICATION_MAC);
+#else
+ AddItemWithStringId(IDC_CREATE_SHORTCUTS, IDS_CREATE_SHORTCUTS);
+#endif
+ AddSeparator();
+#endif
+
+ AddItemWithStringId(IDC_MANAGE_EXTENSIONS, IDS_SHOW_EXTENSIONS);
+ AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER);
+ AddItemWithStringId(IDC_CLEAR_BROWSING_DATA, IDS_CLEAR_BROWSING_DATA);
+
+ AddSeparator();
+#if defined(OS_CHROMEOS) || defined(OS_WIN) || defined(OS_LINUX)
+ AddItemWithStringId(IDC_FEEDBACK, IDS_FEEDBACK);
+ AddSeparator();
+#endif
+
+ encoding_menu_model_.reset(new EncodingMenuModel(browser));
+ AddSubMenuWithStringId(IDC_ENCODING_MENU, IDS_ENCODING_MENU,
+ encoding_menu_model_.get());
+ AddItemWithStringId(IDC_VIEW_SOURCE, IDS_VIEW_SOURCE);
+ if (g_browser_process->have_inspector_files()) {
+ AddItemWithStringId(IDC_DEV_TOOLS, IDS_DEV_TOOLS);
+ AddItemWithStringId(IDC_DEV_TOOLS_CONSOLE, IDS_DEV_TOOLS_CONSOLE);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// WrenchMenuModel
+
+WrenchMenuModel::WrenchMenuModel(menus::AcceleratorProvider* provider,
+ Browser* browser)
+ : ALLOW_THIS_IN_INITIALIZER_LIST(menus::SimpleMenuModel(this)),
+ provider_(provider),
+ browser_(browser),
+ tabstrip_model_(browser_->tabstrip_model()) {
+ Build();
+ UpdateZoomControls();
+
+ tabstrip_model_->AddObserver(this);
+
+ registrar_.Add(this, NotificationType::ZOOM_LEVEL_CHANGED,
+ Source<Profile>(browser_->profile()));
+ registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
+ NotificationService::AllSources());
+}
+
+WrenchMenuModel::~WrenchMenuModel() {
+ if (tabstrip_model_)
+ tabstrip_model_->RemoveObserver(this);
+}
+
+bool WrenchMenuModel::DoesCommandIdDismissMenu(int command_id) const {
+ return command_id != IDC_ZOOM_MINUS && command_id != IDC_ZOOM_PLUS;
+}
+
+bool WrenchMenuModel::IsItemForCommandIdDynamic(int command_id) const {
+ return command_id == IDC_ZOOM_PERCENT_DISPLAY ||
+#if defined(OS_MACOSX)
+ command_id == IDC_FULLSCREEN ||
+#endif
+ command_id == IDC_SYNC_BOOKMARKS ||
+ command_id == IDC_VIEW_BACKGROUND_PAGES;
+}
+
+bool WrenchMenuModel::GetIconForCommandId(int command_id,
+ SkBitmap* bitmap) const {
+ switch (command_id) {
+ case IDC_VIEW_BACKGROUND_PAGES: {
+ int num_pages = BackgroundPageTracker::GetInstance()->
+ GetUnacknowledgedBackgroundPageCount();
+ if (num_pages > 0) {
+ *bitmap = GetBackgroundPageIcon();
+ return true;
+ } else {
+ // No icon.
+ return false;
+ }
+ }
+ default:
+ // No icon for other dynamic menu items.
+ return false;
+ }
+}
+
+string16 WrenchMenuModel::GetLabelForCommandId(int command_id) const {
+ switch (command_id) {
+ case IDC_SYNC_BOOKMARKS:
+ return GetSyncMenuLabel();
+ case IDC_ZOOM_PERCENT_DISPLAY:
+ return zoom_label_;
+#if defined(OS_MACOSX)
+ case IDC_FULLSCREEN: {
+ int string_id = IDS_ENTER_FULLSCREEN_MAC; // Default to Enter.
+ // Note: On startup, |window()| may be NULL.
+ if (browser_->window() && browser_->window()->IsFullscreen())
+ string_id = IDS_EXIT_FULLSCREEN_MAC;
+ return l10n_util::GetStringUTF16(string_id);
+ }
+#endif
+ case IDC_VIEW_BACKGROUND_PAGES: {
+ string16 num_background_pages = base::FormatNumber(
+ BackgroundPageTracker::GetInstance()->GetBackgroundPageCount());
+ return l10n_util::GetStringFUTF16(IDS_VIEW_BACKGROUND_PAGES,
+ num_background_pages);
+ }
+ default:
+ NOTREACHED();
+ return string16();
+ }
+}
+
+void WrenchMenuModel::ExecuteCommand(int command_id) {
+ browser_->ExecuteCommand(command_id);
+}
+
+bool WrenchMenuModel::IsCommandIdChecked(int command_id) const {
+ if (command_id == IDC_SHOW_BOOKMARK_BAR) {
+ return browser_->profile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar);
+ }
+
+ return false;
+}
+
+bool WrenchMenuModel::IsCommandIdEnabled(int command_id) const {
+#if defined(OS_CHROMEOS)
+ // Special case because IDC_NEW_WINDOW item should be disabled in BWSI mode,
+ // but accelerator should work.
+ if (command_id == IDC_NEW_WINDOW &&
+ CommandLine::ForCurrentProcess()->HasSwitch(switches::kGuestSession))
+ return false;
+#endif
+
+ return browser_->command_updater()->IsCommandEnabled(command_id);
+}
+
+bool WrenchMenuModel::IsCommandIdVisible(int command_id) const {
+ if (command_id == IDC_UPGRADE_DIALOG) {
+#if defined(OS_CHROMEOS)
+ return (chromeos::CrosLibrary::Get()->GetUpdateLibrary()->status().status
+ == chromeos::UPDATE_STATUS_UPDATED_NEED_REBOOT);
+#else
+ return UpgradeDetector::GetInstance()->notify_upgrade();
+#endif
+ } else if (command_id == IDC_VIEW_INCOMPATIBILITIES) {
+#if defined(OS_WIN)
+ EnumerateModulesModel* loaded_modules =
+ EnumerateModulesModel::GetInstance();
+ return loaded_modules->confirmed_bad_modules_detected() > 0;
+#else
+ return false;
+#endif
+ } else if (command_id == IDC_VIEW_BACKGROUND_PAGES) {
+ BackgroundPageTracker* tracker = BackgroundPageTracker::GetInstance();
+ return tracker->GetBackgroundPageCount() > 0;
+ }
+ return true;
+}
+
+bool WrenchMenuModel::GetAcceleratorForCommandId(
+ int command_id,
+ menus::Accelerator* accelerator) {
+ return provider_->GetAcceleratorForCommandId(command_id, accelerator);
+}
+
+void WrenchMenuModel::TabSelectedAt(TabContentsWrapper* old_contents,
+ TabContentsWrapper* new_contents,
+ int index,
+ bool user_gesture) {
+ // The user has switched between tabs and the new tab may have a different
+ // zoom setting.
+ UpdateZoomControls();
+}
+
+void WrenchMenuModel::TabReplacedAt(TabContentsWrapper* old_contents,
+ TabContentsWrapper* new_contents,
+ int index) {
+ UpdateZoomControls();
+}
+
+void WrenchMenuModel::TabStripModelDeleted() {
+ // During views shutdown, the tabstrip model/browser is deleted first, while
+ // it is the opposite in gtk land.
+ tabstrip_model_->RemoveObserver(this);
+ tabstrip_model_ = NULL;
+}
+
+void WrenchMenuModel::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ switch (type.value) {
+ case NotificationType::ZOOM_LEVEL_CHANGED:
+ case NotificationType::NAV_ENTRY_COMMITTED:
+ UpdateZoomControls();
+ break;
+ default:
+ NOTREACHED();
+ }
+}
+
+// For testing.
+WrenchMenuModel::WrenchMenuModel()
+ : ALLOW_THIS_IN_INITIALIZER_LIST(menus::SimpleMenuModel(this)),
+ provider_(NULL),
+ browser_(NULL),
+ tabstrip_model_(NULL) {
+}
+
+void WrenchMenuModel::Build() {
+ AddItemWithStringId(IDC_NEW_TAB, IDS_NEW_TAB);
+ AddItemWithStringId(IDC_NEW_WINDOW, IDS_NEW_WINDOW);
+ AddItemWithStringId(IDC_NEW_INCOGNITO_WINDOW,
+ IDS_NEW_INCOGNITO_WINDOW);
+
+ AddSeparator();
+#if defined(OS_MACOSX) || (defined(OS_LINUX) && !defined(TOOLKIT_VIEWS))
+ // WARNING: Mac does not use the ButtonMenuItemModel, but instead defines the
+ // layout for this menu item in Toolbar.xib. It does, however, use the
+ // command_id value from AddButtonItem() to identify this special item.
+ edit_menu_item_model_.reset(new menus::ButtonMenuItemModel(IDS_EDIT, this));
+ edit_menu_item_model_->AddGroupItemWithStringId(IDC_CUT, IDS_CUT);
+ edit_menu_item_model_->AddGroupItemWithStringId(IDC_COPY, IDS_COPY);
+ edit_menu_item_model_->AddGroupItemWithStringId(IDC_PASTE, IDS_PASTE);
+ AddButtonItem(IDC_EDIT_MENU, edit_menu_item_model_.get());
+#else
+ // TODO(port): Move to the above.
+ CreateCutCopyPaste();
+#endif
+
+ AddSeparator();
+#if defined(OS_MACOSX) || (defined(OS_LINUX) && !defined(TOOLKIT_VIEWS))
+ // WARNING: See above comment.
+ zoom_menu_item_model_.reset(
+ new menus::ButtonMenuItemModel(IDS_ZOOM_MENU, this));
+ zoom_menu_item_model_->AddGroupItemWithStringId(
+ IDC_ZOOM_MINUS, IDS_ZOOM_MINUS2);
+ zoom_menu_item_model_->AddButtonLabel(IDC_ZOOM_PERCENT_DISPLAY,
+ IDS_ZOOM_PLUS2);
+ zoom_menu_item_model_->AddGroupItemWithStringId(
+ IDC_ZOOM_PLUS, IDS_ZOOM_PLUS2);
+ zoom_menu_item_model_->AddSpace();
+ zoom_menu_item_model_->AddItemWithImage(
+ IDC_FULLSCREEN, IDR_FULLSCREEN_MENU_BUTTON);
+ AddButtonItem(IDC_ZOOM_MENU, zoom_menu_item_model_.get());
+#else
+ // TODO(port): Move to the above.
+ CreateZoomFullscreen();
+#endif
+
+ AddSeparator();
+ AddItemWithStringId(IDC_SAVE_PAGE, IDS_SAVE_PAGE);
+ AddItemWithStringId(IDC_FIND, IDS_FIND);
+ AddItemWithStringId(IDC_PRINT, IDS_PRINT);
+
+ tools_menu_model_.reset(new ToolsMenuModel(this, browser_));
+ AddSubMenuWithStringId(IDC_ZOOM_MENU, IDS_TOOLS_MENU,
+ tools_menu_model_.get());
+
+ AddSeparator();
+#if defined(ENABLE_REMOTING)
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableRemoting)) {
+ AddItem(IDC_REMOTING_SETUP,
+ l10n_util::GetStringUTF16(IDS_REMOTING_SETUP_LABEL));
+ }
+#endif
+ AddItemWithStringId(IDC_SHOW_BOOKMARK_MANAGER, IDS_BOOKMARK_MANAGER);
+ AddItemWithStringId(IDC_SHOW_HISTORY, IDS_SHOW_HISTORY);
+ AddItemWithStringId(IDC_SHOW_DOWNLOADS, IDS_SHOW_DOWNLOADS);
+ AddSeparator();
+
+#if defined(OS_CHROMEOS)
+ AddItemWithStringId(IDC_OPTIONS, IDS_SETTINGS);
+#elif defined(OS_MACOSX)
+ AddItemWithStringId(IDC_OPTIONS, IDS_PREFERENCES);
+#elif defined(OS_LINUX)
+ string16 preferences = gtk_util::GetStockPreferencesMenuLabel();
+ if (!preferences.empty())
+ AddItem(IDC_OPTIONS, preferences);
+ else
+ AddItemWithStringId(IDC_OPTIONS, IDS_PREFERENCES);
+#else
+ AddItemWithStringId(IDC_OPTIONS, IDS_OPTIONS);
+#endif
+
+#if defined(OS_CHROMEOS)
+ const string16 product_name = l10n_util::GetStringUTF16(IDS_PRODUCT_OS_NAME);
+#else
+ const string16 product_name = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
+#endif
+ // On Mac, there is no About item.
+ if (browser_defaults::kShowAboutMenuItem) {
+ AddItem(IDC_ABOUT, l10n_util::GetStringFUTF16(
+ IDS_ABOUT, product_name));
+ }
+ string16 num_background_pages = base::FormatNumber(
+ BackgroundPageTracker::GetInstance()->GetBackgroundPageCount());
+ AddItem(IDC_VIEW_BACKGROUND_PAGES, l10n_util::GetStringFUTF16(
+ IDS_VIEW_BACKGROUND_PAGES, num_background_pages));
+ AddItem(IDC_UPGRADE_DIALOG, l10n_util::GetStringFUTF16(
+ IDS_UPDATE_NOW, product_name));
+ AddItem(IDC_VIEW_INCOMPATIBILITIES, l10n_util::GetStringUTF16(
+ IDS_VIEW_INCOMPATIBILITIES));
+
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ SetIcon(GetIndexOfCommandId(IDC_UPGRADE_DIALOG),
+ *rb.GetBitmapNamed(IDR_UPDATE_MENU));
+#if defined(OS_WIN)
+ SetIcon(GetIndexOfCommandId(IDC_VIEW_INCOMPATIBILITIES),
+ *rb.GetBitmapNamed(IDR_CONFLICT_MENU));
+#endif
+
+ AddItemWithStringId(IDC_HELP_PAGE, IDS_HELP_PAGE);
+ if (browser_defaults::kShowExitMenuItem) {
+ AddSeparator();
+#if defined(OS_CHROMEOS)
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kGuestSession)) {
+ AddItemWithStringId(IDC_EXIT, IDS_EXIT_GUEST_MODE);
+ } else {
+ AddItemWithStringId(IDC_EXIT, IDS_SIGN_OUT);
+ }
+#else
+ AddItemWithStringId(IDC_EXIT, IDS_EXIT);
+#endif
+ }
+}
+
+void WrenchMenuModel::CreateCutCopyPaste() {
+ // WARNING: views/wrench_menu assumes these items are added in this order. If
+ // you change the order you'll need to update wrench_menu as well.
+ AddItemWithStringId(IDC_CUT, IDS_CUT);
+ AddItemWithStringId(IDC_COPY, IDS_COPY);
+ AddItemWithStringId(IDC_PASTE, IDS_PASTE);
+}
+
+void WrenchMenuModel::CreateZoomFullscreen() {
+ // WARNING: views/wrench_menu assumes these items are added in this order. If
+ // you change the order you'll need to update wrench_menu as well.
+ AddItemWithStringId(IDC_ZOOM_MINUS, IDS_ZOOM_MINUS);
+ AddItemWithStringId(IDC_ZOOM_PLUS, IDS_ZOOM_PLUS);
+ AddItemWithStringId(IDC_FULLSCREEN, IDS_FULLSCREEN);
+}
+
+void WrenchMenuModel::UpdateZoomControls() {
+ bool enable_increment = false;
+ bool enable_decrement = false;
+ int zoom_percent = 100;
+ if (browser_->GetSelectedTabContents()) {
+ zoom_percent = browser_->GetSelectedTabContents()->GetZoomPercent(
+ &enable_increment, &enable_decrement);
+ }
+ zoom_label_ = l10n_util::GetStringFUTF16(
+ IDS_ZOOM_PERCENT, base::IntToString16(zoom_percent));
+}
+
+string16 WrenchMenuModel::GetSyncMenuLabel() const {
+ return sync_ui_util::GetSyncMenuLabel(
+ browser_->profile()->GetOriginalProfile()->GetProfileSyncService());
+}
diff --git a/chrome/browser/ui/toolbar/wrench_menu_model.h b/chrome/browser/ui/toolbar/wrench_menu_model.h
new file mode 100644
index 0000000..2690ea9
--- /dev/null
+++ b/chrome/browser/ui/toolbar/wrench_menu_model.h
@@ -0,0 +1,150 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_TOOLBAR_WRENCH_MENU_MODEL_H_
+#define CHROME_BROWSER_UI_TOOLBAR_WRENCH_MENU_MODEL_H_
+#pragma once
+
+#include "app/menus/accelerator.h"
+#include "app/menus/button_menu_item_model.h"
+#include "app/menus/simple_menu_model.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/tabs/tab_strip_model_observer.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+
+class Browser;
+class TabStripModel;
+
+namespace {
+class MockWrenchMenuModel;
+} // namespace
+
+// A menu model that builds the contents of an encoding menu.
+class EncodingMenuModel : public menus::SimpleMenuModel,
+ public menus::SimpleMenuModel::Delegate {
+ public:
+ explicit EncodingMenuModel(Browser* browser);
+ virtual ~EncodingMenuModel();
+
+ // Overridden from menus::SimpleMenuModel::Delegate:
+ virtual bool IsCommandIdChecked(int command_id) const;
+ virtual bool IsCommandIdEnabled(int command_id) const;
+ virtual bool GetAcceleratorForCommandId(int command_id,
+ menus::Accelerator* accelerator);
+ virtual void ExecuteCommand(int command_id);
+
+ private:
+ void Build();
+
+ Browser* browser_; // weak
+
+ DISALLOW_COPY_AND_ASSIGN(EncodingMenuModel);
+};
+
+// A menu model that builds the contents of the zoom menu.
+class ZoomMenuModel : public menus::SimpleMenuModel {
+ public:
+ explicit ZoomMenuModel(menus::SimpleMenuModel::Delegate* delegate);
+ virtual ~ZoomMenuModel();
+
+ private:
+ void Build();
+
+ DISALLOW_COPY_AND_ASSIGN(ZoomMenuModel);
+};
+
+class ToolsMenuModel : public menus::SimpleMenuModel {
+ public:
+ ToolsMenuModel(menus::SimpleMenuModel::Delegate* delegate, Browser* browser);
+ virtual ~ToolsMenuModel();
+
+ private:
+ void Build(Browser* browser);
+
+ scoped_ptr<EncodingMenuModel> encoding_menu_model_;
+
+ DISALLOW_COPY_AND_ASSIGN(ToolsMenuModel);
+};
+
+// A menu model that builds the contents of the wrench menu.
+class WrenchMenuModel : public menus::SimpleMenuModel,
+ public menus::SimpleMenuModel::Delegate,
+ public menus::ButtonMenuItemModel::Delegate,
+ public TabStripModelObserver,
+ public NotificationObserver {
+ public:
+ WrenchMenuModel(menus::AcceleratorProvider* provider, Browser* browser);
+ virtual ~WrenchMenuModel();
+
+ // Overridden for ButtonMenuItemModel::Delegate:
+ virtual bool DoesCommandIdDismissMenu(int command_id) const;
+
+ // Overridden for both ButtonMenuItemModel::Delegate and SimpleMenuModel:
+ virtual bool IsItemForCommandIdDynamic(int command_id) const;
+ virtual string16 GetLabelForCommandId(int command_id) const;
+ virtual bool GetIconForCommandId(int command_id, SkBitmap* icon) const;
+ virtual void ExecuteCommand(int command_id);
+ virtual bool IsCommandIdChecked(int command_id) const;
+ virtual bool IsCommandIdEnabled(int command_id) const;
+ virtual bool IsCommandIdVisible(int command_id) const;
+ virtual bool GetAcceleratorForCommandId(
+ int command_id,
+ menus::Accelerator* accelerator);
+
+ // Overridden from TabStripModelObserver:
+ virtual void TabSelectedAt(TabContentsWrapper* old_contents,
+ TabContentsWrapper* new_contents,
+ int index,
+ bool user_gesture);
+ virtual void TabReplacedAt(TabContentsWrapper* old_contents,
+ TabContentsWrapper* new_contents, int index);
+ virtual void TabStripModelDeleted();
+
+ // Overridden from NotificationObserver:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // Getters.
+ Browser* browser() const { return browser_; }
+
+ // Calculates |zoom_label_| in response to a zoom change.
+ void UpdateZoomControls();
+
+ private:
+ // Testing constructor used for mocking.
+ friend class ::MockWrenchMenuModel;
+ WrenchMenuModel();
+
+ void Build();
+
+ // Adds custom items to the menu. Deprecated in favor of a cross platform
+ // model for button items.
+ void CreateCutCopyPaste();
+ void CreateZoomFullscreen();
+
+ string16 GetSyncMenuLabel() const;
+
+ // Models for the special menu items with buttons.
+ scoped_ptr<menus::ButtonMenuItemModel> edit_menu_item_model_;
+ scoped_ptr<menus::ButtonMenuItemModel> zoom_menu_item_model_;
+
+ // Label of the zoom label in the zoom menu item.
+ string16 zoom_label_;
+
+ // Tools menu.
+ scoped_ptr<ToolsMenuModel> tools_menu_model_;
+
+ menus::AcceleratorProvider* provider_; // weak
+
+ Browser* browser_; // weak
+ TabStripModel* tabstrip_model_; // weak
+
+ NotificationRegistrar registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(WrenchMenuModel);
+};
+
+#endif // CHROME_BROWSER_UI_TOOLBAR_WRENCH_MENU_MODEL_H_
diff --git a/chrome/browser/ui/toolbar/wrench_menu_model_unittest.cc b/chrome/browser/ui/toolbar/wrench_menu_model_unittest.cc
new file mode 100644
index 0000000..92a8125
--- /dev/null
+++ b/chrome/browser/ui/toolbar/wrench_menu_model_unittest.cc
@@ -0,0 +1,105 @@
+// 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.
+
+#include "chrome/browser/ui/toolbar/wrench_menu_model.h"
+
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/test/browser_with_test_window_test.h"
+#include "chrome/test/menu_model_test.h"
+#include "chrome/test/testing_profile.h"
+#include "grit/generated_resources.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class WrenchMenuModelTest : public BrowserWithTestWindowTest,
+ public menus::AcceleratorProvider {
+ public:
+ // Don't handle accelerators.
+ virtual bool GetAcceleratorForCommandId(
+ int command_id,
+ menus::Accelerator* accelerator) { return false; }
+};
+
+// Copies parts of MenuModelTest::Delegate and combines them with the
+// WrenchMenuModel since WrenchMenuModel is now a SimpleMenuModel::Delegate and
+// not derived from SimpleMenuModel.
+class TestWrenchMenuModel : public WrenchMenuModel {
+ public:
+ TestWrenchMenuModel(menus::AcceleratorProvider* provider,
+ Browser* browser)
+ : WrenchMenuModel(provider, browser),
+ execute_count_(0),
+ checked_count_(0),
+ enable_count_(0) {
+ }
+
+ // Testing overrides to menus::SimpleMenuModel::Delegate:
+ virtual bool IsCommandIdChecked(int command_id) const {
+ bool val = WrenchMenuModel::IsCommandIdChecked(command_id);
+ if (val)
+ checked_count_++;
+ return val;
+ }
+
+ virtual bool IsCommandIdEnabled(int command_id) const {
+ ++enable_count_;
+ return true;
+ }
+
+ virtual void ExecuteCommand(int command_id) { ++execute_count_; }
+
+ int execute_count_;
+ mutable int checked_count_;
+ mutable int enable_count_;
+};
+
+TEST_F(WrenchMenuModelTest, Basics) {
+ TestWrenchMenuModel model(this, browser());
+ int itemCount = model.GetItemCount();
+
+ // Verify it has items. The number varies by platform, so we don't check
+ // the exact number.
+ EXPECT_GT(itemCount, 10);
+
+ // Execute a couple of the items and make sure it gets back to our delegate.
+ // We can't use CountEnabledExecutable() here because the encoding menu's
+ // delegate is internal, it doesn't use the one we pass in.
+ model.ActivatedAt(0);
+ EXPECT_TRUE(model.IsEnabledAt(0));
+ // Make sure to use the index that is not separator in all configurations.
+ model.ActivatedAt(2);
+ EXPECT_TRUE(model.IsEnabledAt(2));
+ EXPECT_EQ(model.execute_count_, 2);
+ EXPECT_EQ(model.enable_count_, 2);
+
+ model.execute_count_ = 0;
+ model.enable_count_ = 0;
+
+ // Choose something from the tools submenu and make sure it makes it back to
+ // the delegate as well. Use the first submenu as the tools one.
+ int toolsModelIndex = -1;
+ for (int i = 0; i < itemCount; ++i) {
+ if (model.GetTypeAt(i) == menus::MenuModel::TYPE_SUBMENU) {
+ toolsModelIndex = i;
+ break;
+ }
+ }
+ EXPECT_GT(toolsModelIndex, -1);
+ menus::MenuModel* toolsModel = model.GetSubmenuModelAt(toolsModelIndex);
+ EXPECT_TRUE(toolsModel);
+ EXPECT_GT(toolsModel->GetItemCount(), 2);
+ toolsModel->ActivatedAt(2);
+ EXPECT_TRUE(toolsModel->IsEnabledAt(2));
+ EXPECT_EQ(model.execute_count_, 1);
+ EXPECT_EQ(model.enable_count_, 1);
+}
+
+class EncodingMenuModelTest : public BrowserWithTestWindowTest,
+ public MenuModelTest {
+};
+
+TEST_F(EncodingMenuModelTest, IsCommandIdCheckedWithNoTabs) {
+ EncodingMenuModel model(browser());
+ ASSERT_EQ(NULL, browser()->GetSelectedTabContents());
+ EXPECT_FALSE(model.IsCommandIdChecked(IDC_ENCODING_ISO88591));
+}
diff --git a/chrome/browser/ui/touch/frame/browser_non_client_frame_view_factory_touch.cc b/chrome/browser/ui/touch/frame/browser_non_client_frame_view_factory_touch.cc
new file mode 100644
index 0000000..5223640
--- /dev/null
+++ b/chrome/browser/ui/touch/frame/browser_non_client_frame_view_factory_touch.cc
@@ -0,0 +1,23 @@
+// 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.
+
+#include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"
+
+#include "chrome/browser/ui/touch/frame/touch_browser_frame_view.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+
+namespace browser {
+
+BrowserNonClientFrameView* CreateBrowserNonClientFrameView(
+ BrowserFrame* frame, BrowserView* browser_view) {
+ if (browser_view->IsBrowserTypePopup()) {
+ // TODO(anicolao): implement popups for touch
+ NOTIMPLEMENTED();
+ return NULL;
+ } else {
+ return new TouchBrowserFrameView(frame, browser_view);
+ }
+}
+
+} // browser
diff --git a/chrome/browser/ui/touch/frame/touch_browser_frame_view.cc b/chrome/browser/ui/touch/frame/touch_browser_frame_view.cc
new file mode 100644
index 0000000..839a9a0
--- /dev/null
+++ b/chrome/browser/ui/touch/frame/touch_browser_frame_view.cc
@@ -0,0 +1,131 @@
+// 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.
+
+#include "chrome/browser/ui/touch/frame/touch_browser_frame_view.h"
+
+#include <algorithm>
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/renderer_host/site_instance.h"
+#include "chrome/browser/tab_contents/navigation_controller.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/views/dom_view.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
+#include "chrome/common/url_constants.h"
+#include "gfx/rect.h"
+
+namespace {
+
+const int kKeyboardHeight = 300;
+
+} // namespace
+
+///////////////////////////////////////////////////////////////////////////////
+// TouchBrowserFrameView, public:
+
+TouchBrowserFrameView::TouchBrowserFrameView(BrowserFrame* frame,
+ BrowserView* browser_view)
+ : OpaqueBrowserFrameView(frame, browser_view),
+ keyboard_showing_(false),
+ keyboard_(NULL) {
+ registrar_.Add(this,
+ NotificationType::NAV_ENTRY_COMMITTED,
+ NotificationService::AllSources());
+ registrar_.Add(this,
+ NotificationType::FOCUS_CHANGED_IN_PAGE,
+ NotificationService::AllSources());
+}
+
+TouchBrowserFrameView::~TouchBrowserFrameView() {
+}
+
+void TouchBrowserFrameView::Layout() {
+ OpaqueBrowserFrameView::Layout();
+
+ if (!keyboard_)
+ return;
+
+ keyboard_->SetBounds(GetBoundsForReservedArea());
+ keyboard_->SetVisible(keyboard_showing_);
+ keyboard_->Layout();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// TouchBrowserFrameView, protected:
+int TouchBrowserFrameView::GetReservedHeight() const {
+ if (keyboard_showing_)
+ return kKeyboardHeight;
+
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// TouchBrowserFrameView, private:
+
+void TouchBrowserFrameView::InitVirtualKeyboard() {
+ if (keyboard_)
+ return;
+
+ keyboard_ = new DOMView;
+
+ Profile* keyboard_profile = browser_view()->browser()->profile();
+ DCHECK(keyboard_profile) << "Profile required for virtual keyboard.";
+
+ GURL keyboard_url(chrome::kChromeUIKeyboardURL);
+ keyboard_->Init(keyboard_profile,
+ SiteInstance::CreateSiteInstanceForURL(keyboard_profile, keyboard_url));
+ keyboard_->LoadURL(keyboard_url);
+
+ keyboard_->SetVisible(false);
+ AddChildView(keyboard_);
+}
+
+void TouchBrowserFrameView::UpdateKeyboardAndLayout(bool should_show_keyboard) {
+ if (should_show_keyboard)
+ InitVirtualKeyboard();
+
+ if (should_show_keyboard == keyboard_showing_)
+ return;
+
+ DCHECK(keyboard_);
+
+ keyboard_showing_ = should_show_keyboard;
+
+ // Because the NonClientFrameView is a sibling of the ClientView, we rely on
+ // the parent to resize the ClientView instead of resizing it directly.
+ GetParent()->Layout();
+
+ // The keyboard that pops up may end up hiding the text entry. So make sure
+ // the renderer scrolls when necessary to keep the textfield visible.
+ if (keyboard_showing_) {
+ RenderViewHost* host =
+ browser_view()->browser()->GetSelectedTabContents()->render_view_host();
+ host->ScrollFocusedEditableNodeIntoView();
+ }
+}
+
+void TouchBrowserFrameView::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ Browser* browser = browser_view()->browser();
+ if (type == NotificationType::FOCUS_CHANGED_IN_PAGE) {
+ // Only modify the keyboard state if the currently active tab sent the
+ // notification.
+ if (browser->GetSelectedTabContents()->render_view_host() ==
+ Source<RenderViewHost>(source).ptr()) {
+ UpdateKeyboardAndLayout(*Details<const bool>(details).ptr());
+ }
+ } else if (type == NotificationType::NAV_ENTRY_COMMITTED) {
+ Browser* source_browser = Browser::GetBrowserForController(
+ Source<NavigationController>(source).ptr(), NULL);
+ // If the Browser for the keyboard has navigated, hide the keyboard.
+ if (source_browser == browser) {
+ UpdateKeyboardAndLayout(false);
+ }
+ }
+}
diff --git a/chrome/browser/ui/touch/frame/touch_browser_frame_view.h b/chrome/browser/ui/touch/frame/touch_browser_frame_view.h
new file mode 100644
index 0000000..7fb5703
--- /dev/null
+++ b/chrome/browser/ui/touch/frame/touch_browser_frame_view.h
@@ -0,0 +1,49 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_TOUCH_FRAME_TOUCH_BROWSER_FRAME_VIEW_H_
+#define CHROME_BROWSER_UI_TOUCH_FRAME_TOUCH_BROWSER_FRAME_VIEW_H_
+#pragma once
+
+#include "chrome/browser/ui/views/frame/opaque_browser_frame_view.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+
+class BrowserFrame;
+class BrowserView;
+class DOMView;
+class NotificationDetails;
+class NotificationSource;
+
+class TouchBrowserFrameView : public OpaqueBrowserFrameView,
+ public NotificationObserver {
+ public:
+ // Constructs a non-client view for an BrowserFrame.
+ TouchBrowserFrameView(BrowserFrame* frame, BrowserView* browser_view);
+ virtual ~TouchBrowserFrameView();
+
+ // Overridden from OpaqueBrowserFrameView
+ virtual void Layout();
+
+ protected:
+ // Overridden from OpaqueBrowserFrameView
+ virtual int GetReservedHeight() const;
+
+ private:
+ virtual void InitVirtualKeyboard();
+ virtual void UpdateKeyboardAndLayout(bool should_show_keyboard);
+
+ // Overridden from NotificationObserver.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ bool keyboard_showing_;
+ DOMView* keyboard_;
+ NotificationRegistrar registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(TouchBrowserFrameView);
+};
+
+#endif // CHROME_BROWSER_UI_TOUCH_FRAME_TOUCH_BROWSER_FRAME_VIEW_H_
diff --git a/chrome/browser/view_ids.h b/chrome/browser/ui/view_ids.h
index 948eabb..948eabb 100644
--- a/chrome/browser/view_ids.h
+++ b/chrome/browser/ui/view_ids.h
diff --git a/chrome/browser/ui/views/about_chrome_view.cc b/chrome/browser/ui/views/about_chrome_view.cc
index 2808d98..215c6f0 100644
--- a/chrome/browser/ui/views/about_chrome_view.cc
+++ b/chrome/browser/ui/views/about_chrome_view.cc
@@ -4,6 +4,10 @@
#include "chrome/browser/views/about_chrome_view.h"
+#if defined(OS_WIN)
+#include <commdlg.h>
+#endif // defined(OS_WIN)
+
#include <algorithm>
#include <string>
#include <vector>
@@ -16,7 +20,6 @@
#include "base/utf_string_conversions.h"
#include "base/win/windows_version.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/prefs/pref_service.h"
@@ -26,6 +29,7 @@
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
+#include "chrome/installer/util/browser_distribution.h"
#include "gfx/canvas.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
@@ -40,12 +44,14 @@
#include "webkit/glue/webkit_glue.h"
#if defined(OS_WIN)
-#include <commdlg.h>
-
#include "base/win_util.h"
#include "chrome/browser/views/restart_message_box.h"
#include "chrome/installer/util/install_util.h"
-#endif
+#endif // defined(OS_WIN)
+
+#if defined(OS_WIN) || defined(OS_CHROMEOS)
+#include "chrome/browser/browser_process.h"
+#endif // defined(OS_WIN) || defined(OS_CHROMEOS)
namespace {
// The pixel width of the version text field. Ideally, we'd like to have the
@@ -150,16 +156,16 @@ void AboutChromeView::Init() {
return;
}
- current_version_ = ASCIIToWide(version_info.Version());
+ current_version_ = version_info.Version();
std::string version_modifier = platform_util::GetVersionStringModifier();
if (!version_modifier.empty())
- version_details_ += L" " + ASCIIToWide(version_modifier);
+ version_details_ += " " + version_modifier;
#if !defined(GOOGLE_CHROME_BUILD)
- version_details_ += L" (";
- version_details_ += ASCIIToWide(version_info.LastChange());
- version_details_ += L")";
+ version_details_ += " (";
+ version_details_ += version_info.LastChange();
+ version_details_ += ")";
#endif
// Views we will add to the *parent* of this dialog, since it will display
@@ -204,7 +210,7 @@ void AboutChromeView::Init() {
// This is a text field so people can copy the version number from the dialog.
version_label_ = new views::Textfield();
- version_label_->SetText(WideToUTF16Hack(current_version_ + version_details_));
+ version_label_->SetText(ASCIIToUTF16(current_version_ + version_details_));
version_label_->SetReadOnly(true);
version_label_->RemoveBorder();
version_label_->SetTextColor(SK_ColorBLACK);
@@ -739,12 +745,13 @@ void AboutChromeView::UpdateStatus(GoogleUpdateUpgradeResult result,
// Google Update reported that Chrome is up-to-date. Now make sure that we
// are running the latest version and if not, notify the user by falling
// into the next case of UPGRADE_SUCCESSFUL.
- scoped_ptr<installer::Version> installed_version(
- InstallUtil::GetChromeVersion(false));
- scoped_ptr<installer::Version> running_version(
- installer::Version::GetVersionFromString(current_version_));
+ BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+ scoped_ptr<Version> installed_version(
+ InstallUtil::GetChromeVersion(dist, false));
+ scoped_ptr<Version> running_version(
+ Version::GetVersionFromString(current_version_));
if (!installed_version.get() ||
- !installed_version->IsHigherThan(running_version.get())) {
+ (installed_version->CompareTo(*running_version) < 0)) {
#endif
UserMetrics::RecordAction(
UserMetricsAction("UpgradeCheck_AlreadyUpToDate"), profile_);
@@ -756,7 +763,7 @@ void AboutChromeView::UpdateStatus(GoogleUpdateUpgradeResult result,
std::wstring update_label_text =
l10n_util::GetStringF(IDS_UPGRADE_ALREADY_UP_TO_DATE,
l10n_util::GetString(IDS_PRODUCT_NAME),
- current_version_);
+ ASCIIToUTF16(current_version_));
#endif
if (base::i18n::IsRTL()) {
update_label_text.push_back(
diff --git a/chrome/browser/ui/views/about_chrome_view.h b/chrome/browser/ui/views/about_chrome_view.h
index a2ed439..ab287be 100644
--- a/chrome/browser/ui/views/about_chrome_view.h
+++ b/chrome/browser/ui/views/about_chrome_view.h
@@ -146,10 +146,10 @@ class AboutChromeView : public views::View,
#endif
// Our current version.
- std::wstring current_version_;
+ std::string current_version_;
// Additional information about the version (channel and build number).
- std::wstring version_details_;
+ std::string version_details_;
// The version Google Update reports is available to us.
std::wstring new_version_available_;
diff --git a/chrome/browser/ui/views/about_ipc_dialog.cc b/chrome/browser/ui/views/about_ipc_dialog.cc
index 358e28f..3e5d5d6 100644
--- a/chrome/browser/ui/views/about_ipc_dialog.cc
+++ b/chrome/browser/ui/views/about_ipc_dialog.cc
@@ -59,7 +59,7 @@ enum {
class RegisterLoggerFuncs {
public:
RegisterLoggerFuncs() {
- IPC::Logging::SetLoggerFunctions(g_log_function_mapping);
+ IPC::Logging::set_log_function_map(&g_log_function_mapping);
}
};
@@ -75,45 +75,8 @@ std::set<int> disabled_messages;
bool init_done = false;
HWND settings_dialog = NULL;
-
-// Settings lists.
-struct Settings {
- CListViewCtrl* view;
- CListViewCtrl* view_host;
- CListViewCtrl* plugin;
- CListViewCtrl* plugin_host;
- CListViewCtrl* npobject;
- CListViewCtrl* plugin_process;
- CListViewCtrl* plugin_process_host;
- CListViewCtrl* devtools_agent;
- CListViewCtrl* devtools_client;
-
-} settings_views = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
-
-void CreateColumn(uint32 start, uint32 end, HWND hwnd,
- CListViewCtrl** control) {
- DCHECK(*control == NULL);
- *control = new CListViewCtrl(hwnd);
- CListViewCtrl* control_ptr = *control;
- control_ptr->SetViewType(LVS_REPORT);
- control_ptr->SetExtendedListViewStyle(LVS_EX_CHECKBOXES);
- control_ptr->ModifyStyle(0, LVS_SORTASCENDING | LVS_NOCOLUMNHEADER);
- control_ptr->InsertColumn(0, L"id", LVCFMT_LEFT, 230);
-
- for (uint32 i = start; i < end; i++) {
- std::string name;
- IPC::Logging::GetMessageText(i, &name, NULL, NULL);
- std::wstring wname = UTF8ToWide(name);
-
- int index = control_ptr->InsertItem(
- LVIF_TEXT | LVIF_PARAM, 0, wname.c_str(), 0, 0, 0, i);
-
- control_ptr->SetItemText(index, 0, wname.c_str());
-
- if (disabled_messages.find(i) == disabled_messages.end())
- control_ptr->SetCheckState(index, TRUE);
- }
-}
+// Settings.
+CListViewCtrl* messages = NULL;
void OnCheck(int id, bool checked) {
if (!init_done)
@@ -125,58 +88,38 @@ void OnCheck(int id, bool checked) {
disabled_messages.insert(id);
}
+void InitDialog(HWND hwnd) {
+ messages = new CListViewCtrl(::GetDlgItem(hwnd, IDC_Messages));
-void CheckButtons(CListViewCtrl* control, bool check) {
- int count = control->GetItemCount();
- for (int i = 0; i < count; ++i)
- control->SetCheckState(i, check);
-}
+ messages->SetViewType(LVS_REPORT);
+ messages->SetExtendedListViewStyle(LVS_EX_CHECKBOXES);
+ messages->ModifyStyle(0, LVS_SORTASCENDING | LVS_NOCOLUMNHEADER);
+ messages->InsertColumn(0, L"id", LVCFMT_LEFT, 230);
+
+ LogFunctionMap* log_functions = IPC::Logging::log_function_map();
+ for (LogFunctionMap::iterator i = log_functions->begin();
+ i != log_functions->end(); ++i) {
+ std::string name;
+ (*i->second)(&name, NULL, NULL);
+ if (name.empty())
+ continue; // Will happen if the message file isn't included above.
+ std::wstring wname = UTF8ToWide(name);
+
+ int index = messages->InsertItem(
+ LVIF_TEXT | LVIF_PARAM, 0, wname.c_str(), 0, 0, 0, i->first);
+
+ messages->SetItemText(index, 0, wname.c_str());
+
+ if (disabled_messages.find(i->first) == disabled_messages.end())
+ messages->SetCheckState(index, TRUE);
+ }
-void InitDialog(HWND hwnd) {
- CreateColumn(ViewStart, ViewEnd, ::GetDlgItem(hwnd, IDC_View),
- &settings_views.view);
- CreateColumn(ViewHostStart, ViewHostEnd, ::GetDlgItem(hwnd, IDC_ViewHost),
- &settings_views.view_host);
- CreateColumn(PluginStart, PluginEnd, ::GetDlgItem(hwnd, IDC_Plugin),
- &settings_views.plugin);
- CreateColumn(PluginHostStart, PluginHostEnd,
- ::GetDlgItem(hwnd, IDC_PluginHost),
- &settings_views.plugin_host);
- CreateColumn(NPObjectStart, NPObjectEnd, ::GetDlgItem(hwnd, IDC_NPObject),
- &settings_views.npobject);
- CreateColumn(PluginProcessStart, PluginProcessEnd,
- ::GetDlgItem(hwnd, IDC_PluginProcess),
- &settings_views.plugin_process);
- CreateColumn(PluginProcessHostStart, PluginProcessHostEnd,
- ::GetDlgItem(hwnd, IDC_PluginProcessHost),
- &settings_views.plugin_process_host);
- CreateColumn(DevToolsAgentStart, DevToolsAgentEnd,
- ::GetDlgItem(hwnd, IDC_DevToolsAgent),
- &settings_views.devtools_agent);
- CreateColumn(DevToolsClientStart, DevToolsClientEnd,
- ::GetDlgItem(hwnd, IDC_DevToolsClient),
- &settings_views.devtools_client);
init_done = true;
}
void CloseDialog() {
- delete settings_views.view;
- delete settings_views.view_host;
- delete settings_views.plugin_host;
- delete settings_views.npobject;
- delete settings_views.plugin_process;
- delete settings_views.plugin_process_host;
- delete settings_views.devtools_agent;
- delete settings_views.devtools_client;
- settings_views.view = NULL;
- settings_views.view_host = NULL;
- settings_views.plugin = NULL;
- settings_views.plugin_host = NULL;
- settings_views.npobject = NULL;
- settings_views.plugin_process = NULL;
- settings_views.plugin_process_host = NULL;
- settings_views.devtools_agent = NULL;
- settings_views.devtools_client = NULL;
+ delete messages;
+ messages = NULL;
init_done = false;
@@ -185,7 +128,7 @@ void CloseDialog() {
/* The old version of this code stored the last settings in the preferences.
But with this dialog, there currently isn't an easy way to get the profile
- to asave in the preferences.
+ to save in the preferences.
Profile* current_profile = profile();
if (!current_profile)
return;
@@ -203,38 +146,9 @@ void CloseDialog() {
}
void OnButtonClick(int id) {
- switch (id) {
- case IDC_ViewAll:
- CheckButtons(settings_views.view, true);
- break;
- case IDC_ViewNone:
- CheckButtons(settings_views.view, false);
- break;
- case IDC_ViewHostAll:
- CheckButtons(settings_views.view_host, true);
- break;
- case IDC_ViewHostNone:
- CheckButtons(settings_views.view_host, false);
- break;
- case IDC_PluginAll:
- CheckButtons(settings_views.plugin, true);
- break;
- case IDC_PluginNone:
- CheckButtons(settings_views.plugin, false);
- break;
- case IDC_PluginHostAll:
- CheckButtons(settings_views.plugin_host, true);
- break;
- case IDC_PluginHostNone:
- CheckButtons(settings_views.plugin_host, false);
- break;
- case IDC_NPObjectAll:
- CheckButtons(settings_views.npobject, true);
- break;
- case IDC_NPObjectNone:
- CheckButtons(settings_views.npobject, false);
- break;
- }
+ int count = messages->GetItemCount();
+ for (int i = 0; i < count; ++i)
+ messages->SetCheckState(i, id == IDC_MessagesAll);
}
INT_PTR CALLBACK DialogProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
@@ -250,11 +164,7 @@ INT_PTR CALLBACK DialogProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
break;
case WM_NOTIFY: {
NMLISTVIEW* info = reinterpret_cast<NM_LISTVIEW*>(lparam);
- if ((wparam == IDC_View || wparam == IDC_ViewHost ||
- wparam == IDC_Plugin ||
- wparam == IDC_PluginHost || wparam == IDC_NPObject ||
- wparam == IDC_PluginProcess || wparam == IDC_PluginProcessHost) &&
- info->hdr.code == LVN_ITEMCHANGED) {
+ if (wparam == IDC_Messages && info->hdr.code == LVN_ITEMCHANGED) {
if (info->uChanged & LVIF_STATE) {
bool checked = (info->uNewState >> 12) == 2;
OnCheck(static_cast<int>(info->lParam), checked);
@@ -293,12 +203,12 @@ AboutIPCDialog::AboutIPCDialog()
table_(NULL),
tracking_(false) {
SetupControls();
- IPC::Logging::current()->SetConsumer(this);
+ IPC::Logging::GetInstance()->SetConsumer(this);
}
AboutIPCDialog::~AboutIPCDialog() {
active_dialog = NULL;
- IPC::Logging::current()->SetConsumer(NULL);
+ IPC::Logging::GetInstance()->SetConsumer(NULL);
}
// static
diff --git a/chrome/browser/ui/views/accelerator_table_gtk.cc b/chrome/browser/ui/views/accelerator_table_gtk.cc
index 261420e..fae032a 100644
--- a/chrome/browser/ui/views/accelerator_table_gtk.cc
+++ b/chrome/browser/ui/views/accelerator_table_gtk.cc
@@ -19,6 +19,9 @@ const AcceleratorMapping kAcceleratorMap[] = {
{ app::VKEY_BACK, false, false, false, IDC_BACK },
#if defined(OS_CHROMEOS)
{ app::VKEY_F1, false, false, false, IDC_BACK },
+ // TODO(mazda): Change VKEY_1 to VKEY_OME_2 once the new version of the
+ // keyboard overlay is ready.
+ { app::VKEY_1, false, true, true, IDC_SHOW_KEYBOARD_OVERLAY },
#endif
{ app::VKEY_D, false, true, false, IDC_BOOKMARK_PAGE },
{ app::VKEY_D, true, true, false, IDC_BOOKMARK_ALL_TABS },
diff --git a/chrome/browser/ui/views/accessibility_event_router_views.cc b/chrome/browser/ui/views/accessibility_event_router_views.cc
index 4b1ad00..b563b8d 100644
--- a/chrome/browser/ui/views/accessibility_event_router_views.cc
+++ b/chrome/browser/ui/views/accessibility_event_router_views.cc
@@ -9,8 +9,8 @@
#include "base/message_loop.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/extensions/extension_accessibility_api.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/views/location_bar/location_bar_view.h"
#include "chrome/common/notification_type.h"
#include "views/accessibility/accessibility_types.h"
diff --git a/chrome/browser/ui/views/accessible_pane_view.cc b/chrome/browser/ui/views/accessible_pane_view.cc
index b876940..1e07d1d 100644
--- a/chrome/browser/ui/views/accessible_pane_view.cc
+++ b/chrome/browser/ui/views/accessible_pane_view.cc
@@ -3,10 +3,10 @@
// found in the LICENSE file.
#include "base/logging.h"
-#include "chrome/browser/view_ids.h"
-#include "chrome/browser/views/frame/browser_view.h"
-#include "chrome/browser/views/location_bar/location_bar_view.h"
-#include "chrome/browser/views/accessible_pane_view.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
+#include "chrome/browser/ui/views/accessible_pane_view.h"
#include "views/controls/button/menu_button.h"
#include "views/controls/native/native_view_host.h"
#include "views/focus/focus_search.h"
@@ -107,7 +107,7 @@ void AccessiblePaneView::LocationBarSelectAll() {
}
void AccessiblePaneView::RestoreLastFocusedView() {
- views::ViewStorage* view_storage = views::ViewStorage::GetSharedInstance();
+ views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
views::View* last_focused_view =
view_storage->RetrieveView(last_focused_view_storage_id_);
if (last_focused_view) {
diff --git a/chrome/browser/ui/views/accessible_view_helper.cc b/chrome/browser/ui/views/accessible_view_helper.cc
index 65caf36..ca15381 100644
--- a/chrome/browser/ui/views/accessible_view_helper.cc
+++ b/chrome/browser/ui/views/accessible_view_helper.cc
@@ -6,7 +6,7 @@
#include "app/l10n_util.h"
#include "chrome/browser/accessibility_events.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/views/accessibility_event_router_views.h"
#include "chrome/common/notification_service.h"
#include "views/controls/native/native_view_host.h"
diff --git a/chrome/browser/ui/views/autocomplete/autocomplete_popup_contents_view.cc b/chrome/browser/ui/views/autocomplete/autocomplete_popup_contents_view.cc
index 2f808dd..199e631 100644
--- a/chrome/browser/ui/views/autocomplete/autocomplete_popup_contents_view.cc
+++ b/chrome/browser/ui/views/autocomplete/autocomplete_popup_contents_view.cc
@@ -17,7 +17,7 @@
#include "chrome/browser/autocomplete/autocomplete_popup_model.h"
#include "chrome/browser/instant/instant_confirm_dialog.h"
#include "chrome/browser/instant/promo_counter.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/views/bubble_border.h"
#include "chrome/browser/views/location_bar/location_bar_view.h"
#include "gfx/canvas_skia.h"
@@ -43,6 +43,7 @@
#include <dwmapi.h>
#include "app/win_util.h"
+#include "base/win/scoped_gdi_object.h"
#endif
#if defined(OS_LINUX)
@@ -1123,7 +1124,7 @@ void AutocompletePopupContentsView::UpdateBlurRegion() {
gfx::Path contents_path;
MakeContentsPath(&contents_path, contents_rect);
- ScopedGDIObject<HRGN> popup_region;
+ base::win::ScopedGDIObject<HRGN> popup_region;
popup_region.Set(contents_path.CreateNativeRegion());
bb.hRgnBlur = popup_region.Get();
DwmEnableBlurBehindWindow(GetWidget()->GetNativeView(), &bb);
diff --git a/chrome/browser/ui/views/autofill_profiles_view_win.cc b/chrome/browser/ui/views/autofill_profiles_view_win.cc
index f7c4b1c..9c73a62 100644
--- a/chrome/browser/ui/views/autofill_profiles_view_win.cc
+++ b/chrome/browser/ui/views/autofill_profiles_view_win.cc
@@ -16,14 +16,14 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_manager.h"
#include "chrome/browser/autofill/phone_number.h"
-#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_window.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/views/list_background.h"
-#include "chrome/browser/window_sizer.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/views/list_background.h"
+#include "chrome/browser/ui/window_sizer.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/pref_names.h"
#include "gfx/canvas.h"
diff --git a/chrome/browser/ui/views/bookmark_bar_view.cc b/chrome/browser/ui/views/bookmark_bar_view.cc
index be90191..37e9580 100644
--- a/chrome/browser/ui/views/bookmark_bar_view.cc
+++ b/chrome/browser/ui/views/bookmark_bar_view.cc
@@ -20,11 +20,10 @@
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/browser_shutdown.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/importer/importer_data_types.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/sync/sync_ui_util.h"
@@ -32,11 +31,11 @@
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/view_ids.h"
-#include "chrome/browser/views/bookmark_context_menu.h"
-#include "chrome/browser/views/event_utils.h"
-#include "chrome/browser/views/frame/browser_view.h"
-#include "chrome/browser/views/location_bar/location_bar_view.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/bookmark_context_menu.h"
+#include "chrome/browser/ui/views/event_utils.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/page_transition_types.h"
#include "chrome/common/pref_names.h"
diff --git a/chrome/browser/ui/views/bookmark_bar_view_test.cc b/chrome/browser/ui/views/bookmark_bar_view_test.cc
index fc85e68..d98c20f 100644
--- a/chrome/browser/ui/views/bookmark_bar_view_test.cc
+++ b/chrome/browser/ui/views/bookmark_bar_view_test.cc
@@ -5,11 +5,12 @@
#include "app/keyboard_codes.h"
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/automation/ui_controls.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/page_navigator.h"
#include "chrome/browser/views/bookmark_bar_view.h"
#include "chrome/common/notification_service.h"
@@ -1291,7 +1292,7 @@ class BookmarkBarViewTest15 : public BookmarkBarViewEventTestBase {
ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
views::MenuItemView* delete_menu =
- menu->GetMenuItemByID(IDS_BOOKMARK_BAR_REMOVE);
+ menu->GetMenuItemByID(IDC_BOOKMARK_BAR_REMOVE);
ASSERT_TRUE(delete_menu);
// Click on the delete button.
diff --git a/chrome/browser/ui/views/bookmark_bubble_view.cc b/chrome/browser/ui/views/bookmark_bubble_view.cc
index a1f651b..0fca648 100644
--- a/chrome/browser/ui/views/bookmark_bubble_view.cc
+++ b/chrome/browser/ui/views/bookmark_bubble_view.cc
@@ -14,7 +14,7 @@
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/views/info_bubble.h"
#include "chrome/common/notification_service.h"
#include "gfx/canvas.h"
diff --git a/chrome/browser/ui/views/bookmark_context_menu.cc b/chrome/browser/ui/views/bookmark_context_menu.cc
index cdd778a..bd435ae 100644
--- a/chrome/browser/ui/views/bookmark_context_menu.cc
+++ b/chrome/browser/ui/views/bookmark_context_menu.cc
@@ -6,7 +6,8 @@
#include "app/l10n_util.h"
#include "base/i18n/rtl.h"
-#include "chrome/browser/profile.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/notification_service.h"
#include "grit/generated_resources.h"
#include "views/controls/menu/menu_item_view.h"
@@ -60,7 +61,7 @@ bool BookmarkContextMenu::IsCommandEnabled(int command_id) const {
}
bool BookmarkContextMenu::ShouldCloseAllMenusOnExecute(int id) {
- return id != IDS_BOOKMARK_BAR_REMOVE;
+ return id != IDC_BOOKMARK_BAR_REMOVE;
}
////////////////////////////////////////////////////////////////////////////////
@@ -71,10 +72,6 @@ void BookmarkContextMenu::CloseMenu() {
menu_->Cancel();
}
-void BookmarkContextMenu::AddItem(int command_id) {
- menu_->AppendMenuItemWithLabel(command_id, l10n_util::GetString(command_id));
-}
-
void BookmarkContextMenu::AddItemWithStringId(int command_id, int string_id) {
menu_->AppendMenuItemWithLabel(command_id, l10n_util::GetString(string_id));
}
@@ -83,8 +80,8 @@ void BookmarkContextMenu::AddSeparator() {
menu_->AppendSeparator();
}
-void BookmarkContextMenu::AddCheckboxItem(int command_id) {
- menu_->AppendMenuItem(command_id, l10n_util::GetString(command_id),
+void BookmarkContextMenu::AddCheckboxItem(int command_id, int string_id) {
+ menu_->AppendMenuItem(command_id, l10n_util::GetString(string_id),
views::MenuItemView::CHECKBOX);
}
diff --git a/chrome/browser/ui/views/bookmark_context_menu.h b/chrome/browser/ui/views/bookmark_context_menu.h
index 1c7bf3c..c6cd19d 100644
--- a/chrome/browser/ui/views/bookmark_context_menu.h
+++ b/chrome/browser/ui/views/bookmark_context_menu.h
@@ -51,10 +51,9 @@ class BookmarkContextMenu : public BookmarkContextMenuControllerViewsDelegate,
// Overridden from BookmarkContextMenuControllerViewsDelegate:
virtual void CloseMenu();
- virtual void AddItem(int command_id);
virtual void AddItemWithStringId(int command_id, int string_id);
virtual void AddSeparator();
- virtual void AddCheckboxItem(int command_id);
+ virtual void AddCheckboxItem(int command_id, int string_id);
virtual void WillRemoveBookmarks(
const std::vector<const BookmarkNode*>& bookmarks);
virtual void DidRemoveBookmarks();
diff --git a/chrome/browser/ui/views/bookmark_context_menu_controller_views.cc b/chrome/browser/ui/views/bookmark_context_menu_controller_views.cc
index 1c83a3f..b2f7c29 100644
--- a/chrome/browser/ui/views/bookmark_context_menu_controller_views.cc
+++ b/chrome/browser/ui/views/bookmark_context_menu_controller_views.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/views/bookmark_context_menu_controller_views.h"
#include "base/compiler_specific.h"
+#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/bookmarks/bookmark_editor.h"
#include "chrome/browser/bookmarks/bookmark_folder_editor_controller.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
@@ -12,7 +13,7 @@
#include "chrome/browser/browser_list.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/page_navigator.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/pref_names.h"
@@ -44,56 +45,65 @@ BookmarkContextMenuControllerViews::~BookmarkContextMenuControllerViews() {
void BookmarkContextMenuControllerViews::BuildMenu() {
if (selection_.size() == 1 && selection_[0]->is_url()) {
- delegate_->AddItemWithStringId(IDS_BOOMARK_BAR_OPEN_ALL,
+ delegate_->AddItemWithStringId(IDC_BOOKMARK_BAR_OPEN_ALL,
IDS_BOOMARK_BAR_OPEN_IN_NEW_TAB);
- delegate_->AddItemWithStringId(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW,
+ delegate_->AddItemWithStringId(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW,
IDS_BOOMARK_BAR_OPEN_IN_NEW_WINDOW);
- delegate_->AddItemWithStringId(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO,
+ delegate_->AddItemWithStringId(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO,
IDS_BOOMARK_BAR_OPEN_INCOGNITO);
} else {
- delegate_->AddItem(IDS_BOOMARK_BAR_OPEN_ALL);
- delegate_->AddItem(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW);
- delegate_->AddItem(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO);
+ delegate_->AddItemWithStringId(IDC_BOOKMARK_BAR_OPEN_ALL,
+ IDS_BOOMARK_BAR_OPEN_ALL);
+ delegate_->AddItemWithStringId(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW,
+ IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW);
+ delegate_->AddItemWithStringId(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO,
+ IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO);
}
delegate_->AddSeparator();
if (selection_.size() == 1 && selection_[0]->is_folder()) {
- delegate_->AddItem(IDS_BOOKMARK_BAR_RENAME_FOLDER);
+ delegate_->AddItemWithStringId(IDC_BOOKMARK_BAR_RENAME_FOLDER,
+ IDS_BOOKMARK_BAR_RENAME_FOLDER);
} else {
- delegate_->AddItem(IDS_BOOKMARK_BAR_EDIT);
+ delegate_->AddItemWithStringId(IDC_BOOKMARK_BAR_EDIT,
+ IDS_BOOKMARK_BAR_EDIT);
}
delegate_->AddSeparator();
- delegate_->AddItem(IDS_CUT);
- delegate_->AddItem(IDS_COPY);
- delegate_->AddItem(IDS_PASTE);
+ delegate_->AddItemWithStringId(IDC_CUT, IDS_CUT);
+ delegate_->AddItemWithStringId(IDC_COPY, IDS_COPY);
+ delegate_->AddItemWithStringId(IDC_PASTE, IDS_PASTE);
delegate_->AddSeparator();
- delegate_->AddItem(IDS_BOOKMARK_BAR_REMOVE);
+ delegate_->AddItemWithStringId(IDC_BOOKMARK_BAR_REMOVE,
+ IDS_BOOKMARK_BAR_REMOVE);
delegate_->AddSeparator();
- delegate_->AddItem(IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK);
- delegate_->AddItem(IDS_BOOMARK_BAR_NEW_FOLDER);
+ delegate_->AddItemWithStringId(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK,
+ IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK);
+ delegate_->AddItemWithStringId(IDC_BOOKMARK_BAR_NEW_FOLDER,
+ IDS_BOOMARK_BAR_NEW_FOLDER);
delegate_->AddSeparator();
- delegate_->AddItem(IDS_BOOKMARK_MANAGER);
- delegate_->AddCheckboxItem(IDS_BOOMARK_BAR_ALWAYS_SHOW);
+ delegate_->AddItemWithStringId(IDC_BOOKMARK_MANAGER, IDS_BOOKMARK_MANAGER);
+ delegate_->AddCheckboxItem(IDC_BOOKMARK_BAR_ALWAYS_SHOW,
+ IDS_BOOMARK_BAR_ALWAYS_SHOW);
}
void BookmarkContextMenuControllerViews::ExecuteCommand(int id) {
BookmarkModel* model = RemoveModelObserver();
switch (id) {
- case IDS_BOOMARK_BAR_OPEN_ALL:
- case IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO:
- case IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW: {
+ case IDC_BOOKMARK_BAR_OPEN_ALL:
+ case IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO:
+ case IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW: {
WindowOpenDisposition initial_disposition;
- if (id == IDS_BOOMARK_BAR_OPEN_ALL) {
+ if (id == IDC_BOOKMARK_BAR_OPEN_ALL) {
initial_disposition = NEW_FOREGROUND_TAB;
UserMetrics::RecordAction(
UserMetricsAction("BookmarkBar_ContextMenu_OpenAll"),
profile_);
- } else if (id == IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW) {
+ } else if (id == IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW) {
initial_disposition = NEW_WINDOW;
UserMetrics::RecordAction(
UserMetricsAction("BookmarkBar_ContextMenu_OpenAllInNewWindow"),
@@ -109,8 +119,8 @@ void BookmarkContextMenuControllerViews::ExecuteCommand(int id) {
break;
}
- case IDS_BOOKMARK_BAR_RENAME_FOLDER:
- case IDS_BOOKMARK_BAR_EDIT:
+ case IDC_BOOKMARK_BAR_RENAME_FOLDER:
+ case IDC_BOOKMARK_BAR_EDIT:
UserMetrics::RecordAction(
UserMetricsAction("BookmarkBar_ContextMenu_Edit"), profile_);
@@ -130,7 +140,7 @@ void BookmarkContextMenuControllerViews::ExecuteCommand(int id) {
}
break;
- case IDS_BOOKMARK_BAR_REMOVE: {
+ case IDC_BOOKMARK_BAR_REMOVE: {
UserMetrics::RecordAction(
UserMetricsAction("BookmarkBar_ContextMenu_Remove"), profile_);
@@ -144,7 +154,7 @@ void BookmarkContextMenuControllerViews::ExecuteCommand(int id) {
break;
}
- case IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK: {
+ case IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK: {
UserMetrics::RecordAction(
UserMetricsAction("BookmarkBar_ContextMenu_Add"), profile_);
@@ -156,7 +166,7 @@ void BookmarkContextMenuControllerViews::ExecuteCommand(int id) {
break;
}
- case IDS_BOOMARK_BAR_NEW_FOLDER: {
+ case IDC_BOOKMARK_BAR_NEW_FOLDER: {
UserMetrics::RecordAction(
UserMetricsAction("BookmarkBar_ContextMenu_NewFolder"),
profile_);
@@ -168,11 +178,11 @@ void BookmarkContextMenuControllerViews::ExecuteCommand(int id) {
break;
}
- case IDS_BOOMARK_BAR_ALWAYS_SHOW:
+ case IDC_BOOKMARK_BAR_ALWAYS_SHOW:
bookmark_utils::ToggleWhenVisible(profile_);
break;
- case IDS_BOOKMARK_MANAGER:
+ case IDC_BOOKMARK_MANAGER:
UserMetrics::RecordAction(UserMetricsAction("ShowBookmarkManager"),
profile_);
{
@@ -184,17 +194,17 @@ void BookmarkContextMenuControllerViews::ExecuteCommand(int id) {
}
break;
- case IDS_CUT:
+ case IDC_CUT:
delegate_->WillRemoveBookmarks(selection_);
bookmark_utils::CopyToClipboard(model, selection_, true);
delegate_->DidRemoveBookmarks();
break;
- case IDS_COPY:
+ case IDC_COPY:
bookmark_utils::CopyToClipboard(model, selection_, false);
break;
- case IDS_PASTE: {
+ case IDC_PASTE: {
int index;
const BookmarkNode* paste_target =
bookmark_utils::GetParentForNewNodes(parent_, selection_, &index);
@@ -211,7 +221,7 @@ void BookmarkContextMenuControllerViews::ExecuteCommand(int id) {
}
bool BookmarkContextMenuControllerViews::IsItemChecked(int id) const {
- DCHECK(id == IDS_BOOMARK_BAR_ALWAYS_SHOW);
+ DCHECK(id == IDC_BOOKMARK_BAR_ALWAYS_SHOW);
return profile_->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar);
}
@@ -220,33 +230,33 @@ bool BookmarkContextMenuControllerViews::IsCommandEnabled(int id) const {
(selection_.size() == 1 &&
selection_[0]->GetParent() == model_->root_node());
switch (id) {
- case IDS_BOOMARK_BAR_OPEN_INCOGNITO:
+ case IDC_BOOKMARK_BAR_OPEN_INCOGNITO:
return !profile_->IsOffTheRecord();
- case IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO:
+ case IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO:
return HasURLs() && !profile_->IsOffTheRecord();
- case IDS_BOOMARK_BAR_OPEN_ALL:
- case IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW:
+ case IDC_BOOKMARK_BAR_OPEN_ALL:
+ case IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW:
return HasURLs();
- case IDS_BOOKMARK_BAR_RENAME_FOLDER:
- case IDS_BOOKMARK_BAR_EDIT:
+ case IDC_BOOKMARK_BAR_RENAME_FOLDER:
+ case IDC_BOOKMARK_BAR_EDIT:
return selection_.size() == 1 && !is_root_node;
- case IDS_BOOKMARK_BAR_REMOVE:
+ case IDC_BOOKMARK_BAR_REMOVE:
return !selection_.empty() && !is_root_node;
- case IDS_BOOMARK_BAR_NEW_FOLDER:
- case IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK:
+ case IDC_BOOKMARK_BAR_NEW_FOLDER:
+ case IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK:
return bookmark_utils::GetParentForNewNodes(
parent_, selection_, NULL) != NULL;
- case IDS_COPY:
- case IDS_CUT:
+ case IDC_COPY:
+ case IDC_CUT:
return selection_.size() > 0 && !is_root_node;
- case IDS_PASTE:
+ case IDC_PASTE:
// Paste to selection from the Bookmark Bar, to parent_ everywhere else
return (!selection_.empty() &&
bookmark_utils::CanPasteFromClipboard(selection_[0])) ||
diff --git a/chrome/browser/ui/views/bookmark_context_menu_controller_views.h b/chrome/browser/ui/views/bookmark_context_menu_controller_views.h
index fc3537a..1246a96 100644
--- a/chrome/browser/ui/views/bookmark_context_menu_controller_views.h
+++ b/chrome/browser/ui/views/bookmark_context_menu_controller_views.h
@@ -26,10 +26,9 @@ class BookmarkContextMenuControllerViewsDelegate {
virtual void CloseMenu() = 0;
// Methods that add items to the underlying menu.
- virtual void AddItem(int command_id) = 0;
virtual void AddItemWithStringId(int command_id, int string_id) = 0;
virtual void AddSeparator() = 0;
- virtual void AddCheckboxItem(int command_id) = 0;
+ virtual void AddCheckboxItem(int command_id, int string_id) = 0;
// Sent before bookmarks are removed.
virtual void WillRemoveBookmarks(
diff --git a/chrome/browser/ui/views/bookmark_context_menu_test.cc b/chrome/browser/ui/views/bookmark_context_menu_test.cc
index 8d3f89c..8cf12d4 100644
--- a/chrome/browser/ui/views/bookmark_context_menu_test.cc
+++ b/chrome/browser/ui/views/bookmark_context_menu_test.cc
@@ -4,11 +4,12 @@
#include "base/scoped_ptr.h"
#include "base/utf_string_conversions.h"
+#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/page_navigator.h"
#include "chrome/browser/views/bookmark_context_menu.h"
#include "chrome/common/pref_names.h"
@@ -113,9 +114,9 @@ TEST_F(BookmarkContextMenuTest, DeleteURL) {
BookmarkContextMenu controller(
NULL, profile_.get(), NULL, nodes[0]->GetParent(), nodes);
GURL url = model_->GetBookmarkBarNode()->GetChild(0)->GetURL();
- ASSERT_TRUE(controller.IsCommandEnabled(IDS_BOOKMARK_BAR_REMOVE));
+ ASSERT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
// Delete the URL.
- controller.ExecuteCommand(IDS_BOOKMARK_BAR_REMOVE);
+ controller.ExecuteCommand(IDC_BOOKMARK_BAR_REMOVE);
// Model shouldn't have URL anymore.
ASSERT_FALSE(model_->IsBookmarked(url));
}
@@ -138,15 +139,16 @@ TEST_F(BookmarkContextMenuTest, EmptyNodes) {
BookmarkContextMenu controller(
NULL, profile_.get(), NULL, model_->other_node(),
std::vector<const BookmarkNode*>());
- EXPECT_FALSE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL));
+ EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
EXPECT_FALSE(
- controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW));
- EXPECT_FALSE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO));
- EXPECT_FALSE(controller.IsCommandEnabled(IDS_BOOKMARK_BAR_REMOVE));
+ controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
+ EXPECT_FALSE(
+ controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
+ EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
EXPECT_TRUE(
- controller.IsCommandEnabled(IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK));
+ controller.IsCommandEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
EXPECT_TRUE(
- controller.IsCommandEnabled(IDS_BOOMARK_BAR_NEW_FOLDER));
+ controller.IsCommandEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
}
// Tests the enabled state of the menus when supplied a vector with a single
@@ -156,15 +158,15 @@ TEST_F(BookmarkContextMenuTest, SingleURL) {
nodes.push_back(model_->GetBookmarkBarNode()->GetChild(0));
BookmarkContextMenu controller(
NULL, profile_.get(), NULL, nodes[0]->GetParent(), nodes);
- EXPECT_TRUE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL));
+ EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
EXPECT_TRUE(
- controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW));
- EXPECT_TRUE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO));
- EXPECT_TRUE(controller.IsCommandEnabled(IDS_BOOKMARK_BAR_REMOVE));
+ controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
+ EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
+ EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
EXPECT_TRUE(
- controller.IsCommandEnabled(IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK));
+ controller.IsCommandEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
EXPECT_TRUE(
- controller.IsCommandEnabled(IDS_BOOMARK_BAR_NEW_FOLDER));
+ controller.IsCommandEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
}
// Tests the enabled state of the menus when supplied a vector with multiple
@@ -175,15 +177,15 @@ TEST_F(BookmarkContextMenuTest, MultipleURLs) {
nodes.push_back(model_->GetBookmarkBarNode()->GetChild(1)->GetChild(0));
BookmarkContextMenu controller(
NULL, profile_.get(), NULL, nodes[0]->GetParent(), nodes);
- EXPECT_TRUE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL));
+ EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
EXPECT_TRUE(
- controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW));
- EXPECT_TRUE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO));
- EXPECT_TRUE(controller.IsCommandEnabled(IDS_BOOKMARK_BAR_REMOVE));
+ controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
+ EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
+ EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
EXPECT_TRUE(
- controller.IsCommandEnabled(IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK));
+ controller.IsCommandEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
EXPECT_TRUE(
- controller.IsCommandEnabled(IDS_BOOMARK_BAR_NEW_FOLDER));
+ controller.IsCommandEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
}
// Tests the enabled state of the menus when supplied an vector with a single
@@ -193,15 +195,16 @@ TEST_F(BookmarkContextMenuTest, SingleFolder) {
nodes.push_back(model_->GetBookmarkBarNode()->GetChild(2));
BookmarkContextMenu controller(
NULL, profile_.get(), NULL, nodes[0]->GetParent(), nodes);
- EXPECT_FALSE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL));
+ EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
+ EXPECT_FALSE(
+ controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
EXPECT_FALSE(
- controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW));
- EXPECT_FALSE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO));
- EXPECT_TRUE(controller.IsCommandEnabled(IDS_BOOKMARK_BAR_REMOVE));
+ controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
+ EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
EXPECT_TRUE(
- controller.IsCommandEnabled(IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK));
+ controller.IsCommandEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
EXPECT_TRUE(
- controller.IsCommandEnabled(IDS_BOOMARK_BAR_NEW_FOLDER));
+ controller.IsCommandEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
}
// Tests the enabled state of the menus when supplied a vector with multiple
@@ -212,15 +215,16 @@ TEST_F(BookmarkContextMenuTest, MultipleEmptyFolders) {
nodes.push_back(model_->GetBookmarkBarNode()->GetChild(3));
BookmarkContextMenu controller(
NULL, profile_.get(), NULL, nodes[0]->GetParent(), nodes);
- EXPECT_FALSE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL));
+ EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
+ EXPECT_FALSE(
+ controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
EXPECT_FALSE(
- controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW));
- EXPECT_FALSE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO));
- EXPECT_TRUE(controller.IsCommandEnabled(IDS_BOOKMARK_BAR_REMOVE));
+ controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
+ EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
EXPECT_TRUE(
- controller.IsCommandEnabled(IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK));
+ controller.IsCommandEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
EXPECT_TRUE(
- controller.IsCommandEnabled(IDS_BOOMARK_BAR_NEW_FOLDER));
+ controller.IsCommandEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
}
// Tests the enabled state of the menus when supplied a vector with multiple
@@ -231,15 +235,15 @@ TEST_F(BookmarkContextMenuTest, MultipleFoldersWithURLs) {
nodes.push_back(model_->GetBookmarkBarNode()->GetChild(4));
BookmarkContextMenu controller(
NULL, profile_.get(), NULL, nodes[0]->GetParent(), nodes);
- EXPECT_TRUE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL));
+ EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
EXPECT_TRUE(
- controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW));
- EXPECT_TRUE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO));
- EXPECT_TRUE(controller.IsCommandEnabled(IDS_BOOKMARK_BAR_REMOVE));
+ controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
+ EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
+ EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
EXPECT_TRUE(
- controller.IsCommandEnabled(IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK));
+ controller.IsCommandEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
EXPECT_TRUE(
- controller.IsCommandEnabled(IDS_BOOMARK_BAR_NEW_FOLDER));
+ controller.IsCommandEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
}
// Tests the enabled state of open incognito.
@@ -249,8 +253,9 @@ TEST_F(BookmarkContextMenuTest, DisableIncognito) {
BookmarkContextMenu controller(
NULL, profile_.get(), NULL, nodes[0]->GetParent(), nodes);
profile_->set_off_the_record(true);
- EXPECT_FALSE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_INCOGNITO));
- EXPECT_FALSE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO));
+ EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_INCOGNITO));
+ EXPECT_FALSE(
+ controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
}
// Tests that you can't remove/edit when showing the other node.
@@ -259,8 +264,8 @@ TEST_F(BookmarkContextMenuTest, DisabledItemsWithOtherNode) {
nodes.push_back(model_->other_node());
BookmarkContextMenu controller(
NULL, profile_.get(), NULL, nodes[0], nodes);
- EXPECT_FALSE(controller.IsCommandEnabled(IDS_BOOKMARK_BAR_EDIT));
- EXPECT_FALSE(controller.IsCommandEnabled(IDS_BOOKMARK_BAR_REMOVE));
+ EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_EDIT));
+ EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
}
// Tests the enabled state of the menus when supplied an empty vector and null
@@ -268,15 +273,16 @@ TEST_F(BookmarkContextMenuTest, DisabledItemsWithOtherNode) {
TEST_F(BookmarkContextMenuTest, EmptyNodesNullParent) {
BookmarkContextMenu controller(
NULL, profile_.get(), NULL, NULL, std::vector<const BookmarkNode*>());
- EXPECT_FALSE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL));
+ EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
+ EXPECT_FALSE(
+ controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW));
EXPECT_FALSE(
- controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW));
- EXPECT_FALSE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO));
- EXPECT_FALSE(controller.IsCommandEnabled(IDS_BOOKMARK_BAR_REMOVE));
+ controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
+ EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
EXPECT_FALSE(
- controller.IsCommandEnabled(IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK));
+ controller.IsCommandEnabled(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK));
EXPECT_FALSE(
- controller.IsCommandEnabled(IDS_BOOMARK_BAR_NEW_FOLDER));
+ controller.IsCommandEnabled(IDC_BOOKMARK_BAR_NEW_FOLDER));
}
TEST_F(BookmarkContextMenuTest, CutCopyPasteNode) {
@@ -284,16 +290,16 @@ TEST_F(BookmarkContextMenuTest, CutCopyPasteNode) {
nodes.push_back(model_->GetBookmarkBarNode()->GetChild(0));
scoped_ptr<BookmarkContextMenu> controller(new BookmarkContextMenu(
NULL, profile_.get(), NULL, nodes[0]->GetParent(), nodes));
- EXPECT_TRUE(controller->IsCommandEnabled(IDS_COPY));
- EXPECT_TRUE(controller->IsCommandEnabled(IDS_CUT));
+ EXPECT_TRUE(controller->IsCommandEnabled(IDC_COPY));
+ EXPECT_TRUE(controller->IsCommandEnabled(IDC_CUT));
// Copy the URL.
- controller->ExecuteCommand(IDS_COPY);
+ controller->ExecuteCommand(IDC_COPY);
controller.reset(new BookmarkContextMenu(
NULL, profile_.get(), NULL, nodes[0]->GetParent(), nodes));
int old_count = model_->GetBookmarkBarNode()->GetChildCount();
- controller->ExecuteCommand(IDS_PASTE);
+ controller->ExecuteCommand(IDC_PASTE);
ASSERT_TRUE(model_->GetBookmarkBarNode()->GetChild(1)->is_url());
ASSERT_EQ(old_count + 1, model_->GetBookmarkBarNode()->GetChildCount());
@@ -303,7 +309,7 @@ TEST_F(BookmarkContextMenuTest, CutCopyPasteNode) {
controller.reset(new BookmarkContextMenu(
NULL, profile_.get(), NULL, nodes[0]->GetParent(), nodes));
// Cut the URL.
- controller->ExecuteCommand(IDS_CUT);
+ controller->ExecuteCommand(IDC_CUT);
ASSERT_TRUE(model_->GetBookmarkBarNode()->GetChild(0)->is_url());
ASSERT_TRUE(model_->GetBookmarkBarNode()->GetChild(1)->is_folder());
ASSERT_EQ(old_count, model_->GetBookmarkBarNode()->GetChildCount());
diff --git a/chrome/browser/ui/views/bookmark_editor_view.cc b/chrome/browser/ui/views/bookmark_editor_view.cc
index 895dc59..a64d42e 100644
--- a/chrome/browser/ui/views/bookmark_editor_view.cc
+++ b/chrome/browser/ui/views/bookmark_editor_view.cc
@@ -13,7 +13,7 @@
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/common/pref_names.h"
#include "googleurl/src/gurl.h"
diff --git a/chrome/browser/ui/views/bookmark_editor_view_unittest.cc b/chrome/browser/ui/views/bookmark_editor_view_unittest.cc
index afeeb4e..b2d9dea 100644
--- a/chrome/browser/ui/views/bookmark_editor_view_unittest.cc
+++ b/chrome/browser/ui/views/bookmark_editor_view_unittest.cc
@@ -8,7 +8,7 @@
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/views/bookmark_editor_view.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_profile.h"
diff --git a/chrome/browser/ui/views/bookmark_menu_controller_views.cc b/chrome/browser/ui/views/bookmark_menu_controller_views.cc
index de89264..8829dac 100644
--- a/chrome/browser/ui/views/bookmark_menu_controller_views.cc
+++ b/chrome/browser/ui/views/bookmark_menu_controller_views.cc
@@ -12,7 +12,7 @@
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/metrics/user_metrics.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/page_navigator.h"
#include "chrome/browser/views/bookmark_bar_view.h"
#include "chrome/browser/views/event_utils.h"
diff --git a/chrome/browser/ui/views/browser_actions_container.cc b/chrome/browser/ui/views/browser_actions_container.cc
index ce7bb4b..1f6f61c 100644
--- a/chrome/browser/ui/views/browser_actions_container.cc
+++ b/chrome/browser/ui/views/browser_actions_container.cc
@@ -14,18 +14,18 @@
#include "chrome/browser/extensions/extension_browser_event_router.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/view_ids.h"
-#include "chrome/browser/views/detachable_toolbar_view.h"
-#include "chrome/browser/views/extensions/browser_action_drag_data.h"
-#include "chrome/browser/views/extensions/extension_popup.h"
-#include "chrome/browser/views/toolbar_view.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/detachable_toolbar_view.h"
+#include "chrome/browser/ui/views/extensions/browser_action_drag_data.h"
+#include "chrome/browser/ui/views/extensions/extension_popup.h"
+#include "chrome/browser/ui/views/toolbar_view.h"
#include "chrome/common/extensions/extension_action.h"
#include "chrome/common/extensions/extension_resource.h"
#include "chrome/common/notification_source.h"
@@ -361,8 +361,8 @@ BrowserActionsContainer::BrowserActionsContainer(Browser* browser,
ALLOW_THIS_IN_INITIALIZER_LIST(show_menu_task_factory_(this)) {
SetID(VIEW_ID_BROWSER_ACTION_TOOLBAR);
- if (profile_->GetExtensionsService()) {
- model_ = profile_->GetExtensionsService()->toolbar_model();
+ if (profile_->GetExtensionService()) {
+ model_ = profile_->GetExtensionService()->toolbar_model();
model_->AddObserver(this);
}
@@ -836,7 +836,7 @@ void BrowserActionsContainer::ExtensionPopupIsClosing(ExtensionPopup* popup) {
void BrowserActionsContainer::MoveBrowserAction(const std::string& extension_id,
size_t new_index) {
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
if (service) {
const Extension* extension = service->GetExtensionById(extension_id, false);
model_->MoveBrowserAction(extension, new_index);
@@ -916,7 +916,7 @@ void BrowserActionsContainer::BrowserActionAdded(const Extension* extension,
// Enlarge the container if it was already at maximum size and we're not in
// the middle of upgrading.
if ((model_->GetVisibleIconCount() < 0) &&
- !profile_->GetExtensionsService()->IsBeingUpgraded(extension)) {
+ !profile_->GetExtensionService()->IsBeingUpgraded(extension)) {
suppress_chevron_ = true;
SaveDesiredSizeAndAnimate(Tween::LINEAR, visible_actions + 1);
} else {
@@ -941,7 +941,7 @@ void BrowserActionsContainer::BrowserActionRemoved(const Extension* extension) {
// If the extension is being upgraded we don't want the bar to shrink
// because the icon is just going to get re-added to the same location.
- if (profile_->GetExtensionsService()->IsBeingUpgraded(extension))
+ if (profile_->GetExtensionService()->IsBeingUpgraded(extension))
return;
if (browser_action_views_.size() > visible_actions) {
@@ -1096,5 +1096,5 @@ bool BrowserActionsContainer::ShouldDisplayBrowserAction(
const Extension* extension) {
// Only display incognito-enabled extensions while in incognito mode.
return (!profile_->IsOffTheRecord() ||
- profile_->GetExtensionsService()->IsIncognitoEnabled(extension));
+ profile_->GetExtensionService()->IsIncognitoEnabled(extension));
}
diff --git a/chrome/browser/ui/views/browser_actions_container_browsertest.cc b/chrome/browser/ui/views/browser_actions_container_browsertest.cc
index 79f3c99..8751881 100644
--- a/chrome/browser/ui/views/browser_actions_container_browsertest.cc
+++ b/chrome/browser/ui/views/browser_actions_container_browsertest.cc
@@ -4,8 +4,8 @@
#include "chrome/browser/extensions/browser_action_test_util.h"
#include "chrome/browser/extensions/extension_browsertest.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/views/browser_actions_container.h"
#include "chrome/common/chrome_switches.h"
@@ -229,7 +229,7 @@ IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, ForceHide) {
std::string idA = browser_actions_bar()->GetExtensionId(0);
// Force hide this browser action.
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
service->SetBrowserActionVisibility(service->GetExtensionById(idA, false),
false);
EXPECT_EQ(0, browser_actions_bar()->VisibleBrowserActions());
@@ -243,7 +243,7 @@ IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, ForceHide) {
IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, TestCrash57536) {
LOG(INFO) << "Test starting\n" << std::flush;
- ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ ExtensionService* service = browser()->profile()->GetExtensionService();
const size_t size_before = service->extensions()->size();
LOG(INFO) << "Loading extension\n" << std::flush;
diff --git a/chrome/browser/ui/views/browser_bubble_gtk.cc b/chrome/browser/ui/views/browser_bubble_gtk.cc
index 7f18070..631aff7 100644
--- a/chrome/browser/ui/views/browser_bubble_gtk.cc
+++ b/chrome/browser/ui/views/browser_bubble_gtk.cc
@@ -4,15 +4,19 @@
#include "chrome/browser/views/browser_bubble.h"
+#include <vector>
+
#include "chrome/browser/views/frame/browser_view.h"
#include "views/widget/widget_gtk.h"
#include "views/window/window.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/wm_ipc.h"
-#include "cros/chromeos_wm_ipc_enums.h"
+#include "third_party/cros/chromeos_wm_ipc_enums.h"
#endif
+using std::vector;
+
namespace {
class BubbleWidget : public views::WidgetGtk {
@@ -88,10 +92,14 @@ void BrowserBubble::InitPopup() {
pop->make_transient_to_parent();
pop->Init(frame_->GetNativeView(), bounds_);
#if defined(OS_CHROMEOS)
- chromeos::WmIpc::instance()->SetWindowType(
- pop->GetNativeView(),
- chromeos::WM_IPC_WINDOW_CHROME_INFO_BUBBLE,
- NULL);
+ {
+ vector<int> params;
+ params.push_back(0); // don't show while screen is locked
+ chromeos::WmIpc::instance()->SetWindowType(
+ pop->GetNativeView(),
+ chromeos::WM_IPC_WINDOW_CHROME_INFO_BUBBLE,
+ &params);
+ }
#endif
pop->SetContentsView(view_);
popup_ = pop;
diff --git a/chrome/browser/ui/views/chrome_views_delegate.cc b/chrome/browser/ui/views/chrome_views_delegate.cc
index d872ace..7ed8ef7 100644
--- a/chrome/browser/ui/views/chrome_views_delegate.cc
+++ b/chrome/browser/ui/views/chrome_views_delegate.cc
@@ -9,8 +9,8 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/views/accessibility_event_router_views.h"
-#include "chrome/browser/window_sizer.h"
+#include "chrome/browser/ui/views/accessibility_event_router_views.h"
+#include "chrome/browser/ui/window_sizer.h"
#include "gfx/rect.h"
#if defined(OS_WIN)
diff --git a/chrome/browser/ui/views/clear_browsing_data.cc b/chrome/browser/ui/views/clear_browsing_data.cc
index 1a4021a..0f9a331 100644
--- a/chrome/browser/ui/views/clear_browsing_data.cc
+++ b/chrome/browser/ui/views/clear_browsing_data.cc
@@ -9,7 +9,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/ui/browser.h"
#if defined(OS_WIN)
@@ -43,13 +43,9 @@ namespace browser {
// Defined in browser_dialogs.h for creation of the view.
void ShowClearBrowsingDataView(gfx::NativeWindow parent,
Profile* profile) {
-#if defined(OS_WIN)
- views::Window::CreateChromeWindow(parent, gfx::Rect(),
- new ClearDataView(profile))->Show();
-#else
+
views::Window::CreateChromeWindow(parent, gfx::Rect(),
new ClearBrowsingDataView(profile))->Show();
-#endif
}
} // namespace browser
diff --git a/chrome/browser/ui/views/clear_browsing_data_view.cc b/chrome/browser/ui/views/clear_browsing_data_view.cc
index c03a477..1aec286 100644
--- a/chrome/browser/ui/views/clear_browsing_data_view.cc
+++ b/chrome/browser/ui/views/clear_browsing_data_view.cc
@@ -9,7 +9,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/pref_names.h"
diff --git a/chrome/browser/ui/views/clear_data_view.cc b/chrome/browser/ui/views/clear_data_view.cc
index d759f71..9703277 100644
--- a/chrome/browser/ui/views/clear_data_view.cc
+++ b/chrome/browser/ui/views/clear_data_view.cc
@@ -9,7 +9,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/views/clear_browsing_data.h"
diff --git a/chrome/browser/ui/views/clear_server_data.cc b/chrome/browser/ui/views/clear_server_data.cc
index 7a253c8..da2ac87 100644
--- a/chrome/browser/ui/views/clear_server_data.cc
+++ b/chrome/browser/ui/views/clear_server_data.cc
@@ -11,7 +11,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/ui/browser.h"
diff --git a/chrome/browser/ui/views/collected_cookies_win.cc b/chrome/browser/ui/views/collected_cookies_win.cc
index 3f25992..308c0c4 100644
--- a/chrome/browser/ui/views/collected_cookies_win.cc
+++ b/chrome/browser/ui/views/collected_cookies_win.cc
@@ -7,9 +7,10 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "chrome/browser/cookies_tree_model.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
#include "gfx/color_utils.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
@@ -33,7 +34,7 @@ void ShowCollectedCookiesDialog(gfx::NativeWindow parent_window,
new CollectedCookiesWin(parent_window, tab_contents);
}
-} // namespace browser
+} // namespace browser
namespace {
// Spacing between the infobar frame and its contents.
@@ -47,7 +48,7 @@ const int kInfobarBorderSize = 1;
const int kTreeViewWidth = 400;
const int kTreeViewHeight = 125;
-} // namespace
+} // namespace
// A custom view that conditionally displays an infobar.
class InfobarView : public views::View {
diff --git a/chrome/browser/ui/views/constrained_html_delegate_gtk.cc b/chrome/browser/ui/views/constrained_html_delegate_gtk.cc
index 7680fd8..60f3ec4 100644
--- a/chrome/browser/ui/views/constrained_html_delegate_gtk.cc
+++ b/chrome/browser/ui/views/constrained_html_delegate_gtk.cc
@@ -8,7 +8,7 @@
#include "chrome/browser/dom_ui/html_dialog_ui.h"
#include "chrome/browser/gtk/constrained_window_gtk.h"
#include "chrome/browser/gtk/gtk_util.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/views/tab_contents/tab_contents_container.h"
#include "gfx/rect.h"
diff --git a/chrome/browser/ui/views/constrained_html_delegate_win.cc b/chrome/browser/ui/views/constrained_html_delegate_win.cc
index 6d53e22..34d638e 100644
--- a/chrome/browser/ui/views/constrained_html_delegate_win.cc
+++ b/chrome/browser/ui/views/constrained_html_delegate_win.cc
@@ -6,7 +6,7 @@
#include "chrome/browser/dom_ui/html_dialog_tab_contents_delegate.h"
#include "chrome/browser/dom_ui/html_dialog_ui.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/views/tab_contents/tab_contents_container.h"
#include "gfx/rect.h"
diff --git a/chrome/browser/ui/views/constrained_window_win.cc b/chrome/browser/ui/views/constrained_window_win.cc
index 7fa1dc6..b042f5b 100644
--- a/chrome/browser/ui/views/constrained_window_win.cc
+++ b/chrome/browser/ui/views/constrained_window_win.cc
@@ -7,14 +7,13 @@
#include "app/resource_bundle.h"
#include "app/win_util.h"
#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
-#include "chrome/browser/toolbar_model.h"
-#include "chrome/browser/views/frame/browser_view.h"
-#include "chrome/browser/window_sizer.h"
+#include "chrome/browser/ui/toolbar/toolbar_model.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/window_sizer.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
diff --git a/chrome/browser/ui/views/content_setting_bubble_contents.cc b/chrome/browser/ui/views/content_setting_bubble_contents.cc
index 40a2acc..27104a2 100644
--- a/chrome/browser/ui/views/content_setting_bubble_contents.cc
+++ b/chrome/browser/ui/views/content_setting_bubble_contents.cc
@@ -11,10 +11,10 @@
#include "app/l10n_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/blocked_content_container.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/content_setting_bubble_model.h"
-#include "chrome/browser/host_content_settings_map.h"
#include "chrome/browser/plugin_updater.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/views/browser_dialogs.h"
#include "chrome/browser/views/info_bubble.h"
@@ -115,11 +115,9 @@ ContentSettingBubbleContents::ContentSettingBubbleContents(
profile_(profile),
tab_contents_(tab_contents),
info_bubble_(NULL),
- close_button_(NULL),
+ custom_link_(NULL),
manage_link_(NULL),
- clear_link_(NULL),
- info_link_(NULL),
- load_plugins_link_(NULL) {
+ close_button_(NULL) {
registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
Source<TabContents>(tab_contents));
}
@@ -164,29 +162,17 @@ void ContentSettingBubbleContents::ButtonPressed(views::Button* sender,
void ContentSettingBubbleContents::LinkActivated(views::Link* source,
int event_flags) {
- if (source == manage_link_) {
- info_bubble_->set_fade_away_on_close(true);
- content_setting_bubble_model_->OnManageLinkClicked();
- // CAREFUL: Showing the settings window activates it, which deactivates the
- // info bubble, which causes it to close, which deletes us.
- return;
- }
- if (source == clear_link_) {
- content_setting_bubble_model_->OnClearLinkClicked();
- info_bubble_->set_fade_away_on_close(true);
- info_bubble_->Close(); // CAREFUL: This deletes us.
- return;
- }
- if (source == info_link_) {
- content_setting_bubble_model_->OnInfoLinkClicked();
+ if (source == custom_link_) {
+ content_setting_bubble_model_->OnCustomLinkClicked();
info_bubble_->set_fade_away_on_close(true);
info_bubble_->Close(); // CAREFUL: This deletes us.
return;
}
- if (source == load_plugins_link_) {
- content_setting_bubble_model_->OnLoadPluginsLinkClicked();
+ if (source == manage_link_) {
info_bubble_->set_fade_away_on_close(true);
- info_bubble_->Close(); // CAREFUL: This deletes us.
+ content_setting_bubble_model_->OnManageLinkClicked();
+ // CAREFUL: Showing the settings window activates it, which deactivates the
+ // info bubble, which causes it to close, which deletes us.
return;
}
@@ -216,30 +202,30 @@ void ContentSettingBubbleContents::InitControlLayout() {
const ContentSettingBubbleModel::BubbleContent& bubble_content =
content_setting_bubble_model_->bubble_content();
+ bool bubble_content_empty = true;
if (!bubble_content.title.empty()) {
views::Label* title_label = new views::Label(UTF8ToWide(
bubble_content.title));
layout->StartRow(0, single_column_set_id);
layout->AddView(title_label);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
+ bubble_content_empty = false;
}
const std::set<std::string>& plugins = bubble_content.resource_identifiers;
if (!plugins.empty()) {
+ if (!bubble_content_empty)
+ layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
for (std::set<std::string>::const_iterator it = plugins.begin();
it != plugins.end(); ++it) {
- std::wstring name;
- NPAPI::PluginList::PluginMap groups;
- NPAPI::PluginList::Singleton()->GetPluginGroups(false, &groups);
- if (groups.find(*it) != groups.end())
- name = UTF16ToWide(groups[*it]->GetGroupName());
- else
+ std::wstring name = UTF16ToWide(
+ NPAPI::PluginList::Singleton()->GetPluginGroupName(*it));
+ if (name.empty())
name = UTF8ToWide(*it);
layout->StartRow(0, single_column_set_id);
layout->AddView(new views::Label(name));
+ bubble_content_empty = false;
}
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
}
if (content_setting_bubble_model_->content_type() ==
@@ -256,7 +242,7 @@ void ContentSettingBubbleContents::InitControlLayout() {
for (std::vector<ContentSettingBubbleModel::PopupItem>::const_iterator
i(bubble_content.popup_items.begin());
i != bubble_content.popup_items.end(); ++i) {
- if (i != bubble_content.popup_items.begin())
+ if (!bubble_content_empty)
layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
layout->StartRow(0, popup_column_set_id);
@@ -266,32 +252,26 @@ void ContentSettingBubbleContents::InitControlLayout() {
popup_links_[link] = i - bubble_content.popup_items.begin();
layout->AddView(new Favicon((*i).bitmap, this, link));
layout->AddView(link);
+ bubble_content_empty = false;
}
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
-
- views::Separator* separator = new views::Separator;
- layout->StartRow(0, single_column_set_id);
- layout->AddView(separator);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
}
const ContentSettingBubbleModel::RadioGroup& radio_group =
bubble_content.radio_group;
- for (ContentSettingBubbleModel::RadioItems::const_iterator i =
- radio_group.radio_items.begin();
- i != radio_group.radio_items.end(); ++i) {
- views::RadioButton* radio = new views::RadioButton(UTF8ToWide(*i), 0);
- radio->set_listener(this);
- radio_group_.push_back(radio);
- layout->StartRow(0, single_column_set_id);
- layout->AddView(radio);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
- }
- if (!radio_group_.empty()) {
- views::Separator* separator = new views::Separator;
- layout->StartRow(0, single_column_set_id);
- layout->AddView(separator, 1, 1, GridLayout::FILL, GridLayout::FILL);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
+ if (!radio_group.radio_items.empty()) {
+ for (ContentSettingBubbleModel::RadioItems::const_iterator i =
+ radio_group.radio_items.begin();
+ i != radio_group.radio_items.end(); ++i) {
+ views::RadioButton* radio = new views::RadioButton(UTF8ToWide(*i), 0);
+ radio->set_listener(this);
+ radio_group_.push_back(radio);
+ if (!bubble_content_empty)
+ layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
+ layout->StartRow(0, single_column_set_id);
+ layout->AddView(radio);
+ bubble_content_empty = false;
+ }
+ DCHECK(!radio_group_.empty());
// Now that the buttons have been added to the view hierarchy, it's safe
// to call SetChecked() on them.
radio_group_[radio_group.default_item]->SetChecked(true);
@@ -319,43 +299,21 @@ void ContentSettingBubbleContents::InitControlLayout() {
layout->StartRow(0, indented_single_column_set_id);
layout->AddView(new views::Label(UTF8ToWide(*j), domain_font));
}
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
- }
-
- if (!bubble_content.clear_link.empty()) {
- clear_link_ = new views::Link(UTF8ToWide(bubble_content.clear_link));
- clear_link_->SetController(this);
- layout->StartRow(0, single_column_set_id);
- layout->AddView(clear_link_);
-
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
- layout->StartRow(0, single_column_set_id);
- layout->AddView(new views::Separator, 1, 1,
- GridLayout::FILL, GridLayout::FILL);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
+ bubble_content_empty = false;
}
- if (!bubble_content.info_link.empty()) {
- info_link_ = new views::Link(UTF8ToWide(bubble_content.info_link));
- info_link_->SetController(this);
- layout->StartRow(0, single_column_set_id);
- layout->AddView(info_link_);
-
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
+ if (!bubble_content.custom_link.empty()) {
+ custom_link_ = new views::Link(UTF8ToWide(bubble_content.custom_link));
+ custom_link_->SetEnabled(bubble_content.custom_link_enabled);
+ custom_link_->SetController(this);
+ if (!bubble_content_empty)
+ layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
layout->StartRow(0, single_column_set_id);
- layout->AddView(new views::Separator, 1, 1,
- GridLayout::FILL, GridLayout::FILL);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
+ layout->AddView(custom_link_);
+ bubble_content_empty = false;
}
- if (!bubble_content.load_plugins_link_title.empty()) {
- load_plugins_link_ = new views::Link(
- UTF8ToWide(bubble_content.load_plugins_link_title));
- load_plugins_link_->SetEnabled(bubble_content.load_plugins_link_enabled);
- load_plugins_link_->SetController(this);
- layout->StartRow(0, single_column_set_id);
- layout->AddView(load_plugins_link_);
-
+ if (!bubble_content_empty) {
layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
layout->StartRow(0, single_column_set_id);
layout->AddView(new views::Separator, 1, 1,
diff --git a/chrome/browser/ui/views/content_setting_bubble_contents.h b/chrome/browser/ui/views/content_setting_bubble_contents.h
index 25723a4..45e0635 100644
--- a/chrome/browser/ui/views/content_setting_bubble_contents.h
+++ b/chrome/browser/ui/views/content_setting_bubble_contents.h
@@ -92,11 +92,9 @@ class ContentSettingBubbleContents : public views::View,
PopupLinks popup_links_;
typedef std::vector<views::RadioButton*> RadioGroup;
RadioGroup radio_group_;
- views::NativeButton* close_button_;
+ views::Link* custom_link_;
views::Link* manage_link_;
- views::Link* clear_link_;
- views::Link* info_link_;
- views::Link* load_plugins_link_;
+ views::NativeButton* close_button_;
DISALLOW_IMPLICIT_CONSTRUCTORS(ContentSettingBubbleContents);
};
diff --git a/chrome/browser/ui/views/cookie_info_view.cc b/chrome/browser/ui/views/cookie_info_view.cc
index f2a1bb1..7fe0d54 100644
--- a/chrome/browser/ui/views/cookie_info_view.cc
+++ b/chrome/browser/ui/views/cookie_info_view.cc
@@ -13,7 +13,6 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/cookies_tree_model.h"
-#include "chrome/browser/profile.h"
#include "gfx/canvas.h"
#include "gfx/color_utils.h"
#include "grit/generated_resources.h"
@@ -275,4 +274,3 @@ void CookieInfoView::Init() {
expires_value_field_->SetBackgroundColor(text_area_background);
}
}
-
diff --git a/chrome/browser/ui/views/create_application_shortcut_view.cc b/chrome/browser/ui/views/create_application_shortcut_view.cc
index 2867c9a..4532222 100644
--- a/chrome/browser/ui/views/create_application_shortcut_view.cc
+++ b/chrome/browser/ui/views/create_application_shortcut_view.cc
@@ -10,7 +10,7 @@
#include "base/utf_string_conversions.h"
#include "base/win/windows_version.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
#include "chrome/common/chrome_constants.h"
diff --git a/chrome/browser/ui/views/default_search_view.cc b/chrome/browser/ui/views/default_search_view.cc
index d57ffc4..34dcbf1 100644
--- a/chrome/browser/ui/views/default_search_view.cc
+++ b/chrome/browser/ui/views/default_search_view.cc
@@ -10,7 +10,7 @@
#include "app/message_box_flags.h"
#include "app/resource_bundle.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/search_engines/template_url_prepopulate_data.h"
diff --git a/chrome/browser/ui/views/dialog_stubs_gtk.cc b/chrome/browser/ui/views/dialog_stubs_gtk.cc
index a8e4535..de6c676 100644
--- a/chrome/browser/ui/views/dialog_stubs_gtk.cc
+++ b/chrome/browser/ui/views/dialog_stubs_gtk.cc
@@ -18,9 +18,9 @@
#include "chrome/browser/gtk/options/passwords_exceptions_window_gtk.h"
#include "chrome/browser/gtk/repost_form_warning_gtk.h"
#include "chrome/browser/gtk/task_manager_gtk.h"
-#include "chrome/browser/options_window.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/views/browser_dialogs.h"
+#include "chrome/browser/ui/options/options_window.h"
+#include "chrome/browser/ui/views/browser_dialogs.h"
#include "views/widget/widget.h"
namespace browser {
diff --git a/chrome/browser/ui/views/dom_view.cc b/chrome/browser/ui/views/dom_view.cc
index a4cc19a..cc442d3 100644
--- a/chrome/browser/ui/views/dom_view.cc
+++ b/chrome/browser/ui/views/dom_view.cc
@@ -8,6 +8,10 @@
#include "ipc/ipc_message.h"
#include "views/focus/focus_manager.h"
+#if defined(TOUCH_UI)
+#include "chrome/browser/ui/views/tab_contents/tab_contents_view_views.h"
+#endif
+
DOMView::DOMView() : tab_contents_(NULL), initialized_(false) {
SetFocusable(true);
}
@@ -25,7 +29,7 @@ bool DOMView::Init(Profile* profile, SiteInstance* instance) {
tab_contents_.reset(CreateTabContents(profile, instance));
// Attach the native_view now if the view is already added to Widget.
if (GetWidget())
- Attach(tab_contents_->GetNativeView());
+ AttachTabContents();
return true;
}
@@ -56,7 +60,15 @@ void DOMView::ViewHierarchyChanged(bool is_add, views::View* parent,
// the native view has not been attached yet and tab_contents_ exists.
views::NativeViewHost::ViewHierarchyChanged(is_add, parent, child);
if (is_add && GetWidget() && !native_view() && tab_contents_.get())
- Attach(tab_contents_->GetNativeView());
+ AttachTabContents();
else if (!is_add && child == this && native_view())
Detach();
}
+
+void DOMView::AttachTabContents() {
+#if defined(TOUCH_UI)
+ AttachToView(static_cast<TabContentsViewViews*>(tab_contents_->view()));
+#else
+ Attach(tab_contents_->GetNativeView());
+#endif
+}
diff --git a/chrome/browser/ui/views/dom_view.h b/chrome/browser/ui/views/dom_view.h
index 27d9434..7a95d30 100644
--- a/chrome/browser/ui/views/dom_view.h
+++ b/chrome/browser/ui/views/dom_view.h
@@ -43,6 +43,11 @@ class DOMView : public views::NativeViewHost {
virtual void ViewHierarchyChanged(bool is_add, views::View* parent,
views::View* child);
+ // AttachTabContents calls Attach to hook up the NativeViewHost. This is
+ // here because depending on whether this is a touch build or not the
+ // implementation varies slightly, while Detach is the same in both cases.
+ void AttachTabContents();
+
// Returns new allocated TabContents instance, caller is responsible deleting.
// Override in derived classes to replace TabContents with derivative.
virtual TabContents* CreateTabContents(Profile* profile,
diff --git a/chrome/browser/ui/views/download_item_view.cc b/chrome/browser/ui/views/download_item_view.cc
index 1c1e101..f6d022d 100644
--- a/chrome/browser/ui/views/download_item_view.cc
+++ b/chrome/browser/ui/views/download_item_view.cc
@@ -278,14 +278,16 @@ DownloadItemView::DownloadItemView(DownloadItem* download,
// Elide giant extensions (this shouldn't currently be hit, but might
// in future, should we ever notice unsafe giant extensions).
if (extension.length() > kFileNameMaxLength / 2)
- ElideString(extension, kFileNameMaxLength / 2, &extension);
+ gfx::ElideString(extension, kFileNameMaxLength / 2, &extension);
// The dangerous download label text is different for an extension file.
if (download->is_extension_install()) {
dangerous_download_label_ = new views::Label(
l10n_util::GetString(IDS_PROMPT_DANGEROUS_DOWNLOAD_EXTENSION));
} else {
- ElideString(rootname, kFileNameMaxLength - extension.length(), &rootname);
+ gfx::ElideString(rootname,
+ kFileNameMaxLength - extension.length(),
+ &rootname);
std::wstring filename = rootname + L"." + extension;
filename = UTF16ToWide(base::i18n::GetDisplayStringInLTRDirectionality(
WideToUTF16(filename)));
diff --git a/chrome/browser/ui/views/download_shelf_view.cc b/chrome/browser/ui/views/download_shelf_view.cc
index 7ad21cc..5db8ba1 100644
--- a/chrome/browser/ui/views/download_shelf_view.cc
+++ b/chrome/browser/ui/views/download_shelf_view.cc
@@ -16,9 +16,9 @@
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/view_ids.h"
-#include "chrome/browser/views/download_item_view.h"
-#include "chrome/browser/views/frame/browser_view.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/download_item_view.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
#include "gfx/canvas.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
diff --git a/chrome/browser/ui/views/download_started_animation_win.cc b/chrome/browser/ui/views/download_started_animation_win.cc
index e142b14..2398993 100644
--- a/chrome/browser/ui/views/download_started_animation_win.cc
+++ b/chrome/browser/ui/views/download_started_animation_win.cc
@@ -7,8 +7,9 @@
#include "app/linear_animation.h"
#include "app/resource_bundle.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/notification_details.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
#include "gfx/rect.h"
#include "grit/theme_resources.h"
#include "views/controls/image_view.h"
diff --git a/chrome/browser/ui/views/dropdown_bar_host.cc b/chrome/browser/ui/views/dropdown_bar_host.cc
index 6b6162a..f3367d2 100644
--- a/chrome/browser/ui/views/dropdown_bar_host.cc
+++ b/chrome/browser/ui/views/dropdown_bar_host.cc
@@ -7,13 +7,10 @@
#include "app/keyboard_codes.h"
#include "app/slide_animation.h"
#include "base/scoped_handle.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/view_ids.h"
-#include "chrome/browser/views/dropdown_bar_view.h"
-#include "chrome/browser/views/frame/browser_view.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/dropdown_bar_view.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
#include "gfx/path.h"
#include "gfx/scrollbar_size.h"
#include "views/focus/external_focus_tracker.h"
diff --git a/chrome/browser/ui/views/dropdown_bar_host.h b/chrome/browser/ui/views/dropdown_bar_host.h
index f971ed0..71b0bf3 100644
--- a/chrome/browser/ui/views/dropdown_bar_host.h
+++ b/chrome/browser/ui/views/dropdown_bar_host.h
@@ -139,7 +139,7 @@ class DropdownBarHost : public views::AcceleratorTarget,
// Allows implementation to tweak widget position.
void SetWidgetPositionNative(const gfx::Rect& new_pos, bool no_redraw);
- // Returns a keyboard event suitable for fowarding.
+ // Returns a keyboard event suitable for forwarding.
NativeWebKeyboardEvent GetKeyboardEvent(
const TabContents* contents,
const views::Textfield::Keystroke& key_stroke);
@@ -178,7 +178,7 @@ class DropdownBarHost : public views::AcceleratorTarget,
// dropdown bar. It contains the DropdownBarView.
scoped_ptr<views::Widget> host_;
- // A flag to manually manage visibility. GTK/X11 is asynchrnous and
+ // A flag to manually manage visibility. GTK/X11 is asynchronous and
// the state of the widget can be out of sync.
bool is_visible_;
diff --git a/chrome/browser/ui/views/dropdown_bar_host_gtk.cc b/chrome/browser/ui/views/dropdown_bar_host_gtk.cc
index 2a4e4be..b321c30 100644
--- a/chrome/browser/ui/views/dropdown_bar_host_gtk.cc
+++ b/chrome/browser/ui/views/dropdown_bar_host_gtk.cc
@@ -11,6 +11,10 @@
#include "views/widget/widget_gtk.h"
#include "views/controls/textfield/textfield.h"
+#if defined(TOUCH_UI)
+#include "app/keyboard_code_conversion_gtk.h"
+#endif
+
views::Widget* DropdownBarHost::CreateHost() {
views::WidgetGtk* host = new views::WidgetGtk(views::WidgetGtk::TYPE_CHILD);
// We own the host.
@@ -27,5 +31,22 @@ void DropdownBarHost::SetWidgetPositionNative(const gfx::Rect& new_pos,
NativeWebKeyboardEvent DropdownBarHost::GetKeyboardEvent(
const TabContents* contents,
const views::Textfield::Keystroke& key_stroke) {
+#if defined(TOUCH_UI)
+ // TODO(oshima): This is a copy from
+ // RenderWidgetHostViewViews::OnKeyPressed().
+ // Refactor and eliminate the dup code.
+ const views::KeyEvent& e = key_stroke.key_event();
+ NativeWebKeyboardEvent wke;
+ wke.type = WebKit::WebInputEvent::KeyDown;
+ wke.windowsKeyCode = e.GetKeyCode();
+ wke.setKeyIdentifierFromWindowsKeyCode();
+
+ wke.text[0] = wke.unmodifiedText[0] =
+ static_cast<unsigned short>(gdk_keyval_to_unicode(
+ app::GdkKeyCodeForWindowsKeyCode(e.GetKeyCode(),
+ e.IsShiftDown() ^ e.IsCapsLockDown())));
+ return wke;
+#else
return NativeWebKeyboardEvent(key_stroke.event());
+#endif
}
diff --git a/chrome/browser/ui/views/dropdown_bar_host_win.cc b/chrome/browser/ui/views/dropdown_bar_host_win.cc
index c14fb21..e3d27c8 100644
--- a/chrome/browser/ui/views/dropdown_bar_host_win.cc
+++ b/chrome/browser/ui/views/dropdown_bar_host_win.cc
@@ -4,10 +4,10 @@
#include "chrome/browser/views/dropdown_bar_host.h"
-#include "chrome/browser/find_bar_controller.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
+#include "chrome/browser/ui/find_bar/find_bar_controller.h"
#include "chrome/browser/views/frame/browser_view.h"
#include "views/controls/scrollbar/native_scroll_bar.h"
#include "views/widget/widget_win.h"
diff --git a/chrome/browser/ui/views/extensions/browser_action_drag_data.cc b/chrome/browser/ui/views/extensions/browser_action_drag_data.cc
index 6ab54ce..565c89c 100644
--- a/chrome/browser/ui/views/extensions/browser_action_drag_data.cc
+++ b/chrome/browser/ui/views/extensions/browser_action_drag_data.cc
@@ -7,7 +7,7 @@
#include "base/logging.h"
#include "base/pickle.h"
#include "base/string_util.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
const char* BrowserActionDragData::kClipboardFormatString =
"chromium/x-browser-actions";
diff --git a/chrome/browser/ui/views/extensions/browser_action_drag_data.h b/chrome/browser/ui/views/extensions/browser_action_drag_data.h
index ae26cca..7168025 100644
--- a/chrome/browser/ui/views/extensions/browser_action_drag_data.h
+++ b/chrome/browser/ui/views/extensions/browser_action_drag_data.h
@@ -9,7 +9,7 @@
#include <string>
#include "base/basictypes.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#if defined(TOOLKIT_VIEWS)
#include "app/os_exchange_data.h"
@@ -18,7 +18,6 @@
class BrowserActionButton;
class FilePath;
class Pickle;
-class Profile;
class BrowserActionDragData {
public:
diff --git a/chrome/browser/ui/views/extensions/browser_action_overflow_menu_controller.cc b/chrome/browser/ui/views/extensions/browser_action_overflow_menu_controller.cc
index aa072f6..509188f 100644
--- a/chrome/browser/ui/views/extensions/browser_action_overflow_menu_controller.cc
+++ b/chrome/browser/ui/views/extensions/browser_action_overflow_menu_controller.cc
@@ -7,8 +7,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/extensions/extension_context_menu_model.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/views/browser_actions_container.h"
#include "chrome/browser/views/extensions/browser_action_drag_data.h"
#include "chrome/common/extensions/extension.h"
diff --git a/chrome/browser/ui/views/extensions/extension_installed_bubble.cc b/chrome/browser/ui/views/extensions/extension_installed_bubble.cc
index d779197..1b549d3 100644
--- a/chrome/browser/ui/views/extensions/extension_installed_bubble.cc
+++ b/chrome/browser/ui/views/extensions/extension_installed_bubble.cc
@@ -6,10 +6,11 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
+#include "base/i18n/rtl.h"
#include "base/message_loop.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_window.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/views/browser_actions_container.h"
#include "chrome/browser/views/frame/browser_view.h"
@@ -17,7 +18,8 @@
#include "chrome/browser/views/toolbar_view.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_action.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
@@ -82,9 +84,11 @@ class InstalledBubbleContent : public views::View,
icon_->SetImage(*icon);
AddChildView(icon_);
+ std::wstring extension_name = UTF8ToWide(extension->name());
+ base::i18n::AdjustStringForLocaleDirection(&extension_name);
heading_ = new views::Label(
l10n_util::GetStringF(IDS_EXTENSION_INSTALLED_HEADING,
- UTF8ToWide(extension->name())));
+ extension_name));
heading_->SetFont(rb.GetFont(ResourceBundle::MediumFont));
heading_->SetMultiLine(true);
heading_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
@@ -264,7 +268,8 @@ void ExtensionInstalledBubble::Observe(NotificationType type,
&ExtensionInstalledBubble::ShowInternal));
}
} else if (type == NotificationType::EXTENSION_UNLOADED) {
- const Extension* extension = Details<const Extension>(details).ptr();
+ const Extension* extension =
+ Details<UnloadedExtensionInfo>(details)->extension;
if (extension == extension_)
extension_ = NULL;
} else {
diff --git a/chrome/browser/ui/views/extensions/extension_popup.cc b/chrome/browser/ui/views/extensions/extension_popup.cc
index 454bd60..0271fa4 100644
--- a/chrome/browser/ui/views/extensions/extension_popup.cc
+++ b/chrome/browser/ui/views/extensions/extension_popup.cc
@@ -4,18 +4,20 @@
#include "chrome/browser/views/extensions/extension_popup.h"
-#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_window.h"
+#include <vector>
+
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/debugger/devtools_toggle_action.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_process_manager.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/views/frame/browser_view.h"
-#include "chrome/browser/window_sizer.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/window_sizer.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_source.h"
@@ -24,16 +26,16 @@
#include "views/widget/root_view.h"
#include "views/window/window.h"
-
#if defined(OS_LINUX)
#include "views/widget/widget_gtk.h"
#endif
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/wm_ipc.h"
-#include "cros/chromeos_wm_ipc_enums.h"
+#include "third_party/cros/chromeos_wm_ipc_enums.h"
#endif
+using std::vector;
using views::Widget;
// The minimum, and default maximum dimensions of the popup.
@@ -120,10 +122,14 @@ ExtensionPopup::ExtensionPopup(ExtensionHost* host,
#endif
border_widget_->Init(native_window, bounds());
#if defined(OS_CHROMEOS)
- chromeos::WmIpc::instance()->SetWindowType(
- border_widget_->GetNativeView(),
- chromeos::WM_IPC_WINDOW_CHROME_INFO_BUBBLE,
- NULL);
+ {
+ vector<int> params;
+ params.push_back(0); // don't show while screen is locked
+ chromeos::WmIpc::instance()->SetWindowType(
+ border_widget_->GetNativeView(),
+ chromeos::WM_IPC_WINDOW_CHROME_INFO_BUBBLE,
+ &params);
+ }
#endif
border_ = new BubbleBorder(arrow_location);
border_view_ = new views::View;
diff --git a/chrome/browser/ui/views/external_protocol_dialog.cc b/chrome/browser/ui/views/external_protocol_dialog.cc
index 5b6d975..6f402c3 100644
--- a/chrome/browser/ui/views/external_protocol_dialog.cc
+++ b/chrome/browser/ui/views/external_protocol_dialog.cc
@@ -6,13 +6,13 @@
#include "app/l10n_util.h"
#include "app/message_box_flags.h"
+#include "app/text_elider.h"
#include "base/metrics/histogram.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "base/thread_restrictions.h"
#include "base/utf_string_conversions.h"
#include "base/win/registry.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/external_protocol_handler.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_util.h"
@@ -123,9 +123,9 @@ ExternalProtocolDialog::ExternalProtocolDialog(TabContents* tab_contents,
const int kMaxCommandSize = 256;
std::wstring elided_url_without_scheme;
std::wstring elided_command;
- ElideString(ASCIIToWide(url.possibly_invalid_spec()),
- kMaxUrlWithoutSchemeSize, &elided_url_without_scheme);
- ElideString(command, kMaxCommandSize, &elided_command);
+ gfx::ElideString(ASCIIToWide(url.possibly_invalid_spec()),
+ kMaxUrlWithoutSchemeSize, &elided_url_without_scheme);
+ gfx::ElideString(command, kMaxCommandSize, &elided_command);
std::wstring message_text = l10n_util::GetStringF(
IDS_EXTERNAL_PROTOCOL_INFORMATION,
diff --git a/chrome/browser/ui/views/find_bar_host.cc b/chrome/browser/ui/views/find_bar_host.cc
index e86e435..0eabaaf 100644
--- a/chrome/browser/ui/views/find_bar_host.cc
+++ b/chrome/browser/ui/views/find_bar_host.cc
@@ -5,15 +5,14 @@
#include "chrome/browser/views/find_bar_host.h"
#include "app/keyboard_codes.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/find_bar_controller.h"
#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/view_ids.h"
-#include "chrome/browser/views/find_bar_view.h"
-#include "chrome/browser/views/frame/browser_view.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/find_bar/find_bar_controller.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/find_bar_view.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
#include "views/focus/external_focus_tracker.h"
#include "views/focus/view_storage.h"
#include "views/widget/root_view.h"
@@ -126,7 +125,11 @@ void FindBarHost::SetFindText(const string16& find_text) {
}
void FindBarHost::UpdateUIForFindResult(const FindNotificationDetails& result,
- const string16& find_text) {
+ const string16& find_text) {
+ // Make sure match count is clear. It may get set again in UpdateForResult
+ // if enough data is available.
+ find_bar_view()->ClearMatchCount();
+
if (!find_text.empty())
find_bar_view()->UpdateForResult(result, find_text);
@@ -211,6 +214,14 @@ string16 FindBarHost::GetFindText() {
return find_bar_view()->GetFindText();
}
+string16 FindBarHost::GetFindSelectedText() {
+ return find_bar_view()->GetFindSelectedText();
+}
+
+string16 FindBarHost::GetMatchCountText() {
+ return find_bar_view()->GetMatchCountText();
+}
+
////////////////////////////////////////////////////////////////////////////////
// Overridden from DropdownBarHost:
diff --git a/chrome/browser/ui/views/find_bar_host.h b/chrome/browser/ui/views/find_bar_host.h
index cc52c87..6ab11ca 100644
--- a/chrome/browser/ui/views/find_bar_host.h
+++ b/chrome/browser/ui/views/find_bar_host.h
@@ -6,8 +6,8 @@
#define CHROME_BROWSER_UI_VIEWS_FIND_BAR_HOST_H_
#pragma once
-#include "chrome/browser/find_bar.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
+#include "chrome/browser/ui/find_bar/find_bar.h"
#include "chrome/browser/views/dropdown_bar_host.h"
#include "gfx/native_widget_types.h"
#include "gfx/rect.h"
@@ -72,6 +72,8 @@ class FindBarHost : public DropdownBarHost,
virtual bool GetFindBarWindowInfo(gfx::Point* position,
bool* fully_visible);
virtual string16 GetFindText();
+ virtual string16 GetFindSelectedText();
+ virtual string16 GetMatchCountText();
// Overridden from DropdownBarHost:
// Returns the rectangle representing where to position the find bar. It uses
diff --git a/chrome/browser/ui/views/find_bar_host_gtk.cc b/chrome/browser/ui/views/find_bar_host_gtk.cc
index d9f8986..e17c6d0 100644
--- a/chrome/browser/ui/views/find_bar_host_gtk.cc
+++ b/chrome/browser/ui/views/find_bar_host_gtk.cc
@@ -4,8 +4,8 @@
#include "chrome/browser/views/find_bar_host.h"
-#include "chrome/browser/find_bar_controller.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/find_bar/find_bar_controller.h"
#include "chrome/browser/views/frame/browser_view.h"
#include "chrome/browser/views/tab_contents/tab_contents_view_gtk.h"
#include "views/widget/widget_gtk.h"
diff --git a/chrome/browser/ui/views/find_bar_host_interactive_uitest.cc b/chrome/browser/ui/views/find_bar_host_interactive_uitest.cc
index 2049eb0..cb3d364 100644
--- a/chrome/browser/ui/views/find_bar_host_interactive_uitest.cc
+++ b/chrome/browser/ui/views/find_bar_host_interactive_uitest.cc
@@ -3,15 +3,16 @@
// found in the LICENSE file.
#include "app/keyboard_codes.h"
+#include "base/process_util.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/find_bar_controller.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/views/find_bar_host.h"
-#include "chrome/browser/views/frame/browser_view.h"
-#include "chrome/browser/view_ids.h"
+#include "chrome/browser/ui/find_bar/find_bar_controller.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/find_bar_host.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "net/test/test_server.h"
@@ -38,12 +39,6 @@ class FindInPageTest : public InProcessBrowserTest {
}
};
-void Checkpoint(const char* message, const base::TimeTicks& start_time) {
- LOG(INFO) << message << " : "
- << (base::TimeTicks::Now() - start_time).InMilliseconds()
- << " ms" << std::flush;
-}
-
} // namespace
IN_PROC_BROWSER_TEST_F(FindInPageTest, CrashEscHandlers) {
@@ -125,6 +120,54 @@ IN_PROC_BROWSER_TEST_F(FindInPageTest, FocusRestore) {
EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_LOCATION_BAR));
}
+IN_PROC_BROWSER_TEST_F(FindInPageTest, FocusRestoreOnTabSwitch) {
+ ASSERT_TRUE(test_server()->Start());
+
+ // First we navigate to our test page (tab A).
+ GURL url = test_server()->GetURL(kSimplePage);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ browser()->Find();
+ EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(),
+ VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
+
+ FindBarTesting* find_bar =
+ browser()->GetFindBarController()->find_bar()->GetFindBarTesting();
+
+ // Search for 'a'.
+ ui_test_utils::FindInPage(browser()->GetSelectedTabContents(),
+ ASCIIToUTF16("a"), true, false, NULL);
+ EXPECT_TRUE(ASCIIToUTF16("a") == find_bar->GetFindSelectedText());
+
+ // Open another tab (tab B).
+ browser()->AddSelectedTabWithURL(url, PageTransition::TYPED);
+ ASSERT_TRUE(ui_test_utils::WaitForNavigationInCurrentTab(browser()));
+
+ // Make sure Find box is open.
+ browser()->Find();
+ EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(),
+ VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
+
+ // Search for 'b'.
+ ui_test_utils::FindInPage(browser()->GetSelectedTabContents(),
+ ASCIIToUTF16("b"), true, false, NULL);
+ EXPECT_TRUE(ASCIIToUTF16("b") == find_bar->GetFindSelectedText());
+
+ // Set focus away from the Find bar (to the Location bar).
+ browser()->FocusLocationBar();
+ EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_LOCATION_BAR));
+
+ // Select tab A. Find bar should get focus.
+ browser()->SelectTabContentsAt(0, true);
+ EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(),
+ VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
+ EXPECT_TRUE(ASCIIToUTF16("a") == find_bar->GetFindSelectedText());
+
+ // Select tab B. Location bar should get focus.
+ browser()->SelectTabContentsAt(1, true);
+ EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_LOCATION_BAR));
+}
+
// This tests that whenever you clear values from the Find box and close it that
// it respects that and doesn't show you the last search, as reported in bug:
// http://crbug.com/40121.
@@ -134,66 +177,53 @@ IN_PROC_BROWSER_TEST_F(FindInPageTest, PrepopulateRespectBlank) {
return;
#endif
- base::TimeTicks start_time = base::TimeTicks::Now();
- Checkpoint("Starting test server", start_time);
-
ASSERT_TRUE(test_server()->Start());
+ // Make sure Chrome is in the foreground, otherwise sending input
+ // won't do anything and the test will hang.
+ ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+
// First we navigate to any page.
- Checkpoint("Navigating", start_time);
GURL url = test_server()->GetURL(kSimplePage);
ui_test_utils::NavigateToURL(browser(), url);
// Show the Find bar.
- Checkpoint("Showing Find window", start_time);
browser()->GetFindBarController()->Show();
// Search for "a".
- Checkpoint("Search for 'a'", start_time);
ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
browser(), app::VKEY_A, false, false, false, false));
// We should find "a" here.
- Checkpoint("GetFindBarText", start_time);
EXPECT_EQ(ASCIIToUTF16("a"), GetFindBarText());
// Delete "a".
- Checkpoint("Delete 'a'", start_time);
ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
browser(), app::VKEY_BACK, false, false, false, false));
// Validate we have cleared the text.
- Checkpoint("Validate clear", start_time);
EXPECT_EQ(string16(), GetFindBarText());
// Close the Find box.
- Checkpoint("Close find", start_time);
ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
browser(), app::VKEY_ESCAPE, false, false, false, false));
// Show the Find bar.
- Checkpoint("Showing Find window", start_time);
browser()->GetFindBarController()->Show();
// After the Find box has been reopened, it should not have been prepopulated
// with "a" again.
- Checkpoint("GetFindBarText", start_time);
EXPECT_EQ(string16(), GetFindBarText());
// Close the Find box.
- Checkpoint("Press Esc", start_time);
ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
browser(), app::VKEY_ESCAPE, false, false, false, false));
// Press F3 to trigger FindNext.
- Checkpoint("Press F3", start_time);
ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
browser(), app::VKEY_F3, false, false, false, false));
// After the Find box has been reopened, it should still have no prepopulate
// value.
- Checkpoint("GetFindBarText", start_time);
EXPECT_EQ(string16(), GetFindBarText());
-
- Checkpoint("Test completed", start_time);
}
diff --git a/chrome/browser/ui/views/find_bar_host_win.cc b/chrome/browser/ui/views/find_bar_host_win.cc
index e1e5a50..0133f60 100644
--- a/chrome/browser/ui/views/find_bar_host_win.cc
+++ b/chrome/browser/ui/views/find_bar_host_win.cc
@@ -4,10 +4,10 @@
#include "chrome/browser/views/find_bar_host.h"
-#include "chrome/browser/find_bar_controller.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
+#include "chrome/browser/ui/find_bar/find_bar_controller.h"
#include "chrome/browser/views/frame/browser_view.h"
#include "views/controls/scrollbar/native_scroll_bar.h"
#include "views/widget/widget_win.h"
diff --git a/chrome/browser/ui/views/find_bar_view.cc b/chrome/browser/ui/views/find_bar_view.cc
index eea85a6..72f722c 100644
--- a/chrome/browser/ui/views/find_bar_view.cc
+++ b/chrome/browser/ui/views/find_bar_view.cc
@@ -11,14 +11,14 @@
#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/find_bar_controller.h"
-#include "chrome/browser/find_bar_state.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/themes/browser_theme_provider.h"
-#include "chrome/browser/view_ids.h"
-#include "chrome/browser/views/find_bar_host.h"
-#include "chrome/browser/views/frame/browser_view.h"
+#include "chrome/browser/ui/find_bar/find_bar_controller.h"
+#include "chrome/browser/ui/find_bar/find_bar_state.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/find_bar_host.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
#include "gfx/canvas.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
@@ -97,7 +97,7 @@ FindBarView::FindBarView(FindBarHost* host)
SetID(VIEW_ID_FIND_IN_PAGE);
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- find_text_ = new views::Textfield();
+ find_text_ = new SearchTextfieldView();
find_text_->SetID(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD);
find_text_->SetFont(rb.GetFont(ResourceBundle::BaseFont));
find_text_->set_default_width_in_chars(kDefaultCharWidth);
@@ -187,6 +187,14 @@ string16 FindBarView::GetFindText() const {
return find_text_->text();
}
+string16 FindBarView::GetFindSelectedText() const {
+ return find_text_->GetSelectedText();
+}
+
+string16 FindBarView::GetMatchCountText() const {
+ return WideToUTF16Hack(match_count_text_->GetText());
+}
+
void FindBarView::UpdateForResult(const FindNotificationDetails& result,
const string16& find_text) {
bool have_valid_range =
@@ -223,6 +231,13 @@ void FindBarView::UpdateForResult(const FindNotificationDetails& result,
SchedulePaint();
}
+void FindBarView::ClearMatchCount() {
+ match_count_text_->SetText(L"");
+ UpdateMatchCountAppearance(false);
+ Layout();
+ SchedulePaint();
+}
+
void FindBarView::SetFocusAndSelection(bool select_all) {
#if defined(OS_CHROMEOS)
// TODO(altimofeev): this workaround is needed only when the FindBar was
@@ -530,6 +545,17 @@ bool FindBarView::FocusForwarderView::OnMousePressed(
return true;
}
+FindBarView::SearchTextfieldView::SearchTextfieldView() {
+}
+
+FindBarView::SearchTextfieldView::~SearchTextfieldView() {
+}
+
+void FindBarView::SearchTextfieldView::RequestFocus() {
+ views::View::RequestFocus();
+ SelectAll();
+}
+
FindBarHost* FindBarView::find_bar_host() const {
return static_cast<FindBarHost*>(host());
}
diff --git a/chrome/browser/ui/views/find_bar_view.h b/chrome/browser/ui/views/find_bar_view.h
index a7a5e7f..4047228 100644
--- a/chrome/browser/ui/views/find_bar_view.h
+++ b/chrome/browser/ui/views/find_bar_view.h
@@ -7,7 +7,7 @@
#pragma once
#include "base/string16.h"
-#include "chrome/browser/find_notification_details.h"
+#include "chrome/browser/ui/find_bar/find_notification_details.h"
#include "chrome/browser/views/dropdown_bar_view.h"
#include "gfx/size.h"
#include "views/controls/button/button.h"
@@ -47,11 +47,20 @@ class FindBarView : public DropdownBarView,
string16 GetFindText() const;
void SetFindText(const string16& find_text);
+ // Gets the selected text in the text box.
+ string16 GetFindSelectedText() const;
+
+ // Gets the match count text displayed in the text box.
+ string16 GetMatchCountText() const;
+
// Updates the label inside the Find text box that shows the ordinal of the
// active item and how many matches were found.
void UpdateForResult(const FindNotificationDetails& result,
const string16& find_text);
+ // Clears the current Match Count value in the Find text box.
+ void ClearMatchCount();
+
// Claims focus for the text field and selects its contents.
virtual void SetFocusAndSelection(bool select_all);
@@ -99,12 +108,25 @@ class FindBarView : public DropdownBarView,
DISALLOW_COPY_AND_ASSIGN(FocusForwarderView);
};
+ // A wrapper of views::TextField that allows us to select all text when we
+ // get focus. Represents the text field where the user enters a search term.
+ class SearchTextfieldView : public views::Textfield {
+ public:
+ SearchTextfieldView();
+ virtual ~SearchTextfieldView();
+
+ virtual void RequestFocus();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SearchTextfieldView);
+ };
+
// Returns the OS-specific view for the find bar that acts as an intermediary
// between us and the TabContentsView.
FindBarHost* find_bar_host() const;
#if defined(OS_LINUX)
- // In gtk we get changed signals if we programatically set the text. If we
+ // In GTK we get changed signals if we programmatically set the text. If we
// don't ignore them we run into problems. For example, switching tabs back
// to one with the find bar visible will cause a search to the next found
// text. Also if the find bar had been visible and then hidden and the user
@@ -113,7 +135,7 @@ class FindBarView : public DropdownBarView,
#endif
// The controls in the window.
- views::Textfield* find_text_;
+ SearchTextfieldView* find_text_;
views::Label* match_count_text_;
FocusForwarderView* focus_forwarder_view_;
views::ImageButton* find_previous_button_;
diff --git a/chrome/browser/ui/views/first_run_search_engine_view.cc b/chrome/browser/ui/views/first_run_search_engine_view.cc
index 6688d9e..fa4e6a7 100644
--- a/chrome/browser/ui/views/first_run_search_engine_view.cc
+++ b/chrome/browser/ui/views/first_run_search_engine_view.cc
@@ -13,11 +13,11 @@
#include "base/i18n/rtl.h"
#include "base/rand_util.h"
#include "base/time.h"
-#include "chrome/browser/options_window.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/search_engine_type.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/browser/ui/options/options_window.h"
#include "gfx/canvas.h"
#include "gfx/font.h"
#include "grit/browser_resources.h"
diff --git a/chrome/browser/ui/views/frame/browser_frame_gtk.cc b/chrome/browser/ui/views/frame/browser_frame_gtk.cc
index a2badbd..f092657 100644
--- a/chrome/browser/ui/views/frame/browser_frame_gtk.cc
+++ b/chrome/browser/ui/views/frame/browser_frame_gtk.cc
@@ -5,14 +5,13 @@
#include "chrome/browser/views/frame/browser_frame_gtk.h"
#include "base/logging.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/status_bubble.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/themes/browser_theme_provider.h"
-#include "chrome/browser/views/frame/app_panel_browser_frame_view.h"
-#include "chrome/browser/views/frame/browser_root_view.h"
-#include "chrome/browser/views/frame/browser_view.h"
-#include "chrome/browser/views/frame/opaque_browser_frame_view.h"
-#include "chrome/browser/views/frame/popup_non_client_frame_view.h"
+#include "chrome/browser/ui/status_bubble.h"
+#include "chrome/browser/ui/views/frame/app_panel_browser_frame_view.h"
+#include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"
+#include "chrome/browser/ui/views/frame/browser_root_view.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
#include "gfx/font.h"
#include "views/widget/root_view.h"
#include "views/window/hit_test.h"
@@ -46,12 +45,10 @@ BrowserFrameGtk::~BrowserFrameGtk() {
}
void BrowserFrameGtk::Init() {
- if (browser_frame_view_ == NULL) {
- if (browser_view_->browser()->type() & Browser::TYPE_POPUP)
- browser_frame_view_ = new PopupNonClientFrameView();
- else
- browser_frame_view_ = new OpaqueBrowserFrameView(this, browser_view_);
- }
+ if (browser_frame_view_ == NULL)
+ browser_frame_view_ =
+ browser::CreateBrowserNonClientFrameView(this, browser_view_);
+
GetNonClientView()->SetFrameView(browser_frame_view_);
WindowGtk::Init(NULL, gfx::Rect());
// Don't focus anything on creation, selecting a tab will set the focus.
diff --git a/chrome/browser/ui/views/frame/browser_frame_win.cc b/chrome/browser/ui/views/frame/browser_frame_win.cc
index d7e99fa..d747f73 100644
--- a/chrome/browser/ui/views/frame/browser_frame_win.cc
+++ b/chrome/browser/ui/views/frame/browser_frame_win.cc
@@ -12,15 +12,13 @@
#include "app/win_util.h"
#include "base/win_util.h"
#include "chrome/browser/accessibility/browser_accessibility_state.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/themes/browser_theme_provider.h"
-#include "chrome/browser/views/frame/app_panel_browser_frame_view.h"
#include "chrome/browser/views/frame/browser_non_client_frame_view.h"
#include "chrome/browser/views/frame/browser_root_view.h"
#include "chrome/browser/views/frame/browser_view.h"
#include "chrome/browser/views/frame/glass_browser_frame_view.h"
-#include "chrome/browser/views/frame/opaque_browser_frame_view.h"
#include "grit/theme_resources.h"
#include "views/screen.h"
#include "views/window/window_delegate.h"
@@ -107,9 +105,6 @@ bool BrowserFrameWin::AlwaysUseNativeFrame() const {
if (browser_view_->IsBrowserTypePanel())
return false;
- if (browser_view_->browser()->type() == Browser::TYPE_EXTENSION_APP)
- return false;
-
// We don't theme popup or app windows, so regardless of whether or not a
// theme is active for normal browser windows, we don't want to use the custom
// frame for popups/apps.
@@ -240,7 +235,7 @@ ThemeProvider* BrowserFrameWin::GetDefaultThemeProvider() const {
}
void BrowserFrameWin::OnScreenReaderDetected() {
- Singleton<BrowserAccessibilityState>()->OnScreenReaderDetected();
+ BrowserAccessibilityState::GetInstance()->OnScreenReaderDetected();
WindowWin::OnScreenReaderDetected();
}
@@ -266,10 +261,9 @@ void BrowserFrameWin::Activate() {
views::NonClientFrameView* BrowserFrameWin::CreateFrameViewForWindow() {
if (AlwaysUseNativeFrame())
browser_frame_view_ = new GlassBrowserFrameView(this, browser_view_);
- else if (browser_view_->IsBrowserTypePanel())
- browser_frame_view_ = new AppPanelBrowserFrameView(this, browser_view_);
else
- browser_frame_view_ = new OpaqueBrowserFrameView(this, browser_view_);
+ browser_frame_view_ =
+ browser::CreateBrowserNonClientFrameView(this, browser_view_);
return browser_frame_view_;
}
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
index 2fec304..642c96d 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
@@ -9,6 +9,8 @@
#include "views/window/non_client_view.h"
class BaseTabStrip;
+class BrowserFrame;
+class BrowserView;
// A specialization of the NonClientFrameView object that provides additional
// Browser-specific methods.
@@ -30,4 +32,12 @@ class BrowserNonClientFrameView : public views::NonClientFrameView {
virtual void UpdateThrobber(bool running) = 0;
};
+namespace browser {
+
+// Provided by a browser_non_client_frame_view_factory_*.cc implementation
+BrowserNonClientFrameView* CreateBrowserNonClientFrameView(
+ BrowserFrame* frame, BrowserView* browser_view);
+
+} // browser
+
#endif // CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_NON_CLIENT_FRAME_VIEW_H_
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_gtk.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_gtk.cc
new file mode 100644
index 0000000..93b2c8c
--- /dev/null
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_gtk.cc
@@ -0,0 +1,21 @@
+// 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.
+
+#include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"
+
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/frame/opaque_browser_frame_view.h"
+#include "chrome/browser/ui/views/frame/popup_non_client_frame_view.h"
+
+namespace browser {
+
+BrowserNonClientFrameView* CreateBrowserNonClientFrameView(
+ BrowserFrame* frame, BrowserView* browser_view) {
+ if (browser_view->IsBrowserTypePopup())
+ return new PopupNonClientFrameView();
+ else
+ return new OpaqueBrowserFrameView(frame, browser_view);
+}
+
+} // browser
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_win.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_win.cc
new file mode 100644
index 0000000..69ad1c8
--- /dev/null
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_win.cc
@@ -0,0 +1,21 @@
+// 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.
+
+#include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"
+
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/frame/app_panel_browser_frame_view.h"
+#include "chrome/browser/ui/views/frame/opaque_browser_frame_view.h"
+
+namespace browser {
+
+BrowserNonClientFrameView* CreateBrowserNonClientFrameView(
+ BrowserFrame* frame, BrowserView* browser_view) {
+ if (browser_view->IsBrowserTypePanel())
+ return new AppPanelBrowserFrameView(frame, browser_view);
+ else
+ return new OpaqueBrowserFrameView(frame, browser_view);
+}
+
+} // browser
diff --git a/chrome/browser/ui/views/frame/browser_root_view.cc b/chrome/browser/ui/views/frame/browser_root_view.cc
index e99cccb..51a12a1 100644
--- a/chrome/browser/ui/views/frame/browser_root_view.cc
+++ b/chrome/browser/ui/views/frame/browser_root_view.cc
@@ -10,11 +10,11 @@
#include "chrome/browser/autocomplete/autocomplete.h"
#include "chrome/browser/autocomplete/autocomplete_classifier.h"
#include "chrome/browser/autocomplete/autocomplete_match.h"
-#include "chrome/browser/location_bar.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/views/frame/browser_view.h"
-#include "chrome/browser/views/frame/browser_frame.h"
-#include "chrome/browser/views/tabs/tab_strip.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/omnibox/location_bar.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/frame/browser_frame.h"
+#include "chrome/browser/ui/views/tabs/tab_strip.h"
#include "grit/chromium_strings.h"
BrowserRootView::BrowserRootView(BrowserView* browser_view,
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index e5e9416..f00aef8 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -16,12 +16,10 @@
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/app/chrome_dll_resource.h"
-#include "chrome/browser/app_modal_dialog_queue.h"
#include "chrome/browser/autocomplete/autocomplete_popup_model.h"
#include "chrome/browser/autocomplete/autocomplete_popup_view.h"
#include "chrome/browser/automation/ui_controls.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
-#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/debugger/devtools_window.h"
#include "chrome/browser/dom_ui/bug_report_ui.h"
@@ -30,36 +28,38 @@
#include "chrome/browser/ntp_background_util.h"
#include "chrome/browser/page_info_window.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/sessions/tab_restore_service.h"
#include "chrome/browser/sidebar/sidebar_container.h"
#include "chrome/browser/sidebar/sidebar_manager.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
-#include "chrome/browser/tab_contents_wrapper.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h"
#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/view_ids.h"
-#include "chrome/browser/views/accessible_view_helper.h"
-#include "chrome/browser/views/bookmark_bar_view.h"
-#include "chrome/browser/views/browser_dialogs.h"
-#include "chrome/browser/views/default_search_view.h"
-#include "chrome/browser/views/download_shelf_view.h"
-#include "chrome/browser/views/frame/browser_view_layout.h"
-#include "chrome/browser/views/frame/contents_container.h"
-#include "chrome/browser/views/fullscreen_exit_bubble.h"
-#include "chrome/browser/views/status_bubble_views.h"
-#include "chrome/browser/views/tab_contents/tab_contents_container.h"
-#include "chrome/browser/views/tabs/browser_tab_strip_controller.h"
-#include "chrome/browser/views/tabs/side_tab_strip.h"
-#include "chrome/browser/views/theme_install_bubble_view.h"
-#include "chrome/browser/views/toolbar_view.h"
-#include "chrome/browser/views/update_recommended_message_box.h"
-#include "chrome/browser/views/window.h"
-#include "chrome/browser/window_sizer.h"
-#include "chrome/browser/wrench_menu_model.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "chrome/browser/ui/toolbar/wrench_menu_model.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/accessible_view_helper.h"
+#include "chrome/browser/ui/views/bookmark_bar_view.h"
+#include "chrome/browser/ui/views/browser_dialogs.h"
+#include "chrome/browser/ui/views/default_search_view.h"
+#include "chrome/browser/ui/views/download_shelf_view.h"
+#include "chrome/browser/ui/views/frame/browser_view_layout.h"
+#include "chrome/browser/ui/views/frame/contents_container.h"
+#include "chrome/browser/ui/views/fullscreen_exit_bubble.h"
+#include "chrome/browser/ui/views/status_bubble_views.h"
+#include "chrome/browser/ui/views/tab_contents/tab_contents_container.h"
+#include "chrome/browser/ui/views/tabs/browser_tab_strip_controller.h"
+#include "chrome/browser/ui/views/tabs/side_tab_strip.h"
+#include "chrome/browser/ui/views/theme_install_bubble_view.h"
+#include "chrome/browser/ui/views/toolbar_view.h"
+#include "chrome/browser/ui/views/update_recommended_message_box.h"
+#include "chrome/browser/ui/views/window.h"
+#include "chrome/browser/ui/window_sizer.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension_resource.h"
#include "chrome/common/native_window_notification_source.h"
@@ -92,6 +92,10 @@
#include "views/window/window_gtk.h"
#endif
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/ui/views/keyboard_overlay_delegate.h"
+#endif
+
using base::TimeDelta;
using views::ColumnSet;
using views::GridLayout;
@@ -421,7 +425,7 @@ void BrowserView::SetShowState(int state) {
BrowserView::BrowserView(Browser* browser)
: views::ClientView(NULL, NULL),
last_focused_view_storage_id_(
- views::ViewStorage::GetSharedInstance()->CreateStorageID()),
+ views::ViewStorage::GetInstance()->CreateStorageID()),
frame_(NULL),
browser_(browser),
active_bookmark_bar_(NULL),
@@ -604,12 +608,7 @@ bool BrowserView::AcceleratorPressed(const views::Accelerator& accelerator) {
DCHECK(iter != accelerator_table_.end());
int command_id = iter->second;
- if (browser_->command_updater()->SupportsCommand(command_id) &&
- browser_->command_updater()->IsCommandEnabled(command_id)) {
- browser_->ExecuteCommand(command_id);
- return true;
- }
- return false;
+ return browser_->ExecuteCommandIfEnabled(command_id);
}
bool BrowserView::GetAccelerator(int cmd_id, menus::Accelerator* accelerator) {
@@ -640,13 +639,13 @@ bool BrowserView::GetAccelerator(int cmd_id, menus::Accelerator* accelerator) {
bool BrowserView::ActivateAppModalDialog() const {
// If another browser is app modal, flash and activate the modal browser.
- if (Singleton<AppModalDialogQueue>()->HasActiveDialog()) {
+ if (AppModalDialogQueue::GetInstance()->HasActiveDialog()) {
Browser* active_browser = BrowserList::GetLastActive();
if (active_browser && (browser_ != active_browser)) {
active_browser->window()->FlashFrame();
active_browser->window()->Activate();
}
- Singleton<AppModalDialogQueue>()->ActivateModalDialog();
+ AppModalDialogQueue::GetInstance()->ActivateModalDialog();
return true;
}
return false;
@@ -979,7 +978,7 @@ void BrowserView::RotatePaneFocus(bool forwards) {
}
void BrowserView::SaveFocusedView() {
- views::ViewStorage* view_storage = views::ViewStorage::GetSharedInstance();
+ views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
if (view_storage->RetrieveView(last_focused_view_storage_id_))
view_storage->RemoveView(last_focused_view_storage_id_);
views::View* focused_view = GetRootView()->GetFocusedView();
@@ -1005,6 +1004,10 @@ bool BrowserView::IsBookmarkBarAnimating() const {
return bookmark_bar_view_.get() && bookmark_bar_view_->is_animating();
}
+bool BrowserView::IsTabStripEditable() const {
+ return !tabstrip_->IsDragSessionActive() && !tabstrip_->IsActiveDropTarget();
+}
+
bool BrowserView::IsToolbarVisible() const {
return browser_->SupportsWindowFeature(Browser::FEATURE_TOOLBAR) ||
browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR);
@@ -1271,14 +1274,13 @@ bool BrowserView::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
if (id == -1)
return false;
- if (browser_->IsReservedCommand(id)) {
- // TODO(suzhe): For Linux, should we send things like Ctrl+w, Ctrl+n
- // to the renderer first, just like what
- // BrowserWindowGtk::HandleKeyboardEvent() does?
- // Executing the command may cause |this| object to be destroyed.
- browser_->ExecuteCommand(id);
- return true;
- }
+ // Executing the command may cause |this| object to be destroyed.
+#if defined(OS_LINUX)
+ if (browser_->IsReservedCommand(id) && !event.match_edit_command)
+#else
+ if (browser_->IsReservedCommand(id))
+#endif
+ return browser_->ExecuteCommandIfEnabled(id);
DCHECK(is_keyboard_shortcut != NULL);
*is_keyboard_shortcut = true;
@@ -1385,6 +1387,12 @@ gfx::Rect BrowserView::GetInstantBounds() {
return contents_->GetPreviewBounds();
}
+#if defined(OS_CHROMEOS)
+void BrowserView::ShowKeyboardOverlay(gfx::NativeWindow owning_window) {
+ KeyboardOverlayDelegate::ShowDialog(owning_window);
+}
+#endif
+
///////////////////////////////////////////////////////////////////////////////
// BrowserView, BrowserWindowTesting implementation:
@@ -1517,7 +1525,7 @@ bool BrowserView::GetAcceleratorForCommandId(int command_id,
return toolbar_->GetAcceleratorForCommandId(command_id, accelerator);
}
-bool BrowserView::IsLabelForCommandIdDynamic(int command_id) const {
+bool BrowserView::IsItemForCommandIdDynamic(int command_id) const {
return command_id == IDC_RESTORE_TAB;
}
@@ -1534,7 +1542,7 @@ string16 BrowserView::GetLabelForCommandId(int command_id) const {
}
void BrowserView::ExecuteCommand(int command_id) {
- browser_->ExecuteCommand(command_id);
+ browser_->ExecuteCommandIfEnabled(command_id);
}
///////////////////////////////////////////////////////////////////////////////
@@ -1603,12 +1611,7 @@ bool BrowserView::ExecuteWindowsCommand(int command_id) {
if (command_id_from_app_command != -1)
command_id = command_id_from_app_command;
- if (browser_->command_updater()->SupportsCommand(command_id)) {
- if (browser_->command_updater()->IsCommandEnabled(command_id))
- browser_->ExecuteCommand(command_id);
- return true;
- }
- return false;
+ return browser_->ExecuteCommandIfEnabled(command_id);
}
std::wstring BrowserView::GetWindowName() const {
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index 62c77c3..19635e6 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -275,6 +275,7 @@ class BrowserView : public BrowserBubbleHost,
virtual void DestroyBrowser();
virtual bool IsBookmarkBarVisible() const;
virtual bool IsBookmarkBarAnimating() const;
+ virtual bool IsTabStripEditable() const;
virtual bool IsToolbarVisible() const;
virtual void DisableInactiveFrame();
virtual void ConfirmSetDefaultSearchProvider(
@@ -327,6 +328,9 @@ class BrowserView : public BrowserBubbleHost,
virtual void ShowInstant(TabContents* preview_contents);
virtual void HideInstant(bool instant_is_active);
virtual gfx::Rect GetInstantBounds();
+#if defined(OS_CHROMEOS)
+ virtual void ShowKeyboardOverlay(gfx::NativeWindow owning_window);
+#endif
// Overridden from BrowserWindowTesting:
virtual BookmarkBarView* GetBookmarkBarView() const;
@@ -357,7 +361,7 @@ class BrowserView : public BrowserBubbleHost,
virtual bool IsCommandIdEnabled(int command_id) const;
virtual bool GetAcceleratorForCommandId(int command_id,
menus::Accelerator* accelerator);
- virtual bool IsLabelForCommandIdDynamic(int command_id) const;
+ virtual bool IsItemForCommandIdDynamic(int command_id) const;
virtual string16 GetLabelForCommandId(int command_id) const;
virtual void ExecuteCommand(int command_id);
diff --git a/chrome/browser/ui/views/frame/browser_view_layout.cc b/chrome/browser/ui/views/frame/browser_view_layout.cc
index 5b7dc66..914f202 100644
--- a/chrome/browser/ui/views/frame/browser_view_layout.cc
+++ b/chrome/browser/ui/views/frame/browser_view_layout.cc
@@ -4,18 +4,18 @@
#include "chrome/browser/views/frame/browser_view_layout.h"
-#include "chrome/browser/find_bar.h"
-#include "chrome/browser/find_bar_controller.h"
#include "chrome/browser/sidebar/sidebar_manager.h"
-#include "chrome/browser/view_ids.h"
-#include "chrome/browser/views/bookmark_bar_view.h"
-#include "chrome/browser/views/download_shelf_view.h"
-#include "chrome/browser/views/frame/browser_frame.h"
-#include "chrome/browser/views/frame/browser_view.h"
-#include "chrome/browser/views/frame/contents_container.h"
-#include "chrome/browser/views/tabs/side_tab_strip.h"
-#include "chrome/browser/views/tabs/tab_strip.h"
-#include "chrome/browser/views/toolbar_view.h"
+#include "chrome/browser/ui/find_bar/find_bar.h"
+#include "chrome/browser/ui/find_bar/find_bar_controller.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/bookmark_bar_view.h"
+#include "chrome/browser/ui/views/download_shelf_view.h"
+#include "chrome/browser/ui/views/frame/browser_frame.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/frame/contents_container.h"
+#include "chrome/browser/ui/views/tabs/side_tab_strip.h"
+#include "chrome/browser/ui/views/tabs/tab_strip.h"
+#include "chrome/browser/ui/views/toolbar_view.h"
#include "gfx/scrollbar_size.h"
#include "views/window/window.h"
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
index a7a3369..d5bd3b3 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
@@ -177,6 +177,22 @@ OpaqueBrowserFrameView::~OpaqueBrowserFrameView() {
}
///////////////////////////////////////////////////////////////////////////////
+// OpaqueBrowserFrameView, protected:
+
+int OpaqueBrowserFrameView::GetReservedHeight() const {
+ return 0;
+}
+
+gfx::Rect OpaqueBrowserFrameView::GetBoundsForReservedArea() const {
+ gfx::Rect client_view_bounds = CalculateClientAreaBounds(width(), height());
+ return gfx::Rect(
+ client_view_bounds.x(),
+ client_view_bounds.y() + client_view_bounds.height(),
+ client_view_bounds.width(),
+ GetReservedHeight());
+}
+
+///////////////////////////////////////////////////////////////////////////////
// OpaqueBrowserFrameView, BrowserNonClientFrameView implementation:
gfx::Rect OpaqueBrowserFrameView::GetBoundsForTabStrip(
@@ -1048,5 +1064,6 @@ gfx::Rect OpaqueBrowserFrameView::CalculateClientAreaBounds(int width,
int border_thickness = NonClientBorderThickness();
return gfx::Rect(border_thickness, top_height,
std::max(0, width - (2 * border_thickness)),
- std::max(0, height - top_height - border_thickness));
+ std::max(0, height - GetReservedHeight() -
+ top_height - border_thickness));
}
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.h b/chrome/browser/ui/views/frame/opaque_browser_frame_view.h
index 05830d5..5d27f0c 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.h
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.h
@@ -38,6 +38,13 @@ class OpaqueBrowserFrameView : public BrowserNonClientFrameView,
virtual gfx::Size GetMinimumSize();
protected:
+ BrowserView* browser_view() const { return browser_view_; }
+
+ // Used to allow subclasses to reserve height for other components they
+ // will add. The space is reserved below the ClientView.
+ virtual int GetReservedHeight() const;
+ virtual gfx::Rect GetBoundsForReservedArea() const;
+
// Overridden from views::NonClientFrameView:
virtual gfx::Rect GetBoundsForClientView() const;
virtual bool AlwaysUseNativeFrame() const;
diff --git a/chrome/browser/ui/views/html_dialog_view_browsertest.cc b/chrome/browser/ui/views/html_dialog_view_browsertest.cc
index baacb95..a230922 100644
--- a/chrome/browser/ui/views/html_dialog_view_browsertest.cc
+++ b/chrome/browser/ui/views/html_dialog_view_browsertest.cc
@@ -7,7 +7,6 @@
#include "base/file_path.h"
#include "base/message_loop.h"
#include "base/singleton.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/dom_ui/html_dialog_ui.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
@@ -73,7 +72,7 @@ class HtmlDialogBrowserTest : public InProcessBrowserTest {
public:
WindowChangedObserver() {}
- static WindowChangedObserver* Get() {
+ static WindowChangedObserver* GetInstance() {
return Singleton<WindowChangedObserver>::get();
}
@@ -95,7 +94,7 @@ class HtmlDialogBrowserTest : public InProcessBrowserTest {
public:
WindowChangedObserver() {}
- static WindowChangedObserver* Get() {
+ static WindowChangedObserver* GetInstance() {
return Singleton<WindowChangedObserver>::get();
}
@@ -136,7 +135,8 @@ IN_PROC_BROWSER_TEST_F(HtmlDialogBrowserTest, MAYBE_SizeWindow) {
html_view->InitDialog();
html_view->window()->Show();
- MessageLoopForUI::current()->AddObserver(WindowChangedObserver::Get());
+ MessageLoopForUI::current()->AddObserver(
+ WindowChangedObserver::GetInstance());
gfx::Rect bounds;
html_view->GetWidget()->GetBounds(&bounds, false);
@@ -202,5 +202,6 @@ IN_PROC_BROWSER_TEST_F(HtmlDialogBrowserTest, MAYBE_SizeWindow) {
EXPECT_LT(0, actual_bounds.width());
EXPECT_LT(0, actual_bounds.height());
- MessageLoopForUI::current()->RemoveObserver(WindowChangedObserver::Get());
+ MessageLoopForUI::current()->RemoveObserver(
+ WindowChangedObserver::GetInstance());
}
diff --git a/chrome/browser/ui/views/importer_view.cc b/chrome/browser/ui/views/importer_view.cc
index 4ef686f..cbbfba7 100644
--- a/chrome/browser/ui/views/importer_view.cc
+++ b/chrome/browser/ui/views/importer_view.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/views/importer_view.h"
#include "app/l10n_util.h"
-#include "base/string16.h"
+#include "base/compiler_specific.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
@@ -42,7 +42,7 @@ ImporterView::ImporterView(Profile* profile, int initial_state)
passwords_checkbox_(NULL),
search_engines_checkbox_(NULL),
profile_(profile),
- importer_host_(new ImporterHost()),
+ ALLOW_THIS_IN_INITIALIZER_LIST(importer_host_(new ImporterHost(this))),
initial_state_(initial_state) {
DCHECK(profile);
SetupControl();
@@ -149,9 +149,8 @@ std::wstring ImporterView::GetWindowTitle() const {
}
bool ImporterView::Accept() {
- if (!IsDialogButtonEnabled(MessageBoxFlags::DIALOGBUTTON_OK)) {
+ if (!IsDialogButtonEnabled(MessageBoxFlags::DIALOGBUTTON_OK))
return false;
- }
uint16 items = GetCheckedItems();
@@ -179,15 +178,16 @@ void ImporterView::ButtonPressed(
int ImporterView::GetItemCount() {
DCHECK(importer_host_.get());
- int item_count = importer_host_->GetAvailableProfileCount();
- if (checkbox_items_.size() < static_cast<size_t>(item_count))
- checkbox_items_.resize(item_count, initial_state_);
- return item_count;
+ return checkbox_items_.size();
}
string16 ImporterView::GetItemAt(int index) {
DCHECK(importer_host_.get());
- return WideToUTF16Hack(importer_host_->GetSourceProfileNameAt(index));
+
+ if (!importer_host_->source_profiles_loaded())
+ return l10n_util::GetStringUTF16(IDS_IMPORT_LOADING_PROFILES);
+ else
+ return WideToUTF16Hack(importer_host_->GetSourceProfileNameAt(index));
}
void ImporterView::ItemChanged(views::Combobox* combobox,
@@ -199,6 +199,11 @@ void ImporterView::ItemChanged(views::Combobox* combobox,
if (prev_index == new_index)
return;
+ if (!importer_host_->source_profiles_loaded()) {
+ SetCheckedItemsState(0);
+ return;
+ }
+
// Save the current state
uint16 prev_items = GetCheckedItems();
checkbox_items_[prev_index] = prev_items;
@@ -213,6 +218,15 @@ void ImporterView::ItemChanged(views::Combobox* combobox,
SetCheckedItems(new_items);
}
+void ImporterView::SourceProfilesLoaded() {
+ DCHECK(importer_host_->source_profiles_loaded());
+ checkbox_items_.resize(
+ importer_host_->GetAvailableProfileCount(), initial_state_);
+
+ // Reload the profile combobox.
+ profile_combobox_->ModelChanged();
+}
+
void ImporterView::ImportCanceled() {
ImportComplete();
}
@@ -282,6 +296,5 @@ void ImporterView::SetCheckedItems(uint16 items) {
passwords_checkbox_->SetChecked(!!(items & importer::PASSWORDS));
if (search_engines_checkbox_->IsEnabled())
- search_engines_checkbox_->SetChecked(!!(items &
- importer::SEARCH_ENGINES));
+ search_engines_checkbox_->SetChecked(!!(items & importer::SEARCH_ENGINES));
}
diff --git a/chrome/browser/ui/views/importer_view.h b/chrome/browser/ui/views/importer_view.h
index ca1ce1c..0d06485 100644
--- a/chrome/browser/ui/views/importer_view.h
+++ b/chrome/browser/ui/views/importer_view.h
@@ -31,6 +31,7 @@ class ImporterView : public views::View,
public views::ButtonListener,
public ComboboxModel,
public views::Combobox::Listener,
+ public ImporterList::Observer,
public ImportObserver {
public:
// Creates a new ImporterView. |initial_state| is a bitmask of ImportItems.
@@ -38,11 +39,11 @@ class ImporterView : public views::View,
ImporterView(Profile* profile, int initial_state);
virtual ~ImporterView();
- // Overridden from views::View:
+ // views::View implementation.
virtual gfx::Size GetPreferredSize();
virtual void Layout();
- // Overridden from views::DialogDelegate:
+ // views::DialogDelegate implementation.
virtual std::wstring GetDialogButtonLabel(
MessageBoxFlags::DialogButton button) const;
virtual bool IsDialogButtonEnabled(
@@ -52,19 +53,22 @@ class ImporterView : public views::View,
virtual bool Accept();
virtual views::View* GetContentsView();
- // Overridden from views::ButtonListener:
+ // views::ButtonListener implementation.
virtual void ButtonPressed(views::Button* sender, const views::Event& event);
- // Overridden from ComboboxModel:
+ // ComboboxModel implementation.
virtual int GetItemCount();
virtual string16 GetItemAt(int index);
- // Overridden from ChromeViews::Combobox::Listener:
+ // ChromeViews::Combobox::Listener implementation.
virtual void ItemChanged(views::Combobox* combobox,
int prev_index,
int new_index);
- // Overridden from ImportObserver:
+ // ImporterList::Observer implementation.
+ virtual void SourceProfilesLoaded();
+
+ // ImportObserver implementation.
virtual void ImportCanceled();
virtual void ImportComplete();
diff --git a/chrome/browser/ui/views/info_bubble.cc b/chrome/browser/ui/views/info_bubble.cc
index befb716..cc9e574 100644
--- a/chrome/browser/ui/views/info_bubble.cc
+++ b/chrome/browser/ui/views/info_bubble.cc
@@ -4,9 +4,11 @@
#include "chrome/browser/views/info_bubble.h"
+#include <vector>
+
#include "app/keyboard_codes.h"
#include "app/slide_animation.h"
-#include "chrome/browser/window_sizer.h"
+#include "chrome/browser/ui/window_sizer.h"
#include "chrome/common/notification_service.h"
#include "gfx/canvas_skia.h"
#include "gfx/color_utils.h"
@@ -20,9 +22,11 @@
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/wm_ipc.h"
-#include "cros/chromeos_wm_ipc_enums.h"
+#include "third_party/cros/chromeos_wm_ipc_enums.h"
#endif
+using std::vector;
+
// How long the fade should last for.
static const int kHideFadeDurationMS = 200;
@@ -256,8 +260,10 @@ InfoBubble* InfoBubble::ShowFocusless(
const gfx::Rect& position_relative_to,
BubbleBorder::ArrowLocation arrow_location,
views::View* contents,
- InfoBubbleDelegate* delegate) {
- InfoBubble* window = new InfoBubble(views::WidgetGtk::TYPE_POPUP);
+ InfoBubbleDelegate* delegate,
+ bool show_while_screen_is_locked) {
+ InfoBubble* window = new InfoBubble(views::WidgetGtk::TYPE_POPUP,
+ show_while_screen_is_locked);
window->Init(parent, position_relative_to, arrow_location,
contents, delegate);
return window;
@@ -317,17 +323,22 @@ InfoBubble::InfoBubble()
delegate_(NULL),
show_status_(kOpen),
fade_away_on_close_(false),
+#if defined(OS_CHROMEOS)
+ show_while_screen_is_locked_(false),
+#endif
arrow_location_(BubbleBorder::NONE),
contents_(NULL) {
}
#if defined(OS_CHROMEOS)
-InfoBubble::InfoBubble(views::WidgetGtk::Type type)
+InfoBubble::InfoBubble(views::WidgetGtk::Type type,
+ bool show_while_screen_is_locked)
: WidgetGtk(type),
border_contents_(NULL),
delegate_(NULL),
show_status_(kOpen),
fade_away_on_close_(false),
+ show_while_screen_is_locked_(show_while_screen_is_locked),
arrow_location_(BubbleBorder::NONE),
contents_(NULL) {
}
@@ -380,10 +391,14 @@ void InfoBubble::Init(views::Widget* parent,
make_transient_to_parent();
WidgetGtk::InitWithWidget(parent, gfx::Rect());
#if defined(OS_CHROMEOS)
- chromeos::WmIpc::instance()->SetWindowType(
- GetNativeView(),
- chromeos::WM_IPC_WINDOW_CHROME_INFO_BUBBLE,
- NULL);
+ {
+ vector<int> params;
+ params.push_back(show_while_screen_is_locked_ ? 1 : 0);
+ chromeos::WmIpc::instance()->SetWindowType(
+ GetNativeView(),
+ chromeos::WM_IPC_WINDOW_CHROME_INFO_BUBBLE,
+ &params);
+ }
#endif
#endif
diff --git a/chrome/browser/ui/views/info_bubble.h b/chrome/browser/ui/views/info_bubble.h
index a0db967..d32b4b5 100644
--- a/chrome/browser/ui/views/info_bubble.h
+++ b/chrome/browser/ui/views/info_bubble.h
@@ -201,13 +201,17 @@ class InfoBubble
InfoBubbleDelegate* delegate);
#if defined(OS_CHROMEOS)
- // Shows the InfoBubble not grabbing the focus. Others are the same as above.
- // TYPE_POPUP widget is used to achieve the focusless effect.
+ // Shows the InfoBubble without grabbing the focus. Others are the same as
+ // above. TYPE_POPUP widget is used to achieve the focusless effect.
+ // If |show_while_screen_is_locked| is true, a property is set telling the
+ // window manager to continue showing the bubble even while the screen is
+ // locked.
static InfoBubble* ShowFocusless(views::Widget* parent,
const gfx::Rect& position_relative_to,
BubbleBorder::ArrowLocation arrow_location,
views::View* contents,
- InfoBubbleDelegate* delegate);
+ InfoBubbleDelegate* delegate,
+ bool show_while_screen_is_locked);
#endif
// Resizes and potentially moves the InfoBubble to best accommodate the
@@ -234,7 +238,7 @@ class InfoBubble
protected:
InfoBubble();
#if defined(OS_CHROMEOS)
- explicit InfoBubble(views::WidgetGtk::Type type);
+ InfoBubble(views::WidgetGtk::Type type, bool show_while_screen_is_locked);
#endif
virtual ~InfoBubble();
@@ -299,6 +303,12 @@ class InfoBubble
// Whether to fade away when the bubble closes.
bool fade_away_on_close_;
+#if defined(OS_CHROMEOS)
+ // Should we set a property telling the window manager to show this window
+ // onscreen even when the screen is locked?
+ bool show_while_screen_is_locked_;
+#endif
+
gfx::Rect position_relative_to_;
BubbleBorder::ArrowLocation arrow_location_;
diff --git a/chrome/browser/ui/views/infobars/infobar_container.cc b/chrome/browser/ui/views/infobars/infobar_container.cc
index 5779fde..527aacc 100644
--- a/chrome/browser/ui/views/infobars/infobar_container.cc
+++ b/chrome/browser/ui/views/infobars/infobar_container.cc
@@ -7,9 +7,10 @@
#include "app/l10n_util.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/view_ids.h"
-#include "chrome/browser/views/infobars/infobars.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/infobars/infobars.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
#include "grit/generated_resources.h"
// InfoBarContainer, public: ---------------------------------------------------
diff --git a/chrome/browser/ui/views/instant_confirm_view.cc b/chrome/browser/ui/views/instant_confirm_view.cc
index f8686ee..cddc79b 100644
--- a/chrome/browser/ui/views/instant_confirm_view.cc
+++ b/chrome/browser/ui/views/instant_confirm_view.cc
@@ -9,7 +9,7 @@
#include "chrome/browser/instant/instant_confirm_dialog.h"
#include "chrome/browser/instant/instant_controller.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/ui/views/js_modal_dialog_views.cc b/chrome/browser/ui/views/js_modal_dialog_views.cc
index c6348ea..ac20b4e 100644
--- a/chrome/browser/ui/views/js_modal_dialog_views.cc
+++ b/chrome/browser/ui/views/js_modal_dialog_views.cc
@@ -7,7 +7,7 @@
#include "app/keyboard_codes.h"
#include "app/l10n_util.h"
#include "app/message_box_flags.h"
-#include "chrome/browser/app_modal_dialog.h"
+#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
#include "chrome/browser/views/window.h"
#include "grit/generated_resources.h"
#include "views/controls/message_box_view.h"
diff --git a/chrome/browser/ui/views/js_modal_dialog_views.h b/chrome/browser/ui/views/js_modal_dialog_views.h
index ce7e221..2ff27f9 100644
--- a/chrome/browser/ui/views/js_modal_dialog_views.h
+++ b/chrome/browser/ui/views/js_modal_dialog_views.h
@@ -6,12 +6,12 @@
#define CHROME_BROWSER_UI_VIEWS_JS_MODAL_DIALOG_VIEWS_H_
#pragma once
-#include "chrome/browser/js_modal_dialog.h"
+#include "chrome/browser/ui/app_modal_dialogs/js_modal_dialog.h"
#include <string>
#include "app/message_box_flags.h"
-#include "chrome/browser/native_app_modal_dialog.h"
+#include "chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h"
#include "views/window/dialog_delegate.h"
class MessageBoxView;
diff --git a/chrome/browser/ui/views/keyboard_overlay_delegate.cc b/chrome/browser/ui/views/keyboard_overlay_delegate.cc
new file mode 100644
index 0000000..5673f02
--- /dev/null
+++ b/chrome/browser/ui/views/keyboard_overlay_delegate.cc
@@ -0,0 +1,70 @@
+// 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.
+
+#include "chrome/browser/ui/views/keyboard_overlay_delegate.h"
+
+#include "app/l10n_util.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/dom_ui/html_dialog_ui.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/common/url_constants.h"
+#include "grit/generated_resources.h"
+
+
+void KeyboardOverlayDelegate::ShowDialog(gfx::NativeWindow owning_window) {
+ Browser* browser = BrowserList::GetLastActive();
+ KeyboardOverlayDelegate* delegate = new KeyboardOverlayDelegate(
+ l10n_util::GetString(IDS_KEYBOARD_OVERLAY_TITLE));
+ DCHECK(browser);
+ browser->BrowserShowHtmlDialog(delegate, owning_window);
+}
+
+KeyboardOverlayDelegate::KeyboardOverlayDelegate(
+ const std::wstring& title)
+ : title_(title) {
+}
+
+KeyboardOverlayDelegate::~KeyboardOverlayDelegate() {
+}
+
+bool KeyboardOverlayDelegate::IsDialogModal() const {
+ return true;
+}
+
+std::wstring KeyboardOverlayDelegate::GetDialogTitle() const {
+ return title_;
+}
+
+GURL KeyboardOverlayDelegate::GetDialogContentURL() const {
+ std::string url_string(chrome::kChromeUIKeyboardOverlayURL);
+ return GURL(url_string);
+}
+
+void KeyboardOverlayDelegate::GetDOMMessageHandlers(
+ std::vector<DOMMessageHandler*>* handlers) const {
+}
+
+void KeyboardOverlayDelegate::GetDialogSize(
+ gfx::Size* size) const {
+ size->SetSize(1170, 483);
+}
+
+std::string KeyboardOverlayDelegate::GetDialogArgs() const {
+ return "[]";
+}
+
+void KeyboardOverlayDelegate::OnDialogClosed(
+ const std::string& json_retval) {
+ delete this;
+ return;
+}
+
+void KeyboardOverlayDelegate::OnCloseContents(TabContents* source,
+ bool* out_close_dialog) {
+}
+
+bool KeyboardOverlayDelegate::ShouldShowDialogTitle() const {
+ return false;
+}
diff --git a/chrome/browser/ui/views/keyboard_overlay_delegate.h b/chrome/browser/ui/views/keyboard_overlay_delegate.h
new file mode 100644
index 0000000..9c957e1
--- /dev/null
+++ b/chrome/browser/ui/views/keyboard_overlay_delegate.h
@@ -0,0 +1,39 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_KEYBOARD_OVERLAY_DELEGATE_H_
+#define CHROME_BROWSER_UI_VIEWS_KEYBOARD_OVERLAY_DELEGATE_H_
+
+#include "gfx/native_widget_types.h"
+#include "chrome/browser/dom_ui/html_dialog_ui.h"
+
+class KeyboardOverlayDelegate : public HtmlDialogUIDelegate {
+ public:
+ KeyboardOverlayDelegate(const std::wstring& title);
+
+ // Shows the keyboard overlay dialog box.
+ static void ShowDialog(gfx::NativeWindow owning_window);
+
+ private:
+ ~KeyboardOverlayDelegate();
+
+ // Overridden from HtmlDialogUI::Delegate:
+ virtual bool IsDialogModal() const;
+ virtual std::wstring GetDialogTitle() const;
+ virtual GURL GetDialogContentURL() const;
+ virtual void GetDOMMessageHandlers(
+ std::vector<DOMMessageHandler*>* handlers) const;
+ virtual void GetDialogSize(gfx::Size* size) const;
+ virtual std::string GetDialogArgs() const;
+ virtual void OnDialogClosed(const std::string& json_retval);
+ virtual void OnCloseContents(TabContents* source, bool* out_close_dialog);
+ virtual bool ShouldShowDialogTitle() const;
+
+ // The dialog title.
+ std::wstring title_;
+
+ DISALLOW_COPY_AND_ASSIGN(KeyboardOverlayDelegate);
+};
+
+#endif // CHROME_BROWSER_UI_VIEWS_KEYBOARD_OVERLAY_DELEGATE_H_
diff --git a/chrome/browser/ui/views/keyword_editor_view.cc b/chrome/browser/ui/views/keyword_editor_view.cc
index 6cd877c..610fa9e 100644
--- a/chrome/browser/ui/views/keyword_editor_view.cc
+++ b/chrome/browser/ui/views/keyword_editor_view.cc
@@ -11,7 +11,7 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/search_engines/template_url_table_model.h"
diff --git a/chrome/browser/ui/views/location_bar/click_handler.cc b/chrome/browser/ui/views/location_bar/click_handler.cc
index 92b2bb7..38002ff 100644
--- a/chrome/browser/ui/views/location_bar/click_handler.cc
+++ b/chrome/browser/ui/views/location_bar/click_handler.cc
@@ -6,8 +6,8 @@
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
-#include "chrome/browser/views/location_bar/location_bar_view.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
#include "views/view.h"
ClickHandler::ClickHandler(const views::View* owner,
diff --git a/chrome/browser/ui/views/location_bar/content_setting_image_view.cc b/chrome/browser/ui/views/location_bar/content_setting_image_view.cc
index 7115f15..cd151bb 100644
--- a/chrome/browser/ui/views/location_bar/content_setting_image_view.cc
+++ b/chrome/browser/ui/views/location_bar/content_setting_image_view.cc
@@ -11,9 +11,9 @@
#include "chrome/browser/content_setting_bubble_model.h"
#include "chrome/browser/content_setting_image_model.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
-#include "chrome/browser/views/content_setting_bubble_contents.h"
-#include "chrome/browser/views/location_bar/location_bar_view.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "chrome/browser/ui/views/content_setting_bubble_contents.h"
+#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
#include "chrome/common/chrome_switches.h"
#include "gfx/canvas.h"
#include "gfx/canvas_skia.h"
diff --git a/chrome/browser/ui/views/location_bar/keyword_hint_view.cc b/chrome/browser/ui/views/location_bar/keyword_hint_view.cc
index eec0dd1..5d9192f 100644
--- a/chrome/browser/ui/views/location_bar/keyword_hint_view.cc
+++ b/chrome/browser/ui/views/location_bar/keyword_hint_view.cc
@@ -8,7 +8,7 @@
#include "app/resource_bundle.h"
#include "base/logging.h"
#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "gfx/canvas.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc
index bc15f2f..7915916 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -19,24 +19,24 @@
#include "chrome/browser/autocomplete/autocomplete_popup_model.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/extensions/extension_browser_event_router.h"
-#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/instant/instant_controller.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
-#include "chrome/browser/tab_contents_wrapper.h"
-#include "chrome/browser/ui/views/location_bar/suggested_text_view.h"
-#include "chrome/browser/view_ids.h"
-#include "chrome/browser/views/browser_dialogs.h"
-#include "chrome/browser/views/location_bar/content_setting_image_view.h"
-#include "chrome/browser/views/location_bar/ev_bubble_view.h"
-#include "chrome/browser/views/location_bar/keyword_hint_view.h"
-#include "chrome/browser/views/location_bar/location_icon_view.h"
-#include "chrome/browser/views/location_bar/page_action_image_view.h"
-#include "chrome/browser/views/location_bar/page_action_with_badge_view.h"
-#include "chrome/browser/views/location_bar/selected_keyword_view.h"
-#include "chrome/browser/views/location_bar/star_view.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/browser_dialogs.h"
+#include "chrome/browser/ui/views/location_bar/content_setting_image_view.h"
+#include "chrome/browser/ui/views/location_bar/ev_bubble_view.h"
+#include "chrome/browser/ui/views/location_bar/keyword_hint_view.h"
+#include "chrome/browser/ui/views/location_bar/location_icon_view.h"
+#include "chrome/browser/ui/views/location_bar/page_action_image_view.h"
+#include "chrome/browser/ui/views/location_bar/page_action_with_badge_view.h"
+#include "chrome/browser/ui/views/location_bar/selected_keyword_view.h"
+#include "chrome/browser/ui/views/location_bar/star_view.h"
+#include "chrome/common/notification_service.h"
#include "gfx/canvas_skia.h"
#include "gfx/color_utils.h"
#include "gfx/skia_util.h"
@@ -46,6 +46,7 @@
#include "views/drag_utils.h"
#if defined(OS_WIN)
+#include "chrome/browser/ui/views/location_bar/suggested_text_view.h"
#include "chrome/browser/views/first_run_bubble.h"
#endif
@@ -103,7 +104,9 @@ LocationBarView::LocationBarView(Profile* profile,
ev_bubble_view_(NULL),
location_entry_view_(NULL),
selected_keyword_view_(NULL),
+#if defined(OS_WIN)
suggested_text_view_(NULL),
+#endif
keyword_hint_view_(NULL),
star_view_(NULL),
mode_(mode),
@@ -408,12 +411,14 @@ gfx::Point LocationBarView::GetLocationEntryOrigin() const {
return origin;
}
+#if defined(OS_WIN)
void LocationBarView::OnCommitSuggestedText() {
InstantController* instant = delegate_->GetInstant();
DCHECK(instant);
DCHECK(suggested_text_view_);
OnCommitSuggestedText(location_entry_->GetText());
}
+#endif
gfx::Size LocationBarView::GetPreferredSize() {
return gfx::Size(0, GetThemeProvider()->GetBitmapNamed(mode_ == POPUP ?
@@ -525,7 +530,7 @@ void LocationBarView::Layout() {
const TemplateURL* template_url =
profile_->GetTemplateURLModel()->GetTemplateURLForKeyword(keyword);
if (template_url && template_url->IsExtensionKeyword()) {
- const SkBitmap& bitmap = profile_->GetExtensionsService()->
+ const SkBitmap& bitmap = profile_->GetExtensionService()->
GetOmniboxIcon(template_url->GetExtensionId());
selected_keyword_view_->SetImage(bitmap);
selected_keyword_view_->SetItemPadding(kExtensionItemPadding);
@@ -613,6 +618,7 @@ void LocationBarView::Layout() {
}
}
+#if defined(OS_WIN)
// Layout out the suggested text view right aligned to the location
// entry. Only show the suggested text if we can fit the text from one
// character before the end of the selection to the end of the text and the
@@ -642,6 +648,7 @@ void LocationBarView::Layout() {
location_bounds.height());
}
}
+#endif
location_entry_view_->SetBounds(location_bounds);
}
@@ -775,13 +782,23 @@ void LocationBarView::OnAutocompleteWillAccept() {
bool LocationBarView::OnCommitSuggestedText(const std::wstring& typed_text) {
InstantController* instant = delegate_->GetInstant();
- if (!instant || !HasValidSuggestText()) {
+ if (!instant)
+ return false;
+
+#if defined(OS_WIN)
+ if (!HasValidSuggestText())
return false;
- }
location_entry_->model()->FinalizeInstantQuery(
typed_text,
suggested_text_view_->GetText());
return true;
+#else
+ return location_entry_->CommitInstantSuggestion();
+#endif
+}
+
+bool LocationBarView::AcceptCurrentInstantPreview() {
+ return InstantController::CommitIfCurrent(delegate_->GetInstant());
}
void LocationBarView::OnSetSuggestedSearchText(const string16& suggested_text) {
@@ -868,8 +885,12 @@ void LocationBarView::OnChanged() {
}
void LocationBarView::OnSelectionBoundsChanged() {
+#if defined(OS_WIN)
if (suggested_text_view_)
suggested_text_view_->StopAnimation();
+#else
+ NOTREACHED();
+#endif
}
void LocationBarView::OnInputInProgress(bool in_progress) {
@@ -922,8 +943,8 @@ void LocationBarView::LayoutView(views::View* view,
void LocationBarView::RefreshContentSettingViews() {
for (ContentSettingViews::const_iterator i(content_setting_views_.begin());
i != content_setting_views_.end(); ++i) {
- (*i)->UpdateFromTabContents(
- model_->input_in_progress() ? NULL : GetTabContentsFromDelegate(delegate_));
+ (*i)->UpdateFromTabContents(model_->input_in_progress() ? NULL :
+ GetTabContentsFromDelegate(delegate_));
}
}
@@ -938,7 +959,7 @@ void LocationBarView::RefreshPageActionViews() {
if (mode_ != NORMAL)
return;
- ExtensionsService* service = profile_->GetExtensionsService();
+ ExtensionService* service = profile_->GetExtensionService();
if (!service)
return;
@@ -1045,6 +1066,7 @@ std::string LocationBarView::GetClassName() const {
}
bool LocationBarView::SkipDefaultKeyEventProcessing(const views::KeyEvent& e) {
+#if defined(OS_WIN)
if (views::FocusManager::IsTabTraversalKeyEvent(e)) {
if (HasValidSuggestText()) {
// Return true so that the edit sees the tab and commits the suggestion.
@@ -1054,27 +1076,18 @@ bool LocationBarView::SkipDefaultKeyEventProcessing(const views::KeyEvent& e) {
// Return true so the edit gets the tab event and enters keyword mode.
return true;
}
- InstantController* instant = delegate_->GetInstant();
- if (instant && instant->IsCurrent()) {
- // Tab while showing instant commits instant immediately.
- instant->CommitCurrentPreview(INSTANT_COMMIT_PRESSED_ENTER);
- // Return true so that focus traversal isn't attempted. The edit ends
- // up doing nothing in this case.
+
+ // Tab while showing instant commits instant immediately.
+ // Return true so that focus traversal isn't attempted. The edit ends
+ // up doing nothing in this case.
+ if (AcceptCurrentInstantPreview())
return true;
- }
}
-#if defined(OS_WIN)
return location_entry_->SkipDefaultKeyEventProcessing(e);
#else
- // TODO(jcampan): We need to refactor the code of
- // AutocompleteEditViewWin::SkipDefaultKeyEventProcessing into this class so
- // it can be shared between Windows and Linux.
- // For now, we just override back-space and tab keys, as back-space is the
- // accelerator for back navigation and tab key is used by some input methods.
- if (e.GetKeyCode() == app::VKEY_BACK ||
- views::FocusManager::IsTabTraversalKeyEvent(e))
- return true;
+ // This method is not used for Linux ports. See FocusManager::OnKeyEvent() in
+ // src/views/focus/focus_manager.cc for details.
return false;
#endif
}
@@ -1127,6 +1140,7 @@ void LocationBarView::ShowFirstRunBubble(FirstRun::BubbleType bubble_type) {
}
void LocationBarView::SetSuggestedText(const string16& input) {
+#if defined(OS_WIN)
// Don't show the suggested text if inline autocomplete is prevented.
string16 text = location_entry_->model()->UseVerbatimInstant() ?
string16() : input;
@@ -1143,7 +1157,8 @@ void LocationBarView::SetSuggestedText(const string16& input) {
} else if (suggested_text_view_->GetText() != UTF16ToWide(text)) {
suggested_text_view_->SetText(UTF16ToWide(text));
}
- suggested_text_view_->StartAnimation();
+ if (!location_entry_->IsImeComposing())
+ suggested_text_view_->StartAnimation();
} else if (suggested_text_view_) {
delete suggested_text_view_;
suggested_text_view_ = NULL;
@@ -1153,6 +1168,9 @@ void LocationBarView::SetSuggestedText(const string16& input) {
Layout();
SchedulePaint();
+#else
+ location_entry_->SetInstantSuggestion(UTF16ToUTF8(input));
+#endif
}
std::wstring LocationBarView::GetInputString() const {
@@ -1245,7 +1263,9 @@ void LocationBarView::OnTemplateURLModelChanged() {
ShowFirstRunBubble(bubble_type_);
}
+#if defined(OS_WIN)
bool LocationBarView::HasValidSuggestText() {
return suggested_text_view_ && !suggested_text_view_->size().IsEmpty() &&
!suggested_text_view_->GetText().empty();
}
+#endif
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.h b/chrome/browser/ui/views/location_bar/location_bar_view.h
index 5e45e10..317bd78 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.h
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.h
@@ -13,10 +13,9 @@
#include "chrome/browser/autocomplete/autocomplete_edit.h"
#include "chrome/browser/extensions/extension_context_menu_model.h"
#include "chrome/browser/first_run/first_run.h"
-#include "chrome/browser/location_bar.h"
#include "chrome/browser/search_engines/template_url_model_observer.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/toolbar_model.h"
+#include "chrome/browser/ui/omnibox/location_bar.h"
+#include "chrome/browser/ui/toolbar/toolbar_model.h"
#include "chrome/browser/views/extensions/extension_popup.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
@@ -43,7 +42,7 @@ class PageActionWithBadgeView;
class Profile;
class SelectedKeywordView;
class StarView;
-class SuggestedTextView;
+class TabContents;
class TabContentsWrapper;
class TemplateURLModel;
@@ -52,6 +51,10 @@ class HorizontalPainter;
class Label;
};
+#if defined(OS_WIN)
+class SuggestedTextView;
+#endif
+
/////////////////////////////////////////////////////////////////////////////
//
// LocationBarView class
@@ -154,8 +157,10 @@ class LocationBarView : public LocationBar,
// appears, not where the icons are shown).
gfx::Point GetLocationEntryOrigin() const;
+#if defined(OS_WIN)
// Invoked from SuggestedTextView when the suggested text should be committed.
void OnCommitSuggestedText();
+#endif
// Sizing functions
virtual gfx::Size GetPreferredSize();
@@ -192,6 +197,7 @@ class LocationBarView : public LocationBar,
virtual void OnAutocompleteLosingFocus(gfx::NativeView view_gaining_focus);
virtual void OnAutocompleteWillAccept();
virtual bool OnCommitSuggestedText(const std::wstring& typed_text);
+ virtual bool AcceptCurrentInstantPreview();
virtual void OnSetSuggestedSearchText(const string16& suggested_text);
virtual void OnPopupBoundsChanged(const gfx::Rect& bounds);
virtual void OnAutocompleteAccept(const GURL& url,
@@ -309,14 +315,14 @@ class LocationBarView : public LocationBar,
#if defined(OS_WIN)
// Helper for the Mouse event handlers that does all the real work.
void OnMouseEvent(const views::MouseEvent& event, UINT msg);
+
+ // Returns true if the suggest text is valid.
+ bool HasValidSuggestText();
#endif
// Helper to show the first run info bubble.
void ShowFirstRunBubbleInternal(FirstRun::BubbleType bubble_type);
- // Returns true if the suggest text is valid.
- bool HasValidSuggestText();
-
// Current profile. Not owned by us.
Profile* profile_;
@@ -370,9 +376,11 @@ class LocationBarView : public LocationBar,
// Shown if the user has selected a keyword.
SelectedKeywordView* selected_keyword_view_;
+#if defined(OS_WIN)
// View responsible for showing suggested text. This is NULL when there is no
// suggested text.
SuggestedTextView* suggested_text_view_;
+#endif
// Shown if the selected url has a corresponding keyword.
KeywordHintView* keyword_hint_view_;
diff --git a/chrome/browser/ui/views/location_bar/page_action_image_view.cc b/chrome/browser/ui/views/location_bar/page_action_image_view.cc
index c7155bf..0b0bf35 100644
--- a/chrome/browser/ui/views/location_bar/page_action_image_view.cc
+++ b/chrome/browser/ui/views/location_bar/page_action_image_view.cc
@@ -7,8 +7,8 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/extensions/extension_browser_event_router.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/views/frame/browser_view.h"
#include "chrome/browser/views/location_bar/location_bar_view.h"
#include "chrome/browser/platform_util.h"
@@ -26,7 +26,7 @@ PageActionImageView::PageActionImageView(LocationBarView* owner,
current_tab_id_(-1),
preview_enabled_(false),
popup_(NULL) {
- const Extension* extension = profile->GetExtensionsService()->
+ const Extension* extension = profile->GetExtensionService()->
GetExtensionById(page_action->extension_id(), false);
DCHECK(extension);
@@ -146,7 +146,7 @@ bool PageActionImageView::OnKeyPressed(const views::KeyEvent& e) {
void PageActionImageView::ShowContextMenu(const gfx::Point& p,
bool is_mouse_gesture) {
- const Extension* extension = profile_->GetExtensionsService()->
+ const Extension* extension = profile_->GetExtensionService()->
GetExtensionById(page_action()->extension_id(), false);
Browser* browser = BrowserView::GetBrowserViewForNativeWindow(
platform_util::GetTopLevel(GetWidget()->GetNativeView()))->browser();
diff --git a/chrome/browser/ui/views/location_bar/selected_keyword_view.cc b/chrome/browser/ui/views/location_bar/selected_keyword_view.cc
index 182015b..69b639c 100644
--- a/chrome/browser/ui/views/location_bar/selected_keyword_view.cc
+++ b/chrome/browser/ui/views/location_bar/selected_keyword_view.cc
@@ -7,9 +7,9 @@
#include "app/l10n_util.h"
#include "base/logging.h"
#include "chrome/browser/search_engines/template_url_model.h"
-#include "chrome/browser/location_bar_util.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/views/location_bar/keyword_hint_view.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/omnibox/location_bar_util.h"
+#include "chrome/browser/ui/views/location_bar/keyword_hint_view.h"
#include "grit/generated_resources.h"
SelectedKeywordView::SelectedKeywordView(const int background_images[],
diff --git a/chrome/browser/ui/views/location_bar/star_view.cc b/chrome/browser/ui/views/location_bar/star_view.cc
index 7d22441..95de4c0 100644
--- a/chrome/browser/ui/views/location_bar/star_view.cc
+++ b/chrome/browser/ui/views/location_bar/star_view.cc
@@ -8,8 +8,8 @@
#include "app/resource_bundle.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/command_updater.h"
-#include "chrome/browser/view_ids.h"
-#include "chrome/browser/views/browser_dialogs.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/browser_dialogs.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
diff --git a/chrome/browser/ui/views/login_view.h b/chrome/browser/ui/views/login_view.h
index 0a345bf..2c529f5 100644
--- a/chrome/browser/ui/views/login_view.h
+++ b/chrome/browser/ui/views/login_view.h
@@ -7,7 +7,7 @@
#pragma once
#include "base/task.h"
-#include "chrome/browser/login_model.h"
+#include "chrome/browser/ui/login/login_model.h"
#include "views/view.h"
namespace views {
diff --git a/chrome/browser/ui/views/modal_dialog_delegate.cc b/chrome/browser/ui/views/modal_dialog_delegate.cc
deleted file mode 100644
index a08d611..0000000
--- a/chrome/browser/ui/views/modal_dialog_delegate.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// 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.
-
-#include "chrome/browser/views/modal_dialog_delegate.h"
-
-#include "base/logging.h"
-#include "chrome/browser/views/window.h"
-#include "views/window/window.h"
-
-void ModalDialogDelegate::ShowModalDialog() {
- gfx::NativeWindow root_hwnd = GetDialogRootWindow();
- // GetMessageBoxRootWindow() will be NULL if there's no selected tab (e.g.,
- // during shutdown), in which case we simply skip showing this dialog.
- if (!root_hwnd) {
- Cancel();
- } else {
- dialog_ = browser::CreateViewsWindow(root_hwnd, gfx::Rect(), this);
- dialog_->Show();
- }
-}
-
-void ModalDialogDelegate::ActivateModalDialog() {
- DCHECK(dialog_);
- // Ensure that the dialog is visible and at the top of the z-order. These
- // conditions may not be true if the dialog was opened on a different virtual
- // desktop to the one the browser window is on.
- dialog_->Show();
- dialog_->Activate();
-}
-
-void ModalDialogDelegate::CloseModalDialog() {
- // If the dialog is visible close it.
- if (dialog_)
- dialog_->Close();
-}
-
-ModalDialogDelegate::ModalDialogDelegate() : dialog_(NULL) {
-}
-
diff --git a/chrome/browser/ui/views/modal_dialog_delegate.h b/chrome/browser/ui/views/modal_dialog_delegate.h
deleted file mode 100644
index d03efc7..0000000
--- a/chrome/browser/ui/views/modal_dialog_delegate.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_UI_VIEWS_MODAL_DIALOG_DELEGATE_H_
-#define CHROME_BROWSER_UI_VIEWS_MODAL_DIALOG_DELEGATE_H_
-#pragma once
-
-#include "views/window/dialog_delegate.h"
-
-namespace views {
-class Window;
-}
-
-class ModalDialogDelegate : public views::DialogDelegate {
- public:
- virtual ~ModalDialogDelegate() {}
- // Methods called from AppModalDialog.
- virtual gfx::NativeWindow GetDialogRootWindow() = 0;
- virtual void ShowModalDialog();
- virtual void ActivateModalDialog();
- virtual void CloseModalDialog();
- protected:
- ModalDialogDelegate();
-
- // The dialog if it is currently visible.
- views::Window* dialog_;
-};
-
-#endif // CHROME_BROWSER_UI_VIEWS_MODAL_DIALOG_DELEGATE_H_
-
diff --git a/chrome/browser/ui/views/notifications/balloon_view.cc b/chrome/browser/ui/views/notifications/balloon_view.cc
index d2696d4..034e0a0 100644
--- a/chrome/browser/ui/views/notifications/balloon_view.cc
+++ b/chrome/browser/ui/views/notifications/balloon_view.cc
@@ -16,7 +16,6 @@
#include "chrome/browser/notifications/desktop_notification_service.h"
#include "chrome/browser/notifications/notification.h"
#include "chrome/browser/notifications/notification_options_menu_model.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/themes/browser_theme_provider.h"
@@ -132,6 +131,10 @@ gfx::Size BalloonViewImpl::GetSize() const {
return gfx::Size(GetTotalWidth(), GetTotalHeight());
}
+BalloonHost* BalloonViewImpl::GetHost() const {
+ return html_contents_.get();
+}
+
void BalloonViewImpl::RunMenu(views::View* source, const gfx::Point& pt) {
RunOptionsMenu(pt);
}
@@ -167,6 +170,10 @@ void BalloonViewImpl::DidChangeBounds(const gfx::Rect& previous,
SizeContentsWindow();
}
+gfx::Size BalloonViewImpl::GetPreferredSize() {
+ return gfx::Size(1000, 1000);
+}
+
void BalloonViewImpl::SizeContentsWindow() {
if (!html_container_ || !frame_container_)
return;
diff --git a/chrome/browser/ui/views/notifications/balloon_view.h b/chrome/browser/ui/views/notifications/balloon_view.h
index 7372c84..c069a0a 100644
--- a/chrome/browser/ui/views/notifications/balloon_view.h
+++ b/chrome/browser/ui/views/notifications/balloon_view.h
@@ -15,7 +15,6 @@
#include "chrome/browser/notifications/balloon.h"
#include "chrome/browser/views/notifications/balloon_view_host.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
#include "gfx/path.h"
#include "gfx/point.h"
#include "gfx/rect.h"
@@ -60,23 +59,21 @@ class BalloonViewImpl : public BalloonView,
virtual void RepositionToBalloon();
virtual void Close(bool by_user);
virtual gfx::Size GetSize() const;
- virtual BalloonHost* GetHost() const { return html_contents_.get(); }
+ virtual BalloonHost* GetHost() const;
private:
// views::View interface.
virtual void Paint(gfx::Canvas* canvas);
virtual void DidChangeBounds(const gfx::Rect& previous,
const gfx::Rect& current);
- virtual gfx::Size GetPreferredSize() {
- return gfx::Size(1000, 1000);
- }
+ virtual gfx::Size GetPreferredSize();
// views::ViewMenuDelegate interface.
- void RunMenu(views::View* source, const gfx::Point& pt);
+ virtual void RunMenu(views::View* source, const gfx::Point& pt);
// views::WidgetDelegate interface.
- void DisplayChanged();
- void WorkAreaChanged();
+ virtual void DisplayChanged();
+ virtual void WorkAreaChanged();
// views::ButtonListener interface.
virtual void ButtonPressed(views::Button* sender, const views::Event&);
diff --git a/chrome/browser/ui/views/notifications/balloon_view_host.cc b/chrome/browser/ui/views/notifications/balloon_view_host.cc
index 24a7fe2..eb9cb20 100644
--- a/chrome/browser/ui/views/notifications/balloon_view_host.cc
+++ b/chrome/browser/ui/views/notifications/balloon_view_host.cc
@@ -37,8 +37,8 @@ class BalloonViewHostView : public views::NativeViewHost {
views::View* child) {
NativeViewHost::ViewHierarchyChanged(is_add, parent, child);
if (is_add && GetWidget() && !initialized_) {
- host_->Init(GetWidget()->GetNativeView());
initialized_ = true;
+ host_->Init(GetWidget()->GetNativeView());
}
}
@@ -79,7 +79,7 @@ void BalloonViewHost::InitRenderWidgetHostView() {
RenderWidgetHostViewViews* view_views =
static_cast<RenderWidgetHostViewViews*>(render_widget_host_view_);
view_views->InitAsChild();
- native_host_->Attach(view_views->native_view());
+ native_host_->AttachToView(view_views);
#else
RenderWidgetHostViewGtk* view_gtk =
static_cast<RenderWidgetHostViewGtk*>(render_widget_host_view_);
@@ -90,3 +90,7 @@ void BalloonViewHost::InitRenderWidgetHostView() {
NOTIMPLEMENTED();
#endif
}
+
+RenderWidgetHostView* BalloonViewHost::render_widget_host_view() const {
+ return render_widget_host_view_;
+}
diff --git a/chrome/browser/ui/views/notifications/balloon_view_host.h b/chrome/browser/ui/views/notifications/balloon_view_host.h
index a2f6663..23f82b9 100644
--- a/chrome/browser/ui/views/notifications/balloon_view_host.h
+++ b/chrome/browser/ui/views/notifications/balloon_view_host.h
@@ -39,9 +39,7 @@ class BalloonViewHost : public BalloonHost {
protected:
virtual void InitRenderWidgetHostView();
- virtual RenderWidgetHostView* render_widget_host_view() const {
- return render_widget_host_view_;
- }
+ virtual RenderWidgetHostView* render_widget_host_view() const;
private:
// The platform-specific widget host view. Pointer is owned by the RVH.
diff --git a/chrome/browser/ui/views/options/advanced_contents_view.cc b/chrome/browser/ui/views/options/advanced_contents_view.cc
index 2931598..e6588aa 100644
--- a/chrome/browser/ui/views/options/advanced_contents_view.cc
+++ b/chrome/browser/ui/views/options/advanced_contents_view.cc
@@ -28,25 +28,24 @@
#include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/gears_integration.h"
-#include "chrome/browser/options_util.h"
#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prefs/pref_set_observer.h"
#include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h"
#include "chrome/browser/printing/cloud_print/cloud_print_setup_flow.h"
#include "chrome/browser/printing/cloud_print/cloud_print_url.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/browser/shell_dialogs.h"
-#include "chrome/browser/show_options_url.h"
#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/views/browser_dialogs.h"
-#include "chrome/browser/views/clear_browsing_data.h"
-#include "chrome/browser/views/list_background.h"
-#include "chrome/browser/views/options/content_settings_window_view.h"
-#include "chrome/browser/views/options/fonts_languages_window_view.h"
-#include "chrome/browser/views/restart_message_box.h"
+#include "chrome/browser/ui/options/options_util.h"
+#include "chrome/browser/ui/options/show_options_url.h"
+#include "chrome/browser/ui/views/browser_dialogs.h"
+#include "chrome/browser/ui/views/clear_browsing_data.h"
+#include "chrome/browser/ui/views/list_background.h"
+#include "chrome/browser/ui/views/options/content_settings_window_view.h"
+#include "chrome/browser/ui/views/options/fonts_languages_window_view.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
@@ -524,8 +523,6 @@ void PrivacySection::ButtonPressed(
"Options_MetricsReportingCheckbox_Disable"),
profile()->GetPrefs());
ResolveMetricsReportingEnabled();
- if (enabled == reporting_enabled_checkbox_->checked())
- RestartMessageBox::ShowMessageBox(GetWindow()->GetNativeWindow());
enable_metrics_recording_.SetValue(enabled);
} else if (sender == content_settings_button_) {
UserMetricsRecordAction(UserMetricsAction("Options_ContentSettings"), NULL);
@@ -790,7 +787,6 @@ class SecuritySection : public AdvancedSection,
private:
// Controls for this section:
views::Label* ssl_info_label_;
- views::Checkbox* enable_ssl2_checkbox_;
views::Checkbox* enable_ssl3_checkbox_;
views::Checkbox* enable_tls1_checkbox_;
views::Checkbox* check_for_cert_revocation_checkbox_;
@@ -802,7 +798,6 @@ class SecuritySection : public AdvancedSection,
SecuritySection::SecuritySection(Profile* profile)
: ssl_info_label_(NULL),
- enable_ssl2_checkbox_(NULL),
enable_ssl3_checkbox_(NULL),
enable_tls1_checkbox_(NULL),
check_for_cert_revocation_checkbox_(NULL),
@@ -814,15 +809,7 @@ SecuritySection::SecuritySection(Profile* profile)
void SecuritySection::ButtonPressed(
views::Button* sender, const views::Event& event) {
- if (sender == enable_ssl2_checkbox_) {
- bool enabled = enable_ssl2_checkbox_->checked();
- if (enabled) {
- UserMetricsRecordAction(UserMetricsAction("Options_SSL2_Enable"), NULL);
- } else {
- UserMetricsRecordAction(UserMetricsAction("Options_SSL2_Disable"), NULL);
- }
- net::SSLConfigServiceWin::SetSSL2Enabled(enabled);
- } else if (sender == enable_ssl3_checkbox_) {
+ if (sender == enable_ssl3_checkbox_) {
bool enabled = enable_ssl3_checkbox_->checked();
if (enabled) {
UserMetricsRecordAction(UserMetricsAction("Options_SSL3_Enable"), NULL);
@@ -862,9 +849,6 @@ void SecuritySection::InitControlLayout() {
ssl_info_label_ = new views::Label(
l10n_util::GetString(IDS_OPTIONS_SSL_GROUP_DESCRIPTION));
- enable_ssl2_checkbox_ = new views::Checkbox(
- l10n_util::GetString(IDS_OPTIONS_SSL_USESSL2));
- enable_ssl2_checkbox_->set_listener(this);
enable_ssl3_checkbox_ = new views::Checkbox(
l10n_util::GetString(IDS_OPTIONS_SSL_USESSL3));
enable_ssl3_checkbox_->set_listener(this);
@@ -900,8 +884,6 @@ void SecuritySection::InitControlLayout() {
indented_column_set_id, false);
AddWrappingLabelRow(layout, ssl_info_label_, single_column_view_set_id,
true);
- AddWrappingCheckboxRow(layout, enable_ssl2_checkbox_,
- indented_column_set_id, true);
AddWrappingCheckboxRow(layout, enable_ssl3_checkbox_,
indented_column_set_id, true);
AddWrappingCheckboxRow(layout, enable_tls1_checkbox_,
@@ -916,13 +898,11 @@ void SecuritySection::NotifyPrefChanged(const std::string* pref_name) {
if (!pref_name) {
net::SSLConfig config;
if (net::SSLConfigServiceWin::GetSSLConfigNow(&config)) {
- enable_ssl2_checkbox_->SetChecked(config.ssl2_enabled);
enable_ssl3_checkbox_->SetChecked(config.ssl3_enabled);
enable_tls1_checkbox_->SetChecked(config.tls1_enabled);
check_for_cert_revocation_checkbox_->SetChecked(
config.rev_checking_enabled);
} else {
- enable_ssl2_checkbox_->SetEnabled(false);
enable_ssl3_checkbox_->SetEnabled(false);
enable_tls1_checkbox_->SetEnabled(false);
check_for_cert_revocation_checkbox_->SetEnabled(false);
diff --git a/chrome/browser/ui/views/options/advanced_page_view.cc b/chrome/browser/ui/views/options/advanced_page_view.cc
index 712955c..287c124 100644
--- a/chrome/browser/ui/views/options/advanced_page_view.cc
+++ b/chrome/browser/ui/views/options/advanced_page_view.cc
@@ -7,10 +7,10 @@
#include "app/l10n_util.h"
#include "app/message_box_flags.h"
#include "base/string_util.h"
-#include "chrome/browser/options_util.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/views/options/advanced_contents_view.h"
-#include "chrome/browser/views/options/managed_prefs_banner_view.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/options/options_util.h"
+#include "chrome/browser/ui/views/options/advanced_contents_view.h"
+#include "chrome/browser/ui/views/options/managed_prefs_banner_view.h"
#include "chrome/common/chrome_constants.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/ui/views/options/content_filter_page_view.cc b/chrome/browser/ui/views/options/content_filter_page_view.cc
index 320611d..3e4ba8d 100644
--- a/chrome/browser/ui/views/options/content_filter_page_view.cc
+++ b/chrome/browser/ui/views/options/content_filter_page_view.cc
@@ -6,12 +6,13 @@
#include "app/l10n_util.h"
#include "base/command_line.h"
+#include "chrome/browser/content_settings/content_settings_details.h"
#include "chrome/browser/geolocation/geolocation_content_settings_map.h"
#include "chrome/browser/geolocation/geolocation_exceptions_table_model.h"
#include "chrome/browser/notifications/desktop_notification_service.h"
#include "chrome/browser/notifications/notification_exceptions_table_model.h"
#include "chrome/browser/plugin_exceptions_table_model.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/views/options/exceptions_view.h"
#include "chrome/browser/views/options/simple_content_exceptions_view.h"
#include "chrome/common/chrome_switches.h"
@@ -152,6 +153,10 @@ void ContentFilterPageView::InitControlLayout() {
registrar_.Add(this, NotificationType::CONTENT_SETTINGS_CHANGED,
NotificationService::AllSources());
+ registrar_.Add(this, NotificationType::DESKTOP_NOTIFICATION_DEFAULT_CHANGED,
+ NotificationService::AllSources());
+ registrar_.Add(this, NotificationType::GEOLOCATION_SETTINGS_CHANGED,
+ NotificationService::AllSources());
}
///////////////////////////////////////////////////////////////////////////////
@@ -162,9 +167,13 @@ void ContentFilterPageView::UpdateView() {
if (content_type_ == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
default_setting = profile()->GetGeolocationContentSettingsMap()->
GetDefaultContentSetting();
+ is_content_type_managed = profile()->GetGeolocationContentSettingsMap()->
+ IsDefaultContentSettingManaged();
} else if (content_type_ == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
default_setting = profile()->GetDesktopNotificationService()->
GetDefaultContentSetting();
+ is_content_type_managed = profile()->GetDesktopNotificationService()->
+ IsDefaultContentSettingManaged();
} else {
default_setting = profile()->GetHostContentSettingsMap()->
GetDefaultContentSetting(content_type_);
@@ -253,7 +262,7 @@ void ContentFilterPageView::ButtonPressed(views::Button* sender,
}
void ContentFilterPageView::NotifyContentSettingsChanged(
- const HostContentSettingsMap::ContentSettingsDetails *details) {
+ const ContentSettingsDetails* details) {
if (details->type() == CONTENT_SETTINGS_TYPE_DEFAULT ||
details->type() == content_type_) {
UpdateView();
@@ -265,8 +274,16 @@ void ContentFilterPageView::Observe(NotificationType type,
const NotificationDetails& details) {
if (type == NotificationType::CONTENT_SETTINGS_CHANGED) {
NotifyContentSettingsChanged(
- Details<HostContentSettingsMap::ContentSettingsDetails>
- (details).ptr());
+ Details<ContentSettingsDetails>(details).ptr());
+ } else if (type == NotificationType::GEOLOCATION_SETTINGS_CHANGED) {
+ NotifyContentSettingsChanged(
+ Details<ContentSettingsDetails>(details).ptr());
+ } else if (type == NotificationType::DESKTOP_NOTIFICATION_DEFAULT_CHANGED) {
+ ContentSettingsDetails content_settings_details(
+ ContentSettingsPattern(),
+ CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
+ "");
+ NotifyContentSettingsChanged(&content_settings_details);
} else {
OptionsPageBase::Observe(type, source, details);
}
diff --git a/chrome/browser/ui/views/options/content_filter_page_view.h b/chrome/browser/ui/views/options/content_filter_page_view.h
index dd4629e..5f23583 100644
--- a/chrome/browser/ui/views/options/content_filter_page_view.h
+++ b/chrome/browser/ui/views/options/content_filter_page_view.h
@@ -6,7 +6,7 @@
#define CHROME_BROWSER_UI_VIEWS_OPTIONS_CONTENT_FILTER_PAGE_VIEW_H_
#pragma once
-#include "chrome/browser/host_content_settings_map.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/views/options/options_page_view.h"
#include "chrome/common/content_settings_types.h"
#include "chrome/common/notification_registrar.h"
@@ -39,7 +39,7 @@ class ContentFilterPageView : public OptionsPageView,
virtual void UpdateView();
virtual void NotifyContentSettingsChanged(
- const HostContentSettingsMap::ContentSettingsDetails *details);
+ const ContentSettingsDetails* details);
// OptionsPageView implementation:
virtual void InitControlLayout();
diff --git a/chrome/browser/ui/views/options/content_page_view.cc b/chrome/browser/ui/views/options/content_page_view.cc
index 8ba1dd8..5118834 100644
--- a/chrome/browser/ui/views/options/content_page_view.cc
+++ b/chrome/browser/ui/views/options/content_page_view.cc
@@ -15,10 +15,9 @@
#include "chrome/browser/autofill/autofill_dialog.h"
#include "chrome/browser/autofill/personal_data_manager.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/importer/importer_data_types.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/sync_ui_util.h"
#include "chrome/browser/sync/sync_setup_wizard.h"
#include "chrome/browser/ui/browser.h"
diff --git a/chrome/browser/ui/views/options/content_settings_window_view.cc b/chrome/browser/ui/views/options/content_settings_window_view.cc
index 2a2146c..ef0e746 100644
--- a/chrome/browser/ui/views/options/content_settings_window_view.cc
+++ b/chrome/browser/ui/views/options/content_settings_window_view.cc
@@ -6,9 +6,8 @@
#include "app/l10n_util.h"
#include "base/stl_util-inl.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/views/options/advanced_page_view.h"
#include "chrome/browser/views/options/content_filter_page_view.h"
#include "chrome/browser/views/options/cookie_filter_page_view.h"
diff --git a/chrome/browser/ui/views/options/cookie_filter_page_view.cc b/chrome/browser/ui/views/options/cookie_filter_page_view.cc
index 6cfeab7..7b8db39 100644
--- a/chrome/browser/ui/views/options/cookie_filter_page_view.cc
+++ b/chrome/browser/ui/views/options/cookie_filter_page_view.cc
@@ -5,10 +5,10 @@
#include "chrome/browser/views/options/cookie_filter_page_view.h"
#include "app/l10n_util.h"
-#include "chrome/browser/host_content_settings_map.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/show_options_url.h"
-#include "chrome/browser/views/options/cookies_view.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/options/show_options_url.h"
+#include "chrome/browser/ui/views/options/cookies_view.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
diff --git a/chrome/browser/ui/views/options/cookies_view.cc b/chrome/browser/ui/views/options/cookies_view.cc
index 5e2b6d0..e06b511 100644
--- a/chrome/browser/ui/views/options/cookies_view.cc
+++ b/chrome/browser/ui/views/options/cookies_view.cc
@@ -9,7 +9,7 @@
#include "app/l10n_util.h"
#include "base/message_loop.h"
#include "base/string_util.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/views/appcache_info_view.h"
#include "chrome/browser/views/cookie_info_view.h"
#include "chrome/browser/views/database_info_view.h"
diff --git a/chrome/browser/ui/views/options/exception_editor_view.cc b/chrome/browser/ui/views/options/exception_editor_view.cc
index 93ca859..7b111d8 100644
--- a/chrome/browser/ui/views/options/exception_editor_view.cc
+++ b/chrome/browser/ui/views/options/exception_editor_view.cc
@@ -24,7 +24,7 @@ ExceptionEditorView::ExceptionEditorView(
ContentExceptionsTableModel* model,
bool allow_off_the_record,
int index,
- const HostContentSettingsMap::Pattern& pattern,
+ const ContentSettingsPattern& pattern,
ContentSetting setting,
bool is_off_the_record)
: delegate_(delegate),
@@ -63,7 +63,7 @@ std::wstring ExceptionEditorView::GetWindowTitle() const {
bool ExceptionEditorView::IsDialogButtonEnabled(
MessageBoxFlags::DialogButton button) const {
if (button == MessageBoxFlags::DIALOGBUTTON_OK) {
- return IsPatternValid(HostContentSettingsMap::Pattern(
+ return IsPatternValid(ContentSettingsPattern(
UTF16ToUTF8(pattern_tf_->text())),
incognito_cb_->checked());
}
@@ -75,7 +75,7 @@ bool ExceptionEditorView::Cancel() {
}
bool ExceptionEditorView::Accept() {
- HostContentSettingsMap::Pattern new_pattern(UTF16ToUTF8(pattern_tf_->text()));
+ ContentSettingsPattern new_pattern(UTF16ToUTF8(pattern_tf_->text()));
ContentSetting setting =
cb_model_.SettingForIndex(action_cb_->selected_item());
bool is_off_the_record = incognito_cb_->checked();
@@ -91,7 +91,7 @@ views::View* ExceptionEditorView::GetContentsView() {
void ExceptionEditorView::ContentsChanged(views::Textfield* sender,
const std::wstring& new_contents) {
GetDialogClientView()->UpdateDialogButtons();
- UpdateImageView(pattern_iv_, IsPatternValid(HostContentSettingsMap::Pattern(
+ UpdateImageView(pattern_iv_, IsPatternValid(ContentSettingsPattern(
UTF16ToUTF8(pattern_tf_->text())), incognito_cb_->checked()));
}
@@ -110,7 +110,7 @@ void ExceptionEditorView::Init() {
pattern_iv_ = new views::ImageView;
- UpdateImageView(pattern_iv_, IsPatternValid(HostContentSettingsMap::Pattern(
+ UpdateImageView(pattern_iv_, IsPatternValid(ContentSettingsPattern(
UTF16ToUTF8(pattern_tf_->text())), is_off_the_record_));
action_cb_ = new views::Combobox(&cb_model_);
@@ -158,7 +158,7 @@ views::Label* ExceptionEditorView::CreateLabel(int message_id) {
}
bool ExceptionEditorView::IsPatternValid(
- const HostContentSettingsMap::Pattern& pattern,
+ const ContentSettingsPattern& pattern,
bool is_off_the_record) const {
bool is_valid_pattern = pattern.IsValid() &&
(model_->IndexOfExceptionByPattern(pattern, is_off_the_record) == -1);
diff --git a/chrome/browser/ui/views/options/exception_editor_view.h b/chrome/browser/ui/views/options/exception_editor_view.h
index 571e29e..db8ddf6 100644
--- a/chrome/browser/ui/views/options/exception_editor_view.h
+++ b/chrome/browser/ui/views/options/exception_editor_view.h
@@ -8,8 +8,8 @@
#include <string>
+#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/content_setting_combo_model.h"
-#include "chrome/browser/host_content_settings_map.h"
#include "chrome/common/content_settings.h"
#include "chrome/common/content_settings_types.h"
#include "views/window/dialog_delegate.h"
@@ -38,7 +38,7 @@ class ExceptionEditorView : public views::View,
public:
// Invoked when the user accepts the edit.
virtual void AcceptExceptionEdit(
- const HostContentSettingsMap::Pattern& pattern,
+ const ContentSettingsPattern& pattern,
ContentSetting setting,
bool is_off_the_record,
int index,
@@ -55,7 +55,7 @@ class ExceptionEditorView : public views::View,
ContentExceptionsTableModel* model,
bool allow_off_the_record,
int index,
- const HostContentSettingsMap::Pattern& pattern,
+ const ContentSettingsPattern& pattern,
ContentSetting setting,
bool is_off_the_record);
virtual ~ExceptionEditorView() {}
@@ -87,7 +87,7 @@ class ExceptionEditorView : public views::View,
// Returns true if we're adding a new item.
bool is_new() const { return index_ == -1; }
- bool IsPatternValid(const HostContentSettingsMap::Pattern& pattern,
+ bool IsPatternValid(const ContentSettingsPattern& pattern,
bool is_off_the_record) const;
void UpdateImageView(views::ImageView* image_view, bool is_valid);
@@ -99,7 +99,7 @@ class ExceptionEditorView : public views::View,
// Index of the item being edited. If -1, indices this is a new entry.
const bool allow_off_the_record_;
const int index_;
- const HostContentSettingsMap::Pattern pattern_;
+ const ContentSettingsPattern pattern_;
const ContentSetting setting_;
const bool is_off_the_record_;
diff --git a/chrome/browser/ui/views/options/exceptions_page_view.cc b/chrome/browser/ui/views/options/exceptions_page_view.cc
index 7788c5c..eb5d8c6 100644
--- a/chrome/browser/ui/views/options/exceptions_page_view.cc
+++ b/chrome/browser/ui/views/options/exceptions_page_view.cc
@@ -8,7 +8,7 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
#include "views/background.h"
diff --git a/chrome/browser/ui/views/options/exceptions_view.cc b/chrome/browser/ui/views/options/exceptions_view.cc
index eadaf75..0a622a1 100644
--- a/chrome/browser/ui/views/options/exceptions_view.cc
+++ b/chrome/browser/ui/views/options/exceptions_view.cc
@@ -128,7 +128,7 @@ std::wstring ExceptionsView::GetWindowTitle() const {
}
void ExceptionsView::AcceptExceptionEdit(
- const HostContentSettingsMap::Pattern& pattern,
+ const ContentSettingsPattern& pattern,
ContentSetting setting,
bool is_off_the_record,
int index,
@@ -234,7 +234,7 @@ void ExceptionsView::UpdateButtonState() {
void ExceptionsView::Add() {
ExceptionEditorView* view =
new ExceptionEditorView(this, &model_, allow_off_the_record_, -1,
- HostContentSettingsMap::Pattern(),
+ ContentSettingsPattern(),
CONTENT_SETTING_BLOCK, false);
view->Show(window()->GetNativeWindow());
diff --git a/chrome/browser/ui/views/options/exceptions_view.h b/chrome/browser/ui/views/options/exceptions_view.h
index 3624816..a0747be 100644
--- a/chrome/browser/ui/views/options/exceptions_view.h
+++ b/chrome/browser/ui/views/options/exceptions_view.h
@@ -69,7 +69,7 @@ class ExceptionsView : public ExceptionEditorView::Delegate,
// ExceptionEditorView::Delegate implementation.
virtual void AcceptExceptionEdit(
- const HostContentSettingsMap::Pattern& pattern,
+ const ContentSettingsPattern& pattern,
ContentSetting setting,
bool is_off_the_record,
int index,
diff --git a/chrome/browser/ui/views/options/fonts_languages_window_view.cc b/chrome/browser/ui/views/options/fonts_languages_window_view.cc
index cab82c7..edf0fa2 100644
--- a/chrome/browser/ui/views/options/fonts_languages_window_view.cc
+++ b/chrome/browser/ui/views/options/fonts_languages_window_view.cc
@@ -6,7 +6,7 @@
#include "app/l10n_util.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/views/options/fonts_page_view.h"
#include "chrome/browser/views/options/languages_page_view.h"
#include "chrome/common/chrome_constants.h"
diff --git a/chrome/browser/ui/views/options/fonts_page_view.cc b/chrome/browser/ui/views/options/fonts_page_view.cc
index 3a98b15..ddbc676 100644
--- a/chrome/browser/ui/views/options/fonts_page_view.cc
+++ b/chrome/browser/ui/views/options/fonts_page_view.cc
@@ -18,7 +18,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/default_encoding_combo_model.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/shell_dialogs.h"
#include "chrome/common/pref_names.h"
#include "gfx/canvas_skia.h"
diff --git a/chrome/browser/ui/views/options/general_page_view.cc b/chrome/browser/ui/views/options/general_page_view.cc
index 623b592..11be9c6 100644
--- a/chrome/browser/ui/views/options/general_page_view.cc
+++ b/chrome/browser/ui/views/options/general_page_view.cc
@@ -18,16 +18,16 @@
#include "chrome/browser/instant/instant_controller.h"
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/prefs/session_startup_pref.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/search_engines/template_url_model_observer.h"
-#include "chrome/browser/show_options_url.h"
#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/views/keyword_editor_view.h"
-#include "chrome/browser/views/options/managed_prefs_banner_view.h"
-#include "chrome/browser/views/options/options_group_view.h"
+#include "chrome/browser/ui/options/show_options_url.h"
+#include "chrome/browser/ui/views/keyword_editor_view.h"
+#include "chrome/browser/ui/views/options/managed_prefs_banner_view.h"
+#include "chrome/browser/ui/views/options/options_group_view.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
diff --git a/chrome/browser/ui/views/options/languages_page_view.cc b/chrome/browser/ui/views/options/languages_page_view.cc
index 207841c..9abe7c4 100644
--- a/chrome/browser/ui/views/options/languages_page_view.cc
+++ b/chrome/browser/ui/views/options/languages_page_view.cc
@@ -19,7 +19,7 @@
#include "chrome/browser/language_combobox_model.h"
#include "chrome/browser/language_order_table_model.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/shell_dialogs.h"
#include "chrome/browser/views/restart_message_box.h"
#include "chrome/common/chrome_switches.h"
diff --git a/chrome/browser/ui/views/options/options_page_view.cc b/chrome/browser/ui/views/options/options_page_view.cc
index 6073442..81b1e98 100644
--- a/chrome/browser/ui/views/options/options_page_view.cc
+++ b/chrome/browser/ui/views/options/options_page_view.cc
@@ -4,10 +4,8 @@
#include "chrome/browser/views/options/options_page_view.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/common/notification_service.h"
#include "views/widget/widget.h"
///////////////////////////////////////////////////////////////////////////////
@@ -39,4 +37,3 @@ void OptionsPageView::ViewHierarchyChanged(bool is_add,
AccessibilityTypes::Role OptionsPageView::GetAccessibleRole() {
return AccessibilityTypes::ROLE_PAGETAB;
}
-
diff --git a/chrome/browser/ui/views/options/options_page_view.h b/chrome/browser/ui/views/options/options_page_view.h
index 8562f11..bbbc8c4 100644
--- a/chrome/browser/ui/views/options/options_page_view.h
+++ b/chrome/browser/ui/views/options/options_page_view.h
@@ -6,7 +6,7 @@
#define CHROME_BROWSER_UI_VIEWS_OPTIONS_OPTIONS_PAGE_VIEW_H__
#pragma once
-#include "chrome/browser/options_page_base.h"
+#include "chrome/browser/ui/options/options_page_base.h"
#include "views/controls/link.h"
#include "views/controls/button/native_button.h"
diff --git a/chrome/browser/ui/views/options/options_window_view.cc b/chrome/browser/ui/views/options/options_window_view.cc
index 8201bd8..ae7f545 100644
--- a/chrome/browser/ui/views/options/options_window_view.cc
+++ b/chrome/browser/ui/views/options/options_window_view.cc
@@ -2,19 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/options_window.h"
-
#include "app/l10n_util.h"
#include "base/utf_string_conversions.h"
-#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_window.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/views/options/advanced_page_view.h"
-#include "chrome/browser/views/options/content_page_view.h"
-#include "chrome/browser/views/options/general_page_view.h"
-#include "chrome/browser/window_sizer.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/options/options_window.h"
+#include "chrome/browser/ui/views/options/advanced_page_view.h"
+#include "chrome/browser/ui/views/options/content_page_view.h"
+#include "chrome/browser/ui/views/options/general_page_view.h"
+#include "chrome/browser/ui/window_sizer.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/pref_names.h"
#include "grit/chromium_strings.h"
diff --git a/chrome/browser/ui/views/options/passwords_page_view.cc b/chrome/browser/ui/views/options/passwords_page_view.cc
index e33b0b6..cdb3187 100644
--- a/chrome/browser/ui/views/options/passwords_page_view.cc
+++ b/chrome/browser/ui/views/options/passwords_page_view.cc
@@ -10,7 +10,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/password_manager/password_store.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
#include "views/background.h"
diff --git a/chrome/browser/ui/views/options/passwords_page_view.h b/chrome/browser/ui/views/options/passwords_page_view.h
index 0204db5..f465b57 100644
--- a/chrome/browser/ui/views/options/passwords_page_view.h
+++ b/chrome/browser/ui/views/options/passwords_page_view.h
@@ -13,7 +13,7 @@
#include "base/scoped_ptr.h"
#include "base/stl_util-inl.h"
#include "chrome/browser/password_manager/password_store.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/views/confirm_message_box_dialog.h"
#include "chrome/browser/views/options/options_page_view.h"
diff --git a/chrome/browser/ui/views/options/plugin_filter_page_view.cc b/chrome/browser/ui/views/options/plugin_filter_page_view.cc
index aee62ff..94ae40d 100644
--- a/chrome/browser/ui/views/options/plugin_filter_page_view.cc
+++ b/chrome/browser/ui/views/options/plugin_filter_page_view.cc
@@ -5,8 +5,8 @@
#include "chrome/browser/views/options/plugin_filter_page_view.h"
#include "app/l10n_util.h"
-#include "chrome/browser/show_options_url.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/options/show_options_url.h"
#include "chrome/common/url_constants.h"
#include "grit/generated_resources.h"
#include "views/grid_layout.h"
diff --git a/chrome/browser/ui/views/page_info_bubble_view.cc b/chrome/browser/ui/views/page_info_bubble_view.cc
index 0dbd950..073c6f7 100644
--- a/chrome/browser/ui/views/page_info_bubble_view.cc
+++ b/chrome/browser/ui/views/page_info_bubble_view.cc
@@ -96,7 +96,7 @@ PageInfoBubbleView::PageInfoBubbleView(gfx::NativeWindow parent_window,
animation_start_height_(0) {
if (cert_id_ > 0) {
scoped_refptr<net::X509Certificate> cert;
- CertStore::GetSharedInstance()->RetrieveCert(cert_id_, &cert);
+ CertStore::GetInstance()->RetrieveCert(cert_id_, &cert);
// When running with fake certificate (Chrome Frame) or Gears in offline
// mode, we have no os certificate, so there is no cert to show. Don't
// bother showing the cert info link in that case.
diff --git a/chrome/browser/ui/views/repost_form_warning_view.cc b/chrome/browser/ui/views/repost_form_warning_view.cc
index 7d7ed67..d29258b 100644
--- a/chrome/browser/ui/views/repost_form_warning_view.cc
+++ b/chrome/browser/ui/views/repost_form_warning_view.cc
@@ -11,7 +11,6 @@
#include "chrome/browser/repost_form_warning_controller.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/notification_service.h"
#include "grit/generated_resources.h"
#include "views/controls/message_box_view.h"
#include "views/window/window.h"
diff --git a/chrome/browser/ui/views/select_file_dialog.cc b/chrome/browser/ui/views/select_file_dialog.cc
index 702d546..f012838 100644
--- a/chrome/browser/ui/views/select_file_dialog.cc
+++ b/chrome/browser/ui/views/select_file_dialog.cc
@@ -15,7 +15,7 @@
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/dom_ui/html_dialog_ui.h"
-#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/shell_dialogs.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
diff --git a/chrome/browser/ui/views/ssl_client_certificate_selector_win.cc b/chrome/browser/ui/views/ssl_client_certificate_selector_win.cc
index d860953..c7ddab3 100644
--- a/chrome/browser/ui/views/ssl_client_certificate_selector_win.cc
+++ b/chrome/browser/ui/views/ssl_client_certificate_selector_win.cc
@@ -12,7 +12,6 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_thread.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/ssl/ssl_client_auth_handler.h"
#include "chrome/browser/tab_contents/tab_contents.h"
diff --git a/chrome/browser/ui/views/status_bubble_views.h b/chrome/browser/ui/views/status_bubble_views.h
index 118f027..456eab7 100644
--- a/chrome/browser/ui/views/status_bubble_views.h
+++ b/chrome/browser/ui/views/status_bubble_views.h
@@ -10,7 +10,7 @@
#include "base/scoped_ptr.h"
#include "base/string16.h"
#include "base/task.h"
-#include "chrome/browser/status_bubble.h"
+#include "chrome/browser/ui/status_bubble.h"
#include "googleurl/src/gurl.h"
#include "gfx/rect.h"
diff --git a/chrome/browser/ui/views/tab_contents/native_tab_contents_container_gtk.cc b/chrome/browser/ui/views/tab_contents/native_tab_contents_container_gtk.cc
index 0c07fa7..82c0b26 100644
--- a/chrome/browser/ui/views/tab_contents/native_tab_contents_container_gtk.cc
+++ b/chrome/browser/ui/views/tab_contents/native_tab_contents_container_gtk.cc
@@ -7,8 +7,8 @@
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/tab_contents/interstitial_page.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/view_ids.h"
-#include "chrome/browser/views/tab_contents/tab_contents_container.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/tab_contents/tab_contents_container.h"
#include "views/focus/focus_manager.h"
#include "views/widget/root_view.h"
#include "views/widget/widget.h"
diff --git a/chrome/browser/ui/views/tab_contents/native_tab_contents_container_win.cc b/chrome/browser/ui/views/tab_contents/native_tab_contents_container_win.cc
index eba411f..99c37a9 100644
--- a/chrome/browser/ui/views/tab_contents/native_tab_contents_container_win.cc
+++ b/chrome/browser/ui/views/tab_contents/native_tab_contents_container_win.cc
@@ -7,9 +7,9 @@
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/tab_contents/interstitial_page.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/view_ids.h"
-#include "chrome/browser/views/tab_contents/tab_contents_container.h"
-#include "chrome/browser/views/tab_contents/tab_contents_view_win.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/tab_contents/tab_contents_container.h"
+#include "chrome/browser/ui/views/tab_contents/tab_contents_view_win.h"
#include "views/focus/focus_manager.h"
diff --git a/chrome/browser/ui/views/tab_contents/render_view_context_menu_views.cc b/chrome/browser/ui/views/tab_contents/render_view_context_menu_views.cc
index e7ac1a6..75675cd 100644
--- a/chrome/browser/ui/views/tab_contents/render_view_context_menu_views.cc
+++ b/chrome/browser/ui/views/tab_contents/render_view_context_menu_views.cc
@@ -5,9 +5,8 @@
#include "chrome/browser/views/tab_contents/render_view_context_menu_views.h"
#include "app/keyboard_codes.h"
-#include "base/compiler_specific.h"
+#include "base/logging.h"
#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/profile.h"
#include "grit/generated_resources.h"
#include "views/accelerator.h"
#include "views/controls/menu/menu_2.h"
diff --git a/chrome/browser/ui/views/tab_contents/tab_contents_container.cc b/chrome/browser/ui/views/tab_contents/tab_contents_container.cc
index 9ab6078..47ed229 100644
--- a/chrome/browser/ui/views/tab_contents/tab_contents_container.cc
+++ b/chrome/browser/ui/views/tab_contents/tab_contents_container.cc
@@ -8,9 +8,10 @@
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/tab_contents/interstitial_page.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/view_ids.h"
-#include "chrome/browser/views/tab_contents/native_tab_contents_container.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/tab_contents/native_tab_contents_container.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
#if defined(TOUCH_UI)
#include "chrome/browser/ui/views/tab_contents/native_tab_contents_container_gtk.h"
@@ -38,6 +39,9 @@ void TabContentsContainer::ChangeTabContents(TabContents* contents) {
if (tab_contents_) {
#if !defined(TOUCH_UI)
native_container_->DetachContents(tab_contents_);
+#else
+ views::View *v = static_cast<TabContentsViewViews*>(tab_contents_->view());
+ RemoveChildView(v);
#endif
tab_contents_->WasHidden();
RemoveObservers();
@@ -152,7 +156,7 @@ void TabContentsContainer::RemoveObservers() {
void TabContentsContainer::RenderViewHostChanged(RenderViewHost* old_host,
RenderViewHost* new_host) {
#if defined(TOUCH_UI)
- NOTIMPLEMENTED(); // TODO(anicolao)
+ NOTIMPLEMENTED(); // TODO(anicolao)
#else
if (new_host) {
RenderWidgetHostViewChanged(
diff --git a/chrome/browser/ui/views/tab_contents/tab_contents_drag_win.cc b/chrome/browser/ui/views/tab_contents/tab_contents_drag_win.cc
index bc31aac..7ea2501 100644
--- a/chrome/browser/ui/views/tab_contents/tab_contents_drag_win.cc
+++ b/chrome/browser/ui/views/tab_contents/tab_contents_drag_win.cc
@@ -18,7 +18,6 @@
#include "chrome/browser/download/download_util.h"
#include "chrome/browser/download/drag_download_file.h"
#include "chrome/browser/download/drag_download_util.h"
-#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/web_drag_source_win.h"
#include "chrome/browser/tab_contents/web_drag_utils_win.h"
diff --git a/chrome/browser/ui/views/tab_contents/tab_contents_view_gtk.cc b/chrome/browser/ui/views/tab_contents/tab_contents_view_gtk.cc
index 0a31684..3d0db15 100644
--- a/chrome/browser/ui/views/tab_contents/tab_contents_view_gtk.cc
+++ b/chrome/browser/ui/views/tab_contents/tab_contents_view_gtk.cc
@@ -8,17 +8,14 @@
#include <gtk/gtk.h>
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
#include "build/build_config.h"
#include "chrome/browser/download/download_shelf.h"
#include "chrome/browser/gtk/constrained_window_gtk.h"
#include "chrome/browser/gtk/tab_contents_drag_source.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_view_host_factory.h"
-#if defined(TOUCH_UI)
-#include "chrome/browser/renderer_host/render_widget_host_view_views.h"
-#else
#include "chrome/browser/renderer_host/render_widget_host_view_gtk.h"
-#endif
#include "chrome/browser/tab_contents/interstitial_page.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
@@ -110,7 +107,7 @@ TabContentsViewGtk::TabContentsViewGtk(TabContents* tab_contents)
ignore_next_char_event_(false) {
drag_source_.reset(new TabContentsDragSource(this));
last_focused_view_storage_id_ =
- views::ViewStorage::GetSharedInstance()->CreateStorageID();
+ views::ViewStorage::GetInstance()->CreateStorageID();
}
TabContentsViewGtk::~TabContentsViewGtk() {
@@ -118,7 +115,7 @@ TabContentsViewGtk::~TabContentsViewGtk() {
//
// It is possible the view went away before us, so we only do this if the
// view is registered.
- views::ViewStorage* view_storage = views::ViewStorage::GetSharedInstance();
+ views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL)
view_storage->RemoveView(last_focused_view_storage_id_);
@@ -178,30 +175,6 @@ RenderWidgetHostView* TabContentsViewGtk::CreateViewForWidget(
sad_tab_ = NULL;
}
-#if defined(TOUCH_UI)
- RenderWidgetHostViewViews* view =
- new RenderWidgetHostViewViews(render_widget_host);
- SetContentsView(view);
- view->Show();
- view->InitAsChild();
-
- g_signal_connect(view->native_view(), "focus",
- G_CALLBACK(OnFocus), tab_contents());
- g_signal_connect(view->native_view(), "leave-notify-event",
- G_CALLBACK(OnLeaveNotify2), tab_contents());
- g_signal_connect(view->native_view(), "motion-notify-event",
- G_CALLBACK(CallMouseMove), this);
- g_signal_connect(view->native_view(), "scroll-event",
- G_CALLBACK(OnMouseScroll), tab_contents());
- gtk_widget_add_events(view->native_view(), GDK_LEAVE_NOTIFY_MASK |
- GDK_POINTER_MOTION_MASK);
-
- // Renderer target DnD.
- if (tab_contents()->ShouldAcceptDragAndDrop())
- drag_dest_.reset(new WebDragDestGtk(tab_contents(), view->native_view()));
-
- return view;
-#else
RenderWidgetHostViewGtk* view =
new RenderWidgetHostViewGtk(render_widget_host);
view->InitAsChild();
@@ -222,7 +195,6 @@ RenderWidgetHostView* TabContentsViewGtk::CreateViewForWidget(
gtk_fixed_put(GTK_FIXED(GetNativeView()), view->native_view(), 0, 0);
return view;
-#endif
}
gfx::NativeView TabContentsViewGtk::GetNativeView() const {
@@ -306,7 +278,7 @@ void TabContentsViewGtk::SetInitialFocus() {
}
void TabContentsViewGtk::StoreFocus() {
- views::ViewStorage* view_storage = views::ViewStorage::GetSharedInstance();
+ views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL)
view_storage->RemoveView(last_focused_view_storage_id_);
@@ -323,7 +295,7 @@ void TabContentsViewGtk::StoreFocus() {
}
void TabContentsViewGtk::RestoreFocus() {
- views::ViewStorage* view_storage = views::ViewStorage::GetSharedInstance();
+ views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
views::View* last_focused_view =
view_storage->RetrieveView(last_focused_view_storage_id_);
if (!last_focused_view) {
@@ -430,20 +402,6 @@ gboolean TabContentsViewGtk::OnPaint(GtkWidget* widget, GdkEventExpose* event) {
sad_tab_->SetBounds(gfx::Rect(0, 0, bounds.width(), bounds.height()));
gfx::CanvasSkiaPaint canvas(event);
sad_tab_->ProcessPaint(&canvas);
- } else {
-#if defined(TOUCH_UI)
- // there's no native view, so just like sad tabs
- // we need to pass on the message to paint the page
- gfx::Rect bounds;
- GetBounds(&bounds, true);
- views::View *view = reinterpret_cast<RenderWidgetHostViewViews *>
- (tab_contents()->render_view_host()->view());
- if (view) {
- view->SetBounds(gfx::Rect(0, 0, bounds.width(), bounds.height()));
- gfx::CanvasSkiaPaint canvas(event);
- view->ProcessPaint(&canvas);
- }
-#endif
}
return false; // False indicates other widgets should get the event as well.
}
diff --git a/chrome/browser/ui/views/tab_contents/tab_contents_view_views.cc b/chrome/browser/ui/views/tab_contents/tab_contents_view_views.cc
index 10d3daf..5abdc07 100644
--- a/chrome/browser/ui/views/tab_contents/tab_contents_view_views.cc
+++ b/chrome/browser/ui/views/tab_contents/tab_contents_view_views.cc
@@ -40,7 +40,7 @@ TabContentsViewViews::TabContentsViewViews(TabContents* tab_contents)
sad_tab_(NULL),
ignore_next_char_event_(false) {
last_focused_view_storage_id_ =
- views::ViewStorage::GetSharedInstance()->CreateStorageID();
+ views::ViewStorage::GetInstance()->CreateStorageID();
SetLayoutManager(new views::FillLayout());
}
@@ -49,7 +49,7 @@ TabContentsViewViews::~TabContentsViewViews() {
//
// It is possible the view went away before us, so we only do this if the
// view is registered.
- views::ViewStorage* view_storage = views::ViewStorage::GetSharedInstance();
+ views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL)
view_storage->RemoveView(last_focused_view_storage_id_);
}
@@ -84,9 +84,8 @@ RenderWidgetHostView* TabContentsViewViews::CreateViewForWidget(
// If we were showing sad tab, remove it now.
if (sad_tab_ != NULL) {
- RemoveChildView(sad_tab_);
- AddChildView(new views::View());
- sad_tab_ = NULL;
+ RemoveChildView(sad_tab_.get());
+ sad_tab_.reset();
}
RenderWidgetHostViewViews* view =
@@ -132,6 +131,13 @@ void TabContentsViewViews::SetPageTitle(const std::wstring& title) {
}
void TabContentsViewViews::OnTabCrashed() {
+ if (sad_tab_ != NULL)
+ return;
+
+ sad_tab_.reset(new SadTabView(tab_contents()));
+ RemoveAllChildViews(true);
+ AddChildView(sad_tab_.get());
+ Layout();
}
void TabContentsViewViews::SizeContents(const gfx::Size& size) {
@@ -155,7 +161,8 @@ void TabContentsViewViews::Focus() {
}
RenderWidgetHostView* rwhv = tab_contents()->GetRenderWidgetHostView();
- gtk_widget_grab_focus(rwhv ? rwhv->GetNativeView() : GetNativeView());
+ if (rwhv)
+ rwhv->Focus();
}
void TabContentsViewViews::SetInitialFocus() {
@@ -166,7 +173,7 @@ void TabContentsViewViews::SetInitialFocus() {
}
void TabContentsViewViews::StoreFocus() {
- views::ViewStorage* view_storage = views::ViewStorage::GetSharedInstance();
+ views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL)
view_storage->RemoveView(last_focused_view_storage_id_);
@@ -183,7 +190,7 @@ void TabContentsViewViews::StoreFocus() {
}
void TabContentsViewViews::RestoreFocus() {
- views::ViewStorage* view_storage = views::ViewStorage::GetSharedInstance();
+ views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
views::View* last_focused_view =
view_storage->RetrieveView(last_focused_view_storage_id_);
if (!last_focused_view) {
@@ -210,6 +217,12 @@ void TabContentsViewViews::RestoreFocus() {
}
}
+void TabContentsViewViews::DidChangeBounds(const gfx::Rect& previous,
+ const gfx::Rect& current) {
+ if (IsVisibleInRootView())
+ WasSized(gfx::Size(current.width(), current.height()));
+}
+
void TabContentsViewViews::Paint(gfx::Canvas* canvas) {
}
@@ -251,8 +264,22 @@ void TabContentsViewViews::ShowContextMenu(const ContextMenuParams& params) {
if (tab_contents()->delegate()->HandleContextMenu(params))
return;
- // TODO(anicolao): implement context menus for touch
- NOTIMPLEMENTED();
+ context_menu_.reset(new RenderViewContextMenuViews(tab_contents(), params));
+ context_menu_->Init();
+
+ gfx::Point screen_point(params.x, params.y);
+ RenderWidgetHostViewViews* rwhv = static_cast<RenderWidgetHostViewViews*>
+ (tab_contents()->GetRenderWidgetHostView());
+ if (rwhv) {
+ views::View::ConvertPointToScreen(rwhv, &screen_point);
+ }
+
+ // Enable recursive tasks on the message loop so we can get updates while
+ // the context menu is being displayed.
+ bool old_state = MessageLoop::current()->NestableTasksAllowed();
+ MessageLoop::current()->SetNestableTasksAllowed(true);
+ context_menu_->RunMenuAt(screen_point.x(), screen_point.y());
+ MessageLoop::current()->SetNestableTasksAllowed(old_state);
}
void TabContentsViewViews::ShowPopupMenu(const gfx::Rect& bounds,
diff --git a/chrome/browser/ui/views/tab_contents/tab_contents_view_views.h b/chrome/browser/ui/views/tab_contents/tab_contents_view_views.h
index dfb7ed7..ab0e666 100644
--- a/chrome/browser/ui/views/tab_contents/tab_contents_view_views.h
+++ b/chrome/browser/ui/views/tab_contents/tab_contents_view_views.h
@@ -60,6 +60,9 @@ class TabContentsViewViews : public TabContentsView, public views::View {
virtual void RestoreFocus();
// views::View implementation
+ virtual void DidChangeBounds(const gfx::Rect& previous,
+ const gfx::Rect& current);
+
virtual void Paint(gfx::Canvas* canvas);
// Backend implementation of RenderViewHostDelegate::View.
@@ -98,7 +101,7 @@ class TabContentsViewViews : public TabContentsView, public views::View {
// Used to render the sad tab. This will be non-NULL only when the sad tab is
// visible.
- SadTabView* sad_tab_;
+ scoped_ptr<SadTabView> sad_tab_;
// Whether to ignore the next CHAR keyboard event.
bool ignore_next_char_event_;
diff --git a/chrome/browser/ui/views/tab_contents/tab_contents_view_win.cc b/chrome/browser/ui/views/tab_contents/tab_contents_view_win.cc
index 71adf3a..164fd92 100644
--- a/chrome/browser/ui/views/tab_contents/tab_contents_view_win.cc
+++ b/chrome/browser/ui/views/tab_contents/tab_contents_view_win.cc
@@ -7,7 +7,6 @@
#include <windows.h>
#include "base/time.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/download/download_request_limiter.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
@@ -42,7 +41,7 @@ TabContentsViewWin::TabContentsViewWin(TabContents* tab_contents)
close_tab_after_drag_ends_(false),
sad_tab_(NULL) {
last_focused_view_storage_id_ =
- views::ViewStorage::GetSharedInstance()->CreateStorageID();
+ views::ViewStorage::GetInstance()->CreateStorageID();
}
TabContentsViewWin::~TabContentsViewWin() {
@@ -50,7 +49,7 @@ TabContentsViewWin::~TabContentsViewWin() {
//
// It is possible the view went away before us, so we only do this if the
// view is registered.
- views::ViewStorage* view_storage = views::ViewStorage::GetSharedInstance();
+ views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL)
view_storage->RemoveView(last_focused_view_storage_id_);
}
@@ -214,7 +213,7 @@ void TabContentsViewWin::SetInitialFocus() {
}
void TabContentsViewWin::StoreFocus() {
- views::ViewStorage* view_storage = views::ViewStorage::GetSharedInstance();
+ views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL)
view_storage->RemoveView(last_focused_view_storage_id_);
@@ -244,7 +243,7 @@ void TabContentsViewWin::StoreFocus() {
}
void TabContentsViewWin::RestoreFocus() {
- views::ViewStorage* view_storage = views::ViewStorage::GetSharedInstance();
+ views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
views::View* last_focused_view =
view_storage->RetrieveView(last_focused_view_storage_id_);
diff --git a/chrome/browser/ui/views/tab_icon_view.cc b/chrome/browser/ui/views/tab_icon_view.cc
index 547b039..27f82d4 100644
--- a/chrome/browser/ui/views/tab_icon_view.cc
+++ b/chrome/browser/ui/views/tab_icon_view.cc
@@ -14,7 +14,6 @@
#include "base/file_util.h"
#include "base/logging.h"
#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
#include "gfx/canvas.h"
#include "gfx/favicon_size.h"
#include "grit/app_resources.h"
diff --git a/chrome/browser/ui/views/tabs/base_tab.cc b/chrome/browser/ui/views/tabs/base_tab.cc
index e612e1d..01a5344 100644
--- a/chrome/browser/ui/views/tabs/base_tab.cc
+++ b/chrome/browser/ui/views/tabs/base_tab.cc
@@ -15,8 +15,8 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/views/tabs/tab_controller.h"
-#include "chrome/browser/view_ids.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/tabs/tab_controller.h"
#include "chrome/common/chrome_switches.h"
#include "gfx/canvas_skia.h"
#include "gfx/favicon_size.h"
@@ -34,7 +34,7 @@
static const int kPulseDurationMs = 200;
// How long the hover state takes.
-static const int kHoverDurationMs = 90;
+static const int kHoverDurationMs = 400;
namespace {
diff --git a/chrome/browser/ui/views/tabs/base_tab_strip.cc b/chrome/browser/ui/views/tabs/base_tab_strip.cc
index 4f844ed..3035d30 100644
--- a/chrome/browser/ui/views/tabs/base_tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/base_tab_strip.cc
@@ -5,9 +5,9 @@
#include "chrome/browser/views/tabs/base_tab_strip.h"
#include "base/logging.h"
-#include "chrome/browser/view_ids.h"
-#include "chrome/browser/views/tabs/dragged_tab_controller.h"
-#include "chrome/browser/views/tabs/tab_strip_controller.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/tabs/dragged_tab_controller.h"
+#include "chrome/browser/ui/views/tabs/tab_strip_controller.h"
#include "views/widget/root_view.h"
#include "views/window/window.h"
@@ -226,6 +226,15 @@ bool BaseTabStrip::IsDragSessionActive() const {
return drag_controller_.get() != NULL;
}
+bool BaseTabStrip::IsActiveDropTarget() const {
+ for (int i = 0; i < tab_count(); ++i) {
+ BaseTab* tab = base_tab_at_tab_index(i);
+ if (tab->dragging())
+ return true;
+ }
+ return false;
+}
+
void BaseTabStrip::SelectTab(BaseTab* tab) {
int model_index = GetModelIndexOfBaseTab(tab);
if (IsValidModelIndex(model_index))
diff --git a/chrome/browser/ui/views/tabs/base_tab_strip.h b/chrome/browser/ui/views/tabs/base_tab_strip.h
index 8f9d5b4..491f991 100644
--- a/chrome/browser/ui/views/tabs/base_tab_strip.h
+++ b/chrome/browser/ui/views/tabs/base_tab_strip.h
@@ -131,6 +131,9 @@ class BaseTabStrip : public views::View,
// Returns true if a drag session is currently active.
bool IsDragSessionActive() const;
+ // Returns true if a tab is being dragged into this tab strip.
+ bool IsActiveDropTarget() const;
+
// TabController overrides:
virtual void SelectTab(BaseTab* tab);
virtual void CloseTab(BaseTab* tab);
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
index 426fe58..3a64df6 100644
--- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
+++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
@@ -6,16 +6,16 @@
#include "base/auto_reset.h"
#include "base/command_line.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tab_contents_wrapper.h"
-#include "chrome/browser/tab_menu_model.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/views/tabs/base_tab_strip.h"
-#include "chrome/browser/views/tabs/tab_renderer_data.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "chrome/browser/ui/tabs/tab_menu_model.h"
+#include "chrome/browser/ui/views/tabs/base_tab_strip.h"
+#include "chrome/browser/ui/views/tabs/tab_renderer_data.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
diff --git a/chrome/browser/ui/views/tabs/dragged_tab_controller.cc b/chrome/browser/ui/views/tabs/dragged_tab_controller.cc
index 691f99f..d7e350a 100644
--- a/chrome/browser/ui/views/tabs/dragged_tab_controller.cc
+++ b/chrome/browser/ui/views/tabs/dragged_tab_controller.cc
@@ -28,7 +28,8 @@
#include "chrome/browser/views/tabs/side_tab_strip.h"
#include "chrome/browser/views/tabs/tab.h"
#include "chrome/browser/views/tabs/tab_strip.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
#include "gfx/canvas_skia.h"
#include "grit/theme_resources.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -42,8 +43,8 @@
#endif
#if defined(OS_LINUX)
-#include <gdk/gdk.h>
-#include <gdk/gdkkeysyms.h>
+#include <gdk/gdk.h> // NOLINT
+#include <gdk/gdkkeysyms.h> // NOLINT
#endif
static const int kHorizontalMoveThreshold = 16; // Pixels.
diff --git a/chrome/browser/ui/views/tabs/dragged_tab_controller.h b/chrome/browser/ui/views/tabs/dragged_tab_controller.h
index 2d00ac6..78481ae 100644
--- a/chrome/browser/ui/views/tabs/dragged_tab_controller.h
+++ b/chrome/browser/ui/views/tabs/dragged_tab_controller.h
@@ -9,9 +9,9 @@
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
#include "base/timer.h"
-#include "chrome/browser/dock_info.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
-#include "chrome/browser/tab_contents_wrapper.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "chrome/browser/ui/tabs/dock_info.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "gfx/rect.h"
diff --git a/chrome/browser/ui/views/tabs/side_tab_strip.cc b/chrome/browser/ui/views/tabs/side_tab_strip.cc
index b449bb9..c9e2b69 100644
--- a/chrome/browser/ui/views/tabs/side_tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/side_tab_strip.cc
@@ -6,9 +6,9 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
-#include "chrome/browser/views/tabs/side_tab.h"
-#include "chrome/browser/views/tabs/tab_strip_controller.h"
-#include "chrome/browser/view_ids.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/tabs/side_tab.h"
+#include "chrome/browser/ui/views/tabs/tab_strip_controller.h"
#include "gfx/canvas.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index dda22fb..59cab04 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/views/tabs/tab.h"
+#include "chrome/browser/ui/views/tabs/tab.h"
#include <limits>
@@ -357,6 +357,13 @@ bool Tab::GetTooltipTextOrigin(const gfx::Point& p, gfx::Point* origin) {
return true;
}
+void Tab::OnMouseMoved(const views::MouseEvent& e) {
+ hover_point_ = e.location();
+ // We need to redraw here because otherwise the hover glow does not update
+ // and follow the new mouse position.
+ SchedulePaint();
+}
+
////////////////////////////////////////////////////////////////////////////////
// Tab, private
@@ -465,13 +472,18 @@ void Tab::PaintInactiveTabBackground(gfx::Canvas* canvas) {
int bg_offset_y = GetThemeProvider()->HasCustomImage(tab_id) ?
0 : background_offset_.y();
+ // We need a CanvasSkia object to be able to extract the bitmap from.
+ // We draw everything to this canvas and then output it to the canvas
+ // parameter in addition to using it to mask the hover glow if needed.
+ gfx::CanvasSkia background_canvas(width(), height(), false);
+
// Draw left edge. Don't draw over the toolbar, as we're not the foreground
// tab.
SkBitmap tab_l = SkBitmapOperations::CreateTiledBitmap(
*tab_bg, offset, bg_offset_y, tab_image->l_width, height());
SkBitmap theme_l =
SkBitmapOperations::CreateMaskedBitmap(tab_l, *alpha->image_l);
- canvas->DrawBitmapInt(theme_l,
+ background_canvas.DrawBitmapInt(theme_l,
0, 0, theme_l.width(), theme_l.height() - kToolbarOverlap,
0, 0, theme_l.width(), theme_l.height() - kToolbarOverlap,
false);
@@ -482,7 +494,7 @@ void Tab::PaintInactiveTabBackground(gfx::Canvas* canvas) {
tab_image->r_width, height());
SkBitmap theme_r =
SkBitmapOperations::CreateMaskedBitmap(tab_r, *alpha->image_r);
- canvas->DrawBitmapInt(theme_r,
+ background_canvas.DrawBitmapInt(theme_r,
0, 0, theme_r.width(), theme_r.height() - kToolbarOverlap,
width() - theme_r.width(), 0, theme_r.width(),
theme_r.height() - kToolbarOverlap, false);
@@ -490,7 +502,7 @@ void Tab::PaintInactiveTabBackground(gfx::Canvas* canvas) {
// Draw center. Instead of masking out the top portion we simply skip over
// it by incrementing by kDropShadowHeight, since it's a simple rectangle.
// And again, don't draw over the toolbar.
- canvas->TileImageInt(*tab_bg,
+ background_canvas.TileImageInt(*tab_bg,
offset + tab_image->l_width,
bg_offset_y + kDropShadowHeight + tab_image->y_offset,
tab_image->l_width,
@@ -498,6 +510,17 @@ void Tab::PaintInactiveTabBackground(gfx::Canvas* canvas) {
width() - tab_image->l_width - tab_image->r_width,
height() - kDropShadowHeight - kToolbarOverlap - tab_image->y_offset);
+ canvas->DrawBitmapInt(background_canvas.ExtractBitmap(), 0, 0);
+
+ if (!GetThemeProvider()->HasCustomImage(tab_id) &&
+ hover_animation() && hover_animation()->IsShowing()) {
+ SkBitmap hover_glow = DrawHoverGlowBitmap(width(), height());
+ // Draw the hover glow clipped to the background into hover_image.
+ SkBitmap hover_image = SkBitmapOperations::CreateMaskedBitmap(
+ hover_glow, background_canvas.ExtractBitmap());
+ canvas->DrawBitmapInt(hover_image, 0, 0);
+ }
+
// Now draw the highlights/shadows around the tab edge.
canvas->DrawBitmapInt(*tab_inactive_image->image_l, 0, 0);
canvas->TileImageInt(*tab_inactive_image->image_c,
@@ -552,6 +575,43 @@ void Tab::PaintActiveTabBackground(gfx::Canvas* canvas) {
canvas->DrawBitmapInt(*tab_image->image_r, width() - tab_image->r_width, 0);
}
+SkBitmap Tab::DrawHoverGlowBitmap(int width_input, int height_input) {
+ // Draw a radial gradient to hover_canvas so we can export the bitmap.
+ gfx::CanvasSkia hover_canvas(width_input, height_input, false);
+
+ // Draw a radial gradient to hover_canvas.
+ int radius = width() / 3;
+
+ SkPaint paint;
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setFlags(SkPaint::kAntiAlias_Flag);
+ SkPoint loc = { SkIntToScalar(hover_point_.x()),
+ SkIntToScalar(hover_point_.y()) };
+ SkColor colors[2];
+ const SlideAnimation* hover_slide = hover_animation();
+ int hover_alpha = 0;
+ if (hover_slide) {
+ hover_alpha =
+ static_cast<int>(255 * kHoverOpacity * hover_slide->GetCurrentValue());
+ }
+ colors[0] = SkColorSetARGB(hover_alpha, 255, 255, 255);
+ colors[1] = SkColorSetARGB(0, 255, 255, 255);
+ SkShader* shader = SkGradientShader::CreateRadial(
+ loc,
+ SkIntToScalar(radius),
+ colors,
+ NULL,
+ 2,
+ SkShader::kClamp_TileMode);
+ paint.setShader(shader);
+ shader->unref();
+ hover_canvas.DrawRectInt(hover_point_.x() - radius,
+ hover_point_.y() - radius,
+ radius * 2, radius * 2, paint);
+
+ return hover_canvas.ExtractBitmap();
+}
+
int Tab::IconCapacity() const {
if (height() < GetMinimumUnselectedSize().height())
return 0;
diff --git a/chrome/browser/ui/views/tabs/tab.h b/chrome/browser/ui/views/tabs/tab.h
index 1394e4b..a3da1c5 100644
--- a/chrome/browser/ui/views/tabs/tab.h
+++ b/chrome/browser/ui/views/tabs/tab.h
@@ -75,12 +75,14 @@ class Tab : public BaseTab {
virtual bool HasHitTestMask() const;
virtual void GetHitTestMask(gfx::Path* path) const;
virtual bool GetTooltipTextOrigin(const gfx::Point& p, gfx::Point* origin);
+ virtual void OnMouseMoved(const views::MouseEvent& event);
// Paint various portions of the Tab
void PaintTabBackground(gfx::Canvas* canvas);
void PaintInactiveTabBackgroundWithTitleChange(gfx::Canvas* canvas);
void PaintInactiveTabBackground(gfx::Canvas* canvas);
void PaintActiveTabBackground(gfx::Canvas* canvas);
+ SkBitmap DrawHoverGlowBitmap(int width, int height);
// Returns the number of favicon-size elements that can fit in the tab's
// current size.
@@ -104,8 +106,8 @@ class Tab : public BaseTab {
// The offset used to paint the inactive background image.
gfx::Point background_offset_;
- // Hover animation.
- scoped_ptr<SlideAnimation> hover_animation_;
+ // The center point for the radial hover glow.
+ gfx::Point hover_point_;
// Animation used when the title of an inactive mini tab changes.
scoped_ptr<MultiAnimation> mini_title_animation_;
diff --git a/chrome/browser/ui/views/tabs/tab_dragging_test.cc b/chrome/browser/ui/views/tabs/tab_dragging_test.cc
index 2cb0171..dc433ad 100644
--- a/chrome/browser/ui/views/tabs/tab_dragging_test.cc
+++ b/chrome/browser/ui/views/tabs/tab_dragging_test.cc
@@ -5,7 +5,7 @@
#include "base/command_line.h"
#include "base/file_util.h"
#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/view_ids.h"
+#include "chrome/browser/ui/view_ids.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index 247475b..d8e03f2 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -13,9 +13,9 @@
#include "chrome/browser/defaults.h"
#include "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/view_ids.h"
-#include "chrome/browser/views/tabs/tab.h"
-#include "chrome/browser/views/tabs/tab_strip_controller.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/tabs/tab.h"
+#include "chrome/browser/ui/views/tabs/tab_strip_controller.h"
#include "chrome/common/pref_names.h"
#include "gfx/canvas_skia.h"
#include "gfx/path.h"
diff --git a/chrome/browser/ui/views/task_manager_view.cc b/chrome/browser/ui/views/task_manager_view.cc
index 489bebf..99061c6 100644
--- a/chrome/browser/ui/views/task_manager_view.cc
+++ b/chrome/browser/ui/views/task_manager_view.cc
@@ -189,6 +189,10 @@ void TaskManagerTableModel::OnItemsAdded(int start, int length) {
void TaskManagerTableModel::OnItemsRemoved(int start, int length) {
if (observer_)
observer_->OnItemsRemoved(start, length);
+
+ // We may need to change the indentation of some items if the topmost item
+ // in the group was removed, so update the view.
+ OnModelChanged();
}
// The Task manager UI container.
diff --git a/chrome/browser/ui/views/theme_background.cc b/chrome/browser/ui/views/theme_background.cc
index ad8d2ed..b2320fc 100644
--- a/chrome/browser/ui/views/theme_background.cc
+++ b/chrome/browser/ui/views/theme_background.cc
@@ -5,7 +5,7 @@
#include "chrome/browser/views/theme_background.h"
#include "app/resource_bundle.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/browser/views/frame/browser_view.h"
#include "gfx/canvas.h"
diff --git a/chrome/browser/ui/views/theme_install_bubble_view.cc b/chrome/browser/ui/views/theme_install_bubble_view.cc
index 7593fc7..d811774 100644
--- a/chrome/browser/ui/views/theme_install_bubble_view.cc
+++ b/chrome/browser/ui/views/theme_install_bubble_view.cc
@@ -7,6 +7,7 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/notification_service.h"
#include "gfx/canvas_skia.h"
#include "grit/generated_resources.h"
#include "views/widget/widget.h"
@@ -24,7 +25,7 @@ static const int kTextVertPadding = 45;
// track of number of loads happening. Close bubble when num_loads < 1.
static int num_loads_extant_ = 0;
-}
+} // namespace
ThemeInstallBubbleView::ThemeInstallBubbleView(TabContents* tab_contents)
: popup_(NULL) {
@@ -162,4 +163,3 @@ void ThemeInstallBubbleView::Show(TabContents* tab_contents) {
if (num_loads_extant_ < 2)
new ThemeInstallBubbleView(tab_contents);
}
-
diff --git a/chrome/browser/ui/views/theme_install_bubble_view.h b/chrome/browser/ui/views/theme_install_bubble_view.h
index f0460b9..ca4c827 100644
--- a/chrome/browser/ui/views/theme_install_bubble_view.h
+++ b/chrome/browser/ui/views/theme_install_bubble_view.h
@@ -10,7 +10,6 @@
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
#include "gfx/canvas.h"
#include "views/controls/label.h"
@@ -76,4 +75,3 @@ class ThemeInstallBubbleView : public NotificationObserver,
};
#endif // CHROME_BROWSER_UI_VIEWS_THEME_INSTALL_BUBBLE_VIEW_H_
-
diff --git a/chrome/browser/ui/views/toolbar_view.cc b/chrome/browser/ui/views/toolbar_view.cc
index 43806a5..7044ec2 100644
--- a/chrome/browser/ui/views/toolbar_view.cc
+++ b/chrome/browser/ui/views/toolbar_view.cc
@@ -10,17 +10,17 @@
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/accessibility/browser_accessibility_state.h"
#include "chrome/browser/background_page_tracker.h"
-#include "chrome/browser/browser_window.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/themes/browser_theme_provider.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/toolbar/wrench_menu_model.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/browser_actions_container.h"
+#include "chrome/browser/ui/views/event_utils.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/upgrade_detector.h"
-#include "chrome/browser/view_ids.h"
-#include "chrome/browser/views/browser_actions_container.h"
-#include "chrome/browser/views/event_utils.h"
-#include "chrome/browser/views/frame/browser_view.h"
-#include "chrome/browser/wrench_menu_model.h"
#include "chrome/common/badge_util.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
@@ -233,7 +233,7 @@ void ToolbarView::Init(Profile* profile) {
SetProfile(profile);
// Accessibility specific tooltip text.
- if (Singleton<BrowserAccessibilityState>()->IsAccessibleBrowser()) {
+ if (BrowserAccessibilityState::GetInstance()->IsAccessibleBrowser()) {
back_->SetTooltipText(l10n_util::GetString(IDS_ACCNAME_TOOLTIP_BACK));
forward_->SetTooltipText(l10n_util::GetString(IDS_ACCNAME_TOOLTIP_FORWARD));
}
@@ -355,7 +355,7 @@ cleanup:
destroyed_flag_ = NULL;
// Stop showing the background app badge also.
- BackgroundPageTracker::GetSingleton()->AcknowledgeBackgroundPages();
+ BackgroundPageTracker::GetInstance()->AcknowledgeBackgroundPages();
}
////////////////////////////////////////////////////////////////////////////////
@@ -628,18 +628,18 @@ bool ToolbarView::IsUpgradeRecommended() {
return (chromeos::CrosLibrary::Get()->GetUpdateLibrary()->status().status ==
chromeos::UPDATE_STATUS_UPDATED_NEED_REBOOT);
#else
- return (Singleton<UpgradeDetector>::get()->notify_upgrade());
+ return (UpgradeDetector::GetInstance()->notify_upgrade());
#endif
}
bool ToolbarView::ShouldShowBackgroundPageBadge() {
- return BackgroundPageTracker::GetSingleton()->
+ return BackgroundPageTracker::GetInstance()->
GetUnacknowledgedBackgroundPageCount() > 0;
}
bool ToolbarView::ShouldShowIncompatibilityWarning() {
#if defined(OS_WIN)
- EnumerateModulesModel* loaded_modules = EnumerateModulesModel::GetSingleton();
+ EnumerateModulesModel* loaded_modules = EnumerateModulesModel::GetInstance();
return loaded_modules->confirmed_bad_modules_detected() > 0;
#else
return false;
@@ -761,7 +761,7 @@ SkBitmap ToolbarView::GetBackgroundPageBadge() {
ThemeProvider* tp = GetThemeProvider();
SkBitmap* badge = tp->GetBitmapNamed(IDR_BACKGROUND_BADGE);
string16 badge_text = base::FormatNumber(
- BackgroundPageTracker::GetSingleton()->GetBackgroundPageCount());
+ BackgroundPageTracker::GetInstance()->GetBackgroundPageCount());
return badge_util::DrawBadgeIconOverlay(
*badge,
kBadgeTextFontSize,
diff --git a/chrome/browser/ui/views/toolbar_view.h b/chrome/browser/ui/views/toolbar_view.h
index 3553ed2..e8c13af 100644
--- a/chrome/browser/ui/views/toolbar_view.h
+++ b/chrome/browser/ui/views/toolbar_view.h
@@ -12,12 +12,12 @@
#include "app/slide_animation.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
-#include "chrome/browser/back_forward_menu_model.h"
#include "chrome/browser/command_updater.h"
#include "chrome/browser/prefs/pref_member.h"
-#include "chrome/browser/views/accessible_pane_view.h"
-#include "chrome/browser/views/location_bar/location_bar_view.h"
-#include "chrome/browser/views/reload_button.h"
+#include "chrome/browser/ui/toolbar/back_forward_menu_model.h"
+#include "chrome/browser/ui/views/accessible_pane_view.h"
+#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
+#include "chrome/browser/ui/views/reload_button.h"
#include "views/controls/button/menu_button.h"
#include "views/controls/menu/menu.h"
#include "views/controls/menu/menu_wrapper.h"
diff --git a/chrome/browser/ui/views/uninstall_view.cc b/chrome/browser/ui/views/uninstall_view.cc
index a7535b0..ecd2ac7 100644
--- a/chrome/browser/ui/views/uninstall_view.cc
+++ b/chrome/browser/ui/views/uninstall_view.cc
@@ -65,10 +65,11 @@ void UninstallView::SetupControls() {
layout->AddView(delete_profile_);
// Set default browser combo box
- if (BrowserDistribution::GetDistribution()->CanSetAsDefault() &&
+ BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+ if (dist->CanSetAsDefault() &&
ShellIntegration::IsDefaultBrowser()) {
browsers_.reset(new BrowsersMap());
- ShellUtil::GetRegisteredBrowsers(browsers_.get());
+ ShellUtil::GetRegisteredBrowsers(dist, browsers_.get());
if (!browsers_->empty()) {
layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
diff --git a/chrome/browser/ui/views/url_picker.cc b/chrome/browser/ui/views/url_picker.cc
index 4051e63..14a294c 100644
--- a/chrome/browser/ui/views/url_picker.cc
+++ b/chrome/browser/ui/views/url_picker.cc
@@ -14,8 +14,7 @@
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/possible_url_model.h"
#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "grit/app_resources.h"
#include "grit/generated_resources.h"
diff --git a/chrome/browser/ui/views/wrench_menu.cc b/chrome/browser/ui/views/wrench_menu.cc
index c798d5a..3d86f91 100644
--- a/chrome/browser/ui/views/wrench_menu.cc
+++ b/chrome/browser/ui/views/wrench_menu.cc
@@ -11,7 +11,7 @@
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/notification_observer.h"
@@ -683,40 +683,11 @@ MenuItemView* WrenchMenu::AppendMenuItem(MenuItemView* parent,
MenuModel::ItemType menu_type,
int* next_id) {
int id = (*next_id)++;
- SkBitmap icon;
- std::wstring label;
- MenuItemView::Type type;
- switch (menu_type) {
- case MenuModel::TYPE_COMMAND:
- model->GetIconAt(index, &icon);
- type = MenuItemView::NORMAL;
- label = UTF16ToWide(model->GetLabelAt(index));
- break;
- case MenuModel::TYPE_CHECK:
- type = MenuItemView::CHECKBOX;
- label = UTF16ToWide(model->GetLabelAt(index));
- break;
- case MenuModel::TYPE_RADIO:
- type = MenuItemView::RADIO;
- label = UTF16ToWide(model->GetLabelAt(index));
- break;
- case MenuModel::TYPE_SEPARATOR:
- type = MenuItemView::SEPARATOR;
- break;
- case MenuModel::TYPE_SUBMENU:
- type = MenuItemView::SUBMENU;
- label = UTF16ToWide(model->GetLabelAt(index));
- break;
- default:
- NOTREACHED();
- type = MenuItemView::NORMAL;
- break;
- }
id_to_entry_[id].first = model;
id_to_entry_[id].second = index;
- MenuItemView* menu_item = parent->AppendMenuItemImpl(id, label, icon, type);
+ MenuItemView* menu_item = parent->AppendMenuItemFromModel(model, index, id);
if (menu_item)
menu_item->SetVisible(model->IsVisibleAt(index));
diff --git a/chrome/browser/ui/window_sizer.cc b/chrome/browser/ui/window_sizer.cc
new file mode 100644
index 0000000..292f5fc
--- /dev/null
+++ b/chrome/browser/ui/window_sizer.cc
@@ -0,0 +1,336 @@
+// 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.
+
+#include "chrome/browser/ui/window_sizer.h"
+
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/common/pref_names.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// An implementation of WindowSizer::StateProvider that gets the last active
+// and persistent state from the browser window and the user's profile.
+class DefaultStateProvider : public WindowSizer::StateProvider {
+ public:
+ explicit DefaultStateProvider(const std::string& app_name, Browser* browser)
+ : app_name_(app_name),
+ browser_(browser) {
+ }
+
+ // Overridden from WindowSizer::StateProvider:
+ virtual bool GetPersistentState(gfx::Rect* bounds,
+ bool* maximized,
+ gfx::Rect* work_area) const {
+ DCHECK(bounds && maximized);
+
+ std::string key(prefs::kBrowserWindowPlacement);
+ if (!app_name_.empty()) {
+ key.append("_");
+ key.append(app_name_);
+ }
+
+ if (!g_browser_process->local_state())
+ return false;
+
+ const DictionaryValue* wp_pref =
+ g_browser_process->local_state()->GetDictionary(key.c_str());
+ int top = 0, left = 0, bottom = 0, right = 0;
+ bool has_prefs =
+ wp_pref &&
+ wp_pref->GetInteger("top", &top) &&
+ wp_pref->GetInteger("left", &left) &&
+ wp_pref->GetInteger("bottom", &bottom) &&
+ wp_pref->GetInteger("right", &right) &&
+ wp_pref->GetBoolean("maximized", maximized);
+ bounds->SetRect(left, top, std::max(0, right - left),
+ std::max(0, bottom - top));
+
+ int work_area_top = 0;
+ int work_area_left = 0;
+ int work_area_bottom = 0;
+ int work_area_right = 0;
+ if (wp_pref) {
+ wp_pref->GetInteger("work_area_top", &work_area_top);
+ wp_pref->GetInteger("work_area_left", &work_area_left);
+ wp_pref->GetInteger("work_area_bottom", &work_area_bottom);
+ wp_pref->GetInteger("work_area_right", &work_area_right);
+ }
+ work_area->SetRect(work_area_left, work_area_top,
+ std::max(0, work_area_right - work_area_left),
+ std::max(0, work_area_bottom - work_area_top));
+
+ return has_prefs;
+ }
+
+ virtual bool GetLastActiveWindowState(gfx::Rect* bounds) const {
+ // Applications are always restored with the same position.
+ if (!app_name_.empty())
+ return false;
+
+ // If a reference browser is set, use its window. Otherwise find last
+ // active.
+ BrowserWindow* window = NULL;
+ if (browser_) {
+ window = browser_->window();
+ DCHECK(window);
+ } else {
+ BrowserList::const_reverse_iterator it = BrowserList::begin_last_active();
+ BrowserList::const_reverse_iterator end = BrowserList::end_last_active();
+ for (; (it != end); ++it) {
+ Browser* last_active = *it;
+ if (last_active && last_active->type() == Browser::TYPE_NORMAL) {
+ window = last_active->window();
+ DCHECK(window);
+ break;
+ }
+ }
+ }
+
+ if (window) {
+ *bounds = window->GetRestoredBounds();
+ return true;
+ }
+
+ return false;
+ }
+
+ private:
+ std::string app_name_;
+
+ // If set, is used as the reference browser for GetLastActiveWindowState.
+ Browser* browser_;
+ DISALLOW_COPY_AND_ASSIGN(DefaultStateProvider);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// MonitorInfoProvider, public:
+
+WindowSizer::MonitorInfoProvider::MonitorInfoProvider() {}
+
+WindowSizer::MonitorInfoProvider::~MonitorInfoProvider() {}
+
+///////////////////////////////////////////////////////////////////////////////
+// WindowSizer, public:
+
+WindowSizer::WindowSizer(
+ StateProvider* state_provider,
+ MonitorInfoProvider* monitor_info_provider) {
+ Init(state_provider, monitor_info_provider);
+}
+
+WindowSizer::~WindowSizer() {
+ if (state_provider_)
+ delete state_provider_;
+ if (monitor_info_provider_)
+ delete monitor_info_provider_;
+}
+
+// static
+void WindowSizer::GetBrowserWindowBounds(const std::string& app_name,
+ const gfx::Rect& specified_bounds,
+ Browser* browser,
+ gfx::Rect* window_bounds,
+ bool* maximized) {
+ const WindowSizer sizer(new DefaultStateProvider(app_name, browser),
+ CreateDefaultMonitorInfoProvider());
+ sizer.DetermineWindowBounds(specified_bounds, window_bounds, maximized);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// WindowSizer, private:
+
+WindowSizer::WindowSizer(const std::string& app_name) {
+ Init(new DefaultStateProvider(app_name, NULL),
+ CreateDefaultMonitorInfoProvider());
+}
+
+void WindowSizer::Init(StateProvider* state_provider,
+ MonitorInfoProvider* monitor_info_provider) {
+ state_provider_ = state_provider;
+ monitor_info_provider_ = monitor_info_provider;
+}
+
+void WindowSizer::DetermineWindowBounds(const gfx::Rect& specified_bounds,
+ gfx::Rect* bounds,
+ bool* maximized) const {
+ *bounds = specified_bounds;
+ if (bounds->IsEmpty()) {
+ // See if there's saved placement information.
+ if (!GetLastWindowBounds(bounds)) {
+ if (!GetSavedWindowBounds(bounds, maximized)) {
+ // No saved placement, figure out some sensible default size based on
+ // the user's screen size.
+ GetDefaultWindowBounds(bounds);
+ }
+ }
+ }
+}
+
+bool WindowSizer::GetLastWindowBounds(gfx::Rect* bounds) const {
+ DCHECK(bounds);
+ if (!state_provider_ || !state_provider_->GetLastActiveWindowState(bounds))
+ return false;
+ gfx::Rect last_window_bounds = *bounds;
+ bounds->Offset(kWindowTilePixels, kWindowTilePixels);
+ AdjustBoundsToBeVisibleOnMonitorContaining(last_window_bounds,
+ gfx::Rect(),
+ bounds);
+ return true;
+}
+
+bool WindowSizer::GetSavedWindowBounds(gfx::Rect* bounds,
+ bool* maximized) const {
+ DCHECK(bounds && maximized);
+ gfx::Rect saved_work_area;
+ if (!state_provider_ ||
+ !state_provider_->GetPersistentState(bounds, maximized, &saved_work_area))
+ return false;
+ AdjustBoundsToBeVisibleOnMonitorContaining(*bounds, saved_work_area, bounds);
+ return true;
+}
+
+void WindowSizer::GetDefaultWindowBounds(gfx::Rect* default_bounds) const {
+ DCHECK(default_bounds);
+ DCHECK(monitor_info_provider_);
+
+ gfx::Rect work_area = monitor_info_provider_->GetPrimaryMonitorWorkArea();
+
+ // The default size is either some reasonably wide width, or if the work
+ // area is narrower, then the work area width less some aesthetic padding.
+ int default_width = std::min(work_area.width() - 2 * kWindowTilePixels, 1050);
+ int default_height = work_area.height() - 2 * kWindowTilePixels;
+
+ // For wider aspect ratio displays at higher resolutions, we might size the
+ // window narrower to allow two windows to easily be placed side-by-side.
+ gfx::Rect screen_size = monitor_info_provider_->GetPrimaryMonitorBounds();
+ double width_to_height =
+ static_cast<double>(screen_size.width()) / screen_size.height();
+
+ // The least wide a screen can be to qualify for the halving described above.
+ static const int kMinScreenWidthForWindowHalving = 1600;
+ // We assume 16:9/10 is a fairly standard indicator of a wide aspect ratio
+ // computer display.
+ if (((width_to_height * 10) >= 16) &&
+ work_area.width() > kMinScreenWidthForWindowHalving) {
+ // Halve the work area, subtracting aesthetic padding on either side.
+ // The padding is set so that two windows, side by side have
+ // kWindowTilePixels between screen edge and each other.
+ default_width = static_cast<int>(work_area.width() / 2. -
+ 1.5 * kWindowTilePixels);
+ }
+ default_bounds->SetRect(kWindowTilePixels + work_area.x(),
+ kWindowTilePixels + work_area.y(),
+ default_width, default_height);
+}
+
+bool WindowSizer::PositionIsOffscreen(int position, Edge edge) const {
+ DCHECK(monitor_info_provider_);
+ size_t monitor_count = monitor_info_provider_->GetMonitorCount();
+ for (size_t i = 0; i < monitor_count; ++i) {
+ gfx::Rect work_area = monitor_info_provider_->GetWorkAreaAt(i);
+ switch (edge) {
+ case TOP:
+ if (position >= work_area.y())
+ return false;
+ break;
+ case LEFT:
+ if (position >= work_area.x())
+ return false;
+ break;
+ case BOTTOM:
+ if (position <= work_area.bottom())
+ return false;
+ break;
+ case RIGHT:
+ if (position <= work_area.right())
+ return false;
+ break;
+ }
+ }
+ return true;
+}
+
+namespace {
+ // Minimum height of the visible part of a window.
+ static const int kMinVisibleHeight = 30;
+ // Minimum width of the visible part of a window.
+ static const int kMinVisibleWidth = 30;
+}
+
+void WindowSizer::AdjustBoundsToBeVisibleOnMonitorContaining(
+ const gfx::Rect& other_bounds,
+ const gfx::Rect& saved_work_area,
+ gfx::Rect* bounds) const {
+ DCHECK(bounds);
+ DCHECK(monitor_info_provider_);
+
+ // Find the size of the work area of the monitor that intersects the bounds
+ // of the anchor window.
+ gfx::Rect work_area =
+ monitor_info_provider_->GetMonitorWorkAreaMatching(other_bounds);
+
+ // If height or width are 0, reset to the default size.
+ gfx::Rect default_bounds;
+ GetDefaultWindowBounds(&default_bounds);
+ if (bounds->height() <= 0)
+ bounds->set_height(default_bounds.height());
+ if (bounds->width() <= 0)
+ bounds->set_width(default_bounds.width());
+
+ // Ensure the minimum height and width.
+ bounds->set_height(std::max(kMinVisibleHeight, bounds->height()));
+ bounds->set_width(std::max(kMinVisibleWidth, bounds->width()));
+
+ // Ensure that the title bar is not above the work area.
+ if (bounds->y() < work_area.y())
+ bounds->set_y(work_area.y());
+
+ // Reposition and resize the bounds if the saved_work_area is different from
+ // the current work area and the current work area doesn't completely contain
+ // the bounds.
+ if (!saved_work_area.IsEmpty() &&
+ saved_work_area != work_area &&
+ !work_area.Contains(*bounds)) {
+ bounds->set_width(std::min(bounds->width(), work_area.width()));
+ bounds->set_height(std::min(bounds->height(), work_area.height()));
+ bounds->set_x(
+ std::max(work_area.x(),
+ std::min(bounds->x(), work_area.right() - bounds->width())));
+ bounds->set_y(
+ std::max(work_area.y(),
+ std::min(bounds->y(), work_area.bottom() - bounds->height())));
+ }
+
+#if defined(OS_MACOSX)
+ // Limit the maximum height. On the Mac the sizer is on the
+ // bottom-right of the window, and a window cannot be moved "up"
+ // past the menubar. If the window is too tall you'll never be able
+ // to shrink it again. Windows does not have this limitation
+ // (e.g. can be resized from the top).
+ bounds->set_height(std::min(work_area.height(), bounds->height()));
+
+ // On mac, we want to be aggressive about repositioning windows that are
+ // partially offscreen. If the window is partially offscreen horizontally,
+ // move it to be flush with the left edge of the work area.
+ if (bounds->x() < work_area.x() || bounds->right() > work_area.right())
+ bounds->set_x(work_area.x());
+
+ // If the window is partially offscreen vertically, move it to be flush with
+ // the top of the work area.
+ if (bounds->y() < work_area.y() || bounds->bottom() > work_area.bottom())
+ bounds->set_y(work_area.y());
+#else
+ // On non-Mac platforms, we are less aggressive about repositioning. Simply
+ // ensure that at least kMinVisibleWidth * kMinVisibleHeight is visible.
+ const int min_y = work_area.y() + kMinVisibleHeight - bounds->height();
+ const int min_x = work_area.x() + kMinVisibleWidth - bounds->width();
+ const int max_y = work_area.bottom() - kMinVisibleHeight;
+ const int max_x = work_area.right() - kMinVisibleWidth;
+ bounds->set_y(std::max(min_y, std::min(max_y, bounds->y())));
+ bounds->set_x(std::max(min_x, std::min(max_x, bounds->x())));
+#endif // defined(OS_MACOSX)
+}
diff --git a/chrome/browser/ui/window_sizer.h b/chrome/browser/ui/window_sizer.h
new file mode 100644
index 0000000..7d34399
--- /dev/null
+++ b/chrome/browser/ui/window_sizer.h
@@ -0,0 +1,184 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_WINDOW_SIZER_H_
+#define CHROME_BROWSER_UI_WINDOW_SIZER_H_
+#pragma once
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "gfx/rect.h"
+
+class Browser;
+
+///////////////////////////////////////////////////////////////////////////////
+// WindowSizer
+//
+// A class that determines the best new size and position for a window to be
+// shown at based several factors, including the position and size of the last
+// window of the same type, the last saved bounds of the window from the
+// previous session, and default system metrics if neither of the above two
+// conditions exist. The system has built-in providers for monitor metrics
+// and persistent storage (using preferences) but can be overrided with mocks
+// for testing.
+//
+class WindowSizer {
+ public:
+ class MonitorInfoProvider;
+ class StateProvider;
+
+ // The WindowSizer assumes ownership of these objects.
+ WindowSizer(StateProvider* state_provider,
+ MonitorInfoProvider* monitor_info_provider);
+ virtual ~WindowSizer();
+
+ // Static factory methods to create default MonitorInfoProvider
+ // instances. The returned object is owned by the caller.
+ static MonitorInfoProvider* CreateDefaultMonitorInfoProvider();
+
+ // An interface implemented by an object that can retrieve information about
+ // the monitors on the system.
+ class MonitorInfoProvider {
+ public:
+ MonitorInfoProvider();
+ virtual ~MonitorInfoProvider();
+
+ // Returns the bounds of the work area of the primary monitor.
+ virtual gfx::Rect GetPrimaryMonitorWorkArea() const = 0;
+
+ // Returns the bounds of the primary monitor.
+ virtual gfx::Rect GetPrimaryMonitorBounds() const = 0;
+
+ // Returns the bounds of the work area of the monitor that most closely
+ // intersects the provided bounds.
+ virtual gfx::Rect GetMonitorWorkAreaMatching(
+ const gfx::Rect& match_rect) const = 0;
+
+ // Returns the delta between the work area and the monitor bounds for the
+ // monitor that most closely intersects the provided bounds.
+ virtual gfx::Point GetBoundsOffsetMatching(
+ const gfx::Rect& match_rect) const = 0;
+
+ // Ensures number and coordinates of work areas are up-to-date. You must
+ // call this before calling either of the below functions, as work areas can
+ // change while the program is running.
+ virtual void UpdateWorkAreas() = 0;
+
+ // Returns the number of monitors on the system.
+ size_t GetMonitorCount() const {
+ return work_areas_.size();
+ }
+
+ // Returns the bounds of the work area of the monitor at the specified
+ // index.
+ gfx::Rect GetWorkAreaAt(size_t index) const {
+ return work_areas_[index];
+ }
+
+ protected:
+ std::vector<gfx::Rect> work_areas_;
+ };
+
+ // An interface implemented by an object that can retrieve state from either a
+ // persistent store or an existing window.
+ class StateProvider {
+ public:
+ virtual ~StateProvider() { }
+
+ // Retrieve the persisted bounds of the window. Returns true if there was
+ // persisted data to retrieve state information, false otherwise.
+ virtual bool GetPersistentState(gfx::Rect* bounds,
+ bool* maximized,
+ gfx::Rect* work_area) const = 0;
+
+ // Retrieve the bounds of the most recent window of the matching type.
+ // Returns true if there was a last active window to retrieve state
+ // information from, false otherwise.
+ virtual bool GetLastActiveWindowState(gfx::Rect* bounds) const = 0;
+ };
+
+ // Determines the position, size and maximized state for a window as it is
+ // created. This function uses several strategies to figure out optimal size
+ // and placement, first looking for an existing active window, then falling
+ // back to persisted data from a previous session, finally utilizing a default
+ // algorithm. If |specified_bounds| are non-empty, this value is returned
+ // instead. For use only in testing.
+ //
+ // NOTE: |maximized| is only set if we're restoring a saved maximized window.
+ // When creating a new window based on an existing active window, standard
+ // Windows behavior is to have it always be nonmaximized, even if the existing
+ // window is maximized.
+ void DetermineWindowBounds(const gfx::Rect& specified_bounds,
+ gfx::Rect* bounds,
+ bool* maximized) const;
+
+ // Determines the size, position and maximized state for the browser window.
+ // See documentation for DetermineWindowBounds above. Normally,
+ // |window_bounds| is calculated by calling GetLastActiveWindowState(). To
+ // explicitly specify a particular window to base the bounds on, pass in a
+ // non-NULL value for |browser|.
+ static void GetBrowserWindowBounds(const std::string& app_name,
+ const gfx::Rect& specified_bounds,
+ Browser* browser,
+ gfx::Rect* window_bounds,
+ bool* maximized);
+
+ // Returns the default origin for popups of the given size.
+ static gfx::Point GetDefaultPopupOrigin(const gfx::Size& size);
+
+ // How much horizontal and vertical offset there is between newly
+ // opened windows. This value may be different on each platform.
+ static const int kWindowTilePixels;
+
+ private:
+ // The edge of the screen to check for out-of-bounds.
+ enum Edge { TOP, LEFT, BOTTOM, RIGHT };
+
+ explicit WindowSizer(const std::string& app_name);
+
+ void Init(StateProvider* state_provider,
+ MonitorInfoProvider* monitor_info_provider);
+
+ // Gets the size and placement of the last window. Returns true if this data
+ // is valid, false if there is no last window and the application should
+ // restore saved state from preferences using RestoreWindowPosition.
+ bool GetLastWindowBounds(gfx::Rect* bounds) const;
+
+ // Gets the size and placement of the last window in the last session, saved
+ // in local state preferences. Returns true if local state exists containing
+ // this information, false if this information does not exist and a default
+ // size should be used.
+ bool GetSavedWindowBounds(gfx::Rect* bounds, bool* maximized) const;
+
+ // Gets the default window position and size if there is no last window and
+ // no saved window placement in prefs. This function determines the default
+ // size based on monitor size, etc.
+ void GetDefaultWindowBounds(gfx::Rect* default_bounds) const;
+
+ // Returns true if the specified position is "offscreen" for the given edge,
+ // meaning that it's outside all work areas in the direction of that edge.
+ bool PositionIsOffscreen(int position, Edge edge) const;
+
+ // Adjusts |bounds| to be visible onscreen, biased toward the work area of the
+ // monitor containing |other_bounds|. Despite the name, this doesn't
+ // guarantee the bounds are fully contained within this monitor's work rect;
+ // it just tried to ensure the edges are visible on _some_ work rect.
+ // If |saved_work_area| is non-empty, it is used to determine whether the
+ // monitor cofiguration has changed. If it has, bounds are repositioned and
+ // resized if necessary to make them completely contained in the current work
+ // area.
+ void AdjustBoundsToBeVisibleOnMonitorContaining(
+ const gfx::Rect& other_bounds,
+ const gfx::Rect& saved_work_area,
+ gfx::Rect* bounds) const;
+
+ // Providers for persistent storage and monitor metrics.
+ StateProvider* state_provider_;
+ MonitorInfoProvider* monitor_info_provider_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowSizer);
+};
+
+#endif // CHROME_BROWSER_WINDOW_SIZER_H_
diff --git a/chrome/browser/ui/window_sizer_linux.cc b/chrome/browser/ui/window_sizer_linux.cc
new file mode 100644
index 0000000..2d2dff6
--- /dev/null
+++ b/chrome/browser/ui/window_sizer_linux.cc
@@ -0,0 +1,131 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/window_sizer.h"
+
+#include <gtk/gtk.h>
+
+#include "base/logging.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_window.h"
+
+// Used to pad the default new window size. On Windows, this is also used for
+// positioning new windows (each window is offset from the previous one).
+// Since we don't position windows, it's only used for the default new window
+// size.
+const int WindowSizer::kWindowTilePixels = 10;
+
+// An implementation of WindowSizer::MonitorInfoProvider that gets the actual
+// monitor information from X via GDK.
+class DefaultMonitorInfoProvider : public WindowSizer::MonitorInfoProvider {
+ public:
+ DefaultMonitorInfoProvider() { }
+
+ virtual gfx::Rect GetPrimaryMonitorWorkArea() const {
+ gfx::Rect rect;
+ if (GetScreenWorkArea(&rect))
+ return rect.Intersect(GetPrimaryMonitorBounds());
+
+ // Return the best we've got.
+ return GetPrimaryMonitorBounds();
+ }
+
+ virtual gfx::Rect GetPrimaryMonitorBounds() const {
+ GdkScreen* screen = gdk_screen_get_default();
+ GdkRectangle rect;
+ gdk_screen_get_monitor_geometry(screen, 0, &rect);
+ return gfx::Rect(rect);
+ }
+
+ virtual gfx::Rect GetMonitorWorkAreaMatching(
+ const gfx::Rect& match_rect) const {
+ // TODO(thestig) Implement multi-monitor support.
+ return GetPrimaryMonitorWorkArea();
+ }
+
+ virtual gfx::Point GetBoundsOffsetMatching(
+ const gfx::Rect& match_rect) const {
+ // TODO(thestig) Implement multi-monitor support.
+ return GetPrimaryMonitorWorkArea().origin();
+ }
+
+ void UpdateWorkAreas() {
+ // TODO(thestig) Implement multi-monitor support.
+ work_areas_.clear();
+ work_areas_.push_back(GetPrimaryMonitorBounds());
+ }
+
+ private:
+ // Get the available screen space as a gfx::Rect, or return false if
+ // if it's unavailable (i.e. the window manager doesn't support
+ // retrieving this).
+ // TODO(thestig) Use _NET_CURRENT_DESKTOP here as well?
+ bool GetScreenWorkArea(gfx::Rect* out_rect) const {
+ gboolean ok;
+ guchar* raw_data = NULL;
+ gint data_len = 0;
+ ok = gdk_property_get(gdk_get_default_root_window(), // a gdk window
+ gdk_atom_intern("_NET_WORKAREA", FALSE), // property
+ gdk_atom_intern("CARDINAL", FALSE), // property type
+ 0, // byte offset into property
+ 0xff, // property length to retrieve
+ false, // delete property after retrieval?
+ NULL, // returned property type
+ NULL, // returned data format
+ &data_len, // returned data len
+ &raw_data); // returned data
+ if (!ok)
+ return false;
+
+ // We expect to get four longs back: x, y, width, height.
+ if (data_len < static_cast<gint>(4 * sizeof(glong))) {
+ NOTREACHED();
+ g_free(raw_data);
+ return false;
+ }
+
+ glong* data = reinterpret_cast<glong*>(raw_data);
+ gint x = data[0];
+ gint y = data[1];
+ gint width = data[2];
+ gint height = data[3];
+ g_free(raw_data);
+
+ out_rect->SetRect(x, y, width, height);
+ return true;
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(DefaultMonitorInfoProvider);
+};
+
+// static
+WindowSizer::MonitorInfoProvider*
+WindowSizer::CreateDefaultMonitorInfoProvider() {
+ return new DefaultMonitorInfoProvider();
+}
+
+// static
+gfx::Point WindowSizer::GetDefaultPopupOrigin(const gfx::Size& size) {
+ scoped_ptr<MonitorInfoProvider> provider(CreateDefaultMonitorInfoProvider());
+ gfx::Rect monitor_bounds = provider->GetPrimaryMonitorWorkArea();
+ gfx::Point corner(monitor_bounds.x(), monitor_bounds.y());
+ if (Browser* browser = BrowserList::GetLastActive()) {
+ GtkWindow* window =
+ reinterpret_cast<GtkWindow*>(browser->window()->GetNativeHandle());
+ int x = 0, y = 0;
+ gtk_window_get_position(window, &x, &y);
+ // Limit to not overflow the work area right and bottom edges.
+ gfx::Point limit(
+ std::min(x + kWindowTilePixels, monitor_bounds.right() - size.width()),
+ std::min(y + kWindowTilePixels,
+ monitor_bounds.bottom() - size.height()));
+ // Adjust corner to now overflow the work area left and top edges, so
+ // that if a popup does not fit the title-bar is remains visible.
+ corner = gfx::Point(
+ std::max(corner.x(), limit.x()),
+ std::max(corner.y(), limit.y()));
+ }
+ return corner;
+}
diff --git a/chrome/browser/ui/window_sizer_mac.mm b/chrome/browser/ui/window_sizer_mac.mm
new file mode 100644
index 0000000..5d1bb66
--- /dev/null
+++ b/chrome/browser/ui/window_sizer_mac.mm
@@ -0,0 +1,144 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/window_sizer.h"
+
+
+// How much horizontal and vertical offset there is between newly
+// opened windows.
+const int WindowSizer::kWindowTilePixels = 22;
+
+namespace {
+
+class DefaultMonitorInfoProvider : public WindowSizer::MonitorInfoProvider {
+ public:
+ DefaultMonitorInfoProvider() { }
+
+ // Overridden from WindowSizer::MonitorInfoProvider:
+ virtual gfx::Rect GetPrimaryMonitorWorkArea() const {
+ // Primary monitor is defined as the monitor with the menubar,
+ // which is always at index 0.
+ NSScreen* primary = [[NSScreen screens] objectAtIndex:0];
+ NSRect frame = [primary frame];
+ NSRect visible_frame = [primary visibleFrame];
+
+ // Convert coordinate systems.
+ gfx::Rect rect = gfx::Rect(NSRectToCGRect(visible_frame));
+ rect.set_y(frame.size.height -
+ visible_frame.origin.y - visible_frame.size.height);
+ return rect;
+ }
+
+ virtual gfx::Rect GetPrimaryMonitorBounds() const {
+ // Primary monitor is defined as the monitor with the menubar,
+ // which is always at index 0.
+ NSScreen* primary = [[NSScreen screens] objectAtIndex:0];
+ return gfx::Rect(NSRectToCGRect([primary frame]));
+ }
+
+ virtual gfx::Rect GetMonitorWorkAreaMatching(
+ const gfx::Rect& match_rect) const {
+ NSScreen* match_screen = GetMatchingScreen(match_rect);
+ return ConvertCoordinateSystem([match_screen visibleFrame]);
+ }
+
+ virtual gfx::Point GetBoundsOffsetMatching(
+ const gfx::Rect& match_rect) const {
+ NSScreen* match_screen = GetMatchingScreen(match_rect);
+ gfx::Rect bounds = ConvertCoordinateSystem([match_screen frame]);
+ gfx::Rect work_area = ConvertCoordinateSystem([match_screen visibleFrame]);
+ return gfx::Point(work_area.x() - bounds.x(), work_area.y() - bounds.y());
+ }
+
+ virtual void UpdateWorkAreas();
+
+ private:
+ // Returns a pointer to the screen that most closely matches the
+ // given |match_rect|. This function currently returns the screen
+ // that contains the largest amount of |match_rect| by area.
+ NSScreen* GetMatchingScreen(const gfx::Rect& match_rect) const {
+ // Default to the monitor with the current keyboard focus, in case
+ // |match_rect| is not on any screen at all.
+ NSScreen* max_screen = [NSScreen mainScreen];
+ int max_area = 0;
+
+ for (NSScreen* screen in [NSScreen screens]) {
+ gfx::Rect monitor_area = ConvertCoordinateSystem([screen frame]);
+ gfx::Rect intersection = monitor_area.Intersect(match_rect);
+ int area = intersection.width() * intersection.height();
+ if (area > max_area) {
+ max_area = area;
+ max_screen = screen;
+ }
+ }
+
+ return max_screen;
+ }
+
+ // The lower left corner of screen 0 is always at (0, 0). The
+ // cross-platform code expects the origin to be in the upper left,
+ // so we have to translate |ns_rect| to the new coordinate
+ // system.
+ gfx::Rect ConvertCoordinateSystem(NSRect ns_rect) const;
+
+ DISALLOW_COPY_AND_ASSIGN(DefaultMonitorInfoProvider);
+};
+
+void DefaultMonitorInfoProvider::UpdateWorkAreas() {
+ work_areas_.clear();
+
+ for (NSScreen* screen in [NSScreen screens]) {
+ gfx::Rect rect = ConvertCoordinateSystem([screen visibleFrame]);
+ work_areas_.push_back(rect);
+ }
+}
+
+gfx::Rect DefaultMonitorInfoProvider::ConvertCoordinateSystem(
+ NSRect ns_rect) const {
+ // Primary monitor is defined as the monitor with the menubar,
+ // which is always at index 0.
+ NSScreen* primary_screen = [[NSScreen screens] objectAtIndex:0];
+ float primary_screen_height = [primary_screen frame].size.height;
+ gfx::Rect rect(NSRectToCGRect(ns_rect));
+ rect.set_y(primary_screen_height - rect.y() - rect.height());
+ return rect;
+}
+
+} // namespace
+
+// static
+WindowSizer::MonitorInfoProvider*
+WindowSizer::CreateDefaultMonitorInfoProvider() {
+ return new DefaultMonitorInfoProvider();
+}
+
+// static
+gfx::Point WindowSizer::GetDefaultPopupOrigin(const gfx::Size& size) {
+ NSRect work_area = [[NSScreen mainScreen] visibleFrame];
+ NSRect main_area = [[[NSScreen screens] objectAtIndex:0] frame];
+ NSPoint corner = NSMakePoint(NSMinX(work_area), NSMaxY(work_area));
+
+ if (Browser* b = BrowserList::GetLastActive()) {
+ NSWindow* window = b->window()->GetNativeHandle();
+ NSRect window_frame = [window frame];
+
+ // Limit to not overflow the work area right and bottom edges.
+ NSPoint limit = NSMakePoint(
+ std::min(NSMinX(window_frame) + kWindowTilePixels,
+ NSMaxX(work_area) - size.width()),
+ std::max(NSMaxY(window_frame) - kWindowTilePixels,
+ NSMinY(work_area) + size.height()));
+
+ // Adjust corner to now overflow the work area left and top edges, so
+ // that if a popup does not fit the title-bar is remains visible.
+ corner = NSMakePoint(std::max(corner.x, limit.x),
+ std::min(corner.y, limit.y));
+ }
+
+ return gfx::Point(corner.x, NSHeight(main_area) - corner.y);
+}
diff --git a/chrome/browser/ui/window_sizer_unittest.cc b/chrome/browser/ui/window_sizer_unittest.cc
new file mode 100644
index 0000000..f11065f
--- /dev/null
+++ b/chrome/browser/ui/window_sizer_unittest.cc
@@ -0,0 +1,1002 @@
+// 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.
+
+#include <vector>
+
+#include "chrome/browser/ui/window_sizer.h"
+#include "base/logging.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Some standard monitor sizes (no task bar).
+static const gfx::Rect tentwentyfour(0, 0, 1024, 768);
+static const gfx::Rect twelveeighty(0, 0, 1280, 1024);
+static const gfx::Rect sixteenhundred(0, 0, 1600, 1200);
+static const gfx::Rect sixteeneighty(0, 0, 1680, 1050);
+static const gfx::Rect nineteentwenty(0, 0, 1920, 1200);
+
+// Represents a 1024x768 monitor that is not the primary monitor, arranged to
+// the immediate left of the primary 1024x768 monitor.
+static const gfx::Rect left_nonprimary(-1024, 0, 1024, 768);
+
+// Represents a 1024x768 monitor that is not the primary monitor, arranged to
+// the immediate right of the primary 1024x768 monitor.
+static const gfx::Rect right_nonprimary(1024, 0, 1024, 768);
+
+// Represents a 1024x768 monitor that is not the primary monitor, arranged to
+// the immediate top of the primary 1024x768 monitor.
+static const gfx::Rect top_nonprimary(0, -768, 1024, 768);
+
+// Represents a 1024x768 monitor that is not the primary monitor, arranged to
+// the immediate bottom of the primary 1024x768 monitor.
+static const gfx::Rect bottom_nonprimary(0, 768, 1024, 768);
+
+// The work area for 1024x768 monitors with different taskbar orientations.
+static const gfx::Rect taskbar_bottom_work_area(0, 0, 1024, 734);
+static const gfx::Rect taskbar_top_work_area(0, 34, 1024, 734);
+static const gfx::Rect taskbar_left_work_area(107, 0, 917, 768);
+static const gfx::Rect taskbar_right_work_area(0, 0, 917, 768);
+
+static int kWindowTilePixels = WindowSizer::kWindowTilePixels;
+
+// Testing implementation of WindowSizer::MonitorInfoProvider that we can use
+// to fake various monitor layouts and sizes.
+class TestMonitorInfoProvider : public WindowSizer::MonitorInfoProvider {
+ public:
+ TestMonitorInfoProvider() {}
+ virtual ~TestMonitorInfoProvider() {}
+
+ void AddMonitor(const gfx::Rect& bounds, const gfx::Rect& work_area) {
+ DCHECK(bounds.Contains(work_area));
+ monitor_bounds_.push_back(bounds);
+ work_areas_.push_back(work_area);
+ }
+
+ // Overridden from WindowSizer::MonitorInfoProvider:
+ virtual gfx::Rect GetPrimaryMonitorWorkArea() const {
+ return work_areas_[0];
+ }
+
+ virtual gfx::Rect GetPrimaryMonitorBounds() const {
+ return monitor_bounds_[0];
+ }
+
+ virtual gfx::Rect GetMonitorWorkAreaMatching(
+ const gfx::Rect& match_rect) const {
+ return work_areas_[GetMonitorIndexMatchingBounds(match_rect)];
+ }
+
+ virtual gfx::Point GetBoundsOffsetMatching(
+ const gfx::Rect& match_rect) const {
+ int monitor_index = GetMonitorIndexMatchingBounds(match_rect);
+ gfx::Rect bounds = monitor_bounds_[monitor_index];
+ const gfx::Rect& work_area = work_areas_[monitor_index];
+ return gfx::Point(work_area.x() - bounds.x(), work_area.y() - bounds.y());
+ }
+
+ virtual void UpdateWorkAreas() { }
+
+ private:
+ size_t GetMonitorIndexMatchingBounds(const gfx::Rect& match_rect) const {
+ int max_area = 0;
+ size_t max_area_index = 0;
+ // Loop through all the monitors, finding the one that intersects the
+ // largest area of the supplied match rect.
+ for (size_t i = 0; i < work_areas_.size(); ++i) {
+ gfx::Rect overlap(match_rect.Intersect(work_areas_[i]));
+ int area = overlap.width() * overlap.height();
+ if (area > max_area) {
+ max_area = area;
+ max_area_index = i;
+ }
+ }
+ return max_area_index;
+ }
+
+ std::vector<gfx::Rect> monitor_bounds_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestMonitorInfoProvider);
+};
+
+// Testing implementation of WindowSizer::StateProvider that we use to fake
+// persistent storage and existing windows.
+class TestStateProvider : public WindowSizer::StateProvider {
+ public:
+ TestStateProvider()
+ : persistent_maximized_(false),
+ has_persistent_data_(false),
+ has_last_active_data_(false) {
+ }
+ virtual ~TestStateProvider() {}
+
+ void SetPersistentState(const gfx::Rect& bounds,
+ bool maximized,
+ const gfx::Rect& work_area,
+ bool has_persistent_data) {
+ persistent_bounds_ = bounds;
+ persistent_maximized_ = maximized;
+ persistent_work_area_ = work_area;
+ has_persistent_data_ = has_persistent_data;
+ }
+
+ void SetLastActiveState(const gfx::Rect& bounds, bool has_last_active_data) {
+ last_active_bounds_ = bounds;
+ has_last_active_data_ = has_last_active_data;
+ }
+
+ // Overridden from WindowSizer::StateProvider:
+ virtual bool GetPersistentState(gfx::Rect* bounds,
+ bool* maximized,
+ gfx::Rect* saved_work_area) const {
+ *bounds = persistent_bounds_;
+ *maximized = persistent_maximized_;
+ *saved_work_area = persistent_work_area_;
+ return has_persistent_data_;
+ }
+
+ virtual bool GetLastActiveWindowState(gfx::Rect* bounds) const {
+ *bounds = last_active_bounds_;
+ return has_last_active_data_;
+ }
+
+ private:
+ gfx::Rect persistent_bounds_;
+ bool persistent_maximized_;
+ gfx::Rect persistent_work_area_;
+ bool has_persistent_data_;
+
+ gfx::Rect last_active_bounds_;
+ bool has_last_active_data_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestStateProvider);
+};
+
+// A convenience function to read the window bounds from the window sizer
+// according to the specified configuration.
+enum Source { DEFAULT, LAST_ACTIVE, PERSISTED };
+static void GetWindowBounds(const gfx::Rect& monitor1_bounds,
+ const gfx::Rect& monitor1_work_area,
+ const gfx::Rect& monitor2_bounds,
+ const gfx::Rect& state,
+ bool maximized,
+ const gfx::Rect& work_area,
+ Source source,
+ gfx::Rect* out_bounds,
+ bool* out_maximized) {
+ TestMonitorInfoProvider* mip = new TestMonitorInfoProvider;
+ mip->AddMonitor(monitor1_bounds, monitor1_work_area);
+ if (!monitor2_bounds.IsEmpty())
+ mip->AddMonitor(monitor2_bounds, monitor2_bounds);
+ TestStateProvider* sp = new TestStateProvider;
+ if (source == PERSISTED)
+ sp->SetPersistentState(state, maximized, work_area, true);
+ else if (source == LAST_ACTIVE)
+ sp->SetLastActiveState(state, true);
+ WindowSizer sizer(sp, mip);
+ sizer.DetermineWindowBounds(gfx::Rect(), out_bounds, out_maximized);
+}
+
+// Test that the window is sized appropriately for the first run experience
+// where the default window bounds calculation is invoked.
+TEST(WindowSizerTest, DefaultSizeCase) {
+ { // 4:3 monitor case, 1024x768, no taskbar
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(), gfx::Rect(),
+ false, gfx::Rect(), DEFAULT, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(kWindowTilePixels, kWindowTilePixels,
+ 1024 - kWindowTilePixels * 2,
+ 768 - kWindowTilePixels * 2),
+ window_bounds);
+ }
+
+ { // 4:3 monitor case, 1024x768, taskbar on bottom
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, taskbar_bottom_work_area, gfx::Rect(),
+ gfx::Rect(), false, gfx::Rect(), DEFAULT, &window_bounds,
+ &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(kWindowTilePixels, kWindowTilePixels,
+ 1024 - kWindowTilePixels * 2,
+ (taskbar_bottom_work_area.height() -
+ kWindowTilePixels * 2)),
+ window_bounds);
+ }
+
+ { // 4:3 monitor case, 1024x768, taskbar on right
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, taskbar_right_work_area, gfx::Rect(),
+ gfx::Rect(), false, gfx::Rect(), DEFAULT, &window_bounds,
+ &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(kWindowTilePixels, kWindowTilePixels,
+ taskbar_right_work_area.width() - kWindowTilePixels*2,
+ 768 - kWindowTilePixels * 2),
+ window_bounds);
+ }
+
+ { // 4:3 monitor case, 1024x768, taskbar on left
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, taskbar_left_work_area, gfx::Rect(),
+ gfx::Rect(), false, gfx::Rect(), DEFAULT, &window_bounds,
+ &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(taskbar_left_work_area.x() + kWindowTilePixels,
+ kWindowTilePixels,
+ taskbar_left_work_area.width() - kWindowTilePixels * 2,
+ (taskbar_left_work_area.height() -
+ kWindowTilePixels * 2)),
+ window_bounds);
+ }
+
+ { // 4:3 monitor case, 1024x768, taskbar on top
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, taskbar_top_work_area, gfx::Rect(),
+ gfx::Rect(), false, gfx::Rect(), DEFAULT, &window_bounds,
+ &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(kWindowTilePixels,
+ taskbar_top_work_area.y() + kWindowTilePixels,
+ 1024 - kWindowTilePixels * 2,
+ taskbar_top_work_area.height() - kWindowTilePixels * 2),
+ window_bounds);
+ }
+
+ { // 4:3 monitor case, 1280x1024
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(twelveeighty, twelveeighty, gfx::Rect(), gfx::Rect(),
+ false, gfx::Rect(), DEFAULT, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(kWindowTilePixels, kWindowTilePixels,
+ 1050,
+ 1024 - kWindowTilePixels * 2),
+ window_bounds);
+ }
+
+ { // 4:3 monitor case, 1600x1200
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(sixteenhundred, sixteenhundred, gfx::Rect(), gfx::Rect(),
+ false, gfx::Rect(), DEFAULT, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(kWindowTilePixels, kWindowTilePixels,
+ 1050,
+ 1200 - kWindowTilePixels * 2),
+ window_bounds);
+ }
+
+ { // 16:10 monitor case, 1680x1050
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(sixteeneighty, sixteeneighty, gfx::Rect(), gfx::Rect(),
+ false, gfx::Rect(), DEFAULT, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(kWindowTilePixels, kWindowTilePixels,
+ 840 - static_cast<int>(kWindowTilePixels * 1.5),
+ 1050 - kWindowTilePixels * 2),
+ window_bounds);
+ }
+
+ { // 16:10 monitor case, 1920x1200
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(nineteentwenty, nineteentwenty, gfx::Rect(), gfx::Rect(),
+ false, gfx::Rect(), DEFAULT, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(kWindowTilePixels, kWindowTilePixels,
+ 960 - static_cast<int>(kWindowTilePixels * 1.5),
+ 1200 - kWindowTilePixels * 2),
+ window_bounds);
+ }
+}
+
+// Test that the next opened window is positioned appropriately given the
+// bounds of an existing window of the same type.
+TEST(WindowSizerTest, LastWindowBoundsCase) {
+ { // normal, in the middle of the screen somewhere.
+ gfx::Rect window_bounds;
+ bool maximized = false;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(kWindowTilePixels, kWindowTilePixels, 500, 400),
+ false, gfx::Rect(), LAST_ACTIVE,
+ &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(kWindowTilePixels * 2,
+ kWindowTilePixels * 2, 500, 400), window_bounds);
+ }
+
+ { // taskbar on top.
+ gfx::Rect window_bounds;
+ bool maximized = false;
+ GetWindowBounds(tentwentyfour, taskbar_top_work_area, gfx::Rect(),
+ gfx::Rect(kWindowTilePixels, kWindowTilePixels, 500, 400),
+ false, gfx::Rect(), LAST_ACTIVE,
+ &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(kWindowTilePixels * 2,
+ std::max(kWindowTilePixels * 2,
+ 34 /* toolbar height */),
+ 500, 400), window_bounds);
+ }
+
+ { // too small to satisify the minimum visibility condition.
+ gfx::Rect window_bounds;
+ bool maximized = false;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(kWindowTilePixels, kWindowTilePixels, 29, 29),
+ false, gfx::Rect(), LAST_ACTIVE,
+ &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(kWindowTilePixels * 2,
+ kWindowTilePixels * 2,
+ 30 /* not 29 */,
+ 30 /* not 29 */),
+ window_bounds);
+ }
+
+
+ { // normal, but maximized
+ gfx::Rect window_bounds;
+ bool maximized = false;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(kWindowTilePixels, kWindowTilePixels, 500, 400),
+ true, gfx::Rect(), LAST_ACTIVE,
+ &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(kWindowTilePixels * 2,
+ kWindowTilePixels * 2, 500, 400), window_bounds);
+ }
+}
+
+// Test that the window opened is sized appropriately given persisted sizes.
+TEST(WindowSizerTest, PersistedBoundsCase) {
+ { // normal, in the middle of the screen somewhere.
+ gfx::Rect initial_bounds(kWindowTilePixels, kWindowTilePixels, 500, 400);
+
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(), initial_bounds,
+ false, gfx::Rect(), PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(initial_bounds, window_bounds);
+ }
+
+ { // normal, maximized.
+ gfx::Rect initial_bounds(0, 0, 1024, 768);
+
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(), initial_bounds,
+ true, gfx::Rect(), PERSISTED, &window_bounds, &maximized);
+ EXPECT_TRUE(maximized);
+ EXPECT_EQ(initial_bounds, window_bounds);
+ }
+
+ { // normal, on non-primary monitor in negative coords.
+ gfx::Rect initial_bounds(-600, 10, 500, 400);
+
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, left_nonprimary,
+ initial_bounds, false, gfx::Rect(), PERSISTED,
+ &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(initial_bounds, window_bounds);
+ }
+
+ { // normal, on non-primary monitor in negative coords, maximized.
+ gfx::Rect initial_bounds(-1024, 0, 1024, 768);
+
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, left_nonprimary,
+ initial_bounds, true, gfx::Rect(), PERSISTED,
+ &window_bounds, &maximized);
+ EXPECT_TRUE(maximized);
+ EXPECT_EQ(initial_bounds, window_bounds);
+ }
+
+ { // Non-primary monitor resoultion has changed, but the monitor still
+ // completely contains the window.
+
+ gfx::Rect initial_bounds(1074, 50, 600, 500);
+
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(1024, 0, 800, 600),
+ initial_bounds, false, right_nonprimary,
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(initial_bounds, window_bounds);
+ }
+
+ { // Non-primary monitor resoultion has changed, and the window is partially
+ // off-screen.
+
+ gfx::Rect initial_bounds(1274, 50, 600, 500);
+
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(1024, 0, 800, 600),
+ initial_bounds, false, right_nonprimary,
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(1224, 50, 600, 500), window_bounds);
+ }
+
+ { // Non-primary monitor resoultion has changed, and the window is now too
+ // large for the monitor.
+
+ gfx::Rect initial_bounds(1274, 50, 900, 700);
+
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(1024, 0, 800, 600),
+ initial_bounds, false, right_nonprimary,
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(1024, 0, 800, 600), window_bounds);
+ }
+
+ { // width and height too small
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(kWindowTilePixels, kWindowTilePixels, 29, 29),
+ false, gfx::Rect(), PERSISTED,
+ &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(kWindowTilePixels, kWindowTilePixels,
+ 30 /* not 29 */, 30 /* not 29 */),
+ window_bounds);
+ }
+
+#if defined(OS_MACOSX)
+ { // Saved state is too tall to possibly be resized. Mac resizers
+ // are at the bottom of the window, and no piece of a window can
+ // be moved higher than the menubar. (Perhaps the user changed
+ // resolution to something smaller before relaunching Chrome?)
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(kWindowTilePixels, kWindowTilePixels, 30, 5000),
+ false, gfx::Rect(), PERSISTED,
+ &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(tentwentyfour.height(), window_bounds.height());
+ }
+#endif // defined(OS_MACOSX)
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// The following unittests have different results on Mac/non-Mac because we
+// reposition windows aggressively on Mac. The *WithAggressiveReposition tests
+// are run on Mac, and the *WithNonAggressiveRepositioning tests are run on
+// other platforms.
+
+#if defined(OS_MACOSX)
+TEST(WindowSizerTest, LastWindowOffscreenWithAggressiveRepositioning) {
+ { // taskbar on left. The new window overlaps slightly with the taskbar, so
+ // it is moved to be flush with the left edge of the work area.
+ gfx::Rect window_bounds;
+ bool maximized = false;
+ GetWindowBounds(tentwentyfour, taskbar_left_work_area, gfx::Rect(),
+ gfx::Rect(kWindowTilePixels, kWindowTilePixels, 500, 400),
+ false, gfx::Rect(), LAST_ACTIVE,
+ &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(taskbar_left_work_area.x(),
+ kWindowTilePixels * 2, 500, 400), window_bounds);
+ }
+
+ { // offset would put the new window offscreen at the bottom
+ gfx::Rect window_bounds;
+ bool maximized = false;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(10, 729, 500, 400), false, gfx::Rect(),
+ LAST_ACTIVE, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(10 + kWindowTilePixels,
+ 0 /* not 729 + kWindowTilePixels */,
+ 500, 400),
+ window_bounds);
+ }
+
+ { // offset would put the new window offscreen at the right
+ gfx::Rect window_bounds;
+ bool maximized = false;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(985, 10, 500, 400), false, gfx::Rect(),
+ LAST_ACTIVE, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(0 /* not 985 + kWindowTilePixels*/,
+ 10 + kWindowTilePixels,
+ 500, 400),
+ window_bounds);
+ }
+
+ { // offset would put the new window offscreen at the bottom right
+ gfx::Rect window_bounds;
+ bool maximized = false;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(985, 729, 500, 400), false, gfx::Rect(),
+ LAST_ACTIVE, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(0 /* not 985 + kWindowTilePixels*/,
+ 0 /* not 729 + kWindowTilePixels*/,
+ 500, 400),
+ window_bounds);
+ }
+}
+
+TEST(WindowSizerTest, PersistedWindowOffscreenWithAggressiveRepositioning) {
+ { // off the left
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(-471, 50, 500, 400), false, gfx::Rect(),
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(0 /* not -471 */, 50, 500, 400), window_bounds);
+ }
+
+ { // off the top
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(50, -370, 500, 400), false, gfx::Rect(),
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(50, 0, 500, 400), window_bounds);
+ }
+
+ { // off the right
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(995, 50, 500, 400), false, gfx::Rect(),
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(0 /* not 995 */, 50, 500, 400), window_bounds);
+ }
+
+ { // off the bottom
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(50, 739, 500, 400), false, gfx::Rect(), PERSISTED,
+ &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(50, 0 /* not 739 */, 500, 400), window_bounds);
+ }
+
+ { // off the topleft
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(-471, -371, 500, 400), false, gfx::Rect(),
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(0 /* not -471 */, 0 /* not -371 */, 500, 400),
+ window_bounds);
+ }
+
+ { // off the topright
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(995, -371, 500, 400), false, gfx::Rect(),
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(0 /* not 995 */, 0 /* not -371 */, 500, 400),
+ window_bounds);
+ }
+
+ { // off the bottomleft
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(-471, 739, 500, 400), false, gfx::Rect(),
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(0 /* not -471 */, 0 /* not 739 */, 500, 400),
+ window_bounds);
+ }
+
+ { // off the bottomright
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(995, 739, 500, 400), false, gfx::Rect(),
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(0 /* not 995 */, 0 /* not 739 */, 500, 400),
+ window_bounds);
+ }
+
+ { // entirely off left
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(-700, 50, 500, 400), false, gfx::Rect(),
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(0 /* not -700 */, 50, 500, 400), window_bounds);
+ }
+
+ { // entirely off left (monitor was detached since last run)
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(-700, 50, 500, 400), false, left_nonprimary,
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(0, 50, 500, 400), window_bounds);
+ }
+
+ { // entirely off top
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(50, -500, 500, 400), false, gfx::Rect(),
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(50, 0, 500, 400), window_bounds);
+ }
+
+ { // entirely off top (monitor was detached since last run)
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(50, -500, 500, 400), false, top_nonprimary,
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(50, 0, 500, 400), window_bounds);
+ }
+
+ { // entirely off right
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(1200, 50, 500, 400), false, gfx::Rect(),
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(0 /* not 1200 */, 50, 500, 400), window_bounds);
+ }
+
+ { // entirely off right (monitor was detached since last run)
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(1200, 50, 500, 400), false, right_nonprimary,
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(524 /* not 1200 */, 50, 500, 400), window_bounds);
+ }
+
+ { // entirely off bottom
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(50, 800, 500, 400), false, gfx::Rect(), PERSISTED,
+ &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(50, 0 /* not 800 */, 500, 400), window_bounds);
+ }
+
+ { // entirely off bottom (monitor was detached since last run)
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(50, 800, 500, 400), false, bottom_nonprimary,
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(50, 368 /* not 800 */, 500, 400), window_bounds);
+ }
+
+ { // wider than the screen. off both the left and right
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(-100, 50, 2000, 400), false, gfx::Rect(),
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(0 /* not -100 */, 50, 2000, 400), window_bounds);
+ }
+}
+#else
+TEST(WindowSizerTest, LastWindowOffscreenWithNonAggressiveRepositioning) {
+ { // taskbar on left.
+ gfx::Rect window_bounds;
+ bool maximized = false;
+ GetWindowBounds(tentwentyfour, taskbar_left_work_area, gfx::Rect(),
+ gfx::Rect(kWindowTilePixels, kWindowTilePixels, 500, 400),
+ false, gfx::Rect(), LAST_ACTIVE,
+ &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(kWindowTilePixels * 2,
+ kWindowTilePixels * 2, 500, 400), window_bounds);
+ }
+
+ // Linux does not tile windows, so tile adjustment tests don't make sense.
+#if !defined(OS_LINUX)
+ { // offset would put the new window offscreen at the bottom but the minimum
+ // visibility condition is barely satisfied without relocation.
+ gfx::Rect window_bounds;
+ bool maximized = false;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(10, 728, 500, 400), false, gfx::Rect(),
+ LAST_ACTIVE, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(10 + kWindowTilePixels, 738,
+ 500, 400), window_bounds);
+ }
+
+ { // offset would put the new window offscreen at the bottom and the minimum
+ // visibility condition is satisified by relocation.
+ gfx::Rect window_bounds;
+ bool maximized = false;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(10, 729, 500, 400), false, gfx::Rect(),
+ LAST_ACTIVE, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(10 + kWindowTilePixels, 738 /* not 739 */, 500, 400),
+ window_bounds);
+ }
+
+ { // offset would put the new window offscreen at the right but the minimum
+ // visibility condition is barely satisfied without relocation.
+ gfx::Rect window_bounds;
+ bool maximized = false;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(984, 10, 500, 400), false, gfx::Rect(),
+ LAST_ACTIVE, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(994, 10 + kWindowTilePixels, 500, 400), window_bounds);
+ }
+
+ { // offset would put the new window offscreen at the right and the minimum
+ // visibility condition is satisified by relocation.
+ gfx::Rect window_bounds;
+ bool maximized = false;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(985, 10, 500, 400), false, gfx::Rect(),
+ LAST_ACTIVE, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(994 /* not 995 */, 10 + kWindowTilePixels,
+ 500, 400), window_bounds);
+ }
+
+ { // offset would put the new window offscreen at the bottom right and the
+ // minimum visibility condition is satisified by relocation.
+ gfx::Rect window_bounds;
+ bool maximized = false;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(985, 729, 500, 400), false, gfx::Rect(),
+ LAST_ACTIVE, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(994 /* not 995 */, 738 /* not 739 */, 500, 400),
+ window_bounds);
+ }
+#endif // !defined(OS_LINUX)
+}
+
+TEST(WindowSizerTest, PersistedWindowOffscreenWithNonAggressiveRepositioning) {
+ { // off the left but the minimum visibility condition is barely satisfied
+ // without relocaiton.
+ gfx::Rect initial_bounds(-470, 50, 500, 400);
+
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ initial_bounds, false, gfx::Rect(), PERSISTED,
+ &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(initial_bounds, window_bounds);
+ }
+
+ { // off the left and the minimum visibility condition is satisfied by
+ // relocation.
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(-471, 50, 500, 400), false, gfx::Rect(),
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(-470 /* not -471 */, 50, 500, 400), window_bounds);
+ }
+
+ { // off the top
+ gfx::Rect initial_bounds(50, -370, 500, 400);
+
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(50, -370, 500, 400), false, gfx::Rect(),
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(50, 0, 500, 400), window_bounds);
+ }
+
+ { // off the right but the minimum visibility condition is barely satisified
+ // without relocation.
+ gfx::Rect initial_bounds(994, 50, 500, 400);
+
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ initial_bounds, false, gfx::Rect(), PERSISTED,
+ &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(initial_bounds, window_bounds);
+ }
+
+ { // off the right and the minimum visibility condition is satisified by
+ // relocation.
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(995, 50, 500, 400), false, gfx::Rect(),
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(994 /* not 995 */, 50, 500, 400), window_bounds);
+ }
+
+ { // off the bottom but the minimum visibility condition is barely satisified
+ // without relocation.
+ gfx::Rect initial_bounds(50, 738, 500, 400);
+
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ initial_bounds, false, gfx::Rect(), PERSISTED,
+ &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(initial_bounds, window_bounds);
+ }
+
+ { // off the bottom and the minimum visibility condition is satisified by
+ // relocation.
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(50, 739, 500, 400), false, gfx::Rect(), PERSISTED,
+ &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(50, 738 /* not 739 */, 500, 400), window_bounds);
+ }
+
+ { // off the topleft
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(-471, -371, 500, 400), false, gfx::Rect(),
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(-470 /* not -471 */, 0, 500, 400),
+ window_bounds);
+ }
+
+ { // off the topright and the minimum visibility condition is satisified by
+ // relocation.
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(995, -371, 500, 400), false, gfx::Rect(),
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(994 /* not 995 */, 0, 500, 400),
+ window_bounds);
+ }
+
+ { // off the bottomleft and the minimum visibility condition is satisified by
+ // relocation.
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(-471, 739, 500, 400), false, gfx::Rect(),
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(-470 /* not -471 */, 738 /* not 739 */, 500, 400),
+ window_bounds);
+ }
+
+ { // off the bottomright and the minimum visibility condition is satisified by
+ // relocation.
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(995, 739, 500, 400), false, gfx::Rect(),
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(994 /* not 995 */, 738 /* not 739 */, 500, 400),
+ window_bounds);
+ }
+
+ { // entirely off left
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(-700, 50, 500, 400), false, gfx::Rect(),
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(-470 /* not -700 */, 50, 500, 400), window_bounds);
+ }
+
+ { // entirely off left (monitor was detached since last run)
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(-700, 50, 500, 400), false, left_nonprimary,
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(0, 50, 500, 400), window_bounds);
+ }
+
+ { // entirely off top
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(50, -500, 500, 400), false, gfx::Rect(),
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(50, 0, 500, 400), window_bounds);
+ }
+
+ { // entirely off top (monitor was detached since last run)
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(50, -500, 500, 400), false, top_nonprimary,
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(50, 0, 500, 400), window_bounds);
+ }
+
+ { // entirely off right
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(1200, 50, 500, 400), false, gfx::Rect(),
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(994 /* not 1200 */, 50, 500, 400), window_bounds);
+ }
+
+ { // entirely off right (monitor was detached since last run)
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(1200, 50, 500, 400), false, right_nonprimary,
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(524, 50, 500, 400), window_bounds);
+ }
+
+ { // entirely off bottom
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(50, 800, 500, 400), false, gfx::Rect(), PERSISTED,
+ &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(50, 738 /* not 800 */, 500, 400), window_bounds);
+ }
+
+ { // entirely off bottom (monitor was detached since last run)
+ gfx::Rect window_bounds;
+ bool maximized;
+ GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
+ gfx::Rect(50, 800, 500, 400), false, bottom_nonprimary,
+ PERSISTED, &window_bounds, &maximized);
+ EXPECT_FALSE(maximized);
+ EXPECT_EQ(gfx::Rect(50, 368, 500, 400), window_bounds);
+ }
+}
+#endif //defined(OS_MACOSX)
diff --git a/chrome/browser/ui/window_sizer_win.cc b/chrome/browser/ui/window_sizer_win.cc
new file mode 100644
index 0000000..a2952a4
--- /dev/null
+++ b/chrome/browser/ui/window_sizer_win.cc
@@ -0,0 +1,108 @@
+// Copyright (c) 2009 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 "chrome/browser/ui/window_sizer.h"
+
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_window.h"
+
+// How much horizontal and vertical offset there is between newly
+// opened windows.
+const int WindowSizer::kWindowTilePixels = 10;
+
+// An implementation of WindowSizer::MonitorInfoProvider that gets the actual
+// monitor information from Windows.
+class DefaultMonitorInfoProvider : public WindowSizer::MonitorInfoProvider {
+ public:
+ DefaultMonitorInfoProvider() { }
+
+ // Overridden from WindowSizer::MonitorInfoProvider:
+ virtual gfx::Rect GetPrimaryMonitorWorkArea() const {
+ return gfx::Rect(GetMonitorInfoForMonitor(MonitorFromWindow(NULL,
+ MONITOR_DEFAULTTOPRIMARY)).rcWork);
+ }
+
+ virtual gfx::Rect GetPrimaryMonitorBounds() const {
+ return gfx::Rect(GetMonitorInfoForMonitor(MonitorFromWindow(NULL,
+ MONITOR_DEFAULTTOPRIMARY)).rcMonitor);
+ }
+
+ virtual gfx::Rect GetMonitorWorkAreaMatching(
+ const gfx::Rect& match_rect) const {
+ RECT other_bounds_rect = match_rect.ToRECT();
+ MONITORINFO monitor_info = GetMonitorInfoForMonitor(MonitorFromRect(
+ &other_bounds_rect, MONITOR_DEFAULTTONEAREST));
+ return gfx::Rect(monitor_info.rcWork);
+ }
+
+ virtual gfx::Point GetBoundsOffsetMatching(
+ const gfx::Rect& match_rect) const {
+ RECT other_bounds_rect = match_rect.ToRECT();
+ MONITORINFO monitor_info = GetMonitorInfoForMonitor(MonitorFromRect(
+ &other_bounds_rect, MONITOR_DEFAULTTONEAREST));
+ return gfx::Point(monitor_info.rcWork.left - monitor_info.rcMonitor.left,
+ monitor_info.rcWork.top - monitor_info.rcMonitor.top);
+ }
+
+ void UpdateWorkAreas() {
+ work_areas_.clear();
+ EnumDisplayMonitors(NULL, NULL,
+ &DefaultMonitorInfoProvider::MonitorEnumProc,
+ reinterpret_cast<LPARAM>(&work_areas_));
+ }
+
+ private:
+ // A callback for EnumDisplayMonitors that records the work area of the
+ // current monitor in the enumeration.
+ static BOOL CALLBACK MonitorEnumProc(HMONITOR monitor,
+ HDC monitor_dc,
+ LPRECT monitor_rect,
+ LPARAM data) {
+ reinterpret_cast<std::vector<gfx::Rect>*>(data)->push_back(
+ gfx::Rect(GetMonitorInfoForMonitor(monitor).rcWork));
+ return TRUE;
+ }
+
+ static MONITORINFO GetMonitorInfoForMonitor(HMONITOR monitor) {
+ MONITORINFO monitor_info = { 0 };
+ monitor_info.cbSize = sizeof(monitor_info);
+ GetMonitorInfo(monitor, &monitor_info);
+ return monitor_info;
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(DefaultMonitorInfoProvider);
+};
+
+// static
+WindowSizer::MonitorInfoProvider*
+WindowSizer::CreateDefaultMonitorInfoProvider() {
+ return new DefaultMonitorInfoProvider();
+}
+
+// static
+gfx::Point WindowSizer::GetDefaultPopupOrigin(const gfx::Size& size) {
+ RECT area;
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &area, 0);
+ gfx::Point corner(area.left, area.top);
+
+ if (Browser* b = BrowserList::GetLastActive()) {
+ RECT browser;
+ HWND window = reinterpret_cast<HWND>(b->window()->GetNativeHandle());
+ if (GetWindowRect(window, &browser)) {
+ // Limit to not overflow the work area right and bottom edges.
+ gfx::Point limit(
+ std::min(browser.left + kWindowTilePixels, area.right-size.width()),
+ std::min(browser.top + kWindowTilePixels, area.bottom-size.height())
+ );
+ // Adjust corner to now overflow the work area left and top edges, so
+ // that if a popup does not fit the title-bar is remains visible.
+ corner = gfx::Point(
+ std::max(corner.x(), limit.x()),
+ std::max(corner.y(), limit.y())
+ );
+ }
+ }
+ return corner;
+}
diff --git a/chrome/browser/unload_uitest.cc b/chrome/browser/unload_uitest.cc
index 6abc736..bf45ecc 100644
--- a/chrome/browser/unload_uitest.cc
+++ b/chrome/browser/unload_uitest.cc
@@ -6,7 +6,7 @@
#include "base/file_util.h"
#include "base/platform_thread.h"
#include "chrome/browser/net/url_request_mock_http_job.h"
-#include "chrome/browser/view_ids.h"
+#include "chrome/browser/ui/view_ids.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
diff --git a/chrome/browser/upgrade_detector.cc b/chrome/browser/upgrade_detector.cc
index 6a65c7a..99d8a2b 100644
--- a/chrome/browser/upgrade_detector.cc
+++ b/chrome/browser/upgrade_detector.cc
@@ -7,6 +7,7 @@
#include <string>
#include "base/command_line.h"
+#include "base/singleton.h"
#include "base/scoped_ptr.h"
#include "base/time.h"
#include "base/task.h"
@@ -26,10 +27,10 @@
#if defined(OS_WIN)
#include "chrome/installer/util/install_util.h"
#elif defined(OS_MACOSX)
-#include "chrome/browser/cocoa/keystone_glue.h"
+#include "chrome/browser/ui/cocoa/keystone_glue.h"
#elif defined(OS_POSIX)
#include "base/process_util.h"
-#include "chrome/installer/util/version.h"
+#include "base/version.h"
#endif
namespace {
@@ -79,22 +80,24 @@ class DetectUpgradeTask : public Task {
virtual void Run() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- using installer::Version;
scoped_ptr<Version> installed_version;
#if defined(OS_WIN)
// Get the version of the currently *installed* instance of Chrome,
// which might be newer than the *running* instance if we have been
// upgraded in the background.
- installed_version.reset(InstallUtil::GetChromeVersion(false));
+ // TODO(tommi): Check if using the default distribution is always the right
+ // thing to do.
+ BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+ installed_version.reset(InstallUtil::GetChromeVersion(dist, false));
if (!installed_version.get()) {
// User level Chrome is not installed, check system level.
- installed_version.reset(InstallUtil::GetChromeVersion(true));
+ installed_version.reset(InstallUtil::GetChromeVersion(dist, true));
}
#elif defined(OS_MACOSX)
installed_version.reset(
- Version::GetVersionFromString(
- keystone_glue::CurrentlyInstalledVersion()));
+ Version::GetVersionFromString(UTF16ToASCII(
+ keystone_glue::CurrentlyInstalledVersion())));
#elif defined(OS_POSIX)
// POSIX but not Mac OS X: Linux, etc.
CommandLine command_line(*CommandLine::ForCurrentProcess());
@@ -105,7 +108,7 @@ class DetectUpgradeTask : public Task {
return;
}
- installed_version.reset(Version::GetVersionFromString(ASCIIToUTF16(reply)));
+ installed_version.reset(Version::GetVersionFromString(reply));
#endif
// Get the version of the currently *running* instance of Chrome.
@@ -115,7 +118,7 @@ class DetectUpgradeTask : public Task {
return;
}
scoped_ptr<Version> running_version(
- Version::GetVersionFromString(ASCIIToUTF16(version_info.Version())));
+ Version::GetVersionFromString(version_info.Version()));
if (running_version.get() == NULL) {
NOTREACHED() << "Failed to parse version info";
return;
@@ -125,7 +128,7 @@ class DetectUpgradeTask : public Task {
// switching from dev to beta channel, for example). The user needs a
// restart in this case as well. See http://crbug.com/46547
if (!installed_version.get() ||
- installed_version->IsHigherThan(running_version.get())) {
+ (installed_version->CompareTo(*running_version) > 0)) {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
upgrade_detected_task_);
upgrade_detected_task_ = NULL;
@@ -164,6 +167,11 @@ UpgradeDetector::UpgradeDetector()
UpgradeDetector::~UpgradeDetector() {
}
+// static
+UpgradeDetector* UpgradeDetector::GetInstance() {
+ return Singleton<UpgradeDetector>::get();
+}
+
void UpgradeDetector::CheckForUpgrade() {
method_factory_.RevokeAll();
Task* callback_task =
diff --git a/chrome/browser/upgrade_detector.h b/chrome/browser/upgrade_detector.h
index 7c15128..e6aa6a6 100644
--- a/chrome/browser/upgrade_detector.h
+++ b/chrome/browser/upgrade_detector.h
@@ -6,9 +6,9 @@
#define CHROME_BROWSER_UPGRADE_DETECTOR_H_
#pragma once
-#include "base/singleton.h"
#include "base/timer.h"
+template <typename T> struct DefaultSingletonTraits;
class PrefService;
///////////////////////////////////////////////////////////////////////////////
@@ -23,6 +23,9 @@ class PrefService;
//
class UpgradeDetector {
public:
+ // Returns the singleton instance.
+ static UpgradeDetector* GetInstance();
+
~UpgradeDetector();
static void RegisterPrefs(PrefService* prefs);
@@ -30,9 +33,10 @@ class UpgradeDetector {
bool notify_upgrade() { return notify_upgrade_; }
private:
- UpgradeDetector();
friend struct DefaultSingletonTraits<UpgradeDetector>;
+ UpgradeDetector();
+
// Launches a task on the file thread to check if we have the latest version.
void CheckForUpgrade();
diff --git a/chrome/browser/user_style_sheet_watcher.h b/chrome/browser/user_style_sheet_watcher.h
index 5c28314..bbc9ae0 100644
--- a/chrome/browser/user_style_sheet_watcher.h
+++ b/chrome/browser/user_style_sheet_watcher.h
@@ -10,7 +10,7 @@
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/file_path_watcher.h"
+#include "chrome/browser/file_path_watcher/file_path_watcher.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "googleurl/src/gurl.h"
diff --git a/chrome/browser/utility_process_host.cc b/chrome/browser/utility_process_host.cc
index 22495f8..4d208fd 100644
--- a/chrome/browser/utility_process_host.cc
+++ b/chrome/browser/utility_process_host.cc
@@ -153,20 +153,26 @@ bool UtilityProcessHost::StartProcess(const FilePath& exposed_dir) {
return true;
}
-void UtilityProcessHost::OnMessageReceived(const IPC::Message& message) {
+bool UtilityProcessHost::OnMessageReceived(const IPC::Message& message) {
BrowserThread::PostTask(
client_thread_id_, FROM_HERE,
NewRunnableMethod(client_.get(), &Client::OnMessageReceived, message));
+ return true;
}
-void UtilityProcessHost::OnProcessCrashed() {
+void UtilityProcessHost::OnProcessCrashed(int exit_code) {
BrowserThread::PostTask(
client_thread_id_, FROM_HERE,
- NewRunnableMethod(client_.get(), &Client::OnProcessCrashed));
+ NewRunnableMethod(client_.get(), &Client::OnProcessCrashed, exit_code));
+}
+
+bool UtilityProcessHost::CanShutdown() {
+ return true;
}
-void UtilityProcessHost::Client::OnMessageReceived(
+bool UtilityProcessHost::Client::OnMessageReceived(
const IPC::Message& message) {
+ bool handled = true;
IPC_BEGIN_MESSAGE_MAP(UtilityProcessHost, message)
IPC_MESSAGE_HANDLER(UtilityHostMsg_UnpackExtension_Succeeded,
Client::OnUnpackExtensionSucceeded)
@@ -188,5 +194,7 @@ void UtilityProcessHost::Client::OnMessageReceived(
Client::OnIDBKeysFromValuesAndKeyPathSucceeded)
IPC_MESSAGE_HANDLER(UtilityHostMsg_IDBKeysFromValuesAndKeyPath_Failed,
Client::OnIDBKeysFromValuesAndKeyPathFailed)
+ IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP_EX()
+ return handled;
}
diff --git a/chrome/browser/utility_process_host.h b/chrome/browser/utility_process_host.h
index 48d5e38..c1f4055 100644
--- a/chrome/browser/utility_process_host.h
+++ b/chrome/browser/utility_process_host.h
@@ -15,7 +15,6 @@
#include "chrome/browser/browser_child_process_host.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/common/extensions/update_manifest.h"
-#include "ipc/ipc_channel.h"
class DictionaryValue;
class IndexedDBKey;
@@ -39,7 +38,7 @@ class UtilityProcessHost : public BrowserChildProcessHost {
Client() {}
// Called when the process has crashed.
- virtual void OnProcessCrashed() {}
+ virtual void OnProcessCrashed(int exit_code) {}
// Called when the extension has unpacked successfully. |manifest| is the
// parsed manifest.json file. |catalogs| contains list of all parsed
@@ -98,7 +97,7 @@ class UtilityProcessHost : public BrowserChildProcessHost {
private:
friend class UtilityProcessHost;
- void OnMessageReceived(const IPC::Message& message);
+ bool OnMessageReceived(const IPC::Message& message);
DISALLOW_COPY_AND_ASSIGN(Client);
};
@@ -150,16 +149,11 @@ class UtilityProcessHost : public BrowserChildProcessHost {
bool StartProcess(const FilePath& exposed_dir);
// IPC messages:
- void OnMessageReceived(const IPC::Message& message);
+ virtual bool OnMessageReceived(const IPC::Message& message);
// BrowserChildProcessHost:
- virtual void OnProcessCrashed();
- virtual bool CanShutdown() { return true; }
- virtual URLRequestContext* GetRequestContext(
- uint32 request_id,
- const ViewHostMsg_Resource_Request& request_data) {
- return NULL;
- }
+ virtual void OnProcessCrashed(int exit_code);
+ virtual bool CanShutdown();
// A pointer to our client interface, who will be informed of progress.
scoped_refptr<Client> client_;
diff --git a/chrome/browser/visitedlink/visitedlink_event_listener.cc b/chrome/browser/visitedlink/visitedlink_event_listener.cc
new file mode 100644
index 0000000..bca0d25
--- /dev/null
+++ b/chrome/browser/visitedlink/visitedlink_event_listener.cc
@@ -0,0 +1,65 @@
+// 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.
+
+#include "chrome/browser/visitedlink/visitedlink_event_listener.h"
+
+#include "base/shared_memory.h"
+#include "chrome/browser/renderer_host/render_process_host.h"
+
+using base::Time;
+using base::TimeDelta;
+
+// The amount of time we wait to accumulate visited link additions.
+static const int kCommitIntervalMs = 100;
+
+VisitedLinkEventListener::VisitedLinkEventListener() {
+}
+
+VisitedLinkEventListener::~VisitedLinkEventListener() {
+}
+
+void VisitedLinkEventListener::NewTable(base::SharedMemory* table_memory) {
+ if (!table_memory)
+ return;
+
+ // Send to all RenderProcessHosts.
+ for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
+ !i.IsAtEnd(); i.Advance()) {
+ if (!i.GetCurrentValue()->HasConnection())
+ continue;
+
+ i.GetCurrentValue()->SendVisitedLinkTable(table_memory);
+ }
+}
+
+void VisitedLinkEventListener::Add(VisitedLinkMaster::Fingerprint fingerprint) {
+ pending_visited_links_.push_back(fingerprint);
+
+ if (!coalesce_timer_.IsRunning()) {
+ coalesce_timer_.Start(
+ TimeDelta::FromMilliseconds(kCommitIntervalMs), this,
+ &VisitedLinkEventListener::CommitVisitedLinks);
+ }
+}
+
+void VisitedLinkEventListener::Reset() {
+ pending_visited_links_.clear();
+ coalesce_timer_.Stop();
+
+ // Send to all RenderProcessHosts.
+ for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
+ !i.IsAtEnd(); i.Advance()) {
+ i.GetCurrentValue()->ResetVisitedLinks();
+ }
+}
+
+void VisitedLinkEventListener::CommitVisitedLinks() {
+ // Send to all RenderProcessHosts.
+ for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
+ !i.IsAtEnd(); i.Advance()) {
+ i.GetCurrentValue()->AddVisitedLinks(pending_visited_links_);
+ }
+
+ pending_visited_links_.clear();
+}
diff --git a/chrome/browser/visitedlink/visitedlink_event_listener.h b/chrome/browser/visitedlink/visitedlink_event_listener.h
new file mode 100644
index 0000000..020b0a9
--- /dev/null
+++ b/chrome/browser/visitedlink/visitedlink_event_listener.h
@@ -0,0 +1,38 @@
+// 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.
+
+// VisitedLinkEventListener broadcasts link coloring database updates to all
+// processes. It also coalesces the updates to avoid excessive broadcasting of
+// messages to the renderers.
+
+#ifndef CHROME_BROWSER_VISITEDLINK_VISITEDLINK_EVENT_LISTENER_H_
+#define CHROME_BROWSER_VISITEDLINK_VISITEDLINK_EVENT_LISTENER_H_
+#pragma once
+
+#include "base/timer.h"
+#include "chrome/browser/visitedlink/visitedlink_master.h"
+
+namespace base {
+class SharedMemory;
+}
+
+class VisitedLinkEventListener : public VisitedLinkMaster::Listener {
+ public:
+ VisitedLinkEventListener();
+ virtual ~VisitedLinkEventListener();
+
+ virtual void NewTable(base::SharedMemory* table_memory);
+ virtual void Add(VisitedLinkMaster::Fingerprint fingerprint);
+ virtual void Reset();
+
+ private:
+ void CommitVisitedLinks();
+
+ base::OneShotTimer<VisitedLinkEventListener> coalesce_timer_;
+ VisitedLinkCommon::Fingerprints pending_visited_links_;
+
+ DISALLOW_COPY_AND_ASSIGN(VisitedLinkEventListener);
+};
+
+#endif // CHROME_BROWSER_VISITEDLINK_VISITEDLINK_EVENT_LISTENER_H_
diff --git a/chrome/browser/visitedlink/visitedlink_master.cc b/chrome/browser/visitedlink/visitedlink_master.cc
new file mode 100644
index 0000000..d93ea46
--- /dev/null
+++ b/chrome/browser/visitedlink/visitedlink_master.cc
@@ -0,0 +1,1001 @@
+// 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.
+
+#include "chrome/browser/visitedlink/visitedlink_master.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <io.h>
+#include <shlobj.h>
+#endif // defined(OS_WIN)
+#include <stdio.h>
+
+#include <algorithm>
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/path_service.h"
+#include "base/process_util.h"
+#include "base/rand_util.h"
+#include "base/stack_container.h"
+#include "base/string_util.h"
+#include "base/thread_restrictions.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/history/history.h"
+#include "chrome/browser/profiles/profile.h"
+
+using file_util::ScopedFILE;
+using file_util::OpenFile;
+using file_util::TruncateFile;
+
+const int32 VisitedLinkMaster::kFileHeaderSignatureOffset = 0;
+const int32 VisitedLinkMaster::kFileHeaderVersionOffset = 4;
+const int32 VisitedLinkMaster::kFileHeaderLengthOffset = 8;
+const int32 VisitedLinkMaster::kFileHeaderUsedOffset = 12;
+const int32 VisitedLinkMaster::kFileHeaderSaltOffset = 16;
+
+const int32 VisitedLinkMaster::kFileCurrentVersion = 2;
+
+// the signature at the beginning of the URL table = "VLnk" (visited links)
+const int32 VisitedLinkMaster::kFileSignature = 0x6b6e4c56;
+const size_t VisitedLinkMaster::kFileHeaderSize =
+ kFileHeaderSaltOffset + LINK_SALT_LENGTH;
+
+// This value should also be the same as the smallest size in the lookup
+// table in NewTableSizeForCount (prime number).
+const unsigned VisitedLinkMaster::kDefaultTableSize = 16381;
+
+const size_t VisitedLinkMaster::kBigDeleteThreshold = 64;
+
+namespace {
+
+// Fills the given salt structure with some quasi-random values
+// It is not necessary to generate a cryptographically strong random string,
+// only that it be reasonably different for different users.
+void GenerateSalt(uint8 salt[LINK_SALT_LENGTH]) {
+ DCHECK_EQ(LINK_SALT_LENGTH, 8) << "This code assumes the length of the salt";
+ uint64 randval = base::RandUint64();
+ memcpy(salt, &randval, 8);
+}
+
+// AsyncWriter ----------------------------------------------------------------
+
+// This task executes on a background thread and executes a write. This
+// prevents us from blocking the UI thread doing I/O.
+class AsyncWriter : public Task {
+ public:
+ AsyncWriter(FILE* file, int32 offset, const void* data, size_t data_len)
+ : file_(file),
+ offset_(offset) {
+ data_->resize(data_len);
+ memcpy(&*data_->begin(), data, data_len);
+ }
+
+ virtual void Run() {
+ WriteToFile(file_, offset_,
+ &*data_->begin(), static_cast<int32>(data_->size()));
+ }
+
+ // Exposed as a static so it can be called directly from the Master to
+ // reduce the number of platform-specific I/O sites we have. Returns true if
+ // the write was complete.
+ static bool WriteToFile(FILE* file,
+ off_t offset,
+ const void* data,
+ size_t data_len) {
+ if (fseek(file, offset, SEEK_SET) != 0)
+ return false; // Don't write to an invalid part of the file.
+
+ size_t num_written = fwrite(data, 1, data_len, file);
+
+ // The write may not make it to the kernel (stdlib may buffer the write)
+ // until the next fseek/fclose call. If we crash, it's easy for our used
+ // item count to be out of sync with the number of hashes we write.
+ // Protect against this by calling fflush.
+ int ret = fflush(file);
+ DCHECK_EQ(0, ret);
+ return num_written == data_len;
+ }
+
+ private:
+ // The data to write and where to write it.
+ FILE* file_;
+ int32 offset_; // Offset from the beginning of the file.
+
+ // Most writes are just a single fingerprint, so we reserve that much in this
+ // object to avoid mallocs in that case.
+ StackVector<char, sizeof(VisitedLinkCommon::Fingerprint)> data_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncWriter);
+};
+
+// Used to asynchronously set the end of the file. This must be done on the
+// same thread as the writing to keep things synchronized.
+class AsyncSetEndOfFile : public Task {
+ public:
+ explicit AsyncSetEndOfFile(FILE* file) : file_(file) {}
+
+ virtual void Run() {
+ TruncateFile(file_);
+ }
+
+ private:
+ FILE* file_;
+ DISALLOW_COPY_AND_ASSIGN(AsyncSetEndOfFile);
+};
+
+// Used to asynchronously close a file. This must be done on the same thread as
+// the writing to keep things synchronized.
+class AsyncCloseHandle : public Task {
+ public:
+ explicit AsyncCloseHandle(FILE* file) : file_(file) {}
+
+ virtual void Run() {
+ fclose(file_);
+ }
+
+ private:
+ FILE* file_;
+ DISALLOW_COPY_AND_ASSIGN(AsyncCloseHandle);
+};
+
+} // namespace
+
+// TableBuilder ---------------------------------------------------------------
+
+// How rebuilding from history works
+// ---------------------------------
+//
+// We mark that we're rebuilding from history by setting the table_builder_
+// member in VisitedLinkMaster to the TableBuilder we create. This builder
+// will be called on the history thread by the history system for every URL
+// in the database.
+//
+// The builder will store the fingerprints for those URLs, and then marshalls
+// back to the main thread where the VisitedLinkMaster will be notified. The
+// master then replaces its table with a new table containing the computed
+// fingerprints.
+//
+// The builder must remain active while the history system is using it.
+// Sometimes, the master will be deleted before the rebuild is complete, in
+// which case it notifies the builder via DisownMaster(). The builder will
+// delete itself once rebuilding is complete, and not execute any callback.
+class VisitedLinkMaster::TableBuilder
+ : public HistoryService::URLEnumerator,
+ public base::RefCountedThreadSafe<TableBuilder> {
+ public:
+ TableBuilder(VisitedLinkMaster* master,
+ const uint8 salt[LINK_SALT_LENGTH]);
+
+ // Called on the main thread when the master is being destroyed. This will
+ // prevent a crash when the query completes and the master is no longer
+ // around. We can not actually do anything but mark this fact, since the
+ // table will be being rebuilt simultaneously on the other thread.
+ void DisownMaster();
+
+ // HistoryService::URLEnumerator
+ virtual void OnURL(const GURL& url);
+ virtual void OnComplete(bool succeed);
+
+ private:
+ friend class base::RefCountedThreadSafe<TableBuilder>;
+
+ ~TableBuilder() {}
+
+ // OnComplete mashals to this function on the main thread to do the
+ // notification.
+ void OnCompleteMainThread();
+
+ // Owner of this object. MAY ONLY BE ACCESSED ON THE MAIN THREAD!
+ VisitedLinkMaster* master_;
+
+ // Indicates whether the operation has failed or not.
+ bool success_;
+
+ // Salt for this new table.
+ uint8 salt_[LINK_SALT_LENGTH];
+
+ // Stores the fingerprints we computed on the background thread.
+ VisitedLinkCommon::Fingerprints fingerprints_;
+};
+
+// VisitedLinkMaster ----------------------------------------------------------
+
+VisitedLinkMaster::VisitedLinkMaster(Listener* listener,
+ Profile* profile) {
+ InitMembers(listener, profile);
+}
+
+VisitedLinkMaster::VisitedLinkMaster(Listener* listener,
+ HistoryService* history_service,
+ bool suppress_rebuild,
+ const FilePath& filename,
+ int32 default_table_size) {
+ InitMembers(listener, NULL);
+
+ database_name_override_ = filename;
+ table_size_override_ = default_table_size;
+ history_service_override_ = history_service;
+ suppress_rebuild_ = suppress_rebuild;
+}
+
+VisitedLinkMaster::~VisitedLinkMaster() {
+ if (table_builder_.get()) {
+ // Prevent the table builder from calling us back now that we're being
+ // destroyed. Note that we DON'T delete the object, since the history
+ // system is still writing into it. When that is complete, the table
+ // builder will destroy itself when it finds we are gone.
+ table_builder_->DisownMaster();
+ }
+ FreeURLTable();
+}
+
+void VisitedLinkMaster::InitMembers(Listener* listener, Profile* profile) {
+ DCHECK(listener);
+
+ listener_ = listener;
+ file_ = NULL;
+ shared_memory_ = NULL;
+ shared_memory_serial_ = 0;
+ used_items_ = 0;
+ table_size_override_ = 0;
+ history_service_override_ = NULL;
+ suppress_rebuild_ = false;
+ profile_ = profile;
+
+#ifndef NDEBUG
+ posted_asynchronous_operation_ = false;
+#endif
+}
+
+bool VisitedLinkMaster::Init() {
+ // We probably shouldn't be loading this from the UI thread,
+ // but it does need to happen early on in startup.
+ // http://code.google.com/p/chromium/issues/detail?id=24163
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+ if (!InitFromFile())
+ return InitFromScratch(suppress_rebuild_);
+ return true;
+}
+
+VisitedLinkMaster::Hash VisitedLinkMaster::TryToAddURL(const GURL& url) {
+ // Extra check that we are not off the record. This should not happen.
+ if (profile_ && profile_->IsOffTheRecord()) {
+ NOTREACHED();
+ return null_hash_;
+ }
+
+ if (!url.is_valid())
+ return null_hash_; // Don't add invalid URLs.
+
+ Fingerprint fingerprint = ComputeURLFingerprint(url.spec().data(),
+ url.spec().size(),
+ salt_);
+ if (table_builder_) {
+ // If we have a pending delete for this fingerprint, cancel it.
+ std::set<Fingerprint>::iterator found =
+ deleted_since_rebuild_.find(fingerprint);
+ if (found != deleted_since_rebuild_.end())
+ deleted_since_rebuild_.erase(found);
+
+ // A rebuild is in progress, save this addition in the temporary list so
+ // it can be added once rebuild is complete.
+ added_since_rebuild_.insert(fingerprint);
+ }
+
+ // If the table is "full", we don't add URLs and just drop them on the floor.
+ // This can happen if we get thousands of new URLs and something causes
+ // the table resizing to fail. This check prevents a hang in that case. Note
+ // that this is *not* the resize limit, this is just a sanity check.
+ if (used_items_ / 8 > table_length_ / 10)
+ return null_hash_; // Table is more than 80% full.
+
+ return AddFingerprint(fingerprint, true);
+}
+
+void VisitedLinkMaster::AddURL(const GURL& url) {
+ Hash index = TryToAddURL(url);
+ if (!table_builder_ && index != null_hash_) {
+ // Not rebuilding, so we want to keep the file on disk up-to-date.
+ WriteUsedItemCountToFile();
+ WriteHashRangeToFile(index, index);
+ ResizeTableIfNecessary();
+ }
+}
+
+void VisitedLinkMaster::AddURLs(const std::vector<GURL>& url) {
+ for (std::vector<GURL>::const_iterator i = url.begin();
+ i != url.end(); ++i) {
+ Hash index = TryToAddURL(*i);
+ if (!table_builder_ && index != null_hash_)
+ ResizeTableIfNecessary();
+ }
+
+ // Keeps the file on disk up-to-date.
+ if (!table_builder_)
+ WriteFullTable();
+}
+
+void VisitedLinkMaster::DeleteAllURLs() {
+ // Any pending modifications are invalid.
+ added_since_rebuild_.clear();
+ deleted_since_rebuild_.clear();
+
+ // Clear the hash table.
+ used_items_ = 0;
+ memset(hash_table_, 0, this->table_length_ * sizeof(Fingerprint));
+
+ // Resize it if it is now too empty. Resize may write the new table out for
+ // us, otherwise, schedule writing the new table to disk ourselves.
+ if (!ResizeTableIfNecessary())
+ WriteFullTable();
+
+ listener_->Reset();
+}
+
+void VisitedLinkMaster::DeleteURLs(const std::set<GURL>& urls) {
+ typedef std::set<GURL>::const_iterator SetIterator;
+
+ if (urls.empty())
+ return;
+
+ listener_->Reset();
+
+ if (table_builder_) {
+ // A rebuild is in progress, save this deletion in the temporary list so
+ // it can be added once rebuild is complete.
+ for (SetIterator i = urls.begin(); i != urls.end(); ++i) {
+ if (!i->is_valid())
+ continue;
+
+ Fingerprint fingerprint =
+ ComputeURLFingerprint(i->spec().data(), i->spec().size(), salt_);
+ deleted_since_rebuild_.insert(fingerprint);
+
+ // If the URL was just added and now we're deleting it, it may be in the
+ // list of things added since the last rebuild. Delete it from that list.
+ std::set<Fingerprint>::iterator found =
+ added_since_rebuild_.find(fingerprint);
+ if (found != added_since_rebuild_.end())
+ added_since_rebuild_.erase(found);
+
+ // Delete the URLs from the in-memory table, but don't bother writing
+ // to disk since it will be replaced soon.
+ DeleteFingerprint(fingerprint, false);
+ }
+ return;
+ }
+
+ // Compute the deleted URLs' fingerprints and delete them
+ std::set<Fingerprint> deleted_fingerprints;
+ for (SetIterator i = urls.begin(); i != urls.end(); ++i) {
+ if (!i->is_valid())
+ continue;
+ deleted_fingerprints.insert(
+ ComputeURLFingerprint(i->spec().data(), i->spec().size(), salt_));
+ }
+ DeleteFingerprintsFromCurrentTable(deleted_fingerprints);
+}
+
+// See VisitedLinkCommon::IsVisited which should be in sync with this algorithm
+VisitedLinkMaster::Hash VisitedLinkMaster::AddFingerprint(
+ Fingerprint fingerprint,
+ bool send_notifications) {
+ if (!hash_table_ || table_length_ == 0) {
+ NOTREACHED(); // Not initialized.
+ return null_hash_;
+ }
+
+ Hash cur_hash = HashFingerprint(fingerprint);
+ Hash first_hash = cur_hash;
+ while (true) {
+ Fingerprint cur_fingerprint = FingerprintAt(cur_hash);
+ if (cur_fingerprint == fingerprint)
+ return null_hash_; // This fingerprint is already in there, do nothing.
+
+ if (cur_fingerprint == null_fingerprint_) {
+ // End of probe sequence found, insert here.
+ hash_table_[cur_hash] = fingerprint;
+ used_items_++;
+ // If allowed, notify listener that a new visited link was added.
+ if (send_notifications)
+ listener_->Add(fingerprint);
+ return cur_hash;
+ }
+
+ // Advance in the probe sequence.
+ cur_hash = IncrementHash(cur_hash);
+ if (cur_hash == first_hash) {
+ // This means that we've wrapped around and are about to go into an
+ // infinite loop. Something was wrong with the hashtable resizing
+ // logic, so stop here.
+ NOTREACHED();
+ return null_hash_;
+ }
+ }
+}
+
+void VisitedLinkMaster::DeleteFingerprintsFromCurrentTable(
+ const std::set<Fingerprint>& fingerprints) {
+ bool bulk_write = (fingerprints.size() > kBigDeleteThreshold);
+
+ // Delete the URLs from the table.
+ for (std::set<Fingerprint>::const_iterator i = fingerprints.begin();
+ i != fingerprints.end(); ++i)
+ DeleteFingerprint(*i, !bulk_write);
+
+ // These deleted fingerprints may make us shrink the table.
+ if (ResizeTableIfNecessary())
+ return; // The resize function wrote the new table to disk for us.
+
+ // Nobody wrote this out for us, write the full file to disk.
+ if (bulk_write)
+ WriteFullTable();
+}
+
+bool VisitedLinkMaster::DeleteFingerprint(Fingerprint fingerprint,
+ bool update_file) {
+ if (!hash_table_ || table_length_ == 0) {
+ NOTREACHED(); // Not initialized.
+ return false;
+ }
+ if (!IsVisited(fingerprint))
+ return false; // Not in the database to delete.
+
+ // First update the header used count.
+ used_items_--;
+ if (update_file)
+ WriteUsedItemCountToFile();
+
+ Hash deleted_hash = HashFingerprint(fingerprint);
+
+ // Find the range of "stuff" in the hash table that is adjacent to this
+ // fingerprint. These are things that could be affected by the change in
+ // the hash table. Since we use linear probing, anything after the deleted
+ // item up until an empty item could be affected.
+ Hash end_range = deleted_hash;
+ while (true) {
+ Hash next_hash = IncrementHash(end_range);
+ if (next_hash == deleted_hash)
+ break; // We wrapped around and the whole table is full.
+ if (!hash_table_[next_hash])
+ break; // Found the last spot.
+ end_range = next_hash;
+ }
+
+ // We could get all fancy and move the affected fingerprints around, but
+ // instead we just remove them all and re-add them (minus our deleted one).
+ // This will mean there's a small window of time where the affected links
+ // won't be marked visited.
+ StackVector<Fingerprint, 32> shuffled_fingerprints;
+ Hash stop_loop = IncrementHash(end_range); // The end range is inclusive.
+ for (Hash i = deleted_hash; i != stop_loop; i = IncrementHash(i)) {
+ if (hash_table_[i] != fingerprint) {
+ // Don't save the one we're deleting!
+ shuffled_fingerprints->push_back(hash_table_[i]);
+
+ // This will balance the increment of this value in AddFingerprint below
+ // so there is no net change.
+ used_items_--;
+ }
+ hash_table_[i] = null_fingerprint_;
+ }
+
+ if (!shuffled_fingerprints->empty()) {
+ // Need to add the new items back.
+ for (size_t i = 0; i < shuffled_fingerprints->size(); i++)
+ AddFingerprint(shuffled_fingerprints[i], false);
+ }
+
+ // Write the affected range to disk [deleted_hash, end_range].
+ if (update_file)
+ WriteHashRangeToFile(deleted_hash, end_range);
+
+ return true;
+}
+
+bool VisitedLinkMaster::WriteFullTable() {
+ // This function can get called when the file is open, for example, when we
+ // resize the table. We must handle this case and not try to reopen the file,
+ // since there may be write operations pending on the file I/O thread.
+ //
+ // Note that once we start writing, we do not delete on error. This means
+ // there can be a partial file, but the short file will be detected next time
+ // we start, and will be replaced.
+ //
+ // This might possibly get corrupted if we crash in the middle of writing.
+ // We should pick up the most common types of these failures when we notice
+ // that the file size is different when we load it back in, and then we will
+ // regenerate the table.
+ if (!file_) {
+ FilePath filename;
+ GetDatabaseFileName(&filename);
+ file_ = OpenFile(filename, "wb+");
+ if (!file_) {
+ DLOG(ERROR) << "Failed to open file " << filename.value();
+ return false;
+ }
+ }
+
+ // Write the new header.
+ int32 header[4];
+ header[0] = kFileSignature;
+ header[1] = kFileCurrentVersion;
+ header[2] = table_length_;
+ header[3] = used_items_;
+ WriteToFile(file_, 0, header, sizeof(header));
+ WriteToFile(file_, sizeof(header), salt_, LINK_SALT_LENGTH);
+
+ // Write the hash data.
+ WriteToFile(file_, kFileHeaderSize,
+ hash_table_, table_length_ * sizeof(Fingerprint));
+
+ // The hash table may have shrunk, so make sure this is the end.
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE, new AsyncSetEndOfFile(file_));
+ return true;
+}
+
+bool VisitedLinkMaster::InitFromFile() {
+ DCHECK(file_ == NULL);
+
+ FilePath filename;
+ GetDatabaseFileName(&filename);
+ ScopedFILE file_closer(OpenFile(filename, "rb+"));
+ if (!file_closer.get())
+ return false;
+
+ int32 num_entries, used_count;
+ if (!ReadFileHeader(file_closer.get(), &num_entries, &used_count, salt_))
+ return false; // Header isn't valid.
+
+ // Allocate and read the table.
+ if (!CreateURLTable(num_entries, false))
+ return false;
+ if (!ReadFromFile(file_closer.get(), kFileHeaderSize,
+ hash_table_, num_entries * sizeof(Fingerprint))) {
+ FreeURLTable();
+ return false;
+ }
+ used_items_ = used_count;
+
+#ifndef NDEBUG
+ DebugValidate();
+#endif
+
+ file_ = file_closer.release();
+ return true;
+}
+
+bool VisitedLinkMaster::InitFromScratch(bool suppress_rebuild) {
+ int32 table_size = kDefaultTableSize;
+ if (table_size_override_)
+ table_size = table_size_override_;
+
+ // The salt must be generated before the table so that it can be copied to
+ // the shared memory.
+ GenerateSalt(salt_);
+ if (!CreateURLTable(table_size, true))
+ return false;
+
+#ifndef NDEBUG
+ DebugValidate();
+#endif
+
+ if (suppress_rebuild) {
+ // When we disallow rebuilds (normally just unit tests), just use the
+ // current empty table.
+ return WriteFullTable();
+ }
+
+ // This will build the table from history. On the first run, history will
+ // be empty, so this will be correct. This will also write the new table
+ // to disk. We don't want to save explicitly here, since the rebuild may
+ // not complete, leaving us with an empty but valid visited link database.
+ // In the future, we won't know we need to try rebuilding again.
+ return RebuildTableFromHistory();
+}
+
+bool VisitedLinkMaster::ReadFileHeader(FILE* file,
+ int32* num_entries,
+ int32* used_count,
+ uint8 salt[LINK_SALT_LENGTH]) {
+ // Get file size.
+ // Note that there is no need to seek back to the original location in the
+ // file since ReadFromFile() [which is the next call accessing the file]
+ // seeks before reading.
+ if (fseek(file, 0, SEEK_END) == -1)
+ return false;
+ size_t file_size = ftell(file);
+
+ if (file_size <= kFileHeaderSize)
+ return false;
+
+ uint8 header[kFileHeaderSize];
+ if (!ReadFromFile(file, 0, &header, kFileHeaderSize))
+ return false;
+
+ // Verify the signature.
+ int32 signature;
+ memcpy(&signature, &header[kFileHeaderSignatureOffset], sizeof(signature));
+ if (signature != kFileSignature)
+ return false;
+
+ // Verify the version is up-to-date. As with other read errors, a version
+ // mistmatch will trigger a rebuild of the database from history, which will
+ // have the effect of migrating the database.
+ int32 version;
+ memcpy(&version, &header[kFileHeaderVersionOffset], sizeof(version));
+ if (version != kFileCurrentVersion)
+ return false; // Bad version.
+
+ // Read the table size and make sure it matches the file size.
+ memcpy(num_entries, &header[kFileHeaderLengthOffset], sizeof(*num_entries));
+ if (*num_entries * sizeof(Fingerprint) + kFileHeaderSize != file_size)
+ return false; // Bad size.
+
+ // Read the used item count.
+ memcpy(used_count, &header[kFileHeaderUsedOffset], sizeof(*used_count));
+ if (*used_count > *num_entries)
+ return false; // Bad used item count;
+
+ // Read the salt.
+ memcpy(salt, &header[kFileHeaderSaltOffset], LINK_SALT_LENGTH);
+
+ // This file looks OK from the header's perspective.
+ return true;
+}
+
+bool VisitedLinkMaster::GetDatabaseFileName(FilePath* filename) {
+ if (!database_name_override_.empty()) {
+ // use this filename, the directory must exist
+ *filename = database_name_override_;
+ return true;
+ }
+
+ if (!profile_ || profile_->GetPath().empty())
+ return false;
+
+ FilePath profile_dir = profile_->GetPath();
+ *filename = profile_dir.Append(FILE_PATH_LITERAL("Visited Links"));
+ return true;
+}
+
+// Initializes the shared memory structure. The salt should already be filled
+// in so that it can be written to the shared memory
+bool VisitedLinkMaster::CreateURLTable(int32 num_entries, bool init_to_empty) {
+ // The table is the size of the table followed by the entries.
+ uint32 alloc_size = num_entries * sizeof(Fingerprint) + sizeof(SharedHeader);
+
+ // Create the shared memory object.
+ shared_memory_ = new base::SharedMemory();
+ if (!shared_memory_)
+ return false;
+
+ if (!shared_memory_->CreateAndMapAnonymous(alloc_size)) {
+ delete shared_memory_;
+ shared_memory_ = NULL;
+ return false;
+ }
+
+ if (init_to_empty) {
+ memset(shared_memory_->memory(), 0, alloc_size);
+ used_items_ = 0;
+ }
+ table_length_ = num_entries;
+
+ // Save the header for other processes to read.
+ SharedHeader* header = static_cast<SharedHeader*>(shared_memory_->memory());
+ header->length = table_length_;
+ memcpy(header->salt, salt_, LINK_SALT_LENGTH);
+
+ // Our table pointer is just the data immediately following the size.
+ hash_table_ = reinterpret_cast<Fingerprint*>(
+ static_cast<char*>(shared_memory_->memory()) + sizeof(SharedHeader));
+
+ return true;
+}
+
+bool VisitedLinkMaster::BeginReplaceURLTable(int32 num_entries) {
+ base::SharedMemory *old_shared_memory = shared_memory_;
+ Fingerprint* old_hash_table = hash_table_;
+ int32 old_table_length = table_length_;
+ if (!CreateURLTable(num_entries, true)) {
+ // Try to put back the old state.
+ shared_memory_ = old_shared_memory;
+ hash_table_ = old_hash_table;
+ table_length_ = old_table_length;
+ return false;
+ }
+
+#ifndef NDEBUG
+ DebugValidate();
+#endif
+
+ return true;
+}
+
+void VisitedLinkMaster::FreeURLTable() {
+ if (shared_memory_) {
+ delete shared_memory_;
+ shared_memory_ = NULL;
+ }
+ if (!file_)
+ return;
+
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE, new AsyncCloseHandle(file_));
+}
+
+bool VisitedLinkMaster::ResizeTableIfNecessary() {
+ DCHECK(table_length_ > 0) << "Must have a table";
+
+ // Load limits for good performance/space. We are pretty conservative about
+ // keeping the table not very full. This is because we use linear probing
+ // which increases the likelihood of clumps of entries which will reduce
+ // performance.
+ const float max_table_load = 0.5f; // Grow when we're > this full.
+ const float min_table_load = 0.2f; // Shrink when we're < this full.
+
+ float load = ComputeTableLoad();
+ if (load < max_table_load &&
+ (table_length_ <= static_cast<float>(kDefaultTableSize) ||
+ load > min_table_load))
+ return false;
+
+ // Table needs to grow or shrink.
+ int new_size = NewTableSizeForCount(used_items_);
+ DCHECK(new_size > used_items_);
+ DCHECK(load <= min_table_load || new_size > table_length_);
+ ResizeTable(new_size);
+ return true;
+}
+
+void VisitedLinkMaster::ResizeTable(int32 new_size) {
+ DCHECK(shared_memory_ && shared_memory_->memory() && hash_table_);
+ shared_memory_serial_++;
+
+#ifndef NDEBUG
+ DebugValidate();
+#endif
+
+ base::SharedMemory* old_shared_memory = shared_memory_;
+ Fingerprint* old_hash_table = hash_table_;
+ int32 old_table_length = table_length_;
+ if (!BeginReplaceURLTable(new_size))
+ return;
+
+ // Now we have two tables, our local copy which is the old one, and the new
+ // one loaded into this object where we need to copy the data.
+ for (int32 i = 0; i < old_table_length; i++) {
+ Fingerprint cur = old_hash_table[i];
+ if (cur)
+ AddFingerprint(cur, false);
+ }
+
+ // On error unmapping, just forget about it since we can't do anything
+ // else to release it.
+ delete old_shared_memory;
+
+ // Send an update notification to all child processes so they read the new
+ // table.
+ listener_->NewTable(shared_memory_);
+
+#ifndef NDEBUG
+ DebugValidate();
+#endif
+
+ // The new table needs to be written to disk.
+ WriteFullTable();
+}
+
+uint32 VisitedLinkMaster::NewTableSizeForCount(int32 item_count) const {
+ // These table sizes are selected to be the maximum prime number less than
+ // a "convenient" multiple of 1K.
+ static const int table_sizes[] = {
+ 16381, // 16K = 16384 <- don't shrink below this table size
+ // (should be == default_table_size)
+ 32767, // 32K = 32768
+ 65521, // 64K = 65536
+ 130051, // 128K = 131072
+ 262127, // 256K = 262144
+ 524269, // 512K = 524288
+ 1048549, // 1M = 1048576
+ 2097143, // 2M = 2097152
+ 4194301, // 4M = 4194304
+ 8388571, // 8M = 8388608
+ 16777199, // 16M = 16777216
+ 33554347}; // 32M = 33554432
+
+ // Try to leave the table 33% full.
+ int desired = item_count * 3;
+
+ // Find the closest prime.
+ for (size_t i = 0; i < arraysize(table_sizes); i ++) {
+ if (table_sizes[i] > desired)
+ return table_sizes[i];
+ }
+
+ // Growing very big, just approximate a "good" number, not growing as much
+ // as normal.
+ return item_count * 2 - 1;
+}
+
+// See the TableBuilder definition in the header file for how this works.
+bool VisitedLinkMaster::RebuildTableFromHistory() {
+ DCHECK(!table_builder_);
+ if (table_builder_)
+ return false;
+
+ HistoryService* history_service = history_service_override_;
+ if (!history_service && profile_) {
+ history_service = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ }
+
+ if (!history_service) {
+ DLOG(WARNING) << "Attempted to rebuild visited link table, but couldn't "
+ "obtain a HistoryService.";
+ return false;
+ }
+
+ // TODO(brettw) make sure we have reasonable salt!
+ table_builder_ = new TableBuilder(this, salt_);
+
+ // Make sure the table builder stays live during the call, even if the
+ // master is deleted. This is balanced in TableBuilder::OnCompleteMainThread.
+ table_builder_->AddRef();
+ history_service->IterateURLs(table_builder_);
+ return true;
+}
+
+// See the TableBuilder declaration above for how this works.
+void VisitedLinkMaster::OnTableRebuildComplete(
+ bool success,
+ const std::vector<Fingerprint>& fingerprints) {
+ if (success) {
+ // Replace the old table with a new blank one.
+ shared_memory_serial_++;
+
+ // We are responsible for freeing it AFTER it has been replaced if
+ // replacement succeeds.
+ base::SharedMemory* old_shared_memory = shared_memory_;
+
+ int new_table_size = NewTableSizeForCount(
+ static_cast<int>(fingerprints.size() + added_since_rebuild_.size()));
+ if (BeginReplaceURLTable(new_table_size)) {
+ // Free the old table.
+ delete old_shared_memory;
+
+ // Add the stored fingerprints to the hash table.
+ for (size_t i = 0; i < fingerprints.size(); i++)
+ AddFingerprint(fingerprints[i], false);
+
+ // Also add anything that was added while we were asynchronously
+ // generating the new table.
+ for (std::set<Fingerprint>::iterator i = added_since_rebuild_.begin();
+ i != added_since_rebuild_.end(); ++i)
+ AddFingerprint(*i, false);
+ added_since_rebuild_.clear();
+
+ // Now handle deletions.
+ DeleteFingerprintsFromCurrentTable(deleted_since_rebuild_);
+ deleted_since_rebuild_.clear();
+
+ // Send an update notification to all child processes.
+ listener_->NewTable(shared_memory_);
+
+ // We shouldn't be writing the table from the main thread!
+ // http://code.google.com/p/chromium/issues/detail?id=24163
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+ WriteFullTable();
+ }
+ }
+ table_builder_ = NULL; // Will release our reference to the builder.
+
+ // Notify the unit test that the rebuild is complete (will be NULL in prod.)
+ if (rebuild_complete_task_.get()) {
+ rebuild_complete_task_->Run();
+ rebuild_complete_task_.reset(NULL);
+ }
+}
+
+void VisitedLinkMaster::WriteToFile(FILE* file,
+ off_t offset,
+ void* data,
+ int32 data_size) {
+#ifndef NDEBUG
+ posted_asynchronous_operation_ = true;
+#endif
+
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ new AsyncWriter(file, offset, data, data_size));
+}
+
+void VisitedLinkMaster::WriteUsedItemCountToFile() {
+ if (!file_)
+ return; // See comment on the file_ variable for why this might happen.
+ WriteToFile(file_, kFileHeaderUsedOffset, &used_items_, sizeof(used_items_));
+}
+
+void VisitedLinkMaster::WriteHashRangeToFile(Hash first_hash, Hash last_hash) {
+ if (!file_)
+ return; // See comment on the file_ variable for why this might happen.
+ if (last_hash < first_hash) {
+ // Handle wraparound at 0. This first write is first_hash->EOF
+ WriteToFile(file_, first_hash * sizeof(Fingerprint) + kFileHeaderSize,
+ &hash_table_[first_hash],
+ (table_length_ - first_hash + 1) * sizeof(Fingerprint));
+
+ // Now do 0->last_lash.
+ WriteToFile(file_, kFileHeaderSize, hash_table_,
+ (last_hash + 1) * sizeof(Fingerprint));
+ } else {
+ // Normal case, just write the range.
+ WriteToFile(file_, first_hash * sizeof(Fingerprint) + kFileHeaderSize,
+ &hash_table_[first_hash],
+ (last_hash - first_hash + 1) * sizeof(Fingerprint));
+ }
+}
+
+bool VisitedLinkMaster::ReadFromFile(FILE* file,
+ off_t offset,
+ void* data,
+ size_t data_size) {
+#ifndef NDEBUG
+ // Since this function is synchronous, we require that no asynchronous
+ // operations could possibly be pending.
+ DCHECK(!posted_asynchronous_operation_);
+#endif
+
+ fseek(file, offset, SEEK_SET);
+
+ size_t num_read = fread(data, 1, data_size, file);
+ return num_read == data_size;
+}
+
+// VisitedLinkTableBuilder ----------------------------------------------------
+
+VisitedLinkMaster::TableBuilder::TableBuilder(
+ VisitedLinkMaster* master,
+ const uint8 salt[LINK_SALT_LENGTH])
+ : master_(master),
+ success_(true) {
+ fingerprints_.reserve(4096);
+ memcpy(salt_, salt, sizeof(salt));
+}
+
+// TODO(brettw): Do we want to try to cancel the request if this happens? It
+// could delay shutdown if there are a lot of URLs.
+void VisitedLinkMaster::TableBuilder::DisownMaster() {
+ master_ = NULL;
+}
+
+void VisitedLinkMaster::TableBuilder::OnURL(const GURL& url) {
+ if (!url.is_empty()) {
+ fingerprints_.push_back(VisitedLinkMaster::ComputeURLFingerprint(
+ url.spec().data(), url.spec().length(), salt_));
+ }
+}
+
+void VisitedLinkMaster::TableBuilder::OnComplete(bool success) {
+ success_ = success;
+ DLOG_IF(WARNING, !success) << "Unable to rebuild visited links";
+
+ // Marshal to the main thread to notify the VisitedLinkMaster that the
+ // rebuild is complete.
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(this, &TableBuilder::OnCompleteMainThread));
+}
+
+void VisitedLinkMaster::TableBuilder::OnCompleteMainThread() {
+ if (master_)
+ master_->OnTableRebuildComplete(success_, fingerprints_);
+
+ // WILL (generally) DELETE THIS! This balances the AddRef in
+ // VisitedLinkMaster::RebuildTableFromHistory.
+ Release();
+}
diff --git a/chrome/browser/visitedlink/visitedlink_master.h b/chrome/browser/visitedlink/visitedlink_master.h
new file mode 100644
index 0000000..93e2aef
--- /dev/null
+++ b/chrome/browser/visitedlink/visitedlink_master.h
@@ -0,0 +1,388 @@
+// 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.
+
+#ifndef CHROME_BROWSER_VISITEDLINK_VISITEDLINK_MASTER_H_
+#define CHROME_BROWSER_VISITEDLINK_VISITEDLINK_MASTER_H_
+#pragma once
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+#include <set>
+#include <vector>
+
+#include "base/file_path.h"
+#include "base/gtest_prod_util.h"
+#include "base/ref_counted.h"
+#include "base/shared_memory.h"
+#include "chrome/browser/history/history.h"
+#include "chrome/common/visitedlink_common.h"
+
+class GURL;
+class Profile;
+
+// Controls the link coloring database. The master controls all writing to the
+// database as well as disk I/O. There should be only one master.
+//
+// This class will defer writing operations to the file thread. This means that
+// class destruction, the file may still be open since operations are pending on
+// another thread.
+class VisitedLinkMaster : public VisitedLinkCommon {
+ public:
+ // Listens to the link coloring database events. The master is given this
+ // event as a constructor argument and dispatches events using it.
+ class Listener {
+ public:
+ virtual ~Listener() {}
+
+ // Called when link coloring database has been created or replaced. The
+ // argument is the new table handle.
+ virtual void NewTable(base::SharedMemory*) = 0;
+
+ // Called when new link has been added. The argument is the fingerprint
+ // (hash) of the link.
+ virtual void Add(Fingerprint fingerprint) = 0;
+
+ // Called when link coloring state has been reset. This may occur when
+ // entire or parts of history were deleted.
+ virtual void Reset() = 0;
+ };
+
+ // The |listener| may not be NULL.
+ VisitedLinkMaster(Listener* listener, Profile* profile);
+
+ // In unit test mode, we allow the caller to optionally specify the database
+ // filename so that it can be run from a unit test. The directory where this
+ // file resides must exist in this mode. You can also specify the default
+ // table size to test table resizing. If this parameter is 0, we will use the
+ // defaults.
+ //
+ // In the unit test mode, we also allow the caller to provide a history
+ // service pointer (the history service can't be fetched from the browser
+ // process when we're in unit test mode). This can be NULL to try to access
+ // the main version, which will probably fail (which can be good for testing
+ // this failure mode).
+ //
+ // When |suppress_rebuild| is set, we'll not attempt to load data from
+ // history if the file can't be loaded. This should generally be set for
+ // testing except when you want to test the rebuild process explicitly.
+ VisitedLinkMaster(Listener* listener,
+ HistoryService* history_service,
+ bool suppress_rebuild,
+ const FilePath& filename,
+ int32 default_table_size);
+ virtual ~VisitedLinkMaster();
+
+ // Must be called immediately after object creation. Nothing else will work
+ // until this is called. Returns true on success, false means that this
+ // object won't work.
+ bool Init();
+
+ base::SharedMemory* shared_memory() { return shared_memory_; }
+
+ // Adds a URL to the table.
+ void AddURL(const GURL& url);
+
+ // Adds a set of URLs to the table.
+ void AddURLs(const std::vector<GURL>& url);
+
+ // Deletes the specified URLs from the table.
+ void DeleteURLs(const std::set<GURL>& urls);
+
+ // Clears the visited links table by deleting the file from disk. Used as
+ // part of history clearing.
+ void DeleteAllURLs();
+
+#if defined(UNIT_TEST) || !defined(NDEBUG) || defined(PERF_TEST)
+ // This is a debugging function that can be called to double-check internal
+ // data structures. It will assert if the check fails.
+ void DebugValidate();
+
+ // Sets a task to execute when the next rebuild from history is complete.
+ // This is used by unit tests to wait for the rebuild to complete before
+ // they continue. The pointer will be owned by this object after the call.
+ void set_rebuild_complete_task(Task* task) {
+ DCHECK(!rebuild_complete_task_.get());
+ rebuild_complete_task_.reset(task);
+ }
+
+ // returns the number of items in the table for testing verification
+ int32 GetUsedCount() const {
+ return used_items_;
+ }
+
+ // Call to cause the entire database file to be re-written from scratch
+ // to disk. Used by the performance tester.
+ bool RewriteFile() {
+ return WriteFullTable();
+ }
+#endif
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(VisitedLinkTest, Delete);
+ FRIEND_TEST_ALL_PREFIXES(VisitedLinkTest, BigDelete);
+ FRIEND_TEST_ALL_PREFIXES(VisitedLinkTest, BigImport);
+
+ // Object to rebuild the table on the history thread (see the .cc file).
+ class TableBuilder;
+
+ // Byte offsets of values in the header.
+ static const int32 kFileHeaderSignatureOffset;
+ static const int32 kFileHeaderVersionOffset;
+ static const int32 kFileHeaderLengthOffset;
+ static const int32 kFileHeaderUsedOffset;
+ static const int32 kFileHeaderSaltOffset;
+
+ // The signature at the beginning of a file.
+ static const int32 kFileSignature;
+
+ // version of the file format this module currently uses
+ static const int32 kFileCurrentVersion;
+
+ // Bytes in the file header, including the salt.
+ static const size_t kFileHeaderSize;
+
+ // When creating a fresh new table, we use this many entries.
+ static const unsigned kDefaultTableSize;
+
+ // When the user is deleting a boatload of URLs, we don't really want to do
+ // individual writes for each of them. When the count exceeds this threshold,
+ // we will write the whole table to disk at once instead of individual items.
+ static const size_t kBigDeleteThreshold;
+
+ // Backend for the constructors initializing the members.
+ void InitMembers(Listener* listener, Profile* profile);
+
+ // If a rebuild is in progress, we save the URL in the temporary list.
+ // Otherwise, we add this to the table. Returns the index of the
+ // inserted fingerprint or null_hash_ on failure.
+ Hash TryToAddURL(const GURL& url);
+
+ // File I/O functions
+ // ------------------
+
+ // Writes the entire table to disk, returning true on success. It will leave
+ // the table file open and the handle to it in file_
+ bool WriteFullTable();
+
+ // Try to load the table from the database file. If the file doesn't exist or
+ // is corrupt, this will return failure.
+ bool InitFromFile();
+
+ // Reads the header of the link coloring database from disk. Assumes the
+ // file pointer is at the beginning of the file and that there are no pending
+ // asynchronous I/O operations.
+ //
+ // Returns true on success and places the size of the table in num_entries
+ // and the number of nonzero fingerprints in used_count. This will fail if
+ // the version of the file is not the current version of the database.
+ bool ReadFileHeader(FILE* hfile, int32* num_entries, int32* used_count,
+ uint8 salt[LINK_SALT_LENGTH]);
+
+ // Fills *filename with the name of the link database filename
+ bool GetDatabaseFileName(FilePath* filename);
+
+ // Wrapper around Window's WriteFile using asynchronous I/O. This will proxy
+ // the write to a background thread.
+ void WriteToFile(FILE* hfile, off_t offset, void* data, int32 data_size);
+
+ // Helper function to schedule and asynchronous write of the used count to
+ // disk (this is a common operation).
+ void WriteUsedItemCountToFile();
+
+ // Helper function to schedule an asynchronous write of the given range of
+ // hash functions to disk. The range is inclusive on both ends. The range can
+ // wrap around at 0 and this function will handle it.
+ void WriteHashRangeToFile(Hash first_hash, Hash last_hash);
+
+ // Synchronous read from the file. Assumes there are no pending asynchronous
+ // I/O functions. Returns true if the entire buffer was successfully filled.
+ bool ReadFromFile(FILE* hfile, off_t offset, void* data, size_t data_size);
+
+ // General table handling
+ // ----------------------
+
+ // Called to add a fingerprint to the table. If |send_notifications| is true
+ // and the item is added successfully, Listener::Add will be invoked.
+ // Returns the index of the inserted fingerprint or null_hash_ if there was a
+ // duplicate and this item was skippped.
+ Hash AddFingerprint(Fingerprint fingerprint, bool send_notifications);
+
+ // Deletes all fingerprints from the given vector from the current hash table
+ // and syncs it to disk if there are changes. This does not update the
+ // deleted_since_rebuild_ list, the caller must update this itself if there
+ // is an update pending.
+ void DeleteFingerprintsFromCurrentTable(
+ const std::set<Fingerprint>& fingerprints);
+
+ // Removes the indicated fingerprint from the table. If the update_file flag
+ // is set, the changes will also be written to disk. Returns true if the
+ // fingerprint was deleted, false if it was not in the table to delete.
+ bool DeleteFingerprint(Fingerprint fingerprint, bool update_file);
+
+ // Creates a new empty table, call if InitFromFile() fails. Normally, when
+ // |suppress_rebuild| is false, the table will be rebuilt from history,
+ // keeping us in sync. When |suppress_rebuild| is true, the new table will be
+ // empty and we will not consult history. This is used when clearing the
+ // database and for unit tests.
+ bool InitFromScratch(bool suppress_rebuild);
+
+ // Allocates the Fingerprint structure and length. When init_to_empty is set,
+ // the table will be filled with 0s and used_items_ will be set to 0 as well.
+ // If the flag is not set, these things are untouched and it is the
+ // responsibility of the caller to fill them (like when we are reading from
+ // a file).
+ bool CreateURLTable(int32 num_entries, bool init_to_empty);
+
+ // A wrapper for CreateURLTable, this will allocate a new table, initialized
+ // to empty. The caller is responsible for saving the shared memory pointer
+ // and handles before this call (they will be replaced with new ones) and
+ // releasing them later. This is designed for callers that make a new table
+ // and then copy values from the old table to the new one, then release the
+ // old table.
+ //
+ // Returns true on success. On failure, the old table will be restored. The
+ // caller should not attemp to release the pointer/handle in this case.
+ bool BeginReplaceURLTable(int32 num_entries);
+
+ // unallocates the Fingerprint table
+ void FreeURLTable();
+
+ // For growing the table. ResizeTableIfNecessary will check to see if the
+ // table should be resized and calls ResizeTable if needed. Returns true if
+ // we decided to resize the table.
+ bool ResizeTableIfNecessary();
+
+ // Resizes the table (growing or shrinking) as necessary to accomodate the
+ // current count.
+ void ResizeTable(int32 new_size);
+
+ // Returns the desired table size for |item_count| URLs.
+ uint32 NewTableSizeForCount(int32 item_count) const;
+
+ // Computes the table load as fraction. For example, if 1/4 of the entries are
+ // full, this value will be 0.25
+ float ComputeTableLoad() const {
+ return static_cast<float>(used_items_) / static_cast<float>(table_length_);
+ }
+
+ // Initializes a rebuild of the visited link database based on the browser
+ // history. This will set table_builder_ while working, and there should not
+ // already be a rebuild in place when called. See the definition for more
+ // details on how this works.
+ //
+ // Returns true on success. Failure means we're not attempting to rebuild
+ // the database because something failed.
+ bool RebuildTableFromHistory();
+
+ // Callback that the table rebuilder uses when the rebuild is complete.
+ // |success| is true if the fingerprint generation succeeded, in which case
+ // |fingerprints| will contain the computed fingerprints. On failure, there
+ // will be no fingerprints.
+ void OnTableRebuildComplete(bool success,
+ const std::vector<Fingerprint>& fingerprints);
+
+ // Increases or decreases the given hash value by one, wrapping around as
+ // necessary. Used for probing.
+ inline Hash IncrementHash(Hash hash) {
+ if (hash >= table_length_ - 1)
+ return 0; // Wrap around.
+ return hash + 1;
+ }
+ inline Hash DecrementHash(Hash hash) {
+ if (hash <= 0)
+ return table_length_ - 1; // Wrap around.
+ return hash - 1;
+ }
+
+ Listener* listener_;
+
+#ifndef NDEBUG
+ // Indicates whether any asynchronous operation has ever been completed.
+ // We do some synchronous reads that require that no asynchronous operations
+ // are pending, yet we don't track whether they have been completed. This
+ // flag is a sanity check that these reads only happen before any
+ // asynchronous writes have been fired.
+ bool posted_asynchronous_operation_;
+#endif
+
+ // Reference to the user profile that this object belongs to
+ // (it knows the path to where the data is stored)
+ Profile* profile_;
+
+ // When non-NULL, indicates we are in database rebuild mode and points to
+ // the class collecting fingerprint information from the history system.
+ // The pointer is owned by this class, but it must remain valid while the
+ // history query is running. We must only delete it when the query is done.
+ scoped_refptr<TableBuilder> table_builder_;
+
+ // Indicates URLs added and deleted since we started rebuilding the table.
+ std::set<Fingerprint> added_since_rebuild_;
+ std::set<Fingerprint> deleted_since_rebuild_;
+
+ // TODO(brettw) Support deletion, we need to track whether anything was
+ // deleted during the rebuild here. Then we should delete any of these
+ // entries from the complete table later.
+ // std::vector<Fingerprint> removed_since_rebuild_;
+
+ // The currently open file with the table in it. This may be NULL if we're
+ // rebuilding and haven't written a new version yet. Writing to the file may
+ // be safely ignored in this case.
+ FILE* file_;
+
+ // Shared memory consists of a SharedHeader followed by the table.
+ base::SharedMemory *shared_memory_;
+
+ // When we generate new tables, we increment the serial number of the
+ // shared memory object.
+ int32 shared_memory_serial_;
+
+ // Number of non-empty items in the table, used to compute fullness.
+ int32 used_items_;
+
+ // Testing values -----------------------------------------------------------
+ //
+ // The following fields exist for testing purposes. They are not used in
+ // release builds. It'd be nice to eliminate them in release builds, but we
+ // don't want to change the signature of the object between the unit test and
+ // regular builds. Instead, we just have "default" values that these take
+ // in release builds that give "regular" behavior.
+
+ // Overridden database file name for testing
+ FilePath database_name_override_;
+
+ // When nonzero, overrides the table size for new databases for testing
+ int32 table_size_override_;
+
+ // When non-NULL, overrides the history service to use rather than as the
+ // BrowserProcess. This is provided for unit tests.
+ HistoryService* history_service_override_;
+
+ // When non-NULL, indicates the task that should be run after the next
+ // rebuild from history is complete.
+ scoped_ptr<Task> rebuild_complete_task_;
+
+ // Set to prevent us from attempting to rebuild the database from global
+ // history if we have an error opening the file. This is used for testing,
+ // will be false in production.
+ bool suppress_rebuild_;
+
+ DISALLOW_COPY_AND_ASSIGN(VisitedLinkMaster);
+};
+
+// NOTE: These methods are defined inline here, so we can share the compilation
+// of visitedlink_master.cc between the browser and the unit/perf tests.
+
+#if defined(UNIT_TEST) || defined(PERF_TEST) || !defined(NDEBUG)
+inline void VisitedLinkMaster::DebugValidate() {
+ int32 used_count = 0;
+ for (int32 i = 0; i < table_length_; i++) {
+ if (hash_table_[i])
+ used_count++;
+ }
+ DCHECK_EQ(used_count, used_items_);
+}
+#endif
+
+#endif // CHROME_BROWSER_VISITEDLINK_VISITEDLINK_MASTER_H_
diff --git a/chrome/browser/visitedlink/visitedlink_perftest.cc b/chrome/browser/visitedlink/visitedlink_perftest.cc
new file mode 100644
index 0000000..7d44b59
--- /dev/null
+++ b/chrome/browser/visitedlink/visitedlink_perftest.cc
@@ -0,0 +1,207 @@
+// 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.
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/perftimer.h"
+#include "base/shared_memory.h"
+#include "base/string_util.h"
+#include "base/test/test_file_util.h"
+#include "chrome/browser/visitedlink/visitedlink_master.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::TimeDelta;
+
+namespace {
+
+// how we generate URLs, note that the two strings should be the same length
+const int add_count = 10000;
+const int load_test_add_count = 250000;
+const char added_prefix[] = "http://www.google.com/stuff/something/foo?session=85025602345625&id=1345142319023&seq=";
+const char unadded_prefix[] = "http://www.google.org/stuff/something/foo?session=39586739476365&id=2347624314402&seq=";
+
+// Returns a URL with the given prefix and index
+GURL TestURL(const char* prefix, int i) {
+ return GURL(StringPrintf("%s%d", prefix, i));
+}
+
+// We have no slaves, so all methods on this listener are a no-ops.
+class DummyVisitedLinkEventListener : public VisitedLinkMaster::Listener {
+ public:
+ DummyVisitedLinkEventListener() {}
+ virtual void NewTable(base::SharedMemory* table) {}
+ virtual void Add(VisitedLinkCommon::Fingerprint) {}
+ virtual void Reset() {}
+
+ static DummyVisitedLinkEventListener* GetInstance() {
+ static DummyVisitedLinkEventListener instance;
+ return &instance;
+ }
+};
+
+
+// Call at the beginning of the test to retrieve the database name.
+void InitDBName(std::wstring* db_name) {
+ FilePath db_path;
+ ASSERT_TRUE(file_util::GetCurrentDirectory(&db_path));
+ db_path = db_path.AppendASCII("TempVisitedLinks");
+ *db_name = db_path.ToWStringHack();
+}
+
+// this checks IsVisited for the URLs starting with the given prefix and
+// within the given range
+void CheckVisited(VisitedLinkMaster& master, const char* prefix,
+ int begin, int end) {
+ for (int i = begin; i < end; i++)
+ master.IsVisited(TestURL(prefix, i));
+}
+
+// Fills that master's table with URLs starting with the given prefix and
+// within the given range
+void FillTable(VisitedLinkMaster& master, const char* prefix,
+ int begin, int end) {
+ for (int i = begin; i < end; i++)
+ master.AddURL(TestURL(prefix, i));
+}
+
+class VisitedLink : public testing::Test {
+ protected:
+ std::wstring db_name_;
+ virtual void SetUp() {
+ InitDBName(&db_name_);
+ file_util::Delete(db_name_, false);
+ }
+ virtual void TearDown() {
+ file_util::Delete(db_name_, false);
+ }
+};
+
+} // namespace
+
+// This test tests adding many things to a database, and how long it takes
+// to query the database with different numbers of things in it. The time
+// is the total time to do all the operations, and as such, it is only
+// useful for a regression test. If there is a regression, it might be
+// useful to make another set of tests to test these things in isolation.
+TEST_F(VisitedLink, TestAddAndQuery) {
+ // init
+ VisitedLinkMaster master(DummyVisitedLinkEventListener::GetInstance(),
+ NULL, true, FilePath(db_name_), 0);
+ ASSERT_TRUE(master.Init());
+
+ PerfTimeLogger timer("Visited_link_add_and_query");
+
+ // first check without anything in the table
+ CheckVisited(master, added_prefix, 0, add_count);
+
+ // now fill half the table
+ const int half_size = add_count / 2;
+ FillTable(master, added_prefix, 0, half_size);
+
+ // check the table again, half of these URLs will be visited, the other half
+ // will not
+ CheckVisited(master, added_prefix, 0, add_count);
+
+ // fill the rest of the table
+ FillTable(master, added_prefix, half_size, add_count);
+
+ // check URLs, doing half visited, half unvisited
+ CheckVisited(master, added_prefix, 0, add_count);
+ CheckVisited(master, unadded_prefix, 0, add_count);
+}
+
+// Tests how long it takes to write and read a large database to and from disk.
+TEST_F(VisitedLink, TestLoad) {
+ // create a big DB
+ {
+ PerfTimeLogger table_initialization_timer("Table_initialization");
+
+ VisitedLinkMaster master(DummyVisitedLinkEventListener::GetInstance(),
+ NULL, true, FilePath(db_name_), 0);
+
+ // time init with empty table
+ PerfTimeLogger initTimer("Empty_visited_link_init");
+ bool success = master.Init();
+ initTimer.Done();
+ ASSERT_TRUE(success);
+
+ // add a bunch of stuff
+ // TODO(maruel): This is very inefficient because the file gets rewritten
+ // many time and this is the actual bottleneck of this test. The file should
+ // only get written that the end of the FillTable call, not 4169(!) times.
+ FillTable(master, added_prefix, 0, load_test_add_count);
+
+ // time writing the file out out
+ PerfTimeLogger flushTimer("Visited_link_database_flush");
+ master.RewriteFile();
+ // TODO(maruel): Without calling FlushFileBuffers(master.file_); you don't
+ // know really how much time it took to write the file.
+ flushTimer.Done();
+
+ table_initialization_timer.Done();
+ }
+
+ // test loading the DB back, we do this several times since the flushing is
+ // not very reliable.
+ const int load_count = 5;
+ std::vector<double> cold_load_times;
+ std::vector<double> hot_load_times;
+ for (int i = 0; i < load_count; i++) {
+ // make sure the file has to be re-loaded
+ file_util::EvictFileFromSystemCache(
+ FilePath::FromWStringHack(std::wstring(db_name_)));
+
+ // cold load (no OS cache, hopefully)
+ {
+ PerfTimer cold_timer;
+
+ VisitedLinkMaster master(DummyVisitedLinkEventListener::GetInstance(),
+ NULL,
+ true,
+ FilePath(db_name_),
+ 0);
+ bool success = master.Init();
+ TimeDelta elapsed = cold_timer.Elapsed();
+ ASSERT_TRUE(success);
+
+ cold_load_times.push_back(elapsed.InMillisecondsF());
+ }
+
+ // hot load (with OS caching the file in memory)
+ {
+ PerfTimer hot_timer;
+
+ VisitedLinkMaster master(DummyVisitedLinkEventListener::GetInstance(),
+ NULL,
+ true,
+ FilePath(db_name_),
+ 0);
+ bool success = master.Init();
+ TimeDelta elapsed = hot_timer.Elapsed();
+ ASSERT_TRUE(success);
+
+ hot_load_times.push_back(elapsed.InMillisecondsF());
+ }
+ }
+
+ // We discard the max and return the average time.
+ cold_load_times.erase(std::max_element(cold_load_times.begin(),
+ cold_load_times.end()));
+ hot_load_times.erase(std::max_element(hot_load_times.begin(),
+ hot_load_times.end()));
+
+ double cold_sum = 0, hot_sum = 0;
+ for (int i = 0; i < static_cast<int>(cold_load_times.size()); i++) {
+ cold_sum += cold_load_times[i];
+ hot_sum += hot_load_times[i];
+ }
+ LogPerfResult("Visited_link_cold_load_time",
+ cold_sum / cold_load_times.size(), "ms");
+ LogPerfResult("Visited_link_hot_load_time",
+ hot_sum / hot_load_times.size(), "ms");
+}
diff --git a/chrome/browser/visitedlink/visitedlink_unittest.cc b/chrome/browser/visitedlink/visitedlink_unittest.cc
new file mode 100644
index 0000000..c187440
--- /dev/null
+++ b/chrome/browser/visitedlink/visitedlink_unittest.cc
@@ -0,0 +1,774 @@
+// 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.
+
+#include <vector>
+#include <string>
+#include <cstdio>
+
+#include "base/message_loop.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/process_util.h"
+#include "base/shared_memory.h"
+#include "base/string_util.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/visitedlink/visitedlink_master.h"
+#include "chrome/browser/visitedlink/visitedlink_event_listener.h"
+#include "chrome/browser/renderer_host/browser_render_process_host.h"
+#include "chrome/browser/renderer_host/test/test_render_view_host.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/renderer/visitedlink_slave.h"
+#include "chrome/test/testing_profile.h"
+#include "googleurl/src/gurl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// a nice long URL that we can append numbers to to get new URLs
+const char g_test_prefix[] =
+ "http://www.google.com/products/foo/index.html?id=45028640526508376&seq=";
+const int g_test_count = 1000;
+
+// Returns a test URL for index |i|
+GURL TestURL(int i) {
+ return GURL(StringPrintf("%s%d", g_test_prefix, i));
+}
+
+std::vector<VisitedLinkSlave*> g_slaves;
+
+} // namespace
+
+class TrackingVisitedLinkEventListener : public VisitedLinkMaster::Listener {
+ public:
+ TrackingVisitedLinkEventListener()
+ : reset_count_(0),
+ add_count_(0) {}
+
+ virtual void NewTable(base::SharedMemory* table) {
+ if (table) {
+ for (std::vector<VisitedLinkSlave>::size_type i = 0;
+ i < g_slaves.size(); i++) {
+ base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle();
+ table->ShareToProcess(base::GetCurrentProcessHandle(), &new_handle);
+ g_slaves[i]->Init(new_handle);
+ }
+ }
+ }
+ virtual void Add(VisitedLinkCommon::Fingerprint) { add_count_++; }
+ virtual void Reset() { reset_count_++; }
+
+ void SetUp() {
+ reset_count_ = 0;
+ add_count_ = 0;
+ }
+
+ int reset_count() const { return reset_count_; }
+ int add_count() const { return add_count_; }
+
+ private:
+ int reset_count_;
+ int add_count_;
+};
+
+class VisitedLinkTest : public testing::Test {
+ protected:
+ VisitedLinkTest()
+ : ui_thread_(BrowserThread::UI, &message_loop_),
+ file_thread_(BrowserThread::FILE, &message_loop_) {}
+ // Initialize the history system. This should be called before InitVisited().
+ bool InitHistory() {
+ history_service_ = new HistoryService;
+ return history_service_->Init(history_dir_, NULL);
+ }
+
+ // Initializes the visited link objects. Pass in the size that you want a
+ // freshly created table to be. 0 means use the default.
+ //
+ // |suppress_rebuild| is set when we're not testing rebuilding, see
+ // the VisitedLinkMaster constructor.
+ bool InitVisited(int initial_size, bool suppress_rebuild) {
+ // Initialize the visited link system.
+ master_.reset(new VisitedLinkMaster(&listener_, history_service_,
+ suppress_rebuild, visited_file_,
+ initial_size));
+ return master_->Init();
+ }
+
+ // May be called multiple times (some tests will do this to clear things,
+ // and TearDown will do this to make sure eveything is shiny before quitting.
+ void ClearDB() {
+ if (master_.get())
+ master_.reset(NULL);
+
+ if (history_service_.get()) {
+ history_service_->SetOnBackendDestroyTask(new MessageLoop::QuitTask);
+ history_service_->Cleanup();
+ history_service_ = NULL;
+
+ // Wait for the backend class to terminate before deleting the files and
+ // moving to the next test. Note: if this never terminates, somebody is
+ // probably leaking a reference to the history backend, so it never calls
+ // our destroy task.
+ MessageLoop::current()->Run();
+ }
+ }
+
+ // Loads the database from disk and makes sure that the same URLs are present
+ // as were generated by TestIO_Create(). This also checks the URLs with a
+ // slave to make sure it reads the data properly.
+ void Reload() {
+ // Clean up after our caller, who may have left the database open.
+ ClearDB();
+
+ ASSERT_TRUE(InitHistory());
+ ASSERT_TRUE(InitVisited(0, true));
+ master_->DebugValidate();
+
+ // check that the table has the proper number of entries
+ int used_count = master_->GetUsedCount();
+ ASSERT_EQ(used_count, g_test_count);
+
+ // Create a slave database.
+ VisitedLinkSlave slave;
+ base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle();
+ master_->shared_memory()->ShareToProcess(
+ base::GetCurrentProcessHandle(), &new_handle);
+ bool success = slave.Init(new_handle);
+ ASSERT_TRUE(success);
+ g_slaves.push_back(&slave);
+
+ bool found;
+ for (int i = 0; i < g_test_count; i++) {
+ GURL cur = TestURL(i);
+ found = master_->IsVisited(cur);
+ EXPECT_TRUE(found) << "URL " << i << "not found in master.";
+
+ found = slave.IsVisited(cur);
+ EXPECT_TRUE(found) << "URL " << i << "not found in slave.";
+ }
+
+ // test some random URL so we know that it returns false sometimes too
+ found = master_->IsVisited(GURL("http://unfound.site/"));
+ ASSERT_FALSE(found);
+ found = slave.IsVisited(GURL("http://unfound.site/"));
+ ASSERT_FALSE(found);
+
+ master_->DebugValidate();
+
+ g_slaves.clear();
+ }
+
+ // testing::Test
+ virtual void SetUp() {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+
+ history_dir_ = temp_dir_.path().AppendASCII("VisitedLinkTest");
+ ASSERT_TRUE(file_util::CreateDirectory(history_dir_));
+
+ visited_file_ = history_dir_.Append(FILE_PATH_LITERAL("VisitedLinks"));
+ listener_.SetUp();
+ }
+
+ virtual void TearDown() {
+ ClearDB();
+ }
+
+ ScopedTempDir temp_dir_;
+
+ MessageLoop message_loop_;
+ BrowserThread ui_thread_;
+ BrowserThread file_thread_;
+
+ // Filenames for the services;
+ FilePath history_dir_;
+ FilePath visited_file_;
+
+ scoped_ptr<VisitedLinkMaster> master_;
+ scoped_refptr<HistoryService> history_service_;
+ TrackingVisitedLinkEventListener listener_;
+};
+
+// This test creates and reads some databases to make sure the data is
+// preserved throughout those operations.
+TEST_F(VisitedLinkTest, DatabaseIO) {
+ ASSERT_TRUE(InitHistory());
+ ASSERT_TRUE(InitVisited(0, true));
+
+ for (int i = 0; i < g_test_count; i++)
+ master_->AddURL(TestURL(i));
+
+ // Test that the database was written properly
+ Reload();
+}
+
+// Checks that we can delete things properly when there are collisions.
+TEST_F(VisitedLinkTest, Delete) {
+ static const int32 kInitialSize = 17;
+ ASSERT_TRUE(InitHistory());
+ ASSERT_TRUE(InitVisited(kInitialSize, true));
+
+ // Add a cluster from 14-17 wrapping around to 0. These will all hash to the
+ // same value.
+ const VisitedLinkCommon::Fingerprint kFingerprint0 = kInitialSize * 0 + 14;
+ const VisitedLinkCommon::Fingerprint kFingerprint1 = kInitialSize * 1 + 14;
+ const VisitedLinkCommon::Fingerprint kFingerprint2 = kInitialSize * 2 + 14;
+ const VisitedLinkCommon::Fingerprint kFingerprint3 = kInitialSize * 3 + 14;
+ const VisitedLinkCommon::Fingerprint kFingerprint4 = kInitialSize * 4 + 14;
+ master_->AddFingerprint(kFingerprint0, false); // @14
+ master_->AddFingerprint(kFingerprint1, false); // @15
+ master_->AddFingerprint(kFingerprint2, false); // @16
+ master_->AddFingerprint(kFingerprint3, false); // @0
+ master_->AddFingerprint(kFingerprint4, false); // @1
+
+ // Deleting 14 should move the next value up one slot (we do not specify an
+ // order).
+ EXPECT_EQ(kFingerprint3, master_->hash_table_[0]);
+ master_->DeleteFingerprint(kFingerprint3, false);
+ VisitedLinkCommon::Fingerprint zero_fingerprint = 0;
+ EXPECT_EQ(zero_fingerprint, master_->hash_table_[1]);
+ EXPECT_NE(zero_fingerprint, master_->hash_table_[0]);
+
+ // Deleting the other four should leave the table empty.
+ master_->DeleteFingerprint(kFingerprint0, false);
+ master_->DeleteFingerprint(kFingerprint1, false);
+ master_->DeleteFingerprint(kFingerprint2, false);
+ master_->DeleteFingerprint(kFingerprint4, false);
+
+ EXPECT_EQ(0, master_->used_items_);
+ for (int i = 0; i < kInitialSize; i++)
+ EXPECT_EQ(zero_fingerprint, master_->hash_table_[i]) <<
+ "Hash table has values in it.";
+}
+
+// When we delete more than kBigDeleteThreshold we trigger different behavior
+// where the entire file is rewritten.
+TEST_F(VisitedLinkTest, BigDelete) {
+ ASSERT_TRUE(InitHistory());
+ ASSERT_TRUE(InitVisited(16381, true));
+
+ // Add the base set of URLs that won't be deleted.
+ // Reload() will test for these.
+ for (int32 i = 0; i < g_test_count; i++)
+ master_->AddURL(TestURL(i));
+
+ // Add more URLs than necessary to trigger this case.
+ const int kTestDeleteCount = VisitedLinkMaster::kBigDeleteThreshold + 2;
+ std::set<GURL> urls_to_delete;
+ for (int32 i = g_test_count; i < g_test_count + kTestDeleteCount; i++) {
+ GURL url(TestURL(i));
+ master_->AddURL(url);
+ urls_to_delete.insert(url);
+ }
+
+ master_->DeleteURLs(urls_to_delete);
+ master_->DebugValidate();
+
+ Reload();
+}
+
+TEST_F(VisitedLinkTest, DeleteAll) {
+ ASSERT_TRUE(InitHistory());
+ ASSERT_TRUE(InitVisited(0, true));
+
+ {
+ VisitedLinkSlave slave;
+ base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle();
+ master_->shared_memory()->ShareToProcess(
+ base::GetCurrentProcessHandle(), &new_handle);
+ ASSERT_TRUE(slave.Init(new_handle));
+ g_slaves.push_back(&slave);
+
+ // Add the test URLs.
+ for (int i = 0; i < g_test_count; i++) {
+ master_->AddURL(TestURL(i));
+ ASSERT_EQ(i + 1, master_->GetUsedCount());
+ }
+ master_->DebugValidate();
+
+ // Make sure the slave picked up the adds.
+ for (int i = 0; i < g_test_count; i++)
+ EXPECT_TRUE(slave.IsVisited(TestURL(i)));
+
+ // Clear the table and make sure the slave picked it up.
+ master_->DeleteAllURLs();
+ EXPECT_EQ(0, master_->GetUsedCount());
+ for (int i = 0; i < g_test_count; i++) {
+ EXPECT_FALSE(master_->IsVisited(TestURL(i)));
+ EXPECT_FALSE(slave.IsVisited(TestURL(i)));
+ }
+
+ // Close the database.
+ g_slaves.clear();
+ ClearDB();
+ }
+
+ // Reopen and validate.
+ ASSERT_TRUE(InitHistory());
+ ASSERT_TRUE(InitVisited(0, true));
+ master_->DebugValidate();
+ EXPECT_EQ(0, master_->GetUsedCount());
+ for (int i = 0; i < g_test_count; i++)
+ EXPECT_FALSE(master_->IsVisited(TestURL(i)));
+}
+
+// This tests that the master correctly resizes its tables when it gets too
+// full, notifies its slaves of the change, and updates the disk.
+TEST_F(VisitedLinkTest, Resizing) {
+ // Create a very small database.
+ const int32 initial_size = 17;
+ ASSERT_TRUE(InitHistory());
+ ASSERT_TRUE(InitVisited(initial_size, true));
+
+ // ...and a slave
+ VisitedLinkSlave slave;
+ base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle();
+ master_->shared_memory()->ShareToProcess(
+ base::GetCurrentProcessHandle(), &new_handle);
+ bool success = slave.Init(new_handle);
+ ASSERT_TRUE(success);
+ g_slaves.push_back(&slave);
+
+ int32 used_count = master_->GetUsedCount();
+ ASSERT_EQ(used_count, 0);
+
+ for (int i = 0; i < g_test_count; i++) {
+ master_->AddURL(TestURL(i));
+ used_count = master_->GetUsedCount();
+ ASSERT_EQ(i + 1, used_count);
+ }
+
+ // Verify that the table got resized sufficiently.
+ int32 table_size;
+ VisitedLinkCommon::Fingerprint* table;
+ master_->GetUsageStatistics(&table_size, &table);
+ used_count = master_->GetUsedCount();
+ ASSERT_GT(table_size, used_count);
+ ASSERT_EQ(used_count, g_test_count) <<
+ "table count doesn't match the # of things we added";
+
+ // Verify that the slave got the resize message and has the same
+ // table information.
+ int32 child_table_size;
+ VisitedLinkCommon::Fingerprint* child_table;
+ slave.GetUsageStatistics(&child_table_size, &child_table);
+ ASSERT_EQ(table_size, child_table_size);
+ for (int32 i = 0; i < table_size; i++) {
+ ASSERT_EQ(table[i], child_table[i]);
+ }
+
+ master_->DebugValidate();
+ g_slaves.clear();
+
+ // This tests that the file is written correctly by reading it in using
+ // a new database.
+ Reload();
+}
+
+// Tests that if the database doesn't exist, it will be rebuilt from history.
+TEST_F(VisitedLinkTest, Rebuild) {
+ ASSERT_TRUE(InitHistory());
+
+ // Add half of our URLs to history. This needs to be done before we
+ // initialize the visited link DB.
+ int history_count = g_test_count / 2;
+ for (int i = 0; i < history_count; i++)
+ history_service_->AddPage(TestURL(i), history::SOURCE_BROWSED);
+
+ // Initialize the visited link DB. Since the visited links file doesn't exist
+ // and we don't suppress history rebuilding, this will load from history.
+ ASSERT_TRUE(InitVisited(0, false));
+
+ // While the table is rebuilding, add the rest of the URLs to the visited
+ // link system. This isn't guaranteed to happen during the rebuild, so we
+ // can't be 100% sure we're testing the right thing, but in practice is.
+ // All the adds above will generally take some time queuing up on the
+ // history thread, and it will take a while to catch up to actually
+ // processing the rebuild that has queued behind it. We will generally
+ // finish adding all of the URLs before it has even found the first URL.
+ for (int i = history_count; i < g_test_count; i++)
+ master_->AddURL(TestURL(i));
+
+ // Add one more and then delete it.
+ master_->AddURL(TestURL(g_test_count));
+ std::set<GURL> deleted_urls;
+ deleted_urls.insert(TestURL(g_test_count));
+ master_->DeleteURLs(deleted_urls);
+
+ // Wait for the rebuild to complete. The task will terminate the message
+ // loop when the rebuild is done. There's no chance that the rebuild will
+ // complete before we set the task because the rebuild completion message
+ // is posted to the message loop; until we Run() it, rebuild can not
+ // complete.
+ master_->set_rebuild_complete_task(new MessageLoop::QuitTask);
+ MessageLoop::current()->Run();
+
+ // Test that all URLs were written to the database properly.
+ Reload();
+
+ // Make sure the extra one was *not* written (Reload won't test this).
+ EXPECT_FALSE(master_->IsVisited(TestURL(g_test_count)));
+}
+
+// Test that importing a large number of URLs will work
+TEST_F(VisitedLinkTest, BigImport) {
+ ASSERT_TRUE(InitHistory());
+ ASSERT_TRUE(InitVisited(0, false));
+
+ // Before the table rebuilds, add a large number of URLs
+ int total_count = VisitedLinkMaster::kDefaultTableSize + 10;
+ for (int i = 0; i < total_count; i++)
+ master_->AddURL(TestURL(i));
+
+ // Wait for the rebuild to complete.
+ master_->set_rebuild_complete_task(new MessageLoop::QuitTask);
+ MessageLoop::current()->Run();
+
+ // Ensure that the right number of URLs are present
+ int used_count = master_->GetUsedCount();
+ ASSERT_EQ(used_count, total_count);
+}
+
+TEST_F(VisitedLinkTest, Listener) {
+ ASSERT_TRUE(InitHistory());
+ ASSERT_TRUE(InitVisited(0, true));
+
+ // Add test URLs.
+ for (int i = 0; i < g_test_count; i++) {
+ master_->AddURL(TestURL(i));
+ ASSERT_EQ(i + 1, master_->GetUsedCount());
+ }
+
+ std::set<GURL> deleted_urls;
+ deleted_urls.insert(TestURL(0));
+ // Delete an URL.
+ master_->DeleteURLs(deleted_urls);
+ // ... and all of the remaining ones.
+ master_->DeleteAllURLs();
+
+ // Verify that VisitedLinkMaster::Listener::Add was called for each added URL.
+ EXPECT_EQ(g_test_count, listener_.add_count());
+ // Verify that VisitedLinkMaster::Listener::Reset was called both when one and
+ // all URLs are deleted.
+ EXPECT_EQ(2, listener_.reset_count());
+}
+
+class VisitCountingProfile : public TestingProfile {
+ public:
+ explicit VisitCountingProfile(VisitedLinkEventListener* event_listener)
+ : add_count_(0),
+ add_event_count_(0),
+ reset_event_count_(0),
+ event_listener_(event_listener) {}
+
+ virtual VisitedLinkMaster* GetVisitedLinkMaster() {
+ if (!visited_link_master_.get()) {
+ visited_link_master_.reset(new VisitedLinkMaster(event_listener_, this));
+ visited_link_master_->Init();
+ }
+ return visited_link_master_.get();
+ }
+
+ void CountAddEvent(int by) {
+ add_count_ += by;
+ add_event_count_++;
+ }
+
+ void CountResetEvent() {
+ reset_event_count_++;
+ }
+
+ VisitedLinkMaster* master() const { return visited_link_master_.get(); }
+ int add_count() const { return add_count_; }
+ int add_event_count() const { return add_event_count_; }
+ int reset_event_count() const { return reset_event_count_; }
+
+ private:
+ int add_count_;
+ int add_event_count_;
+ int reset_event_count_;
+ VisitedLinkEventListener* event_listener_;
+ scoped_ptr<VisitedLinkMaster> visited_link_master_;
+};
+
+class VisitCountingRenderProcessHost : public MockRenderProcessHost {
+ public:
+ explicit VisitCountingRenderProcessHost(Profile* profile)
+ : MockRenderProcessHost(profile) {}
+
+ virtual void AddVisitedLinks(
+ const VisitedLinkCommon::Fingerprints& visited_links) {
+ VisitCountingProfile* counting_profile =
+ static_cast<VisitCountingProfile*>(profile());
+ counting_profile->CountAddEvent(visited_links.size());
+ }
+ virtual void ResetVisitedLinks() {
+ VisitCountingProfile* counting_profile =
+ static_cast<VisitCountingProfile*>(profile());
+ counting_profile->CountResetEvent();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(VisitCountingRenderProcessHost);
+};
+
+// Stub out as little as possible, borrowing from MockRenderProcessHost.
+class VisitRelayingRenderProcessHost : public BrowserRenderProcessHost {
+ public:
+ explicit VisitRelayingRenderProcessHost(Profile* profile)
+ : BrowserRenderProcessHost(profile) {
+ }
+ virtual ~VisitRelayingRenderProcessHost() {
+ }
+
+ virtual bool Init() { return true; }
+
+ virtual void CancelResourceRequests(int render_widget_id) {
+ }
+
+ virtual void CrossSiteClosePageACK(int new_render_process_host_id,
+ int new_request_id) {
+ }
+
+ virtual bool WaitForPaintMsg(int render_widget_id,
+ const base::TimeDelta& max_delay,
+ IPC::Message* msg) {
+ return false;
+ }
+
+ virtual bool Send(IPC::Message* msg) {
+ VisitCountingProfile* counting_profile =
+ static_cast<VisitCountingProfile*>(profile());
+
+ if (msg->type() == ViewMsg_VisitedLink_Add::ID)
+ counting_profile->CountAddEvent(1);
+ else if (msg->type() == ViewMsg_VisitedLink_Reset::ID)
+ counting_profile->CountResetEvent();
+
+ delete msg;
+ return true;
+ }
+
+ virtual void SetBackgrounded(bool backgrounded) {
+ backgrounded_ = backgrounded;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(VisitRelayingRenderProcessHost);
+};
+
+class VisitedLinkRenderProcessHostFactory
+ : public MockRenderProcessHostFactory {
+ public:
+ VisitedLinkRenderProcessHostFactory()
+ : MockRenderProcessHostFactory(),
+ relay_mode_(false) {}
+ virtual RenderProcessHost* CreateRenderProcessHost(Profile* profile) const {
+ if (relay_mode_)
+ return new VisitRelayingRenderProcessHost(profile);
+ else
+ return new VisitCountingRenderProcessHost(profile);
+ }
+
+ void set_relay_mode(bool mode) { relay_mode_ = mode; }
+
+ private:
+ bool relay_mode_;
+
+ DISALLOW_COPY_AND_ASSIGN(VisitedLinkRenderProcessHostFactory);
+};
+
+class VisitedLinkEventsTest : public RenderViewHostTestHarness {
+ public:
+ VisitedLinkEventsTest()
+ : RenderViewHostTestHarness(),
+ file_thread_(BrowserThread::FILE, &message_loop_) {}
+ ~VisitedLinkEventsTest() {
+ // This ends up using the file thread to schedule the delete.
+ profile_.reset();
+ message_loop_.RunAllPending();
+ }
+ virtual void SetFactoryMode() {}
+ virtual void SetUp() {
+ SetFactoryMode();
+ event_listener_.reset(new VisitedLinkEventListener());
+ rvh_factory_.set_render_process_host_factory(&vc_rph_factory_);
+ profile_.reset(new VisitCountingProfile(event_listener_.get()));
+ RenderViewHostTestHarness::SetUp();
+ }
+
+ VisitCountingProfile* profile() const {
+ return static_cast<VisitCountingProfile*>(profile_.get());
+ }
+
+ void WaitForCoalescense() {
+ // Let the timer fire.
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ new MessageLoop::QuitTask(), 110);
+ MessageLoop::current()->Run();
+ }
+
+ protected:
+ VisitedLinkRenderProcessHostFactory vc_rph_factory_;
+
+ private:
+ scoped_ptr<VisitedLinkEventListener> event_listener_;
+ BrowserThread file_thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(VisitedLinkEventsTest);
+};
+
+class VisitedLinkRelayTest : public VisitedLinkEventsTest {
+ public:
+ virtual void SetFactoryMode() { vc_rph_factory_.set_relay_mode(true); }
+};
+
+TEST_F(VisitedLinkEventsTest, Coalescense) {
+ // add some URLs to master.
+ VisitedLinkMaster* master = profile_->GetVisitedLinkMaster();
+ // Add a few URLs.
+ master->AddURL(GURL("http://acidtests.org/"));
+ master->AddURL(GURL("http://google.com/"));
+ master->AddURL(GURL("http://chromium.org/"));
+ // Just for kicks, add a duplicate URL. This shouldn't increase the resulting
+ master->AddURL(GURL("http://acidtests.org/"));
+
+ // Make sure that coalescing actually occurs. There should be no links or
+ // events received by the renderer.
+ EXPECT_EQ(0, profile()->add_count());
+ EXPECT_EQ(0, profile()->add_event_count());
+
+ WaitForCoalescense();
+
+ // We now should have 3 entries added in 1 event.
+ EXPECT_EQ(3, profile()->add_count());
+ EXPECT_EQ(1, profile()->add_event_count());
+
+ // Test whether the coalescing continues by adding a few more URLs.
+ master->AddURL(GURL("http://google.com/chrome/"));
+ master->AddURL(GURL("http://webkit.org/"));
+ master->AddURL(GURL("http://acid3.acidtests.org/"));
+
+ WaitForCoalescense();
+
+ // We should have 6 entries added in 2 events.
+ EXPECT_EQ(6, profile()->add_count());
+ EXPECT_EQ(2, profile()->add_event_count());
+
+ // Test whether duplicate entries produce add events.
+ master->AddURL(GURL("http://acidtests.org/"));
+
+ WaitForCoalescense();
+
+ // We should have no change in results.
+ EXPECT_EQ(6, profile()->add_count());
+ EXPECT_EQ(2, profile()->add_event_count());
+
+ // Ensure that the coalescing does not resume after resetting.
+ master->AddURL(GURL("http://build.chromium.org/"));
+ master->DeleteAllURLs();
+
+ WaitForCoalescense();
+
+ // We should have no change in results except for one new reset event.
+ EXPECT_EQ(6, profile()->add_count());
+ EXPECT_EQ(2, profile()->add_event_count());
+ EXPECT_EQ(1, profile()->reset_event_count());
+}
+
+TEST_F(VisitedLinkRelayTest, Basics) {
+ VisitedLinkMaster* master = profile_->GetVisitedLinkMaster();
+ rvh()->CreateRenderView(string16());
+
+ // Add a few URLs.
+ master->AddURL(GURL("http://acidtests.org/"));
+ master->AddURL(GURL("http://google.com/"));
+ master->AddURL(GURL("http://chromium.org/"));
+
+ WaitForCoalescense();
+
+ // We now should have 1 add event.
+ EXPECT_EQ(1, profile()->add_event_count());
+ EXPECT_EQ(0, profile()->reset_event_count());
+
+ master->DeleteAllURLs();
+
+ WaitForCoalescense();
+
+ // We should have no change in add results, plus one new reset event.
+ EXPECT_EQ(1, profile()->add_event_count());
+ EXPECT_EQ(1, profile()->reset_event_count());
+}
+
+TEST_F(VisitedLinkRelayTest, TabVisibility) {
+ VisitedLinkMaster* master = profile_->GetVisitedLinkMaster();
+ rvh()->CreateRenderView(string16());
+
+ // Simulate tab becoming inactive.
+ rvh()->WasHidden();
+
+ // Add a few URLs.
+ master->AddURL(GURL("http://acidtests.org/"));
+ master->AddURL(GURL("http://google.com/"));
+ master->AddURL(GURL("http://chromium.org/"));
+
+ WaitForCoalescense();
+
+ // We shouldn't have any events.
+ EXPECT_EQ(0, profile()->add_event_count());
+ EXPECT_EQ(0, profile()->reset_event_count());
+
+ // Simulate the tab becoming active.
+ rvh()->WasRestored();
+
+ // We should now have 3 add events, still no reset events.
+ EXPECT_EQ(1, profile()->add_event_count());
+ EXPECT_EQ(0, profile()->reset_event_count());
+
+ // Deactivate the tab again.
+ rvh()->WasHidden();
+
+ // Add a bunch of URLs (over 50) to exhaust the link event buffer.
+ for (int i = 0; i < 100; i++)
+ master->AddURL(TestURL(i));
+
+ WaitForCoalescense();
+
+ // Again, no change in events until tab is active.
+ EXPECT_EQ(1, profile()->add_event_count());
+ EXPECT_EQ(0, profile()->reset_event_count());
+
+ // Activate the tab.
+ rvh()->WasRestored();
+
+ // We should have only one more reset event.
+ EXPECT_EQ(1, profile()->add_event_count());
+ EXPECT_EQ(1, profile()->reset_event_count());
+}
+
+TEST_F(VisitedLinkRelayTest, WebViewReadiness) {
+ VisitedLinkMaster* master = profile_->GetVisitedLinkMaster();
+
+ // Add a few URLs.
+ master->AddURL(GURL("http://acidtests.org/"));
+ master->AddURL(GURL("http://google.com/"));
+ master->AddURL(GURL("http://chromium.org/"));
+
+ WaitForCoalescense();
+
+ std::set<GURL> deleted_urls;
+ deleted_urls.insert(GURL("http://acidtests.org/"));
+ master->DeleteURLs(deleted_urls);
+
+ // We shouldn't have any events, because RenderView hasn't been created,
+ // and we ensure that updates are sent until it is.
+ EXPECT_EQ(0, profile()->add_event_count());
+ EXPECT_EQ(0, profile()->reset_event_count());
+
+ rvh()->CreateRenderView(string16());
+
+ // We should now have just a reset event: adds are eaten up by a reset
+ // that followed.
+ EXPECT_EQ(0, profile()->add_event_count());
+ EXPECT_EQ(1, profile()->reset_event_count());
+}
diff --git a/chrome/browser/visitedlink_event_listener.cc b/chrome/browser/visitedlink_event_listener.cc
deleted file mode 100644
index 3c06608..0000000
--- a/chrome/browser/visitedlink_event_listener.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/visitedlink_event_listener.h"
-
-#include "base/shared_memory.h"
-#include "chrome/browser/renderer_host/render_process_host.h"
-
-using base::Time;
-using base::TimeDelta;
-
-// The amount of time we wait to accumulate visited link additions.
-static const int kCommitIntervalMs = 100;
-
-VisitedLinkEventListener::VisitedLinkEventListener() {
-}
-
-VisitedLinkEventListener::~VisitedLinkEventListener() {
-}
-
-void VisitedLinkEventListener::NewTable(base::SharedMemory* table_memory) {
- if (!table_memory)
- return;
-
- // Send to all RenderProcessHosts.
- for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
- !i.IsAtEnd(); i.Advance()) {
- if (!i.GetCurrentValue()->HasConnection())
- continue;
-
- i.GetCurrentValue()->SendVisitedLinkTable(table_memory);
- }
-}
-
-void VisitedLinkEventListener::Add(VisitedLinkMaster::Fingerprint fingerprint) {
- pending_visited_links_.push_back(fingerprint);
-
- if (!coalesce_timer_.IsRunning()) {
- coalesce_timer_.Start(
- TimeDelta::FromMilliseconds(kCommitIntervalMs), this,
- &VisitedLinkEventListener::CommitVisitedLinks);
- }
-}
-
-void VisitedLinkEventListener::Reset() {
- pending_visited_links_.clear();
- coalesce_timer_.Stop();
-
- // Send to all RenderProcessHosts.
- for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
- !i.IsAtEnd(); i.Advance()) {
- i.GetCurrentValue()->ResetVisitedLinks();
- }
-}
-
-void VisitedLinkEventListener::CommitVisitedLinks() {
- // Send to all RenderProcessHosts.
- for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
- !i.IsAtEnd(); i.Advance()) {
- i.GetCurrentValue()->AddVisitedLinks(pending_visited_links_);
- }
-
- pending_visited_links_.clear();
-}
diff --git a/chrome/browser/visitedlink_event_listener.h b/chrome/browser/visitedlink_event_listener.h
deleted file mode 100644
index 00a7392..0000000
--- a/chrome/browser/visitedlink_event_listener.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2009 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.
-
-// VisitedLinkEventListener broadcasts link coloring database updates to all
-// processes. It also coalesces the updates to avoid excessive broadcasting of
-// messages to the renderers.
-
-#ifndef CHROME_BROWSER_VISITEDLINK_EVENT_LISTENER_H_
-#define CHROME_BROWSER_VISITEDLINK_EVENT_LISTENER_H_
-#pragma once
-
-#include "base/timer.h"
-#include "chrome/browser/visitedlink_master.h"
-
-namespace base {
-class SharedMemory;
-}
-
-class VisitedLinkEventListener : public VisitedLinkMaster::Listener {
- public:
- VisitedLinkEventListener();
- virtual ~VisitedLinkEventListener();
-
- virtual void NewTable(base::SharedMemory* table_memory);
- virtual void Add(VisitedLinkMaster::Fingerprint fingerprint);
- virtual void Reset();
-
- private:
- void CommitVisitedLinks();
-
- base::OneShotTimer<VisitedLinkEventListener> coalesce_timer_;
- VisitedLinkCommon::Fingerprints pending_visited_links_;
-
- DISALLOW_COPY_AND_ASSIGN(VisitedLinkEventListener);
-};
-
-#endif // CHROME_BROWSER_VISITEDLINK_EVENT_LISTENER_H_
diff --git a/chrome/browser/visitedlink_master.cc b/chrome/browser/visitedlink_master.cc
deleted file mode 100644
index 6fdb461..0000000
--- a/chrome/browser/visitedlink_master.cc
+++ /dev/null
@@ -1,1002 +0,0 @@
-// 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.
-
-#include "chrome/browser/visitedlink_master.h"
-
-#if defined(OS_WIN)
-#include <windows.h>
-#include <io.h>
-#include <shlobj.h>
-#endif // defined(OS_WIN)
-#include <stdio.h>
-
-#include <algorithm>
-
-#include "base/file_util.h"
-#include "base/logging.h"
-#include "base/message_loop.h"
-#include "base/path_service.h"
-#include "base/process_util.h"
-#include "base/rand_util.h"
-#include "base/stack_container.h"
-#include "base/string_util.h"
-#include "base/thread_restrictions.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/history/history.h"
-#include "chrome/browser/profile.h"
-
-using file_util::ScopedFILE;
-using file_util::OpenFile;
-using file_util::TruncateFile;
-
-const int32 VisitedLinkMaster::kFileHeaderSignatureOffset = 0;
-const int32 VisitedLinkMaster::kFileHeaderVersionOffset = 4;
-const int32 VisitedLinkMaster::kFileHeaderLengthOffset = 8;
-const int32 VisitedLinkMaster::kFileHeaderUsedOffset = 12;
-const int32 VisitedLinkMaster::kFileHeaderSaltOffset = 16;
-
-const int32 VisitedLinkMaster::kFileCurrentVersion = 2;
-
-// the signature at the beginning of the URL table = "VLnk" (visited links)
-const int32 VisitedLinkMaster::kFileSignature = 0x6b6e4c56;
-const size_t VisitedLinkMaster::kFileHeaderSize =
- kFileHeaderSaltOffset + LINK_SALT_LENGTH;
-
-// This value should also be the same as the smallest size in the lookup
-// table in NewTableSizeForCount (prime number).
-const unsigned VisitedLinkMaster::kDefaultTableSize = 16381;
-
-const size_t VisitedLinkMaster::kBigDeleteThreshold = 64;
-
-namespace {
-
-// Fills the given salt structure with some quasi-random values
-// It is not necessary to generate a cryptographically strong random string,
-// only that it be reasonably different for different users.
-void GenerateSalt(uint8 salt[LINK_SALT_LENGTH]) {
- DCHECK_EQ(LINK_SALT_LENGTH, 8) << "This code assumes the length of the salt";
- uint64 randval = base::RandUint64();
- memcpy(salt, &randval, 8);
-}
-
-// AsyncWriter ----------------------------------------------------------------
-
-// This task executes on a background thread and executes a write. This
-// prevents us from blocking the UI thread doing I/O.
-class AsyncWriter : public Task {
- public:
- AsyncWriter(FILE* file, int32 offset, const void* data, size_t data_len)
- : file_(file),
- offset_(offset) {
- data_->resize(data_len);
- memcpy(&*data_->begin(), data, data_len);
- }
-
- virtual void Run() {
- WriteToFile(file_, offset_,
- &*data_->begin(), static_cast<int32>(data_->size()));
- }
-
- // Exposed as a static so it can be called directly from the Master to
- // reduce the number of platform-specific I/O sites we have. Returns true if
- // the write was complete.
- static bool WriteToFile(FILE* file,
- off_t offset,
- const void* data,
- size_t data_len) {
- if (fseek(file, offset, SEEK_SET) != 0)
- return false; // Don't write to an invalid part of the file.
-
- size_t num_written = fwrite(data, 1, data_len, file);
-
- // The write may not make it to the kernel (stdlib may buffer the write)
- // until the next fseek/fclose call. If we crash, it's easy for our used
- // item count to be out of sync with the number of hashes we write.
- // Protect against this by calling fflush.
- int ret = fflush(file);
- DCHECK_EQ(0, ret);
- return num_written == data_len;
- }
-
- private:
- // The data to write and where to write it.
- FILE* file_;
- int32 offset_; // Offset from the beginning of the file.
-
- // Most writes are just a single fingerprint, so we reserve that much in this
- // object to avoid mallocs in that case.
- StackVector<char, sizeof(VisitedLinkCommon::Fingerprint)> data_;
-
- DISALLOW_COPY_AND_ASSIGN(AsyncWriter);
-};
-
-// Used to asynchronously set the end of the file. This must be done on the
-// same thread as the writing to keep things synchronized.
-class AsyncSetEndOfFile : public Task {
- public:
- explicit AsyncSetEndOfFile(FILE* file) : file_(file) {}
-
- virtual void Run() {
- TruncateFile(file_);
- }
-
- private:
- FILE* file_;
- DISALLOW_COPY_AND_ASSIGN(AsyncSetEndOfFile);
-};
-
-// Used to asynchronously close a file. This must be done on the same thread as
-// the writing to keep things synchronized.
-class AsyncCloseHandle : public Task {
- public:
- explicit AsyncCloseHandle(FILE* file) : file_(file) {}
-
- virtual void Run() {
- fclose(file_);
- }
-
- private:
- FILE* file_;
- DISALLOW_COPY_AND_ASSIGN(AsyncCloseHandle);
-};
-
-} // namespace
-
-// TableBuilder ---------------------------------------------------------------
-
-// How rebuilding from history works
-// ---------------------------------
-//
-// We mark that we're rebuilding from history by setting the table_builder_
-// member in VisitedLinkMaster to the TableBuilder we create. This builder
-// will be called on the history thread by the history system for every URL
-// in the database.
-//
-// The builder will store the fingerprints for those URLs, and then marshalls
-// back to the main thread where the VisitedLinkMaster will be notified. The
-// master then replaces its table with a new table containing the computed
-// fingerprints.
-//
-// The builder must remain active while the history system is using it.
-// Sometimes, the master will be deleted before the rebuild is complete, in
-// which case it notifies the builder via DisownMaster(). The builder will
-// delete itself once rebuilding is complete, and not execute any callback.
-class VisitedLinkMaster::TableBuilder
- : public HistoryService::URLEnumerator,
- public base::RefCountedThreadSafe<TableBuilder> {
- public:
- TableBuilder(VisitedLinkMaster* master,
- const uint8 salt[LINK_SALT_LENGTH]);
-
- // Called on the main thread when the master is being destroyed. This will
- // prevent a crash when the query completes and the master is no longer
- // around. We can not actually do anything but mark this fact, since the
- // table will be being rebuilt simultaneously on the other thread.
- void DisownMaster();
-
- // HistoryService::URLEnumerator
- virtual void OnURL(const GURL& url);
- virtual void OnComplete(bool succeed);
-
- private:
- friend class base::RefCountedThreadSafe<TableBuilder>;
-
- ~TableBuilder() {}
-
- // OnComplete mashals to this function on the main thread to do the
- // notification.
- void OnCompleteMainThread();
-
- // Owner of this object. MAY ONLY BE ACCESSED ON THE MAIN THREAD!
- VisitedLinkMaster* master_;
-
- // Indicates whether the operation has failed or not.
- bool success_;
-
- // Salt for this new table.
- uint8 salt_[LINK_SALT_LENGTH];
-
- // Stores the fingerprints we computed on the background thread.
- VisitedLinkCommon::Fingerprints fingerprints_;
-};
-
-// VisitedLinkMaster ----------------------------------------------------------
-
-VisitedLinkMaster::VisitedLinkMaster(Listener* listener,
- Profile* profile) {
- InitMembers(listener, profile);
-}
-
-VisitedLinkMaster::VisitedLinkMaster(Listener* listener,
- HistoryService* history_service,
- bool suppress_rebuild,
- const FilePath& filename,
- int32 default_table_size) {
- InitMembers(listener, NULL);
-
- database_name_override_ = filename;
- table_size_override_ = default_table_size;
- history_service_override_ = history_service;
- suppress_rebuild_ = suppress_rebuild;
-}
-
-VisitedLinkMaster::~VisitedLinkMaster() {
- if (table_builder_.get()) {
- // Prevent the table builder from calling us back now that we're being
- // destroyed. Note that we DON'T delete the object, since the history
- // system is still writing into it. When that is complete, the table
- // builder will destroy itself when it finds we are gone.
- table_builder_->DisownMaster();
- }
- FreeURLTable();
-}
-
-void VisitedLinkMaster::InitMembers(Listener* listener, Profile* profile) {
- DCHECK(listener);
-
- listener_ = listener;
- file_ = NULL;
- shared_memory_ = NULL;
- shared_memory_serial_ = 0;
- used_items_ = 0;
- table_size_override_ = 0;
- history_service_override_ = NULL;
- suppress_rebuild_ = false;
- profile_ = profile;
-
-#ifndef NDEBUG
- posted_asynchronous_operation_ = false;
-#endif
-}
-
-bool VisitedLinkMaster::Init() {
- // We probably shouldn't be loading this from the UI thread,
- // but it does need to happen early on in startup.
- // http://code.google.com/p/chromium/issues/detail?id=24163
- base::ThreadRestrictions::ScopedAllowIO allow_io;
- if (!InitFromFile())
- return InitFromScratch(suppress_rebuild_);
- return true;
-}
-
-VisitedLinkMaster::Hash VisitedLinkMaster::TryToAddURL(const GURL& url) {
- // Extra check that we are not off the record. This should not happen.
- if (profile_ && profile_->IsOffTheRecord()) {
- NOTREACHED();
- return null_hash_;
- }
-
- if (!url.is_valid())
- return null_hash_; // Don't add invalid URLs.
-
- Fingerprint fingerprint = ComputeURLFingerprint(url.spec().data(),
- url.spec().size(),
- salt_);
- if (table_builder_) {
- // If we have a pending delete for this fingerprint, cancel it.
- std::set<Fingerprint>::iterator found =
- deleted_since_rebuild_.find(fingerprint);
- if (found != deleted_since_rebuild_.end())
- deleted_since_rebuild_.erase(found);
-
- // A rebuild is in progress, save this addition in the temporary list so
- // it can be added once rebuild is complete.
- added_since_rebuild_.insert(fingerprint);
- }
-
- // If the table is "full", we don't add URLs and just drop them on the floor.
- // This can happen if we get thousands of new URLs and something causes
- // the table resizing to fail. This check prevents a hang in that case. Note
- // that this is *not* the resize limit, this is just a sanity check.
- if (used_items_ / 8 > table_length_ / 10)
- return null_hash_; // Table is more than 80% full.
-
- return AddFingerprint(fingerprint, true);
-}
-
-void VisitedLinkMaster::AddURL(const GURL& url) {
- Hash index = TryToAddURL(url);
- if (!table_builder_ && index != null_hash_) {
- // Not rebuilding, so we want to keep the file on disk up-to-date.
- WriteUsedItemCountToFile();
- WriteHashRangeToFile(index, index);
- ResizeTableIfNecessary();
- }
-}
-
-void VisitedLinkMaster::AddURLs(const std::vector<GURL>& url) {
- for (std::vector<GURL>::const_iterator i = url.begin();
- i != url.end(); ++i) {
- Hash index = TryToAddURL(*i);
- if (!table_builder_ && index != null_hash_)
- ResizeTableIfNecessary();
- }
-
- // Keeps the file on disk up-to-date.
- if (!table_builder_)
- WriteFullTable();
-}
-
-void VisitedLinkMaster::DeleteAllURLs() {
- // Any pending modifications are invalid.
- added_since_rebuild_.clear();
- deleted_since_rebuild_.clear();
-
- // Clear the hash table.
- used_items_ = 0;
- memset(hash_table_, 0, this->table_length_ * sizeof(Fingerprint));
-
- // Resize it if it is now too empty. Resize may write the new table out for
- // us, otherwise, schedule writing the new table to disk ourselves.
- if (!ResizeTableIfNecessary())
- WriteFullTable();
-
- listener_->Reset();
-}
-
-void VisitedLinkMaster::DeleteURLs(const std::set<GURL>& urls) {
- typedef std::set<GURL>::const_iterator SetIterator;
-
- if (urls.empty())
- return;
-
- listener_->Reset();
-
- if (table_builder_) {
- // A rebuild is in progress, save this deletion in the temporary list so
- // it can be added once rebuild is complete.
- for (SetIterator i = urls.begin(); i != urls.end(); ++i) {
- if (!i->is_valid())
- continue;
-
- Fingerprint fingerprint =
- ComputeURLFingerprint(i->spec().data(), i->spec().size(), salt_);
- deleted_since_rebuild_.insert(fingerprint);
-
- // If the URL was just added and now we're deleting it, it may be in the
- // list of things added since the last rebuild. Delete it from that list.
- std::set<Fingerprint>::iterator found =
- added_since_rebuild_.find(fingerprint);
- if (found != added_since_rebuild_.end())
- added_since_rebuild_.erase(found);
-
- // Delete the URLs from the in-memory table, but don't bother writing
- // to disk since it will be replaced soon.
- DeleteFingerprint(fingerprint, false);
- }
- return;
- }
-
- // Compute the deleted URLs' fingerprints and delete them
- std::set<Fingerprint> deleted_fingerprints;
- for (SetIterator i = urls.begin(); i != urls.end(); ++i) {
- if (!i->is_valid())
- continue;
- deleted_fingerprints.insert(
- ComputeURLFingerprint(i->spec().data(), i->spec().size(), salt_));
- }
- DeleteFingerprintsFromCurrentTable(deleted_fingerprints);
-}
-
-// See VisitedLinkCommon::IsVisited which should be in sync with this algorithm
-VisitedLinkMaster::Hash VisitedLinkMaster::AddFingerprint(
- Fingerprint fingerprint,
- bool send_notifications) {
- if (!hash_table_ || table_length_ == 0) {
- NOTREACHED(); // Not initialized.
- return null_hash_;
- }
-
- Hash cur_hash = HashFingerprint(fingerprint);
- Hash first_hash = cur_hash;
- while (true) {
- Fingerprint cur_fingerprint = FingerprintAt(cur_hash);
- if (cur_fingerprint == fingerprint)
- return null_hash_; // This fingerprint is already in there, do nothing.
-
- if (cur_fingerprint == null_fingerprint_) {
- // End of probe sequence found, insert here.
- hash_table_[cur_hash] = fingerprint;
- used_items_++;
- // If allowed, notify listener that a new visited link was added.
- if (send_notifications)
- listener_->Add(fingerprint);
- return cur_hash;
- }
-
- // Advance in the probe sequence.
- cur_hash = IncrementHash(cur_hash);
- if (cur_hash == first_hash) {
- // This means that we've wrapped around and are about to go into an
- // infinite loop. Something was wrong with the hashtable resizing
- // logic, so stop here.
- NOTREACHED();
- return null_hash_;
- }
- }
-}
-
-void VisitedLinkMaster::DeleteFingerprintsFromCurrentTable(
- const std::set<Fingerprint>& fingerprints) {
- bool bulk_write = (fingerprints.size() > kBigDeleteThreshold);
-
- // Delete the URLs from the table.
- for (std::set<Fingerprint>::const_iterator i = fingerprints.begin();
- i != fingerprints.end(); ++i)
- DeleteFingerprint(*i, !bulk_write);
-
- // These deleted fingerprints may make us shrink the table.
- if (ResizeTableIfNecessary())
- return; // The resize function wrote the new table to disk for us.
-
- // Nobody wrote this out for us, write the full file to disk.
- if (bulk_write)
- WriteFullTable();
-}
-
-bool VisitedLinkMaster::DeleteFingerprint(Fingerprint fingerprint,
- bool update_file) {
- if (!hash_table_ || table_length_ == 0) {
- NOTREACHED(); // Not initialized.
- return false;
- }
- if (!IsVisited(fingerprint))
- return false; // Not in the database to delete.
-
- // First update the header used count.
- used_items_--;
- if (update_file)
- WriteUsedItemCountToFile();
-
- Hash deleted_hash = HashFingerprint(fingerprint);
-
- // Find the range of "stuff" in the hash table that is adjacent to this
- // fingerprint. These are things that could be affected by the change in
- // the hash table. Since we use linear probing, anything after the deleted
- // item up until an empty item could be affected.
- Hash end_range = deleted_hash;
- while (true) {
- Hash next_hash = IncrementHash(end_range);
- if (next_hash == deleted_hash)
- break; // We wrapped around and the whole table is full.
- if (!hash_table_[next_hash])
- break; // Found the last spot.
- end_range = next_hash;
- }
-
- // We could get all fancy and move the affected fingerprints around, but
- // instead we just remove them all and re-add them (minus our deleted one).
- // This will mean there's a small window of time where the affected links
- // won't be marked visited.
- StackVector<Fingerprint, 32> shuffled_fingerprints;
- Hash stop_loop = IncrementHash(end_range); // The end range is inclusive.
- for (Hash i = deleted_hash; i != stop_loop; i = IncrementHash(i)) {
- if (hash_table_[i] != fingerprint) {
- // Don't save the one we're deleting!
- shuffled_fingerprints->push_back(hash_table_[i]);
-
- // This will balance the increment of this value in AddFingerprint below
- // so there is no net change.
- used_items_--;
- }
- hash_table_[i] = null_fingerprint_;
- }
-
- if (!shuffled_fingerprints->empty()) {
- // Need to add the new items back.
- for (size_t i = 0; i < shuffled_fingerprints->size(); i++)
- AddFingerprint(shuffled_fingerprints[i], false);
- }
-
- // Write the affected range to disk [deleted_hash, end_range].
- if (update_file)
- WriteHashRangeToFile(deleted_hash, end_range);
-
- return true;
-}
-
-bool VisitedLinkMaster::WriteFullTable() {
- // This function can get called when the file is open, for example, when we
- // resize the table. We must handle this case and not try to reopen the file,
- // since there may be write operations pending on the file I/O thread.
- //
- // Note that once we start writing, we do not delete on error. This means
- // there can be a partial file, but the short file will be detected next time
- // we start, and will be replaced.
- //
- // This might possibly get corrupted if we crash in the middle of writing.
- // We should pick up the most common types of these failures when we notice
- // that the file size is different when we load it back in, and then we will
- // regenerate the table.
- if (!file_) {
- FilePath filename;
- GetDatabaseFileName(&filename);
- file_ = OpenFile(filename, "wb+");
- if (!file_) {
- DLOG(ERROR) << "Failed to open file " << filename.value();
- return false;
- }
- }
-
- // Write the new header.
- int32 header[4];
- header[0] = kFileSignature;
- header[1] = kFileCurrentVersion;
- header[2] = table_length_;
- header[3] = used_items_;
- WriteToFile(file_, 0, header, sizeof(header));
- WriteToFile(file_, sizeof(header), salt_, LINK_SALT_LENGTH);
-
- // Write the hash data.
- WriteToFile(file_, kFileHeaderSize,
- hash_table_, table_length_ * sizeof(Fingerprint));
-
- // The hash table may have shrunk, so make sure this is the end.
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE, new AsyncSetEndOfFile(file_));
- return true;
-}
-
-bool VisitedLinkMaster::InitFromFile() {
- DCHECK(file_ == NULL);
-
- FilePath filename;
- GetDatabaseFileName(&filename);
- ScopedFILE file_closer(OpenFile(filename, "rb+"));
- if (!file_closer.get())
- return false;
-
- int32 num_entries, used_count;
- if (!ReadFileHeader(file_closer.get(), &num_entries, &used_count, salt_))
- return false; // Header isn't valid.
-
- // Allocate and read the table.
- if (!CreateURLTable(num_entries, false))
- return false;
- if (!ReadFromFile(file_closer.get(), kFileHeaderSize,
- hash_table_, num_entries * sizeof(Fingerprint))) {
- FreeURLTable();
- return false;
- }
- used_items_ = used_count;
-
-#ifndef NDEBUG
- DebugValidate();
-#endif
-
- file_ = file_closer.release();
- return true;
-}
-
-bool VisitedLinkMaster::InitFromScratch(bool suppress_rebuild) {
- int32 table_size = kDefaultTableSize;
- if (table_size_override_)
- table_size = table_size_override_;
-
- // The salt must be generated before the table so that it can be copied to
- // the shared memory.
- GenerateSalt(salt_);
- if (!CreateURLTable(table_size, true))
- return false;
-
-#ifndef NDEBUG
- DebugValidate();
-#endif
-
- if (suppress_rebuild) {
- // When we disallow rebuilds (normally just unit tests), just use the
- // current empty table.
- return WriteFullTable();
- }
-
- // This will build the table from history. On the first run, history will
- // be empty, so this will be correct. This will also write the new table
- // to disk. We don't want to save explicitly here, since the rebuild may
- // not complete, leaving us with an empty but valid visited link database.
- // In the future, we won't know we need to try rebuilding again.
- return RebuildTableFromHistory();
-}
-
-bool VisitedLinkMaster::ReadFileHeader(FILE* file,
- int32* num_entries,
- int32* used_count,
- uint8 salt[LINK_SALT_LENGTH]) {
- // Get file size.
- // Note that there is no need to seek back to the original location in the
- // file since ReadFromFile() [which is the next call accessing the file]
- // seeks before reading.
- if (fseek(file, 0, SEEK_END) == -1)
- return false;
- size_t file_size = ftell(file);
-
- if (file_size <= kFileHeaderSize)
- return false;
-
- uint8 header[kFileHeaderSize];
- if (!ReadFromFile(file, 0, &header, kFileHeaderSize))
- return false;
-
- // Verify the signature.
- int32 signature;
- memcpy(&signature, &header[kFileHeaderSignatureOffset], sizeof(signature));
- if (signature != kFileSignature)
- return false;
-
- // Verify the version is up-to-date. As with other read errors, a version
- // mistmatch will trigger a rebuild of the database from history, which will
- // have the effect of migrating the database.
- int32 version;
- memcpy(&version, &header[kFileHeaderVersionOffset], sizeof(version));
- if (version != kFileCurrentVersion)
- return false; // Bad version.
-
- // Read the table size and make sure it matches the file size.
- memcpy(num_entries, &header[kFileHeaderLengthOffset], sizeof(*num_entries));
- if (*num_entries * sizeof(Fingerprint) + kFileHeaderSize != file_size)
- return false; // Bad size.
-
- // Read the used item count.
- memcpy(used_count, &header[kFileHeaderUsedOffset], sizeof(*used_count));
- if (*used_count > *num_entries)
- return false; // Bad used item count;
-
- // Read the salt.
- memcpy(salt, &header[kFileHeaderSaltOffset], LINK_SALT_LENGTH);
-
- // This file looks OK from the header's perspective.
- return true;
-}
-
-bool VisitedLinkMaster::GetDatabaseFileName(FilePath* filename) {
- if (!database_name_override_.empty()) {
- // use this filename, the directory must exist
- *filename = database_name_override_;
- return true;
- }
-
- if (!profile_ || profile_->GetPath().empty())
- return false;
-
- FilePath profile_dir = profile_->GetPath();
- *filename = profile_dir.Append(FILE_PATH_LITERAL("Visited Links"));
- return true;
-}
-
-// Initializes the shared memory structure. The salt should already be filled
-// in so that it can be written to the shared memory
-bool VisitedLinkMaster::CreateURLTable(int32 num_entries, bool init_to_empty) {
- // The table is the size of the table followed by the entries.
- uint32 alloc_size = num_entries * sizeof(Fingerprint) + sizeof(SharedHeader);
-
- // Create the shared memory object.
- shared_memory_ = new base::SharedMemory();
- if (!shared_memory_)
- return false;
-
- if (!shared_memory_->CreateAndMapAnonymous(alloc_size)) {
- delete shared_memory_;
- shared_memory_ = NULL;
- return false;
- }
-
- if (init_to_empty) {
- memset(shared_memory_->memory(), 0, alloc_size);
- used_items_ = 0;
- }
- table_length_ = num_entries;
-
- // Save the header for other processes to read.
- SharedHeader* header = static_cast<SharedHeader*>(shared_memory_->memory());
- header->length = table_length_;
- memcpy(header->salt, salt_, LINK_SALT_LENGTH);
-
- // Our table pointer is just the data immediately following the size.
- hash_table_ = reinterpret_cast<Fingerprint*>(
- static_cast<char*>(shared_memory_->memory()) + sizeof(SharedHeader));
-
- return true;
-}
-
-bool VisitedLinkMaster::BeginReplaceURLTable(int32 num_entries) {
- base::SharedMemory *old_shared_memory = shared_memory_;
- Fingerprint* old_hash_table = hash_table_;
- int32 old_table_length = table_length_;
- if (!CreateURLTable(num_entries, true)) {
- // Try to put back the old state.
- shared_memory_ = old_shared_memory;
- hash_table_ = old_hash_table;
- table_length_ = old_table_length;
- return false;
- }
-
-#ifndef NDEBUG
- DebugValidate();
-#endif
-
- return true;
-}
-
-void VisitedLinkMaster::FreeURLTable() {
- if (shared_memory_) {
- delete shared_memory_;
- shared_memory_ = NULL;
- }
- if (!file_)
- return;
-
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE, new AsyncCloseHandle(file_));
-}
-
-bool VisitedLinkMaster::ResizeTableIfNecessary() {
- DCHECK(table_length_ > 0) << "Must have a table";
-
- // Load limits for good performance/space. We are pretty conservative about
- // keeping the table not very full. This is because we use linear probing
- // which increases the likelihood of clumps of entries which will reduce
- // performance.
- const float max_table_load = 0.5f; // Grow when we're > this full.
- const float min_table_load = 0.2f; // Shrink when we're < this full.
-
- float load = ComputeTableLoad();
- if (load < max_table_load &&
- (table_length_ <= static_cast<float>(kDefaultTableSize) ||
- load > min_table_load))
- return false;
-
- // Table needs to grow or shrink.
- int new_size = NewTableSizeForCount(used_items_);
- DCHECK(new_size > used_items_);
- DCHECK(load <= min_table_load || new_size > table_length_);
- ResizeTable(new_size);
- return true;
-}
-
-void VisitedLinkMaster::ResizeTable(int32 new_size) {
- DCHECK(shared_memory_ && shared_memory_->memory() && hash_table_);
- shared_memory_serial_++;
-
-#ifndef NDEBUG
- DebugValidate();
-#endif
-
- base::SharedMemory* old_shared_memory = shared_memory_;
- Fingerprint* old_hash_table = hash_table_;
- int32 old_table_length = table_length_;
- if (!BeginReplaceURLTable(new_size))
- return;
-
- // Now we have two tables, our local copy which is the old one, and the new
- // one loaded into this object where we need to copy the data.
- for (int32 i = 0; i < old_table_length; i++) {
- Fingerprint cur = old_hash_table[i];
- if (cur)
- AddFingerprint(cur, false);
- }
-
- // On error unmapping, just forget about it since we can't do anything
- // else to release it.
- delete old_shared_memory;
-
- // Send an update notification to all child processes so they read the new
- // table.
- listener_->NewTable(shared_memory_);
-
-#ifndef NDEBUG
- DebugValidate();
-#endif
-
- // The new table needs to be written to disk.
- WriteFullTable();
-}
-
-uint32 VisitedLinkMaster::NewTableSizeForCount(int32 item_count) const {
- // These table sizes are selected to be the maximum prime number less than
- // a "convenient" multiple of 1K.
- static const int table_sizes[] = {
- 16381, // 16K = 16384 <- don't shrink below this table size
- // (should be == default_table_size)
- 32767, // 32K = 32768
- 65521, // 64K = 65536
- 130051, // 128K = 131072
- 262127, // 256K = 262144
- 524269, // 512K = 524288
- 1048549, // 1M = 1048576
- 2097143, // 2M = 2097152
- 4194301, // 4M = 4194304
- 8388571, // 8M = 8388608
- 16777199, // 16M = 16777216
- 33554347}; // 32M = 33554432
-
- // Try to leave the table 33% full.
- int desired = item_count * 3;
-
- // Find the closest prime.
- for (size_t i = 0; i < arraysize(table_sizes); i ++) {
- if (table_sizes[i] > desired)
- return table_sizes[i];
- }
-
- // Growing very big, just approximate a "good" number, not growing as much
- // as normal.
- return item_count * 2 - 1;
-}
-
-// See the TableBuilder definition in the header file for how this works.
-bool VisitedLinkMaster::RebuildTableFromHistory() {
- DCHECK(!table_builder_);
- if (table_builder_)
- return false;
-
- HistoryService* history_service = history_service_override_;
- if (!history_service && profile_) {
- history_service = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
- }
-
- if (!history_service) {
- DLOG(WARNING) << "Attempted to rebuild visited link table, but couldn't "
- "obtain a HistoryService.";
- return false;
- }
-
- // TODO(brettw) make sure we have reasonable salt!
- table_builder_ = new TableBuilder(this, salt_);
-
- // Make sure the table builder stays live during the call, even if the
- // master is deleted. This is balanced in TableBuilder::OnCompleteMainThread.
- table_builder_->AddRef();
- history_service->IterateURLs(table_builder_);
- return true;
-}
-
-// See the TableBuilder declaration above for how this works.
-void VisitedLinkMaster::OnTableRebuildComplete(
- bool success,
- const std::vector<Fingerprint>& fingerprints) {
- if (success) {
- // Replace the old table with a new blank one.
- shared_memory_serial_++;
-
- // We are responsible for freeing it AFTER it has been replaced if
- // replacement succeeds.
- base::SharedMemory* old_shared_memory = shared_memory_;
-
- int new_table_size = NewTableSizeForCount(
- static_cast<int>(fingerprints.size() + added_since_rebuild_.size()));
- if (BeginReplaceURLTable(new_table_size)) {
- // Free the old table.
- delete old_shared_memory;
-
- // Add the stored fingerprints to the hash table.
- for (size_t i = 0; i < fingerprints.size(); i++)
- AddFingerprint(fingerprints[i], false);
-
- // Also add anything that was added while we were asynchronously
- // generating the new table.
- for (std::set<Fingerprint>::iterator i = added_since_rebuild_.begin();
- i != added_since_rebuild_.end(); ++i)
- AddFingerprint(*i, false);
- added_since_rebuild_.clear();
-
- // Now handle deletions.
- DeleteFingerprintsFromCurrentTable(deleted_since_rebuild_);
- deleted_since_rebuild_.clear();
-
- // Send an update notification to all child processes.
- listener_->NewTable(shared_memory_);
-
- // We shouldn't be writing the table from the main thread!
- // http://code.google.com/p/chromium/issues/detail?id=24163
- base::ThreadRestrictions::ScopedAllowIO allow_io;
- WriteFullTable();
- }
- }
- table_builder_ = NULL; // Will release our reference to the builder.
-
- // Notify the unit test that the rebuild is complete (will be NULL in prod.)
- if (rebuild_complete_task_.get()) {
- rebuild_complete_task_->Run();
- rebuild_complete_task_.reset(NULL);
- }
-}
-
-void VisitedLinkMaster::WriteToFile(FILE* file,
- off_t offset,
- void* data,
- int32 data_size) {
-#ifndef NDEBUG
- posted_asynchronous_operation_ = true;
-#endif
-
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- new AsyncWriter(file, offset, data, data_size));
-}
-
-void VisitedLinkMaster::WriteUsedItemCountToFile() {
- if (!file_)
- return; // See comment on the file_ variable for why this might happen.
- WriteToFile(file_, kFileHeaderUsedOffset, &used_items_, sizeof(used_items_));
-}
-
-void VisitedLinkMaster::WriteHashRangeToFile(Hash first_hash, Hash last_hash) {
- if (!file_)
- return; // See comment on the file_ variable for why this might happen.
- if (last_hash < first_hash) {
- // Handle wraparound at 0. This first write is first_hash->EOF
- WriteToFile(file_, first_hash * sizeof(Fingerprint) + kFileHeaderSize,
- &hash_table_[first_hash],
- (table_length_ - first_hash + 1) * sizeof(Fingerprint));
-
- // Now do 0->last_lash.
- WriteToFile(file_, kFileHeaderSize, hash_table_,
- (last_hash + 1) * sizeof(Fingerprint));
- } else {
- // Normal case, just write the range.
- WriteToFile(file_, first_hash * sizeof(Fingerprint) + kFileHeaderSize,
- &hash_table_[first_hash],
- (last_hash - first_hash + 1) * sizeof(Fingerprint));
- }
-}
-
-bool VisitedLinkMaster::ReadFromFile(FILE* file,
- off_t offset,
- void* data,
- size_t data_size) {
-#ifndef NDEBUG
- // Since this function is synchronous, we require that no asynchronous
- // operations could possibly be pending.
- DCHECK(!posted_asynchronous_operation_);
-#endif
-
- fseek(file, offset, SEEK_SET);
-
- size_t num_read = fread(data, 1, data_size, file);
- return num_read == data_size;
-}
-
-// VisitedLinkTableBuilder ----------------------------------------------------
-
-VisitedLinkMaster::TableBuilder::TableBuilder(
- VisitedLinkMaster* master,
- const uint8 salt[LINK_SALT_LENGTH])
- : master_(master),
- success_(true) {
- fingerprints_.reserve(4096);
- memcpy(salt_, salt, sizeof(salt));
-}
-
-// TODO(brettw): Do we want to try to cancel the request if this happens? It
-// could delay shutdown if there are a lot of URLs.
-void VisitedLinkMaster::TableBuilder::DisownMaster() {
- master_ = NULL;
-}
-
-void VisitedLinkMaster::TableBuilder::OnURL(const GURL& url) {
- if (!url.is_empty()) {
- fingerprints_.push_back(VisitedLinkMaster::ComputeURLFingerprint(
- url.spec().data(), url.spec().length(), salt_));
- }
-}
-
-void VisitedLinkMaster::TableBuilder::OnComplete(bool success) {
- success_ = success;
- DLOG_IF(WARNING, !success) << "Unable to rebuild visited links";
-
- // Marshal to the main thread to notify the VisitedLinkMaster that the
- // rebuild is complete.
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- NewRunnableMethod(this, &TableBuilder::OnCompleteMainThread));
-}
-
-void VisitedLinkMaster::TableBuilder::OnCompleteMainThread() {
- if (master_)
- master_->OnTableRebuildComplete(success_, fingerprints_);
-
- // WILL (generally) DELETE THIS! This balances the AddRef in
- // VisitedLinkMaster::RebuildTableFromHistory.
- Release();
-}
diff --git a/chrome/browser/visitedlink_master.h b/chrome/browser/visitedlink_master.h
deleted file mode 100644
index 55d260b..0000000
--- a/chrome/browser/visitedlink_master.h
+++ /dev/null
@@ -1,388 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_VISITEDLINK_MASTER_H__
-#define CHROME_BROWSER_VISITEDLINK_MASTER_H__
-#pragma once
-
-#if defined(OS_WIN)
-#include <windows.h>
-#endif
-#include <set>
-#include <vector>
-
-#include "base/file_path.h"
-#include "base/gtest_prod_util.h"
-#include "base/ref_counted.h"
-#include "base/shared_memory.h"
-#include "chrome/browser/history/history.h"
-#include "chrome/common/visitedlink_common.h"
-
-class GURL;
-class Profile;
-
-// Controls the link coloring database. The master controls all writing to the
-// database as well as disk I/O. There should be only one master.
-//
-// This class will defer writing operations to the file thread. This means that
-// class destruction, the file may still be open since operations are pending on
-// another thread.
-class VisitedLinkMaster : public VisitedLinkCommon {
- public:
- // Listens to the link coloring database events. The master is given this
- // event as a constructor argument and dispatches events using it.
- class Listener {
- public:
- virtual ~Listener() {}
-
- // Called when link coloring database has been created or replaced. The
- // argument is the new table handle.
- virtual void NewTable(base::SharedMemory*) = 0;
-
- // Called when new link has been added. The argument is the fingerprint
- // (hash) of the link.
- virtual void Add(Fingerprint fingerprint) = 0;
-
- // Called when link coloring state has been reset. This may occur when
- // entire or parts of history were deleted.
- virtual void Reset() = 0;
- };
-
- // The |listener| may not be NULL.
- VisitedLinkMaster(Listener* listener, Profile* profile);
-
- // In unit test mode, we allow the caller to optionally specify the database
- // filename so that it can be run from a unit test. The directory where this
- // file resides must exist in this mode. You can also specify the default
- // table size to test table resizing. If this parameter is 0, we will use the
- // defaults.
- //
- // In the unit test mode, we also allow the caller to provide a history
- // service pointer (the history service can't be fetched from the browser
- // process when we're in unit test mode). This can be NULL to try to access
- // the main version, which will probably fail (which can be good for testing
- // this failure mode).
- //
- // When |suppress_rebuild| is set, we'll not attempt to load data from
- // history if the file can't be loaded. This should generally be set for
- // testing except when you want to test the rebuild process explicitly.
- VisitedLinkMaster(Listener* listener,
- HistoryService* history_service,
- bool suppress_rebuild,
- const FilePath& filename,
- int32 default_table_size);
- virtual ~VisitedLinkMaster();
-
- // Must be called immediately after object creation. Nothing else will work
- // until this is called. Returns true on success, false means that this
- // object won't work.
- bool Init();
-
- base::SharedMemory* shared_memory() { return shared_memory_; }
-
- // Adds a URL to the table.
- void AddURL(const GURL& url);
-
- // Adds a set of URLs to the table.
- void AddURLs(const std::vector<GURL>& url);
-
- // Deletes the specified URLs from the table.
- void DeleteURLs(const std::set<GURL>& urls);
-
- // Clears the visited links table by deleting the file from disk. Used as
- // part of history clearing.
- void DeleteAllURLs();
-
-#if defined(UNIT_TEST) || !defined(NDEBUG) || defined(PERF_TEST)
- // This is a debugging function that can be called to double-check internal
- // data structures. It will assert if the check fails.
- void DebugValidate();
-
- // Sets a task to execute when the next rebuild from history is complete.
- // This is used by unit tests to wait for the rebuild to complete before
- // they continue. The pointer will be owned by this object after the call.
- void set_rebuild_complete_task(Task* task) {
- DCHECK(!rebuild_complete_task_.get());
- rebuild_complete_task_.reset(task);
- }
-
- // returns the number of items in the table for testing verification
- int32 GetUsedCount() const {
- return used_items_;
- }
-
- // Call to cause the entire database file to be re-written from scratch
- // to disk. Used by the performance tester.
- bool RewriteFile() {
- return WriteFullTable();
- }
-#endif
-
- private:
- FRIEND_TEST_ALL_PREFIXES(VisitedLinkTest, Delete);
- FRIEND_TEST_ALL_PREFIXES(VisitedLinkTest, BigDelete);
- FRIEND_TEST_ALL_PREFIXES(VisitedLinkTest, BigImport);
-
- // Object to rebuild the table on the history thread (see the .cc file).
- class TableBuilder;
-
- // Byte offsets of values in the header.
- static const int32 kFileHeaderSignatureOffset;
- static const int32 kFileHeaderVersionOffset;
- static const int32 kFileHeaderLengthOffset;
- static const int32 kFileHeaderUsedOffset;
- static const int32 kFileHeaderSaltOffset;
-
- // The signature at the beginning of a file.
- static const int32 kFileSignature;
-
- // version of the file format this module currently uses
- static const int32 kFileCurrentVersion;
-
- // Bytes in the file header, including the salt.
- static const size_t kFileHeaderSize;
-
- // When creating a fresh new table, we use this many entries.
- static const unsigned kDefaultTableSize;
-
- // When the user is deleting a boatload of URLs, we don't really want to do
- // individual writes for each of them. When the count exceeds this threshold,
- // we will write the whole table to disk at once instead of individual items.
- static const size_t kBigDeleteThreshold;
-
- // Backend for the constructors initializing the members.
- void InitMembers(Listener* listener, Profile* profile);
-
- // If a rebuild is in progress, we save the URL in the temporary list.
- // Otherwise, we add this to the table. Returns the index of the
- // inserted fingerprint or null_hash_ on failure.
- Hash TryToAddURL(const GURL& url);
-
- // File I/O functions
- // ------------------
-
- // Writes the entire table to disk, returning true on success. It will leave
- // the table file open and the handle to it in file_
- bool WriteFullTable();
-
- // Try to load the table from the database file. If the file doesn't exist or
- // is corrupt, this will return failure.
- bool InitFromFile();
-
- // Reads the header of the link coloring database from disk. Assumes the
- // file pointer is at the beginning of the file and that there are no pending
- // asynchronous I/O operations.
- //
- // Returns true on success and places the size of the table in num_entries
- // and the number of nonzero fingerprints in used_count. This will fail if
- // the version of the file is not the current version of the database.
- bool ReadFileHeader(FILE* hfile, int32* num_entries, int32* used_count,
- uint8 salt[LINK_SALT_LENGTH]);
-
- // Fills *filename with the name of the link database filename
- bool GetDatabaseFileName(FilePath* filename);
-
- // Wrapper around Window's WriteFile using asynchronous I/O. This will proxy
- // the write to a background thread.
- void WriteToFile(FILE* hfile, off_t offset, void* data, int32 data_size);
-
- // Helper function to schedule and asynchronous write of the used count to
- // disk (this is a common operation).
- void WriteUsedItemCountToFile();
-
- // Helper function to schedule an asynchronous write of the given range of
- // hash functions to disk. The range is inclusive on both ends. The range can
- // wrap around at 0 and this function will handle it.
- void WriteHashRangeToFile(Hash first_hash, Hash last_hash);
-
- // Synchronous read from the file. Assumes there are no pending asynchronous
- // I/O functions. Returns true if the entire buffer was successfully filled.
- bool ReadFromFile(FILE* hfile, off_t offset, void* data, size_t data_size);
-
- // General table handling
- // ----------------------
-
- // Called to add a fingerprint to the table. If |send_notifications| is true
- // and the item is added successfully, Listener::Add will be invoked.
- // Returns the index of the inserted fingerprint or null_hash_ if there was a
- // duplicate and this item was skippped.
- Hash AddFingerprint(Fingerprint fingerprint, bool send_notifications);
-
- // Deletes all fingerprints from the given vector from the current hash table
- // and syncs it to disk if there are changes. This does not update the
- // deleted_since_rebuild_ list, the caller must update this itself if there
- // is an update pending.
- void DeleteFingerprintsFromCurrentTable(
- const std::set<Fingerprint>& fingerprints);
-
- // Removes the indicated fingerprint from the table. If the update_file flag
- // is set, the changes will also be written to disk. Returns true if the
- // fingerprint was deleted, false if it was not in the table to delete.
- bool DeleteFingerprint(Fingerprint fingerprint, bool update_file);
-
- // Creates a new empty table, call if InitFromFile() fails. Normally, when
- // |suppress_rebuild| is false, the table will be rebuilt from history,
- // keeping us in sync. When |suppress_rebuild| is true, the new table will be
- // empty and we will not consult history. This is used when clearing the
- // database and for unit tests.
- bool InitFromScratch(bool suppress_rebuild);
-
- // Allocates the Fingerprint structure and length. When init_to_empty is set,
- // the table will be filled with 0s and used_items_ will be set to 0 as well.
- // If the flag is not set, these things are untouched and it is the
- // responsibility of the caller to fill them (like when we are reading from
- // a file).
- bool CreateURLTable(int32 num_entries, bool init_to_empty);
-
- // A wrapper for CreateURLTable, this will allocate a new table, initialized
- // to empty. The caller is responsible for saving the shared memory pointer
- // and handles before this call (they will be replaced with new ones) and
- // releasing them later. This is designed for callers that make a new table
- // and then copy values from the old table to the new one, then release the
- // old table.
- //
- // Returns true on success. On failure, the old table will be restored. The
- // caller should not attemp to release the pointer/handle in this case.
- bool BeginReplaceURLTable(int32 num_entries);
-
- // unallocates the Fingerprint table
- void FreeURLTable();
-
- // For growing the table. ResizeTableIfNecessary will check to see if the
- // table should be resized and calls ResizeTable if needed. Returns true if
- // we decided to resize the table.
- bool ResizeTableIfNecessary();
-
- // Resizes the table (growing or shrinking) as necessary to accomodate the
- // current count.
- void ResizeTable(int32 new_size);
-
- // Returns the desired table size for |item_count| URLs.
- uint32 NewTableSizeForCount(int32 item_count) const;
-
- // Computes the table load as fraction. For example, if 1/4 of the entries are
- // full, this value will be 0.25
- float ComputeTableLoad() const {
- return static_cast<float>(used_items_) / static_cast<float>(table_length_);
- }
-
- // Initializes a rebuild of the visited link database based on the browser
- // history. This will set table_builder_ while working, and there should not
- // already be a rebuild in place when called. See the definition for more
- // details on how this works.
- //
- // Returns true on success. Failure means we're not attempting to rebuild
- // the database because something failed.
- bool RebuildTableFromHistory();
-
- // Callback that the table rebuilder uses when the rebuild is complete.
- // |success| is true if the fingerprint generation succeeded, in which case
- // |fingerprints| will contain the computed fingerprints. On failure, there
- // will be no fingerprints.
- void OnTableRebuildComplete(bool success,
- const std::vector<Fingerprint>& fingerprints);
-
- // Increases or decreases the given hash value by one, wrapping around as
- // necessary. Used for probing.
- inline Hash IncrementHash(Hash hash) {
- if (hash >= table_length_ - 1)
- return 0; // Wrap around.
- return hash + 1;
- }
- inline Hash DecrementHash(Hash hash) {
- if (hash <= 0)
- return table_length_ - 1; // Wrap around.
- return hash - 1;
- }
-
- Listener* listener_;
-
-#ifndef NDEBUG
- // Indicates whether any asynchronous operation has ever been completed.
- // We do some synchronous reads that require that no asynchronous operations
- // are pending, yet we don't track whether they have been completed. This
- // flag is a sanity check that these reads only happen before any
- // asynchronous writes have been fired.
- bool posted_asynchronous_operation_;
-#endif
-
- // Reference to the user profile that this object belongs to
- // (it knows the path to where the data is stored)
- Profile* profile_;
-
- // When non-NULL, indicates we are in database rebuild mode and points to
- // the class collecting fingerprint information from the history system.
- // The pointer is owned by this class, but it must remain valid while the
- // history query is running. We must only delete it when the query is done.
- scoped_refptr<TableBuilder> table_builder_;
-
- // Indicates URLs added and deleted since we started rebuilding the table.
- std::set<Fingerprint> added_since_rebuild_;
- std::set<Fingerprint> deleted_since_rebuild_;
-
- // TODO(brettw) Support deletion, we need to track whether anything was
- // deleted during the rebuild here. Then we should delete any of these
- // entries from the complete table later.
- // std::vector<Fingerprint> removed_since_rebuild_;
-
- // The currently open file with the table in it. This may be NULL if we're
- // rebuilding and haven't written a new version yet. Writing to the file may
- // be safely ignored in this case.
- FILE* file_;
-
- // Shared memory consists of a SharedHeader followed by the table.
- base::SharedMemory *shared_memory_;
-
- // When we generate new tables, we increment the serial number of the
- // shared memory object.
- int32 shared_memory_serial_;
-
- // Number of non-empty items in the table, used to compute fullness.
- int32 used_items_;
-
- // Testing values -----------------------------------------------------------
- //
- // The following fields exist for testing purposes. They are not used in
- // release builds. It'd be nice to eliminate them in release builds, but we
- // don't want to change the signature of the object between the unit test and
- // regular builds. Instead, we just have "default" values that these take
- // in release builds that give "regular" behavior.
-
- // Overridden database file name for testing
- FilePath database_name_override_;
-
- // When nonzero, overrides the table size for new databases for testing
- int32 table_size_override_;
-
- // When non-NULL, overrides the history service to use rather than as the
- // BrowserProcess. This is provided for unit tests.
- HistoryService* history_service_override_;
-
- // When non-NULL, indicates the task that should be run after the next
- // rebuild from history is complete.
- scoped_ptr<Task> rebuild_complete_task_;
-
- // Set to prevent us from attempting to rebuild the database from global
- // history if we have an error opening the file. This is used for testing,
- // will be false in production.
- bool suppress_rebuild_;
-
- DISALLOW_COPY_AND_ASSIGN(VisitedLinkMaster);
-};
-
-// NOTE: These methods are defined inline here, so we can share the compilation
-// of visitedlink_master.cc between the browser and the unit/perf tests.
-
-#if defined(UNIT_TEST) || defined(PERF_TEST) || !defined(NDEBUG)
-inline void VisitedLinkMaster::DebugValidate() {
- int32 used_count = 0;
- for (int32 i = 0; i < table_length_; i++) {
- if (hash_table_[i])
- used_count++;
- }
- DCHECK_EQ(used_count, used_items_);
-}
-#endif
-
-#endif // CHROME_BROWSER_VISITEDLINK_MASTER_H__
diff --git a/chrome/browser/visitedlink_perftest.cc b/chrome/browser/visitedlink_perftest.cc
deleted file mode 100644
index a21848d..0000000
--- a/chrome/browser/visitedlink_perftest.cc
+++ /dev/null
@@ -1,207 +0,0 @@
-// 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.
-
-#include <algorithm>
-#include <string>
-#include <vector>
-
-#include "base/file_path.h"
-#include "base/file_util.h"
-#include "base/perftimer.h"
-#include "base/shared_memory.h"
-#include "base/string_util.h"
-#include "base/test/test_file_util.h"
-#include "chrome/browser/visitedlink_master.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::TimeDelta;
-
-namespace {
-
-// how we generate URLs, note that the two strings should be the same length
-const int add_count = 10000;
-const int load_test_add_count = 250000;
-const char added_prefix[] = "http://www.google.com/stuff/something/foo?session=85025602345625&id=1345142319023&seq=";
-const char unadded_prefix[] = "http://www.google.org/stuff/something/foo?session=39586739476365&id=2347624314402&seq=";
-
-// Returns a URL with the given prefix and index
-GURL TestURL(const char* prefix, int i) {
- return GURL(StringPrintf("%s%d", prefix, i));
-}
-
-// We have no slaves, so all methods on this listener are a no-ops.
-class DummyVisitedLinkEventListener : public VisitedLinkMaster::Listener {
- public:
- DummyVisitedLinkEventListener() {}
- virtual void NewTable(base::SharedMemory* table) {}
- virtual void Add(VisitedLinkCommon::Fingerprint) {}
- virtual void Reset() {}
-
- static DummyVisitedLinkEventListener* GetInstance() {
- static DummyVisitedLinkEventListener instance;
- return &instance;
- }
-};
-
-
-// Call at the beginning of the test to retrieve the database name.
-void InitDBName(std::wstring* db_name) {
- FilePath db_path;
- ASSERT_TRUE(file_util::GetCurrentDirectory(&db_path));
- db_path = db_path.AppendASCII("TempVisitedLinks");
- *db_name = db_path.ToWStringHack();
-}
-
-// this checks IsVisited for the URLs starting with the given prefix and
-// within the given range
-void CheckVisited(VisitedLinkMaster& master, const char* prefix,
- int begin, int end) {
- for (int i = begin; i < end; i++)
- master.IsVisited(TestURL(prefix, i));
-}
-
-// Fills that master's table with URLs starting with the given prefix and
-// within the given range
-void FillTable(VisitedLinkMaster& master, const char* prefix,
- int begin, int end) {
- for (int i = begin; i < end; i++)
- master.AddURL(TestURL(prefix, i));
-}
-
-class VisitedLink : public testing::Test {
- protected:
- std::wstring db_name_;
- virtual void SetUp() {
- InitDBName(&db_name_);
- file_util::Delete(db_name_, false);
- }
- virtual void TearDown() {
- file_util::Delete(db_name_, false);
- }
-};
-
-} // namespace
-
-// This test tests adding many things to a database, and how long it takes
-// to query the database with different numbers of things in it. The time
-// is the total time to do all the operations, and as such, it is only
-// useful for a regression test. If there is a regression, it might be
-// useful to make another set of tests to test these things in isolation.
-TEST_F(VisitedLink, TestAddAndQuery) {
- // init
- VisitedLinkMaster master(DummyVisitedLinkEventListener::GetInstance(),
- NULL, true, FilePath(db_name_), 0);
- ASSERT_TRUE(master.Init());
-
- PerfTimeLogger timer("Visited_link_add_and_query");
-
- // first check without anything in the table
- CheckVisited(master, added_prefix, 0, add_count);
-
- // now fill half the table
- const int half_size = add_count / 2;
- FillTable(master, added_prefix, 0, half_size);
-
- // check the table again, half of these URLs will be visited, the other half
- // will not
- CheckVisited(master, added_prefix, 0, add_count);
-
- // fill the rest of the table
- FillTable(master, added_prefix, half_size, add_count);
-
- // check URLs, doing half visited, half unvisited
- CheckVisited(master, added_prefix, 0, add_count);
- CheckVisited(master, unadded_prefix, 0, add_count);
-}
-
-// Tests how long it takes to write and read a large database to and from disk.
-TEST_F(VisitedLink, TestLoad) {
- // create a big DB
- {
- PerfTimeLogger table_initialization_timer("Table_initialization");
-
- VisitedLinkMaster master(DummyVisitedLinkEventListener::GetInstance(),
- NULL, true, FilePath(db_name_), 0);
-
- // time init with empty table
- PerfTimeLogger initTimer("Empty_visited_link_init");
- bool success = master.Init();
- initTimer.Done();
- ASSERT_TRUE(success);
-
- // add a bunch of stuff
- // TODO(maruel): This is very inefficient because the file gets rewritten
- // many time and this is the actual bottleneck of this test. The file should
- // only get written that the end of the FillTable call, not 4169(!) times.
- FillTable(master, added_prefix, 0, load_test_add_count);
-
- // time writing the file out out
- PerfTimeLogger flushTimer("Visited_link_database_flush");
- master.RewriteFile();
- // TODO(maruel): Without calling FlushFileBuffers(master.file_); you don't
- // know really how much time it took to write the file.
- flushTimer.Done();
-
- table_initialization_timer.Done();
- }
-
- // test loading the DB back, we do this several times since the flushing is
- // not very reliable.
- const int load_count = 5;
- std::vector<double> cold_load_times;
- std::vector<double> hot_load_times;
- for (int i = 0; i < load_count; i++) {
- // make sure the file has to be re-loaded
- file_util::EvictFileFromSystemCache(
- FilePath::FromWStringHack(std::wstring(db_name_)));
-
- // cold load (no OS cache, hopefully)
- {
- PerfTimer cold_timer;
-
- VisitedLinkMaster master(DummyVisitedLinkEventListener::GetInstance(),
- NULL,
- true,
- FilePath(db_name_),
- 0);
- bool success = master.Init();
- TimeDelta elapsed = cold_timer.Elapsed();
- ASSERT_TRUE(success);
-
- cold_load_times.push_back(elapsed.InMillisecondsF());
- }
-
- // hot load (with OS caching the file in memory)
- {
- PerfTimer hot_timer;
-
- VisitedLinkMaster master(DummyVisitedLinkEventListener::GetInstance(),
- NULL,
- true,
- FilePath(db_name_),
- 0);
- bool success = master.Init();
- TimeDelta elapsed = hot_timer.Elapsed();
- ASSERT_TRUE(success);
-
- hot_load_times.push_back(elapsed.InMillisecondsF());
- }
- }
-
- // We discard the max and return the average time.
- cold_load_times.erase(std::max_element(cold_load_times.begin(),
- cold_load_times.end()));
- hot_load_times.erase(std::max_element(hot_load_times.begin(),
- hot_load_times.end()));
-
- double cold_sum = 0, hot_sum = 0;
- for (int i = 0; i < static_cast<int>(cold_load_times.size()); i++) {
- cold_sum += cold_load_times[i];
- hot_sum += hot_load_times[i];
- }
- LogPerfResult("Visited_link_cold_load_time",
- cold_sum / cold_load_times.size(), "ms");
- LogPerfResult("Visited_link_hot_load_time",
- hot_sum / hot_load_times.size(), "ms");
-}
diff --git a/chrome/browser/visitedlink_unittest.cc b/chrome/browser/visitedlink_unittest.cc
deleted file mode 100644
index 14bc78a..0000000
--- a/chrome/browser/visitedlink_unittest.cc
+++ /dev/null
@@ -1,774 +0,0 @@
-// 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.
-
-#include <vector>
-#include <string>
-#include <cstdio>
-
-#include "base/message_loop.h"
-#include "base/file_util.h"
-#include "base/path_service.h"
-#include "base/process_util.h"
-#include "base/shared_memory.h"
-#include "base/string_util.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/visitedlink_master.h"
-#include "chrome/browser/visitedlink_event_listener.h"
-#include "chrome/browser/renderer_host/browser_render_process_host.h"
-#include "chrome/browser/renderer_host/test/test_render_view_host.h"
-#include "chrome/common/render_messages.h"
-#include "chrome/renderer/visitedlink_slave.h"
-#include "chrome/test/testing_profile.h"
-#include "googleurl/src/gurl.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-// a nice long URL that we can append numbers to to get new URLs
-const char g_test_prefix[] =
- "http://www.google.com/products/foo/index.html?id=45028640526508376&seq=";
-const int g_test_count = 1000;
-
-// Returns a test URL for index |i|
-GURL TestURL(int i) {
- return GURL(StringPrintf("%s%d", g_test_prefix, i));
-}
-
-std::vector<VisitedLinkSlave*> g_slaves;
-
-} // namespace
-
-class TrackingVisitedLinkEventListener : public VisitedLinkMaster::Listener {
- public:
- TrackingVisitedLinkEventListener()
- : reset_count_(0),
- add_count_(0) {}
-
- virtual void NewTable(base::SharedMemory* table) {
- if (table) {
- for (std::vector<VisitedLinkSlave>::size_type i = 0;
- i < g_slaves.size(); i++) {
- base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle();
- table->ShareToProcess(base::GetCurrentProcessHandle(), &new_handle);
- g_slaves[i]->Init(new_handle);
- }
- }
- }
- virtual void Add(VisitedLinkCommon::Fingerprint) { add_count_++; }
- virtual void Reset() { reset_count_++; }
-
- void SetUp() {
- reset_count_ = 0;
- add_count_ = 0;
- }
-
- int reset_count() const { return reset_count_; }
- int add_count() const { return add_count_; }
-
- private:
- int reset_count_;
- int add_count_;
-};
-
-class VisitedLinkTest : public testing::Test {
- protected:
- VisitedLinkTest()
- : ui_thread_(BrowserThread::UI, &message_loop_),
- file_thread_(BrowserThread::FILE, &message_loop_) {}
- // Initialize the history system. This should be called before InitVisited().
- bool InitHistory() {
- history_service_ = new HistoryService;
- return history_service_->Init(history_dir_, NULL);
- }
-
- // Initializes the visited link objects. Pass in the size that you want a
- // freshly created table to be. 0 means use the default.
- //
- // |suppress_rebuild| is set when we're not testing rebuilding, see
- // the VisitedLinkMaster constructor.
- bool InitVisited(int initial_size, bool suppress_rebuild) {
- // Initialize the visited link system.
- master_.reset(new VisitedLinkMaster(&listener_, history_service_,
- suppress_rebuild, visited_file_,
- initial_size));
- return master_->Init();
- }
-
- // May be called multiple times (some tests will do this to clear things,
- // and TearDown will do this to make sure eveything is shiny before quitting.
- void ClearDB() {
- if (master_.get())
- master_.reset(NULL);
-
- if (history_service_.get()) {
- history_service_->SetOnBackendDestroyTask(new MessageLoop::QuitTask);
- history_service_->Cleanup();
- history_service_ = NULL;
-
- // Wait for the backend class to terminate before deleting the files and
- // moving to the next test. Note: if this never terminates, somebody is
- // probably leaking a reference to the history backend, so it never calls
- // our destroy task.
- MessageLoop::current()->Run();
- }
- }
-
- // Loads the database from disk and makes sure that the same URLs are present
- // as were generated by TestIO_Create(). This also checks the URLs with a
- // slave to make sure it reads the data properly.
- void Reload() {
- // Clean up after our caller, who may have left the database open.
- ClearDB();
-
- ASSERT_TRUE(InitHistory());
- ASSERT_TRUE(InitVisited(0, true));
- master_->DebugValidate();
-
- // check that the table has the proper number of entries
- int used_count = master_->GetUsedCount();
- ASSERT_EQ(used_count, g_test_count);
-
- // Create a slave database.
- VisitedLinkSlave slave;
- base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle();
- master_->shared_memory()->ShareToProcess(
- base::GetCurrentProcessHandle(), &new_handle);
- bool success = slave.Init(new_handle);
- ASSERT_TRUE(success);
- g_slaves.push_back(&slave);
-
- bool found;
- for (int i = 0; i < g_test_count; i++) {
- GURL cur = TestURL(i);
- found = master_->IsVisited(cur);
- EXPECT_TRUE(found) << "URL " << i << "not found in master.";
-
- found = slave.IsVisited(cur);
- EXPECT_TRUE(found) << "URL " << i << "not found in slave.";
- }
-
- // test some random URL so we know that it returns false sometimes too
- found = master_->IsVisited(GURL("http://unfound.site/"));
- ASSERT_FALSE(found);
- found = slave.IsVisited(GURL("http://unfound.site/"));
- ASSERT_FALSE(found);
-
- master_->DebugValidate();
-
- g_slaves.clear();
- }
-
- // testing::Test
- virtual void SetUp() {
- ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-
- history_dir_ = temp_dir_.path().AppendASCII("VisitedLinkTest");
- ASSERT_TRUE(file_util::CreateDirectory(history_dir_));
-
- visited_file_ = history_dir_.Append(FILE_PATH_LITERAL("VisitedLinks"));
- listener_.SetUp();
- }
-
- virtual void TearDown() {
- ClearDB();
- }
-
- ScopedTempDir temp_dir_;
-
- MessageLoop message_loop_;
- BrowserThread ui_thread_;
- BrowserThread file_thread_;
-
- // Filenames for the services;
- FilePath history_dir_;
- FilePath visited_file_;
-
- scoped_ptr<VisitedLinkMaster> master_;
- scoped_refptr<HistoryService> history_service_;
- TrackingVisitedLinkEventListener listener_;
-};
-
-// This test creates and reads some databases to make sure the data is
-// preserved throughout those operations.
-TEST_F(VisitedLinkTest, DatabaseIO) {
- ASSERT_TRUE(InitHistory());
- ASSERT_TRUE(InitVisited(0, true));
-
- for (int i = 0; i < g_test_count; i++)
- master_->AddURL(TestURL(i));
-
- // Test that the database was written properly
- Reload();
-}
-
-// Checks that we can delete things properly when there are collisions.
-TEST_F(VisitedLinkTest, Delete) {
- static const int32 kInitialSize = 17;
- ASSERT_TRUE(InitHistory());
- ASSERT_TRUE(InitVisited(kInitialSize, true));
-
- // Add a cluster from 14-17 wrapping around to 0. These will all hash to the
- // same value.
- const VisitedLinkCommon::Fingerprint kFingerprint0 = kInitialSize * 0 + 14;
- const VisitedLinkCommon::Fingerprint kFingerprint1 = kInitialSize * 1 + 14;
- const VisitedLinkCommon::Fingerprint kFingerprint2 = kInitialSize * 2 + 14;
- const VisitedLinkCommon::Fingerprint kFingerprint3 = kInitialSize * 3 + 14;
- const VisitedLinkCommon::Fingerprint kFingerprint4 = kInitialSize * 4 + 14;
- master_->AddFingerprint(kFingerprint0, false); // @14
- master_->AddFingerprint(kFingerprint1, false); // @15
- master_->AddFingerprint(kFingerprint2, false); // @16
- master_->AddFingerprint(kFingerprint3, false); // @0
- master_->AddFingerprint(kFingerprint4, false); // @1
-
- // Deleting 14 should move the next value up one slot (we do not specify an
- // order).
- EXPECT_EQ(kFingerprint3, master_->hash_table_[0]);
- master_->DeleteFingerprint(kFingerprint3, false);
- VisitedLinkCommon::Fingerprint zero_fingerprint = 0;
- EXPECT_EQ(zero_fingerprint, master_->hash_table_[1]);
- EXPECT_NE(zero_fingerprint, master_->hash_table_[0]);
-
- // Deleting the other four should leave the table empty.
- master_->DeleteFingerprint(kFingerprint0, false);
- master_->DeleteFingerprint(kFingerprint1, false);
- master_->DeleteFingerprint(kFingerprint2, false);
- master_->DeleteFingerprint(kFingerprint4, false);
-
- EXPECT_EQ(0, master_->used_items_);
- for (int i = 0; i < kInitialSize; i++)
- EXPECT_EQ(zero_fingerprint, master_->hash_table_[i]) <<
- "Hash table has values in it.";
-}
-
-// When we delete more than kBigDeleteThreshold we trigger different behavior
-// where the entire file is rewritten.
-TEST_F(VisitedLinkTest, BigDelete) {
- ASSERT_TRUE(InitHistory());
- ASSERT_TRUE(InitVisited(16381, true));
-
- // Add the base set of URLs that won't be deleted.
- // Reload() will test for these.
- for (int32 i = 0; i < g_test_count; i++)
- master_->AddURL(TestURL(i));
-
- // Add more URLs than necessary to trigger this case.
- const int kTestDeleteCount = VisitedLinkMaster::kBigDeleteThreshold + 2;
- std::set<GURL> urls_to_delete;
- for (int32 i = g_test_count; i < g_test_count + kTestDeleteCount; i++) {
- GURL url(TestURL(i));
- master_->AddURL(url);
- urls_to_delete.insert(url);
- }
-
- master_->DeleteURLs(urls_to_delete);
- master_->DebugValidate();
-
- Reload();
-}
-
-TEST_F(VisitedLinkTest, DeleteAll) {
- ASSERT_TRUE(InitHistory());
- ASSERT_TRUE(InitVisited(0, true));
-
- {
- VisitedLinkSlave slave;
- base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle();
- master_->shared_memory()->ShareToProcess(
- base::GetCurrentProcessHandle(), &new_handle);
- ASSERT_TRUE(slave.Init(new_handle));
- g_slaves.push_back(&slave);
-
- // Add the test URLs.
- for (int i = 0; i < g_test_count; i++) {
- master_->AddURL(TestURL(i));
- ASSERT_EQ(i + 1, master_->GetUsedCount());
- }
- master_->DebugValidate();
-
- // Make sure the slave picked up the adds.
- for (int i = 0; i < g_test_count; i++)
- EXPECT_TRUE(slave.IsVisited(TestURL(i)));
-
- // Clear the table and make sure the slave picked it up.
- master_->DeleteAllURLs();
- EXPECT_EQ(0, master_->GetUsedCount());
- for (int i = 0; i < g_test_count; i++) {
- EXPECT_FALSE(master_->IsVisited(TestURL(i)));
- EXPECT_FALSE(slave.IsVisited(TestURL(i)));
- }
-
- // Close the database.
- g_slaves.clear();
- ClearDB();
- }
-
- // Reopen and validate.
- ASSERT_TRUE(InitHistory());
- ASSERT_TRUE(InitVisited(0, true));
- master_->DebugValidate();
- EXPECT_EQ(0, master_->GetUsedCount());
- for (int i = 0; i < g_test_count; i++)
- EXPECT_FALSE(master_->IsVisited(TestURL(i)));
-}
-
-// This tests that the master correctly resizes its tables when it gets too
-// full, notifies its slaves of the change, and updates the disk.
-TEST_F(VisitedLinkTest, Resizing) {
- // Create a very small database.
- const int32 initial_size = 17;
- ASSERT_TRUE(InitHistory());
- ASSERT_TRUE(InitVisited(initial_size, true));
-
- // ...and a slave
- VisitedLinkSlave slave;
- base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle();
- master_->shared_memory()->ShareToProcess(
- base::GetCurrentProcessHandle(), &new_handle);
- bool success = slave.Init(new_handle);
- ASSERT_TRUE(success);
- g_slaves.push_back(&slave);
-
- int32 used_count = master_->GetUsedCount();
- ASSERT_EQ(used_count, 0);
-
- for (int i = 0; i < g_test_count; i++) {
- master_->AddURL(TestURL(i));
- used_count = master_->GetUsedCount();
- ASSERT_EQ(i + 1, used_count);
- }
-
- // Verify that the table got resized sufficiently.
- int32 table_size;
- VisitedLinkCommon::Fingerprint* table;
- master_->GetUsageStatistics(&table_size, &table);
- used_count = master_->GetUsedCount();
- ASSERT_GT(table_size, used_count);
- ASSERT_EQ(used_count, g_test_count) <<
- "table count doesn't match the # of things we added";
-
- // Verify that the slave got the resize message and has the same
- // table information.
- int32 child_table_size;
- VisitedLinkCommon::Fingerprint* child_table;
- slave.GetUsageStatistics(&child_table_size, &child_table);
- ASSERT_EQ(table_size, child_table_size);
- for (int32 i = 0; i < table_size; i++) {
- ASSERT_EQ(table[i], child_table[i]);
- }
-
- master_->DebugValidate();
- g_slaves.clear();
-
- // This tests that the file is written correctly by reading it in using
- // a new database.
- Reload();
-}
-
-// Tests that if the database doesn't exist, it will be rebuilt from history.
-TEST_F(VisitedLinkTest, Rebuild) {
- ASSERT_TRUE(InitHistory());
-
- // Add half of our URLs to history. This needs to be done before we
- // initialize the visited link DB.
- int history_count = g_test_count / 2;
- for (int i = 0; i < history_count; i++)
- history_service_->AddPage(TestURL(i), history::SOURCE_BROWSED);
-
- // Initialize the visited link DB. Since the visited links file doesn't exist
- // and we don't suppress history rebuilding, this will load from history.
- ASSERT_TRUE(InitVisited(0, false));
-
- // While the table is rebuilding, add the rest of the URLs to the visited
- // link system. This isn't guaranteed to happen during the rebuild, so we
- // can't be 100% sure we're testing the right thing, but in practice is.
- // All the adds above will generally take some time queuing up on the
- // history thread, and it will take a while to catch up to actually
- // processing the rebuild that has queued behind it. We will generally
- // finish adding all of the URLs before it has even found the first URL.
- for (int i = history_count; i < g_test_count; i++)
- master_->AddURL(TestURL(i));
-
- // Add one more and then delete it.
- master_->AddURL(TestURL(g_test_count));
- std::set<GURL> deleted_urls;
- deleted_urls.insert(TestURL(g_test_count));
- master_->DeleteURLs(deleted_urls);
-
- // Wait for the rebuild to complete. The task will terminate the message
- // loop when the rebuild is done. There's no chance that the rebuild will
- // complete before we set the task because the rebuild completion message
- // is posted to the message loop; until we Run() it, rebuild can not
- // complete.
- master_->set_rebuild_complete_task(new MessageLoop::QuitTask);
- MessageLoop::current()->Run();
-
- // Test that all URLs were written to the database properly.
- Reload();
-
- // Make sure the extra one was *not* written (Reload won't test this).
- EXPECT_FALSE(master_->IsVisited(TestURL(g_test_count)));
-}
-
-// Test that importing a large number of URLs will work
-TEST_F(VisitedLinkTest, BigImport) {
- ASSERT_TRUE(InitHistory());
- ASSERT_TRUE(InitVisited(0, false));
-
- // Before the table rebuilds, add a large number of URLs
- int total_count = VisitedLinkMaster::kDefaultTableSize + 10;
- for (int i = 0; i < total_count; i++)
- master_->AddURL(TestURL(i));
-
- // Wait for the rebuild to complete.
- master_->set_rebuild_complete_task(new MessageLoop::QuitTask);
- MessageLoop::current()->Run();
-
- // Ensure that the right number of URLs are present
- int used_count = master_->GetUsedCount();
- ASSERT_EQ(used_count, total_count);
-}
-
-TEST_F(VisitedLinkTest, Listener) {
- ASSERT_TRUE(InitHistory());
- ASSERT_TRUE(InitVisited(0, true));
-
- // Add test URLs.
- for (int i = 0; i < g_test_count; i++) {
- master_->AddURL(TestURL(i));
- ASSERT_EQ(i + 1, master_->GetUsedCount());
- }
-
- std::set<GURL> deleted_urls;
- deleted_urls.insert(TestURL(0));
- // Delete an URL.
- master_->DeleteURLs(deleted_urls);
- // ... and all of the remaining ones.
- master_->DeleteAllURLs();
-
- // Verify that VisitedLinkMaster::Listener::Add was called for each added URL.
- EXPECT_EQ(g_test_count, listener_.add_count());
- // Verify that VisitedLinkMaster::Listener::Reset was called both when one and
- // all URLs are deleted.
- EXPECT_EQ(2, listener_.reset_count());
-}
-
-class VisitCountingProfile : public TestingProfile {
- public:
- explicit VisitCountingProfile(VisitedLinkEventListener* event_listener)
- : add_count_(0),
- add_event_count_(0),
- reset_event_count_(0),
- event_listener_(event_listener) {}
-
- virtual VisitedLinkMaster* GetVisitedLinkMaster() {
- if (!visited_link_master_.get()) {
- visited_link_master_.reset(new VisitedLinkMaster(event_listener_, this));
- visited_link_master_->Init();
- }
- return visited_link_master_.get();
- }
-
- void CountAddEvent(int by) {
- add_count_ += by;
- add_event_count_++;
- }
-
- void CountResetEvent() {
- reset_event_count_++;
- }
-
- VisitedLinkMaster* master() const { return visited_link_master_.get(); }
- int add_count() const { return add_count_; }
- int add_event_count() const { return add_event_count_; }
- int reset_event_count() const { return reset_event_count_; }
-
- private:
- int add_count_;
- int add_event_count_;
- int reset_event_count_;
- VisitedLinkEventListener* event_listener_;
- scoped_ptr<VisitedLinkMaster> visited_link_master_;
-};
-
-class VisitCountingRenderProcessHost : public MockRenderProcessHost {
- public:
- explicit VisitCountingRenderProcessHost(Profile* profile)
- : MockRenderProcessHost(profile) {}
-
- virtual void AddVisitedLinks(
- const VisitedLinkCommon::Fingerprints& visited_links) {
- VisitCountingProfile* counting_profile =
- static_cast<VisitCountingProfile*>(profile());
- counting_profile->CountAddEvent(visited_links.size());
- }
- virtual void ResetVisitedLinks() {
- VisitCountingProfile* counting_profile =
- static_cast<VisitCountingProfile*>(profile());
- counting_profile->CountResetEvent();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(VisitCountingRenderProcessHost);
-};
-
-// Stub out as little as possible, borrowing from MockRenderProcessHost.
-class VisitRelayingRenderProcessHost : public BrowserRenderProcessHost {
- public:
- explicit VisitRelayingRenderProcessHost(Profile* profile)
- : BrowserRenderProcessHost(profile) {
- }
- virtual ~VisitRelayingRenderProcessHost() {
- }
-
- virtual bool Init() { return true; }
-
- virtual void CancelResourceRequests(int render_widget_id) {
- }
-
- virtual void CrossSiteClosePageACK(int new_render_process_host_id,
- int new_request_id) {
- }
-
- virtual bool WaitForPaintMsg(int render_widget_id,
- const base::TimeDelta& max_delay,
- IPC::Message* msg) {
- return false;
- }
-
- virtual bool Send(IPC::Message* msg) {
- VisitCountingProfile* counting_profile =
- static_cast<VisitCountingProfile*>(profile());
-
- if (msg->type() == ViewMsg_VisitedLink_Add::ID)
- counting_profile->CountAddEvent(1);
- else if (msg->type() == ViewMsg_VisitedLink_Reset::ID)
- counting_profile->CountResetEvent();
-
- delete msg;
- return true;
- }
-
- virtual void SetBackgrounded(bool backgrounded) {
- backgrounded_ = backgrounded;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(VisitRelayingRenderProcessHost);
-};
-
-class VisitedLinkRenderProcessHostFactory
- : public MockRenderProcessHostFactory {
- public:
- VisitedLinkRenderProcessHostFactory()
- : MockRenderProcessHostFactory(),
- relay_mode_(false) {}
- virtual RenderProcessHost* CreateRenderProcessHost(Profile* profile) const {
- if (relay_mode_)
- return new VisitRelayingRenderProcessHost(profile);
- else
- return new VisitCountingRenderProcessHost(profile);
- }
-
- void set_relay_mode(bool mode) { relay_mode_ = mode; }
-
- private:
- bool relay_mode_;
-
- DISALLOW_COPY_AND_ASSIGN(VisitedLinkRenderProcessHostFactory);
-};
-
-class VisitedLinkEventsTest : public RenderViewHostTestHarness {
- public:
- VisitedLinkEventsTest()
- : RenderViewHostTestHarness(),
- file_thread_(BrowserThread::FILE, &message_loop_) {}
- ~VisitedLinkEventsTest() {
- // This ends up using the file thread to schedule the delete.
- profile_.reset();
- message_loop_.RunAllPending();
- }
- virtual void SetFactoryMode() {}
- virtual void SetUp() {
- SetFactoryMode();
- event_listener_.reset(new VisitedLinkEventListener());
- rvh_factory_.set_render_process_host_factory(&vc_rph_factory_);
- profile_.reset(new VisitCountingProfile(event_listener_.get()));
- RenderViewHostTestHarness::SetUp();
- }
-
- VisitCountingProfile* profile() const {
- return static_cast<VisitCountingProfile*>(profile_.get());
- }
-
- void WaitForCoalescense() {
- // Let the timer fire.
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- new MessageLoop::QuitTask(), 110);
- MessageLoop::current()->Run();
- }
-
- protected:
- VisitedLinkRenderProcessHostFactory vc_rph_factory_;
-
- private:
- scoped_ptr<VisitedLinkEventListener> event_listener_;
- BrowserThread file_thread_;
-
- DISALLOW_COPY_AND_ASSIGN(VisitedLinkEventsTest);
-};
-
-class VisitedLinkRelayTest : public VisitedLinkEventsTest {
- public:
- virtual void SetFactoryMode() { vc_rph_factory_.set_relay_mode(true); }
-};
-
-TEST_F(VisitedLinkEventsTest, Coalescense) {
- // add some URLs to master.
- VisitedLinkMaster* master = profile_->GetVisitedLinkMaster();
- // Add a few URLs.
- master->AddURL(GURL("http://acidtests.org/"));
- master->AddURL(GURL("http://google.com/"));
- master->AddURL(GURL("http://chromium.org/"));
- // Just for kicks, add a duplicate URL. This shouldn't increase the resulting
- master->AddURL(GURL("http://acidtests.org/"));
-
- // Make sure that coalescing actually occurs. There should be no links or
- // events received by the renderer.
- EXPECT_EQ(0, profile()->add_count());
- EXPECT_EQ(0, profile()->add_event_count());
-
- WaitForCoalescense();
-
- // We now should have 3 entries added in 1 event.
- EXPECT_EQ(3, profile()->add_count());
- EXPECT_EQ(1, profile()->add_event_count());
-
- // Test whether the coalescing continues by adding a few more URLs.
- master->AddURL(GURL("http://google.com/chrome/"));
- master->AddURL(GURL("http://webkit.org/"));
- master->AddURL(GURL("http://acid3.acidtests.org/"));
-
- WaitForCoalescense();
-
- // We should have 6 entries added in 2 events.
- EXPECT_EQ(6, profile()->add_count());
- EXPECT_EQ(2, profile()->add_event_count());
-
- // Test whether duplicate entries produce add events.
- master->AddURL(GURL("http://acidtests.org/"));
-
- WaitForCoalescense();
-
- // We should have no change in results.
- EXPECT_EQ(6, profile()->add_count());
- EXPECT_EQ(2, profile()->add_event_count());
-
- // Ensure that the coalescing does not resume after resetting.
- master->AddURL(GURL("http://build.chromium.org/"));
- master->DeleteAllURLs();
-
- WaitForCoalescense();
-
- // We should have no change in results except for one new reset event.
- EXPECT_EQ(6, profile()->add_count());
- EXPECT_EQ(2, profile()->add_event_count());
- EXPECT_EQ(1, profile()->reset_event_count());
-}
-
-TEST_F(VisitedLinkRelayTest, Basics) {
- VisitedLinkMaster* master = profile_->GetVisitedLinkMaster();
- rvh()->CreateRenderView(string16());
-
- // Add a few URLs.
- master->AddURL(GURL("http://acidtests.org/"));
- master->AddURL(GURL("http://google.com/"));
- master->AddURL(GURL("http://chromium.org/"));
-
- WaitForCoalescense();
-
- // We now should have 1 add event.
- EXPECT_EQ(1, profile()->add_event_count());
- EXPECT_EQ(0, profile()->reset_event_count());
-
- master->DeleteAllURLs();
-
- WaitForCoalescense();
-
- // We should have no change in add results, plus one new reset event.
- EXPECT_EQ(1, profile()->add_event_count());
- EXPECT_EQ(1, profile()->reset_event_count());
-}
-
-TEST_F(VisitedLinkRelayTest, TabVisibility) {
- VisitedLinkMaster* master = profile_->GetVisitedLinkMaster();
- rvh()->CreateRenderView(string16());
-
- // Simulate tab becoming inactive.
- rvh()->WasHidden();
-
- // Add a few URLs.
- master->AddURL(GURL("http://acidtests.org/"));
- master->AddURL(GURL("http://google.com/"));
- master->AddURL(GURL("http://chromium.org/"));
-
- WaitForCoalescense();
-
- // We shouldn't have any events.
- EXPECT_EQ(0, profile()->add_event_count());
- EXPECT_EQ(0, profile()->reset_event_count());
-
- // Simulate the tab becoming active.
- rvh()->WasRestored();
-
- // We should now have 3 add events, still no reset events.
- EXPECT_EQ(1, profile()->add_event_count());
- EXPECT_EQ(0, profile()->reset_event_count());
-
- // Deactivate the tab again.
- rvh()->WasHidden();
-
- // Add a bunch of URLs (over 50) to exhaust the link event buffer.
- for (int i = 0; i < 100; i++)
- master->AddURL(TestURL(i));
-
- WaitForCoalescense();
-
- // Again, no change in events until tab is active.
- EXPECT_EQ(1, profile()->add_event_count());
- EXPECT_EQ(0, profile()->reset_event_count());
-
- // Activate the tab.
- rvh()->WasRestored();
-
- // We should have only one more reset event.
- EXPECT_EQ(1, profile()->add_event_count());
- EXPECT_EQ(1, profile()->reset_event_count());
-}
-
-TEST_F(VisitedLinkRelayTest, WebViewReadiness) {
- VisitedLinkMaster* master = profile_->GetVisitedLinkMaster();
-
- // Add a few URLs.
- master->AddURL(GURL("http://acidtests.org/"));
- master->AddURL(GURL("http://google.com/"));
- master->AddURL(GURL("http://chromium.org/"));
-
- WaitForCoalescense();
-
- std::set<GURL> deleted_urls;
- deleted_urls.insert(GURL("http://acidtests.org/"));
- master->DeleteURLs(deleted_urls);
-
- // We shouldn't have any events, because RenderView hasn't been created,
- // and we ensure that updates are sent until it is.
- EXPECT_EQ(0, profile()->add_event_count());
- EXPECT_EQ(0, profile()->reset_event_count());
-
- rvh()->CreateRenderView(string16());
-
- // We should now have just a reset event: adds are eaten up by a reset
- // that followed.
- EXPECT_EQ(0, profile()->add_event_count());
- EXPECT_EQ(1, profile()->reset_event_count());
-}
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc
index 79fb3f7..05d6c9f 100644
--- a/chrome/browser/web_applications/web_app.cc
+++ b/chrome/browser/web_applications/web_app.cc
@@ -24,13 +24,12 @@
#include "base/win/windows_version.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/download/download_util.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_plugin_util.h"
#include "chrome/common/notification_registrar.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
#include "chrome/common/web_apps.h"
@@ -40,6 +39,8 @@
#if defined(OS_WIN)
#include "base/win_util.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
#include "gfx/icon_util.h"
#endif // defined(OS_WIN)
diff --git a/chrome/browser/web_resource/web_resource_service.cc b/chrome/browser/web_resource/web_resource_service.cc
index 4076d14..cdee197 100644
--- a/chrome/browser/web_resource/web_resource_service.cc
+++ b/chrome/browser/web_resource/web_resource_service.cc
@@ -13,8 +13,8 @@
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/extensions/extensions_service.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/sync_ui_util.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
@@ -154,7 +154,7 @@ class WebResourceService::UnpackerClient
~UnpackerClient() {}
// UtilityProcessHost::Client
- virtual void OnProcessCrashed() {
+ virtual void OnProcessCrashed(int exit_code) {
if (got_response_)
return;
@@ -499,7 +499,7 @@ bool CanShowPromo(Profile* profile) {
promo_closed = prefs->GetBoolean(prefs::kNTPPromoClosed);
bool has_extensions = false;
- ExtensionsService* extensions_service = profile->GetExtensionsService();
+ ExtensionService* extensions_service = profile->GetExtensionService();
if (extensions_service) {
const ExtensionList* extensions = extensions_service->extensions();
for (ExtensionList::const_iterator iter = extensions->begin();
diff --git a/chrome/browser/webdata/web_data_service_unittest.cc b/chrome/browser/webdata/web_data_service_unittest.cc
index 81f34b4..d56aebf 100644
--- a/chrome/browser/webdata/web_data_service_unittest.cc
+++ b/chrome/browser/webdata/web_data_service_unittest.cc
@@ -21,12 +21,12 @@
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/credit_card.h"
#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/guid.h"
#include "chrome/browser/webdata/autofill_change.h"
#include "chrome/browser/webdata/autofill_entry.h"
#include "chrome/browser/webdata/web_data_service.h"
#include "chrome/browser/webdata/web_data_service_test_util.h"
#include "chrome/common/chrome_paths.h"
+#include "chrome/common/guid.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
diff --git a/chrome/browser/webdata/web_database.cc b/chrome/browser/webdata/web_database.cc
index 1229339..2400c04 100644
--- a/chrome/browser/webdata/web_database.cc
+++ b/chrome/browser/webdata/web_database.cc
@@ -21,11 +21,11 @@
#include "chrome/browser/autofill/autofill_type.h"
#include "chrome/browser/autofill/credit_card.h"
#include "chrome/browser/diagnostics/sqlite_diagnostics.h"
-#include "chrome/browser/guid.h"
#include "chrome/browser/history/history_database.h"
#include "chrome/browser/password_manager/encryptor.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/webdata/autofill_change.h"
+#include "chrome/common/guid.h"
#include "chrome/common/notification_service.h"
#include "gfx/codec/png_codec.h"
#include "third_party/skia/include/core/SkBitmap.h"
diff --git a/chrome/browser/webdata/web_database_unittest.cc b/chrome/browser/webdata/web_database_unittest.cc
index dcae787..dc38100 100644
--- a/chrome/browser/webdata/web_database_unittest.cc
+++ b/chrome/browser/webdata/web_database_unittest.cc
@@ -22,13 +22,13 @@
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/autofill_type.h"
#include "chrome/browser/autofill/credit_card.h"
-#include "chrome/browser/guid.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/password_manager/encryptor.h"
#include "chrome/browser/webdata/autofill_change.h"
#include "chrome/browser/webdata/autofill_entry.h"
#include "chrome/browser/webdata/web_database.h"
#include "chrome/common/chrome_paths.h"
+#include "chrome/common/guid.h"
#include "chrome/test/ui_test_utils.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/window_sizer.cc b/chrome/browser/window_sizer.cc
deleted file mode 100644
index e6c1b57..0000000
--- a/chrome/browser/window_sizer.cc
+++ /dev/null
@@ -1,336 +0,0 @@
-// 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.
-
-#include "chrome/browser/window_sizer.h"
-
-#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_window.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/common/pref_names.h"
-
-///////////////////////////////////////////////////////////////////////////////
-// An implementation of WindowSizer::StateProvider that gets the last active
-// and persistent state from the browser window and the user's profile.
-class DefaultStateProvider : public WindowSizer::StateProvider {
- public:
- explicit DefaultStateProvider(const std::string& app_name, Browser* browser)
- : app_name_(app_name),
- browser_(browser) {
- }
-
- // Overridden from WindowSizer::StateProvider:
- virtual bool GetPersistentState(gfx::Rect* bounds,
- bool* maximized,
- gfx::Rect* work_area) const {
- DCHECK(bounds && maximized);
-
- std::string key(prefs::kBrowserWindowPlacement);
- if (!app_name_.empty()) {
- key.append("_");
- key.append(app_name_);
- }
-
- if (!g_browser_process->local_state())
- return false;
-
- const DictionaryValue* wp_pref =
- g_browser_process->local_state()->GetDictionary(key.c_str());
- int top = 0, left = 0, bottom = 0, right = 0;
- bool has_prefs =
- wp_pref &&
- wp_pref->GetInteger("top", &top) &&
- wp_pref->GetInteger("left", &left) &&
- wp_pref->GetInteger("bottom", &bottom) &&
- wp_pref->GetInteger("right", &right) &&
- wp_pref->GetBoolean("maximized", maximized);
- bounds->SetRect(left, top, std::max(0, right - left),
- std::max(0, bottom - top));
-
- int work_area_top = 0;
- int work_area_left = 0;
- int work_area_bottom = 0;
- int work_area_right = 0;
- if (wp_pref) {
- wp_pref->GetInteger("work_area_top", &work_area_top);
- wp_pref->GetInteger("work_area_left", &work_area_left);
- wp_pref->GetInteger("work_area_bottom", &work_area_bottom);
- wp_pref->GetInteger("work_area_right", &work_area_right);
- }
- work_area->SetRect(work_area_left, work_area_top,
- std::max(0, work_area_right - work_area_left),
- std::max(0, work_area_bottom - work_area_top));
-
- return has_prefs;
- }
-
- virtual bool GetLastActiveWindowState(gfx::Rect* bounds) const {
- // Applications are always restored with the same position.
- if (!app_name_.empty())
- return false;
-
- // If a reference browser is set, use its window. Otherwise find last
- // active.
- BrowserWindow* window = NULL;
- if (browser_) {
- window = browser_->window();
- DCHECK(window);
- } else {
- BrowserList::const_reverse_iterator it = BrowserList::begin_last_active();
- BrowserList::const_reverse_iterator end = BrowserList::end_last_active();
- for (; (it != end); ++it) {
- Browser* last_active = *it;
- if (last_active && last_active->type() == Browser::TYPE_NORMAL) {
- window = last_active->window();
- DCHECK(window);
- break;
- }
- }
- }
-
- if (window) {
- *bounds = window->GetRestoredBounds();
- return true;
- }
-
- return false;
- }
-
- private:
- std::string app_name_;
-
- // If set, is used as the reference browser for GetLastActiveWindowState.
- Browser* browser_;
- DISALLOW_COPY_AND_ASSIGN(DefaultStateProvider);
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// MonitorInfoProvider, public:
-
-WindowSizer::MonitorInfoProvider::MonitorInfoProvider() {}
-
-WindowSizer::MonitorInfoProvider::~MonitorInfoProvider() {}
-
-///////////////////////////////////////////////////////////////////////////////
-// WindowSizer, public:
-
-WindowSizer::WindowSizer(
- StateProvider* state_provider,
- MonitorInfoProvider* monitor_info_provider) {
- Init(state_provider, monitor_info_provider);
-}
-
-WindowSizer::~WindowSizer() {
- if (state_provider_)
- delete state_provider_;
- if (monitor_info_provider_)
- delete monitor_info_provider_;
-}
-
-// static
-void WindowSizer::GetBrowserWindowBounds(const std::string& app_name,
- const gfx::Rect& specified_bounds,
- Browser* browser,
- gfx::Rect* window_bounds,
- bool* maximized) {
- const WindowSizer sizer(new DefaultStateProvider(app_name, browser),
- CreateDefaultMonitorInfoProvider());
- sizer.DetermineWindowBounds(specified_bounds, window_bounds, maximized);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// WindowSizer, private:
-
-WindowSizer::WindowSizer(const std::string& app_name) {
- Init(new DefaultStateProvider(app_name, NULL),
- CreateDefaultMonitorInfoProvider());
-}
-
-void WindowSizer::Init(StateProvider* state_provider,
- MonitorInfoProvider* monitor_info_provider) {
- state_provider_ = state_provider;
- monitor_info_provider_ = monitor_info_provider;
-}
-
-void WindowSizer::DetermineWindowBounds(const gfx::Rect& specified_bounds,
- gfx::Rect* bounds,
- bool* maximized) const {
- *bounds = specified_bounds;
- if (bounds->IsEmpty()) {
- // See if there's saved placement information.
- if (!GetLastWindowBounds(bounds)) {
- if (!GetSavedWindowBounds(bounds, maximized)) {
- // No saved placement, figure out some sensible default size based on
- // the user's screen size.
- GetDefaultWindowBounds(bounds);
- }
- }
- }
-}
-
-bool WindowSizer::GetLastWindowBounds(gfx::Rect* bounds) const {
- DCHECK(bounds);
- if (!state_provider_ || !state_provider_->GetLastActiveWindowState(bounds))
- return false;
- gfx::Rect last_window_bounds = *bounds;
- bounds->Offset(kWindowTilePixels, kWindowTilePixels);
- AdjustBoundsToBeVisibleOnMonitorContaining(last_window_bounds,
- gfx::Rect(),
- bounds);
- return true;
-}
-
-bool WindowSizer::GetSavedWindowBounds(gfx::Rect* bounds,
- bool* maximized) const {
- DCHECK(bounds && maximized);
- gfx::Rect saved_work_area;
- if (!state_provider_ ||
- !state_provider_->GetPersistentState(bounds, maximized, &saved_work_area))
- return false;
- AdjustBoundsToBeVisibleOnMonitorContaining(*bounds, saved_work_area, bounds);
- return true;
-}
-
-void WindowSizer::GetDefaultWindowBounds(gfx::Rect* default_bounds) const {
- DCHECK(default_bounds);
- DCHECK(monitor_info_provider_);
-
- gfx::Rect work_area = monitor_info_provider_->GetPrimaryMonitorWorkArea();
-
- // The default size is either some reasonably wide width, or if the work
- // area is narrower, then the work area width less some aesthetic padding.
- int default_width = std::min(work_area.width() - 2 * kWindowTilePixels, 1050);
- int default_height = work_area.height() - 2 * kWindowTilePixels;
-
- // For wider aspect ratio displays at higher resolutions, we might size the
- // window narrower to allow two windows to easily be placed side-by-side.
- gfx::Rect screen_size = monitor_info_provider_->GetPrimaryMonitorBounds();
- double width_to_height =
- static_cast<double>(screen_size.width()) / screen_size.height();
-
- // The least wide a screen can be to qualify for the halving described above.
- static const int kMinScreenWidthForWindowHalving = 1600;
- // We assume 16:9/10 is a fairly standard indicator of a wide aspect ratio
- // computer display.
- if (((width_to_height * 10) >= 16) &&
- work_area.width() > kMinScreenWidthForWindowHalving) {
- // Halve the work area, subtracting aesthetic padding on either side.
- // The padding is set so that two windows, side by side have
- // kWindowTilePixels between screen edge and each other.
- default_width = static_cast<int>(work_area.width() / 2. -
- 1.5 * kWindowTilePixels);
- }
- default_bounds->SetRect(kWindowTilePixels + work_area.x(),
- kWindowTilePixels + work_area.y(),
- default_width, default_height);
-}
-
-bool WindowSizer::PositionIsOffscreen(int position, Edge edge) const {
- DCHECK(monitor_info_provider_);
- size_t monitor_count = monitor_info_provider_->GetMonitorCount();
- for (size_t i = 0; i < monitor_count; ++i) {
- gfx::Rect work_area = monitor_info_provider_->GetWorkAreaAt(i);
- switch (edge) {
- case TOP:
- if (position >= work_area.y())
- return false;
- break;
- case LEFT:
- if (position >= work_area.x())
- return false;
- break;
- case BOTTOM:
- if (position <= work_area.bottom())
- return false;
- break;
- case RIGHT:
- if (position <= work_area.right())
- return false;
- break;
- }
- }
- return true;
-}
-
-namespace {
- // Minimum height of the visible part of a window.
- static const int kMinVisibleHeight = 30;
- // Minimum width of the visible part of a window.
- static const int kMinVisibleWidth = 30;
-}
-
-void WindowSizer::AdjustBoundsToBeVisibleOnMonitorContaining(
- const gfx::Rect& other_bounds,
- const gfx::Rect& saved_work_area,
- gfx::Rect* bounds) const {
- DCHECK(bounds);
- DCHECK(monitor_info_provider_);
-
- // Find the size of the work area of the monitor that intersects the bounds
- // of the anchor window.
- gfx::Rect work_area =
- monitor_info_provider_->GetMonitorWorkAreaMatching(other_bounds);
-
- // If height or width are 0, reset to the default size.
- gfx::Rect default_bounds;
- GetDefaultWindowBounds(&default_bounds);
- if (bounds->height() <= 0)
- bounds->set_height(default_bounds.height());
- if (bounds->width() <= 0)
- bounds->set_width(default_bounds.width());
-
- // Ensure the minimum height and width.
- bounds->set_height(std::max(kMinVisibleHeight, bounds->height()));
- bounds->set_width(std::max(kMinVisibleWidth, bounds->width()));
-
- // Ensure that the title bar is not above the work area.
- if (bounds->y() < work_area.y())
- bounds->set_y(work_area.y());
-
- // Reposition and resize the bounds if the saved_work_area is different from
- // the current work area and the current work area doesn't completely contain
- // the bounds.
- if (!saved_work_area.IsEmpty() &&
- saved_work_area != work_area &&
- !work_area.Contains(*bounds)) {
- bounds->set_width(std::min(bounds->width(), work_area.width()));
- bounds->set_height(std::min(bounds->height(), work_area.height()));
- bounds->set_x(
- std::max(work_area.x(),
- std::min(bounds->x(), work_area.right() - bounds->width())));
- bounds->set_y(
- std::max(work_area.y(),
- std::min(bounds->y(), work_area.bottom() - bounds->height())));
- }
-
-#if defined(OS_MACOSX)
- // Limit the maximum height. On the Mac the sizer is on the
- // bottom-right of the window, and a window cannot be moved "up"
- // past the menubar. If the window is too tall you'll never be able
- // to shrink it again. Windows does not have this limitation
- // (e.g. can be resized from the top).
- bounds->set_height(std::min(work_area.height(), bounds->height()));
-
- // On mac, we want to be aggressive about repositioning windows that are
- // partially offscreen. If the window is partially offscreen horizontally,
- // move it to be flush with the left edge of the work area.
- if (bounds->x() < work_area.x() || bounds->right() > work_area.right())
- bounds->set_x(work_area.x());
-
- // If the window is partially offscreen vertically, move it to be flush with
- // the top of the work area.
- if (bounds->y() < work_area.y() || bounds->bottom() > work_area.bottom())
- bounds->set_y(work_area.y());
-#else
- // On non-Mac platforms, we are less aggressive about repositioning. Simply
- // ensure that at least kMinVisibleWidth * kMinVisibleHeight is visible.
- const int min_y = work_area.y() + kMinVisibleHeight - bounds->height();
- const int min_x = work_area.x() + kMinVisibleWidth - bounds->width();
- const int max_y = work_area.bottom() - kMinVisibleHeight;
- const int max_x = work_area.right() - kMinVisibleWidth;
- bounds->set_y(std::max(min_y, std::min(max_y, bounds->y())));
- bounds->set_x(std::max(min_x, std::min(max_x, bounds->x())));
-#endif // defined(OS_MACOSX)
-}
diff --git a/chrome/browser/window_sizer.h b/chrome/browser/window_sizer.h
deleted file mode 100644
index d200d36..0000000
--- a/chrome/browser/window_sizer.h
+++ /dev/null
@@ -1,184 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_WINDOW_SIZER_H_
-#define CHROME_BROWSER_WINDOW_SIZER_H_
-#pragma once
-
-#include <vector>
-
-#include "base/basictypes.h"
-#include "gfx/rect.h"
-
-class Browser;
-
-///////////////////////////////////////////////////////////////////////////////
-// WindowSizer
-//
-// A class that determines the best new size and position for a window to be
-// shown at based several factors, including the position and size of the last
-// window of the same type, the last saved bounds of the window from the
-// previous session, and default system metrics if neither of the above two
-// conditions exist. The system has built-in providers for monitor metrics
-// and persistent storage (using preferences) but can be overrided with mocks
-// for testing.
-//
-class WindowSizer {
- public:
- class MonitorInfoProvider;
- class StateProvider;
-
- // The WindowSizer assumes ownership of these objects.
- WindowSizer(StateProvider* state_provider,
- MonitorInfoProvider* monitor_info_provider);
- virtual ~WindowSizer();
-
- // Static factory methods to create default MonitorInfoProvider
- // instances. The returned object is owned by the caller.
- static MonitorInfoProvider* CreateDefaultMonitorInfoProvider();
-
- // An interface implemented by an object that can retrieve information about
- // the monitors on the system.
- class MonitorInfoProvider {
- public:
- MonitorInfoProvider();
- virtual ~MonitorInfoProvider();
-
- // Returns the bounds of the work area of the primary monitor.
- virtual gfx::Rect GetPrimaryMonitorWorkArea() const = 0;
-
- // Returns the bounds of the primary monitor.
- virtual gfx::Rect GetPrimaryMonitorBounds() const = 0;
-
- // Returns the bounds of the work area of the monitor that most closely
- // intersects the provided bounds.
- virtual gfx::Rect GetMonitorWorkAreaMatching(
- const gfx::Rect& match_rect) const = 0;
-
- // Returns the delta between the work area and the monitor bounds for the
- // monitor that most closely intersects the provided bounds.
- virtual gfx::Point GetBoundsOffsetMatching(
- const gfx::Rect& match_rect) const = 0;
-
- // Ensures number and coordinates of work areas are up-to-date. You must
- // call this before calling either of the below functions, as work areas can
- // change while the program is running.
- virtual void UpdateWorkAreas() = 0;
-
- // Returns the number of monitors on the system.
- size_t GetMonitorCount() const {
- return work_areas_.size();
- }
-
- // Returns the bounds of the work area of the monitor at the specified
- // index.
- gfx::Rect GetWorkAreaAt(size_t index) const {
- return work_areas_[index];
- }
-
- protected:
- std::vector<gfx::Rect> work_areas_;
- };
-
- // An interface implemented by an object that can retrieve state from either a
- // persistent store or an existing window.
- class StateProvider {
- public:
- virtual ~StateProvider() { }
-
- // Retrieve the persisted bounds of the window. Returns true if there was
- // persisted data to retrieve state information, false otherwise.
- virtual bool GetPersistentState(gfx::Rect* bounds,
- bool* maximized,
- gfx::Rect* work_area) const = 0;
-
- // Retrieve the bounds of the most recent window of the matching type.
- // Returns true if there was a last active window to retrieve state
- // information from, false otherwise.
- virtual bool GetLastActiveWindowState(gfx::Rect* bounds) const = 0;
- };
-
- // Determines the position, size and maximized state for a window as it is
- // created. This function uses several strategies to figure out optimal size
- // and placement, first looking for an existing active window, then falling
- // back to persisted data from a previous session, finally utilizing a default
- // algorithm. If |specified_bounds| are non-empty, this value is returned
- // instead. For use only in testing.
- //
- // NOTE: |maximized| is only set if we're restoring a saved maximized window.
- // When creating a new window based on an existing active window, standard
- // Windows behavior is to have it always be nonmaximized, even if the existing
- // window is maximized.
- void DetermineWindowBounds(const gfx::Rect& specified_bounds,
- gfx::Rect* bounds,
- bool* maximized) const;
-
- // Determines the size, position and maximized state for the browser window.
- // See documentation for DetermineWindowBounds above. Normally,
- // |window_bounds| is calculated by calling GetLastActiveWindowState(). To
- // explicitly specify a particular window to base the bounds on, pass in a
- // non-NULL value for |browser|.
- static void GetBrowserWindowBounds(const std::string& app_name,
- const gfx::Rect& specified_bounds,
- Browser* browser,
- gfx::Rect* window_bounds,
- bool* maximized);
-
- // Returns the default origin for popups of the given size.
- static gfx::Point GetDefaultPopupOrigin(const gfx::Size& size);
-
- // How much horizontal and vertical offset there is between newly
- // opened windows. This value may be different on each platform.
- static const int kWindowTilePixels;
-
- private:
- // The edge of the screen to check for out-of-bounds.
- enum Edge { TOP, LEFT, BOTTOM, RIGHT };
-
- explicit WindowSizer(const std::string& app_name);
-
- void Init(StateProvider* state_provider,
- MonitorInfoProvider* monitor_info_provider);
-
- // Gets the size and placement of the last window. Returns true if this data
- // is valid, false if there is no last window and the application should
- // restore saved state from preferences using RestoreWindowPosition.
- bool GetLastWindowBounds(gfx::Rect* bounds) const;
-
- // Gets the size and placement of the last window in the last session, saved
- // in local state preferences. Returns true if local state exists containing
- // this information, false if this information does not exist and a default
- // size should be used.
- bool GetSavedWindowBounds(gfx::Rect* bounds, bool* maximized) const;
-
- // Gets the default window position and size if there is no last window and
- // no saved window placement in prefs. This function determines the default
- // size based on monitor size, etc.
- void GetDefaultWindowBounds(gfx::Rect* default_bounds) const;
-
- // Returns true if the specified position is "offscreen" for the given edge,
- // meaning that it's outside all work areas in the direction of that edge.
- bool PositionIsOffscreen(int position, Edge edge) const;
-
- // Adjusts |bounds| to be visible onscreen, biased toward the work area of the
- // monitor containing |other_bounds|. Despite the name, this doesn't
- // guarantee the bounds are fully contained within this monitor's work rect;
- // it just tried to ensure the edges are visible on _some_ work rect.
- // If |saved_work_area| is non-empty, it is used to determine whether the
- // monitor cofiguration has changed. If it has, bounds are repositioned and
- // resized if necessary to make them completely contained in the current work
- // area.
- void AdjustBoundsToBeVisibleOnMonitorContaining(
- const gfx::Rect& other_bounds,
- const gfx::Rect& saved_work_area,
- gfx::Rect* bounds) const;
-
- // Providers for persistent storage and monitor metrics.
- StateProvider* state_provider_;
- MonitorInfoProvider* monitor_info_provider_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowSizer);
-};
-
-#endif // CHROME_BROWSER_WINDOW_SIZER_H_
diff --git a/chrome/browser/window_sizer_linux.cc b/chrome/browser/window_sizer_linux.cc
deleted file mode 100644
index 778a557..0000000
--- a/chrome/browser/window_sizer_linux.cc
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/window_sizer.h"
-
-#include <gtk/gtk.h>
-
-#include "base/logging.h"
-#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_window.h"
-#include "chrome/browser/ui/browser.h"
-
-// Used to pad the default new window size. On Windows, this is also used for
-// positioning new windows (each window is offset from the previous one).
-// Since we don't position windows, it's only used for the default new window
-// size.
-const int WindowSizer::kWindowTilePixels = 10;
-
-// An implementation of WindowSizer::MonitorInfoProvider that gets the actual
-// monitor information from X via GDK.
-class DefaultMonitorInfoProvider : public WindowSizer::MonitorInfoProvider {
- public:
- DefaultMonitorInfoProvider() { }
-
- virtual gfx::Rect GetPrimaryMonitorWorkArea() const {
- gfx::Rect rect;
- if (GetScreenWorkArea(&rect))
- return rect.Intersect(GetPrimaryMonitorBounds());
-
- // Return the best we've got.
- return GetPrimaryMonitorBounds();
- }
-
- virtual gfx::Rect GetPrimaryMonitorBounds() const {
- GdkScreen* screen = gdk_screen_get_default();
- GdkRectangle rect;
- gdk_screen_get_monitor_geometry(screen, 0, &rect);
- return gfx::Rect(rect);
- }
-
- virtual gfx::Rect GetMonitorWorkAreaMatching(
- const gfx::Rect& match_rect) const {
- // TODO(thestig) Implement multi-monitor support.
- return GetPrimaryMonitorWorkArea();
- }
-
- virtual gfx::Point GetBoundsOffsetMatching(
- const gfx::Rect& match_rect) const {
- // TODO(thestig) Implement multi-monitor support.
- return GetPrimaryMonitorWorkArea().origin();
- }
-
- void UpdateWorkAreas() {
- // TODO(thestig) Implement multi-monitor support.
- work_areas_.clear();
- work_areas_.push_back(GetPrimaryMonitorBounds());
- }
-
- private:
- // Get the available screen space as a gfx::Rect, or return false if
- // if it's unavailable (i.e. the window manager doesn't support
- // retrieving this).
- // TODO(thestig) Use _NET_CURRENT_DESKTOP here as well?
- bool GetScreenWorkArea(gfx::Rect* out_rect) const {
- gboolean ok;
- guchar* raw_data = NULL;
- gint data_len = 0;
- ok = gdk_property_get(gdk_get_default_root_window(), // a gdk window
- gdk_atom_intern("_NET_WORKAREA", FALSE), // property
- gdk_atom_intern("CARDINAL", FALSE), // property type
- 0, // byte offset into property
- 0xff, // property length to retrieve
- false, // delete property after retrieval?
- NULL, // returned property type
- NULL, // returned data format
- &data_len, // returned data len
- &raw_data); // returned data
- if (!ok)
- return false;
-
- // We expect to get four longs back: x, y, width, height.
- if (data_len < static_cast<gint>(4 * sizeof(glong))) {
- NOTREACHED();
- g_free(raw_data);
- return false;
- }
-
- glong* data = reinterpret_cast<glong*>(raw_data);
- gint x = data[0];
- gint y = data[1];
- gint width = data[2];
- gint height = data[3];
- g_free(raw_data);
-
- out_rect->SetRect(x, y, width, height);
- return true;
- }
-
- DISALLOW_COPY_AND_ASSIGN(DefaultMonitorInfoProvider);
-};
-
-// static
-WindowSizer::MonitorInfoProvider*
-WindowSizer::CreateDefaultMonitorInfoProvider() {
- return new DefaultMonitorInfoProvider();
-}
-
-// static
-gfx::Point WindowSizer::GetDefaultPopupOrigin(const gfx::Size& size) {
- scoped_ptr<MonitorInfoProvider> provider(CreateDefaultMonitorInfoProvider());
- gfx::Rect monitor_bounds = provider->GetPrimaryMonitorWorkArea();
- gfx::Point corner(monitor_bounds.x(), monitor_bounds.y());
- if (Browser* browser = BrowserList::GetLastActive()) {
- GtkWindow* window =
- reinterpret_cast<GtkWindow*>(browser->window()->GetNativeHandle());
- int x = 0, y = 0;
- gtk_window_get_position(window, &x, &y);
- // Limit to not overflow the work area right and bottom edges.
- gfx::Point limit(
- std::min(x + kWindowTilePixels, monitor_bounds.right() - size.width()),
- std::min(y + kWindowTilePixels,
- monitor_bounds.bottom() - size.height()));
- // Adjust corner to now overflow the work area left and top edges, so
- // that if a popup does not fit the title-bar is remains visible.
- corner = gfx::Point(
- std::max(corner.x(), limit.x()),
- std::max(corner.y(), limit.y()));
- }
- return corner;
-}
diff --git a/chrome/browser/window_sizer_mac.mm b/chrome/browser/window_sizer_mac.mm
deleted file mode 100644
index c303cc4..0000000
--- a/chrome/browser/window_sizer_mac.mm
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_list.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/window_sizer.h"
-
-
-// How much horizontal and vertical offset there is between newly
-// opened windows.
-const int WindowSizer::kWindowTilePixels = 22;
-
-namespace {
-
-class DefaultMonitorInfoProvider : public WindowSizer::MonitorInfoProvider {
- public:
- DefaultMonitorInfoProvider() { }
-
- // Overridden from WindowSizer::MonitorInfoProvider:
- virtual gfx::Rect GetPrimaryMonitorWorkArea() const {
- // Primary monitor is defined as the monitor with the menubar,
- // which is always at index 0.
- NSScreen* primary = [[NSScreen screens] objectAtIndex:0];
- NSRect frame = [primary frame];
- NSRect visible_frame = [primary visibleFrame];
-
- // Convert coordinate systems.
- gfx::Rect rect = gfx::Rect(NSRectToCGRect(visible_frame));
- rect.set_y(frame.size.height -
- visible_frame.origin.y - visible_frame.size.height);
- return rect;
- }
-
- virtual gfx::Rect GetPrimaryMonitorBounds() const {
- // Primary monitor is defined as the monitor with the menubar,
- // which is always at index 0.
- NSScreen* primary = [[NSScreen screens] objectAtIndex:0];
- return gfx::Rect(NSRectToCGRect([primary frame]));
- }
-
- virtual gfx::Rect GetMonitorWorkAreaMatching(
- const gfx::Rect& match_rect) const {
- NSScreen* match_screen = GetMatchingScreen(match_rect);
- return ConvertCoordinateSystem([match_screen visibleFrame]);
- }
-
- virtual gfx::Point GetBoundsOffsetMatching(
- const gfx::Rect& match_rect) const {
- NSScreen* match_screen = GetMatchingScreen(match_rect);
- gfx::Rect bounds = ConvertCoordinateSystem([match_screen frame]);
- gfx::Rect work_area = ConvertCoordinateSystem([match_screen visibleFrame]);
- return gfx::Point(work_area.x() - bounds.x(), work_area.y() - bounds.y());
- }
-
- virtual void UpdateWorkAreas();
-
- private:
- // Returns a pointer to the screen that most closely matches the
- // given |match_rect|. This function currently returns the screen
- // that contains the largest amount of |match_rect| by area.
- NSScreen* GetMatchingScreen(const gfx::Rect& match_rect) const {
- // Default to the monitor with the current keyboard focus, in case
- // |match_rect| is not on any screen at all.
- NSScreen* max_screen = [NSScreen mainScreen];
- int max_area = 0;
-
- for (NSScreen* screen in [NSScreen screens]) {
- gfx::Rect monitor_area = ConvertCoordinateSystem([screen frame]);
- gfx::Rect intersection = monitor_area.Intersect(match_rect);
- int area = intersection.width() * intersection.height();
- if (area > max_area) {
- max_area = area;
- max_screen = screen;
- }
- }
-
- return max_screen;
- }
-
- // The lower left corner of screen 0 is always at (0, 0). The
- // cross-platform code expects the origin to be in the upper left,
- // so we have to translate |ns_rect| to the new coordinate
- // system.
- gfx::Rect ConvertCoordinateSystem(NSRect ns_rect) const;
-
- DISALLOW_COPY_AND_ASSIGN(DefaultMonitorInfoProvider);
-};
-
-void DefaultMonitorInfoProvider::UpdateWorkAreas() {
- work_areas_.clear();
-
- for (NSScreen* screen in [NSScreen screens]) {
- gfx::Rect rect = ConvertCoordinateSystem([screen visibleFrame]);
- work_areas_.push_back(rect);
- }
-}
-
-gfx::Rect DefaultMonitorInfoProvider::ConvertCoordinateSystem(
- NSRect ns_rect) const {
- // Primary monitor is defined as the monitor with the menubar,
- // which is always at index 0.
- NSScreen* primary_screen = [[NSScreen screens] objectAtIndex:0];
- float primary_screen_height = [primary_screen frame].size.height;
- gfx::Rect rect(NSRectToCGRect(ns_rect));
- rect.set_y(primary_screen_height - rect.y() - rect.height());
- return rect;
-}
-
-} // namespace
-
-// static
-WindowSizer::MonitorInfoProvider*
-WindowSizer::CreateDefaultMonitorInfoProvider() {
- return new DefaultMonitorInfoProvider();
-}
-
-// static
-gfx::Point WindowSizer::GetDefaultPopupOrigin(const gfx::Size& size) {
- NSRect work_area = [[NSScreen mainScreen] visibleFrame];
- NSRect main_area = [[[NSScreen screens] objectAtIndex:0] frame];
- NSPoint corner = NSMakePoint(NSMinX(work_area), NSMaxY(work_area));
-
- if (Browser* b = BrowserList::GetLastActive()) {
- NSWindow* window = b->window()->GetNativeHandle();
- NSRect window_frame = [window frame];
-
- // Limit to not overflow the work area right and bottom edges.
- NSPoint limit = NSMakePoint(
- std::min(NSMinX(window_frame) + kWindowTilePixels,
- NSMaxX(work_area) - size.width()),
- std::max(NSMaxY(window_frame) - kWindowTilePixels,
- NSMinY(work_area) + size.height()));
-
- // Adjust corner to now overflow the work area left and top edges, so
- // that if a popup does not fit the title-bar is remains visible.
- corner = NSMakePoint(std::max(corner.x, limit.x),
- std::min(corner.y, limit.y));
- }
-
- return gfx::Point(corner.x, NSHeight(main_area) - corner.y);
-}
diff --git a/chrome/browser/window_sizer_unittest.cc b/chrome/browser/window_sizer_unittest.cc
deleted file mode 100644
index 622d114..0000000
--- a/chrome/browser/window_sizer_unittest.cc
+++ /dev/null
@@ -1,1002 +0,0 @@
-// 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.
-
-#include <vector>
-
-#include "chrome/browser/window_sizer.h"
-#include "base/logging.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-// Some standard monitor sizes (no task bar).
-static const gfx::Rect tentwentyfour(0, 0, 1024, 768);
-static const gfx::Rect twelveeighty(0, 0, 1280, 1024);
-static const gfx::Rect sixteenhundred(0, 0, 1600, 1200);
-static const gfx::Rect sixteeneighty(0, 0, 1680, 1050);
-static const gfx::Rect nineteentwenty(0, 0, 1920, 1200);
-
-// Represents a 1024x768 monitor that is not the primary monitor, arranged to
-// the immediate left of the primary 1024x768 monitor.
-static const gfx::Rect left_nonprimary(-1024, 0, 1024, 768);
-
-// Represents a 1024x768 monitor that is not the primary monitor, arranged to
-// the immediate right of the primary 1024x768 monitor.
-static const gfx::Rect right_nonprimary(1024, 0, 1024, 768);
-
-// Represents a 1024x768 monitor that is not the primary monitor, arranged to
-// the immediate top of the primary 1024x768 monitor.
-static const gfx::Rect top_nonprimary(0, -768, 1024, 768);
-
-// Represents a 1024x768 monitor that is not the primary monitor, arranged to
-// the immediate bottom of the primary 1024x768 monitor.
-static const gfx::Rect bottom_nonprimary(0, 768, 1024, 768);
-
-// The work area for 1024x768 monitors with different taskbar orientations.
-static const gfx::Rect taskbar_bottom_work_area(0, 0, 1024, 734);
-static const gfx::Rect taskbar_top_work_area(0, 34, 1024, 734);
-static const gfx::Rect taskbar_left_work_area(107, 0, 917, 768);
-static const gfx::Rect taskbar_right_work_area(0, 0, 917, 768);
-
-static int kWindowTilePixels = WindowSizer::kWindowTilePixels;
-
-// Testing implementation of WindowSizer::MonitorInfoProvider that we can use
-// to fake various monitor layouts and sizes.
-class TestMonitorInfoProvider : public WindowSizer::MonitorInfoProvider {
- public:
- TestMonitorInfoProvider() {}
- virtual ~TestMonitorInfoProvider() {}
-
- void AddMonitor(const gfx::Rect& bounds, const gfx::Rect& work_area) {
- DCHECK(bounds.Contains(work_area));
- monitor_bounds_.push_back(bounds);
- work_areas_.push_back(work_area);
- }
-
- // Overridden from WindowSizer::MonitorInfoProvider:
- virtual gfx::Rect GetPrimaryMonitorWorkArea() const {
- return work_areas_[0];
- }
-
- virtual gfx::Rect GetPrimaryMonitorBounds() const {
- return monitor_bounds_[0];
- }
-
- virtual gfx::Rect GetMonitorWorkAreaMatching(
- const gfx::Rect& match_rect) const {
- return work_areas_[GetMonitorIndexMatchingBounds(match_rect)];
- }
-
- virtual gfx::Point GetBoundsOffsetMatching(
- const gfx::Rect& match_rect) const {
- int monitor_index = GetMonitorIndexMatchingBounds(match_rect);
- gfx::Rect bounds = monitor_bounds_[monitor_index];
- const gfx::Rect& work_area = work_areas_[monitor_index];
- return gfx::Point(work_area.x() - bounds.x(), work_area.y() - bounds.y());
- }
-
- virtual void UpdateWorkAreas() { }
-
- private:
- size_t GetMonitorIndexMatchingBounds(const gfx::Rect& match_rect) const {
- int max_area = 0;
- size_t max_area_index = 0;
- // Loop through all the monitors, finding the one that intersects the
- // largest area of the supplied match rect.
- for (size_t i = 0; i < work_areas_.size(); ++i) {
- gfx::Rect overlap(match_rect.Intersect(work_areas_[i]));
- int area = overlap.width() * overlap.height();
- if (area > max_area) {
- max_area = area;
- max_area_index = i;
- }
- }
- return max_area_index;
- }
-
- std::vector<gfx::Rect> monitor_bounds_;
-
- DISALLOW_COPY_AND_ASSIGN(TestMonitorInfoProvider);
-};
-
-// Testing implementation of WindowSizer::StateProvider that we use to fake
-// persistent storage and existing windows.
-class TestStateProvider : public WindowSizer::StateProvider {
- public:
- TestStateProvider()
- : persistent_maximized_(false),
- has_persistent_data_(false),
- has_last_active_data_(false) {
- }
- virtual ~TestStateProvider() {}
-
- void SetPersistentState(const gfx::Rect& bounds,
- bool maximized,
- const gfx::Rect& work_area,
- bool has_persistent_data) {
- persistent_bounds_ = bounds;
- persistent_maximized_ = maximized;
- persistent_work_area_ = work_area;
- has_persistent_data_ = has_persistent_data;
- }
-
- void SetLastActiveState(const gfx::Rect& bounds, bool has_last_active_data) {
- last_active_bounds_ = bounds;
- has_last_active_data_ = has_last_active_data;
- }
-
- // Overridden from WindowSizer::StateProvider:
- virtual bool GetPersistentState(gfx::Rect* bounds,
- bool* maximized,
- gfx::Rect* saved_work_area) const {
- *bounds = persistent_bounds_;
- *maximized = persistent_maximized_;
- *saved_work_area = persistent_work_area_;
- return has_persistent_data_;
- }
-
- virtual bool GetLastActiveWindowState(gfx::Rect* bounds) const {
- *bounds = last_active_bounds_;
- return has_last_active_data_;
- }
-
- private:
- gfx::Rect persistent_bounds_;
- bool persistent_maximized_;
- gfx::Rect persistent_work_area_;
- bool has_persistent_data_;
-
- gfx::Rect last_active_bounds_;
- bool has_last_active_data_;
-
- DISALLOW_COPY_AND_ASSIGN(TestStateProvider);
-};
-
-// A convenience function to read the window bounds from the window sizer
-// according to the specified configuration.
-enum Source { DEFAULT, LAST_ACTIVE, PERSISTED };
-static void GetWindowBounds(const gfx::Rect& monitor1_bounds,
- const gfx::Rect& monitor1_work_area,
- const gfx::Rect& monitor2_bounds,
- const gfx::Rect& state,
- bool maximized,
- const gfx::Rect& work_area,
- Source source,
- gfx::Rect* out_bounds,
- bool* out_maximized) {
- TestMonitorInfoProvider* mip = new TestMonitorInfoProvider;
- mip->AddMonitor(monitor1_bounds, monitor1_work_area);
- if (!monitor2_bounds.IsEmpty())
- mip->AddMonitor(monitor2_bounds, monitor2_bounds);
- TestStateProvider* sp = new TestStateProvider;
- if (source == PERSISTED)
- sp->SetPersistentState(state, maximized, work_area, true);
- else if (source == LAST_ACTIVE)
- sp->SetLastActiveState(state, true);
- WindowSizer sizer(sp, mip);
- sizer.DetermineWindowBounds(gfx::Rect(), out_bounds, out_maximized);
-}
-
-// Test that the window is sized appropriately for the first run experience
-// where the default window bounds calculation is invoked.
-TEST(WindowSizerTest, DefaultSizeCase) {
- { // 4:3 monitor case, 1024x768, no taskbar
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(), gfx::Rect(),
- false, gfx::Rect(), DEFAULT, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(kWindowTilePixels, kWindowTilePixels,
- 1024 - kWindowTilePixels * 2,
- 768 - kWindowTilePixels * 2),
- window_bounds);
- }
-
- { // 4:3 monitor case, 1024x768, taskbar on bottom
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, taskbar_bottom_work_area, gfx::Rect(),
- gfx::Rect(), false, gfx::Rect(), DEFAULT, &window_bounds,
- &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(kWindowTilePixels, kWindowTilePixels,
- 1024 - kWindowTilePixels * 2,
- (taskbar_bottom_work_area.height() -
- kWindowTilePixels * 2)),
- window_bounds);
- }
-
- { // 4:3 monitor case, 1024x768, taskbar on right
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, taskbar_right_work_area, gfx::Rect(),
- gfx::Rect(), false, gfx::Rect(), DEFAULT, &window_bounds,
- &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(kWindowTilePixels, kWindowTilePixels,
- taskbar_right_work_area.width() - kWindowTilePixels*2,
- 768 - kWindowTilePixels * 2),
- window_bounds);
- }
-
- { // 4:3 monitor case, 1024x768, taskbar on left
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, taskbar_left_work_area, gfx::Rect(),
- gfx::Rect(), false, gfx::Rect(), DEFAULT, &window_bounds,
- &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(taskbar_left_work_area.x() + kWindowTilePixels,
- kWindowTilePixels,
- taskbar_left_work_area.width() - kWindowTilePixels * 2,
- (taskbar_left_work_area.height() -
- kWindowTilePixels * 2)),
- window_bounds);
- }
-
- { // 4:3 monitor case, 1024x768, taskbar on top
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, taskbar_top_work_area, gfx::Rect(),
- gfx::Rect(), false, gfx::Rect(), DEFAULT, &window_bounds,
- &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(kWindowTilePixels,
- taskbar_top_work_area.y() + kWindowTilePixels,
- 1024 - kWindowTilePixels * 2,
- taskbar_top_work_area.height() - kWindowTilePixels * 2),
- window_bounds);
- }
-
- { // 4:3 monitor case, 1280x1024
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(twelveeighty, twelveeighty, gfx::Rect(), gfx::Rect(),
- false, gfx::Rect(), DEFAULT, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(kWindowTilePixels, kWindowTilePixels,
- 1050,
- 1024 - kWindowTilePixels * 2),
- window_bounds);
- }
-
- { // 4:3 monitor case, 1600x1200
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(sixteenhundred, sixteenhundred, gfx::Rect(), gfx::Rect(),
- false, gfx::Rect(), DEFAULT, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(kWindowTilePixels, kWindowTilePixels,
- 1050,
- 1200 - kWindowTilePixels * 2),
- window_bounds);
- }
-
- { // 16:10 monitor case, 1680x1050
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(sixteeneighty, sixteeneighty, gfx::Rect(), gfx::Rect(),
- false, gfx::Rect(), DEFAULT, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(kWindowTilePixels, kWindowTilePixels,
- 840 - static_cast<int>(kWindowTilePixels * 1.5),
- 1050 - kWindowTilePixels * 2),
- window_bounds);
- }
-
- { // 16:10 monitor case, 1920x1200
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(nineteentwenty, nineteentwenty, gfx::Rect(), gfx::Rect(),
- false, gfx::Rect(), DEFAULT, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(kWindowTilePixels, kWindowTilePixels,
- 960 - static_cast<int>(kWindowTilePixels * 1.5),
- 1200 - kWindowTilePixels * 2),
- window_bounds);
- }
-}
-
-// Test that the next opened window is positioned appropriately given the
-// bounds of an existing window of the same type.
-TEST(WindowSizerTest, LastWindowBoundsCase) {
- { // normal, in the middle of the screen somewhere.
- gfx::Rect window_bounds;
- bool maximized = false;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(kWindowTilePixels, kWindowTilePixels, 500, 400),
- false, gfx::Rect(), LAST_ACTIVE,
- &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(kWindowTilePixels * 2,
- kWindowTilePixels * 2, 500, 400), window_bounds);
- }
-
- { // taskbar on top.
- gfx::Rect window_bounds;
- bool maximized = false;
- GetWindowBounds(tentwentyfour, taskbar_top_work_area, gfx::Rect(),
- gfx::Rect(kWindowTilePixels, kWindowTilePixels, 500, 400),
- false, gfx::Rect(), LAST_ACTIVE,
- &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(kWindowTilePixels * 2,
- std::max(kWindowTilePixels * 2,
- 34 /* toolbar height */),
- 500, 400), window_bounds);
- }
-
- { // too small to satisify the minimum visibility condition.
- gfx::Rect window_bounds;
- bool maximized = false;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(kWindowTilePixels, kWindowTilePixels, 29, 29),
- false, gfx::Rect(), LAST_ACTIVE,
- &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(kWindowTilePixels * 2,
- kWindowTilePixels * 2,
- 30 /* not 29 */,
- 30 /* not 29 */),
- window_bounds);
- }
-
-
- { // normal, but maximized
- gfx::Rect window_bounds;
- bool maximized = false;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(kWindowTilePixels, kWindowTilePixels, 500, 400),
- true, gfx::Rect(), LAST_ACTIVE,
- &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(kWindowTilePixels * 2,
- kWindowTilePixels * 2, 500, 400), window_bounds);
- }
-}
-
-// Test that the window opened is sized appropriately given persisted sizes.
-TEST(WindowSizerTest, PersistedBoundsCase) {
- { // normal, in the middle of the screen somewhere.
- gfx::Rect initial_bounds(kWindowTilePixels, kWindowTilePixels, 500, 400);
-
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(), initial_bounds,
- false, gfx::Rect(), PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(initial_bounds, window_bounds);
- }
-
- { // normal, maximized.
- gfx::Rect initial_bounds(0, 0, 1024, 768);
-
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(), initial_bounds,
- true, gfx::Rect(), PERSISTED, &window_bounds, &maximized);
- EXPECT_TRUE(maximized);
- EXPECT_EQ(initial_bounds, window_bounds);
- }
-
- { // normal, on non-primary monitor in negative coords.
- gfx::Rect initial_bounds(-600, 10, 500, 400);
-
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, left_nonprimary,
- initial_bounds, false, gfx::Rect(), PERSISTED,
- &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(initial_bounds, window_bounds);
- }
-
- { // normal, on non-primary monitor in negative coords, maximized.
- gfx::Rect initial_bounds(-1024, 0, 1024, 768);
-
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, left_nonprimary,
- initial_bounds, true, gfx::Rect(), PERSISTED,
- &window_bounds, &maximized);
- EXPECT_TRUE(maximized);
- EXPECT_EQ(initial_bounds, window_bounds);
- }
-
- { // Non-primary monitor resoultion has changed, but the monitor still
- // completely contains the window.
-
- gfx::Rect initial_bounds(1074, 50, 600, 500);
-
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(1024, 0, 800, 600),
- initial_bounds, false, right_nonprimary,
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(initial_bounds, window_bounds);
- }
-
- { // Non-primary monitor resoultion has changed, and the window is partially
- // off-screen.
-
- gfx::Rect initial_bounds(1274, 50, 600, 500);
-
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(1024, 0, 800, 600),
- initial_bounds, false, right_nonprimary,
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(1224, 50, 600, 500), window_bounds);
- }
-
- { // Non-primary monitor resoultion has changed, and the window is now too
- // large for the monitor.
-
- gfx::Rect initial_bounds(1274, 50, 900, 700);
-
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(1024, 0, 800, 600),
- initial_bounds, false, right_nonprimary,
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(1024, 0, 800, 600), window_bounds);
- }
-
- { // width and height too small
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(kWindowTilePixels, kWindowTilePixels, 29, 29),
- false, gfx::Rect(), PERSISTED,
- &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(kWindowTilePixels, kWindowTilePixels,
- 30 /* not 29 */, 30 /* not 29 */),
- window_bounds);
- }
-
-#if defined(OS_MACOSX)
- { // Saved state is too tall to possibly be resized. Mac resizers
- // are at the bottom of the window, and no piece of a window can
- // be moved higher than the menubar. (Perhaps the user changed
- // resolution to something smaller before relaunching Chrome?)
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(kWindowTilePixels, kWindowTilePixels, 30, 5000),
- false, gfx::Rect(), PERSISTED,
- &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(tentwentyfour.height(), window_bounds.height());
- }
-#endif // defined(OS_MACOSX)
-}
-
-//////////////////////////////////////////////////////////////////////////////
-// The following unittests have different results on Mac/non-Mac because we
-// reposition windows aggressively on Mac. The *WithAggressiveReposition tests
-// are run on Mac, and the *WithNonAggressiveRepositioning tests are run on
-// other platforms.
-
-#if defined(OS_MACOSX)
-TEST(WindowSizerTest, LastWindowOffscreenWithAggressiveRepositioning) {
- { // taskbar on left. The new window overlaps slightly with the taskbar, so
- // it is moved to be flush with the left edge of the work area.
- gfx::Rect window_bounds;
- bool maximized = false;
- GetWindowBounds(tentwentyfour, taskbar_left_work_area, gfx::Rect(),
- gfx::Rect(kWindowTilePixels, kWindowTilePixels, 500, 400),
- false, gfx::Rect(), LAST_ACTIVE,
- &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(taskbar_left_work_area.x(),
- kWindowTilePixels * 2, 500, 400), window_bounds);
- }
-
- { // offset would put the new window offscreen at the bottom
- gfx::Rect window_bounds;
- bool maximized = false;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(10, 729, 500, 400), false, gfx::Rect(),
- LAST_ACTIVE, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(10 + kWindowTilePixels,
- 0 /* not 729 + kWindowTilePixels */,
- 500, 400),
- window_bounds);
- }
-
- { // offset would put the new window offscreen at the right
- gfx::Rect window_bounds;
- bool maximized = false;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(985, 10, 500, 400), false, gfx::Rect(),
- LAST_ACTIVE, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(0 /* not 985 + kWindowTilePixels*/,
- 10 + kWindowTilePixels,
- 500, 400),
- window_bounds);
- }
-
- { // offset would put the new window offscreen at the bottom right
- gfx::Rect window_bounds;
- bool maximized = false;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(985, 729, 500, 400), false, gfx::Rect(),
- LAST_ACTIVE, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(0 /* not 985 + kWindowTilePixels*/,
- 0 /* not 729 + kWindowTilePixels*/,
- 500, 400),
- window_bounds);
- }
-}
-
-TEST(WindowSizerTest, PersistedWindowOffscreenWithAggressiveRepositioning) {
- { // off the left
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(-471, 50, 500, 400), false, gfx::Rect(),
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(0 /* not -471 */, 50, 500, 400), window_bounds);
- }
-
- { // off the top
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(50, -370, 500, 400), false, gfx::Rect(),
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(50, 0, 500, 400), window_bounds);
- }
-
- { // off the right
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(995, 50, 500, 400), false, gfx::Rect(),
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(0 /* not 995 */, 50, 500, 400), window_bounds);
- }
-
- { // off the bottom
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(50, 739, 500, 400), false, gfx::Rect(), PERSISTED,
- &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(50, 0 /* not 739 */, 500, 400), window_bounds);
- }
-
- { // off the topleft
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(-471, -371, 500, 400), false, gfx::Rect(),
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(0 /* not -471 */, 0 /* not -371 */, 500, 400),
- window_bounds);
- }
-
- { // off the topright
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(995, -371, 500, 400), false, gfx::Rect(),
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(0 /* not 995 */, 0 /* not -371 */, 500, 400),
- window_bounds);
- }
-
- { // off the bottomleft
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(-471, 739, 500, 400), false, gfx::Rect(),
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(0 /* not -471 */, 0 /* not 739 */, 500, 400),
- window_bounds);
- }
-
- { // off the bottomright
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(995, 739, 500, 400), false, gfx::Rect(),
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(0 /* not 995 */, 0 /* not 739 */, 500, 400),
- window_bounds);
- }
-
- { // entirely off left
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(-700, 50, 500, 400), false, gfx::Rect(),
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(0 /* not -700 */, 50, 500, 400), window_bounds);
- }
-
- { // entirely off left (monitor was detached since last run)
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(-700, 50, 500, 400), false, left_nonprimary,
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(0, 50, 500, 400), window_bounds);
- }
-
- { // entirely off top
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(50, -500, 500, 400), false, gfx::Rect(),
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(50, 0, 500, 400), window_bounds);
- }
-
- { // entirely off top (monitor was detached since last run)
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(50, -500, 500, 400), false, top_nonprimary,
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(50, 0, 500, 400), window_bounds);
- }
-
- { // entirely off right
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(1200, 50, 500, 400), false, gfx::Rect(),
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(0 /* not 1200 */, 50, 500, 400), window_bounds);
- }
-
- { // entirely off right (monitor was detached since last run)
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(1200, 50, 500, 400), false, right_nonprimary,
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(524 /* not 1200 */, 50, 500, 400), window_bounds);
- }
-
- { // entirely off bottom
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(50, 800, 500, 400), false, gfx::Rect(), PERSISTED,
- &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(50, 0 /* not 800 */, 500, 400), window_bounds);
- }
-
- { // entirely off bottom (monitor was detached since last run)
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(50, 800, 500, 400), false, bottom_nonprimary,
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(50, 368 /* not 800 */, 500, 400), window_bounds);
- }
-
- { // wider than the screen. off both the left and right
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(-100, 50, 2000, 400), false, gfx::Rect(),
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(0 /* not -100 */, 50, 2000, 400), window_bounds);
- }
-}
-#else
-TEST(WindowSizerTest, LastWindowOffscreenWithNonAggressiveRepositioning) {
- { // taskbar on left.
- gfx::Rect window_bounds;
- bool maximized = false;
- GetWindowBounds(tentwentyfour, taskbar_left_work_area, gfx::Rect(),
- gfx::Rect(kWindowTilePixels, kWindowTilePixels, 500, 400),
- false, gfx::Rect(), LAST_ACTIVE,
- &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(kWindowTilePixels * 2,
- kWindowTilePixels * 2, 500, 400), window_bounds);
- }
-
- // Linux does not tile windows, so tile adjustment tests don't make sense.
-#if !defined(OS_LINUX)
- { // offset would put the new window offscreen at the bottom but the minimum
- // visibility condition is barely satisfied without relocation.
- gfx::Rect window_bounds;
- bool maximized = false;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(10, 728, 500, 400), false, gfx::Rect(),
- LAST_ACTIVE, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(10 + kWindowTilePixels, 738,
- 500, 400), window_bounds);
- }
-
- { // offset would put the new window offscreen at the bottom and the minimum
- // visibility condition is satisified by relocation.
- gfx::Rect window_bounds;
- bool maximized = false;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(10, 729, 500, 400), false, gfx::Rect(),
- LAST_ACTIVE, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(10 + kWindowTilePixels, 738 /* not 739 */, 500, 400),
- window_bounds);
- }
-
- { // offset would put the new window offscreen at the right but the minimum
- // visibility condition is barely satisfied without relocation.
- gfx::Rect window_bounds;
- bool maximized = false;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(984, 10, 500, 400), false, gfx::Rect(),
- LAST_ACTIVE, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(994, 10 + kWindowTilePixels, 500, 400), window_bounds);
- }
-
- { // offset would put the new window offscreen at the right and the minimum
- // visibility condition is satisified by relocation.
- gfx::Rect window_bounds;
- bool maximized = false;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(985, 10, 500, 400), false, gfx::Rect(),
- LAST_ACTIVE, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(994 /* not 995 */, 10 + kWindowTilePixels,
- 500, 400), window_bounds);
- }
-
- { // offset would put the new window offscreen at the bottom right and the
- // minimum visibility condition is satisified by relocation.
- gfx::Rect window_bounds;
- bool maximized = false;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(985, 729, 500, 400), false, gfx::Rect(),
- LAST_ACTIVE, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(994 /* not 995 */, 738 /* not 739 */, 500, 400),
- window_bounds);
- }
-#endif // !defined(OS_LINUX)
-}
-
-TEST(WindowSizerTest, PersistedWindowOffscreenWithNonAggressiveRepositioning) {
- { // off the left but the minimum visibility condition is barely satisfied
- // without relocaiton.
- gfx::Rect initial_bounds(-470, 50, 500, 400);
-
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- initial_bounds, false, gfx::Rect(), PERSISTED,
- &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(initial_bounds, window_bounds);
- }
-
- { // off the left and the minimum visibility condition is satisfied by
- // relocation.
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(-471, 50, 500, 400), false, gfx::Rect(),
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(-470 /* not -471 */, 50, 500, 400), window_bounds);
- }
-
- { // off the top
- gfx::Rect initial_bounds(50, -370, 500, 400);
-
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(50, -370, 500, 400), false, gfx::Rect(),
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(50, 0, 500, 400), window_bounds);
- }
-
- { // off the right but the minimum visibility condition is barely satisified
- // without relocation.
- gfx::Rect initial_bounds(994, 50, 500, 400);
-
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- initial_bounds, false, gfx::Rect(), PERSISTED,
- &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(initial_bounds, window_bounds);
- }
-
- { // off the right and the minimum visibility condition is satisified by
- // relocation.
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(995, 50, 500, 400), false, gfx::Rect(),
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(994 /* not 995 */, 50, 500, 400), window_bounds);
- }
-
- { // off the bottom but the minimum visibility condition is barely satisified
- // without relocation.
- gfx::Rect initial_bounds(50, 738, 500, 400);
-
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- initial_bounds, false, gfx::Rect(), PERSISTED,
- &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(initial_bounds, window_bounds);
- }
-
- { // off the bottom and the minimum visibility condition is satisified by
- // relocation.
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(50, 739, 500, 400), false, gfx::Rect(), PERSISTED,
- &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(50, 738 /* not 739 */, 500, 400), window_bounds);
- }
-
- { // off the topleft
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(-471, -371, 500, 400), false, gfx::Rect(),
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(-470 /* not -471 */, 0, 500, 400),
- window_bounds);
- }
-
- { // off the topright and the minimum visibility condition is satisified by
- // relocation.
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(995, -371, 500, 400), false, gfx::Rect(),
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(994 /* not 995 */, 0, 500, 400),
- window_bounds);
- }
-
- { // off the bottomleft and the minimum visibility condition is satisified by
- // relocation.
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(-471, 739, 500, 400), false, gfx::Rect(),
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(-470 /* not -471 */, 738 /* not 739 */, 500, 400),
- window_bounds);
- }
-
- { // off the bottomright and the minimum visibility condition is satisified by
- // relocation.
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(995, 739, 500, 400), false, gfx::Rect(),
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(994 /* not 995 */, 738 /* not 739 */, 500, 400),
- window_bounds);
- }
-
- { // entirely off left
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(-700, 50, 500, 400), false, gfx::Rect(),
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(-470 /* not -700 */, 50, 500, 400), window_bounds);
- }
-
- { // entirely off left (monitor was detached since last run)
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(-700, 50, 500, 400), false, left_nonprimary,
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(0, 50, 500, 400), window_bounds);
- }
-
- { // entirely off top
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(50, -500, 500, 400), false, gfx::Rect(),
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(50, 0, 500, 400), window_bounds);
- }
-
- { // entirely off top (monitor was detached since last run)
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(50, -500, 500, 400), false, top_nonprimary,
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(50, 0, 500, 400), window_bounds);
- }
-
- { // entirely off right
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(1200, 50, 500, 400), false, gfx::Rect(),
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(994 /* not 1200 */, 50, 500, 400), window_bounds);
- }
-
- { // entirely off right (monitor was detached since last run)
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(1200, 50, 500, 400), false, right_nonprimary,
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(524, 50, 500, 400), window_bounds);
- }
-
- { // entirely off bottom
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(50, 800, 500, 400), false, gfx::Rect(), PERSISTED,
- &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(50, 738 /* not 800 */, 500, 400), window_bounds);
- }
-
- { // entirely off bottom (monitor was detached since last run)
- gfx::Rect window_bounds;
- bool maximized;
- GetWindowBounds(tentwentyfour, tentwentyfour, gfx::Rect(),
- gfx::Rect(50, 800, 500, 400), false, bottom_nonprimary,
- PERSISTED, &window_bounds, &maximized);
- EXPECT_FALSE(maximized);
- EXPECT_EQ(gfx::Rect(50, 368, 500, 400), window_bounds);
- }
-}
-#endif //defined(OS_MACOSX)
diff --git a/chrome/browser/window_sizer_win.cc b/chrome/browser/window_sizer_win.cc
deleted file mode 100644
index 0574a3d..0000000
--- a/chrome/browser/window_sizer_win.cc
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/window_sizer.h"
-
-#include "chrome/browser/browser_list.h"
-#include "chrome/browser/browser_window.h"
-#include "chrome/browser/ui/browser.h"
-
-// How much horizontal and vertical offset there is between newly
-// opened windows.
-const int WindowSizer::kWindowTilePixels = 10;
-
-// An implementation of WindowSizer::MonitorInfoProvider that gets the actual
-// monitor information from Windows.
-class DefaultMonitorInfoProvider : public WindowSizer::MonitorInfoProvider {
- public:
- DefaultMonitorInfoProvider() { }
-
- // Overridden from WindowSizer::MonitorInfoProvider:
- virtual gfx::Rect GetPrimaryMonitorWorkArea() const {
- return gfx::Rect(GetMonitorInfoForMonitor(MonitorFromWindow(NULL,
- MONITOR_DEFAULTTOPRIMARY)).rcWork);
- }
-
- virtual gfx::Rect GetPrimaryMonitorBounds() const {
- return gfx::Rect(GetMonitorInfoForMonitor(MonitorFromWindow(NULL,
- MONITOR_DEFAULTTOPRIMARY)).rcMonitor);
- }
-
- virtual gfx::Rect GetMonitorWorkAreaMatching(
- const gfx::Rect& match_rect) const {
- RECT other_bounds_rect = match_rect.ToRECT();
- MONITORINFO monitor_info = GetMonitorInfoForMonitor(MonitorFromRect(
- &other_bounds_rect, MONITOR_DEFAULTTONEAREST));
- return gfx::Rect(monitor_info.rcWork);
- }
-
- virtual gfx::Point GetBoundsOffsetMatching(
- const gfx::Rect& match_rect) const {
- RECT other_bounds_rect = match_rect.ToRECT();
- MONITORINFO monitor_info = GetMonitorInfoForMonitor(MonitorFromRect(
- &other_bounds_rect, MONITOR_DEFAULTTONEAREST));
- return gfx::Point(monitor_info.rcWork.left - monitor_info.rcMonitor.left,
- monitor_info.rcWork.top - monitor_info.rcMonitor.top);
- }
-
- void UpdateWorkAreas() {
- work_areas_.clear();
- EnumDisplayMonitors(NULL, NULL,
- &DefaultMonitorInfoProvider::MonitorEnumProc,
- reinterpret_cast<LPARAM>(&work_areas_));
- }
-
- private:
- // A callback for EnumDisplayMonitors that records the work area of the
- // current monitor in the enumeration.
- static BOOL CALLBACK MonitorEnumProc(HMONITOR monitor,
- HDC monitor_dc,
- LPRECT monitor_rect,
- LPARAM data) {
- reinterpret_cast<std::vector<gfx::Rect>*>(data)->push_back(
- gfx::Rect(GetMonitorInfoForMonitor(monitor).rcWork));
- return TRUE;
- }
-
- static MONITORINFO GetMonitorInfoForMonitor(HMONITOR monitor) {
- MONITORINFO monitor_info = { 0 };
- monitor_info.cbSize = sizeof(monitor_info);
- GetMonitorInfo(monitor, &monitor_info);
- return monitor_info;
- }
-
- DISALLOW_COPY_AND_ASSIGN(DefaultMonitorInfoProvider);
-};
-
-// static
-WindowSizer::MonitorInfoProvider*
-WindowSizer::CreateDefaultMonitorInfoProvider() {
- return new DefaultMonitorInfoProvider();
-}
-
-// static
-gfx::Point WindowSizer::GetDefaultPopupOrigin(const gfx::Size& size) {
- RECT area;
- SystemParametersInfo(SPI_GETWORKAREA, 0, &area, 0);
- gfx::Point corner(area.left, area.top);
-
- if (Browser* b = BrowserList::GetLastActive()) {
- RECT browser;
- HWND window = reinterpret_cast<HWND>(b->window()->GetNativeHandle());
- if (GetWindowRect(window, &browser)) {
- // Limit to not overflow the work area right and bottom edges.
- gfx::Point limit(
- std::min(browser.left + kWindowTilePixels, area.right-size.width()),
- std::min(browser.top + kWindowTilePixels, area.bottom-size.height())
- );
- // Adjust corner to now overflow the work area left and top edges, so
- // that if a popup does not fit the title-bar is remains visible.
- corner = gfx::Point(
- std::max(corner.x(), limit.x()),
- std::max(corner.y(), limit.y())
- );
- }
- }
- return corner;
-}
diff --git a/chrome/browser/worker_host/message_port_dispatcher.cc b/chrome/browser/worker_host/message_port_dispatcher.cc
deleted file mode 100644
index 3fedd67..0000000
--- a/chrome/browser/worker_host/message_port_dispatcher.cc
+++ /dev/null
@@ -1,292 +0,0 @@
-// Copyright (c) 2009 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 "chrome/browser/worker_host/message_port_dispatcher.h"
-
-#include "base/callback.h"
-#include "base/singleton.h"
-#include "chrome/browser/browser_thread.h"
-#include "chrome/browser/renderer_host/resource_message_filter.h"
-#include "chrome/browser/worker_host/worker_process_host.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/worker_messages.h"
-
-struct MessagePortDispatcher::MessagePort {
- // sender and route_id are what we need to send messages to the port.
- IPC::Message::Sender* sender;
- int route_id;
- // A function pointer to generate a new route id for the sender above.
- // Owned by "sender" above, so don't delete.
- CallbackWithReturnValue<int>::Type* next_routing_id;
- // A globally unique id for this message port.
- int message_port_id;
- // The globally unique id of the entangled message port.
- int entangled_message_port_id;
- // If true, all messages to this message port are queued and not delivered.
- bool queue_messages;
- QueuedMessages queued_messages;
-};
-
-MessagePortDispatcher* MessagePortDispatcher::GetInstance() {
- return Singleton<MessagePortDispatcher>::get();
-}
-
-MessagePortDispatcher::MessagePortDispatcher()
- : next_message_port_id_(0),
- sender_(NULL),
- next_routing_id_(NULL) {
- // Receive a notification if a message filter or WorkerProcessHost is deleted.
- registrar_.Add(this, NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN,
- NotificationService::AllSources());
-
- registrar_.Add(this, NotificationType::WORKER_PROCESS_HOST_SHUTDOWN,
- NotificationService::AllSources());
-}
-
-MessagePortDispatcher::~MessagePortDispatcher() {
-}
-
-bool MessagePortDispatcher::OnMessageReceived(
- const IPC::Message& message,
- IPC::Message::Sender* sender,
- CallbackWithReturnValue<int>::Type* next_routing_id,
- bool* message_was_ok) {
- sender_ = sender;
- next_routing_id_ = next_routing_id;
-
- bool handled = true;
- *message_was_ok = true;
-
- IPC_BEGIN_MESSAGE_MAP_EX(MessagePortDispatcher, message, *message_was_ok)
- IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_CreateMessagePort, OnCreate)
- IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_DestroyMessagePort, OnDestroy)
- IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_Entangle, OnEntangle)
- IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_PostMessage, OnPostMessage)
- IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_QueueMessages, OnQueueMessages)
- IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_SendQueuedMessages,
- OnSendQueuedMessages)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP_EX()
-
- sender_ = NULL;
- next_routing_id_ = NULL;
-
- return handled;
-}
-
-void MessagePortDispatcher::UpdateMessagePort(
- int message_port_id,
- IPC::Message::Sender* sender,
- int routing_id,
- CallbackWithReturnValue<int>::Type* next_routing_id) {
- if (!message_ports_.count(message_port_id)) {
- NOTREACHED();
- return;
- }
-
- MessagePort& port = message_ports_[message_port_id];
- port.sender = sender;
- port.route_id = routing_id;
- port.next_routing_id = next_routing_id;
-}
-
-bool MessagePortDispatcher::Send(IPC::Message* message) {
- return sender_->Send(message);
-}
-
-void MessagePortDispatcher::OnCreate(int *route_id,
- int* message_port_id) {
- *message_port_id = ++next_message_port_id_;
- *route_id = next_routing_id_->Run();
-
- MessagePort port;
- port.sender = sender_;
- port.route_id = *route_id;
- port.next_routing_id = next_routing_id_;
- port.message_port_id = *message_port_id;
- port.entangled_message_port_id = MSG_ROUTING_NONE;
- port.queue_messages = false;
- message_ports_[*message_port_id] = port;
-}
-
-void MessagePortDispatcher::OnDestroy(int message_port_id) {
- if (!message_ports_.count(message_port_id)) {
- NOTREACHED();
- return;
- }
-
- DCHECK(message_ports_[message_port_id].queued_messages.empty());
- Erase(message_port_id);
-}
-
-void MessagePortDispatcher::OnEntangle(int local_message_port_id,
- int remote_message_port_id) {
- if (!message_ports_.count(local_message_port_id) ||
- !message_ports_.count(remote_message_port_id)) {
- NOTREACHED();
- return;
- }
-
- DCHECK(message_ports_[remote_message_port_id].entangled_message_port_id ==
- MSG_ROUTING_NONE);
- message_ports_[remote_message_port_id].entangled_message_port_id =
- local_message_port_id;
-}
-
-void MessagePortDispatcher::OnPostMessage(
- int sender_message_port_id,
- const string16& message,
- const std::vector<int>& sent_message_port_ids) {
- if (!message_ports_.count(sender_message_port_id)) {
- NOTREACHED();
- return;
- }
-
- int entangled_message_port_id =
- message_ports_[sender_message_port_id].entangled_message_port_id;
- if (entangled_message_port_id == MSG_ROUTING_NONE)
- return; // Process could have crashed.
-
- if (!message_ports_.count(entangled_message_port_id)) {
- NOTREACHED();
- return;
- }
-
- PostMessageTo(entangled_message_port_id, message, sent_message_port_ids);
-}
-
-void MessagePortDispatcher::PostMessageTo(
- int message_port_id,
- const string16& message,
- const std::vector<int>& sent_message_port_ids) {
- if (!message_ports_.count(message_port_id)) {
- NOTREACHED();
- return;
- }
- for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
- if (!message_ports_.count(sent_message_port_ids[i])) {
- NOTREACHED();
- return;
- }
- }
-
- MessagePort& entangled_port = message_ports_[message_port_id];
-
- std::vector<MessagePort*> sent_ports(sent_message_port_ids.size());
- for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
- sent_ports[i] = &message_ports_[sent_message_port_ids[i]];
- sent_ports[i]->queue_messages = true;
- }
-
- if (entangled_port.queue_messages) {
- entangled_port.queued_messages.push_back(
- std::make_pair(message, sent_message_port_ids));
- } else {
- // If a message port was sent around, the new location will need a routing
- // id. Instead of having the created port send us a sync message to get it,
- // send along with the message.
- std::vector<int> new_routing_ids(sent_message_port_ids.size());
- for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
- new_routing_ids[i] = entangled_port.next_routing_id->Run();
- sent_ports[i]->sender = entangled_port.sender;
-
- // Update the entry for the sent port as it can be in a different process.
- sent_ports[i]->route_id = new_routing_ids[i];
- }
-
- if (entangled_port.sender) {
- // Now send the message to the entangled port.
- IPC::Message* ipc_msg = new WorkerProcessMsg_Message(
- entangled_port.route_id, message, sent_message_port_ids,
- new_routing_ids);
- entangled_port.sender->Send(ipc_msg);
- }
- }
-}
-
-void MessagePortDispatcher::OnQueueMessages(int message_port_id) {
- if (!message_ports_.count(message_port_id)) {
- NOTREACHED();
- return;
- }
-
- MessagePort& port = message_ports_[message_port_id];
- if (port.sender) {
- port.sender->Send(new WorkerProcessMsg_MessagesQueued(port.route_id));
- port.queue_messages = true;
- port.sender = NULL;
- }
-}
-
-void MessagePortDispatcher::OnSendQueuedMessages(
- int message_port_id,
- const QueuedMessages& queued_messages) {
- if (!message_ports_.count(message_port_id)) {
- NOTREACHED();
- return;
- }
-
- // Send the queued messages to the port again. This time they'll reach the
- // new location.
- MessagePort& port = message_ports_[message_port_id];
- port.queue_messages = false;
- port.queued_messages.insert(port.queued_messages.begin(),
- queued_messages.begin(),
- queued_messages.end());
- SendQueuedMessagesIfPossible(message_port_id);
-}
-
-void MessagePortDispatcher::SendQueuedMessagesIfPossible(int message_port_id) {
- if (!message_ports_.count(message_port_id)) {
- NOTREACHED();
- return;
- }
-
- MessagePort& port = message_ports_[message_port_id];
- if (port.queue_messages || !port.sender)
- return;
-
- for (QueuedMessages::iterator iter = port.queued_messages.begin();
- iter != port.queued_messages.end(); ++iter) {
- PostMessageTo(message_port_id, iter->first, iter->second);
- }
- port.queued_messages.clear();
-}
-
-void MessagePortDispatcher::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- IPC::Message::Sender* sender = NULL;
- if (type.value == NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN) {
- sender = Source<ResourceMessageFilter>(source).ptr();
- } else if (type.value == NotificationType::WORKER_PROCESS_HOST_SHUTDOWN) {
- sender = Source<WorkerProcessHost>(source).ptr();
- } else {
- NOTREACHED();
- }
-
- // Check if the (possibly) crashed process had any message ports.
- for (MessagePorts::iterator iter = message_ports_.begin();
- iter != message_ports_.end();) {
- MessagePorts::iterator cur_item = iter++;
- if (cur_item->second.sender == sender) {
- Erase(cur_item->first);
- }
- }
-}
-
-void MessagePortDispatcher::Erase(int message_port_id) {
- MessagePorts::iterator erase_item = message_ports_.find(message_port_id);
- DCHECK(erase_item != message_ports_.end());
-
- int entangled_id = erase_item->second.entangled_message_port_id;
- if (entangled_id != MSG_ROUTING_NONE) {
- // Do the disentanglement (and be paranoid about the other side existing
- // just in case something unusual happened during entanglement).
- if (message_ports_.count(entangled_id)) {
- message_ports_[entangled_id].entangled_message_port_id = MSG_ROUTING_NONE;
- }
- }
- message_ports_.erase(erase_item);
-}
diff --git a/chrome/browser/worker_host/message_port_dispatcher.h b/chrome/browser/worker_host/message_port_dispatcher.h
deleted file mode 100644
index 566416b..0000000
--- a/chrome/browser/worker_host/message_port_dispatcher.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_WORKER_HOST_MESSAGE_PORT_DISPATCHER_H_
-#define CHROME_BROWSER_WORKER_HOST_MESSAGE_PORT_DISPATCHER_H_
-#pragma once
-
-#include <map>
-#include <utility>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/callback.h"
-#include "base/singleton.h"
-#include "base/string16.h"
-#include "base/task.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
-#include "ipc/ipc_message.h"
-
-class MessagePortDispatcher : public NotificationObserver {
- public:
- typedef std::vector<std::pair<string16, std::vector<int> > > QueuedMessages;
-
- // Returns the MessagePortDispatcher singleton.
- static MessagePortDispatcher* GetInstance();
-
- bool OnMessageReceived(const IPC::Message& message,
- IPC::Message::Sender* sender,
- CallbackWithReturnValue<int>::Type* next_routing_id,
- bool* message_was_ok);
-
- // Updates the information needed to reach a message port when it's sent to a
- // (possibly different) process.
- void UpdateMessagePort(
- int message_port_id,
- IPC::Message::Sender* sender,
- int routing_id,
- CallbackWithReturnValue<int>::Type* next_routing_id);
-
- // Attempts to send the queued messages for a message port.
- void SendQueuedMessagesIfPossible(int message_port_id);
-
- bool Send(IPC::Message* message);
-
- private:
- friend struct DefaultSingletonTraits<MessagePortDispatcher>;
-
- MessagePortDispatcher();
- ~MessagePortDispatcher();
-
- // Message handlers.
- void OnCreate(int* route_id, int* message_port_id);
- void OnDestroy(int message_port_id);
- void OnEntangle(int local_message_port_id, int remote_message_port_id);
- void OnPostMessage(int sender_message_port_id,
- const string16& message,
- const std::vector<int>& sent_message_port_ids);
- void OnQueueMessages(int message_port_id);
- void OnSendQueuedMessages(int message_port_id,
- const QueuedMessages& queued_messages);
-
- void PostMessageTo(int message_port_id,
- const string16& message,
- const std::vector<int>& sent_message_port_ids);
-
- // NotificationObserver interface.
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- // Handles the details of removing a message port id. Before calling this,
- // verify that the message port id exists.
- void Erase(int message_port_id);
-
- struct MessagePort;
- typedef std::map<int, MessagePort> MessagePorts;
- MessagePorts message_ports_;
-
- // We need globally unique identifiers for each message port.
- int next_message_port_id_;
-
- // Valid only during IPC message dispatching.
- IPC::Message::Sender* sender_;
- CallbackWithReturnValue<int>::Type* next_routing_id_;
-
- NotificationRegistrar registrar_;
-
- DISALLOW_COPY_AND_ASSIGN(MessagePortDispatcher);
-};
-
-#endif // CHROME_BROWSER_WORKER_HOST_MESSAGE_PORT_DISPATCHER_H_
diff --git a/chrome/browser/worker_host/message_port_service.cc b/chrome/browser/worker_host/message_port_service.cc
new file mode 100644
index 0000000..6638e71
--- /dev/null
+++ b/chrome/browser/worker_host/message_port_service.cc
@@ -0,0 +1,236 @@
+// Copyright (c) 2009 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 "chrome/browser/worker_host/message_port_service.h"
+
+#include "chrome/browser/worker_host/worker_message_filter.h"
+#include "chrome/common/worker_messages.h"
+
+struct MessagePortService::MessagePort {
+ // |filter| and |route_id| are what we need to send messages to the port.
+ // |filter| is just a weak pointer since we get notified when its process has
+ // gone away and remove it.
+ WorkerMessageFilter* filter;
+ int route_id;
+ // A globally unique id for this message port.
+ int message_port_id;
+ // The globally unique id of the entangled message port.
+ int entangled_message_port_id;
+ // If true, all messages to this message port are queued and not delivered.
+ bool queue_messages;
+ QueuedMessages queued_messages;
+};
+
+MessagePortService* MessagePortService::GetInstance() {
+ return Singleton<MessagePortService>::get();
+}
+
+MessagePortService::MessagePortService()
+ : next_message_port_id_(0) {
+}
+
+MessagePortService::~MessagePortService() {
+}
+
+void MessagePortService::UpdateMessagePort(
+ int message_port_id,
+ WorkerMessageFilter* filter,
+ int routing_id) {
+ if (!message_ports_.count(message_port_id)) {
+ NOTREACHED();
+ return;
+ }
+
+ MessagePort& port = message_ports_[message_port_id];
+ port.filter = filter;
+ port.route_id = routing_id;
+}
+
+void MessagePortService::OnWorkerMessageFilterClosing(
+ WorkerMessageFilter* filter) {
+ // Check if the (possibly) crashed process had any message ports.
+ for (MessagePorts::iterator iter = message_ports_.begin();
+ iter != message_ports_.end();) {
+ MessagePorts::iterator cur_item = iter++;
+ if (cur_item->second.filter == filter) {
+ Erase(cur_item->first);
+ }
+ }
+}
+
+void MessagePortService::Create(int route_id,
+ WorkerMessageFilter* filter,
+ int* message_port_id) {
+ *message_port_id = ++next_message_port_id_;
+
+ MessagePort port;
+ port.filter = filter;
+ port.route_id = route_id;
+ port.message_port_id = *message_port_id;
+ port.entangled_message_port_id = MSG_ROUTING_NONE;
+ port.queue_messages = false;
+ message_ports_[*message_port_id] = port;
+}
+
+void MessagePortService::Destroy(int message_port_id) {
+ if (!message_ports_.count(message_port_id)) {
+ NOTREACHED();
+ return;
+ }
+
+ DCHECK(message_ports_[message_port_id].queued_messages.empty());
+ Erase(message_port_id);
+}
+
+void MessagePortService::Entangle(int local_message_port_id,
+ int remote_message_port_id) {
+ if (!message_ports_.count(local_message_port_id) ||
+ !message_ports_.count(remote_message_port_id)) {
+ NOTREACHED();
+ return;
+ }
+
+ DCHECK(message_ports_[remote_message_port_id].entangled_message_port_id ==
+ MSG_ROUTING_NONE);
+ message_ports_[remote_message_port_id].entangled_message_port_id =
+ local_message_port_id;
+}
+
+void MessagePortService::PostMessage(
+ int sender_message_port_id,
+ const string16& message,
+ const std::vector<int>& sent_message_port_ids) {
+ if (!message_ports_.count(sender_message_port_id)) {
+ NOTREACHED();
+ return;
+ }
+
+ int entangled_message_port_id =
+ message_ports_[sender_message_port_id].entangled_message_port_id;
+ if (entangled_message_port_id == MSG_ROUTING_NONE)
+ return; // Process could have crashed.
+
+ if (!message_ports_.count(entangled_message_port_id)) {
+ NOTREACHED();
+ return;
+ }
+
+ PostMessageTo(entangled_message_port_id, message, sent_message_port_ids);
+}
+
+void MessagePortService::PostMessageTo(
+ int message_port_id,
+ const string16& message,
+ const std::vector<int>& sent_message_port_ids) {
+ if (!message_ports_.count(message_port_id)) {
+ NOTREACHED();
+ return;
+ }
+ for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
+ if (!message_ports_.count(sent_message_port_ids[i])) {
+ NOTREACHED();
+ return;
+ }
+ }
+
+ MessagePort& entangled_port = message_ports_[message_port_id];
+
+ std::vector<MessagePort*> sent_ports(sent_message_port_ids.size());
+ for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
+ sent_ports[i] = &message_ports_[sent_message_port_ids[i]];
+ sent_ports[i]->queue_messages = true;
+ }
+
+ if (entangled_port.queue_messages) {
+ entangled_port.queued_messages.push_back(
+ std::make_pair(message, sent_message_port_ids));
+ return;
+ }
+
+ if (!entangled_port.filter) {
+ NOTREACHED();
+ return;
+ }
+
+ // If a message port was sent around, the new location will need a routing
+ // id. Instead of having the created port send us a sync message to get it,
+ // send along with the message.
+ std::vector<int> new_routing_ids(sent_message_port_ids.size());
+ for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
+ new_routing_ids[i] = entangled_port.filter->GetNextRoutingID();
+ sent_ports[i]->filter = entangled_port.filter;
+
+ // Update the entry for the sent port as it can be in a different process.
+ sent_ports[i]->route_id = new_routing_ids[i];
+ }
+
+ // Now send the message to the entangled port.
+ entangled_port.filter->Send(new WorkerProcessMsg_Message(
+ entangled_port.route_id, message, sent_message_port_ids,
+ new_routing_ids));
+}
+
+void MessagePortService::QueueMessages(int message_port_id) {
+ if (!message_ports_.count(message_port_id)) {
+ NOTREACHED();
+ return;
+ }
+
+ MessagePort& port = message_ports_[message_port_id];
+ if (port.filter) {
+ port.filter->Send(new WorkerProcessMsg_MessagesQueued(port.route_id));
+ port.queue_messages = true;
+ port.filter = NULL;
+ }
+}
+
+void MessagePortService::SendQueuedMessages(
+ int message_port_id,
+ const QueuedMessages& queued_messages) {
+ if (!message_ports_.count(message_port_id)) {
+ NOTREACHED();
+ return;
+ }
+
+ // Send the queued messages to the port again. This time they'll reach the
+ // new location.
+ MessagePort& port = message_ports_[message_port_id];
+ port.queue_messages = false;
+ port.queued_messages.insert(port.queued_messages.begin(),
+ queued_messages.begin(),
+ queued_messages.end());
+ SendQueuedMessagesIfPossible(message_port_id);
+}
+
+void MessagePortService::SendQueuedMessagesIfPossible(int message_port_id) {
+ if (!message_ports_.count(message_port_id)) {
+ NOTREACHED();
+ return;
+ }
+
+ MessagePort& port = message_ports_[message_port_id];
+ if (port.queue_messages || !port.filter)
+ return;
+
+ for (QueuedMessages::iterator iter = port.queued_messages.begin();
+ iter != port.queued_messages.end(); ++iter) {
+ PostMessageTo(message_port_id, iter->first, iter->second);
+ }
+ port.queued_messages.clear();
+}
+
+void MessagePortService::Erase(int message_port_id) {
+ MessagePorts::iterator erase_item = message_ports_.find(message_port_id);
+ DCHECK(erase_item != message_ports_.end());
+
+ int entangled_id = erase_item->second.entangled_message_port_id;
+ if (entangled_id != MSG_ROUTING_NONE) {
+ // Do the disentanglement (and be paranoid about the other side existing
+ // just in case something unusual happened during entanglement).
+ if (message_ports_.count(entangled_id)) {
+ message_ports_[entangled_id].entangled_message_port_id = MSG_ROUTING_NONE;
+ }
+ }
+ message_ports_.erase(erase_item);
+}
diff --git a/chrome/browser/worker_host/message_port_service.h b/chrome/browser/worker_host/message_port_service.h
new file mode 100644
index 0000000..9c30b6e
--- /dev/null
+++ b/chrome/browser/worker_host/message_port_service.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_WORKER_HOST_MESSAGE_PORT_SERVICE_H_
+#define CHROME_BROWSER_WORKER_HOST_MESSAGE_PORT_SERVICE_H_
+#pragma once
+
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/singleton.h"
+#include "base/string16.h"
+#include "base/task.h"
+#include "ipc/ipc_message.h"
+
+class WorkerMessageFilter;
+
+class MessagePortService {
+ public:
+ typedef std::vector<std::pair<string16, std::vector<int> > > QueuedMessages;
+
+ // Returns the MessagePortService singleton.
+ static MessagePortService* GetInstance();
+
+ // These methods correspond to the message port related IPCs.
+ void Create(int route_id, WorkerMessageFilter* filter, int* message_port_id);
+ void Destroy(int message_port_id);
+ void Entangle(int local_message_port_id, int remote_message_port_id);
+ void PostMessage(int sender_message_port_id,
+ const string16& message,
+ const std::vector<int>& sent_message_port_ids);
+ void QueueMessages(int message_port_id);
+ void SendQueuedMessages(int message_port_id,
+ const QueuedMessages& queued_messages);
+
+ // Updates the information needed to reach a message port when it's sent to a
+ // (possibly different) process.
+ void UpdateMessagePort(
+ int message_port_id,
+ WorkerMessageFilter* filter,
+ int routing_id);
+
+ void OnWorkerMessageFilterClosing(WorkerMessageFilter* filter);
+
+ // Attempts to send the queued messages for a message port.
+ void SendQueuedMessagesIfPossible(int message_port_id);
+
+ private:
+ friend struct DefaultSingletonTraits<MessagePortService>;
+
+ MessagePortService();
+ ~MessagePortService();
+
+ void PostMessageTo(int message_port_id,
+ const string16& message,
+ const std::vector<int>& sent_message_port_ids);
+
+ // Handles the details of removing a message port id. Before calling this,
+ // verify that the message port id exists.
+ void Erase(int message_port_id);
+
+ struct MessagePort;
+ typedef std::map<int, MessagePort> MessagePorts;
+ MessagePorts message_ports_;
+
+ // We need globally unique identifiers for each message port.
+ int next_message_port_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePortService);
+};
+
+#endif // CHROME_BROWSER_WORKER_HOST_MESSAGE_PORT_SERVICE_H_
diff --git a/chrome/browser/worker_host/worker_document_set.cc b/chrome/browser/worker_host/worker_document_set.cc
index 3588bb1..0b3c634 100644
--- a/chrome/browser/worker_host/worker_document_set.cc
+++ b/chrome/browser/worker_host/worker_document_set.cc
@@ -4,32 +4,34 @@
#include "chrome/browser/worker_host/worker_document_set.h"
+#include "base/logging.h"
+
WorkerDocumentSet::WorkerDocumentSet() {
}
-void WorkerDocumentSet::Add(IPC::Message::Sender* parent,
+void WorkerDocumentSet::Add(WorkerMessageFilter* parent,
unsigned long long document_id,
- int renderer_id,
- int render_view_route_id) {
- DocumentInfo info(parent, document_id, renderer_id, render_view_route_id);
+ int render_process_id,
+ int render_view_id) {
+ DocumentInfo info(parent, document_id, render_process_id, render_view_id);
document_set_.insert(info);
}
-bool WorkerDocumentSet::Contains(IPC::Message::Sender* parent,
+bool WorkerDocumentSet::Contains(WorkerMessageFilter* parent,
unsigned long long document_id) const {
for (DocumentInfoSet::const_iterator i = document_set_.begin();
i != document_set_.end(); ++i) {
- if (i->sender() == parent && i->document_id() == document_id)
+ if (i->filter() == parent && i->document_id() == document_id)
return true;
}
return false;
}
-void WorkerDocumentSet::Remove(IPC::Message::Sender* parent,
+void WorkerDocumentSet::Remove(WorkerMessageFilter* parent,
unsigned long long document_id) {
for (DocumentInfoSet::iterator i = document_set_.begin();
i != document_set_.end(); i++) {
- if (i->sender() == parent && i->document_id() == document_id) {
+ if (i->filter() == parent && i->document_id() == document_id) {
document_set_.erase(i);
break;
}
@@ -38,14 +40,14 @@ void WorkerDocumentSet::Remove(IPC::Message::Sender* parent,
DCHECK(!Contains(parent, document_id));
}
-void WorkerDocumentSet::RemoveAll(IPC::Message::Sender* parent) {
+void WorkerDocumentSet::RemoveAll(WorkerMessageFilter* parent) {
for (DocumentInfoSet::iterator i = document_set_.begin();
i != document_set_.end();) {
// Note this idiom is somewhat tricky - calling document_set_.erase(iter)
// invalidates any iterators that point to the element being removed, so
// bump the iterator beyond the item being removed before calling erase.
- if (i->sender() == parent) {
+ if (i->filter() == parent) {
DocumentInfoSet::iterator item_to_delete = i++;
document_set_.erase(item_to_delete);
} else {
@@ -55,12 +57,13 @@ void WorkerDocumentSet::RemoveAll(IPC::Message::Sender* parent) {
}
WorkerDocumentSet::DocumentInfo::DocumentInfo(
- IPC::Message::Sender* sender, unsigned long long document_id,
- int renderer_id, int render_view_route_id)
- : sender_(sender),
+ WorkerMessageFilter* filter, unsigned long long document_id,
+ int render_process_id, int render_view_id)
+ : filter_(filter),
document_id_(document_id),
- renderer_id_(renderer_id),
- render_view_route_id_(render_view_route_id) {
+ render_process_id_(render_process_id),
+ render_view_id_(render_view_id) {
}
-WorkerDocumentSet::~WorkerDocumentSet() {}
+WorkerDocumentSet::~WorkerDocumentSet() {
+}
diff --git a/chrome/browser/worker_host/worker_document_set.h b/chrome/browser/worker_host/worker_document_set.h
index 7894fc4..49da2b6 100644
--- a/chrome/browser/worker_host/worker_document_set.h
+++ b/chrome/browser/worker_host/worker_document_set.h
@@ -10,7 +10,8 @@
#include "base/basictypes.h"
#include "base/ref_counted.h"
-#include "ipc/ipc_message.h"
+
+class WorkerMessageFilter;
// The WorkerDocumentSet tracks all of the DOM documents associated with a
// set of workers. With nested workers, multiple workers can share the same
@@ -23,53 +24,53 @@ class WorkerDocumentSet : public base::RefCounted<WorkerDocumentSet> {
// The information we track for each document
class DocumentInfo {
public:
- DocumentInfo(IPC::Message::Sender* sender, unsigned long long document_id,
- int renderer_id, int render_view_route_id);
- IPC::Message::Sender* sender() const { return sender_; }
+ DocumentInfo(WorkerMessageFilter* filter, unsigned long long document_id,
+ int renderer_process_id, int render_view_id);
+ WorkerMessageFilter* filter() const { return filter_; }
unsigned long long document_id() const { return document_id_; }
- int renderer_id() const { return renderer_id_; }
- int render_view_route_id() const { return render_view_route_id_; }
+ int render_process_id() const { return render_process_id_; }
+ int render_view_id() const { return render_view_id_; }
// Define operator "<", which is used to determine uniqueness within
// the set.
bool operator <(const DocumentInfo& other) const {
// Items are identical if the sender and document_id are identical,
// otherwise create an arbitrary stable ordering based on the document
- // id/sender.
- if (sender() == other.sender()) {
+ // id/filter.
+ if (filter() == other.filter()) {
return document_id() < other.document_id();
} else {
- return reinterpret_cast<unsigned long long>(sender()) <
- reinterpret_cast<unsigned long long>(other.sender());
+ return reinterpret_cast<unsigned long long>(filter()) <
+ reinterpret_cast<unsigned long long>(other.filter());
}
}
private:
- IPC::Message::Sender* sender_;
+ WorkerMessageFilter* filter_;
unsigned long long document_id_;
- int renderer_id_;
- int render_view_route_id_;
+ int render_process_id_;
+ int render_view_id_;
};
// Adds a document to a shared worker's document set. Also includes the
- // associated renderer_id the document is associated with, to enable
+ // associated render_process_id the document is associated with, to enable
// communication with the parent tab for things like http auth dialogs.
- void Add(IPC::Message::Sender* parent,
+ void Add(WorkerMessageFilter* parent,
unsigned long long document_id,
- int renderer_id,
- int render_view_route_id);
+ int render_process_id,
+ int render_view_id);
// Checks to see if a document is in a shared worker's document set.
- bool Contains(IPC::Message::Sender* parent,
+ bool Contains(WorkerMessageFilter* parent,
unsigned long long document_id) const;
// Removes a specific document from a worker's document set when that document
// is detached.
- void Remove(IPC::Message::Sender* parent, unsigned long long document_id);
+ void Remove(WorkerMessageFilter* parent, unsigned long long document_id);
// Invoked when a render process exits, to remove all associated documents
// from a worker's document set.
- void RemoveAll(IPC::Message::Sender* parent);
+ void RemoveAll(WorkerMessageFilter* parent);
bool IsEmpty() const { return document_set_.empty(); }
diff --git a/chrome/browser/worker_host/worker_message_filter.cc b/chrome/browser/worker_host/worker_message_filter.cc
new file mode 100644
index 0000000..b598202
--- /dev/null
+++ b/chrome/browser/worker_host/worker_message_filter.cc
@@ -0,0 +1,116 @@
+// 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.
+
+#include "chrome/browser/worker_host/worker_message_filter.h"
+
+#include "chrome/browser/net/chrome_url_request_context.h"
+#include "chrome/browser/worker_host/message_port_service.h"
+#include "chrome/browser/worker_host/worker_service.h"
+#include "chrome/common/net/url_request_context_getter.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
+#include "chrome/common/worker_messages.h"
+
+WorkerMessageFilter::WorkerMessageFilter(
+ int render_process_id,
+ URLRequestContextGetter* request_context,
+ ResourceDispatcherHost* resource_dispatcher_host,
+ CallbackWithReturnValue<int>::Type* next_routing_id)
+ : render_process_id_(render_process_id),
+ request_context_(request_context),
+ resource_dispatcher_host_(resource_dispatcher_host),
+ next_routing_id_(next_routing_id) {
+}
+
+WorkerMessageFilter::~WorkerMessageFilter() {
+}
+
+void WorkerMessageFilter::OnChannelClosing() {
+ BrowserMessageFilter::OnChannelClosing();
+
+ MessagePortService::GetInstance()->OnWorkerMessageFilterClosing(this);
+ WorkerService::GetInstance()->OnWorkerMessageFilterClosing(this);
+}
+
+bool WorkerMessageFilter::OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(WorkerMessageFilter, message, *message_was_ok)
+ // Worker messages.
+ // Only sent from renderer for now, until we have nested workers.
+ IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWorker, OnCreateWorker)
+ // Only sent from renderer for now, until we have nested workers.
+ IPC_MESSAGE_HANDLER(ViewHostMsg_LookupSharedWorker, OnLookupSharedWorker)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_CancelCreateDedicatedWorker,
+ OnCancelCreateDedicatedWorker)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_ForwardToWorker, OnForwardToWorker)
+ // Only sent from renderer.
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DocumentDetached, OnDocumentDetached)
+ // Message Port related messages.
+ IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_CreateMessagePort,
+ OnCreateMessagePort)
+ IPC_MESSAGE_FORWARD(WorkerProcessHostMsg_DestroyMessagePort,
+ MessagePortService::GetInstance(),
+ MessagePortService::Destroy)
+ IPC_MESSAGE_FORWARD(WorkerProcessHostMsg_Entangle,
+ MessagePortService::GetInstance(),
+ MessagePortService::Entangle)
+ IPC_MESSAGE_FORWARD(WorkerProcessHostMsg_PostMessage,
+ MessagePortService::GetInstance(),
+ MessagePortService::PostMessage)
+ IPC_MESSAGE_FORWARD(WorkerProcessHostMsg_QueueMessages,
+ MessagePortService::GetInstance(),
+ MessagePortService::QueueMessages)
+ IPC_MESSAGE_FORWARD(WorkerProcessHostMsg_SendQueuedMessages,
+ MessagePortService::GetInstance(),
+ MessagePortService::SendQueuedMessages)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP_EX()
+
+ return handled;
+}
+
+int WorkerMessageFilter::GetNextRoutingID() {
+ return next_routing_id_->Run();
+}
+
+void WorkerMessageFilter::OnCreateWorker(
+ const ViewHostMsg_CreateWorker_Params& params,
+ int* route_id) {
+ *route_id = params.route_id != MSG_ROUTING_NONE ?
+ params.route_id : next_routing_id_->Run();
+ WorkerService::GetInstance()->CreateWorker(
+ params, *route_id, this, request_context_);
+}
+
+void WorkerMessageFilter::OnLookupSharedWorker(
+ const ViewHostMsg_CreateWorker_Params& params,
+ bool* exists,
+ int* route_id,
+ bool* url_error) {
+ *route_id = next_routing_id_->Run();
+
+ bool off_the_record = static_cast<ChromeURLRequestContext*>(
+ request_context_->GetURLRequestContext())->is_off_the_record();
+ WorkerService::GetInstance()->LookupSharedWorker(
+ params, *route_id, this, off_the_record, exists, url_error);
+}
+
+void WorkerMessageFilter::OnCancelCreateDedicatedWorker(int route_id) {
+ WorkerService::GetInstance()->CancelCreateDedicatedWorker(route_id, this);
+}
+
+void WorkerMessageFilter::OnForwardToWorker(const IPC::Message& message) {
+ WorkerService::GetInstance()->ForwardToWorker(message, this);
+}
+
+void WorkerMessageFilter::OnDocumentDetached(unsigned long long document_id) {
+ WorkerService::GetInstance()->DocumentDetached(document_id, this);
+}
+
+void WorkerMessageFilter::OnCreateMessagePort(int *route_id,
+ int* message_port_id) {
+ *route_id = next_routing_id_->Run();
+ MessagePortService::GetInstance()->Create(*route_id, this, message_port_id);
+}
diff --git a/chrome/browser/worker_host/worker_message_filter.h b/chrome/browser/worker_host/worker_message_filter.h
new file mode 100644
index 0000000..2e32dab
--- /dev/null
+++ b/chrome/browser/worker_host/worker_message_filter.h
@@ -0,0 +1,62 @@
+// 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.
+
+#ifndef CHROME_BROWSER_WORKER_HOST_WORKER_MESSAGE_FILTER_H_
+#define CHROME_BROWSER_WORKER_HOST_WORKER_MESSAGE_FILTER_H_
+
+#include "base/callback.h"
+#include "chrome/browser/browser_message_filter.h"
+
+class ResourceDispatcherHost;
+class URLRequestContextGetter;
+struct ViewHostMsg_CreateWorker_Params;
+
+class WorkerMessageFilter : public BrowserMessageFilter {
+ public:
+ // |next_routing_id| is owned by this object. It can be used up until
+ // OnChannelClosing.
+ WorkerMessageFilter(
+ int render_process_id,
+ URLRequestContextGetter* request_context,
+ ResourceDispatcherHost* resource_dispatcher_host,
+ CallbackWithReturnValue<int>::Type* next_routing_id);
+
+ // BrowserMessageFilter implementation.
+ virtual void OnChannelClosing();
+ virtual bool OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok);
+
+ int GetNextRoutingID();
+ int render_process_id() const { return render_process_id_; }
+ ResourceDispatcherHost* resource_dispatcher_host() const {
+ return resource_dispatcher_host_;
+ }
+
+ private:
+ ~WorkerMessageFilter();
+
+ // Message handlers.
+ void OnCreateWorker(const ViewHostMsg_CreateWorker_Params& params,
+ int* route_id);
+ void OnLookupSharedWorker(const ViewHostMsg_CreateWorker_Params& params,
+ bool* exists,
+ int* route_id,
+ bool* url_error);
+ void OnCancelCreateDedicatedWorker(int route_id);
+ void OnForwardToWorker(const IPC::Message& message);
+ void OnDocumentDetached(unsigned long long document_id);
+ void OnCreateMessagePort(int* route_id, int* message_port_id);
+
+ int render_process_id_;
+ scoped_refptr<URLRequestContextGetter> request_context_;
+ ResourceDispatcherHost* resource_dispatcher_host_;
+
+ // This is guaranteed to be valid until OnChannelClosing is closed, and it's
+ // not used after.
+ scoped_ptr<CallbackWithReturnValue<int>::Type> next_routing_id_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(WorkerMessageFilter);
+};
+
+#endif // CHROME_BROWSER_WORKER_HOST_WORKER_MESSAGE_FILTER_H_
diff --git a/chrome/browser/worker_host/worker_process_host.cc b/chrome/browser/worker_host/worker_process_host.cc
index ec1eed1..2006e2f 100644
--- a/chrome/browser/worker_host/worker_process_host.cc
+++ b/chrome/browser/worker_host/worker_process_host.cc
@@ -15,23 +15,23 @@
#include "chrome/browser/appcache/appcache_dispatcher_host.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/child_process_security_policy.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/file_system/file_system_dispatcher_host.h"
-#include "chrome/browser/host_content_settings_map.h"
-#include "chrome/browser/mime_registry_dispatcher.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/mime_registry_message_filter.h"
#include "chrome/browser/net/chrome_url_request_context.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/renderer_host/blob_dispatcher_host.h"
-#include "chrome/browser/renderer_host/database_dispatcher_host.h"
-#include "chrome/browser/renderer_host/file_utilities_dispatcher_host.h"
+#include "chrome/browser/renderer_host/blob_message_filter.h"
+#include "chrome/browser/renderer_host/database_message_filter.h"
+#include "chrome/browser/renderer_host/file_utilities_message_filter.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
#include "chrome/browser/renderer_host/render_view_host_notification_task.h"
-#include "chrome/browser/renderer_host/resource_message_filter.h"
-#include "chrome/browser/worker_host/message_port_dispatcher.h"
+#include "chrome/browser/renderer_host/socket_stream_dispatcher_host.h"
+#include "chrome/browser/worker_host/message_port_service.h"
+#include "chrome/browser/worker_host/worker_message_filter.h"
#include "chrome/browser/worker_host/worker_service.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/debug_flags.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/render_messages_params.h"
#include "chrome/common/result_codes.h"
@@ -41,6 +41,30 @@
#include "net/base/registry_controlled_domain.h"
#include "webkit/fileapi/file_system_path_manager.h"
+namespace {
+
+// Helper class that we pass to SocketStreamDispatcherHost so that it can find
+// the right URLRequestContext for a request.
+class URLRequestContextOverride
+ : public ResourceMessageFilter::URLRequestContextOverride {
+ public:
+ explicit URLRequestContextOverride(
+ URLRequestContext* url_request_context)
+ : url_request_context_(url_request_context) {
+ }
+ virtual ~URLRequestContextOverride() {}
+
+ virtual URLRequestContext* GetRequestContext(
+ uint32 request_id, ResourceType::Type resource_type) {
+ return url_request_context_;
+ }
+
+ private:
+ URLRequestContext* url_request_context_;
+};
+
+} // namespace
+
// Notifies RenderViewHost that one or more worker objects crashed.
class WorkerCrashTask : public Task {
public:
@@ -66,50 +90,12 @@ class WorkerCrashTask : public Task {
WorkerProcessHost::WorkerProcessHost(
ResourceDispatcherHost* resource_dispatcher_host,
- ChromeURLRequestContext *request_context)
+ URLRequestContextGetter* request_context)
: BrowserChildProcessHost(WORKER_PROCESS, resource_dispatcher_host),
- request_context_(request_context),
- appcache_dispatcher_host_(
- new AppCacheDispatcherHost(request_context)),
- ALLOW_THIS_IN_INITIALIZER_LIST(blob_dispatcher_host_(
- new BlobDispatcherHost(
- this->id(), request_context->blob_storage_context()))),
- ALLOW_THIS_IN_INITIALIZER_LIST(file_system_dispatcher_host_(
- new FileSystemDispatcherHost(this, request_context))),
- ALLOW_THIS_IN_INITIALIZER_LIST(file_utilities_dispatcher_host_(
- new FileUtilitiesDispatcherHost(this, this->id()))),
- ALLOW_THIS_IN_INITIALIZER_LIST(mime_registry_dispatcher_(
- new MimeRegistryDispatcher(this))) {
- next_route_id_callback_.reset(NewCallbackWithReturnValue(
- WorkerService::GetInstance(), &WorkerService::next_worker_route_id));
- db_dispatcher_host_ = new DatabaseDispatcherHost(
- request_context->database_tracker(), this,
- request_context_->host_content_settings_map());
- appcache_dispatcher_host_->Initialize(this);
+ request_context_(request_context) {
}
WorkerProcessHost::~WorkerProcessHost() {
- // Shut down the database dispatcher host.
- db_dispatcher_host_->Shutdown();
-
- // Shut down the blob dispatcher host.
- blob_dispatcher_host_->Shutdown();
-
- // Shut down the file system dispatcher host.
- file_system_dispatcher_host_->Shutdown();
-
- // Shut down the file utilities dispatcher host.
- file_utilities_dispatcher_host_->Shutdown();
-
- // Shut down the mime registry dispatcher host.
- mime_registry_dispatcher_->Shutdown();
-
- // Let interested observers know we are being deleted.
- NotificationService::current()->Notify(
- NotificationType::WORKER_PROCESS_HOST_SHUTDOWN,
- Source<WorkerProcessHost>(this),
- NotificationService::NoDetails());
-
// If we crashed, tell the RenderViewHosts.
for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
const WorkerDocumentSet::DocumentInfoSet& parents =
@@ -118,15 +104,15 @@ WorkerProcessHost::~WorkerProcessHost() {
parents.begin(); parent_iter != parents.end(); ++parent_iter) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
- new WorkerCrashTask(parent_iter->renderer_id(),
- parent_iter->render_view_route_id()));
+ new WorkerCrashTask(parent_iter->render_process_id(),
+ parent_iter->render_view_id()));
}
}
ChildProcessSecurityPolicy::GetInstance()->Remove(id());
}
-bool WorkerProcessHost::Init() {
+bool WorkerProcessHost::Init(int render_process_id) {
if (!CreateChannel())
return false;
@@ -200,7 +186,7 @@ bool WorkerProcessHost::Init() {
// requests them.
ChildProcessSecurityPolicy::GetInstance()->GrantPermissionsForFile(
id(),
- request_context_->browser_file_system_context()->
+ GetChromeURLRequestContext()->file_system_context()->
path_manager()->base_path(),
base::PLATFORM_FILE_OPEN |
base::PLATFORM_FILE_CREATE |
@@ -215,9 +201,38 @@ bool WorkerProcessHost::Init() {
base::PLATFORM_FILE_WRITE_ATTRIBUTES);
}
+ CreateMessageFilters(render_process_id);
+
return true;
}
+void WorkerProcessHost::CreateMessageFilters(int render_process_id) {
+ ChromeURLRequestContext* chrome_url_context = GetChromeURLRequestContext();
+
+ worker_message_filter_= new WorkerMessageFilter(
+ render_process_id,
+ request_context_,
+ resource_dispatcher_host(),
+ NewCallbackWithReturnValue(
+ WorkerService::GetInstance(), &WorkerService::next_worker_route_id));
+ AddFilter(worker_message_filter_);
+ AddFilter(new AppCacheDispatcherHost(chrome_url_context, id()));
+ AddFilter(new FileSystemDispatcherHost(chrome_url_context));
+ AddFilter(new FileUtilitiesMessageFilter(id()));
+ AddFilter(
+ new BlobMessageFilter(id(), chrome_url_context->blob_storage_context()));
+ AddFilter(new MimeRegistryMessageFilter());
+ AddFilter(new DatabaseMessageFilter(
+ chrome_url_context->database_tracker(),
+ chrome_url_context->host_content_settings_map()));
+
+ SocketStreamDispatcherHost* socket_stream_dispatcher_host =
+ new SocketStreamDispatcherHost();
+ socket_stream_dispatcher_host->set_url_request_context_override(
+ new URLRequestContextOverride(chrome_url_context));
+ AddFilter(socket_stream_dispatcher_host);
+}
+
void WorkerProcessHost::CreateWorker(const WorkerInstance& instance) {
ChildProcessSecurityPolicy::GetInstance()->GrantRequestURL(
id(), instance.url());
@@ -236,22 +251,21 @@ void WorkerProcessHost::CreateWorker(const WorkerInstance& instance) {
UpdateTitle();
- // Walk all pending senders and let them know the worker has been created
+ // Walk all pending filters and let them know the worker has been created
// (could be more than one in the case where we had to queue up worker
// creation because the worker process limit was reached).
- for (WorkerInstance::SenderList::const_iterator i =
- instance.senders().begin();
- i != instance.senders().end(); ++i) {
+ for (WorkerInstance::FilterList::const_iterator i =
+ instance.filters().begin();
+ i != instance.filters().end(); ++i) {
i->first->Send(new ViewMsg_WorkerCreated(i->second));
}
}
bool WorkerProcessHost::FilterMessage(const IPC::Message& message,
- IPC::Message::Sender* sender) {
+ WorkerMessageFilter* filter) {
for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
- if (!i->closed() && i->HasSender(sender, message.routing_id())) {
- RelayMessage(
- message, this, i->worker_route_id(), next_route_id_callback_.get());
+ if (!i->closed() && i->HasFilter(filter, message.routing_id())) {
+ RelayMessage(message, worker_message_filter_, i->worker_route_id());
return true;
}
}
@@ -259,111 +273,94 @@ bool WorkerProcessHost::FilterMessage(const IPC::Message& message,
return false;
}
-URLRequestContext* WorkerProcessHost::GetRequestContext(
- uint32 request_id,
- const ViewHostMsg_Resource_Request& request_data) {
- return request_context_;
-}
-
-// Sent to notify the browser process when a worker context invokes close(), so
-// no new connections are sent to shared workers.
-void WorkerProcessHost::OnWorkerContextClosed(int worker_route_id) {
- for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
- if (i->worker_route_id() == worker_route_id) {
- // Set the closed flag - this will stop any further messages from
- // being sent to the worker (messages can still be sent from the worker,
- // for exception reporting, etc).
- i->set_closed(true);
- break;
- }
- }
+void WorkerProcessHost::OnProcessLaunched() {
}
-void WorkerProcessHost::OnMessageReceived(const IPC::Message& message) {
+bool WorkerProcessHost::OnMessageReceived(const IPC::Message& message) {
bool msg_is_ok = true;
- bool handled =
- appcache_dispatcher_host_->OnMessageReceived(message, &msg_is_ok) ||
- db_dispatcher_host_->OnMessageReceived(message, &msg_is_ok) ||
- blob_dispatcher_host_->OnMessageReceived(message, &msg_is_ok) ||
- file_system_dispatcher_host_->OnMessageReceived(message, &msg_is_ok) ||
- file_utilities_dispatcher_host_->OnMessageReceived(message) ||
- mime_registry_dispatcher_->OnMessageReceived(message) ||
- MessagePortDispatcher::GetInstance()->OnMessageReceived(
- message, this, next_route_id_callback_.get(), &msg_is_ok);
-
- if (!handled) {
- handled = true;
- IPC_BEGIN_MESSAGE_MAP_EX(WorkerProcessHost, message, msg_is_ok)
- IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWorker, OnCreateWorker)
- IPC_MESSAGE_HANDLER(ViewHostMsg_LookupSharedWorker, OnLookupSharedWorker)
- IPC_MESSAGE_HANDLER(ViewHostMsg_CancelCreateDedicatedWorker,
- OnCancelCreateDedicatedWorker)
- IPC_MESSAGE_HANDLER(WorkerHostMsg_WorkerContextClosed,
- OnWorkerContextClosed);
- IPC_MESSAGE_HANDLER(ViewHostMsg_ForwardToWorker,
- OnForwardToWorker)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(WorkerProcessHostMsg_AllowDatabase,
- OnAllowDatabase)
- IPC_MESSAGE_UNHANDLED(handled = false)
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(WorkerProcessHost, message, msg_is_ok)
+ IPC_MESSAGE_HANDLER(WorkerHostMsg_WorkerContextClosed,
+ OnWorkerContextClosed)
+ IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_AllowDatabase, OnAllowDatabase)
+ IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP_EX()
- }
if (!msg_is_ok) {
NOTREACHED();
+ UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_WPH"));
base::KillProcess(handle(), ResultCodes::KILLED_BAD_MESSAGE, false);
}
if (handled)
- return;
+ return true;
for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
if (i->worker_route_id() == message.routing_id()) {
if (!i->shared()) {
// Don't relay messages from shared workers (all communication is via
// the message port).
- WorkerInstance::SenderInfo info = i->GetSender();
- CallbackWithReturnValue<int>::Type* next_route_id =
- GetNextRouteIdCallback(info.first);
- RelayMessage(message, info.first, info.second, next_route_id);
+ WorkerInstance::FilterInfo info = i->GetFilter();
+ RelayMessage(message, info.first, info.second);
}
if (message.type() == WorkerHostMsg_WorkerContextDestroyed::ID) {
instances_.erase(i);
UpdateTitle();
}
- break;
+ return true;
}
}
+ return false;
}
-void WorkerProcessHost::OnProcessLaunched() {
- db_dispatcher_host_->Init(handle());
- file_system_dispatcher_host_->Init(handle());
- file_utilities_dispatcher_host_->Init(handle());
+// Sent to notify the browser process when a worker context invokes close(), so
+// no new connections are sent to shared workers.
+void WorkerProcessHost::OnWorkerContextClosed(int worker_route_id) {
+ for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
+ if (i->worker_route_id() == worker_route_id) {
+ // Set the closed flag - this will stop any further messages from
+ // being sent to the worker (messages can still be sent from the worker,
+ // for exception reporting, etc).
+ i->set_closed(true);
+ break;
+ }
+ }
}
-CallbackWithReturnValue<int>::Type* WorkerProcessHost::GetNextRouteIdCallback(
- IPC::Message::Sender* sender) {
- // We don't keep callbacks for senders associated with workers, so figure out
- // what kind of sender this is, and cast it to the correct class to get the
- // callback.
- for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
- !iter.Done(); ++iter) {
- WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
- if (static_cast<IPC::Message::Sender*>(worker) == sender)
- return worker->next_route_id_callback_.get();
- }
+void WorkerProcessHost::OnAllowDatabase(int worker_route_id,
+ const GURL& url,
+ const string16& name,
+ const string16& display_name,
+ unsigned long estimated_size,
+ bool* result) {
+ ContentSetting content_setting = GetChromeURLRequestContext()->
+ host_content_settings_map()->GetContentSetting(
+ url, CONTENT_SETTINGS_TYPE_COOKIES, "");
+
+ *result = content_setting != CONTENT_SETTING_BLOCK;
- // Must be a ResourceMessageFilter.
- return static_cast<ResourceMessageFilter*>(sender)->next_route_id_callback();
+ // Find the worker instance and forward the message to all attached documents.
+ for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
+ if (i->worker_route_id() != worker_route_id)
+ continue;
+ const WorkerDocumentSet::DocumentInfoSet& documents =
+ i->worker_document_set()->documents();
+ for (WorkerDocumentSet::DocumentInfoSet::const_iterator doc =
+ documents.begin(); doc != documents.end(); ++doc) {
+ CallRenderViewHostContentSettingsDelegate(
+ doc->render_process_id(), doc->render_view_id(),
+ &RenderViewHostDelegate::ContentSettings::OnWebDatabaseAccessed,
+ url, name, display_name, estimated_size, !*result);
+ }
+ break;
+ }
}
void WorkerProcessHost::RelayMessage(
const IPC::Message& message,
- IPC::Message::Sender* sender,
- int route_id,
- CallbackWithReturnValue<int>::Type* next_route_id) {
-
+ WorkerMessageFilter* filter,
+ int route_id) {
if (message.type() == WorkerMsg_PostMessage::ID) {
// We want to send the receiver a routing id for the new channel, so
// crack the message first.
@@ -378,19 +375,19 @@ void WorkerProcessHost::RelayMessage(
return;
for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
- new_routing_ids[i] = next_route_id->Run();
- MessagePortDispatcher::GetInstance()->UpdateMessagePort(
- sent_message_port_ids[i], sender, new_routing_ids[i], next_route_id);
+ new_routing_ids[i] = filter->GetNextRoutingID();
+ MessagePortService::GetInstance()->UpdateMessagePort(
+ sent_message_port_ids[i], filter, new_routing_ids[i]);
}
- sender->Send(new WorkerMsg_PostMessage(
+ filter->Send(new WorkerMsg_PostMessage(
route_id, msg, sent_message_port_ids, new_routing_ids));
// Send any queued messages to the sent message ports. We can only do this
// after sending the above message, since it's the one that sets up the
// message port route which the queued messages are sent to.
for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
- MessagePortDispatcher::GetInstance()->
+ MessagePortService::GetInstance()->
SendQueuedMessagesIfPossible(sent_message_port_ids[i]);
}
} else if (message.type() == WorkerMsg_Connect::ID) {
@@ -401,35 +398,35 @@ void WorkerProcessHost::RelayMessage(
&message, &sent_message_port_id, &new_routing_id)) {
return;
}
- new_routing_id = next_route_id->Run();
- MessagePortDispatcher::GetInstance()->UpdateMessagePort(
- sent_message_port_id, sender, new_routing_id, next_route_id);
+ new_routing_id = filter->GetNextRoutingID();
+ MessagePortService::GetInstance()->UpdateMessagePort(
+ sent_message_port_id, filter, new_routing_id);
// Resend the message with the new routing id.
- sender->Send(new WorkerMsg_Connect(
+ filter->Send(new WorkerMsg_Connect(
route_id, sent_message_port_id, new_routing_id));
// Send any queued messages for the sent port.
- MessagePortDispatcher::GetInstance()->SendQueuedMessagesIfPossible(
+ MessagePortService::GetInstance()->SendQueuedMessagesIfPossible(
sent_message_port_id);
} else {
IPC::Message* new_message = new IPC::Message(message);
new_message->set_routing_id(route_id);
- sender->Send(new_message);
+ filter->Send(new_message);
return;
}
}
-void WorkerProcessHost::SenderShutdown(IPC::Message::Sender* sender) {
+void WorkerProcessHost::FilterShutdown(WorkerMessageFilter* filter) {
for (Instances::iterator i = instances_.begin(); i != instances_.end();) {
bool shutdown = false;
- i->RemoveSenders(sender);
+ i->RemoveFilters(filter);
if (i->shared()) {
- i->worker_document_set()->RemoveAll(sender);
+ i->worker_document_set()->RemoveAll(filter);
if (i->worker_document_set()->IsEmpty()) {
shutdown = true;
}
- } else if (i->NumSenders() == 0) {
+ } else if (i->NumFilters() == 0) {
shutdown = true;
}
if (shutdown) {
@@ -441,6 +438,10 @@ void WorkerProcessHost::SenderShutdown(IPC::Message::Sender* sender) {
}
}
+bool WorkerProcessHost::CanShutdown() {
+ return instances_.empty();
+}
+
void WorkerProcessHost::UpdateTitle() {
std::set<std::string> titles;
for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
@@ -452,8 +453,7 @@ void WorkerProcessHost::UpdateTitle() {
// Check if it's an extension-created worker, in which case we want to use
// the name of the extension.
- std::string extension_name = static_cast<ChromeURLRequestContext*>(
- Profile::GetDefaultRequestContext()->GetURLRequestContext())->
+ std::string extension_name = GetChromeURLRequestContext()->
extension_info_map()->GetNameForExtension(title);
if (!extension_name.empty()) {
titles.insert(extension_name);
@@ -477,96 +477,19 @@ void WorkerProcessHost::UpdateTitle() {
set_name(ASCIIToWide(display_title));
}
-void WorkerProcessHost::OnLookupSharedWorker(
- const ViewHostMsg_CreateWorker_Params& params,
- bool* exists,
- int* route_id,
- bool* url_mismatch) {
- *route_id = WorkerService::GetInstance()->next_worker_route_id();
- // TODO(atwilson): Add code to pass in the current worker's document set for
- // these nested workers. Code below will not work for SharedWorkers as it
- // only looks at a single parent.
- DCHECK(instances_.front().worker_document_set()->documents().size() == 1);
- WorkerDocumentSet::DocumentInfoSet::const_iterator first_parent =
- instances_.front().worker_document_set()->documents().begin();
- *exists = WorkerService::GetInstance()->LookupSharedWorker(
- params.url, params.name, instances_.front().off_the_record(),
- params.document_id, first_parent->renderer_id(),
- first_parent->render_view_route_id(), this, *route_id, url_mismatch);
-}
-
-void WorkerProcessHost::OnCreateWorker(
- const ViewHostMsg_CreateWorker_Params& params, int* route_id) {
- DCHECK(instances_.size() == 1); // Only called when one process per worker.
- // TODO(atwilson): Add code to pass in the current worker's document set for
- // these nested workers. Code below will not work for SharedWorkers as it
- // only looks at a single parent.
- DCHECK(instances_.front().worker_document_set()->documents().size() == 1);
- WorkerDocumentSet::DocumentInfoSet::const_iterator first_parent =
- instances_.front().worker_document_set()->documents().begin();
- *route_id = params.route_id == MSG_ROUTING_NONE ?
- WorkerService::GetInstance()->next_worker_route_id() : params.route_id;
-
- if (params.is_shared)
- WorkerService::GetInstance()->CreateSharedWorker(
- params.url, instances_.front().off_the_record(),
- params.name, params.document_id, first_parent->renderer_id(),
- first_parent->render_view_route_id(), this, *route_id,
- params.script_resource_appcache_id, request_context_);
- else
- WorkerService::GetInstance()->CreateDedicatedWorker(
- params.url, instances_.front().off_the_record(),
- params.document_id, first_parent->renderer_id(),
- first_parent->render_view_route_id(), this, *route_id,
- id(), params.parent_appcache_host_id, request_context_);
-}
-
-void WorkerProcessHost::OnCancelCreateDedicatedWorker(int route_id) {
- WorkerService::GetInstance()->CancelCreateDedicatedWorker(this, route_id);
-}
-
-void WorkerProcessHost::OnForwardToWorker(const IPC::Message& message) {
- WorkerService::GetInstance()->ForwardMessage(message, this);
-}
-
-void WorkerProcessHost::OnAllowDatabase(const GURL& url,
- const string16& name,
- const string16& display_name,
- unsigned long estimated_size,
- IPC::Message* reply_msg) {
- ContentSetting content_setting =
- request_context_->host_content_settings_map()->GetContentSetting(
- url, CONTENT_SETTINGS_TYPE_COOKIES, "");
-
- bool allowed = content_setting != CONTENT_SETTING_BLOCK;
-
- // Find the worker instance and forward the message to all attached documents.
- for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
- if (i->worker_route_id() != reply_msg->routing_id())
- continue;
- const WorkerDocumentSet::DocumentInfoSet& documents =
- i->worker_document_set()->documents();
- for (WorkerDocumentSet::DocumentInfoSet::const_iterator doc =
- documents.begin(); doc != documents.end(); ++doc) {
- CallRenderViewHostContentSettingsDelegate(
- doc->renderer_id(), doc->render_view_route_id(),
- &RenderViewHostDelegate::ContentSettings::OnWebDatabaseAccessed,
- url, name, display_name, estimated_size, !allowed);
- }
- break;
- }
- WorkerProcessHostMsg_AllowDatabase::WriteReplyParams(reply_msg, allowed);
- Send(reply_msg);
+ChromeURLRequestContext* WorkerProcessHost::GetChromeURLRequestContext() {
+ return static_cast<ChromeURLRequestContext*>(
+ request_context_->GetURLRequestContext());
}
-void WorkerProcessHost::DocumentDetached(IPC::Message::Sender* parent,
+void WorkerProcessHost::DocumentDetached(WorkerMessageFilter* filter,
unsigned long long document_id) {
// Walk all instances and remove the document from their document set.
for (Instances::iterator i = instances_.begin(); i != instances_.end();) {
if (!i->shared()) {
++i;
} else {
- i->worker_document_set()->Remove(parent, document_id);
+ i->worker_document_set()->Remove(filter, document_id);
if (i->worker_document_set()->IsEmpty()) {
// This worker has no more associated documents - shut it down.
Send(new WorkerMsg_TerminateWorkerContext(i->worker_route_id()));
@@ -587,7 +510,7 @@ WorkerProcessHost::WorkerInstance::WorkerInstance(
int parent_process_id,
int parent_appcache_host_id,
int64 main_resource_appcache_id,
- ChromeURLRequestContext* request_context)
+ URLRequestContextGetter* request_context)
: url_(url),
shared_(shared),
off_the_record_(off_the_record),
@@ -599,8 +522,6 @@ WorkerProcessHost::WorkerInstance::WorkerInstance(
main_resource_appcache_id_(main_resource_appcache_id),
request_context_(request_context),
worker_document_set_(new WorkerDocumentSet()) {
- DCHECK(!request_context ||
- (off_the_record == request_context->is_off_the_record()));
}
WorkerProcessHost::WorkerInstance::~WorkerInstance() {
@@ -631,65 +552,65 @@ bool WorkerProcessHost::WorkerInstance::Matches(
return name_ == match_name;
}
-void WorkerProcessHost::WorkerInstance::AddSender(IPC::Message::Sender* sender,
- int sender_route_id) {
- if (!HasSender(sender, sender_route_id)) {
- SenderInfo info(sender, sender_route_id);
- senders_.push_back(info);
+void WorkerProcessHost::WorkerInstance::AddFilter(WorkerMessageFilter* filter,
+ int route_id) {
+ if (!HasFilter(filter, route_id)) {
+ FilterInfo info(filter, route_id);
+ filters_.push_back(info);
}
- // Only shared workers can have more than one associated sender.
- DCHECK(shared_ || senders_.size() == 1);
+ // Only shared workers can have more than one associated filter.
+ DCHECK(shared_ || filters_.size() == 1);
}
-void WorkerProcessHost::WorkerInstance::RemoveSender(
- IPC::Message::Sender* sender, int sender_route_id) {
- for (SenderList::iterator i = senders_.begin(); i != senders_.end();) {
- if (i->first == sender && i->second == sender_route_id)
- i = senders_.erase(i);
+void WorkerProcessHost::WorkerInstance::RemoveFilter(
+ WorkerMessageFilter* filter, int route_id) {
+ for (FilterList::iterator i = filters_.begin(); i != filters_.end();) {
+ if (i->first == filter && i->second == route_id)
+ i = filters_.erase(i);
else
++i;
}
- // Should not be duplicate copies in the sender set.
- DCHECK(!HasSender(sender, sender_route_id));
+ // Should not be duplicate copies in the filter set.
+ DCHECK(!HasFilter(filter, route_id));
}
-void WorkerProcessHost::WorkerInstance::RemoveSenders(
- IPC::Message::Sender* sender) {
- for (SenderList::iterator i = senders_.begin(); i != senders_.end();) {
- if (i->first == sender)
- i = senders_.erase(i);
+void WorkerProcessHost::WorkerInstance::RemoveFilters(
+ WorkerMessageFilter* filter) {
+ for (FilterList::iterator i = filters_.begin(); i != filters_.end();) {
+ if (i->first == filter)
+ i = filters_.erase(i);
else
++i;
}
}
-bool WorkerProcessHost::WorkerInstance::HasSender(
- IPC::Message::Sender* sender, int sender_route_id) const {
- for (SenderList::const_iterator i = senders_.begin(); i != senders_.end();
+bool WorkerProcessHost::WorkerInstance::HasFilter(
+ WorkerMessageFilter* filter, int route_id) const {
+ for (FilterList::const_iterator i = filters_.begin(); i != filters_.end();
++i) {
- if (i->first == sender && i->second == sender_route_id)
+ if (i->first == filter && i->second == route_id)
return true;
}
return false;
}
bool WorkerProcessHost::WorkerInstance::RendererIsParent(
- int renderer_id, int render_view_route_id) const {
+ int render_process_id, int render_view_id) const {
const WorkerDocumentSet::DocumentInfoSet& parents =
worker_document_set()->documents();
for (WorkerDocumentSet::DocumentInfoSet::const_iterator parent_iter =
parents.begin();
parent_iter != parents.end(); ++parent_iter) {
- if (parent_iter->renderer_id() == renderer_id &&
- parent_iter->render_view_route_id() == render_view_route_id) {
+ if (parent_iter->render_process_id() == render_process_id &&
+ parent_iter->render_view_id() == render_view_id) {
return true;
}
}
return false;
}
-WorkerProcessHost::WorkerInstance::SenderInfo
-WorkerProcessHost::WorkerInstance::GetSender() const {
- DCHECK(NumSenders() == 1);
- return *senders_.begin();
+WorkerProcessHost::WorkerInstance::FilterInfo
+WorkerProcessHost::WorkerInstance::GetFilter() const {
+ DCHECK(NumFilters() == 1);
+ return *filters_.begin();
}
diff --git a/chrome/browser/worker_host/worker_process_host.h b/chrome/browser/worker_host/worker_process_host.h
index 2ddcdff..f3f6fdd 100644
--- a/chrome/browser/worker_host/worker_process_host.h
+++ b/chrome/browser/worker_host/worker_process_host.h
@@ -9,34 +9,19 @@
#include <list>
#include "base/basictypes.h"
-#include "base/callback.h"
#include "base/file_path.h"
-#include "base/ref_counted.h"
#include "chrome/browser/browser_child_process_host.h"
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/browser/worker_host/worker_document_set.h"
#include "googleurl/src/gurl.h"
-#include "ipc/ipc_channel.h"
-
-class AppCacheDispatcherHost;
-class BlobDispatcherHost;
-class ChromeURLRequestContext;
-class ChromeURLRequestContextGetter;
-class DatabaseDispatcherHost;
-class FileSystemDispatcherHost;
-class FileUtilitiesDispatcherHost;
-class MimeRegistryDispatcher;
-namespace webkit_database {
-class DatabaseTracker;
-} // namespace webkit_database
-
-struct ViewHostMsg_CreateWorker_Params;
+
+class URLRequestContextGetter;
// The WorkerProcessHost is the interface that represents the browser side of
// the browser <-> worker communication channel. There will be one
// WorkerProcessHost per worker process. Currently each worker runs in its own
// process, but that may change. However, we do assume [by storing a
-// ChromeURLRequestContext] that a WorkerProcessHost serves a single Profile.
+// URLRequestContext] that a WorkerProcessHost serves a single Profile.
class WorkerProcessHost : public BrowserChildProcessHost {
public:
@@ -52,24 +37,24 @@ class WorkerProcessHost : public BrowserChildProcessHost {
int parent_process_id,
int parent_appcache_host_id,
int64 main_resource_appcache_id,
- ChromeURLRequestContext* request_context);
+ URLRequestContextGetter* request_context);
~WorkerInstance();
// Unique identifier for a worker client.
- typedef std::pair<IPC::Message::Sender*, int> SenderInfo;
+ typedef std::pair<WorkerMessageFilter*, int> FilterInfo;
- // APIs to manage the sender list for a given instance.
- void AddSender(IPC::Message::Sender* sender, int sender_route_id);
- void RemoveSender(IPC::Message::Sender* sender, int sender_route_id);
- void RemoveSenders(IPC::Message::Sender* sender);
- bool HasSender(IPC::Message::Sender* sender, int sender_route_id) const;
- bool RendererIsParent(int renderer_id, int render_view_route_id) const;
- int NumSenders() const { return senders_.size(); }
- // Returns the single sender (must only be one).
- SenderInfo GetSender() const;
+ // APIs to manage the filter list for a given instance.
+ void AddFilter(WorkerMessageFilter* filter, int route_id);
+ void RemoveFilter(WorkerMessageFilter* filter, int route_id);
+ void RemoveFilters(WorkerMessageFilter* filter);
+ bool HasFilter(WorkerMessageFilter* filter, int route_id) const;
+ bool RendererIsParent(int render_process_id, int render_view_id) const;
+ int NumFilters() const { return filters_.size(); }
+ // Returns the single filter (must only be one).
+ FilterInfo GetFilter() const;
- typedef std::list<SenderInfo> SenderList;
- const SenderList& senders() const { return senders_; }
+ typedef std::list<FilterInfo> FilterList;
+ const FilterList& filters() const { return filters_; }
// Checks if this WorkerInstance matches the passed url/name params
// (per the comparison algorithm in the WebWorkers spec). This API only
@@ -100,12 +85,12 @@ class WorkerProcessHost : public BrowserChildProcessHost {
WorkerDocumentSet* worker_document_set() const {
return worker_document_set_;
}
- ChromeURLRequestContext* request_context() const {
+ URLRequestContextGetter* request_context() const {
return request_context_;
}
private:
- // Set of all senders (clients) associated with this worker.
+ // Set of all filters (clients) associated with this worker.
GURL url_;
bool shared_;
bool off_the_record_;
@@ -115,34 +100,36 @@ class WorkerProcessHost : public BrowserChildProcessHost {
int parent_process_id_;
int parent_appcache_host_id_;
int64 main_resource_appcache_id_;
- scoped_refptr<ChromeURLRequestContext> request_context_;
- SenderList senders_;
+ scoped_refptr<URLRequestContextGetter> request_context_;
+ FilterList filters_;
scoped_refptr<WorkerDocumentSet> worker_document_set_;
};
WorkerProcessHost(
ResourceDispatcherHost* resource_dispatcher_host,
- ChromeURLRequestContext* request_context);
+ URLRequestContextGetter* request_context);
~WorkerProcessHost();
// Starts the process. Returns true iff it succeeded.
- bool Init();
+ // |render_process_id| is the renderer process responsible for starting this
+ // worker.
+ bool Init(int render_process_id);
// Creates a worker object in the process.
void CreateWorker(const WorkerInstance& instance);
// Returns true iff the given message from a renderer process was forwarded to
// the worker.
- bool FilterMessage(const IPC::Message& message, IPC::Message::Sender* sender);
+ bool FilterMessage(const IPC::Message& message, WorkerMessageFilter* filter);
- void SenderShutdown(IPC::Message::Sender* sender);
+ void FilterShutdown(WorkerMessageFilter* filter);
// Shuts down any shared workers that are no longer referenced by active
// documents.
- void DocumentDetached(IPC::Message::Sender* sender,
+ void DocumentDetached(WorkerMessageFilter* filter,
unsigned long long document_id);
- ChromeURLRequestContext* request_context() const {
+ URLRequestContextGetter* request_context() const {
return request_context_;
}
@@ -154,68 +141,45 @@ class WorkerProcessHost : public BrowserChildProcessHost {
Instances& mutable_instances() { return instances_; }
private:
- // ResourceDispatcherHost::Receiver implementation:
- virtual URLRequestContext* GetRequestContext(
- uint32 request_id,
- const ViewHostMsg_Resource_Request& request_data);
-
- // Called when a message arrives from the worker process.
- virtual void OnMessageReceived(const IPC::Message& message);
-
// Called when the process has been launched successfully.
virtual void OnProcessLaunched();
- // Called when the app invokes close() from within worker context.
- void OnWorkerContextClosed(int worker_route_id);
+ // Creates and adds the message filters.
+ void CreateMessageFilters(int render_process_id);
- // Called if a worker tries to connect to a shared worker.
- void OnLookupSharedWorker(const ViewHostMsg_CreateWorker_Params& params,
- bool* exists,
- int* route_id,
- bool* url_error);
+ // IPC::Channel::Listener implementation:
+ // Called when a message arrives from the worker process.
+ virtual bool OnMessageReceived(const IPC::Message& message);
- // Given a Sender, returns the callback that generates a new routing id.
- static CallbackWithReturnValue<int>::Type* GetNextRouteIdCallback(
- IPC::Message::Sender* sender);
+ void OnWorkerContextClosed(int worker_route_id);
+ void OnAllowDatabase(int worker_route_id,
+ const GURL& url,
+ const string16& name,
+ const string16& display_name,
+ unsigned long estimated_size,
+ bool* result);
// Relays a message to the given endpoint. Takes care of parsing the message
// if it contains a message port and sending it a valid route id.
static void RelayMessage(const IPC::Message& message,
- IPC::Message::Sender* sender,
- int route_id,
- CallbackWithReturnValue<int>::Type* next_route_id);
+ WorkerMessageFilter* filter,
+ int route_id);
- virtual bool CanShutdown() { return instances_.empty(); }
+ virtual bool CanShutdown();
// Updates the title shown in the task manager.
void UpdateTitle();
- void OnCreateWorker(const ViewHostMsg_CreateWorker_Params& params,
- int* route_id);
- void OnCancelCreateDedicatedWorker(int route_id);
- void OnForwardToWorker(const IPC::Message& message);
-
- // Checks the content settings whether access to web databases is enabled and
- // relays the WebDatabaseAccessed message to all documents attached to a
- // worker.
- void OnAllowDatabase(const GURL& url,
- const string16& name,
- const string16& display_name,
- unsigned long estimated_size,
- IPC::Message* reply_msg);
+ ChromeURLRequestContext* GetChromeURLRequestContext();
Instances instances_;
- scoped_refptr<ChromeURLRequestContext> request_context_;
- scoped_ptr<AppCacheDispatcherHost> appcache_dispatcher_host_;
- scoped_refptr<DatabaseDispatcherHost> db_dispatcher_host_;
- scoped_ptr<BlobDispatcherHost> blob_dispatcher_host_;
- scoped_refptr<FileSystemDispatcherHost> file_system_dispatcher_host_;
- scoped_refptr<FileUtilitiesDispatcherHost> file_utilities_dispatcher_host_;
- scoped_refptr<MimeRegistryDispatcher> mime_registry_dispatcher_;
+ scoped_refptr<URLRequestContextGetter> request_context_;
- // A callback to create a routing id for the associated worker process.
- scoped_ptr<CallbackWithReturnValue<int>::Type> next_route_id_callback_;
+ // A reference to the filter associated with this worker process. We need to
+ // keep this around since we'll use it when forward messages to the worker
+ // process.
+ scoped_refptr<WorkerMessageFilter> worker_message_filter_;
DISALLOW_COPY_AND_ASSIGN(WorkerProcessHost);
};
diff --git a/chrome/browser/worker_host/worker_service.cc b/chrome/browser/worker_host/worker_service.cc
index 60fa03d..cea298d 100644
--- a/chrome/browser/worker_host/worker_service.cc
+++ b/chrome/browser/worker_host/worker_service.cc
@@ -4,19 +4,18 @@
#include "chrome/browser/worker_host/worker_service.h"
+#include <string>
+
#include "base/command_line.h"
#include "base/singleton.h"
#include "base/sys_info.h"
#include "base/thread.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/host_content_settings_map.h"
-#include "chrome/browser/plugin_service.h"
-#include "chrome/browser/renderer_host/render_process_host.h"
-#include "chrome/browser/renderer_host/resource_message_filter.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
+#include "chrome/browser/worker_host/worker_message_filter.h"
#include "chrome/browser/worker_host/worker_process_host.h"
#include "chrome/common/chrome_switches.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
#include "chrome/common/worker_messages.h"
#include "net/base/registry_controlled_domain.h"
@@ -28,97 +27,205 @@ WorkerService* WorkerService::GetInstance() {
return Singleton<WorkerService>::get();
}
-WorkerService::WorkerService()
- : next_worker_route_id_(0),
- resource_dispatcher_host_(NULL) {
- // Receive a notification if a message filter or WorkerProcessHost is deleted.
- registrar_.Add(this, NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN,
- NotificationService::AllSources());
-
- registrar_.Add(this, NotificationType::WORKER_PROCESS_HOST_SHUTDOWN,
- NotificationService::AllSources());
-}
-
-void WorkerService::Initialize(ResourceDispatcherHost* rdh) {
- resource_dispatcher_host_ = rdh;
+WorkerService::WorkerService() : next_worker_route_id_(0) {
}
WorkerService::~WorkerService() {
}
-bool WorkerService::CreateDedicatedWorker(
- const GURL& url,
- bool is_off_the_record,
- unsigned long long document_id,
- int renderer_pid,
- int render_view_route_id,
- IPC::Message::Sender* sender,
- int sender_route_id,
- int parent_process_id,
- int parent_appcache_host_id,
- ChromeURLRequestContext* request_context) {
- return CreateWorker(url, false, is_off_the_record, string16(),
- document_id, renderer_pid, render_view_route_id,
- sender, sender_route_id,
- parent_process_id, parent_appcache_host_id, 0,
- request_context);
-}
+void WorkerService::OnWorkerMessageFilterClosing(WorkerMessageFilter* filter) {
+ for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
+ !iter.Done(); ++iter) {
+ WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
+ worker->FilterShutdown(filter);
+ }
+
+ // See if that process had any queued workers.
+ for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin();
+ i != queued_workers_.end();) {
+ i->RemoveFilters(filter);
+ if (i->NumFilters() == 0) {
+ i = queued_workers_.erase(i);
+ } else {
+ ++i;
+ }
+ }
-bool WorkerService::CreateSharedWorker(
- const GURL& url,
- bool is_off_the_record,
- const string16& name,
- unsigned long long document_id,
- int renderer_pid,
- int render_view_route_id,
- IPC::Message::Sender* sender,
- int sender_route_id,
- int64 main_resource_appcache_id,
- ChromeURLRequestContext* request_context) {
- return CreateWorker(url, true, is_off_the_record, name,
- document_id, renderer_pid, render_view_route_id,
- sender, sender_route_id,
- 0, 0, main_resource_appcache_id,
- request_context);
+ // Also, see if that process had any pending shared workers.
+ for (WorkerProcessHost::Instances::iterator iter =
+ pending_shared_workers_.begin();
+ iter != pending_shared_workers_.end(); ) {
+ iter->worker_document_set()->RemoveAll(filter);
+ if (iter->worker_document_set()->IsEmpty()) {
+ iter = pending_shared_workers_.erase(iter);
+ } else {
+ ++iter;
+ }
+ }
+
+ // Either a worker proceess has shut down, in which case we can start one of
+ // the queued workers, or a renderer has shut down, in which case it doesn't
+ // affect anything. We call this function in both scenarios because then we
+ // don't have to keep track which filters are from worker processes.
+ TryStartingQueuedWorker();
}
-bool WorkerService::CreateWorker(
- const GURL& url,
- bool is_shared,
- bool off_the_record,
- const string16& name,
- unsigned long long document_id,
- int renderer_id,
- int render_view_route_id,
- IPC::Message::Sender* sender,
- int sender_route_id,
- int parent_process_id,
- int parent_appcache_host_id,
- int64 main_resource_appcache_id,
- ChromeURLRequestContext* request_context) {
+void WorkerService::CreateWorker(const ViewHostMsg_CreateWorker_Params& params,
+ int route_id,
+ WorkerMessageFilter* filter,
+ URLRequestContextGetter* request_context) {
+
+ ChromeURLRequestContext* context = static_cast<ChromeURLRequestContext*>(
+ request_context->GetURLRequestContext());
+
// Generate a unique route id for the browser-worker communication that's
// unique among all worker processes. That way when the worker process sends
// a wrapped IPC message through us, we know which WorkerProcessHost to give
// it to.
- WorkerProcessHost::WorkerInstance instance(url,
- is_shared,
- off_the_record,
- name,
- next_worker_route_id(),
- parent_process_id,
- parent_appcache_host_id,
- main_resource_appcache_id,
- request_context);
- instance.AddSender(sender, sender_route_id);
+ WorkerProcessHost::WorkerInstance instance(
+ params.url,
+ params.is_shared,
+ context->is_off_the_record(),
+ params.name,
+ next_worker_route_id(),
+ params.is_shared ? 0 : filter->render_process_id(),
+ params.is_shared ? 0 : params.parent_appcache_host_id,
+ params.is_shared ? params.script_resource_appcache_id : 0,
+ request_context);
+ instance.AddFilter(filter, route_id);
instance.worker_document_set()->Add(
- sender, document_id, renderer_id, render_view_route_id);
+ filter, params.document_id, filter->render_process_id(),
+ params.render_view_route_id);
- return CreateWorkerFromInstance(instance);
+ CreateWorkerFromInstance(instance);
+}
+
+void WorkerService::LookupSharedWorker(
+ const ViewHostMsg_CreateWorker_Params& params,
+ int route_id,
+ WorkerMessageFilter* filter,
+ bool off_the_record,
+ bool* exists,
+ bool* url_mismatch) {
+
+ *exists = true;
+ WorkerProcessHost::WorkerInstance* instance = FindSharedWorkerInstance(
+ params.url, params.name, off_the_record);
+
+ if (!instance) {
+ // If no worker instance currently exists, we need to create a pending
+ // instance - this is to make sure that any subsequent lookups passing a
+ // mismatched URL get the appropriate url_mismatch error at lookup time.
+ // Having named shared workers was a Really Bad Idea due to details like
+ // this.
+ instance = CreatePendingInstance(params.url, params.name, off_the_record);
+ *exists = false;
+ }
+
+ // Make sure the passed-in instance matches the URL - if not, return an
+ // error.
+ if (params.url != instance->url()) {
+ *url_mismatch = true;
+ *exists = false;
+ } else {
+ *url_mismatch = false;
+ // Add our route ID to the existing instance so we can send messages to it.
+ instance->AddFilter(filter, route_id);
+
+ // Add the passed filter/document_id to the worker instance.
+ // TODO(atwilson): This won't work if the message is from a worker process.
+ // We don't support that yet though (this message is only sent from
+ // renderers) but when we do, we'll need to add code to pass in the current
+ // worker's document set for nested workers.
+ instance->worker_document_set()->Add(
+ filter, params.document_id, filter->render_process_id(),
+ params.render_view_route_id);
+ }
+}
+
+void WorkerService::CancelCreateDedicatedWorker(
+ int route_id,
+ WorkerMessageFilter* filter) {
+ for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin();
+ i != queued_workers_.end(); ++i) {
+ if (i->HasFilter(filter, route_id)) {
+ DCHECK(!i->shared());
+ queued_workers_.erase(i);
+ return;
+ }
+ }
+
+ // There could be a race condition where the WebWorkerProxy told us to cancel
+ // the worker right as we sent it a message say it's been created. Look at
+ // the running workers.
+ for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
+ !iter.Done(); ++iter) {
+ WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
+ for (WorkerProcessHost::Instances::const_iterator instance =
+ worker->instances().begin();
+ instance != worker->instances().end(); ++instance) {
+ if (instance->HasFilter(filter, route_id)) {
+ // Fake a worker destroyed message so that WorkerProcessHost cleans up
+ // properly.
+ WorkerHostMsg_WorkerContextDestroyed message(route_id);
+ ForwardToWorker(message, filter);
+ return;
+ }
+ }
+ }
+
+ DCHECK(false) << "Couldn't find worker to cancel";
+}
+
+void WorkerService::ForwardToWorker(const IPC::Message& message,
+ WorkerMessageFilter* filter) {
+ for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
+ !iter.Done(); ++iter) {
+ WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
+ if (worker->FilterMessage(message, filter))
+ return;
+ }
+
+ // TODO(jabdelmalek): tell filter that callee is gone
+}
+
+void WorkerService::DocumentDetached(unsigned long long document_id,
+ WorkerMessageFilter* filter) {
+ // Any associated shared workers can be shut down.
+ for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
+ !iter.Done(); ++iter) {
+ WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
+ worker->DocumentDetached(filter, document_id);
+ }
+
+ // Remove any queued shared workers for this document.
+ for (WorkerProcessHost::Instances::iterator iter = queued_workers_.begin();
+ iter != queued_workers_.end();) {
+ if (iter->shared()) {
+ iter->worker_document_set()->Remove(filter, document_id);
+ if (iter->worker_document_set()->IsEmpty()) {
+ iter = queued_workers_.erase(iter);
+ continue;
+ }
+ }
+ ++iter;
+ }
+
+ // Remove the document from any pending shared workers.
+ for (WorkerProcessHost::Instances::iterator iter =
+ pending_shared_workers_.begin();
+ iter != pending_shared_workers_.end(); ) {
+ iter->worker_document_set()->Remove(filter, document_id);
+ if (iter->worker_document_set()->IsEmpty()) {
+ iter = pending_shared_workers_.erase(iter);
+ } else {
+ ++iter;
+ }
+ }
}
bool WorkerService::CreateWorkerFromInstance(
WorkerProcessHost::WorkerInstance instance) {
-
// TODO(michaeln): We need to ensure that a process is working
// on behalf of a single profile. The process sharing logic below
// does not ensure that. Consider making WorkerService a per profile
@@ -144,17 +251,17 @@ bool WorkerService::CreateWorkerFromInstance(
WorkerProcessHost::WorkerInstance* existing_instance =
FindSharedWorkerInstance(
instance.url(), instance.name(), instance.off_the_record());
- WorkerProcessHost::WorkerInstance::SenderInfo sender_info =
- instance.GetSender();
+ WorkerProcessHost::WorkerInstance::FilterInfo filter_info =
+ instance.GetFilter();
// If this worker is already running, no need to create a new copy. Just
// inform the caller that the worker has been created.
if (existing_instance) {
- // Walk the worker's sender list to see if this client is listed. If not,
+ // Walk the worker's filter list to see if this client is listed. If not,
// then it means that the worker started by the client already exited so
// we should not attach to this new one (http://crbug.com/29243).
- if (!existing_instance->HasSender(sender_info.first, sender_info.second))
+ if (!existing_instance->HasFilter(filter_info.first, filter_info.second))
return false;
- sender_info.first->Send(new ViewMsg_WorkerCreated(sender_info.second));
+ filter_info.first->Send(new ViewMsg_WorkerCreated(filter_info.second));
return true;
}
@@ -162,38 +269,38 @@ bool WorkerService::CreateWorkerFromInstance(
WorkerProcessHost::WorkerInstance* pending = FindPendingInstance(
instance.url(), instance.name(), instance.off_the_record());
// If there's no instance *and* no pending instance (or there is a pending
- // instance but it does not contain our sender info), then it means the
+ // instance but it does not contain our filter info), then it means the
// worker started up and exited already. Log a warning because this should
// be a very rare occurrence and is probably a bug, but it *can* happen so
// handle it gracefully.
if (!pending ||
- !pending->HasSender(sender_info.first, sender_info.second)) {
+ !pending->HasFilter(filter_info.first, filter_info.second)) {
DLOG(WARNING) << "Pending worker already exited";
return false;
}
- // Assign the accumulated document set and sender list for this pending
+ // Assign the accumulated document set and filter list for this pending
// worker to the new instance.
DCHECK(!pending->worker_document_set()->IsEmpty());
instance.ShareDocumentSet(*pending);
- for (WorkerProcessHost::WorkerInstance::SenderList::const_iterator i =
- pending->senders().begin();
- i != pending->senders().end(); ++i) {
- instance.AddSender(i->first, i->second);
+ for (WorkerProcessHost::WorkerInstance::FilterList::const_iterator i =
+ pending->filters().begin();
+ i != pending->filters().end(); ++i) {
+ instance.AddFilter(i->first, i->second);
}
RemovePendingInstances(
instance.url(), instance.name(), instance.off_the_record());
- // Remove any queued instances of this worker and copy over the sender to
+ // Remove any queued instances of this worker and copy over the filter to
// this instance.
for (WorkerProcessHost::Instances::iterator iter = queued_workers_.begin();
iter != queued_workers_.end();) {
if (iter->Matches(instance.url(), instance.name(),
instance.off_the_record())) {
- DCHECK(iter->NumSenders() == 1);
- WorkerProcessHost::WorkerInstance::SenderInfo sender_info =
- iter->GetSender();
- instance.AddSender(sender_info.first, sender_info.second);
+ DCHECK(iter->NumFilters() == 1);
+ WorkerProcessHost::WorkerInstance::FilterInfo filter_info =
+ iter->GetFilter();
+ instance.AddFilter(filter_info.first, filter_info.second);
iter = queued_workers_.erase(iter);
} else {
++iter;
@@ -202,9 +309,15 @@ bool WorkerService::CreateWorkerFromInstance(
}
if (!worker) {
- worker = new WorkerProcessHost(resource_dispatcher_host_,
- instance.request_context());
- if (!worker->Init()) {
+ WorkerMessageFilter* first_filter = instance.filters().begin()->first;
+ worker = new WorkerProcessHost(
+ first_filter->resource_dispatcher_host(),
+ instance.request_context());
+ // TODO(atwilson): This won't work if the message is from a worker process.
+ // We don't support that yet though (this message is only sent from
+ // renderers) but when we do, we'll need to add code to pass in the current
+ // worker's document set for nested workers.
+ if (!worker->Init(first_filter->render_process_id())) {
delete worker;
return false;
}
@@ -218,128 +331,6 @@ bool WorkerService::CreateWorkerFromInstance(
return true;
}
-bool WorkerService::LookupSharedWorker(
- const GURL &url,
- const string16& name,
- bool off_the_record,
- unsigned long long document_id,
- int renderer_id,
- int render_view_route_id,
- IPC::Message::Sender* sender,
- int sender_route_id,
- bool* url_mismatch) {
- bool found_instance = true;
- WorkerProcessHost::WorkerInstance* instance =
- FindSharedWorkerInstance(url, name, off_the_record);
-
- if (!instance) {
- // If no worker instance currently exists, we need to create a pending
- // instance - this is to make sure that any subsequent lookups passing a
- // mismatched URL get the appropriate url_mismatch error at lookup time.
- // Having named shared workers was a Really Bad Idea due to details like
- // this.
- instance = CreatePendingInstance(url, name, off_the_record);
- found_instance = false;
- }
-
- // Make sure the passed-in instance matches the URL - if not, return an
- // error.
- if (url != instance->url()) {
- *url_mismatch = true;
- return false;
- } else {
- *url_mismatch = false;
- }
-
- // Add our route ID to the existing instance so we can send messages to it.
- instance->AddSender(sender, sender_route_id);
-
- // Add the passed sender/document_id to the worker instance.
- instance->worker_document_set()->Add(
- sender, document_id, renderer_id, render_view_route_id);
- return found_instance;
-}
-
-void WorkerService::DocumentDetached(IPC::Message::Sender* sender,
- unsigned long long document_id) {
- for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
- !iter.Done(); ++iter) {
- WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
- worker->DocumentDetached(sender, document_id);
- }
-
- // Remove any queued shared workers for this document.
- for (WorkerProcessHost::Instances::iterator iter = queued_workers_.begin();
- iter != queued_workers_.end();) {
- if (iter->shared()) {
- iter->worker_document_set()->Remove(sender, document_id);
- if (iter->worker_document_set()->IsEmpty()) {
- iter = queued_workers_.erase(iter);
- continue;
- }
- }
- ++iter;
- }
-
- // Remove the document from any pending shared workers.
- for (WorkerProcessHost::Instances::iterator iter =
- pending_shared_workers_.begin();
- iter != pending_shared_workers_.end(); ) {
- iter->worker_document_set()->Remove(sender, document_id);
- if (iter->worker_document_set()->IsEmpty()) {
- iter = pending_shared_workers_.erase(iter);
- } else {
- ++iter;
- }
- }
-
-}
-
-void WorkerService::CancelCreateDedicatedWorker(IPC::Message::Sender* sender,
- int sender_route_id) {
- for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin();
- i != queued_workers_.end(); ++i) {
- if (i->HasSender(sender, sender_route_id)) {
- DCHECK(!i->shared());
- queued_workers_.erase(i);
- return;
- }
- }
-
- // There could be a race condition where the WebWorkerProxy told us to cancel
- // the worker right as we sent it a message say it's been created. Look at
- // the running workers.
- for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
- !iter.Done(); ++iter) {
- WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
- for (WorkerProcessHost::Instances::const_iterator instance =
- worker->instances().begin();
- instance != worker->instances().end(); ++instance) {
- if (instance->HasSender(sender, sender_route_id)) {
- // Fake a worker destroyed message so that WorkerProcessHost cleans up
- // properly.
- WorkerHostMsg_WorkerContextDestroyed msg(sender_route_id);
- ForwardMessage(msg, sender);
- return;
- }
- }
- }
-
- DCHECK(false) << "Couldn't find worker to cancel";
-}
-
-void WorkerService::ForwardMessage(const IPC::Message& message,
- IPC::Message::Sender* sender) {
- for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
- !iter.Done(); ++iter) {
- WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
- if (worker->FilterMessage(message, sender))
- return;
- }
-
- // TODO(jabdelmalek): tell sender that callee is gone
-}
-
WorkerProcessHost* WorkerService::GetProcessForDomain(const GURL& url) {
int num_processes = 0;
std::string domain =
@@ -398,8 +389,8 @@ bool WorkerService::CanCreateWorkerProcess(
parents.begin();
parent_iter != parents.end(); ++parent_iter) {
bool hit_total_worker_limit = false;
- if (TabCanCreateWorkerProcess(parent_iter->renderer_id(),
- parent_iter->render_view_route_id(),
+ if (TabCanCreateWorkerProcess(parent_iter->render_process_id(),
+ parent_iter->render_view_id(),
&hit_total_worker_limit)) {
return true;
}
@@ -413,8 +404,8 @@ bool WorkerService::CanCreateWorkerProcess(
return false;
}
-bool WorkerService::TabCanCreateWorkerProcess(int renderer_id,
- int render_view_route_id,
+bool WorkerService::TabCanCreateWorkerProcess(int render_process_id,
+ int render_view_id,
bool* hit_total_worker_limit) {
int total_workers = 0;
int workers_per_tab = 0;
@@ -430,7 +421,7 @@ bool WorkerService::TabCanCreateWorkerProcess(int renderer_id,
*hit_total_worker_limit = true;
return false;
}
- if (cur_instance->RendererIsParent(renderer_id, render_view_route_id)) {
+ if (cur_instance->RendererIsParent(render_process_id, render_view_id)) {
workers_per_tab++;
if (workers_per_tab >= kMaxWorkersPerTabWhenSeparate)
return false;
@@ -441,53 +432,7 @@ bool WorkerService::TabCanCreateWorkerProcess(int renderer_id,
return true;
}
-void WorkerService::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- if (type.value == NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN) {
- ResourceMessageFilter* sender = Source<ResourceMessageFilter>(source).ptr();
- SenderShutdown(sender);
- } else if (type.value == NotificationType::WORKER_PROCESS_HOST_SHUTDOWN) {
- WorkerProcessHost* sender = Source<WorkerProcessHost>(source).ptr();
- SenderShutdown(sender);
- WorkerProcessDestroyed(sender);
- } else {
- NOTREACHED();
- }
-}
-
-void WorkerService::SenderShutdown(IPC::Message::Sender* sender) {
- for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
- !iter.Done(); ++iter) {
- WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
- worker->SenderShutdown(sender);
- }
-
- // See if that render process had any queued workers.
- for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin();
- i != queued_workers_.end();) {
- i->RemoveSenders(sender);
- if (i->NumSenders() == 0) {
- i = queued_workers_.erase(i);
- } else {
- ++i;
- }
- }
-
- // Also, see if that render process had any pending shared workers.
- for (WorkerProcessHost::Instances::iterator iter =
- pending_shared_workers_.begin();
- iter != pending_shared_workers_.end(); ) {
- iter->worker_document_set()->RemoveAll(sender);
- if (iter->worker_document_set()->IsEmpty()) {
- iter = pending_shared_workers_.erase(iter);
- } else {
- ++iter;
- }
- }
-}
-
-void WorkerService::WorkerProcessDestroyed(WorkerProcessHost* process) {
+void WorkerService::TryStartingQueuedWorker() {
if (queued_workers_.empty())
return;
@@ -510,6 +455,30 @@ void WorkerService::WorkerProcessDestroyed(WorkerProcessHost* process) {
}
}
+bool WorkerService::GetRendererForWorker(int worker_process_id,
+ int* render_process_id,
+ int* render_view_id) const {
+ for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
+ !iter.Done(); ++iter) {
+ if (iter->id() != worker_process_id)
+ continue;
+
+ // This code assumes one worker per process, see function comment in header!
+ WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
+ WorkerProcessHost::Instances::const_iterator first_instance =
+ worker->instances().begin();
+ if (first_instance == worker->instances().end())
+ return false;
+
+ WorkerDocumentSet::DocumentInfoSet::const_iterator info =
+ first_instance->worker_document_set()->documents().begin();
+ *render_process_id = info->render_process_id();
+ *render_view_id = info->render_view_id();
+ return true;
+ }
+ return false;
+}
+
const WorkerProcessHost::WorkerInstance* WorkerService::FindWorkerInstance(
int worker_process_id) {
for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
diff --git a/chrome/browser/worker_host/worker_service.h b/chrome/browser/worker_host/worker_service.h
index 744f116..7c39d57 100644
--- a/chrome/browser/worker_host/worker_service.h
+++ b/chrome/browser/worker_host/worker_service.h
@@ -11,83 +11,50 @@
#include "base/basictypes.h"
#include "base/singleton.h"
#include "chrome/browser/worker_host/worker_process_host.h"
-#include "chrome/common/notification_registrar.h"
#include "googleurl/src/gurl.h"
#include "ipc/ipc_message.h"
-class ChromeURLRequestContext;
-class ResourceDispatcherHost;
+class URLRequestContextGetter;
+struct ViewHostMsg_CreateWorker_Params;
-class WorkerService : public NotificationObserver {
+// A singelton for managing HTML5 web workers.
+class WorkerService {
public:
// Returns the WorkerService singleton.
static WorkerService* GetInstance();
- // Initialize the WorkerService. OK to be called multiple times.
- void Initialize(ResourceDispatcherHost* rdh);
-
- // Creates a decidated worker. Returns true on success.
- bool CreateDedicatedWorker(const GURL &url,
- bool is_off_the_record,
- unsigned long long document_id,
- int renderer_pid,
- int render_view_route_id,
- IPC::Message::Sender* sender,
- int sender_route_id,
- int parent_process_id,
- int parent_appcache_host_id,
- ChromeURLRequestContext* request_context);
-
- // Creates a shared worker. Returns true on success.
- bool CreateSharedWorker(const GURL &url,
- bool is_off_the_record,
- const string16& name,
- unsigned long long document_id,
- int renderer_pid,
- int render_view_route_id,
- IPC::Message::Sender* sender,
- int sender_route_id,
- int64 main_resource_appcache_id,
- ChromeURLRequestContext* request_context);
-
- // Validates the passed URL and checks for the existence of matching shared
- // worker. Returns true if the url was found, and sets the url_mismatch out
- // param to true/false depending on whether there's a url mismatch with an
- // existing shared worker with the same name.
- bool LookupSharedWorker(const GURL &url,
- const string16& name,
+ // These methods correspond to worker related IPCs.
+ void CreateWorker(const ViewHostMsg_CreateWorker_Params& params,
+ int route_id,
+ WorkerMessageFilter* filter,
+ URLRequestContextGetter* request_context);
+ void LookupSharedWorker(const ViewHostMsg_CreateWorker_Params& params,
+ int route_id,
+ WorkerMessageFilter* filter,
bool off_the_record,
- unsigned long long document_id,
- int renderer_pid,
- int render_view_route_id,
- IPC::Message::Sender* sender,
- int sender_route_id,
- bool* url_mismatch);
-
- // Notification from the renderer that a given document has detached, so any
- // associated shared workers can be shut down.
- void DocumentDetached(IPC::Message::Sender* sender,
- unsigned long long document_id);
-
- // Cancel creation of a dedicated worker that hasn't started yet.
- void CancelCreateDedicatedWorker(IPC::Message::Sender* sender,
- int sender_route_id);
-
- // Called by the worker creator when a message arrives that should be
- // forwarded to the worker process.
- void ForwardMessage(const IPC::Message& message,
- IPC::Message::Sender* sender);
+ bool* exists,
+ bool* url_error);
+ void CancelCreateDedicatedWorker(int route_id, WorkerMessageFilter* filter);
+ void ForwardToWorker(const IPC::Message& message,
+ WorkerMessageFilter* filter);
+ void DocumentDetached(unsigned long long document_id,
+ WorkerMessageFilter* filter);
+
+ void OnWorkerMessageFilterClosing(WorkerMessageFilter* filter);
int next_worker_route_id() { return ++next_worker_route_id_; }
+ // Given a worker's process id, return the IDs of the renderer process and
+ // render view that created it. For shared workers, this returns the first
+ // parent.
// TODO(dimich): This code assumes there is 1 worker per worker process, which
// is how it is today until V8 can run in separate threads.
+ bool GetRendererForWorker(int worker_process_id,
+ int* render_process_id,
+ int* render_view_id) const;
const WorkerProcessHost::WorkerInstance* FindWorkerInstance(
int worker_process_id);
- WorkerProcessHost::WorkerInstance* FindSharedWorkerInstance(
- const GURL& url, const string16& name, bool off_the_record);
-
// Used when multiple workers can run in the same process.
static const int kMaxWorkerProcessesWhenSharing;
@@ -101,20 +68,6 @@ class WorkerService : public NotificationObserver {
WorkerService();
~WorkerService();
- bool CreateWorker(const GURL &url,
- bool is_shared,
- bool is_off_the_record,
- const string16& name,
- unsigned long long document_id,
- int renderer_pid,
- int render_view_route_id,
- IPC::Message::Sender* sender,
- int sender_route_id,
- int parent_process_id,
- int parent_appcache_host_id,
- int64 main_resource_appcache_id,
- ChromeURLRequestContext* request_context);
-
// Given a WorkerInstance, create an associated worker process.
bool CreateWorkerFromInstance(WorkerProcessHost::WorkerInstance instance);
@@ -139,18 +92,10 @@ class WorkerService : public NotificationObserver {
// worker process based on the process limit when we're using a strategy of
// one worker per process.
bool TabCanCreateWorkerProcess(
- int renderer_id, int render_view_route_id, bool* hit_total_worker_limit);
+ int render_process_id, int render_route_id, bool* hit_total_worker_limit);
- // NotificationObserver interface.
- void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- // Notifies us that a process that's talking to a worker has shut down.
- void SenderShutdown(IPC::Message::Sender* sender);
-
- // Notifies us that a worker process has closed.
- void WorkerProcessDestroyed(WorkerProcessHost* process);
+ // Tries to see if any of the queued workers can be created.
+ void TryStartingQueuedWorker();
// APIs for manipulating our set of pending shared worker instances.
WorkerProcessHost::WorkerInstance* CreatePendingInstance(
@@ -160,9 +105,11 @@ class WorkerService : public NotificationObserver {
void RemovePendingInstances(
const GURL& url, const string16& name, bool off_the_record);
+ WorkerProcessHost::WorkerInstance* FindSharedWorkerInstance(
+ const GURL& url, const string16& name, bool off_the_record);
+
NotificationRegistrar registrar_;
int next_worker_route_id_;
- ResourceDispatcherHost* resource_dispatcher_host_;
WorkerProcessHost::Instances queued_workers_;
diff --git a/chrome/browser/wrench_menu_model.cc b/chrome/browser/wrench_menu_model.cc
deleted file mode 100644
index ef43655..0000000
--- a/chrome/browser/wrench_menu_model.cc
+++ /dev/null
@@ -1,539 +0,0 @@
-// 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.
-
-#include "chrome/browser/wrench_menu_model.h"
-
-#include <algorithm>
-#include <cmath>
-
-#include "app/l10n_util.h"
-#include "app/menus/button_menu_item_model.h"
-#include "app/resource_bundle.h"
-#include "base/command_line.h"
-#include "base/i18n/number_formatting.h"
-#include "base/string_number_conversions.h"
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/background_page_tracker.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/defaults.h"
-#include "chrome/browser/encoding_menu_controller.h"
-#include "chrome/browser/profile.h"
-#include "chrome/browser/prefs/pref_service.h"
-#include "chrome/browser/sync/profile_sync_service.h"
-#include "chrome/browser/sync/sync_ui_util.h"
-#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/browser/tabs/tab_strip_model.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/upgrade_detector.h"
-#include "chrome/common/badge_util.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/notification_service.h"
-#include "chrome/common/notification_source.h"
-#include "chrome/common/notification_type.h"
-#include "chrome/common/pref_names.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-
-#if defined(OS_LINUX)
-#include <gtk/gtk.h>
-#include "chrome/browser/gtk/gtk_util.h"
-#endif
-
-#if defined(OS_MACOSX)
-#include "chrome/browser/browser_window.h"
-#endif
-
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/cros/cros_library.h"
-#include "chrome/browser/chromeos/cros/update_library.h"
-#endif
-
-#if defined(OS_WIN)
-#include "chrome/browser/enumerate_modules_model_win.h"
-#endif
-
-// The size of the font used for dynamic text overlays on menu items.
-const float kMenuBadgeFontSize = 12.0;
-
-namespace {
-SkBitmap GetBackgroundPageIcon() {
- string16 pages = base::FormatNumber(
- BackgroundPageTracker::GetSingleton()->GetBackgroundPageCount());
- return badge_util::DrawBadgeIconOverlay(
- *ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_BACKGROUND_MENU),
- kMenuBadgeFontSize,
- pages,
- l10n_util::GetStringUTF16(IDS_BACKGROUND_PAGE_BADGE_OVERFLOW));
-}
-
-} // namespace
-
-////////////////////////////////////////////////////////////////////////////////
-// EncodingMenuModel
-
-EncodingMenuModel::EncodingMenuModel(Browser* browser)
- : ALLOW_THIS_IN_INITIALIZER_LIST(menus::SimpleMenuModel(this)),
- browser_(browser) {
- Build();
-}
-
-EncodingMenuModel::~EncodingMenuModel() {
-}
-
-void EncodingMenuModel::Build() {
- EncodingMenuController::EncodingMenuItemList encoding_menu_items;
- EncodingMenuController encoding_menu_controller;
- encoding_menu_controller.GetEncodingMenuItems(browser_->profile(),
- &encoding_menu_items);
-
- int group_id = 0;
- EncodingMenuController::EncodingMenuItemList::iterator it =
- encoding_menu_items.begin();
- for (; it != encoding_menu_items.end(); ++it) {
- int id = it->first;
- string16& label = it->second;
- if (id == 0) {
- AddSeparator();
- } else {
- if (id == IDC_ENCODING_AUTO_DETECT) {
- AddCheckItem(id, label);
- } else {
- // Use the id of the first radio command as the id of the group.
- if (group_id <= 0)
- group_id = id;
- AddRadioItem(id, label, group_id);
- }
- }
- }
-}
-
-bool EncodingMenuModel::IsCommandIdChecked(int command_id) const {
- TabContents* current_tab = browser_->GetSelectedTabContents();
- if (!current_tab)
- return false;
- EncodingMenuController controller;
- return controller.IsItemChecked(browser_->profile(),
- current_tab->encoding(), command_id);
-}
-
-bool EncodingMenuModel::IsCommandIdEnabled(int command_id) const {
- bool enabled = browser_->command_updater()->IsCommandEnabled(command_id);
- // Special handling for the contents of the Encoding submenu. On Mac OS,
- // instead of enabling/disabling the top-level menu item, the submenu's
- // contents get disabled, per Apple's HIG.
-#if defined(OS_MACOSX)
- enabled &= browser_->command_updater()->IsCommandEnabled(IDC_ENCODING_MENU);
-#endif
- return enabled;
-}
-
-bool EncodingMenuModel::GetAcceleratorForCommandId(
- int command_id,
- menus::Accelerator* accelerator) {
- return false;
-}
-
-void EncodingMenuModel::ExecuteCommand(int command_id) {
- browser_->ExecuteCommand(command_id);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// ZoomMenuModel
-
-ZoomMenuModel::ZoomMenuModel(menus::SimpleMenuModel::Delegate* delegate)
- : SimpleMenuModel(delegate) {
- Build();
-}
-
-ZoomMenuModel::~ZoomMenuModel() {
-}
-
-void ZoomMenuModel::Build() {
- AddItemWithStringId(IDC_ZOOM_PLUS, IDS_ZOOM_PLUS);
- AddItemWithStringId(IDC_ZOOM_NORMAL, IDS_ZOOM_NORMAL);
- AddItemWithStringId(IDC_ZOOM_MINUS, IDS_ZOOM_MINUS);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// ToolsMenuModel
-
-ToolsMenuModel::ToolsMenuModel(menus::SimpleMenuModel::Delegate* delegate,
- Browser* browser)
- : SimpleMenuModel(delegate) {
- Build(browser);
-}
-
-ToolsMenuModel::~ToolsMenuModel() {}
-
-void ToolsMenuModel::Build(Browser* browser) {
- AddCheckItemWithStringId(IDC_SHOW_BOOKMARK_BAR, IDS_SHOW_BOOKMARK_BAR);
-
- AddSeparator();
-
-#if !defined(OS_CHROMEOS)
-#if defined(OS_MACOSX)
- AddItemWithStringId(IDC_CREATE_SHORTCUTS, IDS_CREATE_APPLICATION_MAC);
-#else
- AddItemWithStringId(IDC_CREATE_SHORTCUTS, IDS_CREATE_SHORTCUTS);
-#endif
- AddSeparator();
-#endif
-
- AddItemWithStringId(IDC_MANAGE_EXTENSIONS, IDS_SHOW_EXTENSIONS);
- AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER);
- AddItemWithStringId(IDC_CLEAR_BROWSING_DATA, IDS_CLEAR_BROWSING_DATA);
-
- AddSeparator();
-#if defined(OS_CHROMEOS) || defined(OS_WIN) || defined(OS_LINUX)
- AddItemWithStringId(IDC_FEEDBACK, IDS_FEEDBACK);
- AddSeparator();
-#endif
-
- encoding_menu_model_.reset(new EncodingMenuModel(browser));
- AddSubMenuWithStringId(IDC_ENCODING_MENU, IDS_ENCODING_MENU,
- encoding_menu_model_.get());
- AddItemWithStringId(IDC_VIEW_SOURCE, IDS_VIEW_SOURCE);
- if (g_browser_process->have_inspector_files()) {
- AddItemWithStringId(IDC_DEV_TOOLS, IDS_DEV_TOOLS);
- AddItemWithStringId(IDC_DEV_TOOLS_CONSOLE, IDS_DEV_TOOLS_CONSOLE);
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// WrenchMenuModel
-
-WrenchMenuModel::WrenchMenuModel(menus::AcceleratorProvider* provider,
- Browser* browser)
- : ALLOW_THIS_IN_INITIALIZER_LIST(menus::SimpleMenuModel(this)),
- provider_(provider),
- browser_(browser),
- tabstrip_model_(browser_->tabstrip_model()) {
- Build();
- UpdateZoomControls();
-
- tabstrip_model_->AddObserver(this);
-
- registrar_.Add(this, NotificationType::ZOOM_LEVEL_CHANGED,
- Source<Profile>(browser_->profile()));
- registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
- NotificationService::AllSources());
- registrar_.Add(this,
- NotificationType::BACKGROUND_PAGE_TRACKER_CHANGED,
- NotificationService::AllSources());
-}
-
-WrenchMenuModel::~WrenchMenuModel() {
- if (tabstrip_model_)
- tabstrip_model_->RemoveObserver(this);
-}
-
-bool WrenchMenuModel::DoesCommandIdDismissMenu(int command_id) const {
- return command_id != IDC_ZOOM_MINUS && command_id != IDC_ZOOM_PLUS;
-}
-
-bool WrenchMenuModel::IsLabelForCommandIdDynamic(int command_id) const {
- return command_id == IDC_ZOOM_PERCENT_DISPLAY ||
-#if defined(OS_MACOSX)
- command_id == IDC_FULLSCREEN ||
-#endif
- command_id == IDC_SYNC_BOOKMARKS ||
- command_id == IDC_VIEW_BACKGROUND_PAGES;
-}
-
-string16 WrenchMenuModel::GetLabelForCommandId(int command_id) const {
- switch (command_id) {
- case IDC_SYNC_BOOKMARKS:
- return GetSyncMenuLabel();
- case IDC_ZOOM_PERCENT_DISPLAY:
- return zoom_label_;
-#if defined(OS_MACOSX)
- case IDC_FULLSCREEN: {
- int string_id = IDS_ENTER_FULLSCREEN_MAC; // Default to Enter.
- // Note: On startup, |window()| may be NULL.
- if (browser_->window() && browser_->window()->IsFullscreen())
- string_id = IDS_EXIT_FULLSCREEN_MAC;
- return l10n_util::GetStringUTF16(string_id);
- }
-#endif
- case IDC_VIEW_BACKGROUND_PAGES: {
- string16 num_background_pages = base::FormatNumber(
- BackgroundPageTracker::GetSingleton()->GetBackgroundPageCount());
- return l10n_util::GetStringFUTF16(IDS_VIEW_BACKGROUND_PAGES,
- num_background_pages);
- }
- default:
- NOTREACHED();
- return string16();
- }
-}
-
-void WrenchMenuModel::ExecuteCommand(int command_id) {
- browser_->ExecuteCommand(command_id);
-}
-
-bool WrenchMenuModel::IsCommandIdChecked(int command_id) const {
- if (command_id == IDC_SHOW_BOOKMARK_BAR) {
- return browser_->profile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar);
- }
-
- return false;
-}
-
-bool WrenchMenuModel::IsCommandIdEnabled(int command_id) const {
-#if defined(OS_CHROMEOS)
- // Special case because IDC_NEW_WINDOW item should be disabled in BWSI mode,
- // but accelerator should work.
- if (command_id == IDC_NEW_WINDOW &&
- CommandLine::ForCurrentProcess()->HasSwitch(switches::kGuestSession))
- return false;
-#endif
-
- return browser_->command_updater()->IsCommandEnabled(command_id);
-}
-
-bool WrenchMenuModel::IsCommandIdVisible(int command_id) const {
- if (command_id == IDC_UPGRADE_DIALOG) {
-#if defined(OS_CHROMEOS)
- return (chromeos::CrosLibrary::Get()->GetUpdateLibrary()->status().status
- == chromeos::UPDATE_STATUS_UPDATED_NEED_REBOOT);
-#else
- return Singleton<UpgradeDetector>::get()->notify_upgrade();
-#endif
- } else if (command_id == IDC_VIEW_INCOMPATIBILITIES) {
-#if defined(OS_WIN)
- EnumerateModulesModel* loaded_modules =
- EnumerateModulesModel::GetSingleton();
- return loaded_modules->confirmed_bad_modules_detected() > 0;
-#else
- return false;
-#endif
- } else if (command_id == IDC_VIEW_BACKGROUND_PAGES) {
- BackgroundPageTracker* tracker = BackgroundPageTracker::GetSingleton();
- return tracker->GetBackgroundPageCount() > 0;
- }
- return true;
-}
-
-bool WrenchMenuModel::GetAcceleratorForCommandId(
- int command_id,
- menus::Accelerator* accelerator) {
- return provider_->GetAcceleratorForCommandId(command_id, accelerator);
-}
-
-void WrenchMenuModel::TabSelectedAt(TabContentsWrapper* old_contents,
- TabContentsWrapper* new_contents,
- int index,
- bool user_gesture) {
- // The user has switched between tabs and the new tab may have a different
- // zoom setting.
- UpdateZoomControls();
-}
-
-void WrenchMenuModel::TabReplacedAt(TabContentsWrapper* old_contents,
- TabContentsWrapper* new_contents,
- int index) {
- UpdateZoomControls();
-}
-
-void WrenchMenuModel::TabStripModelDeleted() {
- // During views shutdown, the tabstrip model/browser is deleted first, while
- // it is the opposite in gtk land.
- tabstrip_model_->RemoveObserver(this);
- tabstrip_model_ = NULL;
-}
-
-void WrenchMenuModel::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- switch (type.value) {
- case NotificationType::BACKGROUND_PAGE_TRACKER_CHANGED: {
- int num_pages = BackgroundPageTracker::GetSingleton()->
- GetUnacknowledgedBackgroundPageCount();
- if (num_pages > 0) {
- SetIcon(GetIndexOfCommandId(IDC_VIEW_BACKGROUND_PAGES),
- GetBackgroundPageIcon());
- } else {
- // Just set a blank icon (no icon).
- SetIcon(GetIndexOfCommandId(IDC_VIEW_BACKGROUND_PAGES), SkBitmap());
- }
- break;
- }
- case NotificationType::ZOOM_LEVEL_CHANGED:
- case NotificationType::NAV_ENTRY_COMMITTED:
- UpdateZoomControls();
- break;
- default:
- NOTREACHED();
- }
-}
-
-// For testing.
-WrenchMenuModel::WrenchMenuModel()
- : ALLOW_THIS_IN_INITIALIZER_LIST(menus::SimpleMenuModel(this)),
- provider_(NULL),
- browser_(NULL),
- tabstrip_model_(NULL) {
-}
-
-void WrenchMenuModel::Build() {
- AddItemWithStringId(IDC_NEW_TAB, IDS_NEW_TAB);
- AddItemWithStringId(IDC_NEW_WINDOW, IDS_NEW_WINDOW);
- AddItemWithStringId(IDC_NEW_INCOGNITO_WINDOW,
- IDS_NEW_INCOGNITO_WINDOW);
-
- AddSeparator();
-#if defined(OS_MACOSX) || (defined(OS_LINUX) && !defined(TOOLKIT_VIEWS))
- // WARNING: Mac does not use the ButtonMenuItemModel, but instead defines the
- // layout for this menu item in Toolbar.xib. It does, however, use the
- // command_id value from AddButtonItem() to identify this special item.
- edit_menu_item_model_.reset(new menus::ButtonMenuItemModel(IDS_EDIT, this));
- edit_menu_item_model_->AddGroupItemWithStringId(IDC_CUT, IDS_CUT);
- edit_menu_item_model_->AddGroupItemWithStringId(IDC_COPY, IDS_COPY);
- edit_menu_item_model_->AddGroupItemWithStringId(IDC_PASTE, IDS_PASTE);
- AddButtonItem(IDC_EDIT_MENU, edit_menu_item_model_.get());
-#else
- // TODO(port): Move to the above.
- CreateCutCopyPaste();
-#endif
-
- AddSeparator();
-#if defined(OS_MACOSX) || (defined(OS_LINUX) && !defined(TOOLKIT_VIEWS))
- // WARNING: See above comment.
- zoom_menu_item_model_.reset(
- new menus::ButtonMenuItemModel(IDS_ZOOM_MENU, this));
- zoom_menu_item_model_->AddGroupItemWithStringId(
- IDC_ZOOM_MINUS, IDS_ZOOM_MINUS2);
- zoom_menu_item_model_->AddButtonLabel(IDC_ZOOM_PERCENT_DISPLAY,
- IDS_ZOOM_PLUS2);
- zoom_menu_item_model_->AddGroupItemWithStringId(
- IDC_ZOOM_PLUS, IDS_ZOOM_PLUS2);
- zoom_menu_item_model_->AddSpace();
- zoom_menu_item_model_->AddItemWithImage(
- IDC_FULLSCREEN, IDR_FULLSCREEN_MENU_BUTTON);
- AddButtonItem(IDC_ZOOM_MENU, zoom_menu_item_model_.get());
-#else
- // TODO(port): Move to the above.
- CreateZoomFullscreen();
-#endif
-
- AddSeparator();
- AddItemWithStringId(IDC_SAVE_PAGE, IDS_SAVE_PAGE);
- AddItemWithStringId(IDC_FIND, IDS_FIND);
- AddItemWithStringId(IDC_PRINT, IDS_PRINT);
-
- tools_menu_model_.reset(new ToolsMenuModel(this, browser_));
- AddSubMenuWithStringId(IDC_ZOOM_MENU, IDS_TOOLS_MENU,
- tools_menu_model_.get());
-
- AddSeparator();
-#if defined(ENABLE_REMOTING)
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableRemoting)) {
- AddItem(IDC_REMOTING_SETUP,
- l10n_util::GetStringUTF16(IDS_REMOTING_SETUP_LABEL));
- }
-#endif
- AddItemWithStringId(IDC_SHOW_BOOKMARK_MANAGER, IDS_BOOKMARK_MANAGER);
- AddItemWithStringId(IDC_SHOW_HISTORY, IDS_SHOW_HISTORY);
- AddItemWithStringId(IDC_SHOW_DOWNLOADS, IDS_SHOW_DOWNLOADS);
- AddSeparator();
-
-#if defined(OS_CHROMEOS)
- AddItemWithStringId(IDC_OPTIONS, IDS_SETTINGS);
-#elif defined(OS_MACOSX)
- AddItemWithStringId(IDC_OPTIONS, IDS_PREFERENCES);
-#elif defined(OS_LINUX)
- string16 preferences = gtk_util::GetStockPreferencesMenuLabel();
- if (!preferences.empty())
- AddItem(IDC_OPTIONS, preferences);
- else
- AddItemWithStringId(IDC_OPTIONS, IDS_PREFERENCES);
-#else
- AddItemWithStringId(IDC_OPTIONS, IDS_OPTIONS);
-#endif
-
-#if defined(OS_CHROMEOS)
- const string16 product_name = l10n_util::GetStringUTF16(IDS_PRODUCT_OS_NAME);
-#else
- const string16 product_name = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
-#endif
- // On Mac, there is no About item.
- if (browser_defaults::kShowAboutMenuItem) {
- AddItem(IDC_ABOUT, l10n_util::GetStringFUTF16(
- IDS_ABOUT, product_name));
- }
- string16 num_background_pages = base::FormatNumber(
- BackgroundPageTracker::GetSingleton()->GetBackgroundPageCount());
- AddItem(IDC_VIEW_BACKGROUND_PAGES, l10n_util::GetStringFUTF16(
- IDS_VIEW_BACKGROUND_PAGES, num_background_pages));
- AddItem(IDC_UPGRADE_DIALOG, l10n_util::GetStringFUTF16(
- IDS_UPDATE_NOW, product_name));
- AddItem(IDC_VIEW_INCOMPATIBILITIES, l10n_util::GetStringUTF16(
- IDS_VIEW_INCOMPATIBILITIES));
-
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- SetIcon(GetIndexOfCommandId(IDC_UPGRADE_DIALOG),
- *rb.GetBitmapNamed(IDR_UPDATE_MENU));
-#if defined(OS_WIN)
- SetIcon(GetIndexOfCommandId(IDC_VIEW_INCOMPATIBILITIES),
- *rb.GetBitmapNamed(IDR_CONFLICT_MENU));
-#endif
-
- // Add an icon to the View Background Pages item if there are unacknowledged
- // pages.
- if (BackgroundPageTracker::GetSingleton()->
- GetUnacknowledgedBackgroundPageCount() > 0) {
- SetIcon(GetIndexOfCommandId(IDC_VIEW_BACKGROUND_PAGES),
- GetBackgroundPageIcon());
- }
-
- AddItemWithStringId(IDC_HELP_PAGE, IDS_HELP_PAGE);
- if (browser_defaults::kShowExitMenuItem) {
- AddSeparator();
-#if defined(OS_CHROMEOS)
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kGuestSession)) {
- AddItemWithStringId(IDC_EXIT, IDS_EXIT_GUEST_MODE);
- } else {
- AddItemWithStringId(IDC_EXIT, IDS_SIGN_OUT);
- }
-#else
- AddItemWithStringId(IDC_EXIT, IDS_EXIT);
-#endif
- }
-}
-
-void WrenchMenuModel::CreateCutCopyPaste() {
- // WARNING: views/wrench_menu assumes these items are added in this order. If
- // you change the order you'll need to update wrench_menu as well.
- AddItemWithStringId(IDC_CUT, IDS_CUT);
- AddItemWithStringId(IDC_COPY, IDS_COPY);
- AddItemWithStringId(IDC_PASTE, IDS_PASTE);
-}
-
-void WrenchMenuModel::CreateZoomFullscreen() {
- // WARNING: views/wrench_menu assumes these items are added in this order. If
- // you change the order you'll need to update wrench_menu as well.
- AddItemWithStringId(IDC_ZOOM_MINUS, IDS_ZOOM_MINUS);
- AddItemWithStringId(IDC_ZOOM_PLUS, IDS_ZOOM_PLUS);
- AddItemWithStringId(IDC_FULLSCREEN, IDS_FULLSCREEN);
-}
-
-void WrenchMenuModel::UpdateZoomControls() {
- bool enable_increment = false;
- bool enable_decrement = false;
- int zoom_percent = 100;
- if (browser_->GetSelectedTabContents()) {
- zoom_percent = browser_->GetSelectedTabContents()->GetZoomPercent(
- &enable_increment, &enable_decrement);
- }
- zoom_label_ = l10n_util::GetStringFUTF16(
- IDS_ZOOM_PERCENT, base::IntToString16(zoom_percent));
-}
-
-string16 WrenchMenuModel::GetSyncMenuLabel() const {
- return sync_ui_util::GetSyncMenuLabel(
- browser_->profile()->GetOriginalProfile()->GetProfileSyncService());
-}
diff --git a/chrome/browser/wrench_menu_model.h b/chrome/browser/wrench_menu_model.h
deleted file mode 100644
index 39f67b1..0000000
--- a/chrome/browser/wrench_menu_model.h
+++ /dev/null
@@ -1,149 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_WRENCH_MENU_MODEL_H_
-#define CHROME_BROWSER_WRENCH_MENU_MODEL_H_
-#pragma once
-
-#include "app/menus/accelerator.h"
-#include "app/menus/button_menu_item_model.h"
-#include "app/menus/simple_menu_model.h"
-#include "base/scoped_ptr.h"
-#include "chrome/browser/tabs/tab_strip_model_observer.h"
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
-
-class Browser;
-class TabStripModel;
-
-namespace {
-class MockWrenchMenuModel;
-} // namespace
-
-// A menu model that builds the contents of an encoding menu.
-class EncodingMenuModel : public menus::SimpleMenuModel,
- public menus::SimpleMenuModel::Delegate {
- public:
- explicit EncodingMenuModel(Browser* browser);
- virtual ~EncodingMenuModel();
-
- // Overridden from menus::SimpleMenuModel::Delegate:
- virtual bool IsCommandIdChecked(int command_id) const;
- virtual bool IsCommandIdEnabled(int command_id) const;
- virtual bool GetAcceleratorForCommandId(int command_id,
- menus::Accelerator* accelerator);
- virtual void ExecuteCommand(int command_id);
-
- private:
- void Build();
-
- Browser* browser_; // weak
-
- DISALLOW_COPY_AND_ASSIGN(EncodingMenuModel);
-};
-
-// A menu model that builds the contents of the zoom menu.
-class ZoomMenuModel : public menus::SimpleMenuModel {
- public:
- explicit ZoomMenuModel(menus::SimpleMenuModel::Delegate* delegate);
- virtual ~ZoomMenuModel();
-
- private:
- void Build();
-
- DISALLOW_COPY_AND_ASSIGN(ZoomMenuModel);
-};
-
-class ToolsMenuModel : public menus::SimpleMenuModel {
- public:
- ToolsMenuModel(menus::SimpleMenuModel::Delegate* delegate, Browser* browser);
- virtual ~ToolsMenuModel();
-
- private:
- void Build(Browser* browser);
-
- scoped_ptr<EncodingMenuModel> encoding_menu_model_;
-
- DISALLOW_COPY_AND_ASSIGN(ToolsMenuModel);
-};
-
-// A menu model that builds the contents of the wrench menu.
-class WrenchMenuModel : public menus::SimpleMenuModel,
- public menus::SimpleMenuModel::Delegate,
- public menus::ButtonMenuItemModel::Delegate,
- public TabStripModelObserver,
- public NotificationObserver {
- public:
- WrenchMenuModel(menus::AcceleratorProvider* provider, Browser* browser);
- virtual ~WrenchMenuModel();
-
- // Overridden for ButtonMenuItemModel::Delegate:
- virtual bool DoesCommandIdDismissMenu(int command_id) const;
-
- // Overridden for both ButtonMenuItemModel::Delegate and SimpleMenuModel:
- virtual bool IsLabelForCommandIdDynamic(int command_id) const;
- virtual string16 GetLabelForCommandId(int command_id) const;
- virtual void ExecuteCommand(int command_id);
- virtual bool IsCommandIdChecked(int command_id) const;
- virtual bool IsCommandIdEnabled(int command_id) const;
- virtual bool IsCommandIdVisible(int command_id) const;
- virtual bool GetAcceleratorForCommandId(
- int command_id,
- menus::Accelerator* accelerator);
-
- // Overridden from TabStripModelObserver:
- virtual void TabSelectedAt(TabContentsWrapper* old_contents,
- TabContentsWrapper* new_contents,
- int index,
- bool user_gesture);
- virtual void TabReplacedAt(TabContentsWrapper* old_contents,
- TabContentsWrapper* new_contents, int index);
- virtual void TabStripModelDeleted();
-
- // Overridden from NotificationObserver:
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- // Getters.
- Browser* browser() const { return browser_; }
-
- // Calculates |zoom_label_| in response to a zoom change.
- void UpdateZoomControls();
-
- private:
- // Testing constructor used for mocking.
- friend class ::MockWrenchMenuModel;
- WrenchMenuModel();
-
- void Build();
-
- // Adds custom items to the menu. Deprecated in favor of a cross platform
- // model for button items.
- void CreateCutCopyPaste();
- void CreateZoomFullscreen();
-
- string16 GetSyncMenuLabel() const;
-
- // Models for the special menu items with buttons.
- scoped_ptr<menus::ButtonMenuItemModel> edit_menu_item_model_;
- scoped_ptr<menus::ButtonMenuItemModel> zoom_menu_item_model_;
-
- // Label of the zoom label in the zoom menu item.
- string16 zoom_label_;
-
- // Tools menu.
- scoped_ptr<ToolsMenuModel> tools_menu_model_;
-
- menus::AcceleratorProvider* provider_; // weak
-
- Browser* browser_; // weak
- TabStripModel* tabstrip_model_; // weak
-
- NotificationRegistrar registrar_;
-
- DISALLOW_COPY_AND_ASSIGN(WrenchMenuModel);
-};
-
-#endif // CHROME_BROWSER_WRENCH_MENU_MODEL_H_
diff --git a/chrome/browser/wrench_menu_model_unittest.cc b/chrome/browser/wrench_menu_model_unittest.cc
deleted file mode 100644
index 188abf4..0000000
--- a/chrome/browser/wrench_menu_model_unittest.cc
+++ /dev/null
@@ -1,105 +0,0 @@
-// 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.
-
-#include "chrome/browser/wrench_menu_model.h"
-
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/test/browser_with_test_window_test.h"
-#include "chrome/test/menu_model_test.h"
-#include "chrome/test/testing_profile.h"
-#include "grit/generated_resources.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-class WrenchMenuModelTest : public BrowserWithTestWindowTest,
- public menus::AcceleratorProvider {
- public:
- // Don't handle accelerators.
- virtual bool GetAcceleratorForCommandId(
- int command_id,
- menus::Accelerator* accelerator) { return false; }
-};
-
-// Copies parts of MenuModelTest::Delegate and combines them with the
-// WrenchMenuModel since WrenchMenuModel is now a SimpleMenuModel::Delegate and
-// not derived from SimpleMenuModel.
-class TestWrenchMenuModel : public WrenchMenuModel {
- public:
- TestWrenchMenuModel(menus::AcceleratorProvider* provider,
- Browser* browser)
- : WrenchMenuModel(provider, browser),
- execute_count_(0),
- checked_count_(0),
- enable_count_(0) {
- }
-
- // Testing overrides to menus::SimpleMenuModel::Delegate:
- virtual bool IsCommandIdChecked(int command_id) const {
- bool val = WrenchMenuModel::IsCommandIdChecked(command_id);
- if (val)
- checked_count_++;
- return val;
- }
-
- virtual bool IsCommandIdEnabled(int command_id) const {
- ++enable_count_;
- return true;
- }
-
- virtual void ExecuteCommand(int command_id) { ++execute_count_; }
-
- int execute_count_;
- mutable int checked_count_;
- mutable int enable_count_;
-};
-
-TEST_F(WrenchMenuModelTest, Basics) {
- TestWrenchMenuModel model(this, browser());
- int itemCount = model.GetItemCount();
-
- // Verify it has items. The number varies by platform, so we don't check
- // the exact number.
- EXPECT_GT(itemCount, 10);
-
- // Execute a couple of the items and make sure it gets back to our delegate.
- // We can't use CountEnabledExecutable() here because the encoding menu's
- // delegate is internal, it doesn't use the one we pass in.
- model.ActivatedAt(0);
- EXPECT_TRUE(model.IsEnabledAt(0));
- // Make sure to use the index that is not separator in all configurations.
- model.ActivatedAt(2);
- EXPECT_TRUE(model.IsEnabledAt(2));
- EXPECT_EQ(model.execute_count_, 2);
- EXPECT_EQ(model.enable_count_, 2);
-
- model.execute_count_ = 0;
- model.enable_count_ = 0;
-
- // Choose something from the tools submenu and make sure it makes it back to
- // the delegate as well. Use the first submenu as the tools one.
- int toolsModelIndex = -1;
- for (int i = 0; i < itemCount; ++i) {
- if (model.GetTypeAt(i) == menus::MenuModel::TYPE_SUBMENU) {
- toolsModelIndex = i;
- break;
- }
- }
- EXPECT_GT(toolsModelIndex, -1);
- menus::MenuModel* toolsModel = model.GetSubmenuModelAt(toolsModelIndex);
- EXPECT_TRUE(toolsModel);
- EXPECT_GT(toolsModel->GetItemCount(), 2);
- toolsModel->ActivatedAt(2);
- EXPECT_TRUE(toolsModel->IsEnabledAt(2));
- EXPECT_EQ(model.execute_count_, 1);
- EXPECT_EQ(model.enable_count_, 1);
-}
-
-class EncodingMenuModelTest : public BrowserWithTestWindowTest,
- public MenuModelTest {
-};
-
-TEST_F(EncodingMenuModelTest, IsCommandIdCheckedWithNoTabs) {
- EncodingMenuModel model(browser());
- ASSERT_EQ(NULL, browser()->GetSelectedTabContents());
- EXPECT_FALSE(model.IsCommandIdChecked(IDC_ENCODING_ISO88591));
-}
diff --git a/chrome/browser/zygote_host_linux.cc b/chrome/browser/zygote_host_linux.cc
index b6115f1..6e2c7e3 100644
--- a/chrome/browser/zygote_host_linux.cc
+++ b/chrome/browser/zygote_host_linux.cc
@@ -20,14 +20,13 @@
#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/scoped_ptr.h"
-#include "base/unix_domain_socket_posix.h"
#include "base/utf_string_conversions.h"
-
#include "chrome/browser/renderer_host/render_sandbox_host_linux.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/process_watcher.h"
-
+#include "chrome/common/result_codes.h"
+#include "chrome/common/unix_domain_socket_posix.h"
#include "sandbox/linux/suid/suid_unsafe_environment_variables.h"
static void SaveSUIDUnsafeEnvironmentVariables() {
@@ -66,6 +65,11 @@ ZygoteHost::~ZygoteHost() {
close(control_fd_);
}
+// static
+ZygoteHost* ZygoteHost::GetInstance() {
+ return Singleton<ZygoteHost>::get();
+}
+
void ZygoteHost::Init(const std::string& sandbox_cmd) {
DCHECK(!init_);
init_ = true;
@@ -98,11 +102,8 @@ void ZygoteHost::Init(const std::string& sandbox_cmd) {
switches::kUserDataDir, // Make logs go to the right file.
// Load (in-process) Pepper plugins in-process in the zygote pre-sandbox.
switches::kRegisterPepperPlugins,
-#if defined(USE_SECCOMP_SANDBOX)
switches::kDisableSeccompSandbox,
-#else
switches::kEnableSeccompSandbox,
-#endif
};
cmd_line.CopySwitchesFrom(browser_command_line, kForwardSwitches,
arraysize(kForwardSwitches));
@@ -129,7 +130,7 @@ void ZygoteHost::Init(const std::string& sandbox_cmd) {
// Start up the sandbox host process and get the file descriptor for the
// renderers to talk to it.
- const int sfd = Singleton<RenderSandboxHostLinux>()->GetRendererSocket();
+ const int sfd = RenderSandboxHostLinux::GetInstance()->GetRendererSocket();
fds_to_map.push_back(std::make_pair(sfd, 5));
int dummy_fd = -1;
@@ -151,7 +152,8 @@ void ZygoteHost::Init(const std::string& sandbox_cmd) {
std::vector<int> fds_vec;
const int kExpectedLength = sizeof(kZygoteMagic);
char buf[kExpectedLength];
- const ssize_t len = base::RecvMsg(fds[0], buf, sizeof(buf), &fds_vec);
+ const ssize_t len = UnixDomainSocket::RecvMsg(fds[0], buf, sizeof(buf),
+ &fds_vec);
CHECK(len == kExpectedLength) << "Incorrect zygote magic length";
CHECK(0 == strcmp(buf, kZygoteMagic)) << "Incorrect zygote magic";
@@ -188,7 +190,8 @@ void ZygoteHost::Init(const std::string& sandbox_cmd) {
Pickle pickle;
pickle.WriteInt(kCmdGetSandboxStatus);
std::vector<int> empty_fds;
- if (!base::SendMsg(control_fd_, pickle.data(), pickle.size(), empty_fds))
+ if (!UnixDomainSocket::SendMsg(control_fd_, pickle.data(), pickle.size(),
+ empty_fds))
LOG(FATAL) << "Cannot communicate with zygote";
// We don't wait for the reply. We'll read it in ReadReply.
}
@@ -233,7 +236,8 @@ pid_t ZygoteHost::ForkRenderer(
pid_t pid;
{
AutoLock lock(control_lock_);
- if (!base::SendMsg(control_fd_, pickle.data(), pickle.size(), fds))
+ if (!UnixDomainSocket::SendMsg(control_fd_, pickle.data(), pickle.size(),
+ fds))
return base::kNullProcessHandle;
if (ReadReply(&pid, sizeof(pid)) != sizeof(pid))
@@ -311,13 +315,18 @@ void ZygoteHost::EnsureProcessTerminated(pid_t process) {
PLOG(ERROR) << "write";
}
-bool ZygoteHost::DidProcessCrash(base::ProcessHandle handle,
- bool* child_exited) {
+base::TerminationStatus ZygoteHost::GetTerminationStatus(
+ base::ProcessHandle handle,
+ int* exit_code) {
DCHECK(init_);
Pickle pickle;
- pickle.WriteInt(kCmdDidProcessCrash);
+ pickle.WriteInt(kCmdGetTerminationStatus);
pickle.WriteInt(handle);
+ // Set this now to handle the early termination cases.
+ if (exit_code)
+ *exit_code = ResultCodes::NORMAL_EXIT;
+
static const unsigned kMaxMessageLength = 128;
char buf[kMaxMessageLength];
ssize_t len;
@@ -331,23 +340,23 @@ bool ZygoteHost::DidProcessCrash(base::ProcessHandle handle,
if (len == -1) {
LOG(WARNING) << "Error reading message from zygote: " << errno;
- return false;
+ return base::TERMINATION_STATUS_NORMAL_TERMINATION;
} else if (len == 0) {
LOG(WARNING) << "Socket closed prematurely.";
- return false;
+ return base::TERMINATION_STATUS_NORMAL_TERMINATION;
}
Pickle read_pickle(buf, len);
- bool did_crash, tmp_child_exited;
+ int status, tmp_exit_code;
void* iter = NULL;
- if (!read_pickle.ReadBool(&iter, &did_crash) ||
- !read_pickle.ReadBool(&iter, &tmp_child_exited)) {
- LOG(WARNING) << "Error parsing DidProcessCrash response from zygote.";
- return false;
+ if (!read_pickle.ReadInt(&iter, &status) ||
+ !read_pickle.ReadInt(&iter, &tmp_exit_code)) {
+ LOG(WARNING) << "Error parsing GetTerminationStatus response from zygote.";
+ return base::TERMINATION_STATUS_NORMAL_TERMINATION;
}
- if (child_exited)
- *child_exited = tmp_child_exited;
+ if (exit_code)
+ *exit_code = tmp_exit_code;
- return did_crash;
+ return static_cast<base::TerminationStatus>(status);
}
diff --git a/chrome/browser/zygote_host_linux.h b/chrome/browser/zygote_host_linux.h
index ffb7964..e13f1b4 100644
--- a/chrome/browser/zygote_host_linux.h
+++ b/chrome/browser/zygote_host_linux.h
@@ -14,6 +14,7 @@
#include "base/global_descriptors_posix.h"
#include "base/lock.h"
#include "base/process.h"
+#include "base/process_util.h"
template<typename Type>
struct DefaultSingletonTraits;
@@ -26,6 +27,9 @@ static const char kZygoteMagic[] = "ZYGOTE_OK";
// process.
class ZygoteHost {
public:
+ // Returns the singleton instance.
+ static ZygoteHost* GetInstance();
+
void Init(const std::string& sandbox_cmd);
// Tries to start a renderer process. Returns its pid on success, otherwise
@@ -34,26 +38,27 @@ class ZygoteHost {
const base::GlobalDescriptors::Mapping& mapping);
void EnsureProcessTerminated(pid_t process);
- // Get the termination status (exit code) of the process and return true if
- // the status indicates the process crashed. |child_exited| is set to true
- // iff the child process has terminated. (|child_exited| may be NULL.)
- bool DidProcessCrash(base::ProcessHandle handle, bool* child_exited);
+ // Get the termination status (and, optionally, the exit code) of
+ // the process. |exit_code| is set to the exit code of the child
+ // process. (|exit_code| may be NULL.)
+ base::TerminationStatus GetTerminationStatus(base::ProcessHandle handle,
+ int* exit_code);
// These are the command codes used on the wire between the browser and the
// zygote.
enum {
- kCmdFork = 0, // Fork off a new renderer.
- kCmdReap = 1, // Reap a renderer child.
- kCmdDidProcessCrash = 2, // Check if child process crashed.
- kCmdGetSandboxStatus = 3, // Read a bitmask of kSandbox*
+ kCmdFork = 0, // Fork off a new renderer.
+ kCmdReap = 1, // Reap a renderer child.
+ kCmdGetTerminationStatus = 2, // Check what happend to a child process.
+ kCmdGetSandboxStatus = 3, // Read a bitmask of kSandbox*
};
// These form a bitmask which describes the conditions of the sandbox that
// the zygote finds itself in.
enum {
- kSandboxSUID = 1 << 0, // SUID sandbox active
- kSandboxPIDNS = 1 << 1, // SUID sandbox is using the PID namespace
- kSandboxNetNS = 1 << 2, // SUID sandbox is using the network namespace
+ kSandboxSUID = 1 << 0, // SUID sandbox active
+ kSandboxPIDNS = 1 << 1, // SUID sandbox is using the PID namespace
+ kSandboxNetNS = 1 << 2, // SUID sandbox is using the network namespace
kSandboxSeccomp = 1 << 3, // seccomp sandbox active.
};
diff --git a/chrome/browser/zygote_main_linux.cc b/chrome/browser/zygote_main_linux.cc
index 008d3a4..c0ba88c 100644
--- a/chrome/browser/zygote_main_linux.cc
+++ b/chrome/browser/zygote_main_linux.cc
@@ -32,23 +32,20 @@
#include "base/rand_util.h"
#include "base/scoped_ptr.h"
#include "base/sys_info.h"
-#include "base/unix_domain_socket_posix.h"
#include "build/build_config.h"
-
#include "chrome/browser/zygote_host_linux.h"
#include "chrome/common/chrome_descriptors.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/font_config_ipc_linux.h"
#include "chrome/common/main_function_params.h"
#include "chrome/common/pepper_plugin_registry.h"
#include "chrome/common/process_watcher.h"
+#include "chrome/common/result_codes.h"
#include "chrome/common/sandbox_methods_linux.h"
-
+#include "chrome/common/unix_domain_socket_posix.h"
#include "media/base/media.h"
-
-#include "skia/ext/SkFontHost_fontconfig_control.h"
-
#include "seccompsandbox/sandbox.h"
-
+#include "skia/ext/SkFontHost_fontconfig_control.h"
#include "unicode/timezone.h"
#if defined(ARCH_CPU_X86_FAMILY) && !defined(CHROMIUM_SELINUX) && \
@@ -115,8 +112,8 @@ class Zygote {
// Let the ZygoteHost know we are ready to go.
// The receiving code is in chrome/browser/zygote_host_linux.cc.
std::vector<int> empty;
- bool r = base::SendMsg(kBrowserDescriptor, kZygoteMagic,
- sizeof(kZygoteMagic), empty);
+ bool r = UnixDomainSocket::SendMsg(kBrowserDescriptor, kZygoteMagic,
+ sizeof(kZygoteMagic), empty);
CHECK(r) << "Sending zygote magic failed";
}
@@ -140,7 +137,7 @@ class Zygote {
std::vector<int> fds;
static const unsigned kMaxMessageLength = 1024;
char buf[kMaxMessageLength];
- const ssize_t len = base::RecvMsg(fd, buf, sizeof(buf), &fds);
+ const ssize_t len = UnixDomainSocket::RecvMsg(fd, buf, sizeof(buf), &fds);
if (len == 0 || (len == -1 && errno == ECONNRESET)) {
// EOF from the browser. We should die.
@@ -167,10 +164,10 @@ class Zygote {
break;
HandleReapRequest(fd, pickle, iter);
return false;
- case ZygoteHost::kCmdDidProcessCrash:
+ case ZygoteHost::kCmdGetTerminationStatus:
if (!fds.empty())
break;
- HandleDidProcessCrash(fd, pickle, iter);
+ HandleGetTerminationStatus(fd, pickle, iter);
return false;
case ZygoteHost::kCmdGetSandboxStatus:
HandleGetSandboxStatus(fd, pickle, iter);
@@ -209,26 +206,31 @@ class Zygote {
ProcessWatcher::EnsureProcessTerminated(actual_child);
}
- void HandleDidProcessCrash(int fd, const Pickle& pickle, void* iter) {
+ void HandleGetTerminationStatus(int fd, const Pickle& pickle, void* iter) {
base::ProcessHandle child;
if (!pickle.ReadInt(&iter, &child)) {
- LOG(WARNING) << "Error parsing DidProcessCrash request from browser";
+ LOG(WARNING) << "Error parsing GetTerminationStatus request "
+ << "from browser";
return;
}
- bool child_exited;
- bool did_crash;
+ base::TerminationStatus status;
+ int exit_code;
if (g_suid_sandbox_active)
child = real_pids_to_sandbox_pids[child];
- if (child)
- did_crash = base::DidProcessCrash(&child_exited, child);
- else
- did_crash = child_exited = false;
+ if (child) {
+ status = base::GetTerminationStatus(child, &exit_code);
+ } else {
+ // Assume that if we can't find the child in the sandbox, then
+ // it terminated normally.
+ status = base::TERMINATION_STATUS_NORMAL_TERMINATION;
+ exit_code = ResultCodes::NORMAL_EXIT;
+ }
Pickle write_pickle;
- write_pickle.WriteBool(did_crash);
- write_pickle.WriteBool(child_exited);
+ write_pickle.WriteInt(static_cast<int>(status));
+ write_pickle.WriteInt(exit_code);
if (HANDLE_EINTR(write(fd, write_pickle.data(), write_pickle.size())) !=
write_pickle.size()) {
PLOG(ERROR) << "write";
@@ -291,9 +293,9 @@ class Zygote {
request.WriteInt(LinuxSandbox::METHOD_GET_CHILD_WITH_INODE);
request.WriteUInt64(dummy_inode);
- const ssize_t r = base::SendRecvMsg(kMagicSandboxIPCDescriptor,
- reply_buf, sizeof(reply_buf),
- NULL, request);
+ const ssize_t r = UnixDomainSocket::SendRecvMsg(
+ kMagicSandboxIPCDescriptor, reply_buf, sizeof(reply_buf), NULL,
+ request);
if (r == -1) {
LOG(ERROR) << "Failed to get child process's real PID";
goto error;
@@ -382,7 +384,7 @@ class Zygote {
close(kBrowserDescriptor); // our socket from the browser
if (g_suid_sandbox_active)
close(kZygoteIdDescriptor); // another socket from the browser
- Singleton<base::GlobalDescriptors>()->Reset(mapping);
+ base::GlobalDescriptors::GetInstance()->Reset(mapping);
#if defined(CHROMIUM_SELINUX)
SELinuxTransitionToTypeOrDie("chromium_renderer_t");
@@ -447,7 +449,7 @@ static void ProxyLocaltimeCallToBrowser(time_t input, struct tm* output,
std::string(reinterpret_cast<char*>(&input), sizeof(input)));
uint8_t reply_buf[512];
- const ssize_t r = base::SendRecvMsg(
+ const ssize_t r = UnixDomainSocket::SendRecvMsg(
kMagicSandboxIPCDescriptor, reply_buf, sizeof(reply_buf), NULL, request);
if (r == -1) {
memset(output, 0, sizeof(struct tm));
@@ -643,7 +645,8 @@ static bool EnterSandbox() {
return false;
}
- SkiaFontConfigUseIPCImplementation(kMagicSandboxIPCDescriptor);
+ SkiaFontConfigSetImplementation(
+ new FontConfigIPC(kMagicSandboxIPCDescriptor));
// Previously, we required that the binary be non-readable. This causes the
// kernel to mark the process as non-dumpable at startup. The thinking was
@@ -672,7 +675,8 @@ static bool EnterSandbox() {
}
} else if (switches::SeccompSandboxEnabled()) {
PreSandboxInit();
- SkiaFontConfigUseIPCImplementation(kMagicSandboxIPCDescriptor);
+ SkiaFontConfigSetImplementation(
+ new FontConfigIPC(kMagicSandboxIPCDescriptor));
} else {
SkiaFontConfigUseDirectImplementation();
}
diff --git a/chrome/common/DEPS b/chrome/common/DEPS
index 18175ac..a4256b3 100644
--- a/chrome/common/DEPS
+++ b/chrome/common/DEPS
@@ -9,6 +9,7 @@ include_rules = [
"+sandbox/src",
"+skia",
"+webkit/glue",
+ "+webkit/plugins",
# Other libraries.
"+chrome/third_party/xdg_user_dirs",
diff --git a/chrome/common/appcache/appcache_dispatcher.h b/chrome/common/appcache/appcache_dispatcher.h
index f099183..f88a38a 100644
--- a/chrome/common/appcache/appcache_dispatcher.h
+++ b/chrome/common/appcache/appcache_dispatcher.h
@@ -9,20 +9,21 @@
#include <string>
#include <vector>
#include "chrome/common/appcache/appcache_backend_proxy.h"
-#include "ipc/ipc_message.h"
+#include "ipc/ipc_channel.h"
#include "webkit/appcache/appcache_frontend_impl.h"
// Dispatches appcache related messages sent to a child process from the
// main browser process. There is one instance per child process. Messages
// are dispatched on the main child thread. The ChildThread base class
// creates an instance and delegates calls to it.
-class AppCacheDispatcher {
+class AppCacheDispatcher : public IPC::Channel::Listener {
public:
explicit AppCacheDispatcher(IPC::Message::Sender* sender)
: backend_proxy_(sender) {}
AppCacheBackendProxy* backend_proxy() { return &backend_proxy_; }
+ // IPC::Channel::Listener implementation
bool OnMessageReceived(const IPC::Message& msg);
private:
diff --git a/chrome/common/automation_messages.cc b/chrome/common/automation_messages.cc
index df6d0e2..8dcac0e 100644
--- a/chrome/common/automation_messages.cc
+++ b/chrome/common/automation_messages.cc
@@ -2,8 +2,673 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#define IPC_MESSAGE_IMPL
#include "chrome/common/automation_messages.h"
-#define MESSAGES_INTERNAL_IMPL_FILE \
- "chrome/common/automation_messages_internal.h"
-#include "ipc/ipc_message_impl_macros.h"
+
+AutomationURLRequest::AutomationURLRequest()
+ : resource_type(0),
+ load_flags(0) {
+}
+
+AutomationURLRequest::AutomationURLRequest(
+ const std::string& in_url,
+ const std::string& in_method,
+ const std::string& in_referrer,
+ const std::string& in_extra_request_headers,
+ scoped_refptr<net::UploadData> in_upload_data,
+ int in_resource_type,
+ int in_load_flags)
+ : url(in_url),
+ method(in_method),
+ referrer(in_referrer),
+ extra_request_headers(in_extra_request_headers),
+ upload_data(in_upload_data),
+ resource_type(in_resource_type),
+ load_flags(in_load_flags) {
+}
+
+AutomationURLRequest::~AutomationURLRequest() {}
+
+AutomationURLResponse::AutomationURLResponse()
+ : content_length(0),
+ redirect_status(0) {
+}
+
+AutomationURLResponse::AutomationURLResponse(const std::string& in_mime_type,
+ const std::string& in_headers,
+ int64 in_content_length,
+ const base::Time& in_last_modified,
+ const std::string& in_redirect_url,
+ int in_redirect_status)
+ : mime_type(in_mime_type),
+ headers(in_headers),
+ content_length(in_content_length),
+ last_modified(in_last_modified),
+ redirect_url(in_redirect_url),
+ redirect_status(in_redirect_status) {
+}
+
+
+AutomationURLResponse::~AutomationURLResponse() {}
+
+ExternalTabSettings::ExternalTabSettings()
+ : parent(NULL),
+ dimensions(),
+ style(0),
+ is_off_the_record(false),
+ load_requests_via_automation(false),
+ handle_top_level_requests(false),
+ initial_url(),
+ referrer(),
+ infobars_enabled(false),
+ route_all_top_level_navigations(false) {
+}
+
+ExternalTabSettings::ExternalTabSettings(
+ gfx::NativeWindow in_parent,
+ const gfx::Rect& in_dimensions,
+ unsigned int in_style,
+ bool in_is_off_the_record,
+ bool in_load_requests_via_automation,
+ bool in_handle_top_level_requests,
+ const GURL& in_initial_url,
+ const GURL& in_referrer,
+ bool in_infobars_enabled,
+ bool in_route_all_top_level_navigations)
+ : parent(in_parent),
+ dimensions(in_dimensions),
+ style(in_style),
+ is_off_the_record(in_is_off_the_record),
+ load_requests_via_automation(in_load_requests_via_automation),
+ handle_top_level_requests(in_handle_top_level_requests),
+ initial_url(in_initial_url),
+ referrer(in_referrer),
+ infobars_enabled(in_infobars_enabled),
+ route_all_top_level_navigations(in_route_all_top_level_navigations) {
+}
+
+ExternalTabSettings::~ExternalTabSettings() {}
+
+NavigationInfo::NavigationInfo()
+ : navigation_type(0),
+ relative_offset(0),
+ navigation_index(0),
+ displayed_insecure_content(0),
+ ran_insecure_content(0) {
+}
+
+NavigationInfo::NavigationInfo(int in_navigation_type,
+ int in_relative_offset,
+ int in_navigation_index,
+ const std::wstring& in_title,
+ const GURL& in_url,
+ const GURL& in_referrer,
+ SecurityStyle in_security_style,
+ bool in_displayed_insecure_content,
+ bool in_ran_insecure_content)
+ : navigation_type(in_navigation_type),
+ relative_offset(in_relative_offset),
+ navigation_index(in_navigation_index),
+ title(in_title),
+ url(in_url),
+ referrer(in_referrer),
+ security_style(in_security_style),
+ displayed_insecure_content(in_displayed_insecure_content),
+ ran_insecure_content(in_ran_insecure_content) {
+}
+
+NavigationInfo::~NavigationInfo() {}
+
+MiniContextMenuParams::MiniContextMenuParams()
+ : screen_x(0),
+ screen_y(0) {
+}
+
+MiniContextMenuParams::MiniContextMenuParams(int in_screen_x,
+ int in_screen_y,
+ const GURL& in_link_url,
+ const GURL& in_unfiltered_link_url,
+ const GURL& in_src_url,
+ const GURL& in_page_url,
+ const GURL& in_frame_url)
+ : screen_x(in_screen_x),
+ screen_y(in_screen_y),
+ link_url(in_link_url),
+ unfiltered_link_url(in_unfiltered_link_url),
+ src_url(in_src_url),
+ page_url(in_page_url),
+ frame_url(in_frame_url) {
+}
+
+MiniContextMenuParams::~MiniContextMenuParams() {}
+
+AttachExternalTabParams::AttachExternalTabParams()
+ : cookie(0),
+ disposition(0),
+ user_gesture(false) {
+}
+
+AttachExternalTabParams::AttachExternalTabParams(
+ uint64 in_cookie,
+ const GURL& in_url,
+ const gfx::Rect& in_dimensions,
+ int in_disposition,
+ bool in_user_gesture,
+ const std::string& in_profile_name)
+ : cookie(in_cookie),
+ url(in_url),
+ dimensions(in_dimensions),
+ disposition(in_disposition),
+ user_gesture(in_user_gesture),
+ profile_name(in_profile_name) {
+}
+
+AttachExternalTabParams::~AttachExternalTabParams() {}
+
+namespace IPC {
+
+// static
+void ParamTraits<AutomationMsg_Find_Params>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.unused);
+ WriteParam(m, p.search_string);
+ WriteParam(m, p.forward);
+ WriteParam(m, p.match_case);
+ WriteParam(m, p.find_next);
+}
+
+// static
+bool ParamTraits<AutomationMsg_Find_Params>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->unused) &&
+ ReadParam(m, iter, &p->search_string) &&
+ ReadParam(m, iter, &p->forward) &&
+ ReadParam(m, iter, &p->match_case) &&
+ ReadParam(m, iter, &p->find_next);
+}
+
+// static
+void ParamTraits<AutomationMsg_Find_Params>::Log(const param_type& p,
+ std::string* l) {
+ l->append("<AutomationMsg_Find_Params>");
+}
+
+// static
+void ParamTraits<AutomationMsg_NavigationResponseValues>::Write(
+ Message* m,
+ const param_type& p) {
+ m->WriteInt(p);
+}
+
+// static
+bool ParamTraits<AutomationMsg_NavigationResponseValues>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ int type;
+ if (!m->ReadInt(iter, &type))
+ return false;
+ *p = static_cast<AutomationMsg_NavigationResponseValues>(type);
+ return true;
+}
+
+// static
+void ParamTraits<AutomationMsg_NavigationResponseValues>::Log(
+ const param_type& p, std::string* l) {
+ std::string control;
+ switch (p) {
+ case AUTOMATION_MSG_NAVIGATION_ERROR:
+ control = "AUTOMATION_MSG_NAVIGATION_ERROR";
+ break;
+ case AUTOMATION_MSG_NAVIGATION_SUCCESS:
+ control = "AUTOMATION_MSG_NAVIGATION_SUCCESS";
+ break;
+ case AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED:
+ control = "AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED";
+ break;
+ default:
+ control = "UNKNOWN";
+ break;
+ }
+
+ LogParam(control, l);
+}
+
+// static
+void ParamTraits<AutomationMsg_ExtensionResponseValues>::Write(
+ Message* m,
+ const param_type& p) {
+ m->WriteInt(p);
+}
+
+// static
+bool ParamTraits<AutomationMsg_ExtensionResponseValues>::Read(
+ const Message* m,
+ void** iter,
+ param_type* p) {
+ int type;
+ if (!m->ReadInt(iter, &type))
+ return false;
+ *p = static_cast<AutomationMsg_ExtensionResponseValues>(type);
+ return true;
+}
+
+// static
+void ParamTraits<AutomationMsg_ExtensionResponseValues>::Log(
+ const param_type& p,
+ std::string* l) {
+ std::string control;
+ switch (p) {
+ case AUTOMATION_MSG_EXTENSION_INSTALL_SUCCEEDED:
+ control = "AUTOMATION_MSG_EXTENSION_INSTALL_SUCCEEDED";
+ break;
+ case AUTOMATION_MSG_EXTENSION_INSTALL_FAILED:
+ control = "AUTOMATION_MSG_EXTENSION_INSTALL_FAILED";
+ break;
+ default:
+ control = "UNKNOWN";
+ break;
+ }
+
+ LogParam(control, l);
+}
+
+// static
+void ParamTraits<AutomationMsg_ExtensionProperty>::Write(Message* m,
+ const param_type& p) {
+ m->WriteInt(p);
+}
+
+// static
+bool ParamTraits<AutomationMsg_ExtensionProperty>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ int type;
+ if (!m->ReadInt(iter, &type))
+ return false;
+ *p = static_cast<AutomationMsg_ExtensionProperty>(type);
+ return true;
+}
+
+// static
+void ParamTraits<AutomationMsg_ExtensionProperty>::Log(const param_type& p,
+ std::string* l) {
+ std::string control;
+ switch (p) {
+ case AUTOMATION_MSG_EXTENSION_ID:
+ control = "AUTOMATION_MSG_EXTENSION_ID";
+ break;
+ case AUTOMATION_MSG_EXTENSION_NAME:
+ control = "AUTOMATION_MSG_EXTENSION_NAME";
+ break;
+ case AUTOMATION_MSG_EXTENSION_VERSION:
+ control = "AUTOMATION_MSG_EXTENSION_VERSION";
+ break;
+ case AUTOMATION_MSG_EXTENSION_BROWSER_ACTION_INDEX:
+ control = "AUTOMATION_MSG_EXTENSION_BROWSER_ACTION_INDEX";
+ break;
+ default:
+ control = "UNKNOWN";
+ break;
+ }
+
+ LogParam(control, l);
+}
+
+// static
+void ParamTraits<SecurityStyle>::Write(Message* m, const param_type& p) {
+ m->WriteInt(p);
+}
+
+// static
+bool ParamTraits<SecurityStyle>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ int type;
+ if (!m->ReadInt(iter, &type))
+ return false;
+ *p = static_cast<SecurityStyle>(type);
+ return true;
+}
+
+// static
+void ParamTraits<SecurityStyle>::Log(const param_type& p, std::string* l) {
+ std::string control;
+ switch (p) {
+ case SECURITY_STYLE_UNKNOWN:
+ control = "SECURITY_STYLE_UNKNOWN";
+ break;
+ case SECURITY_STYLE_UNAUTHENTICATED:
+ control = "SECURITY_STYLE_UNAUTHENTICATED";
+ break;
+ case SECURITY_STYLE_AUTHENTICATION_BROKEN:
+ control = "SECURITY_STYLE_AUTHENTICATION_BROKEN";
+ break;
+ case SECURITY_STYLE_AUTHENTICATED:
+ control = "SECURITY_STYLE_AUTHENTICATED";
+ break;
+ default:
+ control = "UNKNOWN";
+ break;
+ }
+
+ LogParam(control, l);
+}
+
+// static
+void ParamTraits<PageType>::Write(Message* m, const param_type& p) {
+ m->WriteInt(p);
+}
+
+// static
+bool ParamTraits<PageType>::Read(const Message* m, void** iter, param_type* p) {
+ int type;
+ if (!m->ReadInt(iter, &type))
+ return false;
+ *p = static_cast<PageType>(type);
+ return true;
+}
+
+// static
+void ParamTraits<PageType>::Log(const param_type& p, std::string* l) {
+ std::string control;
+ switch (p) {
+ case NORMAL_PAGE:
+ control = "NORMAL_PAGE";
+ break;
+ case ERROR_PAGE:
+ control = "ERROR_PAGE";
+ break;
+ case INTERSTITIAL_PAGE:
+ control = "INTERSTITIAL_PAGE";
+ break;
+ default:
+ control = "UNKNOWN";
+ break;
+ }
+
+ LogParam(control, l);
+}
+
+// static
+void ParamTraits<AutomationURLRequest>::Write(Message* m, const param_type& p) {
+ WriteParam(m, p.url);
+ WriteParam(m, p.method);
+ WriteParam(m, p.referrer);
+ WriteParam(m, p.extra_request_headers);
+ WriteParam(m, p.upload_data);
+ WriteParam(m, p.resource_type);
+ WriteParam(m, p.load_flags);
+}
+
+// static
+bool ParamTraits<AutomationURLRequest>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return ReadParam(m, iter, &p->url) &&
+ ReadParam(m, iter, &p->method) &&
+ ReadParam(m, iter, &p->referrer) &&
+ ReadParam(m, iter, &p->extra_request_headers) &&
+ ReadParam(m, iter, &p->upload_data) &&
+ ReadParam(m, iter, &p->resource_type) &&
+ ReadParam(m, iter, &p->load_flags);
+}
+
+// static
+void ParamTraits<AutomationURLRequest>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.url, l);
+ l->append(", ");
+ LogParam(p.method, l);
+ l->append(", ");
+ LogParam(p.referrer, l);
+ l->append(", ");
+ LogParam(p.extra_request_headers, l);
+ l->append(", ");
+ LogParam(p.upload_data, l);
+ l->append(", ");
+ LogParam(p.resource_type, l);
+ l->append(", ");
+ LogParam(p.load_flags, l);
+ l->append(")");
+}
+
+// static
+void ParamTraits<AutomationURLResponse>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.mime_type);
+ WriteParam(m, p.headers);
+ WriteParam(m, p.content_length);
+ WriteParam(m, p.last_modified);
+ WriteParam(m, p.redirect_url);
+ WriteParam(m, p.redirect_status);
+}
+
+// static
+bool ParamTraits<AutomationURLResponse>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return ReadParam(m, iter, &p->mime_type) &&
+ ReadParam(m, iter, &p->headers) &&
+ ReadParam(m, iter, &p->content_length) &&
+ ReadParam(m, iter, &p->last_modified) &&
+ ReadParam(m, iter, &p->redirect_url) &&
+ ReadParam(m, iter, &p->redirect_status);
+}
+
+// static
+void ParamTraits<AutomationURLResponse>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.mime_type, l);
+ l->append(", ");
+ LogParam(p.headers, l);
+ l->append(", ");
+ LogParam(p.content_length, l);
+ l->append(", ");
+ LogParam(p.last_modified, l);
+ l->append(", ");
+ LogParam(p.redirect_url, l);
+ l->append(", ");
+ LogParam(p.redirect_status, l);
+ l->append(")");
+}
+
+// static
+void ParamTraits<ExternalTabSettings>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.parent);
+ WriteParam(m, p.dimensions);
+ WriteParam(m, p.style);
+ WriteParam(m, p.is_off_the_record);
+ WriteParam(m, p.load_requests_via_automation);
+ WriteParam(m, p.handle_top_level_requests);
+ WriteParam(m, p.initial_url);
+ WriteParam(m, p.referrer);
+ WriteParam(m, p.infobars_enabled);
+ WriteParam(m, p.route_all_top_level_navigations);
+}
+
+// static
+bool ParamTraits<ExternalTabSettings>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return ReadParam(m, iter, &p->parent) &&
+ ReadParam(m, iter, &p->dimensions) &&
+ ReadParam(m, iter, &p->style) &&
+ ReadParam(m, iter, &p->is_off_the_record) &&
+ ReadParam(m, iter, &p->load_requests_via_automation) &&
+ ReadParam(m, iter, &p->handle_top_level_requests) &&
+ ReadParam(m, iter, &p->initial_url) &&
+ ReadParam(m, iter, &p->referrer) &&
+ ReadParam(m, iter, &p->infobars_enabled) &&
+ ReadParam(m, iter, &p->route_all_top_level_navigations);
+}
+
+// static
+void ParamTraits<ExternalTabSettings>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.parent, l);
+ l->append(", ");
+ LogParam(p.dimensions, l);
+ l->append(", ");
+ LogParam(p.style, l);
+ l->append(", ");
+ LogParam(p.is_off_the_record, l);
+ l->append(", ");
+ LogParam(p.load_requests_via_automation, l);
+ l->append(", ");
+ LogParam(p.handle_top_level_requests, l);
+ l->append(", ");
+ LogParam(p.initial_url, l);
+ l->append(", ");
+ LogParam(p.referrer, l);
+ l->append(", ");
+ LogParam(p.infobars_enabled, l);
+ l->append(", ");
+ LogParam(p.route_all_top_level_navigations, l);
+ l->append(")");
+}
+
+// static
+void ParamTraits<NavigationInfo>::Write(Message* m, const param_type& p) {
+ WriteParam(m, p.navigation_type);
+ WriteParam(m, p.relative_offset);
+ WriteParam(m, p.navigation_index);
+ WriteParam(m, p.title);
+ WriteParam(m, p.url);
+ WriteParam(m, p.referrer);
+ WriteParam(m, p.security_style);
+ WriteParam(m, p.displayed_insecure_content);
+ WriteParam(m, p.ran_insecure_content);
+}
+
+// static
+bool ParamTraits<NavigationInfo>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return ReadParam(m, iter, &p->navigation_type) &&
+ ReadParam(m, iter, &p->relative_offset) &&
+ ReadParam(m, iter, &p->navigation_index) &&
+ ReadParam(m, iter, &p->title) &&
+ ReadParam(m, iter, &p->url) &&
+ ReadParam(m, iter, &p->referrer) &&
+ ReadParam(m, iter, &p->security_style) &&
+ ReadParam(m, iter, &p->displayed_insecure_content) &&
+ ReadParam(m, iter, &p->ran_insecure_content);
+}
+
+// static
+void ParamTraits<NavigationInfo>::Log(const param_type& p, std::string* l) {
+ l->append("(");
+ LogParam(p.navigation_type, l);
+ l->append(", ");
+ LogParam(p.relative_offset, l);
+ l->append(", ");
+ LogParam(p.navigation_index, l);
+ l->append(", ");
+ LogParam(p.title, l);
+ l->append(", ");
+ LogParam(p.url, l);
+ l->append(", ");
+ LogParam(p.referrer, l);
+ l->append(", ");
+ LogParam(p.security_style, l);
+ l->append(", ");
+ LogParam(p.displayed_insecure_content, l);
+ l->append(", ");
+ LogParam(p.ran_insecure_content, l);
+ l->append(")");
+}
+
+// static
+void ParamTraits<MiniContextMenuParams>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.screen_x);
+ WriteParam(m, p.screen_y);
+ WriteParam(m, p.link_url);
+ WriteParam(m, p.unfiltered_link_url);
+ WriteParam(m, p.src_url);
+ WriteParam(m, p.page_url);
+ WriteParam(m, p.frame_url);
+}
+
+// static
+bool ParamTraits<MiniContextMenuParams>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return ReadParam(m, iter, &p->screen_x) &&
+ ReadParam(m, iter, &p->screen_y) &&
+ ReadParam(m, iter, &p->link_url) &&
+ ReadParam(m, iter, &p->unfiltered_link_url) &&
+ ReadParam(m, iter, &p->src_url) &&
+ ReadParam(m, iter, &p->page_url) &&
+ ReadParam(m, iter, &p->frame_url);
+}
+
+// static
+void ParamTraits<MiniContextMenuParams>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.screen_x, l);
+ l->append(", ");
+ LogParam(p.screen_y, l);
+ l->append(", ");
+ LogParam(p.link_url, l);
+ l->append(", ");
+ LogParam(p.unfiltered_link_url, l);
+ l->append(", ");
+ LogParam(p.src_url, l);
+ l->append(", ");
+ LogParam(p.page_url, l);
+ l->append(", ");
+ LogParam(p.frame_url, l);
+ l->append(")");
+}
+
+// static
+void ParamTraits<AttachExternalTabParams>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.cookie);
+ WriteParam(m, p.url);
+ WriteParam(m, p.dimensions);
+ WriteParam(m, p.disposition);
+ WriteParam(m, p.user_gesture);
+ WriteParam(m, p.profile_name);
+}
+
+// static
+bool ParamTraits<AttachExternalTabParams>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return ReadParam(m, iter, &p->cookie) &&
+ ReadParam(m, iter, &p->url) &&
+ ReadParam(m, iter, &p->dimensions) &&
+ ReadParam(m, iter, &p->disposition) &&
+ ReadParam(m, iter, &p->user_gesture) &&
+ ReadParam(m, iter, &p->profile_name);
+}
+
+// static
+void ParamTraits<AttachExternalTabParams>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.cookie, l);
+ l->append(", ");
+ LogParam(p.url, l);
+ l->append(", ");
+ LogParam(p.dimensions, l);
+ l->append(", ");
+ LogParam(p.disposition, l);
+ l->append(", ");
+ LogParam(p.user_gesture, l);
+ l->append(",");
+ LogParam(p.profile_name, l);
+ l->append(")");
+}
+
+} // namespace IPC
diff --git a/chrome/common/automation_messages.h b/chrome/common/automation_messages.h
index 0f8ec7c..7a9ba91 100644
--- a/chrome/common/automation_messages.h
+++ b/chrome/common/automation_messages.h
@@ -34,216 +34,218 @@ struct AutomationMsg_Find_Params {
bool find_next;
};
+struct AutomationURLResponse {
+ AutomationURLResponse();
+ AutomationURLResponse(const std::string& mime_type,
+ const std::string& headers,
+ int64 content_length,
+ const base::Time& last_modified,
+ const std::string& redirect_url,
+ int redirect_status);
+ ~AutomationURLResponse();
+
+ std::string mime_type;
+ std::string headers;
+ int64 content_length;
+ base::Time last_modified;
+ std::string redirect_url;
+ int redirect_status;
+};
+
+struct ExternalTabSettings {
+ ExternalTabSettings();
+ ExternalTabSettings(gfx::NativeWindow parent,
+ const gfx::Rect& dimensions,
+ unsigned int style,
+ bool is_off_the_record,
+ bool load_requests_via_automation,
+ bool handle_top_level_requests,
+ const GURL& initial_url,
+ const GURL& referrer,
+ bool infobars_enabled,
+ bool route_all_top_level_navigations);
+ ~ExternalTabSettings();
+
+ gfx::NativeWindow parent;
+ gfx::Rect dimensions;
+ unsigned int style;
+ bool is_off_the_record;
+ bool load_requests_via_automation;
+ bool handle_top_level_requests;
+ GURL initial_url;
+ GURL referrer;
+ bool infobars_enabled;
+ bool route_all_top_level_navigations;
+};
+
+struct NavigationInfo {
+ NavigationInfo();
+ NavigationInfo(int navigation_type,
+ int relative_offset,
+ int navigation_index,
+ const std::wstring& title,
+ const GURL& url,
+ const GURL& referrer,
+ SecurityStyle security_style,
+ bool displayed_insecure_content,
+ bool ran_insecure_content);
+ ~NavigationInfo();
+
+ int navigation_type;
+ int relative_offset;
+ int navigation_index;
+ std::wstring title;
+ GURL url;
+ GURL referrer;
+ SecurityStyle security_style;
+ bool displayed_insecure_content;
+ bool ran_insecure_content;
+};
+
+// A stripped down version of ContextMenuParams in webkit/glue/context_menu.h.
+struct MiniContextMenuParams {
+ MiniContextMenuParams();
+ MiniContextMenuParams(int screen_x,
+ int screen_y,
+ const GURL& link_url,
+ const GURL& unfiltered_link_url,
+ const GURL& src_url,
+ const GURL& page_url,
+ const GURL& frame_url);
+ ~MiniContextMenuParams();
+
+ // The x coordinate for displaying the menu.
+ int screen_x;
+
+ // The y coordinate for displaying the menu.
+ int screen_y;
+
+ // This is the URL of the link that encloses the node the context menu was
+ // invoked on.
+ GURL link_url;
+
+ // The link URL to be used ONLY for "copy link address". We don't validate
+ // this field in the frontend process.
+ GURL unfiltered_link_url;
+
+ // This is the source URL for the element that the context menu was
+ // invoked on. Example of elements with source URLs are img, audio, and
+ // video.
+ GURL src_url;
+
+ // This is the URL of the top level page that the context menu was invoked
+ // on.
+ GURL page_url;
+
+ // This is the URL of the subframe that the context menu was invoked on.
+ GURL frame_url;
+};
+
+struct AttachExternalTabParams {
+ AttachExternalTabParams();
+ AttachExternalTabParams(uint64 cookie,
+ const GURL& url,
+ const gfx::Rect& dimensions,
+ int disposition,
+ bool user_gesture,
+ const std::string& profile_name);
+ ~AttachExternalTabParams();
+
+ uint64 cookie;
+ GURL url;
+ gfx::Rect dimensions;
+ int disposition;
+ bool user_gesture;
+ std::string profile_name;
+};
+
+#if defined(OS_WIN)
+
+struct Reposition_Params {
+ HWND window;
+ HWND window_insert_after;
+ int left;
+ int top;
+ int width;
+ int height;
+ int flags;
+ bool set_parent;
+ HWND parent_window;
+};
+
+#endif // defined(OS_WIN)
+
+struct AutomationURLRequest {
+ AutomationURLRequest();
+ AutomationURLRequest(const std::string& url,
+ const std::string& method,
+ const std::string& referrer,
+ const std::string& extra_request_headers,
+ scoped_refptr<net::UploadData> upload_data,
+ int resource_type,
+ int load_flags);
+ ~AutomationURLRequest();
+
+ std::string url;
+ std::string method;
+ std::string referrer;
+ std::string extra_request_headers;
+ scoped_refptr<net::UploadData> upload_data;
+ int resource_type; // see webkit/glue/resource_type.h
+ int load_flags; // see net/base/load_flags.h
+};
+
namespace IPC {
template <>
struct ParamTraits<AutomationMsg_Find_Params> {
typedef AutomationMsg_Find_Params param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.unused);
- WriteParam(m, p.search_string);
- WriteParam(m, p.forward);
- WriteParam(m, p.match_case);
- WriteParam(m, p.find_next);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return
- ReadParam(m, iter, &p->unused) &&
- ReadParam(m, iter, &p->search_string) &&
- ReadParam(m, iter, &p->forward) &&
- ReadParam(m, iter, &p->match_case) &&
- ReadParam(m, iter, &p->find_next);
- }
- static void Log(const param_type& p, std::string* l) {
- l->append("<AutomationMsg_Find_Params>");
- }
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
};
template <>
struct ParamTraits<AutomationMsg_NavigationResponseValues> {
typedef AutomationMsg_NavigationResponseValues param_type;
- static void Write(Message* m, const param_type& p) {
- m->WriteInt(p);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- int type;
- if (!m->ReadInt(iter, &type))
- return false;
- *p = static_cast<AutomationMsg_NavigationResponseValues>(type);
- return true;
- }
- static void Log(const param_type& p, std::string* l) {
- std::string control;
- switch (p) {
- case AUTOMATION_MSG_NAVIGATION_ERROR:
- control = "AUTOMATION_MSG_NAVIGATION_ERROR";
- break;
- case AUTOMATION_MSG_NAVIGATION_SUCCESS:
- control = "AUTOMATION_MSG_NAVIGATION_SUCCESS";
- break;
- case AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED:
- control = "AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED";
- break;
- default:
- control = "UNKNOWN";
- break;
- }
-
- LogParam(control, l);
- }
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
};
template <>
struct ParamTraits<AutomationMsg_ExtensionResponseValues> {
typedef AutomationMsg_ExtensionResponseValues param_type;
- static void Write(Message* m, const param_type& p) {
- m->WriteInt(p);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- int type;
- if (!m->ReadInt(iter, &type))
- return false;
- *p = static_cast<AutomationMsg_ExtensionResponseValues>(type);
- return true;
- }
- static void Log(const param_type& p, std::string* l) {
- std::string control;
- switch (p) {
- case AUTOMATION_MSG_EXTENSION_INSTALL_SUCCEEDED:
- control = "AUTOMATION_MSG_EXTENSION_INSTALL_SUCCEEDED";
- break;
- case AUTOMATION_MSG_EXTENSION_INSTALL_FAILED:
- control = "AUTOMATION_MSG_EXTENSION_INSTALL_FAILED";
- break;
- default:
- control = "UNKNOWN";
- break;
- }
-
- LogParam(control, l);
- }
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
};
template <>
struct ParamTraits<AutomationMsg_ExtensionProperty> {
typedef AutomationMsg_ExtensionProperty param_type;
- static void Write(Message* m, const param_type& p) {
- m->WriteInt(p);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- int type;
- if (!m->ReadInt(iter, &type))
- return false;
- *p = static_cast<AutomationMsg_ExtensionProperty>(type);
- return true;
- }
- static void Log(const param_type& p, std::string* l) {
- std::string control;
- switch (p) {
- case AUTOMATION_MSG_EXTENSION_ID:
- control = "AUTOMATION_MSG_EXTENSION_ID";
- break;
- case AUTOMATION_MSG_EXTENSION_NAME:
- control = "AUTOMATION_MSG_EXTENSION_NAME";
- break;
- case AUTOMATION_MSG_EXTENSION_VERSION:
- control = "AUTOMATION_MSG_EXTENSION_VERSION";
- break;
- case AUTOMATION_MSG_EXTENSION_BROWSER_ACTION_INDEX:
- control = "AUTOMATION_MSG_EXTENSION_BROWSER_ACTION_INDEX";
- break;
- default:
- control = "UNKNOWN";
- break;
- }
-
- LogParam(control, l);
- }
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
};
template <>
struct ParamTraits<SecurityStyle> {
typedef SecurityStyle param_type;
- static void Write(Message* m, const param_type& p) {
- m->WriteInt(p);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- int type;
- if (!m->ReadInt(iter, &type))
- return false;
- *p = static_cast<SecurityStyle>(type);
- return true;
- }
- static void Log(const param_type& p, std::string* l) {
- std::string control;
- switch (p) {
- case SECURITY_STYLE_UNKNOWN:
- control = "SECURITY_STYLE_UNKNOWN";
- break;
- case SECURITY_STYLE_UNAUTHENTICATED:
- control = "SECURITY_STYLE_UNAUTHENTICATED";
- break;
- case SECURITY_STYLE_AUTHENTICATION_BROKEN:
- control = "SECURITY_STYLE_AUTHENTICATION_BROKEN";
- break;
- case SECURITY_STYLE_AUTHENTICATED:
- control = "SECURITY_STYLE_AUTHENTICATED";
- break;
- default:
- control = "UNKNOWN";
- break;
- }
-
- LogParam(control, l);
- }
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
};
template <>
struct ParamTraits<PageType> {
typedef PageType param_type;
- static void Write(Message* m, const param_type& p) {
- m->WriteInt(p);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- int type;
- if (!m->ReadInt(iter, &type))
- return false;
- *p = static_cast<PageType>(type);
- return true;
- }
- static void Log(const param_type& p, std::string* l) {
- std::string control;
- switch (p) {
- case NORMAL_PAGE:
- control = "NORMAL_PAGE";
- break;
- case ERROR_PAGE:
- control = "ERROR_PAGE";
- break;
- case INTERSTITIAL_PAGE:
- control = "INTERSTITIAL_PAGE";
- break;
- default:
- control = "UNKNOWN";
- break;
- }
-
- LogParam(control, l);
- }
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
};
#if defined(OS_WIN)
-struct Reposition_Params {
- HWND window;
- HWND window_insert_after;
- int left;
- int top;
- int width;
- int height;
- int flags;
- bool set_parent;
- HWND parent_window;
-};
// Traits for SetWindowPos_Params structure to pack/unpack.
template <>
@@ -295,351 +297,61 @@ struct ParamTraits<Reposition_Params> {
};
#endif // defined(OS_WIN)
-struct AutomationURLRequest {
- std::string url;
- std::string method;
- std::string referrer;
- std::string extra_request_headers;
- scoped_refptr<net::UploadData> upload_data;
- int resource_type; // see webkit/glue/resource_type.h
- int load_flags; // see net/base/load_flags.h
-};
-
// Traits for AutomationURLRequest structure to pack/unpack.
template <>
struct ParamTraits<AutomationURLRequest> {
typedef AutomationURLRequest param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.url);
- WriteParam(m, p.method);
- WriteParam(m, p.referrer);
- WriteParam(m, p.extra_request_headers);
- WriteParam(m, p.upload_data);
- WriteParam(m, p.resource_type);
- WriteParam(m, p.load_flags);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return ReadParam(m, iter, &p->url) &&
- ReadParam(m, iter, &p->method) &&
- ReadParam(m, iter, &p->referrer) &&
- ReadParam(m, iter, &p->extra_request_headers) &&
- ReadParam(m, iter, &p->upload_data) &&
- ReadParam(m, iter, &p->resource_type) &&
- ReadParam(m, iter, &p->load_flags);
- }
- static void Log(const param_type& p, std::string* l) {
- l->append("(");
- LogParam(p.url, l);
- l->append(", ");
- LogParam(p.method, l);
- l->append(", ");
- LogParam(p.referrer, l);
- l->append(", ");
- LogParam(p.extra_request_headers, l);
- l->append(", ");
- LogParam(p.upload_data, l);
- l->append(", ");
- LogParam(p.resource_type, l);
- l->append(", ");
- LogParam(p.load_flags, l);
- l->append(")");
- }
-};
-
-struct AutomationURLResponse {
- std::string mime_type;
- std::string headers;
- int64 content_length;
- base::Time last_modified;
- std::string redirect_url;
- int redirect_status;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
};
// Traits for AutomationURLResponse structure to pack/unpack.
template <>
struct ParamTraits<AutomationURLResponse> {
typedef AutomationURLResponse param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.mime_type);
- WriteParam(m, p.headers);
- WriteParam(m, p.content_length);
- WriteParam(m, p.last_modified);
- WriteParam(m, p.redirect_url);
- WriteParam(m, p.redirect_status);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return ReadParam(m, iter, &p->mime_type) &&
- ReadParam(m, iter, &p->headers) &&
- ReadParam(m, iter, &p->content_length) &&
- ReadParam(m, iter, &p->last_modified) &&
- ReadParam(m, iter, &p->redirect_url) &&
- ReadParam(m, iter, &p->redirect_status);
- }
- static void Log(const param_type& p, std::string* l) {
- l->append("(");
- LogParam(p.mime_type, l);
- l->append(", ");
- LogParam(p.headers, l);
- l->append(", ");
- LogParam(p.content_length, l);
- l->append(", ");
- LogParam(p.last_modified, l);
- l->append(", ");
- LogParam(p.redirect_url, l);
- l->append(", ");
- LogParam(p.redirect_status, l);
- l->append(")");
- }
-};
-
-struct ExternalTabSettings {
- gfx::NativeWindow parent;
- gfx::Rect dimensions;
- unsigned int style;
- bool is_off_the_record;
- bool load_requests_via_automation;
- bool handle_top_level_requests;
- GURL initial_url;
- GURL referrer;
- bool infobars_enabled;
- bool route_all_top_level_navigations;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
};
// Traits for ExternalTabSettings structure to pack/unpack.
template <>
struct ParamTraits<ExternalTabSettings> {
typedef ExternalTabSettings param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.parent);
- WriteParam(m, p.dimensions);
- WriteParam(m, p.style);
- WriteParam(m, p.is_off_the_record);
- WriteParam(m, p.load_requests_via_automation);
- WriteParam(m, p.handle_top_level_requests);
- WriteParam(m, p.initial_url);
- WriteParam(m, p.referrer);
- WriteParam(m, p.infobars_enabled);
- WriteParam(m, p.route_all_top_level_navigations);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return ReadParam(m, iter, &p->parent) &&
- ReadParam(m, iter, &p->dimensions) &&
- ReadParam(m, iter, &p->style) &&
- ReadParam(m, iter, &p->is_off_the_record) &&
- ReadParam(m, iter, &p->load_requests_via_automation) &&
- ReadParam(m, iter, &p->handle_top_level_requests) &&
- ReadParam(m, iter, &p->initial_url) &&
- ReadParam(m, iter, &p->referrer) &&
- ReadParam(m, iter, &p->infobars_enabled) &&
- ReadParam(m, iter, &p->route_all_top_level_navigations);
- }
- static void Log(const param_type& p, std::string* l) {
- l->append("(");
- LogParam(p.parent, l);
- l->append(", ");
- LogParam(p.dimensions, l);
- l->append(", ");
- LogParam(p.style, l);
- l->append(", ");
- LogParam(p.is_off_the_record, l);
- l->append(", ");
- LogParam(p.load_requests_via_automation, l);
- l->append(", ");
- LogParam(p.handle_top_level_requests, l);
- l->append(", ");
- LogParam(p.initial_url, l);
- l->append(", ");
- LogParam(p.referrer, l);
- l->append(", ");
- LogParam(p.infobars_enabled, l);
- l->append(", ");
- LogParam(p.route_all_top_level_navigations, l);
- l->append(")");
- }
-};
-
-struct NavigationInfo {
- int navigation_type;
- int relative_offset;
- int navigation_index;
- std::wstring title;
- GURL url;
- GURL referrer;
- SecurityStyle security_style;
- bool displayed_insecure_content;
- bool ran_insecure_content;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
};
// Traits for NavigationInfo structure to pack/unpack.
template <>
struct ParamTraits<NavigationInfo> {
typedef NavigationInfo param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.navigation_type);
- WriteParam(m, p.relative_offset);
- WriteParam(m, p.navigation_index);
- WriteParam(m, p.title);
- WriteParam(m, p.url);
- WriteParam(m, p.referrer);
- WriteParam(m, p.security_style);
- WriteParam(m, p.displayed_insecure_content);
- WriteParam(m, p.ran_insecure_content);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return ReadParam(m, iter, &p->navigation_type) &&
- ReadParam(m, iter, &p->relative_offset) &&
- ReadParam(m, iter, &p->navigation_index) &&
- ReadParam(m, iter, &p->title) &&
- ReadParam(m, iter, &p->url) &&
- ReadParam(m, iter, &p->referrer) &&
- ReadParam(m, iter, &p->security_style) &&
- ReadParam(m, iter, &p->displayed_insecure_content) &&
- ReadParam(m, iter, &p->ran_insecure_content);
- }
- static void Log(const param_type& p, std::string* l) {
- l->append("(");
- LogParam(p.navigation_type, l);
- l->append(", ");
- LogParam(p.relative_offset, l);
- l->append(", ");
- LogParam(p.navigation_index, l);
- l->append(", ");
- LogParam(p.title, l);
- l->append(", ");
- LogParam(p.url, l);
- l->append(", ");
- LogParam(p.referrer, l);
- l->append(", ");
- LogParam(p.security_style, l);
- l->append(", ");
- LogParam(p.displayed_insecure_content, l);
- l->append(", ");
- LogParam(p.ran_insecure_content, l);
- l->append(")");
- }
-};
-
-// A stripped down version of ContextMenuParams in webkit/glue/context_menu.h.
-struct MiniContextMenuParams {
- // The x coordinate for displaying the menu.
- int screen_x;
-
- // The y coordinate for displaying the menu.
- int screen_y;
-
- // This is the URL of the link that encloses the node the context menu was
- // invoked on.
- GURL link_url;
-
- // The link URL to be used ONLY for "copy link address". We don't validate
- // this field in the frontend process.
- GURL unfiltered_link_url;
-
- // This is the source URL for the element that the context menu was
- // invoked on. Example of elements with source URLs are img, audio, and
- // video.
- GURL src_url;
-
- // This is the URL of the top level page that the context menu was invoked
- // on.
- GURL page_url;
-
- // This is the URL of the subframe that the context menu was invoked on.
- GURL frame_url;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
};
// Traits for MiniContextMenuParams structure to pack/unpack.
template <>
struct ParamTraits<MiniContextMenuParams> {
typedef MiniContextMenuParams param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.screen_x);
- WriteParam(m, p.screen_y);
- WriteParam(m, p.link_url);
- WriteParam(m, p.unfiltered_link_url);
- WriteParam(m, p.src_url);
- WriteParam(m, p.page_url);
- WriteParam(m, p.frame_url);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- return ReadParam(m, iter, &p->screen_x) &&
- ReadParam(m, iter, &p->screen_y) &&
- ReadParam(m, iter, &p->link_url) &&
- ReadParam(m, iter, &p->unfiltered_link_url) &&
- ReadParam(m, iter, &p->src_url) &&
- ReadParam(m, iter, &p->page_url) &&
- ReadParam(m, iter, &p->frame_url);
- }
- static void Log(const param_type& p, std::string* l) {
- l->append("(");
- LogParam(p.screen_x, l);
- l->append(", ");
- LogParam(p.screen_y, l);
- l->append(", ");
- LogParam(p.link_url, l);
- l->append(", ");
- LogParam(p.unfiltered_link_url, l);
- l->append(", ");
- LogParam(p.src_url, l);
- l->append(", ");
- LogParam(p.page_url, l);
- l->append(", ");
- LogParam(p.frame_url, l);
- l->append(")");
- }
-};
-
-struct AttachExternalTabParams {
- uint64 cookie;
- GURL url;
- gfx::Rect dimensions;
- int disposition;
- bool user_gesture;
- std::string profile_name;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
};
template <>
struct ParamTraits<AttachExternalTabParams> {
typedef AttachExternalTabParams param_type;
- static void Write(Message* m, const param_type& p) {
- WriteParam(m, p.cookie);
- WriteParam(m, p.url);
- WriteParam(m, p.dimensions);
- WriteParam(m, p.disposition);
- WriteParam(m, p.user_gesture);
- WriteParam(m, p.profile_name);
- }
-
- static bool Read(const Message* m, void** iter, param_type* p) {
- return ReadParam(m, iter, &p->cookie) &&
- ReadParam(m, iter, &p->url) &&
- ReadParam(m, iter, &p->dimensions) &&
- ReadParam(m, iter, &p->disposition) &&
- ReadParam(m, iter, &p->user_gesture) &&
- ReadParam(m, iter, &p->profile_name);
- }
-
- static void Log(const param_type& p, std::string* l) {
- l->append("(");
- LogParam(p.cookie, l);
- l->append(", ");
- LogParam(p.url, l);
- l->append(", ");
- LogParam(p.dimensions, l);
- l->append(", ");
- LogParam(p.disposition, l);
- l->append(", ");
- LogParam(p.user_gesture, l);
- l->append(",");
- LogParam(p.profile_name, l);
- l->append(")");
- }
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
};
} // namespace IPC
-#define MESSAGES_INTERNAL_FILE \
- "chrome/common/automation_messages_internal.h"
-#include "ipc/ipc_message_macros.h"
+#include "chrome/common/automation_messages_internal.h"
#endif // CHROME_COMMON_AUTOMATION_MESSAGES_H__
diff --git a/chrome/common/automation_messages_internal.h b/chrome/common/automation_messages_internal.h
index 6888ea4..a0a71ae 100644
--- a/chrome/common/automation_messages_internal.h
+++ b/chrome/common/automation_messages_internal.h
@@ -4,1456 +4,1437 @@
// Defines the IPC messages used by the automation interface.
-// This header is meant to be included in multiple passes, hence no traditional
-// header guard.
-// See ipc_message_macros.h for explanation of the macros and passes.
-
#include <string>
#include <vector>
-#include "base/basictypes.h"
#include "base/string16.h"
#include "chrome/common/content_settings.h"
#include "chrome/common/navigation_types.h"
#include "chrome/test/automation/autocomplete_edit_proxy.h"
-#include "gfx/point.h"
#include "gfx/rect.h"
#include "googleurl/src/gurl.h"
#include "ipc/ipc_message_macros.h"
#include "net/url_request/url_request_status.h"
+
+
// NOTE: All IPC messages have either a routing_id of 0 (for asynchronous
// messages), or one that's been assigned by the proxy (for calls
// which expect a response). The routing_id shouldn't be used for
// any other purpose in these message types.
-// NOTE: All the new IPC messages should go at the end (before IPC_END_MESSAGES)
-// The IPC message IDs are part of an enum and hence the value
-// assumed to be constant across the builds may change.
-// The messages AutomationMsg_WindowHWND* in particular should not change
-// since the PageCyclerReferenceTest depends on the correctness of the
-// message IDs across the builds.
-
-IPC_BEGIN_MESSAGES(Automation)
-
- // This message is fired when the AutomationProvider is up and running
- // in the app (the app is not fully up at this point). The parameter to this
- // message is the version string of the automation provider. This parameter
- // is defined to be the version string as returned by
- // chrome::VersionInfo::Version().
- // The client can choose to use this version string to decide whether or not
- // it can talk to the provider.
- IPC_MESSAGE_ROUTED1(AutomationMsg_Hello, std::string)
-
- // This message is fired when the initial tab(s) are finished loading.
- IPC_MESSAGE_ROUTED0(AutomationMsg_InitialLoadsComplete)
-
- // This message notifies the AutomationProvider to append a new tab the
- // window with the given handle. The return value contains the index of
- // the new tab, or -1 if the request failed.
- // The second parameter is the url to be loaded in the new tab.
- IPC_SYNC_MESSAGE_ROUTED2_1(AutomationMsg_AppendTab, int, GURL, int)
-
- // This message requests the (zero-based) index for the currently
- // active tab in the window with the given handle. The return value contains
- // the index of the active tab, or -1 if the request failed.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_ActiveTabIndex, int, int)
-
- // This message notifies the AutomationProvider to active the tab.
- // The first parameter is the handle to window resource.
- // The second parameter is the (zero-based) index to be activated
- IPC_SYNC_MESSAGE_ROUTED2_1(AutomationMsg_ActivateTab, int, int, int)
-
- // This message requests the cookie value for given url in the
- // profile of the tab identified by the second parameter. The first
- // parameter is the URL string. The response contains the length of the
- // cookie value string. On failure, this length = -1.
- IPC_SYNC_MESSAGE_ROUTED2_2(AutomationMsg_GetCookies, GURL, int,
- int, std::string)
-
- // This message notifies the AutomationProvider to set and broadcast a cookie
- // with given name and value for the given url in the profile of the tab
- // identified by the third parameter. The first parameter is the URL
- // string, and the second parameter is the cookie name and value to be set.
- // The return value is a non-negative value on success.
- IPC_SYNC_MESSAGE_ROUTED3_1(AutomationMsg_SetCookie, GURL, std::string,
- int, int)
-
- // This message notifies the AutomationProvider to navigate to a specified
- // url in the tab with given handle. The first parameter is the handle to
- // the tab resource. The second parameter is the target url. The return
- // value contains a status code which is nonnegative on success.
- // See AutomationMsg_NavigationResponseValues for the return value.
- //
- // Deprecated in favor of
- // AutomationMsg_NavigateToURLBlockUntilNavigationsComplete.
- // TODO(phajdan.jr): Remove when the reference build gets updated.
- IPC_SYNC_MESSAGE_ROUTED2_1(AutomationMsg_NavigateToURL, int, GURL,
- AutomationMsg_NavigationResponseValues)
-
- // This message is used to implement the asynchronous version of
- // NavigateToURL.
- IPC_SYNC_MESSAGE_ROUTED2_1(AutomationMsg_NavigationAsync,
- int /* tab handle */,
- GURL,
- bool /* result */)
-
- // This message notifies the AutomationProvider to navigate back in session
- // history in the tab with given handle. The first parameter is the handle
- // to the tab resource.
- // See AutomationMsg_NavigationResponseValues for the navigation response
- // values.
- //
- // Deprecated in favor of AutomationMsg_GoBackBlockUntilNavigationsComplete.
- // TODO(phajdan.jr): Remove when the reference build gets updated.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_GoBack, int,
- AutomationMsg_NavigationResponseValues)
-
- // This message notifies the AutomationProvider to navigate forward in session
- // history in the tab with given handle. The first parameter is the handle
- // to the tab resource.
- // See AutomationMsg_NavigationResponseValues for the navigation response
- // values.
- //
- // Deprecated in favor of
- // AutomationMsg_GoForwardBlockUntilNavigationsComplete.
- // TODO(phajdan.jr): Remove when the reference build gets updated.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_GoForward, int,
- AutomationMsg_NavigationResponseValues)
-
- // This message requests the number of browser windows that the app currently
- // has open. The return value is the number of windows.
- IPC_SYNC_MESSAGE_ROUTED0_1(AutomationMsg_BrowserWindowCount, int)
-
- // This message requests the handle (int64 app-unique identifier) of the
- // window with the given (zero-based) index. On error, the returned handle
- // value is 0.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_BrowserWindow, int, int)
-
- // This message requests the number of tabs in the window with the given
- // handle. The return value contains the number of tabs, or -1 if the
- // request failed.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_TabCount, int, int)
-
- // This message requests the handle of the tab with the given (zero-based)
- // index in the given app window. First parameter specifies the given window
- // handle, second specifies the given tab_index. On error, the returned handle
- // value is 0.
- IPC_SYNC_MESSAGE_ROUTED2_1(AutomationMsg_Tab, int, int, int)
-
- // This message requests the the title of the tab with the given handle.
- // The return value contains the size of the title string. On error, this
- // value should be -1 and empty string. Note that the title can be empty in
- // which case the size would be 0.
- IPC_SYNC_MESSAGE_ROUTED1_2(AutomationMsg_TabTitle,
- int,
- int,
- std::wstring)
-
- // This message requests the url of the tab with the given handle.
- // The return value contains a success flag and the URL string. The URL will
- // be empty on failure, and it still may be empty on success.
- IPC_SYNC_MESSAGE_ROUTED1_2(AutomationMsg_TabURL,
- int /* tab handle */,
- bool /* success flag */,
- GURL)
+// NOTE: All the new IPC messages should go at the end.
+// The IPC message IDs need to match the reference builds. Since we know
+// define the IDs based on __LINE__, to allow these IPC messages to be
+// used to control an old version of Chrome we need the message IDs to
+// remain the same. This means that you should not change the line number
+// of any of the messages below. This will be fixed once Xcode supports
+// __COUNTER__, in which case we can get rid of the __LINE__.
+
+#define IPC_MESSAGE_START AutomationMsgStart
+
+// This message is fired when the AutomationProvider is up and running
+// in the app (the app is not fully up at this point). The parameter to this
+// message is the version string of the automation provider. This parameter
+// is defined to be the version string as returned by
+// chrome::VersionInfo::Version().
+// The client can choose to use this version string to decide whether or not
+// it can talk to the provider.
+IPC_MESSAGE_CONTROL1(AutomationMsg_Hello,
+ std::string)
+
+// This message is fired when the initial tab(s) are finished loading.
+IPC_MESSAGE_CONTROL0(AutomationMsg_InitialLoadsComplete)
+
+// This message notifies the AutomationProvider to append a new tab the
+// window with the given handle. The return value contains the index of
+// the new tab, or -1 if the request failed.
+// The second parameter is the url to be loaded in the new tab.
+IPC_SYNC_MESSAGE_CONTROL2_1(AutomationMsg_AppendTab,
+ int,
+ GURL,
+ int)
+
+// This message requests the (zero-based) index for the currently
+// active tab in the window with the given handle. The return value contains
+// the index of the active tab, or -1 if the request failed.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_ActiveTabIndex,
+ int,
+ int)
+
+// This message notifies the AutomationProvider to active the tab.
+// The first parameter is the handle to window resource.
+// The second parameter is the (zero-based) index to be activated
+IPC_SYNC_MESSAGE_CONTROL2_1(AutomationMsg_ActivateTab,
+ int,
+ int,
+ int)
+
+// This message requests the cookie value for given url in the
+// profile of the tab identified by the second parameter. The first
+// parameter is the URL string. The response contains the length of the
+// cookie value string. On failure, this length = -1.
+IPC_SYNC_MESSAGE_CONTROL2_2(AutomationMsg_GetCookies,
+ GURL,
+ int,
+ int,
+ std::string)
+
+// This message notifies the AutomationProvider to set and broadcast a cookie
+// with given name and value for the given url in the profile of the tab
+// identified by the third parameter. The first parameter is the URL
+// string, and the second parameter is the cookie name and value to be set.
+// The return value is a non-negative value on success.
+IPC_SYNC_MESSAGE_CONTROL3_1(AutomationMsg_SetCookie,
+ GURL,
+ std::string,
+ int,
+ int)
+
+// This message is used to implement the asynchronous version of
+// NavigateToURL.
+IPC_SYNC_MESSAGE_CONTROL2_1(AutomationMsg_NavigationAsync,
+ int /* tab handle */,
+ GURL,
+ bool /* result */)
+
+// This message requests the number of browser windows that the app currently
+// has open. The return value is the number of windows.
+IPC_SYNC_MESSAGE_CONTROL0_1(AutomationMsg_BrowserWindowCount,
+ int)
+
+// This message requests the handle (int64 app-unique identifier) of the
+// window with the given (zero-based) index. On error, the returned handle
+// value is 0.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_BrowserWindow,
+ int,
+ int)
+
+// This message requests the number of tabs in the window with the given
+// handle. The return value contains the number of tabs, or -1 if the
+// request failed.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_TabCount,
+ int,
+ int)
+
+// This message requests the handle of the tab with the given (zero-based)
+// index in the given app window. First parameter specifies the given window
+// handle, second specifies the given tab_index. On error, the returned handle
+// value is 0.
+IPC_SYNC_MESSAGE_CONTROL2_1(AutomationMsg_Tab,
+ int,
+ int,
+ int)
+
+// This message requests the the title of the tab with the given handle.
+// The return value contains the size of the title string. On error, this
+// value should be -1 and empty string. Note that the title can be empty in
+// which case the size would be 0.
+IPC_SYNC_MESSAGE_CONTROL1_2(AutomationMsg_TabTitle,
+ int,
+ int,
+ std::wstring)
+
+// This message requests the url of the tab with the given handle.
+// The return value contains a success flag and the URL string. The URL will
+// be empty on failure, and it still may be empty on success.
+IPC_SYNC_MESSAGE_CONTROL1_2(AutomationMsg_TabURL,
+ int /* tab handle */,
+ bool /* success flag */,
+ GURL)
+
+// This message notifies the AutomationProxy that a handle that it has
+// previously been given is now invalid. (For instance, if the handle
+// represented a window which has now been closed.) The parameter
+// value is the handle.
+IPC_MESSAGE_CONTROL1(AutomationMsg_InvalidateHandle,
+ int)
+
+// This message notifies the AutomationProvider that a handle is no
+// longer being used, so it can stop paying attention to the
+// associated resource. The parameter value is the handle.
+IPC_MESSAGE_CONTROL1(AutomationMsg_HandleUnused,
+ int)
+
+// This message tells the AutomationProvider to provide the given
+// authentication data to the specified tab, in response to an HTTP/FTP
+// authentication challenge.
+IPC_SYNC_MESSAGE_CONTROL3_1(AutomationMsg_SetAuth,
+ int /* tab handle */,
+ std::wstring /* username */,
+ std::wstring /* password */,
+ AutomationMsg_NavigationResponseValues /* status */)
+
+// This message tells the AutomationProvider to cancel the login in the
+// specified tab.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_CancelAuth,
+ int /* tab handle */,
+ AutomationMsg_NavigationResponseValues /* status */)
+
+// Requests that the automation provider ask history for the most recent
+// chain of redirects coming from the given URL. The response must be
+// decoded by the caller manually; it contains an integer indicating the
+// number of URLs, followed by that many wstrings indicating a chain of
+// redirects. On failure, the count will be negative.
+IPC_SYNC_MESSAGE_CONTROL2_2(AutomationMsg_RedirectsFrom,
+ int /* tab handle */,
+ GURL /* source URL */,
+ bool /* succeeded */,
+ std::vector<GURL> /* redirects */)
+
+// This message asks the AutomationProvider whether a tab is waiting for
+// login info.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_NeedsAuth,
+ int /* tab handle */,
+ bool /* status */)
+
+// This message requests that the AutomationProvider executes a JavaScript,
+// which is sent embedded in a 'javascript:' URL.
+// The javascript is executed in context of child frame whose xpath
+// is passed as parameter (context_frame). The execution results in
+// a serialized JSON string response.
+IPC_SYNC_MESSAGE_CONTROL3_1(AutomationMsg_DomOperation,
+ int /* tab handle */,
+ std::wstring /* context_frame */,
+ std::wstring /* the javascript to be executed */,
+ std::string /* the serialized json string containg
+ the result of a javascript
+ execution */)
+
+// Is the Download Shelf visible for the specified browser?
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_ShelfVisibility,
+ int /* browser_handle */,
+ bool /* is_visible */)
+
+// This message requests the number of constrained windows in the tab with
+// the given handle. The return value contains the number of constrained
+// windows, or -1 if the request failed.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_ConstrainedWindowCount,
+ int /* tab_handle */,
+ int /* constrained_window_count */)
+
+// This message requests the bounds of the specified View element in
+// window coordinates.
+// Request:
+// int - the handle of the window in which the view appears
+// int - the ID of the view, as specified in chrome/browser/ui/view_ids.h
+// bool - whether the bounds should be returned in the screen coordinates
+// (if true) or in the browser coordinates (if false).
+// Response:
+// bool - true if the view was found
+// gfx::Rect - the bounds of the view, in window coordinates
+IPC_SYNC_MESSAGE_CONTROL3_2(AutomationMsg_WindowViewBounds,
+ int,
+ int,
+ bool,
+ bool,
+ gfx::Rect)
+
+// This message sets the bounds of the window.
+// Request:
+// int - the handle of the window to resize
+// gfx::Rect - the bounds of the window
+// Response:
+// bool - true if the resize was successful
+IPC_SYNC_MESSAGE_CONTROL2_1(AutomationMsg_SetWindowBounds,
+ int,
+ gfx::Rect,
+ bool)
+
+// TODO(port): Port these messages.
+//
+// This message requests that a drag be performed in window coordinate space
+// Request:
+// int - the handle of the window that's the context for this drag
+// std::vector<gfx::Point> - the path of the drag in window coordinate
+// space; it should have at least 2 points
+// (start and end)
+// int - the flags which identify the mouse button(s) for the drag, as
+// defined in chrome/views/event.h
+// Response:
+// bool - true if the drag could be performed
+IPC_SYNC_MESSAGE_CONTROL4_1(AutomationMsg_WindowDrag,
+ int,
+ std::vector<gfx::Point>,
+ int,
+ bool,
+ bool)
+
+// Similar to AutomationMsg_InitialLoadsComplete, this indicates that the
+// new tab ui has completed the initial load of its data.
+// Time is how many milliseconds the load took.
+IPC_MESSAGE_CONTROL1(AutomationMsg_InitialNewTabUILoadComplete,
+ int /* time */)
+
+// This message sends a inspect element request for a given tab. The response
+// contains the number of resources loaded by the inspector controller.
+IPC_SYNC_MESSAGE_CONTROL3_1(AutomationMsg_InspectElement,
+ int, /* tab_handle */
+ int, /* x */
+ int /* y */,
+ int)
+
+// This message requests the process ID of the tab that corresponds
+// to the given automation handle.
+// The return value has an integer corresponding to the PID of the tab's
+// renderer, 0 if the tab currently has no renderer process, or -1 on error.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_TabProcessID,
+ int /* tab_handle */,
+ int /* process ID */)
+
+// This tells the browser to enable or disable the filtered network layer.
+IPC_MESSAGE_CONTROL1(AutomationMsg_SetFilteredInet,
+ bool /* enabled */)
+
+// Gets the directory that downloads will occur in for the active profile.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_DownloadDirectory,
+ int /* tab_handle */,
+ FilePath /* directory */)
+
+// This message requests the id of the view that has the focus in the
+// specified window. If no view is focused, -1 is returned. Note that the
+// window should either be a ViewWindow or a Browser.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_GetFocusedViewID,
+ int /* view_handle */,
+ int /* focused_view_id */)
+
+// This message shows/hides the window.
+IPC_SYNC_MESSAGE_CONTROL2_1(AutomationMsg_SetWindowVisible,
+ int /* view_handle */,
+ bool /* visible */,
+ bool /* success */)
+
+// Gets the active status of a window.
+IPC_SYNC_MESSAGE_CONTROL1_2(AutomationMsg_IsWindowActive,
+ int /* view_handle */,
+ bool /* success */,
+ bool /* active */)
+
+// Makes the specified window the active window.
+IPC_SYNC_MESSAGE_CONTROL1_0(AutomationMsg_ActivateWindow,
+ int /* view_handle */)
+
+// Opens a new browser window.
+// TODO(sky): remove this and replace with OpenNewBrowserWindowOfType.
+// Doing this requires updating the reference build.
+IPC_SYNC_MESSAGE_CONTROL1_0(AutomationMsg_OpenNewBrowserWindow,
+ bool /* show */ )
+
+// This message requests the handle (int64 app-unique identifier) of the
+// current active top window. On error, the returned handle value is 0.
+IPC_SYNC_MESSAGE_CONTROL0_1(AutomationMsg_ActiveWindow,
+ int)
+
+// This message requests the browser associated with the specified window
+// handle.
+// The return value contains a success flag and the handle of the browser.
+IPC_SYNC_MESSAGE_CONTROL1_2(AutomationMsg_BrowserForWindow,
+ int /* window handle */,
+ bool /* success flag */,
+ int /* browser handle */)
+
+// This message requests the window associated with the specified browser
+// handle.
+// The return value contains a success flag and the handle of the window.
+IPC_SYNC_MESSAGE_CONTROL1_2(AutomationMsg_WindowForBrowser,
+ int /* browser handle */,
+ bool /* success flag */,
+ int /* window handle */)
+
+// This message requests the AutocompleteEdit associated with the specified
+// browser handle.
+// The return value contains a success flag and the handle of the omnibox.
+IPC_SYNC_MESSAGE_CONTROL1_2(AutomationMsg_AutocompleteEditForBrowser,
+ int /* browser handle */,
+ bool /* success flag */,
+ int /* AutocompleteEdit handle */)
+
+// This message requests that a mouse click be performed in window coordinate
+// space.
+// Request:
+// int - the handle of the window that's the context for this click
+// gfx::Point - the point to click
+// int - the flags which identify the mouse button(s) for the click, as
+// defined in chrome/views/event.h
+IPC_MESSAGE_CONTROL3(AutomationMsg_WindowClick,
+ int,
+ gfx::Point,
+ int)
+
+// This message requests that a key press be performed.
+// Request:
+// int - the handle of the window that's the context for this click
+// int - the app::KeyboardCode of the key that was pressed.
+// int - the flags which identify the modifiers (shift, ctrl, alt)
+// associated for, as defined in chrome/views/event.h
+IPC_MESSAGE_CONTROL3(AutomationMsg_WindowKeyPress,
+ int,
+ int,
+ int)
+
+// This message notifies the AutomationProvider to create a tab which is
+// hosted by an external process.
+// Request:
+// ExternalTabSettings - settings for external tab
+IPC_SYNC_MESSAGE_CONTROL1_4(AutomationMsg_CreateExternalTab,
+ ExternalTabSettings /* settings*/,
+ gfx::NativeWindow /* Tab container window */,
+ gfx::NativeWindow /* Tab window */,
+ int /* Handle to the new tab */,
+ int /* Session Id of the new tab */)
+
+// This message notifies the AutomationProvider to navigate to a specified
+// url in the external tab with given handle. The first parameter is the
+// handle to the tab resource. The second parameter is the target url.
+// The third parameter is the referrer.
+// The return value contains a status code which is nonnegative on success.
+// see AutomationMsg_NavigationResponseValues for the navigation response.
+IPC_SYNC_MESSAGE_CONTROL3_1(AutomationMsg_NavigateInExternalTab,
+ int,
+ GURL,
+ GURL,
+ AutomationMsg_NavigationResponseValues)
+
+// This message is an outgoing message from Chrome to an external host.
+// It is a notification that the NavigationState was changed
+// Request:
+// -int: The flags specifying what changed
+// (see TabContents::InvalidateTypes)
+// Response:
+// None expected
+IPC_MESSAGE_ROUTED2(AutomationMsg_NavigationStateChanged,
+ int, // TabContents::InvalidateTypes
+ NavigationInfo) // title, url etc.
+
+// This message is an outgoing message from Chrome to an external host.
+// It is a notification that the target URL has changed (the target URL
+// is the URL of the link that the user is hovering on)
+// Request:
+// -std::wstring: The new target URL
+// Response:
+// None expected
+IPC_MESSAGE_ROUTED1(AutomationMsg_UpdateTargetUrl,
+ std::wstring)
+
+// This message notifies the AutomationProvider to show the specified html
+// text in an interstitial page in the tab with given handle. The first
+// parameter is the handle to the tab resource. The second parameter is the
+// html text to be displayed.
+// The return value contains a success flag.
+IPC_SYNC_MESSAGE_CONTROL2_1(AutomationMsg_ShowInterstitialPage,
+ int,
+ std::string,
+ AutomationMsg_NavigationResponseValues)
+
+// This message notifies the AutomationProvider to hide the current
+// interstitial page in the tab with given handle. The parameter is the
+// handle to the tab resource.
+// The return value contains a success flag.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_HideInterstitialPage,
+ int,
+ bool)
+
+// This message requests that a tab be closed.
+// Request:
+// - int: handle of the tab to close
+// - bool: if true the proxy blocks until the tab has completely closed,
+// otherwise the proxy only blocks until it initiates the close.
+IPC_SYNC_MESSAGE_CONTROL2_1(AutomationMsg_CloseTab,
+ int,
+ bool,
+ bool)
+
+// This message requests that the browser be closed.
+// Request:
+// - int: handle of the browser which contains the tab
+// Response:
+// - bool: whether the operation was successfull.
+// - bool: whether the browser process will be terminated as a result (if
+// this was the last closed browser window).
+IPC_SYNC_MESSAGE_CONTROL1_2(AutomationMsg_CloseBrowser,
+ int,
+ bool,
+ bool)
+
+IPC_MESSAGE_CONTROL1(AutomationMsg_CloseBrowserRequestAsync,
+ int)
#if defined(OS_WIN)
- // TODO(estade): delete this unused message.
- IPC_SYNC_MESSAGE_ROUTED0_0(AutomationMsg_WindowHWND)
-
- // This message requests the HWND of the tab that corresponds
- // to the given automation handle.
- // The return value contains the HWND value, which is 0 if the call fails.
- //
- // TODO(estade): The only test that uses this message is
- // NPAPIVisiblePluginTester.SelfDeletePluginInvokeInSynchronousMouseMove. It
- // can probably be done in another way, and this can be removed.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_TabHWND,
- int /* tab_handle */,
- HWND /* win32 Window Handle */)
+// TODO(port): Port these messages.
+//
+// This message is an outgoing message from Chrome to an external host.
+// It is a request to process a keyboard accelerator.
+// Request:
+// -MSG: The keyboard message
+// Response:
+// None expected
+// TODO(sanjeevr): Ideally we need to add a response from the external
+// host saying whether it processed the accelerator
+IPC_MESSAGE_ROUTED1(AutomationMsg_HandleAccelerator,
+ MSG)
+
+// This message is sent by the container of an externally hosted tab to
+// reflect any accelerator keys that it did not process. This gives the
+// tab a chance to handle the keys
+// Request:
+// - int: handle of the tab
+// -MSG: The keyboard message that the container did not handle
+// Response:
+// None expected
+IPC_MESSAGE_CONTROL2(AutomationMsg_ProcessUnhandledAccelerator,
+ int,
+ MSG)
#endif // defined(OS_WIN)
- // This message notifies the AutomationProxy that a handle that it has
- // previously been given is now invalid. (For instance, if the handle
- // represented a window which has now been closed.) The parameter
- // value is the handle.
- IPC_MESSAGE_ROUTED1(AutomationMsg_InvalidateHandle, int)
-
- // This message notifies the AutomationProvider that a handle is no
- // longer being used, so it can stop paying attention to the
- // associated resource. The parameter value is the handle.
- IPC_MESSAGE_ROUTED1(AutomationMsg_HandleUnused, int)
-
- // This message tells the AutomationProvider to provide the given
- // authentication data to the specified tab, in response to an HTTP/FTP
- // authentication challenge.
- IPC_SYNC_MESSAGE_ROUTED3_1(AutomationMsg_SetAuth,
- int, // tab handle
- std::wstring, // username
- std::wstring, // password
- AutomationMsg_NavigationResponseValues) // status
-
- // This message tells the AutomationProvider to cancel the login in the
- // specified tab.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_CancelAuth,
- int, // tab handle
- AutomationMsg_NavigationResponseValues) // status
-
- // Requests that the automation provider ask history for the most recent
- // chain of redirects coming from the given URL. The response must be
- // decoded by the caller manually; it contains an integer indicating the
- // number of URLs, followed by that many wstrings indicating a chain of
- // redirects. On failure, the count will be negative.
- IPC_SYNC_MESSAGE_ROUTED2_2(AutomationMsg_RedirectsFrom,
- int, // tab handle
- GURL, // source URL
- bool /* succeeded */,
- std::vector<GURL> /* redirects */)
-
- // This message asks the AutomationProvider whether a tab is waiting for
- // login info.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_NeedsAuth,
- int, // tab handle
- bool) // status
-
- // This message requests the AutomationProvider to apply a certain
- // accelerator. It is completely asynchronous with the resulting accelerator
- // action.
- IPC_SYNC_MESSAGE_ROUTED2_0(AutomationMsg_ApplyAccelerator,
- int, // window handle
- int) // accelerator id like (IDC_BACK,
- // IDC_FORWARD, etc)
- // The list can be found at
- // chrome/app/chrome_command_ids.h
-
- // This message requests that the AutomationProvider executes a JavaScript,
- // which is sent embedded in a 'javascript:' URL.
- // The javascript is executed in context of child frame whose xpath
- // is passed as parameter (context_frame). The execution results in
- // a serialized JSON string response.
- IPC_SYNC_MESSAGE_ROUTED3_1(AutomationMsg_DomOperation,
- int, // tab handle
- std::wstring, // context_frame
- std::wstring, // the javascript to be executed
- std::string) // the serialized json string
- // containing the result of a
- // javascript execution
-
- // Is the Download Shelf visible for the specified browser?
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_ShelfVisibility,
- int /* browser_handle */,
- bool /* is_visible */)
-
- // This message requests the number of constrained windows in the tab with
- // the given handle. The return value contains the number of constrained
- // windows, or -1 if the request failed.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_ConstrainedWindowCount,
- int /* tab_handle */,
- int /* constrained_window_count */)
-
- // This message requests the bounds of the specified View element in
- // window coordinates.
- // Request:
- // int - the handle of the window in which the view appears
- // int - the ID of the view, as specified in chrome/browser/view_ids.h
- // bool - whether the bounds should be returned in the screen coordinates
- // (if true) or in the browser coordinates (if false).
- // Response:
- // bool - true if the view was found
- // gfx::Rect - the bounds of the view, in window coordinates
- IPC_SYNC_MESSAGE_ROUTED3_2(AutomationMsg_WindowViewBounds, int, int,
- bool, bool, gfx::Rect)
-
- // This message sets the bounds of the window.
- // Request:
- // int - the handle of the window to resize
- // gfx::Rect - the bounds of the window
- // Response:
- // bool - true if the resize was successful
- IPC_SYNC_MESSAGE_ROUTED2_1(AutomationMsg_SetWindowBounds, int, gfx::Rect,
- bool)
+// Sent by the external tab to the host to notify that the user has tabbed
+// out of the tab.
+// Request:
+// - bool: |reverse| set to true when shift-tabbing out of the tab, false
+// otherwise.
+// Response:
+// None expected
+IPC_MESSAGE_ROUTED1(AutomationMsg_TabbedOut,
+ bool)
+
+// Sent by the external tab host to ask focus to be set to either the first
+// or last element on the page.
+// Request:
+// - int: handle of the tab
+// - bool: |reverse|
+// true: Focus will be set to the last focusable element
+// false: Focus will be set to the first focusable element
+// - bool: |restore_focus_to_view|
+// true: The renderer view associated with the current tab will be
+// infomed that it is receiving focus.
+// Response:
+// None expected
+IPC_MESSAGE_CONTROL3(AutomationMsg_SetInitialFocus,
+ int,
+ bool,
+ bool)
+
+// This message is an outgoing message from Chrome to an external host.
+// It is a request to open a url
+// Request:
+// -GURL: The URL to open
+// -GURL: The referrer
+// -int: The WindowOpenDisposition that specifies where the URL should
+// be opened (new tab, new window etc).
+// Response:
+// None expected
+IPC_MESSAGE_ROUTED3(AutomationMsg_OpenURL,
+ GURL,
+ GURL,
+ int)
+
+// This message requests the provider to wait until the specified tab has
+// finished restoring after session restore.
+// Request:
+// - int: handle of the tab
+// Response:
+// - bool: whether the operation was successful.
+IPC_SYNC_MESSAGE_CONTROL1_0(AutomationMsg_WaitForTabToBeRestored,
+ int)
+
+// This message is an outgoing message from Chrome to an external host.
+// It is a notification that a navigation happened
+// Request:
+//
+// Response:
+// None expected
+IPC_MESSAGE_ROUTED1(AutomationMsg_DidNavigate,
+ NavigationInfo)
+
+// This message requests the different security states of the page displayed
+// in the specified tab.
+// Request:
+// - int: handle of the tab
+// Response:
+// - bool: whether the operation was successful.
+// - SecurityStyle: the security style of the tab.
+// - int: the status of the server's ssl cert (0 means no errors or no ssl
+// was used).
+// - int: the insecure content state, 0 means no insecure contents.
+
+IPC_SYNC_MESSAGE_CONTROL1_4(AutomationMsg_GetSecurityState,
+ int,
+ bool,
+ SecurityStyle,
+ int,
+ int)
+
+// This message requests the page type of the page displayed in the specified
+// tab (normal, error or interstitial).
+// Request:
+// - int: handle of the tab
+// Response:
+// - bool: whether the operation was successful.
+// - PageType: the type of the page currently displayed.
+IPC_SYNC_MESSAGE_CONTROL1_2(AutomationMsg_GetPageType,
+ int,
+ bool,
+ PageType)
+
+// This message simulates the user action on the SSL blocking page showing in
+// the specified tab. This message is only effective if an interstitial page
+// is showing in the tab.
+// Request:
+// - int: handle of the tab
+// - bool: whether to proceed or abort the navigation
+// Response:
+// - AutomationMsg_NavigationResponseValues: result of the operation.
+IPC_SYNC_MESSAGE_CONTROL2_1(AutomationMsg_ActionOnSSLBlockingPage,
+ int,
+ bool,
+ AutomationMsg_NavigationResponseValues)
+
+// Message to request that a browser window is brought to the front and
+// activated.
+// Request:
+// - int: handle of the browser window.
+// Response:
+// - bool: True if the browser is brought to the front.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_BringBrowserToFront,
+ int,
+ bool)
+
+// Message to request whether a certain item is enabled of disabled in the
+// menu in the browser window
+//
+// Request:
+// - int: handle of the browser window.
+// - int: IDC message identifier to query if enabled
+// Response:
+// - bool: True if the command is enabled on the menu
+IPC_SYNC_MESSAGE_CONTROL2_1(AutomationMsg_IsMenuCommandEnabled,
+ int,
+ int,
+ bool)
+
+// This message notifies the AutomationProvider to print the tab with given
+// handle. The first parameter is the handle to the tab resource. The
+// return value contains a bool which is true on success.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_PrintNow,
+ int,
+ bool)
+
+// This message notifies the AutomationProvider to reload the current page in
+// the tab with given handle. The first parameter is the handle to the tab
+// resource. The return value contains a status code which is nonnegative on
+// success.
+// see AutomationMsg_NavigationResponseValues for the navigation response.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_Reload,
+ int,
+ AutomationMsg_NavigationResponseValues)
+
+// This message requests the handle (int64 app-unique identifier) of the
+// last active browser window, or the browser at index 0 if there is no last
+// active browser, or it no longer exists. Returns 0 if no browser windows
+// exist.
+IPC_SYNC_MESSAGE_CONTROL0_1(AutomationMsg_LastActiveBrowserWindow,
+ int)
+
+// This message notifies the AutomationProvider to save the page with given
+// handle. The first parameter is the handle to the tab resource. The second
+// parameter is the main HTML file name. The third parameter is the directory
+// for saving resources. The fourth parameter is the saving type: 0 for HTML
+// only; 1 for complete web page.
+// The return value contains a bool which is true on success.
+IPC_SYNC_MESSAGE_CONTROL4_1(AutomationMsg_SavePage,
+ int,
+ FilePath,
+ FilePath,
+ int,
+ bool)
+
+// This message requests the text currently being displayed in the
+// AutocompleteEdit. The parameter is the handle to the AutocompleteEdit.
+// The return value is a string indicating the text in the AutocompleteEdit.
+IPC_SYNC_MESSAGE_CONTROL1_2(AutomationMsg_AutocompleteEditGetText,
+ int /* autocomplete edit handle */,
+ bool /* the requested autocomplete edit exists */,
+ std::wstring /* omnibox text */)
+
+// This message sets the text being displayed in the AutocompleteEdit. The
+// first parameter is the handle to the omnibox and the second parameter is
+// the text to be displayed in the AutocompleteEdit.
+// The return value has no parameters and is returned when the operation has
+// completed.
+IPC_SYNC_MESSAGE_CONTROL2_1(AutomationMsg_AutocompleteEditSetText,
+ int /* autocomplete edit handle */,
+ std::wstring /* text to set */,
+ bool /* the requested autocomplete edit exists */)
+
+// This message requests if a query to a autocomplete provider is still in
+// progress. The first parameter in the request is the handle to the
+// autocomplete edit.
+// The first return value indicates if the request succeeded.
+// The second return value indicates if a query is still in progress.
+IPC_SYNC_MESSAGE_CONTROL1_2( \
+ AutomationMsg_AutocompleteEditIsQueryInProgress,
+ int /* autocomplete edit handle*/,
+ bool /* the requested autocomplete edit exists */,
+ bool /* indicates if a query is in progress */)
+
+// This message requests a list of the autocomplete messages currently being
+// displayed by the popup. The parameter in the request is a handle to the
+// autocomplete edit.
+// The first return value indicates if the request was successful, while
+// while the second is the actual list of matches.
+IPC_SYNC_MESSAGE_CONTROL1_2(AutomationMsg_AutocompleteEditGetMatches,
+ int /* autocomplete edit handle*/,
+ bool /* the requested autocomplete edit exists */,
+ std::vector<AutocompleteMatchData> /* matches */)
+
+// This message requests the execution of a browser command in the browser
+// for which the handle is specified.
+// The return value contains a boolean, whether the command was dispatched.
+IPC_SYNC_MESSAGE_CONTROL2_1(AutomationMsg_WindowExecuteCommandAsync,
+ int /* automation handle */,
+ int /* browser command */,
+ bool /* success flag */)
+
+// This message requests the execution of a browser command in the browser
+// for which the handle is specified.
+// The return value contains a boolean, whether the command was dispatched
+// and successful executed.
+IPC_SYNC_MESSAGE_CONTROL2_1(AutomationMsg_WindowExecuteCommand,
+ int /* automation handle */,
+ int /* browser command */,
+ bool /* success flag */)
+
+
+// This message opens the Find window within a tab corresponding to the
+// supplied tab handle.
+IPC_MESSAGE_CONTROL1(AutomationMsg_OpenFindInPage,
+ int /* tab_handle */)
+
+// Posts a message from external host to chrome renderer.
+IPC_MESSAGE_CONTROL4(AutomationMsg_HandleMessageFromExternalHost,
+ int /* automation handle */,
+ std::string /* message */,
+ std::string /* origin */,
+ std::string /* target */)
+
+// A message for an external host.
+IPC_MESSAGE_ROUTED3(AutomationMsg_ForwardMessageToExternalHost,
+ std::string /* message */,
+ std::string /* origin */,
+ std::string /* target */)
+
+// This message starts a find within a tab corresponding to the supplied
+// tab handle. The parameter |request| specifies what to search for.
+// If an error occurs, |matches_found| will be -1.
+//
+IPC_SYNC_MESSAGE_CONTROL2_2(AutomationMsg_Find,
+ int /* tab_handle */,
+ AutomationMsg_Find_Params /* params */,
+ int /* active_ordinal */,
+ int /* matches_found */)
+
+// Is the Find window fully visible (and not animating) for the specified
+// tab?
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_FindWindowVisibility,
+ int /* tab_handle */,
+ bool /* is_visible */)
+
+// Where is the Find window located. |x| and |y| will be -1, -1 on failure.
+IPC_SYNC_MESSAGE_CONTROL1_2(AutomationMsg_FindWindowLocation,
+ int /* tab_handle */,
+ int /* x */,
+ int /* y */)
+
+// Is the Bookmark bar visible? The return value will indicate whether it is
+// visible or not and whether it is being animated into (or out of its place).
+IPC_SYNC_MESSAGE_CONTROL1_2(AutomationMsg_BookmarkBarVisibility,
+ int /* browser_handle */,
+ bool, /* is_visible */
+ bool /* still_animating */)
+
+// This message requests the number of related info bars opened. It
+// returns -1 if an error occurred.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_GetInfoBarCount,
+ int /* tab_handle */,
+ int /* info bar count */)
+
+// This message triggers the action associated with the "accept" button in
+// the info-bar at the specified index. If |wait for navigation| is true, it
+// won't return until a navigation has occurred.
+IPC_SYNC_MESSAGE_CONTROL3_1(AutomationMsg_ClickInfoBarAccept,
+ int /* tab_handle */,
+ int /* info bar index */,
+ bool /* wait for navigation */,
+
+ /* navigation result */
+ AutomationMsg_NavigationResponseValues)
+
+// This message retrieves the last time a navigation occurred in the specified
+// tab. The value is intended to be used with WaitForNavigation.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_GetLastNavigationTime,
+ int /* tab_handle */,
+ int64 /* last navigation time */)
+
+// This messages is used to block until a new navigation occurs (if there is
+// none more recent then the time specified).
+IPC_SYNC_MESSAGE_CONTROL2_1(AutomationMsg_WaitForNavigation,
+ int /* tab_handle */,
+ int64 /* last navigation time */,
+
+ /* navigation result */
+ AutomationMsg_NavigationResponseValues)
+
+// This messages sets an int-value preference.
+IPC_SYNC_MESSAGE_CONTROL3_1(AutomationMsg_SetIntPreference,
+ int /* browser handle */,
+ std::string /* pref name */,
+ int /* value */,
+ bool /* success */)
+
+// Queries whether an app modal dialog is currently being shown. (i.e. a
+// javascript alert) and which buttons it contains.
+IPC_SYNC_MESSAGE_CONTROL0_2(AutomationMsg_ShowingAppModalDialog,
+ bool /* showing dialog */,
+ int /* view::DelegateDialog::DialogButton */)
+
+// This message triggers the specified button for the currently showing
+// modal dialog.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_ClickAppModalDialogButton,
+ int /* view::DelegateDialog::DialogButton */,
+ bool /* success */)
+
+// This messages sets a string-value preference.
+IPC_SYNC_MESSAGE_CONTROL3_1(AutomationMsg_SetStringPreference,
+ int /* browser handle */,
+ std::string /* pref name */,
+ std::string /* pref value */,
+ bool)
+
+// This messages gets a boolean-value preference.
+IPC_SYNC_MESSAGE_CONTROL2_2(AutomationMsg_GetBooleanPreference,
+ int /* browser handle */,
+ std::string /* pref name */,
+ bool /* success */,
+ bool /* pref value */)
+
+// This messages sets a boolean-value preference.
+IPC_SYNC_MESSAGE_CONTROL3_1(AutomationMsg_SetBooleanPreference,
+ int /* browser handle */,
+ std::string /* pref name */,
+ bool /* pref value */,
+ bool /* success */)
+
+// Queries the current used encoding name of the page in the specified
+// web content tab.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_GetPageCurrentEncoding,
+ int /* tab handle */,
+ std::string /* current used encoding name */)
+
+// Uses the specified encoding to override the encoding of the page in the
+// specified web content tab.
+IPC_SYNC_MESSAGE_CONTROL2_1(AutomationMsg_OverrideEncoding,
+ int /* tab handle */,
+ std::string /* overrided encoding name */,
+ bool /* success */)
+
+// Used to disable the dialog box that prompts the user for a path when
+// saving a web page.
+IPC_SYNC_MESSAGE_CONTROL1_0(AutomationMsg_SavePackageShouldPromptUser,
+ bool /* false if we want to not show the dialog */)
+
+// This message is an outgoing message from Chrome to an external host.
+// It is a notification that a navigation failed
+// Request:
+// -int : The status code.
+// -GURL: The URL we failed to navigate to.
+// Response:
+// None expected
+IPC_MESSAGE_ROUTED2(AutomationMsg_NavigationFailed,
+ int,
+ GURL)
#if defined(OS_WIN)
- // TODO(port): Port these messages.
- //
- // This message requests that a drag be performed in window coordinate space
- // Request:
- // int - the handle of the window that's the context for this drag
- // std::vector<gfx::Point> - the path of the drag in window coordinate
- // space; it should have at least 2 points
- // (start and end)
- // int - the flags which identify the mouse button(s) for the drag, as
- // defined in chrome/views/event.h
- // Response:
- // bool - true if the drag could be performed
- IPC_SYNC_MESSAGE_ROUTED4_1(AutomationMsg_WindowDrag,
- int, std::vector<gfx::Point>, int, bool, bool)
+// This message is an outgoing message from an automation client to Chrome.
+// It is used to reposition a chrome tab window.
+IPC_MESSAGE_CONTROL2(AutomationMsg_TabReposition,
+ int /* tab handle */,
+ Reposition_Params /* SetWindowPos params */)
#endif // defined(OS_WIN)
- // Similar to AutomationMsg_InitialLoadsComplete, this indicates that the
- // new tab ui has completed the initial load of its data.
- // Time is how many milliseconds the load took.
- IPC_MESSAGE_ROUTED1(AutomationMsg_InitialNewTabUILoadComplete,
- int /* time */)
-
- // This message starts a find within a tab corresponding to the supplied
- // tab handle. The return value contains the number of matches found on the
- // page within the tab specified. The parameter 'search_string' specifies
- // what string to search for, 'forward' specifies whether to search in
- // forward direction (1=forward, 0=back), 'match_case' specifies case
- // sensitivity
- // (1=case sensitive, 0=case insensitive). If an error occurs, matches_found
- // will be -1.
- //
- // NOTE: This message has been deprecated, please use the new message
- // AutomationMsg_Find below.
- //
- IPC_SYNC_MESSAGE_ROUTED4_2(AutomationMsg_FindInPage, // DEPRECATED.
- int, /* tab_handle */
- std::wstring, /* find_request */
- int, /* forward */
- int /* match_case */,
- int /* active_ordinal */,
- int /* matches_found */)
-
- // This message sends a inspect element request for a given tab. The response
- // contains the number of resources loaded by the inspector controller.
- IPC_SYNC_MESSAGE_ROUTED3_1(AutomationMsg_InspectElement,
- int, /* tab_handle */
- int, /* x */
- int /* y */,
- int)
-
- // This message requests the process ID of the tab that corresponds
- // to the given automation handle.
- // The return value has an integer corresponding to the PID of the tab's
- // renderer, 0 if the tab currently has no renderer process, or -1 on error.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_TabProcessID,
- int /* tab_handle */,
- int /* process ID */)
-
- // This tells the browser to enable or disable the filtered network layer.
- IPC_MESSAGE_ROUTED1(AutomationMsg_SetFilteredInet,
- bool /* enabled */)
-
- // Gets the directory that downloads will occur in for the active profile.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_DownloadDirectory,
- int /* tab_handle */,
- FilePath /* directory */)
-
- // This message requests the id of the view that has the focus in the
- // specified window. If no view is focused, -1 is returned. Note that the
- // window should either be a ViewWindow or a Browser.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_GetFocusedViewID,
- int /* view_handle */,
- int /* focused_view_id */)
-
- // This message shows/hides the window.
- IPC_SYNC_MESSAGE_ROUTED2_1(AutomationMsg_SetWindowVisible,
- int /* view_handle */,
- bool /* visible */,
- bool /* success */)
-
- // Gets the active status of a window.
- IPC_SYNC_MESSAGE_ROUTED1_2(AutomationMsg_IsWindowActive,
- int /* view_handle */,
- bool /* success */,
- bool /* active */)
-
- // Makes the specified window the active window.
- IPC_SYNC_MESSAGE_ROUTED1_0(AutomationMsg_ActivateWindow,
- int /* view_handle */)
-
- // Opens a new browser window.
- // TODO(sky): remove this and replace with OpenNewBrowserWindowOfType.
- // Doing this requires updating the reference build.
- IPC_SYNC_MESSAGE_ROUTED1_0(AutomationMsg_OpenNewBrowserWindow,
- bool /* show */ )
-
- // This message requests the handle (int64 app-unique identifier) of the
- // current active top window. On error, the returned handle value is 0.
- IPC_SYNC_MESSAGE_ROUTED0_1(AutomationMsg_ActiveWindow, int)
-
- // This message requests the browser associated with the specified window
- // handle.
- // The return value contains a success flag and the handle of the browser.
- IPC_SYNC_MESSAGE_ROUTED1_2(AutomationMsg_BrowserForWindow,
- int /* window handle */,
- bool /* success flag */,
- int /* browser handle */)
-
- // This message requests the window associated with the specified browser
- // handle.
- // The return value contains a success flag and the handle of the window.
- IPC_SYNC_MESSAGE_ROUTED1_2(AutomationMsg_WindowForBrowser,
- int /* browser handle */,
- bool /* success flag */,
- int /* window handle */)
-
- // This message requests the AutocompleteEdit associated with the specified
- // browser handle.
- // The return value contains a success flag and the handle of the omnibox.
- IPC_SYNC_MESSAGE_ROUTED1_2(AutomationMsg_AutocompleteEditForBrowser,
- int /* browser handle */,
- bool /* success flag */,
- int /* AutocompleteEdit handle */)
+// Gets the title of the top level browser window.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_WindowTitle,
+ int /* automation handle */,
+ string16 /* title text */ )
+
+// Tab load complete
+IPC_MESSAGE_ROUTED1(AutomationMsg_TabLoaded,
+ GURL)
+
+// This message requests the tabstrip index of the tab with the given handle.
+// The return value contains the index, which will be -1 on failure.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_TabIndex,
+ int,
+ int)
+
+// This message requests the handle (int64 app-unique identifier) of
+// a valid normal browser window, i.e. normal type and non-incognito mode.
+// On error, the returned handle value is 0.
+IPC_SYNC_MESSAGE_CONTROL0_1(AutomationMsg_FindNormalBrowserWindow,
+ int)
+
+// This message requests the number of normal browser windows, i.e. normal
+// type and non-incognito mode that the app currently has open. The return
+// value is the number of windows.
+IPC_SYNC_MESSAGE_CONTROL0_1(AutomationMsg_NormalBrowserWindowCount,
+ int)
+
+// Used to put the browser into "extension automation mode" for a given
+// set of Chrome Extensions API functions for the current profile, or turn
+// off automation mode. The specified tab is used as the conduit for all
+// automated API functions. It must be an external tab (as in
+// AutomationMsg_CreateExternalTab).
+IPC_MESSAGE_CONTROL2(AutomationMsg_SetEnableExtensionAutomation,
+ // Tab handle.
+ int,
+ // Empty to disable automation, non-empty to enable
+ // automation of the specified API functions, single
+ // entry of "*" to enable automation of all API
+ // functions.
+ std::vector<std::string>)
+
+// This message tells the browser to start using the new proxy configuration
+// represented by the given JSON string. The parameters used in the JSON
+// string are defined in automation_constants.h.
+IPC_MESSAGE_CONTROL1(AutomationMsg_SetProxyConfig,
+ std::string /* proxy_config_json_string */)
+
+// Sets Download Shelf visibility for the specified browser.
+IPC_SYNC_MESSAGE_CONTROL2_0(AutomationMsg_SetShelfVisibility,
+ int /* browser_handle */,
+ bool /* is_visible */)
+
+// This message requests the number of blocked popups in a certain tab with
+// the given handle. The return value is the number of blocked popups, or -1
+// if this request failed.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_BlockedPopupCount,
+ int /* tab_handle */,
+ int /* blocked_popup_count */)
+
+// This message retrieves the locale of the browser process. On success
+// |chrome_locale| will contain the locale as reported by ICU. On failure
+// |chrome_locale| is the empty string.
+IPC_SYNC_MESSAGE_CONTROL0_1(AutomationMsg_GetBrowserLocale,
+ string16 /* chrome_locale */)
#if defined(OS_WIN)
- // TODO(estade): This message is defined later on for Mac and Linux. This is
- // to avoid adding a new IPC in the middle for those platforms (see comment
- // at top). The message is exactly the same, so they should be remerged when
- // all messages in this file have been made cross-platform (at which point we
- // will need to check in new reference builds).
- //
- // This message requests that a mouse click be performed in window coordinate
- // space.
- // Request:
- // int - the handle of the window that's the context for this click
- // gfx::Point - the point to click
- // int - the flags which identify the mouse button(s) for the click, as
- // defined in chrome/views/event.h
- IPC_MESSAGE_ROUTED3(AutomationMsg_WindowClick, int, gfx::Point, int)
-#endif // defined(OS_WIN)
-
- // This message requests that a key press be performed.
- // Request:
- // int - the handle of the window that's the context for this click
- // int - the app::KeyboardCode of the key that was pressed.
- // int - the flags which identify the modifiers (shift, ctrl, alt)
- // associated for, as defined in chrome/views/event.h
- IPC_MESSAGE_ROUTED3(AutomationMsg_WindowKeyPress, int, int, int)
-
- // This message notifies the AutomationProvider to create a tab which is
- // hosted by an external process.
- // Request:
- // ExternalTabSettings - settings for external tab
- IPC_SYNC_MESSAGE_ROUTED1_4(AutomationMsg_CreateExternalTab,
- IPC::ExternalTabSettings /* settings*/,
- gfx::NativeWindow /* Tab container window */,
- gfx::NativeWindow /* Tab window */,
- int /* Handle to the new tab */,
- int /* Session Id of the new tab */)
-
- // This message notifies the AutomationProvider to navigate to a specified
- // url in the external tab with given handle. The first parameter is the
- // handle to the tab resource. The second parameter is the target url.
- // The third parameter is the referrer.
- // The return value contains a status code which is nonnegative on success.
- // see AutomationMsg_NavigationResponseValues for the navigation response.
- IPC_SYNC_MESSAGE_ROUTED3_1(AutomationMsg_NavigateInExternalTab,
- int,
- GURL,
- GURL,
- AutomationMsg_NavigationResponseValues)
-
- // This message is an outgoing message from Chrome to an external host.
- // It is a notification that the NavigationState was changed
- // Request:
- // -int: The flags specifying what changed
- // (see TabContents::InvalidateTypes)
- // Response:
- // None expected
- IPC_MESSAGE_ROUTED3(AutomationMsg_NavigationStateChanged,
- int, // tab handle
- int, // TabContents::InvalidateTypes
- IPC::NavigationInfo) // title, url etc.
-
- // This message is an outgoing message from Chrome to an external host.
- // It is a notification that the target URL has changed (the target URL
- // is the URL of the link that the user is hovering on)
- // Request:
- // -int: The tab handle
- // -std::wstring: The new target URL
- // Response:
- // None expected
- IPC_MESSAGE_ROUTED2(AutomationMsg_UpdateTargetUrl, int, std::wstring)
-
- // This message notifies the AutomationProvider to show the specified html
- // text in an interstitial page in the tab with given handle. The first
- // parameter is the handle to the tab resource. The second parameter is the
- // html text to be displayed.
- // The return value contains a success flag.
- IPC_SYNC_MESSAGE_ROUTED2_1(AutomationMsg_ShowInterstitialPage,
- int,
- std::string,
- AutomationMsg_NavigationResponseValues)
-
- // This message notifies the AutomationProvider to hide the current
- // interstitial page in the tab with given handle. The parameter is the
- // handle to the tab resource.
- // The return value contains a success flag.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_HideInterstitialPage, int,
- bool)
-
- // This message requests that a tab be closed.
- // Request:
- // - int: handle of the tab to close
- // - bool: if true the proxy blocks until the tab has completely closed,
- // otherwise the proxy only blocks until it initiates the close.
- IPC_SYNC_MESSAGE_ROUTED2_1(AutomationMsg_CloseTab, int, bool, bool)
-
- // This message requests that the browser be closed.
- // Request:
- // - int: handle of the browser which contains the tab
- // Response:
- // - bool: whether the operation was successfull.
- // - bool: whether the browser process will be terminated as a result (if
- // this was the last closed browser window).
- IPC_SYNC_MESSAGE_ROUTED1_2(AutomationMsg_CloseBrowser, int, bool,
- bool)
-
- IPC_MESSAGE_ROUTED1(AutomationMsg_CloseBrowserRequestAsync, int)
-
- // Unused.
- // Response:
- // None expected
- IPC_MESSAGE_ROUTED1(AutomationMsg_Unused, int)
-
-#if defined(OS_WIN)
- // TODO(port): Port these messages.
- //
- // This message is an outgoing message from Chrome to an external host.
- // It is a request to process a keyboard accelerator.
- // Request:
- // -int: Tab handle
- // -MSG: The keyboard message
- // Response:
- // None expected
- // TODO(sanjeevr): Ideally we need to add a response from the external
- // host saying whether it processed the accelerator
- IPC_MESSAGE_ROUTED2(AutomationMsg_HandleAccelerator, int, MSG)
-
- // This message is sent by the container of an externally hosted tab to
- // reflect any accelerator keys that it did not process. This gives the
- // tab a chance to handle the keys
- // Request:
- // - int: handle of the tab
- // -MSG: The keyboard message that the container did not handle
- // Response:
- // None expected
- IPC_MESSAGE_ROUTED2(AutomationMsg_ProcessUnhandledAccelerator, int, MSG)
-#endif // defined(OS_WIN)
-
- // Sent by the external tab to the host to notify that the user has tabbed
- // out of the tab.
- // Request:
- // - int: Tab handle
- // - bool: |reverse| set to true when shift-tabbing out of the tab, false
- // otherwise.
- // Response:
- // None expected
- IPC_MESSAGE_ROUTED2(AutomationMsg_TabbedOut, int, bool)
-
- // Sent by the external tab host to ask focus to be set to either the first
- // or last element on the page.
- // Request:
- // - int: handle of the tab
- // - bool: |reverse|
- // true: Focus will be set to the last focusable element
- // false: Focus will be set to the first focusable element
- // - bool: |restore_focus_to_view|
- // true: The renderer view associated with the current tab will be
- // infomed that it is receiving focus.
- // Response:
- // None expected
- IPC_MESSAGE_ROUTED3(AutomationMsg_SetInitialFocus, int, bool, bool)
-
- // This message is an outgoing message from Chrome to an external host.
- // It is a request to open a url
- // Request:
- // -int: Tab handle
- // -GURL: The URL to open
- // -GURL: The referrer
- // -int: The WindowOpenDisposition that specifies where the URL should
- // be opened (new tab, new window etc).
- // Response:
- // None expected
- IPC_MESSAGE_ROUTED4(AutomationMsg_OpenURL, int, GURL, GURL, int)
-
- // This message requests the provider to wait until the specified tab has
- // finished restoring after session restore.
- // Request:
- // - int: handle of the tab
- // Response:
- // - bool: whether the operation was successful.
- IPC_SYNC_MESSAGE_ROUTED1_0(AutomationMsg_WaitForTabToBeRestored, int)
-
- // This message is an outgoing message from Chrome to an external host.
- // It is a notification that a navigation happened
- // Request:
- // -int: Tab handle
- //
- // Response:
- // None expected
- IPC_MESSAGE_ROUTED2(AutomationMsg_DidNavigate, int, IPC::NavigationInfo)
-
- // This message requests the different security states of the page displayed
- // in the specified tab.
- // Request:
- // - int: handle of the tab
- // Response:
- // - bool: whether the operation was successful.
- // - SecurityStyle: the security style of the tab.
- // - int: the status of the server's ssl cert (0 means no errors or no ssl
- // was used).
- // - int: the insecure content state, 0 means no insecure contents.
-
- IPC_SYNC_MESSAGE_ROUTED1_4(AutomationMsg_GetSecurityState,
- int,
- bool,
- SecurityStyle,
- int,
- int)
-
- // This message requests the page type of the page displayed in the specified
- // tab (normal, error or interstitial).
- // Request:
- // - int: handle of the tab
- // Response:
- // - bool: whether the operation was successful.
- // - PageType: the type of the page currently displayed.
- IPC_SYNC_MESSAGE_ROUTED1_2(AutomationMsg_GetPageType, int, bool, PageType)
-
- // This message simulates the user action on the SSL blocking page showing in
- // the specified tab. This message is only effective if an interstitial page
- // is showing in the tab.
- // Request:
- // - int: handle of the tab
- // - bool: whether to proceed or abort the navigation
- // Response:
- // - AutomationMsg_NavigationResponseValues: result of the operation.
- IPC_SYNC_MESSAGE_ROUTED2_1(AutomationMsg_ActionOnSSLBlockingPage, int, bool,
- AutomationMsg_NavigationResponseValues)
-
- // Message to request that a browser window is brought to the front and
- // activated.
- // Request:
- // - int: handle of the browser window.
- // Response:
- // - bool: True if the browser is brought to the front.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_BringBrowserToFront, int, bool)
-
- // Message to request whether a certain item is enabled of disabled in the
- // menu in the browser window
- //
- // Request:
- // - int: handle of the browser window.
- // - int: IDC message identifier to query if enabled
- // Response:
- // - bool: True if the command is enabled on the menu
- IPC_SYNC_MESSAGE_ROUTED2_1(AutomationMsg_IsMenuCommandEnabled, int, int, bool)
-
- // This message notifies the AutomationProvider to print the tab with given
- // handle. The first parameter is the handle to the tab resource. The
- // return value contains a bool which is true on success.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_PrintNow, int, bool)
-
- // This message notifies the AutomationProvider to reload the current page in
- // the tab with given handle. The first parameter is the handle to the tab
- // resource. The return value contains a status code which is nonnegative on
- // success.
- // see AutomationMsg_NavigationResponseValues for the navigation response.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_Reload, int,
- AutomationMsg_NavigationResponseValues)
-
- // This message requests the handle (int64 app-unique identifier) of the
- // last active browser window, or the browser at index 0 if there is no last
- // active browser, or it no longer exists. Returns 0 if no browser windows
- // exist.
- IPC_SYNC_MESSAGE_ROUTED0_1(AutomationMsg_LastActiveBrowserWindow, int)
-
- // This message notifies the AutomationProvider to save the page with given
- // handle. The first parameter is the handle to the tab resource. The second
- // parameter is the main HTML file name. The third parameter is the directory
- // for saving resources. The fourth parameter is the saving type: 0 for HTML
- // only; 1 for complete web page.
- // The return value contains a bool which is true on success.
- IPC_SYNC_MESSAGE_ROUTED4_1(AutomationMsg_SavePage, int, FilePath, FilePath,
- int, bool)
-
- // This message requests the text currently being displayed in the
- // AutocompleteEdit. The parameter is the handle to the AutocompleteEdit.
- // The return value is a string indicating the text in the AutocompleteEdit.
- IPC_SYNC_MESSAGE_ROUTED1_2(AutomationMsg_AutocompleteEditGetText,
- int /* autocomplete edit handle */,
- bool /* the requested autocomplete edit exists */,
- std::wstring /* omnibox text */)
-
- // This message sets the text being displayed in the AutocompleteEdit. The
- // first parameter is the handle to the omnibox and the second parameter is
- // the text to be displayed in the AutocompleteEdit.
- // The return value has no parameters and is returned when the operation has
- // completed.
- IPC_SYNC_MESSAGE_ROUTED2_1(AutomationMsg_AutocompleteEditSetText,
- int /* autocomplete edit handle */,
- std::wstring /* text to set */,
- bool /* the requested autocomplete edit exists */)
-
- // This message requests if a query to a autocomplete provider is still in
- // progress. The first parameter in the request is the handle to the
- // autocomplete edit.
- // The first return value indicates if the request succeeded.
- // The second return value indicates if a query is still in progress.
- IPC_SYNC_MESSAGE_ROUTED1_2( \
- AutomationMsg_AutocompleteEditIsQueryInProgress,
- int /* autocomplete edit handle*/,
- bool /* the requested autocomplete edit exists */,
- bool /* indicates if a query is in progress */)
-
- // This message requests a list of the autocomplete messages currently being
- // displayed by the popup. The parameter in the request is a handle to the
- // autocomplete edit.
- // The first return value indicates if the request was successful, while
- // while the second is the actual list of matches.
- IPC_SYNC_MESSAGE_ROUTED1_2(AutomationMsg_AutocompleteEditGetMatches,
- int /* autocomplete edit handle*/,
- bool /* the requested autocomplete edit exists */,
- std::vector<AutocompleteMatchData> /* matches */)
-
- // This message requests the execution of a browser command in the browser
- // for which the handle is specified.
- // The return value contains a boolean, whether the command was dispatched.
- IPC_SYNC_MESSAGE_ROUTED2_1(AutomationMsg_WindowExecuteCommandAsync,
- int /* automation handle */,
- int /* browser command */,
- bool /* success flag */)
-
- // This message requests the execution of a browser command in the browser
- // for which the handle is specified.
- // The return value contains a boolean, whether the command was dispatched
- // and successful executed.
- IPC_SYNC_MESSAGE_ROUTED2_1(AutomationMsg_WindowExecuteCommand,
- int /* automation handle */,
- int /* browser command */,
- bool /* success flag */)
-
-
- // This message opens the Find window within a tab corresponding to the
- // supplied tab handle.
- IPC_MESSAGE_ROUTED1(AutomationMsg_OpenFindInPage,
- int /* tab_handle */)
-
- // Posts a message from external host to chrome renderer.
- IPC_MESSAGE_ROUTED4(AutomationMsg_HandleMessageFromExternalHost,
- int /* automation handle */,
- std::string /* message */,
- std::string /* origin */,
- std::string /* target */)
-
- // A message for an external host.
- IPC_MESSAGE_ROUTED4(AutomationMsg_ForwardMessageToExternalHost,
- int, /* handle */
- std::string /* message */,
- std::string /* origin */,
- std::string /* target */)
-
- // This message starts a find within a tab corresponding to the supplied
- // tab handle. The parameter |request| specifies what to search for.
- // If an error occurs, |matches_found| will be -1.
- //
- IPC_SYNC_MESSAGE_ROUTED2_2(AutomationMsg_Find,
- int /* tab_handle */,
- AutomationMsg_Find_Params /* params */,
- int /* active_ordinal */,
- int /* matches_found */)
-
- // Is the Find window fully visible (and not animating) for the specified
- // tab?
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_FindWindowVisibility,
- int /* tab_handle */,
- bool /* is_visible */)
-
- // Where is the Find window located. |x| and |y| will be -1, -1 on failure.
- IPC_SYNC_MESSAGE_ROUTED1_2(AutomationMsg_FindWindowLocation,
- int /* tab_handle */,
- int /* x */,
- int /* y */)
-
- // Is the Bookmark bar visible? The return value will indicate whether it is
- // visible or not and whether it is being animated into (or out of its place).
- IPC_SYNC_MESSAGE_ROUTED1_2(AutomationMsg_BookmarkBarVisibility,
- int /* browser_handle */,
- bool, /* is_visible */
- bool /* still_animating */)
-
- // This message requests the number of related info bars opened. It
- // returns -1 if an error occurred.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_GetInfoBarCount,
- int /* tab_handle */,
- int /* info bar count */)
-
- // This message triggers the action associated with the "accept" button in
- // the info-bar at the specified index. If |wait for navigation| is true, it
- // won't return until a navigation has occurred.
- IPC_SYNC_MESSAGE_ROUTED3_1(AutomationMsg_ClickInfoBarAccept,
- int /* tab_handle */,
- int /* info bar index */,
- bool /* wait for navigation */,
-
- /* navigation result */
- AutomationMsg_NavigationResponseValues)
-
- // This message retrieves the last time a navigation occurred in the specified
- // tab. The value is intended to be used with WaitForNavigation.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_GetLastNavigationTime,
- int /* tab_handle */,
- int64 /* last navigation time */)
-
- // This messages is used to block until a new navigation occurs (if there is
- // none more recent then the time specified).
- IPC_SYNC_MESSAGE_ROUTED2_1(AutomationMsg_WaitForNavigation,
- int /* tab_handle */,
- int64 /* last navigation time */,
-
- /* navigation result */
- AutomationMsg_NavigationResponseValues)
-
- // This messages sets an int-value preference.
- IPC_SYNC_MESSAGE_ROUTED3_1(AutomationMsg_SetIntPreference,
- int /* browser handle */,
- std::string /* pref name */,
- int /* value */,
- bool /* success */)
-
- // Queries whether an app modal dialog is currently being shown. (i.e. a
- // javascript alert) and which buttons it contains.
- IPC_SYNC_MESSAGE_ROUTED0_2(AutomationMsg_ShowingAppModalDialog,
- bool /* showing dialog */,
- int /* view::DelegateDialog::DialogButton */)
-
- // This message triggers the specified button for the currently showing
- // modal dialog.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_ClickAppModalDialogButton,
- int /* view::DelegateDialog::DialogButton */,
- bool /* success */)
-
- // This messages sets a string-value preference.
- IPC_SYNC_MESSAGE_ROUTED3_1(AutomationMsg_SetStringPreference,
- int /* browser handle */,
- std::string /* pref name */,
- std::string /* pref value */,
- bool)
-
- // This messages gets a boolean-value preference.
- IPC_SYNC_MESSAGE_ROUTED2_2(AutomationMsg_GetBooleanPreference,
- int /* browser handle */,
- std::string /* pref name */,
- bool /* success */,
- bool /* pref value */)
-
- // This messages sets a boolean-value preference.
- IPC_SYNC_MESSAGE_ROUTED3_1(AutomationMsg_SetBooleanPreference,
- int /* browser handle */,
- std::string /* pref name */,
- bool /* pref value */,
- bool /* success */)
-
- // Queries the current used encoding name of the page in the specified
- // web content tab.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_GetPageCurrentEncoding,
- int /* tab handle */,
- std::string /* current used encoding name */)
-
- // Uses the specified encoding to override the encoding of the page in the
- // specified web content tab.
- IPC_SYNC_MESSAGE_ROUTED2_1(AutomationMsg_OverrideEncoding,
- int /* tab handle */,
- std::string /* overrided encoding name */,
- bool /* success */)
-
- // Used to disable the dialog box that prompts the user for a path when
- // saving a web page.
- IPC_SYNC_MESSAGE_ROUTED1_0(AutomationMsg_SavePackageShouldPromptUser,
- bool /* false if we want to not show the dialog */)
-
- // This message is an outgoing message from Chrome to an external host.
- // It is a notification that a navigation failed
- // Request:
- // -int : Tab handle
- // -int : The status code.
- // -GURL: The URL we failed to navigate to.
- // Response:
- // None expected
- IPC_MESSAGE_ROUTED3(AutomationMsg_NavigationFailed, int, int, GURL)
-
-#if defined(OS_WIN)
- // This message is an outgoing message from an automation client to Chrome.
- // It is used to reposition a chrome tab window.
- IPC_MESSAGE_ROUTED2(AutomationMsg_TabReposition,
- int /* tab handle */,
- IPC::Reposition_Params /* SetWindowPos params */)
-#endif // defined(OS_WIN)
-
- // Gets the title of the top level browser window.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_WindowTitle,
- int /* automation handle */,
- string16 /* title text */ )
-
- // Tab load complete
- IPC_MESSAGE_ROUTED2(AutomationMsg_TabLoaded,
- int, // tab handle
- GURL)
-
- // This message requests the tabstrip index of the tab with the given handle.
- // The return value contains the index, which will be -1 on failure.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_TabIndex, int, int)
-
- // This message requests the handle (int64 app-unique identifier) of
- // a valid normal browser window, i.e. normal type and non-incognito mode.
- // On error, the returned handle value is 0.
- IPC_SYNC_MESSAGE_ROUTED0_1(AutomationMsg_FindNormalBrowserWindow, int)
-
- // This message requests the number of normal browser windows, i.e. normal
- // type and non-incognito mode that the app currently has open. The return
- // value is the number of windows.
- IPC_SYNC_MESSAGE_ROUTED0_1(AutomationMsg_NormalBrowserWindowCount, int)
-
- // Used to put the browser into "extension automation mode" for a given
- // set of Chrome Extensions API functions for the current profile, or turn
- // off automation mode. The specified tab is used as the conduit for all
- // automated API functions. It must be an external tab (as in
- // AutomationMsg_CreateExternalTab).
- IPC_MESSAGE_ROUTED2(AutomationMsg_SetEnableExtensionAutomation,
- // Tab handle.
- int,
- // Empty to disable automation, non-empty to enable
- // automation of the specified API functions, single
- // entry of "*" to enable automation of all API
- // functions.
- std::vector<std::string>)
-
- // This message tells the browser to start using the new proxy configuration
- // represented by the given JSON string. The parameters used in the JSON
- // string are defined in automation_constants.h.
- IPC_MESSAGE_ROUTED1(AutomationMsg_SetProxyConfig,
- std::string /* proxy_config_json_string */)
-
- // Sets Download Shelf visibility for the specified browser.
- IPC_SYNC_MESSAGE_ROUTED2_0(AutomationMsg_SetShelfVisibility,
- int /* browser_handle */,
- bool /* is_visible */)
-
- // This message requests the number of blocked popups in a certain tab with
- // the given handle. The return value is the number of blocked popups, or -1
- // if this request failed.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_BlockedPopupCount,
- int /* tab_handle */,
- int /* blocked_popup_count */)
-
- // This message retrieves the locale of the browser process. On success
- // |chrome_locale| will contain the locale as reported by ICU. On failure
- // |chrome_locale| is the empty string.
- IPC_SYNC_MESSAGE_ROUTED0_1(AutomationMsg_GetBrowserLocale,
- string16 /* chrome_locale */)
-
-#if defined(OS_WIN)
- IPC_MESSAGE_ROUTED4(AutomationMsg_ForwardContextMenuToExternalHost,
- int /* tab_handle */,
- HANDLE /* source menu handle */,
- int /* align flags */,
- IPC::MiniContextMenuParams /* params */)
-
- IPC_MESSAGE_ROUTED2(AutomationMsg_ForwardContextMenuCommandToChrome,
- int /* tab_handle */,
- int /* selected_command */)
+IPC_MESSAGE_ROUTED3(AutomationMsg_ForwardContextMenuToExternalHost,
+ HANDLE /* source menu handle */,
+ int /* align flags */,
+ MiniContextMenuParams /* params */)
+
+IPC_MESSAGE_CONTROL2(AutomationMsg_ForwardContextMenuCommandToChrome,
+ int /* tab_handle */,
+ int /* selected_command */)
#endif // OS_WIN
- // A URL request to be fetched via automation
- IPC_MESSAGE_ROUTED3(AutomationMsg_RequestStart,
- int /* tab_handle */,
- int /* request_id */,
- IPC::AutomationURLRequest /* request */)
-
- // Read data from a URL request to be fetched via automation
- IPC_MESSAGE_ROUTED3(AutomationMsg_RequestRead,
- int /* tab_handle */,
- int /* request_id */,
- int /* bytes_to_read */)
-
- // Response to a AutomationMsg_RequestStart message
- IPC_MESSAGE_ROUTED3(AutomationMsg_RequestStarted,
- int /* tab_handle */,
- int /* request_id */,
- IPC::AutomationURLResponse /* response */)
-
- // Data read via automation
- IPC_MESSAGE_ROUTED3(AutomationMsg_RequestData,
- int /* tab_handle */,
- int /* request_id */,
- std::string /* data */)
-
- IPC_MESSAGE_ROUTED3(AutomationMsg_RequestEnd,
- int /* tab_handle */,
- int /* request_id */,
- URLRequestStatus /* status */)
-
- IPC_MESSAGE_ROUTED1(AutomationMsg_PrintAsync,
- int /* tab_handle */)
-
- IPC_MESSAGE_ROUTED3(AutomationMsg_SetCookieAsync,
- int /* tab_handle */,
- GURL /* url */,
- std::string /* cookie */)
-
- IPC_MESSAGE_ROUTED1(AutomationMsg_SelectAll,
- int /* tab handle */)
-
- IPC_MESSAGE_ROUTED1(AutomationMsg_Cut,
- int /* tab handle */)
-
- IPC_MESSAGE_ROUTED1(AutomationMsg_Copy,
- int /* tab handle */)
-
- IPC_MESSAGE_ROUTED1(AutomationMsg_Paste,
- int /* tab handle */)
-
- IPC_MESSAGE_ROUTED1(AutomationMsg_ReloadAsync,
- int /* tab handle */)
-
- IPC_MESSAGE_ROUTED1(AutomationMsg_StopAsync,
- int /* tab handle */)
-
- // Returns the number of times a filter was used to service an URL request.
- // See AutomationMsg_SetFilteredInet.
- IPC_SYNC_MESSAGE_ROUTED0_1(AutomationMsg_GetFilteredInetHitCount,
- int /* hit_count */)
-
- // Is the browser in fullscreen mode?
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_IsFullscreen,
- int /* browser_handle */,
- bool /* is_fullscreen */)
-
- // Is the fullscreen bubble visible?
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_IsFullscreenBubbleVisible,
- int /* browser_handle */,
- bool /* is_visible */)
-
-#if defined(OS_POSIX)
- // See previous definition of this message for explanation of why it is
- // defined twice.
- IPC_MESSAGE_ROUTED3(AutomationMsg_WindowClick, int, gfx::Point, int)
-#endif
-
- // This message notifies the AutomationProvider to navigate to a specified
- // url in the tab with given handle. The first parameter is the handle to
- // the tab resource. The second parameter is the target url. The third
- // parameter is the number of navigations that are required for a successful
- // return value. See AutomationMsg_NavigationResponseValues for the return
- // value.
- IPC_SYNC_MESSAGE_ROUTED3_1(
- AutomationMsg_NavigateToURLBlockUntilNavigationsComplete, int, GURL, int,
- AutomationMsg_NavigationResponseValues)
-
- // This message notifies the AutomationProvider to navigate to a specified
- // navigation entry index in the external tab with given handle. The first
- // parameter is the handle to the tab resource. The second parameter is the
- // index of navigation entry.
- // The return value contains a status code which is nonnegative on success.
- // see AutomationMsg_NavigationResponseValues for the navigation response.
- IPC_SYNC_MESSAGE_ROUTED2_1(AutomationMsg_NavigateExternalTabAtIndex, int, int,
- AutomationMsg_NavigationResponseValues)
-
- // This message requests the provider to wait until the window count
- // reached the specified value.
- // Request:
- // - int: target browser window count
- // Response:
- // - bool: whether the operation was successful.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_WaitForBrowserWindowCountToBecome,
- int, bool)
-
- // This message requests the provider to wait until an application modal
- // dialog is shown.
- // Response:
- // - bool: whether the operation was successful
- IPC_SYNC_MESSAGE_ROUTED0_1(AutomationMsg_WaitForAppModalDialogToBeShown, bool)
-
- // This message notifies the AutomationProvider to navigate back in session
- // history in the tab with given handle. The first parameter is the handle
- // to the tab resource. The second parameter is the number of navigations the
- // provider will wait for.
- // See AutomationMsg_NavigationResponseValues for the navigation response
- // values.
- IPC_SYNC_MESSAGE_ROUTED2_1(AutomationMsg_GoBackBlockUntilNavigationsComplete,
- int, int,
- AutomationMsg_NavigationResponseValues)
-
- // This message notifies the AutomationProvider to navigate forward in session
- // history in the tab with given handle. The first parameter is the handle
- // to the tab resource. The second parameter is the number of navigations
- // the provider will wait for.
- // See AutomationMsg_NavigationResponseValues for the navigation response
- // values.
- IPC_SYNC_MESSAGE_ROUTED2_1(
- AutomationMsg_GoForwardBlockUntilNavigationsComplete, int, int,
- AutomationMsg_NavigationResponseValues)
-
- // This message is used by automation clients to upload histogram data to the
- // browser process.
- IPC_MESSAGE_ROUTED1(AutomationMsg_RecordHistograms,
- std::vector<std::string> /* histogram_list */)
-
- IPC_MESSAGE_ROUTED2(AutomationMsg_AttachExternalTab,
- int /* 'source' tab_handle */,
- IPC::AttachExternalTabParams)
-
- // Sent when the automation client connects to an existing tab.
- IPC_SYNC_MESSAGE_ROUTED3_4(AutomationMsg_ConnectExternalTab,
- uint64 /* cookie */,
- bool /* allow/block tab*/,
- gfx::NativeWindow /* parent window */,
- gfx::NativeWindow /* Tab container window */,
- gfx::NativeWindow /* Tab window */,
- int /* Handle to the new tab */,
- int /* Session Id of the new tab */)
-
-#if defined(OS_POSIX)
- // TODO(estade): this should be merged with the windows message of the same
- // name. See comment for WindowClick.
- IPC_SYNC_MESSAGE_ROUTED4_1(AutomationMsg_WindowDrag,
- int, std::vector<gfx::Point>, int, bool, bool)
-#endif // defined(OS_POSIX)
-
- // This message gets the bounds of the window.
- // Request:
- // int - the handle of the window to query
- // Response:
- // gfx::Rect - the bounds of the window
- // bool - true if the query was successful
- IPC_SYNC_MESSAGE_ROUTED1_2(AutomationMsg_GetWindowBounds, int, gfx::Rect,
- bool)
-
- // Simulate an end of session. Normally this happens when the user
- // shuts down the machine or logs off.
- // Request:
- // int - the handle of the browser
- // Response:
- // bool - true if succesful
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_TerminateSession, int, bool)
-
- // Returns whether the window is maximized.
- // Request:
- // int - the handle of the window
- // Response:
- // bool - true if the window is maximized
- // bool - true if query is successful
- IPC_SYNC_MESSAGE_ROUTED1_2(AutomationMsg_IsWindowMaximized, int, bool, bool)
-
- IPC_MESSAGE_ROUTED2(AutomationMsg_SetPageFontSize,
- int /* tab_handle */,
- int /* The font size */)
-
- // Returns a metric event duration that was last recorded. Returns -1 if the
- // event hasn't occurred yet.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_GetMetricEventDuration,
- std::string /* event_name */,
- int /* duration ms */)
-
- // Sent by automation provider - go to history entry via automation.
- IPC_MESSAGE_ROUTED2(AutomationMsg_RequestGoToHistoryEntryOffset,
- int, // tab handle
- int) // numbers of entries (negative or positive)
-
- // Silently install the extension in the given crx file.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_InstallExtension,
- FilePath /* full path to crx file */,
- AutomationMsg_ExtensionResponseValues)
-
- // Silently load the extension in the given directory. This expects an
- // extension expanded into the directory, not a crx file.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_LoadExpandedExtension,
- FilePath /* root directory of extension */,
- AutomationMsg_ExtensionResponseValues)
-
- // Retrieves a list of the root directories of all enabled extensions
- // that have been installed into Chrome by dropping a .crx file onto
- // Chrome or an equivalent action (including loaded extensions).
- // Other types of extensions are not included on the list (e.g. "component",
- // "app" or "external" extensions) since since CEEE does not yet support them
- // (and it actually only support a single extension in its profile for now).
- IPC_SYNC_MESSAGE_ROUTED0_1(AutomationMsg_GetEnabledExtensions,
- std::vector<FilePath>)
-
- // This message requests the type of the window with the given handle. The
- // return value contains the type (Browser::Type), or -1 if the request
- // failed.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_Type, int, int)
-
- // Opens a new browser window of a specific type.
- IPC_SYNC_MESSAGE_ROUTED2_0(AutomationMsg_OpenNewBrowserWindowOfType,
- int /* Type (Browser::Type) */,
- bool /* show */ )
-
- // This message requests that the mouse be moved to this location, in
- // window coordinate space.
- // Request:
- // int - the handle of the window that's the context for this click
- // gfx::Point - the location to move to
- IPC_MESSAGE_ROUTED2(AutomationMsg_WindowMouseMove, int, gfx::Point)
-
- // Called when requests should be downloaded using a host browser's
- // download mechanism when chrome is being embedded.
- IPC_MESSAGE_ROUTED2(AutomationMsg_DownloadRequestInHost,
- int /* tab_handle */,
- int /* request_id */)
-
- // Shuts down the session service for the browser identified by
- // |browser_handle|. On success |result| is set to true.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_ShutdownSessionService,
- int /* browser_handle */,
- bool /* result */)
-
- IPC_MESSAGE_ROUTED1(AutomationMsg_SaveAsAsync,
- int /* tab handle */)
+// A URL request to be fetched via automation
+IPC_MESSAGE_ROUTED2(AutomationMsg_RequestStart,
+ int /* request_id */,
+ AutomationURLRequest /* request */)
+
+// Read data from a URL request to be fetched via automation
+IPC_MESSAGE_ROUTED2(AutomationMsg_RequestRead,
+ int /* request_id */,
+ int /* bytes_to_read */)
+
+// Response to a AutomationMsg_RequestStart message
+IPC_MESSAGE_ROUTED2(AutomationMsg_RequestStarted,
+ int /* request_id */,
+ AutomationURLResponse /* response */)
+
+// Data read via automation
+IPC_MESSAGE_ROUTED2(AutomationMsg_RequestData,
+ int /* request_id */,
+ std::string /* data */)
+
+IPC_MESSAGE_ROUTED2(AutomationMsg_RequestEnd,
+ int /* request_id */,
+ URLRequestStatus /* status */)
+
+IPC_MESSAGE_CONTROL1(AutomationMsg_PrintAsync,
+ int /* tab_handle */)
+
+IPC_MESSAGE_ROUTED2(AutomationMsg_SetCookieAsync,
+ GURL /* url */,
+ std::string /* cookie */)
+
+IPC_MESSAGE_CONTROL1(AutomationMsg_SelectAll,
+ int /* tab handle */)
+
+IPC_MESSAGE_CONTROL1(AutomationMsg_Cut,
+ int /* tab handle */)
+
+IPC_MESSAGE_CONTROL1(AutomationMsg_Copy,
+ int /* tab handle */)
+
+IPC_MESSAGE_CONTROL1(AutomationMsg_Paste,
+ int /* tab handle */)
+
+IPC_MESSAGE_CONTROL1(AutomationMsg_ReloadAsync,
+ int /* tab handle */)
+
+IPC_MESSAGE_CONTROL1(AutomationMsg_StopAsync,
+ int /* tab handle */)
+
+// Returns the number of times a filter was used to service an URL request.
+// See AutomationMsg_SetFilteredInet.
+IPC_SYNC_MESSAGE_CONTROL0_1(AutomationMsg_GetFilteredInetHitCount,
+ int /* hit_count */)
+
+// Is the browser in fullscreen mode?
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_IsFullscreen,
+ int /* browser_handle */,
+ bool /* is_fullscreen */)
+
+// Is the fullscreen bubble visible?
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_IsFullscreenBubbleVisible,
+ int /* browser_handle */,
+ bool /* is_visible */)
+
+// This message notifies the AutomationProvider to navigate to a specified
+// url in the tab with given handle. The first parameter is the handle to
+// the tab resource. The second parameter is the target url. The third
+// parameter is the number of navigations that are required for a successful
+// return value. See AutomationMsg_NavigationResponseValues for the return
+// value.
+IPC_SYNC_MESSAGE_CONTROL3_1(
+ AutomationMsg_NavigateToURLBlockUntilNavigationsComplete,
+ int,
+ GURL,
+ int,
+ AutomationMsg_NavigationResponseValues)
+
+// This message notifies the AutomationProvider to navigate to a specified
+// navigation entry index in the external tab with given handle. The first
+// parameter is the handle to the tab resource. The second parameter is the
+// index of navigation entry.
+// The return value contains a status code which is nonnegative on success.
+// see AutomationMsg_NavigationResponseValues for the navigation response.
+IPC_SYNC_MESSAGE_CONTROL2_1(AutomationMsg_NavigateExternalTabAtIndex,
+ int,
+ int,
+ AutomationMsg_NavigationResponseValues)
+
+// This message requests the provider to wait until the window count
+// reached the specified value.
+// Request:
+// - int: target browser window count
+// Response:
+// - bool: whether the operation was successful.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_WaitForBrowserWindowCountToBecome,
+ int,
+ bool)
+
+// This message requests the provider to wait until an application modal
+// dialog is shown.
+// Response:
+// - bool: whether the operation was successful
+IPC_SYNC_MESSAGE_CONTROL0_1(AutomationMsg_WaitForAppModalDialogToBeShown,
+ bool)
+
+// This message notifies the AutomationProvider to navigate back in session
+// history in the tab with given handle. The first parameter is the handle
+// to the tab resource. The second parameter is the number of navigations the
+// provider will wait for.
+// See AutomationMsg_NavigationResponseValues for the navigation response
+// values.
+IPC_SYNC_MESSAGE_CONTROL2_1(AutomationMsg_GoBackBlockUntilNavigationsComplete,
+ int,
+ int,
+ AutomationMsg_NavigationResponseValues)
+
+// This message notifies the AutomationProvider to navigate forward in session
+// history in the tab with given handle. The first parameter is the handle
+// to the tab resource. The second parameter is the number of navigations
+// the provider will wait for.
+// See AutomationMsg_NavigationResponseValues for the navigation response
+// values.
+IPC_SYNC_MESSAGE_CONTROL2_1(
+ AutomationMsg_GoForwardBlockUntilNavigationsComplete,
+ int,
+ int,
+ AutomationMsg_NavigationResponseValues)
+
+// This message is used by automation clients to upload histogram data to the
+// browser process.
+IPC_MESSAGE_CONTROL1(AutomationMsg_RecordHistograms,
+ std::vector<std::string> /* histogram_list */)
+
+IPC_MESSAGE_ROUTED1(AutomationMsg_AttachExternalTab,
+ AttachExternalTabParams)
+
+// Sent when the automation client connects to an existing tab.
+IPC_SYNC_MESSAGE_CONTROL3_4(AutomationMsg_ConnectExternalTab,
+ uint64 /* cookie */,
+ bool /* allow/block tab*/,
+ gfx::NativeWindow /* parent window */,
+ gfx::NativeWindow /* Tab container window */,
+ gfx::NativeWindow /* Tab window */,
+ int /* Handle to the new tab */,
+ int /* Session Id of the new tab */)
+
+// This message gets the bounds of the window.
+// Request:
+// int - the handle of the window to query
+// Response:
+// gfx::Rect - the bounds of the window
+// bool - true if the query was successful
+IPC_SYNC_MESSAGE_CONTROL1_2(AutomationMsg_GetWindowBounds,
+ int,
+ gfx::Rect,
+ bool)
+
+// Simulate an end of session. Normally this happens when the user
+// shuts down the machine or logs off.
+// Request:
+// int - the handle of the browser
+// Response:
+// bool - true if succesful
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_TerminateSession,
+ int,
+ bool)
+
+// Returns whether the window is maximized.
+// Request:
+// int - the handle of the window
+// Response:
+// bool - true if the window is maximized
+// bool - true if query is successful
+IPC_SYNC_MESSAGE_CONTROL1_2(AutomationMsg_IsWindowMaximized,
+ int,
+ bool,
+ bool)
+
+IPC_MESSAGE_CONTROL2(AutomationMsg_SetPageFontSize,
+ int /* tab_handle */,
+ int /* The font size */)
+
+// Returns a metric event duration that was last recorded. Returns -1 if the
+// event hasn't occurred yet.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_GetMetricEventDuration,
+ std::string /* event_name */,
+ int /* duration ms */)
+
+// Sent by automation provider - go to history entry via automation.
+IPC_MESSAGE_ROUTED1(AutomationMsg_RequestGoToHistoryEntryOffset,
+ int) // numbers of entries (negative or positive)
+
+// Silently install the extension in the given crx file.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_InstallExtension,
+ FilePath /* full path to crx file */,
+ AutomationMsg_ExtensionResponseValues)
+
+// Silently load the extension in the given directory. This expects an
+// extension expanded into the directory, not a crx file.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_LoadExpandedExtension,
+ FilePath /* root directory of extension */,
+ AutomationMsg_ExtensionResponseValues)
+
+// Retrieves a list of the root directories of all enabled extensions
+// that have been installed into Chrome by dropping a .crx file onto
+// Chrome or an equivalent action (including loaded extensions).
+// Other types of extensions are not included on the list (e.g. "component",
+// "app" or "external" extensions) since since CEEE does not yet support them
+// (and it actually only support a single extension in its profile for now).
+IPC_SYNC_MESSAGE_CONTROL0_1(AutomationMsg_GetEnabledExtensions,
+ std::vector<FilePath>)
+
+// This message requests the type of the window with the given handle. The
+// return value contains the type (Browser::Type), or -1 if the request
+// failed.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_Type,
+ int,
+ int)
+
+// Opens a new browser window of a specific type.
+IPC_SYNC_MESSAGE_CONTROL2_0(AutomationMsg_OpenNewBrowserWindowOfType,
+ int /* Type (Browser::Type) */,
+ bool /* show */ )
+
+// This message requests that the mouse be moved to this location, in
+// window coordinate space.
+// Request:
+// int - the handle of the window that's the context for this click
+// gfx::Point - the location to move to
+IPC_MESSAGE_CONTROL2(AutomationMsg_WindowMouseMove,
+ int,
+ gfx::Point)
+
+// Called when requests should be downloaded using a host browser's
+// download mechanism when chrome is being embedded.
+IPC_MESSAGE_ROUTED1(AutomationMsg_DownloadRequestInHost,
+ int /* request_id */)
+
+// Shuts down the session service for the browser identified by
+// |browser_handle|. On success |result| is set to true.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_ShutdownSessionService,
+ int /* browser_handle */,
+ bool /* result */)
+
+IPC_MESSAGE_CONTROL1(AutomationMsg_SaveAsAsync,
+ int /* tab handle */)
#if defined(OS_WIN)
- // An incoming message from an automation host to Chrome. Signals that
- // the browser containing |tab_handle| has moved.
- IPC_MESSAGE_ROUTED1(AutomationMsg_BrowserMove,
- int /* tab handle */)
+// An incoming message from an automation host to Chrome. Signals that
+// the browser containing |tab_handle| has moved.
+IPC_MESSAGE_CONTROL1(AutomationMsg_BrowserMove,
+ int /* tab handle */)
#endif
- // Used to get cookies for the given URL.
- IPC_MESSAGE_ROUTED3(AutomationMsg_GetCookiesFromHost,
- int /* tab_handle */,
- GURL /* url */,
- int /* opaque_cookie_id */)
-
- IPC_MESSAGE_ROUTED5(AutomationMsg_GetCookiesHostResponse,
- int /* tab_handle */,
- bool /* success */,
- GURL /* url */,
- std::string /* cookies */,
- int /* opaque_cookie_id */)
-
- // If the given host is empty, then the default content settings are
- // modified.
- IPC_SYNC_MESSAGE_ROUTED4_1(AutomationMsg_SetContentSetting,
- int /* browser handle */,
- std::string /* host */,
- ContentSettingsType /* content type */,
- ContentSetting /* setting */,
- bool /* success */)
+// Used to get cookies for the given URL.
+IPC_MESSAGE_ROUTED2(AutomationMsg_GetCookiesFromHost,
+ GURL /* url */,
+ int /* opaque_cookie_id */)
+
+IPC_MESSAGE_CONTROL5(AutomationMsg_GetCookiesHostResponse,
+ int /* tab_handle */,
+ bool /* success */,
+ GURL /* url */,
+ std::string /* cookies */,
+ int /* opaque_cookie_id */)
+
+// If the given host is empty, then the default content settings are
+// modified.
+IPC_SYNC_MESSAGE_CONTROL4_1(AutomationMsg_SetContentSetting,
+ int /* browser handle */,
+ std::string /* host */,
+ ContentSettingsType /* content type */,
+ ContentSetting /* setting */,
+ bool /* success */)
#if defined(OS_CHROMEOS)
- // Logs in through the browser's login wizard if available.
- IPC_SYNC_MESSAGE_ROUTED2_1(AutomationMsg_LoginWithUserAndPass,
- std::string /* username*/,
- std::string /* password*/,
- bool /* Whether successful*/)
+// Logs in through the browser's login wizard if available.
+IPC_SYNC_MESSAGE_CONTROL2_1(AutomationMsg_LoginWithUserAndPass,
+ std::string /* username*/,
+ std::string /* password*/,
+ bool /* Whether successful*/)
#endif
- // Return the bookmarks encoded as a JSON string.
- IPC_SYNC_MESSAGE_ROUTED1_2(AutomationMsg_GetBookmarksAsJSON,
- int /* browser_handle */,
- std::string /* bookmarks as a JSON string */,
- bool /* success */)
-
- // Wait for the bookmark model to load.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_WaitForBookmarkModelToLoad,
- int /* browser_handle */,
- bool /* success */)
-
- // Bookmark addition, modification, and removal.
- // Bookmarks are indexed by their id.
- IPC_SYNC_MESSAGE_ROUTED4_1(AutomationMsg_AddBookmarkGroup,
- int /* browser_handle */,
- int64 /* parent_id */,
- int /* index */,
- std::wstring /* title */,
- bool /* success */)
- IPC_SYNC_MESSAGE_ROUTED5_1(AutomationMsg_AddBookmarkURL,
- int /* browser_handle */,
- int64 /* parent_id */,
- int /* index */,
- std::wstring /* title */,
- GURL /* url */,
- bool /* success */)
- IPC_SYNC_MESSAGE_ROUTED4_1(AutomationMsg_ReparentBookmark,
- int /* browser_handle */,
- int64 /* id */,
- int64 /* new_parent_id */,
- int /* index */,
- bool /* success */)
- IPC_SYNC_MESSAGE_ROUTED3_1(AutomationMsg_SetBookmarkTitle,
- int /* browser_handle */,
- int64 /* id */,
- std::wstring /* title */,
- bool /* success */)
- IPC_SYNC_MESSAGE_ROUTED3_1(AutomationMsg_SetBookmarkURL,
- int /* browser_handle */,
- int64 /* id */,
- GURL /* url */,
- bool /* success */)
- IPC_SYNC_MESSAGE_ROUTED2_1(AutomationMsg_RemoveBookmark,
- int /* browser_handle */,
- int64 /* id */,
- bool /* success */)
-
- // This message informs the browser process to remove the history entries
- // for the specified types across all time ranges. See
- // browsing_data_remover.h for a list of REMOVE_* types supported in the
- // remove_mask parameter.
- IPC_MESSAGE_ROUTED1(AutomationMsg_RemoveBrowsingData, int)
-
- // Block until the focused view id changes to something other than
- // |previous_view_id|.
- IPC_SYNC_MESSAGE_ROUTED2_2(AutomationMsg_WaitForFocusedViewIDToChange,
- int /* window handle */,
- int /* previous_view_id */,
- bool /* success */,
- int /* new_view_id */)
-
- // To avoid race conditions, waiting until a popup menu opens is a
- // three-step process:
- // 1. Call StartTrackingPopupMenus.
- // 2. Call an automation method that results in opening the popup menu.
- // 3. Call WaitForPopupMenuToOpen and check for success.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_StartTrackingPopupMenus,
- int /* browser handle */,
- bool /* success */)
- IPC_SYNC_MESSAGE_ROUTED0_1(AutomationMsg_WaitForPopupMenuToOpen,
- bool /* success */)
-
- // Generic pyauto pattern to help avoid future addition of
- // automation messages.
- IPC_SYNC_MESSAGE_ROUTED2_2(AutomationMsg_SendJSONRequest,
- int /* browser_handle */,
- std::string /* JSON request */,
- std::string /* JSON response */,
- bool /* success */)
-
- // Installs an extension from the crx file and returns its id.
- // On error, |extension handle| will be 0.
- IPC_SYNC_MESSAGE_ROUTED2_1(AutomationMsg_InstallExtensionAndGetHandle,
- FilePath /* full path to crx file */,
- bool /* with UI */,
- int /* extension handle */)
-
- // Waits for the next extension test result. Sets |test result| as the
- // received result and |message| as any accompanying message with the
- // result, which could be the empty string.
- IPC_SYNC_MESSAGE_ROUTED0_2(AutomationMsg_WaitForExtensionTestResult,
- bool /* test result */,
- std::string /* message */)
-
- // Uninstalls an extension. On success |success| is true.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_UninstallExtension,
- int /* extension handle */,
- bool /* success */)
-
- // Enables an extension. On success |success| is true.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_EnableExtension,
- int /* extension handle */,
- bool /* success */)
-
- // Disables an extension. On success |success| is true.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_DisableExtension,
- int /* extension handle */,
- bool /* success */)
-
- // Executes the action associated with the given extension. This executes
- // the extension's page or browser action in the given browser, but does
- // not open popups. On success |success| is true.
- IPC_SYNC_MESSAGE_ROUTED2_1(
- AutomationMsg_ExecuteExtensionActionInActiveTabAsync,
- int /* extension handle */,
- int /* browser handle */,
- bool /* success */)
-
- // Moves the browser action to the given index in the browser action toolbar.
- // On success |success| is true.
- IPC_SYNC_MESSAGE_ROUTED2_1(AutomationMsg_MoveExtensionBrowserAction,
- int /* extension handle */,
- int /* index */,
- bool /* success */)
-
- // Gets an extension property |property type|. On success |success| is true,
- // and |property value| is set.
- IPC_SYNC_MESSAGE_ROUTED2_2(AutomationMsg_GetExtensionProperty,
- int /* extension handle */,
- AutomationMsg_ExtensionProperty /* property type */,
- bool /* success */,
- std::string /* property value */)
-
- // Resets to the default theme.
- IPC_SYNC_MESSAGE_ROUTED0_0(AutomationMsg_ResetToDefaultTheme)
-
- // Navigates asynchronously to a URL with a certain disposition,
- // like in a new tab.
- IPC_SYNC_MESSAGE_ROUTED3_1(AutomationMsg_NavigationAsyncWithDisposition,
- int /* tab handle */,
- GURL,
- WindowOpenDisposition,
- bool /* result */)
-
-
- // This message requests the cookie be deleted for given url in the
- // profile of the tab identified by the first parameter. The second
- // parameter is the cookie name.
- IPC_SYNC_MESSAGE_ROUTED3_1(AutomationMsg_DeleteCookie, GURL, std::string,
- int /* tab handle */,
- bool /* result */)
-
- // This message triggers the collected cookies dialog for a specific tab.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_ShowCollectedCookiesDialog,
- int /* tab handle */,
- bool /* result */)
-
- // This message requests the external tab identified by the tab handle
- // passed in be closed.
- // Request:
- // -int: Tab handle
- // Response:
- // None expected
- IPC_MESSAGE_ROUTED1(AutomationMsg_CloseExternalTab, int)
-
- // This message requests that the external tab identified by the tab handle
- // runs unload handlers if any on the current page.
- // Request:
- // -int: Tab handle
- // -bool: result: true->unload, false->don't unload
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_RunUnloadHandlers, int, bool)
-
- // This message sets the current zoom level on the tab
- // Request:
- // -int: Tab handle
- // -int: Zoom level. Values ZOOM_OUT = -1, RESET = 0, ZOOM_IN = 1
- // Response:
- // None expected
- IPC_MESSAGE_ROUTED2(AutomationMsg_SetZoomLevel, int, int)
-
- // Waits for tab count to reach target value.
- IPC_SYNC_MESSAGE_ROUTED2_1(AutomationMsg_WaitForTabCountToBecome,
- int /* browser handle */,
- int /* target tab count */,
- bool /* success */)
-
- // Waits for the infobar count to reach given number.
- IPC_SYNC_MESSAGE_ROUTED2_1(AutomationMsg_WaitForInfoBarCount,
- int /* tab handle */,
- int /* target count */,
- bool /* success */)
-
- // Waits for the autocomplete edit to receive focus.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_WaitForAutocompleteEditFocus,
- int /* autocomplete edit handle */,
- bool /* success */)
-
- // Loads all blocked plug-ins on the page.
- IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_LoadBlockedPlugins,
- int /* tab handle */,
- bool /* success */)
-
- // Captures the entire page for the tab, including those portions not in
- // view, and saves the image as a PNG in the given file location.
- // Request:
- // -int: Tab handle
- // -FilePath: Path to save the captured image to
- // Response:
- // -bool: Whether the method succeeded
- IPC_SYNC_MESSAGE_ROUTED2_1(AutomationMsg_CaptureEntirePageAsPNG, int,
- FilePath, bool)
-
-IPC_END_MESSAGES(Automation)
+// Return the bookmarks encoded as a JSON string.
+IPC_SYNC_MESSAGE_CONTROL1_2(AutomationMsg_GetBookmarksAsJSON,
+ int /* browser_handle */,
+ std::string /* bookmarks as a JSON string */,
+ bool /* success */)
+
+// Wait for the bookmark model to load.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_WaitForBookmarkModelToLoad,
+ int /* browser_handle */,
+ bool /* success */)
+
+// Bookmark addition, modification, and removal.
+// Bookmarks are indexed by their id.
+IPC_SYNC_MESSAGE_CONTROL4_1(AutomationMsg_AddBookmarkGroup,
+ int /* browser_handle */,
+ int64 /* parent_id */,
+ int /* index */,
+ std::wstring /* title */,
+ bool /* success */)
+IPC_SYNC_MESSAGE_CONTROL5_1(AutomationMsg_AddBookmarkURL,
+ int /* browser_handle */,
+ int64 /* parent_id */,
+ int /* index */,
+ std::wstring /* title */,
+ GURL /* url */,
+ bool /* success */)
+IPC_SYNC_MESSAGE_CONTROL4_1(AutomationMsg_ReparentBookmark,
+ int /* browser_handle */,
+ int64 /* id */,
+ int64 /* new_parent_id */,
+ int /* index */,
+ bool /* success */)
+IPC_SYNC_MESSAGE_CONTROL3_1(AutomationMsg_SetBookmarkTitle,
+ int /* browser_handle */,
+ int64 /* id */,
+ std::wstring /* title */,
+ bool /* success */)
+IPC_SYNC_MESSAGE_CONTROL3_1(AutomationMsg_SetBookmarkURL,
+ int /* browser_handle */,
+ int64 /* id */,
+ GURL /* url */,
+ bool /* success */)
+IPC_SYNC_MESSAGE_CONTROL2_1(AutomationMsg_RemoveBookmark,
+ int /* browser_handle */,
+ int64 /* id */,
+ bool /* success */)
+
+// This message informs the browser process to remove the history entries
+// for the specified types across all time ranges. See
+// browsing_data_remover.h for a list of REMOVE_* types supported in the
+// remove_mask parameter.
+IPC_MESSAGE_CONTROL1(AutomationMsg_RemoveBrowsingData,
+ int)
+
+// Block until the focused view id changes to something other than
+// |previous_view_id|.
+IPC_SYNC_MESSAGE_CONTROL2_2(AutomationMsg_WaitForFocusedViewIDToChange,
+ int /* window handle */,
+ int /* previous_view_id */,
+ bool /* success */,
+ int /* new_view_id */)
+
+// To avoid race conditions, waiting until a popup menu opens is a
+// three-step process:
+// 1. Call StartTrackingPopupMenus.
+// 2. Call an automation method that results in opening the popup menu.
+// 3. Call WaitForPopupMenuToOpen and check for success.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_StartTrackingPopupMenus,
+ int /* browser handle */,
+ bool /* success */)
+IPC_SYNC_MESSAGE_CONTROL0_1(AutomationMsg_WaitForPopupMenuToOpen,
+ bool /* success */)
+
+// Generic pyauto pattern to help avoid future addition of
+// automation messages.
+IPC_SYNC_MESSAGE_CONTROL2_2(AutomationMsg_SendJSONRequest,
+ int /* browser_handle */,
+ std::string /* JSON request */,
+ std::string /* JSON response */,
+ bool /* success */)
+
+// Installs an extension from the crx file and returns its id.
+// On error, |extension handle| will be 0.
+IPC_SYNC_MESSAGE_CONTROL2_1(AutomationMsg_InstallExtensionAndGetHandle,
+ FilePath /* full path to crx file */,
+ bool /* with UI */,
+ int /* extension handle */)
+
+// Waits for the next extension test result. Sets |test result| as the
+// received result and |message| as any accompanying message with the
+// result, which could be the empty string.
+IPC_SYNC_MESSAGE_CONTROL0_2(AutomationMsg_WaitForExtensionTestResult,
+ bool /* test result */,
+ std::string /* message */)
+
+// Uninstalls an extension. On success |success| is true.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_UninstallExtension,
+ int /* extension handle */,
+ bool /* success */)
+
+// Enables an extension. On success |success| is true.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_EnableExtension,
+ int /* extension handle */,
+ bool /* success */)
+
+// Disables an extension. On success |success| is true.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_DisableExtension,
+ int /* extension handle */,
+ bool /* success */)
+
+// Executes the action associated with the given extension. This executes
+// the extension's page or browser action in the given browser, but does
+// not open popups. On success |success| is true.
+IPC_SYNC_MESSAGE_CONTROL2_1(
+ AutomationMsg_ExecuteExtensionActionInActiveTabAsync,
+ int /* extension handle */,
+ int /* browser handle */,
+ bool /* success */)
+
+// Moves the browser action to the given index in the browser action toolbar.
+// On success |success| is true.
+IPC_SYNC_MESSAGE_CONTROL2_1(AutomationMsg_MoveExtensionBrowserAction,
+ int /* extension handle */,
+ int /* index */,
+ bool /* success */)
+
+// Gets an extension property |property type|. On success |success| is true,
+// and |property value| is set.
+IPC_SYNC_MESSAGE_CONTROL2_2(AutomationMsg_GetExtensionProperty,
+ int /* extension handle */,
+ AutomationMsg_ExtensionProperty /* property type */,
+ bool /* success */,
+ std::string /* property value */)
+
+// Resets to the default theme.
+IPC_SYNC_MESSAGE_CONTROL0_0(AutomationMsg_ResetToDefaultTheme)
+
+// Navigates asynchronously to a URL with a certain disposition,
+// like in a new tab.
+IPC_SYNC_MESSAGE_CONTROL3_1(AutomationMsg_NavigationAsyncWithDisposition,
+ int /* tab handle */,
+ GURL,
+ WindowOpenDisposition,
+ bool /* result */)
+
+
+// This message requests the cookie be deleted for given url in the
+// profile of the tab identified by the first parameter. The second
+// parameter is the cookie name.
+IPC_SYNC_MESSAGE_CONTROL3_1(AutomationMsg_DeleteCookie,
+ GURL,
+ std::string,
+ int /* tab handle */,
+ bool /* result */)
+
+// This message triggers the collected cookies dialog for a specific tab.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_ShowCollectedCookiesDialog,
+ int /* tab handle */,
+ bool /* result */)
+
+// This message requests the external tab identified by the tab handle
+// passed in be closed.
+// Request:
+// Response:
+// None expected
+IPC_MESSAGE_ROUTED0(AutomationMsg_CloseExternalTab)
+
+// This message requests that the external tab identified by the tab handle
+// runs unload handlers if any on the current page.
+// Request:
+// -int: Tab handle
+// -bool: result: true->unload, false->don't unload
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_RunUnloadHandlers,
+ int,
+ bool)
+
+// This message sets the current zoom level on the tab
+// Request:
+// -int: Tab handle
+// -int: Zoom level. Values ZOOM_OUT = -1, RESET = 0, ZOOM_IN = 1
+// Response:
+// None expected
+IPC_MESSAGE_CONTROL2(AutomationMsg_SetZoomLevel,
+ int,
+ int)
+
+// Waits for tab count to reach target value.
+IPC_SYNC_MESSAGE_CONTROL2_1(AutomationMsg_WaitForTabCountToBecome,
+ int /* browser handle */,
+ int /* target tab count */,
+ bool /* success */)
+
+// Waits for the infobar count to reach given number.
+IPC_SYNC_MESSAGE_CONTROL2_1(AutomationMsg_WaitForInfoBarCount,
+ int /* tab handle */,
+ int /* target count */,
+ bool /* success */)
+
+// Waits for the autocomplete edit to receive focus.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_WaitForAutocompleteEditFocus,
+ int /* autocomplete edit handle */,
+ bool /* success */)
+
+// Loads all blocked plug-ins on the page.
+IPC_SYNC_MESSAGE_CONTROL1_1(AutomationMsg_LoadBlockedPlugins,
+ int /* tab handle */,
+ bool /* success */)
+
+// Captures the entire page for the tab, including those portions not in
+// view, and saves the image as a PNG in the given file location.
+// Request:
+// -int: Tab handle
+// -FilePath: Path to save the captured image to
+// Response:
+// -bool: Whether the method succeeded
+IPC_SYNC_MESSAGE_CONTROL2_1(AutomationMsg_CaptureEntirePageAsPNG,
+ int,
+ FilePath,
+ bool)
diff --git a/chrome/common/child_process.cc b/chrome/common/child_process.cc
index dd6fd40..af05a65 100644
--- a/chrome/common/child_process.cc
+++ b/chrome/common/child_process.cc
@@ -97,10 +97,10 @@ void ChildProcess::WaitForDebugger(const std::wstring& label) {
// TODO(playmobil): In the long term, overriding this flag doesn't seem
// right, either use our own flag or open a dialog we can use.
// This is just to ease debugging in the interim.
- LOG(WARNING) << label
- << " ("
- << getpid()
- << ") paused waiting for debugger to attach @ pid";
+ LOG(ERROR) << label
+ << " ("
+ << getpid()
+ << ") paused waiting for debugger to attach @ pid";
// Install a signal handler so that pause can be woken.
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
diff --git a/chrome/common/child_process_host.cc b/chrome/common/child_process_host.cc
index b001eff..e03b3a6 100644
--- a/chrome/common/child_process_host.cc
+++ b/chrome/common/child_process_host.cc
@@ -13,7 +13,6 @@
#include "chrome/common/chrome_switches.h"
#include "chrome/common/plugin_messages.h"
#include "ipc/ipc_logging.h"
-#include "ipc/ipc_message.h"
#if defined(OS_LINUX)
#include "base/linux_util.h"
@@ -25,6 +24,17 @@ ChildProcessHost::ChildProcessHost()
}
ChildProcessHost::~ChildProcessHost() {
+ for (size_t i = 0; i < filters_.size(); ++i) {
+ filters_[i]->OnChannelClosing();
+ filters_[i]->OnFilterRemoved();
+ }
+}
+
+void ChildProcessHost::AddFilter(IPC::ChannelProxy::MessageFilter* filter) {
+ filters_.push_back(filter);
+
+ if (channel_.get())
+ filter->OnFilterAdded(channel_.get());
}
// static
@@ -109,13 +119,16 @@ bool ChildProcessHost::CreateChannel() {
if (!channel_->Connect())
return false;
+ for (size_t i = 0; i < filters_.size(); ++i)
+ filters_[i]->OnFilterAdded(channel_.get());
+
// Make sure these messages get sent first.
#if defined(IPC_MESSAGE_LOG_ENABLED)
- bool enabled = IPC::Logging::current()->Enabled();
- SendOnChannel(new PluginProcessMsg_SetIPCLoggingEnabled(enabled));
+ bool enabled = IPC::Logging::GetInstance()->Enabled();
+ Send(new PluginProcessMsg_SetIPCLoggingEnabled(enabled));
#endif
- SendOnChannel(new PluginProcessMsg_AskBeforeShutdown());
+ Send(new PluginProcessMsg_AskBeforeShutdown());
opening_channel_ = true;
@@ -126,54 +139,57 @@ void ChildProcessHost::InstanceCreated() {
Notify(NotificationType::CHILD_INSTANCE_CREATED);
}
-bool ChildProcessHost::SendOnChannel(IPC::Message* msg) {
+bool ChildProcessHost::Send(IPC::Message* message) {
if (!channel_.get()) {
- delete msg;
+ delete message;
return false;
}
- return channel_->Send(msg);
+ return channel_->Send(message);
}
void ChildProcessHost::OnChildDied() {
delete this;
}
-bool ChildProcessHost::InterceptMessageFromChild(const IPC::Message& msg) {
- return false;
-}
-
ChildProcessHost::ListenerHook::ListenerHook(ChildProcessHost* host)
: host_(host) {
}
-void ChildProcessHost::ListenerHook::OnMessageReceived(
+bool ChildProcessHost::ListenerHook::OnMessageReceived(
const IPC::Message& msg) {
#ifdef IPC_MESSAGE_LOG_ENABLED
- IPC::Logging* logger = IPC::Logging::current();
+ IPC::Logging* logger = IPC::Logging::GetInstance();
if (msg.type() == IPC_LOGGING_ID) {
logger->OnReceivedLoggingMessage(msg);
- return;
+ return true;
}
if (logger->Enabled())
logger->OnPreDispatchMessage(msg);
#endif
- bool handled = host_->InterceptMessageFromChild(msg);
-
- if (!handled) {
- if (msg.type() == PluginProcessHostMsg_ShutdownRequest::ID) {
- if (host_->CanShutdown())
- host_->SendOnChannel(new PluginProcessMsg_Shutdown());
- } else {
- host_->OnMessageReceived(msg);
+ bool handled = false;
+ for (size_t i = 0; i < host_->filters_.size(); ++i) {
+ if (host_->filters_[i]->OnMessageReceived(msg)) {
+ handled = true;
+ break;
}
}
+ if (!handled && msg.type() == PluginProcessHostMsg_ShutdownRequest::ID) {
+ if (host_->CanShutdown())
+ host_->Send(new PluginProcessMsg_Shutdown());
+ handled = true;
+ }
+
+ if (!handled)
+ handled = host_->OnMessageReceived(msg);
+
#ifdef IPC_MESSAGE_LOG_ENABLED
if (logger->Enabled())
logger->OnPostDispatchMessage(msg, host_->channel_id_);
#endif
+ return handled;
}
void ChildProcessHost::ListenerHook::OnChannelConnected(int32 peer_pid) {
@@ -181,16 +197,22 @@ void ChildProcessHost::ListenerHook::OnChannelConnected(int32 peer_pid) {
host_->OnChannelConnected(peer_pid);
// Notify in the main loop of the connection.
host_->Notify(NotificationType::CHILD_PROCESS_HOST_CONNECTED);
+
+ for (size_t i = 0; i < host_->filters_.size(); ++i)
+ host_->filters_[i]->OnChannelConnected(peer_pid);
}
void ChildProcessHost::ListenerHook::OnChannelError() {
host_->opening_channel_ = false;
host_->OnChannelError();
+ for (size_t i = 0; i < host_->filters_.size(); ++i)
+ host_->filters_[i]->OnChannelError();
+
// This will delete host_, which will also destroy this!
host_->OnChildDied();
}
void ChildProcessHost::ForceShutdown() {
- SendOnChannel(new PluginProcessMsg_Shutdown());
+ Send(new PluginProcessMsg_Shutdown());
}
diff --git a/chrome/common/child_process_host.h b/chrome/common/child_process_host.h
index 72438e8..c822346 100644
--- a/chrome/common/child_process_host.h
+++ b/chrome/common/child_process_host.h
@@ -7,6 +7,7 @@
#pragma once
#include <string>
+#include <vector>
#include "build/build_config.h"
@@ -17,7 +18,7 @@
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
#include "chrome/common/notification_type.h"
-#include "ipc/ipc_channel.h"
+#include "ipc/ipc_channel_proxy.h"
class CommandLine;
class FilePath;
@@ -29,8 +30,8 @@ class Message;
// Provides common functionality for hosting a child process and processing IPC
// messages between the host and the child process. Subclasses are responsible
// for the actual launching and terminating of the child processes.
-//
-class ChildProcessHost : public IPC::Channel::Listener {
+class ChildProcessHost : public IPC::Channel::Listener,
+ public IPC::Message::Sender {
public:
virtual ~ChildProcessHost();
@@ -56,16 +57,14 @@ class ChildProcessHost : public IPC::Channel::Listener {
static void PreCacheFont(LOGFONT font);
#endif // defined(OS_WIN)
+ // IPC::Message::Sender implementation.
+ bool Send(IPC::Message* message);
+
protected:
ChildProcessHost();
- // A helper method to send an IPC message to the child on the channel.
- // It behavies just like IPC::Message::Sender::Send. The implementor takes
- // ownership of the given Message regardless of whether or not this method
- // succeeds. This class does not implement IPC::Message::Sender to prevent
- // conflicts with subclasses which indirectly could inherit from
- // IPC::Message::Sender.
- bool SendOnChannel(IPC::Message* msg);
+ // Adds an IPC message filter. A reference will be kept to the filter.
+ void AddFilter(IPC::ChannelProxy::MessageFilter* filter);
// Derived classes return true if it's ok to shut down the child process.
virtual bool CanShutdown() = 0;
@@ -81,7 +80,7 @@ class ChildProcessHost : public IPC::Channel::Listener {
virtual void InstanceCreated();
// IPC::Channel::Listener implementation:
- virtual void OnMessageReceived(const IPC::Message& msg) { }
+ virtual bool OnMessageReceived(const IPC::Message& msg) { return false; }
virtual void OnChannelConnected(int32 peer_pid) { }
virtual void OnChannelError() { }
@@ -91,9 +90,8 @@ class ChildProcessHost : public IPC::Channel::Listener {
// Called when the child process goes away.
virtual void OnChildDied();
- // Allows the derived implementation to intercept a message before it is
- // handed to the IPC::Channel::Listener::OnMessageReceived implementation.
- virtual bool InterceptMessageFromChild(const IPC::Message& msg);
+ // Notifies the derived class that we told the child process to kill itself.
+ virtual void ShutdownStarted() { }
// Subclasses can implement specific notification methods.
virtual void Notify(NotificationType type) { }
@@ -104,7 +102,7 @@ class ChildProcessHost : public IPC::Channel::Listener {
class ListenerHook : public IPC::Channel::Listener {
public:
explicit ListenerHook(ChildProcessHost* host);
- virtual void OnMessageReceived(const IPC::Message& msg);
+ virtual bool OnMessageReceived(const IPC::Message& msg);
virtual void OnChannelConnected(int32 peer_pid);
virtual void OnChannelError();
private:
@@ -117,6 +115,11 @@ class ChildProcessHost : public IPC::Channel::Listener {
scoped_ptr<IPC::Channel> channel_;
std::string channel_id_;
+ // Holds all the IPC message filters. Since this object lives on the IO
+ // thread, we don't have a IPC::ChannelProxy and so we manage filters
+ // manually.
+ std::vector<scoped_refptr<IPC::ChannelProxy::MessageFilter> > filters_;
+
DISALLOW_COPY_AND_ASSIGN(ChildProcessHost);
};
diff --git a/chrome/common/child_thread.cc b/chrome/common/child_thread.cc
index 8e6fbce..53823bc 100644
--- a/chrome/common/child_thread.cc
+++ b/chrome/common/child_thread.cc
@@ -43,11 +43,11 @@ void ChildThread::Init() {
}
channel_.reset(new IPC::SyncChannel(channel_name_,
- IPC::Channel::MODE_CLIENT, this, NULL,
+ IPC::Channel::MODE_CLIENT, this,
ChildProcess::current()->io_message_loop(), true,
ChildProcess::current()->GetShutDownEvent()));
#ifdef IPC_MESSAGE_LOG_ENABLED
- IPC::Logging::current()->SetIPCSender(this);
+ IPC::Logging::GetInstance()->SetIPCSender(this);
#endif
resource_dispatcher_.reset(new ResourceDispatcher(this));
@@ -66,11 +66,16 @@ void ChildThread::Init() {
ChildThread::~ChildThread() {
#ifdef IPC_MESSAGE_LOG_ENABLED
- IPC::Logging::current()->SetIPCSender(NULL);
+ IPC::Logging::GetInstance()->SetIPCSender(NULL);
#endif
channel_->RemoveFilter(sync_message_filter_.get());
+ // Close this channel before resetting the message loop attached to it so
+ // the message loop can call ChannelProxy::Context::OnChannelClosed(), which
+ // releases the reference count to this channel.
+ channel_->Close();
+
// The ChannelProxy object caches a pointer to the IPC thread, so need to
// reset it as it's not guaranteed to outlive this object.
// NOTE: this also has the side-effect of not closing the main IPC channel to
@@ -134,14 +139,14 @@ MessageLoop* ChildThread::message_loop() {
return message_loop_;
}
-void ChildThread::OnMessageReceived(const IPC::Message& msg) {
+bool ChildThread::OnMessageReceived(const IPC::Message& msg) {
// Resource responses are sent to the resource dispatcher.
if (resource_dispatcher_->OnMessageReceived(msg))
- return;
+ return true;
if (socket_stream_dispatcher_->OnMessageReceived(msg))
- return;
+ return true;
if (file_system_dispatcher_->OnMessageReceived(msg))
- return;
+ return true;
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(ChildThread, msg)
@@ -155,13 +160,12 @@ void ChildThread::OnMessageReceived(const IPC::Message& msg) {
IPC_END_MESSAGE_MAP()
if (handled)
- return;
+ return true;
- if (msg.routing_id() == MSG_ROUTING_CONTROL) {
- OnControlMessageReceived(msg);
- } else {
- router_.OnMessageReceived(msg);
- }
+ if (msg.routing_id() == MSG_ROUTING_CONTROL)
+ return OnControlMessageReceived(msg);
+
+ return router_.OnMessageReceived(msg);
}
void ChildThread::OnAskBeforeShutdown() {
@@ -175,9 +179,9 @@ void ChildThread::OnShutdown() {
#if defined(IPC_MESSAGE_LOG_ENABLED)
void ChildThread::OnSetIPCLoggingEnabled(bool enable) {
if (enable)
- IPC::Logging::current()->Enable();
+ IPC::Logging::GetInstance()->Enable();
else
- IPC::Logging::current()->Disable();
+ IPC::Logging::GetInstance()->Disable();
}
#endif // IPC_MESSAGE_LOG_ENABLED
diff --git a/chrome/common/child_thread.h b/chrome/common/child_thread.h
index 337a7f8..dbe8677 100644
--- a/chrome/common/child_thread.h
+++ b/chrome/common/child_thread.h
@@ -74,7 +74,9 @@ class ChildThread : public IPC::Channel::Listener,
// Called when the process refcount is 0.
void OnProcessFinalRelease();
- virtual void OnControlMessageReceived(const IPC::Message& msg) { }
+ virtual bool OnControlMessageReceived(const IPC::Message& msg) {
+ return false;
+ }
virtual void OnAskBeforeShutdown();
virtual void OnShutdown();
@@ -92,7 +94,7 @@ class ChildThread : public IPC::Channel::Listener,
void Init();
// IPC::Channel::Listener implementation:
- virtual void OnMessageReceived(const IPC::Message& msg);
+ virtual bool OnMessageReceived(const IPC::Message& msg);
virtual void OnChannelError();
std::string channel_name_;
diff --git a/chrome/common/chrome_application_mac.h b/chrome/common/chrome_application_mac.h
new file mode 100644
index 0000000..2ea557c
--- /dev/null
+++ b/chrome/common/chrome_application_mac.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2009 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 CHROME_COMMON_CHROME_APPLICATION_MAC_H_
+#define CHROME_COMMON_CHROME_APPLICATION_MAC_H_
+#pragma once
+
+#if defined(__OBJC__)
+
+#import <AppKit/AppKit.h>
+
+#include "base/basictypes.h"
+#include "base/message_pump_mac.h"
+#include "base/scoped_nsobject.h"
+
+// Event hooks must implement this protocol.
+@protocol CrApplicationEventHookProtocol
+- (void)hookForEvent:(NSEvent*)theEvent;
+@end
+
+
+@interface CrApplication : NSApplication<CrAppProtocol> {
+ @private
+ BOOL handlingSendEvent_;
+ // Array of objects implementing the CrApplicationEventHookProtocol
+ scoped_nsobject<NSMutableArray> eventHooks_;
+}
+- (BOOL)isHandlingSendEvent;
+
+// Add or remove an event hook to be called for every sendEvent:
+// that the application receives. These handlers are called before
+// the normal [NSApplication sendEvent:] call is made.
+
+// This is not a good alternative to a nested event loop. It should
+// be used only when normal event logic and notification breaks down
+// (e.g. when clicking outside a canBecomeKey:NO window to "switch
+// context" out of it).
+- (void)addEventHook:(id<CrApplicationEventHookProtocol>)hook;
+- (void)removeEventHook:(id<CrApplicationEventHookProtocol>)hook;
+
++ (NSApplication*)sharedApplication;
+@end
+
+namespace chrome_application_mac {
+
+// Controls the state of |handlingSendEvent_| in the event loop so that it is
+// reset properly.
+class ScopedSendingEvent {
+ public:
+ ScopedSendingEvent();
+ ~ScopedSendingEvent();
+
+ private:
+ CrApplication* app_;
+ BOOL handling_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedSendingEvent);
+};
+
+} // namespace chrome_application_mac
+
+#endif // defined(__OBJC__)
+
+namespace chrome_application_mac {
+
+// To be used to instantiate CrApplication from C++ code.
+void RegisterCrApp();
+
+} // namespace chrome_application_mac
+
+#endif // CHROME_COMMON_CHROME_APPLICATION_MAC_H_
diff --git a/chrome/common/chrome_application_mac.mm b/chrome/common/chrome_application_mac.mm
new file mode 100644
index 0000000..3c1b013
--- /dev/null
+++ b/chrome/common/chrome_application_mac.mm
@@ -0,0 +1,76 @@
+// Copyright (c) 2009 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 "chrome/common/chrome_application_mac.h"
+
+#include "base/logging.h"
+
+@interface CrApplication ()
+- (void)setHandlingSendEvent:(BOOL)handlingSendEvent;
+@end
+
+@implementation CrApplication
+// Initialize NSApplication using the custom subclass. Check whether NSApp
+// was already initialized using another class, because that would break
+// some things.
++ (NSApplication*)sharedApplication {
+ NSApplication* app = [super sharedApplication];
+ if (![NSApp isKindOfClass:self]) {
+ LOG(ERROR) << "NSApp should be of type " << [[self className] UTF8String]
+ << ", not " << [[NSApp className] UTF8String];
+ DCHECK(false) << "NSApp is of wrong type";
+ }
+ return app;
+}
+
+- (id)init {
+ if ((self = [super init])) {
+ eventHooks_.reset([[NSMutableArray alloc] init]);
+ }
+ return self;
+}
+
+- (BOOL)isHandlingSendEvent {
+ return handlingSendEvent_;
+}
+
+- (void)setHandlingSendEvent:(BOOL)handlingSendEvent {
+ handlingSendEvent_ = handlingSendEvent;
+}
+
+- (void)sendEvent:(NSEvent*)event {
+ chrome_application_mac::ScopedSendingEvent sendingEventScoper;
+ for (id<CrApplicationEventHookProtocol> handler in eventHooks_.get()) {
+ [handler hookForEvent:event];
+ }
+ [super sendEvent:event];
+}
+
+- (void)addEventHook:(id<CrApplicationEventHookProtocol>)handler {
+ [eventHooks_ addObject:handler];
+}
+
+- (void)removeEventHook:(id<CrApplicationEventHookProtocol>)handler {
+ [eventHooks_ removeObject:handler];
+}
+
+@end
+
+namespace chrome_application_mac {
+
+ScopedSendingEvent::ScopedSendingEvent()
+ : app_(static_cast<CrApplication*>([CrApplication sharedApplication])),
+ handling_([app_ isHandlingSendEvent]) {
+ [app_ setHandlingSendEvent:YES];
+}
+
+ScopedSendingEvent::~ScopedSendingEvent() {
+ [app_ setHandlingSendEvent:handling_];
+}
+
+void RegisterCrApp() {
+ [CrApplication sharedApplication];
+}
+
+} // namespace chrome_application_mac
diff --git a/chrome/common/chrome_constants.cc b/chrome/common/chrome_constants.cc
index e6a3246..97bb58e 100644
--- a/chrome/common/chrome_constants.cc
+++ b/chrome/common/chrome_constants.cc
@@ -11,10 +11,8 @@
#if defined(OS_MACOSX)
#if defined(GOOGLE_CHROME_BUILD)
#define PRODUCT_STRING "Google Chrome"
-#define PRODUCT_STRING_W L"Google Chrome"
#elif defined(CHROMIUM_BUILD)
#define PRODUCT_STRING "Chromium"
-#define PRODUCT_STRING_W L"Chromium"
#else
#error Unknown branding
#endif
@@ -22,29 +20,32 @@
namespace chrome {
+const char kChromeVersionEnvVar[] = "CHROME_VERSION";
+
// The following should not be used for UI strings; they are meant
// for system strings only. UI changes should be made in the GRD.
#if defined(OS_WIN)
-const wchar_t kBrowserProcessExecutableName[] = L"chrome.exe";
-const wchar_t kHelperProcessExecutableName[] = L"chrome.exe";
+const FilePath::CharType kBrowserProcessExecutableName[] = FPL("chrome.exe");
+const FilePath::CharType kHelperProcessExecutableName[] = FPL("chrome.exe");
#elif defined(OS_LINUX)
-const wchar_t kBrowserProcessExecutableName[] = L"chrome";
+const FilePath::CharType kBrowserProcessExecutableName[] = FPL("chrome");
// Helper processes end up with a name of "exe" due to execing via
// /proc/self/exe. See bug 22703.
-const wchar_t kHelperProcessExecutableName[] = L"exe";
+const FilePath::CharType kHelperProcessExecutableName[] = FPL("exe");
#elif defined(OS_MACOSX)
-const wchar_t kBrowserProcessExecutableName[] = PRODUCT_STRING_W;
-const wchar_t kHelperProcessExecutableName[] = PRODUCT_STRING_W L" Helper";
+const FilePath::CharType kBrowserProcessExecutableName[] = FPL(PRODUCT_STRING);
+const FilePath::CharType kHelperProcessExecutableName[] =
+ FPL(PRODUCT_STRING " Helper");
#endif // OS_*
#if defined(OS_WIN)
-const wchar_t kBrowserProcessExecutablePath[] = L"chrome.exe";
+const FilePath::CharType kBrowserProcessExecutablePath[] = FPL("chrome.exe");
const FilePath::CharType kHelperProcessExecutablePath[] = FPL("chrome.exe");
#elif defined(OS_LINUX)
-const wchar_t kBrowserProcessExecutablePath[] = L"chrome";
+const FilePath::CharType kBrowserProcessExecutablePath[] = FPL("chrome");
const FilePath::CharType kHelperProcessExecutablePath[] = FPL("chrome");
#elif defined(OS_MACOSX)
-const wchar_t kBrowserProcessExecutablePath[] =
- PRODUCT_STRING_W L".app/Contents/MacOS/" PRODUCT_STRING_W;
+const FilePath::CharType kBrowserProcessExecutablePath[] =
+ FPL(PRODUCT_STRING ".app/Contents/MacOS/" PRODUCT_STRING);
const FilePath::CharType kHelperProcessExecutablePath[] =
FPL(PRODUCT_STRING " Helper.app/Contents/MacOS/" PRODUCT_STRING " Helper");
#endif // OS_*
@@ -89,7 +90,9 @@ const FilePath::CharType kFaviconsFilename[] = FPL("Favicons");
const FilePath::CharType kHistoryFilename[] = FPL("History");
const FilePath::CharType kLocalStateFilename[] = FPL("Local State");
const FilePath::CharType kPreferencesFilename[] = FPL("Preferences");
-const FilePath::CharType kSafeBrowsingFilename[] = FPL("Safe Browsing Bloom");
+const FilePath::CharType kSafeBrowsingBaseFilename[] = FPL("Safe Browsing");
+const FilePath::CharType kSafeBrowsingPhishingModelFilename[] =
+ FPL("Safe Browsing Phishing Model");
const FilePath::CharType kSingletonCookieFilename[] = FPL("SingletonCookie");
const FilePath::CharType kSingletonSocketFilename[] = FPL("SingletonSocket");
const FilePath::CharType kSingletonLockFilename[] = FPL("SingletonLock");
diff --git a/chrome/common/chrome_constants.h b/chrome/common/chrome_constants.h
index bc4d4bf..56be2f8 100644
--- a/chrome/common/chrome_constants.h
+++ b/chrome/common/chrome_constants.h
@@ -14,9 +14,11 @@ namespace chrome {
extern const char kChromeVersion[];
-extern const wchar_t kBrowserProcessExecutableName[];
-extern const wchar_t kHelperProcessExecutableName[];
-extern const wchar_t kBrowserProcessExecutablePath[];
+extern const char kChromeVersionEnvVar[];
+
+extern const FilePath::CharType kBrowserProcessExecutableName[];
+extern const FilePath::CharType kHelperProcessExecutableName[];
+extern const FilePath::CharType kBrowserProcessExecutablePath[];
extern const FilePath::CharType kHelperProcessExecutablePath[];
#if defined(OS_MACOSX)
extern const FilePath::CharType kFrameworkName[];
@@ -50,7 +52,8 @@ extern const FilePath::CharType kFaviconsFilename[];
extern const FilePath::CharType kHistoryFilename[];
extern const FilePath::CharType kLocalStateFilename[];
extern const FilePath::CharType kPreferencesFilename[];
-extern const FilePath::CharType kSafeBrowsingFilename[];
+extern const FilePath::CharType kSafeBrowsingBaseFilename[];
+extern const FilePath::CharType kSafeBrowsingPhishingModelFilename[];
extern const FilePath::CharType kSingletonCookieFilename[];
extern const FilePath::CharType kSingletonSocketFilename[];
extern const FilePath::CharType kSingletonLockFilename[];
diff --git a/chrome/common/chrome_paths.cc b/chrome/common/chrome_paths.cc
index 181cf0a..1b8e612 100644
--- a/chrome/common/chrome_paths.cc
+++ b/chrome/common/chrome_paths.cc
@@ -239,6 +239,18 @@ bool PathProvider(int key, FilePath* result) {
cur = cur.Append(FILE_PATH_LITERAL("libpdf.so"));
#endif
break;
+ case chrome::FILE_NACL_PLUGIN:
+ if (!GetInternalPluginsDirectory(&cur))
+ return false;
+#if defined(OS_WIN)
+ cur = cur.Append(FILE_PATH_LITERAL("ppGoogleNaClPluginChrome.dll"));
+#elif defined(OS_MACOSX)
+ // TODO(noelallen) Please verify this extention name is correct.
+ cur = cur.Append(FILE_PATH_LITERAL("ppGoogleNaClPluginChrome.plugin"));
+#else // Linux and Chrome OS
+ cur = cur.Append(FILE_PATH_LITERAL("libppGoogleNaClPluginChrome.so"));
+#endif
+ break;
case chrome::FILE_RESOURCES_PACK:
#if defined(OS_MACOSX)
if (mac_util::AmIBundled()) {
diff --git a/chrome/common/chrome_paths.h b/chrome/common/chrome_paths.h
index 63037c6..21867bd 100644
--- a/chrome/common/chrome_paths.h
+++ b/chrome/common/chrome_paths.h
@@ -57,6 +57,7 @@ enum {
FILE_GEARS_PLUGIN, // Full path to the gears.dll plugin file.
FILE_FLASH_PLUGIN, // Full path to the internal Flash plugin file.
FILE_PDF_PLUGIN, // Full path to the internal PDF plugin file.
+ FILE_NACL_PLUGIN, // Full path to the internal NaCl plugin file.
FILE_LIBAVCODEC, // Full path to libavcodec media decoding
// library.
FILE_LIBAVFORMAT, // Full path to libavformat media parsing
diff --git a/chrome/common/chrome_paths_win.cc b/chrome/common/chrome_paths_win.cc
index 74a730d..8207db6 100644
--- a/chrome/common/chrome_paths_win.cc
+++ b/chrome/common/chrome_paths_win.cc
@@ -15,6 +15,7 @@
#include "base/path_service.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/installer/util/browser_distribution.h"
+#include "chrome/installer/util/master_preferences.h"
namespace chrome {
@@ -30,10 +31,10 @@ bool GetDefaultUserDataDirectory(FilePath* result) {
bool GetChromeFrameUserDataDirectory(FilePath* result) {
if (!PathService::Get(base::DIR_LOCAL_APP_DATA, result))
return false;
-#if defined(GOOGLE_CHROME_BUILD)
- *result = result->Append(FILE_PATH_LITERAL("Google"));
-#endif
- *result = result->Append(L"Chrome Frame");
+ BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_FRAME,
+ installer::MasterPreferences::ForCurrentProcess());
+ *result = result->Append(dist->GetInstallSubDir());
*result = result->Append(chrome::kUserDataDirname);
return true;
}
diff --git a/chrome/common/chrome_plugin_lib.cc b/chrome/common/chrome_plugin_lib.cc
index 3277f4a..1bd118b 100644
--- a/chrome/common/chrome_plugin_lib.cc
+++ b/chrome/common/chrome_plugin_lib.cc
@@ -19,7 +19,7 @@
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/chrome_paths.h"
-#include "webkit/glue/plugins/plugin_list.h"
+#include "webkit/plugins/npapi/plugin_list.h"
using base::TimeDelta;
@@ -114,7 +114,7 @@ void ChromePluginLib::RegisterPluginsWithNPAPI() {
FilePath path;
// Register Gears, if available.
if (PathService::Get(chrome::FILE_GEARS_PLUGIN, &path))
- NPAPI::PluginList::Singleton()->AddExtraPluginPath(path);
+ webkit::npapi::PluginList::Singleton()->AddExtraPluginPath(path);
}
static void LogPluginLoadTime(const TimeDelta &time) {
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 1d91c88..df8e12c 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -26,6 +26,9 @@ const char kAllowFileAccessFromFiles[] = "allow-file-access-from-files";
// directories. This switch re-enables file:// for testing.
const char kAllowFileAccess[] = "allow-file-access";
+// Don't block outdated plugins.
+const char kAllowOutdatedPlugins[] = "allow-outdated-plugins";
+
// Disable checking of the renegotiation extension and any future checks over
// and above what a "traditional" SSL stack might do. This has been requested
// in order to support some web development tools that intercept SSL
@@ -59,6 +62,7 @@ const char kAppsGalleryReturnTokens[] = "apps-gallery-return-tokens";
// The URL to use for the gallery link in the app launcher.
const char kAppsGalleryURL[] = "apps-gallery-url";
+// The update url used by gallery/webstore extensions.
const char kAppsGalleryUpdateURL[] = "apps-gallery-update-url";
// Disable throbber for extension apps.
@@ -83,9 +87,6 @@ const char kAuthServerWhitelist[] = "auth-server-whitelist";
// automation-related messages on IPC channel with the given ID.
const char kAutomationClientChannelID[] = "automation-channel";
-// Block non-sandboxed plugins.
-const char kBlockNonSandboxedPlugins[] = "block-nonsandboxed-plugins";
-
// Causes the browser process to throw an assertion on startup.
const char kBrowserAssertTest[] = "assert-test";
@@ -203,6 +204,12 @@ const char kDisableDevTools[] = "disable-dev-tools";
// Disables device orientation events.
const char kDisableDeviceOrientation[] = "disable-device-orientation";
+// By default, if the URL request throttler finds that a server is overloaded or
+// encounters an error, it rejects requests to the server for a period of time,
+// which is determined by an exponential back-off algorithm. This switch
+// disables such behavior.
+const char kDisableEnforcedThrottling[] = "disable-enforced-throttling";
+
// Disable experimental WebGL support.
const char kDisableExperimentalWebGL[] = "disable-webgl";
@@ -217,6 +224,9 @@ const char kDisableExtensionsFileAccessCheck[] =
// Disable FileSystem API.
const char kDisableFileSystem[] = "disable-file-system";
+// Disables the sandbox for the built-in flash player.
+const char kDisableFlashSandbox[] = "disable-flash-sandbox";
+
// Suppresses support for the Geolocation javascript API.
const char kDisableGeolocation[] = "disable-geolocation";
@@ -238,6 +248,9 @@ const char kDisableHistoryQuickProvider[] = "disable-history-quick-provider";
// Disable the use of the HistoryURLProvider for autocomplete results.
const char kDisableHistoryURLProvider[] = "disable-history-url-provider";
+// Disable the Indexed Database API.
+const char kDisableIndexedDatabase[] = "disable-indexed-database";
+
// Disable the internal Flash Player.
const char kDisableInternalFlash[] = "disable-internal-flash";
@@ -267,9 +280,6 @@ const char kDisableLogging[] = "disable-logging";
// notification.
const char kDisableNewTabFirstRun[] = "disable-new-tab-first-run";
-// Prevent outdated plugins from running.
-const char kDisableOutdatedPlugins[] = "disable-outdated-plugins";
-
// Prevent plugins from running.
const char kDisablePlugins[] = "disable-plugins";
@@ -317,6 +327,9 @@ const char kDisableSyncApps[] = "disable-sync-apps";
// Disable syncing of autofill.
const char kDisableSyncAutofill[] = "disable-sync-autofill";
+// Disable syncing of autofill Profile.
+const char kDisableSyncAutofillProfile[] = "disable-sync-autofill-profile";
+
// Disable syncing of bookmarks.
const char kDisableSyncBookmarks[] = "disable-sync-bookmarks";
@@ -412,7 +425,10 @@ const char kEnableBenchmarking[] = "enable-benchmarking";
// blocked pop-ups only.
const char kEnableBlockContentAnimation[] = "enable-blocked-content-animation";
-// Enable experimental client-side detection of phishing pages.
+// In the browser process this switch is used to enable or disable the
+// client-side phishing detection. In the renderer this switch is only enabled
+// if this switch is enabled in the browser and the user has opted in to UMA
+// stats and SafeBrowsing is enabled in the preferences.
const char kEnableClientSidePhishingDetection[] =
"enable-client-side-phishing-detection";
@@ -469,19 +485,12 @@ const char kEnableFastback[] = "enable-fastback";
// testing, for example page cycler and layout tests. See bug 1157243.
const char kEnableFileCookies[] = "enable-file-cookies";
-// Enables the sandbox for the built-in flash player.
-const char kEnableFlashSandbox[] = "enable-flash-sandbox";
-
-
// Enable IPv6 support, even if probes suggest that it may not be fully
// supported. Some probes may require internet connections, and this flag will
// allow support independent of application testing.
// This flag overrides "disable-ipv6" which appears elswhere in this file.
const char kEnableIPv6[] = "enable-ipv6";
-// Enable the Indexed Database API.
-const char kEnableIndexedDatabase[] = "enable-indexed-database";
-
// Enable the GPU plugin and Pepper 3D rendering.
const char kEnableGPUPlugin[] = "enable-gpu-plugin";
@@ -507,9 +516,13 @@ const char kEnableNaClDebug[] = "enable-nacl-debug";
// Enable Native Web Worker support.
const char kEnableNativeWebWorkers[] = "enable-native-web-workers";
-// Is the predictive varition of instant enabled?
+// Is InstantController::PREDICTIVE_TYPE enabled?
const char kEnablePredictiveInstant[] = "enable-predictive-instant";
+// Is InstantController::PREDICTIVE_NO_AUTO_COMPLETE_TYPE enabled?
+const char kEnablePredictiveNoAutoCompleteInstant[] =
+ "enable-predictive-no-auto-complete-instant";
+
// This applies only when the process type is "service". Enables the
// Chromoting Host Process within the service process.
const char kEnableRemoting[] = "enable-remoting";
@@ -706,9 +719,9 @@ const char kHomePage[] = "homepage";
// "MAP * baz, EXCLUDE www.google.com" --> Remaps everything to "baz",
// except for "www.google.com".
//
-// These mappings apply to the endpoint host in a URLRequest (the TCP connect
-// and host resolver in a direct connection, and the CONNECT in an http proxy
-// connection, and the endpoint host in a SOCKS proxy connection).
+// These mappings apply to the endpoint host in a net::URLRequest (the TCP
+// connect and host resolver in a direct connection, and the CONNECT in an http
+// proxy connection, and the endpoint host in a SOCKS proxy connection).
const char kHostRules[] = "host-rules";
// The maximum number of concurrent host resolve requests (i.e. DNS) to allow.
@@ -828,6 +841,9 @@ const char kNoExperiments[] = "no-experiments";
// you're for some reason tempted to pass them both.
const char kNoFirstRun[] = "no-first-run";
+// Don't Sandbox the GPU process, does not affect other sandboxed processes.
+const char kNoGpuSandbox[] = "no-gpu-sandbox";
+
// Support a separate switch that enables the v8 playback extension.
// The extension causes javascript calls to Date.now() and Math.random()
// to return consistent values, such that subsequent loads of the same
@@ -845,7 +861,7 @@ const char kNoProxyServer[] = "no-proxy-server";
// Don't send HTTP-Referer headers.
const char kNoReferrers[] = "no-referrers";
-// Runs the renderer outside the sandbox.
+// Disables the sandbox for all process types that are normally sandboxed.
const char kNoSandbox[] = "no-sandbox";
// Does not automatically open a browser window on startup (used when launching
@@ -1020,6 +1036,10 @@ const char kSbMacKeyURLPrefix[] = "safebrowsing-mackey-url-prefix";
// This is used for testing only.
const char kSbDisableAutoUpdate[] = "safebrowsing-disable-auto-update";
+// If present, safebrowsing checks download url and download content's hash
+// to make sure the content are not malicious.
+const char kSbEnableDownloadProtection[] = "safebrowsing-download-protection";
+
// Enable support for SDCH filtering (dictionary based expansion of content).
// Optional argument is *the* only domain name that will have SDCH suppport.
// Default is "-enable-sdch" to advertise SDCH on all domains.
@@ -1309,13 +1329,6 @@ const char kEnableExposeForTabs[] = "enable-expose-for-tabs";
// Cause the OS X sandbox write to syslog every time an access to a resource
// is denied by the sandbox.
const char kEnableSandboxLogging[] = "enable-sandbox-logging";
-
-
-// Temporary flag to revert to the old WorkerPool implementation.
-// This will be removed once we either fix the Mac WorkerPool
-// implementation, or completely switch to the shared (with Linux)
-// implementation.
-const char kDisableLinuxWorkerPool[] = "disable-linux-worker-pool";
#else
// Enable Kiosk mode.
const char kKioskMode[] = "kiosk";
@@ -1343,25 +1356,19 @@ const char kTouchDevices[] = "touch-devices";
#endif
-// USE_SECCOMP_SANDBOX controls whether the seccomp sandbox is opt-in or -out.
+// SeccompSandboxEnabled() controls whether we are using Seccomp.
+// It is currently off by default on all platforms.
// TODO(evan): unify all of these once we turn the seccomp sandbox always
// on. Also remove the #include of command_line.h above.
-#if defined(USE_SECCOMP_SANDBOX)
+
// Disable the seccomp sandbox (Linux only)
const char kDisableSeccompSandbox[] = "disable-seccomp-sandbox";
-#else
// Enable the seccomp sandbox (Linux only)
const char kEnableSeccompSandbox[] = "enable-seccomp-sandbox";
-#endif
bool SeccompSandboxEnabled() {
-#if defined(USE_SECCOMP_SANDBOX)
- return !CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableSeccompSandbox);
-#else
return CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableSeccompSandbox);
-#endif
}
// -----------------------------------------------------------------------------
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index f8ac686..1270ac4 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -23,6 +23,7 @@ namespace switches {
extern const char kActivateOnLaunch[];
extern const char kAllowFileAccessFromFiles[];
extern const char kAllowFileAccess[];
+extern const char kAllowOutdatedPlugins[];
extern const char kAllowSSLMITMProxies[];
extern const char kAllowSandboxDebugging[];
extern const char kAllowScriptingGallery[];
@@ -37,7 +38,6 @@ extern const char kAuthNegotiateDelegateWhitelist[];
extern const char kAuthSchemes[];
extern const char kAuthServerWhitelist[];
extern const char kAutomationClientChannelID[];
-extern const char kBlockNonSandboxedPlugins[];
extern const char kBrowserAssertTest[];
extern const char kBrowserCrashTest[];
extern const char kBrowserSubprocessPath[];
@@ -67,10 +67,12 @@ extern const char kDisableDatabases[];
extern const char kDisableDesktopNotifications[];
extern const char kDisableDevTools[];
extern const char kDisableDeviceOrientation[];
+extern const char kDisableEnforcedThrottling[];
extern const char kDisableExperimentalWebGL[];
extern const char kDisableExtensionsFileAccessCheck[];
extern const char kDisableExtensions[];
extern const char kDisableFileSystem[];
+extern const char kDisableFlashSandbox[];
extern const char kDisableGLSLTranslator[];
extern const char kDisableGeolocation[];
extern const char kDisableGpuWatchdog[];
@@ -78,13 +80,13 @@ extern const char kDisableHangMonitor[];
extern const char kDisableHistoryQuickProvider[];
extern const char kDisableHistoryURLProvider[];
extern const char kDisableInternalFlash[];
+extern const char kDisableIndexedDatabase[];
extern const char kDisableIPv6[];
extern const char kDisableJavaScript[];
extern const char kDisableJava[];
extern const char kDisableLocalStorage[];
extern const char kDisableLogging[];
extern const char kDisableNewTabFirstRun[];
-extern const char kDisableOutdatedPlugins[];
extern const char kDisablePlugins[];
extern const char kDisablePopupBlocking[];
extern const char kDisablePreconnect[];
@@ -100,6 +102,7 @@ extern const char kDisableSSLFalseStart[];
extern const char kDisableSync[];
extern const char kDisableSyncApps[];
extern const char kDisableSyncAutofill[];
+extern const char kDisableSyncAutofillProfile[];
extern const char kDisableSyncBookmarks[];
extern const char kDisableSyncExtensions[];
extern const char kDisableSyncPreferences[];
@@ -140,10 +143,8 @@ extern const char kEnableExperimentalExtensionApis[];
extern const char kEnableExtensionTimelineApi[];
extern const char kEnableFastback[];
extern const char kEnableFileCookies[];
-extern const char kEnableFlashSandbox[];
extern const char kEnableGPUPlugin[];
extern const char kEnableIPv6[];
-extern const char kEnableIndexedDatabase[];
extern const char kEnableLogging[];
extern const char kEnableMemoryInfo[];
extern const char kEnableMonitorProfile[];
@@ -154,6 +155,7 @@ extern const char kEnablePagePrerender[];
extern const char kEnableSyncNewAutofill[];
extern const char kEnablePreconnect[];
extern const char kEnablePredictiveInstant[];
+extern const char kEnablePredictiveNoAutoCompleteInstant[];
extern const char kEnablePreparsedJsCaching[];
extern const char kEnablePrintPreview[];
extern const char kEnableRemoting[];
@@ -194,6 +196,7 @@ extern const char kForceAppsPromoVisible[];
extern const char kForceFieldTestNameAndValue[];
extern const char kForceInternalPDFPlugin[];
extern const char kForceRendererAccessibility[];
+extern const char kForceStubLibcros[];
extern const char kGpuLauncher[];
extern const char kGpuProcess[];
extern const char kGpuStartupDialog[];
@@ -237,6 +240,7 @@ extern const char kNoDefaultBrowserCheck[];
extern const char kNoEvents[];
extern const char kNoExperiments[];
extern const char kNoFirstRun[];
+extern const char kNoGpuSandbox[];
extern const char kNoJsRandomness[];
extern const char kNoProxyServer[];
extern const char kNoReferrers[];
@@ -286,6 +290,7 @@ extern const char kSafePlugins[];
extern const char kSbInfoURLPrefix[];
extern const char kSbMacKeyURLPrefix[];
extern const char kSbDisableAutoUpdate[];
+extern const char kSbEnableDownloadProtection[];
extern const char kSdchFilter[];
extern const char kSearchInOmniboxHint[];
extern const char kServiceProcess[];
@@ -354,7 +359,6 @@ extern const char kGuestSession[];
extern const char kStubCros[];
extern const char kScreenSaverUrl[];
extern const char kCompressSystemFeedback[];
-extern const char kForceStubLibcros[];
extern const char kEnableDOMUIMenu[];
extern const char kEnableMediaPlayer[];
extern const char kEnableAdvancedFileSystem[];
@@ -380,7 +384,6 @@ extern const char kPasswordStore[];
extern const char kDisableHolePunching[];
extern const char kEnableExposeForTabs[];
extern const char kEnableSandboxLogging[];
-extern const char kDisableLinuxWorkerPool[];
#else
extern const char kKioskMode[];
#endif
@@ -400,11 +403,9 @@ extern const char kRendererCheckFalseTest[];
extern const char kTouchDevices[];
#endif
-#if defined(USE_SECCOMP_SANDBOX)
extern const char kDisableSeccompSandbox[];
-#else
extern const char kEnableSeccompSandbox[];
-#endif
+
// Return true if the switches indicate the seccomp sandbox is enabled.
bool SeccompSandboxEnabled();
diff --git a/chrome/common/chrome_version_info.cc b/chrome/common/chrome_version_info.cc
index 5157c4a..7bca883 100644
--- a/chrome/common/chrome_version_info.cc
+++ b/chrome/common/chrome_version_info.cc
@@ -32,19 +32,19 @@ bool VersionInfo::is_valid() const {
std::string VersionInfo::Name() const {
if (!is_valid())
return std::string();
- return WideToASCII(version_info_->product_name());
+ return UTF16ToASCII(version_info_->product_name());
}
std::string VersionInfo::Version() const {
if (!is_valid())
return std::string();
- return WideToASCII(version_info_->product_version());
+ return UTF16ToASCII(version_info_->product_version());
}
std::string VersionInfo::LastChange() const {
if (!is_valid())
return std::string();
- return WideToASCII(version_info_->last_change());
+ return UTF16ToASCII(version_info_->last_change());
}
bool VersionInfo::IsOfficialBuild() const {
diff --git a/chrome/common/common_param_traits.cc b/chrome/common/common_param_traits.cc
index 165224c..40417fc 100644
--- a/chrome/common/common_param_traits.cc
+++ b/chrome/common/common_param_traits.cc
@@ -13,6 +13,7 @@
#include "gfx/rect.h"
#include "googleurl/src/gurl.h"
#include "net/base/upload_data.h"
+#include "printing/backend/print_backend.h"
#include "printing/native_metafile.h"
#include "printing/page_range.h"
@@ -232,25 +233,36 @@ void ParamTraits<WebApplicationInfo>::Write(Message* m,
WriteParam(m, p.title);
WriteParam(m, p.description);
WriteParam(m, p.app_url);
+ WriteParam(m, p.launch_container);
WriteParam(m, p.icons.size());
+ WriteParam(m, p.permissions.size());
+
for (size_t i = 0; i < p.icons.size(); ++i) {
WriteParam(m, p.icons[i].url);
WriteParam(m, p.icons[i].width);
WriteParam(m, p.icons[i].height);
WriteParam(m, p.icons[i].data);
}
+
+ for (size_t i = 0; i < p.permissions.size(); ++i)
+ WriteParam(m, p.permissions[i]);
}
bool ParamTraits<WebApplicationInfo>::Read(
const Message* m, void** iter, WebApplicationInfo* r) {
- size_t icon_count;
+ size_t icon_count = 0;
+ size_t permissions_count = 0;
+
bool result =
ReadParam(m, iter, &r->title) &&
ReadParam(m, iter, &r->description) &&
ReadParam(m, iter, &r->app_url) &&
- ReadParam(m, iter, &icon_count);
+ ReadParam(m, iter, &r->launch_container) &&
+ ReadParam(m, iter, &icon_count) &&
+ ReadParam(m, iter, &permissions_count);
if (!result)
return false;
+
for (size_t i = 0; i < icon_count; ++i) {
param_type::IconInfo icon_info;
result =
@@ -262,6 +274,14 @@ bool ParamTraits<WebApplicationInfo>::Read(
return false;
r->icons.push_back(icon_info);
}
+
+ for (size_t i = 0; i < permissions_count; ++i) {
+ std::string permission;
+ if (!ReadParam(m, iter, &permission))
+ return false;
+ r->permissions.push_back(permission);
+ }
+
return true;
}
@@ -627,4 +647,34 @@ void ParamTraits<base::PlatformFileInfo>::Log(
l->append(")");
}
+void ParamTraits<printing::PrinterCapsAndDefaults>::Write(
+ Message* m, const param_type& p) {
+ WriteParam(m, p.printer_capabilities);
+ WriteParam(m, p.caps_mime_type);
+ WriteParam(m, p.printer_defaults);
+ WriteParam(m, p.defaults_mime_type);
+}
+
+bool ParamTraits<printing::PrinterCapsAndDefaults>::Read(
+ const Message* m, void** iter, param_type* p) {
+ return
+ ReadParam(m, iter, &p->printer_capabilities) &&
+ ReadParam(m, iter, &p->caps_mime_type) &&
+ ReadParam(m, iter, &p->printer_defaults) &&
+ ReadParam(m, iter, &p->defaults_mime_type);
+}
+
+void ParamTraits<printing::PrinterCapsAndDefaults>::Log(
+ const param_type& p, std::string* l) {
+ l->append("(");
+ LogParam(p.printer_capabilities, l);
+ l->append(",");
+ LogParam(p.caps_mime_type, l);
+ l->append(",");
+ LogParam(p.printer_defaults, l);
+ l->append(",");
+ LogParam(p.defaults_mime_type, l);
+ l->append(")");
+}
+
} // namespace IPC
diff --git a/chrome/common/common_param_traits.h b/chrome/common/common_param_traits.h
index 6862482..3638443 100644
--- a/chrome/common/common_param_traits.h
+++ b/chrome/common/common_param_traits.h
@@ -14,6 +14,7 @@
#include "app/surface/transport_dib.h"
#include "base/file_util.h"
+#include "base/platform_file.h"
#include "base/ref_counted.h"
#include "chrome/common/content_settings.h"
#include "chrome/common/page_zoom.h"
@@ -55,6 +56,7 @@ class UploadData;
namespace printing {
struct PageRange;
+struct PrinterCapsAndDefaults;
} // namespace printing
namespace webkit_glue {
@@ -327,6 +329,20 @@ struct ParamTraits<base::PlatformFileInfo> {
static void Log(const param_type& p, std::string* l);
};
+// Traits for base::PlatformFileError
+template <>
+struct SimilarTypeTraits<base::PlatformFileError> {
+ typedef int Type;
+};
+
+template <>
+struct ParamTraits<printing::PrinterCapsAndDefaults> {
+ typedef printing::PrinterCapsAndDefaults param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
} // namespace IPC
#endif // CHROME_COMMON_COMMON_PARAM_TRAITS_H_
diff --git a/chrome/common/common_param_traits_unittest.cc b/chrome/common/common_param_traits_unittest.cc
index 6086c12..8446158 100644
--- a/chrome/common/common_param_traits_unittest.cc
+++ b/chrome/common/common_param_traits_unittest.cc
@@ -13,6 +13,7 @@
#include "googleurl/src/gurl.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_message_utils.h"
+#include "printing/backend/print_backend.h"
#include "printing/native_metafile.h"
#include "printing/page_range.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -264,3 +265,24 @@ TEST(IPCMessageTest, Metafile) {
}
#endif // defined(OS_WIN)
+// Tests printing::PrinterCapsAndDefaults serialization
+TEST(IPCMessageTest, PrinterCapsAndDefaults) {
+ printing::PrinterCapsAndDefaults input;
+ input.printer_capabilities = "Test Capabilities";
+ input.caps_mime_type = "text/plain";
+ input.printer_defaults = "Test Defaults";
+ input.defaults_mime_type = "text/plain";
+
+ IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+ IPC::ParamTraits<printing::PrinterCapsAndDefaults>::Write(&msg, input);
+
+ printing::PrinterCapsAndDefaults output;
+ void* iter = NULL;
+ EXPECT_TRUE(IPC::ParamTraits<printing::PrinterCapsAndDefaults>::Read(
+ &msg, &iter, &output));
+ EXPECT_TRUE(input.printer_capabilities == output.printer_capabilities);
+ EXPECT_TRUE(input.caps_mime_type == output.caps_mime_type);
+ EXPECT_TRUE(input.printer_defaults == output.printer_defaults);
+ EXPECT_TRUE(input.defaults_mime_type == output.defaults_mime_type);
+}
+
diff --git a/chrome/common/database_messages.cc b/chrome/common/database_messages.cc
new file mode 100644
index 0000000..0b1b5d9
--- /dev/null
+++ b/chrome/common/database_messages.cc
@@ -0,0 +1,8 @@
+// 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.
+
+#include "chrome/common/common_param_traits.h"
+
+#define IPC_MESSAGE_IMPL
+#include "chrome/common/database_messages.h"
diff --git a/chrome/common/database_messages.h b/chrome/common/database_messages.h
new file mode 100644
index 0000000..bb910b0
--- /dev/null
+++ b/chrome/common/database_messages.h
@@ -0,0 +1,79 @@
+// 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.
+
+#ifndef CHROME_COMMON_DATABASE_MESSAGES_H_
+#define CHROME_COMMON_DATABASE_MESSAGES_H_
+#pragma once
+
+#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_param_traits.h"
+#include "ipc/ipc_platform_file.h"
+
+#define IPC_MESSAGE_START DatabaseMsgStart
+
+// Database messages sent from the browser to the renderer.
+
+// Notifies the child process of the new database size
+IPC_MESSAGE_CONTROL4(DatabaseMsg_UpdateSize,
+ string16 /* the origin */,
+ string16 /* the database name */,
+ int64 /* the new database size */,
+ int64 /* space available to origin */)
+
+// Asks the child process to close a database immediately
+IPC_MESSAGE_CONTROL2(DatabaseMsg_CloseImmediately,
+ string16 /* the origin */,
+ string16 /* the database name */)
+
+// Database messages sent from the renderer to the browser.
+
+// Sent by the renderer process to check whether access to web databases is
+// granted by content settings. This may block and trigger a cookie prompt.
+IPC_SYNC_MESSAGE_ROUTED4_1(DatabaseHostMsg_Allow,
+ std::string /* origin_url */,
+ string16 /* database name */,
+ string16 /* database display name */,
+ unsigned long /* estimated size */,
+ bool /* result */)
+
+// Asks the browser process to open a DB file with the given name.
+IPC_SYNC_MESSAGE_CONTROL2_1(DatabaseHostMsg_OpenFile,
+ string16 /* vfs file name */,
+ int /* desired flags */,
+ IPC::PlatformFileForTransit /* file_handle */)
+
+// Asks the browser process to delete a DB file
+IPC_SYNC_MESSAGE_CONTROL2_1(DatabaseHostMsg_DeleteFile,
+ string16 /* vfs file name */,
+ bool /* whether or not to sync the directory */,
+ int /* SQLite error code */)
+
+// Asks the browser process to return the attributes of a DB file
+IPC_SYNC_MESSAGE_CONTROL1_1(DatabaseHostMsg_GetFileAttributes,
+ string16 /* vfs file name */,
+ int32 /* the attributes for the given DB file */)
+
+// Asks the browser process to return the size of a DB file
+IPC_SYNC_MESSAGE_CONTROL1_1(DatabaseHostMsg_GetFileSize,
+ string16 /* vfs file name */,
+ int64 /* the size of the given DB file */)
+
+// Notifies the browser process that a new database has been opened
+IPC_MESSAGE_CONTROL4(DatabaseHostMsg_Opened,
+ string16 /* origin identifier */,
+ string16 /* database name */,
+ string16 /* database description */,
+ int64 /* estimated size */)
+
+// Notifies the browser process that a database might have been modified
+IPC_MESSAGE_CONTROL2(DatabaseHostMsg_Modified,
+ string16 /* origin identifier */,
+ string16 /* database name */)
+
+// Notifies the browser process that a database is about to close
+IPC_MESSAGE_CONTROL2(DatabaseHostMsg_Closed,
+ string16 /* origin identifier */,
+ string16 /* database name */)
+
+#endif // CHROME_COMMON_DATABASE_MESSAGES_H_
diff --git a/chrome/common/database_util.cc b/chrome/common/database_util.cc
index ea4e2cc..36abdb8 100644
--- a/chrome/common/database_util.cc
+++ b/chrome/common/database_util.cc
@@ -5,7 +5,7 @@
#include "chrome/common/database_util.h"
#include "chrome/common/child_thread.h"
-#include "chrome/common/render_messages.h"
+#include "chrome/common/database_messages.h"
#include "ipc/ipc_sync_message_filter.h"
#include "third_party/sqlite/sqlite3.h"
#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
@@ -20,7 +20,7 @@ WebKitClient::FileHandle DatabaseUtil::databaseOpenFile(
scoped_refptr<IPC::SyncMessageFilter> filter(
ChildThread::current()->sync_message_filter());
- filter->Send(new ViewHostMsg_DatabaseOpenFile(
+ filter->Send(new DatabaseHostMsg_OpenFile(
vfs_file_name, desired_flags, &file_handle));
return IPC::PlatformFileForTransitToPlatformFile(file_handle);
@@ -31,7 +31,7 @@ int DatabaseUtil::databaseDeleteFile(
int rv = SQLITE_IOERR_DELETE;
scoped_refptr<IPC::SyncMessageFilter> filter(
ChildThread::current()->sync_message_filter());
- filter->Send(new ViewHostMsg_DatabaseDeleteFile(
+ filter->Send(new DatabaseHostMsg_DeleteFile(
vfs_file_name, sync_dir, &rv));
return rv;
}
@@ -40,7 +40,7 @@ long DatabaseUtil::databaseGetFileAttributes(const WebString& vfs_file_name) {
int32 rv = -1;
scoped_refptr<IPC::SyncMessageFilter> filter(
ChildThread::current()->sync_message_filter());
- filter->Send(new ViewHostMsg_DatabaseGetFileAttributes(vfs_file_name, &rv));
+ filter->Send(new DatabaseHostMsg_GetFileAttributes(vfs_file_name, &rv));
return rv;
}
@@ -48,6 +48,6 @@ long long DatabaseUtil::databaseGetFileSize(const WebString& vfs_file_name) {
int64 rv = 0LL;
scoped_refptr<IPC::SyncMessageFilter> filter(
ChildThread::current()->sync_message_filter());
- filter->Send(new ViewHostMsg_DatabaseGetFileSize(vfs_file_name, &rv));
+ filter->Send(new DatabaseHostMsg_GetFileSize(vfs_file_name, &rv));
return rv;
}
diff --git a/chrome/common/db_message_filter.cc b/chrome/common/db_message_filter.cc
index 8e3bbc6..e10bb1d 100644
--- a/chrome/common/db_message_filter.cc
+++ b/chrome/common/db_message_filter.cc
@@ -4,8 +4,9 @@
#include "chrome/common/db_message_filter.h"
-#include "chrome/common/render_messages.h"
+#include "chrome/common/database_messages.h"
#include "third_party/WebKit/WebKit/chromium/public/WebDatabase.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
DBMessageFilter::DBMessageFilter() {
}
@@ -13,8 +14,8 @@ DBMessageFilter::DBMessageFilter() {
bool DBMessageFilter::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(DBMessageFilter, message)
- IPC_MESSAGE_HANDLER(ViewMsg_DatabaseUpdateSize, OnDatabaseUpdateSize)
- IPC_MESSAGE_HANDLER(ViewMsg_DatabaseCloseImmediately,
+ IPC_MESSAGE_HANDLER(DatabaseMsg_UpdateSize, OnDatabaseUpdateSize)
+ IPC_MESSAGE_HANDLER(DatabaseMsg_CloseImmediately,
OnDatabaseCloseImmediately)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
diff --git a/chrome/common/default_plugin.cc b/chrome/common/default_plugin.cc
index bba738b..3337c7c 100644
--- a/chrome/common/default_plugin.cc
+++ b/chrome/common/default_plugin.cc
@@ -5,13 +5,13 @@
#include "chrome/common/default_plugin.h"
#include "chrome/default_plugin/plugin_main.h"
-#include "webkit/glue/plugins/plugin_list.h"
+#include "webkit/plugins/npapi/plugin_list.h"
namespace chrome {
void RegisterInternalDefaultPlugin() {
- const NPAPI::PluginVersionInfo default_plugin = {
- FilePath(kDefaultPluginLibraryName),
+ const webkit::npapi::PluginVersionInfo default_plugin = {
+ FilePath(webkit::npapi::kDefaultPluginLibraryName),
L"Default Plug-in",
L"Provides functionality for installing third-party plug-ins",
L"1",
@@ -27,7 +27,8 @@ void RegisterInternalDefaultPlugin() {
}
};
- NPAPI::PluginList::Singleton()->RegisterInternalPlugin(default_plugin);
+ webkit::npapi::PluginList::Singleton()->RegisterInternalPlugin(
+ default_plugin);
}
} // namespace chrome
diff --git a/chrome/common/devtools_messages.cc b/chrome/common/devtools_messages.cc
index 8ea923e..4efa63d 100644
--- a/chrome/common/devtools_messages.cc
+++ b/chrome/common/devtools_messages.cc
@@ -2,8 +2,5 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#define IPC_MESSAGE_IMPL
#include "chrome/common/devtools_messages.h"
-
-#define MESSAGES_INTERNAL_IMPL_FILE \
- "chrome/common/devtools_messages_internal.h"
-#include "ipc/ipc_message_impl_macros.h"
diff --git a/chrome/common/devtools_messages.h b/chrome/common/devtools_messages.h
index 060c4d9..ab54b51 100644
--- a/chrome/common/devtools_messages.h
+++ b/chrome/common/devtools_messages.h
@@ -7,12 +7,10 @@
#pragma once
#include <map>
-
-#include "ipc/ipc_message_utils.h"
+#include <string>
typedef std::map<std::string, std::string> DevToolsRuntimeProperties;
-#define MESSAGES_INTERNAL_FILE "chrome/common/devtools_messages_internal.h"
-#include "ipc/ipc_message_macros.h"
+#include "chrome/common/devtools_messages_internal.h"
#endif // CHROME_COMMON_DEVTOOLS_MESSAGES_H_
diff --git a/chrome/common/devtools_messages_internal.h b/chrome/common/devtools_messages_internal.h
index ac8dbce..6019d60 100644
--- a/chrome/common/devtools_messages_internal.h
+++ b/chrome/common/devtools_messages_internal.h
@@ -2,10 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// This header is meant to be included in multiple passes, hence no traditional
-// header guard.
-// See ipc_message_macros.h for explanation of the macros and passes.
-
// Developer tools consist of the following parts:
//
// DevToolsAgent lives in the renderer of an inspected page and provides access
@@ -44,57 +40,51 @@
#include "ipc/ipc_message_macros.h"
+#define IPC_MESSAGE_START DevToolsMsgStart
+
// These are messages sent from DevToolsAgent to DevToolsClient through the
// browser.
-IPC_BEGIN_MESSAGES(DevToolsClient)
-
- // WebKit-level transport.
- IPC_MESSAGE_CONTROL1(DevToolsClientMsg_DispatchOnInspectorFrontend,
- std::string /* message */)
+// WebKit-level transport.
+IPC_MESSAGE_CONTROL1(DevToolsClientMsg_DispatchOnInspectorFrontend,
+ std::string /* message */)
- // Legacy debugger output message.
- IPC_MESSAGE_CONTROL1(DevToolsClientMsg_DebuggerOutput,
- std::string /* message */)
+// Legacy debugger output message.
+IPC_MESSAGE_CONTROL1(DevToolsClientMsg_DebuggerOutput,
+ std::string /* message */)
- // Legacy APU dispatch message.
- IPC_MESSAGE_CONTROL1(DevToolsClientMsg_DispatchToAPU,
- std::string /* message */)
-
-IPC_END_MESSAGES(DevToolsClient)
+// Legacy APU dispatch message.
+IPC_MESSAGE_CONTROL1(DevToolsClientMsg_DispatchToAPU,
+ std::string /* message */)
//-----------------------------------------------------------------------------
// These are messages sent from DevToolsClient to DevToolsAgent through the
// browser.
-IPC_BEGIN_MESSAGES(DevToolsAgent)
-
- // Tells agent that there is a client host connected to it.
- IPC_MESSAGE_CONTROL1(DevToolsAgentMsg_Attach,
- DevToolsRuntimeProperties /* properties */)
-
- // Tells agent that there is no longer a client host connected to it.
- IPC_MESSAGE_CONTROL0(DevToolsAgentMsg_Detach)
-
- // Tells agent that the front-end has been loaded
- IPC_MESSAGE_CONTROL0(DevToolsAgentMsg_FrontendLoaded)
-
- // WebKit-level transport.
- IPC_MESSAGE_CONTROL1(DevToolsAgentMsg_DispatchOnInspectorBackend,
- std::string /* message */)
-
- // Send debugger command to the debugger agent. Debugger commands should
- // be handled on IO thread(while all other devtools messages are handled in
- // the render thread) to allow executing the commands when v8 is on a
- // breakpoint.
- IPC_MESSAGE_CONTROL1(DevToolsAgentMsg_DebuggerCommand,
- std::string /* command */)
-
- // Inspect element with the given coordinates.
- IPC_MESSAGE_CONTROL2(DevToolsAgentMsg_InspectElement,
- int /* x */,
- int /* y */)
-
- // Enables/disables the apu agent.
- IPC_MESSAGE_CONTROL1(DevToolsAgentMsg_SetApuAgentEnabled, bool /* enabled */)
-
-IPC_END_MESSAGES(DevToolsAgent)
+// Tells agent that there is a client host connected to it.
+IPC_MESSAGE_CONTROL1(DevToolsAgentMsg_Attach,
+ DevToolsRuntimeProperties /* properties */)
+
+// Tells agent that there is no longer a client host connected to it.
+IPC_MESSAGE_CONTROL0(DevToolsAgentMsg_Detach)
+
+// Tells agent that the front-end has been loaded
+IPC_MESSAGE_CONTROL0(DevToolsAgentMsg_FrontendLoaded)
+
+// WebKit-level transport.
+IPC_MESSAGE_CONTROL1(DevToolsAgentMsg_DispatchOnInspectorBackend,
+ std::string /* message */)
+
+// Send debugger command to the debugger agent. Debugger commands should
+// be handled on IO thread(while all other devtools messages are handled in
+// the render thread) to allow executing the commands when v8 is on a
+// breakpoint.
+IPC_MESSAGE_CONTROL1(DevToolsAgentMsg_DebuggerCommand,
+ std::string /* command */)
+
+// Inspect element with the given coordinates.
+IPC_MESSAGE_CONTROL2(DevToolsAgentMsg_InspectElement,
+ int /* x */,
+ int /* y */)
+
+// Enables/disables the apu agent.
+IPC_MESSAGE_CONTROL1(DevToolsAgentMsg_SetApuAgentEnabled, bool /* enabled */)
diff --git a/chrome/common/dom_storage_common.h b/chrome/common/dom_storage_common.h
index 21ba19c..5946384 100644
--- a/chrome/common/dom_storage_common.h
+++ b/chrome/common/dom_storage_common.h
@@ -6,6 +6,10 @@
#define CHROME_COMMON_DOM_STORAGE_COMMON_H_
#pragma once
+#include "build/build_config.h"
+
+#include "base/basictypes.h"
+
const int64 kLocalStorageNamespaceId = 0;
const int64 kInvalidSessionStorageNamespaceId = kLocalStorageNamespaceId;
diff --git a/chrome/common/dom_storage_messages.cc b/chrome/common/dom_storage_messages.cc
new file mode 100644
index 0000000..9aee345
--- /dev/null
+++ b/chrome/common/dom_storage_messages.cc
@@ -0,0 +1,125 @@
+// 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.
+
+#include "chrome/common/common_param_traits.h"
+
+#define IPC_MESSAGE_IMPL
+#include "chrome/common/dom_storage_messages.h"
+
+DOMStorageMsg_Event_Params::DOMStorageMsg_Event_Params()
+ : storage_type(DOM_STORAGE_LOCAL) {
+}
+
+DOMStorageMsg_Event_Params::~DOMStorageMsg_Event_Params() {
+}
+
+namespace IPC {
+
+void ParamTraits<DOMStorageMsg_Event_Params>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.key);
+ WriteParam(m, p.old_value);
+ WriteParam(m, p.new_value);
+ WriteParam(m, p.origin);
+ WriteParam(m, p.url);
+ WriteParam(m, p.storage_type);
+}
+
+bool ParamTraits<DOMStorageMsg_Event_Params>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->key) &&
+ ReadParam(m, iter, &p->old_value) &&
+ ReadParam(m, iter, &p->new_value) &&
+ ReadParam(m, iter, &p->origin) &&
+ ReadParam(m, iter, &p->url) &&
+ ReadParam(m, iter, &p->storage_type);
+}
+
+void ParamTraits<DOMStorageMsg_Event_Params>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.key, l);
+ l->append(", ");
+ LogParam(p.old_value, l);
+ l->append(", ");
+ LogParam(p.new_value, l);
+ l->append(", ");
+ LogParam(p.origin, l);
+ l->append(", ");
+ LogParam(p.url, l);
+ l->append(", ");
+ LogParam(p.storage_type, l);
+ l->append(")");
+}
+
+void ParamTraits<DOMStorageType>::Write(Message* m, const param_type& p) {
+ m->WriteInt(p);
+}
+
+bool ParamTraits<DOMStorageType>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ int type;
+ if (!m->ReadInt(iter, &type))
+ return false;
+ *p = static_cast<param_type>(type);
+ return true;
+}
+
+void ParamTraits<DOMStorageType>::Log(const param_type& p, std::string* l) {
+ std::string control;
+ switch (p) {
+ case DOM_STORAGE_LOCAL:
+ control = "DOM_STORAGE_LOCAL";
+ break;
+ case DOM_STORAGE_SESSION:
+ control = "DOM_STORAGE_SESSION";
+ break;
+ default:
+ NOTIMPLEMENTED();
+ control = "UNKNOWN";
+ break;
+ }
+ LogParam(control, l);
+}
+
+void ParamTraits<WebKit::WebStorageArea::Result>::Write(Message* m,
+ const param_type& p) {
+ m->WriteInt(p);
+}
+
+bool ParamTraits<WebKit::WebStorageArea::Result>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ int type;
+ if (!m->ReadInt(iter, &type))
+ return false;
+ *p = static_cast<param_type>(type);
+ return true;
+}
+
+void ParamTraits<WebKit::WebStorageArea::Result>::Log(const param_type& p,
+ std::string* l) {
+ std::string control;
+ switch (p) {
+ case WebKit::WebStorageArea::ResultOK:
+ control = "WebKit::WebStorageArea::ResultOK";
+ break;
+ case WebKit::WebStorageArea::ResultBlockedByQuota:
+ control = "WebKit::WebStorageArea::ResultBlockedByQuota";
+ break;
+ case WebKit::WebStorageArea::ResultBlockedByPolicy:
+ control = "WebKit::WebStorageArea::ResultBlockedByPolicy";
+ break;
+ default:
+ NOTIMPLEMENTED();
+ control = "UNKNOWN";
+ break;
+ }
+ LogParam(control, l);
+}
+
+} // namespace IPC
diff --git a/chrome/common/dom_storage_messages.h b/chrome/common/dom_storage_messages.h
new file mode 100644
index 0000000..e36f517
--- /dev/null
+++ b/chrome/common/dom_storage_messages.h
@@ -0,0 +1,125 @@
+// 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.
+
+#ifndef CHROME_COMMON_DOM_STORAGE_MESSAGES_H_
+#define CHROME_COMMON_DOM_STORAGE_MESSAGES_H_
+#pragma once
+
+#include "chrome/common/dom_storage_common.h"
+#include "googleurl/src/gurl.h"
+#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_param_traits.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebStorageArea.h"
+
+#define IPC_MESSAGE_START DOMStorageMsgStart
+
+// Signals a storage event.
+struct DOMStorageMsg_Event_Params {
+ DOMStorageMsg_Event_Params();
+ ~DOMStorageMsg_Event_Params();
+
+ // The key that generated the storage event. Null if clear() was called.
+ NullableString16 key;
+
+ // The old value of this key. Null on clear() or if it didn't have a value.
+ NullableString16 old_value;
+
+ // The new value of this key. Null on removeItem() or clear().
+ NullableString16 new_value;
+
+ // The origin this is associated with.
+ string16 origin;
+
+ // The URL of the page that caused the storage event.
+ GURL url;
+
+ // The storage type of this event.
+ DOMStorageType storage_type;
+};
+
+namespace IPC {
+
+template <>
+struct ParamTraits<DOMStorageMsg_Event_Params> {
+ typedef DOMStorageMsg_Event_Params param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct ParamTraits<DOMStorageType> {
+ typedef DOMStorageType param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct ParamTraits<WebKit::WebStorageArea::Result> {
+ typedef WebKit::WebStorageArea::Result param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
+};
+
+} // namespace IPC
+
+// DOM Storage messages sent from the browser to the renderer.
+
+// Storage events are broadcast to renderer processes.
+IPC_MESSAGE_CONTROL1(DOMStorageMsg_Event,
+ DOMStorageMsg_Event_Params)
+
+
+// DOM Storage messages sent from the renderer to the browser.
+
+
+// Get the storage area id for a particular origin within a namespace.
+IPC_SYNC_MESSAGE_CONTROL2_1(DOMStorageHostMsg_StorageAreaId,
+ int64 /* namespace_id */,
+ string16 /* origin */,
+ int64 /* storage_area_id */)
+
+// Get the length of a storage area.
+IPC_SYNC_MESSAGE_CONTROL1_1(DOMStorageHostMsg_Length,
+ int64 /* storage_area_id */,
+ unsigned /* length */)
+
+// Get a the ith key within a storage area.
+IPC_SYNC_MESSAGE_CONTROL2_1(DOMStorageHostMsg_Key,
+ int64 /* storage_area_id */,
+ unsigned /* index */,
+ NullableString16 /* key */)
+
+// Get a value based on a key from a storage area.
+IPC_SYNC_MESSAGE_CONTROL2_1(DOMStorageHostMsg_GetItem,
+ int64 /* storage_area_id */,
+ string16 /* key */,
+ NullableString16 /* value */)
+
+// Set a value that's associated with a key in a storage area.
+IPC_SYNC_MESSAGE_CONTROL5_2(DOMStorageHostMsg_SetItem,
+ int /* routing_id */,
+ int64 /* storage_area_id */,
+ string16 /* key */,
+ string16 /* value */,
+ GURL /* url */,
+ WebKit::WebStorageArea::Result /* result */,
+ NullableString16 /* old_value */)
+
+// Remove the value associated with a key in a storage area.
+IPC_SYNC_MESSAGE_CONTROL3_1(DOMStorageHostMsg_RemoveItem,
+ int64 /* storage_area_id */,
+ string16 /* key */,
+ GURL /* url */,
+ NullableString16 /* old_value */)
+
+// Clear the storage area.
+IPC_SYNC_MESSAGE_CONTROL2_1(DOMStorageHostMsg_Clear,
+ int64 /* storage_area_id */,
+ GURL /* url */,
+ bool /* something_cleared */)
+
+#endif // CHROME_COMMON_DOM_STORAGE_MESSAGES_H_
diff --git a/chrome/common/extensions/api/extension_api.json b/chrome/common/extensions/api/extension_api.json
index 1cb4a0e..8dac7c4 100644
--- a/chrome/common/extensions/api/extension_api.json
+++ b/chrome/common/extensions/api/extension_api.json
@@ -517,10 +517,15 @@
"optional": true,
"description": "If true, enqueues this utterance if TTS is already in progress. If false (the default), interrupts any current speech and flushes the speech queue before speaking this new utterance."
},
- "languageName": {
+ "voiceName": {
"type": "string",
"optional": true,
- "description": "The language name for synthesis specified in the form <language>-<locale>, e.g. en-US, en-GB, fr-CA, zh-CN, etc."
+ "description": "The name of the voice to use for synthesis."
+ },
+ "locale": {
+ "type": "string",
+ "optional": true,
+ "description": "The language and region code that specify the language and dialect to be used for synthesis, in the form <language>-<region>, e.g. en-US, en-GB, fr-CA, zh-CN, etc."
},
"gender": {
"type": "string",
@@ -584,6 +589,99 @@
]
}
]
+ },
+ {
+ "name": "speakCompleted",
+ "nodoc": true,
+ "type": "function",
+ "description": "A callback passed to the onSpeak event.",
+ "parameters": [
+ {
+ "type": "integer",
+ "name": "requestId"
+ },
+ {
+ "type": "string",
+ "optional": "true",
+ "name": "errorMessage"
+ }
+ ]
+ }
+ ],
+ "events": [
+ {
+ "name": "onSpeak",
+ "type": "function",
+ "description": "Called when the user makes a call to tts.speak and the options matches one of the tts_voices from this extension's manifest.",
+ "parameters": [
+ {
+ "type": "string",
+ "name": "utterance",
+ "description": "The text to speak."
+ },
+ {
+ "type": "object",
+ "name": "options",
+ "description": "The speak options.",
+ "properties": {
+ "voiceName": {
+ "type": "string",
+ "optional": true,
+ "description": "The name of the voice to use for synthesis."
+ },
+ "locale": {
+ "type": "string",
+ "optional": true,
+ "description": "The language and region code that specify the language and dialect to be used for synthesis, in the form <language>-<region>, e.g. en-US, en-GB, fr-CA, zh-CN, etc."
+ },
+ "gender": {
+ "type": "string",
+ "optional": true,
+ "description": "Gender of voice for synthesized speech.",
+ "enum": ["male", "female"]
+ },
+ "rate": {
+ "type": "number",
+ "optional": true,
+ "minimum": 0,
+ "maximum": 1,
+ "description": "Speaking speed between 0 and 1 inclusive, with 0 being slowest and 1 being fastest."
+ },
+ "pitch": {
+ "type": "number",
+ "optional": true,
+ "minimum": 0,
+ "maximum": 1,
+ "description": "Speaking pitch between 0 and 1 inclusive, with 0 being lowest and 1 being highest."
+ },
+ "volume": {
+ "type": "number",
+ "optional": true,
+ "minimum": 0,
+ "maximum": 1,
+ "description": "Speaking volume between 0 and 1 inclusive, with 0 being lowest and 1 being highest."
+ }
+ }
+ },
+ {
+ "type": "function",
+ "name": "callback",
+ "description": "You must call this function when speaking is finished.",
+ "parameters": [
+ {
+ "type": "string",
+ "name": "error",
+ "optional": true,
+ "description": "Error message, which will be returned to the caller in chrome.extension.lastError."
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "name": "onStop",
+ "type": "function",
+ "description": "Fired when a call is made to tts.stop and this extension may be in the middle of speaking."
}
]
},
@@ -710,6 +808,7 @@
{"type": "array", "items": {"type": "string"}}
]
},
+ "tabId": {"type": "integer", "minimum": 0, "optional": true, "description": "The id of the tab for which you want to adopt to the new window."},
"left": {"type": "integer", "optional": true, "description": "The number of pixels to position the new window from the left edge of the screen. If not specified, the new window is offset naturally from the last focusd window."},
"top": {"type": "integer", "optional": true, "description": "The number of pixels to position the new window from the top edge of the screen. If not specified, the new window is offset naturally from the last focusd window."},
"width": {"type": "integer", "minimum": 0, "optional": true, "description": "The width in pixels of the new window. If not specified defaults to a natural width."},
@@ -3635,8 +3734,12 @@
"description": "An object encapsulating a complete proxy configuration.",
"properties": {
"rules": {"$ref": "ProxyRules", "optional": true, "description": "The proxy rules describing this configuration."},
- "autoDetect": {"type": "boolean", "optional": true, "description": "True if the proxy settings sbould be detected automatically."},
- "pacScript": {"$ref": "PacScript", "optional": true, "description": "The proxy auto-config (PAC) script for this configuration."}
+ "pacScript": {"$ref": "PacScript", "optional": true, "description": "The proxy auto-config (PAC) script for this configuration."},
+ "mode": {
+ "type": "string",
+ "enum": ["direct", "auto_detect", "pac_script", "fixed_servers", "system"],
+ "description": "'direct' = Never use a proxy<br>'auto_detect' = Auto detect proxy settings<br>'pac_script' = Use specified PAC script<br>'fixed_servers' = Manually specify proxy servers<br>'system' = Use system proxy settings"
+ }
}
}
],
@@ -3815,7 +3918,7 @@
"name": "state",
"type": "string",
"enum": ["hidden", "shown", "active"],
- "description": "'hidden' indicates sidebar is not defined for the specified tab (show was never called or hide() was called). Nothing is displayed for this sidebar.</br>'shown' means sidebar is defined for the specified tab; mini tab is displayed for this sidebar. Sidebar UI is either collapsed or displaying a content of some other extension's sidebar.</br>'active' indicates that sidebar is defined for the specified tab; sidebar UI is expanded and displaying this sidebar's content."
+ "description": "'hidden' indicates sidebar is not defined for the specified tab (show was never called or hide() was called). Nothing is displayed for this sidebar.<br>'shown' means sidebar is defined for the specified tab; mini tab is displayed for this sidebar. Sidebar UI is either collapsed or displaying a content of some other extension's sidebar.<br>'active' indicates that sidebar is defined for the specified tab; sidebar UI is expanded and displaying this sidebar's content."
}
]
}
@@ -4133,7 +4236,7 @@
},
{
"name": "get",
- "description": "Return information about the installed extension with the given ID.",
+ "description": "Return information about the installed extension or app that has the given ID.",
"parameters": [
{
"name": "id",
diff --git a/chrome/common/extensions/docs/a11y.html b/chrome/common/extensions/docs/a11y.html
index d18f6f7..721b93a 100644
--- a/chrome/common/extensions/docs/a11y.html
+++ b/chrome/common/extensions/docs/a11y.html
@@ -956,7 +956,7 @@ see <a href="samples.html">Samples</a>.
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/api_index.html b/chrome/common/extensions/docs/api_index.html
index af8e72b..5480998 100644
--- a/chrome/common/extensions/docs/api_index.html
+++ b/chrome/common/extensions/docs/api_index.html
@@ -523,7 +523,7 @@ For more information, see the video
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/api_other.html b/chrome/common/extensions/docs/api_other.html
index 7a0077e..baa17f2 100644
--- a/chrome/common/extensions/docs/api_other.html
+++ b/chrome/common/extensions/docs/api_other.html
@@ -555,7 +555,7 @@ just as they do in other web pages.
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/apps.html b/chrome/common/extensions/docs/apps.html
index 0b50ed7..53634d6 100644
--- a/chrome/common/extensions/docs/apps.html
+++ b/chrome/common/extensions/docs/apps.html
@@ -378,7 +378,7 @@ extensions and packaged apps, and packaged apps and hosted apps:
<ul>
<li> <a href="http://code.google.com/chrome/apps/articles/thinking_in_web_apps.html">Thinking in Web Apps</a> </li>
- <li> <a href="http://codesite-staging:29006/chrome/webstore/articles/apps_vs_extensions.html">Extensions, Packaged Apps, and Hosted Apps in the Chrome Web Store</a> </li>
+ <li> <a href="http://code.google.com/chrome/webstore/articles/apps_vs_extensions.html">Extensions, Packaged Apps, and Hosted Apps in the Chrome Web Store</a> </li>
</ul>
@@ -653,7 +653,7 @@ basic concepts about extensions.
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/autoupdate.html b/chrome/common/extensions/docs/autoupdate.html
index d3aaf51..b65e2a8 100644
--- a/chrome/common/extensions/docs/autoupdate.html
+++ b/chrome/common/extensions/docs/autoupdate.html
@@ -612,7 +612,7 @@ Another option is to use the --extensions-update-frequency command-line flag to
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/background_pages.html b/chrome/common/extensions/docs/background_pages.html
index 85d9b99..68dfa2d 100644
--- a/chrome/common/extensions/docs/background_pages.html
+++ b/chrome/common/extensions/docs/background_pages.html
@@ -605,7 +605,7 @@ from a file named <code>image.html</code>.
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/bookmarks.html b/chrome/common/extensions/docs/bookmarks.html
index 33dd392..1f31c7b 100644
--- a/chrome/common/extensions/docs/bookmarks.html
+++ b/chrome/common/extensions/docs/bookmarks.html
@@ -5323,7 +5323,7 @@ For other examples and for help in viewing the source code, see
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/browserAction.html b/chrome/common/extensions/docs/browserAction.html
index f8b505f..639fd88 100644
--- a/chrome/common/extensions/docs/browserAction.html
+++ b/chrome/common/extensions/docs/browserAction.html
@@ -1909,7 +1909,7 @@ For other examples and for help in viewing the source code, see
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/content_scripts.html b/chrome/common/extensions/docs/content_scripts.html
index e64f704..3e529d2 100644
--- a/chrome/common/extensions/docs/content_scripts.html
+++ b/chrome/common/extensions/docs/content_scripts.html
@@ -961,7 +961,7 @@ sending a request to its parent extension.
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/contextMenus.html b/chrome/common/extensions/docs/contextMenus.html
index 981c17d..1265b34 100644
--- a/chrome/common/extensions/docs/contextMenus.html
+++ b/chrome/common/extensions/docs/contextMenus.html
@@ -2933,7 +2933,7 @@ You can find samples of this API on the
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/cookies.html b/chrome/common/extensions/docs/cookies.html
index f45e8ef..582afa1 100644
--- a/chrome/common/extensions/docs/cookies.html
+++ b/chrome/common/extensions/docs/cookies.html
@@ -3611,7 +3611,7 @@ see <a href="samples.html">Samples</a>.
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/crx.html b/chrome/common/extensions/docs/crx.html
index 9a72d60..b1b2df7 100644
--- a/chrome/common/extensions/docs/crx.html
+++ b/chrome/common/extensions/docs/crx.html
@@ -638,7 +638,7 @@ echo "Wrote $crx"
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/css/samples.css b/chrome/common/extensions/docs/css/samples.css
index de3bdb5..05701ea 100644
--- a/chrome/common/extensions/docs/css/samples.css
+++ b/chrome/common/extensions/docs/css/samples.css
@@ -75,7 +75,6 @@ img.icon {
margin: 10px 0;
background: #eee;
padding: 10px;
- -webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
}
@@ -99,4 +98,4 @@ img.icon {
padding: 50px 0;
font-size: 17px;
font-weight: bold;
-} \ No newline at end of file
+}
diff --git a/chrome/common/extensions/docs/devguide.html b/chrome/common/extensions/docs/devguide.html
index 8e489a6..a806b4b 100644
--- a/chrome/common/extensions/docs/devguide.html
+++ b/chrome/common/extensions/docs/devguide.html
@@ -607,7 +607,7 @@ applies to packaged apps, as well as extensions.
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/docs.html b/chrome/common/extensions/docs/docs.html
index baab851..aa629a7 100644
--- a/chrome/common/extensions/docs/docs.html
+++ b/chrome/common/extensions/docs/docs.html
@@ -610,7 +610,7 @@ The following table lists the doc locations and explains how they differ.
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/events.html b/chrome/common/extensions/docs/events.html
index 3136703..e6a3bb2 100644
--- a/chrome/common/extensions/docs/events.html
+++ b/chrome/common/extensions/docs/events.html
@@ -515,7 +515,7 @@ bool hasListener(function callback(...))
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/examples/api/bookmarks/basic.zip b/chrome/common/extensions/docs/examples/api/bookmarks/basic.zip
index 73a1258..02d772f 100644
--- a/chrome/common/extensions/docs/examples/api/bookmarks/basic.zip
+++ b/chrome/common/extensions/docs/examples/api/bookmarks/basic.zip
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/api/bookmarks/basic/icon.png b/chrome/common/extensions/docs/examples/api/bookmarks/basic/icon.png
new file mode 100644
index 0000000..9a79a46
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/bookmarks/basic/icon.png
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/api/omnibox/simple-example.zip b/chrome/common/extensions/docs/examples/api/omnibox/simple-example.zip
index 17d22b2..2a5116d 100644
--- a/chrome/common/extensions/docs/examples/api/omnibox/simple-example.zip
+++ b/chrome/common/extensions/docs/examples/api/omnibox/simple-example.zip
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/extensions/app_launcher.zip b/chrome/common/extensions/docs/examples/extensions/app_launcher.zip
new file mode 100644
index 0000000..6f71c38
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/app_launcher.zip
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/extensions/app_launcher/browser_action_icon.png b/chrome/common/extensions/docs/examples/extensions/app_launcher/browser_action_icon.png
new file mode 100644
index 0000000..046ee42
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/app_launcher/browser_action_icon.png
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/extensions/app_launcher/icon.png b/chrome/common/extensions/docs/examples/extensions/app_launcher/icon.png
new file mode 100644
index 0000000..4aa2994
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/app_launcher/icon.png
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/extensions/app_launcher/manifest.json b/chrome/common/extensions/docs/examples/extensions/app_launcher/manifest.json
new file mode 100644
index 0000000..86b0286
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/app_launcher/manifest.json
@@ -0,0 +1,13 @@
+{
+ "name": "App Launcher",
+ "version": "0.7.3",
+ "permissions": ["management"],
+ "browser_action": {
+ "default_icon": "browser_action_icon.png",
+ "default_title": "App Launcher",
+ "default_popup": "popup.html"
+ },
+ "icons": {
+ "48": "icon.png"
+ }
+}
diff --git a/chrome/common/extensions/docs/examples/extensions/app_launcher/popup.css b/chrome/common/extensions/docs/examples/extensions/app_launcher/popup.css
new file mode 100644
index 0000000..aa6ce07
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/app_launcher/popup.css
@@ -0,0 +1,49 @@
+// 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.
+
+html {
+ overflow-x: hidden;
+}
+
+body {
+ font-family: Helvetica, Arial, sans-serif;
+}
+
+#search_container {
+ text-align: center;
+}
+
+#search {
+ width: 85%;
+}
+
+.app {
+ width: 100%;
+ margin-top: 7px;
+ margin-bottom: 7px;
+ margin-left: 2px;
+ margin-right: 20px;
+ white-space: nowrap;
+}
+
+.app img {
+ vertical-align: middle;
+ height: 38px;
+ width: 38px;
+}
+
+.app_title {
+ vertical-align: middle;
+ margin-left: 5px;
+}
+
+.app:hover {
+ background-color: rgb(250,250,250);
+ cursor:pointer;
+ outline: 1px dotted rgb(100,100,200);
+}
+
+.app_selected,.app_selected:hover {
+ background-color: rgb(230,230,230);
+}
diff --git a/chrome/common/extensions/docs/examples/extensions/app_launcher/popup.html b/chrome/common/extensions/docs/examples/extensions/app_launcher/popup.html
new file mode 100644
index 0000000..ca14080
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/app_launcher/popup.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<!--
+ * 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.
+-->
+<html>
+<head>
+<link rel="stylesheet" type="text/css" href="popup.css">
+<script src="popup.js"></script>
+</head>
+<body onload="onLoad()">
+
+<div id="spacer_dummy"></div>
+<div id="outer">
+
+<div id="appstore_link" style="display:none">
+<p>No apps installed.</p><p>
+<a href='javascript:chrome.tabs.create({"url":"https://chrome.google.com/webstore", "selected":true});window.close();'>Go get some</a></p>
+</div>
+
+<div id="search_container">
+<input id="search" type="text" placeholder="type to search"
+ oninput="onSearchInput()" spellcheck="false">
+</div>
+
+<div id="apps"></div>
+
+</div>
+
+</body>
+</html>
diff --git a/chrome/common/extensions/docs/examples/extensions/app_launcher/popup.js b/chrome/common/extensions/docs/examples/extensions/app_launcher/popup.js
new file mode 100644
index 0000000..8918c62
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/app_launcher/popup.js
@@ -0,0 +1,198 @@
+// 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.
+
+function $(id) {
+ return document.getElementById(id);
+}
+
+// Returns the largest size icon, or a default icon, for the given |app|.
+function getIconURL(app) {
+ if (!app.icons || app.icons.length == 0) {
+ return chrome.extension.getURL("icon.png");
+ }
+ var largest = {size:0};
+ for (var i = 0; i < app.icons.length; i++) {
+ var icon = app.icons[i];
+ if (icon.size > largest.size) {
+ largest = icon;
+ }
+ }
+ return largest.url;
+}
+
+function launchApp(id) {
+ chrome.management.launchApp(id);
+ window.close(); // Only needed on OSX because of crbug.com/63594
+}
+
+// Adds DOM nodes for |app| into |appsDiv|.
+function addApp(appsDiv, app, selected) {
+ var div = document.createElement("div");
+ div.className = "app" + (selected ? " app_selected" : "");
+
+ div.onclick = function() {
+ launchApp(app.id);
+ };
+
+ var img = document.createElement("img");
+ img.src = getIconURL(app);
+ div.appendChild(img);
+
+ var title = document.createElement("span");
+ title.className = "app_title";
+ title.innerText = app.name;
+ div.appendChild(title);
+
+ appsDiv.appendChild(div);
+}
+
+// The list of all apps & extensions.
+var completeList = [];
+
+// A filtered list of apps we actually want to show.
+var appList = [];
+
+// The index of an app in |appList| that should be highlighted.
+var selectedIndex = 0;
+
+function reloadAppDisplay() {
+ var appsDiv = $("apps");
+
+ // Empty the current content.
+ appsDiv.innerHTML = "";
+
+ for (var i = 0; i < appList.length; i++) {
+ var item = appList[i];
+ addApp(appsDiv, item, i == selectedIndex);
+ }
+}
+
+// Puts only enabled apps from completeList into appList.
+function rebuildAppList(filter) {
+ selectedIndex = 0;
+ appList = [];
+ for (var i = 0; i < completeList.length; i++){
+ var item = completeList[i];
+ // Skip extensions and disabled apps.
+ if (!item.isApp || !item.enabled) {
+ continue;
+ }
+ if (filter && item.name.toLowerCase().search(filter) < 0) {
+ continue;
+ }
+ appList.push(item);
+ }
+}
+
+// In order to keep the popup bubble from shrinking as your search narrows the
+// list of apps shown, we set an explicit width on the outermost div.
+var didSetExplicitWidth = false;
+
+function adjustWidthIfNeeded(filter) {
+ if (filter.length > 0 && !didSetExplicitWidth) {
+ // Set an explicit width, correcting for any scroll bar present.
+ var outer = $("outer");
+ var correction = window.innerWidth - document.documentElement.clientWidth;
+ var width = outer.offsetWidth;
+ $("spacer_dummy").style.width = width + correction + "px";
+ didSetExplicitWidth = true;
+ }
+}
+
+// Shows the list of apps based on the search box contents.
+function onSearchInput() {
+ var filter = $("search").value;
+ adjustWidthIfNeeded(filter);
+ rebuildAppList(filter);
+ reloadAppDisplay();
+}
+
+function compare(a, b) {
+ return (a > b) ? 1 : (a == b ? 0 : -1);
+}
+
+function compareByName(app1, app2) {
+ return compare(app1.name.toLowerCase(), app2.name.toLowerCase());
+}
+
+function onLoad() {
+ chrome.management.getAll(function(info) {
+ var appCount = 0;
+ for (var i = 0; i < info.length; i++) {
+ if (info[i].isApp) {
+ appCount++;
+ }
+ }
+ if (appCount == 0) {
+ $("search").style.display = "none";
+ $("appstore_link").style.display = "";
+ return;
+ }
+ completeList = info.sort(compareByName);
+ onSearchInput();
+ });
+}
+
+// Changes the selected app in the list.
+function changeSelection(newIndex) {
+ if (newIndex >= 0 && newIndex <= appList.length - 1) {
+ selectedIndex = newIndex;
+ reloadAppDisplay();
+
+ var selected = document.getElementsByClassName("app_selected")[0];
+ var rect = selected.getBoundingClientRect();
+ if (newIndex == 0) {
+ window.scrollTo(0, 0);
+ } else if (newIndex == appList.length - 1) {
+ window.scrollTo(0, document.height);
+ } else if (rect.top < 0) {
+ window.scrollBy(0, rect.top);
+ } else if (rect.bottom > innerHeight) {
+ window.scrollBy(0, rect.bottom - innerHeight);
+ }
+ }
+}
+
+var keys = {
+ ENTER : 13,
+ ESCAPE : 27,
+ END : 35,
+ HOME : 36,
+ LEFT : 37,
+ UP : 38,
+ RIGHT : 39,
+ DOWN : 40
+};
+
+// Set up a key event handler that handles moving the selected app up/down,
+// hitting enter to launch the selected app, as well as auto-focusing the
+// search box as soon as you start typing.
+window.onkeydown = function(event) {
+ switch (event.keyCode) {
+ case keys.DOWN:
+ changeSelection(selectedIndex + 1);
+ break;
+ case keys.UP:
+ changeSelection(selectedIndex - 1);
+ break;
+ case keys.HOME:
+ changeSelection(0);
+ break;
+ case keys.END:
+ changeSelection(appList.length - 1);
+ break;
+ case keys.ENTER:
+ var app = appList[selectedIndex];
+ if (app) {
+ launchApp(app.id);
+ }
+ break;
+ default:
+ // Focus the search box and return true so you can just start typing even
+ // when the search box isn't focused.
+ $("search").focus();
+ return true;
+ }
+ return false;
+};
diff --git a/chrome/common/extensions/docs/examples/extensions/benchmark.zip b/chrome/common/extensions/docs/examples/extensions/benchmark.zip
index a322ab3..3d799d2 100644
--- a/chrome/common/extensions/docs/examples/extensions/benchmark.zip
+++ b/chrome/common/extensions/docs/examples/extensions/benchmark.zip
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/extensions/benchmark/options.html b/chrome/common/extensions/docs/examples/extensions/benchmark/options.html
index 24adc77..6db31d2 100644
--- a/chrome/common/extensions/docs/examples/extensions/benchmark/options.html
+++ b/chrome/common/extensions/docs/examples/extensions/benchmark/options.html
@@ -36,9 +36,9 @@ div#header {
position: relative;
overflow: hidden;
background: #5296de;
- -webkit-background-size: 100%;
+ background-size: 100%;
border: 1px solid #3a75bd;
- -webkit-border-radius: 6px;
+ border-radius: 6px;
color: white;
text-shadow: 0 0 2px black;
}
diff --git a/chrome/common/extensions/docs/examples/extensions/buildbot.zip b/chrome/common/extensions/docs/examples/extensions/buildbot.zip
index d7eb8c4..9e7ad86 100644
--- a/chrome/common/extensions/docs/examples/extensions/buildbot.zip
+++ b/chrome/common/extensions/docs/examples/extensions/buildbot.zip
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/extensions/buildbot/bg.html b/chrome/common/extensions/docs/examples/extensions/buildbot/bg.html
index 39dd344..dda276e 100644
--- a/chrome/common/extensions/docs/examples/extensions/buildbot/bg.html
+++ b/chrome/common/extensions/docs/examples/extensions/buildbot/bg.html
@@ -49,9 +49,14 @@ function requestURL(url, callback) {
try {
xhr.onreadystatechange = function(state) {
if (xhr.readyState == 4) {
- var text = xhr.responseText;
- //console.log(text);
- callback(text);
+ if (xhr.status == 200) {
+ var text = xhr.responseText;
+ //console.log(text);
+ callback(text);
+ } else {
+ chrome.browserAction.setBadgeText({text:"?"});
+ chrome.browserAction.setBadgeBackgroundColor({color:[0,0,255,255]});
+ }
}
}
diff --git a/chrome/common/extensions/docs/examples/extensions/buildbot/manifest.json b/chrome/common/extensions/docs/examples/extensions/buildbot/manifest.json
index 1acb250..baeca6d 100644
--- a/chrome/common/extensions/docs/examples/extensions/buildbot/manifest.json
+++ b/chrome/common/extensions/docs/examples/extensions/buildbot/manifest.json
@@ -1,6 +1,6 @@
{
"name": "Chromium Buildbot Monitor",
- "version": "0.7.5",
+ "version": "0.7.6",
"description": "Displays the status of the Chromium buildbot in the toolbar. Click to see more detailed status in a popup.",
"icons": { "128": "icon.png" },
"background_page": "bg.html",
diff --git a/chrome/common/extensions/docs/examples/extensions/buildbot/popup.html b/chrome/common/extensions/docs/examples/extensions/buildbot/popup.html
index 3a66636..f89511a 100644
--- a/chrome/common/extensions/docs/examples/extensions/buildbot/popup.html
+++ b/chrome/common/extensions/docs/examples/extensions/buildbot/popup.html
@@ -17,7 +17,11 @@ function updateBotList(text) {
}
var data;
try {
- data = JSON.parse(results[1]);
+ // The build bot returns invalid JSON. Namely it uses single
+ // quotes and includes commas in some invalid locations. We have to
+ // run some regexps across the text to fix it up.
+ var jsonString = results[1].replace(/'/g, '"').replace(/},]/g,'}]');
+ data = JSON.parse(jsonString);
} catch (e) {
console.dir(e);
console.log(text);
@@ -104,9 +108,13 @@ function requestURL(url, callback) {
try {
xhr.onreadystatechange = function(state) {
if (xhr.readyState == 4) {
- var text = xhr.responseText;
- //console.log(text);
- callback(text);
+ if (xhr.status == 200) {
+ var text = xhr.responseText;
+ //console.log(text);
+ callback(text);
+ } else {
+ bots.innerText = "Error.";
+ }
}
}
@@ -147,7 +155,7 @@ body {
#links {
background-color: #efefef;
border: 1px solid #cccccc;
- -webkit-border-radius: 5px;
+ border-radius: 5px;
margin-top: 1px;
padding: 3px;
white-space: nowrap;
@@ -175,7 +183,7 @@ body.small .bot {
.bot {
cursor: pointer;
- -webkit-border-radius: 5px;
+ border-radius: 5px;
margin-top: 1px;
padding: 3px;
white-space: nowrap;
diff --git a/chrome/common/extensions/docs/examples/extensions/chrome_search.zip b/chrome/common/extensions/docs/examples/extensions/chrome_search.zip
index d0ad166..a38e561 100644
--- a/chrome/common/extensions/docs/examples/extensions/chrome_search.zip
+++ b/chrome/common/extensions/docs/examples/extensions/chrome_search.zip
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/extensions/chrome_search/manifest.json b/chrome/common/extensions/docs/examples/extensions/chrome_search/manifest.json
index 54de17c..3254391 100644
--- a/chrome/common/extensions/docs/examples/extensions/chrome_search/manifest.json
+++ b/chrome/common/extensions/docs/examples/extensions/chrome_search/manifest.json
@@ -1,9 +1,9 @@
{
"background_page": "background.html",
"description": "Add support to the omnibox to search the Chromium source code.",
+ "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRx0y4f/CuomPPeGxcVMo7yfYZ1apxD+9e3ItNtPRBi8WMmzG0xhjnqvm03LTfTljbzA1L93s31HkjS5Bd12qM8SSZxOOizsZveK1tdpX0QelikSUaz1wwIyjatoC/jJy7vuuk0j5kPeLkNAhYGJTqN3H/Pqt0lFF1VFX4+fCEvQIDAQAB",
"name": "Chromium Search",
"omnibox": { "keyword" : "src" },
"permissions": [ "tabs", "http://www.google.com/" ],
- "version": "5",
- "minimum_chrome_version": "9"
+ "version": "4"
}
diff --git a/chrome/common/extensions/docs/examples/extensions/imageinfo.zip b/chrome/common/extensions/docs/examples/extensions/imageinfo.zip
index 9ab6603..dbce95b 100644
--- a/chrome/common/extensions/docs/examples/extensions/imageinfo.zip
+++ b/chrome/common/extensions/docs/examples/extensions/imageinfo.zip
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/tutorials/getstarted.zip b/chrome/common/extensions/docs/examples/tutorials/getstarted.zip
index 54083ae..268cc5d 100644
--- a/chrome/common/extensions/docs/examples/tutorials/getstarted.zip
+++ b/chrome/common/extensions/docs/examples/tutorials/getstarted.zip
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/tutorials/getstarted/getstarted.zip b/chrome/common/extensions/docs/examples/tutorials/getstarted/getstarted.zip
new file mode 100644
index 0000000..37deb7f
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/tutorials/getstarted/getstarted.zip
Binary files differ
diff --git a/chrome/common/extensions/docs/experimental.clipboard.html b/chrome/common/extensions/docs/experimental.clipboard.html
index 24287e0..4852c75 100644
--- a/chrome/common/extensions/docs/experimental.clipboard.html
+++ b/chrome/common/extensions/docs/experimental.clipboard.html
@@ -966,7 +966,7 @@ generally indicates the tab is going away.
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/experimental.contextMenus.html b/chrome/common/extensions/docs/experimental.contextMenus.html
index aa7a362..5f246fd 100644
--- a/chrome/common/extensions/docs/experimental.contextMenus.html
+++ b/chrome/common/extensions/docs/experimental.contextMenus.html
@@ -480,7 +480,7 @@ You can read all about it at its new home:
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/experimental.cookies.html b/chrome/common/extensions/docs/experimental.cookies.html
index 5fdcdcc..b179e08 100644
--- a/chrome/common/extensions/docs/experimental.cookies.html
+++ b/chrome/common/extensions/docs/experimental.cookies.html
@@ -480,7 +480,7 @@ You can read all about it at its new home:
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/experimental.history.html b/chrome/common/extensions/docs/experimental.history.html
index 0e45ec7..b839162 100644
--- a/chrome/common/extensions/docs/experimental.history.html
+++ b/chrome/common/extensions/docs/experimental.history.html
@@ -480,7 +480,7 @@ You can read all about it at its new home:
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/experimental.html b/chrome/common/extensions/docs/experimental.html
index 1c9ebe1..fd600a2 100644
--- a/chrome/common/extensions/docs/experimental.html
+++ b/chrome/common/extensions/docs/experimental.html
@@ -547,7 +547,7 @@ For information on the standard APIs that extensions can use, see
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/experimental.idle.html b/chrome/common/extensions/docs/experimental.idle.html
index 6d1ae19..6f709ae 100644
--- a/chrome/common/extensions/docs/experimental.idle.html
+++ b/chrome/common/extensions/docs/experimental.idle.html
@@ -480,7 +480,7 @@ You can read all about it at its new home:
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/experimental.infobars.html b/chrome/common/extensions/docs/experimental.infobars.html
index f542b7a..59e642d 100644
--- a/chrome/common/extensions/docs/experimental.infobars.html
+++ b/chrome/common/extensions/docs/experimental.infobars.html
@@ -800,7 +800,7 @@ For example:
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/experimental.processes.html b/chrome/common/extensions/docs/experimental.processes.html
index f2a289e..a41a1c6 100644
--- a/chrome/common/extensions/docs/experimental.processes.html
+++ b/chrome/common/extensions/docs/experimental.processes.html
@@ -1107,7 +1107,7 @@ http://src.chromium.org/viewvc/chrome/trunk/src/chrome/test/data/extensions/api_
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/experimental.proxy.html b/chrome/common/extensions/docs/experimental.proxy.html
index 07c2ed9..a13ce9e 100644
--- a/chrome/common/extensions/docs/experimental.proxy.html
+++ b/chrome/common/extensions/docs/experimental.proxy.html
@@ -1314,7 +1314,7 @@
</div><div>
<div>
<dt>
- <var>autoDetect</var>
+ <var>pacScript</var>
<em>
<!-- TYPE -->
@@ -1323,15 +1323,15 @@
<span class="optional">optional</span>
<span class="enum" style="display: none; ">enumerated</span>
<span id="typeTemplate">
- <span style="display: none; ">
- <a> Type</a>
- </span>
<span>
- <span style="display: none; ">
+ <a href="experimental.proxy.html#type-PacScript">PacScript</a>
+ </span>
+ <span style="display: none; ">
+ <span>
array of <span><span></span></span>
</span>
- <span>boolean</span>
- <span style="display: none; "></span>
+ <span>paramType</span>
+ <span></span>
</span>
</span>
)
@@ -1342,7 +1342,7 @@
<dd class="todo" style="display: none; ">
Undocumented.
</dd>
- <dd>True if the proxy settings sbould be detected automatically.</dd>
+ <dd>The proxy auto-config (PAC) script for this configuration.</dd>
<dd style="display: none; ">
This parameter was added in version
<b><span></span></b>.
@@ -1372,24 +1372,24 @@
</div><div>
<div>
<dt>
- <var>pacScript</var>
+ <var>mode</var>
<em>
<!-- TYPE -->
<div style="display:inline">
(
- <span class="optional">optional</span>
- <span class="enum" style="display: none; ">enumerated</span>
+ <span class="optional" style="display: none; ">optional</span>
+ <span class="enum">enumerated</span>
<span id="typeTemplate">
- <span>
- <a href="experimental.proxy.html#type-PacScript">PacScript</a>
- </span>
<span style="display: none; ">
- <span>
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
array of <span><span></span></span>
</span>
- <span>paramType</span>
- <span></span>
+ <span>string</span>
+ <span>["direct", "auto_detect", "pac_script", "fixed_servers", "system"]</span>
</span>
</span>
)
@@ -1400,7 +1400,7 @@
<dd class="todo" style="display: none; ">
Undocumented.
</dd>
- <dd>The proxy auto-config (PAC) script for this configuration.</dd>
+ <dd>'direct' = Never use a proxy<br>'auto_detect' = Auto detect proxy settings<br>'pac_script' = Use specified PAC script<br>'fixed_servers' = Manually specify proxy servers<br>'system' = Use system proxy settings</dd>
<dd style="display: none; ">
This parameter was added in version
<b><span></span></b>.
@@ -1455,7 +1455,7 @@
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/experimental.sidebar.html b/chrome/common/extensions/docs/experimental.sidebar.html
index 148de03..727bf89 100644
--- a/chrome/common/extensions/docs/experimental.sidebar.html
+++ b/chrome/common/extensions/docs/experimental.sidebar.html
@@ -2583,7 +2583,7 @@
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/experimental.webNavigation.html b/chrome/common/extensions/docs/experimental.webNavigation.html
index 52a04af..237ee23 100644
--- a/chrome/common/extensions/docs/experimental.webNavigation.html
+++ b/chrome/common/extensions/docs/experimental.webNavigation.html
@@ -2555,7 +2555,7 @@
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/experimental.webRequest.html b/chrome/common/extensions/docs/experimental.webRequest.html
index 71769af..14346ff 100644
--- a/chrome/common/extensions/docs/experimental.webRequest.html
+++ b/chrome/common/extensions/docs/experimental.webRequest.html
@@ -2493,7 +2493,7 @@
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/extension.html b/chrome/common/extensions/docs/extension.html
index a0e11fd..e7bb9e7 100644
--- a/chrome/common/extensions/docs/extension.html
+++ b/chrome/common/extensions/docs/extension.html
@@ -3556,7 +3556,7 @@ For details, see
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/external_extensions.html b/chrome/common/extensions/docs/external_extensions.html
index 0ee2ed5..39c1540 100644
--- a/chrome/common/extensions/docs/external_extensions.html
+++ b/chrome/common/extensions/docs/external_extensions.html
@@ -768,7 +768,7 @@ through the UI, and then uninstalling it. </p>
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/faq.html b/chrome/common/extensions/docs/faq.html
index 0e17982..66cc1b4 100644
--- a/chrome/common/extensions/docs/faq.html
+++ b/chrome/common/extensions/docs/faq.html
@@ -872,7 +872,7 @@ win,stable,#.#.###.#,#.#.###.#</pre>
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/getstarted.html b/chrome/common/extensions/docs/getstarted.html
index 3dafe3c..d7e94c8 100644
--- a/chrome/common/extensions/docs/getstarted.html
+++ b/chrome/common/extensions/docs/getstarted.html
@@ -376,6 +376,7 @@ to the toolbar of Google Chrome.
by clicking the wrench icon
<img src="images/toolsmenu.gif" width="29" height="29" alt="" style="margin-top:0">
and choosing <b>Tools &gt; Extensions</b>.
+ (On Mac, use <b>Window &gt; Extensions</b>.)
</li>
<li>
@@ -655,7 +656,7 @@ If you don't feel like reading, try these:
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/history.html b/chrome/common/extensions/docs/history.html
index e6be466..ce1c49e 100644
--- a/chrome/common/extensions/docs/history.html
+++ b/chrome/common/extensions/docs/history.html
@@ -3150,7 +3150,7 @@ For other examples and for help in viewing the source code, see
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/hosting.html b/chrome/common/extensions/docs/hosting.html
index 0a688fb..e852619 100644
--- a/chrome/common/extensions/docs/hosting.html
+++ b/chrome/common/extensions/docs/hosting.html
@@ -560,7 +560,7 @@ or try hosting the <code>.crx</code> file at another server.
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/i18n-messages.html b/chrome/common/extensions/docs/i18n-messages.html
index 3c85b6b..cf07efd 100644
--- a/chrome/common/extensions/docs/i18n-messages.html
+++ b/chrome/common/extensions/docs/i18n-messages.html
@@ -814,7 +814,7 @@ because its value is obvious from the "content" field.
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/i18n.html b/chrome/common/extensions/docs/i18n.html
index d5e3bb9..39d0f83 100644
--- a/chrome/common/extensions/docs/i18n.html
+++ b/chrome/common/extensions/docs/i18n.html
@@ -1421,7 +1421,7 @@ For details on calling <code>getAcceptLanguages()</code>, see the
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/idle.html b/chrome/common/extensions/docs/idle.html
index 1ab1b64..6b3aa54 100644
--- a/chrome/common/extensions/docs/idle.html
+++ b/chrome/common/extensions/docs/idle.html
@@ -713,7 +713,7 @@ For example:
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/images/perms-hw1.png b/chrome/common/extensions/docs/images/perms-hw1.png
index 224bd2d..eb6a79e 100644
--- a/chrome/common/extensions/docs/images/perms-hw1.png
+++ b/chrome/common/extensions/docs/images/perms-hw1.png
Binary files differ
diff --git a/chrome/common/extensions/docs/images/perms-hw2.png b/chrome/common/extensions/docs/images/perms-hw2.png
index 644a276..8fd5c47 100644
--- a/chrome/common/extensions/docs/images/perms-hw2.png
+++ b/chrome/common/extensions/docs/images/perms-hw2.png
Binary files differ
diff --git a/chrome/common/extensions/docs/index.html b/chrome/common/extensions/docs/index.html
index 54cd32f..7e89cfc 100644
--- a/chrome/common/extensions/docs/index.html
+++ b/chrome/common/extensions/docs/index.html
@@ -582,7 +582,7 @@ For more information, see the
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/management.html b/chrome/common/extensions/docs/management.html
index 3bb1d52..7efee0e 100644
--- a/chrome/common/extensions/docs/management.html
+++ b/chrome/common/extensions/docs/management.html
@@ -384,7 +384,7 @@ For example:</p>
<div class="description">
<p class="todo" style="display: none; ">Undocumented.</p>
- <p>Return information about the installed extension with the given ID.</p>
+ <p>Return information about the installed extension or app that has the given ID.</p>
<!-- PARAMETERS -->
<h4>Parameters</h4>
@@ -2661,7 +2661,7 @@ For example:</p>
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/manifest.html b/chrome/common/extensions/docs/manifest.html
index 658290f..c043355 100644
--- a/chrome/common/extensions/docs/manifest.html
+++ b/chrome/common/extensions/docs/manifest.html
@@ -441,9 +441,8 @@ see <a href="i18n.html">Internationalization</a> for details.
The URL of the homepage for this extension. The extensions management page (chrome://extensions)
will contain a link to this URL. This field is particularly useful if you
<a href="hosting.html">host the extension on your own site</a>. If you distribute your
-extension using the <a href="https://chrome.google.com/extensions">Extensions Gallery</a>,
-the homepage URL defaults to the extension's own gallery page.
-<!-- PENDING: check whether the same is true of the store -->
+extension using the <a href="https://chrome.google.com/extensions">Extensions Gallery</a> or <a href="https://chrome.google.com/webstore">Chrome Web Store</a>,
+the homepage URL defaults to the extension's own page.
</p>
<h3 id="icons">icons</h3>
@@ -950,7 +949,7 @@ For more information, see
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/match_patterns.html b/chrome/common/extensions/docs/match_patterns.html
index ddbc56b..c9aa23c 100644
--- a/chrome/common/extensions/docs/match_patterns.html
+++ b/chrome/common/extensions/docs/match_patterns.html
@@ -702,7 +702,7 @@ Here are some examples of <em>invalid</em> pattern matches:
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/messaging.html b/chrome/common/extensions/docs/messaging.html
index 19e683d..4d7d884 100644
--- a/chrome/common/extensions/docs/messaging.html
+++ b/chrome/common/extensions/docs/messaging.html
@@ -768,7 +768,7 @@ For more examples and for help in viewing the source code, see
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/notifications.html b/chrome/common/extensions/docs/notifications.html
index 82c5e07..3afbd73 100644
--- a/chrome/common/extensions/docs/notifications.html
+++ b/chrome/common/extensions/docs/notifications.html
@@ -609,7 +609,7 @@ see the <a href="http://dev.chromium.org/developers/design-documents/desktop-not
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/npapi.html b/chrome/common/extensions/docs/npapi.html
index 8aad2ea..904bff2 100644
--- a/chrome/common/extensions/docs/npapi.html
+++ b/chrome/common/extensions/docs/npapi.html
@@ -567,7 +567,7 @@ avoid making your NPAPI plugin public whenever possible.
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/omnibox.html b/chrome/common/extensions/docs/omnibox.html
index 6f7afa7..24fad5e 100644
--- a/chrome/common/extensions/docs/omnibox.html
+++ b/chrome/common/extensions/docs/omnibox.html
@@ -1217,7 +1217,7 @@ You can find samples of this API on the
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/options.html b/chrome/common/extensions/docs/options.html
index 982032f..701630a 100644
--- a/chrome/common/extensions/docs/options.html
+++ b/chrome/common/extensions/docs/options.html
@@ -558,7 +558,7 @@ Favorite Color:
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/override.html b/chrome/common/extensions/docs/override.html
index bfa7e7d..6d03561 100644
--- a/chrome/common/extensions/docs/override.html
+++ b/chrome/common/extensions/docs/override.html
@@ -663,7 +663,7 @@ For other examples and for help in viewing the source code, see
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/overview.html b/chrome/common/extensions/docs/overview.html
index 49e7d8c..2d5760f 100644
--- a/chrome/common/extensions/docs/overview.html
+++ b/chrome/common/extensions/docs/overview.html
@@ -937,7 +937,7 @@ Here are some ideas for where to go next:
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/packaging.html b/chrome/common/extensions/docs/packaging.html
index ccfa542..4939c6c 100644
--- a/chrome/common/extensions/docs/packaging.html
+++ b/chrome/common/extensions/docs/packaging.html
@@ -649,7 +649,7 @@ to create <code>.crx</code> files, see <a href="crx.html">CRX package format</a>
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/pageAction.html b/chrome/common/extensions/docs/pageAction.html
index 36d96af..b086ab8 100644
--- a/chrome/common/extensions/docs/pageAction.html
+++ b/chrome/common/extensions/docs/pageAction.html
@@ -427,6 +427,15 @@ follow these guidelines:</p>
for features that make sense
for most pages.
Use <a href="browserAction.html">browser actions</a> instead.
+ </li><li><b>Do</b> use icons
+ that are slightly lighter weight
+ than <a href="browserAction.html#icon">browser action icons</a>.
+ Most icons that Chrome displays
+ in the location bar
+ are smaller than 19 pixels.
+ If the edge pixels are used,
+ they are usually only used
+ for a faint shadow.
</li><li><b>Don't</b> constantly animate your icon.
That's just annoying.
</li></ul>
@@ -1655,7 +1664,7 @@ For other examples and for help in viewing the source code, see
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/permission_warnings.html b/chrome/common/extensions/docs/permission_warnings.html
index eb062e3..1c6ed92 100644
--- a/chrome/common/extensions/docs/permission_warnings.html
+++ b/chrome/common/extensions/docs/permission_warnings.html
@@ -326,21 +326,9 @@
<div id="static"><div id="pageData-name" class="pageData">Permission Warnings</div>
<div id="pageData-showTOC" class="pageData">true</div>
-<!--
-NOTE: When this doc is updated, the online help should also be updated:
-http://www.google.com/support/chrome/bin/answer.py?hl=en&answer=186213
-
-We should periodically look at
-http://src.chromium.org/viewvc/chrome/trunk/src/chrome/app/generated_resources.grd?view=markup
-to make sure that we're covering all messages. Search for
-IDS_EXTENSION_PROMPT_WARNING
-(e.g. IDS_EXTENSION_PROMPT_WARNING_BROWSING_HISTORY).
--->
-
<p>
To use most chrome.* APIs and extension capabilities,
-your extension must declare its intent in the
-<a href="manifest.html">manifest</a>,
+your extension must declare its intent in the manifest,
often in the "permissions" field.
Some of these declarations
result in a warning when
@@ -364,7 +352,7 @@ Here's a typical dialog
that a user might see when installing an extension:
</p>
-<img src="images/perms-hw1.png" width="410" height="193" alt="Permission warning: 'It can access: Your data on api.flickr.com'">
+<img src="images/perms-hw1.png" width="387" height="162" alt="Permission warning: 'This extension can access: Your data on api.flickr.com'">
<p>
The warning about access to data on api.flickr.com
@@ -415,7 +403,7 @@ Clicking the Re-enable button
brings up the following warning:
</p>
-<img src="images/perms-hw2.png" width="412" height="220" alt="Permission warning: 'It can access: Your data on api.flickr.com and flickr.com; Your browsing history'">
+<img src="images/perms-hw2.png" width="387" height="190" alt="Permission warning: 'This extension can access: Your data on api.flickr.com and flickr.com; Your browsing history'">
<h2 id="warnings"> Warnings and their triggers </h2>
@@ -426,7 +414,8 @@ results in the seemingly unrelated warning
that the extension can access your browsing history.
The reason for the warning is that
although the <code>chrome.tabs</code> API
-might be used only to open new tabs,
+might be used only to open new tabs
+(<a href="tabs.html#method-create"><code>chrome.tabs.create()</code></a>),
it can also be used to see the URL that's associated
with every newly opened tab
(using their <a href="tabs.html#type-Tab">Tab</a> objects).
@@ -436,14 +425,13 @@ with every newly opened tab
<b>Note:</b>
As of Google Chrome 7,
you no longer need to specify the "tabs" permission
-just to call <code>chrome.tabs.create()</code>
-or <code>chrome.tabs.update()</code>.
+just to call <code>chrome.tabs.create()</code>.
</p>
<p>
The following table lists the warning messages
that users can see,
-along with the manifest entries
+along with the <a href="manifest.html">manifest</a> entries
that trigger them.
</p>
@@ -455,7 +443,7 @@ that trigger them.
<tr>
<td style="font-weight:bold">
- <!-- IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS -->
+ <!-- IDS_EXTENSION_PROMPT2_WARNING_FULL_ACCESS -->
All data on your computer and the websites you visit
</td>
<td>
@@ -469,7 +457,7 @@ that trigger them.
<tr>
<td style="font-weight:bold">
- <!-- IDS_EXTENSION_PROMPT_WARNING_BOOKMARKS -->
+ <!-- IDS_EXTENSION_PROMPT2_WARNING_BOOKMARKS -->
Your bookmarks
</td>
<td>
@@ -483,7 +471,7 @@ that trigger them.
<tr>
<td style="font-weight:bold">
- <!-- IDS_EXTENSION_PROMPT_WARNING_BROWSING_HISTORY -->
+ <!-- IDS_EXTENSION_PROMPT2_WARNING_BROWSING_HISTORY -->
Your browsing history
</td>
<td>
@@ -510,7 +498,7 @@ that trigger them.
<tr>
<td style="font-weight:bold">
- <!-- IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS -->
+ <!-- IDS_EXTENSION_PROMPT2_WARNING_ALL_HOSTS -->
Your data on all websites
</td>
<td>
@@ -543,8 +531,8 @@ that trigger them.
</tr>
<tr>
<td style="font-weight:bold">
- <!-- IDS_EXTENSION_PROMPT_WARNING_?_HOST -->
- <!-- IDS_EXTENSION_PROMPT_WARNING_4_OR_MORE_HOSTS -->
+ <!-- IDS_EXTENSION_PROMPT2_WARNING_?_HOST -->
+ <!-- IDS_EXTENSION_PROMPT2_WARNING_4_OR_MORE_HOSTS -->
Your data on <em>{list of websites}</em>
</td>
<td>
@@ -577,29 +565,7 @@ that trigger them.
<tr>
<td style="font-weight:bold">
- <!-- IDS_EXTENSION_PROMPT_WARNING_MANAGEMENT -->
- Your list of installed apps, extensions, and themes
- <br>
- <span style="font-weight:normal; font-style:italic">or</span>
- <br>
- Manage themes, extensions, and apps
-
- <!-- PENDING: remove "Manage...apps" alternative message
- once the fix is out on stable channel -->
- <!-- See http://crbug.com/67859 -->
- </td>
- <td>
- "management" permission
- </td>
- <td>
- The "management" permission is required by the
- <a href="management.html"><code>chrome.management</code></a> module.
- </td>
-</tr>
-
-<tr>
- <td style="font-weight:bold">
- <!-- IDS_EXTENSION_PROMPT_WARNING_GEOLOCATION -->
+ <!-- IDS_EXTENSION_PROMPT2_WARNING_GEOLOCATION -->
Your physical location
</td>
<td>
@@ -825,7 +791,7 @@ by clicking the <b>chrome://extensions</b> page's
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/samples.html b/chrome/common/extensions/docs/samples.html
index f57fa01..85ae945 100644
--- a/chrome/common/extensions/docs/samples.html
+++ b/chrome/common/extensions/docs/samples.html
@@ -303,7 +303,7 @@
<!-- STATIC CONTENT PLACEHOLDER -->
<div id="static"><link rel="stylesheet" href="css/samples.css">
-<script>var search_data = {"0262260daf0c8f7b28feff2ef23b05e7abf9d1e0":"A BROWSER ACTION WHICH CHANGES ITS ICON WHEN CLICKED. BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETICON","ea2894c41cb8e80a4433a3e6c5772dadce9be90d":"A BROWSER ACTION WITH A POPUP THAT CHANGES THE PAGE COLOR. BROWSER_ACTION POPUP TABS CHROME.TABS.EXECUTESCRIPT","ede3c47b7757245be42ec33fd5ca63df4b490066":"A BROWSER ACTION WITH NO ICON THAT MAKES THE PAGE RED BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.TABS.EXECUTESCRIPT","fbf0aa1a09a15ff8cc4fc7de4fd176d6c663d07a":"ACCEPTLANGUAGE RETURNS ACCEPT LANGUAGES OF THE BROWSER BROWSER_ACTION POPUP CHROME.I18N.GETACCEPTLANGUAGES CHROME.I18N.GETMESSAGE","9a6e4ec46997fb92b324974afa08a3d007e2537f":"ANIMATED PAGE ACTION THIS EXTENSION ADDS AN ANIMATED BROWSER ACTION TO THE TOOLBAR. BACKGROUND_PAGE PAGE_ACTION TABS CHROME.PAGEACTION.HIDE CHROME.PAGEACTION.ONCLICKED CHROME.PAGEACTION.SETICON CHROME.PAGEACTION.SETTITLE CHROME.PAGEACTION.SHOW CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONSELECTIONCHANGED","9747e3d6a3eab39bc7c17f11a80573c62d44c7e5":"BLANK NEW TAB PAGE CHROME_URL_OVERRIDES","903e7277139e1e6caec123d3319cab295d8d1b3a":"CHROME SOUNDS ENJOY A MORE MAGICAL AND IMMERSIVE EXPERIENCE WHEN BROWSING THE WEB USING THE POWER OF SOUND. BACKGROUND_PAGE BOOKMARKS OPTIONS_PAGE TABS CHROME.BOOKMARKS.ONCREATED CHROME.BOOKMARKS.ONMOVED CHROME.BOOKMARKS.ONREMOVED CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST CHROME.TABS.GET CHROME.TABS.ONATTACHED CHROME.TABS.ONCREATED CHROME.TABS.ONDETACHED CHROME.TABS.ONMOVED CHROME.TABS.ONREMOVED CHROME.TABS.ONSELECTIONCHANGED CHROME.TABS.ONUPDATED CHROME.WINDOWS.ONCREATED CHROME.WINDOWS.ONFOCUSCHANGED CHROME.WINDOWS.ONREMOVED","0e790e035a4a00b6f1def5ef9a7d7be1bce95ab5":"CHROMIUM BUILDBOT MONITOR DISPLAYS THE STATUS OF THE CHROMIUM BUILDBOT IN THE TOOLBAR. CLICK TO SEE MORE DETAILED STATUS IN A POPUP. BACKGROUND_PAGE BROWSER_ACTION NOTIFICATIONS OPTIONS_PAGE POPUP CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.BROWSERACTION.SETTITLE CHROME.EXTENSION.GETURL","ac31228200b41a87982e386cc90d3a6eee4ad885":"CHROMIUM SEARCH ADD SUPPORT TO THE OMNIBOX TO SEARCH THE CHROMIUM SOURCE CODE. BACKGROUND_PAGE TABS CHROME.OMNIBOX.ONINPUTCANCELLED CHROME.OMNIBOX.ONINPUTCHANGED CHROME.OMNIBOX.ONINPUTENTERED CHROME.OMNIBOX.ONINPUTSTARTED CHROME.OMNIBOX.SETDEFAULTSUGGESTION CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.UPDATE","7d5d6cf195bc25480256618e360aa38c6e6fba82":"CLD DISPLAYS THE LANGUAGE OF A TAB BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.SETBADGETEXT CHROME.TABS.DETECTLANGUAGE CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONSELECTIONCHANGED CHROME.TABS.ONUPDATED","5d81304a17cf7ac2887484f730fbd2b01e51e166":"CONTEXT MENUS SAMPLE SHOWS SOME OF THE FEATURES OF THE CONTEXT MENUS API BACKGROUND_PAGE CONTEXTMENUS CHROME.CONTEXTMENUS.CREATE","4daa6becd0899a54776d9cf7f09613ed1a9f4d77":"COOKIE API TEST EXTENSION TESTING COOKIE API BACKGROUND_PAGE BROWSER_ACTION COOKIES TABS CHROME.BROWSERACTION.ONCLICKED CHROME.COOKIES.GET CHROME.COOKIES.GETALL CHROME.COOKIES.ONCHANGED CHROME.COOKIES.REMOVE CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.UPDATE CHROME.WINDOWS.GET CHROME.WINDOWS.GETALL","6871d09f4a96bf9d4b6cc724d00e909cee0f3902":"CROSS-DOMAIN XMLHTTPREQUEST FROM A CONTENT SCRIPT DEMONSTRATES A METHOD TO MAKE A CROSS-DOMAIN XMLHTTPREQUEST FETCH FROM A CONTENT SCRIPT. THIS EXTENSION FETCHES THE CURRENT TRENDING TOPICS FROM TWITTER AND INSERTS THEM IN AN OVERLAY AT THE TOP OF GOOGLE NEWS. VISIT HTTP://NEWS.GOOGLE.COM TO TEST THIS EXTENSION. BACKGROUND_PAGE CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST","028eb5364924344029bcbe1d527f132fc72b34e5":"EMAIL THIS PAGE (BY GOOGLE) THIS EXTENSION ADDS AN EMAIL BUTTON TO THE TOOLBAR WHICH ALLOWS YOU TO EMAIL THE PAGE LINK USING YOUR DEFAULT MAIL CLIENT OR GMAIL. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE TABS CHROME.BROWSERACTION.ONCLICKED CHROME.EXTENSION.CONNECT CHROME.EXTENSION.ONCONNECT CHROME.TABS.CREATE CHROME.TABS.EXECUTESCRIPT CHROME.TABS.UPDATE","763a08e9b06595d785568a8d392b95a2f3700258":"EVENT TRACKING WITH GOOGLE ANALYTICS A SAMPLE EXTENSION WHICH USES GOOGLE ANALYTICS TO TRACK USAGE. BACKGROUND_PAGE BROWSER_ACTION POPUP","e3df888a89e35bdeb9c8bc8d03be5e1851b97c68":"EXTENSION DOCS SEARCH SEARCH THE CHROME EXTENSIONS DOCUMENTATION. TO USE, TYPE CRDOC PLUS A SEARCH TERM INTO THE OMNIBOX. BACKGROUND_PAGE TABS CHROME.OMNIBOX.ONINPUTCHANGED CHROME.OMNIBOX.ONINPUTENTERED CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.ONREMOVED CHROME.TABS.UPDATE","8b0dd31216235941bdd8eb33fda915ef5cf79a82":"GOOGLE CALENDAR CHECKER (BY GOOGLE) QUICKLY SEE THE TIME UNTIL YOUR NEXT MEETING FROM ANY OF YOUR CALENDARS. CLICK ON THE BUTTON TO BE TAKEN TO YOUR CALENDAR. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.BROWSERACTION.SETICON CHROME.BROWSERACTION.SETTITLE CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST CHROME.I18N.GETMESSAGE CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.ONUPDATED CHROME.TABS.UPDATE","4e35caa9742fb82dbd628892d23a781614f6eff6":"GOOGLE DOCUMENT LIST VIEWER DEMONSTRATES HOW TO USE OAUTH TO CONNECT THE GOOGLE DOCUMENTS LIST DATA API. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE POPUP TABS CHROME.BROWSERACTION.SETBADGETEXT CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONUPDATED CHROME.TABS.REMOVE","bb57f7a0132cbeb36ad7e7bb0ab75c21704234ca":"GOOGLE MAIL CHECKER DISPLAYS THE NUMBER OF UNREAD MESSAGES IN YOUR GOOGLE MAIL INBOX. YOU CAN ALSO CLICK THE BUTTON TO OPEN YOUR INBOX. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.BROWSERACTION.SETICON CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.I18N.GETMESSAGE CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.ONUPDATED CHROME.TABS.UPDATE","1682e05ea9a1bde985123b04f6f8ac50a8a64033":"GOOGLE WAVE NOTIFIER FIND OUT WHEN YOU HAVE NEW WAVES AND PREVIEW THEM FAST. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE POPUP TABS CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONUPDATED CHROME.TABS.REMOVE","14b9651fda4e57b2a5914ba73a779812201b750a":"HELLO WORLD THE FIRST EXTENSION THAT I MADE. BROWSER_ACTION POPUP","2020d72f2577f53caf8e94e3dbac0fb849ceaa4d":"IDLE - SIMPLE EXAMPLE DEMONSTRATES THE IDLE API BACKGROUND_PAGE BROWSER_ACTION IDLE CHROME.BROWSERACTION.ONCLICKED CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.IDLE.ONSTATECHANGED CHROME.IDLE.QUERYSTATE","0ea1588bd07b20338fc21f725de1542a5fdf9726":"IGOOGLE NEW TAB PAGE CHROME_URL_OVERRIDES","646325c25f572a1d15edc73d057f821d847a4fbe":"IMAGEINFO GET IMAGE INFO FOR IMAGES, INCLUDING EXIF DATA BACKGROUND_PAGE CONTEXTMENUS TABS CHROME.CONTEXTMENUS.CREATE CHROME.TABS.GET CHROME.TABS.GETCURRENT CHROME.WINDOWS.CREATE CHROME.WINDOWS.UPDATE","ec97ec20ca2f095d081e39f1565fc12af09ef067":"MAPPY FINDS ADDRESSES IN THE WEB PAGE YOURE ON AND POPS UP A MAP WINDOW. BACKGROUND_PAGE PAGE_ACTION POPUP TABS CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.ONREQUEST CHROME.PAGEACTION.HIDE CHROME.PAGEACTION.SETTITLE CHROME.PAGEACTION.SHOW CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONSELECTIONCHANGED CHROME.TABS.ONUPDATED CHROME.TABS.SENDREQUEST","b2f5f8a790e16f091a7e4e0a39b2d0a6d32e3a6d":"MERGE WINDOWS MERGES ALL OF THE BROWSERS WINDOWS INTO THE CURRENT WINDOW BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.MOVE CHROME.WINDOWS.GET CHROME.WINDOWS.GETALL CHROME.WINDOWS.GETCURRENT","51a83d2ba3a32e3ff1bdb624d4e18ccec4c4038e":"MESSAGE TIMER TIMES HOW LONG IT TAKES TO SEND A MESSAGE TO A CONTENT SCRIPT AND BACK. BROWSER_ACTION POPUP TABS CHROME.EXTENSION.ONCONNECT CHROME.EXTENSION.ONREQUEST CHROME.TABS.CONNECT CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.SENDREQUEST","4f6785ec4f937add6728615682dd37c9a42d9548":"MY BOOKMARKS A BROWSER ACTION WITH A POPUP DUMP OF ALL BOOKMARKS, INCLUDING SEARCH, ADD, EDIT AND DELETE. BOOKMARKS BROWSER_ACTION POPUP TABS CHROME.BOOKMARKS.CREATE CHROME.BOOKMARKS.GET CHROME.BOOKMARKS.GETTREE CHROME.BOOKMARKS.REMOVE CHROME.BOOKMARKS.UPDATE CHROME.TABS.CREATE","597015d3bcce3da693b02314afd607bec4f55291":"NEWS READER DISPLAYS THE FIRST 5 ITEMS FROM THE GOOGLE NEWS - TOP NEWS RSS FEED IN A POPUP. BROWSER_ACTION POPUP TABS CHROME.TABS.CREATE","6444e5c8ae112a6a433909c5e770669cd16e2e5f":"NEWS READER DISPLAYS THE FIRST 5 ITEMS FROM THE GOOGLE NEWS - TOP NEWS RSS FEED IN A POPUP. BROWSER_ACTION POPUP TABS CHROME.I18N.GETMESSAGE CHROME.TABS.CREATE","3aea027164cb9b732ba4a8c51cb93708891726ef":"NEWS READER (BY GOOGLE) DISPLAYS THE LATEST STORIES FROM GOOGLE NEWS IN A POPUP. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE POPUP TABS CHROME.EXTENSION.GETURL CHROME.I18N.GETMESSAGE CHROME.TABS.CREATE","f799e26ceef2367cf836f24bcb47df4398b0df58":"NOTIFICATION DEMO SHOWS OFF DESKTOP NOTIFICATIONS, WHICH ARE TOAST WINDOWS THAT POP UP ON THE DESKTOP. BACKGROUND_PAGE NOTIFICATIONS OPTIONS_PAGE TABS CHROME.TABS.CREATE","e787b322bddbc6289bb31b7d7550b1bf6456a80b":"OMNIBOX EXAMPLE TO USE, TYPE OMNIX PLUS A SEARCH TERM INTO THE OMNIBOX. BACKGROUND_PAGE CHROME.OMNIBOX.ONINPUTCHANGED CHROME.OMNIBOX.ONINPUTENTERED","8d0a50b57c26bb498be592e871001ffed91541b4":"PAGE ACTION BY CONTENT SHOWS A PAGE ACTION FOR HTML PAGES CONTAINING THE WORD SANDWICH BACKGROUND_PAGE PAGE_ACTION CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST CHROME.PAGEACTION.SHOW","80b86ccc6e8520660fa591caa565826f0ed1b12c":"PAGE ACTION BY URL SHOWS A PAGE ACTION FOR URLS WHICH HAVE THE LETTER G IN THEM. BACKGROUND_PAGE PAGE_ACTION TABS CHROME.PAGEACTION.SHOW CHROME.TABS.ONUPDATED","d74c3c18a1c1dd18b035149105a306f837c8823e":"PAGE BENCHMARKER CHROMIUM PAGE BENCHMARKER. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.BROWSERACTION.SETTITLE CHROME.EXTENSION.CONNECT CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.GETEXTENSIONTABS CHROME.EXTENSION.GETURL CHROME.EXTENSION.ONCONNECT CHROME.TABS.CREATE CHROME.TABS.EXECUTESCRIPT CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.GETSELECTED CHROME.TABS.REMOVE CHROME.TABS.UPDATE CHROME.WINDOWS.GET CHROME.WINDOWS.GETCURRENT","e6ae17ab4ccfd7e059c8c01f25760ca5d894c7fd":"PRINT THIS PAGE ADDS A PRINT BUTTON TO THE BROWSER. BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.TABS.UPDATE","beff6ecd9677dea0a7c648c5042165b48bb66f09":"PROCESS MONITOR ADDS A BROWSER ACTION THAT MONITORS RESOURCE USAGE OF ALL BROWSER PROCESSES. BROWSER_ACTION EXPERIMENTAL POPUP TABS CHROME.EXPERIMENTAL.PROCESSES.ONUPDATED","56a8d2ac24ca7bba78fd88ad57f43fc13c784497":"SAMPLE - OAUTH CONTACTS USES OAUTH TO CONNECT TO GOOGLES CONTACTS SERVICE AND DISPLAY A LIST OF YOUR CONTACTS. BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETICON CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONUPDATED CHROME.TABS.REMOVE","38f6e1e17756ede38b1364c7114a738ca717dcbb":"SANDWICHBAR SHOWS AN INFOBAR ON PAGES WHICH CONTAIN THE WORD SANDWICH BACKGROUND_PAGE EXPERIMENTAL CHROME.EXPERIMENTAL.INFOBARS.SHOW CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST","fc89b35755483af30b66cd72cefa34a43a3e8312":"SHOW TABS IN PROCESS ADDS A BROWSER ACTION SHOWING WHICH TABS SHARE THE CURRENT TABS PROCESS. BROWSER_ACTION EXPERIMENTAL POPUP TABS CHROME.EXPERIMENTAL.PROCESSES.GETPROCESSIDFORTAB CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.UPDATE CHROME.WINDOWS.GET CHROME.WINDOWS.GETALL CHROME.WINDOWS.GETCURRENT CHROME.WINDOWS.UPDATE","230463f2d5c3d4d0ca13c230e1f00f2aae0a8a64":"TAB INSPECTOR UTILITY FOR WORKING WITH THE EXTENSION TABS API BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.GETSELECTED CHROME.TABS.MOVE CHROME.TABS.ONATTACHED CHROME.TABS.ONCREATED CHROME.TABS.ONDETACHED CHROME.TABS.ONMOVED CHROME.TABS.ONREMOVED CHROME.TABS.ONSELECTIONCHANGED CHROME.TABS.ONUPDATED CHROME.TABS.REMOVE CHROME.TABS.UPDATE CHROME.WINDOWS.CREATE CHROME.WINDOWS.GET CHROME.WINDOWS.GETALL CHROME.WINDOWS.GETCURRENT CHROME.WINDOWS.GETLASTFOCUSED CHROME.WINDOWS.ONCREATED CHROME.WINDOWS.ONFOCUSCHANGED CHROME.WINDOWS.ONREMOVED CHROME.WINDOWS.REMOVE CHROME.WINDOWS.UPDATE","e1697cacebad05218798bf3e8a0f724517f0e8c3":"TEST SCREENSHOT EXTENSION DEMONSTRATE SCREENSHOT FUNCTIONALITY IN THE CHROME.TABS API. BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.EXTENSION.GETURL CHROME.EXTENSION.GETVIEWS CHROME.TABS.CAPTUREVISIBLETAB CHROME.TABS.CREATE CHROME.TABS.ONUPDATED","b3de91ab04b7d7a2670ca7ee9d740eb42cead0b6":"TYPED URL HISTORY READS YOUR HISTORY, AND SHOWS THE TOP TEN PAGES YOU GO TO BY TYPING THE URL. BROWSER_ACTION HISTORY TABS CHROME.HISTORY.GETVISITS CHROME.HISTORY.SEARCH CHROME.TABS.CREATE"}</script>
+<script>var search_data = {"0262260daf0c8f7b28feff2ef23b05e7abf9d1e0":"A BROWSER ACTION WHICH CHANGES ITS ICON WHEN CLICKED. BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETICON","ea2894c41cb8e80a4433a3e6c5772dadce9be90d":"A BROWSER ACTION WITH A POPUP THAT CHANGES THE PAGE COLOR. BROWSER_ACTION POPUP TABS CHROME.TABS.EXECUTESCRIPT","ede3c47b7757245be42ec33fd5ca63df4b490066":"A BROWSER ACTION WITH NO ICON THAT MAKES THE PAGE RED BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.TABS.EXECUTESCRIPT","fbf0aa1a09a15ff8cc4fc7de4fd176d6c663d07a":"ACCEPTLANGUAGE RETURNS ACCEPT LANGUAGES OF THE BROWSER BROWSER_ACTION POPUP CHROME.I18N.GETACCEPTLANGUAGES CHROME.I18N.GETMESSAGE","9a6e4ec46997fb92b324974afa08a3d007e2537f":"ANIMATED PAGE ACTION THIS EXTENSION ADDS AN ANIMATED BROWSER ACTION TO THE TOOLBAR. BACKGROUND_PAGE PAGE_ACTION TABS CHROME.PAGEACTION.HIDE CHROME.PAGEACTION.ONCLICKED CHROME.PAGEACTION.SETICON CHROME.PAGEACTION.SETTITLE CHROME.PAGEACTION.SHOW CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONSELECTIONCHANGED","a1f7cf79dd555b04fa8d603247a040e644996293":"APP LAUNCHER BROWSER_ACTION MANAGEMENT CHROME.EXTENSION.GETURL CHROME.MANAGEMENT.GET CHROME.MANAGEMENT.GETALL CHROME.MANAGEMENT.LAUNCHAPP CHROME.TABS.CREATE","9747e3d6a3eab39bc7c17f11a80573c62d44c7e5":"BLANK NEW TAB PAGE CHROME_URL_OVERRIDES","903e7277139e1e6caec123d3319cab295d8d1b3a":"CHROME SOUNDS ENJOY A MORE MAGICAL AND IMMERSIVE EXPERIENCE WHEN BROWSING THE WEB USING THE POWER OF SOUND. BACKGROUND_PAGE BOOKMARKS OPTIONS_PAGE TABS CHROME.BOOKMARKS.ONCREATED CHROME.BOOKMARKS.ONMOVED CHROME.BOOKMARKS.ONREMOVED CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST CHROME.TABS.GET CHROME.TABS.ONATTACHED CHROME.TABS.ONCREATED CHROME.TABS.ONDETACHED CHROME.TABS.ONMOVED CHROME.TABS.ONREMOVED CHROME.TABS.ONSELECTIONCHANGED CHROME.TABS.ONUPDATED CHROME.WINDOWS.ONCREATED CHROME.WINDOWS.ONFOCUSCHANGED CHROME.WINDOWS.ONREMOVED","0e790e035a4a00b6f1def5ef9a7d7be1bce95ab5":"CHROMIUM BUILDBOT MONITOR DISPLAYS THE STATUS OF THE CHROMIUM BUILDBOT IN THE TOOLBAR. CLICK TO SEE MORE DETAILED STATUS IN A POPUP. BACKGROUND_PAGE BROWSER_ACTION NOTIFICATIONS OPTIONS_PAGE POPUP CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.BROWSERACTION.SETTITLE CHROME.EXTENSION.GETURL","ac31228200b41a87982e386cc90d3a6eee4ad885":"CHROMIUM SEARCH ADD SUPPORT TO THE OMNIBOX TO SEARCH THE CHROMIUM SOURCE CODE. BACKGROUND_PAGE TABS CHROME.OMNIBOX.ONINPUTCANCELLED CHROME.OMNIBOX.ONINPUTCHANGED CHROME.OMNIBOX.ONINPUTENTERED CHROME.OMNIBOX.ONINPUTSTARTED CHROME.OMNIBOX.SETDEFAULTSUGGESTION CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.UPDATE","7d5d6cf195bc25480256618e360aa38c6e6fba82":"CLD DISPLAYS THE LANGUAGE OF A TAB BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.SETBADGETEXT CHROME.TABS.DETECTLANGUAGE CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONSELECTIONCHANGED CHROME.TABS.ONUPDATED","5d81304a17cf7ac2887484f730fbd2b01e51e166":"CONTEXT MENUS SAMPLE SHOWS SOME OF THE FEATURES OF THE CONTEXT MENUS API BACKGROUND_PAGE CONTEXTMENUS CHROME.CONTEXTMENUS.CREATE","4daa6becd0899a54776d9cf7f09613ed1a9f4d77":"COOKIE API TEST EXTENSION TESTING COOKIE API BACKGROUND_PAGE BROWSER_ACTION COOKIES TABS CHROME.BROWSERACTION.ONCLICKED CHROME.COOKIES.GET CHROME.COOKIES.GETALL CHROME.COOKIES.ONCHANGED CHROME.COOKIES.REMOVE CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.UPDATE CHROME.WINDOWS.GET CHROME.WINDOWS.GETALL","6871d09f4a96bf9d4b6cc724d00e909cee0f3902":"CROSS-DOMAIN XMLHTTPREQUEST FROM A CONTENT SCRIPT DEMONSTRATES A METHOD TO MAKE A CROSS-DOMAIN XMLHTTPREQUEST FETCH FROM A CONTENT SCRIPT. THIS EXTENSION FETCHES THE CURRENT TRENDING TOPICS FROM TWITTER AND INSERTS THEM IN AN OVERLAY AT THE TOP OF GOOGLE NEWS. VISIT HTTP://NEWS.GOOGLE.COM TO TEST THIS EXTENSION. BACKGROUND_PAGE CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST","028eb5364924344029bcbe1d527f132fc72b34e5":"EMAIL THIS PAGE (BY GOOGLE) THIS EXTENSION ADDS AN EMAIL BUTTON TO THE TOOLBAR WHICH ALLOWS YOU TO EMAIL THE PAGE LINK USING YOUR DEFAULT MAIL CLIENT OR GMAIL. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE TABS CHROME.BROWSERACTION.ONCLICKED CHROME.EXTENSION.CONNECT CHROME.EXTENSION.ONCONNECT CHROME.TABS.CREATE CHROME.TABS.EXECUTESCRIPT CHROME.TABS.UPDATE","763a08e9b06595d785568a8d392b95a2f3700258":"EVENT TRACKING WITH GOOGLE ANALYTICS A SAMPLE EXTENSION WHICH USES GOOGLE ANALYTICS TO TRACK USAGE. BACKGROUND_PAGE BROWSER_ACTION POPUP","e3df888a89e35bdeb9c8bc8d03be5e1851b97c68":"EXTENSION DOCS SEARCH SEARCH THE CHROME EXTENSIONS DOCUMENTATION. TO USE, TYPE CRDOC PLUS A SEARCH TERM INTO THE OMNIBOX. BACKGROUND_PAGE TABS CHROME.OMNIBOX.ONINPUTCHANGED CHROME.OMNIBOX.ONINPUTENTERED CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.ONREMOVED CHROME.TABS.UPDATE","8b0dd31216235941bdd8eb33fda915ef5cf79a82":"GOOGLE CALENDAR CHECKER (BY GOOGLE) QUICKLY SEE THE TIME UNTIL YOUR NEXT MEETING FROM ANY OF YOUR CALENDARS. CLICK ON THE BUTTON TO BE TAKEN TO YOUR CALENDAR. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.BROWSERACTION.SETICON CHROME.BROWSERACTION.SETTITLE CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST CHROME.I18N.GETMESSAGE CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.ONUPDATED CHROME.TABS.UPDATE","4e35caa9742fb82dbd628892d23a781614f6eff6":"GOOGLE DOCUMENT LIST VIEWER DEMONSTRATES HOW TO USE OAUTH TO CONNECT THE GOOGLE DOCUMENTS LIST DATA API. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE POPUP TABS CHROME.BROWSERACTION.SETBADGETEXT CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONUPDATED CHROME.TABS.REMOVE","bb57f7a0132cbeb36ad7e7bb0ab75c21704234ca":"GOOGLE MAIL CHECKER DISPLAYS THE NUMBER OF UNREAD MESSAGES IN YOUR GOOGLE MAIL INBOX. YOU CAN ALSO CLICK THE BUTTON TO OPEN YOUR INBOX. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.BROWSERACTION.SETICON CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.I18N.GETMESSAGE CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.ONUPDATED CHROME.TABS.UPDATE","1682e05ea9a1bde985123b04f6f8ac50a8a64033":"GOOGLE WAVE NOTIFIER FIND OUT WHEN YOU HAVE NEW WAVES AND PREVIEW THEM FAST. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE POPUP TABS CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONUPDATED CHROME.TABS.REMOVE","14b9651fda4e57b2a5914ba73a779812201b750a":"HELLO WORLD THE FIRST EXTENSION THAT I MADE. BROWSER_ACTION POPUP","2020d72f2577f53caf8e94e3dbac0fb849ceaa4d":"IDLE - SIMPLE EXAMPLE DEMONSTRATES THE IDLE API BACKGROUND_PAGE BROWSER_ACTION IDLE CHROME.BROWSERACTION.ONCLICKED CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.IDLE.ONSTATECHANGED CHROME.IDLE.QUERYSTATE","0ea1588bd07b20338fc21f725de1542a5fdf9726":"IGOOGLE NEW TAB PAGE CHROME_URL_OVERRIDES","646325c25f572a1d15edc73d057f821d847a4fbe":"IMAGEINFO GET IMAGE INFO FOR IMAGES, INCLUDING EXIF DATA BACKGROUND_PAGE CONTEXTMENUS TABS CHROME.CONTEXTMENUS.CREATE CHROME.TABS.GET CHROME.TABS.GETCURRENT CHROME.WINDOWS.CREATE CHROME.WINDOWS.UPDATE","ec97ec20ca2f095d081e39f1565fc12af09ef067":"MAPPY FINDS ADDRESSES IN THE WEB PAGE YOURE ON AND POPS UP A MAP WINDOW. BACKGROUND_PAGE PAGE_ACTION POPUP TABS CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.ONREQUEST CHROME.PAGEACTION.HIDE CHROME.PAGEACTION.SETTITLE CHROME.PAGEACTION.SHOW CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONSELECTIONCHANGED CHROME.TABS.ONUPDATED CHROME.TABS.SENDREQUEST","b2f5f8a790e16f091a7e4e0a39b2d0a6d32e3a6d":"MERGE WINDOWS MERGES ALL OF THE BROWSERS WINDOWS INTO THE CURRENT WINDOW BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.MOVE CHROME.WINDOWS.GET CHROME.WINDOWS.GETALL CHROME.WINDOWS.GETCURRENT","51a83d2ba3a32e3ff1bdb624d4e18ccec4c4038e":"MESSAGE TIMER TIMES HOW LONG IT TAKES TO SEND A MESSAGE TO A CONTENT SCRIPT AND BACK. BROWSER_ACTION POPUP TABS CHROME.EXTENSION.ONCONNECT CHROME.EXTENSION.ONREQUEST CHROME.TABS.CONNECT CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.SENDREQUEST","4f6785ec4f937add6728615682dd37c9a42d9548":"MY BOOKMARKS A BROWSER ACTION WITH A POPUP DUMP OF ALL BOOKMARKS, INCLUDING SEARCH, ADD, EDIT AND DELETE. BOOKMARKS BROWSER_ACTION POPUP TABS CHROME.BOOKMARKS.CREATE CHROME.BOOKMARKS.GET CHROME.BOOKMARKS.GETTREE CHROME.BOOKMARKS.REMOVE CHROME.BOOKMARKS.UPDATE CHROME.TABS.CREATE","597015d3bcce3da693b02314afd607bec4f55291":"NEWS READER DISPLAYS THE FIRST 5 ITEMS FROM THE GOOGLE NEWS - TOP NEWS RSS FEED IN A POPUP. BROWSER_ACTION POPUP TABS CHROME.TABS.CREATE","6444e5c8ae112a6a433909c5e770669cd16e2e5f":"NEWS READER DISPLAYS THE FIRST 5 ITEMS FROM THE GOOGLE NEWS - TOP NEWS RSS FEED IN A POPUP. BROWSER_ACTION POPUP TABS CHROME.I18N.GETMESSAGE CHROME.TABS.CREATE","3aea027164cb9b732ba4a8c51cb93708891726ef":"NEWS READER (BY GOOGLE) DISPLAYS THE LATEST STORIES FROM GOOGLE NEWS IN A POPUP. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE POPUP TABS CHROME.EXTENSION.GETURL CHROME.I18N.GETMESSAGE CHROME.TABS.CREATE","f799e26ceef2367cf836f24bcb47df4398b0df58":"NOTIFICATION DEMO SHOWS OFF DESKTOP NOTIFICATIONS, WHICH ARE TOAST WINDOWS THAT POP UP ON THE DESKTOP. BACKGROUND_PAGE NOTIFICATIONS OPTIONS_PAGE TABS CHROME.TABS.CREATE","e787b322bddbc6289bb31b7d7550b1bf6456a80b":"OMNIBOX EXAMPLE TO USE, TYPE OMNIX PLUS A SEARCH TERM INTO THE OMNIBOX. BACKGROUND_PAGE CHROME.OMNIBOX.ONINPUTCHANGED CHROME.OMNIBOX.ONINPUTENTERED","8d0a50b57c26bb498be592e871001ffed91541b4":"PAGE ACTION BY CONTENT SHOWS A PAGE ACTION FOR HTML PAGES CONTAINING THE WORD SANDWICH BACKGROUND_PAGE PAGE_ACTION CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST CHROME.PAGEACTION.SHOW","80b86ccc6e8520660fa591caa565826f0ed1b12c":"PAGE ACTION BY URL SHOWS A PAGE ACTION FOR URLS WHICH HAVE THE LETTER G IN THEM. BACKGROUND_PAGE PAGE_ACTION TABS CHROME.PAGEACTION.SHOW CHROME.TABS.ONUPDATED","d74c3c18a1c1dd18b035149105a306f837c8823e":"PAGE BENCHMARKER CHROMIUM PAGE BENCHMARKER. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.BROWSERACTION.SETTITLE CHROME.EXTENSION.CONNECT CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.GETEXTENSIONTABS CHROME.EXTENSION.GETURL CHROME.EXTENSION.ONCONNECT CHROME.TABS.CREATE CHROME.TABS.EXECUTESCRIPT CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.GETSELECTED CHROME.TABS.REMOVE CHROME.TABS.UPDATE CHROME.WINDOWS.GET CHROME.WINDOWS.GETCURRENT","e6ae17ab4ccfd7e059c8c01f25760ca5d894c7fd":"PRINT THIS PAGE ADDS A PRINT BUTTON TO THE BROWSER. BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.TABS.UPDATE","beff6ecd9677dea0a7c648c5042165b48bb66f09":"PROCESS MONITOR ADDS A BROWSER ACTION THAT MONITORS RESOURCE USAGE OF ALL BROWSER PROCESSES. BROWSER_ACTION EXPERIMENTAL POPUP TABS CHROME.EXPERIMENTAL.PROCESSES.ONUPDATED","56a8d2ac24ca7bba78fd88ad57f43fc13c784497":"SAMPLE - OAUTH CONTACTS USES OAUTH TO CONNECT TO GOOGLES CONTACTS SERVICE AND DISPLAY A LIST OF YOUR CONTACTS. BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETICON CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONUPDATED CHROME.TABS.REMOVE","38f6e1e17756ede38b1364c7114a738ca717dcbb":"SANDWICHBAR SHOWS AN INFOBAR ON PAGES WHICH CONTAIN THE WORD SANDWICH BACKGROUND_PAGE EXPERIMENTAL CHROME.EXPERIMENTAL.INFOBARS.SHOW CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST","fc89b35755483af30b66cd72cefa34a43a3e8312":"SHOW TABS IN PROCESS ADDS A BROWSER ACTION SHOWING WHICH TABS SHARE THE CURRENT TABS PROCESS. BROWSER_ACTION EXPERIMENTAL POPUP TABS CHROME.EXPERIMENTAL.PROCESSES.GETPROCESSIDFORTAB CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.UPDATE CHROME.WINDOWS.GET CHROME.WINDOWS.GETALL CHROME.WINDOWS.GETCURRENT CHROME.WINDOWS.UPDATE","230463f2d5c3d4d0ca13c230e1f00f2aae0a8a64":"TAB INSPECTOR UTILITY FOR WORKING WITH THE EXTENSION TABS API BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.GETSELECTED CHROME.TABS.MOVE CHROME.TABS.ONATTACHED CHROME.TABS.ONCREATED CHROME.TABS.ONDETACHED CHROME.TABS.ONMOVED CHROME.TABS.ONREMOVED CHROME.TABS.ONSELECTIONCHANGED CHROME.TABS.ONUPDATED CHROME.TABS.REMOVE CHROME.TABS.UPDATE CHROME.WINDOWS.CREATE CHROME.WINDOWS.GET CHROME.WINDOWS.GETALL CHROME.WINDOWS.GETCURRENT CHROME.WINDOWS.GETLASTFOCUSED CHROME.WINDOWS.ONCREATED CHROME.WINDOWS.ONFOCUSCHANGED CHROME.WINDOWS.ONREMOVED CHROME.WINDOWS.REMOVE CHROME.WINDOWS.UPDATE","e1697cacebad05218798bf3e8a0f724517f0e8c3":"TEST SCREENSHOT EXTENSION DEMONSTRATE SCREENSHOT FUNCTIONALITY IN THE CHROME.TABS API. BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.EXTENSION.GETURL CHROME.EXTENSION.GETVIEWS CHROME.TABS.CAPTUREVISIBLETAB CHROME.TABS.CREATE CHROME.TABS.ONUPDATED","b3de91ab04b7d7a2670ca7ee9d740eb42cead0b6":"TYPED URL HISTORY READS YOUR HISTORY, AND SHOWS THE TOP TEN PAGES YOU GO TO BY TYPING THE URL. BROWSER_ACTION HISTORY TABS CHROME.HISTORY.GETVISITS CHROME.HISTORY.SEARCH CHROME.TABS.CREATE"}</script>
<script src="js/sample_search.js"></script>
@@ -558,6 +558,51 @@
</ul>
</div>
<div><a href="examples/api/pageAction/set_icon.zip">Download .zip</a></div>
+</div><div class="sample" id="a1f7cf79dd555b04fa8d603247a040e644996293">
+ <img class="icon" style="display: none; ">
+ <img class="icon" src="images/sample-default-icon.png">
+ <h2 class="name">
+ <a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/extensions/app_launcher/">App Launcher</a>
+ </h2>
+ <p class="metadata features">Uses
+ <span>
+ <strong>browser_action</strong><span style="display: none; ">, </span>
+ <span> and</span>
+ </span><span>
+ <strong>management</strong><span style="display: none; ">, </span>
+ <span style="display: none; "> and</span>
+ </span>
+ </p>
+ <p></p>
+ <div class="apicalls"><strong>Calls:</strong>
+ <ul>
+ <li>
+ <code><a href="extension.html#method-getURL">chrome.extension.getURL</a></code>
+ </li><li>
+ <code><a href="management.html#method-get">chrome.management.get</a></code>
+ </li><li>
+ <code><a href="management.html#method-getAll">chrome.management.getAll</a></code>
+ </li><li>
+ <code><a href="management.html#method-launchApp">chrome.management.launchApp</a></code>
+ </li><li>
+ <code><a href="tabs.html#method-create">chrome.tabs.create</a></code>
+ </li>
+ </ul>
+ </div>
+ <div class="sourcefiles"><strong>Source files:</strong>
+ <ul>
+ <li>
+ <code><a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/extensions/app_launcher/manifest.json?content-type=text/plain">manifest.json</a></code>
+ </li><li>
+ <code><a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/extensions/app_launcher/popup.css?content-type=text/plain">popup.css</a></code>
+ </li><li>
+ <code><a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/extensions/app_launcher/popup.html?content-type=text/plain">popup.html</a></code>
+ </li><li>
+ <code><a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/extensions/app_launcher/popup.js?content-type=text/plain">popup.js</a></code>
+ </li>
+ </ul>
+ </div>
+ <div><a href="examples/extensions/app_launcher.zip">Download .zip</a></div>
</div><div class="sample" id="9747e3d6a3eab39bc7c17f11a80573c62d44c7e5">
<img class="icon" style="display: none; ">
<img class="icon" src="images/sample-default-icon.png">
@@ -2777,7 +2822,7 @@
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/samples.json b/chrome/common/extensions/docs/samples.json
index 89ffe2e..9e70b0c 100644
--- a/chrome/common/extensions/docs/samples.json
+++ b/chrome/common/extensions/docs/samples.json
@@ -279,6 +279,34 @@
"zip_path": "examples/api/pageAction/set_icon.zip"
},
{
+ "api_calls": [
+ "chrome.extension.getURL",
+ "chrome.management.get",
+ "chrome.management.getAll",
+ "chrome.management.launchApp",
+ "chrome.tabs.create"
+ ],
+ "description": "",
+ "features": [
+ "browser_action",
+ "management"
+ ],
+ "icon": null,
+ "id": "a1f7cf79dd555b04fa8d603247a040e644996293",
+ "name": "App Launcher",
+ "path": "examples/extensions/app_launcher/",
+ "protocols": [],
+ "search_string": "APP LAUNCHER BROWSER_ACTION MANAGEMENT CHROME.EXTENSION.GETURL CHROME.MANAGEMENT.GET CHROME.MANAGEMENT.GETALL CHROME.MANAGEMENT.LAUNCHAPP CHROME.TABS.CREATE",
+ "source_files": [
+ "manifest.json",
+ "popup.css",
+ "popup.html",
+ "popup.js"
+ ],
+ "source_hash": "4cb1348cfca9c990117d52290f93eb5fc5081bc2",
+ "zip_path": "examples/extensions/app_launcher.zip"
+ },
+ {
"api_calls": [],
"description": "",
"features": [
@@ -373,7 +401,7 @@
"options.html",
"popup.html"
],
- "source_hash": "bbd36a3d1d5580b477929d081f5a3a467ad32c63",
+ "source_hash": "a6ad5cd2a77ef54c0d96b4c5da014cfac34487db",
"zip_path": "examples/extensions/buildbot.zip"
},
{
@@ -404,7 +432,7 @@
"background.html",
"manifest.json"
],
- "source_hash": "37dd43080094bbe459b0429f1a2b995c33bab7c3",
+ "source_hash": "027409688a677867e3f2fcbc530ceac904ccedea",
"zip_path": "examples/extensions/chrome_search.zip"
},
{
@@ -913,7 +941,7 @@
"info.html",
"manifest.json"
],
- "source_hash": "672f49ed8edbe0829c7ba5a1d890b4440b157991",
+ "source_hash": "c746d9114348f4b414c1ec05e988e2807feb963a",
"zip_path": "examples/extensions/imageinfo.zip"
},
{
@@ -1286,7 +1314,7 @@
"util/sorttable.js",
"util/table2CSV.js"
],
- "source_hash": "7b6fde63c8dd0e626d176e8ce34ad43649746436",
+ "source_hash": "7e592dbd3446353f7d98d1760f7cd773035aaaad",
"zip_path": "examples/extensions/benchmark.zip"
},
{
diff --git a/chrome/common/extensions/docs/server/chromeextensionsdocs.py b/chrome/common/extensions/docs/server/chromeextensionsdocs.py
index 9edf5cd..a3778f4 100644
--- a/chrome/common/extensions/docs/server/chromeextensionsdocs.py
+++ b/chrome/common/extensions/docs/server/chromeextensionsdocs.py
@@ -6,6 +6,7 @@
import cgi
import logging
import re
+import os
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
@@ -43,10 +44,10 @@ DEFAULT_CACHE_TIME = 300
class MainPage(webapp.RequestHandler):
# get page from memcache, or else fetch it from src
def get(self):
- path = self.request.path
+ path = os.path.realpath(os.path.join('/', self.request.path))
# special path to invoke the unit tests
# TODO(nickbaum): is there a less ghetto way to invoke the unit test?
- if path == "/test/":
+ if path == "/test":
self.unitTest()
return
# if root, redirect to index.html
diff --git a/chrome/common/extensions/docs/static/apps.html b/chrome/common/extensions/docs/static/apps.html
index b4696bb..2cf3944 100644
--- a/chrome/common/extensions/docs/static/apps.html
+++ b/chrome/common/extensions/docs/static/apps.html
@@ -60,7 +60,7 @@ extensions and packaged apps, and packaged apps and hosted apps:
<ul>
<li> <a href="http://code.google.com/chrome/apps/articles/thinking_in_web_apps.html">Thinking in Web Apps</a> </li>
- <li> <a href="http://codesite-staging:29006/chrome/webstore/articles/apps_vs_extensions.html">Extensions, Packaged Apps, and Hosted Apps in the Chrome Web Store</a> </li>
+ <li> <a href="http://code.google.com/chrome/webstore/articles/apps_vs_extensions.html">Extensions, Packaged Apps, and Hosted Apps in the Chrome Web Store</a> </li>
</ul>
diff --git a/chrome/common/extensions/docs/static/getstarted.html b/chrome/common/extensions/docs/static/getstarted.html
index f1ec273..1121b58 100644
--- a/chrome/common/extensions/docs/static/getstarted.html
+++ b/chrome/common/extensions/docs/static/getstarted.html
@@ -65,6 +65,7 @@ to the toolbar of Google Chrome.
<img src="images/toolsmenu.gif" width="29" height="29" alt=""
style="margin-top:0" />
and choosing <b>Tools > Extensions</b>.
+ (On Mac, use <b>Window > Extensions</b>.)
</li>
<li>
diff --git a/chrome/common/extensions/docs/static/manifest.html b/chrome/common/extensions/docs/static/manifest.html
index 3f2f34e..aed4953 100644
--- a/chrome/common/extensions/docs/static/manifest.html
+++ b/chrome/common/extensions/docs/static/manifest.html
@@ -111,9 +111,8 @@ see <a href="i18n.html">Internationalization</a> for details.
The URL of the homepage for this extension. The extensions management page (chrome://extensions)
will contain a link to this URL. This field is particularly useful if you
<a href="hosting.html">host the extension on your own site</a>. If you distribute your
-extension using the <a href="https://chrome.google.com/extensions">Extensions Gallery</a>,
-the homepage URL defaults to the extension's own gallery page.
-<!-- PENDING: check whether the same is true of the store -->
+extension using the <a href="https://chrome.google.com/extensions">Extensions Gallery</a> or <a href="https://chrome.google.com/webstore">Chrome Web Store</a>,
+the homepage URL defaults to the extension's own page.
</p>
<h3 id="icons">icons</h3>
diff --git a/chrome/common/extensions/docs/static/pageAction.html b/chrome/common/extensions/docs/static/pageAction.html
index 60933ff..3def87e 100644
--- a/chrome/common/extensions/docs/static/pageAction.html
+++ b/chrome/common/extensions/docs/static/pageAction.html
@@ -95,6 +95,15 @@ follow these guidelines:</p>
for features that make sense
for most pages.
Use <a href="browserAction.html">browser actions</a> instead.
+ <li><b>Do</b> use icons
+ that are slightly lighter weight
+ than <a href="browserAction.html#icon">browser action icons</a>.
+ Most icons that Chrome displays
+ in the location bar
+ are smaller than 19 pixels.
+ If the edge pixels are used,
+ they are usually only used
+ for a faint shadow.
<li><b>Don't</b> constantly animate your icon.
That's just annoying.
</ul>
diff --git a/chrome/common/extensions/docs/static/permission_warnings.html b/chrome/common/extensions/docs/static/permission_warnings.html
index 4671f58..eea6558 100644
--- a/chrome/common/extensions/docs/static/permission_warnings.html
+++ b/chrome/common/extensions/docs/static/permission_warnings.html
@@ -1,21 +1,9 @@
<div id="pageData-name" class="pageData">Permission Warnings</div>
<div id="pageData-showTOC" class="pageData">true</div>
-<!--
-NOTE: When this doc is updated, the online help should also be updated:
-http://www.google.com/support/chrome/bin/answer.py?hl=en&answer=186213
-
-We should periodically look at
-http://src.chromium.org/viewvc/chrome/trunk/src/chrome/app/generated_resources.grd?view=markup
-to make sure that we're covering all messages. Search for
-IDS_EXTENSION_PROMPT_WARNING
-(e.g. IDS_EXTENSION_PROMPT_WARNING_BROWSING_HISTORY).
--->
-
<p>
To use most chrome.* APIs and extension capabilities,
-your extension must declare its intent in the
-<a href="manifest.html">manifest</a>,
+your extension must declare its intent in the manifest,
often in the "permissions" field.
Some of these declarations
result in a warning when
@@ -40,8 +28,8 @@ that a user might see when installing an extension:
</p>
<img src="images/perms-hw1.png"
- width="410" height="193"
- alt="Permission warning: 'It can access: Your data on api.flickr.com'"
+ width="387" height="162"
+ alt="Permission warning: 'This extension can access: Your data on api.flickr.com'"
/>
<p>
@@ -99,8 +87,8 @@ brings up the following warning:
</p>
<img src="images/perms-hw2.png"
- width="412" height="220"
- alt="Permission warning: 'It can access: Your data on api.flickr.com and flickr.com; Your browsing history'"
+ width="387" height="190"
+ alt="Permission warning: 'This extension can access: Your data on api.flickr.com and flickr.com; Your browsing history'"
/>
@@ -112,7 +100,8 @@ results in the seemingly unrelated warning
that the extension can access your browsing history.
The reason for the warning is that
although the <code>chrome.tabs</code> API
-might be used only to open new tabs,
+might be used only to open new tabs
+(<a href="tabs.html#method-create"><code>chrome.tabs.create()</code></a>),
it can also be used to see the URL that's associated
with every newly opened tab
(using their <a href="tabs.html#type-Tab">Tab</a> objects).
@@ -122,14 +111,13 @@ with every newly opened tab
<b>Note:</b>
As of Google Chrome 7,
you no longer need to specify the "tabs" permission
-just to call <code>chrome.tabs.create()</code>
-or <code>chrome.tabs.update()</code>.
+just to call <code>chrome.tabs.create()</code>.
</p>
<p>
The following table lists the warning messages
that users can see,
-along with the manifest entries
+along with the <a href="manifest.html">manifest</a> entries
that trigger them.
</p>
@@ -141,7 +129,7 @@ that trigger them.
<tr>
<td style="font-weight:bold">
- <!-- IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS -->
+ <!-- IDS_EXTENSION_PROMPT2_WARNING_FULL_ACCESS -->
All data on your computer and the websites you visit
</td>
<td>
@@ -155,7 +143,7 @@ that trigger them.
<tr>
<td style="font-weight:bold">
- <!-- IDS_EXTENSION_PROMPT_WARNING_BOOKMARKS -->
+ <!-- IDS_EXTENSION_PROMPT2_WARNING_BOOKMARKS -->
Your bookmarks
</td>
<td>
@@ -169,7 +157,7 @@ that trigger them.
<tr>
<td style="font-weight:bold">
- <!-- IDS_EXTENSION_PROMPT_WARNING_BROWSING_HISTORY -->
+ <!-- IDS_EXTENSION_PROMPT2_WARNING_BROWSING_HISTORY -->
Your browsing history
</td>
<td>
@@ -196,7 +184,7 @@ that trigger them.
<tr>
<td style="font-weight:bold">
- <!-- IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS -->
+ <!-- IDS_EXTENSION_PROMPT2_WARNING_ALL_HOSTS -->
Your data on all websites
</td>
<td>
@@ -229,8 +217,8 @@ that trigger them.
</tr>
<tr>
<td style="font-weight:bold">
- <!-- IDS_EXTENSION_PROMPT_WARNING_?_HOST -->
- <!-- IDS_EXTENSION_PROMPT_WARNING_4_OR_MORE_HOSTS -->
+ <!-- IDS_EXTENSION_PROMPT2_WARNING_?_HOST -->
+ <!-- IDS_EXTENSION_PROMPT2_WARNING_4_OR_MORE_HOSTS -->
Your data on <em>{list of websites}</em>
</td>
<td>
@@ -263,29 +251,7 @@ that trigger them.
<tr>
<td style="font-weight:bold">
- <!-- IDS_EXTENSION_PROMPT_WARNING_MANAGEMENT -->
- Your list of installed apps, extensions, and themes
- <br />
- <span style="font-weight:normal; font-style:italic">or</span>
- <br />
- Manage themes, extensions, and apps
-
- <!-- PENDING: remove "Manage...apps" alternative message
- once the fix is out on stable channel -->
- <!-- See http://crbug.com/67859 -->
- </td>
- <td>
- "management" permission
- </td>
- <td>
- The "management" permission is required by the
- <a href="management.html"><code>chrome.management</code></a> module.
- </td>
-</tr>
-
-<tr>
- <td style="font-weight:bold">
- <!-- IDS_EXTENSION_PROMPT_WARNING_GEOLOCATION -->
+ <!-- IDS_EXTENSION_PROMPT2_WARNING_GEOLOCATION -->
Your physical location
</td>
<td>
diff --git a/chrome/common/extensions/docs/static/themes.html b/chrome/common/extensions/docs/static/themes.html
index 651a74d..0d04779 100644
--- a/chrome/common/extensions/docs/static/themes.html
+++ b/chrome/common/extensions/docs/static/themes.html
@@ -66,7 +66,7 @@ file for a theme:
Colors are in RGB format.
To find the strings you can use within the "colors" field,
look for kColor* strings in
-<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/themes/browser_theme_provider.cc"><code>browser_theme_provider.cc</code></a>.
+<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/browser_theme_provider.cc"><code>browser_theme_provider.cc</code></a>.
</p>
<h3 id="images">images</h3>
@@ -75,7 +75,7 @@ look for kColor* strings in
Image resources use paths relative to the root of the extension.
You can override any of the images that are specified by
<code>kThemeableImages</code> in
-<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/themes/browser_theme_provider.cc"><code>browser_theme_provider.cc</code></a>.
+<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/browser_theme_provider.cc"><code>browser_theme_provider.cc</code></a>.
Just remove the "IDR_"
and convert the remaining characters to lowercase.
For example, <code>IDR_THEME_NTP_BACKGROUND</code>
@@ -92,7 +92,7 @@ properties such as background alignment,
background repeat,
and an alternate logo.
To see the properties and the values they can have, see
-<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/themes/browser_theme_provider.cc"><code>browser_theme_provider.cc</code></a>.
+<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/browser_theme_provider.cc"><code>browser_theme_provider.cc</code></a>.
<!-- [PENDING: We should flesh this out.] -->
</p>
@@ -106,7 +106,7 @@ because images don't work across platforms
and are brittle in the case of adding new buttons.
To find the strings you can use within the "tints" field,
look for kTint* strings in
-<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/themes/browser_theme_provider.cc"><code>browser_theme_provider.cc</code></a>.
+<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/browser_theme_provider.cc"><code>browser_theme_provider.cc</code></a>.
</p>
<p>
diff --git a/chrome/common/extensions/docs/static/tut_debugging.html b/chrome/common/extensions/docs/static/tut_debugging.html
index 7713e90..20d46c5 100644
--- a/chrome/common/extensions/docs/static/tut_debugging.html
+++ b/chrome/common/extensions/docs/static/tut_debugging.html
@@ -38,7 +38,7 @@ in the Extensions page.
find the extension files and load them.
If you don't have a handy copy of the files,
extract them from this
- <a href="examples/tutorials/getstarted.zip">ZIP file</a>.
+ <a href="examples/tutorials/getstarted/getstarted.zip">ZIP file</a>.
See Getting Started if you need
<a href="getstarted.html#load-ext">instructions
for loading the extension</a>.
diff --git a/chrome/common/extensions/docs/tabs.html b/chrome/common/extensions/docs/tabs.html
index 27b26be..cf7d2f6 100644
--- a/chrome/common/extensions/docs/tabs.html
+++ b/chrome/common/extensions/docs/tabs.html
@@ -7373,7 +7373,7 @@ For other examples and for help in viewing the source code, see
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/template/api_template.html b/chrome/common/extensions/docs/template/api_template.html
index 1b47011..b495e8d 100644
--- a/chrome/common/extensions/docs/template/api_template.html
+++ b/chrome/common/extensions/docs/template/api_template.html
@@ -471,7 +471,7 @@
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- &copy;2011 Google
+ &copy;2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/themes.html b/chrome/common/extensions/docs/themes.html
index 57c8063..b488a9d 100644
--- a/chrome/common/extensions/docs/themes.html
+++ b/chrome/common/extensions/docs/themes.html
@@ -379,7 +379,7 @@ file for a theme:
Colors are in RGB format.
To find the strings you can use within the "colors" field,
look for kColor* strings in
-<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/themes/browser_theme_provider.cc"><code>browser_theme_provider.cc</code></a>.
+<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/browser_theme_provider.cc"><code>browser_theme_provider.cc</code></a>.
</p>
<h3 id="images">images</h3>
@@ -388,7 +388,7 @@ look for kColor* strings in
Image resources use paths relative to the root of the extension.
You can override any of the images that are specified by
<code>kThemeableImages</code> in
-<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/themes/browser_theme_provider.cc"><code>browser_theme_provider.cc</code></a>.
+<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/browser_theme_provider.cc"><code>browser_theme_provider.cc</code></a>.
Just remove the "IDR_"
and convert the remaining characters to lowercase.
For example, <code>IDR_THEME_NTP_BACKGROUND</code>
@@ -405,7 +405,7 @@ properties such as background alignment,
background repeat,
and an alternate logo.
To see the properties and the values they can have, see
-<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/themes/browser_theme_provider.cc"><code>browser_theme_provider.cc</code></a>.
+<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/browser_theme_provider.cc"><code>browser_theme_provider.cc</code></a>.
<!-- [PENDING: We should flesh this out.] -->
</p>
@@ -419,7 +419,7 @@ because images don't work across platforms
and are brittle in the case of adding new buttons.
To find the strings you can use within the "tints" field,
look for kTint* strings in
-<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/themes/browser_theme_provider.cc"><code>browser_theme_provider.cc</code></a>.
+<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/browser_theme_provider.cc"><code>browser_theme_provider.cc</code></a>.
</p>
<p>
@@ -627,7 +627,7 @@ Community-written documentation to help you write themes is here:
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/tut_analytics.html b/chrome/common/extensions/docs/tut_analytics.html
index 4c695ff..d6a070f 100644
--- a/chrome/common/extensions/docs/tut_analytics.html
+++ b/chrome/common/extensions/docs/tut_analytics.html
@@ -695,7 +695,7 @@ extension.</p>
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/tut_debugging.html b/chrome/common/extensions/docs/tut_debugging.html
index 821c8e9..64a4ae1 100644
--- a/chrome/common/extensions/docs/tut_debugging.html
+++ b/chrome/common/extensions/docs/tut_debugging.html
@@ -368,7 +368,7 @@ in the Extensions page.
find the extension files and load them.
If you don't have a handy copy of the files,
extract them from this
- <a href="examples/tutorials/getstarted.zip">ZIP file</a>.
+ <a href="examples/tutorials/getstarted/getstarted.zip">ZIP file</a>.
See Getting Started if you need
<a href="getstarted.html#load-ext">instructions
for loading the extension</a>.
@@ -743,7 +743,7 @@ of Getting Started.
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/tut_oauth.html b/chrome/common/extensions/docs/tut_oauth.html
index 1d21c96..1783eda 100644
--- a/chrome/common/extensions/docs/tut_oauth.html
+++ b/chrome/common/extensions/docs/tut_oauth.html
@@ -685,7 +685,7 @@ Sample extensions that use these techniques are available in the Chromium source
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/tutorials.html b/chrome/common/extensions/docs/tutorials.html
index 8657aed..b88a9cf 100644
--- a/chrome/common/extensions/docs/tutorials.html
+++ b/chrome/common/extensions/docs/tutorials.html
@@ -498,7 +498,7 @@ more specialized topics:
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/whats_new.html b/chrome/common/extensions/docs/whats_new.html
index 9e2b8ed..79d6835 100644
--- a/chrome/common/extensions/docs/whats_new.html
+++ b/chrome/common/extensions/docs/whats_new.html
@@ -610,7 +610,7 @@ No API or manifest changes worth noting.
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/windows.html b/chrome/common/extensions/docs/windows.html
index ad163a2..1332caf 100644
--- a/chrome/common/extensions/docs/windows.html
+++ b/chrome/common/extensions/docs/windows.html
@@ -616,6 +616,64 @@ For other examples and for help in viewing the source code, see
</div><div>
<div>
<dt>
+ <var>tabId</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>integer</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>The id of the tab for which you want to adopt to the new window.</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div><div>
+ <div>
+ <dt>
<var>left</var>
<em>
@@ -3668,7 +3726,7 @@ For other examples and for help in viewing the source code, see
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/docs/xhr.html b/chrome/common/extensions/docs/xhr.html
index 4710c3e..b76acc5 100644
--- a/chrome/common/extensions/docs/xhr.html
+++ b/chrome/common/extensions/docs/xhr.html
@@ -628,7 +628,7 @@ prefer HTTPS whenever possible.
<a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
</p>
<p>
- ©2011 Google
+ ©2010 Google
</p>
<!-- begin analytics -->
diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc
index c49399a..bdbb33a 100644
--- a/chrome/common/extensions/extension.cc
+++ b/chrome/common/extensions/extension.cc
@@ -31,7 +31,6 @@
#include "chrome/common/extensions/extension_l10n_util.h"
#include "chrome/common/extensions/extension_resource.h"
#include "chrome/common/extensions/user_script.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
#include "googleurl/src/url_util.h"
#include "grit/chromium_strings.h"
@@ -133,7 +132,7 @@ const size_t kNumNonPermissionFunctionNames =
// A singleton object containing global data needed by the extension objects.
class ExtensionConfig {
public:
- static ExtensionConfig* GetSingleton() {
+ static ExtensionConfig* GetInstance() {
return Singleton<ExtensionConfig>::get();
}
@@ -288,7 +287,7 @@ GURL Extension::GalleryUpdateUrl(bool secure) {
// static
int Extension::GetPermissionMessageId(const std::string& permission) {
- return ExtensionConfig::GetSingleton()->GetPermissionMessageId(permission);
+ return ExtensionConfig::GetInstance()->GetPermissionMessageId(permission);
}
std::vector<string16> Extension::GetPermissionMessages() const {
@@ -470,7 +469,7 @@ std::string Extension::GenerateIdForPath(const FilePath& path) {
return id;
}
-Extension::HistogramType Extension::GetHistogramType() const {
+Extension::Type Extension::GetType() const {
if (is_theme())
return TYPE_THEME;
if (converted_from_user_script())
@@ -1267,8 +1266,7 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
*error = errors::kInvalidVersion;
return false;
}
- version_.reset(
- Version::GetVersionFromString(version_str));
+ version_.reset(Version::GetVersionFromString(version_str));
if (!version_.get() ||
version_->components().size() > 4) {
*error = errors::kInvalidVersion;
@@ -1742,6 +1740,15 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
if (web_extent().is_empty() || location() == Extension::COMPONENT) {
// Check if it's a module permission. If so, enable that permission.
if (IsAPIPermission(permission_str)) {
+ // Only allow the experimental API permission if the command line
+ // flag is present, or if the extension is a component of Chrome.
+ if (permission_str == Extension::kExperimentalPermission &&
+ !CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableExperimentalExtensionApis) &&
+ location() != Extension::COMPONENT) {
+ *error = errors::kExperimentalFlagRequired;
+ return false;
+ }
api_permissions_.insert(permission_str);
continue;
}
@@ -1781,9 +1788,8 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
}
if (source.HasKey(keys::kDefaultLocale)) {
- if (!source.GetString(keys::kDefaultLocale,
- &default_locale_) ||
- default_locale_.empty()) {
+ if (!source.GetString(keys::kDefaultLocale, &default_locale_) ||
+ !l10n_util::IsValidLocaleSyntax(default_locale_)) {
*error = errors::kInvalidDefaultLocale;
return false;
}
@@ -1846,6 +1852,59 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
devtools_url_ = GetResourceURL(devtools_str);
}
+ // Initialize text-to-speech voices (optional).
+ if (source.HasKey(keys::kTts)) {
+ DictionaryValue* tts_dict;
+ if (!source.GetDictionary(keys::kTts, &tts_dict)) {
+ *error = errors::kInvalidTts;
+ return false;
+ }
+
+ if (tts_dict->HasKey(keys::kTtsVoices)) {
+ ListValue* tts_voices;
+ if (!tts_dict->GetList(keys::kTtsVoices, &tts_voices)) {
+ *error = errors::kInvalidTtsVoices;
+ return false;
+ }
+
+ for (size_t i = 0; i < tts_voices->GetSize(); i++) {
+ DictionaryValue* one_tts_voice;
+ if (!tts_voices->GetDictionary(i, &one_tts_voice)) {
+ *error = errors::kInvalidTtsVoices;
+ return false;
+ }
+
+ TtsVoice voice_data;
+ if (one_tts_voice->HasKey(keys::kTtsVoicesVoiceName)) {
+ if (!one_tts_voice->GetString(
+ keys::kTtsVoicesVoiceName, &voice_data.voice_name)) {
+ *error = errors::kInvalidTtsVoicesVoiceName;
+ return false;
+ }
+ }
+ if (one_tts_voice->HasKey(keys::kTtsVoicesLocale)) {
+ if (!one_tts_voice->GetString(
+ keys::kTtsVoicesLocale, &voice_data.locale) ||
+ !l10n_util::IsValidLocaleSyntax(voice_data.locale)) {
+ *error = errors::kInvalidTtsVoicesLocale;
+ return false;
+ }
+ }
+ if (one_tts_voice->HasKey(keys::kTtsVoicesGender)) {
+ if (!one_tts_voice->GetString(
+ keys::kTtsVoicesGender, &voice_data.gender) ||
+ (voice_data.gender != keys::kTtsGenderMale &&
+ voice_data.gender != keys::kTtsGenderFemale)) {
+ *error = errors::kInvalidTtsVoicesGender;
+ return false;
+ }
+ }
+
+ tts_voices_.push_back(voice_data);
+ }
+ }
+ }
+
// Initialize incognito behavior. Apps default to split mode, extensions
// default to spanning.
incognito_split_mode_ = is_app();
@@ -1966,7 +2025,7 @@ static std::string SizeToString(const gfx::Size& max_size) {
void Extension::SetScriptingWhitelist(
const std::vector<std::string>& whitelist) {
ScriptingWhitelist* current_whitelist =
- ExtensionConfig::GetSingleton()->whitelist();
+ ExtensionConfig::GetInstance()->whitelist();
current_whitelist->clear();
for (ScriptingWhitelist::const_iterator it = whitelist.begin();
it != whitelist.end(); ++it) {
@@ -2201,20 +2260,7 @@ bool Extension::HasFullPermissions() const {
bool Extension::IsAPIPermission(const std::string& str) const {
for (size_t i = 0; i < Extension::kNumPermissions; ++i) {
if (str == Extension::kPermissions[i].name) {
- // Only allow the experimental API permission if the command line
- // flag is present, or if the extension is a component of Chrome.
- if (str == Extension::kExperimentalPermission) {
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableExperimentalExtensionApis)) {
- return true;
- } else if (location() == Extension::COMPONENT) {
- return true;
- } else {
- return false;
- }
- } else {
- return true;
- }
+ return true;
}
}
return false;
@@ -2225,7 +2271,7 @@ bool Extension::CanExecuteScriptEverywhere() const {
return true;
ScriptingWhitelist* whitelist =
- ExtensionConfig::GetSingleton()->whitelist();
+ ExtensionConfig::GetInstance()->whitelist();
for (ScriptingWhitelist::const_iterator it = whitelist->begin();
it != whitelist->end(); ++it) {
@@ -2260,9 +2306,15 @@ UninstalledExtensionInfo::UninstalledExtensionInfo(
const Extension& extension)
: extension_id(extension.id()),
extension_api_permissions(extension.api_permissions()),
- is_theme(extension.is_theme()),
- is_app(extension.is_app()),
- converted_from_user_script(extension.converted_from_user_script()),
+ extension_type(extension.GetType()),
update_url(extension.update_url()) {}
UninstalledExtensionInfo::~UninstalledExtensionInfo() {}
+
+
+UnloadedExtensionInfo::UnloadedExtensionInfo(
+ const Extension* extension,
+ Reason reason)
+ : reason(reason),
+ already_disabled(false),
+ extension(extension) {}
diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h
index 0d171d8..4c82fd6 100644
--- a/chrome/common/extensions/extension.h
+++ b/chrome/common/extensions/extension.h
@@ -83,9 +83,9 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
EXTENSION_ICON_BITTY = 16,
};
- // Type used for UMA_HISTOGRAM_ENUMERATION about extensions.
- // Do not change the order of entries or remove entries in this list.
- enum HistogramType {
+ // Do not change the order of entries or remove entries in this list
+ // as this is used in UMA_HISTOGRAM_ENUMERATIONs about extensions.
+ enum Type {
TYPE_UNKNOWN = 0,
TYPE_EXTENSION,
TYPE_THEME,
@@ -100,6 +100,12 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
bool is_public; // False if only this extension can load this plugin.
};
+ struct TtsVoice {
+ std::string voice_name;
+ std::string locale;
+ std::string gender;
+ };
+
// A permission is defined by its |name| (what is used in the manifest),
// and the |message_id| that's used by install/update UI.
struct Permission {
@@ -227,8 +233,8 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
IsExternalLocation(location);
}
- // See HistogramType definition above.
- HistogramType GetHistogramType() const;
+ // See Type definition above.
+ Type GetType() const;
// Returns an absolute url to a resource inside of an extension. The
// |extension_url| argument should be the url() from an Extension object. The
@@ -296,8 +302,8 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
// Returns the url prefix for the extension/apps gallery. Can be set via the
// --apps-gallery-url switch. The URL returned will not contain a trailing
// slash. Do not use this as a prefix/extent for the store. Instead see
- // ExtensionsService::GetWebStoreApp or
- // ExtensionsService::IsDownloadFromGallery
+ // ExtensionService::GetWebStoreApp or
+ // ExtensionService::IsDownloadFromGallery
static std::string ChromeStoreLaunchURL();
// Helper function that consolidates the check for whether the script can
@@ -428,6 +434,7 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
}
const std::string omnibox_keyword() const { return omnibox_keyword_; }
bool incognito_split_mode() const { return incognito_split_mode_; }
+ const std::vector<TtsVoice>& tts_voices() const { return tts_voices_; }
// App-related.
bool is_app() const { return is_app_; }
@@ -691,7 +698,10 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
// The Omnibox keyword for this extension, or empty if there is none.
std::string omnibox_keyword_;
- FRIEND_TEST_ALL_PREFIXES(ExtensionsServiceTest,
+ // List of text-to-speech voices that this extension provides, if any.
+ std::vector<TtsVoice> tts_voices_;
+
+ FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest,
UpdateExtensionPreservesLocation);
FRIEND_TEST_ALL_PREFIXES(ExtensionTest, LoadPageActionHelper);
FRIEND_TEST_ALL_PREFIXES(ExtensionTest, InitFromValueInvalid);
@@ -730,12 +740,26 @@ struct UninstalledExtensionInfo {
std::string extension_id;
std::set<std::string> extension_api_permissions;
- // TODO(akalin): Once we have a unified ExtensionType, replace the
- // below member variables with a member of that type.
- bool is_theme;
- bool is_app;
- bool converted_from_user_script;
+ Extension::Type extension_type;
GURL update_url;
};
+struct UnloadedExtensionInfo {
+ enum Reason {
+ DISABLE, // The extension is being disabled.
+ UPDATE, // The extension is being updated to a newer version.
+ UNINSTALL, // The extension is being uninstalled.
+ };
+
+ Reason reason;
+
+ // Was the extension already disabled?
+ bool already_disabled;
+
+ // The extension being unloaded - this should always be non-NULL.
+ const Extension* extension;
+
+ UnloadedExtensionInfo(const Extension* extension, Reason reason);
+};
+
#endif // CHROME_COMMON_EXTENSIONS_EXTENSION_H_
diff --git a/chrome/common/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc
index 2e99e2b..dd15afa 100644
--- a/chrome/common/extensions/extension_constants.cc
+++ b/chrome/common/extensions/extension_constants.cc
@@ -60,6 +60,13 @@ const char* kThemeImages = "images";
const char* kThemeTints = "tints";
const char* kToolstripPath = "path";
const char* kToolstrips = "toolstrips";
+const char* kTts = "tts";
+const char* kTtsGenderFemale = "female";
+const char* kTtsGenderMale = "male";
+const char* kTtsVoices = "voices";
+const char* kTtsVoicesGender = "gender";
+const char* kTtsVoicesLocale = "locale";
+const char* kTtsVoicesVoiceName = "voiceName";
const char* kType = "type";
const char* kUpdateURL = "update_url";
const char* kVersion = "version";
@@ -98,6 +105,9 @@ const char* kDisabledByPolicy =
const char* kDevToolsExperimental =
"You must request the 'experimental' permission in order to use the"
" DevTools API.";
+const char* kExperimentalFlagRequired =
+ "Loading extensions with 'experimental' permission requires"
+ " --enable-experimental-extension-apis command line flag.";
const char* kHostedAppsCannotIncludeExtensionFeatures =
"Hosted apps cannot use extension features.";
const char* kInvalidAllFrames =
@@ -231,6 +241,16 @@ const char* kInvalidToolstrip =
"Invalid value for 'toolstrips[*]'";
const char* kInvalidToolstrips =
"Invalid value for 'toolstrips'.";
+const char* kInvalidTts =
+ "Invalid value for 'tts'.";
+const char* kInvalidTtsVoices =
+ "Invalid value for 'tts.voices'.";
+const char* kInvalidTtsVoicesGender =
+ "Invalid value for 'tts.voices[*].gender'.";
+const char* kInvalidTtsVoicesLocale =
+ "Invalid value for 'tts.voices[*].locale'.";
+const char* kInvalidTtsVoicesVoiceName =
+ "Invalid value for 'tts.voices[*].voiceName'.";
const char* kInvalidUpdateURL =
"Invalid value for update url: '[*]'.";
const char* kInvalidVersion =
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h
index cf09515..7f09630 100644
--- a/chrome/common/extensions/extension_constants.h
+++ b/chrome/common/extensions/extension_constants.h
@@ -65,6 +65,13 @@ namespace extension_manifest_keys {
extern const char* kThemeTints;
extern const char* kToolstripPath;
extern const char* kToolstrips;
+ extern const char* kTts;
+ extern const char* kTtsGenderFemale;
+ extern const char* kTtsGenderMale;
+ extern const char* kTtsVoices;
+ extern const char* kTtsVoicesGender;
+ extern const char* kTtsVoicesLocale;
+ extern const char* kTtsVoicesVoiceName;
extern const char* kType;
extern const char* kUpdateURL;
extern const char* kVersion;
@@ -92,6 +99,8 @@ namespace extension_manifest_errors {
extern const char* kCannotScriptGallery;
extern const char* kChromeVersionTooLow;
extern const char* kDevToolsExperimental;
+ extern const char* kDisabledByPolicy;
+ extern const char* kExperimentalFlagRequired;
extern const char* kHostedAppsCannotIncludeExtensionFeatures;
extern const char* kInvalidAllFrames;
extern const char* kInvalidBackground;
@@ -105,7 +114,6 @@ namespace extension_manifest_errors {
extern const char* kInvalidCssList;
extern const char* kInvalidDefaultLocale;
extern const char* kInvalidDescription;
- extern const char* kDisabledByPolicy;
extern const char* kInvalidDevToolsPage;
extern const char* kInvalidGlob;
extern const char* kInvalidGlobList;
@@ -160,6 +168,11 @@ namespace extension_manifest_errors {
extern const char* kInvalidThemeTints;
extern const char* kInvalidToolstrip;
extern const char* kInvalidToolstrips;
+ extern const char* kInvalidTts;
+ extern const char* kInvalidTtsVoices;
+ extern const char* kInvalidTtsVoicesGender;
+ extern const char* kInvalidTtsVoicesLocale;
+ extern const char* kInvalidTtsVoicesVoiceName;
extern const char* kInvalidUpdateURL;
extern const char* kInvalidVersion;
extern const char* kInvalidWebURL;
@@ -243,8 +256,7 @@ namespace extension_misc {
PROMO_LAUNCH_WEB_STORE,
PROMO_CLOSE,
PROMO_EXPIRE,
- PROMO_SEEN,
- PROMO_BUCKET_BOUNDARY
+ PROMO_BUCKET_BOUNDARY = PROMO_EXPIRE + 1
};
} // extension_misc
diff --git a/chrome/common/extensions/extension_file_util.cc b/chrome/common/extensions/extension_file_util.cc
index f2350cc..e8636be 100644
--- a/chrome/common/extensions/extension_file_util.cc
+++ b/chrome/common/extensions/extension_file_util.cc
@@ -77,7 +77,7 @@ void UninstallExtension(const FilePath& extensions_dir,
const std::string& id) {
// We don't care about the return value. If this fails (and it can, due to
// plugins that aren't unloaded yet, it will get cleaned up by
- // ExtensionsService::GarbageCollectExtensions).
+ // ExtensionService::GarbageCollectExtensions).
file_util::Delete(extensions_dir.AppendASCII(id), true); // recursive.
}
diff --git a/chrome/common/extensions/extension_file_util_unittest.cc b/chrome/common/extensions/extension_file_util_unittest.cc
index 230712d..3f59da6 100644
--- a/chrome/common/extensions/extension_file_util_unittest.cc
+++ b/chrome/common/extensions/extension_file_util_unittest.cc
@@ -239,5 +239,5 @@ TEST(ExtensionFileUtil, ExtensionURLToRelativeFilePath) {
}
// TODO(aa): More tests as motivation allows. Maybe steal some from
-// ExtensionsService? Many of them could probably be tested here without the
+// ExtensionService? Many of them could probably be tested here without the
// MessageLoop shenanigans.
diff --git a/chrome/common/extensions/extension_l10n_util.cc b/chrome/common/extensions/extension_l10n_util.cc
index 34762fd..994ab83 100644
--- a/chrome/common/extensions/extension_l10n_util.cc
+++ b/chrome/common/extensions/extension_l10n_util.cc
@@ -167,37 +167,14 @@ bool AddLocale(const std::set<std::string>& chrome_locales,
return true;
}
-std::string NormalizeLocale(const std::string& locale) {
- std::string normalized_locale(locale);
- std::replace(normalized_locale.begin(), normalized_locale.end(), '-', '_');
-
- return normalized_locale;
-}
-
std::string CurrentLocaleOrDefault() {
- std::string current_locale = NormalizeLocale(*GetProcessLocale());
+ std::string current_locale = l10n_util::NormalizeLocale(*GetProcessLocale());
if (current_locale.empty())
current_locale = "en";
return current_locale;
}
-void GetParentLocales(const std::string& current_locale,
- std::vector<std::string>* parent_locales) {
- std::string locale(NormalizeLocale(current_locale));
-
- const int kNameCapacity = 256;
- char parent[kNameCapacity];
- base::strlcpy(parent, locale.c_str(), kNameCapacity);
- parent_locales->push_back(parent);
- UErrorCode err = U_ZERO_ERROR;
- while (uloc_getParent(parent, parent, kNameCapacity, &err) > 0) {
- if (U_FAILURE(err))
- break;
- parent_locales->push_back(parent);
- }
-}
-
void GetAllLocales(std::set<std::string>* all_locales) {
const std::vector<std::string>& available_locales =
l10n_util::GetAvailableLocales();
@@ -205,7 +182,7 @@ void GetAllLocales(std::set<std::string>* all_locales) {
// I.e. for sr_Cyrl_RS we add sr_Cyrl_RS, sr_Cyrl and sr.
for (size_t i = 0; i < available_locales.size(); ++i) {
std::vector<std::string> result;
- GetParentLocales(available_locales[i], &result);
+ l10n_util::GetParentLocales(available_locales[i], &result);
all_locales->insert(result.begin(), result.end());
}
}
@@ -240,6 +217,7 @@ bool GetValidLocales(const FilePath& locale_path,
return true;
}
+
// Loads contents of the messages file for given locale. If file is not found,
// or there was parsing error we return NULL and set |error|.
// Caller owns the returned object.
@@ -270,7 +248,7 @@ ExtensionMessageBundle* LoadMessageCatalogs(
// Order locales to load as current_locale, first_parent, ..., default_locale.
std::vector<std::string> all_fallback_locales;
if (!application_locale.empty() && application_locale != default_locale)
- GetParentLocales(application_locale, &all_fallback_locales);
+ l10n_util::GetParentLocales(application_locale, &all_fallback_locales);
all_fallback_locales.push_back(default_locale);
std::vector<linked_ptr<DictionaryValue> > catalogs;
diff --git a/chrome/common/extensions/extension_l10n_util.h b/chrome/common/extensions/extension_l10n_util.h
index e1fdfa0..57aa68f 100644
--- a/chrome/common/extensions/extension_l10n_util.h
+++ b/chrome/common/extensions/extension_l10n_util.h
@@ -59,18 +59,9 @@ bool AddLocale(const std::set<std::string>& chrome_locales,
std::set<std::string>* valid_locales,
std::string* error);
-// Converts all - into _, to be consistent with ICU and file system names.
-std::string NormalizeLocale(const std::string& locale);
-
// Returns normalized current locale, or default locale - en_US.
std::string CurrentLocaleOrDefault();
-// Produce a vector of parent locales for given locale.
-// It includes the current locale in the result.
-// sr_Cyrl_RS generates sr_Cyrl_RS, sr_Cyrl and sr.
-void GetParentLocales(const std::string& current_locale,
- std::vector<std::string>* parent_locales);
-
// Extends list of Chrome locales to them and their parents, so we can do
// proper fallback.
void GetAllLocales(std::set<std::string>* all_locales);
diff --git a/chrome/common/extensions/extension_l10n_util_unittest.cc b/chrome/common/extensions/extension_l10n_util_unittest.cc
index 1487452..0ec7e97 100644
--- a/chrome/common/extensions/extension_l10n_util_unittest.cc
+++ b/chrome/common/extensions/extension_l10n_util_unittest.cc
@@ -214,17 +214,6 @@ TEST(ExtensionL10nUtil, LoadMessageCatalogsDuplicateKeys) {
EXPECT_TRUE(error.empty());
}
-TEST(ExtensionL10nUtil, GetParentLocales) {
- std::vector<std::string> locales;
- const std::string top_locale("sr_Cyrl_RS");
- extension_l10n_util::GetParentLocales(top_locale, &locales);
-
- ASSERT_EQ(3U, locales.size());
- EXPECT_EQ("sr_Cyrl_RS", locales[0]);
- EXPECT_EQ("sr_Cyrl", locales[1]);
- EXPECT_EQ("sr", locales[2]);
-}
-
// Caller owns the returned object.
ExtensionMessageBundle* CreateManifestBundle() {
linked_ptr<DictionaryValue> catalog(new DictionaryValue);
diff --git a/chrome/common/extensions/extension_manifests_unittest.cc b/chrome/common/extensions/extension_manifests_unittest.cc
index 2132b6c..f7c8f27 100644
--- a/chrome/common/extensions/extension_manifests_unittest.cc
+++ b/chrome/common/extensions/extension_manifests_unittest.cc
@@ -245,6 +245,15 @@ TEST_F(ExtensionManifestTest, ChromeURLContentScriptInvalid) {
errors::kInvalidMatch);
}
+TEST_F(ExtensionManifestTest, ExperimentalPermission) {
+ LoadAndExpectError("experimental.json", errors::kExperimentalFlagRequired);
+ CommandLine old_command_line = *CommandLine::ForCurrentProcess();
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableExperimentalExtensionApis);
+ LoadAndExpectSuccess("experimental.json");
+ *CommandLine::ForCurrentProcess() = old_command_line;
+}
+
TEST_F(ExtensionManifestTest, DevToolsExtensions) {
LoadAndExpectError("devtools_extension_no_permissions.json",
errors::kDevToolsExperimental);
@@ -365,3 +374,37 @@ TEST_F(ExtensionManifestTest, DefaultPathForExtent) {
EXPECT_TRUE(extension->web_extent().ContainsURL(
GURL("http://www.google.com/monkey")));
}
+
+TEST_F(ExtensionManifestTest, DefaultLocale) {
+ LoadAndExpectError("default_locale_invalid.json",
+ extension_manifest_errors::kInvalidDefaultLocale);
+
+ scoped_refptr<Extension> extension(
+ LoadAndExpectSuccess("default_locale_valid.json"));
+ EXPECT_EQ("de-AT", extension->default_locale());
+}
+
+TEST_F(ExtensionManifestTest, TtsProvider) {
+ LoadAndExpectError("tts_provider_invalid_1.json",
+ extension_manifest_errors::kInvalidTts);
+ LoadAndExpectError("tts_provider_invalid_2.json",
+ extension_manifest_errors::kInvalidTtsVoices);
+ LoadAndExpectError("tts_provider_invalid_3.json",
+ extension_manifest_errors::kInvalidTtsVoices);
+ LoadAndExpectError("tts_provider_invalid_4.json",
+ extension_manifest_errors::kInvalidTtsVoicesVoiceName);
+ LoadAndExpectError("tts_provider_invalid_5.json",
+ extension_manifest_errors::kInvalidTtsVoicesLocale);
+ LoadAndExpectError("tts_provider_invalid_6.json",
+ extension_manifest_errors::kInvalidTtsVoicesLocale);
+ LoadAndExpectError("tts_provider_invalid_7.json",
+ extension_manifest_errors::kInvalidTtsVoicesGender);
+
+ scoped_refptr<Extension> extension(
+ LoadAndExpectSuccess("tts_provider_valid.json"));
+
+ ASSERT_EQ(1u, extension->tts_voices().size());
+ EXPECT_EQ("name", extension->tts_voices()[0].voice_name);
+ EXPECT_EQ("en-US", extension->tts_voices()[0].locale);
+ EXPECT_EQ("female", extension->tts_voices()[0].gender);
+}
diff --git a/chrome/common/extensions/extension_message_bundle.cc b/chrome/common/extensions/extension_message_bundle.cc
index 3f7c152..ea28c83 100644
--- a/chrome/common/extensions/extension_message_bundle.cc
+++ b/chrome/common/extensions/extension_message_bundle.cc
@@ -10,9 +10,9 @@
#include "app/l10n_util.h"
#include "base/hash_tables.h"
#include "base/i18n/rtl.h"
+#include "base/lazy_instance.h"
#include "base/linked_ptr.h"
#include "base/scoped_ptr.h"
-#include "base/singleton.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
@@ -316,18 +316,30 @@ std::string ExtensionMessageBundle::GetL10nMessage(
//
///////////////////////////////////////////////////////////////////////////////
+// Unique class for Singleton.
+struct ExtensionToMessagesMap {
+ ExtensionToMessagesMap();
+ ~ExtensionToMessagesMap();
+
+ // Maps extension ID to message map.
+ ExtensionToL10nMessagesMap messages_map;
+};
+
+static base::LazyInstance<ExtensionToMessagesMap> g_extension_to_messages_map(
+ base::LINKER_INITIALIZED);
+
ExtensionToMessagesMap::ExtensionToMessagesMap() {}
ExtensionToMessagesMap::~ExtensionToMessagesMap() {}
ExtensionToL10nMessagesMap* GetExtensionToL10nMessagesMap() {
- return &Singleton<ExtensionToMessagesMap>()->messages_map;
+ return &g_extension_to_messages_map.Get().messages_map;
}
L10nMessagesMap* GetL10nMessagesMap(const std::string extension_id) {
ExtensionToL10nMessagesMap::iterator it =
- Singleton<ExtensionToMessagesMap>()->messages_map.find(extension_id);
- if (it != Singleton<ExtensionToMessagesMap>()->messages_map.end())
+ g_extension_to_messages_map.Get().messages_map.find(extension_id);
+ if (it != g_extension_to_messages_map.Get().messages_map.end())
return &(it->second);
return NULL;
diff --git a/chrome/common/extensions/extension_message_bundle.h b/chrome/common/extensions/extension_message_bundle.h
index 6370559..df3bf35 100644
--- a/chrome/common/extensions/extension_message_bundle.h
+++ b/chrome/common/extensions/extension_message_bundle.h
@@ -155,15 +155,6 @@ typedef std::map<std::string, std::string> L10nMessagesMap;
// A map of extension ID to l10n message map.
typedef std::map<std::string, L10nMessagesMap > ExtensionToL10nMessagesMap;
-// Unique class for Singleton.
-struct ExtensionToMessagesMap {
- ExtensionToMessagesMap();
- ~ExtensionToMessagesMap();
-
- // Maps extension ID to message map.
- ExtensionToL10nMessagesMap messages_map;
-};
-
// Returns the extension_id to messages map.
ExtensionToL10nMessagesMap* GetExtensionToL10nMessagesMap();
diff --git a/chrome/common/extensions/extension_resource_unittest.cc b/chrome/common/extensions/extension_resource_unittest.cc
index 1590225..e7b3ef0 100644
--- a/chrome/common/extensions/extension_resource_unittest.cc
+++ b/chrome/common/extensions/extension_resource_unittest.cc
@@ -58,8 +58,7 @@ TEST(ExtensionResourceTest, CreateWithAllResourcesOnDisk) {
ASSERT_TRUE(file_util::CreateDirectory(l10n_path));
std::vector<std::string> locales;
- extension_l10n_util::GetParentLocales(l10n_util::GetApplicationLocale(""),
- &locales);
+ l10n_util::GetParentLocales(l10n_util::GetApplicationLocale(""), &locales);
ASSERT_FALSE(locales.empty());
for (size_t i = 0; i < locales.size(); i++) {
FilePath make_path;
diff --git a/chrome/common/extensions/extension_unpacker.cc b/chrome/common/extensions/extension_unpacker.cc
index e270870..1ff4342 100644
--- a/chrome/common/extensions/extension_unpacker.cc
+++ b/chrome/common/extensions/extension_unpacker.cc
@@ -4,6 +4,8 @@
#include "chrome/common/extensions/extension_unpacker.h"
+#include <set>
+
#include "base/file_util.h"
#include "base/scoped_handle.h"
#include "base/scoped_temp_dir.h"
@@ -18,7 +20,6 @@
#include "chrome/common/extensions/extension_file_util.h"
#include "chrome/common/extensions/extension_l10n_util.h"
#include "chrome/common/json_value_serializer.h"
-#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
#include "chrome/common/zip.h"
#include "ipc/ipc_message_utils.h"
@@ -150,7 +151,6 @@ bool ExtensionUnpacker::Run() {
extension_path_.DirName().AppendASCII(filenames::kTempExtensionName);
if (!file_util::CreateDirectory(temp_install_dir_)) {
-
#if defined(OS_WIN)
std::string dir_string = WideToUTF8(temp_install_dir_.value());
#else
diff --git a/chrome/common/extensions/update_manifest.cc b/chrome/common/extensions/update_manifest.cc
index 3329456..c75aa01 100644
--- a/chrome/common/extensions/update_manifest.cc
+++ b/chrome/common/extensions/update_manifest.cc
@@ -10,6 +10,7 @@
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "base/string_number_conversions.h"
+#include "base/stringprintf.h"
#include "base/version.h"
#include "chrome/common/libxml_utils.h"
#include "libxml/tree.h"
@@ -35,7 +36,7 @@ void UpdateManifest::ParseError(const char* details, ...) {
// TODO(asargent) make a platform abstracted newline?
errors_ += "\r\n";
}
- StringAppendV(&errors_, details, args);
+ base::StringAppendV(&errors_, details, args);
va_end(args);
}
@@ -81,7 +82,7 @@ static void XmlErrorFunc(void *context, const char *message, ...) {
va_list args;
va_start(args, message);
std::string* error = static_cast<std::string*>(context);
- StringAppendV(error, message, args);
+ base::StringAppendV(error, message, args);
va_end(args);
}
diff --git a/chrome/common/extensions/url_pattern.h b/chrome/common/extensions/url_pattern.h
index 72810ba..c0f17af 100644
--- a/chrome/common/extensions/url_pattern.h
+++ b/chrome/common/extensions/url_pattern.h
@@ -203,19 +203,10 @@ class URLPattern {
private:
friend class std::vector<URLPattern>;
-// See clang bug: http://llvm.org/bugs/show_bug.cgi?id=8479
-#if defined(__clang__)
- public:
-#endif
-
// Note: don't use this directly. This exists so URLPattern can be used
// with STL containers.
URLPattern();
-#if defined(__clang__)
- private:
-#endif
-
// A bitmask containing the schemes which are considered valid for this
// pattern. Parse() uses this to decide whether a pattern contains a valid
// scheme. MatchesScheme uses this to decide whether a wildcard scheme_
diff --git a/chrome/common/file_system/file_system_dispatcher.h b/chrome/common/file_system/file_system_dispatcher.h
index b8ffb2c..21bc792 100644
--- a/chrome/common/file_system/file_system_dispatcher.h
+++ b/chrome/common/file_system/file_system_dispatcher.h
@@ -25,11 +25,12 @@ class GURL;
// Dispatches and sends file system related messages sent to/from a child
// process from/to the main browser process. There is one instance
// per child process. Messages are dispatched on the main child thread.
-class FileSystemDispatcher {
+class FileSystemDispatcher : public IPC::Channel::Listener {
public:
FileSystemDispatcher();
~FileSystemDispatcher();
+ // IPC::Channel::Listener implementation.
bool OnMessageReceived(const IPC::Message& msg);
bool OpenFileSystem(const GURL& origin_url,
diff --git a/chrome/common/file_utilities_messages.cc b/chrome/common/file_utilities_messages.cc
new file mode 100644
index 0000000..b1236ae
--- /dev/null
+++ b/chrome/common/file_utilities_messages.cc
@@ -0,0 +1,8 @@
+// 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.
+
+#include "chrome/common/common_param_traits.h"
+
+#define IPC_MESSAGE_IMPL
+#include "chrome/common/file_utilities_messages.h"
diff --git a/chrome/common/file_utilities_messages.h b/chrome/common/file_utilities_messages.h
new file mode 100644
index 0000000..6b8157d
--- /dev/null
+++ b/chrome/common/file_utilities_messages.h
@@ -0,0 +1,35 @@
+// 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.
+
+#ifndef CHROME_COMMON_FILE_UTILITIES_MESSAGES_H_
+#define CHROME_COMMON_FILE_UTILITIES_MESSAGES_H_
+#pragma once
+
+#include "base/time.h"
+#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_param_traits.h"
+#include "ipc/ipc_platform_file.h"
+
+#define IPC_MESSAGE_START FileUtilitiesMsgStart
+
+// File utilities messages sent from the renderer to the browser.
+
+// Get file size in bytes. Set result to -1 if failed to get the file size.
+IPC_SYNC_MESSAGE_CONTROL1_1(FileUtilitiesMsg_GetFileSize,
+ FilePath /* path */,
+ int64 /* result */)
+
+// Get file modification time in seconds. Set result to 0 if failed to get the
+// file modification time.
+IPC_SYNC_MESSAGE_CONTROL1_1(FileUtilitiesMsg_GetFileModificationTime,
+ FilePath /* path */,
+ base::Time /* result */)
+
+// Open the file.
+IPC_SYNC_MESSAGE_CONTROL2_1(FileUtilitiesMsg_OpenFile,
+ FilePath /* path */,
+ int /* mode */,
+ IPC::PlatformFileForTransit /* result */)
+
+#endif // CHROME_COMMON_FILE_UTILITIES_MESSAGES_H_
diff --git a/chrome/common/font_config_ipc_linux.cc b/chrome/common/font_config_ipc_linux.cc
new file mode 100644
index 0000000..a2e86a9
--- /dev/null
+++ b/chrome/common/font_config_ipc_linux.cc
@@ -0,0 +1,110 @@
+// 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.
+
+#include "chrome/common/font_config_ipc_linux.h"
+
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include "base/pickle.h"
+#include "chrome/common/unix_domain_socket_posix.h"
+
+FontConfigIPC::FontConfigIPC(int fd)
+ : fd_(fd) {
+}
+
+FontConfigIPC::~FontConfigIPC() {
+ close(fd_);
+}
+
+bool FontConfigIPC::Match(std::string* result_family,
+ unsigned* result_filefaceid,
+ bool filefaceid_valid, unsigned filefaceid,
+ const std::string& family,
+ const void* characters, size_t characters_bytes,
+ bool* is_bold, bool* is_italic) {
+ if (family.length() > kMaxFontFamilyLength)
+ return false;
+
+ Pickle request;
+ request.WriteInt(METHOD_MATCH);
+ request.WriteBool(filefaceid_valid);
+ if (filefaceid_valid)
+ request.WriteUInt32(filefaceid);
+
+ request.WriteBool(is_bold && *is_bold);
+ request.WriteBool(is_bold && *is_italic);
+
+ request.WriteUInt32(characters_bytes);
+ if (characters_bytes)
+ request.WriteBytes(characters, characters_bytes);
+
+ request.WriteString(family);
+
+ uint8_t reply_buf[512];
+ const ssize_t r = UnixDomainSocket::SendRecvMsg(fd_, reply_buf,
+ sizeof(reply_buf), NULL,
+ request);
+ if (r == -1)
+ return false;
+
+ Pickle reply(reinterpret_cast<char*>(reply_buf), r);
+ void* iter = NULL;
+ bool result;
+ if (!reply.ReadBool(&iter, &result))
+ return false;
+ if (!result)
+ return false;
+
+ uint32_t reply_filefaceid;
+ std::string reply_family;
+ bool resulting_bold, resulting_italic;
+ if (!reply.ReadUInt32(&iter, &reply_filefaceid) ||
+ !reply.ReadString(&iter, &reply_family) ||
+ !reply.ReadBool(&iter, &resulting_bold) ||
+ !reply.ReadBool(&iter, &resulting_italic)) {
+ return false;
+ }
+
+ *result_filefaceid = reply_filefaceid;
+ if (result_family)
+ *result_family = reply_family;
+
+ if (is_bold)
+ *is_bold = resulting_bold;
+ if (is_italic)
+ *is_italic = resulting_italic;
+
+ return true;
+}
+
+int FontConfigIPC::Open(unsigned filefaceid) {
+ Pickle request;
+ request.WriteInt(METHOD_OPEN);
+ request.WriteUInt32(filefaceid);
+
+ int result_fd = -1;
+ uint8_t reply_buf[256];
+ const ssize_t r = UnixDomainSocket::SendRecvMsg(fd_, reply_buf,
+ sizeof(reply_buf),
+ &result_fd, request);
+
+ if (r == -1)
+ return -1;
+
+ Pickle reply(reinterpret_cast<char*>(reply_buf), r);
+ bool result;
+ void* iter = NULL;
+ if (!reply.ReadBool(&iter, &result) ||
+ !result) {
+ if (result_fd)
+ close(result_fd);
+ return -1;
+ }
+
+ return result_fd;
+}
diff --git a/chrome/common/font_config_ipc_linux.h b/chrome/common/font_config_ipc_linux.h
new file mode 100644
index 0000000..e478f6a
--- /dev/null
+++ b/chrome/common/font_config_ipc_linux.h
@@ -0,0 +1,40 @@
+// 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.
+
+#ifndef CHROME_COMMON_FONT_CONFIG_IPC_LINUX_H_
+#define CHROME_COMMON_FONT_CONFIG_IPC_LINUX_H_
+#pragma once
+
+#include "skia/ext/SkFontHost_fontconfig_impl.h"
+
+#include <string>
+
+// FontConfig implementation for Skia that proxies out of process to get out
+// of the sandbox. See http://code.google.com/p/chromium/wiki/LinuxSandboxIPC
+class FontConfigIPC : public FontConfigInterface {
+ public:
+ explicit FontConfigIPC(int fd);
+ ~FontConfigIPC();
+
+ // FontConfigInterface implementation.
+ virtual bool Match(std::string* result_family,
+ unsigned* result_filefaceid,
+ bool filefaceid_valid,
+ unsigned filefaceid,
+ const std::string& family,
+ const void* characters,
+ size_t characters_bytes,
+ bool* is_bold, bool* is_italic);
+ virtual int Open(unsigned filefaceid);
+
+ enum Method {
+ METHOD_MATCH = 0,
+ METHOD_OPEN = 1,
+ };
+
+ private:
+ const int fd_;
+};
+
+#endif // CHROME_COMMON_FONT_CONFIG_IPC_LINUX_H_
diff --git a/chrome/common/gpu_messages.cc b/chrome/common/gpu_messages.cc
index bd850a1..9d5c32e 100644
--- a/chrome/common/gpu_messages.cc
+++ b/chrome/common/gpu_messages.cc
@@ -2,19 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/common/gpu_messages.h"
-
#include "chrome/common/gpu_create_command_buffer_config.h"
#include "chrome/common/gpu_info.h"
#include "chrome/common/dx_diag_node.h"
#include "gfx/rect.h"
#include "gfx/size.h"
#include "ipc/ipc_channel_handle.h"
-#include "ipc/ipc_message_utils.h"
-#define MESSAGES_INTERNAL_IMPL_FILE \
- "chrome/common/gpu_messages_internal.h"
-#include "ipc/ipc_message_impl_macros.h"
+#define IPC_MESSAGE_IMPL
+#include "chrome/common/gpu_messages.h"
#if defined(OS_MACOSX)
diff --git a/chrome/common/gpu_messages.h b/chrome/common/gpu_messages.h
index f932c99..387d2b1 100644
--- a/chrome/common/gpu_messages.h
+++ b/chrome/common/gpu_messages.h
@@ -13,8 +13,6 @@
#include "gfx/native_widget_types.h"
#include "gpu/command_buffer/common/command_buffer.h"
-#define MESSAGES_INTERNAL_FILE \
- "chrome/common/gpu_messages_internal.h"
-#include "ipc/ipc_message_macros.h"
+#include "chrome/common/gpu_messages_internal.h"
#endif // CHROME_COMMON_GPU_MESSAGES_H_
diff --git a/chrome/common/gpu_messages_internal.h b/chrome/common/gpu_messages_internal.h
index 1872992..22f2f9d 100644
--- a/chrome/common/gpu_messages_internal.h
+++ b/chrome/common/gpu_messages_internal.h
@@ -2,13 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// This header is meant to be included in multiple passes, hence no traditional
-// header guard. It is included by backing_store_messages_internal.h
-// See ipc_message_macros.h for explanation of the macros and passes.
-
-// This file needs to be included again, even though we're actually included
-// from it via utility_messages.h.
-
#include <vector>
#include <string>
@@ -16,6 +9,8 @@
#include "chrome/common/gpu_video_common.h"
#include "ipc/ipc_message_macros.h"
+#define IPC_MESSAGE_START GpuMsgStart
+
namespace gfx {
class Size;
}
@@ -30,42 +25,40 @@ class GPUInfo;
//------------------------------------------------------------------------------
// GPU Messages
// These are messages from the browser to the GPU process.
-IPC_BEGIN_MESSAGES(Gpu)
-
- // Tells the GPU process to create a new channel for communication with a
- // given renderer. The channel name is returned in a
- // GpuHostMsg_ChannelEstablished message. The renderer ID is passed so that
- // the GPU process reuses an existing channel to that process if it exists.
- // This ID is a unique opaque identifier generated by the browser process.
- IPC_MESSAGE_CONTROL1(GpuMsg_EstablishChannel,
- int /* renderer_id */)
-
- // Tells the GPU process to close the channel identified by IPC channel
- // handle. If no channel can be identified, do nothing.
- IPC_MESSAGE_CONTROL1(GpuMsg_CloseChannel,
- IPC::ChannelHandle /* channel_handle */)
-
- // Provides a synchronization point to guarantee that the processing of
- // previous asynchronous messages (i.e., GpuMsg_EstablishChannel) has
- // completed. (This message can't be synchronous because the
- // GpuProcessHost uses an IPC::ChannelProxy, which sends all messages
- // asynchronously.) Results in a GpuHostMsg_SynchronizeReply.
- IPC_MESSAGE_CONTROL0(GpuMsg_Synchronize)
-
- // Tells the GPU process to create a context for collecting graphics card
- // information.
- IPC_MESSAGE_CONTROL0(GpuMsg_CollectGraphicsInfo)
+// Tells the GPU process to create a new channel for communication with a
+// given renderer. The channel name is returned in a
+// GpuHostMsg_ChannelEstablished message. The renderer ID is passed so that
+// the GPU process reuses an existing channel to that process if it exists.
+// This ID is a unique opaque identifier generated by the browser process.
+IPC_MESSAGE_CONTROL1(GpuMsg_EstablishChannel,
+ int /* renderer_id */)
+
+// Tells the GPU process to close the channel identified by IPC channel
+// handle. If no channel can be identified, do nothing.
+IPC_MESSAGE_CONTROL1(GpuMsg_CloseChannel,
+ IPC::ChannelHandle /* channel_handle */)
+
+// Provides a synchronization point to guarantee that the processing of
+// previous asynchronous messages (i.e., GpuMsg_EstablishChannel) has
+// completed. (This message can't be synchronous because the
+// GpuProcessHost uses an IPC::ChannelProxy, which sends all messages
+// asynchronously.) Results in a GpuHostMsg_SynchronizeReply.
+IPC_MESSAGE_CONTROL0(GpuMsg_Synchronize)
+
+// Tells the GPU process to create a context for collecting graphics card
+// information.
+IPC_MESSAGE_CONTROL0(GpuMsg_CollectGraphicsInfo)
#if defined(OS_MACOSX)
- // Tells the GPU process that the browser process handled the swap
- // buffers request with the given number. Note that it is possible
- // for the browser process to coalesce frames; it is not guaranteed
- // that every GpuHostMsg_AcceleratedSurfaceBuffersSwapped message
- // will result in a buffer swap on the browser side.
- IPC_MESSAGE_CONTROL3(GpuMsg_AcceleratedSurfaceBuffersSwappedACK,
- int /* renderer_id */,
- int32 /* route_id */,
- uint64 /* swap_buffers_count */)
+// Tells the GPU process that the browser process handled the swap
+// buffers request with the given number. Note that it is possible
+// for the browser process to coalesce frames; it is not guaranteed
+// that every GpuHostMsg_AcceleratedSurfaceBuffersSwapped message
+// will result in a buffer swap on the browser side.
+IPC_MESSAGE_CONTROL3(GpuMsg_AcceleratedSurfaceBuffersSwappedACK,
+ int /* renderer_id */,
+ int32 /* route_id */,
+ uint64 /* swap_buffers_count */)
// Tells the GPU process that the IOSurface of the buffer belonging to
// |renderer_route_id| a given id was destroyed, either by the user closing the
@@ -75,289 +68,270 @@ IPC_MESSAGE_CONTROL2(GpuMsg_DidDestroyAcceleratedSurface,
int32 /* renderer_route_id */)
#endif
- // Tells the GPU process to crash.
- IPC_MESSAGE_CONTROL0(GpuMsg_Crash)
-
- // Tells the GPU process to hang.
- IPC_MESSAGE_CONTROL0(GpuMsg_Hang)
+// Tells the GPU process to crash.
+IPC_MESSAGE_CONTROL0(GpuMsg_Crash)
-IPC_END_MESSAGES(Gpu)
+// Tells the GPU process to hang.
+IPC_MESSAGE_CONTROL0(GpuMsg_Hang)
//------------------------------------------------------------------------------
// GPU Host Messages
// These are messages from the GPU process to the browser.
-IPC_BEGIN_MESSAGES(GpuHost)
+// Response to a GpuHostMsg_EstablishChannel message.
+IPC_MESSAGE_CONTROL2(GpuHostMsg_ChannelEstablished,
+ IPC::ChannelHandle, /* channel_handle */
+ GPUInfo /* GPU logging stats */)
- // Response to a GpuHostMsg_EstablishChannel message.
- IPC_MESSAGE_CONTROL2(GpuHostMsg_ChannelEstablished,
- IPC::ChannelHandle, /* channel_handle */
- GPUInfo /* GPU logging stats */)
+// Response to a GpuMsg_Synchronize message.
+IPC_MESSAGE_CONTROL0(GpuHostMsg_SynchronizeReply)
- // Response to a GpuMsg_Synchronize message.
- IPC_MESSAGE_CONTROL0(GpuHostMsg_SynchronizeReply)
-
- // Response to a GpuMsg_CollectGraphicsInfo.
- IPC_MESSAGE_CONTROL1(GpuHostMsg_GraphicsInfoCollected,
- GPUInfo /* GPU logging stats */)
+// Response to a GpuMsg_CollectGraphicsInfo.
+IPC_MESSAGE_CONTROL1(GpuHostMsg_GraphicsInfoCollected,
+ GPUInfo /* GPU logging stats */)
#if defined(OS_LINUX)
- // Get the XID for a view ID.
- IPC_SYNC_MESSAGE_CONTROL1_1(GpuHostMsg_GetViewXID,
- gfx::NativeViewId, /* view */
- unsigned long /* xid */)
+// Get the XID for a view ID.
+IPC_SYNC_MESSAGE_CONTROL1_1(GpuHostMsg_GetViewXID,
+ gfx::NativeViewId, /* view */
+ unsigned long /* xid */)
- // Release the lock on the window.
- // If the associated view has been destroyed, destroy the window.
- IPC_MESSAGE_CONTROL1(GpuHostMsg_ReleaseXID,
- unsigned long /* xid */)
+// Release the lock on the window.
+// If the associated view has been destroyed, destroy the window.
+IPC_MESSAGE_CONTROL1(GpuHostMsg_ReleaseXID,
+ unsigned long /* xid */)
- IPC_SYNC_MESSAGE_CONTROL2_1(GpuHostMsg_ResizeXID,
- unsigned long, /* xid */
- gfx::Size, /* size */
- bool /* success */)
+IPC_SYNC_MESSAGE_CONTROL2_1(GpuHostMsg_ResizeXID,
+ unsigned long, /* xid */
+ gfx::Size, /* size */
+ bool /* success */)
#elif defined(OS_MACOSX)
- // This message, used on Mac OS X 10.6 and later (where IOSurface is
- // supported), is sent from the GPU process to the browser to indicate that a
- // new backing store was allocated for the given "window" (fake
- // PluginWindowHandle). The renderer ID and render view ID are needed in
- // order to uniquely identify the RenderWidgetHostView on the browser side.
- IPC_MESSAGE_CONTROL1(GpuHostMsg_AcceleratedSurfaceSetIOSurface,
- GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params)
-
- // This message notifies the browser process that the renderer
- // swapped the buffers associated with the given "window", which
- // should cause the browser to redraw the compositor's contents.
- IPC_MESSAGE_CONTROL1(GpuHostMsg_AcceleratedSurfaceBuffersSwapped,
- GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params)
+// This message, used on Mac OS X 10.6 and later (where IOSurface is
+// supported), is sent from the GPU process to the browser to indicate that a
+// new backing store was allocated for the given "window" (fake
+// PluginWindowHandle). The renderer ID and render view ID are needed in
+// order to uniquely identify the RenderWidgetHostView on the browser side.
+IPC_MESSAGE_CONTROL1(GpuHostMsg_AcceleratedSurfaceSetIOSurface,
+ GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params)
+
+// This message notifies the browser process that the renderer
+// swapped the buffers associated with the given "window", which
+// should cause the browser to redraw the compositor's contents.
+IPC_MESSAGE_CONTROL1(GpuHostMsg_AcceleratedSurfaceBuffersSwapped,
+ GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params)
#elif defined(OS_WIN)
- // Get the HWND for the compositor window and if necessary, create it
- IPC_SYNC_MESSAGE_CONTROL2_1(GpuHostMsg_GetCompositorHostWindow,
- int32, /* renderer_id */
- int32, /* render_view_id */
- gfx::PluginWindowHandle /* compositor_host_id */)
-
- IPC_MESSAGE_CONTROL2(GpuHostMsg_ScheduleComposite,
- int32, /* renderer_id */
- int32 /* render_view_id */)
+// Get the HWND for the compositor window and if necessary, create it
+IPC_SYNC_MESSAGE_CONTROL2_1(GpuHostMsg_GetCompositorHostWindow,
+ int32, /* renderer_id */
+ int32, /* render_view_id */
+ gfx::PluginWindowHandle /* compositor_host_id */)
+
+IPC_MESSAGE_CONTROL2(GpuHostMsg_ScheduleComposite,
+ int32, /* renderer_id */
+ int32 /* render_view_id */)
#endif
-IPC_END_MESSAGES(GpuHost)
-
//------------------------------------------------------------------------------
// GPU Channel Messages
// These are messages from a renderer process to the GPU process.
-IPC_BEGIN_MESSAGES(GpuChannel)
-
- // Tells the GPU process to create a new command buffer that renders directly
- // to a native view. The |render_view_id| is currently needed only on Mac OS
- // X in order to identify the window on the browser side into which the
- // rendering results go. A corresponding GpuCommandBufferStub is created.
- IPC_SYNC_MESSAGE_CONTROL3_1(GpuChannelMsg_CreateViewCommandBuffer,
- gfx::NativeViewId, /* view */
- int32, /* render_view_id */
- GPUCreateCommandBufferConfig, /* init_params */
- int32 /* route_id */)
-
- // Tells the GPU process to create a new command buffer that renders to an
- // offscreen frame buffer. If parent_route_id is not zero, the texture backing
- // the frame buffer is mapped into the corresponding parent command buffer's
- // namespace, with the name of parent_texture_id. This ID is in the parent's
- // namespace.
- IPC_SYNC_MESSAGE_CONTROL4_1(GpuChannelMsg_CreateOffscreenCommandBuffer,
- int32, /* parent_route_id */
- gfx::Size, /* size */
- GPUCreateCommandBufferConfig, /* init_params */
- uint32, /* parent_texture_id */
- int32 /* route_id */)
-
- // The CommandBufferProxy sends this to the GpuCommandBufferStub in its
- // destructor, so that the stub deletes the actual CommandBufferService
- // object that it's hosting.
- // TODO(apatrick): Implement this.
- IPC_SYNC_MESSAGE_CONTROL1_0(GpuChannelMsg_DestroyCommandBuffer,
- int32 /* instance_id */)
-
- // Create hardware video decoder && associate it with the output |decoder_id|;
- // We need this to be control message because we had to map the GpuChannel and
- // |decoder_id|.
- IPC_MESSAGE_CONTROL2(GpuChannelMsg_CreateVideoDecoder,
- int32, /* context_route_id */
- int32) /* decoder_id */
-
- // Release all resource of the hardware video decoder which was assocaited
- // with the input |decoder_id|.
- // TODO(hclam): This message needs to be asynchronous.
- IPC_SYNC_MESSAGE_CONTROL1_0(GpuChannelMsg_DestroyVideoDecoder,
- int32 /* decoder_id */)
-
-IPC_END_MESSAGES(GpuChannel)
+// Tells the GPU process to create a new command buffer that renders directly
+// to a native view. The |render_view_id| is currently needed only on Mac OS
+// X in order to identify the window on the browser side into which the
+// rendering results go. A corresponding GpuCommandBufferStub is created.
+IPC_SYNC_MESSAGE_CONTROL3_1(GpuChannelMsg_CreateViewCommandBuffer,
+ gfx::NativeViewId, /* view */
+ int32, /* render_view_id */
+ GPUCreateCommandBufferConfig, /* init_params */
+ int32 /* route_id */)
+
+// Tells the GPU process to create a new command buffer that renders to an
+// offscreen frame buffer. If parent_route_id is not zero, the texture backing
+// the frame buffer is mapped into the corresponding parent command buffer's
+// namespace, with the name of parent_texture_id. This ID is in the parent's
+// namespace.
+IPC_SYNC_MESSAGE_CONTROL4_1(GpuChannelMsg_CreateOffscreenCommandBuffer,
+ int32, /* parent_route_id */
+ gfx::Size, /* size */
+ GPUCreateCommandBufferConfig, /* init_params */
+ uint32, /* parent_texture_id */
+ int32 /* route_id */)
+
+// The CommandBufferProxy sends this to the GpuCommandBufferStub in its
+// destructor, so that the stub deletes the actual CommandBufferService
+// object that it's hosting.
+// TODO(apatrick): Implement this.
+IPC_SYNC_MESSAGE_CONTROL1_0(GpuChannelMsg_DestroyCommandBuffer,
+ int32 /* instance_id */)
+
+// Create hardware video decoder && associate it with the output |decoder_id|;
+// We need this to be control message because we had to map the GpuChannel and
+// |decoder_id|.
+IPC_MESSAGE_CONTROL2(GpuChannelMsg_CreateVideoDecoder,
+ int32, /* context_route_id */
+ int32) /* decoder_id */
+
+// Release all resource of the hardware video decoder which was assocaited
+// with the input |decoder_id|.
+// TODO(hclam): This message needs to be asynchronous.
+IPC_SYNC_MESSAGE_CONTROL1_0(GpuChannelMsg_DestroyVideoDecoder,
+ int32 /* decoder_id */)
//------------------------------------------------------------------------------
// GPU Command Buffer Messages
// These are messages between a renderer process to the GPU process relating to
// a single OpenGL context.
-IPC_BEGIN_MESSAGES(GpuCommandBuffer)
- // Initialize a command buffer with the given number of command entries.
- // Returns the shared memory handle for the command buffer mapped to the
- // calling process.
- IPC_SYNC_MESSAGE_ROUTED1_1(GpuCommandBufferMsg_Initialize,
- int32 /* size */,
- base::SharedMemoryHandle /* ring_buffer */)
-
- // Get the current state of the command buffer.
- IPC_SYNC_MESSAGE_ROUTED0_1(GpuCommandBufferMsg_GetState,
- gpu::CommandBuffer::State /* state */)
-
- // Get the current state of the command buffer asynchronously. State is
- // returned via UpdateState message.
- IPC_MESSAGE_ROUTED0(GpuCommandBufferMsg_AsyncGetState)
-
- // Synchronize the put and get offsets of both processes. Caller passes its
- // current put offset. Current state (including get offset) is returned.
- IPC_SYNC_MESSAGE_ROUTED1_1(GpuCommandBufferMsg_Flush,
- int32 /* put_offset */,
- gpu::CommandBuffer::State /* state */)
-
- // Asynchronously synchronize the put and get offsets of both processes.
- // Caller passes its current put offset. Current state (including get offset)
- // is returned via an UpdateState message.
- IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_AsyncFlush,
- int32 /* put_offset */)
-
- // Return the current state of the command buffer following a request via
- // an AsyncGetState or AsyncFlush message. (This message is sent from the
- // GPU process to the renderer process.)
- IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_UpdateState,
- gpu::CommandBuffer::State /* state */)
-
- // Indicates that a SwapBuffers call has been issued.
- IPC_MESSAGE_ROUTED0(GpuCommandBufferMsg_SwapBuffers)
-
- // Create a shared memory transfer buffer. Returns an id that can be used to
- // identify the transfer buffer from a comment.
- IPC_SYNC_MESSAGE_ROUTED1_1(GpuCommandBufferMsg_CreateTransferBuffer,
- int32 /* size */,
- int32 /* id */)
-
- // Destroy a previously created transfer buffer.
- IPC_SYNC_MESSAGE_ROUTED1_0(GpuCommandBufferMsg_DestroyTransferBuffer,
- int32 /* id */)
-
- // Get the shared memory handle for a transfer buffer mapped to the callers
- // process.
- IPC_SYNC_MESSAGE_ROUTED1_2(GpuCommandBufferMsg_GetTransferBuffer,
- int32 /* id */,
- base::SharedMemoryHandle /* transfer_buffer */,
- uint32 /* size */)
-
- // Send from command buffer stub to proxy when window is invalid and must be
- // repainted.
- IPC_MESSAGE_ROUTED0(GpuCommandBufferMsg_NotifyRepaint)
-
- // Tells the GPU process to resize an offscreen frame buffer.
- IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_ResizeOffscreenFrameBuffer,
- gfx::Size /* size */)
+// Initialize a command buffer with the given number of command entries.
+// Returns the shared memory handle for the command buffer mapped to the
+// calling process.
+IPC_SYNC_MESSAGE_ROUTED1_1(GpuCommandBufferMsg_Initialize,
+ int32 /* size */,
+ base::SharedMemoryHandle /* ring_buffer */)
+
+// Get the current state of the command buffer.
+IPC_SYNC_MESSAGE_ROUTED0_1(GpuCommandBufferMsg_GetState,
+ gpu::CommandBuffer::State /* state */)
+
+// Get the current state of the command buffer asynchronously. State is
+// returned via UpdateState message.
+IPC_MESSAGE_ROUTED0(GpuCommandBufferMsg_AsyncGetState)
+
+// Synchronize the put and get offsets of both processes. Caller passes its
+// current put offset. Current state (including get offset) is returned.
+IPC_SYNC_MESSAGE_ROUTED1_1(GpuCommandBufferMsg_Flush,
+ int32 /* put_offset */,
+ gpu::CommandBuffer::State /* state */)
+
+// Asynchronously synchronize the put and get offsets of both processes.
+// Caller passes its current put offset. Current state (including get offset)
+// is returned via an UpdateState message.
+IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_AsyncFlush,
+ int32 /* put_offset */)
+
+// Return the current state of the command buffer following a request via
+// an AsyncGetState or AsyncFlush message. (This message is sent from the
+// GPU process to the renderer process.)
+IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_UpdateState,
+ gpu::CommandBuffer::State /* state */)
+
+// Indicates that a SwapBuffers call has been issued.
+IPC_MESSAGE_ROUTED0(GpuCommandBufferMsg_SwapBuffers)
+
+// Create a shared memory transfer buffer. Returns an id that can be used to
+// identify the transfer buffer from a comment.
+IPC_SYNC_MESSAGE_ROUTED1_1(GpuCommandBufferMsg_CreateTransferBuffer,
+ int32 /* size */,
+ int32 /* id */)
+
+// Destroy a previously created transfer buffer.
+IPC_SYNC_MESSAGE_ROUTED1_0(GpuCommandBufferMsg_DestroyTransferBuffer,
+ int32 /* id */)
+
+// Get the shared memory handle for a transfer buffer mapped to the callers
+// process.
+IPC_SYNC_MESSAGE_ROUTED1_2(GpuCommandBufferMsg_GetTransferBuffer,
+ int32 /* id */,
+ base::SharedMemoryHandle /* transfer_buffer */,
+ uint32 /* size */)
+
+// Send from command buffer stub to proxy when window is invalid and must be
+// repainted.
+IPC_MESSAGE_ROUTED0(GpuCommandBufferMsg_NotifyRepaint)
+
+// Tells the GPU process to resize an offscreen frame buffer.
+IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_ResizeOffscreenFrameBuffer,
+ gfx::Size /* size */)
#if defined(OS_MACOSX)
- // On Mac OS X the GPU plugin must be offscreen, because there is no
- // true cross-process window hierarchy. For this reason we must send
- // resize events explicitly to the command buffer stub so it can
- // reallocate its backing store and send the new one back to the
- // browser. This message is currently used only on 10.6 and later.
- IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_SetWindowSize,
- gfx::Size /* size */)
+// On Mac OS X the GPU plugin must be offscreen, because there is no
+// true cross-process window hierarchy. For this reason we must send
+// resize events explicitly to the command buffer stub so it can
+// reallocate its backing store and send the new one back to the
+// browser. This message is currently used only on 10.6 and later.
+IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_SetWindowSize,
+ gfx::Size /* size */)
#endif
-IPC_END_MESSAGES(GpuCommandBuffer)
-
//------------------------------------------------------------------------------
// GPU Video Decoder Messages
// These messages are sent from Renderer process to GPU process.
-IPC_BEGIN_MESSAGES(GpuVideoDecoder)
- // Initialize and configure GpuVideoDecoder asynchronously.
- IPC_MESSAGE_ROUTED1(GpuVideoDecoderMsg_Initialize,
- GpuVideoDecoderInitParam)
-
- // Destroy and release GpuVideoDecoder asynchronously.
- IPC_MESSAGE_ROUTED0(GpuVideoDecoderMsg_Destroy)
+// Initialize and configure GpuVideoDecoder asynchronously.
+IPC_MESSAGE_ROUTED1(GpuVideoDecoderMsg_Initialize,
+ GpuVideoDecoderInitParam)
- // Start decoder flushing operation.
- IPC_MESSAGE_ROUTED0(GpuVideoDecoderMsg_Flush)
+// Destroy and release GpuVideoDecoder asynchronously.
+IPC_MESSAGE_ROUTED0(GpuVideoDecoderMsg_Destroy)
- // Tell the decoder to start prerolling.
- IPC_MESSAGE_ROUTED0(GpuVideoDecoderMsg_Preroll)
+// Start decoder flushing operation.
+IPC_MESSAGE_ROUTED0(GpuVideoDecoderMsg_Flush)
- // Send input buffer to GpuVideoDecoder.
- IPC_MESSAGE_ROUTED1(GpuVideoDecoderMsg_EmptyThisBuffer,
- GpuVideoDecoderInputBufferParam)
+// Tell the decoder to start prerolling.
+IPC_MESSAGE_ROUTED0(GpuVideoDecoderMsg_Preroll)
- // Ask the GPU process to produce a video frame with the ID.
- IPC_MESSAGE_ROUTED1(GpuVideoDecoderMsg_ProduceVideoFrame,
- int32) /* Video Frame ID */
+// Send input buffer to GpuVideoDecoder.
+IPC_MESSAGE_ROUTED1(GpuVideoDecoderMsg_EmptyThisBuffer,
+ GpuVideoDecoderInputBufferParam)
- // Sent from Renderer process to the GPU process to notify that textures are
- // generated for a video frame.
- IPC_MESSAGE_ROUTED2(GpuVideoDecoderMsg_VideoFrameAllocated,
- int32, /* Video Frame ID */
- std::vector<uint32>) /* Textures for video frame */
+// Ask the GPU process to produce a video frame with the ID.
+IPC_MESSAGE_ROUTED1(GpuVideoDecoderMsg_ProduceVideoFrame,
+ int32) /* Video Frame ID */
-IPC_END_MESSAGES(GpuVideoDecoder)
+// Sent from Renderer process to the GPU process to notify that textures are
+// generated for a video frame.
+IPC_MESSAGE_ROUTED2(GpuVideoDecoderMsg_VideoFrameAllocated,
+ int32, /* Video Frame ID */
+ std::vector<uint32>) /* Textures for video frame */
//------------------------------------------------------------------------------
// GPU Video Decoder Host Messages
// These messages are sent from GPU process to Renderer process.
-IPC_BEGIN_MESSAGES(GpuVideoDecoderHost)
- // Inform GpuVideoDecoderHost that a GpuVideoDecoder is created.
- IPC_MESSAGE_ROUTED1(GpuVideoDecoderHostMsg_CreateVideoDecoderDone,
- int32) /* decoder_id */
-
- // Confirm GpuVideoDecoder had been initialized or failed to initialize.
- // TODO(hclam): Change this to Done instead of ACK.
- IPC_MESSAGE_ROUTED1(GpuVideoDecoderHostMsg_InitializeACK,
- GpuVideoDecoderInitDoneParam)
-
- // Confrim GpuVideoDecoder had been destroyed properly.
- // TODO(hclam): Change this to Done instead of ACK.
- IPC_MESSAGE_ROUTED0(GpuVideoDecoderHostMsg_DestroyACK)
-
- // Confirm decoder had been flushed.
- // TODO(hclam): Change this to Done instead of ACK.
- IPC_MESSAGE_ROUTED0(GpuVideoDecoderHostMsg_FlushACK)
-
- // Confirm preroll operation is done.
- IPC_MESSAGE_ROUTED0(GpuVideoDecoderHostMsg_PrerollDone)
-
- // GpuVideoDecoder has consumed input buffer from transfer buffer.
- // TODO(hclam): Change this to Done instead of ACK.
- IPC_MESSAGE_ROUTED0(GpuVideoDecoderHostMsg_EmptyThisBufferACK)
-
- // GpuVideoDecoder require new input buffer.
- IPC_MESSAGE_ROUTED0(GpuVideoDecoderHostMsg_EmptyThisBufferDone)
-
- // GpuVideoDecoder reports that a video frame is ready to be consumed.
- IPC_MESSAGE_ROUTED4(GpuVideoDecoderHostMsg_ConsumeVideoFrame,
- int32, /* Video Frame ID */
- int64, /* Timestamp in microseconds */
- int64, /* Duration in microseconds */
- int32) /* Flags */
-
- // Allocate video frames for output of the hardware video decoder.
- IPC_MESSAGE_ROUTED4(GpuVideoDecoderHostMsg_AllocateVideoFrames,
- int32, /* Number of video frames to generate */
- uint32, /* Width of the video frame */
- uint32, /* Height of the video frame */
- int32 /* Format of the video frame */)
-
- // Release all video frames allocated for a hardware video decoder.
- IPC_MESSAGE_ROUTED0(GpuVideoDecoderHostMsg_ReleaseAllVideoFrames)
-
- // GpuVideoDecoder report output format change.
- IPC_MESSAGE_ROUTED1(GpuVideoDecoderHostMsg_MediaFormatChange,
- GpuVideoDecoderFormatChangeParam)
-
- // GpuVideoDecoder report error.
- IPC_MESSAGE_ROUTED1(GpuVideoDecoderHostMsg_ErrorNotification,
- GpuVideoDecoderErrorInfoParam)
-
-IPC_END_MESSAGES(GpuVideoDecoderHost)
+// Inform GpuVideoDecoderHost that a GpuVideoDecoder is created.
+IPC_MESSAGE_ROUTED1(GpuVideoDecoderHostMsg_CreateVideoDecoderDone,
+ int32) /* decoder_id */
+
+// Confirm GpuVideoDecoder had been initialized or failed to initialize.
+// TODO(hclam): Change this to Done instead of ACK.
+IPC_MESSAGE_ROUTED1(GpuVideoDecoderHostMsg_InitializeACK,
+ GpuVideoDecoderInitDoneParam)
+
+// Confrim GpuVideoDecoder had been destroyed properly.
+// TODO(hclam): Change this to Done instead of ACK.
+IPC_MESSAGE_ROUTED0(GpuVideoDecoderHostMsg_DestroyACK)
+
+// Confirm decoder had been flushed.
+// TODO(hclam): Change this to Done instead of ACK.
+IPC_MESSAGE_ROUTED0(GpuVideoDecoderHostMsg_FlushACK)
+
+// Confirm preroll operation is done.
+IPC_MESSAGE_ROUTED0(GpuVideoDecoderHostMsg_PrerollDone)
+
+// GpuVideoDecoder has consumed input buffer from transfer buffer.
+// TODO(hclam): Change this to Done instead of ACK.
+IPC_MESSAGE_ROUTED0(GpuVideoDecoderHostMsg_EmptyThisBufferACK)
+
+// GpuVideoDecoder require new input buffer.
+IPC_MESSAGE_ROUTED0(GpuVideoDecoderHostMsg_EmptyThisBufferDone)
+
+// GpuVideoDecoder reports that a video frame is ready to be consumed.
+IPC_MESSAGE_ROUTED4(GpuVideoDecoderHostMsg_ConsumeVideoFrame,
+ int32, /* Video Frame ID */
+ int64, /* Timestamp in microseconds */
+ int64, /* Duration in microseconds */
+ int32) /* Flags */
+
+// Allocate video frames for output of the hardware video decoder.
+IPC_MESSAGE_ROUTED4(GpuVideoDecoderHostMsg_AllocateVideoFrames,
+ int32, /* Number of video frames to generate */
+ uint32, /* Width of the video frame */
+ uint32, /* Height of the video frame */
+ int32 /* Format of the video frame */)
+
+// Release all video frames allocated for a hardware video decoder.
+IPC_MESSAGE_ROUTED0(GpuVideoDecoderHostMsg_ReleaseAllVideoFrames)
+
+// GpuVideoDecoder report output format change.
+IPC_MESSAGE_ROUTED1(GpuVideoDecoderHostMsg_MediaFormatChange,
+ GpuVideoDecoderFormatChangeParam)
+
+// GpuVideoDecoder report error.
+IPC_MESSAGE_ROUTED1(GpuVideoDecoderHostMsg_ErrorNotification,
+ GpuVideoDecoderErrorInfoParam)
diff --git a/chrome/common/gpu_plugin.cc b/chrome/common/gpu_plugin.cc
index 84ab339..4600638 100644
--- a/chrome/common/gpu_plugin.cc
+++ b/chrome/common/gpu_plugin.cc
@@ -9,18 +9,15 @@
#include "base/utf_string_conversions.h"
#include "chrome/common/chrome_switches.h"
#include "gpu/gpu_plugin/gpu_plugin.h"
-#include "webkit/glue/plugins/plugin_list.h"
-
-#if defined(ENABLE_GPU)
-#include "webkit/glue/plugins/plugin_constants_win.h"
-#endif
+#include "webkit/plugins/npapi/plugin_list.h"
namespace chrome {
void RegisterInternalGPUPlugin() {
#if defined(ENABLE_GPU)
- static const std::wstring kWideMimeType = ASCIIToWide(kGPUPluginMimeType);
- static const NPAPI::PluginVersionInfo kGPUPluginInfo = {
+ static const std::wstring kWideMimeType = ASCIIToWide(
+ "application/vnd.google.chrome.gpu-plugin");
+ static const webkit::npapi::PluginVersionInfo kGPUPluginInfo = {
FilePath(FILE_PATH_LITERAL("gpu-plugin")),
L"GPU Plug-in",
L"GPU Rendering Plug-in",
@@ -38,7 +35,8 @@ void RegisterInternalGPUPlugin() {
};
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableGPUPlugin))
- NPAPI::PluginList::Singleton()->RegisterInternalPlugin(kGPUPluginInfo);
+ webkit::npapi::PluginList::Singleton()->RegisterInternalPlugin(
+ kGPUPluginInfo);
#endif // ENABLE_GPU
}
diff --git a/chrome/common/guid.cc b/chrome/common/guid.cc
new file mode 100644
index 0000000..a6b4b09
--- /dev/null
+++ b/chrome/common/guid.cc
@@ -0,0 +1,32 @@
+// 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.
+
+#include "chrome/common/guid.h"
+
+#include "base/rand_util.h"
+#include "base/stringprintf.h"
+
+namespace guid {
+
+bool IsValidGUID(const std::string& guid) {
+ const size_t kGUIDLength = 36U;
+ if (guid.length() != kGUIDLength)
+ return false;
+
+ std::string hexchars = "0123456789ABCDEF";
+ for (uint32 i = 0; i < guid.length(); ++i) {
+ char current = guid[i];
+ if (i == 8 || i == 13 || i == 18 || i == 23) {
+ if (current != '-')
+ return false;
+ } else {
+ if (hexchars.find(current) == std::string::npos)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // namespace guid
diff --git a/chrome/common/guid.h b/chrome/common/guid.h
new file mode 100644
index 0000000..9121c9e
--- /dev/null
+++ b/chrome/common/guid.h
@@ -0,0 +1,32 @@
+// 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.
+
+#ifndef CHROME_COMMON_GUID_H_
+#define CHROME_COMMON_GUID_H_
+#pragma once
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "build/build_config.h"
+
+namespace guid {
+
+// Generate a 128-bit random GUID of the form: "%08X-%04X-%04X-%04X-%012llX".
+// If GUID generation fails an empty string is returned.
+// The POSIX implementation uses psuedo random number generation to create
+// the GUID. The Windows implementation uses system services.
+std::string GenerateGUID();
+
+// Returns true if the input string conforms to the GUID format.
+bool IsValidGUID(const std::string& guid);
+
+#if defined(OS_POSIX)
+// For unit testing purposes only. Do not use outside of tests.
+std::string RandomDataToGUIDString(const uint64 bytes[2]);
+#endif
+
+} // namespace guid
+
+#endif // CHROME_COMMON_GUID_H_
diff --git a/chrome/common/guid_posix.cc b/chrome/common/guid_posix.cc
new file mode 100644
index 0000000..f21788b
--- /dev/null
+++ b/chrome/common/guid_posix.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 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.
+
+#include "chrome/common/guid.h"
+
+#include "base/rand_util.h"
+#include "base/stringprintf.h"
+
+namespace guid {
+
+std::string GenerateGUID() {
+ uint64 sixteen_bytes[2] = { base::RandUint64(), base::RandUint64() };
+ return RandomDataToGUIDString(sixteen_bytes);
+}
+
+// TODO(cmasone): Once we're comfortable this works, migrate Windows code to
+// use this as well.
+std::string RandomDataToGUIDString(const uint64 bytes[2]) {
+ return StringPrintf("%08X-%04X-%04X-%04X-%012llX",
+ static_cast<unsigned int>(bytes[0] >> 32),
+ static_cast<unsigned int>((bytes[0] >> 16) & 0x0000ffff),
+ static_cast<unsigned int>(bytes[0] & 0x0000ffff),
+ static_cast<unsigned int>(bytes[1] >> 48),
+ bytes[1] & 0x0000ffffffffffffULL);
+}
+
+} // namespace guid
diff --git a/chrome/common/guid_unittest.cc b/chrome/common/guid_unittest.cc
new file mode 100644
index 0000000..628bafc
--- /dev/null
+++ b/chrome/common/guid_unittest.cc
@@ -0,0 +1,42 @@
+// 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.
+
+#include "chrome/common/guid.h"
+
+#include <limits>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_POSIX)
+TEST(GUIDTest, GUIDGeneratesAllZeroes) {
+ uint64 bytes[] = { 0, 0 };
+ std::string clientid = guid::RandomDataToGUIDString(bytes);
+ EXPECT_EQ("00000000-0000-0000-0000-000000000000", clientid);
+}
+
+TEST(GUIDTest, GUIDGeneratesCorrectly) {
+ uint64 bytes[] = { 0x0123456789ABCDEFULL, 0xFEDCBA9876543210ULL };
+ std::string clientid = guid::RandomDataToGUIDString(bytes);
+ EXPECT_EQ("01234567-89AB-CDEF-FEDC-BA9876543210", clientid);
+}
+#endif
+
+TEST(GUIDTest, GUIDCorrectlyFormatted) {
+ const int kIterations = 10;
+ for (int it = 0; it < kIterations; ++it) {
+ std::string guid = guid::GenerateGUID();
+ EXPECT_TRUE(guid::IsValidGUID(guid));
+ }
+}
+
+TEST(GUIDTest, GUIDBasicUniqueness) {
+ const int kIterations = 10;
+ for (int it = 0; it < kIterations; ++it) {
+ std::string guid1 = guid::GenerateGUID();
+ std::string guid2 = guid::GenerateGUID();
+ EXPECT_EQ(36U, guid1.length());
+ EXPECT_EQ(36U, guid2.length());
+ EXPECT_NE(guid1, guid2);
+ }
+}
diff --git a/chrome/common/guid_win.cc b/chrome/common/guid_win.cc
new file mode 100644
index 0000000..0d95cd6
--- /dev/null
+++ b/chrome/common/guid_win.cc
@@ -0,0 +1,38 @@
+// Copyright (c) 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.
+
+#include "chrome/common/guid.h"
+
+#include <stdlib.h>
+
+#include <objbase.h>
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+
+namespace guid {
+
+std::string GenerateGUID() {
+ const int kGUIDSize = 39;
+
+ GUID guid;
+ HRESULT guid_result = CoCreateGuid(&guid);
+ DCHECK(SUCCEEDED(guid_result));
+ if (!SUCCEEDED(guid_result))
+ return std::string();
+
+ std::wstring guid_string;
+ int result = StringFromGUID2(guid,
+ WriteInto(&guid_string, kGUIDSize), kGUIDSize);
+ DCHECK(result == kGUIDSize);
+ if (result != kGUIDSize)
+ return std::string();
+
+ return WideToUTF8(guid_string.substr(1, guid_string.length() - 2));
+}
+
+} // namespace guid
diff --git a/chrome/common/indexed_db_key.cc b/chrome/common/indexed_db_key.cc
index 4488673..0379c30 100644
--- a/chrome/common/indexed_db_key.cc
+++ b/chrome/common/indexed_db_key.cc
@@ -29,12 +29,17 @@ void IndexedDBKey::SetInvalid() {
type_ = WebIDBKey::InvalidType;
}
-void IndexedDBKey::Set(const string16& string) {
+void IndexedDBKey::SetString(const string16& string) {
type_ = WebIDBKey::StringType;
string_ = string;
}
-void IndexedDBKey::Set(double number) {
+void IndexedDBKey::SetDate(double date) {
+ type_ = WebIDBKey::DateType;
+ date_ = date;
+}
+
+void IndexedDBKey::SetNumber(double number) {
type_ = WebIDBKey::NumberType;
number_ = number;
}
@@ -44,6 +49,7 @@ void IndexedDBKey::Set(const WebIDBKey& key) {
string_ = key.type() == WebIDBKey::StringType ?
static_cast<string16>(key.string()) : string16();
number_ = key.type() == WebIDBKey::NumberType ? key.number() : 0;
+ date_ = key.type() == WebIDBKey::DateType ? key.date() : 0;
}
IndexedDBKey::operator WebIDBKey() const {
@@ -51,9 +57,11 @@ IndexedDBKey::operator WebIDBKey() const {
case WebIDBKey::NullType:
return WebIDBKey::createNull();
case WebIDBKey::StringType:
- return WebIDBKey(string_);
+ return WebIDBKey::createString(string_);
+ case WebIDBKey::DateType:
+ return WebIDBKey::createDate(date_);
case WebIDBKey::NumberType:
- return WebIDBKey(number_);
+ return WebIDBKey::createNumber(number_);
case WebIDBKey::InvalidType:
return WebIDBKey::createInvalid();
}
diff --git a/chrome/common/indexed_db_key.h b/chrome/common/indexed_db_key.h
index 60b4529..b740c10 100644
--- a/chrome/common/indexed_db_key.h
+++ b/chrome/common/indexed_db_key.h
@@ -18,12 +18,14 @@ class IndexedDBKey {
void SetNull();
void SetInvalid();
- void Set(const string16& string);
- void Set(double number);
+ void SetString(const string16& string);
+ void SetDate(double date);
+ void SetNumber(double number);
void Set(const WebKit::WebIDBKey& key);
WebKit::WebIDBKey::Type type() const { return type_; }
const string16& string() const { return string_; }
+ double date() const { return date_; }
double number() const { return number_; }
operator WebKit::WebIDBKey() const;
@@ -31,6 +33,7 @@ class IndexedDBKey {
private:
WebKit::WebIDBKey::Type type_;
string16 string_;
+ double date_;
double number_;
};
diff --git a/chrome/common/indexed_db_messages.cc b/chrome/common/indexed_db_messages.cc
new file mode 100644
index 0000000..c7c0e22
--- /dev/null
+++ b/chrome/common/indexed_db_messages.cc
@@ -0,0 +1,339 @@
+// 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.
+
+#include "chrome/common/common_param_traits.h"
+
+#define IPC_MESSAGE_IMPL
+#include "chrome/common/indexed_db_messages.h"
+
+IndexedDBHostMsg_FactoryOpen_Params::IndexedDBHostMsg_FactoryOpen_Params()
+ : routing_id(0),
+ response_id(0),
+ maximum_size(0) {
+}
+
+IndexedDBHostMsg_FactoryOpen_Params::~IndexedDBHostMsg_FactoryOpen_Params() {
+}
+
+IndexedDBHostMsg_DatabaseCreateObjectStore_Params::
+ IndexedDBHostMsg_DatabaseCreateObjectStore_Params()
+ : auto_increment(false),
+ transaction_id(0),
+ idb_database_id(0) {
+}
+
+IndexedDBHostMsg_DatabaseCreateObjectStore_Params::
+ ~IndexedDBHostMsg_DatabaseCreateObjectStore_Params() {
+}
+
+IndexedDBHostMsg_IndexOpenCursor_Params::
+ IndexedDBHostMsg_IndexOpenCursor_Params()
+ : response_id(0),
+ lower_open(false),
+ upper_open(false),
+ direction(0),
+ idb_index_id(0),
+ transaction_id(0) {
+}
+
+IndexedDBHostMsg_IndexOpenCursor_Params::
+ ~IndexedDBHostMsg_IndexOpenCursor_Params() {
+}
+
+
+IndexedDBHostMsg_ObjectStorePut_Params::
+ IndexedDBHostMsg_ObjectStorePut_Params()
+ : idb_object_store_id(0),
+ response_id(0),
+ add_only(false),
+ transaction_id(0) {
+}
+
+IndexedDBHostMsg_ObjectStorePut_Params::
+~IndexedDBHostMsg_ObjectStorePut_Params() {
+}
+
+IndexedDBHostMsg_ObjectStoreCreateIndex_Params::
+ IndexedDBHostMsg_ObjectStoreCreateIndex_Params()
+ : unique(false),
+ transaction_id(0),
+ idb_object_store_id(0) {
+}
+
+IndexedDBHostMsg_ObjectStoreCreateIndex_Params::
+ ~IndexedDBHostMsg_ObjectStoreCreateIndex_Params() {
+}
+
+
+IndexedDBHostMsg_ObjectStoreOpenCursor_Params::
+ IndexedDBHostMsg_ObjectStoreOpenCursor_Params()
+ : response_id(0),
+ lower_open(false),
+ upper_open(false),
+ direction(0),
+ idb_object_store_id(0),
+ transaction_id(0) {
+}
+
+IndexedDBHostMsg_ObjectStoreOpenCursor_Params::
+ ~IndexedDBHostMsg_ObjectStoreOpenCursor_Params() {
+}
+
+namespace IPC {
+
+void ParamTraits<IndexedDBHostMsg_FactoryOpen_Params>::Write(
+ Message* m,
+ const param_type& p) {
+ WriteParam(m, p.routing_id);
+ WriteParam(m, p.response_id);
+ WriteParam(m, p.origin);
+ WriteParam(m, p.name);
+ WriteParam(m, p.maximum_size);
+}
+
+bool ParamTraits<IndexedDBHostMsg_FactoryOpen_Params>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->routing_id) &&
+ ReadParam(m, iter, &p->response_id) &&
+ ReadParam(m, iter, &p->origin) &&
+ ReadParam(m, iter, &p->name) &&
+ ReadParam(m, iter, &p->maximum_size);
+}
+
+void ParamTraits<IndexedDBHostMsg_FactoryOpen_Params>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.routing_id, l);
+ l->append(", ");
+ LogParam(p.response_id, l);
+ l->append(", ");
+ LogParam(p.origin, l);
+ l->append(", ");
+ LogParam(p.name, l);
+ l->append(", ");
+ LogParam(p.maximum_size, l);
+ l->append(")");
+}
+
+void ParamTraits<IndexedDBHostMsg_DatabaseCreateObjectStore_Params>::Write(
+ Message* m,
+ const param_type& p) {
+ WriteParam(m, p.name);
+ WriteParam(m, p.key_path);
+ WriteParam(m, p.auto_increment);
+ WriteParam(m, p.transaction_id);
+ WriteParam(m, p.idb_database_id);
+}
+
+bool ParamTraits<IndexedDBHostMsg_DatabaseCreateObjectStore_Params>::Read(
+ const Message* m,
+ void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->name) &&
+ ReadParam(m, iter, &p->key_path) &&
+ ReadParam(m, iter, &p->auto_increment) &&
+ ReadParam(m, iter, &p->transaction_id) &&
+ ReadParam(m, iter, &p->idb_database_id);
+}
+
+void ParamTraits<IndexedDBHostMsg_DatabaseCreateObjectStore_Params>::Log(
+ const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.name, l);
+ l->append(", ");
+ LogParam(p.key_path, l);
+ l->append(", ");
+ LogParam(p.auto_increment, l);
+ l->append(", ");
+ LogParam(p.transaction_id, l);
+ l->append(", ");
+ LogParam(p.idb_database_id, l);
+ l->append(")");
+}
+
+void ParamTraits<IndexedDBHostMsg_IndexOpenCursor_Params>::Write(
+ Message* m,
+ const param_type& p) {
+ WriteParam(m, p.response_id);
+ WriteParam(m, p.lower_key);
+ WriteParam(m, p.upper_key);
+ WriteParam(m, p.lower_open);
+ WriteParam(m, p.upper_open);
+ WriteParam(m, p.direction);
+ WriteParam(m, p.idb_index_id);
+ WriteParam(m, p.transaction_id);
+}
+
+bool ParamTraits<IndexedDBHostMsg_IndexOpenCursor_Params>::Read(
+ const Message* m,
+ void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->response_id) &&
+ ReadParam(m, iter, &p->lower_key) &&
+ ReadParam(m, iter, &p->upper_key) &&
+ ReadParam(m, iter, &p->lower_open) &&
+ ReadParam(m, iter, &p->upper_open) &&
+ ReadParam(m, iter, &p->direction) &&
+ ReadParam(m, iter, &p->idb_index_id) &&
+ ReadParam(m, iter, &p->transaction_id);
+}
+
+void ParamTraits<IndexedDBHostMsg_IndexOpenCursor_Params>::Log(
+ const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.response_id, l);
+ l->append(", ");
+ LogParam(p.lower_key, l);
+ l->append(", ");
+ LogParam(p.upper_key, l);
+ l->append(", ");
+ LogParam(p.lower_open, l);
+ l->append(", ");
+ LogParam(p.upper_open, l);
+ l->append(", ");
+ LogParam(p.direction, l);
+ l->append(", ");
+ LogParam(p.idb_index_id, l);
+ l->append(",");
+ LogParam(p.transaction_id, l);
+ l->append(")");
+}
+
+void ParamTraits<IndexedDBHostMsg_ObjectStorePut_Params>::Write(
+ Message* m,
+ const param_type& p) {
+ WriteParam(m, p.idb_object_store_id);
+ WriteParam(m, p.response_id);
+ WriteParam(m, p.serialized_value);
+ WriteParam(m, p.key);
+ WriteParam(m, p.add_only);
+ WriteParam(m, p.transaction_id);
+}
+
+bool ParamTraits<IndexedDBHostMsg_ObjectStorePut_Params>::Read(
+ const Message* m,
+ void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->idb_object_store_id) &&
+ ReadParam(m, iter, &p->response_id) &&
+ ReadParam(m, iter, &p->serialized_value) &&
+ ReadParam(m, iter, &p->key) &&
+ ReadParam(m, iter, &p->add_only) &&
+ ReadParam(m, iter, &p->transaction_id);
+}
+
+void ParamTraits<IndexedDBHostMsg_ObjectStorePut_Params>::Log(
+ const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.idb_object_store_id, l);
+ l->append(", ");
+ LogParam(p.response_id, l);
+ l->append(", ");
+ LogParam(p.serialized_value, l);
+ l->append(", ");
+ LogParam(p.key, l);
+ l->append(", ");
+ LogParam(p.add_only, l);
+ l->append(", ");
+ LogParam(p.transaction_id, l);
+ l->append(")");
+}
+
+void ParamTraits<IndexedDBHostMsg_ObjectStoreCreateIndex_Params>::Write(
+ Message* m,
+ const param_type& p) {
+ WriteParam(m, p.name);
+ WriteParam(m, p.key_path);
+ WriteParam(m, p.unique);
+ WriteParam(m, p.transaction_id);
+ WriteParam(m, p.idb_object_store_id);
+}
+
+bool ParamTraits<IndexedDBHostMsg_ObjectStoreCreateIndex_Params>::Read(
+ const Message* m,
+ void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->name) &&
+ ReadParam(m, iter, &p->key_path) &&
+ ReadParam(m, iter, &p->unique) &&
+ ReadParam(m, iter, &p->transaction_id) &&
+ ReadParam(m, iter, &p->idb_object_store_id);
+}
+
+void ParamTraits<IndexedDBHostMsg_ObjectStoreCreateIndex_Params>::Log(
+ const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.name, l);
+ l->append(", ");
+ LogParam(p.key_path, l);
+ l->append(", ");
+ LogParam(p.unique, l);
+ l->append(", ");
+ LogParam(p.transaction_id, l);
+ l->append(", ");
+ LogParam(p.idb_object_store_id, l);
+ l->append(")");
+}
+
+void ParamTraits<IndexedDBHostMsg_ObjectStoreOpenCursor_Params>::Write(
+ Message* m,
+ const param_type& p) {
+ WriteParam(m, p.response_id);
+ WriteParam(m, p.lower_key);
+ WriteParam(m, p.upper_key);
+ WriteParam(m, p.lower_open);
+ WriteParam(m, p.upper_open);
+ WriteParam(m, p.direction);
+ WriteParam(m, p.idb_object_store_id);
+ WriteParam(m, p.transaction_id);
+}
+
+bool ParamTraits<IndexedDBHostMsg_ObjectStoreOpenCursor_Params>::Read(
+ const Message* m,
+ void** iter,
+ param_type* p) {
+ return
+ ReadParam(m, iter, &p->response_id) &&
+ ReadParam(m, iter, &p->lower_key) &&
+ ReadParam(m, iter, &p->upper_key) &&
+ ReadParam(m, iter, &p->lower_open) &&
+ ReadParam(m, iter, &p->upper_open) &&
+ ReadParam(m, iter, &p->direction) &&
+ ReadParam(m, iter, &p->idb_object_store_id) &&
+ ReadParam(m, iter, &p->transaction_id);
+}
+
+void ParamTraits<IndexedDBHostMsg_ObjectStoreOpenCursor_Params>::Log(
+ const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.response_id, l);
+ l->append(", ");
+ LogParam(p.lower_key, l);
+ l->append(", ");
+ LogParam(p.upper_key, l);
+ l->append(", ");
+ LogParam(p.lower_open, l);
+ l->append(", ");
+ LogParam(p.upper_open, l);
+ l->append(", ");
+ LogParam(p.direction, l);
+ l->append(", ");
+ LogParam(p.idb_object_store_id, l);
+ l->append(",");
+ LogParam(p.transaction_id, l);
+ l->append(")");
+}
+
+} // namespace IPC
diff --git a/chrome/common/indexed_db_messages.h b/chrome/common/indexed_db_messages.h
new file mode 100644
index 0000000..8eb77eb
--- /dev/null
+++ b/chrome/common/indexed_db_messages.h
@@ -0,0 +1,493 @@
+// 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.
+
+#ifndef CHROME_COMMON_INDEXED_DB_MESSAGES_H_
+#define CHROME_COMMON_INDEXED_DB_MESSAGES_H_
+#pragma once
+
+#include "chrome/common/indexed_db_key.h"
+#include "chrome/common/indexed_db_param_traits.h"
+#include "chrome/common/serialized_script_value.h"
+#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_param_traits.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebExceptionCode.h"
+
+#define IPC_MESSAGE_START IndexedDBMsgStart
+
+// Used to open an indexed database.
+struct IndexedDBHostMsg_FactoryOpen_Params {
+ IndexedDBHostMsg_FactoryOpen_Params();
+ ~IndexedDBHostMsg_FactoryOpen_Params();
+
+ // The routing ID of the view initiating the open.
+ int32 routing_id;
+
+ // The response should have this id.
+ int32 response_id;
+
+ // The origin doing the initiating.
+ string16 origin;
+
+ // The name of the database.
+ string16 name;
+
+ // The maximum size of the database.
+ uint64 maximum_size;
+};
+
+// Used to create an object store.
+struct IndexedDBHostMsg_DatabaseCreateObjectStore_Params {
+ IndexedDBHostMsg_DatabaseCreateObjectStore_Params();
+ ~IndexedDBHostMsg_DatabaseCreateObjectStore_Params();
+
+ // The name of the object store.
+ string16 name;
+
+ // The keyPath of the object store.
+ NullableString16 key_path;
+
+ // Whether the object store created should have a key generator.
+ bool auto_increment;
+
+ // The transaction this is associated with.
+ int32 transaction_id;
+
+ // The database the object store belongs to.
+ int32 idb_database_id;
+};
+
+// Used to open both cursors and object cursors in IndexedDB.
+struct IndexedDBHostMsg_IndexOpenCursor_Params {
+ IndexedDBHostMsg_IndexOpenCursor_Params();
+ ~IndexedDBHostMsg_IndexOpenCursor_Params();
+
+ // The response should have this id.
+ int32 response_id;
+
+ // The serialized lower key.
+ IndexedDBKey lower_key;
+
+ // The serialized upper key.
+ IndexedDBKey upper_key;
+
+ // Is the lower bound open?
+ bool lower_open;
+
+ // Is the upper bound open?
+ bool upper_open;
+
+ // The direction of this cursor.
+ int32 direction;
+
+ // The index the index belongs to.
+ int32 idb_index_id;
+
+ // The transaction this request belongs to.
+ int transaction_id;
+};
+
+// Used to set a value in an object store.
+struct IndexedDBHostMsg_ObjectStorePut_Params {
+ IndexedDBHostMsg_ObjectStorePut_Params();
+ ~IndexedDBHostMsg_ObjectStorePut_Params();
+
+ // The object store's id.
+ int32 idb_object_store_id;
+
+ // The id any response should contain.
+ int32 response_id;
+
+ // The value to set.
+ SerializedScriptValue serialized_value;
+
+ // The key to set it on (may not be "valid"/set in some cases).
+ IndexedDBKey key;
+
+ // If it already exists, don't update (just return an error).
+ bool add_only;
+
+ // The transaction it's associated with.
+ int transaction_id;
+};
+
+// Used to create an index.
+struct IndexedDBHostMsg_ObjectStoreCreateIndex_Params {
+ IndexedDBHostMsg_ObjectStoreCreateIndex_Params();
+ ~IndexedDBHostMsg_ObjectStoreCreateIndex_Params();
+
+ // The name of the index.
+ string16 name;
+
+ // The keyPath of the index.
+ NullableString16 key_path;
+
+ // Whether the index created has unique keys.
+ bool unique;
+
+ // The transaction this is associated with.
+ int32 transaction_id;
+
+ // The object store the index belongs to.
+ int32 idb_object_store_id;
+};
+
+// Used to open an IndexedDB cursor.
+struct IndexedDBHostMsg_ObjectStoreOpenCursor_Params {
+ IndexedDBHostMsg_ObjectStoreOpenCursor_Params();
+ ~IndexedDBHostMsg_ObjectStoreOpenCursor_Params();
+
+ // The response should have this id.
+ int32 response_id;
+
+ // The serialized lower key.
+ IndexedDBKey lower_key;
+
+ // The serialized upper key.
+ IndexedDBKey upper_key;
+
+ // Is the lower bound open?
+ bool lower_open;
+
+ // Is the upper bound open?
+ bool upper_open;
+
+ // The direction of this cursor.
+ int32 direction;
+
+ // The object store the cursor belongs to.
+ int32 idb_object_store_id;
+
+ // The transaction this request belongs to.
+ int transaction_id;
+};
+
+namespace IPC {
+template <>
+struct ParamTraits<IndexedDBHostMsg_FactoryOpen_Params> {
+ typedef IndexedDBHostMsg_FactoryOpen_Params param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct ParamTraits<IndexedDBHostMsg_DatabaseCreateObjectStore_Params> {
+ typedef IndexedDBHostMsg_DatabaseCreateObjectStore_Params param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct ParamTraits<IndexedDBHostMsg_IndexOpenCursor_Params> {
+ typedef IndexedDBHostMsg_IndexOpenCursor_Params param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct ParamTraits<IndexedDBHostMsg_ObjectStorePut_Params> {
+ typedef IndexedDBHostMsg_ObjectStorePut_Params param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct ParamTraits<IndexedDBHostMsg_ObjectStoreCreateIndex_Params> {
+ typedef IndexedDBHostMsg_ObjectStoreCreateIndex_Params param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct ParamTraits<IndexedDBHostMsg_ObjectStoreOpenCursor_Params> {
+ typedef IndexedDBHostMsg_ObjectStoreOpenCursor_Params param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
+};
+
+} // namespace IPC
+
+// Indexed DB messages sent from the browser to the renderer.
+
+// IDBCallback message handlers.
+IPC_MESSAGE_CONTROL1(IndexedDBMsg_CallbacksSuccessNull,
+ int32 /* response_id */)
+IPC_MESSAGE_CONTROL2(IndexedDBMsg_CallbacksSuccessIDBCursor,
+ int32 /* response_id */,
+ int32 /* cursor_id */)
+IPC_MESSAGE_CONTROL2(IndexedDBMsg_CallbacksSuccessIDBDatabase,
+ int32 /* response_id */,
+ int32 /* idb_database_id */)
+IPC_MESSAGE_CONTROL2(IndexedDBMsg_CallbacksSuccessIndexedDBKey,
+ int32 /* response_id */,
+ IndexedDBKey /* indexed_db_key */)
+IPC_MESSAGE_CONTROL2(IndexedDBMsg_CallbacksSuccessIDBIndex,
+ int32 /* response_id */,
+ int32 /* idb_index_id */)
+IPC_MESSAGE_CONTROL2(IndexedDBMsg_CallbacksSuccessIDBObjectStore,
+ int32 /* response_id */,
+ int32 /* idb_object_store_id */)
+IPC_MESSAGE_CONTROL2(IndexedDBMsg_CallbacksSuccessIDBTransaction,
+ int32 /* response_id */,
+ int32 /* idb_transaction_id */)
+IPC_MESSAGE_CONTROL2(IndexedDBMsg_CallbacksSuccessSerializedScriptValue,
+ int32 /* response_id */,
+ SerializedScriptValue /* serialized_script_value */)
+IPC_MESSAGE_CONTROL3(IndexedDBMsg_CallbacksError,
+ int32 /* response_id */,
+ int /* code */,
+ string16 /* message */)
+
+// IDBTransactionCallback message handlers.
+IPC_MESSAGE_CONTROL1(IndexedDBMsg_TransactionCallbacksAbort,
+ int32 /* transaction_id */)
+IPC_MESSAGE_CONTROL1(IndexedDBMsg_TransactionCallbacksComplete,
+ int32 /* transaction_id */)
+IPC_MESSAGE_CONTROL1(IndexedDBMsg_TransactionCallbacksTimeout,
+ int32 /* transaction_id */)
+
+
+// Indexed DB messages sent from the renderer to the browser.
+
+// WebIDBCursor::direction() message.
+IPC_SYNC_MESSAGE_CONTROL1_1(IndexedDBHostMsg_CursorDirection,
+ int32, /* idb_cursor_id */
+ int32 /* direction */)
+
+// WebIDBCursor::key() message.
+IPC_SYNC_MESSAGE_CONTROL1_1(IndexedDBHostMsg_CursorKey,
+ int32, /* idb_cursor_id */
+ IndexedDBKey /* key */)
+
+// WebIDBCursor::value() message.
+IPC_SYNC_MESSAGE_CONTROL1_2(IndexedDBHostMsg_CursorValue,
+ int32, /* idb_cursor_id */
+ SerializedScriptValue, /* script_value */
+ IndexedDBKey /* key */)
+
+// WebIDBCursor::update() message.
+IPC_SYNC_MESSAGE_CONTROL3_1(IndexedDBHostMsg_CursorUpdate,
+ int32, /* idb_cursor_id */
+ int32, /* response_id */
+ SerializedScriptValue, /* value */
+ WebKit::WebExceptionCode /* ec */)
+
+// WebIDBCursor::continue() message.
+IPC_SYNC_MESSAGE_CONTROL3_1(IndexedDBHostMsg_CursorContinue,
+ int32, /* idb_cursor_id */
+ int32, /* response_id */
+ IndexedDBKey, /* key */
+ WebKit::WebExceptionCode /* ec */)
+
+// WebIDBCursor::remove() message.
+IPC_SYNC_MESSAGE_CONTROL2_1(IndexedDBHostMsg_CursorDelete,
+ int32, /* idb_cursor_id */
+ int32, /* response_id */
+ WebKit::WebExceptionCode /* ec */)
+
+// WebIDBFactory::open() message.
+IPC_MESSAGE_CONTROL1(IndexedDBHostMsg_FactoryOpen,
+ IndexedDBHostMsg_FactoryOpen_Params)
+
+// WebIDBDatabase::name() message.
+IPC_SYNC_MESSAGE_CONTROL1_1(IndexedDBHostMsg_DatabaseName,
+ int32, /* idb_database_id */
+ string16 /* name */)
+
+// WebIDBDatabase::version() message.
+IPC_SYNC_MESSAGE_CONTROL1_1(IndexedDBHostMsg_DatabaseVersion,
+ int32, /* idb_database_id */
+ string16 /* version */)
+
+// WebIDBDatabase::objectStoreNames() message.
+IPC_SYNC_MESSAGE_CONTROL1_1(IndexedDBHostMsg_DatabaseObjectStoreNames,
+ int32, /* idb_database_id */
+ std::vector<string16> /* objectStoreNames */)
+
+// WebIDBDatabase::createObjectStore() message.
+IPC_SYNC_MESSAGE_CONTROL1_2(IndexedDBHostMsg_DatabaseCreateObjectStore,
+ IndexedDBHostMsg_DatabaseCreateObjectStore_Params,
+ int32, /* object_store_id */
+ WebKit::WebExceptionCode /* ec */)
+
+// WebIDBDatabase::removeObjectStore() message.
+IPC_SYNC_MESSAGE_CONTROL3_1(IndexedDBHostMsg_DatabaseDeleteObjectStore,
+ int32, /* idb_database_id */
+ string16, /* name */
+ int32, /* transaction_id */
+ WebKit::WebExceptionCode /* ec */)
+
+// WebIDBDatabase::setVersion() message.
+IPC_SYNC_MESSAGE_CONTROL3_1(IndexedDBHostMsg_DatabaseSetVersion,
+ int32, /* idb_database_id */
+ int32, /* response_id */
+ string16, /* version */
+ WebKit::WebExceptionCode /* ec */)
+
+// WebIDBDatabase::transaction() message.
+// TODO: make this message async. Have the renderer create a
+// temporary ID and keep a map in the browser process of real
+// IDs to temporary IDs. We can then update the transaction
+// to its real ID asynchronously.
+IPC_SYNC_MESSAGE_CONTROL4_2(IndexedDBHostMsg_DatabaseTransaction,
+ int32, /* idb_database_id */
+ std::vector<string16>, /* object_stores */
+ int32, /* mode */
+ int32, /* timeout */
+ int32, /* idb_transaction_id */
+ WebKit::WebExceptionCode /* ec */)
+
+// WebIDBDatabase::~WebIDBDatabase() message.
+IPC_MESSAGE_CONTROL1(IndexedDBHostMsg_DatabaseDestroyed,
+ int32 /* idb_database_id */)
+
+// WebIDBIndex::name() message.
+IPC_SYNC_MESSAGE_CONTROL1_1(IndexedDBHostMsg_IndexName,
+ int32, /* idb_index_id */
+ string16 /* name */)
+
+// WebIDBIndex::storeName() message.
+IPC_SYNC_MESSAGE_CONTROL1_1(IndexedDBHostMsg_IndexStoreName,
+ int32, /* idb_index_id */
+ string16 /* store_name */)
+
+// WebIDBIndex::keyPath() message.
+IPC_SYNC_MESSAGE_CONTROL1_1(IndexedDBHostMsg_IndexKeyPath,
+ int32, /* idb_index_id */
+ NullableString16 /* key_path */)
+
+// WebIDBIndex::unique() message.
+IPC_SYNC_MESSAGE_CONTROL1_1(IndexedDBHostMsg_IndexUnique,
+ int32, /* idb_unique_id */
+ bool /* unique */)
+
+// WebIDBIndex::openObjectCursor() message.
+IPC_SYNC_MESSAGE_CONTROL1_1(IndexedDBHostMsg_IndexOpenObjectCursor,
+ IndexedDBHostMsg_IndexOpenCursor_Params,
+ WebKit::WebExceptionCode /* ec */)
+
+// WebIDBIndex::openKeyCursor() message.
+IPC_SYNC_MESSAGE_CONTROL1_1(IndexedDBHostMsg_IndexOpenKeyCursor,
+ IndexedDBHostMsg_IndexOpenCursor_Params,
+ WebKit::WebExceptionCode /* ec */)
+
+// WebIDBIndex::getObject() message.
+IPC_SYNC_MESSAGE_CONTROL4_1(IndexedDBHostMsg_IndexGetObject,
+ int32, /* idb_index_id */
+ int32, /* response_id */
+ IndexedDBKey, /* key */
+ int32, /* transaction_id */
+ WebKit::WebExceptionCode /* ec */)
+
+// WebIDBIndex::getKey() message.
+IPC_SYNC_MESSAGE_CONTROL4_1(IndexedDBHostMsg_IndexGetKey,
+ int32, /* idb_index_id */
+ int32, /* response_id */
+ IndexedDBKey, /* key */
+ int32, /* transaction_id */
+ WebKit::WebExceptionCode /* ec */)
+
+// WebIDBIndex::~WebIDBIndex() message.
+IPC_MESSAGE_CONTROL1(IndexedDBHostMsg_IndexDestroyed,
+ int32 /* idb_index_id */)
+
+// WebIDBObjectStore::name() message.
+IPC_SYNC_MESSAGE_CONTROL1_1(IndexedDBHostMsg_ObjectStoreName,
+ int32, /* idb_object_store_id */
+ string16 /* name */)
+
+// WebIDBObjectStore::keyPath() message.
+IPC_SYNC_MESSAGE_CONTROL1_1(IndexedDBHostMsg_ObjectStoreKeyPath,
+ int32, /* idb_object_store_id */
+ NullableString16 /* keyPath */)
+
+// WebIDBObjectStore::indexNames() message.
+IPC_SYNC_MESSAGE_CONTROL1_1(IndexedDBHostMsg_ObjectStoreIndexNames,
+ int32, /* idb_object_store_id */
+ std::vector<string16> /* index_names */)
+
+// WebIDBObjectStore::get() message.
+IPC_SYNC_MESSAGE_CONTROL4_1(IndexedDBHostMsg_ObjectStoreGet,
+ int32, /* idb_object_store_id */
+ int32, /* response_id */
+ IndexedDBKey, /* key */
+ int32, /* transaction_id */
+ WebKit::WebExceptionCode /* ec */)
+
+// WebIDBObjectStore::put() message.
+IPC_SYNC_MESSAGE_CONTROL1_1(IndexedDBHostMsg_ObjectStorePut,
+ IndexedDBHostMsg_ObjectStorePut_Params,
+ WebKit::WebExceptionCode /* ec */)
+
+// WebIDBObjectStore::delete() message.
+IPC_SYNC_MESSAGE_CONTROL4_1(IndexedDBHostMsg_ObjectStoreDelete,
+ int32, /* idb_object_store_id */
+ int32, /* response_id */
+ IndexedDBKey, /* key */
+ int32, /* transaction_id */
+ WebKit::WebExceptionCode /* ec */)
+
+// WebIDBObjectStore::createIndex() message.
+IPC_SYNC_MESSAGE_CONTROL1_2(IndexedDBHostMsg_ObjectStoreCreateIndex,
+ IndexedDBHostMsg_ObjectStoreCreateIndex_Params,
+ int32, /* index_id */
+ WebKit::WebExceptionCode /* ec */)
+
+// WebIDBObjectStore::index() message.
+IPC_SYNC_MESSAGE_CONTROL2_2(IndexedDBHostMsg_ObjectStoreIndex,
+ int32, /* idb_object_store_id */
+ string16, /* name */
+ int32, /* idb_index_id */
+ WebKit::WebExceptionCode /* ec */)
+
+// WebIDBObjectStore::deleteIndex() message.
+IPC_SYNC_MESSAGE_CONTROL3_1(IndexedDBHostMsg_ObjectStoreDeleteIndex,
+ int32, /* idb_object_store_id */
+ string16, /* name */
+ int32, /* transaction_id */
+ WebKit::WebExceptionCode /* ec */)
+
+// WebIDBObjectStore::openCursor() message.
+IPC_SYNC_MESSAGE_CONTROL1_1(IndexedDBHostMsg_ObjectStoreOpenCursor,
+ IndexedDBHostMsg_ObjectStoreOpenCursor_Params,
+ WebKit::WebExceptionCode /* ec */)
+
+// WebIDBObjectStore::~WebIDBObjectStore() message.
+IPC_MESSAGE_CONTROL1(IndexedDBHostMsg_ObjectStoreDestroyed,
+ int32 /* idb_object_store_id */)
+
+// WebIDBDatabase::~WebIDBCursor() message.
+IPC_MESSAGE_CONTROL1(IndexedDBHostMsg_CursorDestroyed,
+ int32 /* idb_cursor_id */)
+
+// IDBTransaction::ObjectStore message.
+IPC_SYNC_MESSAGE_CONTROL2_2(IndexedDBHostMsg_TransactionObjectStore,
+ int32, /* transaction_id */
+ string16, /* name */
+ int32, /* object_store_id */
+ WebKit::WebExceptionCode /* ec */)
+
+// WebIDBTransaction::mode() message.
+IPC_SYNC_MESSAGE_CONTROL1_1(IndexedDBHostMsg_TransactionMode,
+ int32, /* idb_transaction_id */
+ int /* mode */)
+
+// WebIDBTransaction::abort() message.
+IPC_MESSAGE_CONTROL1(IndexedDBHostMsg_TransactionAbort,
+ int32 /* idb_transaction_id */)
+
+// IDBTransaction::DidCompleteTaskEvents() message.
+IPC_MESSAGE_CONTROL1(IndexedDBHostMsg_TransactionDidCompleteTaskEvents,
+ int32 /* idb_transaction_id */)
+
+// WebIDBTransaction::~WebIDBTransaction() message.
+IPC_MESSAGE_CONTROL1(IndexedDBHostMsg_TransactionDestroyed,
+ int32 /* idb_transaction_id */)
+
+#endif // CHROME_COMMON_INDEXED_DB_MESSAGES_H_
diff --git a/chrome/common/indexed_db_param_traits.cc b/chrome/common/indexed_db_param_traits.cc
index 3bab96e..70c10ff 100644
--- a/chrome/common/indexed_db_param_traits.cc
+++ b/chrome/common/indexed_db_param_traits.cc
@@ -50,6 +50,7 @@ void ParamTraits<IndexedDBKey>::Write(Message* m, const param_type& p) {
WriteParam(m, int(p.type()));
// TODO(jorlow): Technically, we only need to pack the type being used.
WriteParam(m, p.string());
+ WriteParam(m, p.date());
WriteParam(m, p.number());
}
@@ -58,11 +59,14 @@ bool ParamTraits<IndexedDBKey>::Read(const Message* m,
param_type* r) {
int type;
string16 string;
+ double date;
double number;
bool ok =
ReadParam(m, iter, &type) &&
ReadParam(m, iter, &string) &&
+ ReadParam(m, iter, &date) &&
ReadParam(m, iter, &number);
+
if (!ok)
return false;
switch (type) {
@@ -70,10 +74,13 @@ bool ParamTraits<IndexedDBKey>::Read(const Message* m,
r->SetNull();
return true;
case WebKit::WebIDBKey::StringType:
- r->Set(string);
+ r->SetString(string);
+ return true;
+ case WebKit::WebIDBKey::DateType:
+ r->SetDate(date);
return true;
case WebKit::WebIDBKey::NumberType:
- r->Set(number);
+ r->SetNumber(number);
return true;
case WebKit::WebIDBKey::InvalidType:
r->SetInvalid();
@@ -89,6 +96,8 @@ void ParamTraits<IndexedDBKey>::Log(const param_type& p, std::string* l) {
l->append(", ");
LogParam(p.string(), l);
l->append(", ");
+ LogParam(p.date(), l);
+ l->append(", ");
LogParam(p.number(), l);
l->append(")");
}
diff --git a/chrome/common/json_pref_store.cc b/chrome/common/json_pref_store.cc
index d68307f..f5ff728 100644
--- a/chrome/common/json_pref_store.cc
+++ b/chrome/common/json_pref_store.cc
@@ -30,7 +30,50 @@ JsonPrefStore::~JsonPrefStore() {
writer_.DoScheduledWrite();
}
-PrefStore::PrefReadError JsonPrefStore::ReadPrefs() {
+PrefStore::ReadResult JsonPrefStore::GetValue(const std::string& key,
+ Value** result) const {
+ return prefs_->Get(key, result) ? READ_OK : READ_NO_VALUE;
+}
+
+void JsonPrefStore::AddObserver(PrefStore::Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void JsonPrefStore::RemoveObserver(PrefStore::Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void JsonPrefStore::SetValue(const std::string& key, Value* value) {
+ DCHECK(value);
+ scoped_ptr<Value> new_value(value);
+ Value* old_value = NULL;
+ prefs_->Get(key, &old_value);
+ if (!old_value || !value->Equals(old_value)) {
+ prefs_->Set(key, new_value.release());
+ FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key));
+ }
+}
+
+void JsonPrefStore::SetValueSilently(const std::string& key, Value* value) {
+ DCHECK(value);
+ scoped_ptr<Value> new_value(value);
+ Value* old_value = NULL;
+ prefs_->Get(key, &old_value);
+ if (!old_value || !value->Equals(old_value))
+ prefs_->Set(key, new_value.release());
+}
+
+void JsonPrefStore::RemoveValue(const std::string& key) {
+ if (prefs_->Remove(key, NULL)) {
+ FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key));
+ }
+}
+
+bool JsonPrefStore::ReadOnly() const {
+ return read_only_;
+}
+
+PersistentPrefStore::PrefReadError JsonPrefStore::ReadPrefs() {
if (path_.empty()) {
read_only_ = true;
return PREF_READ_ERROR_FILE_NOT_SPECIFIED;
diff --git a/chrome/common/json_pref_store.h b/chrome/common/json_pref_store.h
index 0407d1e..a587ba0 100644
--- a/chrome/common/json_pref_store.h
+++ b/chrome/common/json_pref_store.h
@@ -8,9 +8,12 @@
#include <string>
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/observer_list.h"
#include "base/scoped_ptr.h"
-#include "chrome/common/pref_store.h"
#include "chrome/common/important_file_writer.h"
+#include "chrome/common/persistent_pref_store.h"
namespace base {
class MessageLoopProxy;
@@ -18,8 +21,10 @@ class MessageLoopProxy;
class DictionaryValue;
class FilePath;
+class Value;
-class JsonPrefStore : public PrefStore,
+// A writable PrefStore implementation that is used for user preferences.
+class JsonPrefStore : public PersistentPrefStore,
public ImportantFileWriter::DataSerializer {
public:
// |file_message_loop_proxy| is the MessageLoopProxy for a thread on which
@@ -28,21 +33,24 @@ class JsonPrefStore : public PrefStore,
base::MessageLoopProxy* file_message_loop_proxy);
virtual ~JsonPrefStore();
- // PrefStore methods:
- virtual bool ReadOnly() { return read_only_; }
-
- virtual DictionaryValue* prefs() const { return prefs_.get(); }
+ // PrefStore overrides:
+ virtual ReadResult GetValue(const std::string& key, Value** result) const;
+ virtual void AddObserver(PrefStore::Observer* observer);
+ virtual void RemoveObserver(PrefStore::Observer* observer);
+ // PersistentPrefStore overrides:
+ virtual void SetValue(const std::string& key, Value* value);
+ virtual void SetValueSilently(const std::string& key, Value* value);
+ virtual void RemoveValue(const std::string& key);
+ virtual bool ReadOnly() const;
virtual PrefReadError ReadPrefs();
-
virtual bool WritePrefs();
-
virtual void ScheduleWritePrefs();
- // ImportantFileWriter::DataSerializer methods:
- virtual bool SerializeData(std::string* data);
-
private:
+ // ImportantFileWriter::DataSerializer overrides:
+ virtual bool SerializeData(std::string* output);
+
FilePath path_;
scoped_ptr<DictionaryValue> prefs_;
@@ -51,6 +59,10 @@ class JsonPrefStore : public PrefStore,
// Helper for safely writing pref data.
ImportantFileWriter writer_;
+
+ ObserverList<PrefStore::Observer, true> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(JsonPrefStore);
};
#endif // CHROME_COMMON_JSON_PREF_STORE_H_
diff --git a/chrome/common/json_pref_store_unittest.cc b/chrome/common/json_pref_store_unittest.cc
index e38aba2..326e32d 100644
--- a/chrome/common/json_pref_store_unittest.cc
+++ b/chrome/common/json_pref_store_unittest.cc
@@ -54,9 +54,9 @@ TEST_F(JsonPrefStoreTest, NonExistentFile) {
FilePath bogus_input_file = data_dir_.AppendASCII("read.txt");
ASSERT_FALSE(file_util::PathExists(bogus_input_file));
JsonPrefStore pref_store(bogus_input_file, message_loop_proxy_.get());
- EXPECT_EQ(PrefStore::PREF_READ_ERROR_NO_FILE, pref_store.ReadPrefs());
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
+ pref_store.ReadPrefs());
EXPECT_FALSE(pref_store.ReadOnly());
- EXPECT_TRUE(pref_store.prefs()->empty());
}
// Test fallback behavior for an invalid file.
@@ -65,9 +65,9 @@ TEST_F(JsonPrefStoreTest, InvalidFile) {
FilePath invalid_file = test_dir_.AppendASCII("invalid.json");
ASSERT_TRUE(file_util::CopyFile(invalid_file_original, invalid_file));
JsonPrefStore pref_store(invalid_file, message_loop_proxy_.get());
- EXPECT_EQ(PrefStore::PREF_READ_ERROR_JSON_PARSE, pref_store.ReadPrefs());
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE,
+ pref_store.ReadPrefs());
EXPECT_FALSE(pref_store.ReadOnly());
- EXPECT_TRUE(pref_store.prefs()->empty());
// The file should have been moved aside.
EXPECT_FALSE(file_util::PathExists(invalid_file));
@@ -85,9 +85,8 @@ TEST_F(JsonPrefStoreTest, Basic) {
FilePath input_file = test_dir_.AppendASCII("write.json");
ASSERT_TRUE(file_util::PathExists(input_file));
JsonPrefStore pref_store(input_file, message_loop_proxy_.get());
- ASSERT_EQ(PrefStore::PREF_READ_ERROR_NONE, pref_store.ReadPrefs());
+ ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store.ReadPrefs());
ASSERT_FALSE(pref_store.ReadOnly());
- DictionaryValue* prefs = pref_store.prefs();
// The JSON file looks like this:
// {
@@ -105,38 +104,55 @@ TEST_F(JsonPrefStoreTest, Basic) {
std::string cnn("http://www.cnn.com");
+ Value* actual;
+ EXPECT_EQ(PrefStore::READ_OK,
+ pref_store.GetValue(prefs::kHomePage, &actual));
std::string string_value;
- EXPECT_TRUE(prefs->GetString(prefs::kHomePage, &string_value));
+ EXPECT_TRUE(actual->GetAsString(&string_value));
EXPECT_EQ(cnn, string_value);
const char kSomeDirectory[] = "some_directory";
+ EXPECT_EQ(PrefStore::READ_OK, pref_store.GetValue(kSomeDirectory, &actual));
FilePath::StringType path;
- EXPECT_TRUE(prefs->GetString(kSomeDirectory, &path));
+ EXPECT_TRUE(actual->GetAsString(&path));
EXPECT_EQ(FilePath::StringType(FILE_PATH_LITERAL("/usr/local/")), path);
FilePath some_path(FILE_PATH_LITERAL("/usr/sbin/"));
- prefs->SetString(kSomeDirectory, some_path.value());
- EXPECT_TRUE(prefs->GetString(kSomeDirectory, &path));
+
+ pref_store.SetValue(kSomeDirectory,
+ Value::CreateStringValue(some_path.value()));
+ EXPECT_EQ(PrefStore::READ_OK, pref_store.GetValue(kSomeDirectory, &actual));
+ EXPECT_TRUE(actual->GetAsString(&path));
EXPECT_EQ(some_path.value(), path);
// Test reading some other data types from sub-dictionaries.
- bool boolean;
- EXPECT_TRUE(prefs->GetBoolean(kNewWindowsInTabs, &boolean));
+ EXPECT_EQ(PrefStore::READ_OK,
+ pref_store.GetValue(kNewWindowsInTabs, &actual));
+ bool boolean = false;
+ EXPECT_TRUE(actual->GetAsBoolean(&boolean));
EXPECT_TRUE(boolean);
- prefs->SetBoolean(kNewWindowsInTabs, false);
- EXPECT_TRUE(prefs->GetBoolean(kNewWindowsInTabs, &boolean));
+ pref_store.SetValue(kNewWindowsInTabs,
+ Value::CreateBooleanValue(false));
+ EXPECT_EQ(PrefStore::READ_OK,
+ pref_store.GetValue(kNewWindowsInTabs, &actual));
+ EXPECT_TRUE(actual->GetAsBoolean(&boolean));
EXPECT_FALSE(boolean);
- int integer;
- EXPECT_TRUE(prefs->GetInteger(kMaxTabs, &integer));
+ EXPECT_EQ(PrefStore::READ_OK, pref_store.GetValue(kMaxTabs, &actual));
+ int integer = 0;
+ EXPECT_TRUE(actual->GetAsInteger(&integer));
EXPECT_EQ(20, integer);
- prefs->SetInteger(kMaxTabs, 10);
- EXPECT_TRUE(prefs->GetInteger(kMaxTabs, &integer));
+ pref_store.SetValue(kMaxTabs, Value::CreateIntegerValue(10));
+ EXPECT_EQ(PrefStore::READ_OK, pref_store.GetValue(kMaxTabs, &actual));
+ EXPECT_TRUE(actual->GetAsInteger(&integer));
EXPECT_EQ(10, integer);
- prefs->SetString(kLongIntPref, base::Int64ToString(214748364842LL));
- EXPECT_TRUE(prefs->GetString(kLongIntPref, &string_value));
+ pref_store.SetValue(kLongIntPref,
+ Value::CreateStringValue(
+ base::Int64ToString(214748364842LL)));
+ EXPECT_EQ(PrefStore::READ_OK, pref_store.GetValue(kLongIntPref, &actual));
+ EXPECT_TRUE(actual->GetAsString(&string_value));
int64 value;
base::StringToInt64(string_value, &value);
EXPECT_EQ(214748364842LL, value);
diff --git a/chrome/common/json_schema_validator.cc b/chrome/common/json_schema_validator.cc
index ee28a89..a76b2d9 100644
--- a/chrome/common/json_schema_validator.cc
+++ b/chrome/common/json_schema_validator.cc
@@ -159,6 +159,7 @@ JSONSchemaValidator::JSONSchemaValidator(DictionaryValue* schema,
}
}
+JSONSchemaValidator::~JSONSchemaValidator() {}
bool JSONSchemaValidator::Validate(Value* instance) {
errors_.clear();
diff --git a/chrome/common/json_schema_validator.h b/chrome/common/json_schema_validator.h
index 9af31fb..68030f8 100644
--- a/chrome/common/json_schema_validator.h
+++ b/chrome/common/json_schema_validator.h
@@ -113,6 +113,8 @@ class JSONSchemaValidator {
// not be used with untrusted schemas.
JSONSchemaValidator(DictionaryValue* schema, ListValue* types);
+ ~JSONSchemaValidator();
+
// Whether the validator allows additional items for objects and lists, beyond
// those defined by their schema, by default.
//
diff --git a/chrome/common/json_value_serializer.h b/chrome/common/json_value_serializer.h
index 11b7b7a..e0c9569 100644
--- a/chrome/common/json_value_serializer.h
+++ b/chrome/common/json_value_serializer.h
@@ -33,12 +33,12 @@ class JSONStringValueSerializer : public ValueSerializer {
allow_trailing_comma_(false) {
}
- ~JSONStringValueSerializer();
+ virtual ~JSONStringValueSerializer();
// Attempt to serialize the data structure represented by Value into
// JSON. If the return value is true, the result will have been written
// into the string passed into the constructor.
- bool Serialize(const Value& root);
+ virtual bool Serialize(const Value& root);
// Attempt to deserialize the data structure encoded in the string passed
// in to the constructor into a structure of Value objects. If the return
@@ -47,7 +47,7 @@ class JSONStringValueSerializer : public ValueSerializer {
// If |error_message| is non-null, it will be filled in with a formatted
// error message including the location of the error if appropriate.
// The caller takes ownership of the returned value.
- Value* Deserialize(int* error_code, std::string* error_message);
+ virtual Value* Deserialize(int* error_code, std::string* error_message);
void set_pretty_print(bool new_value) { pretty_print_ = new_value; }
bool pretty_print() { return pretty_print_; }
@@ -75,7 +75,7 @@ class JSONFileValueSerializer : public ValueSerializer {
explicit JSONFileValueSerializer(const FilePath& json_file_path)
: json_file_path_(json_file_path) {}
- ~JSONFileValueSerializer() {}
+ virtual ~JSONFileValueSerializer() {}
// DO NOT USE except in unit tests to verify the file was written properly.
// We should never serialize directly to a file since this will block the
@@ -85,7 +85,7 @@ class JSONFileValueSerializer : public ValueSerializer {
// Attempt to serialize the data structure represented by Value into
// JSON. If the return value is true, the result will have been written
// into the file whose name was passed into the constructor.
- bool Serialize(const Value& root);
+ virtual bool Serialize(const Value& root);
// Attempt to deserialize the data structure encoded in the file passed
// in to the constructor into a structure of Value objects. If the return
@@ -94,7 +94,7 @@ class JSONFileValueSerializer : public ValueSerializer {
// If |error_message| is non-null, it will be filled in with a formatted
// error message including the location of the error if appropriate.
// The caller takes ownership of the returned value.
- Value* Deserialize(int* error_code, std::string* error_message);
+ virtual Value* Deserialize(int* error_code, std::string* error_message);
// This enum is designed to safely overlap with JSONReader::JsonParseError.
enum JsonFileError {
diff --git a/chrome/common/logging_chrome.cc b/chrome/common/logging_chrome.cc
index 196c581..c607f21 100644
--- a/chrome/common/logging_chrome.cc
+++ b/chrome/common/logging_chrome.cc
@@ -164,23 +164,17 @@ FilePath SetUpSymlinkIfNeeded(const FilePath& symlink_path, bool new_log) {
target_path = GenerateTimestampedName(symlink_path, base::Time::Now());
// We don't care if the unlink fails; we're going to continue anyway.
- if (unlink(symlink_path.value().c_str()) == -1) {
+ if (::unlink(symlink_path.value().c_str()) == -1) {
if (symlink_exists) // only warn if we might expect it to succeed.
PLOG(WARNING) << "Unable to unlink " << symlink_path.value();
}
- if (symlink(target_path.value().c_str(),
- symlink_path.value().c_str()) == -1) {
+ if (!file_util::CreateSymbolicLink(target_path, symlink_path)) {
PLOG(ERROR) << "Unable to create symlink " << symlink_path.value()
<< " pointing at " << target_path.value();
}
} else {
- char buf[PATH_MAX];
- ssize_t count = readlink(symlink_path.value().c_str(), buf, arraysize(buf));
- if (count > 0) {
- target_path = FilePath(FilePath::StringType(buf, count));
- } else {
+ if (!file_util::ReadSymbolicLink(symlink_path, &target_path))
PLOG(ERROR) << "Unable to read symlink " << symlink_path.value();
- }
}
return target_path;
}
@@ -244,7 +238,7 @@ void InitChromeLogging(const CommandLine& command_line,
"Attempted to initialize logging when it was already initialized.";
#if defined(OS_POSIX) && defined(IPC_MESSAGE_LOG_ENABLED)
- IPC::Logging::SetLoggerFunctions(g_log_function_mapping);
+ IPC::Logging::set_log_function_map(&g_log_function_mapping);
#endif
FilePath log_path = GetLogFileName();
diff --git a/chrome/common/message_router.cc b/chrome/common/message_router.cc
index 6bd6e95..b3ea596 100644
--- a/chrome/common/message_router.cc
+++ b/chrome/common/message_router.cc
@@ -10,9 +10,10 @@ MessageRouter::MessageRouter() {
MessageRouter::~MessageRouter() {
}
-void MessageRouter::OnControlMessageReceived(const IPC::Message& msg) {
+bool MessageRouter::OnControlMessageReceived(const IPC::Message& msg) {
NOTREACHED() <<
"should override in subclass if you care about control messages";
+ return false;
}
bool MessageRouter::Send(IPC::Message* msg) {
@@ -30,12 +31,11 @@ void MessageRouter::RemoveRoute(int32 routing_id) {
routes_.Remove(routing_id);
}
-void MessageRouter::OnMessageReceived(const IPC::Message& msg) {
- if (msg.routing_id() == MSG_ROUTING_CONTROL) {
- OnControlMessageReceived(msg);
- } else {
- RouteMessage(msg);
- }
+bool MessageRouter::OnMessageReceived(const IPC::Message& msg) {
+ if (msg.routing_id() == MSG_ROUTING_CONTROL)
+ return OnControlMessageReceived(msg);
+
+ return RouteMessage(msg);
}
bool MessageRouter::RouteMessage(const IPC::Message& msg) {
diff --git a/chrome/common/message_router.h b/chrome/common/message_router.h
index 6a61091..e6709be 100644
--- a/chrome/common/message_router.h
+++ b/chrome/common/message_router.h
@@ -34,10 +34,10 @@ class MessageRouter : public IPC::Channel::Listener,
virtual ~MessageRouter();
// Implemented by subclasses to handle control messages
- virtual void OnControlMessageReceived(const IPC::Message& msg);
+ virtual bool OnControlMessageReceived(const IPC::Message& msg);
// IPC::Channel::Listener implementation:
- virtual void OnMessageReceived(const IPC::Message& msg);
+ virtual bool OnMessageReceived(const IPC::Message& msg);
// Like OnMessageReceived, except it only handles routed messages. Returns
// true if the message was dispatched, or false if there was no listener for
diff --git a/chrome/common/metrics_helpers.cc b/chrome/common/metrics_helpers.cc
index 6462383..c452937 100644
--- a/chrome/common/metrics_helpers.cc
+++ b/chrome/common/metrics_helpers.cc
@@ -377,6 +377,10 @@ int64 MetricsLogBase::GetBuildTime() {
return integral_build_time;
}
+MetricsLog* MetricsLogBase::AsMetricsLog() {
+ return NULL;
+}
+
// TODO(JAR): A The following should really be part of the histogram class.
// Internal state is being needlessly exposed, and it would be hard to reuse
// this code. If we moved this into the Histogram class, then we could use
@@ -499,6 +503,10 @@ void MetricsServiceBase::SnapshotProblemResolved(int amount) {
std::abs(amount));
}
+HistogramSender::HistogramSender() {}
+
+HistogramSender::~HistogramSender() {}
+
void HistogramSender::TransmitAllHistograms(Histogram::Flags flag_to_set,
bool send_only_uma) {
StatisticsRecorder::Histograms histograms;
diff --git a/chrome/common/metrics_helpers.h b/chrome/common/metrics_helpers.h
index b261488..3de3fbd 100644
--- a/chrome/common/metrics_helpers.h
+++ b/chrome/common/metrics_helpers.h
@@ -99,9 +99,7 @@ class MetricsLogBase {
version_extension_ = extension;
}
- virtual MetricsLog* AsMetricsLog() {
- return NULL;
- }
+ virtual MetricsLog* AsMetricsLog();
protected:
class XmlWrapper;
@@ -185,8 +183,8 @@ class MetricsLogBase {
// onward.
class HistogramSender {
protected:
- HistogramSender() {}
- virtual ~HistogramSender() {}
+ HistogramSender();
+ virtual ~HistogramSender();
// Snapshot all histograms, and transmit the delta.
// The arguments allow a derived class to select only a subset for
diff --git a/chrome/common/mime_registry_messages.cc b/chrome/common/mime_registry_messages.cc
new file mode 100644
index 0000000..e8c2b9b
--- /dev/null
+++ b/chrome/common/mime_registry_messages.cc
@@ -0,0 +1,8 @@
+// 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.
+
+#include "chrome/common/common_param_traits.h"
+
+#define IPC_MESSAGE_IMPL
+#include "chrome/common/mime_registry_messages.h"
diff --git a/chrome/common/mime_registry_messages.h b/chrome/common/mime_registry_messages.h
new file mode 100644
index 0000000..636009f
--- /dev/null
+++ b/chrome/common/mime_registry_messages.h
@@ -0,0 +1,28 @@
+// 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.
+
+#ifndef CHROME_COMMON_MIME_REGISTRY_MESSAGES_H_
+#define CHROME_COMMON_MIME_REGISTRY_MESSAGES_H_
+#pragma once
+
+#include "base/file_path.h"
+#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_param_traits.h"
+
+#define IPC_MESSAGE_START MimeRegistryMsgStart
+
+// Mime registry messages sent from the renderer to the browser.
+
+// Sent to query MIME information.
+IPC_SYNC_MESSAGE_CONTROL1_1(MimeRegistryMsg_GetMimeTypeFromExtension,
+ FilePath::StringType /* extension */,
+ std::string /* mime_type */)
+IPC_SYNC_MESSAGE_CONTROL1_1(MimeRegistryMsg_GetMimeTypeFromFile,
+ FilePath /* file_path */,
+ std::string /* mime_type */)
+IPC_SYNC_MESSAGE_CONTROL1_1(MimeRegistryMsg_GetPreferredExtensionForMimeType,
+ std::string /* mime_type */,
+ FilePath::StringType /* extension */)
+
+#endif // CHROME_COMMON_MIME_REGISTRY_MESSAGES_H_
diff --git a/chrome/common/nacl_messages.cc b/chrome/common/nacl_messages.cc
index 291ed5a..1b2aff9 100644
--- a/chrome/common/nacl_messages.cc
+++ b/chrome/common/nacl_messages.cc
@@ -2,8 +2,5 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#define IPC_MESSAGE_IMPL
#include "chrome/common/nacl_messages.h"
-
-#define MESSAGES_INTERNAL_IMPL_FILE \
- "chrome/common/nacl_messages_internal.h"
-#include "ipc/ipc_message_impl_macros.h"
diff --git a/chrome/common/nacl_messages.h b/chrome/common/nacl_messages.h
index 11abf19..6c7c771 100644
--- a/chrome/common/nacl_messages.h
+++ b/chrome/common/nacl_messages.h
@@ -8,11 +8,6 @@
#define CHROME_COMMON_NACL_MESSAGES_H_
#pragma once
-#include "base/basictypes.h"
-#include "ipc/ipc_message_utils.h"
-
-#define MESSAGES_INTERNAL_FILE "chrome/common/nacl_messages_internal.h"
-#include "ipc/ipc_message_macros.h"
+#include "chrome/common/nacl_messages_internal.h"
#endif // CHROME_COMMON_NACL_MESSAGES_H_
-
diff --git a/chrome/common/nacl_messages_internal.h b/chrome/common/nacl_messages_internal.h
index e302118..ea96a03 100644
--- a/chrome/common/nacl_messages_internal.h
+++ b/chrome/common/nacl_messages_internal.h
@@ -6,25 +6,24 @@
#include "chrome/common/nacl_types.h"
#include "ipc/ipc_message_macros.h"
+#define IPC_MESSAGE_START NaClMsgStart
+
//-----------------------------------------------------------------------------
// NaClProcess messages
// These are messages sent from the browser to the NaCl process.
-IPC_BEGIN_MESSAGES(NaClProcess)
- // Tells the NaCl process to start.
- IPC_MESSAGE_CONTROL1(NaClProcessMsg_Start,
- std::vector<nacl::FileDescriptor> /* sockets */)
-
- // Tells the NaCl broker to launch a NaCl loader process.
- IPC_MESSAGE_CONTROL1(NaClProcessMsg_LaunchLoaderThroughBroker,
- std::wstring /* channel ID for the loader */)
+// Tells the NaCl process to start.
+IPC_MESSAGE_CONTROL1(NaClProcessMsg_Start,
+ std::vector<nacl::FileDescriptor> /* sockets */)
- // Notify the browser process that the loader was launched successfully.
- IPC_MESSAGE_CONTROL2(NaClProcessMsg_LoaderLaunched,
- std::wstring, /* channel ID for the loader */
- base::ProcessHandle /* loader process handle */)
+// Tells the NaCl broker to launch a NaCl loader process.
+IPC_MESSAGE_CONTROL1(NaClProcessMsg_LaunchLoaderThroughBroker,
+ std::wstring /* channel ID for the loader */)
- // Notify the broker that all loader processes have been terminated and it
- // should shutdown.
- IPC_MESSAGE_CONTROL0(NaClProcessMsg_StopBroker)
-IPC_END_MESSAGES(NaClProcess)
+// Notify the browser process that the loader was launched successfully.
+IPC_MESSAGE_CONTROL2(NaClProcessMsg_LoaderLaunched,
+ std::wstring, /* channel ID for the loader */
+ base::ProcessHandle /* loader process handle */)
+// Notify the broker that all loader processes have been terminated and it
+// should shutdown.
+IPC_MESSAGE_CONTROL0(NaClProcessMsg_StopBroker)
diff --git a/chrome/common/native_web_keyboard_event.h b/chrome/common/native_web_keyboard_event.h
index 4f6548d..1ed0cb1 100644
--- a/chrome/common/native_web_keyboard_event.h
+++ b/chrome/common/native_web_keyboard_event.h
@@ -59,6 +59,13 @@ struct NativeWebKeyboardEvent : public WebKit::WebKeyboardEvent {
// it is hit in ime mode.
// Currently, it's only used by Linux and Mac ports.
bool skip_in_browser;
+
+#if defined(OS_LINUX)
+ // True if the key event matches an edit command. In order to ensure the edit
+ // command always work in web page, the browser should not pre-handle this key
+ // event as a reserved accelerator. See http://crbug.com/54573
+ bool match_edit_command;
+#endif
};
#endif // CHROME_COMMON_NATIVE_WEB_KEYBOARD_EVENT_H_
diff --git a/chrome/common/native_web_keyboard_event_linux.cc b/chrome/common/native_web_keyboard_event_linux.cc
index 571550e..7165c98 100644
--- a/chrome/common/native_web_keyboard_event_linux.cc
+++ b/chrome/common/native_web_keyboard_event_linux.cc
@@ -33,12 +33,14 @@ void FreeEvent(GdkEventKey* event) {
NativeWebKeyboardEvent::NativeWebKeyboardEvent()
: os_event(NULL),
- skip_in_browser(false) {
+ skip_in_browser(false),
+ match_edit_command(false) {
}
NativeWebKeyboardEvent::NativeWebKeyboardEvent(const GdkEventKey* native_event)
: WebKeyboardEvent(WebInputEventFactory::keyboardEvent(native_event)),
- skip_in_browser(false) {
+ skip_in_browser(false),
+ match_edit_command(false) {
CopyEventTo(native_event, &os_event);
}
@@ -49,13 +51,15 @@ NativeWebKeyboardEvent::NativeWebKeyboardEvent(wchar_t character,
state,
time_stamp_seconds)),
os_event(NULL),
- skip_in_browser(false) {
+ skip_in_browser(false),
+ match_edit_command(false) {
}
NativeWebKeyboardEvent::NativeWebKeyboardEvent(
const NativeWebKeyboardEvent& other)
: WebKeyboardEvent(other),
- skip_in_browser(other.skip_in_browser) {
+ skip_in_browser(other.skip_in_browser),
+ match_edit_command(other.match_edit_command) {
CopyEventTo(other.os_event, &os_event);
}
@@ -67,6 +71,7 @@ NativeWebKeyboardEvent& NativeWebKeyboardEvent::operator=(
CopyEventTo(other.os_event, &os_event);
skip_in_browser = other.skip_in_browser;
+ match_edit_command = other.match_edit_command;
return *this;
}
diff --git a/chrome/common/navigation_gesture.h b/chrome/common/navigation_gesture.h
index e27ea4c..729f4d2 100644
--- a/chrome/common/navigation_gesture.h
+++ b/chrome/common/navigation_gesture.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// 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.
@@ -7,17 +7,14 @@
#pragma once
enum NavigationGesture {
- NavigationGestureUser, // User initiated navigation/load. This is not
- // currently used due to the untrustworthy nature
- // of userGestureHint (wasRunByUserGesture). See
- // bug 1051891.
- NavigationGestureAuto, // Non-user initiated navigation / load. For example
- // onload or setTimeout triggered document.location
- // changes, and form.submits. See bug 1046841 for
- // some cases that should be treated this way but
- // aren't yet.
- NavigationGestureUnknown, // What we assign when userGestureHint returns true
- // because we can't trust it.
+ // User initiated navigation/load.
+ NavigationGestureUser,
+ // Non-user initiated navigation/load. For example, onload- or
+ // setTimeout-triggered document.location changes and form.submits. See
+ // http://b/1046841 for some cases that should be treated this way but aren't.
+ NavigationGestureAuto,
+ // Initial state.
+ NavigationGestureUnknown,
};
#endif // CHROME_COMMON_NAVIGATION_GESTURE_H_
diff --git a/chrome/common/net/gaia/gaia_auth_fetcher.h b/chrome/common/net/gaia/gaia_auth_fetcher.h
index e0fe76e..1a1602d 100644
--- a/chrome/common/net/gaia/gaia_auth_fetcher.h
+++ b/chrome/common/net/gaia/gaia_auth_fetcher.h
@@ -74,12 +74,12 @@ class GaiaAuthFetcher : public URLFetcher::Delegate {
const std::string& info_key);
// Implementation of URLFetcher::Delegate
- void OnURLFetchComplete(const URLFetcher* source,
- const GURL& url,
- const URLRequestStatus& status,
- int response_code,
- const ResponseCookies& cookies,
- const std::string& data);
+ virtual void OnURLFetchComplete(const URLFetcher* source,
+ const GURL& url,
+ const URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data);
// StartClientLogin been called && results not back yet?
bool HasPendingFetch();
diff --git a/chrome/common/net/gaia/gaia_authenticator.cc b/chrome/common/net/gaia/gaia_authenticator.cc
index 563ee3a..36d060e 100644
--- a/chrome/common/net/gaia/gaia_authenticator.cc
+++ b/chrome/common/net/gaia/gaia_authenticator.cc
@@ -196,6 +196,13 @@ bool GaiaAuthenticator::PerformGaiaRequest(const AuthParams& params,
}
}
+bool GaiaAuthenticator::Post(const GURL& url,
+ const std::string& post_body,
+ unsigned long* response_code,
+ std::string* response_body) {
+ return false;
+}
+
bool GaiaAuthenticator::LookupEmail(AuthResults* results) {
DCHECK_EQ(MessageLoop::current(), message_loop_);
// Use the provided Gaia server, but change the path to what V1 expects.
@@ -238,6 +245,11 @@ bool GaiaAuthenticator::LookupEmail(AuthResults* results) {
return false;
}
+int GaiaAuthenticator::GetBackoffDelaySeconds(int current_backoff_delay) {
+ NOTREACHED();
+ return current_backoff_delay;
+}
+
// We need to call this explicitly when we need to obtain a long-lived session
// token.
bool GaiaAuthenticator::IssueAuthToken(AuthResults* results,
diff --git a/chrome/common/net/gaia/gaia_authenticator.h b/chrome/common/net/gaia/gaia_authenticator.h
index 789863e..be1b2d9 100644
--- a/chrome/common/net/gaia/gaia_authenticator.h
+++ b/chrome/common/net/gaia/gaia_authenticator.h
@@ -180,9 +180,7 @@ class GaiaAuthenticator {
virtual bool PerformGaiaRequest(const AuthParams& params,
AuthResults* results);
virtual bool Post(const GURL& url, const std::string& post_body,
- unsigned long* response_code, std::string* response_body) {
- return false;
- }
+ unsigned long* response_code, std::string* response_body);
// Caller should fill in results->LSID before calling. Result in
// results->primary_email.
@@ -193,10 +191,7 @@ class GaiaAuthenticator {
// TODO(sanjeevr): This should be made pure virtual. But this class is
// currently directly being used in sync/engine/authenticator.cc, which is
// wrong.
- virtual int GetBackoffDelaySeconds(int current_backoff_delay) {
- NOTREACHED();
- return current_backoff_delay;
- }
+ virtual int GetBackoffDelaySeconds(int current_backoff_delay);
public:
// Retrieve email.
diff --git a/chrome/common/net/http_return.h b/chrome/common/net/http_return.h
index 7cb7731..517a849 100644
--- a/chrome/common/net/http_return.h
+++ b/chrome/common/net/http_return.h
@@ -10,9 +10,10 @@
// contains a few HTTP return codes. Add more HTTP return codes.
enum HTTPReturnCode {
RC_REQUEST_OK = 200,
+ RC_BAD_REQUEST = 400,
RC_UNAUTHORIZED = 401,
RC_FORBIDDEN = 403,
+ RC_INTERNAL_SERVER_ERROR = 500,
};
#endif // CHROME_COMMON_NET_HTTP_RETURN_H_
-
diff --git a/chrome/common/net/url_fetcher.cc b/chrome/common/net/url_fetcher.cc
index 64a12f8..81b47cf 100644
--- a/chrome/common/net/url_fetcher.cc
+++ b/chrome/common/net/url_fetcher.cc
@@ -35,7 +35,7 @@ bool URLFetcher::g_interception_enabled = false;
class URLFetcher::Core
: public base::RefCountedThreadSafe<URLFetcher::Core>,
- public URLRequest::Delegate {
+ public net::URLRequest::Delegate {
public:
// For POST requests, set |content_type| to the MIME type of the content
// and set |content| to the data to upload. |flags| are flags to apply to
@@ -61,9 +61,9 @@ class URLFetcher::Core
// Reports that the received content was malformed.
void ReceivedContentWasMalformed();
- // URLRequest::Delegate implementation.
- virtual void OnResponseStarted(URLRequest* request);
- virtual void OnReadCompleted(URLRequest* request, int bytes_read);
+ // Overridden from net::URLRequest::Delegate:
+ virtual void OnResponseStarted(net::URLRequest* request);
+ virtual void OnReadCompleted(net::URLRequest* request, int bytes_read);
URLFetcher::Delegate* delegate() const { return delegate_; }
@@ -117,7 +117,7 @@ class URLFetcher::Core
scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
// The message loop proxy for the thread
// on which the request IO happens.
- scoped_ptr<URLRequest> request_; // The actual request this wraps
+ scoped_ptr<net::URLRequest> request_; // The actual request this wraps
int load_flags_; // Flags for the load operation
int response_code_; // HTTP status code for the request
std::string data_; // Results of the request
@@ -273,7 +273,7 @@ void URLFetcher::Core::CancelAll() {
g_registry.Get().CancelAll();
}
-void URLFetcher::Core::OnResponseStarted(URLRequest* request) {
+void URLFetcher::Core::OnResponseStarted(net::URLRequest* request) {
DCHECK_EQ(request, request_.get());
DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
if (request_->status().is_success()) {
@@ -291,7 +291,8 @@ void URLFetcher::Core::OnResponseStarted(URLRequest* request) {
OnReadCompleted(request_.get(), bytes_read);
}
-void URLFetcher::Core::OnReadCompleted(URLRequest* request, int bytes_read) {
+void URLFetcher::Core::OnReadCompleted(net::URLRequest* request,
+ int bytes_read) {
DCHECK(request == request_);
DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
@@ -337,7 +338,7 @@ void URLFetcher::Core::StartURLRequest() {
DCHECK(!request_.get());
g_registry.Get().AddURLFetcherCore(this);
- request_.reset(new URLRequest(original_url_, this));
+ request_.reset(new net::URLRequest(original_url_, this));
int flags = request_->load_flags() | load_flags_;
if (!g_interception_enabled) {
flags = flags | net::LOAD_DISABLE_INTERCEPT;
diff --git a/chrome/common/net/url_fetcher.h b/chrome/common/net/url_fetcher.h
index 78ad752..87eef4e 100644
--- a/chrome/common/net/url_fetcher.h
+++ b/chrome/common/net/url_fetcher.h
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// This file contains URLFetcher, a wrapper around URLRequest that handles
+// This file contains URLFetcher, a wrapper around net::URLRequest that handles
// low-level details like thread safety, ref counting, and incremental buffer
// reading. This is useful for callers who simply want to get the data from a
// URL and don't care about all the nitty-gritty details.
diff --git a/chrome/common/net/url_fetcher_unittest.cc b/chrome/common/net/url_fetcher_unittest.cc
index c231dca..d1f7ef3 100644
--- a/chrome/common/net/url_fetcher_unittest.cc
+++ b/chrome/common/net/url_fetcher_unittest.cc
@@ -409,7 +409,7 @@ URLFetcherBadHTTPSTest::URLFetcherBadHTTPSTest() {
// The "server certificate expired" error should result in automatic
// cancellation of the request by
-// URLRequest::Delegate::OnSSLCertificateError.
+// net::URLRequest::Delegate::OnSSLCertificateError.
void URLFetcherBadHTTPSTest::OnURLFetchComplete(
const URLFetcher* source,
const GURL& url,
diff --git a/chrome/common/net/url_request_intercept_job.cc b/chrome/common/net/url_request_intercept_job.cc
index 329eea6..641a8e8 100644
--- a/chrome/common/net/url_request_intercept_job.cc
+++ b/chrome/common/net/url_request_intercept_job.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// 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.
//
@@ -8,10 +8,13 @@
#include "chrome/common/net/url_request_intercept_job.h"
+#include <vector>
+
+#include "base/compiler_specific.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "chrome/common/chrome_plugin_lib.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/x509_certificate.h"
@@ -25,13 +28,14 @@ using base::TimeDelta;
// URLRequestInterceptJob
//
-URLRequestInterceptJob::URLRequestInterceptJob(URLRequest* request,
+URLRequestInterceptJob::URLRequestInterceptJob(net::URLRequest* request,
ChromePluginLib* plugin,
ScopableCPRequest* cprequest)
- : URLRequestJob(request),
+ : net::URLRequestJob(request),
cprequest_(cprequest),
plugin_(plugin),
- read_buffer_(NULL) {
+ read_buffer_(NULL),
+ ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
cprequest_->data = this; // see FromCPRequest().
registrar_.Add(this, NotificationType::CHROME_PLUGIN_UNLOADED,
@@ -53,8 +57,10 @@ void URLRequestInterceptJob::DetachPlugin() {
void URLRequestInterceptJob::Start() {
// Start reading asynchronously so that all error reporting and data
// callbacks happen as they would for network requests.
- MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
- this, &URLRequestInterceptJob::StartAsync));
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &URLRequestInterceptJob::StartAsync));
}
void URLRequestInterceptJob::Kill() {
@@ -63,7 +69,8 @@ void URLRequestInterceptJob::Kill() {
CPERR_CANCELLED);
DetachPlugin();
}
- URLRequestJob::Kill();
+ net::URLRequestJob::Kill();
+ method_factory_.RevokeAll();
}
bool URLRequestInterceptJob::ReadRawData(net::IOBuffer* dest, int dest_size,
diff --git a/chrome/common/net/url_request_intercept_job.h b/chrome/common/net/url_request_intercept_job.h
index 6d47bfc..581b30a 100644
--- a/chrome/common/net/url_request_intercept_job.h
+++ b/chrome/common/net/url_request_intercept_job.h
@@ -9,6 +9,7 @@
#include <string>
#include "base/scoped_ptr.h"
+#include "base/task.h"
#include "net/url_request/url_request_job.h"
#include "chrome/common/chrome_plugin_api.h"
#include "chrome/common/chrome_plugin_util.h"
@@ -36,7 +37,7 @@ class URLRequestInterceptJob : public net::URLRequestJob,
void OnStartCompleted(int result);
void OnReadCompleted(int bytes_read);
- // URLRequestJob
+ // net::URLRequestJob
virtual void Start();
virtual void Kill();
virtual bool GetMimeType(std::string* mime_type) const;
@@ -64,6 +65,7 @@ class URLRequestInterceptJob : public net::URLRequestJob,
ChromePluginLib* plugin_;
net::IOBuffer* read_buffer_;
int read_buffer_size_;
+ ScopedRunnableMethodFactory<URLRequestInterceptJob> method_factory_;
DISALLOW_COPY_AND_ASSIGN(URLRequestInterceptJob);
};
diff --git a/chrome/common/notification_type.h b/chrome/common/notification_type.h
index e2da69c..e7484aa 100644
--- a/chrome/common/notification_type.h
+++ b/chrome/common/notification_type.h
@@ -117,12 +117,12 @@ class NotificationType {
// The DOM for a frame was fully constructed, but referenced resources
// might not be fully loaded yet. The source is a
// Source<NavigationController> corresponding to the tab in which the load
- // occurred. Details are the long long frame ID.
+ // occurred. Details are the int64 frame ID.
FRAME_DOM_CONTENT_LOADED,
// The frame finished loading. The source is a Source<NavigationController>
// corresponding to the tab in which the load occurred. Details are the
- // long long frame ID.
+ // int64 frame ID.
FRAME_DID_FINISH_LOAD,
// Content was loaded from an in-memory cache. The source will be a
@@ -183,16 +183,6 @@ class NotificationType {
// change. There are no details.
SSL_INTERNAL_STATE_CHANGED,
- // Lets resource handlers and other interested observers know when the
- // message filter is being deleted and can no longer be used. This will
- // also get sent if the renderer crashes (and in that case, it'll be sent
- // twice).
- RESOURCE_MESSAGE_FILTER_SHUTDOWN,
-
- // Lets interested observers know when a WorkerProcessHost is being deleted
- // and can no longer be used.
- WORKER_PROCESS_HOST_SHUTDOWN,
-
// Views -------------------------------------------------------------------
// Notification that a view was removed from a view hierarchy. The source
@@ -502,7 +492,8 @@ class NotificationType {
WEB_CACHE_STATS_OBSERVED,
// The focused element inside a page has changed. The source is the render
- // view host for the page, there are no details.
+ // view host for the page. The details are a Details<const bool> that
+ // indicates whether or not an editable node was focused.
FOCUS_CHANGED_IN_PAGE,
// Notification posted from ExecuteJavascriptInWebFrameNotifyResult. The
@@ -510,7 +501,7 @@ class NotificationType {
// invoked on. The details are a std::pair<int, Value*> with the int giving
// the id returned from ExecuteJavascriptInWebFrameNotifyResult and the
// Value the results of the javascript expression. The Value is owned by
- // RenderViewHost.
+ // RenderViewHost and may be a Null Value.
EXECUTE_JAVASCRIPT_RESULT,
// BackgroundContents ------------------------------------------------------
@@ -548,12 +539,20 @@ class NotificationType {
// The details are in a Details<ChildProcessInfo>.
CHILD_PROCESS_HOST_DISCONNECTED,
- // This message is sent when a child process disappears unexpectedly.
- // There is no usable source, since it is sent from an ephemeral task;
- // register for AllSources() to receive this notification. The details are
- // in a Details<ChildProcessInfo>.
+ // This message is sent when a child process disappears
+ // unexpectedly as a result of a crash. There is no usable
+ // source, since it is sent from an ephemeral task; register for
+ // AllSources() to receive this notification. The details are in
+ // a Details<ChildProcessInfo>.
CHILD_PROCESS_CRASHED,
+ // This message is sent when a child process disappears
+ // unexpectedly as a result of a termination signal. There is no
+ // usable source, since it is sent from an ephemeral task;
+ // register for AllSources() to receive this notification. The
+ // details are in a Details<ChildProcessInfo>.
+ CHILD_PROCESS_WAS_KILLED,
+
// This message indicates that an instance of a particular child was
// created in a page. (If one page contains several regions rendered by
// the same child, this notification will occur once for each region
@@ -736,6 +735,10 @@ class NotificationType {
// PrefService and the details a std::string of the changed path.
PREF_CHANGED,
+ // This is broadcast after the preference subsystem has completed
+ // asynchronous initalization of a PrefService.
+ PREF_INITIALIZATION_COMPLETED,
+
// Sent when a default request context has been created, so calling
// Profile::GetDefaultRequestContext() will not return NULL. This is sent
// on the thread where Profile::GetRequestContext() is first called, which
@@ -851,16 +854,13 @@ class NotificationType {
EXTENSION_UNINSTALLED,
// Sent when an extension is unloaded. This happens when an extension is
- // uninstalled or disabled. The details are an Extension, and the source is
- // a Profile.
+ // uninstalled or disabled. The details are an UnloadedExtensionInfo, and
+ // the source is a Profile.
//
- // Note that when this notification is sent, ExtensionsService has already
+ // Note that when this notification is sent, ExtensionService has already
// removed the extension from its internal state.
EXTENSION_UNLOADED,
- // Same as above, but for a disabled extension.
- EXTENSION_UNLOADED_DISABLED,
-
// Sent when an extension has updated its user scripts. The details are an
// Extension, and the source is a Profile.
EXTENSION_USER_SCRIPTS_UPDATED,
@@ -1103,6 +1103,11 @@ class NotificationType {
// details are None.
DESKTOP_NOTIFICATION_SETTINGS_CHANGED,
+ // Sent when the geolocation settings change. The source is the
+ // GeolocationContentSettingsMap object, the details are
+ // ContentSettingsNotificationsDetails.
+ GEOLOCATION_SETTINGS_CHANGED,
+
// Sync --------------------------------------------------------------------
// Sent when the sync backend has been paused.
@@ -1247,6 +1252,9 @@ class NotificationType {
// os device has failed.
OWNER_KEY_FETCH_ATTEMPT_FAILED,
+ // Sent after device was successfully owned.
+ OWNERSHIP_TAKEN,
+
// This is sent to a ChromeOS settings observer when a system setting is
// changed. The source is the CrosSettings and the details a std::string of
// the changed setting.
@@ -1286,19 +1294,6 @@ class NotificationType {
// |webkit_glue::PasswordForm|s that were affected.
LOGINS_CHANGED,
- // Configuration Policy ----------------------------------------------------
- // This notification is sent whenever the administrator changes policy.
- // The detail of this notification is not used.
- POLICY_CHANGED,
-
- // This notification is sent whenever the device token becomes available
- // that the policy subsystem uses to fetch policy from the cloud.
- DEVICE_TOKEN_AVAILABLE,
-
- // This notification is sent whenever cloud policies are fetched and
- // updated. The detail of this notification is not used.
- CLOUD_POLICY_UPDATE,
-
// Count (must be last) ----------------------------------------------------
// Used to determine the number of notification types. Not valid as
// a type parameter when registering for or posting notifications.
diff --git a/chrome/common/pepper_file_messages.cc b/chrome/common/pepper_file_messages.cc
new file mode 100644
index 0000000..30f6ad1
--- /dev/null
+++ b/chrome/common/pepper_file_messages.cc
@@ -0,0 +1,34 @@
+// 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.
+
+#include "chrome/common/common_param_traits.h"
+
+#define IPC_MESSAGE_IMPL
+#include "chrome/common/pepper_file_messages.h"
+
+namespace IPC {
+
+void ParamTraits<webkit::ppapi::DirEntry>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.name);
+ WriteParam(m, p.is_dir);
+}
+
+bool ParamTraits<webkit::ppapi::DirEntry>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return ReadParam(m, iter, &p->name) &&
+ ReadParam(m, iter, &p->is_dir);
+}
+
+void ParamTraits<webkit::ppapi::DirEntry>::Log(const param_type& p,
+ std::string* l) {
+ l->append("(");
+ LogParam(p.name, l);
+ l->append(", ");
+ LogParam(p.is_dir, l);
+ l->append(")");
+}
+
+} // namespace IPC
diff --git a/chrome/common/pepper_file_messages.h b/chrome/common/pepper_file_messages.h
new file mode 100644
index 0000000..657b3e3
--- /dev/null
+++ b/chrome/common/pepper_file_messages.h
@@ -0,0 +1,68 @@
+// 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.
+
+#ifndef CHROME_COMMON_PEPPER_FILE_MESSAGES_H_
+#define CHROME_COMMON_PEPPER_FILE_MESSAGES_H_
+#pragma once
+
+#include "chrome/common/common_param_traits.h"
+#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_param_traits.h"
+#include "ipc/ipc_platform_file.h"
+#include "webkit/plugins/ppapi/dir_contents.h"
+
+#define IPC_MESSAGE_START PepperFileMsgStart
+
+namespace IPC {
+
+// Also needed for Serializing DirContents, which is just a vector of DirEntry.
+template <>
+struct ParamTraits<webkit::ppapi::DirEntry> {
+ typedef webkit::ppapi::DirEntry param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
+};
+
+} // namespace IPC
+
+// Trusted Pepper Filesystem messages from the renderer to the browser.
+
+// Open the file.
+IPC_SYNC_MESSAGE_CONTROL2_2(PepperFileMsg_OpenFile,
+ FilePath /* path */,
+ int /* flags */,
+ base::PlatformFileError /* error_code */,
+ IPC::PlatformFileForTransit /* result */)
+
+// Rename the file.
+IPC_SYNC_MESSAGE_CONTROL2_1(PepperFileMsg_RenameFile,
+ FilePath /* path_from */,
+ FilePath /* path_to */,
+ base::PlatformFileError /* error_code */)
+
+// Delete the file.
+IPC_SYNC_MESSAGE_CONTROL2_1(PepperFileMsg_DeleteFileOrDir,
+ FilePath /* path */,
+ bool /* recursive */,
+ base::PlatformFileError /* error_code */)
+
+// Create the directory.
+IPC_SYNC_MESSAGE_CONTROL1_1(PepperFileMsg_CreateDir,
+ FilePath /* path */,
+ base::PlatformFileError /* error_code */)
+
+// Query the file's info.
+IPC_SYNC_MESSAGE_CONTROL1_2(PepperFileMsg_QueryFile,
+ FilePath /* path */,
+ base::PlatformFileInfo, /* info */
+ base::PlatformFileError /* error_code */)
+
+// Get the directory's contents.
+IPC_SYNC_MESSAGE_CONTROL1_2(PepperFileMsg_GetDirContents,
+ FilePath /* path */,
+ webkit::ppapi::DirContents, /* contents */
+ base::PlatformFileError /* error_code */)
+
+#endif // CHROME_COMMON_PEPPER_FILE_MESSAGES_H_
diff --git a/chrome/common/pepper_plugin_registry.cc b/chrome/common/pepper_plugin_registry.cc
index f812afd..5223e55 100644
--- a/chrome/common/pepper_plugin_registry.cc
+++ b/chrome/common/pepper_plugin_registry.cc
@@ -21,6 +21,14 @@ const char* PepperPluginRegistry::kPDFPluginExtension = "pdf";
const char* PepperPluginRegistry::kPDFPluginDescription =
"Portable Document Format";
+const char* PepperPluginRegistry::kNaClPluginName = "Chrome NaCl";
+const char* PepperPluginRegistry::kNaClPluginMimeType =
+ "application/x-ppapi-nacl-srpc";
+const char* PepperPluginRegistry::kNaClPluginExtension = "nexe";
+const char* PepperPluginRegistry::kNaClPluginDescription =
+ "Native Client Executable";
+
+
PepperPluginInfo::PepperPluginInfo()
: is_internal(false),
is_out_of_process(false) {
@@ -30,8 +38,12 @@ PepperPluginInfo::~PepperPluginInfo() {}
// static
PepperPluginRegistry* PepperPluginRegistry::GetInstance() {
- static PepperPluginRegistry registry;
- return &registry;
+ static PepperPluginRegistry* registry = NULL;
+ // This object leaks. It is a temporary hack to work around a crash.
+ // http://code.google.com/p/chromium/issues/detail?id=63234
+ if (!registry)
+ registry = new PepperPluginRegistry;
+ return registry;
}
// static
@@ -136,6 +148,27 @@ void PepperPluginRegistry::GetExtraPlugins(
skip_pdf_file_check = true;
}
}
+
+ // Verify that we enable nacl on the command line. The name of the
+ // switch varies between the browser and renderer process.
+ bool enable_nacl =
+ CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableNaCl) ||
+ CommandLine::ForCurrentProcess()->HasSwitch(switches::kInternalNaCl);
+
+ static bool skip_nacl_file_check = false;
+ if (enable_nacl && PathService::Get(chrome::FILE_NACL_PLUGIN, &path)) {
+ if (skip_nacl_file_check || file_util::PathExists(path)) {
+ PepperPluginInfo nacl;
+ nacl.path = path;
+ nacl.name = kNaClPluginName;
+ nacl.mime_types.push_back(kNaClPluginMimeType);
+ nacl.file_extensions = kNaClPluginExtension;
+ nacl.type_descriptions = kNaClPluginDescription;
+ plugins->push_back(nacl);
+
+ skip_nacl_file_check = true;
+ }
+ }
}
PepperPluginRegistry::InternalPluginInfo::InternalPluginInfo() {
@@ -187,7 +220,7 @@ bool PepperPluginRegistry::RunOutOfProcessForPlugin(
return false;
}
-pepper::PluginModule* PepperPluginRegistry::GetModule(
+webkit::ppapi::PluginModule* PepperPluginRegistry::GetModule(
const FilePath& path) const {
ModuleMap::const_iterator it = modules_.find(path);
if (it == modules_.end())
@@ -207,9 +240,8 @@ PepperPluginRegistry::PepperPluginRegistry() {
it != internal_plugin_info.end();
++it) {
const FilePath& path = it->path;
- ModuleHandle module =
- pepper::PluginModule::CreateInternalModule(it->entry_points);
- if (!module) {
+ ModuleHandle module(new webkit::ppapi::PluginModule);
+ if (!module->InitAsInternalPlugin(it->entry_points)) {
DLOG(ERROR) << "Failed to load pepper module: " << path.value();
continue;
}
@@ -227,8 +259,8 @@ PepperPluginRegistry::PepperPluginRegistry() {
continue; // Only preload in-process plugins.
const FilePath& path = plugins[i].path;
- ModuleHandle module = pepper::PluginModule::CreateModule(path);
- if (!module) {
+ ModuleHandle module(new webkit::ppapi::PluginModule);
+ if (!module->InitAsLibrary(path)) {
DLOG(ERROR) << "Failed to load pepper module: " << path.value();
continue;
}
diff --git a/chrome/common/pepper_plugin_registry.h b/chrome/common/pepper_plugin_registry.h
index 60762c5..424ed1a 100644
--- a/chrome/common/pepper_plugin_registry.h
+++ b/chrome/common/pepper_plugin_registry.h
@@ -11,7 +11,7 @@
#include <vector>
#include "base/file_path.h"
-#include "webkit/glue/plugins/pepper_plugin_module.h"
+#include "webkit/plugins/ppapi/plugin_module.h"
struct PepperPluginInfo {
PepperPluginInfo();
@@ -40,6 +40,11 @@ class PepperPluginRegistry {
static const char* kPDFPluginExtension;
static const char* kPDFPluginDescription;
+ static const char* kNaClPluginName;
+ static const char* kNaClPluginMimeType;
+ static const char* kNaClPluginExtension;
+ static const char* kNaClPluginDescription;
+
static PepperPluginRegistry* GetInstance();
// Returns the list of known pepper plugins. This method is static so that
@@ -59,7 +64,7 @@ class PepperPluginRegistry {
// Returns a preloaded module for the given path. This only works for
// non-out-of-process plugins since we preload them so they will run in the
// sandbox. Returns NULL if the plugin hasn't been preloaded.
- pepper::PluginModule* GetModule(const FilePath& path) const;
+ webkit::ppapi::PluginModule* GetModule(const FilePath& path) const;
~PepperPluginRegistry();
@@ -69,14 +74,14 @@ class PepperPluginRegistry {
struct InternalPluginInfo : public PepperPluginInfo {
InternalPluginInfo(); // Sets |is_internal|.
- pepper::PluginModule::EntryPoints entry_points;
+ webkit::ppapi::PluginModule::EntryPoints entry_points;
};
typedef std::vector<InternalPluginInfo> InternalPluginInfoList;
static void GetInternalPluginInfo(InternalPluginInfoList* plugin_info);
PepperPluginRegistry();
- typedef scoped_refptr<pepper::PluginModule> ModuleHandle;
+ typedef scoped_refptr<webkit::ppapi::PluginModule> ModuleHandle;
typedef std::map<FilePath, ModuleHandle> ModuleMap;
ModuleMap modules_;
};
diff --git a/chrome/common/persistent_pref_store.h b/chrome/common/persistent_pref_store.h
new file mode 100644
index 0000000..9e2fb0a
--- /dev/null
+++ b/chrome/common/persistent_pref_store.h
@@ -0,0 +1,69 @@
+// 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.
+
+#ifndef CHROME_COMMON_PERSISTENT_PREF_STORE_H_
+#define CHROME_COMMON_PERSISTENT_PREF_STORE_H_
+#pragma once
+
+#include <string>
+
+#include <chrome/common/pref_store.h>
+
+// This interface is complementary to the PrefStore interface, declaring
+// additional functionatliy that adds support for setting values and persisting
+// the data to some backing store.
+class PersistentPrefStore : public PrefStore {
+ public:
+ virtual ~PersistentPrefStore() {}
+
+ // Unique integer code for each type of error so we can report them
+ // distinctly in a histogram.
+ // NOTE: Don't change the order here as it will change the server's meaning
+ // of the histogram.
+ enum PrefReadError {
+ PREF_READ_ERROR_NONE = 0,
+ PREF_READ_ERROR_JSON_PARSE,
+ PREF_READ_ERROR_JSON_TYPE,
+ PREF_READ_ERROR_ACCESS_DENIED,
+ PREF_READ_ERROR_FILE_OTHER,
+ PREF_READ_ERROR_FILE_LOCKED,
+ PREF_READ_ERROR_NO_FILE,
+ PREF_READ_ERROR_JSON_REPEAT,
+ PREF_READ_ERROR_OTHER,
+ PREF_READ_ERROR_FILE_NOT_SPECIFIED
+ };
+
+ // Sets a |value| for |key| in the store. Assumes ownership of |value|, which
+ // must be non-NULL.
+ virtual void SetValue(const std::string& key, Value* value) = 0;
+
+ // Same as SetValue, but doesn't generate notifications. This is used by
+ // GetMutableDictionary() and GetMutableList() in order to put empty entries
+ // into the user pref store. Using SetValue is not an option since existing
+ // tests rely on the number of notifications generated.
+ //
+ // TODO(mnissler, danno): Can we replace GetMutableDictionary() and
+ // GetMutableList() with something along the lines of ScopedPrefUpdate that
+ // updates the value in the end?
+ virtual void SetValueSilently(const std::string& key, Value* value) = 0;
+
+ // Removes the value for |key|.
+ virtual void RemoveValue(const std::string& key) = 0;
+
+ // Whether the store is in a pseudo-read-only mode where changes are not
+ // actually persisted to disk. This happens in some cases when there are
+ // read errors during startup.
+ virtual bool ReadOnly() const = 0;
+
+ // Reads the preferences from disk.
+ virtual PrefReadError ReadPrefs() = 0;
+
+ // Writes the preferences to disk immediately.
+ virtual bool WritePrefs() = 0;
+
+ // Schedules an asynchronous write operation.
+ virtual void ScheduleWritePrefs() = 0;
+};
+
+#endif // CHROME_COMMON_PERSISTENT_PREF_STORE_H_
diff --git a/chrome/common/plugin_messages.cc b/chrome/common/plugin_messages.cc
index 0434197..d9117ff 100644
--- a/chrome/common/plugin_messages.cc
+++ b/chrome/common/plugin_messages.cc
@@ -2,14 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/common/plugin_messages.h"
-
#include "base/utf_string_conversions.h"
#include "ipc/ipc_channel_handle.h"
-#define MESSAGES_INTERNAL_IMPL_FILE \
- "chrome/common/plugin_messages_internal.h"
-#include "ipc/ipc_message_impl_macros.h"
+#define IPC_MESSAGE_IMPL
+#include "chrome/common/plugin_messages.h"
PluginMsg_Init_Params::PluginMsg_Init_Params()
: containing_window(0),
diff --git a/chrome/common/plugin_messages.h b/chrome/common/plugin_messages.h
index 3935fa8..4753c9d 100644
--- a/chrome/common/plugin_messages.h
+++ b/chrome/common/plugin_messages.h
@@ -236,8 +236,6 @@ struct ParamTraits<PluginMsg_UpdateGeometry_Param> {
} // namespace IPC
-
-#define MESSAGES_INTERNAL_FILE "chrome/common/plugin_messages_internal.h"
-#include "ipc/ipc_message_macros.h"
+#include "chrome/common/plugin_messages_internal.h"
#endif // CHROME_COMMON_PLUGIN_MESSAGES_H_
diff --git a/chrome/common/plugin_messages_internal.h b/chrome/common/plugin_messages_internal.h
index 7ebfd58..54ba2eb 100644
--- a/chrome/common/plugin_messages_internal.h
+++ b/chrome/common/plugin_messages_internal.h
@@ -12,523 +12,511 @@
#include "base/file_descriptor_posix.h"
#endif
+#define IPC_MESSAGE_START PluginMsgStart
+
//-----------------------------------------------------------------------------
// PluginProcess messages
// These are messages sent from the browser to the plugin process.
-IPC_BEGIN_MESSAGES(PluginProcess)
- // Tells the plugin process to create a new channel for communication with a
- // given renderer. The channel name is returned in a
- // PluginProcessHostMsg_ChannelCreated message. The renderer ID is passed so
- // that the plugin process reuses an existing channel to that process if it
- // exists. This ID is a unique opaque identifier generated by the browser
- // process.
- IPC_MESSAGE_CONTROL2(PluginProcessMsg_CreateChannel,
- int /* renderer_id */,
- bool /* off_the_record */)
-
- // Allows a chrome plugin loaded in the browser process to send arbitrary
- // data to an instance of the same plugin loaded in a plugin process.
- IPC_MESSAGE_CONTROL1(PluginProcessMsg_PluginMessage,
- std::vector<uint8> /* opaque data */)
-
- // Tells the plugin process to notify every connected renderer of the pending
- // shutdown, so we don't mistake it for a crash.
- IPC_MESSAGE_CONTROL0(PluginProcessMsg_NotifyRenderersOfPendingShutdown)
-
- // The following messages are used by all child processes, even though they
- // are listed under PluginProcess. It seems overkill to define ChildProcess.
- // Tells the child process it should stop.
- IPC_MESSAGE_CONTROL0(PluginProcessMsg_AskBeforeShutdown)
-
- // Sent in response to PluginProcessHostMsg_ShutdownRequest to tell the child
- // process that it's safe to shutdown.
- IPC_MESSAGE_CONTROL0(PluginProcessMsg_Shutdown)
+// Tells the plugin process to create a new channel for communication with a
+// given renderer. The channel name is returned in a
+// PluginProcessHostMsg_ChannelCreated message. The renderer ID is passed so
+// that the plugin process reuses an existing channel to that process if it
+// exists. This ID is a unique opaque identifier generated by the browser
+// process.
+IPC_MESSAGE_CONTROL2(PluginProcessMsg_CreateChannel,
+ int /* renderer_id */,
+ bool /* off_the_record */)
+
+// Allows a chrome plugin loaded in the browser process to send arbitrary
+// data to an instance of the same plugin loaded in a plugin process.
+IPC_MESSAGE_CONTROL1(PluginProcessMsg_PluginMessage,
+ std::vector<uint8> /* opaque data */)
+
+// Tells the plugin process to notify every connected renderer of the pending
+// shutdown, so we don't mistake it for a crash.
+IPC_MESSAGE_CONTROL0(PluginProcessMsg_NotifyRenderersOfPendingShutdown)
+
+// The following messages are used by all child processes, even though they
+// are listed under PluginProcess. It seems overkill to define ChildProcess.
+// Tells the child process it should stop.
+IPC_MESSAGE_CONTROL0(PluginProcessMsg_AskBeforeShutdown)
+
+// Sent in response to PluginProcessHostMsg_ShutdownRequest to tell the child
+// process that it's safe to shutdown.
+IPC_MESSAGE_CONTROL0(PluginProcessMsg_Shutdown)
#if defined(IPC_MESSAGE_LOG_ENABLED)
- // Tell the child process to begin or end IPC message logging.
- // Like above, this is used by all ChildProcesses.
- IPC_MESSAGE_CONTROL1(PluginProcessMsg_SetIPCLoggingEnabled,
- bool /* on or off */)
+// Tell the child process to begin or end IPC message logging.
+// Like above, this is used by all ChildProcesses.
+IPC_MESSAGE_CONTROL1(PluginProcessMsg_SetIPCLoggingEnabled,
+ bool /* on or off */)
#endif
-IPC_END_MESSAGES(PluginProcess)
-
//-----------------------------------------------------------------------------
// PluginProcessHost messages
// These are messages sent from the plugin process to the browser process.
-IPC_BEGIN_MESSAGES(PluginProcessHost)
- // Response to a PluginProcessMsg_CreateChannel message.
- IPC_MESSAGE_CONTROL1(PluginProcessHostMsg_ChannelCreated,
- IPC::ChannelHandle /* channel_handle */)
-
- IPC_SYNC_MESSAGE_CONTROL0_1(PluginProcessHostMsg_GetPluginFinderUrl,
- std::string /* plugin finder URL */)
-
- IPC_MESSAGE_CONTROL0(PluginProcessHostMsg_ShutdownRequest)
-
- // Allows a chrome plugin loaded in a plugin process to send arbitrary
- // data to an instance of the same plugin loaded in the browser process.
- IPC_MESSAGE_CONTROL1(PluginProcessHostMsg_PluginMessage,
- std::vector<uint8> /* opaque data */)
-
- // Allows a chrome plugin loaded in a plugin process to send arbitrary
- // data to an instance of the same plugin loaded in the browser process.
- IPC_SYNC_MESSAGE_CONTROL1_1(PluginProcessHostMsg_PluginSyncMessage,
- std::vector<uint8> /* opaque data */,
- std::vector<uint8> /* opaque data response */)
-
- // Used to get cookies for the given URL. The request_context is a
- // CPBrowsingContext, but is passed as int32 to avoid compilation errors.
- IPC_SYNC_MESSAGE_CONTROL2_1(PluginProcessHostMsg_GetCookies,
- int32 /* request_context */,
- GURL /* url */,
- std::string /* cookies */)
-
- // Used by the plugin process to verify that its renderer |renderer_id| has
- // permission to access the given |files|.
- IPC_SYNC_MESSAGE_CONTROL2_1(PluginProcessHostMsg_AccessFiles,
- int /* renderer_id */,
- std::vector<std::string> /* files */,
- bool /* allowed */)
-
- // Get the list of proxies to use for |url|, as a semicolon delimited list
- // of "<TYPE> <HOST>:<PORT>" | "DIRECT". See also ViewHostMsg_ResolveProxy
- // which does the same thing.
- IPC_SYNC_MESSAGE_CONTROL1_2(PluginProcessHostMsg_ResolveProxy,
- GURL /* url */,
- int /* network error */,
- std::string /* proxy list */)
+// Response to a PluginProcessMsg_CreateChannel message.
+IPC_MESSAGE_CONTROL1(PluginProcessHostMsg_ChannelCreated,
+ IPC::ChannelHandle /* channel_handle */)
+
+IPC_SYNC_MESSAGE_CONTROL0_1(PluginProcessHostMsg_GetPluginFinderUrl,
+ std::string /* plugin finder URL */)
+
+IPC_MESSAGE_CONTROL0(PluginProcessHostMsg_ShutdownRequest)
+
+// Allows a chrome plugin loaded in a plugin process to send arbitrary
+// data to an instance of the same plugin loaded in the browser process.
+IPC_MESSAGE_CONTROL1(PluginProcessHostMsg_PluginMessage,
+ std::vector<uint8> /* opaque data */)
+
+// Allows a chrome plugin loaded in a plugin process to send arbitrary
+// data to an instance of the same plugin loaded in the browser process.
+IPC_SYNC_MESSAGE_CONTROL1_1(PluginProcessHostMsg_PluginSyncMessage,
+ std::vector<uint8> /* opaque data */,
+ std::vector<uint8> /* opaque data response */)
+
+// Used to get cookies for the given URL. The request_context is a
+// CPBrowsingContext, but is passed as int32 to avoid compilation errors.
+IPC_SYNC_MESSAGE_CONTROL2_1(PluginProcessHostMsg_GetCookies,
+ int32 /* request_context */,
+ GURL /* url */,
+ std::string /* cookies */)
+
+// Used by the plugin process to verify that its renderer |renderer_id| has
+// permission to access the given |files|.
+IPC_SYNC_MESSAGE_CONTROL2_1(PluginProcessHostMsg_AccessFiles,
+ int /* renderer_id */,
+ std::vector<std::string> /* files */,
+ bool /* allowed */)
+
+// Get the list of proxies to use for |url|, as a semicolon delimited list
+// of "<TYPE> <HOST>:<PORT>" | "DIRECT". See also ViewHostMsg_ResolveProxy
+// which does the same thing.
+IPC_SYNC_MESSAGE_CONTROL1_2(PluginProcessHostMsg_ResolveProxy,
+ GURL /* url */,
+ int /* network error */,
+ std::string /* proxy list */)
#if defined(OS_WIN)
- // Creates a child window of the given parent window on the UI thread.
- IPC_SYNC_MESSAGE_CONTROL1_1(PluginProcessHostMsg_CreateWindow,
- HWND /* parent */,
- HWND /* child */)
-
- // Destroys the given window's parent on the UI thread.
- IPC_MESSAGE_CONTROL2(PluginProcessHostMsg_PluginWindowDestroyed,
- HWND /* window */,
- HWND /* parent */)
-
- IPC_MESSAGE_ROUTED3(PluginProcessHostMsg_DownloadUrl,
- std::string /* URL */,
- int /* process id */,
- HWND /* caller window */)
+// Creates a child window of the given parent window on the UI thread.
+IPC_SYNC_MESSAGE_CONTROL1_1(PluginProcessHostMsg_CreateWindow,
+ HWND /* parent */,
+ HWND /* child */)
+
+// Destroys the given window's parent on the UI thread.
+IPC_MESSAGE_CONTROL2(PluginProcessHostMsg_PluginWindowDestroyed,
+ HWND /* window */,
+ HWND /* parent */)
+
+IPC_MESSAGE_ROUTED3(PluginProcessHostMsg_DownloadUrl,
+ std::string /* URL */,
+ int /* process id */,
+ HWND /* caller window */)
#endif
#if defined(USE_X11)
- // On X11, the mapping between NativeViewId and X window ids
- // is known only to the browser. This message lets the plugin process
- // ask about a NativeViewId that was provided by the renderer.
- // It will get 0 back if it's a bogus input.
- IPC_SYNC_MESSAGE_CONTROL1_1(PluginProcessHostMsg_MapNativeViewId,
- gfx::NativeViewId /* input: native view id */,
- gfx::PluginWindowHandle /* output: X window id */)
+// On X11, the mapping between NativeViewId and X window ids
+// is known only to the browser. This message lets the plugin process
+// ask about a NativeViewId that was provided by the renderer.
+// It will get 0 back if it's a bogus input.
+IPC_SYNC_MESSAGE_CONTROL1_1(PluginProcessHostMsg_MapNativeViewId,
+ gfx::NativeViewId /* input: native view id */,
+ gfx::PluginWindowHandle /* output: X window id */)
#endif
#if defined(OS_MACOSX)
- // On Mac OS X, we need the browser to keep track of plugin windows so
- // that it can add and remove them from stacking groups, hide and show the
- // menu bar, etc. We pass the window rect for convenience so that the
- // browser can easily tell if the window is fullscreen.
-
- // Notifies the browser that the plugin has selected a window (i.e., brought
- // it to the front and wants it to have keyboard focus).
- IPC_MESSAGE_CONTROL3(PluginProcessHostMsg_PluginSelectWindow,
- uint32 /* window ID */,
- gfx::Rect /* window rect */,
- bool /* modal */)
-
- // Notifies the browser that the plugin has shown a window.
- IPC_MESSAGE_CONTROL3(PluginProcessHostMsg_PluginShowWindow,
- uint32 /* window ID */,
- gfx::Rect /* window rect */,
- bool /* modal */)
-
- // Notifies the browser that the plugin has hidden a window.
- IPC_MESSAGE_CONTROL2(PluginProcessHostMsg_PluginHideWindow,
- uint32 /* window ID */,
- gfx::Rect /* window rect */)
-
- // Notifies the browser that a plugin instance has requested a cursor
- // visibility change.
- IPC_MESSAGE_CONTROL1(PluginProcessHostMsg_PluginSetCursorVisibility,
- bool /* cursor visibility */)
+// On Mac OS X, we need the browser to keep track of plugin windows so
+// that it can add and remove them from stacking groups, hide and show the
+// menu bar, etc. We pass the window rect for convenience so that the
+// browser can easily tell if the window is fullscreen.
+
+// Notifies the browser that the plugin has selected a window (i.e., brought
+// it to the front and wants it to have keyboard focus).
+IPC_MESSAGE_CONTROL3(PluginProcessHostMsg_PluginSelectWindow,
+ uint32 /* window ID */,
+ gfx::Rect /* window rect */,
+ bool /* modal */)
+
+// Notifies the browser that the plugin has shown a window.
+IPC_MESSAGE_CONTROL3(PluginProcessHostMsg_PluginShowWindow,
+ uint32 /* window ID */,
+ gfx::Rect /* window rect */,
+ bool /* modal */)
+
+// Notifies the browser that the plugin has hidden a window.
+IPC_MESSAGE_CONTROL2(PluginProcessHostMsg_PluginHideWindow,
+ uint32 /* window ID */,
+ gfx::Rect /* window rect */)
+
+// Notifies the browser that a plugin instance has requested a cursor
+// visibility change.
+IPC_MESSAGE_CONTROL1(PluginProcessHostMsg_PluginSetCursorVisibility,
+ bool /* cursor visibility */)
#endif
-IPC_END_MESSAGES(PluginProcessHost)
-
//-----------------------------------------------------------------------------
// Plugin messages
// These are messages sent from the renderer process to the plugin process.
-IPC_BEGIN_MESSAGES(Plugin)
- // Tells the plugin process to create a new plugin instance with the given
- // id. A corresponding WebPluginDelegateStub is created which hosts the
- // WebPluginDelegateImpl.
- IPC_SYNC_MESSAGE_CONTROL1_1(PluginMsg_CreateInstance,
- std::string /* mime_type */,
- int /* instance_id */)
-
- // The WebPluginDelegateProxy sends this to the WebPluginDelegateStub in its
- // destructor, so that the stub deletes the actual WebPluginDelegateImpl
- // object that it's hosting.
- IPC_SYNC_MESSAGE_CONTROL1_0(PluginMsg_DestroyInstance,
- int /* instance_id */)
-
- IPC_SYNC_MESSAGE_CONTROL0_1(PluginMsg_GenerateRouteID,
- int /* id */)
-
- // The messages below all map to WebPluginDelegate methods.
- IPC_SYNC_MESSAGE_ROUTED1_1(PluginMsg_Init,
- PluginMsg_Init_Params,
- bool /* result */)
-
- // Used to synchronously request a paint for windowless plugins.
- IPC_SYNC_MESSAGE_ROUTED1_0(PluginMsg_Paint,
- gfx::Rect /* damaged_rect */)
-
- // Sent by the renderer after it paints from its backing store so that the
- // plugin knows it can send more invalidates.
- IPC_MESSAGE_ROUTED0(PluginMsg_DidPaint)
-
- IPC_SYNC_MESSAGE_ROUTED0_2(PluginMsg_Print,
- base::SharedMemoryHandle /* shared_memory*/,
- uint32 /* size */)
-
- IPC_SYNC_MESSAGE_ROUTED0_1(PluginMsg_GetPluginScriptableObject,
- int /* route_id */)
-
- IPC_MESSAGE_ROUTED3(PluginMsg_DidFinishLoadWithReason,
- GURL /* url */,
- int /* reason */,
- int /* notify_id */)
-
- // Updates the plugin location.
- IPC_MESSAGE_ROUTED1(PluginMsg_UpdateGeometry,
- PluginMsg_UpdateGeometry_Param)
-
- // A synchronous version of above.
- IPC_SYNC_MESSAGE_ROUTED1_0(PluginMsg_UpdateGeometrySync,
- PluginMsg_UpdateGeometry_Param)
-
- IPC_SYNC_MESSAGE_ROUTED1_0(PluginMsg_SetFocus,
- bool /* focused */)
-
- IPC_SYNC_MESSAGE_ROUTED1_2(PluginMsg_HandleInputEvent,
- IPC::WebInputEventPointer /* event */,
- bool /* handled */,
- WebCursor /* cursor type*/)
-
- IPC_MESSAGE_ROUTED1(PluginMsg_SetContentAreaFocus,
- bool /* has_focus */)
+// Tells the plugin process to create a new plugin instance with the given
+// id. A corresponding WebPluginDelegateStub is created which hosts the
+// WebPluginDelegateImpl.
+IPC_SYNC_MESSAGE_CONTROL1_1(PluginMsg_CreateInstance,
+ std::string /* mime_type */,
+ int /* instance_id */)
+
+// The WebPluginDelegateProxy sends this to the WebPluginDelegateStub in its
+// destructor, so that the stub deletes the actual WebPluginDelegateImpl
+// object that it's hosting.
+IPC_SYNC_MESSAGE_CONTROL1_0(PluginMsg_DestroyInstance,
+ int /* instance_id */)
+
+IPC_SYNC_MESSAGE_CONTROL0_1(PluginMsg_GenerateRouteID,
+ int /* id */)
+
+// The messages below all map to WebPluginDelegate methods.
+IPC_SYNC_MESSAGE_ROUTED1_1(PluginMsg_Init,
+ PluginMsg_Init_Params,
+ bool /* result */)
+
+// Used to synchronously request a paint for windowless plugins.
+IPC_SYNC_MESSAGE_ROUTED1_0(PluginMsg_Paint,
+ gfx::Rect /* damaged_rect */)
+
+// Sent by the renderer after it paints from its backing store so that the
+// plugin knows it can send more invalidates.
+IPC_MESSAGE_ROUTED0(PluginMsg_DidPaint)
+
+IPC_SYNC_MESSAGE_ROUTED0_2(PluginMsg_Print,
+ base::SharedMemoryHandle /* shared_memory*/,
+ uint32 /* size */)
+
+IPC_SYNC_MESSAGE_ROUTED0_1(PluginMsg_GetPluginScriptableObject,
+ int /* route_id */)
+
+IPC_MESSAGE_ROUTED3(PluginMsg_DidFinishLoadWithReason,
+ GURL /* url */,
+ int /* reason */,
+ int /* notify_id */)
+
+// Updates the plugin location.
+IPC_MESSAGE_ROUTED1(PluginMsg_UpdateGeometry,
+ PluginMsg_UpdateGeometry_Param)
+
+// A synchronous version of above.
+IPC_SYNC_MESSAGE_ROUTED1_0(PluginMsg_UpdateGeometrySync,
+ PluginMsg_UpdateGeometry_Param)
+
+IPC_SYNC_MESSAGE_ROUTED1_0(PluginMsg_SetFocus,
+ bool /* focused */)
+
+IPC_SYNC_MESSAGE_ROUTED1_2(PluginMsg_HandleInputEvent,
+ IPC::WebInputEventPointer /* event */,
+ bool /* handled */,
+ WebCursor /* cursor type*/)
+
+IPC_MESSAGE_ROUTED1(PluginMsg_SetContentAreaFocus,
+ bool /* has_focus */)
#if defined(OS_MACOSX)
- IPC_MESSAGE_ROUTED1(PluginMsg_SetWindowFocus,
- bool /* has_focus */)
+IPC_MESSAGE_ROUTED1(PluginMsg_SetWindowFocus,
+ bool /* has_focus */)
- IPC_MESSAGE_ROUTED0(PluginMsg_ContainerHidden)
+IPC_MESSAGE_ROUTED0(PluginMsg_ContainerHidden)
- IPC_MESSAGE_ROUTED3(PluginMsg_ContainerShown,
- gfx::Rect /* window_frame */,
- gfx::Rect /* view_frame */,
- bool /* has_focus */)
+IPC_MESSAGE_ROUTED3(PluginMsg_ContainerShown,
+ gfx::Rect /* window_frame */,
+ gfx::Rect /* view_frame */,
+ bool /* has_focus */)
- IPC_MESSAGE_ROUTED2(PluginMsg_WindowFrameChanged,
- gfx::Rect /* window_frame */,
- gfx::Rect /* view_frame */)
+IPC_MESSAGE_ROUTED2(PluginMsg_WindowFrameChanged,
+ gfx::Rect /* window_frame */,
+ gfx::Rect /* view_frame */)
- IPC_MESSAGE_ROUTED1(PluginMsg_ImeCompositionConfirmed,
- string16 /* text */)
+IPC_MESSAGE_ROUTED1(PluginMsg_ImeCompositionConfirmed,
+ string16 /* text */)
#endif
- IPC_SYNC_MESSAGE_ROUTED3_0(PluginMsg_WillSendRequest,
- unsigned long /* id */,
- GURL /* url */,
- int /* http_status_code */)
+IPC_SYNC_MESSAGE_ROUTED3_0(PluginMsg_WillSendRequest,
+ unsigned long /* id */,
+ GURL /* url */,
+ int /* http_status_code */)
- IPC_MESSAGE_ROUTED1(PluginMsg_DidReceiveResponse,
- PluginMsg_DidReceiveResponseParams)
+IPC_MESSAGE_ROUTED1(PluginMsg_DidReceiveResponse,
+ PluginMsg_DidReceiveResponseParams)
- IPC_MESSAGE_ROUTED3(PluginMsg_DidReceiveData,
- unsigned long /* id */,
- std::vector<char> /* buffer */,
- int /* data_offset */)
+IPC_MESSAGE_ROUTED3(PluginMsg_DidReceiveData,
+ unsigned long /* id */,
+ std::vector<char> /* buffer */,
+ int /* data_offset */)
- IPC_MESSAGE_ROUTED1(PluginMsg_DidFinishLoading,
- unsigned long /* id */)
+IPC_MESSAGE_ROUTED1(PluginMsg_DidFinishLoading,
+ unsigned long /* id */)
- IPC_MESSAGE_ROUTED1(PluginMsg_DidFail,
- unsigned long /* id */)
+IPC_MESSAGE_ROUTED1(PluginMsg_DidFail,
+ unsigned long /* id */)
- IPC_MESSAGE_ROUTED4(PluginMsg_SendJavaScriptStream,
- GURL /* url */,
- std::string /* result */,
- bool /* success */,
- int /* notify_id */)
+IPC_MESSAGE_ROUTED4(PluginMsg_SendJavaScriptStream,
+ GURL /* url */,
+ std::string /* result */,
+ bool /* success */,
+ int /* notify_id */)
- IPC_MESSAGE_ROUTED2(PluginMsg_DidReceiveManualResponse,
- GURL /* url */,
- PluginMsg_DidReceiveResponseParams)
+IPC_MESSAGE_ROUTED2(PluginMsg_DidReceiveManualResponse,
+ GURL /* url */,
+ PluginMsg_DidReceiveResponseParams)
- IPC_MESSAGE_ROUTED1(PluginMsg_DidReceiveManualData,
- std::vector<char> /* buffer */)
+IPC_MESSAGE_ROUTED1(PluginMsg_DidReceiveManualData,
+ std::vector<char> /* buffer */)
- IPC_MESSAGE_ROUTED0(PluginMsg_DidFinishManualLoading)
+IPC_MESSAGE_ROUTED0(PluginMsg_DidFinishManualLoading)
- IPC_MESSAGE_ROUTED0(PluginMsg_DidManualLoadFail)
+IPC_MESSAGE_ROUTED0(PluginMsg_DidManualLoadFail)
- IPC_MESSAGE_ROUTED0(PluginMsg_InstallMissingPlugin)
+IPC_MESSAGE_ROUTED0(PluginMsg_InstallMissingPlugin)
- IPC_MESSAGE_ROUTED3(PluginMsg_HandleURLRequestReply,
- unsigned long /* resource_id */,
- GURL /* url */,
- int /* notify_id */)
+IPC_MESSAGE_ROUTED3(PluginMsg_HandleURLRequestReply,
+ unsigned long /* resource_id */,
+ GURL /* url */,
+ int /* notify_id */)
- IPC_MESSAGE_ROUTED2(PluginMsg_HTTPRangeRequestReply,
- unsigned long /* resource_id */,
- int /* range_request_id */)
+IPC_MESSAGE_ROUTED2(PluginMsg_HTTPRangeRequestReply,
+ unsigned long /* resource_id */,
+ int /* range_request_id */)
- IPC_SYNC_MESSAGE_ROUTED0_1(PluginMsg_CreateCommandBuffer,
- int /* route_id */)
+IPC_SYNC_MESSAGE_ROUTED0_1(PluginMsg_CreateCommandBuffer,
+ int /* route_id */)
- IPC_MESSAGE_ROUTED0(PluginMsg_DestroyCommandBuffer)
+IPC_MESSAGE_ROUTED0(PluginMsg_DestroyCommandBuffer)
- IPC_MESSAGE_CONTROL1(PluginMsg_SignalModalDialogEvent,
- gfx::NativeViewId /* containing_window */)
+IPC_MESSAGE_CONTROL1(PluginMsg_SignalModalDialogEvent,
+ gfx::NativeViewId /* containing_window */)
- IPC_MESSAGE_CONTROL1(PluginMsg_ResetModalDialogEvent,
- gfx::NativeViewId /* containing_window */)
+IPC_MESSAGE_CONTROL1(PluginMsg_ResetModalDialogEvent,
+ gfx::NativeViewId /* containing_window */)
#if defined(OS_MACOSX)
- // This message, used only on 10.6 and later, transmits the "fake"
- // window handle allocated by the browser on behalf of the renderer
- // to the GPU plugin.
- IPC_MESSAGE_ROUTED1(PluginMsg_SetFakeAcceleratedSurfaceWindowHandle,
- gfx::PluginWindowHandle /* window */)
+// This message, used only on 10.6 and later, transmits the "fake"
+// window handle allocated by the browser on behalf of the renderer
+// to the GPU plugin.
+IPC_MESSAGE_ROUTED1(PluginMsg_SetFakeAcceleratedSurfaceWindowHandle,
+ gfx::PluginWindowHandle /* window */)
#endif
- IPC_MESSAGE_CONTROL3(PluginMsg_ClearSiteData,
- uint64, /* flags */
- std::string, /* domain */
- base::Time /* begin_time */)
-
-IPC_END_MESSAGES(Plugin)
+IPC_MESSAGE_CONTROL3(PluginMsg_ClearSiteData,
+ uint64, /* flags */
+ std::string, /* domain */
+ base::Time /* begin_time */)
//-----------------------------------------------------------------------------
// PluginHost messages
// These are messages sent from the plugin process to the renderer process.
// They all map to the corresponding WebPlugin methods.
-IPC_BEGIN_MESSAGES(PluginHost)
- // Sends the plugin window information to the renderer.
- // The window parameter is a handle to the window if the plugin is a windowed
- // plugin. It is NULL for windowless plugins.
- IPC_SYNC_MESSAGE_ROUTED1_0(PluginHostMsg_SetWindow,
- gfx::PluginWindowHandle /* window */)
+// Sends the plugin window information to the renderer.
+// The window parameter is a handle to the window if the plugin is a windowed
+// plugin. It is NULL for windowless plugins.
+IPC_SYNC_MESSAGE_ROUTED1_0(PluginHostMsg_SetWindow,
+ gfx::PluginWindowHandle /* window */)
#if defined(OS_WIN)
- // The modal_loop_pump_messages_event parameter is an event handle which is
- // passed in for windowless plugins and is used to indicate if messages
- // are to be pumped in sync calls to the plugin process. Currently used
- // in HandleEvent calls.
- IPC_SYNC_MESSAGE_ROUTED1_0(PluginHostMsg_SetWindowlessPumpEvent,
- HANDLE /* modal_loop_pump_messages_event */)
+// The modal_loop_pump_messages_event parameter is an event handle which is
+// passed in for windowless plugins and is used to indicate if messages
+// are to be pumped in sync calls to the plugin process. Currently used
+// in HandleEvent calls.
+IPC_SYNC_MESSAGE_ROUTED1_0(PluginHostMsg_SetWindowlessPumpEvent,
+ HANDLE /* modal_loop_pump_messages_event */)
#endif
- IPC_MESSAGE_ROUTED1(PluginHostMsg_URLRequest,
- PluginHostMsg_URLRequest_Params)
+IPC_MESSAGE_ROUTED1(PluginHostMsg_URLRequest,
+ PluginHostMsg_URLRequest_Params)
- IPC_MESSAGE_ROUTED1(PluginHostMsg_CancelResource,
- int /* id */)
+IPC_MESSAGE_ROUTED1(PluginHostMsg_CancelResource,
+ int /* id */)
- IPC_MESSAGE_ROUTED1(PluginHostMsg_InvalidateRect,
- gfx::Rect /* rect */)
+IPC_MESSAGE_ROUTED1(PluginHostMsg_InvalidateRect,
+ gfx::Rect /* rect */)
- IPC_SYNC_MESSAGE_ROUTED1_1(PluginHostMsg_GetWindowScriptNPObject,
- int /* route id */,
- bool /* success */)
+IPC_SYNC_MESSAGE_ROUTED1_1(PluginHostMsg_GetWindowScriptNPObject,
+ int /* route id */,
+ bool /* success */)
- IPC_SYNC_MESSAGE_ROUTED1_1(PluginHostMsg_GetPluginElement,
- int /* route id */,
- bool /* success */)
+IPC_SYNC_MESSAGE_ROUTED1_1(PluginHostMsg_GetPluginElement,
+ int /* route id */,
+ bool /* success */)
- IPC_MESSAGE_ROUTED3(PluginHostMsg_SetCookie,
- GURL /* url */,
- GURL /* first_party_for_cookies */,
- std::string /* cookie */)
+IPC_MESSAGE_ROUTED3(PluginHostMsg_SetCookie,
+ GURL /* url */,
+ GURL /* first_party_for_cookies */,
+ std::string /* cookie */)
- IPC_SYNC_MESSAGE_ROUTED2_1(PluginHostMsg_GetCookies,
- GURL /* url */,
- GURL /* first_party_for_cookies */,
- std::string /* cookies */)
+IPC_SYNC_MESSAGE_ROUTED2_1(PluginHostMsg_GetCookies,
+ GURL /* url */,
+ GURL /* first_party_for_cookies */,
+ std::string /* cookies */)
- // Asks the browser to show a modal HTML dialog. The dialog is passed the
- // given arguments as a JSON string, and returns its result as a JSON string
- // through json_retval.
- IPC_SYNC_MESSAGE_ROUTED4_1(PluginHostMsg_ShowModalHTMLDialog,
- GURL /* url */,
- int /* width */,
- int /* height */,
- std::string /* json_arguments */,
- std::string /* json_retval */)
+// Asks the browser to show a modal HTML dialog. The dialog is passed the
+// given arguments as a JSON string, and returns its result as a JSON string
+// through json_retval.
+IPC_SYNC_MESSAGE_ROUTED4_1(PluginHostMsg_ShowModalHTMLDialog,
+ GURL /* url */,
+ int /* width */,
+ int /* height */,
+ std::string /* json_arguments */,
+ std::string /* json_retval */)
- IPC_SYNC_MESSAGE_ROUTED2_2(PluginHostMsg_GetDragData,
- NPVariant_Param /* event */,
- bool /* add_data */,
- std::vector<NPVariant_Param> /* result_values */,
- bool /* result_success */)
+IPC_SYNC_MESSAGE_ROUTED2_2(PluginHostMsg_GetDragData,
+ NPVariant_Param /* event */,
+ bool /* add_data */,
+ std::vector<NPVariant_Param> /* result_values */,
+ bool /* result_success */)
- IPC_SYNC_MESSAGE_ROUTED2_1(PluginHostMsg_SetDropEffect,
- NPVariant_Param /* event */,
- int /* effect */,
- bool /* result_success */)
+IPC_SYNC_MESSAGE_ROUTED2_1(PluginHostMsg_SetDropEffect,
+ NPVariant_Param /* event */,
+ int /* effect */,
+ bool /* result_success */)
- IPC_MESSAGE_ROUTED1(PluginHostMsg_MissingPluginStatus,
- int /* status */)
+IPC_MESSAGE_ROUTED1(PluginHostMsg_MissingPluginStatus,
+ int /* status */)
- IPC_SYNC_MESSAGE_ROUTED0_1(PluginHostMsg_GetCPBrowsingContext,
- uint32 /* context */)
+IPC_SYNC_MESSAGE_ROUTED0_1(PluginHostMsg_GetCPBrowsingContext,
+ uint32 /* context */)
- IPC_MESSAGE_ROUTED0(PluginHostMsg_CancelDocumentLoad)
+IPC_MESSAGE_ROUTED0(PluginHostMsg_CancelDocumentLoad)
- IPC_MESSAGE_ROUTED3(PluginHostMsg_InitiateHTTPRangeRequest,
- std::string /* url */,
- std::string /* range_info */,
- int /* range_request_id */)
+IPC_MESSAGE_ROUTED3(PluginHostMsg_InitiateHTTPRangeRequest,
+ std::string /* url */,
+ std::string /* range_info */,
+ int /* range_request_id */)
- IPC_MESSAGE_ROUTED2(PluginHostMsg_DeferResourceLoading,
- unsigned long /* resource_id */,
- bool /* defer */)
+IPC_MESSAGE_ROUTED2(PluginHostMsg_DeferResourceLoading,
+ unsigned long /* resource_id */,
+ bool /* defer */)
- IPC_SYNC_MESSAGE_CONTROL1_0(PluginHostMsg_SetException,
- std::string /* message */)
+IPC_SYNC_MESSAGE_CONTROL1_0(PluginHostMsg_SetException,
+ std::string /* message */)
- IPC_MESSAGE_CONTROL0(PluginHostMsg_PluginShuttingDown)
+IPC_MESSAGE_CONTROL0(PluginHostMsg_PluginShuttingDown)
#if defined(OS_MACOSX)
- IPC_MESSAGE_ROUTED1(PluginHostMsg_UpdateGeometry_ACK,
- int /* ack_key */)
-
- IPC_MESSAGE_ROUTED1(PluginHostMsg_SetImeEnabled,
- bool /* enabled */)
-
- // This message, used in Mac OS X 10.5 and earlier, is sent from the plug-in
- // process to the renderer process to indicate that the plug-in allocated a
- // new TransportDIB that holds the GPU's rendered image. This information is
- // then forwarded to the browser process via a similar message.
- IPC_MESSAGE_ROUTED4(PluginHostMsg_AcceleratedSurfaceSetTransportDIB,
- gfx::PluginWindowHandle /* window */,
- int32 /* width */,
- int32 /* height */,
- TransportDIB::Handle /* handle to the TransportDIB */)
-
- // Synthesize a fake window handle for the plug-in to identify the instance
- // to the browser, allowing mapping to a surface for hardware accelleration
- // of plug-in content. The browser generates the handle which is then set on
- // the plug-in. |opaque| indicates whether the content should be treated as
- // opaque.
- IPC_MESSAGE_ROUTED1(PluginHostMsg_BindFakePluginWindowHandle,
- bool /* opaque */)
-
- // This message, used only on 10.6 and later, is sent from the plug-in process
- // to the renderer process to indicate that the plugin allocated a new
- // IOSurface object of the given width and height. This information is then
- // forwarded on to the browser process.
- //
- // NOTE: the original intent was to pass a mach port as the IOSurface
- // identifier but it looks like that will be a lot of work. For now we pass an
- // ID from IOSurfaceGetID.
- IPC_MESSAGE_ROUTED4(PluginHostMsg_AcceleratedSurfaceSetIOSurface,
- gfx::PluginWindowHandle /* window */,
- int32 /* width */,
- int32 /* height */,
- uint64 /* surface_id */)
-
-
- // On the Mac, shared memory can't be allocated in the sandbox, so
- // the TransportDIB used by the plug-in for rendering has to be allocated
- // and managed by the browser. This is a synchronous message, use with care.
- IPC_SYNC_MESSAGE_ROUTED1_1(PluginHostMsg_AllocTransportDIB,
- size_t /* requested memory size */,
- TransportDIB::Handle /* output: DIB handle */)
-
- // Since the browser keeps handles to the allocated transport DIBs, this
- // message is sent to tell the browser that it may release them when the
- // renderer is finished with them.
- IPC_MESSAGE_ROUTED1(PluginHostMsg_FreeTransportDIB,
- TransportDIB::Id /* DIB id */)
-
- // This message notifies the renderer process (and from there the
- // browser process) that the plug-in swapped the buffers associated
- // with the given "window", which should cause the browser to redraw
- // the various plug-ins' contents.
- IPC_MESSAGE_ROUTED2(PluginHostMsg_AcceleratedSurfaceBuffersSwapped,
- gfx::PluginWindowHandle /* window */,
- uint64 /* surface_id */)
+IPC_MESSAGE_ROUTED1(PluginHostMsg_UpdateGeometry_ACK,
+ int /* ack_key */)
+
+IPC_MESSAGE_ROUTED1(PluginHostMsg_SetImeEnabled,
+ bool /* enabled */)
+
+// This message, used in Mac OS X 10.5 and earlier, is sent from the plug-in
+// process to the renderer process to indicate that the plug-in allocated a
+// new TransportDIB that holds the GPU's rendered image. This information is
+// then forwarded to the browser process via a similar message.
+IPC_MESSAGE_ROUTED4(PluginHostMsg_AcceleratedSurfaceSetTransportDIB,
+ gfx::PluginWindowHandle /* window */,
+ int32 /* width */,
+ int32 /* height */,
+ TransportDIB::Handle /* handle to the TransportDIB */)
+
+// Synthesize a fake window handle for the plug-in to identify the instance
+// to the browser, allowing mapping to a surface for hardware accelleration
+// of plug-in content. The browser generates the handle which is then set on
+// the plug-in. |opaque| indicates whether the content should be treated as
+// opaque.
+IPC_MESSAGE_ROUTED1(PluginHostMsg_BindFakePluginWindowHandle,
+ bool /* opaque */)
+
+// This message, used only on 10.6 and later, is sent from the plug-in process
+// to the renderer process to indicate that the plugin allocated a new
+// IOSurface object of the given width and height. This information is then
+// forwarded on to the browser process.
+//
+// NOTE: the original intent was to pass a mach port as the IOSurface
+// identifier but it looks like that will be a lot of work. For now we pass an
+// ID from IOSurfaceGetID.
+IPC_MESSAGE_ROUTED4(PluginHostMsg_AcceleratedSurfaceSetIOSurface,
+ gfx::PluginWindowHandle /* window */,
+ int32 /* width */,
+ int32 /* height */,
+ uint64 /* surface_id */)
+
+
+// On the Mac, shared memory can't be allocated in the sandbox, so
+// the TransportDIB used by the plug-in for rendering has to be allocated
+// and managed by the browser. This is a synchronous message, use with care.
+IPC_SYNC_MESSAGE_ROUTED1_1(PluginHostMsg_AllocTransportDIB,
+ size_t /* requested memory size */,
+ TransportDIB::Handle /* output: DIB handle */)
+
+// Since the browser keeps handles to the allocated transport DIBs, this
+// message is sent to tell the browser that it may release them when the
+// renderer is finished with them.
+IPC_MESSAGE_ROUTED1(PluginHostMsg_FreeTransportDIB,
+ TransportDIB::Id /* DIB id */)
+
+// This message notifies the renderer process (and from there the
+// browser process) that the plug-in swapped the buffers associated
+// with the given "window", which should cause the browser to redraw
+// the various plug-ins' contents.
+IPC_MESSAGE_ROUTED2(PluginHostMsg_AcceleratedSurfaceBuffersSwapped,
+ gfx::PluginWindowHandle /* window */,
+ uint64 /* surface_id */)
#endif
- IPC_MESSAGE_CONTROL1(PluginHostMsg_ClearSiteDataResult,
- bool /* success */)
+IPC_MESSAGE_CONTROL1(PluginHostMsg_ClearSiteDataResult,
+ bool /* success */)
- IPC_MESSAGE_ROUTED2(PluginHostMsg_URLRedirectResponse,
- bool /* allow */,
- int /* resource_id */)
+IPC_MESSAGE_ROUTED2(PluginHostMsg_URLRedirectResponse,
+ bool /* allow */,
+ int /* resource_id */)
-IPC_END_MESSAGES(PluginHost)
//-----------------------------------------------------------------------------
// NPObject messages
// These are messages used to marshall NPObjects. They are sent both from the
// plugin to the renderer and from the renderer to the plugin.
-IPC_BEGIN_MESSAGES(NPObject)
- IPC_SYNC_MESSAGE_ROUTED0_0(NPObjectMsg_Release)
-
- IPC_SYNC_MESSAGE_ROUTED1_1(NPObjectMsg_HasMethod,
- NPIdentifier_Param /* name */,
- bool /* result */)
-
- IPC_SYNC_MESSAGE_ROUTED3_2(NPObjectMsg_Invoke,
- bool /* is_default */,
- NPIdentifier_Param /* method */,
- std::vector<NPVariant_Param> /* args */,
- NPVariant_Param /* result_param */,
- bool /* result */)
-
- IPC_SYNC_MESSAGE_ROUTED1_1(NPObjectMsg_HasProperty,
- NPIdentifier_Param /* name */,
- bool /* result */)
-
- IPC_SYNC_MESSAGE_ROUTED1_2(NPObjectMsg_GetProperty,
- NPIdentifier_Param /* name */,
- NPVariant_Param /* property */,
- bool /* result */)
-
- IPC_SYNC_MESSAGE_ROUTED2_1(NPObjectMsg_SetProperty,
- NPIdentifier_Param /* name */,
- NPVariant_Param /* property */,
- bool /* result */)
-
- IPC_SYNC_MESSAGE_ROUTED1_1(NPObjectMsg_RemoveProperty,
- NPIdentifier_Param /* name */,
- bool /* result */)
-
- IPC_SYNC_MESSAGE_ROUTED0_0(NPObjectMsg_Invalidate)
-
- IPC_SYNC_MESSAGE_ROUTED0_2(NPObjectMsg_Enumeration,
- std::vector<NPIdentifier_Param> /* value */,
- bool /* result */)
-
- IPC_SYNC_MESSAGE_ROUTED1_2(NPObjectMsg_Construct,
- std::vector<NPVariant_Param> /* args */,
- NPVariant_Param /* result_param */,
- bool /* result */)
-
- IPC_SYNC_MESSAGE_ROUTED2_2(NPObjectMsg_Evaluate,
- std::string /* script */,
- bool /* popups_allowed */,
- NPVariant_Param /* result_param */,
- bool /* result */)
-
-IPC_END_MESSAGES(NPObject)
+IPC_SYNC_MESSAGE_ROUTED0_0(NPObjectMsg_Release)
+
+IPC_SYNC_MESSAGE_ROUTED1_1(NPObjectMsg_HasMethod,
+ NPIdentifier_Param /* name */,
+ bool /* result */)
+
+IPC_SYNC_MESSAGE_ROUTED3_2(NPObjectMsg_Invoke,
+ bool /* is_default */,
+ NPIdentifier_Param /* method */,
+ std::vector<NPVariant_Param> /* args */,
+ NPVariant_Param /* result_param */,
+ bool /* result */)
+
+IPC_SYNC_MESSAGE_ROUTED1_1(NPObjectMsg_HasProperty,
+ NPIdentifier_Param /* name */,
+ bool /* result */)
+
+IPC_SYNC_MESSAGE_ROUTED1_2(NPObjectMsg_GetProperty,
+ NPIdentifier_Param /* name */,
+ NPVariant_Param /* property */,
+ bool /* result */)
+
+IPC_SYNC_MESSAGE_ROUTED2_1(NPObjectMsg_SetProperty,
+ NPIdentifier_Param /* name */,
+ NPVariant_Param /* property */,
+ bool /* result */)
+
+IPC_SYNC_MESSAGE_ROUTED1_1(NPObjectMsg_RemoveProperty,
+ NPIdentifier_Param /* name */,
+ bool /* result */)
+
+IPC_SYNC_MESSAGE_ROUTED0_0(NPObjectMsg_Invalidate)
+
+IPC_SYNC_MESSAGE_ROUTED0_2(NPObjectMsg_Enumeration,
+ std::vector<NPIdentifier_Param> /* value */,
+ bool /* result */)
+
+IPC_SYNC_MESSAGE_ROUTED1_2(NPObjectMsg_Construct,
+ std::vector<NPVariant_Param> /* args */,
+ NPVariant_Param /* result_param */,
+ bool /* result */)
+
+IPC_SYNC_MESSAGE_ROUTED2_2(NPObjectMsg_Evaluate,
+ std::string /* script */,
+ bool /* popups_allowed */,
+ NPVariant_Param /* result_param */,
+ bool /* result */)
diff --git a/chrome/common/policy_constants.cc b/chrome/common/policy_constants.cc
index 42efba9..8ed8934 100644
--- a/chrome/common/policy_constants.cc
+++ b/chrome/common/policy_constants.cc
@@ -32,7 +32,10 @@ const char kDefaultSearchProviderIconURL[] =
const char kDefaultSearchProviderEncodings[] =
"DefaultSearchProviderEncodings";
const char kDisableSpdy[] = "DisableSpdy";
-const char kProxyServerMode[] = "ProxyServerMode";
+// We consider the name ProxyMode more apt than ProxyServerMode but could
+// not change it after publishing that name for the win registry and policy
+// config files.
+const char kProxyMode[] = "ProxyServerMode";
const char kProxyServer[] = "ProxyServer";
const char kProxyPacUrl[] = "ProxyPacUrl";
const char kProxyBypassList[] = "ProxyBypassList";
@@ -62,6 +65,8 @@ const char kDefaultImagesSetting[] = "DefaultImagesSetting";
const char kDefaultJavaScriptSetting[] = "DefaultJavaScriptSetting";
const char kDefaultPluginsSetting[] = "DefaultPluginsSetting";
const char kDefaultPopupsSetting[] = "DefaultPopupsSetting";
+const char kDefaultNotificationSetting[] = "DefaultNotificationSetting";
+const char kDefaultGeolocationSetting[] = "DefaultGeolocationSetting";
const char kAuthSchemes[] = "AuthSchemes";
const char kDisableAuthNegotiateCnameLookup[] =
"DisableAuthNegotiateCnameLookup";
diff --git a/chrome/common/policy_constants.h b/chrome/common/policy_constants.h
index c5b8536..279197e 100644
--- a/chrome/common/policy_constants.h
+++ b/chrome/common/policy_constants.h
@@ -30,7 +30,7 @@ extern const char kDefaultSearchProviderSuggestURL[];
extern const char kDefaultSearchProviderIconURL[];
extern const char kDefaultSearchProviderEncodings[];
extern const char kDisableSpdy[];
-extern const char kProxyServerMode[];
+extern const char kProxyMode[];
extern const char kProxyServer[];
extern const char kProxyPacUrl[];
extern const char kProxyBypassList[];
@@ -59,6 +59,8 @@ extern const char kDefaultImagesSetting[];
extern const char kDefaultJavaScriptSetting[];
extern const char kDefaultPluginsSetting[];
extern const char kDefaultPopupsSetting[];
+extern const char kDefaultNotificationSetting[];
+extern const char kDefaultGeolocationSetting[];
extern const char kAuthSchemes[];
extern const char kDisableAuthNegotiateCnameLookup[];
extern const char kEnableAuthNegotiatePort[];
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 8adb8fc..3da0b2c 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -41,7 +41,15 @@ const char kRestoreOnStartup[] = "session.restore_on_startup";
const char kURLsToRestoreOnStartup[] = "session.urls_to_restore_on_startup";
// The application locale.
+// For OS_CHROMEOS we maintain kApplicationLocale property in both local state
+// and user's profile. Global property determines locale of login screen,
+// while user's profile determines his personal locale preference.
const char kApplicationLocale[] = "intl.app_locale";
+#if defined(OS_CHROMEOS)
+// Non-syncable item. Used for two-step initialization of locale in ChromeOS
+// because synchronization of kApplicationLocale is not instant.
+const char kApplicationLocaleBackup[] = "intl.app_locale_backup";
+#endif
// The default character encoding to assume for a web page in the
// absence of MIME charset specification
@@ -194,18 +202,27 @@ const char kAlternateErrorPagesEnabled[] = "alternate_error_pages.enabled";
// A boolean pref set to true if DNS pre-fetching is being done in browser.
const char kDnsPrefetchingEnabled[] = "dns_prefetching.enabled";
+// OBSOLETE: new pref now stored with user prefs instead of profile, as
+// kDnsPrefetchingStartupList.
+const char kDnsStartupPrefetchList[] = "StartupDNSPrefetchList";
+
// An adaptively identified list of domain names to be pre-fetched during the
// next startup, based on what was actually needed during this startup.
-const char kDnsStartupPrefetchList[] = "StartupDNSPrefetchList";
+const char kDnsPrefetchingStartupList[] = "dns_prefetching.startup_list";
-// Disables the SPDY protocol.
-const char kDisableSpdy[] = "spdy.disabled";
+// OBSOLETE: new pref now stored with user prefs instead of profile, as
+// kDnsPrefetchingHostReferralList.
+const char kDnsHostReferralList[] = "HostReferralList";
// A list of host names used to fetch web pages, and their commonly used
// sub-resource hostnames (and expected latency benefits from pre-resolving, or
// preconnecting to, such sub-resource hostnames).
// This list is adaptively grown and pruned.
-const char kDnsHostReferralList[] = "HostReferralList";
+const char kDnsPrefetchingHostReferralList[] =
+ "dns_prefetching.host_referral_list";
+
+// Disables the SPDY protocol.
+const char kDisableSpdy[] = "spdy.disabled";
// Is the cookie prompt expanded?
const char kCookiePromptExpanded[] = "cookieprompt.expanded";
@@ -226,11 +243,18 @@ const char kInstantEnabledTime[] = "instant.enabled_time";
// that are used.
const char kInstantPromo[] = "instant.promo";
+// Used to migrate preferences from local state to user preferences to
+// enable multiple profiles.
+// Holds possible values:
+// 0: no preferences migrated yet.
+// 1: dns prefetching preferences stored in user preferences.
+const char kMultipleProfilePrefMigration[] =
+ "profile.multiple_profile_prefs_version";
+
#if defined(USE_NSS) || defined(USE_OPENSSL)
// Prefs for SSLConfigServicePref. Currently, these are only present on
// and used by NSS/OpenSSL using OSes.
const char kCertRevocationCheckingEnabled[] = "ssl.rev_checking.enabled";
-const char kSSL2Enabled[] = "ssl.ssl2.enabled";
const char kSSL3Enabled[] = "ssl.ssl3.enabled";
const char kTLS1Enabled[] = "ssl.tls1.enabled";
#endif
@@ -443,8 +467,12 @@ const char kDeleteCache[] = "browser.clear_data.cache";
const char kDeleteCookies[] = "browser.clear_data.cookies";
const char kDeletePasswords[] = "browser.clear_data.passwords";
const char kDeleteFormData[] = "browser.clear_data.form_data";
+const char kDeleteLSOData[] = "browser.clear_data.lso_data";
const char kDeleteTimePeriod[] = "browser.clear_data.time_period";
+// Whether there is a Flash version installed that supports clearing LSO data.
+const char kClearPluginLSODataEnabled[] = "browser.clear_lso_data_enabled";
+
// Boolean pref to define the default values for using spellchecker.
const char kEnableSpellCheck[] = "browser.enable_spellchecking";
@@ -555,6 +583,11 @@ const char kBlockNonsandboxedPlugins[] = "profile.block_nonsandboxed_plugins";
// storage, etc..) should be deleted on exit.
const char kClearSiteDataOnExit[] = "profile.clear_site_data_on_exit";
+// Boolean that is true when plug-in locally stored data ("Flash cookies")
+// should be deleted on exit.
+const char kClearPluginLSODataOnExit[] =
+ "profile.clear_plugin_lso_data_on_exit";
+
// Double that indicates the default zoom level.
const char kDefaultZoomLevel[] = "profile.default_zoom_level";
@@ -763,11 +796,6 @@ const char kPreferencesWindowPlacement[] = "preferences.window_placement";
// renderer's in-memory cache of objects.
const char kMemoryCacheSize[] = "renderer.memory_cache.size";
-// Boolean that records if chrome has set "launch on startup" property for
-// itself earlier and is allowed to reset it later, reducing likelihood of
-// overriding user choices.
-const char kLaunchOnStartupResetAllowed[] = "launch_on_startup_reset_allowed";
-
// String which specifies where to download files to by default.
const char kDownloadDefaultDirectory[] = "download.default_directory";
@@ -1001,6 +1029,7 @@ const char kSyncPasswords[] = "sync.passwords";
const char kSyncPreferences[] = "sync.preferences";
const char kSyncApps[] = "sync.apps";
const char kSyncAutofill[] = "sync.autofill";
+const char kSyncAutofillProfile[] = "sync.autofill_profile";
const char kSyncThemes[] = "sync.themes";
const char kSyncTypedUrls[] = "sync.typed_urls";
const char kSyncExtensions[] = "sync.extensions";
@@ -1018,6 +1047,10 @@ const char kSyncSuppressStart[] = "sync.suppress_start";
// user settings DB to the token service.
const char kSyncCredentialsMigrated[] = "sync.credentials_migrated";
+// Boolean to represent whether the legacy autofill profile data has been
+// migrated to the new model.
+const char kAutofillProfileMigrated[] = "sync.autofill_migrated";
+
// A string that can be used to restore sync encryption infrastructure on
// startup so that the user doesn't need to provide credentials on each start.
const char kEncryptionBootstrapToken[] = "sync.encryption_bootstrap_token";
@@ -1102,11 +1135,10 @@ const char kCloudPrintPrintSystemSettings[] =
// Used by the service process to determine if the remoting host is enabled.
const char kRemotingHostEnabled[] = "remoting.host_enabled";
-// Boolean to disable proxy altogether. If true, other proxy
-// preferences are ignored.
-const char kNoProxyServer[] = "proxy.disabled";
-// Boolean specifying if proxy should be auto-detected.
-const char kProxyAutoDetect[] = "proxy.auto_detect";
+// Integer to specify the type of proxy settings.
+// See ProxyPrefs for possible values and interactions with the other proxy
+// preferences.
+const char kProxyMode[] = "proxy.mode";
// String specifying the proxy server. For a specification of the expected
// syntax see net::ProxyConfig::ProxyRules::ParseFromString().
const char kProxyServer[] = "proxy.server";
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index fae79ec..0450a21 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -25,6 +25,9 @@ extern const char kURLsToRestoreOnStartup[];
// and user's profile. Global property determines locale of login screen,
// while user's profile determines his personal locale preference.
extern const char kApplicationLocale[];
+#if defined(OS_CHROMEOS)
+extern const char kApplicationLocaleBackup[];
+#endif
extern const char kDefaultCharset[];
extern const char kAcceptLanguages[];
@@ -75,8 +78,10 @@ extern const char kSearchProviderOverridesVersion[];
extern const char kPromptForDownload[];
extern const char kAlternateErrorPagesEnabled[];
extern const char kDnsPrefetchingEnabled[];
-extern const char kDnsStartupPrefetchList[];
-extern const char kDnsHostReferralList[];
+extern const char kDnsStartupPrefetchList[]; // OBSOLETE
+extern const char kDnsPrefetchingStartupList[];
+extern const char kDnsHostReferralList[]; // OBSOLETE
+extern const char kDnsPrefetchingHostReferralList[];
extern const char kDisableSpdy[];
extern const char kCookiePromptExpanded[];
extern const char kInstantConfirmDialogShown[];
@@ -84,9 +89,9 @@ extern const char kInstantEnabled[];
extern const char kInstantEnabledOnce[];
extern const char kInstantEnabledTime[];
extern const char kInstantPromo[];
+extern const char kMultipleProfilePrefMigration[];
#if defined(USE_NSS) || defined(USE_OPENSSL)
extern const char kCertRevocationCheckingEnabled[];
-extern const char kSSL2Enabled[];
extern const char kSSL3Enabled[];
extern const char kTLS1Enabled[];
#endif
@@ -168,6 +173,8 @@ extern const char kDeleteCache[];
extern const char kDeleteCookies[];
extern const char kDeletePasswords[];
extern const char kDeleteFormData[];
+extern const char kDeleteLSOData[];
+extern const char kClearPluginLSODataEnabled[];
extern const char kEnableSpellCheck[];
extern const char kEnabledLabsExperiments[];
extern const char kEnableAutoSpellCorrect[];
@@ -211,6 +218,7 @@ extern const char kContentSettingsPatterns[];
extern const char kBlockThirdPartyCookies[];
extern const char kBlockNonsandboxedPlugins[];
extern const char kClearSiteDataOnExit[];
+extern const char kClearPluginLSODataOnExit[];
extern const char kDefaultZoomLevel[];
extern const char kPerHostZoomLevels[];
extern const char kAutoFillEnabled[];
@@ -275,8 +283,6 @@ extern const char kKeywordEditorWindowPlacement[];
extern const char kPreferencesWindowPlacement[];
extern const char kMemoryCacheSize[];
-extern const char kLaunchOnStartupResetAllowed[];
-
extern const char kDownloadDefaultDirectory[];
extern const char kDownloadExtensionsToOpen[];
extern const char kDownloadDirUpgraded[];
@@ -370,6 +376,7 @@ extern const char kSyncPasswords[];
extern const char kSyncPreferences[];
extern const char kSyncApps[];
extern const char kSyncAutofill[];
+extern const char kSyncAutofillProfile[];
extern const char kSyncThemes[];
extern const char kSyncTypedUrls[];
extern const char kSyncExtensions[];
@@ -379,6 +386,7 @@ extern const char kGoogleServicesUsername[];
extern const char kSyncCredentialsMigrated[];
extern const char kSyncUsingSecondaryPassphrase[];
extern const char kEncryptionBootstrapToken[];
+extern const char kAutofillProfileMigrated[];
extern const char kWebAppCreateOnDesktop[];
extern const char kWebAppCreateInAppsMenu[];
@@ -403,8 +411,7 @@ extern const char kCloudPrintPrintSystemSettings[];
extern const char kRemotingHasSetupCompleted[];
extern const char kRemotingHostEnabled[];
-extern const char kNoProxyServer[];
-extern const char kProxyAutoDetect[];
+extern const char kProxyMode[];
extern const char kProxyServer[];
extern const char kProxyPacUrl[];
extern const char kProxyBypassList[];
diff --git a/chrome/common/pref_store.cc b/chrome/common/pref_store.cc
index cf85417..47e7c38 100644
--- a/chrome/common/pref_store.cc
+++ b/chrome/common/pref_store.cc
@@ -3,12 +3,7 @@
// found in the LICENSE file.
#include "chrome/common/pref_store.h"
-#include "base/values.h"
-Value* PrefStore::CreateUseDefaultSentinelValue() {
- return Value::CreateNullValue();
-}
-
-bool PrefStore::IsUseDefaultSentinelValue(Value* value) {
- return value->IsType(Value::TYPE_NULL);
+bool PrefStore::IsInitializationComplete() const {
+ return true;
}
diff --git a/chrome/common/pref_store.h b/chrome/common/pref_store.h
index 7011eba..35818a0 100644
--- a/chrome/common/pref_store.h
+++ b/chrome/common/pref_store.h
@@ -6,62 +6,58 @@
#define CHROME_COMMON_PREF_STORE_H_
#pragma once
-class DictionaryValue;
+#include <string>
+
+#include "base/basictypes.h"
+
class Value;
// This is an abstract interface for reading and writing from/to a persistent
-// preference store, used by |PrefService|. An implementation using a JSON file
-// can be found in |JsonPrefStore|, while an implementation without any backing
-// store (currently used for testing) can be found in |DummyPrefStore|.
+// preference store, used by PrefService. An implementation using a JSON file
+// can be found in JsonPrefStore, while an implementation without any backing
+// store for testing can be found in TestingPrefStore. Furthermore, there is
+// CommandLinePrefStore, which bridges command line options to preferences and
+// ConfigurationPolicyPrefStore, which is used for hooking up configuration
+// policy with the preference subsystem.
class PrefStore {
public:
- // Unique integer code for each type of error so we can report them
- // distinctly in a histogram.
- // NOTE: Don't change the order here as it will change the server's meaning
- // of the histogram.
- enum PrefReadError {
- PREF_READ_ERROR_NONE = 0,
- PREF_READ_ERROR_JSON_PARSE,
- PREF_READ_ERROR_JSON_TYPE,
- PREF_READ_ERROR_ACCESS_DENIED,
- PREF_READ_ERROR_FILE_OTHER,
- PREF_READ_ERROR_FILE_LOCKED,
- PREF_READ_ERROR_NO_FILE,
- PREF_READ_ERROR_JSON_REPEAT,
- PREF_READ_ERROR_OTHER,
- PREF_READ_ERROR_FILE_NOT_SPECIFIED
+ // Observer interface for monitoring PrefStore.
+ class Observer {
+ public:
+ virtual ~Observer() {}
+
+ // Called when the value for the given |key| in the store changes.
+ virtual void OnPrefValueChanged(const std::string& key) = 0;
+ // Notification about the PrefStore being fully initialized.
+ virtual void OnInitializationCompleted() = 0;
};
- // To require that the default value be used for a preference, a
- // PrefStore can set the value in its own prefs dictionary to the
- // sentinel Value returned by this function.
- // TODO(danno): Instead of having a sentinel value, pref stores
- // should return a richer set of information from the property
- // accessor methods to indicate that the default should be used.
- static Value* CreateUseDefaultSentinelValue();
-
- // Returns true if a value is the special sentinel value created by
- // CreateUseDefaultSentinelValue.
- static bool IsUseDefaultSentinelValue(Value* value);
-
- virtual ~PrefStore() { }
+ // Return values for GetValue().
+ enum ReadResult {
+ // Value found and returned.
+ READ_OK,
+ // No value present, but skip other pref stores and use default.
+ READ_USE_DEFAULT,
+ // No value present.
+ READ_NO_VALUE,
+ };
- // Whether the store is in a pseudo-read-only mode where changes are not
- // actually persisted to disk. This happens in some cases when there are
- // read errors during startup.
- virtual bool ReadOnly() { return true; }
+ PrefStore() {}
+ virtual ~PrefStore() {}
- // TODO(danno): PrefValueStore shouldn't allow direct access to the
- // DictionaryValue. Instead, it should have getters that return a
- // richer set of information for a pref, including if the store
- // wants to return the default value for a preference.
- virtual DictionaryValue* prefs() const = 0;
+ // Add and remove observers.
+ virtual void AddObserver(Observer* observer) {}
+ virtual void RemoveObserver(Observer* observer) {}
- virtual PrefReadError ReadPrefs() = 0;
+ // Whether the store has completed all asynchronous initialization.
+ virtual bool IsInitializationComplete() const;
- virtual bool WritePrefs() { return true; }
+ // Get the value for a given preference |key| and stores it in |result|.
+ // |result| is only modified if the return value is READ_OK. Ownership of the
+ // |result| value remains with the PrefStore.
+ virtual ReadResult GetValue(const std::string& key, Value** result) const = 0;
- virtual void ScheduleWritePrefs() { }
+ DISALLOW_COPY_AND_ASSIGN(PrefStore);
};
#endif // CHROME_COMMON_PREF_STORE_H_
diff --git a/chrome/common/pref_store_observer_mock.h b/chrome/common/pref_store_observer_mock.h
new file mode 100644
index 0000000..2a49284
--- /dev/null
+++ b/chrome/common/pref_store_observer_mock.h
@@ -0,0 +1,26 @@
+// 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.
+
+#ifndef CHROME_COMMON_PREF_STORE_OBSERVER_MOCK_H_
+#define CHROME_COMMON_PREF_STORE_OBSERVER_MOCK_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "chrome/common/pref_store.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+// A gmock-ified implementation of PrefStore::Observer.
+class PrefStoreObserverMock : public PrefStore::Observer {
+ public:
+ PrefStoreObserverMock() {}
+ virtual ~PrefStoreObserverMock() {}
+
+ MOCK_METHOD1(OnPrefValueChanged, void(const std::string&));
+ MOCK_METHOD0(OnInitializationCompleted, void());
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PrefStoreObserverMock);
+};
+
+#endif // CHROME_COMMON_PREF_STORE_OBSERVER_MOCK_H_
diff --git a/chrome/common/remoting/chromoting_host_info.h b/chrome/common/remoting/chromoting_host_info.h
new file mode 100644
index 0000000..e803eef
--- /dev/null
+++ b/chrome/common/remoting/chromoting_host_info.h
@@ -0,0 +1,23 @@
+// 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.
+
+#ifndef CHROME_COMMON_REMOTING_CHROMOTING_HOST_INFO_H_
+#define CHROME_COMMON_REMOTING_CHROMOTING_HOST_INFO_H_
+
+#include <string>
+
+namespace remoting {
+
+// This struct is used for ServiceHostMsg_ChromotingHost_Info IPC message.
+struct ChromotingHostInfo {
+ std::string host_id;
+ std::string hostname;
+ std::string public_key;
+ std::string login;
+ bool enabled;
+};
+
+} // namespace remoting
+
+#endif // CHROME_COMMON_REMOTING_CHROMOTING_HOST_INFO_H_
diff --git a/chrome/common/render_messages.cc b/chrome/common/render_messages.cc
index be20600..c865a68 100644
--- a/chrome/common/render_messages.cc
+++ b/chrome/common/render_messages.cc
@@ -2,18 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/common/render_messages.h"
-
#include "base/values.h"
#include "chrome/common/edit_command.h"
#include "chrome/common/extensions/extension_extent.h"
#include "chrome/common/extensions/url_pattern.h"
#include "chrome/common/gpu_param_traits.h"
-#include "chrome/common/indexed_db_key.h"
-#include "chrome/common/indexed_db_param_traits.h"
#include "chrome/common/render_messages_params.h"
#include "chrome/common/resource_response.h"
-#include "chrome/common/serialized_script_value.h"
#include "chrome/common/speech_input_result.h"
#include "chrome/common/thumbnail_score.h"
#include "chrome/common/web_apps.h"
@@ -23,33 +18,24 @@
#include "net/base/upload_data.h"
#include "net/http/http_response_headers.h"
#include "third_party/WebKit/WebKit/chromium/public/WebCompositionUnderline.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebFindOptions.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebMediaPlayerAction.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebScreenInfo.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "webkit/appcache/appcache_interfaces.h"
#include "webkit/blob/blob_data.h"
-#include "webkit/glue/context_menu.h"
-#include "webkit/glue/form_data.h"
#include "webkit/glue/form_field.h"
#include "webkit/glue/password_form.h"
-#include "webkit/glue/password_form_dom_manager.h"
-#include "webkit/glue/plugins/webplugin.h"
-#include "webkit/glue/plugins/webplugininfo.h"
#include "webkit/glue/resource_loader_bridge.h"
#include "webkit/glue/webaccessibility.h"
#include "webkit/glue/webcookie.h"
#include "webkit/glue/webcursor.h"
-#include "webkit/glue/webdropdata.h"
#include "webkit/glue/webmenuitem.h"
+#include "webkit/plugins/npapi/webplugin.h"
#if defined(OS_MACOSX)
#include "chrome/common/font_descriptor_mac.h"
#endif
-#define MESSAGES_INTERNAL_IMPL_FILE \
- "chrome/common/render_messages_internal.h"
-#include "ipc/ipc_message_impl_macros.h"
+#define IPC_MESSAGE_IMPL
+#include "chrome/common/render_messages.h"
namespace IPC {
@@ -210,8 +196,8 @@ void ParamTraits<ContextMenuParams>::Log(const param_type& p,
l->append("<ContextMenuParams>");
}
-void ParamTraits<webkit_glue::WebPluginGeometry>::Write(Message* m,
- const param_type& p) {
+void ParamTraits<webkit::npapi::WebPluginGeometry>::Write(Message* m,
+ const param_type& p) {
WriteParam(m, p.window);
WriteParam(m, p.window_rect);
WriteParam(m, p.clip_rect);
@@ -220,7 +206,7 @@ void ParamTraits<webkit_glue::WebPluginGeometry>::Write(Message* m,
WriteParam(m, p.visible);
}
-bool ParamTraits<webkit_glue::WebPluginGeometry>::Read(
+bool ParamTraits<webkit::npapi::WebPluginGeometry>::Read(
const Message* m, void** iter, param_type* p) {
return
ReadParam(m, iter, &p->window) &&
@@ -231,8 +217,8 @@ bool ParamTraits<webkit_glue::WebPluginGeometry>::Read(
ReadParam(m, iter, &p->visible);
}
-void ParamTraits<webkit_glue::WebPluginGeometry>::Log(const param_type& p,
- std::string* l) {
+void ParamTraits<webkit::npapi::WebPluginGeometry>::Log(const param_type& p,
+ std::string* l) {
l->append("(");
LogParam(p.window, l);
l->append(", ");
@@ -248,21 +234,24 @@ void ParamTraits<webkit_glue::WebPluginGeometry>::Log(const param_type& p,
l->append(")");
}
-void ParamTraits<WebPluginMimeType>::Write(Message* m, const param_type& p) {
+void ParamTraits<webkit::npapi::WebPluginMimeType>::Write(Message* m,
+ const param_type& p) {
WriteParam(m, p.mime_type);
WriteParam(m, p.file_extensions);
WriteParam(m, p.description);
}
-bool ParamTraits<WebPluginMimeType>::Read(const Message* m, void** iter,
- param_type* r) {
+bool ParamTraits<webkit::npapi::WebPluginMimeType>::Read(const Message* m,
+ void** iter,
+ param_type* r) {
return
ReadParam(m, iter, &r->mime_type) &&
ReadParam(m, iter, &r->file_extensions) &&
ReadParam(m, iter, &r->description);
}
-void ParamTraits<WebPluginMimeType>::Log(const param_type& p, std::string* l) {
+void ParamTraits<webkit::npapi::WebPluginMimeType>::Log(const param_type& p,
+ std::string* l) {
l->append("(");
LogParam(p.mime_type, l);
l->append(", ");
@@ -272,7 +261,8 @@ void ParamTraits<WebPluginMimeType>::Log(const param_type& p, std::string* l) {
l->append(")");
}
-void ParamTraits<WebPluginInfo>::Write(Message* m, const param_type& p) {
+void ParamTraits<webkit::npapi::WebPluginInfo>::Write(Message* m,
+ const param_type& p) {
WriteParam(m, p.name);
WriteParam(m, p.path);
WriteParam(m, p.version);
@@ -281,8 +271,9 @@ void ParamTraits<WebPluginInfo>::Write(Message* m, const param_type& p) {
WriteParam(m, p.enabled);
}
-bool ParamTraits<WebPluginInfo>::Read(const Message* m, void** iter,
- param_type* r) {
+bool ParamTraits<webkit::npapi::WebPluginInfo>::Read(const Message* m,
+ void** iter,
+ param_type* r) {
return
ReadParam(m, iter, &r->name) &&
ReadParam(m, iter, &r->path) &&
@@ -292,7 +283,8 @@ bool ParamTraits<WebPluginInfo>::Read(const Message* m, void** iter,
ReadParam(m, iter, &r->enabled);
}
-void ParamTraits<WebPluginInfo>::Log(const param_type& p, std::string* l) {
+void ParamTraits<webkit::npapi::WebPluginInfo>::Log(const param_type& p,
+ std::string* l) {
l->append("(");
LogParam(p.name, l);
l->append(", ");
@@ -1222,26 +1214,6 @@ void ParamTraits<AudioBuffersState>::Log(const param_type& p, std::string* l) {
l->append(")");
}
-void ParamTraits<PepperDirEntry>::Write(Message* m, const param_type& p) {
- WriteParam(m, p.name);
- WriteParam(m, p.is_dir);
-}
-
-bool ParamTraits<PepperDirEntry>::Read(const Message* m,
- void** iter,
- param_type* p) {
- return ReadParam(m, iter, &p->name) &&
- ReadParam(m, iter, &p->is_dir);
-}
-
-void ParamTraits<PepperDirEntry>::Log(const param_type& p, std::string* l) {
- l->append("(");
- LogParam(p.name, l);
- l->append(", ");
- LogParam(p.is_dir, l);
- l->append(")");
-}
-
void ParamTraits<speech_input::SpeechInputResultItem>::Write(
Message* m, const param_type& p) {
WriteParam(m, p.utterance);
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h
index fb68afa..e06a667 100644
--- a/chrome/common/render_messages.h
+++ b/chrome/common/render_messages.h
@@ -17,18 +17,14 @@
#include "base/string16.h"
#include "chrome/common/common_param_traits.h"
#include "chrome/common/css_colors.h"
-#include "chrome/common/dom_storage_common.h"
-#include "chrome/common/indexed_db_param_traits.h"
#include "chrome/common/page_transition_types.h"
#include "chrome/common/translate_errors.h"
#include "chrome/common/view_types.h"
#include "chrome/common/webkit_param_traits.h"
#include "ipc/ipc_message_utils.h"
#include "ipc/ipc_platform_file.h" // ifdefed typedef.
-#include "third_party/WebKit/WebKit/chromium/public/WebStorageArea.h"
#include "webkit/appcache/appcache_interfaces.h" // enum appcache::Status
#include "webkit/fileapi/file_system_types.h" // enum fileapi::FileSystemType
-#include "webkit/glue/plugins/pepper_dir_contents.h"
#if defined(OS_MACOSX)
struct FontDescriptor;
@@ -65,10 +61,17 @@ struct ResourceLoadTimingInfo;
struct ResourceResponseInfo;
struct WebAccessibility;
struct WebCookie;
-struct WebPluginGeometry;
struct WebAccessibility;
}
+namespace webkit {
+namespace npapi {
+struct WebPluginGeometry;
+struct WebPluginInfo;
+struct WebPluginMimeType;
+}
+}
+
struct AudioBuffersState;
class ExtensionExtent;
class GURL;
@@ -81,8 +84,6 @@ struct SyncLoadResult;
struct RendererPreferences;
struct WebDropData;
struct WebMenuItem;
-struct WebPluginInfo;
-struct WebPluginMimeType;
struct WebPreferences;
// Forward declarations of structures used to store data for when we have a lot
@@ -99,17 +100,11 @@ struct ViewHostMsg_Resource_Request;
struct ViewMsg_Print_Params;
struct ViewMsg_PrintPage_Params;
struct ViewMsg_PrintPages_Params;
+struct ViewHostMsg_DidPreviewDocument_Params;
struct ViewHostMsg_DidPrintPage_Params;
struct ViewHostMsg_Audio_CreateStream_Params;
struct ViewHostMsg_ShowPopup_Params;
struct ViewHostMsg_ScriptedPrint_Params;
-struct ViewMsg_DOMStorageEvent_Params;
-struct ViewHostMsg_IDBFactoryOpen_Params;
-struct ViewHostMsg_IDBDatabaseCreateObjectStore_Params;
-struct ViewHostMsg_IDBIndexOpenCursor_Params;
-struct ViewHostMsg_IDBObjectStoreCreateIndex_Params;
-struct ViewHostMsg_IDBObjectStoreOpenCursor_Params;
-struct ViewHostMsg_IDBObjectStorePut_Params;
struct ViewMsg_ExecuteCode_Params;
struct ViewHostMsg_CreateWorker_Params;
struct ViewHostMsg_ShowNotification_Params;
@@ -162,8 +157,8 @@ struct ParamTraits<ContextMenuParams> {
};
template <>
-struct ParamTraits<webkit_glue::WebPluginGeometry> {
- typedef webkit_glue::WebPluginGeometry param_type;
+struct ParamTraits<webkit::npapi::WebPluginGeometry> {
+ typedef webkit::npapi::WebPluginGeometry param_type;
static void Write(Message* m, const param_type& p);
static bool Read(const Message* m, void** iter, param_type* p);
static void Log(const param_type& p, std::string* l);
@@ -171,16 +166,16 @@ struct ParamTraits<webkit_glue::WebPluginGeometry> {
// Traits for ViewMsg_GetPlugins_Reply structure to pack/unpack.
template <>
-struct ParamTraits<WebPluginMimeType> {
- typedef WebPluginMimeType param_type;
+struct ParamTraits<webkit::npapi::WebPluginMimeType> {
+ typedef webkit::npapi::WebPluginMimeType param_type;
static void Write(Message* m, const param_type& p);
static bool Read(const Message* m, void** iter, param_type* r);
static void Log(const param_type& p, std::string* l);
};
template <>
-struct ParamTraits<WebPluginInfo> {
- typedef WebPluginInfo param_type;
+struct ParamTraits<webkit::npapi::WebPluginInfo> {
+ typedef webkit::npapi::WebPluginInfo param_type;
static void Write(Message* m, const param_type& p);
static bool Read(const Message* m, void** iter, param_type* r);
static void Log(const param_type& p, std::string* l);
@@ -480,73 +475,6 @@ struct ParamTraits<EditCommand> {
static void Log(const param_type& p, std::string* l);
};
-// Traits for DOMStorageType enum.
-template <>
-struct ParamTraits<DOMStorageType> {
- typedef DOMStorageType param_type;
- static void Write(Message* m, const param_type& p) {
- m->WriteInt(p);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- int type;
- if (!m->ReadInt(iter, &type))
- return false;
- *p = static_cast<param_type>(type);
- return true;
- }
- static void Log(const param_type& p, std::string* l) {
- std::string control;
- switch (p) {
- case DOM_STORAGE_LOCAL:
- control = "DOM_STORAGE_LOCAL";
- break;
- case DOM_STORAGE_SESSION:
- control = "DOM_STORAGE_SESSION";
- break;
- default:
- NOTIMPLEMENTED();
- control = "UNKNOWN";
- break;
- }
- LogParam(control, l);
- }
-};
-
-// Traits for WebKit::WebStorageArea::Result enum.
-template <>
-struct ParamTraits<WebKit::WebStorageArea::Result> {
- typedef WebKit::WebStorageArea::Result param_type;
- static void Write(Message* m, const param_type& p) {
- m->WriteInt(p);
- }
- static bool Read(const Message* m, void** iter, param_type* p) {
- int type;
- if (!m->ReadInt(iter, &type))
- return false;
- *p = static_cast<param_type>(type);
- return true;
- }
- static void Log(const param_type& p, std::string* l) {
- std::string control;
- switch (p) {
- case WebKit::WebStorageArea::ResultOK:
- control = "WebKit::WebStorageArea::ResultOK";
- break;
- case WebKit::WebStorageArea::ResultBlockedByQuota:
- control = "WebKit::WebStorageArea::ResultBlockedByQuota";
- break;
- case WebKit::WebStorageArea::ResultBlockedByPolicy:
- control = "WebKit::WebStorageArea::ResultBlockedByPolicy";
- break;
- default:
- NOTIMPLEMENTED();
- control = "UNKNOWN";
- break;
- }
- LogParam(control, l);
- }
-};
-
// Traits for WebCookie
template <>
struct ParamTraits<webkit_glue::WebCookie> {
@@ -602,12 +530,6 @@ struct ParamTraits<scoped_refptr<webkit_blob::BlobData> > {
static void Log(const param_type& p, std::string* l);
};
-// Traits for base::PlatformFileError
-template <>
-struct SimilarTypeTraits<base::PlatformFileError> {
- typedef int Type;
-};
-
template <>
struct SimilarTypeTraits<fileapi::FileSystemType> {
typedef int Type;
@@ -623,14 +545,6 @@ struct ParamTraits<AudioBuffersState> {
};
template <>
-struct ParamTraits<PepperDirEntry> {
- typedef PepperDirEntry param_type;
- static void Write(Message* m, const param_type& p);
- static bool Read(const Message* m, void** iter, param_type* p);
- static void Log(const param_type& p, std::string* l);
-};
-
-template <>
struct ParamTraits<speech_input::SpeechInputResultItem> {
typedef speech_input::SpeechInputResultItem param_type;
static void Write(Message* m, const param_type& p);
@@ -640,7 +554,6 @@ struct ParamTraits<speech_input::SpeechInputResultItem> {
} // namespace IPC
-#define MESSAGES_INTERNAL_FILE "chrome/common/render_messages_internal.h"
-#include "ipc/ipc_message_macros.h"
+#include "chrome/common/render_messages_internal.h"
#endif // CHROME_COMMON_RENDER_MESSAGES_H_
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index 2dba9ae..f94f1ed 100644
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -2,11 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// This header is meant to be included in multiple passes, hence no traditional
-// header guard.
-// See ipc_message_macros.h for explanation of the macros and passes.
-
#include <map>
+#include <set>
#include <string>
#include <vector>
@@ -27,7 +24,14 @@
#include "chrome/common/window_container_type.h"
#include "ipc/ipc_message_macros.h"
#include "media/audio/audio_buffers_state.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebExceptionCode.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebFindOptions.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebMediaPlayerAction.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebScreenInfo.h"
+#include "webkit/glue/context_menu.h"
+#include "webkit/glue/form_data.h"
+#include "webkit/glue/password_form_dom_manager.h"
+#include "webkit/glue/webdropdata.h"
+#include "webkit/plugins/npapi/webplugininfo.h"
#if defined(OS_POSIX)
#include "base/file_descriptor_posix.h"
@@ -45,8 +49,8 @@
// Substitution map for l10n messages.
typedef std::map<std::string, std::string> SubstitutionMap;
+class Value;
class GPUInfo;
-class SerializedScriptValue;
class SkBitmap;
struct ThumbnailScore;
class WebCursor;
@@ -68,3012 +72,2560 @@ namespace file_util {
struct FileInfo;
}
+#define IPC_MESSAGE_START ViewMsgStart
+
//-----------------------------------------------------------------------------
// RenderView messages
// These are messages sent from the browser to the renderer process.
-IPC_BEGIN_MESSAGES(View)
- // Used typically when recovering from a crash. The new rendering process
- // sets its global "next page id" counter to the given value.
- IPC_MESSAGE_CONTROL1(ViewMsg_SetNextPageID,
- int32 /* next_page_id */)
-
- // Sends System Colors corresponding to a set of CSS color keywords
- // down the pipe.
- // This message must be sent to the renderer immediately on launch
- // before creating any new views.
- // The message can also be sent during a renderer's lifetime if system colors
- // are updated.
- // TODO(jeremy): Possibly change IPC format once we have this all hooked up.
- IPC_MESSAGE_ROUTED1(ViewMsg_SetCSSColors,
- std::vector<CSSColors::CSSColorMapping>)
-
- // Tells the renderer to create a new view.
- // This message is slightly different, the view it takes (via
- // ViewMsg_New_Params) is the view to create, the message itself is sent as a
- // non-view control message.
- IPC_MESSAGE_CONTROL1(ViewMsg_New,
- ViewMsg_New_Params)
-
- // Tells the renderer to set its maximum cache size to the supplied value.
- IPC_MESSAGE_CONTROL3(ViewMsg_SetCacheCapacities,
- size_t /* min_dead_capacity */,
- size_t /* max_dead_capacity */,
- size_t /* capacity */)
-
- // Tells the renderer to cleat the cache.
- IPC_MESSAGE_CONTROL0(ViewMsg_ClearCache)
-
- // Reply in response to ViewHostMsg_ShowView or ViewHostMsg_ShowWidget.
- // similar to the new command, but used when the renderer created a view
- // first, and we need to update it.
- IPC_MESSAGE_ROUTED1(ViewMsg_CreatingNew_ACK,
- gfx::NativeViewId /* parent_hwnd */)
-
- // Sends updated preferences to the renderer.
- IPC_MESSAGE_ROUTED1(ViewMsg_SetRendererPrefs,
- RendererPreferences)
-
- // Tells the renderer to perform the given action on the media player
- // located at the given point.
- IPC_MESSAGE_ROUTED2(ViewMsg_MediaPlayerActionAt,
- gfx::Point, /* location */
- WebKit::WebMediaPlayerAction)
-
- // Tells the render view to close.
- IPC_MESSAGE_ROUTED0(ViewMsg_Close)
-
- // Tells the render view to change its size. A ViewHostMsg_PaintRect message
- // is generated in response provided new_size is not empty and not equal to
- // the view's current size. The generated ViewHostMsg_PaintRect message will
- // have the IS_RESIZE_ACK flag set. It also receives the resizer rect so that
- // we don't have to fetch it every time WebKit asks for it.
- IPC_MESSAGE_ROUTED2(ViewMsg_Resize,
- gfx::Size /* new_size */,
- gfx::Rect /* resizer_rect */)
-
- // Sent to inform the view that it was hidden. This allows it to reduce its
- // resource utilization.
- IPC_MESSAGE_ROUTED0(ViewMsg_WasHidden)
-
- // Tells the render view that it is no longer hidden (see WasHidden), and the
- // render view is expected to respond with a full repaint if needs_repainting
- // is true. In that case, the generated ViewHostMsg_PaintRect message will
- // have the IS_RESTORE_ACK flag set. If needs_repainting is false, then this
- // message does not trigger a message in response.
- IPC_MESSAGE_ROUTED1(ViewMsg_WasRestored,
- bool /* needs_repainting */)
-
- // Tells the render view to capture a thumbnail image of the page. The
- // render view responds with a ViewHostMsg_Thumbnail.
- IPC_MESSAGE_ROUTED0(ViewMsg_CaptureThumbnail)
-
- // Tells the render view to capture a thumbnail image of the page. The
- // render view responds with a ViewHostMsg_Snapshot.
- IPC_MESSAGE_ROUTED0(ViewMsg_CaptureSnapshot)
-
- // Tells the render view to switch the CSS to print media type, renders every
- // requested pages and switch back the CSS to display media type.
- IPC_MESSAGE_ROUTED0(ViewMsg_PrintPages)
-
- // Tells the render view that printing is done so it can clean up.
- IPC_MESSAGE_ROUTED2(ViewMsg_PrintingDone,
- int /* document_cookie */,
- bool /* success */)
-
- // Tells the render view to switch the CSS to print media type, renders every
- // requested pages for print preview.
- IPC_MESSAGE_ROUTED0(ViewMsg_PrintPreview)
-
- // Sends back to the browser the rendered "printed page" for preview that was
- // requested by a ViewMsg_PrintPage message or from scripted printing. The
- // memory handle in this message is already valid in the browser process.
- IPC_MESSAGE_ROUTED2(ViewHostMsg_PagesReadyForPreview,
- int /* document cookie */,
- int /* fd in browser */)
-
- // Tells the renderer to dump as much memory as it can, perhaps because we
- // have memory pressure or the renderer is (or will be) paged out. This
- // should only result in purging objects we can recalculate, e.g. caches or
- // JS garbage, not in purging irreplaceable objects.
- IPC_MESSAGE_CONTROL0(ViewMsg_PurgeMemory)
-
- // Sent to render the view into the supplied transport DIB, resize
- // the web widget to match the |page_size|, scale it by the
- // appropriate scale to make it fit the |desired_size|, and return
- // it. In response to this message, the host generates a
- // ViewHostMsg_PaintAtSize_ACK message. Note that the DIB *must* be
- // the right size to receive an RGBA image at the |desired_size|.
- // |tag| is sent along with ViewHostMsg_PaintAtSize_ACK unmodified to
- // identify the PaintAtSize message the ACK belongs to.
- IPC_MESSAGE_ROUTED4(ViewMsg_PaintAtSize,
- TransportDIB::Handle /* dib_handle */,
- int /* tag */,
- gfx::Size /* page_size */,
- gfx::Size /* desired_size */)
-
- // Tells the render view that a ViewHostMsg_UpdateRect message was processed.
- // This signals the render view that it can send another UpdateRect message.
- IPC_MESSAGE_ROUTED0(ViewMsg_UpdateRect_ACK)
-
- // Message payload includes:
- // 1. A blob that should be cast to WebInputEvent
- // 2. An optional boolean value indicating if a RawKeyDown event is associated
- // to a keyboard shortcut of the browser.
- IPC_MESSAGE_ROUTED0(ViewMsg_HandleInputEvent)
-
- // This message notifies the renderer that the next key event is bound to one
- // or more pre-defined edit commands. If the next key event is not handled
- // by webkit, the specified edit commands shall be executed against current
- // focused frame.
- // Parameters
- // * edit_commands (see chrome/common/edit_command_types.h)
- // Contains one or more edit commands.
- // See third_party/WebKit/WebCore/editing/EditorCommand.cpp for detailed
- // definition of webkit edit commands.
- //
- // This message must be sent just before sending a key event.
- IPC_MESSAGE_ROUTED1(ViewMsg_SetEditCommandsForNextKeyEvent,
- std::vector<EditCommand> /* edit_commands */)
-
- // Message payload is the name/value of a WebCore edit command to execute.
- IPC_MESSAGE_ROUTED2(ViewMsg_ExecuteEditCommand,
- std::string, /* name */
- std::string /* value */)
-
- IPC_MESSAGE_ROUTED0(ViewMsg_MouseCaptureLost)
-
- // TODO(darin): figure out how this meshes with RestoreFocus
- IPC_MESSAGE_ROUTED1(ViewMsg_SetFocus, bool /* enable */)
-
- // Tells the renderer to focus the first (last if reverse is true) focusable
- // node.
- IPC_MESSAGE_ROUTED1(ViewMsg_SetInitialFocus, bool /* reverse */)
-
- // Tells the renderer to scroll the currently focused node into view only if
- // the currently focused node is a Text node (textfield, text area or content
- // editable divs).
- IPC_MESSAGE_ROUTED0(ViewMsg_ScrollFocusedEditableNodeIntoView)
-
- // Tells the renderer to perform the specified navigation, interrupting any
- // existing navigation.
- IPC_MESSAGE_ROUTED1(ViewMsg_Navigate, ViewMsg_Navigate_Params)
-
- IPC_MESSAGE_ROUTED0(ViewMsg_Stop)
-
- // Tells the renderer to reload the current focused frame
- IPC_MESSAGE_ROUTED0(ViewMsg_ReloadFrame)
-
- // This message notifies the renderer that the user has closed the FindInPage
- // window (and what action to take regarding the selection).
- IPC_MESSAGE_ROUTED1(ViewMsg_StopFinding,
- ViewMsg_StopFinding_Params /* action */)
-
- // These messages are typically generated from context menus and request the
- // renderer to apply the specified operation to the current selection.
- IPC_MESSAGE_ROUTED0(ViewMsg_Undo)
- IPC_MESSAGE_ROUTED0(ViewMsg_Redo)
- IPC_MESSAGE_ROUTED0(ViewMsg_Cut)
- IPC_MESSAGE_ROUTED0(ViewMsg_Copy)
+// Used typically when recovering from a crash. The new rendering process
+// sets its global "next page id" counter to the given value.
+IPC_MESSAGE_CONTROL1(ViewMsg_SetNextPageID,
+ int32 /* next_page_id */)
+
+// Sends System Colors corresponding to a set of CSS color keywords
+// down the pipe.
+// This message must be sent to the renderer immediately on launch
+// before creating any new views.
+// The message can also be sent during a renderer's lifetime if system colors
+// are updated.
+// TODO(jeremy): Possibly change IPC format once we have this all hooked up.
+IPC_MESSAGE_ROUTED1(ViewMsg_SetCSSColors,
+ std::vector<CSSColors::CSSColorMapping>)
+
+// Tells the renderer to create a new view.
+// This message is slightly different, the view it takes (via
+// ViewMsg_New_Params) is the view to create, the message itself is sent as a
+// non-view control message.
+IPC_MESSAGE_CONTROL1(ViewMsg_New,
+ ViewMsg_New_Params)
+
+// Tells the renderer to set its maximum cache size to the supplied value.
+IPC_MESSAGE_CONTROL3(ViewMsg_SetCacheCapacities,
+ size_t /* min_dead_capacity */,
+ size_t /* max_dead_capacity */,
+ size_t /* capacity */)
+
+// Tells the renderer to cleat the cache.
+IPC_MESSAGE_CONTROL0(ViewMsg_ClearCache)
+
+// Reply in response to ViewHostMsg_ShowView or ViewHostMsg_ShowWidget.
+// similar to the new command, but used when the renderer created a view
+// first, and we need to update it.
+IPC_MESSAGE_ROUTED1(ViewMsg_CreatingNew_ACK,
+ gfx::NativeViewId /* parent_hwnd */)
+
+// Sends updated preferences to the renderer.
+IPC_MESSAGE_ROUTED1(ViewMsg_SetRendererPrefs,
+ RendererPreferences)
+
+// Tells the renderer to perform the given action on the media player
+// located at the given point.
+IPC_MESSAGE_ROUTED2(ViewMsg_MediaPlayerActionAt,
+ gfx::Point, /* location */
+ WebKit::WebMediaPlayerAction)
+
+// Tells the render view to close.
+IPC_MESSAGE_ROUTED0(ViewMsg_Close)
+
+// Tells the render view to change its size. A ViewHostMsg_PaintRect message
+// is generated in response provided new_size is not empty and not equal to
+// the view's current size. The generated ViewHostMsg_PaintRect message will
+// have the IS_RESIZE_ACK flag set. It also receives the resizer rect so that
+// we don't have to fetch it every time WebKit asks for it.
+IPC_MESSAGE_ROUTED2(ViewMsg_Resize,
+ gfx::Size /* new_size */,
+ gfx::Rect /* resizer_rect */)
+
+// Sent to inform the view that it was hidden. This allows it to reduce its
+// resource utilization.
+IPC_MESSAGE_ROUTED0(ViewMsg_WasHidden)
+
+// Tells the render view that it is no longer hidden (see WasHidden), and the
+// render view is expected to respond with a full repaint if needs_repainting
+// is true. In that case, the generated ViewHostMsg_PaintRect message will
+// have the IS_RESTORE_ACK flag set. If needs_repainting is false, then this
+// message does not trigger a message in response.
+IPC_MESSAGE_ROUTED1(ViewMsg_WasRestored,
+ bool /* needs_repainting */)
+
+// Tells the render view to capture a thumbnail image of the page. The
+// render view responds with a ViewHostMsg_Thumbnail.
+IPC_MESSAGE_ROUTED0(ViewMsg_CaptureThumbnail)
+
+// Tells the render view to capture a thumbnail image of the page. The
+// render view responds with a ViewHostMsg_Snapshot.
+IPC_MESSAGE_ROUTED0(ViewMsg_CaptureSnapshot)
+
+// Tells the render view to switch the CSS to print media type, renders every
+// requested pages and switch back the CSS to display media type.
+IPC_MESSAGE_ROUTED0(ViewMsg_PrintPages)
+
+// Tells the render view that printing is done so it can clean up.
+IPC_MESSAGE_ROUTED2(ViewMsg_PrintingDone,
+ int /* document_cookie */,
+ bool /* success */)
+
+// Tells the render view to switch the CSS to print media type, renders every
+// requested pages for print preview.
+IPC_MESSAGE_ROUTED0(ViewMsg_PrintPreview)
+
+// Sends back to the browser the rendered "printed document" for preview that
+// was requested by a ViewMsg_PrintPreview message. The memory handle in this
+// message is already valid in the browser process.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_PagesReadyForPreview,
+ ViewHostMsg_DidPreviewDocument_Params /* params */)
+
+// Tells the renderer to dump as much memory as it can, perhaps because we
+// have memory pressure or the renderer is (or will be) paged out. This
+// should only result in purging objects we can recalculate, e.g. caches or
+// JS garbage, not in purging irreplaceable objects.
+IPC_MESSAGE_CONTROL0(ViewMsg_PurgeMemory)
+
+// Sent to render the view into the supplied transport DIB, resize
+// the web widget to match the |page_size|, scale it by the
+// appropriate scale to make it fit the |desired_size|, and return
+// it. In response to this message, the host generates a
+// ViewHostMsg_PaintAtSize_ACK message. Note that the DIB *must* be
+// the right size to receive an RGBA image at the |desired_size|.
+// |tag| is sent along with ViewHostMsg_PaintAtSize_ACK unmodified to
+// identify the PaintAtSize message the ACK belongs to.
+IPC_MESSAGE_ROUTED4(ViewMsg_PaintAtSize,
+ TransportDIB::Handle /* dib_handle */,
+ int /* tag */,
+ gfx::Size /* page_size */,
+ gfx::Size /* desired_size */)
+
+// Tells the render view that a ViewHostMsg_UpdateRect message was processed.
+// This signals the render view that it can send another UpdateRect message.
+IPC_MESSAGE_ROUTED0(ViewMsg_UpdateRect_ACK)
+
+// Message payload includes:
+// 1. A blob that should be cast to WebInputEvent
+// 2. An optional boolean value indicating if a RawKeyDown event is associated
+// to a keyboard shortcut of the browser.
+IPC_MESSAGE_ROUTED0(ViewMsg_HandleInputEvent)
+
+// This message notifies the renderer that the next key event is bound to one
+// or more pre-defined edit commands. If the next key event is not handled
+// by webkit, the specified edit commands shall be executed against current
+// focused frame.
+// Parameters
+// * edit_commands (see chrome/common/edit_command_types.h)
+// Contains one or more edit commands.
+// See third_party/WebKit/WebCore/editing/EditorCommand.cpp for detailed
+// definition of webkit edit commands.
+//
+// This message must be sent just before sending a key event.
+IPC_MESSAGE_ROUTED1(ViewMsg_SetEditCommandsForNextKeyEvent,
+ std::vector<EditCommand> /* edit_commands */)
+
+// Message payload is the name/value of a WebCore edit command to execute.
+IPC_MESSAGE_ROUTED2(ViewMsg_ExecuteEditCommand,
+ std::string, /* name */
+ std::string /* value */)
+
+IPC_MESSAGE_ROUTED0(ViewMsg_MouseCaptureLost)
+
+// TODO(darin): figure out how this meshes with RestoreFocus
+IPC_MESSAGE_ROUTED1(ViewMsg_SetFocus, bool /* enable */)
+
+// Tells the renderer to focus the first (last if reverse is true) focusable
+// node.
+IPC_MESSAGE_ROUTED1(ViewMsg_SetInitialFocus, bool /* reverse */)
+
+// Tells the renderer to scroll the currently focused node into view only if
+// the currently focused node is a Text node (textfield, text area or content
+// editable divs).
+IPC_MESSAGE_ROUTED0(ViewMsg_ScrollFocusedEditableNodeIntoView)
+
+// Tells the renderer to perform the specified navigation, interrupting any
+// existing navigation.
+IPC_MESSAGE_ROUTED1(ViewMsg_Navigate, ViewMsg_Navigate_Params)
+
+IPC_MESSAGE_ROUTED0(ViewMsg_Stop)
+
+// Tells the renderer to reload the current focused frame
+IPC_MESSAGE_ROUTED0(ViewMsg_ReloadFrame)
+
+// This message notifies the renderer that the user has closed the FindInPage
+// window (and what action to take regarding the selection).
+IPC_MESSAGE_ROUTED1(ViewMsg_StopFinding,
+ ViewMsg_StopFinding_Params /* action */)
+
+// These messages are typically generated from context menus and request the
+// renderer to apply the specified operation to the current selection.
+IPC_MESSAGE_ROUTED0(ViewMsg_Undo)
+IPC_MESSAGE_ROUTED0(ViewMsg_Redo)
+IPC_MESSAGE_ROUTED0(ViewMsg_Cut)
+IPC_MESSAGE_ROUTED0(ViewMsg_Copy)
#if defined(OS_MACOSX)
- IPC_MESSAGE_ROUTED0(ViewMsg_CopyToFindPboard)
+IPC_MESSAGE_ROUTED0(ViewMsg_CopyToFindPboard)
#endif
- IPC_MESSAGE_ROUTED0(ViewMsg_Paste)
- // Replaces the selected region or a word around the cursor with the
- // specified string.
- IPC_MESSAGE_ROUTED1(ViewMsg_Replace, string16)
- IPC_MESSAGE_ROUTED0(ViewMsg_ToggleSpellCheck)
- IPC_MESSAGE_ROUTED0(ViewMsg_Delete)
- IPC_MESSAGE_ROUTED0(ViewMsg_SelectAll)
- IPC_MESSAGE_ROUTED1(ViewMsg_ToggleSpellPanel, bool)
-
- // This message tells the renderer to advance to the next misspelling. It is
- // sent when the user clicks the "Find Next" button on the spelling panel.
- IPC_MESSAGE_ROUTED0(ViewMsg_AdvanceToNextMisspelling)
-
- // Copies the image at location x, y to the clipboard (if there indeed is an
- // image at that location).
- IPC_MESSAGE_ROUTED2(ViewMsg_CopyImageAt,
- int /* x */,
- int /* y */)
-
- // History system notification that the visited link database has been
- // replaced. It has one SharedMemoryHandle argument consisting of the table
- // handle. This handle is valid in the context of the renderer
- IPC_MESSAGE_CONTROL1(ViewMsg_VisitedLink_NewTable, base::SharedMemoryHandle)
-
- // History system notification that a link has been added and the link
- // coloring state for the given hash must be re-calculated.
- IPC_MESSAGE_CONTROL1(ViewMsg_VisitedLink_Add, std::vector<uint64>)
-
- // History system notification that one or more history items have been
- // deleted, which at this point means that all link coloring state must be
- // re-calculated.
- IPC_MESSAGE_CONTROL0(ViewMsg_VisitedLink_Reset)
-
- // Notification that the user scripts have been updated. It has one
- // SharedMemoryHandle argument consisting of the pickled script data. This
- // handle is valid in the context of the renderer.
- IPC_MESSAGE_CONTROL1(ViewMsg_UserScripts_UpdatedScripts,
- base::SharedMemoryHandle)
-
- // Sent when the user wants to search for a word on the page (find in page).
- IPC_MESSAGE_ROUTED3(ViewMsg_Find,
- int /* request_id */,
- string16 /* search_text */,
- WebKit::WebFindOptions)
-
- // Send from the renderer to the browser to return the script running result.
- IPC_MESSAGE_ROUTED2(ViewMsg_ExecuteCodeFinished,
- int, /* request id */
- bool /* whether the script ran successfully */)
-
- // Sent when the headers are available for a resource request.
- IPC_MESSAGE_ROUTED2(ViewMsg_Resource_ReceivedResponse,
- int /* request_id */,
- ResourceResponseHead)
-
- // Sent when cached metadata from a resource request is ready.
- IPC_MESSAGE_ROUTED2(ViewMsg_Resource_ReceivedCachedMetadata,
- int /* request_id */,
- std::vector<char> /* data */)
-
- // Sent as upload progress is being made.
- IPC_MESSAGE_ROUTED3(ViewMsg_Resource_UploadProgress,
- int /* request_id */,
- int64 /* position */,
- int64 /* size */)
-
- // Sent when the request has been redirected. The receiver is expected to
- // respond with either a FollowRedirect message (if the redirect is to be
- // followed) or a CancelRequest message (if it should not be followed).
- IPC_MESSAGE_ROUTED3(ViewMsg_Resource_ReceivedRedirect,
- int /* request_id */,
- GURL /* new_url */,
- ResourceResponseHead)
-
- // Sent when some data from a resource request is ready. The handle should
- // already be mapped into the process that receives this message.
- IPC_MESSAGE_ROUTED3(ViewMsg_Resource_DataReceived,
- int /* request_id */,
- base::SharedMemoryHandle /* data */,
- int /* data_len */)
-
- // Sent when some data from a resource request has been downloaded to
- // file. This is only called in the 'download_to_file' case and replaces
- // ViewMsg_Resource_DataReceived in the call sequence in that case.
- IPC_MESSAGE_ROUTED2(ViewMsg_Resource_DataDownloaded,
- int /* request_id */,
- int /* data_len */)
-
- // Sent when the request has been completed.
- IPC_MESSAGE_ROUTED4(ViewMsg_Resource_RequestComplete,
- int /* request_id */,
- URLRequestStatus /* status */,
- std::string /* security info */,
- base::Time /* completion_time */)
-
- // Sent when user prompting is required before a ViewHostMsg_GetCookies
- // message can complete. This message indicates that the renderer should
- // pump messages while waiting for cookies.
- IPC_MESSAGE_CONTROL0(ViewMsg_SignalCookiePromptEvent)
-
- // Request for the renderer to evaluate an xpath to a frame and execute a
- // javascript: url in that frame's context. The message is completely
- // asynchronous and no corresponding response message is sent back.
- //
- // frame_xpath contains the modified xpath notation to identify an inner
- // subframe (starting from the root frame). It is a concatenation of
- // number of smaller xpaths delimited by '\n'. Each chunk in the string can
- // be evaluated to a frame in its parent-frame's context.
- //
- // Example: /html/body/iframe/\n/html/body/div/iframe/\n/frameset/frame[0]
- // can be broken into 3 xpaths
- // /html/body/iframe evaluates to an iframe within the root frame
- // /html/body/div/iframe evaluates to an iframe within the level-1 iframe
- // /frameset/frame[0] evaluates to first frame within the level-2 iframe
- //
- // jscript_url is the string containing the javascript: url to be executed
- // in the target frame's context. The string should start with "javascript:"
- // and continue with a valid JS text.
- //
- // If the fourth parameter is true the result is sent back to the renderer
- // using the message ViewHostMsg_ScriptEvalResponse.
- // ViewHostMsg_ScriptEvalResponse is passed the ID parameter so that the
- // client can uniquely identify the request.
- IPC_MESSAGE_ROUTED4(ViewMsg_ScriptEvalRequest,
- string16, /* frame_xpath */
- string16, /* jscript_url */
- int, /* ID */
- bool /* If true, result is sent back. */)
-
- // Request for the renderer to evaluate an xpath to a frame and insert css
- // into that frame's document. See ViewMsg_ScriptEvalRequest for details on
- // allowed xpath expressions.
- IPC_MESSAGE_ROUTED3(ViewMsg_CSSInsertRequest,
- std::wstring, /* frame_xpath */
- std::string, /* css string */
- std::string /* element id */)
-
- // Log a message to the console of the target frame
- IPC_MESSAGE_ROUTED3(ViewMsg_AddMessageToConsole,
- string16 /* frame_xpath */,
- string16 /* message */,
- WebKit::WebConsoleMessage::Level /* message_level */)
-
- // RenderViewHostDelegate::RenderViewCreated method sends this message to a
- // new renderer to notify it that it will host developer tools UI and should
- // set up all neccessary bindings and create DevToolsClient instance that
- // will handle communication with inspected page DevToolsAgent.
- IPC_MESSAGE_ROUTED0(ViewMsg_SetupDevToolsClient)
-
- // Change the zoom level for the current main frame. If the level actually
- // changes, a ViewHostMsg_DidZoomURL message will be sent back to the browser
- // telling it what url got zoomed and what its current zoom level is.
- IPC_MESSAGE_ROUTED1(ViewMsg_Zoom,
- PageZoom::Function /* function */)
-
- // Set the zoom level for the current main frame. If the level actually
- // changes, a ViewHostMsg_DidZoomURL message will be sent back to the browser
- // telling it what url got zoomed and what its current zoom level is.
- IPC_MESSAGE_ROUTED1(ViewMsg_SetZoomLevel,
- double /* zoom_level */)
-
- // Set the zoom level for a particular url that the renderer is in the
- // process of loading. This will be stored, to be used if the load commits
- // and ignored otherwise.
- IPC_MESSAGE_ROUTED2(ViewMsg_SetZoomLevelForLoadingURL,
- GURL /* url */,
- double /* zoom_level */)
-
- // Set the zoom level for a particular url, so all render views
- // displaying this url can update their zoom levels to match.
- IPC_MESSAGE_CONTROL2(ViewMsg_SetZoomLevelForCurrentURL,
- GURL /* url */,
- double /* zoom_level */)
-
- // Set the content settings for a particular url that the renderer is in the
- // process of loading. This will be stored, to be used if the load commits
- // and ignored otherwise.
- IPC_MESSAGE_ROUTED2(ViewMsg_SetContentSettingsForLoadingURL,
- GURL /* url */,
- ContentSettings /* content_settings */)
-
- // Set the content settings for a particular url, so all render views
- // displaying this host url update their content settings to match.
- IPC_MESSAGE_CONTROL2(ViewMsg_SetContentSettingsForCurrentURL,
- GURL /* url */,
- ContentSettings /* content_settings */)
-
- // Change encoding of page in the renderer.
- IPC_MESSAGE_ROUTED1(ViewMsg_SetPageEncoding,
- std::string /*new encoding name*/)
-
- // Reset encoding of page in the renderer back to default.
- IPC_MESSAGE_ROUTED0(ViewMsg_ResetPageEncodingToDefault)
-
- // Requests the renderer to reserve a range of page ids.
- IPC_MESSAGE_ROUTED1(ViewMsg_ReservePageIDRange,
- int /* size_of_range */)
-
- // Fill a form with data and optionally submit it
- IPC_MESSAGE_ROUTED1(ViewMsg_FormFill,
- webkit_glue::FormData /* form */)
-
- // Fill a password form and prepare field autocomplete for multiple
- // matching logins.
- IPC_MESSAGE_ROUTED1(ViewMsg_FillPasswordForm,
- webkit_glue::PasswordFormFillData)
-
- // D&d drop target messages.
- IPC_MESSAGE_ROUTED4(ViewMsg_DragTargetDragEnter,
- WebDropData /* drop_data */,
- gfx::Point /* client_pt */,
- gfx::Point /* screen_pt */,
- WebKit::WebDragOperationsMask /* ops_allowed */)
- IPC_MESSAGE_ROUTED3(ViewMsg_DragTargetDragOver,
- gfx::Point /* client_pt */,
- gfx::Point /* screen_pt */,
- WebKit::WebDragOperationsMask /* ops_allowed */)
- IPC_MESSAGE_ROUTED0(ViewMsg_DragTargetDragLeave)
- IPC_MESSAGE_ROUTED2(ViewMsg_DragTargetDrop,
- gfx::Point /* client_pt */,
- gfx::Point /* screen_pt */)
-
- // Notifies the renderer of updates in mouse position of an in-progress
- // drag. if |ended| is true, then the user has ended the drag operation.
- IPC_MESSAGE_ROUTED4(ViewMsg_DragSourceEndedOrMoved,
- gfx::Point /* client_pt */,
- gfx::Point /* screen_pt */,
- bool /* ended */,
- WebKit::WebDragOperation /* drag_operation */)
-
- // Notifies the renderer that the system DoDragDrop call has ended.
- IPC_MESSAGE_ROUTED0(ViewMsg_DragSourceSystemDragEnded)
-
- // Used to tell a render view whether it should expose various bindings
- // that allow JS content extended privileges. See BindingsPolicy for valid
- // flag values.
- IPC_MESSAGE_ROUTED1(ViewMsg_AllowBindings,
- int /* enabled_bindings_flags */)
-
- // Tell the renderer to add a property to the DOMUI binding object. This
- // only works if we allowed DOMUI bindings.
- IPC_MESSAGE_ROUTED2(ViewMsg_SetDOMUIProperty,
- std::string /* property_name */,
- std::string /* property_value_json */)
-
- // This message starts/stop monitoring the input method status of the focused
- // edit control of a renderer process.
- // Parameters
- // * is_active (bool)
- // Indicates if an input method is active in the browser process.
- // The possible actions when a renderer process receives this message are
- // listed below:
- // Value Action
- // true Start sending IPC message ViewHostMsg_ImeUpdateTextInputState
- // to notify the input method status of the focused edit control.
- // false Stop sending IPC message ViewHostMsg_ImeUpdateTextInputState.
- IPC_MESSAGE_ROUTED1(ViewMsg_SetInputMethodActive,
- bool /* is_active */)
-
- // This message sends a string being composed with an input method.
- IPC_MESSAGE_ROUTED4(
- ViewMsg_ImeSetComposition,
- string16, /* text */
- std::vector<WebKit::WebCompositionUnderline>, /* underlines */
- int, /* selectiont_start */
- int /* selection_end */)
-
- // This message confirms an ongoing composition.
- IPC_MESSAGE_ROUTED0(ViewMsg_ImeConfirmComposition)
-
- // This passes a set of webkit preferences down to the renderer.
- IPC_MESSAGE_ROUTED1(ViewMsg_UpdateWebPreferences, WebPreferences)
-
- // Used to notify the render-view that the browser has received a reply for
- // the Find operation and is interested in receiving the next one. This is
- // used to prevent the renderer from spamming the browser process with
- // results.
- IPC_MESSAGE_ROUTED0(ViewMsg_FindReplyACK)
-
- // Used to notify the render-view that we have received a target URL. Used
- // to prevent target URLs spamming the browser.
- IPC_MESSAGE_ROUTED0(ViewMsg_UpdateTargetURL_ACK)
-
- // Sets the alternate error page URL (link doctor) for the renderer process.
- IPC_MESSAGE_ROUTED1(ViewMsg_SetAltErrorPageURL, GURL)
-
- // Install the first missing pluign.
- IPC_MESSAGE_ROUTED0(ViewMsg_InstallMissingPlugin)
-
- // Tells the renderer to empty its plugin list cache, optional reloading
- // pages containing plugins.
- IPC_MESSAGE_CONTROL1(ViewMsg_PurgePluginListCache,
- bool /* reload_pages */)
-
- // Tells the render view to load all blocked plugins.
- IPC_MESSAGE_ROUTED0(ViewMsg_LoadBlockedPlugins)
-
- IPC_MESSAGE_ROUTED1(ViewMsg_RunFileChooserResponse,
- std::vector<FilePath> /* selected files */)
-
- // Used to instruct the RenderView to go into "view source" mode.
- IPC_MESSAGE_ROUTED0(ViewMsg_EnableViewSourceMode)
-
- // Get all savable resource links from current webpage, include main
- // frame and sub-frame.
- IPC_MESSAGE_ROUTED1(ViewMsg_GetAllSavableResourceLinksForCurrentPage,
- GURL /* url of page which is needed to save */)
-
- // Get html data by serializing all frames of current page with lists
- // which contain all resource links that have local copy.
- IPC_MESSAGE_ROUTED3(ViewMsg_GetSerializedHtmlDataForCurrentPageWithLocalLinks,
- std::vector<GURL> /* urls that have local copy */,
- std::vector<FilePath> /* paths of local copy */,
- FilePath /* local directory path */)
-
- // Requests application info for the page. The renderer responds back with
- // ViewHostMsg_DidGetApplicationInfo.
- IPC_MESSAGE_ROUTED1(ViewMsg_GetApplicationInfo, int32 /*page_id*/)
-
- // Requests the renderer to download the specified favicon image encode it as
- // PNG and send the PNG data back ala ViewHostMsg_DidDownloadFavIcon.
- IPC_MESSAGE_ROUTED3(ViewMsg_DownloadFavIcon,
- int /* identifier for the request */,
- GURL /* URL of the image */,
- int /* Size of the image. Normally 0, but set if you have
- a preferred image size to request, such as when
- downloading the favicon */)
-
- // When a renderer sends a ViewHostMsg_Focus to the browser process,
- // the browser has the option of sending a ViewMsg_CantFocus back to
- // the renderer.
- IPC_MESSAGE_ROUTED0(ViewMsg_CantFocus)
-
- // Instructs the renderer to invoke the frame's shouldClose method, which
- // runs the onbeforeunload event handler. Expects the result to be returned
- // via ViewHostMsg_ShouldClose.
- IPC_MESSAGE_ROUTED0(ViewMsg_ShouldClose)
-
- // Instructs the renderer to close the current page, including running the
- // onunload event handler. See the struct in render_messages.h for more.
- //
- // Expects a ClosePage_ACK message when finished, where the parameters are
- // echoed back.
- IPC_MESSAGE_ROUTED1(ViewMsg_ClosePage,
- ViewMsg_ClosePage_Params)
-
- // Asks the renderer to send back stats on the WebCore cache broken down by
- // resource types.
- IPC_MESSAGE_CONTROL0(ViewMsg_GetCacheResourceStats)
-
- // Asks the renderer to send back Histograms.
- IPC_MESSAGE_CONTROL1(ViewMsg_GetRendererHistograms,
- int /* sequence number of Renderer Histograms. */)
+IPC_MESSAGE_ROUTED0(ViewMsg_Paste)
+// Replaces the selected region or a word around the cursor with the
+// specified string.
+IPC_MESSAGE_ROUTED1(ViewMsg_Replace, string16)
+IPC_MESSAGE_ROUTED0(ViewMsg_ToggleSpellCheck)
+IPC_MESSAGE_ROUTED0(ViewMsg_Delete)
+IPC_MESSAGE_ROUTED0(ViewMsg_SelectAll)
+IPC_MESSAGE_ROUTED1(ViewMsg_ToggleSpellPanel, bool)
+
+// This message tells the renderer to advance to the next misspelling. It is
+// sent when the user clicks the "Find Next" button on the spelling panel.
+IPC_MESSAGE_ROUTED0(ViewMsg_AdvanceToNextMisspelling)
+
+// Copies the image at location x, y to the clipboard (if there indeed is an
+// image at that location).
+IPC_MESSAGE_ROUTED2(ViewMsg_CopyImageAt,
+ int /* x */,
+ int /* y */)
+
+// History system notification that the visited link database has been
+// replaced. It has one SharedMemoryHandle argument consisting of the table
+// handle. This handle is valid in the context of the renderer
+IPC_MESSAGE_CONTROL1(ViewMsg_VisitedLink_NewTable, base::SharedMemoryHandle)
+
+// History system notification that a link has been added and the link
+// coloring state for the given hash must be re-calculated.
+IPC_MESSAGE_CONTROL1(ViewMsg_VisitedLink_Add, std::vector<uint64>)
+
+// History system notification that one or more history items have been
+// deleted, which at this point means that all link coloring state must be
+// re-calculated.
+IPC_MESSAGE_CONTROL0(ViewMsg_VisitedLink_Reset)
+
+// Notification that the user scripts have been updated. It has one
+// SharedMemoryHandle argument consisting of the pickled script data. This
+// handle is valid in the context of the renderer.
+IPC_MESSAGE_CONTROL1(ViewMsg_UserScripts_UpdatedScripts,
+ base::SharedMemoryHandle)
+
+// Sent when the user wants to search for a word on the page (find in page).
+IPC_MESSAGE_ROUTED3(ViewMsg_Find,
+ int /* request_id */,
+ string16 /* search_text */,
+ WebKit::WebFindOptions)
+
+// Send from the renderer to the browser to return the script running result.
+IPC_MESSAGE_ROUTED2(ViewMsg_ExecuteCodeFinished,
+ int, /* request id */
+ bool /* whether the script ran successfully */)
+
+// Sent when the headers are available for a resource request.
+IPC_MESSAGE_ROUTED2(ViewMsg_Resource_ReceivedResponse,
+ int /* request_id */,
+ ResourceResponseHead)
+
+// Sent when cached metadata from a resource request is ready.
+IPC_MESSAGE_ROUTED2(ViewMsg_Resource_ReceivedCachedMetadata,
+ int /* request_id */,
+ std::vector<char> /* data */)
+
+// Sent as upload progress is being made.
+IPC_MESSAGE_ROUTED3(ViewMsg_Resource_UploadProgress,
+ int /* request_id */,
+ int64 /* position */,
+ int64 /* size */)
+
+// Sent when the request has been redirected. The receiver is expected to
+// respond with either a FollowRedirect message (if the redirect is to be
+// followed) or a CancelRequest message (if it should not be followed).
+IPC_MESSAGE_ROUTED3(ViewMsg_Resource_ReceivedRedirect,
+ int /* request_id */,
+ GURL /* new_url */,
+ ResourceResponseHead)
+
+// Sent when some data from a resource request is ready. The handle should
+// already be mapped into the process that receives this message.
+IPC_MESSAGE_ROUTED3(ViewMsg_Resource_DataReceived,
+ int /* request_id */,
+ base::SharedMemoryHandle /* data */,
+ int /* data_len */)
+
+// Sent when some data from a resource request has been downloaded to
+// file. This is only called in the 'download_to_file' case and replaces
+// ViewMsg_Resource_DataReceived in the call sequence in that case.
+IPC_MESSAGE_ROUTED2(ViewMsg_Resource_DataDownloaded,
+ int /* request_id */,
+ int /* data_len */)
+
+// Sent when the request has been completed.
+IPC_MESSAGE_ROUTED4(ViewMsg_Resource_RequestComplete,
+ int /* request_id */,
+ URLRequestStatus /* status */,
+ std::string /* security info */,
+ base::Time /* completion_time */)
+
+// Sent when user prompting is required before a ViewHostMsg_GetCookies
+// message can complete. This message indicates that the renderer should
+// pump messages while waiting for cookies.
+IPC_MESSAGE_CONTROL0(ViewMsg_SignalCookiePromptEvent)
+
+// Request for the renderer to evaluate an xpath to a frame and execute a
+// javascript: url in that frame's context. The message is completely
+// asynchronous and no corresponding response message is sent back.
+//
+// frame_xpath contains the modified xpath notation to identify an inner
+// subframe (starting from the root frame). It is a concatenation of
+// number of smaller xpaths delimited by '\n'. Each chunk in the string can
+// be evaluated to a frame in its parent-frame's context.
+//
+// Example: /html/body/iframe/\n/html/body/div/iframe/\n/frameset/frame[0]
+// can be broken into 3 xpaths
+// /html/body/iframe evaluates to an iframe within the root frame
+// /html/body/div/iframe evaluates to an iframe within the level-1 iframe
+// /frameset/frame[0] evaluates to first frame within the level-2 iframe
+//
+// jscript_url is the string containing the javascript: url to be executed
+// in the target frame's context. The string should start with "javascript:"
+// and continue with a valid JS text.
+//
+// If the fourth parameter is true the result is sent back to the renderer
+// using the message ViewHostMsg_ScriptEvalResponse.
+// ViewHostMsg_ScriptEvalResponse is passed the ID parameter so that the
+// client can uniquely identify the request.
+IPC_MESSAGE_ROUTED4(ViewMsg_ScriptEvalRequest,
+ string16, /* frame_xpath */
+ string16, /* jscript_url */
+ int, /* ID */
+ bool /* If true, result is sent back. */)
+
+// Request for the renderer to evaluate an xpath to a frame and insert css
+// into that frame's document. See ViewMsg_ScriptEvalRequest for details on
+// allowed xpath expressions.
+IPC_MESSAGE_ROUTED3(ViewMsg_CSSInsertRequest,
+ std::wstring, /* frame_xpath */
+ std::string, /* css string */
+ std::string /* element id */)
+
+// Log a message to the console of the target frame
+IPC_MESSAGE_ROUTED3(ViewMsg_AddMessageToConsole,
+ string16 /* frame_xpath */,
+ string16 /* message */,
+ WebKit::WebConsoleMessage::Level /* message_level */)
+
+// RenderViewHostDelegate::RenderViewCreated method sends this message to a
+// new renderer to notify it that it will host developer tools UI and should
+// set up all neccessary bindings and create DevToolsClient instance that
+// will handle communication with inspected page DevToolsAgent.
+IPC_MESSAGE_ROUTED0(ViewMsg_SetupDevToolsClient)
+
+// Change the zoom level for the current main frame. If the level actually
+// changes, a ViewHostMsg_DidZoomURL message will be sent back to the browser
+// telling it what url got zoomed and what its current zoom level is.
+IPC_MESSAGE_ROUTED1(ViewMsg_Zoom,
+ PageZoom::Function /* function */)
+
+// Set the zoom level for the current main frame. If the level actually
+// changes, a ViewHostMsg_DidZoomURL message will be sent back to the browser
+// telling it what url got zoomed and what its current zoom level is.
+IPC_MESSAGE_ROUTED1(ViewMsg_SetZoomLevel,
+ double /* zoom_level */)
+
+// Set the zoom level for a particular url that the renderer is in the
+// process of loading. This will be stored, to be used if the load commits
+// and ignored otherwise.
+IPC_MESSAGE_ROUTED2(ViewMsg_SetZoomLevelForLoadingURL,
+ GURL /* url */,
+ double /* zoom_level */)
+
+// Set the zoom level for a particular url, so all render views
+// displaying this url can update their zoom levels to match.
+IPC_MESSAGE_CONTROL2(ViewMsg_SetZoomLevelForCurrentURL,
+ GURL /* url */,
+ double /* zoom_level */)
+
+// Set the content settings for a particular url that the renderer is in the
+// process of loading. This will be stored, to be used if the load commits
+// and ignored otherwise.
+IPC_MESSAGE_ROUTED2(ViewMsg_SetContentSettingsForLoadingURL,
+ GURL /* url */,
+ ContentSettings /* content_settings */)
+
+// Set the content settings for a particular url, so all render views
+// displaying this host url update their content settings to match.
+IPC_MESSAGE_CONTROL2(ViewMsg_SetContentSettingsForCurrentURL,
+ GURL /* url */,
+ ContentSettings /* content_settings */)
+
+// Change encoding of page in the renderer.
+IPC_MESSAGE_ROUTED1(ViewMsg_SetPageEncoding,
+ std::string /*new encoding name*/)
+
+// Reset encoding of page in the renderer back to default.
+IPC_MESSAGE_ROUTED0(ViewMsg_ResetPageEncodingToDefault)
+
+// Requests the renderer to reserve a range of page ids.
+IPC_MESSAGE_ROUTED1(ViewMsg_ReservePageIDRange,
+ int /* size_of_range */)
+
+// Fill a form with data and optionally submit it
+IPC_MESSAGE_ROUTED1(ViewMsg_FormFill,
+ webkit_glue::FormData /* form */)
+
+// Fill a password form and prepare field autocomplete for multiple
+// matching logins.
+IPC_MESSAGE_ROUTED1(ViewMsg_FillPasswordForm,
+ webkit_glue::PasswordFormFillData)
+
+// D&d drop target messages.
+IPC_MESSAGE_ROUTED4(ViewMsg_DragTargetDragEnter,
+ WebDropData /* drop_data */,
+ gfx::Point /* client_pt */,
+ gfx::Point /* screen_pt */,
+ WebKit::WebDragOperationsMask /* ops_allowed */)
+IPC_MESSAGE_ROUTED3(ViewMsg_DragTargetDragOver,
+ gfx::Point /* client_pt */,
+ gfx::Point /* screen_pt */,
+ WebKit::WebDragOperationsMask /* ops_allowed */)
+IPC_MESSAGE_ROUTED0(ViewMsg_DragTargetDragLeave)
+IPC_MESSAGE_ROUTED2(ViewMsg_DragTargetDrop,
+ gfx::Point /* client_pt */,
+ gfx::Point /* screen_pt */)
+
+// Notifies the renderer of updates in mouse position of an in-progress
+// drag. if |ended| is true, then the user has ended the drag operation.
+IPC_MESSAGE_ROUTED4(ViewMsg_DragSourceEndedOrMoved,
+ gfx::Point /* client_pt */,
+ gfx::Point /* screen_pt */,
+ bool /* ended */,
+ WebKit::WebDragOperation /* drag_operation */)
+
+// Notifies the renderer that the system DoDragDrop call has ended.
+IPC_MESSAGE_ROUTED0(ViewMsg_DragSourceSystemDragEnded)
+
+// Used to tell a render view whether it should expose various bindings
+// that allow JS content extended privileges. See BindingsPolicy for valid
+// flag values.
+IPC_MESSAGE_ROUTED1(ViewMsg_AllowBindings,
+ int /* enabled_bindings_flags */)
+
+// Tell the renderer to add a property to the DOMUI binding object. This
+// only works if we allowed DOMUI bindings.
+IPC_MESSAGE_ROUTED2(ViewMsg_SetDOMUIProperty,
+ std::string /* property_name */,
+ std::string /* property_value_json */)
+
+// This message starts/stop monitoring the input method status of the focused
+// edit control of a renderer process.
+// Parameters
+// * is_active (bool)
+// Indicates if an input method is active in the browser process.
+// The possible actions when a renderer process receives this message are
+// listed below:
+// Value Action
+// true Start sending IPC message ViewHostMsg_ImeUpdateTextInputState
+// to notify the input method status of the focused edit control.
+// false Stop sending IPC message ViewHostMsg_ImeUpdateTextInputState.
+IPC_MESSAGE_ROUTED1(ViewMsg_SetInputMethodActive,
+ bool /* is_active */)
+
+// This message sends a string being composed with an input method.
+IPC_MESSAGE_ROUTED4(
+ ViewMsg_ImeSetComposition,
+ string16, /* text */
+ std::vector<WebKit::WebCompositionUnderline>, /* underlines */
+ int, /* selectiont_start */
+ int /* selection_end */)
+
+// This message confirms an ongoing composition.
+IPC_MESSAGE_ROUTED0(ViewMsg_ImeConfirmComposition)
+
+// This passes a set of webkit preferences down to the renderer.
+IPC_MESSAGE_ROUTED1(ViewMsg_UpdateWebPreferences, WebPreferences)
+
+// Used to notify the render-view that the browser has received a reply for
+// the Find operation and is interested in receiving the next one. This is
+// used to prevent the renderer from spamming the browser process with
+// results.
+IPC_MESSAGE_ROUTED0(ViewMsg_FindReplyACK)
+
+// Used to notify the render-view that we have received a target URL. Used
+// to prevent target URLs spamming the browser.
+IPC_MESSAGE_ROUTED0(ViewMsg_UpdateTargetURL_ACK)
+
+// Sets the alternate error page URL (link doctor) for the renderer process.
+IPC_MESSAGE_ROUTED1(ViewMsg_SetAltErrorPageURL, GURL)
+
+// Install the first missing pluign.
+IPC_MESSAGE_ROUTED0(ViewMsg_InstallMissingPlugin)
+
+// Tells the renderer to empty its plugin list cache, optional reloading
+// pages containing plugins.
+IPC_MESSAGE_CONTROL1(ViewMsg_PurgePluginListCache,
+ bool /* reload_pages */)
+
+// Tells the render view to load all blocked plugins.
+IPC_MESSAGE_ROUTED0(ViewMsg_LoadBlockedPlugins)
+
+IPC_MESSAGE_ROUTED1(ViewMsg_RunFileChooserResponse,
+ std::vector<FilePath> /* selected files */)
+
+// Used to instruct the RenderView to go into "view source" mode.
+IPC_MESSAGE_ROUTED0(ViewMsg_EnableViewSourceMode)
+
+// Get all savable resource links from current webpage, include main
+// frame and sub-frame.
+IPC_MESSAGE_ROUTED1(ViewMsg_GetAllSavableResourceLinksForCurrentPage,
+ GURL /* url of page which is needed to save */)
+
+// Get html data by serializing all frames of current page with lists
+// which contain all resource links that have local copy.
+IPC_MESSAGE_ROUTED3(ViewMsg_GetSerializedHtmlDataForCurrentPageWithLocalLinks,
+ std::vector<GURL> /* urls that have local copy */,
+ std::vector<FilePath> /* paths of local copy */,
+ FilePath /* local directory path */)
+
+// Requests application info for the page. The renderer responds back with
+// ViewHostMsg_DidGetApplicationInfo.
+IPC_MESSAGE_ROUTED1(ViewMsg_GetApplicationInfo, int32 /*page_id*/)
+
+// Requests the renderer to download the specified favicon image encode it as
+// PNG and send the PNG data back ala ViewHostMsg_DidDownloadFavIcon.
+IPC_MESSAGE_ROUTED3(ViewMsg_DownloadFavIcon,
+ int /* identifier for the request */,
+ GURL /* URL of the image */,
+ int /* Size of the image. Normally 0, but set if you have
+ a preferred image size to request, such as when
+ downloading the favicon */)
+
+// When a renderer sends a ViewHostMsg_Focus to the browser process,
+// the browser has the option of sending a ViewMsg_CantFocus back to
+// the renderer.
+IPC_MESSAGE_ROUTED0(ViewMsg_CantFocus)
+
+// Instructs the renderer to invoke the frame's shouldClose method, which
+// runs the onbeforeunload event handler. Expects the result to be returned
+// via ViewHostMsg_ShouldClose.
+IPC_MESSAGE_ROUTED0(ViewMsg_ShouldClose)
+
+// Instructs the renderer to close the current page, including running the
+// onunload event handler. See the struct in render_messages.h for more.
+//
+// Expects a ClosePage_ACK message when finished, where the parameters are
+// echoed back.
+IPC_MESSAGE_ROUTED1(ViewMsg_ClosePage,
+ ViewMsg_ClosePage_Params)
+
+// Asks the renderer to send back stats on the WebCore cache broken down by
+// resource types.
+IPC_MESSAGE_CONTROL0(ViewMsg_GetCacheResourceStats)
+
+// Asks the renderer to send back Histograms.
+IPC_MESSAGE_CONTROL1(ViewMsg_GetRendererHistograms,
+ int /* sequence number of Renderer Histograms. */)
#if defined(USE_TCMALLOC)
- // Asks the renderer to send back tcmalloc stats.
- IPC_MESSAGE_CONTROL0(ViewMsg_GetRendererTcmalloc)
+// Asks the renderer to send back tcmalloc stats.
+IPC_MESSAGE_CONTROL0(ViewMsg_GetRendererTcmalloc)
#endif
- // Asks the renderer to send back V8 heap stats.
- IPC_MESSAGE_CONTROL0(ViewMsg_GetV8HeapStats)
-
- // Notifies the renderer about ui theme changes
- IPC_MESSAGE_ROUTED0(ViewMsg_ThemeChanged)
-
- // Notifies the renderer that a paint is to be generated for the rectangle
- // passed in.
- IPC_MESSAGE_ROUTED1(ViewMsg_Repaint,
- gfx::Size /* The view size to be repainted */)
-
- // Posts a message to the renderer.
- IPC_MESSAGE_ROUTED3(ViewMsg_HandleMessageFromExternalHost,
- std::string /* The message */,
- std::string /* The origin */,
- std::string /* The target*/)
-
- // Sent to the renderer when a popup window should no longer count against
- // the current popup count (either because it's not a popup or because it was
- // a generated by a user action or because a constrained popup got turned
- // into a full window).
- IPC_MESSAGE_ROUTED0(ViewMsg_DisassociateFromPopupCount)
-
- // The browser sends this to a renderer process in response to a
- // ViewHostMsg_EstablishGpuChannel message.
- IPC_MESSAGE_CONTROL2(ViewMsg_GpuChannelEstablished,
- IPC::ChannelHandle /* handle to channel */,
- GPUInfo /* stats about GPU process*/)
-
- // Notifies the renderer of the appcache that has been selected for a
- // a particular host. This is sent in reply to AppCacheMsg_SelectCache.
- IPC_MESSAGE_CONTROL2(AppCacheMsg_CacheSelected,
- int /* host_id */,
- appcache::AppCacheInfo)
-
- // Notifies the renderer of an AppCache status change.
- IPC_MESSAGE_CONTROL2(AppCacheMsg_StatusChanged,
- std::vector<int> /* host_ids */,
- appcache::Status)
-
- // Notifies the renderer of an AppCache event other than the
- // progress event which has a seperate message.
- IPC_MESSAGE_CONTROL2(AppCacheMsg_EventRaised,
- std::vector<int> /* host_ids */,
- appcache::EventID)
-
- // Notifies the renderer of an AppCache progress event.
- IPC_MESSAGE_CONTROL4(AppCacheMsg_ProgressEventRaised,
- std::vector<int> /* host_ids */,
- GURL /* url being processed */,
- int /* total */,
- int /* complete */)
-
- // Notifies the renderer of an AppCache error event.
- IPC_MESSAGE_CONTROL2(AppCacheMsg_ErrorEventRaised,
- std::vector<int> /* host_ids */,
- std::string /* error_message */)
-
- // Notifies the renderer of an AppCache logging message.
- IPC_MESSAGE_CONTROL3(AppCacheMsg_LogMessage,
- int /* host_id */,
- int /* log_level */,
- std::string /* message */)
-
- // Notifies the renderer of the fact that AppCache access was blocked.
- IPC_MESSAGE_CONTROL2(AppCacheMsg_ContentBlocked,
- int /* host_id */,
- GURL /* manifest_url */)
-
- // Reply to the ViewHostMsg_QueryFormFieldAutoFill message with the
- // AutoFill suggestions.
- IPC_MESSAGE_ROUTED5(ViewMsg_AutoFillSuggestionsReturned,
- int /* id of the request message */,
- std::vector<string16> /* names */,
- std::vector<string16> /* labels */,
- std::vector<string16> /* icons */,
- std::vector<int> /* unique_ids */)
-
- // Reply to the ViewHostMsg_FillAutoFillFormData message with the
- // AutoFill form data.
- IPC_MESSAGE_ROUTED2(ViewMsg_AutoFillFormDataFilled,
- int /* id of the request message */,
- webkit_glue::FormData /* form data */)
-
- // Sent by the Browser process to alert a window about whether a it should
- // allow a scripted window.close(). The renderer assumes every new window is a
- // blocked popup until notified otherwise.
- IPC_MESSAGE_ROUTED1(ViewMsg_AllowScriptToClose,
- bool /* script_can_close */)
-
- // Sent by AudioRendererHost to renderer to request an audio packet.
- IPC_MESSAGE_ROUTED2(ViewMsg_RequestAudioPacket,
- int /* stream id */,
- AudioBuffersState)
-
- // Tell the renderer process that the audio stream has been created, renderer
- // process would be given a ShareMemoryHandle that it should write to from
- // then on.
- IPC_MESSAGE_ROUTED3(ViewMsg_NotifyAudioStreamCreated,
- int /* stream id */,
- base::SharedMemoryHandle /* handle */,
- uint32 /* length */)
-
- // Tell the renderer process that a low latency audio stream has been created,
- // renderer process would be given a SyncSocket that it should write to from
- // then on.
+// Asks the renderer to send back V8 heap stats.
+IPC_MESSAGE_CONTROL0(ViewMsg_GetV8HeapStats)
+
+// Notifies the renderer about ui theme changes
+IPC_MESSAGE_ROUTED0(ViewMsg_ThemeChanged)
+
+// Notifies the renderer that a paint is to be generated for the rectangle
+// passed in.
+IPC_MESSAGE_ROUTED1(ViewMsg_Repaint,
+ gfx::Size /* The view size to be repainted */)
+
+// Posts a message to the renderer.
+IPC_MESSAGE_ROUTED3(ViewMsg_HandleMessageFromExternalHost,
+ std::string /* The message */,
+ std::string /* The origin */,
+ std::string /* The target*/)
+
+// Sent to the renderer when a popup window should no longer count against
+// the current popup count (either because it's not a popup or because it was
+// a generated by a user action or because a constrained popup got turned
+// into a full window).
+IPC_MESSAGE_ROUTED0(ViewMsg_DisassociateFromPopupCount)
+
+// The browser sends this to a renderer process in response to a
+// ViewHostMsg_EstablishGpuChannel message.
+IPC_MESSAGE_CONTROL2(ViewMsg_GpuChannelEstablished,
+ IPC::ChannelHandle /* handle to channel */,
+ GPUInfo /* stats about GPU process*/)
+
+// Notifies the renderer of the appcache that has been selected for a
+// a particular host. This is sent in reply to AppCacheMsg_SelectCache.
+IPC_MESSAGE_CONTROL2(AppCacheMsg_CacheSelected,
+ int /* host_id */,
+ appcache::AppCacheInfo)
+
+// Notifies the renderer of an AppCache status change.
+IPC_MESSAGE_CONTROL2(AppCacheMsg_StatusChanged,
+ std::vector<int> /* host_ids */,
+ appcache::Status)
+
+// Notifies the renderer of an AppCache event other than the
+// progress event which has a seperate message.
+IPC_MESSAGE_CONTROL2(AppCacheMsg_EventRaised,
+ std::vector<int> /* host_ids */,
+ appcache::EventID)
+
+// Notifies the renderer of an AppCache progress event.
+IPC_MESSAGE_CONTROL4(AppCacheMsg_ProgressEventRaised,
+ std::vector<int> /* host_ids */,
+ GURL /* url being processed */,
+ int /* total */,
+ int /* complete */)
+
+// Notifies the renderer of an AppCache error event.
+IPC_MESSAGE_CONTROL2(AppCacheMsg_ErrorEventRaised,
+ std::vector<int> /* host_ids */,
+ std::string /* error_message */)
+
+// Notifies the renderer of an AppCache logging message.
+IPC_MESSAGE_CONTROL3(AppCacheMsg_LogMessage,
+ int /* host_id */,
+ int /* log_level */,
+ std::string /* message */)
+
+// Notifies the renderer of the fact that AppCache access was blocked.
+IPC_MESSAGE_CONTROL2(AppCacheMsg_ContentBlocked,
+ int /* host_id */,
+ GURL /* manifest_url */)
+
+// Reply to the ViewHostMsg_QueryFormFieldAutoFill message with the
+// AutoFill suggestions.
+IPC_MESSAGE_ROUTED5(ViewMsg_AutoFillSuggestionsReturned,
+ int /* id of the request message */,
+ std::vector<string16> /* names */,
+ std::vector<string16> /* labels */,
+ std::vector<string16> /* icons */,
+ std::vector<int> /* unique_ids */)
+
+// Reply to the ViewHostMsg_FillAutoFillFormData message with the
+// AutoFill form data.
+IPC_MESSAGE_ROUTED2(ViewMsg_AutoFillFormDataFilled,
+ int /* id of the request message */,
+ webkit_glue::FormData /* form data */)
+
+// Sent by the Browser process to alert a window about whether a it should
+// allow a scripted window.close(). The renderer assumes every new window is a
+// blocked popup until notified otherwise.
+IPC_MESSAGE_ROUTED1(ViewMsg_AllowScriptToClose,
+ bool /* script_can_close */)
+
+// Sent by AudioRendererHost to renderer to request an audio packet.
+IPC_MESSAGE_ROUTED2(ViewMsg_RequestAudioPacket,
+ int /* stream id */,
+ AudioBuffersState)
+
+// Tell the renderer process that the audio stream has been created, renderer
+// process would be given a ShareMemoryHandle that it should write to from
+// then on.
+IPC_MESSAGE_ROUTED3(ViewMsg_NotifyAudioStreamCreated,
+ int /* stream id */,
+ base::SharedMemoryHandle /* handle */,
+ uint32 /* length */)
+
+// Tell the renderer process that a low latency audio stream has been created,
+// renderer process would be given a SyncSocket that it should write to from
+// then on.
#if defined(OS_WIN)
- IPC_MESSAGE_ROUTED4(ViewMsg_NotifyLowLatencyAudioStreamCreated,
- int /* stream id */,
- base::SharedMemoryHandle /* handle */,
- base::SyncSocket::Handle /* socket handle */,
- uint32 /* length */)
+IPC_MESSAGE_ROUTED4(ViewMsg_NotifyLowLatencyAudioStreamCreated,
+ int /* stream id */,
+ base::SharedMemoryHandle /* handle */,
+ base::SyncSocket::Handle /* socket handle */,
+ uint32 /* length */)
#else
- IPC_MESSAGE_ROUTED4(ViewMsg_NotifyLowLatencyAudioStreamCreated,
- int /* stream id */,
- base::SharedMemoryHandle /* handle */,
- base::FileDescriptor /* socket handle */,
- uint32 /* length */)
+IPC_MESSAGE_ROUTED4(ViewMsg_NotifyLowLatencyAudioStreamCreated,
+ int /* stream id */,
+ base::SharedMemoryHandle /* handle */,
+ base::FileDescriptor /* socket handle */,
+ uint32 /* length */)
#endif
- // Notification message sent from AudioRendererHost to renderer for state
- // update after the renderer has requested a Create/Start/Close.
- IPC_MESSAGE_ROUTED2(ViewMsg_NotifyAudioStreamStateChanged,
- int /* stream id */,
- ViewMsg_AudioStreamState_Params /* new state */)
-
- IPC_MESSAGE_ROUTED2(ViewMsg_NotifyAudioStreamVolume,
- int /* stream id */,
- double /* volume */)
-
- // Notification that a move or resize renderer's containing window has
- // started.
- IPC_MESSAGE_ROUTED0(ViewMsg_MoveOrResizeStarted)
-
- // The browser sends this message in response to all extension api calls.
- IPC_MESSAGE_ROUTED4(ViewMsg_ExtensionResponse,
- int /* request_id */,
- bool /* success */,
- std::string /* response */,
- std::string /* error */)
-
- // This message is optionally routed. If used as a control message, it
- // will call a javascript function in every registered context in the
- // target process. If routed, it will be restricted to the contexts that
- // are part of the target RenderView.
- // If |extension_id| is non-empty, the function will be invoked only in
- // contexts owned by the extension. |args| is a list of primitive Value types
- // that are passed to the function.
- IPC_MESSAGE_ROUTED4(ViewMsg_ExtensionMessageInvoke,
- std::string /* extension_id */,
- std::string /* function_name */,
- ListValue /* args */,
- GURL /* event URL */)
-
- // Tell the renderer process all known extension function names.
- IPC_MESSAGE_CONTROL1(ViewMsg_Extension_SetFunctionNames,
- std::vector<std::string>)
-
- // Tell the renderer process which permissions the given extension has. See
- // Extension::Permissions for which elements correspond to which permissions.
- IPC_MESSAGE_CONTROL2(ViewMsg_Extension_SetAPIPermissions,
- std::string /* extension_id */,
- std::set<std::string> /* permissions */)
-
- // Tell the renderer process which host permissions the given extension has.
- IPC_MESSAGE_CONTROL2(
- ViewMsg_Extension_SetHostPermissions,
- GURL /* source extension's origin */,
- std::vector<URLPattern> /* URLPatterns the extension can access */)
-
- // Tell the renderer process all known page action ids for a particular
- // extension.
- IPC_MESSAGE_CONTROL2(ViewMsg_Extension_UpdatePageActions,
- std::string /* extension_id */,
- std::vector<std::string> /* page_action_ids */)
-
- // Changes the text direction of the currently selected input field (if any).
- IPC_MESSAGE_ROUTED1(ViewMsg_SetTextDirection,
- WebKit::WebTextDirection /* direction */)
-
- // Tells the renderer to clear the focused node (if any).
- IPC_MESSAGE_ROUTED0(ViewMsg_ClearFocusedNode)
-
- // Make the RenderView transparent and render it onto a custom background. The
- // background will be tiled in both directions if it is not large enough.
- IPC_MESSAGE_ROUTED1(ViewMsg_SetBackground,
- SkBitmap /* background */)
-
- // Reply to ViewHostMsg_RequestMove, ViewHostMsg_ShowView, and
- // ViewHostMsg_ShowWidget to inform the renderer that the browser has
- // processed the move. The browser may have ignored the move, but it finished
- // processing. This is used because the renderer keeps a temporary cache of
- // the widget position while these asynchronous operations are in progress.
- IPC_MESSAGE_ROUTED0(ViewMsg_Move_ACK)
-
- // Used to instruct the RenderView to send back updates to the preferred size.
- IPC_MESSAGE_ROUTED1(ViewMsg_EnablePreferredSizeChangedMode, int /*flags*/)
-
- IPC_MESSAGE_ROUTED4(ViewMsg_SearchBoxChange,
- string16 /*value*/,
- bool /*verbatim*/,
- int /*selection_start*/,
- int /*selection_end*/)
- IPC_MESSAGE_ROUTED2(ViewMsg_SearchBoxSubmit,
- string16 /*value*/,
- bool /*verbatim*/)
- IPC_MESSAGE_ROUTED0(ViewMsg_SearchBoxCancel)
- IPC_MESSAGE_ROUTED1(ViewMsg_SearchBoxResize,
- gfx::Rect /*search_box_bounds*/)
- IPC_MESSAGE_ROUTED2(ViewMsg_DetermineIfPageSupportsInstant,
- string16 /*value*/,
- bool /* verbatim */)
-
- // Used to tell the renderer not to add scrollbars with height and
- // width below a threshold.
- IPC_MESSAGE_ROUTED1(ViewMsg_DisableScrollbarsForSmallWindows,
- gfx::Size /* disable_scrollbar_size_limit */)
-
- // Used to inform the renderer that the browser has displayed its
- // requested notification.
- IPC_MESSAGE_ROUTED1(ViewMsg_PostDisplayToNotificationObject,
- int /* notification_id */)
-
- // Used to inform the renderer that the browser has encountered an error
- // trying to display a notification.
- IPC_MESSAGE_ROUTED2(ViewMsg_PostErrorToNotificationObject,
- int /* notification_id */,
- string16 /* message */)
-
- // Informs the renderer that the one if its notifications has closed.
- IPC_MESSAGE_ROUTED2(ViewMsg_PostCloseToNotificationObject,
- int /* notification_id */,
- bool /* by_user */)
-
- // Informs the renderer that one of its notifications was clicked on.
- IPC_MESSAGE_ROUTED1(ViewMsg_PostClickToNotificationObject,
- int /* notification_id */)
-
- // Informs the renderer that the one if its notifications has closed.
- IPC_MESSAGE_ROUTED1(ViewMsg_PermissionRequestDone,
- int /* request_id */)
-
- // Activate/deactivate the RenderView (i.e., set its controls' tint
- // accordingly, etc.).
- IPC_MESSAGE_ROUTED1(ViewMsg_SetActive,
- bool /* active */)
+// Notification message sent from AudioRendererHost to renderer for state
+// update after the renderer has requested a Create/Start/Close.
+IPC_MESSAGE_ROUTED2(ViewMsg_NotifyAudioStreamStateChanged,
+ int /* stream id */,
+ ViewMsg_AudioStreamState_Params /* new state */)
+
+IPC_MESSAGE_ROUTED2(ViewMsg_NotifyAudioStreamVolume,
+ int /* stream id */,
+ double /* volume */)
+
+// Notification that a move or resize renderer's containing window has
+// started.
+IPC_MESSAGE_ROUTED0(ViewMsg_MoveOrResizeStarted)
+
+// The browser sends this message in response to all extension api calls.
+IPC_MESSAGE_ROUTED4(ViewMsg_ExtensionResponse,
+ int /* request_id */,
+ bool /* success */,
+ std::string /* response */,
+ std::string /* error */)
+
+// This message is optionally routed. If used as a control message, it
+// will call a javascript function in every registered context in the
+// target process. If routed, it will be restricted to the contexts that
+// are part of the target RenderView.
+// If |extension_id| is non-empty, the function will be invoked only in
+// contexts owned by the extension. |args| is a list of primitive Value types
+// that are passed to the function.
+IPC_MESSAGE_ROUTED4(ViewMsg_ExtensionMessageInvoke,
+ std::string /* extension_id */,
+ std::string /* function_name */,
+ ListValue /* args */,
+ GURL /* event URL */)
+
+// Tell the renderer process all known extension function names.
+IPC_MESSAGE_CONTROL1(ViewMsg_Extension_SetFunctionNames,
+ std::vector<std::string>)
+
+// Tell the renderer process which permissions the given extension has. See
+// Extension::Permissions for which elements correspond to which permissions.
+IPC_MESSAGE_CONTROL2(ViewMsg_Extension_SetAPIPermissions,
+ std::string /* extension_id */,
+ std::set<std::string> /* permissions */)
+
+// Tell the renderer process which host permissions the given extension has.
+IPC_MESSAGE_CONTROL2(
+ ViewMsg_Extension_SetHostPermissions,
+ GURL /* source extension's origin */,
+ std::vector<URLPattern> /* URLPatterns the extension can access */)
+
+// Tell the renderer process all known page action ids for a particular
+// extension.
+IPC_MESSAGE_CONTROL2(ViewMsg_Extension_UpdatePageActions,
+ std::string /* extension_id */,
+ std::vector<std::string> /* page_action_ids */)
+
+// Changes the text direction of the currently selected input field (if any).
+IPC_MESSAGE_ROUTED1(ViewMsg_SetTextDirection,
+ WebKit::WebTextDirection /* direction */)
+
+// Tells the renderer to clear the focused node (if any).
+IPC_MESSAGE_ROUTED0(ViewMsg_ClearFocusedNode)
+
+// Make the RenderView transparent and render it onto a custom background. The
+// background will be tiled in both directions if it is not large enough.
+IPC_MESSAGE_ROUTED1(ViewMsg_SetBackground,
+ SkBitmap /* background */)
+
+// Reply to ViewHostMsg_RequestMove, ViewHostMsg_ShowView, and
+// ViewHostMsg_ShowWidget to inform the renderer that the browser has
+// processed the move. The browser may have ignored the move, but it finished
+// processing. This is used because the renderer keeps a temporary cache of
+// the widget position while these asynchronous operations are in progress.
+IPC_MESSAGE_ROUTED0(ViewMsg_Move_ACK)
+
+// Used to instruct the RenderView to send back updates to the preferred size.
+IPC_MESSAGE_ROUTED1(ViewMsg_EnablePreferredSizeChangedMode, int /*flags*/)
+
+IPC_MESSAGE_ROUTED4(ViewMsg_SearchBoxChange,
+ string16 /*value*/,
+ bool /*verbatim*/,
+ int /*selection_start*/,
+ int /*selection_end*/)
+IPC_MESSAGE_ROUTED2(ViewMsg_SearchBoxSubmit,
+ string16 /*value*/,
+ bool /*verbatim*/)
+IPC_MESSAGE_ROUTED0(ViewMsg_SearchBoxCancel)
+IPC_MESSAGE_ROUTED1(ViewMsg_SearchBoxResize,
+ gfx::Rect /*search_box_bounds*/)
+IPC_MESSAGE_ROUTED2(ViewMsg_DetermineIfPageSupportsInstant,
+ string16 /*value*/,
+ bool /* verbatim */)
+
+// Used to tell the renderer not to add scrollbars with height and
+// width below a threshold.
+IPC_MESSAGE_ROUTED1(ViewMsg_DisableScrollbarsForSmallWindows,
+ gfx::Size /* disable_scrollbar_size_limit */)
+
+// Used to inform the renderer that the browser has displayed its
+// requested notification.
+IPC_MESSAGE_ROUTED1(ViewMsg_PostDisplayToNotificationObject,
+ int /* notification_id */)
+
+// Used to inform the renderer that the browser has encountered an error
+// trying to display a notification.
+IPC_MESSAGE_ROUTED2(ViewMsg_PostErrorToNotificationObject,
+ int /* notification_id */,
+ string16 /* message */)
+
+// Informs the renderer that the one if its notifications has closed.
+IPC_MESSAGE_ROUTED2(ViewMsg_PostCloseToNotificationObject,
+ int /* notification_id */,
+ bool /* by_user */)
+
+// Informs the renderer that one of its notifications was clicked on.
+IPC_MESSAGE_ROUTED1(ViewMsg_PostClickToNotificationObject,
+ int /* notification_id */)
+
+// Informs the renderer that the one if its notifications has closed.
+IPC_MESSAGE_ROUTED1(ViewMsg_PermissionRequestDone,
+ int /* request_id */)
+
+// Activate/deactivate the RenderView (i.e., set its controls' tint
+// accordingly, etc.).
+IPC_MESSAGE_ROUTED1(ViewMsg_SetActive,
+ bool /* active */)
#if defined(OS_MACOSX)
- // Let the RenderView know its window has changed visibility.
- IPC_MESSAGE_ROUTED1(ViewMsg_SetWindowVisibility,
- bool /* visibile */)
-
- // Let the RenderView know its window's frame has changed.
- IPC_MESSAGE_ROUTED2(ViewMsg_WindowFrameChanged,
- gfx::Rect /* window frame */,
- gfx::Rect /* content view frame */)
-
- // Tell the renderer that text has been retured from plugin IME.
- IPC_MESSAGE_ROUTED2(ViewMsg_PluginImeCompositionConfirmed,
- string16 /* text */,
- int /* plugin_id */)
+// Let the RenderView know its window has changed visibility.
+IPC_MESSAGE_ROUTED1(ViewMsg_SetWindowVisibility,
+ bool /* visibile */)
+
+// Let the RenderView know its window's frame has changed.
+IPC_MESSAGE_ROUTED2(ViewMsg_WindowFrameChanged,
+ gfx::Rect /* window frame */,
+ gfx::Rect /* content view frame */)
+
+// Tell the renderer that text has been retured from plugin IME.
+IPC_MESSAGE_ROUTED2(ViewMsg_PluginImeCompositionConfirmed,
+ string16 /* text */,
+ int /* plugin_id */)
#endif
- // Response message to ViewHostMsg_CreateShared/DedicatedWorker.
- // Sent when the worker has started.
- IPC_MESSAGE_ROUTED0(ViewMsg_WorkerCreated)
-
- // Tell the renderer which browser window it's being attached to.
- IPC_MESSAGE_ROUTED1(ViewMsg_UpdateBrowserWindowId,
- int /* id of browser window */)
-
- // Tell the renderer which type this view is.
- IPC_MESSAGE_ROUTED1(ViewMsg_NotifyRenderViewType,
- ViewType::Type /* view_type */)
-
- // Notification that renderer should run some JavaScript code.
- IPC_MESSAGE_ROUTED1(ViewMsg_ExecuteCode,
- ViewMsg_ExecuteCode_Params)
-
- // Notifies the child process of the new database size
- IPC_MESSAGE_CONTROL4(ViewMsg_DatabaseUpdateSize,
- string16 /* the origin */,
- string16 /* the database name */,
- int64 /* the new database size */,
- int64 /* space available to origin */)
-
- // Asks the child process to close a database immediately
- IPC_MESSAGE_CONTROL2(ViewMsg_DatabaseCloseImmediately,
- string16 /* the origin */,
- string16 /* the database name */)
-
- // Storage events are broadcast to renderer processes.
- IPC_MESSAGE_CONTROL1(ViewMsg_DOMStorageEvent,
- ViewMsg_DOMStorageEvent_Params)
-
- // IDBCallback message handlers.
- IPC_MESSAGE_CONTROL1(ViewMsg_IDBCallbacksSuccessNull,
- int32 /* response_id */)
- IPC_MESSAGE_CONTROL2(ViewMsg_IDBCallbacksSuccessIDBCursor,
- int32 /* response_id */,
- int32 /* cursor_id */)
- IPC_MESSAGE_CONTROL2(ViewMsg_IDBCallbacksSuccessIDBDatabase,
- int32 /* response_id */,
- int32 /* idb_database_id */)
- IPC_MESSAGE_CONTROL2(ViewMsg_IDBCallbacksSuccessIndexedDBKey,
- int32 /* response_id */,
- IndexedDBKey /* indexed_db_key */)
- IPC_MESSAGE_CONTROL2(ViewMsg_IDBCallbacksSuccessIDBIndex,
- int32 /* response_id */,
- int32 /* idb_index_id */)
- IPC_MESSAGE_CONTROL2(ViewMsg_IDBCallbacksSuccessIDBObjectStore,
- int32 /* response_id */,
- int32 /* idb_object_store_id */)
- IPC_MESSAGE_CONTROL2(ViewMsg_IDBCallbacksSuccessIDBTransaction,
- int32 /* response_id */,
- int32 /* idb_transaction_id */)
- IPC_MESSAGE_CONTROL2(ViewMsg_IDBCallbacksSuccessSerializedScriptValue,
- int32 /* response_id */,
- SerializedScriptValue /* serialized_script_value */)
- IPC_MESSAGE_CONTROL3(ViewMsg_IDBCallbacksError,
- int32 /* response_id */,
- int /* code */,
- string16 /* message */)
-
- // IDBTransactionCallback message handlers.
- IPC_MESSAGE_CONTROL1(ViewMsg_IDBTransactionCallbacksAbort,
- int32 /* transaction_id */)
- IPC_MESSAGE_CONTROL1(ViewMsg_IDBTransactionCallbacksComplete,
- int32 /* transaction_id */)
- IPC_MESSAGE_CONTROL1(ViewMsg_IDBTransactionCallbacksTimeout,
- int32 /* transaction_id */)
+// Response message to ViewHostMsg_CreateShared/DedicatedWorker.
+// Sent when the worker has started.
+IPC_MESSAGE_ROUTED0(ViewMsg_WorkerCreated)
+
+// Tell the renderer which browser window it's being attached to.
+IPC_MESSAGE_ROUTED1(ViewMsg_UpdateBrowserWindowId,
+ int /* id of browser window */)
+
+// Tell the renderer which type this view is.
+IPC_MESSAGE_ROUTED1(ViewMsg_NotifyRenderViewType,
+ ViewType::Type /* view_type */)
+
+// Notification that renderer should run some JavaScript code.
+IPC_MESSAGE_ROUTED1(ViewMsg_ExecuteCode,
+ ViewMsg_ExecuteCode_Params)
#if defined(IPC_MESSAGE_LOG_ENABLED)
- // Tell the renderer process to begin or end IPC message logging.
- IPC_MESSAGE_CONTROL1(ViewMsg_SetIPCLoggingEnabled,
- bool /* on or off */)
+// Tell the renderer process to begin or end IPC message logging.
+IPC_MESSAGE_CONTROL1(ViewMsg_SetIPCLoggingEnabled,
+ bool /* on or off */)
#endif
- // Socket Stream messages:
- // These are messages from the browser to the SocketStreamHandle on
- // a renderer.
-
- // A |socket_id| is assigned by ViewHostMsg_SocketStream_Connect.
- // The Socket Stream is connected. The SocketStreamHandle should keep track
- // of how much it has pending (how much it has requested to be sent) and
- // shouldn't go over |max_pending_send_allowed| bytes.
- IPC_MESSAGE_CONTROL2(ViewMsg_SocketStream_Connected,
- int /* socket_id */,
- int /* max_pending_send_allowed */)
-
- // |data| is received on the Socket Stream.
- IPC_MESSAGE_CONTROL2(ViewMsg_SocketStream_ReceivedData,
- int /* socket_id */,
- std::vector<char> /* data */)
-
- // |amount_sent| bytes of data requested by
- // ViewHostMsg_SocketStream_SendData has been sent on the Socket Stream.
- IPC_MESSAGE_CONTROL2(ViewMsg_SocketStream_SentData,
- int /* socket_id */,
- int /* amount_sent */)
-
- // The Socket Stream is closed.
- IPC_MESSAGE_CONTROL1(ViewMsg_SocketStream_Closed,
- int /* socket_id */)
-
- // SpellChecker messages.
-
- // Passes some initialization params to the renderer's spellchecker. This can
- // be called directly after startup or in (async) response to a
- // RequestDictionary ViewHost message.
- IPC_MESSAGE_CONTROL4(ViewMsg_SpellChecker_Init,
- IPC::PlatformFileForTransit /* bdict_file */,
- std::vector<std::string> /* custom_dict_words */,
- std::string /* language */,
- bool /* auto spell correct */)
-
- // A word has been added to the custom dictionary; update the local custom
- // word list.
- IPC_MESSAGE_CONTROL1(ViewMsg_SpellChecker_WordAdded,
- std::string /* word */)
-
- // Toggle the auto spell correct functionality.
- IPC_MESSAGE_CONTROL1(ViewMsg_SpellChecker_EnableAutoSpellCorrect,
- bool /* enable */)
-
- // Executes custom context menu action that was provided from WebKit.
- IPC_MESSAGE_ROUTED1(ViewMsg_CustomContextMenuAction,
- unsigned /* action */)
-
- // Tells the renderer to translate the page contents from one language to
- // another.
- IPC_MESSAGE_ROUTED4(ViewMsg_TranslatePage,
- int /* page id */,
- std::string, /* the script injected in the page */
- std::string, /* BCP 47/RFC 5646 language code the page
- is in */
- std::string /* BCP 47/RFC 5646 language code to translate
- to */)
-
- // Tells the renderer to revert the text of translated page to its original
- // contents.
- IPC_MESSAGE_ROUTED1(ViewMsg_RevertTranslation,
- int /* page id */)
-
- // Reply in response to ViewHostMsg_Geolocation_RequestPermission.
- IPC_MESSAGE_ROUTED2(ViewMsg_Geolocation_PermissionSet,
- int /* bridge_id */,
- bool /* is_allowed */)
-
- // Sent after ViewHostMsg_Geolocation_StartUpdating iff the user has granted
- // permission and we have a position available or an error occurs (such as
- // permission denied, position unavailable, etc.)
- IPC_MESSAGE_ROUTED1(ViewMsg_Geolocation_PositionUpdated,
- Geoposition /* geoposition */)
-
- // Sent on process startup to indicate whether this process is running in
- // incognito mode.
- IPC_MESSAGE_CONTROL1(ViewMsg_SetIsIncognitoProcess,
- bool /* is_incognito_processs */)
-
- // Notification that the list of extensions has been updated.
- IPC_MESSAGE_CONTROL1(ViewMsg_ExtensionsUpdated,
- ViewMsg_ExtensionsUpdated_Params)
-
- // Enable accessibility in the renderer process.
- IPC_MESSAGE_ROUTED0(ViewMsg_EnableAccessibility)
-
- // Relay a request from assistive technology to set focus to a given node.
- IPC_MESSAGE_ROUTED1(ViewMsg_SetAccessibilityFocus,
- int /* object id */)
-
- // Relay a request from assistive technology to perform the default action
- // on a given node.
- IPC_MESSAGE_ROUTED1(ViewMsg_AccessibilityDoDefaultAction,
- int /* object id */)
-
- // Tells the render view that a ViewHostMsg_AccessibilityNotifications
- // message was processed and it can send addition notifications.
- IPC_MESSAGE_ROUTED0(ViewMsg_AccessibilityNotifications_ACK)
-
- // Relay a speech recognition result, either partial or final.
- IPC_MESSAGE_ROUTED2(ViewMsg_SpeechInput_SetRecognitionResult,
- int /* request id */,
- speech_input::SpeechInputResultArray /* result */)
-
- // Indicate that speech recognizer has stopped recording and started
- // recognition.
- IPC_MESSAGE_ROUTED1(ViewMsg_SpeechInput_RecordingComplete,
- int /* request id */)
-
- // Indicate that speech recognizer has completed recognition. This will be
- // the last message sent in response to a
- // ViewHostMsg_SpeechInput_StartRecognition.
- IPC_MESSAGE_ROUTED1(ViewMsg_SpeechInput_RecognitionComplete,
- int /* request id */)
-
- // Notification that the device's orientation has changed.
- IPC_MESSAGE_ROUTED1(ViewMsg_DeviceOrientationUpdated,
- ViewMsg_DeviceOrientationUpdated_Params)
-
- // WebFrameClient::openFileSystem response messages.
- IPC_MESSAGE_CONTROL4(ViewMsg_OpenFileSystemRequest_Complete,
- int /* request_id */,
- bool /* accepted */,
- std::string /* name */,
- FilePath /* root_path */)
-
- // WebFileSystem response messages.
- IPC_MESSAGE_CONTROL1(ViewMsg_FileSystem_DidSucceed,
- int /* request_id */)
- IPC_MESSAGE_CONTROL2(ViewMsg_FileSystem_DidReadMetadata,
- int /* request_id */,
- base::PlatformFileInfo)
- IPC_MESSAGE_CONTROL3(ViewMsg_FileSystem_DidReadDirectory,
- int /* request_id */,
- std::vector<base::FileUtilProxy::Entry> /* entries */,
- bool /* has_more */)
-
- IPC_MESSAGE_CONTROL3(ViewMsg_FileSystem_DidWrite,
- int /* request_id */,
- int64 /* byte count */,
- bool /* complete */)
- IPC_MESSAGE_CONTROL2(ViewMsg_FileSystem_DidFail,
- int /* request_id */,
- base::PlatformFileError /* error_code */)
-
- // The response to ViewHostMsg_AsyncOpenFile.
- IPC_MESSAGE_ROUTED3(ViewMsg_AsyncOpenFile_ACK,
- base::PlatformFileError /* error_code */,
- IPC::PlatformFileForTransit /* file descriptor */,
- int /* message_id */)
-
- // A classification model for client-side phishing detection.
- // The given file contains an encoded safe_browsing::ClientSideModel
- // protocol buffer.
- IPC_MESSAGE_CONTROL1(ViewMsg_SetPhishingModel,
- IPC::PlatformFileForTransit /* model_file */)
-
- // External popup menus.
- IPC_MESSAGE_ROUTED1(ViewMsg_SelectPopupMenuItem,
- int /* selected index, -1 means no selection */)
-
- // Indicate whether speech input API is enabled or not.
- IPC_MESSAGE_CONTROL1(ViewMsg_SpeechInput_SetFeatureEnabled,
- bool /* enabled */)
-
-IPC_END_MESSAGES(View)
-
+// Socket Stream messages:
+// These are messages from the browser to the SocketStreamHandle on
+// a renderer.
+
+// A |socket_id| is assigned by ViewHostMsg_SocketStream_Connect.
+// The Socket Stream is connected. The SocketStreamHandle should keep track
+// of how much it has pending (how much it has requested to be sent) and
+// shouldn't go over |max_pending_send_allowed| bytes.
+IPC_MESSAGE_CONTROL2(ViewMsg_SocketStream_Connected,
+ int /* socket_id */,
+ int /* max_pending_send_allowed */)
+
+// |data| is received on the Socket Stream.
+IPC_MESSAGE_CONTROL2(ViewMsg_SocketStream_ReceivedData,
+ int /* socket_id */,
+ std::vector<char> /* data */)
+
+// |amount_sent| bytes of data requested by
+// ViewHostMsg_SocketStream_SendData has been sent on the Socket Stream.
+IPC_MESSAGE_CONTROL2(ViewMsg_SocketStream_SentData,
+ int /* socket_id */,
+ int /* amount_sent */)
+
+// The Socket Stream is closed.
+IPC_MESSAGE_CONTROL1(ViewMsg_SocketStream_Closed,
+ int /* socket_id */)
+
+// SpellChecker messages.
+
+// Passes some initialization params to the renderer's spellchecker. This can
+// be called directly after startup or in (async) response to a
+// RequestDictionary ViewHost message.
+IPC_MESSAGE_CONTROL4(ViewMsg_SpellChecker_Init,
+ IPC::PlatformFileForTransit /* bdict_file */,
+ std::vector<std::string> /* custom_dict_words */,
+ std::string /* language */,
+ bool /* auto spell correct */)
+
+// A word has been added to the custom dictionary; update the local custom
+// word list.
+IPC_MESSAGE_CONTROL1(ViewMsg_SpellChecker_WordAdded,
+ std::string /* word */)
+
+// Toggle the auto spell correct functionality.
+IPC_MESSAGE_CONTROL1(ViewMsg_SpellChecker_EnableAutoSpellCorrect,
+ bool /* enable */)
+
+// Executes custom context menu action that was provided from WebKit.
+IPC_MESSAGE_ROUTED1(ViewMsg_CustomContextMenuAction,
+ unsigned /* action */)
+
+// Tells the renderer to translate the page contents from one language to
+// another.
+IPC_MESSAGE_ROUTED4(ViewMsg_TranslatePage,
+ int /* page id */,
+ std::string, /* the script injected in the page */
+ std::string, /* BCP 47/RFC 5646 language code the page
+ is in */
+ std::string /* BCP 47/RFC 5646 language code to translate
+ to */)
+
+// Tells the renderer to revert the text of translated page to its original
+// contents.
+IPC_MESSAGE_ROUTED1(ViewMsg_RevertTranslation,
+ int /* page id */)
+
+// Reply in response to ViewHostMsg_Geolocation_RequestPermission.
+IPC_MESSAGE_ROUTED2(ViewMsg_Geolocation_PermissionSet,
+ int /* bridge_id */,
+ bool /* is_allowed */)
+
+// Sent after ViewHostMsg_Geolocation_StartUpdating iff the user has granted
+// permission and we have a position available or an error occurs (such as
+// permission denied, position unavailable, etc.)
+IPC_MESSAGE_ROUTED1(ViewMsg_Geolocation_PositionUpdated,
+ Geoposition /* geoposition */)
+
+// Sent on process startup to indicate whether this process is running in
+// incognito mode.
+IPC_MESSAGE_CONTROL1(ViewMsg_SetIsIncognitoProcess,
+ bool /* is_incognito_processs */)
+
+// Notification that the list of extensions has been updated.
+IPC_MESSAGE_CONTROL1(ViewMsg_ExtensionsUpdated,
+ ViewMsg_ExtensionsUpdated_Params)
+
+// Enable accessibility in the renderer process.
+IPC_MESSAGE_ROUTED0(ViewMsg_EnableAccessibility)
+
+// Relay a request from assistive technology to set focus to a given node.
+IPC_MESSAGE_ROUTED1(ViewMsg_SetAccessibilityFocus,
+ int /* object id */)
+
+// Relay a request from assistive technology to perform the default action
+// on a given node.
+IPC_MESSAGE_ROUTED1(ViewMsg_AccessibilityDoDefaultAction,
+ int /* object id */)
+
+// Tells the render view that a ViewHostMsg_AccessibilityNotifications
+// message was processed and it can send addition notifications.
+IPC_MESSAGE_ROUTED0(ViewMsg_AccessibilityNotifications_ACK)
+
+// Relay a speech recognition result, either partial or final.
+IPC_MESSAGE_ROUTED2(ViewMsg_SpeechInput_SetRecognitionResult,
+ int /* request id */,
+ speech_input::SpeechInputResultArray /* result */)
+
+// Indicate that speech recognizer has stopped recording and started
+// recognition.
+IPC_MESSAGE_ROUTED1(ViewMsg_SpeechInput_RecordingComplete,
+ int /* request id */)
+
+// Indicate that speech recognizer has completed recognition. This will be
+// the last message sent in response to a
+// ViewHostMsg_SpeechInput_StartRecognition.
+IPC_MESSAGE_ROUTED1(ViewMsg_SpeechInput_RecognitionComplete,
+ int /* request id */)
+
+// Notification that the device's orientation has changed.
+IPC_MESSAGE_ROUTED1(ViewMsg_DeviceOrientationUpdated,
+ ViewMsg_DeviceOrientationUpdated_Params)
+
+// WebFrameClient::openFileSystem response messages.
+IPC_MESSAGE_CONTROL4(ViewMsg_OpenFileSystemRequest_Complete,
+ int /* request_id */,
+ bool /* accepted */,
+ std::string /* name */,
+ FilePath /* root_path */)
+
+// WebFileSystem response messages.
+IPC_MESSAGE_CONTROL1(ViewMsg_FileSystem_DidSucceed,
+ int /* request_id */)
+IPC_MESSAGE_CONTROL2(ViewMsg_FileSystem_DidReadMetadata,
+ int /* request_id */,
+ base::PlatformFileInfo)
+IPC_MESSAGE_CONTROL3(ViewMsg_FileSystem_DidReadDirectory,
+ int /* request_id */,
+ std::vector<base::FileUtilProxy::Entry> /* entries */,
+ bool /* has_more */)
+
+IPC_MESSAGE_CONTROL3(ViewMsg_FileSystem_DidWrite,
+ int /* request_id */,
+ int64 /* byte count */,
+ bool /* complete */)
+IPC_MESSAGE_CONTROL2(ViewMsg_FileSystem_DidFail,
+ int /* request_id */,
+ base::PlatformFileError /* error_code */)
+
+// The response to ViewHostMsg_AsyncOpenFile.
+IPC_MESSAGE_ROUTED3(ViewMsg_AsyncOpenFile_ACK,
+ base::PlatformFileError /* error_code */,
+ IPC::PlatformFileForTransit /* file descriptor */,
+ int /* message_id */)
+
+// A classification model for client-side phishing detection.
+// The given file contains an encoded safe_browsing::ClientSideModel
+// protocol buffer.
+IPC_MESSAGE_CONTROL1(ViewMsg_SetPhishingModel,
+ IPC::PlatformFileForTransit /* model_file */)
+
+// External popup menus.
+IPC_MESSAGE_ROUTED1(ViewMsg_SelectPopupMenuItem,
+ int /* selected index, -1 means no selection */)
+
+// Indicate whether speech input API is enabled or not.
+IPC_MESSAGE_CONTROL1(ViewMsg_SpeechInput_SetFeatureEnabled,
+ bool /* enabled */)
//-----------------------------------------------------------------------------
// TabContents messages
// These are messages sent from the renderer to the browser process.
-IPC_BEGIN_MESSAGES(ViewHost)
- // Sent by the renderer when it is creating a new window. The browser creates
- // a tab for it and responds with a ViewMsg_CreatingNew_ACK. If route_id is
- // MSG_ROUTING_NONE, the view couldn't be created.
- IPC_SYNC_MESSAGE_CONTROL1_2(ViewHostMsg_CreateWindow,
- ViewHostMsg_CreateWindow_Params,
- int /* route_id */,
- int64 /* cloned_session_storage_namespace_id */)
-
- // Similar to ViewHostMsg_CreateWindow, except used for sub-widgets, like
- // <select> dropdowns. This message is sent to the TabContents that
- // contains the widget being created.
- IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_CreateWidget,
- int /* opener_id */,
- WebKit::WebPopupType /* popup type */,
- int /* route_id */)
-
- // Similar to ViewHostMsg_CreateWidget except the widget is a full screen
- // window.
- IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_CreateFullscreenWidget,
- int /* opener_id */,
- WebKit::WebPopupType /* popup type */,
- int /* route_id */)
-
- // These three messages are sent to the parent RenderViewHost to display the
- // page/widget that was created by
- // CreateWindow/CreateWidget/CreateFullscreenWidget. routing_id
- // refers to the id that was returned from the Create message above.
- // The initial_position parameter is a rectangle in screen coordinates.
- //
- // FUTURE: there will probably be flags here to control if the result is
- // in a new window.
- IPC_MESSAGE_ROUTED4(ViewHostMsg_ShowView,
- int /* route_id */,
- WindowOpenDisposition /* disposition */,
- gfx::Rect /* initial_pos */,
- bool /* opened_by_user_gesture */)
-
- IPC_MESSAGE_ROUTED2(ViewHostMsg_ShowWidget,
- int /* route_id */,
- gfx::Rect /* initial_pos */)
-
- // Message to show a full screen widget.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_ShowFullscreenWidget,
- int /* route_id */)
-
- // Message to show a popup menu using native cocoa controls (Mac only).
- IPC_MESSAGE_ROUTED1(ViewHostMsg_ShowPopup,
- ViewHostMsg_ShowPopup_Params)
-
- // This message is sent after ViewHostMsg_ShowView to cause the RenderView
- // to run in a modal fashion until it is closed.
- IPC_SYNC_MESSAGE_ROUTED0_0(ViewHostMsg_RunModal)
-
- IPC_MESSAGE_CONTROL1(ViewHostMsg_UpdatedCacheStats,
- WebKit::WebCache::UsageStats /* stats */)
-
- // Indicates the renderer is ready in response to a ViewMsg_New or
- // a ViewMsg_CreatingNew_ACK.
- IPC_MESSAGE_ROUTED0(ViewHostMsg_RenderViewReady)
-
- // Indicates the renderer process is gone. This actually is sent by the
- // browser process to itself, but keeps the interface cleaner.
- IPC_MESSAGE_ROUTED0(ViewHostMsg_RenderViewGone)
-
- // Sent by the renderer process to request that the browser close the view.
- // This corresponds to the window.close() API, and the browser may ignore
- // this message. Otherwise, the browser will generates a ViewMsg_Close
- // message to close the view.
- IPC_MESSAGE_ROUTED0(ViewHostMsg_Close)
-
- // Sent by the renderer process to request that the browser move the view.
- // This corresponds to the window.resizeTo() and window.moveTo() APIs, and
- // the browser may ignore this message.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_RequestMove,
- gfx::Rect /* position */)
-
- // Notifies the browser that a frame in the view has changed. This message
- // has a lot of parameters and is packed/unpacked by functions defined in
- // render_messages.h.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_FrameNavigate,
- ViewHostMsg_FrameNavigate_Params)
-
- // Notifies the browser that we have session history information.
- // page_id: unique ID that allows us to distinguish between history entries.
- IPC_MESSAGE_ROUTED2(ViewHostMsg_UpdateState,
- int32 /* page_id */,
- std::string /* state */)
-
- // Notifies the browser that a document has been loaded in a frame.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_DocumentLoadedInFrame,
- long long /* frame_id */)
-
- // Notifies the browser that a frame finished loading.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_DidFinishLoad,
- long long /* frame_id */)
-
- // Changes the title for the page in the UI when the page is navigated or the
- // title changes.
- // TODO(darin): use a UTF-8 string to reduce data size
- IPC_MESSAGE_ROUTED2(ViewHostMsg_UpdateTitle, int32, std::wstring)
-
- // Changes the icon url for the page in the UI.
- IPC_MESSAGE_ROUTED2(ViewHostMsg_UpdateIconURL, int32, GURL)
-
- // Change the encoding name of the page in UI when the page has detected
- // proper encoding name.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_UpdateEncoding,
- std::string /* new encoding name */)
-
- // Notifies the browser that we want to show a destination url for a potential
- // action (e.g. when the user is hovering over a link).
- IPC_MESSAGE_ROUTED2(ViewHostMsg_UpdateTargetURL, int32, GURL)
-
- // Sent when the renderer starts loading the page. This corresponds to
- // WebKit's notion of the throbber starting. Note that sometimes you may get
- // duplicates of these during a single load.
- IPC_MESSAGE_ROUTED0(ViewHostMsg_DidStartLoading)
-
- // Sent when the renderer is done loading a page. This corresponds to WebKit's
- // notion of the throbber stopping.
- IPC_MESSAGE_ROUTED0(ViewHostMsg_DidStopLoading)
-
- // Sent when the document element is available for the toplevel frame. This
- // happens after the page starts loading, but before all resources are
- // finished.
- IPC_MESSAGE_ROUTED0(ViewHostMsg_DocumentAvailableInMainFrame)
-
- // Sent when after the onload handler has been invoked for the document
- // in the toplevel frame.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_DocumentOnLoadCompletedInMainFrame,
- int32 /* page_id */)
-
- // Sent when the renderer loads a resource from its memory cache.
- // The security info is non empty if the resource was originally loaded over
- // a secure connection.
- // Note: May only be sent once per URL per frame per committed load.
- IPC_MESSAGE_ROUTED4(ViewHostMsg_DidLoadResourceFromMemoryCache,
- GURL /* url */,
- std::string /* frame_origin */,
- std::string /* main_frame_origin */,
- std::string /* security info */)
-
- // Sent when the renderer displays insecure content in a secure page.
- IPC_MESSAGE_ROUTED0(ViewHostMsg_DidDisplayInsecureContent)
-
- // Sent when the renderer runs insecure content in a secure origin.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_DidRunInsecureContent,
- std::string /* security_origin */)
-
- // Sent when the renderer starts a provisional load for a frame.
- IPC_MESSAGE_ROUTED3(ViewHostMsg_DidStartProvisionalLoadForFrame,
- long long /* frame_id */,
- bool /* true if it is the main frame */,
- GURL /* url */)
-
- // Sent when the renderer fails a provisional load with an error.
- IPC_MESSAGE_ROUTED5(ViewHostMsg_DidFailProvisionalLoadWithError,
- long long /* frame_id */,
- bool /* true if it is the main frame */,
- int /* error_code */,
- GURL /* url */,
- bool /* true if the failure is the result of
- navigating to a POST again and we're going to
- show the POST interstitial */)
-
- // Tells the render view that a ViewHostMsg_PaintAtSize message was
- // processed, and the DIB is ready for use. |tag| has the same value that
- // the tag sent along with ViewMsg_PaintAtSize.
- IPC_MESSAGE_ROUTED2(ViewHostMsg_PaintAtSize_ACK,
- int /* tag */,
- gfx::Size /* size */)
-
- // Sent to update part of the view. In response to this message, the host
- // generates a ViewMsg_UpdateRect_ACK message.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_UpdateRect,
- ViewHostMsg_UpdateRect_Params)
-
- // Sent by the renderer when accelerated compositing is enabled or disabled to
- // notify the browser whether or not is should do painting.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_DidActivateAcceleratedCompositing,
- bool /* true if the accelerated compositor is actve */)
-
- // Acknowledges receipt of a ViewMsg_HandleInputEvent message.
- // Payload is a WebInputEvent::Type which is the type of the event, followed
- // by an optional WebInputEvent which is provided only if the event was not
- // processed.
- IPC_MESSAGE_ROUTED0(ViewHostMsg_HandleInputEvent_ACK)
-
- IPC_MESSAGE_ROUTED0(ViewHostMsg_Focus)
- IPC_MESSAGE_ROUTED0(ViewHostMsg_Blur)
-
- // Message sent from renderer to the browser when focus changes inside the
- // webpage. The parameter says whether the newly focused element needs
- // keyboard input (true for textfields, text areas and content editable divs).
- IPC_MESSAGE_ROUTED1(ViewHostMsg_FocusedNodeChanged,
- bool /* is_editable_node */)
-
- // Returns the window location of the given window.
- // TODO(shess): Provide a mapping from reply_msg->routing_id() to
- // HWND so that we can eliminate the NativeViewId parameter.
- IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_GetWindowRect,
- gfx::NativeViewId /* window */,
- gfx::Rect /* Out: Window location */)
-
- IPC_MESSAGE_ROUTED1(ViewHostMsg_SetCursor, WebCursor)
- // Result of string search in the page.
- // Response to ViewMsg_Find with the results of the requested find-in-page
- // search, the number of matches found and the selection rect (in screen
- // coordinates) for the string found. If |final_update| is false, it signals
- // that this is not the last Find_Reply message - more will be sent as the
- // scoping effort continues.
- IPC_MESSAGE_ROUTED5(ViewHostMsg_Find_Reply,
- int /* request_id */,
- int /* number of matches */,
- gfx::Rect /* selection_rect */,
- int /* active_match_ordinal */,
- bool /* final_update */)
-
- // Makes a resource request via the browser.
- IPC_MESSAGE_ROUTED2(ViewHostMsg_RequestResource,
- int /* request_id */,
- ViewHostMsg_Resource_Request)
-
- // Cancels a resource request with the ID given as the parameter.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_CancelRequest,
- int /* request_id */)
-
- // Follows a redirect that occured for the resource request with the ID given
- // as the parameter.
- IPC_MESSAGE_ROUTED3(ViewHostMsg_FollowRedirect,
- int /* request_id */,
- bool /* has_new_first_party_for_cookies */,
- GURL /* new_first_party_for_cookies */)
-
- // Makes a synchronous resource request via the browser.
- IPC_SYNC_MESSAGE_ROUTED2_1(ViewHostMsg_SyncLoad,
- int /* request_id */,
- ViewHostMsg_Resource_Request,
- SyncLoadResult)
-
- // Used to set a cookie. The cookie is set asynchronously, but will be
- // available to a subsequent ViewHostMsg_GetCookies request.
- IPC_MESSAGE_ROUTED3(ViewHostMsg_SetCookie,
- GURL /* url */,
- GURL /* first_party_for_cookies */,
- std::string /* cookie */)
-
- // Used to get cookies for the given URL. This may block waiting for a
- // previous SetCookie message to be processed.
- IPC_SYNC_MESSAGE_ROUTED2_1(ViewHostMsg_GetCookies,
- GURL /* url */,
- GURL /* first_party_for_cookies */,
- std::string /* cookies */)
-
- // Used to get raw cookie information for the given URL. This may block
- // waiting for a previous SetCookie message to be processed.
- IPC_SYNC_MESSAGE_ROUTED2_1(ViewHostMsg_GetRawCookies,
- GURL /* url */,
- GURL /* first_party_for_cookies */,
- std::vector<webkit_glue::WebCookie>
- /* raw_cookies */)
-
- // Used to delete cookie for the given URL and name
- IPC_SYNC_MESSAGE_CONTROL2_0(ViewHostMsg_DeleteCookie,
- GURL /* url */,
- std::string /* cookie_name */)
-
- // Used to check if cookies are enabled for the given URL. This may block
- // waiting for a previous SetCookie message to be processed.
- IPC_SYNC_MESSAGE_ROUTED2_1(ViewHostMsg_CookiesEnabled,
- GURL /* url */,
- GURL /* first_party_for_cookies */,
- bool /* cookies_enabled */)
-
- // Used to get the list of plugins
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_GetPlugins,
- bool /* refresh*/,
- std::vector<WebPluginInfo> /* plugins */)
-
- // Return information about a plugin for the given URL and MIME
- // type. If there is no matching plugin, |found| is false. If
- // |enabled| in the WebPluginInfo struct is false, the plug-in is
- // treated as if it was not installed at all.
- //
- // If |setting| is set to CONTENT_SETTING_BLOCK, the plug-in is
- // blocked by the content settings for |policy_url|. It still
- // appears in navigator.plugins in Javascript though, and can be
- // loaded via click-to-play.
- //
- // If |setting| is set to CONTENT_SETTING_ALLOW, the domain is
- // explicitly white-listed for the plug-in, or the user has chosen
- // not to block nonsandboxed plugins.
- //
- // If |setting| is set to CONTENT_SETTING_DEFAULT, the plug-in is
- // neither blocked nor white-listed, which means that it's allowed
- // by default and can still be blocked if it's non-sandboxed.
- //
- // |actual_mime_type| is the actual mime type supported by the
- // plugin found that match the URL given (one for each item in
- // |info|).
- IPC_SYNC_MESSAGE_CONTROL3_4(ViewHostMsg_GetPluginInfo,
- GURL /* url */,
- GURL /* policy_url */,
- std::string /* mime_type */,
- bool /* found */,
- WebPluginInfo /* plugin info */,
- ContentSetting /* setting */,
- std::string /* actual_mime_type */)
-
- // Requests spellcheck for a word.
- IPC_SYNC_MESSAGE_ROUTED2_2(ViewHostMsg_SpellCheck,
- string16 /* word to check */,
- int /* document tag*/,
- int /* misspell location */,
- int /* misspell length */)
-
- // Asks the browser for a unique document tag.
- IPC_SYNC_MESSAGE_ROUTED0_1(ViewHostMsg_GetDocumentTag,
- int /* the tag */)
-
-
- // This message tells the spellchecker that a document, identified by an int
- // tag, has been closed and all of the ignored words for that document can be
- // forgotten.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_DocumentWithTagClosed,
- int /* the tag */)
-
- // Tells the browser to display or not display the SpellingPanel
- IPC_MESSAGE_ROUTED1(ViewHostMsg_ShowSpellingPanel,
- bool /* if true, then show it, otherwise hide it*/)
-
- // Tells the browser to update the spelling panel with the given word.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_UpdateSpellingPanelWithMisspelledWord,
- string16 /* the word to update the panel with */)
-
- // Tells the browser that content in the current page was blocked due to the
- // user's content settings.
- IPC_MESSAGE_ROUTED2(ViewHostMsg_ContentBlocked,
- ContentSettingsType, /* type of blocked content */
- std::string /* resource identifier */)
-
- // Tells the browser that a specific Appcache manifest in the current page
- // was accessed.
- IPC_MESSAGE_ROUTED2(ViewHostMsg_AppCacheAccessed,
- GURL /* manifest url */,
- bool /* blocked by policy */)
-
- // Tells the browser that a specific Web database in the current page was
- // accessed.
- IPC_MESSAGE_ROUTED5(ViewHostMsg_WebDatabaseAccessed,
- GURL /* origin url */,
- string16 /* database name */,
- string16 /* database display name */,
- unsigned long /* estimated size */,
- bool /* blocked by policy */)
-
- // Initiates a download based on user actions like 'ALT+click'.
- IPC_MESSAGE_ROUTED2(ViewHostMsg_DownloadUrl,
- GURL /* url */,
- GURL /* referrer */)
-
- // Used to go to the session history entry at the given offset (ie, -1 will
- // return the "back" item).
- IPC_MESSAGE_ROUTED1(ViewHostMsg_GoToEntryAtOffset,
- int /* offset (from current) of history item to get */)
-
- IPC_SYNC_MESSAGE_ROUTED4_2(ViewHostMsg_RunJavaScriptMessage,
- std::wstring /* in - alert message */,
- std::wstring /* in - default prompt */,
- GURL /* in - originating page URL */,
- int /* in - dialog flags */,
- bool /* out - success */,
- std::wstring /* out - prompt field */)
-
- // Provides the contents for the given page that was loaded recently.
- IPC_MESSAGE_ROUTED5(ViewHostMsg_PageContents,
- GURL /* URL of the page */,
- int32 /* page id */,
- string16 /* page contents */,
- std::string /* page ISO639_1 language code */,
- bool /* whether the page can be translated */)
-
- // Used to get the extension message bundle.
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_GetExtensionMessageBundle,
- std::string /* extension id */,
- SubstitutionMap /* message bundle */)
-
- // Specifies the URL as the first parameter (a wstring) and thumbnail as
- // binary data as the second parameter.
- IPC_MESSAGE_ROUTED3(ViewHostMsg_Thumbnail,
- GURL /* url */,
- ThumbnailScore /* score */,
- SkBitmap /* bitmap */)
-
- // Send a snapshot of the tab contents to the render host.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_Snapshot,
- SkBitmap /* bitmap */)
-
- // Notification that the url for the favicon of a site has been determined.
- IPC_MESSAGE_ROUTED2(ViewHostMsg_UpdateFavIconURL,
- int32 /* page_id */,
- GURL /* url of the favicon */)
-
- // Used to tell the parent that the user right clicked on an area of the
- // content area, and a context menu should be shown for it. The params
- // object contains information about the node(s) that were selected when the
- // user right clicked.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_ContextMenu, ContextMenuParams)
-
- // Requests that the given URL be opened in the specified manner.
- IPC_MESSAGE_ROUTED3(ViewHostMsg_OpenURL,
- GURL /* url */,
- GURL /* referrer */,
- WindowOpenDisposition /* disposition */)
-
- // Notifies that the preferred size of the content changed.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_DidContentsPreferredSizeChange,
- gfx::Size /* pref_size */)
-
- // Following message is used to communicate the values received by the
- // callback binding the JS to Cpp.
- // An instance of browser that has an automation host listening to it can
- // have a javascript send a native value (string, number, boolean) to the
- // listener in Cpp. (DomAutomationController)
- IPC_MESSAGE_ROUTED2(ViewHostMsg_DomOperationResponse,
- std::string /* json_string */,
- int /* automation_id */)
-
- // A message from HTML-based UI. When (trusted) Javascript calls
- // send(message, args), this message is sent to the browser.
- IPC_MESSAGE_ROUTED3(ViewHostMsg_DOMUISend,
- GURL /* source_url */,
- std::string /* message */,
- std::string /* args (as a JSON string) */)
-
- // A message for an external host.
- IPC_MESSAGE_ROUTED3(ViewHostMsg_ForwardMessageToExternalHost,
- std::string /* message */,
- std::string /* origin */,
- std::string /* target */)
-
- // A renderer sends this to the browser process when it wants to
- // create a plugin. The browser will create the plugin process if
- // necessary, and will return a handle to the channel on success.
- // On error an empty string is returned.
- IPC_SYNC_MESSAGE_CONTROL2_2(ViewHostMsg_OpenChannelToPlugin,
- GURL /* url */,
- std::string /* mime_type */,
- IPC::ChannelHandle /* handle to channel */,
- WebPluginInfo /* info */)
-
- // A renderer sends this to the browser process when it wants to
- // create a pepper plugin. The browser will create the plugin process if
- // necessary, and will return a handle to the channel on success.
- // On error an empty string is returned.
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_OpenChannelToPepperPlugin,
- FilePath /* path */,
- IPC::ChannelHandle /* handle to channel */)
-
- // A renderer sends this to the browser process when it wants to
- // create connect to the GPU. The browser will create the GPU process if
- // necessary, and will return a handle to the channel via
- // a GpuChannelEstablished message.
- IPC_MESSAGE_CONTROL0(ViewHostMsg_EstablishGpuChannel)
-
- // A renderer sends this to the browser process to provide a synchronization
- // point for GPU operations, in particular to make sure the GPU channel has
- // been established.
- IPC_SYNC_MESSAGE_CONTROL0_0(ViewHostMsg_SynchronizeGpu)
-
- // A renderer sends this to the browser process when it wants to start
- // a new instance of the Native Client process. The browser will launch
- // the process and return a handle to an IMC channel.
- IPC_SYNC_MESSAGE_CONTROL2_3(ViewHostMsg_LaunchNaCl,
- std::wstring /* url for the NaCl module */,
- int /* socket count */,
- std::vector<nacl::FileDescriptor>
- /* imc channel handles */,
- base::ProcessHandle /* NaCl process handle */,
- base::ProcessId /* NaCl process id */)
+// Sent by the renderer when it is creating a new window. The browser creates
+// a tab for it and responds with a ViewMsg_CreatingNew_ACK. If route_id is
+// MSG_ROUTING_NONE, the view couldn't be created.
+IPC_SYNC_MESSAGE_CONTROL1_2(ViewHostMsg_CreateWindow,
+ ViewHostMsg_CreateWindow_Params,
+ int /* route_id */,
+ int64 /* cloned_session_storage_namespace_id */)
+
+// Similar to ViewHostMsg_CreateWindow, except used for sub-widgets, like
+// <select> dropdowns. This message is sent to the TabContents that
+// contains the widget being created.
+IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_CreateWidget,
+ int /* opener_id */,
+ WebKit::WebPopupType /* popup type */,
+ int /* route_id */)
+
+// Similar to ViewHostMsg_CreateWidget except the widget is a full screen
+// window.
+IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_CreateFullscreenWidget,
+ int /* opener_id */,
+ WebKit::WebPopupType /* popup type */,
+ int /* route_id */)
+
+// These three messages are sent to the parent RenderViewHost to display the
+// page/widget that was created by
+// CreateWindow/CreateWidget/CreateFullscreenWidget. routing_id
+// refers to the id that was returned from the Create message above.
+// The initial_position parameter is a rectangle in screen coordinates.
+//
+// FUTURE: there will probably be flags here to control if the result is
+// in a new window.
+IPC_MESSAGE_ROUTED4(ViewHostMsg_ShowView,
+ int /* route_id */,
+ WindowOpenDisposition /* disposition */,
+ gfx::Rect /* initial_pos */,
+ bool /* opened_by_user_gesture */)
+
+IPC_MESSAGE_ROUTED2(ViewHostMsg_ShowWidget,
+ int /* route_id */,
+ gfx::Rect /* initial_pos */)
+
+// Message to show a full screen widget.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_ShowFullscreenWidget,
+ int /* route_id */)
+
+// Message to show a popup menu using native cocoa controls (Mac only).
+IPC_MESSAGE_ROUTED1(ViewHostMsg_ShowPopup,
+ ViewHostMsg_ShowPopup_Params)
+
+// This message is sent after ViewHostMsg_ShowView to cause the RenderView
+// to run in a modal fashion until it is closed.
+IPC_SYNC_MESSAGE_ROUTED0_0(ViewHostMsg_RunModal)
+
+IPC_MESSAGE_CONTROL1(ViewHostMsg_UpdatedCacheStats,
+ WebKit::WebCache::UsageStats /* stats */)
+
+// Indicates the renderer is ready in response to a ViewMsg_New or
+// a ViewMsg_CreatingNew_ACK.
+IPC_MESSAGE_ROUTED0(ViewHostMsg_RenderViewReady)
+
+
+// Indicates the renderer process is gone. This actually is sent by the
+// browser process to itself, but keeps the interface cleaner.
+IPC_MESSAGE_ROUTED2(ViewHostMsg_RenderViewGone,
+ int, /* this really is base::TerminationStatus */
+ int /* exit_code */)
+
+// Sent by the renderer process to request that the browser close the view.
+// This corresponds to the window.close() API, and the browser may ignore
+// this message. Otherwise, the browser will generates a ViewMsg_Close
+// message to close the view.
+IPC_MESSAGE_ROUTED0(ViewHostMsg_Close)
+
+// Sent by the renderer process to request that the browser move the view.
+// This corresponds to the window.resizeTo() and window.moveTo() APIs, and
+// the browser may ignore this message.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_RequestMove,
+ gfx::Rect /* position */)
+
+// Notifies the browser that a frame in the view has changed. This message
+// has a lot of parameters and is packed/unpacked by functions defined in
+// render_messages.h.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_FrameNavigate,
+ ViewHostMsg_FrameNavigate_Params)
+
+// Notifies the browser that we have session history information.
+// page_id: unique ID that allows us to distinguish between history entries.
+IPC_MESSAGE_ROUTED2(ViewHostMsg_UpdateState,
+ int32 /* page_id */,
+ std::string /* state */)
+
+// Notifies the browser that a document has been loaded in a frame.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_DocumentLoadedInFrame,
+ int64 /* frame_id */)
+
+// Notifies the browser that a frame finished loading.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_DidFinishLoad,
+ int64 /* frame_id */)
+
+// Changes the title for the page in the UI when the page is navigated or the
+// title changes.
+// TODO(darin): use a UTF-8 string to reduce data size
+IPC_MESSAGE_ROUTED2(ViewHostMsg_UpdateTitle, int32, std::wstring)
+
+// Changes the icon url for the page in the UI.
+IPC_MESSAGE_ROUTED2(ViewHostMsg_UpdateIconURL, int32, GURL)
+
+// Change the encoding name of the page in UI when the page has detected
+// proper encoding name.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_UpdateEncoding,
+ std::string /* new encoding name */)
+
+// Notifies the browser that we want to show a destination url for a potential
+// action (e.g. when the user is hovering over a link).
+IPC_MESSAGE_ROUTED2(ViewHostMsg_UpdateTargetURL, int32, GURL)
+
+// Sent when the renderer starts loading the page. This corresponds to
+// WebKit's notion of the throbber starting. Note that sometimes you may get
+// duplicates of these during a single load.
+IPC_MESSAGE_ROUTED0(ViewHostMsg_DidStartLoading)
+
+// Sent when the renderer is done loading a page. This corresponds to WebKit's
+// notion of the throbber stopping.
+IPC_MESSAGE_ROUTED0(ViewHostMsg_DidStopLoading)
+
+// Sent when the renderer main frame has made progress loading.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_DidChangeLoadProgress,
+ double /* load_progress */)
+
+// Sent when the document element is available for the toplevel frame. This
+// happens after the page starts loading, but before all resources are
+// finished.
+IPC_MESSAGE_ROUTED0(ViewHostMsg_DocumentAvailableInMainFrame)
+
+// Sent when after the onload handler has been invoked for the document
+// in the toplevel frame.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_DocumentOnLoadCompletedInMainFrame,
+ int32 /* page_id */)
+
+// Sent when the renderer loads a resource from its memory cache.
+// The security info is non empty if the resource was originally loaded over
+// a secure connection.
+// Note: May only be sent once per URL per frame per committed load.
+IPC_MESSAGE_ROUTED4(ViewHostMsg_DidLoadResourceFromMemoryCache,
+ GURL /* url */,
+ std::string /* frame_origin */,
+ std::string /* main_frame_origin */,
+ std::string /* security info */)
+
+// Sent when the renderer displays insecure content in a secure page.
+IPC_MESSAGE_ROUTED0(ViewHostMsg_DidDisplayInsecureContent)
+
+// Sent when the renderer runs insecure content in a secure origin.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_DidRunInsecureContent,
+ std::string /* security_origin */)
+
+// Sent when the renderer starts a provisional load for a frame.
+IPC_MESSAGE_ROUTED3(ViewHostMsg_DidStartProvisionalLoadForFrame,
+ int64 /* frame_id */,
+ bool /* true if it is the main frame */,
+ GURL /* url */)
+
+// Sent when the renderer fails a provisional load with an error.
+IPC_MESSAGE_ROUTED5(ViewHostMsg_DidFailProvisionalLoadWithError,
+ int64 /* frame_id */,
+ bool /* true if it is the main frame */,
+ int /* error_code */,
+ GURL /* url */,
+ bool /* true if the failure is the result of
+ navigating to a POST again and we're going to
+ show the POST interstitial */)
+
+// Tells the render view that a ViewHostMsg_PaintAtSize message was
+// processed, and the DIB is ready for use. |tag| has the same value that
+// the tag sent along with ViewMsg_PaintAtSize.
+IPC_MESSAGE_ROUTED2(ViewHostMsg_PaintAtSize_ACK,
+ int /* tag */,
+ gfx::Size /* size */)
+
+// Sent to update part of the view. In response to this message, the host
+// generates a ViewMsg_UpdateRect_ACK message.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_UpdateRect,
+ ViewHostMsg_UpdateRect_Params)
+
+// Sent by the renderer when accelerated compositing is enabled or disabled to
+// notify the browser whether or not is should do painting.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_DidActivateAcceleratedCompositing,
+ bool /* true if the accelerated compositor is actve */)
+
+// Acknowledges receipt of a ViewMsg_HandleInputEvent message.
+// Payload is a WebInputEvent::Type which is the type of the event, followed
+// by an optional WebInputEvent which is provided only if the event was not
+// processed.
+IPC_MESSAGE_ROUTED0(ViewHostMsg_HandleInputEvent_ACK)
+
+IPC_MESSAGE_ROUTED0(ViewHostMsg_Focus)
+IPC_MESSAGE_ROUTED0(ViewHostMsg_Blur)
+
+// Message sent from renderer to the browser when focus changes inside the
+// webpage. The parameter says whether the newly focused element needs
+// keyboard input (true for textfields, text areas and content editable divs).
+IPC_MESSAGE_ROUTED1(ViewHostMsg_FocusedNodeChanged,
+ bool /* is_editable_node */)
+
+// Returns the window location of the given window.
+// TODO(shess): Provide a mapping from reply_msg->routing_id() to
+// HWND so that we can eliminate the NativeViewId parameter.
+IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_GetWindowRect,
+ gfx::NativeViewId /* window */,
+ gfx::Rect /* Out: Window location */)
+
+IPC_MESSAGE_ROUTED1(ViewHostMsg_SetCursor, WebCursor)
+// Result of string search in the page.
+// Response to ViewMsg_Find with the results of the requested find-in-page
+// search, the number of matches found and the selection rect (in screen
+// coordinates) for the string found. If |final_update| is false, it signals
+// that this is not the last Find_Reply message - more will be sent as the
+// scoping effort continues.
+IPC_MESSAGE_ROUTED5(ViewHostMsg_Find_Reply,
+ int /* request_id */,
+ int /* number of matches */,
+ gfx::Rect /* selection_rect */,
+ int /* active_match_ordinal */,
+ bool /* final_update */)
+
+// Makes a resource request via the browser.
+IPC_MESSAGE_ROUTED2(ViewHostMsg_RequestResource,
+ int /* request_id */,
+ ViewHostMsg_Resource_Request)
+
+// Cancels a resource request with the ID given as the parameter.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_CancelRequest,
+ int /* request_id */)
+
+// Follows a redirect that occured for the resource request with the ID given
+// as the parameter.
+IPC_MESSAGE_ROUTED3(ViewHostMsg_FollowRedirect,
+ int /* request_id */,
+ bool /* has_new_first_party_for_cookies */,
+ GURL /* new_first_party_for_cookies */)
+
+// Makes a synchronous resource request via the browser.
+IPC_SYNC_MESSAGE_ROUTED2_1(ViewHostMsg_SyncLoad,
+ int /* request_id */,
+ ViewHostMsg_Resource_Request,
+ SyncLoadResult)
+
+// Used to set a cookie. The cookie is set asynchronously, but will be
+// available to a subsequent ViewHostMsg_GetCookies request.
+IPC_MESSAGE_ROUTED3(ViewHostMsg_SetCookie,
+ GURL /* url */,
+ GURL /* first_party_for_cookies */,
+ std::string /* cookie */)
+
+// Used to get cookies for the given URL. This may block waiting for a
+// previous SetCookie message to be processed.
+IPC_SYNC_MESSAGE_ROUTED2_1(ViewHostMsg_GetCookies,
+ GURL /* url */,
+ GURL /* first_party_for_cookies */,
+ std::string /* cookies */)
+
+// Used to get raw cookie information for the given URL. This may block
+// waiting for a previous SetCookie message to be processed.
+IPC_SYNC_MESSAGE_ROUTED2_1(ViewHostMsg_GetRawCookies,
+ GURL /* url */,
+ GURL /* first_party_for_cookies */,
+ std::vector<webkit_glue::WebCookie>
+ /* raw_cookies */)
+
+// Used to delete cookie for the given URL and name
+IPC_SYNC_MESSAGE_CONTROL2_0(ViewHostMsg_DeleteCookie,
+ GURL /* url */,
+ std::string /* cookie_name */)
+
+// Used to check if cookies are enabled for the given URL. This may block
+// waiting for a previous SetCookie message to be processed.
+IPC_SYNC_MESSAGE_ROUTED2_1(ViewHostMsg_CookiesEnabled,
+ GURL /* url */,
+ GURL /* first_party_for_cookies */,
+ bool /* cookies_enabled */)
+
+// Used to get the list of plugins
+IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_GetPlugins,
+ bool /* refresh*/,
+ std::vector<webkit::npapi::WebPluginInfo> /* plugins */)
+
+// Return information about a plugin for the given URL and MIME
+// type. If there is no matching plugin, |found| is false. If
+// |enabled| in the WebPluginInfo struct is false, the plug-in is
+// treated as if it was not installed at all.
+//
+// If |setting| is set to CONTENT_SETTING_BLOCK, the plug-in is
+// blocked by the content settings for |policy_url|. It still
+// appears in navigator.plugins in Javascript though, and can be
+// loaded via click-to-play.
+//
+// If |setting| is set to CONTENT_SETTING_ALLOW, the domain is
+// explicitly white-listed for the plug-in, or the user has chosen
+// not to block nonsandboxed plugins.
+//
+// If |setting| is set to CONTENT_SETTING_DEFAULT, the plug-in is
+// neither blocked nor white-listed, which means that it's allowed
+// by default and can still be blocked if it's non-sandboxed.
+//
+// |actual_mime_type| is the actual mime type supported by the
+// plugin found that match the URL given (one for each item in
+// |info|).
+IPC_SYNC_MESSAGE_CONTROL3_4(ViewHostMsg_GetPluginInfo,
+ GURL /* url */,
+ GURL /* policy_url */,
+ std::string /* mime_type */,
+ bool /* found */,
+ webkit::npapi::WebPluginInfo /* plugin info */,
+ ContentSetting /* setting */,
+ std::string /* actual_mime_type */)
+
+// Requests spellcheck for a word.
+IPC_SYNC_MESSAGE_ROUTED2_2(ViewHostMsg_SpellCheck,
+ string16 /* word to check */,
+ int /* document tag*/,
+ int /* misspell location */,
+ int /* misspell length */)
+
+// Asks the browser for a unique document tag.
+IPC_SYNC_MESSAGE_ROUTED0_1(ViewHostMsg_GetDocumentTag,
+ int /* the tag */)
+
+
+// This message tells the spellchecker that a document, identified by an int
+// tag, has been closed and all of the ignored words for that document can be
+// forgotten.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_DocumentWithTagClosed,
+ int /* the tag */)
+
+// Tells the browser to display or not display the SpellingPanel
+IPC_MESSAGE_ROUTED1(ViewHostMsg_ShowSpellingPanel,
+ bool /* if true, then show it, otherwise hide it*/)
+
+// Tells the browser to update the spelling panel with the given word.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_UpdateSpellingPanelWithMisspelledWord,
+ string16 /* the word to update the panel with */)
+
+// Tells the browser that content in the current page was blocked due to the
+// user's content settings.
+IPC_MESSAGE_ROUTED2(ViewHostMsg_ContentBlocked,
+ ContentSettingsType, /* type of blocked content */
+ std::string /* resource identifier */)
+
+// Tells the browser that a specific Appcache manifest in the current page
+// was accessed.
+IPC_MESSAGE_ROUTED2(ViewHostMsg_AppCacheAccessed,
+ GURL /* manifest url */,
+ bool /* blocked by policy */)
+
+// Tells the browser that a specific Web database in the current page was
+// accessed.
+IPC_MESSAGE_ROUTED5(ViewHostMsg_WebDatabaseAccessed,
+ GURL /* origin url */,
+ string16 /* database name */,
+ string16 /* database display name */,
+ unsigned long /* estimated size */,
+ bool /* blocked by policy */)
+
+// Initiates a download based on user actions like 'ALT+click'.
+IPC_MESSAGE_ROUTED2(ViewHostMsg_DownloadUrl,
+ GURL /* url */,
+ GURL /* referrer */)
+
+// Used to go to the session history entry at the given offset (ie, -1 will
+// return the "back" item).
+IPC_MESSAGE_ROUTED1(ViewHostMsg_GoToEntryAtOffset,
+ int /* offset (from current) of history item to get */)
+
+IPC_SYNC_MESSAGE_ROUTED4_2(ViewHostMsg_RunJavaScriptMessage,
+ std::wstring /* in - alert message */,
+ std::wstring /* in - default prompt */,
+ GURL /* in - originating page URL */,
+ int /* in - dialog flags */,
+ bool /* out - success */,
+ std::wstring /* out - prompt field */)
+
+// Provides the contents for the given page that was loaded recently.
+IPC_MESSAGE_ROUTED5(ViewHostMsg_PageContents,
+ GURL /* URL of the page */,
+ int32 /* page id */,
+ string16 /* page contents */,
+ std::string /* page ISO639_1 language code */,
+ bool /* whether the page can be translated */)
+
+// Used to get the extension message bundle.
+IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_GetExtensionMessageBundle,
+ std::string /* extension id */,
+ SubstitutionMap /* message bundle */)
+
+// Specifies the URL as the first parameter (a wstring) and thumbnail as
+// binary data as the second parameter.
+IPC_MESSAGE_ROUTED3(ViewHostMsg_Thumbnail,
+ GURL /* url */,
+ ThumbnailScore /* score */,
+ SkBitmap /* bitmap */)
+
+// Send a snapshot of the tab contents to the render host.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_Snapshot,
+ SkBitmap /* bitmap */)
+
+// Notification that the url for the favicon of a site has been determined.
+IPC_MESSAGE_ROUTED2(ViewHostMsg_UpdateFavIconURL,
+ int32 /* page_id */,
+ GURL /* url of the favicon */)
+
+// Used to tell the parent that the user right clicked on an area of the
+// content area, and a context menu should be shown for it. The params
+// object contains information about the node(s) that were selected when the
+// user right clicked.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_ContextMenu, ContextMenuParams)
+
+// Requests that the given URL be opened in the specified manner.
+IPC_MESSAGE_ROUTED3(ViewHostMsg_OpenURL,
+ GURL /* url */,
+ GURL /* referrer */,
+ WindowOpenDisposition /* disposition */)
+
+// Notifies that the preferred size of the content changed.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_DidContentsPreferredSizeChange,
+ gfx::Size /* pref_size */)
+
+// Following message is used to communicate the values received by the
+// callback binding the JS to Cpp.
+// An instance of browser that has an automation host listening to it can
+// have a javascript send a native value (string, number, boolean) to the
+// listener in Cpp. (DomAutomationController)
+IPC_MESSAGE_ROUTED2(ViewHostMsg_DomOperationResponse,
+ std::string /* json_string */,
+ int /* automation_id */)
+
+// A message from HTML-based UI. When (trusted) Javascript calls
+// send(message, args), this message is sent to the browser.
+IPC_MESSAGE_ROUTED3(ViewHostMsg_DOMUISend,
+ GURL /* source_url */,
+ std::string /* message */,
+ std::string /* args (as a JSON string) */)
+
+// A message for an external host.
+IPC_MESSAGE_ROUTED3(ViewHostMsg_ForwardMessageToExternalHost,
+ std::string /* message */,
+ std::string /* origin */,
+ std::string /* target */)
+
+// A renderer sends this to the browser process when it wants to
+// create a plugin. The browser will create the plugin process if
+// necessary, and will return a handle to the channel on success.
+// On error an empty string is returned.
+IPC_SYNC_MESSAGE_CONTROL2_2(ViewHostMsg_OpenChannelToPlugin,
+ GURL /* url */,
+ std::string /* mime_type */,
+ IPC::ChannelHandle /* channel_handle */,
+ webkit::npapi::WebPluginInfo /* info */)
+
+// A renderer sends this to the browser process when it wants to
+// create a pepper plugin. The browser will create the plugin process if
+// necessary, and will return a handle to the channel on success.
+// On error an empty string is returned.
+IPC_SYNC_MESSAGE_CONTROL1_2(ViewHostMsg_OpenChannelToPepperPlugin,
+ FilePath /* path */,
+ base::ProcessHandle /* plugin_process_handle */,
+ IPC::ChannelHandle /* handle to channel */)
+
+// A renderer sends this to the browser process when it wants to
+// create connect to the GPU. The browser will create the GPU process if
+// necessary, and will return a handle to the channel via
+// a GpuChannelEstablished message.
+IPC_MESSAGE_CONTROL0(ViewHostMsg_EstablishGpuChannel)
+
+// A renderer sends this to the browser process to provide a synchronization
+// point for GPU operations, in particular to make sure the GPU channel has
+// been established.
+IPC_SYNC_MESSAGE_CONTROL0_0(ViewHostMsg_SynchronizeGpu)
+
+// A renderer sends this to the browser process when it wants to start
+// a new instance of the Native Client process. The browser will launch
+// the process and return a handle to an IMC channel.
+IPC_SYNC_MESSAGE_CONTROL2_3(ViewHostMsg_LaunchNaCl,
+ std::wstring /* url for the NaCl module */,
+ int /* socket count */,
+ std::vector<nacl::FileDescriptor>
+ /* imc channel handles */,
+ base::ProcessHandle /* NaCl process handle */,
+ base::ProcessId /* NaCl process id */)
#if defined(USE_X11)
- // A renderer sends this when it needs a browser-side widget for
- // hosting a windowed plugin. id is the XID of the plugin window, for which
- // the container is created.
- IPC_SYNC_MESSAGE_ROUTED1_0(ViewHostMsg_CreatePluginContainer,
- gfx::PluginWindowHandle /* id */)
-
- // Destroy a plugin container previously created using CreatePluginContainer.
- // id is the XID of the plugin window corresponding to the container that is
- // to be destroyed.
- IPC_SYNC_MESSAGE_ROUTED1_0(ViewHostMsg_DestroyPluginContainer,
- gfx::PluginWindowHandle /* id */)
+// A renderer sends this when it needs a browser-side widget for
+// hosting a windowed plugin. id is the XID of the plugin window, for which
+// the container is created.
+IPC_SYNC_MESSAGE_ROUTED1_0(ViewHostMsg_CreatePluginContainer,
+ gfx::PluginWindowHandle /* id */)
+
+// Destroy a plugin container previously created using CreatePluginContainer.
+// id is the XID of the plugin window corresponding to the container that is
+// to be destroyed.
+IPC_SYNC_MESSAGE_ROUTED1_0(ViewHostMsg_DestroyPluginContainer,
+ gfx::PluginWindowHandle /* id */)
#endif
- // Clipboard IPC messages
-
- // This message is used when the object list does not contain a bitmap.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_ClipboardWriteObjectsAsync,
- Clipboard::ObjectMap /* objects */)
- // This message is used when the object list contains a bitmap.
- // It is synchronized so that the renderer knows when it is safe to
- // free the shared memory used to transfer the bitmap.
- IPC_SYNC_MESSAGE_CONTROL2_0(ViewHostMsg_ClipboardWriteObjectsSync,
- Clipboard::ObjectMap /* objects */,
- base::SharedMemoryHandle /* bitmap handle */)
- IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_ClipboardIsFormatAvailable,
- std::string /* format */,
- Clipboard::Buffer /* buffer */,
- bool /* result */)
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_ClipboardReadText,
- Clipboard::Buffer /* buffer */,
- string16 /* result */)
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_ClipboardReadAsciiText,
- Clipboard::Buffer /* buffer */,
- std::string /* result */)
- IPC_SYNC_MESSAGE_CONTROL1_2(ViewHostMsg_ClipboardReadHTML,
- Clipboard::Buffer /* buffer */,
- string16 /* markup */,
- GURL /* url */)
-
- IPC_SYNC_MESSAGE_CONTROL1_3(ViewHostMsg_ClipboardReadAvailableTypes,
- Clipboard::Buffer /* buffer */,
- bool /* result */,
- std::vector<string16> /* types */,
- bool /* contains filenames */)
- IPC_SYNC_MESSAGE_CONTROL2_3(ViewHostMsg_ClipboardReadData,
- Clipboard::Buffer /* buffer */,
- string16 /* type */,
- bool /* succeeded */,
- string16 /* data */,
- string16 /* metadata */)
- IPC_SYNC_MESSAGE_CONTROL1_2(ViewHostMsg_ClipboardReadFilenames,
- Clipboard::Buffer /* buffer */,
- bool /* result */,
- std::vector<string16> /* filenames */)
+// Clipboard IPC messages
+
+// This message is used when the object list does not contain a bitmap.
+IPC_MESSAGE_CONTROL1(ViewHostMsg_ClipboardWriteObjectsAsync,
+ Clipboard::ObjectMap /* objects */)
+// This message is used when the object list contains a bitmap.
+// It is synchronized so that the renderer knows when it is safe to
+// free the shared memory used to transfer the bitmap.
+IPC_SYNC_MESSAGE_CONTROL2_0(ViewHostMsg_ClipboardWriteObjectsSync,
+ Clipboard::ObjectMap /* objects */,
+ base::SharedMemoryHandle /* bitmap handle */)
+IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_ClipboardIsFormatAvailable,
+ std::string /* format */,
+ Clipboard::Buffer /* buffer */,
+ bool /* result */)
+IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_ClipboardReadText,
+ Clipboard::Buffer /* buffer */,
+ string16 /* result */)
+IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_ClipboardReadAsciiText,
+ Clipboard::Buffer /* buffer */,
+ std::string /* result */)
+IPC_SYNC_MESSAGE_CONTROL1_2(ViewHostMsg_ClipboardReadHTML,
+ Clipboard::Buffer /* buffer */,
+ string16 /* markup */,
+ GURL /* url */)
+
+IPC_SYNC_MESSAGE_CONTROL1_3(ViewHostMsg_ClipboardReadAvailableTypes,
+ Clipboard::Buffer /* buffer */,
+ bool /* result */,
+ std::vector<string16> /* types */,
+ bool /* contains filenames */)
+IPC_SYNC_MESSAGE_CONTROL2_3(ViewHostMsg_ClipboardReadData,
+ Clipboard::Buffer /* buffer */,
+ string16 /* type */,
+ bool /* succeeded */,
+ string16 /* data */,
+ string16 /* metadata */)
+IPC_SYNC_MESSAGE_CONTROL1_2(ViewHostMsg_ClipboardReadFilenames,
+ Clipboard::Buffer /* buffer */,
+ bool /* result */,
+ std::vector<string16> /* filenames */)
#if defined(OS_MACOSX)
- IPC_MESSAGE_CONTROL1(ViewHostMsg_ClipboardFindPboardWriteStringAsync,
- string16 /* text */)
-
- // Request that the browser load a font into shared memory for us.
- IPC_SYNC_MESSAGE_CONTROL1_2(ViewHostMsg_LoadFont,
- FontDescriptor /* font to load */,
- uint32 /* buffer size */,
- base::SharedMemoryHandle /* font data */)
+IPC_MESSAGE_CONTROL1(ViewHostMsg_ClipboardFindPboardWriteStringAsync,
+ string16 /* text */)
+
+// Request that the browser load a font into shared memory for us.
+IPC_SYNC_MESSAGE_CONTROL1_2(ViewHostMsg_LoadFont,
+ FontDescriptor /* font to load */,
+ uint32 /* buffer size */,
+ base::SharedMemoryHandle /* font data */)
#endif
#if defined(OS_WIN)
- // Request that the given font be loaded by the browser so it's cached by the
- // OS. Please see ChildProcessHost::PreCacheFont for details.
- IPC_SYNC_MESSAGE_CONTROL1_0(ViewHostMsg_PreCacheFont,
- LOGFONT /* font data */)
+// Request that the given font be loaded by the browser so it's cached by the
+// OS. Please see ChildProcessHost::PreCacheFont for details.
+IPC_SYNC_MESSAGE_CONTROL1_0(ViewHostMsg_PreCacheFont,
+ LOGFONT /* font data */)
#endif // defined(OS_WIN)
- // Returns WebScreenInfo corresponding to the view.
- // TODO(shess): Provide a mapping from reply_msg->routing_id() to
- // HWND so that we can eliminate the NativeViewId parameter.
- IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_GetScreenInfo,
- gfx::NativeViewId /* view */,
- WebKit::WebScreenInfo /* results */)
-
- // Send the tooltip text for the current mouse position to the browser.
- IPC_MESSAGE_ROUTED2(ViewHostMsg_SetTooltipText,
- std::wstring /* tooltip text string */,
- WebKit::WebTextDirection /* text direction hint */)
-
- // Notification that the text selection has changed.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_SelectionChanged,
- std::string /* currently selected text */)
-
- // Asks the browser to display the file chooser. The result is returned in a
- // ViewHost_RunFileChooserResponse message.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_RunFileChooser,
- ViewHostMsg_RunFileChooser_Params)
-
- // Notification that forms have been seen that are candidates for
- // filling/submitting by the AutoFillManager.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_FormsSeen,
- std::vector<webkit_glue::FormData> /* forms */)
-
- // Notification that password forms have been seen that are candidates for
- // filling/submitting by the password manager.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_PasswordFormsFound,
- std::vector<webkit_glue::PasswordForm> /* forms */)
-
- // Notification that initial layout has occurred and the following password
- // forms are visible on the page (e.g. not set to display:none.)
- IPC_MESSAGE_ROUTED1(ViewHostMsg_PasswordFormsVisible,
- std::vector<webkit_glue::PasswordForm> /* forms */)
-
- // Notification that a form has been submitted. The user hit the button.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_FormSubmitted,
- webkit_glue::FormData /* form */)
-
- // Used to tell the parent the user started dragging in the content area. The
- // WebDropData struct contains contextual information about the pieces of the
- // page the user dragged. The parent uses this notification to initiate a
- // drag session at the OS level.
- IPC_MESSAGE_ROUTED4(ViewHostMsg_StartDragging,
- WebDropData /* drop_data */,
- WebKit::WebDragOperationsMask /* ops_allowed */,
- SkBitmap /* image */,
- gfx::Point /* image_offset */)
-
- // The page wants to update the mouse cursor during a drag & drop operation.
- // |is_drop_target| is true if the mouse is over a valid drop target.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_UpdateDragCursor,
- WebKit::WebDragOperation /* drag_operation */)
-
- // Tells the browser to move the focus to the next (previous if reverse is
- // true) focusable element.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_TakeFocus, bool /* reverse */)
-
- // Notification that the page has an OpenSearch description document
- // associated with it.
- IPC_MESSAGE_ROUTED3(ViewHostMsg_PageHasOSDD,
- int32 /* page_id */,
- GURL /* url of OS description document */,
- ViewHostMsg_PageHasOSDD_Type)
-
- // Find out if the given url's security origin is installed as a search
- // provider.
- IPC_SYNC_MESSAGE_ROUTED2_1(
- ViewHostMsg_GetSearchProviderInstallState,
- GURL /* page url */,
- GURL /* inquiry url */,
- ViewHostMsg_GetSearchProviderInstallState_Params /* install */)
-
- // Required for updating text input state.
- IPC_MESSAGE_ROUTED2(ViewHostMsg_ImeUpdateTextInputState,
- WebKit::WebTextInputType, /* text_input_type */
- gfx::Rect /* caret_rect */)
-
- // Required for cancelling an ongoing input method composition.
- IPC_MESSAGE_ROUTED0(ViewHostMsg_ImeCancelComposition)
-
- // Tells the browser that the renderer is done calculating the number of
- // rendered pages according to the specified settings.
- IPC_MESSAGE_ROUTED2(ViewHostMsg_DidGetPrintedPagesCount,
- int /* rendered document cookie */,
- int /* number of rendered pages */)
-
- // Sends back to the browser the rendered "printed page" that was requested by
- // a ViewMsg_PrintPage message or from scripted printing. The memory handle in
- // this message is already valid in the browser process.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_DidPrintPage,
- ViewHostMsg_DidPrintPage_Params /* page content */)
-
- // The renderer wants to know the default print settings.
- IPC_SYNC_MESSAGE_ROUTED0_1(ViewHostMsg_GetDefaultPrintSettings,
- ViewMsg_Print_Params /* default_settings */)
-
- // It's the renderer that controls the printing process when it is generated
- // by javascript. This step is about showing UI to the user to select the
- // final print settings. The output parameter is the same as
- // ViewMsg_PrintPages which is executed implicitly.
- IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_ScriptedPrint,
- ViewHostMsg_ScriptedPrint_Params,
- ViewMsg_PrintPages_Params
- /* settings chosen by the user*/)
-
- // WebKit and JavaScript error messages to log to the console
- // or debugger UI.
- IPC_MESSAGE_ROUTED3(ViewHostMsg_AddMessageToConsole,
- std::wstring, /* msg */
- int32, /* line number */
- std::wstring /* source id */)
-
- // Stores new inspector setting in the profile.
- IPC_MESSAGE_ROUTED2(ViewHostMsg_UpdateInspectorSetting,
- std::string, /* key */
- std::string /* value */)
-
- // Wraps an IPC message that's destined to the DevToolsClient on
- // DevToolsAgent->browser hop.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_ForwardToDevToolsClient,
- IPC::Message /* one of DevToolsClientMsg_XXX types */)
-
- // Wraps an IPC message that's destined to the DevToolsAgent on
- // DevToolsClient->browser hop.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_ForwardToDevToolsAgent,
- IPC::Message /* one of DevToolsAgentMsg_XXX types */)
-
- // Activates (brings to the front) corresponding dev tools window.
- IPC_MESSAGE_ROUTED0(ViewHostMsg_ActivateDevToolsWindow)
-
- // Closes dev tools window that is inspecting current render_view_host.
- IPC_MESSAGE_ROUTED0(ViewHostMsg_CloseDevToolsWindow)
-
- // Attaches dev tools window that is inspecting current render_view_host.
- IPC_MESSAGE_ROUTED0(ViewHostMsg_RequestDockDevToolsWindow)
-
- // Detaches dev tools window that is inspecting current render_view_host.
- IPC_MESSAGE_ROUTED0(ViewHostMsg_RequestUndockDevToolsWindow)
-
- // Updates runtime features store in devtools manager in order to support
- // cross-navigation instrumentation.
- IPC_MESSAGE_ROUTED2(ViewHostMsg_DevToolsRuntimePropertyChanged,
- std::string /* name */,
- std::string /* value */)
-
- // Send back a string to be recorded by UserMetrics.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_UserMetricsRecordAction,
- std::string /* action */)
-
- // Send back histograms as vector of pickled-histogram strings.
- IPC_MESSAGE_CONTROL2(ViewHostMsg_RendererHistograms,
- int, /* sequence number of Renderer Histograms. */
- std::vector<std::string>)
+// Returns WebScreenInfo corresponding to the view.
+// TODO(shess): Provide a mapping from reply_msg->routing_id() to
+// HWND so that we can eliminate the NativeViewId parameter.
+IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_GetScreenInfo,
+ gfx::NativeViewId /* view */,
+ WebKit::WebScreenInfo /* results */)
+
+// Send the tooltip text for the current mouse position to the browser.
+IPC_MESSAGE_ROUTED2(ViewHostMsg_SetTooltipText,
+ std::wstring /* tooltip text string */,
+ WebKit::WebTextDirection /* text direction hint */)
+
+// Notification that the text selection has changed.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_SelectionChanged,
+ std::string /* currently selected text */)
+
+// Asks the browser to display the file chooser. The result is returned in a
+// ViewHost_RunFileChooserResponse message.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_RunFileChooser,
+ ViewHostMsg_RunFileChooser_Params)
+
+// Notification that forms have been seen that are candidates for
+// filling/submitting by the AutoFillManager.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_FormsSeen,
+ std::vector<webkit_glue::FormData> /* forms */)
+
+// Notification that password forms have been seen that are candidates for
+// filling/submitting by the password manager.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_PasswordFormsFound,
+ std::vector<webkit_glue::PasswordForm> /* forms */)
+
+// Notification that initial layout has occurred and the following password
+// forms are visible on the page (e.g. not set to display:none.)
+IPC_MESSAGE_ROUTED1(ViewHostMsg_PasswordFormsVisible,
+ std::vector<webkit_glue::PasswordForm> /* forms */)
+
+// Notification that a form has been submitted. The user hit the button.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_FormSubmitted,
+ webkit_glue::FormData /* form */)
+
+// Used to tell the parent the user started dragging in the content area. The
+// WebDropData struct contains contextual information about the pieces of the
+// page the user dragged. The parent uses this notification to initiate a
+// drag session at the OS level.
+IPC_MESSAGE_ROUTED4(ViewHostMsg_StartDragging,
+ WebDropData /* drop_data */,
+ WebKit::WebDragOperationsMask /* ops_allowed */,
+ SkBitmap /* image */,
+ gfx::Point /* image_offset */)
+
+// The page wants to update the mouse cursor during a drag & drop operation.
+// |is_drop_target| is true if the mouse is over a valid drop target.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_UpdateDragCursor,
+ WebKit::WebDragOperation /* drag_operation */)
+
+// Tells the browser to move the focus to the next (previous if reverse is
+// true) focusable element.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_TakeFocus, bool /* reverse */)
+
+// Notification that the page has an OpenSearch description document
+// associated with it.
+IPC_MESSAGE_ROUTED3(ViewHostMsg_PageHasOSDD,
+ int32 /* page_id */,
+ GURL /* url of OS description document */,
+ ViewHostMsg_PageHasOSDD_Type)
+
+// Find out if the given url's security origin is installed as a search
+// provider.
+IPC_SYNC_MESSAGE_ROUTED2_1(
+ ViewHostMsg_GetSearchProviderInstallState,
+ GURL /* page url */,
+ GURL /* inquiry url */,
+ ViewHostMsg_GetSearchProviderInstallState_Params /* install */)
+
+// Required for updating text input state.
+IPC_MESSAGE_ROUTED2(ViewHostMsg_ImeUpdateTextInputState,
+ WebKit::WebTextInputType, /* text_input_type */
+ gfx::Rect /* caret_rect */)
+
+// Required for cancelling an ongoing input method composition.
+IPC_MESSAGE_ROUTED0(ViewHostMsg_ImeCancelComposition)
+
+// Tells the browser that the renderer is done calculating the number of
+// rendered pages according to the specified settings.
+IPC_MESSAGE_ROUTED2(ViewHostMsg_DidGetPrintedPagesCount,
+ int /* rendered document cookie */,
+ int /* number of rendered pages */)
+
+// Sends back to the browser the rendered "printed page" that was requested by
+// a ViewMsg_PrintPage message or from scripted printing. The memory handle in
+// this message is already valid in the browser process.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_DidPrintPage,
+ ViewHostMsg_DidPrintPage_Params /* page content */)
+
+// The renderer wants to know the default print settings.
+IPC_SYNC_MESSAGE_ROUTED0_1(ViewHostMsg_GetDefaultPrintSettings,
+ ViewMsg_Print_Params /* default_settings */)
+
+// It's the renderer that controls the printing process when it is generated
+// by javascript. This step is about showing UI to the user to select the
+// final print settings. The output parameter is the same as
+// ViewMsg_PrintPages which is executed implicitly.
+IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_ScriptedPrint,
+ ViewHostMsg_ScriptedPrint_Params,
+ ViewMsg_PrintPages_Params
+ /* settings chosen by the user*/)
+
+// WebKit and JavaScript error messages to log to the console
+// or debugger UI.
+IPC_MESSAGE_ROUTED3(ViewHostMsg_AddMessageToConsole,
+ std::wstring, /* msg */
+ int32, /* line number */
+ std::wstring /* source id */)
+
+// Stores new inspector setting in the profile.
+IPC_MESSAGE_ROUTED2(ViewHostMsg_UpdateInspectorSetting,
+ std::string, /* key */
+ std::string /* value */)
+
+// Wraps an IPC message that's destined to the DevToolsClient on
+// DevToolsAgent->browser hop.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_ForwardToDevToolsClient,
+ IPC::Message /* one of DevToolsClientMsg_XXX types */)
+
+// Wraps an IPC message that's destined to the DevToolsAgent on
+// DevToolsClient->browser hop.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_ForwardToDevToolsAgent,
+ IPC::Message /* one of DevToolsAgentMsg_XXX types */)
+
+// Activates (brings to the front) corresponding dev tools window.
+IPC_MESSAGE_ROUTED0(ViewHostMsg_ActivateDevToolsWindow)
+
+// Closes dev tools window that is inspecting current render_view_host.
+IPC_MESSAGE_ROUTED0(ViewHostMsg_CloseDevToolsWindow)
+
+// Attaches dev tools window that is inspecting current render_view_host.
+IPC_MESSAGE_ROUTED0(ViewHostMsg_RequestDockDevToolsWindow)
+
+// Detaches dev tools window that is inspecting current render_view_host.
+IPC_MESSAGE_ROUTED0(ViewHostMsg_RequestUndockDevToolsWindow)
+
+// Updates runtime features store in devtools manager in order to support
+// cross-navigation instrumentation.
+IPC_MESSAGE_ROUTED2(ViewHostMsg_DevToolsRuntimePropertyChanged,
+ std::string /* name */,
+ std::string /* value */)
+
+// Send back a string to be recorded by UserMetrics.
+IPC_MESSAGE_CONTROL1(ViewHostMsg_UserMetricsRecordAction,
+ std::string /* action */)
+
+// Send back histograms as vector of pickled-histogram strings.
+IPC_MESSAGE_CONTROL2(ViewHostMsg_RendererHistograms,
+ int, /* sequence number of Renderer Histograms. */
+ std::vector<std::string>)
#if defined USE_TCMALLOC
- // Send back tcmalloc stats output.
- IPC_MESSAGE_CONTROL2(ViewHostMsg_RendererTcmalloc,
- int /* pid */,
- std::string /* tcmalloc debug output */)
+// Send back tcmalloc stats output.
+IPC_MESSAGE_CONTROL2(ViewHostMsg_RendererTcmalloc,
+ int /* pid */,
+ std::string /* tcmalloc debug output */)
#endif
- // Sends back stats about the V8 heap.
- IPC_MESSAGE_CONTROL2(ViewHostMsg_V8HeapStats,
- int /* size of heap (allocated from the OS) */,
- int /* bytes in use */)
-
- // Request for a DNS prefetch of the names in the array.
- // NameList is typedef'ed std::vector<std::string>
- IPC_MESSAGE_CONTROL1(ViewHostMsg_DnsPrefetch,
- std::vector<std::string> /* hostnames */)
-
- // Notifies when default plugin updates status of the missing plugin.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_MissingPluginStatus,
- int /* status */)
-
- // Sent by the renderer process to indicate that a plugin instance has
- // crashed.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_CrashedPlugin,
- FilePath /* plugin_path */)
-
- // Notifies when a plugin couldn't be loaded because it's outdated.
- IPC_MESSAGE_ROUTED2(ViewHostMsg_DisabledOutdatedPlugin,
- string16, /* name */
- GURL /* update_url */)
-
- // Displays a JavaScript out-of-memory message in the infobar.
- IPC_MESSAGE_ROUTED0(ViewHostMsg_JSOutOfMemory)
-
- // Displays a box to confirm that the user wants to navigate away from the
- // page. Replies true if yes, false otherwise, the reply string is ignored,
- // but is included so that we can use OnJavaScriptMessageBoxClosed.
- IPC_SYNC_MESSAGE_ROUTED2_2(ViewHostMsg_RunBeforeUnloadConfirm,
- GURL, /* in - originating frame URL */
- std::wstring /* in - alert message */,
- bool /* out - success */,
- std::wstring /* out - This is ignored.*/)
-
- IPC_MESSAGE_ROUTED3(ViewHostMsg_SendCurrentPageAllSavableResourceLinks,
- std::vector<GURL> /* all savable resource links */,
- std::vector<GURL> /* all referrers of resource links */,
- std::vector<GURL> /* all frame links */)
-
- IPC_MESSAGE_ROUTED3(ViewHostMsg_SendSerializedHtmlData,
- GURL /* frame's url */,
- std::string /* data buffer */,
- int32 /* complete status */)
-
- IPC_SYNC_MESSAGE_ROUTED4_1(ViewHostMsg_ShowModalHTMLDialog,
- GURL /* url */,
- int /* width */,
- int /* height */,
- std::string /* json_arguments */,
- std::string /* json_retval */)
-
- IPC_MESSAGE_ROUTED2(ViewHostMsg_DidGetApplicationInfo,
- int32 /* page_id */,
- WebApplicationInfo)
-
- // Sent by the renderer to implement chrome.app.installApplication().
- IPC_MESSAGE_ROUTED1(ViewHostMsg_InstallApplication,
- WebApplicationInfo)
-
- // Provides the result from running OnMsgShouldClose. |proceed| matches the
- // return value of the the frame's shouldClose method (which includes the
- // onbeforeunload handler): true if the user decided to proceed with leaving
- // the page.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_ShouldClose_ACK,
- bool /* proceed */)
-
- // Indicates that the current page has been closed, after a ClosePage
- // message. The parameters are just echoed from the ClosePage request.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_ClosePage_ACK,
- ViewMsg_ClosePage_Params)
-
- IPC_MESSAGE_ROUTED4(ViewHostMsg_DidDownloadFavIcon,
- int /* Identifier of the request */,
- GURL /* URL of the image */,
- bool /* true if there was a network error */,
- SkBitmap /* image_data */)
-
- // Sent to query MIME information.
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_GetMimeTypeFromExtension,
- FilePath::StringType /* extension */,
- std::string /* mime_type */)
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_GetMimeTypeFromFile,
- FilePath /* file_path */,
- std::string /* mime_type */)
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_GetPreferredExtensionForMimeType,
- std::string /* mime_type */,
- FilePath::StringType /* extension */)
-
- // Get the CPBrowsingContext associated with the renderer sending this
- // message.
- IPC_SYNC_MESSAGE_CONTROL0_1(ViewHostMsg_GetCPBrowsingContext,
- uint32 /* context */)
-
- // Sent when the renderer process is done processing a DataReceived
- // message.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_DataReceived_ACK,
- int /* request_id */)
-
- IPC_MESSAGE_CONTROL1(ViewHostMsg_RevealFolderInOS,
- FilePath /* path */)
-
- // Sent when the renderer has processed a DataDownloaded message.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_DataDownloaded_ACK,
- int /* request_id */)
-
- // Sent when the renderer process deletes a resource loader.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_ReleaseDownloadedFile,
- int /* request_id */)
-
- // Sent when a provisional load on the main frame redirects.
- IPC_MESSAGE_ROUTED3(ViewHostMsg_DidRedirectProvisionalLoad,
- int /* page_id */,
- GURL /* last url */,
- GURL /* url redirected to */)
-
- // Sent by the renderer process to acknowledge receipt of a
- // UploadProgress message.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_UploadProgress_ACK,
- int /* request_id */)
-
- // Sent when the renderer changes the zoom level for a particular url, so the
- // browser can update its records. If remember is true, then url is used to
- // update the zoom level for all pages in that site. Otherwise, the render
- // view's id is used so that only the menu is updated.
- IPC_MESSAGE_ROUTED3(ViewHostMsg_DidZoomURL,
- double /* zoom_level */,
- bool /* remember */,
- GURL /* url */)
+// Sends back stats about the V8 heap.
+IPC_MESSAGE_CONTROL2(ViewHostMsg_V8HeapStats,
+ int /* size of heap (allocated from the OS) */,
+ int /* bytes in use */)
+
+// Request for a DNS prefetch of the names in the array.
+// NameList is typedef'ed std::vector<std::string>
+IPC_MESSAGE_CONTROL1(ViewHostMsg_DnsPrefetch,
+ std::vector<std::string> /* hostnames */)
+
+// Notifies when default plugin updates status of the missing plugin.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_MissingPluginStatus,
+ int /* status */)
+
+// Sent by the renderer process to indicate that a plugin instance has
+// crashed.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_CrashedPlugin,
+ FilePath /* plugin_path */)
+
+// Notifies when a plugin couldn't be loaded because it's outdated.
+IPC_MESSAGE_ROUTED2(ViewHostMsg_BlockedOutdatedPlugin,
+ string16, /* name */
+ GURL /* update_url */)
+
+// Displays a JavaScript out-of-memory message in the infobar.
+IPC_MESSAGE_ROUTED0(ViewHostMsg_JSOutOfMemory)
+
+// Displays a box to confirm that the user wants to navigate away from the
+// page. Replies true if yes, false otherwise, the reply string is ignored,
+// but is included so that we can use OnJavaScriptMessageBoxClosed.
+IPC_SYNC_MESSAGE_ROUTED2_2(ViewHostMsg_RunBeforeUnloadConfirm,
+ GURL, /* in - originating frame URL */
+ std::wstring /* in - alert message */,
+ bool /* out - success */,
+ std::wstring /* out - This is ignored.*/)
+
+IPC_MESSAGE_ROUTED3(ViewHostMsg_SendCurrentPageAllSavableResourceLinks,
+ std::vector<GURL> /* all savable resource links */,
+ std::vector<GURL> /* all referrers of resource links */,
+ std::vector<GURL> /* all frame links */)
+
+IPC_MESSAGE_ROUTED3(ViewHostMsg_SendSerializedHtmlData,
+ GURL /* frame's url */,
+ std::string /* data buffer */,
+ int32 /* complete status */)
+
+IPC_SYNC_MESSAGE_ROUTED4_1(ViewHostMsg_ShowModalHTMLDialog,
+ GURL /* url */,
+ int /* width */,
+ int /* height */,
+ std::string /* json_arguments */,
+ std::string /* json_retval */)
+
+IPC_MESSAGE_ROUTED2(ViewHostMsg_DidGetApplicationInfo,
+ int32 /* page_id */,
+ WebApplicationInfo)
+
+// Sent by the renderer to implement chrome.app.installApplication().
+IPC_MESSAGE_ROUTED1(ViewHostMsg_InstallApplication,
+ WebApplicationInfo)
+
+// Provides the result from running OnMsgShouldClose. |proceed| matches the
+// return value of the the frame's shouldClose method (which includes the
+// onbeforeunload handler): true if the user decided to proceed with leaving
+// the page.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_ShouldClose_ACK,
+ bool /* proceed */)
+
+// Indicates that the current page has been closed, after a ClosePage
+// message. The parameters are just echoed from the ClosePage request.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_ClosePage_ACK,
+ ViewMsg_ClosePage_Params)
+
+IPC_MESSAGE_ROUTED4(ViewHostMsg_DidDownloadFavIcon,
+ int /* Identifier of the request */,
+ GURL /* URL of the image */,
+ bool /* true if there was a network error */,
+ SkBitmap /* image_data */)
+
+// Get the CPBrowsingContext associated with the renderer sending this
+// message.
+IPC_SYNC_MESSAGE_CONTROL0_1(ViewHostMsg_GetCPBrowsingContext,
+ uint32 /* context */)
+
+// Sent when the renderer process is done processing a DataReceived
+// message.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_DataReceived_ACK,
+ int /* request_id */)
+
+IPC_MESSAGE_CONTROL1(ViewHostMsg_RevealFolderInOS,
+ FilePath /* path */)
+
+// Sent when the renderer has processed a DataDownloaded message.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_DataDownloaded_ACK,
+ int /* request_id */)
+
+// Sent when the renderer process deletes a resource loader.
+IPC_MESSAGE_CONTROL1(ViewHostMsg_ReleaseDownloadedFile,
+ int /* request_id */)
+
+// Sent when a provisional load on the main frame redirects.
+IPC_MESSAGE_ROUTED3(ViewHostMsg_DidRedirectProvisionalLoad,
+ int /* page_id */,
+ GURL /* last url */,
+ GURL /* url redirected to */)
+
+// Sent by the renderer process to acknowledge receipt of a
+// UploadProgress message.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_UploadProgress_ACK,
+ int /* request_id */)
+
+// Sent when the renderer changes the zoom level for a particular url, so the
+// browser can update its records. If remember is true, then url is used to
+// update the zoom level for all pages in that site. Otherwise, the render
+// view's id is used so that only the menu is updated.
+IPC_MESSAGE_ROUTED3(ViewHostMsg_DidZoomURL,
+ double /* zoom_level */,
+ bool /* remember */,
+ GURL /* url */)
#if defined(OS_WIN)
- // Duplicates a shared memory handle from the renderer to the browser. Then
- // the renderer can flush the handle.
- IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_DuplicateSection,
- base::SharedMemoryHandle /* renderer handle */,
- base::SharedMemoryHandle /* browser handle */)
+// Duplicates a shared memory handle from the renderer to the browser. Then
+// the renderer can flush the handle.
+IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_DuplicateSection,
+ base::SharedMemoryHandle /* renderer handle */,
+ base::SharedMemoryHandle /* browser handle */)
#endif
#if defined(USE_X11)
- // Asks the browser to create a temporary file for the renderer to fill
- // in resulting NativeMetafile in printing.
- IPC_SYNC_MESSAGE_CONTROL0_2(ViewHostMsg_AllocateTempFileForPrinting,
- base::FileDescriptor /* temp file fd */,
- int /* fd in browser*/)
- IPC_MESSAGE_CONTROL1(ViewHostMsg_TempFileForPrintingWritten,
- int /* fd in browser */)
-#endif
-
-#if defined(OS_MACOSX)
- // Asks the browser to create a block of shared memory for the renderer to
- // pass NativeMetafile data to the browser.
- IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_AllocatePDFTransport,
- uint32 /* buffer size */,
- base::SharedMemoryHandle /* browser handle */)
+// Asks the browser to create a temporary file for the renderer to fill
+// in resulting NativeMetafile in printing.
+IPC_SYNC_MESSAGE_CONTROL0_2(ViewHostMsg_AllocateTempFileForPrinting,
+ base::FileDescriptor /* temp file fd */,
+ int /* fd in browser*/)
+IPC_MESSAGE_CONTROL1(ViewHostMsg_TempFileForPrintingWritten,
+ int /* fd in browser */)
#endif
#if defined(OS_POSIX)
- // Asks the browser to create a block of shared memory for the renderer to
- // fill in and pass back to the browser.
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_AllocateSharedMemoryBuffer,
- uint32 /* buffer size */,
- base::SharedMemoryHandle /* browser handle */)
+// Asks the browser to create a block of shared memory for the renderer to
+// fill in and pass back to the browser.
+IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_AllocateSharedMemoryBuffer,
+ uint32 /* buffer size */,
+ base::SharedMemoryHandle /* browser handle */)
#endif
- // Provide the browser process with information about the WebCore resource
- // cache.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_ResourceTypeStats,
- WebKit::WebCache::ResourceTypeStats)
-
- // Notify the browser that this render process can or can't be suddenly
- // terminated.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_SuddenTerminationChanged,
- bool /* enabled */)
-
- // Returns the window location of the window this widget is embeded.
- // TODO(shess): Provide a mapping from reply_msg->routing_id() to
- // HWND so that we can eliminate the NativeViewId parameter.
- IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_GetRootWindowRect,
- gfx::NativeViewId /* window */,
- gfx::Rect /* Out: Window location */)
-
- // Informs the browser of a new appcache host.
- IPC_MESSAGE_CONTROL1(AppCacheMsg_RegisterHost,
- int /* host_id */)
-
- // Informs the browser of an appcache host being destroyed.
- IPC_MESSAGE_CONTROL1(AppCacheMsg_UnregisterHost,
- int /* host_id */)
-
- // Initiates the cache selection algorithm for the given host.
- // This is sent prior to any subresource loads. An AppCacheMsg_CacheSelected
- // message will be sent in response.
- // 'host_id' indentifies a specific document or worker
- // 'document_url' the url of the main resource
- // 'appcache_document_was_loaded_from' the id of the appcache the main
- // resource was loaded from or kNoCacheId
- // 'opt_manifest_url' the manifest url specified in the <html> tag if any
- IPC_MESSAGE_CONTROL4(AppCacheMsg_SelectCache,
- int /* host_id */,
- GURL /* document_url */,
- int64 /* appcache_document_was_loaded_from */,
- GURL /* opt_manifest_url */)
-
- // Initiates worker specific cache selection algorithm for the given host.
- IPC_MESSAGE_CONTROL3(AppCacheMsg_SelectCacheForWorker,
- int /* host_id */,
- int /* parent_process_id */,
- int /* parent_host_id */)
- IPC_MESSAGE_CONTROL2(AppCacheMsg_SelectCacheForSharedWorker,
- int /* host_id */,
- int64 /* appcache_id */)
-
- // Informs the browser of a 'foreign' entry in an appcache.
- IPC_MESSAGE_CONTROL3(AppCacheMsg_MarkAsForeignEntry,
- int /* host_id */,
- GURL /* document_url */,
- int64 /* appcache_document_was_loaded_from */)
-
- // Returns the status of the appcache associated with host_id.
- IPC_SYNC_MESSAGE_CONTROL1_1(AppCacheMsg_GetStatus,
- int /* host_id */,
- appcache::Status)
-
- // Initiates an update of the appcache associated with host_id.
- IPC_SYNC_MESSAGE_CONTROL1_1(AppCacheMsg_StartUpdate,
- int /* host_id */,
- bool /* success */)
-
- // Swaps a new pending appcache, if there is one, into use for host_id.
- IPC_SYNC_MESSAGE_CONTROL1_1(AppCacheMsg_SwapCache,
- int /* host_id */,
- bool /* success */)
-
- // Gets resource list from appcache synchronously.
- IPC_SYNC_MESSAGE_CONTROL1_1(AppCacheMsg_GetResourceList,
- int /* host_id in*/,
- std::vector<appcache::AppCacheResourceInfo>
- /* resources out */)
-
- // Queries the browser for AutoFill suggestions for a form input field.
- IPC_MESSAGE_ROUTED3(ViewHostMsg_QueryFormFieldAutoFill,
- int /* id of this message */,
- webkit_glue::FormData /* the form */,
- webkit_glue::FormField /* the form field */)
-
- // Sent when the popup with AutoFill suggestions for a form is shown.
- IPC_MESSAGE_ROUTED0(ViewHostMsg_DidShowAutoFillSuggestions)
-
- // Instructs the browser to fill in the values for a form using AutoFill
- // profile data.
- IPC_MESSAGE_ROUTED4(ViewHostMsg_FillAutoFillFormData,
- int /* id of this message */,
- webkit_glue::FormData /* the form */,
- webkit_glue::FormField /* the form field */,
- int /* profile unique ID */)
-
- // Sent when a form is previewed or filled with AutoFill suggestions.
- IPC_MESSAGE_ROUTED0(ViewHostMsg_DidFillAutoFillFormData)
-
- // Instructs the browser to remove the specified Autocomplete entry from the
- // database.
- IPC_MESSAGE_ROUTED2(ViewHostMsg_RemoveAutocompleteEntry,
- string16 /* field name */,
- string16 /* value */)
-
- // Instructs the browser to show the AutoFill dialog.
- IPC_MESSAGE_ROUTED0(ViewHostMsg_ShowAutoFillDialog)
-
- // Get the list of proxies to use for |url|, as a semicolon delimited list
- // of "<TYPE> <HOST>:<PORT>" | "DIRECT". See also
- // PluginProcessHostMsg_ResolveProxy which does the same thing.
- IPC_SYNC_MESSAGE_CONTROL1_2(ViewHostMsg_ResolveProxy,
- GURL /* url */,
- int /* network error */,
- std::string /* proxy list */)
-
- // Request that got sent to browser for creating an audio output stream
- IPC_MESSAGE_ROUTED3(ViewHostMsg_CreateAudioStream,
- int /* stream_id */,
- ViewHostMsg_Audio_CreateStream_Params,
- bool /* low-latency */)
-
- // Tell the browser the audio buffer prepared for stream
- // (render_view_id, stream_id) is filled and is ready to be consumed.
- IPC_MESSAGE_ROUTED2(ViewHostMsg_NotifyAudioPacketReady,
- int /* stream_id */,
- uint32 /* packet size */)
-
- // Start buffering and play the audio stream specified by
- // (render_view_id, stream_id).
- IPC_MESSAGE_ROUTED1(ViewHostMsg_PlayAudioStream,
- int /* stream_id */)
-
- // Pause the audio stream specified by (render_view_id, stream_id).
- IPC_MESSAGE_ROUTED1(ViewHostMsg_PauseAudioStream,
- int /* stream_id */)
-
- // Discard all buffered audio data for the specified audio stream.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_FlushAudioStream,
- int /* stream_id */)
-
- // Close an audio stream specified by (render_view_id, stream_id).
- IPC_MESSAGE_ROUTED1(ViewHostMsg_CloseAudioStream,
- int /* stream_id */)
-
- // Get audio volume of the stream specified by (render_view_id, stream_id).
- IPC_MESSAGE_ROUTED1(ViewHostMsg_GetAudioVolume,
- int /* stream_id */)
-
- // Set audio volume of the stream specified by (render_view_id, stream_id).
- // TODO(hclam): change this to vector if we have channel numbers other than 2.
- IPC_MESSAGE_ROUTED2(ViewHostMsg_SetAudioVolume,
- int /* stream_id */,
- double /* volume */)
-
- // A renderer sends this message when an extension process starts an API
- // request. The browser will always respond with a ViewMsg_ExtensionResponse.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_ExtensionRequest,
- ViewHostMsg_DomMessage_Params)
-
- // Notify the browser that the given extension added a listener to an event.
- IPC_MESSAGE_CONTROL2(ViewHostMsg_ExtensionAddListener,
- std::string /* extension_id */,
- std::string /* name */)
-
- // Notify the browser that the given extension removed a listener from an
- // event.
- IPC_MESSAGE_CONTROL2(ViewHostMsg_ExtensionRemoveListener,
- std::string /* extension_id */,
- std::string /* name */)
+// Provide the browser process with information about the WebCore resource
+// cache.
+IPC_MESSAGE_CONTROL1(ViewHostMsg_ResourceTypeStats,
+ WebKit::WebCache::ResourceTypeStats)
+
+// Notify the browser that this render process can or can't be suddenly
+// terminated.
+IPC_MESSAGE_CONTROL1(ViewHostMsg_SuddenTerminationChanged,
+ bool /* enabled */)
+
+// Returns the window location of the window this widget is embeded.
+// TODO(shess): Provide a mapping from reply_msg->routing_id() to
+// HWND so that we can eliminate the NativeViewId parameter.
+IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_GetRootWindowRect,
+ gfx::NativeViewId /* window */,
+ gfx::Rect /* Out: Window location */)
+
+// Informs the browser of a new appcache host.
+IPC_MESSAGE_CONTROL1(AppCacheMsg_RegisterHost,
+ int /* host_id */)
+
+// Informs the browser of an appcache host being destroyed.
+IPC_MESSAGE_CONTROL1(AppCacheMsg_UnregisterHost,
+ int /* host_id */)
+
+// Initiates the cache selection algorithm for the given host.
+// This is sent prior to any subresource loads. An AppCacheMsg_CacheSelected
+// message will be sent in response.
+// 'host_id' indentifies a specific document or worker
+// 'document_url' the url of the main resource
+// 'appcache_document_was_loaded_from' the id of the appcache the main
+// resource was loaded from or kNoCacheId
+// 'opt_manifest_url' the manifest url specified in the <html> tag if any
+IPC_MESSAGE_CONTROL4(AppCacheMsg_SelectCache,
+ int /* host_id */,
+ GURL /* document_url */,
+ int64 /* appcache_document_was_loaded_from */,
+ GURL /* opt_manifest_url */)
+
+// Initiates worker specific cache selection algorithm for the given host.
+IPC_MESSAGE_CONTROL3(AppCacheMsg_SelectCacheForWorker,
+ int /* host_id */,
+ int /* parent_process_id */,
+ int /* parent_host_id */)
+IPC_MESSAGE_CONTROL2(AppCacheMsg_SelectCacheForSharedWorker,
+ int /* host_id */,
+ int64 /* appcache_id */)
+
+// Informs the browser of a 'foreign' entry in an appcache.
+IPC_MESSAGE_CONTROL3(AppCacheMsg_MarkAsForeignEntry,
+ int /* host_id */,
+ GURL /* document_url */,
+ int64 /* appcache_document_was_loaded_from */)
+
+// Returns the status of the appcache associated with host_id.
+IPC_SYNC_MESSAGE_CONTROL1_1(AppCacheMsg_GetStatus,
+ int /* host_id */,
+ appcache::Status)
+
+// Initiates an update of the appcache associated with host_id.
+IPC_SYNC_MESSAGE_CONTROL1_1(AppCacheMsg_StartUpdate,
+ int /* host_id */,
+ bool /* success */)
+
+// Swaps a new pending appcache, if there is one, into use for host_id.
+IPC_SYNC_MESSAGE_CONTROL1_1(AppCacheMsg_SwapCache,
+ int /* host_id */,
+ bool /* success */)
+
+// Gets resource list from appcache synchronously.
+IPC_SYNC_MESSAGE_CONTROL1_1(AppCacheMsg_GetResourceList,
+ int /* host_id in*/,
+ std::vector<appcache::AppCacheResourceInfo>
+ /* resources out */)
+
+// Queries the browser for AutoFill suggestions for a form input field.
+IPC_MESSAGE_ROUTED3(ViewHostMsg_QueryFormFieldAutoFill,
+ int /* id of this message */,
+ webkit_glue::FormData /* the form */,
+ webkit_glue::FormField /* the form field */)
+
+// Sent when the popup with AutoFill suggestions for a form is shown.
+IPC_MESSAGE_ROUTED0(ViewHostMsg_DidShowAutoFillSuggestions)
+
+// Instructs the browser to fill in the values for a form using AutoFill
+// profile data.
+IPC_MESSAGE_ROUTED4(ViewHostMsg_FillAutoFillFormData,
+ int /* id of this message */,
+ webkit_glue::FormData /* the form */,
+ webkit_glue::FormField /* the form field */,
+ int /* profile unique ID */)
+
+// Sent when a form is previewed or filled with AutoFill suggestions.
+IPC_MESSAGE_ROUTED0(ViewHostMsg_DidFillAutoFillFormData)
+
+// Instructs the browser to remove the specified Autocomplete entry from the
+// database.
+IPC_MESSAGE_ROUTED2(ViewHostMsg_RemoveAutocompleteEntry,
+ string16 /* field name */,
+ string16 /* value */)
+
+// Instructs the browser to show the AutoFill dialog.
+IPC_MESSAGE_ROUTED0(ViewHostMsg_ShowAutoFillDialog)
+
+// Get the list of proxies to use for |url|, as a semicolon delimited list
+// of "<TYPE> <HOST>:<PORT>" | "DIRECT". See also
+// PluginProcessHostMsg_ResolveProxy which does the same thing.
+IPC_SYNC_MESSAGE_CONTROL1_2(ViewHostMsg_ResolveProxy,
+ GURL /* url */,
+ int /* network error */,
+ std::string /* proxy list */)
+
+// Request that got sent to browser for creating an audio output stream
+IPC_MESSAGE_ROUTED3(ViewHostMsg_CreateAudioStream,
+ int /* stream_id */,
+ ViewHostMsg_Audio_CreateStream_Params,
+ bool /* low-latency */)
+
+// Tell the browser the audio buffer prepared for stream
+// (render_view_id, stream_id) is filled and is ready to be consumed.
+IPC_MESSAGE_ROUTED2(ViewHostMsg_NotifyAudioPacketReady,
+ int /* stream_id */,
+ uint32 /* packet size */)
+
+// Start buffering and play the audio stream specified by
+// (render_view_id, stream_id).
+IPC_MESSAGE_ROUTED1(ViewHostMsg_PlayAudioStream,
+ int /* stream_id */)
+
+// Pause the audio stream specified by (render_view_id, stream_id).
+IPC_MESSAGE_ROUTED1(ViewHostMsg_PauseAudioStream,
+ int /* stream_id */)
+
+// Discard all buffered audio data for the specified audio stream.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_FlushAudioStream,
+ int /* stream_id */)
+
+// Close an audio stream specified by (render_view_id, stream_id).
+IPC_MESSAGE_ROUTED1(ViewHostMsg_CloseAudioStream,
+ int /* stream_id */)
+
+// Get audio volume of the stream specified by (render_view_id, stream_id).
+IPC_MESSAGE_ROUTED1(ViewHostMsg_GetAudioVolume,
+ int /* stream_id */)
+
+// Set audio volume of the stream specified by (render_view_id, stream_id).
+// TODO(hclam): change this to vector if we have channel numbers other than 2.
+IPC_MESSAGE_ROUTED2(ViewHostMsg_SetAudioVolume,
+ int /* stream_id */,
+ double /* volume */)
+
+// A renderer sends this message when an extension process starts an API
+// request. The browser will always respond with a ViewMsg_ExtensionResponse.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_ExtensionRequest,
+ ViewHostMsg_DomMessage_Params)
+
+// Notify the browser that the given extension added a listener to an event.
+IPC_MESSAGE_CONTROL2(ViewHostMsg_ExtensionAddListener,
+ std::string /* extension_id */,
+ std::string /* name */)
+
+// Notify the browser that the given extension removed a listener from an
+// event.
+IPC_MESSAGE_CONTROL2(ViewHostMsg_ExtensionRemoveListener,
+ std::string /* extension_id */,
+ std::string /* name */)
#if defined(OS_MACOSX)
- // On OSX, we cannot allocated shared memory from within the sandbox, so
- // this call exists for the renderer to ask the browser to allocate memory
- // on its behalf. We return a file descriptor to the POSIX shared memory.
- // If the |cache_in_browser| flag is |true|, then a copy of the shmem is kept
- // by the browser, and it is the caller's repsonsibility to send a
- // ViewHostMsg_FreeTransportDIB message in order to release the cached shmem.
- // In all cases, the caller is responsible for deleting the resulting
- // TransportDIB.
- IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_AllocTransportDIB,
- size_t, /* bytes requested */
- bool, /* cache in the browser */
- TransportDIB::Handle /* DIB */)
-
- // Since the browser keeps handles to the allocated transport DIBs, this
- // message is sent to tell the browser that it may release them when the
- // renderer is finished with them.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_FreeTransportDIB,
- TransportDIB::Id /* DIB id */)
-
- // Instructs the browser to start or stop plugin IME.
- IPC_MESSAGE_ROUTED2(ViewHostMsg_SetPluginImeEnabled,
- bool, /* enabled */
- int /* plugin_id */)
-
- //---------------------------------------------------------------------------
- // Messages related to accelerated plugins
-
- // This is sent from the renderer to the browser to allocate a fake
- // PluginWindowHandle on the browser side which is used to identify
- // the plugin to the browser later when backing store is allocated
- // or reallocated. |opaque| indicates whether the plugin's output is
- // considered to be opaque, as opposed to translucent. This message
- // is reused for rendering the accelerated compositor's output.
- // |root| indicates whether the output is supposed to cover the
- // entire window.
- IPC_SYNC_MESSAGE_ROUTED2_1(ViewHostMsg_AllocateFakePluginWindowHandle,
- bool /* opaque */,
- bool /* root */,
- gfx::PluginWindowHandle /* id */)
-
- // Destroys a fake window handle previously allocated using
- // AllocateFakePluginWindowHandle.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_DestroyFakePluginWindowHandle,
- gfx::PluginWindowHandle /* id */)
-
- // This message, used on Mac OS X 10.5 and earlier (no IOSurface support),
- // is sent from the renderer to the browser on behalf of the plug-in
- // to indicate that a new backing store was allocated for that plug-in
- // instance.
- IPC_MESSAGE_ROUTED4(ViewHostMsg_AcceleratedSurfaceSetTransportDIB,
- gfx::PluginWindowHandle /* window */,
- int32 /* width */,
- int32 /* height */,
- TransportDIB::Handle /* handle for the DIB */)
-
- // This message, used on Mac OS X 10.6 and later (where IOSurface is
- // supported), is sent from the renderer to the browser on behalf of the
- // plug-in to indicate that a new backing store was allocated for that
- // plug-in instance.
- //
- // NOTE: the original intent was to pass a mach port as the IOSurface
- // identifier but it looks like that will be a lot of work. For now we pass an
- // ID from IOSurfaceGetID.
- IPC_MESSAGE_ROUTED4(ViewHostMsg_AcceleratedSurfaceSetIOSurface,
- gfx::PluginWindowHandle /* window */,
- int32 /* width */,
- int32 /* height */,
- uint64 /* surface_id */)
-
- // This message notifies the browser process that the plug-in
- // swapped the buffers associated with the given "window", which
- // should cause the browser to redraw the various plug-ins'
- // contents.
- IPC_MESSAGE_ROUTED2(ViewHostMsg_AcceleratedSurfaceBuffersSwapped,
- gfx::PluginWindowHandle /* window */,
- uint64 /* surface_id */)
+// On OSX, we cannot allocated shared memory from within the sandbox, so
+// this call exists for the renderer to ask the browser to allocate memory
+// on its behalf. We return a file descriptor to the POSIX shared memory.
+// If the |cache_in_browser| flag is |true|, then a copy of the shmem is kept
+// by the browser, and it is the caller's repsonsibility to send a
+// ViewHostMsg_FreeTransportDIB message in order to release the cached shmem.
+// In all cases, the caller is responsible for deleting the resulting
+// TransportDIB.
+IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_AllocTransportDIB,
+ size_t, /* bytes requested */
+ bool, /* cache in the browser */
+ TransportDIB::Handle /* DIB */)
+
+// Since the browser keeps handles to the allocated transport DIBs, this
+// message is sent to tell the browser that it may release them when the
+// renderer is finished with them.
+IPC_MESSAGE_CONTROL1(ViewHostMsg_FreeTransportDIB,
+ TransportDIB::Id /* DIB id */)
+
+// Instructs the browser to start or stop plugin IME.
+IPC_MESSAGE_ROUTED2(ViewHostMsg_SetPluginImeEnabled,
+ bool, /* enabled */
+ int /* plugin_id */)
+
+//---------------------------------------------------------------------------
+// Messages related to accelerated plugins
+
+// This is sent from the renderer to the browser to allocate a fake
+// PluginWindowHandle on the browser side which is used to identify
+// the plugin to the browser later when backing store is allocated
+// or reallocated. |opaque| indicates whether the plugin's output is
+// considered to be opaque, as opposed to translucent. This message
+// is reused for rendering the accelerated compositor's output.
+// |root| indicates whether the output is supposed to cover the
+// entire window.
+IPC_SYNC_MESSAGE_ROUTED2_1(ViewHostMsg_AllocateFakePluginWindowHandle,
+ bool /* opaque */,
+ bool /* root */,
+ gfx::PluginWindowHandle /* id */)
+
+// Destroys a fake window handle previously allocated using
+// AllocateFakePluginWindowHandle.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_DestroyFakePluginWindowHandle,
+ gfx::PluginWindowHandle /* id */)
+
+// This message, used on Mac OS X 10.5 and earlier (no IOSurface support),
+// is sent from the renderer to the browser on behalf of the plug-in
+// to indicate that a new backing store was allocated for that plug-in
+// instance.
+IPC_MESSAGE_ROUTED4(ViewHostMsg_AcceleratedSurfaceSetTransportDIB,
+ gfx::PluginWindowHandle /* window */,
+ int32 /* width */,
+ int32 /* height */,
+ TransportDIB::Handle /* handle for the DIB */)
+
+// This message, used on Mac OS X 10.6 and later (where IOSurface is
+// supported), is sent from the renderer to the browser on behalf of the
+// plug-in to indicate that a new backing store was allocated for that
+// plug-in instance.
+//
+// NOTE: the original intent was to pass a mach port as the IOSurface
+// identifier but it looks like that will be a lot of work. For now we pass an
+// ID from IOSurfaceGetID.
+IPC_MESSAGE_ROUTED4(ViewHostMsg_AcceleratedSurfaceSetIOSurface,
+ gfx::PluginWindowHandle /* window */,
+ int32 /* width */,
+ int32 /* height */,
+ uint64 /* surface_id */)
+
+// This message notifies the browser process that the plug-in
+// swapped the buffers associated with the given "window", which
+// should cause the browser to redraw the various plug-ins'
+// contents.
+IPC_MESSAGE_ROUTED2(ViewHostMsg_AcceleratedSurfaceBuffersSwapped,
+ gfx::PluginWindowHandle /* window */,
+ uint64 /* surface_id */)
#endif
- // A renderer sends this to the browser process when it wants to create a
- // worker. The browser will create the worker process if necessary, and
- // will return the route id on success. On error returns MSG_ROUTING_NONE.
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_CreateWorker,
- ViewHostMsg_CreateWorker_Params,
- int /* route_id */)
-
- // This message is sent to the browser to see if an instance of this shared
- // worker already exists. If so, it returns exists == true. If a
- // non-empty name is passed, also validates that the url matches the url of
- // the existing worker. If a matching worker is found, the passed-in
- // document_id is associated with that worker, to ensure that the worker
- // stays alive until the document is detached.
- // The route_id returned can be used to forward messages to the worker via
- // ForwardToWorker if it exists, otherwise it should be passed in to any
- // future call to CreateWorker to avoid creating duplicate workers.
- IPC_SYNC_MESSAGE_CONTROL1_3(ViewHostMsg_LookupSharedWorker,
- ViewHostMsg_CreateWorker_Params,
- bool /* exists */,
- int /* route_id */,
- bool /* url_mismatch */)
-
- // A renderer sends this to the browser process when a document has been
- // detached. The browser will use this to constrain the lifecycle of worker
- // processes (SharedWorkers are shut down when their last associated document
- // is detached).
- IPC_MESSAGE_CONTROL1(ViewHostMsg_DocumentDetached,
- uint64 /* document_id */)
-
- // A message sent to the browser on behalf of a renderer which wants to show
- // a desktop notification.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_ShowDesktopNotification,
- ViewHostMsg_ShowNotification_Params)
- IPC_MESSAGE_ROUTED1(ViewHostMsg_CancelDesktopNotification,
- int /* notification_id */ )
- IPC_MESSAGE_ROUTED2(ViewHostMsg_RequestNotificationPermission,
- GURL /* origin */,
- int /* callback_context */)
- IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_CheckNotificationPermission,
- GURL /* source page */,
- int /* permission_result */)
-
- // Sent if the worker object has sent a ViewHostMsg_CreateDedicatedWorker
- // message and not received a ViewMsg_WorkerCreated reply, but in the
- // mean time it's destroyed. This tells the browser to not create the queued
- // worker.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_CancelCreateDedicatedWorker,
- int /* route_id */)
-
- // Wraps an IPC message that's destined to the worker on the renderer->browser
- // hop.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_ForwardToWorker,
- IPC::Message /* message */)
-
- // Open a channel to all listening contexts owned by the extension with
- // the given ID. This always returns a valid port ID which can be used for
- // sending messages. If an error occurred, the opener will be notified
- // asynchronously.
- IPC_SYNC_MESSAGE_CONTROL4_1(ViewHostMsg_OpenChannelToExtension,
- int /* routing_id */,
- std::string /* source_extension_id */,
- std::string /* target_extension_id */,
- std::string /* channel_name */,
- int /* port_id */)
-
- // Get a port handle to the given tab. The handle can be used for sending
- // messages to the extension.
- IPC_SYNC_MESSAGE_CONTROL4_1(ViewHostMsg_OpenChannelToTab,
- int /* routing_id */,
- int /* tab_id */,
- std::string /* extension_id */,
- std::string /* channel_name */,
- int /* port_id */)
-
- // Send a message to an extension process. The handle is the value returned
- // by ViewHostMsg_OpenChannelTo*.
- IPC_MESSAGE_ROUTED2(ViewHostMsg_ExtensionPostMessage,
- int /* port_id */,
- std::string /* message */)
-
- // Send a message to an extension process. The handle is the value returned
- // by ViewHostMsg_OpenChannelTo*.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_ExtensionCloseChannel,
- int /* port_id */)
-
- // Sent to notify the browser about renderer accessibility notifications.
- // The browser responds with a ViewMsg_AccessibilityNotifications_ACK.
- IPC_MESSAGE_ROUTED1(
- ViewHostMsg_AccessibilityNotifications,
- std::vector<ViewHostMsg_AccessibilityNotification_Params>)
-
- // Message sent from the renderer to the browser to request that the browser
- // close all sockets. Used for debugging/testing.
- IPC_MESSAGE_CONTROL0(ViewHostMsg_CloseCurrentConnections)
-
- // Message sent from the renderer to the browser to request that the browser
- // enable or disable the cache. Used for debugging/testing.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_SetCacheMode,
- bool /* enabled */)
-
- // Message sent from the renderer to the browser to request that the browser
- // clear the cache. Used for debugging/testing.
- IPC_SYNC_MESSAGE_CONTROL0_1(ViewHostMsg_ClearCache,
- int /* result */)
-
- // Message sent from the renderer to the browser to request that the browser
- // enable or disable spdy. Used for debugging/testing/benchmarking.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_EnableSpdy,
- bool /* enable */)
-
- // Message sent from the renderer to the browser to request that the browser
- // cache |data| associated with |url|.
- IPC_MESSAGE_CONTROL3(ViewHostMsg_DidGenerateCacheableMetadata,
- GURL /* url */,
- double /* expected_response_time */,
- std::vector<char> /* data */)
-
- // Get the storage area id for a particular origin within a namespace.
- IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_DOMStorageStorageAreaId,
- int64 /* namespace_id */,
- string16 /* origin */,
- int64 /* storage_area_id */)
-
- // Get the length of a storage area.
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_DOMStorageLength,
- int64 /* storage_area_id */,
- unsigned /* length */)
-
- // Get a the ith key within a storage area.
- IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_DOMStorageKey,
- int64 /* storage_area_id */,
- unsigned /* index */,
- NullableString16 /* key */)
-
- // Get a value based on a key from a storage area.
- IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_DOMStorageGetItem,
- int64 /* storage_area_id */,
- string16 /* key */,
- NullableString16 /* value */)
-
- // Set a value that's associated with a key in a storage area.
- IPC_SYNC_MESSAGE_ROUTED4_2(ViewHostMsg_DOMStorageSetItem,
- int64 /* storage_area_id */,
- string16 /* key */,
- string16 /* value */,
- GURL /* url */,
- WebKit::WebStorageArea::Result /* result */,
- NullableString16 /* old_value */)
-
- // Remove the value associated with a key in a storage area.
- IPC_SYNC_MESSAGE_CONTROL3_1(ViewHostMsg_DOMStorageRemoveItem,
- int64 /* storage_area_id */,
- string16 /* key */,
- GURL /* url */,
- NullableString16 /* old_value */)
-
- // Clear the storage area.
- IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_DOMStorageClear,
- int64 /* storage_area_id */,
- GURL /* url */,
- bool /* something_cleared */)
-
- // WebIDBCursor::direction() message.
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBCursorDirection,
- int32, /* idb_cursor_id */
- int32 /* direction */)
-
- // WebIDBCursor::key() message.
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBCursorKey,
- int32, /* idb_cursor_id */
- IndexedDBKey)
-
- // WebIDBCursor::value() message.
- IPC_SYNC_MESSAGE_CONTROL1_2(ViewHostMsg_IDBCursorValue,
- int32, /* idb_cursor_id */
- SerializedScriptValue, /* script_value */
- IndexedDBKey /* key */)
-
- // WebIDBCursor::update() message.
- IPC_SYNC_MESSAGE_CONTROL3_1(ViewHostMsg_IDBCursorUpdate,
- int32, /* idb_cursor_id */
- int32, /* response_id */
- SerializedScriptValue, /* value */
- WebKit::WebExceptionCode /* ec */)
-
- // WebIDBCursor::continue() message.
- IPC_SYNC_MESSAGE_CONTROL3_1(ViewHostMsg_IDBCursorContinue,
- int32, /* idb_cursor_id */
- int32, /* response_id */
- IndexedDBKey, /* key */
- WebKit::WebExceptionCode /* ec */)
-
- // WebIDBCursor::remove() message.
- IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_IDBCursorRemove,
- int32, /* idb_cursor_id */
- int32, /* response_id */
- WebKit::WebExceptionCode /* ec */)
-
- // WebIDBFactory::open() message.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_IDBFactoryOpen,
- ViewHostMsg_IDBFactoryOpen_Params)
-
- // WebIDBDatabase::name() message.
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBDatabaseName,
- int32, /* idb_database_id */
- string16 /* name */)
-
- // WebIDBDatabase::version() message.
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBDatabaseVersion,
- int32, /* idb_database_id */
- string16 /* vesion */)
-
- // WebIDBDatabase::objectStoreNames() message.
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBDatabaseObjectStoreNames,
- int32, /* idb_database_id */
- std::vector<string16> /* objectStoreNames */)
-
- // WebIDBDatabase::createObjectStore() message.
- IPC_SYNC_MESSAGE_CONTROL1_2(ViewHostMsg_IDBDatabaseCreateObjectStore,
- ViewHostMsg_IDBDatabaseCreateObjectStore_Params,
- int32, /* object_store_id */
- WebKit::WebExceptionCode /* ec */)
-
- // WebIDBDatabase::removeObjectStore() message.
- IPC_SYNC_MESSAGE_CONTROL3_1(ViewHostMsg_IDBDatabaseRemoveObjectStore,
- int32, /* idb_database_id */
- string16, /* name */
- int32, /* transaction_id */
- WebKit::WebExceptionCode /* ec */)
-
- // WebIDBDatabase::setVersion() message.
- IPC_SYNC_MESSAGE_CONTROL3_1(ViewHostMsg_IDBDatabaseSetVersion,
- int32, /* idb_database_id */
- int32, /* response_id */
- string16, /* version */
- WebKit::WebExceptionCode /* ec */)
-
- // WebIDBDatabase::transaction() message.
- // TODO: make this message async. Have the renderer create a
- // temporary ID and keep a map in the browser process of real
- // IDs to temporary IDs. We can then update the transaction
- // to its real ID asynchronously.
- IPC_SYNC_MESSAGE_CONTROL4_2(ViewHostMsg_IDBDatabaseTransaction,
- int32, /* idb_database_id */
- std::vector<string16>, /* object_stores */
- int32, /* mode */
- int32, /* timeout */
- int32, /* idb_transaction_id */
- WebKit::WebExceptionCode /* ec */)
-
- // WebIDBDatabase::~WebIDBDatabase() message.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_IDBDatabaseDestroyed,
- int32 /* idb_database_id */)
-
- // WebIDBIndex::name() message.
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBIndexName,
- int32, /* idb_index_id */
- string16 /* name */)
-
- // WebIDBIndex::storeName() message.
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBIndexStoreName,
- int32, /* idb_index_id */
- string16 /* store_name */)
-
- // WebIDBIndex::keyPath() message.
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBIndexKeyPath,
- int32, /* idb_index_id */
- NullableString16 /* key_path */)
-
- // WebIDBIndex::unique() message.
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBIndexUnique,
- int32, /* idb_unique_id */
- bool /* unique */)
-
- // WebIDBIndex::openObjectCursor() message.
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBIndexOpenObjectCursor,
- ViewHostMsg_IDBIndexOpenCursor_Params,
- WebKit::WebExceptionCode /* ec */)
-
- // WebIDBIndex::openKeyCursor() message.
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBIndexOpenKeyCursor,
- ViewHostMsg_IDBIndexOpenCursor_Params,
- WebKit::WebExceptionCode /* ec */)
-
- // WebIDBIndex::getObject() message.
- IPC_SYNC_MESSAGE_CONTROL4_1(ViewHostMsg_IDBIndexGetObject,
- int32, /* idb_index_id */
- int32, /* response_id */
- IndexedDBKey, /* key */
- int32, /* transaction_id */
- WebKit::WebExceptionCode /* ec */)
-
- // WebIDBIndex::getKey() message.
- IPC_SYNC_MESSAGE_CONTROL4_1(ViewHostMsg_IDBIndexGetKey,
- int32, /* idb_index_id */
- int32, /* response_id */
- IndexedDBKey, /* key */
- int32, /* transaction_id */
- WebKit::WebExceptionCode /* ec */)
-
- // WebIDBIndex::~WebIDBIndex() message.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_IDBIndexDestroyed,
- int32 /* idb_index_id */)
-
- // WebIDBObjectStore::name() message.
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBObjectStoreName,
- int32, /* idb_object_store_id */
- string16 /* name */)
-
- // WebIDBObjectStore::keyPath() message.
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBObjectStoreKeyPath,
- int32, /* idb_object_store_id */
- NullableString16 /* keyPath */)
-
- // WebIDBObjectStore::indexNames() message.
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBObjectStoreIndexNames,
- int32, /* idb_object_store_id */
- std::vector<string16> /* index_names */)
-
- // WebIDBObjectStore::get() message.
- IPC_SYNC_MESSAGE_CONTROL4_1(ViewHostMsg_IDBObjectStoreGet,
- int32, /* idb_object_store_id */
- int32, /* response_id */
- IndexedDBKey, /* key */
- int32, /* transaction_id */
- WebKit::WebExceptionCode /* ec */)
-
- // WebIDBObjectStore::put() message.
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBObjectStorePut,
- ViewHostMsg_IDBObjectStorePut_Params,
- WebKit::WebExceptionCode /* ec */)
-
- // WebIDBObjectStore::remove() message.
- IPC_SYNC_MESSAGE_CONTROL4_1(ViewHostMsg_IDBObjectStoreRemove,
- int32, /* idb_object_store_id */
- int32, /* response_id */
- IndexedDBKey, /* key */
- int32, /* transaction_id */
- WebKit::WebExceptionCode /* ec */)
-
- // WebIDBObjectStore::createIndex() message.
- IPC_SYNC_MESSAGE_CONTROL1_2(ViewHostMsg_IDBObjectStoreCreateIndex,
- ViewHostMsg_IDBObjectStoreCreateIndex_Params,
- int32, /* index_id */
- WebKit::WebExceptionCode /* ec */)
-
- // WebIDBObjectStore::index() message.
- IPC_SYNC_MESSAGE_CONTROL2_2(ViewHostMsg_IDBObjectStoreIndex,
- int32, /* idb_object_store_id */
- string16, /* name */
- int32, /* idb_index_id */
- WebKit::WebExceptionCode /* ec */)
-
- // WebIDBObjectStore::removeIndex() message.
- IPC_SYNC_MESSAGE_CONTROL3_1(ViewHostMsg_IDBObjectStoreRemoveIndex,
- int32, /* idb_object_store_id */
- string16, /* name */
- int32, /* transaction_id */
- WebKit::WebExceptionCode /* ec */)
-
- // WebIDBObjectStore::openCursor() message.
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBObjectStoreOpenCursor,
- ViewHostMsg_IDBObjectStoreOpenCursor_Params,
- WebKit::WebExceptionCode /* ec */)
-
- // WebIDBObjectStore::~WebIDBObjectStore() message.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_IDBObjectStoreDestroyed,
- int32 /* idb_object_store_id */)
-
- // WebIDBDatabase::~WebIDBCursor() message.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_IDBCursorDestroyed,
- int32 /* idb_cursor_id */)
-
- // IDBTransaction::ObjectStore message.
- IPC_SYNC_MESSAGE_CONTROL2_2(ViewHostMsg_IDBTransactionObjectStore,
- int32, /* transaction_id */
- string16, /* name */
- int32, /* object_store_id */
- WebKit::WebExceptionCode /* ec */)
-
- // WebIDBTransaction::mode() message.
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_IDBTransactionMode,
- int32, /* idb_transaction_id */
- int /* mode */)
-
- // WebIDBTransaction::abort() message.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_IDBTransactionAbort,
- int32 /* idb_transaction_id */)
-
- // IDBTransaction::DidCompleteTaskEvents() message.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_IDBTransactionDidCompleteTaskEvents,
- int32 /* idb_transaction_id */)
-
- // WebIDBTransaction::~WebIDBTransaction() message.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_IDBTransactionDestroyed,
- int32 /* idb_transaction_id */)
-
- // Get file size in bytes. Set result to -1 if failed to get the file size.
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_GetFileSize,
- FilePath /* path */,
- int64 /* result */)
-
- // Get file modification time in seconds. Set result to 0 if failed to get the
- // file modification time.
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_GetFileModificationTime,
- FilePath /* path */,
- base::Time /* result */)
-
- // Open the file.
- IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_OpenFile,
- FilePath /* path */,
- int /* mode */,
- IPC::PlatformFileForTransit /* result */)
-
- // Opens a file asynchronously. The response returns a file descriptor
- // and an error code from base/platform_file.h.
- IPC_MESSAGE_ROUTED3(ViewHostMsg_AsyncOpenFile,
- FilePath /* file path */,
- int /* flags */,
- int /* message_id */)
-
- // Sent by the renderer process to acknowledge receipt of a
- // ViewMsg_CSSInsertRequest message and css has been inserted into the frame.
- IPC_MESSAGE_ROUTED0(ViewHostMsg_OnCSSInserted)
-
- // Sent by the renderer process to check whether access to web databases is
- // granted by content settings. This may block and trigger a cookie prompt.
- IPC_SYNC_MESSAGE_ROUTED4_1(ViewHostMsg_AllowDatabase,
- std::string /* origin_url */,
- string16 /* database name */,
- string16 /* database display name */,
- unsigned long /* estimated size */,
- bool /* result */)
-
- // Asks the browser process to open a DB file with the given name.
- IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_DatabaseOpenFile,
- string16 /* vfs file name */,
- int /* desired flags */,
- IPC::PlatformFileForTransit /* file_handle */)
-
- // Asks the browser process to delete a DB file
- IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_DatabaseDeleteFile,
- string16 /* vfs file name */,
- bool /* whether or not to sync the directory */,
- int /* SQLite error code */)
-
- // Asks the browser process to return the attributes of a DB file
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_DatabaseGetFileAttributes,
- string16 /* vfs file name */,
- int32 /* the attributes for the given DB file */)
-
- // Asks the browser process to return the size of a DB file
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_DatabaseGetFileSize,
- string16 /* vfs file name */,
- int64 /* the size of the given DB file */)
-
- // Notifies the browser process that a new database has been opened
- IPC_MESSAGE_CONTROL4(ViewHostMsg_DatabaseOpened,
- string16 /* origin identifier */,
- string16 /* database name */,
- string16 /* database description */,
- int64 /* estimated size */)
-
- // Notifies the browser process that a database might have been modified
- IPC_MESSAGE_CONTROL2(ViewHostMsg_DatabaseModified,
- string16 /* origin identifier */,
- string16 /* database name */)
-
- // Notifies the browser process that a database is about to close
- IPC_MESSAGE_CONTROL2(ViewHostMsg_DatabaseClosed,
- string16 /* origin identifier */,
- string16 /* database name */)
-
- // Notifies the browser of the language (ISO 639_1 code language, such as fr,
- // en, zh...) of the current page.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_PageLanguageDetermined,
- std::string /* the language */)
-
- // Notifies the browser that a page has been translated.
- IPC_MESSAGE_ROUTED4(ViewHostMsg_PageTranslated,
- int, /* page id */
- std::string /* the original language */,
- std::string /* the translated language */,
- TranslateErrors::Type /* the error type if available */)
-
- //---------------------------------------------------------------------------
- // Socket Stream messages:
- // These are messages from the SocketStreamHandle to the browser.
-
- // Open new Socket Stream for the |socket_url| identified by |socket_id|
- // in the renderer process.
- // The browser starts connecting asynchronously.
- // Once Socket Stream connection is established, the browser will send
- // ViewMsg_SocketStream_Connected back.
- IPC_MESSAGE_CONTROL2(ViewHostMsg_SocketStream_Connect,
- GURL /* socket_url */,
- int /* socket_id */)
-
- // Request to send data on the Socket Stream.
- // SocketStreamHandle can send data at most |max_pending_send_allowed| bytes,
- // which is given by ViewMsg_SocketStream_Connected at any time.
- // The number of pending bytes can be tracked by size of |data| sent
- // and |amount_sent| parameter of ViewMsg_SocketStream_DataSent.
- // That is, the following constraints is applied:
- // (accumulated total of |data|) - (accumulated total of |amount_sent|)
- // <= |max_pending_send_allowed|
- // If the SocketStreamHandle ever tries to exceed the
- // |max_pending_send_allowed|, the connection will be closed.
- IPC_MESSAGE_CONTROL2(ViewHostMsg_SocketStream_SendData,
- int /* socket_id */,
- std::vector<char> /* data */)
-
- // Request to close the Socket Stream.
- // The browser will send ViewMsg_SocketStream_Closed back when the Socket
- // Stream is completely closed.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_SocketStream_Close,
- int /* socket_id */)
-
- //---------------------------------------------------------------------------
- // Request for cryptographic operation messages:
- // These are messages from the renderer to the browser to perform a
- // cryptographic operation.
-
- // Asks the browser process to generate a keypair for grabbing a client
- // certificate from a CA (<keygen> tag), and returns the signed public
- // key and challenge string.
- IPC_SYNC_MESSAGE_CONTROL3_1(ViewHostMsg_Keygen,
- uint32 /* key size index */,
- std::string /* challenge string */,
- GURL /* URL of requestor */,
- std::string /* signed public key and challenge */)
-
- // The renderer has tried to spell check a word, but couldn't because no
- // dictionary was available to load. Request that the browser find an
- // appropriate dictionary and return it.
- IPC_MESSAGE_CONTROL0(ViewHostMsg_SpellChecker_RequestDictionary)
-
- IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_SpellChecker_PlatformCheckSpelling,
- string16 /* word */,
- int /* document tag */,
- bool /* correct */)
-
- IPC_SYNC_MESSAGE_CONTROL1_1(
- ViewHostMsg_SpellChecker_PlatformFillSuggestionList,
- string16 /* word */,
- std::vector<string16> /* suggestions */)
-
- //---------------------------------------------------------------------------
- // Geolocation services messages
-
- // A GeolocationServiceBridgeImpl in the renderer process has been created.
- // This is used to lazily initialize the host dispatchers and related
- // Geolocation infrastructure in the browser process.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_Geolocation_RegisterDispatcher,
- int /* render_view_id */)
-
- // A GeolocationServiceBridgeImpl has been destroyed.
- // This is used to let the Geolocation infrastructure do its cleanup.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_Geolocation_UnregisterDispatcher,
- int /* render_view_id */)
-
- // The |render_view_id| and |bridge_id| representing |host| is requesting
- // permission to access geolocation position.
- // This will be replied by ViewMsg_Geolocation_PermissionSet.
- IPC_MESSAGE_CONTROL3(ViewHostMsg_Geolocation_RequestPermission,
- int /* render_view_id */,
- int /* bridge_id */,
- GURL /* GURL of the frame requesting geolocation */)
-
- // The |render_view_id| and |bridge_id| representing |GURL| is cancelling its
- // previous permission request to access geolocation position.
- IPC_MESSAGE_CONTROL3(ViewHostMsg_Geolocation_CancelPermissionRequest,
- int /* render_view_id */,
- int /* bridge_id */,
- GURL /* GURL of the frame */)
-
- // The |render_view_id| and |bridge_id| requests Geolocation service to start
- // updating.
- // This is an asynchronous call, and the browser process may eventually reply
- // with the updated geoposition, or an error (access denied, location
- // unavailable, etc.)
- IPC_MESSAGE_CONTROL4(ViewHostMsg_Geolocation_StartUpdating,
- int /* render_view_id */,
- int /* bridge_id */,
- GURL /* GURL of the frame requesting geolocation */,
- bool /* enable_high_accuracy */)
-
- // The |render_view_id| and |bridge_id| requests Geolocation service to stop
- // updating.
- // Note that the geolocation service may continue to fetch geolocation data
- // for other origins.
- IPC_MESSAGE_CONTROL2(ViewHostMsg_Geolocation_StopUpdating,
- int /* render_view_id */,
- int /* bridge_id */)
-
- // The |render_view_id| and |bridge_id| requests Geolocation service to
- // suspend.
- // Note that the geolocation service may continue to fetch geolocation data
- // for other origins.
- IPC_MESSAGE_CONTROL2(ViewHostMsg_Geolocation_Suspend,
- int /* render_view_id */,
- int /* bridge_id */)
-
- // The |render_view_id| and |bridge_id| requests Geolocation service to
- // resume.
- IPC_MESSAGE_CONTROL2(ViewHostMsg_Geolocation_Resume,
- int /* render_view_id */,
- int /* bridge_id */)
-
- // Updates the minimum/maximum allowed zoom percent for this tab from the
- // default values. If |remember| is true, then the zoom setting is applied to
- // other pages in the site and is saved, otherwise it only applies to this
- // tab.
- IPC_MESSAGE_ROUTED3(ViewHostMsg_UpdateZoomLimits,
- int /* minimum_percent */,
- int /* maximum_percent */,
- bool /* remember */)
-
- // Requests the speech input service to start speech recognition on behalf of
- // the given |render_view_id|.
- IPC_MESSAGE_CONTROL5(ViewHostMsg_SpeechInput_StartRecognition,
- int /* render_view_id */,
- int /* request_id */,
- gfx::Rect /* element_rect */,
- std::string /* language */,
- std::string /* grammar */)
-
- // Requests the speech input service to cancel speech recognition on behalf of
- // the given |render_view_id|. If speech recognition is not happening nor or
- // is happening on behalf of some other render view, this call does nothing.
- IPC_MESSAGE_CONTROL2(ViewHostMsg_SpeechInput_CancelRecognition,
- int /* render_view_id */,
- int /* request id */)
-
- // Requests the speech input service to stop audio recording on behalf of
- // the given |render_view_id|. Any audio recorded so far will be fed to the
- // speech recognizer. If speech recognition is not happening nor or is
- // happening on behalf of some other render view, this call does nothing.
- IPC_MESSAGE_CONTROL2(ViewHostMsg_SpeechInput_StopRecording,
- int /* render_view_id */,
- int /* request id */)
-
- //---------------------------------------------------------------------------
- // Device orientation services messages:
-
- // A RenderView requests to start receiving device orientation updates.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_DeviceOrientation_StartUpdating,
- int /* render_view_id */)
-
- // A RenderView requests to stop receiving device orientation updates.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_DeviceOrientation_StopUpdating,
- int /* render_view_id */)
-
- //---------------------------------------------------------------------------
- // FileSystem API messages
- // These are messages sent from the renderer to the browser process.
-
- // WebFrameClient::openFileSystem() message.
- IPC_MESSAGE_CONTROL5(ViewHostMsg_OpenFileSystemRequest,
- int /* request_id */,
- GURL /* origin_url */,
- fileapi::FileSystemType /* type */,
- int64 /* requested_size */,
- bool /* create */)
-
- // WebFileSystem::move() message.
- IPC_MESSAGE_CONTROL3(ViewHostMsg_FileSystem_Move,
- int /* request_id */,
- FilePath /* src path */,
- FilePath /* dest path */)
-
- // WebFileSystem::copy() message.
- IPC_MESSAGE_CONTROL3(ViewHostMsg_FileSystem_Copy,
- int /* request_id */,
- FilePath /* src path */,
- FilePath /* dest path */)
-
- // WebFileSystem::remove() message.
- IPC_MESSAGE_CONTROL3(ViewHostMsg_FileSystem_Remove,
- int /* request_id */,
- FilePath /* path */,
- bool /* recursive */)
-
- // WebFileSystem::readMetadata() message.
- IPC_MESSAGE_CONTROL2(ViewHostMsg_FileSystem_ReadMetadata,
- int /* request_id */,
- FilePath /* path */)
-
- // WebFileSystem::create() message.
- IPC_MESSAGE_CONTROL5(ViewHostMsg_FileSystem_Create,
- int /* request_id */,
- FilePath /* path */,
- bool /* exclusive */,
- bool /* is_directory */,
- bool /* recursive */)
-
- // WebFileSystem::exists() messages.
- IPC_MESSAGE_CONTROL3(ViewHostMsg_FileSystem_Exists,
- int /* request_id */,
- FilePath /* path */,
- bool /* is_directory */)
-
- // WebFileSystem::readDirectory() message.
- IPC_MESSAGE_CONTROL2(ViewHostMsg_FileSystem_ReadDirectory,
- int /* request_id */,
- FilePath /* path */)
-
- // WebFileWriter::write() message.
- IPC_MESSAGE_CONTROL4(ViewHostMsg_FileSystem_Write,
- int /* request id */,
- FilePath /* file path */,
- GURL /* blob URL */,
- int64 /* position */)
-
- // WebFileWriter::truncate() message.
- IPC_MESSAGE_CONTROL3(ViewHostMsg_FileSystem_Truncate,
- int /* request id */,
- FilePath /* file path */,
- int64 /* length */)
-
- // Pepper's Touch() message.
- IPC_MESSAGE_CONTROL4(ViewHostMsg_FileSystem_TouchFile,
- int /* request_id */,
- FilePath /* path */,
- base::Time /* last_access_time */,
- base::Time /* last_modified_time */)
-
- // WebFileWriter::cancel() message.
- IPC_MESSAGE_CONTROL2(ViewHostMsg_FileSystem_CancelWrite,
- int /* request id */,
- int /* id of request to cancel */)
-
- //---------------------------------------------------------------------------
- // Blob messages:
-
- // Registers a blob URL referring to the specified blob data.
- IPC_MESSAGE_CONTROL2(ViewHostMsg_RegisterBlobUrl,
- GURL /* url */,
- scoped_refptr<webkit_blob::BlobData> /* blob_data */)
-
- // Registers a blob URL referring to the blob data identified by the specified
- // source URL.
- IPC_MESSAGE_CONTROL2(ViewHostMsg_RegisterBlobUrlFrom,
- GURL /* url */,
- GURL /* src_url */)
-
- // Unregister a blob URL.
- IPC_MESSAGE_CONTROL1(ViewHostMsg_UnregisterBlobUrl, GURL /* url */)
-
- // Suggest results -----------------------------------------------------------
-
- IPC_MESSAGE_ROUTED2(ViewHostMsg_SetSuggestions,
- int32 /* page_id */,
- std::vector<std::string> /* suggestions */)
-
- IPC_MESSAGE_ROUTED2(ViewHostMsg_InstantSupportDetermined,
- int32 /* page_id */,
- bool /* result */)
-
- // Client-Side Phishing Detector ---------------------------------------------
- // Inform the browser that the current URL is phishing according to the
- // client-side phishing detector.
- IPC_MESSAGE_ROUTED3(ViewHostMsg_DetectedPhishingSite,
- GURL /* phishing_url */,
- double /* phishing_score */,
- SkBitmap /* thumbnail */)
-
- // Response from ViewMsg_ScriptEvalRequest. The ID is the parameter supplied
- // to ViewMsg_ScriptEvalRequest. The result is true if the script evaluated
- // to the boolean result true, false otherwise.
- IPC_MESSAGE_ROUTED2(ViewHostMsg_ScriptEvalResponse,
- int /* id */,
- bool /* result */)
-
- // Updates the content restrictions, i.e. to disable print/copy.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_UpdateContentRestrictions,
- int /* restrictions */)
-
- // Trusted Pepper Filesystem messages ----------------------------------------
-
- // Open the file.
- IPC_SYNC_MESSAGE_CONTROL2_2(ViewHostMsg_PepperOpenFile,
- FilePath /* path */,
- int /* flags */,
- base::PlatformFileError /* error_code */,
- IPC::PlatformFileForTransit /* result */)
-
- // Rename the file.
- IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_PepperRenameFile,
- FilePath /* path_from */,
- FilePath /* path_to */,
- base::PlatformFileError /* error_code */)
-
- // Delete the file.
- IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_PepperDeleteFileOrDir,
- FilePath /* path */,
- bool /* recursive */,
- base::PlatformFileError /* error_code */)
-
- // Create the directory.
- IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_PepperCreateDir,
- FilePath /* path */,
- base::PlatformFileError /* error_code */)
-
- // Query the file's info.
- IPC_SYNC_MESSAGE_CONTROL1_2(ViewHostMsg_PepperQueryFile,
- FilePath /* path */,
- base::PlatformFileInfo, /* info */
- base::PlatformFileError /* error_code */)
-
- // Get the directory's contents.
- IPC_SYNC_MESSAGE_CONTROL1_2(ViewHostMsg_PepperGetDirContents,
- FilePath /* path */,
- PepperDirContents, /* contents */
- base::PlatformFileError /* error_code */)
-
-IPC_END_MESSAGES(ViewHost)
+// A renderer sends this to the browser process when it wants to create a
+// worker. The browser will create the worker process if necessary, and
+// will return the route id on success. On error returns MSG_ROUTING_NONE.
+IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_CreateWorker,
+ ViewHostMsg_CreateWorker_Params,
+ int /* route_id */)
+
+// This message is sent to the browser to see if an instance of this shared
+// worker already exists. If so, it returns exists == true. If a
+// non-empty name is passed, also validates that the url matches the url of
+// the existing worker. If a matching worker is found, the passed-in
+// document_id is associated with that worker, to ensure that the worker
+// stays alive until the document is detached.
+// The route_id returned can be used to forward messages to the worker via
+// ForwardToWorker if it exists, otherwise it should be passed in to any
+// future call to CreateWorker to avoid creating duplicate workers.
+IPC_SYNC_MESSAGE_CONTROL1_3(ViewHostMsg_LookupSharedWorker,
+ ViewHostMsg_CreateWorker_Params,
+ bool /* exists */,
+ int /* route_id */,
+ bool /* url_mismatch */)
+
+// A renderer sends this to the browser process when a document has been
+// detached. The browser will use this to constrain the lifecycle of worker
+// processes (SharedWorkers are shut down when their last associated document
+// is detached).
+IPC_MESSAGE_CONTROL1(ViewHostMsg_DocumentDetached,
+ uint64 /* document_id */)
+
+// A message sent to the browser on behalf of a renderer which wants to show
+// a desktop notification.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_ShowDesktopNotification,
+ ViewHostMsg_ShowNotification_Params)
+IPC_MESSAGE_ROUTED1(ViewHostMsg_CancelDesktopNotification,
+ int /* notification_id */ )
+IPC_MESSAGE_ROUTED2(ViewHostMsg_RequestNotificationPermission,
+ GURL /* origin */,
+ int /* callback_context */)
+IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_CheckNotificationPermission,
+ GURL /* source page */,
+ int /* permission_result */)
+
+// Sent if the worker object has sent a ViewHostMsg_CreateDedicatedWorker
+// message and not received a ViewMsg_WorkerCreated reply, but in the
+// mean time it's destroyed. This tells the browser to not create the queued
+// worker.
+IPC_MESSAGE_CONTROL1(ViewHostMsg_CancelCreateDedicatedWorker,
+ int /* route_id */)
+
+// Wraps an IPC message that's destined to the worker on the renderer->browser
+// hop.
+IPC_MESSAGE_CONTROL1(ViewHostMsg_ForwardToWorker,
+ IPC::Message /* message */)
+
+// Open a channel to all listening contexts owned by the extension with
+// the given ID. This always returns a valid port ID which can be used for
+// sending messages. If an error occurred, the opener will be notified
+// asynchronously.
+IPC_SYNC_MESSAGE_CONTROL4_1(ViewHostMsg_OpenChannelToExtension,
+ int /* routing_id */,
+ std::string /* source_extension_id */,
+ std::string /* target_extension_id */,
+ std::string /* channel_name */,
+ int /* port_id */)
+
+// Get a port handle to the given tab. The handle can be used for sending
+// messages to the extension.
+IPC_SYNC_MESSAGE_CONTROL4_1(ViewHostMsg_OpenChannelToTab,
+ int /* routing_id */,
+ int /* tab_id */,
+ std::string /* extension_id */,
+ std::string /* channel_name */,
+ int /* port_id */)
+
+// Send a message to an extension process. The handle is the value returned
+// by ViewHostMsg_OpenChannelTo*.
+IPC_MESSAGE_ROUTED2(ViewHostMsg_ExtensionPostMessage,
+ int /* port_id */,
+ std::string /* message */)
+
+// Send a message to an extension process. The handle is the value returned
+// by ViewHostMsg_OpenChannelTo*.
+IPC_MESSAGE_CONTROL1(ViewHostMsg_ExtensionCloseChannel,
+ int /* port_id */)
+
+// Sent to notify the browser about renderer accessibility notifications.
+// The browser responds with a ViewMsg_AccessibilityNotifications_ACK.
+IPC_MESSAGE_ROUTED1(
+ ViewHostMsg_AccessibilityNotifications,
+ std::vector<ViewHostMsg_AccessibilityNotification_Params>)
+
+// Message sent from the renderer to the browser to request that the browser
+// close all sockets. Used for debugging/testing.
+IPC_MESSAGE_CONTROL0(ViewHostMsg_CloseCurrentConnections)
+
+// Message sent from the renderer to the browser to request that the browser
+// enable or disable the cache. Used for debugging/testing.
+IPC_MESSAGE_CONTROL1(ViewHostMsg_SetCacheMode,
+ bool /* enabled */)
+
+// Message sent from the renderer to the browser to request that the browser
+// clear the cache. Used for debugging/testing.
+IPC_SYNC_MESSAGE_CONTROL0_1(ViewHostMsg_ClearCache,
+ int /* result */)
+
+// Message sent from the renderer to the browser to request that the browser
+// enable or disable spdy. Used for debugging/testing/benchmarking.
+IPC_MESSAGE_CONTROL1(ViewHostMsg_EnableSpdy,
+ bool /* enable */)
+
+// Message sent from the renderer to the browser to request that the browser
+// cache |data| associated with |url|.
+IPC_MESSAGE_CONTROL3(ViewHostMsg_DidGenerateCacheableMetadata,
+ GURL /* url */,
+ double /* expected_response_time */,
+ std::vector<char> /* data */)
+
+// Opens a file asynchronously. The response returns a file descriptor
+// and an error code from base/platform_file.h.
+IPC_MESSAGE_ROUTED3(ViewHostMsg_AsyncOpenFile,
+ FilePath /* file path */,
+ int /* flags */,
+ int /* message_id */)
+
+// Sent by the renderer process to acknowledge receipt of a
+// ViewMsg_CSSInsertRequest message and css has been inserted into the frame.
+IPC_MESSAGE_ROUTED0(ViewHostMsg_OnCSSInserted)
+
+// Notifies the browser of the language (ISO 639_1 code language, such as fr,
+// en, zh...) of the current page.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_PageLanguageDetermined,
+ std::string /* the language */)
+
+// Notifies the browser that a page has been translated.
+IPC_MESSAGE_ROUTED4(ViewHostMsg_PageTranslated,
+ int, /* page id */
+ std::string /* the original language */,
+ std::string /* the translated language */,
+ TranslateErrors::Type /* the error type if available */)
+
+//---------------------------------------------------------------------------
+// Socket Stream messages:
+// These are messages from the SocketStreamHandle to the browser.
+
+// Open new Socket Stream for the |socket_url| identified by |socket_id|
+// in the renderer process.
+// The browser starts connecting asynchronously.
+// Once Socket Stream connection is established, the browser will send
+// ViewMsg_SocketStream_Connected back.
+IPC_MESSAGE_CONTROL2(ViewHostMsg_SocketStream_Connect,
+ GURL /* socket_url */,
+ int /* socket_id */)
+
+// Request to send data on the Socket Stream.
+// SocketStreamHandle can send data at most |max_pending_send_allowed| bytes,
+// which is given by ViewMsg_SocketStream_Connected at any time.
+// The number of pending bytes can be tracked by size of |data| sent
+// and |amount_sent| parameter of ViewMsg_SocketStream_DataSent.
+// That is, the following constraints is applied:
+// (accumulated total of |data|) - (accumulated total of |amount_sent|)
+// <= |max_pending_send_allowed|
+// If the SocketStreamHandle ever tries to exceed the
+// |max_pending_send_allowed|, the connection will be closed.
+IPC_MESSAGE_CONTROL2(ViewHostMsg_SocketStream_SendData,
+ int /* socket_id */,
+ std::vector<char> /* data */)
+
+// Request to close the Socket Stream.
+// The browser will send ViewMsg_SocketStream_Closed back when the Socket
+// Stream is completely closed.
+IPC_MESSAGE_CONTROL1(ViewHostMsg_SocketStream_Close,
+ int /* socket_id */)
+
+//---------------------------------------------------------------------------
+// Request for cryptographic operation messages:
+// These are messages from the renderer to the browser to perform a
+// cryptographic operation.
+
+// Asks the browser process to generate a keypair for grabbing a client
+// certificate from a CA (<keygen> tag), and returns the signed public
+// key and challenge string.
+IPC_SYNC_MESSAGE_CONTROL3_1(ViewHostMsg_Keygen,
+ uint32 /* key size index */,
+ std::string /* challenge string */,
+ GURL /* URL of requestor */,
+ std::string /* signed public key and challenge */)
+
+// The renderer has tried to spell check a word, but couldn't because no
+// dictionary was available to load. Request that the browser find an
+// appropriate dictionary and return it.
+IPC_MESSAGE_CONTROL0(ViewHostMsg_SpellChecker_RequestDictionary)
+
+IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_SpellChecker_PlatformCheckSpelling,
+ string16 /* word */,
+ int /* document tag */,
+ bool /* correct */)
+
+IPC_SYNC_MESSAGE_CONTROL1_1(
+ ViewHostMsg_SpellChecker_PlatformFillSuggestionList,
+ string16 /* word */,
+ std::vector<string16> /* suggestions */)
+
+//---------------------------------------------------------------------------
+// Geolocation services messages
+
+// A GeolocationServiceBridgeImpl in the renderer process has been created.
+// This is used to lazily initialize the host dispatchers and related
+// Geolocation infrastructure in the browser process.
+IPC_MESSAGE_CONTROL1(ViewHostMsg_Geolocation_RegisterDispatcher,
+ int /* render_view_id */)
+
+// A GeolocationServiceBridgeImpl has been destroyed.
+// This is used to let the Geolocation infrastructure do its cleanup.
+IPC_MESSAGE_CONTROL1(ViewHostMsg_Geolocation_UnregisterDispatcher,
+ int /* render_view_id */)
+
+// The |render_view_id| and |bridge_id| representing |host| is requesting
+// permission to access geolocation position.
+// This will be replied by ViewMsg_Geolocation_PermissionSet.
+IPC_MESSAGE_CONTROL3(ViewHostMsg_Geolocation_RequestPermission,
+ int /* render_view_id */,
+ int /* bridge_id */,
+ GURL /* GURL of the frame requesting geolocation */)
+
+// The |render_view_id| and |bridge_id| representing |GURL| is cancelling its
+// previous permission request to access geolocation position.
+IPC_MESSAGE_CONTROL3(ViewHostMsg_Geolocation_CancelPermissionRequest,
+ int /* render_view_id */,
+ int /* bridge_id */,
+ GURL /* GURL of the frame */)
+
+// The |render_view_id| and |bridge_id| requests Geolocation service to start
+// updating.
+// This is an asynchronous call, and the browser process may eventually reply
+// with the updated geoposition, or an error (access denied, location
+// unavailable, etc.)
+IPC_MESSAGE_CONTROL4(ViewHostMsg_Geolocation_StartUpdating,
+ int /* render_view_id */,
+ int /* bridge_id */,
+ GURL /* GURL of the frame requesting geolocation */,
+ bool /* enable_high_accuracy */)
+
+// The |render_view_id| and |bridge_id| requests Geolocation service to stop
+// updating.
+// Note that the geolocation service may continue to fetch geolocation data
+// for other origins.
+IPC_MESSAGE_CONTROL2(ViewHostMsg_Geolocation_StopUpdating,
+ int /* render_view_id */,
+ int /* bridge_id */)
+
+// The |render_view_id| and |bridge_id| requests Geolocation service to
+// suspend.
+// Note that the geolocation service may continue to fetch geolocation data
+// for other origins.
+IPC_MESSAGE_CONTROL2(ViewHostMsg_Geolocation_Suspend,
+ int /* render_view_id */,
+ int /* bridge_id */)
+
+// The |render_view_id| and |bridge_id| requests Geolocation service to
+// resume.
+IPC_MESSAGE_CONTROL2(ViewHostMsg_Geolocation_Resume,
+ int /* render_view_id */,
+ int /* bridge_id */)
+
+// Updates the minimum/maximum allowed zoom percent for this tab from the
+// default values. If |remember| is true, then the zoom setting is applied to
+// other pages in the site and is saved, otherwise it only applies to this
+// tab.
+IPC_MESSAGE_ROUTED3(ViewHostMsg_UpdateZoomLimits,
+ int /* minimum_percent */,
+ int /* maximum_percent */,
+ bool /* remember */)
+
+// Requests the speech input service to start speech recognition on behalf of
+// the given |render_view_id|.
+IPC_MESSAGE_CONTROL5(ViewHostMsg_SpeechInput_StartRecognition,
+ int /* render_view_id */,
+ int /* request_id */,
+ gfx::Rect /* element_rect */,
+ std::string /* language */,
+ std::string /* grammar */)
+
+// Requests the speech input service to cancel speech recognition on behalf of
+// the given |render_view_id|. If speech recognition is not happening nor or
+// is happening on behalf of some other render view, this call does nothing.
+IPC_MESSAGE_CONTROL2(ViewHostMsg_SpeechInput_CancelRecognition,
+ int /* render_view_id */,
+ int /* request id */)
+
+// Requests the speech input service to stop audio recording on behalf of
+// the given |render_view_id|. Any audio recorded so far will be fed to the
+// speech recognizer. If speech recognition is not happening nor or is
+// happening on behalf of some other render view, this call does nothing.
+IPC_MESSAGE_CONTROL2(ViewHostMsg_SpeechInput_StopRecording,
+ int /* render_view_id */,
+ int /* request id */)
+
+//---------------------------------------------------------------------------
+// Device orientation services messages:
+
+// A RenderView requests to start receiving device orientation updates.
+IPC_MESSAGE_CONTROL1(ViewHostMsg_DeviceOrientation_StartUpdating,
+ int /* render_view_id */)
+
+// A RenderView requests to stop receiving device orientation updates.
+IPC_MESSAGE_CONTROL1(ViewHostMsg_DeviceOrientation_StopUpdating,
+ int /* render_view_id */)
+
+//---------------------------------------------------------------------------
+// FileSystem API messages
+// These are messages sent from the renderer to the browser process.
+
+// WebFrameClient::openFileSystem() message.
+IPC_MESSAGE_CONTROL5(ViewHostMsg_OpenFileSystemRequest,
+ int /* request_id */,
+ GURL /* origin_url */,
+ fileapi::FileSystemType /* type */,
+ int64 /* requested_size */,
+ bool /* create */)
+
+// WebFileSystem::move() message.
+IPC_MESSAGE_CONTROL3(ViewHostMsg_FileSystem_Move,
+ int /* request_id */,
+ FilePath /* src path */,
+ FilePath /* dest path */)
+
+// WebFileSystem::copy() message.
+IPC_MESSAGE_CONTROL3(ViewHostMsg_FileSystem_Copy,
+ int /* request_id */,
+ FilePath /* src path */,
+ FilePath /* dest path */)
+
+// WebFileSystem::remove() message.
+IPC_MESSAGE_CONTROL3(ViewHostMsg_FileSystem_Remove,
+ int /* request_id */,
+ FilePath /* path */,
+ bool /* recursive */)
+
+// WebFileSystem::readMetadata() message.
+IPC_MESSAGE_CONTROL2(ViewHostMsg_FileSystem_ReadMetadata,
+ int /* request_id */,
+ FilePath /* path */)
+
+// WebFileSystem::create() message.
+IPC_MESSAGE_CONTROL5(ViewHostMsg_FileSystem_Create,
+ int /* request_id */,
+ FilePath /* path */,
+ bool /* exclusive */,
+ bool /* is_directory */,
+ bool /* recursive */)
+
+// WebFileSystem::exists() messages.
+IPC_MESSAGE_CONTROL3(ViewHostMsg_FileSystem_Exists,
+ int /* request_id */,
+ FilePath /* path */,
+ bool /* is_directory */)
+
+// WebFileSystem::readDirectory() message.
+IPC_MESSAGE_CONTROL2(ViewHostMsg_FileSystem_ReadDirectory,
+ int /* request_id */,
+ FilePath /* path */)
+
+// WebFileWriter::write() message.
+IPC_MESSAGE_CONTROL4(ViewHostMsg_FileSystem_Write,
+ int /* request id */,
+ FilePath /* file path */,
+ GURL /* blob URL */,
+ int64 /* position */)
+
+// WebFileWriter::truncate() message.
+IPC_MESSAGE_CONTROL3(ViewHostMsg_FileSystem_Truncate,
+ int /* request id */,
+ FilePath /* file path */,
+ int64 /* length */)
+
+// Pepper's Touch() message.
+IPC_MESSAGE_CONTROL4(ViewHostMsg_FileSystem_TouchFile,
+ int /* request_id */,
+ FilePath /* path */,
+ base::Time /* last_access_time */,
+ base::Time /* last_modified_time */)
+
+// WebFileWriter::cancel() message.
+IPC_MESSAGE_CONTROL2(ViewHostMsg_FileSystem_CancelWrite,
+ int /* request id */,
+ int /* id of request to cancel */)
+
+//---------------------------------------------------------------------------
+// Blob messages:
+
+// Registers a blob URL referring to the specified blob data.
+IPC_MESSAGE_CONTROL2(ViewHostMsg_RegisterBlobUrl,
+ GURL /* url */,
+ scoped_refptr<webkit_blob::BlobData> /* blob_data */)
+
+// Registers a blob URL referring to the blob data identified by the specified
+// source URL.
+IPC_MESSAGE_CONTROL2(ViewHostMsg_RegisterBlobUrlFrom,
+ GURL /* url */,
+ GURL /* src_url */)
+
+// Unregister a blob URL.
+IPC_MESSAGE_CONTROL1(ViewHostMsg_UnregisterBlobUrl, GURL /* url */)
+
+// Suggest results -----------------------------------------------------------
+
+IPC_MESSAGE_ROUTED2(ViewHostMsg_SetSuggestions,
+ int32 /* page_id */,
+ std::vector<std::string> /* suggestions */)
+
+IPC_MESSAGE_ROUTED2(ViewHostMsg_InstantSupportDetermined,
+ int32 /* page_id */,
+ bool /* result */)
+
+// Client-Side Phishing Detector ---------------------------------------------
+// Inform the browser that the current URL is phishing according to the
+// client-side phishing detector.
+IPC_MESSAGE_ROUTED3(ViewHostMsg_DetectedPhishingSite,
+ GURL /* phishing_url */,
+ double /* phishing_score */,
+ SkBitmap /* thumbnail */)
+
+// Response from ViewMsg_ScriptEvalRequest. The ID is the parameter supplied
+// to ViewMsg_ScriptEvalRequest. The result has the value returned by the
+// script as it's only element, one of Null, Boolean, Integer, Real, Date, or
+// String.
+IPC_MESSAGE_ROUTED2(ViewHostMsg_ScriptEvalResponse,
+ int /* id */,
+ ListValue /* result */)
+
+// Updates the content restrictions, i.e. to disable print/copy.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_UpdateContentRestrictions,
+ int /* restrictions */)
diff --git a/chrome/common/render_messages_params.cc b/chrome/common/render_messages_params.cc
index 2b8638d..7fab193 100644
--- a/chrome/common/render_messages_params.cc
+++ b/chrome/common/render_messages_params.cc
@@ -6,7 +6,6 @@
#include "chrome/common/navigation_gesture.h"
#include "chrome/common/common_param_traits.h"
-#include "chrome/common/indexed_db_param_traits.h"
#include "chrome/common/render_messages.h"
#include "net/base/upload_data.h"
@@ -66,6 +65,7 @@ ViewHostMsg_Resource_Request::ViewHostMsg_Resource_Request()
request_context(0),
appcache_host_id(0),
download_to_file(false),
+ has_user_gesture(false),
host_renderer_id(0),
host_render_view_id(0) {
}
@@ -118,6 +118,21 @@ ViewMsg_PrintPages_Params::ViewMsg_PrintPages_Params() {
ViewMsg_PrintPages_Params::~ViewMsg_PrintPages_Params() {
}
+ViewHostMsg_DidPreviewDocument_Params::ViewHostMsg_DidPreviewDocument_Params()
+ : data_size(0) {
+#if defined(OS_WIN)
+ // Initialize |metafile_data_handle| only on Windows because it maps
+ // base::SharedMemoryHandle to HANDLE. We do not need to initialize this
+ // variable on Posix because it maps base::SharedMemoryHandle to
+ // FileDescriptior, which has the default constructor.
+ metafile_data_handle = INVALID_HANDLE_VALUE;
+#endif
+}
+
+ViewHostMsg_DidPreviewDocument_Params::
+ ~ViewHostMsg_DidPreviewDocument_Params() {
+}
+
ViewHostMsg_DidPrintPage_Params::ViewHostMsg_DidPrintPage_Params()
: data_size(0),
document_cookie(0),
@@ -165,83 +180,6 @@ ViewHostMsg_ScriptedPrint_Params::ViewHostMsg_ScriptedPrint_Params()
ViewHostMsg_ScriptedPrint_Params::~ViewHostMsg_ScriptedPrint_Params() {
}
-ViewMsg_DOMStorageEvent_Params::ViewMsg_DOMStorageEvent_Params()
- : storage_type_(DOM_STORAGE_LOCAL) {
-}
-
-ViewMsg_DOMStorageEvent_Params::~ViewMsg_DOMStorageEvent_Params() {
-}
-
-ViewHostMsg_IDBFactoryOpen_Params::ViewHostMsg_IDBFactoryOpen_Params()
- : routing_id_(0),
- response_id_(0),
- maximum_size_(0) {
-}
-
-ViewHostMsg_IDBFactoryOpen_Params::~ViewHostMsg_IDBFactoryOpen_Params() {
-}
-
-ViewHostMsg_IDBDatabaseCreateObjectStore_Params::
- ViewHostMsg_IDBDatabaseCreateObjectStore_Params()
- : auto_increment_(false),
- transaction_id_(0),
- idb_database_id_(0) {
-}
-
-ViewHostMsg_IDBDatabaseCreateObjectStore_Params::
- ~ViewHostMsg_IDBDatabaseCreateObjectStore_Params() {
-}
-
-ViewHostMsg_IDBIndexOpenCursor_Params::ViewHostMsg_IDBIndexOpenCursor_Params()
- : response_id_(0),
- lower_open_(false),
- upper_open_(false),
- direction_(0),
- idb_index_id_(0),
- transaction_id_(0) {
-}
-
-ViewHostMsg_IDBIndexOpenCursor_Params::
- ~ViewHostMsg_IDBIndexOpenCursor_Params() {
-}
-
-
-ViewHostMsg_IDBObjectStorePut_Params::ViewHostMsg_IDBObjectStorePut_Params()
- : idb_object_store_id_(0),
- response_id_(0),
- add_only_(false),
- transaction_id_(0) {
-}
-
-ViewHostMsg_IDBObjectStorePut_Params::~ViewHostMsg_IDBObjectStorePut_Params() {
-}
-
-ViewHostMsg_IDBObjectStoreCreateIndex_Params::
-ViewHostMsg_IDBObjectStoreCreateIndex_Params()
- : unique_(false),
- transaction_id_(0),
- idb_object_store_id_(0) {
-}
-
-ViewHostMsg_IDBObjectStoreCreateIndex_Params::
-~ViewHostMsg_IDBObjectStoreCreateIndex_Params() {
-}
-
-
-ViewHostMsg_IDBObjectStoreOpenCursor_Params::
- ViewHostMsg_IDBObjectStoreOpenCursor_Params()
- : response_id_(0),
- lower_open_(false),
- upper_open_(false),
- direction_(0),
- idb_object_store_id_(0),
- transaction_id_(0) {
-}
-
-ViewHostMsg_IDBObjectStoreOpenCursor_Params::
- ~ViewHostMsg_IDBObjectStoreOpenCursor_Params() {
-}
-
ViewMsg_ExecuteCode_Params::ViewMsg_ExecuteCode_Params() {
}
@@ -942,6 +880,7 @@ void ParamTraits<ViewHostMsg_Resource_Request>::Write(Message* m,
WriteParam(m, p.appcache_host_id);
WriteParam(m, p.upload_data);
WriteParam(m, p.download_to_file);
+ WriteParam(m, p.has_user_gesture);
WriteParam(m, p.host_renderer_id);
WriteParam(m, p.host_render_view_id);
}
@@ -964,6 +903,7 @@ bool ParamTraits<ViewHostMsg_Resource_Request>::Read(const Message* m,
ReadParam(m, iter, &r->appcache_host_id) &&
ReadParam(m, iter, &r->upload_data) &&
ReadParam(m, iter, &r->download_to_file) &&
+ ReadParam(m, iter, &r->has_user_gesture) &&
ReadParam(m, iter, &r->host_renderer_id) &&
ReadParam(m, iter, &r->host_render_view_id);
}
@@ -993,6 +933,8 @@ void ParamTraits<ViewHostMsg_Resource_Request>::Log(const param_type& p,
l->append(", ");
LogParam(p.download_to_file, l);
l->append(", ");
+ LogParam(p.has_user_gesture, l);
+ l->append(", ");
LogParam(p.host_renderer_id, l);
l->append(", ");
LogParam(p.host_render_view_id, l);
@@ -1068,6 +1010,26 @@ void ParamTraits<ViewMsg_PrintPages_Params>::Log(const param_type& p,
l->append("<ViewMsg_PrintPages_Params>");
}
+void ParamTraits<ViewHostMsg_DidPreviewDocument_Params>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.metafile_data_handle);
+ WriteParam(m, p.data_size);
+ WriteParam(m, p.document_cookie);
+}
+
+bool ParamTraits<ViewHostMsg_DidPreviewDocument_Params>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return ReadParam(m, iter, &p->metafile_data_handle) &&
+ ReadParam(m, iter, &p->data_size) &&
+ ReadParam(m, iter, &p->document_cookie);
+}
+
+void ParamTraits<ViewHostMsg_DidPreviewDocument_Params>::Log(
+ const param_type& p, std::string* l) {
+ l->append("<ViewHostMsg_DidPreviewDocument_Params>");
+}
+
void ParamTraits<ViewHostMsg_DidPrintPage_Params>::Write(Message* m,
const param_type& p) {
WriteParam(m, p.metafile_data_handle);
@@ -1213,303 +1175,6 @@ void ParamTraits<ViewHostMsg_ScriptedPrint_Params>::Log(const param_type& p,
l->append(")");
}
-void ParamTraits<ViewMsg_DOMStorageEvent_Params>::Write(Message* m,
- const param_type& p) {
- WriteParam(m, p.key_);
- WriteParam(m, p.old_value_);
- WriteParam(m, p.new_value_);
- WriteParam(m, p.origin_);
- WriteParam(m, p.url_);
- WriteParam(m, p.storage_type_);
-}
-
-bool ParamTraits<ViewMsg_DOMStorageEvent_Params>::Read(const Message* m,
- void** iter,
- param_type* p) {
- return
- ReadParam(m, iter, &p->key_) &&
- ReadParam(m, iter, &p->old_value_) &&
- ReadParam(m, iter, &p->new_value_) &&
- ReadParam(m, iter, &p->origin_) &&
- ReadParam(m, iter, &p->url_) &&
- ReadParam(m, iter, &p->storage_type_);
-}
-
-void ParamTraits<ViewMsg_DOMStorageEvent_Params>::Log(const param_type& p,
- std::string* l) {
- l->append("(");
- LogParam(p.key_, l);
- l->append(", ");
- LogParam(p.old_value_, l);
- l->append(", ");
- LogParam(p.new_value_, l);
- l->append(", ");
- LogParam(p.origin_, l);
- l->append(", ");
- LogParam(p.url_, l);
- l->append(", ");
- LogParam(p.storage_type_, l);
- l->append(")");
-}
-
-void ParamTraits<ViewHostMsg_IDBFactoryOpen_Params>::Write(
- Message* m,
- const param_type& p) {
- WriteParam(m, p.routing_id_);
- WriteParam(m, p.response_id_);
- WriteParam(m, p.origin_);
- WriteParam(m, p.name_);
- WriteParam(m, p.description_);
- WriteParam(m, p.maximum_size_);
-}
-
-bool ParamTraits<ViewHostMsg_IDBFactoryOpen_Params>::Read(const Message* m,
- void** iter,
- param_type* p) {
- return
- ReadParam(m, iter, &p->routing_id_) &&
- ReadParam(m, iter, &p->response_id_) &&
- ReadParam(m, iter, &p->origin_) &&
- ReadParam(m, iter, &p->name_) &&
- ReadParam(m, iter, &p->description_) &&
- ReadParam(m, iter, &p->maximum_size_);
-}
-
-void ParamTraits<ViewHostMsg_IDBFactoryOpen_Params>::Log(const param_type& p,
- std::string* l) {
- l->append("(");
- LogParam(p.routing_id_, l);
- l->append(", ");
- LogParam(p.response_id_, l);
- l->append(", ");
- LogParam(p.origin_, l);
- l->append(", ");
- LogParam(p.name_, l);
- l->append(", ");
- LogParam(p.description_, l);
- l->append(", ");
- LogParam(p.maximum_size_, l);
- l->append(")");
-}
-
-void ParamTraits<ViewHostMsg_IDBDatabaseCreateObjectStore_Params>::Write(
- Message* m,
- const param_type& p) {
- WriteParam(m, p.name_);
- WriteParam(m, p.key_path_);
- WriteParam(m, p.auto_increment_);
- WriteParam(m, p.transaction_id_);
- WriteParam(m, p.idb_database_id_);
-}
-
-bool ParamTraits<ViewHostMsg_IDBDatabaseCreateObjectStore_Params>::Read(
- const Message* m,
- void** iter,
- param_type* p) {
- return
- ReadParam(m, iter, &p->name_) &&
- ReadParam(m, iter, &p->key_path_) &&
- ReadParam(m, iter, &p->auto_increment_) &&
- ReadParam(m, iter, &p->transaction_id_) &&
- ReadParam(m, iter, &p->idb_database_id_);
-}
-
-void ParamTraits<ViewHostMsg_IDBDatabaseCreateObjectStore_Params>::Log(
- const param_type& p,
- std::string* l) {
- l->append("(");
- LogParam(p.name_, l);
- l->append(", ");
- LogParam(p.key_path_, l);
- l->append(", ");
- LogParam(p.auto_increment_, l);
- l->append(", ");
- LogParam(p.transaction_id_, l);
- l->append(", ");
- LogParam(p.idb_database_id_, l);
- l->append(")");
-}
-
-void ParamTraits<ViewHostMsg_IDBIndexOpenCursor_Params>::Write(
- Message* m,
- const param_type& p) {
- WriteParam(m, p.response_id_);
- WriteParam(m, p.lower_key_);
- WriteParam(m, p.upper_key_);
- WriteParam(m, p.lower_open_);
- WriteParam(m, p.upper_open_);
- WriteParam(m, p.direction_);
- WriteParam(m, p.idb_index_id_);
- WriteParam(m, p.transaction_id_);
-}
-
-bool ParamTraits<ViewHostMsg_IDBIndexOpenCursor_Params>::Read(
- const Message* m,
- void** iter,
- param_type* p) {
- return
- ReadParam(m, iter, &p->response_id_) &&
- ReadParam(m, iter, &p->lower_key_) &&
- ReadParam(m, iter, &p->upper_key_) &&
- ReadParam(m, iter, &p->lower_open_) &&
- ReadParam(m, iter, &p->upper_open_) &&
- ReadParam(m, iter, &p->direction_) &&
- ReadParam(m, iter, &p->idb_index_id_) &&
- ReadParam(m, iter, &p->transaction_id_);
-}
-
-void ParamTraits<ViewHostMsg_IDBIndexOpenCursor_Params>::Log(
- const param_type& p,
- std::string* l) {
- l->append("(");
- LogParam(p.response_id_, l);
- l->append(", ");
- LogParam(p.lower_key_, l);
- l->append(", ");
- LogParam(p.upper_key_, l);
- l->append(", ");
- LogParam(p.lower_open_, l);
- l->append(", ");
- LogParam(p.upper_open_, l);
- l->append(", ");
- LogParam(p.direction_, l);
- l->append(", ");
- LogParam(p.idb_index_id_, l);
- l->append(",");
- LogParam(p.transaction_id_, l);
- l->append(")");
-}
-
-void ParamTraits<ViewHostMsg_IDBObjectStorePut_Params>::Write(
- Message* m,
- const param_type& p) {
- WriteParam(m, p.idb_object_store_id_);
- WriteParam(m, p.response_id_);
- WriteParam(m, p.serialized_value_);
- WriteParam(m, p.key_);
- WriteParam(m, p.add_only_);
- WriteParam(m, p.transaction_id_);
-}
-
-bool ParamTraits<ViewHostMsg_IDBObjectStorePut_Params>::Read(
- const Message* m,
- void** iter,
- param_type* p) {
- return
- ReadParam(m, iter, &p->idb_object_store_id_) &&
- ReadParam(m, iter, &p->response_id_) &&
- ReadParam(m, iter, &p->serialized_value_) &&
- ReadParam(m, iter, &p->key_) &&
- ReadParam(m, iter, &p->add_only_) &&
- ReadParam(m, iter, &p->transaction_id_);
-}
-
-void ParamTraits<ViewHostMsg_IDBObjectStorePut_Params>::Log(
- const param_type& p,
- std::string* l) {
- l->append("(");
- LogParam(p.idb_object_store_id_, l);
- l->append(", ");
- LogParam(p.response_id_, l);
- l->append(", ");
- LogParam(p.serialized_value_, l);
- l->append(", ");
- LogParam(p.key_, l);
- l->append(", ");
- LogParam(p.add_only_, l);
- l->append(", ");
- LogParam(p.transaction_id_, l);
- l->append(")");
-}
-
-void ParamTraits<ViewHostMsg_IDBObjectStoreCreateIndex_Params>::Write(
- Message* m,
- const param_type& p) {
- WriteParam(m, p.name_);
- WriteParam(m, p.key_path_);
- WriteParam(m, p.unique_);
- WriteParam(m, p.transaction_id_);
- WriteParam(m, p.idb_object_store_id_);
-}
-
-bool ParamTraits<ViewHostMsg_IDBObjectStoreCreateIndex_Params>::Read(
- const Message* m,
- void** iter,
- param_type* p) {
- return
- ReadParam(m, iter, &p->name_) &&
- ReadParam(m, iter, &p->key_path_) &&
- ReadParam(m, iter, &p->unique_) &&
- ReadParam(m, iter, &p->transaction_id_) &&
- ReadParam(m, iter, &p->idb_object_store_id_);
-}
-
-void ParamTraits<ViewHostMsg_IDBObjectStoreCreateIndex_Params>::Log(
- const param_type& p,
- std::string* l) {
- l->append("(");
- LogParam(p.name_, l);
- l->append(", ");
- LogParam(p.key_path_, l);
- l->append(", ");
- LogParam(p.unique_, l);
- l->append(", ");
- LogParam(p.transaction_id_, l);
- l->append(", ");
- LogParam(p.idb_object_store_id_, l);
- l->append(")");
-}
-
-void ParamTraits<ViewHostMsg_IDBObjectStoreOpenCursor_Params>::Write(
- Message* m,
- const param_type& p) {
- WriteParam(m, p.response_id_);
- WriteParam(m, p.lower_key_);
- WriteParam(m, p.upper_key_);
- WriteParam(m, p.lower_open_);
- WriteParam(m, p.upper_open_);
- WriteParam(m, p.direction_);
- WriteParam(m, p.idb_object_store_id_);
- WriteParam(m, p.transaction_id_);
-}
-
-bool ParamTraits<ViewHostMsg_IDBObjectStoreOpenCursor_Params>::Read(
- const Message* m,
- void** iter,
- param_type* p) {
- return
- ReadParam(m, iter, &p->response_id_) &&
- ReadParam(m, iter, &p->lower_key_) &&
- ReadParam(m, iter, &p->upper_key_) &&
- ReadParam(m, iter, &p->lower_open_) &&
- ReadParam(m, iter, &p->upper_open_) &&
- ReadParam(m, iter, &p->direction_) &&
- ReadParam(m, iter, &p->idb_object_store_id_) &&
- ReadParam(m, iter, &p->transaction_id_);
-}
-
-void ParamTraits<ViewHostMsg_IDBObjectStoreOpenCursor_Params>::Log(
- const param_type& p,
- std::string* l) {
- l->append("(");
- LogParam(p.response_id_, l);
- l->append(", ");
- LogParam(p.lower_key_, l);
- l->append(", ");
- LogParam(p.upper_key_, l);
- l->append(", ");
- LogParam(p.lower_open_, l);
- l->append(", ");
- LogParam(p.upper_open_, l);
- l->append(", ");
- LogParam(p.direction_, l);
- l->append(", ");
- LogParam(p.idb_object_store_id_, l);
- l->append(",");
- LogParam(p.transaction_id_, l);
- l->append(")");
-}
-
void ParamTraits<ViewMsg_ExecuteCode_Params>::Write(Message* m,
const param_type& p) {
WriteParam(m, p.request_id);
diff --git a/chrome/common/render_messages_params.h b/chrome/common/render_messages_params.h
index 64cf1e5..97817d2 100644
--- a/chrome/common/render_messages_params.h
+++ b/chrome/common/render_messages_params.h
@@ -16,11 +16,9 @@
#include "base/shared_memory.h"
#include "base/time.h"
#include "base/values.h"
-#include "chrome/common/dom_storage_common.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_extent.h"
#include "chrome/common/extensions/url_pattern.h"
-#include "chrome/common/indexed_db_key.h"
#include "chrome/common/navigation_gesture.h"
#include "chrome/common/navigation_types.h"
#include "chrome/common/page_transition_types.h"
@@ -34,11 +32,11 @@
#include "media/audio/audio_parameters.h"
#include "third_party/WebKit/WebKit/chromium/public/WebTextDirection.h"
#include "webkit/glue/password_form.h"
-#include "webkit/glue/plugins/webplugin.h"
#include "webkit/glue/resource_type.h"
#include "webkit/glue/webaccessibility.h"
#include "webkit/glue/webmenuitem.h"
#include "webkit/glue/webpreferences.h"
+#include "webkit/plugins/npapi/webplugin.h"
// TODO(erg): Split this file into $1_db_params.h, $1_audio_params.h,
// $1_print_params.h and $1_render_params.h.
@@ -249,7 +247,7 @@ struct ViewHostMsg_FrameNavigate_Params {
// The frame ID for this navigation. The frame ID uniquely identifies the
// frame the navigation happened in for a given renderer.
- long long frame_id;
+ int64 frame_id;
// URL of the page being loaded.
GURL url;
@@ -358,7 +356,7 @@ struct ViewHostMsg_UpdateRect_Params {
gfx::Rect resizer_rect;
// New window locations for plugin child windows.
- std::vector<webkit_glue::WebPluginGeometry> plugin_window_moves;
+ std::vector<webkit::npapi::WebPluginGeometry> plugin_window_moves;
// The following describes the various bits that may be set in flags:
//
@@ -449,7 +447,7 @@ struct ViewHostMsg_Resource_Request {
// Additional HTTP request headers.
std::string headers;
- // URLRequest load flags (0 by default).
+ // net::URLRequest load flags (0 by default).
int load_flags;
// Unique ID of process that originated this request. For normal renderer
@@ -473,6 +471,9 @@ struct ViewHostMsg_Resource_Request {
bool download_to_file;
+ // True if the request was user initiated.
+ bool has_user_gesture;
+
// The following two members are specified if the request is initiated by
// a plugin like Gears.
@@ -551,6 +552,21 @@ struct ViewMsg_PrintPages_Params {
std::vector<int> pages;
};
+//Parameters to describe a rendered document.
+struct ViewHostMsg_DidPreviewDocument_Params {
+ ViewHostMsg_DidPreviewDocument_Params();
+ ~ViewHostMsg_DidPreviewDocument_Params();
+
+ // A shared memory handle to metafile data.
+ base::SharedMemoryHandle metafile_data_handle;
+
+ // Size of metafile data.
+ uint32 data_size;
+
+ // Cookie for the document to ensure correctness.
+ int document_cookie;
+};
+
// Parameters to describe a rendered page.
struct ViewHostMsg_DidPrintPage_Params {
ViewHostMsg_DidPrintPage_Params();
@@ -632,180 +648,6 @@ struct ViewHostMsg_ScriptedPrint_Params {
bool use_overlays;
};
-// Signals a storage event.
-struct ViewMsg_DOMStorageEvent_Params {
- ViewMsg_DOMStorageEvent_Params();
- ~ViewMsg_DOMStorageEvent_Params();
-
- // The key that generated the storage event. Null if clear() was called.
- NullableString16 key_;
-
- // The old value of this key. Null on clear() or if it didn't have a value.
- NullableString16 old_value_;
-
- // The new value of this key. Null on removeItem() or clear().
- NullableString16 new_value_;
-
- // The origin this is associated with.
- string16 origin_;
-
- // The URL of the page that caused the storage event.
- GURL url_;
-
- // The storage type of this event.
- DOMStorageType storage_type_;
-};
-
-// Used to open an indexed database.
-struct ViewHostMsg_IDBFactoryOpen_Params {
- ViewHostMsg_IDBFactoryOpen_Params();
- ~ViewHostMsg_IDBFactoryOpen_Params();
-
- // The routing ID of the view initiating the open.
- int32 routing_id_;
-
- // The response should have this id.
- int32 response_id_;
-
- // The origin doing the initiating.
- string16 origin_;
-
- // The name of the database.
- string16 name_;
-
- // The description of the database.
- string16 description_;
-
- // The maximum size of the database.
- uint64 maximum_size_;
-};
-
-// Used to create an object store.
-struct ViewHostMsg_IDBDatabaseCreateObjectStore_Params {
- ViewHostMsg_IDBDatabaseCreateObjectStore_Params();
- ~ViewHostMsg_IDBDatabaseCreateObjectStore_Params();
-
- // The name of the object store.
- string16 name_;
-
- // The keyPath of the object store.
- NullableString16 key_path_;
-
- // Whether the object store created should have a key generator.
- bool auto_increment_;
-
- // The transaction this is associated with.
- int32 transaction_id_;
-
- // The database the object store belongs to.
- int32 idb_database_id_;
-};
-
-// Used to open both cursors and object cursors in IndexedDB.
-struct ViewHostMsg_IDBIndexOpenCursor_Params {
- ViewHostMsg_IDBIndexOpenCursor_Params();
- ~ViewHostMsg_IDBIndexOpenCursor_Params();
-
- // The response should have this id.
- int32 response_id_;
-
- // The serialized lower key.
- IndexedDBKey lower_key_;
-
- // The serialized upper key.
- IndexedDBKey upper_key_;
-
- // Is the lower bound open?
- bool lower_open_;
-
- // Is the upper bound open?
- bool upper_open_;
-
- // The direction of this cursor.
- int32 direction_;
-
- // The index the index belongs to.
- int32 idb_index_id_;
-
- // The transaction this request belongs to.
- int transaction_id_;
-};
-
-// Used to set a value in an object store.
-struct ViewHostMsg_IDBObjectStorePut_Params {
- ViewHostMsg_IDBObjectStorePut_Params();
- ~ViewHostMsg_IDBObjectStorePut_Params();
-
- // The object store's id.
- int32 idb_object_store_id_;
-
- // The id any response should contain.
- int32 response_id_;
-
- // The value to set.
- SerializedScriptValue serialized_value_;
-
- // The key to set it on (may not be "valid"/set in some cases).
- IndexedDBKey key_;
-
- // If it already exists, don't update (just return an error).
- bool add_only_;
-
- // The transaction it's associated with.
- int transaction_id_;
-};
-
-// Used to create an index.
-struct ViewHostMsg_IDBObjectStoreCreateIndex_Params {
- ViewHostMsg_IDBObjectStoreCreateIndex_Params();
- ~ViewHostMsg_IDBObjectStoreCreateIndex_Params();
-
- // The name of the index.
- string16 name_;
-
- // The keyPath of the index.
- NullableString16 key_path_;
-
- // Whether the index created has unique keys.
- bool unique_;
-
- // The transaction this is associated with.
- int32 transaction_id_;
-
- // The object store the index belongs to.
- int32 idb_object_store_id_;
-};
-
-// Used to open an IndexedDB cursor.
-struct ViewHostMsg_IDBObjectStoreOpenCursor_Params {
- ViewHostMsg_IDBObjectStoreOpenCursor_Params();
- ~ViewHostMsg_IDBObjectStoreOpenCursor_Params();
-
- // The response should have this id.
- int32 response_id_;
-
- // The serialized lower key.
- IndexedDBKey lower_key_;
-
- // The serialized upper key.
- IndexedDBKey upper_key_;
-
- // Is the lower bound open?
- bool lower_open_;
-
- // Is the upper bound open?
- bool upper_open_;
-
- // The direction of this cursor.
- int32 direction_;
-
- // The object store the cursor belongs to.
- int32 idb_object_store_id_;
-
- // The transaction this request belongs to.
- int transaction_id_;
-};
-
// Allows an extension to execute code in a tab.
struct ViewMsg_ExecuteCode_Params {
ViewMsg_ExecuteCode_Params();
@@ -1159,6 +1001,14 @@ struct ParamTraits<ViewMsg_PrintPages_Params> {
};
template <>
+struct ParamTraits<ViewHostMsg_DidPreviewDocument_Params> {
+ typedef ViewHostMsg_DidPreviewDocument_Params param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
struct ParamTraits<ViewHostMsg_DidPrintPage_Params> {
typedef ViewHostMsg_DidPrintPage_Params param_type;
static void Write(Message* m, const param_type& p);
@@ -1191,62 +1041,6 @@ struct ParamTraits<ViewHostMsg_ScriptedPrint_Params> {
};
template <>
-struct ParamTraits<ViewMsg_DOMStorageEvent_Params> {
- typedef ViewMsg_DOMStorageEvent_Params param_type;
- static void Write(Message* m, const param_type& p);
- static bool Read(const Message* m, void** iter, param_type* p);
- static void Log(const param_type& p, std::string* l);
-};
-
-template <>
-struct ParamTraits<ViewHostMsg_IDBFactoryOpen_Params> {
- typedef ViewHostMsg_IDBFactoryOpen_Params param_type;
- static void Write(Message* m, const param_type& p);
- static bool Read(const Message* m, void** iter, param_type* p);
- static void Log(const param_type& p, std::string* l);
-};
-
-template <>
-struct ParamTraits<ViewHostMsg_IDBDatabaseCreateObjectStore_Params> {
- typedef ViewHostMsg_IDBDatabaseCreateObjectStore_Params param_type;
- static void Write(Message* m, const param_type& p);
- static bool Read(const Message* m, void** iter, param_type* p);
- static void Log(const param_type& p, std::string* l);
-};
-
-template <>
-struct ParamTraits<ViewHostMsg_IDBIndexOpenCursor_Params> {
- typedef ViewHostMsg_IDBIndexOpenCursor_Params param_type;
- static void Write(Message* m, const param_type& p);
- static bool Read(const Message* m, void** iter, param_type* p);
- static void Log(const param_type& p, std::string* l);
-};
-
-template <>
-struct ParamTraits<ViewHostMsg_IDBObjectStorePut_Params> {
- typedef ViewHostMsg_IDBObjectStorePut_Params param_type;
- static void Write(Message* m, const param_type& p);
- static bool Read(const Message* m, void** iter, param_type* p);
- static void Log(const param_type& p, std::string* l);
-};
-
-template <>
-struct ParamTraits<ViewHostMsg_IDBObjectStoreCreateIndex_Params> {
- typedef ViewHostMsg_IDBObjectStoreCreateIndex_Params param_type;
- static void Write(Message* m, const param_type& p);
- static bool Read(const Message* m, void** iter, param_type* p);
- static void Log(const param_type& p, std::string* l);
-};
-
-template <>
-struct ParamTraits<ViewHostMsg_IDBObjectStoreOpenCursor_Params> {
- typedef ViewHostMsg_IDBObjectStoreOpenCursor_Params param_type;
- static void Write(Message* m, const param_type& p);
- static bool Read(const Message* m, void** iter, param_type* p);
- static void Log(const param_type& p, std::string* l);
-};
-
-template<>
struct ParamTraits<ViewMsg_ExecuteCode_Params> {
typedef ViewMsg_ExecuteCode_Params param_type;
static void Write(Message* m, const param_type& p);
diff --git a/chrome/common/resource_dispatcher.cc b/chrome/common/resource_dispatcher.cc
index aff0367..e4747b9 100644
--- a/chrome/common/resource_dispatcher.cc
+++ b/chrome/common/resource_dispatcher.cc
@@ -111,6 +111,7 @@ IPCResourceLoaderBridge::IPCResourceLoaderBridge(
request_.request_context = request_info.request_context;
request_.appcache_host_id = request_info.appcache_host_id;
request_.download_to_file = request_info.download_to_file;
+ request_.has_user_gesture = request_info.has_user_gesture;
request_.host_renderer_id = host_renderer_id_;
request_.host_render_view_id = host_render_view_id_;
}
@@ -401,11 +402,6 @@ void ResourceDispatcher::OnReceivedRedirect(
if (request_info->peer->OnReceivedRedirect(new_url, info,
&has_new_first_party_for_cookies,
&new_first_party_for_cookies)) {
- // Double-check if the request is still around. The call above could
- // potentially remove it.
- request_info = GetPendingRequestInfo(request_id);
- if (!request_info)
- return;
request_info->pending_redirect_message.reset(
new ViewHostMsg_FollowRedirect(routing_id, request_id,
has_new_first_party_for_cookies,
diff --git a/chrome/common/resource_dispatcher.h b/chrome/common/resource_dispatcher.h
index 3ca3492..52c6589 100644
--- a/chrome/common/resource_dispatcher.h
+++ b/chrome/common/resource_dispatcher.h
@@ -23,13 +23,12 @@ struct ResourceResponseHead;
// This class serves as a communication interface between the
// ResourceDispatcherHost in the browser process and the ResourceLoaderBridge in
// the child process. It can be used from any child process.
-class ResourceDispatcher {
+class ResourceDispatcher : public IPC::Channel::Listener {
public:
explicit ResourceDispatcher(IPC::Message::Sender* sender);
~ResourceDispatcher();
- // Called to possibly handle the incoming IPC message. Returns true if
- // handled, else false.
+ // IPC::Channel::Listener implementation.
bool OnMessageReceived(const IPC::Message& message);
// Creates a ResourceLoaderBridge for this type of dispatcher, this is so
diff --git a/chrome/common/result_codes.h b/chrome/common/result_codes.h
index 6625cb0..ae842bb 100644
--- a/chrome/common/result_codes.h
+++ b/chrome/common/result_codes.h
@@ -21,9 +21,9 @@
class ResultCodes {
public:
enum ExitCode {
- NORMAL_EXIT = base::PROCESS_END_NORMAL_TERMINATION,
- TASKMAN_KILL = base::PROCESS_END_KILLED_BY_USER,
- HUNG = base::PROCESS_END_PROCESS_WAS_HUNG,
+ NORMAL_EXIT = 0, // Process terminated normally.
+ KILLED = 1, // Process was killed by user or system.
+ HUNG = 2, // Process hung.
INVALID_CMDLINE_URL, // An invalid command line url was given.
SBOX_INIT_FAILED, // The sandbox could not be initialized.
GOOGLE_UPDATE_INIT_FAILED, // The Google Update client stub init failed.
@@ -58,6 +58,7 @@ class ResultCodes {
PROFILE_IN_USE, // The profile was in use on another host.
UNINSTALL_EXTENSION_ERROR, // Failed to silently uninstall an extension.
+ PACK_EXTENSION_ERROR, // Failed to pack an extension via the cmd line.
EXIT_LAST_CODE // Last return code (keep it last).
};
diff --git a/chrome/common/sandbox_init_wrapper.h b/chrome/common/sandbox_init_wrapper.h
index 56716fc..3c70a7a 100644
--- a/chrome/common/sandbox_init_wrapper.h
+++ b/chrome/common/sandbox_init_wrapper.h
@@ -32,8 +32,9 @@ class SandboxInitWrapper {
sandbox::BrokerServices* BrokerServices() const { return broker_services_; }
sandbox::TargetServices* TargetServices() const { return target_services_; }
- // Initialize the sandbox for renderer and plug-in processes, depending on
- // the command line flags. The browser process is not sandboxed.
+ // Initialize the sandbox for renderer, gpu, utility, worker, nacl, and
+ // plug-in processes, depending on the command line flags. The browser
+ // process is not sandboxed.
// Returns true if the sandbox was initialized succesfully, false if an error
// occurred. If process_type isn't one that needs sandboxing true is always
// returned.
diff --git a/chrome/common/sandbox_init_wrapper_mac.cc b/chrome/common/sandbox_init_wrapper_mac.cc
index adffd0c..b9cfa50 100644
--- a/chrome/common/sandbox_init_wrapper_mac.cc
+++ b/chrome/common/sandbox_init_wrapper_mac.cc
@@ -54,9 +54,10 @@ bool SandboxInitWrapper::InitializeSandbox(const CommandLine& command_line,
} else if (process_type == switches::kNaClLoaderProcess) {
// Native Client sel_ldr (user untrusted code) sandbox.
sandbox_process_type = Sandbox::SANDBOX_TYPE_NACL_LOADER;
+ } else if (process_type == switches::kGpuProcess) {
+ sandbox_process_type = Sandbox::SANDBOX_TYPE_GPU;
} else if ((process_type == switches::kPluginProcess) ||
(process_type == switches::kProfileImportProcess) ||
- (process_type == switches::kGpuProcess) ||
(process_type == switches::kServiceProcess)) {
return true;
} else {
@@ -67,7 +68,7 @@ bool SandboxInitWrapper::InitializeSandbox(const CommandLine& command_line,
}
// Warm up APIs before turning on the sandbox.
- Sandbox::SandboxWarmup();
+ Sandbox::SandboxWarmup(sandbox_process_type);
// Actually sandbox the process.
return Sandbox::EnableSandbox(sandbox_process_type, allowed_dir);
diff --git a/chrome/common/sandbox_mac.h b/chrome/common/sandbox_mac.h
index f16fdb5..e81f72e 100644
--- a/chrome/common/sandbox_mac.h
+++ b/chrome/common/sandbox_mac.h
@@ -75,12 +75,15 @@ class Sandbox {
// Native Client sandbox for the user's untrusted code.
SANDBOX_TYPE_NACL_LOADER,
+ // GPU process.
+ SANDBOX_TYPE_GPU,
+
SANDBOX_AFTER_TYPE_LAST_TYPE, // Placeholder to ease iteration.
};
// Warm up System APIs that empirically need to be accessed before the Sandbox
- // is turned on.
- static void SandboxWarmup();
+ // is turned on. |sandbox_type| is the type of sandbox to warm up.
+ static void SandboxWarmup(SandboxProcessType sandbox_type);
// Turns on the OS X sandbox for this process.
// |sandbox_type| - type of Sandbox to use.
diff --git a/chrome/common/sandbox_mac.mm b/chrome/common/sandbox_mac.mm
index 81defc7..b5f9d22 100644
--- a/chrome/common/sandbox_mac.mm
+++ b/chrome/common/sandbox_mac.mm
@@ -7,11 +7,15 @@
#include "base/debug_util.h"
#import <Cocoa/Cocoa.h>
+#import <OpenGL/OpenGL.h>
+
extern "C" {
#include <sandbox.h>
}
+#include <signal.h>
#include <sys/param.h>
+#include "app/gfx/gl/gl_context.h"
#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/file_util.h"
@@ -24,6 +28,7 @@ extern "C" {
#include "base/sys_info.h"
#include "base/sys_string_conversions.h"
#include "base/utf_string_conversions.h"
+#include "chrome/common/chrome_application_mac.h"
#include "chrome/common/chrome_switches.h"
#include "unicode/uchar.h"
@@ -177,7 +182,7 @@ bool Sandbox::QuoteStringForRegex(const std::string& str_utf8,
// 10.5.6, 10.6.0
// static
-void Sandbox::SandboxWarmup() {
+void Sandbox::SandboxWarmup(SandboxProcessType sandbox_type) {
base::mac::ScopedNSAutoreleasePool scoped_pool;
{ // CGColorSpaceCreateWithName(), CGBitmapContextCreate() - 10.5.6
@@ -228,8 +233,41 @@ void Sandbox::SandboxWarmup() {
CGImageSourceGetStatus(img);
}
- { // Native Client access to /dev/random.
- GetUrandomFD();
+ // Process-type dependent warm-up.
+ switch (sandbox_type) {
+ case SANDBOX_TYPE_NACL_LOADER:
+ {
+ // Native Client access to /dev/random.
+ GetUrandomFD();
+ }
+ break;
+
+ case SANDBOX_TYPE_GPU:
+ { // GPU-related stuff is very slow without this, probably because
+ // the sandbox prevents loading graphics drivers or some such.
+ CGLPixelFormatAttribute attribs[] = { (CGLPixelFormatAttribute)0 };
+ CGLPixelFormatObj format;
+ GLint n;
+ CGLChoosePixelFormat(attribs, &format, &n);
+ if (format)
+ CGLReleasePixelFormat(format);
+ }
+
+ {
+ // Preload either the desktop GL or the osmesa so, depending on the
+ // --use-gl flag.
+ gfx::GLContext::InitializeOneOff();
+ }
+
+ {
+ // Access to /dev/random is required for the field trial code.
+ GetUrandomFD();
+ }
+ break;
+
+ default:
+ // To shut up a gcc warning.
+ break;
}
}
@@ -314,6 +352,9 @@ NSString* LoadSandboxTemplate(Sandbox::SandboxProcessType sandbox_type) {
// untrusted code within Native Client.
sandbox_config_filename = @"nacl_loader";
break;
+ case Sandbox::SANDBOX_TYPE_GPU:
+ sandbox_config_filename = @"gpu";
+ break;
default:
NOTREACHED();
return nil;
@@ -465,7 +506,7 @@ bool Sandbox::EnableSandbox(SandboxProcessType sandbox_type,
// Enable verbose logging if enabled on the command line. (See common.sb
// for details).
- const CommandLine *command_line = CommandLine::ForCurrentProcess();
+ const CommandLine* command_line = CommandLine::ForCurrentProcess();
bool enable_logging =
command_line->HasSwitch(switches::kEnableSandboxLogging);;
if (enable_logging) {
diff --git a/chrome/common/sandbox_mac_unittest_helper.mm b/chrome/common/sandbox_mac_unittest_helper.mm
index 4e885b5..aff7471 100644
--- a/chrome/common/sandbox_mac_unittest_helper.mm
+++ b/chrome/common/sandbox_mac_unittest_helper.mm
@@ -50,13 +50,14 @@ void AddSandboxTestCase(const char* test_name, MacSandboxTestCase* test_class) {
} // namespace internal
-bool MacSandboxTest:: RunTestInAllSandboxTypes(const char* test_name,
- const char* test_data) {
+bool MacSandboxTest::RunTestInAllSandboxTypes(const char* test_name,
+ const char* test_data) {
// Go through all the sandbox types, and run the test case in each of them
// if one fails, abort.
for(int i = static_cast<int>(Sandbox::SANDBOX_TYPE_FIRST_TYPE);
i < Sandbox::SANDBOX_AFTER_TYPE_LAST_TYPE;
++i) {
+
if (!RunTestInSandbox(static_cast<Sandbox::SandboxProcessType>(i),
test_name, test_data)) {
LOG(ERROR) << "Sandboxed test (" << test_name << ")" <<
@@ -143,7 +144,7 @@ MULTIPROCESS_TEST_MAIN(mac_sandbox_test_runner) {
return -1;
}
- Sandbox::SandboxWarmup();
+ Sandbox::SandboxWarmup(sandbox_type);
if (!Sandbox::EnableSandbox(sandbox_type, FilePath())) {
LOG(ERROR) << "Failed to initialize sandbox " << sandbox_type;
diff --git a/chrome/common/sandbox_policy.cc b/chrome/common/sandbox_policy.cc
index 75e6469..2667cf9 100644
--- a/chrome/common/sandbox_policy.cc
+++ b/chrome/common/sandbox_policy.cc
@@ -116,29 +116,28 @@ PluginPolicyCategory GetPolicyCategoryForPlugin(
bool AddDirectory(int path, const wchar_t* sub_dir, bool children,
sandbox::TargetPolicy::Semantics access,
sandbox::TargetPolicy* policy) {
- std::wstring directory;
+ FilePath directory;
if (!PathService::Get(path, &directory))
return false;
if (sub_dir) {
- file_util::AppendToPath(&directory, sub_dir);
+ directory = directory.Append(sub_dir);
file_util::AbsolutePath(&directory);
}
sandbox::ResultCode result;
result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, access,
- directory.c_str());
+ directory.value().c_str());
if (result != sandbox::SBOX_ALL_OK)
return false;
+ std::wstring directory_str = directory.value() + L"\\";
if (children)
- file_util::AppendToPath(&directory, L"*");
- else
- // Add the version of the path that ends with a separator.
- file_util::AppendToPath(&directory, L"");
+ directory_str += L"*";
+ // Otherwise, add the version of the path that ends with a separator.
result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, access,
- directory.c_str());
+ directory_str.c_str());
if (result != sandbox::SBOX_ALL_OK)
return false;
@@ -198,10 +197,11 @@ bool AddGenericPolicy(sandbox::TargetPolicy* policy) {
// Add the policy for debug message only in debug
#ifndef NDEBUG
- std::wstring debug_message;
- if (!PathService::Get(chrome::DIR_APP, &debug_message))
+ FilePath app_dir;
+ if (!PathService::Get(chrome::DIR_APP, &app_dir))
return false;
- if (!win_util::ConvertToLongPath(debug_message, &debug_message))
+ std::wstring debug_message;
+ if (!win_util::ConvertToLongPath(app_dir.value(), &debug_message))
return false;
file_util::AppendToPath(&debug_message, L"debug_message.exe");
result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_PROCESS,
@@ -532,7 +532,7 @@ base::ProcessHandle StartProcessWithAccess(CommandLine* cmd_line,
if (!in_sandbox && (type == ChildProcessInfo::PLUGIN_PROCESS)) {
in_sandbox = browser_command_line.HasSwitch(switches::kSafePlugins) ||
(IsBuiltInFlash(cmd_line, NULL) &&
- browser_command_line.HasSwitch(switches::kEnableFlashSandbox));
+ !browser_command_line.HasSwitch(switches::kDisableFlashSandbox));
}
if (browser_command_line.HasSwitch(switches::kNoSandbox)) {
diff --git a/chrome/common/security_filter_peer.h b/chrome/common/security_filter_peer.h
index 2559bf3..e82f748 100644
--- a/chrome/common/security_filter_peer.h
+++ b/chrome/common/security_filter_peer.h
@@ -110,10 +110,10 @@ class ReplaceContentPeer : public SecurityFilterPeer {
virtual void OnReceivedResponse(
const webkit_glue::ResourceResponseInfo& info,
bool content_filtered);
- void OnReceivedData(const char* data, int len);
- void OnCompletedRequest(const URLRequestStatus& status,
- const std::string& security_info,
- const base::Time& completion_time);
+ virtual void OnReceivedData(const char* data, int len);
+ virtual void OnCompletedRequest(const URLRequestStatus& status,
+ const std::string& security_info,
+ const base::Time& completion_time);
private:
webkit_glue::ResourceResponseInfo response_info_;
diff --git a/chrome/common/service_messages.cc b/chrome/common/service_messages.cc
index 97a10fd..b221881 100644
--- a/chrome/common/service_messages.cc
+++ b/chrome/common/service_messages.cc
@@ -2,8 +2,46 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "chrome/common/remoting/chromoting_host_info.h"
+#include "ipc/ipc_channel_handle.h"
+
+#define IPC_MESSAGE_IMPL
#include "chrome/common/service_messages.h"
-#define MESSAGES_INTERNAL_IMPL_FILE \
- "chrome/common/service_messages_internal.h"
-#include "ipc/ipc_message_impl_macros.h"
+namespace IPC {
+
+void ParamTraits<remoting::ChromotingHostInfo> ::Write(
+ Message* m, const param_type& p) {
+ WriteParam(m, p.host_id);
+ WriteParam(m, p.hostname);
+ WriteParam(m, p.public_key);
+ WriteParam(m, p.enabled);
+ WriteParam(m, p.login);
+}
+
+bool ParamTraits<remoting::ChromotingHostInfo> ::Read(
+ const Message* m, void** iter, param_type* p) {
+ bool ret = ReadParam(m, iter, &p->host_id);
+ ret = ret && ReadParam(m, iter, &p->hostname);
+ ret = ret && ReadParam(m, iter, &p->public_key);
+ ret = ret && ReadParam(m, iter, &p->enabled);
+ ret = ret && ReadParam(m, iter, &p->login);
+ return ret;
+}
+
+void ParamTraits<remoting::ChromotingHostInfo> ::Log(
+ const param_type& p, std::string* l) {
+ l->append("(");
+ LogParam(p.host_id, l);
+ l->append(", ");
+ LogParam(p.hostname, l);
+ l->append(", ");
+ LogParam(p.public_key, l);
+ l->append(", ");
+ LogParam(p.enabled, l);
+ l->append(", ");
+ LogParam(p.login, l);
+ l->append(")");
+}
+
+} // namespace IPC
diff --git a/chrome/common/service_messages.h b/chrome/common/service_messages.h
index d514bff..1f8d75e 100644
--- a/chrome/common/service_messages.h
+++ b/chrome/common/service_messages.h
@@ -5,10 +5,22 @@
#ifndef CHROME_COMMON_SERVICE_MESSAGES_H_
#define CHROME_COMMON_SERVICE_MESSAGES_H_
-#include "ipc/ipc_message_utils.h"
+#include "chrome/common/service_messages_internal.h"
-#define MESSAGES_INTERNAL_FILE "chrome/common/service_messages_internal.h"
-#include "ipc/ipc_message_macros.h"
+namespace remoting {
+struct ChromotingHostInfo;
+} // namespace remoting
-#endif // CHROME_COMMON_SERVICE_MESSAGES_H_
+namespace IPC {
+
+template <>
+struct ParamTraits<remoting::ChromotingHostInfo> {
+ typedef remoting::ChromotingHostInfo param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
+};
+} // namespace IPC
+
+#endif // CHROME_COMMON_SERVICE_MESSAGES_H_
diff --git a/chrome/common/service_messages_internal.h b/chrome/common/service_messages_internal.h
index bb6e34d..94a0215 100644
--- a/chrome/common/service_messages_internal.h
+++ b/chrome/common/service_messages_internal.h
@@ -4,66 +4,67 @@
#include <string>
-// This header is meant to be included in multiple passes, hence no traditional
-// header guard.
-// See ipc_message_macros.h for explanation of the macros and passes.
-
-// This file needs to be included again, even though we're actually included
-// from it via utility_messages.h.
#include "ipc/ipc_message_macros.h"
+#include "chrome/common/remoting/chromoting_host_info.h"
+
+#define IPC_MESSAGE_START ServiceMsgStart
+
//------------------------------------------------------------------------------
// Service process messages:
// These are messages from the browser to the service process.
-IPC_BEGIN_MESSAGES(Service)
+// Tell the service process to enable the cloud proxy passing in the lsid
+// of the account to be used.
+IPC_MESSAGE_CONTROL1(ServiceMsg_EnableCloudPrintProxy,
+ std::string /* lsid */)
+// Tell the service process to enable the cloud proxy passing in specific
+// tokens to be used.
+IPC_MESSAGE_CONTROL2(ServiceMsg_EnableCloudPrintProxyWithTokens,
+ std::string, /* token for cloudprint service */
+ std::string /* token for Google Talk service */)
+// Tell the service process to disable the cloud proxy.
+IPC_MESSAGE_CONTROL0(ServiceMsg_DisableCloudPrintProxy)
- // Tell the service process to enable the cloud proxy passing in the lsid
- // of the account to be used.
- IPC_MESSAGE_CONTROL1(ServiceMsg_EnableCloudPrintProxy,
- std::string /* lsid */)
- // Tell the service process to enable the cloud proxy passing in specific
- // tokens to be used.
- IPC_MESSAGE_CONTROL2(ServiceMsg_EnableCloudPrintProxyWithTokens,
- std::string, /* token for cloudprint service */
- std::string /* token for Google Talk service */)
- // Tell the service process to disable the cloud proxy.
- IPC_MESSAGE_CONTROL0(ServiceMsg_DisableCloudPrintProxy)
+// Requests a message back on whether the cloud print proxy is
+// enabled.
+IPC_MESSAGE_CONTROL0(ServiceMsg_IsCloudPrintProxyEnabled)
- // Requests a message back on whether the cloud print proxy is
- // enabled.
- IPC_MESSAGE_CONTROL0(ServiceMsg_IsCloudPrintProxyEnabled)
+// This message is for testing purpose.
+IPC_MESSAGE_CONTROL0(ServiceMsg_Hello)
- // This message is for testing purpose.
- IPC_MESSAGE_CONTROL0(ServiceMsg_Hello)
+// Set credentials used by the RemotingHost.
+IPC_MESSAGE_CONTROL2(ServiceMsg_SetRemotingHostCredentials,
+ std::string, /* username */
+ std::string /* token for XMPP */)
- // This message is for enabling the remoting process.
- IPC_MESSAGE_CONTROL3(ServiceMsg_EnableRemotingWithTokens,
- std::string, /* username */
- std::string, /* Token for remoting */
- std::string /* Token for Google Talk */)
+// Enabled remoting host.
+IPC_MESSAGE_CONTROL0(ServiceMsg_EnableRemotingHost)
- // Tell the service process to shutdown.
- IPC_MESSAGE_CONTROL0(ServiceMsg_Shutdown)
+// Disable remoting host.
+IPC_MESSAGE_CONTROL0(ServiceMsg_DisableRemotingHost)
- // Tell the service process that an update is available.
- IPC_MESSAGE_CONTROL0(ServiceMsg_UpdateAvailable)
+// Get remoting host status information.
+IPC_MESSAGE_CONTROL0(ServiceMsg_GetRemotingHostInfo)
-IPC_END_MESSAGES(Service)
+// Tell the service process to shutdown.
+IPC_MESSAGE_CONTROL0(ServiceMsg_Shutdown)
+
+// Tell the service process that an update is available.
+IPC_MESSAGE_CONTROL0(ServiceMsg_UpdateAvailable)
//------------------------------------------------------------------------------
// Service process host messages:
// These are messages from the service process to the browser.
-IPC_BEGIN_MESSAGES(ServiceHost)
-
- // Sent when the cloud print proxy has an authentication error.
- IPC_MESSAGE_CONTROL0(ServiceHostMsg_CloudPrintProxy_AuthError)
+// Sent when the cloud print proxy has an authentication error.
+IPC_MESSAGE_CONTROL0(ServiceHostMsg_CloudPrintProxy_AuthError)
- // Sent as a response to a request for enablement status.
- IPC_MESSAGE_CONTROL2(ServiceHostMsg_CloudPrintProxy_IsEnabled,
- bool, /* Is the proxy enabled? */
- std::string /* Email address of account */)
+// Sent as a response to a request for enablement status.
+IPC_MESSAGE_CONTROL2(ServiceHostMsg_CloudPrintProxy_IsEnabled,
+ bool, /* Is the proxy enabled? */
+ std::string /* Email address of account */)
- // Sent from the service process in response to a Hello message.
- IPC_MESSAGE_CONTROL0(ServiceHostMsg_GoodDay)
+IPC_MESSAGE_CONTROL1(ServiceHostMsg_RemotingHost_HostInfo,
+ remoting::ChromotingHostInfo /* host_info */)
-IPC_END_MESSAGES(ServiceHost)
+// Sent from the service process in response to a Hello message.
+IPC_MESSAGE_CONTROL0(ServiceHostMsg_GoodDay)
diff --git a/chrome/common/service_process_util.cc b/chrome/common/service_process_util.cc
index 489610a..bcbac69 100644
--- a/chrome/common/service_process_util.cc
+++ b/chrome/common/service_process_util.cc
@@ -6,14 +6,15 @@
#include "base/logging.h"
#include "base/path_service.h"
#include "base/process_util.h"
+#include "base/singleton.h"
#include "base/string16.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
+#include "base/version.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/service_process_util.h"
-#include "chrome/installer/util/version.h"
namespace {
@@ -74,9 +75,7 @@ ServiceProcessRunningState GetServiceProcessRunningState(
if (service_version_out)
*service_version_out = version;
- scoped_ptr<installer::Version> service_version;
- service_version.reset(
- installer::Version::GetVersionFromString(ASCIIToUTF16(version)));
+ scoped_ptr<Version> service_version(Version::GetVersionFromString(version));
// If the version string is invalid, treat it like an older version.
if (!service_version.get())
return SERVICE_OLDER_VERSION_RUNNING;
@@ -89,9 +88,8 @@ ServiceProcessRunningState GetServiceProcessRunningState(
// are out of date.
return SERVICE_NEWER_VERSION_RUNNING;
}
- scoped_ptr<installer::Version> running_version(
- installer::Version::GetVersionFromString(
- ASCIIToUTF16(version_info.Version())));
+ scoped_ptr<Version> running_version(Version::GetVersionFromString(
+ version_info.Version()));
if (!running_version.get()) {
NOTREACHED() << "Failed to parse version info";
// Our own version is invalid. This is an error case. Pretend that we
@@ -99,9 +97,9 @@ ServiceProcessRunningState GetServiceProcessRunningState(
return SERVICE_NEWER_VERSION_RUNNING;
}
- if (running_version->IsHigherThan(service_version.get())) {
+ if (running_version->CompareTo(*service_version) > 0) {
return SERVICE_OLDER_VERSION_RUNNING;
- } else if (service_version->IsHigherThan(running_version.get())) {
+ } else if (service_version->CompareTo(*running_version) > 0) {
return SERVICE_NEWER_VERSION_RUNNING;
}
return SERVICE_SAME_VERSION_RUNNING;
@@ -156,6 +154,11 @@ ServiceProcessState::~ServiceProcessState() {
TearDownState();
}
+// static
+ServiceProcessState* ServiceProcessState::GetInstance() {
+ return Singleton<ServiceProcessState>::get();
+}
+
bool ServiceProcessState::Initialize() {
if (!TakeSingletonLock()) {
return false;
diff --git a/chrome/common/service_process_util.h b/chrome/common/service_process_util.h
index 28304e1..6f2685e 100644
--- a/chrome/common/service_process_util.h
+++ b/chrome/common/service_process_util.h
@@ -12,6 +12,8 @@
#include "base/shared_memory.h"
#include "base/task.h"
+template <typename T> struct DefaultSingletonTraits;
+
// Return the IPC channel to connect to the service process.
//
std::string GetServiceProcessChannelName();
@@ -48,11 +50,11 @@ bool ForceServiceProcessShutdown(const std::string& version);
// and this class are shared.
class ServiceProcessState {
public:
- ServiceProcessState();
- ~ServiceProcessState();
+ // Returns the singleton instance.
+ static ServiceProcessState* GetInstance();
// Tries to become the sole service process for the current user data dir.
- // Returns false is another service process is already running.
+ // Returns false if another service process is already running.
bool Initialize();
// Signal that the service process is ready.
@@ -69,7 +71,10 @@ class ServiceProcessState {
// Unregister the service process to run on startup.
bool RemoveFromAutoRun();
+
private:
+ ServiceProcessState();
+ ~ServiceProcessState();
// Create the shared memory data for the service process.
bool CreateSharedData();
@@ -95,6 +100,8 @@ class ServiceProcessState {
struct StateData;
StateData* state_;
scoped_ptr<base::SharedMemory> shared_mem_service_data_;
+
+ friend struct DefaultSingletonTraits<ServiceProcessState>;
};
#endif // CHROME_COMMON_SERVICE_PROCESS_UTIL_H_
diff --git a/chrome/common/service_process_util_unittest.cc b/chrome/common/service_process_util_unittest.cc
index 6000b5c..58b68e1 100644
--- a/chrome/common/service_process_util_unittest.cc
+++ b/chrome/common/service_process_util_unittest.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/at_exit.h"
#include "base/process_util.h"
#include "base/string_util.h"
#include "chrome/common/chrome_version_info.h"
@@ -18,18 +19,28 @@ TEST(ServiceProcessUtilTest, ScopedVersionedName) {
EXPECT_NE(std::string::npos, scoped_name.find(version_info.Version()));
}
+class ServiceProcessStateTest : public testing::Test {
+ private:
+ // This is used to release the ServiceProcessState singleton after each test.
+ base::ShadowingAtExitManager at_exit_manager_;
+};
+
#if defined(OS_WIN)
// Singleton-ness is only implemented on Windows.
-TEST(ServiceProcessStateTest, Singleton) {
+// TODO(sanjeev): Rewrite this test to spawn a new process and test using the
+// ServiceProcessState singleton across processes.
+/*
+TEST_F(ServiceProcessStateTest, Singleton) {
ServiceProcessState state;
EXPECT_TRUE(state.Initialize());
// The second instance should fail to Initialize.
ServiceProcessState another_state;
EXPECT_FALSE(another_state.Initialize());
}
+*/
#endif // defined(OS_WIN)
-TEST(ServiceProcessStateTest, ReadyState) {
+TEST_F(ServiceProcessStateTest, ReadyState) {
#if defined(OS_WIN)
// On Posix, we use a lock file on disk to signal readiness. This lock file
// could be lying around from previous crashes which could cause
@@ -38,15 +49,15 @@ TEST(ServiceProcessStateTest, ReadyState) {
// Posix, this check will only execute on Windows.
EXPECT_FALSE(CheckServiceProcessReady());
#endif // defined(OS_WIN)
- ServiceProcessState state;
- EXPECT_TRUE(state.Initialize());
- state.SignalReady(NULL);
+ ServiceProcessState* state = ServiceProcessState::GetInstance();
+ EXPECT_TRUE(state->Initialize());
+ state->SignalReady(NULL);
EXPECT_TRUE(CheckServiceProcessReady());
- state.SignalStopped();
+ state->SignalStopped();
EXPECT_FALSE(CheckServiceProcessReady());
}
-TEST(ServiceProcessStateTest, SharedMem) {
+TEST_F(ServiceProcessStateTest, SharedMem) {
#if defined(OS_WIN)
// On Posix, named shared memory uses a file on disk. This file
// could be lying around from previous crashes which could cause
@@ -55,8 +66,8 @@ TEST(ServiceProcessStateTest, SharedMem) {
// implementation on Posix, this check will only execute on Windows.
EXPECT_EQ(0, GetServiceProcessPid());
#endif // defined(OS_WIN)
- ServiceProcessState state;
- EXPECT_TRUE(state.Initialize());
+ ServiceProcessState* state = ServiceProcessState::GetInstance();
+ EXPECT_TRUE(state->Initialize());
EXPECT_EQ(base::GetCurrentProcId(), GetServiceProcessPid());
}
diff --git a/chrome/common/socket_stream_dispatcher.h b/chrome/common/socket_stream_dispatcher.h
index e0bf58f..01c5421 100644
--- a/chrome/common/socket_stream_dispatcher.h
+++ b/chrome/common/socket_stream_dispatcher.h
@@ -9,10 +9,7 @@
#include <vector>
#include "base/basictypes.h"
-
-namespace IPC {
-class Message;
-}
+#include "ipc/ipc_channel.h"
namespace WebKit {
class WebSocketStreamHandle;
@@ -27,7 +24,7 @@ class WebSocketStreamHandleDelegate;
// main browser process. There is one instance per child process. Messages
// are dispatched on the main child thread. The RenderThread class
// creates an instance of SocketStreamDispatcher and delegates calls to it.
-class SocketStreamDispatcher {
+class SocketStreamDispatcher : public IPC::Channel::Listener {
public:
SocketStreamDispatcher();
~SocketStreamDispatcher() {}
@@ -35,6 +32,8 @@ class SocketStreamDispatcher {
static webkit_glue::WebSocketStreamHandleBridge* CreateBridge(
WebKit::WebSocketStreamHandle* handle,
webkit_glue::WebSocketStreamHandleDelegate* delegate);
+
+ // IPC::Channel::Listener implementation.
bool OnMessageReceived(const IPC::Message& msg);
private:
diff --git a/chrome/common/sqlite_utils.cc b/chrome/common/sqlite_utils.cc
index d11b925..9d16c7f 100644
--- a/chrome/common/sqlite_utils.cc
+++ b/chrome/common/sqlite_utils.cc
@@ -8,8 +8,8 @@
#include "base/file_path.h"
#include "base/lock.h"
+#include "base/lazy_instance.h"
#include "base/logging.h"
-#include "base/singleton.h"
#include "base/stl_util-inl.h"
#include "base/string16.h"
@@ -76,10 +76,13 @@ class DefaultSQLErrorHandlerFactory : public SQLErrorHandlerFactory {
Lock lock_;
};
+static base::LazyInstance<DefaultSQLErrorHandlerFactory>
+ g_default_sql_error_handler_factory(base::LINKER_INITIALIZED);
+
SQLErrorHandlerFactory* GetErrorHandlerFactory() {
// TODO(cpu): Testing needs to override the error handler.
// Destruction of DefaultSQLErrorHandlerFactory handled by at_exit manager.
- return Singleton<DefaultSQLErrorHandlerFactory>::get();
+ return g_default_sql_error_handler_factory.Pointer();
}
namespace sqlite_utils {
diff --git a/chrome/common/time_format.cc b/chrome/common/time_format.cc
index c62f4f5..9de3a40 100644
--- a/chrome/common/time_format.cc
+++ b/chrome/common/time_format.cc
@@ -7,9 +7,9 @@
#include <vector>
#include "app/l10n_util.h"
+#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
-#include "base/singleton.h"
#include "base/stl_util-inl.h"
#include "base/string16.h"
#include "base/time.h"
@@ -168,8 +168,7 @@ class TimeFormatter {
STLDeleteContainerPointers(time_elapsed_formatter_.begin(),
time_elapsed_formatter_.end());
}
- friend class Singleton<TimeFormatter>;
- friend struct DefaultSingletonTraits<TimeFormatter>;
+ friend struct base::DefaultLazyInstanceTraits<TimeFormatter>;
std::vector<icu::PluralFormat*> short_formatter_;
std::vector<icu::PluralFormat*> time_left_formatter_;
@@ -182,6 +181,9 @@ class TimeFormatter {
DISALLOW_COPY_AND_ASSIGN(TimeFormatter);
};
+static base::LazyInstance<TimeFormatter> g_time_formatter(
+ base::LINKER_INITIALIZED);
+
void TimeFormatter::BuildFormats(
FormatType format_type, std::vector<icu::PluralFormat*>* time_formats) {
static const icu::UnicodeString kKeywords[] = {
@@ -253,8 +255,6 @@ icu::PluralFormat* TimeFormatter::createFallbackFormat(
return format;
}
-Singleton<TimeFormatter> time_formatter;
-
static string16 FormatTimeImpl(const TimeDelta& delta, FormatType format_type) {
if (delta.ToInternalValue() < 0) {
NOTREACHED() << "Negative duration";
@@ -264,7 +264,7 @@ static string16 FormatTimeImpl(const TimeDelta& delta, FormatType format_type) {
int number;
const std::vector<icu::PluralFormat*>& formatters =
- time_formatter->formatter(format_type);
+ g_time_formatter.Get().formatter(format_type);
UErrorCode error = U_ZERO_ERROR;
icu::UnicodeString time_string;
diff --git a/chrome/common/unix_domain_socket_posix.cc b/chrome/common/unix_domain_socket_posix.cc
new file mode 100644
index 0000000..31f0135
--- /dev/null
+++ b/chrome/common/unix_domain_socket_posix.cc
@@ -0,0 +1,151 @@
+// 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.
+
+#include "chrome/common/unix_domain_socket_posix.h"
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+
+#include "base/eintr_wrapper.h"
+#include "base/logging.h"
+#include "base/pickle.h"
+
+// static
+bool UnixDomainSocket::SendMsg(int fd,
+ const void* buf,
+ size_t length,
+ const std::vector<int>& fds) {
+ struct msghdr msg;
+ memset(&msg, 0, sizeof(msg));
+ struct iovec iov = {const_cast<void*>(buf), length};
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ char* control_buffer = NULL;
+ if (fds.size()) {
+ const unsigned control_len = CMSG_SPACE(sizeof(int) * fds.size());
+ control_buffer = new char[control_len];
+
+ struct cmsghdr *cmsg;
+ msg.msg_control = control_buffer;
+ msg.msg_controllen = control_len;
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int) * fds.size());
+ memcpy(CMSG_DATA(cmsg), &fds[0], sizeof(int) * fds.size());
+ msg.msg_controllen = cmsg->cmsg_len;
+ }
+
+ const ssize_t r = HANDLE_EINTR(sendmsg(fd, &msg, 0));
+ const bool ret = static_cast<ssize_t>(length) == r;
+ delete[] control_buffer;
+ return ret;
+}
+
+// static
+ssize_t UnixDomainSocket::RecvMsg(int fd,
+ void* buf,
+ size_t length,
+ std::vector<int>* fds) {
+ static const unsigned kMaxDescriptors = 16;
+
+ fds->clear();
+
+ struct msghdr msg;
+ memset(&msg, 0, sizeof(msg));
+ struct iovec iov = {buf, length};
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ char control_buffer[CMSG_SPACE(sizeof(int) * kMaxDescriptors)];
+ msg.msg_control = control_buffer;
+ msg.msg_controllen = sizeof(control_buffer);
+
+ const ssize_t r = HANDLE_EINTR(recvmsg(fd, &msg, 0));
+ if (r == -1)
+ return -1;
+
+ int* wire_fds = NULL;
+ unsigned wire_fds_len = 0;
+
+ if (msg.msg_controllen > 0) {
+ struct cmsghdr* cmsg;
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_RIGHTS) {
+ const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0);
+ DCHECK(payload_len % sizeof(int) == 0);
+ wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
+ wire_fds_len = payload_len / sizeof(int);
+ break;
+ }
+ }
+ }
+
+ if (msg.msg_flags & MSG_TRUNC || msg.msg_flags & MSG_CTRUNC) {
+ for (unsigned i = 0; i < wire_fds_len; ++i)
+ close(wire_fds[i]);
+ errno = EMSGSIZE;
+ return -1;
+ }
+
+ fds->resize(wire_fds_len);
+ memcpy(&(*fds)[0], wire_fds, sizeof(int) * wire_fds_len);
+
+ return r;
+}
+
+// static
+ssize_t UnixDomainSocket::SendRecvMsg(int fd,
+ uint8_t* reply,
+ unsigned max_reply_len,
+ int* result_fd,
+ const Pickle& request) {
+ int fds[2];
+
+ // This socketpair is only used for the IPC and is cleaned up before
+ // returning.
+ if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fds) == -1)
+ return false;
+
+ std::vector<int> fd_vector;
+ fd_vector.push_back(fds[1]);
+ if (!SendMsg(fd, request.data(), request.size(), fd_vector)) {
+ close(fds[0]);
+ close(fds[1]);
+ return -1;
+ }
+ close(fds[1]);
+
+ fd_vector.clear();
+ const ssize_t reply_len = RecvMsg(fds[0], reply, max_reply_len, &fd_vector);
+ close(fds[0]);
+ if (reply_len == -1)
+ return -1;
+
+ if ((fd_vector.size() > 0 && result_fd == NULL) || fd_vector.size() > 1) {
+ for (std::vector<int>::const_iterator
+ i = fd_vector.begin(); i != fd_vector.end(); ++i) {
+ close(*i);
+ }
+
+ NOTREACHED();
+
+ return -1;
+ }
+
+ if (result_fd) {
+ if (fd_vector.size() == 0) {
+ *result_fd = -1;
+ } else {
+ *result_fd = fd_vector[0];
+ }
+ }
+
+ return reply_len;
+}
+
diff --git a/chrome/common/unix_domain_socket_posix.h b/chrome/common/unix_domain_socket_posix.h
new file mode 100644
index 0000000..405ca95
--- /dev/null
+++ b/chrome/common/unix_domain_socket_posix.h
@@ -0,0 +1,54 @@
+// 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.
+
+#ifndef CHROME_COMMON_UNIX_DOMAIN_SOCKET_POSIX_H_
+#define CHROME_COMMON_UNIX_DOMAIN_SOCKET_POSIX_H_
+#pragma once
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <vector>
+
+class Pickle;
+
+class UnixDomainSocket {
+ public:
+ // Use sendmsg to write the given msg and include a vector of file
+ // descriptors. Returns true if successful.
+ static bool SendMsg(int fd,
+ const void* msg,
+ size_t length,
+ const std::vector<int>& fds);
+
+ // Use recvmsg to read a message and an array of file descriptors. Returns
+ // -1 on failure. Note: will read, at most, 16 descriptors.
+ static ssize_t RecvMsg(int fd,
+ void* msg,
+ size_t length,
+ std::vector<int>* fds);
+
+ // Perform a sendmsg/recvmsg pair.
+ // 1. This process creates a UNIX DGRAM socketpair.
+ // 2. This proces writes a request to |fd| with an SCM_RIGHTS control
+ // message containing on end of the fresh socket pair.
+ // 3. This process blocks reading from the other end of the fresh
+ // socketpair.
+ // 4. The target process receives the request, processes it and writes the
+ // reply to the end of the socketpair contained in the request.
+ // 5. This process wakes up and continues.
+ //
+ // fd: descriptor to send the request on
+ // reply: buffer for the reply
+ // reply_len: size of |reply|
+ // result_fd: (may be NULL) the file descriptor returned in the reply
+ // (if any)
+ // request: the bytes to send in the request
+ static ssize_t SendRecvMsg(int fd,
+ uint8_t* reply,
+ unsigned reply_len,
+ int* result_fd,
+ const Pickle& request);
+};
+
+#endif // CHROME_COMMON_UNIX_DOMAIN_SOCKET_POSIX_H_
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc
index 6a1c6a2..12ab2de 100644
--- a/chrome/common/url_constants.cc
+++ b/chrome/common/url_constants.cc
@@ -54,6 +54,7 @@ const char kAboutCrashURL[] = "about:crash";
const char kAboutCreditsURL[] = "about:credits";
const char kAboutDNSURL[] = "about:dns";
const char kAboutFlagsURL[] = "about:flags";
+const char kAboutGpuURL[] = "about:gpu";
const char kAboutGpuCrashURL[] = "about:gpucrash";
const char kAboutGpuHangURL[] = "about:gpuhang";
const char kAboutHangURL[] = "about:hang";
@@ -113,10 +114,12 @@ const char kChromeUIDownloadsHost[] = "downloads";
const char kChromeUIExtensionsHost[] = "extensions";
const char kChromeUIFavIconHost[] = "favicon";
const char kChromeUIFlagsHost[] = "flags";
+const char kChromeUIGpuInternalsHost[] = "gpu-internals";
const char kChromeUIHistoryHost[] = "history";
const char kChromeUIHistory2Host[] = "history2";
const char kChromeUIInspectorHost[] = "inspector";
const char kChromeUIKeyboardHost[] = "keyboard";
+const char kChromeUILoginHost[] = "login";
const char kChromeUINetInternalsHost[] = "net-internals";
const char kChromeUINewTabHost[] = "newtab";
const char kChromeUIPluginsHost[] = "plugins";
@@ -158,6 +161,9 @@ const char kCloudPrintSetupHost[] = "cloudprintsetup";
const char kNetworkViewInternalsURL[] = "chrome://net-internals/";
const char kNetworkViewCacheURL[] = "chrome://view-http-cache/";
+// GPU sub pages
+const char kGpuInternalsURL[] = "chrome://gpu-internals/";
+
// Option sub pages.
const char kAdvancedOptionsSubPage[] = "advanced";
const char kAutoFillSubPage[] = "autoFillOptions";
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h
index 1980b6e..9b7c519 100644
--- a/chrome/common/url_constants.h
+++ b/chrome/common/url_constants.h
@@ -47,6 +47,7 @@ extern const char kAboutCrashURL[];
extern const char kAboutCreditsURL[];
extern const char kAboutDNSURL[];
extern const char kAboutFlagsURL[];
+extern const char kAboutGpuURL[];
extern const char kAboutGpuCrashURL[];
extern const char kAboutGpuHangURL[];
extern const char kAboutHangURL[];
@@ -105,9 +106,11 @@ extern const char kChromeUIDownloadsHost[];
extern const char kChromeUIExtensionsHost[];
extern const char kChromeUIFavIconHost[];
extern const char kChromeUIFlagsHost[];
+extern const char kChromeUIGpuInternalsHost[];
extern const char kChromeUIHistory2Host[];
extern const char kChromeUIHistoryHost[];
extern const char kChromeUIKeyboardHost[];
+extern const char kChromeUILoginHost[];
extern const char kChromeUINetInternalsHost[];
extern const char kChromeUINewTabHost[];
extern const char kChromeUIPluginsHost[];
@@ -154,6 +157,9 @@ extern const char kCloudPrintSetupHost[];
extern const char kNetworkViewCacheURL[];
extern const char kNetworkViewInternalsURL[];
+// GPU related URLs
+extern const char kGpuInternalsURL[];
+
// Options sub-pages.
extern const char kAdvancedOptionsSubPage[];
extern const char kAutoFillSubPage[];
diff --git a/chrome/common/utility_messages.cc b/chrome/common/utility_messages.cc
index b0cd5cc..ee079aa 100644
--- a/chrome/common/utility_messages.cc
+++ b/chrome/common/utility_messages.cc
@@ -2,15 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/common/utility_messages.h"
-
+#include "base/file_path.h"
#include "base/values.h"
#include "chrome/common/common_param_traits.h"
#include "chrome/common/indexed_db_key.h"
#include "chrome/common/serialized_script_value.h"
-#include "base/file_path.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#define MESSAGES_INTERNAL_IMPL_FILE \
- "chrome/common/utility_messages_internal.h"
-#include "ipc/ipc_message_impl_macros.h"
+#define IPC_MESSAGE_IMPL
+#include "chrome/common/utility_messages.h"
diff --git a/chrome/common/utility_messages.h b/chrome/common/utility_messages.h
index 49bc9ce..3e298d6 100644
--- a/chrome/common/utility_messages.h
+++ b/chrome/common/utility_messages.h
@@ -71,7 +71,6 @@ struct ParamTraits<UpdateManifest::Results> {
} // namespace IPC
-#define MESSAGES_INTERNAL_FILE "chrome/common/utility_messages_internal.h"
-#include "ipc/ipc_message_macros.h"
+#include "chrome/common/utility_messages_internal.h"
#endif // CHROME_COMMON_UTILITY_MESSAGES_H_
diff --git a/chrome/common/utility_messages_internal.h b/chrome/common/utility_messages_internal.h
index adb7077..5381155 100644
--- a/chrome/common/utility_messages_internal.h
+++ b/chrome/common/utility_messages_internal.h
@@ -5,17 +5,14 @@
#include <string>
#include <vector>
-// This header is meant to be included in multiple passes, hence no traditional
-// header guard. It is included by utility_messages_internal.h
-// See ipc_message_macros.h for explanation of the macros and passes.
-
-// This file needs to be included again, even though we're actually included
-// from it via utility_messages.h.
-#include "ipc/ipc_message_macros.h"
-
#include "base/platform_file.h"
#include "gfx/rect.h"
+#include "ipc/ipc_message_macros.h"
+#include "printing/backend/print_backend.h"
#include "printing/page_range.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+#define IPC_MESSAGE_START NaClMsgStart
class FilePath;
class IndexedDBKey;
@@ -25,118 +22,129 @@ class SkBitmap;
//------------------------------------------------------------------------------
// Utility process messages:
// These are messages from the browser to the utility process.
-IPC_BEGIN_MESSAGES(Utility)
-
- // Tell the utility process to unpack the given extension file in its
- // directory and verify that it is valid.
- IPC_MESSAGE_CONTROL1(UtilityMsg_UnpackExtension,
- FilePath /* extension_filename */)
-
- // Tell the utility process to parse the given JSON data and verify its
- // validity.
- IPC_MESSAGE_CONTROL1(UtilityMsg_UnpackWebResource,
- std::string /* JSON data */)
-
- // Tell the utility process to parse the given xml document.
- IPC_MESSAGE_CONTROL1(UtilityMsg_ParseUpdateManifest,
- std::string /* xml document contents */)
-
- // Tell the utility process to decode the given image data.
- IPC_MESSAGE_CONTROL1(UtilityMsg_DecodeImage,
- std::vector<unsigned char>) // encoded image contents
-
- // Tell the utility process to render the given PDF into a metafile.
- IPC_MESSAGE_CONTROL5(UtilityMsg_RenderPDFPagesToMetafile,
- base::PlatformFile, // PDF file
- FilePath, // Location for output metafile
- gfx::Rect, // Render Area
- int, // DPI
- std::vector<printing::PageRange>)
-
- // Tell the utility process to extract the given IDBKeyPath from the
- // SerializedScriptValue vector and reply with the corresponding IDBKeys.
- IPC_MESSAGE_CONTROL3(UtilityMsg_IDBKeysFromValuesAndKeyPath,
- int, // id
- std::vector<SerializedScriptValue>,
- string16) // IDBKeyPath
-
- // Tells the utility process that it's running in batch mode.
- IPC_MESSAGE_CONTROL0(UtilityMsg_BatchMode_Started)
-
- // Tells the utility process that it can shutdown.
- IPC_MESSAGE_CONTROL0(UtilityMsg_BatchMode_Finished)
-
-IPC_END_MESSAGES(Utility)
+// Tell the utility process to unpack the given extension file in its
+// directory and verify that it is valid.
+IPC_MESSAGE_CONTROL1(UtilityMsg_UnpackExtension,
+ FilePath /* extension_filename */)
+
+// Tell the utility process to parse the given JSON data and verify its
+// validity.
+IPC_MESSAGE_CONTROL1(UtilityMsg_UnpackWebResource,
+ std::string /* JSON data */)
+
+// Tell the utility process to parse the given xml document.
+IPC_MESSAGE_CONTROL1(UtilityMsg_ParseUpdateManifest,
+ std::string /* xml document contents */)
+
+// Tell the utility process to decode the given image data.
+IPC_MESSAGE_CONTROL1(UtilityMsg_DecodeImage,
+ std::vector<unsigned char>) // encoded image contents
+
+// Tell the utility process to render the given PDF into a metafile.
+IPC_MESSAGE_CONTROL5(UtilityMsg_RenderPDFPagesToMetafile,
+ base::PlatformFile, // PDF file
+ FilePath, // Location for output metafile
+ gfx::Rect, // Render Area
+ int, // DPI
+ std::vector<printing::PageRange>)
+
+// Tell the utility process to extract the given IDBKeyPath from the
+// SerializedScriptValue vector and reply with the corresponding IDBKeys.
+IPC_MESSAGE_CONTROL3(UtilityMsg_IDBKeysFromValuesAndKeyPath,
+ int, // id
+ std::vector<SerializedScriptValue>,
+ string16) // IDBKeyPath
+
+// Tells the utility process that it's running in batch mode.
+IPC_MESSAGE_CONTROL0(UtilityMsg_BatchMode_Started)
+
+// Tells the utility process that it can shutdown.
+IPC_MESSAGE_CONTROL0(UtilityMsg_BatchMode_Finished)
+
+// Tells the utility process to get capabilities and defaults for the specified
+// printer. Used on Windows to isolate the service process from printer driver
+// crashes by executing this in a separate process. This does not run in a
+// sandbox.
+IPC_MESSAGE_CONTROL1(UtilityMsg_GetPrinterCapsAndDefaults,
+ std::string /* printer name */)
//------------------------------------------------------------------------------
// Utility process host messages:
// These are messages from the utility process to the browser.
-IPC_BEGIN_MESSAGES(UtilityHost)
-
- // Reply when the utility process is done unpacking an extension. |manifest|
- // is the parsed manifest.json file.
- // The unpacker should also have written out files containing the decoded
- // images and message catalogs from the extension. See ExtensionUnpacker for
- // details.
- IPC_MESSAGE_CONTROL1(UtilityHostMsg_UnpackExtension_Succeeded,
- DictionaryValue /* manifest */)
-
- // Reply when the utility process has failed while unpacking an extension.
- // |error_message| is a user-displayable explanation of what went wrong.
- IPC_MESSAGE_CONTROL1(UtilityHostMsg_UnpackExtension_Failed,
- std::string /* error_message, if any */)
-
- // Reply when the utility process is done unpacking and parsing JSON data
- // from a web resource.
- IPC_MESSAGE_CONTROL1(UtilityHostMsg_UnpackWebResource_Succeeded,
- DictionaryValue /* json data */)
-
- // Reply when the utility process has failed while unpacking and parsing a
- // web resource. |error_message| is a user-readable explanation of what
- // went wrong.
- IPC_MESSAGE_CONTROL1(UtilityHostMsg_UnpackWebResource_Failed,
- std::string /* error_message, if any */)
-
- // Reply when the utility process has succeeded in parsing an update manifest
- // xml document.
- IPC_MESSAGE_CONTROL1(UtilityHostMsg_ParseUpdateManifest_Succeeded,
- UpdateManifest::Results /* updates */)
-
- // Reply when an error occured parsing the update manifest. |error_message|
- // is a description of what went wrong suitable for logging.
- IPC_MESSAGE_CONTROL1(UtilityHostMsg_ParseUpdateManifest_Failed,
- std::string /* error_message, if any */)
-
- // Reply when the utility process has succeeded in decoding the image.
- IPC_MESSAGE_CONTROL1(UtilityHostMsg_DecodeImage_Succeeded,
- SkBitmap) // decoded image
-
- // Reply when an error occured decoding the image.
- IPC_MESSAGE_CONTROL0(UtilityHostMsg_DecodeImage_Failed)
-
- // Reply when the utility process has succeeded in rendering the PDF.
- IPC_MESSAGE_CONTROL1(UtilityHostMsg_RenderPDFPagesToMetafile_Succeeded,
- int) // Highest rendered page number
-
- // Reply when an error occured rendering the PDF.
- IPC_MESSAGE_CONTROL0(UtilityHostMsg_RenderPDFPagesToMetafile_Failed)
+// Reply when the utility process is done unpacking an extension. |manifest|
+// is the parsed manifest.json file.
+// The unpacker should also have written out files containing the decoded
+// images and message catalogs from the extension. See ExtensionUnpacker for
+// details.
+IPC_MESSAGE_CONTROL1(UtilityHostMsg_UnpackExtension_Succeeded,
+ DictionaryValue /* manifest */)
+
+// Reply when the utility process has failed while unpacking an extension.
+// |error_message| is a user-displayable explanation of what went wrong.
+IPC_MESSAGE_CONTROL1(UtilityHostMsg_UnpackExtension_Failed,
+ std::string /* error_message, if any */)
+
+// Reply when the utility process is done unpacking and parsing JSON data
+// from a web resource.
+IPC_MESSAGE_CONTROL1(UtilityHostMsg_UnpackWebResource_Succeeded,
+ DictionaryValue /* json data */)
+
+// Reply when the utility process has failed while unpacking and parsing a
+// web resource. |error_message| is a user-readable explanation of what
+// went wrong.
+IPC_MESSAGE_CONTROL1(UtilityHostMsg_UnpackWebResource_Failed,
+ std::string /* error_message, if any */)
+
+// Reply when the utility process has succeeded in parsing an update manifest
+// xml document.
+IPC_MESSAGE_CONTROL1(UtilityHostMsg_ParseUpdateManifest_Succeeded,
+ UpdateManifest::Results /* updates */)
+
+// Reply when an error occured parsing the update manifest. |error_message|
+// is a description of what went wrong suitable for logging.
+IPC_MESSAGE_CONTROL1(UtilityHostMsg_ParseUpdateManifest_Failed,
+ std::string /* error_message, if any */)
+
+// Reply when the utility process has succeeded in decoding the image.
+IPC_MESSAGE_CONTROL1(UtilityHostMsg_DecodeImage_Succeeded,
+ SkBitmap) // decoded image
+
+// Reply when an error occured decoding the image.
+IPC_MESSAGE_CONTROL0(UtilityHostMsg_DecodeImage_Failed)
+
+// Reply when the utility process has succeeded in rendering the PDF.
+IPC_MESSAGE_CONTROL1(UtilityHostMsg_RenderPDFPagesToMetafile_Succeeded,
+ int) // Highest rendered page number
+
+// Reply when an error occured rendering the PDF.
+IPC_MESSAGE_CONTROL0(UtilityHostMsg_RenderPDFPagesToMetafile_Failed)
#if defined(OS_WIN)
- // Request that the given font be loaded by the host so it's cached by the
- // OS. Please see ChildProcessHost::PreCacheFont for details.
- IPC_SYNC_MESSAGE_CONTROL1_0(UtilityHostMsg_PreCacheFont,
- LOGFONT /* font data */)
+// Request that the given font be loaded by the host so it's cached by the
+// OS. Please see ChildProcessHost::PreCacheFont for details.
+IPC_SYNC_MESSAGE_CONTROL1_0(UtilityHostMsg_PreCacheFont,
+ LOGFONT /* font data */)
#endif // defined(OS_WIN)
- // Reply when the utility process has succeeded in obtaining the value for
- // IDBKeyPath.
- IPC_MESSAGE_CONTROL2(UtilityHostMsg_IDBKeysFromValuesAndKeyPath_Succeeded,
- int /* id */,
- std::vector<IndexedDBKey> /* value */)
+// Reply when the utility process has succeeded in obtaining the value for
+// IDBKeyPath.
+IPC_MESSAGE_CONTROL2(UtilityHostMsg_IDBKeysFromValuesAndKeyPath_Succeeded,
+ int /* id */,
+ std::vector<IndexedDBKey> /* value */)
+
+// Reply when the utility process has failed in obtaining the value for
+// IDBKeyPath.
+IPC_MESSAGE_CONTROL1(UtilityHostMsg_IDBKeysFromValuesAndKeyPath_Failed,
+ int /* id */)
+
+// Reply when the utility process has succeeded in obtaining the printer
+// capabilities and defaults.
+IPC_MESSAGE_CONTROL2(UtilityHostMsg_GetPrinterCapsAndDefaults_Succeeded,
+ std::string /* printer name */,
+ printing::PrinterCapsAndDefaults)
- // Reply when the utility process has failed in obtaining the value for
- // IDBKeyPath.
- IPC_MESSAGE_CONTROL1(UtilityHostMsg_IDBKeysFromValuesAndKeyPath_Failed,
- int /* id */)
+// Reply when the utility process has failed to obtain the printer
+// capabilities and defaults.
+IPC_MESSAGE_CONTROL1(UtilityHostMsg_GetPrinterCapsAndDefaults_Failed,
+ std::string /* printer name */)
-IPC_END_MESSAGES(UtilityHost)
diff --git a/chrome/common/web_database_observer_impl.cc b/chrome/common/web_database_observer_impl.cc
index 8c008e4..b683b72 100644
--- a/chrome/common/web_database_observer_impl.cc
+++ b/chrome/common/web_database_observer_impl.cc
@@ -7,8 +7,9 @@
#include "base/auto_reset.h"
#include "base/message_loop.h"
#include "base/string16.h"
-#include "chrome/common/render_messages.h"
+#include "chrome/common/database_messages.h"
#include "third_party/WebKit/WebKit/chromium/public/WebDatabase.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
WebDatabaseObserverImpl::WebDatabaseObserverImpl(
IPC::Message::Sender* sender)
@@ -20,7 +21,7 @@ void WebDatabaseObserverImpl::databaseOpened(
const WebKit::WebDatabase& database) {
string16 origin_identifier = database.securityOrigin().databaseIdentifier();
string16 database_name = database.name();
- sender_->Send(new ViewHostMsg_DatabaseOpened(
+ sender_->Send(new DatabaseHostMsg_Opened(
origin_identifier, database_name,
database.displayName(), database.estimatedSize()));
database_connections_.AddConnection(origin_identifier, database_name);
@@ -28,7 +29,7 @@ void WebDatabaseObserverImpl::databaseOpened(
void WebDatabaseObserverImpl::databaseModified(
const WebKit::WebDatabase& database) {
- sender_->Send(new ViewHostMsg_DatabaseModified(
+ sender_->Send(new DatabaseHostMsg_Modified(
database.securityOrigin().databaseIdentifier(), database.name()));
}
@@ -36,7 +37,7 @@ void WebDatabaseObserverImpl::databaseClosed(
const WebKit::WebDatabase& database) {
string16 origin_identifier = database.securityOrigin().databaseIdentifier();
string16 database_name = database.name();
- sender_->Send(new ViewHostMsg_DatabaseClosed(
+ sender_->Send(new DatabaseHostMsg_Closed(
origin_identifier, database_name));
database_connections_.RemoveConnection(origin_identifier, database_name);
if (waiting_for_dbs_to_close_ && database_connections_.IsEmpty())
diff --git a/chrome/common/webmessageportchannel_impl.cc b/chrome/common/webmessageportchannel_impl.cc
index b7a9388..0778871 100644
--- a/chrome/common/webmessageportchannel_impl.cc
+++ b/chrome/common/webmessageportchannel_impl.cc
@@ -180,11 +180,14 @@ void WebMessagePortChannelImpl::Send(IPC::Message* message) {
ChildThread::current()->Send(message);
}
-void WebMessagePortChannelImpl::OnMessageReceived(const IPC::Message& message) {
+bool WebMessagePortChannelImpl::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
IPC_BEGIN_MESSAGE_MAP(WebMessagePortChannelImpl, message)
IPC_MESSAGE_HANDLER(WorkerProcessMsg_Message, OnMessage)
IPC_MESSAGE_HANDLER(WorkerProcessMsg_MessagesQueued, OnMessagedQueued)
+ IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
+ return handled;
}
void WebMessagePortChannelImpl::OnMessage(
diff --git a/chrome/common/webmessageportchannel_impl.h b/chrome/common/webmessageportchannel_impl.h
index 3c96fc3..0199ebb 100644
--- a/chrome/common/webmessageportchannel_impl.h
+++ b/chrome/common/webmessageportchannel_impl.h
@@ -48,7 +48,7 @@ class WebMessagePortChannelImpl
void Send(IPC::Message* message);
// IPC::Channel::Listener implementation.
- virtual void OnMessageReceived(const IPC::Message& message);
+ virtual bool OnMessageReceived(const IPC::Message& message);
void OnMessage(const string16& message,
const std::vector<int>& sent_message_port_ids,
diff --git a/chrome/common/worker_messages.cc b/chrome/common/worker_messages.cc
index 192e4fd..19b8d23 100644
--- a/chrome/common/worker_messages.cc
+++ b/chrome/common/worker_messages.cc
@@ -2,13 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/common/worker_messages.h"
-
#include "chrome/common/common_param_traits.h"
-#define MESSAGES_INTERNAL_IMPL_FILE \
- "chrome/common/worker_messages_internal.h"
-#include "ipc/ipc_message_impl_macros.h"
+#define IPC_MESSAGE_IMPL
+#include "chrome/common/worker_messages.h"
WorkerHostMsg_PostConsoleMessageToWorkerObject_Params::
WorkerHostMsg_PostConsoleMessageToWorkerObject_Params()
diff --git a/chrome/common/worker_messages.h b/chrome/common/worker_messages.h
index 0e76c4f..28fec62 100644
--- a/chrome/common/worker_messages.h
+++ b/chrome/common/worker_messages.h
@@ -71,7 +71,6 @@ struct ParamTraits<WorkerProcessMsg_CreateWorker_Params> {
} // namespace IPC
-#define MESSAGES_INTERNAL_FILE "chrome/common/worker_messages_internal.h"
-#include "ipc/ipc_message_macros.h"
+#include "chrome/common/worker_messages_internal.h"
#endif // CHROME_COMMON_WORKER_MESSAGES_H_
diff --git a/chrome/common/worker_messages_internal.h b/chrome/common/worker_messages_internal.h
index 5d0cb62..e661f67 100644
--- a/chrome/common/worker_messages_internal.h
+++ b/chrome/common/worker_messages_internal.h
@@ -8,128 +8,122 @@
#include "googleurl/src/gurl.h"
#include "ipc/ipc_message_macros.h"
+#define IPC_MESSAGE_START WorkerMsgStart
//-----------------------------------------------------------------------------
// WorkerProcess messages
// These are messages sent from the browser to the worker process.
-IPC_BEGIN_MESSAGES(WorkerProcess)
- IPC_MESSAGE_CONTROL1(WorkerProcessMsg_CreateWorker,
- WorkerProcessMsg_CreateWorker_Params)
+IPC_MESSAGE_CONTROL1(WorkerProcessMsg_CreateWorker,
+ WorkerProcessMsg_CreateWorker_Params)
- // Note: these Message Port related messages can also be sent to the
- // renderer process. Putting them here since we don't have a shared place
- // like common_messages_internal.h
- IPC_MESSAGE_ROUTED3(WorkerProcessMsg_Message,
- string16 /* message */,
- std::vector<int> /* sent_message_port_ids */,
- std::vector<int> /* new_routing_ids */)
+// Note: these Message Port related messages can also be sent to the
+// renderer process. Putting them here since we don't have a shared place
+// like common_messages_internal.h
+IPC_MESSAGE_ROUTED3(WorkerProcessMsg_Message,
+ string16 /* message */,
+ std::vector<int> /* sent_message_port_ids */,
+ std::vector<int> /* new_routing_ids */)
- // Tells the Message Port Channel object that there are no more in-flight
- // messages arriving.
- IPC_MESSAGE_ROUTED0(WorkerProcessMsg_MessagesQueued)
-IPC_END_MESSAGES(WorkerProcess)
+// Tells the Message Port Channel object that there are no more in-flight
+// messages arriving.
+IPC_MESSAGE_ROUTED0(WorkerProcessMsg_MessagesQueued)
//-----------------------------------------------------------------------------
// WorkerProcessHost messages
// These are messages sent from the worker process to the browser process.
-IPC_BEGIN_MESSAGES(WorkerProcessHost)
- // Note: these Message Port related messages can also be sent out from the
- // renderer process. Putting them here since we don't have a shared place
- // like common_messages_internal.h
-
- // Creates a new Message Port Channel object. The first paramaeter is the
- // message port channel's routing id in this process. The second parameter
- // is the process-wide-unique identifier for that port.
- IPC_SYNC_MESSAGE_CONTROL0_2(WorkerProcessHostMsg_CreateMessagePort,
- int /* route_id */,
- int /* message_port_id */)
-
- // Sent when a Message Port Channel object is destroyed.
- IPC_MESSAGE_CONTROL1(WorkerProcessHostMsg_DestroyMessagePort,
- int /* message_port_id */)
-
- // Sends a message to a message port. Optionally sends a message port as
- // as well if sent_message_port_id != MSG_ROUTING_NONE.
- IPC_MESSAGE_CONTROL3(WorkerProcessHostMsg_PostMessage,
- int /* sender_message_port_id */,
- string16 /* message */,
- std::vector<int> /* sent_message_port_ids */)
-
- // Causes messages sent to the remote port to be delivered to this local port.
- IPC_MESSAGE_CONTROL2(WorkerProcessHostMsg_Entangle,
- int /* local_message_port_id */,
- int /* remote_message_port_id */)
-
- // Causes the browser to queue messages sent to this port until the the port
- // has made sure that all in-flight messages were routed to the new
- // destination.
- IPC_MESSAGE_CONTROL1(WorkerProcessHostMsg_QueueMessages,
- int /* message_port_id */)
-
- // Sends the browser all the queued messages that arrived at this message port
- // after it was sent in a postMessage call.
- // NOTE: MSVS can't compile the macro if std::vector<std::pair<string16, int> >
- // is used, so we typedef it in worker_messages.h.
- IPC_MESSAGE_CONTROL2(WorkerProcessHostMsg_SendQueuedMessages,
- int /* message_port_id */,
- std::vector<QueuedMessage> /* queued_messages */)
-
- // Sent by the worker process to check whether access to web databases is
- // granted by content settings.
- IPC_SYNC_MESSAGE_ROUTED4_1(WorkerProcessHostMsg_AllowDatabase,
- GURL /* origin url */,
- string16 /* database name */,
- string16 /* database display name */,
- unsigned long /* estimated size */,
- bool /* result */)
-IPC_END_MESSAGES(WorkerProcessHost)
+// Note: these Message Port related messages can also be sent out from the
+// renderer process. Putting them here since we don't have a shared place
+// like common_messages_internal.h
+
+// Creates a new Message Port Channel object. The first paramaeter is the
+// message port channel's routing id in this process. The second parameter
+// is the process-wide-unique identifier for that port.
+IPC_SYNC_MESSAGE_CONTROL0_2(WorkerProcessHostMsg_CreateMessagePort,
+ int /* route_id */,
+ int /* message_port_id */)
+
+// Sent when a Message Port Channel object is destroyed.
+IPC_MESSAGE_CONTROL1(WorkerProcessHostMsg_DestroyMessagePort,
+ int /* message_port_id */)
+
+// Sends a message to a message port. Optionally sends a message port as
+// as well if sent_message_port_id != MSG_ROUTING_NONE.
+IPC_MESSAGE_CONTROL3(WorkerProcessHostMsg_PostMessage,
+ int /* sender_message_port_id */,
+ string16 /* message */,
+ std::vector<int> /* sent_message_port_ids */)
+
+// Causes messages sent to the remote port to be delivered to this local port.
+IPC_MESSAGE_CONTROL2(WorkerProcessHostMsg_Entangle,
+ int /* local_message_port_id */,
+ int /* remote_message_port_id */)
+
+// Causes the browser to queue messages sent to this port until the the port
+// has made sure that all in-flight messages were routed to the new
+// destination.
+IPC_MESSAGE_CONTROL1(WorkerProcessHostMsg_QueueMessages,
+ int /* message_port_id */)
+
+// Sends the browser all the queued messages that arrived at this message port
+// after it was sent in a postMessage call.
+// NOTE: MSVS can't compile the macro if std::vector<std::pair<string16, int> >
+// is used, so we typedef it in worker_messages.h.
+IPC_MESSAGE_CONTROL2(WorkerProcessHostMsg_SendQueuedMessages,
+ int /* message_port_id */,
+ std::vector<QueuedMessage> /* queued_messages */)
+
+// Sent by the worker process to check whether access to web databases is
+// granted by content settings.
+IPC_SYNC_MESSAGE_CONTROL5_1(WorkerProcessHostMsg_AllowDatabase,
+ int /* worker_route_id */,
+ GURL /* origin url */,
+ string16 /* database name */,
+ string16 /* database display name */,
+ unsigned long /* estimated size */,
+ bool /* result */)
//-----------------------------------------------------------------------------
// Worker messages
// These are messages sent from the renderer process to the worker process.
-IPC_BEGIN_MESSAGES(Worker)
- IPC_MESSAGE_ROUTED3(WorkerMsg_StartWorkerContext,
- GURL /* url */,
- string16 /* user_agent */,
- string16 /* source_code */)
+IPC_MESSAGE_ROUTED3(WorkerMsg_StartWorkerContext,
+ GURL /* url */,
+ string16 /* user_agent */,
+ string16 /* source_code */)
- IPC_MESSAGE_ROUTED0(WorkerMsg_TerminateWorkerContext)
+IPC_MESSAGE_ROUTED0(WorkerMsg_TerminateWorkerContext)
- IPC_MESSAGE_ROUTED3(WorkerMsg_PostMessage,
- string16 /* message */,
- std::vector<int> /* sent_message_port_ids */,
- std::vector<int> /* new_routing_ids */)
+IPC_MESSAGE_ROUTED3(WorkerMsg_PostMessage,
+ string16 /* message */,
+ std::vector<int> /* sent_message_port_ids */,
+ std::vector<int> /* new_routing_ids */)
- IPC_MESSAGE_ROUTED2(WorkerMsg_Connect,
- int /* sent_message_port_id */,
- int /* routing_id */)
+IPC_MESSAGE_ROUTED2(WorkerMsg_Connect,
+ int /* sent_message_port_id */,
+ int /* routing_id */)
- IPC_MESSAGE_ROUTED0(WorkerMsg_WorkerObjectDestroyed)
-IPC_END_MESSAGES(Worker)
+IPC_MESSAGE_ROUTED0(WorkerMsg_WorkerObjectDestroyed)
//-----------------------------------------------------------------------------
// WorkerHost messages
// These are messages sent from the worker process to the renderer process.
-IPC_BEGIN_MESSAGES(WorkerHost)
- // WorkerMsg_PostMessage is also sent here.
- IPC_MESSAGE_ROUTED3(WorkerHostMsg_PostExceptionToWorkerObject,
- string16 /* error_message */,
- int /* line_number */,
- string16 /* source_url*/)
-
- IPC_MESSAGE_ROUTED1(WorkerHostMsg_PostConsoleMessageToWorkerObject,
- WorkerHostMsg_PostConsoleMessageToWorkerObject_Params)
-
- IPC_MESSAGE_ROUTED1(WorkerHostMsg_ConfirmMessageFromWorkerObject,
- bool /* bool has_pending_activity */)
-
- IPC_MESSAGE_ROUTED1(WorkerHostMsg_ReportPendingActivity,
- bool /* bool has_pending_activity */)
-
- IPC_MESSAGE_CONTROL1(WorkerHostMsg_WorkerContextClosed,
- int /* worker_route_id */)
- IPC_MESSAGE_ROUTED0(WorkerHostMsg_WorkerContextDestroyed)
-IPC_END_MESSAGES(WorkerHost)
+// WorkerMsg_PostMessage is also sent here.
+IPC_MESSAGE_ROUTED3(WorkerHostMsg_PostExceptionToWorkerObject,
+ string16 /* error_message */,
+ int /* line_number */,
+ string16 /* source_url*/)
+
+IPC_MESSAGE_ROUTED1(WorkerHostMsg_PostConsoleMessageToWorkerObject,
+ WorkerHostMsg_PostConsoleMessageToWorkerObject_Params)
+
+IPC_MESSAGE_ROUTED1(WorkerHostMsg_ConfirmMessageFromWorkerObject,
+ bool /* bool has_pending_activity */)
+
+IPC_MESSAGE_ROUTED1(WorkerHostMsg_ReportPendingActivity,
+ bool /* bool has_pending_activity */)
+
+IPC_MESSAGE_CONTROL1(WorkerHostMsg_WorkerContextClosed,
+ int /* worker_route_id */)
+IPC_MESSAGE_ROUTED0(WorkerHostMsg_WorkerContextDestroyed)
diff --git a/googleurl/src/gurl.cc b/googleurl/src/gurl.cc
index 3a1f2b9..e41cb71 100644
--- a/googleurl/src/gurl.cc
+++ b/googleurl/src/gurl.cc
@@ -34,6 +34,7 @@
#endif
#include <algorithm>
+#include <iostream>
#include "googleurl/src/gurl.h"
@@ -454,3 +455,6 @@ void GURL::Swap(GURL* other) {
std::swap(parsed_, other->parsed_);
}
+std::ostream& operator<<(std::ostream& out, const GURL& url) {
+ return out << url.possibly_invalid_spec();
+}
diff --git a/googleurl/src/gurl.h b/googleurl/src/gurl.h
index 4088f27..803cdfe 100644
--- a/googleurl/src/gurl.h
+++ b/googleurl/src/gurl.h
@@ -370,8 +370,6 @@ class GURL {
};
// Stream operator so GURL can be used in assertion statements.
-inline std::ostream& operator<<(std::ostream& out, const GURL& url) {
- return out << url.possibly_invalid_spec();
-}
+GURL_API std::ostream& operator<<(std::ostream& out, const GURL& url);
#endif // GOOGLEURL_SRC_GURL_H__
diff --git a/net/base/bandwidth_metrics.cc b/net/base/bandwidth_metrics.cc
new file mode 100644
index 0000000..fa23a77
--- /dev/null
+++ b/net/base/bandwidth_metrics.cc
@@ -0,0 +1,36 @@
+// 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.
+
+#include "base/lazy_instance.h"
+#include "net/base/bandwidth_metrics.h"
+
+static base::LazyInstance<net::BandwidthMetrics> g_bandwidth_metrics(
+ base::LINKER_INITIALIZED);
+
+namespace net {
+
+ScopedBandwidthMetrics::ScopedBandwidthMetrics()
+ : started_(false) {
+}
+
+ScopedBandwidthMetrics::~ScopedBandwidthMetrics() {
+ if (started_)
+ g_bandwidth_metrics.Get().StopStream();
+}
+
+void ScopedBandwidthMetrics::StartStream() {
+ started_ = true;
+ g_bandwidth_metrics.Get().StartStream();
+}
+
+void ScopedBandwidthMetrics::StopStream() {
+ started_ = false;
+ g_bandwidth_metrics.Get().StopStream();
+}
+
+void ScopedBandwidthMetrics::RecordBytes(int bytes) {
+ g_bandwidth_metrics.Get().RecordBytes(bytes);
+}
+
+} // namespace net
diff --git a/net/base/bandwidth_metrics.h b/net/base/bandwidth_metrics.h
index 80fa005..ce1a498 100644
--- a/net/base/bandwidth_metrics.h
+++ b/net/base/bandwidth_metrics.h
@@ -121,33 +121,17 @@ class BandwidthMetrics {
// ensure we always stop them.
class ScopedBandwidthMetrics {
public:
- explicit ScopedBandwidthMetrics(BandwidthMetrics* metrics)
- : metrics_(metrics), started_(false) {
- }
-
- ~ScopedBandwidthMetrics() {
- if (started_)
- metrics_->StopStream();
- }
-
- void StartStream() {
- started_ = true;
- metrics_->StartStream();
- }
+ ScopedBandwidthMetrics();
+ ~ScopedBandwidthMetrics();
- void StopStream() {
- started_ = false;
- metrics_->StopStream();
- }
-
- void RecordBytes(int bytes) { metrics_->RecordBytes(bytes); }
+ void StartStream();
+ void StopStream();
+ void RecordBytes(int bytes);
private:
- BandwidthMetrics* metrics_;
bool started_;
};
} // namespace net
#endif // NET_BASE_BANDWIDTH_METRICS_H_
-
diff --git a/net/base/capturing_net_log.cc b/net/base/capturing_net_log.cc
index c488e06..fccd5ae 100644
--- a/net/base/capturing_net_log.cc
+++ b/net/base/capturing_net_log.cc
@@ -18,7 +18,7 @@ CapturingNetLog::Entry::Entry(EventType type,
CapturingNetLog::Entry::~Entry() {}
CapturingNetLog::CapturingNetLog(size_t max_num_entries)
- : next_id_(0), max_num_entries_(max_num_entries) {
+ : last_id_(-1), max_num_entries_(max_num_entries) {
}
CapturingNetLog::~CapturingNetLog() {}
@@ -28,16 +28,27 @@ void CapturingNetLog::AddEntry(EventType type,
const Source& source,
EventPhase phase,
EventParameters* extra_parameters) {
+ AutoLock lock(lock_);
Entry entry(type, time, source, phase, extra_parameters);
if (entries_.size() + 1 < max_num_entries_)
entries_.push_back(entry);
}
uint32 CapturingNetLog::NextID() {
- return next_id_++;
+ return base::subtle::NoBarrier_AtomicIncrement(&last_id_, 1);
+}
+
+NetLog::LogLevel CapturingNetLog::GetLogLevel() const {
+ return LOG_ALL_BUT_BYTES;
+}
+
+void CapturingNetLog::GetEntries(EntryList* entry_list) const {
+ AutoLock lock(lock_);
+ *entry_list = entries_;
}
void CapturingNetLog::Clear() {
+ AutoLock lock(lock_);
entries_.clear();
}
@@ -51,16 +62,13 @@ CapturingBoundNetLog::CapturingBoundNetLog(size_t max_num_entries)
CapturingBoundNetLog::~CapturingBoundNetLog() {}
-void CapturingBoundNetLog::Clear() {
- capturing_net_log_->Clear();
+void CapturingBoundNetLog::GetEntries(
+ CapturingNetLog::EntryList* entry_list) const {
+ capturing_net_log_->GetEntries(entry_list);
}
-void CapturingBoundNetLog::AppendTo(const BoundNetLog& net_log) const {
- for (size_t i = 0; i < entries().size(); ++i) {
- const CapturingNetLog::Entry& entry = entries()[i];
- net_log.AddEntryWithTime(entry.type, entry.time, entry.phase,
- entry.extra_parameters);
- }
+void CapturingBoundNetLog::Clear() {
+ capturing_net_log_->Clear();
}
} // namespace net
diff --git a/net/base/capturing_net_log.h b/net/base/capturing_net_log.h
index ff7cf16..9254725 100644
--- a/net/base/capturing_net_log.h
+++ b/net/base/capturing_net_log.h
@@ -8,7 +8,9 @@
#include <vector>
+#include "base/atomicops.h"
#include "base/basictypes.h"
+#include "base/lock.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "base/time.h"
@@ -52,15 +54,20 @@ class CapturingNetLog : public NetLog {
EventPhase phase,
EventParameters* extra_parameters);
virtual uint32 NextID();
- virtual LogLevel GetLogLevel() const { return LOG_ALL_BUT_BYTES; }
+ virtual LogLevel GetLogLevel() const;
// Returns the list of all entries in the log.
- const EntryList& entries() const { return entries_; }
+ void GetEntries(EntryList* entry_list) const;
void Clear();
private:
- uint32 next_id_;
+ // Needs to be "mutable" so can use it in GetEntries().
+ mutable Lock lock_;
+
+ // Last assigned source ID. Incremented to get the next one.
+ base::subtle::Atomic32 last_id_;
+
size_t max_num_entries_;
EntryList entries_;
@@ -85,17 +92,11 @@ class CapturingBoundNetLog {
return BoundNetLog(source_, capturing_net_log_.get());
}
- // Returns the list of all entries in the log.
- const CapturingNetLog::EntryList& entries() const {
- return capturing_net_log_->entries();
- }
+ // Fills |entry_list| with all entries in the log.
+ void GetEntries(CapturingNetLog::EntryList* entry_list) const;
void Clear();
- // Sends all of captured messages to |net_log|, using the same source ID
- // as |net_log|.
- void AppendTo(const BoundNetLog& net_log) const;
-
private:
NetLog::Source source_;
scoped_ptr<CapturingNetLog> capturing_net_log_;
diff --git a/net/base/cert_database_nss_unittest.cc b/net/base/cert_database_nss_unittest.cc
index 5056e5d..8e69104 100644
--- a/net/base/cert_database_nss_unittest.cc
+++ b/net/base/cert_database_nss_unittest.cc
@@ -104,16 +104,9 @@ bool ReadCertIntoList(const std::string& name, CertificateList* certs) {
class CertDatabaseNSSTest : public testing::Test {
public:
virtual void SetUp() {
- if (!temp_db_initialized_) {
- ScopedTempDir* temp_db_dir = Singleton<
- ScopedTempDir,
- DefaultSingletonTraits<ScopedTempDir>,
- CertDatabaseNSSTest>::get();
- ASSERT_TRUE(temp_db_dir->CreateUniqueTempDir());
- ASSERT_TRUE(
- base::OpenTestNSSDB(temp_db_dir->path(), "CertDatabaseNSSTest db"));
- temp_db_initialized_ = true;
- }
+ ASSERT_TRUE(temp_db_dir_.CreateUniqueTempDir());
+ ASSERT_TRUE(
+ base::OpenTestNSSDB(temp_db_dir_.path(), "CertDatabaseNSSTest db"));
slot_.reset(base::GetDefaultNSSKeySlot());
// Test db should be empty at start of test.
@@ -121,7 +114,6 @@ class CertDatabaseNSSTest : public testing::Test {
}
virtual void TearDown() {
// Don't try to cleanup if the setup failed.
- ASSERT_TRUE(temp_db_initialized_);
ASSERT_TRUE(slot_.get());
EXPECT_TRUE(CleanupSlotContents(slot_.get()));
@@ -133,12 +125,9 @@ class CertDatabaseNSSTest : public testing::Test {
CertDatabase cert_db_;
private:
- static bool temp_db_initialized_;
+ ScopedTempDir temp_db_dir_;
};
-// static
-bool CertDatabaseNSSTest::temp_db_initialized_ = false;
-
TEST_F(CertDatabaseNSSTest, ListCerts) {
// This test isn't terribly useful, though it will at least let valgrind test
// for leaks.
diff --git a/net/base/cert_database_openssl.cc b/net/base/cert_database_openssl.cc
index 73a67c1..ec5ec24 100644
--- a/net/base/cert_database_openssl.cc
+++ b/net/base/cert_database_openssl.cc
@@ -4,7 +4,11 @@
#include "net/base/cert_database.h"
+#include <openssl/x509.h>
+
+#include "base/logging.h"
#include "net/base/net_errors.h"
+#include "net/base/openssl_private_key_store.h"
#include "net/base/x509_certificate.h"
namespace net {
@@ -18,22 +22,28 @@ int CertDatabase::CheckUserCert(X509Certificate* cert) {
if (cert->HasExpired())
return ERR_CERT_DATE_INVALID;
- // TODO(bulach): implement me.
- return ERR_NOT_IMPLEMENTED;
+ if (!OpenSSLPrivateKeyStore::GetInstance()->FetchPrivateKey(
+ X509_PUBKEY_get(X509_get_X509_PUBKEY(cert->os_cert_handle()))))
+ return ERR_NO_PRIVATE_KEY_FOR_CERT;
+
+ return OK;
}
int CertDatabase::AddUserCert(X509Certificate* cert) {
// TODO(bulach): implement me.
+ NOTIMPLEMENTED();
return ERR_NOT_IMPLEMENTED;
}
void CertDatabase::ListCerts(CertificateList* certs) {
// TODO(bulach): implement me.
+ NOTIMPLEMENTED();
}
int CertDatabase::ImportFromPKCS12(const std::string& data,
const string16& password) {
// TODO(bulach): implement me.
+ NOTIMPLEMENTED();
return ERR_NOT_IMPLEMENTED;
}
@@ -41,18 +51,20 @@ int CertDatabase::ExportToPKCS12(const CertificateList& certs,
const string16& password,
std::string* output) const {
// TODO(bulach): implement me.
+ NOTIMPLEMENTED();
return 0;
}
bool CertDatabase::DeleteCertAndKey(const X509Certificate* cert) {
// TODO(bulach): implement me.
+ NOTIMPLEMENTED();
return false;
}
unsigned int CertDatabase::GetCertTrust(const X509Certificate* cert,
CertType type) const {
// TODO(bulach): implement me.
- // NOTE: This method is currently only declared for USE_NSS builds.
+ NOTIMPLEMENTED();
return 0;
}
@@ -60,7 +72,7 @@ bool CertDatabase::SetCertTrust(const X509Certificate* cert,
CertType type,
unsigned int trust_bits) {
// TODO(bulach): implement me.
- // NOTE: This method is currently only declared for USE_NSS builds.
+ NOTIMPLEMENTED();
return false;
}
diff --git a/net/base/cert_test_util.cc b/net/base/cert_test_util.cc
index df00b9d..fb0c0f8 100644
--- a/net/base/cert_test_util.cc
+++ b/net/base/cert_test_util.cc
@@ -4,153 +4,37 @@
#include "net/base/cert_test_util.h"
-#include "build/build_config.h"
-
-#if defined(USE_OPENSSL)
-#include <openssl/err.h>
-#include <openssl/ssl.h>
-#include <openssl/x509v3.h>
-#include "base/openssl_util.h"
-#elif defined(USE_NSS)
-#include <cert.h>
-#include "base/nss_util.h"
-#elif defined(OS_MACOSX)
-#include <Security/Security.h>
-#include "base/mac/scoped_cftyperef.h"
-#endif
-
+#include "base/file_path.h"
#include "base/file_util.h"
-#include "base/logging.h"
#include "base/path_service.h"
#include "net/base/x509_certificate.h"
namespace net {
-#if defined(USE_OPENSSL)
-X509Certificate* AddTemporaryRootCertToStore(X509* x509_cert) {
- if (!X509_STORE_add_cert(X509Certificate::cert_store(), x509_cert)) {
- unsigned long error_code = ERR_get_error();
- if (ERR_GET_LIB(error_code) != ERR_LIB_X509 ||
- ERR_GET_REASON(error_code) != X509_R_CERT_ALREADY_IN_HASH_TABLE) {
- base::ClearOpenSSLERRStack(FROM_HERE);
- return NULL;
- }
- }
- return X509Certificate::CreateFromHandle(
- x509_cert, X509Certificate::SOURCE_LONE_CERT_IMPORT,
- X509Certificate::OSCertHandles());
-}
-
-X509Certificate* LoadTemporaryRootCert(const FilePath& filename) {
- base::EnsureOpenSSLInit();
-
- std::string rawcert;
- if (!file_util::ReadFileToString(filename, &rawcert)) {
- LOG(ERROR) << "Can't load certificate " << filename.value();
- return NULL;
- }
-
- base::ScopedOpenSSL<BIO, BIO_free_all> cert_bio(
- BIO_new_mem_buf(const_cast<char*>(rawcert.c_str()),
- rawcert.length()));
- if (!cert_bio.get()) {
- LOG(ERROR) << "Can't create read-only BIO " << filename.value();
- return NULL;
- }
-
- base::ScopedOpenSSL<X509, X509_free> pem_cert(PEM_read_bio_X509(
- cert_bio.get(), NULL, NULL, NULL));
- if (pem_cert.get())
- return AddTemporaryRootCertToStore(pem_cert.get());
-
- // File does not contain PEM data, let's try DER.
- const unsigned char* der_data =
- reinterpret_cast<const unsigned char*>(rawcert.c_str());
- int der_length = rawcert.length();
- base::ScopedOpenSSL<X509, X509_free> der_cert(d2i_X509(
- NULL, &der_data, der_length));
- if (der_cert.get())
- return AddTemporaryRootCertToStore(der_cert.get());
-
- LOG(ERROR) << "Can't parse certificate " << filename.value();
- return NULL;
+FilePath GetTestCertsDirectory() {
+ FilePath certs_dir;
+ PathService::Get(base::DIR_SOURCE_ROOT, &certs_dir);
+ certs_dir = certs_dir.AppendASCII("net");
+ certs_dir = certs_dir.AppendASCII("data");
+ certs_dir = certs_dir.AppendASCII("ssl");
+ certs_dir = certs_dir.AppendASCII("certificates");
+ return certs_dir;
}
-#elif defined(USE_NSS)
-X509Certificate* LoadTemporaryRootCert(const FilePath& filename) {
- base::EnsureNSSInit();
- std::string rawcert;
- if (!file_util::ReadFileToString(filename, &rawcert)) {
- LOG(ERROR) << "Can't load certificate " << filename.value();
+scoped_refptr<X509Certificate> ImportCertFromFile(
+ const FilePath& certs_dir,
+ const std::string& cert_file) {
+ FilePath cert_path = certs_dir.AppendASCII(cert_file);
+ std::string cert_data;
+ if (!file_util::ReadFileToString(cert_path, &cert_data))
return NULL;
- }
- CERTCertificate *cert;
- cert = CERT_DecodeCertFromPackage(const_cast<char *>(rawcert.c_str()),
- rawcert.length());
- if (!cert) {
- LOG(ERROR) << "Can't convert certificate " << filename.value();
+ CertificateList certs_in_file =
+ X509Certificate::CreateCertificateListFromBytes(
+ cert_data.data(), cert_data.size(), X509Certificate::FORMAT_AUTO);
+ if (certs_in_file.empty())
return NULL;
- }
-
- // TODO(port): remove this const_cast after NSS 3.12.3 is released
- CERTCertTrust trust;
- int rv = CERT_DecodeTrustString(&trust, const_cast<char *>("TCu,Cu,Tu"));
- if (rv != SECSuccess) {
- LOG(ERROR) << "Can't decode trust string";
- CERT_DestroyCertificate(cert);
- return NULL;
- }
-
- rv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), cert, &trust);
- if (rv != SECSuccess) {
- LOG(ERROR) << "Can't change trust for certificate " << filename.value();
- CERT_DestroyCertificate(cert);
- return NULL;
- }
-
- X509Certificate* result = X509Certificate::CreateFromHandle(
- cert,
- X509Certificate::SOURCE_LONE_CERT_IMPORT,
- X509Certificate::OSCertHandles());
- CERT_DestroyCertificate(cert);
- return result;
-}
-#endif
-
-#if defined(OS_MACOSX)
-X509Certificate* LoadTemporaryRootCert(const FilePath& filename) {
- std::string rawcert;
- if (!file_util::ReadFileToString(filename, &rawcert)) {
- LOG(ERROR) << "Can't load certificate " << filename.value();
- return NULL;
- }
-
- CFDataRef pem = CFDataCreate(kCFAllocatorDefault,
- reinterpret_cast<const UInt8*>(rawcert.data()),
- static_cast<CFIndex>(rawcert.size()));
- if (!pem)
- return NULL;
- base::mac::ScopedCFTypeRef<CFDataRef> scoped_pem(pem);
-
- SecExternalFormat input_format = kSecFormatUnknown;
- SecExternalItemType item_type = kSecItemTypeUnknown;
- CFArrayRef cert_array = NULL;
- if (SecKeychainItemImport(pem, NULL, &input_format, &item_type, 0, NULL, NULL,
- &cert_array))
- return NULL;
- base::mac::ScopedCFTypeRef<CFArrayRef> scoped_cert_array(cert_array);
-
- if (!CFArrayGetCount(cert_array))
- return NULL;
-
- SecCertificateRef cert_ref = static_cast<SecCertificateRef>(
- const_cast<void*>(CFArrayGetValueAtIndex(cert_array, 0)));
-
- return X509Certificate::CreateFromHandle(cert_ref,
- X509Certificate::SOURCE_LONE_CERT_IMPORT,
- X509Certificate::OSCertHandles());
+ return certs_in_file[0];
}
-#endif
} // namespace net
diff --git a/net/base/cert_test_util.h b/net/base/cert_test_util.h
index 8709156..3452ac5 100644
--- a/net/base/cert_test_util.h
+++ b/net/base/cert_test_util.h
@@ -6,7 +6,9 @@
#define NET_BASE_CERT_TEST_UTIL_H_
#pragma once
-#include "build/build_config.h"
+#include <string>
+
+#include "base/ref_counted.h"
class FilePath;
@@ -14,11 +16,16 @@ namespace net {
class X509Certificate;
-#if defined(USE_NSS) || defined(OS_MACOSX) || defined(USE_OPENSSL)
-// Loads and trusts a root CA certificate (stored in a file) temporarily.
-// TODO(wtc): Implement this function on Windows (http://crbug.com/8470).
-X509Certificate* LoadTemporaryRootCert(const FilePath& filename);
-#endif
+// Returns a FilePath object representing the src/net/data/ssl/certificates
+// directory in the source tree.
+FilePath GetTestCertsDirectory();
+
+// Imports a certificate file in the src/net/data/ssl/certificates directory.
+// certs_dir represents the test certificates directory. cert_file is the
+// name of the certificate file. If cert_file contains multiple certificates,
+// the first certificate found will be returned.
+scoped_refptr<X509Certificate> ImportCertFromFile(const FilePath& certs_dir,
+ const std::string& cert_file);
} // namespace net
diff --git a/net/base/cert_verifier.cc b/net/base/cert_verifier.cc
index ae910b4..4b3d904 100644
--- a/net/base/cert_verifier.cc
+++ b/net/base/cert_verifier.cc
@@ -1,45 +1,158 @@
-// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// 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.
#include "net/base/cert_verifier.h"
-#if defined(USE_NSS)
-#include <private/pprthred.h> // PR_DetatchThread
-#endif
-
+#include "base/compiler_specific.h"
#include "base/lock.h"
-#include "base/message_loop_proxy.h"
-#include "base/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "base/stl_util-inl.h"
#include "base/worker_pool.h"
-#include "net/base/cert_verify_result.h"
#include "net/base/net_errors.h"
#include "net/base/x509_certificate.h"
+#if defined(USE_NSS)
+#include <private/pprthred.h> // PR_DetachThread
+#endif
+
namespace net {
-class CertVerifier::Request :
- public base::RefCountedThreadSafe<CertVerifier::Request> {
+////////////////////////////////////////////////////////////////////////////
+
+// Life of a request:
+//
+// CertVerifier CertVerifierJob CertVerifierWorker Request
+// | (origin loop) (worker loop)
+// |
+// Verify()
+// |---->-------------------<creates>
+// |
+// |---->----<creates>
+// |
+// |---->---------------------------------------------------<creates>
+// |
+// |---->--------------------Start
+// | |
+// | PostTask
+// |
+// | <starts verifying>
+// |---->-----AddRequest |
+// |
+// |
+// |
+// Finish
+// |
+// PostTask
+//
+// |
+// DoReply
+// |----<-----------------------|
+// HandleResult
+// |
+// |---->-----HandleResult
+// |
+// |------>-----------------------------------Post
+//
+//
+//
+// On a cache hit, CertVerifier::Verify() returns synchronously without
+// posting a task to a worker thread.
+
+// The number of CachedCertVerifyResult objects that we'll cache.
+static const unsigned kMaxCacheEntries = 256;
+
+// The number of seconds for which we'll cache a cache entry.
+static const unsigned kTTLSecs = 1800; // 30 minutes.
+
+namespace {
+
+class DefaultTimeService : public CertVerifier::TimeService {
+ public:
+ // CertVerifier::TimeService methods:
+ virtual base::Time Now() { return base::Time::Now(); }
+};
+
+} // namespace
+
+CachedCertVerifyResult::CachedCertVerifyResult() : error(ERR_FAILED) {
+}
+
+CachedCertVerifyResult::~CachedCertVerifyResult() {}
+
+bool CachedCertVerifyResult::HasExpired(const base::Time current_time) const {
+ return current_time >= expiry;
+}
+
+// Represents the output and result callback of a request.
+class CertVerifierRequest {
public:
- Request(CertVerifier* verifier,
- X509Certificate* cert,
- const std::string& hostname,
- int flags,
- CertVerifyResult* verify_result,
- CompletionCallback* callback)
+ CertVerifierRequest(CompletionCallback* callback,
+ CertVerifyResult* verify_result)
+ : callback_(callback),
+ verify_result_(verify_result) {
+ }
+
+ // Ensures that the result callback will never be made.
+ void Cancel() {
+ callback_ = NULL;
+ verify_result_ = NULL;
+ }
+
+ // Copies the contents of |verify_result| to the caller's
+ // CertVerifyResult and calls the callback.
+ void Post(const CachedCertVerifyResult& verify_result) {
+ if (callback_) {
+ *verify_result_ = verify_result.result;
+ callback_->Run(verify_result.error);
+ }
+ delete this;
+ }
+
+ private:
+ CompletionCallback* callback_;
+ CertVerifyResult* verify_result_;
+};
+
+
+// CertVerifierWorker runs on a worker thread and takes care of the blocking
+// process of performing the certificate verification. Deletes itself
+// eventually if Start() succeeds.
+class CertVerifierWorker {
+ public:
+ CertVerifierWorker(X509Certificate* cert,
+ const std::string& hostname,
+ int flags,
+ CertVerifier* cert_verifier)
: cert_(cert),
hostname_(hostname),
flags_(flags),
- verifier_(verifier),
- verify_result_(verify_result),
- callback_(callback),
- origin_loop_proxy_(base::MessageLoopProxy::CreateForCurrentThread()),
- error_(OK) {
+ origin_loop_(MessageLoop::current()),
+ cert_verifier_(cert_verifier),
+ canceled_(false),
+ error_(ERR_FAILED) {
+ }
+
+ bool Start() {
+ DCHECK_EQ(MessageLoop::current(), origin_loop_);
+
+ return WorkerPool::PostTask(
+ FROM_HERE, NewRunnableMethod(this, &CertVerifierWorker::Run),
+ true /* task is slow */);
}
- void DoVerify() {
- // Running on the worker thread
- error_ = cert_->Verify(hostname_, flags_, &result_);
+ // Cancel is called from the origin loop when the CertVerifier is getting
+ // deleted.
+ void Cancel() {
+ DCHECK_EQ(MessageLoop::current(), origin_loop_);
+ AutoLock locked(lock_);
+ canceled_ = true;
+ }
+
+ private:
+ void Run() {
+ // Runs on a worker thread.
+ error_ = cert_->Verify(hostname_, flags_, &verify_result_);
#if defined(USE_NSS)
// Detach the thread from NSPR.
// Calling NSS functions attaches the thread to NSPR, which stores
@@ -50,109 +163,319 @@ class CertVerifier::Request :
// destructors run.
PR_DetachThread();
#endif
+ Finish();
+ }
- scoped_ptr<Task> reply(NewRunnableMethod(this, &Request::DoCallback));
-
- // The origin loop could go away while we are trying to post to it, so we
- // need to call its PostTask method inside a lock. See ~CertVerifier.
- AutoLock locked(origin_loop_proxy_lock_);
- if (origin_loop_proxy_) {
- bool posted = origin_loop_proxy_->PostTask(FROM_HERE, reply.release());
- // TODO(willchan): Fix leaks and then change this to a DCHECK.
- LOG_IF(ERROR, !posted) << "Leaked CertVerifier!";
+ // DoReply runs on the origin thread.
+ void DoReply() {
+ DCHECK_EQ(MessageLoop::current(), origin_loop_);
+ {
+ // We lock here because the worker thread could still be in Finished,
+ // after the PostTask, but before unlocking |lock_|. If we do not lock in
+ // this case, we will end up deleting a locked Lock, which can lead to
+ // memory leaks or worse errors.
+ AutoLock locked(lock_);
+ if (!canceled_) {
+ cert_verifier_->HandleResult(cert_, hostname_, flags_,
+ error_, verify_result_);
+ }
}
+ delete this;
}
- void DoCallback() {
- // Running on the origin thread.
+ void Finish() {
+ // Runs on the worker thread.
+ // We assume that the origin loop outlives the CertVerifier. If the
+ // CertVerifier is deleted, it will call Cancel on us. If it does so
+ // before the Acquire, we'll delete ourselves and return. If it's trying to
+ // do so concurrently, then it'll block on the lock and we'll call PostTask
+ // while the CertVerifier (and therefore the MessageLoop) is still alive.
+ // If it does so after this function, we assume that the MessageLoop will
+ // process pending tasks. In which case we'll notice the |canceled_| flag
+ // in DoReply.
- // We may have been cancelled!
- if (!verifier_)
- return;
+ bool canceled;
+ {
+ AutoLock locked(lock_);
+ canceled = canceled_;
+ if (!canceled) {
+ origin_loop_->PostTask(
+ FROM_HERE, NewRunnableMethod(this, &CertVerifierWorker::DoReply));
+ }
+ }
- *verify_result_ = result_;
+ if (canceled)
+ delete this;
+ }
- // Drop the verifier's reference to us. Do this before running the
- // callback since the callback might result in the verifier being
- // destroyed.
- verifier_->request_ = NULL;
+ scoped_refptr<X509Certificate> cert_;
+ const std::string hostname_;
+ const int flags_;
+ MessageLoop* const origin_loop_;
+ CertVerifier* const cert_verifier_;
- callback_->Run(error_);
- }
+ // lock_ protects canceled_.
+ Lock lock_;
- void Cancel() {
- verifier_ = NULL;
+ // If canceled_ is true,
+ // * origin_loop_ cannot be accessed by the worker thread,
+ // * cert_verifier_ cannot be accessed by any thread.
+ bool canceled_;
+
+ int error_;
+ CertVerifyResult verify_result_;
+
+ DISALLOW_COPY_AND_ASSIGN(CertVerifierWorker);
+};
- AutoLock locked(origin_loop_proxy_lock_);
- origin_loop_proxy_ = NULL;
+// A CertVerifierJob is a one-to-one counterpart of a CertVerifierWorker. It
+// lives only on the CertVerifier's origin message loop.
+class CertVerifierJob {
+ public:
+ explicit CertVerifierJob(CertVerifierWorker* worker) : worker_(worker) {
}
- private:
- friend class base::RefCountedThreadSafe<CertVerifier::Request>;
+ ~CertVerifierJob() {
+ if (worker_)
+ worker_->Cancel();
+ }
- ~Request() {}
+ void AddRequest(CertVerifierRequest* request) {
+ requests_.push_back(request);
+ }
- // Set on the origin thread, read on the worker thread.
- scoped_refptr<X509Certificate> cert_;
- std::string hostname_;
- // bitwise OR'd of X509Certificate::VerifyFlags.
- int flags_;
+ void HandleResult(const CachedCertVerifyResult& verify_result) {
+ worker_ = NULL;
+ PostAll(verify_result);
+ }
- // Only used on the origin thread (where Verify was called).
- CertVerifier* verifier_;
- CertVerifyResult* verify_result_;
- CompletionCallback* callback_;
+ private:
+ void PostAll(const CachedCertVerifyResult& verify_result) {
+ std::vector<CertVerifierRequest*> requests;
+ requests_.swap(requests);
- // Used to post ourselves onto the origin thread.
- Lock origin_loop_proxy_lock_;
- // Use a MessageLoopProxy in case the owner of the CertVerifier is leaked, so
- // this code won't crash: http://crbug.com/42275. If this is leaked, then it
- // doesn't get Cancel()'d, so |origin_loop_proxy_| doesn't get NULL'd out. If
- // the MessageLoop goes away, then if we had used a MessageLoop, this would
- // crash.
- scoped_refptr<base::MessageLoopProxy> origin_loop_proxy_;
+ for (std::vector<CertVerifierRequest*>::iterator
+ i = requests.begin(); i != requests.end(); i++) {
+ (*i)->Post(verify_result);
+ // Post() causes the CertVerifierRequest to delete itself.
+ }
+ }
- // Assigned on the worker thread, read on the origin thread.
- int error_;
- CertVerifyResult result_;
+ std::vector<CertVerifierRequest*> requests_;
+ CertVerifierWorker* worker_;
};
-//-----------------------------------------------------------------------------
-CertVerifier::CertVerifier() {
+CertVerifier::CertVerifier()
+ : time_service_(new DefaultTimeService),
+ requests_(0),
+ cache_hits_(0),
+ inflight_joins_(0) {
+}
+
+CertVerifier::CertVerifier(TimeService* time_service)
+ : time_service_(time_service),
+ requests_(0),
+ cache_hits_(0),
+ inflight_joins_(0) {
}
CertVerifier::~CertVerifier() {
- if (request_)
- request_->Cancel();
+ STLDeleteValues(&inflight_);
}
int CertVerifier::Verify(X509Certificate* cert,
const std::string& hostname,
int flags,
CertVerifyResult* verify_result,
- CompletionCallback* callback) {
- DCHECK(!request_) << "verifier already in use";
+ CompletionCallback* callback,
+ RequestHandle* out_req) {
+ DCHECK(CalledOnValidThread());
- // Do a synchronous verification.
- if (!callback) {
- CertVerifyResult result;
- int rv = cert->Verify(hostname, flags, &result);
- *verify_result = result;
- return rv;
+ if (!callback || !verify_result || hostname.empty()) {
+ *out_req = NULL;
+ return ERR_INVALID_ARGUMENT;
}
- request_ = new Request(this, cert, hostname, flags, verify_result, callback);
+ requests_++;
- // Dispatch to worker thread...
- if (!WorkerPool::PostTask(FROM_HERE,
- NewRunnableMethod(request_.get(), &Request::DoVerify), true)) {
- NOTREACHED();
- request_ = NULL;
- return ERR_FAILED;
+ const RequestParams key = {cert->fingerprint(), hostname, flags};
+ // First check the cache.
+ std::map<RequestParams, CachedCertVerifyResult>::iterator i;
+ i = cache_.find(key);
+ if (i != cache_.end()) {
+ if (!i->second.HasExpired(time_service_->Now())) {
+ cache_hits_++;
+ *out_req = NULL;
+ *verify_result = i->second.result;
+ return i->second.error;
+ }
+ // Cache entry has expired.
+ cache_.erase(i);
}
+ // No cache hit. See if an identical request is currently in flight.
+ CertVerifierJob* job;
+ std::map<RequestParams, CertVerifierJob*>::const_iterator j;
+ j = inflight_.find(key);
+ if (j != inflight_.end()) {
+ // An identical request is in flight already. We'll just attach our
+ // callback.
+ inflight_joins_++;
+ job = j->second;
+ } else {
+ // Need to make a new request.
+ CertVerifierWorker* worker = new CertVerifierWorker(cert, hostname, flags,
+ this);
+ job = new CertVerifierJob(worker);
+ inflight_.insert(std::make_pair(key, job));
+ if (!worker->Start()) {
+ inflight_.erase(key);
+ delete job;
+ delete worker;
+ *out_req = NULL;
+ return ERR_FAILED; // TODO(wtc): Log an error message.
+ }
+ }
+
+ CertVerifierRequest* request =
+ new CertVerifierRequest(callback, verify_result);
+ job->AddRequest(request);
+ *out_req = request;
return ERR_IO_PENDING;
}
+void CertVerifier::CancelRequest(RequestHandle req) {
+ DCHECK(CalledOnValidThread());
+ CertVerifierRequest* request = reinterpret_cast<CertVerifierRequest*>(req);
+ request->Cancel();
+}
+
+void CertVerifier::ClearCache() {
+ DCHECK(CalledOnValidThread());
+
+ cache_.clear();
+ // Leaves inflight_ alone.
+}
+
+size_t CertVerifier::GetCacheSize() const {
+ DCHECK(CalledOnValidThread());
+
+ return cache_.size();
+}
+
+// HandleResult is called by CertVerifierWorker on the origin message loop.
+// It deletes CertVerifierJob.
+void CertVerifier::HandleResult(X509Certificate* cert,
+ const std::string& hostname,
+ int flags,
+ int error,
+ const CertVerifyResult& verify_result) {
+ DCHECK(CalledOnValidThread());
+
+ const base::Time current_time(time_service_->Now());
+
+ CachedCertVerifyResult cached_result;
+ cached_result.error = error;
+ cached_result.result = verify_result;
+ uint32 ttl = kTTLSecs;
+ cached_result.expiry = current_time + base::TimeDelta::FromSeconds(ttl);
+
+ const RequestParams key = {cert->fingerprint(), hostname, flags};
+
+ DCHECK_GE(kMaxCacheEntries, 1u);
+ DCHECK_LE(cache_.size(), kMaxCacheEntries);
+ if (cache_.size() == kMaxCacheEntries) {
+ // Need to remove an element of the cache.
+ std::map<RequestParams, CachedCertVerifyResult>::iterator i, cur;
+ for (i = cache_.begin(); i != cache_.end(); ) {
+ cur = i++;
+ if (cur->second.HasExpired(current_time))
+ cache_.erase(cur);
+ }
+ }
+ if (cache_.size() == kMaxCacheEntries) {
+ // If we didn't clear out any expired entries, we just remove the first
+ // element. Crummy but simple.
+ cache_.erase(cache_.begin());
+ }
+
+ cache_.insert(std::make_pair(key, cached_result));
+
+ std::map<RequestParams, CertVerifierJob*>::iterator j;
+ j = inflight_.find(key);
+ if (j == inflight_.end()) {
+ NOTREACHED();
+ return;
+ }
+ CertVerifierJob* job = j->second;
+ inflight_.erase(j);
+
+ job->HandleResult(cached_result);
+ delete job;
+}
+
+/////////////////////////////////////////////////////////////////////
+
+SingleRequestCertVerifier::SingleRequestCertVerifier(
+ CertVerifier* cert_verifier)
+ : cert_verifier_(cert_verifier),
+ cur_request_(NULL),
+ cur_request_callback_(NULL),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ callback_(this, &SingleRequestCertVerifier::OnVerifyCompletion)) {
+ DCHECK(cert_verifier_ != NULL);
+}
+
+SingleRequestCertVerifier::~SingleRequestCertVerifier() {
+ if (cur_request_) {
+ cert_verifier_->CancelRequest(cur_request_);
+ cur_request_ = NULL;
+ }
+}
+
+int SingleRequestCertVerifier::Verify(X509Certificate* cert,
+ const std::string& hostname,
+ int flags,
+ CertVerifyResult* verify_result,
+ CompletionCallback* callback) {
+ // Should not be already in use.
+ DCHECK(!cur_request_ && !cur_request_callback_);
+
+ // Do a synchronous verification.
+ if (!callback)
+ return cert->Verify(hostname, flags, verify_result);
+
+ CertVerifier::RequestHandle request = NULL;
+
+ // We need to be notified of completion before |callback| is called, so that
+ // we can clear out |cur_request_*|.
+ int rv = cert_verifier_->Verify(
+ cert, hostname, flags, verify_result, &callback_, &request);
+
+ if (rv == ERR_IO_PENDING) {
+ // Cleared in OnVerifyCompletion().
+ cur_request_ = request;
+ cur_request_callback_ = callback;
+ }
+
+ return rv;
+}
+
+void SingleRequestCertVerifier::OnVerifyCompletion(int result) {
+ DCHECK(cur_request_ && cur_request_callback_);
+
+ CompletionCallback* callback = cur_request_callback_;
+
+ // Clear the outstanding request information.
+ cur_request_ = NULL;
+ cur_request_callback_ = NULL;
+
+ // Call the user's original callback.
+ callback->Run(result);
+}
+
} // namespace net
+
+DISABLE_RUNNABLE_METHOD_REFCOUNT(net::CertVerifierWorker);
+
diff --git a/net/base/cert_verifier.h b/net/base/cert_verifier.h
index 791f8d3..3d19abb 100644
--- a/net/base/cert_verifier.h
+++ b/net/base/cert_verifier.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2008-2009 The Chromium Authors. All rights reserved.
+// 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.
@@ -6,29 +6,68 @@
#define NET_BASE_CERT_VERIFIER_H_
#pragma once
+#include <map>
#include <string>
#include "base/basictypes.h"
-#include "base/ref_counted.h"
+#include "base/non_thread_safe.h"
+#include "base/scoped_ptr.h"
+#include "base/time.h"
+#include "net/base/cert_verify_result.h"
#include "net/base/completion_callback.h"
+#include "net/base/x509_cert_types.h"
namespace net {
-class CertVerifyResult;
+class CertVerifierJob;
+class CertVerifierWorker;
class X509Certificate;
-// This class represents the task of verifying a certificate. It can only
-// verify a single certificate at a time, so if you need to verify multiple
-// certificates at the same time, you will need to allocate a CertVerifier
-// object for each certificate.
+// CachedCertVerifyResult contains the result of a certificate verification.
+struct CachedCertVerifyResult {
+ CachedCertVerifyResult();
+ ~CachedCertVerifyResult();
+
+ int error; // The return value of CertVerifier::Verify.
+ CertVerifyResult result; // The output of CertVerifier::Verify.
+
+ // The time at which the certificate verification result expires.
+ base::Time expiry;
+
+ // Returns true if |current_time| is greater than or equal to |expiry|.
+ bool HasExpired(base::Time current_time) const;
+};
+
+// CertVerifier represents a service for verifying certificates.
//
-class CertVerifier {
+// CertVerifier can handle multiple requests at a time, so when canceling a
+// request the RequestHandle that was returned by Verify() needs to be
+// given. A simpler alternative for consumers that only have 1 outstanding
+// request at a time is to create a SingleRequestCertVerifier wrapper around
+// CertVerifier (which will automatically cancel the single request when it
+// goes out of scope).
+class CertVerifier : public NonThreadSafe {
public:
+ // Opaque type used to cancel a request.
+ typedef void* RequestHandle;
+
+ // CertVerifier must not call base::Time::Now() directly. It must call
+ // time_service_->Now(). This allows unit tests to mock the current time.
+ class TimeService {
+ public:
+ virtual ~TimeService() {}
+
+ virtual base::Time Now() = 0;
+ };
+
CertVerifier();
- // If a completion callback is pending when the verifier is destroyed, the
- // certificate verification is cancelled, and the completion callback will
- // not be called.
+ // Used by unit tests to mock the current time. Takes ownership of
+ // |time_service|.
+ explicit CertVerifier(TimeService* time_service);
+
+ // When the verifier is destroyed, all certificate verifications requests are
+ // canceled, and their completion callbacks will not be called.
~CertVerifier();
// Verifies the given certificate against the given hostname. Returns OK if
@@ -49,23 +88,128 @@ class CertVerifier {
// VERIFY_REV_CHECKING_ENABLED is not set), EV certificate verification will
// not be performed.
//
- // When callback is null, the operation completes synchronously.
- //
- // When callback is non-null, ERR_IO_PENDING is returned if the operation
+ // |callback| must not be null. ERR_IO_PENDING is returned if the operation
// could not be completed synchronously, in which case the result code will
// be passed to the callback when available.
//
- int Verify(X509Certificate* cert, const std::string& hostname,
- int flags, CertVerifyResult* verify_result,
- CompletionCallback* callback);
+ // If |out_req| is non-NULL, then |*out_req| will be filled with a handle to
+ // the async request. This handle is not valid after the request has
+ // completed.
+ int Verify(X509Certificate* cert,
+ const std::string& hostname,
+ int flags,
+ CertVerifyResult* verify_result,
+ CompletionCallback* callback,
+ RequestHandle* out_req);
+
+ // Cancels the specified request. |req| is the handle returned by Verify().
+ // After a request is canceled, its completion callback will not be called.
+ void CancelRequest(RequestHandle req);
+
+ // Clears the verification result cache.
+ void ClearCache();
+
+ size_t GetCacheSize() const;
+
+ uint64 requests() const { return requests_; }
+ uint64 cache_hits() const { return cache_hits_; }
+ uint64 inflight_joins() const { return inflight_joins_; }
private:
- class Request;
- friend class Request;
- scoped_refptr<Request> request_;
+ friend class CertVerifierWorker; // Calls HandleResult.
+
+ // Input parameters of a certificate verification request.
+ struct RequestParams {
+ bool operator==(const RequestParams& other) const {
+ // |flags| is compared before |cert_fingerprint| and |hostname| under
+ // assumption that integer comparisons are faster than memory and string
+ // comparisons.
+ return (flags == other.flags &&
+ memcmp(cert_fingerprint.data, other.cert_fingerprint.data,
+ sizeof(cert_fingerprint.data)) == 0 &&
+ hostname == other.hostname);
+ }
+
+ bool operator<(const RequestParams& other) const {
+ // |flags| is compared before |cert_fingerprint| and |hostname| under
+ // assumption that integer comparisons are faster than memory and string
+ // comparisons.
+ if (flags != other.flags)
+ return flags < other.flags;
+ int rv = memcmp(cert_fingerprint.data, other.cert_fingerprint.data,
+ sizeof(cert_fingerprint.data));
+ if (rv != 0)
+ return rv < 0;
+ return hostname < other.hostname;
+ }
+
+ SHA1Fingerprint cert_fingerprint;
+ std::string hostname;
+ int flags;
+ };
+
+ void HandleResult(X509Certificate* cert,
+ const std::string& hostname,
+ int flags,
+ int error,
+ const CertVerifyResult& verify_result);
+
+ // cache_ maps from a request to a cached result. The cached result may
+ // have expired and the size of |cache_| must be <= kMaxCacheEntries.
+ std::map<RequestParams, CachedCertVerifyResult> cache_;
+
+ // inflight_ maps from a request to an active verification which is taking
+ // place.
+ std::map<RequestParams, CertVerifierJob*> inflight_;
+
+ scoped_ptr<TimeService> time_service_;
+
+ uint64 requests_;
+ uint64 cache_hits_;
+ uint64 inflight_joins_;
+
DISALLOW_COPY_AND_ASSIGN(CertVerifier);
};
+// This class represents the task of verifying a certificate. It wraps
+// CertVerifier to verify only a single certificate at a time and cancels this
+// request when going out of scope.
+class SingleRequestCertVerifier {
+ public:
+ // |cert_verifier| must remain valid for the lifetime of |this|.
+ explicit SingleRequestCertVerifier(CertVerifier* cert_verifier);
+
+ // If a completion callback is pending when the verifier is destroyed, the
+ // certificate verification is canceled, and the completion callback will
+ // not be called.
+ ~SingleRequestCertVerifier();
+
+ // Verifies the given certificate, filling out the |verify_result| object
+ // upon success. See CertVerifier::Verify() for details.
+ int Verify(X509Certificate* cert,
+ const std::string& hostname,
+ int flags,
+ CertVerifyResult* verify_result,
+ CompletionCallback* callback);
+
+ private:
+ // Callback for when the request to |cert_verifier_| completes, so we
+ // dispatch to the user's callback.
+ void OnVerifyCompletion(int result);
+
+ // The actual certificate verifier that will handle the request.
+ CertVerifier* const cert_verifier_;
+
+ // The current request (if any).
+ CertVerifier::RequestHandle cur_request_;
+ CompletionCallback* cur_request_callback_;
+
+ // Completion callback for when request to |cert_verifier_| completes.
+ net::CompletionCallbackImpl<SingleRequestCertVerifier> callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(SingleRequestCertVerifier);
+};
+
} // namespace net
#endif // NET_BASE_CERT_VERIFIER_H_
diff --git a/net/base/cert_verifier_unittest.cc b/net/base/cert_verifier_unittest.cc
new file mode 100644
index 0000000..ca5e1f4
--- /dev/null
+++ b/net/base/cert_verifier_unittest.cc
@@ -0,0 +1,260 @@
+// 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.
+
+#include "net/base/cert_verifier.h"
+
+#include "base/callback.h"
+#include "base/file_path.h"
+#include "base/stringprintf.h"
+#include "net/base/cert_test_util.h"
+#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
+#include "net/base/x509_certificate.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+class TestTimeService : public CertVerifier::TimeService {
+ public:
+ // CertVerifier::TimeService methods:
+ virtual base::Time Now() { return current_time_; }
+
+ void set_current_time(base::Time now) { current_time_ = now; }
+
+ private:
+ base::Time current_time_;
+};
+
+class CertVerifierTest : public testing::Test {
+};
+
+class ExplodingCallback : public CallbackRunner<Tuple1<int> > {
+ public:
+ virtual void RunWithParams(const Tuple1<int>& params) {
+ FAIL();
+ }
+};
+
+// Tests a cache hit, which should results in synchronous completion.
+TEST_F(CertVerifierTest, CacheHit) {
+ TestTimeService* time_service = new TestTimeService;
+ base::Time current_time = base::Time::Now();
+ time_service->set_current_time(current_time);
+ CertVerifier verifier(time_service);
+
+ FilePath certs_dir = GetTestCertsDirectory();
+ scoped_refptr<X509Certificate> google_cert(
+ ImportCertFromFile(certs_dir, "google.single.der"));
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), google_cert);
+
+ int error;
+ CertVerifyResult verify_result;
+ TestCompletionCallback callback;
+ CertVerifier::RequestHandle request_handle;
+
+ error = verifier.Verify(google_cert, "www.example.com", 0, &verify_result,
+ &callback, &request_handle);
+ ASSERT_EQ(ERR_IO_PENDING, error);
+ ASSERT_TRUE(request_handle != NULL);
+ error = callback.WaitForResult();
+ ASSERT_TRUE(IsCertificateError(error));
+ ASSERT_EQ(1u, verifier.requests());
+ ASSERT_EQ(0u, verifier.cache_hits());
+ ASSERT_EQ(0u, verifier.inflight_joins());
+
+ error = verifier.Verify(google_cert, "www.example.com", 0, &verify_result,
+ &callback, &request_handle);
+ // Synchronous completion.
+ ASSERT_NE(ERR_IO_PENDING, error);
+ ASSERT_TRUE(IsCertificateError(error));
+ ASSERT_TRUE(request_handle == NULL);
+ ASSERT_EQ(2u, verifier.requests());
+ ASSERT_EQ(1u, verifier.cache_hits());
+ ASSERT_EQ(0u, verifier.inflight_joins());
+}
+
+// Tests an inflight join.
+TEST_F(CertVerifierTest, InflightJoin) {
+ TestTimeService* time_service = new TestTimeService;
+ base::Time current_time = base::Time::Now();
+ time_service->set_current_time(current_time);
+ CertVerifier verifier(time_service);
+
+ FilePath certs_dir = GetTestCertsDirectory();
+ scoped_refptr<X509Certificate> google_cert(
+ ImportCertFromFile(certs_dir, "google.single.der"));
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), google_cert);
+
+ int error;
+ CertVerifyResult verify_result;
+ TestCompletionCallback callback;
+ CertVerifier::RequestHandle request_handle;
+ CertVerifyResult verify_result2;
+ TestCompletionCallback callback2;
+ CertVerifier::RequestHandle request_handle2;
+
+ error = verifier.Verify(google_cert, "www.example.com", 0, &verify_result,
+ &callback, &request_handle);
+ ASSERT_EQ(ERR_IO_PENDING, error);
+ ASSERT_TRUE(request_handle != NULL);
+ error = verifier.Verify(google_cert, "www.example.com", 0, &verify_result2,
+ &callback2, &request_handle2);
+ ASSERT_EQ(ERR_IO_PENDING, error);
+ ASSERT_TRUE(request_handle2 != NULL);
+ error = callback.WaitForResult();
+ ASSERT_TRUE(IsCertificateError(error));
+ error = callback2.WaitForResult();
+ ASSERT_TRUE(IsCertificateError(error));
+ ASSERT_EQ(2u, verifier.requests());
+ ASSERT_EQ(0u, verifier.cache_hits());
+ ASSERT_EQ(1u, verifier.inflight_joins());
+}
+
+// Tests cache entry expiration.
+TEST_F(CertVerifierTest, ExpiredCacheEntry) {
+ TestTimeService* time_service = new TestTimeService;
+ base::Time current_time = base::Time::Now();
+ time_service->set_current_time(current_time);
+ CertVerifier verifier(time_service);
+
+ FilePath certs_dir = GetTestCertsDirectory();
+ scoped_refptr<X509Certificate> google_cert(
+ ImportCertFromFile(certs_dir, "google.single.der"));
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), google_cert);
+
+ int error;
+ CertVerifyResult verify_result;
+ TestCompletionCallback callback;
+ CertVerifier::RequestHandle request_handle;
+
+ error = verifier.Verify(google_cert, "www.example.com", 0, &verify_result,
+ &callback, &request_handle);
+ ASSERT_EQ(ERR_IO_PENDING, error);
+ ASSERT_TRUE(request_handle != NULL);
+ error = callback.WaitForResult();
+ ASSERT_TRUE(IsCertificateError(error));
+ ASSERT_EQ(1u, verifier.requests());
+ ASSERT_EQ(0u, verifier.cache_hits());
+ ASSERT_EQ(0u, verifier.inflight_joins());
+
+ // Before expiration, should have a cache hit.
+ error = verifier.Verify(google_cert, "www.example.com", 0, &verify_result,
+ &callback, &request_handle);
+ // Synchronous completion.
+ ASSERT_NE(ERR_IO_PENDING, error);
+ ASSERT_TRUE(IsCertificateError(error));
+ ASSERT_TRUE(request_handle == NULL);
+ ASSERT_EQ(2u, verifier.requests());
+ ASSERT_EQ(1u, verifier.cache_hits());
+ ASSERT_EQ(0u, verifier.inflight_joins());
+
+ // After expiration, should not have a cache hit.
+ ASSERT_EQ(1u, verifier.GetCacheSize());
+ current_time += base::TimeDelta::FromMinutes(60);
+ time_service->set_current_time(current_time);
+ error = verifier.Verify(google_cert, "www.example.com", 0, &verify_result,
+ &callback, &request_handle);
+ ASSERT_EQ(ERR_IO_PENDING, error);
+ ASSERT_TRUE(request_handle != NULL);
+ ASSERT_EQ(0u, verifier.GetCacheSize());
+ error = callback.WaitForResult();
+ ASSERT_TRUE(IsCertificateError(error));
+ ASSERT_EQ(3u, verifier.requests());
+ ASSERT_EQ(1u, verifier.cache_hits());
+ ASSERT_EQ(0u, verifier.inflight_joins());
+}
+
+// Tests a full cache.
+TEST_F(CertVerifierTest, FullCache) {
+ TestTimeService* time_service = new TestTimeService;
+ base::Time current_time = base::Time::Now();
+ time_service->set_current_time(current_time);
+ CertVerifier verifier(time_service);
+
+ FilePath certs_dir = GetTestCertsDirectory();
+ scoped_refptr<X509Certificate> google_cert(
+ ImportCertFromFile(certs_dir, "google.single.der"));
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), google_cert);
+
+ int error;
+ CertVerifyResult verify_result;
+ TestCompletionCallback callback;
+ CertVerifier::RequestHandle request_handle;
+
+ error = verifier.Verify(google_cert, "www.example.com", 0, &verify_result,
+ &callback, &request_handle);
+ ASSERT_EQ(ERR_IO_PENDING, error);
+ ASSERT_TRUE(request_handle != NULL);
+ error = callback.WaitForResult();
+ ASSERT_TRUE(IsCertificateError(error));
+ ASSERT_EQ(1u, verifier.requests());
+ ASSERT_EQ(0u, verifier.cache_hits());
+ ASSERT_EQ(0u, verifier.inflight_joins());
+
+ const unsigned kCacheSize = 256;
+
+ for (unsigned i = 0; i < kCacheSize; i++) {
+ std::string hostname = base::StringPrintf("www%d.example.com", i + 1);
+ error = verifier.Verify(google_cert, hostname, 0, &verify_result,
+ &callback, &request_handle);
+ ASSERT_EQ(ERR_IO_PENDING, error);
+ ASSERT_TRUE(request_handle != NULL);
+ error = callback.WaitForResult();
+ ASSERT_TRUE(IsCertificateError(error));
+ }
+ ASSERT_EQ(kCacheSize + 1, verifier.requests());
+ ASSERT_EQ(0u, verifier.cache_hits());
+ ASSERT_EQ(0u, verifier.inflight_joins());
+
+ ASSERT_EQ(kCacheSize, verifier.GetCacheSize());
+ current_time += base::TimeDelta::FromMinutes(60);
+ time_service->set_current_time(current_time);
+ error = verifier.Verify(google_cert, "www999.example.com", 0, &verify_result,
+ &callback, &request_handle);
+ ASSERT_EQ(ERR_IO_PENDING, error);
+ ASSERT_TRUE(request_handle != NULL);
+ ASSERT_EQ(kCacheSize, verifier.GetCacheSize());
+ error = callback.WaitForResult();
+ ASSERT_EQ(1u, verifier.GetCacheSize());
+ ASSERT_TRUE(IsCertificateError(error));
+ ASSERT_EQ(kCacheSize + 2, verifier.requests());
+ ASSERT_EQ(0u, verifier.cache_hits());
+ ASSERT_EQ(0u, verifier.inflight_joins());
+}
+
+// Tests that the callback of a canceled request is never made.
+TEST_F(CertVerifierTest, CancelRequest) {
+ CertVerifier verifier;
+
+ FilePath certs_dir = GetTestCertsDirectory();
+ scoped_refptr<X509Certificate> google_cert(
+ ImportCertFromFile(certs_dir, "google.single.der"));
+ ASSERT_NE(static_cast<X509Certificate*>(NULL), google_cert);
+
+ int error;
+ CertVerifyResult verify_result;
+ ExplodingCallback exploding_callback;
+ CertVerifier::RequestHandle request_handle;
+
+ error = verifier.Verify(google_cert, "www.example.com", 0, &verify_result,
+ &exploding_callback, &request_handle);
+ ASSERT_EQ(ERR_IO_PENDING, error);
+ ASSERT_TRUE(request_handle != NULL);
+ verifier.CancelRequest(request_handle);
+
+ // Issue a few more requests to the worker pool and wait for their
+ // completion, so that the task of the canceled request (which runs on a
+ // worker thread) is likely to complete by the end of this test.
+ TestCompletionCallback callback;
+ for (int i = 0; i < 5; ++i) {
+ error = verifier.Verify(google_cert, "www2.example.com", 0, &verify_result,
+ &callback, &request_handle);
+ ASSERT_EQ(ERR_IO_PENDING, error);
+ ASSERT_TRUE(request_handle != NULL);
+ error = callback.WaitForResult();
+ verifier.ClearCache();
+ }
+}
+
+} // namespace net
diff --git a/net/base/cookie_monster.cc b/net/base/cookie_monster.cc
index 1bb2d01..76589c7 100644
--- a/net/base/cookie_monster.cc
+++ b/net/base/cookie_monster.cc
@@ -407,7 +407,15 @@ void CookieMonster::SetExpiryAndKeyScheme(ExpiryAndKeyScheme key_scheme) {
expiry_and_key_scheme_ = key_scheme;
}
+<<<<<<< HEAD
#if defined(ANDROID)
+=======
+void CookieMonster::SetClearPersistentStoreOnExit(bool clear_local_store) {
+ if(store_)
+ store_->SetClearLocalStateOnExit(clear_local_store);
+}
+
+>>>>>>> chromium.org at r10.0.621.0
void CookieMonster::FlushStore(Task* completion_task) {
AutoLock autolock(lock_);
if (initialized_ && store_)
@@ -415,7 +423,10 @@ void CookieMonster::FlushStore(Task* completion_task) {
else if (completion_task)
MessageLoop::current()->PostTask(FROM_HERE, completion_task);
}
+<<<<<<< HEAD
#endif
+=======
+>>>>>>> chromium.org at r10.0.621.0
// The system resolution is not high enough, so we can have multiple
// set cookies that result in the same system time. When this happens, we
@@ -1329,7 +1340,11 @@ void CookieMonster::DeleteCookie(const GURL& url,
}
}
-CookieMonster::CookieList CookieMonster::GetAllCookies() {
+CookieMonster* CookieMonster::GetCookieMonster() {
+ return this;
+}
+
+CookieList CookieMonster::GetAllCookies() {
AutoLock autolock(lock_);
InitIfNecessary();
@@ -1362,13 +1377,12 @@ CookieMonster::CookieList CookieMonster::GetAllCookies() {
return cookie_list;
}
-CookieMonster::CookieList CookieMonster::GetAllCookiesForURL(const GURL& url) {
+CookieList CookieMonster::GetAllCookiesForURLWithOptions(
+ const GURL& url,
+ const CookieOptions& options) {
AutoLock autolock(lock_);
InitIfNecessary();
- CookieOptions options;
- options.set_include_httponly();
-
std::vector<CanonicalCookie*> cookie_ptrs;
FindCookiesForHostAndDomain(url, options, false, &cookie_ptrs);
std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter);
@@ -1381,6 +1395,13 @@ CookieMonster::CookieList CookieMonster::GetAllCookiesForURL(const GURL& url) {
return cookies;
}
+CookieList CookieMonster::GetAllCookiesForURL(const GURL& url) {
+ CookieOptions options;
+ options.set_include_httponly();
+
+ return GetAllCookiesForURLWithOptions(url, options);
+}
+
void CookieMonster::FindCookiesForHostAndDomain(
const GURL& url,
const CookieOptions& options,
diff --git a/net/base/cookie_monster.h b/net/base/cookie_monster.h
index b168eb8..2c66554 100644
--- a/net/base/cookie_monster.h
+++ b/net/base/cookie_monster.h
@@ -30,6 +30,8 @@ class Histogram;
namespace net {
+class CookieList;
+
// The cookie monster is the system for storing and retrieving cookies. It has
// an in-memory list of all cookies, and synchronizes non-session cookies to an
// optional permanent storage that implements the PersistentCookieStore
@@ -95,7 +97,6 @@ class CookieMonster : public CookieStore {
// subtantially more entries in the map.
typedef std::multimap<std::string, CanonicalCookie*> CookieMap;
typedef std::pair<CookieMap::iterator, CookieMap::iterator> CookieMapItPair;
- typedef std::vector<CanonicalCookie> CookieList;
// The key and expiry scheme to be used by the monster.
// EKS_KEEP_RECENT_AND_PURGE_ETLDP1 means to use
@@ -146,7 +147,7 @@ class CookieMonster : public CookieStore {
// Deletes all cookies with that might apply to |url| that has |cookie_name|.
virtual void DeleteCookie(const GURL& url, const std::string& cookie_name);
- virtual CookieMonster* GetCookieMonster() { return this; }
+ virtual CookieMonster* GetCookieMonster();
// Sets a cookie given explicit user-provided cookie attributes. The cookie
// name, value, domain, etc. are each provided as separate strings. This
@@ -169,10 +170,15 @@ class CookieMonster : public CookieStore {
CookieList GetAllCookies();
// Returns all the cookies, for use in management UI, etc. Filters results
- // using given url scheme, host / domain and path. This does not mark the
- // cookies as having been accessed.
+ // using given url scheme, host / domain and path and options. This does not
+ // mark the cookies as having been accessed.
// The returned cookies are ordered by longest path, then earliest
// creation date.
+ CookieList GetAllCookiesForURLWithOptions(const GURL& url,
+ const CookieOptions& options);
+
+ // Invokes GetAllCookiesForURLWithOptions with options set to include HTTP
+ // only cookies.
CookieList GetAllCookiesForURL(const GURL& url);
// Deletes all of the cookies.
@@ -207,6 +213,10 @@ class CookieMonster : public CookieStore {
// function must be called before initialization.
void SetExpiryAndKeyScheme(ExpiryAndKeyScheme key_scheme);
+ // Delegates the call to set the |clear_local_store_on_exit_| flag of the
+ // PersistentStore if it exists.
+ void SetClearPersistentStoreOnExit(bool clear_local_store);
+
// There are some unknowns about how to correctly handle file:// cookies,
// and our implementation for this is not robust enough. This allows you
// to enable support, but it should only be used for testing. Bug 1157243.
@@ -214,14 +224,20 @@ class CookieMonster : public CookieStore {
static void EnableFileScheme();
static bool enable_file_scheme_;
+<<<<<<< HEAD
#if defined(ANDROID)
+=======
+>>>>>>> chromium.org at r10.0.621.0
// Flush the backing store (if any) to disk and post the given task when done.
// WARNING: THE CALLBACK WILL RUN ON A RANDOM THREAD. IT MUST BE THREAD SAFE.
// It may be posted to the current thread, or it may run on the thread that
// actually does the flushing. Your Task should generally post a notification
// to the thread you actually want to be notified on.
void FlushStore(Task* completion_task);
+<<<<<<< HEAD
#endif
+=======
+>>>>>>> chromium.org at r10.0.621.0
private:
~CookieMonster();
@@ -692,15 +708,22 @@ typedef base::RefCountedThreadSafe<CookieMonster::PersistentCookieStore>
class CookieMonster::PersistentCookieStore
: public RefcountedPersistentCookieStore {
public:
- virtual ~PersistentCookieStore() { }
+ virtual ~PersistentCookieStore() {}
// Initializes the store and retrieves the existing cookies. This will be
// called only once at startup.
- virtual bool Load(std::vector<CookieMonster::CanonicalCookie*>*) = 0;
+ virtual bool Load(std::vector<CookieMonster::CanonicalCookie*>* cookies) = 0;
+
+ virtual void AddCookie(const CanonicalCookie& cc) = 0;
+ virtual void UpdateCookieAccessTime(const CanonicalCookie& cc) = 0;
+ virtual void DeleteCookie(const CanonicalCookie& cc) = 0;
- virtual void AddCookie(const CanonicalCookie&) = 0;
- virtual void UpdateCookieAccessTime(const CanonicalCookie&) = 0;
- virtual void DeleteCookie(const CanonicalCookie&) = 0;
+ // Sets the value of the user preference whether the persistent storage
+ // must be deleted upon destruction.
+ virtual void SetClearLocalStateOnExit(bool clear_local_state) = 0;
+
+ // Flush the store and post the given Task when complete.
+ virtual void Flush(Task* completion_task) = 0;
#if defined(ANDROID)
// Flush the store and post the given Task when complete.
@@ -708,12 +731,15 @@ class CookieMonster::PersistentCookieStore
#endif
protected:
- PersistentCookieStore() { }
+ PersistentCookieStore() {}
private:
DISALLOW_COPY_AND_ASSIGN(PersistentCookieStore);
};
+class CookieList : public std::vector<CookieMonster::CanonicalCookie> {
+};
+
} // namespace net
#endif // NET_BASE_COOKIE_MONSTER_H_
diff --git a/net/base/cookie_monster_store_test.h b/net/base/cookie_monster_store_test.h
index 8a21930..84ead74 100644
--- a/net/base/cookie_monster_store_test.h
+++ b/net/base/cookie_monster_store_test.h
@@ -7,6 +7,7 @@
// that need to test out CookieMonster interactions with the backing store.
// It should only be included by test code.
+#include "base/message_loop.h"
#include "base/time.h"
#include "net/base/cookie_monster.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -66,6 +67,14 @@ class MockPersistentCookieStore
CookieStoreCommand(CookieStoreCommand::REMOVE, cookie));
}
+ virtual void Flush(Task* completion_task) {
+ if (completion_task)
+ MessageLoop::current()->PostTask(FROM_HERE, completion_task);
+ }
+
+ // No files are created so nothing to clear either
+ virtual void SetClearLocalStateOnExit(bool clear_local_state) {}
+
void SetLoadExpectation(
bool return_value,
const std::vector<net::CookieMonster::CanonicalCookie*>& result) {
@@ -185,6 +194,13 @@ class MockSimplePersistentCookieStore
cookies_.erase(it);
}
+ virtual void Flush(Task* completion_task) {
+ if (completion_task)
+ MessageLoop::current()->PostTask(FROM_HERE, completion_task);
+ }
+
+ virtual void SetClearLocalStateOnExit(bool clear_local_state) {}
+
private:
CanonicalCookieMap cookies_;
};
diff --git a/net/base/cookie_monster_unittest.cc b/net/base/cookie_monster_unittest.cc
index 6fce2a0..a0c16ea 100644
--- a/net/base/cookie_monster_unittest.cc
+++ b/net/base/cookie_monster_unittest.cc
@@ -1003,7 +1003,7 @@ TEST(CookieMonsterTest, TestSecure) {
}
static Time GetFirstCookieAccessDate(net::CookieMonster* cm) {
- const net::CookieMonster::CookieList all_cookies(cm->GetAllCookies());
+ const net::CookieList all_cookies(cm->GetAllCookies());
return all_cookies.front().LastAccessDate();
}
@@ -1138,8 +1138,8 @@ TEST(CookieMonsterTest, NetUtilCookieTest) {
static bool FindAndDeleteCookie(net::CookieMonster* cm,
const std::string& domain,
const std::string& name) {
- net::CookieMonster::CookieList cookies = cm->GetAllCookies();
- for (net::CookieMonster::CookieList::iterator it = cookies.begin();
+ net::CookieList cookies = cm->GetAllCookies();
+ for (net::CookieList::iterator it = cookies.begin();
it != cookies.end(); ++it)
if (it->Domain() == domain && it->Name() == name)
return cm->DeleteCanonicalCookie(*it);
@@ -1204,9 +1204,8 @@ TEST(CookieMonsterTest, GetAllCookiesForURL) {
PlatformThread::Sleep(kLastAccessThresholdMilliseconds + 20);
// Check cookies for url.
- net::CookieMonster::CookieList cookies =
- cm->GetAllCookiesForURL(url_google);
- net::CookieMonster::CookieList::iterator it = cookies.begin();
+ net::CookieList cookies = cm->GetAllCookiesForURL(url_google);
+ net::CookieList::iterator it = cookies.begin();
ASSERT_TRUE(it != cookies.end());
EXPECT_EQ("www.google.izzle", it->Domain());
@@ -1218,6 +1217,17 @@ TEST(CookieMonsterTest, GetAllCookiesForURL) {
ASSERT_TRUE(++it == cookies.end());
+ // Check cookies for url excluding http-only cookies.
+ cookies =
+ cm->GetAllCookiesForURLWithOptions(url_google, net::CookieOptions());
+ it = cookies.begin();
+
+ ASSERT_TRUE(it != cookies.end());
+ EXPECT_EQ(".google.izzle", it->Domain());
+ EXPECT_EQ("C", it->Name());
+
+ ASSERT_TRUE(++it == cookies.end());
+
// Test secure cookies.
cookies = cm->GetAllCookiesForURL(url_google_secure);
it = cookies.begin();
@@ -1258,9 +1268,8 @@ TEST(CookieMonsterTest, GetAllCookiesForURLPathMatching) {
"E=F;",
options));
- net::CookieMonster::CookieList cookies =
- cm->GetAllCookiesForURL(url_google_foo);
- net::CookieMonster::CookieList::iterator it = cookies.begin();
+ net::CookieList cookies = cm->GetAllCookiesForURL(url_google_foo);
+ net::CookieList::iterator it = cookies.begin();
ASSERT_TRUE(it != cookies.end());
EXPECT_EQ("A", it->Name());
@@ -1299,10 +1308,10 @@ TEST(CookieMonsterTest, DeleteCookieByName) {
cm->DeleteCookie(GURL(std::string(kUrlGoogle) + "/foo/bar"), "A");
- net::CookieMonster::CookieList cookies = cm->GetAllCookies();
+ net::CookieList cookies = cm->GetAllCookies();
size_t expected_size = 4;
EXPECT_EQ(expected_size, cookies.size());
- for (net::CookieMonster::CookieList::iterator it = cookies.begin();
+ for (net::CookieList::iterator it = cookies.begin();
it != cookies.end(); ++it) {
EXPECT_NE("A1", it->Value());
EXPECT_NE("A2", it->Value());
@@ -1494,7 +1503,7 @@ TEST(CookieMonsterTest, DontImportDuplicateCreationTimes) {
scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(store, NULL));
- net::CookieMonster::CookieList list(cm->GetAllCookies());
+ net::CookieList list(cm->GetAllCookies());
EXPECT_EQ(2U, list.size());
// Confirm that we have one of each.
std::string name1(list[0].Name());
@@ -1617,9 +1626,8 @@ TEST(CookieMonsterTest, SetCookieWithDetails) {
url_google_foo, "A=", "B", std::string(), "foo", base::Time(),
false, false));
- net::CookieMonster::CookieList cookies =
- cm->GetAllCookiesForURL(url_google_foo);
- net::CookieMonster::CookieList::iterator it = cookies.begin();
+ net::CookieList cookies = cm->GetAllCookiesForURL(url_google_foo);
+ net::CookieList::iterator it = cookies.begin();
ASSERT_TRUE(it != cookies.end());
EXPECT_EQ("A", it->Name());
@@ -1771,10 +1779,10 @@ TEST(CookieMonsterTest, UniqueCreationTime) {
".google.com", "/", Time(), false, false);
// Now we check
- net::CookieMonster::CookieList cookie_list(cm->GetAllCookies());
+ net::CookieList cookie_list(cm->GetAllCookies());
typedef std::map<int64, net::CookieMonster::CanonicalCookie> TimeCookieMap;
TimeCookieMap check_map;
- for (net::CookieMonster::CookieList::const_iterator it = cookie_list.begin();
+ for (net::CookieList::const_iterator it = cookie_list.begin();
it != cookie_list.end(); it++) {
const int64 creation_date = it->CreationDate().ToInternalValue();
TimeCookieMap::const_iterator
@@ -1867,7 +1875,7 @@ TEST(CookieMonsterTest, BackingStoreCommunication) {
// Create a new cookie monster and make sure that everything is correct
{
scoped_refptr<net::CookieMonster> cmin(new CookieMonster(store, NULL));
- CookieMonster::CookieList cookies(cmin->GetAllCookies());
+ CookieList cookies(cmin->GetAllCookies());
ASSERT_EQ(2u, cookies.size());
// Ordering is path length, then creation time. So second cookie
// will come first, and we need to swap them.
@@ -1914,7 +1922,7 @@ TEST(CookieMonsterTest, CookieOrdering) {
CookieOptions()));
{
unsigned int i = 0;
- CookieMonster::CookieList cookies(cm->GetAllCookiesForURL(
+ CookieList cookies(cm->GetAllCookiesForURL(
GURL("http://d.c.b.a.google.com/aa/bb/cc/dd")));
ASSERT_EQ(5u, cookies.size());
EXPECT_EQ("d", cookies[i++].Name());
@@ -1926,7 +1934,7 @@ TEST(CookieMonsterTest, CookieOrdering) {
{
unsigned int i = 0;
- CookieMonster::CookieList cookies(cm->GetAllCookies());
+ CookieList cookies(cm->GetAllCookies());
ASSERT_EQ(6u, cookies.size());
EXPECT_EQ("d", cookies[i++].Name());
EXPECT_EQ("a", cookies[i++].Name());
@@ -2047,7 +2055,7 @@ TEST(CookieMonsterTest, ForceSessionOnly) {
options));
// Get the canonical cookie.
- CookieMonster::CookieList cookie_list = cm->GetAllCookies();
+ CookieList cookie_list = cm->GetAllCookies();
ASSERT_EQ(1U, cookie_list.size());
ASSERT_FALSE(cookie_list[0].IsPersistent());
@@ -2061,4 +2069,108 @@ TEST(CookieMonsterTest, ForceSessionOnly) {
ASSERT_EQ(0U, cookie_list.size());
}
+namespace {
+
+// Mock PersistentCookieStore that keeps track of the number of Flush() calls.
+class FlushablePersistentStore : public CookieMonster::PersistentCookieStore {
+ public:
+ FlushablePersistentStore() : flush_count_(0) {}
+
+ bool Load(std::vector<CookieMonster::CanonicalCookie*>*) {
+ return false;
+ }
+
+ void AddCookie(const CookieMonster::CanonicalCookie&) {}
+ void UpdateCookieAccessTime(const CookieMonster::CanonicalCookie&) {}
+ void DeleteCookie(const CookieMonster::CanonicalCookie&) {}
+ void SetClearLocalStateOnExit(bool clear_local_state) {}
+
+ void Flush(Task* completion_callback) {
+ ++flush_count_;
+ if (completion_callback) {
+ completion_callback->Run();
+ delete completion_callback;
+ }
+ }
+
+ int flush_count() {
+ return flush_count_;
+ }
+
+ private:
+ volatile int flush_count_;
+};
+
+// Counts the number of times Callback() has been run.
+class CallbackCounter : public base::RefCountedThreadSafe<CallbackCounter> {
+ public:
+ CallbackCounter() : callback_count_(0) {}
+
+ void Callback() {
+ ++callback_count_;
+ }
+
+ int callback_count() {
+ return callback_count_;
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<CallbackCounter>;
+ volatile int callback_count_;
+};
+
+} // namespace
+
+// Test that FlushStore() is forwarded to the store and callbacks are posted.
+TEST(CookieMonsterTest, FlushStore) {
+ scoped_refptr<CallbackCounter> counter(new CallbackCounter());
+ scoped_refptr<FlushablePersistentStore> store(new FlushablePersistentStore());
+ scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(store, NULL));
+
+ ASSERT_EQ(0, store->flush_count());
+ ASSERT_EQ(0, counter->callback_count());
+
+ // Before initialization, FlushStore() should just run the callback.
+ cm->FlushStore(NewRunnableMethod(counter.get(), &CallbackCounter::Callback));
+ MessageLoop::current()->RunAllPending();
+
+ ASSERT_EQ(0, store->flush_count());
+ ASSERT_EQ(1, counter->callback_count());
+
+ // NULL callback is safe.
+ cm->FlushStore(NULL);
+ MessageLoop::current()->RunAllPending();
+
+ ASSERT_EQ(0, store->flush_count());
+ ASSERT_EQ(1, counter->callback_count());
+
+ // After initialization, FlushStore() should delegate to the store.
+ cm->GetAllCookies(); // Force init.
+ cm->FlushStore(NewRunnableMethod(counter.get(), &CallbackCounter::Callback));
+ MessageLoop::current()->RunAllPending();
+
+ ASSERT_EQ(1, store->flush_count());
+ ASSERT_EQ(2, counter->callback_count());
+
+ // NULL callback is still safe.
+ cm->FlushStore(NULL);
+ MessageLoop::current()->RunAllPending();
+
+ ASSERT_EQ(2, store->flush_count());
+ ASSERT_EQ(2, counter->callback_count());
+
+ // If there's no backing store, FlushStore() is always a safe no-op.
+ cm = new net::CookieMonster(NULL, NULL);
+ cm->GetAllCookies(); // Force init.
+ cm->FlushStore(NULL);
+ MessageLoop::current()->RunAllPending();
+
+ ASSERT_EQ(2, counter->callback_count());
+
+ cm->FlushStore(NewRunnableMethod(counter.get(), &CallbackCounter::Callback));
+ MessageLoop::current()->RunAllPending();
+
+ ASSERT_EQ(3, counter->callback_count());
+}
+
} // namespace
diff --git a/net/base/data_url.cc b/net/base/data_url.cc
index e30f7da..e387cd1 100644
--- a/net/base/data_url.cc
+++ b/net/base/data_url.cc
@@ -60,6 +60,10 @@ bool DataURL::Parse(const GURL& url, std::string* mime_type,
if (charset->empty())
charset->assign("US-ASCII");
+ // The caller may not be interested in receiving the data.
+ if (!data)
+ return true;
+
// Preserve spaces if dealing with text or xml input, same as mozilla:
// https://bugzilla.mozilla.org/show_bug.cgi?id=138052
// but strip them otherwise:
diff --git a/net/base/data_url.h b/net/base/data_url.h
index b40878a..65a211a 100644
--- a/net/base/data_url.h
+++ b/net/base/data_url.h
@@ -37,6 +37,9 @@ class DataURL {
// If the URL is malformed, then this method will return false, and its
// output variables will remain unchanged. On success, true is returned.
//
+ // OPTIONAL: If |data| is NULL, then the <data> section will not be parsed
+ // or validated.
+ //
static bool Parse(const GURL& url,
std::string* mime_type,
std::string* charset,
diff --git a/net/base/data_url_unittest.cc b/net/base/data_url_unittest.cc
index b7c2dc0..c90fb8b 100644
--- a/net/base/data_url_unittest.cc
+++ b/net/base/data_url_unittest.cc
@@ -9,13 +9,13 @@
namespace {
- struct ParseTestData {
- const char* url;
- bool is_valid;
- const char* mime_type;
- const char* charset;
- const char* data;
- };
+struct ParseTestData {
+ const char* url;
+ bool is_valid;
+ const char* mime_type;
+ const char* charset;
+ const char* data;
+};
class DataURLTest : public testing::Test {
};
diff --git a/net/base/directory_lister.cc b/net/base/directory_lister.cc
index 0a22d2b..61a2d65 100644
--- a/net/base/directory_lister.cc
+++ b/net/base/directory_lister.cc
@@ -11,6 +11,7 @@
#include "base/i18n/file_util_icu.h"
#include "base/message_loop.h"
#include "base/platform_thread.h"
+#include "base/thread_restrictions.h"
#include "net/base/net_errors.h"
namespace net {
@@ -122,6 +123,9 @@ DirectoryLister::DirectoryLister(const FilePath& dir,
DirectoryLister::~DirectoryLister() {
if (thread_) {
+ // This is a bug and we should stop joining this thread.
+ // http://crbug.com/65331
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
PlatformThread::Join(thread_);
}
}
@@ -147,6 +151,9 @@ void DirectoryLister::Cancel() {
canceled_.Set();
if (thread_) {
+ // This is a bug and we should stop joining this thread.
+ // http://crbug.com/65331
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
PlatformThread::Join(thread_);
thread_ = kNullThreadHandle;
}
diff --git a/net/base/directory_lister.h b/net/base/directory_lister.h
index 8623088..b531880 100644
--- a/net/base/directory_lister.h
+++ b/net/base/directory_lister.h
@@ -82,7 +82,7 @@ class DirectoryLister : public base::RefCountedThreadSafe<DirectoryLister>,
void set_delegate(DirectoryListerDelegate* d) { delegate_ = d; }
// PlatformThread::Delegate implementation
- void ThreadMain();
+ virtual void ThreadMain();
private:
friend class base::RefCountedThreadSafe<DirectoryLister>;
diff --git a/net/base/dnsrr_resolver.cc b/net/base/dnsrr_resolver.cc
index 0c21857..ba9b42b 100644
--- a/net/base/dnsrr_resolver.cc
+++ b/net/base/dnsrr_resolver.cc
@@ -20,9 +20,6 @@
#include "net/base/dns_util.h"
#include "net/base/net_errors.h"
-DISABLE_RUNNABLE_METHOD_REFCOUNT(net::RRResolverWorker);
-DISABLE_RUNNABLE_METHOD_REFCOUNT(net::RRResolverHandle);
-
// Life of a query:
//
// DnsRRResolver RRResolverJob RRResolverWorker ... Handle
@@ -82,7 +79,7 @@ DISABLE_RUNNABLE_METHOD_REFCOUNT(net::RRResolverHandle);
namespace net {
static const uint16 kClassIN = 1;
-// kMaxCacheEntries is the number of RRResponse object that we'll cache.
+// kMaxCacheEntries is the number of RRResponse objects that we'll cache.
static const unsigned kMaxCacheEntries = 32;
// kNegativeTTLSecs is the number of seconds for which we'll cache a negative
// cache entry.
@@ -104,6 +101,7 @@ class RRResolverHandle {
// Cancel ensures that the result callback will never be made.
void Cancel() {
callback_ = NULL;
+ response_ = NULL;
}
// Post copies the contents of |response| to the caller's RRResponse and
@@ -118,11 +116,8 @@ class RRResolverHandle {
}
private:
- friend class RRResolverWorker;
- friend class DnsRRResolver;
-
CompletionCallback* callback_;
- RRResponse* const response_;
+ RRResponse* response_;
};
@@ -248,7 +243,7 @@ class RRResolverWorker {
Finish();
}
-#endif // OS_WIN
+#endif // OS_WIN
// HandleTestCases stuffs in magic test values in the event that the query is
// from a unittest.
@@ -277,8 +272,9 @@ class RRResolverWorker {
DCHECK_EQ(MessageLoop::current(), origin_loop_);
{
// We lock here because the worker thread could still be in Finished,
- // after the PostTask, but before unlocking |lock_|. In this case, we end
- // up deleting a locked Lock, which can lead to memory leaks.
+ // after the PostTask, but before unlocking |lock_|. If we do not lock in
+ // this case, we will end up deleting a locked Lock, which can lead to
+ // memory leaks or worse errors.
AutoLock locked(lock_);
if (!canceled_)
dnsrr_resolver_->HandleResult(name_, rrtype_, result_, response_);
@@ -453,12 +449,12 @@ class Buffer {
}
private:
- DISALLOW_COPY_AND_ASSIGN(Buffer);
-
const uint8* p_;
const uint8* const packet_;
unsigned len_;
const unsigned packet_len_;
+
+ DISALLOW_COPY_AND_ASSIGN(Buffer);
};
bool RRResponse::HasExpired(const base::Time current_time) const {
@@ -558,12 +554,12 @@ bool RRResponse::ParseFromResponse(const uint8* p, unsigned len,
// lives only on the DnsRRResolver's origin message loop.
class RRResolverJob {
public:
- RRResolverJob(RRResolverWorker* worker)
+ explicit RRResolverJob(RRResolverWorker* worker)
: worker_(worker) {
}
~RRResolverJob() {
- Cancel(ERR_NAME_NOT_RESOLVED);
+ Cancel(ERR_ABORTED);
}
void AddHandle(RRResolverHandle* handle) {
@@ -579,9 +575,8 @@ class RRResolverJob {
if (worker_) {
worker_->Cancel();
worker_ = NULL;
+ PostAll(error, NULL);
}
-
- PostAll(error, NULL);
}
private:
@@ -699,11 +694,7 @@ void DnsRRResolver::OnIPAddressChanged() {
inflight.swap(inflight_);
cache_.clear();
- for (std::map<std::pair<std::string, uint16>, RRResolverJob*>::iterator
- i = inflight.begin(); i != inflight.end(); i++) {
- i->second->Cancel(ERR_ABORTED);
- delete i->second;
- }
+ STLDeleteValues(&inflight);
}
// HandleResult is called on the origin message loop.
@@ -718,12 +709,11 @@ void DnsRRResolver::HandleResult(const std::string& name, uint16 rrtype,
if (cache_.size() == kMaxCacheEntries) {
// need to remove an element of the cache.
const base::Time current_time(base::Time::Now());
- for (std::map<std::pair<std::string, uint16>, RRResponse>::iterator
- i = cache_.begin(); i != cache_.end(); ++i) {
- if (i->second.HasExpired(current_time)) {
- cache_.erase(i);
- break;
- }
+ std::map<std::pair<std::string, uint16>, RRResponse>::iterator i, cur;
+ for (i = cache_.begin(); i != cache_.end(); ) {
+ cur = i++;
+ if (cur->second.HasExpired(current_time))
+ cache_.erase(cur);
}
}
if (cache_.size() == kMaxCacheEntries) {
@@ -748,3 +738,6 @@ void DnsRRResolver::HandleResult(const std::string& name, uint16 rrtype,
}
} // namespace net
+
+DISABLE_RUNNABLE_METHOD_REFCOUNT(net::RRResolverHandle);
+DISABLE_RUNNABLE_METHOD_REFCOUNT(net::RRResolverWorker);
diff --git a/net/base/dnsrr_resolver.h b/net/base/dnsrr_resolver.h
index 64a1be5..30de5fe 100644
--- a/net/base/dnsrr_resolver.h
+++ b/net/base/dnsrr_resolver.h
@@ -19,8 +19,6 @@
#include "net/base/completion_callback.h"
#include "net/base/network_change_notifier.h"
-class MessageLoop;
-
namespace net {
// RRResponse contains the result of a successful request for a resource record.
@@ -57,7 +55,6 @@ struct RRResponse {
class BoundNetLog;
class RRResolverWorker;
class RRResolverJob;
-class RRResolverHandle;
// DnsRRResolver resolves arbitary DNS resource record types. It should not be
// confused with HostResolver and should not be used to resolve A/AAAA records.
@@ -117,11 +114,11 @@ class DnsRRResolver : public NonThreadSafe,
void HandleResult(const std::string& name, uint16 rrtype, int result,
const RRResponse& response);
- // cache maps from a request to a cached response. The cached answer may have
- // expired and the size of |cache| must be <= kMaxCacheEntries.
+ // cache_ maps from a request to a cached response. The cached answer may
+ // have expired and the size of |cache_| must be <= kMaxCacheEntries.
// < name , rrtype>
std::map<std::pair<std::string, uint16>, RRResponse> cache_;
- // inflight maps from a request to an active resolution which is taking
+ // inflight_ maps from a request to an active resolution which is taking
// place.
std::map<std::pair<std::string, uint16>, RRResolverJob*> inflight_;
@@ -136,4 +133,4 @@ class DnsRRResolver : public NonThreadSafe,
} // namespace net
-#endif // NET_BASE_DNSRR_RESOLVER_H_
+#endif // NET_BASE_DNSRR_RESOLVER_H_
diff --git a/net/base/escape.cc b/net/base/escape.cc
index 3c39f95..5479b82 100644
--- a/net/base/escape.cc
+++ b/net/base/escape.cc
@@ -71,19 +71,27 @@ const std::string Escape(const std::string& text, const Charmap& charmap,
//
// The basic rule is that we can't unescape anything that would changing parsing
// like # or ?. We also can't unescape &, =, or + since that could be part of a
-// query and that could change the server's parsing of the query.
+// query and that could change the server's parsing of the query. Nor can we
+// unescape \ since googleurl will convert it to a /.
+//
+// Lastly, we can't unescape anything that doesn't have a canonical
+// representation in a URL. This means that unescaping will change the URL, and
+// you could get different behavior if you copy and paste the URL, or press
+// enter in the URL bar. The list of characters that fall into this category
+// are the ones labeled PASS (allow either escaped or unescaped) in the big
+// lookup table at the top of googleurl/src/url_canon_path.cc
const char kUrlUnescape[128] = {
// NULL, control chars...
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// ' ' ! " # $ % & ' ( ) * + , - . /
- 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1,
+ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
// 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0,
// @ A B C D E F G H I J K L M N O
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
// P Q R S T U V W X Y Z [ \ ] ^ _
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
// ` a b c d e f g h i j k l m n o
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
// p q r s t u v w x y z { | } ~ <NBSP>
diff --git a/net/base/escape_unittest.cc b/net/base/escape_unittest.cc
index 01cd9e1..04a040e 100644
--- a/net/base/escape_unittest.cc
+++ b/net/base/escape_unittest.cc
@@ -159,17 +159,17 @@ TEST(EscapeTest, UnescapeURLComponentASCII) {
{"%%%%%%", UnescapeRule::NORMAL, "%%%%%%"},
{"Don't escape anything", UnescapeRule::NORMAL, "Don't escape anything"},
{"Invalid %escape %2", UnescapeRule::NORMAL, "Invalid %escape %2"},
- {"Some%20random text %25%3bOK", UnescapeRule::NONE,
- "Some%20random text %25%3bOK"},
- {"Some%20random text %25%3bOK", UnescapeRule::NORMAL,
- "Some%20random text %25;OK"},
- {"Some%20random text %25%3bOK", UnescapeRule::SPACES,
- "Some random text %25;OK"},
- {"Some%20random text %25%3bOK", UnescapeRule::URL_SPECIAL_CHARS,
- "Some%20random text %;OK"},
- {"Some%20random text %25%3bOK",
+ {"Some%20random text %25%2dOK", UnescapeRule::NONE,
+ "Some%20random text %25%2dOK"},
+ {"Some%20random text %25%2dOK", UnescapeRule::NORMAL,
+ "Some%20random text %25-OK"},
+ {"Some%20random text %25%2dOK", UnescapeRule::SPACES,
+ "Some random text %25-OK"},
+ {"Some%20random text %25%2dOK", UnescapeRule::URL_SPECIAL_CHARS,
+ "Some%20random text %-OK"},
+ {"Some%20random text %25%2dOK",
UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS,
- "Some random text %;OK"},
+ "Some random text %-OK"},
{"%A0%B1%C2%D3%E4%F5", UnescapeRule::NORMAL, "\xA0\xB1\xC2\xD3\xE4\xF5"},
{"%Aa%Bb%Cc%Dd%Ee%Ff", UnescapeRule::NORMAL, "\xAa\xBb\xCc\xDd\xEe\xFf"},
// Certain URL-sensitive characters should not be unescaped unless asked.
@@ -220,17 +220,17 @@ TEST(EscapeTest, UnescapeURLComponent) {
{L"%%%%%%", UnescapeRule::NORMAL, L"%%%%%%"},
{L"Don't escape anything", UnescapeRule::NORMAL, L"Don't escape anything"},
{L"Invalid %escape %2", UnescapeRule::NORMAL, L"Invalid %escape %2"},
- {L"Some%20random text %25%3bOK", UnescapeRule::NONE,
- L"Some%20random text %25%3bOK"},
- {L"Some%20random text %25%3bOK", UnescapeRule::NORMAL,
- L"Some%20random text %25;OK"},
- {L"Some%20random text %25%3bOK", UnescapeRule::SPACES,
- L"Some random text %25;OK"},
- {L"Some%20random text %25%3bOK", UnescapeRule::URL_SPECIAL_CHARS,
- L"Some%20random text %;OK"},
- {L"Some%20random text %25%3bOK",
+ {L"Some%20random text %25%2dOK", UnescapeRule::NONE,
+ L"Some%20random text %25%2dOK"},
+ {L"Some%20random text %25%2dOK", UnescapeRule::NORMAL,
+ L"Some%20random text %25-OK"},
+ {L"Some%20random text %25%2dOK", UnescapeRule::SPACES,
+ L"Some random text %25-OK"},
+ {L"Some%20random text %25%2dOK", UnescapeRule::URL_SPECIAL_CHARS,
+ L"Some%20random text %-OK"},
+ {L"Some%20random text %25%2dOK",
UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS,
- L"Some random text %;OK"},
+ L"Some random text %-OK"},
{L"%A0%B1%C2%D3%E4%F5", UnescapeRule::NORMAL, L"\xA0\xB1\xC2\xD3\xE4\xF5"},
{L"%Aa%Bb%Cc%Dd%Ee%Ff", UnescapeRule::NORMAL, L"\xAa\xBb\xCc\xDd\xEe\xFf"},
// Certain URL-sensitive characters should not be unescaped unless asked.
@@ -307,10 +307,10 @@ TEST(EscapeTest, UnescapeAndDecodeUTF8URLComponent) {
"+Invalid %escape %2+",
" Invalid %escape %2 ",
L"+Invalid %escape %2+"},
- { "Some random text %25%3BOK",
- "Some random text %25;OK",
- "Some random text %25;OK",
- L"Some random text %25;OK"},
+ { "Some random text %25%2dOK",
+ "Some random text %25-OK",
+ "Some random text %25-OK",
+ L"Some random text %25-OK"},
{ "%01%02%03%04%05%06%07%08%09",
"%01%02%03%04%05%06%07%08%09",
"%01%02%03%04%05%06%07%08%09",
@@ -349,9 +349,9 @@ TEST(EscapeTest, AdjustOffset) {
{"test", 2, 2},
{"test", 4, std::wstring::npos},
{"test", std::wstring::npos, std::wstring::npos},
- {"%3Btest", 6, 4},
- {"%3Btest", 2, std::wstring::npos},
- {"test%3B", 2, 2},
+ {"%2dtest", 6, 4},
+ {"%2dtest", 2, std::wstring::npos},
+ {"test%2d", 2, 2},
{"%E4%BD%A0+%E5%A5%BD", 9, 1},
{"%E4%BD%A0+%E5%A5%BD", 6, std::wstring::npos},
{"%ED%B0%80+%E5%A5%BD", 6, 6},
diff --git a/net/base/forwarding_net_log.cc b/net/base/forwarding_net_log.cc
deleted file mode 100644
index 7cfd6a9..0000000
--- a/net/base/forwarding_net_log.cc
+++ /dev/null
@@ -1,96 +0,0 @@
-// 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.
-
-#include "net/base/forwarding_net_log.h"
-
-#include "base/lock.h"
-#include "base/logging.h"
-#include "base/message_loop.h"
-
-namespace net {
-
-// Reference-counted wrapper, so we can use PostThread and it can safely
-// outlive the parent ForwardingNetLog.
-class ForwardingNetLog::Core
- : public base::RefCountedThreadSafe<ForwardingNetLog::Core> {
- public:
- Core(NetLog* impl, MessageLoop* loop) : impl_(impl), loop_(loop) {
- DCHECK(impl);
- DCHECK(loop);
- }
-
- // Called once the parent ForwardingNetLog is being destroyed. It
- // is invalid to access |loop_| and |impl_| afterwards.
- void Orphan() {
- AutoLock l(lock_);
- loop_ = NULL;
- impl_ = NULL;
- }
-
- void AddEntry(EventType type,
- const base::TimeTicks& time,
- const Source& source,
- EventPhase phase,
- EventParameters* params) {
- AutoLock l(lock_);
- if (!loop_)
- return; // Was orphaned.
-
- loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(
- this, &Core::AddEntryOnLoop, type, time, source, phase,
- scoped_refptr<EventParameters>(params)));
- }
-
- private:
- void AddEntryOnLoop(EventType type,
- const base::TimeTicks& time,
- const Source& source,
- EventPhase phase,
- scoped_refptr<EventParameters> params) {
- AutoLock l(lock_);
- if (!loop_)
- return; // Was orphaned.
-
- DCHECK_EQ(MessageLoop::current(), loop_);
-
- impl_->AddEntry(type, time, source, phase, params);
- }
-
- Lock lock_;
- NetLog* impl_;
- MessageLoop* loop_;
-};
-
-ForwardingNetLog::ForwardingNetLog(NetLog* impl, MessageLoop* loop)
- : core_(new Core(impl, loop)) {
-}
-
-ForwardingNetLog::~ForwardingNetLog() {
- core_->Orphan();
-}
-
-void ForwardingNetLog::AddEntry(EventType type,
- const base::TimeTicks& time,
- const Source& source,
- EventPhase phase,
- EventParameters* params) {
- core_->AddEntry(type, time, source, phase, params);
-}
-
-uint32 ForwardingNetLog::NextID() {
- // Can't forward a synchronous API.
- CHECK(false) << "Not supported";
- return 0;
-}
-
-NetLog::LogLevel ForwardingNetLog::GetLogLevel() const {
- // Can't forward a synchronous API.
- CHECK(false) << "Not supported";
- return LOG_ALL_BUT_BYTES;
-}
-
-} // namespace net
-
diff --git a/net/base/forwarding_net_log.h b/net/base/forwarding_net_log.h
deleted file mode 100644
index 257b4c7..0000000
--- a/net/base/forwarding_net_log.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// 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.
-
-#ifndef NET_BASE_FORWARDING_NET_LOG_H_
-#define NET_BASE_FORWARDING_NET_LOG_H_
-#pragma once
-
-#include "base/basictypes.h"
-#include "net/base/net_log.h"
-
-class MessageLoop;
-
-namespace net {
-
-// ForwardingNetLog is a wrapper that can be called on any thread, and will
-// forward any calls to NetLog::AddEntry() over to |impl| on the specified
-// message loop.
-//
-// This allows using a non-threadsafe NetLog implementation from another
-// thread.
-//
-// TODO(eroman): Explore making NetLog threadsafe and obviating the need
-// for this class.
-class ForwardingNetLog : public NetLog {
- public:
- // Both |impl| and |loop| must outlive the lifetime of this instance.
- // |impl| will be operated only from |loop|.
- ForwardingNetLog(NetLog* impl, MessageLoop* loop);
-
- // On destruction any outstanding call to AddEntry() which didn't make
- // it to |loop| yet will be cancelled.
- ~ForwardingNetLog();
-
- // NetLog methods:
- virtual void AddEntry(EventType type,
- const base::TimeTicks& time,
- const Source& source,
- EventPhase phase,
- EventParameters* params);
- virtual uint32 NextID();
- virtual LogLevel GetLogLevel() const;
-
- private:
- class Core;
- scoped_refptr<Core> core_;
-
- DISALLOW_COPY_AND_ASSIGN(ForwardingNetLog);
-};
-
-} // namespace net
-
-#endif // NET_BASE_FORWARDING_NET_LOG_H_
-
diff --git a/net/base/forwarding_net_log_unittest.cc b/net/base/forwarding_net_log_unittest.cc
deleted file mode 100644
index 3f25129..0000000
--- a/net/base/forwarding_net_log_unittest.cc
+++ /dev/null
@@ -1,84 +0,0 @@
-// 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.
-
-#include "net/base/forwarding_net_log.h"
-
-#include "base/message_loop.h"
-#include "net/base/capturing_net_log.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-
-namespace {
-
-// Test forwarding a call to AddEntry() to another implementation, operating
-// on this same message loop.
-TEST(ForwardingNetLogTest, Basic) {
- // Create a forwarding NetLog that sends messages to this same thread.
- CapturingNetLog log(CapturingNetLog::kUnbounded);
- ForwardingNetLog forwarding(&log, MessageLoop::current());
-
- EXPECT_EQ(0u, log.entries().size());
-
- NetLogStringParameter* params = new NetLogStringParameter("xxx", "yyy");
-
- forwarding.AddEntry(
- NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
- base::TimeTicks(),
- NetLog::Source(),
- NetLog::PHASE_NONE,
- params);
-
- // Should still be empty, since we posted an async task.
- EXPECT_EQ(0u, log.entries().size());
-
- MessageLoop::current()->RunAllPending();
-
- // After draining the message loop, we should now have executed the task
- // and hence emitted the log entry.
- ASSERT_EQ(1u, log.entries().size());
-
- // Check that the forwarded call contained received all the right inputs.
- EXPECT_EQ(NetLog::TYPE_PAC_JAVASCRIPT_ALERT, log.entries()[0].type);
- EXPECT_EQ(NetLog::SOURCE_NONE, log.entries()[0].source.type);
- EXPECT_EQ(NetLog::PHASE_NONE, log.entries()[0].phase);
- EXPECT_EQ(params, log.entries()[0].extra_parameters.get());
-
- // Check that the parameters is still referenced. (if the reference was
- // lost then this will be a memory error and probaby crash).
- EXPECT_EQ("yyy", params->value());
-}
-
-// Test forwarding a call to AddEntry() to another implementation that runs
-// on the same message loop. However destroy the forwarder before the posted
-// task has a chance to run.
-TEST(ForwardingNetLogTest, Orphan) {
- // Create a forwarding NetLog that sends messages to this same thread.
- CapturingNetLog log(CapturingNetLog::kUnbounded);
- {
- ForwardingNetLog forwarding(&log, MessageLoop::current());
- EXPECT_EQ(0u, log.entries().size());
-
- forwarding.AddEntry(
- NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
- base::TimeTicks(),
- NetLog::Source(),
- NetLog::PHASE_NONE,
- NULL);
-
- // Should still be empty, since we posted an async task.
- EXPECT_EQ(0u, log.entries().size());
- }
-
- // At this point the ForwardingNetLog is deleted. However it had already
- // posted a task to the message loop. Once we drain the message loop, we
- // verify that the task didn't actually try to emit to the NetLog.
- MessageLoop::current()->RunAllPending();
- EXPECT_EQ(0u, log.entries().size());
-}
-
-} // namespace
-
-} // namespace net
-
diff --git a/net/base/host_resolver.cc b/net/base/host_resolver.cc
index fbd63bd..a8b642a 100644
--- a/net/base/host_resolver.cc
+++ b/net/base/host_resolver.cc
@@ -25,6 +25,14 @@ HostResolver::HostResolver() {
HostResolver::~HostResolver() {
}
+AddressFamily HostResolver::GetDefaultAddressFamily() const {
+ return net::ADDRESS_FAMILY_UNSPECIFIED;
+}
+
+HostResolverImpl* HostResolver::GetAsHostResolverImpl() {
+ return NULL;
+}
+
SingleRequestHostResolver::SingleRequestHostResolver(HostResolver* resolver)
: resolver_(resolver),
cur_request_(NULL),
diff --git a/net/base/host_resolver.h b/net/base/host_resolver.h
index 471ad8a..4fc5c89 100644
--- a/net/base/host_resolver.h
+++ b/net/base/host_resolver.h
@@ -170,14 +170,12 @@ class HostResolver {
// results to AF_INET by passing in ADDRESS_FAMILY_IPV4, or to
// AF_INET6 by passing in ADDRESS_FAMILY_IPV6.
virtual void SetDefaultAddressFamily(AddressFamily address_family) {}
- virtual AddressFamily GetDefaultAddressFamily() const {
- return net::ADDRESS_FAMILY_UNSPECIFIED;
- }
+ virtual AddressFamily GetDefaultAddressFamily() const;
// Returns |this| cast to a HostResolverImpl*, or NULL if the subclass
// is not compatible with HostResolverImpl. Used primarily to expose
// additional functionality on the about:net-internals page.
- virtual HostResolverImpl* GetAsHostResolverImpl() { return NULL; }
+ virtual HostResolverImpl* GetAsHostResolverImpl();
// Does additional cleanup prior to destruction.
virtual void Shutdown() {}
diff --git a/net/base/host_resolver_impl.cc b/net/base/host_resolver_impl.cc
index 3dd99c4..fded5ff 100644
--- a/net/base/host_resolver_impl.cc
+++ b/net/base/host_resolver_impl.cc
@@ -1135,6 +1135,10 @@ void HostResolverImpl::ProbeIPv6Support() {
OnIPAddressChanged(); // Give initial setup call.
}
+HostResolverImpl* HostResolverImpl::GetAsHostResolverImpl() {
+ return this;
+}
+
void HostResolverImpl::Shutdown() {
DCHECK(CalledOnValidThread());
diff --git a/net/base/host_resolver_impl.h b/net/base/host_resolver_impl.h
index 46ce31d..68c8c0b 100644
--- a/net/base/host_resolver_impl.h
+++ b/net/base/host_resolver_impl.h
@@ -105,7 +105,7 @@ class HostResolverImpl : public HostResolver,
// address family to IPv4 iff IPv6 is not supported.
void ProbeIPv6Support();
- virtual HostResolverImpl* GetAsHostResolverImpl() { return this; }
+ virtual HostResolverImpl* GetAsHostResolverImpl();
// TODO(eroman): hack for http://crbug.com/15513
virtual void Shutdown();
diff --git a/net/base/host_resolver_impl_unittest.cc b/net/base/host_resolver_impl_unittest.cc
index f3bdb74..4d26ab9 100644
--- a/net/base/host_resolver_impl_unittest.cc
+++ b/net/base/host_resolver_impl_unittest.cc
@@ -271,11 +271,14 @@ TEST_F(HostResolverImplTest, SynchronousLookup) {
int err = host_resolver->Resolve(info, &addrlist, NULL, NULL, log.bound());
EXPECT_EQ(OK, err);
- EXPECT_EQ(2u, log.entries().size());
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
+
+ EXPECT_EQ(2u, entries.size());
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 0, NetLog::TYPE_HOST_RESOLVER_IMPL));
+ entries, 0, NetLog::TYPE_HOST_RESOLVER_IMPL));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 1, NetLog::TYPE_HOST_RESOLVER_IMPL));
+ entries, 1, NetLog::TYPE_HOST_RESOLVER_IMPL));
const struct addrinfo* ainfo = addrlist.head();
EXPECT_EQ(static_cast<addrinfo*>(NULL), ainfo->ai_next);
@@ -304,18 +307,23 @@ TEST_F(HostResolverImplTest, AsynchronousLookup) {
log.bound());
EXPECT_EQ(ERR_IO_PENDING, err);
- EXPECT_EQ(1u, log.entries().size());
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
+
+ EXPECT_EQ(1u, entries.size());
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 0, NetLog::TYPE_HOST_RESOLVER_IMPL));
+ entries, 0, NetLog::TYPE_HOST_RESOLVER_IMPL));
MessageLoop::current()->Run();
ASSERT_TRUE(callback_called_);
ASSERT_EQ(OK, callback_result_);
- EXPECT_EQ(2u, log.entries().size());
+ log.GetEntries(&entries);
+
+ EXPECT_EQ(2u, entries.size());
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 1, NetLog::TYPE_HOST_RESOLVER_IMPL));
+ entries, 1, NetLog::TYPE_HOST_RESOLVER_IMPL));
const struct addrinfo* ainfo = addrlist.head();
EXPECT_EQ(static_cast<addrinfo*>(NULL), ainfo->ai_next);
@@ -356,31 +364,37 @@ TEST_F(HostResolverImplTest, CanceledAsynchronousLookup) {
resolver_proc->Signal();
- EXPECT_EQ(2u, log.entries().size());
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
+
+ EXPECT_EQ(2u, entries.size());
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 0, NetLog::TYPE_HOST_RESOLVER_IMPL));
+ entries, 0, NetLog::TYPE_HOST_RESOLVER_IMPL));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 1, NetLog::TYPE_HOST_RESOLVER_IMPL));
+ entries, 1, NetLog::TYPE_HOST_RESOLVER_IMPL));
+
+ net::CapturingNetLog::EntryList net_log_entries;
+ net_log.GetEntries(&net_log_entries);
- int pos = net::ExpectLogContainsSomewhereAfter(net_log.entries(), 0,
+ int pos = net::ExpectLogContainsSomewhereAfter(net_log_entries, 0,
net::NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST,
net::NetLog::PHASE_BEGIN);
- pos = net::ExpectLogContainsSomewhereAfter(net_log.entries(), pos + 1,
+ pos = net::ExpectLogContainsSomewhereAfter(net_log_entries, pos + 1,
net::NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
net::NetLog::PHASE_BEGIN);
// Both Job and Request need to be cancelled.
- pos = net::ExpectLogContainsSomewhereAfter(net_log.entries(), pos + 1,
+ pos = net::ExpectLogContainsSomewhereAfter(net_log_entries, pos + 1,
net::NetLog::TYPE_CANCELLED,
net::NetLog::PHASE_NONE);
// Don't care about order in which they end, or when the other one is
// cancelled.
- net::ExpectLogContainsSomewhereAfter(net_log.entries(), pos + 1,
+ net::ExpectLogContainsSomewhereAfter(net_log_entries, pos + 1,
net::NetLog::TYPE_CANCELLED,
net::NetLog::PHASE_NONE);
- net::ExpectLogContainsSomewhereAfter(net_log.entries(), pos + 1,
+ net::ExpectLogContainsSomewhereAfter(net_log_entries, pos + 1,
net::NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST,
net::NetLog::PHASE_END);
- net::ExpectLogContainsSomewhereAfter(net_log.entries(), pos + 1,
+ net::ExpectLogContainsSomewhereAfter(net_log_entries, pos + 1,
net::NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
net::NetLog::PHASE_END);
@@ -943,11 +957,14 @@ TEST_F(HostResolverImplTest, Observers) {
int rv = host_resolver->Resolve(info1, &addrlist, NULL, NULL, log.bound());
EXPECT_EQ(OK, rv);
- EXPECT_EQ(2u, log.entries().size());
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
+
+ EXPECT_EQ(2u, entries.size());
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 0, NetLog::TYPE_HOST_RESOLVER_IMPL));
+ entries, 0, NetLog::TYPE_HOST_RESOLVER_IMPL));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 1, NetLog::TYPE_HOST_RESOLVER_IMPL));
+ entries, 1, NetLog::TYPE_HOST_RESOLVER_IMPL));
EXPECT_EQ(1U, observer.start_log.size());
EXPECT_EQ(1U, observer.finish_log.size());
diff --git a/net/base/keygen_handler_openssl.cc b/net/base/keygen_handler_openssl.cc
index 0f5d874..73aabd7 100644
--- a/net/base/keygen_handler_openssl.cc
+++ b/net/base/keygen_handler_openssl.cc
@@ -4,15 +4,39 @@
#include "net/base/keygen_handler.h"
-#if defined(USE_OPENSSL)
+#include <openssl/ssl.h>
+
+#include "base/crypto/rsa_private_key.h"
+#include "base/logging.h"
+#include "base/openssl_util.h"
+#include "base/scoped_ptr.h"
+#include "net/base/openssl_private_key_store.h"
namespace net {
std::string KeygenHandler::GenKeyAndSignChallenge() {
- // TODO(bulach): implement me.
- return "";
+ scoped_ptr<base::RSAPrivateKey> key(
+ base::RSAPrivateKey::Create(key_size_in_bits_));
+ EVP_PKEY* pkey = key->key();
+
+ if (stores_key_)
+ OpenSSLPrivateKeyStore::GetInstance()->StorePrivateKey(url_, pkey);
+
+ base::ScopedOpenSSL<NETSCAPE_SPKI, NETSCAPE_SPKI_free> spki(
+ NETSCAPE_SPKI_new());
+ ASN1_STRING_set(spki.get()->spkac->challenge,
+ challenge_.data(), challenge_.size());
+ NETSCAPE_SPKI_set_pubkey(spki.get(), pkey);
+ // Using MD5 as this is what is required in HTML5, even though the SPKI
+ // structure does allow the use of a SHA-1 signature.
+ NETSCAPE_SPKI_sign(spki.get(), pkey, EVP_md5());
+ char* spkistr = NETSCAPE_SPKI_b64_encode(spki.get());
+
+ std::string result(spkistr);
+ OPENSSL_free(spkistr);
+
+ return result;
}
} // namespace net
-#endif // USE_OPENSSL
diff --git a/net/base/keygen_handler_unittest.cc b/net/base/keygen_handler_unittest.cc
index d3bf4f5..f4251f2 100644
--- a/net/base/keygen_handler_unittest.cc
+++ b/net/base/keygen_handler_unittest.cc
@@ -4,14 +4,9 @@
#include "net/base/keygen_handler.h"
-#include "build/build_config.h" // Needs to be imported early for USE_NSS
-
-#if defined(USE_NSS)
-#include <private/pprthred.h> // PR_DetachThread
-#endif
-
#include <string>
+#include "build/build_config.h"
#include "base/base64.h"
#include "base/logging.h"
#include "base/nss_util.h"
@@ -21,6 +16,10 @@
#include "base/worker_pool.h"
#include "testing/gtest/include/gtest/gtest.h"
+#if defined(USE_NSS)
+#include <private/pprthred.h> // PR_DetachThread
+#endif
+
namespace net {
namespace {
@@ -96,7 +95,7 @@ class ConcurrencyTestTask : public Task {
base::ThreadRestrictions::ScopedAllowSingleton scoped_allow_singleton;
KeygenHandler handler(768, "some challenge",
GURL("http://www.example.com"));
- handler.set_stores_key(false); // Don't leave the key-pair behind.
+ handler.set_stores_key(false); // Don't leave the key-pair behind.
*result_ = handler.GenKeyAndSignChallenge();
event_->Signal();
#if defined(USE_NSS)
diff --git a/net/base/listen_socket.h b/net/base/listen_socket.h
index 7ce8887..e730b82 100644
--- a/net/base/listen_socket.h
+++ b/net/base/listen_socket.h
@@ -114,8 +114,8 @@ class ListenSocket : public base::RefCountedThreadSafe<ListenSocket>,
// The socket's libevent wrapper
MessageLoopForIO::FileDescriptorWatcher watcher_;
// Called by MessagePumpLibevent when the socket is ready to do I/O
- void OnFileCanReadWithoutBlocking(int fd);
- void OnFileCanWriteWithoutBlocking(int fd);
+ virtual void OnFileCanReadWithoutBlocking(int fd);
+ virtual void OnFileCanWriteWithoutBlocking(int fd);
#endif
SOCKET socket_;
diff --git a/net/base/load_flags_list.h b/net/base/load_flags_list.h
index 6f230bb..a8420a5 100644
--- a/net/base/load_flags_list.h
+++ b/net/base/load_flags_list.h
@@ -30,7 +30,7 @@ LOAD_FLAG(ONLY_FROM_CACHE, 1 << 3)
LOAD_FLAG(DISABLE_CACHE, 1 << 4)
// This is a navigation that will not be intercepted by any registered
-// URLRequest::Interceptors.
+// net::URLRequest::Interceptors.
LOAD_FLAG(DISABLE_INTERCEPT, 1 << 5)
// If present, upload progress messages should be provided to initiator.
diff --git a/net/base/load_states.h b/net/base/load_states.h
index d80e182..64b2a46 100644
--- a/net/base/load_states.h
+++ b/net/base/load_states.h
@@ -13,7 +13,7 @@ namespace net {
enum LoadState {
// This is the default state. It corresponds to a resource load that has
// either not yet begun or is idle waiting for the consumer to do something
- // to move things along (e.g., the consumer of an URLRequest may not have
+ // to move things along (e.g., the consumer of an net::URLRequest may not have
// called Read yet).
LOAD_STATE_IDLE,
@@ -65,7 +65,7 @@ enum LoadState {
// read to complete. In the case of a HTTP transaction, this corresponds to
// the period after the response headers have been received and before all of
// the response body has been downloaded. (NOTE: This state only applies for
- // an URLRequest while there is an outstanding Read operation.)
+ // an net::URLRequest while there is an outstanding Read operation.)
LOAD_STATE_READING_RESPONSE,
};
diff --git a/net/base/mime_sniffer.cc b/net/base/mime_sniffer.cc
index bd16462..1a52b99 100644
--- a/net/base/mime_sniffer.cc
+++ b/net/base/mime_sniffer.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// 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.
@@ -146,8 +146,6 @@ static const MagicNumber kMagicNumbers[] = {
MAGIC_NUMBER("image/tiff", "II*")
MAGIC_NUMBER("image/tiff", "MM\x00*")
MAGIC_NUMBER("audio/mpeg", "ID3")
- MAGIC_NUMBER("image/webp", "RIFF....WEBPVP8 ")
- MAGIC_NUMBER("video/webm", "\x1A\x45\xDF\xA3")
// TODO(abarth): we don't handle partial byte matches yet
// MAGIC_NUMBER("video/mpeg", "\x00\x00\x01\xB")
// MAGIC_NUMBER("audio/mpeg", "\xFF\xE")
@@ -217,19 +215,6 @@ static scoped_refptr<base::Histogram> UMASnifferHistogramGet(const char* name,
return counter;
}
-// Compare content header to a magic number where magic_entry can contain '.'
-// for single character of anything, allowing some bytes to be skipped.
-static bool MagicCmp(const char* magic_entry, const char* content, size_t len) {
- while (len) {
- if ((*magic_entry != '.') && (*magic_entry != *content))
- return false;
- ++magic_entry;
- ++content;
- --len;
- }
- return true;
-}
-
static bool MatchMagicNumber(const char* content, size_t size,
const MagicNumber* magic_entry,
std::string* result) {
@@ -254,7 +239,7 @@ static bool MatchMagicNumber(const char* content, size_t size,
}
} else {
if (size >= len)
- match = MagicCmp(magic_entry->magic, content, len);
+ match = (memcmp(magic_entry->magic, content, len) == 0);
}
if (match) {
@@ -266,8 +251,7 @@ static bool MatchMagicNumber(const char* content, size_t size,
static bool CheckForMagicNumbers(const char* content, size_t size,
const MagicNumber* magic, size_t magic_len,
- base::Histogram* counter,
- std::string* result) {
+ base::Histogram* counter, std::string* result) {
for (size_t i = 0; i < magic_len; ++i) {
if (MatchMagicNumber(content, size, &(magic[i]), result)) {
if (counter) counter->Add(static_cast<int>(i));
diff --git a/net/base/mime_util.cc b/net/base/mime_util.cc
index ddcfc4b..d95c029 100644
--- a/net/base/mime_util.cc
+++ b/net/base/mime_util.cc
@@ -9,8 +9,8 @@
#include "net/base/platform_mime_util.h"
#include "base/hash_tables.h"
+#include "base/lazy_instance.h"
#include "base/logging.h"
-#include "base/singleton.h"
#include "base/string_split.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
@@ -51,7 +51,7 @@ class MimeUtil : public PlatformMimeUtil {
const std::vector<std::string>& codecs) const;
private:
- friend struct DefaultSingletonTraits<MimeUtil>;
+ friend struct base::DefaultLazyInstanceTraits<MimeUtil>;
MimeUtil() {
InitializeMimeTypeMaps();
}
@@ -71,6 +71,8 @@ class MimeUtil : public PlatformMimeUtil {
StrictMappings strict_format_map_;
}; // class MimeUtil
+static base::LazyInstance<MimeUtil> g_mime_util(base::LINKER_INITIALIZED);
+
struct MimeInfo {
const char* mime_type;
const char* extensions; // comma separated list
@@ -473,70 +475,67 @@ bool MimeUtil::IsSupportedStrictMediaMimeType(const std::string& mime_type,
// Wrappers for the singleton
//----------------------------------------------------------------------------
-static MimeUtil* GetMimeUtil() {
- return Singleton<MimeUtil>::get();
-}
-
bool GetMimeTypeFromExtension(const FilePath::StringType& ext,
std::string* mime_type) {
- return GetMimeUtil()->GetMimeTypeFromExtension(ext, mime_type);
+ return g_mime_util.Get().GetMimeTypeFromExtension(ext, mime_type);
}
bool GetMimeTypeFromFile(const FilePath& file_path, std::string* mime_type) {
- return GetMimeUtil()->GetMimeTypeFromFile(file_path, mime_type);
+ return g_mime_util.Get().GetMimeTypeFromFile(file_path, mime_type);
}
bool GetPreferredExtensionForMimeType(const std::string& mime_type,
FilePath::StringType* extension) {
- return GetMimeUtil()->GetPreferredExtensionForMimeType(mime_type, extension);
+ return g_mime_util.Get().GetPreferredExtensionForMimeType(mime_type,
+ extension);
}
bool IsSupportedImageMimeType(const char* mime_type) {
- return GetMimeUtil()->IsSupportedImageMimeType(mime_type);
+ return g_mime_util.Get().IsSupportedImageMimeType(mime_type);
}
bool IsSupportedMediaMimeType(const char* mime_type) {
- return GetMimeUtil()->IsSupportedMediaMimeType(mime_type);
+ return g_mime_util.Get().IsSupportedMediaMimeType(mime_type);
}
bool IsSupportedNonImageMimeType(const char* mime_type) {
- return GetMimeUtil()->IsSupportedNonImageMimeType(mime_type);
+ return g_mime_util.Get().IsSupportedNonImageMimeType(mime_type);
}
bool IsSupportedJavascriptMimeType(const char* mime_type) {
- return GetMimeUtil()->IsSupportedJavascriptMimeType(mime_type);
+ return g_mime_util.Get().IsSupportedJavascriptMimeType(mime_type);
}
bool IsViewSourceMimeType(const char* mime_type) {
- return GetMimeUtil()->IsViewSourceMimeType(mime_type);
+ return g_mime_util.Get().IsViewSourceMimeType(mime_type);
}
bool IsSupportedMimeType(const std::string& mime_type) {
- return GetMimeUtil()->IsSupportedMimeType(mime_type);
+ return g_mime_util.Get().IsSupportedMimeType(mime_type);
}
bool MatchesMimeType(const std::string &mime_type_pattern,
const std::string &mime_type) {
- return GetMimeUtil()->MatchesMimeType(mime_type_pattern, mime_type);
+ return g_mime_util.Get().MatchesMimeType(mime_type_pattern, mime_type);
}
bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) {
- return GetMimeUtil()->AreSupportedMediaCodecs(codecs);
+ return g_mime_util.Get().AreSupportedMediaCodecs(codecs);
}
bool IsStrictMediaMimeType(const std::string& mime_type) {
- return GetMimeUtil()->IsStrictMediaMimeType(mime_type);
+ return g_mime_util.Get().IsStrictMediaMimeType(mime_type);
}
bool IsSupportedStrictMediaMimeType(const std::string& mime_type,
const std::vector<std::string>& codecs) {
- return GetMimeUtil()->IsSupportedStrictMediaMimeType(mime_type, codecs);
+ return g_mime_util.Get().IsSupportedStrictMediaMimeType(mime_type, codecs);
}
void ParseCodecString(const std::string& codecs,
std::vector<std::string>* codecs_out,
const bool strip) {
- GetMimeUtil()->ParseCodecString(codecs, codecs_out, strip);
+ g_mime_util.Get().ParseCodecString(codecs, codecs_out, strip);
}
namespace {
diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h
index bc7065d..8f94c4a 100644
--- a/net/base/net_error_list.h
+++ b/net/base/net_error_list.h
@@ -215,6 +215,11 @@ NET_ERROR(NETWORK_ACCESS_DENIED, -138)
// The request throttler module cancelled this request to avoid DDOS.
NET_ERROR(TEMPORARILY_THROTTLED, -139)
+// A request to create an SSL tunnel connection through the HTTPS proxy
+// received a non-200 (OK) and non-407 (Proxy Auth) response. The response
+// body might include a description of why the request failed.
+NET_ERROR(HTTPS_PROXY_TUNNEL_RESPONSE, -140)
+
// Certificate error codes
//
// The values of certificate error codes must be consecutive.
diff --git a/net/base/net_log.cc b/net/base/net_log.cc
index 1499d72..c9e7319 100644
--- a/net/base/net_log.cc
+++ b/net/base/net_log.cc
@@ -194,4 +194,27 @@ Value* NetLogSourceParameter::ToValue() const {
return dict;
}
+ScopedNetLogEvent::ScopedNetLogEvent(
+ const BoundNetLog& net_log,
+ NetLog::EventType event_type,
+ const scoped_refptr<NetLog::EventParameters>& params)
+ : net_log_(net_log),
+ event_type_(event_type) {
+ net_log_.BeginEvent(event_type, params);
+}
+
+ScopedNetLogEvent::~ScopedNetLogEvent() {
+ net_log_.EndEvent(event_type_, end_event_params_);
+}
+
+void ScopedNetLogEvent::SetEndEventParameters(
+ const scoped_refptr<NetLog::EventParameters>& end_event_params) {
+ DCHECK(!end_event_params_.get());
+ end_event_params_ = end_event_params;
+}
+
+const BoundNetLog& ScopedNetLogEvent::net_log() const {
+ return net_log_;
+}
+
} // namespace net
diff --git a/net/base/net_log.h b/net/base/net_log.h
index ad775fa..b8f903d 100644
--- a/net/base/net_log.h
+++ b/net/base/net_log.h
@@ -22,20 +22,17 @@ namespace net {
// NetLog is the destination for log messages generated by the network stack.
// Each log message has a "source" field which identifies the specific entity
-// that generated the message (for example, which URLRequest or which
+// that generated the message (for example, which net::URLRequest or which
// SocketStream).
//
// To avoid needing to pass in the "source id" to the logging functions, NetLog
// is usually accessed through a BoundNetLog, which will always pass in a
// specific source ID.
//
-// Note that NetLog is NOT THREADSAFE.
-//
// ******** The NetLog (and associated logging) is a work in progress ********
//
// TODO(eroman): Remove the 'const' qualitifer from the BoundNetLog methods.
-// TODO(eroman): Make the DNS jobs emit into the NetLog.
-// TODO(eroman): Start a new Source each time URLRequest redirects
+// TODO(eroman): Start a new Source each time net::URLRequest redirects
// (simpler to reason about each as a separate entity).
class NetLog {
@@ -273,6 +270,30 @@ class NetLogSourceParameter : public NetLog::EventParameters {
const NetLog::Source value_;
};
+// ScopedNetLogEvent logs a begin event on creation, and the corresponding end
+// event on destruction.
+class ScopedNetLogEvent {
+ public:
+ ScopedNetLogEvent(const BoundNetLog& net_log,
+ NetLog::EventType event_type,
+ const scoped_refptr<NetLog::EventParameters>& params);
+
+ ~ScopedNetLogEvent();
+
+ // Sets the parameters that will logged on object destruction. Can be called
+ // at most once for a given ScopedNetLogEvent object. If not called, the end
+ // event will have no parameters.
+ void SetEndEventParameters(
+ const scoped_refptr<NetLog::EventParameters>& end_event_params);
+
+ const BoundNetLog& net_log() const;
+
+ private:
+ BoundNetLog net_log_;
+ const NetLog::EventType event_type_;
+ scoped_refptr<NetLog::EventParameters> end_event_params_;
+};
+
} // namespace net
#endif // NET_BASE_NET_LOG_H_
diff --git a/net/base/net_log_event_type_list.h b/net/base/net_log_event_type_list.h
index 0021c0d..f1bc4f8 100644
--- a/net/base/net_log_event_type_list.h
+++ b/net/base/net_log_event_type_list.h
@@ -13,7 +13,8 @@
// log context around it.)
EVENT_TYPE(CANCELLED)
-// Marks the creation/destruction of a request (URLRequest or SocketStream).
+// Marks the creation/destruction of a request (net::URLRequest or
+// SocketStream).
EVENT_TYPE(REQUEST_ALIVE)
// ------------------------------------------------------------------------
@@ -324,6 +325,9 @@ EVENT_TYPE(SOCKS_UNKNOWN_ADDRESS_TYPE)
// The start/end of a SSL connect().
EVENT_TYPE(SSL_CONNECT)
+// The start/end of a SSL accept().
+EVENT_TYPE(SSL_ACCEPT)
+
// An SSL error occurred while trying to do the indicated activity.
// The following parameters are attached to the event:
// {
@@ -464,12 +468,12 @@ EVENT_TYPE(SOCKET_POOL_BOUND_TO_SOCKET)
EVENT_TYPE(SOCKET_POOL_CONNECTING_N_SOCKETS)
// ------------------------------------------------------------------------
-// URLRequest
+// net::URLRequest
// ------------------------------------------------------------------------
-// Measures the time it took a URLRequestJob to start. For the most part this
-// corresponds with the time between URLRequest::Start() and
-// URLRequest::ResponseStarted(), however it is also repeated for every
+// Measures the time it took a net::URLRequestJob to start. For the most part
+// this corresponds with the time between net::URLRequest::Start() and
+// net::URLRequest::ResponseStarted(), however it is also repeated for every
// redirect, and every intercepted job that handles the request.
//
// For the BEGIN phase, the following parameters are attached:
@@ -486,7 +490,7 @@ EVENT_TYPE(SOCKET_POOL_CONNECTING_N_SOCKETS)
// }
EVENT_TYPE(URL_REQUEST_START_JOB)
-// This event is sent once a URLRequest receives a redirect. The parameters
+// This event is sent once a net::URLRequest receives a redirect. The parameters
// attached to the event are:
// {
// "location": <The URL that was redirected to>
@@ -589,7 +593,7 @@ EVENT_TYPE(SPDY_SESSION)
EVENT_TYPE(SPDY_SESSION_SYN_STREAM)
// This event is sent for a SPDY SYN_STREAM pushed by the server, where a
-// URLRequest is already waiting for the stream.
+// net::URLRequest is already waiting for the stream.
// The following parameters are attached:
// {
// "flags": <The control frame flags>
diff --git a/net/base/net_log_unittest.cc b/net/base/net_log_unittest.cc
new file mode 100644
index 0000000..8523955
--- /dev/null
+++ b/net/base/net_log_unittest.cc
@@ -0,0 +1,34 @@
+// 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.
+
+#include "net/base/capturing_net_log.h"
+#include "net/base/net_log.h"
+#include "net/base/net_log_unittest.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace {
+
+TEST(NetLog, ScopedNetLogEventTest) {
+ CapturingNetLog log(CapturingNetLog::kUnbounded);
+ BoundNetLog net_log(BoundNetLog::Make(&log, NetLog::SOURCE_URL_REQUEST));
+
+ scoped_ptr<ScopedNetLogEvent> net_log_event(
+ new ScopedNetLogEvent(net_log, NetLog::TYPE_REQUEST_ALIVE, NULL));
+
+ CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
+ EXPECT_EQ(1u, entries.size());
+ EXPECT_TRUE(LogContainsBeginEvent(entries, 0, NetLog::TYPE_REQUEST_ALIVE));
+
+ net_log_event.reset();
+ log.GetEntries(&entries);
+ EXPECT_EQ(2u, entries.size());
+ EXPECT_TRUE(LogContainsEndEvent(entries, 1, NetLog::TYPE_REQUEST_ALIVE));
+}
+
+} // namespace
+
+} // namespace net
diff --git a/net/base/net_util.cc b/net/base/net_util.cc
index 5e02544..1562951 100644
--- a/net/base/net_util.cc
+++ b/net/base/net_util.cc
@@ -518,6 +518,11 @@ bool IsCompatibleWithASCIILetters(const std::string& lang) {
typedef std::map<std::string, icu::UnicodeSet*> LangToExemplarSetMap;
class LangToExemplarSet {
+ public:
+ static LangToExemplarSet* GetInstance() {
+ return Singleton<LangToExemplarSet>::get();
+ }
+
private:
LangToExemplarSetMap map;
LangToExemplarSet() { }
@@ -535,7 +540,7 @@ class LangToExemplarSet {
bool GetExemplarSetForLang(const std::string& lang,
icu::UnicodeSet** lang_set) {
- const LangToExemplarSetMap& map = Singleton<LangToExemplarSet>()->map;
+ const LangToExemplarSetMap& map = LangToExemplarSet::GetInstance()->map;
LangToExemplarSetMap::const_iterator pos = map.find(lang);
if (pos != map.end()) {
*lang_set = pos->second;
@@ -546,7 +551,7 @@ bool GetExemplarSetForLang(const std::string& lang,
void SetExemplarSetForLang(const std::string& lang,
icu::UnicodeSet* lang_set) {
- LangToExemplarSetMap& map = Singleton<LangToExemplarSet>()->map;
+ LangToExemplarSetMap& map = LangToExemplarSet::GetInstance()->map;
map.insert(std::make_pair(lang, lang_set));
}
@@ -1052,7 +1057,7 @@ const FormatUrlType kFormatUrlOmitAll = kFormatUrlOmitUsernamePassword |
kFormatUrlOmitHTTP | kFormatUrlOmitTrailingSlashOnBareHostname;
// TODO(viettrungluu): We don't want non-POD globals; change this.
-std::set<int> explicitly_allowed_ports;
+std::multiset<int> explicitly_allowed_ports;
GURL FilePathToFileURL(const FilePath& path) {
// Produce a URL like "file:///C:/foo" for a regular file, or
@@ -1145,7 +1150,9 @@ std::string GetFileNameFromCD(const std::string& header,
// RFC 5987 value should be ASCII-only.
if (!IsStringASCII(value))
return std::string();
- std::string tmp = UnescapeURLComponent(value, UnescapeRule::SPACES);
+ std::string tmp = UnescapeURLComponent(
+ value,
+ UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS);
if (base::ConvertToUtf8AndNormalize(tmp, charset, &decoded))
return decoded;
}
@@ -1360,7 +1367,7 @@ std::string GetDirectoryListingEntry(const string16& name,
string16 modified_str;
// |modified| can be NULL in FTP listings.
if (!modified.is_null()) {
- modified_str = WideToUTF16Hack(base::TimeFormatShortDateAndTime(modified));
+ modified_str = base::TimeFormatShortDateAndTime(modified);
}
base::JsonDoubleQuote(modified_str, true, &result);
@@ -1494,12 +1501,7 @@ bool IsPortAllowedByOverride(int port) {
if (explicitly_allowed_ports.empty())
return false;
- std::set<int>::const_iterator it =
- std::find(explicitly_allowed_ports.begin(),
- explicitly_allowed_ports.end(),
- port);
-
- return it != explicitly_allowed_ports.end();
+ return explicitly_allowed_ports.count(port) > 0;
}
int SetNonBlocking(int fd) {
@@ -1724,7 +1726,7 @@ void SetExplicitlyAllowedPorts(const std::string& allowed_ports) {
if (allowed_ports.empty())
return;
- std::set<int> ports;
+ std::multiset<int> ports;
size_t last = 0;
size_t size = allowed_ports.size();
// The comma delimiter.
@@ -1750,6 +1752,18 @@ void SetExplicitlyAllowedPorts(const std::string& allowed_ports) {
explicitly_allowed_ports = ports;
}
+ScopedPortException::ScopedPortException(int port) : port_(port) {
+ explicitly_allowed_ports.insert(port);
+}
+
+ScopedPortException::~ScopedPortException() {
+ std::multiset<int>::iterator it = explicitly_allowed_ports.find(port_);
+ if (it != explicitly_allowed_ports.end())
+ explicitly_allowed_ports.erase(it);
+ else
+ NOTREACHED();
+}
+
enum IPv6SupportStatus {
IPV6_CANNOT_CREATE_SOCKETS,
IPV6_CAN_CREATE_SOCKETS,
diff --git a/net/base/net_util.h b/net/base/net_util.h
index 4b87c70..bb145e0 100644
--- a/net/base/net_util.h
+++ b/net/base/net_util.h
@@ -71,7 +71,7 @@ extern const FormatUrlType kFormatUrlOmitTrailingSlashOnBareHostname;
extern const FormatUrlType kFormatUrlOmitAll;
// Holds a list of ports that should be accepted despite bans.
-extern std::set<int> explicitly_allowed_ports;
+extern std::multiset<int> explicitly_allowed_ports;
// Given the full path to a file name, creates a file: URL. The returned URL
// may not be valid if the input is malformed.
@@ -125,7 +125,7 @@ void GetIdentityFromURL(const GURL& url,
std::string GetHostOrSpecFromURL(const GURL& url);
// Return the value of the HTTP response header with name 'name'. 'headers'
-// should be in the format that URLRequest::GetResponseHeaders() returns.
+// should be in the format that net::URLRequest::GetResponseHeaders() returns.
// Returns the empty string if the header is not found.
std::wstring GetSpecificHeader(const std::wstring& headers,
const std::wstring& name);
@@ -338,6 +338,17 @@ GURL SimplifyUrlForRequest(const GURL& url);
void SetExplicitlyAllowedPorts(const std::string& allowed_ports);
+class ScopedPortException {
+ public:
+ ScopedPortException(int port);
+ ~ScopedPortException();
+
+ private:
+ int port_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedPortException);
+};
+
// Perform a simplistic test to see if IPv6 is supported by trying to create an
// IPv6 socket.
// TODO(jar): Make test more in-depth as needed.
diff --git a/net/base/openssl_memory_private_key_store.cc b/net/base/openssl_memory_private_key_store.cc
new file mode 100644
index 0000000..6b65dbe
--- /dev/null
+++ b/net/base/openssl_memory_private_key_store.cc
@@ -0,0 +1,68 @@
+// 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.
+
+// Defines an in-memory private key store, primarily used for testing.
+
+#include <openssl/evp.h>
+
+#include "net/base/openssl_private_key_store.h"
+
+#include "base/logging.h"
+#include "base/openssl_util.h"
+#include "base/singleton.h"
+#include "net/base/x509_certificate.h"
+
+namespace net {
+
+namespace {
+
+class OpenSSLMemoryKeyStore : public OpenSSLPrivateKeyStore {
+ public:
+ OpenSSLMemoryKeyStore() {}
+
+ static OpenSSLMemoryKeyStore* GetInstance() {
+ return Singleton<OpenSSLMemoryKeyStore>::get();
+ }
+
+ virtual ~OpenSSLMemoryKeyStore() {
+ AutoLock lock(lock_);
+ for (std::vector<EVP_PKEY*>::iterator it = keys_.begin();
+ it != keys_.end(); ++it) {
+ EVP_PKEY_free(*it);
+ }
+ }
+
+ virtual bool StorePrivateKey(const GURL& url, EVP_PKEY* pkey) {
+ CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
+ AutoLock lock(lock_);
+ keys_.push_back(pkey);
+ return true;
+ }
+
+ virtual EVP_PKEY* FetchPrivateKey(EVP_PKEY* pkey) {
+ AutoLock lock(lock_);
+ for (std::vector<EVP_PKEY*>::iterator it = keys_.begin();
+ it != keys_.end(); ++it) {
+ if (EVP_PKEY_cmp(*it, pkey) == 1)
+ return *it;
+ }
+ return NULL;
+ }
+
+ private:
+ std::vector<EVP_PKEY*> keys_;
+ Lock lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(OpenSSLMemoryKeyStore);
+};
+
+} // namespace
+
+// static
+OpenSSLPrivateKeyStore* OpenSSLPrivateKeyStore::GetInstance() {
+ return OpenSSLMemoryKeyStore::GetInstance();
+}
+
+} // namespace net
+
diff --git a/net/base/openssl_private_key_store.h b/net/base/openssl_private_key_store.h
new file mode 100644
index 0000000..17f8fe1
--- /dev/null
+++ b/net/base/openssl_private_key_store.h
@@ -0,0 +1,51 @@
+// 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.
+
+#ifndef NET_BASE_OPENSSL_PRIVATE_KEY_STORE_H_
+#define NET_BASE_OPENSSL_PRIVATE_KEY_STORE_H_
+#pragma once
+
+#include "base/basictypes.h"
+
+typedef struct evp_pkey_st EVP_PKEY;
+
+class GURL;
+
+namespace net {
+
+// Defines an abstract store for private keys; the OpenSSL library does not
+// provide this service so it is left to individual platforms to provide it.
+//
+// The contract is that the private key will be stored in an appropriate secure
+// system location, and be available to the SSLClientSocketOpenSSL when using a
+// client certificate created against the associated public key for client
+// authentication.
+class OpenSSLPrivateKeyStore {
+ public:
+ // Platforms must define this factory function as appropriate.
+ static OpenSSLPrivateKeyStore* GetInstance();
+
+ virtual ~OpenSSLPrivateKeyStore() {}
+
+ // Called to store a private key generated via <keygen> while visiting |url|.
+ // Does not takes ownership of |pkey|, the caller reamins responsible to
+ // EVP_PKEY_free it. (Internally, a copy maybe made or the reference count
+ // incremented).
+ // Returns false if an error occurred whilst attempting to store the key.
+ virtual bool StorePrivateKey(const GURL& url, EVP_PKEY* pkey) = 0;
+
+ // Given a |public_key| part returns the corresponding private key, or NULL
+ // if no key found. Does NOT return ownership.
+ virtual EVP_PKEY* FetchPrivateKey(EVP_PKEY* public_key) = 0;
+
+ protected:
+ OpenSSLPrivateKeyStore() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OpenSSLPrivateKeyStore);
+};
+
+} // namespace net
+
+#endif // NET_BASE_OPENSSL_PRIVATE_KEY_STORE_H_
diff --git a/net/base/registry_controlled_domain.h b/net/base/registry_controlled_domain.h
index fc64f3a..7586c12 100644
--- a/net/base/registry_controlled_domain.h
+++ b/net/base/registry_controlled_domain.h
@@ -198,6 +198,11 @@ class RegistryControlledDomainService {
static size_t GetRegistryLength(const std::wstring& host,
bool allow_unknown_registries);
+ // Returns the singleton instance, after attempting to initialize it.
+ // NOTE that if the effective-TLD data resource can't be found, the instance
+ // will be initialized and continue operation with simple default TLD data.
+ static RegistryControlledDomainService* GetInstance();
+
protected:
// The entire protected API is only for unit testing. I mean it. Don't make
// me come over there!
@@ -221,11 +226,6 @@ class RegistryControlledDomainService {
// To allow construction of the internal singleton instance.
friend struct DefaultSingletonTraits<RegistryControlledDomainService>;
- // Returns the singleton instance, after attempting to initialize it.
- // NOTE that if the effective-TLD data resource can't be found, the instance
- // will be initialized and continue operation with simple default TLD data.
- static RegistryControlledDomainService* GetInstance();
-
// Internal workings of the static public methods. See above.
static std::string GetDomainAndRegistryImpl(const std::string& host);
size_t GetRegistryLengthImpl(const std::string& host,
diff --git a/net/base/ssl_cert_request_info.cc b/net/base/ssl_cert_request_info.cc
index b7728e5..bb91632 100644
--- a/net/base/ssl_cert_request_info.cc
+++ b/net/base/ssl_cert_request_info.cc
@@ -11,11 +11,6 @@ namespace net {
SSLCertRequestInfo::SSLCertRequestInfo() {
}
-void SSLCertRequestInfo::Reset() {
- host_and_port.clear();
- client_certs.clear();
-}
-
SSLCertRequestInfo::~SSLCertRequestInfo() {
}
diff --git a/net/base/ssl_cert_request_info.h b/net/base/ssl_cert_request_info.h
index 416e902..22eecfe 100644
--- a/net/base/ssl_cert_request_info.h
+++ b/net/base/ssl_cert_request_info.h
@@ -22,9 +22,6 @@ class SSLCertRequestInfo
public:
SSLCertRequestInfo();
- // Resets the SSLCertRequestInfo as if no certificate had been requested.
- void Reset();
-
// The host and port of the SSL server that requested client authentication.
std::string host_and_port;
diff --git a/net/base/ssl_cipher_suite_names.cc b/net/base/ssl_cipher_suite_names.cc
index 39efd1c..eb6fe46 100644
--- a/net/base/ssl_cipher_suite_names.cc
+++ b/net/base/ssl_cipher_suite_names.cc
@@ -366,7 +366,7 @@ void SSLVersionToString(const char** name, int ssl_version) {
*name = "TLS 1.2";
break;
default:
- NOTREACHED();
+ NOTREACHED() << ssl_version;
*name = "???";
break;
}
diff --git a/net/base/ssl_config_service.cc b/net/base/ssl_config_service.cc
index 041c720..d6df3ea 100644
--- a/net/base/ssl_config_service.cc
+++ b/net/base/ssl_config_service.cc
@@ -20,11 +20,12 @@ SSLConfig::CertAndStatus::CertAndStatus() : cert_status(0) {}
SSLConfig::CertAndStatus::~CertAndStatus() {}
SSLConfig::SSLConfig()
- : rev_checking_enabled(true), ssl2_enabled(false), ssl3_enabled(true),
+ : rev_checking_enabled(true), ssl3_enabled(true),
tls1_enabled(true), dnssec_enabled(false), snap_start_enabled(false),
dns_cert_provenance_checking_enabled(false),
- mitm_proxies_allowed(false), false_start_enabled(true),
- send_client_cert(false), verify_ev_cert(false), ssl3_fallback(false) {
+ session_resume_disabled(false), mitm_proxies_allowed(false),
+ false_start_enabled(true), send_client_cert(false),
+ verify_ev_cert(false), ssl3_fallback(false) {
}
SSLConfig::~SSLConfig() {
@@ -173,7 +174,6 @@ void SSLConfigService::RemoveObserver(Observer* observer) {
void SSLConfigService::ProcessConfigUpdate(const SSLConfig& orig_config,
const SSLConfig& new_config) {
if (orig_config.rev_checking_enabled != new_config.rev_checking_enabled ||
- orig_config.ssl2_enabled != new_config.ssl2_enabled ||
orig_config.ssl3_enabled != new_config.ssl3_enabled ||
orig_config.tls1_enabled != new_config.tls1_enabled) {
FOR_EACH_OBSERVER(Observer, observer_list_, OnSSLConfigChanged());
diff --git a/net/base/ssl_config_service.h b/net/base/ssl_config_service.h
index 0639f48..de2ebef 100644
--- a/net/base/ssl_config_service.h
+++ b/net/base/ssl_config_service.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// 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.
@@ -18,13 +18,13 @@ namespace net {
// A collection of SSL-related configuration settings.
struct SSLConfig {
// Default to revocation checking.
- // Default to SSL 2.0 off, SSL 3.0 on, and TLS 1.0 on.
+ // Default to SSL 3.0 on and TLS 1.0 on.
SSLConfig();
~SSLConfig();
bool rev_checking_enabled; // True if server certificate revocation
// checking is enabled.
- bool ssl2_enabled; // True if SSL 2.0 is enabled.
+ // SSL 2.0 is not supported.
bool ssl3_enabled; // True if SSL 3.0 is enabled.
bool tls1_enabled; // True if TLS 1.0 is enabled.
bool dnssec_enabled; // True if we'll accept DNSSEC chains in certificates.
@@ -32,14 +32,22 @@ struct SSLConfig {
// True if we'll do async checks for certificate provenance using DNS.
bool dns_cert_provenance_checking_enabled;
- // Cipher suites which should be explicitly prevented from being used. By
- // default, all cipher suites supported by the underlying SSL implementation
- // will be enabled, except for:
+ // TODO(hclam): This option is used to simplify the SSLServerSocketNSS
+ // implementation and should be removed when session caching is implemented.
+ // See http://crbug.com/67236 for more details.
+ bool session_resume_disabled; // Don't allow session resume.
+
+ // Cipher suites which should be explicitly prevented from being used in
+ // addition to those disabled by the net built-in policy -- by default, all
+ // cipher suites supported by the underlying SSL implementation will be
+ // enabled except for:
// - Null encryption cipher suites.
// - Weak cipher suites: < 80 bits of security strength.
// - FORTEZZA cipher suites (obsolete).
// - IDEA cipher suites (RFC 5469 explains why).
// - Anonymous cipher suites.
+ // The ciphers listed in |disabled_cipher_suites| will be removed in addition
+ // to the above statically defined disable list.
//
// Though cipher suites are sent in TLS as "uint8 CipherSuite[2]", in
// big-endian form, they should be declared in host byte order, with the
@@ -47,7 +55,7 @@ struct SSLConfig {
// Ex: To disable TLS_RSA_WITH_RC4_128_MD5, specify 0x0004, while to
// disable TLS_ECDH_ECDSA_WITH_RC4_128_SHA, specify 0xC002.
//
- // TODO(rsleevi): Not implemented when using OpenSSL or Schannel.
+ // TODO(rsleevi): Not implemented when using Schannel.
std::vector<uint16> disabled_cipher_suites;
// True if we allow this connection to be MITM attacked. This sounds a little
@@ -112,7 +120,6 @@ class SSLConfigService : public base::RefCountedThreadSafe<SSLConfigService> {
// data in SSLConfig, just those that qualify as a user config change.
// The following settings are considered user changes:
// rev_checking_enabled
- // ssl2_enabled
// ssl3_enabled
// tls1_enabled
virtual void OnSSLConfigChanged() = 0;
@@ -181,7 +188,7 @@ class SSLConfigService : public base::RefCountedThreadSafe<SSLConfigService> {
virtual ~SSLConfigService();
// SetFlags sets the values of several flags based on global configuration.
- static void SetSSLConfigFlags(SSLConfig*);
+ static void SetSSLConfigFlags(SSLConfig* ssl_config);
// Process before/after config update.
void ProcessConfigUpdate(const SSLConfig& orig_config,
diff --git a/net/base/ssl_config_service_mac.cc b/net/base/ssl_config_service_mac.cc
index 148bba4..06f9555 100644
--- a/net/base/ssl_config_service_mac.cc
+++ b/net/base/ssl_config_service_mac.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// 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.
@@ -17,7 +17,6 @@ namespace {
static const int kConfigUpdateInterval = 10; // seconds
-static const bool kSSL2EnabledDefaultValue = false;
static const bool kSSL3EnabledDefaultValue = true;
static const bool kTLS1EnabledDefaultValue = true;
@@ -27,7 +26,6 @@ static CFStringRef kOCSPStyleKey = CFSTR("OCSPStyle");
static CFStringRef kCRLStyleKey = CFSTR("CRLStyle");
static CFStringRef kNoneRevocationValue = CFSTR("None");
static CFStringRef kBestAttemptRevocationValue = CFSTR("BestAttempt");
-static CFStringRef kSSL2EnabledKey = CFSTR("org.chromium.ssl.ssl2");
static CFStringRef kSSL3EnabledKey = CFSTR("org.chromium.ssl.ssl3");
static CFStringRef kTLS1EnabledKey = CFSTR("org.chromium.ssl.tls1");
@@ -89,8 +87,6 @@ bool SSLConfigServiceMac::GetSSLConfigNow(SSLConfig* config) {
config->rev_checking_enabled = (RevocationStyleIsEnabled(kOCSPStyleKey) ||
RevocationStyleIsEnabled(kCRLStyleKey));
- config->ssl2_enabled = SSLVersionIsEnabled(kSSL2EnabledKey,
- kSSL2EnabledDefaultValue);
config->ssl3_enabled = SSLVersionIsEnabled(kSSL3EnabledKey,
kSSL3EnabledDefaultValue);
config->tls1_enabled = SSLVersionIsEnabled(kTLS1EnabledKey,
@@ -103,14 +99,6 @@ bool SSLConfigServiceMac::GetSSLConfigNow(SSLConfig* config) {
}
// static
-void SSLConfigServiceMac::SetSSL2Enabled(bool enabled) {
- CFPreferencesSetAppValue(kSSL2EnabledKey,
- enabled ? kCFBooleanTrue : kCFBooleanFalse,
- kCFPreferencesCurrentApplication);
- CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication);
-}
-
-// static
void SSLConfigServiceMac::SetSSL3Enabled(bool enabled) {
CFPreferencesSetAppValue(kSSL3EnabledKey,
enabled ? kCFBooleanTrue : kCFBooleanFalse,
diff --git a/net/base/ssl_config_service_mac.h b/net/base/ssl_config_service_mac.h
index 4524d95..2583e80 100644
--- a/net/base/ssl_config_service_mac.h
+++ b/net/base/ssl_config_service_mac.h
@@ -24,7 +24,6 @@ class SSLConfigServiceMac : public SSLConfigService {
// Setters. Can be called on any thread.
static void SetRevCheckingEnabled(bool enabled);
- static void SetSSL2Enabled(bool enabled);
static void SetSSL3Enabled(bool enabled);
static void SetTLS1Enabled(bool enabled);
diff --git a/net/base/ssl_config_service_mac_unittest.cc b/net/base/ssl_config_service_mac_unittest.cc
index c94f213..a933b1c 100644
--- a/net/base/ssl_config_service_mac_unittest.cc
+++ b/net/base/ssl_config_service_mac_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// 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.
@@ -39,7 +39,6 @@ TEST(SSLConfigServiceMacTest, GetNowTest) {
// Verify that the constructor sets the correct default values.
net::SSLConfig config;
EXPECT_TRUE(config.rev_checking_enabled);
- EXPECT_FALSE(config.ssl2_enabled);
EXPECT_TRUE(config.ssl3_enabled);
EXPECT_TRUE(config.tls1_enabled);
@@ -69,19 +68,6 @@ TEST(SSLConfigServiceMacTest, SetTest) {
net::SSLConfigServiceMac::SetRevCheckingEnabled(
config_save.rev_checking_enabled);
- // Test SetSSL2Enabled.
- net::SSLConfigServiceMac::SetSSL2Enabled(true);
- rv = net::SSLConfigServiceMac::GetSSLConfigNow(&config);
- EXPECT_TRUE(rv);
- EXPECT_TRUE(config.ssl2_enabled);
-
- net::SSLConfigServiceMac::SetSSL2Enabled(false);
- rv = net::SSLConfigServiceMac::GetSSLConfigNow(&config);
- EXPECT_TRUE(rv);
- EXPECT_FALSE(config.ssl2_enabled);
-
- net::SSLConfigServiceMac::SetSSL2Enabled(config_save.ssl2_enabled);
-
// Test SetSSL3Enabled.
net::SSLConfigServiceMac::SetSSL3Enabled(true);
rv = net::SSLConfigServiceMac::GetSSLConfigNow(&config);
@@ -147,15 +133,13 @@ TEST(SSLConfigServiceMacTest, ObserverTest) {
EXPECT_TRUE(rv);
net::SSLConfig config;
- net::SSLConfigServiceMac::SetSSL2Enabled(false);
- config_service->GetSSLConfigAt(&config, now);
// Add an observer.
SSLConfigServiceMacObserver observer;
config_service->AddObserver(&observer);
- // Toggle SSL2.
- net::SSLConfigServiceMac::SetSSL2Enabled(!config_save.ssl2_enabled);
+ // Toggle SSL3.
+ net::SSLConfigServiceMac::SetSSL3Enabled(!config_save.ssl3_enabled);
config_service->GetSSLConfigAt(&config, later);
// Verify that the observer was notified.
@@ -164,7 +148,7 @@ TEST(SSLConfigServiceMacTest, ObserverTest) {
// Remove the observer.
config_service->RemoveObserver(&observer);
- // Restore the original SSL2 setting.
- net::SSLConfigServiceMac::SetSSL2Enabled(config_save.ssl2_enabled);
+ // Restore the original SSL3 setting.
+ net::SSLConfigServiceMac::SetSSL3Enabled(config_save.ssl3_enabled);
}
diff --git a/net/base/ssl_config_service_win.cc b/net/base/ssl_config_service_win.cc
index d4153c3..aca0626 100644
--- a/net/base/ssl_config_service_win.cc
+++ b/net/base/ssl_config_service_win.cc
@@ -29,7 +29,6 @@ static const wchar_t kProtocolsValueName[] = L"SecureProtocols";
// The bits are OR'ed to form the DWORD value. So 0xa0 means SSL 3.0 and
// TLS 1.0.
enum {
- SSL2 = 0x08,
SSL3 = 0x20,
TLS1 = 0x80
};
@@ -77,7 +76,6 @@ bool SSLConfigServiceWin::GetSSLConfigNow(SSLConfig* config) {
protocols = PROTOCOLS_DEFAULT;
config->rev_checking_enabled = (revocation != 0);
- config->ssl2_enabled = ((protocols & SSL2) != 0);
config->ssl3_enabled = ((protocols & SSL3) != 0);
config->tls1_enabled = ((protocols & TLS1) != 0);
SSLConfigService::SetSSLConfigFlags(config);
@@ -96,6 +94,7 @@ bool SSLConfigServiceWin::GetSSLConfigNow(SSLConfig* config) {
void SSLConfigServiceWin::SetRevCheckingEnabled(bool enabled) {
// This registry access goes to disk and will slow down the IO thread.
// http://crbug.com/61455
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
DWORD value = enabled;
RegKey internet_settings(HKEY_CURRENT_USER, kInternetSettingsSubKeyName,
KEY_WRITE);
@@ -105,11 +104,6 @@ void SSLConfigServiceWin::SetRevCheckingEnabled(bool enabled) {
}
// static
-void SSLConfigServiceWin::SetSSL2Enabled(bool enabled) {
- SetSSLVersionEnabled(SSL2, enabled);
-}
-
-// static
void SSLConfigServiceWin::SetSSL3Enabled(bool enabled) {
SetSSLVersionEnabled(SSL3, enabled);
}
@@ -123,6 +117,7 @@ void SSLConfigServiceWin::SetTLS1Enabled(bool enabled) {
void SSLConfigServiceWin::SetSSLVersionEnabled(int version, bool enabled) {
// This registry access goes to disk and will slow down the IO thread.
// http://crbug.com/61455
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
RegKey internet_settings(HKEY_CURRENT_USER, kInternetSettingsSubKeyName,
KEY_READ | KEY_WRITE);
DWORD value;
diff --git a/net/base/ssl_config_service_win.h b/net/base/ssl_config_service_win.h
index e5eb862..6d5b29f 100644
--- a/net/base/ssl_config_service_win.h
+++ b/net/base/ssl_config_service_win.h
@@ -29,7 +29,6 @@ class SSLConfigServiceWin : public SSLConfigService {
// Setters. Can be called on any thread.
static void SetRevCheckingEnabled(bool enabled);
- static void SetSSL2Enabled(bool enabled);
static void SetSSL3Enabled(bool enabled);
static void SetTLS1Enabled(bool enabled);
diff --git a/net/base/ssl_config_service_win_unittest.cc b/net/base/ssl_config_service_win_unittest.cc
index 1db4cef..7669d99 100644
--- a/net/base/ssl_config_service_win_unittest.cc
+++ b/net/base/ssl_config_service_win_unittest.cc
@@ -39,7 +39,6 @@ TEST(SSLConfigServiceWinTest, GetNowTest) {
// Verify that the constructor sets the correct default values.
net::SSLConfig config;
EXPECT_EQ(true, config.rev_checking_enabled);
- EXPECT_EQ(false, config.ssl2_enabled);
EXPECT_EQ(true, config.ssl3_enabled);
EXPECT_EQ(true, config.tls1_enabled);
@@ -69,19 +68,6 @@ TEST(SSLConfigServiceWinTest, SetTest) {
net::SSLConfigServiceWin::SetRevCheckingEnabled(
config_save.rev_checking_enabled);
- // Test SetSSL2Enabled.
- net::SSLConfigServiceWin::SetSSL2Enabled(true);
- rv = net::SSLConfigServiceWin::GetSSLConfigNow(&config);
- EXPECT_TRUE(rv);
- EXPECT_TRUE(config.ssl2_enabled);
-
- net::SSLConfigServiceWin::SetSSL2Enabled(false);
- rv = net::SSLConfigServiceWin::GetSSLConfigNow(&config);
- EXPECT_TRUE(rv);
- EXPECT_FALSE(config.ssl2_enabled);
-
- net::SSLConfigServiceWin::SetSSL2Enabled(config_save.ssl2_enabled);
-
// Test SetSSL3Enabled.
net::SSLConfigServiceWin::SetSSL3Enabled(true);
rv = net::SSLConfigServiceWin::GetSSLConfigNow(&config);
@@ -147,15 +133,13 @@ TEST(SSLConfigServiceWinTest, ObserverTest) {
EXPECT_TRUE(rv);
net::SSLConfig config;
- net::SSLConfigServiceWin::SetSSL2Enabled(false);
- config_service->GetSSLConfigAt(&config, now);
// Add an observer.
SSLConfigServiceWinObserver observer;
config_service->AddObserver(&observer);
- // Toggle SSL2.
- net::SSLConfigServiceWin::SetSSL2Enabled(!config_save.ssl2_enabled);
+ // Toggle SSL3.
+ net::SSLConfigServiceWin::SetSSL3Enabled(!config_save.ssl3_enabled);
config_service->GetSSLConfigAt(&config, later);
// Verify that the observer was notified.
@@ -164,7 +148,7 @@ TEST(SSLConfigServiceWinTest, ObserverTest) {
// Remove the observer.
config_service->RemoveObserver(&observer);
- // Restore the original SSL2 setting.
- net::SSLConfigServiceWin::SetSSL2Enabled(config_save.ssl2_enabled);
+ // Restore the original SSL3 setting.
+ net::SSLConfigServiceWin::SetSSL3Enabled(config_save.ssl3_enabled);
}
diff --git a/net/base/ssl_false_start_blacklist.txt b/net/base/ssl_false_start_blacklist.txt
index 4ef94be..aec6142 100644
--- a/net/base/ssl_false_start_blacklist.txt
+++ b/net/base/ssl_false_start_blacklist.txt
@@ -174,7 +174,6 @@ amo-happy-patients.com
amo-signature.net
amo-top.net
ampecommerce.com
-amsbwm.org
amsi.alliedgroup.net
amwaylive.com
analytics.sonymusic.com
@@ -741,7 +740,6 @@ cmithun.dojiggy.com
cms.whereilive.com.au
cnw.albertaequestrian.com
cnw.hcbc.ca
-co-labs.org
codarts.nl
coddy.com
cofunds.co.uk
@@ -861,9 +859,7 @@ cwa.fandr.com
cwa.telecomputing.no
cwt.no
cwtnordic.com
-cyberobservatories.net
cybershoppersonline.com
-cybs.rogers.com
d-ikt.no
d-starjob.com
d115.de
@@ -883,7 +879,6 @@ datasettlement.com
datatel.com
davidson.edu
davisregional.com
-daymet.org
dbpn.com
dc.myflorida.com
dc110.4shared.com
@@ -936,7 +931,6 @@ district205.net
djmmusic.com
dl.com
dl.rakuten.co.jp
-dlese.org
dmgov.org
dmz.rgcweb.org
docmesa.com
@@ -1165,6 +1159,7 @@ europass.cz
europlan.ru
eurotax.at
events.sainc.com
+everbox.com
evergabe-online.info
evoline.net
evoraoralcaresite.com
@@ -1359,7 +1354,6 @@ geometrik.golder.se
geonosis.itsso.gc.ca
georgefox.edu
gepartsrebates.com
-gepon.org
germfree.org
get1931roadster.com
get1933caddy.com
@@ -1460,7 +1454,6 @@ ggusd.us
ggy.com
gilmorehealth.com
giltcdn.com
-gisclimatechange.org
global2.mtsallstream.com
glove.mizunoballpark.com
glowinghealth.com.au
@@ -2000,7 +1993,6 @@ leshamwowoffre.com
level.mol.hu
lexor.lsp.at
lexsan.vestingonline.nl
-lgelements.com
lh.k12.ar.us
library.failteireland.ie
liemerscollege.nl
@@ -2686,11 +2678,8 @@ myesafedepositbox.com
myevolver.com
myexterran.com
myfauquierhealth.org
-myflcourtaccess.com
myfldocs.com
myfloodonline.com
-myfloridacounty.com
-myfloridaremit.com
myfluvaccine.com
mygetmighytighty.com
mygiftregistry.co.za
@@ -2825,7 +2814,6 @@ nraesafe.com
nrwbank.com
ns002.toshiba-sol.co.jp
ns11mm.sept11mm.org
-nsdlnetwork.org
nsw.gov.au
nswmentors.com
ntdira.com
@@ -3534,7 +3522,6 @@ s-yoyaku.city.urayasu.chiba.jp
s.ixiaa.com
s.ncp.imrworldwide.com
s1defense.com
-s2task.globe.gov
saab-leadengine.de
saas.dynamate.eu
saas.it-telcom.nl
@@ -4042,7 +4029,6 @@ tc4men.com
tco.cfbt-inspections.com
tcspost.thomassen.com
tdj.ac.jp
-teachingboxes.org
teachingpersonnel.com
teambrandon.ca
tecdlr.com
@@ -4062,7 +4048,6 @@ terrabanking.romexterra.ro
testdrivereward.com
testdriveunlimited2.com
tewkesburyschool.org
-tfelements.com
tge.cl
tgn.co.jp
tgw.com
@@ -4154,7 +4139,6 @@ toranomon-ichiba.com
tosti-asia.com
totalcore.com
touchnbrush.tv
-touchnet.com
toutatice.fr
tpmail.transplace.com
tracs.txstate.edu
@@ -4233,7 +4217,6 @@ uab.edu
uatoa.americanexpress.com
ube-ind.co.jp
ubi.pt
-ucar.edu
ucf.edu
uci.edu
uckac.edu
@@ -4480,7 +4463,6 @@ wastis-eu.st.com
wcupa.edu
wcvpn.wartburg.edu
wdpartnersonline.com
-weathercoalition.org
web-opas.osakaya.co.jp
web-pl.daikin.co.jp
web-vpn.hefr.ch
diff --git a/net/base/test_root_certs.cc b/net/base/test_root_certs.cc
new file mode 100644
index 0000000..6d4bc18
--- /dev/null
+++ b/net/base/test_root_certs.cc
@@ -0,0 +1,59 @@
+// 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.
+
+#include "net/base/test_root_certs.h"
+
+#include <string>
+
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "net/base/x509_certificate.h"
+
+namespace net {
+
+namespace {
+
+bool g_has_instance = false;
+
+base::LazyInstance<TestRootCerts,
+ base::LeakyLazyInstanceTraits<TestRootCerts> >
+ g_test_root_certs(base::LINKER_INITIALIZED);
+
+CertificateList LoadCertificates(const FilePath& filename) {
+ std::string raw_cert;
+ if (!file_util::ReadFileToString(filename, &raw_cert)) {
+ LOG(ERROR) << "Can't load certificate " << filename.value();
+ return CertificateList();
+ }
+
+ return X509Certificate::CreateCertificateListFromBytes(
+ raw_cert.data(), raw_cert.length(), X509Certificate::FORMAT_AUTO);
+}
+
+} // namespace
+
+// static
+TestRootCerts* TestRootCerts::GetInstance() {
+ return g_test_root_certs.Pointer();
+}
+
+bool TestRootCerts::HasInstance() {
+ return g_has_instance;
+}
+
+bool TestRootCerts::AddFromFile(const FilePath& file) {
+ CertificateList root_certs = LoadCertificates(file);
+ if (root_certs.empty() || root_certs.size() > 1)
+ return false;
+
+ return Add(root_certs.front());
+}
+
+TestRootCerts::TestRootCerts() {
+ Init();
+ g_has_instance = true;
+}
+
+} // namespace net
diff --git a/net/base/test_root_certs.h b/net/base/test_root_certs.h
new file mode 100644
index 0000000..3fa8fcf
--- /dev/null
+++ b/net/base/test_root_certs.h
@@ -0,0 +1,103 @@
+// 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.
+
+#ifndef NET_BASE_TEST_ROOT_CERTS_H_
+#define NET_BASE_TEST_ROOT_CERTS_H_
+#pragma once
+
+#include "base/lazy_instance.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <wincrypt.h>
+#elif defined(OS_MACOSX)
+#include <CoreFoundation/CFArray.h>
+#include <Security/SecTrust.h>
+#include "base/mac/scoped_cftyperef.h"
+#elif defined(USE_NSS)
+#include <list>
+#endif
+
+class FilePath;
+
+namespace net {
+
+class X509Certificate;
+
+// TestRootCerts is a helper class for unit tests that is used to
+// artificially mark a certificate as trusted, independent of the local
+// machine configuration.
+class TestRootCerts {
+ public:
+ // Obtains the Singleton instance to the trusted certificates.
+ static TestRootCerts* GetInstance();
+
+ // Returns true if an instance exists, without forcing an initialization.
+ static bool HasInstance();
+
+ // Marks |certificate| as trusted for X509Certificate::Verify(). Returns
+ // false if the certificate could not be marked trusted.
+ bool Add(X509Certificate* certificate);
+
+ // Reads a single certificate from |file| and marks it as trusted. Returns
+ // false if an error is encountered, such as being unable to read |file|
+ // or more than one certificate existing in |file|.
+ bool AddFromFile(const FilePath& file);
+
+ // Clears the trusted status of any certificates that were previously
+ // marked trusted via Add().
+ void Clear();
+
+ // Returns true if there are no certificates that have been marked trusted.
+ bool IsEmpty() const;
+
+#if defined(OS_MACOSX)
+ CFArrayRef temporary_roots() const { return temporary_roots_; }
+
+ // Modifies the root certificates of |trust_ref| to include the
+ // certificates stored in |temporary_roots_|. If IsEmpty() is true, this
+ // does not modify |trust_ref|.
+ OSStatus FixupSecTrustRef(SecTrustRef trust_ref) const;
+#elif defined(OS_WIN)
+ HCERTSTORE temporary_roots() const { return temporary_roots_; }
+
+ // Returns an HCERTCHAINENGINE suitable to be used for certificate
+ // validation routines, or NULL to indicate that the default system chain
+ // engine is appropriate. The caller is responsible for freeing the
+ // returned HCERTCHAINENGINE.
+ HCERTCHAINENGINE GetChainEngine() const;
+#endif
+
+ private:
+ friend struct base::DefaultLazyInstanceTraits<TestRootCerts>;
+
+ TestRootCerts();
+ ~TestRootCerts();
+
+ // Performs platform-dependent initialization.
+ void Init();
+
+#if defined(OS_MACOSX)
+ base::mac::ScopedCFTypeRef<CFMutableArrayRef> temporary_roots_;
+#elif defined(OS_WIN)
+ HCERTSTORE temporary_roots_;
+#elif defined(USE_NSS)
+ // It is necessary to maintain a cache of the original certificate trust
+ // settings, in order to restore them when Clear() is called.
+ class TrustEntry;
+ std::list<TrustEntry*> trust_cache_;
+#endif
+
+#if defined(OS_WIN) || defined(USE_OPENSSL)
+ // True if there are no temporarily trusted root certificates.
+ bool empty_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(TestRootCerts);
+};
+
+} // namespace net
+
+#endif // NET_BASE_TEST_ROOT_CERTS_H_
diff --git a/net/base/test_root_certs_mac.cc b/net/base/test_root_certs_mac.cc
new file mode 100644
index 0000000..6a8611a
--- /dev/null
+++ b/net/base/test_root_certs_mac.cc
@@ -0,0 +1,135 @@
+// 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.
+
+#include "net/base/test_root_certs.h"
+
+#include <Security/Security.h>
+
+#include "base/logging.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "net/base/x509_certificate.h"
+
+namespace net {
+
+namespace {
+
+#if !defined(MAC_OS_X_VERSION_10_6) || \
+ MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
+// Declared in <Security/SecBase.h> of the 10.6 SDK.
+enum {
+ errSecUnimplemented = -4,
+};
+#endif
+
+typedef OSStatus (*SecTrustSetAnchorCertificatesOnlyFuncPtr)(SecTrustRef,
+ Boolean);
+
+Boolean OurSecCertificateEqual(const void* value1, const void* value2) {
+ if (CFGetTypeID(value1) != SecCertificateGetTypeID() ||
+ CFGetTypeID(value2) != SecCertificateGetTypeID())
+ return CFEqual(value1, value2);
+ return X509Certificate::IsSameOSCert(
+ reinterpret_cast<SecCertificateRef>(const_cast<void*>(value1)),
+ reinterpret_cast<SecCertificateRef>(const_cast<void*>(value2)));
+}
+
+const void* RetainWrapper(CFAllocatorRef unused, const void* value) {
+ return CFRetain(value);
+}
+
+void ReleaseWrapper(CFAllocatorRef unused, const void* value) {
+ CFRelease(value);
+}
+
+// CFEqual prior to 10.6 only performed pointer checks on SecCertificateRefs,
+// rather than checking if they were the same (logical) certificate, so a
+// custom structure is used for the array callbacks.
+const CFArrayCallBacks kCertArrayCallbacks = {
+ 0, // version
+ RetainWrapper,
+ ReleaseWrapper,
+ CFCopyDescription,
+ OurSecCertificateEqual,
+};
+
+} // namespace
+
+bool TestRootCerts::Add(X509Certificate* certificate) {
+ if (CFArrayContainsValue(temporary_roots_,
+ CFRangeMake(0, CFArrayGetCount(temporary_roots_)),
+ certificate->os_cert_handle()))
+ return true;
+ CFArrayAppendValue(temporary_roots_, certificate->os_cert_handle());
+ return true;
+}
+
+void TestRootCerts::Clear() {
+ CFArrayRemoveAllValues(temporary_roots_);
+}
+
+bool TestRootCerts::IsEmpty() const {
+ return CFArrayGetCount(temporary_roots_) == 0;
+}
+
+OSStatus TestRootCerts::FixupSecTrustRef(SecTrustRef trust_ref) const {
+ if (IsEmpty())
+ return noErr;
+
+ CFBundleRef bundle =
+ CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security"));
+ SecTrustSetAnchorCertificatesOnlyFuncPtr set_anchor_certificates_only = NULL;
+ if (bundle) {
+ set_anchor_certificates_only =
+ reinterpret_cast<SecTrustSetAnchorCertificatesOnlyFuncPtr>(
+ CFBundleGetFunctionPointerForName(bundle,
+ CFSTR("SecTrustSetAnchorCertificatesOnly")));
+ }
+
+ OSStatus status = noErr;
+ if (set_anchor_certificates_only) {
+ // OS X 10.6 includes a function where the system trusts can be
+ // preserved while appending application trusts. This is preferable,
+ // because it preserves any user trust settings (explicit distrust),
+ // which the naive copy in 10.5 does not. Unfortunately, though the
+ // function pointer may be available, it is not always implemented. If it
+ // returns errSecUnimplemented, fall through to the 10.5 behaviour.
+ status = SecTrustSetAnchorCertificates(trust_ref, temporary_roots_);
+ if (status)
+ return status;
+ status = set_anchor_certificates_only(trust_ref, false);
+ if (status != errSecUnimplemented)
+ return status;
+
+ // Restore the original settings before falling back.
+ status = SecTrustSetAnchorCertificates(trust_ref, NULL);
+ if (status)
+ return status;
+ }
+
+ // On 10.5, the system certificates have to be copied and merged into
+ // the application trusts, and may override any user trust settings.
+ CFArrayRef system_roots = NULL;
+ status = SecTrustCopyAnchorCertificates(&system_roots);
+ if (status)
+ return status;
+
+ base::mac::ScopedCFTypeRef<CFArrayRef> scoped_system_roots(system_roots);
+ base::mac::ScopedCFTypeRef<CFMutableArrayRef> scoped_roots(
+ CFArrayCreateMutableCopy(kCFAllocatorDefault, 0,
+ scoped_system_roots));
+ DCHECK(scoped_roots.get());
+
+ CFArrayAppendArray(scoped_roots, temporary_roots_,
+ CFRangeMake(0, CFArrayGetCount(temporary_roots_)));
+ return SecTrustSetAnchorCertificates(trust_ref, scoped_roots);
+}
+
+TestRootCerts::~TestRootCerts() {}
+
+void TestRootCerts::Init() {
+ temporary_roots_.reset(CFArrayCreateMutable(kCFAllocatorDefault, 0,
+ &kCertArrayCallbacks));
+}
+
+} // namespace net
diff --git a/net/base/test_root_certs_nss.cc b/net/base/test_root_certs_nss.cc
new file mode 100644
index 0000000..ae5ff5c
--- /dev/null
+++ b/net/base/test_root_certs_nss.cc
@@ -0,0 +1,119 @@
+// 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.
+
+#include "net/base/test_root_certs.h"
+
+#include <cert.h>
+
+#include "base/logging.h"
+#include "base/nss_util.h"
+#include "base/stl_util-inl.h"
+#include "net/base/x509_certificate.h"
+
+namespace net {
+
+// TrustEntry is used to store the original CERTCertificate and CERTCertTrust
+// for a certificate whose trust status has been changed by the
+// TestRootCerts.
+class TestRootCerts::TrustEntry {
+ public:
+ // Creates a new TrustEntry by incrementing the reference to |certificate|
+ // and copying |trust|.
+ TrustEntry(CERTCertificate* certificate, CERTCertTrust trust);
+ ~TrustEntry();
+
+ CERTCertificate* certificate() const { return certificate_; }
+ CERTCertTrust trust() const { return trust_; }
+
+ private:
+ // The temporary root certificate.
+ CERTCertificate* certificate_;
+
+ // The original trust settings, before |certificate_| was manipulated to
+ // be a temporarily trusted root.
+ CERTCertTrust trust_;
+
+ DISALLOW_COPY_AND_ASSIGN(TrustEntry);
+};
+
+TestRootCerts::TrustEntry::TrustEntry(CERTCertificate* certificate,
+ CERTCertTrust trust)
+ : certificate_(CERT_DupCertificate(certificate)),
+ trust_(trust) {
+}
+
+TestRootCerts::TrustEntry::~TrustEntry() {
+ CERT_DestroyCertificate(certificate_);
+}
+
+bool TestRootCerts::Add(X509Certificate* certificate) {
+ // Preserve the original trust bits so that they can be restored when
+ // the certificate is removed.
+ CERTCertTrust original_trust;
+ SECStatus rv = CERT_GetCertTrust(certificate->os_cert_handle(),
+ &original_trust);
+ if (rv != SECSuccess) {
+ // CERT_GetCertTrust will fail if the certificate does not have any
+ // particular trust settings associated with it, and attempts to use
+ // |original_trust| later to restore the original trust settings will not
+ // cause the trust settings to be revoked. If the certificate has no
+ // particular trust settings associated with it, mark the certificate as
+ // a valid CA certificate with no specific trust.
+ rv = CERT_DecodeTrustString(&original_trust, "c,c,c");
+ }
+
+ // Change the trust bits to unconditionally trust this certificate.
+ CERTCertTrust new_trust;
+ rv = CERT_DecodeTrustString(&new_trust, "TCu,Cu,Tu");
+ if (rv != SECSuccess) {
+ LOG(ERROR) << "Cannot decode certificate trust string.";
+ return false;
+ }
+
+ rv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(),
+ certificate->os_cert_handle(),
+ &new_trust);
+ if (rv != SECSuccess) {
+ LOG(ERROR) << "Cannot change certificate trust.";
+ return false;
+ }
+
+ trust_cache_.push_back(new TrustEntry(certificate->os_cert_handle(),
+ original_trust));
+ return true;
+}
+
+void TestRootCerts::Clear() {
+ // Restore the certificate trusts to what they were originally, before
+ // Add() was called. Work from the rear first, since if a certificate was
+ // added twice, the second entry's original trust status will be that of
+ // the first entry, while the first entry contains the desired resultant
+ // status.
+ for (std::list<TrustEntry*>::reverse_iterator it = trust_cache_.rbegin();
+ it != trust_cache_.rend(); ++it) {
+ CERTCertTrust original_trust = (*it)->trust();
+ SECStatus rv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(),
+ (*it)->certificate(),
+ &original_trust);
+ // DCHECK(), rather than LOG(), as a failure to restore the original
+ // trust can cause flake or hard-to-trace errors in any unit tests that
+ // occur after Clear() has been called.
+ DCHECK_EQ(SECSuccess, rv) << "Cannot restore certificate trust.";
+ }
+ STLDeleteElements(&trust_cache_);
+}
+
+bool TestRootCerts::IsEmpty() const {
+ return trust_cache_.empty();
+}
+
+TestRootCerts::~TestRootCerts() {
+ Clear();
+}
+
+void TestRootCerts::Init() {
+ base::EnsureNSSInit();
+}
+
+} // namespace net
diff --git a/net/base/test_root_certs_openssl.cc b/net/base/test_root_certs_openssl.cc
new file mode 100644
index 0000000..8307703
--- /dev/null
+++ b/net/base/test_root_certs_openssl.cc
@@ -0,0 +1,51 @@
+// 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.
+
+#include "net/base/test_root_certs.h"
+
+#include <openssl/err.h>
+#include <openssl/x509v3.h>
+
+#include "base/logging.h"
+#include "base/openssl_util.h"
+#include "base/tracked.h"
+#include "net/base/x509_certificate.h"
+
+namespace net {
+
+bool TestRootCerts::Add(X509Certificate* certificate) {
+ if (!X509_STORE_add_cert(X509Certificate::cert_store(),
+ certificate->os_cert_handle())) {
+ unsigned long error_code = ERR_peek_error();
+ if (ERR_GET_LIB(error_code) != ERR_LIB_X509 ||
+ ERR_GET_REASON(error_code) != X509_R_CERT_ALREADY_IN_HASH_TABLE) {
+ base::ClearOpenSSLERRStack(FROM_HERE);
+ return false;
+ }
+ ERR_clear_error();
+ }
+
+ empty_ = false;
+ return true;
+}
+
+void TestRootCerts::Clear() {
+ if (empty_)
+ return;
+
+ X509Certificate::ResetCertStore();
+ empty_ = true;
+}
+
+bool TestRootCerts::IsEmpty() const {
+ return empty_;
+}
+
+TestRootCerts::~TestRootCerts() {}
+
+void TestRootCerts::Init() {
+ empty_ = true;
+}
+
+} // namespace net
diff --git a/net/base/test_root_certs_win.cc b/net/base/test_root_certs_win.cc
new file mode 100644
index 0000000..7862e40
--- /dev/null
+++ b/net/base/test_root_certs_win.cc
@@ -0,0 +1,206 @@
+// 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.
+
+#include "net/base/test_root_certs.h"
+
+#include <windows.h>
+#include <wincrypt.h>
+
+#include "base/basictypes.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "net/base/x509_certificate.h"
+
+namespace net {
+
+namespace {
+
+// Provides a CertDllOpenStoreProv callback provider function, to be called
+// by CertOpenStore when the CERT_STORE_PROV_SYSTEM_W store is opened. See
+// http://msdn.microsoft.com/en-us/library/aa376043(VS.85).aspx.
+BOOL WINAPI InterceptedOpenStoreW(LPCSTR store_provider,
+ DWORD encoding,
+ HCRYPTPROV crypt_provider,
+ DWORD flags,
+ const void* extra,
+ HCERTSTORE memory_store,
+ PCERT_STORE_PROV_INFO store_info);
+
+// CryptoAPIInjector is used to inject a store provider function for system
+// certificate stores before the one provided internally by Crypt32.dll.
+// Once injected, there is no way to remove, so every call to open a system
+// store will be redirected to the injected function.
+struct CryptoAPIInjector {
+ // The previous default function for opening system stores. For most
+ // configurations, this should point to Crypt32's internal
+ // I_CertDllOpenSystemStoreProvW function.
+ PFN_CERT_DLL_OPEN_STORE_PROV_FUNC original_function;
+
+ // The handle that CryptoAPI uses to ensure the DLL implementing
+ // |original_function| remains loaded in memory.
+ HCRYPTOIDFUNCADDR original_handle;
+
+ private:
+ friend struct base::DefaultLazyInstanceTraits<CryptoAPIInjector>;
+
+ CryptoAPIInjector()
+ : original_function(NULL),
+ original_handle(NULL) {
+ HCRYPTOIDFUNCSET registered_functions =
+ CryptInitOIDFunctionSet(CRYPT_OID_OPEN_STORE_PROV_FUNC, 0);
+
+ // Preserve the original handler function in |original_function|. If other
+ // functions are overridden, they will also need to be preserved.
+ BOOL ok = CryptGetOIDFunctionAddress(
+ registered_functions, 0, CERT_STORE_PROV_SYSTEM_W, 0,
+ reinterpret_cast<void**>(&original_function), &original_handle);
+ DCHECK(ok);
+
+ // For now, intercept only the numeric form of the system store
+ // function, CERT_STORE_PROV_SYSTEM_W (0x0A), which is what Crypt32
+ // functionality uses exclusively. Depending on the machine that tests
+ // are being run on, it may prove necessary to also intercept
+ // sz_CERT_STORE_PROV_SYSTEM_[A/W] and CERT_STORE_PROV_SYSTEM_A, based
+ // on whether or not any third-party CryptoAPI modules have been
+ // installed.
+ const CRYPT_OID_FUNC_ENTRY kFunctionToIntercept =
+ { CERT_STORE_PROV_SYSTEM_W, &InterceptedOpenStoreW };
+
+ // Inject kFunctionToIntercept at the front of the linked list that
+ // crypt32 uses when CertOpenStore is called, replacing the existing
+ // registered function.
+ ok = CryptInstallOIDFunctionAddress(NULL, 0,
+ CRYPT_OID_OPEN_STORE_PROV_FUNC, 1,
+ &kFunctionToIntercept,
+ CRYPT_INSTALL_OID_FUNC_BEFORE_FLAG);
+ DCHECK(ok);
+ }
+
+ // This is never called, because this object is intentionally leaked.
+ // Certificate verification happens on a non-joinable worker thread, which
+ // may still be running when ~AtExitManager is called, so the LazyInstance
+ // must be leaky.
+ ~CryptoAPIInjector() {
+ original_function = NULL;
+ CryptFreeOIDFunctionAddress(original_handle, NULL);
+ }
+};
+
+base::LazyInstance<CryptoAPIInjector,
+ base::LeakyLazyInstanceTraits<CryptoAPIInjector> >
+ g_capi_injector(base::LINKER_INITIALIZED);
+
+BOOL WINAPI InterceptedOpenStoreW(LPCSTR store_provider,
+ DWORD encoding,
+ HCRYPTPROV crypt_provider,
+ DWORD flags,
+ const void* store_name,
+ HCERTSTORE memory_store,
+ PCERT_STORE_PROV_INFO store_info) {
+ // If the high word is all zeroes, then |store_provider| is a numeric ID.
+ // Otherwise, it's a pointer to a null-terminated ASCII string. See the
+ // documentation for CryptGetOIDFunctionAddress for more information.
+ uint32 store_as_uint = reinterpret_cast<uint32>(store_provider);
+ if (store_as_uint > 0xFFFF || store_provider != CERT_STORE_PROV_SYSTEM_W ||
+ !g_capi_injector.Get().original_function)
+ return FALSE;
+
+ BOOL ok = g_capi_injector.Get().original_function(store_provider, encoding,
+ crypt_provider, flags,
+ store_name, memory_store,
+ store_info);
+ // Only the Root store should have certificates injected. If
+ // CERT_SYSTEM_STORE_RELOCATE_FLAG is set, then |store_name| points to a
+ // CERT_SYSTEM_STORE_RELOCATE_PARA structure, rather than a
+ // NULL-terminated wide string, so check before making a string
+ // comparison.
+ if (!ok || TestRootCerts::GetInstance()->IsEmpty() ||
+ (flags & CERT_SYSTEM_STORE_RELOCATE_FLAG) ||
+ lstrcmpiW(reinterpret_cast<LPCWSTR>(store_name), L"root"))
+ return ok;
+
+ // The result of CertOpenStore with CERT_STORE_PROV_SYSTEM_W is documented
+ // to be a collection store, and that appears to hold for |memory_store|.
+ // Attempting to add an individual certificate to |memory_store| causes
+ // the request to be forwarded to the first physical store in the
+ // collection that accepts modifications, which will cause a secure
+ // confirmation dialog to be displayed, confirming the user wishes to
+ // trust the certificate. However, appending a store to the collection
+ // will merely modify the temporary collection store, and will not persist
+ // any changes to the underlying physical store. When the |memory_store| is
+ // searched to see if a certificate is in the Root store, all the
+ // underlying stores in the collection will be searched, and any certificate
+ // in temporary_roots() will be found and seen as trusted.
+ return CertAddStoreToCollection(
+ memory_store, TestRootCerts::GetInstance()->temporary_roots(), 0, 0);
+}
+
+} // namespace
+
+bool TestRootCerts::Add(X509Certificate* certificate) {
+ // Ensure that the default CryptoAPI functionality has been intercepted.
+ // If a test certificate is never added, then no interception should
+ // happen.
+ g_capi_injector.Get();
+
+ BOOL ok = CertAddCertificateContextToStore(
+ temporary_roots_, certificate->os_cert_handle(),
+ CERT_STORE_ADD_NEW, NULL);
+ if (!ok) {
+ // If the certificate is already added, return successfully.
+ return GetLastError() == CRYPT_E_EXISTS;
+ }
+
+ empty_ = false;
+ return true;
+}
+
+void TestRootCerts::Clear() {
+ empty_ = true;
+
+ PCCERT_CONTEXT prev_cert = NULL;
+ while (prev_cert = CertEnumCertificatesInStore(temporary_roots_, NULL))
+ CertDeleteCertificateFromStore(prev_cert);
+}
+
+bool TestRootCerts::IsEmpty() const {
+ return empty_;
+}
+
+HCERTCHAINENGINE TestRootCerts::GetChainEngine() const {
+ if (IsEmpty())
+ return NULL; // Default chain engine will suffice.
+
+ // Each HCERTCHAINENGINE caches both the configured system stores and
+ // information about each chain that has been built. In order to ensure
+ // that changes to |temporary_roots_| are properly propagated and that the
+ // various caches are flushed, when at least one certificate is added,
+ // return a new chain engine for every call. Each chain engine creation
+ // should re-open the root store, ensuring the most recent changes are
+ // visible.
+ CERT_CHAIN_ENGINE_CONFIG engine_config = {
+ sizeof(engine_config)
+ };
+ engine_config.dwFlags =
+ CERT_CHAIN_ENABLE_CACHE_AUTO_UPDATE |
+ CERT_CHAIN_ENABLE_SHARE_STORE;
+ HCERTCHAINENGINE chain_engine = NULL;
+ BOOL ok = CertCreateCertificateChainEngine(&engine_config, &chain_engine);
+ DCHECK(ok);
+ return chain_engine;
+}
+
+TestRootCerts::~TestRootCerts() {
+ CertCloseStore(temporary_roots_, 0);
+}
+
+void TestRootCerts::Init() {
+ empty_ = true;
+ temporary_roots_ = CertOpenStore(
+ CERT_STORE_PROV_MEMORY, 0, NULL,
+ CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, NULL);
+ DCHECK(temporary_roots_);
+}
+
+} // namespace net
diff --git a/net/base/transport_security_state.cc b/net/base/transport_security_state.cc
index 598ed48..258d59f 100644
--- a/net/base/transport_security_state.cc
+++ b/net/base/transport_security_state.cc
@@ -20,6 +20,8 @@
namespace net {
+const long int TransportSecurityState::kMaxHSTSAgeSecs = 86400 * 365; // 1 year
+
TransportSecurityState::TransportSecurityState()
: delegate_(NULL) {
}
@@ -98,6 +100,24 @@ bool TransportSecurityState::IsEnabledForHost(DomainState* result,
return false;
}
+// MaxAgeToInt converts a string representation of a number of seconds into a
+// int. We use strtol in order to handle overflow correctly. The string may
+// contain an arbitary number which we should truncate correctly rather than
+// throwing a parse failure.
+static bool MaxAgeToInt(std::string::const_iterator begin,
+ std::string::const_iterator end,
+ int* result) {
+ const std::string s(begin, end);
+ char* endptr;
+ long int i = strtol(s.data(), &endptr, 10 /* base */);
+ if (*endptr || i < 0)
+ return false;
+ if (i > TransportSecurityState::kMaxHSTSAgeSecs)
+ i = TransportSecurityState::kMaxHSTSAgeSecs;
+ *result = i;
+ return true;
+}
+
// "Strict-Transport-Security" ":"
// "max-age" "=" delta-seconds [ ";" "includeSubDomains" ]
bool TransportSecurityState::ParseHeader(const std::string& value,
@@ -106,7 +126,7 @@ bool TransportSecurityState::ParseHeader(const std::string& value,
DCHECK(max_age);
DCHECK(include_subdomains);
- int max_age_candidate;
+ int max_age_candidate = 0;
enum ParserState {
START,
@@ -142,11 +162,9 @@ bool TransportSecurityState::ParseHeader(const std::string& value,
case AFTER_MAX_AGE_EQUALS:
if (IsAsciiWhitespace(*tokenizer.token_begin()))
continue;
- if (!base::StringToInt(tokenizer.token_begin(),
- tokenizer.token_end(),
- &max_age_candidate))
- return false;
- if (max_age_candidate < 0)
+ if (!MaxAgeToInt(tokenizer.token_begin(),
+ tokenizer.token_end(),
+ &max_age_candidate))
return false;
state = AFTER_MAX_AGE;
break;
@@ -411,8 +429,12 @@ bool TransportSecurityState::IsPreloadedSTS(
{19, true, "\015sunshinepress\003org"},
{21, false, "\003www\013noisebridge\003net"},
{10, false, "\004neg9\003org"},
+ {12, true, "\006riseup\003net"},
{11, false, "\006factor\002cc"},
- {19, true, "\015splendidbacon\003com"},
+ {22, false, "\007members\010mayfirst\003org"},
+ {22, false, "\007support\010mayfirst\003org"},
+ {17, false, "\002id\010mayfirst\003org"},
+ {20, false, "\005lists\010mayfirst\003org"},
};
static const size_t kNumPreloadedSTS = ARRAYSIZE_UNSAFE(kPreloadedSTS);
diff --git a/net/base/transport_security_state.h b/net/base/transport_security_state.h
index 49b44d7..fcd4e79 100644
--- a/net/base/transport_security_state.h
+++ b/net/base/transport_security_state.h
@@ -88,6 +88,9 @@ class TransportSecurityState :
bool Serialise(std::string* output);
bool Deserialise(const std::string& state, bool* dirty);
+ // The maximum number of seconds for which we'll cache an HSTS request.
+ static const long int kMaxHSTSAgeSecs;
+
private:
friend class base::RefCountedThreadSafe<TransportSecurityState>;
FRIEND_TEST_ALL_PREFIXES(TransportSecurityStateTest, IsPreloaded);
diff --git a/net/base/transport_security_state_unittest.cc b/net/base/transport_security_state_unittest.cc
index 126ca2b..3364bf1 100644
--- a/net/base/transport_security_state_unittest.cc
+++ b/net/base/transport_security_state_unittest.cc
@@ -116,18 +116,27 @@ TEST_F(TransportSecurityStateTest, ValidHeaders) {
EXPECT_TRUE(TransportSecurityState::ParseHeader(
"max-age=39408299 ;incLudesUbdOmains", &max_age, &include_subdomains));
- EXPECT_EQ(max_age, 39408299);
+ EXPECT_EQ(max_age,
+ std::min(TransportSecurityState::kMaxHSTSAgeSecs, 39408299l));
EXPECT_TRUE(include_subdomains);
EXPECT_TRUE(TransportSecurityState::ParseHeader(
"max-age=394082038 ; incLudesUbdOmains", &max_age, &include_subdomains));
- EXPECT_EQ(max_age, 394082038);
+ EXPECT_EQ(max_age,
+ std::min(TransportSecurityState::kMaxHSTSAgeSecs, 394082038l));
EXPECT_TRUE(include_subdomains);
EXPECT_TRUE(TransportSecurityState::ParseHeader(
" max-age=0 ; incLudesUbdOmains ", &max_age, &include_subdomains));
EXPECT_EQ(max_age, 0);
EXPECT_TRUE(include_subdomains);
+
+ EXPECT_TRUE(TransportSecurityState::ParseHeader(
+ " max-age=999999999999999999999999999999999999999999999 ;"
+ " incLudesUbdOmains ",
+ &max_age, &include_subdomains));
+ EXPECT_EQ(max_age, TransportSecurityState::kMaxHSTSAgeSecs);
+ EXPECT_TRUE(include_subdomains);
}
TEST_F(TransportSecurityStateTest, SimpleMatches) {
@@ -346,12 +355,17 @@ TEST_F(TransportSecurityStateTest, Preloaded) {
EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "neg9.org"));
EXPECT_FALSE(state->IsEnabledForHost(&domain_state, "www.neg9.org"));
+ EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "riseup.net"));
+ EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "foo.riseup.net"));
+
EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "factor.cc"));
EXPECT_FALSE(state->IsEnabledForHost(&domain_state, "www.factor.cc"));
- EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "splendidbacon.com"));
- EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "www.splendidbacon.com"));
- EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "foo.splendidbacon.com"));
+ EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "members.mayfirst.org"));
+ EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "support.mayfirst.org"));
+ EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "id.mayfirst.org"));
+ EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "lists.mayfirst.org"));
+ EXPECT_FALSE(state->IsEnabledForHost(&domain_state, "www.mayfirst.org"));
}
TEST_F(TransportSecurityStateTest, LongNames) {
diff --git a/net/base/winsock_init.cc b/net/base/winsock_init.cc
index ccaf01c..41810ef 100644
--- a/net/base/winsock_init.cc
+++ b/net/base/winsock_init.cc
@@ -6,8 +6,8 @@
#include "net/base/winsock_init.h"
+#include "base/lazy_instance.h"
#include "base/logging.h"
-#include "base/singleton.h"
namespace {
@@ -37,12 +37,15 @@ class WinsockInitSingleton {
}
};
+static base::LazyInstance<WinsockInitSingleton> g_winsock_init_singleton(
+ base::LINKER_INITIALIZED);
+
} // namespace
namespace net {
void EnsureWinsockInit() {
- Singleton<WinsockInitSingleton>::get();
+ g_winsock_init_singleton.Get();
}
} // namespace net
diff --git a/net/base/x509_cert_types.cc b/net/base/x509_cert_types.cc
index cdfbdaa..6beb3ec 100644
--- a/net/base/x509_cert_types.cc
+++ b/net/base/x509_cert_types.cc
@@ -6,9 +6,27 @@
#include "net/base/x509_certificate.h"
#include "base/logging.h"
+#include "base/string_number_conversions.h"
+#include "base/string_piece.h"
+#include "base/time.h"
namespace net {
+namespace {
+
+// Helper for ParseCertificateDate. |*field| must contain at least
+// |field_len| characters. |*field| will be advanced by |field_len| on exit.
+// |*ok| is set to false if there is an error in parsing the number, but left
+// untouched otherwise. Returns the parsed integer.
+int ParseIntAndAdvance(const char** field, size_t field_len, bool* ok) {
+ int result = 0;
+ *ok &= base::StringToInt(*field, *field + field_len, &result);
+ *field += field_len;
+ return result;
+}
+
+} // namespace
+
CertPrincipal::CertPrincipal() {
}
@@ -75,4 +93,34 @@ bool CertPolicy::HasDeniedCert() const {
return !denied_.empty();
}
+bool ParseCertificateDate(const base::StringPiece& raw_date,
+ CertDateFormat format,
+ base::Time* time) {
+ size_t year_length = format == CERT_DATE_FORMAT_UTC_TIME ? 2 : 4;
+
+ if (raw_date.length() < 11 + year_length)
+ return false;
+
+ const char* field = raw_date.data();
+ bool valid = true;
+ base::Time::Exploded exploded = {0};
+
+ exploded.year = ParseIntAndAdvance(&field, year_length, &valid);
+ exploded.month = ParseIntAndAdvance(&field, 2, &valid);
+ exploded.day_of_month = ParseIntAndAdvance(&field, 2, &valid);
+ exploded.hour = ParseIntAndAdvance(&field, 2, &valid);
+ exploded.minute = ParseIntAndAdvance(&field, 2, &valid);
+ exploded.second = ParseIntAndAdvance(&field, 2, &valid);
+ if (valid && year_length == 2)
+ exploded.year += exploded.year < 50 ? 2000 : 1900;
+
+ valid &= exploded.HasValidValues();
+
+ if (!valid)
+ return false;
+
+ *time = base::Time::FromUTCExploded(exploded);
+ return true;
+}
+
} // namespace net
diff --git a/net/base/x509_cert_types.h b/net/base/x509_cert_types.h
index f762e56..eb3ad60 100644
--- a/net/base/x509_cert_types.h
+++ b/net/base/x509_cert_types.h
@@ -18,6 +18,11 @@
#include <Security/x509defs.h>
#endif
+namespace base {
+class Time;
+class StringPiece;
+} // namespace base
+
namespace net {
class X509Certificate;
@@ -127,6 +132,23 @@ inline bool CSSMOIDEqual(const CSSM_OID* oid1, const CSSM_OID* oid2) {
}
#endif
+// A list of ASN.1 date/time formats that ParseCertificateDate() supports,
+// encoded in the canonical forms specified in RFC 2459/3280/5280.
+enum CertDateFormat {
+ // UTCTime: Format is YYMMDDHHMMSSZ
+ CERT_DATE_FORMAT_UTC_TIME,
+
+ // GeneralizedTime: Format is YYYYMMDDHHMMSSZ
+ CERT_DATE_FORMAT_GENERALIZED_TIME,
+};
+
+// Attempts to parse |raw_date|, an ASN.1 date/time string encoded as
+// |format|, and writes the result into |*time|. If an invalid date is
+// specified, or if parsing fails, returns false, and |*time| will not be
+// updated.
+bool ParseCertificateDate(const base::StringPiece& raw_date,
+ CertDateFormat format,
+ base::Time* time);
} // namespace net
#endif // NET_BASE_X509_CERT_TYPES_H_
diff --git a/net/base/x509_certificate.h b/net/base/x509_certificate.h
index 763bf9d..98375db 100644
--- a/net/base/x509_certificate.h
+++ b/net/base/x509_certificate.h
@@ -36,6 +36,10 @@ struct CERTCertificateStr;
class Pickle;
+namespace base {
+class RSAPrivateKey;
+} // namespace base
+
namespace net {
class CertVerifyResult;
@@ -148,6 +152,29 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> {
int length,
int format);
+ // Create a self-signed certificate containing the public key in |key|.
+ // Subject, serial number and validity period are given as parameters.
+ // The certificate is signed by the private key in |key|. The hashing
+ // algorithm for the signature is SHA-1.
+ //
+ // |subject| is a distinguished name defined in RFC4514.
+ //
+ // An example:
+ // CN=Michael Wong,O=FooBar Corporation,DC=foobar,DC=com
+ //
+ // SECURUITY WARNING
+ //
+ // Using self-signed certificates has the following security risks:
+ // 1. Encryption without authentication and thus vulnerable to
+ // man-in-the-middle attacks.
+ // 2. Self-signed certificates cannot be revoked.
+ //
+ // Use this certificate only after the above risks are acknowledged.
+ static X509Certificate* CreateSelfSigned(base::RSAPrivateKey* key,
+ const std::string& subject,
+ uint32 serial_number,
+ base::TimeDelta valid_duration);
+
// Creates a X509Certificate from the ground up. Used by tests that simulate
// SSL connections.
X509Certificate(const std::string& subject, const std::string& issuer,
@@ -220,7 +247,7 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> {
static bool GetSSLClientCertificates(
const std::string& server_domain,
const std::vector<CertPrincipal>& valid_issuers,
- std::vector<scoped_refptr<X509Certificate> >* certs);
+ CertificateList* certs);
// Creates the chain of certs to use for this client identity cert.
CFArrayRef CreateClientCertificateChain() const;
@@ -266,6 +293,11 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> {
int flags,
CertVerifyResult* verify_result) const;
+ // This method returns the DER encoded certificate.
+ // If the return value is true then the DER encoded certificate is available.
+ // The content of the DER encoded certificate is written to |encoded|.
+ bool GetDEREncoded(std::string* encoded);
+
OSCertHandle os_cert_handle() const { return cert_handle_; }
// Returns true if two OSCertHandles refer to identical certificates.
@@ -289,6 +321,7 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> {
private:
friend class base::RefCountedThreadSafe<X509Certificate>;
+ friend class TestRootCerts; // For unit tests
FRIEND_TEST_ALL_PREFIXES(X509CertificateTest, Cache);
FRIEND_TEST_ALL_PREFIXES(X509CertificateTest, IntermediateCertificates);
@@ -308,6 +341,12 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> {
#endif
bool VerifyEV() const;
+#if defined(USE_OPENSSL)
+ // Resets the store returned by cert_store() to default state. Used by
+ // TestRootCerts to undo modifications.
+ static void ResetCertStore();
+#endif
+
// Calculates the SHA-1 fingerprint of the certificate. Returns an empty
// (all zero) fingerprint on failure.
static SHA1Fingerprint CalculateFingerprint(OSCertHandle cert_handle);
diff --git a/net/base/x509_certificate_mac.cc b/net/base/x509_certificate_mac.cc
index 5a5d457..fd965cb 100644
--- a/net/base/x509_certificate_mac.cc
+++ b/net/base/x509_certificate_mac.cc
@@ -17,6 +17,7 @@
#include "net/base/cert_status_flags.h"
#include "net/base/cert_verify_result.h"
#include "net/base/net_errors.h"
+#include "net/base/test_root_certs.h"
using base::mac::ScopedCFTypeRef;
using base::Time;
@@ -25,62 +26,6 @@ namespace net {
namespace {
-class MacTrustedCertificates {
- public:
- // Sets the trusted root certificate used by tests. Call with |cert| set
- // to NULL to clear the test certificate.
- void SetTestCertificate(X509Certificate* cert) {
- AutoLock lock(lock_);
- test_certificate_ = cert;
- }
-
- // Returns an array containing the trusted certificates for use with
- // SecTrustSetAnchorCertificates(). Returns NULL if the system-supplied
- // list of trust anchors is acceptable (that is, there is not test
- // certificate available). Ownership follows the Create Rule (caller
- // is responsible for calling CFRelease on the non-NULL result).
- CFArrayRef CopyTrustedCertificateArray() {
- AutoLock lock(lock_);
-
- if (!test_certificate_)
- return NULL;
-
- // Failure to copy the anchor certificates or add the test certificate
- // is non-fatal; SecTrustEvaluate() will use the system anchors instead.
- CFArrayRef anchor_array;
- OSStatus status = SecTrustCopyAnchorCertificates(&anchor_array);
- if (status)
- return NULL;
- ScopedCFTypeRef<CFArrayRef> scoped_anchor_array(anchor_array);
- CFMutableArrayRef merged_array = CFArrayCreateMutableCopy(
- kCFAllocatorDefault, 0, anchor_array);
- if (!merged_array)
- return NULL;
- CFArrayAppendValue(merged_array, test_certificate_->os_cert_handle());
-
- return merged_array;
- }
- private:
- friend struct base::DefaultLazyInstanceTraits<MacTrustedCertificates>;
-
- // Obtain an instance of MacTrustedCertificates via the singleton
- // interface.
- MacTrustedCertificates() : test_certificate_(NULL) { }
-
- // An X509Certificate object that may be appended to the list of
- // system trusted anchors.
- scoped_refptr<X509Certificate> test_certificate_;
-
- // The trusted cache may be accessed from multiple threads.
- mutable Lock lock_;
-
- DISALLOW_COPY_AND_ASSIGN(MacTrustedCertificates);
-};
-
-base::LazyInstance<MacTrustedCertificates,
- base::LeakyLazyInstanceTraits<MacTrustedCertificates> >
- g_mac_trusted_certificates(base::LINKER_INITIALIZED);
-
typedef OSStatus (*SecTrustCopyExtendedResultFuncPtr)(SecTrustRef,
CFDictionaryRef*);
@@ -222,9 +167,10 @@ void GetCertGeneralNamesForOID(X509Certificate::OSCertHandle cert_handle,
for (size_t field = 0; field < fields.num_of_fields; ++field) {
if (CSSMOIDEqual(&fields.fields[field].FieldOid, &oid)) {
CSSM_X509_EXTENSION_PTR cssm_ext =
- (CSSM_X509_EXTENSION_PTR)fields.fields[field].FieldValue.Data;
+ reinterpret_cast<CSSM_X509_EXTENSION_PTR>(
+ fields.fields[field].FieldValue.Data);
CE_GeneralNames* alt_name =
- (CE_GeneralNames*) cssm_ext->value.parsedValue;
+ reinterpret_cast<CE_GeneralNames*>(cssm_ext->value.parsedValue);
for (size_t name = 0; name < alt_name->numNames; ++name) {
const CE_GeneralName& name_struct = alt_name->generalName[name];
@@ -235,10 +181,9 @@ void GetCertGeneralNamesForOID(X509Certificate::OSCertHandle cert_handle,
// CE_GeneralNameType for more information.
if (name_struct.nameType == name_type) {
const CSSM_DATA& name_data = name_struct.name;
- std::string value =
- std::string(reinterpret_cast<std::string::value_type*>
- (name_data.Data),
- name_data.Length);
+ std::string value = std::string(
+ reinterpret_cast<const char*>(name_data.Data),
+ name_data.Length);
result->push_back(value);
}
}
@@ -257,43 +202,23 @@ void GetCertDateForOID(X509Certificate::OSCertHandle cert_handle,
for (size_t field = 0; field < fields.num_of_fields; ++field) {
if (CSSMOIDEqual(&fields.fields[field].FieldOid, &oid)) {
- CSSM_X509_TIME* x509_time =
- reinterpret_cast<CSSM_X509_TIME *>
- (fields.fields[field].FieldValue.Data);
- std::string time_string =
- std::string(reinterpret_cast<std::string::value_type*>
- (x509_time->time.Data),
- x509_time->time.Length);
-
- DCHECK(x509_time->timeType == BER_TAG_UTC_TIME ||
- x509_time->timeType == BER_TAG_GENERALIZED_TIME);
-
- struct tm time;
- const char* parse_string;
- if (x509_time->timeType == BER_TAG_UTC_TIME)
- parse_string = "%y%m%d%H%M%SZ";
- else if (x509_time->timeType == BER_TAG_GENERALIZED_TIME)
- parse_string = "%y%m%d%H%M%SZ";
- else {
- // Those are the only two BER tags for time; if neither are used then
- // this is a rather broken cert.
+ CSSM_X509_TIME* x509_time = reinterpret_cast<CSSM_X509_TIME*>(
+ fields.fields[field].FieldValue.Data);
+ if (x509_time->timeType != BER_TAG_UTC_TIME &&
+ x509_time->timeType != BER_TAG_GENERALIZED_TIME) {
+ LOG(ERROR) << "Unsupported date/time format "
+ << x509_time->timeType;
return;
}
- strptime(time_string.c_str(), parse_string, &time);
-
- Time::Exploded exploded;
- exploded.year = time.tm_year + 1900;
- exploded.month = time.tm_mon + 1;
- exploded.day_of_week = time.tm_wday;
- exploded.day_of_month = time.tm_mday;
- exploded.hour = time.tm_hour;
- exploded.minute = time.tm_min;
- exploded.second = time.tm_sec;
- exploded.millisecond = 0;
-
- *result = Time::FromUTCExploded(exploded);
- break;
+ base::StringPiece time_string(
+ reinterpret_cast<const char*>(x509_time->time.Data),
+ x509_time->time.Length);
+ CertDateFormat format = x509_time->timeType == BER_TAG_UTC_TIME ?
+ CERT_DATE_FORMAT_UTC_TIME : CERT_DATE_FORMAT_GENERALIZED_TIME;
+ if (!ParseCertificateDate(time_string, format, result))
+ LOG(ERROR) << "Invalid certificate date/time " << time_string;
+ return;
}
}
}
@@ -334,7 +259,8 @@ OSStatus CreatePolicy(const CSSM_OID* policy_OID,
// Caller is responsible for releasing the value stored into *out_cert_chain.
OSStatus CopyCertChain(SecCertificateRef cert_handle,
CFArrayRef* out_cert_chain) {
- DCHECK(cert_handle && out_cert_chain);
+ DCHECK(cert_handle);
+ DCHECK(out_cert_chain);
// Create an SSL policy ref configured for client cert evaluation.
SecPolicyRef ssl_policy;
OSStatus result = X509Certificate::CreateSSLClientPolicy(&ssl_policy);
@@ -343,9 +269,9 @@ OSStatus CopyCertChain(SecCertificateRef cert_handle,
ScopedCFTypeRef<SecPolicyRef> scoped_ssl_policy(ssl_policy);
// Create a SecTrustRef.
- ScopedCFTypeRef<CFArrayRef> input_certs(
- CFArrayCreate(NULL, (const void**)&cert_handle, 1,
- &kCFTypeArrayCallBacks));
+ ScopedCFTypeRef<CFArrayRef> input_certs(CFArrayCreate(
+ NULL, const_cast<const void**>(reinterpret_cast<void**>(&cert_handle)),
+ 1, &kCFTypeArrayCallBacks));
SecTrustRef trust_ref = NULL;
result = SecTrustCreateWithCertificates(input_certs, ssl_policy, &trust_ref);
if (result)
@@ -400,8 +326,8 @@ void AddCertificatesFromBytes(const char* data, size_t length,
X509Certificate::OSCertHandles* output) {
SecExternalFormat input_format = format;
ScopedCFTypeRef<CFDataRef> local_data(CFDataCreateWithBytesNoCopy(
- kCFAllocatorDefault, reinterpret_cast<const UInt8*>(data),
- length, kCFAllocatorNull));
+ kCFAllocatorDefault, reinterpret_cast<const UInt8*>(data), length,
+ kCFAllocatorNull));
CFArrayRef items = NULL;
OSStatus status = SecKeychainItemImport(local_data, NULL, &input_format,
@@ -445,20 +371,15 @@ void AddCertificatesFromBytes(const char* data, size_t length,
} // namespace
-void SetMacTestCertificate(X509Certificate* cert) {
- g_mac_trusted_certificates.Get().SetTestCertificate(cert);
-}
-
void X509Certificate::Initialize() {
const CSSM_X509_NAME* name;
OSStatus status = SecCertificateGetSubject(cert_handle_, &name);
- if (!status) {
+ if (!status)
subject_.Parse(name);
- }
+
status = SecCertificateGetIssuer(cert_handle_, &name);
- if (!status) {
+ if (!status)
issuer_.Parse(name);
- }
GetCertDateForOID(cert_handle_, CSSMOID_X509V1ValidityNotBefore,
&valid_start_);
@@ -479,6 +400,16 @@ X509Certificate* X509Certificate::CreateFromPickle(const Pickle& pickle,
return CreateFromBytes(data, length);
}
+// static
+X509Certificate* X509Certificate::CreateSelfSigned(
+ base::RSAPrivateKey* key,
+ const std::string& subject,
+ uint32 serial_number,
+ base::TimeDelta valid_duration) {
+ // TODO(port): Implement.
+ return NULL;
+}
+
void X509Certificate::Persist(Pickle* pickle) {
CSSM_DATA cert_data;
OSStatus status = SecCertificateGetData(cert_handle_, &cert_data);
@@ -548,13 +479,8 @@ int X509Certificate::Verify(const std::string& hostname, int flags,
return NetErrorFromOSStatus(status);
ScopedCFTypeRef<SecTrustRef> scoped_trust_ref(trust_ref);
- // Set the trusted anchor certificates for the SecTrustRef by merging the
- // system trust anchors and the test root certificate.
- CFArrayRef anchor_array =
- g_mac_trusted_certificates.Get().CopyTrustedCertificateArray();
- ScopedCFTypeRef<CFArrayRef> scoped_anchor_array(anchor_array);
- if (anchor_array) {
- status = SecTrustSetAnchorCertificates(trust_ref, anchor_array);
+ if (TestRootCerts::HasInstance()) {
+ status = TestRootCerts::GetInstance()->FixupSecTrustRef(trust_ref);
if (status)
return NetErrorFromOSStatus(status);
}
@@ -659,9 +585,8 @@ int X509Certificate::Verify(const std::string& hostname, int flags,
if (cert_status == CERT_STATUS_COMMON_NAME_INVALID) {
std::vector<std::string> names;
GetDNSNames(&names);
- if (OverrideHostnameMismatch(hostname, &names)) {
+ if (OverrideHostnameMismatch(hostname, &names))
cert_status = 0;
- }
}
verify_result->cert_status |= cert_status;
}
@@ -682,9 +607,8 @@ int X509Certificate::Verify(const std::string& hostname, int flags,
if (status)
return NetErrorFromOSStatus(status);
verify_result->cert_status |= CertStatusFromOSStatus(cssm_result);
- if (!verify_result->cert_status) {
+ if (!verify_result->cert_status)
verify_result->cert_status |= CERT_STATUS_INVALID;
- }
break;
}
@@ -727,6 +651,17 @@ int X509Certificate::Verify(const std::string& hostname, int flags,
return OK;
}
+bool X509Certificate::GetDEREncoded(std::string* encoded) {
+ encoded->clear();
+ CSSM_DATA der_data;
+ if(SecCertificateGetData(cert_handle_, &der_data) == noErr) {
+ encoded->append(reinterpret_cast<char*>(der_data.Data),
+ der_data.Length);
+ return true;
+ }
+ return false;
+}
+
bool X509Certificate::VerifyEV() const {
// We don't call this private method, but we do need to implement it because
// it's defined in x509_certificate.h. We perform EV checking in the
@@ -818,8 +753,8 @@ SHA1Fingerprint X509Certificate::CalculateFingerprint(
if (status)
return sha1;
- DCHECK(NULL != cert_data.Data);
- DCHECK(0 != cert_data.Length);
+ DCHECK(cert_data.Data);
+ DCHECK_NE(cert_data.Length, 0U);
CC_SHA1(cert_data.Data, cert_data.Length, sha1.data);
@@ -870,7 +805,7 @@ bool X509Certificate::IsIssuedBy(
CFArrayRef cert_chain = NULL;
OSStatus result;
result = CopyCertChain(os_cert_handle(), &cert_chain);
- if (result != noErr)
+ if (result)
return false;
ScopedCFTypeRef<CFArrayRef> scoped_cert_chain(cert_chain);
@@ -906,20 +841,22 @@ OSStatus X509Certificate::CreateSSLClientPolicy(SecPolicyRef* out_policy) {
}
// static
-bool X509Certificate::GetSSLClientCertificates (
+bool X509Certificate::GetSSLClientCertificates(
const std::string& server_domain,
const std::vector<CertPrincipal>& valid_issuers,
- std::vector<scoped_refptr<X509Certificate> >* certs) {
+ CertificateList* certs) {
ScopedCFTypeRef<SecIdentityRef> preferred_identity;
if (!server_domain.empty()) {
// See if there's an identity preference for this domain:
ScopedCFTypeRef<CFStringRef> domain_str(
base::SysUTF8ToCFStringRef("https://" + server_domain));
SecIdentityRef identity = NULL;
- if (SecIdentityCopyPreference(domain_str,
- 0,
- NULL, // validIssuers argument is ignored :(
- &identity) == noErr)
+ // While SecIdentityCopyPreferences appears to take a list of CA issuers
+ // to restrict the identity search to, within Security.framework the
+ // argument is ignored and filtering unimplemented. See
+ // SecIdentity.cpp in libsecurity_keychain, specifically
+ // _SecIdentityCopyPreferenceMatchingName().
+ if (SecIdentityCopyPreference(domain_str, 0, NULL, &identity) == noErr)
preferred_identity.reset(identity);
}
@@ -997,8 +934,10 @@ CFArrayRef X509Certificate::CreateClientCertificateChain() const {
CFArrayRef cert_chain = NULL;
result = CopyCertChain(cert_handle_, &cert_chain);
- if (result)
- goto exit;
+ if (result) {
+ LOG(ERROR) << "CreateIdentityCertificateChain error " << result;
+ return chain.release();
+ }
// Append the intermediate certs from SecTrust to the result array:
if (cert_chain) {
@@ -1010,9 +949,7 @@ CFArrayRef X509Certificate::CreateClientCertificateChain() const {
}
CFRelease(cert_chain);
}
-exit:
- if (result)
- LOG(ERROR) << "CreateIdentityCertificateChain error " << result;
+
return chain.release();
}
diff --git a/net/base/x509_certificate_nss.cc b/net/base/x509_certificate_nss.cc
index 5061238..05e736c 100644
--- a/net/base/x509_certificate_nss.cc
+++ b/net/base/x509_certificate_nss.cc
@@ -5,6 +5,8 @@
#include "net/base/x509_certificate.h"
#include <cert.h>
+#include <cryptohi.h>
+#include <keyhi.h>
#include <nss.h>
#include <pk11pub.h>
#include <prerror.h>
@@ -14,6 +16,7 @@
#include <sechash.h>
#include <sslerr.h>
+#include "base/crypto/rsa_private_key.h"
#include "base/logging.h"
#include "base/pickle.h"
#include "base/scoped_ptr.h"
@@ -604,6 +607,108 @@ X509Certificate* X509Certificate::CreateFromPickle(const Pickle& pickle,
return CreateFromBytes(data, length);
}
+// static
+X509Certificate* X509Certificate::CreateSelfSigned(
+ base::RSAPrivateKey* key,
+ const std::string& subject,
+ uint32 serial_number,
+ base::TimeDelta valid_duration) {
+ DCHECK(key);
+
+ // Create info about public key.
+ CERTSubjectPublicKeyInfo* spki =
+ SECKEY_CreateSubjectPublicKeyInfo(key->public_key());
+ if (!spki)
+ return NULL;
+
+ // Create the certificate request.
+ CERTName* subject_name =
+ CERT_AsciiToName(const_cast<char*>(subject.c_str()));
+ CERTCertificateRequest* cert_request =
+ CERT_CreateCertificateRequest(subject_name, spki, NULL);
+ SECKEY_DestroySubjectPublicKeyInfo(spki);
+
+ if (!cert_request) {
+ PRErrorCode prerr = PR_GetError();
+ LOG(ERROR) << "Failed to create certificate request: " << prerr;
+ CERT_DestroyName(subject_name);
+ return NULL;
+ }
+
+ PRTime now = PR_Now();
+ PRTime not_after = now + valid_duration.InMicroseconds();
+
+ // Note that the time is now in micro-second unit.
+ CERTValidity* validity = CERT_CreateValidity(now, not_after);
+ CERTCertificate* cert = CERT_CreateCertificate(serial_number, subject_name,
+ validity, cert_request);
+ if (!cert) {
+ PRErrorCode prerr = PR_GetError();
+ LOG(ERROR) << "Failed to create certificate: " << prerr;
+ }
+
+ // Cleanup for resources used to generate the cert.
+ CERT_DestroyName(subject_name);
+ CERT_DestroyValidity(validity);
+ CERT_DestroyCertificateRequest(cert_request);
+
+ // Sign the cert here. The logic of this method references SignCert() in NSS
+ // utility certutil: http://mxr.mozilla.org/security/ident?i=SignCert.
+
+ // |arena| is used to encode the cert.
+ PRArenaPool* arena = cert->arena;
+ SECOidTag algo_id = SEC_GetSignatureAlgorithmOidTag(key->key()->keyType,
+ SEC_OID_SHA1);
+ if (algo_id == SEC_OID_UNKNOWN) {
+ CERT_DestroyCertificate(cert);
+ return NULL;
+ }
+
+ SECStatus rv = SECOID_SetAlgorithmID(arena, &cert->signature, algo_id, 0);
+ if (rv != SECSuccess) {
+ CERT_DestroyCertificate(cert);
+ return NULL;
+ }
+
+ // Generate a cert of version 3.
+ *(cert->version.data) = 2;
+ cert->version.len = 1;
+
+ SECItem der;
+ der.len = 0;
+ der.data = NULL;
+
+ // Use ASN1 DER to encode the cert.
+ void* encode_result = SEC_ASN1EncodeItem(
+ arena, &der, cert, SEC_ASN1_GET(CERT_CertificateTemplate));
+ if (!encode_result) {
+ CERT_DestroyCertificate(cert);
+ return NULL;
+ }
+
+ // Allocate space to contain the signed cert.
+ SECItem* result = SECITEM_AllocItem(arena, NULL, 0);
+ if (!result) {
+ CERT_DestroyCertificate(cert);
+ return NULL;
+ }
+
+ // Sign the ASN1 encoded cert and save it to |result|.
+ rv = SEC_DerSignData(arena, result, der.data, der.len, key->key(), algo_id);
+ if (rv != SECSuccess) {
+ CERT_DestroyCertificate(cert);
+ return NULL;
+ }
+
+ // Save the signed result to the cert.
+ cert->derCert = *result;
+
+ X509Certificate* x509_cert =
+ CreateFromHandle(cert, SOURCE_LONE_CERT_IMPORT, OSCertHandles());
+ CERT_DestroyCertificate(cert);
+ return x509_cert;
+}
+
void X509Certificate::Persist(Pickle* pickle) {
pickle->WriteData(reinterpret_cast<const char*>(cert_handle_->derCert.data),
cert_handle_->derCert.len);
@@ -724,6 +829,15 @@ bool X509Certificate::VerifyEV() const {
return true;
}
+bool X509Certificate::GetDEREncoded(std::string* encoded) {
+ if (!cert_handle_->derCert.len)
+ return false;
+ encoded->clear();
+ encoded->append(reinterpret_cast<char*>(cert_handle_->derCert.data),
+ cert_handle_->derCert.len);
+ return true;
+}
+
// static
bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a,
X509Certificate::OSCertHandle b) {
diff --git a/net/base/x509_certificate_openssl.cc b/net/base/x509_certificate_openssl.cc
index 5b2d365..4c339fc 100644
--- a/net/base/x509_certificate_openssl.cc
+++ b/net/base/x509_certificate_openssl.cc
@@ -206,7 +206,7 @@ void DERCache_free(void* parent, void* ptr, CRYPTO_EX_DATA* ad, int idx,
class X509InitSingleton {
public:
- static X509InitSingleton* Get() {
+ static X509InitSingleton* GetInstance() {
// We allow the X509 store to leak, because it is used from a non-joinable
// worker that is not stopped on shutdown, hence may still be using
// OpenSSL library after the AtExit runner has completed.
@@ -216,16 +216,20 @@ class X509InitSingleton {
int der_cache_ex_index() const { return der_cache_ex_index_; }
X509_STORE* store() const { return store_.get(); }
+ void ResetCertStore() {
+ store_.reset(X509_STORE_new());
+ DCHECK(store_.get());
+ X509_STORE_set_default_paths(store_.get());
+ // TODO(joth): Enable CRL (see X509_STORE_set_flags(X509_V_FLAG_CRL_CHECK)).
+ }
+
private:
friend struct DefaultSingletonTraits<X509InitSingleton>;
- X509InitSingleton()
- : der_cache_ex_index_((base::EnsureOpenSSLInit(),
- X509_get_ex_new_index(0, 0, 0, 0,
- DERCache_free))),
- store_(X509_STORE_new()) {
+ X509InitSingleton() {
+ base::EnsureOpenSSLInit();
+ der_cache_ex_index_ = X509_get_ex_new_index(0, 0, 0, 0, DERCache_free);
DCHECK_NE(der_cache_ex_index_, -1);
- X509_STORE_set_default_paths(store_.get());
- // TODO(joth): Enable CRL (see X509_STORE_set_flags(X509_V_FLAG_CRL_CHECK)).
+ ResetCertStore();
}
int der_cache_ex_index_;
@@ -259,7 +263,8 @@ DERCache* SetDERCache(X509Certificate::OSCertHandle cert,
// not free it).
bool GetDERAndCacheIfNeeded(X509Certificate::OSCertHandle cert,
DERCache* der_cache) {
- int x509_der_cache_index = X509InitSingleton::Get()->der_cache_ex_index();
+ int x509_der_cache_index =
+ X509InitSingleton::GetInstance()->der_cache_ex_index();
// Re-encoding the DER data via i2d_X509 is an expensive operation, but it's
// necessary for comparing two certificates. We re-encode at most once per
@@ -311,6 +316,11 @@ void X509Certificate::Initialize() {
nxou::ParseDate(X509_get_notAfter(cert_handle_), &valid_expiry_);
}
+// static
+void X509Certificate::ResetCertStore() {
+ X509InitSingleton::GetInstance()->ResetCertStore();
+}
+
SHA1Fingerprint X509Certificate::CalculateFingerprint(OSCertHandle cert) {
SHA1Fingerprint sha1;
unsigned int sha1_size = static_cast<unsigned int>(sizeof(sha1.data));
@@ -372,6 +382,16 @@ X509Certificate* X509Certificate::CreateFromPickle(const Pickle& pickle,
return CreateFromBytes(data, length);
}
+// static
+X509Certificate* X509Certificate::CreateSelfSigned(
+ base::RSAPrivateKey* key,
+ const std::string& subject,
+ uint32 serial_number,
+ base::TimeDelta valid_duration) {
+ // TODO(port): Implement.
+ return NULL;
+}
+
void X509Certificate::Persist(Pickle* pickle) {
DERCache der_cache;
if (!GetDERAndCacheIfNeeded(cert_handle_, &der_cache))
@@ -392,7 +412,7 @@ void X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const {
// static
X509_STORE* X509Certificate::cert_store() {
- return X509InitSingleton::Get()->store();
+ return X509InitSingleton::GetInstance()->store();
}
#ifndef ANDROID
@@ -426,19 +446,26 @@ int X509Certificate::Verify(const std::string& hostname,
cert_handle_, intermediates.get());
CHECK_EQ(1, rv);
- if (X509_verify_cert(ctx.get()) == 1) {
- return OK;
+ if (X509_verify_cert(ctx.get()) != 1) {
+ int x509_error = X509_STORE_CTX_get_error(ctx.get());
+ int cert_status = MapCertErrorToCertStatus(x509_error);
+ LOG(ERROR) << "X509 Verification error "
+ << X509_verify_cert_error_string(x509_error)
+ << " : " << x509_error
+ << " : " << X509_STORE_CTX_get_error_depth(ctx.get())
+ << " : " << cert_status;
+ verify_result->cert_status |= cert_status;
}
- int x509_error = X509_STORE_CTX_get_error(ctx.get());
- int cert_status = MapCertErrorToCertStatus(x509_error);
- LOG(ERROR) << "X509 Verification error "
- << X509_verify_cert_error_string(x509_error)
- << " : " << x509_error
- << " : " << X509_STORE_CTX_get_error_depth(ctx.get())
- << " : " << cert_status;
- verify_result->cert_status |= cert_status;
- return MapCertStatusToNetError(verify_result->cert_status);
+ if (IsCertStatusError(verify_result->cert_status))
+ return MapCertStatusToNetError(verify_result->cert_status);
+
+ return OK;
+}
+
+bool X509Certificate::GetDEREncoded(std::string* encoded) {
+ // TODO(port): Implement.
+ return false;
}
#endif
diff --git a/net/base/x509_certificate_unittest.cc b/net/base/x509_certificate_unittest.cc
index 31173e4..dba5ef3 100644
--- a/net/base/x509_certificate_unittest.cc
+++ b/net/base/x509_certificate_unittest.cc
@@ -1,7 +1,8 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// 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.
+#include "base/crypto/rsa_private_key.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/path_service.h"
@@ -11,6 +12,7 @@
#include "net/base/cert_verify_result.h"
#include "net/base/net_errors.h"
#include "net/base/test_certificate_data.h"
+#include "net/base/test_root_certs.h"
#include "net/base/x509_certificate.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -161,30 +163,6 @@ const CertificateFormatTestData FormatTestData[] = {
NULL, } },
};
-// Returns a FilePath object representing the src/net/data/ssl/certificates
-// directory in the source tree.
-FilePath GetTestCertsDirectory() {
- FilePath certs_dir;
- PathService::Get(base::DIR_SOURCE_ROOT, &certs_dir);
- certs_dir = certs_dir.AppendASCII("net");
- certs_dir = certs_dir.AppendASCII("data");
- certs_dir = certs_dir.AppendASCII("ssl");
- certs_dir = certs_dir.AppendASCII("certificates");
- return certs_dir;
-}
-
-// Imports a certificate file in the src/net/data/ssl/certificates directory.
-// certs_dir represents the test certificates directory. cert_file is the
-// name of the certificate file.
-X509Certificate* ImportCertFromFile(const FilePath& certs_dir,
- const std::string& cert_file) {
- FilePath cert_path = certs_dir.AppendASCII(cert_file);
- std::string cert_data;
- if (!file_util::ReadFileToString(cert_path, &cert_data))
- return NULL;
- return X509Certificate::CreateFromBytes(cert_data.data(), cert_data.size());
-}
-
CertificateList CreateCertificateListFromFile(
const FilePath& certs_dir,
const std::string& cert_file,
@@ -427,13 +405,8 @@ TEST(X509CertificateTest, UnoSoftCertParsing) {
EXPECT_NE(0, verify_result.cert_status & CERT_STATUS_AUTHORITY_INVALID);
}
-#if defined(USE_NSS) || defined(USE_OPENSSL)
// A regression test for http://crbug.com/31497.
// This certificate will expire on 2012-04-08.
-// TODO(wtc): we can't run this test on Mac because MacTrustedCertificates
-// can hold only one additional trusted root certificate for unit tests.
-// TODO(wtc): we can't run this test on Windows because LoadTemporaryRootCert
-// isn't implemented (http//crbug.com/8470).
TEST(X509CertificateTest, IntermediateCARequireExplicitPolicy) {
FilePath certs_dir = GetTestCertsDirectory();
@@ -448,9 +421,8 @@ TEST(X509CertificateTest, IntermediateCARequireExplicitPolicy) {
ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert);
FilePath root_cert_path = certs_dir.AppendASCII("dod_root_ca_2_cert.der");
- scoped_refptr<X509Certificate> root_cert =
- LoadTemporaryRootCert(root_cert_path);
- ASSERT_NE(static_cast<X509Certificate*>(NULL), root_cert);
+ TestRootCerts* root_certs = TestRootCerts::GetInstance();
+ ASSERT_TRUE(root_certs->AddFromFile(root_cert_path));
X509Certificate::OSCertHandles intermediates;
intermediates.push_back(intermediate_cert->os_cert_handle());
@@ -464,8 +436,8 @@ TEST(X509CertificateTest, IntermediateCARequireExplicitPolicy) {
int error = cert_chain->Verify("www.us.army.mil", flags, &verify_result);
EXPECT_EQ(OK, error);
EXPECT_EQ(0, verify_result.cert_status);
+ root_certs->Clear();
}
-#endif
// Tests X509Certificate::Cache via X509Certificate::CreateFromHandle. We
// call X509Certificate::CreateFromHandle several times and observe whether
@@ -687,6 +659,33 @@ TEST(X509CertificateTest, IsIssuedBy) {
}
#endif // defined(OS_MACOSX)
+#if defined(USE_NSS) || defined(OS_WIN)
+// This test creates a signed cert from a private key and then verify content
+// of the certificate.
+TEST(X509CertificateTest, CreateSelfSigned) {
+ scoped_ptr<base::RSAPrivateKey> private_key(
+ base::RSAPrivateKey::Create(1024));
+ scoped_refptr<net::X509Certificate> cert =
+ net::X509Certificate::CreateSelfSigned(
+ private_key.get(), "CN=subject", 1, base::TimeDelta::FromDays(1));
+
+ EXPECT_EQ("subject", cert->subject().GetDisplayName());
+ EXPECT_FALSE(cert->HasExpired());
+}
+
+TEST(X509CertificateTest, GetDEREncoded) {
+ scoped_ptr<base::RSAPrivateKey> private_key(
+ base::RSAPrivateKey::Create(1024));
+ scoped_refptr<net::X509Certificate> cert =
+ net::X509Certificate::CreateSelfSigned(
+ private_key.get(), "CN=subject", 0, base::TimeDelta::FromDays(1));
+
+ std::string der_cert;
+ EXPECT_TRUE(cert->GetDEREncoded(&der_cert));
+ EXPECT_FALSE(der_cert.empty());
+}
+#endif
+
class X509CertificateParseTest
: public testing::TestWithParam<CertificateFormatTestData> {
public:
diff --git a/net/base/x509_certificate_win.cc b/net/base/x509_certificate_win.cc
index 75cdf40..663563d 100644
--- a/net/base/x509_certificate_win.cc
+++ b/net/base/x509_certificate_win.cc
@@ -4,9 +4,11 @@
#include "net/base/x509_certificate.h"
+#include "base/crypto/rsa_private_key.h"
+#include "base/crypto/scoped_capi_types.h"
+#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/pickle.h"
-#include "base/singleton.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
@@ -15,6 +17,7 @@
#include "net/base/ev_root_ca_metadata.h"
#include "net/base/net_errors.h"
#include "net/base/scoped_cert_chain_context.h"
+#include "net/base/test_root_certs.h"
#pragma comment(lib, "crypt32.lib")
@@ -24,6 +27,21 @@ namespace net {
namespace {
+typedef base::ScopedCAPIHandle<
+ HCERTSTORE,
+ base::CAPIDestroyerWithFlags<HCERTSTORE,
+ CertCloseStore, 0> > ScopedHCERTSTORE;
+
+struct FreeChainEngineFunctor {
+ void operator()(HCERTCHAINENGINE engine) const {
+ if (engine)
+ CertFreeCertificateChainEngine(engine);
+ }
+};
+
+typedef base::ScopedCAPIHandle<HCERTCHAINENGINE, FreeChainEngineFunctor>
+ ScopedHCERTCHAINENGINE;
+
//-----------------------------------------------------------------------------
// TODO(wtc): This is a copy of the MapSecurityError function in
@@ -484,6 +502,70 @@ X509Certificate* X509Certificate::CreateFromPickle(const Pickle& pickle,
return cert;
}
+// static
+X509Certificate* X509Certificate::CreateSelfSigned(
+ base::RSAPrivateKey* key,
+ const std::string& subject,
+ uint32 serial_number,
+ base::TimeDelta valid_duration) {
+ // Get the ASN.1 encoding of the certificate subject.
+ std::wstring w_subject = ASCIIToWide(subject);
+ DWORD encoded_subject_length = 0;
+ if (!CertStrToName(
+ X509_ASN_ENCODING,
+ const_cast<wchar_t*>(w_subject.c_str()),
+ CERT_X500_NAME_STR, NULL, NULL, &encoded_subject_length, NULL)) {
+ return NULL;
+ }
+
+ scoped_array<char> encoded_subject(new char[encoded_subject_length]);
+ if (!CertStrToName(
+ X509_ASN_ENCODING,
+ const_cast<wchar_t*>(w_subject.c_str()),
+ CERT_X500_NAME_STR, NULL,
+ reinterpret_cast<BYTE*>(encoded_subject.get()),
+ &encoded_subject_length, NULL)) {
+ return NULL;
+ }
+
+ CERT_NAME_BLOB subject_name;
+ memset(&subject_name, 0, sizeof(subject_name));
+ subject_name.cbData = encoded_subject_length;
+ subject_name.pbData = reinterpret_cast<BYTE*>(encoded_subject.get());
+
+ CRYPT_ALGORITHM_IDENTIFIER sign_algo;
+ memset(&sign_algo, 0, sizeof(sign_algo));
+ sign_algo.pszObjId = szOID_RSA_SHA1RSA;
+
+ base::Time not_valid = base::Time::Now() + valid_duration;
+ base::Time::Exploded exploded;
+ not_valid.UTCExplode(&exploded);
+
+ // Create the system time struct representing our exploded time.
+ SYSTEMTIME system_time;
+ system_time.wYear = exploded.year;
+ system_time.wMonth = exploded.month;
+ system_time.wDayOfWeek = exploded.day_of_week;
+ system_time.wDay = exploded.day_of_month;
+ system_time.wHour = exploded.hour;
+ system_time.wMinute = exploded.minute;
+ system_time.wSecond = exploded.second;
+ system_time.wMilliseconds = exploded.millisecond;
+
+ PCCERT_CONTEXT cert_handle =
+ CertCreateSelfSignCertificate(key->provider(), &subject_name,
+ CERT_CREATE_SELFSIGN_NO_KEY_INFO,
+ NULL, &sign_algo, 0, &system_time, 0);
+ DCHECK(cert_handle) << "Failed to create self-signed certificate: "
+ << logging::GetLastSystemErrorCode();
+
+ X509Certificate* cert = CreateFromHandle(cert_handle,
+ SOURCE_LONE_CERT_IMPORT,
+ OSCertHandles());
+ FreeOSCertHandle(cert_handle);
+ return cert;
+}
+
void X509Certificate::Persist(Pickle* pickle) {
DCHECK(cert_handle_);
DWORD length;
@@ -529,7 +611,7 @@ class GlobalCertStore {
}
private:
- friend struct DefaultSingletonTraits<GlobalCertStore>;
+ friend struct base::DefaultLazyInstanceTraits<GlobalCertStore>;
GlobalCertStore()
: cert_store_(CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, 0, NULL)) {
@@ -544,9 +626,12 @@ class GlobalCertStore {
DISALLOW_COPY_AND_ASSIGN(GlobalCertStore);
};
+static base::LazyInstance<GlobalCertStore> g_cert_store(
+ base::LINKER_INITIALIZED);
+
// static
HCERTSTORE X509Certificate::cert_store() {
- return Singleton<GlobalCertStore>::get()->cert_store();
+ return g_cert_store.Get().cert_store();
}
int X509Certificate::Verify(const std::string& hostname,
@@ -606,15 +691,26 @@ int X509Certificate::Verify(const std::string& hostname,
}
}
+ // For non-test scenarios, use the default HCERTCHAINENGINE, NULL, which
+ // corresponds to HCCE_CURRENT_USER and is is initialized as needed by
+ // crypt32. However, when testing, it is necessary to create a new
+ // HCERTCHAINENGINE and use that instead. This is because each
+ // HCERTCHAINENGINE maintains a cache of information about certificates
+ // encountered, and each test run may modify the trust status of a
+ // certificate.
+ ScopedHCERTCHAINENGINE chain_engine(NULL);
+ if (TestRootCerts::HasInstance())
+ chain_engine.reset(TestRootCerts::GetInstance()->GetChainEngine());
+
PCCERT_CHAIN_CONTEXT chain_context;
// IE passes a non-NULL pTime argument that specifies the current system
// time. IE passes CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT as the
// chain_flags argument.
if (!CertGetCertificateChain(
- NULL, // default chain engine, HCCE_CURRENT_USER
+ chain_engine,
cert_handle_,
NULL, // current system time
- cert_handle_->hCertStore, // search this store
+ cert_handle_->hCertStore,
&chain_para,
chain_flags,
NULL, // reserved
@@ -628,10 +724,10 @@ int X509Certificate::Verify(const std::string& hostname,
chain_para.RequestedIssuancePolicy.Usage.rgpszUsageIdentifier = NULL;
CertFreeCertificateChain(chain_context);
if (!CertGetCertificateChain(
- NULL, // default chain engine, HCCE_CURRENT_USER
+ chain_engine,
cert_handle_,
NULL, // current system time
- cert_handle_->hCertStore, // search this store
+ cert_handle_->hCertStore,
&chain_para,
chain_flags,
NULL, // reserved
@@ -642,7 +738,6 @@ int X509Certificate::Verify(const std::string& hostname,
ScopedCertChainContext scoped_chain_context(chain_context);
GetCertChainInfo(chain_context, verify_result);
-
verify_result->cert_status |= MapCertChainErrorStatusToCertStatus(
chain_context->TrustStatus.dwErrorStatus);
@@ -748,6 +843,15 @@ int X509Certificate::Verify(const std::string& hostname,
return OK;
}
+bool X509Certificate::GetDEREncoded(std::string* encoded) {
+ if (!cert_handle_->pbCertEncoded || !cert_handle_->cbCertEncoded)
+ return false;
+ encoded->clear();
+ encoded->append(reinterpret_cast<char*>(cert_handle_->pbCertEncoded),
+ cert_handle_->cbCertEncoded);
+ return true;
+}
+
// Returns true if the certificate is an extended-validation certificate.
//
// This function checks the certificatePolicies extensions of the
diff --git a/net/base/x509_openssl_util.cc b/net/base/x509_openssl_util.cc
index 9e44c4b..35871ad 100644
--- a/net/base/x509_openssl_util.cc
+++ b/net/base/x509_openssl_util.cc
@@ -5,30 +5,14 @@
#include "net/base/x509_openssl_util.h"
#include "base/logging.h"
-#include "base/string_number_conversions.h"
#include "base/string_piece.h"
#include "base/string_util.h"
-#include "base/time.h"
+#include "net/base/x509_cert_types.h"
namespace net {
namespace x509_openssl_util {
-namespace {
-
-// Helper for ParseDate. |*field| must contain at least |field_len| characters.
-// |*field| will be advanced by |field_len| on exit. |*ok| is set to false if
-// there is an error in parsing the number, but left untouched otherwise.
-// Returns the parsed integer.
-int ParseIntAndAdvance(const char** field, size_t field_len, bool* ok) {
- int result = 0;
- *ok &= base::StringToInt(*field, *field + field_len, &result);
- *field += field_len;
- return result;
-}
-
-} // namespace
-
bool ParsePrincipalKeyAndValueByIndex(X509_NAME* name,
int index,
std::string* key,
@@ -78,35 +62,10 @@ bool ParseDate(ASN1_TIME* x509_time, base::Time* time) {
base::StringPiece str_date(reinterpret_cast<const char*>(x509_time->data),
x509_time->length);
- // UTCTime: YYMMDDHHMMSSZ
- // GeneralizedTime: YYYYMMDDHHMMSSZ
- size_t year_length = x509_time->type == V_ASN1_UTCTIME ? 2 : 4;
-
- if (str_date.length() < 11 + year_length)
- return false;
-
- const char* field = str_date.data();
- bool valid = true;
- base::Time::Exploded exploded = {0};
-
- exploded.year = ParseIntAndAdvance(&field, year_length, &valid);
- exploded.month = ParseIntAndAdvance(&field, 2, &valid);
- exploded.day_of_month = ParseIntAndAdvance(&field, 2, &valid);
- exploded.hour = ParseIntAndAdvance(&field, 2, &valid);
- exploded.minute = ParseIntAndAdvance(&field, 2, &valid);
- exploded.second = ParseIntAndAdvance(&field, 2, &valid);
- if (valid && year_length == 2)
- exploded.year += exploded.year < 50 ? 2000 : 1900;
- valid &= exploded.HasValidValues();
-
- if (!valid) {
- NOTREACHED() << "can't parse x509 date " << str_date;
- return false;
- }
-
- *time = base::Time::FromUTCExploded(exploded);
- return true;
+ CertDateFormat format = x509_time->type == V_ASN1_UTCTIME ?
+ CERT_DATE_FORMAT_UTC_TIME : CERT_DATE_FORMAT_GENERALIZED_TIME;
+ return ParseCertificateDate(str_date, format, time);
}
// TODO(joth): Investigate if we can upstream this into the OpenSSL library,
@@ -149,9 +108,17 @@ bool VerifyHostname(const std::string& hostname,
}
DCHECK(!reference_name.empty());
- // TODO(joth): Add IP address support. See http://crbug.com/62973
if (found_ip6_chars || !found_alpha) {
- NOTIMPLEMENTED() << hostname;
+ // For now we just do simple localhost IP address support, primarily as
+ // it's needed by the test server. TODO(joth): Replace this with full IP
+ // address support. See http://crbug.com/62973
+ if (hostname == "127.0.0.1" &&
+ std::find(cert_names.begin(), cert_names.end(), hostname) !=
+ cert_names.end()) {
+ DVLOG(1) << "Allowing localhost IP certificate: " << hostname;
+ return true;
+ }
+ NOTIMPLEMENTED() << hostname; // See comment above.
return false;
}
@@ -217,6 +184,6 @@ bool VerifyHostname(const std::string& hostname,
return false;
}
-} // namespace x509_openssl_util
+} // namespace x509_openssl_util
-} // namespace net
+} // namespace net
diff --git a/net/base/x509_openssl_util_unittest.cc b/net/base/x509_openssl_util_unittest.cc
index 50589ad..4727d4c 100644
--- a/net/base/x509_openssl_util_unittest.cc
+++ b/net/base/x509_openssl_util_unittest.cc
@@ -60,7 +60,8 @@ CertificateNameVerifyTestData kNameVerifyTestData[] = {
{ false, "baz2.example.net", "baz*.example.net" },
{ false, "bar.*.example.net", "bar.*.example.net" },
{ false, "bar.f*o.example.net", "bar.f*o.example.net" },
- // IP addresses currently not supported.
+ // IP addresses currently not supported, except for the localhost.
+ { true, "127.0.0.1", "127.0.0.1" },
{ false, "192.168.1.1", "192.168.1.1" },
{ false, "FEDC:BA98:7654:3210:FEDC:BA98:7654:3210",
"FEDC:BA98:7654:3210:FEDC:BA98:7654:3210" },
diff --git a/net/data/ftp/dir-listing-hprc-1 b/net/data/ftp/dir-listing-hprc-1
deleted file mode 100644
index ee3504f..0000000
--- a/net/data/ftp/dir-listing-hprc-1
+++ /dev/null
@@ -1,2 +0,0 @@
- .
- ..
diff --git a/net/data/ftp/dir-listing-hprc-1.expected b/net/data/ftp/dir-listing-hprc-1.expected
deleted file mode 100644
index 6259526..0000000
--- a/net/data/ftp/dir-listing-hprc-1.expected
+++ /dev/null
@@ -1,17 +0,0 @@
--
-.
-0
-1994
-11
-15
-12
-45
-
--
-..
-0
-1994
-11
-15
-12
-45
diff --git a/net/data/ftp/dir-listing-hprc-2 b/net/data/ftp/dir-listing-hprc-2
deleted file mode 100644
index 31a8688..0000000
--- a/net/data/ftp/dir-listing-hprc-2
+++ /dev/null
@@ -1,4 +0,0 @@
- .
- ..
- .welcome
- readme
diff --git a/net/data/ftp/dir-listing-hprc-2.expected b/net/data/ftp/dir-listing-hprc-2.expected
deleted file mode 100644
index e597b76..0000000
--- a/net/data/ftp/dir-listing-hprc-2.expected
+++ /dev/null
@@ -1,35 +0,0 @@
--
-.
-0
-1994
-11
-15
-12
-45
-
--
-..
-0
-1994
-11
-15
-12
-45
-
--
-.welcome
-0
-1994
-11
-15
-12
-45
-
--
-readme
-0
-1994
-11
-15
-12
-45
diff --git a/net/data/ftp/dir-listing-hprc-3 b/net/data/ftp/dir-listing-hprc-3
deleted file mode 100644
index 0e2f2d0..0000000
--- a/net/data/ftp/dir-listing-hprc-3
+++ /dev/null
@@ -1,3 +0,0 @@
- .
- ..
- Multi Word File Name.txt
diff --git a/net/data/ftp/dir-listing-hprc-3.expected b/net/data/ftp/dir-listing-hprc-3.expected
deleted file mode 100644
index a71cbd2..0000000
--- a/net/data/ftp/dir-listing-hprc-3.expected
+++ /dev/null
@@ -1,26 +0,0 @@
--
-.
-0
-1994
-11
-15
-12
-45
-
--
-..
-0
-1994
-11
-15
-12
-45
-
--
-Multi Word File Name.txt
-0
-1994
-11
-15
-12
-45
diff --git a/net/data/ftp/dir-listing-mlsd-1 b/net/data/ftp/dir-listing-mlsd-1
deleted file mode 100644
index 9463845..0000000
--- a/net/data/ftp/dir-listing-mlsd-1
+++ /dev/null
@@ -1,5 +0,0 @@
-type=dir;sizd=512;modify=20010414155043;UNIX.mode=0555;unique=6ag5b4e3ff; bin
-type=dir;sizd=512;modify=20010414155237;UNIX.mode=0555;unique=6ag5b4e400; etc
-type=dir;sizd=512;modify=20010705213550;UNIX.mode=0711;unique=6ag5b4e401; hidden
-type=dir;sizd=512;modify=20050422001005;UNIX.mode=0755;unique=100ff03g6164000; j
-type=dir;sizd=512;modify=20031021200128;UNIX.mode=0755;unique=6ag5b4e403; pub
diff --git a/net/data/ftp/dir-listing-mlsd-1.expected b/net/data/ftp/dir-listing-mlsd-1.expected
deleted file mode 100644
index 7720451..0000000
--- a/net/data/ftp/dir-listing-mlsd-1.expected
+++ /dev/null
@@ -1,44 +0,0 @@
-d
-bin
--1
-2001
-4
-14
-15
-50
-
-d
-etc
--1
-2001
-4
-14
-15
-52
-
-d
-hidden
--1
-2001
-7
-5
-21
-35
-
-d
-j
--1
-2005
-4
-22
-0
-10
-
-d
-pub
--1
-2003
-10
-21
-20
-1
diff --git a/net/data/ftp/dir-listing-mlsd-2 b/net/data/ftp/dir-listing-mlsd-2
deleted file mode 100644
index 939638a..0000000
--- a/net/data/ftp/dir-listing-mlsd-2
+++ /dev/null
@@ -1 +0,0 @@
-type=file;size=839;modify=19980908010757;UNIX.mode=0644;unique=6ag5b4e47d; ftpmotd
diff --git a/net/data/ftp/dir-listing-mlsd-2.expected b/net/data/ftp/dir-listing-mlsd-2.expected
deleted file mode 100644
index 33659ea..0000000
--- a/net/data/ftp/dir-listing-mlsd-2.expected
+++ /dev/null
@@ -1,8 +0,0 @@
--
-ftpmotd
-839
-1998
-9
-8
-1
-7
diff --git a/net/data/ssl/certificates/README b/net/data/ssl/certificates/README
index a58aaa1..1793476 100644
--- a/net/data/ssl/certificates/README
+++ b/net/data/ssl/certificates/README
@@ -34,3 +34,8 @@ unit tests.
- punycodetest.der : A test self-signed server certificate with punycode name.
The common name is "xn--wgv71a119e.com" (日本語.com)
+
+- unittest.selfsigned.der : A self-signed certificate generated using private
+ key in unittest.key.bin. The common name is "unittest".
+
+- unittest.key.bin : private key stored unencrypted.
diff --git a/net/data/ssl/certificates/unittest.key.bin b/net/data/ssl/certificates/unittest.key.bin
new file mode 100644
index 0000000..2ec712b
--- /dev/null
+++ b/net/data/ssl/certificates/unittest.key.bin
Binary files differ
diff --git a/net/data/ssl/certificates/unittest.selfsigned.der b/net/data/ssl/certificates/unittest.selfsigned.der
new file mode 100644
index 0000000..48c8d74
--- /dev/null
+++ b/net/data/ssl/certificates/unittest.selfsigned.der
Binary files differ
diff --git a/net/disk_cache/backend_impl.cc b/net/disk_cache/backend_impl.cc
index 78ebcc0..284657f 100644
--- a/net/disk_cache/backend_impl.cc
+++ b/net/disk_cache/backend_impl.cc
@@ -179,7 +179,12 @@ bool SetFieldTrialInfo(int size_group) {
std::string group1 = base::StringPrintf("CacheSizeGroup_%d", size_group);
trial1->AppendGroup(group1, base::FieldTrial::kAllRemainingProbability);
- return false;
+ scoped_refptr<base::FieldTrial> trial2(
+ new base::FieldTrial("CacheThrottle", 100));
+ int group2a = trial2->AppendGroup("CacheThrottle_On", 10); // 10 % in.
+ trial2->AppendGroup("CacheThrottle_Off", 10); // 10 % control.
+
+ return trial2->group() == group2a;
}
// ------------------------------------------------------------------------
@@ -423,7 +428,7 @@ BackendImpl::~BackendImpl() {
// ------------------------------------------------------------------------
int32 BackendImpl::GetEntryCount() const {
- if (!index_)
+ if (!index_ || disabled_)
return 0;
// num_entries includes entries already evicted.
int32 not_deleted = data_->header.num_entries -
@@ -1214,6 +1219,10 @@ void BackendImpl::OnOperationCompleted(base::TimeDelta elapsed_time) {
if (cache_type() != net::DISK_CACHE)
return;
+ UMA_HISTOGRAM_TIMES(base::FieldTrial::MakeName("DiskCache.TotalIOTime",
+ "CacheThrottle").data(),
+ elapsed_time);
+
if (!throttle_requests_)
return;
diff --git a/net/disk_cache/backend_unittest.cc b/net/disk_cache/backend_unittest.cc
index bfb78b6..d3e79a1 100644
--- a/net/disk_cache/backend_unittest.cc
+++ b/net/disk_cache/backend_unittest.cc
@@ -1444,7 +1444,7 @@ void DiskCacheBackendTest::BackendDisable() {
ASSERT_EQ(net::OK, OpenNextEntry(&iter, &entry1));
EXPECT_NE(net::OK, OpenNextEntry(&iter, &entry2));
- EXPECT_EQ(2, cache_->GetEntryCount());
+ EXPECT_EQ(0, cache_->GetEntryCount());
EXPECT_NE(net::OK, CreateEntry("Something new", &entry2));
entry1->Close();
@@ -1601,7 +1601,7 @@ void DiskCacheBackendTest::BackendDisable4() {
// This line should disable the cache but not delete it.
EXPECT_NE(net::OK, OpenNextEntry(&iter, &entry4));
- EXPECT_EQ(4, cache_->GetEntryCount());
+ EXPECT_EQ(0, cache_->GetEntryCount());
EXPECT_NE(net::OK, CreateEntry("cache is disabled", &entry4));
diff --git a/net/disk_cache/entry_impl.cc b/net/disk_cache/entry_impl.cc
index ce59270..e5e6482 100644
--- a/net/disk_cache/entry_impl.cc
+++ b/net/disk_cache/entry_impl.cc
@@ -296,11 +296,15 @@ EntryImpl::EntryImpl(BackendImpl* backend, Addr address, bool read_only)
// written before).
EntryImpl::~EntryImpl() {
Log("~EntryImpl in");
- backend_->OnEntryDestroyBegin(entry_.address());
- // Save the sparse info to disk before deleting this entry.
+ // Save the sparse info to disk. This will generate IO for this entry and
+ // maybe for a child entry, so it is important to do it before deleting this
+ // entry.
sparse_.reset();
+ // Remove this entry from the list of open entries.
+ backend_->OnEntryDestroyBegin(entry_.address());
+
if (doomed_) {
DeleteEntryData(true);
} else {
diff --git a/net/disk_cache/entry_unittest.cc b/net/disk_cache/entry_unittest.cc
index bea940c..cb7f680 100644
--- a/net/disk_cache/entry_unittest.cc
+++ b/net/disk_cache/entry_unittest.cc
@@ -48,6 +48,7 @@ class DiskCacheEntryTest : public DiskCacheTestWithCache {
void HugeSparseIO();
void GetAvailableRange();
void CouldBeSparse();
+ void UpdateSparseEntry();
void DoomSparseEntry();
void PartialSparseEntry();
};
@@ -514,7 +515,7 @@ TEST_F(DiskCacheEntryTest, RequestThrottling) {
int ret = entry->WriteData(0, 0, buffer, kSize, &cb, false);
EXPECT_EQ(net::ERR_IO_PENDING, ret);
}
- // We have 9 queued requests, lets dispatch them all at once.
+ // We have 9 queued requests, let's dispatch them all.
cache_impl_->ThrottleRequestsForTest(false);
EXPECT_TRUE(helper.WaitUntilCacheIoFinished(expected));
@@ -857,7 +858,7 @@ void DiskCacheEntryTest::ZeroLengthIO() {
EXPECT_EQ(0, ReadData(entry, 0, 50000, NULL, 0));
EXPECT_EQ(100000, entry->GetDataSize(0));
- // Lets verify the actual content.
+ // Let's verify the actual content.
const int kSize = 20;
const char zeros[kSize] = {};
scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kSize));
@@ -1655,6 +1656,50 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyMisalignedGetAvailableRange) {
entry->Close();
}
+void DiskCacheEntryTest::UpdateSparseEntry() {
+ std::string key("the first key");
+ disk_cache::Entry* entry1;
+ ASSERT_EQ(net::OK, CreateEntry(key, &entry1));
+
+ const int kSize = 2048;
+ scoped_refptr<net::IOBuffer> buf_1(new net::IOBuffer(kSize));
+ scoped_refptr<net::IOBuffer> buf_2(new net::IOBuffer(kSize));
+ CacheTestFillBuffer(buf_1->data(), kSize, false);
+
+ // Write at offset 0.
+ VerifySparseIO(entry1, 0, buf_1, kSize, buf_2);
+ entry1->Close();
+
+ // Write at offset 2048.
+ ASSERT_EQ(net::OK, OpenEntry(key, &entry1));
+ VerifySparseIO(entry1, 2048, buf_1, kSize, buf_2);
+
+ disk_cache::Entry* entry2;
+ ASSERT_EQ(net::OK, CreateEntry("the second key", &entry2));
+
+ entry1->Close();
+ entry2->Close();
+ FlushQueueForTest();
+ if (memory_only_)
+ EXPECT_EQ(2, cache_->GetEntryCount());
+ else
+ EXPECT_EQ(3, cache_->GetEntryCount());
+}
+
+TEST_F(DiskCacheEntryTest, UpdateSparseEntry) {
+ SetDirectMode();
+ SetCacheType(net::MEDIA_CACHE);
+ InitCache();
+ UpdateSparseEntry();
+}
+
+TEST_F(DiskCacheEntryTest, MemoryOnlyUpdateSparseEntry) {
+ SetMemoryOnlyMode();
+ SetCacheType(net::MEDIA_CACHE);
+ InitCache();
+ UpdateSparseEntry();
+}
+
void DiskCacheEntryTest::DoomSparseEntry() {
std::string key1("the first key");
std::string key2("the second key");
diff --git a/net/disk_cache/file_win.cc b/net/disk_cache/file_win.cc
index 5b01224..737b8e8 100644
--- a/net/disk_cache/file_win.cc
+++ b/net/disk_cache/file_win.cc
@@ -5,8 +5,8 @@
#include "net/disk_cache/file.h"
#include "base/file_path.h"
+#include "base/lazy_instance.h"
#include "base/message_loop.h"
-#include "base/singleton.h"
#include "net/disk_cache/disk_cache.h"
namespace {
@@ -33,6 +33,9 @@ class CompletionHandler : public MessageLoopForIO::IOHandler {
DWORD actual_bytes, DWORD error);
};
+static base::LazyInstance<CompletionHandler> g_completion_handler(
+ base::LINKER_INITIALIZED);
+
void CompletionHandler::OnIOCompleted(MessageLoopForIO::IOContext* context,
DWORD actual_bytes, DWORD error) {
MyOverlapped* data = reinterpret_cast<MyOverlapped*>(context);
@@ -52,7 +55,7 @@ void CompletionHandler::OnIOCompleted(MessageLoopForIO::IOContext* context,
MyOverlapped::MyOverlapped(disk_cache::File* file, size_t offset,
disk_cache::FileIOCallback* callback) {
memset(this, 0, sizeof(*this));
- context_.handler = Singleton<CompletionHandler>::get();
+ context_.handler = g_completion_handler.Pointer();
context_.overlapped.Offset = static_cast<DWORD>(offset);
file_ = file;
callback_ = callback;
@@ -81,7 +84,7 @@ bool File::Init(const FilePath& name) {
return false;
MessageLoopForIO::current()->RegisterIOHandler(
- platform_file_, Singleton<CompletionHandler>::get());
+ platform_file_, g_completion_handler.Pointer());
init_ = true;
sync_platform_file_ = CreateFile(name.value().c_str(), access, sharing, NULL,
@@ -255,7 +258,7 @@ void File::WaitForPendingIO(int* num_pending_io) {
while (*num_pending_io) {
// Asynchronous IO operations may be in flight and the completion may end
// up calling us back so let's wait for them.
- MessageLoopForIO::IOHandler* handler = Singleton<CompletionHandler>::get();
+ MessageLoopForIO::IOHandler* handler = g_completion_handler.Pointer();
MessageLoopForIO::current()->WaitForIOCompletion(100, handler);
}
}
diff --git a/net/disk_cache/in_flight_backend_io.cc b/net/disk_cache/in_flight_backend_io.cc
index d83bd10..5752353 100644
--- a/net/disk_cache/in_flight_backend_io.cc
+++ b/net/disk_cache/in_flight_backend_io.cc
@@ -287,6 +287,7 @@ InFlightBackendIO::InFlightBackendIO(BackendImpl* backend,
base::MessageLoopProxy* background_thread)
: backend_(backend),
background_thread_(background_thread),
+ max_queue_len_(0),
queue_entry_ops_(false) {
}
@@ -445,10 +446,16 @@ void InFlightBackendIO::WaitForPendingIO() {
void InFlightBackendIO::StartQueingOperations() {
queue_entry_ops_ = true;
+ CACHE_UMA(COUNTS_10000, "InitialQueuedOperations", 0, pending_ops_.size());
+ if (!pending_ops_.size()) {
+ queueing_start_ = base::TimeTicks::Now();
+ max_queue_len_ = 0;
+ }
}
void InFlightBackendIO::StopQueingOperations() {
queue_entry_ops_ = false;
+ CACHE_UMA(COUNTS_10000, "FinalQueuedOperations", 0, pending_ops_.size());
}
void InFlightBackendIO::OnOperationComplete(BackgroundIO* operation,
@@ -461,13 +468,10 @@ void InFlightBackendIO::OnOperationComplete(BackgroundIO* operation,
// Process the next request. Note that invoking the callback may result
// in the backend destruction (and with it this object), so we should deal
// with the next operation before invoking the callback.
- if (queue_entry_ops_) {
- PostQueuedOperation();
- } else {
- // If we are not throttling requests anymore, dispatch the whole queue.
- CACHE_UMA(COUNTS_10000, "FinalQueuedOperations", 0,
- pending_ops_.size());
- PostAllQueuedOperations();
+ PostQueuedOperation();
+ if (!pending_ops_.size() && !queue_entry_ops_) {
+ CACHE_UMA(AGE_MS, "ThrottleTime", 0, queueing_start_);
+ CACHE_UMA(COUNTS_10000, "MaxQueuedOperations", 0, max_queue_len_);
}
}
}
@@ -498,6 +502,7 @@ void InFlightBackendIO::QueueOperation(BackendIO* operation) {
// We keep the operation that we are executing in the list so that we know
// when it completes.
pending_ops_.push_back(operation);
+ max_queue_len_ = std::max(max_queue_len_, pending_ops_.size());
if (empty_list)
PostOperation(operation);
}
@@ -517,14 +522,6 @@ void InFlightBackendIO::PostQueuedOperation() {
PostOperation(next_op);
}
-void InFlightBackendIO::PostAllQueuedOperations() {
- for (OperationList::iterator it = pending_ops_.begin();
- it != pending_ops_.end(); ++it) {
- PostOperation(*it);
- }
- pending_ops_.clear();
-}
-
bool InFlightBackendIO::RemoveFirstQueuedOperation(BackendIO* operation) {
DCHECK(!pending_ops_.empty());
scoped_refptr<BackendIO> next_op = pending_ops_.front();
diff --git a/net/disk_cache/in_flight_backend_io.h b/net/disk_cache/in_flight_backend_io.h
index ca239dd..7b4b111 100644
--- a/net/disk_cache/in_flight_backend_io.h
+++ b/net/disk_cache/in_flight_backend_io.h
@@ -200,12 +200,13 @@ class InFlightBackendIO : public InFlightIO {
void QueueOperation(BackendIO* operation);
void PostOperation(BackendIO* operation);
void PostQueuedOperation();
- void PostAllQueuedOperations();
bool RemoveFirstQueuedOperation(BackendIO* operation);
BackendImpl* backend_;
scoped_refptr<base::MessageLoopProxy> background_thread_;
OperationList pending_ops_; // Entry (async) operations to be posted.
+ base::TimeTicks queueing_start_;
+ size_t max_queue_len_;
bool queue_entry_ops_; // True if we are queuing entry (async) operations.
DISALLOW_COPY_AND_ASSIGN(InFlightBackendIO);
diff --git a/net/ftp/ftp_directory_listing_buffer.cc b/net/ftp/ftp_directory_listing_buffer.cc
index f6e8748..58533b8 100644
--- a/net/ftp/ftp_directory_listing_buffer.cc
+++ b/net/ftp/ftp_directory_listing_buffer.cc
@@ -9,9 +9,7 @@
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "net/base/net_errors.h"
-#include "net/ftp/ftp_directory_listing_parser_hprc.h"
#include "net/ftp/ftp_directory_listing_parser_ls.h"
-#include "net/ftp/ftp_directory_listing_parser_mlsd.h"
#include "net/ftp/ftp_directory_listing_parser_netware.h"
#include "net/ftp/ftp_directory_listing_parser_vms.h"
#include "net/ftp/ftp_directory_listing_parser_windows.h"
@@ -21,9 +19,7 @@ namespace net {
FtpDirectoryListingBuffer::FtpDirectoryListingBuffer(
const base::Time& current_time)
: current_parser_(NULL) {
- parsers_.insert(new FtpDirectoryListingParserHprc(current_time));
parsers_.insert(new FtpDirectoryListingParserLs(current_time));
- parsers_.insert(new FtpDirectoryListingParserMlsd());
parsers_.insert(new FtpDirectoryListingParserNetware(current_time));
parsers_.insert(new FtpDirectoryListingParserVms());
parsers_.insert(new FtpDirectoryListingParserWindows());
diff --git a/net/ftp/ftp_directory_listing_buffer_unittest.cc b/net/ftp/ftp_directory_listing_buffer_unittest.cc
index ceddfc4..cb120a6 100644
--- a/net/ftp/ftp_directory_listing_buffer_unittest.cc
+++ b/net/ftp/ftp_directory_listing_buffer_unittest.cc
@@ -19,9 +19,6 @@ namespace {
TEST(FtpDirectoryListingBufferTest, Parse) {
const char* test_files[] = {
- "dir-listing-hprc-1",
- "dir-listing-hprc-2",
- "dir-listing-hprc-3",
"dir-listing-ls-1",
"dir-listing-ls-1-utf8",
"dir-listing-ls-2",
@@ -45,8 +42,6 @@ TEST(FtpDirectoryListingBufferTest, Parse) {
"dir-listing-ls-20", // TODO(phajdan.jr): should use windows-1251 encoding.
"dir-listing-ls-21", // TODO(phajdan.jr): should use windows-1251 encoding.
"dir-listing-ls-22", // TODO(phajdan.jr): should use windows-1251 encoding.
- "dir-listing-mlsd-1",
- "dir-listing-mlsd-2",
"dir-listing-netware-1",
"dir-listing-netware-2",
"dir-listing-vms-1",
diff --git a/net/ftp/ftp_directory_listing_parser_hprc.cc b/net/ftp/ftp_directory_listing_parser_hprc.cc
deleted file mode 100644
index 621aba1..0000000
--- a/net/ftp/ftp_directory_listing_parser_hprc.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-// 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.
-
-#include "net/ftp/ftp_directory_listing_parser_hprc.h"
-
-#include "base/logging.h"
-#include "base/time.h"
-
-namespace net {
-
-FtpDirectoryListingParserHprc::FtpDirectoryListingParserHprc(
- const base::Time& current_time)
- : current_time_(current_time) {
-}
-
-FtpDirectoryListingParserHprc::~FtpDirectoryListingParserHprc() {}
-
-FtpServerType FtpDirectoryListingParserHprc::GetServerType() const {
- return SERVER_HPRC;
-}
-
-bool FtpDirectoryListingParserHprc::ConsumeLine(const string16& line) {
- if (line.empty())
- return false;
-
- // All lines begin with a space.
- if (line[0] != ' ')
- return false;
-
- FtpDirectoryListingEntry entry;
- entry.name = line.substr(1);
-
- // We don't know anything beyond the file name, so just pick some arbitrary
- // values.
- // TODO(phajdan.jr): consider adding an UNKNOWN entry type.
- entry.type = FtpDirectoryListingEntry::FILE;
- entry.size = 0;
- entry.last_modified = current_time_;
-
- entries_.push(entry);
- return true;
-}
-
-bool FtpDirectoryListingParserHprc::OnEndOfInput() {
- return true;
-}
-
-bool FtpDirectoryListingParserHprc::EntryAvailable() const {
- return !entries_.empty();
-}
-
-FtpDirectoryListingEntry FtpDirectoryListingParserHprc::PopEntry() {
- DCHECK(EntryAvailable());
- FtpDirectoryListingEntry entry = entries_.front();
- entries_.pop();
- return entry;
-}
-
-} // namespace net
diff --git a/net/ftp/ftp_directory_listing_parser_hprc.h b/net/ftp/ftp_directory_listing_parser_hprc.h
deleted file mode 100644
index d153810..0000000
--- a/net/ftp/ftp_directory_listing_parser_hprc.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// 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.
-
-#ifndef NET_FTP_FTP_DIRECTORY_LISTING_PARSER_HPRC_H_
-#define NET_FTP_FTP_DIRECTORY_LISTING_PARSER_HPRC_H_
-#pragma once
-
-#include <queue>
-
-#include "base/basictypes.h"
-#include "base/time.h"
-#include "net/ftp/ftp_directory_listing_parser.h"
-
-namespace net {
-
-// Parser for directory listings served by HPRC,
-// see http://hprc.external.hp.com/ and http://crbug.com/56547.
-class FtpDirectoryListingParserHprc : public FtpDirectoryListingParser {
- public:
- // Constructor. When we need to provide the last modification time
- // that we don't know, |current_time| will be used. This allows passing
- // a specific date during testing.
- explicit FtpDirectoryListingParserHprc(const base::Time& current_time);
- virtual ~FtpDirectoryListingParserHprc();
-
- // FtpDirectoryListingParser methods:
- virtual FtpServerType GetServerType() const;
- virtual bool ConsumeLine(const string16& line);
- virtual bool OnEndOfInput();
- virtual bool EntryAvailable() const;
- virtual FtpDirectoryListingEntry PopEntry();
-
- private:
- // Store the current time. We use it in place of last modification time
- // that is unknown (the server doesn't send it).
- const base::Time current_time_;
-
- std::queue<FtpDirectoryListingEntry> entries_;
-
- DISALLOW_COPY_AND_ASSIGN(FtpDirectoryListingParserHprc);
-};
-
-} // namespace net
-
-#endif // NET_FTP_FTP_DIRECTORY_LISTING_PARSER_HPRC_H_
diff --git a/net/ftp/ftp_directory_listing_parser_hprc_unittest.cc b/net/ftp/ftp_directory_listing_parser_hprc_unittest.cc
deleted file mode 100644
index bd057e9..0000000
--- a/net/ftp/ftp_directory_listing_parser_hprc_unittest.cc
+++ /dev/null
@@ -1,46 +0,0 @@
-// 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.
-
-#include "net/ftp/ftp_directory_listing_parser_unittest.h"
-
-#include "base/format_macros.h"
-#include "base/string_util.h"
-#include "base/stringprintf.h"
-#include "net/ftp/ftp_directory_listing_parser_hprc.h"
-
-namespace {
-
-typedef net::FtpDirectoryListingParserTest FtpDirectoryListingParserHprcTest;
-
-TEST_F(FtpDirectoryListingParserHprcTest, Good) {
- const struct SingleLineTestData good_cases[] = {
- { " .welcome",
- net::FtpDirectoryListingEntry::FILE, ".welcome", 0,
- 1994, 11, 15, 12, 45 },
- };
- for (size_t i = 0; i < arraysize(good_cases); i++) {
- SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
- good_cases[i].input));
-
- net::FtpDirectoryListingParserHprc parser(GetMockCurrentTime());
- RunSingleLineTestCase(&parser, good_cases[i]);
- }
-}
-
-TEST_F(FtpDirectoryListingParserHprcTest, Bad) {
- const char* bad_cases[] = {
- "",
- "test",
- "-rw-r--r-- 1 ftp ftp 528 Nov 01 2007 README",
- "d [RWCEAFMS] ftpadmin 512 Jan 29 2004 pub",
- "TEST.DIR;1 1 4-MAR-1999 22:14:34 [UCX$NOBO,ANONYMOUS] (RWE,RWE,RWE,RWE)",
- "type=dir;modify=20010414155237;UNIX.mode=0555;unique=6ag5b4e400; etc",
- };
- for (size_t i = 0; i < arraysize(bad_cases); i++) {
- net::FtpDirectoryListingParserHprc parser(GetMockCurrentTime());
- EXPECT_FALSE(parser.ConsumeLine(UTF8ToUTF16(bad_cases[i]))) << bad_cases[i];
- }
-}
-
-} // namespace
diff --git a/net/ftp/ftp_directory_listing_parser_ls.cc b/net/ftp/ftp_directory_listing_parser_ls.cc
index 40546c8..9660eab 100644
--- a/net/ftp/ftp_directory_listing_parser_ls.cc
+++ b/net/ftp/ftp_directory_listing_parser_ls.cc
@@ -91,6 +91,10 @@ FtpDirectoryListingParserLs::FtpDirectoryListingParserLs(
FtpDirectoryListingParserLs::~FtpDirectoryListingParserLs() {}
+FtpServerType FtpDirectoryListingParserLs::GetServerType() const {
+ return SERVER_LS;
+}
+
bool FtpDirectoryListingParserLs::ConsumeLine(const string16& line) {
if (line.empty() && !received_nonempty_line_) {
// Allow empty lines only at the beginning of the listing. For example VMS
diff --git a/net/ftp/ftp_directory_listing_parser_ls.h b/net/ftp/ftp_directory_listing_parser_ls.h
index 6cb3655..3004f70 100644
--- a/net/ftp/ftp_directory_listing_parser_ls.h
+++ b/net/ftp/ftp_directory_listing_parser_ls.h
@@ -23,7 +23,7 @@ class FtpDirectoryListingParserLs : public FtpDirectoryListingParser {
virtual ~FtpDirectoryListingParserLs();
// FtpDirectoryListingParser methods:
- virtual FtpServerType GetServerType() const { return SERVER_LS; }
+ virtual FtpServerType GetServerType() const;
virtual bool ConsumeLine(const string16& line);
virtual bool OnEndOfInput();
virtual bool EntryAvailable() const;
diff --git a/net/ftp/ftp_directory_listing_parser_mlsd.cc b/net/ftp/ftp_directory_listing_parser_mlsd.cc
deleted file mode 100644
index d8ae618..0000000
--- a/net/ftp/ftp_directory_listing_parser_mlsd.cc
+++ /dev/null
@@ -1,142 +0,0 @@
-// 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.
-
-#include "net/ftp/ftp_directory_listing_parser_mlsd.h"
-
-#include <map>
-#include <vector>
-
-#include "base/stl_util-inl.h"
-#include "base/string_number_conversions.h"
-#include "base/string_split.h"
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-
-// You can read the specification of the MLSD format at
-// http://tools.ietf.org/html/rfc3659#page-23.
-
-namespace {
-
-// The MLSD date listing is specified at
-// http://tools.ietf.org/html/rfc3659#page-6.
-bool MlsdDateListingToTime(const string16& text, base::Time* time) {
- base::Time::Exploded time_exploded = { 0 };
-
- // We will only test 12 characters, but RFC-3659 requires 14 (we ignore the
- // last two digits, which contain the number of seconds).
- if (text.length() < 14)
- return false;
-
- if (!base::StringToInt(text.begin(), text.begin() + 4, &time_exploded.year))
- return false;
- if (!base::StringToInt(text.begin() + 4,
- text.begin() + 6,
- &time_exploded.month))
- return false;
- if (!base::StringToInt(text.begin() + 6,
- text.begin() + 8,
- &time_exploded.day_of_month))
- return false;
- if (!base::StringToInt(text.begin() + 8,
- text.begin() + 10,
- &time_exploded.hour))
- return false;
- if (!base::StringToInt(text.begin() + 10,
- text.begin() + 12,
- &time_exploded.minute))
- return false;
-
- // We don't know the time zone of the server, so just use local time.
- *time = base::Time::FromLocalExploded(time_exploded);
- return true;
-}
-
-} // namespace
-
-namespace net {
-
-FtpDirectoryListingParserMlsd::FtpDirectoryListingParserMlsd() {}
-
-FtpDirectoryListingParserMlsd::~FtpDirectoryListingParserMlsd() {}
-
-bool FtpDirectoryListingParserMlsd::ConsumeLine(const string16& line) {
- // The first space indicates where the filename begins.
- string16::size_type first_space_pos = line.find(' ');
- if (first_space_pos == string16::npos || first_space_pos < 1)
- return false;
-
- string16 facts_string = line.substr(0, first_space_pos - 1);
- string16 filename = line.substr(first_space_pos + 1);
- std::vector<string16> facts_split;
- base::SplitString(facts_string, ';', &facts_split);
-
- const char* keys[] = {
- "modify",
- "size",
- "type",
- };
-
- std::map<std::string, string16> facts;
- for (std::vector<string16>::const_iterator i = facts_split.begin();
- i != facts_split.end(); ++i) {
- string16::size_type equal_sign_pos = i->find('=');
- if (equal_sign_pos == string16::npos)
- return false;
- string16 key = i->substr(0, equal_sign_pos);
- string16 value = i->substr(equal_sign_pos + 1);
-
- // If we're interested in a key, record its value. Note that we don't detect
- // a case when the server is sending duplicate keys. We're not validating
- // the input, just parsing it.
- for (size_t j = 0; j < arraysize(keys); j++)
- if (LowerCaseEqualsASCII(key, keys[j]))
- facts[keys[j]] = value;
- }
- if (!ContainsKey(facts, "type"))
- return false;
-
- FtpDirectoryListingEntry entry;
- entry.name = filename;
-
- if (LowerCaseEqualsASCII(facts["type"], "dir")) {
- entry.type = FtpDirectoryListingEntry::DIRECTORY;
- entry.size = -1;
- } else if (LowerCaseEqualsASCII(facts["type"], "file")) {
- entry.type = FtpDirectoryListingEntry::FILE;
- if (!ContainsKey(facts, "size"))
- return false;
- if (!base::StringToInt64(facts["size"], &entry.size))
- return false;
- } else {
- // Ignore other types of entries. They are either not interesting for us
- // (cdir, pdir), or not regular files (OS-specific types). There is no
- // specific type for symlink. Symlinks get a type of their target.
- return true;
- }
-
- if (!ContainsKey(facts, "modify"))
- return false;
- if (!MlsdDateListingToTime(facts["modify"], &entry.last_modified))
- return false;
-
- entries_.push(entry);
- return true;
-}
-
-bool FtpDirectoryListingParserMlsd::OnEndOfInput() {
- return true;
-}
-
-bool FtpDirectoryListingParserMlsd::EntryAvailable() const {
- return !entries_.empty();
-}
-
-FtpDirectoryListingEntry FtpDirectoryListingParserMlsd::PopEntry() {
- DCHECK(EntryAvailable());
- FtpDirectoryListingEntry entry = entries_.front();
- entries_.pop();
- return entry;
-}
-
-} // namespace net
diff --git a/net/ftp/ftp_directory_listing_parser_mlsd.h b/net/ftp/ftp_directory_listing_parser_mlsd.h
deleted file mode 100644
index c3e3acf..0000000
--- a/net/ftp/ftp_directory_listing_parser_mlsd.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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.
-
-#ifndef NET_FTP_FTP_DIRECTORY_LISTING_PARSER_MLSD_H_
-#define NET_FTP_FTP_DIRECTORY_LISTING_PARSER_MLSD_H_
-#pragma once
-
-#include <queue>
-
-#include "net/ftp/ftp_directory_listing_parser.h"
-
-namespace net {
-
-// Parser for MLSD directory listing (RFC-3659). For more info see
-// http://tools.ietf.org/html/rfc3659#page-23.
-class FtpDirectoryListingParserMlsd : public FtpDirectoryListingParser {
- public:
- FtpDirectoryListingParserMlsd();
- virtual ~FtpDirectoryListingParserMlsd();
-
- // FtpDirectoryListingParser methods:
- virtual FtpServerType GetServerType() const { return SERVER_MLSD; }
- virtual bool ConsumeLine(const string16& line);
- virtual bool OnEndOfInput();
- virtual bool EntryAvailable() const;
- virtual FtpDirectoryListingEntry PopEntry();
-
- private:
- std::queue<FtpDirectoryListingEntry> entries_;
-
- DISALLOW_COPY_AND_ASSIGN(FtpDirectoryListingParserMlsd);
-};
-
-} // namespace net
-
-#endif // NET_FTP_FTP_DIRECTORY_LISTING_PARSER_MLSD_H_
diff --git a/net/ftp/ftp_directory_listing_parser_mlsd_unittest.cc b/net/ftp/ftp_directory_listing_parser_mlsd_unittest.cc
deleted file mode 100644
index f65abc2..0000000
--- a/net/ftp/ftp_directory_listing_parser_mlsd_unittest.cc
+++ /dev/null
@@ -1,68 +0,0 @@
-// 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.
-
-#include "net/ftp/ftp_directory_listing_parser_unittest.h"
-
-#include "base/format_macros.h"
-#include "base/string_util.h"
-#include "base/stringprintf.h"
-#include "net/ftp/ftp_directory_listing_parser_mlsd.h"
-
-namespace {
-
-typedef net::FtpDirectoryListingParserTest FtpDirectoryListingParserMlsdTest;
-
-TEST_F(FtpDirectoryListingParserMlsdTest, Good) {
- const struct SingleLineTestData good_cases[] = {
- { "type=file;size=380565;modify=20030606190749; README",
- net::FtpDirectoryListingEntry::FILE, "README", 380565,
- 2003, 6, 6, 19, 7 },
- { "type=dir;sizd=512;modify=20031021200128; pub",
- net::FtpDirectoryListingEntry::DIRECTORY, "pub", -1,
- 2003, 10, 21, 20, 1 },
- { "type=dir;sizd=512;modify=20091009080706;UNIX.mode=0755; pub",
- net::FtpDirectoryListingEntry::DIRECTORY, "pub", -1,
- 2009, 10, 9, 8, 7 },
- { "type=dir;modify=20010414155237;UNIX.mode=0555;unique=6ag5b4e400; etc",
- net::FtpDirectoryListingEntry::DIRECTORY, "etc", -1,
- 2001, 4, 14, 15, 52 },
- };
- for (size_t i = 0; i < arraysize(good_cases); i++) {
- SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
- good_cases[i].input));
-
- net::FtpDirectoryListingParserMlsd parser;
- RunSingleLineTestCase(&parser, good_cases[i]);
- }
-}
-
-TEST_F(FtpDirectoryListingParserMlsdTest, Bad) {
- const char* bad_cases[] = {
- "",
- " ",
- " ",
- ";",
- "; ",
- " ;",
- " foo",
- "garbage",
- "total 5",
- "type=file;size=380565;modify=20030606190749;README",
- "type=file;size=380565;modify=20030606190749;",
- "type=file;size=380565;modify=20030606190749",
- "size=380565;modify=20030606190749; README",
- "type=file;modify=20030606190749; README",
- "type=file;size=380565; README",
- "type=file; size=380565; modify=20030606190749; README",
- " type=file;size=380565;modify=20030606190749; README",
- "type=file;size=garbage;modify=20030606190749; README",
- "type=file;size=380565;modify=garbage; README",
- };
- for (size_t i = 0; i < arraysize(bad_cases); i++) {
- net::FtpDirectoryListingParserMlsd parser;
- EXPECT_FALSE(parser.ConsumeLine(UTF8ToUTF16(bad_cases[i]))) << bad_cases[i];
- }
-}
-
-} // namespace
diff --git a/net/ftp/ftp_directory_listing_parser_netware.cc b/net/ftp/ftp_directory_listing_parser_netware.cc
index ab7fb6d..1801a4a 100644
--- a/net/ftp/ftp_directory_listing_parser_netware.cc
+++ b/net/ftp/ftp_directory_listing_parser_netware.cc
@@ -42,6 +42,10 @@ FtpDirectoryListingParserNetware::FtpDirectoryListingParserNetware(
FtpDirectoryListingParserNetware::~FtpDirectoryListingParserNetware() {}
+FtpServerType FtpDirectoryListingParserNetware::GetServerType() const {
+ return SERVER_NETWARE;
+}
+
bool FtpDirectoryListingParserNetware::ConsumeLine(const string16& line) {
if (!received_first_line_) {
received_first_line_ = true;
diff --git a/net/ftp/ftp_directory_listing_parser_netware.h b/net/ftp/ftp_directory_listing_parser_netware.h
index 5fdcd84..48aebfc 100644
--- a/net/ftp/ftp_directory_listing_parser_netware.h
+++ b/net/ftp/ftp_directory_listing_parser_netware.h
@@ -23,7 +23,7 @@ class FtpDirectoryListingParserNetware : public FtpDirectoryListingParser {
virtual ~FtpDirectoryListingParserNetware();
// FtpDirectoryListingParser methods:
- virtual FtpServerType GetServerType() const { return SERVER_NETWARE; }
+ virtual FtpServerType GetServerType() const;
virtual bool ConsumeLine(const string16& line);
virtual bool OnEndOfInput();
virtual bool EntryAvailable() const;
diff --git a/net/ftp/ftp_directory_listing_parser_vms.cc b/net/ftp/ftp_directory_listing_parser_vms.cc
index ed12665..c74dad0 100644
--- a/net/ftp/ftp_directory_listing_parser_vms.cc
+++ b/net/ftp/ftp_directory_listing_parser_vms.cc
@@ -170,6 +170,10 @@ FtpDirectoryListingParserVms::FtpDirectoryListingParserVms()
FtpDirectoryListingParserVms::~FtpDirectoryListingParserVms() {}
+FtpServerType FtpDirectoryListingParserVms::GetServerType() const {
+ return SERVER_VMS;
+}
+
bool FtpDirectoryListingParserVms::ConsumeLine(const string16& line) {
switch (state_) {
case STATE_INITIAL:
diff --git a/net/ftp/ftp_directory_listing_parser_vms.h b/net/ftp/ftp_directory_listing_parser_vms.h
index 12f8dc7..118365d 100644
--- a/net/ftp/ftp_directory_listing_parser_vms.h
+++ b/net/ftp/ftp_directory_listing_parser_vms.h
@@ -19,7 +19,7 @@ class FtpDirectoryListingParserVms : public FtpDirectoryListingParser {
virtual ~FtpDirectoryListingParserVms();
// FtpDirectoryListingParser methods:
- virtual FtpServerType GetServerType() const { return SERVER_VMS; }
+ virtual FtpServerType GetServerType() const;
virtual bool ConsumeLine(const string16& line);
virtual bool OnEndOfInput();
virtual bool EntryAvailable() const;
diff --git a/net/ftp/ftp_directory_listing_parser_windows.cc b/net/ftp/ftp_directory_listing_parser_windows.cc
index e321173..ef733d5 100644
--- a/net/ftp/ftp_directory_listing_parser_windows.cc
+++ b/net/ftp/ftp_directory_listing_parser_windows.cc
@@ -15,7 +15,7 @@ namespace {
bool WindowsDateListingToTime(const std::vector<string16>& columns,
base::Time* time) {
- DCHECK_LE(4U, columns.size());
+ DCHECK_LE(3U, columns.size());
base::Time::Exploded time_exploded = { 0 };
@@ -76,19 +76,26 @@ FtpDirectoryListingParserWindows::FtpDirectoryListingParserWindows() {}
FtpDirectoryListingParserWindows::~FtpDirectoryListingParserWindows() {}
+FtpServerType FtpDirectoryListingParserWindows::GetServerType() const {
+ return SERVER_WINDOWS;
+}
+
bool FtpDirectoryListingParserWindows::ConsumeLine(const string16& line) {
std::vector<string16> columns;
base::SplitString(CollapseWhitespace(line, false), ' ', &columns);
- // We may receive file names containing spaces, which can make the number of
- // columns arbitrarily large. We will handle that later. For now just make
- // sure we have all the columns that should normally be there.
- if (columns.size() < 4)
+ // Every line of the listing consists of the following:
+ //
+ // 1. date
+ // 2. time
+ // 3. size in bytes (or "<DIR>" for directories)
+ // 4. filename (may be empty or contain spaces)
+ //
+ // For now, make sure we have 1-3, and handle 4 later.
+ if (columns.size() < 3)
return false;
FtpDirectoryListingEntry entry;
- entry.name = FtpUtil::GetStringPartAfterColumns(line, 3);
-
if (EqualsASCII(columns[2], "<DIR>")) {
entry.type = FtpDirectoryListingEntry::DIRECTORY;
entry.size = -1;
@@ -103,6 +110,14 @@ bool FtpDirectoryListingParserWindows::ConsumeLine(const string16& line) {
if (!WindowsDateListingToTime(columns, &entry.last_modified))
return false;
+ entry.name = FtpUtil::GetStringPartAfterColumns(line, 3);
+ if (entry.name.empty()) {
+ // Some FTP servers send listing entries with empty names. It's not obvious
+ // how to display such an entry, so we ignore them. We don't want to make
+ // the parsing fail at this point though. Other entries can still be useful.
+ return true;
+ }
+
entries_.push(entry);
return true;
}
diff --git a/net/ftp/ftp_directory_listing_parser_windows.h b/net/ftp/ftp_directory_listing_parser_windows.h
index 91ffe36..1f029af 100644
--- a/net/ftp/ftp_directory_listing_parser_windows.h
+++ b/net/ftp/ftp_directory_listing_parser_windows.h
@@ -18,7 +18,7 @@ class FtpDirectoryListingParserWindows : public FtpDirectoryListingParser {
virtual ~FtpDirectoryListingParserWindows();
// FtpDirectoryListingParser methods:
- virtual FtpServerType GetServerType() const { return SERVER_WINDOWS; }
+ virtual FtpServerType GetServerType() const;
virtual bool ConsumeLine(const string16& line);
virtual bool OnEndOfInput();
virtual bool EntryAvailable() const;
diff --git a/net/ftp/ftp_directory_listing_parser_windows_unittest.cc b/net/ftp/ftp_directory_listing_parser_windows_unittest.cc
index 60309cb..aeb64e7 100644
--- a/net/ftp/ftp_directory_listing_parser_windows_unittest.cc
+++ b/net/ftp/ftp_directory_listing_parser_windows_unittest.cc
@@ -64,15 +64,42 @@ TEST_F(FtpDirectoryListingParserWindowsTest, Good) {
}
}
+TEST_F(FtpDirectoryListingParserWindowsTest, Ignored) {
+ const char* ignored_cases[] = {
+ "12-07-10 12:05AM <DIR> ", // http://crbug.com/66097
+ "12-07-10 12:05AM 1234 ",
+ };
+ for (size_t i = 0; i < arraysize(ignored_cases); i++) {
+ SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
+ ignored_cases[i]));
+
+ net::FtpDirectoryListingParserWindows parser;
+ EXPECT_TRUE(parser.ConsumeLine(UTF8ToUTF16(ignored_cases[i])));
+ EXPECT_FALSE(parser.EntryAvailable());
+ EXPECT_TRUE(parser.OnEndOfInput());
+ EXPECT_FALSE(parser.EntryAvailable());
+ }
+}
+
TEST_F(FtpDirectoryListingParserWindowsTest, Bad) {
const char* bad_cases[] = {
"",
"garbage",
+ "11-02-09 05:32PM <GARBAGE>",
"11-02-09 05:32PM <GARBAGE> NT",
+ "11-02-09 05:32 <DIR>",
+ "11-FEB-09 05:32PM <DIR>",
+ "11-02 05:32PM <DIR>",
+ "11-02-09 05:32PM -1",
"11-02-09 05:32 <DIR> NT",
"11-FEB-09 05:32PM <DIR> NT",
"11-02 05:32PM <DIR> NT",
"11-02-09 05:32PM -1 NT",
+ "99-25-10 12:00AM 0",
+ "12-99-10 12:00AM 0",
+ "12-25-10 99:00AM 0",
+ "12-25-10 12:99AM 0",
+ "12-25-10 12:00ZM 0",
"99-25-10 12:00AM 0 months out of range",
"12-99-10 12:00AM 0 days out of range",
"12-25-10 99:00AM 0 hours out of range",
diff --git a/net/ftp/ftp_network_transaction.cc b/net/ftp/ftp_network_transaction.cc
index bfda5bd..0285e08 100644
--- a/net/ftp/ftp_network_transaction.cc
+++ b/net/ftp/ftp_network_transaction.cc
@@ -371,9 +371,6 @@ int FtpNetworkTransaction::ProcessCtrlResponse() {
case COMMAND_CWD:
rv = ProcessResponseCWD(response);
break;
- case COMMAND_MLSD:
- rv = ProcessResponseMLSD(response);
- break;
case COMMAND_LIST:
rv = ProcessResponseLIST(response);
break;
@@ -394,9 +391,6 @@ int FtpNetworkTransaction::ProcessCtrlResponse() {
case COMMAND_RETR:
rv = ProcessResponseRETR(response);
break;
- case COMMAND_MLSD:
- rv = ProcessResponseMLSD(response);
- break;
case COMMAND_LIST:
rv = ProcessResponseLIST(response);
break;
@@ -573,10 +567,6 @@ int FtpNetworkTransaction::DoLoop(int result) {
DCHECK(rv == OK);
rv = DoCtrlWriteCWD();
break;
- case STATE_CTRL_WRITE_MLSD:
- DCHECK(rv == 0);
- rv = DoCtrlWriteMLSD();
- break;
case STATE_CTRL_WRITE_LIST:
DCHECK(rv == OK);
rv = DoCtrlWriteLIST();
@@ -1073,7 +1063,7 @@ int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) {
case ERROR_CLASS_INITIATED:
return Stop(ERR_INVALID_RESPONSE);
case ERROR_CLASS_OK:
- next_state_ = STATE_CTRL_WRITE_MLSD;
+ next_state_ = STATE_CTRL_WRITE_LIST;
break;
case ERROR_CLASS_INFO_NEEDED:
return Stop(ERR_INVALID_RESPONSE);
@@ -1104,41 +1094,6 @@ int FtpNetworkTransaction::ProcessResponseCWD(const FtpCtrlResponse& response) {
return OK;
}
-// MLSD command
-int FtpNetworkTransaction::DoCtrlWriteMLSD() {
- next_state_ = STATE_CTRL_READ;
- return SendFtpCommand("MLSD", COMMAND_MLSD);
-}
-
-int FtpNetworkTransaction::ProcessResponseMLSD(
- const FtpCtrlResponse& response) {
- switch (GetErrorClass(response.status_code)) {
- case ERROR_CLASS_INITIATED:
- // We want the client to start reading the response at this point.
- // It got here either through Start or RestartWithAuth. We want that
- // method to complete. Not setting next state here will make DoLoop exit
- // and in turn make Start/RestartWithAuth complete.
- response_.is_directory_listing = true;
- break;
- case ERROR_CLASS_OK:
- response_.is_directory_listing = true;
- next_state_ = STATE_CTRL_WRITE_QUIT;
- break;
- case ERROR_CLASS_INFO_NEEDED:
- return Stop(ERR_INVALID_RESPONSE);
- case ERROR_CLASS_TRANSIENT_ERROR:
- case ERROR_CLASS_PERMANENT_ERROR:
- // Fallback to the LIST command, more widely supported,
- // but without a specified output format.
- next_state_ = STATE_CTRL_WRITE_LIST;
- break;
- default:
- NOTREACHED();
- return Stop(ERR_UNEXPECTED);
- }
- return OK;
-}
-
// LIST command
int FtpNetworkTransaction::DoCtrlWriteLIST() {
std::string command(system_type_ == SYSTEM_TYPE_VMS ? "LIST *.*;0" : "LIST");
diff --git a/net/ftp/ftp_network_transaction.h b/net/ftp/ftp_network_transaction.h
index 5bad335..678308a 100644
--- a/net/ftp/ftp_network_transaction.h
+++ b/net/ftp/ftp_network_transaction.h
@@ -58,7 +58,6 @@ class FtpNetworkTransaction : public FtpTransaction {
COMMAND_SIZE,
COMMAND_RETR,
COMMAND_CWD,
- COMMAND_MLSD,
COMMAND_LIST,
COMMAND_QUIT,
};
@@ -142,8 +141,6 @@ class FtpNetworkTransaction : public FtpTransaction {
int ProcessResponseSIZE(const FtpCtrlResponse& response);
int DoCtrlWriteCWD();
int ProcessResponseCWD(const FtpCtrlResponse& response);
- int DoCtrlWriteMLSD();
- int ProcessResponseMLSD(const FtpCtrlResponse& response);
int DoCtrlWriteLIST();
int ProcessResponseLIST(const FtpCtrlResponse& response);
int DoCtrlWriteQUIT();
@@ -234,7 +231,6 @@ class FtpNetworkTransaction : public FtpTransaction {
STATE_CTRL_WRITE_RETR,
STATE_CTRL_WRITE_SIZE,
STATE_CTRL_WRITE_CWD,
- STATE_CTRL_WRITE_MLSD,
STATE_CTRL_WRITE_LIST,
STATE_CTRL_WRITE_QUIT,
// Data connection states:
diff --git a/net/ftp/ftp_network_transaction_unittest.cc b/net/ftp/ftp_network_transaction_unittest.cc
index 1c22c5b..8da3baf 100644
--- a/net/ftp/ftp_network_transaction_unittest.cc
+++ b/net/ftp/ftp_network_transaction_unittest.cc
@@ -41,7 +41,6 @@ class FtpSocketDataProvider : public DynamicSocketDataProvider {
PRE_SIZE,
PRE_EPSV,
PRE_PASV,
- PRE_MLSD,
PRE_LIST,
PRE_RETR,
PRE_CWD,
@@ -189,11 +188,7 @@ class FtpSocketDataProviderDirectoryListing : public FtpSocketDataProvider {
return Verify("SIZE /\r\n", data, PRE_CWD,
"550 I can only retrieve regular files\r\n");
case PRE_CWD:
- return Verify("CWD /\r\n", data, PRE_MLSD, "200 OK\r\n");
- case PRE_MLSD:
- return Verify("MLSD\r\n", data, PRE_QUIT,
- "150 Accepted data connection\r\n"
- "226 MLSD complete\r\n");
+ return Verify("CWD /\r\n", data, PRE_LIST, "200 OK\r\n");
case PRE_LIST:
return Verify("LIST\r\n", data, PRE_QUIT, "200 OK\r\n");
default:
@@ -275,10 +270,8 @@ class FtpSocketDataProviderVMSDirectoryListing : public FtpSocketDataProvider {
return Verify("SIZE ANONYMOUS_ROOT:[000000]dir\r\n", data, PRE_CWD,
"550 I can only retrieve regular files\r\n");
case PRE_CWD:
- return Verify("CWD ANONYMOUS_ROOT:[dir]\r\n", data, PRE_MLSD,
+ return Verify("CWD ANONYMOUS_ROOT:[dir]\r\n", data, PRE_LIST,
"200 OK\r\n");
- case PRE_MLSD:
- return Verify("MLSD\r\n", data, PRE_LIST, "500 Invalid command\r\n");
case PRE_LIST:
return Verify("LIST *.*;0\r\n", data, PRE_QUIT, "200 OK\r\n");
default:
@@ -315,10 +308,8 @@ class FtpSocketDataProviderVMSDirectoryListingRootDirectory
return Verify("SIZE ANONYMOUS_ROOT\r\n", data, PRE_CWD,
"550 I can only retrieve regular files\r\n");
case PRE_CWD:
- return Verify("CWD ANONYMOUS_ROOT:[000000]\r\n", data, PRE_MLSD,
+ return Verify("CWD ANONYMOUS_ROOT:[000000]\r\n", data, PRE_LIST,
"200 OK\r\n");
- case PRE_MLSD:
- return Verify("MLSD\r\n", data, PRE_LIST, "500 Invalid command\r\n");
case PRE_LIST:
return Verify("LIST *.*;0\r\n", data, PRE_QUIT, "200 OK\r\n");
default:
@@ -1329,16 +1320,6 @@ TEST_F(FtpNetworkTransactionTest, DirectoryTransactionFailCwd) {
ERR_FTP_FAILED);
}
-TEST_F(FtpNetworkTransactionTest, DirectoryTransactionFailMlsd) {
- FtpSocketDataProviderDirectoryListing ctrl_socket;
- TransactionFailHelper(&ctrl_socket,
- "ftp://host",
- FtpSocketDataProvider::PRE_MLSD,
- FtpSocketDataProvider::PRE_LIST,
- "500 Unrecognized command\r\n",
- OK);
-}
-
TEST_F(FtpNetworkTransactionTest, DirectoryTransactionFailList) {
FtpSocketDataProviderVMSDirectoryListing ctrl_socket;
// Use unallocated 599 FTP error code to make sure it falls into the generic
diff --git a/net/ftp/ftp_server_type_histograms.h b/net/ftp/ftp_server_type_histograms.h
index 6a856b1..e89ad3d 100644
--- a/net/ftp/ftp_server_type_histograms.h
+++ b/net/ftp/ftp_server_type_histograms.h
@@ -24,8 +24,8 @@ enum FtpServerType {
SERVER_WINDOWS = 10, // Server using Windows listing style.
SERVER_VMS = 11, // Server using VMS listing style.
SERVER_NETWARE = 12, // Server using Netware listing style.
- SERVER_MLSD = 13, // Server using MLSD listing (RFC-3659).
- SERVER_HPRC = 14, // Server using HPRC listing (http://crbug.com/56547).
+
+ // Types 13-14 are RESERVED (were earlier used for MLSD listings).
NUM_OF_SERVER_TYPES
};
diff --git a/net/http/des.cc b/net/http/des.cc
index 21a8455..2a5ffa0 100644
--- a/net/http/des.cc
+++ b/net/http/des.cc
@@ -6,7 +6,10 @@
#include "base/logging.h"
-#if defined(USE_NSS)
+#if defined(USE_OPENSSL)
+#include <openssl/des.h>
+#include "base/openssl_util.h"
+#elif defined(USE_NSS)
#include <nss.h>
#include <pk11pub.h>
#include "base/nss_util.h"
@@ -92,10 +95,15 @@ void DESMakeKey(const uint8* raw, uint8* key) {
#if defined(USE_OPENSSL)
void DESEncrypt(const uint8* key, const uint8* src, uint8* hash) {
+<<<<<<< HEAD
#ifndef ANDROID
base::EnsureOpenSSLInit();
#endif
+=======
+ base::EnsureOpenSSLInit();
+
+>>>>>>> chromium.org at r10.0.621.0
DES_key_schedule ks;
DES_set_key_unchecked(
reinterpret_cast<const_DES_cblock*>(const_cast<uint8*>(key)), &ks);
diff --git a/net/http/disk_cache_based_ssl_host_info.cc b/net/http/disk_cache_based_ssl_host_info.cc
index cd1cac8..1b1dfaf 100644
--- a/net/http/disk_cache_based_ssl_host_info.cc
+++ b/net/http/disk_cache_based_ssl_host_info.cc
@@ -9,6 +9,7 @@
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/http/http_cache.h"
+#include "net/http/http_network_session.h"
namespace net {
@@ -16,10 +17,11 @@ DiskCacheBasedSSLHostInfo::DiskCacheBasedSSLHostInfo(
const std::string& hostname,
const SSLConfig& ssl_config,
HttpCache* http_cache)
- : SSLHostInfo(hostname, ssl_config),
- callback_(new CancelableCompletionCallback<DiskCacheBasedSSLHostInfo>(
- ALLOW_THIS_IN_INITIALIZER_LIST(this),
- &DiskCacheBasedSSLHostInfo::DoLoop)),
+ : SSLHostInfo(hostname, ssl_config,
+ http_cache->network_layer()->GetSession()->cert_verifier()),
+ weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
+ callback_(new CallbackImpl(weak_ptr_factory_.GetWeakPtr(),
+ &DiskCacheBasedSSLHostInfo::DoLoop)),
state_(GET_BACKEND),
ready_(false),
hostname_(hostname),
@@ -39,7 +41,8 @@ DiskCacheBasedSSLHostInfo::~DiskCacheBasedSSLHostInfo() {
DCHECK(!user_callback_);
if (entry_)
entry_->Close();
- callback_->Cancel();
+ if (!IsCallbackPending())
+ delete callback_;
}
std::string DiskCacheBasedSSLHostInfo::key() const {
@@ -92,13 +95,27 @@ void DiskCacheBasedSSLHostInfo::DoLoop(int rv) {
} while (rv != ERR_IO_PENDING && state_ != NONE);
}
+bool DiskCacheBasedSSLHostInfo::IsCallbackPending() const {
+ switch (state_) {
+ case GET_BACKEND_COMPLETE:
+ case OPEN_COMPLETE:
+ case READ_COMPLETE:
+ case CREATE_COMPLETE:
+ case WRITE_COMPLETE:
+ return true;
+ default:
+ return false;
+ }
+}
+
int DiskCacheBasedSSLHostInfo::DoGetBackend() {
state_ = GET_BACKEND_COMPLETE;
- return http_cache_->GetBackend(&backend_, callback_.get());
+ return http_cache_->GetBackend(callback_->backend_pointer(), callback_);
}
int DiskCacheBasedSSLHostInfo::DoGetBackendComplete(int rv) {
if (rv == OK) {
+ backend_ = callback_->backend();
state_ = OPEN;
} else {
state_ = WAIT_FOR_DATA_READY_DONE;
@@ -108,11 +125,12 @@ int DiskCacheBasedSSLHostInfo::DoGetBackendComplete(int rv) {
int DiskCacheBasedSSLHostInfo::DoOpen() {
state_ = OPEN_COMPLETE;
- return backend_->OpenEntry(key(), &entry_, callback_.get());
+ return backend_->OpenEntry(key(), callback_->entry_pointer(), callback_);
}
int DiskCacheBasedSSLHostInfo::DoOpenComplete(int rv) {
if (rv == OK) {
+ entry_ = callback_->entry();
state_ = READ;
} else {
state_ = WAIT_FOR_DATA_READY_DONE;
@@ -131,7 +149,7 @@ int DiskCacheBasedSSLHostInfo::DoRead() {
read_buffer_ = new IOBuffer(size);
state_ = READ_COMPLETE;
return entry_->ReadData(0 /* index */, 0 /* offset */, read_buffer_,
- size, callback_.get());
+ size, callback_);
}
int DiskCacheBasedSSLHostInfo::DoReadComplete(int rv) {
@@ -195,13 +213,14 @@ void DiskCacheBasedSSLHostInfo::Persist() {
int DiskCacheBasedSSLHostInfo::DoCreate() {
DCHECK(entry_ == NULL);
state_ = CREATE_COMPLETE;
- return backend_->CreateEntry(key(), &entry_, callback_.get());
+ return backend_->CreateEntry(key(), callback_->entry_pointer(), callback_);
}
int DiskCacheBasedSSLHostInfo::DoCreateComplete(int rv) {
if (rv != OK) {
state_ = SET_DONE;
} else {
+ entry_ = callback_->entry();
state_ = WRITE;
}
return OK;
@@ -211,9 +230,9 @@ int DiskCacheBasedSSLHostInfo::DoWrite() {
write_buffer_ = new IOBuffer(new_data_.size());
memcpy(write_buffer_->data(), new_data_.data(), new_data_.size());
state_ = WRITE_COMPLETE;
+
return entry_->WriteData(0 /* index */, 0 /* offset */, write_buffer_,
- new_data_.size(), callback_.get(),
- true /* truncate */);
+ new_data_.size(), callback_, true /* truncate */);
}
int DiskCacheBasedSSLHostInfo::DoWriteComplete(int rv) {
diff --git a/net/http/disk_cache_based_ssl_host_info.h b/net/http/disk_cache_based_ssl_host_info.h
index 1d53b90..fee0a5c 100644
--- a/net/http/disk_cache_based_ssl_host_info.h
+++ b/net/http/disk_cache_based_ssl_host_info.h
@@ -10,6 +10,7 @@
#include "base/lock.h"
#include "base/non_thread_safe.h"
#include "base/scoped_ptr.h"
+#include "base/weak_ptr.h"
#include "net/base/completion_callback.h"
#include "net/disk_cache/disk_cache.h"
#include "net/socket/ssl_host_info.h"
@@ -36,7 +37,53 @@ class DiskCacheBasedSSLHostInfo : public SSLHostInfo,
virtual void Persist();
private:
+ enum State {
+ GET_BACKEND,
+ GET_BACKEND_COMPLETE,
+ OPEN,
+ OPEN_COMPLETE,
+ READ,
+ READ_COMPLETE,
+ WAIT_FOR_DATA_READY_DONE,
+ CREATE,
+ CREATE_COMPLETE,
+ WRITE,
+ WRITE_COMPLETE,
+ SET_DONE,
+ NONE,
+ };
+
~DiskCacheBasedSSLHostInfo();
+
+ class CallbackImpl : public CallbackRunner<Tuple1<int> > {
+ public:
+ CallbackImpl(const base::WeakPtr<DiskCacheBasedSSLHostInfo>& obj,
+ void (DiskCacheBasedSSLHostInfo::*meth) (int))
+ : obj_(obj),
+ meth_(meth) {
+ }
+
+ virtual void RunWithParams(const Tuple1<int>& params) {
+ if (!obj_) {
+ delete this;
+ } else {
+ DispatchToMethod(obj_.get(), meth_, params);
+ }
+ }
+
+ disk_cache::Backend** backend_pointer() { return &backend_; }
+ disk_cache::Entry** entry_pointer() { return &entry_; }
+ disk_cache::Backend* backend() const { return backend_; }
+ disk_cache::Entry* entry() const { return entry_; }
+
+ private:
+ base::WeakPtr<DiskCacheBasedSSLHostInfo> obj_;
+ void (DiskCacheBasedSSLHostInfo::*meth_) (int);
+
+ disk_cache::Backend* backend_;
+ disk_cache::Entry* entry_;
+ };
+
std::string key() const;
void DoLoop(int rv);
@@ -58,31 +105,18 @@ class DiskCacheBasedSSLHostInfo : public SSLHostInfo,
// SetDone is the terminal state of the write operation.
int SetDone();
- enum State {
- GET_BACKEND,
- GET_BACKEND_COMPLETE,
- OPEN,
- OPEN_COMPLETE,
- READ,
- READ_COMPLETE,
- WAIT_FOR_DATA_READY_DONE,
- CREATE,
- CREATE_COMPLETE,
- WRITE,
- WRITE_COMPLETE,
- SET_DONE,
- NONE,
- };
+ // IsCallbackPending returns true if we have a pending callback.
+ bool IsCallbackPending() const;
- scoped_refptr<CancelableCompletionCallback<DiskCacheBasedSSLHostInfo> >
- callback_;
+ base::WeakPtrFactory<DiskCacheBasedSSLHostInfo> weak_ptr_factory_;
+ CallbackImpl* callback_;
State state_;
bool ready_;
std::string new_data_;
const std::string hostname_;
HttpCache* const http_cache_;
disk_cache::Backend* backend_;
- disk_cache::Entry *entry_;
+ disk_cache::Entry* entry_;
CompletionCallback* user_callback_;
scoped_refptr<net::IOBuffer> read_buffer_;
scoped_refptr<net::IOBuffer> write_buffer_;
diff --git a/net/http/http_alternate_protocols.h b/net/http/http_alternate_protocols.h
index e06e13a..d5f9d77 100644
--- a/net/http/http_alternate_protocols.h
+++ b/net/http/http_alternate_protocols.h
@@ -26,6 +26,7 @@ class HttpAlternateProtocols {
NPN_SPDY_2,
NUM_ALTERNATE_PROTOCOLS,
BROKEN, // The alternate protocol is known to be broken.
+ UNINITIALIZED,
};
struct PortProtocolPair {
diff --git a/net/http/http_auth_cache_unittest.cc b/net/http/http_auth_cache_unittest.cc
index 5773d15..2c28969 100644
--- a/net/http/http_auth_cache_unittest.cc
+++ b/net/http/http_auth_cache_unittest.cc
@@ -29,7 +29,7 @@ class MockAuthHandler : public HttpAuthHandler {
properties_ = 0;
}
- HttpAuth::AuthorizationResult HandleAnotherChallenge(
+ virtual HttpAuth::AuthorizationResult HandleAnotherChallenge(
HttpAuth::ChallengeTokenizer* challenge) {
return HttpAuth::AUTHORIZATION_RESULT_REJECT;
}
diff --git a/net/http/http_auth_controller.cc b/net/http/http_auth_controller.cc
index e4e2dd4..e97d06e 100644
--- a/net/http/http_auth_controller.cc
+++ b/net/http/http_auth_controller.cc
@@ -52,10 +52,36 @@ std::string AuthChallengeLogMessage(HttpResponseHeaders* headers) {
enum AuthEvent {
AUTH_EVENT_START = 0,
- AUTH_EVENT_REJECT = 1,
- AUTH_EVENT_MAX = 2,
+ AUTH_EVENT_REJECT,
+ AUTH_EVENT_MAX,
};
+enum AuthTarget {
+ AUTH_TARGET_PROXY = 0,
+ AUTH_TARGET_SECURE_PROXY,
+ AUTH_TARGET_SERVER,
+ AUTH_TARGET_SECURE_SERVER,
+ AUTH_TARGET_MAX,
+};
+
+AuthTarget DetermineAuthTarget(const HttpAuthHandler* handler) {
+ switch (handler->target()) {
+ case HttpAuth::AUTH_PROXY:
+ if (handler->origin().SchemeIsSecure())
+ return AUTH_TARGET_SECURE_PROXY;
+ else
+ return AUTH_TARGET_PROXY;
+ case HttpAuth::AUTH_SERVER:
+ if (handler->origin().SchemeIsSecure())
+ return AUTH_TARGET_SECURE_SERVER;
+ else
+ return AUTH_TARGET_SERVER;
+ default:
+ NOTREACHED();
+ return AUTH_TARGET_MAX;
+ }
+}
+
// Records the number of authentication events per authentication scheme.
void HistogramAuthEvent(HttpAuthHandler* handler, AuthEvent auth_event) {
#if !defined(NDEBUG)
@@ -68,8 +94,12 @@ void HistogramAuthEvent(HttpAuthHandler* handler, AuthEvent auth_event) {
DCHECK_EQ(first_thread, PlatformThread::CurrentId());
#endif
- // This assumes that the schemes maintain a consistent score from
- // 1 to 4 inclusive. The results map to:
+ HttpAuthHandler::AuthScheme auth_scheme = handler->auth_scheme();
+ DCHECK(auth_scheme >= 0 && auth_scheme < HttpAuthHandler::AUTH_SCHEME_MAX);
+
+ // Record start and rejection events for authentication.
+ //
+ // The results map to:
// Basic Start: 0
// Basic Reject: 1
// Digest Start: 2
@@ -78,12 +108,41 @@ void HistogramAuthEvent(HttpAuthHandler* handler, AuthEvent auth_event) {
// NTLM Reject: 5
// Negotiate Start: 6
// Negotiate Reject: 7
- static const int kScoreMin = 1;
- static const int kScoreMax = 4;
- static const int kBucketsMax = kScoreMax * AUTH_EVENT_MAX + 1;
- DCHECK(handler->score() >= kScoreMin && handler->score() <= kScoreMax);
- int bucket = (handler->score() - kScoreMin) * AUTH_EVENT_MAX + auth_event;
- UMA_HISTOGRAM_ENUMERATION("Net.HttpAuthCount", bucket, kBucketsMax);
+ static const int kEventBucketsEnd =
+ HttpAuthHandler::AUTH_SCHEME_MAX * AUTH_EVENT_MAX;
+ int event_bucket = auth_scheme * AUTH_EVENT_MAX + auth_event;
+ DCHECK(event_bucket >= 0 && event_bucket < kEventBucketsEnd);
+ UMA_HISTOGRAM_ENUMERATION("Net.HttpAuthCount", event_bucket,
+ kEventBucketsEnd);
+
+ // Record the target of the authentication.
+ //
+ // The results map to:
+ // Basic Proxy: 0
+ // Basic Secure Proxy: 1
+ // Basic Server: 2
+ // Basic Secure Server: 3
+ // Digest Proxy: 4
+ // Digest Secure Proxy: 5
+ // Digest Server: 6
+ // Digest Secure Server: 7
+ // NTLM Proxy: 8
+ // NTLM Secure Proxy: 9
+ // NTLM Server: 10
+ // NTLM Secure Server: 11
+ // Negotiate Proxy: 12
+ // Negotiate Secure Proxy: 13
+ // Negotiate Server: 14
+ // Negotiate Secure Server: 15
+ if (auth_event != AUTH_EVENT_START)
+ return;
+ static const int kTargetBucketsEnd =
+ HttpAuthHandler::AUTH_SCHEME_MAX * AUTH_TARGET_MAX;
+ AuthTarget auth_target = DetermineAuthTarget(handler);
+ int target_bucket = auth_scheme * AUTH_TARGET_MAX + auth_target;
+ DCHECK(target_bucket >= 0 && target_bucket < kTargetBucketsEnd);
+ UMA_HISTOGRAM_ENUMERATION("Net.HttpAuthTarget", target_bucket,
+ kTargetBucketsEnd);
}
} // namespace
@@ -334,6 +393,14 @@ void HttpAuthController::ResetAuth(const string16& username,
}
}
+bool HttpAuthController::HaveAuthHandler() const {
+ return handler_.get() != NULL;
+}
+
+bool HttpAuthController::HaveAuth() const {
+ return handler_.get() && !identity_.invalid;
+}
+
void HttpAuthController::InvalidateCurrentHandler() {
DCHECK(CalledOnValidThread());
diff --git a/net/http/http_auth_controller.h b/net/http/http_auth_controller.h
index bcda707..1d0a5cd 100644
--- a/net/http/http_auth_controller.h
+++ b/net/http/http_auth_controller.h
@@ -63,13 +63,9 @@ class HttpAuthController : public base::RefCounted<HttpAuthController>,
virtual void ResetAuth(const string16& username,
const string16& password);
- virtual bool HaveAuthHandler() const {
- return handler_.get() != NULL;
- }
+ virtual bool HaveAuthHandler() const;
- virtual bool HaveAuth() const {
- return handler_.get() && !identity_.invalid;
- }
+ virtual bool HaveAuth() const;
virtual scoped_refptr<AuthChallengeInfo> auth_info();
diff --git a/net/http/http_auth_gssapi_posix.cc b/net/http/http_auth_gssapi_posix.cc
index bd2734f..c492b1b 100644
--- a/net/http/http_auth_gssapi_posix.cc
+++ b/net/http/http_auth_gssapi_posix.cc
@@ -13,6 +13,7 @@
#include "base/logging.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
+#include "base/thread_restrictions.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
@@ -446,6 +447,10 @@ base::NativeLibrary GSSAPISharedLibrary::LoadSharedLibrary() {
for (size_t i = 0; i < num_lib_names; ++i) {
const char* library_name = library_names[i];
FilePath file_path(library_name);
+
+ // TODO(asanka): Move library loading to a separate thread.
+ // http://crbug.com/66702
+ base::ThreadRestrictions::ScopedAllowIO allow_io_temporarily;
base::NativeLibrary lib = base::LoadNativeLibrary(file_path);
if (lib) {
// Only return this library if we can bind the functions we need.
diff --git a/net/http/http_auth_handler.cc b/net/http/http_auth_handler.cc
index d6e6a62..5c86d69 100644
--- a/net/http/http_auth_handler.cc
+++ b/net/http/http_auth_handler.cc
@@ -13,7 +13,8 @@
namespace net {
HttpAuthHandler::HttpAuthHandler()
- : score_(-1),
+ : auth_scheme_(AUTH_SCHEME_MAX),
+ score_(-1),
target_(HttpAuth::AUTH_NONE),
properties_(-1),
original_callback_(NULL),
@@ -50,6 +51,7 @@ bool HttpAuthHandler::InitFromChallenge(
DCHECK(!ok || !scheme().empty());
DCHECK(!ok || score_ != -1);
DCHECK(!ok || properties_ != -1);
+ DCHECK(!ok || auth_scheme_ != AUTH_SCHEME_MAX);
if (ok)
histogram_ = base::Histogram::FactoryTimeGet(
@@ -99,6 +101,14 @@ int HttpAuthHandler::GenerateAuthToken(const string16* username,
return rv;
}
+bool HttpAuthHandler::NeedsIdentity() {
+ return true;
+}
+
+bool HttpAuthHandler::AllowsDefaultCredentials() {
+ return false;
+}
+
void HttpAuthHandler::OnGenerateAuthTokenComplete(int rv) {
CompletionCallback* callback = original_callback_;
FinishGenerateAuthToken();
diff --git a/net/http/http_auth_handler.h b/net/http/http_auth_handler.h
index 908b065..b48d4c2 100644
--- a/net/http/http_auth_handler.h
+++ b/net/http/http_auth_handler.h
@@ -27,6 +27,14 @@ struct HttpRequestInfo;
// HttpAuthHandler objects are typically created by an HttpAuthHandlerFactory.
class HttpAuthHandler {
public:
+ enum AuthScheme {
+ AUTH_SCHEME_BASIC = 0,
+ AUTH_SCHEME_DIGEST,
+ AUTH_SCHEME_NTLM,
+ AUTH_SCHEME_NEGOTIATE,
+ AUTH_SCHEME_MAX,
+ };
+
HttpAuthHandler();
virtual ~HttpAuthHandler();
@@ -80,6 +88,11 @@ class HttpAuthHandler {
CompletionCallback* callback,
std::string* auth_token);
+ // The authentication scheme as an enumerated value.
+ AuthScheme auth_scheme() const {
+ return auth_scheme_;
+ }
+
// Lowercase name of the auth scheme
const std::string& scheme() const {
return scheme_;
@@ -105,6 +118,13 @@ class HttpAuthHandler {
return target_;
}
+ // Returns the proxy or server which issued the authentication challenge
+ // that this HttpAuthHandler is handling. The URL includes scheme, host, and
+ // port, but does not include path.
+ const GURL& origin() const {
+ return origin_;
+ }
+
// Returns true if the authentication scheme does not send the username and
// password in the clear.
bool encrypts_identity() const {
@@ -123,14 +143,14 @@ class HttpAuthHandler {
// requires an identity.
// TODO(wtc): Find a better way to handle a multi-round challenge-response
// sequence used by a connection-based authentication scheme.
- virtual bool NeedsIdentity() { return true; }
+ virtual bool NeedsIdentity();
// Returns whether the default credentials may be used for the |origin| passed
// into |InitFromChallenge|. If true, the user does not need to be prompted
// for username and password to establish credentials.
// NOTE: SSO is a potential security risk.
// TODO(cbentzel): Add a pointer to Firefox documentation about risk.
- virtual bool AllowsDefaultCredentials() { return false; }
+ virtual bool AllowsDefaultCredentials();
protected:
enum Property {
@@ -155,6 +175,9 @@ class HttpAuthHandler {
CompletionCallback* callback,
std::string* auth_token) = 0;
+ // The auth-scheme as an enumerated value.
+ AuthScheme auth_scheme_;
+
// The lowercase auth-scheme {"basic", "digest", "ntlm", "negotiate"}
std::string scheme_;
diff --git a/net/http/http_auth_handler_basic.cc b/net/http/http_auth_handler_basic.cc
index 35b088f..8ee775d 100644
--- a/net/http/http_auth_handler_basic.cc
+++ b/net/http/http_auth_handler_basic.cc
@@ -23,6 +23,7 @@ namespace net {
// We allow it to be compatibility with certain embedded webservers that don't
// include a realm (see http://crbug.com/20984.)
bool HttpAuthHandlerBasic::Init(HttpAuth::ChallengeTokenizer* challenge) {
+ auth_scheme_ = AUTH_SCHEME_BASIC;
scheme_ = "basic";
score_ = 1;
properties_ = 0;
diff --git a/net/http/http_auth_handler_basic.h b/net/http/http_auth_handler_basic.h
index a9031bb..a48c5d8 100644
--- a/net/http/http_auth_handler_basic.h
+++ b/net/http/http_auth_handler_basic.h
@@ -31,7 +31,7 @@ class HttpAuthHandlerBasic : public HttpAuthHandler {
scoped_ptr<HttpAuthHandler>* handler);
};
- HttpAuth::AuthorizationResult HandleAnotherChallenge(
+ virtual HttpAuth::AuthorizationResult HandleAnotherChallenge(
HttpAuth::ChallengeTokenizer* challenge);
protected:
diff --git a/net/http/http_auth_handler_digest.cc b/net/http/http_auth_handler_digest.cc
index 517558f..2b103f4 100644
--- a/net/http/http_auth_handler_digest.cc
+++ b/net/http/http_auth_handler_digest.cc
@@ -266,6 +266,7 @@ HttpAuth::AuthorizationResult HttpAuthHandlerDigest::HandleAnotherChallenge(
// webserver was not sending the realm with a BASIC challenge).
bool HttpAuthHandlerDigest::ParseChallenge(
HttpAuth::ChallengeTokenizer* challenge) {
+ auth_scheme_ = AUTH_SCHEME_DIGEST;
scheme_ = "digest";
score_ = 2;
properties_ = ENCRYPTS_IDENTITY;
diff --git a/net/http/http_auth_handler_digest.h b/net/http/http_auth_handler_digest.h
index 25cf16a..c319f5d 100644
--- a/net/http/http_auth_handler_digest.h
+++ b/net/http/http_auth_handler_digest.h
@@ -77,7 +77,7 @@ class HttpAuthHandlerDigest : public HttpAuthHandler {
scoped_ptr<const NonceGenerator> nonce_generator_;
};
- HttpAuth::AuthorizationResult HandleAnotherChallenge(
+ virtual HttpAuth::AuthorizationResult HandleAnotherChallenge(
HttpAuth::ChallengeTokenizer* challenge);
protected:
diff --git a/net/http/http_auth_handler_digest_unittest.cc b/net/http/http_auth_handler_digest_unittest.cc
index 9338bca..9b57c16 100644
--- a/net/http/http_auth_handler_digest_unittest.cc
+++ b/net/http/http_auth_handler_digest_unittest.cc
@@ -15,6 +15,73 @@
namespace net {
+namespace {
+
+const char* const kSimpleChallenge =
+ "Digest realm=\"Oblivion\", nonce=\"nonce-value\"";
+
+// RespondToChallenge creates an HttpAuthHandlerDigest for the specified
+// |challenge|, and generates a response to the challenge which is returned in
+// |token|.
+//
+// The return value indicates whether the |token| was successfully created.
+//
+// If |target| is HttpAuth::AUTH_PROXY, then |proxy_name| specifies the source
+// of the |challenge|. Otherwise, the scheme and host and port of |request_url|
+// indicates the origin of the challenge.
+bool RespondToChallenge(HttpAuth::Target target,
+ const std::string& proxy_name,
+ const std::string& request_url,
+ const std::string& challenge,
+ std::string* token) {
+ // Input validation.
+ if (token == NULL) {
+ ADD_FAILURE() << "|token| must be non-NULL";
+ return false;
+ }
+ EXPECT_TRUE(target != HttpAuth::AUTH_PROXY || !proxy_name.empty());
+ EXPECT_FALSE(request_url.empty());
+ EXPECT_FALSE(challenge.empty());
+
+ token->clear();
+ scoped_ptr<HttpAuthHandlerDigest::Factory> factory(
+ new HttpAuthHandlerDigest::Factory());
+ HttpAuthHandlerDigest::NonceGenerator* nonce_generator =
+ new HttpAuthHandlerDigest::FixedNonceGenerator("client_nonce");
+ factory->set_nonce_generator(nonce_generator);
+ scoped_ptr<HttpAuthHandler> handler;
+
+ // Create a handler for a particular challenge.
+ GURL url_origin(target == HttpAuth::AUTH_SERVER ? request_url : proxy_name);
+ int rv_create = factory->CreateAuthHandlerFromString(
+ challenge, target, url_origin.GetOrigin(), BoundNetLog(), &handler);
+ if (rv_create != OK || handler.get() == NULL) {
+ ADD_FAILURE() << "Unable to create auth handler.";
+ return false;
+ }
+
+ // Create a token in response to the challenge.
+ // NOTE: HttpAuthHandlerDigest's implementation of GenerateAuthToken always
+ // completes synchronously. That's why this test can get away with a
+ // TestCompletionCallback without an IO thread.
+ TestCompletionCallback callback;
+ scoped_ptr<HttpRequestInfo> request(new HttpRequestInfo());
+ request->url = GURL(request_url);
+ const string16 kFoo = ASCIIToUTF16("foo");
+ const string16 kBar = ASCIIToUTF16("bar");
+ int rv_generate = handler->GenerateAuthToken(
+ &kFoo, &kBar, request.get(), &callback, token);
+ if (rv_generate != OK) {
+ ADD_FAILURE() << "Problems generating auth token";
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace
+
+
TEST(HttpAuthHandlerDigestTest, ParseChallenge) {
static const struct {
// The challenge string.
@@ -488,75 +555,14 @@ TEST(HttpAuthHandlerDigest, HandleAnotherChallenge) {
handler->HandleAnotherChallenge(&tok_stale_false));
}
-namespace {
-
-const char* const kSimpleChallenge =
- "Digest realm=\"Oblivion\", nonce=\"nonce-value\"";
-
-// RespondToChallenge creates an HttpAuthHandlerDigest for the specified
-// |challenge|, and generates a response to the challenge which is returned in
-// |token|.
-//
-// The return value is an error string - an empty string indicates no errors.
-//
-// If |target| is HttpAuth::AUTH_PROXY, then |proxy_name| specifies the source
-// of the |challenge|. Otherwise, the scheme and host and port of |request_url|
-// indicates the origin of the challenge.
-std::string RespondToChallenge(HttpAuth::Target target,
- const std::string& proxy_name,
- const std::string& request_url,
- const std::string& challenge,
- std::string* token) {
- // Input validation.
- DCHECK(token);
- DCHECK(target != HttpAuth::AUTH_PROXY || !proxy_name.empty());
- DCHECK(!request_url.empty());
- DCHECK(!challenge.empty());
-
- token->clear();
- scoped_ptr<HttpAuthHandlerDigest::Factory> factory(
- new HttpAuthHandlerDigest::Factory());
- HttpAuthHandlerDigest::NonceGenerator* nonce_generator =
- new HttpAuthHandlerDigest::FixedNonceGenerator("client_nonce");
- factory->set_nonce_generator(nonce_generator);
- scoped_ptr<HttpAuthHandler> handler;
-
- // Create a handler for a particular challenge.
- GURL url_origin(target == HttpAuth::AUTH_SERVER ? request_url : proxy_name);
- int rv_create = factory->CreateAuthHandlerFromString(
- challenge, target, url_origin.GetOrigin(), BoundNetLog(), &handler);
- if (rv_create != OK || handler.get() == NULL)
- return "Unable to create auth handler.";
-
- // Create a token in response to the challenge.
- // NOTE: HttpAuthHandlerDigest's implementation of GenerateAuthToken always
- // completes synchronously. That's why this test can get away with a
- // TestCompletionCallback without an IO thread.
- TestCompletionCallback callback;
- scoped_ptr<HttpRequestInfo> request(new HttpRequestInfo());
- request->url = GURL(request_url);
- const string16 kFoo = ASCIIToUTF16("foo");
- const string16 kBar = ASCIIToUTF16("bar");
- int rv_generate = handler->GenerateAuthToken(
- &kFoo, &kBar, request.get(), &callback, token);
- if (rv_generate != OK)
- return "Problems generating auth token";
-
- // The token was correctly generated and is returned in |token|.
- return std::string();
-}
-
-} // namespace
-
TEST(HttpAuthHandlerDigest, RespondToServerChallenge) {
std::string auth_token;
- std::string error_text = RespondToChallenge(
+ EXPECT_TRUE(RespondToChallenge(
HttpAuth::AUTH_SERVER,
std::string(),
"http://www.example.com/path/to/resource",
kSimpleChallenge,
- &auth_token);
- EXPECT_EQ("", error_text);
+ &auth_token));
EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", "
"nonce=\"nonce-value\", uri=\"/path/to/resource\", "
"response=\"6779f90bd0d658f937c1af967614fe84\"",
@@ -565,13 +571,12 @@ TEST(HttpAuthHandlerDigest, RespondToServerChallenge) {
TEST(HttpAuthHandlerDigest, RespondToHttpsServerChallenge) {
std::string auth_token;
- std::string error_text = RespondToChallenge(
+ EXPECT_TRUE(RespondToChallenge(
HttpAuth::AUTH_SERVER,
std::string(),
"https://www.example.com/path/to/resource",
kSimpleChallenge,
- &auth_token);
- EXPECT_EQ("", error_text);
+ &auth_token));
EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", "
"nonce=\"nonce-value\", uri=\"/path/to/resource\", "
"response=\"6779f90bd0d658f937c1af967614fe84\"",
@@ -580,13 +585,12 @@ TEST(HttpAuthHandlerDigest, RespondToHttpsServerChallenge) {
TEST(HttpAuthHandlerDigest, RespondToProxyChallenge) {
std::string auth_token;
- std::string error_text = RespondToChallenge(
+ EXPECT_TRUE(RespondToChallenge(
HttpAuth::AUTH_PROXY,
"http://proxy.intranet.corp.com:3128",
"http://www.example.com/path/to/resource",
kSimpleChallenge,
- &auth_token);
- EXPECT_EQ("", error_text);
+ &auth_token));
EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", "
"nonce=\"nonce-value\", uri=\"/path/to/resource\", "
"response=\"6779f90bd0d658f937c1af967614fe84\"",
@@ -595,13 +599,12 @@ TEST(HttpAuthHandlerDigest, RespondToProxyChallenge) {
TEST(HttpAuthHandlerDigest, RespondToProxyChallengeHttps) {
std::string auth_token;
- std::string error_text = RespondToChallenge(
+ EXPECT_TRUE(RespondToChallenge(
HttpAuth::AUTH_PROXY,
"http://proxy.intranet.corp.com:3128",
"https://www.example.com/path/to/resource",
kSimpleChallenge,
- &auth_token);
- EXPECT_EQ("", error_text);
+ &auth_token));
EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", "
"nonce=\"nonce-value\", uri=\"www.example.com:443\", "
"response=\"3270da8467afbe9ddf2334a48d46e9b9\"",
@@ -610,13 +613,12 @@ TEST(HttpAuthHandlerDigest, RespondToProxyChallengeHttps) {
TEST(HttpAuthHandlerDigest, RespondToChallengeAuthQop) {
std::string auth_token;
- std::string error_text = RespondToChallenge(
+ EXPECT_TRUE(RespondToChallenge(
HttpAuth::AUTH_SERVER,
std::string(),
"http://www.example.com/path/to/resource",
"Digest realm=\"Oblivion\", nonce=\"nonce-value\", qop=\"auth\"",
- &auth_token);
- EXPECT_EQ("", error_text);
+ &auth_token));
EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", "
"nonce=\"nonce-value\", uri=\"/path/to/resource\", "
"response=\"5b1459beda5cee30d6ff9e970a69c0ea\", "
@@ -626,14 +628,13 @@ TEST(HttpAuthHandlerDigest, RespondToChallengeAuthQop) {
TEST(HttpAuthHandlerDigest, RespondToChallengeOpaque) {
std::string auth_token;
- std::string error_text = RespondToChallenge(
+ EXPECT_TRUE(RespondToChallenge(
HttpAuth::AUTH_SERVER,
std::string(),
"http://www.example.com/path/to/resource",
"Digest realm=\"Oblivion\", nonce=\"nonce-value\", "
"qop=\"auth\", opaque=\"opaque text\"",
- &auth_token);
- EXPECT_EQ("", error_text);
+ &auth_token));
EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", "
"nonce=\"nonce-value\", uri=\"/path/to/resource\", "
"response=\"5b1459beda5cee30d6ff9e970a69c0ea\", "
diff --git a/net/http/http_auth_handler_mock.cc b/net/http/http_auth_handler_mock.cc
index d1e8bb2..0a49169 100644
--- a/net/http/http_auth_handler_mock.cc
+++ b/net/http/http_auth_handler_mock.cc
@@ -72,6 +72,7 @@ void HttpAuthHandlerMock::SetGenerateExpectation(bool async, int rv) {
}
bool HttpAuthHandlerMock::Init(HttpAuth::ChallengeTokenizer* challenge) {
+ auth_scheme_ = AUTH_SCHEME_BASIC;
scheme_ = "mock";
score_ = 1;
properties_ = connection_based_ ? IS_CONNECTION_BASED : 0;
diff --git a/net/http/http_auth_handler_negotiate.cc b/net/http/http_auth_handler_negotiate.cc
index 0fce354..2544728 100644
--- a/net/http/http_auth_handler_negotiate.cc
+++ b/net/http/http_auth_handler_negotiate.cc
@@ -93,6 +93,7 @@ bool HttpAuthHandlerNegotiate::Init(HttpAuth::ChallengeTokenizer* challenge) {
#endif
if (CanDelegate())
auth_system_.Delegate();
+ auth_scheme_ = AUTH_SCHEME_NEGOTIATE;
scheme_ = "negotiate";
score_ = 4;
properties_ = ENCRYPTS_IDENTITY | IS_CONNECTION_BASED;
diff --git a/net/http/http_auth_handler_ntlm.cc b/net/http/http_auth_handler_ntlm.cc
index 352b2ed..f987e48 100644
--- a/net/http/http_auth_handler_ntlm.cc
+++ b/net/http/http_auth_handler_ntlm.cc
@@ -93,6 +93,7 @@ int HttpAuthHandlerNTLM::GenerateAuthTokenImpl(
}
bool HttpAuthHandlerNTLM::Init(HttpAuth::ChallengeTokenizer* tok) {
+ auth_scheme_ = AUTH_SCHEME_NTLM;
scheme_ = "ntlm";
score_ = 3;
properties_ = ENCRYPTS_IDENTITY | IS_CONNECTION_BASED;
diff --git a/net/http/http_auth_handler_unittest.cc b/net/http/http_auth_handler_unittest.cc
index d63b9fb..c3d0114 100644
--- a/net/http/http_auth_handler_unittest.cc
+++ b/net/http/http_auth_handler_unittest.cc
@@ -49,11 +49,12 @@ TEST(HttpAuthHandlerTest, NetLog) {
if (async)
test_callback.WaitForResult();
- EXPECT_EQ(2u, capturing_net_log.entries().size());
- EXPECT_TRUE(LogContainsBeginEvent(capturing_net_log.entries(),
- 0, event_type));
- EXPECT_TRUE(LogContainsEndEvent(capturing_net_log.entries(),
- 1, event_type));
+ net::CapturingNetLog::EntryList entries;
+ capturing_net_log.GetEntries(&entries);
+
+ EXPECT_EQ(2u, entries.size());
+ EXPECT_TRUE(LogContainsBeginEvent(entries, 0, event_type));
+ EXPECT_TRUE(LogContainsEndEvent(entries, 1, event_type));
}
}
}
diff --git a/net/http/http_basic_stream.cc b/net/http/http_basic_stream.cc
index 64352c4..061bb30 100644
--- a/net/http/http_basic_stream.cc
+++ b/net/http/http_basic_stream.cc
@@ -16,8 +16,10 @@
namespace net {
HttpBasicStream::HttpBasicStream(ClientSocketHandle* connection,
+ HttpStreamParser* parser,
bool using_proxy)
: read_buf_(new GrowableIOBuffer()),
+ parser_(parser),
connection_(connection),
using_proxy_(using_proxy),
request_info_(NULL) {
@@ -26,6 +28,7 @@ HttpBasicStream::HttpBasicStream(ClientSocketHandle* connection,
int HttpBasicStream::InitializeStream(const HttpRequestInfo* request_info,
const BoundNetLog& net_log,
CompletionCallback* callback) {
+ DCHECK(!parser_.get());
request_info_ = request_info;
parser_.reset(new HttpStreamParser(connection_.get(), request_info,
read_buf_, net_log));
@@ -38,6 +41,7 @@ int HttpBasicStream::SendRequest(const HttpRequestHeaders& headers,
HttpResponseInfo* response,
CompletionCallback* callback) {
DCHECK(parser_.get());
+ DCHECK(request_info_);
const std::string path = using_proxy_ ?
HttpUtil::SpecForRequest(request_info_->url) :
HttpUtil::PathForRequest(request_info_->url);
@@ -75,7 +79,7 @@ HttpStream* HttpBasicStream::RenewStreamForAuth() {
DCHECK(IsResponseBodyComplete());
DCHECK(!IsMoreDataBuffered());
parser_.reset();
- return new HttpBasicStream(connection_.release(), using_proxy_);
+ return new HttpBasicStream(connection_.release(), NULL, using_proxy_);
}
bool HttpBasicStream::IsResponseBodyComplete() const {
diff --git a/net/http/http_basic_stream.h b/net/http/http_basic_stream.h
index 83136c0..918596a 100644
--- a/net/http/http_basic_stream.h
+++ b/net/http/http_basic_stream.h
@@ -30,7 +30,13 @@ class UploadDataStream;
class HttpBasicStream : public HttpStream {
public:
- HttpBasicStream(ClientSocketHandle* connection, bool using_proxy);
+ // Constructs a new HttpBasicStream. If |parser| is NULL, then
+ // InitializeStream should be called to initialize it correctly. If
+ // |parser| is non-null, then InitializeStream should not be called,
+ // as the stream is already initialized.
+ HttpBasicStream(ClientSocketHandle* connection,
+ HttpStreamParser* parser,
+ bool using_proxy);
virtual ~HttpBasicStream();
// HttpStream methods:
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc
index 896a6ac..51cc55f 100644
--- a/net/http/http_cache.cc
+++ b/net/http/http_cache.cc
@@ -263,7 +263,7 @@ void HttpCache::MetadataWriter::OnIOComplete(int result) {
class HttpCache::SSLHostInfoFactoryAdaptor : public SSLHostInfoFactory {
public:
- SSLHostInfoFactoryAdaptor(HttpCache* http_cache)
+ explicit SSLHostInfoFactoryAdaptor(HttpCache* http_cache)
: http_cache_(http_cache) {
}
@@ -279,6 +279,7 @@ class HttpCache::SSLHostInfoFactoryAdaptor : public SSLHostInfoFactory {
//-----------------------------------------------------------------------------
HttpCache::HttpCache(HostResolver* host_resolver,
+ CertVerifier* cert_verifier,
DnsRRResolver* dnsrr_resolver,
DnsCertProvenanceChecker* dns_cert_checker_,
ProxyService* proxy_service,
@@ -293,12 +294,11 @@ HttpCache::HttpCache(HostResolver* host_resolver,
ssl_host_info_factory_(new SSLHostInfoFactoryAdaptor(
ALLOW_THIS_IN_INITIALIZER_LIST(this))),
network_layer_(HttpNetworkLayer::CreateFactory(host_resolver,
- dnsrr_resolver, dns_cert_checker_,
+ cert_verifier, dnsrr_resolver, dns_cert_checker_,
ssl_host_info_factory_.get(),
proxy_service, ssl_config_service,
http_auth_handler_factory, network_delegate, net_log)),
- ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
- enable_range_support_(true) {
+ ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)) {
}
HttpCache::HttpCache(HttpNetworkSession* session,
@@ -307,8 +307,7 @@ HttpCache::HttpCache(HttpNetworkSession* session,
building_backend_(false),
mode_(NORMAL),
network_layer_(HttpNetworkLayer::CreateFactory(session)),
- ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
- enable_range_support_(true) {
+ ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)) {
}
HttpCache::HttpCache(HttpTransactionFactory* network_layer,
@@ -317,8 +316,7 @@ HttpCache::HttpCache(HttpTransactionFactory* network_layer,
building_backend_(false),
mode_(NORMAL),
network_layer_(network_layer),
- ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
- enable_range_support_(true) {
+ ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)) {
}
HttpCache::~HttpCache() {
@@ -385,7 +383,7 @@ int HttpCache::CreateTransaction(scoped_ptr<HttpTransaction>* trans) {
if (!disk_cache_.get())
CreateBackend(NULL, NULL); // We don't care about the result.
- trans->reset(new HttpCache::Transaction(this, enable_range_support_));
+ trans->reset(new HttpCache::Transaction(this));
return OK;
}
@@ -421,8 +419,7 @@ void HttpCache::WriteMetadata(const GURL& url,
if (!disk_cache_.get())
CreateBackend(NULL, NULL); // We don't care about the result.
- HttpCache::Transaction* trans =
- new HttpCache::Transaction(this, enable_range_support_);
+ HttpCache::Transaction* trans = new HttpCache::Transaction(this);
MetadataWriter* writer = new MetadataWriter(trans);
// The writer will self destruct when done.
diff --git a/net/http/http_cache.h b/net/http/http_cache.h
index 06c2ab9..5c812da 100644
--- a/net/http/http_cache.h
+++ b/net/http/http_cache.h
@@ -41,6 +41,7 @@ class Entry;
namespace net {
+class CertVerifier;
class DnsCertProvenanceChecker;
class DnsRRResolver;
class HostResolver;
@@ -117,6 +118,7 @@ class HttpCache : public HttpTransactionFactory,
// The disk cache is initialized lazily (by CreateTransaction) in this case.
// The HttpCache takes ownership of the |backend_factory|.
HttpCache(HostResolver* host_resolver,
+ CertVerifier* cert_verifier,
DnsRRResolver* dnsrr_resolver,
DnsCertProvenanceChecker* dns_cert_checker,
ProxyService* proxy_service,
@@ -179,10 +181,6 @@ class HttpCache : public HttpTransactionFactory,
// immediately, but they will not be reusable. This is for debugging.
void CloseCurrentConnections();
- void set_enable_range_support(bool value) {
- enable_range_support_ = value;
- }
-
protected:
// Disk cache entry data indices.
enum {
@@ -368,8 +366,6 @@ class HttpCache : public HttpTransactionFactory,
ScopedRunnableMethodFactory<HttpCache> task_factory_;
- bool enable_range_support_;
-
typedef base::hash_map<std::string, int> PlaybackCacheMap;
scoped_ptr<PlaybackCacheMap> playback_cache_map_;
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
index 1720509..923ee25 100644
--- a/net/http/http_cache_transaction.cc
+++ b/net/http/http_cache_transaction.cc
@@ -97,7 +97,7 @@ static bool HeaderMatches(const HttpRequestHeaders& headers,
//-----------------------------------------------------------------------------
-HttpCache::Transaction::Transaction(HttpCache* cache, bool enable_range_support)
+HttpCache::Transaction::Transaction(HttpCache* cache)
: next_state_(STATE_NONE),
request_(NULL),
cache_(cache->AsWeakPtr()),
@@ -110,7 +110,6 @@ HttpCache::Transaction::Transaction(HttpCache* cache, bool enable_range_support)
target_state_(STATE_NONE),
reading_(false),
invalid_range_(false),
- enable_range_support_(enable_range_support),
truncated_(false),
is_sparse_(false),
server_responded_206_(false),
@@ -139,7 +138,7 @@ HttpCache::Transaction::~Transaction() {
if (cache_) {
if (entry_) {
- bool cancel_request = reading_ && enable_range_support_;
+ bool cancel_request = reading_;
if (cancel_request) {
if (partial_.get()) {
entry_->disk_entry->CancelSparseIO();
@@ -683,7 +682,7 @@ int HttpCache::Transaction::DoSuccessfulSendRequest() {
DoneWritingToEntry(false);
}
- if (enable_range_support_ && new_response_->headers->response_code() == 416) {
+ if (new_response_->headers->response_code() == 416) {
DCHECK_EQ(NONE, mode_);
response_ = *new_response_;
return OK;
@@ -1284,13 +1283,8 @@ void HttpCache::Transaction::SetRequest(const BoundNetLog& net_log,
bool range_found = false;
bool external_validation_error = false;
- if (request_->extra_headers.HasHeader(HttpRequestHeaders::kRange)) {
- if (enable_range_support_) {
- range_found = true;
- } else {
- effective_load_flags_ |= LOAD_DISABLE_CACHE;
- }
- }
+ if (request_->extra_headers.HasHeader(HttpRequestHeaders::kRange))
+ range_found = true;
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSpecialHeaders); ++i) {
if (HeaderMatches(request_->extra_headers, kSpecialHeaders[i].search)) {
@@ -1429,9 +1423,6 @@ int HttpCache::Transaction::BeginPartialCacheValidation() {
!truncated_)
return BeginCacheValidation();
- if (!enable_range_support_)
- return BeginCacheValidation();
-
bool byte_range_requested = partial_.get() != NULL;
if (byte_range_requested) {
next_state_ = STATE_CACHE_QUERY_DATA;
@@ -1552,9 +1543,6 @@ bool HttpCache::Transaction::RequiresValidation() {
if (effective_load_flags_ & LOAD_VALIDATE_CACHE)
return true;
- if (response_.headers->response_code() == 206 && !enable_range_support_)
- return true;
-
if (response_.headers->RequiresValidation(
response_.request_time, response_.response_time, Time::Now()))
return true;
@@ -1570,11 +1558,6 @@ bool HttpCache::Transaction::RequiresValidation() {
bool HttpCache::Transaction::ConditionalizeRequest() {
DCHECK(response_.headers);
- if (!enable_range_support_ && response_.headers->response_code() != 200) {
- // This only makes sense for cached 200 responses.
- return false;
- }
-
// This only makes sense for cached 200 or 206 responses.
if (response_.headers->response_code() != 200 &&
response_.headers->response_code() != 206)
@@ -1653,7 +1636,7 @@ bool HttpCache::Transaction::ConditionalizeRequest() {
bool HttpCache::Transaction::ValidatePartialResponse(bool* partial_content) {
const HttpResponseHeaders* headers = new_response_->headers;
int response_code = headers->response_code();
- bool partial_response = enable_range_support_ ? response_code == 206 : false;
+ bool partial_response = (response_code == 206);
*partial_content = false;
if (!entry_)
diff --git a/net/http/http_cache_transaction.h b/net/http/http_cache_transaction.h
index a842ade..bc0b211 100644
--- a/net/http/http_cache_transaction.h
+++ b/net/http/http_cache_transaction.h
@@ -28,7 +28,7 @@ struct HttpRequestInfo;
// factory.
class HttpCache::Transaction : public HttpTransaction {
public:
- Transaction(HttpCache* cache, bool enable_range_support);
+ Transaction(HttpCache* cache);
virtual ~Transaction();
// HttpTransaction methods:
@@ -339,7 +339,6 @@ class HttpCache::Transaction : public HttpTransaction {
State target_state_;
bool reading_; // We are already reading.
bool invalid_range_; // We may bypass the cache for this request.
- bool enable_range_support_;
bool truncated_; // We don't have all the response data.
bool is_sparse_; // The data is stored in sparse byte ranges.
bool server_responded_206_;
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc
index b4dde9b..a40a5b8 100644
--- a/net/http/http_cache_unittest.cc
+++ b/net/http/http_cache_unittest.cc
@@ -1044,19 +1044,22 @@ TEST(HttpCache, SimpleGETNoDiskCache) {
// Check that the NetLog was filled as expected.
// (We attempted to both Open and Create entries, but both failed).
- EXPECT_EQ(6u, log.entries().size());
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
+
+ EXPECT_EQ(6u, entries.size());
EXPECT_TRUE(net::LogContainsBeginEvent(
- log.entries(), 0, net::NetLog::TYPE_HTTP_CACHE_WAITING));
+ entries, 0, net::NetLog::TYPE_HTTP_CACHE_WAITING));
EXPECT_TRUE(net::LogContainsEndEvent(
- log.entries(), 1, net::NetLog::TYPE_HTTP_CACHE_WAITING));
+ entries, 1, net::NetLog::TYPE_HTTP_CACHE_WAITING));
EXPECT_TRUE(net::LogContainsBeginEvent(
- log.entries(), 2, net::NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY));
+ entries, 2, net::NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY));
EXPECT_TRUE(net::LogContainsEndEvent(
- log.entries(), 3, net::NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY));
+ entries, 3, net::NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY));
EXPECT_TRUE(net::LogContainsBeginEvent(
- log.entries(), 4, net::NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY));
+ entries, 4, net::NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY));
EXPECT_TRUE(net::LogContainsEndEvent(
- log.entries(), 5, net::NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY));
+ entries, 5, net::NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY));
EXPECT_EQ(1, cache.network_layer()->transaction_count());
EXPECT_EQ(0, cache.disk_cache()->open_count());
@@ -1145,23 +1148,26 @@ TEST(HttpCache, SimpleGET_LoadOnlyFromCache_Hit) {
log.bound());
// Check that the NetLog was filled as expected.
- EXPECT_EQ(8u, log.entries().size());
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
+
+ EXPECT_EQ(8u, entries.size());
EXPECT_TRUE(net::LogContainsBeginEvent(
- log.entries(), 0, net::NetLog::TYPE_HTTP_CACHE_WAITING));
+ entries, 0, net::NetLog::TYPE_HTTP_CACHE_WAITING));
EXPECT_TRUE(net::LogContainsEndEvent(
- log.entries(), 1, net::NetLog::TYPE_HTTP_CACHE_WAITING));
+ entries, 1, net::NetLog::TYPE_HTTP_CACHE_WAITING));
EXPECT_TRUE(net::LogContainsBeginEvent(
- log.entries(), 2, net::NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY));
+ entries, 2, net::NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY));
EXPECT_TRUE(net::LogContainsEndEvent(
- log.entries(), 3, net::NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY));
+ entries, 3, net::NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY));
EXPECT_TRUE(net::LogContainsBeginEvent(
- log.entries(), 4, net::NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY));
+ entries, 4, net::NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY));
EXPECT_TRUE(net::LogContainsEndEvent(
- log.entries(), 5, net::NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY));
+ entries, 5, net::NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY));
EXPECT_TRUE(net::LogContainsBeginEvent(
- log.entries(), 6, net::NetLog::TYPE_HTTP_CACHE_WAITING));
+ entries, 6, net::NetLog::TYPE_HTTP_CACHE_WAITING));
EXPECT_TRUE(net::LogContainsEndEvent(
- log.entries(), 7, net::NetLog::TYPE_HTTP_CACHE_WAITING));
+ entries, 7, net::NetLog::TYPE_HTTP_CACHE_WAITING));
// force this transaction to read from the cache
MockTransaction transaction(kSimpleGET_Transaction);
@@ -1172,23 +1178,25 @@ TEST(HttpCache, SimpleGET_LoadOnlyFromCache_Hit) {
RunTransactionTestWithLog(cache.http_cache(), transaction, log.bound());
// Check that the NetLog was filled as expected.
- EXPECT_EQ(8u, log.entries().size());
+ log.GetEntries(&entries);
+
+ EXPECT_EQ(8u, entries.size());
EXPECT_TRUE(net::LogContainsBeginEvent(
- log.entries(), 0, net::NetLog::TYPE_HTTP_CACHE_WAITING));
+ entries, 0, net::NetLog::TYPE_HTTP_CACHE_WAITING));
EXPECT_TRUE(net::LogContainsEndEvent(
- log.entries(), 1, net::NetLog::TYPE_HTTP_CACHE_WAITING));
+ entries, 1, net::NetLog::TYPE_HTTP_CACHE_WAITING));
EXPECT_TRUE(net::LogContainsBeginEvent(
- log.entries(), 2, net::NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY));
+ entries, 2, net::NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY));
EXPECT_TRUE(net::LogContainsEndEvent(
- log.entries(), 3, net::NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY));
+ entries, 3, net::NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY));
EXPECT_TRUE(net::LogContainsBeginEvent(
- log.entries(), 4, net::NetLog::TYPE_HTTP_CACHE_WAITING));
+ entries, 4, net::NetLog::TYPE_HTTP_CACHE_WAITING));
EXPECT_TRUE(net::LogContainsEndEvent(
- log.entries(), 5, net::NetLog::TYPE_HTTP_CACHE_WAITING));
+ entries, 5, net::NetLog::TYPE_HTTP_CACHE_WAITING));
EXPECT_TRUE(net::LogContainsBeginEvent(
- log.entries(), 6, net::NetLog::TYPE_HTTP_CACHE_READ_INFO));
+ entries, 6, net::NetLog::TYPE_HTTP_CACHE_READ_INFO));
EXPECT_TRUE(net::LogContainsEndEvent(
- log.entries(), 7, net::NetLog::TYPE_HTTP_CACHE_READ_INFO));
+ entries, 7, net::NetLog::TYPE_HTTP_CACHE_READ_INFO));
EXPECT_EQ(1, cache.network_layer()->transaction_count());
EXPECT_EQ(1, cache.disk_cache()->open_count());
@@ -1268,23 +1276,26 @@ TEST(HttpCache, SimpleGET_LoadBypassCache) {
RunTransactionTestWithLog(cache.http_cache(), transaction, log.bound());
// Check that the NetLog was filled as expected.
- EXPECT_EQ(8u, log.entries().size());
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
+
+ EXPECT_EQ(8u, entries.size());
EXPECT_TRUE(net::LogContainsBeginEvent(
- log.entries(), 0, net::NetLog::TYPE_HTTP_CACHE_WAITING));
+ entries, 0, net::NetLog::TYPE_HTTP_CACHE_WAITING));
EXPECT_TRUE(net::LogContainsEndEvent(
- log.entries(), 1, net::NetLog::TYPE_HTTP_CACHE_WAITING));
+ entries, 1, net::NetLog::TYPE_HTTP_CACHE_WAITING));
EXPECT_TRUE(net::LogContainsBeginEvent(
- log.entries(), 2, net::NetLog::TYPE_HTTP_CACHE_DOOM_ENTRY));
+ entries, 2, net::NetLog::TYPE_HTTP_CACHE_DOOM_ENTRY));
EXPECT_TRUE(net::LogContainsEndEvent(
- log.entries(), 3, net::NetLog::TYPE_HTTP_CACHE_DOOM_ENTRY));
+ entries, 3, net::NetLog::TYPE_HTTP_CACHE_DOOM_ENTRY));
EXPECT_TRUE(net::LogContainsBeginEvent(
- log.entries(), 4, net::NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY));
+ entries, 4, net::NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY));
EXPECT_TRUE(net::LogContainsEndEvent(
- log.entries(), 5, net::NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY));
+ entries, 5, net::NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY));
EXPECT_TRUE(net::LogContainsBeginEvent(
- log.entries(), 6, net::NetLog::TYPE_HTTP_CACHE_WAITING));
+ entries, 6, net::NetLog::TYPE_HTTP_CACHE_WAITING));
EXPECT_TRUE(net::LogContainsEndEvent(
- log.entries(), 7, net::NetLog::TYPE_HTTP_CACHE_WAITING));
+ entries, 7, net::NetLog::TYPE_HTTP_CACHE_WAITING));
EXPECT_EQ(2, cache.network_layer()->transaction_count());
EXPECT_EQ(0, cache.disk_cache()->open_count());
@@ -2767,7 +2778,6 @@ TEST(HttpCache, RangeGET_SkipsCache) {
// header.
TEST(HttpCache, RangeGET_SkipsCache2) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
MockTransaction transaction(kRangeGET_Transaction);
transaction.request_headers = "If-None-Match: foo\r\n"
@@ -2802,7 +2812,6 @@ TEST(HttpCache, RangeGET_SkipsCache2) {
// Tests that receiving 206 for a regular request is handled correctly.
TEST(HttpCache, GET_Crazy206) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
// Write to the cache.
MockTransaction transaction(kRangeGET_TransactionOK);
@@ -2828,7 +2837,6 @@ TEST(HttpCache, GET_Crazy206) {
// cache and the network.
TEST(HttpCache, RangeGET_OK) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
AddMockTransaction(&kRangeGET_TransactionOK);
std::string headers;
@@ -2884,7 +2892,6 @@ TEST(HttpCache, RangeGET_OK) {
// cache and the network, with synchronous responses.
TEST(HttpCache, RangeGET_SyncOK) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
MockTransaction transaction(kRangeGET_TransactionOK);
transaction.test_mode = TEST_MODE_SYNC_ALL;
@@ -2939,7 +2946,6 @@ TEST(HttpCache, RangeGET_SyncOK) {
// Tests that we don't revalidate an entry unless we are required to do so.
TEST(HttpCache, RangeGET_Revalidate1) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
std::string headers;
// Write to the cache (40-49).
@@ -2981,7 +2987,6 @@ TEST(HttpCache, RangeGET_Revalidate1) {
// Checks that we revalidate an entry when the headers say so.
TEST(HttpCache, RangeGET_Revalidate2) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
std::string headers;
// Write to the cache (40-49).
@@ -3014,7 +3019,6 @@ TEST(HttpCache, RangeGET_Revalidate2) {
// Tests that we deal with 304s for range requests.
TEST(HttpCache, RangeGET_304) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
AddMockTransaction(&kRangeGET_TransactionOK);
std::string headers;
@@ -3045,7 +3049,6 @@ TEST(HttpCache, RangeGET_304) {
// Tests that we deal with 206s when revalidating range requests.
TEST(HttpCache, RangeGET_ModifiedResult) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
AddMockTransaction(&kRangeGET_TransactionOK);
std::string headers;
@@ -3083,7 +3086,6 @@ TEST(HttpCache, RangeGET_ModifiedResult) {
// We start with one suffix request, followed by a request from a given point.
TEST(HttpCache, UnknownRangeGET_1) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
AddMockTransaction(&kRangeGET_TransactionOK);
std::string headers;
@@ -3119,7 +3121,6 @@ TEST(HttpCache, UnknownRangeGET_1) {
// We'll also verify that synchronous cache responses work as intended.
TEST(HttpCache, UnknownRangeGET_2) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
std::string headers;
MockTransaction transaction(kRangeGET_TransactionOK);
@@ -3158,7 +3159,6 @@ TEST(HttpCache, UnknownRangeGET_2) {
// up things.
TEST(HttpCache, UnknownRangeGET_304) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
std::string headers;
MockTransaction transaction(kRangeGET_TransactionOK);
@@ -3187,7 +3187,6 @@ TEST(HttpCache, UnknownRangeGET_304) {
// Tests that we can handle non-range requests when we have cached a range.
TEST(HttpCache, GET_Previous206) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
AddMockTransaction(&kRangeGET_TransactionOK);
std::string headers;
@@ -3219,7 +3218,6 @@ TEST(HttpCache, GET_Previous206) {
// part of the object and the server replies with 304 (Not Modified).
TEST(HttpCache, GET_Previous206_NotModified) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
MockTransaction transaction(kRangeGET_TransactionOK);
AddMockTransaction(&transaction);
@@ -3260,7 +3258,6 @@ TEST(HttpCache, GET_Previous206_NotModified) {
// new content provided by the server (206).
TEST(HttpCache, GET_Previous206_NewContent) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
AddMockTransaction(&kRangeGET_TransactionOK);
std::string headers;
@@ -3302,7 +3299,6 @@ TEST(HttpCache, GET_Previous206_NewContent) {
// Tests that we can handle cached 206 responses that are not sparse.
TEST(HttpCache, GET_Previous206_NotSparse) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
// Create a disk cache entry that stores 206 headers while not being sparse.
disk_cache::Entry* entry;
@@ -3345,7 +3341,6 @@ TEST(HttpCache, GET_Previous206_NotSparse) {
// we issue a range request and expect to receive a range.
TEST(HttpCache, RangeGET_Previous206_NotSparse_2) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
AddMockTransaction(&kRangeGET_TransactionOK);
// Create a disk cache entry that stores 206 headers while not being sparse.
@@ -3387,7 +3382,6 @@ TEST(HttpCache, RangeGET_Previous206_NotSparse_2) {
// Tests that we can handle range requests with cached 200 responses.
TEST(HttpCache, RangeGET_Previous200) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
// Store the whole thing with status 200.
MockTransaction transaction(kTypicalGET_Transaction);
@@ -3458,7 +3452,6 @@ TEST(HttpCache, RangeGET_Previous200) {
// Tests that we can handle a 200 response when dealing with sparse entries.
TEST(HttpCache, RangeRequestResultsIn200) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
AddMockTransaction(&kRangeGET_TransactionOK);
std::string headers;
@@ -3499,7 +3492,6 @@ TEST(HttpCache, RangeRequestResultsIn200) {
// only deletes the entry if the resource has indeed changed.
TEST(HttpCache, RangeGET_MoreThanCurrentSize) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
AddMockTransaction(&kRangeGET_TransactionOK);
std::string headers;
@@ -3533,7 +3525,6 @@ TEST(HttpCache, RangeGET_MoreThanCurrentSize) {
// Tests that we don't delete a sparse entry when we cancel a request.
TEST(HttpCache, RangeGET_Cancel) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
AddMockTransaction(&kRangeGET_TransactionOK);
MockHttpRequest request(kRangeGET_TransactionOK);
@@ -3571,7 +3562,6 @@ TEST(HttpCache, RangeGET_Cancel) {
// cancelling the previous one.
TEST(HttpCache, RangeGET_Cancel2) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
AddMockTransaction(&kRangeGET_TransactionOK);
RunTransactionTest(cache.http_cache(), kRangeGET_TransactionOK);
@@ -3617,7 +3607,6 @@ TEST(HttpCache, RangeGET_Cancel2) {
// a row, making sure that the second is waiting for the entry to be ready.
TEST(HttpCache, RangeGET_Cancel3) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
AddMockTransaction(&kRangeGET_TransactionOK);
RunTransactionTest(cache.http_cache(), kRangeGET_TransactionOK);
@@ -3677,7 +3666,6 @@ TEST(HttpCache, RangeGET_Cancel3) {
// Tests that an invalid range response results in no cached entry.
TEST(HttpCache, RangeGET_InvalidResponse1) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
std::string headers;
MockTransaction transaction(kRangeGET_TransactionOK);
@@ -3706,7 +3694,6 @@ TEST(HttpCache, RangeGET_InvalidResponse1) {
// Tests that we reject a range that doesn't match the content-length.
TEST(HttpCache, RangeGET_InvalidResponse2) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
std::string headers;
MockTransaction transaction(kRangeGET_TransactionOK);
@@ -3736,7 +3723,6 @@ TEST(HttpCache, RangeGET_InvalidResponse2) {
// ignore the response.
TEST(HttpCache, RangeGET_InvalidResponse3) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
std::string headers;
MockTransaction transaction(kRangeGET_TransactionOK);
@@ -3784,7 +3770,6 @@ TEST(HttpCache, RangeGET_InvalidResponse3) {
TEST(HttpCache, RangeGET_LargeValues) {
// We need a real sparse cache for this test.
MockHttpCache cache(net::HttpCache::DefaultBackend::InMemory(1024 * 1024));
- cache.http_cache()->set_enable_range_support(true);
std::string headers;
MockTransaction transaction(kRangeGET_TransactionOK);
@@ -3820,7 +3805,6 @@ TEST(HttpCache, RangeGET_NoDiskCache) {
factory->FinishCreation(); // We'll complete synchronously.
MockHttpCache cache(factory);
- cache.http_cache()->set_enable_range_support(true);
AddMockTransaction(&kRangeGET_TransactionOK);
RunTransactionTest(cache.http_cache(), kRangeGET_TransactionOK);
@@ -3832,7 +3816,6 @@ TEST(HttpCache, RangeGET_NoDiskCache) {
// Tests that we handle byte range requests that skip the cache.
TEST(HttpCache, RangeHEAD) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
AddMockTransaction(&kRangeGET_TransactionOK);
MockTransaction transaction(kRangeGET_TransactionOK);
@@ -3855,7 +3838,6 @@ TEST(HttpCache, RangeHEAD) {
// request for the next range and the server gives us a 200 synchronously.
TEST(HttpCache, RangeGET_FastFlakyServer) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
MockTransaction transaction(kRangeGET_TransactionOK);
transaction.request_headers = "Range: bytes = 40-\r\n" EXTRA_HEADER;
@@ -3882,7 +3864,6 @@ TEST(HttpCache, RangeGET_FastFlakyServer) {
// asking for more data.
TEST(HttpCache, RangeGET_FastFlakyServer2) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
// First, check with an empty cache (WRITE mode).
MockTransaction transaction(kRangeGET_TransactionOK);
@@ -3923,7 +3904,6 @@ TEST(HttpCache, RangeGET_FastFlakyServer2) {
// This test hits a NOTREACHED so it is a release mode only test.
TEST(HttpCache, RangeGET_OK_LoadOnlyFromCache) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
AddMockTransaction(&kRangeGET_TransactionOK);
// Write to the cache (40-49).
@@ -3988,7 +3968,6 @@ TEST(HttpCache, WriteResponseInfo_Truncated) {
// to read from the network.
TEST(HttpCache, DoomOnDestruction) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
MockHttpRequest request(kSimpleGET_Transaction);
@@ -4019,7 +3998,6 @@ TEST(HttpCache, DoomOnDestruction) {
// does not have content-length and strong validators.
TEST(HttpCache, DoomOnDestruction2) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
MockHttpRequest request(kSimpleGET_Transaction);
@@ -4056,7 +4034,6 @@ TEST(HttpCache, DoomOnDestruction2) {
// has an "Accept-Ranges: none" header.
TEST(HttpCache, DoomOnDestruction3) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
MockTransaction transaction(kSimpleGET_Transaction);
transaction.response_headers =
@@ -4101,7 +4078,6 @@ TEST(HttpCache, DoomOnDestruction3) {
// Tests that we mark an entry as incomplete when the request is cancelled.
TEST(HttpCache, Set_Truncated_Flag) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
MockTransaction transaction(kSimpleGET_Transaction);
transaction.response_headers =
@@ -4162,7 +4138,6 @@ TEST(HttpCache, Set_Truncated_Flag) {
// Tests that we can continue with a request that was interrupted.
TEST(HttpCache, GET_IncompleteResource) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
AddMockTransaction(&kRangeGET_TransactionOK);
// Create a disk cache entry that stores an incomplete resource.
@@ -4223,7 +4198,6 @@ TEST(HttpCache, GET_IncompleteResource) {
// Tests that we delete truncated entries if the server changes its mind midway.
TEST(HttpCache, GET_IncompleteResource2) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
AddMockTransaction(&kRangeGET_TransactionOK);
// Create a disk cache entry that stores an incomplete resource.
@@ -4283,7 +4257,6 @@ TEST(HttpCache, GET_IncompleteResource2) {
// as truncated.
TEST(HttpCache, GET_CancelIncompleteResource) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
AddMockTransaction(&kRangeGET_TransactionOK);
// Create a disk cache entry that stores an incomplete resource.
@@ -4349,7 +4322,6 @@ TEST(HttpCache, GET_CancelIncompleteResource) {
// Tests that we can handle range requests when we have a truncated entry.
TEST(HttpCache, RangeGET_IncompleteResource) {
MockHttpCache cache;
- cache.http_cache()->set_enable_range_support(true);
AddMockTransaction(&kRangeGET_TransactionOK);
// Create a disk cache entry that stores an incomplete resource.
diff --git a/net/http/http_net_log_params.h b/net/http/http_net_log_params.h
index 6a0b47b..1631363 100644
--- a/net/http/http_net_log_params.h
+++ b/net/http/http_net_log_params.h
@@ -24,7 +24,7 @@ class NetLogHttpRequestParameter : public NetLog::EventParameters {
NetLogHttpRequestParameter(const std::string& line,
const HttpRequestHeaders& headers);
- Value* ToValue() const;
+ virtual Value* ToValue() const;
const HttpRequestHeaders& GetHeaders() const {
return headers_;
@@ -48,7 +48,7 @@ class NetLogHttpResponseParameter : public NetLog::EventParameters {
explicit NetLogHttpResponseParameter(
const scoped_refptr<HttpResponseHeaders>& headers);
- Value* ToValue() const;
+ virtual Value* ToValue() const;
const HttpResponseHeaders& GetHeaders() const {
return *headers_;
diff --git a/net/http/http_network_layer.cc b/net/http/http_network_layer.cc
index 3da23c2..3d3c5dd 100644
--- a/net/http/http_network_layer.cc
+++ b/net/http/http_network_layer.cc
@@ -21,6 +21,7 @@ namespace net {
// static
HttpTransactionFactory* HttpNetworkLayer::CreateFactory(
HostResolver* host_resolver,
+ CertVerifier* cert_verifier,
DnsRRResolver* dnsrr_resolver,
DnsCertProvenanceChecker* dns_cert_checker,
SSLHostInfoFactory* ssl_host_info_factory,
@@ -32,7 +33,7 @@ HttpTransactionFactory* HttpNetworkLayer::CreateFactory(
DCHECK(proxy_service);
return new HttpNetworkLayer(ClientSocketFactory::GetDefaultFactory(),
- host_resolver, dnsrr_resolver,
+ host_resolver, cert_verifier, dnsrr_resolver,
dns_cert_checker,
ssl_host_info_factory, proxy_service,
ssl_config_service, http_auth_handler_factory,
@@ -52,6 +53,7 @@ HttpTransactionFactory* HttpNetworkLayer::CreateFactory(
HttpNetworkLayer::HttpNetworkLayer(
ClientSocketFactory* socket_factory,
HostResolver* host_resolver,
+ CertVerifier* cert_verifier,
DnsRRResolver* dnsrr_resolver,
DnsCertProvenanceChecker* dns_cert_checker,
SSLHostInfoFactory* ssl_host_info_factory,
@@ -62,6 +64,7 @@ HttpNetworkLayer::HttpNetworkLayer(
NetLog* net_log)
: socket_factory_(socket_factory),
host_resolver_(host_resolver),
+ cert_verifier_(cert_verifier),
dnsrr_resolver_(dnsrr_resolver),
dns_cert_checker_(dns_cert_checker),
ssl_host_info_factory_(ssl_host_info_factory),
@@ -80,6 +83,7 @@ HttpNetworkLayer::HttpNetworkLayer(
HttpNetworkLayer::HttpNetworkLayer(
ClientSocketFactory* socket_factory,
HostResolver* host_resolver,
+ CertVerifier* cert_verifier,
DnsRRResolver* dnsrr_resolver,
DnsCertProvenanceChecker* dns_cert_checker,
SSLHostInfoFactory* ssl_host_info_factory,
@@ -91,6 +95,7 @@ HttpNetworkLayer::HttpNetworkLayer(
NetLog* net_log)
: socket_factory_(socket_factory),
host_resolver_(host_resolver),
+ cert_verifier_(cert_verifier),
dnsrr_resolver_(dnsrr_resolver),
dns_cert_checker_(dns_cert_checker),
ssl_host_info_factory_(ssl_host_info_factory),
@@ -108,6 +113,8 @@ HttpNetworkLayer::HttpNetworkLayer(
HttpNetworkLayer::HttpNetworkLayer(HttpNetworkSession* session)
: socket_factory_(ClientSocketFactory::GetDefaultFactory()),
+ host_resolver_(NULL),
+ cert_verifier_(NULL),
dnsrr_resolver_(NULL),
dns_cert_checker_(NULL),
ssl_host_info_factory_(NULL),
@@ -150,6 +157,7 @@ HttpNetworkSession* HttpNetworkLayer::GetSession() {
spdy_session_pool_.reset(new SpdySessionPool(ssl_config_service_));
session_ = new HttpNetworkSession(
host_resolver_,
+ cert_verifier_,
dnsrr_resolver_,
dns_cert_checker_,
ssl_host_info_factory_,
@@ -162,6 +170,7 @@ HttpNetworkSession* HttpNetworkLayer::GetSession() {
net_log_);
// These were just temps for lazy-initializing HttpNetworkSession.
host_resolver_ = NULL;
+ cert_verifier_ = NULL;
dnsrr_resolver_ = NULL;
dns_cert_checker_ = NULL;
ssl_host_info_factory_ = NULL;
diff --git a/net/http/http_network_layer.h b/net/http/http_network_layer.h
index 7781efb..91e1a86 100644
--- a/net/http/http_network_layer.h
+++ b/net/http/http_network_layer.h
@@ -15,6 +15,7 @@
namespace net {
+class CertVerifier;
class ClientSocketFactory;
class DnsCertProvenanceChecker;
class DnsRRResolver;
@@ -30,10 +31,12 @@ class SSLHostInfoFactory;
class HttpNetworkLayer : public HttpTransactionFactory, public NonThreadSafe {
public:
- // |socket_factory|, |proxy_service| and |host_resolver| must remain valid for
- // the lifetime of HttpNetworkLayer.
+ // |socket_factory|, |proxy_service|, |host_resolver|, etc. must remain
+ // valid for the lifetime of HttpNetworkLayer.
+ // TODO(wtc): we only need the next constructor.
HttpNetworkLayer(ClientSocketFactory* socket_factory,
HostResolver* host_resolver,
+ CertVerifier* cert_verifier,
DnsRRResolver* dnsrr_resolver,
DnsCertProvenanceChecker* dns_cert_checker,
SSLHostInfoFactory* ssl_host_info_factory,
@@ -42,11 +45,10 @@ class HttpNetworkLayer : public HttpTransactionFactory, public NonThreadSafe {
HttpAuthHandlerFactory* http_auth_handler_factory,
HttpNetworkDelegate* network_delegate,
NetLog* net_log);
- // Construct a HttpNetworkLayer with an existing HttpNetworkSession which
- // contains a valid ProxyService.
HttpNetworkLayer(
ClientSocketFactory* socket_factory,
HostResolver* host_resolver,
+ CertVerifier* cert_verifier,
DnsRRResolver* dnsrr_resolver,
DnsCertProvenanceChecker* dns_cert_checker,
SSLHostInfoFactory* ssl_host_info_factory,
@@ -57,6 +59,8 @@ class HttpNetworkLayer : public HttpTransactionFactory, public NonThreadSafe {
HttpNetworkDelegate* network_delegate,
NetLog* net_log);
+ // Construct a HttpNetworkLayer with an existing HttpNetworkSession which
+ // contains a valid ProxyService.
explicit HttpNetworkLayer(HttpNetworkSession* session);
~HttpNetworkLayer();
@@ -64,6 +68,7 @@ class HttpNetworkLayer : public HttpTransactionFactory, public NonThreadSafe {
// and allows other implementations to be substituted.
static HttpTransactionFactory* CreateFactory(
HostResolver* host_resolver,
+ CertVerifier* cert_verifier,
DnsRRResolver* dnsrr_resolver,
DnsCertProvenanceChecker* dns_cert_checker,
SSLHostInfoFactory* ssl_host_info_factory,
@@ -100,9 +105,10 @@ class HttpNetworkLayer : public HttpTransactionFactory, public NonThreadSafe {
// The factory we will use to create network sockets.
ClientSocketFactory* socket_factory_;
- // The host resolver and proxy service that will be used when lazily
+ // The host resolver, proxy service, etc. that will be used when lazily
// creating |session_|.
HostResolver* host_resolver_;
+ CertVerifier* cert_verifier_;
DnsRRResolver* dnsrr_resolver_;
DnsCertProvenanceChecker* dns_cert_checker_;
SSLHostInfoFactory* ssl_host_info_factory_;
diff --git a/net/http/http_network_layer_unittest.cc b/net/http/http_network_layer_unittest.cc
index 3ed54bf..2720c10 100644
--- a/net/http/http_network_layer_unittest.cc
+++ b/net/http/http_network_layer_unittest.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 "net/base/cert_verifier.h"
#include "net/base/mock_host_resolver.h"
#include "net/base/net_log.h"
#include "net/base/ssl_config_service_defaults.h"
@@ -21,9 +22,11 @@ class HttpNetworkLayerTest : public PlatformTest {
TEST_F(HttpNetworkLayerTest, CreateAndDestroy) {
MockHostResolver host_resolver;
+ net::CertVerifier cert_verifier;
net::HttpNetworkLayer factory(
NULL,
&host_resolver,
+ &cert_verifier,
NULL /* dnsrr_resolver */,
NULL /* dns_cert_checker */,
NULL /* ssl_host_info_factory */,
@@ -41,9 +44,11 @@ TEST_F(HttpNetworkLayerTest, CreateAndDestroy) {
TEST_F(HttpNetworkLayerTest, Suspend) {
MockHostResolver host_resolver;
+ net::CertVerifier cert_verifier;
net::HttpNetworkLayer factory(
NULL,
&host_resolver,
+ &cert_verifier,
NULL /* dnsrr_resolver */,
NULL /* dns_cert_checker */,
NULL /* ssl_host_info_factory */,
@@ -90,9 +95,11 @@ TEST_F(HttpNetworkLayerTest, GET) {
mock_socket_factory.AddSocketDataProvider(&data);
MockHostResolver host_resolver;
+ net::CertVerifier cert_verifier;
net::HttpNetworkLayer factory(
&mock_socket_factory,
&host_resolver,
+ &cert_verifier,
NULL /* dnsrr_resolver */,
NULL /* dns_cert_checker */,
NULL /* ssl_host_info_factory */,
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index 1e77b49..e3de475 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -20,6 +20,7 @@ namespace net {
// TODO(mbelshe): Move the socket factories into HttpStreamFactory.
HttpNetworkSession::HttpNetworkSession(
HostResolver* host_resolver,
+ CertVerifier* cert_verifier,
DnsRRResolver* dnsrr_resolver,
DnsCertProvenanceChecker* dns_cert_checker,
SSLHostInfoFactory* ssl_host_info_factory,
@@ -32,6 +33,7 @@ HttpNetworkSession::HttpNetworkSession(
NetLog* net_log)
: socket_factory_(client_socket_factory),
host_resolver_(host_resolver),
+ cert_verifier_(cert_verifier),
dnsrr_resolver_(dnsrr_resolver),
dns_cert_checker_(dns_cert_checker),
proxy_service_(proxy_service),
@@ -39,6 +41,7 @@ HttpNetworkSession::HttpNetworkSession(
socket_pool_manager_(net_log,
client_socket_factory,
host_resolver,
+ cert_verifier,
dnsrr_resolver,
dns_cert_checker,
ssl_host_info_factory,
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h
index 43424d2..2c923b6 100644
--- a/net/http/http_network_session.h
+++ b/net/http/http_network_session.h
@@ -28,6 +28,7 @@ class Value;
namespace net {
+class CertVerifier;
class ClientSocketFactory;
class DnsCertProvenanceChecker;
class DnsRRResolver;
@@ -48,6 +49,7 @@ class HttpNetworkSession : public base::RefCounted<HttpNetworkSession>,
public:
HttpNetworkSession(
HostResolver* host_resolver,
+ CertVerifier* cert_verifier,
DnsRRResolver* dnsrr_resolver,
DnsCertProvenanceChecker* dns_cert_checker,
SSLHostInfoFactory* ssl_host_info_factory,
@@ -109,6 +111,7 @@ class HttpNetworkSession : public base::RefCounted<HttpNetworkSession>,
// SSL sockets come from the socket_factory().
ClientSocketFactory* socket_factory() { return socket_factory_; }
HostResolver* host_resolver() { return host_resolver_; }
+ CertVerifier* cert_verifier() { return cert_verifier_; }
DnsRRResolver* dnsrr_resolver() { return dnsrr_resolver_; }
DnsCertProvenanceChecker* dns_cert_checker() {
return dns_cert_checker_;
@@ -152,6 +155,7 @@ class HttpNetworkSession : public base::RefCounted<HttpNetworkSession>,
SSLClientAuthCache ssl_client_auth_cache_;
HttpAlternateProtocols alternate_protocols_;
HostResolver* const host_resolver_;
+ CertVerifier* cert_verifier_;
DnsRRResolver* dnsrr_resolver_;
DnsCertProvenanceChecker* dns_cert_checker_;
scoped_refptr<ProxyService> proxy_service_;
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index 7621e5a..64a4fa7 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -285,11 +285,13 @@ int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len,
scoped_refptr<HttpResponseHeaders> headers(GetResponseHeaders());
if (headers_valid_ && headers.get() && stream_request_.get()) {
// We're trying to read the body of the response but we're still trying
- // to establish an SSL tunnel through the proxy. We can't read these
+ // to establish an SSL tunnel through an HTTP proxy. We can't read these
// bytes when establishing a tunnel because they might be controlled by
// an active network attacker. We don't worry about this for HTTP
// because an active network attacker can already control HTTP sessions.
- // We reach this case when the user cancels a 407 proxy auth prompt.
+ // We reach this case when the user cancels a 407 proxy auth prompt. We
+ // also don't worry about this for an HTTPS Proxy, because the
+ // communication with the proxy is secure.
// See http://crbug.com/8473.
DCHECK(proxy_info_.is_http() || proxy_info_.is_https());
DCHECK_EQ(headers->response_code(), 407);
@@ -301,7 +303,6 @@ int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len,
// Are we using SPDY or HTTP?
next_state = STATE_READ_BODY;
- DCHECK(stream_->GetResponseInfo()->headers);
read_buf_ = buf;
read_buf_len_ = buf_len;
@@ -410,6 +411,18 @@ void HttpNetworkTransaction::OnNeedsClientAuth(
OnIOComplete(ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
}
+void HttpNetworkTransaction::OnHttpsProxyTunnelResponse(
+ const HttpResponseInfo& response_info,
+ HttpStream* stream) {
+ DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
+
+ headers_valid_ = true;
+ response_ = response_info;
+ stream_.reset(stream);
+ stream_request_.reset(); // we're done with the stream request
+ OnIOComplete(ERR_HTTPS_PROXY_TUNNEL_RESPONSE);
+}
+
bool HttpNetworkTransaction::is_https_request() const {
return request_->url.SchemeIs("https");
}
@@ -535,12 +548,12 @@ int HttpNetworkTransaction::DoCreateStreamComplete(int result) {
DCHECK(stream_.get());
} else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
result = HandleCertificateRequest(result);
+ } else if (result == ERR_HTTPS_PROXY_TUNNEL_RESPONSE) {
+ // Return OK and let the caller read the proxy's error page
+ next_state_ = STATE_NONE;
+ return OK;
}
- // Handle possible handshake errors that may have occurred if the stream
- // used SSL for one or more of the layers.
- result = HandleSSLHandshakeError(result);
-
// At this point we are done with the stream_request_.
stream_request_.reset();
return result;
@@ -683,6 +696,23 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
result = HandleCertificateRequest(result);
if (result == OK)
return result;
+ } else if ((result == ERR_SSL_DECOMPRESSION_FAILURE_ALERT ||
+ result == ERR_SSL_BAD_RECORD_MAC_ALERT) &&
+ ssl_config_.tls1_enabled &&
+ !SSLConfigService::IsKnownStrictTLSServer(request_->url.host())) {
+ // Some buggy servers select DEFLATE compression when offered and then
+ // fail to ever decompress anything. They will send a fatal alert telling
+ // us this. Normally we would pick this up during the handshake because
+ // our Finished message is compressed and we'll never get the server's
+ // Finished if it fails to process ours.
+ //
+ // However, with False Start, we'll believe that the handshake is
+ // complete as soon as we've /sent/ our Finished message. In this case,
+ // we only find out that the server is buggy here, when we try to read
+ // the initial reply.
+ session_->http_stream_factory()->AddTLSIntolerantServer(request_->url);
+ ResetConnectionAndRequestForResend();
+ return OK;
}
if (result < 0 && result != ERR_CONNECTION_CLOSED)
@@ -994,61 +1024,11 @@ int HttpNetworkTransaction::HandleCertificateRequest(int error) {
return OK;
}
-// TODO(rch): This does not correctly handle errors when an SSL proxy is
-// being used, as all of the errors are handled as if they were generated
-// by the endpoint host, request_->url, rather than considering if they were
-// generated by the SSL proxy. http://crbug.com/66424
-int HttpNetworkTransaction::HandleSSLHandshakeError(int error) {
- DCHECK(request_);
- if (ssl_config_.send_client_cert &&
- (error == ERR_SSL_PROTOCOL_ERROR ||
- error == ERR_BAD_SSL_CLIENT_AUTH_CERT)) {
- session_->ssl_client_auth_cache()->Remove(
- GetHostAndPort(request_->url));
- }
-
- switch (error) {
- case ERR_SSL_PROTOCOL_ERROR:
- case ERR_SSL_VERSION_OR_CIPHER_MISMATCH:
- case ERR_SSL_DECOMPRESSION_FAILURE_ALERT:
- case ERR_SSL_BAD_RECORD_MAC_ALERT:
- if (ssl_config_.tls1_enabled &&
- !SSLConfigService::IsKnownStrictTLSServer(request_->url.host())) {
- // This could be a TLS-intolerant server, an SSL 3.0 server that
- // chose a TLS-only cipher suite or a server with buggy DEFLATE
- // support. Turn off TLS 1.0, DEFLATE support and retry.
- session_->http_stream_factory()->AddTLSIntolerantServer(request_->url);
- ResetConnectionAndRequestForResend();
- error = OK;
- }
- break;
- case ERR_SSL_SNAP_START_NPN_MISPREDICTION:
- // This means that we tried to Snap Start a connection, but we
- // mispredicted the NPN result. This isn't a problem from the point of
- // view of the SSL layer because the server will ignore the application
- // data in the Snap Start extension. However, at the HTTP layer, we have
- // already decided that it's a HTTP or SPDY connection and it's easier to
- // abort and start again.
- ResetConnectionAndRequestForResend();
- error = OK;
- break;
- }
- return error;
-}
-
// This method determines whether it is safe to resend the request after an
// IO error. It can only be called in response to request header or body
// write errors or response header read errors. It should not be used in
// other cases, such as a Connect error.
int HttpNetworkTransaction::HandleIOError(int error) {
- // SSL errors may happen at any time during the stream and indicate issues
- // with the underlying connection. Because the peer may request
- // renegotiation at any time, check and handle any possible SSL handshake
- // related errors. In addition to renegotiation, TLS False/Snap Start may
- // cause SSL handshake errors to be delayed until the first Read on the
- // underlying connection.
- error = HandleSSLHandshakeError(error);
-
switch (error) {
// If we try to reuse a connection that the server is in the process of
// closing, we may end up successfully writing out our request (or a
@@ -1062,6 +1042,16 @@ int HttpNetworkTransaction::HandleIOError(int error) {
error = OK;
}
break;
+ case ERR_SSL_SNAP_START_NPN_MISPREDICTION:
+ // This means that we tried to Snap Start a connection, but we
+ // mispredicted the NPN result. This isn't a problem from the point of
+ // view of the SSL layer because the server will ignore the application
+ // data in the Snap Start extension. However, at the HTTP layer, we have
+ // already decided that it's a HTTP or SPDY connection and it's easier to
+ // abort and start again.
+ ResetConnectionAndRequestForResend();
+ error = OK;
+ break;
}
return error;
}
diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h
index 0595813..dfcee41 100644
--- a/net/http/http_network_transaction.h
+++ b/net/http/http_network_transaction.h
@@ -65,6 +65,8 @@ class HttpNetworkTransaction : public HttpTransaction,
const HttpResponseInfo& response_info,
HttpAuthController* auth_controller);
virtual void OnNeedsClientAuth(SSLCertRequestInfo* cert_info);
+ virtual void OnHttpsProxyTunnelResponse(const HttpResponseInfo& response_info,
+ HttpStream* stream);
private:
FRIEND_TEST_ALL_PREFIXES(HttpNetworkTransactionTest, ResetStateForRestart);
@@ -135,11 +137,6 @@ class HttpNetworkTransaction : public HttpTransaction,
// Called to handle a client certificate request.
int HandleCertificateRequest(int error);
- // Called to possibly recover from an SSL handshake error. Sets next_state_
- // and returns OK if recovering from the error. Otherwise, the same error
- // code is returned.
- int HandleSSLHandshakeError(int error);
-
// Called to possibly recover from the given error. Sets next_state_ and
// returns OK if recovering from the error. Otherwise, the same error code
// is returned.
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index b9acbfc..260de13 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -20,7 +20,6 @@
#include "net/base/net_log.h"
#include "net/base/net_log_unittest.h"
#include "net/base/request_priority.h"
-#include "net/base/ssl_cert_request_info.h"
#include "net/base/ssl_config_service_defaults.h"
#include "net/base/ssl_info.h"
#include "net/base/test_completion_callback.h"
@@ -75,6 +74,7 @@ struct SessionDependencies {
// Default set of dependencies -- "null" proxy service.
SessionDependencies()
: host_resolver(new MockHostResolver),
+ cert_verifier(new CertVerifier),
proxy_service(ProxyService::CreateDirect()),
ssl_config_service(new SSLConfigServiceDefaults),
http_auth_handler_factory(
@@ -84,6 +84,7 @@ struct SessionDependencies {
// Custom proxy service dependency.
explicit SessionDependencies(ProxyService* proxy_service)
: host_resolver(new MockHostResolver),
+ cert_verifier(new CertVerifier),
proxy_service(proxy_service),
ssl_config_service(new SSLConfigServiceDefaults),
http_auth_handler_factory(
@@ -91,6 +92,7 @@ struct SessionDependencies {
net_log(NULL) {}
scoped_ptr<MockHostResolverBase> host_resolver;
+ scoped_ptr<CertVerifier> cert_verifier;
scoped_refptr<ProxyService> proxy_service;
scoped_refptr<SSLConfigService> ssl_config_service;
MockClientSocketFactory socket_factory;
@@ -100,6 +102,7 @@ struct SessionDependencies {
HttpNetworkSession* CreateSession(SessionDependencies* session_deps) {
return new HttpNetworkSession(session_deps->host_resolver.get(),
+ session_deps->cert_verifier.get(),
NULL /* dnsrr_resolver */,
NULL /* dns_cert_checker */,
NULL /* ssl_host_info_factory */,
@@ -175,15 +178,18 @@ class HttpNetworkTransactionTest : public PlatformTest {
rv = ReadTransaction(trans.get(), &out.response_data);
EXPECT_EQ(OK, rv);
+
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
size_t pos = ExpectLogContainsSomewhere(
- log.entries(), 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_HEADERS,
+ entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_HEADERS,
NetLog::PHASE_NONE);
ExpectLogContainsSomewhere(
- log.entries(), pos,
+ entries, pos,
NetLog::TYPE_HTTP_TRANSACTION_READ_RESPONSE_HEADERS,
NetLog::PHASE_NONE);
- CapturingNetLog::Entry entry = log.entries()[pos];
+ CapturingNetLog::Entry entry = entries[pos];
NetLogHttpRequestParameter* request_params =
static_cast<NetLogHttpRequestParameter*>(entry.extra_parameters.get());
EXPECT_EQ("GET / HTTP/1.1\r\n", request_params->GetLine());
@@ -308,7 +314,8 @@ CaptureGroupNameHttpProxySocketPool::CaptureGroupNameSocketPool(
template<>
CaptureGroupNameSSLSocketPool::CaptureGroupNameSocketPool(
HttpNetworkSession* session)
- : SSLClientSocketPool(0, 0, NULL, session->host_resolver(), NULL, NULL,
+ : SSLClientSocketPool(0, 0, NULL, session->host_resolver(),
+ session->cert_verifier(), NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL) {}
//-----------------------------------------------------------------------------
@@ -1526,11 +1533,13 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthProxyNoKeepAlive) {
rv = callback1.WaitForResult();
EXPECT_EQ(OK, rv);
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
size_t pos = ExpectLogContainsSomewhere(
- log.entries(), 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
+ entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
NetLog::PHASE_NONE);
ExpectLogContainsSomewhere(
- log.entries(), pos,
+ entries, pos,
NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
NetLog::PHASE_NONE);
@@ -1630,11 +1639,13 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthProxyKeepAlive) {
rv = callback1.WaitForResult();
EXPECT_EQ(OK, rv);
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
size_t pos = ExpectLogContainsSomewhere(
- log.entries(), 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
+ entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
NetLog::PHASE_NONE);
ExpectLogContainsSomewhere(
- log.entries(), pos,
+ entries, pos,
NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
NetLog::PHASE_NONE);
@@ -1832,11 +1843,13 @@ TEST_F(HttpNetworkTransactionTest, HttpsServerRequestsProxyAuthThroughProxy) {
rv = callback1.WaitForResult();
EXPECT_EQ(ERR_UNEXPECTED_PROXY_AUTH, rv);
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
size_t pos = ExpectLogContainsSomewhere(
- log.entries(), 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
+ entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
NetLog::PHASE_NONE);
ExpectLogContainsSomewhere(
- log.entries(), pos,
+ entries, pos,
NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
NetLog::PHASE_NONE);
}
@@ -2267,10 +2280,11 @@ TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyConnectFailure) {
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback1.WaitForResult();
- EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
+ EXPECT_EQ(OK, rv);
const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response == NULL);
+ ASSERT_FALSE(response == NULL);
+ EXPECT_EQ(500, response->headers->response_code());
}
// Test the challenge-response-retry sequence through an HTTPS Proxy
@@ -4458,6 +4472,238 @@ TEST_F(HttpNetworkTransactionTest, HTTPSViaHttpsProxy) {
EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
}
+// Test an HTTPS Proxy's ability to redirect a CONNECT request
+TEST_F(HttpNetworkTransactionTest, RedirectOfHttpsConnectViaHttpsProxy) {
+ SessionDependencies session_deps(
+ ProxyService::CreateFixed("https://proxy:70"));
+
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("https://www.google.com/");
+ request.load_flags = 0;
+
+ MockWrite data_writes[] = {
+ MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Proxy-Connection: keep-alive\r\n\r\n"),
+ };
+
+ MockRead data_reads[] = {
+ MockRead("HTTP/1.1 302 Redirect\r\n"),
+ MockRead("Location: http://login.example.com/\r\n"),
+ MockRead("Content-Length: 0\r\n\r\n"),
+ MockRead(false, OK),
+ };
+
+ StaticSocketDataProvider data(data_reads, arraysize(data_reads),
+ data_writes, arraysize(data_writes));
+ SSLSocketDataProvider proxy_ssl(true, OK); // SSL to the proxy
+
+ session_deps.socket_factory.AddSocketDataProvider(&data);
+ session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl);
+
+ TestCompletionCallback callback;
+
+ scoped_ptr<HttpTransaction> trans(
+ new HttpNetworkTransaction(CreateSession(&session_deps)));
+
+ int rv = trans->Start(&request, &callback, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ rv = callback.WaitForResult();
+ EXPECT_EQ(OK, rv);
+ const HttpResponseInfo* response = trans->GetResponseInfo();
+
+ ASSERT_FALSE(response == NULL);
+
+ EXPECT_EQ(302, response->headers->response_code());
+ std::string url;
+ EXPECT_TRUE(response->headers->IsRedirect(&url));
+ EXPECT_EQ("http://login.example.com/", url);
+}
+
+// Test an HTTPS (SPDY) Proxy's ability to redirect a CONNECT request
+TEST_F(HttpNetworkTransactionTest, RedirectOfHttpsConnectViaSpdyProxy) {
+ SessionDependencies session_deps(
+ ProxyService::CreateFixed("https://proxy:70"));
+
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("https://www.google.com/");
+ request.load_flags = 0;
+
+ scoped_ptr<spdy::SpdyFrame> conn(ConstructSpdyConnect(NULL, 0, 1));
+ scoped_ptr<spdy::SpdyFrame> goaway(ConstructSpdyRstStream(1, spdy::CANCEL));
+ MockWrite data_writes[] = {
+ CreateMockWrite(*conn.get(), 0, false),
+ };
+
+ static const char* const kExtraHeaders[] = {
+ "location",
+ "http://login.example.com/",
+ };
+ scoped_ptr<spdy::SpdyFrame> resp(
+ ConstructSpdySynReplyError("302 Redirect", kExtraHeaders,
+ arraysize(kExtraHeaders)/2, 1));
+ MockRead data_reads[] = {
+ CreateMockRead(*resp.get(), 1, false),
+ MockRead(true, 0, 2), // EOF
+ };
+
+ scoped_refptr<DelayedSocketData> data(
+ new DelayedSocketData(
+ 1, // wait for one write to finish before reading.
+ data_reads, arraysize(data_reads),
+ data_writes, arraysize(data_writes)));
+ SSLSocketDataProvider proxy_ssl(true, OK); // SSL to the proxy
+ proxy_ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
+ proxy_ssl.next_proto = "spdy/2";
+ proxy_ssl.was_npn_negotiated = true;
+
+ session_deps.socket_factory.AddSocketDataProvider(data.get());
+ session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl);
+
+ TestCompletionCallback callback;
+
+ scoped_ptr<HttpTransaction> trans(
+ new HttpNetworkTransaction(CreateSession(&session_deps)));
+
+ int rv = trans->Start(&request, &callback, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ rv = callback.WaitForResult();
+ EXPECT_EQ(OK, rv);
+ const HttpResponseInfo* response = trans->GetResponseInfo();
+
+ ASSERT_FALSE(response == NULL);
+
+ EXPECT_EQ(302, response->headers->response_code());
+ std::string url;
+ EXPECT_TRUE(response->headers->IsRedirect(&url));
+ EXPECT_EQ("http://login.example.com/", url);
+}
+
+// Test an HTTPS Proxy's ability to provide a response to a CONNECT request
+TEST_F(HttpNetworkTransactionTest, ErrorResponseTofHttpsConnectViaHttpsProxy) {
+ SessionDependencies session_deps(
+ ProxyService::CreateFixed("https://proxy:70"));
+
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("https://www.google.com/");
+ request.load_flags = 0;
+
+ MockWrite data_writes[] = {
+ MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Proxy-Connection: keep-alive\r\n\r\n"),
+ };
+
+ MockRead data_reads[] = {
+ MockRead("HTTP/1.1 404 Not Found\r\n"),
+ MockRead("Content-Length: 23\r\n\r\n"),
+ MockRead("The host does not exist"),
+ MockRead(false, OK),
+ };
+
+ StaticSocketDataProvider data(data_reads, arraysize(data_reads),
+ data_writes, arraysize(data_writes));
+ SSLSocketDataProvider proxy_ssl(true, OK); // SSL to the proxy
+
+ session_deps.socket_factory.AddSocketDataProvider(&data);
+ session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl);
+
+ TestCompletionCallback callback;
+
+ scoped_ptr<HttpTransaction> trans(
+ new HttpNetworkTransaction(CreateSession(&session_deps)));
+
+ int rv = trans->Start(&request, &callback, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ rv = callback.WaitForResult();
+ EXPECT_EQ(OK, rv);
+ const HttpResponseInfo* response = trans->GetResponseInfo();
+
+ ASSERT_FALSE(response == NULL);
+
+ EXPECT_EQ(404, response->headers->response_code());
+ EXPECT_EQ(23, response->headers->GetContentLength());
+ EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
+ EXPECT_FALSE(response->ssl_info.is_valid());
+
+ std::string response_data;
+ ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ EXPECT_EQ("The host does not exist", response_data);
+}
+
+// Test an HTTPS (SPDY) Proxy's ability to provide a response to a CONNECT
+// request
+TEST_F(HttpNetworkTransactionTest, ErrorResponseTofHttpsConnectViaSpdyProxy) {
+ SessionDependencies session_deps(
+ ProxyService::CreateFixed("https://proxy:70"));
+
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("https://www.google.com/");
+ request.load_flags = 0;
+
+ scoped_ptr<spdy::SpdyFrame> conn(ConstructSpdyConnect(NULL, 0, 1));
+ scoped_ptr<spdy::SpdyFrame> goaway(ConstructSpdyRstStream(1, spdy::CANCEL));
+ MockWrite data_writes[] = {
+ CreateMockWrite(*conn.get(), 0, false),
+ };
+
+ static const char* const kExtraHeaders[] = {
+ "location",
+ "http://login.example.com/",
+ };
+ scoped_ptr<spdy::SpdyFrame> resp(
+ ConstructSpdySynReplyError("404 Not Found", kExtraHeaders,
+ arraysize(kExtraHeaders)/2, 1));
+ scoped_ptr<spdy::SpdyFrame> body(
+ ConstructSpdyBodyFrame(1, "The host does not exist", 23, true));
+ MockRead data_reads[] = {
+ CreateMockRead(*resp.get(), 1, false),
+ CreateMockRead(*body.get(), 2, false),
+ MockRead(true, 0, 3), // EOF
+ };
+
+ scoped_refptr<DelayedSocketData> data(
+ new DelayedSocketData(
+ 1, // wait for one write to finish before reading.
+ data_reads, arraysize(data_reads),
+ data_writes, arraysize(data_writes)));
+ SSLSocketDataProvider proxy_ssl(true, OK); // SSL to the proxy
+ proxy_ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated;
+ proxy_ssl.next_proto = "spdy/2";
+ proxy_ssl.was_npn_negotiated = true;
+
+ session_deps.socket_factory.AddSocketDataProvider(data.get());
+ session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl);
+
+ TestCompletionCallback callback;
+
+ scoped_ptr<HttpTransaction> trans(
+ new HttpNetworkTransaction(CreateSession(&session_deps)));
+
+ int rv = trans->Start(&request, &callback, BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ rv = callback.WaitForResult();
+ EXPECT_EQ(OK, rv);
+ const HttpResponseInfo* response = trans->GetResponseInfo();
+
+ ASSERT_FALSE(response == NULL);
+
+ EXPECT_EQ(404, response->headers->response_code());
+ EXPECT_FALSE(response->ssl_info.is_valid());
+
+ std::string response_data;
+ ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
+ EXPECT_EQ("The host does not exist", response_data);
+}
+
// Test HTTPS connections to a site with a bad certificate, going through an
// HTTPS proxy
TEST_F(HttpNetworkTransactionTest, HTTPSBadCertificateViaHttpsProxy) {
@@ -6465,6 +6711,10 @@ class CapturingProxyResolver : public ProxyResolver {
NOTREACHED();
}
+ virtual void CancelSetPacScript() {
+ NOTREACHED();
+ }
+
virtual int SetPacScript(const scoped_refptr<ProxyResolverScriptData>&,
CompletionCallback* /*callback*/) {
return OK;
@@ -6671,7 +6921,8 @@ TEST_F(HttpNetworkTransactionTest,
session->ssl_config_service()->GetSSLConfig(&ssl_config);
ClientSocket* socket = connection->release_socket();
socket = session->socket_factory()->CreateSSLClientSocket(
- socket, HostPortPair("" , 443), ssl_config, NULL /* ssl_host_info */);
+ socket, HostPortPair("" , 443), ssl_config, NULL /* ssl_host_info */,
+ session->cert_verifier());
connection->set_socket(socket);
EXPECT_EQ(ERR_IO_PENDING, socket->Connect(&callback));
EXPECT_EQ(OK, callback.WaitForResult());
@@ -7725,11 +7976,13 @@ TEST_F(HttpNetworkTransactionTest, ProxyTunnelGet) {
rv = callback1.WaitForResult();
EXPECT_EQ(OK, rv);
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
size_t pos = ExpectLogContainsSomewhere(
- log.entries(), 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
+ entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
NetLog::PHASE_NONE);
ExpectLogContainsSomewhere(
- log.entries(), pos,
+ entries, pos,
NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
NetLog::PHASE_NONE);
@@ -7787,11 +8040,13 @@ TEST_F(HttpNetworkTransactionTest, ProxyTunnelGetHangup) {
rv = callback1.WaitForResult();
EXPECT_EQ(ERR_EMPTY_RESPONSE, rv);
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
size_t pos = ExpectLogContainsSomewhere(
- log.entries(), 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
+ entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
NetLog::PHASE_NONE);
ExpectLogContainsSomewhere(
- log.entries(), pos,
+ entries, pos,
NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
NetLog::PHASE_NONE);
}
@@ -7952,303 +8207,4 @@ TEST_F(HttpNetworkTransactionTest, NPNMispredict) {
EXPECT_EQ("hello world", contents);
}
-// Ensure that a client certificate is removed from the SSL client auth
-// cache when:
-// 1) No proxy is involved.
-// 2) TLS False Start is disabled.
-// 3) The initial TLS handshake requests a client certificate.
-// 4) The client supplies an invalid/unacceptable certificate.
-TEST_F(HttpNetworkTransactionTest, ClientAuthCertCache_Direct_NoFalseStart) {
- SessionDependencies session_deps;
-
- scoped_refptr<SSLCertRequestInfo> cert_request(new SSLCertRequestInfo());
- cert_request->host_and_port = "www.example.com:443";
-
- // [ssl_]data1 contains the data for the first SSL handshake. When a
- // CertificateRequest is received for the first time, the handshake will
- // be aborted to allow the caller to provide a certificate.
- SSLSocketDataProvider ssl_data1(true /* async */,
- net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
- ssl_data1.cert_request_info = cert_request.get();
- session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data1);
- net::StaticSocketDataProvider data1(NULL, 0, NULL, 0);
- session_deps.socket_factory.AddSocketDataProvider(&data1);
-
- // [ssl_]data2 contains the data for the second SSL handshake. When TLS
- // False Start is not being used, the result of the SSL handshake will be
- // returned as part of the SSLClientSocket::Connect() call. This test
- // matches the result of a server sending a handshake_failure alert,
- // rather than a Finished message, because it requires a client
- // certificate and none was supplied.
- SSLSocketDataProvider ssl_data2(true /* async */,
- net::ERR_SSL_PROTOCOL_ERROR);
- ssl_data2.cert_request_info = cert_request.get();
- session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data2);
- net::StaticSocketDataProvider data2(NULL, 0, NULL, 0);
- session_deps.socket_factory.AddSocketDataProvider(&data2);
-
- // [ssl_]data3 contains the data for the third SSL handshake. When a
- // connection to a server fails during an SSL handshake,
- // HttpNetworkTransaction will attempt to fallback to SSLv3 if the initial
- // connection was attempted with TLSv1. This is transparent to the caller
- // of the HttpNetworkTransaction. Because this test failure is due to
- // requiring a client certificate, this fallback handshake should also
- // fail.
- SSLSocketDataProvider ssl_data3(true /* async */,
- net::ERR_SSL_PROTOCOL_ERROR);
- ssl_data3.cert_request_info = cert_request.get();
- session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data3);
- net::StaticSocketDataProvider data3(NULL, 0, NULL, 0);
- session_deps.socket_factory.AddSocketDataProvider(&data3);
-
- scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
- scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session));
-
- net::HttpRequestInfo request_info;
- request_info.url = GURL("https://www.example.com/");
- request_info.method = "GET";
- request_info.load_flags = net::LOAD_NORMAL;
-
- // Begin the SSL handshake with the peer. This consumes ssl_data1.
- TestCompletionCallback callback;
- int rv = trans->Start(&request_info, &callback, net::BoundNetLog());
- ASSERT_EQ(net::ERR_IO_PENDING, rv);
-
- // Complete the SSL handshake, which should abort due to requiring a
- // client certificate.
- rv = callback.WaitForResult();
- ASSERT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv);
-
- // Indicate that no certificate should be supplied. From the perspective
- // of SSLClientCertCache, NULL is just as meaningful as a real
- // certificate, so this is the same as supply a
- // legitimate-but-unacceptable certificate.
- rv = trans->RestartWithCertificate(NULL, &callback);
- ASSERT_EQ(net::ERR_IO_PENDING, rv);
-
- // Ensure the certificate was added to the client auth cache before
- // allowing the connection to continue restarting.
- scoped_refptr<X509Certificate> client_cert;
- ASSERT_TRUE(session->ssl_client_auth_cache()->Lookup("www.example.com:443",
- &client_cert));
- ASSERT_EQ(NULL, client_cert.get());
-
- // Restart the handshake. This will consume ssl_data2, which fails, and
- // then consume ssl_data3, which should also fail. The result code is
- // checked against what ssl_data3 should return.
- rv = callback.WaitForResult();
- ASSERT_EQ(net::ERR_SSL_PROTOCOL_ERROR, rv);
-
- // Ensure that the client certificate is removed from the cache on a
- // handshake failure.
- ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("www.example.com:443",
- &client_cert));
-}
-
-// Ensure that a client certificate is removed from the SSL client auth
-// cache when:
-// 1) No proxy is involved.
-// 2) TLS False Start is enabled.
-// 3) The initial TLS handshake requests a client certificate.
-// 4) The client supplies an invalid/unacceptable certificate.
-TEST_F(HttpNetworkTransactionTest, ClientAuthCertCache_Direct_FalseStart) {
- SessionDependencies session_deps;
-
- scoped_refptr<SSLCertRequestInfo> cert_request(new SSLCertRequestInfo());
- cert_request->host_and_port = "www.example.com:443";
-
- // When TLS False Start is used, SSLClientSocket::Connect() calls will
- // return successfully after reading up to the peer's Certificate message.
- // This is to allow the caller to call SSLClientSocket::Write(), which can
- // enqueue application data to be sent in the same packet as the
- // ChangeCipherSpec and Finished messages.
- // The actual handshake will be finished when SSLClientSocket::Read() is
- // called, which expects to process the peer's ChangeCipherSpec and
- // Finished messages. If there was an error negotiating with the peer,
- // such as due to the peer requiring a client certificate when none was
- // supplied, the alert sent by the peer won't be processed until Read() is
- // called.
-
- // Like the non-False Start case, when a client certificate is requested by
- // the peer, the handshake is aborted during the Connect() call.
- // [ssl_]data1 represents the initial SSL handshake with the peer.
- SSLSocketDataProvider ssl_data1(true /* async */,
- net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
- ssl_data1.cert_request_info = cert_request.get();
- session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data1);
- net::StaticSocketDataProvider data1(NULL, 0, NULL, 0);
- session_deps.socket_factory.AddSocketDataProvider(&data1);
-
- // When a client certificate is supplied, Connect() will not be aborted
- // when the peer requests the certificate. Instead, the handshake will
- // artificially succeed, allowing the caller to write the HTTP request to
- // the socket. The handshake messages are not processed until Read() is
- // called, which then detects that the handshake was aborted, due to the
- // peer sending a handshake_failure because it requires a client
- // certificate.
- SSLSocketDataProvider ssl_data2(true /* async */, net::OK);
- ssl_data2.cert_request_info = cert_request.get();
- session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data2);
- net::MockRead data2_reads[] = {
- net::MockRead(true /* async */, net::ERR_SSL_PROTOCOL_ERROR),
- };
- net::StaticSocketDataProvider data2(
- data2_reads, arraysize(data2_reads), NULL, 0);
- session_deps.socket_factory.AddSocketDataProvider(&data2);
-
- // As described in ClientAuthCertCache_Direct_NoFalseStart, [ssl_]data3 is
- // the data for the SSL handshake once the TLSv1 connection falls back to
- // SSLv3. It has the same behaviour as [ssl_]data2.
- SSLSocketDataProvider ssl_data3(true /* async */, net::OK);
- ssl_data3.cert_request_info = cert_request.get();
- session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data3);
- net::StaticSocketDataProvider data3(
- data2_reads, arraysize(data2_reads), NULL, 0);
- session_deps.socket_factory.AddSocketDataProvider(&data3);
-
- scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
- scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session));
-
- net::HttpRequestInfo request_info;
- request_info.url = GURL("https://www.example.com/");
- request_info.method = "GET";
- request_info.load_flags = net::LOAD_NORMAL;
-
- // Begin the initial SSL handshake.
- TestCompletionCallback callback;
- int rv = trans->Start(&request_info, &callback, net::BoundNetLog());
- ASSERT_EQ(net::ERR_IO_PENDING, rv);
-
- // Complete the SSL handshake, which should abort due to requiring a
- // client certificate.
- rv = callback.WaitForResult();
- ASSERT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv);
-
- // Indicate that no certificate should be supplied. From the perspective
- // of SSLClientCertCache, NULL is just as meaningful as a real
- // certificate, so this is the same as supply a
- // legitimate-but-unacceptable certificate.
- rv = trans->RestartWithCertificate(NULL, &callback);
- ASSERT_EQ(net::ERR_IO_PENDING, rv);
-
- // Ensure the certificate was added to the client auth cache before
- // allowing the connection to continue restarting.
- scoped_refptr<X509Certificate> client_cert;
- ASSERT_TRUE(session->ssl_client_auth_cache()->Lookup("www.example.com:443",
- &client_cert));
- ASSERT_EQ(NULL, client_cert.get());
-
-
- // Restart the handshake. This will consume ssl_data2, which fails, and
- // then consume ssl_data3, which should also fail. The result code is
- // checked against what ssl_data3 should return.
- rv = callback.WaitForResult();
- ASSERT_EQ(net::ERR_SSL_PROTOCOL_ERROR, rv);
-
- // Ensure that the client certificate is removed from the cache on a
- // handshake failure.
- ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("www.example.com:443",
- &client_cert));
-}
-
-// Ensure that a client certificate is removed from the SSL client auth
-// cache when:
-// 1) An HTTPS proxy is involved.
-// 3) The HTTPS proxy requests a client certificate.
-// 4) The client supplies an invalid/unacceptable certificate for the
-// proxy.
-// The test is repeated twice, first for connecting to an HTTPS endpoint,
-// then for connecting to an HTTP endpoint.
-TEST_F(HttpNetworkTransactionTest, ClientAuthCertCache_Proxy_Fail) {
- SessionDependencies session_deps(
- ProxyService::CreateFixed("https://proxy:70"));
- CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
- session_deps.net_log = log.bound().net_log();
-
- scoped_refptr<SSLCertRequestInfo> cert_request(new SSLCertRequestInfo());
- cert_request->host_and_port = "proxy:70";
-
- // See ClientAuthCertCache_Direct_NoFalseStart for the explanation of
- // [ssl_]data[1-3]. Rather than represending the endpoint
- // (www.example.com:443), they represent failures with the HTTPS proxy
- // (proxy:70).
- SSLSocketDataProvider ssl_data1(true /* async */,
- net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
- ssl_data1.cert_request_info = cert_request.get();
- session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data1);
- net::StaticSocketDataProvider data1(NULL, 0, NULL, 0);
- session_deps.socket_factory.AddSocketDataProvider(&data1);
-
- SSLSocketDataProvider ssl_data2(true /* async */,
- net::ERR_SSL_PROTOCOL_ERROR);
- ssl_data2.cert_request_info = cert_request.get();
- session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data2);
- net::StaticSocketDataProvider data2(NULL, 0, NULL, 0);
- session_deps.socket_factory.AddSocketDataProvider(&data2);
-
- SSLSocketDataProvider ssl_data3(true /* async */,
- net::ERR_SSL_PROTOCOL_ERROR);
- ssl_data3.cert_request_info = cert_request.get();
- session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data3);
- net::StaticSocketDataProvider data3(NULL, 0, NULL, 0);
- session_deps.socket_factory.AddSocketDataProvider(&data3);
-
- net::HttpRequestInfo requests[2];
- requests[0].url = GURL("https://www.example.com/");
- requests[0].method = "GET";
- requests[0].load_flags = net::LOAD_NORMAL;
-
- requests[1].url = GURL("http://www.example.com/");
- requests[1].method = "GET";
- requests[1].load_flags = net::LOAD_NORMAL;
-
- for (size_t i = 0; i < arraysize(requests); ++i) {
- session_deps.socket_factory.ResetNextMockIndexes();
- scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
- scoped_ptr<HttpNetworkTransaction> trans(
- new HttpNetworkTransaction(session));
-
- // Begin the SSL handshake with the proxy.
- TestCompletionCallback callback;
- int rv = trans->Start(&requests[i], &callback, net::BoundNetLog());
- ASSERT_EQ(net::ERR_IO_PENDING, rv);
-
- // Complete the SSL handshake, which should abort due to requiring a
- // client certificate.
- rv = callback.WaitForResult();
- ASSERT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv);
-
- // Indicate that no certificate should be supplied. From the perspective
- // of SSLClientCertCache, NULL is just as meaningful as a real
- // certificate, so this is the same as supply a
- // legitimate-but-unacceptable certificate.
- rv = trans->RestartWithCertificate(NULL, &callback);
- ASSERT_EQ(net::ERR_IO_PENDING, rv);
-
- // Ensure the certificate was added to the client auth cache before
- // allowing the connection to continue restarting.
- scoped_refptr<X509Certificate> client_cert;
- ASSERT_TRUE(session->ssl_client_auth_cache()->Lookup("proxy:70",
- &client_cert));
- ASSERT_EQ(NULL, client_cert.get());
- // Ensure the certificate was NOT cached for the endpoint. This only
- // applies to HTTPS requests, but is fine to check for HTTP requests.
- ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("www.example.com:443",
- &client_cert));
-
- // Restart the handshake. This will consume ssl_data2, which fails, and
- // then consume ssl_data3, which should also fail. The result code is
- // checked against what ssl_data3 should return.
- rv = callback.WaitForResult();
- ASSERT_EQ(net::ERR_PROXY_CONNECTION_FAILED, rv);
-
- // Now that the new handshake has failed, ensure that the client
- // certificate was removed from the client auth cache.
- ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("proxy:70",
- &client_cert));
- ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("www.example.com:443",
- &client_cert));
- }
-}
-
} // namespace net
diff --git a/net/http/http_proxy_client_socket.cc b/net/http/http_proxy_client_socket.cc
index 1ff325c..efff248 100644
--- a/net/http/http_proxy_client_socket.cc
+++ b/net/http/http_proxy_client_socket.cc
@@ -12,6 +12,7 @@
#include "net/base/io_buffer.h"
#include "net/base/net_log.h"
#include "net/base/net_util.h"
+#include "net/http/http_basic_stream.h"
#include "net/http/http_net_log_params.h"
#include "net/http/http_network_session.h"
#include "net/http/http_proxy_utils.h"
@@ -31,7 +32,8 @@ HttpProxyClientSocket::HttpProxyClientSocket(
HttpAuthCache* http_auth_cache,
HttpAuthHandlerFactory* http_auth_handler_factory,
bool tunnel,
- bool using_spdy)
+ bool using_spdy,
+ bool is_https_proxy)
: ALLOW_THIS_IN_INITIALIZER_LIST(
io_callback_(this, &HttpProxyClientSocket::OnIOComplete)),
next_state_(STATE_NONE),
@@ -46,6 +48,7 @@ HttpProxyClientSocket::HttpProxyClientSocket(
: NULL),
tunnel_(tunnel),
using_spdy_(using_spdy),
+ is_https_proxy_(is_https_proxy),
net_log_(transport_socket->socket()->NetLog()) {
// Synthesize the bits of a request that we actually use.
request_.url = request_url;
@@ -59,6 +62,7 @@ HttpProxyClientSocket::~HttpProxyClientSocket() {
Disconnect();
}
+<<<<<<< HEAD
#ifdef ANDROID
// TODO(kristianm): handle the case when wait_for_connect is true
// (sync requests)
@@ -68,6 +72,15 @@ int HttpProxyClientSocket::Connect(CompletionCallback* callback
, bool wait_for_connect
#endif
) {
+=======
+HttpStream* HttpProxyClientSocket::CreateConnectResponseStream() {
+ return new HttpBasicStream(transport_.release(),
+ http_stream_parser_.release(), false);
+}
+
+
+int HttpProxyClientSocket::Connect(CompletionCallback* callback) {
+>>>>>>> chromium.org at r10.0.621.0
DCHECK(transport_.get());
DCHECK(transport_->socket());
DCHECK(!user_callback_);
@@ -153,7 +166,8 @@ void HttpProxyClientSocket::LogBlockedTunnelResponse(int response_code) const {
}
void HttpProxyClientSocket::Disconnect() {
- transport_->socket()->Disconnect();
+ if (transport_.get())
+ transport_->socket()->Disconnect();
// Reset other states to make sure they aren't mistakenly used later.
// These are the states initialized by Connect().
@@ -170,6 +184,10 @@ bool HttpProxyClientSocket::IsConnectedAndIdle() const {
transport_->socket()->IsConnectedAndIdle();
}
+const BoundNetLog& HttpProxyClientSocket::NetLog() const {
+ return net_log_;
+}
+
void HttpProxyClientSocket::SetSubresourceSpeculation() {
if (transport_.get() && transport_->socket()) {
transport_->socket()->SetSubresourceSpeculation();
@@ -413,6 +431,8 @@ int HttpProxyClientSocket::DoReadHeadersComplete(int result) {
return HandleAuthChallenge();
default:
+ if (is_https_proxy_)
+ return ERR_HTTPS_PROXY_TUNNEL_RESPONSE;
// For all other status codes, we conservatively fail the CONNECT
// request.
// We lose something by doing this. We have seen proxy 403, 404, and
diff --git a/net/http/http_proxy_client_socket.h b/net/http/http_proxy_client_socket.h
index 335f930..ef53c2d 100644
--- a/net/http/http_proxy_client_socket.h
+++ b/net/http/http_proxy_client_socket.h
@@ -17,7 +17,7 @@
#include "net/http/http_request_headers.h"
#include "net/http/http_request_info.h"
#include "net/http/http_response_info.h"
-#include "net/socket/client_socket.h"
+#include "net/http/proxy_client_socket.h"
class GURL;
@@ -32,7 +32,7 @@ class HttpStream;
class HttpStreamParser;
class IOBuffer;
-class HttpProxyClientSocket : public ClientSocket {
+class HttpProxyClientSocket : public ProxyClientSocket {
public:
// Takes ownership of |transport_socket|, which should already be connected
// by the time Connect() is called. If tunnel is true then on Connect()
@@ -45,7 +45,8 @@ class HttpProxyClientSocket : public ClientSocket {
HttpAuthCache* http_auth_cache,
HttpAuthHandlerFactory* http_auth_handler_factory,
bool tunnel,
- bool using_spdy);
+ bool using_spdy,
+ bool is_https_proxy);
// On destruction Disconnect() is called.
virtual ~HttpProxyClientSocket();
@@ -55,10 +56,12 @@ class HttpProxyClientSocket : public ClientSocket {
// RestartWithAuth.
int RestartWithAuth(CompletionCallback* callback);
- const HttpResponseInfo* GetResponseInfo() const {
+ const HttpResponseInfo* GetConnectResponseInfo() const {
return response_.headers ? &response_ : NULL;
}
+ virtual HttpStream* CreateConnectResponseStream();
+
const scoped_refptr<HttpAuthController>& auth_controller() {
return auth_;
}
@@ -78,7 +81,7 @@ class HttpProxyClientSocket : public ClientSocket {
virtual void Disconnect();
virtual bool IsConnected() const;
virtual bool IsConnectedAndIdle() const;
- virtual const BoundNetLog& NetLog() const { return net_log_; }
+ virtual const BoundNetLog& NetLog() const;
virtual void SetSubresourceSpeculation();
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
@@ -150,7 +153,7 @@ class HttpProxyClientSocket : public ClientSocket {
scoped_refptr<IOBuffer> drain_buf_;
// Stores the underlying socket.
- const scoped_ptr<ClientSocketHandle> transport_;
+ scoped_ptr<ClientSocketHandle> transport_;
// The hostname and port of the endpoint. This is not necessarily the one
// specified by the URL, due to Alternate-Protocol or fixed testing ports.
@@ -159,6 +162,8 @@ class HttpProxyClientSocket : public ClientSocket {
const bool tunnel_;
// If true, then the connection to the proxy is a SPDY connection.
const bool using_spdy_;
+ // If true, then SSL is used to communicate with this proxy
+ const bool is_https_proxy_;
std::string request_line_;
HttpRequestHeaders request_headers_;
diff --git a/net/http/http_proxy_client_socket_pool.cc b/net/http/http_proxy_client_socket_pool.cc
index 119321a..4680bb1 100644
--- a/net/http/http_proxy_client_socket_pool.cc
+++ b/net/http/http_proxy_client_socket_pool.cc
@@ -334,17 +334,25 @@ int HttpProxyConnectJob::DoHttpProxyConnect() {
params_->http_auth_cache(),
params_->http_auth_handler_factory(),
params_->tunnel(),
+<<<<<<< HEAD
using_spdy_));
return transport_socket_->Connect(&callback_
#ifdef ANDROID
, false
#endif
);
+=======
+ using_spdy_,
+ params_->ssl_params() != NULL));
+ return transport_socket_->Connect(&callback_);
+>>>>>>> chromium.org at r10.0.621.0
}
int HttpProxyConnectJob::DoHttpProxyConnectComplete(int result) {
- if (result == OK || result == ERR_PROXY_AUTH_REQUESTED)
+ if (result == OK || result == ERR_PROXY_AUTH_REQUESTED ||
+ result == ERR_HTTPS_PROXY_TUNNEL_RESPONSE) {
set_socket(transport_socket_.release());
+ }
return result;
}
@@ -442,6 +450,10 @@ void HttpProxyClientSocketPool::CloseIdleSockets() {
base_.CloseIdleSockets();
}
+int HttpProxyClientSocketPool::IdleSocketCount() const {
+ return base_.idle_socket_count();
+}
+
int HttpProxyClientSocketPool::IdleSocketCountInGroup(
const std::string& group_name) const {
return base_.IdleSocketCountInGroup(group_name);
@@ -474,4 +486,12 @@ DictionaryValue* HttpProxyClientSocketPool::GetInfoAsValue(
return dict;
}
+base::TimeDelta HttpProxyClientSocketPool::ConnectionTimeout() const {
+ return base_.ConnectionTimeout();
+}
+
+ClientSocketPoolHistograms* HttpProxyClientSocketPool::histograms() const {
+ return base_.histograms();
+}
+
} // namespace net
diff --git a/net/http/http_proxy_client_socket_pool.h b/net/http/http_proxy_client_socket_pool.h
index a6ef0b8..39a8896 100644
--- a/net/http/http_proxy_client_socket_pool.h
+++ b/net/http/http_proxy_client_socket_pool.h
@@ -15,6 +15,7 @@
#include "net/base/host_port_pair.h"
#include "net/http/http_auth.h"
#include "net/http/http_response_info.h"
+#include "net/http/proxy_client_socket.h"
#include "net/socket/client_socket_pool_base.h"
#include "net/socket/client_socket_pool_histograms.h"
#include "net/socket/client_socket_pool.h"
@@ -163,7 +164,7 @@ class HttpProxyConnectJob : public ConnectJob {
State next_state_;
CompletionCallbackImpl<HttpProxyConnectJob> callback_;
scoped_ptr<ClientSocketHandle> transport_socket_handle_;
- scoped_ptr<ClientSocket> transport_socket_;
+ scoped_ptr<ProxyClientSocket> transport_socket_;
bool using_spdy_;
HttpResponseInfo error_response_info_;
@@ -210,9 +211,7 @@ class HttpProxyClientSocketPool : public ClientSocketPool {
virtual void CloseIdleSockets();
- virtual int IdleSocketCount() const {
- return base_.idle_socket_count();
- }
+ virtual int IdleSocketCount() const;
virtual int IdleSocketCountInGroup(const std::string& group_name) const;
@@ -223,13 +222,9 @@ class HttpProxyClientSocketPool : public ClientSocketPool {
const std::string& type,
bool include_nested_pools) const;
- virtual base::TimeDelta ConnectionTimeout() const {
- return base_.ConnectionTimeout();
- }
+ virtual base::TimeDelta ConnectionTimeout() const;
- virtual ClientSocketPoolHistograms* histograms() const {
- return base_.histograms();
- };
+ virtual ClientSocketPoolHistograms* histograms() const;
private:
typedef ClientSocketPoolBase<HttpProxySocketParams> PoolBase;
diff --git a/net/http/http_proxy_client_socket_pool_unittest.cc b/net/http/http_proxy_client_socket_pool_unittest.cc
index 56fae19..8c6d545 100644
--- a/net/http/http_proxy_client_socket_pool_unittest.cc
+++ b/net/http/http_proxy_client_socket_pool_unittest.cc
@@ -62,9 +62,11 @@ class HttpProxyClientSocketPoolTest : public TestWithHttpParam {
ssl_histograms_("MockSSL"),
ssl_config_service_(new SSLConfigServiceDefaults),
host_resolver_(new MockHostResolver),
+ cert_verifier_(new CertVerifier),
ssl_socket_pool_(kMaxSockets, kMaxSocketsPerGroup,
&ssl_histograms_,
host_resolver_.get(),
+ cert_verifier_.get(),
NULL /* dnsrr_resolver */,
NULL /* dns_cert_checker */,
NULL /* ssl_host_info_factory */,
@@ -77,6 +79,7 @@ class HttpProxyClientSocketPoolTest : public TestWithHttpParam {
http_auth_handler_factory_(
HttpAuthHandlerFactory::CreateDefault(host_resolver_.get())),
session_(new HttpNetworkSession(host_resolver_.get(),
+ cert_verifier_.get(),
NULL /* dnsrr_resolver */,
NULL /* dns_cert_checker */,
NULL /* ssl_host_info_factory */,
@@ -192,6 +195,7 @@ class HttpProxyClientSocketPoolTest : public TestWithHttpParam {
ClientSocketPoolHistograms ssl_histograms_;
scoped_refptr<SSLConfigService> ssl_config_service_;
scoped_ptr<HostResolver> host_resolver_;
+ scoped_ptr<CertVerifier> cert_verifier_;
SSLClientSocketPool ssl_socket_pool_;
scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory_;
@@ -498,9 +502,18 @@ TEST_P(HttpProxyClientSocketPoolTest, TunnelSetupError) {
data_->RunFor(2);
- EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, callback_.WaitForResult());
- EXPECT_FALSE(handle_.is_initialized());
- EXPECT_FALSE(handle_.socket());
+ rv = callback_.WaitForResult();
+ if (GetParam() == HTTP) {
+ // HTTP Proxy CONNECT responses are not trustworthy
+ EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
+ EXPECT_FALSE(handle_.is_initialized());
+ EXPECT_FALSE(handle_.socket());
+ } else {
+ // HTTPS or SPDY Proxy CONNECT responses are trustworthy
+ EXPECT_EQ(ERR_HTTPS_PROXY_TUNNEL_RESPONSE, rv);
+ EXPECT_TRUE(handle_.is_initialized());
+ EXPECT_TRUE(handle_.socket());
+ }
}
// It would be nice to also test the timeouts in HttpProxyClientSocketPool.
diff --git a/net/http/http_response_body_drainer_unittest.cc b/net/http/http_response_body_drainer_unittest.cc
index 75f099a..76304f8 100644
--- a/net/http/http_response_body_drainer_unittest.cc
+++ b/net/http/http_response_body_drainer_unittest.cc
@@ -178,6 +178,7 @@ class HttpResponseBodyDrainerTest : public testing::Test {
NULL /* host_resolver */,
NULL /* dnsrr_resolver */,
NULL /* dns_cert_checker */,
+ NULL,
NULL /* ssl_host_info_factory */,
ProxyService::CreateDirect(),
NULL,
diff --git a/net/http/http_stream_factory.h b/net/http/http_stream_factory.h
index dceb00b..c5a0dc3 100644
--- a/net/http/http_stream_factory.h
+++ b/net/http/http_stream_factory.h
@@ -48,8 +48,8 @@ class HttpStreamFactory : public StreamFactory,
const BoundNetLog& net_log,
CompletionCallback* callback);
- void AddTLSIntolerantServer(const GURL& url);
- bool IsTLSIntolerantServer(const GURL& url);
+ virtual void AddTLSIntolerantServer(const GURL& url);
+ virtual bool IsTLSIntolerantServer(const GURL& url);
virtual void ProcessAlternateProtocol(
HttpAlternateProtocols* alternate_protocols,
@@ -66,6 +66,8 @@ class HttpStreamFactory : public StreamFactory,
// Turns spdy on or off.
static void set_spdy_enabled(bool value) {
spdy_enabled_ = value;
+ if (value == false)
+ set_next_protos("");
}
static bool spdy_enabled() { return spdy_enabled_; }
diff --git a/net/http/http_stream_factory_unittest.cc b/net/http/http_stream_factory_unittest.cc
index 63fce33..646f79c 100644
--- a/net/http/http_stream_factory_unittest.cc
+++ b/net/http/http_stream_factory_unittest.cc
@@ -7,6 +7,7 @@
#include <string>
#include "base/basictypes.h"
+#include "net/base/cert_verifier.h"
#include "net/base/mock_host_resolver.h"
#include "net/base/net_log.h"
#include "net/base/ssl_config_service_defaults.h"
@@ -27,6 +28,7 @@ struct SessionDependencies {
// Custom proxy service dependency.
explicit SessionDependencies(ProxyService* proxy_service)
: host_resolver(new MockHostResolver),
+ cert_verifier(new CertVerifier),
proxy_service(proxy_service),
ssl_config_service(new SSLConfigServiceDefaults),
http_auth_handler_factory(
@@ -34,6 +36,7 @@ struct SessionDependencies {
net_log(NULL) {}
scoped_ptr<MockHostResolverBase> host_resolver;
+ scoped_ptr<CertVerifier> cert_verifier;
scoped_refptr<ProxyService> proxy_service;
scoped_refptr<SSLConfigService> ssl_config_service;
MockClientSocketFactory socket_factory;
@@ -43,6 +46,7 @@ struct SessionDependencies {
HttpNetworkSession* CreateSession(SessionDependencies* session_deps) {
return new HttpNetworkSession(session_deps->host_resolver.get(),
+ session_deps->cert_verifier.get(),
NULL /* dnsrr_resolver */,
NULL /* dns_cert_checker */,
NULL /* ssl_host_info_factory */,
@@ -170,7 +174,8 @@ CapturePreconnectsHttpProxySocketPool::CapturePreconnectsSocketPool(
template<>
CapturePreconnectsSSLSocketPool::CapturePreconnectsSocketPool(
HttpNetworkSession* session)
- : SSLClientSocketPool(0, 0, NULL, session->host_resolver(), NULL, NULL,
+ : SSLClientSocketPool(0, 0, NULL, session->host_resolver(),
+ session->cert_verifier(), NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL) {}
TEST(HttpStreamFactoryTest, PreconnectDirect) {
diff --git a/net/http/http_stream_request.cc b/net/http/http_stream_request.cc
index fbe4a32..8f4c9b1 100644
--- a/net/http/http_stream_request.cc
+++ b/net/http/http_stream_request.cc
@@ -63,6 +63,7 @@ HttpStreamRequest::HttpStreamRequest(
force_spdy_always_(HttpStreamFactory::force_spdy_always()),
force_spdy_over_ssl_(HttpStreamFactory::force_spdy_over_ssl()),
spdy_certificate_error_(OK),
+ alternate_protocol_(HttpAlternateProtocols::UNINITIALIZED),
establishing_tunnel_(false),
was_alternate_protocol_available_(false),
was_npn_negotiated_(false),
@@ -147,6 +148,18 @@ LoadState HttpStreamRequest::GetLoadState() const {
}
}
+bool HttpStreamRequest::was_alternate_protocol_available() const {
+ return was_alternate_protocol_available_;
+}
+
+bool HttpStreamRequest::was_npn_negotiated() const {
+ return was_npn_negotiated_;
+}
+
+bool HttpStreamRequest::using_spdy() const {
+ return using_spdy_;
+}
+
void HttpStreamRequest::GetSSLInfo() {
DCHECK(using_ssl_);
DCHECK(!establishing_tunnel_);
@@ -193,6 +206,12 @@ void HttpStreamRequest::OnNeedsClientAuthCallback(
delegate_->OnNeedsClientAuth(cert_info);
}
+void HttpStreamRequest::OnHttpsProxyTunnelResponseCallback(
+ const HttpResponseInfo& response_info,
+ HttpStream* stream) {
+ delegate_->OnHttpsProxyTunnelResponse(response_info, stream);
+}
+
void HttpStreamRequest::OnPreconnectsComplete(int result) {
preconnect_delegate_->OnPreconnectsComplete(this, result);
}
@@ -240,7 +259,7 @@ int HttpStreamRequest::RunLoop(int result) {
HttpProxyClientSocket* http_proxy_socket =
static_cast<HttpProxyClientSocket*>(connection_->socket());
const HttpResponseInfo* tunnel_auth_response =
- http_proxy_socket->GetResponseInfo();
+ http_proxy_socket->GetConnectResponseInfo();
next_state_ = STATE_WAITING_USER_ACTION;
MessageLoop::current()->PostTask(
@@ -260,6 +279,23 @@ int HttpStreamRequest::RunLoop(int result) {
connection_->ssl_error_response_info().cert_request_info));
return ERR_IO_PENDING;
+ case ERR_HTTPS_PROXY_TUNNEL_RESPONSE:
+ {
+ DCHECK(connection_.get());
+ DCHECK(connection_->socket());
+ DCHECK(establishing_tunnel_);
+
+ ProxyClientSocket* proxy_socket =
+ static_cast<ProxyClientSocket*>(connection_->socket());
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &HttpStreamRequest::OnHttpsProxyTunnelResponseCallback,
+ *proxy_socket->GetConnectResponseInfo(),
+ proxy_socket->CreateConnectResponseStream()));
+ return ERR_IO_PENDING;
+ }
+
case OK:
next_state_ = STATE_DONE;
MessageLoop::current()->PostTask(
@@ -657,13 +693,15 @@ int HttpStreamRequest::DoInitConnectionComplete(int result) {
if (!force_spdy_over_ssl_ && force_spdy_always_)
SwitchToSpdyMode();
- if (result == ERR_PROXY_AUTH_REQUESTED) {
+ if (result == ERR_PROXY_AUTH_REQUESTED ||
+ result == ERR_HTTPS_PROXY_TUNNEL_RESPONSE) {
DCHECK(!ssl_started);
// Other state (i.e. |using_ssl_|) suggests that |connection_| will have an
// SSL socket, but there was an error before that could happen. This
// puts the in progress HttpProxy socket into |connection_| in order to
- // complete the auth. The tunnel restart code is careful to remove it
- // before returning control to the rest of this class.
+ // complete the auth (or read the response body). The tunnel restart code
+ // is careful to remove it before returning control to the rest of this
+ // class.
connection_.reset(connection_->release_pending_http_proxy_connection());
return result;
}
@@ -709,7 +747,7 @@ int HttpStreamRequest::DoInitConnectionComplete(int result) {
}
}
if (result < 0)
- return result;
+ return HandleSSLHandshakeError(result);
}
next_state_ = STATE_CREATE_STREAM;
@@ -739,7 +777,8 @@ int HttpStreamRequest::DoCreateStream() {
if (!using_spdy_) {
bool using_proxy = (proxy_info()->is_http() || proxy_info()->is_https()) &&
request_info().url.SchemeIs("http");
- stream_.reset(new HttpBasicStream(connection_.release(), using_proxy));
+ stream_.reset(new HttpBasicStream(connection_.release(), NULL,
+ using_proxy));
return OK;
}
@@ -787,8 +826,8 @@ int HttpStreamRequest::DoCreateStream() {
if (spdy_session->IsClosed())
return ERR_CONNECTION_CLOSED;
- bool useRelativeUrl = direct || request_info().url.SchemeIs("https");
- stream_.reset(new SpdyHttpStream(spdy_session, useRelativeUrl));
+ bool use_relative_url = direct || request_info().url.SchemeIs("https");
+ stream_.reset(new SpdyHttpStream(spdy_session, use_relative_url));
return OK;
}
@@ -856,18 +895,6 @@ scoped_refptr<SSLSocketParams> HttpStreamRequest::GenerateSSLParams(
ssl_config()->tls1_enabled = false;
}
- if (proxy_info()->is_https() && ssl_config()->send_client_cert) {
- // When connecting through an HTTPS proxy, disable TLS False Start so
- // that client authentication errors can be distinguished between those
- // originating from the proxy server (ERR_PROXY_CONNECTION_FAILED) and
- // those originating from the endpoint (ERR_SSL_PROTOCOL_ERROR /
- // ERR_BAD_SSL_CLIENT_AUTH_CERT).
- // TODO(rch): This assumes that the HTTPS proxy will only request a
- // client certificate during the initial handshake.
- // http://crbug.com/FIXME
- ssl_config()->false_start_enabled = false;
- }
-
UMA_HISTOGRAM_ENUMERATION("Net.ConnectionUsedSSLv3Fallback",
static_cast<int>(ssl_config()->ssl3_fallback), 2);
@@ -956,11 +983,6 @@ int HttpStreamRequest::ReconsiderProxyAfterError(int error) {
return error;
}
- if (proxy_info()->is_https() && ssl_config_->send_client_cert) {
- session_->ssl_client_auth_cache()->Remove(
- proxy_info()->proxy_server().host_port_pair().ToString());
- }
-
int rv = session_->proxy_service()->ReconsiderProxyAfterError(
request_info().url, proxy_info(), &io_callback_, &pac_request_,
net_log_);
@@ -1007,6 +1029,35 @@ int HttpStreamRequest::HandleCertificateError(int error) {
return error;
}
+int HttpStreamRequest::HandleSSLHandshakeError(int error) {
+ if (ssl_config()->send_client_cert &&
+ (error == ERR_SSL_PROTOCOL_ERROR ||
+ error == ERR_BAD_SSL_CLIENT_AUTH_CERT)) {
+ session_->ssl_client_auth_cache()->Remove(
+ GetHostAndPort(request_info().url));
+ }
+
+ switch (error) {
+ case ERR_SSL_PROTOCOL_ERROR:
+ case ERR_SSL_VERSION_OR_CIPHER_MISMATCH:
+ case ERR_SSL_DECOMPRESSION_FAILURE_ALERT:
+ case ERR_SSL_BAD_RECORD_MAC_ALERT:
+ if (ssl_config()->tls1_enabled &&
+ !SSLConfigService::IsKnownStrictTLSServer(
+ request_info().url.host())) {
+ // This could be a TLS-intolerant server, an SSL 3.0 server that
+ // chose a TLS-only cipher suite or a server with buggy DEFLATE
+ // support. Turn off TLS 1.0, DEFLATE support and retry.
+ factory_->AddTLSIntolerantServer(request_info().url);
+ next_state_ = STATE_INIT_CONNECTION;
+ DCHECK(!connection_.get() || !connection_->socket());
+ error = OK;
+ }
+ break;
+ }
+ return error;
+}
+
void HttpStreamRequest::SwitchToSpdyMode() {
if (HttpStreamFactory::spdy_enabled())
using_spdy_ = true;
diff --git a/net/http/http_stream_request.h b/net/http/http_stream_request.h
index c07dc1c..f20b5f3 100644
--- a/net/http/http_stream_request.h
+++ b/net/http/http_stream_request.h
@@ -69,11 +69,9 @@ class HttpStreamRequest : public StreamRequest {
const string16& password);
virtual LoadState GetLoadState() const;
- virtual bool was_alternate_protocol_available() const {
- return was_alternate_protocol_available_;
- }
- virtual bool was_npn_negotiated() const { return was_npn_negotiated_; }
- virtual bool using_spdy() const { return using_spdy_; }
+ virtual bool was_alternate_protocol_available() const;
+ virtual bool was_npn_negotiated() const;
+ virtual bool using_spdy() const;
private:
enum AlternateProtocolMode {
@@ -109,6 +107,8 @@ class HttpStreamRequest : public StreamRequest {
void OnNeedsProxyAuthCallback(const HttpResponseInfo& response_info,
HttpAuthController* auth_controller);
void OnNeedsClientAuthCallback(SSLCertRequestInfo* cert_info);
+ void OnHttpsProxyTunnelResponseCallback(const HttpResponseInfo& response_info,
+ HttpStream* stream);
void OnPreconnectsComplete(int result);
void OnIOComplete(int result);
@@ -172,6 +172,11 @@ class HttpStreamRequest : public StreamRequest {
// Called to handle a client certificate request.
int HandleCertificateRequest(int error);
+ // Called to possibly recover from an SSL handshake error. Sets next_state_
+ // and returns OK if recovering from the error. Otherwise, the same error
+ // code is returned.
+ int HandleSSLHandshakeError(int error);
+
// Moves this stream request into SPDY mode.
void SwitchToSpdyMode();
diff --git a/net/http/proxy_client_socket.h b/net/http/proxy_client_socket.h
new file mode 100644
index 0000000..6557c88
--- /dev/null
+++ b/net/http/proxy_client_socket.h
@@ -0,0 +1,35 @@
+// 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.
+
+#ifndef NET_HTTP_PROXY_CLIENT_SOCKET_H_
+#define NET_HTTP_PROXY_CLIENT_SOCKET_H_
+#pragma once
+
+#include "net/socket/client_socket.h"
+
+namespace net {
+
+class HttpStream;
+class HttpResponseInfo;
+
+class ProxyClientSocket : public ClientSocket {
+ public:
+ ProxyClientSocket() {}
+ virtual ~ProxyClientSocket() {}
+
+ // Returns the HttpResponseInfo (including HTTP Headers) from
+ // the response to the CONNECT request.
+ virtual const HttpResponseInfo* GetConnectResponseInfo() const = 0;
+
+ // Transfers ownership of a newly created HttpStream to the caller
+ // which can be used to read the response body.
+ virtual HttpStream* CreateConnectResponseStream() = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ProxyClientSocket);
+};
+
+} // namespace net
+
+#endif // NET_HTTP_PROXY_CLIENT_SOCKET_H_
diff --git a/net/http/stream_factory.h b/net/http/stream_factory.h
index 94b3cc8..1a7aa77 100644
--- a/net/http/stream_factory.h
+++ b/net/http/stream_factory.h
@@ -69,6 +69,13 @@ class StreamRequest {
// may take a reference if it needs the cert_info beyond the lifetime of
// this callback.
virtual void OnNeedsClientAuth(SSLCertRequestInfo* cert_info) = 0;
+
+ // This is the failure of the CONNECT request through an HTTPS proxy.
+ // Headers can be read from |response_info|, while the body can be read
+ // from |stream|.
+ // Ownership of |stream| is transferred to the delegate.
+ virtual void OnHttpsProxyTunnelResponse(
+ const HttpResponseInfo& response_info, HttpStream* stream) = 0;
};
virtual ~StreamRequest() {}
diff --git a/net/net.gyp b/net/net.gyp
index a5134da..09b6267 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -29,6 +29,8 @@
'base/address_list_net_log_param.h',
'base/auth.cc',
'base/auth.h',
+ 'base/bandwidth_metrics.cc',
+ 'base/bandwidth_metrics.h',
'base/cache_type.h',
'base/capturing_net_log.cc',
'base/capturing_net_log.h',
@@ -76,8 +78,6 @@
'base/file_stream_win.cc',
'base/filter.cc',
'base/filter.h',
- 'base/forwarding_net_log.cc',
- 'base/forwarding_net_log.h',
'base/gzip_filter.cc',
'base/gzip_filter.h',
'base/gzip_header.cc',
@@ -142,6 +142,8 @@
'base/network_config_watcher_mac.h',
'base/nss_memio.c',
'base/nss_memio.h',
+ 'base/openssl_memory_private_key_store.cc',
+ 'base/openssl_private_key_store.h',
'base/pem_tokenizer.cc',
'base/pem_tokenizer.h',
'base/platform_mime_util.h',
@@ -175,6 +177,12 @@
'base/ssl_info.h',
'base/static_cookie_policy.cc',
'base/static_cookie_policy.h',
+ 'base/test_root_certs.cc',
+ 'base/test_root_certs.h',
+ 'base/test_root_certs_mac.cc',
+ 'base/test_root_certs_nss.cc',
+ 'base/test_root_certs_openssl.cc',
+ 'base/test_root_certs_win.cc',
'base/transport_security_state.cc',
'base/transport_security_state.h',
'base/sys_addrinfo.h',
@@ -237,7 +245,7 @@
'conditions': [
['use_openssl==1', {
'dependencies': [
- '../build/linux/system.gyp:openssl',
+ '../third_party/openssl/openssl.gyp:openssl',
],
}, { # else: not using openssl. Use NSS.
'dependencies': [
@@ -250,6 +258,7 @@
'sources!': [
'base/cert_database_nss.cc',
'base/keygen_handler_nss.cc',
+ 'base/test_root_certs_nss.cc',
'base/x509_certificate_nss.cc',
'third_party/mozilla_security_manager/nsKeygenHandler.cpp',
'third_party/mozilla_security_manager/nsKeygenHandler.h',
@@ -270,6 +279,7 @@
'base/keygen_handler_nss.cc',
'base/nss_memio.c',
'base/nss_memio.h',
+ 'base/test_root_certs_nss.cc',
'base/x509_certificate_nss.cc',
'third_party/mozilla_security_manager/nsKeygenHandler.cpp',
'third_party/mozilla_security_manager/nsKeygenHandler.h',
@@ -285,6 +295,9 @@
'sources!': [
'base/cert_database_openssl.cc',
'base/keygen_handler_openssl.cc',
+ 'base/openssl_memory_private_key_store.cc',
+ 'base/openssl_private_key_store.h',
+ 'base/test_root_certs_openssl.cc',
'base/x509_certificate_openssl.cc',
'base/x509_openssl_util.cc',
'base/x509_openssl_util.h',
@@ -334,7 +347,6 @@
'../third_party/zlib/zlib.gyp:zlib',
'net_base',
'net_resources',
- 'ssl_host_info',
],
'sources': [
'disk_cache/addr.cc',
@@ -400,12 +412,8 @@
'ftp/ftp_directory_listing_buffer.h',
'ftp/ftp_directory_listing_parser.cc',
'ftp/ftp_directory_listing_parser.h',
- 'ftp/ftp_directory_listing_parser_hprc.cc',
- 'ftp/ftp_directory_listing_parser_hprc.h',
'ftp/ftp_directory_listing_parser_ls.cc',
'ftp/ftp_directory_listing_parser_ls.h',
- 'ftp/ftp_directory_listing_parser_mlsd.cc',
- 'ftp/ftp_directory_listing_parser_mlsd.h',
'ftp/ftp_directory_listing_parser_netware.cc',
'ftp/ftp_directory_listing_parser_netware.h',
'ftp/ftp_directory_listing_parser_vms.cc',
@@ -519,6 +527,7 @@
'http/md4.h',
'http/partial_data.cc',
'http/partial_data.h',
+ 'http/proxy_client_socket.h',
'http/stream_factory.h',
'ocsp/nss_ocsp.cc',
'ocsp/nss_ocsp.h',
@@ -533,6 +542,7 @@
'proxy/proxy_config.cc',
'proxy/proxy_config.h',
'proxy/proxy_config_service.h',
+ 'proxy/proxy_config_service_fixed.cc',
'proxy/proxy_config_service_fixed.h',
'proxy/proxy_config_service_linux.cc',
'proxy/proxy_config_service_linux.h',
@@ -584,6 +594,8 @@
'socket/client_socket_pool_manager.h',
'socket/dns_cert_provenance_checker.cc',
'socket/dns_cert_provenance_checker.h',
+ 'socket/nss_ssl_util.cc',
+ 'socket/nss_ssl_util.h',
'socket/socket.h',
'socket/socks5_client_socket.cc',
'socket/socks5_client_socket.h',
@@ -591,6 +603,7 @@
'socket/socks_client_socket.h',
'socket/socks_client_socket_pool.cc',
'socket/socks_client_socket_pool.h',
+ 'socket/ssl_client_socket.cc',
'socket/ssl_client_socket.h',
'socket/ssl_client_socket_mac.cc',
'socket/ssl_client_socket_mac.h',
@@ -608,6 +621,11 @@
'socket/ssl_client_socket_win.h',
'socket/ssl_error_params.cc',
'socket/ssl_error_params.h',
+ 'socket/ssl_server_socket.h',
+ 'socket/ssl_server_socket_nss.cc',
+ 'socket/ssl_server_socket_nss.h',
+ 'socket/ssl_host_info.cc',
+ 'socket/ssl_host_info.h',
'socket/tcp_client_socket.cc',
'socket/tcp_client_socket.h',
'socket/tcp_client_socket_libevent.cc',
@@ -707,6 +725,7 @@
'websockets/websocket_handshake_handler.h',
'websockets/websocket_job.cc',
'websockets/websocket_job.h',
+ 'websockets/websocket_net_log_params.cc',
'websockets/websocket_net_log_params.h',
'websockets/websocket_throttle.cc',
'websockets/websocket_throttle.h',
@@ -732,10 +751,14 @@
'ocsp/nss_ocsp.h',
'socket/dns_cert_provenance_check.cc',
'socket/dns_cert_provenance_check.h',
+ 'socket/nss_ssl_util.cc',
+ 'socket/nss_ssl_util.h',
'socket/ssl_client_socket_nss.cc',
'socket/ssl_client_socket_nss.h',
'socket/ssl_client_socket_nss_factory.cc',
'socket/ssl_client_socket_nss_factory.h',
+ 'socket/ssl_server_socket_nss.cc',
+ 'socket/ssl_server_socket_nss.h',
],
},
{ # else !use_openssl: remove the unneeded files
@@ -753,7 +776,7 @@
'conditions': [
['use_openssl==1', {
'dependencies': [
- '../build/linux/system.gyp:openssl',
+ '../third_party/openssl/openssl.gyp:openssl',
],
},
{ # else use_openssl==0, use NSS
@@ -829,6 +852,7 @@
'sources': [
'base/address_list_unittest.cc',
'base/cert_database_nss_unittest.cc',
+ 'base/cert_verifier_unittest.cc',
'base/cookie_monster_unittest.cc',
'base/data_url_unittest.cc',
'base/directory_lister_unittest.cc',
@@ -839,7 +863,6 @@
'base/file_stream_unittest.cc',
'base/filter_unittest.cc',
'base/filter_unittest.h',
- 'base/forwarding_net_log_unittest.cc',
'base/gzip_filter_unittest.cc',
'base/host_cache_unittest.cc',
'base/host_mapping_rules_unittest.cc',
@@ -851,6 +874,7 @@
'base/mapped_host_resolver_unittest.cc',
'base/mime_sniffer_unittest.cc',
'base/mime_util_unittest.cc',
+ 'base/net_log_unittest.cc',
'base/net_log_unittest.h',
'base/net_test_suite.h',
'base/net_util_unittest.cc',
@@ -886,8 +910,6 @@
'ftp/ftp_ctrl_response_buffer_unittest.cc',
'ftp/ftp_directory_listing_buffer_unittest.cc',
'ftp/ftp_directory_listing_parser_ls_unittest.cc',
- 'ftp/ftp_directory_listing_parser_hprc_unittest.cc',
- 'ftp/ftp_directory_listing_parser_mlsd_unittest.cc',
'ftp/ftp_directory_listing_parser_netware_unittest.cc',
'ftp/ftp_directory_listing_parser_vms_unittest.cc',
'ftp/ftp_directory_listing_parser_windows_unittest.cc',
@@ -947,6 +969,7 @@
'socket/socks_client_socket_unittest.cc',
'socket/ssl_client_socket_unittest.cc',
'socket/ssl_client_socket_pool_unittest.cc',
+ 'socket/ssl_server_socket_unittest.cc',
'socket/tcp_client_socket_pool_unittest.cc',
'socket/tcp_client_socket_unittest.cc',
'socket_stream/socket_stream_metrics_unittest.cc',
@@ -1040,46 +1063,6 @@
],
},
{
- # This is a separate target in order to limit the scope of the protobuf
- # includes.
- 'target_name': 'ssl_host_info',
- 'type': '<(library)',
- 'dependencies': [
- '../base/base.gyp:base',
- '../third_party/protobuf/protobuf.gyp:protobuf_lite',
- '../third_party/protobuf/protobuf.gyp:protoc#host',
- ],
- 'sources': [
- 'socket/ssl_host_info.proto',
- 'socket/ssl_host_info.cc',
- 'socket/ssl_host_info.h',
- ],
- 'rules': [
- {
- 'rule_name': 'genproto',
- 'extension': 'proto',
- 'inputs': [
- '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)protoc<(EXECUTABLE_SUFFIX)',
- ],
- 'outputs': [
- '<(SHARED_INTERMEDIATE_DIR)/protoc_out/net/socket/<(RULE_INPUT_ROOT).pb.h',
- '<(SHARED_INTERMEDIATE_DIR)/protoc_out/net/socket/<(RULE_INPUT_ROOT).pb.cc',
- ],
- 'action': [
- '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)protoc<(EXECUTABLE_SUFFIX)',
- 'socket/<(RULE_INPUT_ROOT)<(RULE_INPUT_EXT)',
- '--cpp_out=<(SHARED_INTERMEDIATE_DIR)/protoc_out/net',
- ],
- 'message': 'Generating C++ code from <(RULE_INPUT_PATH)',
- 'process_outputs_as_sources': 1,
- },
- ],
- 'include_dirs': [
- '<(SHARED_INTERMEDIATE_DIR)/protoc_out/net',
- '<(SHARED_INTERMEDIATE_DIR)/protoc_out',
- ],
- },
- {
'target_name': 'net_perftests',
'type': 'executable',
'dependencies': [
@@ -1196,8 +1179,8 @@
'conditions': [
['use_openssl==1', {
'dependencies': [
- '../build/linux/system.gyp:openssl',
- ]
+ '../third_party/openssl/openssl.gyp:openssl',
+ ],
}, {
'dependencies': [
'../build/linux/system.gyp:nss',
diff --git a/net/ocsp/nss_ocsp.cc b/net/ocsp/nss_ocsp.cc
index 7618f9e..02edd05 100644
--- a/net/ocsp/nss_ocsp.cc
+++ b/net/ocsp/nss_ocsp.cc
@@ -140,13 +140,13 @@ base::LazyInstance<OCSPNSSInitialization> g_ocsp_nss_initialization(
base::LINKER_INITIALIZED);
// Concrete class for SEC_HTTP_REQUEST_SESSION.
-// Public methods except virtual methods of URLRequest::Delegate (On* methods)
-// run on certificate verifier thread (worker thread).
-// Virtual methods of URLRequest::Delegate and private methods run
+// Public methods except virtual methods of net::URLRequest::Delegate
+// (On* methods) run on certificate verifier thread (worker thread).
+// Virtual methods of net::URLRequest::Delegate and private methods run
// on IO thread.
class OCSPRequestSession
: public base::RefCountedThreadSafe<OCSPRequestSession>,
- public URLRequest::Delegate {
+ public net::URLRequest::Delegate {
public:
OCSPRequestSession(const GURL& url,
const char* http_request_method,
@@ -248,7 +248,20 @@ class OCSPRequestSession
return data_;
}
- virtual void OnResponseStarted(URLRequest* request) {
+ virtual void OnReceivedRedirect(net::URLRequest* request,
+ const GURL& new_url,
+ bool* defer_redirect) {
+ DCHECK_EQ(request, request_);
+ DCHECK_EQ(MessageLoopForIO::current(), io_loop_);
+
+ if (!new_url.SchemeIs("http")) {
+ // Prevent redirects to non-HTTP schemes, including HTTPS. This matches
+ // the initial check in OCSPServerSession::CreateRequest().
+ CancelURLRequest();
+ }
+ }
+
+ virtual void OnResponseStarted(net::URLRequest* request) {
DCHECK_EQ(request, request_);
DCHECK_EQ(MessageLoopForIO::current(), io_loop_);
@@ -262,7 +275,7 @@ class OCSPRequestSession
OnReadCompleted(request_, bytes_read);
}
- virtual void OnReadCompleted(URLRequest* request, int bytes_read) {
+ virtual void OnReadCompleted(net::URLRequest* request, int bytes_read) {
DCHECK_EQ(request, request_);
DCHECK_EQ(MessageLoopForIO::current(), io_loop_);
@@ -349,7 +362,7 @@ class OCSPRequestSession
g_ocsp_io_loop.Get().AddRequest(this);
}
- request_ = new URLRequest(url_, this);
+ request_ = new net::URLRequest(url_, this);
request_->set_context(url_request_context);
// To meet the privacy requirements of off-the-record mode.
request_->set_load_flags(
@@ -376,7 +389,7 @@ class OCSPRequestSession
GURL url_; // The URL we eventually wound up at
std::string http_request_method_;
base::TimeDelta timeout_; // The timeout for OCSP
- URLRequest* request_; // The actual request this wraps
+ net::URLRequest* request_; // The actual request this wraps
scoped_refptr<net::IOBuffer> buffer_; // Read buffer
net::HttpRequestHeaders extra_request_headers_;
std::string upload_content_; // HTTP POST payload
@@ -567,7 +580,7 @@ SECStatus OCSPCreateSession(const char* host, PRUint16 portnum,
if (request_context == NULL) {
LOG(ERROR) << "No URLRequestContext for OCSP handler.";
// The application failed to call SetURLRequestContextForOCSP, so we
- // can't create and use URLRequest. PR_NOT_IMPLEMENTED_ERROR is not an
+ // can't create and use net::URLRequest. PR_NOT_IMPLEMENTED_ERROR is not an
// accurate error code for this error condition, but is close enough.
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
return SECFailure;
diff --git a/net/proxy/init_proxy_resolver_unittest.cc b/net/proxy/init_proxy_resolver_unittest.cc
index 0c7e8a1..c1a69d1 100644
--- a/net/proxy/init_proxy_resolver_unittest.cc
+++ b/net/proxy/init_proxy_resolver_unittest.cc
@@ -107,6 +107,8 @@ class RuleBasedProxyScriptFetcher : public ProxyScriptFetcher {
virtual void Cancel() {}
+ virtual URLRequestContext* GetRequestContext() { return NULL; }
+
private:
const Rules* rules_;
};
@@ -130,6 +132,10 @@ class RuleBasedProxyResolver : public ProxyResolver {
NOTREACHED();
}
+ virtual void CancelSetPacScript() {
+ NOTREACHED();
+ }
+
virtual int SetPacScript(
const scoped_refptr<ProxyResolverScriptData>& script_data,
CompletionCallback* callback) {
@@ -181,19 +187,22 @@ TEST(InitProxyResolverTest, CustomPacSucceeds) {
EXPECT_EQ(rule.text(), resolver.script_data()->utf16());
// Check the NetLog was filled correctly.
- EXPECT_EQ(6u, log.entries().size());
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
+
+ EXPECT_EQ(6u, entries.size());
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 0, NetLog::TYPE_INIT_PROXY_RESOLVER));
+ entries, 0, NetLog::TYPE_INIT_PROXY_RESOLVER));
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 1, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
+ entries, 1, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 2, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
+ entries, 2, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 3, NetLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT));
+ entries, 3, NetLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 4, NetLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT));
+ entries, 4, NetLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 5, NetLog::TYPE_INIT_PROXY_RESOLVER));
+ entries, 5, NetLog::TYPE_INIT_PROXY_RESOLVER));
}
// Fail downloading the custom PAC script.
@@ -215,15 +224,18 @@ TEST(InitProxyResolverTest, CustomPacFails1) {
EXPECT_EQ(NULL, resolver.script_data());
// Check the NetLog was filled correctly.
- EXPECT_EQ(4u, log.entries().size());
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
+
+ EXPECT_EQ(4u, entries.size());
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 0, NetLog::TYPE_INIT_PROXY_RESOLVER));
+ entries, 0, NetLog::TYPE_INIT_PROXY_RESOLVER));
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 1, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
+ entries, 1, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 2, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
+ entries, 2, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 3, NetLog::TYPE_INIT_PROXY_RESOLVER));
+ entries, 3, NetLog::TYPE_INIT_PROXY_RESOLVER));
}
// Fail parsing the custom PAC script.
@@ -326,31 +338,34 @@ TEST(InitProxyResolverTest, AutodetectFailCustomSuccess2) {
// Check the NetLog was filled correctly.
// (Note that the Fetch and Set states are repeated since both WPAD and custom
// PAC scripts are tried).
- EXPECT_EQ(11u, log.entries().size());
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
+
+ EXPECT_EQ(11u, entries.size());
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 0, NetLog::TYPE_INIT_PROXY_RESOLVER));
+ entries, 0, NetLog::TYPE_INIT_PROXY_RESOLVER));
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 1, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
+ entries, 1, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 2, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
+ entries, 2, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 3, NetLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT));
+ entries, 3, NetLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 4, NetLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT));
+ entries, 4, NetLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT));
EXPECT_TRUE(LogContainsEvent(
- log.entries(), 5,
+ entries, 5,
NetLog::TYPE_INIT_PROXY_RESOLVER_FALLING_BACK_TO_NEXT_PAC_URL,
NetLog::PHASE_NONE));
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 6, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
+ entries, 6, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 7, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
+ entries, 7, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 8, NetLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT));
+ entries, 8, NetLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 9, NetLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT));
+ entries, 9, NetLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 10, NetLog::TYPE_INIT_PROXY_RESOLVER));
+ entries, 10, NetLog::TYPE_INIT_PROXY_RESOLVER));
}
// Fails at WPAD (downloading), and fails at custom PAC (downloading).
@@ -438,19 +453,22 @@ TEST(InitProxyResolverTest, CustomPacFails1_WithPositiveDelay) {
EXPECT_EQ(NULL, resolver.script_data());
// Check the NetLog was filled correctly.
- EXPECT_EQ(6u, log.entries().size());
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
+
+ EXPECT_EQ(6u, entries.size());
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 0, NetLog::TYPE_INIT_PROXY_RESOLVER));
+ entries, 0, NetLog::TYPE_INIT_PROXY_RESOLVER));
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 1, NetLog::TYPE_INIT_PROXY_RESOLVER_WAIT));
+ entries, 1, NetLog::TYPE_INIT_PROXY_RESOLVER_WAIT));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 2, NetLog::TYPE_INIT_PROXY_RESOLVER_WAIT));
+ entries, 2, NetLog::TYPE_INIT_PROXY_RESOLVER_WAIT));
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 3, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
+ entries, 3, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 4, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
+ entries, 4, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 5, NetLog::TYPE_INIT_PROXY_RESOLVER));
+ entries, 5, NetLog::TYPE_INIT_PROXY_RESOLVER));
}
// This is a copy-paste of CustomPacFails1, with the exception that we give it
@@ -475,15 +493,18 @@ TEST(InitProxyResolverTest, CustomPacFails1_WithNegativeDelay) {
EXPECT_EQ(NULL, resolver.script_data());
// Check the NetLog was filled correctly.
- EXPECT_EQ(4u, log.entries().size());
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
+
+ EXPECT_EQ(4u, entries.size());
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 0, NetLog::TYPE_INIT_PROXY_RESOLVER));
+ entries, 0, NetLog::TYPE_INIT_PROXY_RESOLVER));
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 1, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
+ entries, 1, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 2, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
+ entries, 2, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 3, NetLog::TYPE_INIT_PROXY_RESOLVER));
+ entries, 3, NetLog::TYPE_INIT_PROXY_RESOLVER));
}
} // namespace
diff --git a/net/proxy/multi_threaded_proxy_resolver.cc b/net/proxy/multi_threaded_proxy_resolver.cc
index d696438..6c348d2 100644
--- a/net/proxy/multi_threaded_proxy_resolver.cc
+++ b/net/proxy/multi_threaded_proxy_resolver.cc
@@ -8,8 +8,8 @@
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/thread.h"
-#include "net/base/capturing_net_log.h"
#include "net/base/net_errors.h"
+#include "net/base/net_log.h"
#include "net/proxy/proxy_info.h"
// TODO(eroman): Have the MultiThreadedProxyResolver clear its PAC script
@@ -253,13 +253,9 @@ class MultiThreadedProxyResolver::GetProxyForURLJob
// Runs on the worker thread.
virtual void Run(MessageLoop* origin_loop) {
- const size_t kNetLogBound = 50u;
- worker_log_.reset(new CapturingNetLog(kNetLogBound));
- BoundNetLog bound_worker_log(NetLog::Source(), worker_log_.get());
-
ProxyResolver* resolver = executor()->resolver();
int rv = resolver->GetProxyForURL(
- url_, &results_buf_, NULL, NULL, bound_worker_log);
+ url_, &results_buf_, NULL, NULL, net_log_);
DCHECK_NE(rv, ERR_IO_PENDING);
origin_loop->PostTask(
@@ -272,12 +268,6 @@ class MultiThreadedProxyResolver::GetProxyForURLJob
void QueryComplete(int result_code) {
// The Job may have been cancelled after it was started.
if (!was_cancelled()) {
- // Merge the load log that was generated on the worker thread, into the
- // main log.
- CapturingBoundNetLog bound_worker_log(NetLog::Source(),
- worker_log_.release());
- bound_worker_log.AppendTo(net_log_);
-
if (result_code >= OK) { // Note: unit-tests use values > 0.
results_->Use(results_buf_);
}
@@ -288,16 +278,14 @@ class MultiThreadedProxyResolver::GetProxyForURLJob
// Must only be used on the "origin" thread.
ProxyInfo* results_;
+
+ // Can be used on either "origin" or worker thread.
BoundNetLog net_log_;
const GURL url_;
// Usable from within DoQuery on the worker thread.
ProxyInfo results_buf_;
- // Used to pass the captured events between DoQuery [worker thread] and
- // QueryComplete [origin thread].
- scoped_ptr<CapturingNetLog> worker_log_;
-
bool was_waiting_for_thread_;
};
@@ -318,7 +306,7 @@ MultiThreadedProxyResolver::Executor::Executor(
std::string thread_name =
base::StringPrintf("PAC thread #%d", thread_number);
thread_.reset(new base::Thread(thread_name.c_str()));
- thread_->Start();
+ CHECK(thread_->Start());
}
void MultiThreadedProxyResolver::Executor::StartJob(Job* job) {
diff --git a/net/proxy/multi_threaded_proxy_resolver_unittest.cc b/net/proxy/multi_threaded_proxy_resolver_unittest.cc
index 7027161..a18804f 100644
--- a/net/proxy/multi_threaded_proxy_resolver_unittest.cc
+++ b/net/proxy/multi_threaded_proxy_resolver_unittest.cc
@@ -60,6 +60,10 @@ class MockProxyResolver : public ProxyResolver {
NOTREACHED();
}
+ virtual void CancelSetPacScript() {
+ NOTREACHED();
+ }
+
virtual int SetPacScript(
const scoped_refptr<ProxyResolverScriptData>& script_data,
CompletionCallback* callback) {
@@ -169,6 +173,10 @@ class ForwardingProxyResolver : public ProxyResolver {
impl_->CancelRequest(request);
}
+ virtual void CancelSetPacScript() {
+ impl_->CancelSetPacScript();
+ }
+
virtual int SetPacScript(
const scoped_refptr<ProxyResolverScriptData>& script_data,
CompletionCallback* callback) {
@@ -260,9 +268,11 @@ TEST(MultiThreadedProxyResolverTest, SingleThread_Basic) {
// on completion, this should have been copied into |log0|.
// We also have 1 log entry that was emitted by the
// MultiThreadedProxyResolver.
- ASSERT_EQ(2u, log0.entries().size());
- EXPECT_EQ(NetLog::TYPE_SUBMITTED_TO_RESOLVER_THREAD,
- log0.entries()[0].type);
+ net::CapturingNetLog::EntryList entries0;
+ log0.GetEntries(&entries0);
+
+ ASSERT_EQ(2u, entries0.size());
+ EXPECT_EQ(NetLog::TYPE_SUBMITTED_TO_RESOLVER_THREAD, entries0[0].type);
// Start 3 more requests (request1 to request3).
@@ -368,30 +378,42 @@ TEST(MultiThreadedProxyResolverTest,
// 1 entry from the mock proxy resolver.
EXPECT_EQ(0, callback0.WaitForResult());
EXPECT_EQ("PROXY request0:80", results0.ToPacString());
- ASSERT_EQ(2u, log0.entries().size());
+
+ net::CapturingNetLog::EntryList entries0;
+ log0.GetEntries(&entries0);
+
+ ASSERT_EQ(2u, entries0.size());
EXPECT_EQ(NetLog::TYPE_SUBMITTED_TO_RESOLVER_THREAD,
- log0.entries()[0].type);
+ entries0[0].type);
// Check that request 1 completed as expected.
EXPECT_EQ(1, callback1.WaitForResult());
EXPECT_EQ("PROXY request1:80", results1.ToPacString());
- ASSERT_EQ(4u, log1.entries().size());
+
+ net::CapturingNetLog::EntryList entries1;
+ log1.GetEntries(&entries1);
+
+ ASSERT_EQ(4u, entries1.size());
EXPECT_TRUE(LogContainsBeginEvent(
- log1.entries(), 0,
+ entries1, 0,
NetLog::TYPE_WAITING_FOR_PROXY_RESOLVER_THREAD));
EXPECT_TRUE(LogContainsEndEvent(
- log1.entries(), 1,
+ entries1, 1,
NetLog::TYPE_WAITING_FOR_PROXY_RESOLVER_THREAD));
// Check that request 2 completed as expected.
EXPECT_EQ(2, callback2.WaitForResult());
EXPECT_EQ("PROXY request2:80", results2.ToPacString());
- ASSERT_EQ(4u, log2.entries().size());
+
+ net::CapturingNetLog::EntryList entries2;
+ log2.GetEntries(&entries2);
+
+ ASSERT_EQ(4u, entries2.size());
EXPECT_TRUE(LogContainsBeginEvent(
- log2.entries(), 0,
+ entries2, 0,
NetLog::TYPE_WAITING_FOR_PROXY_RESOLVER_THREAD));
EXPECT_TRUE(LogContainsEndEvent(
- log2.entries(), 1,
+ entries2, 1,
NetLog::TYPE_WAITING_FOR_PROXY_RESOLVER_THREAD));
}
diff --git a/net/proxy/proxy_bypass_rules.cc b/net/proxy/proxy_bypass_rules.cc
index ce018bf..91c6f44 100644
--- a/net/proxy/proxy_bypass_rules.cc
+++ b/net/proxy/proxy_bypass_rules.cc
@@ -4,6 +4,7 @@
#include "net/proxy/proxy_bypass_rules.h"
+#include "base/stl_util-inl.h"
#include "base/string_number_conversions.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"
@@ -45,6 +46,12 @@ class HostnamePatternRule : public ProxyBypassRules::Rule {
return str;
}
+ virtual Rule* Clone() const {
+ return new HostnamePatternRule(optional_scheme_,
+ hostname_pattern_,
+ optional_port_);
+ }
+
private:
const std::string optional_scheme_;
const std::string hostname_pattern_;
@@ -63,6 +70,10 @@ class BypassLocalRule : public ProxyBypassRules::Rule {
virtual std::string ToString() const {
return "<local>";
}
+
+ virtual Rule* Clone() const {
+ return new BypassLocalRule();
+ }
};
// Rule for matching a URL that is an IP address, if that IP address falls
@@ -102,6 +113,13 @@ class BypassIPBlockRule : public ProxyBypassRules::Rule {
return description_;
}
+ virtual Rule* Clone() const {
+ return new BypassIPBlockRule(description_,
+ optional_scheme_,
+ ip_prefix_,
+ prefix_length_in_bits_);
+ }
+
private:
const std::string description_;
const std::string optional_scheme_;
@@ -122,18 +140,29 @@ bool IsIPAddress(const std::string& domain) {
} // namespace
+ProxyBypassRules::Rule::Rule() {
+}
+
+ProxyBypassRules::Rule::~Rule() {
+}
+
+bool ProxyBypassRules::Rule::Equals(const Rule& rule) const {
+ return ToString() == rule.ToString();
+}
+
ProxyBypassRules::ProxyBypassRules() {
}
-ProxyBypassRules::ProxyBypassRules(const ProxyBypassRules& rhs)
- : rules_(rhs.rules_) {
+ProxyBypassRules::ProxyBypassRules(const ProxyBypassRules& rhs) {
+ AssignFrom(rhs);
}
ProxyBypassRules::~ProxyBypassRules() {
+ Clear();
}
ProxyBypassRules& ProxyBypassRules::operator=(const ProxyBypassRules& rhs) {
- rules_ = rhs.rules_;
+ AssignFrom(rhs);
return *this;
}
@@ -146,11 +175,11 @@ bool ProxyBypassRules::Matches(const GURL& url) const {
}
bool ProxyBypassRules::Equals(const ProxyBypassRules& other) const {
- if (rules_.size() != other.rules().size())
+ if (rules_.size() != other.rules_.size())
return false;
for (size_t i = 0; i < rules_.size(); ++i) {
- if (!rules_[i]->Equals(*other.rules()[i]))
+ if (!rules_[i]->Equals(*other.rules_[i]))
return false;
}
return true;
@@ -171,14 +200,14 @@ bool ProxyBypassRules::AddRuleForHostname(const std::string& optional_scheme,
if (hostname_pattern.empty())
return false;
- rules_.push_back(make_scoped_refptr(new HostnamePatternRule(optional_scheme,
- hostname_pattern,
- optional_port)));
+ rules_.push_back(new HostnamePatternRule(optional_scheme,
+ hostname_pattern,
+ optional_port));
return true;
}
void ProxyBypassRules::AddRuleToBypassLocal() {
- rules_.push_back(make_scoped_refptr(new BypassLocalRule));
+ rules_.push_back(new BypassLocalRule);
}
bool ProxyBypassRules::AddRuleFromString(const std::string& raw) {
@@ -191,7 +220,17 @@ bool ProxyBypassRules::AddRuleFromStringUsingSuffixMatching(
}
void ProxyBypassRules::Clear() {
- rules_.clear();
+ STLDeleteElements(&rules_);
+}
+
+void ProxyBypassRules::AssignFrom(const ProxyBypassRules& other) {
+ Clear();
+
+ // Make a copy of the rules list.
+ for (RuleList::const_iterator it = other.rules_.begin();
+ it != other.rules_.end(); ++it) {
+ rules_.push_back((*it)->Clone());
+ }
}
void ProxyBypassRules::ParseFromStringInternal(
@@ -241,8 +280,8 @@ bool ProxyBypassRules::AddRuleFromStringInternal(
if (!ParseCIDRBlock(raw, &ip_prefix, &prefix_length_in_bits))
return false;
- rules_.push_back(make_scoped_refptr(
- new BypassIPBlockRule(raw, scheme, ip_prefix, prefix_length_in_bits)));
+ rules_.push_back(
+ new BypassIPBlockRule(raw, scheme, ip_prefix, prefix_length_in_bits));
return true;
}
diff --git a/net/proxy/proxy_bypass_rules.h b/net/proxy/proxy_bypass_rules.h
index 9873154..ad8afdc 100644
--- a/net/proxy/proxy_bypass_rules.h
+++ b/net/proxy/proxy_bypass_rules.h
@@ -9,7 +9,6 @@
#include <string>
#include <vector>
-#include "base/ref_counted.h"
#include "googleurl/src/gurl.h"
namespace net {
@@ -20,10 +19,10 @@ namespace net {
class ProxyBypassRules {
public:
// Interface for an individual proxy bypass rule.
- class Rule : public base::RefCounted<Rule> {
+ class Rule {
public:
- Rule() {}
- virtual ~Rule() {}
+ Rule();
+ virtual ~Rule();
// Returns true if |url| matches the rule.
virtual bool Matches(const GURL& url) const = 0;
@@ -32,15 +31,16 @@ class ProxyBypassRules {
// visualizing the rules, and also to test equality of a rules list.
virtual std::string ToString() const = 0;
- bool Equals(const Rule& rule) const {
- return ToString() == rule.ToString();
- }
+ // Creates a copy of this rule. (Caller is responsible for deleting it)
+ virtual Rule* Clone() const = 0;
+
+ bool Equals(const Rule& rule) const;
private:
DISALLOW_COPY_AND_ASSIGN(Rule);
};
- typedef std::vector<scoped_refptr<Rule> > RuleList;
+ typedef std::vector<const Rule*> RuleList;
// Note: This class supports copy constructor and assignment.
ProxyBypassRules();
@@ -48,7 +48,9 @@ class ProxyBypassRules {
~ProxyBypassRules();
ProxyBypassRules& operator=(const ProxyBypassRules& rhs);
- // Returns the current list of rules.
+ // Returns the current list of rules. The rules list contains pointers
+ // which are owned by this class, callers should NOT keep references
+ // or delete them.
const RuleList& rules() const { return rules_; }
// Returns true if |url| matches any of the proxy bypass rules.
@@ -154,6 +156,9 @@ class ProxyBypassRules {
// Removes all the rules.
void Clear();
+ // Sets |*this| to |other|.
+ void AssignFrom(const ProxyBypassRules& other);
+
private:
// The following are variants of ParseFromString() and AddRuleFromString(),
// which additionally prefix hostname patterns with a wildcard if
diff --git a/net/proxy/proxy_config_service_fixed.cc b/net/proxy/proxy_config_service_fixed.cc
new file mode 100644
index 0000000..b23c265
--- /dev/null
+++ b/net/proxy/proxy_config_service_fixed.cc
@@ -0,0 +1,20 @@
+// 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.
+
+#include "net/proxy/proxy_config_service_fixed.h"
+
+namespace net {
+
+ProxyConfigServiceFixed::ProxyConfigServiceFixed(const ProxyConfig& pc)
+ : pc_(pc) {
+}
+
+ProxyConfigServiceFixed::~ProxyConfigServiceFixed() {}
+
+bool ProxyConfigServiceFixed::GetLatestProxyConfig(ProxyConfig* config) {
+ *config = pc_;
+ return true;
+}
+
+} // namespace net
diff --git a/net/proxy/proxy_config_service_fixed.h b/net/proxy/proxy_config_service_fixed.h
index e9eac8e..b0d8f03 100644
--- a/net/proxy/proxy_config_service_fixed.h
+++ b/net/proxy/proxy_config_service_fixed.h
@@ -15,15 +15,13 @@ namespace net {
// Implementation of ProxyConfigService that returns a fixed result.
class ProxyConfigServiceFixed : public ProxyConfigService {
public:
- explicit ProxyConfigServiceFixed(const ProxyConfig& pc) : pc_(pc) {}
+ explicit ProxyConfigServiceFixed(const ProxyConfig& pc);
+ virtual ~ProxyConfigServiceFixed();
// ProxyConfigService methods:
virtual void AddObserver(Observer* observer) {}
virtual void RemoveObserver(Observer* observer) {}
- virtual bool GetLatestProxyConfig(ProxyConfig* config) {
- *config = pc_;
- return true;
- }
+ virtual bool GetLatestProxyConfig(ProxyConfig* config);
private:
ProxyConfig pc_;
diff --git a/net/proxy/proxy_config_service_linux.cc b/net/proxy/proxy_config_service_linux.cc
index 5e548cf..3867df1 100644
--- a/net/proxy/proxy_config_service_linux.cc
+++ b/net/proxy/proxy_config_service_linux.cc
@@ -1255,4 +1255,16 @@ ProxyConfigServiceLinux::ProxyConfigServiceLinux(
: delegate_(new Delegate(env_var_getter, gconf_getter)) {
}
+void ProxyConfigServiceLinux::AddObserver(Observer* observer) {
+ delegate_->AddObserver(observer);
+}
+
+void ProxyConfigServiceLinux::RemoveObserver(Observer* observer) {
+ delegate_->RemoveObserver(observer);
+}
+
+bool ProxyConfigServiceLinux::GetLatestProxyConfig(ProxyConfig* config) {
+ return delegate_->GetLatestProxyConfig(config);
+}
+
} // namespace net
diff --git a/net/proxy/proxy_config_service_linux.h b/net/proxy/proxy_config_service_linux.h
index db2492c..ca82822 100644
--- a/net/proxy/proxy_config_service_linux.h
+++ b/net/proxy/proxy_config_service_linux.h
@@ -239,18 +239,9 @@ class ProxyConfigServiceLinux : public ProxyConfigService {
// ProxyConfigService methods:
// Called from IO thread.
-
- virtual void AddObserver(Observer* observer) {
- delegate_->AddObserver(observer);
- }
-
- virtual void RemoveObserver(Observer* observer) {
- delegate_->RemoveObserver(observer);
- }
-
- virtual bool GetLatestProxyConfig(ProxyConfig* config) {
- return delegate_->GetLatestProxyConfig(config);
- }
+ virtual void AddObserver(Observer* observer);
+ virtual void RemoveObserver(Observer* observer);
+ virtual bool GetLatestProxyConfig(ProxyConfig* config);
private:
scoped_refptr<Delegate> delegate_;
diff --git a/net/proxy/proxy_resolver.h b/net/proxy/proxy_resolver.h
index 9220f5e..fcc2395 100644
--- a/net/proxy/proxy_resolver.h
+++ b/net/proxy/proxy_resolver.h
@@ -54,10 +54,7 @@ class ProxyResolver {
// contain the actual script bytes rather than just the URL.
bool expects_pac_bytes() const { return expects_pac_bytes_; }
- // TODO(eroman): Make this =0.
- virtual void CancelSetPacScript() {
- NOTREACHED();
- }
+ virtual void CancelSetPacScript() = 0;
// Frees any unneeded memory held by the resolver, e.g. garbage in the JS
// engine. Most subclasses don't need to do anything, so we provide a default
diff --git a/net/proxy/proxy_resolver_js_bindings_unittest.cc b/net/proxy/proxy_resolver_js_bindings_unittest.cc
index 6b33a34..ecb36ca 100644
--- a/net/proxy/proxy_resolver_js_bindings_unittest.cc
+++ b/net/proxy/proxy_resolver_js_bindings_unittest.cc
@@ -304,65 +304,82 @@ TEST(ProxyResolverJSBindingsTest, NetLog) {
bindings->set_current_request_context(&context);
std::string ip_address;
-
- ASSERT_EQ(0u, log.entries().size());
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
+ ASSERT_EQ(0u, entries.size());
// Call all the bindings. Each call should be logging something to
// our NetLog.
bindings->MyIpAddress(&ip_address);
- EXPECT_EQ(2u, log.entries().size());
+
+ log.GetEntries(&entries);
+ EXPECT_EQ(2u, entries.size());
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 0, NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS));
+ entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 1, NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS));
+ entries, 1, NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS));
bindings->MyIpAddressEx(&ip_address);
- EXPECT_EQ(4u, log.entries().size());
+
+ log.GetEntries(&entries);
+ EXPECT_EQ(4u, entries.size());
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 2, NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS_EX));
+ entries, 2, NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS_EX));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 3, NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS_EX));
+ entries, 3, NetLog::TYPE_PAC_JAVASCRIPT_MY_IP_ADDRESS_EX));
bindings->DnsResolve("foo", &ip_address);
- EXPECT_EQ(6u, log.entries().size());
+
+ log.GetEntries(&entries);
+ EXPECT_EQ(6u, entries.size());
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 4, NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE));
+ entries, 4, NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 5, NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE));
+ entries, 5, NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE));
bindings->DnsResolveEx("foo", &ip_address);
- EXPECT_EQ(8u, log.entries().size());
+
+ log.GetEntries(&entries);
+ EXPECT_EQ(8u, entries.size());
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 6, NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE_EX));
+ entries, 6, NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE_EX));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 7, NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE_EX));
+ entries, 7, NetLog::TYPE_PAC_JAVASCRIPT_DNS_RESOLVE_EX));
// Nothing has been emitted globally yet.
- EXPECT_EQ(0u, global_log.entries().size());
+ net::CapturingNetLog::EntryList global_log_entries;
+ global_log.GetEntries(&global_log_entries);
+ EXPECT_EQ(0u, global_log_entries.size());
bindings->OnError(30, string16());
- EXPECT_EQ(9u, log.entries().size());
+
+ log.GetEntries(&entries);
+ EXPECT_EQ(9u, entries.size());
EXPECT_TRUE(LogContainsEvent(
- log.entries(), 8, NetLog::TYPE_PAC_JAVASCRIPT_ERROR,
+ entries, 8, NetLog::TYPE_PAC_JAVASCRIPT_ERROR,
NetLog::PHASE_NONE));
// We also emit errors to the top-level log stream.
- EXPECT_EQ(1u, global_log.entries().size());
+ global_log.GetEntries(&global_log_entries);
+ EXPECT_EQ(1u, global_log_entries.size());
EXPECT_TRUE(LogContainsEvent(
- global_log.entries(), 0, NetLog::TYPE_PAC_JAVASCRIPT_ERROR,
+ global_log_entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_ERROR,
NetLog::PHASE_NONE));
bindings->Alert(string16());
- EXPECT_EQ(10u, log.entries().size());
+
+ log.GetEntries(&entries);
+ EXPECT_EQ(10u, entries.size());
EXPECT_TRUE(LogContainsEvent(
- log.entries(), 9, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
+ entries, 9, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
NetLog::PHASE_NONE));
// We also emit javascript alerts to the top-level log stream.
- EXPECT_EQ(2u, global_log.entries().size());
+ global_log.GetEntries(&global_log_entries);
+ EXPECT_EQ(2u, global_log_entries.size());
EXPECT_TRUE(LogContainsEvent(
- global_log.entries(), 1, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
+ global_log_entries, 1, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
NetLog::PHASE_NONE));
}
diff --git a/net/proxy/proxy_resolver_mac.cc b/net/proxy/proxy_resolver_mac.cc
index 442715d..128450f 100644
--- a/net/proxy/proxy_resolver_mac.cc
+++ b/net/proxy/proxy_resolver_mac.cc
@@ -53,6 +53,12 @@ void ResultCallback(void* client, CFArrayRef proxies, CFErrorRef error) {
namespace net {
+ProxyResolverMac::ProxyResolverMac()
+ : ProxyResolver(false /*expects_pac_bytes*/) {
+}
+
+ProxyResolverMac::~ProxyResolverMac() {}
+
// Gets the proxy information for a query URL from a PAC. Implementation
// inspired by http://developer.apple.com/samplecode/CFProxySupportTool/
int ProxyResolverMac::GetProxyForURL(const GURL& query_url,
@@ -171,4 +177,19 @@ int ProxyResolverMac::GetProxyForURL(const GURL& query_url,
return OK;
}
+void ProxyResolverMac::CancelRequest(RequestHandle request) {
+ NOTREACHED();
+}
+
+void ProxyResolverMac::CancelSetPacScript() {
+ NOTREACHED();
+}
+
+int ProxyResolverMac::SetPacScript(
+ const scoped_refptr<ProxyResolverScriptData>& script_data,
+ CompletionCallback* /*callback*/) {
+ script_data_ = script_data;
+ return OK;
+}
+
} // namespace net
diff --git a/net/proxy/proxy_resolver_mac.h b/net/proxy/proxy_resolver_mac.h
index 950b11f..fe6e791 100644
--- a/net/proxy/proxy_resolver_mac.h
+++ b/net/proxy/proxy_resolver_mac.h
@@ -16,7 +16,8 @@ namespace net {
// proxies.
class ProxyResolverMac : public ProxyResolver {
public:
- ProxyResolverMac() : ProxyResolver(false /*expects_pac_bytes*/) {}
+ ProxyResolverMac();
+ virtual ~ProxyResolverMac();
// ProxyResolver methods:
virtual int GetProxyForURL(const GURL& url,
@@ -25,16 +26,13 @@ class ProxyResolverMac : public ProxyResolver {
RequestHandle* request,
const BoundNetLog& net_log);
- virtual void CancelRequest(RequestHandle request) {
- NOTREACHED();
- }
+ virtual void CancelRequest(RequestHandle request);
+
+ virtual void CancelSetPacScript();
virtual int SetPacScript(
const scoped_refptr<ProxyResolverScriptData>& script_data,
- CompletionCallback* /*callback*/) {
- script_data_ = script_data;
- return OK;
- }
+ CompletionCallback* /*callback*/);
private:
scoped_refptr<ProxyResolverScriptData> script_data_;
diff --git a/net/proxy/proxy_resolver_v8.cc b/net/proxy/proxy_resolver_v8.cc
index 2bf3b6d..80a1937 100644
--- a/net/proxy/proxy_resolver_v8.cc
+++ b/net/proxy/proxy_resolver_v8.cc
@@ -721,6 +721,10 @@ void ProxyResolverV8::CancelRequest(RequestHandle request) {
NOTREACHED();
}
+void ProxyResolverV8::CancelSetPacScript() {
+ NOTREACHED();
+}
+
void ProxyResolverV8::PurgeMemory() {
context_->PurgeMemory();
}
diff --git a/net/proxy/proxy_resolver_v8.h b/net/proxy/proxy_resolver_v8.h
index 7345f45..28bdcd0 100644
--- a/net/proxy/proxy_resolver_v8.h
+++ b/net/proxy/proxy_resolver_v8.h
@@ -47,6 +47,7 @@ class ProxyResolverV8 : public ProxyResolver {
RequestHandle* /*request*/,
const BoundNetLog& net_log);
virtual void CancelRequest(RequestHandle request);
+ virtual void CancelSetPacScript();
virtual void PurgeMemory();
virtual void Shutdown();
virtual int SetPacScript(
diff --git a/net/proxy/proxy_resolver_v8_unittest.cc b/net/proxy/proxy_resolver_v8_unittest.cc
index 3e61cd7..eff0413 100644
--- a/net/proxy/proxy_resolver_v8_unittest.cc
+++ b/net/proxy/proxy_resolver_v8_unittest.cc
@@ -138,8 +138,10 @@ TEST(ProxyResolverV8Test, Direct) {
EXPECT_EQ(0U, resolver.mock_js_bindings()->alerts.size());
EXPECT_EQ(0U, resolver.mock_js_bindings()->errors.size());
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
// No bindings were called, so no log entries.
- EXPECT_EQ(0u, log.entries().size());
+ EXPECT_EQ(0u, entries.size());
}
TEST(ProxyResolverV8Test, ReturnEmptyString) {
diff --git a/net/proxy/proxy_resolver_winhttp.cc b/net/proxy/proxy_resolver_winhttp.cc
index 962271f..13f5fb5 100644
--- a/net/proxy/proxy_resolver_winhttp.cc
+++ b/net/proxy/proxy_resolver_winhttp.cc
@@ -21,23 +21,6 @@ using base::TimeTicks;
namespace net {
-// A small wrapper for histogramming purposes ;-)
-static BOOL CallWinHttpGetProxyForUrl(HINTERNET session, LPCWSTR url,
- WINHTTP_AUTOPROXY_OPTIONS* options,
- WINHTTP_PROXY_INFO* results) {
- TimeTicks time_start = TimeTicks::Now();
- BOOL rv = WinHttpGetProxyForUrl(session, url, options, results);
- TimeDelta time_delta = TimeTicks::Now() - time_start;
- // Record separately success and failure times since they will have very
- // different characteristics.
- if (rv) {
- UMA_HISTOGRAM_LONG_TIMES("Net.GetProxyForUrl_OK", time_delta);
- } else {
- UMA_HISTOGRAM_LONG_TIMES("Net.GetProxyForUrl_FAIL", time_delta);
- }
- return rv;
-}
-
static void FreeInfo(WINHTTP_PROXY_INFO* info) {
if (info->lpszProxy)
GlobalFree(info->lpszProxy);
@@ -82,12 +65,12 @@ int ProxyResolverWinHttp::GetProxyForURL(const GURL& query_url,
// Otherwise, we fail over to trying it with a value of true. This way we
// get good performance in the case where WinHTTP uses an out-of-process
// resolver. This is important for Vista and Win2k3.
- BOOL ok = CallWinHttpGetProxyForUrl(
+ BOOL ok = WinHttpGetProxyForUrl(
session_handle_, ASCIIToWide(query_url.spec()).c_str(), &options, &info);
if (!ok) {
if (ERROR_WINHTTP_LOGIN_FAILURE == GetLastError()) {
options.fAutoLogonIfChallenged = TRUE;
- ok = CallWinHttpGetProxyForUrl(
+ ok = WinHttpGetProxyForUrl(
session_handle_, ASCIIToWide(query_url.spec()).c_str(),
&options, &info);
}
@@ -141,6 +124,10 @@ void ProxyResolverWinHttp::CancelRequest(RequestHandle request) {
NOTREACHED();
}
+void ProxyResolverWinHttp::CancelSetPacScript() {
+ NOTREACHED();
+}
+
int ProxyResolverWinHttp::SetPacScript(
const scoped_refptr<ProxyResolverScriptData>& script_data,
CompletionCallback* /*callback*/) {
diff --git a/net/proxy/proxy_resolver_winhttp.h b/net/proxy/proxy_resolver_winhttp.h
index 68d1109..9784672 100644
--- a/net/proxy/proxy_resolver_winhttp.h
+++ b/net/proxy/proxy_resolver_winhttp.h
@@ -27,6 +27,9 @@ class ProxyResolverWinHttp : public ProxyResolver {
RequestHandle* /*request*/,
const BoundNetLog& /*net_log*/);
virtual void CancelRequest(RequestHandle request);
+
+ virtual void CancelSetPacScript();
+
virtual int SetPacScript(
const scoped_refptr<ProxyResolverScriptData>& script_data,
CompletionCallback* /*callback*/);
diff --git a/net/proxy/proxy_script_fetcher.h b/net/proxy/proxy_script_fetcher.h
index 0a28065..bf33bcb 100644
--- a/net/proxy/proxy_script_fetcher.h
+++ b/net/proxy/proxy_script_fetcher.h
@@ -48,7 +48,7 @@ class ProxyScriptFetcher {
// Returns the request context that this fetcher uses to issue downloads,
// or NULL.
- virtual URLRequestContext* GetRequestContext() { return NULL; }
+ virtual URLRequestContext* GetRequestContext() = 0;
};
} // namespace net
diff --git a/net/proxy/proxy_script_fetcher_impl.cc b/net/proxy/proxy_script_fetcher_impl.cc
index 221e5c0..0a54046 100644
--- a/net/proxy/proxy_script_fetcher_impl.cc
+++ b/net/proxy/proxy_script_fetcher_impl.cc
@@ -86,7 +86,7 @@ ProxyScriptFetcherImpl::ProxyScriptFetcherImpl(
}
ProxyScriptFetcherImpl::~ProxyScriptFetcherImpl() {
- // The URLRequest's destructor will cancel the outstanding request, and
+ // The net::URLRequest's destructor will cancel the outstanding request, and
// ensure that the delegate (this) is not called again.
}
@@ -99,7 +99,7 @@ int ProxyScriptFetcherImpl::Fetch(const GURL& url,
DCHECK(callback);
DCHECK(text);
- cur_request_.reset(new URLRequest(url, this));
+ cur_request_.reset(new net::URLRequest(url, this));
cur_request_->set_context(url_request_context_);
cur_request_->set_method("GET");
@@ -129,7 +129,7 @@ int ProxyScriptFetcherImpl::Fetch(const GURL& url,
}
void ProxyScriptFetcherImpl::Cancel() {
- // ResetCurRequestState will free the URLRequest, which will cause
+ // ResetCurRequestState will free the net::URLRequest, which will cause
// cancellation.
ResetCurRequestState();
}
@@ -138,7 +138,7 @@ URLRequestContext* ProxyScriptFetcherImpl::GetRequestContext() {
return url_request_context_;
}
-void ProxyScriptFetcherImpl::OnAuthRequired(URLRequest* request,
+void ProxyScriptFetcherImpl::OnAuthRequired(net::URLRequest* request,
AuthChallengeInfo* auth_info) {
DCHECK_EQ(request, cur_request_.get());
// TODO(eroman):
@@ -147,7 +147,7 @@ void ProxyScriptFetcherImpl::OnAuthRequired(URLRequest* request,
request->CancelAuth();
}
-void ProxyScriptFetcherImpl::OnSSLCertificateError(URLRequest* request,
+void ProxyScriptFetcherImpl::OnSSLCertificateError(net::URLRequest* request,
int cert_error,
X509Certificate* cert) {
DCHECK_EQ(request, cur_request_.get());
@@ -157,7 +157,7 @@ void ProxyScriptFetcherImpl::OnSSLCertificateError(URLRequest* request,
request->Cancel();
}
-void ProxyScriptFetcherImpl::OnResponseStarted(URLRequest* request) {
+void ProxyScriptFetcherImpl::OnResponseStarted(net::URLRequest* request) {
DCHECK_EQ(request, cur_request_.get());
if (!request->status().is_success()) {
@@ -191,7 +191,7 @@ void ProxyScriptFetcherImpl::OnResponseStarted(URLRequest* request) {
ReadBody(request);
}
-void ProxyScriptFetcherImpl::OnReadCompleted(URLRequest* request,
+void ProxyScriptFetcherImpl::OnReadCompleted(net::URLRequest* request,
int num_bytes) {
DCHECK_EQ(request, cur_request_.get());
if (ConsumeBytesRead(request, num_bytes)) {
@@ -200,7 +200,7 @@ void ProxyScriptFetcherImpl::OnReadCompleted(URLRequest* request,
}
}
-void ProxyScriptFetcherImpl::OnResponseCompleted(URLRequest* request) {
+void ProxyScriptFetcherImpl::OnResponseCompleted(net::URLRequest* request) {
DCHECK_EQ(request, cur_request_.get());
// Use |result_code_| as the request's error if we have already set it to
@@ -211,7 +211,7 @@ void ProxyScriptFetcherImpl::OnResponseCompleted(URLRequest* request) {
FetchCompleted();
}
-void ProxyScriptFetcherImpl::ReadBody(URLRequest* request) {
+void ProxyScriptFetcherImpl::ReadBody(net::URLRequest* request) {
// Read as many bytes as are available synchronously.
while (true) {
int num_bytes;
@@ -226,7 +226,7 @@ void ProxyScriptFetcherImpl::ReadBody(URLRequest* request) {
}
}
-bool ProxyScriptFetcherImpl::ConsumeBytesRead(URLRequest* request,
+bool ProxyScriptFetcherImpl::ConsumeBytesRead(net::URLRequest* request,
int num_bytes) {
if (num_bytes <= 0) {
// Error while reading, or EOF.
@@ -277,7 +277,7 @@ void ProxyScriptFetcherImpl::ResetCurRequestState() {
}
void ProxyScriptFetcherImpl::OnTimeout(int id) {
- // Timeout tasks may outlive the URLRequest they reference. Make sure it
+ // Timeout tasks may outlive the net::URLRequest they reference. Make sure it
// is still applicable.
if (cur_request_id_ != id)
return;
diff --git a/net/proxy/proxy_script_fetcher_impl.h b/net/proxy/proxy_script_fetcher_impl.h
index b671f6d..4461650 100644
--- a/net/proxy/proxy_script_fetcher_impl.h
+++ b/net/proxy/proxy_script_fetcher_impl.h
@@ -24,7 +24,7 @@ namespace net {
// Implementation of ProxyScriptFetcher that downloads scripts using the
// specified request context.
class ProxyScriptFetcherImpl : public ProxyScriptFetcher,
- public URLRequest::Delegate {
+ public net::URLRequest::Delegate {
public:
// Creates a ProxyScriptFetcher that issues requests through
// |url_request_context|. |url_request_context| must remain valid for the
@@ -43,15 +43,14 @@ class ProxyScriptFetcherImpl : public ProxyScriptFetcher,
virtual void Cancel();
virtual URLRequestContext* GetRequestContext();
- // URLRequest::Delegate methods:
-
- virtual void OnAuthRequired(URLRequest* request,
+ // net::URLRequest::Delegate methods:
+ virtual void OnAuthRequired(net::URLRequest* request,
AuthChallengeInfo* auth_info);
- virtual void OnSSLCertificateError(URLRequest* request, int cert_error,
+ virtual void OnSSLCertificateError(net::URLRequest* request, int cert_error,
X509Certificate* cert);
- virtual void OnResponseStarted(URLRequest* request);
- virtual void OnReadCompleted(URLRequest* request, int num_bytes);
- virtual void OnResponseCompleted(URLRequest* request);
+ virtual void OnResponseStarted(net::URLRequest* request);
+ virtual void OnReadCompleted(net::URLRequest* request, int num_bytes);
+ virtual void OnResponseCompleted(net::URLRequest* request);
// Used by unit-tests to modify the default limits.
base::TimeDelta SetTimeoutConstraint(base::TimeDelta timeout);
@@ -59,11 +58,11 @@ class ProxyScriptFetcherImpl : public ProxyScriptFetcher,
private:
// Read more bytes from the response.
- void ReadBody(URLRequest* request);
+ void ReadBody(net::URLRequest* request);
// Handles a response from Read(). Returns true if we should continue trying
// to read. |num_bytes| is 0 for EOF, and < 0 on errors.
- bool ConsumeBytesRead(URLRequest* request, int num_bytes);
+ bool ConsumeBytesRead(net::URLRequest* request, int num_bytes);
// Called once the request has completed to notify the caller of
// |response_code_| and |response_text_|.
@@ -82,7 +81,7 @@ class ProxyScriptFetcherImpl : public ProxyScriptFetcher,
// The context used for making network requests.
URLRequestContext* url_request_context_;
- // Buffer that URLRequest writes into.
+ // Buffer that net::URLRequest writes into.
enum { kBufSize = 4096 };
scoped_refptr<net::IOBuffer> buf_;
@@ -90,7 +89,7 @@ class ProxyScriptFetcherImpl : public ProxyScriptFetcher,
int next_id_;
// The current (in progress) request, or NULL.
- scoped_ptr<URLRequest> cur_request_;
+ scoped_ptr<net::URLRequest> cur_request_;
// State for current request (only valid when |cur_request_| is not NULL):
diff --git a/net/proxy/proxy_script_fetcher_impl_unittest.cc b/net/proxy/proxy_script_fetcher_impl_unittest.cc
index 347bbe9..ec0fb58 100644
--- a/net/proxy/proxy_script_fetcher_impl_unittest.cc
+++ b/net/proxy/proxy_script_fetcher_impl_unittest.cc
@@ -39,18 +39,21 @@ class RequestContext : public URLRequestContext {
host_resolver_ =
net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism,
NULL, NULL);
+ cert_verifier_ = new net::CertVerifier;
proxy_service_ = net::ProxyService::CreateFixed(no_proxy);
ssl_config_service_ = new net::SSLConfigServiceDefaults;
http_transaction_factory_ = new net::HttpCache(
- net::HttpNetworkLayer::CreateFactory(host_resolver_, NULL, NULL, NULL,
- proxy_service_, ssl_config_service_, NULL, NULL, NULL),
+ net::HttpNetworkLayer::CreateFactory(host_resolver_, cert_verifier_,
+ NULL, NULL, NULL, proxy_service_, ssl_config_service_, NULL, NULL,
+ NULL),
net::HttpCache::DefaultBackend::InMemory(0));
}
private:
~RequestContext() {
delete http_transaction_factory_;
+ delete cert_verifier_;
delete host_resolver_;
}
};
@@ -76,7 +79,7 @@ class ProxyScriptFetcherImplTest : public PlatformTest {
}
static void SetUpTestCase() {
- URLRequest::AllowFileAccess();
+ net::URLRequest::AllowFileAccess();
}
protected:
diff --git a/net/proxy/proxy_service.cc b/net/proxy/proxy_service.cc
index b4aa96d..d7fa0ef 100644
--- a/net/proxy/proxy_service.cc
+++ b/net/proxy/proxy_service.cc
@@ -12,7 +12,6 @@
#include "base/message_loop.h"
#include "base/string_util.h"
#include "googleurl/src/gurl.h"
-#include "net/base/forwarding_net_log.h"
#include "net/base/net_log.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
@@ -127,6 +126,10 @@ class ProxyResolverNull : public ProxyResolver {
NOTREACHED();
}
+ virtual void CancelSetPacScript() {
+ NOTREACHED();
+ }
+
virtual int SetPacScript(
const scoped_refptr<ProxyResolverScriptData>& /*script_data*/,
CompletionCallback* /*callback*/) {
@@ -155,6 +158,10 @@ class ProxyResolverFromPacString : public ProxyResolver {
NOTREACHED();
}
+ virtual void CancelSetPacScript() {
+ NOTREACHED();
+ }
+
virtual int SetPacScript(
const scoped_refptr<ProxyResolverScriptData>& pac_script,
CompletionCallback* callback) {
@@ -170,16 +177,14 @@ class ProxyResolverFactoryForV8 : public ProxyResolverFactory {
public:
// |async_host_resolver|, |io_loop| and |net_log| must remain
// valid for the duration of our lifetime.
- // Both |async_host_resolver| and |net_log| will only be operated on
- // |io_loop|.
+ // |async_host_resolver| will only be operated on |io_loop|.
ProxyResolverFactoryForV8(HostResolver* async_host_resolver,
MessageLoop* io_loop,
NetLog* net_log)
: ProxyResolverFactory(true /*expects_pac_bytes*/),
async_host_resolver_(async_host_resolver),
io_loop_(io_loop),
- forwarding_net_log_(
- net_log ? new ForwardingNetLog(net_log, io_loop) : NULL) {
+ net_log_(net_log) {
}
virtual ProxyResolver* CreateProxyResolver() {
@@ -189,8 +194,7 @@ class ProxyResolverFactoryForV8 : public ProxyResolverFactory {
new SyncHostResolverBridge(async_host_resolver_, io_loop_);
ProxyResolverJSBindings* js_bindings =
- ProxyResolverJSBindings::CreateDefault(sync_host_resolver,
- forwarding_net_log_.get());
+ ProxyResolverJSBindings::CreateDefault(sync_host_resolver, net_log_);
// ProxyResolverV8 takes ownership of |js_bindings|.
return new ProxyResolverV8(js_bindings);
@@ -199,10 +203,7 @@ class ProxyResolverFactoryForV8 : public ProxyResolverFactory {
private:
HostResolver* const async_host_resolver_;
MessageLoop* io_loop_;
-
- // Thread-safe wrapper around a non-threadsafe NetLog implementation. This
- // enables the proxy resolver to emit log messages from the PAC thread.
- scoped_ptr<ForwardingNetLog> forwarding_net_log_;
+ NetLog* net_log_;
};
// Creates ProxyResolvers using a platform-specific implementation.
@@ -480,9 +481,13 @@ ProxyService* ProxyService::CreateFixed(const std::string& proxy) {
// static
ProxyService* ProxyService::CreateDirect() {
+ return CreateDirectWithNetLog(NULL);
+}
+
+ProxyService* ProxyService::CreateDirectWithNetLog(NetLog* net_log) {
// Use direct connections.
return new ProxyService(new ProxyConfigServiceDirect, new ProxyResolverNull,
- NULL);
+ net_log);
}
// static
diff --git a/net/proxy/proxy_service.h b/net/proxy/proxy_service.h
index 8a161ea..ba56f4d 100644
--- a/net/proxy/proxy_service.h
+++ b/net/proxy/proxy_service.h
@@ -193,6 +193,8 @@ class ProxyService : public base::RefCountedThreadSafe<ProxyService>,
// Creates a proxy service that uses a DIRECT connection for all requests.
static ProxyService* CreateDirect();
+ // |net_log|'s lifetime must exceed ProxyService.
+ static ProxyService* CreateDirectWithNetLog(NetLog* net_log);
// This method is used by tests to create a ProxyService that returns a
// hardcoded proxy fallback list (|pac_string|) for every URL.
diff --git a/net/proxy/proxy_service_unittest.cc b/net/proxy/proxy_service_unittest.cc
index 1c77876..7dec769 100644
--- a/net/proxy/proxy_service_unittest.cc
+++ b/net/proxy/proxy_service_unittest.cc
@@ -98,6 +98,8 @@ class MockProxyScriptFetcher : public ProxyScriptFetcher {
virtual void Cancel() {}
+ virtual URLRequestContext* GetRequestContext() { return NULL; }
+
const GURL& pending_request_url() const {
return pending_request_url_;
}
@@ -130,14 +132,17 @@ TEST(ProxyServiceTest, Direct) {
EXPECT_TRUE(info.is_direct());
// Check the NetLog was filled correctly.
- EXPECT_EQ(3u, log.entries().size());
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
+
+ EXPECT_EQ(3u, entries.size());
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 0, NetLog::TYPE_PROXY_SERVICE));
+ entries, 0, NetLog::TYPE_PROXY_SERVICE));
EXPECT_TRUE(LogContainsEvent(
- log.entries(), 1, NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST,
+ entries, 1, NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST,
NetLog::PHASE_NONE));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 2, NetLog::TYPE_PROXY_SERVICE));
+ entries, 2, NetLog::TYPE_PROXY_SERVICE));
}
TEST(ProxyServiceTest, PAC) {
@@ -174,15 +179,18 @@ TEST(ProxyServiceTest, PAC) {
EXPECT_EQ("foopy:80", info.proxy_server().ToURI());
// Check the NetLog was filled correctly.
- EXPECT_EQ(5u, log.entries().size());
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
+
+ EXPECT_EQ(5u, entries.size());
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 0, NetLog::TYPE_PROXY_SERVICE));
+ entries, 0, NetLog::TYPE_PROXY_SERVICE));
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 1, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC));
+ entries, 1, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 2, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC));
+ entries, 2, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 4, NetLog::TYPE_PROXY_SERVICE));
+ entries, 4, NetLog::TYPE_PROXY_SERVICE));
}
// Test that the proxy resolver does not see the URL's username/password
@@ -1149,18 +1157,21 @@ TEST(ProxyServiceTest, CancelWhilePACFetching) {
EXPECT_FALSE(callback1.have_result()); // Cancelled.
EXPECT_FALSE(callback2.have_result()); // Cancelled.
+ net::CapturingNetLog::EntryList entries1;
+ log1.GetEntries(&entries1);
+
// Check the NetLog for request 1 (which was cancelled) got filled properly.
- EXPECT_EQ(4u, log1.entries().size());
+ EXPECT_EQ(4u, entries1.size());
EXPECT_TRUE(LogContainsBeginEvent(
- log1.entries(), 0, NetLog::TYPE_PROXY_SERVICE));
+ entries1, 0, NetLog::TYPE_PROXY_SERVICE));
EXPECT_TRUE(LogContainsBeginEvent(
- log1.entries(), 1, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC));
+ entries1, 1, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC));
// Note that TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC is never completed before
// the cancellation occured.
EXPECT_TRUE(LogContainsEvent(
- log1.entries(), 2, NetLog::TYPE_CANCELLED, NetLog::PHASE_NONE));
+ entries1, 2, NetLog::TYPE_CANCELLED, NetLog::PHASE_NONE));
EXPECT_TRUE(LogContainsEndEvent(
- log1.entries(), 3, NetLog::TYPE_PROXY_SERVICE));
+ entries1, 3, NetLog::TYPE_PROXY_SERVICE));
}
// Test that if auto-detect fails, we fall-back to the custom pac.
@@ -1679,11 +1690,14 @@ TEST(ProxyServiceTest, NetworkChangeTriggersPacRefetch) {
// In particular, PROXY_CONFIG_CHANGED should have only been emitted once
// (for the initial setup), and NOT a second time when the IP address
// changed.
- EXPECT_TRUE(LogContainsEntryWithType(log.entries(), 0,
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
+
+ EXPECT_TRUE(LogContainsEntryWithType(entries, 0,
NetLog::TYPE_PROXY_CONFIG_CHANGED));
- ASSERT_EQ(13u, log.entries().size());
- for (size_t i = 1; i < log.entries().size(); ++i)
- EXPECT_NE(NetLog::TYPE_PROXY_CONFIG_CHANGED, log.entries()[i].type);
+ ASSERT_EQ(13u, entries.size());
+ for (size_t i = 1; i < entries.size(); ++i)
+ EXPECT_NE(NetLog::TYPE_PROXY_CONFIG_CHANGED, entries[i].type);
}
} // namespace net
diff --git a/net/proxy/sync_host_resolver_bridge_unittest.cc b/net/proxy/sync_host_resolver_bridge_unittest.cc
index cd4264e..43c829f 100644
--- a/net/proxy/sync_host_resolver_bridge_unittest.cc
+++ b/net/proxy/sync_host_resolver_bridge_unittest.cc
@@ -109,6 +109,10 @@ class SyncProxyResolver : public ProxyResolver {
host_resolver_->Shutdown();
}
+ virtual void CancelSetPacScript() {
+ NOTREACHED();
+ }
+
virtual int SetPacScript(
const scoped_refptr<ProxyResolverScriptData>& script_data,
CompletionCallback* callback) {
diff --git a/net/server/http_listen_socket.cc b/net/server/http_listen_socket.cc
index f35582b..a946bd9 100644
--- a/net/server/http_listen_socket.cc
+++ b/net/server/http_listen_socket.cc
@@ -310,6 +310,14 @@ bool HttpListenSocket::ParseHeaders(HttpServerRequestInfo* info) {
return false;
}
+void HttpListenSocket::Close() {
+ ListenSocket::Close();
+}
+
+void HttpListenSocket::Listen() {
+ ListenSocket::Listen();
+}
+
void HttpListenSocket::DidAccept(ListenSocket* server,
ListenSocket* connection) {
connection->AddRef();
@@ -344,6 +352,6 @@ void HttpListenSocket::DidRead(ListenSocket*,
}
void HttpListenSocket::DidClose(ListenSocket* sock) {
- sock->Release();
delegate_->OnClose(this);
+ sock->Release();
}
diff --git a/net/server/http_listen_socket.h b/net/server/http_listen_socket.h
index 2eae47d..8b0bbc2 100644
--- a/net/server/http_listen_socket.h
+++ b/net/server/http_listen_socket.h
@@ -44,8 +44,8 @@ class HttpListenSocket : public ListenSocket,
void Send404();
void Send500(const std::string& message);
- void Close() { ListenSocket::Close(); }
- void Listen() { ListenSocket::Listen(); }
+ virtual void Close();
+ virtual void Listen();
// ListenSocketDelegate
virtual void DidAccept(ListenSocket* server, ListenSocket* connection);
diff --git a/net/socket/client_socket_factory.cc b/net/socket/client_socket_factory.cc
index 8965630..f4da066 100644
--- a/net/socket/client_socket_factory.cc
+++ b/net/socket/client_socket_factory.cc
@@ -4,7 +4,7 @@
#include "net/socket/client_socket_factory.h"
-#include "base/singleton.h"
+#include "base/lazy_instance.h"
#include "build/build_config.h"
#include "net/socket/client_socket_handle.h"
#if defined(OS_WIN)
@@ -30,19 +30,21 @@ SSLClientSocket* DefaultSSLClientSocketFactory(
const HostPortPair& host_and_port,
const SSLConfig& ssl_config,
SSLHostInfo* ssl_host_info,
+ CertVerifier* cert_verifier,
DnsCertProvenanceChecker* dns_cert_checker) {
scoped_ptr<SSLHostInfo> shi(ssl_host_info);
#if defined(OS_WIN)
- return new SSLClientSocketWin(transport_socket, host_and_port, ssl_config);
+ return new SSLClientSocketWin(transport_socket, host_and_port, ssl_config,
+ cert_verifier);
#elif defined(USE_OPENSSL)
return new SSLClientSocketOpenSSL(transport_socket, host_and_port,
- ssl_config);
+ ssl_config, cert_verifier);
#elif defined(USE_NSS)
return new SSLClientSocketNSS(transport_socket, host_and_port, ssl_config,
- shi.release(), dns_cert_checker);
+ shi.release(), cert_verifier, dns_cert_checker);
#elif defined(OS_MACOSX)
return new SSLClientSocketNSS(transport_socket, host_and_port, ssl_config,
- shi.release(), dns_cert_checker);
+ shi.release(), cert_verifier, dns_cert_checker);
#else
NOTIMPLEMENTED();
return NULL;
@@ -65,17 +67,21 @@ class DefaultClientSocketFactory : public ClientSocketFactory {
const HostPortPair& host_and_port,
const SSLConfig& ssl_config,
SSLHostInfo* ssl_host_info,
+ CertVerifier* cert_verifier,
DnsCertProvenanceChecker* dns_cert_checker) {
return g_ssl_factory(transport_socket, host_and_port, ssl_config,
- ssl_host_info, dns_cert_checker);
+ ssl_host_info, cert_verifier, dns_cert_checker);
}
};
+static base::LazyInstance<DefaultClientSocketFactory>
+ g_default_client_socket_factory(base::LINKER_INITIALIZED);
+
} // namespace
// static
ClientSocketFactory* ClientSocketFactory::GetDefaultFactory() {
- return Singleton<DefaultClientSocketFactory>::get();
+ return g_default_client_socket_factory.Pointer();
}
// static
@@ -89,11 +95,12 @@ SSLClientSocket* ClientSocketFactory::CreateSSLClientSocket(
ClientSocket* transport_socket,
const HostPortPair& host_and_port,
const SSLConfig& ssl_config,
- SSLHostInfo* ssl_host_info) {
+ SSLHostInfo* ssl_host_info,
+ CertVerifier* cert_verifier) {
ClientSocketHandle* socket_handle = new ClientSocketHandle();
socket_handle->set_socket(transport_socket);
return CreateSSLClientSocket(socket_handle, host_and_port, ssl_config,
- ssl_host_info,
+ ssl_host_info, cert_verifier,
NULL /* DnsCertProvenanceChecker */);
}
diff --git a/net/socket/client_socket_factory.h b/net/socket/client_socket_factory.h
index 0ab370a..2a0cd7c 100644
--- a/net/socket/client_socket_factory.h
+++ b/net/socket/client_socket_factory.h
@@ -14,6 +14,7 @@
namespace net {
class AddressList;
+class CertVerifier;
class ClientSocket;
class ClientSocketHandle;
class DnsCertProvenanceChecker;
@@ -28,6 +29,7 @@ typedef SSLClientSocket* (*SSLClientSocketFactory)(
const HostPortPair& host_and_port,
const SSLConfig& ssl_config,
SSLHostInfo* ssl_host_info,
+ CertVerifier* cert_verifier,
DnsCertProvenanceChecker* dns_cert_checker);
// An interface used to instantiate ClientSocket objects. Used to facilitate
@@ -48,6 +50,7 @@ class ClientSocketFactory {
const HostPortPair& host_and_port,
const SSLConfig& ssl_config,
SSLHostInfo* ssl_host_info,
+ CertVerifier* cert_verifier,
DnsCertProvenanceChecker* dns_cert_checker) = 0;
// Deprecated function (http://crbug.com/37810) that takes a ClientSocket.
@@ -55,7 +58,8 @@ class ClientSocketFactory {
ClientSocket* transport_socket,
const HostPortPair& host_and_port,
const SSLConfig& ssl_config,
- SSLHostInfo* ssl_host_info);
+ SSLHostInfo* ssl_host_info,
+ CertVerifier* cert_verifier);
// Returns the default ClientSocketFactory.
static ClientSocketFactory* GetDefaultFactory();
diff --git a/net/socket/client_socket_pool.h b/net/socket/client_socket_pool.h
index 23bb63f..c889ab4 100644
--- a/net/socket/client_socket_pool.h
+++ b/net/socket/client_socket_pool.h
@@ -45,8 +45,8 @@ class ClientSocketPool {
// The caller must recover from the error before using the connection, or
// Disconnect the socket before releasing or resetting the |handle|.
// The current recoverable errors are: the errors accepted by
- // IsCertificateError(err) and PROXY_AUTH_REQUESTED when reported by
- // HttpProxyClientSocketPool.
+ // IsCertificateError(err) and PROXY_AUTH_REQUESTED, or
+ // HTTPS_PROXY_TUNNEL_RESPONSE when reported by HttpProxyClientSocketPool.
//
// If this function returns OK, then |handle| is initialized upon return.
// The |handle|'s is_initialized method will return true in this case. If a
diff --git a/net/socket/client_socket_pool_base.cc b/net/socket/client_socket_pool_base.cc
index 9cbefa9..871966f 100644
--- a/net/socket/client_socket_pool_base.cc
+++ b/net/socket/client_socket_pool_base.cc
@@ -359,12 +359,8 @@ int ClientSocketPoolBaseHelper::RequestSocketInternal(
group->AddJob(connect_job.release());
} else {
LogBoundConnectJobToRequest(connect_job->net_log().source(), request);
- ClientSocket* error_socket = NULL;
- if (!preconnecting) {
- DCHECK(handle);
- connect_job->GetAdditionalErrorState(handle);
- error_socket = connect_job->ReleaseSocket();
- }
+ connect_job->GetAdditionalErrorState(handle);
+ ClientSocket* error_socket = connect_job->ReleaseSocket();
if (error_socket) {
HandOutSocket(error_socket, false /* not reused */, handle,
base::TimeDelta(), group, request->net_log());
diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc
index 0d8827e..7c0e2e1 100644
--- a/net/socket/client_socket_pool_base_unittest.cc
+++ b/net/socket/client_socket_pool_base_unittest.cc
@@ -110,6 +110,7 @@ class MockClientSocketFactory : public ClientSocketFactory {
const HostPortPair& host_and_port,
const SSLConfig& ssl_config,
SSLHostInfo* ssl_host_info,
+ CertVerifier* cert_verifier,
DnsCertProvenanceChecker* dns_cert_checker) {
NOTIMPLEMENTED();
delete ssl_host_info;
@@ -620,21 +621,24 @@ TEST_F(ClientSocketPoolBaseTest, ConnectJob_TimedOut) {
PlatformThread::Sleep(1);
EXPECT_EQ(ERR_TIMED_OUT, delegate.WaitForResult());
- EXPECT_EQ(6u, log.entries().size());
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
+
+ EXPECT_EQ(6u, entries.size());
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 0, NetLog::TYPE_SOCKET_POOL_CONNECT_JOB));
+ entries, 0, NetLog::TYPE_SOCKET_POOL_CONNECT_JOB));
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 1, NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_CONNECT));
+ entries, 1, NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_CONNECT));
EXPECT_TRUE(LogContainsEvent(
- log.entries(), 2, NetLog::TYPE_CONNECT_JOB_SET_SOCKET,
+ entries, 2, NetLog::TYPE_CONNECT_JOB_SET_SOCKET,
NetLog::PHASE_NONE));
EXPECT_TRUE(LogContainsEvent(
- log.entries(), 3, NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_TIMED_OUT,
+ entries, 3, NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_TIMED_OUT,
NetLog::PHASE_NONE));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 4, NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_CONNECT));
+ entries, 4, NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_CONNECT));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 5, NetLog::TYPE_SOCKET_POOL_CONNECT_JOB));
+ entries, 5, NetLog::TYPE_SOCKET_POOL_CONNECT_JOB));
}
TEST_F(ClientSocketPoolBaseTest, BasicSynchronous) {
@@ -655,17 +659,20 @@ TEST_F(ClientSocketPoolBaseTest, BasicSynchronous) {
EXPECT_TRUE(handle.socket());
handle.Reset();
- EXPECT_EQ(4u, log.entries().size());
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
+
+ EXPECT_EQ(4u, entries.size());
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 0, NetLog::TYPE_SOCKET_POOL));
+ entries, 0, NetLog::TYPE_SOCKET_POOL));
EXPECT_TRUE(LogContainsEvent(
- log.entries(), 1, NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB,
+ entries, 1, NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB,
NetLog::PHASE_NONE));
EXPECT_TRUE(LogContainsEvent(
- log.entries(), 2, NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET,
+ entries, 2, NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET,
NetLog::PHASE_NONE));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 3, NetLog::TYPE_SOCKET_POOL));
+ entries, 3, NetLog::TYPE_SOCKET_POOL));
}
TEST_F(ClientSocketPoolBaseTest, InitConnectionFailure) {
@@ -692,14 +699,17 @@ TEST_F(ClientSocketPoolBaseTest, InitConnectionFailure) {
EXPECT_FALSE(handle.is_ssl_error());
EXPECT_TRUE(handle.ssl_error_response_info().headers.get() == NULL);
- EXPECT_EQ(3u, log.entries().size());
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
+
+ EXPECT_EQ(3u, entries.size());
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 0, NetLog::TYPE_SOCKET_POOL));
+ entries, 0, NetLog::TYPE_SOCKET_POOL));
EXPECT_TRUE(LogContainsEvent(
- log.entries(), 1, NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB,
+ entries, 1, NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB,
NetLog::PHASE_NONE));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 2, NetLog::TYPE_SOCKET_POOL));
+ entries, 2, NetLog::TYPE_SOCKET_POOL));
}
TEST_F(ClientSocketPoolBaseTest, TotalLimit) {
@@ -1503,17 +1513,20 @@ TEST_F(ClientSocketPoolBaseTest, BasicAsynchronous) {
EXPECT_TRUE(handle.socket());
handle.Reset();
- EXPECT_EQ(4u, log.entries().size());
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
+
+ EXPECT_EQ(4u, entries.size());
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 0, NetLog::TYPE_SOCKET_POOL));
+ entries, 0, NetLog::TYPE_SOCKET_POOL));
EXPECT_TRUE(LogContainsEvent(
- log.entries(), 1, NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB,
+ entries, 1, NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB,
NetLog::PHASE_NONE));
EXPECT_TRUE(LogContainsEvent(
- log.entries(), 2, NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET,
+ entries, 2, NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET,
NetLog::PHASE_NONE));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 3, NetLog::TYPE_SOCKET_POOL));
+ entries, 3, NetLog::TYPE_SOCKET_POOL));
}
TEST_F(ClientSocketPoolBaseTest,
@@ -1540,14 +1553,17 @@ TEST_F(ClientSocketPoolBaseTest,
EXPECT_FALSE(handle.is_ssl_error());
EXPECT_TRUE(handle.ssl_error_response_info().headers.get() == NULL);
- EXPECT_EQ(3u, log.entries().size());
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
+
+ EXPECT_EQ(3u, entries.size());
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 0, NetLog::TYPE_SOCKET_POOL));
+ entries, 0, NetLog::TYPE_SOCKET_POOL));
EXPECT_TRUE(LogContainsEvent(
- log.entries(), 1, NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB,
+ entries, 1, NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB,
NetLog::PHASE_NONE));
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), 2, NetLog::TYPE_SOCKET_POOL));
+ entries, 2, NetLog::TYPE_SOCKET_POOL));
}
TEST_F(ClientSocketPoolBaseTest, TwoRequestsCancelOne) {
@@ -1892,8 +1908,11 @@ TEST_F(ClientSocketPoolBaseTest, CleanupTimedOutIdleSockets) {
log.bound());
EXPECT_EQ(OK, rv);
EXPECT_TRUE(handle.is_reused());
+
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
EXPECT_TRUE(LogContainsEntryWithType(
- log.entries(), 1, NetLog::TYPE_SOCKET_POOL_REUSED_AN_EXISTING_SOCKET));
+ entries, 1, NetLog::TYPE_SOCKET_POOL_REUSED_AN_EXISTING_SOCKET));
}
// Make sure that we process all pending requests even when we're stalling
@@ -2906,13 +2925,6 @@ TEST_F(ClientSocketPoolBaseTest, RequestSocketsSynchronousError) {
BoundNetLog());
ASSERT_FALSE(pool_->HasGroup("a"));
-
- connect_job_factory_->set_job_type(
- TestConnectJob::kMockAdditionalErrorStateJob);
- pool_->RequestSockets("a", &params_, kDefaultMaxSocketsPerGroup,
- BoundNetLog());
-
- ASSERT_FALSE(pool_->HasGroup("a"));
}
TEST_F(ClientSocketPoolBaseTest, RequestSocketsMultipleTimesDoesNothing) {
diff --git a/net/socket/client_socket_pool_manager.cc b/net/socket/client_socket_pool_manager.cc
index 6c73c36..8516fbc 100644
--- a/net/socket/client_socket_pool_manager.cc
+++ b/net/socket/client_socket_pool_manager.cc
@@ -55,6 +55,7 @@ ClientSocketPoolManager::ClientSocketPoolManager(
NetLog* net_log,
ClientSocketFactory* socket_factory,
HostResolver* host_resolver,
+ CertVerifier* cert_verifier,
DnsRRResolver* dnsrr_resolver,
DnsCertProvenanceChecker* dns_cert_checker,
SSLHostInfoFactory* ssl_host_info_factory,
@@ -63,6 +64,7 @@ ClientSocketPoolManager::ClientSocketPoolManager(
: net_log_(net_log),
socket_factory_(socket_factory),
host_resolver_(host_resolver),
+ cert_verifier_(cert_verifier),
dnsrr_resolver_(dnsrr_resolver),
dns_cert_checker_(dns_cert_checker),
ssl_host_info_factory_(ssl_host_info_factory),
@@ -80,6 +82,7 @@ ClientSocketPoolManager::ClientSocketPoolManager(
g_max_sockets, g_max_sockets_per_group,
&ssl_pool_histograms_,
host_resolver,
+ cert_verifier,
dnsrr_resolver,
dns_cert_checker,
ssl_host_info_factory,
@@ -230,6 +233,7 @@ HttpProxyClientSocketPool* ClientSocketPoolManager::GetSocketPoolForHTTPProxy(
g_max_sockets_per_proxy_server, g_max_sockets_per_group,
&ssl_for_https_proxy_pool_histograms_,
host_resolver_,
+ cert_verifier_,
dnsrr_resolver_,
dns_cert_checker_,
ssl_host_info_factory_,
@@ -266,6 +270,7 @@ SSLClientSocketPool* ClientSocketPoolManager::GetSocketPoolForSSLWithProxy(
g_max_sockets_per_proxy_server, g_max_sockets_per_group,
&ssl_pool_histograms_,
host_resolver_,
+ cert_verifier_,
dnsrr_resolver_,
dns_cert_checker_,
ssl_host_info_factory_,
diff --git a/net/socket/client_socket_pool_manager.h b/net/socket/client_socket_pool_manager.h
index 823213e..cfcb465 100644
--- a/net/socket/client_socket_pool_manager.h
+++ b/net/socket/client_socket_pool_manager.h
@@ -6,8 +6,8 @@
// simple container for all of them. Most importantly, it handles the lifetime
// and destruction order properly.
-#ifndef NET_SOCKET_CLIENT_SOCKET_POOL_MANAGER_
-#define NET_SOCKET_CLIENT_SOCKET_POOL_MANAGER_
+#ifndef NET_SOCKET_CLIENT_SOCKET_POOL_MANAGER_H_
+#define NET_SOCKET_CLIENT_SOCKET_POOL_MANAGER_H_
#pragma once
#include <map>
@@ -23,6 +23,7 @@ class Value;
namespace net {
+class CertVerifier;
class ClientSocketFactory;
class ClientSocketPoolHistograms;
class DnsCertProvenanceChecker;
@@ -54,13 +55,14 @@ class OwnedPoolMap : public std::map<Key, Value> {
}
};
-} // internal
+} // namespace internal
class ClientSocketPoolManager : public NonThreadSafe {
public:
ClientSocketPoolManager(NetLog* net_log,
ClientSocketFactory* socket_factory,
HostResolver* host_resolver,
+ CertVerifier* cert_verifier,
DnsRRResolver* dnsrr_resolver,
DnsCertProvenanceChecker* dns_cert_checker,
SSLHostInfoFactory* ssl_host_info_factory,
@@ -106,6 +108,7 @@ class ClientSocketPoolManager : public NonThreadSafe {
NetLog* const net_log_;
ClientSocketFactory* const socket_factory_;
HostResolver* const host_resolver_;
+ CertVerifier* const cert_verifier_;
DnsRRResolver* const dnsrr_resolver_;
DnsCertProvenanceChecker* const dns_cert_checker_;
SSLHostInfoFactory* const ssl_host_info_factory_;
@@ -146,4 +149,4 @@ class ClientSocketPoolManager : public NonThreadSafe {
} // namespace net
-#endif // NET_SOCKET_CLIENT_SOCKET_POOL_MANAGER_
+#endif // NET_SOCKET_CLIENT_SOCKET_POOL_MANAGER_H_
diff --git a/net/socket/dns_cert_provenance_checker.cc b/net/socket/dns_cert_provenance_checker.cc
index 27c4982..51a9750 100644
--- a/net/socket/dns_cert_provenance_checker.cc
+++ b/net/socket/dns_cert_provenance_checker.cc
@@ -16,13 +16,14 @@
#include <set>
#include <string>
+#include "base/base64.h"
#include "base/basictypes.h"
#include "base/crypto/encryptor.h"
#include "base/crypto/symmetric_key.h"
+#include "base/lazy_instance.h"
#include "base/non_thread_safe.h"
#include "base/pickle.h"
#include "base/scoped_ptr.h"
-#include "base/singleton.h"
#include "net/base/completion_callback.h"
#include "net/base/dns_util.h"
#include "net/base/dnsrr_resolver.h"
@@ -72,13 +73,16 @@ class DnsCertLimits {
}
private:
- friend struct DefaultSingletonTraits<DnsCertLimits>;
+ friend struct base::DefaultLazyInstanceTraits<DnsCertLimits>;
std::set<std::string> uploaded_hostnames_;
DISALLOW_COPY_AND_ASSIGN(DnsCertLimits);
};
+static base::LazyInstance<DnsCertLimits> g_dns_cert_limits(
+ base::LINKER_INITIALIZED);
+
// DnsCertProvenanceCheck performs the DNS lookup of the certificate. This
// class is self-deleting.
class DnsCertProvenanceCheck : public NonThreadSafe {
@@ -105,7 +109,7 @@ class DnsCertProvenanceCheck : public NonThreadSafe {
if (der_certs_.empty())
return;
- DnsCertLimits* const limits = Singleton<DnsCertLimits>::get();
+ DnsCertLimits* const limits = g_dns_cert_limits.Pointer();
if (limits->HaveReachedMaxUploads() ||
limits->HaveUploadedForHostname(hostname_)) {
return;
@@ -124,7 +128,7 @@ class DnsCertProvenanceCheck : public NonThreadSafe {
}
fingerprint_hex[SHA1_LENGTH * 2] = 0;
- static const char kBaseCertName[] = ".certs.links.org";
+ static const char kBaseCertName[] = ".certs.googlednstest.com";
domain_.assign(fingerprint_hex);
domain_.append(kBaseCertName);
@@ -146,7 +150,8 @@ class DnsCertProvenanceCheck : public NonThreadSafe {
LOG(ERROR) << "FAILED"
<< " hostname:" << hostname_
<< " domain:" << domain_;
- Singleton<DnsCertLimits>::get()->DidUpload(hostname_);
+ g_dns_cert_limits.Get().DidUpload(hostname_);
+ LogCertificates(der_certs_);
delegate_->OnDnsCertLookupFailed(hostname_, der_certs_);
} else if (status == OK) {
LOG(ERROR) << "GOOD"
@@ -159,6 +164,35 @@ class DnsCertProvenanceCheck : public NonThreadSafe {
delete this;
}
+ // LogCertificates writes a certificate chain, in PEM format, to LOG(ERROR).
+ static void LogCertificates(
+ const std::vector<std::string>& der_certs) {
+ std::string dump;
+ bool first = true;
+
+ for (std::vector<std::string>::const_iterator
+ i = der_certs.begin(); i != der_certs.end(); i++) {
+ if (!first)
+ dump += "\n";
+ first = false;
+
+ dump += "-----BEGIN CERTIFICATE-----\n";
+ std::string b64_encoded;
+ base::Base64Encode(*i, &b64_encoded);
+ for (size_t i = 0; i < b64_encoded.size();) {
+ size_t todo = b64_encoded.size() - i;
+ if (todo > 64)
+ todo = 64;
+ dump += b64_encoded.substr(i, todo);
+ dump += "\n";
+ i += todo;
+ }
+ dump += "-----END CERTIFICATE-----";
+ }
+
+ LOG(ERROR) << "Offending certificates:\n" << dump;
+ }
+
const std::string hostname_;
std::string domain_;
DnsRRResolver* dnsrr_resolver_;
diff --git a/net/socket/nss_ssl_util.cc b/net/socket/nss_ssl_util.cc
new file mode 100644
index 0000000..eb8bafb
--- /dev/null
+++ b/net/socket/nss_ssl_util.cc
@@ -0,0 +1,240 @@
+// 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.
+
+#include "net/socket/nss_ssl_util.h"
+
+#include <nss.h>
+#include <secerr.h>
+#include <ssl.h>
+#include <sslerr.h>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/nss_util.h"
+#include "base/singleton.h"
+#include "base/thread_restrictions.h"
+#include "base/values.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_log.h"
+
+namespace net {
+
+class NSSSSLInitSingleton {
+ public:
+ NSSSSLInitSingleton() {
+ base::EnsureNSSInit();
+
+ NSS_SetDomesticPolicy();
+
+#if defined(USE_SYSTEM_SSL)
+ // Use late binding to avoid scary but benign warning
+ // "Symbol `SSL_ImplementedCiphers' has different size in shared object,
+ // consider re-linking"
+ // TODO(wtc): Use the new SSL_GetImplementedCiphers and
+ // SSL_GetNumImplementedCiphers functions when we require NSS 3.12.6.
+ // See https://bugzilla.mozilla.org/show_bug.cgi?id=496993.
+ const PRUint16* pSSL_ImplementedCiphers = static_cast<const PRUint16*>(
+ dlsym(RTLD_DEFAULT, "SSL_ImplementedCiphers"));
+ if (pSSL_ImplementedCiphers == NULL) {
+ NOTREACHED() << "Can't get list of supported ciphers";
+ return;
+ }
+#else
+#define pSSL_ImplementedCiphers SSL_ImplementedCiphers
+#endif
+
+ // Explicitly enable exactly those ciphers with keys of at least 80 bits
+ for (int i = 0; i < SSL_NumImplementedCiphers; i++) {
+ SSLCipherSuiteInfo info;
+ if (SSL_GetCipherSuiteInfo(pSSL_ImplementedCiphers[i], &info,
+ sizeof(info)) == SECSuccess) {
+ SSL_CipherPrefSetDefault(pSSL_ImplementedCiphers[i],
+ (info.effectiveKeyBits >= 80));
+ }
+ }
+
+ // Enable SSL.
+ SSL_OptionSetDefault(SSL_SECURITY, PR_TRUE);
+
+ // All other SSL options are set per-session by SSLClientSocket and
+ // SSLServerSocket.
+ }
+
+ ~NSSSSLInitSingleton() {
+ // Have to clear the cache, or NSS_Shutdown fails with SEC_ERROR_BUSY.
+ SSL_ClearSessionCache();
+ }
+};
+
+static base::LazyInstance<NSSSSLInitSingleton> g_nss_ssl_init_singleton(
+ base::LINKER_INITIALIZED);
+
+// Initialize the NSS SSL library if it isn't already initialized. This must
+// be called before any other NSS SSL functions. This function is
+// thread-safe, and the NSS SSL library will only ever be initialized once.
+// The NSS SSL library will be properly shut down on program exit.
+void EnsureNSSSSLInit() {
+ // Initializing SSL causes us to do blocking IO.
+ // Temporarily allow it until we fix
+ // http://code.google.com/p/chromium/issues/detail?id=59847
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+ g_nss_ssl_init_singleton.Get();
+}
+
+// Map a Chromium net error code to an NSS error code.
+// See _MD_unix_map_default_error in the NSS source
+// tree for inspiration.
+PRErrorCode MapErrorToNSS(int result) {
+ if (result >=0)
+ return result;
+
+ switch (result) {
+ case ERR_IO_PENDING:
+ return PR_WOULD_BLOCK_ERROR;
+ case ERR_ACCESS_DENIED:
+ case ERR_NETWORK_ACCESS_DENIED:
+ // For connect, this could be mapped to PR_ADDRESS_NOT_SUPPORTED_ERROR.
+ return PR_NO_ACCESS_RIGHTS_ERROR;
+ case ERR_NOT_IMPLEMENTED:
+ return PR_NOT_IMPLEMENTED_ERROR;
+ case ERR_INTERNET_DISCONNECTED: // Equivalent to ENETDOWN.
+ return PR_NETWORK_UNREACHABLE_ERROR; // Best approximation.
+ case ERR_CONNECTION_TIMED_OUT:
+ case ERR_TIMED_OUT:
+ return PR_IO_TIMEOUT_ERROR;
+ case ERR_CONNECTION_RESET:
+ return PR_CONNECT_RESET_ERROR;
+ case ERR_CONNECTION_ABORTED:
+ return PR_CONNECT_ABORTED_ERROR;
+ case ERR_CONNECTION_REFUSED:
+ return PR_CONNECT_REFUSED_ERROR;
+ case ERR_ADDRESS_UNREACHABLE:
+ return PR_HOST_UNREACHABLE_ERROR; // Also PR_NETWORK_UNREACHABLE_ERROR.
+ case ERR_ADDRESS_INVALID:
+ return PR_ADDRESS_NOT_AVAILABLE_ERROR;
+ case ERR_NAME_NOT_RESOLVED:
+ return PR_DIRECTORY_LOOKUP_ERROR;
+ default:
+ LOG(WARNING) << "MapErrorToNSS " << result
+ << " mapped to PR_UNKNOWN_ERROR";
+ return PR_UNKNOWN_ERROR;
+ }
+}
+
+// The default error mapping function.
+// Maps an NSS error code to a network error code.
+int MapNSSError(PRErrorCode err) {
+ // TODO(port): fill this out as we learn what's important
+ switch (err) {
+ case PR_WOULD_BLOCK_ERROR:
+ return ERR_IO_PENDING;
+ case PR_ADDRESS_NOT_SUPPORTED_ERROR: // For connect.
+ case PR_NO_ACCESS_RIGHTS_ERROR:
+ return ERR_ACCESS_DENIED;
+ case PR_IO_TIMEOUT_ERROR:
+ return ERR_TIMED_OUT;
+ case PR_CONNECT_RESET_ERROR:
+ return ERR_CONNECTION_RESET;
+ case PR_CONNECT_ABORTED_ERROR:
+ return ERR_CONNECTION_ABORTED;
+ case PR_CONNECT_REFUSED_ERROR:
+ return ERR_CONNECTION_REFUSED;
+ case PR_HOST_UNREACHABLE_ERROR:
+ case PR_NETWORK_UNREACHABLE_ERROR:
+ return ERR_ADDRESS_UNREACHABLE;
+ case PR_ADDRESS_NOT_AVAILABLE_ERROR:
+ return ERR_ADDRESS_INVALID;
+ case PR_INVALID_ARGUMENT_ERROR:
+ return ERR_INVALID_ARGUMENT;
+ case PR_END_OF_FILE_ERROR:
+ return ERR_CONNECTION_CLOSED;
+ case PR_NOT_IMPLEMENTED_ERROR:
+ return ERR_NOT_IMPLEMENTED;
+
+ case SEC_ERROR_INVALID_ARGS:
+ return ERR_INVALID_ARGUMENT;
+
+ case SSL_ERROR_SSL_DISABLED:
+ return ERR_NO_SSL_VERSIONS_ENABLED;
+ case SSL_ERROR_NO_CYPHER_OVERLAP:
+ case SSL_ERROR_UNSUPPORTED_VERSION:
+ return ERR_SSL_VERSION_OR_CIPHER_MISMATCH;
+ case SSL_ERROR_HANDSHAKE_FAILURE_ALERT:
+ case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT:
+ case SSL_ERROR_ILLEGAL_PARAMETER_ALERT:
+ return ERR_SSL_PROTOCOL_ERROR;
+ case SSL_ERROR_DECOMPRESSION_FAILURE_ALERT:
+ return ERR_SSL_DECOMPRESSION_FAILURE_ALERT;
+ case SSL_ERROR_BAD_MAC_ALERT:
+ return ERR_SSL_BAD_RECORD_MAC_ALERT;
+ case SSL_ERROR_UNSAFE_NEGOTIATION:
+ return ERR_SSL_UNSAFE_NEGOTIATION;
+ case SSL_ERROR_WEAK_SERVER_KEY:
+ return ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY;
+
+ default: {
+ if (IS_SSL_ERROR(err)) {
+ LOG(WARNING) << "Unknown SSL error " << err <<
+ " mapped to net::ERR_SSL_PROTOCOL_ERROR";
+ return ERR_SSL_PROTOCOL_ERROR;
+ }
+ LOG(WARNING) << "Unknown error " << err <<
+ " mapped to net::ERR_FAILED";
+ return ERR_FAILED;
+ }
+ }
+}
+
+// Context-sensitive error mapping functions.
+int MapNSSHandshakeError(PRErrorCode err) {
+ switch (err) {
+ // If the server closed on us, it is a protocol error.
+ // Some TLS-intolerant servers do this when we request TLS.
+ case PR_END_OF_FILE_ERROR:
+ // The handshake may fail because some signature (for example, the
+ // signature in the ServerKeyExchange message for an ephemeral
+ // Diffie-Hellman cipher suite) is invalid.
+ case SEC_ERROR_BAD_SIGNATURE:
+ return ERR_SSL_PROTOCOL_ERROR;
+ default:
+ return MapNSSError(err);
+ }
+}
+
+// Extra parameters to attach to the NetLog when we receive an error in response
+// to a call to an NSS function. Used instead of SSLErrorParams with
+// events of type TYPE_SSL_NSS_ERROR. Automatically looks up last PR error.
+class SSLFailedNSSFunctionParams : public NetLog::EventParameters {
+ public:
+ // |param| is ignored if it has a length of 0.
+ SSLFailedNSSFunctionParams(const std::string& function,
+ const std::string& param)
+ : function_(function), param_(param), ssl_lib_error_(PR_GetError()) {
+ }
+
+ virtual Value* ToValue() const {
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetString("function", function_);
+ if (!param_.empty())
+ dict->SetString("param", param_);
+ dict->SetInteger("ssl_lib_error", ssl_lib_error_);
+ return dict;
+ }
+
+ private:
+ const std::string function_;
+ const std::string param_;
+ const PRErrorCode ssl_lib_error_;
+};
+
+void LogFailedNSSFunction(const BoundNetLog& net_log,
+ const char* function,
+ const char* param) {
+ net_log.AddEvent(
+ NetLog::TYPE_SSL_NSS_ERROR,
+ make_scoped_refptr(new SSLFailedNSSFunctionParams(function, param)));
+}
+
+} // namespace net
diff --git a/net/socket/nss_ssl_util.h b/net/socket/nss_ssl_util.h
new file mode 100644
index 0000000..64bf3cf
--- /dev/null
+++ b/net/socket/nss_ssl_util.h
@@ -0,0 +1,36 @@
+// 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.
+
+// This file is only inclued in ssl_client_socket_nss.cc and
+// ssl_server_socket_nss.cc to share common functions of NSS.
+
+#ifndef NET_SOCKET_NSS_SSL_UTIL_H_
+#define NEt_SOCKET_NSS_SSL_UTIL_H_
+
+#include <prerror.h>
+
+namespace net {
+
+class BoundNetLog;
+
+// Initalize NSS SSL library.
+void EnsureNSSSSLInit();
+
+// Log a failed NSS funcion call.
+void LogFailedNSSFunction(const BoundNetLog& net_log,
+ const char* function,
+ const char* param);
+
+// Map network error code to NSS error code.
+PRErrorCode MapErrorToNSS(int result);
+
+// Map NSS error code to network error code.
+int MapNSSError(PRErrorCode err);
+
+// Map NSS handshake error to network error code.
+int MapNSSHandshakeError(PRErrorCode err);
+
+} // namespace net
+
+#endif // NET_SOCKET_NSS_SSL_UTIL_H_
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc
index 96280b6..d88399d 100644
--- a/net/socket/socket_test_util.cc
+++ b/net/socket/socket_test_util.cc
@@ -15,7 +15,6 @@
#include "net/base/address_family.h"
#include "net/base/auth.h"
#include "net/base/host_resolver_proc.h"
-#include "net/base/ssl_cert_request_info.h"
#include "net/base/ssl_info.h"
#include "net/http/http_network_session.h"
#include "net/http/http_request_headers.h"
@@ -403,7 +402,7 @@ int DeterministicMockTCPClientSocket::Read(
return CompleteRead();
}
-void DeterministicMockTCPClientSocket::CompleteWrite(){
+void DeterministicMockTCPClientSocket::CompleteWrite() {
was_used_to_convey_data_ = true;
write_pending_ = false;
write_callback_->Run(write_result_);
@@ -532,18 +531,6 @@ void MockSSLClientSocket::GetSSLInfo(net::SSLInfo* ssl_info) {
ssl_info->Reset();
}
-void MockSSLClientSocket::GetSSLCertRequestInfo(
- net::SSLCertRequestInfo* cert_request_info) {
- DCHECK(cert_request_info);
- if (data_->cert_request_info) {
- cert_request_info->host_and_port =
- data_->cert_request_info->host_and_port;
- cert_request_info->client_certs = data_->cert_request_info->client_certs;
- } else {
- cert_request_info->Reset();
- }
-}
-
SSLClientSocket::NextProtoStatus MockSSLClientSocket::GetNextProto(
std::string* proto) {
*proto = data_->next_proto;
@@ -1029,6 +1016,7 @@ SSLClientSocket* MockClientSocketFactory::CreateSSLClientSocket(
const HostPortPair& host_and_port,
const SSLConfig& ssl_config,
SSLHostInfo* ssl_host_info,
+ CertVerifier* cert_verifier,
DnsCertProvenanceChecker* dns_cert_checker) {
MockSSLClientSocket* socket =
new MockSSLClientSocket(transport_socket, host_and_port, ssl_config,
@@ -1079,6 +1067,7 @@ SSLClientSocket* DeterministicMockClientSocketFactory::CreateSSLClientSocket(
const HostPortPair& host_and_port,
const SSLConfig& ssl_config,
SSLHostInfo* ssl_host_info,
+ CertVerifier* cert_verifier,
DnsCertProvenanceChecker* dns_cert_checker) {
MockSSLClientSocket* socket =
new MockSSLClientSocket(transport_socket, host_and_port, ssl_config,
diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h
index 38b0054..73dd07c 100644
--- a/net/socket/socket_test_util.h
+++ b/net/socket/socket_test_util.h
@@ -245,14 +245,12 @@ struct SSLSocketDataProvider {
SSLSocketDataProvider(bool async, int result)
: connect(async, result),
next_proto_status(SSLClientSocket::kNextProtoUnsupported),
- was_npn_negotiated(false),
- cert_request_info(NULL) { }
+ was_npn_negotiated(false) { }
MockConnect connect;
SSLClientSocket::NextProtoStatus next_proto_status;
std::string next_proto;
bool was_npn_negotiated;
- net::SSLCertRequestInfo* cert_request_info;
};
// A DataProvider where the client must write a request before the reads (e.g.
@@ -539,6 +537,7 @@ class MockClientSocketFactory : public ClientSocketFactory {
const HostPortPair& host_and_port,
const SSLConfig& ssl_config,
SSLHostInfo* ssl_host_info,
+ CertVerifier* cert_verifier,
DnsCertProvenanceChecker* dns_cert_checker);
SocketDataProviderArray<SocketDataProvider>& mock_data() {
return mock_data_;
@@ -715,8 +714,6 @@ class MockSSLClientSocket : public MockClientSocket {
// SSLClientSocket methods:
virtual void GetSSLInfo(net::SSLInfo* ssl_info);
- virtual void GetSSLCertRequestInfo(
- net::SSLCertRequestInfo* cert_request_info);
virtual NextProtoStatus GetNextProto(std::string* proto);
virtual bool was_npn_negotiated() const;
virtual bool set_was_npn_negotiated(bool negotiated);
@@ -886,6 +883,7 @@ class DeterministicMockClientSocketFactory : public ClientSocketFactory {
const HostPortPair& host_and_port,
const SSLConfig& ssl_config,
SSLHostInfo* ssl_host_info,
+ CertVerifier* cert_verifier,
DnsCertProvenanceChecker* dns_cert_checker);
SocketDataProviderArray<DeterministicSocketData>& mock_data() {
diff --git a/net/socket/socks5_client_socket.cc b/net/socket/socks5_client_socket.cc
index c6600a3..b2c5df9 100644
--- a/net/socket/socks5_client_socket.cc
+++ b/net/socket/socks5_client_socket.cc
@@ -113,6 +113,10 @@ bool SOCKS5ClientSocket::IsConnectedAndIdle() const {
return completed_handshake_ && transport_->socket()->IsConnectedAndIdle();
}
+const BoundNetLog& SOCKS5ClientSocket::NetLog() const {
+ return net_log_;
+}
+
void SOCKS5ClientSocket::SetSubresourceSpeculation() {
if (transport_.get() && transport_->socket()) {
transport_->socket()->SetSubresourceSpeculation();
diff --git a/net/socket/socks5_client_socket.h b/net/socket/socks5_client_socket.h
index 36facda..75c8fc5 100644
--- a/net/socket/socks5_client_socket.h
+++ b/net/socket/socks5_client_socket.h
@@ -59,7 +59,7 @@ class SOCKS5ClientSocket : public ClientSocket {
virtual void Disconnect();
virtual bool IsConnected() const;
virtual bool IsConnectedAndIdle() const;
- virtual const BoundNetLog& NetLog() const { return net_log_; }
+ virtual const BoundNetLog& NetLog() const;
virtual void SetSubresourceSpeculation();
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
diff --git a/net/socket/socks5_client_socket_unittest.cc b/net/socket/socks5_client_socket_unittest.cc
index 2152c86..5458411 100644
--- a/net/socket/socks5_client_socket_unittest.cc
+++ b/net/socket/socks5_client_socket_unittest.cc
@@ -131,14 +131,19 @@ TEST_F(SOCKS5ClientSocketTest, CompleteHandshake) {
int rv = user_sock_->Connect(&callback_);
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_FALSE(user_sock_->IsConnected());
- EXPECT_TRUE(LogContainsBeginEvent(net_log_.entries(), 0,
+
+ net::CapturingNetLog::EntryList net_log_entries;
+ net_log_.GetEntries(&net_log_entries);
+ EXPECT_TRUE(LogContainsBeginEvent(net_log_entries, 0,
NetLog::TYPE_SOCKS5_CONNECT));
rv = callback_.WaitForResult();
EXPECT_EQ(OK, rv);
EXPECT_TRUE(user_sock_->IsConnected());
- EXPECT_TRUE(LogContainsEndEvent(net_log_.entries(), -1,
+
+ net_log_.GetEntries(&net_log_entries);
+ EXPECT_TRUE(LogContainsEndEvent(net_log_entries, -1,
NetLog::TYPE_SOCKS5_CONNECT));
scoped_refptr<IOBuffer> buffer(new IOBuffer(payload_write.size()));
@@ -248,12 +253,18 @@ TEST_F(SOCKS5ClientSocketTest, PartialReadWrites) {
hostname, 80, &net_log_));
int rv = user_sock_->Connect(&callback_);
EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_TRUE(LogContainsBeginEvent(net_log_.entries(), 0,
+
+ net::CapturingNetLog::EntryList net_log_entries;
+ net_log_.GetEntries(&net_log_entries);
+ EXPECT_TRUE(LogContainsBeginEvent(net_log_entries, 0,
NetLog::TYPE_SOCKS5_CONNECT));
+
rv = callback_.WaitForResult();
EXPECT_EQ(OK, rv);
EXPECT_TRUE(user_sock_->IsConnected());
- EXPECT_TRUE(LogContainsEndEvent(net_log_.entries(), -1,
+
+ net_log_.GetEntries(&net_log_entries);
+ EXPECT_TRUE(LogContainsEndEvent(net_log_entries, -1,
NetLog::TYPE_SOCKS5_CONNECT));
}
@@ -273,12 +284,16 @@ TEST_F(SOCKS5ClientSocketTest, PartialReadWrites) {
hostname, 80, &net_log_));
int rv = user_sock_->Connect(&callback_);
EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_TRUE(LogContainsBeginEvent(net_log_.entries(), 0,
+
+ net::CapturingNetLog::EntryList net_log_entries;
+ net_log_.GetEntries(&net_log_entries);
+ EXPECT_TRUE(LogContainsBeginEvent(net_log_entries, 0,
NetLog::TYPE_SOCKS5_CONNECT));
rv = callback_.WaitForResult();
EXPECT_EQ(OK, rv);
EXPECT_TRUE(user_sock_->IsConnected());
- EXPECT_TRUE(LogContainsEndEvent(net_log_.entries(), -1,
+ net_log_.GetEntries(&net_log_entries);
+ EXPECT_TRUE(LogContainsEndEvent(net_log_entries, -1,
NetLog::TYPE_SOCKS5_CONNECT));
}
@@ -299,12 +314,15 @@ TEST_F(SOCKS5ClientSocketTest, PartialReadWrites) {
hostname, 80, &net_log_));
int rv = user_sock_->Connect(&callback_);
EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_TRUE(LogContainsBeginEvent(net_log_.entries(), 0,
+ net::CapturingNetLog::EntryList net_log_entries;
+ net_log_.GetEntries(&net_log_entries);
+ EXPECT_TRUE(LogContainsBeginEvent(net_log_entries, 0,
NetLog::TYPE_SOCKS5_CONNECT));
rv = callback_.WaitForResult();
EXPECT_EQ(OK, rv);
EXPECT_TRUE(user_sock_->IsConnected());
- EXPECT_TRUE(LogContainsEndEvent(net_log_.entries(), -1,
+ net_log_.GetEntries(&net_log_entries);
+ EXPECT_TRUE(LogContainsEndEvent(net_log_entries, -1,
NetLog::TYPE_SOCKS5_CONNECT));
}
@@ -327,12 +345,15 @@ TEST_F(SOCKS5ClientSocketTest, PartialReadWrites) {
hostname, 80, &net_log_));
int rv = user_sock_->Connect(&callback_);
EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_TRUE(LogContainsBeginEvent(net_log_.entries(), 0,
+ net::CapturingNetLog::EntryList net_log_entries;
+ net_log_.GetEntries(&net_log_entries);
+ EXPECT_TRUE(LogContainsBeginEvent(net_log_entries, 0,
NetLog::TYPE_SOCKS5_CONNECT));
rv = callback_.WaitForResult();
EXPECT_EQ(OK, rv);
EXPECT_TRUE(user_sock_->IsConnected());
- EXPECT_TRUE(LogContainsEndEvent(net_log_.entries(), -1,
+ net_log_.GetEntries(&net_log_entries);
+ EXPECT_TRUE(LogContainsEndEvent(net_log_entries, -1,
NetLog::TYPE_SOCKS5_CONNECT));
}
}
diff --git a/net/socket/socks_client_socket.cc b/net/socket/socks_client_socket.cc
index fe3c015..47c654e 100644
--- a/net/socket/socks_client_socket.cc
+++ b/net/socket/socks_client_socket.cc
@@ -147,6 +147,10 @@ bool SOCKSClientSocket::IsConnectedAndIdle() const {
return completed_handshake_ && transport_->socket()->IsConnectedAndIdle();
}
+const BoundNetLog& SOCKSClientSocket::NetLog() const {
+ return net_log_;
+}
+
void SOCKSClientSocket::SetSubresourceSpeculation() {
if (transport_.get() && transport_->socket()) {
transport_->socket()->SetSubresourceSpeculation();
diff --git a/net/socket/socks_client_socket.h b/net/socket/socks_client_socket.h
index 653694e..a8fd04c 100644
--- a/net/socket/socks_client_socket.h
+++ b/net/socket/socks_client_socket.h
@@ -56,7 +56,7 @@ class SOCKSClientSocket : public ClientSocket {
virtual void Disconnect();
virtual bool IsConnected() const;
virtual bool IsConnectedAndIdle() const;
- virtual const BoundNetLog& NetLog() const { return net_log_; }
+ virtual const BoundNetLog& NetLog() const;
virtual void SetSubresourceSpeculation();
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
diff --git a/net/socket/socks_client_socket_pool.cc b/net/socket/socks_client_socket_pool.cc
index 5b419ba..f7f75b1 100644
--- a/net/socket/socks_client_socket_pool.cc
+++ b/net/socket/socks_client_socket_pool.cc
@@ -247,6 +247,10 @@ void SOCKSClientSocketPool::CloseIdleSockets() {
base_.CloseIdleSockets();
}
+int SOCKSClientSocketPool::IdleSocketCount() const {
+ return base_.idle_socket_count();
+}
+
int SOCKSClientSocketPool::IdleSocketCountInGroup(
const std::string& group_name) const {
return base_.IdleSocketCountInGroup(group_name);
@@ -272,4 +276,12 @@ DictionaryValue* SOCKSClientSocketPool::GetInfoAsValue(
return dict;
}
+base::TimeDelta SOCKSClientSocketPool::ConnectionTimeout() const {
+ return base_.ConnectionTimeout();
+}
+
+ClientSocketPoolHistograms* SOCKSClientSocketPool::histograms() const {
+ return base_.histograms();
+};
+
} // namespace net
diff --git a/net/socket/socks_client_socket_pool.h b/net/socket/socks_client_socket_pool.h
index 35b228e..fd19820 100644
--- a/net/socket/socks_client_socket_pool.h
+++ b/net/socket/socks_client_socket_pool.h
@@ -144,9 +144,7 @@ class SOCKSClientSocketPool : public ClientSocketPool {
virtual void CloseIdleSockets();
- virtual int IdleSocketCount() const {
- return base_.idle_socket_count();
- }
+ virtual int IdleSocketCount() const;
virtual int IdleSocketCountInGroup(const std::string& group_name) const;
@@ -157,13 +155,9 @@ class SOCKSClientSocketPool : public ClientSocketPool {
const std::string& type,
bool include_nested_pools) const;
- virtual base::TimeDelta ConnectionTimeout() const {
- return base_.ConnectionTimeout();
- }
+ virtual base::TimeDelta ConnectionTimeout() const;
- virtual ClientSocketPoolHistograms* histograms() const {
- return base_.histograms();
- };
+ virtual ClientSocketPoolHistograms* histograms() const;
private:
typedef ClientSocketPoolBase<SOCKSSocketParams> PoolBase;
diff --git a/net/socket/socks_client_socket_unittest.cc b/net/socket/socks_client_socket_unittest.cc
index 11a88ae..aa5338a 100644
--- a/net/socket/socks_client_socket_unittest.cc
+++ b/net/socket/socks_client_socket_unittest.cc
@@ -142,16 +142,20 @@ TEST_F(SOCKSClientSocketTest, CompleteHandshake) {
int rv = user_sock_->Connect(&callback_);
EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
EXPECT_TRUE(
- LogContainsBeginEvent(log.entries(), 0, NetLog::TYPE_SOCKS_CONNECT));
+ LogContainsBeginEvent(entries, 0, NetLog::TYPE_SOCKS_CONNECT));
EXPECT_FALSE(user_sock_->IsConnected());
- rv = callback_.WaitForResult();
+ rv = callback_.WaitForResult();
EXPECT_EQ(OK, rv);
EXPECT_TRUE(user_sock_->IsConnected());
EXPECT_EQ(SOCKSClientSocket::kSOCKS4, user_sock_->socks_version_);
+ log.GetEntries(&entries);
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), -1, NetLog::TYPE_SOCKS_CONNECT));
+ entries, -1, NetLog::TYPE_SOCKS_CONNECT));
scoped_refptr<IOBuffer> buffer(new IOBuffer(payload_write.size()));
memcpy(buffer->data(), payload_write.data(), payload_write.size());
@@ -208,14 +212,19 @@ TEST_F(SOCKSClientSocketTest, HandshakeFailures) {
int rv = user_sock_->Connect(&callback_);
EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 0, NetLog::TYPE_SOCKS_CONNECT));
+ entries, 0, NetLog::TYPE_SOCKS_CONNECT));
+
rv = callback_.WaitForResult();
EXPECT_EQ(tests[i].fail_code, rv);
EXPECT_FALSE(user_sock_->IsConnected());
EXPECT_TRUE(tcp_sock_->IsConnected());
+ log.GetEntries(&entries);
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), -1, NetLog::TYPE_SOCKS_CONNECT));
+ entries, -1, NetLog::TYPE_SOCKS_CONNECT));
}
}
@@ -240,13 +249,17 @@ TEST_F(SOCKSClientSocketTest, PartialServerReads) {
int rv = user_sock_->Connect(&callback_);
EXPECT_EQ(ERR_IO_PENDING, rv);
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 0, NetLog::TYPE_SOCKS_CONNECT));
+ entries, 0, NetLog::TYPE_SOCKS_CONNECT));
+
rv = callback_.WaitForResult();
EXPECT_EQ(OK, rv);
EXPECT_TRUE(user_sock_->IsConnected());
+ log.GetEntries(&entries);
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), -1, NetLog::TYPE_SOCKS_CONNECT));
+ entries, -1, NetLog::TYPE_SOCKS_CONNECT));
}
// Tests scenario when the client sends the handshake request in
@@ -274,13 +287,17 @@ TEST_F(SOCKSClientSocketTest, PartialClientWrites) {
int rv = user_sock_->Connect(&callback_);
EXPECT_EQ(ERR_IO_PENDING, rv);
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 0, NetLog::TYPE_SOCKS_CONNECT));
+ entries, 0, NetLog::TYPE_SOCKS_CONNECT));
+
rv = callback_.WaitForResult();
EXPECT_EQ(OK, rv);
EXPECT_TRUE(user_sock_->IsConnected());
+ log.GetEntries(&entries);
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), -1, NetLog::TYPE_SOCKS_CONNECT));
+ entries, -1, NetLog::TYPE_SOCKS_CONNECT));
}
// Tests the case when the server sends a smaller sized handshake data
@@ -302,13 +319,17 @@ TEST_F(SOCKSClientSocketTest, FailedSocketRead) {
int rv = user_sock_->Connect(&callback_);
EXPECT_EQ(ERR_IO_PENDING, rv);
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 0, NetLog::TYPE_SOCKS_CONNECT));
+ entries, 0, NetLog::TYPE_SOCKS_CONNECT));
+
rv = callback_.WaitForResult();
EXPECT_EQ(ERR_CONNECTION_CLOSED, rv);
EXPECT_FALSE(user_sock_->IsConnected());
+ log.GetEntries(&entries);
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), -1, NetLog::TYPE_SOCKS_CONNECT));
+ entries, -1, NetLog::TYPE_SOCKS_CONNECT));
}
// Tries to connect to an unknown DNS and on failure should revert to SOCKS4A.
@@ -335,14 +356,18 @@ TEST_F(SOCKSClientSocketTest, SOCKS4AFailedDNS) {
int rv = user_sock_->Connect(&callback_);
EXPECT_EQ(ERR_IO_PENDING, rv);
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 0, NetLog::TYPE_SOCKS_CONNECT));
+ entries, 0, NetLog::TYPE_SOCKS_CONNECT));
+
rv = callback_.WaitForResult();
EXPECT_EQ(OK, rv);
EXPECT_TRUE(user_sock_->IsConnected());
EXPECT_EQ(SOCKSClientSocket::kSOCKS4a, user_sock_->socks_version_);
+ log.GetEntries(&entries);
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), -1, NetLog::TYPE_SOCKS_CONNECT));
+ entries, -1, NetLog::TYPE_SOCKS_CONNECT));
}
// Tries to connect to a domain that resolves to IPv6.
@@ -371,14 +396,18 @@ TEST_F(SOCKSClientSocketTest, SOCKS4AIfDomainInIPv6) {
int rv = user_sock_->Connect(&callback_);
EXPECT_EQ(ERR_IO_PENDING, rv);
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
EXPECT_TRUE(LogContainsBeginEvent(
- log.entries(), 0, NetLog::TYPE_SOCKS_CONNECT));
+ entries, 0, NetLog::TYPE_SOCKS_CONNECT));
+
rv = callback_.WaitForResult();
EXPECT_EQ(OK, rv);
EXPECT_TRUE(user_sock_->IsConnected());
EXPECT_EQ(SOCKSClientSocket::kSOCKS4a, user_sock_->socks_version_);
+ log.GetEntries(&entries);
EXPECT_TRUE(LogContainsEndEvent(
- log.entries(), -1, NetLog::TYPE_SOCKS_CONNECT));
+ entries, -1, NetLog::TYPE_SOCKS_CONNECT));
}
// Calls Disconnect() while a host resolve is in progress. The outstanding host
diff --git a/net/socket/ssl_client_socket.cc b/net/socket/ssl_client_socket.cc
new file mode 100644
index 0000000..5635ad5
--- /dev/null
+++ b/net/socket/ssl_client_socket.cc
@@ -0,0 +1,62 @@
+// 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.
+
+#include "net/socket/ssl_client_socket.h"
+
+namespace net {
+
+SSLClientSocket::SSLClientSocket()
+ : was_npn_negotiated_(false),
+ was_spdy_negotiated_(false) {
+}
+
+SSLClientSocket::NextProto SSLClientSocket::NextProtoFromString(
+ const std::string& proto_string) {
+ if (proto_string == "http1.1" || proto_string == "http/1.1") {
+ return kProtoHTTP11;
+ } else if (proto_string == "spdy/1") {
+ return kProtoSPDY1;
+ } else if (proto_string == "spdy/2") {
+ return kProtoSPDY2;
+ } else {
+ return kProtoUnknown;
+ }
+}
+
+bool SSLClientSocket::IgnoreCertError(int error, int load_flags) {
+ if (error == OK || load_flags & LOAD_IGNORE_ALL_CERT_ERRORS)
+ return true;
+
+ if (error == ERR_CERT_COMMON_NAME_INVALID &&
+ (load_flags & LOAD_IGNORE_CERT_COMMON_NAME_INVALID))
+ return true;
+
+ if (error == ERR_CERT_DATE_INVALID &&
+ (load_flags & LOAD_IGNORE_CERT_DATE_INVALID))
+ return true;
+
+ if (error == ERR_CERT_AUTHORITY_INVALID &&
+ (load_flags & LOAD_IGNORE_CERT_AUTHORITY_INVALID))
+ return true;
+
+ return false;
+}
+
+bool SSLClientSocket::was_npn_negotiated() const {
+ return was_npn_negotiated_;
+}
+
+bool SSLClientSocket::set_was_npn_negotiated(bool negotiated) {
+ return was_npn_negotiated_ = negotiated;
+}
+
+bool SSLClientSocket::was_spdy_negotiated() const {
+ return was_spdy_negotiated_;
+}
+
+bool SSLClientSocket::set_was_spdy_negotiated(bool negotiated) {
+ return was_spdy_negotiated_ = negotiated;
+}
+
+} // namespace net
diff --git a/net/socket/ssl_client_socket.h b/net/socket/ssl_client_socket.h
index c3eb0da..0778e85 100644
--- a/net/socket/ssl_client_socket.h
+++ b/net/socket/ssl_client_socket.h
@@ -44,12 +44,14 @@ class DNSSECProvider {
//
class SSLClientSocket : public ClientSocket {
public:
- SSLClientSocket() : was_npn_negotiated_(false), was_spdy_negotiated_(false) {
- }
+ SSLClientSocket();
+
// Next Protocol Negotiation (NPN) allows a TLS client and server to come to
// an agreement about the application level protocol to speak over a
// connection.
enum NextProtoStatus {
+ // WARNING: These values are serialised to disk. Don't change them.
+
kNextProtoUnsupported = 0, // The server doesn't support NPN.
kNextProtoNegotiated = 1, // We agreed on a protocol.
kNextProtoNoOverlap = 2, // No protocols in common. We requested
@@ -84,52 +86,19 @@ class SSLClientSocket : public ClientSocket {
// supported list.
virtual NextProtoStatus GetNextProto(std::string* proto) = 0;
- static NextProto NextProtoFromString(const std::string& proto_string) {
- if (proto_string == "http1.1" || proto_string == "http/1.1") {
- return kProtoHTTP11;
- } else if (proto_string == "spdy/1") {
- return kProtoSPDY1;
- } else if (proto_string == "spdy/2") {
- return kProtoSPDY2;
- } else {
- return kProtoUnknown;
- }
- }
-
- static bool IgnoreCertError(int error, int load_flags) {
- if (error == OK || load_flags & LOAD_IGNORE_ALL_CERT_ERRORS)
- return true;
-
- if (error == ERR_CERT_COMMON_NAME_INVALID &&
- (load_flags & LOAD_IGNORE_CERT_COMMON_NAME_INVALID))
- return true;
- if(error == ERR_CERT_DATE_INVALID &&
- (load_flags & LOAD_IGNORE_CERT_DATE_INVALID))
- return true;
- if(error == ERR_CERT_AUTHORITY_INVALID &&
- (load_flags & LOAD_IGNORE_CERT_AUTHORITY_INVALID))
- return true;
-
- return false;
- }
-
- virtual bool was_npn_negotiated() const {
- return was_npn_negotiated_;
- }
-
- virtual bool set_was_npn_negotiated(bool negotiated) {
- return was_npn_negotiated_ = negotiated;
- }
+ static NextProto NextProtoFromString(const std::string& proto_string);
+
+ static bool IgnoreCertError(int error, int load_flags);
+
+ virtual bool was_npn_negotiated() const;
+
+ virtual bool set_was_npn_negotiated(bool negotiated);
virtual void UseDNSSEC(DNSSECProvider*) { }
- virtual bool was_spdy_negotiated() const {
- return was_spdy_negotiated_;
- }
+ virtual bool was_spdy_negotiated() const;
- virtual bool set_was_spdy_negotiated(bool negotiated) {
- return was_spdy_negotiated_ = negotiated;
- }
+ virtual bool set_was_spdy_negotiated(bool negotiated);
private:
// True if NPN was responded to, independent of selecting SPDY or HTTP.
diff --git a/net/socket/ssl_client_socket_mac.cc b/net/socket/ssl_client_socket_mac.cc
index 8b45592..e0753b9 100644
--- a/net/socket/ssl_client_socket_mac.cc
+++ b/net/socket/ssl_client_socket_mac.cc
@@ -13,9 +13,7 @@
#include "base/lazy_instance.h"
#include "base/mac/scoped_cftyperef.h"
-#include "base/singleton.h"
#include "base/string_util.h"
-#include "base/sys_info.h"
#include "net/base/address_list.h"
#include "net/base/cert_verifier.h"
#include "net/base/io_buffer.h"
@@ -142,27 +140,6 @@ enum {
};
#endif
-// On OS X 10.5.x, SSLHandshake() is broken with respect to renegotiation
-// handshakes, and the only way to advance the handshake state machine is
-// to use SSLRead(), which transparently re-handshakes and then reads
-// application data. Using SSLRead() to pump the handshake, rather than
-// SSLHandshake(), is not presently implemented, so on 10.5.x, SSL
-// renegotiation is disabled entirely. On 10.6.x, SSLHandshake() behaves as
-// expected/documented, so renegotiation is supported.
-struct RenegotiationBroken {
- RenegotiationBroken() : broken(false) {
- int32 major, minor, bugfix;
- base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix);
- if (major < 10 || (major == 10 && minor < 6))
- broken = true;
- }
-
- bool broken;
-};
-
-base::LazyInstance<RenegotiationBroken> g_renegotiation_broken(
- base::LINKER_INITIALIZED);
-
// For an explanation of the Mac OS X error codes, please refer to:
// http://developer.apple.com/mac/library/documentation/Security/Reference/secureTransportRef/Reference/reference.html
int NetErrorFromOSStatus(OSStatus status) {
@@ -498,7 +475,7 @@ class EnabledCipherSuites {
const std::vector<SSLCipherSuite>& ciphers() const { return ciphers_; }
private:
- friend struct DefaultSingletonTraits<EnabledCipherSuites>;
+ friend struct base::DefaultLazyInstanceTraits<EnabledCipherSuites>;
EnabledCipherSuites();
~EnabledCipherSuites() {}
@@ -507,6 +484,9 @@ class EnabledCipherSuites {
DISALLOW_COPY_AND_ASSIGN(EnabledCipherSuites);
};
+static base::LazyInstance<EnabledCipherSuites> g_enabled_cipher_suites(
+ base::LINKER_INITIALIZED);
+
EnabledCipherSuites::EnabledCipherSuites() {
SSLContextRef ssl_context;
OSStatus status = SSLNewContext(false, &ssl_context);
@@ -540,7 +520,8 @@ EnabledCipherSuites::EnabledCipherSuites() {
SSLClientSocketMac::SSLClientSocketMac(ClientSocketHandle* transport_socket,
const HostPortPair& host_and_port,
- const SSLConfig& ssl_config)
+ const SSLConfig& ssl_config,
+ CertVerifier* cert_verifier)
: handshake_io_callback_(this, &SSLClientSocketMac::OnHandshakeIOComplete),
transport_read_callback_(this,
&SSLClientSocketMac::OnTransportReadComplete),
@@ -555,6 +536,7 @@ SSLClientSocketMac::SSLClientSocketMac(ClientSocketHandle* transport_socket,
user_read_buf_len_(0),
user_write_buf_len_(0),
next_handshake_state_(STATE_NONE),
+ cert_verifier_(cert_verifier),
renegotiating_(false),
client_cert_requested_(false),
ssl_context_(NULL),
@@ -800,7 +782,7 @@ int SSLClientSocketMac::InitializeSSLContext() {
status = SSLSetProtocolVersionEnabled(ssl_context_,
kSSLProtocol2,
- ssl_config_.ssl2_enabled);
+ false);
if (status)
return NetErrorFromOSStatus(status);
@@ -817,7 +799,7 @@ int SSLClientSocketMac::InitializeSSLContext() {
return NetErrorFromOSStatus(status);
std::vector<SSLCipherSuite> enabled_ciphers =
- Singleton<EnabledCipherSuites>::get()->ciphers();
+ g_enabled_cipher_suites.Get().ciphers();
CipherSuiteIsDisabledFunctor is_disabled_cipher(
ssl_config_.disabled_cipher_suites);
@@ -1094,7 +1076,7 @@ int SSLClientSocketMac::DoVerifyCert() {
flags |= X509Certificate::VERIFY_REV_CHECKING_ENABLED;
if (ssl_config_.verify_ev_cert)
flags |= X509Certificate::VERIFY_EV_CERT;
- verifier_.reset(new CertVerifier);
+ verifier_.reset(new SingleRequestCertVerifier(cert_verifier_));
return verifier_->Verify(server_cert_, host_and_port_.host(), flags,
&server_cert_verify_result_,
&handshake_io_callback_);
@@ -1145,9 +1127,6 @@ int SSLClientSocketMac::DoPayloadRead() {
OSStatus status = SSLRead(ssl_context_, user_read_buf_->data(),
user_read_buf_len_, &processed);
if (status == errSSLWouldBlock && renegotiating_) {
- if (g_renegotiation_broken.Get().broken)
- return ERR_SSL_RENEGOTIATION_REQUESTED;
-
CHECK_EQ(static_cast<size_t>(0), processed);
next_handshake_state_ = STATE_HANDSHAKE;
return DoHandshakeLoop(OK);
diff --git a/net/socket/ssl_client_socket_mac.h b/net/socket/ssl_client_socket_mac.h
index 1e8d888..0a43e2f 100644
--- a/net/socket/ssl_client_socket_mac.h
+++ b/net/socket/ssl_client_socket_mac.h
@@ -23,6 +23,7 @@ namespace net {
class CertVerifier;
class ClientSocketHandle;
+class SingleRequestCertVerifier;
// An SSL client socket implemented with Secure Transport.
class SSLClientSocketMac : public SSLClientSocket {
@@ -35,7 +36,8 @@ class SSLClientSocketMac : public SSLClientSocket {
// the SSL settings.
SSLClientSocketMac(ClientSocketHandle* transport_socket,
const HostPortPair& host_and_port,
- const SSLConfig& ssl_config);
+ const SSLConfig& ssl_config,
+ CertVerifier* cert_verifier);
~SSLClientSocketMac();
// SSLClientSocket methods:
@@ -141,7 +143,8 @@ class SSLClientSocketMac : public SSLClientSocket {
State next_handshake_state_;
scoped_refptr<X509Certificate> server_cert_;
- scoped_ptr<CertVerifier> verifier_;
+ CertVerifier* const cert_verifier_;
+ scoped_ptr<SingleRequestCertVerifier> verifier_;
CertVerifyResult server_cert_verify_result_;
// The initial handshake has already completed, and the current handshake
diff --git a/net/socket/ssl_client_socket_mac_factory.cc b/net/socket/ssl_client_socket_mac_factory.cc
index bf732e6..211e2a4 100644
--- a/net/socket/ssl_client_socket_mac_factory.cc
+++ b/net/socket/ssl_client_socket_mac_factory.cc
@@ -14,9 +14,11 @@ SSLClientSocket* SSLClientSocketMacFactory(
const HostPortPair& host_and_port,
const SSLConfig& ssl_config,
SSLHostInfo* ssl_host_info,
+ CertVerifier* cert_verifier,
DnsCertProvenanceChecker* dns_cert_checker) {
delete ssl_host_info;
- return new SSLClientSocketMac(transport_socket, host_and_port, ssl_config);
+ return new SSLClientSocketMac(transport_socket, host_and_port, ssl_config,
+ cert_verifier);
}
} // namespace net
diff --git a/net/socket/ssl_client_socket_mac_factory.h b/net/socket/ssl_client_socket_mac_factory.h
index 5539136..ebda9c3 100644
--- a/net/socket/ssl_client_socket_mac_factory.h
+++ b/net/socket/ssl_client_socket_mac_factory.h
@@ -19,6 +19,7 @@ SSLClientSocket* SSLClientSocketMacFactory(
const HostPortPair& host_and_port,
const SSLConfig& ssl_config,
SSLHostInfo* ssl_host_info,
+ CertVerifier* cert_verifier,
DnsCertProvenanceChecker* dns_cert_checker);
} // namespace net
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
index 8a9d336..333fe67 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -65,7 +65,6 @@
#include "base/metrics/histogram.h"
#include "base/logging.h"
#include "base/nss_util.h"
-#include "base/singleton.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
@@ -88,6 +87,7 @@
#include "net/ocsp/nss_ocsp.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/dns_cert_provenance_checker.h"
+#include "net/socket/nss_ssl_util.h"
#include "net/socket/ssl_error_params.h"
#include "net/socket/ssl_host_info.h"
@@ -139,180 +139,6 @@ namespace net {
namespace {
-class NSSSSLInitSingleton {
- public:
- NSSSSLInitSingleton() {
- base::EnsureNSSInit();
-
- NSS_SetDomesticPolicy();
-
-#if defined(USE_SYSTEM_SSL)
- // Use late binding to avoid scary but benign warning
- // "Symbol `SSL_ImplementedCiphers' has different size in shared object,
- // consider re-linking"
- // TODO(wtc): Use the new SSL_GetImplementedCiphers and
- // SSL_GetNumImplementedCiphers functions when we require NSS 3.12.6.
- // See https://bugzilla.mozilla.org/show_bug.cgi?id=496993.
- const PRUint16* pSSL_ImplementedCiphers = static_cast<const PRUint16*>(
- dlsym(RTLD_DEFAULT, "SSL_ImplementedCiphers"));
- if (pSSL_ImplementedCiphers == NULL) {
- NOTREACHED() << "Can't get list of supported ciphers";
- return;
- }
-#else
-#define pSSL_ImplementedCiphers SSL_ImplementedCiphers
-#endif
-
- // Explicitly enable exactly those ciphers with keys of at least 80 bits
- for (int i = 0; i < SSL_NumImplementedCiphers; i++) {
- SSLCipherSuiteInfo info;
- if (SSL_GetCipherSuiteInfo(pSSL_ImplementedCiphers[i], &info,
- sizeof(info)) == SECSuccess) {
- SSL_CipherPrefSetDefault(pSSL_ImplementedCiphers[i],
- (info.effectiveKeyBits >= 80));
- }
- }
-
- // Enable SSL.
- SSL_OptionSetDefault(SSL_SECURITY, PR_TRUE);
-
- // All other SSL options are set per-session by SSLClientSocket.
- }
-
- ~NSSSSLInitSingleton() {
- // Have to clear the cache, or NSS_Shutdown fails with SEC_ERROR_BUSY.
- SSL_ClearSessionCache();
- }
-};
-
-// Initialize the NSS SSL library if it isn't already initialized. This must
-// be called before any other NSS SSL functions. This function is
-// thread-safe, and the NSS SSL library will only ever be initialized once.
-// The NSS SSL library will be properly shut down on program exit.
-void EnsureNSSSSLInit() {
- // Initializing SSL causes us to do blocking IO.
- // Temporarily allow it until we fix
- // http://code.google.com/p/chromium/issues/detail?id=59847
- base::ThreadRestrictions::ScopedAllowIO allow_io;
-
- Singleton<NSSSSLInitSingleton>::get();
-}
-
-// The default error mapping function.
-// Maps an NSPR error code to a network error code.
-int MapNSPRError(PRErrorCode err) {
- // TODO(port): fill this out as we learn what's important
- switch (err) {
- case PR_WOULD_BLOCK_ERROR:
- return ERR_IO_PENDING;
- case PR_ADDRESS_NOT_SUPPORTED_ERROR: // For connect.
- case PR_NO_ACCESS_RIGHTS_ERROR:
- return ERR_ACCESS_DENIED;
- case PR_IO_TIMEOUT_ERROR:
- return ERR_TIMED_OUT;
- case PR_CONNECT_RESET_ERROR:
- return ERR_CONNECTION_RESET;
- case PR_CONNECT_ABORTED_ERROR:
- return ERR_CONNECTION_ABORTED;
- case PR_CONNECT_REFUSED_ERROR:
- return ERR_CONNECTION_REFUSED;
- case PR_HOST_UNREACHABLE_ERROR:
- case PR_NETWORK_UNREACHABLE_ERROR:
- return ERR_ADDRESS_UNREACHABLE;
- case PR_ADDRESS_NOT_AVAILABLE_ERROR:
- return ERR_ADDRESS_INVALID;
- case PR_INVALID_ARGUMENT_ERROR:
- return ERR_INVALID_ARGUMENT;
- case PR_END_OF_FILE_ERROR:
- return ERR_CONNECTION_CLOSED;
- case PR_NOT_IMPLEMENTED_ERROR:
- return ERR_NOT_IMPLEMENTED;
-
- case SEC_ERROR_INVALID_ARGS:
- return ERR_INVALID_ARGUMENT;
-
- case SSL_ERROR_SSL_DISABLED:
- return ERR_NO_SSL_VERSIONS_ENABLED;
- case SSL_ERROR_NO_CYPHER_OVERLAP:
- case SSL_ERROR_UNSUPPORTED_VERSION:
- return ERR_SSL_VERSION_OR_CIPHER_MISMATCH;
- case SSL_ERROR_HANDSHAKE_FAILURE_ALERT:
- case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT:
- case SSL_ERROR_ILLEGAL_PARAMETER_ALERT:
- return ERR_SSL_PROTOCOL_ERROR;
- case SSL_ERROR_DECOMPRESSION_FAILURE_ALERT:
- return ERR_SSL_DECOMPRESSION_FAILURE_ALERT;
- case SSL_ERROR_BAD_MAC_ALERT:
- return ERR_SSL_BAD_RECORD_MAC_ALERT;
- case SSL_ERROR_UNSAFE_NEGOTIATION:
- return ERR_SSL_UNSAFE_NEGOTIATION;
- case SSL_ERROR_WEAK_SERVER_KEY:
- return ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY;
-
- default: {
- if (IS_SSL_ERROR(err)) {
- LOG(WARNING) << "Unknown SSL error " << err <<
- " mapped to net::ERR_SSL_PROTOCOL_ERROR";
- return ERR_SSL_PROTOCOL_ERROR;
- }
- LOG(WARNING) << "Unknown error " << err <<
- " mapped to net::ERR_FAILED";
- return ERR_FAILED;
- }
- }
-}
-
-// Context-sensitive error mapping functions.
-
-int MapHandshakeError(PRErrorCode err) {
- switch (err) {
- // If the server closed on us, it is a protocol error.
- // Some TLS-intolerant servers do this when we request TLS.
- case PR_END_OF_FILE_ERROR:
- // The handshake may fail because some signature (for example, the
- // signature in the ServerKeyExchange message for an ephemeral
- // Diffie-Hellman cipher suite) is invalid.
- case SEC_ERROR_BAD_SIGNATURE:
- return ERR_SSL_PROTOCOL_ERROR;
- default:
- return MapNSPRError(err);
- }
-}
-
-// Extra parameters to attach to the NetLog when we receive an error in response
-// to a call to an NSS function. Used instead of SSLErrorParams with
-// events of type TYPE_SSL_NSS_ERROR. Automatically looks up last PR error.
-class SSLFailedNSSFunctionParams : public NetLog::EventParameters {
- public:
- // |param| is ignored if it has a length of 0.
- SSLFailedNSSFunctionParams(const std::string& function,
- const std::string& param)
- : function_(function), param_(param), ssl_lib_error_(PR_GetError()) {
- }
-
- virtual Value* ToValue() const {
- DictionaryValue* dict = new DictionaryValue();
- dict->SetString("function", function_);
- if (!param_.empty())
- dict->SetString("param", param_);
- dict->SetInteger("ssl_lib_error", ssl_lib_error_);
- return dict;
- }
-
- private:
- const std::string function_;
- const std::string param_;
- const PRErrorCode ssl_lib_error_;
-};
-
-void LogFailedNSSFunction(const BoundNetLog& net_log,
- const char* function,
- const char* param) {
- net_log.AddEvent(
- NetLog::TYPE_SSL_NSS_ERROR,
- make_scoped_refptr(new SSLFailedNSSFunctionParams(function, param)));
-}
-
#if defined(OS_WIN)
// This callback is intended to be used with CertFindChainInStore. In addition
@@ -405,6 +231,7 @@ SSLClientSocketNSS::SSLClientSocketNSS(ClientSocketHandle* transport_socket,
const HostPortPair& host_and_port,
const SSLConfig& ssl_config,
SSLHostInfo* ssl_host_info,
+ CertVerifier* cert_verifier,
DnsCertProvenanceChecker* dns_ctx)
: ALLOW_THIS_IN_INITIALIZER_LIST(buffer_send_callback_(
this, &SSLClientSocketNSS::BufferSendComplete)),
@@ -427,6 +254,7 @@ SSLClientSocketNSS::SSLClientSocketNSS(ClientSocketHandle* transport_socket,
server_cert_verify_result_(NULL),
ssl_connection_status_(0),
client_auth_cert_needed_(false),
+ cert_verifier_(cert_verifier),
handshake_callback_called_(false),
completed_handshake_(false),
pseudo_connected_(false),
@@ -476,6 +304,11 @@ void SSLClientSocketNSS::SaveSnapStartInfo() {
if (!ssl_host_info_.get())
return;
+ // If the SSLHostInfo hasn't managed to load from disk yet then we can't save
+ // anything.
+ if (ssl_host_info_->WaitForDataReady(NULL) != OK)
+ return;
+
SECStatus rv;
SSLSnapStartResult snap_start_type;
rv = SSL_GetSnapStartResult(nss_fd_, &snap_start_type);
@@ -485,8 +318,6 @@ void SSLClientSocketNSS::SaveSnapStartInfo() {
}
net_log_.AddEvent(NetLog::TYPE_SSL_SNAP_START,
new NetLogIntegerParameter("type", snap_start_type));
- LOG(ERROR) << "Snap Start: " << snap_start_type << " "
- << host_and_port_.ToString();
if (snap_start_type == SSL_SNAP_START_FULL ||
snap_start_type == SSL_SNAP_START_RESUME) {
// If we did a successful Snap Start then our information was correct and
@@ -504,14 +335,13 @@ void SSLClientSocketNSS::SaveSnapStartInfo() {
if (hello_data_len > std::numeric_limits<uint16>::max())
return;
SSLHostInfo::State* state = ssl_host_info_->mutable_state();
+ state->server_hello =
+ std::string(reinterpret_cast<const char *>(hello_data), hello_data_len);
if (hello_data_len > 0) {
- state->server_hello =
- std::string(reinterpret_cast<const char *>(hello_data), hello_data_len);
state->npn_valid = true;
state->npn_status = GetNextProto(&state->npn_protocol);
} else {
- state->server_hello.clear();
state->npn_valid = false;
}
@@ -526,7 +356,6 @@ void SSLClientSocketNSS::SaveSnapStartInfo() {
certs[i]->derCert.len));
}
- LOG(ERROR) << "Setting Snap Start info " << host_and_port_.ToString();
ssl_host_info_->Persist();
}
@@ -694,19 +523,14 @@ int SSLClientSocketNSS::InitializeSSLOptions() {
return ERR_UNEXPECTED;
}
- rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SSL2, ssl_config_.ssl2_enabled);
+ rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SSL2, PR_FALSE);
if (rv != SECSuccess) {
LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_ENABLE_SSL2");
return ERR_UNEXPECTED;
}
- // SNI is enabled automatically if TLS is enabled -- as long as
- // SSL_V2_COMPATIBLE_HELLO isn't.
- // So don't do V2 compatible hellos unless we're really using SSL2,
- // to avoid errors like
- // "common name `mail.google.com' != requested host name `gmail.com'"
- rv = SSL_OptionSet(nss_fd_, SSL_V2_COMPATIBLE_HELLO,
- ssl_config_.ssl2_enabled);
+ // Don't do V2 compatible hellos because they don't support TLS extensions.
+ rv = SSL_OptionSet(nss_fd_, SSL_V2_COMPATIBLE_HELLO, PR_FALSE);
if (rv != SECSuccess) {
LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_V2_COMPATIBLE_HELLO");
return ERR_UNEXPECTED;
@@ -743,6 +567,13 @@ int SSLClientSocketNSS::InitializeSSLOptions() {
#error "You need to install NSS-3.12 or later to build chromium"
#endif
+ rv = SSL_OptionSet(nss_fd_, SSL_NO_CACHE,
+ ssl_config_.session_resume_disabled);
+ if (rv != SECSuccess) {
+ LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_NO_CACHE");
+ return ERR_UNEXPECTED;
+ }
+
#ifdef SSL_ENABLE_DEFLATE
// Some web servers have been found to break if TLS is used *or* if DEFLATE
// is advertised. Thus, if TLS is disabled (probably because we are doing
@@ -919,6 +750,7 @@ void SSLClientSocketNSS::Disconnect() {
completed_handshake_ = false;
pseudo_connected_ = false;
eset_mitm_detected_ = false;
+ start_cert_verification_time_ = base::TimeTicks();
predicted_cert_chain_correct_ = false;
peername_initialized_ = false;
nss_bufs_ = NULL;
@@ -962,6 +794,10 @@ int SSLClientSocketNSS::GetPeerAddress(AddressList* address) const {
return transport_->socket()->GetPeerAddress(address);
}
+const BoundNetLog& SSLClientSocketNSS::NetLog() const {
+ return net_log_;
+}
+
void SSLClientSocketNSS::SetSubresourceSpeculation() {
if (transport_.get() && transport_->socket()) {
transport_->socket()->SetSubresourceSpeculation();
@@ -1365,46 +1201,6 @@ void SSLClientSocketNSS::OnRecvComplete(int result) {
LeaveFunction("");
}
-// Map a Chromium net error code to an NSS error code.
-// See _MD_unix_map_default_error in the NSS source
-// tree for inspiration.
-static PRErrorCode MapErrorToNSS(int result) {
- if (result >=0)
- return result;
-
- switch (result) {
- case ERR_IO_PENDING:
- return PR_WOULD_BLOCK_ERROR;
- case ERR_ACCESS_DENIED:
- case ERR_NETWORK_ACCESS_DENIED:
- // For connect, this could be mapped to PR_ADDRESS_NOT_SUPPORTED_ERROR.
- return PR_NO_ACCESS_RIGHTS_ERROR;
- case ERR_NOT_IMPLEMENTED:
- return PR_NOT_IMPLEMENTED_ERROR;
- case ERR_INTERNET_DISCONNECTED: // Equivalent to ENETDOWN.
- return PR_NETWORK_UNREACHABLE_ERROR; // Best approximation.
- case ERR_CONNECTION_TIMED_OUT:
- case ERR_TIMED_OUT:
- return PR_IO_TIMEOUT_ERROR;
- case ERR_CONNECTION_RESET:
- return PR_CONNECT_RESET_ERROR;
- case ERR_CONNECTION_ABORTED:
- return PR_CONNECT_ABORTED_ERROR;
- case ERR_CONNECTION_REFUSED:
- return PR_CONNECT_REFUSED_ERROR;
- case ERR_ADDRESS_UNREACHABLE:
- return PR_HOST_UNREACHABLE_ERROR; // Also PR_NETWORK_UNREACHABLE_ERROR.
- case ERR_ADDRESS_INVALID:
- return PR_ADDRESS_NOT_AVAILABLE_ERROR;
- case ERR_NAME_NOT_RESOLVED:
- return PR_DIRECTORY_LOOKUP_ERROR;
- default:
- LOG(WARNING) << "MapErrorToNSS " << result
- << " mapped to PR_UNKNOWN_ERROR";
- return PR_UNKNOWN_ERROR;
- }
-}
-
// Do network I/O between the given buffer and the given socket.
// Return true if some I/O performed, false otherwise (error or ERR_IO_PENDING)
bool SSLClientSocketNSS::DoTransportIO() {
@@ -1648,7 +1444,8 @@ SECStatus SSLClientSocketNSS::OwnAuthCertHandler(void* arg,
if (common_name) {
if (strcmp(common_name, "ESET_RootSslCert") == 0)
that->eset_mitm_detected_ = true;
- if (strcmp(common_name, "ContentWatch Root Certificate Authority") == 0) {
+ if (strcmp(common_name,
+ "ContentWatch Root Certificate Authority") == 0) {
// This is NetNanny. NetNanny are updating their product so we
// silently disable False Start for now.
rv = SSL_OptionSet(socket, SSL_ENABLE_FALSE_START, PR_FALSE);
@@ -2192,7 +1989,7 @@ int SSLClientSocketNSS::DoHandshake() {
}
} else {
PRErrorCode prerr = PR_GetError();
- net_error = MapHandshakeError(prerr);
+ net_error = MapNSSHandshakeError(prerr);
// If not done, stay in this state
if (net_error == ERR_IO_PENDING) {
@@ -2443,6 +2240,7 @@ int SSLClientSocketNSS::DoVerifyCert(int result) {
DCHECK(server_cert_);
GotoState(STATE_VERIFY_CERT_COMPLETE);
+ start_cert_verification_time_ = base::TimeTicks::Now();
if (ssl_host_info_.get() && !ssl_host_info_->state().certs.empty() &&
predicted_cert_chain_correct_) {
@@ -2452,9 +2250,11 @@ int SSLClientSocketNSS::DoVerifyCert(int result) {
// verification to finish rather than start our own.
net_log_.AddEvent(NetLog::TYPE_SSL_VERIFICATION_MERGED, NULL);
UMA_HISTOGRAM_ENUMERATION("Net.SSLVerificationMerged", 1 /* true */, 2);
- base::TimeTicks now = base::TimeTicks::Now();
+ base::TimeTicks end_time = ssl_host_info_->verification_end_time();
+ if (end_time.is_null())
+ end_time = base::TimeTicks::Now();
UMA_HISTOGRAM_TIMES("Net.SSLVerificationMergedMsSaved",
- now - ssl_host_info_->verification_start_time());
+ end_time - ssl_host_info_->verification_start_time());
server_cert_verify_result_ = &ssl_host_info_->cert_verify_result();
return ssl_host_info_->WaitForCertVerification(&handshake_io_callback_);
} else {
@@ -2466,7 +2266,7 @@ int SSLClientSocketNSS::DoVerifyCert(int result) {
flags |= X509Certificate::VERIFY_REV_CHECKING_ENABLED;
if (ssl_config_.verify_ev_cert)
flags |= X509Certificate::VERIFY_EV_CERT;
- verifier_.reset(new CertVerifier);
+ verifier_.reset(new SingleRequestCertVerifier(cert_verifier_));
server_cert_verify_result_ = &local_server_cert_verify_result_;
return verifier_->Verify(server_cert_, host_and_port_.host(), flags,
&local_server_cert_verify_result_,
@@ -2478,6 +2278,16 @@ int SSLClientSocketNSS::DoVerifyCert(int result) {
int SSLClientSocketNSS::DoVerifyCertComplete(int result) {
verifier_.reset();
+
+ if (!start_cert_verification_time_.is_null()) {
+ base::TimeDelta verify_time =
+ base::TimeTicks::Now() - start_cert_verification_time_;
+ if (result == OK)
+ UMA_HISTOGRAM_TIMES("Net.SSLCertVerificationTime", verify_time);
+ else
+ UMA_HISTOGRAM_TIMES("Net.SSLCertVerificationTimeError", verify_time);
+ }
+
// We used to remember the intermediate CA certs in the NSS database
// persistently. However, NSS opens a connection to the SQLite database
// during NSS initialization and doesn't close the connection until NSS
@@ -2568,7 +2378,7 @@ int SSLClientSocketNSS::DoPayloadRead() {
return ERR_IO_PENDING;
}
LeaveFunction("");
- rv = MapNSPRError(prerr);
+ rv = MapNSSError(prerr);
net_log_.AddEvent(NetLog::TYPE_SSL_READ_ERROR,
make_scoped_refptr(new SSLErrorParams(rv, prerr)));
return rv;
@@ -2589,7 +2399,7 @@ int SSLClientSocketNSS::DoPayloadWrite() {
return ERR_IO_PENDING;
}
LeaveFunction("");
- rv = MapNSPRError(prerr);
+ rv = MapNSSError(prerr);
net_log_.AddEvent(NetLog::TYPE_SSL_WRITE_ERROR,
make_scoped_refptr(new SSLErrorParams(rv, prerr)));
return rv;
diff --git a/net/socket/ssl_client_socket_nss.h b/net/socket/ssl_client_socket_nss.h
index 6f291b3..6389db8 100644
--- a/net/socket/ssl_client_socket_nss.h
+++ b/net/socket/ssl_client_socket_nss.h
@@ -32,6 +32,7 @@ class BoundNetLog;
class CertVerifier;
class ClientSocketHandle;
class DnsCertProvenanceChecker;
+class SingleRequestCertVerifier;
class SSLHostInfo;
class X509Certificate;
@@ -48,6 +49,7 @@ class SSLClientSocketNSS : public SSLClientSocket {
const HostPortPair& host_and_port,
const SSLConfig& ssl_config,
SSLHostInfo* ssl_host_info,
+ CertVerifier* cert_verifier,
DnsCertProvenanceChecker* dnsrr_resolver);
~SSLClientSocketNSS();
@@ -67,7 +69,7 @@ class SSLClientSocketNSS : public SSLClientSocket {
virtual bool IsConnected() const;
virtual bool IsConnectedAndIdle() const;
virtual int GetPeerAddress(AddressList* address) const;
- virtual const BoundNetLog& NetLog() const { return net_log_; }
+ virtual const BoundNetLog& NetLog() const;
virtual void SetSubresourceSpeculation();
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
@@ -197,7 +199,8 @@ class SSLClientSocketNSS : public SSLClientSocket {
std::vector<scoped_refptr<X509Certificate> > client_certs_;
bool client_auth_cert_needed_;
- scoped_ptr<CertVerifier> verifier_;
+ CertVerifier* const cert_verifier_;
+ scoped_ptr<SingleRequestCertVerifier> verifier_;
// True if NSS has called HandshakeCallback.
bool handshake_callback_called_;
@@ -253,6 +256,8 @@ class SSLClientSocketNSS : public SSLClientSocket {
std::string predicted_npn_proto_;
bool predicted_npn_proto_used_;
+ base::TimeTicks start_cert_verification_time_;
+
scoped_ptr<SSLHostInfo> ssl_host_info_;
DnsCertProvenanceChecker* const dns_cert_checker_;
};
diff --git a/net/socket/ssl_client_socket_nss_factory.cc b/net/socket/ssl_client_socket_nss_factory.cc
index e4c01f0..435ddff 100644
--- a/net/socket/ssl_client_socket_nss_factory.cc
+++ b/net/socket/ssl_client_socket_nss_factory.cc
@@ -19,10 +19,11 @@ SSLClientSocket* SSLClientSocketNSSFactory(
const HostPortPair& host_and_port,
const SSLConfig& ssl_config,
SSLHostInfo* ssl_host_info,
+ CertVerifier* cert_verifier,
DnsCertProvenanceChecker* dns_cert_checker) {
scoped_ptr<SSLHostInfo> shi(ssl_host_info);
return new SSLClientSocketNSS(transport_socket, host_and_port, ssl_config,
- shi.release(), dns_cert_checker);
+ shi.release(), cert_verifier, dns_cert_checker);
}
} // namespace net
diff --git a/net/socket/ssl_client_socket_nss_factory.h b/net/socket/ssl_client_socket_nss_factory.h
index 15b05b2..ed5e588 100644
--- a/net/socket/ssl_client_socket_nss_factory.h
+++ b/net/socket/ssl_client_socket_nss_factory.h
@@ -19,6 +19,7 @@ SSLClientSocket* SSLClientSocketNSSFactory(
const HostPortPair& host_and_port,
const SSLConfig& ssl_config,
SSLHostInfo* ssl_host_info,
+ CertVerifier* cert_verifier,
DnsCertProvenanceChecker* dns_cert_checker);
} // namespace net
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc
index f80b21c..8bef0ef 100644
--- a/net/socket/ssl_client_socket_openssl.cc
+++ b/net/socket/ssl_client_socket_openssl.cc
@@ -19,8 +19,11 @@
#include "base/singleton.h"
#include "net/base/cert_verifier.h"
#include "net/base/net_errors.h"
+#include "net/base/openssl_private_key_store.h"
+#include "net/base/ssl_cert_request_info.h"
#include "net/base/ssl_connection_status_flags.h"
#include "net/base/ssl_info.h"
+#include "net/socket/ssl_error_params.h"
namespace net {
@@ -39,7 +42,140 @@ const size_t kMaxRecvBufferSize = 4096;
const int kSessionCacheTimeoutSeconds = 60 * 60;
const size_t kSessionCacheMaxEntires = 1024;
-int MapOpenSSLError(int err) {
+// This method doesn't seemed to have made it into the OpenSSL headers.
+unsigned long SSL_CIPHER_get_id(const SSL_CIPHER* cipher) { return cipher->id; }
+
+// Used for encoding the |connection_status| field of an SSLInfo object.
+int EncodeSSLConnectionStatus(int cipher_suite,
+ int compression,
+ int version) {
+ return ((cipher_suite & SSL_CONNECTION_CIPHERSUITE_MASK) <<
+ SSL_CONNECTION_CIPHERSUITE_SHIFT) |
+ ((compression & SSL_CONNECTION_COMPRESSION_MASK) <<
+ SSL_CONNECTION_COMPRESSION_SHIFT) |
+ ((version & SSL_CONNECTION_VERSION_MASK) <<
+ SSL_CONNECTION_VERSION_SHIFT);
+}
+
+// Returns the net SSL version number (see ssl_connection_status_flags.h) for
+// this SSL connection.
+int GetNetSSLVersion(SSL* ssl) {
+ switch (SSL_version(ssl)) {
+ case SSL2_VERSION:
+ return SSL_CONNECTION_VERSION_SSL2;
+ case SSL3_VERSION:
+ return SSL_CONNECTION_VERSION_SSL3;
+ case TLS1_VERSION:
+ return SSL_CONNECTION_VERSION_TLS1;
+ case 0x0302:
+ return SSL_CONNECTION_VERSION_TLS1_1;
+ case 0x0303:
+ return SSL_CONNECTION_VERSION_TLS1_2;
+ default:
+ return SSL_CONNECTION_VERSION_UNKNOWN;
+ }
+}
+
+int MapOpenSSLErrorSSL() {
+ // Walk down the error stack to find the SSLerr generated reason.
+ unsigned long error_code;
+ do {
+ error_code = ERR_get_error();
+ if (error_code == 0)
+ return ERR_SSL_PROTOCOL_ERROR;
+ } while (ERR_GET_LIB(error_code) != ERR_LIB_SSL);
+
+ DVLOG(1) << "OpenSSL SSL error, reason: " << ERR_GET_REASON(error_code)
+ << ", name: " << ERR_error_string(error_code, NULL);
+ switch (ERR_GET_REASON(error_code)) {
+ case SSL_R_READ_TIMEOUT_EXPIRED:
+ return ERR_TIMED_OUT;
+ case SSL_R_BAD_RESPONSE_ARGUMENT:
+ return ERR_INVALID_ARGUMENT;
+ case SSL_R_UNKNOWN_CERTIFICATE_TYPE:
+ case SSL_R_UNKNOWN_CIPHER_TYPE:
+ case SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE:
+ case SSL_R_UNKNOWN_PKEY_TYPE:
+ case SSL_R_UNKNOWN_REMOTE_ERROR_TYPE:
+ case SSL_R_UNKNOWN_SSL_VERSION:
+ return ERR_NOT_IMPLEMENTED;
+ case SSL_R_UNSUPPORTED_SSL_VERSION:
+ case SSL_R_NO_CIPHER_MATCH:
+ case SSL_R_NO_SHARED_CIPHER:
+ case SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY:
+ case SSL_R_TLSV1_ALERT_PROTOCOL_VERSION:
+ return ERR_SSL_VERSION_OR_CIPHER_MISMATCH;
+ case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE:
+ case SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE:
+ case SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED:
+ case SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED:
+ case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN:
+ case SSL_R_TLSV1_ALERT_ACCESS_DENIED:
+ case SSL_R_TLSV1_ALERT_UNKNOWN_CA:
+ return ERR_BAD_SSL_CLIENT_AUTH_CERT;
+ case SSL_R_BAD_DECOMPRESSION:
+ case SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE:
+ return ERR_SSL_DECOMPRESSION_FAILURE_ALERT;
+ case SSL_R_SSLV3_ALERT_BAD_RECORD_MAC:
+ return ERR_SSL_BAD_RECORD_MAC_ALERT;
+ case SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED:
+ return ERR_SSL_UNSAFE_NEGOTIATION;
+ case SSL_R_WRONG_NUMBER_OF_KEY_BITS:
+ return ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY;
+ // SSL_R_UNKNOWN_PROTOCOL is reported if premature application data is
+ // received (see http://crbug.com/42538), and also if all the protocol
+ // versions supported by the server were disabled in this socket instance.
+ // Mapped to ERR_SSL_PROTOCOL_ERROR for compatibility with other SSL sockets
+ // in the former scenario.
+ case SSL_R_UNKNOWN_PROTOCOL:
+ case SSL_R_SSL_HANDSHAKE_FAILURE:
+ case SSL_R_DECRYPTION_FAILED:
+ case SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC:
+ case SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG:
+ case SSL_R_DIGEST_CHECK_FAILED:
+ case SSL_R_DUPLICATE_COMPRESSION_ID:
+ case SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER:
+ case SSL_R_ENCRYPTED_LENGTH_TOO_LONG:
+ case SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST:
+ case SSL_R_EXCESSIVE_MESSAGE_SIZE:
+ case SSL_R_EXTRA_DATA_IN_MESSAGE:
+ case SSL_R_GOT_A_FIN_BEFORE_A_CCS:
+ case SSL_R_ILLEGAL_PADDING:
+ case SSL_R_INVALID_CHALLENGE_LENGTH:
+ case SSL_R_INVALID_COMMAND:
+ case SSL_R_INVALID_PURPOSE:
+ case SSL_R_INVALID_STATUS_RESPONSE:
+ case SSL_R_INVALID_TICKET_KEYS_LENGTH:
+ case SSL_R_KEY_ARG_TOO_LONG:
+ case SSL_R_READ_WRONG_PACKET_TYPE:
+ case SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE:
+ // TODO(joth): SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE may be returned from the
+ // server after receiving ClientHello if there's no common supported cipher.
+ // Ideally we'd map that specific case to ERR_SSL_VERSION_OR_CIPHER_MISMATCH
+ // to match the NSS implementation. See also http://goo.gl/oMtZW
+ case SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE:
+ case SSL_R_SSLV3_ALERT_NO_CERTIFICATE:
+ case SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER:
+ case SSL_R_TLSV1_ALERT_DECODE_ERROR:
+ case SSL_R_TLSV1_ALERT_DECRYPTION_FAILED:
+ case SSL_R_TLSV1_ALERT_DECRYPT_ERROR:
+ case SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION:
+ case SSL_R_TLSV1_ALERT_INTERNAL_ERROR:
+ case SSL_R_TLSV1_ALERT_NO_RENEGOTIATION:
+ case SSL_R_TLSV1_ALERT_RECORD_OVERFLOW:
+ case SSL_R_TLSV1_ALERT_USER_CANCELLED:
+ return ERR_SSL_PROTOCOL_ERROR;
+ default:
+ LOG(WARNING) << "Unmapped error reason: " << ERR_GET_REASON(error_code);
+ return ERR_FAILED;
+ }
+}
+
+// Converts an OpenSSL error code into a net error code, walking the OpenSSL
+// error stack if needed. Note that |tracer| is not currently used in the
+// implementation, but is passed in anyway as this ensures the caller will clear
+// any residual codes left on the error stack.
+int MapOpenSSLError(int err, const base::OpenSSLErrStackTracer& tracer) {
switch (err) {
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
@@ -47,6 +183,8 @@ int MapOpenSSLError(int err) {
case SSL_ERROR_SYSCALL:
DVLOG(1) << "OpenSSL SYSCALL error, errno " << errno;
return ERR_SSL_PROTOCOL_ERROR;
+ case SSL_ERROR_SSL:
+ return MapOpenSSLErrorSSL();
default:
// TODO(joth): Implement full mapping.
LOG(WARNING) << "Unknown OpenSSL error " << err;
@@ -130,7 +268,7 @@ class SSLSessionCache {
private:
// A pair of maps to allow bi-directional lookups between host:port and an
- // associated seesion.
+ // associated session.
// TODO(joth): When client certificates are implemented we should key the
// cache on the client certificate used in addition to the host-port pair.
typedef std::map<HostPortPair, SSL_SESSION*> HostPortMap;
@@ -146,7 +284,7 @@ class SSLSessionCache {
class SSLContext {
public:
- static SSLContext* Get() { return Singleton<SSLContext>::get(); }
+ static SSLContext* GetInstance() { return Singleton<SSLContext>::get(); }
SSL_CTX* ssl_ctx() { return ssl_ctx_.get(); }
SSLSessionCache* session_cache() { return &session_cache_; }
@@ -176,7 +314,11 @@ class SSLContext {
SSL_CTX_sess_set_remove_cb(ssl_ctx_.get(), RemoveSessionCallbackStatic);
SSL_CTX_set_timeout(ssl_ctx_.get(), kSessionCacheTimeoutSeconds);
SSL_CTX_sess_set_cache_size(ssl_ctx_.get(), kSessionCacheMaxEntires);
+<<<<<<< HEAD
#ifdef ANDROID
+=======
+ SSL_CTX_set_client_cert_cb(ssl_ctx_.get(), ClientCertCallback);
+>>>>>>> chromium.org at r10.0.621.0
#if defined(OPENSSL_NPN_NEGOTIATED)
// TODO(kristianm): Only select this if ssl_config_.next_proto is not empty.
// It would be better if the callback were not a global setting,
@@ -184,11 +326,14 @@ class SSLContext {
SSL_CTX_set_next_proto_select_cb(ssl_ctx_.get(), SelectNextProtoCallback,
NULL);
#endif
+<<<<<<< HEAD
#endif
+=======
+>>>>>>> chromium.org at r10.0.621.0
}
static int NewSessionCallbackStatic(SSL* ssl, SSL_SESSION* session) {
- return Get()->NewSessionCallback(ssl, session);
+ return GetInstance()->NewSessionCallback(ssl, session);
}
int NewSessionCallback(SSL* ssl, SSL_SESSION* session) {
@@ -198,7 +343,7 @@ class SSLContext {
}
static void RemoveSessionCallbackStatic(SSL_CTX* ctx, SSL_SESSION* session) {
- return Get()->RemoveSessionCallback(ctx, session);
+ return GetInstance()->RemoveSessionCallback(ctx, session);
}
void RemoveSessionCallback(SSL_CTX* ctx, SSL_SESSION* session) {
@@ -206,15 +351,30 @@ class SSLContext {
session_cache_.OnSessionRemoved(session);
}
+<<<<<<< HEAD
#ifdef ANDROID
+=======
+ static int ClientCertCallback(SSL* ssl, X509** x509, EVP_PKEY** pkey) {
+ SSLClientSocketOpenSSL* socket = GetInstance()->GetClientSocketFromSSL(ssl);
+ CHECK(socket);
+ return socket->ClientCertRequestCallback(ssl, x509, pkey);
+ }
+
+>>>>>>> chromium.org at r10.0.621.0
static int SelectNextProtoCallback(SSL* ssl,
unsigned char** out, unsigned char* outlen,
const unsigned char* in,
unsigned int inlen, void* arg) {
+<<<<<<< HEAD
SSLClientSocketOpenSSL* socket = Get()->GetClientSocketFromSSL(ssl);
return socket->SelectNextProtoCallback(out, outlen, in, inlen);
}
#endif
+=======
+ SSLClientSocketOpenSSL* socket = GetInstance()->GetClientSocketFromSSL(ssl);
+ return socket->SelectNextProtoCallback(out, outlen, in, inlen);
+ }
+>>>>>>> chromium.org at r10.0.621.0
// This is the index used with SSL_get_ex_data to retrieve the owner
// SSLClientSocketOpenSSL object from an SSL instance.
@@ -242,7 +402,8 @@ struct SslSetClearMask {
SSLClientSocketOpenSSL::SSLClientSocketOpenSSL(
ClientSocketHandle* transport_socket,
const HostPortPair& host_and_port,
- const SSLConfig& ssl_config)
+ const SSLConfig& ssl_config,
+ CertVerifier* cert_verifier)
: ALLOW_THIS_IN_INITIALIZER_LIST(buffer_send_callback_(
this, &SSLClientSocketOpenSSL::BufferSendComplete)),
ALLOW_THIS_IN_INITIALIZER_LIST(buffer_recv_callback_(
@@ -254,6 +415,7 @@ SSLClientSocketOpenSSL::SSLClientSocketOpenSSL(
user_write_callback_(NULL),
completed_handshake_(false),
client_auth_cert_needed_(false),
+ cert_verifier_(cert_verifier),
ALLOW_THIS_IN_INITIALIZER_LIST(handshake_io_callback_(
this, &SSLClientSocketOpenSSL::OnHandshakeIOComplete)),
ssl_(NULL),
@@ -262,9 +424,13 @@ SSLClientSocketOpenSSL::SSLClientSocketOpenSSL(
host_and_port_(host_and_port),
ssl_config_(ssl_config),
trying_cached_session_(false),
+<<<<<<< HEAD
#ifdef ANDROID
npn_status_(kNextProtoUnsupported),
#endif
+=======
+ npn_status_(kNextProtoUnsupported),
+>>>>>>> chromium.org at r10.0.621.0
net_log_(transport_socket->socket()->NetLog()) {
}
@@ -276,7 +442,7 @@ bool SSLClientSocketOpenSSL::Init() {
DCHECK(!ssl_);
DCHECK(!transport_bio_);
- SSLContext* context = SSLContext::Get();
+ SSLContext* context = SSLContext::GetInstance();
base::OpenSSLErrStackTracer err_tracer(FROM_HERE);
ssl_ = SSL_new(context->ssl_ctx());
@@ -316,6 +482,23 @@ bool SSLClientSocketOpenSSL::Init() {
SSL_set_options(ssl_, options.set_mask);
SSL_clear_options(ssl_, options.clear_mask);
+<<<<<<< HEAD
+
+ // Same as above, this time for the SSL mode.
+ SslSetClearMask mode;
+
+#if defined(SSL_MODE_HANDSHAKE_CUTTHROUGH)
+ mode.ConfigureFlag(SSL_MODE_HANDSHAKE_CUTTHROUGH,
+ ssl_config_.false_start_enabled &&
+ !SSLConfigService::IsKnownFalseStartIncompatibleServer(
+ host_and_port_.host()));
+#endif
+
+#if defined(SSL_MODE_RELEASE_BUFFERS)
+ mode.ConfigureFlag(SSL_MODE_RELEASE_BUFFERS, true);
+#endif
+
+=======
// Same as above, this time for the SSL mode.
SslSetClearMask mode;
@@ -331,15 +514,90 @@ bool SSLClientSocketOpenSSL::Init() {
mode.ConfigureFlag(SSL_MODE_RELEASE_BUFFERS, true);
#endif
+>>>>>>> chromium.org at r10.0.621.0
#if defined(SSL_MODE_SMALL_BUFFERS)
mode.ConfigureFlag(SSL_MODE_SMALL_BUFFERS, true);
#endif
SSL_set_mode(ssl_, mode.set_mask);
SSL_clear_mode(ssl_, mode.clear_mask);
+<<<<<<< HEAD
+=======
+
+ // Removing ciphers by ID from OpenSSL is a bit involved as we must use the
+ // textual name with SSL_set_cipher_list because there is no public API to
+ // directly remove a cipher by ID.
+ STACK_OF(SSL_CIPHER)* ciphers = SSL_get_ciphers(ssl_);
+ DCHECK(ciphers);
+ // See SSLConfig::disabled_cipher_suites for description of the suites
+ // disabled by default.
+ std::string command("DEFAULT:!NULL:!aNULL:!IDEA:!FZA");
+ // Walk through all the installed ciphers, seeing if any need to be
+ // appended to the cipher removal |command|.
+ for (int i = 0; i < sk_SSL_CIPHER_num(ciphers); ++i) {
+ const SSL_CIPHER* cipher = sk_SSL_CIPHER_value(ciphers, i);
+ const uint16 id = SSL_CIPHER_get_id(cipher);
+ // Remove any ciphers with a strength of less than 80 bits. Note the NSS
+ // implementation uses "effective" bits here but OpenSSL does not provide
+ // this detail. This only impacts Triple DES: reports 112 vs. 168 bits,
+ // both of which are greater than 80 anyway.
+ bool disable = SSL_CIPHER_get_bits(cipher, NULL) < 80;
+ if (!disable) {
+ disable = std::find(ssl_config_.disabled_cipher_suites.begin(),
+ ssl_config_.disabled_cipher_suites.end(), id) !=
+ ssl_config_.disabled_cipher_suites.end();
+ }
+ if (disable) {
+ const char* name = SSL_CIPHER_get_name(cipher);
+ DVLOG(3) << "Found cipher to remove: '" << name << "', ID: " << id
+ << " strength: " << SSL_CIPHER_get_bits(cipher, NULL);
+ command.append(":!");
+ command.append(name);
+ }
+ }
+ int rv = SSL_set_cipher_list(ssl_, command.c_str());
+ // If this fails (rv = 0) it means there are no ciphers enabled on this SSL.
+ // This will almost certainly result in the socket failing to complete the
+ // handshake at which point the appropriate error is bubbled up to the client.
+ LOG_IF(WARNING, rv != 1) << "SSL_set_cipher_list('" << command << "') "
+ "returned " << rv;
+>>>>>>> chromium.org at r10.0.621.0
return true;
}
+int SSLClientSocketOpenSSL::ClientCertRequestCallback(SSL* ssl,
+ X509** x509,
+ EVP_PKEY** pkey) {
+ DVLOG(3) << "OpenSSL ClientCertRequestCallback called";
+ DCHECK(ssl == ssl_);
+ DCHECK(*x509 == NULL);
+ DCHECK(*pkey == NULL);
+
+ if (!ssl_config_.send_client_cert) {
+ client_auth_cert_needed_ = true;
+ return -1; // Suspends handshake.
+ }
+
+ // Second pass: a client certificate should have been selected.
+ if (ssl_config_.client_cert) {
+ EVP_PKEY* privkey = OpenSSLPrivateKeyStore::GetInstance()->FetchPrivateKey(
+ X509_PUBKEY_get(X509_get_X509_PUBKEY(
+ ssl_config_.client_cert->os_cert_handle())));
+ if (privkey) {
+ // TODO(joth): (copied from NSS) We should wait for server certificate
+ // verification before sending our credentials. See http://crbug.com/13934
+ *x509 = X509Certificate::DupOSCertHandle(
+ ssl_config_.client_cert->os_cert_handle());
+ *pkey = privkey;
+ return 1;
+ }
+ LOG(WARNING) << "Client cert found without private key";
+ }
+
+ // Send no client certificate.
+ return 0;
+}
+
// SSLClientSocket methods
void SSLClientSocketOpenSSL::GetSSLInfo(SSLInfo* ssl_info) {
@@ -353,43 +611,47 @@ void SSLClientSocketOpenSSL::GetSSLInfo(SSLInfo* ssl_info) {
const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl_);
CHECK(cipher);
ssl_info->security_bits = SSL_CIPHER_get_bits(cipher, NULL);
- ssl_info->connection_status |= (cipher->id & SSL_CONNECTION_CIPHERSUITE_MASK)
- << SSL_CONNECTION_CIPHERSUITE_SHIFT;
- DVLOG(2) << SSL_CIPHER_get_name(cipher) << ": cipher ID " << cipher->id
- << " security bits " << ssl_info->security_bits;
-
- // Experimenting suggests the compression object is optional, whereas the
- // cipher (above) is always present.
const COMP_METHOD* compression = SSL_get_current_compression(ssl_);
- if (compression) {
- ssl_info->connection_status |=
- (compression->type & SSL_CONNECTION_COMPRESSION_MASK)
- << SSL_CONNECTION_COMPRESSION_SHIFT;
- DVLOG(2) << SSL_COMP_get_name(compression)
- << ": compression ID " << compression->type;
- }
+
+ ssl_info->connection_status = EncodeSSLConnectionStatus(
+ SSL_CIPHER_get_id(cipher),
+ compression ? compression->type : 0,
+ GetNetSSLVersion(ssl_));
bool peer_supports_renego_ext = !!SSL_get_secure_renegotiation_support(ssl_);
if (!peer_supports_renego_ext)
ssl_info->connection_status |= SSL_CONNECTION_NO_RENEGOTIATION_EXTENSION;
- UMA_HISTOGRAM_ENUMERATION("Net.RenegotiationExtensionSupported",
- (int)peer_supports_renego_ext, 2);
+ UMA_HISTOGRAM_ENUMERATION("Net.RenegotiationExtensionSupported",
+ implicit_cast<int>(peer_supports_renego_ext), 2);
if (ssl_config_.ssl3_fallback)
ssl_info->connection_status |= SSL_CONNECTION_SSL3_FALLBACK;
+
+ DVLOG(3) << "Encoded connection status: cipher suite = "
+ << SSLConnectionStatusToCipherSuite(ssl_info->connection_status)
+ << " compression = "
+ << SSLConnectionStatusToCompression(ssl_info->connection_status)
+ << " version = "
+ << SSLConnectionStatusToVersion(ssl_info->connection_status);
}
void SSLClientSocketOpenSSL::GetSSLCertRequestInfo(
SSLCertRequestInfo* cert_request_info) {
- NOTREACHED();
+ cert_request_info->host_and_port = host_and_port_.ToString();
+ cert_request_info->client_certs = client_certs_;
}
SSLClientSocket::NextProtoStatus SSLClientSocketOpenSSL::GetNextProto(
std::string* proto) {
+<<<<<<< HEAD
#ifdef ANDROID
*proto = npn_proto_;
return npn_status_;
#endif
+=======
+ *proto = npn_proto_;
+ return npn_status_;
+>>>>>>> chromium.org at r10.0.621.0
}
void SSLClientSocketOpenSSL::DoReadCallback(int rv) {
@@ -528,19 +790,33 @@ int SSLClientSocketOpenSSL::DoHandshake() {
int net_error = net::OK;
int rv = SSL_do_handshake(ssl_);
- if (rv == 1) {
+ if (client_auth_cert_needed_) {
+ net_error = ERR_SSL_CLIENT_AUTH_CERT_NEEDED;
+ // If the handshake already succeeded (because the server requests but
+ // doesn't require a client cert), we need to invalidate the SSL session
+ // so that we won't try to resume the non-client-authenticated session in
+ // the next handshake. This will cause the server to ask for a client
+ // cert again.
+ if (rv == 1) {
+ // Remove from session cache but don't clear this connection.
+ SSL_SESSION* session = SSL_get_session(ssl_);
+ if (session) {
+ int rv = SSL_CTX_remove_session(SSL_get_SSL_CTX(ssl_), session);
+ LOG_IF(WARNING, !rv) << "Couldn't invalidate SSL session: " << session;
+ }
+ }
+ } else if (rv == 1) {
if (trying_cached_session_ && logging::DEBUG_MODE) {
DVLOG(2) << "Result of session reuse for " << host_and_port_.ToString()
<< " is: " << (SSL_session_reused(ssl_) ? "Success" : "Fail");
}
-
// SSL handshake is completed. Let's verify the certificate.
const bool got_cert = !!UpdateServerCert();
DCHECK(got_cert);
GotoState(STATE_VERIFY_CERT);
} else {
int ssl_error = SSL_get_error(ssl_, rv);
- net_error = MapOpenSSLError(ssl_error);
+ net_error = MapOpenSSLError(ssl_error, err_tracer);
// If not done, stay in this state
if (net_error == ERR_IO_PENDING) {
@@ -549,12 +825,18 @@ int SSLClientSocketOpenSSL::DoHandshake() {
LOG(ERROR) << "handshake failed; returned " << rv
<< ", SSL error code " << ssl_error
<< ", net_error " << net_error;
+ net_log_.AddEvent(
+ NetLog::TYPE_SSL_HANDSHAKE_ERROR,
+ make_scoped_refptr(new SSLErrorParams(net_error, ssl_error)));
}
}
return net_error;
}
+<<<<<<< HEAD
#ifdef ANDROID
+=======
+>>>>>>> chromium.org at r10.0.621.0
int SSLClientSocketOpenSSL::SelectNextProtoCallback(unsigned char** out,
unsigned char* outlen,
const unsigned char* in,
@@ -587,10 +869,17 @@ int SSLClientSocketOpenSSL::SelectNextProtoCallback(unsigned char** out,
NOTREACHED() << status;
break;
}
+<<<<<<< HEAD
#endif
return SSL_TLSEXT_ERR_OK;
}
#endif
+=======
+ DVLOG(2) << "next protocol: '" << npn_proto_ << "' status: " << npn_status_;
+#endif
+ return SSL_TLSEXT_ERR_OK;
+}
+>>>>>>> chromium.org at r10.0.621.0
int SSLClientSocketOpenSSL::DoVerifyCert(int result) {
DCHECK(server_cert_);
@@ -601,7 +890,7 @@ int SSLClientSocketOpenSSL::DoVerifyCert(int result) {
flags |= X509Certificate::VERIFY_REV_CHECKING_ENABLED;
if (ssl_config_.verify_ev_cert)
flags |= X509Certificate::VERIFY_EV_CERT;
- verifier_.reset(new CertVerifier);
+ verifier_.reset(new SingleRequestCertVerifier(cert_verifier_));
return verifier_->Verify(server_cert_, host_and_port_.host(), flags,
&server_cert_verify_result_,
&handshake_io_callback_);
@@ -961,7 +1250,7 @@ int SSLClientSocketOpenSSL::DoPayloadRead() {
return rv;
int err = SSL_get_error(ssl_, rv);
- return MapOpenSSLError(err);
+ return MapOpenSSLError(err, err_tracer);
}
int SSLClientSocketOpenSSL::DoPayloadWrite() {
@@ -972,7 +1261,7 @@ int SSLClientSocketOpenSSL::DoPayloadWrite() {
return rv;
int err = SSL_get_error(ssl_, rv);
- return MapOpenSSLError(err);
+ return MapOpenSSLError(err, err_tracer);
}
-} // namespace net
+} // namespace net
diff --git a/net/socket/ssl_client_socket_openssl.h b/net/socket/ssl_client_socket_openssl.h
index c8f5d81..72dab75 100644
--- a/net/socket/ssl_client_socket_openssl.h
+++ b/net/socket/ssl_client_socket_openssl.h
@@ -6,6 +6,8 @@
#define NET_SOCKET_SSL_CLIENT_SOCKET_OPENSSL_H_
#pragma once
+#include <string>
+
#include "base/scoped_ptr.h"
#include "net/base/cert_verify_result.h"
#include "net/base/completion_callback.h"
@@ -15,11 +17,14 @@
#include "net/socket/client_socket_handle.h"
typedef struct bio_st BIO;
+typedef struct evp_pkey_st EVP_PKEY;
typedef struct ssl_st SSL;
+typedef struct x509_st X509;
namespace net {
class CertVerifier;
+class SingleRequestCertVerifier;
class SSLCertRequestInfo;
class SSLConfig;
class SSLInfo;
@@ -33,16 +38,27 @@ class SSLClientSocketOpenSSL : public SSLClientSocket {
// settings.
SSLClientSocketOpenSSL(ClientSocketHandle* transport_socket,
const HostPortPair& host_and_port,
- const SSLConfig& ssl_config);
+ const SSLConfig& ssl_config,
+ CertVerifier* cert_verifier);
~SSLClientSocketOpenSSL();
const HostPortPair& host_and_port() const { return host_and_port_; }
+<<<<<<< HEAD
#ifdef ANDROID
// Callback from the SSL layer to check which NPN protocol we are supporting
int SelectNextProtoCallback(unsigned char** out, unsigned char* outlen,
const unsigned char* in, unsigned int inlen);
#endif
+=======
+ // Callback from the SSL layer that indicates the remote server is requesting
+ // a certificate for this client.
+ int ClientCertRequestCallback(SSL* ssl, X509** x509, EVP_PKEY** pkey);
+
+ // Callback from the SSL layer to check which NPN protocol we are supporting
+ int SelectNextProtoCallback(unsigned char** out, unsigned char* outlen,
+ const unsigned char* in, unsigned int inlen);
+>>>>>>> chromium.org at r10.0.621.0
// SSLClientSocket methods:
virtual void GetSSLInfo(SSLInfo* ssl_info);
@@ -58,7 +74,7 @@ class SSLClientSocketOpenSSL : public SSLClientSocket {
virtual void Disconnect();
virtual bool IsConnected() const;
virtual bool IsConnectedAndIdle() const;
- virtual int GetPeerAddress(AddressList*) const;
+ virtual int GetPeerAddress(AddressList* address) const;
virtual const BoundNetLog& NetLog() const;
virtual void SetSubresourceSpeculation();
virtual void SetOmniboxSpeculation();
@@ -81,7 +97,6 @@ class SSLClientSocketOpenSSL : public SSLClientSocket {
int DoVerifyCert(int result);
int DoVerifyCertComplete(int result);
void DoConnectCallback(int result);
- void InvalidateSessionIfBadCertificate();
X509Certificate* UpdateServerCert();
void OnHandshakeIOComplete(int result);
@@ -130,7 +145,8 @@ class SSLClientSocketOpenSSL : public SSLClientSocket {
std::vector<scoped_refptr<X509Certificate> > client_certs_;
bool client_auth_cert_needed_;
- scoped_ptr<CertVerifier> verifier_;
+ CertVerifier* const cert_verifier_;
+ scoped_ptr<SingleRequestCertVerifier> verifier_;
CompletionCallbackImpl<SSLClientSocketOpenSSL> handshake_io_callback_;
// OpenSSL stuff
@@ -151,14 +167,19 @@ class SSLClientSocketOpenSSL : public SSLClientSocket {
STATE_VERIFY_CERT_COMPLETE,
};
State next_handshake_state_;
+<<<<<<< HEAD
#ifdef ANDROID
NextProtoStatus npn_status_;
std::string npn_proto_;
#endif
+=======
+ NextProtoStatus npn_status_;
+ std::string npn_proto_;
+>>>>>>> chromium.org at r10.0.621.0
BoundNetLog net_log_;
};
} // namespace net
-#endif // NET_SOCKET_SSL_CLIENT_SOCKET_OPENSSL_H_
+#endif // NET_SOCKET_SSL_CLIENT_SOCKET_OPENSSL_H_
diff --git a/net/socket/ssl_client_socket_pool.cc b/net/socket/ssl_client_socket_pool.cc
index 54e5152..8002814 100644
--- a/net/socket/ssl_client_socket_pool.cc
+++ b/net/socket/ssl_client_socket_pool.cc
@@ -86,6 +86,7 @@ SSLConnectJob::SSLConnectJob(
HttpProxyClientSocketPool* http_proxy_pool,
ClientSocketFactory* client_socket_factory,
HostResolver* host_resolver,
+ CertVerifier* cert_verifier,
DnsRRResolver* dnsrr_resolver,
DnsCertProvenanceChecker* dns_cert_checker,
SSLHostInfoFactory* ssl_host_info_factory,
@@ -98,7 +99,8 @@ SSLConnectJob::SSLConnectJob(
socks_pool_(socks_pool),
http_proxy_pool_(http_proxy_pool),
client_socket_factory_(client_socket_factory),
- resolver_(host_resolver),
+ host_resolver_(host_resolver),
+ cert_verifier_(cert_verifier),
dnsrr_resolver_(dnsrr_resolver),
dns_cert_checker_(dns_cert_checker),
ssl_host_info_factory_(ssl_host_info_factory),
@@ -203,7 +205,7 @@ int SSLConnectJob::DoLoop(int result) {
int SSLConnectJob::DoTCPConnect() {
DCHECK(tcp_pool_);
- if (ssl_host_info_factory_ && SSLConfigService::snap_start_enabled()) {
+ if (ssl_host_info_factory_) {
ssl_host_info_.reset(
ssl_host_info_factory_->GetForHost(params_->host_and_port().host(),
params_->ssl_config()));
@@ -265,11 +267,12 @@ int SSLConnectJob::DoTunnelConnectComplete(int result) {
// |GetAdditionalErrorState|, we can easily set the state.
if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
error_response_info_ = transport_socket_handle_->ssl_error_response_info();
- } else if (result == ERR_PROXY_AUTH_REQUESTED) {
+ } else if (result == ERR_PROXY_AUTH_REQUESTED ||
+ result == ERR_HTTPS_PROXY_TUNNEL_RESPONSE) {
ClientSocket* socket = transport_socket_handle_->socket();
HttpProxyClientSocket* tunnel_socket =
static_cast<HttpProxyClientSocket*>(socket);
- error_response_info_ = *tunnel_socket->GetResponseInfo();
+ error_response_info_ = *tunnel_socket->GetConnectResponseInfo();
}
if (result < 0)
return result;
@@ -298,12 +301,18 @@ int SSLConnectJob::DoSSLConnect() {
ssl_socket_.reset(client_socket_factory_->CreateSSLClientSocket(
transport_socket_handle_.release(), params_->host_and_port(),
+<<<<<<< HEAD
params_->ssl_config(), ssl_host_info_.release(), dns_cert_checker_));
return ssl_socket_->Connect(&callback_
#ifdef ANDROID
, params_->ignore_limits()
#endif
);
+=======
+ params_->ssl_config(), ssl_host_info_.release(), cert_verifier_,
+ dns_cert_checker_));
+ return ssl_socket_->Connect(&callback_);
+>>>>>>> chromium.org at r10.0.621.0
}
int SSLConnectJob::DoSSLConnectComplete(int result) {
@@ -373,7 +382,7 @@ ConnectJob* SSLClientSocketPool::SSLConnectJobFactory::NewConnectJob(
return new SSLConnectJob(group_name, request.params(), ConnectionTimeout(),
tcp_pool_, socks_pool_, http_proxy_pool_,
client_socket_factory_, host_resolver_,
- dnsrr_resolver_, dns_cert_checker_,
+ cert_verifier_, dnsrr_resolver_, dns_cert_checker_,
ssl_host_info_factory_, delegate, net_log_);
}
@@ -383,6 +392,7 @@ SSLClientSocketPool::SSLConnectJobFactory::SSLConnectJobFactory(
HttpProxyClientSocketPool* http_proxy_pool,
ClientSocketFactory* client_socket_factory,
HostResolver* host_resolver,
+ CertVerifier* cert_verifier,
DnsRRResolver* dnsrr_resolver,
DnsCertProvenanceChecker* dns_cert_checker,
SSLHostInfoFactory* ssl_host_info_factory,
@@ -392,6 +402,7 @@ SSLClientSocketPool::SSLConnectJobFactory::SSLConnectJobFactory(
http_proxy_pool_(http_proxy_pool),
client_socket_factory_(client_socket_factory),
host_resolver_(host_resolver),
+ cert_verifier_(cert_verifier),
dnsrr_resolver_(dnsrr_resolver),
dns_cert_checker_(dns_cert_checker),
ssl_host_info_factory_(ssl_host_info_factory),
@@ -419,6 +430,7 @@ SSLClientSocketPool::SSLClientSocketPool(
int max_sockets_per_group,
ClientSocketPoolHistograms* histograms,
HostResolver* host_resolver,
+ CertVerifier* cert_verifier,
DnsRRResolver* dnsrr_resolver,
DnsCertProvenanceChecker* dns_cert_checker,
SSLHostInfoFactory* ssl_host_info_factory,
@@ -437,8 +449,8 @@ SSLClientSocketPool::SSLClientSocketPool(
base::TimeDelta::FromSeconds(kUsedIdleSocketTimeout),
new SSLConnectJobFactory(tcp_pool, socks_pool, http_proxy_pool,
client_socket_factory, host_resolver,
- dnsrr_resolver, dns_cert_checker,
- ssl_host_info_factory,
+ cert_verifier, dnsrr_resolver,
+ dns_cert_checker, ssl_host_info_factory,
net_log)),
ssl_config_service_(ssl_config_service) {
if (ssl_config_service_)
@@ -492,6 +504,10 @@ void SSLClientSocketPool::CloseIdleSockets() {
base_.CloseIdleSockets();
}
+int SSLClientSocketPool::IdleSocketCount() const {
+ return base_.idle_socket_count();
+}
+
int SSLClientSocketPool::IdleSocketCountInGroup(
const std::string& group_name) const {
return base_.IdleSocketCountInGroup(group_name);
@@ -533,4 +549,12 @@ DictionaryValue* SSLClientSocketPool::GetInfoAsValue(
return dict;
}
+base::TimeDelta SSLClientSocketPool::ConnectionTimeout() const {
+ return base_.ConnectionTimeout();
+}
+
+ClientSocketPoolHistograms* SSLClientSocketPool::histograms() const {
+ return base_.histograms();
+}
+
} // namespace net
diff --git a/net/socket/ssl_client_socket_pool.h b/net/socket/ssl_client_socket_pool.h
index 3d332af..70da04f 100644
--- a/net/socket/ssl_client_socket_pool.h
+++ b/net/socket/ssl_client_socket_pool.h
@@ -22,6 +22,7 @@
namespace net {
+class CertVerifier;
class ClientSocketFactory;
class ConnectJobFactory;
class DnsCertProvenanceChecker;
@@ -101,6 +102,7 @@ class SSLConnectJob : public ConnectJob {
HttpProxyClientSocketPool* http_proxy_pool,
ClientSocketFactory* client_socket_factory,
HostResolver* host_resolver,
+ CertVerifier* cert_verifier,
DnsRRResolver* dnsrr_resolver,
DnsCertProvenanceChecker* dns_cert_checker,
SSLHostInfoFactory* ssl_host_info_factory,
@@ -150,7 +152,8 @@ class SSLConnectJob : public ConnectJob {
SOCKSClientSocketPool* const socks_pool_;
HttpProxyClientSocketPool* const http_proxy_pool_;
ClientSocketFactory* const client_socket_factory_;
- HostResolver* const resolver_;
+ HostResolver* const host_resolver_;
+ CertVerifier* const cert_verifier_;
DnsRRResolver* const dnsrr_resolver_;
DnsCertProvenanceChecker* dns_cert_checker_;
SSLHostInfoFactory* const ssl_host_info_factory_;
@@ -179,6 +182,7 @@ class SSLClientSocketPool : public ClientSocketPool,
int max_sockets_per_group,
ClientSocketPoolHistograms* histograms,
HostResolver* host_resolver,
+ CertVerifier* cert_verifier,
DnsRRResolver* dnsrr_resolver,
DnsCertProvenanceChecker* dns_cert_checker,
SSLHostInfoFactory* ssl_host_info_factory,
@@ -215,9 +219,7 @@ class SSLClientSocketPool : public ClientSocketPool,
virtual void CloseIdleSockets();
- virtual int IdleSocketCount() const {
- return base_.idle_socket_count();
- }
+ virtual int IdleSocketCount() const;
virtual int IdleSocketCountInGroup(const std::string& group_name) const;
@@ -228,13 +230,9 @@ class SSLClientSocketPool : public ClientSocketPool,
const std::string& type,
bool include_nested_pools) const;
- virtual base::TimeDelta ConnectionTimeout() const {
- return base_.ConnectionTimeout();
- }
+ virtual base::TimeDelta ConnectionTimeout() const;
- virtual ClientSocketPoolHistograms* histograms() const {
- return base_.histograms();
- };
+ virtual ClientSocketPoolHistograms* histograms() const;
private:
// SSLConfigService::Observer methods:
@@ -253,6 +251,7 @@ class SSLClientSocketPool : public ClientSocketPool,
HttpProxyClientSocketPool* http_proxy_pool,
ClientSocketFactory* client_socket_factory,
HostResolver* host_resolver,
+ CertVerifier* cert_verifier,
DnsRRResolver* dnsrr_resolver,
DnsCertProvenanceChecker* dns_cert_checker,
SSLHostInfoFactory* ssl_host_info_factory,
@@ -274,6 +273,7 @@ class SSLClientSocketPool : public ClientSocketPool,
HttpProxyClientSocketPool* const http_proxy_pool_;
ClientSocketFactory* const client_socket_factory_;
HostResolver* const host_resolver_;
+ CertVerifier* const cert_verifier_;
DnsRRResolver* const dnsrr_resolver_;
DnsCertProvenanceChecker* const dns_cert_checker_;
SSLHostInfoFactory* const ssl_host_info_factory_;
diff --git a/net/socket/ssl_client_socket_pool_unittest.cc b/net/socket/ssl_client_socket_pool_unittest.cc
index 247638b..37e21ca 100644
--- a/net/socket/ssl_client_socket_pool_unittest.cc
+++ b/net/socket/ssl_client_socket_pool_unittest.cc
@@ -10,6 +10,7 @@
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "net/base/auth.h"
+#include "net/base/cert_verifier.h"
#include "net/base/mock_host_resolver.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
@@ -36,9 +37,11 @@ class SSLClientSocketPoolTest : public testing::Test {
protected:
SSLClientSocketPoolTest()
: host_resolver_(new MockHostResolver),
+ cert_verifier_(new CertVerifier),
http_auth_handler_factory_(HttpAuthHandlerFactory::CreateDefault(
host_resolver_.get())),
session_(new HttpNetworkSession(host_resolver_.get(),
+ cert_verifier_.get(),
NULL /* dnsrr_resolver */,
NULL /* dns_cert_checker */,
NULL /* ssl_host_info_factory */,
@@ -96,7 +99,8 @@ class SSLClientSocketPoolTest : public testing::Test {
kMaxSockets,
kMaxSocketsPerGroup,
ssl_histograms_.get(),
- NULL,
+ NULL /* host_resolver */,
+ NULL /* cert_verifier */,
NULL /* dnsrr_resolver */,
NULL /* dns_cert_checker */,
NULL /* ssl_host_info_factory */,
@@ -131,6 +135,7 @@ class SSLClientSocketPoolTest : public testing::Test {
MockClientSocketFactory socket_factory_;
scoped_ptr<HostResolver> host_resolver_;
+ scoped_ptr<CertVerifier> cert_verifier_;
scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory_;
scoped_refptr<HttpNetworkSession> session_;
diff --git a/net/socket/ssl_client_socket_snapstart_unittest.cc b/net/socket/ssl_client_socket_snapstart_unittest.cc
index 13b2636..d782993 100644
--- a/net/socket/ssl_client_socket_snapstart_unittest.cc
+++ b/net/socket/ssl_client_socket_snapstart_unittest.cc
@@ -41,8 +41,8 @@ namespace net {
// pretends that certificate verification always succeeds.
class TestSSLHostInfo : public SSLHostInfo {
public:
- TestSSLHostInfo()
- : SSLHostInfo("example.com", kDefaultSSLConfig) {
+ explicit TestSSLHostInfo(CertVerifier* cert_verifier)
+ : SSLHostInfo("example.com", kDefaultSSLConfig, cert_verifier) {
if (!saved_.empty())
Parse(saved_);
cert_verification_complete_ = true;
@@ -121,7 +121,7 @@ class SSLClientSocketSnapStartTest : public PlatformTest {
// The listening socket is installed as the child's fd 3.
mapping.push_back(std::make_pair(listener, 3));
base::LaunchApp(args, mapping, false /* don't wait */, &child_);
- HANDLE_EINTR(close(listener));
+ ASSERT_EQ(0, HANDLE_EINTR(close(listener)));
}
// LoadDefaultCert returns the DER encoded default certificate.
@@ -194,7 +194,7 @@ class SSLClientSocketSnapStartTest : public PlatformTest {
scoped_ptr<SSLClientSocket> sock(
socket_factory_->CreateSSLClientSocket(
transport, HostPortPair("example.com", 443), ssl_config_,
- new TestSSLHostInfo()));
+ new TestSSLHostInfo(&cert_verifier_), &cert_verifier_));
TestCompletionCallback callback;
int rv = sock->Connect(&callback);
@@ -234,8 +234,9 @@ class SSLClientSocketSnapStartTest : public PlatformTest {
// SnapStartEventType extracts the type of Snap Start from the NetLog. See
// the SSL_SNAP_START_* defines in sslt.h
int SnapStartEventType() {
- const std::vector<CapturingNetLog::Entry>& entries = log_.entries();
- for (std::vector<CapturingNetLog::Entry>::const_iterator
+ CapturingNetLog::EntryList entries;
+ log_.GetEntries(&entries);
+ for (CapturingNetLog::EntryList::const_iterator
i = entries.begin(); i != entries.end(); i++) {
if (i->type == NetLog::TYPE_SSL_SNAP_START) {
scoped_ptr<Value> value(i->extra_parameters->ToValue());
@@ -253,8 +254,9 @@ class SSLClientSocketSnapStartTest : public PlatformTest {
// it's certificate validation with the optimistic validation from the
// SSLHostInfo.
bool DidMerge() {
- const std::vector<CapturingNetLog::Entry>& entries = log_.entries();
- for (std::vector<CapturingNetLog::Entry>::const_iterator
+ CapturingNetLog::EntryList entries;
+ log_.GetEntries(&entries);
+ for (CapturingNetLog::EntryList::const_iterator
i = entries.begin(); i != entries.end(); i++) {
if (i->type == NetLog::TYPE_SSL_VERIFICATION_MERGED)
return true;
@@ -263,6 +265,7 @@ class SSLClientSocketSnapStartTest : public PlatformTest {
}
base::ProcessHandle child_;
+ CertVerifier cert_verifier_;
ClientSocketFactory* const socket_factory_;
struct sockaddr_in remote_;
int client_;
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index e736d5b..9ba5cbf 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -5,6 +5,7 @@
#include "net/socket/ssl_client_socket.h"
#include "net/base/address_list.h"
+#include "net/base/cert_verifier.h"
#include "net/base/host_resolver.h"
#include "net/base/io_buffer.h"
#include "net/base/net_log.h"
@@ -26,11 +27,24 @@ const net::SSLConfig kDefaultSSLConfig;
class SSLClientSocketTest : public PlatformTest {
public:
SSLClientSocketTest()
- : socket_factory_(net::ClientSocketFactory::GetDefaultFactory()) {
+ : socket_factory_(net::ClientSocketFactory::GetDefaultFactory()),
+ cert_verifier_(new net::CertVerifier) {
}
protected:
+ net::SSLClientSocket* CreateSSLClientSocket(
+ net::ClientSocket* transport_socket,
+ const net::HostPortPair& host_and_port,
+ const net::SSLConfig& ssl_config) {
+ return socket_factory_->CreateSSLClientSocket(transport_socket,
+ host_and_port,
+ ssl_config,
+ NULL,
+ cert_verifier_.get());
+ }
+
net::ClientSocketFactory* socket_factory_;
+ scoped_ptr<net::CertVerifier> cert_verifier_;
};
//-----------------------------------------------------------------------------
@@ -67,18 +81,23 @@ TEST_F(SSLClientSocketTest, Connect) {
scoped_ptr<net::SSLClientSocket> sock(
socket_factory_->CreateSSLClientSocket(
- transport, test_server.host_port_pair(), kDefaultSSLConfig, NULL));
+ transport, test_server.host_port_pair(), kDefaultSSLConfig,
+ NULL, cert_verifier_.get()));
EXPECT_FALSE(sock->IsConnected());
rv = sock->Connect(&callback);
+
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
EXPECT_TRUE(net::LogContainsBeginEvent(
- log.entries(), 5, net::NetLog::TYPE_SSL_CONNECT));
+ entries, 5, net::NetLog::TYPE_SSL_CONNECT));
if (rv == net::ERR_IO_PENDING)
rv = callback.WaitForResult();
EXPECT_EQ(net::OK, rv);
EXPECT_TRUE(sock->IsConnected());
- EXPECT_TRUE(LogContainsSSLConnectEndEvent(log.entries(), -1));
+ log.GetEntries(&entries);
+ EXPECT_TRUE(LogContainsSSLConnectEndEvent(entries, -1));
sock->Disconnect();
EXPECT_FALSE(sock->IsConnected());
@@ -103,14 +122,17 @@ TEST_F(SSLClientSocketTest, ConnectExpired) {
EXPECT_EQ(net::OK, rv);
scoped_ptr<net::SSLClientSocket> sock(
- socket_factory_->CreateSSLClientSocket(
- transport, test_server.host_port_pair(), kDefaultSSLConfig, NULL));
+ CreateSSLClientSocket(transport, test_server.host_port_pair(),
+ kDefaultSSLConfig));
EXPECT_FALSE(sock->IsConnected());
rv = sock->Connect(&callback);
+
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
EXPECT_TRUE(net::LogContainsBeginEvent(
- log.entries(), 5, net::NetLog::TYPE_SSL_CONNECT));
+ entries, 5, net::NetLog::TYPE_SSL_CONNECT));
if (rv == net::ERR_IO_PENDING)
rv = callback.WaitForResult();
@@ -120,7 +142,8 @@ TEST_F(SSLClientSocketTest, ConnectExpired) {
// test that the handshake has finished. This is because it may be
// desirable to disconnect the socket before showing a user prompt, since
// the user may take indefinitely long to respond.
- EXPECT_TRUE(LogContainsSSLConnectEndEvent(log.entries(), -1));
+ log.GetEntries(&entries);
+ EXPECT_TRUE(LogContainsSSLConnectEndEvent(entries, -1));
}
TEST_F(SSLClientSocketTest, ConnectMismatched) {
@@ -142,15 +165,17 @@ TEST_F(SSLClientSocketTest, ConnectMismatched) {
EXPECT_EQ(net::OK, rv);
scoped_ptr<net::SSLClientSocket> sock(
- socket_factory_->CreateSSLClientSocket(
- transport, test_server.host_port_pair(), kDefaultSSLConfig, NULL));
+ CreateSSLClientSocket(transport, test_server.host_port_pair(),
+ kDefaultSSLConfig));
EXPECT_FALSE(sock->IsConnected());
rv = sock->Connect(&callback);
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
EXPECT_TRUE(net::LogContainsBeginEvent(
- log.entries(), 5, net::NetLog::TYPE_SSL_CONNECT));
+ entries, 5, net::NetLog::TYPE_SSL_CONNECT));
if (rv == net::ERR_IO_PENDING)
rv = callback.WaitForResult();
@@ -160,7 +185,8 @@ TEST_F(SSLClientSocketTest, ConnectMismatched) {
// test that the handshake has finished. This is because it may be
// desirable to disconnect the socket before showing a user prompt, since
// the user may take indefinitely long to respond.
- EXPECT_TRUE(LogContainsSSLConnectEndEvent(log.entries(), -1));
+ log.GetEntries(&entries);
+ EXPECT_TRUE(LogContainsSSLConnectEndEvent(entries, -1));
}
// Attempt to connect to a page which requests a client certificate. It should
@@ -185,17 +211,22 @@ TEST_F(SSLClientSocketTest, FLAKY_ConnectClientAuthCertRequested) {
EXPECT_EQ(net::OK, rv);
scoped_ptr<net::SSLClientSocket> sock(
- socket_factory_->CreateSSLClientSocket(
- transport, test_server.host_port_pair(), kDefaultSSLConfig, NULL));
+ CreateSSLClientSocket(transport, test_server.host_port_pair(),
+ kDefaultSSLConfig));
EXPECT_FALSE(sock->IsConnected());
rv = sock->Connect(&callback);
+
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
EXPECT_TRUE(net::LogContainsBeginEvent(
- log.entries(), 5, net::NetLog::TYPE_SSL_CONNECT));
+ entries, 5, net::NetLog::TYPE_SSL_CONNECT));
if (rv == net::ERR_IO_PENDING)
rv = callback.WaitForResult();
+ log.GetEntries(&entries);
+ EXPECT_TRUE(LogContainsSSLConnectEndEvent(entries, -1));
EXPECT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv);
EXPECT_FALSE(sock->IsConnected());
}
@@ -227,22 +258,26 @@ TEST_F(SSLClientSocketTest, ConnectClientAuthSendNullCert) {
ssl_config.client_cert = NULL;
scoped_ptr<net::SSLClientSocket> sock(
- socket_factory_->CreateSSLClientSocket(
- transport, test_server.host_port_pair(), ssl_config, NULL));
+ CreateSSLClientSocket(transport, test_server.host_port_pair(),
+ ssl_config));
EXPECT_FALSE(sock->IsConnected());
// Our test server accepts certificate-less connections.
// TODO(davidben): Add a test which requires them and verify the error.
rv = sock->Connect(&callback);
+
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
EXPECT_TRUE(net::LogContainsBeginEvent(
- log.entries(), 5, net::NetLog::TYPE_SSL_CONNECT));
+ entries, 5, net::NetLog::TYPE_SSL_CONNECT));
if (rv == net::ERR_IO_PENDING)
rv = callback.WaitForResult();
EXPECT_EQ(net::OK, rv);
EXPECT_TRUE(sock->IsConnected());
- EXPECT_TRUE(LogContainsSSLConnectEndEvent(log.entries(), -1));
+ log.GetEntries(&entries);
+ EXPECT_TRUE(LogContainsSSLConnectEndEvent(entries, -1));
sock->Disconnect();
EXPECT_FALSE(sock->IsConnected());
@@ -269,8 +304,8 @@ TEST_F(SSLClientSocketTest, Read) {
EXPECT_EQ(net::OK, rv);
scoped_ptr<net::SSLClientSocket> sock(
- socket_factory_->CreateSSLClientSocket(
- transport, test_server.host_port_pair(), kDefaultSSLConfig, NULL));
+ CreateSSLClientSocket(transport, test_server.host_port_pair(),
+ kDefaultSSLConfig));
rv = sock->Connect(&callback);
if (rv == net::ERR_IO_PENDING)
@@ -325,7 +360,8 @@ TEST_F(SSLClientSocketTest, Read_FullDuplex) {
scoped_ptr<net::SSLClientSocket> sock(
socket_factory_->CreateSSLClientSocket(
- transport, test_server.host_port_pair(), kDefaultSSLConfig, NULL));
+ transport, test_server.host_port_pair(), kDefaultSSLConfig,
+ NULL, cert_verifier_.get()));
rv = sock->Connect(&callback);
if (rv == net::ERR_IO_PENDING)
@@ -378,8 +414,8 @@ TEST_F(SSLClientSocketTest, Read_SmallChunks) {
EXPECT_EQ(net::OK, rv);
scoped_ptr<net::SSLClientSocket> sock(
- socket_factory_->CreateSSLClientSocket(
- transport, test_server.host_port_pair(), kDefaultSSLConfig, NULL));
+ CreateSSLClientSocket(transport, test_server.host_port_pair(),
+ kDefaultSSLConfig));
rv = sock->Connect(&callback);
if (rv == net::ERR_IO_PENDING)
@@ -428,8 +464,8 @@ TEST_F(SSLClientSocketTest, Read_Interrupted) {
EXPECT_EQ(net::OK, rv);
scoped_ptr<net::SSLClientSocket> sock(
- socket_factory_->CreateSSLClientSocket(
- transport, test_server.host_port_pair(), kDefaultSSLConfig, NULL));
+ CreateSSLClientSocket(transport, test_server.host_port_pair(),
+ kDefaultSSLConfig));
rv = sock->Connect(&callback);
if (rv == net::ERR_IO_PENDING)
@@ -498,23 +534,16 @@ TEST_F(SSLClientSocketTest, PrematureApplicationData) {
EXPECT_EQ(net::OK, rv);
scoped_ptr<net::SSLClientSocket> sock(
- socket_factory_->CreateSSLClientSocket(
- transport, test_server.host_port_pair(), kDefaultSSLConfig, NULL));
+ CreateSSLClientSocket(transport, test_server.host_port_pair(),
+ kDefaultSSLConfig));
rv = sock->Connect(&callback);
EXPECT_EQ(net::ERR_SSL_PROTOCOL_ERROR, rv);
}
-#if defined(USE_OPENSSL)
-// TODO(rsleevi): Not implemented for Schannel or OpenSSL. Schannel is
-// controlled by the SSL client socket factory, rather than a define, so it
-// cannot be conditionally disabled here. As Schannel is only used when
+// TODO(rsleevi): Not implemented for Schannel. As Schannel is only used when
// performing client authentication, it will not be tested here.
-#define MAYBE_CipherSuiteDisables DISABLED_CipherSuiteDisables
-#else
-#define MAYBE_CipherSuiteDisables CipherSuiteDisables
-#endif
-TEST_F(SSLClientSocketTest, MAYBE_CipherSuiteDisables) {
+TEST_F(SSLClientSocketTest, CipherSuiteDisables) {
// Rather than exhaustively disabling every RC4 ciphersuite defined at
// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml,
// only disabling those cipher suites that the test server actually
@@ -547,14 +576,16 @@ TEST_F(SSLClientSocketTest, MAYBE_CipherSuiteDisables) {
ssl_config.disabled_cipher_suites.push_back(kCiphersToDisable[i]);
scoped_ptr<net::SSLClientSocket> sock(
- socket_factory_->CreateSSLClientSocket(
- transport, test_server.host_port_pair(), ssl_config, NULL));
+ CreateSSLClientSocket(transport, test_server.host_port_pair(),
+ ssl_config));
EXPECT_FALSE(sock->IsConnected());
rv = sock->Connect(&callback);
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
EXPECT_TRUE(net::LogContainsBeginEvent(
- log.entries(), 5, net::NetLog::TYPE_SSL_CONNECT));
+ entries, 5, net::NetLog::TYPE_SSL_CONNECT));
// NSS has special handling that maps a handshake_failure alert received
// immediately after a client_hello to be a mismatched cipher suite error,
@@ -569,12 +600,13 @@ TEST_F(SSLClientSocketTest, MAYBE_CipherSuiteDisables) {
// The exact ordering differs between SSLClientSocketNSS (which issues an
// extra read) and SSLClientSocketMac (which does not). Just make sure the
// error appears somewhere in the log.
- net::ExpectLogContainsSomewhere(log.entries(), 0,
+ log.GetEntries(&entries);
+ net::ExpectLogContainsSomewhere(entries, 0,
net::NetLog::TYPE_SSL_HANDSHAKE_ERROR,
net::NetLog::PHASE_NONE);
// We cannot test sock->IsConnected(), as the NSS implementation disconnects
// the socket when it encounters an error, whereas other implementations
// leave it connected.
- EXPECT_TRUE(LogContainsSSLConnectEndEvent(log.entries(), -1));
+ EXPECT_TRUE(LogContainsSSLConnectEndEvent(entries, -1));
}
diff --git a/net/socket/ssl_client_socket_win.cc b/net/socket/ssl_client_socket_win.cc
index 72d7492..1d8c039 100644
--- a/net/socket/ssl_client_socket_win.cc
+++ b/net/socket/ssl_client_socket_win.cc
@@ -8,8 +8,8 @@
#include <map>
#include "base/compiler_specific.h"
+#include "base/lazy_instance.h"
#include "base/lock.h"
-#include "base/singleton.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
@@ -110,12 +110,11 @@ static int MapSecurityError(SECURITY_STATUS err) {
//-----------------------------------------------------------------------------
// A bitmask consisting of these bit flags encodes which versions of the SSL
-// protocol (SSL 2.0, SSL 3.0, and TLS 1.0) are enabled.
+// protocol (SSL 3.0 and TLS 1.0) are enabled.
enum {
- SSL2 = 1 << 0,
- SSL3 = 1 << 1,
- TLS1 = 1 << 2,
- SSL_VERSION_MASKS = 1 << 3 // The number of SSL version bitmasks.
+ SSL3 = 1 << 0,
+ TLS1 = 1 << 1,
+ SSL_VERSION_MASKS = 1 << 2 // The number of SSL version bitmasks.
};
// CredHandleClass simply gives a default constructor and a destructor to
@@ -195,6 +194,9 @@ class CredHandleTable {
CredHandleMap client_cert_creds_;
};
+static base::LazyInstance<CredHandleTable> g_cred_handle_table(
+ base::LINKER_INITIALIZED);
+
// static
int CredHandleTable::InitializeHandle(CredHandle* handle,
PCCERT_CONTEXT client_cert,
@@ -210,8 +212,6 @@ int CredHandleTable::InitializeHandle(CredHandle* handle,
// The global system registry settings take precedence over the value of
// schannel_cred.grbitEnabledProtocols.
schannel_cred.grbitEnabledProtocols = 0;
- if (ssl_version_mask & SSL2)
- schannel_cred.grbitEnabledProtocols |= SP_PROT_SSL2;
if (ssl_version_mask & SSL3)
schannel_cred.grbitEnabledProtocols |= SP_PROT_SSL3;
if (ssl_version_mask & TLS1)
@@ -288,9 +288,9 @@ static int GetCredHandle(PCCERT_CONTEXT client_cert,
NOTREACHED();
return ERR_UNEXPECTED;
}
- return Singleton<CredHandleTable>::get()->GetHandle(client_cert,
- ssl_version_mask,
- handle_ptr);
+ return g_cred_handle_table.Get().GetHandle(client_cert,
+ ssl_version_mask,
+ handle_ptr);
}
//-----------------------------------------------------------------------------
@@ -359,6 +359,9 @@ class ClientCertStore {
HCERTSTORE store_;
};
+static base::LazyInstance<ClientCertStore> g_client_cert_store(
+ base::LINKER_INITIALIZED);
+
//-----------------------------------------------------------------------------
// Size of recv_buffer_
@@ -373,7 +376,8 @@ static const int kRecvBufferSize = (5 + 16*1024 + 64);
SSLClientSocketWin::SSLClientSocketWin(ClientSocketHandle* transport_socket,
const HostPortPair& host_and_port,
- const SSLConfig& ssl_config)
+ const SSLConfig& ssl_config,
+ CertVerifier* cert_verifier)
: ALLOW_THIS_IN_INITIALIZER_LIST(
handshake_io_callback_(this,
&SSLClientSocketWin::OnHandshakeIOComplete)),
@@ -390,6 +394,7 @@ SSLClientSocketWin::SSLClientSocketWin(ClientSocketHandle* transport_socket,
user_write_callback_(NULL),
user_write_buf_len_(0),
next_state_(STATE_NONE),
+ cert_verifier_(cert_verifier),
creds_(NULL),
isc_status_(SEC_E_OK),
payload_send_buffer_len_(0),
@@ -510,7 +515,7 @@ void SSLClientSocketWin::GetSSLCertRequestInfo(
// Copy it to our own certificate store, so that we can close the "MY"
// certificate store before returning from this function.
PCCERT_CONTEXT cert_context2 =
- Singleton<ClientCertStore>::get()->CopyCertContext(cert_context);
+ g_client_cert_store.Get().CopyCertContext(cert_context);
if (!cert_context2) {
NOTREACHED();
continue;
@@ -568,8 +573,6 @@ int SSLClientSocketWin::Connect(CompletionCallback* callback
int SSLClientSocketWin::InitializeSSLContext() {
int ssl_version_mask = 0;
- if (ssl_config_.ssl2_enabled)
- ssl_version_mask |= SSL2;
if (ssl_config_.ssl3_enabled)
ssl_version_mask |= SSL3;
if (ssl_config_.tls1_enabled)
@@ -1131,7 +1134,7 @@ int SSLClientSocketWin::DoVerifyCert() {
flags |= X509Certificate::VERIFY_REV_CHECKING_ENABLED;
if (ssl_config_.verify_ev_cert)
flags |= X509Certificate::VERIFY_EV_CERT;
- verifier_.reset(new CertVerifier);
+ verifier_.reset(new SingleRequestCertVerifier(cert_verifier_));
return verifier_->Verify(server_cert_, host_and_port_.host(), flags,
&server_cert_verify_result_,
&handshake_io_callback_);
diff --git a/net/socket/ssl_client_socket_win.h b/net/socket/ssl_client_socket_win.h
index 11d28a2..b927f8d 100644
--- a/net/socket/ssl_client_socket_win.h
+++ b/net/socket/ssl_client_socket_win.h
@@ -28,6 +28,7 @@ class BoundNetLog;
class CertVerifier;
class ClientSocketHandle;
class HostPortPair;
+class SingleRequestCertVerifier;
// An SSL client socket implemented with the Windows Schannel.
class SSLClientSocketWin : public SSLClientSocket {
@@ -40,7 +41,8 @@ class SSLClientSocketWin : public SSLClientSocket {
// the SSL settings.
SSLClientSocketWin(ClientSocketHandle* transport_socket,
const HostPortPair& host_and_port,
- const SSLConfig& ssl_config);
+ const SSLConfig& ssl_config,
+ CertVerifier* cert_verifier);
~SSLClientSocketWin();
// SSLClientSocket methods:
@@ -149,7 +151,8 @@ class SSLClientSocketWin : public SSLClientSocket {
SecPkgContext_StreamSizes stream_sizes_;
scoped_refptr<X509Certificate> server_cert_;
- scoped_ptr<CertVerifier> verifier_;
+ CertVerifier* const cert_verifier_;
+ scoped_ptr<SingleRequestCertVerifier> verifier_;
CertVerifyResult server_cert_verify_result_;
CredHandle* creds_;
diff --git a/net/socket/ssl_host_info.cc b/net/socket/ssl_host_info.cc
index 3fa9e35..f95c851 100644
--- a/net/socket/ssl_host_info.cc
+++ b/net/socket/ssl_host_info.cc
@@ -5,11 +5,12 @@
#include "net/socket/ssl_host_info.h"
#include "base/metrics/histogram.h"
+#include "base/pickle.h"
#include "base/string_piece.h"
-#include "net/base/cert_verifier.h"
#include "net/base/ssl_config_service.h"
#include "net/base/x509_certificate.h"
#include "net/socket/ssl_client_socket.h"
+<<<<<<< HEAD
#ifdef ANDROID
// the android platform build system use a fixed include path relative to the
// top directory (root of the source tree).
@@ -17,6 +18,8 @@
#else
#include "net/socket/ssl_host_info.pb.h"
#endif
+=======
+>>>>>>> chromium.org at r10.0.621.0
namespace net {
@@ -27,9 +30,16 @@ SSLHostInfo::State::State()
SSLHostInfo::State::~State() {}
+void SSLHostInfo::State::Clear() {
+ certs.clear();
+ server_hello.clear();
+ npn_valid = false;
+}
+
SSLHostInfo::SSLHostInfo(
const std::string& hostname,
- const SSLConfig& ssl_config)
+ const SSLConfig& ssl_config,
+ CertVerifier* cert_verifier)
: cert_verification_complete_(false),
cert_verification_error_(ERR_CERT_INVALID),
hostname_(hostname),
@@ -37,6 +47,7 @@ SSLHostInfo::SSLHostInfo(
cert_verification_callback_(NULL),
rev_checking_enabled_(ssl_config.rev_checking_enabled),
verify_ev_cert_(ssl_config.verify_ev_cert),
+ verifier_(cert_verifier),
callback_(new CancelableCompletionCallback<SSLHostInfo>(
ALLOW_THIS_IN_INITIALIZER_LIST(this),
&SSLHostInfo::VerifyCallback)) {
@@ -45,36 +56,6 @@ SSLHostInfo::SSLHostInfo(
SSLHostInfo::~SSLHostInfo() {}
-// This array and the next two functions serve to map between the internal NPN
-// status enum (which might change across versions) and the protocol buffer
-// based enum (which will not).
-static const struct {
- SSLClientSocket::NextProtoStatus npn_status;
- SSLHostInfoProto::NextProtoStatus proto_status;
-} kNPNStatusMapping[] = {
- { SSLClientSocket::kNextProtoUnsupported, SSLHostInfoProto::UNSUPPORTED },
- { SSLClientSocket::kNextProtoNegotiated, SSLHostInfoProto::NEGOTIATED },
- { SSLClientSocket::kNextProtoNoOverlap, SSLHostInfoProto::NO_OVERLAP },
-};
-
-static SSLClientSocket::NextProtoStatus NPNStatusFromProtoStatus(
- SSLHostInfoProto::NextProtoStatus proto_status) {
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kNPNStatusMapping) - 1; i++) {
- if (kNPNStatusMapping[i].proto_status == proto_status)
- return kNPNStatusMapping[i].npn_status;
- }
- return kNPNStatusMapping[ARRAYSIZE_UNSAFE(kNPNStatusMapping) - 1].npn_status;
-}
-
-static SSLHostInfoProto::NextProtoStatus ProtoStatusFromNPNStatus(
- SSLClientSocket::NextProtoStatus npn_status) {
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kNPNStatusMapping) - 1; i++) {
- if (kNPNStatusMapping[i].npn_status == npn_status)
- return kNPNStatusMapping[i].proto_status;
- }
- return kNPNStatusMapping[ARRAYSIZE_UNSAFE(kNPNStatusMapping)-1].proto_status;
-}
-
const SSLHostInfo::State& SSLHostInfo::state() const {
return state_;
}
@@ -84,25 +65,49 @@ SSLHostInfo::State* SSLHostInfo::mutable_state() {
}
bool SSLHostInfo::Parse(const std::string& data) {
- SSLHostInfoProto proto;
State* state = mutable_state();
- state->certs.clear();
- state->server_hello.clear();
- state->npn_valid = false;
+ state->Clear();
cert_verification_complete_ = false;
- if (!proto.ParseFromString(data))
+ bool r = ParseInner(data);
+ if (!r)
+ state->Clear();
+ return r;
+}
+
+bool SSLHostInfo::ParseInner(const std::string& data) {
+ State* state = mutable_state();
+
+ Pickle p(data.data(), data.size());
+ void* iter = NULL;
+
+ int num_der_certs;
+ if (!p.ReadInt(&iter, &num_der_certs) ||
+ num_der_certs < 0) {
return false;
+ }
- for (int i = 0; i < proto.certificate_der_size(); i++)
- state->certs.push_back(proto.certificate_der(i));
- if (proto.has_server_hello())
- state->server_hello = proto.server_hello();
- if (proto.has_npn_status() && proto.has_npn_protocol()) {
- state->npn_valid = true;
- state->npn_status = NPNStatusFromProtoStatus(proto.npn_status());
- state->npn_protocol = proto.npn_protocol();
+ for (int i = 0; i < num_der_certs; i++) {
+ std::string der_cert;
+ if (!p.ReadString(&iter, &der_cert))
+ return false;
+ state->certs.push_back(der_cert);
+ }
+
+ if (!p.ReadString(&iter, &state->server_hello))
+ return false;
+
+ if (!p.ReadBool(&iter, &state->npn_valid))
+ return false;
+
+ if (state->npn_valid) {
+ int status;
+ if (!p.ReadInt(&iter, &status) ||
+ !p.ReadString(&iter, &state->npn_protocol)) {
+ return false;
+ }
+ state->npn_status = static_cast<SSLClientSocket::NextProtoStatus>(status);
}
if (state->certs.size() > 0) {
@@ -116,13 +121,13 @@ bool SSLHostInfo::Parse(const std::string& data) {
flags |= X509Certificate::VERIFY_EV_CERT;
if (rev_checking_enabled_)
flags |= X509Certificate::VERIFY_REV_CHECKING_ENABLED;
- verifier_.reset(new CertVerifier);
VLOG(1) << "Kicking off verification for " << hostname_;
verification_start_time_ = base::TimeTicks::Now();
- if (verifier_->Verify(cert_.get(), hostname_, flags,
- &cert_verify_result_, callback_) == OK) {
- VerifyCallback(OK);
- }
+ verification_end_time_ = base::TimeTicks();
+ int rv = verifier_.Verify(cert_.get(), hostname_, flags,
+ &cert_verify_result_, callback_);
+ if (rv != ERR_IO_PENDING)
+ VerifyCallback(rv);
} else {
cert_parsing_failed_ = true;
DCHECK(!cert_verification_callback_);
@@ -133,21 +138,42 @@ bool SSLHostInfo::Parse(const std::string& data) {
}
std::string SSLHostInfo::Serialize() const {
- SSLHostInfoProto proto;
+ Pickle p(sizeof(Pickle::Header));
+
+ static const unsigned kMaxCertificatesSize = 32 * 1024;
+ unsigned der_certs_size = 0;
for (std::vector<std::string>::const_iterator
i = state_.certs.begin(); i != state_.certs.end(); i++) {
- proto.add_certificate_der(*i);
+ der_certs_size += i->size();
+ }
+
+ // We don't care to save the certificates over a certain size.
+ if (der_certs_size > kMaxCertificatesSize)
+ return "";
+
+ if (!p.WriteInt(state_.certs.size()))
+ return "";
+
+ for (std::vector<std::string>::const_iterator
+ i = state_.certs.begin(); i != state_.certs.end(); i++) {
+ if (!p.WriteString(*i))
+ return "";
+ }
+
+ if (!p.WriteString(state_.server_hello) ||
+ !p.WriteBool(state_.npn_valid)) {
+ return "";
}
- if (!state_.server_hello.empty())
- proto.set_server_hello(state_.server_hello);
if (state_.npn_valid) {
- proto.set_npn_status(ProtoStatusFromNPNStatus(state_.npn_status));
- proto.set_npn_protocol(state_.npn_protocol);
+ if (!p.WriteInt(state_.npn_status) ||
+ !p.WriteString(state_.npn_protocol)) {
+ return "";
+ }
}
- return proto.SerializeAsString();
+ return std::string(reinterpret_cast<const char *>(p.data()), p.size());
}
const CertVerifyResult& SSLHostInfo::cert_verify_result() const {
@@ -170,6 +196,7 @@ void SSLHostInfo::VerifyCallback(int rv) {
const base::TimeDelta duration = now - verification_start_time();
UMA_HISTOGRAM_TIMES("Net.SSLHostInfoVerificationTimeMs", duration);
VLOG(1) << "Verification took " << duration.InMilliseconds() << "ms";
+ verification_end_time_ = now;
cert_verification_complete_ = true;
cert_verification_error_ = rv;
if (cert_verification_callback_) {
diff --git a/net/socket/ssl_host_info.h b/net/socket/ssl_host_info.h
index 10b8cb6..8f1502b 100644
--- a/net/socket/ssl_host_info.h
+++ b/net/socket/ssl_host_info.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef NET_SOCKET_SSL_HOST_INFO_H
-#define NET_SOCKET_SSL_HOST_INFO_H
+#ifndef NET_SOCKET_SSL_HOST_INFO_H_
+#define NET_SOCKET_SSL_HOST_INFO_H_
#include <string>
#include <vector>
@@ -11,13 +11,13 @@
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "base/time.h"
+#include "net/base/cert_verifier.h"
#include "net/base/cert_verify_result.h"
#include "net/base/completion_callback.h"
#include "net/socket/ssl_client_socket.h"
namespace net {
-class CertVerifier;
class X509Certificate;
struct SSLConfig;
@@ -27,7 +27,9 @@ struct SSLConfig;
// certificates.
class SSLHostInfo {
public:
- SSLHostInfo(const std::string& hostname, const SSLConfig& ssl_config);
+ SSLHostInfo(const std::string& hostname,
+ const SSLConfig& ssl_config,
+ CertVerifier *certVerifier);
virtual ~SSLHostInfo();
// Start will commence the lookup. This must be called before any other
@@ -58,6 +60,8 @@ class SSLHostInfo {
State();
~State();
+ void Clear();
+
// certs is a vector of DER encoded X.509 certificates, as the server
// returned them and in the same order.
std::vector<std::string> certs;
@@ -85,15 +89,19 @@ class SSLHostInfo {
// WaitForCertVerification returns ERR_IO_PENDING if the certificate chain in
// |state().certs| is still being validated and arranges for the given
- // callback to be called when the verification completes. If the verification has
- // already finished then WaitForCertVerification returns the result of that
- // verification.
+ // callback to be called when the verification completes. If the verification
+ // has already finished then WaitForCertVerification returns the result of
+ // that verification.
int WaitForCertVerification(CompletionCallback* callback);
base::TimeTicks verification_start_time() const {
return verification_start_time_;
}
+ base::TimeTicks verification_end_time() const {
+ return verification_end_time_;
+ }
+
protected:
// Parse parses an opaque blob of data and fills out the public member fields
// of this object. It returns true iff the parse was successful. The public
@@ -108,6 +116,9 @@ class SSLHostInfo {
// This is the callback function which the CertVerifier calls via |callback_|.
void VerifyCallback(int rv);
+ // ParseInner is a helper function for Parse.
+ bool ParseInner(const std::string& data);
+
// This is the hostname that we'll validate the certificates against.
const std::string hostname_;
bool cert_parsing_failed_;
@@ -116,8 +127,9 @@ class SSLHostInfo {
bool rev_checking_enabled_;
bool verify_ev_cert_;
base::TimeTicks verification_start_time_;
+ base::TimeTicks verification_end_time_;
CertVerifyResult cert_verify_result_;
- scoped_ptr<CertVerifier> verifier_;
+ SingleRequestCertVerifier verifier_;
scoped_refptr<X509Certificate> cert_;
scoped_refptr<CancelableCompletionCallback<SSLHostInfo> > callback_;
};
@@ -134,4 +146,4 @@ class SSLHostInfoFactory {
} // namespace net
-#endif // NET_SOCKET_SSL_HOST_INFO_H
+#endif // NET_SOCKET_SSL_HOST_INFO_H_
diff --git a/net/socket/ssl_host_info.proto b/net/socket/ssl_host_info.proto
deleted file mode 100644
index d74a872..0000000
--- a/net/socket/ssl_host_info.proto
+++ /dev/null
@@ -1,34 +0,0 @@
-// 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.
-
-syntax = "proto2";
-
-option optimize_for = LITE_RUNTIME;
-
-package net;
-
-// SSLHostInfoProto contains information which we store about a given HTTPS
-// server.
-message SSLHostInfoProto {
- // The certificate chain, as returned by the server, as a series of DER
- // encoded X.509 certificates.
- repeated bytes certificate_der = 1;
- // The contents of the server's ServerHello message. Needed in order to
- // predict its response in the case of Snap Start.
- optional bytes server_hello = 2;
-
- // This is a mirror of SSLClientSocket::NextProtoStatus. We use this in order
- // to be robust against changes to that enum, which isn't required to be
- // stable across versions. See the comments there for details.
- enum NextProtoStatus {
- UNSUPPORTED = 0;
- NEGOTIATED = 1;
- NO_OVERLAP = 2;
- }
-
- // When doing Snap Start, we also need to know what protocol we expect the
- // server to negotiate.
- optional NextProtoStatus npn_status = 3;
- optional bytes npn_protocol = 4;
-};
diff --git a/net/socket/ssl_server_socket.h b/net/socket/ssl_server_socket.h
new file mode 100644
index 0000000..b689c71
--- /dev/null
+++ b/net/socket/ssl_server_socket.h
@@ -0,0 +1,53 @@
+// 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.
+
+#ifndef NET_SOCKET_SSL_SERVER_SOCKET_H_
+#define NET_SOCKET_SSL_SERVER_SOCKET_H_
+
+#include "base/basictypes.h"
+#include "net/base/completion_callback.h"
+#include "net/socket/socket.h"
+
+namespace base {
+class RSAPrivateKey;
+} // namespace base
+
+namespace net {
+
+class IOBuffer;
+struct SSLConfig;
+class X509Certificate;
+
+// SSLServerSocket takes an already connected socket and performs SSL on top of
+// it.
+//
+// This class is designed to work in a peer-to-peer connection and is not
+// intended to be used as a standalone SSL server.
+class SSLServerSocket : public Socket {
+ public:
+ virtual ~SSLServerSocket() {}
+
+ // Performs an SSL server handshake on the existing socket. The given socket
+ // must have already been connected.
+ //
+ // Accept either returns ERR_IO_PENDING, in which case the given callback
+ // will be called in the future with the real result, or it completes
+ // synchronously, returning the result immediately.
+ virtual int Accept(CompletionCallback* callback) = 0;
+};
+
+// Creates an SSL server socket using an already connected socket. A certificate
+// and private key needs to be provided.
+//
+// This created server socket will take ownership of |socket|. However |key|
+// is copied.
+// TODO(hclam): Defines ServerSocketFactory to create SSLServerSocket. This will
+// make mocking easier.
+SSLServerSocket* CreateSSLServerSocket(
+ Socket* socket, X509Certificate* certificate, base::RSAPrivateKey* key,
+ const SSLConfig& ssl_config);
+
+} // namespace net
+
+#endif // NET_SOCKET_SSL_SERVER_SOCKET_NSS_H_
diff --git a/net/socket/ssl_server_socket_nss.cc b/net/socket/ssl_server_socket_nss.cc
new file mode 100644
index 0000000..2e47fb8
--- /dev/null
+++ b/net/socket/ssl_server_socket_nss.cc
@@ -0,0 +1,677 @@
+// 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.
+
+#include "net/socket/ssl_server_socket_nss.h"
+
+#if defined(OS_WIN)
+#include <winsock2.h>
+#endif
+
+#if defined(USE_SYSTEM_SSL)
+#include <dlfcn.h>
+#endif
+#if defined(OS_MACOSX)
+#include <Security/Security.h>
+#endif
+#include <certdb.h>
+#include <cryptohi.h>
+#include <hasht.h>
+#include <keyhi.h>
+#include <nspr.h>
+#include <nss.h>
+#include <pk11pub.h>
+#include <secerr.h>
+#include <sechash.h>
+#include <ssl.h>
+#include <sslerr.h>
+#include <sslproto.h>
+
+#include <limits>
+
+#include "base/crypto/rsa_private_key.h"
+#include "base/nss_util_internal.h"
+#include "base/ref_counted.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_log.h"
+#include "net/ocsp/nss_ocsp.h"
+#include "net/socket/nss_ssl_util.h"
+#include "net/socket/ssl_error_params.h"
+
+static const int kRecvBufferSize = 4096;
+
+#define GotoState(s) next_handshake_state_ = s
+
+namespace net {
+
+SSLServerSocket* CreateSSLServerSocket(
+ Socket* socket, X509Certificate* cert, base::RSAPrivateKey* key,
+ const SSLConfig& ssl_config) {
+ return new SSLServerSocketNSS(socket, cert, key, ssl_config);
+}
+
+SSLServerSocketNSS::SSLServerSocketNSS(
+ Socket* transport_socket,
+ scoped_refptr<X509Certificate> cert,
+ base::RSAPrivateKey* key,
+ const SSLConfig& ssl_config)
+ : ALLOW_THIS_IN_INITIALIZER_LIST(buffer_send_callback_(
+ this, &SSLServerSocketNSS::BufferSendComplete)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(buffer_recv_callback_(
+ this, &SSLServerSocketNSS::BufferRecvComplete)),
+ transport_send_busy_(false),
+ transport_recv_busy_(false),
+ user_accept_callback_(NULL),
+ user_read_callback_(NULL),
+ user_write_callback_(NULL),
+ nss_fd_(NULL),
+ nss_bufs_(NULL),
+ transport_socket_(transport_socket),
+ ssl_config_(ssl_config),
+ cert_(cert),
+ next_handshake_state_(STATE_NONE),
+ completed_handshake_(false) {
+ ssl_config_.false_start_enabled = false;
+ ssl_config_.ssl3_enabled = true;
+ ssl_config_.tls1_enabled = true;
+
+ // TODO(hclam): Need a better way to clone a key.
+ std::vector<uint8> key_bytes;
+ CHECK(key->ExportPrivateKey(&key_bytes));
+ key_.reset(base::RSAPrivateKey::CreateFromPrivateKeyInfo(key_bytes));
+ CHECK(key_.get());
+}
+
+SSLServerSocketNSS::~SSLServerSocketNSS() {
+ if (nss_fd_ != NULL) {
+ PR_Close(nss_fd_);
+ nss_fd_ = NULL;
+ }
+}
+
+int SSLServerSocketNSS::Init() {
+ // Initialize the NSS SSL library in a threadsafe way. This also
+ // initializes the NSS base library.
+ EnsureNSSSSLInit();
+ if (!NSS_IsInitialized())
+ return ERR_UNEXPECTED;
+#if !defined(OS_MACOSX) && !defined(OS_WIN)
+ // We must call EnsureOCSPInit() here, on the IO thread, to get the IO loop
+ // by MessageLoopForIO::current().
+ // X509Certificate::Verify() runs on a worker thread of CertVerifier.
+ EnsureOCSPInit();
+#endif
+
+ return OK;
+}
+
+int SSLServerSocketNSS::Accept(CompletionCallback* callback) {
+ net_log_.BeginEvent(NetLog::TYPE_SSL_ACCEPT, NULL);
+
+ int rv = Init();
+ if (rv != OK) {
+ LOG(ERROR) << "Failed to initialize NSS";
+ net_log_.EndEvent(NetLog::TYPE_SSL_ACCEPT, NULL);
+ return rv;
+ }
+
+ rv = InitializeSSLOptions();
+ if (rv != OK) {
+ LOG(ERROR) << "Failed to initialize SSL options";
+ net_log_.EndEvent(NetLog::TYPE_SSL_ACCEPT, NULL);
+ return rv;
+ }
+
+ // Set peer address. TODO(hclam): This should be in a separate method.
+ PRNetAddr peername;
+ memset(&peername, 0, sizeof(peername));
+ peername.raw.family = AF_INET;
+ memio_SetPeerName(nss_fd_, &peername);
+
+ GotoState(STATE_HANDSHAKE);
+ rv = DoHandshakeLoop(net::OK);
+ if (rv == ERR_IO_PENDING) {
+ user_accept_callback_ = callback;
+ } else {
+ net_log_.EndEvent(NetLog::TYPE_SSL_ACCEPT, NULL);
+ }
+
+ return rv > OK ? OK : rv;
+}
+
+int SSLServerSocketNSS::Read(IOBuffer* buf, int buf_len,
+ CompletionCallback* callback) {
+ DCHECK(!user_read_callback_);
+ DCHECK(!user_accept_callback_);
+ DCHECK(!user_read_buf_);
+ DCHECK(nss_bufs_);
+
+ user_read_buf_ = buf;
+ user_read_buf_len_ = buf_len;
+
+ DCHECK(completed_handshake_);
+
+ int rv = DoReadLoop(OK);
+
+ if (rv == ERR_IO_PENDING) {
+ user_read_callback_ = callback;
+ } else {
+ user_read_buf_ = NULL;
+ user_read_buf_len_ = 0;
+ }
+ return rv;
+}
+
+int SSLServerSocketNSS::Write(IOBuffer* buf, int buf_len,
+ CompletionCallback* callback) {
+ DCHECK(!user_write_callback_);
+ DCHECK(!user_write_buf_);
+ DCHECK(nss_bufs_);
+
+ user_write_buf_ = buf;
+ user_write_buf_len_ = buf_len;
+
+ int rv = DoWriteLoop(OK);
+
+ if (rv == ERR_IO_PENDING) {
+ user_write_callback_ = callback;
+ } else {
+ user_write_buf_ = NULL;
+ user_write_buf_len_ = 0;
+ }
+ return rv;
+}
+
+// static
+// NSS calls this if an incoming certificate needs to be verified.
+// Do nothing but return SECSuccess.
+// This is called only in full handshake mode.
+// Peer certificate is retrieved in HandshakeCallback() later, which is called
+// in full handshake mode or in resumption handshake mode.
+SECStatus SSLServerSocketNSS::OwnAuthCertHandler(void* arg,
+ PRFileDesc* socket,
+ PRBool checksig,
+ PRBool is_server) {
+ // TODO(hclam): Implement.
+ // Tell NSS to not verify the certificate.
+ return SECSuccess;
+}
+
+// static
+// NSS calls this when handshake is completed.
+// After the SSL handshake is finished we need to verify the certificate.
+void SSLServerSocketNSS::HandshakeCallback(PRFileDesc* socket,
+ void* arg) {
+ // TODO(hclam): Implement.
+}
+
+int SSLServerSocketNSS::InitializeSSLOptions() {
+ // Transport connected, now hook it up to nss
+ // TODO(port): specify rx and tx buffer sizes separately
+ nss_fd_ = memio_CreateIOLayer(kRecvBufferSize);
+ if (nss_fd_ == NULL) {
+ return ERR_OUT_OF_MEMORY; // TODO(port): map NSPR error code.
+ }
+
+ // Grab pointer to buffers
+ nss_bufs_ = memio_GetSecret(nss_fd_);
+
+ /* Create SSL state machine */
+ /* Push SSL onto our fake I/O socket */
+ nss_fd_ = SSL_ImportFD(NULL, nss_fd_);
+ if (nss_fd_ == NULL) {
+ LogFailedNSSFunction(net_log_, "SSL_ImportFD", "");
+ return ERR_OUT_OF_MEMORY; // TODO(port): map NSPR/NSS error code.
+ }
+ // TODO(port): set more ssl options! Check errors!
+
+ int rv;
+
+ rv = SSL_OptionSet(nss_fd_, SSL_SECURITY, PR_TRUE);
+ if (rv != SECSuccess) {
+ LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_SECURITY");
+ return ERR_UNEXPECTED;
+ }
+
+ rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SSL2, PR_FALSE);
+ if (rv != SECSuccess) {
+ LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_ENABLE_SSL2");
+ return ERR_UNEXPECTED;
+ }
+
+ rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SSL3, PR_TRUE);
+ if (rv != SECSuccess) {
+ LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_ENABLE_SSL3");
+ return ERR_UNEXPECTED;
+ }
+
+ rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_TLS, ssl_config_.tls1_enabled);
+ if (rv != SECSuccess) {
+ LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_ENABLE_TLS");
+ return ERR_UNEXPECTED;
+ }
+
+ for (std::vector<uint16>::const_iterator it =
+ ssl_config_.disabled_cipher_suites.begin();
+ it != ssl_config_.disabled_cipher_suites.end(); ++it) {
+ // This will fail if the specified cipher is not implemented by NSS, but
+ // the failure is harmless.
+ SSL_CipherPrefSet(nss_fd_, *it, PR_FALSE);
+ }
+
+ // Server socket doesn't need session tickets.
+ rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SESSION_TICKETS, PR_FALSE);
+ if (rv != SECSuccess) {
+ LogFailedNSSFunction(
+ net_log_, "SSL_OptionSet", "SSL_ENABLE_SESSION_TICKETS");
+ }
+
+ // Doing this will force PR_Accept perform handshake as server.
+ rv = SSL_OptionSet(nss_fd_, SSL_HANDSHAKE_AS_CLIENT, PR_FALSE);
+ if (rv != SECSuccess) {
+ LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_HANDSHAKE_AS_CLIENT");
+ return ERR_UNEXPECTED;
+ }
+
+ rv = SSL_OptionSet(nss_fd_, SSL_HANDSHAKE_AS_SERVER, PR_TRUE);
+ if (rv != SECSuccess) {
+ LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_HANDSHAKE_AS_SERVER");
+ return ERR_UNEXPECTED;
+ }
+
+ rv = SSL_OptionSet(nss_fd_, SSL_REQUEST_CERTIFICATE, PR_FALSE);
+ if (rv != SECSuccess) {
+ LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_REQUEST_CERTIFICATE");
+ return ERR_UNEXPECTED;
+ }
+
+ rv = SSL_OptionSet(nss_fd_, SSL_REQUIRE_CERTIFICATE, PR_FALSE);
+ if (rv != SECSuccess) {
+ LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_REQUIRE_CERTIFICATE");
+ return ERR_UNEXPECTED;
+ }
+
+ rv = SSL_OptionSet(nss_fd_, SSL_NO_CACHE, PR_TRUE);
+ if (rv != SECSuccess) {
+ LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_NO_CACHE");
+ return ERR_UNEXPECTED;
+ }
+
+ rv = SSL_ConfigServerSessionIDCache(1024, 5, 5, NULL);
+ if (rv != SECSuccess) {
+ LogFailedNSSFunction(net_log_, "SSL_ConfigureServerSessionIDCache", "");
+ return ERR_UNEXPECTED;
+ }
+
+ rv = SSL_AuthCertificateHook(nss_fd_, OwnAuthCertHandler, this);
+ if (rv != SECSuccess) {
+ LogFailedNSSFunction(net_log_, "SSL_AuthCertificateHook", "");
+ return ERR_UNEXPECTED;
+ }
+
+ rv = SSL_HandshakeCallback(nss_fd_, HandshakeCallback, this);
+ if (rv != SECSuccess) {
+ LogFailedNSSFunction(net_log_, "SSL_HandshakeCallback", "");
+ return ERR_UNEXPECTED;
+ }
+
+ // Get a certificate of CERTCertificate structure.
+ std::string der_string;
+ if (!cert_->GetDEREncoded(&der_string))
+ return ERR_UNEXPECTED;
+
+ SECItem der_cert;
+ der_cert.data = reinterpret_cast<unsigned char*>(const_cast<char*>(
+ der_string.data()));
+ der_cert.len = der_string.length();
+ der_cert.type = siDERCertBuffer;
+
+ // Parse into a CERTCertificate structure.
+ CERTCertificate* cert = CERT_NewTempCertificate(
+ CERT_GetDefaultCertDB(), &der_cert, NULL, PR_FALSE, PR_TRUE);
+
+ // Get a key of SECKEYPrivateKey* structure.
+ std::vector<uint8> key_vector;
+ if (!key_->ExportPrivateKey(&key_vector)) {
+ CERT_DestroyCertificate(cert);
+ return ERR_UNEXPECTED;
+ }
+
+ SECKEYPrivateKeyStr* private_key = NULL;
+ PK11SlotInfo *slot = base::GetDefaultNSSKeySlot();
+ if (!slot) {
+ CERT_DestroyCertificate(cert);
+ return ERR_UNEXPECTED;
+ }
+
+ SECItem der_private_key_info;
+ der_private_key_info.data =
+ const_cast<unsigned char*>(&key_vector.front());
+ der_private_key_info.len = key_vector.size();
+ rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
+ slot, &der_private_key_info, NULL, NULL, PR_FALSE, PR_FALSE,
+ KU_DIGITAL_SIGNATURE, &private_key, NULL);
+ PK11_FreeSlot(slot);
+ if (rv != SECSuccess) {
+ CERT_DestroyCertificate(cert);
+ return ERR_UNEXPECTED;
+ }
+
+ // Assign server certificate and private key.
+ SSLKEAType cert_kea = NSS_FindCertKEAType(cert);
+ rv = SSL_ConfigSecureServer(nss_fd_, cert, private_key, cert_kea);
+ CERT_DestroyCertificate(cert);
+ SECKEY_DestroyPrivateKey(private_key);
+
+ if (rv != SECSuccess) {
+ PRErrorCode prerr = PR_GetError();
+ LOG(ERROR) << "Failed to config SSL server: " << prerr;
+ LogFailedNSSFunction(net_log_, "SSL_ConfigureSecureServer", "");
+ return ERR_UNEXPECTED;
+ }
+
+ // Tell SSL we're a server; needed if not letting NSPR do socket I/O
+ rv = SSL_ResetHandshake(nss_fd_, PR_TRUE);
+ if (rv != SECSuccess) {
+ LogFailedNSSFunction(net_log_, "SSL_ResetHandshake", "");
+ return ERR_UNEXPECTED;
+ }
+
+ return OK;
+}
+
+// Return 0 for EOF,
+// > 0 for bytes transferred immediately,
+// < 0 for error (or the non-error ERR_IO_PENDING).
+int SSLServerSocketNSS::BufferSend(void) {
+ if (transport_send_busy_)
+ return ERR_IO_PENDING;
+
+ const char* buf1;
+ const char* buf2;
+ unsigned int len1, len2;
+ memio_GetWriteParams(nss_bufs_, &buf1, &len1, &buf2, &len2);
+ const unsigned int len = len1 + len2;
+
+ int rv = 0;
+ if (len) {
+ scoped_refptr<IOBuffer> send_buffer(new IOBuffer(len));
+ memcpy(send_buffer->data(), buf1, len1);
+ memcpy(send_buffer->data() + len1, buf2, len2);
+ rv = transport_socket_->Write(send_buffer, len,
+ &buffer_send_callback_);
+ if (rv == ERR_IO_PENDING) {
+ transport_send_busy_ = true;
+ } else {
+ memio_PutWriteResult(nss_bufs_, MapErrorToNSS(rv));
+ }
+ }
+
+ return rv;
+}
+
+void SSLServerSocketNSS::BufferSendComplete(int result) {
+ memio_PutWriteResult(nss_bufs_, MapErrorToNSS(result));
+ transport_send_busy_ = false;
+ OnSendComplete(result);
+}
+
+int SSLServerSocketNSS::BufferRecv(void) {
+ if (transport_recv_busy_) return ERR_IO_PENDING;
+
+ char *buf;
+ int nb = memio_GetReadParams(nss_bufs_, &buf);
+ int rv;
+ if (!nb) {
+ // buffer too full to read into, so no I/O possible at moment
+ rv = ERR_IO_PENDING;
+ } else {
+ recv_buffer_ = new IOBuffer(nb);
+ rv = transport_socket_->Read(recv_buffer_, nb, &buffer_recv_callback_);
+ if (rv == ERR_IO_PENDING) {
+ transport_recv_busy_ = true;
+ } else {
+ if (rv > 0)
+ memcpy(buf, recv_buffer_->data(), rv);
+ memio_PutReadResult(nss_bufs_, MapErrorToNSS(rv));
+ recv_buffer_ = NULL;
+ }
+ }
+ return rv;
+}
+
+void SSLServerSocketNSS::BufferRecvComplete(int result) {
+ if (result > 0) {
+ char *buf;
+ memio_GetReadParams(nss_bufs_, &buf);
+ memcpy(buf, recv_buffer_->data(), result);
+ }
+ recv_buffer_ = NULL;
+ memio_PutReadResult(nss_bufs_, MapErrorToNSS(result));
+ transport_recv_busy_ = false;
+ OnRecvComplete(result);
+}
+
+void SSLServerSocketNSS::OnSendComplete(int result) {
+ if (next_handshake_state_ == STATE_HANDSHAKE) {
+ // In handshake phase.
+ OnHandshakeIOComplete(result);
+ return;
+ }
+
+ if (!user_write_buf_ || !completed_handshake_)
+ return;
+
+ int rv = DoWriteLoop(result);
+ if (rv != ERR_IO_PENDING)
+ DoWriteCallback(rv);
+}
+
+void SSLServerSocketNSS::OnRecvComplete(int result) {
+ if (next_handshake_state_ == STATE_HANDSHAKE) {
+ // In handshake phase.
+ OnHandshakeIOComplete(result);
+ return;
+ }
+
+ // Network layer received some data, check if client requested to read
+ // decrypted data.
+ if (!user_read_buf_ || !completed_handshake_)
+ return;
+
+ int rv = DoReadLoop(result);
+ if (rv != ERR_IO_PENDING)
+ DoReadCallback(rv);
+}
+
+void SSLServerSocketNSS::OnHandshakeIOComplete(int result) {
+ int rv = DoHandshakeLoop(result);
+ if (rv != ERR_IO_PENDING) {
+ net_log_.EndEvent(net::NetLog::TYPE_SSL_ACCEPT, NULL);
+ if (user_accept_callback_)
+ DoAcceptCallback(rv);
+ }
+}
+
+void SSLServerSocketNSS::DoAcceptCallback(int rv) {
+ DCHECK_NE(rv, ERR_IO_PENDING);
+
+ CompletionCallback* c = user_accept_callback_;
+ user_accept_callback_ = NULL;
+ c->Run(rv > OK ? OK : rv);
+}
+
+void SSLServerSocketNSS::DoReadCallback(int rv) {
+ DCHECK(rv != ERR_IO_PENDING);
+ DCHECK(user_read_callback_);
+
+ // Since Run may result in Read being called, clear |user_read_callback_|
+ // up front.
+ CompletionCallback* c = user_read_callback_;
+ user_read_callback_ = NULL;
+ user_read_buf_ = NULL;
+ user_read_buf_len_ = 0;
+ c->Run(rv);
+}
+
+void SSLServerSocketNSS::DoWriteCallback(int rv) {
+ DCHECK(rv != ERR_IO_PENDING);
+ DCHECK(user_write_callback_);
+
+ // Since Run may result in Write being called, clear |user_write_callback_|
+ // up front.
+ CompletionCallback* c = user_write_callback_;
+ user_write_callback_ = NULL;
+ user_write_buf_ = NULL;
+ user_write_buf_len_ = 0;
+ c->Run(rv);
+}
+
+// Do network I/O between the given buffer and the given socket.
+// Return true if some I/O performed, false otherwise (error or ERR_IO_PENDING)
+bool SSLServerSocketNSS::DoTransportIO() {
+ bool network_moved = false;
+ if (nss_bufs_ != NULL) {
+ int nsent = BufferSend();
+ int nreceived = BufferRecv();
+ network_moved = (nsent > 0 || nreceived >= 0);
+ }
+ return network_moved;
+}
+
+int SSLServerSocketNSS::DoPayloadRead() {
+ DCHECK(user_read_buf_);
+ DCHECK_GT(user_read_buf_len_, 0);
+ int rv = PR_Read(nss_fd_, user_read_buf_->data(), user_read_buf_len_);
+ if (rv >= 0)
+ return rv;
+ PRErrorCode prerr = PR_GetError();
+ if (prerr == PR_WOULD_BLOCK_ERROR) {
+ return ERR_IO_PENDING;
+ }
+ rv = MapNSSError(prerr);
+ net_log_.AddEvent(NetLog::TYPE_SSL_READ_ERROR,
+ make_scoped_refptr(new SSLErrorParams(rv, prerr)));
+ return rv;
+}
+
+int SSLServerSocketNSS::DoPayloadWrite() {
+ DCHECK(user_write_buf_);
+ int rv = PR_Write(nss_fd_, user_write_buf_->data(), user_write_buf_len_);
+ if (rv >= 0)
+ return rv;
+ PRErrorCode prerr = PR_GetError();
+ if (prerr == PR_WOULD_BLOCK_ERROR) {
+ return ERR_IO_PENDING;
+ }
+ rv = MapNSSError(prerr);
+ net_log_.AddEvent(NetLog::TYPE_SSL_WRITE_ERROR,
+ make_scoped_refptr(new SSLErrorParams(rv, prerr)));
+ return rv;
+}
+
+int SSLServerSocketNSS::DoHandshakeLoop(int last_io_result) {
+ bool network_moved;
+ int rv = last_io_result;
+ do {
+ // Default to STATE_NONE for next state.
+ // (This is a quirk carried over from the windows
+ // implementation. It makes reading the logs a bit harder.)
+ // State handlers can and often do call GotoState just
+ // to stay in the current state.
+ State state = next_handshake_state_;
+ GotoState(STATE_NONE);
+ switch (state) {
+ case STATE_NONE:
+ // we're just pumping data between the buffer and the network
+ break;
+ case STATE_HANDSHAKE:
+ rv = DoHandshake();
+ break;
+ default:
+ rv = ERR_UNEXPECTED;
+ LOG(DFATAL) << "unexpected state " << state;
+ break;
+ }
+
+ // Do the actual network I/O
+ network_moved = DoTransportIO();
+ } while ((rv != ERR_IO_PENDING || network_moved) &&
+ next_handshake_state_ != STATE_NONE);
+ return rv;
+}
+
+int SSLServerSocketNSS::DoReadLoop(int result) {
+ DCHECK(completed_handshake_);
+ DCHECK(next_handshake_state_ == STATE_NONE);
+
+ if (result < 0)
+ return result;
+
+ if (!nss_bufs_) {
+ LOG(DFATAL) << "!nss_bufs_";
+ int rv = ERR_UNEXPECTED;
+ net_log_.AddEvent(NetLog::TYPE_SSL_READ_ERROR,
+ make_scoped_refptr(new SSLErrorParams(rv, 0)));
+ return rv;
+ }
+
+ bool network_moved;
+ int rv;
+ do {
+ rv = DoPayloadRead();
+ network_moved = DoTransportIO();
+ } while (rv == ERR_IO_PENDING && network_moved);
+ return rv;
+}
+
+int SSLServerSocketNSS::DoWriteLoop(int result) {
+ DCHECK(completed_handshake_);
+ DCHECK(next_handshake_state_ == STATE_NONE);
+
+ if (result < 0)
+ return result;
+
+ if (!nss_bufs_) {
+ LOG(DFATAL) << "!nss_bufs_";
+ int rv = ERR_UNEXPECTED;
+ net_log_.AddEvent(NetLog::TYPE_SSL_WRITE_ERROR,
+ make_scoped_refptr(new SSLErrorParams(rv, 0)));
+ return rv;
+ }
+
+ bool network_moved;
+ int rv;
+ do {
+ rv = DoPayloadWrite();
+ network_moved = DoTransportIO();
+ } while (rv == ERR_IO_PENDING && network_moved);
+ return rv;
+}
+
+int SSLServerSocketNSS::DoHandshake() {
+ int net_error = net::OK;
+ SECStatus rv = SSL_ForceHandshake(nss_fd_);
+
+ if (rv == SECSuccess) {
+ completed_handshake_ = true;
+ } else {
+ PRErrorCode prerr = PR_GetError();
+ net_error = MapNSSHandshakeError(prerr);
+
+ // If not done, stay in this state
+ if (net_error == ERR_IO_PENDING) {
+ GotoState(STATE_HANDSHAKE);
+ } else {
+ LOG(ERROR) << "handshake failed; NSS error code " << prerr
+ << ", net_error " << net_error;
+ net_log_.AddEvent(
+ NetLog::TYPE_SSL_HANDSHAKE_ERROR,
+ make_scoped_refptr(new SSLErrorParams(net_error, prerr)));
+ }
+ }
+ return net_error;
+}
+
+} // namespace net
diff --git a/net/socket/ssl_server_socket_nss.h b/net/socket/ssl_server_socket_nss.h
new file mode 100644
index 0000000..3883c9b
--- /dev/null
+++ b/net/socket/ssl_server_socket_nss.h
@@ -0,0 +1,133 @@
+// Copyright (c) 2006-2009 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 NET_SOCKET_SSL_SERVER_SOCKET_NSS_H_
+#define NET_SOCKET_SSL_SERVER_SOCKET_NSS_H_
+#pragma once
+
+#include <certt.h>
+#include <keyt.h>
+#include <nspr.h>
+#include <nss.h>
+
+#include "base/scoped_ptr.h"
+#include "net/base/completion_callback.h"
+#include "net/base/host_port_pair.h"
+#include "net/base/net_log.h"
+#include "net/base/nss_memio.h"
+#include "net/base/ssl_config_service.h"
+#include "net/socket/ssl_server_socket.h"
+
+namespace net {
+
+class SSLServerSocketNSS : public SSLServerSocket {
+ public:
+ // This object takes ownership of the following parameters:
+ // |socket| - A socket that is already connected.
+ // |cert| - The certificate to be used by the server.
+ //
+ // The following parameters are copied in the constructor.
+ // |ssl_config| - Options for SSL socket.
+ // |key| - The private key used by the server.
+ SSLServerSocketNSS(Socket* transport_socket,
+ scoped_refptr<X509Certificate> cert,
+ base::RSAPrivateKey* key,
+ const SSLConfig& ssl_config);
+ virtual ~SSLServerSocketNSS();
+
+ // SSLServerSocket implementation.
+ virtual int Accept(CompletionCallback* callback);
+ virtual int Read(IOBuffer* buf, int buf_len,
+ CompletionCallback* callback);
+ virtual int Write(IOBuffer* buf, int buf_len,
+ CompletionCallback* callback);
+ virtual bool SetReceiveBufferSize(int32 size) { return false; }
+ virtual bool SetSendBufferSize(int32 size) { return false; }
+
+ private:
+ virtual int Init();
+
+ int InitializeSSLOptions();
+
+ void OnSendComplete(int result);
+ void OnRecvComplete(int result);
+ void OnHandshakeIOComplete(int result);
+
+ int BufferSend();
+ void BufferSendComplete(int result);
+ int BufferRecv();
+ void BufferRecvComplete(int result);
+ bool DoTransportIO();
+ int DoPayloadWrite();
+ int DoPayloadRead();
+
+ int DoHandshakeLoop(int last_io_result);
+ int DoReadLoop(int result);
+ int DoWriteLoop(int result);
+ int DoHandshake();
+ void DoAcceptCallback(int result);
+ void DoReadCallback(int result);
+ void DoWriteCallback(int result);
+
+ static SECStatus OwnAuthCertHandler(void* arg,
+ PRFileDesc* socket,
+ PRBool checksig,
+ PRBool is_server);
+ static void HandshakeCallback(PRFileDesc* socket, void* arg);
+
+ // Members used to send and receive buffer.
+ CompletionCallbackImpl<SSLServerSocketNSS> buffer_send_callback_;
+ CompletionCallbackImpl<SSLServerSocketNSS> buffer_recv_callback_;
+ bool transport_send_busy_;
+ bool transport_recv_busy_;
+
+ scoped_refptr<IOBuffer> recv_buffer_;
+
+ BoundNetLog net_log_;
+
+ CompletionCallback* user_accept_callback_;
+ CompletionCallback* user_read_callback_;
+ CompletionCallback* user_write_callback_;
+
+ // Used by Read function.
+ scoped_refptr<IOBuffer> user_read_buf_;
+ int user_read_buf_len_;
+
+ // Used by Write function.
+ scoped_refptr<IOBuffer> user_write_buf_;
+ int user_write_buf_len_;
+
+ // The NSS SSL state machine
+ PRFileDesc* nss_fd_;
+
+ // Buffers for the network end of the SSL state machine
+ memio_Private* nss_bufs_;
+
+ // Socket for sending and receiving data.
+ scoped_ptr<Socket> transport_socket_;
+
+ // Options for the SSL socket.
+ // TODO(hclam): This memeber is currently not used. Should make use of this
+ // member to configure the socket.
+ SSLConfig ssl_config_;
+
+ // Certificate for the server.
+ scoped_refptr<X509Certificate> cert_;
+
+ // Private key used by the server.
+ scoped_ptr<base::RSAPrivateKey> key_;
+
+ enum State {
+ STATE_NONE,
+ STATE_HANDSHAKE,
+ };
+ State next_handshake_state_;
+ bool completed_handshake_;
+
+ DISALLOW_COPY_AND_ASSIGN(SSLServerSocketNSS);
+};
+
+} // namespace net
+
+#endif // NET_SOCKET_SSL_SERVER_SOCKET_NSS_H_
diff --git a/net/socket/ssl_server_socket_unittest.cc b/net/socket/ssl_server_socket_unittest.cc
new file mode 100644
index 0000000..781a3f4
--- /dev/null
+++ b/net/socket/ssl_server_socket_unittest.cc
@@ -0,0 +1,369 @@
+// 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.
+
+// This test suite uses SSLClientSocket to test the implementation of
+// SSLServerSocket. In order to establish connections between the sockets
+// we need two additional classes:
+// 1. FakeSocket
+// Connects SSL socket to FakeDataChannel. This class is just a stub.
+//
+// 2. FakeDataChannel
+// Implements the actual exchange of data between two FakeSockets.
+//
+// Implementations of these two classes are included in this file.
+
+#include "net/socket/ssl_server_socket.h"
+
+#include <queue>
+
+#include "base/crypto/rsa_private_key.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/nss_util.h"
+#include "base/path_service.h"
+#include "net/base/address_list.h"
+#include "net/base/cert_verifier.h"
+#include "net/base/host_port_pair.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_log.h"
+#include "net/base/ssl_config_service.h"
+#include "net/base/x509_certificate.h"
+#include "net/socket/client_socket.h"
+#include "net/socket/client_socket_factory.h"
+#include "net/socket/socket_test_util.h"
+#include "net/socket/ssl_client_socket.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace net {
+
+namespace {
+
+class FakeDataChannel {
+ public:
+ FakeDataChannel() : read_callback_(NULL), read_buf_len_(0) {
+ }
+
+ virtual int Read(IOBuffer* buf, int buf_len,
+ CompletionCallback* callback) {
+ if (data_.empty()) {
+ read_callback_ = callback;
+ read_buf_ = buf;
+ read_buf_len_ = buf_len;
+ return net::ERR_IO_PENDING;
+ }
+ return PropogateData(buf, buf_len);
+ }
+
+ virtual int Write(IOBuffer* buf, int buf_len,
+ CompletionCallback* callback) {
+ data_.push(new net::DrainableIOBuffer(buf, buf_len));
+ DoReadCallback();
+ return buf_len;
+ }
+
+ private:
+ void DoReadCallback() {
+ if (!read_callback_)
+ return;
+
+ int copied = PropogateData(read_buf_, read_buf_len_);
+ net::CompletionCallback* callback = read_callback_;
+ read_callback_ = NULL;
+ read_buf_ = NULL;
+ read_buf_len_ = 0;
+ callback->Run(copied);
+ }
+
+ int PropogateData(scoped_refptr<net::IOBuffer> read_buf, int read_buf_len) {
+ scoped_refptr<net::DrainableIOBuffer> buf = data_.front();
+ int copied = std::min(buf->BytesRemaining(), read_buf_len);
+ memcpy(read_buf->data(), buf->data(), copied);
+ buf->DidConsume(copied);
+
+ if (!buf->BytesRemaining())
+ data_.pop();
+ return copied;
+ }
+
+ net::CompletionCallback* read_callback_;
+ scoped_refptr<net::IOBuffer> read_buf_;
+ int read_buf_len_;
+
+ std::queue<scoped_refptr<net::DrainableIOBuffer> > data_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeDataChannel);
+};
+
+class FakeSocket : public ClientSocket {
+ public:
+ FakeSocket(FakeDataChannel* incoming_channel,
+ FakeDataChannel* outgoing_channel)
+ : incoming_(incoming_channel),
+ outgoing_(outgoing_channel) {
+ }
+
+ virtual ~FakeSocket() {
+
+ }
+
+ virtual int Read(IOBuffer* buf, int buf_len,
+ CompletionCallback* callback) {
+ return incoming_->Read(buf, buf_len, callback);
+ }
+
+ virtual int Write(IOBuffer* buf, int buf_len,
+ CompletionCallback* callback) {
+ return outgoing_->Write(buf, buf_len, callback);
+ }
+
+ virtual bool SetReceiveBufferSize(int32 size) {
+ return true;
+ }
+
+ virtual bool SetSendBufferSize(int32 size) {
+ return true;
+ }
+
+ virtual int Connect(CompletionCallback* callback) {
+ return net::OK;
+ }
+
+ virtual void Disconnect() {}
+
+ virtual bool IsConnected() const {
+ return true;
+ }
+
+ virtual bool IsConnectedAndIdle() const {
+ return true;
+ }
+
+ virtual int GetPeerAddress(AddressList* address) const {
+ net::IPAddressNumber ip_address(4);
+ *address = net::AddressList(ip_address, 0, false);
+ return net::OK;
+ }
+
+ virtual const BoundNetLog& NetLog() const {
+ return net_log_;
+ }
+
+ virtual void SetSubresourceSpeculation() {}
+ virtual void SetOmniboxSpeculation() {}
+
+ virtual bool WasEverUsed() const {
+ return true;
+ }
+
+ virtual bool UsingTCPFastOpen() const {
+ return false;
+ }
+
+ private:
+ net::BoundNetLog net_log_;
+ FakeDataChannel* incoming_;
+ FakeDataChannel* outgoing_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeSocket);
+};
+
+} // namespace
+
+// Verify the correctness of the test helper classes first.
+TEST(FakeSocketTest, DataTransfer) {
+ // Establish channels between two sockets.
+ FakeDataChannel channel_1;
+ FakeDataChannel channel_2;
+ FakeSocket client(&channel_1, &channel_2);
+ FakeSocket server(&channel_2, &channel_1);
+
+ const char kTestData[] = "testing123";
+ const int kTestDataSize = strlen(kTestData);
+ const int kReadBufSize = 1024;
+ scoped_refptr<net::IOBuffer> write_buf = new net::StringIOBuffer(kTestData);
+ scoped_refptr<net::IOBuffer> read_buf = new net::IOBuffer(kReadBufSize);
+
+ // Write then read.
+ EXPECT_EQ(kTestDataSize, server.Write(write_buf, kTestDataSize, NULL));
+ EXPECT_EQ(kTestDataSize, client.Read(read_buf, kReadBufSize, NULL));
+ EXPECT_EQ(0, memcmp(kTestData, read_buf->data(), kTestDataSize));
+
+ // Read then write.
+ TestCompletionCallback callback;
+ EXPECT_EQ(net::ERR_IO_PENDING,
+ server.Read(read_buf, kReadBufSize, &callback));
+ EXPECT_EQ(kTestDataSize, client.Write(write_buf, kTestDataSize, NULL));
+ EXPECT_EQ(kTestDataSize, callback.WaitForResult());
+ EXPECT_EQ(0, memcmp(kTestData, read_buf->data(), kTestDataSize));
+}
+
+class SSLServerSocketTest : public PlatformTest {
+ public:
+ SSLServerSocketTest()
+ : socket_factory_(net::ClientSocketFactory::GetDefaultFactory()) {
+ }
+
+ protected:
+ void Initialize() {
+ FakeSocket* fake_client_socket = new FakeSocket(&channel_1_, &channel_2_);
+ FakeSocket* fake_server_socket = new FakeSocket(&channel_2_, &channel_1_);
+
+ FilePath certs_dir;
+ PathService::Get(base::DIR_SOURCE_ROOT, &certs_dir);
+ certs_dir = certs_dir.AppendASCII("net");
+ certs_dir = certs_dir.AppendASCII("data");
+ certs_dir = certs_dir.AppendASCII("ssl");
+ certs_dir = certs_dir.AppendASCII("certificates");
+
+ FilePath cert_path = certs_dir.AppendASCII("unittest.selfsigned.der");
+ std::string cert_der;
+ ASSERT_TRUE(file_util::ReadFileToString(cert_path, &cert_der));
+
+ scoped_refptr<net::X509Certificate> cert =
+ X509Certificate::CreateFromBytes(cert_der.data(), cert_der.size());
+
+ FilePath key_path = certs_dir.AppendASCII("unittest.key.bin");
+ std::string key_string;
+ ASSERT_TRUE(file_util::ReadFileToString(key_path, &key_string));
+ std::vector<uint8> key_vector(
+ reinterpret_cast<const uint8*>(key_string.data()),
+ reinterpret_cast<const uint8*>(key_string.data() +
+ key_string.length()));
+
+ scoped_ptr<base::RSAPrivateKey> private_key(
+ base::RSAPrivateKey::CreateFromPrivateKeyInfo(key_vector));
+
+ net::SSLConfig ssl_config;
+ ssl_config.false_start_enabled = false;
+ ssl_config.snap_start_enabled = false;
+ ssl_config.ssl3_enabled = true;
+ ssl_config.tls1_enabled = true;
+ ssl_config.session_resume_disabled = true;
+
+ // Certificate provided by the host doesn't need authority.
+ net::SSLConfig::CertAndStatus cert_and_status;
+ cert_and_status.cert_status = net::ERR_CERT_AUTHORITY_INVALID;
+ cert_and_status.cert = cert;
+ ssl_config.allowed_bad_certs.push_back(cert_and_status);
+
+ net::HostPortPair host_and_pair("unittest", 0);
+ client_socket_.reset(
+ socket_factory_->CreateSSLClientSocket(
+ fake_client_socket, host_and_pair, ssl_config, NULL,
+ &cert_verifier_));
+ server_socket_.reset(net::CreateSSLServerSocket(fake_server_socket,
+ cert, private_key.get(),
+ net::SSLConfig()));
+ }
+
+ FakeDataChannel channel_1_;
+ FakeDataChannel channel_2_;
+ scoped_ptr<net::SSLClientSocket> client_socket_;
+ scoped_ptr<net::SSLServerSocket> server_socket_;
+ net::ClientSocketFactory* socket_factory_;
+ net::CertVerifier cert_verifier_;
+};
+
+// SSLServerSocket is only implemented using NSS.
+#if defined(USE_NSS) || defined(OS_WIN) || defined(OS_MACOSX)
+
+// This test only executes creation of client and server sockets. This is to
+// test that creation of sockets doesn't crash and have minimal code to run
+// under valgrind in order to help debugging memory problems.
+TEST_F(SSLServerSocketTest, Initialize) {
+ Initialize();
+}
+
+// This test executes Connect() of SSLClientSocket and Accept() of
+// SSLServerSocket to make sure handshaking between the two sockets are
+// completed successfully.
+TEST_F(SSLServerSocketTest, Handshake) {
+ Initialize();
+
+ if (!base::CheckNSSVersion("3.12.8"))
+ return;
+
+ TestCompletionCallback connect_callback;
+ TestCompletionCallback accept_callback;
+
+ int server_ret = server_socket_->Accept(&accept_callback);
+ EXPECT_TRUE(server_ret == net::OK || server_ret == net::ERR_IO_PENDING);
+
+ int client_ret = client_socket_->Connect(&connect_callback);
+ EXPECT_TRUE(client_ret == net::OK || client_ret == net::ERR_IO_PENDING);
+
+ if (client_ret == net::ERR_IO_PENDING) {
+ EXPECT_EQ(net::OK, connect_callback.WaitForResult());
+ }
+ if (server_ret == net::ERR_IO_PENDING) {
+ EXPECT_EQ(net::OK, accept_callback.WaitForResult());
+ }
+}
+
+TEST_F(SSLServerSocketTest, DataTransfer) {
+ Initialize();
+
+ if (!base::CheckNSSVersion("3.12.8"))
+ return;
+
+ TestCompletionCallback connect_callback;
+ TestCompletionCallback accept_callback;
+
+ // Establish connection.
+ int client_ret = client_socket_->Connect(&connect_callback);
+ EXPECT_TRUE(client_ret == net::OK || client_ret == net::ERR_IO_PENDING);
+
+ int server_ret = server_socket_->Accept(&accept_callback);
+ EXPECT_TRUE(server_ret == net::OK || server_ret == net::ERR_IO_PENDING);
+
+ if (client_ret == net::ERR_IO_PENDING) {
+ EXPECT_EQ(net::OK, connect_callback.WaitForResult());
+ }
+ if (server_ret == net::ERR_IO_PENDING) {
+ EXPECT_EQ(net::OK, accept_callback.WaitForResult());
+ }
+
+ const int kReadBufSize = 1024;
+ scoped_refptr<net::StringIOBuffer> write_buf =
+ new net::StringIOBuffer("testing123");
+ scoped_refptr<net::IOBuffer> read_buf = new net::IOBuffer(kReadBufSize);
+
+ // Write then read.
+ TestCompletionCallback write_callback;
+ TestCompletionCallback read_callback;
+ server_ret = server_socket_->Write(write_buf, write_buf->size(),
+ &write_callback);
+ EXPECT_TRUE(server_ret > 0 || server_ret == net::ERR_IO_PENDING);
+ client_ret = client_socket_->Read(read_buf, kReadBufSize, &read_callback);
+ EXPECT_TRUE(client_ret > 0 || client_ret == net::ERR_IO_PENDING);
+
+ if (server_ret == net::ERR_IO_PENDING) {
+ EXPECT_GT(write_callback.WaitForResult(), 0);
+ }
+ if (client_ret == net::ERR_IO_PENDING) {
+ EXPECT_GT(read_callback.WaitForResult(), 0);
+ }
+ EXPECT_EQ(0, memcmp(write_buf->data(), read_buf->data(), write_buf->size()));
+
+ // Read then write.
+ write_buf = new net::StringIOBuffer("hello123");
+ server_ret = server_socket_->Read(read_buf, kReadBufSize, &read_callback);
+ EXPECT_TRUE(server_ret > 0 || server_ret == net::ERR_IO_PENDING);
+ client_ret = client_socket_->Write(write_buf, write_buf->size(),
+ &write_callback);
+ EXPECT_TRUE(client_ret > 0 || client_ret == net::ERR_IO_PENDING);
+
+ if (server_ret == net::ERR_IO_PENDING) {
+ EXPECT_GT(read_callback.WaitForResult(), 0);
+ }
+ if (client_ret == net::ERR_IO_PENDING) {
+ EXPECT_GT(write_callback.WaitForResult(), 0);
+ }
+ EXPECT_EQ(0, memcmp(write_buf->data(), read_buf->data(), write_buf->size()));
+}
+#endif
+
+} // namespace net
diff --git a/net/socket/tcp_client_socket_libevent.cc b/net/socket/tcp_client_socket_libevent.cc
index ccaa834..ca8b5fd 100644
--- a/net/socket/tcp_client_socket_libevent.cc
+++ b/net/socket/tcp_client_socket_libevent.cc
@@ -657,6 +657,10 @@ int TCPClientSocketLibevent::GetPeerAddress(AddressList* address) const {
return OK;
}
+const BoundNetLog& TCPClientSocketLibevent::NetLog() const {
+ return net_log_;
+}
+
void TCPClientSocketLibevent::SetSubresourceSpeculation() {
use_history_.set_subresource_speculation();
}
diff --git a/net/socket/tcp_client_socket_libevent.h b/net/socket/tcp_client_socket_libevent.h
index b5e4f55..1f3434b 100644
--- a/net/socket/tcp_client_socket_libevent.h
+++ b/net/socket/tcp_client_socket_libevent.h
@@ -49,7 +49,7 @@ class TCPClientSocketLibevent : public ClientSocket, NonThreadSafe {
virtual bool IsConnected() const;
virtual bool IsConnectedAndIdle() const;
virtual int GetPeerAddress(AddressList* address) const;
- virtual const BoundNetLog& NetLog() const { return net_log_; }
+ virtual const BoundNetLog& NetLog() const;
virtual void SetSubresourceSpeculation();
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
diff --git a/net/socket/tcp_client_socket_pool.cc b/net/socket/tcp_client_socket_pool.cc
index 10acc76..d490111 100644
--- a/net/socket/tcp_client_socket_pool.cc
+++ b/net/socket/tcp_client_socket_pool.cc
@@ -46,6 +46,18 @@ TCPSocketParams::TCPSocketParams(const std::string& host, int port,
TCPSocketParams::~TCPSocketParams() {}
+void TCPSocketParams::Initialize(RequestPriority priority,
+ const GURL& referrer,
+ bool disable_resolver_cache) {
+ // The referrer is used by the DNS prefetch system to correlate resolutions
+ // with the page that triggered them. It doesn't impact the actual addresses
+ // that we resolve to.
+ destination_.set_referrer(referrer);
+ destination_.set_priority(priority);
+ if (disable_resolver_cache)
+ destination_.set_allow_cached_response(false);
+}
+
// TCPConnectJobs will time out after this many seconds. Note this is the total
// time, including both host resolution and TCP connect() times.
//
@@ -284,6 +296,10 @@ void TCPClientSocketPool::CloseIdleSockets() {
base_.CloseIdleSockets();
}
+int TCPClientSocketPool::IdleSocketCount() const {
+ return base_.idle_socket_count();
+}
+
int TCPClientSocketPool::IdleSocketCountInGroup(
const std::string& group_name) const {
return base_.IdleSocketCountInGroup(group_name);
@@ -294,4 +310,19 @@ LoadState TCPClientSocketPool::GetLoadState(
return base_.GetLoadState(group_name, handle);
}
+DictionaryValue* TCPClientSocketPool::GetInfoAsValue(
+ const std::string& name,
+ const std::string& type,
+ bool include_nested_pools) const {
+ return base_.GetInfoAsValue(name, type);
+}
+
+base::TimeDelta TCPClientSocketPool::ConnectionTimeout() const {
+ return base_.ConnectionTimeout();
+}
+
+ClientSocketPoolHistograms* TCPClientSocketPool::histograms() const {
+ return base_.histograms();
+}
+
} // namespace net
diff --git a/net/socket/tcp_client_socket_pool.h b/net/socket/tcp_client_socket_pool.h
index 322e1d0..c0c7808 100644
--- a/net/socket/tcp_client_socket_pool.h
+++ b/net/socket/tcp_client_socket_pool.h
@@ -47,15 +47,7 @@ class TCPSocketParams : public base::RefCounted<TCPSocketParams> {
~TCPSocketParams();
void Initialize(RequestPriority priority, const GURL& referrer,
- bool disable_resolver_cache) {
- // The referrer is used by the DNS prefetch system to correlate resolutions
- // with the page that triggered them. It doesn't impact the actual addresses
- // that we resolve to.
- destination_.set_referrer(referrer);
- destination_.set_priority(priority);
- if (disable_resolver_cache)
- destination_.set_allow_cached_response(false);
- }
+ bool disable_resolver_cache);
HostResolver::RequestInfo destination_;
#ifdef ANDROID
@@ -158,9 +150,7 @@ class TCPClientSocketPool : public ClientSocketPool {
virtual void CloseIdleSockets();
- virtual int IdleSocketCount() const {
- return base_.idle_socket_count();
- }
+ virtual int IdleSocketCount() const;
virtual int IdleSocketCountInGroup(const std::string& group_name) const;
@@ -169,17 +159,11 @@ class TCPClientSocketPool : public ClientSocketPool {
virtual DictionaryValue* GetInfoAsValue(const std::string& name,
const std::string& type,
- bool include_nested_pools) const {
- return base_.GetInfoAsValue(name, type);
- }
+ bool include_nested_pools) const;
- virtual base::TimeDelta ConnectionTimeout() const {
- return base_.ConnectionTimeout();
- }
+ virtual base::TimeDelta ConnectionTimeout() const;
- virtual ClientSocketPoolHistograms* histograms() const {
- return base_.histograms();
- }
+ virtual ClientSocketPoolHistograms* histograms() const;
private:
typedef ClientSocketPoolBase<TCPSocketParams> PoolBase;
diff --git a/net/socket/tcp_client_socket_pool_unittest.cc b/net/socket/tcp_client_socket_pool_unittest.cc
index c44815c..454f5b8 100644
--- a/net/socket/tcp_client_socket_pool_unittest.cc
+++ b/net/socket/tcp_client_socket_pool_unittest.cc
@@ -149,7 +149,7 @@ class MockPendingClientSocket : public ClientSocket {
virtual bool IsConnectedAndIdle() const {
return is_connected_;
}
- virtual int GetPeerAddress(AddressList* address) const{
+ virtual int GetPeerAddress(AddressList* address) const {
return ERR_UNEXPECTED;
}
virtual const BoundNetLog& NetLog() const {
@@ -251,6 +251,7 @@ class MockClientSocketFactory : public ClientSocketFactory {
const HostPortPair& host_and_port,
const SSLConfig& ssl_config,
SSLHostInfo* ssl_host_info,
+ CertVerifier* cert_verifier,
DnsCertProvenanceChecker* dns_cert_checker) {
NOTIMPLEMENTED();
delete ssl_host_info;
diff --git a/net/socket/tcp_client_socket_unittest.cc b/net/socket/tcp_client_socket_unittest.cc
index 64d78f3..2ed9441 100644
--- a/net/socket/tcp_client_socket_unittest.cc
+++ b/net/socket/tcp_client_socket_unittest.cc
@@ -105,10 +105,13 @@ TEST_F(TCPClientSocketTest, Connect) {
EXPECT_FALSE(sock_->IsConnected());
int rv = sock_->Connect(&callback);
+
+ net::CapturingNetLog::EntryList net_log_entries;
+ net_log_.GetEntries(&net_log_entries);
EXPECT_TRUE(net::LogContainsBeginEvent(
- net_log_.entries(), 0, net::NetLog::TYPE_SOCKET_ALIVE));
+ net_log_entries, 0, net::NetLog::TYPE_SOCKET_ALIVE));
EXPECT_TRUE(net::LogContainsBeginEvent(
- net_log_.entries(), 1, net::NetLog::TYPE_TCP_CONNECT));
+ net_log_entries, 1, net::NetLog::TYPE_TCP_CONNECT));
if (rv != OK) {
ASSERT_EQ(rv, ERR_IO_PENDING);
rv = callback.WaitForResult();
@@ -116,8 +119,9 @@ TEST_F(TCPClientSocketTest, Connect) {
}
EXPECT_TRUE(sock_->IsConnected());
+ net_log_.GetEntries(&net_log_entries);
EXPECT_TRUE(net::LogContainsEndEvent(
- net_log_.entries(), -1, net::NetLog::TYPE_TCP_CONNECT));
+ net_log_entries, -1, net::NetLog::TYPE_TCP_CONNECT));
sock_->Disconnect();
EXPECT_FALSE(sock_->IsConnected());
diff --git a/net/socket_stream/socket_stream.cc b/net/socket_stream/socket_stream.cc
index 4075e02..21c8e74 100644
--- a/net/socket_stream/socket_stream.cc
+++ b/net/socket_stream/socket_stream.cc
@@ -50,6 +50,8 @@ SocketStream::SocketStream(const GURL& url, Delegate* delegate)
url_(url),
max_pending_send_allowed_(kMaxPendingSendAllowed),
next_state_(STATE_NONE),
+ host_resolver_(NULL),
+ cert_verifier_(NULL),
http_auth_handler_factory_(NULL),
factory_(ClientSocketFactory::GetDefaultFactory()),
proxy_mode_(kDirectConnection),
@@ -119,6 +121,7 @@ void SocketStream::set_context(URLRequestContext* context) {
if (context_) {
host_resolver_ = context_->host_resolver();
+ cert_verifier_ = context_->cert_verifier();
http_auth_handler_factory_ = context_->http_auth_handler_factory();
}
}
@@ -800,7 +803,8 @@ int SocketStream::DoSSLConnect() {
socket_.reset(factory_->CreateSSLClientSocket(socket_.release(),
HostPortPair::FromURL(url_),
ssl_config_,
- NULL /* ssl_host_info */));
+ NULL /* ssl_host_info */,
+ cert_verifier_));
next_state_ = STATE_SSL_CONNECT_COMPLETE;
metrics_->OnSSLConnection();
return socket_->Connect(&io_callback_);
diff --git a/net/socket_stream/socket_stream.h b/net/socket_stream/socket_stream.h
index e1f2584..f485543 100644
--- a/net/socket_stream/socket_stream.h
+++ b/net/socket_stream/socket_stream.h
@@ -274,6 +274,7 @@ class SocketStream : public base::RefCountedThreadSafe<SocketStream> {
State next_state_;
HostResolver* host_resolver_;
+ CertVerifier* cert_verifier_;
HttpAuthHandlerFactory* http_auth_handler_factory_;
ClientSocketFactory* factory_;
diff --git a/net/socket_stream/socket_stream_job.cc b/net/socket_stream/socket_stream_job.cc
index 8d1da73..6636233 100644
--- a/net/socket_stream/socket_stream_job.cc
+++ b/net/socket_stream/socket_stream_job.cc
@@ -9,20 +9,17 @@
namespace net {
-static SocketStreamJobManager* GetJobManager() {
- return Singleton<SocketStreamJobManager>::get();
-}
-
// static
SocketStreamJob::ProtocolFactory* SocketStreamJob::RegisterProtocolFactory(
const std::string& scheme, ProtocolFactory* factory) {
- return GetJobManager()->RegisterProtocolFactory(scheme, factory);
+ return SocketStreamJobManager::GetInstance()->RegisterProtocolFactory(
+ scheme, factory);
}
// static
SocketStreamJob* SocketStreamJob::CreateSocketStreamJob(
const GURL& url, SocketStream::Delegate* delegate) {
- return GetJobManager()->CreateJob(url, delegate);
+ return SocketStreamJobManager::GetInstance()->CreateJob(url, delegate);
}
SocketStreamJob::SocketStreamJob() {}
diff --git a/net/socket_stream/socket_stream_job_manager.cc b/net/socket_stream/socket_stream_job_manager.cc
index 7dd0d6b..de2f0a8 100644
--- a/net/socket_stream/socket_stream_job_manager.cc
+++ b/net/socket_stream/socket_stream_job_manager.cc
@@ -4,6 +4,8 @@
#include "net/socket_stream/socket_stream_job_manager.h"
+#include "base/singleton.h"
+
namespace net {
SocketStreamJobManager::SocketStreamJobManager() {
@@ -12,6 +14,11 @@ SocketStreamJobManager::SocketStreamJobManager() {
SocketStreamJobManager::~SocketStreamJobManager() {
}
+// static
+SocketStreamJobManager* SocketStreamJobManager::GetInstance() {
+ return Singleton<SocketStreamJobManager>::get();
+}
+
SocketStreamJob* SocketStreamJobManager::CreateJob(
const GURL& url, SocketStream::Delegate* delegate) const {
// If url is invalid, create plain SocketStreamJob, which will close
diff --git a/net/socket_stream/socket_stream_job_manager.h b/net/socket_stream/socket_stream_job_manager.h
index 1150058..fbd572d 100644
--- a/net/socket_stream/socket_stream_job_manager.h
+++ b/net/socket_stream/socket_stream_job_manager.h
@@ -12,14 +12,15 @@
#include "net/socket_stream/socket_stream.h"
#include "net/socket_stream/socket_stream_job.h"
+template <typename T> struct DefaultSingletonTraits;
class GURL;
namespace net {
class SocketStreamJobManager {
public:
- SocketStreamJobManager();
- ~SocketStreamJobManager();
+ // Returns the singleton instance.
+ static SocketStreamJobManager* GetInstance();
SocketStreamJob* CreateJob(
const GURL& url, SocketStream::Delegate* delegate) const;
@@ -28,8 +29,12 @@ class SocketStreamJobManager {
const std::string& scheme, SocketStreamJob::ProtocolFactory* factory);
private:
+ friend struct DefaultSingletonTraits<SocketStreamJobManager>;
typedef std::map<std::string, SocketStreamJob::ProtocolFactory*> FactoryMap;
+ SocketStreamJobManager();
+ ~SocketStreamJobManager();
+
mutable Lock lock_;
FactoryMap factories_;
diff --git a/net/socket_stream/socket_stream_metrics_unittest.cc b/net/socket_stream/socket_stream_metrics_unittest.cc
index 64718e3..72ae142 100644
--- a/net/socket_stream/socket_stream_metrics_unittest.cc
+++ b/net/socket_stream/socket_stream_metrics_unittest.cc
@@ -15,7 +15,7 @@ using base::StatisticsRecorder;
namespace net {
TEST(SocketStreamMetricsTest, Initialize) {
- if (!StatisticsRecorder::WasStarted()) {
+ if (!StatisticsRecorder::IsActive()) {
// Create the recorder if not yet started, as SocketStreamMetrics
// relys on the StatisticsRecorder to be present. This is useful when
// tests are run with --gtest_filter='SocketStreamMetricsTest*'.
diff --git a/net/spdy/spdy_http_stream.cc b/net/spdy/spdy_http_stream.cc
index 1b72f7c..15acff7 100644
--- a/net/spdy/spdy_http_stream.cc
+++ b/net/spdy/spdy_http_stream.cc
@@ -21,7 +21,8 @@
namespace net {
-SpdyHttpStream::SpdyHttpStream(SpdySession* spdy_session, bool direct)
+SpdyHttpStream::SpdyHttpStream(SpdySession* spdy_session,
+ bool direct)
: ALLOW_THIS_IN_INITIALIZER_LIST(read_callback_factory_(this)),
stream_(NULL),
spdy_session_(spdy_session),
@@ -34,6 +35,12 @@ SpdyHttpStream::SpdyHttpStream(SpdySession* spdy_session, bool direct)
more_read_data_pending_(false),
direct_(direct) { }
+void SpdyHttpStream::InitializeWithExistingStream(SpdyStream* spdy_stream) {
+ stream_ = spdy_stream;
+ stream_->SetDelegate(this);
+ response_headers_received_ = true;
+}
+
SpdyHttpStream::~SpdyHttpStream() {
if (stream_)
stream_->DetachDelegate();
@@ -42,6 +49,7 @@ SpdyHttpStream::~SpdyHttpStream() {
int SpdyHttpStream::InitializeStream(const HttpRequestInfo* request_info,
const BoundNetLog& stream_net_log,
CompletionCallback* callback) {
+ DCHECK(!stream_.get());
if (spdy_session_->IsClosed())
return ERR_CONNECTION_CLOSED;
@@ -118,7 +126,7 @@ int SpdyHttpStream::ReadResponseBody(
}
bytes_read += bytes_to_copy;
}
- if (spdy_session_->flow_control())
+ if (SpdySession::flow_control())
stream_->IncreaseRecvWindowSize(bytes_read);
return bytes_read;
} else if (stream_->closed()) {
@@ -141,6 +149,32 @@ void SpdyHttpStream::Close(bool not_reusable) {
Cancel();
}
+HttpStream* SpdyHttpStream::RenewStreamForAuth() {
+ return NULL;
+}
+
+bool SpdyHttpStream::IsResponseBodyComplete() const {
+ if (!stream_)
+ return false;
+ return stream_->closed();
+}
+
+bool SpdyHttpStream::CanFindEndOfResponse() const {
+ return true;
+}
+
+bool SpdyHttpStream::IsMoreDataBuffered() const {
+ return false;
+}
+
+bool SpdyHttpStream::IsConnectionReused() const {
+ return spdy_session_->IsReused();
+}
+
+void SpdyHttpStream::SetConnectionReused() {
+ // SPDY doesn't need an indicator here.
+}
+
int SpdyHttpStream::SendRequest(const HttpRequestHeaders& request_headers,
UploadDataStream* request_body,
HttpResponseInfo* response,
@@ -259,7 +293,10 @@ int SpdyHttpStream::OnResponseReceived(const spdy::SpdyHeaderBlock& response,
}
response_headers_received_ = true;
- stream_->GetSSLInfo(&response_info_->ssl_info,
+ // Don't store the SSLInfo in the response here, HttpNetworkTransaction
+ // will take care of that part.
+ SSLInfo ssl_info;
+ stream_->GetSSLInfo(&ssl_info,
&response_info_->was_npn_negotiated);
response_info_->request_time = stream_->GetRequestTime();
response_info_->vary_data.Init(*request_info_, *response_info_->headers);
diff --git a/net/spdy/spdy_http_stream.h b/net/spdy/spdy_http_stream.h
index cd351cd..6e78379 100644
--- a/net/spdy/spdy_http_stream.h
+++ b/net/spdy/spdy_http_stream.h
@@ -31,10 +31,12 @@ class UploadDataStream;
// The SpdyHttpStream is a HTTP-specific type of stream known to a SpdySession.
class SpdyHttpStream : public SpdyStream::Delegate, public HttpStream {
public:
- // SpdyHttpStream constructor
SpdyHttpStream(SpdySession* spdy_session, bool direct);
virtual ~SpdyHttpStream();
+ // Initializes this SpdyHttpStream by wraping an existing SpdyStream.
+ void InitializeWithExistingStream(SpdyStream* spdy_stream);
+
SpdyStream* stream() { return stream_.get(); }
// Cancels any callbacks from being invoked and deletes the stream.
@@ -55,20 +57,12 @@ class SpdyHttpStream : public SpdyStream::Delegate, public HttpStream {
int buf_len,
CompletionCallback* callback);
virtual void Close(bool not_reusable);
- virtual HttpStream* RenewStreamForAuth() { return NULL; }
- virtual bool IsResponseBodyComplete() const {
- if (!stream_)
- return false;
- return stream_->closed();
- }
- virtual bool CanFindEndOfResponse() const { return true; }
- virtual bool IsMoreDataBuffered() const { return false; }
- virtual bool IsConnectionReused() const {
- return spdy_session_->IsReused();
- }
- virtual void SetConnectionReused() {
- // SPDY doesn't need an indicator here.
- }
+ virtual HttpStream* RenewStreamForAuth();
+ virtual bool IsResponseBodyComplete() const;
+ virtual bool CanFindEndOfResponse() const;
+ virtual bool IsMoreDataBuffered() const;
+ virtual bool IsConnectionReused() const;
+ virtual void SetConnectionReused();
virtual void GetSSLInfo(SSLInfo* ssl_info);
virtual void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info);
diff --git a/net/spdy/spdy_http_utils.h b/net/spdy/spdy_http_utils.h
index c6946dd..40f0254 100644
--- a/net/spdy/spdy_http_utils.h
+++ b/net/spdy/spdy_http_utils.h
@@ -17,8 +17,8 @@ class HttpRequestHeaders;
// Convert a SpdyHeaderBlock into an HttpResponseInfo.
// |headers| input parameter with the SpdyHeaderBlock.
// |info| output parameter for the HttpResponseInfo.
-// Returns true if successfully converted. False if there was a failure
-// or if the SpdyHeaderBlock was invalid.
+// Returns true if successfully converted. False if the SpdyHeaderBlock is
+// incomplete (e.g. missing 'status' or 'version').
bool SpdyHeadersToHttpResponse(const spdy::SpdyHeaderBlock& headers,
HttpResponseInfo* response);
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc
index 075b872..586f7dc 100644
--- a/net/spdy/spdy_network_transaction_unittest.cc
+++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -2155,7 +2155,7 @@ TEST_P(SpdyNetworkTransactionTest, DeleteSessionOnReadCallback) {
// Send a spdy request to www.google.com that gets redirected to www.foo.com.
TEST_P(SpdyNetworkTransactionTest, RedirectGetRequest) {
- // These are headers which the URLRequest tacks on.
+ // These are headers which the net::URLRequest tacks on.
const char* const kExtraHeaders[] = {
"accept-charset",
"",
@@ -2233,7 +2233,7 @@ TEST_P(SpdyNetworkTransactionTest, RedirectGetRequest) {
HttpStreamFactory::set_force_spdy_always(true);
TestDelegate d;
{
- URLRequest r(GURL("http://www.google.com/"), &d);
+ net::URLRequest r(GURL("http://www.google.com/"), &d);
SpdyURLRequestContext* spdy_url_request_context =
new SpdyURLRequestContext();
r.set_context(spdy_url_request_context);
@@ -2265,7 +2265,7 @@ TEST_P(SpdyNetworkTransactionTest, RedirectGetRequest) {
// Send a spdy request to www.google.com. Get a pushed stream that redirects to
// www.foo.com.
TEST_P(SpdyNetworkTransactionTest, RedirectServerPush) {
- // These are headers which the URLRequest tacks on.
+ // These are headers which the net::URLRequest tacks on.
const char* const kExtraHeaders[] = {
"accept-charset",
"",
@@ -2364,7 +2364,7 @@ TEST_P(SpdyNetworkTransactionTest, RedirectServerPush) {
scoped_refptr<SpdyURLRequestContext> spdy_url_request_context(
new SpdyURLRequestContext());
{
- URLRequest r(GURL("http://www.google.com/"), &d);
+ net::URLRequest r(GURL("http://www.google.com/"), &d);
r.set_context(spdy_url_request_context);
spdy_url_request_context->socket_factory().
AddSocketDataProvider(data.get());
@@ -2376,7 +2376,7 @@ TEST_P(SpdyNetworkTransactionTest, RedirectServerPush) {
std::string contents("hello!");
EXPECT_EQ(contents, d.data_received());
- URLRequest r2(GURL("http://www.google.com/foo.dat"), &d2);
+ net::URLRequest r2(GURL("http://www.google.com/foo.dat"), &d2);
r2.set_context(spdy_url_request_context);
spdy_url_request_context->socket_factory().
AddSocketDataProvider(data2.get());
@@ -3419,33 +3419,36 @@ TEST_P(SpdyNetworkTransactionTest, NetLog) {
// This test is intentionally non-specific about the exact ordering of the
// log; instead we just check to make sure that certain events exist, and that
// they are in the right order.
- EXPECT_LT(0u, log.entries().size());
+ net::CapturingNetLog::EntryList entries;
+ log.GetEntries(&entries);
+
+ EXPECT_LT(0u, entries.size());
int pos = 0;
- pos = net::ExpectLogContainsSomewhere(log.entries(), 0,
+ pos = net::ExpectLogContainsSomewhere(entries, 0,
net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST,
net::NetLog::PHASE_BEGIN);
- pos = net::ExpectLogContainsSomewhere(log.entries(), pos + 1,
+ pos = net::ExpectLogContainsSomewhere(entries, pos + 1,
net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST,
net::NetLog::PHASE_END);
- pos = net::ExpectLogContainsSomewhere(log.entries(), pos + 1,
+ pos = net::ExpectLogContainsSomewhere(entries, pos + 1,
net::NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS,
net::NetLog::PHASE_BEGIN);
- pos = net::ExpectLogContainsSomewhere(log.entries(), pos + 1,
+ pos = net::ExpectLogContainsSomewhere(entries, pos + 1,
net::NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS,
net::NetLog::PHASE_END);
- pos = net::ExpectLogContainsSomewhere(log.entries(), pos + 1,
+ pos = net::ExpectLogContainsSomewhere(entries, pos + 1,
net::NetLog::TYPE_HTTP_TRANSACTION_READ_BODY,
net::NetLog::PHASE_BEGIN);
- pos = net::ExpectLogContainsSomewhere(log.entries(), pos + 1,
+ pos = net::ExpectLogContainsSomewhere(entries, pos + 1,
net::NetLog::TYPE_HTTP_TRANSACTION_READ_BODY,
net::NetLog::PHASE_END);
// Check that we logged all the headers correctly
pos = net::ExpectLogContainsSomewhere(
- log.entries(), 0,
+ entries, 0,
net::NetLog::TYPE_SPDY_SESSION_SYN_STREAM,
net::NetLog::PHASE_NONE);
- CapturingNetLog::Entry entry = log.entries()[pos];
+ CapturingNetLog::Entry entry = entries[pos];
NetLogSpdySynParameter* request_params =
static_cast<NetLogSpdySynParameter*>(entry.extra_parameters.get());
spdy::SpdyHeaderBlock* headers =
diff --git a/net/spdy/spdy_proxy_client_socket.cc b/net/spdy/spdy_proxy_client_socket.cc
index 62816d2..6d743d2 100644
--- a/net/spdy/spdy_proxy_client_socket.cc
+++ b/net/spdy/spdy_proxy_client_socket.cc
@@ -59,6 +59,11 @@ SpdyProxyClientSocket::~SpdyProxyClientSocket() {
Disconnect();
}
+HttpStream* SpdyProxyClientSocket::CreateConnectResponseStream() {
+ DCHECK(response_stream_.get());
+ return response_stream_.release();
+}
+
// Sends a SYN_STREAM frame to the proxy with a CONNECT request
// for the specified endpoint. Waits for the server to send back
// a SYN_REPLY frame. OK will be returned if the status is 200.
@@ -116,6 +121,10 @@ bool SpdyProxyClientSocket::IsConnectedAndIdle() const {
return IsConnected() && !spdy_stream_->is_idle();
}
+const BoundNetLog& SpdyProxyClientSocket::NetLog() const {
+ return net_log_;
+}
+
void SpdyProxyClientSocket::SetSubresourceSpeculation() {
// TODO(rch): what should this implementation be?
}
@@ -361,10 +370,22 @@ int SpdyProxyClientSocket::DoReadReplyComplete(int result) {
make_scoped_refptr(new NetLogHttpResponseParameter(response_.headers)));
}
- if (response_.headers->response_code() == 200)
+ if (response_.headers->response_code() == 200) {
return OK;
- else
+ } else if (response_.headers->response_code() == 407) {
return ERR_TUNNEL_CONNECTION_FAILED;
+ } else {
+ // Immediately hand off our SpdyStream to a newly created SpdyHttpStream
+ // so that any subsequent SpdyFrames are processed in the context of
+ // the HttpStream, not the socket.
+ DCHECK(spdy_stream_);
+ SpdyStream* stream = spdy_stream_;
+ spdy_stream_ = NULL;
+ response_stream_.reset(new SpdyHttpStream(NULL, false));
+ response_stream_->InitializeWithExistingStream(stream);
+ next_state_ = STATE_DISCONNECTED;
+ return ERR_HTTPS_PROXY_TUNNEL_RESPONSE;
+ }
}
// SpdyStream::Delegate methods:
diff --git a/net/spdy/spdy_proxy_client_socket.h b/net/spdy/spdy_proxy_client_socket.h
index 213cac4..64bcd6a 100644
--- a/net/spdy/spdy_proxy_client_socket.h
+++ b/net/spdy/spdy_proxy_client_socket.h
@@ -18,7 +18,8 @@
#include "net/http/http_request_headers.h"
#include "net/http/http_request_info.h"
#include "net/http/http_response_info.h"
-#include "net/socket/client_socket.h"
+#include "net/http/proxy_client_socket.h"
+#include "net/spdy/spdy_http_stream.h"
#include "net/spdy/spdy_protocol.h"
#include "net/spdy/spdy_session.h"
#include "net/spdy/spdy_stream.h"
@@ -35,7 +36,8 @@ class IOBuffer;
class SpdySession;
class SpdyStream;
-class SpdyProxyClientSocket : public ClientSocket, public SpdyStream::Delegate {
+class SpdyProxyClientSocket : public ProxyClientSocket,
+ public SpdyStream::Delegate {
public:
// Create a socket on top of the |spdy_stream| by sending a SYN_STREAM
// CONNECT frame for |endpoint|. After the SYN_REPLY is received,
@@ -57,10 +59,17 @@ class SpdyProxyClientSocket : public ClientSocket, public SpdyStream::Delegate {
return auth_;
}
- const HttpResponseInfo* GetConnectResponseInfo() const {
+ // ProxyClientSocket methods:
+
+ virtual const HttpResponseInfo* GetConnectResponseInfo() const {
return response_.headers ? &response_ : NULL;
}
+ // In the event of a non-200 response to the CONNECT request, this
+ // method may be called to return an HttpStream in order to read
+ // the response body.
+ virtual HttpStream* CreateConnectResponseStream();
+
// ClientSocket methods:
#ifdef ANDROID
virtual int Connect(CompletionCallback* callback, bool wait_for_connect);
@@ -70,7 +79,7 @@ class SpdyProxyClientSocket : public ClientSocket, public SpdyStream::Delegate {
virtual void Disconnect();
virtual bool IsConnected() const;
virtual bool IsConnectedAndIdle() const;
- virtual const BoundNetLog& NetLog() const { return net_log_; }
+ virtual const BoundNetLog& NetLog() const;
virtual void SetSubresourceSpeculation();
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
@@ -156,6 +165,8 @@ class SpdyProxyClientSocket : public ClientSocket, public SpdyStream::Delegate {
// True if the transport socket has ever sent data.
bool was_ever_used_;
+ scoped_ptr<SpdyHttpStream> response_stream_;
+
const BoundNetLog net_log_;
DISALLOW_COPY_AND_ASSIGN(SpdyProxyClientSocket);
diff --git a/net/spdy/spdy_proxy_client_socket_unittest.cc b/net/spdy/spdy_proxy_client_socket_unittest.cc
index 236713a..c4c5f2c 100644
--- a/net/spdy/spdy_proxy_client_socket_unittest.cc
+++ b/net/spdy/spdy_proxy_client_socket_unittest.cc
@@ -839,12 +839,14 @@ TEST_F(SpdyProxyClientSocketTest, ReadErrorResponseBody) {
Initialize(reads, arraysize(reads), writes, arraysize(writes));
- AssertConnectFails(ERR_TUNNEL_CONNECTION_FAILED);
+ AssertConnectFails(ERR_HTTPS_PROXY_TUNNEL_RESPONSE);
Run(2); // SpdySession consumes the next two reads and sends then to
// sock_ to be buffered.
- AssertSyncReadEquals(kMsg1, kLen1);
- AssertSyncReadEquals(kMsg2, kLen2);
+ EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED, sock_->Read(NULL, 1, NULL));
+ scoped_refptr<IOBuffer> buf(new IOBuffer(kLen1 + kLen2));
+ scoped_ptr<HttpStream> stream(sock_->CreateConnectResponseStream());
+ stream->ReadResponseBody(buf, kLen1 + kLen2, &read_callback_);
}
// ----------- Reads and Writes
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc
index 225c159..cbc1365 100644
--- a/net/spdy/spdy_session.cc
+++ b/net/spdy/spdy_session.cc
@@ -8,6 +8,7 @@
#include "base/linked_ptr.h"
#include "base/logging.h"
#include "base/message_loop.h"
+#include "base/metrics/field_trial.h"
#include "base/metrics/stats_counters.h"
#include "base/stl_util-inl.h"
#include "base/string_number_conversions.h"
@@ -62,17 +63,6 @@ namespace {
const int kReadBufferSize = 8 * 1024;
-void AdjustSocketBufferSizes(ClientSocket* socket) {
- // Adjust socket buffer sizes.
- // SPDY uses one socket, and we want a really big buffer.
- // This greatly helps on links with packet loss - we can even
- // outperform Vista's dynamic window sizing algorithm.
- // TODO(mbelshe): more study.
- const int kSocketBufferSize = 512 * 1024;
- socket->SetReceiveBufferSize(kSocketBufferSize);
- socket->SetSendBufferSize(kSocketBufferSize);
-}
-
class NetLogSpdySessionParameter : public NetLog::EventParameters {
public:
NetLogSpdySessionParameter(const HostPortProxyPair& host_pair)
@@ -246,8 +236,10 @@ SpdySession::SpdySession(const HostPortProxyPair& host_port_proxy_pair,
streams_pushed_and_claimed_count_(0),
streams_abandoned_count_(0),
frames_received_(0),
+ bytes_received_(0),
sent_settings_(false),
received_settings_(false),
+ stalled_streams_(0),
initial_send_window_size_(spdy::kSpdyStreamInitialWindowSize),
initial_recv_window_size_(spdy::kSpdyStreamInitialWindowSize),
net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SPDY_SESSION)) {
@@ -293,8 +285,6 @@ net::Error SpdySession::InitializeWithSocket(
static base::StatsCounter spdy_sessions("spdy.sessions");
spdy_sessions.Increment();
- AdjustSocketBufferSizes(connection->socket());
-
state_ = CONNECTED;
connection_.reset(connection);
is_secure_ = is_secure;
@@ -346,6 +336,7 @@ int SpdySession::CreateStream(
return CreateStreamImpl(url, priority, spdy_stream, stream_net_log);
}
+ stalled_streams_++;
net_log().AddEvent(NetLog::TYPE_SPDY_SESSION_STALLED_MAX_STREAMS, NULL);
create_stream_queues_[priority].push(
PendingCreateStream(url, priority, spdy_stream,
@@ -595,6 +586,8 @@ void SpdySession::OnReadComplete(int bytes_read) {
return;
}
+ bytes_received_ += bytes_read;
+
// The SpdyFramer will use callbacks onto |this| as it parses frames.
// When errors occur, those callbacks can lead to teardown of all references
// to |this|, so maintain a reference to self during this call for safe
@@ -945,9 +938,7 @@ scoped_refptr<SpdyStream> SpdySession::GetActivePushStream(
used_push_streams.Increment();
return stream;
}
- else {
- return NULL;
- }
+ return NULL;
}
bool SpdySession::GetSSLInfo(SSLInfo* ssl_info, bool* was_npn_negotiated) {
@@ -1334,10 +1325,53 @@ void SpdySession::SendWindowUpdate(spdy::SpdyStreamId stream_id,
QueueFrame(window_update_frame.get(), stream->priority(), stream);
}
+// Given a cwnd that we would have sent to the server, modify it based on the
+// field trial policy.
+uint32 ApplyCwndFieldTrialPolicy(int cwnd) {
+ base::FieldTrial* trial = base::FieldTrialList::Find("SpdyCwnd");
+ if (trial->group_name() == "cwnd32")
+ return 32;
+ else if (trial->group_name() == "cwnd16")
+ return 16;
+ else if (trial->group_name() == "cwndMin16")
+ return std::max(cwnd, 16);
+ else if (trial->group_name() == "cwndMin10")
+ return std::max(cwnd, 10);
+ else if (trial->group_name() == "cwndDynamic")
+ return cwnd;
+ NOTREACHED();
+ return cwnd;
+}
+
void SpdySession::SendSettings() {
- const spdy::SpdySettings& settings = spdy_settings_->Get(host_port_pair());
+ // Note: we're copying the settings here, so that we can potentially modify
+ // the settings for the field trial. When removing the field trial, make
+ // this a reference to the const SpdySettings again.
+ spdy::SpdySettings settings = spdy_settings_->Get(host_port_pair());
if (settings.empty())
return;
+
+ // Record Histogram Data and Apply the SpdyCwnd FieldTrial if applicable.
+ for (spdy::SpdySettings::iterator i = settings.begin(),
+ end = settings.end(); i != end; ++i) {
+ const uint32 id = i->first.id();
+ const uint32 val = i->second;
+ switch (id) {
+ case spdy::SETTINGS_CURRENT_CWND:
+ uint32 cwnd = 0;
+ cwnd = ApplyCwndFieldTrialPolicy(val);
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwndSent",
+ cwnd,
+ 1, 200, 100);
+ if (cwnd != val) {
+ i->second = cwnd;
+ i->first.set_flags(spdy::SETTINGS_FLAG_PLEASE_PERSIST);
+ spdy_settings_->Set(host_port_pair(), settings);
+ }
+ break;
+ }
+ }
+
HandleSettings(settings);
net_log_.AddEvent(
@@ -1383,6 +1417,11 @@ void SpdySession::RecordHistograms() {
sent_settings_ ? 1 : 0, 2);
UMA_HISTOGRAM_ENUMERATION("Net.SpdySettingsReceived",
received_settings_ ? 1 : 0, 2);
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamStallsPerSession",
+ stalled_streams_,
+ 0, 300, 50);
+ UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionsWithStalls",
+ stalled_streams_ > 0 ? 1 : 0, 2);
if (received_settings_) {
// Enumerate the saved settings, and set histograms for it.
@@ -1393,9 +1432,31 @@ void SpdySession::RecordHistograms() {
const spdy::SpdySetting setting = *it;
switch (setting.first.id()) {
case spdy::SETTINGS_CURRENT_CWND:
+ // Record several different histograms to see if cwnd converges
+ // for larger volumes of data being sent.
UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd",
setting.second,
1, 200, 100);
+ if (bytes_received_ > 10 * 1024) {
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd10K",
+ setting.second,
+ 1, 200, 100);
+ if (bytes_received_ > 25 * 1024) {
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd25K",
+ setting.second,
+ 1, 200, 100);
+ if (bytes_received_ > 50 * 1024) {
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd50K",
+ setting.second,
+ 1, 200, 100);
+ if (bytes_received_ > 100 * 1024) {
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsCwnd100K",
+ setting.second,
+ 1, 200, 100);
+ }
+ }
+ }
+ }
break;
case spdy::SETTINGS_ROUND_TRIP_TIME:
UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySettingsRTT",
diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h
index 210e9af..6268a4f 100644
--- a/net/spdy/spdy_session.h
+++ b/net/spdy/spdy_session.h
@@ -207,7 +207,7 @@ class SpdySession : public base::RefCounted<SpdySession>,
CLOSED
};
- enum { kDefaultMaxConcurrentStreams = 6 }; // TODO(mbelshe) remove this
+ enum { kDefaultMaxConcurrentStreams = 10 };
struct PendingCreateStream {
const GURL* url;
@@ -408,9 +408,11 @@ class SpdySession : public base::RefCounted<SpdySession>,
int streams_pushed_and_claimed_count_;
int streams_abandoned_count_;
int frames_received_;
+ int bytes_received_;
bool sent_settings_; // Did this session send settings when it started.
bool received_settings_; // Did this session receive at least one settings
// frame.
+ int stalled_streams_; // Count of streams that were ever stalled.
// Initial send window size for the session; can be changed by an
// arriving SETTINGS frame; newly created streams use this value for the
diff --git a/net/spdy/spdy_stream.cc b/net/spdy/spdy_stream.cc
index 8a5d4a4..3900993 100644
--- a/net/spdy/spdy_stream.cc
+++ b/net/spdy/spdy_stream.cc
@@ -6,7 +6,6 @@
#include "base/logging.h"
#include "base/message_loop.h"
-#include "base/singleton.h"
#include "base/values.h"
#include "net/spdy/spdy_session.h"
@@ -47,7 +46,6 @@ SpdyStream::SpdyStream(SpdySession* session,
send_window_size_(spdy::kSpdyStreamInitialWindowSize),
recv_window_size_(spdy::kSpdyStreamInitialWindowSize),
pushed_(pushed),
- metrics_(Singleton<BandwidthMetrics>::get()),
response_received_(false),
session_(session),
delegate_(NULL),
diff --git a/net/spdy/spdy_test_util.h b/net/spdy/spdy_test_util.h
index 0a5d2e0..aeabe6a 100644
--- a/net/spdy/spdy_test_util.h
+++ b/net/spdy/spdy_test_util.h
@@ -7,6 +7,7 @@
#pragma once
#include "base/basictypes.h"
+#include "net/base/cert_verifier.h"
#include "net/base/mock_host_resolver.h"
#include "net/base/request_priority.h"
#include "net/base/ssl_config_service_defaults.h"
@@ -327,6 +328,7 @@ class SpdySessionDependencies {
// Default set of dependencies -- "null" proxy service.
SpdySessionDependencies()
: host_resolver(new MockHostResolver),
+ cert_verifier(new CertVerifier),
proxy_service(ProxyService::CreateDirect()),
ssl_config_service(new SSLConfigServiceDefaults),
socket_factory(new MockClientSocketFactory),
@@ -345,6 +347,7 @@ class SpdySessionDependencies {
// Custom proxy service dependency.
explicit SpdySessionDependencies(ProxyService* proxy_service)
: host_resolver(new MockHostResolver),
+ cert_verifier(new CertVerifier),
proxy_service(proxy_service),
ssl_config_service(new SSLConfigServiceDefaults),
socket_factory(new MockClientSocketFactory),
@@ -354,6 +357,7 @@ class SpdySessionDependencies {
// NOTE: host_resolver must be ordered before http_auth_handler_factory.
scoped_ptr<MockHostResolverBase> host_resolver;
+ scoped_ptr<CertVerifier> cert_verifier;
scoped_refptr<ProxyService> proxy_service;
scoped_refptr<SSLConfigService> ssl_config_service;
scoped_ptr<MockClientSocketFactory> socket_factory;
@@ -363,6 +367,7 @@ class SpdySessionDependencies {
static HttpNetworkSession* SpdyCreateSession(
SpdySessionDependencies* session_deps) {
return new HttpNetworkSession(session_deps->host_resolver.get(),
+ session_deps->cert_verifier.get(),
NULL /* dnsrr_resolver */,
NULL /* dns_cert_checker */,
NULL /* ssl_host_info_factory */,
@@ -377,6 +382,7 @@ class SpdySessionDependencies {
static HttpNetworkSession* SpdyCreateSessionDeterministic(
SpdySessionDependencies* session_deps) {
return new HttpNetworkSession(session_deps->host_resolver.get(),
+ session_deps->cert_verifier.get(),
NULL /* dnsrr_resolver */,
NULL /* dns_cert_checker */,
NULL /* ssl_host_info_factory */,
@@ -395,6 +401,7 @@ class SpdyURLRequestContext : public URLRequestContext {
public:
SpdyURLRequestContext() {
host_resolver_ = new MockHostResolver();
+ cert_verifier_ = new CertVerifier;
proxy_service_ = ProxyService::CreateDirect();
ssl_config_service_ = new SSLConfigServiceDefaults;
http_auth_handler_factory_ = HttpAuthHandlerFactory::CreateDefault(
@@ -402,6 +409,7 @@ class SpdyURLRequestContext : public URLRequestContext {
http_transaction_factory_ = new net::HttpCache(
new HttpNetworkLayer(&socket_factory_,
host_resolver_,
+ cert_verifier_,
NULL /* dnsrr_resolver */,
NULL /* dns_cert_checker */,
NULL /* ssl_host_info_factory */,
@@ -420,6 +428,7 @@ class SpdyURLRequestContext : public URLRequestContext {
virtual ~SpdyURLRequestContext() {
delete http_transaction_factory_;
delete http_auth_handler_factory_;
+ delete cert_verifier_;
delete host_resolver_;
}
diff --git a/net/test/test_server.cc b/net/test/test_server.cc
index 0eaf8b5..9722dc1 100644
--- a/net/test/test_server.cc
+++ b/net/test/test_server.cc
@@ -26,10 +26,10 @@
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "googleurl/src/gurl.h"
-#include "net/base/cert_test_util.h"
#include "net/base/host_port_pair.h"
#include "net/base/host_resolver.h"
#include "net/base/test_completion_callback.h"
+#include "net/base/test_root_certs.h"
#include "net/socket/tcp_client_socket.h"
#include "net/test/python_utils.h"
#include "testing/platform_test.h"
@@ -58,10 +58,6 @@ std::string GetHostname(TestServer::Type type,
} // namespace
-#if defined(OS_MACOSX)
-void SetMacTestCertificate(X509Certificate* cert);
-#endif
-
TestServer::HTTPSOptions::HTTPSOptions()
: server_certificate(CERT_OK),
request_client_certificate(false),
@@ -103,9 +99,8 @@ TestServer::TestServer(const HTTPSOptions& https_options,
}
TestServer::~TestServer() {
-#if defined(OS_MACOSX)
- SetMacTestCertificate(NULL);
-#endif
+ TestRootCerts* root_certs = TestRootCerts::GetInstance();
+ root_certs->Clear();
Stop();
}
@@ -132,8 +127,6 @@ bool TestServer::Start() {
if (type_ == TYPE_HTTPS) {
if (!LoadTestRootCert())
return false;
- if (!CheckCATrusted())
- return false;
}
// Get path to python server script
@@ -159,6 +152,8 @@ bool TestServer::Start() {
return false;
}
+ allowed_port_.reset(new ScopedPortException(host_port_pair_.port()));
+
started_ = true;
return true;
}
@@ -181,6 +176,8 @@ bool TestServer::Stop() {
VLOG(1) << "Kill failed?";
}
+ allowed_port_.reset();
+
return ret;
}
@@ -314,27 +311,8 @@ FilePath TestServer::GetRootCertificatePath() {
}
bool TestServer::LoadTestRootCert() {
-#if defined(USE_NSS)
- if (cert_)
- return true;
-
- // TODO(dkegel): figure out how to get this to only happen once?
-
- // This currently leaks a little memory.
- // TODO(dkegel): fix the leak and remove the entry in
- // tools/valgrind/memcheck/suppressions.txt
- ANNOTATE_SCOPED_MEMORY_LEAK; // Tell heap checker about the leak.
- cert_ = LoadTemporaryRootCert(GetRootCertificatePath());
- return (cert_ != NULL);
-#elif defined(OS_MACOSX)
- X509Certificate* cert = LoadTemporaryRootCert(GetRootCertificatePath());
- if (!cert)
- return false;
- SetMacTestCertificate(cert);
- return true;
-#else
- return true;
-#endif
+ TestRootCerts* root_certs = TestRootCerts::GetInstance();
+ return root_certs->AddFromFile(GetRootCertificatePath());
}
bool TestServer::AddCommandLineArguments(CommandLine* command_line) const {
diff --git a/net/test/test_server.h b/net/test/test_server.h
index 00a8fc9..9686aef 100644
--- a/net/test/test_server.h
+++ b/net/test/test_server.h
@@ -17,16 +17,12 @@
#include "base/file_util.h"
#include "base/process_util.h"
#include "net/base/host_port_pair.h"
+#include "net/base/net_util.h"
#if defined(OS_WIN)
#include "base/scoped_handle_win.h"
#endif
-#if defined(USE_NSS)
-#include "base/ref_counted.h"
-#include "net/base/x509_certificate.h"
-#endif
-
class CommandLine;
class DictionaryValue;
class GURL;
@@ -155,9 +151,6 @@ class TestServer {
// Returns path to the root certificate.
FilePath GetRootCertificatePath();
- // Returns false if our test root certificate is not trusted.
- bool CheckCATrusted() WARN_UNUSED_RESULT;
-
// Load the test root cert, if it hasn't been loaded yet.
bool LoadTestRootCert() WARN_UNUSED_RESULT;
@@ -180,6 +173,8 @@ class TestServer {
// Handle of the Python process running the test server.
base::ProcessHandle process_handle_;
+ scoped_ptr<net::ScopedPortException> allowed_port_;
+
#if defined(OS_WIN)
// JobObject used to clean up orphaned child processes.
ScopedHandle job_handle_;
@@ -200,10 +195,6 @@ class TestServer {
// If |type_| is TYPE_HTTPS, the TLS settings to use for the test server.
HTTPSOptions https_options_;
-#if defined(USE_NSS)
- scoped_refptr<X509Certificate> cert_;
-#endif
-
Type type_;
// Has the server been started?
diff --git a/net/test/test_server_posix.cc b/net/test/test_server_posix.cc
index 43bdb10..de42fb3 100644
--- a/net/test/test_server_posix.cc
+++ b/net/test/test_server_posix.cc
@@ -118,7 +118,7 @@ bool TestServer::LaunchPython(const FilePath& testserver_path) {
// Try to kill any orphaned testserver processes that may be running.
OrphanedTestServerFilter filter(testserver_path.value(),
base::IntToString(host_port_pair_.port()));
- if (!base::KillProcesses(L"python", -1, &filter)) {
+ if (!base::KillProcesses("python", -1, &filter)) {
LOG(WARNING) << "Failed to clean up older orphaned testserver instances.";
}
@@ -163,8 +163,4 @@ bool TestServer::WaitToStart() {
return true;
}
-bool TestServer::CheckCATrusted() {
- return true;
-}
-
} // namespace net
diff --git a/net/test/test_server_win.cc b/net/test/test_server_win.cc
index e1c54e9..e38d0bc 100644
--- a/net/test/test_server_win.cc
+++ b/net/test/test_server_win.cc
@@ -216,32 +216,4 @@ bool TestServer::WaitToStart() {
return true;
}
-bool TestServer::CheckCATrusted() {
- HCERTSTORE cert_store = CertOpenSystemStore(NULL, L"ROOT");
- if (!cert_store) {
- LOG(ERROR) << " could not open trusted root CA store";
- return false;
- }
- PCCERT_CONTEXT cert =
- CertFindCertificateInStore(cert_store,
- X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
- 0,
- CERT_FIND_ISSUER_STR,
- L"Test CA",
- NULL);
- if (cert)
- CertFreeCertificateContext(cert);
- CertCloseStore(cert_store, 0);
-
- if (!cert) {
- LOG(ERROR) << " TEST CONFIGURATION ERROR: you need to import the test ca "
- "certificate to your trusted roots for this test to work. "
- "For more info visit:\n"
- "http://dev.chromium.org/developers/testing\n";
- return false;
- }
-
- return true;
-}
-
} // namespace net
diff --git a/net/tools/dump_cache/dump_cache.cc b/net/tools/dump_cache/dump_cache.cc
index 9644aae..3561fb7 100644
--- a/net/tools/dump_cache/dump_cache.cc
+++ b/net/tools/dump_cache/dump_cache.cc
@@ -46,16 +46,16 @@ const char kInputPath[] = "input";
const char kOutputPath[] = "output";
// Dumps the file headers to stdout.
-const wchar_t kDumpHeaders[] = L"dump-headers";
+const char kDumpHeaders[] = "dump-headers";
// Dumps all entries to stdout.
-const wchar_t kDumpContents[] = L"dump-contents";
+const char kDumpContents[] = "dump-contents";
// Convert the cache to files.
-const wchar_t kDumpToFiles[] = L"dump-to-files";
+const char kDumpToFiles[] = "dump-to-files";
// Upgrade an old version to the current one.
-const wchar_t kUpgrade[] = L"upgrade";
+const char kUpgrade[] = "upgrade";
// Internal use:
const char kSlave[] = "slave";
diff --git a/net/tools/fetch/fetch_client.cc b/net/tools/fetch/fetch_client.cc
index 138bed3..0d9682f 100644
--- a/net/tools/fetch/fetch_client.cc
+++ b/net/tools/fetch/fetch_client.cc
@@ -6,11 +6,12 @@
#include "base/at_exit.h"
#include "base/command_line.h"
+#include "base/lazy_instance.h"
#include "base/message_loop.h"
#include "base/metrics/stats_counters.h"
-#include "base/singleton.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
+#include "net/base/cert_verifier.h"
#include "net/base/completion_callback.h"
#include "net/base/host_resolver.h"
#include "net/base/io_buffer.h"
@@ -47,6 +48,8 @@ class Driver {
int clients_;
};
+static base::LazyInstance<Driver> g_driver(base::LINKER_INITIALIZED);
+
// A network client
class Client {
public:
@@ -60,7 +63,7 @@ class Client {
int rv = factory->CreateTransaction(&transaction_);
DCHECK_EQ(net::OK, rv);
buffer_->AddRef();
- driver_->ClientStarted();
+ g_driver.Get().ClientStarted();
request_info_.url = url_;
request_info_.method = "GET";
int state = transaction_->Start(
@@ -101,7 +104,7 @@ class Client {
void OnRequestComplete(int result) {
static base::StatsCounter requests("FetchClient.requests");
requests.Increment();
- driver_->ClientStopped();
+ g_driver.Get().ClientStopped();
printf(".");
}
@@ -112,7 +115,6 @@ class Client {
scoped_refptr<net::IOBuffer> buffer_;
net::CompletionCallbackImpl<Client> connect_callback_;
net::CompletionCallbackImpl<Client> read_callback_;
- Singleton<Driver> driver_;
};
int main(int argc, char**argv) {
@@ -139,6 +141,7 @@ int main(int argc, char**argv) {
net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism,
NULL, NULL));
+ scoped_ptr<net::CertVerifier> cert_verifier(new net::CertVerifier);
scoped_refptr<net::ProxyService> proxy_service(
net::ProxyService::CreateDirect());
scoped_refptr<net::SSLConfigService> ssl_config_service(
@@ -147,13 +150,15 @@ int main(int argc, char**argv) {
scoped_ptr<net::HttpAuthHandlerFactory> http_auth_handler_factory(
net::HttpAuthHandlerFactory::CreateDefault(host_resolver.get()));
if (use_cache) {
- factory = new net::HttpCache(host_resolver.get(), NULL, NULL, proxy_service,
- ssl_config_service, http_auth_handler_factory.get(), NULL, NULL,
+ factory = new net::HttpCache(host_resolver.get(), cert_verifier.get(),
+ NULL, NULL, proxy_service, ssl_config_service,
+ http_auth_handler_factory.get(), NULL, NULL,
net::HttpCache::DefaultBackend::InMemory(0));
} else {
factory = new net::HttpNetworkLayer(
net::ClientSocketFactory::GetDefaultFactory(),
host_resolver.get(),
+ cert_verifier.get(),
NULL /* dnsrr_resolver */,
NULL /* dns_cert_checker */,
NULL /* ssl_host_info_factory */,
@@ -203,7 +208,7 @@ int main(int argc, char**argv) {
// Dump the stats table.
printf("<stats>\n");
int counter_max = table.GetMaxCounters();
- for (int index=0; index < counter_max; index++) {
+ for (int index = 0; index < counter_max; index++) {
std::string name(table.GetRowName(index));
if (name.length() > 0) {
int value = table.GetRowValue(index);
diff --git a/net/tools/flip_server/balsa_headers.h b/net/tools/flip_server/balsa_headers.h
index a33e857..b51b7f4 100644
--- a/net/tools/flip_server/balsa_headers.h
+++ b/net/tools/flip_server/balsa_headers.h
@@ -392,12 +392,12 @@ class BalsaHeaders {
};
typedef std::vector<base::StringPiece> HeaderTokenList;
- friend bool net::ParseHTTPFirstLine(const char* begin,
- const char* end,
- bool is_request,
- size_t max_request_uri_length,
- BalsaHeaders* headers,
- BalsaFrameEnums::ErrorCode* error_code);
+ friend bool ParseHTTPFirstLine(const char* begin,
+ const char* end,
+ bool is_request,
+ size_t max_request_uri_length,
+ BalsaHeaders* headers,
+ BalsaFrameEnums::ErrorCode* error_code);
protected:
typedef std::vector<HeaderLineDescription> HeaderLines;
@@ -502,16 +502,14 @@ class BalsaHeaders {
const HeaderLines::size_type original_idx = idx_;
do {
--idx_;
- } while (idx_ >= 0 &&
- idx_ < header_lines_size &&
- header_lines[idx_].skip == true);
+ } while (idx_ < header_lines_size && header_lines[idx_].skip == true);
// The condition below exists so that --(rbegin() + 1) == rbegin(), even
// if there are only 'skip == true' elements between the rbegin() iterator
// and the beginning of the vector of HeaderLineDescriptions.
// TODO(fenix): refactor this list so that we don't have to do
// linear scanning through skipped headers (and this condition is
// then unnecessary)
- if (idx_ < 0 || idx_ > header_lines_size) {
+ if (idx_ > header_lines_size) {
idx_ = original_idx - 1;
}
}
@@ -1279,4 +1277,3 @@ class BalsaHeaders {
} // namespace net
#endif // NET_TOOLS_FLIP_SERVER_BALSA_HEADERS_H_
-
diff --git a/net/tools/flip_server/flip_config.h b/net/tools/flip_server/flip_config.h
index 3f202f8..fdf0f46 100644
--- a/net/tools/flip_server/flip_config.h
+++ b/net/tools/flip_server/flip_config.h
@@ -30,8 +30,11 @@ public:
string listen_port_;
string ssl_cert_filename_;
string ssl_key_filename_;
- string server_ip_;
- string server_port_;
+ string http_server_ip_;
+ string http_server_port_;
+ string https_server_ip_;
+ string https_server_port_;
+ int spdy_only_;
int accept_backlog_size_;
bool disable_nagle_;
int accepts_per_wake_;
@@ -43,8 +46,11 @@ public:
string listen_port,
string ssl_cert_filename,
string ssl_key_filename,
- string server_ip,
- string server_port,
+ string http_server_ip,
+ string http_server_port,
+ string https_server_ip,
+ string https_server_port,
+ int spdy_only,
int accept_backlog_size,
bool disable_nagle,
int accepts_per_wake,
@@ -56,8 +62,11 @@ public:
listen_port_(listen_port),
ssl_cert_filename_(ssl_cert_filename),
ssl_key_filename_(ssl_key_filename),
- server_ip_(server_ip),
- server_port_(server_port),
+ http_server_ip_(http_server_ip),
+ http_server_port_(http_server_port),
+ https_server_ip_(https_server_ip),
+ https_server_port_(https_server_port),
+ spdy_only_(spdy_only),
accept_backlog_size_(accept_backlog_size),
disable_nagle_(disable_nagle),
accepts_per_wake_(accepts_per_wake),
@@ -65,6 +74,11 @@ public:
{
VLOG(1) << "Attempting to listen on " << listen_ip_.c_str() << ":"
<< listen_port_.c_str();
+ if (!https_server_ip_.size())
+ https_server_ip_ = http_server_ip_;
+ if (!https_server_port_.size())
+ https_server_port_ = http_server_port_;
+
while (1) {
int ret = net::CreateListeningSocket(listen_ip_,
listen_port_,
@@ -89,8 +103,24 @@ public:
}
}
net::SetNonBlocking(listen_fd_);
- VLOG(1) << "Listening for spdy on port: " << listen_ip_ << ":"
- << listen_port_;
+ VLOG(1) << "Listening on socket: ";
+ if (flip_handler_type == FLIP_HANDLER_PROXY)
+ VLOG(1) << "\tType : Proxy";
+ else if (FLIP_HANDLER_SPDY_SERVER)
+ VLOG(1) << "\tType : SPDY Server";
+ else if (FLIP_HANDLER_HTTP_SERVER)
+ VLOG(1) << "\tType : HTTP Server";
+ VLOG(1) << "\tIP : " << listen_ip_;
+ VLOG(1) << "\tPort : " << listen_port_;
+ VLOG(1) << "\tHTTP Server : " << http_server_ip_ << ":"
+ << http_server_port_;
+ VLOG(1) << "\tHTTPS Server : " << https_server_ip_ << ":"
+ << https_server_port_;
+ VLOG(1) << "\tSSL : "
+ << (ssl_cert_filename.size()?"true":"false");
+ VLOG(1) << "\tCertificate : " << ssl_cert_filename;
+ VLOG(1) << "\tKey : " << ssl_key_filename;
+ VLOG(1) << "\tSpdy Only : " << (spdy_only?"true":"flase");
}
~FlipAcceptor () {}
};
@@ -105,13 +135,15 @@ public:
string forward_ip_header_;
bool wait_for_iface_;
int ssl_session_expiry_;
+ bool ssl_disable_compression_;
FlipConfig() :
server_think_time_in_s_(0),
log_destination_(logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG),
forward_ip_header_enabled_(false),
wait_for_iface_(false),
- ssl_session_expiry_(300)
+ ssl_session_expiry_(300),
+ ssl_disable_compression_(false)
{}
~FlipConfig() {}
@@ -121,8 +153,11 @@ public:
string listen_port,
string ssl_cert_filename,
string ssl_key_filename,
- string server_ip,
- string server_port,
+ string http_server_ip,
+ string http_server_port,
+ string https_server_ip,
+ string https_server_port,
+ int spdy_only,
int accept_backlog_size,
bool disable_nagle,
int accepts_per_wake,
@@ -135,8 +170,11 @@ public:
listen_port,
ssl_cert_filename,
ssl_key_filename,
- server_ip,
- server_port,
+ http_server_ip,
+ http_server_port,
+ https_server_ip,
+ https_server_port,
+ spdy_only,
accept_backlog_size,
disable_nagle,
accepts_per_wake,
diff --git a/net/tools/flip_server/flip_in_mem_edsm_server.cc b/net/tools/flip_server/flip_in_mem_edsm_server.cc
index 7848861..1969e0c 100644
--- a/net/tools/flip_server/flip_in_mem_edsm_server.cc
+++ b/net/tools/flip_server/flip_in_mem_edsm_server.cc
@@ -56,12 +56,10 @@ using std::cout;
#define ACCEPTOR_CLIENT_IDENT acceptor_->listen_ip_ << ":" \
<< acceptor_->listen_port_ << " "
-#define ACCEPTOR_SERVER_IDENT acceptor_->server_ip_ << ":" \
- << acceptor_->server_port_ << " "
#define NEXT_PROTO_STRING "\x06spdy/2\x08http/1.1\x08http/1.0"
-#define SSL_CTX_DEFAULT_CIPHER_LIST "RC4:!aNULL:!eNULL"
+#define SSL_CTX_DEFAULT_CIPHER_LIST "!aNULL:!ADH:!eNull:!LOW:!EXP:RC4+RSA:MEDIUM:HIGH"
// If true, then disables the nagle algorithm);
bool FLAGS_disable_nagle = true;
@@ -214,7 +212,8 @@ void spdy_init_ssl(SSLState* state,
LOG(FATAL) << "Unable to create SSL context";
}
// Disable SSLv2 support.
- SSL_CTX_set_options(state->ssl_ctx, SSL_OP_NO_SSLv2);
+ SSL_CTX_set_options(state->ssl_ctx,
+ SSL_OP_NO_SSLv2 | SSL_OP_CIPHER_SERVER_PREFERENCE);
if (SSL_CTX_use_certificate_file(state->ssl_ctx,
ssl_cert_name.c_str(),
SSL_FILETYPE_PEM) <= 0) {
@@ -246,6 +245,17 @@ void spdy_init_ssl(SSLState* state,
VLOG(1) << "SSL CTX: Setting Release Buffers mode.";
SSL_CTX_set_mode(state->ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
#endif
+
+ // Proper methods to disable compression don't exist until 0.9.9+. For now
+ // we must manipulate the stack of compression methods directly.
+ if (g_proxy_config.ssl_disable_compression_) {
+ STACK_OF(SSL_COMP) *ssl_comp_methods = SSL_COMP_get_compression_methods();
+ int num_methods = sk_SSL_COMP_num(ssl_comp_methods);
+ int i;
+ for (i = 0; i < num_methods; i++) {
+ static_cast<void>(sk_SSL_COMP_delete(ssl_comp_methods, i));
+ }
+ }
}
SSL* spdy_new_ssl(SSL_CTX* ssl_ctx) {
@@ -680,6 +690,8 @@ class SMInterface {
SMInterface* sm_interface,
EpollServer* epoll_server,
int fd,
+ string server_ip,
+ string server_port,
bool use_ssl) = 0;
virtual size_t ProcessReadInput(const char* data, size_t len) = 0;
virtual size_t ProcessWriteInput(const char* data, size_t len) = 0;
@@ -810,6 +822,9 @@ class SMConnection: public SMConnectionInterface,
SSL* ssl_;
public:
+ string server_ip_;
+ string server_port_;
+
EpollServer* epoll_server() { return epoll_server_; }
OutputList* output_list() { return &output_list_; }
MemoryCache* memory_cache() { return memory_cache_; }
@@ -848,6 +863,8 @@ class SMConnection: public SMConnectionInterface,
SMInterface* sm_interface,
EpollServer* epoll_server,
int fd,
+ string server_ip,
+ string server_port,
bool use_ssl) {
if (initialized_) {
LOG(FATAL) << "Attempted to initialize already initialized server";
@@ -862,9 +879,11 @@ class SMConnection: public SMConnectionInterface,
// 0 == connection in progress
// 1 == connection complete
// TODO: is_numeric_host_address value needs to be detected
+ server_ip_ = server_ip;
+ server_port_ = server_port;
int ret = net::CreateConnectedSocket(&fd_,
- acceptor_->server_ip_,
- acceptor_->server_port_,
+ server_ip,
+ server_port,
true,
acceptor_->disable_nagle_);
@@ -875,10 +894,12 @@ class SMConnection: public SMConnectionInterface,
DCHECK_NE(-1, fd_);
connection_complete_ = true;
VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "Connection complete to: " << ACCEPTOR_SERVER_IDENT;
+ << "Connection complete to: " << server_ip_ << ":"
+ << server_port_ << " ";
}
VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "Connecting to server: " << ACCEPTOR_SERVER_IDENT;
+ << "Connecting to server: " << server_ip_ << ":"
+ << server_port_ << " ";
} else {
// If fd != -1 then we are initializing a connection that has just been
// accepted from the listen socket.
@@ -932,24 +953,40 @@ class SMConnection: public SMConnectionInterface,
}
}
- int Send(const char* bytes, int len, int flags) {
+ int Send(const char* data, int len, int flags) {
ssize_t bytes_written = 0;
if (ssl_) {
- bytes_written = SSL_write(ssl_, bytes, len);
- if (bytes_written < 0) {
- switch(SSL_get_error(ssl_, bytes_written)) {
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- case SSL_ERROR_WANT_ACCEPT:
- case SSL_ERROR_WANT_CONNECT:
- return -2;
- default:
- PrintSslError();
- break;
+ // Write smallish chunks to SSL so that we don't have large
+ // multi-packet TLS records to receive before being able to handle
+ // the data.
+ while(len > 0) {
+ const int kMaxTLSRecordSize = 1460;
+ const char* ptr = &(data[bytes_written]);
+ int chunksize = std::min(len, kMaxTLSRecordSize);
+ int rv = SSL_write(ssl_, ptr, chunksize);
+ if (rv <= 0) {
+ switch(SSL_get_error(ssl_, rv)) {
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_ACCEPT:
+ case SSL_ERROR_WANT_CONNECT:
+ rv = -2;
+ break;
+ default:
+ PrintSslError();
+ break;
+ }
+ // If we wrote some data, return that count. Otherwise
+ // return the stall error.
+ return bytes_written > 0 ? bytes_written : rv;
}
+ bytes_written += rv;
+ len -= rv;
+ if (rv != chunksize)
+ break; // If we couldn't write everything, we're implicitly stalled
}
} else {
- bytes_written = send(fd_, bytes, len, flags);
+ bytes_written = send(fd_, data, len, flags);
}
return bytes_written;
}
@@ -1014,7 +1051,8 @@ class SMConnection: public SMConnectionInterface,
if (sock_error == 0) {
connection_complete_ = true;
VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
- << "Connection complete to " << ACCEPTOR_SERVER_IDENT;
+ << "Connection complete to " << server_ip_ << ":"
+ << server_port_ << " ";
} else if (sock_error == EINPROGRESS) {
return;
} else {
@@ -1137,6 +1175,10 @@ class SMConnection: public SMConnectionInterface,
<< "Reusing SPDY interface.";
}
sm_interface_ = sm_spdy_interface_;
+ } else if (acceptor_->spdy_only_) {
+ VLOG(1) << log_prefix_ << ACCEPTOR_CLIENT_IDENT
+ << "SPDY proxy only, closing HTTPS connection.";
+ goto error_or_close;
} else {
if (!sm_streamer_interface_) {
sm_streamer_interface_ = NewStreamerSM(this, NULL,
@@ -1582,11 +1624,14 @@ class SpdySM : public SpdyFramerVisitorInterface, public SMInterface {
SMInterface* sm_interface,
EpollServer* epoll_server,
int fd,
+ string server_ip,
+ string server_port,
bool use_ssl) {
VLOG(2) << ACCEPTOR_CLIENT_IDENT
<< "SpdySM: Initializing server connection.";
connection_->InitSMConnection(connection_pool, sm_interface,
- epoll_server, fd, use_ssl);
+ epoll_server, fd, server_ip, server_port,
+ use_ssl);
}
private:
@@ -1610,7 +1655,8 @@ class SpdySM : public SpdyFramerVisitorInterface, public SMInterface {
return sm_http_interface;
}
- SMInterface* FindOrMakeNewSMConnectionInterface() {
+ SMInterface* FindOrMakeNewSMConnectionInterface(string server_ip,
+ string server_port) {
SMInterface *sm_http_interface;
int32 server_idx;
if (unused_server_interface_list.empty()) {
@@ -1630,19 +1676,22 @@ class SpdySM : public SpdyFramerVisitorInterface, public SMInterface {
sm_http_interface->InitSMInterface(this, server_idx);
sm_http_interface->InitSMConnection(NULL, sm_http_interface,
- epoll_server_, -1, false);
+ epoll_server_, -1,
+ server_ip, server_port, false);
return sm_http_interface;
}
- int SpdyHandleNewStream(const SpdyControlFrame* frame,
- string *http_data)
+ int SpdyHandleNewStream(const SpdyControlFrame* frame,
+ string *http_data,
+ bool *is_https_scheme)
{
bool parsed_headers = false;
SpdyHeaderBlock headers;
const SpdySynStreamControlFrame* syn_stream =
reinterpret_cast<const SpdySynStreamControlFrame*>(frame);
+ *is_https_scheme = false;
parsed_headers = spdy_framer_->ParseHeaderBlock(frame, &headers);
VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: OnSyn("
<< syn_stream->stream_id() << ")";
@@ -1660,6 +1709,11 @@ class SpdySM : public SpdyFramerVisitorInterface, public SMInterface {
return 0;
}
+ SpdyHeaderBlock::iterator scheme = headers.find("scheme");
+ if (scheme->second.compare("https") == 0) {
+ *is_https_scheme = true;
+ }
+
string uri = UrlUtilities::GetUrlPath(url->second);
if (acceptor_->flip_handler_type_ == FLIP_HANDLER_SPDY_SERVER) {
SpdyHeaderBlock::iterator referer = headers.find("referer");
@@ -1707,15 +1761,25 @@ class SpdySM : public SpdyFramerVisitorInterface, public SMInterface {
reinterpret_cast<const SpdySynStreamControlFrame*>(frame);
string http_data;
- int ret = SpdyHandleNewStream(frame, &http_data);
+ bool is_https_scheme;
+ int ret = SpdyHandleNewStream(frame, &http_data, &is_https_scheme);
if (!ret) {
LOG(ERROR) << "SpdySM: Could not convert spdy into http.";
break;
}
if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) {
+ string server_ip;
+ string server_port;
+ if (is_https_scheme) {
+ server_ip = acceptor_->https_server_ip_;
+ server_port = acceptor_->https_server_port_;
+ } else {
+ server_ip = acceptor_->http_server_ip_;
+ server_port = acceptor_->http_server_port_;
+ }
SMInterface *sm_http_interface =
- FindOrMakeNewSMConnectionInterface();
+ FindOrMakeNewSMConnectionInterface(server_ip, server_port);
stream_to_smif_[syn_stream->stream_id()] = sm_http_interface;
sm_http_interface->SetStreamID(syn_stream->stream_id());
sm_http_interface->ProcessWriteInput(http_data.c_str(),
@@ -2151,7 +2215,8 @@ class HttpSM : public BalsaVisitorInterface, public SMInterface {
stream_id_ += 2;
} else {
VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Received Response from "
- << ACCEPTOR_SERVER_IDENT;
+ << connection_->server_ip_ << ":"
+ << connection_->server_port_ << " ";
sm_spdy_interface_->SendSynReply(stream_id_, headers);
}
}
@@ -2175,9 +2240,9 @@ class HttpSM : public BalsaVisitorInterface, public SMInterface {
virtual void ProcessChunkExtensions(const char *input, size_t size) {}
virtual void HeaderDone() {}
virtual void MessageDone() {
+ if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) {
VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: MessageDone. Sending EOF: "
<< "stream " << stream_id_;
- if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) {
sm_spdy_interface_->SendEOF(stream_id_);
} else {
VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: MessageDone.";
@@ -2215,12 +2280,15 @@ class HttpSM : public BalsaVisitorInterface, public SMInterface {
SMInterface* sm_interface,
EpollServer* epoll_server,
int fd,
+ string server_ip,
+ string server_port,
bool use_ssl)
{
VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Initializing server "
<< "connection.";
connection_->InitSMConnection(connection_pool, sm_interface,
- epoll_server, fd, use_ssl);
+ epoll_server, fd, server_ip, server_port,
+ use_ssl);
}
size_t ProcessReadInput(const char* data, size_t len) {
@@ -2259,7 +2327,7 @@ class HttpSM : public BalsaVisitorInterface, public SMInterface {
}
void Reset() {
- VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Reset: stream %d "
+ VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Reset: stream "
<< stream_id_;
http_framer_->Reset();
}
@@ -2268,8 +2336,11 @@ class HttpSM : public BalsaVisitorInterface, public SMInterface {
}
void ResetForNewConnection() {
- VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Server connection closing "
- << "to: " << ACCEPTOR_SERVER_IDENT;
+ if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) {
+ VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Server connection closing "
+ << "to: " << connection_->server_ip_ << ":"
+ << connection_->server_port_ << " ";
+ }
seq_num_ = 0;
output_ordering_.Reset();
http_framer_->Reset();
@@ -2495,12 +2566,15 @@ class StreamerSM : public SMInterface {
SMInterface* sm_interface,
EpollServer* epoll_server,
int fd,
+ string server_ip,
+ string server_port,
bool use_ssl)
{
VLOG(2) << ACCEPTOR_CLIENT_IDENT << "StreamerSM: Initializing server "
<< "connection.";
connection_->InitSMConnection(connection_pool, sm_interface,
- epoll_server, fd, use_ssl);
+ epoll_server, fd, server_ip,
+ server_port, use_ssl);
}
size_t ProcessReadInput(const char* data, size_t len) {
@@ -2562,8 +2636,13 @@ class StreamerSM : public SMInterface {
epoll_server_, acceptor_);
sm_other_interface_->InitSMInterface(this, 0);
}
+ // The Streamer interface is used to stream HTTPS connections, so we
+ // will always use the https_server_ip/port here.
sm_other_interface_->InitSMConnection(NULL, sm_other_interface_,
- epoll_server_, -1, false);
+ epoll_server_, -1,
+ acceptor_->https_server_ip_,
+ acceptor_->https_server_port_,
+ false);
return 1;
}
@@ -2734,6 +2813,7 @@ class SMAcceptorThread : public SimpleThread,
NULL,
&epoll_server_,
server_fd,
+ "", "",
use_ssl_);
}
@@ -2883,22 +2963,43 @@ int main (int argc, char**argv)
unsigned int i = 0;
bool wait_for_iface = false;
+ signal(SIGPIPE, SIG_IGN);
+
CommandLine::Init(argc, argv);
CommandLine cl(argc, argv);
- if (cl.HasSwitch("--help") || argc < 2) {
+ if (cl.HasSwitch("help") || argc < 2) {
cout << argv[0] << " <options>\n";
- cout << "\t--proxy<1..n>=\"<listen ip>,<listen port>,<ssl cert filename>,"
- << "<ssl key filename>,<server ip>,<server port>\"\n";
- cout << "\t--spdy-server=\"<listen ip>,<listen port>,<ssl cert filename>,"
- << "<ssl key filename>\"\n";
- cout << "\t--http-server=\"<listen ip>,<listen port>,<ssl cert filename>,"
- << "<ssl key filename>\"\n";
+ cout << " Proxy options:\n";
+ cout << "\t--proxy<1..n>=\"<listen ip>,<listen port>,"
+ << "<ssl cert filename>,\n"
+ << "\t <ssl key filename>,<http server ip>,"
+ << "<http server port>,\n"
+ << "\t [https server ip],[https server port],"
+ << "<spdy only 0|1>\"\n";
+ cout << "\t * The https server ip and port may be left empty if they are"
+ << " the same as\n"
+ << "\t the http server fields.\n";
+ cout << "\t * spdy only prevents non-spdy https connections from being"
+ << " passed\n"
+ << "\t through the proxy listen ip:port.\n";
cout << "\t--forward-ip-header=<header name>\n";
- cout << "\t--logdest=file|system|both\n";
+ cout << "\n Server options:\n";
+ cout << "\t--spdy-server=\"<listen ip>,<listen port>,[ssl cert filename],\n"
+ << "\t [ssl key filename]\"\n";
+ cout << "\t--http-server=\"<listen ip>,<listen port>,[ssl cert filename],\n"
+ << "\t [ssl key filename]\"\n";
+ cout << "\t * Leaving the ssl cert and key fields empty will disable ssl"
+ << " for the\n"
+ << "\t http and spdy flip servers\n";
+ cout << "\n Global options:\n";
+ cout << "\t--logdest=<file|system|both>\n";
cout << "\t--logfile=<logfile>\n";
cout << "\t--wait-for-iface\n";
+ cout << "\t * The flip server will block until the listen ip has been"
+ << " raised.\n";
cout << "\t--ssl-session-expiry=<seconds> (default is 300)\n";
+ cout << "\t--ssl-disable-compression\n";
cout << "\t--help\n";
exit(0);
}
@@ -2949,23 +3050,31 @@ int main (int argc, char**argv)
g_proxy_config.ssl_session_expiry_ = atoi( session_expiry.c_str() );
}
+ if (cl.HasSwitch("ssl-disable-compression")) {
+ g_proxy_config.ssl_disable_compression_ = true;
+ }
+
InitLogging(g_proxy_config.log_filename_.c_str(),
g_proxy_config.log_destination_,
logging::DONT_LOCK_LOG_FILE,
logging::APPEND_TO_OLD_LOG_FILE);
LOG(INFO) << "Flip SPDY proxy started with configuration:";
- LOG(INFO) << "Logging destination : " << g_proxy_config.log_destination_;
- LOG(INFO) << "Log file : " << g_proxy_config.log_filename_;
- LOG(INFO) << "Forward IP Header : "
+ LOG(INFO) << "Logging destination : " << g_proxy_config.log_destination_;
+ LOG(INFO) << "Log file : " << g_proxy_config.log_filename_;
+ LOG(INFO) << "Forward IP Header : "
<< (g_proxy_config.forward_ip_header_enabled_ ?
g_proxy_config.forward_ip_header_ : "(disabled)");
- LOG(INFO) << "Wait for interfaces : " << (wait_for_iface?"true":"false");
- LOG(INFO) << "Accept backlog size : " << FLAGS_accept_backlog_size;
- LOG(INFO) << "Accepts per wake : " << FLAGS_accepts_per_wake;
- LOG(INFO) << "Disable nagle : "
+ LOG(INFO) << "Wait for interfaces : " << (wait_for_iface?"true":"false");
+ LOG(INFO) << "Accept backlog size : " << FLAGS_accept_backlog_size;
+ LOG(INFO) << "Accepts per wake : " << FLAGS_accepts_per_wake;
+ LOG(INFO) << "Disable nagle : "
<< (FLAGS_disable_nagle?"true":"false");
- LOG(INFO) << "Reuseport : " << (FLAGS_reuseport?"true":"false");
+ LOG(INFO) << "Reuseport : " << (FLAGS_reuseport?"true":"false");
+ LOG(INFO) << "SSL session expiry : "
+ << g_proxy_config.ssl_session_expiry_;
+ LOG(INFO) << "SSL disable compression : "
+ << g_proxy_config.ssl_disable_compression_;
// Proxy Acceptors
while (true) {
@@ -2977,13 +3086,16 @@ int main (int argc, char**argv)
}
string value = cl.GetSwitchValueASCII(name.str());
vector<std::string> valueArgs = split(value, ',');
- CHECK_EQ((unsigned int)6, valueArgs.size());
+ CHECK_EQ((unsigned int)9, valueArgs.size());
+ int spdy_only = atoi(valueArgs[8].c_str());
// If wait_for_iface is enabled, then this call will block
// indefinitely until the interface is raised.
g_proxy_config.AddAcceptor(FLIP_HANDLER_PROXY,
valueArgs[0], valueArgs[1],
valueArgs[2], valueArgs[3],
valueArgs[4], valueArgs[5],
+ valueArgs[6], valueArgs[7],
+ spdy_only,
FLAGS_accept_backlog_size,
FLAGS_disable_nagle,
FLAGS_accepts_per_wake,
@@ -3001,7 +3113,8 @@ int main (int argc, char**argv)
g_proxy_config.AddAcceptor(FLIP_HANDLER_SPDY_SERVER,
valueArgs[0], valueArgs[1],
valueArgs[2], valueArgs[3],
- "", "",
+ "", "", "", "",
+ 0,
FLAGS_accept_backlog_size,
FLAGS_disable_nagle,
FLAGS_accepts_per_wake,
@@ -3019,7 +3132,8 @@ int main (int argc, char**argv)
g_proxy_config.AddAcceptor(FLIP_HANDLER_HTTP_SERVER,
valueArgs[0], valueArgs[1],
valueArgs[2], valueArgs[3],
- "", "",
+ "", "", "", "",
+ 0,
FLAGS_accept_backlog_size,
FLAGS_disable_nagle,
FLAGS_accepts_per_wake,
diff --git a/net/tools/testserver/testserver.py b/net/tools/testserver/testserver.py
index c0dc930..56d7c0e 100755
--- a/net/tools/testserver/testserver.py
+++ b/net/tools/testserver/testserver.py
@@ -151,17 +151,22 @@ class SyncHTTPServer(StoppableHTTPServer):
"""This is a merge of asyncore.loop() and SocketServer.serve_forever().
"""
- def RunDispatcherHandler(dispatcher, handler):
- """Handles a single event for an asyncore.dispatcher.
+ def HandleXmppSocket(fd, socket_map, handler):
+ """Runs the handler for the xmpp connection for fd.
Adapted from asyncore.read() et al.
"""
+ xmpp_connection = socket_map.get(fd)
+ # This could happen if a previous handler call caused fd to get
+ # removed from socket_map.
+ if xmpp_connection is None:
+ return
try:
- handler(dispatcher)
+ handler(xmpp_connection)
except (asyncore.ExitNow, KeyboardInterrupt, SystemExit):
raise
except:
- dispatcher.handle_error()
+ xmpp_connection.handle_error()
while True:
read_fds = [ self.fileno() ]
@@ -191,19 +196,16 @@ class SyncHTTPServer(StoppableHTTPServer):
if fd == self.fileno():
self.HandleRequestNoBlock()
continue
- xmpp_connection = self._xmpp_socket_map.get(fd)
- RunDispatcherHandler(xmpp_connection,
- asyncore.dispatcher.handle_read_event)
+ HandleXmppSocket(fd, self._xmpp_socket_map,
+ asyncore.dispatcher.handle_read_event)
for fd in write_fds:
- xmpp_connection = self._xmpp_socket_map.get(fd)
- RunDispatcherHandler(xmpp_connection,
- asyncore.dispatcher.handle_write_event)
+ HandleXmppSocket(fd, self._xmpp_socket_map,
+ asyncore.dispatcher.handle_write_event)
for fd in exceptional_fds:
- xmpp_connection = self._xmpp_socket_map.get(fd)
- RunDispatcherHandler(xmpp_connection,
- asyncore.dispatcher.handle_expt_event)
+ HandleXmppSocket(fd, self._xmpp_socket_map,
+ asyncore.dispatcher.handle_expt_event)
class BasePageHandler(BaseHTTPServer.BaseHTTPRequestHandler):
@@ -302,11 +304,12 @@ class TestPageHandler(BasePageHandler):
self._mime_types = {
'crx' : 'application/x-chrome-extension',
+ 'exe' : 'application/octet-stream',
'gif': 'image/gif',
'jpeg' : 'image/jpeg',
'jpg' : 'image/jpeg',
- 'xml' : 'text/xml',
- 'pdf' : 'application/pdf'
+ 'pdf' : 'application/pdf',
+ 'xml' : 'text/xml'
}
self._default_mime_type = 'text/html'
diff --git a/net/tools/testserver/xmppserver.py b/net/tools/testserver/xmppserver.py
index ac9c276..de93076 100644
--- a/net/tools/testserver/xmppserver.py
+++ b/net/tools/testserver/xmppserver.py
@@ -370,23 +370,29 @@ class XmppConnection(asynchat.async_chat):
</iq>
""")
- def __init__(self, sock, socket_map, connections, addr):
+ def __init__(self, sock, socket_map, delegate, addr):
"""Starts up the xmpp connection.
Args:
sock: The socket to the client.
socket_map: A map from sockets to their owning objects.
- connections: The set of handshake-completed connections.
+ delegate: The delegate, which is notified when the XMPP
+ handshake is successful, when the connection is closed, and
+ when a notification has to be broadcast.
addr: The host/port of the client.
"""
- asynchat.async_chat.__init__(self, sock)
+ # We do this because in versions of python < 2.6,
+ # async_chat.__init__ doesn't take a map argument nor pass it to
+ # dispatcher.__init__. We rely on the fact that
+ # async_chat.__init__ calls dispatcher.__init__ as the last thing
+ # it does, and that calling dispatcher.__init__ with socket=None
+ # and map=None is essentially a no-op.
+ asynchat.async_chat.__init__(self)
+ asyncore.dispatcher.__init__(self, sock, socket_map)
+
self.set_terminator(None)
- # async_chat in Python 2.4 has a bug where it ignores a
- # socket_map argument. So we handle that ourselves.
- self._socket_map = socket_map
- self._socket_map[self.fileno()] = self
- self._connections = connections
+ self._delegate = delegate
self._parser = StanzaParser(self)
self._jid = None
@@ -412,11 +418,10 @@ class XmppConnection(asynchat.async_chat):
def found_terminator(self):
asynchat.async_chat.found_terminator(self)
- def handle_close(self):
+ def close(self):
print "Closing connection to %s" % self
- # Remove ourselves from anywhere we possibly installed ourselves.
- self._connections.discard(self)
- del self._socket_map[self.fileno()]
+ self._delegate.OnXmppConnectionClosed(self)
+ asynchat.async_chat.close(self)
# Called by self._parser.FeedString().
def FeedStanza(self, stanza):
@@ -431,7 +436,7 @@ class XmppConnection(asynchat.async_chat):
def HandshakeDone(self, jid):
self._jid = jid
self._handshake_task = None
- self._connections.add(self)
+ self._delegate.OnXmppHandshakeDone(self)
print "Handshake done for %s" % self
def _HandleIq(self, iq):
@@ -454,7 +459,7 @@ class XmppConnection(asynchat.async_chat):
self._SendNotifierStanza(id, 'result')
elif command == 'set':
# Send notification request.
- SendNotification(self._connections)
+ self._delegate.SendNotification(self)
else:
raise UnexpectedXml(command_xml)
@@ -491,13 +496,6 @@ class XmppConnection(asynchat.async_chat):
self._SendNotifierStanza(next_id, 'set')
-def SendNotification(connections):
- """Sends a notification to all connections in the given sequence."""
- for connection in connections:
- print 'Sending notification to %s' % connection
- connection.SendNotification()
-
-
class XmppServer(asyncore.dispatcher):
"""The main XMPP server class.
@@ -518,9 +516,30 @@ class XmppServer(asyncore.dispatcher):
self.bind(addr)
self.listen(5)
self._socket_map = socket_map
- self._socket_map[self.fileno()] = self
self._connections = set()
+ self._handshake_done_connections = set()
def handle_accept(self):
(sock, addr) = self.accept()
- XmppConnection(sock, self._socket_map, self._connections, addr)
+ xmpp_connection = XmppConnection(sock, self._socket_map, self, addr)
+ self._connections.add(xmpp_connection)
+
+ def close(self):
+ # A copy is necessary since calling close on each connection
+ # removes it from self._connections.
+ for connection in self._connections.copy():
+ connection.close()
+ asyncore.dispatcher.close(self)
+
+ # XmppConnection delegate methods.
+ def OnXmppHandshakeDone(self, xmpp_connection):
+ self._handshake_done_connections.add(xmpp_connection)
+
+ def OnXmppConnectionClosed(self, xmpp_connection):
+ self._connections.discard(xmpp_connection)
+ self._handshake_done_connections.discard(xmpp_connection)
+
+ def SendNotification(self, unused_xmpp_connection):
+ for connection in self._handshake_done_connections:
+ print 'Sending notification to %s' % connection
+ connection.SendNotification()
diff --git a/net/tools/testserver/xmppserver_test.py b/net/tools/testserver/xmppserver_test.py
index e033a69..61a996f 100644
--- a/net/tools/testserver/xmppserver_test.py
+++ b/net/tools/testserver/xmppserver_test.py
@@ -168,6 +168,7 @@ class HandshakeTaskTest(unittest.TestCase):
class XmppConnectionTest(unittest.TestCase):
def setUp(self):
+ self.connections = set()
self.data = []
# socket-like methods.
@@ -184,13 +185,29 @@ class XmppConnectionTest(unittest.TestCase):
self.data.append(data)
pass
+ def close(self):
+ pass
+
+ # XmppConnection delegate methods.
+ def OnXmppHandshakeDone(self, xmpp_connection):
+ self.connections.add(xmpp_connection)
+
+ def OnXmppConnectionClosed(self, xmpp_connection):
+ self.connections.discard(xmpp_connection)
+
+ def SendNotification(self, unused_xmpp_connection):
+ for connection in self.connections:
+ connection.SendNotification()
+
def testBasic(self):
- connections = set()
+ socket_map = {}
xmpp_connection = xmppserver.XmppConnection(
- self, {}, connections, ('', 0))
- self.assertEqual(len(connections), 0)
+ self, socket_map, self, ('', 0))
+ self.assertEqual(len(socket_map), 1)
+ self.assertEqual(len(self.connections), 0)
xmpp_connection.HandshakeDone(xmppserver.Jid('foo', 'bar'))
- self.assertEqual(len(connections), 1)
+ self.assertEqual(len(socket_map), 1)
+ self.assertEqual(len(self.connections), 1)
# Test subscription request.
self.assertEqual(len(self.data), 0)
@@ -220,6 +237,10 @@ class XmppConnectionTest(unittest.TestCase):
self.assertRaises(xmppserver.UnexpectedXml,
SendUnexpectedNotifierCommand)
+ # Test close
+ xmpp_connection.close()
+ self.assertEqual(len(socket_map), 0)
+ self.assertEqual(len(self.connections), 0)
class XmppServerTest(unittest.TestCase):
@@ -233,6 +254,9 @@ class XmppServerTest(unittest.TestCase):
def getpeername(self):
return ('', 0)
+ def close(self):
+ pass
+
def testBasic(self):
class FakeXmppServer(xmppserver.XmppServer):
def accept(self2):
@@ -244,6 +268,8 @@ class XmppServerTest(unittest.TestCase):
self.assertEqual(len(socket_map), 1)
xmpp_server.handle_accept()
self.assertEqual(len(socket_map), 2)
+ xmpp_server.close()
+ self.assertEqual(len(socket_map), 0)
if __name__ == '__main__':
diff --git a/net/url_request/https_prober.cc b/net/url_request/https_prober.cc
index d69eaf3..bdafcf6 100644
--- a/net/url_request/https_prober.cc
+++ b/net/url_request/https_prober.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/singleton.h"
#include "net/url_request/https_prober.h"
#include "net/url_request/url_request.h"
@@ -15,6 +16,11 @@ HTTPSProber::HTTPSProber() {
HTTPSProber::~HTTPSProber() {
}
+// static
+HTTPSProber* HTTPSProber::GetInstance() {
+ return Singleton<HTTPSProber>::get();
+}
+
bool HTTPSProber::HaveProbed(const std::string& host) const {
return probed_.find(host) != probed_.end();
}
@@ -34,21 +40,21 @@ bool HTTPSProber::ProbeHost(const std::string& host, URLRequestContext* ctx,
GURL url("https://" + host);
DCHECK_EQ(url.host(), host);
- URLRequest* req = new URLRequest(url, this);
+ net::URLRequest* req = new net::URLRequest(url, this);
req->set_context(ctx);
req->Start();
return true;
}
-void HTTPSProber::Success(URLRequest* request) {
+void HTTPSProber::Success(net::URLRequest* request) {
DoCallback(request, true);
}
-void HTTPSProber::Failure(URLRequest* request) {
+void HTTPSProber::Failure(net::URLRequest* request) {
DoCallback(request, false);
}
-void HTTPSProber::DoCallback(URLRequest* request, bool result) {
+void HTTPSProber::DoCallback(net::URLRequest* request, bool result) {
std::map<std::string, HTTPSProberDelegate*>::iterator i =
inflight_probes_.find(request->original_url().host());
DCHECK(i != inflight_probes_.end());
@@ -60,18 +66,18 @@ void HTTPSProber::DoCallback(URLRequest* request, bool result) {
delegate->ProbeComplete(result);
}
-void HTTPSProber::OnAuthRequired(URLRequest* request,
+void HTTPSProber::OnAuthRequired(net::URLRequest* request,
net::AuthChallengeInfo* auth_info) {
Success(request);
}
-void HTTPSProber::OnSSLCertificateError(URLRequest* request,
+void HTTPSProber::OnSSLCertificateError(net::URLRequest* request,
int cert_error,
net::X509Certificate* cert) {
request->ContinueDespiteLastError();
}
-void HTTPSProber::OnResponseStarted(URLRequest* request) {
+void HTTPSProber::OnResponseStarted(net::URLRequest* request) {
if (request->status().status() == URLRequestStatus::SUCCESS) {
Success(request);
} else {
@@ -79,7 +85,7 @@ void HTTPSProber::OnResponseStarted(URLRequest* request) {
}
}
-void HTTPSProber::OnReadCompleted(URLRequest* request, int bytes_read) {
+void HTTPSProber::OnReadCompleted(net::URLRequest* request, int bytes_read) {
NOTREACHED();
}
diff --git a/net/url_request/https_prober.h b/net/url_request/https_prober.h
index 28182c4..5d1a622 100644
--- a/net/url_request/https_prober.h
+++ b/net/url_request/https_prober.h
@@ -10,17 +10,17 @@
#include <set>
#include <string>
-#include "base/singleton.h"
#include "base/task.h"
#include "net/url_request/url_request.h"
+template <typename T> struct DefaultSingletonTraits;
class URLRequestContext;
namespace net {
// This should be scoped inside HTTPSProber, but VC cannot compile
// HTTPProber::Delegate when HTTPSProber also inherits from
-// URLRequest::Delegate.
+// net::URLRequest::Delegate.
class HTTPSProberDelegate {
public:
virtual void ProbeComplete(bool result) = 0;
@@ -31,10 +31,10 @@ class HTTPSProberDelegate {
// HTTPSProber is a singleton object that manages HTTPS probes. A HTTPS probe
// determines if we can connect to a given host over HTTPS. It's used when
// transparently upgrading from HTTP to HTTPS (for example, for SPDY).
-class HTTPSProber : public URLRequest::Delegate {
+class HTTPSProber : public net::URLRequest::Delegate {
public:
- HTTPSProber();
- ~HTTPSProber();
+ // Returns the singleton instance.
+ static HTTPSProber* GetInstance();
// HaveProbed returns true if the given host is known to have been probed
// since the browser was last started.
@@ -52,19 +52,22 @@ class HTTPSProber : public URLRequest::Delegate {
bool ProbeHost(const std::string& host, URLRequestContext* ctx,
HTTPSProberDelegate* delegate);
- // Implementation of URLRequest::Delegate
- void OnAuthRequired(URLRequest* request,
- net::AuthChallengeInfo* auth_info);
- void OnSSLCertificateError(URLRequest* request,
- int cert_error,
- net::X509Certificate* cert);
- void OnResponseStarted(URLRequest* request);
- void OnReadCompleted(URLRequest* request, int bytes_read);
+ // Implementation of net::URLRequest::Delegate
+ virtual void OnAuthRequired(net::URLRequest* request,
+ net::AuthChallengeInfo* auth_info);
+ virtual void OnSSLCertificateError(net::URLRequest* request,
+ int cert_error,
+ net::X509Certificate* cert);
+ virtual void OnResponseStarted(net::URLRequest* request);
+ virtual void OnReadCompleted(net::URLRequest* request, int bytes_read);
private:
- void Success(URLRequest* request);
- void Failure(URLRequest* request);
- void DoCallback(URLRequest* request, bool result);
+ HTTPSProber();
+ ~HTTPSProber();
+
+ void Success(net::URLRequest* request);
+ void Failure(net::URLRequest* request);
+ void DoCallback(net::URLRequest* request, bool result);
std::map<std::string, HTTPSProberDelegate*> inflight_probes_;
std::set<std::string> probed_;
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc
index ac54a1f..26a9da2 100644
--- a/net/url_request/url_request.cc
+++ b/net/url_request/url_request.cc
@@ -29,10 +29,6 @@ namespace {
// Max number of http redirects to follow. Same number as gecko.
const int kMaxRedirects = 20;
-URLRequestJobManager* GetJobManager() {
- return Singleton<URLRequestJobManager>::get();
-}
-
// Discard headers which have meaning in POST (Content-Length, Content-Type,
// Origin).
void StripPostSpecificHeaders(net::HttpRequestHeaders* headers) {
@@ -44,6 +40,8 @@ void StripPostSpecificHeaders(net::HttpRequestHeaders* headers) {
} // namespace
+namespace net {
+
///////////////////////////////////////////////////////////////////////////////
// URLRequest::Interceptor
@@ -128,17 +126,19 @@ URLRequest::~URLRequest() {
// static
URLRequest::ProtocolFactory* URLRequest::RegisterProtocolFactory(
const string& scheme, ProtocolFactory* factory) {
- return GetJobManager()->RegisterProtocolFactory(scheme, factory);
+ return URLRequestJobManager::GetInstance()->RegisterProtocolFactory(scheme,
+ factory);
}
// static
void URLRequest::RegisterRequestInterceptor(Interceptor* interceptor) {
- GetJobManager()->RegisterRequestInterceptor(interceptor);
+ URLRequestJobManager::GetInstance()->RegisterRequestInterceptor(interceptor);
}
// static
void URLRequest::UnregisterRequestInterceptor(Interceptor* interceptor) {
- GetJobManager()->UnregisterRequestInterceptor(interceptor);
+ URLRequestJobManager::GetInstance()->UnregisterRequestInterceptor(
+ interceptor);
}
void URLRequest::AppendBytesToUpload(const char* bytes, int bytes_len) {
@@ -262,7 +262,7 @@ int URLRequest::GetResponseCode() {
// static
bool URLRequest::IsHandledProtocol(const std::string& scheme) {
- return GetJobManager()->SupportsScheme(scheme);
+ return URLRequestJobManager::GetInstance()->SupportsScheme(scheme);
}
// static
@@ -277,12 +277,12 @@ bool URLRequest::IsHandledURL(const GURL& url) {
// static
void URLRequest::AllowFileAccess() {
- GetJobManager()->set_enable_file_access(true);
+ URLRequestJobManager::GetInstance()->set_enable_file_access(true);
}
// static
bool URLRequest::IsFileAccessAllowed() {
- return GetJobManager()->enable_file_access();
+ return URLRequestJobManager::GetInstance()->enable_file_access();
}
@@ -316,7 +316,7 @@ GURL URLRequest::GetSanitizedReferrer() const {
}
void URLRequest::Start() {
- StartJob(GetJobManager()->CreateJob(this));
+ StartJob(URLRequestJobManager::GetInstance()->CreateJob(this));
}
///////////////////////////////////////////////////////////////////////////////
@@ -351,7 +351,7 @@ void URLRequest::StartJob(URLRequestJob* job) {
void URLRequest::Restart() {
// Should only be called if the original job didn't make any progress.
DCHECK(job_ && !job_->has_response_started());
- RestartWithJob(GetJobManager()->CreateJob(this));
+ RestartWithJob(URLRequestJobManager::GetInstance()->CreateJob(this));
}
void URLRequest::RestartWithJob(URLRequestJob *job) {
@@ -425,7 +425,9 @@ void URLRequest::StopCaching() {
}
void URLRequest::ReceivedRedirect(const GURL& location, bool* defer_redirect) {
- URLRequestJob* job = GetJobManager()->MaybeInterceptRedirect(this, location);
+ URLRequestJob* job =
+ URLRequestJobManager::GetInstance()->MaybeInterceptRedirect(this,
+ location);
if (job) {
RestartWithJob(job);
} else if (delegate_) {
@@ -439,7 +441,8 @@ void URLRequest::ResponseStarted() {
params = new net::NetLogIntegerParameter("net_error", status_.os_error());
net_log_.EndEvent(net::NetLog::TYPE_URL_REQUEST_START_JOB, params);
- URLRequestJob* job = GetJobManager()->MaybeInterceptResponse(this);
+ URLRequestJob* job =
+ URLRequestJobManager::GetInstance()->MaybeInterceptResponse(this);
if (job) {
RestartWithJob(job);
} else if (delegate_) {
@@ -598,3 +601,5 @@ URLRequest::UserData* URLRequest::GetUserData(const void* key) const {
void URLRequest::SetUserData(const void* key, UserData* data) {
user_data_[key] = linked_ptr<UserData>(data);
}
+
+} // namespace net
diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h
index fb81500..ffd4f88 100644
--- a/net/url_request/url_request.h
+++ b/net/url_request/url_request.h
@@ -646,6 +646,4 @@ class URLRequest : public NonThreadSafe {
} // namespace net
-typedef net::URLRequest URLRequest;
-
#endif // NET_URL_REQUEST_URL_REQUEST_H_
diff --git a/net/url_request/url_request_about_job.cc b/net/url_request/url_request_about_job.cc
index ac6aa01..b8dab1a 100644
--- a/net/url_request/url_request_about_job.cc
+++ b/net/url_request/url_request_about_job.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// 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.
@@ -10,6 +10,8 @@
#include "base/message_loop.h"
+namespace net {
+
// static
URLRequestJob* URLRequestAboutJob::Factory(URLRequest* request,
const std::string& scheme) {
@@ -38,3 +40,5 @@ URLRequestAboutJob::~URLRequestAboutJob() {
void URLRequestAboutJob::StartAsync() {
NotifyHeadersComplete();
}
+
+} // namespace net
diff --git a/net/url_request/url_request_about_job.h b/net/url_request/url_request_about_job.h
index 52a659e..7617208 100644
--- a/net/url_request/url_request_about_job.h
+++ b/net/url_request/url_request_about_job.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// 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.
@@ -11,6 +11,8 @@
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_job.h"
+namespace net {
+
class URLRequestAboutJob : public URLRequestJob {
public:
explicit URLRequestAboutJob(URLRequest* request);
@@ -26,4 +28,6 @@ class URLRequestAboutJob : public URLRequestJob {
void StartAsync();
};
+} // namespace net
+
#endif // NET_URL_REQUEST_URL_REQUEST_ABOUT_JOB_H_
diff --git a/net/url_request/url_request_context.cc b/net/url_request/url_request_context.cc
index 281aa7e..3bc7da6 100644
--- a/net/url_request/url_request_context.cc
+++ b/net/url_request/url_request_context.cc
@@ -11,6 +11,7 @@
URLRequestContext::URLRequestContext()
: net_log_(NULL),
host_resolver_(NULL),
+ cert_verifier_(NULL),
dnsrr_resolver_(NULL),
dns_cert_checker_(NULL),
http_transaction_factory_(NULL),
@@ -28,3 +29,7 @@ const std::string& URLRequestContext::GetUserAgent(const GURL& url) const {
URLRequestContext::~URLRequestContext() {
}
+
+void URLRequestContext::set_cookie_store(net::CookieStore* cookie_store) {
+ cookie_store_ = cookie_store;
+}
diff --git a/net/url_request/url_request_context.h b/net/url_request/url_request_context.h
index bc601b3..d929696 100644
--- a/net/url_request/url_request_context.h
+++ b/net/url_request/url_request_context.h
@@ -21,6 +21,7 @@
#include "net/socket/dns_cert_provenance_checker.h"
namespace net {
+class CertVerifier;
class CookiePolicy;
class CookieStore;
class DnsCertProvenanceChecker;
@@ -34,7 +35,8 @@ class SSLConfigService;
class URLRequest;
} // namespace net
-// Subclass to provide application-specific context for URLRequest instances.
+// Subclass to provide application-specific context for net::URLRequest
+// instances.
class URLRequestContext
: public base::RefCountedThreadSafe<URLRequestContext>,
public NonThreadSafe {
@@ -45,14 +47,34 @@ class URLRequestContext
return net_log_;
}
+ void set_net_log(net::NetLog* net_log) {
+ net_log_ = net_log;
+ }
+
net::HostResolver* host_resolver() const {
return host_resolver_;
}
+ void set_host_resolver(net::HostResolver* host_resolver) {
+ host_resolver_ = host_resolver;
+ }
+
+ net::CertVerifier* cert_verifier() const {
+ return cert_verifier_;
+ }
+
+ void set_cert_verifier(net::CertVerifier* cert_verifier) {
+ cert_verifier_ = cert_verifier;
+ }
+
net::DnsRRResolver* dnsrr_resolver() const {
return dnsrr_resolver_;
}
+ void set_dnsrr_resolver(net::DnsRRResolver* dnsrr_resolver) {
+ dnsrr_resolver_ = dnsrr_resolver;
+ }
+
net::DnsCertProvenanceChecker* dns_cert_checker() const {
return dns_cert_checker_.get();
}
@@ -62,16 +84,33 @@ class URLRequestContext
return proxy_service_;
}
+ void set_proxy_service(net::ProxyService* proxy_service) {
+ proxy_service_ = proxy_service;
+ }
+
// Get the ssl config service for this context.
net::SSLConfigService* ssl_config_service() const {
return ssl_config_service_;
}
+ // Gets the HTTP Authentication Handler Factory for this context.
+ // The factory is only valid for the lifetime of this URLRequestContext
+ net::HttpAuthHandlerFactory* http_auth_handler_factory() {
+ return http_auth_handler_factory_;
+ }
+ void set_http_auth_handler_factory(net::HttpAuthHandlerFactory* factory) {
+ http_auth_handler_factory_ = factory;
+ }
+
// Gets the http transaction factory for this context.
net::HttpTransactionFactory* http_transaction_factory() const {
return http_transaction_factory_;
}
+ void set_http_transaction_factory(net::HttpTransactionFactory* factory) {
+ http_transaction_factory_ = factory;
+ }
+
// Gets the ftp transaction factory for this context.
net::FtpTransactionFactory* ftp_transaction_factory() {
return ftp_transaction_factory_;
@@ -81,6 +120,8 @@ class URLRequestContext
// cookies are not stored).
net::CookieStore* cookie_store() { return cookie_store_.get(); }
+ void set_cookie_store(net::CookieStore* cookie_store);
+
// Gets the cookie policy for this context (may be null, in which case
// cookies are allowed).
net::CookiePolicy* cookie_policy() { return cookie_policy_; }
@@ -91,12 +132,6 @@ class URLRequestContext
// Gets the FTP authentication cache for this context.
net::FtpAuthCache* ftp_auth_cache() { return &ftp_auth_cache_; }
- // Gets the HTTP Authentication Handler Factory for this context.
- // The factory is only valid for the lifetime of this URLRequestContext
- net::HttpAuthHandlerFactory* http_auth_handler_factory() {
- return http_auth_handler_factory_;
- }
-
// Gets the value of 'Accept-Charset' header field.
const std::string& accept_charset() const { return accept_charset_; }
@@ -134,6 +169,7 @@ class URLRequestContext
// subclasses.
net::NetLog* net_log_;
net::HostResolver* host_resolver_;
+ net::CertVerifier* cert_verifier_;
net::DnsRRResolver* dnsrr_resolver_;
scoped_ptr<net::DnsCertProvenanceChecker> dns_cert_checker_;
scoped_refptr<net::ProxyService> proxy_service_;
diff --git a/net/url_request/url_request_data_job.cc b/net/url_request/url_request_data_job.cc
index 737f169..30b22fb 100644
--- a/net/url_request/url_request_data_job.cc
+++ b/net/url_request/url_request_data_job.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// 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.
@@ -7,7 +7,8 @@
#include "net/url_request/url_request_data_job.h"
#include "net/base/data_url.h"
-#include "net/url_request/url_request.h"
+
+namespace net {
// static
URLRequestJob* URLRequestDataJob::Factory(URLRequest* request,
@@ -27,8 +28,10 @@ bool URLRequestDataJob::GetData(std::string* mime_type,
const GURL& url = request_->url();
if (!url.is_valid())
return false;
- return net::DataURL::Parse(url, mime_type, charset, data);
+ return DataURL::Parse(url, mime_type, charset, data);
}
URLRequestDataJob::~URLRequestDataJob() {
}
+
+} // namespace net
diff --git a/net/url_request/url_request_data_job.h b/net/url_request/url_request_data_job.h
index 7171088..e00d43c 100644
--- a/net/url_request/url_request_data_job.h
+++ b/net/url_request/url_request_data_job.h
@@ -12,18 +12,18 @@
#include "net/url_request/url_request_simple_job.h"
namespace net {
+
class URLRequest;
-} // namespace net
class URLRequestDataJob : public URLRequestSimpleJob {
public:
- explicit URLRequestDataJob(net::URLRequest* request);
+ explicit URLRequestDataJob(URLRequest* request);
virtual bool GetData(std::string* mime_type,
std::string* charset,
std::string* data) const;
- static net::URLRequest::ProtocolFactory Factory;
+ static URLRequest::ProtocolFactory Factory;
private:
~URLRequestDataJob();
@@ -31,4 +31,6 @@ class URLRequestDataJob : public URLRequestSimpleJob {
DISALLOW_COPY_AND_ASSIGN(URLRequestDataJob);
};
+} // namespace net
+
#endif // NET_URL_REQUEST_URL_REQUEST_DATA_JOB_H_
diff --git a/net/url_request/url_request_error_job.cc b/net/url_request/url_request_error_job.cc
index 1aeffac..c69e3f5 100644
--- a/net/url_request/url_request_error_job.cc
+++ b/net/url_request/url_request_error_job.cc
@@ -8,7 +8,9 @@
#include "net/base/net_errors.h"
#include "net/url_request/url_request_status.h"
-URLRequestErrorJob::URLRequestErrorJob(net::URLRequest* request, int error)
+namespace net {
+
+URLRequestErrorJob::URLRequestErrorJob(URLRequest* request, int error)
: URLRequestJob(request), error_(error) {
}
@@ -20,3 +22,5 @@ void URLRequestErrorJob::Start() {
void URLRequestErrorJob::StartAsync() {
NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, error_));
}
+
+} // namespace net
diff --git a/net/url_request/url_request_error_job.h b/net/url_request/url_request_error_job.h
index 6e7c879..9d3ba7b 100644
--- a/net/url_request/url_request_error_job.h
+++ b/net/url_request/url_request_error_job.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// Invalid URLs go through this URLRequestJob class rather than being passed
-// to the default job handler.
+// Invalid URLs go through this net::URLRequestJob class rather than being
+// passed to the default job handler.
#ifndef NET_URL_REQUEST_URL_REQUEST_ERROR_JOB_H_
#define NET_URL_REQUEST_URL_REQUEST_ERROR_JOB_H_
@@ -11,9 +11,11 @@
#include "net/url_request/url_request_job.h"
+namespace net {
+
class URLRequestErrorJob : public URLRequestJob {
public:
- URLRequestErrorJob(net::URLRequest* request, int error);
+ URLRequestErrorJob(URLRequest* request, int error);
virtual void Start();
@@ -25,4 +27,6 @@ class URLRequestErrorJob : public URLRequestJob {
int error_;
};
+} // namespace net
+
#endif // NET_URL_REQUEST_URL_REQUEST_ERROR_JOB_H_
diff --git a/net/url_request/url_request_file_dir_job.cc b/net/url_request/url_request_file_dir_job.cc
index 23ff6ff..553add8 100644
--- a/net/url_request/url_request_file_dir_job.cc
+++ b/net/url_request/url_request_file_dir_job.cc
@@ -4,6 +4,7 @@
#include "net/url_request/url_request_file_dir_job.h"
+#include "base/compiler_specific.h"
#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/sys_string_conversions.h"
@@ -20,15 +21,16 @@
using std::string;
-URLRequestFileDirJob::URLRequestFileDirJob(URLRequest* request,
+URLRequestFileDirJob::URLRequestFileDirJob(net::URLRequest* request,
const FilePath& dir_path)
- : URLRequestJob(request),
+ : net::URLRequestJob(request),
dir_path_(dir_path),
canceled_(false),
list_complete_(false),
wrote_header_(false),
read_pending_(false),
- read_buffer_length_(0) {
+ read_buffer_length_(0),
+ ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
}
URLRequestFileDirJob::~URLRequestFileDirJob() {
@@ -39,13 +41,18 @@ URLRequestFileDirJob::~URLRequestFileDirJob() {
void URLRequestFileDirJob::Start() {
// Start reading asynchronously so that all error reporting and data
// callbacks happen as they would for network requests.
- MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
- this, &URLRequestFileDirJob::StartAsync));
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &URLRequestFileDirJob::StartAsync));
}
void URLRequestFileDirJob::StartAsync() {
DCHECK(!lister_);
+ // TODO(willchan): This is stupid. We should tell |lister_| not to call us
+ // back. Fix this stupidity.
+
// AddRef so that *this* cannot be destroyed while the lister_
// is trying to feed us data.
@@ -62,13 +69,15 @@ void URLRequestFileDirJob::Kill() {
canceled_ = true;
- // Don't call CloseLister or dispatch an error to the URLRequest because we
- // want OnListDone to be called to also write the error to the output stream.
- // OnListDone will notify the URLRequest at this time.
+ // Don't call CloseLister or dispatch an error to the net::URLRequest because
+ // we want OnListDone to be called to also write the error to the output
+ // stream. OnListDone will notify the net::URLRequest at this time.
if (lister_)
lister_->Cancel();
- URLRequestJob::Kill();
+ net::URLRequestJob::Kill();
+
+ method_factory_.RevokeAll();
}
bool URLRequestFileDirJob::ReadRawData(net::IOBuffer* buf, int buf_size,
diff --git a/net/url_request/url_request_file_dir_job.h b/net/url_request/url_request_file_dir_job.h
index aefaf5b..bdb9b37 100644
--- a/net/url_request/url_request_file_dir_job.h
+++ b/net/url_request/url_request_file_dir_job.h
@@ -10,16 +10,17 @@
#include "base/file_path.h"
#include "base/file_util.h"
+#include "base/task.h"
#include "net/base/directory_lister.h"
#include "net/url_request/url_request_job.h"
class URLRequestFileDirJob
- : public URLRequestJob,
+ : public net::URLRequestJob,
public net::DirectoryLister::DirectoryListerDelegate {
public:
URLRequestFileDirJob(net::URLRequest* request, const FilePath& dir_path);
- // URLRequestJob methods:
+ // net::URLRequestJob methods:
virtual void Start();
virtual void StartAsync();
virtual void Kill();
@@ -63,6 +64,7 @@ class URLRequestFileDirJob
bool read_pending_;
scoped_refptr<net::IOBuffer> read_buffer_;
int read_buffer_length_;
+ ScopedRunnableMethodFactory<URLRequestFileDirJob> method_factory_;
DISALLOW_COPY_AND_ASSIGN(URLRequestFileDirJob);
};
diff --git a/net/url_request/url_request_file_job.cc b/net/url_request/url_request_file_job.cc
index 526dabf..230ee06 100644
--- a/net/url_request/url_request_file_job.cc
+++ b/net/url_request/url_request_file_job.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// 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.
@@ -40,6 +40,8 @@
#include "base/worker_pool.h"
#endif
+namespace net {
+
#if defined(OS_WIN)
class URLRequestFileJob::AsyncResolver
: public base::RefCountedThreadSafe<URLRequestFileJob::AsyncResolver> {
@@ -83,16 +85,16 @@ class URLRequestFileJob::AsyncResolver
#endif
// static
-URLRequestJob* URLRequestFileJob::Factory(
- URLRequest* request, const std::string& scheme) {
+URLRequestJob* URLRequestFileJob::Factory(URLRequest* request,
+ const std::string& scheme) {
FilePath file_path;
- const bool is_file = net::FileURLToFilePath(request->url(), &file_path);
+ const bool is_file = FileURLToFilePath(request->url(), &file_path);
#if defined(OS_CHROMEOS)
// Check file access.
if (AccessDisabled(file_path))
- return new URLRequestErrorJob(request, net::ERR_ACCESS_DENIED);
+ return new URLRequestErrorJob(request, ERR_ACCESS_DENIED);
#endif
// We need to decide whether to create URLRequestFileJob for file access or
@@ -118,7 +120,8 @@ URLRequestFileJob::URLRequestFileJob(URLRequest* request,
ALLOW_THIS_IN_INITIALIZER_LIST(
io_callback_(this, &URLRequestFileJob::DidRead)),
is_directory_(false),
- remaining_bytes_(0) {
+ remaining_bytes_(0),
+ ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
}
URLRequestFileJob::~URLRequestFileJob() {
@@ -149,8 +152,10 @@ void URLRequestFileJob::Start() {
}
// Continue asynchronously.
- MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
- this, &URLRequestFileJob::DidResolve, exists, file_info));
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &URLRequestFileJob::DidResolve, exists, file_info));
}
void URLRequestFileJob::Kill() {
@@ -164,9 +169,10 @@ void URLRequestFileJob::Kill() {
#endif
URLRequestJob::Kill();
+ method_factory_.RevokeAll();
}
-bool URLRequestFileJob::ReadRawData(net::IOBuffer* dest, int dest_size,
+bool URLRequestFileJob::ReadRawData(IOBuffer* dest, int dest_size,
int *bytes_read) {
DCHECK_NE(dest_size, 0);
DCHECK(bytes_read);
@@ -192,7 +198,7 @@ bool URLRequestFileJob::ReadRawData(net::IOBuffer* dest, int dest_size,
}
// Otherwise, a read error occured. We may just need to wait...
- if (rv == net::ERR_IO_PENDING) {
+ if (rv == ERR_IO_PENDING) {
SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
} else {
NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv));
@@ -217,16 +223,16 @@ bool URLRequestFileJob::GetMimeType(std::string* mime_type) const {
// http://code.google.com/p/chromium/issues/detail?id=59849
base::ThreadRestrictions::ScopedAllowIO allow_io;
DCHECK(request_);
- return net::GetMimeTypeFromFile(file_path_, mime_type);
+ return GetMimeTypeFromFile(file_path_, mime_type);
}
void URLRequestFileJob::SetExtraRequestHeaders(
- const net::HttpRequestHeaders& headers) {
+ const HttpRequestHeaders& headers) {
std::string range_header;
- if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) {
+ if (headers.GetHeader(HttpRequestHeaders::kRange, &range_header)) {
// We only care about "Range" header here.
- std::vector<net::HttpByteRange> ranges;
- if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) {
+ std::vector<HttpByteRange> ranges;
+ if (HttpUtil::ParseRangeHeader(range_header, &ranges)) {
if (ranges.size() == 1) {
byte_range_ = ranges[0];
} else {
@@ -235,7 +241,7 @@ void URLRequestFileJob::SetExtraRequestHeaders(
// TODO(hclam): decide whether we want to support multiple range
// requests.
NotifyDone(URLRequestStatus(URLRequestStatus::FAILED,
- net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
+ ERR_REQUEST_RANGE_NOT_SATISFIABLE));
}
}
}
@@ -253,7 +259,7 @@ void URLRequestFileJob::DidResolve(
is_directory_ = file_info.is_directory;
- int rv = net::OK;
+ int rv = OK;
// We use URLRequestFileJob to handle files as well as directories without
// trailing slash.
// If a directory does not exist, we return ERR_FILE_NOT_FOUND. Otherwise,
@@ -263,7 +269,7 @@ void URLRequestFileJob::DidResolve(
// So what happens is we append it with trailing slash and redirect it to
// FileDirJob where it is resolved as invalid.
if (!exists) {
- rv = net::ERR_FILE_NOT_FOUND;
+ rv = ERR_FILE_NOT_FOUND;
} else if (!is_directory_) {
// URL requests should not block on the disk!
// http://code.google.com/p/chromium/issues/detail?id=59849
@@ -275,14 +281,14 @@ void URLRequestFileJob::DidResolve(
rv = stream_.Open(file_path_, flags);
}
- if (rv != net::OK) {
+ if (rv != OK) {
NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv));
return;
}
if (!byte_range_.ComputeBounds(file_info.size)) {
NotifyDone(URLRequestStatus(URLRequestStatus::FAILED,
- net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
+ ERR_REQUEST_RANGE_NOT_SATISFIABLE));
return;
}
@@ -294,9 +300,9 @@ void URLRequestFileJob::DidResolve(
if (remaining_bytes_ > 0 &&
byte_range_.first_byte_position() != 0 &&
byte_range_.first_byte_position() !=
- stream_.Seek(net::FROM_BEGIN, byte_range_.first_byte_position())) {
+ stream_.Seek(FROM_BEGIN, byte_range_.first_byte_position())) {
NotifyDone(URLRequestStatus(URLRequestStatus::FAILED,
- net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
+ ERR_REQUEST_RANGE_NOT_SATISFIABLE));
return;
}
@@ -348,7 +354,7 @@ bool URLRequestFileJob::IsRedirectResponse(GURL* location,
if (!resolved)
return false;
- *location = net::FilePathToFileURL(new_path);
+ *location = FilePathToFileURL(new_path);
*http_status_code = 301;
return true;
#else
@@ -359,6 +365,7 @@ bool URLRequestFileJob::IsRedirectResponse(GURL* location,
#if defined(OS_CHROMEOS)
static const char* const kLocalAccessWhiteList[] = {
"/home/chronos/user/Downloads",
+ "/media",
"/mnt/partner_partition",
"/usr/share/chromeos-assets",
"/tmp",
@@ -383,3 +390,4 @@ bool URLRequestFileJob::AccessDisabled(const FilePath& file_path) {
}
#endif
+} // namespace net
diff --git a/net/url_request/url_request_file_job.h b/net/url_request/url_request_file_job.h
index e745cfd..1a09b04 100644
--- a/net/url_request/url_request_file_job.h
+++ b/net/url_request/url_request_file_job.h
@@ -10,6 +10,7 @@
#include <vector>
#include "base/file_path.h"
+#include "base/task.h"
#include "net/base/completion_callback.h"
#include "net/base/file_stream.h"
#include "net/http/http_byte_range.h"
@@ -20,6 +21,8 @@ namespace file_util {
struct FileInfo;
}
+namespace net {
+
// A request job that handles reading file URLs
class URLRequestFileJob : public URLRequestJob {
public:
@@ -27,12 +30,12 @@ class URLRequestFileJob : public URLRequestJob {
virtual void Start();
virtual void Kill();
- virtual bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read);
+ virtual bool ReadRawData(IOBuffer* buf, int buf_size, int* bytes_read);
virtual bool IsRedirectResponse(GURL* location, int* http_status_code);
virtual bool GetContentEncodings(
std::vector<Filter::FilterType>* encoding_type);
virtual bool GetMimeType(std::string* mime_type) const;
- virtual void SetExtraRequestHeaders(const net::HttpRequestHeaders& headers);
+ virtual void SetExtraRequestHeaders(const HttpRequestHeaders& headers);
static URLRequest::ProtocolFactory Factory;
@@ -50,11 +53,11 @@ class URLRequestFileJob : public URLRequestJob {
void DidResolve(bool exists, const base::PlatformFileInfo& file_info);
void DidRead(int result);
- net::CompletionCallbackImpl<URLRequestFileJob> io_callback_;
- net::FileStream stream_;
+ CompletionCallbackImpl<URLRequestFileJob> io_callback_;
+ FileStream stream_;
bool is_directory_;
- net::HttpByteRange byte_range_;
+ HttpByteRange byte_range_;
int64 remaining_bytes_;
#if defined(OS_WIN)
@@ -63,7 +66,11 @@ class URLRequestFileJob : public URLRequestJob {
scoped_refptr<AsyncResolver> async_resolver_;
#endif
+ ScopedRunnableMethodFactory<URLRequestFileJob> method_factory_;
+
DISALLOW_COPY_AND_ASSIGN(URLRequestFileJob);
};
+} // namespace net
+
#endif // NET_URL_REQUEST_URL_REQUEST_FILE_JOB_H_
diff --git a/net/url_request/url_request_filter.cc b/net/url_request/url_request_filter.cc
index fb305b2..946c2c3 100644
--- a/net/url_request/url_request_filter.cc
+++ b/net/url_request/url_request_filter.cc
@@ -27,12 +27,12 @@ net::URLRequestJob* URLRequestFilter::Factory(net::URLRequest* request,
URLRequestFilter::~URLRequestFilter() {}
void URLRequestFilter::AddHostnameHandler(const std::string& scheme,
- const std::string& hostname, URLRequest::ProtocolFactory* factory) {
+ const std::string& hostname, net::URLRequest::ProtocolFactory* factory) {
hostname_handler_map_[make_pair(scheme, hostname)] = factory;
// Register with the ProtocolFactory.
- URLRequest::RegisterProtocolFactory(scheme,
- &URLRequestFilter::Factory);
+ net::URLRequest::RegisterProtocolFactory(scheme,
+ &URLRequestFilter::Factory);
#ifndef NDEBUG
// Check to see if we're masking URLs in the url_handler_map_.
@@ -54,20 +54,22 @@ void URLRequestFilter::RemoveHostnameHandler(const std::string& scheme,
DCHECK(iter != hostname_handler_map_.end());
hostname_handler_map_.erase(iter);
- // Note that we don't unregister from the URLRequest ProtocolFactory as this
- // would left no protocol factory for the scheme. URLRequestFilter::Factory
- // will keep forwarding the requests to the URLRequestInetJob.
+ // Note that we don't unregister from the net::URLRequest ProtocolFactory as
+ // this would left no protocol factory for the scheme.
+ // URLRequestFilter::Factory will keep forwarding the requests to the
+ // URLRequestInetJob.
}
-bool URLRequestFilter::AddUrlHandler(const GURL& url,
- URLRequest::ProtocolFactory* factory) {
+bool URLRequestFilter::AddUrlHandler(
+ const GURL& url,
+ net::URLRequest::ProtocolFactory* factory) {
if (!url.is_valid())
return false;
url_handler_map_[url.spec()] = factory;
// Register with the ProtocolFactory.
- URLRequest::RegisterProtocolFactory(url.scheme(),
- &URLRequestFilter::Factory);
+ net::URLRequest::RegisterProtocolFactory(url.scheme(),
+ &URLRequestFilter::Factory);
#ifndef NDEBUG
// Check to see if this URL is masked by a hostname handler.
HostnameHandlerMap::iterator host_it =
@@ -84,9 +86,10 @@ void URLRequestFilter::RemoveUrlHandler(const GURL& url) {
DCHECK(iter != url_handler_map_.end());
url_handler_map_.erase(iter);
- // Note that we don't unregister from the URLRequest ProtocolFactory as this
- // would left no protocol factory for the scheme. URLRequestFilter::Factory
- // will keep forwarding the requests to the URLRequestInetJob.
+ // Note that we don't unregister from the net::URLRequest ProtocolFactory as
+ // this would left no protocol factory for the scheme.
+ // URLRequestFilter::Factory will keep forwarding the requests to the
+ // URLRequestInetJob.
}
void URLRequestFilter::ClearHandlers() {
@@ -102,7 +105,7 @@ void URLRequestFilter::ClearHandlers() {
}
for (std::set<std::string>::const_iterator scheme = schemes.begin();
scheme != schemes.end(); ++scheme) {
- URLRequest::RegisterProtocolFactory(*scheme, NULL);
+ net::URLRequest::RegisterProtocolFactory(*scheme, NULL);
}
url_handler_map_.clear();
diff --git a/net/url_request/url_request_filter.h b/net/url_request/url_request_filter.h
index c3021cb..716ad4d 100644
--- a/net/url_request/url_request_filter.h
+++ b/net/url_request/url_request_filter.h
@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// A class to help filter URLRequest jobs based on the URL of the request
+// A class to help filter net::URLRequest jobs based on the URL of the request
// rather than just the scheme. Example usage:
//
// // Use as an "http" handler.
-// URLRequest::RegisterProtocolFactory("http", &URLRequestFilter::Factory);
+// net::URLRequest::RegisterProtocolFactory("http", &URLRequestFilter::Factory);
// // Add special handling for the URL http://foo.com/
// URLRequestFilter::GetInstance()->AddUrlHandler(
// GURL("http://foo.com/"),
@@ -36,26 +36,27 @@ class URLRequestFilter {
public:
// scheme,hostname -> ProtocolFactory
typedef std::map<std::pair<std::string, std::string>,
- URLRequest::ProtocolFactory*> HostnameHandlerMap;
- typedef base::hash_map<std::string, URLRequest::ProtocolFactory*>
+ net::URLRequest::ProtocolFactory*> HostnameHandlerMap;
+ typedef base::hash_map<std::string, net::URLRequest::ProtocolFactory*>
UrlHandlerMap;
// Singleton instance for use.
static URLRequestFilter* GetInstance();
- static URLRequest::ProtocolFactory Factory;
+ static net::URLRequest::ProtocolFactory Factory;
~URLRequestFilter();
void AddHostnameHandler(const std::string& scheme,
const std::string& hostname,
- URLRequest::ProtocolFactory* factory);
+ net::URLRequest::ProtocolFactory* factory);
void RemoveHostnameHandler(const std::string& scheme,
const std::string& hostname);
// Returns true if we successfully added the URL handler. This will replace
// old handlers for the URL if one existed.
- bool AddUrlHandler(const GURL& url, URLRequest::ProtocolFactory* factory);
+ bool AddUrlHandler(const GURL& url,
+ net::URLRequest::ProtocolFactory* factory);
void RemoveUrlHandler(const GURL& url);
@@ -70,7 +71,7 @@ class URLRequestFilter {
URLRequestFilter();
// Helper method that looks up the request in the url_handler_map_.
- net::URLRequestJob* FindRequestHandler(URLRequest* request,
+ net::URLRequestJob* FindRequestHandler(net::URLRequest* request,
const std::string& scheme);
// Maps hostnames to factories. Hostnames take priority over URLs.
diff --git a/net/url_request/url_request_ftp_job.cc b/net/url_request/url_request_ftp_job.cc
index aec8248..ea9b23c 100644
--- a/net/url_request/url_request_ftp_job.cc
+++ b/net/url_request/url_request_ftp_job.cc
@@ -16,6 +16,8 @@
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_error_job.h"
+namespace net {
+
URLRequestFtpJob::URLRequestFtpJob(URLRequest* request)
: URLRequestJob(request),
ALLOW_THIS_IN_INITIALIZER_LIST(
@@ -23,7 +25,8 @@ URLRequestFtpJob::URLRequestFtpJob(URLRequest* request)
ALLOW_THIS_IN_INITIALIZER_LIST(
read_callback_(this, &URLRequestFtpJob::OnReadCompleted)),
read_in_progress_(false),
- context_(request->context()) {
+ context_(request->context()),
+ ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
}
URLRequestFtpJob::~URLRequestFtpJob() {
@@ -36,8 +39,8 @@ URLRequestJob* URLRequestFtpJob::Factory(URLRequest* request,
int port = request->url().IntPort();
if (request->url().has_port() &&
- !net::IsPortAllowedByFtp(port) && !net::IsPortAllowedByOverride(port))
- return new URLRequestErrorJob(request, net::ERR_UNSAFE_PORT);
+ !IsPortAllowedByFtp(port) && !IsPortAllowedByOverride(port))
+ return new URLRequestErrorJob(request, ERR_UNSAFE_PORT);
DCHECK(request->context());
DCHECK(request->context()->ftp_transaction_factory());
@@ -61,13 +64,14 @@ void URLRequestFtpJob::Start() {
void URLRequestFtpJob::Kill() {
if (!transaction_.get())
return;
- DestroyTransaction();
+ transaction_.reset();
URLRequestJob::Kill();
+ method_factory_.RevokeAll();
}
-net::LoadState URLRequestFtpJob::GetLoadState() const {
+LoadState URLRequestFtpJob::GetLoadState() const {
return transaction_.get() ?
- transaction_->GetLoadState() : net::LOAD_STATE_IDLE;
+ transaction_->GetLoadState() : LOAD_STATE_IDLE;
}
bool URLRequestFtpJob::NeedsAuth() {
@@ -75,17 +79,17 @@ bool URLRequestFtpJob::NeedsAuth() {
// requires auth (and not a proxy), because connecting to FTP via proxy
// effectively means the browser communicates via HTTP, and uses HTTP's
// Proxy-Authenticate protocol when proxy servers require auth.
- return server_auth_ && server_auth_->state == net::AUTH_STATE_NEED_AUTH;
+ return server_auth_ && server_auth_->state == AUTH_STATE_NEED_AUTH;
}
void URLRequestFtpJob::GetAuthChallengeInfo(
- scoped_refptr<net::AuthChallengeInfo>* result) {
+ scoped_refptr<AuthChallengeInfo>* result) {
DCHECK((server_auth_ != NULL) &&
- (server_auth_->state == net::AUTH_STATE_NEED_AUTH));
- scoped_refptr<net::AuthChallengeInfo> auth_info(new net::AuthChallengeInfo);
+ (server_auth_->state == AUTH_STATE_NEED_AUTH));
+ scoped_refptr<AuthChallengeInfo> auth_info(new AuthChallengeInfo);
auth_info->is_proxy = false;
auth_info->host_and_port = ASCIIToWide(
- net::GetHostAndPort(request_->url()));
+ GetHostAndPort(request_->url()));
auth_info->scheme = L"";
auth_info->realm = L"";
result->swap(auth_info);
@@ -94,7 +98,7 @@ void URLRequestFtpJob::GetAuthChallengeInfo(
void URLRequestFtpJob::SetAuth(const string16& username,
const string16& password) {
DCHECK(NeedsAuth());
- server_auth_->state = net::AUTH_STATE_HAVE_AUTH;
+ server_auth_->state = AUTH_STATE_HAVE_AUTH;
server_auth_->username = username;
server_auth_->password = password;
@@ -106,16 +110,22 @@ void URLRequestFtpJob::SetAuth(const string16& username,
void URLRequestFtpJob::CancelAuth() {
DCHECK(NeedsAuth());
- server_auth_->state = net::AUTH_STATE_CANCELED;
+ server_auth_->state = AUTH_STATE_CANCELED;
// Once the auth is cancelled, we proceed with the request as though
// there were no auth. Schedule this for later so that we don't cause
// any recursing into the caller as a result of this call.
- MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
- this, &URLRequestFtpJob::OnStartCompleted, net::OK));
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &URLRequestFtpJob::OnStartCompleted, OK));
}
-bool URLRequestFtpJob::ReadRawData(net::IOBuffer* buf,
+uint64 URLRequestFtpJob::GetUploadProgress() const {
+ return 0;
+}
+
+bool URLRequestFtpJob::ReadRawData(IOBuffer* buf,
int buf_size,
int *bytes_read) {
DCHECK_NE(buf_size, 0);
@@ -128,7 +138,7 @@ bool URLRequestFtpJob::ReadRawData(net::IOBuffer* buf,
return true;
}
- if (rv == net::ERR_IO_PENDING) {
+ if (rv == ERR_IO_PENDING) {
read_in_progress_ = true;
SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
} else {
@@ -138,13 +148,6 @@ bool URLRequestFtpJob::ReadRawData(net::IOBuffer* buf,
}
void URLRequestFtpJob::OnStartCompleted(int result) {
- // If the request was destroyed, then there is no more work to do.
- if (!request_ || !request_->delegate())
- return;
- // If the transaction was destroyed, then the job was cancelled, and
- // we can just ignore this notification.
- if (!transaction_.get())
- return;
// Clear the IO_PENDING status
SetStatus(URLRequestStatus());
@@ -153,20 +156,20 @@ void URLRequestFtpJob::OnStartCompleted(int result) {
set_expected_content_size(
transaction_->GetResponseInfo()->expected_content_size);
- if (result == net::OK) {
+ if (result == OK) {
NotifyHeadersComplete();
} else if (transaction_->GetResponseInfo()->needs_auth) {
GURL origin = request_->url().GetOrigin();
- if (server_auth_ && server_auth_->state == net::AUTH_STATE_HAVE_AUTH) {
+ if (server_auth_ && server_auth_->state == AUTH_STATE_HAVE_AUTH) {
request_->context()->ftp_auth_cache()->Remove(origin,
server_auth_->username,
server_auth_->password);
} else if (!server_auth_) {
- server_auth_ = new net::AuthData();
+ server_auth_ = new AuthData();
}
- server_auth_->state = net::AUTH_STATE_NEED_AUTH;
+ server_auth_->state = AUTH_STATE_NEED_AUTH;
- net::FtpAuthCache::Entry* cached_auth =
+ FtpAuthCache::Entry* cached_auth =
request_->context()->ftp_auth_cache()->Lookup(origin);
if (cached_auth) {
@@ -195,7 +198,7 @@ void URLRequestFtpJob::OnReadCompleted(int result) {
}
void URLRequestFtpJob::RestartTransactionWithAuth() {
- DCHECK(server_auth_ && server_auth_->state == net::AUTH_STATE_HAVE_AUTH);
+ DCHECK(server_auth_ && server_auth_->state == AUTH_STATE_HAVE_AUTH);
// No matter what, we want to report our status as IO pending since we will
// be notifying our consumer asynchronously via OnStartCompleted.
@@ -204,7 +207,7 @@ void URLRequestFtpJob::RestartTransactionWithAuth() {
int rv = transaction_->RestartWithAuth(server_auth_->username,
server_auth_->password,
&start_callback_);
- if (rv == net::ERR_IO_PENDING)
+ if (rv == ERR_IO_PENDING)
return;
MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
@@ -218,7 +221,7 @@ void URLRequestFtpJob::StartTransaction() {
DCHECK(request_->context()->ftp_transaction_factory());
transaction_.reset(
- request_->context()->ftp_transaction_factory()->CreateTransaction());
+ request_->context()->ftp_transaction_factory()->CreateTransaction());
// No matter what, we want to report our status as IO pending since we will
// be notifying our consumer asynchronously via OnStartCompleted.
@@ -227,19 +230,17 @@ void URLRequestFtpJob::StartTransaction() {
if (transaction_.get()) {
rv = transaction_->Start(
&request_info_, &start_callback_, request_->net_log());
- if (rv == net::ERR_IO_PENDING)
+ if (rv == ERR_IO_PENDING)
return;
} else {
- rv = net::ERR_FAILED;
+ rv = ERR_FAILED;
}
// The transaction started synchronously, but we need to notify the
// URLRequest delegate via the message loop.
- MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
- this, &URLRequestFtpJob::OnStartCompleted, rv));
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &URLRequestFtpJob::OnStartCompleted, rv));
}
-void URLRequestFtpJob::DestroyTransaction() {
- DCHECK(transaction_.get());
-
- transaction_.reset();
-}
+} // namespace net
diff --git a/net/url_request/url_request_ftp_job.h b/net/url_request/url_request_ftp_job.h
index bd2fdc8..d503766 100644
--- a/net/url_request/url_request_ftp_job.h
+++ b/net/url_request/url_request_ftp_job.h
@@ -9,6 +9,7 @@
#include <string>
#include "base/string16.h"
+#include "base/task.h"
#include "net/base/auth.h"
#include "net/base/completion_callback.h"
#include "net/ftp/ftp_request_info.h"
@@ -17,38 +18,39 @@
class URLRequestContext;
+namespace net {
+
// A URLRequestJob subclass that is built on top of FtpTransaction. It
// provides an implementation for FTP.
class URLRequestFtpJob : public URLRequestJob {
public:
- explicit URLRequestFtpJob(net::URLRequest* request);
+ explicit URLRequestFtpJob(URLRequest* request);
- static URLRequestJob* Factory(net::URLRequest* request,
+ static URLRequestJob* Factory(URLRequest* request,
const std::string& scheme);
- // URLRequestJob methods:
+ // Overridden from URLRequestJob:
virtual bool GetMimeType(std::string* mime_type) const;
private:
virtual ~URLRequestFtpJob();
- // URLRequestJob methods:
+ // Overridden from URLRequestJob:
virtual void Start();
virtual void Kill();
- virtual net::LoadState GetLoadState() const;
+ virtual LoadState GetLoadState() const;
virtual bool NeedsAuth();
virtual void GetAuthChallengeInfo(
- scoped_refptr<net::AuthChallengeInfo>* auth_info);
+ scoped_refptr<AuthChallengeInfo>* auth_info);
virtual void SetAuth(const string16& username,
const string16& password);
virtual void CancelAuth();
// TODO(ibrar): Yet to give another look at this function.
- virtual uint64 GetUploadProgress() const { return 0; }
- virtual bool ReadRawData(net::IOBuffer* buf, int buf_size, int *bytes_read);
+ virtual uint64 GetUploadProgress() const;
+ virtual bool ReadRawData(IOBuffer* buf, int buf_size, int *bytes_read);
- void DestroyTransaction();
void StartTransaction();
void OnStartCompleted(int result);
@@ -58,21 +60,25 @@ class URLRequestFtpJob : public URLRequestJob {
void LogFtpServerType(char server_type);
- net::FtpRequestInfo request_info_;
- scoped_ptr<net::FtpTransaction> transaction_;
+ FtpRequestInfo request_info_;
+ scoped_ptr<FtpTransaction> transaction_;
- net::CompletionCallbackImpl<URLRequestFtpJob> start_callback_;
- net::CompletionCallbackImpl<URLRequestFtpJob> read_callback_;
+ CompletionCallbackImpl<URLRequestFtpJob> start_callback_;
+ CompletionCallbackImpl<URLRequestFtpJob> read_callback_;
bool read_in_progress_;
- scoped_refptr<net::AuthData> server_auth_;
+ scoped_refptr<AuthData> server_auth_;
// Keep a reference to the url request context to be sure it's not deleted
// before us.
scoped_refptr<URLRequestContext> context_;
+ ScopedRunnableMethodFactory<URLRequestFtpJob> method_factory_;
+
DISALLOW_COPY_AND_ASSIGN(URLRequestFtpJob);
};
+} // namespace net
+
#endif // NET_URL_REQUEST_URL_REQUEST_FTP_JOB_H_
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index af98de5..5457855 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -38,6 +38,46 @@
static const char kAvailDictionaryHeader[] = "Avail-Dictionary";
+namespace net {
+
+namespace {
+
+class HTTPSProberDelegateImpl : public HTTPSProberDelegate {
+ public:
+ HTTPSProberDelegateImpl(const std::string& host, int max_age,
+ bool include_subdomains,
+ TransportSecurityState* sts)
+ : host_(host),
+ max_age_(max_age),
+ include_subdomains_(include_subdomains),
+ sts_(sts) { }
+
+ virtual void ProbeComplete(bool result) {
+ if (result) {
+ base::Time current_time(base::Time::Now());
+ base::TimeDelta max_age_delta = base::TimeDelta::FromSeconds(max_age_);
+
+ TransportSecurityState::DomainState domain_state;
+ domain_state.expiry = current_time + max_age_delta;
+ domain_state.mode =
+ TransportSecurityState::DomainState::MODE_OPPORTUNISTIC;
+ domain_state.include_subdomains = include_subdomains_;
+
+ sts_->EnableHost(host_, domain_state);
+ }
+
+ delete this;
+ }
+
+ private:
+ const std::string host_;
+ const int max_age_;
+ const bool include_subdomains_;
+ scoped_refptr<TransportSecurityState> sts_;
+};
+
+} // namespace
+
// TODO(darin): make sure the port blocking code is not lost
// static
URLRequestJob* URLRequestHttpJob::Factory(URLRequest* request,
@@ -45,23 +85,23 @@ URLRequestJob* URLRequestHttpJob::Factory(URLRequest* request,
DCHECK(scheme == "http" || scheme == "https");
int port = request->url().IntPort();
- if (!net::IsPortAllowedByDefault(port) && !net::IsPortAllowedByOverride(port))
- return new URLRequestErrorJob(request, net::ERR_UNSAFE_PORT);
+ if (!IsPortAllowedByDefault(port) && !IsPortAllowedByOverride(port))
+ return new URLRequestErrorJob(request, ERR_UNSAFE_PORT);
if (!request->context() ||
!request->context()->http_transaction_factory()) {
NOTREACHED() << "requires a valid context";
- return new URLRequestErrorJob(request, net::ERR_INVALID_ARGUMENT);
+ return new URLRequestErrorJob(request, ERR_INVALID_ARGUMENT);
}
- net::TransportSecurityState::DomainState domain_state;
+ TransportSecurityState::DomainState domain_state;
if (scheme == "http" &&
(request->url().port().empty() || port == 80) &&
request->context()->transport_security_state() &&
request->context()->transport_security_state()->IsEnabledForHost(
&domain_state, request->url().host())) {
if (domain_state.mode ==
- net::TransportSecurityState::DomainState::MODE_STRICT) {
+ TransportSecurityState::DomainState::MODE_STRICT) {
DCHECK_EQ(request->url().scheme(), "http");
url_canon::Replacements<char> replacements;
static const char kNewScheme[] = "https";
@@ -81,8 +121,8 @@ URLRequestHttpJob::URLRequestHttpJob(URLRequest* request)
: URLRequestJob(request),
response_info_(NULL),
response_cookies_save_index_(0),
- proxy_auth_state_(net::AUTH_STATE_DONT_NEED_AUTH),
- server_auth_state_(net::AUTH_STATE_DONT_NEED_AUTH),
+ proxy_auth_state_(AUTH_STATE_DONT_NEED_AUTH),
+ server_auth_state_(AUTH_STATE_DONT_NEED_AUTH),
ALLOW_THIS_IN_INITIALIZER_LIST(can_get_cookies_callback_(
this, &URLRequestHttpJob::OnCanGetCookiesCompleted)),
ALLOW_THIS_IN_INITIALIZER_LIST(can_set_cookie_callback_(
@@ -93,12 +133,13 @@ URLRequestHttpJob::URLRequestHttpJob(URLRequest* request)
this, &URLRequestHttpJob::OnReadCompleted)),
read_in_progress_(false),
transaction_(NULL),
- throttling_entry_(net::URLRequestThrottlerManager::GetInstance()->
+ throttling_entry_(URLRequestThrottlerManager::GetInstance()->
RegisterRequestUrl(request->url())),
sdch_dictionary_advertised_(false),
sdch_test_activated_(false),
sdch_test_control_(false),
- is_cached_content_(false) {
+ is_cached_content_(false),
+ ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
}
URLRequestHttpJob::~URLRequestHttpJob() {
@@ -129,13 +170,13 @@ URLRequestHttpJob::~URLRequestHttpJob() {
}
}
-void URLRequestHttpJob::SetUpload(net::UploadData* upload) {
+void URLRequestHttpJob::SetUpload(UploadData* upload) {
DCHECK(!transaction_.get()) << "cannot change once started";
request_info_.upload_data = upload;
}
void URLRequestHttpJob::SetExtraRequestHeaders(
- const net::HttpRequestHeaders& headers) {
+ const HttpRequestHeaders& headers) {
DCHECK(!transaction_.get()) << "cannot change once started";
request_info_.extra_headers.CopyFrom(headers);
}
@@ -154,7 +195,7 @@ void URLRequestHttpJob::Start() {
if (request_->context()) {
request_info_.extra_headers.SetHeader(
- net::HttpRequestHeaders::kUserAgent,
+ HttpRequestHeaders::kUserAgent,
request_->context()->GetUserAgent(request_->url()));
}
@@ -170,9 +211,9 @@ void URLRequestHttpJob::Kill() {
URLRequestJob::Kill();
}
-net::LoadState URLRequestHttpJob::GetLoadState() const {
+LoadState URLRequestHttpJob::GetLoadState() const {
return transaction_.get() ?
- transaction_->GetLoadState() : net::LOAD_STATE_IDLE;
+ transaction_->GetLoadState() : LOAD_STATE_IDLE;
}
uint64 URLRequestHttpJob::GetUploadProgress() const {
@@ -197,7 +238,7 @@ bool URLRequestHttpJob::GetCharset(std::string* charset) {
return response_info_->headers->GetCharset(charset);
}
-void URLRequestHttpJob::GetResponseInfo(net::HttpResponseInfo* info) {
+void URLRequestHttpJob::GetResponseInfo(HttpResponseInfo* info) {
DCHECK(request_);
DCHECK(transaction_.get());
@@ -252,6 +293,10 @@ bool URLRequestHttpJob::GetContentEncodings(
return !encoding_types->empty();
}
+bool URLRequestHttpJob::IsCachedContent() const {
+ return is_cached_content_;
+}
+
bool URLRequestHttpJob::IsSdchResponse() const {
return sdch_dictionary_advertised_;
}
@@ -287,27 +332,27 @@ bool URLRequestHttpJob::NeedsAuth() {
// because we either provided no auth info, or provided incorrect info.
switch (code) {
case 407:
- if (proxy_auth_state_ == net::AUTH_STATE_CANCELED)
+ if (proxy_auth_state_ == AUTH_STATE_CANCELED)
return false;
- proxy_auth_state_ = net::AUTH_STATE_NEED_AUTH;
+ proxy_auth_state_ = AUTH_STATE_NEED_AUTH;
return true;
case 401:
- if (server_auth_state_ == net::AUTH_STATE_CANCELED)
+ if (server_auth_state_ == AUTH_STATE_CANCELED)
return false;
- server_auth_state_ = net::AUTH_STATE_NEED_AUTH;
+ server_auth_state_ = AUTH_STATE_NEED_AUTH;
return true;
}
return false;
}
void URLRequestHttpJob::GetAuthChallengeInfo(
- scoped_refptr<net::AuthChallengeInfo>* result) {
+ scoped_refptr<AuthChallengeInfo>* result) {
DCHECK(transaction_.get());
DCHECK(response_info_);
// sanity checks:
- DCHECK(proxy_auth_state_ == net::AUTH_STATE_NEED_AUTH ||
- server_auth_state_ == net::AUTH_STATE_NEED_AUTH);
+ DCHECK(proxy_auth_state_ == AUTH_STATE_NEED_AUTH ||
+ server_auth_state_ == AUTH_STATE_NEED_AUTH);
DCHECK(response_info_->headers->response_code() == 401 ||
response_info_->headers->response_code() == 407);
@@ -319,11 +364,11 @@ void URLRequestHttpJob::SetAuth(const string16& username,
DCHECK(transaction_.get());
// Proxy gets set first, then WWW.
- if (proxy_auth_state_ == net::AUTH_STATE_NEED_AUTH) {
- proxy_auth_state_ = net::AUTH_STATE_HAVE_AUTH;
+ if (proxy_auth_state_ == AUTH_STATE_NEED_AUTH) {
+ proxy_auth_state_ = AUTH_STATE_HAVE_AUTH;
} else {
- DCHECK(server_auth_state_ == net::AUTH_STATE_NEED_AUTH);
- server_auth_state_ = net::AUTH_STATE_HAVE_AUTH;
+ DCHECK(server_auth_state_ == AUTH_STATE_NEED_AUTH);
+ server_auth_state_ = AUTH_STATE_HAVE_AUTH;
}
RestartTransactionWithAuth(username, password);
@@ -343,18 +388,18 @@ void URLRequestHttpJob::RestartTransactionWithAuth(
// headers in the 401/407. Since cookies were already appended to
// extra_headers, we need to strip them out before adding them again.
request_info_.extra_headers.RemoveHeader(
- net::HttpRequestHeaders::kCookie);
+ HttpRequestHeaders::kCookie);
AddCookieHeaderAndStart();
}
void URLRequestHttpJob::CancelAuth() {
// Proxy gets set first, then WWW.
- if (proxy_auth_state_ == net::AUTH_STATE_NEED_AUTH) {
- proxy_auth_state_ = net::AUTH_STATE_CANCELED;
+ if (proxy_auth_state_ == AUTH_STATE_NEED_AUTH) {
+ proxy_auth_state_ = AUTH_STATE_CANCELED;
} else {
- DCHECK(server_auth_state_ == net::AUTH_STATE_NEED_AUTH);
- server_auth_state_ = net::AUTH_STATE_CANCELED;
+ DCHECK(server_auth_state_ == AUTH_STATE_NEED_AUTH);
+ server_auth_state_ = AUTH_STATE_CANCELED;
}
// These will be reset in OnStartCompleted.
@@ -369,12 +414,14 @@ void URLRequestHttpJob::CancelAuth() {
//
// We have to do this via InvokeLater to avoid "recursing" the consumer.
//
- MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
- this, &URLRequestHttpJob::OnStartCompleted, net::OK));
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &URLRequestHttpJob::OnStartCompleted, OK));
}
void URLRequestHttpJob::ContinueWithCertificate(
- net::X509Certificate* client_cert) {
+ X509Certificate* client_cert) {
DCHECK(transaction_.get());
DCHECK(!response_info_) << "should not have a response yet";
@@ -384,13 +431,15 @@ void URLRequestHttpJob::ContinueWithCertificate(
SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
int rv = transaction_->RestartWithCertificate(client_cert, &start_callback_);
- if (rv == net::ERR_IO_PENDING)
+ if (rv == ERR_IO_PENDING)
return;
// The transaction started synchronously, but we need to notify the
// URLRequest delegate via the message loop.
- MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
- this, &URLRequestHttpJob::OnStartCompleted, rv));
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &URLRequestHttpJob::OnStartCompleted, rv));
}
void URLRequestHttpJob::ContinueDespiteLastError() {
@@ -405,16 +454,18 @@ void URLRequestHttpJob::ContinueDespiteLastError() {
SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
int rv = transaction_->RestartIgnoringLastError(&start_callback_);
- if (rv == net::ERR_IO_PENDING)
+ if (rv == ERR_IO_PENDING)
return;
// The transaction started synchronously, but we need to notify the
// URLRequest delegate via the message loop.
- MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
- this, &URLRequestHttpJob::OnStartCompleted, rv));
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &URLRequestHttpJob::OnStartCompleted, rv));
}
-bool URLRequestHttpJob::ReadRawData(net::IOBuffer* buf, int buf_size,
+bool URLRequestHttpJob::ReadRawData(IOBuffer* buf, int buf_size,
int *bytes_read) {
DCHECK_NE(buf_size, 0);
DCHECK(bytes_read);
@@ -426,7 +477,7 @@ bool URLRequestHttpJob::ReadRawData(net::IOBuffer* buf, int buf_size,
return true;
}
- if (rv == net::ERR_IO_PENDING) {
+ if (rv == ERR_IO_PENDING) {
read_in_progress_ = true;
SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
} else {
@@ -444,18 +495,20 @@ void URLRequestHttpJob::StopCaching() {
void URLRequestHttpJob::OnCanGetCookiesCompleted(int policy) {
// If the request was destroyed, then there is no more work to do.
if (request_ && request_->delegate()) {
- if (policy == net::ERR_ACCESS_DENIED) {
- request_->delegate()->OnGetCookies(request_, true);
- } else if (policy == net::OK && request_->context()->cookie_store()) {
- request_->delegate()->OnGetCookies(request_, false);
- net::CookieOptions options;
- options.set_include_httponly();
- std::string cookies =
- request_->context()->cookie_store()->GetCookiesWithOptions(
- request_->url(), options);
- if (!cookies.empty()) {
- request_info_.extra_headers.SetHeader(
- net::HttpRequestHeaders::kCookie, cookies);
+ if (request_->context()->cookie_store()) {
+ if (policy == ERR_ACCESS_DENIED) {
+ request_->delegate()->OnGetCookies(request_, true);
+ } else if (policy == OK) {
+ request_->delegate()->OnGetCookies(request_, false);
+ CookieOptions options;
+ options.set_include_httponly();
+ std::string cookies =
+ request_->context()->cookie_store()->GetCookiesWithOptions(
+ request_->url(), options);
+ if (!cookies.empty()) {
+ request_info_.extra_headers.SetHeader(
+ HttpRequestHeaders::kCookie, cookies);
+ }
}
}
// We may have been canceled within OnGetCookies.
@@ -471,27 +524,28 @@ void URLRequestHttpJob::OnCanGetCookiesCompleted(int policy) {
void URLRequestHttpJob::OnCanSetCookieCompleted(int policy) {
// If the request was destroyed, then there is no more work to do.
if (request_ && request_->delegate()) {
- if (policy == net::ERR_ACCESS_DENIED) {
- request_->delegate()->OnSetCookie(
- request_,
- response_cookies_[response_cookies_save_index_],
- net::CookieOptions(),
- true);
- } else if ((policy == net::OK || policy == net::OK_FOR_SESSION_ONLY) &&
- request_->context()->cookie_store()) {
- // OK to save the current response cookie now.
- net::CookieOptions options;
- options.set_include_httponly();
- if (policy == net::OK_FOR_SESSION_ONLY)
- options.set_force_session();
- request_->context()->cookie_store()->SetCookieWithOptions(
- request_->url(), response_cookies_[response_cookies_save_index_],
- options);
- request_->delegate()->OnSetCookie(
- request_,
- response_cookies_[response_cookies_save_index_],
- options,
- false);
+ if (request_->context()->cookie_store()) {
+ if (policy == ERR_ACCESS_DENIED) {
+ request_->delegate()->OnSetCookie(
+ request_,
+ response_cookies_[response_cookies_save_index_],
+ CookieOptions(),
+ true);
+ } else if (policy == OK || policy == OK_FOR_SESSION_ONLY) {
+ // OK to save the current response cookie now.
+ CookieOptions options;
+ options.set_include_httponly();
+ if (policy == OK_FOR_SESSION_ONLY)
+ options.set_force_session();
+ request_->context()->cookie_store()->SetCookieWithOptions(
+ request_->url(), response_cookies_[response_cookies_save_index_],
+ options);
+ request_->delegate()->OnSetCookie(
+ request_,
+ response_cookies_[response_cookies_save_index_],
+ options,
+ false);
+ }
}
response_cookies_save_index_++;
// We may have been canceled within OnSetCookie.
@@ -517,7 +571,7 @@ void URLRequestHttpJob::OnStartCompleted(int result) {
// Clear the IO_PENDING status
SetStatus(URLRequestStatus());
- if (result == net::OK) {
+ if (result == OK) {
SaveCookiesAndNotifyHeadersComplete();
} else if (ShouldTreatAsCertificateError(result)) {
// We encountered an SSL certificate error. Ask our delegate to decide
@@ -526,7 +580,7 @@ void URLRequestHttpJob::OnStartCompleted(int result) {
// ssl_info.
request_->delegate()->OnSSLCertificateError(
request_, result, transaction_->GetResponseInfo()->ssl_info.cert);
- } else if (result == net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
+ } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
request_->delegate()->OnCertificateRequested(
request_, transaction_->GetResponseInfo()->cert_request_info);
} else {
@@ -550,20 +604,20 @@ void URLRequestHttpJob::OnReadCompleted(int result) {
}
bool URLRequestHttpJob::ShouldTreatAsCertificateError(int result) {
- if (!net::IsCertificateError(result))
+ if (!IsCertificateError(result))
return false;
// Check whether our context is using Strict-Transport-Security.
if (!context_->transport_security_state())
return true;
- net::TransportSecurityState::DomainState domain_state;
+ TransportSecurityState::DomainState domain_state;
// TODO(agl): don't ignore opportunistic mode.
const bool r = context_->transport_security_state()->IsEnabledForHost(
&domain_state, request_info_.url.host());
return !r || domain_state.mode ==
- net::TransportSecurityState::DomainState::MODE_OPPORTUNISTIC;
+ TransportSecurityState::DomainState::MODE_OPPORTUNISTIC;
}
void URLRequestHttpJob::NotifyHeadersComplete() {
@@ -576,7 +630,7 @@ void URLRequestHttpJob::NotifyHeadersComplete() {
is_cached_content_ = response_info_->was_cached;
if (!is_cached_content_) {
- net::URLRequestThrottlerHeaderAdapter response_adapter(
+ URLRequestThrottlerHeaderAdapter response_adapter(
response_info_->headers);
throttling_entry_->UpdateWithResponse(&response_adapter);
}
@@ -641,22 +695,31 @@ void URLRequestHttpJob::StartTransaction() {
rv = request_->context()->http_transaction_factory()->CreateTransaction(
&transaction_);
- if (rv == net::OK) {
- rv = transaction_->Start(
- &request_info_, &start_callback_, request_->net_log());
+ if (rv == OK) {
+ if (!throttling_entry_->IsDuringExponentialBackoff() ||
+ !net::URLRequestThrottlerManager::GetInstance()->
+ enforce_throttling()) {
+ rv = transaction_->Start(
+ &request_info_, &start_callback_, request_->net_log());
+ } else {
+ // Special error code for the exponential back-off module.
+ rv = ERR_TEMPORARILY_THROTTLED;
+ }
// Make sure the context is alive for the duration of the
// transaction.
context_ = request_->context();
}
}
- if (rv == net::ERR_IO_PENDING)
+ if (rv == ERR_IO_PENDING)
return;
// The transaction started synchronously, but we need to notify the
// URLRequest delegate via the message loop.
- MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
- this, &URLRequestHttpJob::OnStartCompleted, rv));
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &URLRequestHttpJob::OnStartCompleted, rv));
}
void URLRequestHttpJob::AddExtraHeaders() {
@@ -695,11 +758,11 @@ void URLRequestHttpJob::AddExtraHeaders() {
if (!advertise_sdch) {
// Tell the server what compression formats we support (other than SDCH).
request_info_.extra_headers.SetHeader(
- net::HttpRequestHeaders::kAcceptEncoding, "gzip,deflate");
+ HttpRequestHeaders::kAcceptEncoding, "gzip,deflate");
} else {
// Include SDCH in acceptable list.
request_info_.extra_headers.SetHeader(
- net::HttpRequestHeaders::kAcceptEncoding, "gzip,deflate,sdch");
+ HttpRequestHeaders::kAcceptEncoding, "gzip,deflate,sdch");
if (!avail_dictionaries.empty()) {
request_info_.extra_headers.SetHeader(
kAvailDictionaryHeader,
@@ -718,19 +781,23 @@ void URLRequestHttpJob::AddExtraHeaders() {
// Only add default Accept-Language and Accept-Charset if the request
// didn't have them specified.
if (!request_info_.extra_headers.HasHeader(
- net::HttpRequestHeaders::kAcceptLanguage)) {
+ HttpRequestHeaders::kAcceptLanguage)) {
request_info_.extra_headers.SetHeader(
+<<<<<<< HEAD
net::HttpRequestHeaders::kAcceptLanguage,
#ifdef ANDROID
context->GetAcceptLanguage());
#else
+=======
+ HttpRequestHeaders::kAcceptLanguage,
+>>>>>>> chromium.org at r10.0.621.0
context->accept_language());
#endif
}
if (!request_info_.extra_headers.HasHeader(
- net::HttpRequestHeaders::kAcceptCharset)) {
+ HttpRequestHeaders::kAcceptCharset)) {
request_info_.extra_headers.SetHeader(
- net::HttpRequestHeaders::kAcceptCharset,
+ HttpRequestHeaders::kAcceptCharset,
context->accept_charset());
}
}
@@ -743,16 +810,16 @@ void URLRequestHttpJob::AddCookieHeaderAndStart() {
AddRef(); // Balanced in OnCanGetCookiesCompleted
- int policy = net::OK;
+ int policy = OK;
- if (request_info_.load_flags & net::LOAD_DO_NOT_SEND_COOKIES) {
- policy = net::ERR_FAILED;
+ if (request_info_.load_flags & LOAD_DO_NOT_SEND_COOKIES) {
+ policy = ERR_FAILED;
} else if (request_->context()->cookie_policy()) {
policy = request_->context()->cookie_policy()->CanGetCookies(
request_->url(),
request_->first_party_for_cookies(),
&can_get_cookies_callback_);
- if (policy == net::ERR_IO_PENDING)
+ if (policy == ERR_IO_PENDING)
return; // Wait for completion callback
}
@@ -762,7 +829,7 @@ void URLRequestHttpJob::AddCookieHeaderAndStart() {
void URLRequestHttpJob::SaveCookiesAndNotifyHeadersComplete() {
DCHECK(transaction_.get());
- const net::HttpResponseInfo* response_info = transaction_->GetResponseInfo();
+ const HttpResponseInfo* response_info = transaction_->GetResponseInfo();
DCHECK(response_info);
response_cookies_.clear();
@@ -789,17 +856,17 @@ void URLRequestHttpJob::SaveNextCookie() {
AddRef(); // Balanced in OnCanSetCookieCompleted
- int policy = net::OK;
+ int policy = OK;
- if (request_info_.load_flags & net::LOAD_DO_NOT_SAVE_COOKIES) {
- policy = net::ERR_FAILED;
+ if (request_info_.load_flags & LOAD_DO_NOT_SAVE_COOKIES) {
+ policy = ERR_FAILED;
} else if (request_->context()->cookie_policy()) {
policy = request_->context()->cookie_policy()->CanSetCookie(
request_->url(),
request_->first_party_for_cookies(),
response_cookies_[response_cookies_save_index_],
&can_set_cookie_callback_);
- if (policy == net::ERR_IO_PENDING)
+ if (policy == ERR_IO_PENDING)
return; // Wait for completion callback
}
@@ -807,7 +874,7 @@ void URLRequestHttpJob::SaveNextCookie() {
}
void URLRequestHttpJob::FetchResponseCookies(
- const net::HttpResponseInfo* response_info,
+ const HttpResponseInfo* response_info,
std::vector<std::string>* cookies) {
std::string name = "Set-Cookie";
std::string value;
@@ -819,40 +886,6 @@ void URLRequestHttpJob::FetchResponseCookies(
}
}
-class HTTPSProberDelegate : public net::HTTPSProberDelegate {
- public:
- HTTPSProberDelegate(const std::string& host, int max_age,
- bool include_subdomains,
- net::TransportSecurityState* sts)
- : host_(host),
- max_age_(max_age),
- include_subdomains_(include_subdomains),
- sts_(sts) { }
-
- virtual void ProbeComplete(bool result) {
- if (result) {
- base::Time current_time(base::Time::Now());
- base::TimeDelta max_age_delta = base::TimeDelta::FromSeconds(max_age_);
-
- net::TransportSecurityState::DomainState domain_state;
- domain_state.expiry = current_time + max_age_delta;
- domain_state.mode =
- net::TransportSecurityState::DomainState::MODE_OPPORTUNISTIC;
- domain_state.include_subdomains = include_subdomains_;
-
- sts_->EnableHost(host_, domain_state);
- }
-
- delete this;
- }
-
- private:
- const std::string host_;
- const int max_age_;
- const bool include_subdomains_;
- scoped_refptr<net::TransportSecurityState> sts_;
-};
-
void URLRequestHttpJob::ProcessStrictTransportSecurityHeader() {
DCHECK(response_info_);
@@ -862,7 +895,7 @@ void URLRequestHttpJob::ProcessStrictTransportSecurityHeader() {
const bool https = response_info_->ssl_info.is_valid();
const bool valid_https =
- https && !net::IsCertStatusError(response_info_->ssl_info.cert_status);
+ https && !IsCertStatusError(response_info_->ssl_info.cert_status);
std::string name = "Strict-Transport-Security";
std::string value;
@@ -872,7 +905,7 @@ void URLRequestHttpJob::ProcessStrictTransportSecurityHeader() {
void* iter = NULL;
while (response_info_->headers->EnumerateHeader(&iter, name, &value)) {
- const bool ok = net::TransportSecurityState::ParseHeader(
+ const bool ok = TransportSecurityState::ParseHeader(
value, &max_age, &include_subdomains);
if (!ok)
continue;
@@ -883,9 +916,9 @@ void URLRequestHttpJob::ProcessStrictTransportSecurityHeader() {
base::Time current_time(base::Time::Now());
base::TimeDelta max_age_delta = base::TimeDelta::FromSeconds(max_age);
- net::TransportSecurityState::DomainState domain_state;
+ TransportSecurityState::DomainState domain_state;
domain_state.expiry = current_time + max_age_delta;
- domain_state.mode = net::TransportSecurityState::DomainState::MODE_STRICT;
+ domain_state.mode = TransportSecurityState::DomainState::MODE_STRICT;
domain_state.include_subdomains = include_subdomains;
ctx->transport_security_state()->EnableHost(request_info_.url.host(),
@@ -897,7 +930,7 @@ void URLRequestHttpJob::ProcessStrictTransportSecurityHeader() {
name = "X-Bodge-Transport-Security";
while (response_info_->headers->EnumerateHeader(&iter, name, &value)) {
- const bool ok = net::TransportSecurityState::ParseHeader(
+ const bool ok = TransportSecurityState::ParseHeader(
value, &max_age, &include_subdomains);
if (!ok)
continue;
@@ -907,10 +940,10 @@ void URLRequestHttpJob::ProcessStrictTransportSecurityHeader() {
base::Time current_time(base::Time::Now());
base::TimeDelta max_age_delta = base::TimeDelta::FromSeconds(max_age);
- net::TransportSecurityState::DomainState domain_state;
+ TransportSecurityState::DomainState domain_state;
domain_state.expiry = current_time + max_age_delta;
domain_state.mode =
- net::TransportSecurityState::DomainState::MODE_SPDY_ONLY;
+ TransportSecurityState::DomainState::MODE_SPDY_ONLY;
domain_state.include_subdomains = include_subdomains;
ctx->transport_security_state()->EnableHost(request_info_.url.host(),
@@ -924,19 +957,21 @@ void URLRequestHttpJob::ProcessStrictTransportSecurityHeader() {
// At this point, we have a request for opportunistic encryption over HTTP.
// In this case we need to probe to check that we can make HTTPS
// connections to that host.
- net::HTTPSProber* const prober = Singleton<net::HTTPSProber>::get();
+ HTTPSProber* const prober = HTTPSProber::GetInstance();
if (prober->HaveProbed(request_info_.url.host()) ||
prober->InFlight(request_info_.url.host())) {
continue;
}
- HTTPSProberDelegate* delegate =
- new HTTPSProberDelegate(request_info_.url.host(), max_age,
- include_subdomains,
- ctx->transport_security_state());
+ HTTPSProberDelegateImpl* delegate =
+ new HTTPSProberDelegateImpl(request_info_.url.host(), max_age,
+ include_subdomains,
+ ctx->transport_security_state());
if (!prober->ProbeHost(request_info_.url.host(), request()->context(),
delegate)) {
delete delegate;
}
}
}
+
+} // namespace net
diff --git a/net/url_request/url_request_http_job.h b/net/url_request/url_request_http_job.h
index c9139b0..78778c5 100644
--- a/net/url_request/url_request_http_job.h
+++ b/net/url_request/url_request_http_job.h
@@ -11,53 +11,55 @@
#include "base/scoped_ptr.h"
#include "base/string16.h"
+#include "base/task.h"
#include "net/base/auth.h"
#include "net/base/completion_callback.h"
#include "net/http/http_request_info.h"
#include "net/url_request/url_request_job.h"
#include "net/url_request/url_request_throttler_entry_interface.h"
+class URLRequestContext;
+
namespace net {
+
class HttpResponseInfo;
class HttpTransaction;
-}
-class URLRequestContext;
-// A URLRequestJob subclass that is built on top of HttpTransaction. It
+// A net::URLRequestJob subclass that is built on top of HttpTransaction. It
// provides an implementation for both HTTP and HTTPS.
class URLRequestHttpJob : public URLRequestJob {
public:
- static URLRequestJob* Factory(net::URLRequest* request,
+ static URLRequestJob* Factory(URLRequest* request,
const std::string& scheme);
protected:
- explicit URLRequestHttpJob(net::URLRequest* request);
+ explicit URLRequestHttpJob(URLRequest* request);
- // URLRequestJob methods:
- virtual void SetUpload(net::UploadData* upload);
- virtual void SetExtraRequestHeaders(const net::HttpRequestHeaders& headers);
+ // Overridden from URLRequestJob:
+ virtual void SetUpload(UploadData* upload);
+ virtual void SetExtraRequestHeaders(const HttpRequestHeaders& headers);
virtual void Start();
virtual void Kill();
- virtual net::LoadState GetLoadState() const;
+ virtual LoadState GetLoadState() const;
virtual uint64 GetUploadProgress() const;
virtual bool GetMimeType(std::string* mime_type) const;
virtual bool GetCharset(std::string* charset);
- virtual void GetResponseInfo(net::HttpResponseInfo* info);
+ virtual void GetResponseInfo(HttpResponseInfo* info);
virtual bool GetResponseCookies(std::vector<std::string>* cookies);
virtual int GetResponseCode() const;
virtual bool GetContentEncodings(
std::vector<Filter::FilterType>* encoding_type);
- virtual bool IsCachedContent() const { return is_cached_content_; }
+ virtual bool IsCachedContent() const;
virtual bool IsSdchResponse() const;
virtual bool IsSafeRedirect(const GURL& location);
virtual bool NeedsAuth();
- virtual void GetAuthChallengeInfo(scoped_refptr<net::AuthChallengeInfo>*);
+ virtual void GetAuthChallengeInfo(scoped_refptr<AuthChallengeInfo>*);
virtual void SetAuth(const string16& username,
const string16& password);
virtual void CancelAuth();
- virtual void ContinueWithCertificate(net::X509Certificate* client_cert);
+ virtual void ContinueWithCertificate(X509Certificate* client_cert);
virtual void ContinueDespiteLastError();
- virtual bool ReadRawData(net::IOBuffer* buf, int buf_size, int *bytes_read);
+ virtual bool ReadRawData(IOBuffer* buf, int buf_size, int *bytes_read);
virtual void StopCaching();
// Shadows URLRequestJob's version of this method so we can grab cookies.
@@ -69,7 +71,7 @@ class URLRequestHttpJob : public URLRequestJob {
void AddCookieHeaderAndStart();
void SaveCookiesAndNotifyHeadersComplete();
void SaveNextCookie();
- void FetchResponseCookies(const net::HttpResponseInfo* response_info,
+ void FetchResponseCookies(const HttpResponseInfo* response_info,
std::vector<std::string>* cookies);
// Process the Strict-Transport-Security header, if one exists.
@@ -89,33 +91,33 @@ class URLRequestHttpJob : public URLRequestJob {
// before us.
scoped_refptr<URLRequestContext> context_;
- net::HttpRequestInfo request_info_;
- const net::HttpResponseInfo* response_info_;
+ HttpRequestInfo request_info_;
+ const HttpResponseInfo* response_info_;
std::vector<std::string> response_cookies_;
size_t response_cookies_save_index_;
// Auth states for proxy and origin server.
- net::AuthState proxy_auth_state_;
- net::AuthState server_auth_state_;
+ AuthState proxy_auth_state_;
+ AuthState server_auth_state_;
string16 username_;
string16 password_;
- net::CompletionCallbackImpl<URLRequestHttpJob> can_get_cookies_callback_;
- net::CompletionCallbackImpl<URLRequestHttpJob> can_set_cookie_callback_;
- net::CompletionCallbackImpl<URLRequestHttpJob> start_callback_;
- net::CompletionCallbackImpl<URLRequestHttpJob> read_callback_;
+ CompletionCallbackImpl<URLRequestHttpJob> can_get_cookies_callback_;
+ CompletionCallbackImpl<URLRequestHttpJob> can_set_cookie_callback_;
+ CompletionCallbackImpl<URLRequestHttpJob> start_callback_;
+ CompletionCallbackImpl<URLRequestHttpJob> read_callback_;
bool read_in_progress_;
// An URL for an SDCH dictionary as suggested in a Get-Dictionary HTTP header.
GURL sdch_dictionary_url_;
- scoped_ptr<net::HttpTransaction> transaction_;
+ scoped_ptr<HttpTransaction> transaction_;
// This is used to supervise traffic and enforce exponential back-off.
- scoped_refptr<net::URLRequestThrottlerEntryInterface> throttling_entry_;
+ scoped_refptr<URLRequestThrottlerEntryInterface> throttling_entry_;
// Indicated if an SDCH dictionary was advertised, and hence an SDCH
// compressed response is expected. We use this to help detect (accidental?)
@@ -135,7 +137,11 @@ class URLRequestHttpJob : public URLRequestJob {
private:
virtual ~URLRequestHttpJob();
+ ScopedRunnableMethodFactory<URLRequestHttpJob> method_factory_;
+
DISALLOW_COPY_AND_ASSIGN(URLRequestHttpJob);
};
+} // namespace net
+
#endif // NET_URL_REQUEST_URL_REQUEST_HTTP_JOB_H_
diff --git a/net/url_request/url_request_job.cc b/net/url_request/url_request_job.cc
index a059a00..0c54c10 100644
--- a/net/url_request/url_request_job.cc
+++ b/net/url_request/url_request_job.cc
@@ -21,6 +21,8 @@
using base::Time;
using base::TimeTicks;
+namespace net {
+
// Buffer size allocated when de-compressing data.
// static
const int URLRequestJob::kFilterBufSize = 32 * 1024;
@@ -443,7 +445,7 @@ void URLRequestJob::NotifyHeadersComplete() {
// Initialize to the current time, and let the subclass optionally override
// the time stamps if it has that information. The default request_time is
- // set by URLRequest before it calls our Start method.
+ // set by net::URLRequest before it calls our Start method.
request_->response_info_.response_time = Time::Now();
GetResponseInfo(&request_->response_info_);
@@ -930,3 +932,5 @@ void URLRequestJob::RecordCompressionHistograms() {
COMPRESSION_HISTOGRAM("NoProxy.ShouldHaveBeenCompressed", decompressed_B);
}
}
+
+} // namespace net
diff --git a/net/url_request/url_request_job.h b/net/url_request/url_request_job.h
index 239f5e9..6f91c9a 100644
--- a/net/url_request/url_request_job.h
+++ b/net/url_request/url_request_job.h
@@ -17,20 +17,18 @@
#include "net/base/filter.h"
#include "net/base/load_states.h"
+class URLRequestStatus;
+
namespace net {
+
class AuthChallengeInfo;
class HttpRequestHeaders;
class HttpResponseInfo;
class IOBuffer;
-class UploadData;
class URLRequest;
-class X509Certificate;
-} // namespace net
-
-class URLRequestStatus;
class URLRequestJobMetrics;
-
-namespace net {
+class UploadData;
+class X509Certificate;
class URLRequestJob : public base::RefCounted<URLRequestJob>,
public FilterContext {
@@ -65,9 +63,9 @@ class URLRequestJob : public base::RefCounted<URLRequestJob>,
// This function MUST somehow call NotifyDone/NotifyCanceled or some requests
// will get leaked. Certain callers use that message to know when they can
- // delete their URLRequest object, even when doing a cancel. The default Kill
- // implementation calls NotifyCanceled, so it is recommended that subclasses
- // call URLRequestJob::Kill() after doing any additional work.
+ // delete their net::URLRequest object, even when doing a cancel. The default
+ // Kill implementation calls NotifyCanceled, so it is recommended that
+ // subclasses call URLRequestJob::Kill() after doing any additional work.
//
// The job should endeavor to stop working as soon as is convenient, but must
// not send and complete notifications from inside this function. Instead,
@@ -90,12 +88,12 @@ class URLRequestJob : public base::RefCounted<URLRequestJob>,
// Called to read post-filtered data from this Job, returning the number of
// bytes read, 0 when there is no more data, or -1 if there was an error.
- // This is just the backend for URLRequest::Read, see that function for more
- // info.
+ // This is just the backend for net::URLRequest::Read, see that function for
+ // more info.
bool Read(net::IOBuffer* buf, int buf_size, int* bytes_read);
// Stops further caching of this request, if any. For more info, see
- // URLRequest::StopCaching().
+ // net::URLRequest::StopCaching().
virtual void StopCaching();
// Called to fetch the current load state for the job.
@@ -157,8 +155,8 @@ class URLRequestJob : public base::RefCounted<URLRequestJob>,
// Called to determine if it is okay to redirect this job to the specified
// location. This may be used to implement protocol-specific restrictions.
- // If this function returns false, then the URLRequest will fail reporting
- // net::ERR_UNSAFE_REDIRECT.
+ // If this function returns false, then the net::URLRequest will fail
+ // reporting net::ERR_UNSAFE_REDIRECT.
virtual bool IsSafeRedirect(const GURL& location);
// Called to determine if this response is asking for authentication. Only
@@ -240,8 +238,8 @@ class URLRequestJob : public base::RefCounted<URLRequestJob>,
// that work.
void CompleteNotifyDone();
- // Used as an asynchronous callback for Kill to notify the URLRequest that
- // we were canceled.
+ // Used as an asynchronous callback for Kill to notify the net::URLRequest
+ // that we were canceled.
void NotifyCanceled();
// Notifies the job the request should be restarted.
@@ -256,7 +254,8 @@ class URLRequestJob : public base::RefCounted<URLRequestJob>,
// If returning false, an error occurred or an async IO is now pending.
// If async IO is pending, the status of the request will be
// URLRequestStatus::IO_PENDING, and buf must remain available until the
- // operation is completed. See comments on URLRequest::Read for more info.
+ // operation is completed. See comments on net::URLRequest::Read for more
+ // info.
virtual bool ReadRawData(net::IOBuffer* buf, int buf_size, int *bytes_read);
// Informs the filter that data has been read into its buffer
@@ -298,9 +297,10 @@ class URLRequestJob : public base::RefCounted<URLRequestJob>,
int prefilter_bytes_read_;
// The number of bytes read after passing through the filter.
int postfilter_bytes_read_;
- // True when (we believe) the content in this URLRequest was compressible.
+ // True when (we believe) the content in this net::URLRequest was
+ // compressible.
bool is_compressible_content_;
- // True when the content in this URLRequest was compressed.
+ // True when the content in this net::URLRequest was compressed.
bool is_compressed_;
private:
@@ -424,6 +424,4 @@ class URLRequestJob : public base::RefCounted<URLRequestJob>,
} // namespace net
-typedef net::URLRequestJob URLRequestJob;
-
#endif // NET_URL_REQUEST_URL_REQUEST_JOB_H_
diff --git a/net/url_request/url_request_job_manager.cc b/net/url_request/url_request_job_manager.cc
index 225092b..9f08fd0 100644
--- a/net/url_request/url_request_job_manager.cc
+++ b/net/url_request/url_request_job_manager.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// 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.
@@ -7,6 +7,7 @@
#include <algorithm>
#include "build/build_config.h"
+#include "base/singleton.h"
#include "base/string_util.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
@@ -22,11 +23,13 @@ namespace {
struct SchemeToFactory {
const char* scheme;
- URLRequest::ProtocolFactory* factory;
+ net::URLRequest::ProtocolFactory* factory;
};
} // namespace
+namespace net {
+
static const SchemeToFactory kBuiltinFactories[] = {
{ "http", URLRequestHttpJob::Factory },
{ "https", URLRequestHttpJob::Factory },
@@ -47,19 +50,25 @@ URLRequestJobManager::URLRequestJobManager() : enable_file_access_(false) {
URLRequestJobManager::~URLRequestJobManager() {}
-URLRequestJob* URLRequestJobManager::CreateJob(URLRequest* request) const {
+// static
+URLRequestJobManager* URLRequestJobManager::GetInstance() {
+ return Singleton<URLRequestJobManager>::get();
+}
+
+net::URLRequestJob* URLRequestJobManager::CreateJob(
+ net::URLRequest* request) const {
#ifndef NDEBUG
DCHECK(IsAllowedThread());
#endif
// If we are given an invalid URL, then don't even try to inspect the scheme.
if (!request->url().is_valid())
- return new URLRequestErrorJob(request, net::ERR_INVALID_URL);
+ return new net::URLRequestErrorJob(request, net::ERR_INVALID_URL);
// We do this here to avoid asking interceptors about unsupported schemes.
const std::string& scheme = request->url().scheme(); // already lowercase
if (!SupportsScheme(scheme))
- return new URLRequestErrorJob(request, net::ERR_UNKNOWN_URL_SCHEME);
+ return new net::URLRequestErrorJob(request, net::ERR_UNKNOWN_URL_SCHEME);
// THREAD-SAFETY NOTICE:
// We do not need to acquire the lock here since we are only reading our
@@ -69,7 +78,7 @@ URLRequestJob* URLRequestJobManager::CreateJob(URLRequest* request) const {
if (!(request->load_flags() & net::LOAD_DISABLE_INTERCEPT)) {
InterceptorList::const_iterator i;
for (i = interceptors_.begin(); i != interceptors_.end(); ++i) {
- URLRequestJob* job = (*i)->MaybeIntercept(request);
+ net::URLRequestJob* job = (*i)->MaybeIntercept(request);
if (job)
return job;
}
@@ -80,7 +89,7 @@ URLRequestJob* URLRequestJobManager::CreateJob(URLRequest* request) const {
// built-in protocol factory.
FactoryMap::const_iterator i = factories_.find(scheme);
if (i != factories_.end()) {
- URLRequestJob* job = i->second(request, scheme);
+ net::URLRequestJob* job = i->second(request, scheme);
if (job)
return job;
}
@@ -88,7 +97,7 @@ URLRequestJob* URLRequestJobManager::CreateJob(URLRequest* request) const {
// See if the request should be handled by a built-in protocol factory.
for (size_t i = 0; i < arraysize(kBuiltinFactories); ++i) {
if (scheme == kBuiltinFactories[i].scheme) {
- URLRequestJob* job = (kBuiltinFactories[i].factory)(request, scheme);
+ net::URLRequestJob* job = (kBuiltinFactories[i].factory)(request, scheme);
DCHECK(job); // The built-in factories are not expected to fail!
return job;
}
@@ -98,12 +107,12 @@ URLRequestJob* URLRequestJobManager::CreateJob(URLRequest* request) const {
// wasn't interested in handling the URL. That is fairly unexpected, and we
// don't know have a specific error to report here :-(
LOG(WARNING) << "Failed to map: " << request->url().spec();
- return new URLRequestErrorJob(request, net::ERR_FAILED);
+ return new net::URLRequestErrorJob(request, net::ERR_FAILED);
}
-URLRequestJob* URLRequestJobManager::MaybeInterceptRedirect(
- URLRequest* request,
- const GURL& location) const {
+net::URLRequestJob* URLRequestJobManager::MaybeInterceptRedirect(
+ net::URLRequest* request,
+ const GURL& location) const {
#ifndef NDEBUG
DCHECK(IsAllowedThread());
#endif
@@ -115,15 +124,15 @@ URLRequestJob* URLRequestJobManager::MaybeInterceptRedirect(
InterceptorList::const_iterator i;
for (i = interceptors_.begin(); i != interceptors_.end(); ++i) {
- URLRequestJob* job = (*i)->MaybeInterceptRedirect(request, location);
+ net::URLRequestJob* job = (*i)->MaybeInterceptRedirect(request, location);
if (job)
return job;
}
return NULL;
}
-URLRequestJob* URLRequestJobManager::MaybeInterceptResponse(
- URLRequest* request) const {
+net::URLRequestJob* URLRequestJobManager::MaybeInterceptResponse(
+ net::URLRequest* request) const {
#ifndef NDEBUG
DCHECK(IsAllowedThread());
#endif
@@ -135,7 +144,7 @@ URLRequestJob* URLRequestJobManager::MaybeInterceptResponse(
InterceptorList::const_iterator i;
for (i = interceptors_.begin(); i != interceptors_.end(); ++i) {
- URLRequestJob* job = (*i)->MaybeInterceptResponse(request);
+ net::URLRequestJob* job = (*i)->MaybeInterceptResponse(request);
if (job)
return job;
}
@@ -157,16 +166,16 @@ bool URLRequestJobManager::SupportsScheme(const std::string& scheme) const {
return false;
}
-URLRequest::ProtocolFactory* URLRequestJobManager::RegisterProtocolFactory(
+net::URLRequest::ProtocolFactory* URLRequestJobManager::RegisterProtocolFactory(
const std::string& scheme,
- URLRequest::ProtocolFactory* factory) {
+ net::URLRequest::ProtocolFactory* factory) {
#ifndef NDEBUG
DCHECK(IsAllowedThread());
#endif
AutoLock locked(lock_);
- URLRequest::ProtocolFactory* old_factory;
+ net::URLRequest::ProtocolFactory* old_factory;
FactoryMap::iterator i = factories_.find(scheme);
if (i != factories_.end()) {
old_factory = i->second;
@@ -182,7 +191,7 @@ URLRequest::ProtocolFactory* URLRequestJobManager::RegisterProtocolFactory(
}
void URLRequestJobManager::RegisterRequestInterceptor(
- URLRequest::Interceptor* interceptor) {
+ net::URLRequest::Interceptor* interceptor) {
#ifndef NDEBUG
DCHECK(IsAllowedThread());
#endif
@@ -195,7 +204,7 @@ void URLRequestJobManager::RegisterRequestInterceptor(
}
void URLRequestJobManager::UnregisterRequestInterceptor(
- URLRequest::Interceptor* interceptor) {
+ net::URLRequest::Interceptor* interceptor) {
#ifndef NDEBUG
DCHECK(IsAllowedThread());
#endif
@@ -207,3 +216,5 @@ void URLRequestJobManager::UnregisterRequestInterceptor(
DCHECK(i != interceptors_.end());
interceptors_.erase(i);
}
+
+} // namespace net
diff --git a/net/url_request/url_request_job_manager.h b/net/url_request/url_request_job_manager.h
index 0fbc31e..a0d3c87 100644
--- a/net/url_request/url_request_job_manager.h
+++ b/net/url_request/url_request_job_manager.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef NET_URL_REQUEST_URL_REQUEST_JOB_MANAGER_H__
-#define NET_URL_REQUEST_URL_REQUEST_JOB_MANAGER_H__
+#ifndef NET_URL_REQUEST_URL_REQUEST_JOB_MANAGER_H_
+#define NET_URL_REQUEST_URL_REQUEST_JOB_MANAGER_H_
#pragma once
#include <map>
@@ -14,23 +14,27 @@
#include "base/platform_thread.h"
#include "net/url_request/url_request.h"
+template <typename T> struct DefaultSingletonTraits;
+
+namespace net {
+
// This class is responsible for managing the set of protocol factories and
-// request interceptors that determine how an URLRequestJob gets created to
-// handle an URLRequest.
+// request interceptors that determine how an net::URLRequestJob gets created to
+// handle an net::URLRequest.
//
// MULTI-THREADING NOTICE:
-// URLRequest is designed to have all consumers on a single thread, and so no
-// attempt is made to support ProtocolFactory or Interceptor instances being
-// registered/unregistered or in any way poked on multiple threads. However,
-// we do support checking for supported schemes FROM ANY THREAD (i.e., it is
-// safe to call SupportsScheme on any thread).
+// net::URLRequest is designed to have all consumers on a single thread, and
+// so no attempt is made to support ProtocolFactory or Interceptor instances
+// being registered/unregistered or in any way poked on multiple threads.
+// However, we do support checking for supported schemes FROM ANY THREAD
+// (i.e., it is safe to call SupportsScheme on any thread).
//
class URLRequestJobManager {
public:
- URLRequestJobManager();
- ~URLRequestJobManager();
+ // Returns the singleton instance.
+ static URLRequestJobManager* GetInstance();
- // Instantiate an URLRequestJob implementation based on the registered
+ // Instantiate an net::URLRequestJob implementation based on the registered
// interceptors and protocol factories. This will always succeed in
// returning a job unless we are--in the extreme case--out of memory.
net::URLRequestJob* CreateJob(net::URLRequest* request) const;
@@ -54,19 +58,23 @@ class URLRequestJobManager {
// Register a protocol factory associated with the given scheme. The factory
// parameter may be null to clear any existing association. Returns the
// previously registered protocol factory if any.
- URLRequest::ProtocolFactory* RegisterProtocolFactory(
- const std::string& scheme, URLRequest::ProtocolFactory* factory);
+ net::URLRequest::ProtocolFactory* RegisterProtocolFactory(
+ const std::string& scheme, net::URLRequest::ProtocolFactory* factory);
// Register/unregister a request interceptor.
- void RegisterRequestInterceptor(URLRequest::Interceptor* interceptor);
- void UnregisterRequestInterceptor(URLRequest::Interceptor* interceptor);
+ void RegisterRequestInterceptor(net::URLRequest::Interceptor* interceptor);
+ void UnregisterRequestInterceptor(net::URLRequest::Interceptor* interceptor);
void set_enable_file_access(bool enable) { enable_file_access_ = enable; }
bool enable_file_access() const { return enable_file_access_; }
private:
- typedef std::map<std::string, URLRequest::ProtocolFactory*> FactoryMap;
- typedef std::vector<URLRequest::Interceptor*> InterceptorList;
+ typedef std::map<std::string, net::URLRequest::ProtocolFactory*> FactoryMap;
+ typedef std::vector<net::URLRequest::Interceptor*> InterceptorList;
+ friend struct DefaultSingletonTraits<URLRequestJobManager>;
+
+ URLRequestJobManager();
+ ~URLRequestJobManager();
mutable Lock lock_;
FactoryMap factories_;
@@ -107,4 +115,6 @@ class URLRequestJobManager {
DISALLOW_COPY_AND_ASSIGN(URLRequestJobManager);
};
-#endif // NET_URL_REQUEST_URL_REQUEST_JOB_MANAGER_H__
+} // namespace net
+
+#endif // NET_URL_REQUEST_URL_REQUEST_JOB_MANAGER_H_
diff --git a/net/url_request/url_request_job_metrics.cc b/net/url_request/url_request_job_metrics.cc
index fcaac74..87ef205 100644
--- a/net/url_request/url_request_job_metrics.cc
+++ b/net/url_request/url_request_job_metrics.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// 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.
@@ -8,7 +8,7 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
-using base::TimeDelta;
+namespace net {
URLRequestJobMetrics::URLRequestJobMetrics()
: total_bytes_read_(0),
@@ -30,7 +30,7 @@ void URLRequestJobMetrics::AppendText(std::wstring* text) {
text->append(UTF8ToWide(url_->spec()));
}
- TimeDelta elapsed = end_time_ - start_time_;
+ base::TimeDelta elapsed = end_time_ - start_time_;
base::StringAppendF(text,
L"; total bytes read = %ld; read calls = %d; time = %lld ms;",
static_cast<long>(total_bytes_read_),
@@ -42,3 +42,5 @@ void URLRequestJobMetrics::AppendText(std::wstring* text) {
text->append(L" fail.");
}
}
+
+} // namespace net
diff --git a/net/url_request/url_request_job_metrics.h b/net/url_request/url_request_job_metrics.h
index ce0e4bf..15bbaf6 100644
--- a/net/url_request/url_request_job_metrics.h
+++ b/net/url_request/url_request_job_metrics.h
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Records IO statistics associated with a URLRequestJob.
+// Records IO statistics associated with a net::URLRequestJob.
// See description in navigation_profiler.h for an overview of perf profiling.
#ifndef NET_URL_REQUEST_URL_REQUEST_JOB_METRICS_H_
@@ -16,6 +16,8 @@
#include "base/time.h"
#include "googleurl/src/gurl.h"
+namespace net {
+
class URLRequestJobMetrics {
public:
URLRequestJobMetrics();
@@ -47,4 +49,6 @@ class URLRequestJobMetrics {
void AppendText(std::wstring* text);
};
+} // namespace net
+
#endif // NET_URL_REQUEST_URL_REQUEST_JOB_METRICS_H_
diff --git a/net/url_request/url_request_job_tracker.cc b/net/url_request/url_request_job_tracker.cc
index e3e5d36..49472d9 100644
--- a/net/url_request/url_request_job_tracker.cc
+++ b/net/url_request/url_request_job_tracker.cc
@@ -2,13 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <algorithm>
-
#include "net/url_request/url_request_job_tracker.h"
+#include <algorithm>
+
#include "base/logging.h"
#include "net/url_request/url_request_job.h"
+namespace net {
+
URLRequestJobTracker g_url_request_job_tracker;
URLRequestJobTracker::URLRequestJobTracker() {
@@ -16,9 +18,9 @@ URLRequestJobTracker::URLRequestJobTracker() {
URLRequestJobTracker::~URLRequestJobTracker() {
DLOG_IF(WARNING, active_jobs_.size() != 0) <<
- "Leaking " << active_jobs_.size() << " URLRequestJob object(s), this could "
- "be because the URLRequest forgot to free it (bad), or if the program was "
- "terminated while a request was active (normal).";
+ "Leaking " << active_jobs_.size() << " URLRequestJob object(s), this "
+ "could be because the URLRequest forgot to free it (bad), or if the "
+ "program was terminated while a request was active (normal).";
}
void URLRequestJobTracker::AddNewJob(URLRequestJob* job) {
@@ -56,3 +58,5 @@ void URLRequestJobTracker::OnBytesRead(URLRequestJob* job,
FOR_EACH_OBSERVER(JobObserver, observers_,
OnBytesRead(job, buf, byte_count));
}
+
+} // namespace net
diff --git a/net/url_request/url_request_job_tracker.h b/net/url_request/url_request_job_tracker.h
index cd0bd86..4c8ecec 100644
--- a/net/url_request/url_request_job_tracker.h
+++ b/net/url_request/url_request_job_tracker.h
@@ -11,40 +11,40 @@
#include "base/observer_list.h"
#include "net/url_request/url_request_status.h"
+class GURL;
+
namespace net {
class URLRequestJob;
-} // namespace net
-
-class GURL;
// This class maintains a list of active URLRequestJobs for debugging purposes.
// This allows us to warn on leaked jobs and also allows an observer to track
// what is happening, for example, for the network status monitor.
//
-// NOTE: URLRequest is single-threaded, so this class should only be used on
-// the same thread where all of the application's URLRequest calls are made.
+// NOTE: URLRequest is single-threaded, so this class should only be used
+// onthe same thread where all of the application's URLRequest calls are
+// made.
//
class URLRequestJobTracker {
public:
- typedef std::vector<net::URLRequestJob*> JobList;
+ typedef std::vector<URLRequestJob*> JobList;
typedef JobList::const_iterator JobIterator;
// The observer's methods are called on the thread that called AddObserver.
class JobObserver {
public:
// Called after the given job has been added to the list
- virtual void OnJobAdded(net::URLRequestJob* job) = 0;
+ virtual void OnJobAdded(URLRequestJob* job) = 0;
// Called after the given job has been removed from the list
- virtual void OnJobRemoved(net::URLRequestJob* job) = 0;
+ virtual void OnJobRemoved(URLRequestJob* job) = 0;
// Called when the given job has completed, before notifying the request
- virtual void OnJobDone(net::URLRequestJob* job,
+ virtual void OnJobDone(URLRequestJob* job,
const URLRequestStatus& status) = 0;
// Called when the given job is about to follow a redirect to the given
// new URL. The redirect type is given in status_code
- virtual void OnJobRedirect(net::URLRequestJob* job, const GURL& location,
+ virtual void OnJobRedirect(URLRequestJob* job, const GURL& location,
int status_code) = 0;
// Called when a new chunk of unfiltered bytes has been read for
@@ -52,7 +52,7 @@ class URLRequestJobTracker {
// read event only. |buf| is a pointer to the data buffer that
// contains those bytes. The data in |buf| is only valid for the
// duration of the OnBytesRead callback.
- virtual void OnBytesRead(net::URLRequestJob* job, const char* buf,
+ virtual void OnBytesRead(URLRequestJob* job, const char* buf,
int byte_count) = 0;
virtual ~JobObserver() {}
@@ -73,16 +73,16 @@ class URLRequestJobTracker {
// adds or removes the job from the active list, should be called by the
// job constructor and destructor. Note: don't use "AddJob" since that
// is #defined by windows.h :(
- void AddNewJob(net::URLRequestJob* job);
- void RemoveJob(net::URLRequestJob* job);
+ void AddNewJob(URLRequestJob* job);
+ void RemoveJob(URLRequestJob* job);
// Job status change notifications
- void OnJobDone(net::URLRequestJob* job, const URLRequestStatus& status);
- void OnJobRedirect(net::URLRequestJob* job, const GURL& location,
+ void OnJobDone(URLRequestJob* job, const URLRequestStatus& status);
+ void OnJobRedirect(URLRequestJob* job, const GURL& location,
int status_code);
// Bytes read notifications.
- void OnBytesRead(net::URLRequestJob* job, const char* buf, int byte_count);
+ void OnBytesRead(URLRequestJob* job, const char* buf, int byte_count);
// allows iteration over all active jobs
JobIterator begin() const {
@@ -99,4 +99,6 @@ class URLRequestJobTracker {
extern URLRequestJobTracker g_url_request_job_tracker;
+} // namespace net
+
#endif // NET_URL_REQUEST_URL_REQUEST_JOB_TRACKER_H_
diff --git a/net/url_request/url_request_job_tracker_unittest.cc b/net/url_request/url_request_job_tracker_unittest.cc
index 3ddbcc2..bd62ef7 100644
--- a/net/url_request/url_request_job_tracker_unittest.cc
+++ b/net/url_request/url_request_job_tracker_unittest.cc
@@ -49,29 +49,29 @@ bool GetResponseBody(const GURL& url, std::string* out_body) {
return true;
}
-class MockJobObserver : public URLRequestJobTracker::JobObserver {
+class MockJobObserver : public net::URLRequestJobTracker::JobObserver {
public:
- MOCK_METHOD1(OnJobAdded, void(URLRequestJob* job));
- MOCK_METHOD1(OnJobRemoved, void(URLRequestJob* job));
- MOCK_METHOD2(OnJobDone, void(URLRequestJob* job,
+ MOCK_METHOD1(OnJobAdded, void(net::URLRequestJob* job));
+ MOCK_METHOD1(OnJobRemoved, void(net::URLRequestJob* job));
+ MOCK_METHOD2(OnJobDone, void(net::URLRequestJob* job,
const URLRequestStatus& status));
- MOCK_METHOD3(OnJobRedirect, void(URLRequestJob* job,
+ MOCK_METHOD3(OnJobRedirect, void(net::URLRequestJob* job,
const GURL& location,
int status_code));
- MOCK_METHOD3(OnBytesRead, void(URLRequestJob* job,
+ MOCK_METHOD3(OnBytesRead, void(net::URLRequestJob* job,
const char* buf,
int byte_count));
};
-// A URLRequestJob that returns static content for given URLs. We do
+// A net::URLRequestJob that returns static content for given URLs. We do
// not use URLRequestTestJob here because URLRequestTestJob fakes
// async operations by calling ReadRawData synchronously in an async
-// callback. This test requires a URLRequestJob that returns false for
+// callback. This test requires a net::URLRequestJob that returns false for
// async reads, in order to exercise the real async read codepath.
-class URLRequestJobTrackerTestJob : public URLRequestJob {
+class URLRequestJobTrackerTestJob : public net::URLRequestJob {
public:
- URLRequestJobTrackerTestJob(URLRequest* request, bool async_reads)
- : URLRequestJob(request), async_reads_(async_reads) {}
+ URLRequestJobTrackerTestJob(net::URLRequest* request, bool async_reads)
+ : net::URLRequestJob(request), async_reads_(async_reads) {}
void Start() {
ASSERT_TRUE(GetResponseBody(request_->url(), &response_data_));
@@ -125,7 +125,7 @@ class URLRequestJobTrackerTestJob : public URLRequestJob {
encoding_types->push_back(Filter::FILTER_TYPE_GZIP);
return true;
} else {
- return URLRequestJob::GetContentEncodings(encoding_types);
+ return net::URLRequestJob::GetContentEncodings(encoding_types);
}
}
@@ -151,7 +151,7 @@ MATCHER_P2(MemEq, other, len, "") {
class URLRequestJobTrackerTest : public PlatformTest {
protected:
static void SetUpTestCase() {
- URLRequest::RegisterProtocolFactory("test", &Factory);
+ net::URLRequest::RegisterProtocolFactory("test", &Factory);
}
virtual void SetUp() {
@@ -176,15 +176,15 @@ class URLRequestJobTrackerTest : public PlatformTest {
EXPECT_CALL(observer, OnJobRemoved(NotNull()));
// Attach our observer and perform the resource fetch.
- g_url_request_job_tracker.AddObserver(&observer);
+ net::g_url_request_job_tracker.AddObserver(&observer);
Fetch(gurl);
- g_url_request_job_tracker.RemoveObserver(&observer);
+ net::g_url_request_job_tracker.RemoveObserver(&observer);
}
void Fetch(const GURL& url) {
TestDelegate d;
{
- URLRequest request(url, &d);
+ net::URLRequest request(url, &d);
request.Start();
MessageLoop::current()->RunAllPending();
}
@@ -196,13 +196,14 @@ class URLRequestJobTrackerTest : public PlatformTest {
EXPECT_STREQ(kBasic, d.data_received().c_str());
}
- static URLRequest::ProtocolFactory Factory;
+ static net::URLRequest::ProtocolFactory Factory;
static bool g_async_reads;
};
// static
-URLRequestJob* URLRequestJobTrackerTest::Factory(URLRequest* request,
- const std::string& scheme) {
+net::URLRequestJob* URLRequestJobTrackerTest::Factory(
+ net::URLRequest* request,
+ const std::string& scheme) {
return new URLRequestJobTrackerTestJob(request, g_async_reads);
}
diff --git a/net/url_request/url_request_netlog_params.cc b/net/url_request/url_request_netlog_params.cc
index 56414b1..42076bc 100644
--- a/net/url_request/url_request_netlog_params.cc
+++ b/net/url_request/url_request_netlog_params.cc
@@ -6,11 +6,13 @@
#include "base/values.h"
+namespace net {
+
URLRequestStartEventParameters::URLRequestStartEventParameters(
const GURL& url,
const std::string& method,
int load_flags,
- net::RequestPriority priority)
+ RequestPriority priority)
: url_(url),
method_(method),
load_flags_(load_flags),
@@ -25,3 +27,5 @@ Value* URLRequestStartEventParameters::ToValue() const {
dict->SetInteger("priority", static_cast<int>(priority_));
return dict;
}
+
+} // namespace net
diff --git a/net/url_request/url_request_netlog_params.h b/net/url_request/url_request_netlog_params.h
index 12bd1f1..8b275b9 100644
--- a/net/url_request/url_request_netlog_params.h
+++ b/net/url_request/url_request_netlog_params.h
@@ -13,13 +13,15 @@
#include "net/base/net_log.h"
#include "net/base/request_priority.h"
+namespace net {
+
// Holds the parameters to emit to the NetLog when starting a URLRequest.
-class URLRequestStartEventParameters : public net::NetLog::EventParameters {
+class URLRequestStartEventParameters : public NetLog::EventParameters {
public:
URLRequestStartEventParameters(const GURL& url,
const std::string& method,
int load_flags,
- net::RequestPriority priority);
+ RequestPriority priority);
const GURL& url() const {
return url_;
@@ -35,9 +37,11 @@ class URLRequestStartEventParameters : public net::NetLog::EventParameters {
const GURL url_;
const std::string method_;
const int load_flags_;
- const net::RequestPriority priority_;
+ const RequestPriority priority_;
DISALLOW_COPY_AND_ASSIGN(URLRequestStartEventParameters);
};
+} // namespace net
+
#endif // NET_URL_REQUEST_URL_REQUEST_NETLOG_PARAMS_H_
diff --git a/net/url_request/url_request_redirect_job.cc b/net/url_request/url_request_redirect_job.cc
index 001da10..9c5605a 100644
--- a/net/url_request/url_request_redirect_job.cc
+++ b/net/url_request/url_request_redirect_job.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// 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.
@@ -6,7 +6,9 @@
#include "base/message_loop.h"
-URLRequestRedirectJob::URLRequestRedirectJob(net::URLRequest* request,
+namespace net {
+
+URLRequestRedirectJob::URLRequestRedirectJob(URLRequest* request,
GURL redirect_destination)
: URLRequestJob(request), redirect_destination_(redirect_destination) {
}
@@ -16,10 +18,6 @@ void URLRequestRedirectJob::Start() {
this, &URLRequestRedirectJob::StartAsync));
}
-void URLRequestRedirectJob::StartAsync() {
- NotifyHeadersComplete();
-}
-
bool URLRequestRedirectJob::IsRedirectResponse(GURL* location,
int* http_status_code) {
*location = redirect_destination_;
@@ -27,3 +25,10 @@ bool URLRequestRedirectJob::IsRedirectResponse(GURL* location,
return true;
}
+URLRequestRedirectJob::~URLRequestRedirectJob() {}
+
+void URLRequestRedirectJob::StartAsync() {
+ NotifyHeadersComplete();
+}
+
+} // namespace net
diff --git a/net/url_request/url_request_redirect_job.h b/net/url_request/url_request_redirect_job.h
index 7466cec..425c70b 100644
--- a/net/url_request/url_request_redirect_job.h
+++ b/net/url_request/url_request_redirect_job.h
@@ -10,23 +10,27 @@
class GURL;
+namespace net {
+
// A URLRequestJob that will redirect the request to the specified
// URL. This is useful to restart a request at a different URL based
// on the result of another job.
class URLRequestRedirectJob : public URLRequestJob {
public:
// Constructs a job that redirects to the specified URL.
- URLRequestRedirectJob(net::URLRequest* request, GURL redirect_destination);
+ URLRequestRedirectJob(URLRequest* request, GURL redirect_destination);
virtual void Start();
- bool IsRedirectResponse(GURL* location, int* http_status_code);
+ virtual bool IsRedirectResponse(GURL* location, int* http_status_code);
private:
- ~URLRequestRedirectJob() {}
+ virtual ~URLRequestRedirectJob();
void StartAsync();
GURL redirect_destination_;
};
+} // namespace net
+
#endif // NET_URL_REQUEST_URL_REQUEST_REDIRECT_JOB_H_
diff --git a/net/url_request/url_request_simple_job.cc b/net/url_request/url_request_simple_job.cc
index 38e0c4d..0b95d38 100644
--- a/net/url_request/url_request_simple_job.cc
+++ b/net/url_request/url_request_simple_job.cc
@@ -9,7 +9,9 @@
#include "net/base/net_errors.h"
#include "net/url_request/url_request_status.h"
-URLRequestSimpleJob::URLRequestSimpleJob(net::URLRequest* request)
+namespace net {
+
+URLRequestSimpleJob::URLRequestSimpleJob(URLRequest* request)
: URLRequestJob(request),
data_offset_(0) {
}
@@ -31,7 +33,7 @@ bool URLRequestSimpleJob::GetCharset(std::string* charset) {
return true;
}
-bool URLRequestSimpleJob::ReadRawData(net::IOBuffer* buf, int buf_size,
+bool URLRequestSimpleJob::ReadRawData(IOBuffer* buf, int buf_size,
int* bytes_read) {
DCHECK(bytes_read);
int remaining = static_cast<int>(data_.size()) - data_offset_;
@@ -53,6 +55,8 @@ void URLRequestSimpleJob::StartAsync() {
} else {
// what should the error code be?
NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED,
- net::ERR_INVALID_URL));
+ ERR_INVALID_URL));
}
}
+
+} // namespace net
diff --git a/net/url_request/url_request_simple_job.h b/net/url_request/url_request_simple_job.h
index 877b081..7b48adb 100644
--- a/net/url_request/url_request_simple_job.h
+++ b/net/url_request/url_request_simple_job.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// 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.
@@ -11,15 +11,15 @@
#include "net/url_request/url_request_job.h"
namespace net {
+
class URLRequest;
-} // namespace net
-class URLRequestSimpleJob : public net::URLRequestJob {
+class URLRequestSimpleJob : public URLRequestJob {
public:
- explicit URLRequestSimpleJob(net::URLRequest* request);
+ explicit URLRequestSimpleJob(URLRequest* request);
virtual void Start();
- virtual bool ReadRawData(net::IOBuffer* buf, int buf_size, int *bytes_read);
+ virtual bool ReadRawData(IOBuffer* buf, int buf_size, int *bytes_read);
virtual bool GetMimeType(std::string* mime_type) const;
virtual bool GetCharset(std::string* charset);
@@ -41,4 +41,6 @@ class URLRequestSimpleJob : public net::URLRequestJob {
int data_offset_;
};
+} // namespace net
+
#endif // NET_URL_REQUEST_URL_REQUEST_SIMPLE_JOB_H_
diff --git a/net/url_request/url_request_test_job.cc b/net/url_request/url_request_test_job.cc
index 363d178..7fd019c 100644
--- a/net/url_request/url_request_test_job.cc
+++ b/net/url_request/url_request_test_job.cc
@@ -70,13 +70,13 @@ std::string URLRequestTestJob::test_error_headers() {
}
// static
-URLRequestJob* URLRequestTestJob::Factory(URLRequest* request,
- const std::string& scheme) {
+net::URLRequestJob* URLRequestTestJob::Factory(net::URLRequest* request,
+ const std::string& scheme) {
return new URLRequestTestJob(request);
}
-URLRequestTestJob::URLRequestTestJob(URLRequest* request)
- : URLRequestJob(request),
+URLRequestTestJob::URLRequestTestJob(net::URLRequest* request)
+ : net::URLRequestJob(request),
auto_advance_(false),
stage_(WAITING),
offset_(0),
@@ -84,8 +84,9 @@ URLRequestTestJob::URLRequestTestJob(URLRequest* request)
async_buf_size_(0) {
}
-URLRequestTestJob::URLRequestTestJob(URLRequest* request, bool auto_advance)
- : URLRequestJob(request),
+URLRequestTestJob::URLRequestTestJob(net::URLRequest* request,
+ bool auto_advance)
+ : net::URLRequestJob(request),
auto_advance_(auto_advance),
stage_(WAITING),
offset_(0),
@@ -93,11 +94,11 @@ URLRequestTestJob::URLRequestTestJob(URLRequest* request, bool auto_advance)
async_buf_size_(0) {
}
-URLRequestTestJob::URLRequestTestJob(URLRequest* request,
+URLRequestTestJob::URLRequestTestJob(net::URLRequest* request,
const std::string& response_headers,
const std::string& response_data,
bool auto_advance)
- : URLRequestJob(request),
+ : net::URLRequestJob(request),
auto_advance_(auto_advance),
stage_(WAITING),
response_headers_(new net::HttpResponseHeaders(response_headers)),
@@ -206,7 +207,7 @@ bool URLRequestTestJob::IsRedirectResponse(GURL* location,
void URLRequestTestJob::Kill() {
stage_ = DONE;
- URLRequestJob::Kill();
+ net::URLRequestJob::Kill();
}
void URLRequestTestJob::ProcessNextOperation() {
diff --git a/net/url_request/url_request_test_job.h b/net/url_request/url_request_test_job.h
index 14b90d4..ec92dc2 100644
--- a/net/url_request/url_request_test_job.h
+++ b/net/url_request/url_request_test_job.h
@@ -37,16 +37,16 @@ class URLRequestTestJob : public net::URLRequestJob {
public:
// Constructs a job to return one of the canned responses depending on the
// request url, with auto advance disabled.
- explicit URLRequestTestJob(URLRequest* request);
+ explicit URLRequestTestJob(net::URLRequest* request);
// Constructs a job to return one of the canned responses depending on the
// request url, optionally with auto advance enabled.
- explicit URLRequestTestJob(URLRequest* request, bool auto_advance);
+ explicit URLRequestTestJob(net::URLRequest* request, bool auto_advance);
// Constructs a job to return the given response regardless of the request
// url. The headers should include the HTTP status line and be formatted as
// expected by net::HttpResponseHeaders.
- explicit URLRequestTestJob(URLRequest* request,
+ explicit URLRequestTestJob(net::URLRequest* request,
const std::string& response_headers,
const std::string& response_data,
bool auto_advance);
@@ -86,7 +86,7 @@ class URLRequestTestJob : public net::URLRequestJob {
void set_auto_advance(bool auto_advance) { auto_advance_ = auto_advance; }
// Factory method for protocol factory registration if callers don't subclass
- static URLRequest::ProtocolFactory Factory;
+ static net::URLRequest::ProtocolFactory Factory;
// Job functions
virtual void Start();
diff --git a/net/url_request/url_request_throttler_entry.h b/net/url_request/url_request_throttler_entry.h
index 9b8955d..ac33fa1 100644
--- a/net/url_request/url_request_throttler_entry.h
+++ b/net/url_request/url_request_throttler_entry.h
@@ -18,8 +18,8 @@ namespace net {
// deduce the back-off time for every request.
// The back-off algorithm consists of two parts. Firstly, exponential back-off
// is used when receiving 5XX server errors or malformed response bodies.
-// The exponential back-off rule is enforced by URLRequestHttpJob. Any request
-// sent during the back-off period will be cancelled.
+// The exponential back-off rule is enforced by URLRequestHttpJob. Any
+// request sent during the back-off period will be cancelled.
// Secondly, a sliding window is used to count recent requests to a given
// destination and provide guidance (to the application level only) on whether
// too many requests have been sent and when a good time to send the next one
diff --git a/net/url_request/url_request_throttler_entry_interface.h b/net/url_request/url_request_throttler_entry_interface.h
index f443b29..ed3c17f 100644
--- a/net/url_request/url_request_throttler_entry_interface.h
+++ b/net/url_request/url_request_throttler_entry_interface.h
@@ -21,8 +21,8 @@ class URLRequestThrottlerEntryInterface
// Returns true when we have encountered server errors and are doing
// exponential back-off.
- // URLRequestHttpJob checks this method prior to every request; it cancels
- // requests if this method returns true.
+ // net::URLRequestHttpJob checks this method prior to every request; it
+ // cancels requests if this method returns true.
virtual bool IsDuringExponentialBackoff() const = 0;
// Calculates a recommended sending time for the next request and reserves it.
diff --git a/net/url_request/url_request_throttler_header_adapter.cc b/net/url_request/url_request_throttler_header_adapter.cc
index e453071..368d6fe 100644
--- a/net/url_request/url_request_throttler_header_adapter.cc
+++ b/net/url_request/url_request_throttler_header_adapter.cc
@@ -13,6 +13,8 @@ URLRequestThrottlerHeaderAdapter::URLRequestThrottlerHeaderAdapter(
: response_header_(headers) {
}
+URLRequestThrottlerHeaderAdapter::~URLRequestThrottlerHeaderAdapter() {}
+
std::string URLRequestThrottlerHeaderAdapter::GetNormalizedValue(
const std::string& key) const {
std::string return_value;
diff --git a/net/url_request/url_request_throttler_header_adapter.h b/net/url_request/url_request_throttler_header_adapter.h
index 599a9f6..35d363e 100644
--- a/net/url_request/url_request_throttler_header_adapter.h
+++ b/net/url_request/url_request_throttler_header_adapter.h
@@ -19,7 +19,7 @@ class URLRequestThrottlerHeaderAdapter
: public URLRequestThrottlerHeaderInterface {
public:
explicit URLRequestThrottlerHeaderAdapter(net::HttpResponseHeaders* headers);
- virtual ~URLRequestThrottlerHeaderAdapter() {}
+ virtual ~URLRequestThrottlerHeaderAdapter();
// Implementation of URLRequestThrottlerHeaderInterface
virtual std::string GetNormalizedValue(const std::string& key) const;
diff --git a/net/url_request/url_request_throttler_manager.cc b/net/url_request/url_request_throttler_manager.cc
index 5428d9a..04e05c9 100644
--- a/net/url_request/url_request_throttler_manager.cc
+++ b/net/url_request/url_request_throttler_manager.cc
@@ -32,7 +32,8 @@ scoped_refptr<URLRequestThrottlerEntryInterface>
}
URLRequestThrottlerManager::URLRequestThrottlerManager()
- : requests_since_last_gc_(0) {
+ : requests_since_last_gc_(0),
+ enforce_throttling_(true) {
}
URLRequestThrottlerManager::~URLRequestThrottlerManager() {
diff --git a/net/url_request/url_request_throttler_manager.h b/net/url_request/url_request_throttler_manager.h
index 6c8cd2f..98211d9 100644
--- a/net/url_request/url_request_throttler_manager.h
+++ b/net/url_request/url_request_throttler_manager.h
@@ -49,6 +49,12 @@ class URLRequestThrottlerManager {
// It is only used by unit tests.
void EraseEntryForTests(const GURL& url);
+ void set_enforce_throttling(bool enforce_throttling) {
+ enforce_throttling_ = enforce_throttling;
+ }
+
+ bool enforce_throttling() const { return enforce_throttling_; }
+
protected:
URLRequestThrottlerManager();
~URLRequestThrottlerManager();
@@ -93,6 +99,10 @@ class URLRequestThrottlerManager {
mutable scoped_ptr<GURL::Replacements> url_id_replacements_;
+ // Whether we would like to reject outgoing HTTP requests during the back-off
+ // period.
+ bool enforce_throttling_;
+
DISALLOW_COPY_AND_ASSIGN(URLRequestThrottlerManager);
};
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 2c44a1c..4be2ec5 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -119,7 +119,7 @@ void CheckSSLInfo(const net::SSLInfo& ssl_info) {
class URLRequestTest : public PlatformTest {
public:
static void SetUpTestCase() {
- URLRequest::AllowFileAccess();
+ net::URLRequest::AllowFileAccess();
}
};
@@ -154,7 +154,7 @@ class URLRequestTestHTTP : public URLRequestTest {
for (int i = 0; i < kIterations; ++i) {
TestDelegate d;
- URLRequest r(test_server_.GetURL("echo"), &d);
+ net::URLRequest r(test_server_.GetURL("echo"), &d);
r.set_context(context);
r.set_method(method.c_str());
@@ -188,7 +188,7 @@ TEST_F(URLRequestTestHTTP, ProxyTunnelRedirectTest) {
TestDelegate d;
{
- URLRequest r(GURL("https://www.redirect.com/"), &d);
+ net::URLRequest r(GURL("https://www.redirect.com/"), &d);
r.set_context(
new TestURLRequestContext(test_server_.host_port_pair().ToString()));
@@ -213,7 +213,7 @@ TEST_F(URLRequestTestHTTP, UnexpectedServerAuthTest) {
TestDelegate d;
{
- URLRequest r(GURL("https://www.server-auth.com/"), &d);
+ net::URLRequest r(GURL("https://www.server-auth.com/"), &d);
r.set_context(
new TestURLRequestContext(test_server_.host_port_pair().ToString()));
@@ -386,7 +386,7 @@ class SSLClientAuthTestDelegate : public TestDelegate {
SSLClientAuthTestDelegate() : on_certificate_requested_count_(0) {
}
virtual void OnCertificateRequested(
- URLRequest* request,
+ net::URLRequest* request,
net::SSLCertRequestInfo* cert_request_info) {
on_certificate_requested_count_++;
MessageLoop::current()->Quit();
@@ -536,7 +536,7 @@ TEST_F(URLRequestTestHTTP, CancelTest5) {
// populate cache
{
TestDelegate d;
- URLRequest r(test_server_.GetURL("cachetime"), &d);
+ net::URLRequest r(test_server_.GetURL("cachetime"), &d);
r.set_context(context);
r.Start();
MessageLoop::current()->Run();
@@ -546,7 +546,7 @@ TEST_F(URLRequestTestHTTP, CancelTest5) {
// cancel read from cache (see bug 990242)
{
TestDelegate d;
- URLRequest r(test_server_.GetURL("cachetime"), &d);
+ net::URLRequest r(test_server_.GetURL("cachetime"), &d);
r.set_context(context);
r.Start();
r.Cancel();
@@ -1143,7 +1143,7 @@ TEST_F(URLRequestTestHTTP, VaryHeader) {
// populate the cache
{
TestDelegate d;
- URLRequest req(test_server_.GetURL("echoheader?foo"), &d);
+ net::URLRequest req(test_server_.GetURL("echoheader?foo"), &d);
req.set_context(context);
net::HttpRequestHeaders headers;
headers.SetHeader("foo", "1");
@@ -1155,7 +1155,7 @@ TEST_F(URLRequestTestHTTP, VaryHeader) {
// expect a cache hit
{
TestDelegate d;
- URLRequest req(test_server_.GetURL("echoheader?foo"), &d);
+ net::URLRequest req(test_server_.GetURL("echoheader?foo"), &d);
req.set_context(context);
net::HttpRequestHeaders headers;
headers.SetHeader("foo", "1");
@@ -1169,7 +1169,7 @@ TEST_F(URLRequestTestHTTP, VaryHeader) {
// expect a cache miss
{
TestDelegate d;
- URLRequest req(test_server_.GetURL("echoheader?foo"), &d);
+ net::URLRequest req(test_server_.GetURL("echoheader?foo"), &d);
req.set_context(context);
net::HttpRequestHeaders headers;
headers.SetHeader("foo", "2");
@@ -1192,7 +1192,7 @@ TEST_F(URLRequestTestHTTP, BasicAuth) {
d.set_username(kUser);
d.set_password(kSecret);
- URLRequest r(test_server_.GetURL("auth-basic"), &d);
+ net::URLRequest r(test_server_.GetURL("auth-basic"), &d);
r.set_context(context);
r.Start();
@@ -1209,7 +1209,7 @@ TEST_F(URLRequestTestHTTP, BasicAuth) {
d.set_username(kUser);
d.set_password(kSecret);
- URLRequest r(test_server_.GetURL("auth-basic"), &d);
+ net::URLRequest r(test_server_.GetURL("auth-basic"), &d);
r.set_context(context);
r.set_load_flags(net::LOAD_VALIDATE_CACHE);
r.Start();
@@ -1239,7 +1239,7 @@ TEST_F(URLRequestTestHTTP, BasicAuthWithCookies) {
d.set_username(kUser);
d.set_password(kSecret);
- URLRequest r(url_requiring_auth, &d);
+ net::URLRequest r(url_requiring_auth, &d);
r.set_context(context);
r.Start();
@@ -1265,7 +1265,7 @@ TEST_F(URLRequestTestHTTP, BasicAuthWithCookies) {
replacements.SetPasswordStr(password);
GURL url_with_identity = url_requiring_auth.ReplaceComponents(replacements);
- URLRequest r(url_with_identity, &d);
+ net::URLRequest r(url_with_identity, &d);
r.set_context(context);
r.Start();
@@ -1288,7 +1288,7 @@ TEST_F(URLRequestTest, DoNotSendCookies) {
// Set up a cookie.
{
TestDelegate d;
- URLRequest req(test_server.GetURL("set-cookie?CookieToNotSend=1"), &d);
+ net::URLRequest req(test_server.GetURL("set-cookie?CookieToNotSend=1"), &d);
req.set_context(context);
req.Start();
MessageLoop::current()->Run();
@@ -1337,8 +1337,8 @@ TEST_F(URLRequestTest, DoNotSaveCookies) {
// Set up a cookie.
{
TestDelegate d;
- URLRequest req(test_server.GetURL("set-cookie?CookieToNotUpdate=2"),
- &d);
+ net::URLRequest req(test_server.GetURL("set-cookie?CookieToNotUpdate=2"),
+ &d);
req.set_context(context);
req.Start();
MessageLoop::current()->Run();
@@ -1351,7 +1351,7 @@ TEST_F(URLRequestTest, DoNotSaveCookies) {
// Try to set-up another cookie and update the previous cookie.
{
TestDelegate d;
- URLRequest req(test_server.GetURL(
+ net::URLRequest req(test_server.GetURL(
"set-cookie?CookieToNotSave=1&CookieToNotUpdate=1"), &d);
req.set_load_flags(net::LOAD_DO_NOT_SAVE_COOKIES);
req.set_context(context);
@@ -1393,7 +1393,7 @@ TEST_F(URLRequestTest, DoNotSendCookies_ViaPolicy) {
// Set up a cookie.
{
TestDelegate d;
- URLRequest req(test_server.GetURL("set-cookie?CookieToNotSend=1"), &d);
+ net::URLRequest req(test_server.GetURL("set-cookie?CookieToNotSend=1"), &d);
req.set_context(context);
req.Start();
MessageLoop::current()->Run();
@@ -1447,8 +1447,8 @@ TEST_F(URLRequestTest, DoNotSaveCookies_ViaPolicy) {
// Set up a cookie.
{
TestDelegate d;
- URLRequest req(test_server.GetURL("set-cookie?CookieToNotUpdate=2"),
- &d);
+ net::URLRequest req(test_server.GetURL("set-cookie?CookieToNotUpdate=2"),
+ &d);
req.set_context(context);
req.Start();
MessageLoop::current()->Run();
@@ -1463,7 +1463,7 @@ TEST_F(URLRequestTest, DoNotSaveCookies_ViaPolicy) {
context->set_cookie_policy(&cookie_policy);
TestDelegate d;
- URLRequest req(test_server.GetURL(
+ net::URLRequest req(test_server.GetURL(
"set-cookie?CookieToNotSave=1&CookieToNotUpdate=1"), &d);
req.set_context(context);
req.Start();
@@ -1504,7 +1504,7 @@ TEST_F(URLRequestTest, DoNotSaveEmptyCookies) {
// Set up an empty cookie.
{
TestDelegate d;
- URLRequest req(test_server.GetURL("set-cookie"), &d);
+ net::URLRequest req(test_server.GetURL("set-cookie"), &d);
req.set_context(context);
req.Start();
MessageLoop::current()->Run();
@@ -1524,7 +1524,7 @@ TEST_F(URLRequestTest, DoNotSendCookies_ViaPolicy_Async) {
// Set up a cookie.
{
TestDelegate d;
- URLRequest req(test_server.GetURL("set-cookie?CookieToNotSend=1"), &d);
+ net::URLRequest req(test_server.GetURL("set-cookie?CookieToNotSend=1"), &d);
req.set_context(context);
req.Start();
MessageLoop::current()->Run();
@@ -1579,8 +1579,8 @@ TEST_F(URLRequestTest, DoNotSaveCookies_ViaPolicy_Async) {
// Set up a cookie.
{
TestDelegate d;
- URLRequest req(test_server.GetURL("set-cookie?CookieToNotUpdate=2"),
- &d);
+ net::URLRequest req(test_server.GetURL("set-cookie?CookieToNotUpdate=2"),
+ &d);
req.set_context(context);
req.Start();
MessageLoop::current()->Run();
@@ -1596,7 +1596,7 @@ TEST_F(URLRequestTest, DoNotSaveCookies_ViaPolicy_Async) {
context->set_cookie_policy(&cookie_policy);
TestDelegate d;
- URLRequest req(test_server.GetURL(
+ net::URLRequest req(test_server.GetURL(
"set-cookie?CookieToNotSave=1&CookieToNotUpdate=1"), &d);
req.set_context(context);
req.Start();
@@ -1639,8 +1639,8 @@ TEST_F(URLRequestTest, CancelTest_During_CookiePolicy) {
// Set up a cookie.
{
TestDelegate d;
- URLRequest req(test_server.GetURL("set-cookie?A=1&B=2&C=3"),
- &d);
+ net::URLRequest req(test_server.GetURL("set-cookie?A=1&B=2&C=3"),
+ &d);
req.set_context(context);
req.Start(); // Triggers an asynchronous cookie policy check.
@@ -1654,7 +1654,7 @@ TEST_F(URLRequestTest, CancelTest_During_CookiePolicy) {
context->set_cookie_policy(NULL);
// Let the cookie policy complete. Make sure it handles the destruction of
- // the URLRequest properly.
+ // the net::URLRequest properly.
MessageLoop::current()->RunAllPending();
}
@@ -1671,8 +1671,8 @@ TEST_F(URLRequestTest, CancelTest_During_OnGetCookies) {
{
TestDelegate d;
d.set_cancel_in_get_cookies_blocked(true);
- URLRequest req(test_server.GetURL("set-cookie?A=1&B=2&C=3"),
- &d);
+ net::URLRequest req(test_server.GetURL("set-cookie?A=1&B=2&C=3"),
+ &d);
req.set_context(context);
req.Start(); // Triggers an asynchronous cookie policy check.
@@ -1700,8 +1700,8 @@ TEST_F(URLRequestTest, CancelTest_During_OnSetCookie) {
{
TestDelegate d;
d.set_cancel_in_set_cookie_blocked(true);
- URLRequest req(test_server.GetURL("set-cookie?A=1&B=2&C=3"),
- &d);
+ net::URLRequest req(test_server.GetURL("set-cookie?A=1&B=2&C=3"),
+ &d);
req.set_context(context);
req.Start(); // Triggers an asynchronous cookie policy check.
@@ -1733,7 +1733,7 @@ TEST_F(URLRequestTest, CookiePolicy_ForceSession) {
// Set up a cookie.
{
TestDelegate d;
- URLRequest req(test_server.GetURL(
+ net::URLRequest req(test_server.GetURL(
"set-cookie?A=1;expires=\"Fri, 05 Feb 2010 23:42:01 GMT\""), &d);
req.set_context(context);
req.Start(); // Triggers an asynchronous cookie policy check.
@@ -1745,7 +1745,7 @@ TEST_F(URLRequestTest, CookiePolicy_ForceSession) {
}
// Now, check the cookie store.
- net::CookieMonster::CookieList cookies =
+ net::CookieList cookies =
context->cookie_store()->GetCookieMonster()->GetAllCookies();
EXPECT_EQ(1U, cookies.size());
EXPECT_FALSE(cookies[0].IsPersistent());
@@ -1822,7 +1822,7 @@ TEST_F(URLRequestTestHTTP, Post307RedirectPost) {
// Custom URLRequestJobs for use with interceptor tests
class RestartTestJob : public URLRequestTestJob {
public:
- explicit RestartTestJob(URLRequest* request)
+ explicit RestartTestJob(net::URLRequest* request)
: URLRequestTestJob(request, true) {}
protected:
virtual void StartAsync() {
@@ -1834,7 +1834,7 @@ class RestartTestJob : public URLRequestTestJob {
class CancelTestJob : public URLRequestTestJob {
public:
- explicit CancelTestJob(URLRequest* request)
+ explicit CancelTestJob(net::URLRequest* request)
: URLRequestTestJob(request, true) {}
protected:
virtual void StartAsync() {
@@ -1846,7 +1846,7 @@ class CancelTestJob : public URLRequestTestJob {
class CancelThenRestartTestJob : public URLRequestTestJob {
public:
- explicit CancelThenRestartTestJob(URLRequest* request)
+ explicit CancelThenRestartTestJob(net::URLRequest* request)
: URLRequestTestJob(request, true) {
}
protected:
@@ -1859,7 +1859,7 @@ class CancelThenRestartTestJob : public URLRequestTestJob {
};
// An Interceptor for use with interceptor tests
-class TestInterceptor : URLRequest::Interceptor {
+class TestInterceptor : net::URLRequest::Interceptor {
public:
TestInterceptor()
: intercept_main_request_(false), restart_main_request_(false),
@@ -1872,14 +1872,14 @@ class TestInterceptor : URLRequest::Interceptor {
did_simulate_error_main_(false),
did_intercept_redirect_(false), did_cancel_redirect_(false),
did_intercept_final_(false), did_cancel_final_(false) {
- URLRequest::RegisterRequestInterceptor(this);
+ net::URLRequest::RegisterRequestInterceptor(this);
}
~TestInterceptor() {
- URLRequest::UnregisterRequestInterceptor(this);
+ net::URLRequest::UnregisterRequestInterceptor(this);
}
- virtual URLRequestJob* MaybeIntercept(URLRequest* request) {
+ virtual net::URLRequestJob* MaybeIntercept(net::URLRequest* request) {
if (restart_main_request_) {
restart_main_request_ = false;
did_restart_main_ = true;
@@ -1911,8 +1911,8 @@ class TestInterceptor : URLRequest::Interceptor {
true);
}
- virtual URLRequestJob* MaybeInterceptRedirect(URLRequest* request,
- const GURL& location) {
+ virtual net::URLRequestJob* MaybeInterceptRedirect(net::URLRequest* request,
+ const GURL& location) {
if (cancel_redirect_request_) {
cancel_redirect_request_ = false;
did_cancel_redirect_ = true;
@@ -1928,7 +1928,7 @@ class TestInterceptor : URLRequest::Interceptor {
true);
}
- virtual URLRequestJob* MaybeInterceptResponse(URLRequest* request) {
+ virtual net::URLRequestJob* MaybeInterceptResponse(net::URLRequest* request) {
if (cancel_final_request_) {
cancel_final_request_ = false;
did_cancel_final_ = true;
@@ -2019,9 +2019,9 @@ TEST_F(URLRequestTest, Intercept) {
TestDelegate d;
TestURLRequest req(GURL("http://test_intercept/foo"), &d);
- URLRequest::UserData* user_data0 = new URLRequest::UserData();
- URLRequest::UserData* user_data1 = new URLRequest::UserData();
- URLRequest::UserData* user_data2 = new URLRequest::UserData();
+ net::URLRequest::UserData* user_data0 = new net::URLRequest::UserData();
+ net::URLRequest::UserData* user_data1 = new net::URLRequest::UserData();
+ net::URLRequest::UserData* user_data2 = new net::URLRequest::UserData();
req.SetUserData(NULL, user_data0);
req.SetUserData(&user_data1, user_data1);
req.SetUserData(&user_data2, user_data2);
diff --git a/net/url_request/url_request_unittest.h b/net/url_request/url_request_unittest.h
index af8f49e..50236fd 100644
--- a/net/url_request/url_request_unittest.h
+++ b/net/url_request/url_request_unittest.h
@@ -20,6 +20,7 @@
#include "base/thread.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
+#include "net/base/cert_verifier.h"
#include "net/base/cookie_monster.h"
#include "net/base/cookie_policy.h"
#include "net/base/host_resolver.h"
@@ -150,17 +151,20 @@ class TestURLRequestContext : public URLRequestContext {
delete ftp_transaction_factory_;
delete http_transaction_factory_;
delete http_auth_handler_factory_;
+ delete cert_verifier_;
delete host_resolver_;
}
private:
void Init() {
+ cert_verifier_ = new net::CertVerifier;
ftp_transaction_factory_ = new net::FtpNetworkLayer(host_resolver_);
ssl_config_service_ = new net::SSLConfigServiceDefaults;
http_auth_handler_factory_ = net::HttpAuthHandlerFactory::CreateDefault(
host_resolver_);
http_transaction_factory_ = new net::HttpCache(
net::HttpNetworkLayer::CreateFactory(host_resolver_,
+ cert_verifier_,
NULL /* dnsrr_resolver */,
NULL /* dns_cert_checker */,
NULL /* ssl_host_info_factory */,
@@ -179,17 +183,17 @@ class TestURLRequestContext : public URLRequestContext {
//-----------------------------------------------------------------------------
-class TestURLRequest : public URLRequest {
+class TestURLRequest : public net::URLRequest {
public:
TestURLRequest(const GURL& url, Delegate* delegate)
- : URLRequest(url, delegate) {
+ : net::URLRequest(url, delegate) {
set_context(new TestURLRequestContext());
}
};
//-----------------------------------------------------------------------------
-class TestDelegate : public URLRequest::Delegate {
+class TestDelegate : public net::URLRequest::Delegate {
public:
TestDelegate()
: cancel_in_rr_(false),
@@ -213,7 +217,7 @@ class TestDelegate : public URLRequest::Delegate {
buf_(new net::IOBuffer(kBufferSize)) {
}
- virtual void OnReceivedRedirect(URLRequest* request, const GURL& new_url,
+ virtual void OnReceivedRedirect(net::URLRequest* request, const GURL& new_url,
bool* defer_redirect) {
received_redirect_count_++;
if (quit_on_redirect_) {
@@ -224,7 +228,7 @@ class TestDelegate : public URLRequest::Delegate {
}
}
- virtual void OnResponseStarted(URLRequest* request) {
+ virtual void OnResponseStarted(net::URLRequest* request) {
// It doesn't make sense for the request to have IO pending at this point.
DCHECK(!request->status().is_io_pending());
@@ -247,7 +251,7 @@ class TestDelegate : public URLRequest::Delegate {
}
}
- virtual void OnReadCompleted(URLRequest* request, int bytes_read) {
+ virtual void OnReadCompleted(net::URLRequest* request, int bytes_read) {
// It doesn't make sense for the request to have IO pending at this point.
DCHECK(!request->status().is_io_pending());
@@ -283,12 +287,13 @@ class TestDelegate : public URLRequest::Delegate {
request->Cancel();
}
- virtual void OnResponseCompleted(URLRequest* request) {
+ virtual void OnResponseCompleted(net::URLRequest* request) {
if (quit_on_complete_)
MessageLoop::current()->Quit();
}
- void OnAuthRequired(URLRequest* request, net::AuthChallengeInfo* auth_info) {
+ void OnAuthRequired(net::URLRequest* request,
+ net::AuthChallengeInfo* auth_info) {
if (!username_.empty() || !password_.empty()) {
request->SetAuth(username_, password_);
} else {
@@ -296,7 +301,7 @@ class TestDelegate : public URLRequest::Delegate {
}
}
- virtual void OnSSLCertificateError(URLRequest* request,
+ virtual void OnSSLCertificateError(net::URLRequest* request,
int cert_error,
net::X509Certificate* cert) {
// The caller can control whether it needs all SSL requests to go through,
@@ -309,7 +314,7 @@ class TestDelegate : public URLRequest::Delegate {
request->Cancel();
}
- virtual void OnGetCookies(URLRequest* request, bool blocked_by_policy) {
+ virtual void OnGetCookies(net::URLRequest* request, bool blocked_by_policy) {
if (blocked_by_policy) {
blocked_get_cookies_count_++;
if (cancel_in_getcookiesblocked_)
@@ -317,7 +322,7 @@ class TestDelegate : public URLRequest::Delegate {
}
}
- virtual void OnSetCookie(URLRequest* request,
+ virtual void OnSetCookie(net::URLRequest* request,
const std::string& cookie_line,
const net::CookieOptions& options,
bool blocked_by_policy) {
diff --git a/net/websockets/websocket_job.cc b/net/websockets/websocket_job.cc
index a1e2dde..44c944d 100644
--- a/net/websockets/websocket_job.cc
+++ b/net/websockets/websocket_job.cc
@@ -6,6 +6,7 @@
#include <algorithm>
+#include "base/lazy_instance.h"
#include "base/string_tokenizer.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_errors.h"
@@ -39,20 +40,23 @@ net::SocketStreamJob* WebSocketJobFactory(
class WebSocketJobInitSingleton {
private:
- friend struct DefaultSingletonTraits<WebSocketJobInitSingleton>;
+ friend struct base::DefaultLazyInstanceTraits<WebSocketJobInitSingleton>;
WebSocketJobInitSingleton() {
net::SocketStreamJob::RegisterProtocolFactory("ws", WebSocketJobFactory);
net::SocketStreamJob::RegisterProtocolFactory("wss", WebSocketJobFactory);
}
};
+static base::LazyInstance<WebSocketJobInitSingleton> g_websocket_job_init(
+ base::LINKER_INITIALIZED);
+
} // anonymous namespace
namespace net {
// static
void WebSocketJob::EnsureInit() {
- Singleton<WebSocketJobInitSingleton>::get();
+ g_websocket_job_init.Get();
}
WebSocketJob::WebSocketJob(SocketStream::Delegate* delegate)
@@ -144,8 +148,8 @@ void WebSocketJob::RestartWithAuth(
void WebSocketJob::DetachDelegate() {
state_ = CLOSED;
- Singleton<WebSocketThrottle>::get()->RemoveFromQueue(this);
- Singleton<WebSocketThrottle>::get()->WakeupSocketIfNecessary();
+ WebSocketThrottle::GetInstance()->RemoveFromQueue(this);
+ WebSocketThrottle::GetInstance()->WakeupSocketIfNecessary();
scoped_refptr<WebSocketJob> protect(this);
@@ -165,7 +169,7 @@ int WebSocketJob::OnStartOpenConnection(
DCHECK(!callback_);
state_ = CONNECTING;
addresses_.Copy(socket->address_list().head(), true);
- Singleton<WebSocketThrottle>::get()->PutInQueue(this);
+ WebSocketThrottle::GetInstance()->PutInQueue(this);
if (!waiting_)
return OK;
callback_ = callback;
@@ -237,8 +241,8 @@ void WebSocketJob::OnReceivedData(
void WebSocketJob::OnClose(SocketStream* socket) {
state_ = CLOSED;
- Singleton<WebSocketThrottle>::get()->RemoveFromQueue(this);
- Singleton<WebSocketThrottle>::get()->WakeupSocketIfNecessary();
+ WebSocketThrottle::GetInstance()->RemoveFromQueue(this);
+ WebSocketThrottle::GetInstance()->WakeupSocketIfNecessary();
scoped_refptr<WebSocketJob> protect(this);
@@ -405,8 +409,8 @@ void WebSocketJob::SaveNextCookie() {
handshake_response_.reset();
- Singleton<WebSocketThrottle>::get()->RemoveFromQueue(this);
- Singleton<WebSocketThrottle>::get()->WakeupSocketIfNecessary();
+ WebSocketThrottle::GetInstance()->RemoveFromQueue(this);
+ WebSocketThrottle::GetInstance()->WakeupSocketIfNecessary();
return;
}
diff --git a/net/websockets/websocket_job_unittest.cc b/net/websockets/websocket_job_unittest.cc
index 53d4a62..43d8509 100644
--- a/net/websockets/websocket_job_unittest.cc
+++ b/net/websockets/websocket_job_unittest.cc
@@ -222,7 +222,7 @@ class WebSocketJobTest : public PlatformTest {
addr.ai_addr = reinterpret_cast<sockaddr*>(&sa_in);
addr.ai_next = NULL;
websocket_->addresses_.Copy(&addr, true);
- Singleton<WebSocketThrottle>::get()->PutInQueue(websocket_);
+ WebSocketThrottle::GetInstance()->PutInQueue(websocket_);
}
WebSocketJob::State GetWebSocketJobState() {
return websocket_->state_;
@@ -230,7 +230,7 @@ class WebSocketJobTest : public PlatformTest {
void CloseWebSocketJob() {
if (websocket_->socket_) {
websocket_->socket_->DetachDelegate();
- Singleton<WebSocketThrottle>::get()->RemoveFromQueue(websocket_);
+ WebSocketThrottle::GetInstance()->RemoveFromQueue(websocket_);
}
websocket_->state_ = WebSocketJob::CLOSED;
websocket_->delegate_ = NULL;
diff --git a/net/websockets/websocket_net_log_params.cc b/net/websockets/websocket_net_log_params.cc
new file mode 100644
index 0000000..53b46c8
--- /dev/null
+++ b/net/websockets/websocket_net_log_params.cc
@@ -0,0 +1,51 @@
+// 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.
+
+#include "net/websockets/websocket_net_log_params.h"
+
+namespace net {
+
+NetLogWebSocketHandshakeParameter::NetLogWebSocketHandshakeParameter(
+ const std::string& headers)
+ : headers_(headers) {
+}
+
+Value* NetLogWebSocketHandshakeParameter::ToValue() const {
+ DictionaryValue* dict = new DictionaryValue();
+ ListValue* headers = new ListValue();
+
+ size_t last = 0;
+ size_t headers_size = headers_.size();
+ size_t pos = 0;
+ while (pos <= headers_size) {
+ if (pos == headers_size ||
+ (headers_[pos] == '\r' &&
+ pos + 1 < headers_size && headers_[pos + 1] == '\n')) {
+ std::string entry = headers_.substr(last, pos - last);
+ pos += 2;
+ last = pos;
+
+ headers->Append(new StringValue(entry));
+
+ if (entry.empty()) {
+ // Dump WebSocket key3.
+ std::string key;
+ for (; pos < headers_size; ++pos) {
+ key += base::StringPrintf("\\x%02x", headers_[pos] & 0xff);
+ }
+ headers->Append(new StringValue(key));
+ break;
+ }
+ } else {
+ ++pos;
+ }
+ }
+
+ dict->Set("headers", headers);
+ return dict;
+}
+
+NetLogWebSocketHandshakeParameter::~NetLogWebSocketHandshakeParameter() {}
+
+} // namespace net
diff --git a/net/websockets/websocket_net_log_params.h b/net/websockets/websocket_net_log_params.h
index 4cd058f..1da234c 100644
--- a/net/websockets/websocket_net_log_params.h
+++ b/net/websockets/websocket_net_log_params.h
@@ -21,47 +21,12 @@ namespace net {
class NetLogWebSocketHandshakeParameter : public NetLog::EventParameters {
public:
- explicit NetLogWebSocketHandshakeParameter(const std::string& headers)
- : headers_(headers) {
- }
+ explicit NetLogWebSocketHandshakeParameter(const std::string& headers);
- Value* ToValue() const {
- DictionaryValue* dict = new DictionaryValue();
- ListValue* headers = new ListValue();
-
- size_t last = 0;
- size_t headers_size = headers_.size();
- size_t pos = 0;
- while (pos <= headers_size) {
- if (pos == headers_size ||
- (headers_[pos] == '\r' &&
- pos + 1 < headers_size && headers_[pos + 1] == '\n')) {
- std::string entry = headers_.substr(last, pos - last);
- pos += 2;
- last = pos;
-
- headers->Append(new StringValue(entry));
-
- if (entry.empty()) {
- // Dump WebSocket key3.
- std::string key;
- for (; pos < headers_size; ++pos) {
- key += base::StringPrintf("\\x%02x", headers_[pos] & 0xff);
- }
- headers->Append(new StringValue(key));
- break;
- }
- } else {
- ++pos;
- }
- }
-
- dict->Set("headers", headers);
- return dict;
- }
+ virtual Value* ToValue() const;
private:
- ~NetLogWebSocketHandshakeParameter() {}
+ virtual ~NetLogWebSocketHandshakeParameter();
const std::string headers_;
diff --git a/net/websockets/websocket_throttle.cc b/net/websockets/websocket_throttle.cc
index 2d62815..c714de6 100644
--- a/net/websockets/websocket_throttle.cc
+++ b/net/websockets/websocket_throttle.cc
@@ -54,6 +54,11 @@ WebSocketThrottle::~WebSocketThrottle() {
DCHECK(addr_map_.empty());
}
+// static
+WebSocketThrottle* WebSocketThrottle::GetInstance() {
+ return Singleton<WebSocketThrottle>::get();
+}
+
void WebSocketThrottle::PutInQueue(WebSocketJob* job) {
queue_.push_back(job);
const AddressList& address_list = job->address_list();
diff --git a/net/websockets/websocket_throttle.h b/net/websockets/websocket_throttle.h
index 0849834..9becc62 100644
--- a/net/websockets/websocket_throttle.h
+++ b/net/websockets/websocket_throttle.h
@@ -10,7 +10,8 @@
#include <string>
#include "base/hash_tables.h"
-#include "base/singleton.h"
+
+template <typename T> struct DefaultSingletonTraits;
namespace net {
@@ -27,6 +28,9 @@ class WebSocketJob;
// for that connection to have failed.
class WebSocketThrottle {
public:
+ // Returns the singleton instance.
+ static WebSocketThrottle* GetInstance();
+
// Puts |job| in |queue_| and queues for the destination addresses
// of |job|.
// If other job is using the same destination address, set |job| waiting.
diff --git a/testing/gmock.gyp b/testing/gmock.gyp
index f879dcf..8f73cb6 100644
--- a/testing/gmock.gyp
+++ b/testing/gmock.gyp
@@ -50,9 +50,7 @@
],
},
{
- # Note that calling this "gmock_main" confuses the scons build,
- # which uses "_main" on scons files to produce special behavior.
- 'target_name': 'gmockmain',
+ 'target_name': 'gmock_main',
'type': '<(library)',
'dependencies': [
'gmock',
diff --git a/testing/gtest.gyp b/testing/gtest.gyp
index da95f42..1a91ac5 100644
--- a/testing/gtest.gyp
+++ b/testing/gtest.gyp
@@ -102,15 +102,27 @@
'gtest/include', # So that gtest headers can find themselves.
],
'target_conditions': [
- ['_type=="executable"', {'test': 1}],
+ ['_type=="executable"', {
+ 'test': 1,
+ 'conditions': [
+ ['OS=="mac"', {
+ 'run_as': {
+ 'action????': ['${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}'],
+ },
+ }],
+ ['OS=="win"', {
+ 'run_as': {
+ 'action????': ['$(TargetPath)', '--gtest_print_time'],
+ },
+ }],
+ ],
+ }],
],
'msvs_disabled_warnings': [4800],
},
},
{
- # Note that calling this "gtest_main" confuses the scons build,
- # which uses "_main" on scons files to produce special behavior.
- 'target_name': 'gtestmain',
+ 'target_name': 'gtest_main',
'type': '<(library)',
'dependencies': [
'gtest',
diff --git a/webkit/glue/bookmarklet_unittest.cc b/webkit/glue/bookmarklet_unittest.cc
index 5d8a364..d7fada5 100644
--- a/webkit/glue/bookmarklet_unittest.cc
+++ b/webkit/glue/bookmarklet_unittest.cc
@@ -26,8 +26,8 @@ TEST_F(BookmarkletTest, Redirect) {
test_shell_->LoadURL(
GURL("javascript:location.href='data:text/plain,SUCCESS'"));
test_shell_->WaitTestFinished();
- std::wstring text = test_shell_->GetDocumentText();
- EXPECT_EQ(L"SUCCESS", text);
+ string16 text = test_shell_->GetDocumentText();
+ EXPECT_EQ("SUCCESS", UTF16ToASCII(text));
}
TEST_F(BookmarkletTest, RedirectVoided) {
@@ -38,12 +38,12 @@ TEST_F(BookmarkletTest, RedirectVoided) {
test_shell_->LoadURL(
GURL("javascript:void(location.href='data:text/plain,SUCCESS')"));
test_shell_->WaitTestFinished();
- std::wstring text = test_shell_->GetDocumentText();
- EXPECT_EQ(L"SUCCESS", text);
+ string16 text = test_shell_->GetDocumentText();
+ EXPECT_EQ("SUCCESS", UTF16ToASCII(text));
}
TEST_F(BookmarkletTest, NonEmptyResult) {
- std::wstring text;
+ string16 text;
// TODO(darin): This test fails in a JSC build. WebCore+JSC does not really
// need to support this usage until WebCore supports javascript: URLs that
@@ -54,13 +54,13 @@ TEST_F(BookmarkletTest, NonEmptyResult) {
test_shell_->LoadURL(L"javascript:false");
MessageLoop::current()->RunAllPending();
text = test_shell_->GetDocumentText();
- EXPECT_EQ(L"false", text);
+ EXPECT_EQ("false", UTF16ToASCII(text));
#endif
test_shell_->LoadURL(GURL("javascript:'hello world'"));
MessageLoop::current()->RunAllPending();
text = test_shell_->GetDocumentText();
- EXPECT_EQ(L"hello world", text);
+ EXPECT_EQ("hello world", UTF16ToASCII(text));
}
TEST_F(BookmarkletTest, DocumentWrite) {
@@ -69,8 +69,8 @@ TEST_F(BookmarkletTest, DocumentWrite) {
"document.write('hello world');"
"document.close()"));
MessageLoop::current()->RunAllPending();
- std::wstring text = test_shell_->GetDocumentText();
- EXPECT_EQ(L"hello world", text);
+ string16 text = test_shell_->GetDocumentText();
+ EXPECT_EQ("hello world", UTF16ToASCII(text));
}
} // namespace
diff --git a/webkit/glue/context_menu.cc b/webkit/glue/context_menu.cc
index 390d740..bdfe790 100644
--- a/webkit/glue/context_menu.cc
+++ b/webkit/glue/context_menu.cc
@@ -18,7 +18,7 @@ ContextMenuParams::ContextMenuParams(const WebKit::WebContextMenuData& data)
page_url(data.pageURL),
frame_url(data.frameURL),
media_flags(data.mediaFlags),
- selection_text(UTF16ToWideHack(data.selectedText)),
+ selection_text(data.selectedText),
misspelled_word(data.misspelledWord),
spellcheck_enabled(data.isSpellCheckingEnabled),
is_editable(data.isEditable),
diff --git a/webkit/glue/context_menu.h b/webkit/glue/context_menu.h
index b681a38..c87de41 100644
--- a/webkit/glue/context_menu.h
+++ b/webkit/glue/context_menu.h
@@ -8,7 +8,7 @@
#include <vector>
#include "base/basictypes.h"
-#include "base/utf_string_conversions.h"
+#include "base/string16.h"
#include "googleurl/src/gurl.h"
#include "webkit/glue/webmenuitem.h"
@@ -57,7 +57,7 @@ struct ContextMenuParams {
int media_flags;
// This is the text of the selection that the context menu was invoked on.
- std::wstring selection_text;
+ string16 selection_text;
// The misspelled word under the cursor, if any. Used to generate the
// |dictionary_suggestions| list.
diff --git a/webkit/glue/cpp_bound_class.cc b/webkit/glue/cpp_bound_class.cc
index d58fc4e..c5d15b6 100644
--- a/webkit/glue/cpp_bound_class.cc
+++ b/webkit/glue/cpp_bound_class.cc
@@ -319,7 +319,7 @@ CppVariant* CppBoundClass::GetAsCppVariant() {
}
void CppBoundClass::BindToJavascript(WebFrame* frame,
- const std::wstring& classname) {
+ const std::string& classname) {
#if WEBKIT_USING_JSC
#error "This is not going to work anymore...but it's not clear what the solution is...or if it's still necessary."
JSC::JSLock lock(false);
@@ -328,7 +328,7 @@ void CppBoundClass::BindToJavascript(WebFrame* frame,
// BindToWindowObject will take its own reference to the NPObject, and clean
// up after itself. It will also (indirectly) register the object with V8,
// so we must remember this so we can unregister it when we're destroyed.
- frame->bindToWindowObject(WideToUTF16Hack(classname),
+ frame->bindToWindowObject(ASCIIToUTF16(classname),
NPVARIANT_TO_OBJECT(*GetAsCppVariant()));
bound_to_frame_ = true;
}
diff --git a/webkit/glue/cpp_bound_class.h b/webkit/glue/cpp_bound_class.h
index a446386..06662ce 100644
--- a/webkit/glue/cpp_bound_class.h
+++ b/webkit/glue/cpp_bound_class.h
@@ -65,8 +65,7 @@ class CppBoundClass {
// as window.<classname>. The owner of the CppBoundObject is responsible for
// keeping the object around while the frame is alive, and for destroying it
// afterwards.
- void BindToJavascript(
- WebKit::WebFrame* frame, const std::wstring& classname);
+ void BindToJavascript(WebKit::WebFrame* frame, const std::string& classname);
// The type of callbacks.
typedef Callback2<const CppArgumentList&, CppVariant*>::Type Callback;
diff --git a/webkit/glue/cpp_bound_class_unittest.cc b/webkit/glue/cpp_bound_class_unittest.cc
index f40b66b..54581ad 100644
--- a/webkit/glue/cpp_bound_class_unittest.cc
+++ b/webkit/glue/cpp_bound_class_unittest.cc
@@ -9,6 +9,7 @@
#include <vector>
#include "base/message_loop.h"
+#include "base/string_util.h"
#include "third_party/WebKit/WebKit/chromium/public/WebData.h"
#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h"
#include "third_party/WebKit/WebKit/chromium/public/WebURL.h"
@@ -63,7 +64,7 @@ class ExampleTestShell : public TestShell {
// When called by WebViewDelegate::WindowObjectCleared method, this binds a
// CppExampleObject to window.example.
virtual void BindJSObjectsToWindow(WebFrame* frame) {
- example_bound_class_.BindToJavascript(frame, L"example");
+ example_bound_class_.BindToJavascript(frame, "example");
// We use the layoutTestController binding for notifyDone.
TestShell::BindJSObjectsToWindow(frame);
}
@@ -113,14 +114,15 @@ class CppBoundClassTest : public TestShellTest {
// document text is exactly "SUCCESS".
void CheckJavaScriptSuccess(const std::string& javascript) {
ExecuteJavaScript(javascript);
- EXPECT_EQ(L"SUCCESS", webkit_glue::DumpDocumentText(webframe_));
+ EXPECT_EQ("SUCCESS",
+ UTF16ToASCII(webkit_glue::DumpDocumentText(webframe_)));
}
// Executes the specified JavaScript and checks that the resulting document
// text is empty.
void CheckJavaScriptFailure(const std::string& javascript) {
ExecuteJavaScript(javascript);
- EXPECT_EQ(L"", webkit_glue::DumpDocumentText(webframe_));
+ EXPECT_EQ("", UTF16ToASCII(webkit_glue::DumpDocumentText(webframe_)));
}
// Constructs a JavaScript snippet that evaluates and compares the left and
@@ -238,8 +240,7 @@ TEST_F(CppBoundClassTest, InvokeMethods) {
"example.echoValue()", "null", // Too few arguments
"example.echoType(false)", "true",
- // Re-enable after merging r72243.
- //"example.echoType(19)", "3.14159",
+ "example.echoType(19)", "3.14159",
"example.echoType(9.876)", "3.14159",
"example.echoType('test string')", "'Success!'",
"example.echoType()", "null", // Too few arguments
diff --git a/webkit/glue/cpp_variant.cc b/webkit/glue/cpp_variant.cc
index 8545bc1..0d16cdd 100644
--- a/webkit/glue/cpp_variant.cc
+++ b/webkit/glue/cpp_variant.cc
@@ -211,10 +211,9 @@ bool CppVariant::ToBoolean() const {
return value.boolValue;
}
-std::vector<std::wstring> CppVariant::ToStringVector() const {
-
+std::vector<std::string> CppVariant::ToStringVector() const {
DCHECK(isObject());
- std::vector<std::wstring> wstring_vector;
+ std::vector<std::string> string_vector;
NPObject* np_value = value.objectValue;
NPIdentifier length_id = WebBindings::getStringIdentifier("length");
@@ -242,7 +241,7 @@ std::vector<std::wstring> CppVariant::ToStringVector() const {
std::string string(
NPVARIANT_TO_STRING(index_value).UTF8Characters,
NPVARIANT_TO_STRING(index_value).UTF8Length);
- wstring_vector.push_back(UTF8ToWide(string));
+ string_vector.push_back(string);
}
WebBindings::releaseVariantValue(&index_value);
}
@@ -250,7 +249,7 @@ std::vector<std::wstring> CppVariant::ToStringVector() const {
}
}
}
- return wstring_vector;
+ return string_vector;
}
bool CppVariant::Invoke(const std::string& method, const CppVariant* args,
diff --git a/webkit/glue/cpp_variant.h b/webkit/glue/cpp_variant.h
index 71b3166..34f843a 100644
--- a/webkit/glue/cpp_variant.h
+++ b/webkit/glue/cpp_variant.h
@@ -96,7 +96,7 @@ class CppVariant : public NPVariant {
bool ToBoolean() const;
// Returns a vector of strings for the specified argument. This is useful
// for converting a JavaScript array of strings into a vector of strings.
- std::vector<std::wstring> ToStringVector() const;
+ std::vector<std::string> ToStringVector() const;
// Invoke method of the given name on an object with the supplied arguments.
// The first argument should be the object on which the method is to be
diff --git a/webkit/glue/glue_serialize.cc b/webkit/glue/glue_serialize.cc
index 835ae78..5b76784 100644
--- a/webkit/glue/glue_serialize.cc
+++ b/webkit/glue/glue_serialize.cc
@@ -343,7 +343,9 @@ static void WriteHistoryItem(
// Creates a new HistoryItem tree based on the serialized string.
// Assumes the data is in the format returned by WriteHistoryItem.
static WebHistoryItem ReadHistoryItem(
- const SerializeObject* obj, bool include_form_data) {
+ const SerializeObject* obj,
+ bool include_form_data,
+ bool include_scroll_offset) {
// See note in WriteHistoryItem. on this.
obj->version = ReadInteger(obj);
@@ -368,9 +370,12 @@ static WebHistoryItem ReadHistoryItem(
item.setTitle(ReadString(obj));
item.setAlternateTitle(ReadString(obj));
item.setLastVisitedTime(ReadReal(obj));
+
int x = ReadInteger(obj);
int y = ReadInteger(obj);
- item.setScrollOffset(WebPoint(x, y));
+ if (include_scroll_offset)
+ item.setScrollOffset(WebPoint(x, y));
+
item.setIsTargetItem(ReadBoolean(obj));
item.setVisitCount(ReadInteger(obj));
item.setReferrer(ReadString(obj));
@@ -401,7 +406,9 @@ static WebHistoryItem ReadHistoryItem(
// Subitems
int num_children = ReadInteger(obj);
for (int i = 0; i < num_children; ++i)
- item.appendToChildren(ReadHistoryItem(obj, include_form_data));
+ item.appendToChildren(ReadHistoryItem(obj,
+ include_form_data,
+ include_scroll_offset));
return item;
}
@@ -420,20 +427,22 @@ std::string HistoryItemToString(const WebHistoryItem& item) {
// This assumes that the given serialized string has all the required key,value
// pairs, and does minimal error checking. If |include_form_data| is true,
// the form data from a post is restored, otherwise the form data is empty.
+// If |include_scroll_offset| is true, the scroll offset is restored.
static WebHistoryItem HistoryItemFromString(
const std::string& serialized_item,
- bool include_form_data) {
+ bool include_form_data,
+ bool include_scroll_offset) {
if (serialized_item.empty())
return WebHistoryItem();
SerializeObject obj(serialized_item.data(),
static_cast<int>(serialized_item.length()));
- return ReadHistoryItem(&obj, include_form_data);
+ return ReadHistoryItem(&obj, include_form_data, include_scroll_offset);
}
WebHistoryItem HistoryItemFromString(
const std::string& serialized_item) {
- return HistoryItemFromString(serialized_item, true);
+ return HistoryItemFromString(serialized_item, true, true);
}
// For testing purposes only.
@@ -470,7 +479,22 @@ std::string CreateHistoryStateForURL(const GURL& url) {
std::string RemoveFormDataFromHistoryState(const std::string& content_state) {
// TODO(darin): We should avoid using the WebKit API here, so that we do not
// need to have WebKit initialized before calling this method.
- const WebHistoryItem& item = HistoryItemFromString(content_state, false);
+ const WebHistoryItem& item =
+ HistoryItemFromString(content_state, false, true);
+ if (item.isNull()) {
+ // Couldn't parse the string, return an empty string.
+ return std::string();
+ }
+
+ return HistoryItemToString(item);
+}
+
+std::string RemoveScrollOffsetFromHistoryState(
+ const std::string& content_state) {
+ // TODO(darin): We should avoid using the WebKit API here, so that we do not
+ // need to have WebKit initialized before calling this method.
+ const WebHistoryItem& item =
+ HistoryItemFromString(content_state, true, false);
if (item.isNull()) {
// Couldn't parse the string, return an empty string.
return std::string();
diff --git a/webkit/glue/media/audio_decoder.cc b/webkit/glue/media/audio_decoder.cc
new file mode 100644
index 0000000..3fc05c9
--- /dev/null
+++ b/webkit/glue/media/audio_decoder.cc
@@ -0,0 +1,76 @@
+// 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.
+
+#include "webkit/glue/media/audio_decoder.h"
+
+#include <vector>
+#include "base/basictypes.h"
+#include "base/string_util.h"
+#include "base/time.h"
+#include "media/filters/audio_file_reader.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebAudioBus.h"
+
+using media::AudioFileReader;
+using media::InMemoryDataReader;
+using std::vector;
+using WebKit::WebAudioBus;
+
+namespace webkit_glue {
+
+// Decode in-memory audio file data.
+bool DecodeAudioFileData(
+ WebKit::WebAudioBus* destination_bus,
+ const char* data, size_t data_size, double sample_rate) {
+ DCHECK(destination_bus);
+ if (!destination_bus)
+ return false;
+
+ // Uses the FFmpeg library for audio file reading.
+ InMemoryDataReader data_reader(data, data_size);
+ AudioFileReader reader(&data_reader);
+
+ if (!reader.Open())
+ return false;
+
+ size_t number_of_channels = reader.channels();
+ double file_sample_rate = reader.sample_rate();
+ double duration = reader.duration().InSecondsF();
+ size_t number_of_frames = static_cast<size_t>(reader.number_of_frames());
+
+ // TODO(crogers) : do sample-rate conversion with FFmpeg.
+ // For now, we're ignoring the requested 'sample_rate' and returning
+ // the WebAudioBus at the file's sample-rate.
+ // double destination_sample_rate =
+ // (sample_rate != 0.0) ? sample_rate : file_sample_rate;
+ double destination_sample_rate = file_sample_rate;
+
+ DLOG(INFO) << "Decoding file data -"
+ << " data: " << data
+ << " data size: " << data_size
+ << " duration: " << duration
+ << " number of frames: " << number_of_frames
+ << " sample rate: " << file_sample_rate
+ << " number of channels: " << number_of_channels;
+
+ // Change to destination sample-rate.
+ number_of_frames = static_cast<size_t>(number_of_frames *
+ (destination_sample_rate / file_sample_rate));
+
+ // Allocate and configure the output audio channel data.
+ destination_bus->initialize(number_of_channels,
+ number_of_frames,
+ destination_sample_rate);
+
+ // Wrap the channel pointers which will receive the decoded PCM audio.
+ vector<float*> audio_data;
+ audio_data.reserve(number_of_channels);
+ for (size_t i = 0; i < number_of_channels; ++i) {
+ audio_data.push_back(destination_bus->channelData(i));
+ }
+
+ // Decode the audio file data.
+ return reader.Read(audio_data, number_of_frames);
+}
+
+} // namespace webkit_glue
diff --git a/webkit/glue/media/audio_decoder.h b/webkit/glue/media/audio_decoder.h
new file mode 100644
index 0000000..57cc90b
--- /dev/null
+++ b/webkit/glue/media/audio_decoder.h
@@ -0,0 +1,20 @@
+// 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.
+
+#ifndef WEBKIT_GLUE_MEDIA_AUDIO_DECODER_H_
+#define WEBKIT_GLUE_MEDIA_AUDIO_DECODER_H_
+
+#include "base/basictypes.h"
+
+namespace WebKit { class WebAudioBus; }
+
+namespace webkit_glue {
+
+// Decode in-memory audio file data.
+bool DecodeAudioFileData(WebKit::WebAudioBus* destination_bus, const char* data,
+ size_t data_size, double sample_rate);
+
+} // namespace webkit_glue
+
+#endif // WEBKIT_GLUE_MEDIA_AUDIO_DECODER_H_
diff --git a/webkit/glue/media/buffered_data_source.cc b/webkit/glue/media/buffered_data_source.cc
index 29c86ac..b6efa16 100644
--- a/webkit/glue/media/buffered_data_source.cc
+++ b/webkit/glue/media/buffered_data_source.cc
@@ -2,46 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "base/message_loop.h"
-#include "base/process_util.h"
-#include "base/stl_util-inl.h"
-#include "base/string_util.h"
+#include "webkit/glue/media/buffered_data_source.h"
+
#include "media/base/filter_host.h"
-#include "media/base/media_format.h"
-#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
-#include "net/http/http_response_headers.h"
-#include "webkit/glue/media/buffered_data_source.h"
#include "webkit/glue/webkit_glue.h"
-#include "webkit/glue/webmediaplayer_impl.h"
-
-namespace {
-const char kHttpScheme[] = "http";
-const char kHttpsScheme[] = "https";
-const char kDataScheme[] = "data";
-const int64 kPositionNotSpecified = -1;
-const int kHttpOK = 200;
-const int kHttpPartialContent = 206;
+using WebKit::WebFrame;
-// Define the number of bytes in a megabyte.
-const size_t kMegabyte = 1024 * 1024;
-
-// Backward capacity of the buffer, by default 2MB.
-const size_t kBackwardCapcity = 2 * kMegabyte;
-
-// Forward capacity of the buffer, by default 10MB.
-const size_t kForwardCapacity = 10 * kMegabyte;
-
-// The threshold of bytes that we should wait until the data arrives in the
-// future instead of restarting a new connection. This number is defined in the
-// number of bytes, we should determine this value from typical connection speed
-// and amount of time for a suitable wait. Now I just make a guess for this
-// number to be 2MB.
-// TODO(hclam): determine a better value for this.
-const int kForwardWaitThreshold = 2 * kMegabyte;
+namespace {
// Defines how long we should wait for more data before we declare a connection
// timeout and start a new request.
@@ -58,479 +27,18 @@ const int kReadTrials = 3;
// of FFmpeg.
const int kInitialReadBufferSize = 32768;
-// Returns true if |url| operates on HTTP protocol.
-bool IsHttpProtocol(const GURL& url) {
- return url.SchemeIs(kHttpScheme) || url.SchemeIs(kHttpsScheme);
-}
-
-bool IsDataProtocol(const GURL& url) {
- return url.SchemeIs(kDataScheme);
-}
-
-} // namespace
+} // namespace
namespace webkit_glue {
-/////////////////////////////////////////////////////////////////////////////
-// BufferedResourceLoader
-BufferedResourceLoader::BufferedResourceLoader(
- webkit_glue::MediaResourceLoaderBridgeFactory* bridge_factory,
- const GURL& url,
- int64 first_byte_position,
- int64 last_byte_position)
- : buffer_(new media::SeekableBuffer(kBackwardCapcity, kForwardCapacity)),
- deferred_(false),
- defer_allowed_(true),
- completed_(false),
- range_requested_(false),
- partial_response_(false),
- bridge_factory_(bridge_factory),
- url_(url),
- first_byte_position_(first_byte_position),
- last_byte_position_(last_byte_position),
- start_callback_(NULL),
- bridge_(NULL),
- offset_(0),
- content_length_(kPositionNotSpecified),
- instance_size_(kPositionNotSpecified),
- read_callback_(NULL),
- read_position_(0),
- read_size_(0),
- read_buffer_(NULL),
- first_offset_(0),
- last_offset_(0) {
-}
-
-BufferedResourceLoader::~BufferedResourceLoader() {
-}
-
-void BufferedResourceLoader::Start(net::CompletionCallback* start_callback,
- NetworkEventCallback* event_callback) {
- // Make sure we have not started.
- DCHECK(!bridge_.get());
- DCHECK(!start_callback_.get());
- DCHECK(!event_callback_.get());
- DCHECK(start_callback);
- DCHECK(event_callback);
-
- start_callback_.reset(start_callback);
- event_callback_.reset(event_callback);
-
- if (first_byte_position_ != kPositionNotSpecified) {
- range_requested_ = true;
- // TODO(hclam): server may not support range request so |offset_| may not
- // equal to |first_byte_position_|.
- offset_ = first_byte_position_;
- }
-
- // Creates the bridge on render thread since we can only access
- // ResourceDispatcher on this thread.
- bridge_.reset(
- bridge_factory_->CreateBridge(
- url_,
- net::LOAD_NORMAL,
- first_byte_position_,
- last_byte_position_));
-
- // Increment the reference count right before we start the request. This
- // reference will be release when this request has ended.
- AddRef();
-
- // And start the resource loading.
- bridge_->Start(this);
-}
-
-void BufferedResourceLoader::Stop() {
- // Reset callbacks.
- start_callback_.reset();
- event_callback_.reset();
- read_callback_.reset();
-
- // Use the internal buffer to signal that we have been stopped.
- // TODO(hclam): Not so pretty to do this.
- if (!buffer_.get())
- return;
-
- // Destroy internal buffer.
- buffer_.reset();
-
- if (bridge_.get()) {
- // Cancel the request. This method call will cancel the request
- // asynchronously. We may still get data or messages until we receive
- // a response completed message.
- if (deferred_)
- bridge_->SetDefersLoading(false);
- deferred_ = false;
- bridge_->Cancel();
- }
-}
-
-void BufferedResourceLoader::Read(int64 position,
- int read_size,
- uint8* buffer,
- net::CompletionCallback* read_callback) {
- DCHECK(!read_callback_.get());
- DCHECK(buffer_.get());
- DCHECK(read_callback);
- DCHECK(buffer);
-
- // Save the parameter of reading.
- read_callback_.reset(read_callback);
- read_position_ = position;
- read_size_ = read_size;
- read_buffer_ = buffer;
- // If read position is beyond the instance size, we cannot read there.
- if (instance_size_ != kPositionNotSpecified &&
- instance_size_ <= read_position_) {
- DoneRead(0);
- return;
- }
-
- // Make sure |offset_| and |read_position_| does not differ by a large
- // amount.
- if (read_position_ > offset_ + kint32max ||
- read_position_ < offset_ + kint32min) {
- DoneRead(net::ERR_CACHE_MISS);
- return;
- }
-
- // Prepare the parameters.
- first_offset_ = static_cast<int>(read_position_ - offset_);
- last_offset_ = first_offset_ + read_size_;
-
- // If we can serve the request now, do the actual read.
- if (CanFulfillRead()) {
- ReadInternal();
- DisableDeferIfNeeded();
- return;
- }
-
- // If we expected the read request to be fulfilled later, returns
- // immediately and let more data to flow in.
- if (WillFulfillRead())
- return;
-
- // Make a callback to report failure.
- DoneRead(net::ERR_CACHE_MISS);
-}
-
-int64 BufferedResourceLoader::GetBufferedFirstBytePosition() {
- if (buffer_.get())
- return offset_ - static_cast<int>(buffer_->backward_bytes());
- return kPositionNotSpecified;
-}
-
-int64 BufferedResourceLoader::GetBufferedLastBytePosition() {
- if (buffer_.get())
- return offset_ + static_cast<int>(buffer_->forward_bytes()) - 1;
- return kPositionNotSpecified;
-}
-
-void BufferedResourceLoader::SetAllowDefer(bool is_allowed) {
- defer_allowed_ = is_allowed;
- DisableDeferIfNeeded();
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// BufferedResourceLoader,
-// webkit_glue::ResourceLoaderBridge::Peer implementations
-bool BufferedResourceLoader::OnReceivedRedirect(
- const GURL& new_url,
- const webkit_glue::ResourceResponseInfo& info,
- bool* has_new_first_party_for_cookies,
- GURL* new_first_party_for_cookies) {
- DCHECK(bridge_.get());
-
- // Save the new URL.
- url_ = new_url;
- // TODO(wtc): should we return a new first party for cookies URL?
- *has_new_first_party_for_cookies = false;
-
- // The load may have been stopped and |start_callback| is destroyed.
- // In this case we shouldn't do anything.
- if (!start_callback_.get())
- return true;
-
- if (!IsProtocolSupportedForMedia(new_url)) {
- DoneStart(net::ERR_ADDRESS_INVALID);
- Stop();
- return false;
- }
- return true;
-}
-
-void BufferedResourceLoader::OnReceivedResponse(
- const webkit_glue::ResourceResponseInfo& info,
- bool content_filtered) {
- DCHECK(bridge_.get());
-
- // The loader may have been stopped and |start_callback| is destroyed.
- // In this case we shouldn't do anything.
- if (!start_callback_.get())
- return;
-
- // We make a strong assumption that when we reach here we have either
- // received a response from HTTP/HTTPS protocol or the request was
- // successful (in particular range request). So we only verify the partial
- // response for HTTP and HTTPS protocol.
- if (IsHttpProtocol(url_)) {
- int error = net::OK;
- if (!info.headers) {
- // We expect to receive headers because this is a HTTP or HTTPS protocol,
- // if not report failure.
- error = net::ERR_INVALID_RESPONSE;
- } else {
- if (info.headers->response_code() == kHttpPartialContent)
- partial_response_ = true;
-
- if (range_requested_ && partial_response_) {
- // If we have verified the partial response and it is correct, we will
- // return net::OK.
- if (!VerifyPartialResponse(info))
- error = net::ERR_INVALID_RESPONSE;
- } else if (info.headers->response_code() != kHttpOK) {
- // We didn't request a range but server didn't reply with "200 OK".
- error = net::ERR_FAILED;
- }
- }
-
- if (error != net::OK) {
- DoneStart(error);
- Stop();
- return;
- }
- } else {
- // For any protocol other than HTTP and HTTPS, assume range request is
- // always fulfilled.
- partial_response_ = range_requested_;
- }
-
- // |info.content_length| can be -1, in that case |content_length_| is
- // not specified and this is a streaming response.
- content_length_ = info.content_length;
-
- // If we have not requested a range, then the size of the instance is equal
- // to the content length.
- if (!partial_response_)
- instance_size_ = content_length_;
-
- // Calls with a successful response.
- DoneStart(net::OK);
-}
-
-void BufferedResourceLoader::OnReceivedData(const char* data, int len) {
- DCHECK(bridge_.get());
-
- // If this loader has been stopped, |buffer_| would be destroyed.
- // In this case we shouldn't do anything.
- if (!buffer_.get())
- return;
-
- // Writes more data to |buffer_|.
- buffer_->Append(reinterpret_cast<const uint8*>(data), len);
-
- // If there is an active read request, try to fulfill the request.
- if (HasPendingRead() && CanFulfillRead()) {
- ReadInternal();
- } else if (!defer_allowed_) {
- // If we're not allowed to defer, slide the buffer window forward instead
- // of deferring.
- if (buffer_->forward_bytes() > buffer_->forward_capacity()) {
- size_t excess = buffer_->forward_bytes() - buffer_->forward_capacity();
- bool success = buffer_->Seek(excess);
- DCHECK(success);
- offset_ += first_offset_ + excess;
- }
- }
-
- // At last see if the buffer is full and we need to defer the downloading.
- EnableDeferIfNeeded();
-
- // Notify that we have received some data.
- NotifyNetworkEvent();
-}
-
-void BufferedResourceLoader::OnCompletedRequest(
- const URLRequestStatus& status,
- const std::string& security_info,
- const base::Time& completion_time) {
- DCHECK(bridge_.get());
-
- // Saves the information that the request has completed.
- completed_ = true;
-
- // If there is a start callback, calls it.
- if (start_callback_.get()) {
- DoneStart(status.os_error());
- }
-
- // If there is a pending read but the request has ended, returns with what
- // we have.
- if (HasPendingRead()) {
- // Make sure we have a valid buffer before we satisfy a read request.
- DCHECK(buffer_.get());
-
- if (status.is_success()) {
- // Try to fulfill with what is in the buffer.
- if (CanFulfillRead())
- ReadInternal();
- else
- DoneRead(net::ERR_CACHE_MISS);
- } else {
- // If the request has failed, then fail the read.
- DoneRead(net::ERR_FAILED);
- }
- }
-
- // There must not be any outstanding read request.
- DCHECK(!HasPendingRead());
-
- // Notify that network response is completed.
- NotifyNetworkEvent();
-
- // We incremented the reference count when the loader was started. We balance
- // that reference here so that we get destroyed. This is also the only safe
- // place to destroy the ResourceLoaderBridge.
- bridge_.reset();
- Release();
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// BufferedResourceLoader, private
-void BufferedResourceLoader::EnableDeferIfNeeded() {
- if (!defer_allowed_)
- return;
-
- if (!deferred_ &&
- buffer_->forward_bytes() >= buffer_->forward_capacity()) {
- deferred_ = true;
-
- if (bridge_.get())
- bridge_->SetDefersLoading(true);
-
- NotifyNetworkEvent();
- }
-}
-
-void BufferedResourceLoader::DisableDeferIfNeeded() {
- if (deferred_ &&
- (!defer_allowed_ ||
- buffer_->forward_bytes() < buffer_->forward_capacity() / 2)) {
- deferred_ = false;
-
- if (bridge_.get())
- bridge_->SetDefersLoading(false);
-
- NotifyNetworkEvent();
- }
-}
-
-bool BufferedResourceLoader::CanFulfillRead() {
- // If we are reading too far in the backward direction.
- if (first_offset_ < 0 &&
- first_offset_ + static_cast<int>(buffer_->backward_bytes()) < 0)
- return false;
-
- // If the start offset is too far ahead.
- if (first_offset_ >= static_cast<int>(buffer_->forward_bytes()))
- return false;
-
- // At the point, we verified that first byte requested is within the buffer.
- // If the request has completed, then just returns with what we have now.
- if (completed_)
- return true;
-
- // If the resource request is still active, make sure the whole requested
- // range is covered.
- if (last_offset_ > static_cast<int>(buffer_->forward_bytes()))
- return false;
-
- return true;
-}
-
-bool BufferedResourceLoader::WillFulfillRead() {
- // Reading too far in the backward direction.
- if (first_offset_ < 0 &&
- first_offset_ + static_cast<int>(buffer_->backward_bytes()) < 0)
- return false;
-
- // Try to read too far ahead.
- if (last_offset_ > kForwardWaitThreshold)
- return false;
-
- // The resource request has completed, there's no way we can fulfill the
- // read request.
- if (completed_)
- return false;
-
- return true;
-}
-
-void BufferedResourceLoader::ReadInternal() {
- // Seek to the first byte requested.
- bool ret = buffer_->Seek(first_offset_);
- DCHECK(ret);
-
- // Then do the read.
- int read = static_cast<int>(buffer_->Read(read_buffer_, read_size_));
- offset_ += first_offset_ + read;
-
- // And report with what we have read.
- DoneRead(read);
-}
-
-bool BufferedResourceLoader::VerifyPartialResponse(
- const ResourceResponseInfo& info) {
- int64 first_byte_position, last_byte_position, instance_size;
- if (!info.headers->GetContentRange(&first_byte_position,
- &last_byte_position,
- &instance_size)) {
- return false;
- }
-
- if (instance_size != kPositionNotSpecified)
- instance_size_ = instance_size;
-
- if (first_byte_position_ != -1 &&
- first_byte_position_ != first_byte_position) {
- return false;
- }
-
- // TODO(hclam): I should also check |last_byte_position|, but since
- // we will never make such a request that it is ok to leave it unimplemented.
- return true;
-}
-
-void BufferedResourceLoader::DoneRead(int error) {
- read_callback_->RunWithParams(Tuple1<int>(error));
- read_callback_.reset();
- read_position_ = 0;
- read_size_ = 0;
- read_buffer_ = NULL;
- first_offset_ = 0;
- last_offset_ = 0;
-}
-
-void BufferedResourceLoader::DoneStart(int error) {
- start_callback_->RunWithParams(Tuple1<int>(error));
- start_callback_.reset();
-}
-
-void BufferedResourceLoader::NotifyNetworkEvent() {
- if (event_callback_.get())
- event_callback_->Run();
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// BufferedDataSource
BufferedDataSource::BufferedDataSource(
MessageLoop* render_loop,
- webkit_glue::MediaResourceLoaderBridgeFactory* bridge_factory)
+ WebFrame* frame)
: total_bytes_(kPositionNotSpecified),
loaded_(false),
streaming_(false),
+ frame_(frame),
single_origin_(true),
- bridge_factory_(bridge_factory),
loader_(NULL),
network_activity_(false),
initialize_callback_(NULL),
@@ -558,7 +66,7 @@ BufferedResourceLoader* BufferedDataSource::CreateResourceLoader(
int64 first_byte_position, int64 last_byte_position) {
DCHECK(MessageLoop::current() == render_loop_);
- return new BufferedResourceLoader(bridge_factory_.get(), url_,
+ return new BufferedResourceLoader(url_,
first_byte_position,
last_byte_position);
}
@@ -571,7 +79,7 @@ base::TimeDelta BufferedDataSource::GetTimeoutMilliseconds() {
}
/////////////////////////////////////////////////////////////////////////////
-// BufferedDataSource, media::MediaFilter implementation
+// media::Filter implementation.
void BufferedDataSource::Initialize(const std::string& url,
media::FilterCallback* callback) {
// Saves the url.
@@ -602,7 +110,7 @@ bool BufferedDataSource::IsUrlSupported(const std::string& url) {
GURL gurl(url);
// This data source doesn't support data:// protocol so reject it.
- return IsProtocolSupportedForMedia(gurl) && !IsDataProtocol(gurl);
+ return IsProtocolSupportedForMedia(gurl) && !gurl.SchemeIs(kDataScheme);
}
void BufferedDataSource::Stop(media::FilterCallback* callback) {
@@ -626,7 +134,7 @@ void BufferedDataSource::SetPlaybackRate(float playback_rate) {
}
/////////////////////////////////////////////////////////////////////////////
-// BufferedDataSource, media::DataSource implementation
+// media::DataSource implementation.
void BufferedDataSource::Read(int64 position, size_t size, uint8* data,
media::DataSource::ReadCallback* read_callback) {
render_loop_->PostTask(FROM_HERE,
@@ -658,20 +166,21 @@ void BufferedDataSource::Abort() {
// If we are told to abort, immediately return from any pending read
// with an error.
if (read_callback_.get()) {
- {
AutoLock auto_lock(lock_);
DoneRead_Locked(net::ERR_FAILED);
- }
- CleanupTask();
}
+
+ CleanupTask();
+ frame_ = NULL;
}
/////////////////////////////////////////////////////////////////////////////
-// BufferedDataSource, render thread tasks
+// Render thread tasks.
void BufferedDataSource::InitializeTask() {
DCHECK(MessageLoop::current() == render_loop_);
DCHECK(!loader_.get());
- DCHECK(!stopped_on_render_loop_);
+ if (stopped_on_render_loop_)
+ return;
// Kick starts the watch dog task that will handle connection timeout.
// We run the watch dog 2 times faster the actual timeout so as to catch
@@ -681,24 +190,24 @@ void BufferedDataSource::InitializeTask() {
this,
&BufferedDataSource::WatchDogTask);
- if (IsHttpProtocol(url_)) {
- // Fetch only first 1024 bytes as this usually covers the header portion
- // of a media file that gives enough information about the codecs, etc.
- // This also serve as a probe to determine server capability to serve
- // range request.
- // TODO(hclam): Do some experiments for the best approach.
- loader_ = CreateResourceLoader(0, 1024);
+ if (url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)) {
+ // Do an unbounded range request starting at the beginning. If the server
+ // responds with 200 instead of 206 we'll fall back into a streaming mode.
+ loader_ = CreateResourceLoader(0, kPositionNotSpecified);
loader_->Start(
NewCallback(this, &BufferedDataSource::HttpInitialStartCallback),
- NewCallback(this, &BufferedDataSource::NetworkEventCallback));
+ NewCallback(this, &BufferedDataSource::NetworkEventCallback),
+ frame_);
} else {
// For all other protocols, assume they support range request. We fetch
// the full range of the resource to obtain the instance size because
// we won't be served HTTP headers.
- loader_ = CreateResourceLoader(-1, -1);
+ loader_ = CreateResourceLoader(kPositionNotSpecified,
+ kPositionNotSpecified);
loader_->Start(
NewCallback(this, &BufferedDataSource::NonHttpInitialStartCallback),
- NewCallback(this, &BufferedDataSource::NetworkEventCallback));
+ NewCallback(this, &BufferedDataSource::NetworkEventCallback),
+ frame_);
}
}
@@ -706,11 +215,6 @@ void BufferedDataSource::ReadTask(
int64 position, int read_size, uint8* buffer,
media::DataSource::ReadCallback* read_callback) {
DCHECK(MessageLoop::current() == render_loop_);
-
- // If CleanupTask() was executed we should return immediately. We check this
- // variable to prevent doing any actual work after clean up was done. We do
- // not check |stop_signal_received_| because anything use of it has to be
- // within |lock_| which is not desirable.
if (stopped_on_render_loop_)
return;
@@ -731,8 +235,6 @@ void BufferedDataSource::ReadTask(
void BufferedDataSource::CleanupTask() {
DCHECK(MessageLoop::current() == render_loop_);
-
- // If we have already stopped, do nothing.
if (stopped_on_render_loop_)
return;
@@ -757,13 +259,6 @@ void BufferedDataSource::CleanupTask() {
void BufferedDataSource::RestartLoadingTask() {
DCHECK(MessageLoop::current() == render_loop_);
-
- // This variable is set in CleanupTask(). We check this and do an early
- // return. The sequence of actions which enable this conditions is:
- // 1. Stop() is called from the pipeline.
- // 2. ReadCallback() is called from the resource loader.
- // 3. CleanupTask() is executed.
- // 4. RestartLoadingTask() is executed.
if (stopped_on_render_loop_)
return;
@@ -771,16 +266,18 @@ void BufferedDataSource::RestartLoadingTask() {
if (!read_callback_.get())
return;
- loader_ = CreateResourceLoader(read_position_, -1);
+ loader_ = CreateResourceLoader(read_position_, kPositionNotSpecified);
loader_->SetAllowDefer(!media_is_paused_);
loader_->Start(
NewCallback(this, &BufferedDataSource::PartialReadStartCallback),
- NewCallback(this, &BufferedDataSource::NetworkEventCallback));
+ NewCallback(this, &BufferedDataSource::NetworkEventCallback),
+ frame_);
}
void BufferedDataSource::WatchDogTask() {
DCHECK(MessageLoop::current() == render_loop_);
- DCHECK(!stopped_on_render_loop_);
+ if (stopped_on_render_loop_)
+ return;
// We only care if there is an active read request.
if (!read_callback_.get())
@@ -802,11 +299,12 @@ void BufferedDataSource::WatchDogTask() {
// Stops the current loader and creates a new resource loader and
// retry the request.
loader_->Stop();
- loader_ = CreateResourceLoader(read_position_, -1);
+ loader_ = CreateResourceLoader(read_position_, kPositionNotSpecified);
loader_->SetAllowDefer(!media_is_paused_);
loader_->Start(
NewCallback(this, &BufferedDataSource::PartialReadStartCallback),
- NewCallback(this, &BufferedDataSource::NetworkEventCallback));
+ NewCallback(this, &BufferedDataSource::NetworkEventCallback),
+ frame_);
}
void BufferedDataSource::SetPlaybackRateTask(float playback_rate) {
@@ -829,7 +327,7 @@ void BufferedDataSource::SetPlaybackRateTask(float playback_rate) {
// prior to make this method call.
void BufferedDataSource::ReadInternal() {
DCHECK(MessageLoop::current() == render_loop_);
- DCHECK(loader_.get());
+ DCHECK(loader_);
// First we prepare the intermediate read buffer for BufferedResourceLoader
// to write to.
@@ -872,9 +370,7 @@ void BufferedDataSource::DoneInitialization_Locked() {
}
/////////////////////////////////////////////////////////////////////////////
-// BufferedDataSource, callback methods.
-// These methods are called on the render thread for the events reported by
-// BufferedResourceLoader.
+// BufferedResourceLoader callback methods.
void BufferedDataSource::HttpInitialStartCallback(int error) {
DCHECK(MessageLoop::current() == render_loop_);
DCHECK(loader_.get());
@@ -901,10 +397,12 @@ void BufferedDataSource::HttpInitialStartCallback(int error) {
// Assuming that the Range header was causing the problem. Retry without
// the Range header.
using_range_request_ = false;
- loader_ = CreateResourceLoader(-1, -1);
+ loader_ = CreateResourceLoader(kPositionNotSpecified,
+ kPositionNotSpecified);
loader_->Start(
NewCallback(this, &BufferedDataSource::HttpInitialStartCallback),
- NewCallback(this, &BufferedDataSource::NetworkEventCallback));
+ NewCallback(this, &BufferedDataSource::NetworkEventCallback),
+ frame_);
return;
}
@@ -1058,10 +556,10 @@ void BufferedDataSource::NetworkEventCallback() {
return;
bool network_activity = loader_->network_activity();
- int64 buffered_last_byte_position = loader_->GetBufferedLastBytePosition();
+ int64 buffered_position = loader_->GetBufferedPosition();
// If we get an unspecified value, return immediately.
- if (buffered_last_byte_position == kPositionNotSpecified)
+ if (buffered_position == kPositionNotSpecified)
return;
// We need to prevent calling to filter host and running the callback if
@@ -1080,7 +578,7 @@ void BufferedDataSource::NetworkEventCallback() {
network_activity_ = network_activity;
host()->SetNetworkActivity(network_activity);
}
- host()->SetBufferedBytes(buffered_last_byte_position + 1);
+ host()->SetBufferedBytes(buffered_position + 1);
}
} // namespace webkit_glue
diff --git a/webkit/glue/media/buffered_data_source.h b/webkit/glue/media/buffered_data_source.h
index 2af9e84..1c4e3fa 100644
--- a/webkit/glue/media/buffered_data_source.h
+++ b/webkit/glue/media/buffered_data_source.h
@@ -10,220 +10,18 @@
#include "base/callback.h"
#include "base/lock.h"
#include "base/scoped_ptr.h"
-#include "base/timer.h"
-#include "base/condition_variable.h"
-#include "googleurl/src/gurl.h"
-#include "media/base/filters.h"
-#include "media/base/media_format.h"
-#include "media/base/pipeline.h"
-#include "media/base/seekable_buffer.h"
-#include "net/base/completion_callback.h"
-#include "net/base/file_stream.h"
-#include "webkit/glue/media/media_resource_loader_bridge_factory.h"
-#include "webkit/glue/media/web_data_source.h"
-#include "webkit/glue/webmediaplayer_impl.h"
+#include "webkit/glue/media/buffered_resource_loader.h"
namespace webkit_glue {
-/////////////////////////////////////////////////////////////////////////////
-// BufferedResourceLoader
-// This class works inside demuxer thread and render thread. It contains a
-// resource loader bridge and does the actual resource loading. This object
-// does buffering internally, it defers the resource loading if buffer is
-// full and un-defers the resource loading if it is under buffered.
-class BufferedResourceLoader :
- public base::RefCountedThreadSafe<BufferedResourceLoader>,
- public webkit_glue::ResourceLoaderBridge::Peer {
- public:
- typedef Callback0::Type NetworkEventCallback;
-
- // |bridge_factory| - Factory to create a ResourceLoaderBridge.
- // |url| - URL for the resource to be loaded.
- // |first_byte_position| - First byte to start loading from, -1 for not
- // specified.
- // |last_byte_position| - Last byte to be loaded, -1 for not specified.
- BufferedResourceLoader(
- webkit_glue::MediaResourceLoaderBridgeFactory* bridge_factory,
- const GURL& url,
- int64 first_byte_position,
- int64 last_byte_position);
-
- // Start the resource loading with the specified URL and range.
- // This method operates in asynchronous mode. Once there's a response from the
- // server, success or fail |callback| is called with the result.
- // |callback| is called with the following values:
- // - net::OK
- // The request has started successfully.
- // - net::ERR_FAILED
- // The request has failed because of an error with the network.
- // - net::ERR_INVALID_RESPONSE
- // An invalid response is received from the server.
- // - (Anything else)
- // An error code that indicates the request has failed.
- // |event_callback| is called when the response is completed, data is
- // received, the request is suspended or resumed.
- virtual void Start(net::CompletionCallback* callback,
- NetworkEventCallback* event_callback);
-
- // Stop this loader, cancels and request and release internal buffer.
- virtual void Stop();
-
- // Reads the specified |read_size| from |position| into |buffer| and when
- // the operation is done invoke |callback| with number of bytes read or an
- // error code.
- // |callback| is called with the following values:
- // - (Anything greater than or equal 0)
- // Read was successful with the indicated number of bytes read.
- // - net::ERR_FAILED
- // The read has failed because of an error with the network.
- // - net::ERR_CACHE_MISS
- // The read was made too far away from the current buffered position.
- virtual void Read(int64 position, int read_size,
- uint8* buffer, net::CompletionCallback* callback);
-
- // Returns the position of the first byte buffered. Returns -1 if such value
- // is not available.
- virtual int64 GetBufferedFirstBytePosition();
-
- // Returns the position of the last byte buffered. Returns -1 if such value
- // is not available.
- virtual int64 GetBufferedLastBytePosition();
-
- // Sets whether deferring data is allowed or disallowed.
- virtual void SetAllowDefer(bool is_allowed);
-
- // Gets the content length in bytes of the instance after this loader has been
- // started. If this value is -1, then content length is unknown.
- virtual int64 content_length() { return content_length_; }
-
- // Gets the original size of the file requested. If this value is -1, then
- // the size is unknown.
- virtual int64 instance_size() { return instance_size_; }
-
- // Returns true if the response for this loader is a partial response.
- // It means a 206 response in HTTP/HTTPS protocol.
- virtual bool partial_response() { return partial_response_; }
-
- // Returns true if network is currently active.
- virtual bool network_activity() { return !completed_ && !deferred_; }
-
- // Returns resulting URL.
- virtual const GURL& url() { return url_; }
-
- /////////////////////////////////////////////////////////////////////////////
- // webkit_glue::ResourceLoaderBridge::Peer implementations.
- virtual void OnUploadProgress(uint64 position, uint64 size) {}
- virtual bool OnReceivedRedirect(
- const GURL& new_url,
- const webkit_glue::ResourceResponseInfo& info,
- bool* has_new_first_party_for_cookies,
- GURL* new_first_party_for_cookies);
- virtual void OnReceivedResponse(
- const webkit_glue::ResourceResponseInfo& info,
- bool content_filtered);
- virtual void OnDownloadedData(int len) {}
- virtual void OnReceivedData(const char* data, int len);
- virtual void OnCompletedRequest(
- const URLRequestStatus& status,
- const std::string& security_info,
- const base::Time& completion_time);
-
- protected:
- friend class base::RefCountedThreadSafe<BufferedResourceLoader>;
-
- virtual ~BufferedResourceLoader();
-
- private:
- friend class BufferedResourceLoaderTest;
-
- // Defer the resource loading if the buffer is full.
- void EnableDeferIfNeeded();
-
- // Disable defer loading if we are under-buffered.
- void DisableDeferIfNeeded();
-
- // Returns true if the current read request can be fulfilled by what is in
- // the buffer.
- bool CanFulfillRead();
-
- // Returns true if the current read request will be fulfilled in the future.
- bool WillFulfillRead();
-
- // Method that does the actual read and calls the |read_callbac_|, assuming
- // the request range is in |buffer_|.
- void ReadInternal();
-
- // If we have made a range request, verify the response from the server.
- bool VerifyPartialResponse(const ResourceResponseInfo& info);
-
- // Done with read. Invokes the read callback and reset parameters for the
- // read request.
- void DoneRead(int error);
-
- // Done with start. Invokes the start callback and reset it.
- void DoneStart(int error);
-
- // Calls |event_callback_| in terms of a network event.
- void NotifyNetworkEvent();
-
- bool HasPendingRead() { return read_callback_.get() != NULL; }
-
- // A sliding window of buffer.
- scoped_ptr<media::SeekableBuffer> buffer_;
-
- // True if resource loading was deferred.
- bool deferred_;
-
- // True if resource loader is allowed to defer, false otherwise.
- bool defer_allowed_;
-
- // True if resource loading has completed.
- bool completed_;
-
- // True if a range request was made.
- bool range_requested_;
-
- // True if response data received is a partial range.
- bool partial_response_;
-
- webkit_glue::MediaResourceLoaderBridgeFactory* bridge_factory_;
- GURL url_;
- int64 first_byte_position_;
- int64 last_byte_position_;
-
- // Callback method that listens to network events.
- scoped_ptr<NetworkEventCallback> event_callback_;
-
- // Members used during request start.
- scoped_ptr<net::CompletionCallback> start_callback_;
- scoped_ptr<webkit_glue::ResourceLoaderBridge> bridge_;
- int64 offset_;
- int64 content_length_;
- int64 instance_size_;
-
- // Members used during a read operation. They should be reset after each
- // read has completed or failed.
- scoped_ptr<net::CompletionCallback> read_callback_;
- int64 read_position_;
- int read_size_;
- uint8* read_buffer_;
-
- // Offsets of the requested first byte and last byte in |buffer_|. They are
- // written by VerifyRead().
- int first_offset_;
- int last_offset_;
-
- DISALLOW_COPY_AND_ASSIGN(BufferedResourceLoader);
-};
class BufferedDataSource : public WebDataSource {
public:
- BufferedDataSource(
- MessageLoop* render_loop,
- webkit_glue::MediaResourceLoaderBridgeFactory* bridge_factory);
+ BufferedDataSource(MessageLoop* render_loop,
+ WebKit::WebFrame* frame);
virtual ~BufferedDataSource();
- // media::MediaFilter implementation.
+ // media::Filter implementation.
virtual void Initialize(const std::string& url,
media::FilterCallback* callback);
virtual bool IsUrlSupported(const std::string& url);
@@ -247,7 +45,6 @@ class BufferedDataSource : public WebDataSource {
virtual void Abort();
protected:
-
// A factory method to create a BufferedResourceLoader based on the read
// parameters. We can override this file to object a mock
// BufferedResourceLoader for testing.
@@ -338,12 +135,12 @@ class BufferedDataSource : public WebDataSource {
// i.e. range request is not supported.
bool streaming_;
+ // A webframe for loading.
+ WebKit::WebFrame* frame_;
+
// True if the media resource has a single origin.
bool single_origin_;
- // A factory object to produce ResourceLoaderBridge.
- scoped_ptr<webkit_glue::MediaResourceLoaderBridgeFactory> bridge_factory_;
-
// A resource loader for the media resource.
scoped_refptr<BufferedResourceLoader> loader_;
@@ -385,7 +182,7 @@ class BufferedDataSource : public WebDataSource {
bool stop_signal_received_;
// This variable is set by CleanupTask() that indicates this object is stopped
- // on the render thread.
+ // on the render thread and work should no longer progress.
bool stopped_on_render_loop_;
// This variable is true when we are in a paused state and false when we
diff --git a/webkit/glue/media/buffered_data_source_unittest.cc b/webkit/glue/media/buffered_data_source_unittest.cc
index 81103b2..dcb11ec 100644
--- a/webkit/glue/media/buffered_data_source_unittest.cc
+++ b/webkit/glue/media/buffered_data_source_unittest.cc
@@ -4,22 +4,18 @@
#include <algorithm>
-#include "base/callback.h"
-#include "base/format_macros.h"
-#include "base/message_loop.h"
-#include "base/string_util.h"
-#include "base/stringprintf.h"
-#include "media/base/filters.h"
+#include "base/test/test_timeouts.h"
#include "media/base/mock_filter_host.h"
#include "media/base/mock_filters.h"
#include "net/base/net_errors.h"
-#include "net/http/http_response_headers.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebURLError.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebURLResponse.h"
#include "webkit/glue/media/buffered_data_source.h"
-#include "webkit/glue/media/mock_media_resource_loader_bridge_factory.h"
-#include "webkit/glue/mock_resource_loader_bridge.h"
+#include "webkit/mocks/mock_webframe.h"
using ::testing::_;
using ::testing::Assign;
+using ::testing::AtLeast;
using ::testing::DeleteArg;
using ::testing::DoAll;
using ::testing::InSequence;
@@ -49,476 +45,36 @@ enum NetworkState {
namespace webkit_glue {
-// Submit a request completed event to the resource loader due to request
-// being canceled. Pretending the event is from external.
-ACTION_P(RequestCanceled, loader) {
- URLRequestStatus status;
- status.set_status(URLRequestStatus::CANCELED);
- status.set_os_error(net::ERR_ABORTED);
- loader->OnCompletedRequest(status, "", base::Time());
-}
-
-class BufferedResourceLoaderTest : public testing::Test {
+// A mock BufferedDataSource to inject mock BufferedResourceLoader through
+// CreateResourceLoader() method.
+class MockBufferedDataSource : public BufferedDataSource {
public:
- BufferedResourceLoaderTest() {
- bridge_.reset(new StrictMock<MockResourceLoaderBridge>());
-
- for (int i = 0; i < kDataSize; ++i)
- data_[i] = i;
- }
-
- ~BufferedResourceLoaderTest() {
- if (bridge_.get())
- EXPECT_CALL(*bridge_, OnDestroy());
- EXPECT_CALL(bridge_factory_, OnDestroy());
- }
-
- void Initialize(const char* url, int first_position, int last_position) {
- gurl_ = GURL(url);
- first_position_ = first_position;
- last_position_ = last_position;
-
- loader_ = new BufferedResourceLoader(&bridge_factory_, gurl_,
- first_position_, last_position_);
- }
-
- void SetLoaderBuffer(size_t forward_capacity, size_t backward_capacity) {
- loader_->buffer_.reset(
- new media::SeekableBuffer(backward_capacity, forward_capacity));
- }
-
- void Start() {
- InSequence s;
- EXPECT_CALL(bridge_factory_,
- CreateBridge(gurl_, _, first_position_, last_position_))
- .WillOnce(Return(bridge_.get()));
- EXPECT_CALL(*bridge_, Start(loader_.get()));
- loader_->Start(
- NewCallback(this, &BufferedResourceLoaderTest::StartCallback),
- NewCallback(this, &BufferedResourceLoaderTest::NetworkCallback));
- }
-
- void FullResponse(int64 instance_size) {
- EXPECT_CALL(*this, StartCallback(net::OK));
- ResourceResponseInfo info;
- std::string header = base::StringPrintf("HTTP/1.1 200 OK\n"
- "Content-Length: %" PRId64,
- instance_size);
- replace(header.begin(), header.end(), '\n', '\0');
- info.headers = new net::HttpResponseHeaders(header);
- info.content_length = instance_size;
- loader_->OnReceivedResponse(info, false);
- EXPECT_EQ(instance_size, loader_->content_length());
- EXPECT_EQ(instance_size, loader_->instance_size());
- EXPECT_FALSE(loader_->partial_response());
- }
-
- void PartialResponse(int64 first_position, int64 last_position,
- int64 instance_size) {
- EXPECT_CALL(*this, StartCallback(net::OK));
- int64 content_length = last_position - first_position + 1;
- ResourceResponseInfo info;
- std::string header = base::StringPrintf("HTTP/1.1 206 Partial Content\n"
- "Content-Range: bytes "
- "%" PRId64 "-%" PRId64 "/%" PRId64,
- first_position,
- last_position,
- instance_size);
- replace(header.begin(), header.end(), '\n', '\0');
- info.headers = new net::HttpResponseHeaders(header);
- info.content_length = content_length;
- loader_->OnReceivedResponse(info, false);
- EXPECT_EQ(content_length, loader_->content_length());
- EXPECT_EQ(instance_size, loader_->instance_size());
- EXPECT_TRUE(loader_->partial_response());
- }
-
- void StopWhenLoad() {
- InSequence s;
- EXPECT_CALL(*bridge_, Cancel())
- .WillOnce(RequestCanceled(loader_));
- EXPECT_CALL(*bridge_, OnDestroy())
- .WillOnce(Invoke(this, &BufferedResourceLoaderTest::ReleaseBridge));
- loader_->Stop();
- }
-
- void ReleaseBridge() {
- ignore_result(bridge_.release());
- }
-
- // Helper method to write to |loader_| from |data_|.
- void WriteLoader(int position, int size) {
- EXPECT_CALL(*this, NetworkCallback())
- .RetiresOnSaturation();
- loader_->OnReceivedData(reinterpret_cast<char*>(data_ + position), size);
- }
-
- // Helper method to read from |loader_|.
- void ReadLoader(int64 position, int size, uint8* buffer) {
- loader_->Read(position, size, buffer,
- NewCallback(this, &BufferedResourceLoaderTest::ReadCallback));
- }
-
- // Verifis that data in buffer[0...size] is equal to data_[pos...pos+size].
- void VerifyBuffer(uint8* buffer, int pos, int size) {
- EXPECT_EQ(0, memcmp(buffer, data_ + pos, size));
- }
-
- // Helper method to disallow deferring in |loader_|.
- void DisallowLoaderDefer() {
- if (loader_->deferred_) {
- EXPECT_CALL(*bridge_, SetDefersLoading(false));
- EXPECT_CALL(*this, NetworkCallback());
- }
- loader_->SetAllowDefer(false);
+ MockBufferedDataSource(
+ MessageLoop* message_loop, WebFrame* frame)
+ : BufferedDataSource(message_loop, frame) {
}
- // Helper method to allow deferring in |loader_|.
- void AllowLoaderDefer() {
- loader_->SetAllowDefer(true);
+ virtual base::TimeDelta GetTimeoutMilliseconds() {
+ return base::TimeDelta::FromMilliseconds(
+ TestTimeouts::tiny_timeout_ms());
}
- MOCK_METHOD1(StartCallback, void(int error));
- MOCK_METHOD1(ReadCallback, void(int error));
- MOCK_METHOD0(NetworkCallback, void());
-
- protected:
- GURL gurl_;
- int64 first_position_;
- int64 last_position_;
-
- scoped_refptr<BufferedResourceLoader> loader_;
- StrictMock<MockMediaResourceLoaderBridgeFactory> bridge_factory_;
- scoped_ptr<StrictMock<MockResourceLoaderBridge> > bridge_;
-
- uint8 data_[kDataSize];
+ MOCK_METHOD2(CreateResourceLoader,
+ BufferedResourceLoader*(int64 first_position,
+ int64 last_position));
private:
- DISALLOW_COPY_AND_ASSIGN(BufferedResourceLoaderTest);
+ DISALLOW_COPY_AND_ASSIGN(MockBufferedDataSource);
};
-TEST_F(BufferedResourceLoaderTest, StartStop) {
- Initialize(kHttpUrl, -1, -1);
- Start();
- StopWhenLoad();
-}
-
-// Tests that HTTP header is missing in the response.
-TEST_F(BufferedResourceLoaderTest, MissingHttpHeader) {
- Initialize(kHttpUrl, -1, -1);
- Start();
-
- EXPECT_CALL(*this, StartCallback(net::ERR_INVALID_RESPONSE));
- EXPECT_CALL(*bridge_, Cancel())
- .WillOnce(RequestCanceled(loader_));
- EXPECT_CALL(*bridge_, OnDestroy())
- .WillOnce(Invoke(this, &BufferedResourceLoaderTest::ReleaseBridge));
-
- ResourceResponseInfo info;
- loader_->OnReceivedResponse(info, false);
-}
-
-// Tests that a bad HTTP response is recived, e.g. file not found.
-TEST_F(BufferedResourceLoaderTest, BadHttpResponse) {
- Initialize(kHttpUrl, -1, -1);
- Start();
-
- EXPECT_CALL(*this, StartCallback(net::ERR_FAILED));
- EXPECT_CALL(*bridge_, Cancel())
- .WillOnce(RequestCanceled(loader_));
- EXPECT_CALL(*bridge_, OnDestroy())
- .WillOnce(Invoke(this, &BufferedResourceLoaderTest::ReleaseBridge));
-
- ResourceResponseInfo info;
- info.headers = new net::HttpResponseHeaders("HTTP/1.1 404 Not Found\n");
- loader_->OnReceivedResponse(info, false);
-}
-
-// Tests that partial content is requested but not fulfilled.
-TEST_F(BufferedResourceLoaderTest, NotPartialResponse) {
- Initialize(kHttpUrl, 100, -1);
- Start();
- FullResponse(1024);
- StopWhenLoad();
-}
-
-// Tests that a 200 response is received.
-TEST_F(BufferedResourceLoaderTest, FullResponse) {
- Initialize(kHttpUrl, -1, -1);
- Start();
- FullResponse(1024);
- StopWhenLoad();
-}
-
-// Tests that a partial content response is received.
-TEST_F(BufferedResourceLoaderTest, PartialResponse) {
- Initialize(kHttpUrl, 100, 200);
- Start();
- PartialResponse(100, 200, 1024);
- StopWhenLoad();
-}
-
-// Tests that an invalid partial response is received.
-TEST_F(BufferedResourceLoaderTest, InvalidPartialResponse) {
- Initialize(kHttpUrl, 0, 10);
- Start();
-
- EXPECT_CALL(*this, StartCallback(net::ERR_INVALID_RESPONSE));
- EXPECT_CALL(*bridge_, Cancel())
- .WillOnce(RequestCanceled(loader_));
- EXPECT_CALL(*bridge_, OnDestroy())
- .WillOnce(Invoke(this, &BufferedResourceLoaderTest::ReleaseBridge));
-
- ResourceResponseInfo info;
- std::string header = base::StringPrintf("HTTP/1.1 206 Partial Content\n"
- "Content-Range: bytes %d-%d/%d",
- 1, 10, 1024);
- replace(header.begin(), header.end(), '\n', '\0');
- info.headers = new net::HttpResponseHeaders(header);
- info.content_length = 10;
- loader_->OnReceivedResponse(info, false);
-}
-
-// Tests the logic of sliding window for data buffering and reading.
-TEST_F(BufferedResourceLoaderTest, BufferAndRead) {
- Initialize(kHttpUrl, 10, 29);
- Start();
- PartialResponse(10, 29, 30);
-
- uint8 buffer[10];
- InSequence s;
-
- // Writes 10 bytes and read them back.
- WriteLoader(10, 10);
- EXPECT_CALL(*this, ReadCallback(10));
- ReadLoader(10, 10, buffer);
- VerifyBuffer(buffer, 10, 10);
-
- // Writes 10 bytes and read 2 times.
- WriteLoader(20, 10);
- EXPECT_CALL(*this, ReadCallback(5));
- ReadLoader(20, 5, buffer);
- VerifyBuffer(buffer, 20, 5);
- EXPECT_CALL(*this, ReadCallback(5));
- ReadLoader(25, 5, buffer);
- VerifyBuffer(buffer, 25, 5);
-
- // Read backward within buffer.
- EXPECT_CALL(*this, ReadCallback(10));
- ReadLoader(10, 10, buffer);
- VerifyBuffer(buffer, 10, 10);
-
- // Read backward outside buffer.
- EXPECT_CALL(*this, ReadCallback(net::ERR_CACHE_MISS));
- ReadLoader(9, 10, buffer);
-
- // Response has completed.
- EXPECT_CALL(*this, NetworkCallback());
- EXPECT_CALL(*bridge_, OnDestroy())
- .WillOnce(Invoke(this, &BufferedResourceLoaderTest::ReleaseBridge));
- URLRequestStatus status;
- status.set_status(URLRequestStatus::SUCCESS);
- loader_->OnCompletedRequest(status, "", base::Time());
-
- // Try to read 10 from position 25 will just return with 5 bytes.
- EXPECT_CALL(*this, ReadCallback(5));
- ReadLoader(25, 10, buffer);
- VerifyBuffer(buffer, 25, 5);
-
- // Try to read outside buffered range after request has completed.
- EXPECT_CALL(*this, ReadCallback(net::ERR_CACHE_MISS));
- ReadLoader(5, 10, buffer);
-
- // Try to read beyond the instance size.
- EXPECT_CALL(*this, ReadCallback(0));
- ReadLoader(30, 10, buffer);
-}
-
-TEST_F(BufferedResourceLoaderTest, ReadOutsideBuffer) {
- Initialize(kHttpUrl, 10, 0x00FFFFFF);
- Start();
- PartialResponse(10, 0x00FFFFFF, 0x01000000);
-
- uint8 buffer[10];
- InSequence s;
-
- // Read very far aheard will get a cache miss.
- EXPECT_CALL(*this, ReadCallback(net::ERR_CACHE_MISS));
- ReadLoader(0x00FFFFFF, 1, buffer);
-
- // The following call will not call ReadCallback() because it is waiting for
- // data to arrive.
- ReadLoader(10, 10, buffer);
-
- // Writing to loader will fulfill the read request.
- EXPECT_CALL(*this, ReadCallback(10));
- WriteLoader(10, 20);
- VerifyBuffer(buffer, 10, 10);
-
- // The following call cannot be fulfilled now.
- ReadLoader(25, 10, buffer);
-
- EXPECT_CALL(*this, ReadCallback(5));
- EXPECT_CALL(*this, NetworkCallback());
- EXPECT_CALL(*bridge_, OnDestroy())
- .WillOnce(Invoke(this, &BufferedResourceLoaderTest::ReleaseBridge));
- URLRequestStatus status;
- status.set_status(URLRequestStatus::SUCCESS);
- loader_->OnCompletedRequest(status, "", base::Time());
-}
-
-TEST_F(BufferedResourceLoaderTest, RequestFailedWhenRead) {
- Initialize(kHttpUrl, 10, 29);
- Start();
- PartialResponse(10, 29, 30);
-
- uint8 buffer[10];
- InSequence s;
-
- ReadLoader(10, 10, buffer);
- EXPECT_CALL(*this, ReadCallback(net::ERR_FAILED));
- EXPECT_CALL(*this, NetworkCallback());
- EXPECT_CALL(*bridge_, OnDestroy())
- .WillOnce(Invoke(this, &BufferedResourceLoaderTest::ReleaseBridge));
- URLRequestStatus status;
- status.set_status(URLRequestStatus::FAILED);
- loader_->OnCompletedRequest(status, "", base::Time());
-}
-
-// Tests the logic of caching data to disk when media is paused.
-TEST_F(BufferedResourceLoaderTest, AllowDefer_NoDataReceived) {
- Initialize(kHttpUrl, 10, 99);
- SetLoaderBuffer(10, 20);
- Start();
- PartialResponse(10, 99, 100);
-
- // Start in undeferred state, then disallow defer, then allow defer
- // without receiving data in between.
- DisallowLoaderDefer();
- AllowLoaderDefer();
- StopWhenLoad();
-}
-
-TEST_F(BufferedResourceLoaderTest, AllowDefer_ReadSameWindow) {
- Initialize(kHttpUrl, 10, 99);
- SetLoaderBuffer(10, 20);
- Start();
- PartialResponse(10, 99, 100);
-
- uint8 buffer[10];
-
- // Start in undeferred state, disallow defer, receive data but don't shift
- // buffer window, then allow defer and read.
- DisallowLoaderDefer();
- WriteLoader(10, 10);
- AllowLoaderDefer();
-
- EXPECT_CALL(*this, ReadCallback(10));
- ReadLoader(10, 10, buffer);
- VerifyBuffer(buffer, 10, 10);
- StopWhenLoad();
-}
-
-TEST_F(BufferedResourceLoaderTest, AllowDefer_ReadPastWindow) {
- Initialize(kHttpUrl, 10, 99);
- SetLoaderBuffer(10, 20);
- Start();
- PartialResponse(10, 99, 100);
-
- uint8 buffer[10];
-
- // Not deferred, disallow defer, received data and shift buffer window,
- // allow defer, then read in area outside of buffer window.
- DisallowLoaderDefer();
- WriteLoader(10, 10);
- WriteLoader(20, 50);
- AllowLoaderDefer();
-
- EXPECT_CALL(*this, ReadCallback(net::ERR_CACHE_MISS));
- ReadLoader(10, 10, buffer);
- StopWhenLoad();
-}
-
-TEST_F(BufferedResourceLoaderTest, AllowDefer_DeferredNoDataReceived) {
- Initialize(kHttpUrl, 10, 99);
- SetLoaderBuffer(10, 20);
- Start();
- PartialResponse(10, 99, 100);
-
- uint8 buffer[10];
-
- // Start in deferred state, then disallow defer, receive no data, and
- // allow defer and read.
- EXPECT_CALL(*bridge_, SetDefersLoading(true));
- EXPECT_CALL(*this, NetworkCallback());
- WriteLoader(10, 40);
-
- DisallowLoaderDefer();
- AllowLoaderDefer();
-
- EXPECT_CALL(*this, ReadCallback(10));
- ReadLoader(20, 10, buffer);
- VerifyBuffer(buffer, 20, 10);
- StopWhenLoad();
-}
-
-TEST_F(BufferedResourceLoaderTest, AllowDefer_DeferredReadSameWindow) {
- Initialize(kHttpUrl, 10, 99);
- SetLoaderBuffer(10, 20);
- Start();
- PartialResponse(10, 99, 100);
-
- uint8 buffer[10];
-
- // Start in deferred state, disallow defer, receive data and shift buffer
- // window, allow defer, and read in a place that's still in the window.
- EXPECT_CALL(*bridge_, SetDefersLoading(true));
- EXPECT_CALL(*this, NetworkCallback());
- WriteLoader(10, 30);
-
- DisallowLoaderDefer();
- WriteLoader(40, 5);
- AllowLoaderDefer();
-
- EXPECT_CALL(*this, ReadCallback(10));
- ReadLoader(20, 10, buffer);
- VerifyBuffer(buffer, 20, 10);
- StopWhenLoad();
-}
-
-TEST_F(BufferedResourceLoaderTest, AllowDefer_DeferredReadPastWindow) {
- Initialize(kHttpUrl, 10, 99);
- SetLoaderBuffer(10, 20);
- Start();
- PartialResponse(10, 99, 100);
-
- uint8 buffer[10];
-
- // Start in deferred state, disallow defer, receive data and shift buffer
- // window, allow defer, and read outside of the buffer window.
- EXPECT_CALL(*bridge_, SetDefersLoading(true));
- EXPECT_CALL(*this, NetworkCallback());
- WriteLoader(10, 40);
-
- DisallowLoaderDefer();
- WriteLoader(50, 20);
- WriteLoader(70, 40);
- AllowLoaderDefer();
-
- EXPECT_CALL(*this, ReadCallback(net::ERR_CACHE_MISS));
- ReadLoader(20, 5, buffer);
- StopWhenLoad();
-}
-
-// TODO(hclam): add unit test for defer loading.
-
class MockBufferedResourceLoader : public BufferedResourceLoader {
public:
- MockBufferedResourceLoader() : BufferedResourceLoader(NULL, GURL(), 0, 0) {
+ MockBufferedResourceLoader() : BufferedResourceLoader(GURL(), 0, 0) {
}
- MOCK_METHOD2(Start, void(net::CompletionCallback* read_callback,
- NetworkEventCallback* network_callback));
+ MOCK_METHOD3(Start, void(net::CompletionCallback* read_callback,
+ NetworkEventCallback* network_callback,
+ WebFrame* frame));
MOCK_METHOD0(Stop, void());
MOCK_METHOD4(Read, void(int64 position, int read_size, uint8* buffer,
net::CompletionCallback* callback));
@@ -536,33 +92,10 @@ class MockBufferedResourceLoader : public BufferedResourceLoader {
DISALLOW_COPY_AND_ASSIGN(MockBufferedResourceLoader);
};
-// A mock BufferedDataSource to inject mock BufferedResourceLoader through
-// CreateResourceLoader() method.
-class MockBufferedDataSource : public BufferedDataSource {
- public:
- MockBufferedDataSource(
- MessageLoop* message_loop, MediaResourceLoaderBridgeFactory* factory)
- : BufferedDataSource(message_loop, factory) {
- }
-
- virtual base::TimeDelta GetTimeoutMilliseconds() {
- // It is 100 ms because we don't want the test to run too long.
- return base::TimeDelta::FromMilliseconds(100);
- }
-
- MOCK_METHOD2(CreateResourceLoader, BufferedResourceLoader*(
- int64 first_position, int64 last_position));
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MockBufferedDataSource);
-};
-
class BufferedDataSourceTest : public testing::Test {
public:
BufferedDataSourceTest() {
message_loop_ = MessageLoop::current();
- bridge_factory_.reset(
- new StrictMock<MockMediaResourceLoaderBridgeFactory>());
// Prepare test data.
for (size_t i = 0; i < sizeof(data_); ++i) {
@@ -571,20 +104,14 @@ class BufferedDataSourceTest : public testing::Test {
}
virtual ~BufferedDataSourceTest() {
- if (data_source_) {
- // Release the bridge factory because we don't own it.
- // Expects bridge factory to be destroyed along with data source.
- EXPECT_CALL(*bridge_factory_, OnDestroy())
- .WillOnce(Invoke(this,
- &BufferedDataSourceTest::ReleaseBridgeFactory));
- }
+ ignore_result(frame_.release());
}
void ExpectCreateAndStartResourceLoader(int start_error) {
EXPECT_CALL(*data_source_, CreateResourceLoader(_, _))
.WillOnce(Return(loader_.get()));
- EXPECT_CALL(*loader_, Start(NotNull(), NotNull()))
+ EXPECT_CALL(*loader_, Start(NotNull(), NotNull(), NotNull()))
.WillOnce(
DoAll(Assign(&error_, start_error),
Invoke(this,
@@ -597,15 +124,10 @@ class BufferedDataSourceTest : public testing::Test {
// Saves the url first.
gurl_ = GURL(url);
- media::MediaFormat url_format;
- url_format.SetAsString(media::MediaFormat::kMimeType,
- media::mime_type::kURL);
- url_format.SetAsString(media::MediaFormat::kURL, url);
- data_source_ = new MockBufferedDataSource(MessageLoop::current(),
- bridge_factory_.get());
- CHECK(data_source_);
+ frame_.reset(new NiceMock<MockWebFrame>());
- // There is no need to provide a message loop to data source.
+ data_source_ = new MockBufferedDataSource(MessageLoop::current(),
+ frame_.get());
data_source_->set_host(&host_);
scoped_refptr<NiceMock<MockBufferedResourceLoader> > first_loader(
@@ -631,7 +153,7 @@ class BufferedDataSourceTest : public testing::Test {
// Replace loader_ with a new instance.
loader_ = new NiceMock<MockBufferedResourceLoader>();
- // Create and start Make sure Start() is called the new loader.
+ // Create and start. Make sure Start() is called on the new loader.
ExpectCreateAndStartResourceLoader(net::OK);
// Update initialization variable since we know the second loader will
@@ -705,13 +227,10 @@ class BufferedDataSourceTest : public testing::Test {
message_loop_->RunAllPending();
}
- void ReleaseBridgeFactory() {
- ignore_result(bridge_factory_.release());
- }
-
void InvokeStartCallback(
net::CompletionCallback* callback,
- BufferedResourceLoader::NetworkEventCallback* network_callback) {
+ BufferedResourceLoader::NetworkEventCallback* network_callback,
+ WebFrame* frame) {
callback->RunWithParams(Tuple1<int>(error_));
delete callback;
// TODO(hclam): Save this callback.
@@ -790,7 +309,7 @@ class BufferedDataSourceTest : public testing::Test {
.WillOnce(Return(new_loader));
// 3. Then the new loader will be started.
- EXPECT_CALL(*new_loader, Start(NotNull(), NotNull()))
+ EXPECT_CALL(*new_loader, Start(NotNull(), NotNull(), NotNull()))
.WillOnce(DoAll(Assign(&error_, net::OK),
Invoke(this,
&BufferedDataSourceTest::InvokeStartCallback)));
@@ -856,7 +375,7 @@ class BufferedDataSourceTest : public testing::Test {
// 3. Then the new loader will be started and respond to queries about
// whether this is a partial response using the value of the previous
// loader.
- EXPECT_CALL(*new_loader, Start(NotNull(), NotNull()))
+ EXPECT_CALL(*new_loader, Start(NotNull(), NotNull(), NotNull()))
.WillOnce(DoAll(Assign(&error_, net::OK),
Invoke(this,
&BufferedDataSourceTest::InvokeStartCallback)));
@@ -889,10 +408,9 @@ class BufferedDataSourceTest : public testing::Test {
MOCK_METHOD1(ReadCallback, void(size_t size));
- scoped_ptr<StrictMock<MockMediaResourceLoaderBridgeFactory> >
- bridge_factory_;
scoped_refptr<NiceMock<MockBufferedResourceLoader> > loader_;
scoped_refptr<MockBufferedDataSource> data_source_;
+ scoped_ptr<NiceMock<MockWebFrame> > frame_;
StrictMock<media::MockFilterHost> host_;
GURL gurl_;
diff --git a/webkit/glue/media/buffered_resource_loader.cc b/webkit/glue/media/buffered_resource_loader.cc
new file mode 100644
index 0000000..61aac72
--- /dev/null
+++ b/webkit/glue/media/buffered_resource_loader.cc
@@ -0,0 +1,578 @@
+// 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.
+
+#include "webkit/glue/media/buffered_resource_loader.h"
+
+#include "base/format_macros.h"
+#include "base/string_util.h"
+#include "net/base/net_errors.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebKit.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebKitClient.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebURLError.h"
+#include "webkit/glue/multipart_response_delegate.h"
+#include "webkit/glue/webkit_glue.h"
+
+using WebKit::WebFrame;
+using WebKit::WebString;
+using WebKit::WebURLError;
+using WebKit::WebURLLoader;
+using WebKit::WebURLRequest;
+using WebKit::WebURLResponse;
+using webkit_glue::MultipartResponseDelegate;
+
+namespace {
+
+const int kHttpOK = 200;
+const int kHttpPartialContent = 206;
+
+// Define the number of bytes in a megabyte.
+const size_t kMegabyte = 1024 * 1024;
+
+// Backward capacity of the buffer, by default 2MB.
+const size_t kBackwardCapcity = 2 * kMegabyte;
+
+// Forward capacity of the buffer, by default 10MB.
+const size_t kForwardCapacity = 10 * kMegabyte;
+
+// The threshold of bytes that we should wait until the data arrives in the
+// future instead of restarting a new connection. This number is defined in the
+// number of bytes, we should determine this value from typical connection speed
+// and amount of time for a suitable wait. Now I just make a guess for this
+// number to be 2MB.
+// TODO(hclam): determine a better value for this.
+const int kForwardWaitThreshold = 2 * kMegabyte;
+
+} // namespace
+
+namespace webkit_glue {
+
+BufferedResourceLoader::BufferedResourceLoader(
+ const GURL& url,
+ int64 first_byte_position,
+ int64 last_byte_position)
+ : buffer_(new media::SeekableBuffer(kBackwardCapcity, kForwardCapacity)),
+ deferred_(false),
+ defer_allowed_(true),
+ completed_(false),
+ range_requested_(false),
+ partial_response_(false),
+ url_(url),
+ first_byte_position_(first_byte_position),
+ last_byte_position_(last_byte_position),
+ start_callback_(NULL),
+ offset_(0),
+ content_length_(kPositionNotSpecified),
+ instance_size_(kPositionNotSpecified),
+ read_callback_(NULL),
+ read_position_(0),
+ read_size_(0),
+ read_buffer_(NULL),
+ first_offset_(0),
+ last_offset_(0),
+ keep_test_loader_(false) {
+}
+
+BufferedResourceLoader::~BufferedResourceLoader() {
+ if (!completed_ && url_loader_.get())
+ url_loader_->cancel();
+}
+
+void BufferedResourceLoader::Start(net::CompletionCallback* start_callback,
+ NetworkEventCallback* event_callback,
+ WebFrame* frame) {
+ // Make sure we have not started.
+ DCHECK(!start_callback_.get());
+ DCHECK(!event_callback_.get());
+ DCHECK(start_callback);
+ DCHECK(event_callback);
+ CHECK(frame);
+
+ start_callback_.reset(start_callback);
+ event_callback_.reset(event_callback);
+
+ if (first_byte_position_ != kPositionNotSpecified) {
+ range_requested_ = true;
+ // TODO(hclam): server may not support range request so |offset_| may not
+ // equal to |first_byte_position_|.
+ offset_ = first_byte_position_;
+ }
+
+ // Increment the reference count right before we start the request. This
+ // reference will be release when this request has ended.
+ AddRef();
+
+ // Prepare the request.
+ WebURLRequest request(url_);
+ request.setTargetType(WebURLRequest::TargetIsMedia);
+ request.setHTTPHeaderField(WebString::fromUTF8("Range"),
+ WebString::fromUTF8(GenerateHeaders(
+ first_byte_position_,
+ last_byte_position_)));
+ frame->setReferrerForRequest(request, WebKit::WebURL());
+
+ // This flag is for unittests as we don't want to reset |url_loader|
+ if (!keep_test_loader_)
+ url_loader_.reset(frame->createAssociatedURLLoader());
+
+ // Start the resource loading.
+ url_loader_->loadAsynchronously(request, this);
+}
+
+void BufferedResourceLoader::Stop() {
+ // Reset callbacks.
+ start_callback_.reset();
+ event_callback_.reset();
+ read_callback_.reset();
+
+ // Use the internal buffer to signal that we have been stopped.
+ // TODO(hclam): Not so pretty to do this.
+ if (!buffer_.get())
+ return;
+
+ // Destroy internal buffer.
+ buffer_.reset();
+
+ if (url_loader_.get()) {
+ if (deferred_)
+ url_loader_->setDefersLoading(false);
+ deferred_ = false;
+
+ if (!completed_) {
+ url_loader_->cancel();
+ completed_ = true;
+ }
+ }
+}
+
+void BufferedResourceLoader::Read(int64 position,
+ int read_size,
+ uint8* buffer,
+ net::CompletionCallback* read_callback) {
+ DCHECK(!read_callback_.get());
+ DCHECK(buffer_.get());
+ DCHECK(read_callback);
+ DCHECK(buffer);
+
+ // Save the parameter of reading.
+ read_callback_.reset(read_callback);
+ read_position_ = position;
+ read_size_ = read_size;
+ read_buffer_ = buffer;
+
+ // If read position is beyond the instance size, we cannot read there.
+ if (instance_size_ != kPositionNotSpecified &&
+ instance_size_ <= read_position_) {
+ DoneRead(0);
+ return;
+ }
+
+ // Make sure |offset_| and |read_position_| does not differ by a large
+ // amount.
+ if (read_position_ > offset_ + kint32max ||
+ read_position_ < offset_ + kint32min) {
+ DoneRead(net::ERR_CACHE_MISS);
+ return;
+ }
+
+ // Prepare the parameters.
+ first_offset_ = static_cast<int>(read_position_ - offset_);
+ last_offset_ = first_offset_ + read_size_;
+
+ // If we can serve the request now, do the actual read.
+ if (CanFulfillRead()) {
+ ReadInternal();
+ DisableDeferIfNeeded();
+ return;
+ }
+
+ // If we expected the read request to be fulfilled later, returns
+ // immediately and let more data to flow in.
+ if (WillFulfillRead())
+ return;
+
+ // Make a callback to report failure.
+ DoneRead(net::ERR_CACHE_MISS);
+}
+
+int64 BufferedResourceLoader::GetBufferedPosition() {
+ if (buffer_.get())
+ return offset_ + static_cast<int>(buffer_->forward_bytes()) - 1;
+ return kPositionNotSpecified;
+}
+
+void BufferedResourceLoader::SetAllowDefer(bool is_allowed) {
+ defer_allowed_ = is_allowed;
+ DisableDeferIfNeeded();
+}
+
+int64 BufferedResourceLoader::content_length() {
+ return content_length_;
+}
+
+int64 BufferedResourceLoader::instance_size() {
+ return instance_size_;
+}
+
+bool BufferedResourceLoader::partial_response() {
+ return partial_response_;
+}
+
+bool BufferedResourceLoader::network_activity() {
+ return !completed_ && !deferred_;
+}
+
+const GURL& BufferedResourceLoader::url() {
+ return url_;
+}
+
+void BufferedResourceLoader::SetURLLoaderForTest(WebURLLoader* mock_loader) {
+ url_loader_.reset(mock_loader);
+ keep_test_loader_ = true;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// WebKit::WebURLLoaderClient implementation.
+void BufferedResourceLoader::willSendRequest(
+ WebURLLoader* loader,
+ WebURLRequest& newRequest,
+ const WebURLResponse& redirectResponse) {
+
+ // The load may have been stopped and |start_callback| is destroyed.
+ // In this case we shouldn't do anything.
+ if (!start_callback_.get()) {
+ // Set the url in the request to an invalid value (empty url).
+ newRequest.setURL(WebKit::WebURL());
+ return;
+ }
+
+ if (!IsProtocolSupportedForMedia(newRequest.url())) {
+ // Set the url in the request to an invalid value (empty url).
+ newRequest.setURL(WebKit::WebURL());
+ DoneStart(net::ERR_ADDRESS_INVALID);
+ Stop();
+ return;
+ }
+
+ url_ = newRequest.url();
+}
+
+void BufferedResourceLoader::didSendData(
+ WebURLLoader* loader,
+ unsigned long long bytes_sent,
+ unsigned long long total_bytes_to_be_sent) {
+ NOTIMPLEMENTED();
+}
+
+void BufferedResourceLoader::didReceiveResponse(
+ WebURLLoader* loader,
+ const WebURLResponse& response) {
+
+ // The loader may have been stopped and |start_callback| is destroyed.
+ // In this case we shouldn't do anything.
+ if (!start_callback_.get())
+ return;
+
+ // We make a strong assumption that when we reach here we have either
+ // received a response from HTTP/HTTPS protocol or the request was
+ // successful (in particular range request). So we only verify the partial
+ // response for HTTP and HTTPS protocol.
+ if (url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)) {
+ int error = net::OK;
+
+ if (response.httpStatusCode() == kHttpPartialContent)
+ partial_response_ = true;
+
+ if (range_requested_ && partial_response_) {
+ // If we have verified the partial response and it is correct, we will
+ // return net::OK.
+ if (!VerifyPartialResponse(response))
+ error = net::ERR_INVALID_RESPONSE;
+ } else if (response.httpStatusCode() != kHttpOK) {
+ // We didn't request a range but server didn't reply with "200 OK".
+ error = net::ERR_FAILED;
+ }
+
+ if (error != net::OK) {
+ DoneStart(error);
+ Stop();
+ return;
+ }
+ } else {
+ // For any protocol other than HTTP and HTTPS, assume range request is
+ // always fulfilled.
+ partial_response_ = range_requested_;
+ }
+
+ // Expected content length can be |kPositionNotSpecified|, in that case
+ // |content_length_| is not specified and this is a streaming response.
+ content_length_ = response.expectedContentLength();
+
+ // If we have not requested a range, then the size of the instance is equal
+ // to the content length.
+ if (!partial_response_)
+ instance_size_ = content_length_;
+
+ // Calls with a successful response.
+ DoneStart(net::OK);
+}
+
+void BufferedResourceLoader::didReceiveData(
+ WebURLLoader* loader,
+ const char* data,
+ int data_length) {
+ DCHECK(!completed_);
+ DCHECK_GT(data_length, 0);
+
+ // If this loader has been stopped, |buffer_| would be destroyed.
+ // In this case we shouldn't do anything.
+ if (!buffer_.get())
+ return;
+
+ // Writes more data to |buffer_|.
+ buffer_->Append(reinterpret_cast<const uint8*>(data), data_length);
+
+ // If there is an active read request, try to fulfill the request.
+ if (HasPendingRead() && CanFulfillRead()) {
+ ReadInternal();
+ } else if (!defer_allowed_) {
+ // If we're not allowed to defer, slide the buffer window forward instead
+ // of deferring.
+ if (buffer_->forward_bytes() > buffer_->forward_capacity()) {
+ size_t excess = buffer_->forward_bytes() - buffer_->forward_capacity();
+ bool success = buffer_->Seek(excess);
+ DCHECK(success);
+ offset_ += first_offset_ + excess;
+ }
+ }
+
+ // At last see if the buffer is full and we need to defer the downloading.
+ EnableDeferIfNeeded();
+
+ // Notify that we have received some data.
+ NotifyNetworkEvent();
+}
+
+void BufferedResourceLoader::didDownloadData(
+ WebKit::WebURLLoader* loader,
+ int dataLength) {
+ NOTIMPLEMENTED();
+}
+
+void BufferedResourceLoader::didReceiveCachedMetadata(
+ WebURLLoader* loader,
+ const char* data,
+ int data_length) {
+ NOTIMPLEMENTED();
+}
+
+void BufferedResourceLoader::didFinishLoading(
+ WebURLLoader* loader,
+ double finishTime) {
+ DCHECK(!completed_);
+ completed_ = true;
+
+ // If there is a start callback, calls it.
+ if (start_callback_.get()) {
+ DoneStart(net::OK);
+ }
+
+ // If there is a pending read but the request has ended, returns with what
+ // we have.
+ if (HasPendingRead()) {
+ // Make sure we have a valid buffer before we satisfy a read request.
+ DCHECK(buffer_.get());
+
+ // Try to fulfill with what is in the buffer.
+ if (CanFulfillRead())
+ ReadInternal();
+ else
+ DoneRead(net::ERR_CACHE_MISS);
+ }
+
+ // There must not be any outstanding read request.
+ DCHECK(!HasPendingRead());
+
+ // Notify that network response is completed.
+ NotifyNetworkEvent();
+
+ url_loader_.reset();
+ Release();
+}
+
+void BufferedResourceLoader::didFail(
+ WebURLLoader* loader,
+ const WebURLError& error) {
+ DCHECK(!completed_);
+ completed_ = true;
+
+ // If there is a start callback, calls it.
+ if (start_callback_.get()) {
+ DoneStart(error.reason);
+ }
+
+ // If there is a pending read but the request failed, return with the
+ // reason for the error.
+ if (HasPendingRead()) {
+ DoneRead(error.reason);
+ }
+
+ // Notify that network response is completed.
+ NotifyNetworkEvent();
+
+ url_loader_.reset();
+ Release();
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Helper methods.
+void BufferedResourceLoader::EnableDeferIfNeeded() {
+ if (!defer_allowed_)
+ return;
+
+ if (!deferred_ &&
+ buffer_->forward_bytes() >= buffer_->forward_capacity()) {
+ deferred_ = true;
+
+ if (url_loader_.get())
+ url_loader_->setDefersLoading(true);
+
+ NotifyNetworkEvent();
+ }
+}
+
+void BufferedResourceLoader::DisableDeferIfNeeded() {
+ if (deferred_ &&
+ (!defer_allowed_ ||
+ buffer_->forward_bytes() < buffer_->forward_capacity() / 2)) {
+ deferred_ = false;
+
+ if (url_loader_.get())
+ url_loader_->setDefersLoading(false);
+
+ NotifyNetworkEvent();
+ }
+}
+
+bool BufferedResourceLoader::CanFulfillRead() {
+ // If we are reading too far in the backward direction.
+ if (first_offset_ < 0 &&
+ first_offset_ + static_cast<int>(buffer_->backward_bytes()) < 0)
+ return false;
+
+ // If the start offset is too far ahead.
+ if (first_offset_ >= static_cast<int>(buffer_->forward_bytes()))
+ return false;
+
+ // At the point, we verified that first byte requested is within the buffer.
+ // If the request has completed, then just returns with what we have now.
+ if (completed_)
+ return true;
+
+ // If the resource request is still active, make sure the whole requested
+ // range is covered.
+ if (last_offset_ > static_cast<int>(buffer_->forward_bytes()))
+ return false;
+
+ return true;
+}
+
+bool BufferedResourceLoader::WillFulfillRead() {
+ // Reading too far in the backward direction.
+ if (first_offset_ < 0 &&
+ first_offset_ + static_cast<int>(buffer_->backward_bytes()) < 0)
+ return false;
+
+ // Try to read too far ahead.
+ if (last_offset_ > kForwardWaitThreshold)
+ return false;
+
+ // The resource request has completed, there's no way we can fulfill the
+ // read request.
+ if (completed_)
+ return false;
+
+ return true;
+}
+
+void BufferedResourceLoader::ReadInternal() {
+ // Seek to the first byte requested.
+ bool ret = buffer_->Seek(first_offset_);
+ DCHECK(ret);
+
+ // Then do the read.
+ int read = static_cast<int>(buffer_->Read(read_buffer_, read_size_));
+ offset_ += first_offset_ + read;
+
+ // And report with what we have read.
+ DoneRead(read);
+}
+
+bool BufferedResourceLoader::VerifyPartialResponse(
+ const WebURLResponse& response) {
+ int first_byte_position, last_byte_position, instance_size;
+
+ if (!MultipartResponseDelegate::ReadContentRanges(response,
+ &first_byte_position,
+ &last_byte_position,
+ &instance_size)) {
+ return false;
+ }
+
+ if (instance_size != kPositionNotSpecified) {
+ instance_size_ = instance_size;
+ }
+
+ if (first_byte_position_ != kPositionNotSpecified &&
+ first_byte_position_ != first_byte_position) {
+ return false;
+ }
+
+ // TODO(hclam): I should also check |last_byte_position|, but since
+ // we will never make such a request that it is ok to leave it unimplemented.
+ return true;
+}
+
+std::string BufferedResourceLoader::GenerateHeaders(
+ int64 first_byte_position,
+ int64 last_byte_position) {
+ // Construct the value for the range header.
+ std::string header;
+ if (first_byte_position > kPositionNotSpecified &&
+ last_byte_position > kPositionNotSpecified) {
+ if (first_byte_position <= last_byte_position) {
+ header = base::StringPrintf("bytes=%" PRId64 "-%" PRId64,
+ first_byte_position,
+ last_byte_position);
+ }
+ } else if (first_byte_position > kPositionNotSpecified) {
+ header = base::StringPrintf("bytes=%" PRId64 "-",
+ first_byte_position);
+ } else if (last_byte_position > kPositionNotSpecified) {
+ NOTIMPLEMENTED() << "Suffix range not implemented";
+ }
+ return header;
+}
+
+void BufferedResourceLoader::DoneRead(int error) {
+ read_callback_->RunWithParams(Tuple1<int>(error));
+ read_callback_.reset();
+ read_position_ = 0;
+ read_size_ = 0;
+ read_buffer_ = NULL;
+ first_offset_ = 0;
+ last_offset_ = 0;
+}
+
+void BufferedResourceLoader::DoneStart(int error) {
+ start_callback_->RunWithParams(Tuple1<int>(error));
+ start_callback_.reset();
+}
+
+void BufferedResourceLoader::NotifyNetworkEvent() {
+ if (event_callback_.get())
+ event_callback_->Run();
+}
+
+} // namespace webkit_glue
diff --git a/webkit/glue/media/buffered_resource_loader.h b/webkit/glue/media/buffered_resource_loader.h
new file mode 100644
index 0000000..09b05e6
--- /dev/null
+++ b/webkit/glue/media/buffered_resource_loader.h
@@ -0,0 +1,246 @@
+// 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.
+
+#ifndef WEBKIT_GLUE_MEDIA_BUFFERED_RESOURCE_LOADER_H_
+#define WEBKIT_GLUE_MEDIA_BUFFERED_RESOURCE_LOADER_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/lock.h"
+#include "base/scoped_ptr.h"
+#include "base/timer.h"
+#include "googleurl/src/gurl.h"
+#include "media/base/seekable_buffer.h"
+#include "net/base/file_stream.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebURLLoader.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebURLLoaderClient.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebURLRequest.h"
+#include "webkit/glue/media/web_data_source.h"
+#include "webkit/glue/webmediaplayer_impl.h"
+
+namespace webkit_glue {
+
+const int64 kPositionNotSpecified = -1;
+
+const char kHttpScheme[] = "http";
+const char kHttpsScheme[] = "https";
+const char kDataScheme[] = "data";
+
+// This class works inside demuxer thread and render thread. It contains a
+// WebURLLoader and does the actual resource loading. This object does
+// buffering internally, it defers the resource loading if buffer is full
+// and un-defers the resource loading if it is under buffered.
+class BufferedResourceLoader :
+ public base::RefCountedThreadSafe<BufferedResourceLoader>,
+ public WebKit::WebURLLoaderClient {
+ public:
+ typedef Callback0::Type NetworkEventCallback;
+
+ // |url| - URL for the resource to be loaded.
+ // |first_byte_position| - First byte to start loading from,
+ // |kPositionNotSpecified| for not specified.
+ // |last_byte_position| - Last byte to be loaded,
+ // |kPositionNotSpecified| for not specified.
+ BufferedResourceLoader(const GURL& url,
+ int64 first_byte_position,
+ int64 last_byte_position);
+
+ // Start the resource loading with the specified URL and range.
+ // This method operates in asynchronous mode. Once there's a response from the
+ // server, success or fail |callback| is called with the result.
+ // |callback| is called with the following values:
+ // - net::OK
+ // The request has started successfully.
+ // - net::ERR_FAILED
+ // The request has failed because of an error with the network.
+ // - net::ERR_INVALID_RESPONSE
+ // An invalid response is received from the server.
+ // - (Anything else)
+ // An error code that indicates the request has failed.
+ // |event_callback| is called when the response is completed, data is
+ // received, the request is suspended or resumed.
+ virtual void Start(net::CompletionCallback* callback,
+ NetworkEventCallback* event_callback,
+ WebKit::WebFrame* frame);
+
+ // Stop this loader, cancels and request and release internal buffer.
+ virtual void Stop();
+
+ // Reads the specified |read_size| from |position| into |buffer| and when
+ // the operation is done invoke |callback| with number of bytes read or an
+ // error code.
+ // |callback| is called with the following values:
+ // - (Anything greater than or equal 0)
+ // Read was successful with the indicated number of bytes read.
+ // - net::ERR_FAILED
+ // The read has failed because of an error with the network.
+ // - net::ERR_CACHE_MISS
+ // The read was made too far away from the current buffered position.
+ virtual void Read(int64 position, int read_size,
+ uint8* buffer, net::CompletionCallback* callback);
+
+ // Returns the position of the last byte buffered. Returns
+ // |kPositionNotSpecified| if such value is not available.
+ virtual int64 GetBufferedPosition();
+
+ // Sets whether deferring data is allowed or disallowed.
+ virtual void SetAllowDefer(bool is_allowed);
+
+ // Gets the content length in bytes of the instance after this loader has been
+ // started. If this value is |kPositionNotSpecified|, then content length is
+ // unknown.
+ virtual int64 content_length();
+
+ // Gets the original size of the file requested. If this value is
+ // |kPositionNotSpecified|, then the size is unknown.
+ virtual int64 instance_size();
+
+ // Returns true if the response for this loader is a partial response.
+ // It means a 206 response in HTTP/HTTPS protocol.
+ virtual bool partial_response();
+
+ // Returns true if network is currently active.
+ virtual bool network_activity();
+
+ // Returns resulting URL.
+ virtual const GURL& url();
+
+ // Used to inject a mock used for unittests.
+ virtual void SetURLLoaderForTest(WebKit::WebURLLoader* mock_loader);
+
+ // WebKit::WebURLLoaderClient implementation.
+ virtual void willSendRequest(
+ WebKit::WebURLLoader* loader,
+ WebKit::WebURLRequest& newRequest,
+ const WebKit::WebURLResponse& redirectResponse);
+ virtual void didSendData(
+ WebKit::WebURLLoader* loader,
+ unsigned long long bytesSent,
+ unsigned long long totalBytesToBeSent);
+ virtual void didReceiveResponse(
+ WebKit::WebURLLoader* loader,
+ const WebKit::WebURLResponse& response);
+ virtual void didDownloadData(
+ WebKit::WebURLLoader* loader,
+ int dataLength);
+ virtual void didReceiveData(
+ WebKit::WebURLLoader* loader,
+ const char* data,
+ int dataLength);
+ virtual void didReceiveCachedMetadata(
+ WebKit::WebURLLoader* loader,
+ const char* data, int dataLength);
+ virtual void didFinishLoading(
+ WebKit::WebURLLoader* loader,
+ double finishTime);
+ virtual void didFail(
+ WebKit::WebURLLoader* loader,
+ const WebKit::WebURLError&);
+
+ protected:
+ friend class base::RefCountedThreadSafe<BufferedResourceLoader>;
+
+ virtual ~BufferedResourceLoader();
+
+ private:
+ friend class BufferedResourceLoaderTest;
+
+ // Defer the resource loading if the buffer is full.
+ void EnableDeferIfNeeded();
+
+ // Disable defer loading if we are under-buffered.
+ void DisableDeferIfNeeded();
+
+ // Returns true if the current read request can be fulfilled by what is in
+ // the buffer.
+ bool CanFulfillRead();
+
+ // Returns true if the current read request will be fulfilled in the future.
+ bool WillFulfillRead();
+
+ // Method that does the actual read and calls the |read_callback_|, assuming
+ // the request range is in |buffer_|.
+ void ReadInternal();
+
+ // If we have made a range request, verify the response from the server.
+ bool VerifyPartialResponse(const WebKit::WebURLResponse& response);
+
+ // Returns the value for a range request header using parameters
+ // |first_byte_position| and |last_byte_position|. Negative numbers other
+ // than |kPositionNotSpecified| are not allowed for |first_byte_position| and
+ // |last_byte_position|. |first_byte_position| should always be less than or
+ // equal to |last_byte_position| if they are both not |kPositionNotSpecified|.
+ // Empty string is returned on invalid parameters.
+ std::string GenerateHeaders(int64 first_byte_position,
+ int64 last_byte_position);
+
+ // Done with read. Invokes the read callback and reset parameters for the
+ // read request.
+ void DoneRead(int error);
+
+ // Done with start. Invokes the start callback and reset it.
+ void DoneStart(int error);
+
+ // Calls |event_callback_| in terms of a network event.
+ void NotifyNetworkEvent();
+
+ bool HasPendingRead() { return read_callback_.get() != NULL; }
+
+ // A sliding window of buffer.
+ scoped_ptr<media::SeekableBuffer> buffer_;
+
+ // True if resource loading was deferred.
+ bool deferred_;
+
+ // True if resource loader is allowed to defer, false otherwise.
+ bool defer_allowed_;
+
+ // True if resource loading has completed.
+ bool completed_;
+
+ // True if a range request was made.
+ bool range_requested_;
+
+ // True if response data received is a partial range.
+ bool partial_response_;
+
+ // Does the work of loading and sends data back to this client.
+ scoped_ptr<WebKit::WebURLLoader> url_loader_;
+
+ GURL url_;
+ int64 first_byte_position_;
+ int64 last_byte_position_;
+
+ // Callback method that listens to network events.
+ scoped_ptr<NetworkEventCallback> event_callback_;
+
+ // Members used during request start.
+ scoped_ptr<net::CompletionCallback> start_callback_;
+ int64 offset_;
+ int64 content_length_;
+ int64 instance_size_;
+
+ // Members used during a read operation. They should be reset after each
+ // read has completed or failed.
+ scoped_ptr<net::CompletionCallback> read_callback_;
+ int64 read_position_;
+ int read_size_;
+ uint8* read_buffer_;
+
+ // Offsets of the requested first byte and last byte in |buffer_|. They are
+ // written by Read().
+ int first_offset_;
+ int last_offset_;
+
+ // Used to ensure mocks for unittests are used instead of reset in Start().
+ bool keep_test_loader_;
+
+ DISALLOW_COPY_AND_ASSIGN(BufferedResourceLoader);
+};
+
+} // namespace webkit_glue
+
+#endif // WEBKIT_GLUE_MEDIA_BUFFERED_RESOURCE_LOADER_H_
diff --git a/webkit/glue/media/buffered_resource_loader_unittest.cc b/webkit/glue/media/buffered_resource_loader_unittest.cc
new file mode 100644
index 0000000..8e64c26
--- /dev/null
+++ b/webkit/glue/media/buffered_resource_loader_unittest.cc
@@ -0,0 +1,486 @@
+// 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.
+
+#include <algorithm>
+
+#include "base/format_macros.h"
+#include "base/stringprintf.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_util.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebFrameClient.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebURLError.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebURLResponse.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebView.h"
+#include "webkit/glue/media/buffered_resource_loader.h"
+#include "webkit/mocks/mock_webframe.h"
+#include "webkit/mocks/mock_weburlloader.h"
+
+using ::testing::_;
+using ::testing::Assign;
+using ::testing::AtLeast;
+using ::testing::DeleteArg;
+using ::testing::DoAll;
+using ::testing::InSequence;
+using ::testing::Invoke;
+using ::testing::InvokeWithoutArgs;
+using ::testing::NotNull;
+using ::testing::Return;
+using ::testing::ReturnRef;
+using ::testing::SetArgumentPointee;
+using ::testing::StrictMock;
+using ::testing::NiceMock;
+using ::testing::WithArgs;
+
+using WebKit::WebURLError;
+using WebKit::WebFrameClient;
+using WebKit::WebURLResponse;
+using WebKit::WebView;
+
+namespace {
+
+const char* kHttpUrl = "http://test";
+const int kDataSize = 1024;
+const int kHttpOK = 200;
+const int kHttpPartialContent = 206;
+
+enum NetworkState {
+ NONE,
+ LOADED,
+ LOADING
+};
+
+} // namespace
+
+namespace webkit_glue {
+
+// Submit a request completed event to the resource loader due to request
+// being canceled. Pretending the event is from external.
+ACTION_P(RequestCanceled, loader) {
+ WebURLError error;
+ error.reason = net::ERR_ABORTED;
+ error.domain = WebString::fromUTF8(net::kErrorDomain);
+ loader->didFail(NULL, error);
+}
+
+class BufferedResourceLoaderTest : public testing::Test {
+ public:
+ BufferedResourceLoaderTest() {
+ url_loader_ = new NiceMock<MockWebURLLoader>();
+
+ for (int i = 0; i < kDataSize; ++i)
+ data_[i] = i;
+ }
+
+ virtual ~BufferedResourceLoaderTest() {
+ ignore_result(frame_.release());
+ }
+
+ void Initialize(const char* url, int first_position, int last_position) {
+ gurl_ = GURL(url);
+ first_position_ = first_position;
+ last_position_ = last_position;
+
+ frame_.reset(new NiceMock<MockWebFrame>());
+
+ loader_ = new BufferedResourceLoader(gurl_,
+ first_position_, last_position_);
+ loader_->SetURLLoaderForTest(url_loader_);
+ }
+
+ void SetLoaderBuffer(size_t forward_capacity, size_t backward_capacity) {
+ loader_->buffer_.reset(
+ new media::SeekableBuffer(backward_capacity, forward_capacity));
+ }
+
+ void Start() {
+ InSequence s;
+ EXPECT_CALL(*url_loader_, loadAsynchronously(_, loader_.get()));
+ loader_->Start(
+ NewCallback(this, &BufferedResourceLoaderTest::StartCallback),
+ NewCallback(this, &BufferedResourceLoaderTest::NetworkCallback),
+ frame_.get());
+ }
+
+ void FullResponse(int64 instance_size) {
+ EXPECT_CALL(*this, StartCallback(net::OK));
+
+ WebURLResponse response(gurl_);
+ response.setHTTPHeaderField(WebString::fromUTF8("Content-Length"),
+ WebString::fromUTF8(base::StringPrintf("%"
+ PRId64, instance_size)));
+ response.setExpectedContentLength(instance_size);
+ response.setHTTPStatusCode(kHttpOK);
+ loader_->didReceiveResponse(url_loader_, response);
+ EXPECT_EQ(instance_size, loader_->content_length());
+ EXPECT_EQ(instance_size, loader_->instance_size());
+ EXPECT_FALSE(loader_->partial_response());
+ }
+
+ void PartialResponse(int64 first_position, int64 last_position,
+ int64 instance_size) {
+ EXPECT_CALL(*this, StartCallback(net::OK));
+ int64 content_length = last_position - first_position + 1;
+
+ WebURLResponse response(gurl_);
+ response.setHTTPHeaderField(WebString::fromUTF8("Content-Range"),
+ WebString::fromUTF8(base::StringPrintf("bytes "
+ "%" PRId64 "-%" PRId64 "/%" PRId64,
+ first_position,
+ last_position,
+ instance_size)));
+ response.setExpectedContentLength(content_length);
+ response.setHTTPStatusCode(kHttpPartialContent);
+ loader_->didReceiveResponse(url_loader_, response);
+ EXPECT_EQ(content_length, loader_->content_length());
+ EXPECT_EQ(instance_size, loader_->instance_size());
+ EXPECT_TRUE(loader_->partial_response());
+ }
+
+ void StopWhenLoad() {
+ InSequence s;
+ EXPECT_CALL(*url_loader_, cancel())
+ .WillOnce(RequestCanceled(loader_));
+ loader_->Stop();
+ }
+
+ // Helper method to write to |loader_| from |data_|.
+ void WriteLoader(int position, int size) {
+ EXPECT_CALL(*this, NetworkCallback())
+ .RetiresOnSaturation();
+ loader_->didReceiveData(url_loader_,
+ reinterpret_cast<char*>(data_ + position), size);
+ }
+
+ // Helper method to read from |loader_|.
+ void ReadLoader(int64 position, int size, uint8* buffer) {
+ loader_->Read(position, size, buffer,
+ NewCallback(this, &BufferedResourceLoaderTest::ReadCallback));
+ }
+
+ // Verifis that data in buffer[0...size] is equal to data_[pos...pos+size].
+ void VerifyBuffer(uint8* buffer, int pos, int size) {
+ EXPECT_EQ(0, memcmp(buffer, data_ + pos, size));
+ }
+
+ // Helper method to disallow deferring in |loader_|.
+ void DisallowLoaderDefer() {
+ if (loader_->deferred_) {
+ EXPECT_CALL(*url_loader_, setDefersLoading(false));
+ EXPECT_CALL(*this, NetworkCallback());
+ }
+ loader_->SetAllowDefer(false);
+ }
+
+ // Helper method to allow deferring in |loader_|.
+ void AllowLoaderDefer() {
+ loader_->SetAllowDefer(true);
+ }
+
+ MOCK_METHOD1(StartCallback, void(int error));
+ MOCK_METHOD1(ReadCallback, void(int error));
+ MOCK_METHOD0(NetworkCallback, void());
+
+ protected:
+ GURL gurl_;
+ int64 first_position_;
+ int64 last_position_;
+
+ scoped_refptr<BufferedResourceLoader> loader_;
+ NiceMock<MockWebURLLoader>* url_loader_;
+ scoped_ptr<NiceMock<MockWebFrame> > frame_;
+
+ uint8 data_[kDataSize];
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BufferedResourceLoaderTest);
+};
+
+TEST_F(BufferedResourceLoaderTest, StartStop) {
+ Initialize(kHttpUrl, -1, -1);
+ Start();
+ StopWhenLoad();
+}
+
+// Tests that a bad HTTP response is recived, e.g. file not found.
+TEST_F(BufferedResourceLoaderTest, BadHttpResponse) {
+ Initialize(kHttpUrl, -1, -1);
+ Start();
+
+ EXPECT_CALL(*this, StartCallback(net::ERR_FAILED));
+ EXPECT_CALL(*url_loader_, cancel())
+ .WillOnce(RequestCanceled(loader_));
+
+ WebURLResponse response(gurl_);
+ response.setHTTPStatusCode(404);
+ response.setHTTPStatusText("Not Found\n");
+ loader_->didReceiveResponse(url_loader_, response);
+}
+
+// Tests that partial content is requested but not fulfilled.
+TEST_F(BufferedResourceLoaderTest, NotPartialResponse) {
+ Initialize(kHttpUrl, 100, -1);
+ Start();
+ FullResponse(1024);
+ StopWhenLoad();
+}
+
+// Tests that a 200 response is received.
+TEST_F(BufferedResourceLoaderTest, FullResponse) {
+ Initialize(kHttpUrl, -1, -1);
+ Start();
+ FullResponse(1024);
+ StopWhenLoad();
+}
+
+// Tests that a partial content response is received.
+TEST_F(BufferedResourceLoaderTest, PartialResponse) {
+ Initialize(kHttpUrl, 100, 200);
+ Start();
+ PartialResponse(100, 200, 1024);
+ StopWhenLoad();
+}
+
+// Tests that an invalid partial response is received.
+TEST_F(BufferedResourceLoaderTest, InvalidPartialResponse) {
+ Initialize(kHttpUrl, 0, 10);
+ Start();
+
+ EXPECT_CALL(*this, StartCallback(net::ERR_INVALID_RESPONSE));
+ EXPECT_CALL(*url_loader_, cancel())
+ .WillOnce(RequestCanceled(loader_));
+
+ WebURLResponse response(gurl_);
+ response.setHTTPHeaderField(WebString::fromUTF8("Content-Range"),
+ WebString::fromUTF8(base::StringPrintf("bytes "
+ "%d-%d/%d", 1, 10, 1024)));
+ response.setExpectedContentLength(10);
+ response.setHTTPStatusCode(kHttpPartialContent);
+ loader_->didReceiveResponse(url_loader_, response);
+}
+
+// Tests the logic of sliding window for data buffering and reading.
+TEST_F(BufferedResourceLoaderTest, BufferAndRead) {
+ Initialize(kHttpUrl, 10, 29);
+ Start();
+ PartialResponse(10, 29, 30);
+
+ uint8 buffer[10];
+ InSequence s;
+
+ // Writes 10 bytes and read them back.
+ WriteLoader(10, 10);
+ EXPECT_CALL(*this, ReadCallback(10));
+ ReadLoader(10, 10, buffer);
+ VerifyBuffer(buffer, 10, 10);
+
+ // Writes 10 bytes and read 2 times.
+ WriteLoader(20, 10);
+ EXPECT_CALL(*this, ReadCallback(5));
+ ReadLoader(20, 5, buffer);
+ VerifyBuffer(buffer, 20, 5);
+ EXPECT_CALL(*this, ReadCallback(5));
+ ReadLoader(25, 5, buffer);
+ VerifyBuffer(buffer, 25, 5);
+
+ // Read backward within buffer.
+ EXPECT_CALL(*this, ReadCallback(10));
+ ReadLoader(10, 10, buffer);
+ VerifyBuffer(buffer, 10, 10);
+
+ // Read backward outside buffer.
+ EXPECT_CALL(*this, ReadCallback(net::ERR_CACHE_MISS));
+ ReadLoader(9, 10, buffer);
+
+ // Response has completed.
+ EXPECT_CALL(*this, NetworkCallback());
+ loader_->didFinishLoading(url_loader_, 0);
+
+ // Try to read 10 from position 25 will just return with 5 bytes.
+ EXPECT_CALL(*this, ReadCallback(5));
+ ReadLoader(25, 10, buffer);
+ VerifyBuffer(buffer, 25, 5);
+
+ // Try to read outside buffered range after request has completed.
+ EXPECT_CALL(*this, ReadCallback(net::ERR_CACHE_MISS));
+ ReadLoader(5, 10, buffer);
+
+ // Try to read beyond the instance size.
+ EXPECT_CALL(*this, ReadCallback(0));
+ ReadLoader(30, 10, buffer);
+}
+
+TEST_F(BufferedResourceLoaderTest, ReadOutsideBuffer) {
+ Initialize(kHttpUrl, 10, 0x00FFFFFF);
+ Start();
+ PartialResponse(10, 0x00FFFFFF, 0x01000000);
+
+ uint8 buffer[10];
+ InSequence s;
+
+ // Read very far aheard will get a cache miss.
+ EXPECT_CALL(*this, ReadCallback(net::ERR_CACHE_MISS));
+ ReadLoader(0x00FFFFFF, 1, buffer);
+
+ // The following call will not call ReadCallback() because it is waiting for
+ // data to arrive.
+ ReadLoader(10, 10, buffer);
+
+ // Writing to loader will fulfill the read request.
+ EXPECT_CALL(*this, ReadCallback(10));
+ WriteLoader(10, 20);
+ VerifyBuffer(buffer, 10, 10);
+
+ // The following call cannot be fulfilled now.
+ ReadLoader(25, 10, buffer);
+
+ EXPECT_CALL(*this, ReadCallback(5));
+ EXPECT_CALL(*this, NetworkCallback());
+ loader_->didFinishLoading(url_loader_, 0);
+}
+
+TEST_F(BufferedResourceLoaderTest, RequestFailedWhenRead) {
+ Initialize(kHttpUrl, 10, 29);
+ Start();
+ PartialResponse(10, 29, 30);
+
+ uint8 buffer[10];
+ InSequence s;
+
+ ReadLoader(10, 10, buffer);
+ EXPECT_CALL(*this, ReadCallback(net::ERR_FAILED));
+ EXPECT_CALL(*this, NetworkCallback());
+ WebURLError error;
+ error.reason = net::ERR_FAILED;
+ loader_->didFail(url_loader_, error);
+}
+
+// Tests the logic of caching data to disk when media is paused.
+TEST_F(BufferedResourceLoaderTest, AllowDefer_NoDataReceived) {
+ Initialize(kHttpUrl, 10, 99);
+ SetLoaderBuffer(10, 20);
+ Start();
+ PartialResponse(10, 99, 100);
+
+ // Start in undeferred state, then disallow defer, then allow defer
+ // without receiving data in between.
+ DisallowLoaderDefer();
+ AllowLoaderDefer();
+ StopWhenLoad();
+}
+
+TEST_F(BufferedResourceLoaderTest, AllowDefer_ReadSameWindow) {
+ Initialize(kHttpUrl, 10, 99);
+ SetLoaderBuffer(10, 20);
+ Start();
+ PartialResponse(10, 99, 100);
+
+ uint8 buffer[10];
+
+ // Start in undeferred state, disallow defer, receive data but don't shift
+ // buffer window, then allow defer and read.
+ DisallowLoaderDefer();
+ WriteLoader(10, 10);
+ AllowLoaderDefer();
+
+ EXPECT_CALL(*this, ReadCallback(10));
+ ReadLoader(10, 10, buffer);
+ VerifyBuffer(buffer, 10, 10);
+ StopWhenLoad();
+}
+
+TEST_F(BufferedResourceLoaderTest, AllowDefer_ReadPastWindow) {
+ Initialize(kHttpUrl, 10, 99);
+ SetLoaderBuffer(10, 20);
+ Start();
+ PartialResponse(10, 99, 100);
+
+ uint8 buffer[10];
+
+ // Not deferred, disallow defer, received data and shift buffer window,
+ // allow defer, then read in area outside of buffer window.
+ DisallowLoaderDefer();
+ WriteLoader(10, 10);
+ WriteLoader(20, 50);
+ AllowLoaderDefer();
+
+ EXPECT_CALL(*this, ReadCallback(net::ERR_CACHE_MISS));
+ ReadLoader(10, 10, buffer);
+ StopWhenLoad();
+}
+
+TEST_F(BufferedResourceLoaderTest, AllowDefer_DeferredNoDataReceived) {
+ Initialize(kHttpUrl, 10, 99);
+ SetLoaderBuffer(10, 20);
+ Start();
+ PartialResponse(10, 99, 100);
+
+ uint8 buffer[10];
+
+ // Start in deferred state, then disallow defer, receive no data, and
+ // allow defer and read.
+ EXPECT_CALL(*url_loader_, setDefersLoading(true));
+ EXPECT_CALL(*this, NetworkCallback());
+ WriteLoader(10, 40);
+
+ DisallowLoaderDefer();
+ AllowLoaderDefer();
+
+ EXPECT_CALL(*this, ReadCallback(10));
+ ReadLoader(20, 10, buffer);
+ VerifyBuffer(buffer, 20, 10);
+ StopWhenLoad();
+}
+
+TEST_F(BufferedResourceLoaderTest, AllowDefer_DeferredReadSameWindow) {
+ Initialize(kHttpUrl, 10, 99);
+ SetLoaderBuffer(10, 20);
+ Start();
+ PartialResponse(10, 99, 100);
+
+ uint8 buffer[10];
+
+ // Start in deferred state, disallow defer, receive data and shift buffer
+ // window, allow defer, and read in a place that's still in the window.
+ EXPECT_CALL(*url_loader_, setDefersLoading(true));
+ EXPECT_CALL(*this, NetworkCallback());
+ WriteLoader(10, 30);
+
+ DisallowLoaderDefer();
+ WriteLoader(40, 5);
+ AllowLoaderDefer();
+
+ EXPECT_CALL(*this, ReadCallback(10));
+ ReadLoader(20, 10, buffer);
+ VerifyBuffer(buffer, 20, 10);
+ StopWhenLoad();
+}
+
+TEST_F(BufferedResourceLoaderTest, AllowDefer_DeferredReadPastWindow) {
+ Initialize(kHttpUrl, 10, 99);
+ SetLoaderBuffer(10, 20);
+ Start();
+ PartialResponse(10, 99, 100);
+
+ uint8 buffer[10];
+
+ // Start in deferred state, disallow defer, receive data and shift buffer
+ // window, allow defer, and read outside of the buffer window.
+ EXPECT_CALL(*url_loader_, setDefersLoading(true));
+ EXPECT_CALL(*this, NetworkCallback());
+ WriteLoader(10, 40);
+
+ DisallowLoaderDefer();
+ WriteLoader(50, 20);
+ WriteLoader(70, 40);
+ AllowLoaderDefer();
+
+ EXPECT_CALL(*this, ReadCallback(net::ERR_CACHE_MISS));
+ ReadLoader(20, 5, buffer);
+ StopWhenLoad();
+}
+// TODO(hclam): add unit test for defer loading.
+
+} // namespace webkit_glue
+
diff --git a/webkit/glue/media/media_resource_loader_bridge_factory.cc b/webkit/glue/media/media_resource_loader_bridge_factory.cc
deleted file mode 100644
index 3fb9d65..0000000
--- a/webkit/glue/media/media_resource_loader_bridge_factory.cc
+++ /dev/null
@@ -1,82 +0,0 @@
-// 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.
-
-#include "webkit/glue/media/media_resource_loader_bridge_factory.h"
-
-#include "base/format_macros.h"
-#include "base/string_util.h"
-#include "base/stringprintf.h"
-
-namespace {
-
-// A constant for an unknown position.
-const int64 kPositionNotSpecified = -1;
-
-} // namespace
-
-namespace webkit_glue {
-
-MediaResourceLoaderBridgeFactory::MediaResourceLoaderBridgeFactory(
- const GURL& referrer,
- const std::string& frame_origin,
- const std::string& main_frame_origin,
- int origin_pid,
- int appcache_host_id,
- int32 routing_id)
- : referrer_(referrer),
- frame_origin_(frame_origin),
- main_frame_origin_(main_frame_origin),
- origin_pid_(origin_pid),
- appcache_host_id_(appcache_host_id),
- routing_id_(routing_id) {
-}
-
-MediaResourceLoaderBridgeFactory::~MediaResourceLoaderBridgeFactory() {}
-
-ResourceLoaderBridge* MediaResourceLoaderBridgeFactory::CreateBridge(
- const GURL& url,
- int load_flags,
- int64 first_byte_position,
- int64 last_byte_position) {
- webkit_glue::ResourceLoaderBridge::RequestInfo request_info;
- request_info.method = "GET";
- request_info.url = url;
- request_info.first_party_for_cookies = url;
- request_info.referrer = referrer_;
- request_info.frame_origin = frame_origin_;
- request_info.main_frame_origin = main_frame_origin_;
- request_info.headers = GenerateHeaders(first_byte_position,
- last_byte_position);
- request_info.load_flags = load_flags;
- request_info.requestor_pid = origin_pid_;
- request_info.request_type = ResourceType::MEDIA;
- request_info.appcache_host_id = appcache_host_id_;
- request_info.routing_id = routing_id_;
- return webkit_glue::ResourceLoaderBridge::Create(request_info);
-}
-
-MediaResourceLoaderBridgeFactory::MediaResourceLoaderBridgeFactory() {}
-
-// static
-const std::string MediaResourceLoaderBridgeFactory::GenerateHeaders (
- int64 first_byte_position, int64 last_byte_position) {
- // Construct the range header.
- std::string header;
- if (first_byte_position > kPositionNotSpecified &&
- last_byte_position > kPositionNotSpecified) {
- if (first_byte_position <= last_byte_position) {
- header = base::StringPrintf("Range: bytes=%" PRId64 "-%" PRId64,
- first_byte_position,
- last_byte_position);
- }
- } else if (first_byte_position > kPositionNotSpecified) {
- header = base::StringPrintf("Range: bytes=%" PRId64 "-",
- first_byte_position);
- } else if (last_byte_position > kPositionNotSpecified) {
- NOTIMPLEMENTED() << "Suffix range not implemented";
- }
- return header;
-}
-
-} // namespace webkit_glue
diff --git a/webkit/glue/media/media_resource_loader_bridge_factory.h b/webkit/glue/media/media_resource_loader_bridge_factory.h
deleted file mode 100644
index ccacdc6..0000000
--- a/webkit/glue/media/media_resource_loader_bridge_factory.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright (c) 2009 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 WEBKIT_GLUE_MEDIA_MEDIA_RESOURCE_LOADER_BRIDGE_FACTORY_H_
-#define WEBKIT_GLUE_MEDIA_MEDIA_RESOURCE_LOADER_BRIDGE_FACTORY_H_
-
-#include "base/gtest_prod_util.h"
-#include "webkit/glue/resource_loader_bridge.h"
-
-namespace webkit_glue {
-
-// A factory used to create a ResourceLoaderBridge for the media player.
-// This factory is used also for testing. Testing code can use this class and
-// override CreateBridge() to inject a mock ResourceLoaderBridge for code that
-// interacts with it, e.g. BufferedDataSource.
-class MediaResourceLoaderBridgeFactory {
- public:
- MediaResourceLoaderBridgeFactory(
- const GURL& referrer,
- const std::string& frame_origin,
- const std::string& main_frame_origin,
- int origin_pid,
- int appcache_host_id,
- int32 routing_id);
-
- virtual ~MediaResourceLoaderBridgeFactory();
-
- // Factory method to create a ResourceLoaderBridge with the following
- // parameters:
- // |url| - URL of the resource to be loaded.
- // |load_flags| - Load flags for this loading.
- // |first_byte_position| - First byte position for a range request, -1 if not.
- // |last_byte_position| - Last byte position for a range request, -1 if not.
- virtual ResourceLoaderBridge* CreateBridge(
- const GURL& url,
- int load_flags,
- int64 first_byte_position,
- int64 last_byte_position);
-
- protected:
- // An empty constructor only used by inherited classes.
- MediaResourceLoaderBridgeFactory();
-
- private:
- FRIEND_TEST_ALL_PREFIXES(MediaResourceLoaderBridgeFactoryTest,
- GenerateHeaders);
-
- // Returns a range request header using parameters |first_byte_position| and
- // |last_byte_position|.
- // Negative numbers other than -1 are not allowed for |first_byte_position|
- // and |last_byte_position|. |first_byte_position| should always be less than
- // or equal to |last_byte_position| if they are both not -1.
- // Here's a list of valid parameters:
- // |first_byte_position| |last_byte_position|
- // 0 1000
- // 4096 4096
- // 0 -1
- // -1 -1
- // Empty string is returned on invalid parameters.
- static const std::string GenerateHeaders(int64 first_byte_position,
- int64 last_byte_position);
-
- GURL first_party_for_cookies_;
- GURL referrer_;
- std::string frame_origin_;
- std::string main_frame_origin_;
- std::string headers_;
- int origin_pid_;
- int appcache_host_id_;
- int32 routing_id_;
-};
-
-} // namespace webkit_glue
-
-#endif // WEBKIT_GLUE_MEDIA_MEDIA_RESOURCE_LOADER_BRIDGE_FACTORY_H_
diff --git a/webkit/glue/media/media_resource_loader_bridge_factory_unittest.cc b/webkit/glue/media/media_resource_loader_bridge_factory_unittest.cc
deleted file mode 100644
index 4c0126b..0000000
--- a/webkit/glue/media/media_resource_loader_bridge_factory_unittest.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 2009 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 "net/http/http_util.h"
-#include "webkit/glue/media/media_resource_loader_bridge_factory.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace webkit_glue {
-
-TEST(MediaResourceLoaderBridgeFactoryTest, GenerateHeaders) {
- static const struct {
- const bool success;
- const int64 first_byte_position;
- const int64 last_byte_position;
- } data[] = {
- { false, -1, -1 },
- { false, -5, 0 },
- { false, 100, 0 },
- { true, 0, -1 },
- { true, 0, 0 },
- { true, 100, 100 },
- { true, 50, -1 },
- { true, 10000, -1 },
- { true, 50, 100 },
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
- std::string headers = MediaResourceLoaderBridgeFactory::GenerateHeaders(
- data[i].first_byte_position, data[i].last_byte_position);
- std::vector<net::HttpByteRange> ranges;
- bool ret = net::HttpUtil::ParseRanges(headers, &ranges);
- EXPECT_EQ(data[i].success, ret);
- if (ret) {
- EXPECT_EQ(1u, ranges.size());
- EXPECT_EQ(data[i].first_byte_position,
- ranges[0].first_byte_position());
- EXPECT_EQ(data[i].last_byte_position,
- ranges[0].last_byte_position());
- }
- }
-}
-
-} // namespace webkit_glue
diff --git a/webkit/glue/media/mock_media_resource_loader_bridge_factory.h b/webkit/glue/media/mock_media_resource_loader_bridge_factory.h
deleted file mode 100644
index 3c0a3ae..0000000
--- a/webkit/glue/media/mock_media_resource_loader_bridge_factory.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_MEDIA_MOCK_MEDIA_RESOURCE_LOADER_BRIDGE_FACTORY_H_
-#define WEBKIT_GLUE_MEDIA_MOCK_MEDIA_RESOURCE_LOADER_BRIDGE_FACTORY_H_
-
-#include "testing/gmock/include/gmock/gmock.h"
-#include "webkit/glue/media/media_resource_loader_bridge_factory.h"
-
-namespace webkit_glue {
-
-class MockMediaResourceLoaderBridgeFactory
- : public webkit_glue::MediaResourceLoaderBridgeFactory {
- public:
- MockMediaResourceLoaderBridgeFactory() {
- }
-
- virtual ~MockMediaResourceLoaderBridgeFactory() {
- OnDestroy();
- }
-
- MOCK_METHOD4(CreateBridge,
- webkit_glue::ResourceLoaderBridge*(const GURL& url,
- int load_flags,
- int64 first_byte_position,
- int64 last_byte_position));
- MOCK_METHOD0(OnDestroy, void());
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MockMediaResourceLoaderBridgeFactory);
-};
-
-} // namespace webkit_glue
-
-#endif // WEBKIT_GLUE_MEDIA_MOCK_MEDIA_RESOURCE_LOADER_BRIDGE_FACTORY_H_
diff --git a/webkit/glue/media/simple_data_source.cc b/webkit/glue/media/simple_data_source.cc
index 291928e..8869e28 100644
--- a/webkit/glue/media/simple_data_source.cc
+++ b/webkit/glue/media/simple_data_source.cc
@@ -2,40 +2,35 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "webkit/glue/media/simple_data_source.h"
+
#include "base/message_loop.h"
#include "base/process_util.h"
#include "media/base/filter_host.h"
-#include "net/base/load_flags.h"
#include "net/base/data_url.h"
-#include "net/http/http_response_headers.h"
+#include "net/base/load_flags.h"
#include "net/url_request/url_request_status.h"
-#include "webkit/glue/media/simple_data_source.h"
-#include "webkit/glue/resource_loader_bridge.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebKit.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebKitClient.h"
#include "webkit/glue/webkit_glue.h"
namespace {
-const char kHttpScheme[] = "http";
-const char kHttpsScheme[] = "https";
const char kDataScheme[] = "data";
-// A helper method that accepts only HTTP, HTTPS and FILE protocol.
-bool IsDataProtocol(const GURL& url) {
- return url.SchemeIs(kDataScheme);
-}
-
} // namespace
namespace webkit_glue {
SimpleDataSource::SimpleDataSource(
MessageLoop* render_loop,
- webkit_glue::MediaResourceLoaderBridgeFactory* bridge_factory)
+ WebKit::WebFrame* frame)
: render_loop_(render_loop),
- bridge_factory_(bridge_factory),
+ frame_(frame),
size_(-1),
single_origin_(true),
- state_(UNINITIALIZED) {
+ state_(UNINITIALIZED),
+ keep_test_loader_(false) {
DCHECK(render_loop);
}
@@ -108,34 +103,59 @@ bool SimpleDataSource::IsStreaming() {
return false;
}
-bool SimpleDataSource::OnReceivedRedirect(
- const GURL& new_url,
- const webkit_glue::ResourceResponseInfo& info,
- bool* has_new_first_party_for_cookies,
- GURL* new_first_party_for_cookies) {
+void SimpleDataSource::SetURLLoaderForTest(WebKit::WebURLLoader* mock_loader) {
+ url_loader_.reset(mock_loader);
+ keep_test_loader_ = true;
+}
+
+void SimpleDataSource::willSendRequest(
+ WebKit::WebURLLoader* loader,
+ WebKit::WebURLRequest& newRequest,
+ const WebKit::WebURLResponse& redirectResponse) {
DCHECK(MessageLoop::current() == render_loop_);
- single_origin_ = url_.GetOrigin() == new_url.GetOrigin();
+ single_origin_ = url_.GetOrigin() == GURL(newRequest.url()).GetOrigin();
- // TODO(wtc): should we return a new first party for cookies URL?
- *has_new_first_party_for_cookies = false;
- return true;
+ url_ = newRequest.url();
}
-void SimpleDataSource::OnReceivedResponse(
- const webkit_glue::ResourceResponseInfo& info,
- bool content_filtered) {
+void SimpleDataSource::didSendData(
+ WebKit::WebURLLoader* loader,
+ unsigned long long bytesSent,
+ unsigned long long totalBytesToBeSent) {
+ NOTIMPLEMENTED();
+}
+
+void SimpleDataSource::didReceiveResponse(
+ WebKit::WebURLLoader* loader,
+ const WebKit::WebURLResponse& response) {
DCHECK(MessageLoop::current() == render_loop_);
- size_ = info.content_length;
+ size_ = response.expectedContentLength();
+}
+
+void SimpleDataSource::didDownloadData(
+ WebKit::WebURLLoader* loader,
+ int dataLength) {
+ NOTIMPLEMENTED();
}
-void SimpleDataSource::OnReceivedData(const char* data, int len) {
+void SimpleDataSource::didReceiveData(
+ WebKit::WebURLLoader* loader,
+ const char* data,
+ int data_length) {
DCHECK(MessageLoop::current() == render_loop_);
- data_.append(data, len);
+ data_.append(data, data_length);
}
-void SimpleDataSource::OnCompletedRequest(const URLRequestStatus& status,
- const std::string& security_info,
- const base::Time& completion_time) {
+void SimpleDataSource::didReceiveCachedMetadata(
+ WebKit::WebURLLoader* loader,
+ const char* data,
+ int dataLength) {
+ NOTIMPLEMENTED();
+}
+
+void SimpleDataSource::didFinishLoading(
+ WebKit::WebURLLoader* loader,
+ double finishTime) {
DCHECK(MessageLoop::current() == render_loop_);
AutoLock auto_lock(lock_);
// It's possible this gets called after Stop(), in which case |host_| is no
@@ -143,10 +163,8 @@ void SimpleDataSource::OnCompletedRequest(const URLRequestStatus& status,
if (state_ == STOPPED)
return;
- // Otherwise we should be initializing and have created a bridge.
+ // Otherwise we should be initializing and have created a WebURLLoader.
DCHECK_EQ(state_, INITIALIZING);
- DCHECK(bridge_.get());
- bridge_.reset();
// If we don't get a content length or the request has failed, report it
// as a network error.
@@ -154,7 +172,29 @@ void SimpleDataSource::OnCompletedRequest(const URLRequestStatus& status,
size_ = data_.length();
DCHECK(static_cast<size_t>(size_) == data_.length());
- DoneInitialization_Locked(status.is_success());
+ DoneInitialization_Locked(true);
+}
+
+void SimpleDataSource::didFail(
+ WebKit::WebURLLoader* loader,
+ const WebKit::WebURLError& error) {
+ DCHECK(MessageLoop::current() == render_loop_);
+ AutoLock auto_lock(lock_);
+ // It's possible this gets called after Stop(), in which case |host_| is no
+ // longer valid.
+ if (state_ == STOPPED)
+ return;
+
+ // Otherwise we should be initializing and have created a WebURLLoader.
+ DCHECK_EQ(state_, INITIALIZING);
+
+ // If we don't get a content length or the request has failed, report it
+ // as a network error.
+ if (size_ == -1)
+ size_ = data_.length();
+ DCHECK(static_cast<size_t>(size_) == data_.length());
+
+ DoneInitialization_Locked(false);
}
bool SimpleDataSource::HasSingleOrigin() {
@@ -164,7 +204,7 @@ bool SimpleDataSource::HasSingleOrigin() {
void SimpleDataSource::Abort() {
DCHECK(MessageLoop::current() == render_loop_);
- NOTIMPLEMENTED();
+ frame_ = NULL;
}
void SimpleDataSource::SetURL(const GURL& url) {
@@ -183,9 +223,11 @@ void SimpleDataSource::StartTask() {
if (state_ == STOPPED)
return;
+ CHECK(frame_);
+
DCHECK_EQ(state_, INITIALIZING);
- if (IsDataProtocol(url_)) {
+ if (url_.SchemeIs(kDataScheme)) {
// If this using data protocol, we just need to decode it.
std::string mime_type, charset;
bool success = net::DataURL::Parse(url_, &mime_type, &charset, &data_);
@@ -194,10 +236,18 @@ void SimpleDataSource::StartTask() {
size_ = data_.length();
DoneInitialization_Locked(success);
} else {
- // Create our bridge and start loading the resource.
- bridge_.reset(bridge_factory_->CreateBridge(
- url_, net::LOAD_BYPASS_CACHE, -1, -1));
- bridge_->Start(this);
+ // Prepare the request.
+ WebKit::WebURLRequest request(url_);
+ request.setTargetType(WebKit::WebURLRequest::TargetIsMedia);
+
+ frame_->setReferrerForRequest(request, WebKit::WebURL());
+
+ // This flag is for unittests as we don't want to reset |url_loader|
+ if (!keep_test_loader_)
+ url_loader_.reset(frame_->createAssociatedURLLoader());
+
+ // Start the resource loading.
+ url_loader_->loadAsynchronously(request, this);
}
}
@@ -207,9 +257,9 @@ void SimpleDataSource::CancelTask() {
DCHECK_EQ(state_, STOPPED);
// Cancel any pending requests.
- if (bridge_.get()) {
- bridge_->Cancel();
- bridge_.reset();
+ if (url_loader_.get()) {
+ url_loader_->cancel();
+ url_loader_.reset();
}
}
@@ -220,7 +270,7 @@ void SimpleDataSource::DoneInitialization_Locked(bool success) {
host()->SetTotalBytes(size_);
host()->SetBufferedBytes(size_);
// If scheme is file or data, say we are loaded.
- host()->SetLoaded(url_.SchemeIsFile() || IsDataProtocol(url_));
+ host()->SetLoaded(url_.SchemeIsFile() || url_.SchemeIs(kDataScheme));
} else {
host()->SetError(media::PIPELINE_ERROR_NETWORK);
}
diff --git a/webkit/glue/media/simple_data_source.h b/webkit/glue/media/simple_data_source.h
index ff1e247..f4c83e6 100644
--- a/webkit/glue/media/simple_data_source.h
+++ b/webkit/glue/media/simple_data_source.h
@@ -10,10 +10,17 @@
#ifndef WEBKIT_GLUE_MEDIA_SIMPLE_DATA_SOURCE_H_
#define WEBKIT_GLUE_MEDIA_SIMPLE_DATA_SOURCE_H_
+#include <algorithm>
+#include <string>
+
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
#include "media/base/filters.h"
-#include "webkit/glue/media/media_resource_loader_bridge_factory.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebURLLoader.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebURLLoaderClient.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebURLRequest.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebURLResponse.h"
#include "webkit/glue/media/web_data_source.h"
class MessageLoop;
@@ -22,17 +29,15 @@ class WebMediaPlayerDelegateImpl;
namespace webkit_glue {
class SimpleDataSource : public WebDataSource,
- public webkit_glue::ResourceLoaderBridge::Peer {
+ public WebKit::WebURLLoaderClient {
public:
- SimpleDataSource(
- MessageLoop* render_loop,
- webkit_glue::MediaResourceLoaderBridgeFactory* bridge_factory);
+ SimpleDataSource(MessageLoop* render_loop, WebKit::WebFrame* frame);
virtual ~SimpleDataSource();
- // MediaFilter implementation.
+ // media::Filter implementation.
virtual void Stop(media::FilterCallback* callback);
- // DataSource implementation.
+ // media::DataSource implementation.
virtual void Initialize(const std::string& url,
media::FilterCallback* callback);
virtual const media::MediaFormat& media_format();
@@ -41,21 +46,37 @@ class SimpleDataSource : public WebDataSource,
virtual bool GetSize(int64* size_out);
virtual bool IsStreaming();
- // webkit_glue::ResourceLoaderBridge::Peer implementation.
- virtual void OnUploadProgress(uint64 position, uint64 size) {}
- virtual bool OnReceivedRedirect(
- const GURL& new_url,
- const webkit_glue::ResourceResponseInfo& info,
- bool* has_new_first_party_for_cookies,
- GURL* new_first_party_for_cookies);
- virtual void OnReceivedResponse(
- const webkit_glue::ResourceResponseInfo& info,
- bool content_filtered);
- virtual void OnDownloadedData(int len) {}
- virtual void OnReceivedData(const char* data, int len);
- virtual void OnCompletedRequest(const URLRequestStatus& status,
- const std::string& security_info,
- const base::Time& completion_time);
+ // Used to inject a mock used for unittests.
+ virtual void SetURLLoaderForTest(WebKit::WebURLLoader* mock_loader);
+
+ // WebKit::WebURLLoaderClient implementations.
+ virtual void willSendRequest(
+ WebKit::WebURLLoader* loader,
+ WebKit::WebURLRequest& newRequest,
+ const WebKit::WebURLResponse& redirectResponse);
+ virtual void didSendData(
+ WebKit::WebURLLoader* loader,
+ unsigned long long bytesSent,
+ unsigned long long totalBytesToBeSent);
+ virtual void didReceiveResponse(
+ WebKit::WebURLLoader* loader,
+ const WebKit::WebURLResponse& response);
+ virtual void didDownloadData(
+ WebKit::WebURLLoader* loader,
+ int dataLength);
+ virtual void didReceiveData(
+ WebKit::WebURLLoader* loader,
+ const char* data,
+ int dataLength);
+ virtual void didReceiveCachedMetadata(
+ WebKit::WebURLLoader* loader,
+ const char* data, int dataLength);
+ virtual void didFinishLoading(
+ WebKit::WebURLLoader* loader,
+ double finishTime);
+ virtual void didFail(
+ WebKit::WebURLLoader* loader,
+ const WebKit::WebURLError&);
// webkit_glue::WebDataSource implementation.
virtual bool HasSingleOrigin();
@@ -77,11 +98,11 @@ class SimpleDataSource : public WebDataSource,
// Primarily used for asserting the bridge is loading on the render thread.
MessageLoop* render_loop_;
- // Factory to create a bridge.
- scoped_ptr<webkit_glue::MediaResourceLoaderBridgeFactory> bridge_factory_;
+ // A webframe for loading.
+ WebKit::WebFrame* frame_;
- // Bridge used to load the media resource.
- scoped_ptr<webkit_glue::ResourceLoaderBridge> bridge_;
+ // Does the work of loading and sends data back to this client.
+ scoped_ptr<WebKit::WebURLLoader> url_loader_;
media::MediaFormat media_format_;
GURL url_;
@@ -104,6 +125,9 @@ class SimpleDataSource : public WebDataSource,
// Filter callbacks.
scoped_ptr<media::FilterCallback> initialize_callback_;
+ // Used to ensure mocks for unittests are used instead of reset in Start().
+ bool keep_test_loader_;
+
DISALLOW_COPY_AND_ASSIGN(SimpleDataSource);
};
diff --git a/webkit/glue/media/simple_data_source_unittest.cc b/webkit/glue/media/simple_data_source_unittest.cc
index 537798f..55dc913 100644
--- a/webkit/glue/media/simple_data_source_unittest.cc
+++ b/webkit/glue/media/simple_data_source_unittest.cc
@@ -6,9 +6,15 @@
#include "media/base/filters.h"
#include "media/base/mock_filter_host.h"
#include "media/base/mock_filters.h"
-#include "webkit/glue/media/mock_media_resource_loader_bridge_factory.h"
+#include "net/base/net_errors.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebURLError.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebURLLoader.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebURLRequest.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebURLResponse.h"
#include "webkit/glue/media/simple_data_source.h"
-#include "webkit/glue/mock_resource_loader_bridge.h"
+#include "webkit/mocks/mock_webframe.h"
+#include "webkit/mocks/mock_weburlloader.h"
using ::testing::_;
using ::testing::DoAll;
@@ -21,6 +27,11 @@ using ::testing::SetArgumentPointee;
using ::testing::StrictMock;
using ::testing::WithArgs;
+using WebKit::WebURLError;
+using WebKit::WebURLLoader;
+using WebKit::WebURLRequest;
+using WebKit::WebURLResponse;
+
namespace {
const int kDataSize = 1024;
@@ -39,68 +50,56 @@ namespace webkit_glue {
class SimpleDataSourceTest : public testing::Test {
public:
SimpleDataSourceTest() {
- bridge_factory_.reset(
- new NiceMock<MockMediaResourceLoaderBridgeFactory>());
- bridge_.reset(new NiceMock<MockResourceLoaderBridge>());
-
for (int i = 0; i < kDataSize; ++i) {
data_[i] = i;
}
}
virtual ~SimpleDataSourceTest() {
- if (bridge_.get())
- EXPECT_CALL(*bridge_, OnDestroy());
- if (bridge_factory_.get())
- EXPECT_CALL(*bridge_factory_, OnDestroy());
+ ignore_result(frame_.release());
}
void InitializeDataSource(const char* url) {
+ gurl_ = GURL(url);
+
+ frame_.reset(new NiceMock<MockWebFrame>());
+ url_loader_ = new NiceMock<MockWebURLLoader>();
+
data_source_ = new SimpleDataSource(MessageLoop::current(),
- bridge_factory_.get());
- CHECK(data_source_);
+ frame_.get());
// There is no need to provide a message loop to data source.
data_source_->set_host(&host_);
+ data_source_->SetURLLoaderForTest(url_loader_);
- // First a bridge is created.
InSequence s;
- EXPECT_CALL(*bridge_factory_, CreateBridge(GURL(url), _, -1, -1))
- .WillOnce(Return(bridge_.get()));
- EXPECT_CALL(*bridge_, Start(data_source_.get()))
- .WillOnce(Return(true));
data_source_->Initialize(url, callback_.NewCallback());
-
MessageLoop::current()->RunAllPending();
}
void RequestSucceeded(bool is_loaded) {
- ResourceResponseInfo info;
- info.content_length = kDataSize;
+ WebURLResponse response(gurl_);
+ response.setExpectedContentLength(kDataSize);
- data_source_->OnReceivedResponse(info, false);
+ data_source_->didReceiveResponse(NULL, response);
int64 size;
EXPECT_TRUE(data_source_->GetSize(&size));
EXPECT_EQ(kDataSize, size);
- for (int i = 0; i < kDataSize; ++i)
- data_source_->OnReceivedData(data_ + i, 1);
+ for (int i = 0; i < kDataSize; ++i) {
+ data_source_->didReceiveData(NULL, data_ + i, 1);
+ }
EXPECT_CALL(host_, SetLoaded(is_loaded));
InSequence s;
- EXPECT_CALL(*bridge_, OnDestroy())
- .WillOnce(Invoke(this, &SimpleDataSourceTest::ReleaseBridge));
EXPECT_CALL(host_, SetTotalBytes(kDataSize));
EXPECT_CALL(host_, SetBufferedBytes(kDataSize));
EXPECT_CALL(callback_, OnFilterCallback());
EXPECT_CALL(callback_, OnCallbackDestroyed());
- URLRequestStatus status;
- status.set_status(URLRequestStatus::SUCCESS);
- status.set_os_error(0);
- data_source_->OnCompletedRequest(status, "", base::Time());
+ data_source_->didFinishLoading(NULL, 0);
// Let the tasks to be executed.
MessageLoop::current()->RunAllPending();
@@ -108,28 +107,23 @@ class SimpleDataSourceTest : public testing::Test {
void RequestFailed() {
InSequence s;
- EXPECT_CALL(*bridge_, OnDestroy())
- .WillOnce(Invoke(this, &SimpleDataSourceTest::ReleaseBridge));
EXPECT_CALL(host_, SetError(media::PIPELINE_ERROR_NETWORK));
EXPECT_CALL(callback_, OnFilterCallback());
EXPECT_CALL(callback_, OnCallbackDestroyed());
- URLRequestStatus status;
- status.set_status(URLRequestStatus::FAILED);
- status.set_os_error(100);
- data_source_->OnCompletedRequest(status, "", base::Time());
+ WebURLError error;
+ error.reason = net::ERR_FAILED;
+ data_source_->didFail(NULL, error);
// Let the tasks to be executed.
MessageLoop::current()->RunAllPending();
}
void DestroyDataSource() {
- EXPECT_CALL(*bridge_factory_, OnDestroy())
- .WillOnce(Invoke(this, &SimpleDataSourceTest::ReleaseBridgeFactory));
-
StrictMock<media::MockFilterCallback> callback;
EXPECT_CALL(callback, OnFilterCallback());
EXPECT_CALL(callback, OnCallbackDestroyed());
+
data_source_->Stop(callback.NewCallback());
MessageLoop::current()->RunAllPending();
@@ -148,23 +142,17 @@ class SimpleDataSourceTest : public testing::Test {
}
}
- void ReleaseBridge() {
- ignore_result(bridge_.release());
- }
-
- void ReleaseBridgeFactory() {
- ignore_result(bridge_factory_.release());
- }
-
MOCK_METHOD1(ReadCallback, void(size_t size));
protected:
+ GURL gurl_;
scoped_ptr<MessageLoop> message_loop_;
- scoped_ptr<NiceMock<MockMediaResourceLoaderBridgeFactory> > bridge_factory_;
- scoped_ptr<NiceMock<MockResourceLoaderBridge> > bridge_;
+ NiceMock<MockWebURLLoader>* url_loader_;
scoped_refptr<SimpleDataSource> data_source_;
StrictMock<media::MockFilterHost> host_;
StrictMock<media::MockFilterCallback> callback_;
+ scoped_ptr<NiceMock<MockWebFrame> > frame_;
+
char data_[kDataSize];
DISALLOW_COPY_AND_ASSIGN(SimpleDataSourceTest);
@@ -189,13 +177,16 @@ TEST_F(SimpleDataSourceTest, InitializeFile) {
}
TEST_F(SimpleDataSourceTest, InitializeData) {
+ frame_.reset(new NiceMock<MockWebFrame>());
+ url_loader_ = new NiceMock<MockWebURLLoader>();
+
data_source_ = new SimpleDataSource(MessageLoop::current(),
- bridge_factory_.get());
+ frame_.get());
EXPECT_TRUE(data_source_->IsUrlSupported(kDataUrl));
- CHECK(data_source_);
// There is no need to provide a message loop to data source.
data_source_->set_host(&host_);
+ data_source_->SetURLLoaderForTest(url_loader_);
EXPECT_CALL(host_, SetLoaded(true));
EXPECT_CALL(host_, SetTotalBytes(sizeof(kDataUrlDecoded)));
@@ -218,9 +209,7 @@ TEST_F(SimpleDataSourceTest, RequestFailed) {
TEST_F(SimpleDataSourceTest, StopWhenDownloading) {
InitializeDataSource(kHttpUrl);
- EXPECT_CALL(*bridge_, Cancel());
- EXPECT_CALL(*bridge_, OnDestroy())
- .WillOnce(Invoke(this, &SimpleDataSourceTest::ReleaseBridge));
+ EXPECT_CALL(*url_loader_, cancel());
EXPECT_CALL(callback_, OnCallbackDestroyed());
DestroyDataSource();
}
diff --git a/webkit/glue/mimetype_unittest.cc b/webkit/glue/mimetype_unittest.cc
index 1c2e5f4..3f17e79 100644
--- a/webkit/glue/mimetype_unittest.cc
+++ b/webkit/glue/mimetype_unittest.cc
@@ -23,12 +23,12 @@ class MimeTypeTests : public TestShellTest {
test_shell_->WaitTestFinished();
}
- void CheckMimeType(const char* mimetype, const std::wstring& expected) {
+ void CheckMimeType(const char* mimetype, const std::string& expected) {
std::string path("contenttype?");
GURL url(test_server_.GetURL(path + mimetype));
LoadURL(url);
WebFrame* frame = test_shell_->webView()->mainFrame();
- EXPECT_EQ(expected, webkit_glue::DumpDocumentText(frame));
+ EXPECT_EQ(expected, UTF16ToASCII(webkit_glue::DumpDocumentText(frame)));
}
UnittestTestServer test_server_;
@@ -37,8 +37,8 @@ class MimeTypeTests : public TestShellTest {
TEST_F(MimeTypeTests, MimeTypeTests) {
ASSERT_TRUE(test_server_.Start());
- std::wstring expected_src(L"<html>\n<body>\n"
- L"<p>HTML text</p>\n</body>\n</html>\n");
+ std::string expected_src("<html>\n<body>\n"
+ "<p>HTML text</p>\n</body>\n</html>\n");
// These files should all be displayed as plain text.
const char* plain_text[] = {
@@ -66,7 +66,7 @@ TEST_F(MimeTypeTests, MimeTypeTests) {
"application/xhtml+xml",
};
for (size_t i = 0; i < arraysize(html_src); ++i) {
- CheckMimeType(html_src[i], L"HTML text");
+ CheckMimeType(html_src[i], "HTML text");
}
// These shouldn't be rendered as text or HTML, but shouldn't download
@@ -78,7 +78,7 @@ TEST_F(MimeTypeTests, MimeTypeTests) {
"image/bmp",
};
for (size_t i = 0; i < arraysize(not_text); ++i) {
- CheckMimeType(not_text[i], L"");
+ CheckMimeType(not_text[i], "");
test_shell_->webView()->mainFrame()->stopLoading();
}
diff --git a/webkit/glue/mock_resource_loader_bridge.h b/webkit/glue/mock_resource_loader_bridge.h
deleted file mode 100644
index 49c41ed..0000000
--- a/webkit/glue/mock_resource_loader_bridge.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_MOCK_RESOURCE_LOADER_BRIDGE_H_
-#define WEBKIT_GLUE_MOCK_RESOURCE_LOADER_BRIDGE_H_
-
-#include "testing/gmock/include/gmock/gmock.h"
-#include "webkit/glue/resource_loader_bridge.h"
-
-class FilePath;
-
-namespace webkit_glue {
-
-class MockResourceLoaderBridge : public webkit_glue::ResourceLoaderBridge {
- public:
- MockResourceLoaderBridge() {
- }
-
- virtual ~MockResourceLoaderBridge() {
- OnDestroy();
- }
-
- MOCK_METHOD2(AppendDataToUpload, void(const char* data, int data_len));
- MOCK_METHOD4(AppendFileRangeToUpload,
- void(const FilePath& file_path,
- uint64 offset,
- uint64 length,
- const base::Time& expected_modification_time));
- MOCK_METHOD1(AppendBlobToUpload, void(const GURL& blob_url));
- MOCK_METHOD1(SetUploadIdentifier, void(int64 identifier));
- MOCK_METHOD1(Start, bool(ResourceLoaderBridge::Peer* peer));
- MOCK_METHOD0(Cancel, void());
- MOCK_METHOD1(SetDefersLoading, void(bool value));
- MOCK_METHOD1(SyncLoad, void(SyncLoadResponse* response));
- MOCK_METHOD0(OnDestroy, void());
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MockResourceLoaderBridge);
-};
-
-} // namespace webkit_glue
-
-#endif // WEBKIT_GLUE_MOCK_RESOURCE_LOADER_BRIDGE_H_
diff --git a/webkit/glue/multipart_response_delegate.cc b/webkit/glue/multipart_response_delegate.cc
index 99a9e4c..b8c7758 100644
--- a/webkit/glue/multipart_response_delegate.cc
+++ b/webkit/glue/multipart_response_delegate.cc
@@ -316,7 +316,8 @@ bool MultipartResponseDelegate::ReadMultipartBoundary(
bool MultipartResponseDelegate::ReadContentRanges(
const WebURLResponse& response,
int* content_range_lower_bound,
- int* content_range_upper_bound) {
+ int* content_range_upper_bound,
+ int* content_range_instance_size) {
std::string content_range = response.httpHeaderField("Content-Range").utf8();
if (content_range.empty()) {
@@ -336,12 +337,20 @@ bool MultipartResponseDelegate::ReadContentRanges(
// Skip over the initial space.
byte_range_lower_bound_start_offset++;
+ // Find the lower bound.
size_t byte_range_lower_bound_end_offset =
content_range.find("-", byte_range_lower_bound_start_offset);
if (byte_range_lower_bound_end_offset == std::string::npos) {
return false;
}
+ size_t byte_range_lower_bound_characters =
+ byte_range_lower_bound_end_offset - byte_range_lower_bound_start_offset;
+ std::string byte_range_lower_bound =
+ content_range.substr(byte_range_lower_bound_start_offset,
+ byte_range_lower_bound_characters);
+
+ // Find the upper bound.
size_t byte_range_upper_bound_start_offset =
byte_range_lower_bound_end_offset + 1;
@@ -351,16 +360,31 @@ bool MultipartResponseDelegate::ReadContentRanges(
return false;
}
- if (!base::StringToInt(
- content_range.begin() + byte_range_lower_bound_start_offset,
- content_range.begin() + byte_range_lower_bound_end_offset,
- content_range_lower_bound))
- return false;
+ size_t byte_range_upper_bound_characters =
+ byte_range_upper_bound_end_offset - byte_range_upper_bound_start_offset;
+ std::string byte_range_upper_bound =
+ content_range.substr(byte_range_upper_bound_start_offset,
+ byte_range_upper_bound_characters);
+
+ // Find the instance size.
+ size_t byte_range_instance_size_start_offset =
+ byte_range_upper_bound_end_offset + 1;
+
+ size_t byte_range_instance_size_end_offset =
+ content_range.length();
- if (!base::StringToInt(
- content_range.begin() + byte_range_upper_bound_start_offset,
- content_range.begin() + byte_range_upper_bound_end_offset,
- content_range_upper_bound))
+ size_t byte_range_instance_size_characters =
+ byte_range_instance_size_end_offset -
+ byte_range_instance_size_start_offset;
+ std::string byte_range_instance_size =
+ content_range.substr(byte_range_instance_size_start_offset,
+ byte_range_instance_size_characters);
+
+ if (!base::StringToInt(byte_range_lower_bound, content_range_lower_bound))
+ return false;
+ if (!base::StringToInt(byte_range_upper_bound, content_range_upper_bound))
+ return false;
+ if (!base::StringToInt(byte_range_instance_size, content_range_instance_size))
return false;
return true;
}
diff --git a/webkit/glue/multipart_response_delegate.h b/webkit/glue/multipart_response_delegate.h
index aded54a..0500983 100644
--- a/webkit/glue/multipart_response_delegate.h
+++ b/webkit/glue/multipart_response_delegate.h
@@ -92,7 +92,8 @@ class MultipartResponseDelegate {
// Returns true on success.
static bool ReadContentRanges(const WebKit::WebURLResponse& response,
int* content_range_lower_bound,
- int* content_range_upper_bound);
+ int* content_range_upper_bound,
+ int* content_range_instance_size);
private:
friend class MultipartResponseDelegateTester; // For unittests.
diff --git a/webkit/glue/multipart_response_delegate_unittest.cc b/webkit/glue/multipart_response_delegate_unittest.cc
index fab798c..1837cb5 100644
--- a/webkit/glue/multipart_response_delegate_unittest.cc
+++ b/webkit/glue/multipart_response_delegate_unittest.cc
@@ -550,10 +550,12 @@ TEST(MultipartResponseTest, MultipartContentRangesTest) {
int content_range_lower_bound = 0;
int content_range_upper_bound = 0;
+ int content_range_instance_size = 0;
bool result = MultipartResponseDelegate::ReadContentRanges(
response1, &content_range_lower_bound,
- &content_range_upper_bound);
+ &content_range_upper_bound,
+ &content_range_instance_size);
EXPECT_EQ(result, true);
EXPECT_EQ(content_range_lower_bound, 1000);
@@ -567,10 +569,12 @@ TEST(MultipartResponseTest, MultipartContentRangesTest) {
content_range_lower_bound = 0;
content_range_upper_bound = 0;
+ content_range_instance_size = 0;
result = MultipartResponseDelegate::ReadContentRanges(
response2, &content_range_lower_bound,
- &content_range_upper_bound);
+ &content_range_upper_bound,
+ &content_range_instance_size);
EXPECT_EQ(result, false);
@@ -582,10 +586,12 @@ TEST(MultipartResponseTest, MultipartContentRangesTest) {
content_range_lower_bound = 0;
content_range_upper_bound = 0;
+ content_range_instance_size = 0;
result = MultipartResponseDelegate::ReadContentRanges(
response3, &content_range_lower_bound,
- &content_range_upper_bound);
+ &content_range_upper_bound,
+ &content_range_instance_size);
EXPECT_EQ(result, true);
EXPECT_EQ(content_range_lower_bound, 1000);
@@ -598,10 +604,12 @@ TEST(MultipartResponseTest, MultipartContentRangesTest) {
content_range_lower_bound = 0;
content_range_upper_bound = 0;
+ content_range_instance_size = 0;
result = MultipartResponseDelegate::ReadContentRanges(
response4, &content_range_lower_bound,
- &content_range_upper_bound);
+ &content_range_upper_bound,
+ &content_range_instance_size);
EXPECT_EQ(result, false);
}
diff --git a/webkit/glue/plugins/DEPS b/webkit/glue/plugins/DEPS
deleted file mode 100644
index cfee702..0000000
--- a/webkit/glue/plugins/DEPS
+++ /dev/null
@@ -1,4 +0,0 @@
-include_rules = [
- "+ppapi",
- "+printing",
-]
diff --git a/webkit/glue/plugins/carbon_plugin_window_tracker_mac.cc b/webkit/glue/plugins/carbon_plugin_window_tracker_mac.cc
deleted file mode 100644
index c4ae72d..0000000
--- a/webkit/glue/plugins/carbon_plugin_window_tracker_mac.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (c) 2009 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/logging.h"
-#include "webkit/glue/plugins/carbon_plugin_window_tracker_mac.h"
-
-CarbonPluginWindowTracker::CarbonPluginWindowTracker() {
-}
-
-CarbonPluginWindowTracker* CarbonPluginWindowTracker::SharedInstance() {
- static CarbonPluginWindowTracker* tracker = new CarbonPluginWindowTracker();
- return tracker;
-}
-
-WindowRef CarbonPluginWindowTracker::CreateDummyWindowForDelegate(
- OpaquePluginRef delegate) {
- // The real size will be set by the plugin instance, once that size is known.
- Rect window_bounds = { 0, 0, 100, 100 };
- WindowRef new_ref = NULL;
- if (CreateNewWindow(kDocumentWindowClass,
- kWindowNoTitleBarAttribute,
- &window_bounds,
- &new_ref) == noErr) {
- window_to_delegate_map_[new_ref] = delegate;
- delegate_to_window_map_[delegate] = new_ref;
- }
- return new_ref;
-}
-
-OpaquePluginRef CarbonPluginWindowTracker::GetDelegateForDummyWindow(
- WindowRef window) const {
- WindowToDelegateMap::const_iterator i = window_to_delegate_map_.find(window);
- if (i != window_to_delegate_map_.end())
- return i->second;
- return NULL;
-}
-
-WindowRef CarbonPluginWindowTracker::GetDummyWindowForDelegate(
- OpaquePluginRef delegate) const {
- DelegateToWindowMap::const_iterator i =
- delegate_to_window_map_.find(delegate);
- if (i != delegate_to_window_map_.end())
- return i->second;
- return NULL;
-}
-
-void CarbonPluginWindowTracker::DestroyDummyWindowForDelegate(
- OpaquePluginRef delegate, WindowRef window) {
- DCHECK(GetDelegateForDummyWindow(window) == delegate);
- window_to_delegate_map_.erase(window);
- delegate_to_window_map_.erase(delegate);
- if (window) // Check just in case the initial window creation failed.
- DisposeWindow(window);
-}
diff --git a/webkit/glue/plugins/carbon_plugin_window_tracker_mac.h b/webkit/glue/plugins/carbon_plugin_window_tracker_mac.h
deleted file mode 100644
index 90fc318..0000000
--- a/webkit/glue/plugins/carbon_plugin_window_tracker_mac.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) 2009 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 WEBKIT_GLUE_PLUGINS_CARBON_PLUGIN_WINDOW_TRACKER_MAC_H_
-#define WEBKIT_GLUE_PLUGINS_CARBON_PLUGIN_WINDOW_TRACKER_MAC_H_
-
-#include <Carbon/Carbon.h>
-#include <map>
-
-#include "base/basictypes.h"
-
-// This is really a WebPluginDelegateImpl, but that class is private to the
-// framework, and these functions are called from a dylib.
-typedef void* OpaquePluginRef;
-
-// Creates and tracks the invisible windows that are necessary for
-// Carbon-event-model plugins.
-//
-// Serves as a bridge between plugin delegate instances and the Carbon
-// interposing library. The Carbon functions we interpose work in terms of
-// WindowRefs, and we need to be able to map from those back to the plugin
-// delegates that know what we should claim about the state of the window.
-class __attribute__((visibility("default"))) CarbonPluginWindowTracker {
- public:
- CarbonPluginWindowTracker();
-
- // Returns the shared window tracker instance.
- static CarbonPluginWindowTracker* SharedInstance();
-
- // Creates a new carbon window associated with |delegate|.
- WindowRef CreateDummyWindowForDelegate(OpaquePluginRef delegate);
-
- // Returns the WebPluginDelegate associated with the given dummy window.
- OpaquePluginRef GetDelegateForDummyWindow(WindowRef window) const;
-
- // Returns the dummy window associated with |delegate|.
- WindowRef GetDummyWindowForDelegate(OpaquePluginRef delegate) const;
-
- // Destroys the dummy window for |delegate|.
- void DestroyDummyWindowForDelegate(OpaquePluginRef delegate,
- WindowRef window);
-
- private:
- typedef std::map<WindowRef, OpaquePluginRef> WindowToDelegateMap;
- typedef std::map<OpaquePluginRef, WindowRef> DelegateToWindowMap;
- WindowToDelegateMap window_to_delegate_map_;
- DelegateToWindowMap delegate_to_window_map_;
-
- DISALLOW_COPY_AND_ASSIGN(CarbonPluginWindowTracker);
-};
-
-#endif // WEBKIT_GLUE_PLUGINS_CARBON_PLUGIN_WINDOW_TRACKER_MAC_H_
diff --git a/webkit/glue/plugins/coregraphics_private_symbols_mac.h b/webkit/glue/plugins/coregraphics_private_symbols_mac.h
deleted file mode 100644
index 0342d6f..0000000
--- a/webkit/glue/plugins/coregraphics_private_symbols_mac.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2009 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 WEBKIT_GLUE_PLUGINS_COREGRAPHICS_PRIVATE_SYMBOLS_MAC_H_
-#define WEBKIT_GLUE_PLUGINS_COREGRAPHICS_PRIVATE_SYMBOLS_MAC_H_
-
-// These are CoreGraphics SPI, verified to exist in both 10.5 and 10.6.
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Copies the contents of the window with id |wid| into the given rect in the
-// given context
-OSStatus CGContextCopyWindowCaptureContentsToRect(
- CGContextRef, CGRect, int cid, int wid, int unknown);
-
-// Returns the connection ID we need for the third argument to
-// CGContextCopyWindowCaptureContentsToRect
-int _CGSDefaultConnection(void);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // WEBKIT_GLUE_PLUGINS_COREGRAPHICS_PRIVATE_SYMBOLS_MAC_H_
diff --git a/webkit/glue/plugins/default_plugin_shared.h b/webkit/glue/plugins/default_plugin_shared.h
deleted file mode 100644
index 79d06b3..0000000
--- a/webkit/glue/plugins/default_plugin_shared.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// 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.
-//
-// Thes file contains stuff that should be shared among projects that do some
-// special handling with default plugin
-
-#ifndef WEBKIT_GLUE_PLUGINS_DEFAULT_PLUGIN_SHARED_H
-#define WEBKIT_GLUE_PLUGINS_DEFAULT_PLUGIN_SHARED_H
-
-namespace default_plugin {
-
-// We use the NPNGetValue host function to send notification message to host.
-// This corresponds to NPNVariable defined in npapi.h, and should be chosen so
-// as to not overlap values if NPAPI is updated.
-
-const int kMissingPluginStatusStart = 5000;
-
-enum MissingPluginStatus {
- MISSING_PLUGIN_AVAILABLE,
- MISSING_PLUGIN_USER_STARTED_DOWNLOAD
-};
-
-#if defined(OS_WIN)
-#include <windows.h>
-const int kInstallMissingPluginMessage = WM_APP + 117;
-#endif
-
-} // namespace default_plugin
-
-#endif // WEBKIT_GLUE_PLUGINS_DEFAULT_PLUGIN_SHARED_H
diff --git a/webkit/glue/plugins/gtk_plugin_container.cc b/webkit/glue/plugins/gtk_plugin_container.cc
deleted file mode 100644
index c80bbf1..0000000
--- a/webkit/glue/plugins/gtk_plugin_container.cc
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright (c) 2009 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 "webkit/glue/plugins/gtk_plugin_container.h"
-
-#include <gtk/gtk.h>
-
-#include "base/basictypes.h"
-
-namespace {
-
-// NOTE: This class doesn't have constructors/destructors, it is created
-// through GLib's object management.
-class GtkPluginContainer : public GtkSocket {
- public:
- // Sets the requested size of the widget.
- void set_size(int width, int height) {
- width_ = width;
- height_ = height;
- }
-
- // Casts a widget into a GtkPluginContainer, after checking the type.
- template <class T>
- static GtkPluginContainer *CastChecked(T *instance) {
- return G_TYPE_CHECK_INSTANCE_CAST(instance, GetType(), GtkPluginContainer);
- }
-
- // Create and register our custom container type with GTK.
- static GType GetType() {
- static GType type = 0; // We only want to register our type once.
- if (!type) {
- static const GTypeInfo info = {
- sizeof(GtkSocketClass),
- NULL, NULL,
- static_cast<GClassInitFunc>(&ClassInit),
- NULL, NULL,
- sizeof(GtkPluginContainer),
- 0, &InstanceInit,
- };
- type = g_type_register_static(GTK_TYPE_SOCKET,
- "GtkPluginContainer",
- &info,
- static_cast<GTypeFlags>(0));
- }
- return type;
- }
-
- // Implementation of the class initializer.
- static void ClassInit(gpointer klass, gpointer class_data_unusued) {
- GtkWidgetClass* widget_class = reinterpret_cast<GtkWidgetClass*>(klass);
- widget_class->size_request = &HandleSizeRequest;
- }
-
- // Implementation of the instance initializer (constructor).
- static void InstanceInit(GTypeInstance *instance, gpointer klass) {
- GtkPluginContainer *container = CastChecked(instance);
- container->set_size(0, 0);
- }
-
- // Report our allocation size during size requisition.
- static void HandleSizeRequest(GtkWidget* widget,
- GtkRequisition* requisition) {
- GtkPluginContainer *container = CastChecked(widget);
- requisition->width = container->width_;
- requisition->height = container->height_;
- }
-
- int width_;
- int height_;
- DISALLOW_IMPLICIT_CONSTRUCTORS(GtkPluginContainer);
-};
-
-} // anonymous namespace
-
-// Create a new instance of our GTK widget object.
-GtkWidget* gtk_plugin_container_new() {
- return GTK_WIDGET(g_object_new(GtkPluginContainer::GetType(), NULL));
-}
-
-void gtk_plugin_container_set_size(GtkWidget *widget, int width, int height) {
- GtkPluginContainer::CastChecked(widget)->set_size(width, height);
- // Signal the parent that the size request has changed.
- gtk_widget_queue_resize_no_redraw(widget);
-}
diff --git a/webkit/glue/plugins/gtk_plugin_container.h b/webkit/glue/plugins/gtk_plugin_container.h
deleted file mode 100644
index eed6b94..0000000
--- a/webkit/glue/plugins/gtk_plugin_container.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2009 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 WEBKIT_GLUE_PLUGINS_GTK_PLUGIN_CONTAINER_H_
-#define WEBKIT_GLUE_PLUGINS_GTK_PLUGIN_CONTAINER_H_
-
-// Windowed plugins are embedded via XEmbed, which is implemented by
-// GtkPlug/GtkSocket. But we want to control sizing and positioning
-// directly, so we need a subclass of GtkSocket that sidesteps the
-// size_request handler.
-//
-// The custom size_request handler just reports the size set by
-// gtk_plugin_container_set_size.
-
-typedef struct _GtkWidget GtkWidget;
-
-// Return a new GtkPluginContainer.
-// Intentionally GTK-style here since we're creating a custom GTK widget.
-// This is a GtkSocket subclass; see its documentation for available methods.
-GtkWidget* gtk_plugin_container_new();
-
-// Sets the size of the GtkPluginContainer.
-void gtk_plugin_container_set_size(GtkWidget *widget, int width, int height);
-
-#endif // WEBKIT_GLUE_PLUGINS_GTK_PLUGIN_CONTAINER_H_
diff --git a/webkit/glue/plugins/gtk_plugin_container_manager.cc b/webkit/glue/plugins/gtk_plugin_container_manager.cc
deleted file mode 100644
index 2f82b24..0000000
--- a/webkit/glue/plugins/gtk_plugin_container_manager.cc
+++ /dev/null
@@ -1,155 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/gtk_plugin_container_manager.h"
-
-#include <gtk/gtk.h>
-
-#include "base/logging.h"
-#include "gfx/gtk_util.h"
-#include "webkit/glue/plugins/gtk_plugin_container.h"
-#include "webkit/glue/plugins/webplugin.h"
-
-GtkPluginContainerManager::GtkPluginContainerManager() : host_widget_(NULL) {}
-
-GtkPluginContainerManager::~GtkPluginContainerManager() {}
-
-GtkWidget* GtkPluginContainerManager::CreatePluginContainer(
- gfx::PluginWindowHandle id) {
- DCHECK(host_widget_);
- GtkWidget *widget = gtk_plugin_container_new();
- plugin_window_to_widget_map_.insert(std::make_pair(id, widget));
-
- // The Realize callback is responsible for adding the plug into the socket.
- // The reason is 2-fold:
- // - the plug can't be added until the socket is realized, but this may not
- // happen until the socket is attached to a top-level window, which isn't the
- // case for background tabs.
- // - when dragging tabs, the socket gets unrealized, which breaks the XEMBED
- // connection. We need to make it again when the tab is reattached, and the
- // socket gets realized again.
- //
- // Note, the RealizeCallback relies on the plugin_window_to_widget_map_ to
- // have the mapping.
- g_signal_connect(widget, "realize",
- G_CALLBACK(RealizeCallback), this);
-
- // Don't destroy the widget when the plug is removed.
- g_signal_connect(widget, "plug-removed",
- G_CALLBACK(gtk_true), NULL);
-
- gtk_container_add(GTK_CONTAINER(host_widget_), widget);
- gtk_widget_show(widget);
-
- return widget;
-}
-
-void GtkPluginContainerManager::DestroyPluginContainer(
- gfx::PluginWindowHandle id) {
- DCHECK(host_widget_);
- GtkWidget* widget = MapIDToWidget(id);
- if (widget)
- gtk_widget_destroy(widget);
-
- plugin_window_to_widget_map_.erase(id);
-}
-
-void GtkPluginContainerManager::MovePluginContainer(
- const webkit_glue::WebPluginGeometry& move) {
- DCHECK(host_widget_);
- GtkWidget *widget = MapIDToWidget(move.window);
- if (!widget)
- return;
-
- DCHECK(!GTK_WIDGET_NO_WINDOW(widget));
-
- if (!move.visible) {
- gtk_widget_hide(widget);
- return;
- }
-
- gtk_widget_show(widget);
-
- if (!move.rects_valid)
- return;
-
- // TODO(piman): if the widget hasn't been realized (e.g. the tab has been
- // torn off and the parent gtk widget has been detached from the hierarchy),
- // we lose the cutout information.
- if (GTK_WIDGET_REALIZED(widget)) {
- GdkRectangle clip_rect = move.clip_rect.ToGdkRectangle();
- GdkRegion* clip_region = gdk_region_rectangle(&clip_rect);
- gfx::SubtractRectanglesFromRegion(clip_region, move.cutout_rects);
- gdk_window_shape_combine_region(widget->window, clip_region, 0, 0);
- gdk_region_destroy(clip_region);
- }
-
- // Update the window position. Resizing is handled by WebPluginDelegate.
- // TODO(deanm): Verify that we only need to move and not resize.
- // TODO(evanm): we should cache the last shape and position and skip all
- // of this business in the common case where nothing has changed.
- int current_x, current_y;
-
- // Until the above TODO is resolved, we can grab the last position
- // off of the GtkFixed with a bit of hackery.
- GValue value = {0};
- g_value_init(&value, G_TYPE_INT);
- gtk_container_child_get_property(GTK_CONTAINER(host_widget_), widget,
- "x", &value);
- current_x = g_value_get_int(&value);
- gtk_container_child_get_property(GTK_CONTAINER(host_widget_), widget,
- "y", &value);
- current_y = g_value_get_int(&value);
- g_value_unset(&value);
-
- if (move.window_rect.x() != current_x ||
- move.window_rect.y() != current_y) {
- // Calling gtk_fixed_move unnecessarily is a no-no, as it causes the
- // parent window to repaint!
- gtk_fixed_move(GTK_FIXED(host_widget_),
- widget,
- move.window_rect.x(),
- move.window_rect.y());
- }
-
- gtk_plugin_container_set_size(widget,
- move.window_rect.width(),
- move.window_rect.height());
-}
-
-GtkWidget* GtkPluginContainerManager::MapIDToWidget(
- gfx::PluginWindowHandle id) {
- PluginWindowToWidgetMap::const_iterator i =
- plugin_window_to_widget_map_.find(id);
- if (i != plugin_window_to_widget_map_.end())
- return i->second;
-
- LOG(ERROR) << "Request for widget host for unknown window id " << id;
-
- return NULL;
-}
-
-gfx::PluginWindowHandle GtkPluginContainerManager::MapWidgetToID(
- GtkWidget* widget) {
- for (PluginWindowToWidgetMap::const_iterator i =
- plugin_window_to_widget_map_.begin();
- i != plugin_window_to_widget_map_.end(); ++i) {
- if (i->second == widget)
- return i->first;
- }
-
- LOG(ERROR) << "Request for id for unknown widget";
- return 0;
-}
-
-// static
-void GtkPluginContainerManager::RealizeCallback(GtkWidget* widget,
- void* user_data) {
- GtkPluginContainerManager* plugin_container_manager =
- static_cast<GtkPluginContainerManager*>(user_data);
-
- gfx::PluginWindowHandle id = plugin_container_manager->MapWidgetToID(widget);
- if (id)
- gtk_socket_add_id(GTK_SOCKET(widget), id);
-}
diff --git a/webkit/glue/plugins/gtk_plugin_container_manager.h b/webkit/glue/plugins/gtk_plugin_container_manager.h
deleted file mode 100644
index 7f7db8d..0000000
--- a/webkit/glue/plugins/gtk_plugin_container_manager.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (c) 2009 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 WEBKIT_GLUE_PLUGINS_GTK_PLUGIN_CONTAINER_MANAGER_H_
-#define WEBKIT_GLUE_PLUGINS_GTK_PLUGIN_CONTAINER_MANAGER_H_
-
-#include <gtk/gtk.h>
-#include <map>
-
-#include "gfx/native_widget_types.h"
-
-typedef struct _GtkWidget GtkWidget;
-
-namespace webkit_glue {
-struct WebPluginGeometry;
-}
-
-// Helper class that creates and manages plugin containers (GtkSocket).
-class GtkPluginContainerManager {
- public:
- GtkPluginContainerManager();
- ~GtkPluginContainerManager();
-
- // Sets the widget that will host the plugin containers. Must be a GtkFixed.
- void set_host_widget(GtkWidget *widget) { host_widget_ = widget; }
-
- // Creates a new plugin container, for a given plugin XID.
- GtkWidget* CreatePluginContainer(gfx::PluginWindowHandle id);
-
- // Destroys a plugin container, given the plugin XID.
- void DestroyPluginContainer(gfx::PluginWindowHandle id);
-
- // Takes an update from WebKit about a plugin's position and side and moves
- // the plugin accordingly.
- void MovePluginContainer(const webkit_glue::WebPluginGeometry& move);
-
- private:
- // Maps a plugin XID to the corresponding container widget.
- GtkWidget* MapIDToWidget(gfx::PluginWindowHandle id);
-
- // Maps a container widget to the corresponding plugin XID.
- gfx::PluginWindowHandle MapWidgetToID(GtkWidget* widget);
-
- // Callback for when the plugin container gets realized, at which point it
- // plugs the plugin XID.
- static void RealizeCallback(GtkWidget *widget, void *user_data);
-
- // Parent of the plugin containers.
- GtkWidget* host_widget_;
-
- // A map that associates plugin containers to the plugin XID.
- typedef std::map<gfx::PluginWindowHandle, GtkWidget*> PluginWindowToWidgetMap;
- PluginWindowToWidgetMap plugin_window_to_widget_map_;
-};
-
-#endif // WEBKIT_GLUE_PLUGINS_GTK_PLUGIN_CONTAINER_MANAGER_H_
diff --git a/webkit/glue/plugins/npapi_extension_thunk.cc b/webkit/glue/plugins/npapi_extension_thunk.cc
deleted file mode 100644
index 05a9c5d..0000000
--- a/webkit/glue/plugins/npapi_extension_thunk.cc
+++ /dev/null
@@ -1,551 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/npapi_extension_thunk.h"
-
-#include "base/logging.h"
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-#include "third_party/npapi/bindings/npapi_extensions.h"
-#include "webkit/glue/plugins/plugin_instance.h"
-#include "webkit/glue/plugins/webplugin.h"
-#include "webkit/glue/plugins/webplugin_delegate.h"
-#include "webkit/glue/webkit_glue.h"
-
-// FindInstance()
-// Finds a PluginInstance from an NPP.
-// The caller must take a reference if needed.
-static NPAPI::PluginInstance* FindInstance(NPP id) {
- if (id == NULL) {
- NOTREACHED();
- return NULL;
- }
- return static_cast<NPAPI::PluginInstance*>(id->ndata);
-}
-
-// 2D device API ---------------------------------------------------------------
-
-static NPError Device2DQueryCapability(NPP id, int32_t capability,
- int32_t* value) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin) {
- plugin->webplugin()->delegate()->Device2DQueryCapability(capability, value);
- return NPERR_NO_ERROR;
- } else {
- return NPERR_GENERIC_ERROR;
- }
-}
-
-static NPError Device2DQueryConfig(NPP id,
- const NPDeviceConfig* request,
- NPDeviceConfig* obtain) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin) {
- return plugin->webplugin()->delegate()->Device2DQueryConfig(
- static_cast<const NPDeviceContext2DConfig*>(request),
- static_cast<NPDeviceContext2DConfig*>(obtain));
- }
- return NPERR_GENERIC_ERROR;
-}
-
-static NPError Device2DInitializeContext(NPP id,
- const NPDeviceConfig* config,
- NPDeviceContext* context) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin) {
- return plugin->webplugin()->delegate()->Device2DInitializeContext(
- static_cast<const NPDeviceContext2DConfig*>(config),
- static_cast<NPDeviceContext2D*>(context));
- }
- return NPERR_GENERIC_ERROR;
-}
-
-static NPError Device2DSetStateContext(NPP id,
- NPDeviceContext* context,
- int32_t state,
- intptr_t value) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin) {
- return plugin->webplugin()->delegate()->Device2DSetStateContext(
- static_cast<NPDeviceContext2D*>(context), state, value);
- }
- return NPERR_GENERIC_ERROR;
-}
-
-static NPError Device2DGetStateContext(NPP id,
- NPDeviceContext* context,
- int32_t state,
- intptr_t* value) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin) {
- return plugin->webplugin()->delegate()->Device2DGetStateContext(
- static_cast<NPDeviceContext2D*>(context), state, value);
- }
- return NPERR_GENERIC_ERROR;
-}
-
-static NPError Device2DFlushContext(NPP id,
- NPDeviceContext* context,
- NPDeviceFlushContextCallbackPtr callback,
- void* user_data) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin) {
- NPError err = plugin->webplugin()->delegate()->Device2DFlushContext(
- id, static_cast<NPDeviceContext2D*>(context), callback, user_data);
-
- // Invoke the callback to inform the caller the work was done.
- // TODO(brettw) this is probably not how we want this to work, this should
- // happen when the frame is painted so the plugin knows when it can draw
- // the next frame.
- if (callback != NULL)
- (*callback)(id, context, err, user_data);
-
- // Return any errors.
- return err;
- }
- return NPERR_GENERIC_ERROR;
-}
-
-static NPError Device2DDestroyContext(NPP id,
- NPDeviceContext* context) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin) {
- return plugin->webplugin()->delegate()->Device2DDestroyContext(
- static_cast<NPDeviceContext2D*>(context));
- }
- return NPERR_GENERIC_ERROR;
-}
-
-static NPError Device2DCreateBuffer(NPP id,
- NPDeviceContext* context,
- size_t size,
- int32_t* buffer_id) {
- return NPERR_GENERIC_ERROR;
-}
-
-static NPError Device2DDestroyBuffer(NPP id,
- NPDeviceContext* context,
- int32_t buffer_id) {
- return NPERR_GENERIC_ERROR;
-}
-
-static NPError Device2DMapBuffer(NPP id,
- NPDeviceContext* context,
- int32_t buffer_id,
- NPDeviceBuffer* buffer) {
- return NPERR_GENERIC_ERROR;
-}
-
-// 3D device API ---------------------------------------------------------------
-
-static NPError Device3DQueryCapability(NPP id, int32_t capability,
- int32_t* value) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin) {
- plugin->webplugin()->delegate()->Device3DQueryCapability(capability, value);
- return NPERR_NO_ERROR;
- } else {
- return NPERR_GENERIC_ERROR;
- }
-}
-
-static NPError Device3DQueryConfig(NPP id,
- const NPDeviceConfig* request,
- NPDeviceConfig* obtain) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin) {
- return plugin->webplugin()->delegate()->Device3DQueryConfig(
- static_cast<const NPDeviceContext3DConfig*>(request),
- static_cast<NPDeviceContext3DConfig*>(obtain));
- }
- return NPERR_GENERIC_ERROR;
-}
-
-static NPError Device3DInitializeContext(NPP id,
- const NPDeviceConfig* config,
- NPDeviceContext* context) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin) {
- return plugin->webplugin()->delegate()->Device3DInitializeContext(
- static_cast<const NPDeviceContext3DConfig*>(config),
- static_cast<NPDeviceContext3D*>(context));
- }
- return NPERR_GENERIC_ERROR;
-}
-
-static NPError Device3DSetStateContext(NPP id,
- NPDeviceContext* context,
- int32_t state,
- intptr_t value) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin) {
- return plugin->webplugin()->delegate()->Device3DSetStateContext(
- static_cast<NPDeviceContext3D*>(context), state, value);
- }
- return NPERR_GENERIC_ERROR;
-}
-
-static NPError Device3DGetStateContext(NPP id,
- NPDeviceContext* context,
- int32_t state,
- intptr_t* value) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin) {
- return plugin->webplugin()->delegate()->Device3DGetStateContext(
- static_cast<NPDeviceContext3D*>(context), state, value);
- }
- return NPERR_GENERIC_ERROR;
-}
-
-static NPError Device3DFlushContext(NPP id,
- NPDeviceContext* context,
- NPDeviceFlushContextCallbackPtr callback,
- void* user_data) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin) {
- return plugin->webplugin()->delegate()->Device3DFlushContext(
- id, static_cast<NPDeviceContext3D*>(context), callback, user_data);
- }
- return NPERR_GENERIC_ERROR;
-}
-
-static NPError Device3DDestroyContext(NPP id,
- NPDeviceContext* context) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin) {
- return plugin->webplugin()->delegate()->Device3DDestroyContext(
- static_cast<NPDeviceContext3D*>(context));
- }
- return NPERR_GENERIC_ERROR;
-}
-
-static NPError Device3DCreateBuffer(NPP id,
- NPDeviceContext* context,
- size_t size,
- int32_t* buffer_id) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin) {
- return plugin->webplugin()->delegate()->Device3DCreateBuffer(
- static_cast<NPDeviceContext3D*>(context), size, buffer_id);
- }
- return NPERR_GENERIC_ERROR;
-}
-
-static NPError Device3DDestroyBuffer(NPP id,
- NPDeviceContext* context,
- int32_t buffer_id) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin) {
- return plugin->webplugin()->delegate()->Device3DDestroyBuffer(
- static_cast<NPDeviceContext3D*>(context), buffer_id);
- }
- return NPERR_GENERIC_ERROR;
-}
-
-static NPError Device3DMapBuffer(NPP id,
- NPDeviceContext* context,
- int32_t buffer_id,
- NPDeviceBuffer* buffer) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin) {
- return plugin->webplugin()->delegate()->Device3DMapBuffer(
- static_cast<NPDeviceContext3D*>(context), buffer_id, buffer);
- }
- return NPERR_GENERIC_ERROR;
-}
-
-// Experimental 3D device API --------------------------------------------------
-
-static NPError Device3DGetNumConfigs(NPP id, int32_t* num_configs) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin) {
- return plugin->webplugin()->delegate()->Device3DGetNumConfigs(num_configs);
- }
- return NPERR_GENERIC_ERROR;
-}
-
-static NPError Device3DGetConfigAttribs(NPP id,
- int32_t config,
- int32_t* attrib_list) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin) {
- return plugin->webplugin()->delegate()->Device3DGetConfigAttribs(
- config,
- attrib_list);
- }
- return NPERR_GENERIC_ERROR;
-}
-
-static NPError Device3DCreateContext(NPP id,
- int32_t config,
- const int32_t* attrib_list,
- NPDeviceContext** context) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin) {
- return plugin->webplugin()->delegate()->Device3DCreateContext(
- config,
- attrib_list,
- reinterpret_cast<NPDeviceContext3D**>(context));
- }
- return NPERR_GENERIC_ERROR;
-}
-
-static NPError Device3DSynchronizeContext(
- NPP id,
- NPDeviceContext* context,
- NPDeviceSynchronizationMode mode,
- const int32_t* input_attrib_list,
- int32_t* output_attrib_list,
- NPDeviceSynchronizeContextCallbackPtr callback,
- void* callback_data) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin) {
- return plugin->webplugin()->delegate()->Device3DSynchronizeContext(
- id,
- static_cast<NPDeviceContext3D*>(context),
- mode,
- input_attrib_list,
- output_attrib_list,
- callback,
- callback_data);
- }
- return NPERR_GENERIC_ERROR;
-}
-
-static NPError Device3DRegisterCallback(
- NPP id,
- NPDeviceContext* context,
- int32_t callback_type,
- NPDeviceGenericCallbackPtr callback,
- void* callback_data) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin) {
- return plugin->webplugin()->delegate()->Device3DRegisterCallback(
- id,
- static_cast<NPDeviceContext3D*>(context),
- callback_type,
- callback,
- callback_data);
- }
- return NPERR_GENERIC_ERROR;
-}
-
-// Audio device API ------------------------------------------------------------
-
-static NPError DeviceAudioQueryCapability(NPP id, int32_t capability,
- int32_t* value) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin) {
- plugin->webplugin()->delegate()->DeviceAudioQueryCapability(capability,
- value);
- return NPERR_NO_ERROR;
- } else {
- return NPERR_GENERIC_ERROR;
- }
-}
-
-static NPError DeviceAudioQueryConfig(NPP id,
- const NPDeviceConfig* request,
- NPDeviceConfig* obtain) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin) {
- return plugin->webplugin()->delegate()->DeviceAudioQueryConfig(
- static_cast<const NPDeviceContextAudioConfig*>(request),
- static_cast<NPDeviceContextAudioConfig*>(obtain));
- }
- return NPERR_GENERIC_ERROR;
-}
-
-static NPError DeviceAudioInitializeContext(NPP id,
- const NPDeviceConfig* config,
- NPDeviceContext* context) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin) {
- return plugin->webplugin()->delegate()->DeviceAudioInitializeContext(
- static_cast<const NPDeviceContextAudioConfig*>(config),
- static_cast<NPDeviceContextAudio*>(context));
- }
- return NPERR_GENERIC_ERROR;
-}
-
-static NPError DeviceAudioSetStateContext(NPP id,
- NPDeviceContext* context,
- int32_t state,
- intptr_t value) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin) {
- return plugin->webplugin()->delegate()->DeviceAudioSetStateContext(
- static_cast<NPDeviceContextAudio*>(context), state, value);
- }
- return NPERR_GENERIC_ERROR;
-}
-
-static NPError DeviceAudioGetStateContext(NPP id,
- NPDeviceContext* context,
- int32_t state,
- intptr_t* value) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- return plugin->webplugin()->delegate()->DeviceAudioGetStateContext(
- static_cast<NPDeviceContextAudio*>(context), state, value);
-}
-
-static NPError DeviceAudioFlushContext(NPP id,
- NPDeviceContext* context,
- NPDeviceFlushContextCallbackPtr callback,
- void* user_data) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- return plugin->webplugin()->delegate()->DeviceAudioFlushContext(
- id, static_cast<NPDeviceContextAudio*>(context), callback, user_data);
-}
-
-static NPError DeviceAudioDestroyContext(NPP id,
- NPDeviceContext* context) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- return plugin->webplugin()->delegate()->DeviceAudioDestroyContext(
- static_cast<NPDeviceContextAudio*>(context));
-}
-// -----------------------------------------------------------------------------
-
-static NPDevice* AcquireDevice(NPP id, NPDeviceID device_id) {
- static NPDevice device_2d = {
- Device2DQueryCapability,
- Device2DQueryConfig,
- Device2DInitializeContext,
- Device2DSetStateContext,
- Device2DGetStateContext,
- Device2DFlushContext,
- Device2DDestroyContext,
- Device2DCreateBuffer,
- Device2DDestroyBuffer,
- Device2DMapBuffer,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- };
- static NPDevice device_3d = {
- Device3DQueryCapability,
- Device3DQueryConfig,
- Device3DInitializeContext,
- Device3DSetStateContext,
- Device3DGetStateContext,
- Device3DFlushContext,
- Device3DDestroyContext,
- Device3DCreateBuffer,
- Device3DDestroyBuffer,
- Device3DMapBuffer,
- Device3DGetNumConfigs,
- Device3DGetConfigAttribs,
- Device3DCreateContext,
- Device3DRegisterCallback,
- Device3DSynchronizeContext,
- };
- static NPDevice device_audio = {
- DeviceAudioQueryCapability,
- DeviceAudioQueryConfig,
- DeviceAudioInitializeContext,
- DeviceAudioSetStateContext,
- DeviceAudioGetStateContext,
- DeviceAudioFlushContext,
- DeviceAudioDestroyContext,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- };
-
- switch (device_id) {
- case NPPepper2DDevice:
- return const_cast<NPDevice*>(&device_2d);
- case NPPepper3DDevice:
- return const_cast<NPDevice*>(&device_3d);
- case NPPepperAudioDevice:
- return const_cast<NPDevice*>(&device_audio);
- default:
- return NULL;
- }
-}
-
-static NPError ChooseFile(NPP id,
- const char* mime_types,
- NPChooseFileMode mode,
- NPChooseFileCallback callback,
- void* user_data) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (!plugin)
- return NPERR_GENERIC_ERROR;
-
- if (!plugin->webplugin()->delegate()->ChooseFile(mime_types,
- static_cast<int>(mode),
- callback, user_data))
- return NPERR_GENERIC_ERROR;
-
- return NPERR_NO_ERROR;
-}
-
-static void NumberOfFindResultsChanged(NPP id, int total, bool final_result) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin) {
- plugin->webplugin()->delegate()->NumberOfFindResultsChanged(
- total, final_result);
- }
-}
-
-static void SelectedFindResultChanged(NPP id, int index) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin)
- plugin->webplugin()->delegate()->SelectedFindResultChanged(index);
-}
-
-static NPWidgetExtensions* GetWidgetExtensions(NPP id) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (!plugin)
- return NULL;
-
- return plugin->webplugin()->delegate()->GetWidgetExtensions();
-}
-
-static NPError NPSetCursor(NPP id, NPCursorType type) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (!plugin)
- return NPERR_GENERIC_ERROR;
-
- return plugin->webplugin()->delegate()->SetCursor(type) ?
- NPERR_NO_ERROR : NPERR_GENERIC_ERROR;
-}
-
-static NPFontExtensions* GetFontExtensions(NPP id) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (!plugin)
- return NULL;
-
- return plugin->webplugin()->delegate()->GetFontExtensions();
-}
-
-namespace NPAPI {
-
-NPError GetPepperExtensionsFunctions(void* value) {
- static const NPNExtensions kExtensions = {
- &AcquireDevice,
- &NumberOfFindResultsChanged,
- &SelectedFindResultChanged,
- &ChooseFile,
- &GetWidgetExtensions,
- &NPSetCursor,
- &GetFontExtensions,
- };
-
- // Return a pointer to the canonical function table.
- NPNExtensions* extensions = const_cast<NPNExtensions*>(&kExtensions);
- NPNExtensions** exts = reinterpret_cast<NPNExtensions**>(value);
- *exts = extensions;
- return NPERR_NO_ERROR;
-}
-
-} // namespace NPAPI
diff --git a/webkit/glue/plugins/npapi_extension_thunk.h b/webkit/glue/plugins/npapi_extension_thunk.h
deleted file mode 100644
index fada6bc..0000000
--- a/webkit/glue/plugins/npapi_extension_thunk.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2009 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 WEBKIT_GLUE_PLUGINS_NPAPI_EXTENSION_THUNK_H_
-#define WEBKIT_GLUE_PLUGINS_NPAPI_EXTENSION_THUNK_H_
-
-#include "third_party/npapi/bindings/npapi_extensions.h"
-
-// This file implements forwarding for the NPAPI "Pepper" extensions through to
-// the WebPluginDelegate associated with the plugin.
-
-namespace NPAPI {
-
-// Implements NPN_GetValue for the case of NPNVPepperExtensions. The function
-// pointers in the returned structure implement all the extensions.
-NPError GetPepperExtensionsFunctions(void* value);
-
-} // namespace NPAPI
-
-#endif // WEBKIT_GLUE_PLUGINS_NPAPI_EXTENSION_THUNK_H_
-
-
diff --git a/webkit/glue/plugins/pepper_audio.cc b/webkit/glue/plugins/pepper_audio.cc
deleted file mode 100644
index 1731d8a..0000000
--- a/webkit/glue/plugins/pepper_audio.cc
+++ /dev/null
@@ -1,389 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_audio.h"
-
-#include "base/logging.h"
-#include "ppapi/c/dev/ppb_audio_dev.h"
-#include "ppapi/c/dev/ppb_audio_trusted_dev.h"
-#include "ppapi/c/pp_completion_callback.h"
-#include "webkit/glue/plugins/pepper_common.h"
-
-namespace pepper {
-
-namespace {
-
-// PPB_AudioConfig -------------------------------------------------------------
-
-uint32_t RecommendSampleFrameCount(uint32_t requested_sample_frame_count);
-
-PP_Resource CreateStereo16bit(PP_Module module_id,
- PP_AudioSampleRate_Dev sample_rate,
- uint32_t sample_frame_count) {
- PluginModule* module = ResourceTracker::Get()->GetModule(module_id);
- if (!module)
- return 0;
-
- // TODO(brettw): Currently we don't actually check what the hardware
- // supports, so just allow sample rates of the "guaranteed working" ones.
- if (sample_rate != PP_AUDIOSAMPLERATE_44100 &&
- sample_rate != PP_AUDIOSAMPLERATE_48000)
- return 0;
-
- // TODO(brettw): Currently we don't actually query to get a value from the
- // hardware, so just validate the range.
- if (RecommendSampleFrameCount(sample_frame_count) != sample_frame_count)
- return 0;
-
- scoped_refptr<AudioConfig> config(new AudioConfig(module,
- sample_rate,
- sample_frame_count));
- return config->GetReference();
-}
-
-uint32_t RecommendSampleFrameCount(uint32_t requested_sample_frame_count) {
- // TODO(brettw) Currently we don't actually query to get a value from the
- // hardware, so we always return the input for in-range values.
- if (requested_sample_frame_count < PP_AUDIOMINSAMPLEFRAMECOUNT)
- return PP_AUDIOMINSAMPLEFRAMECOUNT;
- if (requested_sample_frame_count > PP_AUDIOMAXSAMPLEFRAMECOUNT)
- return PP_AUDIOMAXSAMPLEFRAMECOUNT;
- return requested_sample_frame_count;
-}
-
-PP_Bool IsAudioConfig(PP_Resource resource) {
- scoped_refptr<AudioConfig> config = Resource::GetAs<AudioConfig>(resource);
- return BoolToPPBool(!!config);
-}
-
-PP_AudioSampleRate_Dev GetSampleRate(PP_Resource config_id) {
- scoped_refptr<AudioConfig> config = Resource::GetAs<AudioConfig>(config_id);
- return config ? config->sample_rate() : PP_AUDIOSAMPLERATE_NONE;
-}
-
-uint32_t GetSampleFrameCount(PP_Resource config_id) {
- scoped_refptr<AudioConfig> config = Resource::GetAs<AudioConfig>(config_id);
- return config ? config->sample_frame_count() : 0;
-}
-
-const PPB_AudioConfig_Dev ppb_audioconfig = {
- &CreateStereo16bit,
- &RecommendSampleFrameCount,
- &IsAudioConfig,
- &GetSampleRate,
- &GetSampleFrameCount
-};
-
-// PPB_Audio -------------------------------------------------------------------
-
-PP_Resource Create(PP_Instance instance_id, PP_Resource config_id,
- PPB_Audio_Callback user_callback, void* user_data) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return 0;
- if (!user_callback)
- return 0;
- scoped_refptr<Audio> audio(new Audio(instance->module(), instance_id));
- if (!audio->Init(instance->delegate(), config_id,
- user_callback, user_data))
- return 0;
- return audio->GetReference();
-}
-
-PP_Bool IsAudio(PP_Resource resource) {
- scoped_refptr<Audio> audio = Resource::GetAs<Audio>(resource);
- return BoolToPPBool(!!audio);
-}
-
-PP_Resource GetCurrentConfiguration(PP_Resource audio_id) {
- scoped_refptr<Audio> audio = Resource::GetAs<Audio>(audio_id);
- return audio ? audio->GetCurrentConfiguration() : 0;
-}
-
-PP_Bool StartPlayback(PP_Resource audio_id) {
- scoped_refptr<Audio> audio = Resource::GetAs<Audio>(audio_id);
- return audio ? BoolToPPBool(audio->StartPlayback()) : PP_FALSE;
-}
-
-PP_Bool StopPlayback(PP_Resource audio_id) {
- scoped_refptr<Audio> audio = Resource::GetAs<Audio>(audio_id);
- return audio ? BoolToPPBool(audio->StopPlayback()) : PP_FALSE;
-}
-
-const PPB_Audio_Dev ppb_audio = {
- &Create,
- &IsAudio,
- &GetCurrentConfiguration,
- &StartPlayback,
- &StopPlayback,
-};
-
-// PPB_AudioTrusted ------------------------------------------------------------
-
-PP_Resource CreateTrusted(PP_Instance instance_id) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return 0;
- scoped_refptr<Audio> audio(new Audio(instance->module(), instance_id));
- return audio->GetReference();
-}
-
-int32_t Open(PP_Resource audio_id,
- PP_Resource config_id,
- PP_CompletionCallback created) {
- scoped_refptr<Audio> audio = Resource::GetAs<Audio>(audio_id);
- if (!audio)
- return PP_ERROR_BADRESOURCE;
- if (!created.func)
- return PP_ERROR_BADARGUMENT;
- PP_Instance instance_id = audio->pp_instance();
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return PP_ERROR_FAILED;
- return audio->Open(instance->delegate(), config_id, created);
-}
-
-int32_t GetSyncSocket(PP_Resource audio_id, int* sync_socket) {
- scoped_refptr<Audio> audio = Resource::GetAs<Audio>(audio_id);
- if (audio)
- return audio->GetSyncSocket(sync_socket);
- return PP_ERROR_BADRESOURCE;
-}
-
-int32_t GetSharedMemory(PP_Resource audio_id,
- int* shm_handle,
- int32_t* shm_size) {
- scoped_refptr<Audio> audio = Resource::GetAs<Audio>(audio_id);
- if (audio)
- return audio->GetSharedMemory(shm_handle, shm_size);
- return PP_ERROR_BADRESOURCE;
-}
-
-const PPB_AudioTrusted_Dev ppb_audiotrusted = {
- &CreateTrusted,
- &Open,
- &GetSyncSocket,
- &GetSharedMemory,
-};
-
-} // namespace
-
-// AudioConfig -----------------------------------------------------------------
-
-AudioConfig::AudioConfig(PluginModule* module,
- PP_AudioSampleRate_Dev sample_rate,
- uint32_t sample_frame_count)
- : Resource(module),
- sample_rate_(sample_rate),
- sample_frame_count_(sample_frame_count) {
-}
-
-const PPB_AudioConfig_Dev* AudioConfig::GetInterface() {
- return &ppb_audioconfig;
-}
-
-size_t AudioConfig::BufferSize() {
- // TODO(audio): as more options become available, we'll need to
- // have additional code here to correctly calculate the size in
- // bytes of an audio buffer. For now, only support two channel
- // int16_t sample buffers.
- const int kChannels = 2;
- const int kSizeOfSample = sizeof(int16_t);
- return static_cast<size_t>(sample_frame_count_ * kSizeOfSample * kChannels);
-}
-
-AudioConfig* AudioConfig::AsAudioConfig() {
- return this;
-}
-
-// Audio -----------------------------------------------------------------------
-
-Audio::Audio(PluginModule* module, PP_Instance instance_id)
- : Resource(module),
- playing_(false),
- pp_instance_(instance_id),
- audio_(NULL),
- socket_(NULL),
- shared_memory_(NULL),
- shared_memory_size_(0),
- callback_(NULL),
- user_data_(NULL),
- create_callback_pending_(false) {
- create_callback_ = PP_MakeCompletionCallback(NULL, NULL);
-}
-
-Audio::~Audio() {
- // Calling ShutDown() makes sure StreamCreated cannot be called anymore.
- audio_->ShutDown();
- audio_ = NULL;
-
- // Closing the socket causes the thread to exit - wait for it.
- socket_->Close();
- if (audio_thread_.get()) {
- audio_thread_->Join();
- audio_thread_.reset();
- }
-
- // If the completion callback hasn't fired yet, do so here
- // with an error condition.
- if (create_callback_pending_) {
- PP_RunCompletionCallback(&create_callback_, PP_ERROR_ABORTED);
- create_callback_pending_ = false;
- }
- // Shared memory destructor will unmap the memory automatically.
-}
-
-const PPB_Audio_Dev* Audio::GetInterface() {
- return &ppb_audio;
-}
-
-const PPB_AudioTrusted_Dev* Audio::GetTrustedInterface() {
- return &ppb_audiotrusted;
-}
-
-Audio* Audio::AsAudio() {
- return this;
-}
-
-bool Audio::Init(PluginDelegate* plugin_delegate,
- PP_Resource config_id,
- PPB_Audio_Callback callback, void* user_data) {
- CHECK(!audio_);
- config_ = Resource::GetAs<AudioConfig>(config_id);
- if (!config_)
- return false;
- callback_ = callback;
- user_data_ = user_data;
-
- // When the stream is created, we'll get called back on StreamCreated().
- audio_ = plugin_delegate->CreateAudio(config_->sample_rate(),
- config_->sample_frame_count(),
- this);
- return audio_ != NULL;
-}
-
-int32_t Audio::Open(PluginDelegate* plugin_delegate,
- PP_Resource config_id,
- PP_CompletionCallback create_callback) {
- DCHECK(!audio_);
- config_ = Resource::GetAs<AudioConfig>(config_id);
- if (!config_)
- return PP_ERROR_BADRESOURCE;
-
- // When the stream is created, we'll get called back on StreamCreated().
- audio_ = plugin_delegate->CreateAudio(config_->sample_rate(),
- config_->sample_frame_count(),
- this);
- if (!audio_)
- return PP_ERROR_FAILED;
-
- // At this point, we are guaranteeing ownership of the completion
- // callback. Audio promises to fire the completion callback
- // once and only once.
- create_callback_ = create_callback;
- create_callback_pending_ = true;
- return PP_ERROR_WOULDBLOCK;
-}
-
-int32_t Audio::GetSyncSocket(int* sync_socket) {
- if (socket_ != NULL) {
-#if defined(OS_POSIX)
- *sync_socket = socket_->handle();
-#elif defined(OS_WIN)
- *sync_socket = reinterpret_cast<int>(socket_->handle());
-#else
- #error "Platform not supported."
-#endif
- return PP_OK;
- }
- return PP_ERROR_FAILED;
-}
-
-int32_t Audio::GetSharedMemory(int* shm_handle, int32_t* shm_size) {
- if (shared_memory_ != NULL) {
-#if defined(OS_POSIX)
- *shm_handle = shared_memory_->handle().fd;
-#elif defined(OS_WIN)
- *shm_handle = reinterpret_cast<int>(shared_memory_->handle());
-#else
- #error "Platform not supported."
-#endif
- *shm_size = shared_memory_size_;
- return PP_OK;
- }
- return PP_ERROR_FAILED;
-}
-
-bool Audio::StartPlayback() {
- if (playing_)
- return true;
-
- CHECK(!audio_thread_.get());
- if (callback_ && socket_.get()) {
- audio_thread_.reset(new base::DelegateSimpleThread(this,
- "plugin_audio_thread"));
- audio_thread_->Start();
- }
- playing_ = true;
- return audio_->StartPlayback();
-}
-
-bool Audio::StopPlayback() {
- if (!playing_)
- return true;
-
- if (!audio_->StopPlayback())
- return false;
-
- if (audio_thread_.get()) {
- audio_thread_->Join();
- audio_thread_.reset();
- }
- playing_ = false;
- return true;
-}
-
-void Audio::StreamCreated(base::SharedMemoryHandle shared_memory_handle,
- size_t shared_memory_size,
- base::SyncSocket::Handle socket_handle) {
- socket_.reset(new base::SyncSocket(socket_handle));
- shared_memory_.reset(new base::SharedMemory(shared_memory_handle, false));
- shared_memory_size_ = shared_memory_size;
-
- // Trusted side of proxy can specify a callback to recieve handles.
- if (create_callback_pending_) {
- PP_RunCompletionCallback(&create_callback_, 0);
- create_callback_pending_ = false;
- }
-
- // Trusted, non-proxy audio will invoke buffer filling callback on a
- // dedicated thread, see Audio::Run() below.
- if (callback_) {
- shared_memory_->Map(shared_memory_size_);
-
- // In common case StartPlayback() was called before StreamCreated().
- if (playing_) {
- audio_thread_.reset(new base::DelegateSimpleThread(this,
- "plugin_audio_thread"));
- audio_thread_->Start();
- }
- }
-}
-
-void Audio::Run() {
- int pending_data;
- void* buffer = shared_memory_->memory();
- size_t buffer_size_in_bytes = config_->BufferSize();
-
- while (sizeof(pending_data) ==
- socket_->Receive(&pending_data, sizeof(pending_data)) &&
- pending_data >= 0) {
- // Exit the thread on pause.
- if (pending_data < 0)
- return;
- callback_(buffer, buffer_size_in_bytes, user_data_);
- }
-}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_audio.h b/webkit/glue/plugins/pepper_audio.h
deleted file mode 100644
index 8c14666..0000000
--- a/webkit/glue/plugins/pepper_audio.h
+++ /dev/null
@@ -1,136 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_DEVICE_CONTEXT_AUDIO_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_DEVICE_CONTEXT_AUDIO_H_
-
-#include "base/ref_counted.h"
-#include "base/scoped_ptr.h"
-#include "base/shared_memory.h"
-#include "base/simple_thread.h"
-#include "base/sync_socket.h"
-#include "ppapi/c/dev/ppb_audio_dev.h"
-#include "ppapi/c/dev/ppb_audio_config_dev.h"
-#include "ppapi/c/dev/ppb_audio_trusted_dev.h"
-#include "ppapi/c/pp_completion_callback.h"
-#include "webkit/glue/plugins/pepper_plugin_delegate.h"
-#include "webkit/glue/plugins/pepper_plugin_instance.h"
-#include "webkit/glue/plugins/pepper_plugin_module.h"
-#include "webkit/glue/plugins/pepper_resource.h"
-
-namespace pepper {
-
-class PluginInstance;
-class PluginModule;
-
-class AudioConfig : public Resource {
- public:
- AudioConfig(PluginModule* module,
- PP_AudioSampleRate_Dev sample_rate,
- uint32_t sample_frame_count);
- size_t BufferSize();
- static const PPB_AudioConfig_Dev* GetInterface();
-
- PP_AudioSampleRate_Dev sample_rate() { return sample_rate_; }
- uint32_t sample_frame_count() { return sample_frame_count_; }
-
- private:
- // Resource override.
- virtual AudioConfig* AsAudioConfig();
-
- PP_AudioSampleRate_Dev sample_rate_;
- uint32_t sample_frame_count_;
-};
-
-class Audio : public Resource,
- public PluginDelegate::PlatformAudio::Client,
- public base::DelegateSimpleThread::Delegate {
- public:
- explicit Audio(PluginModule* module, PP_Instance instance_id);
- virtual ~Audio();
-
- static const PPB_Audio_Dev* GetInterface();
- static const PPB_AudioTrusted_Dev* GetTrustedInterface();
-
- bool Init(PluginDelegate* plugin_delegate,
- PP_Resource config_id,
- PPB_Audio_Callback user_callback, void* user_data);
-
- int32_t Open(PluginDelegate* plugin_delegate,
- PP_Resource config_id,
- PP_CompletionCallback create_callback);
-
- PP_Resource GetCurrentConfiguration() {
- return config_->GetReference();
- }
-
- PP_Instance pp_instance() {
- return pp_instance_;
- }
-
- int32_t GetSyncSocket(int* sync_socket);
-
- int32_t GetSharedMemory(int* shm_handle, int32_t* shm_size);
-
- bool StartPlayback();
-
- bool StopPlayback();
-
- // Resource override.
- virtual Audio* AsAudio();
-
- private:
- // pepper::PluginDelegate::PlatformAudio::Client implementation.
- virtual void StreamCreated(base::SharedMemoryHandle shared_memory_handle,
- size_t shared_memory_size_,
- base::SyncSocket::Handle socket);
- // End of pepper::PluginDelegate::PlatformAudio::Client implementation.
-
- // Audio thread. DelegateSimpleThread::Delegate implementation.
- virtual void Run();
- // End of DelegateSimpleThread::Delegate implementation.
-
- // True if playing the stream.
- bool playing_;
-
- // AudioConfig used for creating this Audio object.
- scoped_refptr<AudioConfig> config_;
-
- // Instance id
- PP_Instance pp_instance_;
-
- // PluginDelegate audio object that we delegate audio IPC through.
- PluginDelegate::PlatformAudio* audio_;
-
- // Socket used to notify us when audio is ready to accept new samples. This
- // pointer is created in StreamCreated().
- scoped_ptr<base::SyncSocket> socket_;
-
- // Sample buffer in shared memory. This pointer is created in
- // StreamCreated(). The memory is only mapped when the audio thread is
- // created.
- scoped_ptr<base::SharedMemory> shared_memory_;
-
- // The size of the sample buffer in bytes.
- size_t shared_memory_size_;
-
- // When the callback is set, this thread is spawned for calling it.
- scoped_ptr<base::DelegateSimpleThread> audio_thread_;
-
- // Callback to call when audio is ready to accept new samples.
- volatile PPB_Audio_Callback callback_;
-
- // User data pointer passed verbatim to the callback function.
- void* user_data_;
-
- // Is a create callback pending to fire?
- bool create_callback_pending_;
-
- // Trusted callback invoked from StreamCreated.
- PP_CompletionCallback create_callback_;
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_DEVICE_CONTEXT_AUDIO_H_
diff --git a/webkit/glue/plugins/pepper_buffer.cc b/webkit/glue/plugins/pepper_buffer.cc
deleted file mode 100644
index cee10c9..0000000
--- a/webkit/glue/plugins/pepper_buffer.cc
+++ /dev/null
@@ -1,117 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_buffer.h"
-
-#include <algorithm>
-
-#include "base/logging.h"
-#include "base/scoped_ptr.h"
-#include "ppapi/c/dev/ppb_buffer_dev.h"
-#include "ppapi/c/pp_instance.h"
-#include "ppapi/c/pp_module.h"
-#include "ppapi/c/pp_resource.h"
-#include "webkit/glue/plugins/pepper_common.h"
-#include "webkit/glue/plugins/pepper_plugin_instance.h"
-#include "webkit/glue/plugins/pepper_plugin_module.h"
-
-namespace pepper {
-
-namespace {
-
-PP_Resource Create(PP_Module module_id, int32_t size) {
- PluginModule* module = ResourceTracker::Get()->GetModule(module_id);
- if (!module)
- return 0;
-
- scoped_refptr<Buffer> buffer(new Buffer(module));
- if (!buffer->Init(size))
- return 0;
-
- return buffer->GetReference();
-}
-
-PP_Bool IsBuffer(PP_Resource resource) {
- return BoolToPPBool(!!Resource::GetAs<Buffer>(resource));
-}
-
-PP_Bool Describe(PP_Resource resource, int32_t* size_in_bytes) {
- scoped_refptr<Buffer> buffer(Resource::GetAs<Buffer>(resource));
- if (!buffer)
- return PP_FALSE;
- buffer->Describe(size_in_bytes);
- return PP_TRUE;
-}
-
-void* Map(PP_Resource resource) {
- scoped_refptr<Buffer> buffer(Resource::GetAs<Buffer>(resource));
- if (!buffer)
- return NULL;
- return buffer->Map();
-}
-
-void Unmap(PP_Resource resource) {
- scoped_refptr<Buffer> buffer(Resource::GetAs<Buffer>(resource));
- if (!buffer)
- return;
- return buffer->Unmap();
-}
-
-const PPB_Buffer_Dev ppb_buffer = {
- &Create,
- &IsBuffer,
- &Describe,
- &Map,
- &Unmap,
-};
-
-} // namespace
-
-Buffer::Buffer(PluginModule* module)
- : Resource(module),
- size_(0) {
-}
-
-Buffer::~Buffer() {
-}
-
-// static
-const PPB_Buffer_Dev* Buffer::GetInterface() {
- return &ppb_buffer;
-}
-
-bool Buffer::Init(int size) {
- if (size == 0)
- return false;
- Unmap();
- size_ = size;
- return true;
-}
-
-void Buffer::Describe(int* size_in_bytes) const {
- *size_in_bytes = size_;
-}
-
-void* Buffer::Map() {
- if (size_ == 0)
- return NULL;
-
- if (!is_mapped()) {
- mem_buffer_.reset(new unsigned char[size_]);
- memset(mem_buffer_.get(), 0, size_);
- }
- return mem_buffer_.get();
-}
-
-void Buffer::Unmap() {
- mem_buffer_.reset();
-}
-
-void Buffer::Swap(Buffer* other) {
- swap(other->mem_buffer_, mem_buffer_);
- std::swap(other->size_, size_);
-}
-
-} // namespace pepper
-
diff --git a/webkit/glue/plugins/pepper_buffer.h b/webkit/glue/plugins/pepper_buffer.h
deleted file mode 100644
index 2f20e55..0000000
--- a/webkit/glue/plugins/pepper_buffer.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_BUFFER_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_BUFFER_H_
-
-#include "base/basictypes.h"
-#include "base/scoped_ptr.h"
-#include "webkit/glue/plugins/pepper_resource.h"
-
-struct PPB_Buffer_Dev;
-
-namespace pepper {
-
-class PluginInstance;
-
-class Buffer : public Resource {
- public:
- explicit Buffer(PluginModule* module);
- virtual ~Buffer();
-
- int size() const { return size_; }
- unsigned char* mapped_buffer() { return mem_buffer_.get(); }
-
- // Returns true if this buffer is mapped. False means that the buffer is
- // either invalid or not mapped.
- bool is_mapped() const { return !!mem_buffer_.get(); }
-
- // Returns a pointer to the interface implementing PPB_Buffer that is
- // exposed to the plugin.
- static const PPB_Buffer_Dev* GetInterface();
-
- // Resource overrides.
- Buffer* AsBuffer() { return this; }
-
- // PPB_Buffer implementation.
- bool Init(int size);
- void Describe(int* size_in_bytes) const;
- void* Map();
- void Unmap();
-
- // Swaps the guts of this buffer with another.
- void Swap(Buffer* other);
-
- private:
- int size_;
- scoped_array<unsigned char> mem_buffer_;
-
- DISALLOW_COPY_AND_ASSIGN(Buffer);
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_BUFFER_H_
-
diff --git a/webkit/glue/plugins/pepper_char_set.cc b/webkit/glue/plugins/pepper_char_set.cc
deleted file mode 100644
index 1411d59..0000000
--- a/webkit/glue/plugins/pepper_char_set.cc
+++ /dev/null
@@ -1,166 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_char_set.h"
-
-#include <stdlib.h>
-
-#include "base/i18n/icu_string_conversions.h"
-#include "ppapi/c/dev/ppb_char_set_dev.h"
-#include "unicode/ucnv.h"
-#include "unicode/ucnv_cb.h"
-#include "unicode/ucnv_err.h"
-#include "unicode/ustring.h"
-#include "webkit/glue/plugins/pepper_plugin_delegate.h"
-#include "webkit/glue/plugins/pepper_plugin_instance.h"
-#include "webkit/glue/plugins/pepper_plugin_module.h"
-#include "webkit/glue/plugins/pepper_var.h"
-
-namespace pepper {
-
-namespace {
-
-// Converts the given PP error handling behavior to the version in base,
-// placing the result in |*result| and returning true on success. Returns false
-// if the enum is invalid.
-bool PPToBaseConversionError(PP_CharSet_ConversionError on_error,
- base::OnStringConversionError::Type* result) {
- switch (on_error) {
- case PP_CHARSET_CONVERSIONERROR_FAIL:
- *result = base::OnStringConversionError::FAIL;
- return true;
- case PP_CHARSET_CONVERSIONERROR_SKIP:
- *result = base::OnStringConversionError::SKIP;
- return true;
- case PP_CHARSET_CONVERSIONERROR_SUBSTITUTE:
- *result = base::OnStringConversionError::SUBSTITUTE;
- return true;
- default:
- return false;
- }
-}
-
-// The "substitution" behavior of this function does not match the
-// implementation in base, so we partially duplicate the code from
-// icu_string_conversions.cc with the correct error handling setup required
-// by this pepper interface.
-char* UTF16ToCharSet(const uint16_t* utf16, uint32_t utf16_len,
- const char* output_char_set,
- PP_CharSet_ConversionError on_error,
- uint32_t* output_length) {
- *output_length = 0;
-
- UErrorCode status = U_ZERO_ERROR;
- UConverter* converter = ucnv_open(output_char_set, &status);
- if (!U_SUCCESS(status))
- return NULL;
-
- int encoded_max_length = UCNV_GET_MAX_BYTES_FOR_STRING(utf16_len,
- ucnv_getMaxCharSize(converter));
-
- // Setup our error handler.
- switch (on_error) {
- case PP_CHARSET_CONVERSIONERROR_FAIL:
- ucnv_setFromUCallBack(converter, UCNV_FROM_U_CALLBACK_STOP, 0,
- NULL, NULL, &status);
- break;
- case PP_CHARSET_CONVERSIONERROR_SKIP:
- ucnv_setFromUCallBack(converter, UCNV_FROM_U_CALLBACK_SKIP, 0,
- NULL, NULL, &status);
- break;
- case PP_CHARSET_CONVERSIONERROR_SUBSTITUTE: {
- // ICU sets the substitution char for some character sets (like latin1)
- // to be the ASCII "substitution character" (26). We want to use '?'
- // instead for backwards-compat with Windows behavior.
- char subst_chars[32];
- int8_t subst_chars_len = 32;
- ucnv_getSubstChars(converter, subst_chars, &subst_chars_len, &status);
- if (subst_chars_len == 1 && subst_chars[0] == 26) {
- // Override to the question mark character if possible. When using
- // setSubstString, the input is a Unicode character. The function will
- // try to convert it to the destination character set and fail if that
- // can not be converted to the destination character set.
- //
- // We just ignore any failure. If the dest char set has no
- // representation for '?', then we'll just stick to the ICU default
- // substitution character.
- UErrorCode subst_status = U_ZERO_ERROR;
- UChar question_mark = '?';
- ucnv_setSubstString(converter, &question_mark, 1, &subst_status);
- }
-
- ucnv_setFromUCallBack(converter, UCNV_FROM_U_CALLBACK_SUBSTITUTE, 0,
- NULL, NULL, &status);
- break;
- }
- default:
- return NULL;
- }
-
- // ucnv_fromUChars returns size not including terminating null.
- char* encoded = static_cast<char*>(malloc(encoded_max_length + 1));
- int actual_size = ucnv_fromUChars(converter, encoded,
- encoded_max_length, reinterpret_cast<const UChar*>(utf16), utf16_len,
- &status);
- ucnv_close(converter);
- if (!U_SUCCESS(status)) {
- free(encoded);
- return NULL;
- }
- encoded[actual_size] = 0;
- *output_length = actual_size;
- return encoded;
-}
-
-uint16_t* CharSetToUTF16(const char* input, uint32_t input_len,
- const char* input_char_set,
- PP_CharSet_ConversionError on_error,
- uint32_t* output_length) {
- *output_length = 0;
-
- base::OnStringConversionError::Type base_on_error;
- if (!PPToBaseConversionError(on_error, &base_on_error))
- return NULL; // Invalid enum value.
-
- // We can convert this call to the implementation in base to avoid code
- // duplication, although this does introduce an extra copy of the data.
- string16 output;
- if (!base::CodepageToUTF16(std::string(input, input_len), input_char_set,
- base_on_error, &output))
- return NULL;
-
- uint16_t* ret_buf = static_cast<uint16_t*>(
- malloc((output.size() + 1) * sizeof(uint16_t)));
- if (!ret_buf)
- return NULL;
-
- *output_length = static_cast<uint32_t>(output.size());
- memcpy(ret_buf, output.c_str(), (output.size() + 1) * sizeof(uint16_t));
- return ret_buf;
-}
-
-PP_Var GetDefaultCharSet(PP_Module pp_module) {
- PluginModule* module = ResourceTracker::Get()->GetModule(pp_module);
- if (!module)
- return PP_MakeUndefined();
-
- std::string encoding =
- module->GetSomeInstance()->delegate()->GetDefaultEncoding();
- return StringVar::StringToPPVar(module, encoding);
-}
-
-const PPB_CharSet_Dev ppb_charset = {
- &UTF16ToCharSet,
- &CharSetToUTF16,
- &GetDefaultCharSet
-};
-
-} // namespace
-
-// static
-const struct PPB_CharSet_Dev* CharSet::GetInterface() {
- return &ppb_charset;
-}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_char_set.h b/webkit/glue/plugins/pepper_char_set.h
deleted file mode 100644
index 5abb54d..0000000
--- a/webkit/glue/plugins/pepper_char_set.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_CHAR_SET_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_CHAR_SET_H_
-
-struct PPB_CharSet_Dev;
-
-namespace pepper {
-
-class CharSet {
- public:
- // Returns a pointer to the interface implementing PPB_CharSet that is
- // exposed to the plugin.
- static const PPB_CharSet_Dev* GetInterface();
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_CHAR_SET_H_
diff --git a/webkit/glue/plugins/pepper_class.h b/webkit/glue/plugins/pepper_class.h
deleted file mode 100644
index 35bd2c4..0000000
--- a/webkit/glue/plugins/pepper_class.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_CLASS_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_CLASS_H_
-
-#include "webkit/glue/plugins/pepper_resource.h"
-
-#include <string>
-
-#include "base/hash_tables.h"
-#include "ppapi/c/ppb_class.h"
-
-namespace pepper {
-
-class PluginModule;
-
-class VarObjectClass : public Resource {
- public:
- struct Property {
- explicit Property(const PP_ClassProperty& prop);
-
- const PP_ClassFunction method;
- const PP_ClassFunction getter;
- const PP_ClassFunction setter;
- const bool writable;
- const bool enumerable;
- };
-
- struct InstanceData;
-
- typedef base::hash_map<std::string, Property> PropertyMap;
-
- // Returns the PPB_Var interface for the plugin to use.
- static const PPB_Class* GetInterface();
-
- VarObjectClass(PluginModule* module, PP_ClassDestructor destruct,
- PP_ClassFunction invoke, PP_ClassProperty* properties);
- virtual ~VarObjectClass();
-
- // Resource override.
- virtual VarObjectClass* AsVarObjectClass() { return this; }
-
- const PropertyMap &properties() const { return properties_; }
-
- PP_ClassDestructor instance_native_destructor() {
- return instance_native_destructor_;
- }
-
- PP_ClassFunction instance_invoke() {
- return instance_invoke_;
- }
-
- private:
- PropertyMap properties_;
- PP_ClassDestructor instance_native_destructor_;
- PP_ClassFunction instance_invoke_;
-
- DISALLOW_COPY_AND_ASSIGN(VarObjectClass);
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_CLASS_H_
-
diff --git a/webkit/glue/plugins/pepper_common.h b/webkit/glue/plugins/pepper_common.h
deleted file mode 100644
index be9fe3d..0000000
--- a/webkit/glue/plugins/pepper_common.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_COMMON_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_COMMON_H_
-
-#include "ppapi/c/pp_bool.h"
-#include "ppapi/c/pp_var.h"
-
-namespace pepper {
-
-inline PP_Bool BoolToPPBool(bool value) {
- return value ? PP_TRUE : PP_FALSE;
-}
-
-inline bool PPBoolToBool(PP_Bool value) {
- return (PP_TRUE == value);
-}
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_COMMON_H_
-
diff --git a/webkit/glue/plugins/pepper_cursor_control.cc b/webkit/glue/plugins/pepper_cursor_control.cc
deleted file mode 100644
index 62b4e2f..0000000
--- a/webkit/glue/plugins/pepper_cursor_control.cc
+++ /dev/null
@@ -1,92 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_cursor_control.h"
-
-#include "base/logging.h"
-#include "base/ref_counted.h"
-#include "ppapi/c/dev/pp_cursor_type_dev.h"
-#include "ppapi/c/dev/ppb_cursor_control_dev.h"
-#include "ppapi/c/pp_point.h"
-#include "ppapi/c/pp_resource.h"
-#include "webkit/glue/plugins/pepper_common.h"
-#include "webkit/glue/plugins/pepper_image_data.h"
-#include "webkit/glue/plugins/pepper_plugin_instance.h"
-#include "webkit/glue/plugins/pepper_resource.h"
-
-namespace pepper {
-
-namespace {
-
-PP_Bool SetCursor(PP_Instance instance_id,
- PP_CursorType_Dev type,
- PP_Resource custom_image_id,
- const PP_Point* hot_spot) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return PP_FALSE;
-
- scoped_refptr<ImageData> custom_image(
- Resource::GetAs<ImageData>(custom_image_id));
- if (custom_image.get()) {
- // TODO(neb): implement custom cursors.
- NOTIMPLEMENTED();
- return PP_FALSE;
- }
-
- return BoolToPPBool(instance->SetCursor(type));
-}
-
-PP_Bool LockCursor(PP_Instance instance_id) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return PP_FALSE;
-
- // TODO(neb): implement cursor locking.
- return PP_FALSE;
-}
-
-PP_Bool UnlockCursor(PP_Instance instance_id) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return PP_FALSE;
-
- // TODO(neb): implement cursor locking.
- return PP_FALSE;
-}
-
-PP_Bool HasCursorLock(PP_Instance instance_id) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return PP_FALSE;
-
- // TODO(neb): implement cursor locking.
- return PP_FALSE;
-}
-
-PP_Bool CanLockCursor(PP_Instance instance_id) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return PP_FALSE;
-
- // TODO(neb): implement cursor locking.
- return PP_FALSE;
-}
-
-const PPB_CursorControl_Dev cursor_control_interface = {
- &SetCursor,
- &LockCursor,
- &UnlockCursor,
- &HasCursorLock,
- &CanLockCursor
-};
-
-} // namespace
-
-const PPB_CursorControl_Dev* GetCursorControlInterface() {
- return &cursor_control_interface;
-}
-
-} // namespace pepper
-
diff --git a/webkit/glue/plugins/pepper_cursor_control.h b/webkit/glue/plugins/pepper_cursor_control.h
deleted file mode 100644
index 693fb4a..0000000
--- a/webkit/glue/plugins/pepper_cursor_control.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_CURSOR_CONTROL_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_CURSOR_CONTROL_H_
-
-struct PPB_CursorControl_Dev;
-
-namespace pepper {
-
-// There's no class implementing CursorControl so we just expose a getter for
-// the interface implemented in the .cc file here.
-const PPB_CursorControl_Dev* GetCursorControlInterface();
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_CURSOR_CONTROL_H_
-
diff --git a/webkit/glue/plugins/pepper_dir_contents.h b/webkit/glue/plugins/pepper_dir_contents.h
deleted file mode 100644
index 661c577..0000000
--- a/webkit/glue/plugins/pepper_dir_contents.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_DIR_CONTENTS_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_DIR_CONTENTS_H_
-
-#include <vector>
-#include "base/file_path.h"
-
-struct PepperDirEntry {
- FilePath name;
- bool is_dir;
-};
-
-typedef std::vector<PepperDirEntry> PepperDirContents;
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_DIR_CONTENTS_H_
diff --git a/webkit/glue/plugins/pepper_directory_reader.cc b/webkit/glue/plugins/pepper_directory_reader.cc
deleted file mode 100644
index c476b76..0000000
--- a/webkit/glue/plugins/pepper_directory_reader.cc
+++ /dev/null
@@ -1,156 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_directory_reader.h"
-
-#include "base/logging.h"
-#include "base/utf_string_conversions.h"
-#include "ppapi/c/pp_completion_callback.h"
-#include "ppapi/c/pp_errors.h"
-#include "ppapi/c/dev/ppb_directory_reader_dev.h"
-#include "webkit/glue/plugins/pepper_file_callbacks.h"
-#include "webkit/glue/plugins/pepper_common.h"
-#include "webkit/glue/plugins/pepper_file_ref.h"
-#include "webkit/glue/plugins/pepper_file_system.h"
-#include "webkit/glue/plugins/pepper_plugin_delegate.h"
-#include "webkit/glue/plugins/pepper_plugin_instance.h"
-#include "webkit/glue/plugins/pepper_plugin_module.h"
-#include "webkit/glue/plugins/pepper_resource_tracker.h"
-
-namespace pepper {
-
-namespace {
-
-std::string FilePathStringToUTF8String(const FilePath::StringType& str) {
-#if defined(OS_WIN)
- return WideToUTF8(str);
-#elif defined(OS_POSIX)
- return str;
-#else
-#error "Unsupported platform."
-#endif
-}
-
-FilePath::StringType UTF8StringToFilePathString(const std::string& str) {
-#if defined(OS_WIN)
- return UTF8ToWide(str);
-#elif defined(OS_POSIX)
- return str;
-#else
-#error "Unsupported platform."
-#endif
-}
-
-PP_Resource Create(PP_Resource directory_ref_id) {
- scoped_refptr<FileRef> directory_ref(
- Resource::GetAs<FileRef>(directory_ref_id));
- if (!directory_ref)
- return 0;
-
- DirectoryReader* reader = new DirectoryReader(directory_ref);
- return reader->GetReference();
-}
-
-PP_Bool IsDirectoryReader(PP_Resource resource) {
- return BoolToPPBool(!!Resource::GetAs<DirectoryReader>(resource));
-}
-
-int32_t GetNextEntry(PP_Resource reader_id,
- PP_DirectoryEntry_Dev* entry,
- PP_CompletionCallback callback) {
- scoped_refptr<DirectoryReader> reader(
- Resource::GetAs<DirectoryReader>(reader_id));
- if (!reader)
- return PP_ERROR_BADRESOURCE;
-
- return reader->GetNextEntry(entry, callback);
-}
-
-const PPB_DirectoryReader_Dev ppb_directoryreader = {
- &Create,
- &IsDirectoryReader,
- &GetNextEntry
-};
-
-} // namespace
-
-DirectoryReader::DirectoryReader(FileRef* directory_ref)
- : Resource(directory_ref->module()),
- directory_ref_(directory_ref),
- has_more_(true),
- entry_(NULL) {
-}
-
-DirectoryReader::~DirectoryReader() {
-}
-
-const PPB_DirectoryReader_Dev* DirectoryReader::GetInterface() {
- return &ppb_directoryreader;
-}
-
-int32_t DirectoryReader::GetNextEntry(PP_DirectoryEntry_Dev* entry,
- PP_CompletionCallback callback) {
- if (directory_ref_->GetFileSystemType() == PP_FILESYSTEMTYPE_EXTERNAL)
- return PP_ERROR_FAILED;
-
- entry_ = entry;
- if (FillUpEntry()) {
- entry_ = NULL;
- return PP_OK;
- }
-
- PluginInstance* instance = directory_ref_->GetFileSystem()->instance();
- if (!instance->delegate()->ReadDirectory(
- directory_ref_->GetSystemPath(),
- new FileCallbacks(instance->module()->AsWeakPtr(),
- callback, NULL, NULL, this)))
- return PP_ERROR_FAILED;
-
- return PP_ERROR_WOULDBLOCK;
-}
-
-void DirectoryReader::AddNewEntries(
- const std::vector<base::FileUtilProxy::Entry>& entries, bool has_more) {
- DCHECK(!entries.empty());
- has_more_ = has_more;
- std::string dir_path = directory_ref_->GetPath();
- if (dir_path[dir_path.size() - 1] != '/')
- dir_path += '/';
- FilePath::StringType dir_file_path = UTF8StringToFilePathString(dir_path);
- for (std::vector<base::FileUtilProxy::Entry>::const_iterator it =
- entries.begin(); it != entries.end(); it++) {
- base::FileUtilProxy::Entry entry;
- entry.name = dir_file_path + it->name;
- entry.is_directory = it->is_directory;
- entries_.push(entry);
- }
-
- FillUpEntry();
- entry_ = NULL;
-}
-
-bool DirectoryReader::FillUpEntry() {
- DCHECK(entry_);
- if (!entries_.empty()) {
- base::FileUtilProxy::Entry dir_entry = entries_.front();
- entries_.pop();
- if (entry_->file_ref)
- ResourceTracker::Get()->UnrefResource(entry_->file_ref);
- FileRef* file_ref = new FileRef(module(), directory_ref_->GetFileSystem(),
- FilePathStringToUTF8String(dir_entry.name));
- entry_->file_ref = file_ref->GetReference();
- entry_->file_type =
- (dir_entry.is_directory ? PP_FILETYPE_DIRECTORY : PP_FILETYPE_REGULAR);
- return true;
- }
-
- if (!has_more_) {
- entry_->file_ref = 0;
- return true;
- }
-
- return false;
-}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_directory_reader.h b/webkit/glue/plugins/pepper_directory_reader.h
deleted file mode 100644
index 38496bb..0000000
--- a/webkit/glue/plugins/pepper_directory_reader.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_DIRECTORY_READER_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_DIRECTORY_READER_H_
-
-#include <queue>
-
-#include "base/file_util_proxy.h"
-#include "webkit/glue/plugins/pepper_resource.h"
-
-struct PP_CompletionCallback;
-struct PP_DirectoryEntry_Dev;
-struct PPB_DirectoryReader_Dev;
-
-namespace pepper {
-
-class FileRef;
-
-class DirectoryReader : public Resource {
- public:
- explicit DirectoryReader(FileRef* directory_ref);
- virtual ~DirectoryReader();
-
- // Returns a pointer to the interface implementing PPB_DirectoryReader that
- // is exposed to the plugin.
- static const PPB_DirectoryReader_Dev* GetInterface();
-
- // Resource overrides.
- DirectoryReader* AsDirectoryReader() { return this; }
-
- // PPB_DirectoryReader implementation.
- int32_t GetNextEntry(PP_DirectoryEntry_Dev* entry,
- PP_CompletionCallback callback);
-
- void AddNewEntries(const std::vector<base::FileUtilProxy::Entry>& entries,
- bool has_more);
-
- private:
- bool FillUpEntry();
-
- scoped_refptr<FileRef> directory_ref_;
- std::queue<base::FileUtilProxy::Entry> entries_;
- bool has_more_;
- PP_DirectoryEntry_Dev* entry_;
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_DIRECTORY_READER_H_
diff --git a/webkit/glue/plugins/pepper_error_util.cc b/webkit/glue/plugins/pepper_error_util.cc
deleted file mode 100644
index 7472d4a..0000000
--- a/webkit/glue/plugins/pepper_error_util.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_error_util.h"
-
-#include "ppapi/c/pp_errors.h"
-
-namespace pepper {
-
-int PlatformFileErrorToPepperError(base::PlatformFileError error_code) {
- switch (error_code) {
- case base::PLATFORM_FILE_OK:
- return PP_OK;
- case base::PLATFORM_FILE_ERROR_EXISTS:
- return PP_ERROR_FILEEXISTS;
- case base::PLATFORM_FILE_ERROR_NOT_FOUND:
- return PP_ERROR_FILENOTFOUND;
- case base::PLATFORM_FILE_ERROR_ACCESS_DENIED:
- case base::PLATFORM_FILE_ERROR_SECURITY:
- return PP_ERROR_NOACCESS;
- case base::PLATFORM_FILE_ERROR_NO_MEMORY:
- return PP_ERROR_NOMEMORY;
- case base::PLATFORM_FILE_ERROR_NO_SPACE:
- return PP_ERROR_NOSPACE;
- case base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY:
- return PP_ERROR_FAILED;
- default:
- return PP_ERROR_FAILED;
- }
-}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_error_util.h b/webkit/glue/plugins/pepper_error_util.h
deleted file mode 100644
index 12e715c..0000000
--- a/webkit/glue/plugins/pepper_error_util.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_ERROR_UTIL_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_ERROR_UTIL_H_
-
-#include "base/platform_file.h"
-
-namespace pepper {
-
-int PlatformFileErrorToPepperError(base::PlatformFileError error_code);
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_ERROR_UTIL_H_
diff --git a/webkit/glue/plugins/pepper_event_conversion.cc b/webkit/glue/plugins/pepper_event_conversion.cc
deleted file mode 100644
index 300592f..0000000
--- a/webkit/glue/plugins/pepper_event_conversion.cc
+++ /dev/null
@@ -1,301 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_event_conversion.h"
-
-#include "base/i18n/char_iterator.h"
-#include "base/logging.h"
-#include "base/scoped_ptr.h"
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-#include "base/utf_string_conversion_utils.h"
-#include "ppapi/c/pp_input_event.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h"
-#include "webkit/glue/plugins/pepper_common.h"
-
-using WebKit::WebInputEvent;
-using WebKit::WebKeyboardEvent;
-using WebKit::WebMouseEvent;
-using WebKit::WebMouseWheelEvent;
-
-namespace {
-
-PP_InputEvent_Type ConvertEventTypes(WebInputEvent::Type wetype) {
- switch (wetype) {
- case WebInputEvent::MouseDown:
- return PP_INPUTEVENT_TYPE_MOUSEDOWN;
- case WebInputEvent::MouseUp:
- return PP_INPUTEVENT_TYPE_MOUSEUP;
- case WebInputEvent::MouseMove:
- return PP_INPUTEVENT_TYPE_MOUSEMOVE;
- case WebInputEvent::MouseEnter:
- return PP_INPUTEVENT_TYPE_MOUSEENTER;
- case WebInputEvent::MouseLeave:
- return PP_INPUTEVENT_TYPE_MOUSELEAVE;
- case WebInputEvent::MouseWheel:
- return PP_INPUTEVENT_TYPE_MOUSEWHEEL;
- case WebInputEvent::RawKeyDown:
- return PP_INPUTEVENT_TYPE_RAWKEYDOWN;
- case WebInputEvent::KeyDown:
- return PP_INPUTEVENT_TYPE_KEYDOWN;
- case WebInputEvent::KeyUp:
- return PP_INPUTEVENT_TYPE_KEYUP;
- case WebInputEvent::Char:
- return PP_INPUTEVENT_TYPE_CHAR;
- case WebInputEvent::Undefined:
- default:
- return PP_INPUTEVENT_TYPE_UNDEFINED;
- }
-}
-
-// Generates a PP_InputEvent with the fields common to all events, as well as
-// the event type from the given web event. Event-specific fields will be zero
-// initialized.
-PP_InputEvent GetPPEventWithCommonFieldsAndType(
- const WebInputEvent& web_event) {
- PP_InputEvent result;
- memset(&result, 0, sizeof(PP_InputEvent));
- result.type = ConvertEventTypes(web_event.type);
- // TODO(brettw) http://code.google.com/p/chromium/issues/detail?id=57448
- // This should use a tick count rather than the wall clock time that WebKit
- // uses.
- result.time_stamp = web_event.timeStampSeconds;
- return result;
-}
-
-void AppendKeyEvent(const WebInputEvent& event,
- std::vector<PP_InputEvent>* pp_events) {
- const WebKeyboardEvent& key_event =
- reinterpret_cast<const WebKeyboardEvent&>(event);
- PP_InputEvent result = GetPPEventWithCommonFieldsAndType(event);
- result.u.key.modifier = key_event.modifiers;
- result.u.key.key_code = key_event.windowsKeyCode;
- pp_events->push_back(result);
-}
-
-void AppendCharEvent(const WebInputEvent& event,
- std::vector<PP_InputEvent>* pp_events) {
- const WebKeyboardEvent& key_event =
- reinterpret_cast<const WebKeyboardEvent&>(event);
-
- // This is a bit complex, the input event will normally just have one 16-bit
- // character in it, but may be zero or more than one. The text array is
- // just padded with 0 values for the unused ones, but is not necessarily
- // null-terminated.
- //
- // Here we see how many UTF-16 characters we have.
- size_t utf16_char_count = 0;
- while (utf16_char_count < WebKeyboardEvent::textLengthCap &&
- key_event.text[utf16_char_count])
- utf16_char_count++;
-
- // Make a separate PP_InputEvent for each Unicode character in the input.
- base::UTF16CharIterator iter(key_event.text, utf16_char_count);
- while (!iter.end()) {
- PP_InputEvent result = GetPPEventWithCommonFieldsAndType(event);
- result.u.character.modifier = key_event.modifiers;
-
- std::string utf8_char;
- base::WriteUnicodeCharacter(iter.get(), &utf8_char);
- base::strlcpy(result.u.character.text, utf8_char.c_str(),
- sizeof(result.u.character.text));
-
- pp_events->push_back(result);
- iter.Advance();
- }
-}
-
-void AppendMouseEvent(const WebInputEvent& event,
- std::vector<PP_InputEvent>* pp_events) {
- COMPILE_ASSERT(static_cast<int>(WebMouseEvent::ButtonNone) ==
- static_cast<int>(PP_INPUTEVENT_MOUSEBUTTON_NONE),
- MouseNone);
- COMPILE_ASSERT(static_cast<int>(WebMouseEvent::ButtonLeft) ==
- static_cast<int>(PP_INPUTEVENT_MOUSEBUTTON_LEFT),
- MouseLeft);
- COMPILE_ASSERT(static_cast<int>(WebMouseEvent::ButtonRight) ==
- static_cast<int>(PP_INPUTEVENT_MOUSEBUTTON_RIGHT),
- MouseRight);
- COMPILE_ASSERT(static_cast<int>(WebMouseEvent::ButtonMiddle) ==
- static_cast<int>(PP_INPUTEVENT_MOUSEBUTTON_MIDDLE),
- MouseMiddle);
-
- const WebMouseEvent& mouse_event =
- reinterpret_cast<const WebMouseEvent&>(event);
- PP_InputEvent result = GetPPEventWithCommonFieldsAndType(event);
- result.u.mouse.modifier = mouse_event.modifiers;
- result.u.mouse.button =
- static_cast<PP_InputEvent_MouseButton>(mouse_event.button);
- result.u.mouse.x = static_cast<float>(mouse_event.x);
- result.u.mouse.y = static_cast<float>(mouse_event.y);
- result.u.mouse.click_count = mouse_event.clickCount;
- pp_events->push_back(result);
-}
-
-void AppendMouseWheelEvent(const WebInputEvent& event,
- std::vector<PP_InputEvent>* pp_events) {
- const WebMouseWheelEvent& mouse_wheel_event =
- reinterpret_cast<const WebMouseWheelEvent&>(event);
- PP_InputEvent result = GetPPEventWithCommonFieldsAndType(event);
- result.u.wheel.modifier = mouse_wheel_event.modifiers;
- result.u.wheel.delta_x = mouse_wheel_event.deltaX;
- result.u.wheel.delta_y = mouse_wheel_event.deltaY;
- result.u.wheel.wheel_ticks_x = mouse_wheel_event.wheelTicksX;
- result.u.wheel.wheel_ticks_y = mouse_wheel_event.wheelTicksY;
- result.u.wheel.scroll_by_page =
- pepper::BoolToPPBool(!!mouse_wheel_event.scrollByPage);
- pp_events->push_back(result);
-}
-
-
-WebKeyboardEvent* BuildKeyEvent(const PP_InputEvent& event) {
- WebKeyboardEvent* key_event = new WebKeyboardEvent();
- switch (event.type) {
- case PP_INPUTEVENT_TYPE_RAWKEYDOWN:
- key_event->type = WebInputEvent::RawKeyDown;
- break;
- case PP_INPUTEVENT_TYPE_KEYDOWN:
- key_event->type = WebInputEvent::KeyDown;
- break;
- case PP_INPUTEVENT_TYPE_KEYUP:
- key_event->type = WebInputEvent::KeyUp;
- break;
- default:
- NOTREACHED();
- }
- key_event->timeStampSeconds = event.time_stamp;
- key_event->modifiers = event.u.key.modifier;
- key_event->windowsKeyCode = event.u.key.key_code;
- return key_event;
-}
-
-WebKeyboardEvent* BuildCharEvent(const PP_InputEvent& event) {
- WebKeyboardEvent* key_event = new WebKeyboardEvent();
- key_event->type = WebInputEvent::Char;
- key_event->timeStampSeconds = event.time_stamp;
- key_event->modifiers = event.u.character.modifier;
-
- // Make sure to not read beyond the buffer in case some bad code doesn't
- // NULL-terminate it (this is called from plugins).
- size_t text_length_cap = WebKeyboardEvent::textLengthCap;
- size_t text_len = 0;
- while (text_len < text_length_cap && event.u.character.text[text_len])
- text_len++;
- string16 text16 = UTF8ToUTF16(std::string(event.u.character.text, text_len));
-
- memset(key_event->text, 0, text_length_cap);
- memset(key_event->unmodifiedText, 0, text_length_cap);
- for (size_t i = 0;
- i < std::min(text_length_cap, text16.size());
- ++i)
- key_event->text[i] = text16[i];
- return key_event;
-}
-
-WebMouseEvent* BuildMouseEvent(const PP_InputEvent& event) {
- WebMouseEvent* mouse_event = new WebMouseEvent();
- switch (event.type) {
- case PP_INPUTEVENT_TYPE_MOUSEDOWN:
- mouse_event->type = WebInputEvent::MouseDown;
- break;
- case PP_INPUTEVENT_TYPE_MOUSEUP:
- mouse_event->type = WebInputEvent::MouseUp;
- break;
- case PP_INPUTEVENT_TYPE_MOUSEMOVE:
- mouse_event->type = WebInputEvent::MouseMove;
- break;
- case PP_INPUTEVENT_TYPE_MOUSEENTER:
- mouse_event->type = WebInputEvent::MouseEnter;
- break;
- case PP_INPUTEVENT_TYPE_MOUSELEAVE:
- mouse_event->type = WebInputEvent::MouseLeave;
- break;
- default:
- NOTREACHED();
- }
- mouse_event->timeStampSeconds = event.time_stamp;
- mouse_event->modifiers = event.u.mouse.modifier;
- mouse_event->button =
- static_cast<WebMouseEvent::Button>(event.u.mouse.button);
- mouse_event->x = static_cast<int>(event.u.mouse.x);
- mouse_event->y = static_cast<int>(event.u.mouse.y);
- mouse_event->clickCount = event.u.mouse.click_count;
- return mouse_event;
-}
-
-WebMouseWheelEvent* BuildMouseWheelEvent(const PP_InputEvent& event) {
- WebMouseWheelEvent* mouse_wheel_event = new WebMouseWheelEvent();
- mouse_wheel_event->type = WebInputEvent::MouseWheel;
- mouse_wheel_event->timeStampSeconds = event.time_stamp;
- mouse_wheel_event->modifiers = event.u.wheel.modifier;
- mouse_wheel_event->deltaX = event.u.wheel.delta_x;
- mouse_wheel_event->deltaY = event.u.wheel.delta_y;
- mouse_wheel_event->wheelTicksX = event.u.wheel.wheel_ticks_x;
- mouse_wheel_event->wheelTicksY = event.u.wheel.wheel_ticks_y;
- mouse_wheel_event->scrollByPage = event.u.wheel.scroll_by_page;
- return mouse_wheel_event;
-}
-
-} // namespace
-
-namespace pepper {
-
-void CreatePPEvent(const WebInputEvent& event,
- std::vector<PP_InputEvent>* pp_events) {
- pp_events->clear();
-
- switch (event.type) {
- case WebInputEvent::MouseDown:
- case WebInputEvent::MouseUp:
- case WebInputEvent::MouseMove:
- case WebInputEvent::MouseEnter:
- case WebInputEvent::MouseLeave:
- AppendMouseEvent(event, pp_events);
- break;
- case WebInputEvent::MouseWheel:
- AppendMouseWheelEvent(event, pp_events);
- break;
- case WebInputEvent::RawKeyDown:
- case WebInputEvent::KeyDown:
- case WebInputEvent::KeyUp:
- AppendKeyEvent(event, pp_events);
- break;
- case WebInputEvent::Char:
- AppendCharEvent(event, pp_events);
- break;
- case WebInputEvent::Undefined:
- default:
- break;
- }
-}
-
-WebInputEvent* CreateWebInputEvent(const PP_InputEvent& event) {
- scoped_ptr<WebInputEvent> web_input_event;
- switch (event.type) {
- case PP_INPUTEVENT_TYPE_UNDEFINED:
- return NULL;
- case PP_INPUTEVENT_TYPE_MOUSEDOWN:
- case PP_INPUTEVENT_TYPE_MOUSEUP:
- case PP_INPUTEVENT_TYPE_MOUSEMOVE:
- case PP_INPUTEVENT_TYPE_MOUSEENTER:
- case PP_INPUTEVENT_TYPE_MOUSELEAVE:
- web_input_event.reset(BuildMouseEvent(event));
- break;
- case PP_INPUTEVENT_TYPE_MOUSEWHEEL:
- web_input_event.reset(BuildMouseWheelEvent(event));
- break;
- case PP_INPUTEVENT_TYPE_RAWKEYDOWN:
- case PP_INPUTEVENT_TYPE_KEYDOWN:
- case PP_INPUTEVENT_TYPE_KEYUP:
- web_input_event.reset(BuildKeyEvent(event));
- break;
- case PP_INPUTEVENT_TYPE_CHAR:
- web_input_event.reset(BuildCharEvent(event));
- break;
- }
-
- return web_input_event.release();
-}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_event_conversion.h b/webkit/glue/plugins/pepper_event_conversion.h
deleted file mode 100644
index 9eab3e4..0000000
--- a/webkit/glue/plugins/pepper_event_conversion.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_EVENT_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_EVENT_H_
-
-#include <vector>
-
-struct PP_InputEvent;
-
-namespace WebKit {
-class WebInputEvent;
-}
-
-namespace pepper {
-
-// Converts the given WebKit event to one or possibly multiple PP_InputEvents.
-// The generated events will be filled into the given vector. On failure, no
-// events will ge generated and the vector will be empty.
-void CreatePPEvent(const WebKit::WebInputEvent& event,
- std::vector<PP_InputEvent>* pp_events);
-
-// Creates a WebInputEvent from the given PP_InputEvent. If it fails, returns
-// NULL. The caller owns the created object on success.
-WebKit::WebInputEvent* CreateWebInputEvent(const PP_InputEvent& event);
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_EVENT_H_
diff --git a/webkit/glue/plugins/pepper_file_callbacks.cc b/webkit/glue/plugins/pepper_file_callbacks.cc
deleted file mode 100644
index e24927a..0000000
--- a/webkit/glue/plugins/pepper_file_callbacks.cc
+++ /dev/null
@@ -1,99 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_file_callbacks.h"
-
-#include "base/file_path.h"
-#include "base/logging.h"
-#include "ppapi/c/dev/ppb_file_system_dev.h"
-#include "ppapi/c/dev/pp_file_info_dev.h"
-#include "ppapi/c/pp_errors.h"
-#include "webkit/glue/plugins/pepper_directory_reader.h"
-#include "webkit/glue/plugins/pepper_error_util.h"
-#include "webkit/glue/plugins/pepper_file_system.h"
-#include "webkit/fileapi/file_system_types.h"
-
-namespace pepper {
-
-FileCallbacks::FileCallbacks(const base::WeakPtr<PluginModule>& module,
- PP_CompletionCallback callback,
- PP_FileInfo_Dev* info,
- scoped_refptr<FileSystem> file_system,
- scoped_refptr<DirectoryReader> directory_reader)
- : module_(module),
- callback_(callback),
- info_(info),
- file_system_(file_system),
- directory_reader_(directory_reader) {
-}
-
-FileCallbacks::~FileCallbacks() {}
-
-void FileCallbacks::DidSucceed() {
- if (!module_.get() || !callback_.func)
- return;
-
- PP_RunCompletionCallback(&callback_, PP_OK);
-}
-
-void FileCallbacks::DidReadMetadata(
- const base::PlatformFileInfo& file_info) {
- if (!module_.get() || !callback_.func)
- return;
-
- DCHECK(info_);
- DCHECK(file_system_);
- info_->size = file_info.size;
- info_->creation_time = file_info.creation_time.ToDoubleT();
- info_->last_access_time = file_info.last_accessed.ToDoubleT();
- info_->last_modified_time = file_info.last_modified.ToDoubleT();
- info_->system_type = file_system_->type();
- if (file_info.is_directory)
- info_->type = PP_FILETYPE_DIRECTORY;
- else
- info_->type = PP_FILETYPE_REGULAR;
-
- PP_RunCompletionCallback(&callback_, PP_OK);
-}
-
-void FileCallbacks::DidReadDirectory(
- const std::vector<base::FileUtilProxy::Entry>& entries, bool has_more) {
- if (!module_.get() || !callback_.func)
- return;
-
- DCHECK(directory_reader_);
- directory_reader_->AddNewEntries(entries, has_more);
-
- PP_RunCompletionCallback(&callback_, PP_OK);
-}
-
-void FileCallbacks::DidOpenFileSystem(const std::string&,
- const FilePath& root_path) {
- if (!module_.get() || !callback_.func)
- return;
-
- DCHECK(file_system_);
- file_system_->set_root_path(root_path);
- file_system_->set_opened(true);
-
- PP_RunCompletionCallback(&callback_, PP_OK);
-}
-
-void FileCallbacks::DidFail(base::PlatformFileError error_code) {
- RunCallback(error_code);
-}
-
-void FileCallbacks::DidWrite(int64 bytes, bool complete) {
- NOTREACHED();
-}
-
-void FileCallbacks::RunCallback(base::PlatformFileError error_code) {
- if (!module_.get() || !callback_.func)
- return;
-
- PP_RunCompletionCallback(
- &callback_, pepper::PlatformFileErrorToPepperError(error_code));
-}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_file_callbacks.h b/webkit/glue/plugins/pepper_file_callbacks.h
deleted file mode 100644
index d4a92f2..0000000
--- a/webkit/glue/plugins/pepper_file_callbacks.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_FILE_CALLBACKS_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_FILE_CALLBACKS_H_
-
-#include "base/platform_file.h"
-#include "base/weak_ptr.h"
-#include "ppapi/c/pp_completion_callback.h"
-#include "webkit/fileapi/file_system_callback_dispatcher.h"
-
-struct PP_FileInfo_Dev;
-
-namespace base {
-class FilePath;
-}
-
-namespace pepper {
-
-class DirectoryReader;
-class FileSystem;
-class PluginModule;
-
-// Instances of this class are deleted by FileSystemDispatcher.
-class FileCallbacks : public fileapi::FileSystemCallbackDispatcher {
- public:
- FileCallbacks(const base::WeakPtr<PluginModule>& module,
- PP_CompletionCallback callback,
- PP_FileInfo_Dev* info,
- scoped_refptr<FileSystem> file_system,
- scoped_refptr<DirectoryReader> directory_reader);
- virtual ~FileCallbacks();
-
- // FileSystemCallbackDispatcher implementation.
- virtual void DidSucceed();
- virtual void DidReadMetadata(const base::PlatformFileInfo& file_info);
- virtual void DidReadDirectory(
- const std::vector<base::FileUtilProxy::Entry>& entries, bool has_more);
- virtual void DidOpenFileSystem(const std::string&,
- const FilePath& root_path);
- virtual void DidFail(base::PlatformFileError error_code);
- virtual void DidWrite(int64 bytes, bool complete);
-
- private:
- void RunCallback(base::PlatformFileError error_code);
-
- base::WeakPtr<PluginModule> module_;
- PP_CompletionCallback callback_;
- PP_FileInfo_Dev* info_;
- scoped_refptr<FileSystem> file_system_;
- scoped_refptr<DirectoryReader> directory_reader_;
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_FILE_CALLBACKS_H_
diff --git a/webkit/glue/plugins/pepper_file_chooser.cc b/webkit/glue/plugins/pepper_file_chooser.cc
deleted file mode 100644
index 2b54790..0000000
--- a/webkit/glue/plugins/pepper_file_chooser.cc
+++ /dev/null
@@ -1,161 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_file_chooser.h"
-
-#include <string>
-#include <vector>
-
-#include "base/logging.h"
-#include "ppapi/c/pp_completion_callback.h"
-#include "ppapi/c/pp_errors.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebCString.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebFileChooserCompletion.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebFileChooserParams.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebVector.h"
-#include "webkit/glue/plugins/pepper_common.h"
-#include "webkit/glue/plugins/pepper_file_ref.h"
-#include "webkit/glue/plugins/pepper_plugin_delegate.h"
-#include "webkit/glue/plugins/pepper_plugin_instance.h"
-#include "webkit/glue/plugins/pepper_resource_tracker.h"
-#include "webkit/glue/webkit_glue.h"
-
-using WebKit::WebCString;
-using WebKit::WebFileChooserCompletion;
-using WebKit::WebFileChooserParams;
-using WebKit::WebString;
-using WebKit::WebVector;
-
-namespace pepper {
-
-namespace {
-
-PP_Resource Create(PP_Instance instance_id,
- const PP_FileChooserOptions_Dev* options) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return 0;
-
- if ((options->mode != PP_FILECHOOSERMODE_OPEN) &&
- (options->mode != PP_FILECHOOSERMODE_OPENMULTIPLE))
- return 0;
-
- FileChooser* chooser = new FileChooser(instance, options);
- return chooser->GetReference();
-}
-
-PP_Bool IsFileChooser(PP_Resource resource) {
- return BoolToPPBool(!!Resource::GetAs<FileChooser>(resource));
-}
-
-int32_t Show(PP_Resource chooser_id, PP_CompletionCallback callback) {
- scoped_refptr<FileChooser> chooser(
- Resource::GetAs<FileChooser>(chooser_id));
- if (!chooser)
- return PP_ERROR_BADRESOURCE;
-
- return chooser->Show(callback);
-}
-
-PP_Resource GetNextChosenFile(PP_Resource chooser_id) {
- scoped_refptr<FileChooser> chooser(
- Resource::GetAs<FileChooser>(chooser_id));
- if (!chooser)
- return 0;
-
- scoped_refptr<FileRef> file_ref(chooser->GetNextChosenFile());
- if (!file_ref)
- return 0;
-
- return file_ref->GetReference();
-}
-
-const PPB_FileChooser_Dev ppb_filechooser = {
- &Create,
- &IsFileChooser,
- &Show,
- &GetNextChosenFile
-};
-
-class FileChooserCompletionImpl : public WebFileChooserCompletion {
- public:
- FileChooserCompletionImpl(pepper::FileChooser* file_chooser)
- : file_chooser_(file_chooser) {
- DCHECK(file_chooser_);
- }
-
- virtual ~FileChooserCompletionImpl() {}
-
- virtual void didChooseFile(const WebVector<WebString>& file_names) {
- std::vector<std::string> files;
- for (size_t i = 0; i < file_names.size(); i++)
- files.push_back(file_names[i].utf8().data());
-
- file_chooser_->StoreChosenFiles(files);
- }
-
- private:
- FileChooser* file_chooser_;
-};
-
-} // namespace
-
-FileChooser::FileChooser(PluginInstance* instance,
- const PP_FileChooserOptions_Dev* options)
- : Resource(instance->module()),
- delegate_(instance->delegate()),
- mode_(options->mode),
- accept_mime_types_(options->accept_mime_types),
- completion_callback_() {
-}
-
-FileChooser::~FileChooser() {
-}
-
-// static
-const PPB_FileChooser_Dev* FileChooser::GetInterface() {
- return &ppb_filechooser;
-}
-
-void FileChooser::StoreChosenFiles(const std::vector<std::string>& files) {
- next_chosen_file_index_ = 0;
- std::vector<std::string>::const_iterator end_it = files.end();
- for (std::vector<std::string>::const_iterator it = files.begin();
- it != end_it; it++) {
- chosen_files_.push_back(make_scoped_refptr(
- new FileRef(module(), FilePath().AppendASCII(*it))));
- }
-
- if (!completion_callback_.func)
- return;
-
- PP_CompletionCallback callback = {0};
- std::swap(callback, completion_callback_);
- PP_RunCompletionCallback(&callback, 0);
-}
-
-int32_t FileChooser::Show(PP_CompletionCallback callback) {
- DCHECK((mode_ == PP_FILECHOOSERMODE_OPEN) ||
- (mode_ == PP_FILECHOOSERMODE_OPENMULTIPLE));
- DCHECK(!completion_callback_.func);
- completion_callback_ = callback;
-
- WebFileChooserParams params;
- params.multiSelect = (mode_ == PP_FILECHOOSERMODE_OPENMULTIPLE);
- params.acceptTypes = WebString::fromUTF8(accept_mime_types_);
- params.directory = false;
-
- return delegate_->RunFileChooser(
- params, new FileChooserCompletionImpl(this));
-}
-
-scoped_refptr<FileRef> FileChooser::GetNextChosenFile() {
- if (next_chosen_file_index_ >= chosen_files_.size())
- return NULL;
-
- return chosen_files_[next_chosen_file_index_++];
-}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_file_chooser.h b/webkit/glue/plugins/pepper_file_chooser.h
deleted file mode 100644
index 664f934..0000000
--- a/webkit/glue/plugins/pepper_file_chooser.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_FILE_CHOOSER_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_FILE_CHOOSER_H_
-
-#include <string>
-#include <vector>
-
-#include "base/scoped_ptr.h"
-#include "ppapi/c/dev/ppb_file_chooser_dev.h"
-#include "ppapi/c/pp_completion_callback.h"
-#include "webkit/glue/plugins/pepper_resource.h"
-
-namespace pepper {
-
-class PluginDelegate;
-class PluginInstance;
-
-class FileChooser : public Resource {
- public:
- FileChooser(PluginInstance* instance,
- const PP_FileChooserOptions_Dev* options);
- virtual ~FileChooser();
-
- // Returns a pointer to the interface implementing PPB_FileChooser that is
- // exposed to the plugin.
- static const PPB_FileChooser_Dev* GetInterface();
-
- // Resource overrides.
- FileChooser* AsFileChooser() { return this; }
-
- // Stores the list of selected files.
- void StoreChosenFiles(const std::vector<std::string>& files);
-
- // PPB_FileChooser implementation.
- int32_t Show(PP_CompletionCallback callback);
- scoped_refptr<FileRef> GetNextChosenFile();
-
- private:
- PluginDelegate* delegate_;
- PP_FileChooserMode_Dev mode_;
- std::string accept_mime_types_;
- PP_CompletionCallback completion_callback_;
- std::vector< scoped_refptr<FileRef> > chosen_files_;
- size_t next_chosen_file_index_;
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_FILE_CHOOSER_H_
diff --git a/webkit/glue/plugins/pepper_file_io.cc b/webkit/glue/plugins/pepper_file_io.cc
deleted file mode 100644
index 1d3d66e..0000000
--- a/webkit/glue/plugins/pepper_file_io.cc
+++ /dev/null
@@ -1,433 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_file_io.h"
-
-#include "base/callback.h"
-#include "base/file_util.h"
-#include "base/file_util_proxy.h"
-#include "base/message_loop_proxy.h"
-#include "base/platform_file.h"
-#include "base/logging.h"
-#include "base/time.h"
-#include "ppapi/c/dev/ppb_file_io_dev.h"
-#include "ppapi/c/dev/ppb_file_io_trusted_dev.h"
-#include "ppapi/c/pp_completion_callback.h"
-#include "ppapi/c/pp_errors.h"
-#include "webkit/glue/plugins/pepper_common.h"
-#include "webkit/glue/plugins/pepper_file_ref.h"
-#include "webkit/glue/plugins/pepper_plugin_instance.h"
-#include "webkit/glue/plugins/pepper_plugin_module.h"
-#include "webkit/glue/plugins/pepper_resource_tracker.h"
-
-namespace pepper {
-
-namespace {
-
-PP_Resource Create(PP_Module module_id) {
- PluginModule* module = ResourceTracker::Get()->GetModule(module_id);
- if (!module)
- return 0;
-
- FileIO* file_io = new FileIO(module);
- return file_io->GetReference();
-}
-
-PP_Bool IsFileIO(PP_Resource resource) {
- return BoolToPPBool(!!Resource::GetAs<FileIO>(resource));
-}
-
-int32_t Open(PP_Resource file_io_id,
- PP_Resource file_ref_id,
- int32_t open_flags,
- PP_CompletionCallback callback) {
- scoped_refptr<FileIO> file_io(Resource::GetAs<FileIO>(file_io_id));
- if (!file_io)
- return PP_ERROR_BADRESOURCE;
-
- scoped_refptr<FileRef> file_ref(Resource::GetAs<FileRef>(file_ref_id));
- if (!file_ref)
- return PP_ERROR_BADRESOURCE;
-
- return file_io->Open(file_ref, open_flags, callback);
-}
-
-int32_t Query(PP_Resource file_io_id,
- PP_FileInfo_Dev* info,
- PP_CompletionCallback callback) {
- scoped_refptr<FileIO> file_io(Resource::GetAs<FileIO>(file_io_id));
- if (!file_io)
- return PP_ERROR_BADRESOURCE;
- return file_io->Query(info, callback);
-}
-
-int32_t Touch(PP_Resource file_io_id,
- PP_Time last_access_time,
- PP_Time last_modified_time,
- PP_CompletionCallback callback) {
- scoped_refptr<FileIO> file_io(Resource::GetAs<FileIO>(file_io_id));
- if (!file_io)
- return PP_ERROR_BADRESOURCE;
- return file_io->Touch(last_access_time, last_modified_time, callback);
-}
-
-int32_t Read(PP_Resource file_io_id,
- int64_t offset,
- char* buffer,
- int32_t bytes_to_read,
- PP_CompletionCallback callback) {
- scoped_refptr<FileIO> file_io(Resource::GetAs<FileIO>(file_io_id));
- if (!file_io)
- return PP_ERROR_BADRESOURCE;
- return file_io->Read(offset, buffer, bytes_to_read, callback);
-}
-
-int32_t Write(PP_Resource file_io_id,
- int64_t offset,
- const char* buffer,
- int32_t bytes_to_write,
- PP_CompletionCallback callback) {
- scoped_refptr<FileIO> file_io(Resource::GetAs<FileIO>(file_io_id));
- if (!file_io)
- return PP_ERROR_BADRESOURCE;
- return file_io->Write(offset, buffer, bytes_to_write, callback);
-}
-
-int32_t SetLength(PP_Resource file_io_id,
- int64_t length,
- PP_CompletionCallback callback) {
- scoped_refptr<FileIO> file_io(Resource::GetAs<FileIO>(file_io_id));
- if (!file_io)
- return PP_ERROR_BADRESOURCE;
- return file_io->SetLength(length, callback);
-}
-
-int32_t Flush(PP_Resource file_io_id,
- PP_CompletionCallback callback) {
- scoped_refptr<FileIO> file_io(Resource::GetAs<FileIO>(file_io_id));
- if (!file_io)
- return PP_ERROR_BADRESOURCE;
- return file_io->Flush(callback);
-}
-
-void Close(PP_Resource file_io_id) {
- scoped_refptr<FileIO> file_io(Resource::GetAs<FileIO>(file_io_id));
- if (!file_io)
- return;
- file_io->Close();
-}
-
-const PPB_FileIO_Dev ppb_fileio = {
- &Create,
- &IsFileIO,
- &Open,
- &Query,
- &Touch,
- &Read,
- &Write,
- &SetLength,
- &Flush,
- &Close
-};
-
-int32_t GetOSFileDescriptor(PP_Resource file_io_id) {
- scoped_refptr<FileIO> file_io(Resource::GetAs<FileIO>(file_io_id));
- if (!file_io)
- return PP_ERROR_BADRESOURCE;
- return file_io->GetOSFileDescriptor();
-}
-
-int32_t WillWrite(PP_Resource file_io_id,
- int64_t offset,
- int32_t bytes_to_write,
- PP_CompletionCallback callback) {
- scoped_refptr<FileIO> file_io(Resource::GetAs<FileIO>(file_io_id));
- if (!file_io)
- return PP_ERROR_BADRESOURCE;
- return file_io->WillWrite(offset, bytes_to_write, callback);
-}
-
-int32_t WillSetLength(PP_Resource file_io_id,
- int64_t length,
- PP_CompletionCallback callback) {
- scoped_refptr<FileIO> file_io(Resource::GetAs<FileIO>(file_io_id));
- if (!file_io)
- return PP_ERROR_BADRESOURCE;
- return file_io->WillSetLength(length, callback);
-}
-
-const PPB_FileIOTrusted_Dev ppb_fileiotrusted = {
- &GetOSFileDescriptor,
- &WillWrite,
- &WillSetLength
-};
-
-int PlatformFileErrorToPepperError(base::PlatformFileError error_code) {
- switch (error_code) {
- case base::PLATFORM_FILE_OK:
- return PP_OK;
- case base::PLATFORM_FILE_ERROR_EXISTS:
- return PP_ERROR_FILEEXISTS;
- case base::PLATFORM_FILE_ERROR_NOT_FOUND:
- return PP_ERROR_FILENOTFOUND;
- case base::PLATFORM_FILE_ERROR_ACCESS_DENIED:
- return PP_ERROR_NOACCESS;
- case base::PLATFORM_FILE_ERROR_NO_MEMORY:
- return PP_ERROR_NOMEMORY;
- case base::PLATFORM_FILE_ERROR_NO_SPACE:
- return PP_ERROR_NOSPACE;
- case base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY:
- NOTREACHED();
- return PP_ERROR_FAILED;
- default:
- return PP_ERROR_FAILED;
- }
-}
-
-} // namespace
-
-FileIO::FileIO(PluginModule* module)
- : Resource(module),
- delegate_(module->GetSomeInstance()->delegate()),
- ALLOW_THIS_IN_INITIALIZER_LIST(callback_factory_(this)),
- file_(base::kInvalidPlatformFileValue),
- callback_(),
- info_(NULL) {
-}
-
-FileIO::~FileIO() {
- Close();
-}
-
-// static
-const PPB_FileIO_Dev* FileIO::GetInterface() {
- return &ppb_fileio;
-}
-
-// static
-const PPB_FileIOTrusted_Dev* FileIO::GetTrustedInterface() {
- return &ppb_fileiotrusted;
-}
-
-int32_t FileIO::Open(FileRef* file_ref,
- int32_t open_flags,
- PP_CompletionCallback callback) {
- if (file_ != base::kInvalidPlatformFileValue)
- return PP_ERROR_FAILED;
-
- DCHECK(!callback_.func);
- callback_ = callback;
-
- int flags = 0;
- if (open_flags & PP_FILEOPENFLAG_READ)
- flags |= base::PLATFORM_FILE_READ;
- if (open_flags & PP_FILEOPENFLAG_WRITE) {
- flags |= base::PLATFORM_FILE_WRITE;
- flags |= base::PLATFORM_FILE_WRITE_ATTRIBUTES;
- }
-
- if (open_flags & PP_FILEOPENFLAG_TRUNCATE) {
- DCHECK(open_flags & PP_FILEOPENFLAG_WRITE);
- flags |= base::PLATFORM_FILE_TRUNCATE;
- } else if (open_flags & PP_FILEOPENFLAG_CREATE) {
- if (open_flags & PP_FILEOPENFLAG_EXCLUSIVE)
- flags |= base::PLATFORM_FILE_CREATE;
- else
- flags |= base::PLATFORM_FILE_OPEN_ALWAYS;
- } else
- flags |= base::PLATFORM_FILE_OPEN;
-
- file_system_type_ = file_ref->GetFileSystemType();
- if (!delegate_->AsyncOpenFile(
- file_ref->GetSystemPath(), flags,
- callback_factory_.NewCallback(&FileIO::AsyncOpenFileCallback)))
- return PP_ERROR_FAILED;
-
- return PP_ERROR_WOULDBLOCK;
-}
-
-int32_t FileIO::Query(PP_FileInfo_Dev* info,
- PP_CompletionCallback callback) {
- if (file_ == base::kInvalidPlatformFileValue)
- return PP_ERROR_FAILED;
-
- DCHECK(!callback_.func);
- callback_ = callback;
-
- DCHECK(!info_);
- DCHECK(info);
- info_ = info;
-
- if (!base::FileUtilProxy::GetFileInfoFromPlatformFile(
- delegate_->GetFileThreadMessageLoopProxy(), file_,
- callback_factory_.NewCallback(&FileIO::QueryInfoCallback)))
- return PP_ERROR_FAILED;
-
- return PP_ERROR_WOULDBLOCK;
-}
-
-int32_t FileIO::Touch(PP_Time last_access_time,
- PP_Time last_modified_time,
- PP_CompletionCallback callback) {
- if (file_ == base::kInvalidPlatformFileValue)
- return PP_ERROR_FAILED;
-
- DCHECK(!callback_.func);
- callback_ = callback;
-
- if (!base::FileUtilProxy::Touch(
- delegate_->GetFileThreadMessageLoopProxy(),
- file_, base::Time::FromDoubleT(last_access_time),
- base::Time::FromDoubleT(last_modified_time),
- callback_factory_.NewCallback(&FileIO::StatusCallback)))
- return PP_ERROR_FAILED;
-
- return PP_ERROR_WOULDBLOCK;
-}
-
-int32_t FileIO::Read(int64_t offset,
- char* buffer,
- int32_t bytes_to_read,
- PP_CompletionCallback callback) {
- if (file_ == base::kInvalidPlatformFileValue)
- return PP_ERROR_FAILED;
-
- DCHECK(!callback_.func);
- callback_ = callback;
-
- if (!base::FileUtilProxy::Read(
- delegate_->GetFileThreadMessageLoopProxy(),
- file_, offset, buffer, bytes_to_read,
- callback_factory_.NewCallback(&FileIO::ReadWriteCallback)))
- return PP_ERROR_FAILED;
-
- return PP_ERROR_WOULDBLOCK;
-}
-
-int32_t FileIO::Write(int64_t offset,
- const char* buffer,
- int32_t bytes_to_write,
- PP_CompletionCallback callback) {
- if (file_ == base::kInvalidPlatformFileValue)
- return PP_ERROR_FAILED;
-
- DCHECK(!callback_.func);
- callback_ = callback;
-
- if (!base::FileUtilProxy::Write(
- delegate_->GetFileThreadMessageLoopProxy(),
- file_, offset, buffer, bytes_to_write,
- callback_factory_.NewCallback(&FileIO::ReadWriteCallback)))
- return PP_ERROR_FAILED;
-
- return PP_ERROR_WOULDBLOCK;
-}
-
-int32_t FileIO::SetLength(int64_t length,
- PP_CompletionCallback callback) {
- if (file_ == base::kInvalidPlatformFileValue)
- return PP_ERROR_FAILED;
-
- DCHECK(!callback_.func);
- callback_ = callback;
-
- if (!base::FileUtilProxy::Truncate(
- delegate_->GetFileThreadMessageLoopProxy(),
- file_, length,
- callback_factory_.NewCallback(&FileIO::StatusCallback)))
- return PP_ERROR_FAILED;
-
- return PP_ERROR_WOULDBLOCK;
-}
-
-int32_t FileIO::Flush(PP_CompletionCallback callback) {
- if (file_ == base::kInvalidPlatformFileValue)
- return PP_ERROR_FAILED;
-
- DCHECK(!callback_.func);
- callback_ = callback;
-
- if (!base::FileUtilProxy::Flush(
- delegate_->GetFileThreadMessageLoopProxy(), file_,
- callback_factory_.NewCallback(&FileIO::StatusCallback)))
- return PP_ERROR_FAILED;
-
- return PP_ERROR_WOULDBLOCK;
-}
-
-void FileIO::Close() {
- if (file_ != base::kInvalidPlatformFileValue)
- base::FileUtilProxy::Close(
- delegate_->GetFileThreadMessageLoopProxy(), file_, NULL);
-}
-
-int32_t FileIO::GetOSFileDescriptor() {
-#if defined(OS_POSIX)
- return file_;
-#elif defined(OS_WIN)
- return reinterpret_cast<uintptr_t>(file_);
-#else
-#error "Platform not supported."
-#endif
-}
-
-int32_t FileIO::WillWrite(int64_t offset,
- int32_t bytes_to_write,
- PP_CompletionCallback callback) {
- // TODO(dumi): implement me
- return PP_OK;
-}
-
-int32_t FileIO::WillSetLength(int64_t length,
- PP_CompletionCallback callback) {
- // TODO(dumi): implement me
- return PP_OK;
-}
-
-void FileIO::RunPendingCallback(int result) {
- if (!callback_.func)
- return;
-
- PP_CompletionCallback callback = {0};
- std::swap(callback, callback_);
- PP_RunCompletionCallback(&callback, result);
-}
-
-void FileIO::StatusCallback(base::PlatformFileError error_code) {
- RunPendingCallback(PlatformFileErrorToPepperError(error_code));
-}
-
-void FileIO::AsyncOpenFileCallback(base::PlatformFileError error_code,
- base::PlatformFile file) {
- DCHECK(file_ == base::kInvalidPlatformFileValue);
- file_ = file;
- RunPendingCallback(PlatformFileErrorToPepperError(error_code));
-}
-
-void FileIO::QueryInfoCallback(base::PlatformFileError error_code,
- const base::PlatformFileInfo& file_info) {
- DCHECK(info_);
- if (error_code == base::PLATFORM_FILE_OK) {
- info_->size = file_info.size;
- info_->creation_time = file_info.creation_time.ToDoubleT();
- info_->last_access_time = file_info.last_accessed.ToDoubleT();
- info_->last_modified_time = file_info.last_modified.ToDoubleT();
- info_->system_type = file_system_type_;
- if (file_info.is_directory)
- info_->type = PP_FILETYPE_DIRECTORY;
- else
- info_->type = PP_FILETYPE_REGULAR;
- }
- RunPendingCallback(PlatformFileErrorToPepperError(error_code));
-}
-
-void FileIO::ReadWriteCallback(base::PlatformFileError error_code,
- int bytes_read_or_written) {
- if (error_code != base::PLATFORM_FILE_OK)
- RunPendingCallback(PlatformFileErrorToPepperError(error_code));
- else
- RunPendingCallback(bytes_read_or_written);
-}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_file_io.h b/webkit/glue/plugins/pepper_file_io.h
deleted file mode 100644
index 6fee92d..0000000
--- a/webkit/glue/plugins/pepper_file_io.h
+++ /dev/null
@@ -1,94 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_FILE_IO_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_FILE_IO_H_
-
-#include "base/file_path.h"
-#include "base/platform_file.h"
-#include "base/scoped_callback_factory.h"
-#include "base/scoped_ptr.h"
-#include "ppapi/c/dev/pp_file_info_dev.h"
-#include "ppapi/c/pp_completion_callback.h"
-#include "ppapi/c/pp_time.h"
-#include "webkit/glue/plugins/pepper_plugin_delegate.h"
-#include "webkit/glue/plugins/pepper_resource.h"
-
-struct PP_CompletionCallback;
-struct PPB_FileIO_Dev;
-struct PPB_FileIOTrusted_Dev;
-
-namespace pepper {
-
-class PluginModule;
-
-class FileIO : public Resource {
- public:
- explicit FileIO(PluginModule* module);
- virtual ~FileIO();
-
- // Returns a pointer to the interface implementing PPB_FileIO that is exposed
- // to the plugin.
- static const PPB_FileIO_Dev* GetInterface();
-
- // Returns a pointer to the interface implementing PPB_FileIOTrusted that is
- // exposed to the plugin.
- static const PPB_FileIOTrusted_Dev* GetTrustedInterface();
-
- // Resource overrides.
- FileIO* AsFileIO() { return this; }
-
- // PPB_FileIO implementation.
- int32_t Open(FileRef* file_ref,
- int32_t open_flags,
- PP_CompletionCallback callback);
- int32_t Query(PP_FileInfo_Dev* info,
- PP_CompletionCallback callback);
- int32_t Touch(PP_Time last_access_time,
- PP_Time last_modified_time,
- PP_CompletionCallback callback);
- int32_t Read(int64_t offset,
- char* buffer,
- int32_t bytes_to_read,
- PP_CompletionCallback callback);
- int32_t Write(int64_t offset,
- const char* buffer,
- int32_t bytes_to_write,
- PP_CompletionCallback callback);
- int32_t SetLength(int64_t length,
- PP_CompletionCallback callback);
- int32_t Flush(PP_CompletionCallback callback);
- void Close();
-
- // PPB_FileIOTrusted implementation.
- int32_t GetOSFileDescriptor();
- int32_t WillWrite(int64_t offset,
- int32_t bytes_to_write,
- PP_CompletionCallback callback);
- int32_t WillSetLength(int64_t length,
- PP_CompletionCallback callback);
-
- void RunPendingCallback(int result);
- void StatusCallback(base::PlatformFileError error_code);
- void AsyncOpenFileCallback(base::PlatformFileError error_code,
- base::PlatformFile file);
- void QueryInfoCallback(base::PlatformFileError error_code,
- const base::PlatformFileInfo& file_info);
- void ReadWriteCallback(base::PlatformFileError error_code,
- int bytes_read_or_written);
-
- private:
- PluginDelegate* delegate_;
- base::ScopedCallbackFactory<FileIO> callback_factory_;
-
- base::PlatformFile file_;
- PP_FileSystemType_Dev file_system_type_;
-
- PP_CompletionCallback callback_;
- PP_FileInfo_Dev* info_;
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_FILE_IO_H_
diff --git a/webkit/glue/plugins/pepper_file_ref.cc b/webkit/glue/plugins/pepper_file_ref.cc
deleted file mode 100644
index 6068a29..0000000
--- a/webkit/glue/plugins/pepper_file_ref.cc
+++ /dev/null
@@ -1,343 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_file_ref.h"
-
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-#include "ppapi/c/pp_errors.h"
-#include "webkit/glue/plugins/pepper_common.h"
-#include "webkit/glue/plugins/pepper_directory_reader.h"
-#include "webkit/glue/plugins/pepper_file_callbacks.h"
-#include "webkit/glue/plugins/pepper_file_system.h"
-#include "webkit/glue/plugins/pepper_plugin_delegate.h"
-#include "webkit/glue/plugins/pepper_plugin_instance.h"
-#include "webkit/glue/plugins/pepper_plugin_module.h"
-#include "webkit/glue/plugins/pepper_var.h"
-
-namespace pepper {
-
-namespace {
-
-bool IsValidLocalPath(const std::string& path) {
- // The path must start with '/'
- if (path.empty() || path[0] != '/')
- return false;
-
- // The path must contain valid UTF-8 characters.
- if (!IsStringUTF8(path))
- return false;
-
- return true;
-}
-
-void TrimTrailingSlash(std::string* path) {
- // If this path ends with a slash, then normalize it away unless path is the
- // root path.
- if (path->size() > 1 && path->at(path->size() - 1) == '/')
- path->erase(path->size() - 1, 1);
-}
-
-PP_Resource Create(PP_Resource file_system_id, const char* path) {
- scoped_refptr<FileSystem> file_system(
- Resource::GetAs<FileSystem>(file_system_id));
- if (!file_system)
- return 0;
-
- if (!file_system->instance())
- return 0;
-
- std::string validated_path(path);
- if (!IsValidLocalPath(validated_path))
- return 0;
- TrimTrailingSlash(&validated_path);
-
- FileRef* file_ref = new FileRef(file_system->instance()->module(),
- file_system,
- validated_path);
- return file_ref->GetReference();
-}
-
-PP_Bool IsFileRef(PP_Resource resource) {
- return BoolToPPBool(!!Resource::GetAs<FileRef>(resource));
-}
-
-PP_FileSystemType_Dev GetFileSystemType(PP_Resource file_ref_id) {
- scoped_refptr<FileRef> file_ref(Resource::GetAs<FileRef>(file_ref_id));
- if (!file_ref)
- return PP_FILESYSTEMTYPE_EXTERNAL;
- return file_ref->GetFileSystemType();
-}
-
-PP_Var GetName(PP_Resource file_ref_id) {
- scoped_refptr<FileRef> file_ref(Resource::GetAs<FileRef>(file_ref_id));
- if (!file_ref)
- return PP_MakeUndefined();
- return StringVar::StringToPPVar(file_ref->module(), file_ref->GetName());
-}
-
-PP_Var GetPath(PP_Resource file_ref_id) {
- scoped_refptr<FileRef> file_ref(Resource::GetAs<FileRef>(file_ref_id));
- if (!file_ref)
- return PP_MakeUndefined();
-
- if (file_ref->GetFileSystemType() == PP_FILESYSTEMTYPE_EXTERNAL)
- return PP_MakeUndefined();
-
- return StringVar::StringToPPVar(file_ref->module(), file_ref->GetPath());
-}
-
-PP_Resource GetParent(PP_Resource file_ref_id) {
- scoped_refptr<FileRef> file_ref(Resource::GetAs<FileRef>(file_ref_id));
- if (!file_ref)
- return 0;
-
- if (file_ref->GetFileSystemType() == PP_FILESYSTEMTYPE_EXTERNAL)
- return 0;
-
- scoped_refptr<FileRef> parent_ref(file_ref->GetParent());
- if (!parent_ref)
- return 0;
-
- return parent_ref->GetReference();
-}
-
-int32_t MakeDirectory(PP_Resource directory_ref_id,
- PP_Bool make_ancestors,
- PP_CompletionCallback callback) {
- scoped_refptr<FileRef> directory_ref(
- Resource::GetAs<FileRef>(directory_ref_id));
- if (!directory_ref)
- return PP_ERROR_BADRESOURCE;
-
- scoped_refptr<FileSystem> file_system = directory_ref->GetFileSystem();
- if (!file_system || !file_system->opened() ||
- (file_system->type() == PP_FILESYSTEMTYPE_EXTERNAL))
- return PP_ERROR_NOACCESS;
-
- PluginInstance* instance = file_system->instance();
- if (!instance->delegate()->MakeDirectory(
- directory_ref->GetSystemPath(), PPBoolToBool(make_ancestors),
- new FileCallbacks(instance->module()->AsWeakPtr(),
- callback, NULL, NULL, NULL)))
- return PP_ERROR_FAILED;
-
- return PP_ERROR_WOULDBLOCK;
-}
-
-int32_t Query(PP_Resource file_ref_id,
- PP_FileInfo_Dev* info,
- PP_CompletionCallback callback) {
- scoped_refptr<FileRef> file_ref(Resource::GetAs<FileRef>(file_ref_id));
- if (!file_ref)
- return PP_ERROR_BADRESOURCE;
-
- scoped_refptr<FileSystem> file_system = file_ref->GetFileSystem();
- if (!file_system || !file_system->opened() ||
- (file_system->type() == PP_FILESYSTEMTYPE_EXTERNAL))
- return PP_ERROR_NOACCESS;
-
- PluginInstance* instance = file_system->instance();
- if (!instance->delegate()->Query(
- file_ref->GetSystemPath(),
- new FileCallbacks(instance->module()->AsWeakPtr(),
- callback, info, file_system, NULL)))
- return PP_ERROR_FAILED;
-
- return PP_ERROR_WOULDBLOCK;
-}
-
-int32_t Touch(PP_Resource file_ref_id,
- PP_Time last_access_time,
- PP_Time last_modified_time,
- PP_CompletionCallback callback) {
- scoped_refptr<FileRef> file_ref(Resource::GetAs<FileRef>(file_ref_id));
- if (!file_ref)
- return PP_ERROR_BADRESOURCE;
-
- scoped_refptr<FileSystem> file_system = file_ref->GetFileSystem();
- if (!file_system || !file_system->opened() ||
- (file_system->type() == PP_FILESYSTEMTYPE_EXTERNAL))
- return PP_ERROR_NOACCESS;
-
- PluginInstance* instance = file_system->instance();
- if (!instance->delegate()->Touch(
- file_ref->GetSystemPath(), base::Time::FromDoubleT(last_access_time),
- base::Time::FromDoubleT(last_modified_time),
- new FileCallbacks(instance->module()->AsWeakPtr(),
- callback, NULL, NULL, NULL)))
- return PP_ERROR_FAILED;
-
- return PP_ERROR_WOULDBLOCK;
-}
-
-int32_t Delete(PP_Resource file_ref_id,
- PP_CompletionCallback callback) {
- scoped_refptr<FileRef> file_ref(Resource::GetAs<FileRef>(file_ref_id));
- if (!file_ref)
- return PP_ERROR_BADRESOURCE;
-
- scoped_refptr<FileSystem> file_system = file_ref->GetFileSystem();
- if (!file_system || !file_system->opened() ||
- (file_system->type() == PP_FILESYSTEMTYPE_EXTERNAL))
- return PP_ERROR_NOACCESS;
-
- PluginInstance* instance = file_system->instance();
- if (!instance->delegate()->Delete(
- file_ref->GetSystemPath(),
- new FileCallbacks(instance->module()->AsWeakPtr(),
- callback, NULL, NULL, NULL)))
- return PP_ERROR_FAILED;
-
- return PP_ERROR_WOULDBLOCK;
-}
-
-int32_t Rename(PP_Resource file_ref_id,
- PP_Resource new_file_ref_id,
- PP_CompletionCallback callback) {
- scoped_refptr<FileRef> file_ref(Resource::GetAs<FileRef>(file_ref_id));
- if (!file_ref)
- return PP_ERROR_BADRESOURCE;
-
- scoped_refptr<FileRef> new_file_ref(
- Resource::GetAs<FileRef>(new_file_ref_id));
- if (!new_file_ref)
- return PP_ERROR_BADRESOURCE;
-
- scoped_refptr<FileSystem> file_system = file_ref->GetFileSystem();
- if (!file_system || !file_system->opened() ||
- (file_system != new_file_ref->GetFileSystem()) ||
- (file_system->type() == PP_FILESYSTEMTYPE_EXTERNAL))
- return PP_ERROR_NOACCESS;
-
- PluginInstance* instance = file_system->instance();
- if (!instance->delegate()->Rename(
- file_ref->GetSystemPath(), new_file_ref->GetSystemPath(),
- new FileCallbacks(instance->module()->AsWeakPtr(),
- callback, NULL, NULL, NULL)))
- return PP_ERROR_FAILED;
-
- return PP_ERROR_WOULDBLOCK;
-}
-
-const PPB_FileRef_Dev ppb_fileref = {
- &Create,
- &IsFileRef,
- &GetFileSystemType,
- &GetName,
- &GetPath,
- &GetParent,
- &MakeDirectory,
- &Query,
- &Touch,
- &Delete,
- &Rename
-};
-
-} // namespace
-
-FileRef::FileRef()
- : Resource(NULL),
- file_system_(NULL) {
-}
-
-FileRef::FileRef(PluginModule* module,
- scoped_refptr<FileSystem> file_system,
- const std::string& validated_path)
- : Resource(module),
- file_system_(file_system),
- virtual_path_(validated_path) {
-}
-
-FileRef::FileRef(PluginModule* module,
- const FilePath& external_file_path)
- : Resource(module),
- file_system_(NULL),
- system_path_(external_file_path) {
-}
-
-FileRef::~FileRef() {
-}
-
-// static
-const PPB_FileRef_Dev* FileRef::GetInterface() {
- return &ppb_fileref;
-}
-
-std::string FileRef::GetName() const {
- if (GetFileSystemType() == PP_FILESYSTEMTYPE_EXTERNAL) {
- FilePath::StringType path = system_path_.value();
- size_t pos = path.rfind(FilePath::kSeparators[0]);
- DCHECK(pos != FilePath::StringType::npos);
-#if defined(OS_WIN)
- return WideToUTF8(path.substr(pos + 1));
-#elif defined(OS_POSIX)
- return path.substr(pos + 1);
-#else
-#error "Unsupported platform."
-#endif
- }
-
- if (virtual_path_.size() == 1 && virtual_path_[0] == '/')
- return virtual_path_;
-
- // There should always be a leading slash at least!
- size_t pos = virtual_path_.rfind('/');
- DCHECK(pos != std::string::npos);
-
- return virtual_path_.substr(pos + 1);
-}
-
-scoped_refptr<FileRef> FileRef::GetParent() {
- if (GetFileSystemType() == PP_FILESYSTEMTYPE_EXTERNAL)
- return new FileRef();
-
- // There should always be a leading slash at least!
- size_t pos = virtual_path_.rfind('/');
- DCHECK(pos != std::string::npos);
-
- // If the path is "/foo", then we want to include the slash.
- if (pos == 0)
- pos++;
- std::string parent_path = virtual_path_.substr(0, pos);
-
- FileRef* parent_ref = new FileRef(module(), file_system_, parent_path);
- return parent_ref;
-}
-
-scoped_refptr<FileSystem> FileRef::GetFileSystem() const {
- return file_system_;
-}
-
-PP_FileSystemType_Dev FileRef::GetFileSystemType() const {
- if (!file_system_)
- return PP_FILESYSTEMTYPE_EXTERNAL;
-
- return file_system_->type();
-}
-
-std::string FileRef::GetPath() const {
- return virtual_path_;
-}
-
-FilePath FileRef::GetSystemPath() const {
- if (GetFileSystemType() == PP_FILESYSTEMTYPE_EXTERNAL)
- return system_path_;
-
- // Since |virtual_path_| starts with a '/', it is considered an absolute path
- // on POSIX systems. We need to remove the '/' before calling Append() or we
- // will run into a DCHECK.
- FilePath virtual_file_path(
-#if defined(OS_WIN)
- UTF8ToWide(virtual_path_.substr(1))
-#elif defined(OS_POSIX)
- virtual_path_.substr(1)
-#else
-#error "Unsupported platform."
-#endif
- );
- return file_system_->root_path().Append(virtual_file_path);
-}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_file_ref.h b/webkit/glue/plugins/pepper_file_ref.h
deleted file mode 100644
index 88020c1..0000000
--- a/webkit/glue/plugins/pepper_file_ref.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_FILE_REF_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_FILE_REF_H_
-
-#include <string>
-
-#include "base/file_path.h"
-#include "ppapi/c/dev/ppb_file_ref_dev.h"
-#include "webkit/glue/plugins/pepper_resource.h"
-
-namespace pepper {
-
-class FileSystem;
-class PluginInstance;
-class PluginModule;
-
-class FileRef : public Resource {
- public:
- FileRef();
- FileRef(PluginModule* module,
- scoped_refptr<FileSystem> file_system,
- const std::string& validated_path);
- FileRef(PluginModule* module,
- const FilePath& external_file_path);
- virtual ~FileRef();
-
- // Returns a pointer to the interface implementing PPB_FileRef that is
- // exposed to the plugin.
- static const PPB_FileRef_Dev* GetInterface();
-
- // Resource overrides.
- FileRef* AsFileRef() { return this; }
-
- // PPB_FileRef implementation.
- std::string GetName() const;
- scoped_refptr<FileRef> GetParent();
-
- // Returns the file system to which this FileRef belongs.
- scoped_refptr<FileSystem> GetFileSystem() const;
-
- // Returns the type of the file system to which this FileRef belongs.
- PP_FileSystemType_Dev GetFileSystemType() const;
-
- // Returns the virtual path (i.e., the path that the pepper plugin sees)
- // corresponding to this file.
- std::string GetPath() const;
-
- // Returns the system path corresponding to this file.
- FilePath GetSystemPath() const;
-
- private:
- scoped_refptr<FileSystem> file_system_;
- std::string virtual_path_; // UTF-8 encoded
- FilePath system_path_;
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_FILE_REF_H_
diff --git a/webkit/glue/plugins/pepper_file_system.cc b/webkit/glue/plugins/pepper_file_system.cc
deleted file mode 100644
index 9262798..0000000
--- a/webkit/glue/plugins/pepper_file_system.cc
+++ /dev/null
@@ -1,85 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_file_system.h"
-
-#include "base/ref_counted.h"
-#include "ppapi/c/dev/ppb_file_system_dev.h"
-#include "ppapi/c/pp_completion_callback.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebDocument.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebElement.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebPluginContainer.h"
-#include "webkit/fileapi/file_system_types.h"
-#include "webkit/glue/plugins/pepper_directory_reader.h"
-#include "webkit/glue/plugins/pepper_file_callbacks.h"
-#include "webkit/glue/plugins/pepper_plugin_delegate.h"
-#include "webkit/glue/plugins/pepper_plugin_instance.h"
-#include "webkit/glue/plugins/pepper_plugin_module.h"
-#include "webkit/glue/plugins/pepper_resource.h"
-#include "webkit/glue/plugins/pepper_resource_tracker.h"
-
-namespace pepper {
-
-namespace {
-
-PP_Resource Create(PP_Instance instance, PP_FileSystemType_Dev type) {
- PluginInstance* plugin_instance =
- ResourceTracker::Get()->GetInstance(instance);
- if (!plugin_instance)
- return 0;
-
- FileSystem* file_system = new FileSystem(plugin_instance, type);
- return file_system->GetReference();
-}
-
-int32_t Open(PP_Resource file_system_id,
- int64 expected_size,
- PP_CompletionCallback callback) {
- scoped_refptr<FileSystem> file_system(
- Resource::GetAs<FileSystem>(file_system_id));
- if (!file_system)
- return PP_ERROR_BADRESOURCE;
-
- if (file_system->opened())
- return PP_OK;
-
- if ((file_system->type() != PP_FILESYSTEMTYPE_LOCALPERSISTENT) &&
- (file_system->type() != PP_FILESYSTEMTYPE_LOCALTEMPORARY))
- return PP_ERROR_FAILED;
-
- PluginInstance* instance = file_system->instance();
- fileapi::FileSystemType file_system_type =
- (file_system->type() == PP_FILESYSTEMTYPE_LOCALTEMPORARY ?
- fileapi::kFileSystemTypeTemporary :
- fileapi::kFileSystemTypePersistent);
- if (!instance->delegate()->OpenFileSystem(
- instance->container()->element().document().frame()->url(),
- file_system_type, expected_size,
- new FileCallbacks(instance->module()->AsWeakPtr(),
- callback, NULL, file_system, NULL)))
- return PP_ERROR_FAILED;
-
- return PP_ERROR_WOULDBLOCK;
-}
-
-const PPB_FileSystem_Dev ppb_filesystem = {
- &Create,
- &Open
-};
-
-} // namespace
-
-FileSystem::FileSystem(PluginInstance* instance, PP_FileSystemType_Dev type)
- : Resource(instance->module()),
- instance_(instance),
- type_(type),
- opened_(false) {
-}
-
-const PPB_FileSystem_Dev* FileSystem::GetInterface() {
- return &ppb_filesystem;
-}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_file_system.h b/webkit/glue/plugins/pepper_file_system.h
deleted file mode 100644
index 97f1c7d..0000000
--- a/webkit/glue/plugins/pepper_file_system.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_FILE_SYSTEM_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_FILE_SYSTEM_H_
-
-#include "base/basictypes.h"
-#include "base/file_path.h"
-#include "ppapi/c/dev/pp_file_info_dev.h"
-#include "webkit/glue/plugins/pepper_resource.h"
-
-struct PPB_FileSystem_Dev;
-
-namespace pepper {
-
-class PluginInstance;
-
-class FileSystem : public Resource {
- public:
- // Returns a pointer to the interface implementing PPB_FileSystem that is
- // exposed to the plugin.
- static const PPB_FileSystem_Dev* GetInterface();
-
- FileSystem(PluginInstance* instance, PP_FileSystemType_Dev type);
- FileSystem* AsFileSystem() { return this; }
-
- PluginInstance* instance() { return instance_; }
- PP_FileSystemType_Dev type() { return type_; }
- const FilePath& root_path() const { return root_path_; }
- void set_root_path(const FilePath& root_path) { root_path_ = root_path; }
- bool opened() const { return opened_; }
- void set_opened(bool opened) { opened_ = opened; }
-
- private:
- PluginInstance* instance_;
- PP_FileSystemType_Dev type_;
- FilePath root_path_;
- bool opened_;
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_FILE_SYSTEM_H_
diff --git a/webkit/glue/plugins/pepper_font.cc b/webkit/glue/plugins/pepper_font.cc
deleted file mode 100644
index 553c8ed..0000000
--- a/webkit/glue/plugins/pepper_font.cc
+++ /dev/null
@@ -1,294 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_font.h"
-
-#include "base/logging.h"
-#include "base/utf_string_conversions.h"
-#include "ppapi/c/dev/ppb_font_dev.h"
-#include "ppapi/c/pp_rect.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebFont.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebFontDescription.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebRect.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebFloatPoint.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebFloatRect.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebTextRun.h"
-#include "webkit/glue/plugins/pepper_common.h"
-#include "webkit/glue/plugins/pepper_image_data.h"
-#include "webkit/glue/plugins/pepper_plugin_module.h"
-#include "webkit/glue/plugins/pepper_string.h"
-#include "webkit/glue/plugins/pepper_var.h"
-#include "webkit/glue/webkit_glue.h"
-
-using WebKit::WebFloatPoint;
-using WebKit::WebFloatRect;
-using WebKit::WebFont;
-using WebKit::WebFontDescription;
-using WebKit::WebRect;
-using WebKit::WebTextRun;
-
-namespace pepper {
-
-namespace {
-
-bool IsPPFontDescriptionValid(const PP_FontDescription_Dev& desc) {
- // Check validity of UTF-8.
- if (desc.face.type != PP_VARTYPE_STRING &&
- desc.face.type != PP_VARTYPE_UNDEFINED)
- return false;
-
- // Check enum ranges.
- if (static_cast<int>(desc.family) < PP_FONTFAMILY_DEFAULT ||
- static_cast<int>(desc.family) > PP_FONTFAMILY_MONOSPACE)
- return false;
- if (static_cast<int>(desc.weight) < PP_FONTWEIGHT_100 ||
- static_cast<int>(desc.weight) > PP_FONTWEIGHT_900)
- return false;
-
- // Check for excessive sizes which may cause layout to get confused.
- if (desc.size > 200)
- return false;
-
- return true;
-}
-
-// The PP_* version lacks "None", so is just one value shifted from the
-// WebFontDescription version. These values are checked in
-// PPFontDescToWebFontDesc to make sure the conversion is correct. This is a
-// macro so it can also be used in the COMPILE_ASSERTS.
-#define PP_FONTFAMILY_TO_WEB_FONTFAMILY(f) \
- static_cast<WebFontDescription::GenericFamily>(f + 1)
-
-// Assumes the given PP_FontDescription has been validated.
-WebFontDescription PPFontDescToWebFontDesc(const PP_FontDescription_Dev& font) {
- // Verify that the enums match so we can just static cast.
- COMPILE_ASSERT(static_cast<int>(WebFontDescription::Weight100) ==
- static_cast<int>(PP_FONTWEIGHT_100),
- FontWeight100);
- COMPILE_ASSERT(static_cast<int>(WebFontDescription::Weight900) ==
- static_cast<int>(PP_FONTWEIGHT_900),
- FontWeight900);
- COMPILE_ASSERT(WebFontDescription::GenericFamilyStandard ==
- PP_FONTFAMILY_TO_WEB_FONTFAMILY(PP_FONTFAMILY_DEFAULT),
- StandardFamily);
- COMPILE_ASSERT(WebFontDescription::GenericFamilySerif ==
- PP_FONTFAMILY_TO_WEB_FONTFAMILY(PP_FONTFAMILY_SERIF),
- SerifFamily);
- COMPILE_ASSERT(WebFontDescription::GenericFamilySansSerif ==
- PP_FONTFAMILY_TO_WEB_FONTFAMILY(PP_FONTFAMILY_SANSSERIF),
- SansSerifFamily);
- COMPILE_ASSERT(WebFontDescription::GenericFamilyMonospace ==
- PP_FONTFAMILY_TO_WEB_FONTFAMILY(PP_FONTFAMILY_MONOSPACE),
- MonospaceFamily);
-
- WebFontDescription result;
- scoped_refptr<StringVar> face_name(StringVar::FromPPVar(font.face));
- if (face_name)
- result.family = UTF8ToUTF16(face_name->value());
- result.genericFamily = PP_FONTFAMILY_TO_WEB_FONTFAMILY(font.family);
- result.size = static_cast<float>(font.size);
- result.italic = PPBoolToBool(font.italic);
- result.smallCaps = PPBoolToBool(font.small_caps);
- result.weight = static_cast<WebFontDescription::Weight>(font.weight);
- result.letterSpacing = static_cast<short>(font.letter_spacing);
- result.wordSpacing = static_cast<short>(font.word_spacing);
- return result;
-}
-
-// Converts the given PP_TextRun to a WebTextRun, returning true on success.
-// False means the input was invalid.
-bool PPTextRunToWebTextRun(const PP_TextRun_Dev* run, WebTextRun* output) {
- scoped_refptr<StringVar> text_string(StringVar::FromPPVar(run->text));
- if (!text_string)
- return false;
- *output = WebTextRun(UTF8ToUTF16(text_string->value()),
- PPBoolToBool(run->rtl),
- PPBoolToBool(run->override_direction));
- return true;
-}
-
-PP_Resource Create(PP_Module module_id,
- const PP_FontDescription_Dev* description) {
- PluginModule* module = ResourceTracker::Get()->GetModule(module_id);
- if (!module)
- return 0;
-
- if (!IsPPFontDescriptionValid(*description))
- return 0;
-
- scoped_refptr<Font> font(new Font(module, *description));
- return font->GetReference();
-}
-
-PP_Bool IsFont(PP_Resource resource) {
- return BoolToPPBool(!!Resource::GetAs<Font>(resource).get());
-}
-
-PP_Bool Describe(PP_Resource font_id,
- PP_FontDescription_Dev* description,
- PP_FontMetrics_Dev* metrics) {
- scoped_refptr<Font> font(Resource::GetAs<Font>(font_id));
- if (!font.get())
- return PP_FALSE;
- return BoolToPPBool(font->Describe(description, metrics));
-}
-
-PP_Bool DrawTextAt(PP_Resource font_id,
- PP_Resource image_data,
- const PP_TextRun_Dev* text,
- const PP_Point* position,
- uint32_t color,
- const PP_Rect* clip,
- PP_Bool image_data_is_opaque) {
- scoped_refptr<Font> font(Resource::GetAs<Font>(font_id));
- if (!font.get())
- return PP_FALSE;
- return BoolToPPBool(font->DrawTextAt(image_data, text, position, color, clip,
- PPBoolToBool(image_data_is_opaque)));
-}
-
-int32_t MeasureText(PP_Resource font_id, const PP_TextRun_Dev* text) {
- scoped_refptr<Font> font(Resource::GetAs<Font>(font_id));
- if (!font.get())
- return -1;
- return font->MeasureText(text);
-}
-
-uint32_t CharacterOffsetForPixel(PP_Resource font_id,
- const PP_TextRun_Dev* text,
- int32_t pixel_position) {
- scoped_refptr<Font> font(Resource::GetAs<Font>(font_id));
- if (!font.get())
- return false;
- return font->CharacterOffsetForPixel(text, pixel_position);
-}
-
-int32_t PixelOffsetForCharacter(PP_Resource font_id,
- const PP_TextRun_Dev* text,
- uint32_t char_offset) {
- scoped_refptr<Font> font(Resource::GetAs<Font>(font_id));
- if (!font.get())
- return false;
- return font->PixelOffsetForCharacter(text, char_offset);
-}
-
-const PPB_Font_Dev ppb_font = {
- &Create,
- &IsFont,
- &Describe,
- &DrawTextAt,
- &MeasureText,
- &CharacterOffsetForPixel,
- &PixelOffsetForCharacter
-};
-
-} // namespace
-
-Font::Font(PluginModule* module, const PP_FontDescription_Dev& desc)
- : Resource(module) {
- WebFontDescription web_font_desc = PPFontDescToWebFontDesc(desc);
- font_.reset(WebFont::create(web_font_desc));
-}
-
-Font::~Font() {
-}
-
-// static
-const PPB_Font_Dev* Font::GetInterface() {
- return &ppb_font;
-}
-
-bool Font::Describe(PP_FontDescription_Dev* description,
- PP_FontMetrics_Dev* metrics) {
- if (description->face.type != PP_VARTYPE_UNDEFINED)
- return false;
-
- WebFontDescription web_desc = font_->fontDescription();
-
- // While converting the other way in PPFontDescToWebFontDesc we validated
- // that the enums can be casted.
- description->face = StringVar::StringToPPVar(module(),
- UTF16ToUTF8(web_desc.family));
- description->family = static_cast<PP_FontFamily_Dev>(web_desc.genericFamily);
- description->size = static_cast<uint32_t>(web_desc.size);
- description->weight = static_cast<PP_FontWeight_Dev>(web_desc.weight);
- description->italic = BoolToPPBool(web_desc.italic);
- description->small_caps = BoolToPPBool(web_desc.smallCaps);
-
- metrics->height = font_->height();
- metrics->ascent = font_->ascent();
- metrics->descent = font_->descent();
- metrics->line_spacing = font_->lineSpacing();
- metrics->x_height = static_cast<int32_t>(font_->xHeight());
-
- return true;
-}
-
-bool Font::DrawTextAt(PP_Resource image_data,
- const PP_TextRun_Dev* text,
- const PP_Point* position,
- uint32_t color,
- const PP_Rect* clip,
- bool image_data_is_opaque) {
- WebTextRun run;
- if (!PPTextRunToWebTextRun(text, &run))
- return false;
-
- // Get and map the image data we're painting to.
- scoped_refptr<ImageData> image_resource(
- Resource::GetAs<ImageData>(image_data));
- if (!image_resource.get())
- return false;
- ImageDataAutoMapper mapper(image_resource);
- if (!mapper.is_valid())
- return false;
-
- // Convert position and clip.
- WebFloatPoint web_position(static_cast<float>(position->x),
- static_cast<float>(position->y));
- WebRect web_clip;
- if (!clip) {
- // Use entire canvas.
- web_clip = WebRect(0, 0, image_resource->width(), image_resource->height());
- } else {
- web_clip = WebRect(clip->point.x, clip->point.y,
- clip->size.width, clip->size.height);
- }
-
- font_->drawText(webkit_glue::ToWebCanvas(image_resource->mapped_canvas()),
- run, web_position, color, web_clip, image_data_is_opaque);
- return true;
-}
-
-int32_t Font::MeasureText(const PP_TextRun_Dev* text) {
- WebTextRun run;
- if (!PPTextRunToWebTextRun(text, &run))
- return -1;
- return font_->calculateWidth(run);
-}
-
-uint32_t Font::CharacterOffsetForPixel(const PP_TextRun_Dev* text,
- int32_t pixel_position) {
- WebTextRun run;
- if (!PPTextRunToWebTextRun(text, &run))
- return -1;
-
- return static_cast<uint32_t>(font_->offsetForPosition(
- run, static_cast<float>(pixel_position)));
-}
-
-int32_t Font::PixelOffsetForCharacter(const PP_TextRun_Dev* text,
- uint32_t char_offset) {
- WebTextRun run;
- if (!PPTextRunToWebTextRun(text, &run))
- return -1;
- if (char_offset >= run.text.length())
- return -1;
-
- WebFloatRect rect = font_->selectionRectForText(
- run, WebFloatPoint(0.0f, 0.0f), font_->height(), 0, char_offset);
- return static_cast<int>(rect.width);
-}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_font.h b/webkit/glue/plugins/pepper_font.h
deleted file mode 100644
index 3cc001c..0000000
--- a/webkit/glue/plugins/pepper_font.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_FONT_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_FONT_H_
-
-#include "base/scoped_ptr.h"
-#include "ppapi/c/dev/ppb_font_dev.h"
-#include "webkit/glue/plugins/pepper_resource.h"
-
-namespace WebKit {
-class WebFont;
-}
-
-namespace pepper {
-
-class PluginInstance;
-
-class Font : public Resource {
- public:
- Font(PluginModule* module, const PP_FontDescription_Dev& desc);
- virtual ~Font();
-
- // Returns a pointer to the interface implementing PPB_Font that is exposed to
- // the plugin.
- static const PPB_Font_Dev* GetInterface();
-
- // Resource overrides.
- Font* AsFont() { return this; }
-
- // PPB_Font implementation.
- bool Describe(PP_FontDescription_Dev* description,
- PP_FontMetrics_Dev* metrics);
- bool DrawTextAt(PP_Resource image_data,
- const PP_TextRun_Dev* text,
- const PP_Point* position,
- uint32_t color,
- const PP_Rect* clip,
- bool image_data_is_opaque);
- int32_t MeasureText(const PP_TextRun_Dev* text);
- uint32_t CharacterOffsetForPixel(const PP_TextRun_Dev* text,
- int32_t pixel_position);
- int32_t PixelOffsetForCharacter(const PP_TextRun_Dev* text,
- uint32_t char_offset);
-
- private:
- scoped_ptr<WebKit::WebFont> font_;
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_FONT_H_
diff --git a/webkit/glue/plugins/pepper_fullscreen_container.h b/webkit/glue/plugins/pepper_fullscreen_container.h
deleted file mode 100644
index 7d86320..0000000
--- a/webkit/glue/plugins/pepper_fullscreen_container.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_FULLSCREEN_CONTAINER_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_FULLSCREEN_CONTAINER_H_
-
-namespace WebKit {
-struct WebRect;
-} // namespace WebKit
-
-namespace pepper {
-
-// This class is like a lightweight WebPluginContainer for fullscreen pepper
-// plugins, that only handles painting.
-class FullscreenContainer {
- public:
- virtual ~FullscreenContainer() {}
-
- // Invalidates the full plugin region.
- virtual void Invalidate() = 0;
-
- // Invalidates a partial region of the plugin.
- virtual void InvalidateRect(const WebKit::WebRect&) = 0;
-
- // Scrolls a partial region of the plugin in the given direction.
- virtual void ScrollRect(int dx, int dy, const WebKit::WebRect&) = 0;
-
- // Destroys the fullscreen window. This also destroys the FullscreenContainer
- // instance.
- virtual void Destroy() = 0;
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_FULLSCREEN_CONTAINER_H_
diff --git a/webkit/glue/plugins/pepper_graphics_2d.cc b/webkit/glue/plugins/pepper_graphics_2d.cc
deleted file mode 100644
index 7ccfae5..0000000
--- a/webkit/glue/plugins/pepper_graphics_2d.cc
+++ /dev/null
@@ -1,638 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_graphics_2d.h"
-
-#include <iterator>
-
-#include "base/logging.h"
-#include "base/message_loop.h"
-#include "base/task.h"
-#include "gfx/blit.h"
-#include "gfx/point.h"
-#include "gfx/rect.h"
-#include "skia/ext/platform_canvas.h"
-#include "ppapi/c/pp_errors.h"
-#include "ppapi/c/pp_module.h"
-#include "ppapi/c/pp_rect.h"
-#include "ppapi/c/pp_resource.h"
-#include "ppapi/c/ppb_graphics_2d.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "webkit/glue/plugins/pepper_common.h"
-#include "webkit/glue/plugins/pepper_image_data.h"
-#include "webkit/glue/plugins/pepper_plugin_instance.h"
-#include "webkit/glue/plugins/pepper_plugin_module.h"
-
-#if defined(OS_MACOSX)
-#include "base/mac_util.h"
-#include "base/mac/scoped_cftyperef.h"
-#endif
-
-namespace pepper {
-
-namespace {
-
-// Converts a rect inside an image of the given dimensions. The rect may be
-// NULL to indicate it should be the entire image. If the rect is outside of
-// the image, this will do nothing and return false.
-bool ValidateAndConvertRect(const PP_Rect* rect,
- int image_width, int image_height,
- gfx::Rect* dest) {
- if (!rect) {
- // Use the entire image area.
- *dest = gfx::Rect(0, 0, image_width, image_height);
- } else {
- // Validate the passed-in area.
- if (rect->point.x < 0 || rect->point.y < 0 ||
- rect->size.width <= 0 || rect->size.height <= 0)
- return false;
-
- // Check the max bounds, being careful of overflow.
- if (static_cast<int64>(rect->point.x) +
- static_cast<int64>(rect->size.width) >
- static_cast<int64>(image_width))
- return false;
- if (static_cast<int64>(rect->point.y) +
- static_cast<int64>(rect->size.height) >
- static_cast<int64>(image_height))
- return false;
-
- *dest = gfx::Rect(rect->point.x, rect->point.y,
- rect->size.width, rect->size.height);
- }
- return true;
-}
-
-// Converts BGRA <-> RGBA.
-void ConvertBetweenBGRAandRGBA(const uint32_t* input,
- int pixel_length,
- uint32_t* output) {
- for (int i = 0; i < pixel_length; i++) {
- const unsigned char* pixel_in =
- reinterpret_cast<const unsigned char*>(&input[i]);
- unsigned char* pixel_out = reinterpret_cast<unsigned char*>(&output[i]);
- pixel_out[0] = pixel_in[2];
- pixel_out[1] = pixel_in[1];
- pixel_out[2] = pixel_in[0];
- pixel_out[3] = pixel_in[3];
- }
-}
-
-// Converts ImageData from PP_IMAGEDATAFORMAT_BGRA_PREMUL to
-// PP_IMAGEDATAFORMAT_RGBA_PREMUL, or reverse.
-void ConvertImageData(ImageData* src_image, const SkIRect& src_rect,
- ImageData* dest_image, const SkRect& dest_rect) {
- DCHECK(src_image->format() != dest_image->format());
- DCHECK(ImageData::IsImageDataFormatSupported(src_image->format()));
- DCHECK(ImageData::IsImageDataFormatSupported(dest_image->format()));
-
- const SkBitmap* src_bitmap = src_image->GetMappedBitmap();
- const SkBitmap* dest_bitmap = dest_image->GetMappedBitmap();
- if (src_rect.width() == src_image->width() &&
- dest_rect.width() == dest_image->width()) {
- // Fast path if the full line needs to be converted.
- ConvertBetweenBGRAandRGBA(
- src_bitmap->getAddr32(static_cast<int>(src_rect.fLeft),
- static_cast<int>(src_rect.fTop)),
- src_rect.width() * src_rect.height(),
- dest_bitmap->getAddr32(static_cast<int>(dest_rect.fLeft),
- static_cast<int>(dest_rect.fTop)));
- } else {
- // Slow path where we convert line by line.
- for (int y = 0; y < src_rect.height(); y++) {
- ConvertBetweenBGRAandRGBA(
- src_bitmap->getAddr32(static_cast<int>(src_rect.fLeft),
- static_cast<int>(src_rect.fTop + y)),
- src_rect.width(),
- dest_bitmap->getAddr32(static_cast<int>(dest_rect.fLeft),
- static_cast<int>(dest_rect.fTop + y)));
- }
- }
-}
-
-PP_Resource Create(PP_Module module_id,
- const PP_Size* size,
- PP_Bool is_always_opaque) {
- PluginModule* module = ResourceTracker::Get()->GetModule(module_id);
- if (!module)
- return 0;
-
- scoped_refptr<Graphics2D> context(new Graphics2D(module));
- if (!context->Init(size->width, size->height, PPBoolToBool(is_always_opaque)))
- return 0;
- return context->GetReference();
-}
-
-PP_Bool IsGraphics2D(PP_Resource resource) {
- return BoolToPPBool(!!Resource::GetAs<Graphics2D>(resource));
-}
-
-PP_Bool Describe(PP_Resource graphics_2d,
- PP_Size* size,
- PP_Bool* is_always_opaque) {
- scoped_refptr<Graphics2D> context(
- Resource::GetAs<Graphics2D>(graphics_2d));
- if (!context)
- return PP_FALSE;
- return context->Describe(size, is_always_opaque);
-}
-
-void PaintImageData(PP_Resource graphics_2d,
- PP_Resource image_data,
- const PP_Point* top_left,
- const PP_Rect* src_rect) {
- scoped_refptr<Graphics2D> context(
- Resource::GetAs<Graphics2D>(graphics_2d));
- if (context)
- context->PaintImageData(image_data, top_left, src_rect);
-}
-
-void Scroll(PP_Resource graphics_2d,
- const PP_Rect* clip_rect,
- const PP_Point* amount) {
- scoped_refptr<Graphics2D> context(
- Resource::GetAs<Graphics2D>(graphics_2d));
- if (context)
- context->Scroll(clip_rect, amount);
-}
-
-void ReplaceContents(PP_Resource graphics_2d, PP_Resource image_data) {
- scoped_refptr<Graphics2D> context(
- Resource::GetAs<Graphics2D>(graphics_2d));
- if (context)
- context->ReplaceContents(image_data);
-}
-
-int32_t Flush(PP_Resource graphics_2d,
- PP_CompletionCallback callback) {
- scoped_refptr<Graphics2D> context(
- Resource::GetAs<Graphics2D>(graphics_2d));
- if (!context)
- return PP_ERROR_BADRESOURCE;
- return context->Flush(callback);
-}
-
-const PPB_Graphics2D ppb_graphics_2d = {
- &Create,
- &IsGraphics2D,
- &Describe,
- &PaintImageData,
- &Scroll,
- &ReplaceContents,
- &Flush
-};
-
-} // namespace
-
-struct Graphics2D::QueuedOperation {
- enum Type {
- PAINT,
- SCROLL,
- REPLACE
- };
-
- QueuedOperation(Type t)
- : type(t),
- paint_x(0),
- paint_y(0),
- scroll_dx(0),
- scroll_dy(0) {
- }
-
- Type type;
-
- // Valid when type == PAINT.
- scoped_refptr<ImageData> paint_image;
- int paint_x, paint_y;
- gfx::Rect paint_src_rect;
-
- // Valid when type == SCROLL.
- gfx::Rect scroll_clip_rect;
- int scroll_dx, scroll_dy;
-
- // Valid when type == REPLACE.
- scoped_refptr<ImageData> replace_image;
-};
-
-Graphics2D::Graphics2D(PluginModule* module)
- : Resource(module),
- bound_instance_(NULL),
- flushed_any_data_(false),
- offscreen_flush_pending_(false),
- is_always_opaque_(false) {
-}
-
-Graphics2D::~Graphics2D() {
-}
-
-// static
-const PPB_Graphics2D* Graphics2D::GetInterface() {
- return &ppb_graphics_2d;
-}
-
-bool Graphics2D::Init(int width, int height, bool is_always_opaque) {
- // The underlying ImageData will validate the dimensions.
- image_data_ = new ImageData(module());
- if (!image_data_->Init(ImageData::GetNativeImageDataFormat(), width, height,
- true) || !image_data_->Map()) {
- image_data_ = NULL;
- return false;
- }
- is_always_opaque_ = is_always_opaque;
- return true;
-}
-
-PP_Bool Graphics2D::Describe(PP_Size* size, PP_Bool* is_always_opaque) {
- size->width = image_data_->width();
- size->height = image_data_->height();
- *is_always_opaque = PP_FALSE; // TODO(brettw) implement this.
- return PP_TRUE;
-}
-
-void Graphics2D::PaintImageData(PP_Resource image_data,
- const PP_Point* top_left,
- const PP_Rect* src_rect) {
- if (!top_left)
- return;
-
- scoped_refptr<ImageData> image_resource(
- Resource::GetAs<ImageData>(image_data));
- if (!image_resource)
- return;
-
- QueuedOperation operation(QueuedOperation::PAINT);
- operation.paint_image = image_resource;
- if (!ValidateAndConvertRect(src_rect, image_resource->width(),
- image_resource->height(),
- &operation.paint_src_rect))
- return;
-
- // Validate the bitmap position using the previously-validated rect, there
- // should be no painted area outside of the image.
- int64 x64 = static_cast<int64>(top_left->x);
- int64 y64 = static_cast<int64>(top_left->y);
- if (x64 + static_cast<int64>(operation.paint_src_rect.x()) < 0 ||
- x64 + static_cast<int64>(operation.paint_src_rect.right()) >
- image_data_->width())
- return;
- if (y64 + static_cast<int64>(operation.paint_src_rect.y()) < 0 ||
- y64 + static_cast<int64>(operation.paint_src_rect.bottom()) >
- image_data_->height())
- return;
- operation.paint_x = top_left->x;
- operation.paint_y = top_left->y;
-
- queued_operations_.push_back(operation);
-}
-
-void Graphics2D::Scroll(const PP_Rect* clip_rect, const PP_Point* amount) {
- QueuedOperation operation(QueuedOperation::SCROLL);
- if (!ValidateAndConvertRect(clip_rect,
- image_data_->width(),
- image_data_->height(),
- &operation.scroll_clip_rect))
- return;
-
- // If we're being asked to scroll by more than the clip rect size, just
- // ignore this scroll command and say it worked.
- int32 dx = amount->x;
- int32 dy = amount->y;
- if (dx <= -image_data_->width() || dx >= image_data_->width() ||
- dy <= -image_data_->height() || dy >= image_data_->height())
- return;
-
- operation.scroll_dx = dx;
- operation.scroll_dy = dy;
-
- queued_operations_.push_back(operation);
-}
-
-void Graphics2D::ReplaceContents(PP_Resource image_data) {
- scoped_refptr<ImageData> image_resource(
- Resource::GetAs<ImageData>(image_data));
- if (!image_resource)
- return;
- if (!ImageData::IsImageDataFormatSupported(image_resource->format()))
- return;
-
- if (image_resource->width() != image_data_->width() ||
- image_resource->height() != image_data_->height())
- return;
-
- QueuedOperation operation(QueuedOperation::REPLACE);
- operation.replace_image = image_resource;
- queued_operations_.push_back(operation);
-}
-
-int32_t Graphics2D::Flush(const PP_CompletionCallback& callback) {
- // Don't allow more than one pending flush at a time.
- if (HasPendingFlush())
- return PP_ERROR_INPROGRESS;
-
- // TODO(brettw) check that the current thread is not the main one and
- // implement blocking flushes in this case.
- if (!callback.func)
- return PP_ERROR_BADARGUMENT;
-
- bool nothing_visible = true;
- for (size_t i = 0; i < queued_operations_.size(); i++) {
- QueuedOperation& operation = queued_operations_[i];
- gfx::Rect op_rect;
- switch (operation.type) {
- case QueuedOperation::PAINT:
- ExecutePaintImageData(operation.paint_image,
- operation.paint_x, operation.paint_y,
- operation.paint_src_rect,
- &op_rect);
- break;
- case QueuedOperation::SCROLL:
- ExecuteScroll(operation.scroll_clip_rect,
- operation.scroll_dx, operation.scroll_dy,
- &op_rect);
- break;
- case QueuedOperation::REPLACE:
- ExecuteReplaceContents(operation.replace_image, &op_rect);
- break;
- }
-
- // We need the rect to be in terms of the current clip rect of the plugin
- // since that's what will actually be painted. If we issue an invalidate
- // for a clipped-out region, WebKit will do nothing and we won't get any
- // ViewInitiatedPaint/ViewFlushedPaint calls, leaving our callback stranded.
- gfx::Rect visible_changed_rect;
- if (bound_instance_ && !op_rect.IsEmpty())
- visible_changed_rect = bound_instance_->clip().Intersect(op_rect);
-
- if (bound_instance_ && !visible_changed_rect.IsEmpty()) {
- if (operation.type == QueuedOperation::SCROLL) {
- bound_instance_->ScrollRect(operation.scroll_dx, operation.scroll_dy,
- visible_changed_rect);
- } else {
- bound_instance_->InvalidateRect(visible_changed_rect);
- }
- nothing_visible = false;
- }
- }
- queued_operations_.clear();
- flushed_any_data_ = true;
-
- if (nothing_visible) {
- // There's nothing visible to invalidate so just schedule the callback to
- // execute in the next round of the message loop.
- ScheduleOffscreenCallback(FlushCallbackData(callback));
- } else {
- unpainted_flush_callback_.Set(callback);
- }
- return PP_ERROR_WOULDBLOCK;
-}
-
-bool Graphics2D::ReadImageData(PP_Resource image,
- const PP_Point* top_left) {
- // Get and validate the image object to paint into.
- scoped_refptr<ImageData> image_resource(Resource::GetAs<ImageData>(image));
- if (!image_resource)
- return false;
- if (!ImageData::IsImageDataFormatSupported(image_resource->format()))
- return false; // Must be in the right format.
-
- // Validate the bitmap position.
- int x = top_left->x;
- if (x < 0 ||
- static_cast<int64>(x) + static_cast<int64>(image_resource->width()) >
- image_data_->width())
- return false;
- int y = top_left->y;
- if (y < 0 ||
- static_cast<int64>(y) + static_cast<int64>(image_resource->height()) >
- image_data_->height())
- return false;
-
- ImageDataAutoMapper auto_mapper(image_resource);
- if (!auto_mapper.is_valid())
- return false;
-
- SkIRect src_irect = { x, y,
- x + image_resource->width(),
- y + image_resource->height() };
- SkRect dest_rect = { SkIntToScalar(0),
- SkIntToScalar(0),
- SkIntToScalar(image_resource->width()),
- SkIntToScalar(image_resource->height()) };
-
- ImageDataAutoMapper auto_mapper2(image_data_);
- if (image_resource->format() != image_data_->format()) {
- // Convert the image data if the format does not match.
- ConvertImageData(image_data_, src_irect, image_resource.get(), dest_rect);
- } else {
- skia::PlatformCanvas* dest_canvas = image_resource->mapped_canvas();
-
- // We want to replace the contents of the bitmap rather than blend.
- SkPaint paint;
- paint.setXfermodeMode(SkXfermode::kSrc_Mode);
- dest_canvas->drawBitmapRect(*image_data_->GetMappedBitmap(),
- &src_irect, dest_rect, &paint);
- }
- return true;
-}
-
-bool Graphics2D::BindToInstance(PluginInstance* new_instance) {
- if (bound_instance_ == new_instance)
- return true; // Rebinding the same device, nothing to do.
- if (bound_instance_ && new_instance)
- return false; // Can't change a bound device.
-
- if (!new_instance) {
- // When the device is detached, we'll not get any more paint callbacks so
- // we need to clear the list, but we still want to issue any pending
- // callbacks to the plugin.
- if (!unpainted_flush_callback_.is_null()) {
- ScheduleOffscreenCallback(unpainted_flush_callback_);
- unpainted_flush_callback_.Clear();
- }
- if (!painted_flush_callback_.is_null()) {
- ScheduleOffscreenCallback(painted_flush_callback_);
- painted_flush_callback_.Clear();
- }
- } else if (flushed_any_data_) {
- // Only schedule a paint if this backing store has had any data flushed to
- // it. This is an optimization. A "normal" plugin will first allocated a
- // backing store, bind it, and then execute their normal painting and
- // update loop. If binding a device always invalidated, it would mean we
- // would get one paint for the bind, and one for the first time the plugin
- // actually painted something. By not bothering to schedule an invalidate
- // when an empty device is initially bound, we can save an extra paint for
- // many plugins during the critical page initialization phase.
- new_instance->InvalidateRect(gfx::Rect());
- }
-
- bound_instance_ = new_instance;
- return true;
-}
-
-void Graphics2D::Paint(WebKit::WebCanvas* canvas,
- const gfx::Rect& plugin_rect,
- const gfx::Rect& paint_rect) {
- ImageDataAutoMapper auto_mapper(image_data_);
- const SkBitmap& backing_bitmap = *image_data_->GetMappedBitmap();
-
-#if defined(OS_MACOSX)
- SkAutoLockPixels lock(backing_bitmap);
-
- base::mac::ScopedCFTypeRef<CGDataProviderRef> data_provider(
- CGDataProviderCreateWithData(
- NULL, backing_bitmap.getAddr32(0, 0),
- backing_bitmap.rowBytes() * backing_bitmap.height(), NULL));
- base::mac::ScopedCFTypeRef<CGImageRef> image(
- CGImageCreate(
- backing_bitmap.width(), backing_bitmap.height(),
- 8, 32, backing_bitmap.rowBytes(),
- mac_util::GetSystemColorSpace(),
- kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,
- data_provider, NULL, false, kCGRenderingIntentDefault));
-
- // Flip the transform
- CGContextSaveGState(canvas);
- float window_height = static_cast<float>(CGBitmapContextGetHeight(canvas));
- CGContextTranslateCTM(canvas, 0, window_height);
- CGContextScaleCTM(canvas, 1.0, -1.0);
-
- CGRect bounds;
- bounds.origin.x = plugin_rect.origin().x();
- bounds.origin.y = window_height - plugin_rect.origin().y() -
- backing_bitmap.height();
- bounds.size.width = backing_bitmap.width();
- bounds.size.height = backing_bitmap.height();
-
- // TODO(brettw) bug 56673: do a direct memcpy instead of going through CG
- // if the is_always_opaque_ flag is set.
-
- CGContextDrawImage(canvas, bounds, image);
- CGContextRestoreGState(canvas);
-#else
- SkPaint paint;
- if (is_always_opaque_) {
- // When we know the device is opaque, we can disable blending for slightly
- // more optimized painting.
- paint.setXfermodeMode(SkXfermode::kSrc_Mode);
- }
-
- gfx::Point origin(plugin_rect.origin().x(), plugin_rect.origin().y());
- canvas->drawBitmap(backing_bitmap,
- SkIntToScalar(plugin_rect.origin().x()),
- SkIntToScalar(plugin_rect.origin().y()),
- &paint);
-#endif
-}
-
-void Graphics2D::ViewInitiatedPaint() {
- // Move any "unpainted" callback to the painted state. See
- // |unpainted_flush_callback_| in the header for more.
- if (!unpainted_flush_callback_.is_null()) {
- DCHECK(painted_flush_callback_.is_null());
- std::swap(painted_flush_callback_, unpainted_flush_callback_);
- }
-}
-
-void Graphics2D::ViewFlushedPaint() {
- // Notify any "painted" callback. See |unpainted_flush_callback_| in the
- // header for more.
- if (!painted_flush_callback_.is_null()) {
- // We must clear this variable before issuing the callback. It will be
- // common for the plugin to issue another invalidate in response to a flush
- // callback, and we don't want to think that a callback is already pending.
- FlushCallbackData callback;
- std::swap(callback, painted_flush_callback_);
- callback.Execute(PP_OK);
- }
-}
-
-void Graphics2D::ExecutePaintImageData(ImageData* image,
- int x, int y,
- const gfx::Rect& src_rect,
- gfx::Rect* invalidated_rect) {
- // Ensure the source image is mapped to read from it.
- ImageDataAutoMapper auto_mapper(image);
- if (!auto_mapper.is_valid())
- return;
-
- // Portion within the source image to cut out.
- SkIRect src_irect = { src_rect.x(), src_rect.y(),
- src_rect.right(), src_rect.bottom() };
-
- // Location within the backing store to copy to.
- *invalidated_rect = src_rect;
- invalidated_rect->Offset(x, y);
- SkRect dest_rect = { SkIntToScalar(invalidated_rect->x()),
- SkIntToScalar(invalidated_rect->y()),
- SkIntToScalar(invalidated_rect->right()),
- SkIntToScalar(invalidated_rect->bottom()) };
-
- if (image->format() != image_data_->format()) {
- // Convert the image data if the format does not match.
- ConvertImageData(image, src_irect, image_data_, dest_rect);
- } else {
- // We're guaranteed to have a mapped canvas since we mapped it in Init().
- skia::PlatformCanvas* backing_canvas = image_data_->mapped_canvas();
-
- // We want to replace the contents of the bitmap rather than blend.
- SkPaint paint;
- paint.setXfermodeMode(SkXfermode::kSrc_Mode);
- backing_canvas->drawBitmapRect(*image->GetMappedBitmap(),
- &src_irect, dest_rect, &paint);
- }
-}
-
-void Graphics2D::ExecuteScroll(const gfx::Rect& clip, int dx, int dy,
- gfx::Rect* invalidated_rect) {
- gfx::ScrollCanvas(image_data_->mapped_canvas(),
- clip, gfx::Point(dx, dy));
- *invalidated_rect = clip;
-}
-
-void Graphics2D::ExecuteReplaceContents(ImageData* image,
- gfx::Rect* invalidated_rect) {
- if (image->format() != image_data_->format()) {
- DCHECK(image->width() == image_data_->width() &&
- image->height() == image_data_->height());
- // Convert the image data if the format does not match.
- SkIRect src_irect = { 0, 0, image->width(), image->height() };
- SkRect dest_rect = { SkIntToScalar(0),
- SkIntToScalar(0),
- SkIntToScalar(image_data_->width()),
- SkIntToScalar(image_data_->height()) };
- ConvertImageData(image, src_irect, image_data_, dest_rect);
- } else {
- image_data_->Swap(image);
- }
- *invalidated_rect = gfx::Rect(0, 0,
- image_data_->width(), image_data_->height());
-}
-
-void Graphics2D::ScheduleOffscreenCallback(const FlushCallbackData& callback) {
- DCHECK(!HasPendingFlush());
- offscreen_flush_pending_ = true;
- MessageLoop::current()->PostTask(
- FROM_HERE,
- NewRunnableMethod(this,
- &Graphics2D::ExecuteOffscreenCallback,
- callback));
-}
-
-void Graphics2D::ExecuteOffscreenCallback(FlushCallbackData data) {
- DCHECK(offscreen_flush_pending_);
-
- // We must clear this flag before issuing the callback. It will be
- // common for the plugin to issue another invalidate in response to a flush
- // callback, and we don't want to think that a callback is already pending.
- offscreen_flush_pending_ = false;
- data.Execute(PP_OK);
-}
-
-bool Graphics2D::HasPendingFlush() const {
- return !unpainted_flush_callback_.is_null() ||
- !painted_flush_callback_.is_null() ||
- offscreen_flush_pending_;
-}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_graphics_2d.h b/webkit/glue/plugins/pepper_graphics_2d.h
deleted file mode 100644
index 78170ab..0000000
--- a/webkit/glue/plugins/pepper_graphics_2d.h
+++ /dev/null
@@ -1,180 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_GRAPHICS_2D_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_GRAPHICS_2D_H_
-
-#include <vector>
-
-#include "base/basictypes.h"
-#include "ppapi/c/pp_completion_callback.h"
-#include "ppapi/c/ppb_graphics_2d.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebCanvas.h"
-#include "webkit/glue/plugins/pepper_resource.h"
-
-struct PPB_Graphics2D;
-
-namespace gfx {
-class Rect;
-}
-
-namespace pepper {
-
-class ImageData;
-class PluginInstance;
-class PluginModule;
-
-class Graphics2D : public Resource {
- public:
- Graphics2D(PluginModule* module);
- virtual ~Graphics2D();
-
- // Returns a pointer to the interface implementing PPB_ImageData that is
- // exposed to the plugin.
- static const PPB_Graphics2D* GetInterface();
-
- bool Init(int width, int height, bool is_always_opaque);
-
- bool is_always_opaque() const { return is_always_opaque_; }
-
- // Resource override.
- virtual Graphics2D* AsGraphics2D() { return this; }
-
- // PPB_Graphics2D functions.
- PP_Bool Describe(PP_Size* size, PP_Bool* is_always_opaque);
- void PaintImageData(PP_Resource image_data,
- const PP_Point* top_left,
- const PP_Rect* src_rect);
- void Scroll(const PP_Rect* clip_rect, const PP_Point* amount);
- void ReplaceContents(PP_Resource image_data);
- int32_t Flush(const PP_CompletionCallback& callback);
-
- bool ReadImageData(PP_Resource image, const PP_Point* top_left);
-
- // Assciates this device with the given plugin instance. You can pass NULL to
- // clear the existing device. Returns true on success. In this case, a
- // repaint of the page will also be scheduled. Failure means that the device
- // is already bound to a different instance, and nothing will happen.
- bool BindToInstance(PluginInstance* new_instance);
-
- // Paints the current backing store to the web page.
- void Paint(WebKit::WebCanvas* canvas,
- const gfx::Rect& plugin_rect,
- const gfx::Rect& paint_rect);
-
- // Notifications that the view has rendered the page and that it has been
- // flushed to the screen. These messages are used to send Flush callbacks to
- // the plugin. See
- void ViewInitiatedPaint();
- void ViewFlushedPaint();
-
- ImageData* image_data() { return image_data_.get(); }
-
- private:
- // Tracks a call to flush that requires a callback.
- class FlushCallbackData {
- public:
- FlushCallbackData() {
- Clear();
- }
-
- FlushCallbackData(const PP_CompletionCallback& callback) {
- Set(callback);
- }
-
- bool is_null() const { return !callback_.func; }
-
- void Set(const PP_CompletionCallback& callback) {
- callback_ = callback;
- }
-
- void Clear() {
- callback_ = PP_MakeCompletionCallback(NULL, 0);
- }
-
- void Execute(int32_t result) {
- PP_RunCompletionCallback(&callback_, result);
- }
-
- private:
- PP_CompletionCallback callback_;
- };
-
- // Called internally to execute the different queued commands. The
- // parameters to these functions will have already been validated. The last
- // rect argument will be filled by each function with the area affected by
- // the update that requires invalidation. If there were no pixels changed,
- // this rect can be untouched.
- void ExecutePaintImageData(ImageData* image,
- int x, int y,
- const gfx::Rect& src_rect,
- gfx::Rect* invalidated_rect);
- void ExecuteScroll(const gfx::Rect& clip, int dx, int dy,
- gfx::Rect* invalidated_rect);
- void ExecuteReplaceContents(ImageData* image,
- gfx::Rect* invalidated_rect);
-
- // Schedules the offscreen callback to be fired at a future time. This
- // will add the given item to the offscreen_flush_callbacks_ vector.
- void ScheduleOffscreenCallback(const FlushCallbackData& callback);
-
- // Function scheduled to execute by ScheduleOffscreenCallback that actually
- // issues the offscreen callbacks.
- void ExecuteOffscreenCallback(FlushCallbackData data);
-
- // Returns true if there is any type of flush callback pending.
- bool HasPendingFlush() const;
-
- scoped_refptr<ImageData> image_data_;
-
- // Non-owning pointer to the plugin instance this context is currently bound
- // to, if any. If the context is currently unbound, this will be NULL.
- PluginInstance* bound_instance_;
-
- // Keeps track of all drawing commands queued before a Flush call.
- struct QueuedOperation;
- typedef std::vector<QueuedOperation> OperationQueue;
- OperationQueue queued_operations_;
-
- // Indicates whether any changes have been flushed to the backing store.
- // This is initially false and is set to true at the first Flush() call.
- bool flushed_any_data_;
-
- // The plugin can give us one "Flush" at a time. This flush will either be in
- // the "unpainted" state (in which case unpainted_flush_callback_ will be
- // non-NULL) or painted, in which case painted_flush_callback_ will be
- // non-NULL). There can also be an offscreen callback which is handled
- // separately (see offscreen_callback_pending_). Only one of these three
- // things may be set at a time to enforce the "only one pending flush at a
- // time" constraint.
- //
- // "Unpainted" ones are flush requests which have never been painted. These
- // could have been done while the RenderView was already waiting for an ACK
- // from a previous paint, so won't generate a new one yet.
- //
- // "Painted" ones are those flushes that have been painted by RenderView, but
- // for which the ACK from the browser has not yet been received.
- //
- // When we get updates from a plugin with a callback, it is first added to
- // the unpainted callbacks. When the renderer has initiated a paint, we'll
- // move it to the painted callbacks list. When the renderer receives a flush,
- // we'll execute the callback and remove it from the list.
- FlushCallbackData unpainted_flush_callback_;
- FlushCallbackData painted_flush_callback_;
-
- // When doing offscreen flushes, we issue a task that issues the callback
- // later. This is set when one of those tasks is pending so that we can
- // enforce the "only one pending flush at a time" constraint in the API.
- bool offscreen_flush_pending_;
-
- // Set to true if the plugin declares that this device will always be opaque.
- // This allows us to do more optimized painting in some cases.
- bool is_always_opaque_;
-
- DISALLOW_COPY_AND_ASSIGN(Graphics2D);
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_GRAPHICS_2D_H_
diff --git a/webkit/glue/plugins/pepper_graphics_3d.cc b/webkit/glue/plugins/pepper_graphics_3d.cc
deleted file mode 100644
index 2dc4def..0000000
--- a/webkit/glue/plugins/pepper_graphics_3d.cc
+++ /dev/null
@@ -1,256 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_graphics_3d.h"
-
-#include "gpu/command_buffer/common/command_buffer.h"
-#include "base/singleton.h"
-#include "base/thread_local.h"
-#include "ppapi/c/dev/ppb_graphics_3d_dev.h"
-#include "webkit/glue/plugins/pepper_common.h"
-#include "webkit/glue/plugins/pepper_plugin_instance.h"
-
-namespace pepper {
-
-namespace {
-
-struct CurrentContextTag {};
-typedef Singleton<base::ThreadLocalPointer<Graphics3D>,
- DefaultSingletonTraits<base::ThreadLocalPointer<Graphics3D> >,
- CurrentContextTag> CurrentContextKey;
-
-// Size of the transfer buffer.
-enum { kTransferBufferSize = 512 * 1024 };
-
-PP_Bool IsGraphics3D(PP_Resource resource) {
- return BoolToPPBool(!!Resource::GetAs<Graphics3D>(resource));
-}
-
-PP_Bool GetConfigs(int32_t* configs, int32_t config_size, int32_t* num_config) {
- // TODO(neb): Implement me!
- return PP_FALSE;
-}
-
-PP_Bool ChooseConfig(const int32_t* attrib_list, int32_t* configs,
- int32_t config_size, int32_t* num_config) {
- // TODO(neb): Implement me!
- return PP_FALSE;
-}
-
-PP_Bool GetConfigAttrib(int32_t config, int32_t attribute, int32_t* value) {
- // TODO(neb): Implement me!
- return PP_FALSE;
-}
-
-const char* QueryString(int32_t name) {
- switch (name) {
- case EGL_CLIENT_APIS:
- return "OpenGL_ES";
- case EGL_EXTENSIONS:
- return "";
- case EGL_VENDOR:
- return "Google";
- case EGL_VERSION:
- return "1.0 Google";
- default:
- return NULL;
- }
-}
-
-PP_Resource CreateContext(PP_Instance instance_id, int32_t config,
- int32_t share_context,
- const int32_t* attrib_list) {
- DCHECK_EQ(0, share_context);
-
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance) {
- return 0;
- }
-
- scoped_refptr<Graphics3D> context(new Graphics3D(instance->module()));
- if (!context->Init(instance_id, config, attrib_list)) {
- return 0;
- }
-
- return context->GetReference();
-}
-
-void* GetProcAddress(const char* name) {
- // TODO(neb): Implement me!
- return NULL;
-}
-
-PP_Bool MakeCurrent(PP_Resource graphics3d) {
- if (!graphics3d) {
- Graphics3D::ResetCurrent();
- return PP_TRUE;
- } else {
- scoped_refptr<Graphics3D> context(Resource::GetAs<Graphics3D>(graphics3d));
- return BoolToPPBool(context.get() && context->MakeCurrent());
- }
-}
-
-PP_Resource GetCurrentContext() {
- Graphics3D* current_context = Graphics3D::GetCurrent();
- return current_context ? current_context->GetReference() : 0;
-}
-
-PP_Bool SwapBuffers(PP_Resource graphics3d) {
- scoped_refptr<Graphics3D> context(Resource::GetAs<Graphics3D>(graphics3d));
- return BoolToPPBool(context && context->SwapBuffers());
-}
-
-uint32_t GetError() {
- // Technically, this should return the last error that occurred on the current
- // thread, rather than an error associated with a particular context.
- // TODO(apatrick): Fix this.
- Graphics3D* current_context = Graphics3D::GetCurrent();
- if (!current_context)
- return 0;
-
- return current_context->GetError();
-}
-
-const PPB_Graphics3D_Dev ppb_graphics3d = {
- &IsGraphics3D,
- &GetConfigs,
- &ChooseConfig,
- &GetConfigAttrib,
- &QueryString,
- &CreateContext,
- &GetProcAddress,
- &MakeCurrent,
- &GetCurrentContext,
- &SwapBuffers,
- &GetError
-};
-
-} // namespace
-
-Graphics3D::Graphics3D(PluginModule* module)
- : Resource(module),
- bound_instance_(NULL) {
-}
-
-const PPB_Graphics3D_Dev* Graphics3D::GetInterface() {
- return &ppb_graphics3d;
-}
-
-Graphics3D* Graphics3D::GetCurrent() {
- return CurrentContextKey::get()->Get();
-}
-
-void Graphics3D::ResetCurrent() {
- CurrentContextKey::get()->Set(NULL);
-}
-
-Graphics3D::~Graphics3D() {
- Destroy();
-}
-
-bool Graphics3D::Init(PP_Instance instance_id, int32_t config,
- const int32_t* attrib_list) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance) {
- return false;
- }
-
- // Create and initialize the objects required to issue GLES2 calls.
- platform_context_.reset(instance->delegate()->CreateContext3D());
- if (!platform_context_.get()) {
- Destroy();
- return false;
- }
-
- if (!platform_context_->Init()) {
- Destroy();
- return false;
- }
-
- gles2_implementation_ = platform_context_->GetGLES2Implementation();
- DCHECK(gles2_implementation_);
-
- return true;
-}
-
-bool Graphics3D::BindToInstance(PluginInstance* new_instance) {
- if (bound_instance_ == new_instance)
- return true; // Rebinding the same device, nothing to do.
- if (bound_instance_ && new_instance)
- return false; // Can't change a bound device.
-
- if (new_instance) {
- // Resize the backing texture to the size of the instance when it is bound.
- platform_context_->ResizeBackingTexture(new_instance->position().size());
-
- // This is a temporary hack. The SwapBuffers is issued to force the resize
- // to take place before any subsequent rendering. This might lead to a
- // partially rendered frame being displayed. It is also not thread safe
- // since the SwapBuffers is written to the command buffer and that command
- // buffer might be written to by another thread.
- // TODO(apatrick): Figure out the semantics of binding and resizing.
- platform_context_->SwapBuffers();
- }
-
- bound_instance_ = new_instance;
- return true;
-}
-
-bool Graphics3D::MakeCurrent() {
- if (!platform_context_.get())
- return false;
-
- CurrentContextKey::get()->Set(this);
-
- // TODO(apatrick): Return false on context lost.
- return true;
-}
-
-bool Graphics3D::SwapBuffers() {
- if (!platform_context_.get())
- return false;
-
- return platform_context_->SwapBuffers();
-}
-
-unsigned Graphics3D::GetError() {
- if (!platform_context_.get())
- return 0;
-
- return platform_context_->GetError();
-}
-
-void Graphics3D::ResizeBackingTexture(const gfx::Size& size) {
- if (!platform_context_.get())
- return;
-
- platform_context_->ResizeBackingTexture(size);
-}
-
-void Graphics3D::SetSwapBuffersCallback(Callback0::Type* callback) {
- if (!platform_context_.get())
- return;
-
- platform_context_->SetSwapBuffersCallback(callback);
-}
-
-unsigned Graphics3D::GetBackingTextureId() {
- if (!platform_context_.get())
- return 0;
-
- return platform_context_->GetBackingTextureId();
-}
-
-void Graphics3D::Destroy() {
- if (GetCurrent() == this) {
- ResetCurrent();
- }
-
- gles2_implementation_ = NULL;
-
- platform_context_.reset();
-}
-
-} // namespace pepper
-
diff --git a/webkit/glue/plugins/pepper_graphics_3d.h b/webkit/glue/plugins/pepper_graphics_3d.h
deleted file mode 100644
index 5c00068..0000000
--- a/webkit/glue/plugins/pepper_graphics_3d.h
+++ /dev/null
@@ -1,90 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_GRAPHICS_3D_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_GRAPHICS_3D_H_
-
-#include "base/callback.h"
-#include "base/scoped_ptr.h"
-#include "gfx/size.h"
-#include "gpu/command_buffer/client/gles2_cmd_helper.h"
-#include "gpu/command_buffer/client/gles2_implementation.h"
-#include "ppapi/c/pp_instance.h"
-#include "webkit/glue/plugins/pepper_plugin_delegate.h"
-#include "webkit/glue/plugins/pepper_resource.h"
-
-namespace gpu {
-namespace gles2 {
-class GLES2Implementation;
-}
-} // namespace gpu
-
-struct PPB_Graphics3D_Dev;
-struct PPB_OpenGLES_Dev;
-
-namespace pepper {
-
-class Graphics3D : public Resource {
- public:
- explicit Graphics3D(PluginModule* module);
-
- virtual ~Graphics3D();
-
- static const PPB_Graphics3D_Dev* GetInterface();
- static const PPB_OpenGLES_Dev* GetOpenGLESInterface();
-
- static bool Shutdown();
-
- static Graphics3D* GetCurrent();
-
- static void ResetCurrent();
-
- // Resource override.
- virtual Graphics3D* AsGraphics3D() {
- return this;
- }
-
- bool Init(PP_Instance instance_id, int32_t config,
- const int32_t* attrib_list);
-
- // Associates this Graphics3D with the given plugin instance. You can pass
- // NULL to clear the existing device. Returns true on success. In this case,
- // the last rendered frame is displayed.
- // TODO(apatrick): Figure out the best semantics here.
- bool BindToInstance(PluginInstance* new_instance);
-
- bool MakeCurrent();
-
- bool SwapBuffers();
-
- unsigned GetError();
-
- void ResizeBackingTexture(const gfx::Size& size);
-
- void SetSwapBuffersCallback(Callback0::Type* callback);
-
- unsigned GetBackingTextureId();
-
- gpu::gles2::GLES2Implementation* impl() {
- return gles2_implementation_;
- }
-
- private:
- void Destroy();
-
- // Non-owning pointer to the plugin instance this context is currently bound
- // to, if any. If the context is currently unbound, this will be NULL.
- PluginInstance* bound_instance_;
-
- // PluginDelegate's 3D Context. Responsible for providing the command buffer.
- scoped_ptr<PluginDelegate::PlatformContext3D> platform_context_;
-
- // GLES2 Implementation instance. Owned by the platform context's GGL context.
- gpu::gles2::GLES2Implementation* gles2_implementation_;
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_GRAPHICS_3D_H_
-
diff --git a/webkit/glue/plugins/pepper_graphics_3d_gl.cc b/webkit/glue/plugins/pepper_graphics_3d_gl.cc
deleted file mode 100644
index 0a7076f..0000000
--- a/webkit/glue/plugins/pepper_graphics_3d_gl.cc
+++ /dev/null
@@ -1,671 +0,0 @@
-// 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.
-
-// This file is auto-generated. DO NOT EDIT!
-
-#include "webkit/glue/plugins/pepper_graphics_3d.h"
-
-#include "gpu/command_buffer/client/gles2_implementation.h"
-#include "ppapi/c/dev/ppb_opengles_dev.h"
-
-namespace pepper {
-
-namespace {
-
-void ActiveTexture(GLenum texture) {
- Graphics3D::GetCurrent()->impl()->ActiveTexture(texture);
-}
-void AttachShader(GLuint program, GLuint shader) {
- Graphics3D::GetCurrent()->impl()->AttachShader(program, shader);
-}
-void BindAttribLocation(GLuint program, GLuint index, const char* name) {
- Graphics3D::GetCurrent()->impl()->BindAttribLocation(program, index, name);
-}
-void BindBuffer(GLenum target, GLuint buffer) {
- Graphics3D::GetCurrent()->impl()->BindBuffer(target, buffer);
-}
-void BindFramebuffer(GLenum target, GLuint framebuffer) {
- Graphics3D::GetCurrent()->impl()->BindFramebuffer(target, framebuffer);
-}
-void BindRenderbuffer(GLenum target, GLuint renderbuffer) {
- Graphics3D::GetCurrent()->impl()->BindRenderbuffer(target, renderbuffer);
-}
-void BindTexture(GLenum target, GLuint texture) {
- Graphics3D::GetCurrent()->impl()->BindTexture(target, texture);
-}
-void BlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
- Graphics3D::GetCurrent()->impl()->BlendColor(red, green, blue, alpha);
-}
-void BlendEquation(GLenum mode) {
- Graphics3D::GetCurrent()->impl()->BlendEquation(mode);
-}
-void BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) {
- Graphics3D::GetCurrent()->impl()->BlendEquationSeparate(modeRGB, modeAlpha);
-}
-void BlendFunc(GLenum sfactor, GLenum dfactor) {
- Graphics3D::GetCurrent()->impl()->BlendFunc(sfactor, dfactor);
-}
-void BlendFuncSeparate(
- GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {
- Graphics3D::GetCurrent()->impl()->BlendFuncSeparate(
- srcRGB, dstRGB, srcAlpha, dstAlpha);
-}
-void BufferData(
- GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
- Graphics3D::GetCurrent()->impl()->BufferData(target, size, data, usage);
-}
-void BufferSubData(
- GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
- Graphics3D::GetCurrent()->impl()->BufferSubData(target, offset, size, data);
-}
-GLenum CheckFramebufferStatus(GLenum target) {
- return Graphics3D::GetCurrent()->impl()->CheckFramebufferStatus(target);
-}
-void Clear(GLbitfield mask) {
- Graphics3D::GetCurrent()->impl()->Clear(mask);
-}
-void ClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
- Graphics3D::GetCurrent()->impl()->ClearColor(red, green, blue, alpha);
-}
-void ClearDepthf(GLclampf depth) {
- Graphics3D::GetCurrent()->impl()->ClearDepthf(depth);
-}
-void ClearStencil(GLint s) {
- Graphics3D::GetCurrent()->impl()->ClearStencil(s);
-}
-void ColorMask(
- GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
- Graphics3D::GetCurrent()->impl()->ColorMask(red, green, blue, alpha);
-}
-void CompileShader(GLuint shader) {
- Graphics3D::GetCurrent()->impl()->CompileShader(shader);
-}
-void CompressedTexImage2D(
- GLenum target, GLint level, GLenum internalformat, GLsizei width,
- GLsizei height, GLint border, GLsizei imageSize, const void* data) {
- Graphics3D::GetCurrent()->impl()->CompressedTexImage2D(
- target, level, internalformat, width, height, border, imageSize, data);
-}
-void CompressedTexSubImage2D(
- GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
- GLsizei height, GLenum format, GLsizei imageSize, const void* data) {
- Graphics3D::GetCurrent()->impl()->CompressedTexSubImage2D(
- target, level, xoffset, yoffset, width, height, format, imageSize, data);
-}
-void CopyTexImage2D(
- GLenum target, GLint level, GLenum internalformat, GLint x, GLint y,
- GLsizei width, GLsizei height, GLint border) {
- Graphics3D::GetCurrent()->impl()->CopyTexImage2D(
- target, level, internalformat, x, y, width, height, border);
-}
-void CopyTexSubImage2D(
- GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y,
- GLsizei width, GLsizei height) {
- Graphics3D::GetCurrent()->impl()->CopyTexSubImage2D(
- target, level, xoffset, yoffset, x, y, width, height);
-}
-GLuint CreateProgram() {
- return Graphics3D::GetCurrent()->impl()->CreateProgram();
-}
-GLuint CreateShader(GLenum type) {
- return Graphics3D::GetCurrent()->impl()->CreateShader(type);
-}
-void CullFace(GLenum mode) {
- Graphics3D::GetCurrent()->impl()->CullFace(mode);
-}
-void DeleteBuffers(GLsizei n, const GLuint* buffers) {
- Graphics3D::GetCurrent()->impl()->DeleteBuffers(n, buffers);
-}
-void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers) {
- Graphics3D::GetCurrent()->impl()->DeleteFramebuffers(n, framebuffers);
-}
-void DeleteProgram(GLuint program) {
- Graphics3D::GetCurrent()->impl()->DeleteProgram(program);
-}
-void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) {
- Graphics3D::GetCurrent()->impl()->DeleteRenderbuffers(n, renderbuffers);
-}
-void DeleteShader(GLuint shader) {
- Graphics3D::GetCurrent()->impl()->DeleteShader(shader);
-}
-void DeleteTextures(GLsizei n, const GLuint* textures) {
- Graphics3D::GetCurrent()->impl()->DeleteTextures(n, textures);
-}
-void DepthFunc(GLenum func) {
- Graphics3D::GetCurrent()->impl()->DepthFunc(func);
-}
-void DepthMask(GLboolean flag) {
- Graphics3D::GetCurrent()->impl()->DepthMask(flag);
-}
-void DepthRangef(GLclampf zNear, GLclampf zFar) {
- Graphics3D::GetCurrent()->impl()->DepthRangef(zNear, zFar);
-}
-void DetachShader(GLuint program, GLuint shader) {
- Graphics3D::GetCurrent()->impl()->DetachShader(program, shader);
-}
-void Disable(GLenum cap) {
- Graphics3D::GetCurrent()->impl()->Disable(cap);
-}
-void DisableVertexAttribArray(GLuint index) {
- Graphics3D::GetCurrent()->impl()->DisableVertexAttribArray(index);
-}
-void DrawArrays(GLenum mode, GLint first, GLsizei count) {
- Graphics3D::GetCurrent()->impl()->DrawArrays(mode, first, count);
-}
-void DrawElements(
- GLenum mode, GLsizei count, GLenum type, const void* indices) {
- Graphics3D::GetCurrent()->impl()->DrawElements(mode, count, type, indices);
-}
-void Enable(GLenum cap) {
- Graphics3D::GetCurrent()->impl()->Enable(cap);
-}
-void EnableVertexAttribArray(GLuint index) {
- Graphics3D::GetCurrent()->impl()->EnableVertexAttribArray(index);
-}
-void Finish() {
- Graphics3D::GetCurrent()->impl()->Finish();
-}
-void Flush() {
- Graphics3D::GetCurrent()->impl()->Flush();
-}
-void FramebufferRenderbuffer(
- GLenum target, GLenum attachment, GLenum renderbuffertarget,
- GLuint renderbuffer) {
- Graphics3D::GetCurrent()->impl()->FramebufferRenderbuffer(
- target, attachment, renderbuffertarget, renderbuffer);
-}
-void FramebufferTexture2D(
- GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
- GLint level) {
- Graphics3D::GetCurrent()->impl()->FramebufferTexture2D(
- target, attachment, textarget, texture, level);
-}
-void FrontFace(GLenum mode) {
- Graphics3D::GetCurrent()->impl()->FrontFace(mode);
-}
-void GenBuffers(GLsizei n, GLuint* buffers) {
- Graphics3D::GetCurrent()->impl()->GenBuffers(n, buffers);
-}
-void GenerateMipmap(GLenum target) {
- Graphics3D::GetCurrent()->impl()->GenerateMipmap(target);
-}
-void GenFramebuffers(GLsizei n, GLuint* framebuffers) {
- Graphics3D::GetCurrent()->impl()->GenFramebuffers(n, framebuffers);
-}
-void GenRenderbuffers(GLsizei n, GLuint* renderbuffers) {
- Graphics3D::GetCurrent()->impl()->GenRenderbuffers(n, renderbuffers);
-}
-void GenTextures(GLsizei n, GLuint* textures) {
- Graphics3D::GetCurrent()->impl()->GenTextures(n, textures);
-}
-void GetActiveAttrib(
- GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
- GLenum* type, char* name) {
- Graphics3D::GetCurrent()->impl()->GetActiveAttrib(
- program, index, bufsize, length, size, type, name);
-}
-void GetActiveUniform(
- GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
- GLenum* type, char* name) {
- Graphics3D::GetCurrent()->impl()->GetActiveUniform(
- program, index, bufsize, length, size, type, name);
-}
-void GetAttachedShaders(
- GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
- Graphics3D::GetCurrent()->impl()->GetAttachedShaders(
- program, maxcount, count, shaders);
-}
-GLint GetAttribLocation(GLuint program, const char* name) {
- return Graphics3D::GetCurrent()->impl()->GetAttribLocation(program, name);
-}
-void GetBooleanv(GLenum pname, GLboolean* params) {
- Graphics3D::GetCurrent()->impl()->GetBooleanv(pname, params);
-}
-void GetBufferParameteriv(GLenum target, GLenum pname, GLint* params) {
- Graphics3D::GetCurrent()->impl()->GetBufferParameteriv(
- target, pname, params);
-}
-GLenum GetError() {
- return Graphics3D::GetCurrent()->impl()->GetError();
-}
-void GetFloatv(GLenum pname, GLfloat* params) {
- Graphics3D::GetCurrent()->impl()->GetFloatv(pname, params);
-}
-void GetFramebufferAttachmentParameteriv(
- GLenum target, GLenum attachment, GLenum pname, GLint* params) {
- Graphics3D::GetCurrent()->impl()->GetFramebufferAttachmentParameteriv(
- target, attachment, pname, params);
-}
-void GetIntegerv(GLenum pname, GLint* params) {
- Graphics3D::GetCurrent()->impl()->GetIntegerv(pname, params);
-}
-void GetProgramiv(GLuint program, GLenum pname, GLint* params) {
- Graphics3D::GetCurrent()->impl()->GetProgramiv(program, pname, params);
-}
-void GetProgramInfoLog(
- GLuint program, GLsizei bufsize, GLsizei* length, char* infolog) {
- Graphics3D::GetCurrent()->impl()->GetProgramInfoLog(
- program, bufsize, length, infolog);
-}
-void GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params) {
- Graphics3D::GetCurrent()->impl()->GetRenderbufferParameteriv(
- target, pname, params);
-}
-void GetShaderiv(GLuint shader, GLenum pname, GLint* params) {
- Graphics3D::GetCurrent()->impl()->GetShaderiv(shader, pname, params);
-}
-void GetShaderInfoLog(
- GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog) {
- Graphics3D::GetCurrent()->impl()->GetShaderInfoLog(
- shader, bufsize, length, infolog);
-}
-void GetShaderPrecisionFormat(
- GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
- Graphics3D::GetCurrent()->impl()->GetShaderPrecisionFormat(
- shadertype, precisiontype, range, precision);
-}
-void GetShaderSource(
- GLuint shader, GLsizei bufsize, GLsizei* length, char* source) {
- Graphics3D::GetCurrent()->impl()->GetShaderSource(
- shader, bufsize, length, source);
-}
-const GLubyte* GetString(GLenum name) {
- return Graphics3D::GetCurrent()->impl()->GetString(name);
-}
-void GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) {
- Graphics3D::GetCurrent()->impl()->GetTexParameterfv(target, pname, params);
-}
-void GetTexParameteriv(GLenum target, GLenum pname, GLint* params) {
- Graphics3D::GetCurrent()->impl()->GetTexParameteriv(target, pname, params);
-}
-void GetUniformfv(GLuint program, GLint location, GLfloat* params) {
- Graphics3D::GetCurrent()->impl()->GetUniformfv(program, location, params);
-}
-void GetUniformiv(GLuint program, GLint location, GLint* params) {
- Graphics3D::GetCurrent()->impl()->GetUniformiv(program, location, params);
-}
-GLint GetUniformLocation(GLuint program, const char* name) {
- return Graphics3D::GetCurrent()->impl()->GetUniformLocation(program, name);
-}
-void GetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) {
- Graphics3D::GetCurrent()->impl()->GetVertexAttribfv(index, pname, params);
-}
-void GetVertexAttribiv(GLuint index, GLenum pname, GLint* params) {
- Graphics3D::GetCurrent()->impl()->GetVertexAttribiv(index, pname, params);
-}
-void GetVertexAttribPointerv(GLuint index, GLenum pname, void** pointer) {
- Graphics3D::GetCurrent()->impl()->GetVertexAttribPointerv(
- index, pname, pointer);
-}
-void Hint(GLenum target, GLenum mode) {
- Graphics3D::GetCurrent()->impl()->Hint(target, mode);
-}
-GLboolean IsBuffer(GLuint buffer) {
- return Graphics3D::GetCurrent()->impl()->IsBuffer(buffer);
-}
-GLboolean IsEnabled(GLenum cap) {
- return Graphics3D::GetCurrent()->impl()->IsEnabled(cap);
-}
-GLboolean IsFramebuffer(GLuint framebuffer) {
- return Graphics3D::GetCurrent()->impl()->IsFramebuffer(framebuffer);
-}
-GLboolean IsProgram(GLuint program) {
- return Graphics3D::GetCurrent()->impl()->IsProgram(program);
-}
-GLboolean IsRenderbuffer(GLuint renderbuffer) {
- return Graphics3D::GetCurrent()->impl()->IsRenderbuffer(renderbuffer);
-}
-GLboolean IsShader(GLuint shader) {
- return Graphics3D::GetCurrent()->impl()->IsShader(shader);
-}
-GLboolean IsTexture(GLuint texture) {
- return Graphics3D::GetCurrent()->impl()->IsTexture(texture);
-}
-void LineWidth(GLfloat width) {
- Graphics3D::GetCurrent()->impl()->LineWidth(width);
-}
-void LinkProgram(GLuint program) {
- Graphics3D::GetCurrent()->impl()->LinkProgram(program);
-}
-void PixelStorei(GLenum pname, GLint param) {
- Graphics3D::GetCurrent()->impl()->PixelStorei(pname, param);
-}
-void PolygonOffset(GLfloat factor, GLfloat units) {
- Graphics3D::GetCurrent()->impl()->PolygonOffset(factor, units);
-}
-void ReadPixels(
- GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
- void* pixels) {
- Graphics3D::GetCurrent()->impl()->ReadPixels(
- x, y, width, height, format, type, pixels);
-}
-void ReleaseShaderCompiler() {
- Graphics3D::GetCurrent()->impl()->ReleaseShaderCompiler();
-}
-void RenderbufferStorage(
- GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
- Graphics3D::GetCurrent()->impl()->RenderbufferStorage(
- target, internalformat, width, height);
-}
-void SampleCoverage(GLclampf value, GLboolean invert) {
- Graphics3D::GetCurrent()->impl()->SampleCoverage(value, invert);
-}
-void Scissor(GLint x, GLint y, GLsizei width, GLsizei height) {
- Graphics3D::GetCurrent()->impl()->Scissor(x, y, width, height);
-}
-void ShaderBinary(
- GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary,
- GLsizei length) {
- Graphics3D::GetCurrent()->impl()->ShaderBinary(
- n, shaders, binaryformat, binary, length);
-}
-void ShaderSource(
- GLuint shader, GLsizei count, const char** str, const GLint* length) {
- Graphics3D::GetCurrent()->impl()->ShaderSource(shader, count, str, length);
-}
-void StencilFunc(GLenum func, GLint ref, GLuint mask) {
- Graphics3D::GetCurrent()->impl()->StencilFunc(func, ref, mask);
-}
-void StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) {
- Graphics3D::GetCurrent()->impl()->StencilFuncSeparate(face, func, ref, mask);
-}
-void StencilMask(GLuint mask) {
- Graphics3D::GetCurrent()->impl()->StencilMask(mask);
-}
-void StencilMaskSeparate(GLenum face, GLuint mask) {
- Graphics3D::GetCurrent()->impl()->StencilMaskSeparate(face, mask);
-}
-void StencilOp(GLenum fail, GLenum zfail, GLenum zpass) {
- Graphics3D::GetCurrent()->impl()->StencilOp(fail, zfail, zpass);
-}
-void StencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) {
- Graphics3D::GetCurrent()->impl()->StencilOpSeparate(
- face, fail, zfail, zpass);
-}
-void TexImage2D(
- GLenum target, GLint level, GLint internalformat, GLsizei width,
- GLsizei height, GLint border, GLenum format, GLenum type,
- const void* pixels) {
- Graphics3D::GetCurrent()->impl()->TexImage2D(
- target, level, internalformat, width, height, border, format, type,
- pixels);
-}
-void TexParameterf(GLenum target, GLenum pname, GLfloat param) {
- Graphics3D::GetCurrent()->impl()->TexParameterf(target, pname, param);
-}
-void TexParameterfv(GLenum target, GLenum pname, const GLfloat* params) {
- Graphics3D::GetCurrent()->impl()->TexParameterfv(target, pname, params);
-}
-void TexParameteri(GLenum target, GLenum pname, GLint param) {
- Graphics3D::GetCurrent()->impl()->TexParameteri(target, pname, param);
-}
-void TexParameteriv(GLenum target, GLenum pname, const GLint* params) {
- Graphics3D::GetCurrent()->impl()->TexParameteriv(target, pname, params);
-}
-void TexSubImage2D(
- GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
- GLsizei height, GLenum format, GLenum type, const void* pixels) {
- Graphics3D::GetCurrent()->impl()->TexSubImage2D(
- target, level, xoffset, yoffset, width, height, format, type, pixels);
-}
-void Uniform1f(GLint location, GLfloat x) {
- Graphics3D::GetCurrent()->impl()->Uniform1f(location, x);
-}
-void Uniform1fv(GLint location, GLsizei count, const GLfloat* v) {
- Graphics3D::GetCurrent()->impl()->Uniform1fv(location, count, v);
-}
-void Uniform1i(GLint location, GLint x) {
- Graphics3D::GetCurrent()->impl()->Uniform1i(location, x);
-}
-void Uniform1iv(GLint location, GLsizei count, const GLint* v) {
- Graphics3D::GetCurrent()->impl()->Uniform1iv(location, count, v);
-}
-void Uniform2f(GLint location, GLfloat x, GLfloat y) {
- Graphics3D::GetCurrent()->impl()->Uniform2f(location, x, y);
-}
-void Uniform2fv(GLint location, GLsizei count, const GLfloat* v) {
- Graphics3D::GetCurrent()->impl()->Uniform2fv(location, count, v);
-}
-void Uniform2i(GLint location, GLint x, GLint y) {
- Graphics3D::GetCurrent()->impl()->Uniform2i(location, x, y);
-}
-void Uniform2iv(GLint location, GLsizei count, const GLint* v) {
- Graphics3D::GetCurrent()->impl()->Uniform2iv(location, count, v);
-}
-void Uniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) {
- Graphics3D::GetCurrent()->impl()->Uniform3f(location, x, y, z);
-}
-void Uniform3fv(GLint location, GLsizei count, const GLfloat* v) {
- Graphics3D::GetCurrent()->impl()->Uniform3fv(location, count, v);
-}
-void Uniform3i(GLint location, GLint x, GLint y, GLint z) {
- Graphics3D::GetCurrent()->impl()->Uniform3i(location, x, y, z);
-}
-void Uniform3iv(GLint location, GLsizei count, const GLint* v) {
- Graphics3D::GetCurrent()->impl()->Uniform3iv(location, count, v);
-}
-void Uniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
- Graphics3D::GetCurrent()->impl()->Uniform4f(location, x, y, z, w);
-}
-void Uniform4fv(GLint location, GLsizei count, const GLfloat* v) {
- Graphics3D::GetCurrent()->impl()->Uniform4fv(location, count, v);
-}
-void Uniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) {
- Graphics3D::GetCurrent()->impl()->Uniform4i(location, x, y, z, w);
-}
-void Uniform4iv(GLint location, GLsizei count, const GLint* v) {
- Graphics3D::GetCurrent()->impl()->Uniform4iv(location, count, v);
-}
-void UniformMatrix2fv(
- GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
- Graphics3D::GetCurrent()->impl()->UniformMatrix2fv(
- location, count, transpose, value);
-}
-void UniformMatrix3fv(
- GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
- Graphics3D::GetCurrent()->impl()->UniformMatrix3fv(
- location, count, transpose, value);
-}
-void UniformMatrix4fv(
- GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
- Graphics3D::GetCurrent()->impl()->UniformMatrix4fv(
- location, count, transpose, value);
-}
-void UseProgram(GLuint program) {
- Graphics3D::GetCurrent()->impl()->UseProgram(program);
-}
-void ValidateProgram(GLuint program) {
- Graphics3D::GetCurrent()->impl()->ValidateProgram(program);
-}
-void VertexAttrib1f(GLuint indx, GLfloat x) {
- Graphics3D::GetCurrent()->impl()->VertexAttrib1f(indx, x);
-}
-void VertexAttrib1fv(GLuint indx, const GLfloat* values) {
- Graphics3D::GetCurrent()->impl()->VertexAttrib1fv(indx, values);
-}
-void VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) {
- Graphics3D::GetCurrent()->impl()->VertexAttrib2f(indx, x, y);
-}
-void VertexAttrib2fv(GLuint indx, const GLfloat* values) {
- Graphics3D::GetCurrent()->impl()->VertexAttrib2fv(indx, values);
-}
-void VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z) {
- Graphics3D::GetCurrent()->impl()->VertexAttrib3f(indx, x, y, z);
-}
-void VertexAttrib3fv(GLuint indx, const GLfloat* values) {
- Graphics3D::GetCurrent()->impl()->VertexAttrib3fv(indx, values);
-}
-void VertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
- Graphics3D::GetCurrent()->impl()->VertexAttrib4f(indx, x, y, z, w);
-}
-void VertexAttrib4fv(GLuint indx, const GLfloat* values) {
- Graphics3D::GetCurrent()->impl()->VertexAttrib4fv(indx, values);
-}
-void VertexAttribPointer(
- GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
- const void* ptr) {
- Graphics3D::GetCurrent()->impl()->VertexAttribPointer(
- indx, size, type, normalized, stride, ptr);
-}
-void Viewport(GLint x, GLint y, GLsizei width, GLsizei height) {
- Graphics3D::GetCurrent()->impl()->Viewport(x, y, width, height);
-}
-void SwapBuffers() {
- Graphics3D::GetCurrent()->impl()->SwapBuffers();
-}
-
-const struct PPB_OpenGLES_Dev ppb_opengles = {
- &ActiveTexture,
- &AttachShader,
- &BindAttribLocation,
- &BindBuffer,
- &BindFramebuffer,
- &BindRenderbuffer,
- &BindTexture,
- &BlendColor,
- &BlendEquation,
- &BlendEquationSeparate,
- &BlendFunc,
- &BlendFuncSeparate,
- &BufferData,
- &BufferSubData,
- &CheckFramebufferStatus,
- &Clear,
- &ClearColor,
- &ClearDepthf,
- &ClearStencil,
- &ColorMask,
- &CompileShader,
- &CompressedTexImage2D,
- &CompressedTexSubImage2D,
- &CopyTexImage2D,
- &CopyTexSubImage2D,
- &CreateProgram,
- &CreateShader,
- &CullFace,
- &DeleteBuffers,
- &DeleteFramebuffers,
- &DeleteProgram,
- &DeleteRenderbuffers,
- &DeleteShader,
- &DeleteTextures,
- &DepthFunc,
- &DepthMask,
- &DepthRangef,
- &DetachShader,
- &Disable,
- &DisableVertexAttribArray,
- &DrawArrays,
- &DrawElements,
- &Enable,
- &EnableVertexAttribArray,
- &Finish,
- &Flush,
- &FramebufferRenderbuffer,
- &FramebufferTexture2D,
- &FrontFace,
- &GenBuffers,
- &GenerateMipmap,
- &GenFramebuffers,
- &GenRenderbuffers,
- &GenTextures,
- &GetActiveAttrib,
- &GetActiveUniform,
- &GetAttachedShaders,
- &GetAttribLocation,
- &GetBooleanv,
- &GetBufferParameteriv,
- &GetError,
- &GetFloatv,
- &GetFramebufferAttachmentParameteriv,
- &GetIntegerv,
- &GetProgramiv,
- &GetProgramInfoLog,
- &GetRenderbufferParameteriv,
- &GetShaderiv,
- &GetShaderInfoLog,
- &GetShaderPrecisionFormat,
- &GetShaderSource,
- &GetString,
- &GetTexParameterfv,
- &GetTexParameteriv,
- &GetUniformfv,
- &GetUniformiv,
- &GetUniformLocation,
- &GetVertexAttribfv,
- &GetVertexAttribiv,
- &GetVertexAttribPointerv,
- &Hint,
- &IsBuffer,
- &IsEnabled,
- &IsFramebuffer,
- &IsProgram,
- &IsRenderbuffer,
- &IsShader,
- &IsTexture,
- &LineWidth,
- &LinkProgram,
- &PixelStorei,
- &PolygonOffset,
- &ReadPixels,
- &ReleaseShaderCompiler,
- &RenderbufferStorage,
- &SampleCoverage,
- &Scissor,
- &ShaderBinary,
- &ShaderSource,
- &StencilFunc,
- &StencilFuncSeparate,
- &StencilMask,
- &StencilMaskSeparate,
- &StencilOp,
- &StencilOpSeparate,
- &TexImage2D,
- &TexParameterf,
- &TexParameterfv,
- &TexParameteri,
- &TexParameteriv,
- &TexSubImage2D,
- &Uniform1f,
- &Uniform1fv,
- &Uniform1i,
- &Uniform1iv,
- &Uniform2f,
- &Uniform2fv,
- &Uniform2i,
- &Uniform2iv,
- &Uniform3f,
- &Uniform3fv,
- &Uniform3i,
- &Uniform3iv,
- &Uniform4f,
- &Uniform4fv,
- &Uniform4i,
- &Uniform4iv,
- &UniformMatrix2fv,
- &UniformMatrix3fv,
- &UniformMatrix4fv,
- &UseProgram,
- &ValidateProgram,
- &VertexAttrib1f,
- &VertexAttrib1fv,
- &VertexAttrib2f,
- &VertexAttrib2fv,
- &VertexAttrib3f,
- &VertexAttrib3fv,
- &VertexAttrib4f,
- &VertexAttrib4fv,
- &VertexAttribPointer,
- &Viewport,
- &SwapBuffers
-};
-
-} // namespace
-
-const PPB_OpenGLES_Dev* Graphics3D::GetOpenGLESInterface() {
- return &ppb_opengles;
-}
-
-} // namespace pepper
-
diff --git a/webkit/glue/plugins/pepper_image_data.cc b/webkit/glue/plugins/pepper_image_data.cc
deleted file mode 100644
index 92d4364..0000000
--- a/webkit/glue/plugins/pepper_image_data.cc
+++ /dev/null
@@ -1,210 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_image_data.h"
-
-#include <algorithm>
-#include <limits>
-
-#include "base/logging.h"
-#include "base/scoped_ptr.h"
-#include "skia/ext/platform_canvas.h"
-#include "ppapi/c/pp_instance.h"
-#include "ppapi/c/pp_module.h"
-#include "ppapi/c/pp_resource.h"
-#include "ppapi/c/ppb_image_data.h"
-#include "ppapi/c/trusted/ppb_image_data_trusted.h"
-#include "third_party/skia/include/core/SkColorPriv.h"
-#include "webkit/glue/plugins/pepper_common.h"
-#include "webkit/glue/plugins/pepper_plugin_instance.h"
-#include "webkit/glue/plugins/pepper_plugin_module.h"
-
-namespace pepper {
-
-namespace {
-
-PP_ImageDataFormat GetNativeImageDataFormat() {
- return ImageData::GetNativeImageDataFormat();
-}
-
-PP_Bool IsImageDataFormatSupported(PP_ImageDataFormat format) {
- return BoolToPPBool(ImageData::IsImageDataFormatSupported(format));
-}
-
-PP_Resource Create(PP_Module module_id,
- PP_ImageDataFormat format,
- const PP_Size* size,
- PP_Bool init_to_zero) {
- PluginModule* module = ResourceTracker::Get()->GetModule(module_id);
- if (!module)
- return 0;
-
- scoped_refptr<ImageData> data(new ImageData(module));
- if (!data->Init(format,
- size->width,
- size->height,
- PPBoolToBool(init_to_zero))) {
- return 0;
- }
-
- return data->GetReference();
-}
-
-PP_Bool IsImageData(PP_Resource resource) {
- return BoolToPPBool(!!Resource::GetAs<ImageData>(resource));
-}
-
-PP_Bool Describe(PP_Resource resource, PP_ImageDataDesc* desc) {
- // Give predictable values on failure.
- memset(desc, 0, sizeof(PP_ImageDataDesc));
-
- scoped_refptr<ImageData> image_data(Resource::GetAs<ImageData>(resource));
- if (!image_data)
- return PP_FALSE;
- image_data->Describe(desc);
- return PP_TRUE;
-}
-
-void* Map(PP_Resource resource) {
- scoped_refptr<ImageData> image_data(Resource::GetAs<ImageData>(resource));
- if (!image_data)
- return NULL;
- return image_data->Map();
-}
-
-void Unmap(PP_Resource resource) {
- scoped_refptr<ImageData> image_data(Resource::GetAs<ImageData>(resource));
- if (image_data)
- image_data->Unmap();
-}
-
-uint64_t GetNativeMemoryHandle2(PP_Resource resource, uint32_t* byte_count) {
- scoped_refptr<ImageData> image_data(Resource::GetAs<ImageData>(resource));
- if (image_data)
- return image_data->GetNativeMemoryHandle(byte_count);
- return 0;
-}
-
-const PPB_ImageData ppb_imagedata = {
- &GetNativeImageDataFormat,
- &IsImageDataFormatSupported,
- &Create,
- &IsImageData,
- &Describe,
- &Map,
- &Unmap,
-};
-
-const PPB_ImageDataTrusted ppb_imagedata_trusted = {
- &GetNativeMemoryHandle2,
-};
-
-} // namespace
-
-ImageData::ImageData(PluginModule* module)
- : Resource(module),
- format_(PP_IMAGEDATAFORMAT_BGRA_PREMUL),
- width_(0),
- height_(0) {
-}
-
-ImageData::~ImageData() {
-}
-
-// static
-const PPB_ImageData* ImageData::GetInterface() {
- return &ppb_imagedata;
-}
-
-// static
-const PPB_ImageDataTrusted* ImageData::GetTrustedInterface() {
- return &ppb_imagedata_trusted;
-}
-
-// static
-PP_ImageDataFormat ImageData::GetNativeImageDataFormat() {
- if (SK_B32_SHIFT == 0)
- return PP_IMAGEDATAFORMAT_BGRA_PREMUL;
- else if (SK_R32_SHIFT == 0)
- return PP_IMAGEDATAFORMAT_RGBA_PREMUL;
- else
- return PP_IMAGEDATAFORMAT_BGRA_PREMUL; // Default to something on failure.
-}
-
-// static
-bool ImageData::IsImageDataFormatSupported(PP_ImageDataFormat format) {
- return format == PP_IMAGEDATAFORMAT_BGRA_PREMUL ||
- format == PP_IMAGEDATAFORMAT_RGBA_PREMUL;
-}
-
-bool ImageData::Init(PP_ImageDataFormat format,
- int width, int height,
- bool init_to_zero) {
- // TODO(brettw) this should be called only on the main thread!
- // TODO(brettw) use init_to_zero when we implement caching.
- if (!IsImageDataFormatSupported(format))
- return false; // Only support this one format for now.
- if (width <= 0 || height <= 0)
- return false;
- if (static_cast<int64>(width) * static_cast<int64>(height) >=
- std::numeric_limits<int32>::max())
- return false; // Prevent overflow of signed 32-bit ints.
-
- platform_image_.reset(
- module()->GetSomeInstance()->delegate()->CreateImage2D(width, height));
- format_ = format;
- width_ = width;
- height_ = height;
- return !!platform_image_.get();
-}
-
-void ImageData::Describe(PP_ImageDataDesc* desc) const {
- desc->format = format_;
- desc->size.width = width_;
- desc->size.height = height_;
- desc->stride = width_ * 4;
-}
-
-void* ImageData::Map() {
- if (!mapped_canvas_.get()) {
- mapped_canvas_.reset(platform_image_->Map());
- if (!mapped_canvas_.get())
- return NULL;
- }
- const SkBitmap& bitmap =
- mapped_canvas_->getTopPlatformDevice().accessBitmap(true);
-
- // Our platform bitmaps are set to opaque by default, which we don't want.
- const_cast<SkBitmap&>(bitmap).setIsOpaque(false);
-
- bitmap.lockPixels();
- return bitmap.getAddr32(0, 0);
-}
-
-void ImageData::Unmap() {
- // This is currently unimplemented, which is OK. The data will just always
- // be around once it's mapped. Chrome's TransportDIB isn't currently
- // unmappable without freeing it, but this may be something we want to support
- // in the future to save some memory.
-}
-
-uint64 ImageData::GetNativeMemoryHandle(uint32* byte_count) const {
- return platform_image_->GetSharedMemoryHandle(byte_count);
-}
-
-const SkBitmap* ImageData::GetMappedBitmap() const {
- if (!mapped_canvas_.get())
- return NULL;
- return &mapped_canvas_->getTopPlatformDevice().accessBitmap(false);
-}
-
-void ImageData::Swap(ImageData* other) {
- swap(other->platform_image_, platform_image_);
- swap(other->mapped_canvas_, mapped_canvas_);
- std::swap(other->format_, format_);
- std::swap(other->width_, width_);
- std::swap(other->height_, height_);
-}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_image_data.h b/webkit/glue/plugins/pepper_image_data.h
deleted file mode 100644
index 473d4aa..0000000
--- a/webkit/glue/plugins/pepper_image_data.h
+++ /dev/null
@@ -1,131 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_IMAGE_DATA_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_IMAGE_DATA_H_
-
-#include "base/basictypes.h"
-#include "base/scoped_ptr.h"
-#include "ppapi/c/ppb_image_data.h"
-#include "webkit/glue/plugins/pepper_plugin_delegate.h"
-#include "webkit/glue/plugins/pepper_resource.h"
-
-namespace skia {
-class PlatformCanvas;
-}
-
-struct PPB_ImageDataTrusted;
-class SkBitmap;
-
-namespace pepper {
-
-class ImageData : public Resource {
- public:
- explicit ImageData(PluginModule* module);
- virtual ~ImageData();
-
- int width() const { return width_; }
- int height() const { return height_; }
-
- // Returns the image format.
- PP_ImageDataFormat format() const { return format_; }
-
- // Returns true if this image is mapped. False means that the image is either
- // invalid or not mapped. See ImageDataAutoMapper below.
- bool is_mapped() const { return !!mapped_canvas_.get(); }
-
- PluginDelegate::PlatformImage2D* platform_image() const {
- return platform_image_.get();
- }
-
- // Returns a pointer to the interface implementing PPB_ImageData that is
- // exposed to the plugin.
- static const PPB_ImageData* GetInterface();
- static const PPB_ImageDataTrusted* GetTrustedInterface();
-
- // Returns the image data format used by the browser. If the plugin uses the
- // same format, there is no conversion. Otherwise the browser will be in
- // charge of converting from a supported format to its native format.
- static PP_ImageDataFormat GetNativeImageDataFormat();
-
- // Returns true if the format is supported by the browser.
- static bool IsImageDataFormatSupported(PP_ImageDataFormat format);
-
- // Resource overrides.
- virtual ImageData* AsImageData() { return this; }
-
- // PPB_ImageData implementation.
- bool Init(PP_ImageDataFormat format,
- int width, int height,
- bool init_to_zero);
- void Describe(PP_ImageDataDesc* desc) const;
- void* Map();
- void Unmap();
-
- // PPB_ImageDataTrusted implementation.
- uint64 GetNativeMemoryHandle(uint32* byte_count) const;
-
- // The mapped bitmap and canvas will be NULL if the image is not mapped.
- skia::PlatformCanvas* mapped_canvas() const { return mapped_canvas_.get(); }
- const SkBitmap* GetMappedBitmap() const;
-
- // Swaps the guts of this image data with another.
- void Swap(ImageData* other);
-
- private:
- // This will be NULL before initialization, and if this ImageData is
- // swapped with another.
- scoped_ptr<PluginDelegate::PlatformImage2D> platform_image_;
-
- // When the device is mapped, this is the image. Null when umapped.
- scoped_ptr<skia::PlatformCanvas> mapped_canvas_;
-
- PP_ImageDataFormat format_;
- int width_;
- int height_;
-
- DISALLOW_COPY_AND_ASSIGN(ImageData);
-};
-
-// Manages mapping an image resource if necessary. Use this to ensure the
-// image is mapped. The destructor will put the image back into the previous
-// state. You must check is_valid() to make sure the image was successfully
-// mapped before using it.
-//
-// Example:
-// ImageDataAutoMapper mapper(image_data);
-// if (!mapper.is_valid())
-// return utter_failure;
-// image_data->mapped_canvas()->blah(); // Guaranteed valid.
-class ImageDataAutoMapper {
- public:
- ImageDataAutoMapper(ImageData* image_data) : image_data_(image_data) {
- if (image_data_->is_mapped()) {
- is_valid_ = true;
- needs_unmap_ = false;
- } else {
- is_valid_ = needs_unmap_ = !!image_data_->Map();
- }
- }
-
- ~ImageDataAutoMapper() {
- if (needs_unmap_)
- image_data_->Unmap();
- }
-
- // Check this to see if the image was successfully mapped. If this is false,
- // the image could not be mapped and is unusable.
- bool is_valid() const { return is_valid_; }
-
- private:
- ImageData* image_data_;
- bool is_valid_;
- bool needs_unmap_;
-
- DISALLOW_COPY_AND_ASSIGN(ImageDataAutoMapper);
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_IMAGE_DATA_H_
diff --git a/webkit/glue/plugins/pepper_plugin_delegate.h b/webkit/glue/plugins/pepper_plugin_delegate.h
deleted file mode 100644
index 7032c2c..0000000
--- a/webkit/glue/plugins/pepper_plugin_delegate.h
+++ /dev/null
@@ -1,281 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_PLUGIN_DELEGATE_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_PLUGIN_DELEGATE_H_
-
-#include <string>
-
-#include "base/callback.h"
-#include "base/platform_file.h"
-#include "base/ref_counted.h"
-#include "base/shared_memory.h"
-#include "base/sync_socket.h"
-#include "gfx/size.h"
-#include "googleurl/src/gurl.h"
-#include "ppapi/c/pp_completion_callback.h"
-#include "ppapi/c/pp_errors.h"
-#include "ppapi/c/pp_stdint.h"
-#include "webkit/fileapi/file_system_types.h"
-#include "webkit/glue/plugins/pepper_dir_contents.h"
-
-class AudioMessageFilter;
-class GURL;
-
-namespace base {
-class MessageLoopProxy;
-class Time;
-}
-
-namespace fileapi {
-class FileSystemCallbackDispatcher;
-}
-
-namespace gfx {
-class Rect;
-}
-
-namespace gpu {
-namespace gles2 {
-class GLES2Implementation;
-}
-}
-
-namespace skia {
-class PlatformCanvas;
-}
-
-namespace WebKit {
-class WebFileChooserCompletion;
-struct WebFileChooserParams;
-}
-
-struct PP_VideoCompressedDataBuffer_Dev;
-struct PP_VideoDecoderConfig_Dev;
-struct PP_VideoUncompressedDataBuffer_Dev;
-
-class TransportDIB;
-
-namespace pepper {
-
-class FileIO;
-class PluginInstance;
-class FullscreenContainer;
-
-// Virtual interface that the browser implements to implement features for
-// Pepper plugins.
-class PluginDelegate {
- public:
- // Represents an image. This is to allow the browser layer to supply a correct
- // image representation. In Chrome, this will be a TransportDIB.
- class PlatformImage2D {
- public:
- virtual ~PlatformImage2D() {}
-
- // Caller will own the returned pointer, returns NULL on failure.
- virtual skia::PlatformCanvas* Map() = 0;
-
- // Returns the platform-specific shared memory handle of the data backing
- // this image. This is used by PPAPI proxying to send the image to the
- // out-of-process plugin. On success, the size in bytes will be placed into
- // |*bytes_count|. Returns 0 on failure.
- virtual intptr_t GetSharedMemoryHandle(uint32* byte_count) const = 0;
-
- virtual TransportDIB* GetTransportDIB() const = 0;
- };
-
- class PlatformContext3D {
- public:
- virtual ~PlatformContext3D() {}
-
- // Initialize the context.
- virtual bool Init() = 0;
-
- // Present the rendered frame to the compositor.
- virtual bool SwapBuffers() = 0;
-
- // Get the last EGL error.
- virtual unsigned GetError() = 0;
-
- // Resize the backing texture used as a back buffer by OpenGL.
- virtual void ResizeBackingTexture(const gfx::Size& size) = 0;
-
- // Set an optional callback that will be invoked when the side effects of
- // a SwapBuffers call become visible to the compositor. Takes ownership
- // of the callback.
- virtual void SetSwapBuffersCallback(Callback0::Type* callback) = 0;
-
- // If the plugin instance is backed by an OpenGL, return its ID in the
- // compositors namespace. Otherwise return 0. Returns 0 by default.
- virtual unsigned GetBackingTextureId() = 0;
-
- // This call will return the address of the GLES2 implementation for this
- // context that is constructed in Initialize() and is valid until this
- // context is destroyed.
- virtual gpu::gles2::GLES2Implementation* GetGLES2Implementation() = 0;
- };
-
- class PlatformAudio {
- public:
- class Client {
- protected:
- virtual ~Client() {}
-
- public:
- // Called when the stream is created.
- virtual void StreamCreated(base::SharedMemoryHandle shared_memory_handle,
- size_t shared_memory_size,
- base::SyncSocket::Handle socket) = 0;
- };
-
- // Starts the playback. Returns false on error or if called before the
- // stream is created or after the stream is closed.
- virtual bool StartPlayback() = 0;
-
- // Stops the playback. Returns false on error or if called before the stream
- // is created or after the stream is closed.
- virtual bool StopPlayback() = 0;
-
- // Closes the stream. Make sure to call this before the object is
- // destructed.
- virtual void ShutDown() = 0;
-
- protected:
- virtual ~PlatformAudio() {}
- };
-
- class PlatformVideoDecoder {
- public:
- virtual ~PlatformVideoDecoder() {}
-
- // Returns false on failure.
- virtual bool Decode(PP_VideoCompressedDataBuffer_Dev& input_buffer) = 0;
- virtual int32_t Flush(PP_CompletionCallback& callback) = 0;
- virtual bool ReturnUncompressedDataBuffer(
- PP_VideoUncompressedDataBuffer_Dev& buffer) = 0;
- };
-
- // Indicates that the given instance has been created.
- virtual void InstanceCreated(pepper::PluginInstance* instance) = 0;
-
- // Indicates that the given instance is being destroyed. This is called from
- // the destructor, so it's important that the instance is not dereferenced
- // from this call.
- virtual void InstanceDeleted(pepper::PluginInstance* instance) = 0;
-
- // The caller will own the pointer returned from this.
- virtual PlatformImage2D* CreateImage2D(int width, int height) = 0;
-
- // The caller will own the pointer returned from this.
- virtual PlatformContext3D* CreateContext3D() = 0;
-
- // The caller will own the pointer returned from this.
- virtual PlatformVideoDecoder* CreateVideoDecoder(
- const PP_VideoDecoderConfig_Dev& decoder_config) = 0;
-
- // The caller will own the pointer returned from this.
- virtual PlatformAudio* CreateAudio(uint32_t sample_rate,
- uint32_t sample_count,
- PlatformAudio::Client* client) = 0;
-
- // Notifies that the number of find results has changed.
- virtual void NumberOfFindResultsChanged(int identifier,
- int total,
- bool final_result) = 0;
-
- // Notifies that the index of the currently selected item has been updated.
- virtual void SelectedFindResultChanged(int identifier, int index) = 0;
-
- // Runs a file chooser.
- virtual bool RunFileChooser(
- const WebKit::WebFileChooserParams& params,
- WebKit::WebFileChooserCompletion* chooser_completion) = 0;
-
- // Sends an async IPC to open a file.
- typedef Callback2<base::PlatformFileError, base::PlatformFile
- >::Type AsyncOpenFileCallback;
- virtual bool AsyncOpenFile(const FilePath& path,
- int flags,
- AsyncOpenFileCallback* callback) = 0;
- virtual bool OpenFileSystem(
- const GURL& url,
- fileapi::FileSystemType type,
- long long size,
- fileapi::FileSystemCallbackDispatcher* dispatcher) = 0;
- virtual bool MakeDirectory(
- const FilePath& path,
- bool recursive,
- fileapi::FileSystemCallbackDispatcher* dispatcher) = 0;
- virtual bool Query(const FilePath& path,
- fileapi::FileSystemCallbackDispatcher* dispatcher) = 0;
- virtual bool Touch(const FilePath& path,
- const base::Time& last_access_time,
- const base::Time& last_modified_time,
- fileapi::FileSystemCallbackDispatcher* dispatcher) = 0;
- virtual bool Delete(const FilePath& path,
- fileapi::FileSystemCallbackDispatcher* dispatcher) = 0;
- virtual bool Rename(const FilePath& file_path,
- const FilePath& new_file_path,
- fileapi::FileSystemCallbackDispatcher* dispatcher) = 0;
- virtual bool ReadDirectory(
- const FilePath& directory_path,
- fileapi::FileSystemCallbackDispatcher* dispatcher) = 0;
-
- virtual base::PlatformFileError OpenModuleLocalFile(
- const std::string& module_name,
- const FilePath& path,
- int flags,
- base::PlatformFile* file) = 0;
- virtual base::PlatformFileError RenameModuleLocalFile(
- const std::string& module_name,
- const FilePath& path_from,
- const FilePath& path_to) = 0;
- virtual base::PlatformFileError DeleteModuleLocalFileOrDir(
- const std::string& module_name,
- const FilePath& path,
- bool recursive) = 0;
- virtual base::PlatformFileError CreateModuleLocalDir(
- const std::string& module_name,
- const FilePath& path) = 0;
- virtual base::PlatformFileError QueryModuleLocalFile(
- const std::string& module_name,
- const FilePath& path,
- base::PlatformFileInfo* info) = 0;
- virtual base::PlatformFileError GetModuleLocalDirContents(
- const std::string& module_name,
- const FilePath& path,
- PepperDirContents* contents) = 0;
-
- // Returns a MessageLoopProxy instance associated with the message loop
- // of the file thread in this renderer.
- virtual scoped_refptr<base::MessageLoopProxy>
- GetFileThreadMessageLoopProxy() = 0;
-
- // Create a fullscreen container for a plugin instance. This effectively
- // switches the plugin to fullscreen.
- virtual FullscreenContainer* CreateFullscreenContainer(
- PluginInstance* instance) = 0;
-
- // Returns a string with the name of the default 8-bit char encoding.
- virtual std::string GetDefaultEncoding() = 0;
-
- // Sets the mininum and maximium zoom factors.
- virtual void ZoomLimitsChanged(double minimum_factor,
- double maximum_factor) = 0;
-
- // Retrieves the proxy information for the given URL in PAC format. On error,
- // this will return an empty string.
- virtual std::string ResolveProxy(const GURL& url) = 0;
-
- // Tell the browser when resource loading starts/ends.
- virtual void DidStartLoading() = 0;
- virtual void DidStopLoading() = 0;
-
- // Sets restrictions on how the content can be used (i.e. no print/copy).
- virtual void SetContentRestriction(int restrictions) = 0;
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_PLUGIN_DELEGATE_H_
diff --git a/webkit/glue/plugins/pepper_plugin_instance.cc b/webkit/glue/plugins/pepper_plugin_instance.cc
deleted file mode 100644
index f705178..0000000
--- a/webkit/glue/plugins/pepper_plugin_instance.cc
+++ /dev/null
@@ -1,1179 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_plugin_instance.h"
-
-#include "base/logging.h"
-#include "base/metrics/histogram.h"
-#if defined(OS_MACOSX)
-#include "base/mac_util.h"
-#include "base/mac/scoped_cftyperef.h"
-#endif
-#include "base/scoped_ptr.h"
-#include "base/utf_string_conversions.h"
-#include "gfx/rect.h"
-#if defined(OS_WIN)
-#include "gfx/codec/jpeg_codec.h"
-#include "gfx/gdi_util.h"
-#endif
-#include "gfx/skia_util.h"
-#include "ppapi/c/dev/ppb_find_dev.h"
-#include "ppapi/c/dev/ppb_fullscreen_dev.h"
-#include "ppapi/c/dev/ppb_zoom_dev.h"
-#include "ppapi/c/dev/ppp_find_dev.h"
-#include "ppapi/c/dev/ppp_selection_dev.h"
-#include "ppapi/c/dev/ppp_zoom_dev.h"
-#include "ppapi/c/pp_input_event.h"
-#include "ppapi/c/pp_instance.h"
-#include "ppapi/c/pp_rect.h"
-#include "ppapi/c/pp_resource.h"
-#include "ppapi/c/pp_var.h"
-#include "ppapi/c/ppb_core.h"
-#include "ppapi/c/ppb_instance.h"
-#include "ppapi/c/ppp_instance.h"
-#include "printing/native_metafile.h"
-#include "printing/units.h"
-#include "skia/ext/vector_platform_device.h"
-#include "skia/ext/platform_canvas.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebBindings.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebCursorInfo.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebDocument.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebElement.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebPluginContainer.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebRect.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebURLRequest.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebView.h"
-#include "webkit/glue/plugins/pepper_buffer.h"
-#include "webkit/glue/plugins/pepper_common.h"
-#include "webkit/glue/plugins/pepper_graphics_2d.h"
-#include "webkit/glue/plugins/pepper_graphics_3d.h"
-#include "webkit/glue/plugins/pepper_event_conversion.h"
-#include "webkit/glue/plugins/pepper_fullscreen_container.h"
-#include "webkit/glue/plugins/pepper_image_data.h"
-#include "webkit/glue/plugins/pepper_plugin_delegate.h"
-#include "webkit/glue/plugins/pepper_plugin_module.h"
-#include "webkit/glue/plugins/pepper_string.h"
-#include "webkit/glue/plugins/pepper_url_loader.h"
-#include "webkit/glue/plugins/pepper_var.h"
-#include "webkit/glue/plugins/ppp_private.h"
-
-using WebKit::WebBindings;
-using WebKit::WebCanvas;
-using WebKit::WebCursorInfo;
-using WebKit::WebDocument;
-using WebKit::WebFrame;
-using WebKit::WebInputEvent;
-using WebKit::WebPluginContainer;
-using WebKit::WebString;
-using WebKit::WebURLRequest;
-using WebKit::WebView;
-
-namespace pepper {
-
-#if defined(OS_WIN)
-// Exported by pdf.dll
-typedef bool (*RenderPDFPageToDCProc)(
- const unsigned char* pdf_buffer, int buffer_size, int page_number, HDC dc,
- int dpi_x, int dpi_y, int bounds_origin_x, int bounds_origin_y,
- int bounds_width, int bounds_height, bool fit_to_bounds,
- bool stretch_to_bounds, bool keep_aspect_ratio, bool center_in_bounds);
-#endif // defined(OS_WIN)
-
-namespace {
-
-#define COMPILE_ASSERT_MATCHING_ENUM(webkit_name, np_name) \
- COMPILE_ASSERT(int(WebCursorInfo::webkit_name) == int(np_name), \
- mismatching_enums)
-
-COMPILE_ASSERT_MATCHING_ENUM(TypePointer, PP_CURSORTYPE_POINTER);
-COMPILE_ASSERT_MATCHING_ENUM(TypeCross, PP_CURSORTYPE_CROSS);
-COMPILE_ASSERT_MATCHING_ENUM(TypeHand, PP_CURSORTYPE_HAND);
-COMPILE_ASSERT_MATCHING_ENUM(TypeIBeam, PP_CURSORTYPE_IBEAM);
-COMPILE_ASSERT_MATCHING_ENUM(TypeWait, PP_CURSORTYPE_WAIT);
-COMPILE_ASSERT_MATCHING_ENUM(TypeHelp, PP_CURSORTYPE_HELP);
-COMPILE_ASSERT_MATCHING_ENUM(TypeEastResize, PP_CURSORTYPE_EASTRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeNorthResize, PP_CURSORTYPE_NORTHRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeNorthEastResize,
- PP_CURSORTYPE_NORTHEASTRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeNorthWestResize,
- PP_CURSORTYPE_NORTHWESTRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeSouthResize, PP_CURSORTYPE_SOUTHRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeSouthEastResize,
- PP_CURSORTYPE_SOUTHEASTRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeSouthWestResize,
- PP_CURSORTYPE_SOUTHWESTRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeWestResize, PP_CURSORTYPE_WESTRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeNorthSouthResize,
- PP_CURSORTYPE_NORTHSOUTHRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeEastWestResize, PP_CURSORTYPE_EASTWESTRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeNorthEastSouthWestResize,
- PP_CURSORTYPE_NORTHEASTSOUTHWESTRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeNorthWestSouthEastResize,
- PP_CURSORTYPE_NORTHWESTSOUTHEASTRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeColumnResize, PP_CURSORTYPE_COLUMNRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeRowResize, PP_CURSORTYPE_ROWRESIZE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeMiddlePanning, PP_CURSORTYPE_MIDDLEPANNING);
-COMPILE_ASSERT_MATCHING_ENUM(TypeEastPanning, PP_CURSORTYPE_EASTPANNING);
-COMPILE_ASSERT_MATCHING_ENUM(TypeNorthPanning, PP_CURSORTYPE_NORTHPANNING);
-COMPILE_ASSERT_MATCHING_ENUM(TypeNorthEastPanning,
- PP_CURSORTYPE_NORTHEASTPANNING);
-COMPILE_ASSERT_MATCHING_ENUM(TypeNorthWestPanning,
- PP_CURSORTYPE_NORTHWESTPANNING);
-COMPILE_ASSERT_MATCHING_ENUM(TypeSouthPanning, PP_CURSORTYPE_SOUTHPANNING);
-COMPILE_ASSERT_MATCHING_ENUM(TypeSouthEastPanning,
- PP_CURSORTYPE_SOUTHEASTPANNING);
-COMPILE_ASSERT_MATCHING_ENUM(TypeSouthWestPanning,
- PP_CURSORTYPE_SOUTHWESTPANNING);
-COMPILE_ASSERT_MATCHING_ENUM(TypeWestPanning, PP_CURSORTYPE_WESTPANNING);
-COMPILE_ASSERT_MATCHING_ENUM(TypeMove, PP_CURSORTYPE_MOVE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeVerticalText, PP_CURSORTYPE_VERTICALTEXT);
-COMPILE_ASSERT_MATCHING_ENUM(TypeCell, PP_CURSORTYPE_CELL);
-COMPILE_ASSERT_MATCHING_ENUM(TypeContextMenu, PP_CURSORTYPE_CONTEXTMENU);
-COMPILE_ASSERT_MATCHING_ENUM(TypeAlias, PP_CURSORTYPE_ALIAS);
-COMPILE_ASSERT_MATCHING_ENUM(TypeProgress, PP_CURSORTYPE_PROGRESS);
-COMPILE_ASSERT_MATCHING_ENUM(TypeNoDrop, PP_CURSORTYPE_NODROP);
-COMPILE_ASSERT_MATCHING_ENUM(TypeCopy, PP_CURSORTYPE_COPY);
-COMPILE_ASSERT_MATCHING_ENUM(TypeNone, PP_CURSORTYPE_NONE);
-COMPILE_ASSERT_MATCHING_ENUM(TypeNotAllowed, PP_CURSORTYPE_NOTALLOWED);
-COMPILE_ASSERT_MATCHING_ENUM(TypeZoomIn, PP_CURSORTYPE_ZOOMIN);
-COMPILE_ASSERT_MATCHING_ENUM(TypeZoomOut, PP_CURSORTYPE_ZOOMOUT);
-COMPILE_ASSERT_MATCHING_ENUM(TypeCustom, PP_CURSORTYPE_CUSTOM);
-
-void RectToPPRect(const gfx::Rect& input, PP_Rect* output) {
- *output = PP_MakeRectFromXYWH(input.x(), input.y(),
- input.width(), input.height());
-}
-
-PP_Var GetWindowObject(PP_Instance instance_id) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return PP_MakeUndefined();
- return instance->GetWindowObject();
-}
-
-PP_Var GetOwnerElementObject(PP_Instance instance_id) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return PP_MakeUndefined();
- return instance->GetOwnerElementObject();
-}
-
-PP_Bool BindGraphics(PP_Instance instance_id, PP_Resource graphics_id) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return PP_FALSE;
- return BoolToPPBool(instance->BindGraphics(graphics_id));
-}
-
-PP_Bool IsFullFrame(PP_Instance instance_id) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return PP_FALSE;
- return BoolToPPBool(instance->full_frame());
-}
-
-PP_Var ExecuteScript(PP_Instance instance_id,
- PP_Var script,
- PP_Var* exception) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return PP_MakeUndefined();
- return instance->ExecuteScript(script, exception);
-}
-
-const PPB_Instance ppb_instance = {
- &GetWindowObject,
- &GetOwnerElementObject,
- &BindGraphics,
- &IsFullFrame,
- &ExecuteScript,
-};
-
-void NumberOfFindResultsChanged(PP_Instance instance_id,
- int32_t total,
- PP_Bool final_result) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return;
-
- DCHECK_NE(instance->find_identifier(), -1);
- instance->delegate()->NumberOfFindResultsChanged(
- instance->find_identifier(), total, PPBoolToBool(final_result));
-}
-
-void SelectedFindResultChanged(PP_Instance instance_id,
- int32_t index) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return;
-
- DCHECK_NE(instance->find_identifier(), -1);
- instance->delegate()->SelectedFindResultChanged(
- instance->find_identifier(), index);
-}
-
-const PPB_Find_Dev ppb_find = {
- &NumberOfFindResultsChanged,
- &SelectedFindResultChanged,
-};
-
-PP_Bool IsFullscreen(PP_Instance instance_id) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return PP_FALSE;
- return BoolToPPBool(instance->IsFullscreen());
-}
-
-PP_Bool SetFullscreen(PP_Instance instance_id, PP_Bool fullscreen) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return PP_FALSE;
- return BoolToPPBool(instance->SetFullscreen(PPBoolToBool(fullscreen)));
-}
-
-const PPB_Fullscreen_Dev ppb_fullscreen = {
- &IsFullscreen,
- &SetFullscreen,
-};
-
-void ZoomChanged(PP_Instance instance_id, double factor) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return;
-
- // We only want to tell the page to change its zoom if the whole page is the
- // PDF. If we're in an iframe, then don't do anything.
- WebFrame* frame = instance->container()->element().document().frame();
- if (!frame->view()->mainFrame()->document().isPluginDocument())
- return;
-
- double zoom_level = WebView::zoomFactorToZoomLevel(factor);
- // The conversino from zoom level to factor, and back, can introduce rounding
- // errors. i.e. WebKit originally tells us 3.0, but by the time we tell the
- // plugin and it tells us back, the level becomes 3.000000000004. Need to
- // round or else otherwise if the user zooms out, it will go to 3.0 instead of
- // 2.0.
- int rounded =
- static_cast<int>(zoom_level + (zoom_level > 0 ? 0.001 : -0.001));
- if (abs(rounded - zoom_level) < 0.001)
- zoom_level = rounded;
- instance->container()->zoomLevelChanged(zoom_level);
-}
-
-void ZoomLimitsChanged(PP_Instance instance_id,
- double minimum_factor,
- double maximium_factor) {
- if (minimum_factor > maximium_factor) {
- NOTREACHED();
- return;
- }
-
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return;
- instance->delegate()->ZoomLimitsChanged(minimum_factor, maximium_factor);
-}
-
-const PPB_Zoom_Dev ppb_zoom = {
- &ZoomChanged,
- &ZoomLimitsChanged
-};
-
-} // namespace
-
-PluginInstance::PluginInstance(PluginDelegate* delegate,
- PluginModule* module,
- const PPP_Instance* instance_interface)
- : delegate_(delegate),
- module_(module),
- instance_interface_(instance_interface),
- pp_instance_(0),
- container_(NULL),
- full_frame_(false),
- has_webkit_focus_(false),
- has_content_area_focus_(false),
- find_identifier_(-1),
- plugin_find_interface_(NULL),
- plugin_private_interface_(NULL),
- plugin_selection_interface_(NULL),
- plugin_zoom_interface_(NULL),
-#if defined (OS_LINUX)
- num_pages_(0),
- pdf_output_done_(false),
-#endif // defined (OS_LINUX)
- plugin_print_interface_(NULL),
- plugin_graphics_3d_interface_(NULL),
- always_on_top_(false),
- fullscreen_container_(NULL) {
- pp_instance_ = ResourceTracker::Get()->AddInstance(this);
-
- memset(&current_print_settings_, 0, sizeof(current_print_settings_));
- DCHECK(delegate);
- module_->InstanceCreated(this);
- delegate_->InstanceCreated(this);
-}
-
-PluginInstance::~PluginInstance() {
- FOR_EACH_OBSERVER(Observer, observers_, InstanceDestroyed(this));
-
- delegate_->InstanceDeleted(this);
- module_->InstanceDeleted(this);
-
- ResourceTracker::Get()->InstanceDeleted(pp_instance_);
-}
-
-// static
-const PPB_Instance* PluginInstance::GetInterface() {
- return &ppb_instance;
-}
-
-// static
-const PPB_Find_Dev* PluginInstance::GetFindInterface() {
- return &ppb_find;
-}
-
-// static
-const PPB_Fullscreen_Dev* PluginInstance::GetFullscreenInterface() {
- return &ppb_fullscreen;
-}
-
-// static
-const PPB_Zoom_Dev* PluginInstance::GetZoomInterface() {
- return &ppb_zoom;
-}
-
-void PluginInstance::AddObserver(Observer* observer) {
- observers_.AddObserver(observer);
-}
-
-void PluginInstance::RemoveObserver(Observer* observer) {
- observers_.RemoveObserver(observer);
-}
-
-void PluginInstance::Paint(WebCanvas* canvas,
- const gfx::Rect& plugin_rect,
- const gfx::Rect& paint_rect) {
- if (bound_graphics_2d())
- bound_graphics_2d()->Paint(canvas, plugin_rect, paint_rect);
-}
-
-void PluginInstance::InvalidateRect(const gfx::Rect& rect) {
- if (fullscreen_container_) {
- if (rect.IsEmpty())
- fullscreen_container_->Invalidate();
- else
- fullscreen_container_->InvalidateRect(rect);
- } else {
- if (!container_ || position_.IsEmpty())
- return; // Nothing to do.
- if (rect.IsEmpty())
- container_->invalidate();
- else
- container_->invalidateRect(rect);
- }
-}
-
-void PluginInstance::ScrollRect(int dx, int dy, const gfx::Rect& rect) {
- if (fullscreen_container_) {
- fullscreen_container_->ScrollRect(dx, dy, rect);
- } else {
- if (full_frame_) {
- container_->scrollRect(dx, dy, rect);
- } else {
- // Can't do optimized scrolling since there could be other elements on top
- // of us.
- InvalidateRect(rect);
- }
- }
-}
-
-unsigned PluginInstance::GetBackingTextureId() {
- if (!bound_graphics_3d())
- return 0;
-
- return bound_graphics_3d()->GetBackingTextureId();
-}
-
-void PluginInstance::CommitBackingTexture() {
- container_->commitBackingTexture();
-}
-
-PP_Var PluginInstance::GetWindowObject() {
- if (!container_)
- return PP_MakeUndefined();
-
- WebFrame* frame = container_->element().document().frame();
- if (!frame)
- return PP_MakeUndefined();
-
- return ObjectVar::NPObjectToPPVar(module(), frame->windowObject());
-}
-
-PP_Var PluginInstance::GetOwnerElementObject() {
- if (!container_)
- return PP_MakeUndefined();
- return ObjectVar::NPObjectToPPVar(module(),
- container_->scriptableObjectForElement());
-}
-
-bool PluginInstance::BindGraphics(PP_Resource graphics_id) {
- if (!graphics_id) {
- // Special-case clearing the current device.
- if (bound_graphics_.get()) {
- if (bound_graphics_2d()) {
- bound_graphics_2d()->BindToInstance(NULL);
- } else if (bound_graphics_.get()) {
- bound_graphics_3d()->SetSwapBuffersCallback(NULL);
- bound_graphics_3d()->BindToInstance(NULL);
- }
- InvalidateRect(gfx::Rect());
- }
- bound_graphics_ = NULL;
- return true;
- }
-
- scoped_refptr<Graphics2D> graphics_2d =
- Resource::GetAs<Graphics2D>(graphics_id);
- scoped_refptr<Graphics3D> graphics_3d =
- Resource::GetAs<Graphics3D>(graphics_id);
-
- if (graphics_2d) {
- if (!graphics_2d->BindToInstance(this))
- return false; // Can't bind to more than one instance.
-
- // See http://crbug.com/49403: this can be further optimized by keeping the
- // old device around and painting from it.
- if (bound_graphics_2d()) {
- // Start the new image with the content of the old image until the plugin
- // repaints.
- const SkBitmap* old_backing_bitmap =
- bound_graphics_2d()->image_data()->GetMappedBitmap();
- SkRect old_size = SkRect::MakeWH(
- SkScalar(static_cast<float>(old_backing_bitmap->width())),
- SkScalar(static_cast<float>(old_backing_bitmap->height())));
-
- SkCanvas canvas(*graphics_2d->image_data()->GetMappedBitmap());
- canvas.drawBitmap(*old_backing_bitmap, 0, 0);
-
- // Fill in any extra space with white.
- canvas.clipRect(old_size, SkRegion::kDifference_Op);
- canvas.drawARGB(255, 255, 255, 255);
- }
-
- bound_graphics_ = graphics_2d;
- // BindToInstance will have invalidated the plugin if necessary.
- } else if (graphics_3d) {
- if (!graphics_3d->BindToInstance(this))
- return false;
-
- bound_graphics_ = graphics_3d;
- bound_graphics_3d()->SetSwapBuffersCallback(
- NewCallback(this, &PluginInstance::CommitBackingTexture));
- }
-
- return true;
-}
-
-bool PluginInstance::SetCursor(PP_CursorType_Dev type) {
- cursor_.reset(new WebCursorInfo(static_cast<WebCursorInfo::Type>(type)));
- return true;
-}
-
-PP_Var PluginInstance::ExecuteScript(PP_Var script, PP_Var* exception) {
- TryCatch try_catch(module(), exception);
- if (try_catch.has_exception())
- return PP_MakeUndefined();
-
- // Convert the script into an inconvenient NPString object.
- scoped_refptr<StringVar> script_string(StringVar::FromPPVar(script));
- if (!script_string) {
- try_catch.SetException("Script param to ExecuteScript must be a string.");
- return PP_MakeUndefined();
- }
- NPString np_script;
- np_script.UTF8Characters = script_string->value().c_str();
- np_script.UTF8Length = script_string->value().length();
-
- // Get the current frame to pass to the evaluate function.
- WebFrame* frame = container_->element().document().frame();
- if (!frame) {
- try_catch.SetException("No frame to execute script in.");
- return PP_MakeUndefined();
- }
-
- NPVariant result;
- bool ok = WebBindings::evaluate(NULL, frame->windowObject(), &np_script,
- &result);
- if (!ok) {
- // TODO(brettw) bug 54011: The TryCatch isn't working properly and
- // doesn't actually catch this exception.
- try_catch.SetException("Exception caught");
- WebBindings::releaseVariantValue(&result);
- return PP_MakeUndefined();
- }
-
- PP_Var ret = Var::NPVariantToPPVar(module_, &result);
- WebBindings::releaseVariantValue(&result);
- return ret;
-}
-
-void PluginInstance::Delete() {
- instance_interface_->DidDestroy(pp_instance());
-
- if (fullscreen_container_) {
- fullscreen_container_->Destroy();
- fullscreen_container_ = NULL;
- }
- container_ = NULL;
-}
-
-bool PluginInstance::Initialize(WebPluginContainer* container,
- const std::vector<std::string>& arg_names,
- const std::vector<std::string>& arg_values,
- bool full_frame) {
- container_ = container;
- full_frame_ = full_frame;
-
- size_t argc = 0;
- scoped_array<const char*> argn(new const char*[arg_names.size()]);
- scoped_array<const char*> argv(new const char*[arg_names.size()]);
- for (size_t i = 0; i < arg_names.size(); ++i) {
- argn[argc] = arg_names[i].c_str();
- argv[argc] = arg_values[i].c_str();
- argc++;
- }
-
- return PPBoolToBool(instance_interface_->DidCreate(pp_instance(),
- argc,
- argn.get(),
- argv.get()));
-}
-
-bool PluginInstance::HandleDocumentLoad(URLLoader* loader) {
- Resource::ScopedResourceId resource(loader);
- return PPBoolToBool(instance_interface_->HandleDocumentLoad(pp_instance(),
- resource.id));
-}
-
-bool PluginInstance::HandleInputEvent(const WebKit::WebInputEvent& event,
- WebCursorInfo* cursor_info) {
- std::vector<PP_InputEvent> pp_events;
- CreatePPEvent(event, &pp_events);
-
- // Each input event may generate more than one PP_InputEvent.
- bool rv = false;
- for (size_t i = 0; i < pp_events.size(); i++) {
- rv |= PPBoolToBool(instance_interface_->HandleInputEvent(pp_instance(),
- &pp_events[i]));
- }
-
- if (cursor_.get())
- *cursor_info = *cursor_;
- return rv;
-}
-
-PP_Var PluginInstance::GetInstanceObject() {
- return instance_interface_->GetInstanceObject(pp_instance());
-}
-
-void PluginInstance::ViewChanged(const gfx::Rect& position,
- const gfx::Rect& clip) {
- if (position.size() != position_.size() && bound_graphics_3d()) {
- // TODO(apatrick): This is a hack to force the back buffer to resize.
- // It is obviously wrong to call SwapBuffers when a partial frame has
- // potentially been rendered. Plan is to embed resize commands in the
- // command buffer just before ViewChanged is called.
- bound_graphics_3d()->ResizeBackingTexture(position.size());
- bound_graphics_3d()->SwapBuffers();
- }
-
- position_ = position;
-
- if (clip.IsEmpty()) {
- // WebKit can give weird (x,y) positions for empty clip rects (since the
- // position technically doesn't matter). But we want to make these
- // consistent since this is given to the plugin, so force everything to 0
- // in the "everything is clipped" case.
- clip_ = gfx::Rect();
- } else {
- clip_ = clip;
- }
-
- PP_Rect pp_position, pp_clip;
- RectToPPRect(position_, &pp_position);
- RectToPPRect(clip_, &pp_clip);
- instance_interface_->DidChangeView(pp_instance(), &pp_position, &pp_clip);
-}
-
-void PluginInstance::SetWebKitFocus(bool has_focus) {
- if (has_webkit_focus_ == has_focus)
- return;
-
- bool old_plugin_focus = PluginHasFocus();
- has_webkit_focus_ = has_focus;
- if (PluginHasFocus() != old_plugin_focus) {
- instance_interface_->DidChangeFocus(pp_instance(),
- BoolToPPBool(PluginHasFocus()));
- }
-}
-
-void PluginInstance::SetContentAreaFocus(bool has_focus) {
- if (has_content_area_focus_ == has_focus)
- return;
-
- bool old_plugin_focus = PluginHasFocus();
- has_content_area_focus_ = has_focus;
- if (PluginHasFocus() != old_plugin_focus) {
- instance_interface_->DidChangeFocus(pp_instance(),
- BoolToPPBool(PluginHasFocus()));
- }
-}
-
-void PluginInstance::ViewInitiatedPaint() {
- if (bound_graphics_2d())
- bound_graphics_2d()->ViewInitiatedPaint();
-}
-
-void PluginInstance::ViewFlushedPaint() {
- if (bound_graphics_2d())
- bound_graphics_2d()->ViewFlushedPaint();
-}
-
-bool PluginInstance::GetBitmapForOptimizedPluginPaint(
- const gfx::Rect& paint_bounds,
- TransportDIB** dib,
- gfx::Rect* location,
- gfx::Rect* clip) {
- if (!always_on_top_)
- return false;
- if (!bound_graphics_2d() || !bound_graphics_2d()->is_always_opaque())
- return false;
-
- // We specifically want to compare against the area covered by the backing
- // store when seeing if we cover the given paint bounds, since the backing
- // store could be smaller than the declared plugin area.
- ImageData* image_data = bound_graphics_2d()->image_data();
- gfx::Rect plugin_backing_store_rect(position_.origin(),
- gfx::Size(image_data->width(),
- image_data->height()));
- gfx::Rect clip_page(clip_);
- clip_page.Offset(position_.origin());
- gfx::Rect plugin_paint_rect = plugin_backing_store_rect.Intersect(clip_page);
- if (!plugin_paint_rect.Contains(paint_bounds))
- return false;
-
- *dib = image_data->platform_image()->GetTransportDIB();
- *location = plugin_backing_store_rect;
- *clip = clip_page;
- return true;
-}
-
-string16 PluginInstance::GetSelectedText(bool html) {
- if (!LoadSelectionInterface())
- return string16();
-
- PP_Var rv = plugin_selection_interface_->GetSelectedText(pp_instance(),
- BoolToPPBool(html));
- scoped_refptr<StringVar> string(StringVar::FromPPVar(rv));
- Var::PluginReleasePPVar(rv); // Release the ref the plugin transfered to us.
- if (!string)
- return string16();
- return UTF8ToUTF16(string->value());
-}
-
-string16 PluginInstance::GetLinkAtPosition(const gfx::Point& point) {
- if (!LoadPrivateInterface())
- return string16();
-
- PP_Point p;
- p.x = point.x();
- p.y = point.y();
- PP_Var rv = plugin_private_interface_->GetLinkAtPosition(pp_instance(), p);
- scoped_refptr<StringVar> string(StringVar::FromPPVar(rv));
- Var::PluginReleasePPVar(rv); // Release the ref the plugin transfered to us.
- if (!string)
- return string16();
- return UTF8ToUTF16(string->value());
-}
-
-void PluginInstance::Zoom(double factor, bool text_only) {
- if (!LoadZoomInterface())
- return;
- plugin_zoom_interface_->Zoom(pp_instance(), factor, BoolToPPBool(text_only));
-}
-
-bool PluginInstance::StartFind(const string16& search_text,
- bool case_sensitive,
- int identifier) {
- if (!LoadFindInterface())
- return false;
- find_identifier_ = identifier;
- return PPBoolToBool(
- plugin_find_interface_->StartFind(
- pp_instance(),
- UTF16ToUTF8(search_text.c_str()).c_str(),
- BoolToPPBool(case_sensitive)));
-}
-
-void PluginInstance::SelectFindResult(bool forward) {
- if (LoadFindInterface())
- plugin_find_interface_->SelectFindResult(pp_instance(),
- BoolToPPBool(forward));
-}
-
-void PluginInstance::StopFind() {
- if (!LoadFindInterface())
- return;
- find_identifier_ = -1;
- plugin_find_interface_->StopFind(pp_instance());
-}
-
-bool PluginInstance::LoadFindInterface() {
- if (!plugin_find_interface_) {
- plugin_find_interface_ =
- reinterpret_cast<const PPP_Find_Dev*>(module_->GetPluginInterface(
- PPP_FIND_DEV_INTERFACE));
- }
-
- return !!plugin_find_interface_;
-}
-
-bool PluginInstance::LoadPrivateInterface() {
- if (!plugin_private_interface_) {
- plugin_private_interface_ =
- reinterpret_cast<const PPP_Private*>(module_->GetPluginInterface(
- PPP_PRIVATE_INTERFACE));
- }
-
- return !!plugin_private_interface_;
-}
-
-bool PluginInstance::LoadSelectionInterface() {
- if (!plugin_selection_interface_) {
- plugin_selection_interface_ =
- reinterpret_cast<const PPP_Selection_Dev*>(module_->GetPluginInterface(
- PPP_SELECTION_DEV_INTERFACE));
- }
-
- return !!plugin_selection_interface_;
-}
-
-bool PluginInstance::LoadZoomInterface() {
- if (!plugin_zoom_interface_) {
- plugin_zoom_interface_ =
- reinterpret_cast<const PPP_Zoom_Dev*>(module_->GetPluginInterface(
- PPP_ZOOM_DEV_INTERFACE));
- }
-
- return !!plugin_zoom_interface_;
-}
-
-bool PluginInstance::PluginHasFocus() const {
- return has_webkit_focus_ && has_content_area_focus_;
-}
-
-bool PluginInstance::GetPreferredPrintOutputFormat(
- PP_PrintOutputFormat_Dev* format) {
- if (!plugin_print_interface_) {
- plugin_print_interface_ =
- reinterpret_cast<const PPP_Printing_Dev*>(module_->GetPluginInterface(
- PPP_PRINTING_DEV_INTERFACE));
- }
- if (!plugin_print_interface_)
- return false;
- uint32_t format_count = 0;
- PP_PrintOutputFormat_Dev* supported_formats =
- plugin_print_interface_->QuerySupportedFormats(pp_instance(),
- &format_count);
- if (!supported_formats)
- return false;
-
- bool found_supported_format = false;
- for (uint32_t index = 0; index < format_count; index++) {
- if (supported_formats[index] == PP_PRINTOUTPUTFORMAT_PDF) {
- // If we found PDF, we are done.
- found_supported_format = true;
- *format = PP_PRINTOUTPUTFORMAT_PDF;
- break;
- } else if (supported_formats[index] == PP_PRINTOUTPUTFORMAT_RASTER) {
- // We found raster. Keep looking.
- found_supported_format = true;
- *format = PP_PRINTOUTPUTFORMAT_RASTER;
- }
- }
- PluginModule::GetCore()->MemFree(supported_formats);
- return found_supported_format;
-}
-
-bool PluginInstance::SupportsPrintInterface() {
- PP_PrintOutputFormat_Dev format;
- return GetPreferredPrintOutputFormat(&format);
-}
-
-int PluginInstance::PrintBegin(const gfx::Rect& printable_area,
- int printer_dpi) {
- PP_PrintOutputFormat_Dev format;
- if (!GetPreferredPrintOutputFormat(&format)) {
- // PrintBegin should not have been called since SupportsPrintInterface
- // would have returned false;
- NOTREACHED();
- return 0;
- }
-
- PP_PrintSettings_Dev print_settings;
- RectToPPRect(printable_area, &print_settings.printable_area);
- print_settings.dpi = printer_dpi;
- print_settings.orientation = PP_PRINTORIENTATION_NORMAL;
- print_settings.grayscale = PP_FALSE;
- print_settings.format = format;
- int num_pages = plugin_print_interface_->Begin(pp_instance(),
- &print_settings);
- if (!num_pages)
- return 0;
- current_print_settings_ = print_settings;
-#if defined (OS_LINUX)
- num_pages_ = num_pages;
- pdf_output_done_ = false;
-#endif // (OS_LINUX)
- return num_pages;
-}
-
-bool PluginInstance::PrintPage(int page_number, WebKit::WebCanvas* canvas) {
- DCHECK(plugin_print_interface_);
- PP_PrintPageNumberRange_Dev page_range;
-#if defined(OS_LINUX)
- if (current_print_settings_.format == PP_PRINTOUTPUTFORMAT_PDF) {
- // On Linux we will try and output all pages as PDF in the first call to
- // PrintPage. This is a temporary hack.
- // TODO(sanjeevr): Remove this hack and fix this by changing the print
- // interfaces for WebFrame and WebPlugin.
- if (page_number != 0)
- return pdf_output_done_;
- page_range.first_page_number = 0;
- page_range.last_page_number = num_pages_ - 1;
- }
-#else // defined(OS_LINUX)
- page_range.first_page_number = page_range.last_page_number = page_number;
-#endif // defined(OS_LINUX)
-
- PP_Resource print_output =
- plugin_print_interface_->PrintPages(pp_instance(), &page_range, 1);
-
- if (!print_output)
- return false;
-
- bool ret = false;
-
- if (current_print_settings_.format == PP_PRINTOUTPUTFORMAT_PDF)
- ret = PrintPDFOutput(print_output, canvas);
- else if (current_print_settings_.format == PP_PRINTOUTPUTFORMAT_RASTER)
- ret = PrintRasterOutput(print_output, canvas);
-
- // Now we need to release the print output resource.
- PluginModule::GetCore()->ReleaseResource(print_output);
-
- return ret;
-}
-
-void PluginInstance::PrintEnd() {
- DCHECK(plugin_print_interface_);
- if (plugin_print_interface_)
- plugin_print_interface_->End(pp_instance());
- memset(&current_print_settings_, 0, sizeof(current_print_settings_));
-#if defined(OS_MACOSX)
- last_printed_page_ = NULL;
-#elif defined(OS_LINUX)
- num_pages_ = 0;
- pdf_output_done_ = false;
-#endif // defined(OS_LINUX)
-}
-
-bool PluginInstance::IsFullscreen() {
- return fullscreen_container_ != NULL;
-}
-
-bool PluginInstance::SetFullscreen(bool fullscreen) {
- bool is_fullscreen = (fullscreen_container_ != NULL);
- if (fullscreen == is_fullscreen)
- return true;
- VLOG(1) << "Setting fullscreen to " << (fullscreen ? "on" : "off");
- if (fullscreen) {
- fullscreen_container_ = delegate_->CreateFullscreenContainer(this);
- } else {
- fullscreen_container_->Destroy();
- fullscreen_container_ = NULL;
- // TODO(piman): currently the fullscreen container resizes the plugin to the
- // fullscreen size so we need to reset the size here. Eventually it will
- // transparently scale and this won't be necessary.
- if (container_) {
- container_->reportGeometry();
- container_->invalidate();
- }
- }
- return true;
-}
-
-bool PluginInstance::NavigateToURL(const char* url, const char* target) {
- if (!url || !target || !container_)
- return false;
-
- WebDocument document = container_->element().document();
- GURL complete_url = document.completeURL(WebString::fromUTF8(url));
- // Don't try to deal with the security issues of javascript.
- if (complete_url.SchemeIs("javascript"))
- return false;
-
- WebURLRequest request(complete_url);
- document.frame()->setReferrerForRequest(request, GURL());
- request.setHTTPMethod(WebString::fromUTF8("GET"));
- request.setFirstPartyForCookies(document.firstPartyForCookies());
-
- WebString target_str = WebString::fromUTF8(target);
- container_->loadFrameRequest(request, target_str, false, NULL);
- return true;
-}
-
-bool PluginInstance::PrintPDFOutput(PP_Resource print_output,
- WebKit::WebCanvas* canvas) {
- scoped_refptr<Buffer> buffer(Resource::GetAs<Buffer>(print_output));
- if (!buffer.get() || !buffer->is_mapped() || !buffer->size()) {
- NOTREACHED();
- return false;
- }
-#if defined(OS_WIN)
- // For Windows, we need the PDF DLL to render the output PDF to a DC.
- HMODULE pdf_module = GetModuleHandle(L"pdf.dll");
- if (!pdf_module)
- return false;
- RenderPDFPageToDCProc render_proc =
- reinterpret_cast<RenderPDFPageToDCProc>(
- GetProcAddress(pdf_module, "RenderPDFPageToDC"));
- if (!render_proc)
- return false;
-#endif // defined(OS_WIN)
-
- bool ret = false;
-#if defined(OS_LINUX)
- // On Linux we need to get the backing PdfPsMetafile and write the bits
- // directly.
- cairo_t* context = canvas->beginPlatformPaint();
- printing::NativeMetafile* metafile =
- printing::NativeMetafile::FromCairoContext(context);
- DCHECK(metafile);
- if (metafile) {
- ret = metafile->SetRawData(buffer->mapped_buffer(), buffer->size());
- if (ret)
- pdf_output_done_ = true;
- }
- canvas->endPlatformPaint();
-#elif defined(OS_MACOSX)
- printing::NativeMetafile metafile;
- // Create a PDF metafile and render from there into the passed in context.
- if (metafile.Init(buffer->mapped_buffer(), buffer->size())) {
- // Flip the transform.
- CGContextSaveGState(canvas);
- CGContextTranslateCTM(canvas, 0,
- current_print_settings_.printable_area.size.height);
- CGContextScaleCTM(canvas, 1.0, -1.0);
- CGRect page_rect;
- page_rect.origin.x = current_print_settings_.printable_area.point.x;
- page_rect.origin.y = current_print_settings_.printable_area.point.y;
- page_rect.size.width = current_print_settings_.printable_area.size.width;
- page_rect.size.height = current_print_settings_.printable_area.size.height;
-
- ret = metafile.RenderPage(1, canvas, page_rect, true, false, true, true);
- CGContextRestoreGState(canvas);
- }
-#elif defined(OS_WIN)
- // On Windows, we now need to render the PDF to the DC that backs the
- // supplied canvas.
- skia::VectorPlatformDevice& device =
- static_cast<skia::VectorPlatformDevice&>(
- canvas->getTopPlatformDevice());
- HDC dc = device.getBitmapDC();
- gfx::Size size_in_pixels;
- size_in_pixels.set_width(
- printing::ConvertUnit(current_print_settings_.printable_area.size.width,
- static_cast<int>(printing::kPointsPerInch),
- current_print_settings_.dpi));
- size_in_pixels.set_height(
- printing::ConvertUnit(current_print_settings_.printable_area.size.height,
- static_cast<int>(printing::kPointsPerInch),
- current_print_settings_.dpi));
- // We need to render using the actual printer DPI (rendering to a smaller
- // set of pixels leads to a blurry output). However, we need to counter the
- // scaling up that will happen in the browser.
- XFORM xform = {0};
- xform.eM11 = xform.eM22 = static_cast<float>(printing::kPointsPerInch) /
- static_cast<float>(current_print_settings_.dpi);
- ModifyWorldTransform(dc, &xform, MWT_LEFTMULTIPLY);
-
- ret = render_proc(buffer->mapped_buffer(), buffer->size(), 0, dc,
- current_print_settings_.dpi, current_print_settings_.dpi,
- 0, 0, size_in_pixels.width(),
- size_in_pixels.height(), true, false, true, true);
-#endif // defined(OS_WIN)
-
- return ret;
-}
-
-bool PluginInstance::PrintRasterOutput(PP_Resource print_output,
- WebKit::WebCanvas* canvas) {
- scoped_refptr<ImageData> image(Resource::GetAs<ImageData>(print_output));
- if (!image.get() || !image->is_mapped())
- return false;
-
- const SkBitmap* bitmap = image->GetMappedBitmap();
- if (!bitmap)
- return false;
-
- // Draw the printed image into the supplied canvas.
- SkIRect src_rect;
- src_rect.set(0, 0, bitmap->width(), bitmap->height());
- SkRect dest_rect;
- dest_rect.set(
- SkIntToScalar(current_print_settings_.printable_area.point.x),
- SkIntToScalar(current_print_settings_.printable_area.point.y),
- SkIntToScalar(current_print_settings_.printable_area.point.x +
- current_print_settings_.printable_area.size.width),
- SkIntToScalar(current_print_settings_.printable_area.point.y +
- current_print_settings_.printable_area.size.height));
- bool draw_to_canvas = true;
- gfx::Rect dest_rect_gfx;
- dest_rect_gfx.set_x(current_print_settings_.printable_area.point.x);
- dest_rect_gfx.set_y(current_print_settings_.printable_area.point.y);
- dest_rect_gfx.set_width(current_print_settings_.printable_area.size.width);
- dest_rect_gfx.set_height(current_print_settings_.printable_area.size.height);
-
-#if defined(OS_WIN)
- // Since this is a raster output, the size of the bitmap can be
- // huge (especially at high printer DPIs). On Windows, this can
- // result in a HUGE EMF (on Mac and Linux the output goes to PDF
- // which appears to Flate compress the bitmap). So, if this bitmap
- // is larger than 20 MB, we save the bitmap as a JPEG into the EMF
- // DC. Note: We chose JPEG over PNG because JPEG compression seems
- // way faster (about 4 times faster).
- static const int kCompressionThreshold = 20 * 1024 * 1024;
- if (bitmap->getSize() > kCompressionThreshold) {
- DrawJPEGToPlatformDC(*bitmap, dest_rect_gfx, canvas);
- draw_to_canvas = false;
- }
-#endif // defined(OS_WIN)
-#if defined(OS_MACOSX)
- draw_to_canvas = false;
- DrawSkBitmapToCanvas(*bitmap, canvas, dest_rect_gfx,
- current_print_settings_.printable_area.size.height);
- // See comments in the header file.
- last_printed_page_ = image;
-#else // defined(OS_MACOSX)
- if (draw_to_canvas)
- canvas->drawBitmapRect(*bitmap, &src_rect, dest_rect);
-#endif // defined(OS_MACOSX)
- return true;
-}
-
-#if defined(OS_WIN)
-bool PluginInstance::DrawJPEGToPlatformDC(
- const SkBitmap& bitmap,
- const gfx::Rect& printable_area,
- WebKit::WebCanvas* canvas) {
- skia::VectorPlatformDevice& device =
- static_cast<skia::VectorPlatformDevice&>(
- canvas->getTopPlatformDevice());
- HDC dc = device.getBitmapDC();
- // TODO(sanjeevr): This is a temporary hack. If we output a JPEG
- // to the EMF, the EnumEnhMetaFile call fails in the browser
- // process. The failure also happens if we output nothing here.
- // We need to investigate the reason for this failure and fix it.
- // In the meantime this temporary hack of drawing an empty
- // rectangle in the DC gets us by.
- Rectangle(dc, 0, 0, 0, 0);
-
- // Ideally we should add JPEG compression to the VectorPlatformDevice class
- // However, Skia currently has no JPEG compression code and we cannot
- // depend on gfx/jpeg_codec.h in Skia. So we do the compression here.
- SkAutoLockPixels lock(bitmap);
- DCHECK(bitmap.getConfig() == SkBitmap::kARGB_8888_Config);
- const uint32_t* pixels =
- static_cast<const uint32_t*>(bitmap.getPixels());
- std::vector<unsigned char> compressed_image;
- base::TimeTicks start_time = base::TimeTicks::Now();
- bool encoded = gfx::JPEGCodec::Encode(
- reinterpret_cast<const unsigned char*>(pixels),
- gfx::JPEGCodec::FORMAT_BGRA, bitmap.width(), bitmap.height(),
- static_cast<int>(bitmap.rowBytes()), 100, &compressed_image);
- UMA_HISTOGRAM_TIMES("PepperPluginPrint.RasterBitmapCompressTime",
- base::TimeTicks::Now() - start_time);
- if (!encoded) {
- NOTREACHED();
- return false;
- }
- BITMAPINFOHEADER bmi = {0};
- gfx::CreateBitmapHeader(bitmap.width(), bitmap.height(), &bmi);
- bmi.biCompression = BI_JPEG;
- bmi.biSizeImage = compressed_image.size();
- bmi.biHeight = -bmi.biHeight;
- StretchDIBits(dc, printable_area.x(), printable_area.y(),
- printable_area.width(), printable_area.height(),
- 0, 0, bitmap.width(), bitmap.height(),
- &compressed_image.front(),
- reinterpret_cast<const BITMAPINFO*>(&bmi),
- DIB_RGB_COLORS, SRCCOPY);
- return true;
-}
-#endif // OS_WIN
-
-#if defined(OS_MACOSX)
-void PluginInstance::DrawSkBitmapToCanvas(
- const SkBitmap& bitmap, WebKit::WebCanvas* canvas,
- const gfx::Rect& dest_rect,
- int canvas_height) {
- SkAutoLockPixels lock(bitmap);
- DCHECK(bitmap.getConfig() == SkBitmap::kARGB_8888_Config);
- base::mac::ScopedCFTypeRef<CGDataProviderRef> data_provider(
- CGDataProviderCreateWithData(
- NULL, bitmap.getAddr32(0, 0),
- bitmap.rowBytes() * bitmap.height(), NULL));
- base::mac::ScopedCFTypeRef<CGImageRef> image(
- CGImageCreate(
- bitmap.width(), bitmap.height(),
- 8, 32, bitmap.rowBytes(),
- mac_util::GetSystemColorSpace(),
- kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,
- data_provider, NULL, false, kCGRenderingIntentDefault));
-
- // Flip the transform
- CGContextSaveGState(canvas);
- CGContextTranslateCTM(canvas, 0, canvas_height);
- CGContextScaleCTM(canvas, 1.0, -1.0);
-
- CGRect bounds;
- bounds.origin.x = dest_rect.x();
- bounds.origin.y = canvas_height - dest_rect.y() - dest_rect.height();
- bounds.size.width = dest_rect.width();
- bounds.size.height = dest_rect.height();
-
- CGContextDrawImage(canvas, bounds, image);
- CGContextRestoreGState(canvas);
-}
-#endif // defined(OS_MACOSX)
-
-Graphics2D* PluginInstance::bound_graphics_2d() const {
- if (bound_graphics_.get() == NULL)
- return NULL;
-
- return bound_graphics_->Cast<Graphics2D>();
-}
-
-Graphics3D* PluginInstance::bound_graphics_3d() const {
- if (bound_graphics_.get() == NULL)
- return NULL;
-
- return bound_graphics_->Cast<Graphics3D>();
-}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_plugin_instance.h b/webkit/glue/plugins/pepper_plugin_instance.h
deleted file mode 100644
index bd99843..0000000
--- a/webkit/glue/plugins/pepper_plugin_instance.h
+++ /dev/null
@@ -1,318 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_PLUGIN_INSTANCE_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_PLUGIN_INSTANCE_H_
-
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/observer_list.h"
-#include "base/ref_counted.h"
-#include "base/scoped_ptr.h"
-#include "base/string16.h"
-#include "gfx/rect.h"
-#include "ppapi/c/dev/pp_cursor_type_dev.h"
-#include "ppapi/c/dev/ppp_graphics_3d_dev.h"
-#include "ppapi/c/dev/ppp_printing_dev.h"
-#include "ppapi/c/pp_instance.h"
-#include "ppapi/c/pp_resource.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebCanvas.h"
-
-struct PP_Var;
-struct PPB_Instance;
-struct PPB_Find_Dev;
-struct PPB_Fullscreen_Dev;
-struct PPB_Zoom_Dev;
-struct PPP_Find_Dev;
-struct PPP_Instance;
-struct PPP_Private;
-struct PPP_Selection_Dev;
-struct PPP_Zoom_Dev;
-
-class SkBitmap;
-class TransportDIB;
-
-namespace gfx {
-class Rect;
-}
-
-namespace WebKit {
-struct WebCursorInfo;
-class WebInputEvent;
-class WebPluginContainer;
-}
-
-namespace pepper {
-
-class Graphics2D;
-class Graphics3D;
-class ImageData;
-class PluginDelegate;
-class PluginModule;
-class Resource;
-class URLLoader;
-class FullscreenContainer;
-
-// Represents one time a plugin appears on one web page.
-//
-// Note: to get from a PP_Instance to a PluginInstance*, use the
-// ResourceTracker.
-class PluginInstance : public base::RefCounted<PluginInstance> {
- public:
- class Observer {
- public:
- // Indicates that the instance is being destroyed. This will be called from
- // the instance's destructor so don't do anything in this callback that
- // uses the instance.
- virtual void InstanceDestroyed(PluginInstance* instance) = 0;
- };
-
- PluginInstance(PluginDelegate* delegate,
- PluginModule* module,
- const PPP_Instance* instance_interface);
- ~PluginInstance();
-
- static const PPB_Instance* GetInterface();
-
- // Returns a pointer to the interface implementing PPB_Find that is
- // exposed to the plugin.
- static const PPB_Find_Dev* GetFindInterface();
- static const PPB_Fullscreen_Dev* GetFullscreenInterface();
- static const PPB_Zoom_Dev* GetZoomInterface();
-
- PluginDelegate* delegate() const { return delegate_; }
- PluginModule* module() const { return module_.get(); }
-
- WebKit::WebPluginContainer* container() const { return container_; }
-
- const gfx::Rect& position() const { return position_; }
- const gfx::Rect& clip() const { return clip_; }
-
- int find_identifier() const { return find_identifier_; }
-
- void set_always_on_top(bool on_top) { always_on_top_ = on_top; }
-
- // Returns the PP_Instance uniquely identifying this instance. Guaranteed
- // nonzero.
- PP_Instance pp_instance() const { return pp_instance_; }
-
- // Other classes can register an observer for instance events. These pointers
- // are NOT owned by the Instance. If the object implementing the observer
- // goes away, it must take care to unregister itself.
- void AddObserver(Observer* observer);
- void RemoveObserver(Observer* observer);
-
- // Paints the current backing store to the web page.
- void Paint(WebKit::WebCanvas* canvas,
- const gfx::Rect& plugin_rect,
- const gfx::Rect& paint_rect);
-
- // Schedules a paint of the page for the given region. The coordinates are
- // relative to the top-left of the plugin. This does nothing if the plugin
- // has not yet been positioned. You can supply an empty gfx::Rect() to
- // invalidate the entire plugin.
- void InvalidateRect(const gfx::Rect& rect);
-
- // Schedules a scroll of the plugin. This uses optimized scrolling only for
- // full-frame plugins, as otherwise there could be other elements on top. The
- // slow path can also be triggered if there is an overlapping frame.
- void ScrollRect(int dx, int dy, const gfx::Rect& rect);
-
- // If the plugin instance is backed by a texture, return its texture ID in the
- // compositor's namespace. Otherwise return 0. Returns 0 by default.
- virtual unsigned GetBackingTextureId();
-
- // Commit the backing texture to the screen once the side effects some
- // rendering up to an offscreen SwapBuffers are visible.
- void CommitBackingTexture();
-
- // PPB_Instance implementation.
- PP_Var GetWindowObject();
- PP_Var GetOwnerElementObject();
- bool BindGraphics(PP_Resource graphics_id);
- bool full_frame() const { return full_frame_; }
- bool SetCursor(PP_CursorType_Dev type);
- PP_Var ExecuteScript(PP_Var script, PP_Var* exception);
-
- // PPP_Instance pass-through.
- void Delete();
- bool Initialize(WebKit::WebPluginContainer* container,
- const std::vector<std::string>& arg_names,
- const std::vector<std::string>& arg_values,
- bool full_frame);
- bool HandleDocumentLoad(URLLoader* loader);
- bool HandleInputEvent(const WebKit::WebInputEvent& event,
- WebKit::WebCursorInfo* cursor_info);
- PP_Var GetInstanceObject();
- void ViewChanged(const gfx::Rect& position, const gfx::Rect& clip);
-
- // Notifications about focus changes, see has_webkit_focus_ below.
- void SetWebKitFocus(bool has_focus);
- void SetContentAreaFocus(bool has_focus);
-
- // Notifications that the view has rendered the page and that it has been
- // flushed to the screen. These messages are used to send Flush callbacks to
- // the plugin for DeviceContext2D.
- void ViewInitiatedPaint();
- void ViewFlushedPaint();
-
- // If this plugin can be painted merely by copying the backing store to the
- // screen, and the plugin bounds encloses the given paint bounds, returns
- // true. In this case, the location, clipping, and ID of the backing store
- // will be filled into the given output parameters.
- bool GetBitmapForOptimizedPluginPaint(
- const gfx::Rect& paint_bounds,
- TransportDIB** dib,
- gfx::Rect* dib_bounds,
- gfx::Rect* clip);
-
- string16 GetSelectedText(bool html);
- string16 GetLinkAtPosition(const gfx::Point& point);
- void Zoom(double factor, bool text_only);
- bool StartFind(const string16& search_text,
- bool case_sensitive,
- int identifier);
- void SelectFindResult(bool forward);
- void StopFind();
-
- bool SupportsPrintInterface();
- int PrintBegin(const gfx::Rect& printable_area, int printer_dpi);
- bool PrintPage(int page_number, WebKit::WebCanvas* canvas);
- void PrintEnd();
-
- void Graphics3DContextLost();
-
- // Implementation of PPB_Fullscreen_Dev.
- bool IsFullscreen();
- bool SetFullscreen(bool fullscreen);
-
- // Implementation of PPB_Private2.
- bool NavigateToURL(const char* url, const char* target);
-
- private:
- bool LoadFindInterface();
- bool LoadPrivateInterface();
- bool LoadSelectionInterface();
- bool LoadZoomInterface();
-
- // Determines if we think the plugin has focus, both content area and webkit
- // (see has_webkit_focus_ below).
- bool PluginHasFocus() const;
-
- // Queries the plugin for supported print formats and sets |format| to the
- // best format to use. Returns false if the plugin does not support any
- // print format that we can handle (we can handle raster and PDF).
- bool GetPreferredPrintOutputFormat(PP_PrintOutputFormat_Dev* format);
- bool PrintPDFOutput(PP_Resource print_output, WebKit::WebCanvas* canvas);
- bool PrintRasterOutput(PP_Resource print_output, WebKit::WebCanvas* canvas);
-#if defined(OS_WIN)
- bool DrawJPEGToPlatformDC(const SkBitmap& bitmap,
- const gfx::Rect& printable_area,
- WebKit::WebCanvas* canvas);
-#elif defined(OS_MACOSX)
- // Draws the given kARGB_8888_Config bitmap to the specified canvas starting
- // at the specified destination rect.
- void DrawSkBitmapToCanvas(const SkBitmap& bitmap, WebKit::WebCanvas* canvas,
- const gfx::Rect& dest_rect, int canvas_height);
-#endif // OS_MACOSX
-
- // Get the bound graphics context as a concrete 2D graphics context or returns
- // null if the context is not 2D.
- Graphics2D* bound_graphics_2d() const;
-
- // Get the bound graphics context as a concrete 3D graphics context or returns
- // null if the context is not 3D.
- Graphics3D* bound_graphics_3d() const;
-
- PluginDelegate* delegate_;
- scoped_refptr<PluginModule> module_;
- const PPP_Instance* instance_interface_;
-
- PP_Instance pp_instance_;
-
- // NULL until we have been initialized.
- WebKit::WebPluginContainer* container_;
-
- // Indicates whether this is a full frame instance, which means it represents
- // an entire document rather than an embed tag.
- bool full_frame_;
-
- // Position in the viewport (which moves as the page is scrolled) of this
- // plugin. This will be a 0-sized rectangle if the plugin has not yet been
- // laid out.
- gfx::Rect position_;
-
- // Current clip rect. This will be empty if the plugin is not currently
- // visible. This is in the plugin's coordinate system, so fully visible will
- // be (0, 0, w, h) regardless of scroll position.
- gfx::Rect clip_;
-
- // The current device context for painting in 2D or 3D.
- scoped_refptr<Resource> bound_graphics_;
-
- // We track two types of focus, one from WebKit, which is the focus among
- // all elements of the page, one one from the browser, which is whether the
- // tab/window has focus. We tell the plugin it has focus only when both of
- // these values are set to true.
- bool has_webkit_focus_;
- bool has_content_area_focus_;
-
- // The id of the current find operation, or -1 if none is in process.
- int find_identifier_;
-
- // The plugin-provided interfaces.
- const PPP_Find_Dev* plugin_find_interface_;
- const PPP_Private* plugin_private_interface_;
- const PPP_Selection_Dev* plugin_selection_interface_;
- const PPP_Zoom_Dev* plugin_zoom_interface_;
-
- // This is only valid between a successful PrintBegin call and a PrintEnd
- // call.
- PP_PrintSettings_Dev current_print_settings_;
-#if defined(OS_MACOSX)
- // On the Mac, when we draw the bitmap to the PDFContext, it seems necessary
- // to keep the pixels valid until CGContextEndPage is called. We use this
- // variable to hold on to the pixels.
- scoped_refptr<ImageData> last_printed_page_;
-#elif defined(OS_LINUX)
- // On Linux, we always send all pages from the renderer to the browser.
- // So, if the plugin supports printPagesAsPDF we print the entire output
- // in one shot in the first call to PrintPage.
- // (This is a temporary hack until we change the WebFrame and WebPlugin print
- // interfaces).
- // Specifies the total number of pages to be printed. It it set in PrintBegin.
- int32 num_pages_;
- // Specifies whether we have already output all pages. This is used to ignore
- // subsequent PrintPage requests.
- bool pdf_output_done_;
-#endif // defined(OS_LINUX)
-
- // The plugin print interface.
- const PPP_Printing_Dev* plugin_print_interface_;
-
- // The plugin 3D interface.
- const PPP_Graphics3D_Dev* plugin_graphics_3d_interface_;
-
- // Containes the cursor if it's set by the plugin.
- scoped_ptr<WebKit::WebCursorInfo> cursor_;
-
- // Set to true if this plugin thinks it will always be on top. This allows us
- // to use a more optimized painting path in some cases.
- bool always_on_top_;
-
- // Plugin container for fullscreen mode. NULL if not in fullscreen mode.
- FullscreenContainer* fullscreen_container_;
-
- // Non-owning pointers to all active observers.
- ObserverList<Observer, false> observers_;
-
- DISALLOW_COPY_AND_ASSIGN(PluginInstance);
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_PLUGIN_INSTANCE_H_
diff --git a/webkit/glue/plugins/pepper_plugin_module.cc b/webkit/glue/plugins/pepper_plugin_module.cc
deleted file mode 100644
index b7bad9f..0000000
--- a/webkit/glue/plugins/pepper_plugin_module.cc
+++ /dev/null
@@ -1,553 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_plugin_module.h"
-
-#include <set>
-
-#include "base/command_line.h"
-#include "base/message_loop.h"
-#include "base/message_loop_proxy.h"
-#include "base/logging.h"
-#include "base/scoped_ptr.h"
-#include "base/time.h"
-#include "ppapi/c/dev/ppb_buffer_dev.h"
-#include "ppapi/c/dev/ppb_char_set_dev.h"
-#include "ppapi/c/dev/ppb_cursor_control_dev.h"
-#include "ppapi/c/dev/ppb_directory_reader_dev.h"
-#include "ppapi/c/dev/ppb_file_io_dev.h"
-#include "ppapi/c/dev/ppb_file_io_trusted_dev.h"
-#include "ppapi/c/dev/ppb_file_system_dev.h"
-#include "ppapi/c/dev/ppb_find_dev.h"
-#include "ppapi/c/dev/ppb_font_dev.h"
-#include "ppapi/c/dev/ppb_fullscreen_dev.h"
-#include "ppapi/c/dev/ppb_graphics_3d_dev.h"
-#include "ppapi/c/dev/ppb_opengles_dev.h"
-#include "ppapi/c/dev/ppb_scrollbar_dev.h"
-#include "ppapi/c/dev/ppb_testing_dev.h"
-#include "ppapi/c/dev/ppb_transport_dev.h"
-#include "ppapi/c/dev/ppb_url_util_dev.h"
-#include "ppapi/c/dev/ppb_var_deprecated.h"
-#include "ppapi/c/dev/ppb_video_decoder_dev.h"
-#include "ppapi/c/dev/ppb_widget_dev.h"
-#include "ppapi/c/dev/ppb_zoom_dev.h"
-#include "ppapi/c/pp_module.h"
-#include "ppapi/c/pp_resource.h"
-#include "ppapi/c/pp_var.h"
-#include "ppapi/c/ppb_class.h"
-#include "ppapi/c/ppb_core.h"
-#include "ppapi/c/ppb_graphics_2d.h"
-#include "ppapi/c/ppb_image_data.h"
-#include "ppapi/c/ppb_instance.h"
-#include "ppapi/c/ppb_url_loader.h"
-#include "ppapi/c/ppb_url_request_info.h"
-#include "ppapi/c/ppb_url_response_info.h"
-#include "ppapi/c/ppb_var.h"
-#include "ppapi/c/ppp.h"
-#include "ppapi/c/ppp_instance.h"
-#include "ppapi/c/trusted/ppb_image_data_trusted.h"
-#include "ppapi/c/trusted/ppb_url_loader_trusted.h"
-#include "ppapi/proxy/host_dispatcher.h"
-#include "ppapi/proxy/ppapi_messages.h"
-#include "webkit/glue/plugins/pepper_audio.h"
-#include "webkit/glue/plugins/pepper_buffer.h"
-#include "webkit/glue/plugins/pepper_common.h"
-#include "webkit/glue/plugins/pepper_char_set.h"
-#include "webkit/glue/plugins/pepper_class.h"
-#include "webkit/glue/plugins/pepper_cursor_control.h"
-#include "webkit/glue/plugins/pepper_directory_reader.h"
-#include "webkit/glue/plugins/pepper_file_chooser.h"
-#include "webkit/glue/plugins/pepper_file_io.h"
-#include "webkit/glue/plugins/pepper_file_ref.h"
-#include "webkit/glue/plugins/pepper_file_system.h"
-#include "webkit/glue/plugins/pepper_font.h"
-#include "webkit/glue/plugins/pepper_graphics_2d.h"
-#include "webkit/glue/plugins/pepper_image_data.h"
-#include "webkit/glue/plugins/pepper_plugin_instance.h"
-#include "webkit/glue/plugins/pepper_plugin_object.h"
-#include "webkit/glue/plugins/pepper_private.h"
-#include "webkit/glue/plugins/pepper_private2.h"
-#include "webkit/glue/plugins/pepper_resource_tracker.h"
-#include "webkit/glue/plugins/pepper_scrollbar.h"
-#include "webkit/glue/plugins/pepper_transport.h"
-#include "webkit/glue/plugins/pepper_url_loader.h"
-#include "webkit/glue/plugins/pepper_url_request_info.h"
-#include "webkit/glue/plugins/pepper_url_response_info.h"
-#include "webkit/glue/plugins/pepper_url_util.h"
-#include "webkit/glue/plugins/pepper_var.h"
-#include "webkit/glue/plugins/pepper_video_decoder.h"
-#include "webkit/glue/plugins/pepper_widget.h"
-#include "webkit/glue/plugins/ppb_private.h"
-#include "webkit/glue/plugins/ppb_private2.h"
-
-#ifdef ENABLE_GPU
-#include "webkit/glue/plugins/pepper_graphics_3d.h"
-#endif // ENABLE_GPU
-
-#if defined(OS_POSIX)
-#include "ipc/ipc_channel_posix.h"
-#endif
-
-namespace pepper {
-
-namespace {
-
-// Maintains all currently loaded plugin libs for validating PP_Module
-// identifiers.
-typedef std::set<PluginModule*> PluginModuleSet;
-
-PluginModuleSet* GetLivePluginSet() {
- static PluginModuleSet live_plugin_libs;
- return &live_plugin_libs;
-}
-
-base::MessageLoopProxy* GetMainThreadMessageLoop() {
- static scoped_refptr<base::MessageLoopProxy> proxy(
- base::MessageLoopProxy::CreateForCurrentThread());
- return proxy.get();
-}
-
-// PPB_Core --------------------------------------------------------------------
-
-void AddRefResource(PP_Resource resource) {
- if (!ResourceTracker::Get()->AddRefResource(resource)) {
- DLOG(WARNING) << "AddRefResource()ing a nonexistent resource";
- }
-}
-
-void ReleaseResource(PP_Resource resource) {
- if (!ResourceTracker::Get()->UnrefResource(resource)) {
- DLOG(WARNING) << "ReleaseResource()ing a nonexistent resource";
- }
-}
-
-void* MemAlloc(size_t num_bytes) {
- return malloc(num_bytes);
-}
-
-void MemFree(void* ptr) {
- free(ptr);
-}
-
-double GetTime() {
- return base::Time::Now().ToDoubleT();
-}
-
-double GetTickTime() {
- // TODO(brettw) http://code.google.com/p/chromium/issues/detail?id=57448
- // This should be a tick timer rather than wall clock time, but needs to
- // match message times, which also currently use wall clock time.
- return GetTime();
-}
-
-void CallOnMainThread(int delay_in_msec,
- PP_CompletionCallback callback,
- int32_t result) {
- GetMainThreadMessageLoop()->PostDelayedTask(
- FROM_HERE,
- NewRunnableFunction(callback.func, callback.user_data, result),
- delay_in_msec);
-}
-
-PP_Bool IsMainThread() {
- return BoolToPPBool(GetMainThreadMessageLoop()->BelongsToCurrentThread());
-}
-
-const PPB_Core core_interface = {
- &AddRefResource,
- &ReleaseResource,
- &MemAlloc,
- &MemFree,
- &GetTime,
- &GetTickTime,
- &CallOnMainThread,
- &IsMainThread
-};
-
-// PPB_Testing -----------------------------------------------------------------
-
-PP_Bool ReadImageData(PP_Resource device_context_2d,
- PP_Resource image,
- const PP_Point* top_left) {
- scoped_refptr<Graphics2D> context(
- Resource::GetAs<Graphics2D>(device_context_2d));
- if (!context.get())
- return PP_FALSE;
- return BoolToPPBool(context->ReadImageData(image, top_left));
-}
-
-void RunMessageLoop() {
- bool old_state = MessageLoop::current()->NestableTasksAllowed();
- MessageLoop::current()->SetNestableTasksAllowed(true);
- MessageLoop::current()->Run();
- MessageLoop::current()->SetNestableTasksAllowed(old_state);
-}
-
-void QuitMessageLoop() {
- MessageLoop::current()->QuitNow();
-}
-
-uint32_t GetLiveObjectCount(PP_Module module_id) {
- PluginModule* module = ResourceTracker::Get()->GetModule(module_id);
- if (!module)
- return static_cast<uint32_t>(-1);
- return ResourceTracker::Get()->GetLiveObjectsForModule(module);
-}
-
-const PPB_Testing_Dev testing_interface = {
- &ReadImageData,
- &RunMessageLoop,
- &QuitMessageLoop,
- &GetLiveObjectCount
-};
-
-// GetInterface ----------------------------------------------------------------
-
-const void* GetInterface(const char* name) {
- if (strcmp(name, PPB_CORE_INTERFACE) == 0)
- return &core_interface;
- if (strcmp(name, PPB_VAR_DEPRECATED_INTERFACE) == 0)
- return Var::GetDeprecatedInterface();
- if (strcmp(name, PPB_VAR_INTERFACE) == 0)
- return Var::GetInterface();
- if (strcmp(name, PPB_INSTANCE_INTERFACE) == 0)
- return PluginInstance::GetInterface();
- if (strcmp(name, PPB_IMAGEDATA_INTERFACE) == 0)
- return ImageData::GetInterface();
- if (strcmp(name, PPB_IMAGEDATA_TRUSTED_INTERFACE) == 0)
- return ImageData::GetTrustedInterface();
- if (strcmp(name, PPB_AUDIO_CONFIG_DEV_INTERFACE) == 0)
- return AudioConfig::GetInterface();
- if (strcmp(name, PPB_AUDIO_DEV_INTERFACE) == 0)
- return Audio::GetInterface();
- if (strcmp(name, PPB_AUDIO_TRUSTED_DEV_INTERFACE) == 0)
- return Audio::GetTrustedInterface();
- if (strcmp(name, PPB_GRAPHICS_2D_INTERFACE) == 0)
- return Graphics2D::GetInterface();
-#ifdef ENABLE_GPU
- if (strcmp(name, PPB_GRAPHICS_3D_DEV_INTERFACE) == 0)
- return Graphics3D::GetInterface();
- if (strcmp(name, PPB_OPENGLES_DEV_INTERFACE) == 0)
- return Graphics3D::GetOpenGLESInterface();
-#endif // ENABLE_GPU
- if (strcmp(name, PPB_TRANSPORT_DEV_INTERFACE) == 0)
- return Transport::GetInterface();
- if (strcmp(name, PPB_URLLOADER_INTERFACE) == 0)
- return URLLoader::GetInterface();
- if (strcmp(name, PPB_URLLOADERTRUSTED_INTERFACE) == 0)
- return URLLoader::GetTrustedInterface();
- if (strcmp(name, PPB_URLREQUESTINFO_INTERFACE) == 0)
- return URLRequestInfo::GetInterface();
- if (strcmp(name, PPB_URLRESPONSEINFO_INTERFACE) == 0)
- return URLResponseInfo::GetInterface();
- if (strcmp(name, PPB_BUFFER_DEV_INTERFACE) == 0)
- return Buffer::GetInterface();
- if (strcmp(name, PPB_FILEREF_DEV_INTERFACE) == 0)
- return FileRef::GetInterface();
- if (strcmp(name, PPB_FILEIO_DEV_INTERFACE) == 0)
- return FileIO::GetInterface();
- if (strcmp(name, PPB_FILEIOTRUSTED_DEV_INTERFACE) == 0)
- return FileIO::GetTrustedInterface();
- if (strcmp(name, PPB_FILESYSTEM_DEV_INTERFACE) == 0)
- return FileSystem::GetInterface();
- if (strcmp(name, PPB_DIRECTORYREADER_DEV_INTERFACE) == 0)
- return DirectoryReader::GetInterface();
- if (strcmp(name, PPB_WIDGET_DEV_INTERFACE) == 0)
- return Widget::GetInterface();
- if (strcmp(name, PPB_SCROLLBAR_DEV_INTERFACE) == 0)
- return Scrollbar::GetInterface();
- if (strcmp(name, PPB_FONT_DEV_INTERFACE) == 0)
- return Font::GetInterface();
- if (strcmp(name, PPB_FIND_DEV_INTERFACE) == 0)
- return PluginInstance::GetFindInterface();
- if (strcmp(name, PPB_FULLSCREEN_DEV_INTERFACE) == 0)
- return PluginInstance::GetFullscreenInterface();
- if (strcmp(name, PPB_URLUTIL_DEV_INTERFACE) == 0)
- return UrlUtil::GetInterface();
- if (strcmp(name, PPB_PRIVATE_INTERFACE) == 0)
- return Private::GetInterface();
- if (strcmp(name, PPB_PRIVATE2_INTERFACE) == 0)
- return Private2::GetInterface();
- if (strcmp(name, PPB_FILECHOOSER_DEV_INTERFACE) == 0)
- return FileChooser::GetInterface();
- if (strcmp(name, PPB_VIDEODECODER_DEV_INTERFACE) == 0)
- return VideoDecoder::GetInterface();
- if (strcmp(name, PPB_CHAR_SET_DEV_INTERFACE) == 0)
- return CharSet::GetInterface();
- if (strcmp(name, PPB_CURSOR_CONTROL_DEV_INTERFACE) == 0)
- return GetCursorControlInterface();
- if (strcmp(name, PPB_ZOOM_DEV_INTERFACE) == 0)
- return PluginInstance::GetZoomInterface();
- if (strcmp(name, PPB_CLASS_INTERFACE) == 0)
- return VarObjectClass::GetInterface();
-
- // Only support the testing interface when the command line switch is
- // specified. This allows us to prevent people from (ab)using this interface
- // in production code.
- if (strcmp(name, PPB_TESTING_DEV_INTERFACE) == 0) {
- if (CommandLine::ForCurrentProcess()->HasSwitch("enable-pepper-testing"))
- return &testing_interface;
- }
- return NULL;
-}
-
-} // namespace
-
-PluginModule::PluginModule()
- : initialized_(false),
- library_(NULL) {
- pp_module_ = ResourceTracker::Get()->AddModule(this);
- GetMainThreadMessageLoop(); // Initialize the main thread message loop.
- GetLivePluginSet()->insert(this);
-}
-
-PluginModule::~PluginModule() {
- // Free all the plugin objects. This will automatically clear the back-
- // pointer from the NPObject so WebKit can't call into the plugin any more.
- //
- // Swap out the set so we can delete from it (the objects will try to
- // unregister themselves inside the delete call).
- PluginObjectSet plugin_object_copy;
- live_plugin_objects_.swap(plugin_object_copy);
- for (PluginObjectSet::iterator i = live_plugin_objects_.begin();
- i != live_plugin_objects_.end(); ++i)
- delete *i;
-
- // When the module is being deleted, there should be no more instances still
- // holding a reference to us.
- DCHECK(instances_.empty());
-
- GetLivePluginSet()->erase(this);
-
- if (entry_points_.shutdown_module)
- entry_points_.shutdown_module();
-
- if (library_)
- base::UnloadNativeLibrary(library_);
-
- ResourceTracker::Get()->ModuleDeleted(pp_module_);
-}
-
-// static
-scoped_refptr<PluginModule> PluginModule::CreateModule(
- const FilePath& path) {
- // FIXME(brettw) do uniquifying of the plugin here like the NPAPI one.
-
- scoped_refptr<PluginModule> lib(new PluginModule());
- if (!lib->InitFromFile(path))
- return NULL;
-
- return lib;
-}
-
-// static
-scoped_refptr<PluginModule> PluginModule::CreateInternalModule(
- EntryPoints entry_points) {
- scoped_refptr<PluginModule> lib(new PluginModule());
- if (!lib->InitFromEntryPoints(entry_points))
- return NULL;
-
- return lib;
-}
-
-// static
-scoped_refptr<PluginModule> PluginModule::CreateOutOfProcessModule(
- MessageLoop* ipc_message_loop,
- const IPC::ChannelHandle& handle,
- base::WaitableEvent* shutdown_event) {
- scoped_refptr<PluginModule> lib(new PluginModule);
- if (!lib->InitForOutOfProcess(ipc_message_loop, handle, shutdown_event))
- return NULL;
- return lib;
-}
-
-// static
-const PPB_Core* PluginModule::GetCore() {
- return &core_interface;
-}
-
-bool PluginModule::InitFromEntryPoints(const EntryPoints& entry_points) {
- if (initialized_)
- return true;
-
- // Attempt to run the initialization funciton.
- int retval = entry_points.initialize_module(pp_module(), &GetInterface);
- if (retval != 0) {
- LOG(WARNING) << "PPP_InitializeModule returned failure " << retval;
- return false;
- }
-
- entry_points_ = entry_points;
- initialized_ = true;
- return true;
-}
-
-bool PluginModule::InitFromFile(const FilePath& path) {
- if (initialized_)
- return true;
-
- base::NativeLibrary library = base::LoadNativeLibrary(path);
- if (!library)
- return false;
-
- EntryPoints entry_points;
- if (!LoadEntryPoints(library, &entry_points) ||
- !InitFromEntryPoints(entry_points)) {
- base::UnloadNativeLibrary(library);
- return false;
- }
-
- // We let InitFromEntryPoints() handle setting the all the internal state
- // of the object other than the |library_| reference.
- library_ = library;
- return true;
-}
-
-bool PluginModule::InitForOutOfProcess(MessageLoop* ipc_message_loop,
- const IPC::ChannelHandle& handle,
- base::WaitableEvent* shutdown_event) {
- const PPB_Var_Deprecated* var_interface =
- reinterpret_cast<const PPB_Var_Deprecated*>(
- GetInterface(PPB_VAR_DEPRECATED_INTERFACE));
- dispatcher_.reset(new pp::proxy::HostDispatcher(var_interface,
- pp_module(), &GetInterface));
-
-#if defined(OS_POSIX)
- // If we received a ChannelHandle, register it now.
- if (handle.socket.fd >= 0)
- IPC::AddChannelSocket(handle.name, handle.socket.fd);
-#endif
-
- if (!dispatcher_->InitWithChannel(ipc_message_loop, handle.name, true,
- shutdown_event)) {
- dispatcher_.reset();
- return false;
- }
-
- bool init_result = false;
- dispatcher_->Send(new PpapiMsg_InitializeModule(pp_module(), &init_result));
-
- if (!init_result) {
- // TODO(brettw) does the module get unloaded in this case?
- dispatcher_.reset();
- return false;
- }
- return true;
-}
-
-// static
-bool PluginModule::LoadEntryPoints(const base::NativeLibrary& library,
- EntryPoints* entry_points) {
- entry_points->get_interface =
- reinterpret_cast<PPP_GetInterfaceFunc>(
- base::GetFunctionPointerFromNativeLibrary(library,
- "PPP_GetInterface"));
- if (!entry_points->get_interface) {
- LOG(WARNING) << "No PPP_GetInterface in plugin library";
- return false;
- }
-
- entry_points->initialize_module =
- reinterpret_cast<PPP_InitializeModuleFunc>(
- base::GetFunctionPointerFromNativeLibrary(library,
- "PPP_InitializeModule"));
- if (!entry_points->initialize_module) {
- LOG(WARNING) << "No PPP_InitializeModule in plugin library";
- return false;
- }
-
- // It's okay for PPP_ShutdownModule to not be defined and shutdown_module to
- // be NULL.
- entry_points->shutdown_module =
- reinterpret_cast<PPP_ShutdownModuleFunc>(
- base::GetFunctionPointerFromNativeLibrary(library,
- "PPP_ShutdownModule"));
-
- return true;
-}
-
-PluginInstance* PluginModule::CreateInstance(PluginDelegate* delegate) {
- const PPP_Instance* plugin_instance_interface =
- reinterpret_cast<const PPP_Instance*>(GetPluginInterface(
- PPP_INSTANCE_INTERFACE));
- if (!plugin_instance_interface) {
- LOG(WARNING) << "Plugin doesn't support instance interface, failing.";
- return NULL;
- }
- PluginInstance* instance = new PluginInstance(delegate, this,
- plugin_instance_interface);
- if (dispatcher_.get()) {
- pp::proxy::HostDispatcher::SetForInstance(instance->pp_instance(),
- dispatcher_.get());
- }
- return instance;
-}
-
-PluginInstance* PluginModule::GetSomeInstance() const {
- // This will generally crash later if there is not actually any instance to
- // return, so we force a crash now to make bugs easier to track down.
- CHECK(!instances_.empty());
- return *instances_.begin();
-}
-
-const void* PluginModule::GetPluginInterface(const char* name) const {
- if (dispatcher_.get())
- return dispatcher_->GetProxiedInterface(name);
-
- // In-process plugins.
- if (!entry_points_.get_interface)
- return NULL;
- return entry_points_.get_interface(name);
-}
-
-void PluginModule::InstanceCreated(PluginInstance* instance) {
- instances_.insert(instance);
-}
-
-void PluginModule::InstanceDeleted(PluginInstance* instance) {
- pp::proxy::HostDispatcher::RemoveForInstance(instance->pp_instance());
- instances_.erase(instance);
-}
-
-void PluginModule::AddNPObjectVar(ObjectVar* object_var) {
- DCHECK(np_object_to_object_var_.find(object_var->np_object()) ==
- np_object_to_object_var_.end()) << "ObjectVar already in map";
- np_object_to_object_var_[object_var->np_object()] = object_var;
-}
-
-void PluginModule::RemoveNPObjectVar(ObjectVar* object_var) {
- NPObjectToObjectVarMap::iterator found =
- np_object_to_object_var_.find(object_var->np_object());
- if (found == np_object_to_object_var_.end()) {
- NOTREACHED() << "ObjectVar not registered.";
- return;
- }
- if (found->second != object_var) {
- NOTREACHED() << "ObjectVar doesn't match.";
- return;
- }
- np_object_to_object_var_.erase(found);
-}
-
-ObjectVar* PluginModule::ObjectVarForNPObject(NPObject* np_object) const {
- NPObjectToObjectVarMap::const_iterator found =
- np_object_to_object_var_.find(np_object);
- if (found == np_object_to_object_var_.end())
- return NULL;
- return found->second;
-}
-
-void PluginModule::AddPluginObject(PluginObject* plugin_object) {
- DCHECK(live_plugin_objects_.find(plugin_object) ==
- live_plugin_objects_.end());
- live_plugin_objects_.insert(plugin_object);
-}
-
-void PluginModule::RemovePluginObject(PluginObject* plugin_object) {
- // Don't actually verify that the object is in the set since during module
- // deletion we'll be in the process of freeing them.
- live_plugin_objects_.erase(plugin_object);
-}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_plugin_module.h b/webkit/glue/plugins/pepper_plugin_module.h
deleted file mode 100644
index 80eccda..0000000
--- a/webkit/glue/plugins/pepper_plugin_module.h
+++ /dev/null
@@ -1,169 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_PLUGIN_MODULE_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_PLUGIN_MODULE_H_
-
-#include <map>
-#include <set>
-
-#include "base/basictypes.h"
-#include "base/native_library.h"
-#include "base/ref_counted.h"
-#include "base/scoped_ptr.h"
-#include "base/weak_ptr.h"
-#include "ppapi/c/pp_module.h"
-#include "ppapi/c/ppb.h"
-
-class FilePath;
-class MessageLoop;
-typedef struct NPObject NPObject;
-struct PPB_Core;
-typedef void* NPIdentifier;
-
-namespace base {
-class WaitableEvent;
-}
-
-namespace pp {
-namespace proxy {
-class HostDispatcher;
-} // proxy
-} // pp
-
-namespace IPC {
-struct ChannelHandle;
-}
-
-namespace pepper {
-
-class ObjectVar;
-class PluginDelegate;
-class PluginInstance;
-class PluginObject;
-
-// Represents one plugin library loaded into one renderer. This library may
-// have multiple instances.
-//
-// Note: to get from a PP_Instance to a PluginInstance*, use the
-// ResourceTracker.
-class PluginModule : public base::RefCounted<PluginModule>,
- public base::SupportsWeakPtr<PluginModule> {
- public:
- typedef const void* (*PPP_GetInterfaceFunc)(const char*);
- typedef int (*PPP_InitializeModuleFunc)(PP_Module, PPB_GetInterface);
- typedef void (*PPP_ShutdownModuleFunc)();
-
- struct EntryPoints {
- EntryPoints()
- : get_interface(NULL),
- initialize_module(NULL),
- shutdown_module(NULL) {
- }
-
- PPP_GetInterfaceFunc get_interface;
- PPP_InitializeModuleFunc initialize_module;
- PPP_ShutdownModuleFunc shutdown_module;
- };
-
- ~PluginModule();
-
- static scoped_refptr<PluginModule> CreateModule(const FilePath& path);
- static scoped_refptr<PluginModule> CreateInternalModule(
- EntryPoints entry_points);
- static scoped_refptr<PluginModule> CreateOutOfProcessModule(
- MessageLoop* ipc_message_loop,
- const IPC::ChannelHandle& handle,
- base::WaitableEvent* shutdown_event);
-
- static const PPB_Core* GetCore();
-
- PP_Module pp_module() const { return pp_module_; }
-
- void set_name(const std::string& name) { name_ = name; }
- const std::string& name() const { return name_; }
-
- PluginInstance* CreateInstance(PluginDelegate* delegate);
-
- // Returns "some" plugin instance associated with this module. This is not
- // guaranteed to be any one in particular. This is normally used to execute
- // callbacks up to the browser layer that are not inherently per-instance,
- // but the delegate lives only on the plugin instance so we need one of them.
- PluginInstance* GetSomeInstance() const;
-
- const void* GetPluginInterface(const char* name) const;
-
- // This module is associated with a set of instances. The PluginInstance
- // object declares its association with this module in its destructor and
- // releases us in its destructor.
- void InstanceCreated(PluginInstance* instance);
- void InstanceDeleted(PluginInstance* instance);
-
- // Tracks all live ObjectVar. This is so we can map between PluginModule +
- // NPObject and get the ObjectVar corresponding to it. This Add/Remove
- // function should be called by the ObjectVar when it is created and
- // destroyed.
- void AddNPObjectVar(ObjectVar* object_var);
- void RemoveNPObjectVar(ObjectVar* object_var);
-
- // Looks up a previously registered ObjectVar for the given NPObject and
- // module. Returns NULL if there is no ObjectVar corresponding to the given
- // NPObject for the given module. See AddNPObjectVar above.
- ObjectVar* ObjectVarForNPObject(NPObject* np_object) const;
-
- // Tracks all live PluginObjects.
- void AddPluginObject(PluginObject* plugin_object);
- void RemovePluginObject(PluginObject* plugin_object);
-
- private:
- PluginModule();
-
- bool InitFromEntryPoints(const EntryPoints& entry_points);
- bool InitFromFile(const FilePath& path);
- bool InitForOutOfProcess(MessageLoop* ipc_message_loop,
- const IPC::ChannelHandle& handle,
- base::WaitableEvent* shutdown_event);
- static bool LoadEntryPoints(const base::NativeLibrary& library,
- EntryPoints* entry_points);
-
- // Dispatcher for out-of-process plugins. This will be null when the plugin
- // is being run in-process.
- scoped_ptr<pp::proxy::HostDispatcher> dispatcher_;
-
- PP_Module pp_module_;
-
- bool initialized_;
-
- // Holds a reference to the base::NativeLibrary handle if this PluginModule
- // instance wraps functions loaded from a library. Can be NULL. If
- // |library_| is non-NULL, PluginModule will attempt to unload the library
- // during destruction.
- base::NativeLibrary library_;
-
- // Contains pointers to the entry points of the actual plugin
- // implementation. These will be NULL for out-of-process plugins.
- EntryPoints entry_points_;
-
- // The name of the module.
- std::string name_;
-
- // Non-owning pointers to all instances associated with this module. When
- // there are no more instances, this object should be deleted.
- typedef std::set<PluginInstance*> PluginInstanceSet;
- PluginInstanceSet instances_;
-
- // Tracks all live ObjectVars used by this module so we can map NPObjects to
- // the corresponding object. These are non-owning references.
- typedef std::map<NPObject*, ObjectVar*> NPObjectToObjectVarMap;;
- NPObjectToObjectVarMap np_object_to_object_var_;
-
- typedef std::set<PluginObject*> PluginObjectSet;
- PluginObjectSet live_plugin_objects_;
-
- DISALLOW_COPY_AND_ASSIGN(PluginModule);
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_PLUGIN_MODULE_H_
diff --git a/webkit/glue/plugins/pepper_plugin_object.cc b/webkit/glue/plugins/pepper_plugin_object.cc
deleted file mode 100644
index 2705809..0000000
--- a/webkit/glue/plugins/pepper_plugin_object.cc
+++ /dev/null
@@ -1,887 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_plugin_object.h"
-
-#include "base/logging.h"
-#include "base/ref_counted.h"
-#include "base/scoped_ptr.h"
-#include "base/string_number_conversions.h"
-#include "base/string_util.h"
-#include "third_party/npapi/bindings/npapi.h"
-#include "third_party/npapi/bindings/npruntime.h"
-#include "ppapi/c/dev/ppb_var_deprecated.h"
-#include "ppapi/c/dev/ppp_class_deprecated.h"
-#include "ppapi/c/pp_resource.h"
-#include "ppapi/c/pp_var.h"
-#include "ppapi/c/ppb_class.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebBindings.h"
-#include "webkit/glue/plugins/pepper_class.h"
-#include "webkit/glue/plugins/pepper_plugin_module.h"
-#include "webkit/glue/plugins/pepper_resource.h"
-#include "webkit/glue/plugins/pepper_string.h"
-#include "webkit/glue/plugins/pepper_var.h"
-
-using WebKit::WebBindings;
-
-namespace pepper {
-
-namespace {
-
-const char kInvalidValueException[] = "Error: Invalid value";
-const char kInvalidPluginValue[] = "Error: Plugin returned invalid value.";
-
-// -----------------------------------------------------------------------------
-// Utilities
-
-// Converts the given PP_Var to an NPVariant, returning true on success.
-// False means that the given variant is invalid. In this case, the result
-// NPVariant will be set to a void one.
-//
-// The contents of the PP_Var will be copied unless the PP_Var corresponds to
-// an object.
-bool PPVarToNPVariant(PP_Var var, NPVariant* result) {
- switch (var.type) {
- case PP_VARTYPE_UNDEFINED:
- VOID_TO_NPVARIANT(*result);
- break;
- case PP_VARTYPE_NULL:
- NULL_TO_NPVARIANT(*result);
- break;
- case PP_VARTYPE_BOOL:
- BOOLEAN_TO_NPVARIANT(var.value.as_bool, *result);
- break;
- case PP_VARTYPE_INT32:
- INT32_TO_NPVARIANT(var.value.as_int, *result);
- break;
- case PP_VARTYPE_DOUBLE:
- DOUBLE_TO_NPVARIANT(var.value.as_double, *result);
- break;
- case PP_VARTYPE_STRING: {
- scoped_refptr<StringVar> string(StringVar::FromPPVar(var));
- if (!string) {
- VOID_TO_NPVARIANT(*result);
- return false;
- }
- const std::string& value = string->value();
- STRINGN_TO_NPVARIANT(base::strdup(value.c_str()), value.size(), *result);
- break;
- }
- case PP_VARTYPE_OBJECT: {
- scoped_refptr<ObjectVar> object(ObjectVar::FromPPVar(var));
- if (!object) {
- VOID_TO_NPVARIANT(*result);
- return false;
- }
- OBJECT_TO_NPVARIANT(WebBindings::retainObject(object->np_object()),
- *result);
- break;
- }
- }
- return true;
-}
-
-// PPVarArrayFromNPVariantArray ------------------------------------------------
-
-// Converts an array of NPVariants to an array of PP_Var, and scopes the
-// ownership of the PP_Var. This is used when converting argument lists from
-// WebKit to the plugin.
-class PPVarArrayFromNPVariantArray {
- public:
- PPVarArrayFromNPVariantArray(PluginModule* module,
- size_t size,
- const NPVariant* variants)
- : size_(size) {
- if (size_ > 0) {
- array_.reset(new PP_Var[size_]);
- for (size_t i = 0; i < size_; i++)
- array_[i] = Var::NPVariantToPPVar(module, &variants[i]);
- }
- }
-
- ~PPVarArrayFromNPVariantArray() {
- for (size_t i = 0; i < size_; i++)
- Var::PluginReleasePPVar(array_[i]);
- }
-
- PP_Var* array() { return array_.get(); }
-
- private:
- size_t size_;
- scoped_array<PP_Var> array_;
-
- DISALLOW_COPY_AND_ASSIGN(PPVarArrayFromNPVariantArray);
-};
-
-// PPVarFromNPObject -----------------------------------------------------------
-
-// Converts an NPObject tp PP_Var, and scopes the ownership of the PP_Var. This
-// is used when converting 'this' pointer from WebKit to the plugin.
-class PPVarFromNPObject {
- public:
- PPVarFromNPObject(PluginModule* module, NPObject* object)
- : var_(ObjectVar::NPObjectToPPVar(module, object)) {
- }
- ~PPVarFromNPObject() {
- Var::PluginReleasePPVar(var_);
- }
- PP_Var var() const { return var_; }
- private:
- const PP_Var var_;
-
- DISALLOW_COPY_AND_ASSIGN(PPVarFromNPObject);
-};
-
-// PPResultAndExceptionToNPResult ----------------------------------------------
-
-// Convenience object for converting a PPAPI call that can throw an exception
-// and optionally return a value, back to the NPAPI layer which expects a
-// NPVariant as a result.
-//
-// Normal usage is that you will pass the result of exception() to the
-// PPAPI function as the exception output parameter. Then you will either
-// call SetResult with the result of the PPAPI call, or
-// CheckExceptionForNoResult if the PPAPI call doesn't return a PP_Var.
-//
-// Both SetResult and CheckExceptionForNoResult will throw an exception to
-// the JavaScript library if the plugin reported an exception. SetResult
-// will additionally convert the result to an NPVariant and write it to the
-// output parameter given in the constructor.
-class PPResultAndExceptionToNPResult {
- public:
- // The object_var parameter is the object to associate any exception with.
- // It may not be NULL.
- //
- // The np_result parameter is the NPAPI result output parameter. This may be
- // NULL if there is no NPVariant result (like for HasProperty). If this is
- // specified, you must call SetResult() to set it. If it is not, you must
- // call CheckExceptionForNoResult to do the exception checking with no result
- // conversion.
- PPResultAndExceptionToNPResult(NPObject* object_var,
- NPVariant* np_result)
- : object_var_(object_var),
- np_result_(np_result),
- exception_(PP_MakeUndefined()),
- success_(false),
- checked_exception_(false) {
- }
-
- ~PPResultAndExceptionToNPResult() {
- // The user should have called SetResult or CheckExceptionForNoResult
- // before letting this class go out of scope, or the exception will have
- // been lost.
- DCHECK(checked_exception_);
-
- ObjectVar::PluginReleasePPVar(exception_);
- }
-
- // Returns true if an exception has been set.
- bool has_exception() const { return exception_.type != PP_VARTYPE_UNDEFINED; }
-
- // Returns a pointer to the exception. You would pass this to the PPAPI
- // function as the exception parameter. If it is set to non-void, this object
- // will take ownership of destroying it.
- PP_Var* exception() { return &exception_; }
-
- // Returns true if everything succeeded with no exception. This is valid only
- // after calling SetResult/CheckExceptionForNoResult.
- bool success() const {
- DCHECK(checked_exception_);
- return success_;
- }
-
- // Call this with the return value of the PPAPI function. It will convert
- // the result to the NPVariant output parameter and pass any exception on to
- // the JS engine. It will update the success flag and return it.
- bool SetResult(PP_Var result) {
- DCHECK(!checked_exception_); // Don't call more than once.
- DCHECK(np_result_); // Should be expecting a result.
-
- checked_exception_ = true;
-
- if (has_exception()) {
- ThrowException();
- success_ = false;
- } else if (!PPVarToNPVariant(result, np_result_)) {
- WebBindings::setException(object_var_, kInvalidPluginValue);
- success_ = false;
- } else {
- success_ = true;
- }
-
- // No matter what happened, we need to release the reference to the
- // value passed in. On success, a reference to this value will be in
- // the np_result_.
- Var::PluginReleasePPVar(result);
- return success_;
- }
-
- // Call this after calling a PPAPI function that could have set the
- // exception. It will pass the exception on to the JS engine and update
- // the success flag.
- //
- // The success flag will be returned.
- bool CheckExceptionForNoResult() {
- DCHECK(!checked_exception_); // Don't call more than once.
- DCHECK(!np_result_); // Can't have a result when doing this.
-
- checked_exception_ = true;
-
- if (has_exception()) {
- ThrowException();
- success_ = false;
- return false;
- }
- success_ = true;
- return true;
- }
-
- // Call this to ignore any exception. This prevents the DCHECK from failing
- // in the destructor.
- void IgnoreException() {
- checked_exception_ = true;
- }
-
- private:
- // Throws the current exception to JS. The exception must be set.
- void ThrowException() {
- scoped_refptr<StringVar> string(StringVar::FromPPVar(exception_));
- if (string) {
- WebBindings::setException(object_var_, string->value().c_str());
- }
- }
-
- NPObject* object_var_; // Non-owning ref (see constructor).
- NPVariant* np_result_; // Output value, possibly NULL (see constructor).
- PP_Var exception_; // Exception set by the PPAPI call. We own a ref to it.
- bool success_; // See the success() function above.
- bool checked_exception_; // SetResult/CheckExceptionForNoResult was called.
-
- DISALLOW_COPY_AND_ASSIGN(PPResultAndExceptionToNPResult);
-};
-
-// NPObjectAccessorWithIdentifier ----------------------------------------------
-
-// Helper class for our NPObject wrapper. This converts a call from WebKit
-// where it gives us an NPObject and an NPIdentifier to an easily-accessible
-// ObjectVar (corresponding to the NPObject) and PP_Var (corresponding to the
-// NPIdentifier).
-//
-// If the NPObject or identifier is invalid, we'll set is_valid() to false.
-// The caller should check is_valid() before doing anything with the class.
-//
-// JS can't have integer functions, so when dealing with these, we don't want
-// to allow integer identifiers. The calling code can decode if it wants to
-// allow integer identifiers (like for property access) or prohibit them
-// (like for method calling) by setting |allow_integer_identifier|. If this
-// is false and the identifier is an integer, we'll set is_valid() to false.
-//
-// Getting an integer identifier in this case should be impossible. V8
-// shouldn't be allowing this, and the Pepper Var calls from the plugin are
-// supposed to error out before calling into V8 (which will then call us back).
-// Aside from an egregious error, the only time this could happen is an NPAPI
-// plugin calling us.
-class NPObjectAccessorWithIdentifier {
- public:
- NPObjectAccessorWithIdentifier(NPObject* object,
- NPIdentifier identifier,
- bool allow_integer_identifier)
- : object_(PluginObject::FromNPObject(object)),
- identifier_(PP_MakeUndefined()) {
- if (object_) {
- identifier_ = Var::NPIdentifierToPPVar(object_->module(), identifier);
- if (identifier_.type == PP_VARTYPE_INT32 && !allow_integer_identifier)
- identifier_.type = PP_VARTYPE_UNDEFINED; // Mark it invalid.
- }
- }
-
- ~NPObjectAccessorWithIdentifier() {
- Var::PluginReleasePPVar(identifier_);
- }
-
- // Returns true if both the object and identifier are valid.
- bool is_valid() const {
- return object_ && identifier_.type != PP_VARTYPE_UNDEFINED;
- }
-
- PluginObject* object() { return object_; }
- PP_Var identifier() const { return identifier_; }
-
- private:
- PluginObject* object_;
- PP_Var identifier_;
-
- DISALLOW_COPY_AND_ASSIGN(NPObjectAccessorWithIdentifier);
-};
-
-// NPObject implementation in terms of PPP_Class_Deprecated --------------------
-
-NPObject* WrapperClass_Allocate(NPP npp, NPClass* unused) {
- return PluginObject::AllocateObjectWrapper();
-}
-
-void WrapperClass_Deallocate(NPObject* np_object) {
- PluginObject* plugin_object = PluginObject::FromNPObject(np_object);
- if (!plugin_object)
- return;
- plugin_object->ppp_class()->Deallocate(plugin_object->ppp_class_data());
- delete plugin_object;
-}
-
-void WrapperClass_Invalidate(NPObject* object) {
-}
-
-bool WrapperClass_HasMethod(NPObject* object, NPIdentifier method_name) {
- NPObjectAccessorWithIdentifier accessor(object, method_name, false);
- if (!accessor.is_valid())
- return false;
-
- PPResultAndExceptionToNPResult result_converter(
- accessor.object()->GetNPObject(), NULL);
- bool rv = accessor.object()->ppp_class()->HasMethod(
- accessor.object()->ppp_class_data(), accessor.identifier(),
- result_converter.exception());
- result_converter.CheckExceptionForNoResult();
- return rv;
-}
-
-bool WrapperClass_Invoke(NPObject* object, NPIdentifier method_name,
- const NPVariant* argv, uint32_t argc,
- NPVariant* result) {
- NPObjectAccessorWithIdentifier accessor(object, method_name, false);
- if (!accessor.is_valid())
- return false;
-
- PPResultAndExceptionToNPResult result_converter(
- accessor.object()->GetNPObject(), result);
- PPVarArrayFromNPVariantArray args(accessor.object()->module(), argc, argv);
-
- return result_converter.SetResult(accessor.object()->ppp_class()->Call(
- accessor.object()->ppp_class_data(), accessor.identifier(),
- argc, args.array(), result_converter.exception()));
-}
-
-bool WrapperClass_InvokeDefault(NPObject* np_object, const NPVariant* argv,
- uint32_t argc, NPVariant* result) {
- PluginObject* obj = PluginObject::FromNPObject(np_object);
- if (!obj)
- return false;
-
- PPVarArrayFromNPVariantArray args(obj->module(), argc, argv);
- PPResultAndExceptionToNPResult result_converter(obj->GetNPObject(), result);
-
- result_converter.SetResult(obj->ppp_class()->Call(
- obj->ppp_class_data(), PP_MakeUndefined(), argc, args.array(),
- result_converter.exception()));
- return result_converter.success();
-}
-
-bool WrapperClass_HasProperty(NPObject* object, NPIdentifier property_name) {
- NPObjectAccessorWithIdentifier accessor(object, property_name, true);
- if (!accessor.is_valid())
- return false;
-
- PPResultAndExceptionToNPResult result_converter(
- accessor.object()->GetNPObject(), NULL);
- bool rv = accessor.object()->ppp_class()->HasProperty(
- accessor.object()->ppp_class_data(), accessor.identifier(),
- result_converter.exception());
- result_converter.CheckExceptionForNoResult();
- return rv;
-}
-
-bool WrapperClass_GetProperty(NPObject* object, NPIdentifier property_name,
- NPVariant* result) {
- NPObjectAccessorWithIdentifier accessor(object, property_name, true);
- if (!accessor.is_valid())
- return false;
-
- PPResultAndExceptionToNPResult result_converter(
- accessor.object()->GetNPObject(), result);
- return result_converter.SetResult(accessor.object()->ppp_class()->GetProperty(
- accessor.object()->ppp_class_data(), accessor.identifier(),
- result_converter.exception()));
-}
-
-bool WrapperClass_SetProperty(NPObject* object, NPIdentifier property_name,
- const NPVariant* value) {
- NPObjectAccessorWithIdentifier accessor(object, property_name, true);
- if (!accessor.is_valid())
- return false;
-
- PPResultAndExceptionToNPResult result_converter(
- accessor.object()->GetNPObject(), NULL);
- PP_Var value_var = Var::NPVariantToPPVar(accessor.object()->module(), value);
- accessor.object()->ppp_class()->SetProperty(
- accessor.object()->ppp_class_data(), accessor.identifier(), value_var,
- result_converter.exception());
- Var::PluginReleasePPVar(value_var);
- return result_converter.CheckExceptionForNoResult();
-}
-
-bool WrapperClass_RemoveProperty(NPObject* object, NPIdentifier property_name) {
- NPObjectAccessorWithIdentifier accessor(object, property_name, true);
- if (!accessor.is_valid())
- return false;
-
- PPResultAndExceptionToNPResult result_converter(
- accessor.object()->GetNPObject(), NULL);
- accessor.object()->ppp_class()->RemoveProperty(
- accessor.object()->ppp_class_data(), accessor.identifier(),
- result_converter.exception());
- return result_converter.CheckExceptionForNoResult();
-}
-
-bool WrapperClass_Enumerate(NPObject* object, NPIdentifier** values,
- uint32_t* count) {
- *values = NULL;
- *count = 0;
- PluginObject* obj = PluginObject::FromNPObject(object);
- if (!obj)
- return false;
-
- uint32_t property_count = 0;
- PP_Var* properties = NULL; // Must be freed!
- PPResultAndExceptionToNPResult result_converter(obj->GetNPObject(), NULL);
- obj->ppp_class()->GetAllPropertyNames(obj->ppp_class_data(),
- &property_count, &properties,
- result_converter.exception());
-
- // Convert the array of PP_Var to an array of NPIdentifiers. If any
- // conversions fail, we will set the exception.
- if (!result_converter.has_exception()) {
- if (property_count > 0) {
- *values = static_cast<NPIdentifier*>(
- malloc(sizeof(NPIdentifier) * property_count));
- *count = 0; // Will be the number of items successfully converted.
- for (uint32_t i = 0; i < property_count; ++i) {
- if (!((*values)[i] = Var::PPVarToNPIdentifier(properties[i]))) {
- // Throw an exception for the failed convertion.
- *result_converter.exception() = StringVar::StringToPPVar(
- obj->module(), kInvalidValueException);
- break;
- }
- (*count)++;
- }
-
- if (result_converter.has_exception()) {
- // We don't actually have to free the identifiers we converted since
- // all identifiers leak anyway :( .
- free(*values);
- *values = NULL;
- *count = 0;
- }
- }
- }
-
- // This will actually throw the exception, either from GetAllPropertyNames,
- // or if anything was set during the conversion process.
- result_converter.CheckExceptionForNoResult();
-
- // Release the PP_Var that the plugin allocated. On success, they will all
- // be converted to NPVariants, and on failure, we want them to just go away.
- for (uint32_t i = 0; i < property_count; ++i)
- Var::PluginReleasePPVar(properties[i]);
- free(properties);
- return result_converter.success();
-}
-
-bool WrapperClass_Construct(NPObject* object, const NPVariant* argv,
- uint32_t argc, NPVariant* result) {
- PluginObject* obj = PluginObject::FromNPObject(object);
- if (!obj)
- return false;
-
- PPVarArrayFromNPVariantArray args(obj->module(), argc, argv);
- PPResultAndExceptionToNPResult result_converter(obj->GetNPObject(), result);
- return result_converter.SetResult(obj->ppp_class()->Construct(
- obj->ppp_class_data(), argc, args.array(),
- result_converter.exception()));
-}
-
-const NPClass wrapper_class = {
- NP_CLASS_STRUCT_VERSION,
- WrapperClass_Allocate,
- WrapperClass_Deallocate,
- WrapperClass_Invalidate,
- WrapperClass_HasMethod,
- WrapperClass_Invoke,
- WrapperClass_InvokeDefault,
- WrapperClass_HasProperty,
- WrapperClass_GetProperty,
- WrapperClass_SetProperty,
- WrapperClass_RemoveProperty,
- WrapperClass_Enumerate,
- WrapperClass_Construct
-};
-
-} // namespace
-
-// PluginObject ----------------------------------------------------------------
-
-struct PluginObject::NPObjectWrapper : public NPObject {
- // Points to the var object that owns this wrapper. This value may be NULL
- // if there is no var owning this wrapper. This can happen if the plugin
- // releases all references to the var, but a reference to the underlying
- // NPObject is still held by script on the page.
- PluginObject* obj;
-};
-
-PluginObject::PluginObject(PluginModule* module,
- NPObjectWrapper* object_wrapper,
- const PPP_Class_Deprecated* ppp_class,
- void* ppp_class_data)
- : module_(module),
- object_wrapper_(object_wrapper),
- ppp_class_(ppp_class),
- ppp_class_data_(ppp_class_data) {
- // Make the object wrapper refer back to this class so our NPObject
- // implementation can call back into the Pepper layer.
- object_wrapper_->obj = this;
- module_->AddPluginObject(this);
-}
-
-PluginObject::~PluginObject() {
- // The wrapper we made for this NPObject may still have a reference to it
- // from JavaScript, so we clear out its ObjectVar back pointer which will
- // cause all calls "up" to the plugin to become NOPs. Our ObjectVar base
- // class will release our reference to the object, which may or may not
- // delete the NPObject.
- DCHECK(object_wrapper_->obj == this);
- object_wrapper_->obj = NULL;
- module_->RemovePluginObject(this);
-}
-
-PP_Var PluginObject::Create(PluginModule* module,
- const PPP_Class_Deprecated* ppp_class,
- void* ppp_class_data) {
- // This will internally end up calling our AllocateObjectWrapper via the
- // WrapperClass_Allocated function which will have created an object wrapper
- // appropriate for this class (derived from NPObject).
- NPObjectWrapper* wrapper = static_cast<NPObjectWrapper*>(
- WebBindings::createObject(NULL, const_cast<NPClass*>(&wrapper_class)));
-
- // This object will register itself both with the NPObject and with the
- // PluginModule. The NPObject will normally handle its lifetime, and it
- // will get deleted in the destroy method. It may also get deleted when the
- // plugin module is deallocated.
- new PluginObject(module, wrapper, ppp_class, ppp_class_data);
-
- // We can just use a normal ObjectVar to refer to this object from the
- // plugin. It will hold a ref to the underlying NPObject which will in turn
- // hold our pluginObject.
- return ObjectVar::NPObjectToPPVar(module, wrapper);
-}
-
-NPObject* PluginObject::GetNPObject() const {
- return object_wrapper_;
-}
-
-// static
-bool PluginObject::IsInstanceOf(NPObject* np_object,
- const PPP_Class_Deprecated* ppp_class,
- void** ppp_class_data) {
- // Validate that this object is implemented by our wrapper class before
- // trying to get the PluginObject.
- if (np_object->_class != &wrapper_class)
- return false;
-
- PluginObject* plugin_object = FromNPObject(np_object);
- if (!plugin_object)
- return false; // Object is no longer alive.
-
- if (plugin_object->ppp_class() != ppp_class)
- return false;
- if (ppp_class_data)
- *ppp_class_data = plugin_object->ppp_class_data();
- return true;
-}
-
-// static
-PluginObject* PluginObject::FromNPObject(NPObject* object) {
- return static_cast<NPObjectWrapper*>(object)->obj;
-}
-
-// static
-NPObject* PluginObject::AllocateObjectWrapper() {
- NPObjectWrapper* wrapper = new NPObjectWrapper;
- memset(wrapper, 0, sizeof(NPObjectWrapper));
- return wrapper;
-}
-
-// VarObjectClass::InstanceData -----------------------------------------------
-
-struct VarObjectClass::InstanceData : public NPObject {
- InstanceData() : native_data(NULL) {}
-
- scoped_refptr<VarObjectClass> object_class;
- void* native_data;
-};
-
-// VarObjectClass::Property ---------------------------------------------------
-
-VarObjectClass::Property::Property(const PP_ClassProperty& prop)
- : method(prop.method),
- getter(prop.getter),
- setter(prop.setter),
- writable(!(prop.modifiers & PP_OBJECTPROPERTY_MODIFIER_READONLY)),
- enumerable(!(prop.modifiers & PP_OBJECTPROPERTY_MODIFIER_DONTENUM)) {
-}
-
-
-// VarObjectAccessorWithIdentifier ---------------------------------------------
-
-// Helper class for the new (PPB_Class) NPObject wrapper. This converts a call
-// from WebKit where it gives us an NPObject and an NPIdentifier to an
-// easily-accessible InstanceData (corresponding to the NPObject) and
-// std::string and Property (corresponding to the NPIdentifier).
-class VarObjectAccessorWithIdentifier {
- public:
- VarObjectAccessorWithIdentifier(NPObject* object, NPIdentifier identifier)
- : exists_(false),
- instance_(static_cast<VarObjectClass::InstanceData*>(object)),
- property_(NULL) {
- if (instance_) {
- const NPUTF8* string_value = NULL;
- int32_t int_value = 0;
- bool is_string = false;
- WebBindings::extractIdentifierData(identifier, string_value, int_value,
- is_string);
- if (is_string) {
- property_name_ = string_value;
-
- const VarObjectClass::PropertyMap& properties =
- instance_->object_class->properties();
- VarObjectClass::PropertyMap::const_iterator it =
- properties.find(property_name_);
- if (it != properties.end()) {
- property_ = &it->second;
- exists_ = true;
- }
- }
- }
- }
-
- // Return true if the object is valid, the identifier is valid, and the
- // property with said name exists.
- bool exists() const { return exists_; }
- bool is_method() const { return exists() && property_->method; }
- bool is_readable() const { return exists() && property_->getter; }
- bool is_writable() const {
- return exists() && property_->setter && property_->writable;
- }
- const VarObjectClass::InstanceData* instance() const { return instance_; }
- const VarObjectClass::Property* property() const { return property_; }
- PluginModule* module() const {
- return instance_ ? instance_->object_class->module() : NULL;
- }
-
- private:
- bool exists_;
- const VarObjectClass::InstanceData* instance_;
- std::string property_name_;
- const VarObjectClass::Property* property_;
-
- DISALLOW_COPY_AND_ASSIGN(VarObjectAccessorWithIdentifier);
-};
-
-// NPObject implementation in terms of PPB_Class -------------------------------
-
-namespace {
-
-NPObject* VarObjectClassAllocate(NPP npp, NPClass* the_class) {
- return new VarObjectClass::InstanceData;
-}
-
-void VarObjectClassDeallocate(NPObject* object) {
- VarObjectClass::InstanceData* instance =
- static_cast<VarObjectClass::InstanceData*>(object);
- if (instance->object_class->instance_native_destructor())
- instance->object_class->instance_native_destructor()(instance->native_data);
- delete instance;
-}
-
-bool VarObjectClassHasMethod(NPObject* np_obj, NPIdentifier name) {
- VarObjectAccessorWithIdentifier accessor(np_obj, name);
- return accessor.is_method();
-}
-
-bool VarObjectClassInvoke(NPObject* np_obj, NPIdentifier name,
- const NPVariant* args, uint32 arg_count,
- NPVariant* result) {
- VarObjectAccessorWithIdentifier accessor(np_obj, name);
- if (!accessor.is_method())
- return false;
-
- PPResultAndExceptionToNPResult result_converter(np_obj, result);
- PPVarArrayFromNPVariantArray arguments(accessor.module(), arg_count, args);
- PPVarFromNPObject self(accessor.module(), np_obj);
-
- return result_converter.SetResult(accessor.property()->method(
- accessor.instance()->native_data, self.var(), arguments.array(), arg_count,
- result_converter.exception()));
-}
-
-bool VarObjectClassInvokeDefault(NPObject* np_obj,
- const NPVariant* args,
- uint32 arg_count,
- NPVariant* result) {
- VarObjectClass::InstanceData* instance =
- static_cast<VarObjectClass::InstanceData*>(np_obj);
- if (!instance || !instance->object_class->instance_invoke())
- return false;
-
- PPResultAndExceptionToNPResult result_converter(np_obj, result);
- PPVarArrayFromNPVariantArray arguments(instance->object_class->module(),
- arg_count, args);
- PPVarFromNPObject self(instance->object_class->module(), np_obj);
-
- return result_converter.SetResult(instance->object_class->instance_invoke()(
- instance->native_data, self.var(), arguments.array(), arg_count,
- result_converter.exception()));
-}
-
-bool VarObjectClassHasProperty(NPObject* np_obj, NPIdentifier name) {
- VarObjectAccessorWithIdentifier accessor(np_obj, name);
- return accessor.is_readable();
-}
-
-bool VarObjectClassGetProperty(NPObject* np_obj, NPIdentifier name,
- NPVariant* result) {
- VarObjectAccessorWithIdentifier accessor(np_obj, name);
- if (!accessor.is_readable()) {
- return false;
- }
-
- PPResultAndExceptionToNPResult result_converter(np_obj, result);
- PPVarFromNPObject self(accessor.module(), np_obj);
-
- return result_converter.SetResult(accessor.property()->getter(
- accessor.instance()->native_data, self.var(), 0, 0,
- result_converter.exception()));
-}
-
-bool VarObjectClassSetProperty(NPObject* np_obj, NPIdentifier name,
- const NPVariant* variant) {
- VarObjectAccessorWithIdentifier accessor(np_obj, name);
- if (!accessor.is_writable()) {
- return false;
- }
-
- PPResultAndExceptionToNPResult result_converter(np_obj, NULL);
- PPVarArrayFromNPVariantArray arguments(accessor.module(), 1, variant);
- PPVarFromNPObject self(accessor.module(), np_obj);
-
- // Ignore return value.
- Var::PluginReleasePPVar(accessor.property()->setter(
- accessor.instance()->native_data, self.var(), arguments.array(), 1,
- result_converter.exception()));
-
- return result_converter.CheckExceptionForNoResult();
-}
-
-bool VarObjectClassEnumerate(NPObject *np_obj, NPIdentifier **value,
- uint32_t *count) {
- VarObjectClass::InstanceData* instance =
- static_cast<VarObjectClass::InstanceData*>(np_obj);
- *count = 0;
- *value = NULL;
- if (!instance)
- return false;
-
- const VarObjectClass::PropertyMap& properties =
- instance->object_class->properties();
-
- // Don't bother calculating the size of enumerable properties, just allocate
- // enough for all and then fill it partially.
- *value = static_cast<NPIdentifier*>(
- malloc(sizeof(NPIdentifier) * properties.size()));
-
- NPIdentifier* inserter = *value;
- for (VarObjectClass::PropertyMap::const_iterator i = properties.begin();
- i != properties.end(); ++i)
- if (i->second.enumerable)
- *inserter++ = WebBindings::getStringIdentifier(i->first.c_str());
-
- *count = inserter - *value;
- return true;
-}
-
-NPClass objectclassvar_class = {
- NP_CLASS_STRUCT_VERSION,
- &VarObjectClassAllocate,
- &VarObjectClassDeallocate,
- NULL,
- &VarObjectClassHasMethod,
- &VarObjectClassInvoke,
- &VarObjectClassInvokeDefault,
- &VarObjectClassHasProperty,
- &VarObjectClassGetProperty,
- &VarObjectClassSetProperty,
- NULL,
- &VarObjectClassEnumerate,
-};
-
-// PPB_Class interface ---------------------------------------------------------
-
-PP_Resource Create(PP_Module module, PP_ClassDestructor destruct,
- PP_ClassFunction invoke, PP_ClassProperty* properties) {
- PluginModule* plugin_module = ResourceTracker::Get()->GetModule(module);
- if (!properties || !plugin_module)
- return 0;
- scoped_refptr<VarObjectClass> cls = new VarObjectClass(plugin_module,
- destruct,
- invoke,
- properties);
- if (!cls)
- return 0;
- return cls->GetReference();
-}
-
-PP_Var Instantiate(PP_Resource class_object, void* native_data,
- PP_Var* exception) {
- scoped_refptr<VarObjectClass> object_class =
- Resource::GetAs<VarObjectClass>(class_object);
- if (!object_class)
- return PP_MakeUndefined();
- NPObject* obj = WebBindings::createObject(NULL, &objectclassvar_class);
- VarObjectClass::InstanceData* instance_data =
- static_cast<VarObjectClass::InstanceData*>(obj);
- instance_data->object_class = object_class;
- instance_data->native_data = native_data;
- return ObjectVar::NPObjectToPPVar(object_class->module(), obj);
-}
-
-} // namespace
-
-// VarObjectClass --------------------------------------------------------------
-
-VarObjectClass::VarObjectClass(PluginModule* module,
- PP_ClassDestructor destruct,
- PP_ClassFunction invoke,
- PP_ClassProperty* properties)
- : Resource(module),
- instance_native_destructor_(destruct),
- instance_invoke_(invoke) {
- PP_ClassProperty* prop = properties;
- while (prop->name) {
- properties_.insert(std::make_pair(std::string(prop->name),
- Property(*prop)));
- ++prop;
- }
-}
-
-// static
-const PPB_Class* VarObjectClass::GetInterface() {
- static PPB_Class interface = {
- &Create,
- &Instantiate
- };
- return &interface;
-}
-
-// virtual
-VarObjectClass::~VarObjectClass() { }
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_plugin_object.h b/webkit/glue/plugins/pepper_plugin_object.h
deleted file mode 100644
index e31c1b1..0000000
--- a/webkit/glue/plugins/pepper_plugin_object.h
+++ /dev/null
@@ -1,89 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_PLUGIN_OBJECT_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_PLUGIN_OBJECT_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-
-struct PP_Var;
-struct PPP_Class_Deprecated;
-typedef struct NPObject NPObject;
-typedef struct _NPVariant NPVariant;
-
-namespace pepper {
-
-class PluginModule;
-
-class PluginObject {
- public:
- virtual ~PluginObject();
-
- // Allocates a new PluginObject and returns it as a PP_Var with a
- // refcount of 1.
- static PP_Var Create(PluginModule* module,
- const PPP_Class_Deprecated* ppp_class,
- void* ppp_class_data);
-
- PluginModule* module() const { return module_; }
-
- const PPP_Class_Deprecated* ppp_class() { return ppp_class_; }
- void* ppp_class_data() { return ppp_class_data_; };
-
- NPObject* GetNPObject() const;
-
- // Returns true if the given var is an object implemented by the same plugin
- // that owns the var object, and that the class matches. If it matches,
- // returns true and places the class data into |*ppp_class_data| (which can
- // optionally be NULL if no class data is desired).
- static bool IsInstanceOf(NPObject* np_object,
- const PPP_Class_Deprecated* ppp_class,
- void** ppp_class_data);
-
- // Converts the given NPObject to the corresponding ObjectVar.
- //
- // The given NPObject must be one corresponding to a PluginObject or this
- // will crash. If the object is a PluginObject but the plugin has gone
- // away (the object could still be alive because of a reference from JS),
- // then the return value will be NULL.
- static PluginObject* FromNPObject(NPObject* object);
-
- // Allocates a plugin wrapper object and returns it as an NPObject. This is
- // used internally only.
- static NPObject* AllocateObjectWrapper();
-
- private:
- struct NPObjectWrapper;
-
- // This object must be created using the CreateObject function of the which
- // will set up the correct NPObject.
- //
- // The NPObjectWrapper (an NPObject) should already have the reference
- // incremented on it, and this class will take ownership of that reference.
- PluginObject(PluginModule* module,
- NPObjectWrapper* object_wrapper,
- const PPP_Class_Deprecated* ppp_class,
- void* ppp_class_data);
-
- PluginModule* module_;
-
- // Holds a pointer to the NPObject wrapper backing the var. This class
- // derives from NPObject and we hold a reference to it, so it must be
- // refcounted. When the type is not an object, this value will be NULL.
- //
- // We don't actually own this pointer, it's the NPObject that actually
- // owns us.
- NPObjectWrapper* object_wrapper_;
-
- const PPP_Class_Deprecated* ppp_class_;
- void* ppp_class_data_;
-
- DISALLOW_COPY_AND_ASSIGN(PluginObject);
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_PLUGIN_OBJECT_H_
diff --git a/webkit/glue/plugins/pepper_private.cc b/webkit/glue/plugins/pepper_private.cc
deleted file mode 100644
index 0675bee..0000000
--- a/webkit/glue/plugins/pepper_private.cc
+++ /dev/null
@@ -1,302 +0,0 @@
-// 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.
-
-#include "build/build_config.h"
-
-#include "webkit/glue/plugins/pepper_private.h"
-
-#include "unicode/usearch.h"
-
-#include "app/resource_bundle.h"
-#include "base/metrics/histogram.h"
-#include "base/utf_string_conversions.h"
-#include "grit/webkit_resources.h"
-#include "grit/webkit_strings.h"
-#include "skia/ext/platform_canvas.h"
-#include "ppapi/c/pp_resource.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "webkit/glue/webkit_glue.h"
-#include "webkit/glue/plugins/pepper_image_data.h"
-#include "webkit/glue/plugins/pepper_plugin_delegate.h"
-#include "webkit/glue/plugins/pepper_plugin_instance.h"
-#include "webkit/glue/plugins/pepper_plugin_module.h"
-#include "webkit/glue/plugins/pepper_var.h"
-#include "webkit/glue/plugins/ppb_private.h"
-#include "webkit/glue/plugins/pepper_var.h"
-
-namespace pepper {
-
-#if defined(OS_LINUX)
-class PrivateFontFile : public Resource {
- public:
- PrivateFontFile(PluginModule* module, int fd)
- : Resource(module),
- fd_(fd) {
- }
- virtual ~PrivateFontFile() {
- }
-
- // Resource overrides.
- PrivateFontFile* AsPrivateFontFile() { return this; }
-
- bool GetFontTable(uint32_t table,
- void* output,
- uint32_t* output_length);
-
- private:
- int fd_;
-};
-#endif
-
-namespace {
-
-struct ResourceImageInfo {
- PP_ResourceImage pp_id;
- int res_id;
-};
-
-static const ResourceImageInfo kResourceImageMap[] = {
- { PP_RESOURCEIMAGE_PDF_BUTTON_FTH, IDR_PDF_BUTTON_FTH },
- { PP_RESOURCEIMAGE_PDF_BUTTON_FTH_HOVER, IDR_PDF_BUTTON_FTH_HOVER },
- { PP_RESOURCEIMAGE_PDF_BUTTON_FTH_PRESSED, IDR_PDF_BUTTON_FTH_PRESSED },
- { PP_RESOURCEIMAGE_PDF_BUTTON_FTW, IDR_PDF_BUTTON_FTW },
- { PP_RESOURCEIMAGE_PDF_BUTTON_FTW_HOVER, IDR_PDF_BUTTON_FTW_HOVER },
- { PP_RESOURCEIMAGE_PDF_BUTTON_FTW_PRESSED, IDR_PDF_BUTTON_FTW_PRESSED },
- { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN, IDR_PDF_BUTTON_ZOOMIN },
- { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN_HOVER, IDR_PDF_BUTTON_ZOOMIN_HOVER },
- { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN_PRESSED, IDR_PDF_BUTTON_ZOOMIN_PRESSED },
- { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMOUT, IDR_PDF_BUTTON_ZOOMOUT },
- { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMOUT_HOVER, IDR_PDF_BUTTON_ZOOMOUT_HOVER },
- { PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMOUT_PRESSED,
- IDR_PDF_BUTTON_ZOOMOUT_PRESSED },
- { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_0, IDR_PDF_THUMBNAIL_0 },
- { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_1, IDR_PDF_THUMBNAIL_1 },
- { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_2, IDR_PDF_THUMBNAIL_2 },
- { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_3, IDR_PDF_THUMBNAIL_3 },
- { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_4, IDR_PDF_THUMBNAIL_4 },
- { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_5, IDR_PDF_THUMBNAIL_5 },
- { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_6, IDR_PDF_THUMBNAIL_6 },
- { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_7, IDR_PDF_THUMBNAIL_7 },
- { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_8, IDR_PDF_THUMBNAIL_8 },
- { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_9, IDR_PDF_THUMBNAIL_9 },
- { PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_NUM_BACKGROUND,
- IDR_PDF_THUMBNAIL_NUM_BACKGROUND },
-};
-
-PP_Var GetLocalizedString(PP_Module module_id, PP_ResourceString string_id) {
- PluginModule* module = ResourceTracker::Get()->GetModule(module_id);
- if (!module)
- return PP_MakeUndefined();
-
- std::string rv;
- if (string_id == PP_RESOURCESTRING_PDFGETPASSWORD) {
- rv = UTF16ToUTF8(webkit_glue::GetLocalizedString(IDS_PDF_NEED_PASSWORD));
- } else if (string_id == PP_RESOURCESTRING_PDFLOADING) {
- rv = UTF16ToUTF8(webkit_glue::GetLocalizedString(IDS_PDF_PAGE_LOADING));
- } else if (string_id == PP_RESOURCESTRING_PDFLOAD_FAILED) {
- rv = UTF16ToUTF8(webkit_glue::GetLocalizedString(IDS_PDF_PAGE_LOAD_FAILED));
- } else {
- NOTREACHED();
- }
-
- return StringVar::StringToPPVar(module, rv);
-}
-
-PP_Resource GetResourceImage(PP_Module module_id, PP_ResourceImage image_id) {
- int res_id = 0;
- for (size_t i = 0; i < arraysize(kResourceImageMap); ++i) {
- if (kResourceImageMap[i].pp_id == image_id) {
- res_id = kResourceImageMap[i].res_id;
- break;
- }
- }
- if (res_id == 0)
- return 0;
-
- SkBitmap* res_bitmap =
- ResourceBundle::GetSharedInstance().GetBitmapNamed(res_id);
-
- PluginModule* module = ResourceTracker::Get()->GetModule(module_id);
- if (!module)
- return 0;
- scoped_refptr<pepper::ImageData> image_data(new pepper::ImageData(module));
- if (!image_data->Init(ImageData::GetNativeImageDataFormat(),
- res_bitmap->width(), res_bitmap->height(), false)) {
- return 0;
- }
-
- ImageDataAutoMapper mapper(image_data);
- if (!mapper.is_valid())
- return 0;
-
- skia::PlatformCanvas* canvas = image_data->mapped_canvas();
- SkBitmap& ret_bitmap =
- const_cast<SkBitmap&>(canvas->getTopPlatformDevice().accessBitmap(true));
- if (!res_bitmap->copyTo(&ret_bitmap, SkBitmap::kARGB_8888_Config, NULL)) {
- return 0;
- }
-
- return image_data->GetReference();
-}
-
-PP_Resource GetFontFileWithFallback(
- PP_Module module_id,
- const PP_FontDescription_Dev* description,
- PP_PrivateFontCharset charset) {
-#if defined(OS_LINUX)
- PluginModule* module = ResourceTracker::Get()->GetModule(module_id);
- if (!module)
- return 0;
-
- scoped_refptr<StringVar> face_name(StringVar::FromPPVar(description->face));
- if (!face_name)
- return 0;
-
- int fd = webkit_glue::MatchFontWithFallback(
- face_name->value().c_str(),
- description->weight >= PP_FONTWEIGHT_BOLD,
- description->italic,
- charset);
- if (fd == -1)
- return 0;
-
- scoped_refptr<PrivateFontFile> font(new PrivateFontFile(module, fd));
-
- return font->GetReference();
-#else
- // For trusted pepper plugins, this is only needed in Linux since font loading
- // on Windows and Mac works through the renderer sandbox.
- return 0;
-#endif
-}
-
-bool GetFontTableForPrivateFontFile(PP_Resource font_file,
- uint32_t table,
- void* output,
- uint32_t* output_length) {
-#if defined(OS_LINUX)
- scoped_refptr<PrivateFontFile> font(
- Resource::GetAs<PrivateFontFile>(font_file));
- if (!font.get())
- return false;
- return font->GetFontTable(table, output, output_length);
-#else
- return false;
-#endif
-}
-
-void SearchString(PP_Module module,
- const unsigned short* input_string,
- const unsigned short* input_term,
- bool case_sensitive,
- PP_PrivateFindResult** results,
- int* count) {
- const char16* string = reinterpret_cast<const char16*>(input_string);
- const char16* term = reinterpret_cast<const char16*>(input_term);
-
- UErrorCode status = U_ZERO_ERROR;
- UStringSearch* searcher = usearch_open(
- term, -1, string, -1, webkit_glue::GetWebKitLocale().c_str(), 0,
- &status);
- DCHECK(status == U_ZERO_ERROR || status == U_USING_FALLBACK_WARNING ||
- status == U_USING_DEFAULT_WARNING);
- UCollationStrength strength = case_sensitive ? UCOL_TERTIARY : UCOL_PRIMARY;
-
- UCollator* collator = usearch_getCollator(searcher);
- if (ucol_getStrength(collator) != strength) {
- ucol_setStrength(collator, strength);
- usearch_reset(searcher);
- }
-
- status = U_ZERO_ERROR;
- int match_start = usearch_first(searcher, &status);
- DCHECK(status == U_ZERO_ERROR);
-
- std::vector<PP_PrivateFindResult> pp_results;
- while (match_start != USEARCH_DONE) {
- size_t matched_length = usearch_getMatchedLength(searcher);
- PP_PrivateFindResult result;
- result.start_index = match_start;
- result.length = matched_length;
- pp_results.push_back(result);
- match_start = usearch_next(searcher, &status);
- DCHECK(status == U_ZERO_ERROR);
- }
-
- *count = pp_results.size();
- if (*count) {
- *results = reinterpret_cast<PP_PrivateFindResult*>(
- malloc(*count * sizeof(PP_PrivateFindResult)));
- memcpy(*results, &pp_results[0], *count * sizeof(PP_PrivateFindResult));
- } else {
- *results = NULL;
- }
-
- usearch_close(searcher);
-}
-
-void DidStartLoading(PP_Instance instance_id) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return;
- instance->delegate()->DidStartLoading();
-}
-
-void DidStopLoading(PP_Instance instance_id) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return;
- instance->delegate()->DidStopLoading();
-}
-
-void SetContentRestriction(PP_Instance instance_id, int restrictions) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return;
- instance->delegate()->SetContentRestriction(restrictions);
-}
-
-void HistogramPDFPageCount(int count) {
- UMA_HISTOGRAM_COUNTS_10000("PDF.PageCount", count);
-}
-
-void UserMetricsRecordAction(PP_Var action) {
- scoped_refptr<StringVar> action_str(StringVar::FromPPVar(action));
- if (action_str)
- webkit_glue::UserMetricsRecordAction(action_str->value());
-}
-
-const PPB_Private ppb_private = {
- &GetLocalizedString,
- &GetResourceImage,
- &GetFontFileWithFallback,
- &GetFontTableForPrivateFontFile,
- &SearchString,
- &DidStartLoading,
- &DidStopLoading,
- &SetContentRestriction,
- &HistogramPDFPageCount,
- &UserMetricsRecordAction
-};
-
-} // namespace
-
-// static
-const PPB_Private* Private::GetInterface() {
- return &ppb_private;
-}
-
-#if defined(OS_LINUX)
-bool PrivateFontFile::GetFontTable(uint32_t table,
- void* output,
- uint32_t* output_length) {
- size_t temp_size = static_cast<size_t>(*output_length);
- bool rv = webkit_glue::GetFontTable(
- fd_, table, static_cast<uint8_t*>(output), &temp_size);
- *output_length = static_cast<uint32_t>(temp_size);
- return rv;
-}
-#endif
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_private.h b/webkit/glue/plugins/pepper_private.h
deleted file mode 100644
index 06016f0..0000000
--- a/webkit/glue/plugins/pepper_private.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_PRIVATE_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_PRIVATE_H_
-
-#include "webkit/glue/plugins/pepper_resource.h"
-
-struct PPB_Private;
-
-namespace pepper {
-
-class Private {
- public:
- // Returns a pointer to the interface implementing PPB_Private that is exposed
- // to the plugin.
- static const PPB_Private* GetInterface();
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_PRIVATE_H_
diff --git a/webkit/glue/plugins/pepper_private2.cc b/webkit/glue/plugins/pepper_private2.cc
deleted file mode 100644
index 8492b65..0000000
--- a/webkit/glue/plugins/pepper_private2.cc
+++ /dev/null
@@ -1,243 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_private2.h"
-
-#include <string.h>
-
-#include "base/file_path.h"
-#include "base/stringprintf.h"
-#include "base/utf_string_conversions.h"
-#include "googleurl/src/gurl.h"
-#include "ppapi/c/dev/pp_file_info_dev.h"
-#include "ppapi/c/dev/ppb_file_io_dev.h"
-#include "webkit/glue/plugins/pepper_error_util.h"
-#include "webkit/glue/plugins/pepper_plugin_delegate.h"
-#include "webkit/glue/plugins/pepper_plugin_instance.h"
-#include "webkit/glue/plugins/pepper_plugin_module.h"
-#include "webkit/glue/plugins/pepper_var.h"
-#include "webkit/glue/plugins/ppb_private2.h"
-
-namespace pepper {
-
-namespace {
-
-PluginInstance* GetSomeInstance(PP_Module pp_module) {
- PluginModule* module = ResourceTracker::Get()->GetModule(pp_module);
- if (!module)
- return NULL;
-
- return module->GetSomeInstance();
-}
-
-void SetInstanceAlwaysOnTop(PP_Instance pp_instance, bool on_top) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(pp_instance);
- if (!instance)
- return;
- instance->set_always_on_top(on_top);
-}
-
-PP_Var GetProxyForURL(PP_Module pp_module, const char* url) {
- PluginInstance* instance = GetSomeInstance(pp_module);
- if (!instance)
- return PP_MakeUndefined();
-
- GURL gurl(url);
- if (!gurl.is_valid())
- return PP_MakeUndefined();
-
- std::string proxy_host = instance->delegate()->ResolveProxy(gurl);
- if (proxy_host.empty())
- return PP_MakeUndefined(); // No proxy.
- return StringVar::StringToPPVar(instance->module(), proxy_host);
-}
-
-FilePath GetFilePathFromUTF8(const char* path) {
-#if defined(OS_WIN)
- return FilePath(UTF8ToUTF16(path));
-#else
- return FilePath(path);
-#endif
-}
-
-int32_t OpenModuleLocalFile(PP_Module module,
- const char* path,
- int32_t mode,
- PP_FileHandle* file) {
- PluginInstance* instance = GetSomeInstance(module);
- if (!instance)
- return PP_ERROR_FAILED;
-
- int flags = 0;
- if (mode & PP_FILEOPENFLAG_READ)
- flags |= base::PLATFORM_FILE_READ;
- if (mode & PP_FILEOPENFLAG_WRITE) {
- flags |= base::PLATFORM_FILE_WRITE;
- flags |= base::PLATFORM_FILE_WRITE_ATTRIBUTES;
- }
- if (mode & PP_FILEOPENFLAG_TRUNCATE) {
- DCHECK(mode & PP_FILEOPENFLAG_WRITE);
- flags |= base::PLATFORM_FILE_TRUNCATE;
- }
-
- if (mode & PP_FILEOPENFLAG_CREATE) {
- if (mode & PP_FILEOPENFLAG_EXCLUSIVE)
- flags |= base::PLATFORM_FILE_CREATE;
- else
- flags |= base::PLATFORM_FILE_OPEN_ALWAYS;
- } else {
- flags |= base::PLATFORM_FILE_OPEN;
- }
-
- base::PlatformFile base_file;
- base::PlatformFileError result = instance->delegate()->OpenModuleLocalFile(
- instance->module()->name(),
- GetFilePathFromUTF8(path),
- flags,
- &base_file);
- *file = base_file;
- return PlatformFileErrorToPepperError(result);
-}
-
-
-int32_t RenameModuleLocalFile(PP_Module module,
- const char* path_from,
- const char* path_to) {
- PluginInstance* instance = GetSomeInstance(module);
- if (!instance)
- return PP_ERROR_FAILED;
-
- base::PlatformFileError result = instance->delegate()->RenameModuleLocalFile(
- instance->module()->name(),
- GetFilePathFromUTF8(path_from),
- GetFilePathFromUTF8(path_to));
- return PlatformFileErrorToPepperError(result);
-}
-
-int32_t DeleteModuleLocalFileOrDir(PP_Module module,
- const char* path,
- bool recursive) {
- PluginInstance* instance = GetSomeInstance(module);
- if (!instance)
- return PP_ERROR_FAILED;
-
- base::PlatformFileError result =
- instance->delegate()->DeleteModuleLocalFileOrDir(
- instance->module()->name(), GetFilePathFromUTF8(path), recursive);
- return PlatformFileErrorToPepperError(result);
-}
-
-int32_t CreateModuleLocalDir(PP_Module module, const char* path) {
- PluginInstance* instance = GetSomeInstance(module);
- if (!instance)
- return PP_ERROR_FAILED;
-
- base::PlatformFileError result = instance->delegate()->CreateModuleLocalDir(
- instance->module()->name(), GetFilePathFromUTF8(path));
- return PlatformFileErrorToPepperError(result);
-}
-
-int32_t QueryModuleLocalFile(PP_Module module,
- const char* path,
- PP_FileInfo_Dev* info) {
- PluginInstance* instance = GetSomeInstance(module);
- if (!instance)
- return PP_ERROR_FAILED;
-
- base::PlatformFileInfo file_info;
- base::PlatformFileError result = instance->delegate()->QueryModuleLocalFile(
- instance->module()->name(), GetFilePathFromUTF8(path), &file_info);
- if (result == base::PLATFORM_FILE_OK) {
- info->size = file_info.size;
- info->creation_time = file_info.creation_time.ToDoubleT();
- info->last_access_time = file_info.last_accessed.ToDoubleT();
- info->last_modified_time = file_info.last_modified.ToDoubleT();
- info->system_type = PP_FILESYSTEMTYPE_EXTERNAL;
- if (file_info.is_directory)
- info->type = PP_FILETYPE_DIRECTORY;
- else
- info->type = PP_FILETYPE_REGULAR;
- }
- return PlatformFileErrorToPepperError(result);
-}
-
-int32_t GetModuleLocalDirContents(PP_Module module,
- const char* path,
- PP_DirContents_Dev** contents) {
- PluginInstance* instance = GetSomeInstance(module);
- if (!instance)
- return PP_ERROR_FAILED;
-
- *contents = NULL;
- PepperDirContents pepper_contents;
- base::PlatformFileError result =
- instance->delegate()->GetModuleLocalDirContents(
- instance->module()->name(),
- GetFilePathFromUTF8(path),
- &pepper_contents);
-
- if (result != base::PLATFORM_FILE_OK)
- return PlatformFileErrorToPepperError(result);
-
- *contents = new PP_DirContents_Dev;
- size_t count = pepper_contents.size();
- (*contents)->count = count;
- (*contents)->entries = new PP_DirEntry_Dev[count];
- for (size_t i = 0; i < count; ++i) {
- PP_DirEntry_Dev& entry = (*contents)->entries[i];
-#if defined(OS_WIN)
- const std::string& name = UTF16ToUTF8(pepper_contents[i].name.value());
-#else
- const std::string& name = pepper_contents[i].name.value();
-#endif
- size_t size = name.size() + 1;
- char* name_copy = new char[size];
- memcpy(name_copy, name.c_str(), size);
- entry.name = name_copy;
- entry.is_dir = pepper_contents[i].is_dir;
- }
- return PP_OK;
-}
-
-void FreeModuleLocalDirContents(PP_Module module,
- PP_DirContents_Dev* contents) {
- DCHECK(contents);
- for (int32_t i = 0; i < contents->count; ++i) {
- delete [] contents->entries[i].name;
- }
- delete [] contents->entries;
- delete contents;
-}
-
-bool NavigateToURL(PP_Instance pp_instance,
- const char* url,
- const char* target) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(pp_instance);
- if (!instance)
- return false;
- return instance->NavigateToURL(url, target);
-}
-
-const PPB_Private2 ppb_private2 = {
- &SetInstanceAlwaysOnTop,
- &Private2::DrawGlyphs,
- &GetProxyForURL,
- &OpenModuleLocalFile,
- &RenameModuleLocalFile,
- &DeleteModuleLocalFileOrDir,
- &CreateModuleLocalDir,
- &QueryModuleLocalFile,
- &GetModuleLocalDirContents,
- &FreeModuleLocalDirContents,
- &NavigateToURL,
-};
-
-} // namespace
-
-// static
-const PPB_Private2* Private2::GetInterface() {
- return &ppb_private2;
-}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_private2.h b/webkit/glue/plugins/pepper_private2.h
deleted file mode 100644
index 64a766f..0000000
--- a/webkit/glue/plugins/pepper_private2.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_PRIVATE2_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_PRIVATE2_H_
-
-#include "build/build_config.h"
-#include "ppapi/c/pp_point.h"
-#include "ppapi/c/pp_rect.h"
-#include "webkit/glue/plugins/pepper_resource.h"
-
-struct PP_FontDescription_Dev;
-struct PPB_Private2;
-
-namespace pepper {
-
-class Private2 {
- public:
- // Returns a pointer to the interface implementing PPB_Private2 that is
- // exposed to the plugin.
- static const PPB_Private2* GetInterface();
-
- static bool DrawGlyphs(PP_Resource pp_image_data,
- const PP_FontDescription_Dev* font_desc,
- uint32_t color,
- PP_Point position,
- PP_Rect clip,
- float transformation[3][3],
- uint32_t glyph_count,
- uint16_t glyph_indices[],
- PP_Point glyph_advances[])
-#if defined(OS_LINUX)
- ;
-#else
- { return false; }
-#endif
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_PRIVATE2_H_
diff --git a/webkit/glue/plugins/pepper_private2_linux.cc b/webkit/glue/plugins/pepper_private2_linux.cc
deleted file mode 100644
index ed2c04a..0000000
--- a/webkit/glue/plugins/pepper_private2_linux.cc
+++ /dev/null
@@ -1,110 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_private2.h"
-
-#include "skia/ext/platform_canvas.h"
-#include "ppapi/c/pp_point.h"
-#include "ppapi/c/pp_rect.h"
-#include "ppapi/c/dev/ppb_font_dev.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkMatrix.h"
-#include "third_party/skia/include/core/SkPaint.h"
-#include "third_party/skia/include/core/SkPoint.h"
-#include "third_party/skia/include/core/SkTemplates.h"
-#include "third_party/skia/include/core/SkTypeface.h"
-#include "webkit/glue/plugins/pepper_image_data.h"
-#include "webkit/glue/plugins/pepper_var.h"
-
-namespace pepper {
-
-bool Private2::DrawGlyphs(PP_Resource pp_image_data,
- const PP_FontDescription_Dev* font_desc,
- uint32_t color,
- PP_Point position,
- PP_Rect clip,
- float transformation[3][3],
- uint32_t glyph_count,
- uint16_t glyph_indices[],
- PP_Point glyph_advances[]) {
- scoped_refptr<ImageData> image_resource(
- Resource::GetAs<ImageData>(pp_image_data));
- if (!image_resource.get())
- return false;
- ImageDataAutoMapper mapper(image_resource);
- if (!mapper.is_valid())
- return false;
-
- // Set up the typeface.
- scoped_refptr<StringVar> face_name(StringVar::FromPPVar(font_desc->face));
- if (!face_name)
- return false;
- int style = SkTypeface::kNormal;
- if (font_desc->weight >= PP_FONTWEIGHT_BOLD)
- style |= SkTypeface::kBold;
- if (font_desc->italic)
- style |= SkTypeface::kItalic;
- SkTypeface* typeface =
- SkTypeface::CreateFromName(face_name->value().c_str(),
- static_cast<SkTypeface::Style>(style));
- if (!typeface)
- return false;
-
- // Set up the canvas.
- SkCanvas* canvas = image_resource->mapped_canvas();
- canvas->save();
-
- // Clip is applied in pixels before the transform.
- SkRect clip_rect = { clip.point.x, clip.point.y,
- clip.point.x + clip.size.width,
- clip.point.y + clip.size.height };
- canvas->clipRect(clip_rect);
-
- // -- Do not return early below this. The canvas needs restoring and the
- // typeface will leak if it's not assigned to the paint (it's refcounted and
- // the refcount is currently 0).
-
- // Convert & set the matrix.
- SkMatrix matrix;
- matrix.set(SkMatrix::kMScaleX, SkFloatToScalar(transformation[0][0]));
- matrix.set(SkMatrix::kMSkewX, SkFloatToScalar(transformation[0][1]));
- matrix.set(SkMatrix::kMTransX, SkFloatToScalar(transformation[0][2]));
- matrix.set(SkMatrix::kMSkewY, SkFloatToScalar(transformation[1][0]));
- matrix.set(SkMatrix::kMScaleY, SkFloatToScalar(transformation[1][1]));
- matrix.set(SkMatrix::kMTransY, SkFloatToScalar(transformation[1][2]));
- matrix.set(SkMatrix::kMPersp0, SkFloatToScalar(transformation[2][0]));
- matrix.set(SkMatrix::kMPersp1, SkFloatToScalar(transformation[2][1]));
- matrix.set(SkMatrix::kMPersp2, SkFloatToScalar(transformation[2][2]));
- canvas->concat(matrix);
-
- SkPaint paint;
- paint.setColor(color);
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
- paint.setAntiAlias(true);
- paint.setHinting(SkPaint::kFull_Hinting);
- paint.setTextSize(SkIntToScalar(font_desc->size));
- paint.setTypeface(typeface); // Takes a ref and manages lifetime.
- paint.setSubpixelText(true);
- paint.setLCDRenderText(true);
-
- SkScalar x = SkIntToScalar(position.x);
- SkScalar y = SkIntToScalar(position.y);
-
- // Build up the skia advances.
- SkAutoSTMalloc<32, SkPoint> storage(glyph_count);
- SkPoint* sk_positions = storage.get();
- for (uint32_t i = 0; i < glyph_count; i++) {
- sk_positions[i].set(x, y);
- x += SkFloatToScalar(glyph_advances[i].x);
- y += SkFloatToScalar(glyph_advances[i].y);
- }
-
- canvas->drawPosText(glyph_indices, glyph_count * 2, sk_positions, paint);
-
- canvas->restore();
- return true;
-}
-
-} // namespace pepper
-
diff --git a/webkit/glue/plugins/pepper_resource.cc b/webkit/glue/plugins/pepper_resource.cc
deleted file mode 100644
index 851d6e7..0000000
--- a/webkit/glue/plugins/pepper_resource.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_resource.h"
-
-#include "base/logging.h"
-#include "webkit/glue/plugins/pepper_resource_tracker.h"
-
-namespace pepper {
-
-Resource::Resource(PluginModule* module)
- : resource_id_(0), module_(module) {
-}
-
-Resource::~Resource() {
-}
-
-PP_Resource Resource::GetReference() {
- ResourceTracker *tracker = ResourceTracker::Get();
- if (resource_id_)
- tracker->AddRefResource(resource_id_);
- else
- resource_id_ = tracker->AddResource(this);
- return resource_id_;
-}
-
-PP_Resource Resource::GetReferenceNoAddRef() const {
- return resource_id_;
-}
-
-void Resource::StoppedTracking() {
- DCHECK(resource_id_ != 0);
- resource_id_ = 0;
-}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_resource.h b/webkit/glue/plugins/pepper_resource.h
deleted file mode 100644
index 3c4ebca..0000000
--- a/webkit/glue/plugins/pepper_resource.h
+++ /dev/null
@@ -1,140 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_RESOURCE_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_RESOURCE_H_
-
-#include "base/basictypes.h"
-#include "base/ref_counted.h"
-#include "ppapi/c/pp_resource.h"
-#include "webkit/glue/plugins/pepper_resource_tracker.h"
-
-namespace pepper {
-
-// If you inherit from resource, make sure you add the class name here.
-#define FOR_ALL_RESOURCES(F) \
- F(Audio) \
- F(AudioConfig) \
- F(Buffer) \
- F(DirectoryReader) \
- F(FileChooser) \
- F(FileIO) \
- F(FileRef) \
- F(FileSystem) \
- F(Font) \
- F(Graphics2D) \
- F(Graphics3D) \
- F(ImageData) \
- F(ObjectVar) \
- F(PluginModule) \
- F(PrivateFontFile) \
- F(Scrollbar) \
- F(StringVar) \
- F(Transport) \
- F(URLLoader) \
- F(URLRequestInfo) \
- F(URLResponseInfo) \
- F(Var) \
- F(VarObjectClass) \
- F(VideoDecoder) \
- F(Widget)
-
-// Forward declaration of Resource classes.
-#define DECLARE_RESOURCE_CLASS(RESOURCE) class RESOURCE;
-FOR_ALL_RESOURCES(DECLARE_RESOURCE_CLASS)
-#undef DECLARE_RESOURCE_CLASS
-
-class Resource : public base::RefCountedThreadSafe<Resource> {
- public:
- explicit Resource(PluginModule* module);
- virtual ~Resource();
-
- // Returns NULL if the resource is invalid or is a different type.
- template<typename T>
- static scoped_refptr<T> GetAs(PP_Resource res) {
- scoped_refptr<Resource> resource = ResourceTracker::Get()->GetResource(res);
- return resource ? resource->Cast<T>() : NULL;
- }
-
- PluginModule* module() const { return module_; }
-
- // Cast the resource into a specified type. This will return NULL if the
- // resource does not match the specified type. Specializations of this
- // template call into As* functions.
- template <typename T> T* Cast() { return NULL; }
-
- // Returns an resource id of this object. If the object doesn't have a
- // resource id, new one is created with plugin refcount of 1. If it does,
- // the refcount is incremented. Use this when you need to return a new
- // reference to the plugin.
- PP_Resource GetReference();
-
- // Returns the resource ID of this object OR NULL IF THERE IS NONE ASSIGNED.
- // This will happen if the plugin doesn't have a reference to the given
- // resource. The resource will not be addref'ed.
- //
- // This should only be used as an input parameter to the plugin for status
- // updates in the proxy layer, where if the plugin has no reference, it will
- // just give up since nothing needs to be updated.
- //
- // Generally you should use GetReference instead. This is why it has this
- // obscure name rather than pp_resource().
- PP_Resource GetReferenceNoAddRef() const;
-
- // When you need to ensure that a resource has a reference, but you do not
- // want to increase the refcount (for example, if you need to call a plugin
- // callback function with a reference), you can use this class. For example:
- //
- // plugin_callback(.., ScopedResourceId(resource).id, ...);
- class ScopedResourceId {
- public:
- explicit ScopedResourceId(Resource* resource)
- : id(resource->GetReference()) {}
- ~ScopedResourceId() {
- ResourceTracker::Get()->UnrefResource(id);
- }
- const PP_Resource id;
- };
-
- private:
- // Type-specific getters for individual resource types. These will return
- // NULL if the resource does not match the specified type. Used by the Cast()
- // function.
- #define DEFINE_TYPE_GETTER(RESOURCE) \
- virtual RESOURCE* As##RESOURCE() { return NULL; }
- FOR_ALL_RESOURCES(DEFINE_TYPE_GETTER)
- #undef DEFINE_TYPE_GETTER
-
- // If referenced by a plugin, holds the id of this resource object. Do not
- // access this member directly, because it is possible that the plugin holds
- // no references to the object, and therefore the resource_id_ is zero. Use
- // either GetReference() to obtain a new resource_id and increase the
- // refcount, or TemporaryReference when you do not want to increase the
- // refcount.
- PP_Resource resource_id_;
-
- // Non-owning pointer to our module.
- PluginModule* module_;
-
- // Called by the resource tracker when the last plugin reference has been
- // dropped.
- friend class ResourceTracker;
- void StoppedTracking();
-
- DISALLOW_COPY_AND_ASSIGN(Resource);
-};
-
-// Cast() specializations.
-#define DEFINE_RESOURCE_CAST(Type) \
- template <> inline Type* Resource::Cast<Type>() { \
- return As##Type(); \
- }
-
-FOR_ALL_RESOURCES(DEFINE_RESOURCE_CAST)
-#undef DEFINE_RESOURCE_CAST
-
-#undef FOR_ALL_RESOURCES
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_RESOURCE_H_
diff --git a/webkit/glue/plugins/pepper_resource_tracker.cc b/webkit/glue/plugins/pepper_resource_tracker.cc
deleted file mode 100644
index ba6f8f0..0000000
--- a/webkit/glue/plugins/pepper_resource_tracker.cc
+++ /dev/null
@@ -1,167 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_resource_tracker.h"
-
-#include <limits>
-#include <set>
-
-#include "base/logging.h"
-#include "base/rand_util.h"
-#include "ppapi/c/pp_resource.h"
-#include "webkit/glue/plugins/pepper_resource.h"
-
-namespace pepper {
-
-scoped_refptr<Resource> ResourceTracker::GetResource(PP_Resource res) const {
- ResourceMap::const_iterator result = live_resources_.find(res);
- if (result == live_resources_.end()) {
- return scoped_refptr<Resource>();
- }
- return result->second.first;
-}
-
-ResourceTracker::ResourceTracker()
- : last_id_(0) {
-}
-
-ResourceTracker::~ResourceTracker() {
-}
-
-PP_Resource ResourceTracker::AddResource(Resource* resource) {
- // If the plugin manages to create 4B resources...
- if (last_id_ == std::numeric_limits<PP_Resource>::max()) {
- return 0;
- }
- // Add the resource with plugin use-count 1.
- ++last_id_;
- live_resources_.insert(std::make_pair(last_id_, std::make_pair(resource, 1)));
- return last_id_;
-}
-
-bool ResourceTracker::AddRefResource(PP_Resource res) {
- ResourceMap::iterator i = live_resources_.find(res);
- if (i != live_resources_.end()) {
- // We don't protect against overflow, since a plugin as malicious as to ref
- // once per every byte in the address space could have just as well unrefed
- // one time too many.
- ++i->second.second;
- return true;
- } else {
- return false;
- }
-}
-
-bool ResourceTracker::UnrefResource(PP_Resource res) {
- ResourceMap::iterator i = live_resources_.find(res);
- if (i != live_resources_.end()) {
- if (!--i->second.second) {
- i->second.first->StoppedTracking();
- live_resources_.erase(i);
- }
- return true;
- } else {
- return false;
- }
-}
-
-void ResourceTracker::ForceDeletePluginResourceRefs(PP_Resource res) {
- ResourceMap::iterator i = live_resources_.find(res);
- if (i != live_resources_.end())
- return; // Nothing to do.
-
- i->second.second = 0;
- i->second.first->StoppedTracking();
- live_resources_.erase(i);
-}
-
-uint32 ResourceTracker::GetLiveObjectsForModule(PluginModule* module) const {
- // Since this is for testing only, we'll just go through all of them and
- // count.
- //
- // TODO(brettw) we will eventually need to implement more efficient
- // module->resource lookup to free resources when a module is unloaded. In
- // this case, this function can be implemented using that system.
- uint32 count = 0;
- for (ResourceMap::const_iterator i = live_resources_.begin();
- i != live_resources_.end(); ++i)
- count++;
- return count;
-}
-
-PP_Instance ResourceTracker::AddInstance(PluginInstance* instance) {
-#ifndef NDEBUG
- // Make sure we're not adding one more than once.
- for (InstanceMap::const_iterator i = instance_map_.begin();
- i != instance_map_.end(); ++i)
- DCHECK(i->second != instance);
-#endif
-
- // Use a random 64-bit number for the instance ID. This helps prevent some
- // mischeif where you could misallocate resources if you gave a different
- // instance ID.
- //
- // See also AddModule below.
- //
- // Need to make sure the random number isn't a duplicate or 0.
- PP_Instance new_instance;
- do {
- new_instance = static_cast<PP_Instance>(base::RandUint64());
- } while (!new_instance ||
- instance_map_.find(new_instance) != instance_map_.end());
- instance_map_[new_instance] = instance;
- return new_instance;
-}
-
-void ResourceTracker::InstanceDeleted(PP_Instance instance) {
- InstanceMap::iterator found = instance_map_.find(instance);
- if (found == instance_map_.end()) {
- NOTREACHED();
- return;
- }
- instance_map_.erase(found);
-}
-
-PluginInstance* ResourceTracker::GetInstance(PP_Instance instance) {
- InstanceMap::iterator found = instance_map_.find(instance);
- if (found == instance_map_.end())
- return NULL;
- return found->second;
-}
-
-PP_Module ResourceTracker::AddModule(PluginModule* module) {
-#ifndef NDEBUG
- // Make sure we're not adding one more than once.
- for (ModuleMap::const_iterator i = module_map_.begin();
- i != module_map_.end(); ++i)
- DCHECK(i->second != module);
-#endif
-
- // See AddInstance above.
- PP_Module new_module;
- do {
- new_module = static_cast<PP_Module>(base::RandUint64());
- } while (!new_module ||
- module_map_.find(new_module) != module_map_.end());
- module_map_[new_module] = module;
- return new_module;
-}
-
-void ResourceTracker::ModuleDeleted(PP_Module module) {
- ModuleMap::iterator found = module_map_.find(module);
- if (found == module_map_.end()) {
- NOTREACHED();
- return;
- }
- module_map_.erase(found);
-}
-
-PluginModule* ResourceTracker::GetModule(PP_Module module) {
- ModuleMap::iterator found = module_map_.find(module);
- if (found == module_map_.end())
- return NULL;
- return found->second;
-}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_resource_tracker.h b/webkit/glue/plugins/pepper_resource_tracker.h
deleted file mode 100644
index ad25d1a..0000000
--- a/webkit/glue/plugins/pepper_resource_tracker.h
+++ /dev/null
@@ -1,134 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_RESOURCE_TRACKER_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_RESOURCE_TRACKER_H_
-
-#include <map>
-#include <utility>
-
-#include "base/basictypes.h"
-#include "base/hash_tables.h"
-#include "base/ref_counted.h"
-#include "base/singleton.h"
-#include "ppapi/c/pp_instance.h"
-#include "ppapi/c/pp_module.h"
-#include "ppapi/c/pp_resource.h"
-
-namespace pepper {
-
-class PluginInstance;
-class PluginModule;
-class Resource;
-
-// This class maintains a global list of all live pepper resources. It allows
-// us to check resource ID validity and to map them to a specific module.
-//
-// This object is threadsafe.
-class ResourceTracker {
- public:
- // Returns the pointer to the singleton object.
- static ResourceTracker* Get() {
- return Singleton<ResourceTracker>::get();
- }
-
- // PP_Resources --------------------------------------------------------------
-
- // The returned pointer will be NULL if there is no resource. Note that this
- // return value is a scoped_refptr so that we ensure the resource is valid
- // from the point of the lookup to the point that the calling code needs it.
- // Otherwise, the plugin could Release() the resource on another thread and
- // the object will get deleted out from under us.
- scoped_refptr<Resource> GetResource(PP_Resource res) const;
-
- // Increment resource's plugin refcount. See ResourceAndRefCount comments
- // below.
- bool AddRefResource(PP_Resource res);
- bool UnrefResource(PP_Resource res);
-
- // Forces the plugin refcount of the given resource to 0. This can be used to
- // delete an object the plugin has leaked or whose lifetime is otherwise
- // exceeded.
- //
- // Note that this may not necessarily delete the resource object since the
- // regular refcount is maintained separately from the plugin refcount and
- // random components in the Pepper implementation could still have
- // references to it.
- void ForceDeletePluginResourceRefs(PP_Resource res);
-
- // Returns the number of resources associated with this module.
- //
- // This is slow, use only for testing.
- uint32 GetLiveObjectsForModule(PluginModule* module) const;
-
- // PP_Modules ----------------------------------------------------------------
-
- // Adds a new plugin module to the list of tracked module, and returns a new
- // module handle to identify it.
- PP_Module AddModule(PluginModule* module);
-
- // Called when a plugin modulde was deleted and should no longer be tracked.
- // The given handle should be one generated by AddModule.
- void ModuleDeleted(PP_Module module);
-
- // Returns a pointer to the plugin modulde object associated with the given
- // modulde handle. The return value will be NULL if the handle is invalid.
- PluginModule* GetModule(PP_Module module);
-
- // PP_Instances --------------------------------------------------------------
-
- // Adds a new plugin instance to the list of tracked instances, and returns a
- // new instance handle to identify it.
- PP_Instance AddInstance(PluginInstance* instance);
-
- // Called when a plugin instance was deleted and should no longer be tracked.
- // The given handle should be one generated by AddInstance.
- void InstanceDeleted(PP_Instance instance);
-
- // Returns a pointer to the plugin instance object associated with the given
- // instance handle. The return value will be NULL if the handle is invalid.
- PluginInstance* GetInstance(PP_Instance instance);
-
- private:
- friend struct DefaultSingletonTraits<ResourceTracker>;
- friend class Resource;
-
- // Prohibit creation other then by the Singleton class.
- ResourceTracker();
- ~ResourceTracker();
-
- // Adds the given resource to the tracker and assigns it a resource ID and
- // refcount of 1. The assigned resource ID will be returned. Used only by the
- // Resource class.
- PP_Resource AddResource(Resource* resource);
-
- // Last assigned resource ID.
- PP_Resource last_id_;
-
- // For each PP_Resource, keep the Resource* (as refptr) and plugin use count.
- // This use count is different then Resource's RefCount, and is manipulated
- // using this RefResource/UnrefResource. When it drops to zero, we just remove
- // the resource from this resource tracker, but the resource object will be
- // alive so long as some scoped_refptr still holds it's reference. This
- // prevents plugins from forcing destruction of Resource objects.
- typedef std::pair<scoped_refptr<Resource>, size_t> ResourceAndRefCount;
- typedef base::hash_map<PP_Resource, ResourceAndRefCount> ResourceMap;
- ResourceMap live_resources_;
-
- // Tracks all live instances. The pointers are non-owning, the PluginInstance
- // destructor will notify us when the instance is deleted.
- typedef std::map<PP_Instance, PluginInstance*> InstanceMap;
- InstanceMap instance_map_;
-
- // Tracks all live modules. The pointers are non-owning, the PluginModule
- // destructor will notify us when the module is deleted.
- typedef std::map<PP_Module, PluginModule*> ModuleMap;
- ModuleMap module_map_;
-
- DISALLOW_COPY_AND_ASSIGN(ResourceTracker);
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_RESOURCE_TRACKER_H_
diff --git a/webkit/glue/plugins/pepper_scrollbar.cc b/webkit/glue/plugins/pepper_scrollbar.cc
deleted file mode 100644
index 2b96259..0000000
--- a/webkit/glue/plugins/pepper_scrollbar.cc
+++ /dev/null
@@ -1,242 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_scrollbar.h"
-
-#include "base/logging.h"
-#include "base/message_loop.h"
-#include "ppapi/c/dev/ppp_scrollbar_dev.h"
-#include "skia/ext/platform_canvas.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebRect.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebScrollbar.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebVector.h"
-#include "webkit/glue/plugins/pepper_common.h"
-#include "webkit/glue/plugins/pepper_event_conversion.h"
-#include "webkit/glue/plugins/pepper_image_data.h"
-#include "webkit/glue/plugins/pepper_plugin_instance.h"
-#include "webkit/glue/plugins/pepper_plugin_module.h"
-#include "webkit/glue/webkit_glue.h"
-
-#if defined(OS_WIN)
-#include "base/win/windows_version.h"
-#endif
-
-using WebKit::WebInputEvent;
-using WebKit::WebRect;
-using WebKit::WebScrollbar;
-
-namespace pepper {
-
-namespace {
-
-PP_Resource Create(PP_Instance instance_id, PP_Bool vertical) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return 0;
-
- scoped_refptr<Scrollbar> scrollbar(new Scrollbar(instance,
- PPBoolToBool(vertical)));
- return scrollbar->GetReference();
-}
-
-PP_Bool IsScrollbar(PP_Resource resource) {
- return BoolToPPBool(!!Resource::GetAs<Scrollbar>(resource));
-}
-
-uint32_t GetThickness() {
- return WebScrollbar::defaultThickness();
-}
-
-uint32_t GetValue(PP_Resource resource) {
- scoped_refptr<Scrollbar> scrollbar(Resource::GetAs<Scrollbar>(resource));
- if (!scrollbar)
- return 0;
- return scrollbar->GetValue();
-}
-
-void SetValue(PP_Resource resource, uint32_t value) {
- scoped_refptr<Scrollbar> scrollbar(Resource::GetAs<Scrollbar>(resource));
- if (scrollbar)
- scrollbar->SetValue(value);
-}
-
-void SetDocumentSize(PP_Resource resource, uint32_t size) {
- scoped_refptr<Scrollbar> scrollbar(Resource::GetAs<Scrollbar>(resource));
- if (scrollbar)
- scrollbar->SetDocumentSize(size);
-}
-
-void SetTickMarks(PP_Resource resource,
- const PP_Rect* tick_marks,
- uint32_t count) {
- scoped_refptr<Scrollbar> scrollbar(Resource::GetAs<Scrollbar>(resource));
- if (scrollbar)
- scrollbar->SetTickMarks(tick_marks, count);
-}
-
-void ScrollBy(PP_Resource resource, PP_ScrollBy_Dev unit, int32_t multiplier) {
- scoped_refptr<Scrollbar> scrollbar(Resource::GetAs<Scrollbar>(resource));
- if (scrollbar)
- scrollbar->ScrollBy(unit, multiplier);
-}
-
-const PPB_Scrollbar_Dev ppb_scrollbar = {
- &Create,
- &IsScrollbar,
- &GetThickness,
- &GetValue,
- &SetValue,
- &SetDocumentSize,
- &SetTickMarks,
- &ScrollBy
-};
-
-} // namespace
-
-Scrollbar::Scrollbar(PluginInstance* instance, bool vertical)
- : Widget(instance) {
- scrollbar_.reset(WebScrollbar::create(
- static_cast<WebKit::WebScrollbarClient*>(this),
- vertical ? WebScrollbar::Vertical : WebScrollbar::Horizontal));
-}
-
-Scrollbar::~Scrollbar() {
-}
-
-// static
-const PPB_Scrollbar_Dev* Scrollbar::GetInterface() {
- return &ppb_scrollbar;
-}
-
-uint32_t Scrollbar::GetValue() {
- return scrollbar_->value();
-}
-
-void Scrollbar::SetValue(uint32_t value) {
- scrollbar_->setValue(value);
-}
-
-void Scrollbar::SetDocumentSize(uint32_t size) {
- scrollbar_->setDocumentSize(size);
-}
-
-void Scrollbar::SetTickMarks(const PP_Rect* tick_marks, uint32_t count) {
- tickmarks_.resize(count);
- for (uint32 i = 0; i < count; ++i) {
- tickmarks_[i] = WebRect(tick_marks[i].point.x,
- tick_marks[i].point.y,
- tick_marks[i].size.width,
- tick_marks[i].size.height);;
- }
- PP_Rect rect = location();
- Invalidate(&rect);
-}
-
-void Scrollbar::ScrollBy(PP_ScrollBy_Dev unit, int32_t multiplier) {
- WebScrollbar::ScrollDirection direction = multiplier >= 0 ?
- WebScrollbar::ScrollForward : WebScrollbar::ScrollBackward;
- float fmultiplier = 1.0;
-
- WebScrollbar::ScrollGranularity granularity;
- if (unit == PP_SCROLLBY_LINE) {
- granularity = WebScrollbar::ScrollByLine;
- } else if (unit == PP_SCROLLBY_PAGE) {
- granularity = WebScrollbar::ScrollByPage;
- } else if (unit == PP_SCROLLBY_DOCUMENT) {
- granularity = WebScrollbar::ScrollByDocument;
- } else {
- granularity = WebScrollbar::ScrollByPixel;
- fmultiplier = static_cast<float>(multiplier);
- if (fmultiplier < 0)
- fmultiplier *= -1;
- }
- scrollbar_->scroll(direction, granularity, fmultiplier);
-}
-
-bool Scrollbar::Paint(const PP_Rect* rect, ImageData* image) {
- gfx::Rect gfx_rect(rect->point.x,
- rect->point.y,
- rect->size.width,
- rect->size.height);
- skia::PlatformCanvas* canvas = image->mapped_canvas();
- if (!canvas)
- return false;
- scrollbar_->paint(webkit_glue::ToWebCanvas(canvas), gfx_rect);
-
-#if defined(OS_WIN)
- if (base::win::GetVersion() == base::win::VERSION_XP) {
- canvas->getTopPlatformDevice().makeOpaque(
- gfx_rect.x(), gfx_rect.y(), gfx_rect.width(), gfx_rect.height());
- }
-#endif
-
- return true;
-}
-
-bool Scrollbar::HandleEvent(const PP_InputEvent* event) {
- scoped_ptr<WebInputEvent> web_input_event(CreateWebInputEvent(*event));
- if (!web_input_event.get())
- return false;
-
- return scrollbar_->handleInputEvent(*web_input_event.get());
-}
-
-void Scrollbar::SetLocationInternal(const PP_Rect* location) {
- scrollbar_->setLocation(WebRect(location->point.x,
- location->point.y,
- location->size.width,
- location->size.height));
-}
-
-void Scrollbar::valueChanged(WebKit::WebScrollbar* scrollbar) {
- const PPP_Scrollbar_Dev* ppp_scrollbar =
- static_cast<const PPP_Scrollbar_Dev*>(
- module()->GetPluginInterface(PPP_SCROLLBAR_DEV_INTERFACE));
- if (!ppp_scrollbar)
- return;
- ScopedResourceId resource(this);
- ppp_scrollbar->ValueChanged(
- instance()->pp_instance(), resource.id, scrollbar_->value());
-}
-
-void Scrollbar::invalidateScrollbarRect(WebKit::WebScrollbar* scrollbar,
- const WebKit::WebRect& rect) {
- gfx::Rect gfx_rect(rect.x,
- rect.y,
- rect.width,
- rect.height);
- dirty_ = dirty_.Union(gfx_rect);
- // Can't call into the client to tell them about the invalidate right away,
- // since the Scrollbar code is still in the middle of updating its internal
- // state.
- MessageLoop::current()->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &Scrollbar::NotifyInvalidate));
-}
-
-void Scrollbar::getTickmarks(
- WebKit::WebScrollbar* scrollbar,
- WebKit::WebVector<WebKit::WebRect>* tick_marks) const {
- if (tickmarks_.empty()) {
- WebRect* rects = NULL;
- tick_marks->assign(rects, 0);
- } else {
- tick_marks->assign(&tickmarks_[0], tickmarks_.size());
- }
-}
-
-void Scrollbar::NotifyInvalidate() {
- if (dirty_.IsEmpty())
- return;
- PP_Rect pp_rect;
- pp_rect.point.x = dirty_.x();
- pp_rect.point.y = dirty_.y();
- pp_rect.size.width = dirty_.width();
- pp_rect.size.height = dirty_.height();
- dirty_ = gfx::Rect();
- Invalidate(&pp_rect);
-}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_scrollbar.h b/webkit/glue/plugins/pepper_scrollbar.h
deleted file mode 100644
index c444bb3..0000000
--- a/webkit/glue/plugins/pepper_scrollbar.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_SCROLLBAR_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_SCROLLBAR_H_
-
-#include <vector>
-
-#include "gfx/rect.h"
-#include "ppapi/c/dev/ppb_scrollbar_dev.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebRect.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebScrollbarClient.h"
-#include "webkit/glue/plugins/pepper_widget.h"
-
-namespace pepper {
-
-class PluginInstance;
-
-class Scrollbar : public Widget, public WebKit::WebScrollbarClient {
- public:
- Scrollbar(PluginInstance* instance, bool vertical);
- virtual ~Scrollbar();
-
- // Returns a pointer to the interface implementing PPB_Scrollbar that is
- // exposed to the plugin.
- static const PPB_Scrollbar_Dev* GetInterface();
-
- // Resource overrides.
- Scrollbar* AsScrollbar() { return this; }
-
- // PPB_Scrollbar implementation.
- uint32_t GetValue();
- void SetValue(uint32_t value);
- void SetDocumentSize(uint32_t size);
- void SetTickMarks(const PP_Rect* tick_marks, uint32_t count);
- void ScrollBy(PP_ScrollBy_Dev unit, int32_t multiplier);
-
- // PPB_Widget implementation.
- virtual bool Paint(const PP_Rect* rect, ImageData* image);
- virtual bool HandleEvent(const PP_InputEvent* event);
- virtual void SetLocationInternal(const PP_Rect* location);
-
- private:
- // WebKit::WebScrollbarClient implementation.
- virtual void valueChanged(WebKit::WebScrollbar* scrollbar);
- virtual void invalidateScrollbarRect(WebKit::WebScrollbar* scrollbar,
- const WebKit::WebRect& rect);
- virtual void getTickmarks(
- WebKit::WebScrollbar* scrollbar,
- WebKit::WebVector<WebKit::WebRect>* tick_marks) const;
-
- void NotifyInvalidate();
-
- gfx::Rect dirty_;
- std::vector<WebKit::WebRect> tickmarks_;
- scoped_ptr<WebKit::WebScrollbar> scrollbar_;
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_SCROLLBAR_H_
diff --git a/webkit/glue/plugins/pepper_string.cc b/webkit/glue/plugins/pepper_string.cc
deleted file mode 100644
index 53c8943..0000000
--- a/webkit/glue/plugins/pepper_string.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_string.h"
-
-namespace pepper {
-
-String::String(const char* str, uint32 len) : value_(str, len) {}
-
-String::~String() {}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_string.h b/webkit/glue/plugins/pepper_string.h
deleted file mode 100644
index fa1ab2f..0000000
--- a/webkit/glue/plugins/pepper_string.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_STRING_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_STRING_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/ref_counted.h"
-
-namespace pepper {
-
-class String : public base::RefCountedThreadSafe<String> {
- public:
- String(const char* str, uint32 len);
- virtual ~String();
-
- const std::string& value() const { return value_; }
-
- private:
- std::string value_;
-
- DISALLOW_COPY_AND_ASSIGN(String);
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_STRING_H_
diff --git a/webkit/glue/plugins/pepper_transport.cc b/webkit/glue/plugins/pepper_transport.cc
deleted file mode 100644
index 29a4495..0000000
--- a/webkit/glue/plugins/pepper_transport.cc
+++ /dev/null
@@ -1,140 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_transport.h"
-
-#include "base/singleton.h"
-#include "base/thread_local.h"
-#include "ppapi/c/dev/ppb_transport_dev.h"
-#include "webkit/glue/plugins/pepper_common.h"
-#include "webkit/glue/plugins/pepper_plugin_instance.h"
-#include "webkit/glue/plugins/pepper_plugin_module.h"
-
-namespace pepper {
-
-namespace {
-
-// Creates a new transport object with the specified name
-// using the specified protocol.
-PP_Resource CreateTransport(PP_Module module,
- const char* name,
- const char* proto) {
- // TODO(juberti): implement me
- PP_Resource p(0);
- return p;
-}
-
-// Returns whether or not resource is Transport
-PP_Bool IsTransport(PP_Resource resource) {
- return BoolToPPBool(!!Resource::GetAs<Transport>(resource));
-}
-
-// Returns whether the transport is currently writable
-// (i.e. can send data to the remote peer)
-PP_Bool IsWritable(PP_Resource transport) {
- // TODO(juberti): impelement me
- return PP_FALSE;
-}
-
-
-// TODO(juberti): other getters/setters
-// connect state
-// connect type, protocol
-// RTT
-
-
-// Establishes a connection to the remote peer.
-// Returns PP_ERROR_WOULDBLOCK and notifies on |cb|
-// when connectivity is established (or timeout occurs).
-int32_t Connect(PP_Resource transport,
- PP_CompletionCallback cb) {
- // TODO(juberti): impelement me
- return 0;
-}
-
-
-// Obtains another ICE candidate address to be provided
-// to the remote peer. Returns PP_ERROR_WOULDBLOCK
-// if there are no more addresses to be sent.
-int32_t GetNextAddress(PP_Resource transport,
- PP_Var* address,
- PP_CompletionCallback cb) {
- // TODO(juberti): implement me
- return 0;
-}
-
-
-// Provides an ICE candidate address that was received
-// from the remote peer.
-int32_t ReceiveRemoteAddress(PP_Resource transport,
- PP_Var address) {
- // TODO(juberti): implement me
- return 0;
-}
-
-
-// Like recv(), receives data. Returns PP_ERROR_WOULDBLOCK
-// if there is currently no data to receive.
-int32_t Recv(PP_Resource transport,
- void* data,
- uint32_t len,
- PP_CompletionCallback cb) {
- // TODO(juberti): implement me
- return 0;
-}
-
-
-// Like send(), sends data. Returns PP_ERROR_WOULDBLOCK
-// if the socket is currently flow-controlled.
-int32_t Send(PP_Resource transport,
- const void* data,
- uint32_t len,
- PP_CompletionCallback cb) {
- // TODO(juberti): implement me
- return 0;
-}
-
-
-// Disconnects from the remote peer.
-int32_t Close(PP_Resource transport) {
- // TODO(juberti): implement me
- return 0;
-}
-
-
-const PPB_Transport_Dev ppb_transport = {
- &CreateTransport,
- &IsTransport,
- &IsWritable,
- &Connect,
- &GetNextAddress,
- &ReceiveRemoteAddress,
- &Recv,
- &Send,
- &Close,
-};
-
-} // namespace
-
-Transport::Transport(PluginModule* module)
- : Resource(module) {
- // TODO(juberti): impl
-}
-
-const PPB_Transport_Dev* Transport::GetInterface() {
- return &ppb_transport;
-}
-
-Transport::~Transport() {
- // TODO(juberti): teardown
-}
-
-bool Transport::Init(const char* name,
- const char* proto) {
- // TODO(juberti): impl
- return false;
-}
-
-} // namespace pepper
-
diff --git a/webkit/glue/plugins/pepper_transport.h b/webkit/glue/plugins/pepper_transport.h
deleted file mode 100644
index fbba691..0000000
--- a/webkit/glue/plugins/pepper_transport.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_TRANSPORT_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_TRANSPORT_H_
-
-#include "base/scoped_ptr.h"
-#include "ppapi/c/pp_instance.h"
-#include "webkit/glue/plugins/pepper_plugin_delegate.h"
-#include "webkit/glue/plugins/pepper_resource.h"
-
-struct PPB_Transport_Dev;
-
-namespace pepper {
-
-class Transport : public Resource {
- public:
- explicit Transport(PluginModule* module);
- virtual ~Transport();
- static const PPB_Transport_Dev* GetInterface();
- virtual Transport* AsTransport() {
- return this;
- }
- bool Init(const char* name,
- const char* proto);
- private:
-
- DISALLOW_COPY_AND_ASSIGN(Transport);
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_TRANSPORT_H_
-
diff --git a/webkit/glue/plugins/pepper_url_loader.cc b/webkit/glue/plugins/pepper_url_loader.cc
deleted file mode 100644
index 2d94172..0000000
--- a/webkit/glue/plugins/pepper_url_loader.cc
+++ /dev/null
@@ -1,532 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_url_loader.h"
-
-#include "base/logging.h"
-#include "ppapi/c/pp_completion_callback.h"
-#include "ppapi/c/pp_errors.h"
-#include "ppapi/c/ppb_url_loader.h"
-#include "ppapi/c/trusted/ppb_url_loader_trusted.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebDocument.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebElement.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebKit.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebKitClient.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebPluginContainer.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebSecurityOrigin.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebURLLoader.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebURLRequest.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebURLResponse.h"
-#include "webkit/appcache/web_application_cache_host_impl.h"
-#include "webkit/glue/plugins/pepper_common.h"
-#include "webkit/glue/plugins/pepper_plugin_instance.h"
-#include "webkit/glue/plugins/pepper_url_request_info.h"
-#include "webkit/glue/plugins/pepper_url_response_info.h"
-
-using appcache::WebApplicationCacheHostImpl;
-using WebKit::WebFrame;
-using WebKit::WebString;
-using WebKit::WebURL;
-using WebKit::WebURLError;
-using WebKit::WebURLLoader;
-using WebKit::WebURLRequest;
-using WebKit::WebURLResponse;
-
-#ifdef _MSC_VER
-// Do not warn about use of std::copy with raw pointers.
-#pragma warning(disable : 4996)
-#endif
-
-namespace pepper {
-
-namespace {
-
-PP_Resource Create(PP_Instance instance_id) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return 0;
-
- URLLoader* loader = new URLLoader(instance, false);
- return loader->GetReference();
-}
-
-PP_Bool IsURLLoader(PP_Resource resource) {
- return BoolToPPBool(!!Resource::GetAs<URLLoader>(resource));
-}
-
-int32_t Open(PP_Resource loader_id,
- PP_Resource request_id,
- PP_CompletionCallback callback) {
- scoped_refptr<URLLoader> loader(Resource::GetAs<URLLoader>(loader_id));
- if (!loader)
- return PP_ERROR_BADRESOURCE;
-
- scoped_refptr<URLRequestInfo> request(
- Resource::GetAs<URLRequestInfo>(request_id));
- if (!request)
- return PP_ERROR_BADRESOURCE;
-
- return loader->Open(request, callback);
-}
-
-int32_t FollowRedirect(PP_Resource loader_id,
- PP_CompletionCallback callback) {
- scoped_refptr<URLLoader> loader(Resource::GetAs<URLLoader>(loader_id));
- if (!loader)
- return PP_ERROR_BADRESOURCE;
-
- return loader->FollowRedirect(callback);
-}
-
-PP_Bool GetUploadProgress(PP_Resource loader_id,
- int64_t* bytes_sent,
- int64_t* total_bytes_to_be_sent) {
- scoped_refptr<URLLoader> loader(Resource::GetAs<URLLoader>(loader_id));
- if (!loader)
- return PP_FALSE;
-
- return BoolToPPBool(loader->GetUploadProgress(bytes_sent,
- total_bytes_to_be_sent));
-}
-
-PP_Bool GetDownloadProgress(PP_Resource loader_id,
- int64_t* bytes_received,
- int64_t* total_bytes_to_be_received) {
- scoped_refptr<URLLoader> loader(Resource::GetAs<URLLoader>(loader_id));
- if (!loader)
- return PP_FALSE;
-
- return BoolToPPBool(loader->GetDownloadProgress(bytes_received,
- total_bytes_to_be_received));
-}
-
-PP_Resource GetResponseInfo(PP_Resource loader_id) {
- scoped_refptr<URLLoader> loader(Resource::GetAs<URLLoader>(loader_id));
- if (!loader)
- return 0;
-
- URLResponseInfo* response_info = loader->response_info();
- if (!response_info)
- return 0;
-
- return response_info->GetReference();
-}
-
-int32_t ReadResponseBody(PP_Resource loader_id,
- char* buffer,
- int32_t bytes_to_read,
- PP_CompletionCallback callback) {
- scoped_refptr<URLLoader> loader(Resource::GetAs<URLLoader>(loader_id));
- if (!loader)
- return PP_ERROR_BADRESOURCE;
-
- return loader->ReadResponseBody(buffer, bytes_to_read, callback);
-}
-
-int32_t FinishStreamingToFile(PP_Resource loader_id,
- PP_CompletionCallback callback) {
- scoped_refptr<URLLoader> loader(Resource::GetAs<URLLoader>(loader_id));
- if (!loader)
- return PP_ERROR_BADRESOURCE;
-
- return loader->FinishStreamingToFile(callback);
-}
-
-void Close(PP_Resource loader_id) {
- scoped_refptr<URLLoader> loader(Resource::GetAs<URLLoader>(loader_id));
- if (!loader)
- return;
-
- loader->Close();
-}
-
-const PPB_URLLoader ppb_urlloader = {
- &Create,
- &IsURLLoader,
- &Open,
- &FollowRedirect,
- &GetUploadProgress,
- &GetDownloadProgress,
- &GetResponseInfo,
- &ReadResponseBody,
- &FinishStreamingToFile,
- &Close
-};
-
-void GrantUniversalAccess(PP_Resource loader_id) {
- scoped_refptr<URLLoader> loader(Resource::GetAs<URLLoader>(loader_id));
- if (!loader)
- return;
-
- loader->GrantUniversalAccess();
-}
-
-void SetStatusCallback(PP_Resource loader_id,
- PP_URLLoaderTrusted_StatusCallback cb) {
- scoped_refptr<URLLoader> loader(Resource::GetAs<URLLoader>(loader_id));
- if (!loader)
- return;
- loader->SetStatusCallback(cb);
-}
-
-const PPB_URLLoaderTrusted ppb_urlloadertrusted = {
- &GrantUniversalAccess,
- &SetStatusCallback
-};
-
-WebKit::WebFrame* GetFrame(PluginInstance* instance) {
- return instance->container()->element().document().frame();
-}
-
-} // namespace
-
-URLLoader::URLLoader(PluginInstance* instance, bool main_document_loader)
- : Resource(instance->module()),
- instance_(instance),
- main_document_loader_(main_document_loader),
- pending_callback_(),
- bytes_sent_(0),
- total_bytes_to_be_sent_(-1),
- bytes_received_(0),
- total_bytes_to_be_received_(-1),
- user_buffer_(NULL),
- user_buffer_size_(0),
- done_status_(PP_ERROR_WOULDBLOCK),
- has_universal_access_(false),
- status_callback_(NULL) {
- instance->AddObserver(this);
-}
-
-URLLoader::~URLLoader() {
- if (instance_)
- instance_->RemoveObserver(this);
-}
-
-// static
-const PPB_URLLoader* URLLoader::GetInterface() {
- return &ppb_urlloader;
-}
-
-// static
-const PPB_URLLoaderTrusted* URLLoader::GetTrustedInterface() {
- return &ppb_urlloadertrusted;
-}
-
-int32_t URLLoader::Open(URLRequestInfo* request,
- PP_CompletionCallback callback) {
- if (loader_.get())
- return PP_ERROR_INPROGRESS;
-
- // We only support non-blocking calls.
- if (!callback.func)
- return PP_ERROR_BADARGUMENT;
-
- WebFrame* frame = GetFrame(instance_);
- if (!frame)
- return PP_ERROR_FAILED;
- WebURLRequest web_request(request->ToWebURLRequest(frame));
-
- int32_t rv = CanRequest(frame, web_request.url());
- if (rv != PP_OK)
- return rv;
-
- frame->dispatchWillSendRequest(web_request);
-
- // Sets the appcache host id to allow retrieval from the appcache.
- if (WebApplicationCacheHostImpl* appcache_host =
- WebApplicationCacheHostImpl::FromFrame(frame)) {
- appcache_host->willStartSubResourceRequest(web_request);
- }
-
- loader_.reset(WebKit::webKitClient()->createURLLoader());
- if (!loader_.get())
- return PP_ERROR_FAILED;
-
- loader_->loadAsynchronously(web_request, this);
-
- request_info_ = scoped_refptr<URLRequestInfo>(request);
- pending_callback_ = callback;
-
- // Notify completion when we receive a redirect or response headers.
- return PP_ERROR_WOULDBLOCK;
-}
-
-int32_t URLLoader::FollowRedirect(PP_CompletionCallback callback) {
- if (pending_callback_.func)
- return PP_ERROR_INPROGRESS;
-
- // We only support non-blocking calls.
- if (!callback.func)
- return PP_ERROR_BADARGUMENT;
-
- WebURL redirect_url = GURL(response_info_->redirect_url());
-
- int32_t rv = CanRequest(GetFrame(instance_), redirect_url);
- if (rv != PP_OK)
- return rv;
-
- pending_callback_ = callback;
- loader_->setDefersLoading(false); // Allow the redirect to continue.
- return PP_ERROR_WOULDBLOCK;
-}
-
-bool URLLoader::GetUploadProgress(int64_t* bytes_sent,
- int64_t* total_bytes_to_be_sent) {
- if (!RecordUploadProgress()) {
- *bytes_sent = 0;
- *total_bytes_to_be_sent = 0;
- return false;
- }
- *bytes_sent = bytes_sent_;
- *total_bytes_to_be_sent = total_bytes_to_be_sent_;
- return true;
-}
-
-bool URLLoader::GetDownloadProgress(int64_t* bytes_received,
- int64_t* total_bytes_to_be_received) {
- if (!RecordDownloadProgress()) {
- *bytes_received = 0;
- *total_bytes_to_be_received = 0;
- return false;
- }
- *bytes_received = bytes_received_;
- *total_bytes_to_be_received = total_bytes_to_be_received_;
- return true;
-}
-
-int32_t URLLoader::ReadResponseBody(char* buffer, int32_t bytes_to_read,
- PP_CompletionCallback callback) {
- if (!response_info_ || response_info_->body())
- return PP_ERROR_FAILED;
- if (bytes_to_read <= 0 || !buffer)
- return PP_ERROR_BADARGUMENT;
- if (pending_callback_.func)
- return PP_ERROR_INPROGRESS;
-
- // We only support non-blocking calls.
- if (!callback.func)
- return PP_ERROR_BADARGUMENT;
-
- user_buffer_ = buffer;
- user_buffer_size_ = bytes_to_read;
-
- if (!buffer_.empty())
- return FillUserBuffer();
-
- // We may have already reached EOF.
- if (done_status_ != PP_ERROR_WOULDBLOCK) {
- user_buffer_ = NULL;
- user_buffer_size_ = 0;
- return done_status_;
- }
-
- pending_callback_ = callback;
- return PP_ERROR_WOULDBLOCK;
-}
-
-int32_t URLLoader::FinishStreamingToFile(PP_CompletionCallback callback) {
- if (!response_info_ || !response_info_->body())
- return PP_ERROR_FAILED;
- if (pending_callback_.func)
- return PP_ERROR_INPROGRESS;
-
- // We may have already reached EOF.
- if (done_status_ != PP_ERROR_WOULDBLOCK)
- return done_status_;
-
- // Wait for didFinishLoading / didFail.
- pending_callback_ = callback;
- return PP_ERROR_WOULDBLOCK;
-}
-
-void URLLoader::Close() {
- if (loader_.get()) {
- loader_->cancel();
- } else if (main_document_loader_) {
- WebFrame* frame = instance_->container()->element().document().frame();
- frame->stopLoading();
- }
-}
-
-void URLLoader::GrantUniversalAccess() {
- has_universal_access_ = true;
-}
-
-void URLLoader::SetStatusCallback(PP_URLLoaderTrusted_StatusCallback cb) {
- status_callback_ = cb;
-}
-
-void URLLoader::willSendRequest(WebURLLoader* loader,
- WebURLRequest& new_request,
- const WebURLResponse& redirect_response) {
- if (!request_info_->follow_redirects()) {
- SaveResponse(redirect_response);
- loader_->setDefersLoading(true);
- RunCallback(PP_OK);
- } else {
- int32_t rv = CanRequest(GetFrame(instance_), new_request.url());
- if (rv != PP_OK) {
- loader_->setDefersLoading(true);
- RunCallback(rv);
- }
- }
-}
-
-void URLLoader::didSendData(WebURLLoader* loader,
- unsigned long long bytes_sent,
- unsigned long long total_bytes_to_be_sent) {
- // TODO(darin): Bounds check input?
- bytes_sent_ = static_cast<int64_t>(bytes_sent);
- total_bytes_to_be_sent_ = static_cast<int64_t>(total_bytes_to_be_sent);
- UpdateStatus();
-}
-
-void URLLoader::didReceiveResponse(WebURLLoader* loader,
- const WebURLResponse& response) {
- SaveResponse(response);
-
- // Sets -1 if the content length is unknown.
- total_bytes_to_be_received_ = response.expectedContentLength();
- UpdateStatus();
-
- RunCallback(PP_OK);
-}
-
-void URLLoader::didDownloadData(WebURLLoader* loader,
- int data_length) {
- bytes_received_ += data_length;
- UpdateStatus();
-}
-
-void URLLoader::didReceiveData(WebURLLoader* loader,
- const char* data,
- int data_length) {
- bytes_received_ += data_length;
-
- buffer_.insert(buffer_.end(), data, data + data_length);
- if (user_buffer_) {
- RunCallback(FillUserBuffer());
- } else {
- DCHECK(!pending_callback_.func);
- }
-}
-
-void URLLoader::didFinishLoading(WebURLLoader* loader, double finish_time) {
- done_status_ = PP_OK;
- RunCallback(done_status_);
-}
-
-void URLLoader::didFail(WebURLLoader* loader, const WebURLError& error) {
- // TODO(darin): Provide more detailed error information.
- done_status_ = PP_ERROR_FAILED;
- RunCallback(done_status_);
-}
-
-void URLLoader::InstanceDestroyed(PluginInstance* instance) {
- // When the instance is destroyed, we force delete any associated loads.
- DCHECK(instance == instance_);
- instance_ = NULL;
-
- // Normally the only ref to this class will be from the plugin which
- // ForceDeletePluginResourceRefs will free. We don't want our object to be
- // deleted out from under us until the function completes.
- scoped_refptr<URLLoader> death_grip(this);
-
- // Force delete any plugin refs to us. If the instance is being deleted, we
- // don't want to allow the requests to continue to use bandwidth and send us
- // callbacks (for which we might have no plugin).
- ResourceTracker *tracker = ResourceTracker::Get();
- PP_Resource loader_resource = GetReferenceNoAddRef();
- if (loader_resource)
- tracker->ForceDeletePluginResourceRefs(loader_resource);
-
- // Also force free the response from the plugin, both the plugin's ref(s)
- // and ours.
- if (response_info_.get()) {
- PP_Resource response_info_resource = response_info_->GetReferenceNoAddRef();
- if (response_info_resource)
- tracker->ForceDeletePluginResourceRefs(response_info_resource);
- response_info_ = NULL;
- }
-
- // Free the WebKit request.
- loader_.reset();
-
- // Often, |this| will be deleted at the end of this function when death_grip
- // goes out of scope.
-}
-
-void URLLoader::RunCallback(int32_t result) {
- if (!pending_callback_.func)
- return;
-
- PP_CompletionCallback callback = {0};
- std::swap(callback, pending_callback_);
- PP_RunCompletionCallback(&callback, result);
-}
-
-size_t URLLoader::FillUserBuffer() {
- DCHECK(user_buffer_);
- DCHECK(user_buffer_size_);
-
- size_t bytes_to_copy = std::min(buffer_.size(), user_buffer_size_);
- std::copy(buffer_.begin(), buffer_.begin() + bytes_to_copy, user_buffer_);
- buffer_.erase(buffer_.begin(), buffer_.begin() + bytes_to_copy);
-
- // Reset for next time.
- user_buffer_ = NULL;
- user_buffer_size_ = 0;
- return bytes_to_copy;
-}
-
-void URLLoader::SaveResponse(const WebKit::WebURLResponse& response) {
- scoped_refptr<URLResponseInfo> response_info(new URLResponseInfo(module()));
- if (response_info->Initialize(response))
- response_info_ = response_info;
-}
-
-// Checks that the client can request the URL. Returns a PPAPI error code.
-int32_t URLLoader::CanRequest(const WebKit::WebFrame* frame,
- const WebKit::WebURL& url) {
- if (!has_universal_access_ &&
- !frame->securityOrigin().canRequest(url))
- return PP_ERROR_NOACCESS;
-
- return PP_OK;
-}
-
-void URLLoader::UpdateStatus() {
- if (status_callback_ &&
- (RecordDownloadProgress() || RecordUploadProgress())) {
- PP_Resource pp_resource = GetReferenceNoAddRef();
- if (pp_resource) {
- // The PP_Resource on the plugin will be NULL if the plugin has no
- // reference to this object. That's fine, because then we don't need to
- // call UpdateStatus.
- //
- // Here we go through some effort to only send the exact information that
- // the requestor wanted in the request flags. It would be just as
- // efficient to send all of it, but we don't want people to rely on
- // getting download progress when they happen to set the upload progress
- // flag.
- status_callback_(
- instance_->pp_instance(), pp_resource,
- RecordUploadProgress() ? bytes_sent_ : -1,
- RecordUploadProgress() ? total_bytes_to_be_sent_ : -1,
- RecordDownloadProgress() ? bytes_received_ : -1,
- RecordDownloadProgress() ? total_bytes_to_be_received_ : -1);
- }
- }
-}
-
-bool URLLoader::RecordDownloadProgress() const {
- return request_info_ && request_info_->record_download_progress();
-}
-
-bool URLLoader::RecordUploadProgress() const {
- return request_info_ && request_info_->record_upload_progress();
-}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_url_loader.h b/webkit/glue/plugins/pepper_url_loader.h
deleted file mode 100644
index ee8ddd7..0000000
--- a/webkit/glue/plugins/pepper_url_loader.h
+++ /dev/null
@@ -1,140 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_URL_LOADER_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_URL_LOADER_H_
-
-#include <deque>
-
-#include "base/scoped_ptr.h"
-#include "ppapi/c/pp_completion_callback.h"
-#include "ppapi/c/trusted/ppb_url_loader_trusted.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebURLLoaderClient.h"
-#include "webkit/glue/plugins/pepper_plugin_instance.h"
-#include "webkit/glue/plugins/pepper_resource.h"
-
-struct PPB_URLLoader;
-struct PPB_URLLoaderTrusted;
-
-namespace WebKit {
-class WebFrame;
-class WebURL;
-}
-
-namespace pepper {
-
-class PluginInstance;
-class URLRequestInfo;
-class URLResponseInfo;
-
-class URLLoader : public Resource,
- public WebKit::WebURLLoaderClient,
- public PluginInstance::Observer {
- public:
- URLLoader(PluginInstance* instance, bool main_document_loader);
- virtual ~URLLoader();
-
- // Returns a pointer to the interface implementing PPB_URLLoader that is
- // exposed to the plugin.
- static const PPB_URLLoader* GetInterface();
-
- // Returns a pointer to the interface implementing PPB_URLLoaderTrusted that
- // is exposed to the plugin.
- static const PPB_URLLoaderTrusted* GetTrustedInterface();
-
- // Resource overrides.
- URLLoader* AsURLLoader() { return this; }
-
- // PPB_URLLoader implementation.
- int32_t Open(URLRequestInfo* request, PP_CompletionCallback callback);
- int32_t FollowRedirect(PP_CompletionCallback callback);
- bool GetUploadProgress(int64_t* bytes_sent,
- int64_t* total_bytes_to_be_sent);
- bool GetDownloadProgress(int64_t* bytes_received,
- int64_t* total_bytes_to_be_received);
- int32_t ReadResponseBody(char* buffer, int32_t bytes_to_read,
- PP_CompletionCallback callback);
- int32_t FinishStreamingToFile(PP_CompletionCallback callback);
- void Close();
-
- // PPB_URLLoaderTrusted implementation.
- void GrantUniversalAccess();
- void SetStatusCallback(PP_URLLoaderTrusted_StatusCallback cb);
-
- // WebKit::WebURLLoaderClient implementation.
- virtual void willSendRequest(WebKit::WebURLLoader* loader,
- WebKit::WebURLRequest& new_request,
- const WebKit::WebURLResponse& redir_response);
- virtual void didSendData(WebKit::WebURLLoader* loader,
- unsigned long long bytes_sent,
- unsigned long long total_bytes_to_be_sent);
- virtual void didReceiveResponse(WebKit::WebURLLoader* loader,
- const WebKit::WebURLResponse& response);
- virtual void didDownloadData(WebKit::WebURLLoader* loader,
- int data_length);
- virtual void didReceiveData(WebKit::WebURLLoader* loader,
- const char* data,
- int data_length);
- virtual void didFinishLoading(WebKit::WebURLLoader* loader,
- double finish_time);
- virtual void didFail(WebKit::WebURLLoader* loader,
- const WebKit::WebURLError& error);
-
- // PluginInstance::Observer implementation.
- void InstanceDestroyed(PluginInstance* instance);
-
- URLResponseInfo* response_info() const { return response_info_; }
-
- private:
- void RunCallback(int32_t result);
- size_t FillUserBuffer();
-
- // Converts a WebURLResponse to a URLResponseInfo and saves it.
- void SaveResponse(const WebKit::WebURLResponse& response);
-
- int32_t CanRequest(const WebKit::WebFrame* frame, const WebKit::WebURL& url);
-
- // Calls the status_callback_ (if any) with the current upload and download
- // progress. Call this function if you update any of these values to
- // synchronize an out-of-process plugin's state.
- void UpdateStatus();
-
- // Returns true if the plugin has requested we record download or upload
- // progress. When false, we don't need to update the counters. We go out of
- // our way not to allow access to this information unless it's requested,
- // even when it would be easier just to return it and not check, so that
- // plugins don't depend on access without setting the flag.
- bool RecordDownloadProgress() const;
- bool RecordUploadProgress() const;
-
- // This will be NULL if the instance has been deleted but this URLLoader was
- // somehow leaked. In general, you should not need to check this for NULL.
- // However, if you see a NULL pointer crash, that means somebody is holding
- // a reference to this object longer than the PluginInstance's lifetime.
- PluginInstance* instance_;
-
- // If true, then the plugin instance is a full-frame plugin and we're just
- // wrapping the main document's loader (i.e. loader_ is null).
- bool main_document_loader_;
- scoped_ptr<WebKit::WebURLLoader> loader_;
- scoped_refptr<URLRequestInfo> request_info_;
- scoped_refptr<URLResponseInfo> response_info_;
- PP_CompletionCallback pending_callback_;
- std::deque<char> buffer_;
- int64_t bytes_sent_;
- int64_t total_bytes_to_be_sent_;
- int64_t bytes_received_;
- int64_t total_bytes_to_be_received_;
- char* user_buffer_;
- size_t user_buffer_size_;
- int32_t done_status_;
-
- bool has_universal_access_;
-
- PP_URLLoaderTrusted_StatusCallback status_callback_;
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_URL_LOADER_H_
diff --git a/webkit/glue/plugins/pepper_url_request_info.cc b/webkit/glue/plugins/pepper_url_request_info.cc
deleted file mode 100644
index f606509..0000000
--- a/webkit/glue/plugins/pepper_url_request_info.cc
+++ /dev/null
@@ -1,278 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_url_request_info.h"
-
-#include "base/logging.h"
-#include "base/string_util.h"
-#include "googleurl/src/gurl.h"
-#include "net/http/http_util.h"
-#include "ppapi/c/pp_var.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebData.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebDocument.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebHTTPBody.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebURL.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebURLRequest.h"
-#include "webkit/glue/plugins/pepper_common.h"
-#include "webkit/glue/plugins/pepper_file_ref.h"
-#include "webkit/glue/plugins/pepper_plugin_module.h"
-#include "webkit/glue/plugins/pepper_string.h"
-#include "webkit/glue/plugins/pepper_var.h"
-#include "webkit/glue/webkit_glue.h"
-
-using WebKit::WebData;
-using WebKit::WebHTTPBody;
-using WebKit::WebString;
-using WebKit::WebFrame;
-using WebKit::WebURL;
-using WebKit::WebURLRequest;
-
-namespace pepper {
-
-namespace {
-
-// If any of these request headers are specified, they will not be sent.
-// TODO(darin): Add more based on security considerations?
-const char* const kIgnoredRequestHeaders[] = {
- "content-length"
-};
-
-PP_Bool IsIgnoredRequestHeader(const std::string& name) {
- for (size_t i = 0; i < arraysize(kIgnoredRequestHeaders); ++i) {
- if (LowerCaseEqualsASCII(name, kIgnoredRequestHeaders[i]))
- return PP_TRUE;
- }
- return PP_FALSE;
-}
-
-PP_Resource Create(PP_Module module_id) {
- PluginModule* module = ResourceTracker::Get()->GetModule(module_id);
- if (!module)
- return 0;
-
- URLRequestInfo* request = new URLRequestInfo(module);
-
- return request->GetReference();
-}
-
-PP_Bool IsURLRequestInfo(PP_Resource resource) {
- return BoolToPPBool(!!Resource::GetAs<URLRequestInfo>(resource));
-}
-
-PP_Bool SetProperty(PP_Resource request_id,
- PP_URLRequestProperty property,
- PP_Var var) {
- scoped_refptr<URLRequestInfo> request(
- Resource::GetAs<URLRequestInfo>(request_id));
- if (!request)
- return PP_FALSE;
-
- if (var.type == PP_VARTYPE_BOOL) {
- return BoolToPPBool(
- request->SetBooleanProperty(property,
- PPBoolToBool(var.value.as_bool)));
- }
-
- if (var.type == PP_VARTYPE_STRING) {
- scoped_refptr<StringVar> string(StringVar::FromPPVar(var));
- if (string) {
- return BoolToPPBool(request->SetStringProperty(property,
- string->value()));
- }
- }
-
- return PP_FALSE;
-}
-
-PP_Bool AppendDataToBody(PP_Resource request_id,
- const char* data,
- uint32_t len) {
- scoped_refptr<URLRequestInfo> request(
- Resource::GetAs<URLRequestInfo>(request_id));
- if (!request)
- return PP_FALSE;
-
- return BoolToPPBool(request->AppendDataToBody(std::string(data, len)));
-}
-
-PP_Bool AppendFileToBody(PP_Resource request_id,
- PP_Resource file_ref_id,
- int64_t start_offset,
- int64_t number_of_bytes,
- PP_Time expected_last_modified_time) {
- scoped_refptr<URLRequestInfo> request(
- Resource::GetAs<URLRequestInfo>(request_id));
- if (!request)
- return PP_FALSE;
-
- scoped_refptr<FileRef> file_ref(Resource::GetAs<FileRef>(file_ref_id));
- if (!file_ref)
- return PP_FALSE;
-
- return BoolToPPBool(request->AppendFileToBody(file_ref,
- start_offset,
- number_of_bytes,
- expected_last_modified_time));
-}
-
-const PPB_URLRequestInfo ppb_urlrequestinfo = {
- &Create,
- &IsURLRequestInfo,
- &SetProperty,
- &AppendDataToBody,
- &AppendFileToBody
-};
-
-} // namespace
-
-struct URLRequestInfo::BodyItem {
- BodyItem(const std::string& data)
- : data(data),
- start_offset(0),
- number_of_bytes(-1),
- expected_last_modified_time(0.0) {
- }
-
- BodyItem(FileRef* file_ref,
- int64_t start_offset,
- int64_t number_of_bytes,
- PP_Time expected_last_modified_time)
- : file_ref(file_ref),
- start_offset(start_offset),
- number_of_bytes(number_of_bytes),
- expected_last_modified_time(expected_last_modified_time) {
- }
-
- std::string data;
- scoped_refptr<FileRef> file_ref;
- int64_t start_offset;
- int64_t number_of_bytes;
- PP_Time expected_last_modified_time;
-};
-
-URLRequestInfo::URLRequestInfo(PluginModule* module)
- : Resource(module),
- stream_to_file_(false),
- follow_redirects_(true),
- record_download_progress_(false),
- record_upload_progress_(false) {
-}
-
-URLRequestInfo::~URLRequestInfo() {
-}
-
-// static
-const PPB_URLRequestInfo* URLRequestInfo::GetInterface() {
- return &ppb_urlrequestinfo;
-}
-
-bool URLRequestInfo::SetBooleanProperty(PP_URLRequestProperty property,
- bool value) {
- switch (property) {
- case PP_URLREQUESTPROPERTY_STREAMTOFILE:
- stream_to_file_ = value;
- return true;
- case PP_URLREQUESTPROPERTY_FOLLOWREDIRECTS:
- follow_redirects_ = value;
- return true;
- case PP_URLREQUESTPROPERTY_RECORDDOWNLOADPROGRESS:
- record_download_progress_ = value;
- return true;
- case PP_URLREQUESTPROPERTY_RECORDUPLOADPROGRESS:
- record_upload_progress_ = value;
- return true;
- default:
- //NOTIMPLEMENTED(); // TODO(darin): Implement me!
- return false;
- }
-}
-
-bool URLRequestInfo::SetStringProperty(PP_URLRequestProperty property,
- const std::string& value) {
- // TODO(darin): Validate input. Perhaps at a different layer?
- switch (property) {
- case PP_URLREQUESTPROPERTY_URL:
- url_ = value; // NOTE: This may be a relative URL.
- return true;
- case PP_URLREQUESTPROPERTY_METHOD:
- method_ = value;
- return true;
- case PP_URLREQUESTPROPERTY_HEADERS:
- headers_ = value;
- return true;
- default:
- return false;
- }
-}
-
-bool URLRequestInfo::AppendDataToBody(const std::string& data) {
- if (!data.empty())
- body_.push_back(BodyItem(data));
- return true;
-}
-
-bool URLRequestInfo::AppendFileToBody(FileRef* file_ref,
- int64_t start_offset,
- int64_t number_of_bytes,
- PP_Time expected_last_modified_time) {
- // Ignore a call to append nothing.
- if (number_of_bytes == 0)
- return true;
-
- // Check for bad values. (-1 means read until end of file.)
- if (start_offset < 0 || number_of_bytes < -1)
- return false;
-
- body_.push_back(BodyItem(file_ref,
- start_offset,
- number_of_bytes,
- expected_last_modified_time));
- return true;
-}
-
-WebURLRequest URLRequestInfo::ToWebURLRequest(WebFrame* frame) const {
- WebURLRequest web_request;
- web_request.initialize();
- web_request.setURL(frame->document().completeURL(WebString::fromUTF8(url_)));
- web_request.setDownloadToFile(stream_to_file_);
-
- if (!method_.empty())
- web_request.setHTTPMethod(WebString::fromUTF8(method_));
-
- if (!headers_.empty()) {
- net::HttpUtil::HeadersIterator it(headers_.begin(), headers_.end(), "\n");
- while (it.GetNext()) {
- if (!IsIgnoredRequestHeader(it.name())) {
- web_request.addHTTPHeaderField(
- WebString::fromUTF8(it.name()),
- WebString::fromUTF8(it.values()));
- }
- }
- }
-
- if (!body_.empty()) {
- WebHTTPBody http_body;
- http_body.initialize();
- for (size_t i = 0; i < body_.size(); ++i) {
- if (body_[i].file_ref) {
- http_body.appendFileRange(
- webkit_glue::FilePathToWebString(
- body_[i].file_ref->GetSystemPath()),
- body_[i].start_offset,
- body_[i].number_of_bytes,
- body_[i].expected_last_modified_time);
- } else {
- DCHECK(!body_[i].data.empty());
- http_body.appendData(WebData(body_[i].data));
- }
- }
- web_request.setHTTPBody(http_body);
- }
-
- frame->setReferrerForRequest(web_request, WebURL()); // Use default.
- return web_request;
-}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_url_request_info.h b/webkit/glue/plugins/pepper_url_request_info.h
deleted file mode 100644
index 7aa9fc1..0000000
--- a/webkit/glue/plugins/pepper_url_request_info.h
+++ /dev/null
@@ -1,69 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_URL_REQUEST_INFO_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_URL_REQUEST_INFO_H_
-
-#include <string>
-#include <vector>
-
-#include "base/ref_counted.h"
-#include "ppapi/c/ppb_url_request_info.h"
-#include "webkit/glue/plugins/pepper_file_ref.h"
-#include "webkit/glue/plugins/pepper_resource.h"
-
-namespace WebKit {
-class WebFrame;
-class WebURLRequest;
-}
-
-namespace pepper {
-
-class URLRequestInfo : public Resource {
- public:
- explicit URLRequestInfo(PluginModule* module);
- virtual ~URLRequestInfo();
-
- // Returns a pointer to the interface implementing PPB_URLRequestInfo that is
- // exposed to the plugin.
- static const PPB_URLRequestInfo* GetInterface();
-
- // Resource overrides.
- URLRequestInfo* AsURLRequestInfo() { return this; }
-
- // PPB_URLRequestInfo implementation.
- bool SetBooleanProperty(PP_URLRequestProperty property, bool value);
- bool SetStringProperty(PP_URLRequestProperty property,
- const std::string& value);
- bool AppendDataToBody(const std::string& data);
- bool AppendFileToBody(FileRef* file_ref,
- int64_t start_offset,
- int64_t number_of_bytes,
- PP_Time expected_last_modified_time);
-
- WebKit::WebURLRequest ToWebURLRequest(WebKit::WebFrame* frame) const;
-
- bool follow_redirects() { return follow_redirects_; }
-
- bool record_download_progress() const { return record_download_progress_; }
- bool record_upload_progress() const { return record_upload_progress_; }
-
- private:
- struct BodyItem;
- typedef std::vector<BodyItem> Body;
-
- std::string url_;
- std::string method_;
- std::string headers_;
- Body body_;
-
- bool stream_to_file_;
- bool follow_redirects_;
- bool record_download_progress_;
- bool record_upload_progress_;
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_URL_REQUEST_INFO_H_
diff --git a/webkit/glue/plugins/pepper_url_response_info.cc b/webkit/glue/plugins/pepper_url_response_info.cc
deleted file mode 100644
index 5ae484f..0000000
--- a/webkit/glue/plugins/pepper_url_response_info.cc
+++ /dev/null
@@ -1,137 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_url_response_info.h"
-
-#include "base/logging.h"
-#include "ppapi/c/pp_var.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebHTTPHeaderVisitor.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebURL.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebURLResponse.h"
-#include "webkit/glue/plugins/pepper_common.h"
-#include "webkit/glue/plugins/pepper_file_ref.h"
-#include "webkit/glue/plugins/pepper_var.h"
-#include "webkit/glue/webkit_glue.h"
-
-using WebKit::WebHTTPHeaderVisitor;
-using WebKit::WebString;
-using WebKit::WebURLResponse;
-
-namespace pepper {
-
-namespace {
-
-class HeaderFlattener : public WebHTTPHeaderVisitor {
- public:
- const std::string& buffer() const { return buffer_; }
-
- virtual void visitHeader(const WebString& name, const WebString& value) {
- if (!buffer_.empty())
- buffer_.append("\n");
- buffer_.append(name.utf8());
- buffer_.append(": ");
- buffer_.append(value.utf8());
- }
-
- private:
- std::string buffer_;
-};
-
-PP_Bool IsURLResponseInfo(PP_Resource resource) {
- return BoolToPPBool(!!Resource::GetAs<URLResponseInfo>(resource));
-}
-
-PP_Var GetProperty(PP_Resource response_id,
- PP_URLResponseProperty property) {
- scoped_refptr<URLResponseInfo> response(
- Resource::GetAs<URLResponseInfo>(response_id));
- if (!response)
- return PP_MakeUndefined();
-
- return response->GetProperty(property);
-}
-
-PP_Resource GetBody(PP_Resource response_id) {
- scoped_refptr<URLResponseInfo> response(
- Resource::GetAs<URLResponseInfo>(response_id));
- if (!response.get())
- return 0;
-
- FileRef* body = response->body();
- if (!body)
- return 0;
- body->AddRef(); // AddRef for the caller.
-
- return body->GetReference();
-}
-
-const PPB_URLResponseInfo ppb_urlresponseinfo = {
- &IsURLResponseInfo,
- &GetProperty,
- &GetBody
-};
-
-bool IsRedirect(int32_t status) {
- return status >= 300 && status <= 399;
-}
-
-} // namespace
-
-URLResponseInfo::URLResponseInfo(PluginModule* module)
- : Resource(module),
- status_code_(-1) {
-}
-
-URLResponseInfo::~URLResponseInfo() {
-}
-
-// static
-const PPB_URLResponseInfo* URLResponseInfo::GetInterface() {
- return &ppb_urlresponseinfo;
-}
-
-PP_Var URLResponseInfo::GetProperty(PP_URLResponseProperty property) {
- switch (property) {
- case PP_URLRESPONSEPROPERTY_URL:
- return StringVar::StringToPPVar(module(), url_);
- case PP_URLRESPONSEPROPERTY_REDIRECTURL:
- if (IsRedirect(status_code_))
- return StringVar::StringToPPVar(module(), redirect_url_);
- break;
- case PP_URLRESPONSEPROPERTY_REDIRECTMETHOD:
- if (IsRedirect(status_code_))
- return StringVar::StringToPPVar(module(), status_text_);
- break;
- case PP_URLRESPONSEPROPERTY_STATUSCODE:
- return PP_MakeInt32(status_code_);
- case PP_URLRESPONSEPROPERTY_STATUSLINE:
- return StringVar::StringToPPVar(module(), status_text_);
- case PP_URLRESPONSEPROPERTY_HEADERS:
- return StringVar::StringToPPVar(module(), headers_);
- }
- // The default is to return an undefined PP_Var.
- return PP_MakeUndefined();
-}
-
-bool URLResponseInfo::Initialize(const WebURLResponse& response) {
- url_ = response.url().spec();
- status_code_ = response.httpStatusCode();
- status_text_ = response.httpStatusText().utf8();
- if (IsRedirect(status_code_)) {
- redirect_url_ = response.httpHeaderField(
- WebString::fromUTF8("Location")).utf8();
- }
-
- HeaderFlattener flattener;
- response.visitHTTPHeaderFields(&flattener);
- headers_ = flattener.buffer();
-
- WebString file_path = response.downloadFilePath();
- if (!file_path.isEmpty())
- body_ = new FileRef(module(), webkit_glue::WebStringToFilePath(file_path));
- return true;
-}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_url_response_info.h b/webkit/glue/plugins/pepper_url_response_info.h
deleted file mode 100644
index adbf8ef..0000000
--- a/webkit/glue/plugins/pepper_url_response_info.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_URL_RESPONSE_INFO_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_URL_RESPONSE_INFO_H_
-
-#include <string>
-
-#include "ppapi/c/ppb_url_response_info.h"
-#include "webkit/glue/plugins/pepper_resource.h"
-
-namespace WebKit {
-class WebURLResponse;
-}
-
-namespace pepper {
-
-class URLResponseInfo : public Resource {
- public:
- explicit URLResponseInfo(PluginModule* module);
- virtual ~URLResponseInfo();
-
- // Returns a pointer to the interface implementing PPB_URLResponseInfo that
- // is exposed to the plugin.
- static const PPB_URLResponseInfo* GetInterface();
-
- // Resource overrides.
- URLResponseInfo* AsURLResponseInfo() { return this; }
-
- // PPB_URLResponseInfo implementation.
- PP_Var GetProperty(PP_URLResponseProperty property);
-
- bool Initialize(const WebKit::WebURLResponse& response);
-
- FileRef* body() { return body_; }
-
- std::string redirect_url() { return redirect_url_; }
-
- private:
- std::string url_;
- std::string headers_;
- int32_t status_code_;
- std::string status_text_;
- std::string redirect_url_;
- scoped_refptr<FileRef> body_;
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_URL_RESPONSE_INFO_H_
diff --git a/webkit/glue/plugins/pepper_url_util.cc b/webkit/glue/plugins/pepper_url_util.cc
deleted file mode 100644
index 2f97e6c..0000000
--- a/webkit/glue/plugins/pepper_url_util.cc
+++ /dev/null
@@ -1,177 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_url_util.h"
-
-#include "googleurl/src/gurl.h"
-#include "ppapi/c/dev/ppb_url_util_dev.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebDocument.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebElement.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebNode.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebPluginContainer.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebSecurityOrigin.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebURL.h"
-#include "webkit/glue/plugins/pepper_common.h"
-#include "webkit/glue/plugins/pepper_plugin_instance.h"
-#include "webkit/glue/plugins/pepper_string.h"
-#include "webkit/glue/plugins/pepper_var.h"
-
-namespace pepper {
-
-namespace {
-
-void ConvertComponent(const url_parse::Component& input,
- PP_UrlComponent_Dev* output) {
- output->begin = input.begin;
- output->len = input.len;
-}
-
-// Output can be NULL to specify "do nothing." This rule is followed by all the
-// url util functions, so we implement it once here.
-void ConvertComponents(const url_parse::Parsed& input,
- PP_UrlComponents_Dev* output) {
- if (!output)
- return;
-
- ConvertComponent(input.scheme, &output->scheme);
- ConvertComponent(input.username, &output->username);
- ConvertComponent(input.password, &output->password);
- ConvertComponent(input.host, &output->host);
- ConvertComponent(input.port, &output->port);
- ConvertComponent(input.path, &output->path);
- ConvertComponent(input.query, &output->query);
- ConvertComponent(input.ref, &output->ref);
-}
-
-// Used for returning the given GURL from a PPAPI function, with an optional
-// out param indicating the components.
-PP_Var GenerateUrlReturn(PluginModule* module, const GURL& url,
- PP_UrlComponents_Dev* components) {
- if (!url.is_valid())
- return PP_MakeNull();
- ConvertComponents(url.parsed_for_possibly_invalid_spec(), components);
- return StringVar::StringToPPVar(module, url.possibly_invalid_spec());
-}
-
-// Sets |*security_origin| to be the WebKit security origin associated with the
-// document containing the given plugin instance. On success, returns true. If
-// the instance is invalid, returns false and |*security_origin| will be
-// unchanged.
-bool SecurityOriginForInstance(PP_Instance instance_id,
- WebKit::WebSecurityOrigin* security_origin) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return false;
-
- WebKit::WebElement plugin_element = instance->container()->element();
- WebKit::WebFrame* plugin_frame = plugin_element.document().frame();
- if (!plugin_frame)
- return false;
-
- *security_origin = plugin_frame->securityOrigin();
- return true;
-}
-
-PP_Var Canonicalize(PP_Var url, PP_UrlComponents_Dev* components) {
- scoped_refptr<StringVar> url_string(StringVar::FromPPVar(url));
- if (!url_string)
- return PP_MakeNull();
- return GenerateUrlReturn(url_string->module(),
- GURL(url_string->value()), components);
-}
-
-PP_Var ResolveRelativeToUrl(PP_Var base_url,
- PP_Var relative,
- PP_UrlComponents_Dev* components) {
- scoped_refptr<StringVar> base_url_string(StringVar::FromPPVar(base_url));
- scoped_refptr<StringVar> relative_string(StringVar::FromPPVar(relative));
- if (!base_url_string || !relative_string)
- return PP_MakeNull();
-
- GURL base_gurl(base_url_string->value());
- if (!base_gurl.is_valid())
- return PP_MakeNull();
- return GenerateUrlReturn(base_url_string->module(),
- base_gurl.Resolve(relative_string->value()),
- components);
-}
-
-PP_Var ResolveRelativeToDocument(PP_Instance instance_id,
- PP_Var relative,
- PP_UrlComponents_Dev* components) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return PP_MakeNull();
-
- scoped_refptr<StringVar> relative_string(StringVar::FromPPVar(relative));
- if (!relative_string)
- return PP_MakeNull();
-
- WebKit::WebElement plugin_element = instance->container()->element();
- GURL document_url = plugin_element.document().baseURL();
- return GenerateUrlReturn(instance->module(),
- document_url.Resolve(relative_string->value()),
- components);
-}
-
-PP_Bool IsSameSecurityOrigin(PP_Var url_a, PP_Var url_b) {
- scoped_refptr<StringVar> url_a_string(StringVar::FromPPVar(url_a));
- scoped_refptr<StringVar> url_b_string(StringVar::FromPPVar(url_b));
- if (!url_a_string || !url_b_string)
- return PP_FALSE;
-
- GURL gurl_a(url_a_string->value());
- GURL gurl_b(url_b_string->value());
- if (!gurl_a.is_valid() || !gurl_b.is_valid())
- return PP_FALSE;
-
- return BoolToPPBool(gurl_a.GetOrigin() == gurl_b.GetOrigin());
-}
-
-PP_Bool DocumentCanRequest(PP_Instance instance, PP_Var url) {
- scoped_refptr<StringVar> url_string(StringVar::FromPPVar(url));
- if (!url_string)
- return PP_FALSE;
-
- WebKit::WebSecurityOrigin security_origin;
- if (!SecurityOriginForInstance(instance, &security_origin))
- return PP_FALSE;
-
- GURL gurl(url_string->value());
- if (!gurl.is_valid())
- return PP_FALSE;
-
- return BoolToPPBool(security_origin.canRequest(gurl));
-}
-
-PP_Bool DocumentCanAccessDocument(PP_Instance active, PP_Instance target) {
- WebKit::WebSecurityOrigin active_origin;
- if (!SecurityOriginForInstance(active, &active_origin))
- return PP_FALSE;
-
- WebKit::WebSecurityOrigin target_origin;
- if (!SecurityOriginForInstance(active, &target_origin))
- return PP_FALSE;
-
- return BoolToPPBool(active_origin.canAccess(target_origin));
-}
-
-} // namespace
-
-const PPB_UrlUtil_Dev ppb_url_util = {
- &Canonicalize,
- &ResolveRelativeToUrl,
- &ResolveRelativeToDocument,
- &IsSameSecurityOrigin,
- &DocumentCanRequest,
- &DocumentCanAccessDocument
-};
-
-// static
-const PPB_UrlUtil_Dev* UrlUtil::GetInterface() {
- return &ppb_url_util;
-}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_url_util.h b/webkit/glue/plugins/pepper_url_util.h
deleted file mode 100644
index ffb7c76..0000000
--- a/webkit/glue/plugins/pepper_url_util.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_URL_UTIL_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_URL_UTIL_H_
-
-struct PPB_UrlUtil_Dev;
-
-namespace pepper {
-
-class UrlUtil {
- public:
- static const PPB_UrlUtil_Dev* GetInterface();
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_URL_UTIL_H_
diff --git a/webkit/glue/plugins/pepper_var.cc b/webkit/glue/plugins/pepper_var.cc
deleted file mode 100644
index db83229..0000000
--- a/webkit/glue/plugins/pepper_var.cc
+++ /dev/null
@@ -1,853 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_var.h"
-
-#include <limits>
-
-#include "base/logging.h"
-#include "base/scoped_ptr.h"
-#include "base/string_util.h"
-#include "ppapi/c/dev/ppb_var_deprecated.h"
-#include "ppapi/c/ppb_var.h"
-#include "ppapi/c/pp_var.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebBindings.h"
-#include "webkit/glue/plugins/pepper_common.h"
-#include "webkit/glue/plugins/pepper_plugin_instance.h"
-#include "webkit/glue/plugins/pepper_plugin_module.h"
-#include "webkit/glue/plugins/pepper_plugin_object.h"
-#include "v8/include/v8.h"
-
-using WebKit::WebBindings;
-
-namespace pepper {
-
-namespace {
-
-const char kInvalidObjectException[] = "Error: Invalid object";
-const char kInvalidPropertyException[] = "Error: Invalid property";
-const char kInvalidValueException[] = "Error: Invalid value";
-const char kUnableToGetPropertyException[] = "Error: Unable to get property";
-const char kUnableToSetPropertyException[] = "Error: Unable to set property";
-const char kUnableToRemovePropertyException[] =
- "Error: Unable to remove property";
-const char kUnableToGetAllPropertiesException[] =
- "Error: Unable to get all properties";
-const char kUnableToCallMethodException[] = "Error: Unable to call method";
-const char kUnableToConstructException[] = "Error: Unable to construct";
-
-// ---------------------------------------------------------------------------
-// Utilities
-
-// Converts the given PP_Var to an NPVariant, returning true on success.
-// False means that the given variant is invalid. In this case, the result
-// NPVariant will be set to a void one.
-//
-// The contents of the PP_Var will NOT be copied, so you need to ensure that
-// the PP_Var remains valid while the resultant NPVariant is in use.
-bool PPVarToNPVariantNoCopy(PP_Var var, NPVariant* result) {
- switch (var.type) {
- case PP_VARTYPE_UNDEFINED:
- VOID_TO_NPVARIANT(*result);
- break;
- case PP_VARTYPE_NULL:
- NULL_TO_NPVARIANT(*result);
- break;
- case PP_VARTYPE_BOOL:
- BOOLEAN_TO_NPVARIANT(var.value.as_bool, *result);
- break;
- case PP_VARTYPE_INT32:
- INT32_TO_NPVARIANT(var.value.as_int, *result);
- break;
- case PP_VARTYPE_DOUBLE:
- DOUBLE_TO_NPVARIANT(var.value.as_double, *result);
- break;
- case PP_VARTYPE_STRING: {
- scoped_refptr<StringVar> string(StringVar::FromPPVar(var));
- if (!string) {
- VOID_TO_NPVARIANT(*result);
- return false;
- }
- const std::string& value = string->value();
- STRINGN_TO_NPVARIANT(value.c_str(), value.size(), *result);
- break;
- }
- case PP_VARTYPE_OBJECT: {
- scoped_refptr<ObjectVar> object(ObjectVar::FromPPVar(var));
- if (!object) {
- VOID_TO_NPVARIANT(*result);
- return false;
- }
- OBJECT_TO_NPVARIANT(object->np_object(), *result);
- break;
- }
- default:
- VOID_TO_NPVARIANT(*result);
- return false;
- }
- return true;
-}
-
-// ObjectAccessorTryCatch ------------------------------------------------------
-
-// Automatically sets up a TryCatch for accessing the object identified by the
-// given PP_Var. The module from the object will be used for the exception
-// strings generated by the TryCatch.
-//
-// This will automatically retrieve the ObjectVar from the object and throw
-// an exception if it's invalid. At the end of construction, if there is no
-// exception, you know that there is no previously set exception, that the
-// object passed in is valid and ready to use (via the object() getter), and
-// that the TryCatch's module() getter is also set up properly and ready to
-// use.
-class ObjectAccessorTryCatch : public TryCatch {
- public:
- ObjectAccessorTryCatch(PP_Var object, PP_Var* exception)
- : TryCatch(NULL, exception),
- object_(ObjectVar::FromPPVar(object)) {
- if (!object_) {
- // No object or an invalid object was given. This means we have no module
- // to associated with the exception text, so use the magic invalid object
- // exception.
- SetInvalidObjectException();
- } else {
- // When the object is valid, we have a valid module to associate
- set_module(object_->module());
- }
- }
-
- ObjectVar* object() { return object_.get(); }
-
- protected:
- scoped_refptr<ObjectVar> object_;
-
- DISALLOW_COPY_AND_ASSIGN(ObjectAccessorTryCatch);
-};
-
-// ObjectAccessiorWithIdentifierTryCatch ---------------------------------------
-
-// Automatically sets up a TryCatch for accessing the identifier on the given
-// object. This just extends ObjectAccessorTryCatch to additionally convert
-// the given identifier to an NPIdentifier and validate it, throwing an
-// exception if it's invalid.
-//
-// At the end of construction, if there is no exception, you know that there is
-// no previously set exception, that the object passed in is valid and ready to
-// use (via the object() getter), that the identifier is valid and ready to
-// use (via the identifier() getter), and that the TryCatch's module() getter
-// is also set up properly and ready to use.
-class ObjectAccessorWithIdentifierTryCatch : public ObjectAccessorTryCatch {
- public:
- ObjectAccessorWithIdentifierTryCatch(PP_Var object,
- PP_Var identifier,
- PP_Var* exception)
- : ObjectAccessorTryCatch(object, exception),
- identifier_(0) {
- if (!has_exception()) {
- identifier_ = Var::PPVarToNPIdentifier(identifier);
- if (!identifier_)
- SetException(kInvalidPropertyException);
- }
- }
-
- NPIdentifier identifier() const { return identifier_; }
-
- private:
- NPIdentifier identifier_;
-
- DISALLOW_COPY_AND_ASSIGN(ObjectAccessorWithIdentifierTryCatch);
-};
-
-PP_Var RunJSFunction(PP_Var scope_var,
- const char* function_script,
- PP_Var* argv,
- unsigned argc,
- PP_Var* exception) {
- TryCatch try_catch(NULL, exception);
- if (try_catch.has_exception())
- return PP_MakeUndefined();
-
- scoped_refptr<ObjectVar> obj = ObjectVar::FromPPVar(scope_var);
- if (!obj) {
- try_catch.SetInvalidObjectException();
- return PP_MakeUndefined();
- }
-
- try_catch.set_module(obj->module());
-
- scoped_array<NPVariant> args;
- if (argc) {
- args.reset(new NPVariant[argc]);
- for (uint32_t i = 0; i < argc; ++i) {
- if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) {
- // This argument was invalid, throw an exception & give up.
- try_catch.SetException(kInvalidValueException);
- return PP_MakeUndefined();
- }
- }
- }
-
- NPVariant function_var;
- VOID_TO_NPVARIANT(function_var);
- NPString function_string = { function_script, strlen(function_script) };
- if (!WebBindings::evaluate(NULL, obj->np_object(), &function_string,
- &function_var)) {
- try_catch.SetException(kInvalidValueException);
- return PP_MakeUndefined();
- }
- DCHECK(NPVARIANT_IS_OBJECT(function_var));
- DCHECK(!try_catch.has_exception());
-
- NPVariant result_var;
- VOID_TO_NPVARIANT(result_var);
- PP_Var result;
-
- if (WebBindings::invokeDefault(NULL, NPVARIANT_TO_OBJECT(function_var),
- args.get(), argc, &result_var)) {
- result = Var::NPVariantToPPVar(obj->module(), &result_var);
- } else {
- DCHECK(try_catch.has_exception());
- result = PP_MakeUndefined();
- }
-
- WebBindings::releaseVariantValue(&function_var);
- WebBindings::releaseVariantValue(&result_var);
- return result;
-}
-
-// PPB_Var methods -------------------------------------------------------------
-
-PP_Var VarFromUtf8(PP_Module module_id, const char* data, uint32_t len) {
- PluginModule* module = ResourceTracker::Get()->GetModule(module_id);
- if (!module)
- return PP_MakeNull();
- return StringVar::StringToPPVar(module, data, len);
-}
-
-const char* VarToUtf8(PP_Var var, uint32_t* len) {
- scoped_refptr<StringVar> str(StringVar::FromPPVar(var));
- if (!str) {
- *len = 0;
- return NULL;
- }
- *len = static_cast<uint32_t>(str->value().size());
- if (str->value().empty())
- return ""; // Don't return NULL on success.
- return str->value().data();
-}
-
-PP_Var ConvertType(PP_Instance instance,
- struct PP_Var var,
- PP_VarType new_type,
- PP_Var* exception) {
- TryCatch try_catch(NULL, exception);
- if (try_catch.has_exception())
- return PP_MakeUndefined();
-
- if (var.type == new_type)
- return var;
-
- PluginInstance* plugin_instance =
- ResourceTracker::Get()->GetInstance(instance);
- if (!plugin_instance) {
- try_catch.SetInvalidObjectException();
- return PP_MakeUndefined();
- }
-
- try_catch.set_module(plugin_instance->module());
- PP_Var object = plugin_instance->GetWindowObject();
-
- PP_Var params[] = {
- var,
- PP_MakeInt32(new_type),
- PP_MakeInt32(PP_VARTYPE_NULL),
- PP_MakeInt32(PP_VARTYPE_BOOL),
- PP_MakeInt32(PP_VARTYPE_INT32),
- PP_MakeInt32(PP_VARTYPE_DOUBLE),
- PP_MakeInt32(PP_VARTYPE_STRING),
- PP_MakeInt32(PP_VARTYPE_OBJECT)
- };
- PP_Var result = RunJSFunction(object,
- "(function(v, new_type, type_null, type_bool, type_int32, type_double,"
- " type_string, type_object) {"
- " switch(new_type) {"
- " case type_null: return null;"
- " case type_bool: return Boolean(v);"
- " case type_int32: case type_double: return Number(v);"
- " case type_string: return String(v);"
- " case type_object: return Object(v);"
- " default: return undefined;"
- " }})",
- params, sizeof(params) / sizeof(PP_Var), exception);
-
- // Massage Number into the correct type.
- if (new_type == PP_VARTYPE_INT32 && result.type == PP_VARTYPE_DOUBLE) {
- double value = result.value.as_double;
- // Exclusive test wouldn't deal with NaNs correctly.
- if (value >= std::numeric_limits<int32_t>::max()
- && value <= std::numeric_limits<int32_t>::min())
- result = PP_MakeInt32(static_cast<int32_t>(value));
- else
- result = PP_MakeInt32(0);
- } else if (new_type == PP_VARTYPE_DOUBLE && result.type == PP_VARTYPE_INT32) {
- result = PP_MakeDouble(result.value.as_int);
- }
-
- Var::PluginReleasePPVar(object);
- return result;
-}
-
-PP_Var BoolToPPVar(bool value) {
- return PP_MakeBool(BoolToPPBool(value));
-}
-
-void DefineProperty(struct PP_Var object,
- struct PP_ObjectProperty property,
- PP_Var* exception) {
- PP_Var params[] = {
- object, property.name,
- BoolToPPVar(!!(property.modifiers & PP_OBJECTPROPERTY_MODIFIER_HASVALUE)),
- property.value,
- BoolToPPVar(property.getter.type == PP_VARTYPE_OBJECT),
- property.getter,
- BoolToPPVar(property.setter.type == PP_VARTYPE_OBJECT),
- property.setter,
- BoolToPPVar(!!(property.modifiers & PP_OBJECTPROPERTY_MODIFIER_READONLY)),
- BoolToPPVar(!!(property.modifiers & PP_OBJECTPROPERTY_MODIFIER_DONTDELETE)),
- BoolToPPVar(!!(property.modifiers & PP_OBJECTPROPERTY_MODIFIER_DONTENUM))
- };
-
- RunJSFunction(object,
- "(function(o, name,"
- " has_value, value,"
- " has_getter, getter,"
- " has_setter, setter,"
- " modifier_readonly, modifier_dontdelete, modifier_dontenum) {"
- " prop = { 'enumerable': !modifier_dontenum,"
- " 'configurable': !modifier_dontdelete };"
- " if (has_value && !modifier_readonly) prop.writable = true;"
- " if (has_value) prop.value = value;"
- " if (has_getter) prop.get = getter;"
- " if (has_setter) prop.set = setter;"
- " return Object.defineProperty(o, name, prop); })",
- params, sizeof(params) / sizeof(PP_Var), exception);
-}
-
-PP_Bool HasProperty(PP_Var var,
- PP_Var name,
- PP_Var* exception) {
- ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
- if (accessor.has_exception())
- return PP_FALSE;
- return BoolToPPBool(WebBindings::hasProperty(NULL,
- accessor.object()->np_object(),
- accessor.identifier()));
-}
-
-bool HasPropertyDeprecated(PP_Var var,
- PP_Var name,
- PP_Var* exception) {
- return PPBoolToBool(HasProperty(var, name, exception));
-}
-
-bool HasMethodDeprecated(PP_Var var,
- PP_Var name,
- PP_Var* exception) {
- ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
- if (accessor.has_exception())
- return false;
- return WebBindings::hasMethod(NULL, accessor.object()->np_object(),
- accessor.identifier());
-}
-
-PP_Var GetProperty(PP_Var var,
- PP_Var name,
- PP_Var* exception) {
- ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
- if (accessor.has_exception())
- return PP_MakeUndefined();
-
- NPVariant result;
- if (!WebBindings::getProperty(NULL, accessor.object()->np_object(),
- accessor.identifier(), &result)) {
- // An exception may have been raised.
- accessor.SetException(kUnableToGetPropertyException);
- return PP_MakeUndefined();
- }
-
- PP_Var ret = Var::NPVariantToPPVar(accessor.object()->module(), &result);
- WebBindings::releaseVariantValue(&result);
- return ret;
-}
-
-void EnumerateProperties(PP_Var var,
- uint32_t* property_count,
- PP_Var** properties,
- PP_Var* exception) {
- *properties = NULL;
- *property_count = 0;
-
- ObjectAccessorTryCatch accessor(var, exception);
- if (accessor.has_exception())
- return;
-
- NPIdentifier* identifiers = NULL;
- uint32_t count = 0;
- if (!WebBindings::enumerate(NULL, accessor.object()->np_object(),
- &identifiers, &count)) {
- accessor.SetException(kUnableToGetAllPropertiesException);
- return;
- }
-
- if (count == 0)
- return;
-
- *property_count = count;
- *properties = static_cast<PP_Var*>(malloc(sizeof(PP_Var) * count));
- for (uint32_t i = 0; i < count; ++i) {
- (*properties)[i] = Var::NPIdentifierToPPVar(accessor.object()->module(),
- identifiers[i]);
- }
- free(identifiers);
-}
-
-void SetPropertyDeprecated(PP_Var var,
- PP_Var name,
- PP_Var value,
- PP_Var* exception) {
- ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
- if (accessor.has_exception())
- return;
-
- NPVariant variant;
- if (!PPVarToNPVariantNoCopy(value, &variant)) {
- accessor.SetException(kInvalidValueException);
- return;
- }
- if (!WebBindings::setProperty(NULL, accessor.object()->np_object(),
- accessor.identifier(), &variant))
- accessor.SetException(kUnableToSetPropertyException);
-}
-
-PP_Bool DeleteProperty(PP_Var var,
- PP_Var name,
- PP_Var* exception) {
- ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
- if (accessor.has_exception())
- return PP_FALSE;
-
- return BoolToPPBool(
- WebBindings::removeProperty(NULL,
- accessor.object()->np_object(),
- accessor.identifier()));
-}
-
-void DeletePropertyDeprecated(PP_Var var,
- PP_Var name,
- PP_Var* exception) {
- ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
- if (accessor.has_exception())
- return;
-
- if (!WebBindings::removeProperty(NULL, accessor.object()->np_object(),
- accessor.identifier()))
- accessor.SetException(kUnableToRemovePropertyException);
-}
-
-PP_Bool IsCallable(struct PP_Var object) {
- PP_Var result = RunJSFunction(object,
- "(function() { return typeof(this) == 'function' })", NULL, 0, NULL);
- if (result.type == PP_VARTYPE_BOOL)
- return result.value.as_bool;
- return PP_FALSE;
-}
-
-struct PP_Var Call(struct PP_Var object,
- struct PP_Var this_object,
- uint32_t argc,
- struct PP_Var* argv,
- struct PP_Var* exception) {
- ObjectAccessorTryCatch accessor(object, exception);
- if (accessor.has_exception())
- return PP_MakeUndefined();
-
- scoped_array<NPVariant> args;
- if (argc) {
- args.reset(new NPVariant[argc]);
- for (uint32_t i = 0; i < argc; ++i) {
- if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) {
- // This argument was invalid, throw an exception & give up.
- accessor.SetException(kInvalidValueException);
- return PP_MakeUndefined();
- }
- }
- }
-
- NPVariant result;
- if (!WebBindings::invokeDefault(NULL, accessor.object()->np_object(),
- args.get(), argc, &result)) {
- // An exception may have been raised.
- accessor.SetException(kUnableToCallMethodException);
- return PP_MakeUndefined();
- }
-
- PP_Var ret = Var::NPVariantToPPVar(accessor.module(), &result);
- WebBindings::releaseVariantValue(&result);
- return ret;
-}
-
-PP_Var CallDeprecated(PP_Var var,
- PP_Var method_name,
- uint32_t argc,
- PP_Var* argv,
- PP_Var* exception) {
- ObjectAccessorTryCatch accessor(var, exception);
- if (accessor.has_exception())
- return PP_MakeUndefined();
-
- NPIdentifier identifier;
- if (method_name.type == PP_VARTYPE_UNDEFINED) {
- identifier = NULL;
- } else if (method_name.type == PP_VARTYPE_STRING) {
- // Specifically allow only string functions to be called.
- identifier = Var::PPVarToNPIdentifier(method_name);
- if (!identifier) {
- accessor.SetException(kInvalidPropertyException);
- return PP_MakeUndefined();
- }
- } else {
- accessor.SetException(kInvalidPropertyException);
- return PP_MakeUndefined();
- }
-
- scoped_array<NPVariant> args;
- if (argc) {
- args.reset(new NPVariant[argc]);
- for (uint32_t i = 0; i < argc; ++i) {
- if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) {
- // This argument was invalid, throw an exception & give up.
- accessor.SetException(kInvalidValueException);
- return PP_MakeUndefined();
- }
- }
- }
-
- bool ok;
-
- NPVariant result;
- if (identifier) {
- ok = WebBindings::invoke(NULL, accessor.object()->np_object(),
- identifier, args.get(), argc, &result);
- } else {
- ok = WebBindings::invokeDefault(NULL, accessor.object()->np_object(),
- args.get(), argc, &result);
- }
-
- if (!ok) {
- // An exception may have been raised.
- accessor.SetException(kUnableToCallMethodException);
- return PP_MakeUndefined();
- }
-
- PP_Var ret = Var::NPVariantToPPVar(accessor.module(), &result);
- WebBindings::releaseVariantValue(&result);
- return ret;
-}
-
-PP_Var Construct(PP_Var var,
- uint32_t argc,
- PP_Var* argv,
- PP_Var* exception) {
- ObjectAccessorTryCatch accessor(var, exception);
- if (accessor.has_exception())
- return PP_MakeUndefined();
-
- scoped_array<NPVariant> args;
- if (argc) {
- args.reset(new NPVariant[argc]);
- for (uint32_t i = 0; i < argc; ++i) {
- if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) {
- // This argument was invalid, throw an exception & give up.
- accessor.SetException(kInvalidValueException);
- return PP_MakeUndefined();
- }
- }
- }
-
- NPVariant result;
- if (!WebBindings::construct(NULL, accessor.object()->np_object(),
- args.get(), argc, &result)) {
- // An exception may have been raised.
- accessor.SetException(kUnableToConstructException);
- return PP_MakeUndefined();
- }
-
- PP_Var ret = Var::NPVariantToPPVar(accessor.module(), &result);
- WebBindings::releaseVariantValue(&result);
- return ret;
-}
-
-bool IsInstanceOfDeprecated(PP_Var var,
- const PPP_Class_Deprecated* ppp_class,
- void** ppp_class_data) {
- scoped_refptr<ObjectVar> object(ObjectVar::FromPPVar(var));
- if (!object)
- return false; // Not an object at all.
-
- return PluginObject::IsInstanceOf(object->np_object(),
- ppp_class, ppp_class_data);
-}
-
-PP_Var CreateObjectDeprecated(PP_Module module_id,
- const PPP_Class_Deprecated* ppp_class,
- void* ppp_class_data) {
- PluginModule* module = ResourceTracker::Get()->GetModule(module_id);
- if (!module)
- return PP_MakeNull();
- return PluginObject::Create(module, ppp_class, ppp_class_data);
-}
-
-const PPB_Var_Deprecated var_deprecated_interface = {
- &Var::PluginAddRefPPVar,
- &Var::PluginReleasePPVar,
- &VarFromUtf8,
- &VarToUtf8,
- &HasPropertyDeprecated,
- &HasMethodDeprecated,
- &GetProperty,
- &EnumerateProperties,
- &SetPropertyDeprecated,
- &DeletePropertyDeprecated,
- &CallDeprecated,
- &Construct,
- &IsInstanceOfDeprecated,
- &CreateObjectDeprecated
-};
-
-const PPB_Var var_interface = {
- &Var::PluginAddRefPPVar,
- &Var::PluginReleasePPVar,
- &VarFromUtf8,
- &VarToUtf8,
- &ConvertType,
- &DefineProperty,
- &HasProperty,
- &GetProperty,
- &DeleteProperty,
- &EnumerateProperties,
- &IsCallable,
- &Call,
- &Construct,
-};
-
-
-} // namespace
-
-// Var -------------------------------------------------------------------------
-
-Var::Var(PluginModule* module) : Resource(module) {
-}
-
-Var::~Var() {
-}
-
-// static
-PP_Var Var::NPVariantToPPVar(PluginModule* module, const NPVariant* variant) {
- switch (variant->type) {
- case NPVariantType_Void:
- return PP_MakeUndefined();
- case NPVariantType_Null:
- return PP_MakeNull();
- case NPVariantType_Bool:
- return BoolToPPVar(NPVARIANT_TO_BOOLEAN(*variant));
- case NPVariantType_Int32:
- return PP_MakeInt32(NPVARIANT_TO_INT32(*variant));
- case NPVariantType_Double:
- return PP_MakeDouble(NPVARIANT_TO_DOUBLE(*variant));
- case NPVariantType_String:
- return StringVar::StringToPPVar(
- module,
- NPVARIANT_TO_STRING(*variant).UTF8Characters,
- NPVARIANT_TO_STRING(*variant).UTF8Length);
- case NPVariantType_Object:
- return ObjectVar::NPObjectToPPVar(module, NPVARIANT_TO_OBJECT(*variant));
- }
- NOTREACHED();
- return PP_MakeUndefined();
-}
-
-// static
-NPIdentifier Var::PPVarToNPIdentifier(PP_Var var) {
- switch (var.type) {
- case PP_VARTYPE_STRING: {
- scoped_refptr<StringVar> string(StringVar::FromPPVar(var));
- if (!string)
- return NULL;
- return WebBindings::getStringIdentifier(string->value().c_str());
- }
- case PP_VARTYPE_INT32:
- return WebBindings::getIntIdentifier(var.value.as_int);
- default:
- return NULL;
- }
-}
-
-// static
-PP_Var Var::NPIdentifierToPPVar(PluginModule* module, NPIdentifier id) {
- const NPUTF8* string_value = NULL;
- int32_t int_value = 0;
- bool is_string = false;
- WebBindings::extractIdentifierData(id, string_value, int_value, is_string);
- if (is_string)
- return StringVar::StringToPPVar(module, string_value);
-
- return PP_MakeInt32(int_value);
-}
-
-// static
-void Var::PluginAddRefPPVar(PP_Var var) {
- if (var.type == PP_VARTYPE_STRING || var.type == PP_VARTYPE_OBJECT) {
- // TODO(brettw) consider checking that the ID is actually a var ID rather
- // than some random other resource ID.
- if (!ResourceTracker::Get()->AddRefResource(var.value.as_id))
- DLOG(WARNING) << "AddRefVar()ing a nonexistant string/object var.";
- }
-}
-
-// static
-void Var::PluginReleasePPVar(PP_Var var) {
- if (var.type == PP_VARTYPE_STRING || var.type == PP_VARTYPE_OBJECT) {
- // TODO(brettw) consider checking that the ID is actually a var ID rather
- // than some random other resource ID.
- if (!ResourceTracker::Get()->UnrefResource(var.value.as_id))
- DLOG(WARNING) << "ReleaseVar()ing a nonexistant string/object var.";
- }
-}
-
-// static
-const PPB_Var_Deprecated* Var::GetDeprecatedInterface() {
- return &var_deprecated_interface;
-}
-
-const PPB_Var* Var::GetInterface() {
- return &var_interface;
-}
-
-// StringVar -------------------------------------------------------------------
-
-StringVar::StringVar(PluginModule* module, const char* str, uint32 len)
- : Var(module),
- value_(str, len) {
-}
-
-StringVar::~StringVar() {
-}
-
-// static
-PP_Var StringVar::StringToPPVar(PluginModule* module, const std::string& var) {
- return StringToPPVar(module, var.c_str(), var.size());
-}
-
-// static
-PP_Var StringVar::StringToPPVar(PluginModule* module,
- const char* data, uint32 len) {
- scoped_refptr<StringVar> str(new StringVar(module, data, len));
- if (!str || !IsStringUTF8(str->value()))
- return PP_MakeNull();
-
- PP_Var ret;
- ret.type = PP_VARTYPE_STRING;
-
- // The caller takes ownership now.
- ret.value.as_id = str->GetReference();
- return ret;
-}
-
-// static
-scoped_refptr<StringVar> StringVar::FromPPVar(PP_Var var) {
- if (var.type != PP_VARTYPE_STRING)
- return scoped_refptr<StringVar>(NULL);
- return Resource::GetAs<StringVar>(var.value.as_id);
-}
-
-// ObjectVar -------------------------------------------------------------
-
-ObjectVar::ObjectVar(PluginModule* module, NPObject* np_object)
- : Var(module),
- np_object_(np_object) {
- WebBindings::retainObject(np_object_);
- module->AddNPObjectVar(this);
-}
-
-ObjectVar::~ObjectVar() {
- module()->RemoveNPObjectVar(this);
- WebBindings::releaseObject(np_object_);
-}
-
-// static
-PP_Var ObjectVar::NPObjectToPPVar(PluginModule* module, NPObject* object) {
- scoped_refptr<ObjectVar> object_var(module->ObjectVarForNPObject(object));
- if (!object_var) // No object for this module yet, make a new one.
- object_var = new ObjectVar(module, object);
-
- if (!object_var)
- return PP_MakeUndefined();
-
- // Convert to a PP_Var, GetReference will AddRef for us.
- PP_Var result;
- result.type = PP_VARTYPE_OBJECT;
- result.value.as_id = object_var->GetReference();
- return result;
-}
-
-// static
-scoped_refptr<ObjectVar> ObjectVar::FromPPVar(PP_Var var) {
- if (var.type != PP_VARTYPE_OBJECT)
- return scoped_refptr<ObjectVar>(NULL);
- return Resource::GetAs<ObjectVar>(var.value.as_id);
-}
-
-// TryCatch --------------------------------------------------------------------
-
-TryCatch::TryCatch(PluginModule* module, PP_Var* exception)
- : module_(module),
- has_exception_(exception && exception->type != PP_VARTYPE_UNDEFINED),
- exception_(exception) {
- WebBindings::pushExceptionHandler(&TryCatch::Catch, this);
-}
-
-TryCatch::~TryCatch() {
- WebBindings::popExceptionHandler();
-}
-
-void TryCatch::SetException(const char* message) {
- if (!module_) {
- // Don't have a module to make the string.
- SetInvalidObjectException();
- return;
- }
-
- if (!has_exception()) {
- has_exception_ = true;
- if (exception_)
- *exception_ = StringVar::StringToPPVar(module_, message, strlen(message));
- }
-}
-
-void TryCatch::SetInvalidObjectException() {
- if (!has_exception()) {
- has_exception_ = true;
- // TODO(brettw) bug 54504: Have a global singleton string that can hold
- // a generic error message.
- if (exception_)
- *exception_ = PP_MakeInt32(1);
- }
-}
-
-// static
-void TryCatch::Catch(void* self, const char* message) {
- static_cast<TryCatch*>(self)->SetException(message);
-}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_var.h b/webkit/glue/plugins/pepper_var.h
deleted file mode 100644
index 8929448..0000000
--- a/webkit/glue/plugins/pepper_var.h
+++ /dev/null
@@ -1,251 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_VAR_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_VAR_H_
-
-#include <string>
-
-#include "webkit/glue/plugins/pepper_resource.h"
-
-struct PP_Var;
-struct PPB_Var;
-struct PPB_Var_Deprecated;
-typedef struct NPObject NPObject;
-typedef struct _NPVariant NPVariant;
-typedef void* NPIdentifier;
-
-namespace pepper {
-
-// Var -------------------------------------------------------------------------
-
-// Represents a non-POD var. This is derived from a resource even though it
-// isn't a resource from the plugin's perspective. This allows us to re-use
-// the refcounting and the association with the module from the resource code.
-class Var : public Resource {
- public:
- virtual ~Var();
-
- // Resource overrides.
- virtual Var* AsVar() { return this; }
-
- // Returns a PP_Var that corresponds to the given NPVariant. The contents of
- // the NPVariant will be copied unless the NPVariant corresponds to an
- // object. This will handle all Variant types including POD, strings, and
- // objects.
- //
- // The returned PP_Var will have a refcount of 1, this passing ownership of
- // the reference to the caller. This is suitable for returning to a plugin.
- static PP_Var NPVariantToPPVar(PluginModule* module,
- const NPVariant* variant);
-
- // Returns a NPIdentifier that corresponds to the given PP_Var. The contents
- // of the PP_Var will be copied. Returns 0 if the given PP_Var is not a a
- // string or integer type.
- static NPIdentifier PPVarToNPIdentifier(PP_Var var);
-
- // Returns a PP_Var corresponding to the given identifier. In the case of
- // a string identifier, the string will be allocated associated with the
- // given module. A returned string will have a reference count of 1.
- static PP_Var NPIdentifierToPPVar(PluginModule* module, NPIdentifier id);
-
- // Provides access to the manual refcounting of a PP_Var from the plugin's
- // perspective. This is different than the AddRef/Release on this scoped
- // object. This uses the ResourceTracker, which keeps a separate "plugin
- // refcount" that prevents the plugin from messing up our refcounting or
- // freeing something out from under us.
- //
- // You should not generally need to use these functions. However, if you
- // call a plugin function that returns a var, it will transfer a ref to us
- // (the caller) which in the case of a string or object var will need to
- // be released.
- //
- // Example, assuming we're expecting the plugin to return a string:
- // PP_Var rv = some_ppp_interface->DoSomething(a, b, c);
- //
- // // Get the string value. This will take a reference to the object which
- // // will prevent it from being deleted out from under us when we call
- // // PluginReleasePPVar().
- // scoped_refptr<StringVar> string(StringVar::FromPPVar(rv));
- //
- // // Release the reference the plugin gave us when returning the value.
- // // This is legal to do for all types of vars.
- // Var::PluginReleasePPVar(rv);
- //
- // // Use the string.
- // if (!string)
- // return false; // It didn't return a proper string.
- // UseTheString(string->value());
- static void PluginAddRefPPVar(PP_Var var);
- static void PluginReleasePPVar(PP_Var var);
-
- // Returns the PPB_Var_Deprecated interface for the plugin to use.
- static const PPB_Var_Deprecated* GetDeprecatedInterface();
-
- // Returns the PPB_Var interface for the plugin to use.
- static const PPB_Var* GetInterface();
-
- protected:
- // This can only be constructed as a StringVar or an ObjectVar.
- explicit Var(PluginModule* module);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Var);
-};
-
-// StringVar -------------------------------------------------------------------
-
-// Represents a string-based Var.
-//
-// Returning a given string as a PP_Var:
-// return StringVar::StringToPPVar(module, my_string);
-//
-// Converting a PP_Var to a string:
-// scoped_refptr<StringVar> string(StringVar::FromPPVar(var));
-// if (!string)
-// return false; // Not a string or an invalid var.
-// DoSomethingWithTheString(string->value());
-class StringVar : public Var {
- public:
- StringVar(PluginModule* module, const char* str, uint32 len);
- virtual ~StringVar();
-
- const std::string& value() const { return value_; }
-
- // Resource overrides.
- virtual StringVar* AsStringVar() { return this; }
-
- // Helper function to create a PP_Var of type string that contains a copy of
- // the given string. The input data must be valid UTF-8 encoded text, if it
- // is not valid UTF-8, a NULL var will be returned.
- //
- // The return value will have a reference count of 1. Internally, this will
- // create a StringVar, associate it with a module, and return the reference
- // to it in the var.
- static PP_Var StringToPPVar(PluginModule* module, const std::string& str);
- static PP_Var StringToPPVar(PluginModule* module,
- const char* str, uint32 len);
-
- // Helper function that converts a PP_Var to a string. This will return NULL
- // if the PP_Var is not of string type or the string is invalid.
- static scoped_refptr<StringVar> FromPPVar(PP_Var var);
-
- private:
- std::string value_;
-
- DISALLOW_COPY_AND_ASSIGN(StringVar);
-};
-
-// ObjectVar -------------------------------------------------------------------
-
-// Represents a JavaScript object Var. By itself, this represents random
-// NPObjects that a given plugin (identified by the resource's module) wants to
-// reference. If two different modules reference the same NPObject (like the
-// "window" object), then there will be different ObjectVar's (and hence PP_Var
-// IDs) for each module. This allows us to track all references owned by a
-// given module and free them when the plugin exits independently of other
-// plugins that may be running at the same time.
-//
-// See StringVar for examples, except obviously using NPObjects instead of
-// strings.
-class ObjectVar : public Var {
- public:
- virtual ~ObjectVar();
-
- // Resource overrides.
- virtual ObjectVar* AsObjectVar() { return this; }
-
- // Returns the underlying NPObject corresponding to this ObjectVar.
- // Guaranteed non-NULL.
- NPObject* np_object() const { return np_object_; }
-
- // Helper function to create a PP_Var of type object that contains the given
- // NPObject for use byt he given module. Calling this function multiple times
- // given the same module + NPObject results in the same PP_Var, assuming that
- // there is still a PP_Var with a reference open to it from the previous
- // call.
- //
- // The module is necessary because we can have different modules pointing to
- // the same NPObject, and we want to keep their refs separate.
- //
- // If no ObjectVar currently exists corresponding to the NPObject, one is
- // created associated with the given module.
- static PP_Var NPObjectToPPVar(PluginModule* module, NPObject* object);
-
- // Helper function that converts a PP_Var to an object. This will return NULL
- // if the PP_Var is not of object type or the object is invalid.
- static scoped_refptr<ObjectVar> FromPPVar(PP_Var var);
-
- protected:
- // You should always use FromNPObject to create an ObjectVar. This function
- // guarantees that we maintain the 1:1 mapping between NPObject and
- // ObjectVar.
- ObjectVar(PluginModule* module, NPObject* np_object);
-
- private:
- // Guaranteed non-NULL, this is the underlying object used by WebKit. We
- // hold a reference to this object.
- NPObject* np_object_;
-
- DISALLOW_COPY_AND_ASSIGN(ObjectVar);
-};
-
-// TryCatch --------------------------------------------------------------------
-
-// Instantiate this object on the stack to catch V8 exceptions and pass them
-// to an optional out parameter supplied by the plugin.
-class TryCatch {
- public:
- // The given exception may be NULL if the consumer isn't interested in
- // catching exceptions. If non-NULL, the given var will be updated if any
- // exception is thrown (so it must outlive the TryCatch object).
- //
- // The module associated with the exception is passed so we know which module
- // to associate any exception string with. It may be NULL if you don't know
- // the module at construction time, in which case you should set it later
- // by calling set_module().
- //
- // If an exception is thrown when the module is NULL, setting *any* exception
- // will result in using the InvalidObjectException.
- TryCatch(PluginModule* module, PP_Var* exception);
- ~TryCatch();
-
- // Get and set the module. This may be NULL (see the constructor).
- PluginModule* module() { return module_; }
- void set_module(PluginModule* module) { module_ = module; }
-
- // Returns true is an exception has been thrown. This can be true immediately
- // after construction if the var passed to the constructor is non-void.
- bool has_exception() const { return has_exception_; }
-
- // Sets the given exception. If no module has been set yet, the message will
- // be ignored (since we have no module to associate the string with) and the
- // SetInvalidObjectException() will be used instead.
- //
- // If an exception has been previously set, this function will do nothing
- // (normally you want only the first exception).
- void SetException(const char* message);
-
- // Sets the exception to be a generic message contained in a magic string
- // not associated with any module.
- void SetInvalidObjectException();
-
- private:
- static void Catch(void* self, const char* message);
-
- PluginModule* module_;
-
- // True if an exception has been thrown. Since the exception itself may be
- // NULL if the plugin isn't interested in getting the exception, this will
- // always indicate if SetException has been called, regardless of whether
- // the exception itself has been stored.
- bool has_exception_;
-
- // May be null if the consumer isn't interesting in catching exceptions.
- PP_Var* exception_;
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_VAR_H_
diff --git a/webkit/glue/plugins/pepper_video_decoder.cc b/webkit/glue/plugins/pepper_video_decoder.cc
deleted file mode 100644
index cd4d3b5..0000000
--- a/webkit/glue/plugins/pepper_video_decoder.cc
+++ /dev/null
@@ -1,141 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_video_decoder.h"
-
-#include "base/logging.h"
-#include "ppapi/c/dev/pp_video_dev.h"
-#include "ppapi/c/dev/ppb_video_decoder_dev.h"
-#include "ppapi/c/pp_completion_callback.h"
-#include "ppapi/c/pp_errors.h"
-#include "webkit/glue/plugins/pepper_common.h"
-#include "webkit/glue/plugins/pepper_file_ref.h"
-#include "webkit/glue/plugins/pepper_plugin_instance.h"
-#include "webkit/glue/plugins/pepper_resource_tracker.h"
-
-namespace pepper {
-
-namespace {
-
-PP_Bool GetConfig(PP_Instance instance_id,
- PP_VideoCodecId_Dev codec,
- PP_VideoConfig_Dev* configs,
- int32_t config_size,
- int32_t *num_config) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- *num_config = 0;
- if (!instance)
- return PP_FALSE;
-
- // Get configs based on codec.
-
- if (configs) {
- // Fill in the array of configs.
- }
-
- // Update *num_config.
-
- return PP_TRUE;
-}
-
-PP_Resource Create(PP_Instance instance_id,
- const PP_VideoDecoderConfig_Dev* decoder_config) {
- PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id);
- if (!instance)
- return 0;
-
- scoped_refptr<VideoDecoder> decoder(new VideoDecoder(instance));
-
- if (!decoder->Init(*decoder_config))
- return 0;
-
- return decoder->GetReference();
-}
-
-PP_Bool Decode(PP_Resource decoder_id,
- PP_VideoCompressedDataBuffer_Dev* input_buffer) {
- scoped_refptr<VideoDecoder> decoder(
- Resource::GetAs<VideoDecoder>(decoder_id));
- if (!decoder)
- return PP_FALSE;
-
- decoder->Decode(*input_buffer);
- return PP_TRUE;
-}
-
-int32_t Flush(PP_Resource decoder_id, PP_CompletionCallback callback) {
- scoped_refptr<VideoDecoder> decoder(
- Resource::GetAs<VideoDecoder>(decoder_id));
- if (!decoder)
- return PP_ERROR_BADRESOURCE;
-
- return decoder->Flush(callback);
-}
-
-PP_Bool ReturnUncompressedDataBuffer(PP_Resource decoder_id,
- PP_VideoUncompressedDataBuffer_Dev* buffer) {
- scoped_refptr<VideoDecoder> decoder(
- Resource::GetAs<VideoDecoder>(decoder_id));
- if (!decoder)
- return PP_FALSE;
-
- return BoolToPPBool(decoder->ReturnUncompressedDataBuffer(*buffer));
-}
-
-const PPB_VideoDecoder_Dev ppb_videodecoder = {
- &GetConfig,
- &Create,
- &Decode,
- &Flush,
- &ReturnUncompressedDataBuffer
-};
-
-} // namespace
-
-VideoDecoder::VideoDecoder(PluginInstance* instance)
- : Resource(instance->module()),
- instance_(instance) {
-}
-
-VideoDecoder::~VideoDecoder() {
-}
-
-// static
-const PPB_VideoDecoder_Dev* VideoDecoder::GetInterface() {
- return &ppb_videodecoder;
-}
-
-bool VideoDecoder::Init(const PP_VideoDecoderConfig_Dev& decoder_config) {
- if (!instance())
- return false;
-
- platform_video_decoder_.reset(
- instance()->delegate()->CreateVideoDecoder(decoder_config));
-
- return platform_video_decoder_.get()? true : false;
-}
-
-bool VideoDecoder::Decode(PP_VideoCompressedDataBuffer_Dev& input_buffer) {
- if (!platform_video_decoder_.get())
- return false;
-
- return platform_video_decoder_->Decode(input_buffer);
-}
-
-int32_t VideoDecoder::Flush(PP_CompletionCallback& callback) {
- if (!platform_video_decoder_.get())
- return PP_ERROR_FAILED;
-
- return platform_video_decoder_->Flush(callback);
-}
-
-bool VideoDecoder::ReturnUncompressedDataBuffer(
- PP_VideoUncompressedDataBuffer_Dev& buffer) {
- if (!platform_video_decoder_.get())
- return false;
-
- return platform_video_decoder_->ReturnUncompressedDataBuffer(buffer);
-}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_video_decoder.h b/webkit/glue/plugins/pepper_video_decoder.h
deleted file mode 100644
index c828709..0000000
--- a/webkit/glue/plugins/pepper_video_decoder.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_VIDEO_DECODER_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_VIDEO_DECODER_H_
-
-#include "base/scoped_ptr.h"
-#include "webkit/glue/plugins/pepper_plugin_delegate.h"
-#include "webkit/glue/plugins/pepper_resource.h"
-
-struct PP_VideoDecoderConfig_Dev;
-struct PP_VideoCompressedDataBuffer_Dev;
-struct PP_VideoUncompressedDataBuffer_Dev;
-struct PPB_VideoDecoder_Dev;
-
-namespace pepper {
-
-class PluginInstance;
-
-class VideoDecoder : public Resource {
- public:
- VideoDecoder(PluginInstance* instance);
- virtual ~VideoDecoder();
-
- // Returns a pointer to the interface implementing PPB_VideoDecoder that is
- // exposed to the plugin.
- static const PPB_VideoDecoder_Dev* GetInterface();
-
- // Resource overrides.
- VideoDecoder* AsVideoDecoder() { return this; }
-
- PluginInstance* instance() { return instance_.get(); }
-
- // PPB_VideoDecoder implementation.
- bool Init(const PP_VideoDecoderConfig_Dev& decoder_config);
- bool Decode(PP_VideoCompressedDataBuffer_Dev& input_buffer);
- int32_t Flush(PP_CompletionCallback& callback);
- bool ReturnUncompressedDataBuffer(PP_VideoUncompressedDataBuffer_Dev& buffer);
-
- private:
- // This is NULL before initialization, and if this VideoDecoder is
- // swapped with another.
- scoped_ptr<PluginDelegate::PlatformVideoDecoder> platform_video_decoder_;
- scoped_refptr<PluginInstance> instance_;
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_VIDEO_DECODER_H_
diff --git a/webkit/glue/plugins/pepper_webplugin_impl.cc b/webkit/glue/plugins/pepper_webplugin_impl.cc
deleted file mode 100644
index 8da398f..0000000
--- a/webkit/glue/plugins/pepper_webplugin_impl.cc
+++ /dev/null
@@ -1,226 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_webplugin_impl.h"
-
-#include <cmath>
-
-#include "base/message_loop.h"
-#include "ppapi/c/pp_var.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebPluginParams.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebPoint.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebRect.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebView.h"
-#include "webkit/glue/plugins/pepper_plugin_instance.h"
-#include "webkit/glue/plugins/pepper_plugin_module.h"
-#include "webkit/glue/plugins/pepper_url_loader.h"
-#include "webkit/glue/plugins/pepper_var.h"
-
-using WebKit::WebCanvas;
-using WebKit::WebPluginContainer;
-using WebKit::WebPluginParams;
-using WebKit::WebPoint;
-using WebKit::WebRect;
-using WebKit::WebString;
-using WebKit::WebURL;
-using WebKit::WebVector;
-using WebKit::WebView;
-
-namespace pepper {
-
-struct WebPluginImpl::InitData {
- scoped_refptr<PluginModule> module;
- base::WeakPtr<PluginDelegate> delegate;
- std::vector<std::string> arg_names;
- std::vector<std::string> arg_values;
-};
-
-WebPluginImpl::WebPluginImpl(
- PluginModule* plugin_module,
- const WebPluginParams& params,
- const base::WeakPtr<PluginDelegate>& plugin_delegate)
- : init_data_(new InitData()),
- full_frame_(params.loadManually) {
- DCHECK(plugin_module);
- init_data_->module = plugin_module;
- init_data_->delegate = plugin_delegate;
- for (size_t i = 0; i < params.attributeNames.size(); ++i) {
- init_data_->arg_names.push_back(params.attributeNames[i].utf8());
- init_data_->arg_values.push_back(params.attributeValues[i].utf8());
- }
-}
-
-WebPluginImpl::~WebPluginImpl() {
-}
-
-bool WebPluginImpl::initialize(WebPluginContainer* container) {
- // The plugin delegate may have gone away.
- if (!init_data_->delegate)
- return false;
-
- instance_ = init_data_->module->CreateInstance(init_data_->delegate);
- if (!instance_)
- return false;
-
- bool success = instance_->Initialize(container,
- init_data_->arg_names,
- init_data_->arg_values,
- full_frame_);
- if (!success) {
- instance_->Delete();
- instance_ = NULL;
- return false;
- }
-
- init_data_.reset();
- return true;
-}
-
-void WebPluginImpl::destroy() {
- if (instance_) {
- instance_->Delete();
- instance_ = NULL;
- }
-
- MessageLoop::current()->DeleteSoon(FROM_HERE, this);
-}
-
-NPObject* WebPluginImpl::scriptableObject() {
- scoped_refptr<ObjectVar> object(
- ObjectVar::FromPPVar(instance_->GetInstanceObject()));
- if (object)
- return object->np_object();
- return NULL;
-}
-
-void WebPluginImpl::paint(WebCanvas* canvas, const WebRect& rect) {
- if (!instance_->IsFullscreen())
- instance_->Paint(canvas, plugin_rect_, rect);
-}
-
-void WebPluginImpl::updateGeometry(
- const WebRect& window_rect,
- const WebRect& clip_rect,
- const WebVector<WebRect>& cut_outs_rects,
- bool is_visible) {
- plugin_rect_ = window_rect;
- if (!instance_->IsFullscreen())
- instance_->ViewChanged(plugin_rect_, clip_rect);
-}
-
-unsigned WebPluginImpl::getBackingTextureId() {
- return instance_->GetBackingTextureId();
-}
-
-void WebPluginImpl::updateFocus(bool focused) {
- instance_->SetWebKitFocus(focused);
-}
-
-void WebPluginImpl::updateVisibility(bool visible) {
-}
-
-bool WebPluginImpl::acceptsInputEvents() {
- return true;
-}
-
-bool WebPluginImpl::handleInputEvent(const WebKit::WebInputEvent& event,
- WebKit::WebCursorInfo& cursor_info) {
- if (instance_->IsFullscreen())
- return false;
- return instance_->HandleInputEvent(event, &cursor_info);
-}
-
-void WebPluginImpl::didReceiveResponse(
- const WebKit::WebURLResponse& response) {
- DCHECK(!document_loader_);
-
- document_loader_ = new URLLoader(instance_, true);
- document_loader_->didReceiveResponse(NULL, response);
-
- if (!instance_->HandleDocumentLoad(document_loader_))
- document_loader_ = NULL;
-}
-
-void WebPluginImpl::didReceiveData(const char* data, int data_length) {
- if (document_loader_)
- document_loader_->didReceiveData(NULL, data, data_length);
-}
-
-void WebPluginImpl::didFinishLoading() {
- if (document_loader_) {
- document_loader_->didFinishLoading(NULL, 0);
- document_loader_ = NULL;
- }
-}
-
-void WebPluginImpl::didFailLoading(const WebKit::WebURLError& error) {
- if (document_loader_) {
- document_loader_->didFail(NULL, error);
- document_loader_ = NULL;
- }
-}
-
-void WebPluginImpl::didFinishLoadingFrameRequest(const WebKit::WebURL& url,
- void* notify_data) {
-}
-
-void WebPluginImpl::didFailLoadingFrameRequest(
- const WebKit::WebURL& url,
- void* notify_data,
- const WebKit::WebURLError& error) {
-}
-
-bool WebPluginImpl::hasSelection() const {
- return !selectionAsText().isEmpty();
-}
-
-WebString WebPluginImpl::selectionAsText() const {
- return instance_->GetSelectedText(false);
-}
-
-WebString WebPluginImpl::selectionAsMarkup() const {
- return instance_->GetSelectedText(true);
-}
-
-WebURL WebPluginImpl::linkAtPosition(const WebPoint& position) const {
- return GURL(instance_->GetLinkAtPosition(position));
-}
-
-void WebPluginImpl::setZoomLevel(double level, bool text_only) {
- instance_->Zoom(WebView::zoomLevelToZoomFactor(level), text_only);
-}
-
-bool WebPluginImpl::startFind(const WebKit::WebString& search_text,
- bool case_sensitive,
- int identifier) {
- return instance_->StartFind(search_text, case_sensitive, identifier);
-}
-
-void WebPluginImpl::selectFindResult(bool forward) {
- instance_->SelectFindResult(forward);
-}
-
-void WebPluginImpl::stopFind() {
- instance_->StopFind();
-}
-
-bool WebPluginImpl::supportsPaginatedPrint() {
- return instance_->SupportsPrintInterface();
-}
-
-int WebPluginImpl::printBegin(const WebKit::WebRect& printable_area,
- int printer_dpi) {
- return instance_->PrintBegin(printable_area, printer_dpi);
-}
-
-bool WebPluginImpl::printPage(int page_number,
- WebKit::WebCanvas* canvas) {
- return instance_->PrintPage(page_number, canvas);
-}
-
-void WebPluginImpl::printEnd() {
- return instance_->PrintEnd();
-}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_webplugin_impl.h b/webkit/glue/plugins/pepper_webplugin_impl.h
deleted file mode 100644
index 8922143..0000000
--- a/webkit/glue/plugins/pepper_webplugin_impl.h
+++ /dev/null
@@ -1,95 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_WEBPLUGIN_IMPL_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_WEBPLUGIN_IMPL_H_
-
-#include <string>
-#include <vector>
-
-#include "base/weak_ptr.h"
-#include "base/scoped_ptr.h"
-#include "base/task.h"
-#include "gfx/rect.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebPlugin.h"
-
-namespace WebKit {
-struct WebPluginParams;
-}
-
-namespace pepper {
-
-class PluginDelegate;
-class PluginInstance;
-class PluginModule;
-class URLLoader;
-
-class WebPluginImpl : public WebKit::WebPlugin {
- public:
- WebPluginImpl(PluginModule* module,
- const WebKit::WebPluginParams& params,
- const base::WeakPtr<PluginDelegate>& plugin_delegate);
-
- private:
- friend class DeleteTask<WebPluginImpl>;
-
- ~WebPluginImpl();
-
- // WebKit::WebPlugin implementation.
- virtual bool initialize(WebKit::WebPluginContainer* container);
- virtual void destroy();
- virtual NPObject* scriptableObject();
- virtual void paint(WebKit::WebCanvas* canvas, const WebKit::WebRect& rect);
- virtual void updateGeometry(
- const WebKit::WebRect& frame_rect,
- const WebKit::WebRect& clip_rect,
- const WebKit::WebVector<WebKit::WebRect>& cut_outs_rects,
- bool is_visible);
- virtual unsigned getBackingTextureId();
- virtual void updateFocus(bool focused);
- virtual void updateVisibility(bool visible);
- virtual bool acceptsInputEvents();
- virtual bool handleInputEvent(const WebKit::WebInputEvent& event,
- WebKit::WebCursorInfo& cursor_info);
- virtual void didReceiveResponse(const WebKit::WebURLResponse& response);
- virtual void didReceiveData(const char* data, int data_length);
- virtual void didFinishLoading();
- virtual void didFailLoading(const WebKit::WebURLError&);
- virtual void didFinishLoadingFrameRequest(const WebKit::WebURL& url,
- void* notify_data);
- virtual void didFailLoadingFrameRequest(const WebKit::WebURL& url,
- void* notify_data,
- const WebKit::WebURLError& error);
- virtual bool hasSelection() const;
- virtual WebKit::WebString selectionAsText() const;
- virtual WebKit::WebString selectionAsMarkup() const;
- virtual WebKit::WebURL linkAtPosition(const WebKit::WebPoint& position) const;
- virtual void setZoomLevel(double level, bool text_only);
- virtual bool startFind(const WebKit::WebString& search_text,
- bool case_sensitive,
- int identifier);
- virtual void selectFindResult(bool forward);
- virtual void stopFind();
- virtual bool supportsPaginatedPrint();
- virtual int printBegin(const WebKit::WebRect& printable_area,
- int printer_dpi);
- virtual bool printPage(int page_number, WebKit::WebCanvas* canvas);
- virtual void printEnd();
-
- struct InitData;
-
- scoped_ptr<InitData> init_data_; // Cleared upon successful initialization.
- // True if the instance represents the entire document in a frame instead of
- // being an embedded resource.
- bool full_frame_;
- scoped_refptr<PluginInstance> instance_;
- scoped_refptr<URLLoader> document_loader_;
- gfx::Rect plugin_rect_;
-
- DISALLOW_COPY_AND_ASSIGN(WebPluginImpl);
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_WEBPLUGIN_IMPL_H_
diff --git a/webkit/glue/plugins/pepper_widget.cc b/webkit/glue/plugins/pepper_widget.cc
deleted file mode 100644
index e704e8c..0000000
--- a/webkit/glue/plugins/pepper_widget.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/pepper_widget.h"
-
-#include "base/logging.h"
-#include "ppapi/c/dev/ppb_widget_dev.h"
-#include "ppapi/c/dev/ppp_widget_dev.h"
-#include "ppapi/c/pp_completion_callback.h"
-#include "ppapi/c/pp_errors.h"
-#include "webkit/glue/plugins/pepper_common.h"
-#include "webkit/glue/plugins/pepper_image_data.h"
-#include "webkit/glue/plugins/pepper_plugin_instance.h"
-#include "webkit/glue/plugins/pepper_plugin_module.h"
-
-namespace pepper {
-
-namespace {
-
-PP_Bool IsWidget(PP_Resource resource) {
- return BoolToPPBool(!!Resource::GetAs<Widget>(resource));
-}
-
-PP_Bool Paint(PP_Resource resource, const PP_Rect* rect, PP_Resource image_id) {
- scoped_refptr<Widget> widget(Resource::GetAs<Widget>(resource));
- if (!widget)
- return PP_FALSE;
-
- scoped_refptr<ImageData> image(Resource::GetAs<ImageData>(image_id));
- if (!image)
- return PP_FALSE;
-
- return BoolToPPBool(widget->Paint(rect, image));
-}
-
-PP_Bool HandleEvent(PP_Resource resource, const PP_InputEvent* event) {
- scoped_refptr<Widget> widget(Resource::GetAs<Widget>(resource));
- return BoolToPPBool(widget && widget->HandleEvent(event));
-}
-
-PP_Bool GetLocation(PP_Resource resource, PP_Rect* location) {
- scoped_refptr<Widget> widget(Resource::GetAs<Widget>(resource));
- return BoolToPPBool(widget && widget->GetLocation(location));
-}
-
-void SetLocation(PP_Resource resource, const PP_Rect* location) {
- scoped_refptr<Widget> widget(Resource::GetAs<Widget>(resource));
- if (widget)
- widget->SetLocation(location);
-}
-
-const PPB_Widget_Dev ppb_widget = {
- &IsWidget,
- &Paint,
- &HandleEvent,
- &GetLocation,
- &SetLocation,
-};
-
-} // namespace
-
-Widget::Widget(PluginInstance* instance)
- : Resource(instance->module()),
- instance_(instance) {
-}
-
-Widget::~Widget() {
-}
-
-// static
-const PPB_Widget_Dev* Widget::GetInterface() {
- return &ppb_widget;
-}
-
-bool Widget::GetLocation(PP_Rect* location) {
- *location = location_;
- return true;
-}
-
-void Widget::SetLocation(const PP_Rect* location) {
- location_ = *location;
- SetLocationInternal(location);
-}
-
-void Widget::Invalidate(const PP_Rect* dirty) {
- const PPP_Widget_Dev* widget = static_cast<const PPP_Widget_Dev*>(
- module()->GetPluginInterface(PPP_WIDGET_DEV_INTERFACE));
- if (!widget)
- return;
- ScopedResourceId resource(this);
- widget->Invalidate(instance_->pp_instance(), resource.id, dirty);
-}
-
-} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_widget.h b/webkit/glue/plugins/pepper_widget.h
deleted file mode 100644
index cf937bd..0000000
--- a/webkit/glue/plugins/pepper_widget.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_WIDGET_H_
-#define WEBKIT_GLUE_PLUGINS_PEPPER_WIDGET_H_
-
-#include "base/scoped_ptr.h"
-#include "ppapi/c/pp_rect.h"
-#include "webkit/glue/plugins/pepper_resource.h"
-
-struct PPB_Widget_Dev;
-struct PP_InputEvent;
-
-namespace pepper {
-
-class ImageData;
-class PluginInstance;
-
-class Widget : public Resource {
- public:
- explicit Widget(PluginInstance* instance);
- virtual ~Widget();
-
- // Returns a pointer to the interface implementing PPB_Widget that is
- // exposed to the plugin.
- static const PPB_Widget_Dev* GetInterface();
-
- // Resource overrides.
- Widget* AsWidget() { return this; }
-
- // PPB_Widget implementation.
- virtual bool Paint(const PP_Rect* rect, ImageData* image) = 0;
- virtual bool HandleEvent(const PP_InputEvent* event) = 0;
- bool GetLocation(PP_Rect* location);
- void SetLocation(const PP_Rect* location);
-
- // Notifies the plugin instance that the given rect needs to be repainted.
- void Invalidate(const PP_Rect* dirty);
- PluginInstance* instance() { return instance_; }
-
- protected:
- virtual void SetLocationInternal(const PP_Rect* location) = 0;
- PP_Rect location() const { return location_; }
-
- private:
- scoped_refptr<PluginInstance> instance_;
- PP_Rect location_;
-};
-
-} // namespace pepper
-
-#endif // WEBKIT_GLUE_PLUGINS_PEPPER_WIDGET_H_
diff --git a/webkit/glue/plugins/plugin_constants_win.h b/webkit/glue/plugins/plugin_constants_win.h
deleted file mode 100644
index 9913e5d..0000000
--- a/webkit/glue/plugins/plugin_constants_win.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (c) 2006-2009 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 WEBKIT_GLUE_PLUGIN_CONSTANTS_WIN_H_
-#define WEBKIT_GLUE_PLUGIN_CONSTANTS_WIN_H_
-
-// Used by the plugins_test when testing the older WMP plugin to force the new
-// plugin to not get loaded.
-#define kUseOldWMPPluginSwitch "use-old-wmp"
-
-// The window class name for a plugin window.
-#define kNativeWindowClassName L"NativeWindowClass"
-
-// The name of the window class name for the wrapper HWND around the actual
-// plugin window that's used when running in multi-process mode. This window
-// is created on the browser UI thread.
-#define kWrapperNativeWindowClassName L"WrapperNativeWindowClass"
-
-// The name of the custom window message that the browser uses to tell the
-// plugin process to paint a window.
-#define kPaintMessageName L"Chrome_CustomPaint"
-
-// The name of the registry key which NPAPI plugins update on installation.
-#define kRegistryMozillaPlugins L"SOFTWARE\\MozillaPlugins"
-
-#define kMozillaActiveXPlugin L"npmozax.dll"
-#define kNewWMPPlugin L"np-mswmp.dll"
-#define kOldWMPPlugin L"npdsplay.dll"
-#define kYahooApplicationStatePlugin L"npystate.dll"
-#define kWanWangProtocolHandlerPlugin L"npww.dll"
-#define kFlashPlugin L"npswf32.dll"
-#define kAcrobatReaderPlugin L"nppdf32.dll"
-#define kRealPlayerPlugin L"nppl3260.dll"
-#define kSilverlightPlugin L"npctrl.dll"
-#define kJavaPlugin1 L"npjp2.dll"
-#define kJavaPlugin2 L"npdeploytk.dll"
-
-#define kGPUPluginMimeType "application/vnd.google.chrome.gpu-plugin"
-
-#endif // WEBKIT_GLUE_PLUGIN_PLUGIN_LIST_H_
diff --git a/webkit/glue/plugins/plugin_group.cc b/webkit/glue/plugins/plugin_group.cc
deleted file mode 100644
index e68649c..0000000
--- a/webkit/glue/plugins/plugin_group.cc
+++ /dev/null
@@ -1,419 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/plugin_group.h"
-
-#include "base/linked_ptr.h"
-#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "base/values.h"
-#include "base/version.h"
-#include "webkit/glue/plugins/plugin_list.h"
-#include "webkit/glue/plugins/webplugininfo.h"
-
-const char* PluginGroup::kAdobeReader8GroupName = "Adobe Reader 8";
-const char* PluginGroup::kAdobeReader9GroupName = "Adobe Reader 9";
-
-#if defined(OS_MACOSX)
-// Plugin Groups for Mac.
-// Plugins are listed here as soon as vulnerabilities and solutions
-// (new versions) are published.
-// TODO(panayiotis): Get the Real Player version on Mac, somehow.
-static const PluginGroupDefinition kGroupDefinitions[] = {
- { "apple-quicktime", "Quicktime", "QuickTime Plug-in", "", "", "7.6.6",
- "http://www.apple.com/quicktime/download/" },
- { "java-runtime-environment", "Java", "Java", "", "", "",
- "http://support.apple.com/kb/HT1338" },
- { "adobe-flash-player", "Flash", "Shockwave Flash", "", "", "10.1.102",
- "http://get.adobe.com/flashplayer/" },
- { "silverlight-3", "Silverlight 3", "Silverlight", "0", "4", "3.0.50106.0",
- "http://www.microsoft.com/getsilverlight/" },
- { "silverlight-4", "Silverlight 4", "Silverlight", "4", "5", "",
- "http://www.microsoft.com/getsilverlight/" },
- { "flip4mac", "Flip4Mac", "Flip4Mac", "", "", "2.2.1",
- "http://www.telestream.net/flip4mac-wmv/overview.htm" },
- { "shockwave", "Shockwave", "Shockwave for Director", "", "", "11.5.9.615",
- "http://www.adobe.com/shockwave/download/" }
-};
-
-#elif defined(OS_WIN)
-// TODO(panayiotis): We should group "RealJukebox NS Plugin" with the rest of
-// the RealPlayer files.
-static const PluginGroupDefinition kGroupDefinitions[] = {
- { "apple-quicktime", "Quicktime", "QuickTime Plug-in", "", "", "7.6.8",
- "http://www.apple.com/quicktime/download/" },
- { "java-runtime-environment", "Java 6", "Java", "", "6", "6.0.220",
- "http://www.java.com/" },
- { "adobe-reader", PluginGroup::kAdobeReader9GroupName, "Adobe Acrobat", "9",
- "10", "9.4.1", "http://get.adobe.com/reader/" },
- { "adobe-reader-8", PluginGroup::kAdobeReader8GroupName, "Adobe Acrobat", "0",
- "9", "8.2.5", "http://get.adobe.com/reader/" },
- { "adobe-flash-player", "Flash", "Shockwave Flash", "", "", "10.1.102",
- "http://get.adobe.com/flashplayer/" },
- { "silverlight-3", "Silverlight 3", "Silverlight", "0", "4", "3.0.50106.0",
- "http://www.microsoft.com/getsilverlight/" },
- { "silverlight-4", "Silverlight 4", "Silverlight", "4", "5", "",
- "http://www.microsoft.com/getsilverlight/" },
- { "shockwave", "Shockwave", "Shockwave for Director", "", "", "11.5.9.615",
- "http://www.adobe.com/shockwave/download/" },
- { "divx-player", "DivX Player", "DivX Web Player", "", "", "1.4.3.4",
- "http://download.divx.com/divx/autoupdate/player/"
- "DivXWebPlayerInstaller.exe" },
- // These are here for grouping, no vulnerabilies known.
- { "windows-media-player", "Windows Media Player", "Windows Media Player",
- "", "", "", "" },
- { "microsoft-office", "Microsoft Office", "Microsoft Office",
- "", "", "", "" },
- // TODO(panayiotis): The vulnerable versions are
- // (v >= 6.0.12.1040 && v <= 6.0.12.1663)
- // || v == 6.0.12.1698 || v == 6.0.12.1741
- { "realplayer", "RealPlayer", "RealPlayer", "", "", "",
- "http://www.adobe.com/shockwave/download/" },
-};
-
-#else
-static const PluginGroupDefinition kGroupDefinitions[] = {};
-#endif
-
-/*static*/
-std::set<string16>* PluginGroup::policy_disabled_plugin_patterns_;
-
-/*static*/
-const PluginGroupDefinition* PluginGroup::GetPluginGroupDefinitions() {
- return kGroupDefinitions;
-}
-
-/*static*/
-size_t PluginGroup::GetPluginGroupDefinitionsSize() {
- // TODO(viettrungluu): |arraysize()| doesn't work with zero-size arrays.
- return ARRAYSIZE_UNSAFE(kGroupDefinitions);
-}
-
-/*static*/
-void PluginGroup::SetPolicyDisabledPluginPatterns(
- const std::set<string16>& set) {
- if (!policy_disabled_plugin_patterns_)
- policy_disabled_plugin_patterns_ = new std::set<string16>(set);
- else
- *policy_disabled_plugin_patterns_ = set;
-}
-
-/*static*/
-bool PluginGroup::IsPluginNameDisabledByPolicy(const string16& plugin_name) {
- if (!policy_disabled_plugin_patterns_)
- return false;
-
- std::set<string16>::const_iterator pattern(
- policy_disabled_plugin_patterns_->begin());
- while (pattern != policy_disabled_plugin_patterns_->end()) {
- if (MatchPattern(plugin_name, *pattern))
- return true;
- ++pattern;
- }
-
- return false;
-}
-
-/*static*/
-bool PluginGroup::IsPluginPathDisabledByPolicy(const FilePath& plugin_path) {
- std::vector<WebPluginInfo> plugins;
- NPAPI::PluginList::Singleton()->GetPlugins(false, &plugins);
- for (std::vector<WebPluginInfo>::const_iterator it = plugins.begin();
- it != plugins.end();
- ++it) {
- if (FilePath::CompareEqualIgnoreCase(it->path.value(),
- plugin_path.value()) && IsPluginNameDisabledByPolicy(it->name)) {
- return true;
- }
- }
- return false;
-}
-
-PluginGroup::PluginGroup(const string16& group_name,
- const string16& name_matcher,
- const std::string& version_range_low,
- const std::string& version_range_high,
- const std::string& min_version,
- const std::string& update_url,
- const std::string& identifier)
- : identifier_(identifier),
- group_name_(group_name),
- name_matcher_(name_matcher),
- version_range_low_str_(version_range_low),
- version_range_high_str_(version_range_high),
- update_url_(update_url),
- enabled_(false),
- min_version_str_(min_version),
- version_(Version::GetVersionFromString("0")) {
- if (!version_range_low.empty())
- version_range_low_.reset(Version::GetVersionFromString(version_range_low));
- if (!version_range_high.empty()) {
- version_range_high_.reset(
- Version::GetVersionFromString(version_range_high));
- }
- if (!min_version.empty())
- min_version_.reset(Version::GetVersionFromString(min_version));
-}
-
-PluginGroup* PluginGroup::FromPluginGroupDefinition(
- const PluginGroupDefinition& definition) {
- return new PluginGroup(ASCIIToUTF16(definition.name),
- ASCIIToUTF16(definition.name_matcher),
- definition.version_matcher_low,
- definition.version_matcher_high,
- definition.min_version,
- definition.update_url,
- definition.identifier);
-}
-
-PluginGroup::~PluginGroup() { }
-
-PluginGroup* PluginGroup::FromWebPluginInfo(const WebPluginInfo& wpi) {
- // Create a matcher from the name of this plugin.
-#if defined(OS_POSIX)
- std::string identifier = wpi.path.BaseName().value();
-#elif defined(OS_WIN)
- std::string identifier = base::SysWideToUTF8(wpi.path.BaseName().value());
-#endif
- return new PluginGroup(wpi.name, wpi.name, std::string(), std::string(),
- std::string(), std::string(), identifier);
-}
-
-PluginGroup* PluginGroup::CopyOrCreatePluginGroup(
- const WebPluginInfo& info) {
- static PluginMap* hardcoded_plugin_groups = NULL;
- if (!hardcoded_plugin_groups) {
- PluginMap* groups = new PluginMap();
- const PluginGroupDefinition* definitions = GetPluginGroupDefinitions();
- for (size_t i = 0; i < GetPluginGroupDefinitionsSize(); ++i) {
- PluginGroup* definition_group = PluginGroup::FromPluginGroupDefinition(
- definitions[i]);
- std::string identifier = definition_group->identifier();
- DCHECK(groups->find(identifier) == groups->end());
- (*groups)[identifier] = linked_ptr<PluginGroup>(definition_group);
- }
- hardcoded_plugin_groups = groups;
- }
-
- // See if this plugin matches any of the hardcoded groups.
- PluginGroup* hardcoded_group = FindGroupMatchingPlugin(
- *hardcoded_plugin_groups, info);
- if (hardcoded_group) {
- // Make a copy.
- return hardcoded_group->Copy();
- } else {
- // Not found in our hardcoded list, create a new one.
- return PluginGroup::FromWebPluginInfo(info);
- }
-}
-
-PluginGroup* PluginGroup::FindGroupMatchingPlugin(
- const PluginMap& plugin_groups,
- const WebPluginInfo& plugin) {
- for (std::map<std::string, linked_ptr<PluginGroup> >::const_iterator it =
- plugin_groups.begin();
- it != plugin_groups.end();
- ++it) {
- if (it->second->Match(plugin))
- return it->second.get();
- }
- return NULL;
-}
-
-bool PluginGroup::Match(const WebPluginInfo& plugin) const {
- if (name_matcher_.empty()) {
- return false;
- }
-
- // Look for the name matcher anywhere in the plugin name.
- if (plugin.name.find(name_matcher_) == string16::npos) {
- return false;
- }
-
- if (version_range_low_.get() == NULL ||
- version_range_high_.get() == NULL) {
- return true;
- }
-
- // There's a version range, we must be in it.
- scoped_ptr<Version> plugin_version(
- Version::GetVersionFromString(UTF16ToWide(plugin.version)));
- if (plugin_version.get() == NULL) {
- // No version could be extracted, assume we don't match the range.
- return false;
- }
-
- // We match if we are in the range: [low, high)
- return (version_range_low_->CompareTo(*plugin_version) <= 0 &&
- version_range_high_->CompareTo(*plugin_version) > 0);
-}
-
-Version* PluginGroup::CreateVersionFromString(const string16& version_string) {
- // Remove spaces and ')' from the version string,
- // Replace any instances of 'r', ',' or '(' with a dot.
- std::wstring version = UTF16ToWide(version_string);
- RemoveChars(version, L") ", &version);
- std::replace(version.begin(), version.end(), 'r', '.');
- std::replace(version.begin(), version.end(), ',', '.');
- std::replace(version.begin(), version.end(), '(', '.');
-
- return Version::GetVersionFromString(version);
-}
-
-void PluginGroup::UpdateActivePlugin(const WebPluginInfo& plugin) {
- // A group is enabled if any of the files are enabled.
- if (plugin.enabled) {
- if (!enabled_) {
- // If this is the first enabled plugin, use its description.
- enabled_ = true;
- UpdateDescriptionAndVersion(plugin);
- }
- } else {
- // If this is the first plugin and it's disabled,
- // use its description for now.
- if (description_.empty())
- UpdateDescriptionAndVersion(plugin);
- }
-}
-
-void PluginGroup::UpdateDescriptionAndVersion(const WebPluginInfo& plugin) {
- description_ = plugin.desc;
- if (Version* new_version = CreateVersionFromString(plugin.version))
- version_.reset(new_version);
- else
- version_.reset(Version::GetVersionFromString("0"));
-}
-
-void PluginGroup::AddPlugin(const WebPluginInfo& plugin, int position) {
- web_plugin_infos_.push_back(plugin);
- // The position of this plugin relative to the global list of plugins.
- web_plugin_positions_.push_back(position);
- UpdateActivePlugin(plugin);
-}
-
-string16 PluginGroup::GetGroupName() const {
- if (!group_name_.empty())
- return group_name_;
- DCHECK_EQ(1u, web_plugin_infos_.size());
- FilePath::StringType path =
- web_plugin_infos_[0].path.BaseName().RemoveExtension().value();
-#if defined(OS_POSIX)
- return UTF8ToUTF16(path);
-#elif defined(OS_WIN)
- return WideToUTF16(path);
-#endif
-}
-
-DictionaryValue* PluginGroup::GetSummary() const {
- DictionaryValue* result = new DictionaryValue();
- result->SetString("name", GetGroupName());
- result->SetBoolean("enabled", enabled_);
- return result;
-}
-
-DictionaryValue* PluginGroup::GetDataForUI() const {
- string16 name = GetGroupName();
- DictionaryValue* result = new DictionaryValue();
- result->SetString("name", name);
- result->SetString("description", description_);
- result->SetString("version", version_->GetString());
- result->SetString("update_url", update_url_);
- result->SetBoolean("critical", IsVulnerable());
-
- bool group_disabled_by_policy = IsPluginNameDisabledByPolicy(name);
- ListValue* plugin_files = new ListValue();
- bool all_plugins_disabled_by_policy = true;
- for (size_t i = 0; i < web_plugin_infos_.size(); ++i) {
- const WebPluginInfo& web_plugin = web_plugin_infos_[i];
- int priority = web_plugin_positions_[i];
- DictionaryValue* plugin_file = new DictionaryValue();
- plugin_file->SetString("name", web_plugin.name);
- plugin_file->SetString("description", web_plugin.desc);
- plugin_file->SetString("path", web_plugin.path.value());
- plugin_file->SetString("version", web_plugin.version);
- bool plugin_disabled_by_policy = group_disabled_by_policy ||
- IsPluginNameDisabledByPolicy(web_plugin.name);
- if (plugin_disabled_by_policy) {
- plugin_file->SetString("enabledMode", "disabledByPolicy");
- } else {
- all_plugins_disabled_by_policy = false;
- plugin_file->SetString("enabledMode",
- web_plugin.enabled ? "enabled" : "disabledByUser");
- }
- plugin_file->SetInteger("priority", priority);
-
- ListValue* mime_types = new ListValue();
- for (std::vector<WebPluginMimeType>::const_iterator type_it =
- web_plugin.mime_types.begin();
- type_it != web_plugin.mime_types.end();
- ++type_it) {
- DictionaryValue* mime_type = new DictionaryValue();
- mime_type->SetString("mimeType", type_it->mime_type);
- mime_type->SetString("description", type_it->description);
-
- ListValue* file_extensions = new ListValue();
- for (std::vector<std::string>::const_iterator ext_it =
- type_it->file_extensions.begin();
- ext_it != type_it->file_extensions.end();
- ++ext_it) {
- file_extensions->Append(new StringValue(*ext_it));
- }
- mime_type->Set("fileExtensions", file_extensions);
-
- mime_types->Append(mime_type);
- }
- plugin_file->Set("mimeTypes", mime_types);
-
- plugin_files->Append(plugin_file);
- }
-
- if (group_disabled_by_policy || all_plugins_disabled_by_policy) {
- result->SetString("enabledMode", "disabledByPolicy");
- } else {
- result->SetString("enabledMode", enabled_ ? "enabled" : "disabledByUser");
- }
- result->Set("plugin_files", plugin_files);
-
- return result;
-}
-
-// Returns true if the latest version of this plugin group is vulnerable.
-bool PluginGroup::IsVulnerable() const {
- if (min_version_.get() == NULL || version_->GetString() == "0") {
- return false;
- }
- return version_->CompareTo(*min_version_) < 0;
-}
-
-void PluginGroup::DisableOutdatedPlugins() {
- if (!min_version_.get())
- return;
-
- description_ = string16();
- enabled_ = false;
-
- for (std::vector<WebPluginInfo>::iterator it =
- web_plugin_infos_.begin();
- it != web_plugin_infos_.end(); ++it) {
- scoped_ptr<Version> version(CreateVersionFromString(it->version));
- if (version.get() && version->CompareTo(*min_version_) < 0) {
- it->enabled = false;
- NPAPI::PluginList::Singleton()->DisablePlugin(it->path);
- }
- UpdateActivePlugin(*it);
- }
-}
-
-void PluginGroup::Enable(bool enable) {
- for (std::vector<WebPluginInfo>::const_iterator it =
- web_plugin_infos_.begin();
- it != web_plugin_infos_.end(); ++it) {
- if (enable && !IsPluginNameDisabledByPolicy(it->name)) {
- NPAPI::PluginList::Singleton()->EnablePlugin(it->path);
- } else {
- NPAPI::PluginList::Singleton()->DisablePlugin(it->path);
- }
- }
-}
diff --git a/webkit/glue/plugins/plugin_group.h b/webkit/glue/plugins/plugin_group.h
deleted file mode 100644
index 2281437..0000000
--- a/webkit/glue/plugins/plugin_group.h
+++ /dev/null
@@ -1,184 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PLUGIN_GROUP_H_
-#define WEBKIT_GLUE_PLUGINS_PLUGIN_GROUP_H_
-#pragma once
-
-#include <map>
-#include <set>
-#include <vector>
-
-#include "base/gtest_prod_util.h"
-#include "base/scoped_ptr.h"
-#include "base/string16.h"
-
-class DictionaryValue;
-class FilePath;
-class Version;
-struct WebPluginInfo;
-
-namespace NPAPI {
- class PluginList;
-};
-
-template <typename T>
-class linked_ptr;
-
-// Hard-coded definitions of plugin groups.
-struct PluginGroupDefinition {
- const char* identifier; // Unique identifier for this group.
- const char* name; // Name of this group.
- const char* name_matcher; // Substring matcher for the plugin name.
- const char* version_matcher_low; // Matchers for the plugin version.
- const char* version_matcher_high;
- const char* min_version; // Minimum secure version.
- const char* update_url; // Location of latest secure version.
-};
-
-// A PluginGroup can match a range of versions of a specific plugin (as defined
-// by matching a substring of its name).
-// It contains all WebPluginInfo structs (at least one) matching its definition.
-// In addition, it knows about a security "baseline", i.e. the minimum version
-// of a plugin that is needed in order not to exhibit known security
-// vulnerabilities.
-
-class PluginGroup {
- public:
- // Used by about:plugins to disable Reader plugin when internal PDF viewer is
- // enabled.
- static const char* kAdobeReader8GroupName;
- static const char* kAdobeReader9GroupName;
-
- typedef std::map<std::string, linked_ptr<PluginGroup> > PluginMap;
-
- // Creates a PluginGroup from a PluginGroupDefinition.
- static PluginGroup* FromPluginGroupDefinition(
- const PluginGroupDefinition& definition);
-
- ~PluginGroup();
-
- // Creates a PluginGroup from a WebPluginInfo -- when no hard-coded
- // definition is found.
- static PluginGroup* FromWebPluginInfo(const WebPluginInfo& wpi);
-
- // Find a plugin group matching |info| in the list of hardcoded plugins and
- // returns a copy of it if found, or a new group matching exactly this plugin
- // otherwise.
- // The caller should take ownership of the return PluginGroup.
- static PluginGroup* CopyOrCreatePluginGroup(const WebPluginInfo& info);
-
- // Configures the set of plugin name patterns for disabling plugins via
- // enterprise configuration management.
- static void SetPolicyDisabledPluginPatterns(const std::set<string16>& set);
-
- // Tests to see if a plugin is on the blacklist using its name as
- // the lookup key.
- static bool IsPluginNameDisabledByPolicy(const string16& plugin_name);
-
- // Tests to see if a plugin is on the blacklist using its path as
- // the lookup key.
- static bool IsPluginPathDisabledByPolicy(const FilePath& plugin_path);
-
- // Find the PluginGroup matching a Plugin in a list of plugin groups. Returns
- // NULL if no matching PluginGroup is found.
- static PluginGroup* FindGroupMatchingPlugin(
- const std::map<std::string, linked_ptr<PluginGroup> >& plugin_groups,
- const WebPluginInfo& plugin);
-
- // Creates a copy of this plugin group.
- PluginGroup* Copy() {
- return new PluginGroup(group_name_, name_matcher_, version_range_low_str_,
- version_range_high_str_, min_version_str_,
- update_url_, identifier_);
- }
-
- // Returns true if the given plugin matches this group.
- bool Match(const WebPluginInfo& plugin) const;
-
- // Adds the given plugin to this group. Provide the position of the
- // plugin as given by PluginList so we can display its priority.
- void AddPlugin(const WebPluginInfo& plugin, int position);
-
- // Enables/disables this group. This enables/disables all plugins in the
- // group.
- void Enable(bool enable);
-
- // Returns whether the plugin group is enabled or not.
- bool Enabled() const { return enabled_; }
-
- // Returns a unique identifier for this group, if one is defined, or the empty
- // string otherwise.
- const std::string& identifier() const { return identifier_; }
-
- // Returns this group's name, or the filename without extension if the name
- // is empty.
- string16 GetGroupName() const;
-
- // Returns the description of the highest-priority plug-in in the group.
- const string16& description() const { return description_; }
-
- // Returns a DictionaryValue with data to display in the UI.
- DictionaryValue* GetDataForUI() const;
-
- // Returns a DictionaryValue with data to save in the preferences.
- DictionaryValue* GetSummary() const;
-
- // Returns the update URL.
- std::string GetUpdateURL() const { return update_url_; }
-
- // Returns true if the highest-priority plugin in this group has known
- // security problems.
- bool IsVulnerable() const;
-
- // Disables all plugins in this group that are older than the
- // minimum version.
- void DisableOutdatedPlugins();
-
- private:
- FRIEND_TEST_ALL_PREFIXES(PluginGroupTest, PluginGroupDefinition);
-
- static const PluginGroupDefinition* GetPluginGroupDefinitions();
- static size_t GetPluginGroupDefinitionsSize();
-
- PluginGroup(const string16& group_name,
- const string16& name_matcher,
- const std::string& version_range_low,
- const std::string& version_range_high,
- const std::string& min_version,
- const std::string& update_url,
- const std::string& identifier);
-
- Version* CreateVersionFromString(const string16& version_string);
-
- // Set the description and version for this plugin group from the
- // given plug-in.
- void UpdateDescriptionAndVersion(const WebPluginInfo& plugin);
-
- // Updates the active plugin in the group. The active plugin is the first
- // enabled one, or if all plugins are disabled, simply the first one.
- void UpdateActivePlugin(const WebPluginInfo& plugin);
-
- static std::set<string16>* policy_disabled_plugin_patterns_;
-
- std::string identifier_;
- string16 group_name_;
- string16 name_matcher_;
- std::string version_range_low_str_;
- std::string version_range_high_str_;
- scoped_ptr<Version> version_range_low_;
- scoped_ptr<Version> version_range_high_;
- string16 description_;
- std::string update_url_;
- bool enabled_;
- std::string min_version_str_;
- scoped_ptr<Version> min_version_;
- scoped_ptr<Version> version_;
- std::vector<WebPluginInfo> web_plugin_infos_;
- std::vector<int> web_plugin_positions_;
-
- DISALLOW_COPY_AND_ASSIGN(PluginGroup);
-};
-
-#endif // WEBKIT_GLUE_PLUGINS_PLUGIN_GROUP_H_
diff --git a/webkit/glue/plugins/plugin_group_unittest.cc b/webkit/glue/plugins/plugin_group_unittest.cc
deleted file mode 100644
index 467c273..0000000
--- a/webkit/glue/plugins/plugin_group_unittest.cc
+++ /dev/null
@@ -1,181 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/plugin_group.h"
-
-#include <string>
-#include <vector>
-
-#include "base/scoped_ptr.h"
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-#include "base/values.h"
-#include "base/version.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/glue/plugins/webplugininfo.h"
-
-static const PluginGroupDefinition kPluginDef = {
- "myplugin", "MyPlugin", "MyPlugin", "", "", "3.0.44", "http://latest/" };
-static const PluginGroupDefinition kPluginDef3 = {
- "myplugin-3", "MyPlugin 3", "MyPlugin", "0", "4", "3.0.44", "http://latest" };
-static const PluginGroupDefinition kPluginDef4 = {
- "myplugin-4", "MyPlugin 4", "MyPlugin", "4", "5", "4.0.44", "http://latest" };
-static const PluginGroupDefinition kPluginDefNotVulnerable = {
- "myplugin-latest", "MyPlugin", "MyPlugin", "", "", "", "http://latest" };
-
-// name, path, version, desc, mime_types, enabled.
-static WebPluginInfo kPlugin2043 = WebPluginInfo(
- ASCIIToUTF16("MyPlugin"), ASCIIToUTF16("2.0.43"),
- ASCIIToUTF16("MyPlugin version 2.0.43"));
-static WebPluginInfo kPlugin3043 = WebPluginInfo(
- ASCIIToUTF16("MyPlugin"), ASCIIToUTF16("3.0.43"),
- ASCIIToUTF16("MyPlugin version 3.0.43"));
-static WebPluginInfo kPlugin3044 = WebPluginInfo(
- ASCIIToUTF16("MyPlugin"), ASCIIToUTF16("3.0.44"),
- ASCIIToUTF16("MyPlugin version 3.0.44"));
-static WebPluginInfo kPlugin3045 = WebPluginInfo(
- ASCIIToUTF16("MyPlugin"), ASCIIToUTF16("3.0.45"),
- ASCIIToUTF16("MyPlugin version 3.0.45"));
-static WebPluginInfo kPlugin4043 = WebPluginInfo(
- ASCIIToUTF16("MyPlugin"), ASCIIToUTF16("4.0.43"),
- ASCIIToUTF16("MyPlugin version 4.0.43"));
-
-class PluginGroupTest : public testing::Test {
- protected:
- virtual void TearDown() {
- PluginGroup::SetPolicyDisabledPluginPatterns(std::set<string16>());
- }
-};
-
-TEST(PluginGroupTest, PluginGroupMatch) {
- scoped_ptr<PluginGroup> group(PluginGroup::FromPluginGroupDefinition(
- kPluginDef3));
- EXPECT_TRUE(group->Match(kPlugin3045));
- group->AddPlugin(kPlugin3045, 0);
- EXPECT_FALSE(group->IsVulnerable());
-}
-
-TEST(PluginGroupTest, PluginGroupMatchCorrectVersion) {
- scoped_ptr<PluginGroup> group(PluginGroup::FromPluginGroupDefinition(
- kPluginDef3));
- EXPECT_TRUE(group->Match(kPlugin2043));
- EXPECT_TRUE(group->Match(kPlugin3043));
- EXPECT_FALSE(group->Match(kPlugin4043));
-
- group.reset(PluginGroup::FromPluginGroupDefinition(kPluginDef4));
- EXPECT_FALSE(group->Match(kPlugin2043));
- EXPECT_FALSE(group->Match(kPlugin3043));
- EXPECT_TRUE(group->Match(kPlugin4043));
-}
-
-TEST(PluginGroupTest, PluginGroupDescription) {
- string16 desc3043(ASCIIToUTF16("MyPlugin version 3.0.43"));
- string16 desc3045(ASCIIToUTF16("MyPlugin version 3.0.45"));
- WebPluginInfo plugin3043(kPlugin3043);
- WebPluginInfo plugin3045(kPlugin3045);
-
- {
- scoped_ptr<PluginGroup> group(PluginGroup::FromPluginGroupDefinition(
- kPluginDef3));
- EXPECT_TRUE(group->Match(plugin3043));
- group->AddPlugin(plugin3043, 0);
- EXPECT_EQ(desc3043, group->description());
- EXPECT_TRUE(group->IsVulnerable());
- EXPECT_TRUE(group->Match(plugin3045));
- group->AddPlugin(plugin3045, 1);
- EXPECT_EQ(desc3043, group->description());
- EXPECT_TRUE(group->IsVulnerable());
- }
-
- {
- // Disable the first plugin.
- plugin3043.enabled = false;
- scoped_ptr<PluginGroup> group(PluginGroup::FromPluginGroupDefinition(
- kPluginDef3));
- EXPECT_TRUE(group->Match(plugin3043));
- group->AddPlugin(plugin3043, 0);
- EXPECT_EQ(desc3043, group->description());
- EXPECT_TRUE(group->IsVulnerable());
- EXPECT_TRUE(group->Match(plugin3045));
- group->AddPlugin(plugin3045, 1);
- EXPECT_EQ(desc3045, group->description());
- EXPECT_FALSE(group->IsVulnerable());
- }
-
- {
- // Disable the second plugin.
- plugin3045.enabled = false;
- scoped_ptr<PluginGroup> group(PluginGroup::FromPluginGroupDefinition(
- kPluginDef3));
- EXPECT_TRUE(group->Match(plugin3043));
- group->AddPlugin(plugin3043, 1);
- EXPECT_EQ(desc3043, group->description());
- EXPECT_TRUE(group->IsVulnerable());
- EXPECT_TRUE(group->Match(plugin3045));
- group->AddPlugin(plugin3045, 0);
- EXPECT_EQ(desc3043, group->description());
- EXPECT_TRUE(group->IsVulnerable());
- }
-}
-
-TEST(PluginGroupTest, PluginGroupDefinition) {
- const PluginGroupDefinition* definitions =
- PluginGroup::GetPluginGroupDefinitions();
- for (size_t i = 0; i < PluginGroup::GetPluginGroupDefinitionsSize(); ++i) {
- scoped_ptr<PluginGroup> def_group(
- PluginGroup::FromPluginGroupDefinition(definitions[i]));
- ASSERT_TRUE(def_group.get() != NULL);
- EXPECT_FALSE(def_group->Match(kPlugin2043));
- }
-}
-
-TEST(PluginGroupTest, DisableOutdated) {
- scoped_ptr<PluginGroup> group(PluginGroup::FromPluginGroupDefinition(
- kPluginDef3));
- group->AddPlugin(kPlugin3043, 0);
- group->AddPlugin(kPlugin3045, 1);
- EXPECT_EQ(ASCIIToUTF16("MyPlugin version 3.0.43"), group->description());
- EXPECT_TRUE(group->IsVulnerable());
-
- group->DisableOutdatedPlugins();
- EXPECT_EQ(ASCIIToUTF16("MyPlugin version 3.0.45"), group->description());
- EXPECT_FALSE(group->IsVulnerable());
-}
-
-TEST(PluginGroupTest, VersionExtraction) {
- // Some real-world plugin versions (spaces, commata, parentheses, 'r', oh my)
- const char* versions[][2] = {
- { "7.6.6 (1671)", "7.6.6.1671" }, // Quicktime
- { "2, 0, 0, 254", "2.0.0.254" }, // DivX
- { "3, 0, 0, 0", "3.0.0.0" }, // Picasa
- { "1, 0, 0, 1", "1.0.0.1" }, // Earth
- { "10,0,45,2", "10.0.45.2" }, // Flash
- { "11.5.7r609", "11.5.7.609"} // Shockwave
- };
-
- for (size_t i = 0; i < arraysize(versions); i++) {
- const WebPluginInfo plugin = WebPluginInfo(
- ASCIIToUTF16("Blah Plugin"), ASCIIToUTF16(versions[i][0]), string16());
- scoped_ptr<PluginGroup> group(PluginGroup::FromWebPluginInfo(plugin));
- EXPECT_TRUE(group->Match(plugin));
- group->AddPlugin(plugin, 0);
- scoped_ptr<DictionaryValue> data(group->GetDataForUI());
- std::string version;
- data->GetString("version", &version);
- EXPECT_EQ(versions[i][1], version);
- }
-}
-
-TEST(PluginGroupTest, DisabledByPolicy) {
- std::set<string16> disabled_plugins;
- disabled_plugins.insert(ASCIIToUTF16("Disable this!"));
- disabled_plugins.insert(ASCIIToUTF16("*Google*"));
- PluginGroup::SetPolicyDisabledPluginPatterns(disabled_plugins);
-
- EXPECT_FALSE(PluginGroup::IsPluginNameDisabledByPolicy(ASCIIToUTF16("42")));
- EXPECT_TRUE(PluginGroup::IsPluginNameDisabledByPolicy(
- ASCIIToUTF16("Disable this!")));
- EXPECT_TRUE(PluginGroup::IsPluginNameDisabledByPolicy(
- ASCIIToUTF16("Google Earth")));
-}
diff --git a/webkit/glue/plugins/plugin_host.cc b/webkit/glue/plugins/plugin_host.cc
deleted file mode 100644
index 670f589..0000000
--- a/webkit/glue/plugins/plugin_host.cc
+++ /dev/null
@@ -1,1104 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/plugin_host.h"
-
-#include "base/file_util.h"
-#include "base/logging.h"
-#include "base/scoped_ptr.h"
-#include "base/string_piece.h"
-#include "base/string_util.h"
-#if defined(OS_MACOSX)
-#include "base/sys_info.h"
-#endif
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "net/base/net_util.h"
-#include "third_party/npapi/bindings/npapi_extensions.h"
-#include "third_party/npapi/bindings/npruntime.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebBindings.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebKit.h"
-#include "webkit/glue/webkit_glue.h"
-#include "webkit/glue/plugins/default_plugin_shared.h"
-#include "webkit/glue/plugins/npapi_extension_thunk.h"
-#include "webkit/glue/plugins/plugin_instance.h"
-#include "webkit/glue/plugins/plugin_lib.h"
-#include "webkit/glue/plugins/plugin_list.h"
-#include "webkit/glue/plugins/plugin_stream_url.h"
-#include "webkit/glue/plugins/webplugin_delegate.h"
-#include "webkit/glue/plugins/webplugininfo.h"
-
-using WebKit::WebBindings;
-
-// Finds a PluginInstance from an NPP.
-// The caller must take a reference if needed.
-static NPAPI::PluginInstance* FindInstance(NPP id) {
- if (id == NULL) {
- return NULL;
- }
- return reinterpret_cast<NPAPI::PluginInstance*>(id->ndata);
-}
-
-#if defined(OS_MACOSX)
-// Returns true if the OS supports shared accelerated surfaces via IOSurface.
-// This is true on Snow Leopard and higher.
-static bool SupportsSharingAcceleratedSurfaces() {
- int32 major, minor, bugfix;
- base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix);
- return major > 10 || (major == 10 && minor > 5);
-}
-#endif
-
-namespace NPAPI {
-
-scoped_refptr<PluginHost> PluginHost::singleton_;
-
-PluginHost::PluginHost() {
- InitializeHostFuncs();
-}
-
-PluginHost::~PluginHost() {
-}
-
-PluginHost *PluginHost::Singleton() {
- if (singleton_.get() == NULL) {
- singleton_ = new PluginHost();
- }
-
- DCHECK(singleton_.get() != NULL);
- return singleton_;
-}
-
-void PluginHost::InitializeHostFuncs() {
- memset(&host_funcs_, 0, sizeof(host_funcs_));
- host_funcs_.size = sizeof(host_funcs_);
- host_funcs_.version = (NP_VERSION_MAJOR << 8) | (NP_VERSION_MINOR);
-
- // The "basic" functions
- host_funcs_.geturl = &NPN_GetURL;
- host_funcs_.posturl = &NPN_PostURL;
- host_funcs_.requestread = &NPN_RequestRead;
- host_funcs_.newstream = &NPN_NewStream;
- host_funcs_.write = &NPN_Write;
- host_funcs_.destroystream = &NPN_DestroyStream;
- host_funcs_.status = &NPN_Status;
- host_funcs_.uagent = &NPN_UserAgent;
- host_funcs_.memalloc = &NPN_MemAlloc;
- host_funcs_.memfree = &NPN_MemFree;
- host_funcs_.memflush = &NPN_MemFlush;
- host_funcs_.reloadplugins = &NPN_ReloadPlugins;
-
- // We don't implement java yet
- host_funcs_.getJavaEnv = &NPN_GetJavaEnv;
- host_funcs_.getJavaPeer = &NPN_GetJavaPeer;
-
- // Advanced functions we implement
- host_funcs_.geturlnotify = &NPN_GetURLNotify;
- host_funcs_.posturlnotify = &NPN_PostURLNotify;
- host_funcs_.getvalue = &NPN_GetValue;
- host_funcs_.setvalue = &NPN_SetValue;
- host_funcs_.invalidaterect = &NPN_InvalidateRect;
- host_funcs_.invalidateregion = &NPN_InvalidateRegion;
- host_funcs_.forceredraw = &NPN_ForceRedraw;
-
- // These come from the Javascript Engine
- host_funcs_.getstringidentifier = WebBindings::getStringIdentifier;
- host_funcs_.getstringidentifiers = WebBindings::getStringIdentifiers;
- host_funcs_.getintidentifier = WebBindings::getIntIdentifier;
- host_funcs_.identifierisstring = WebBindings::identifierIsString;
- host_funcs_.utf8fromidentifier = WebBindings::utf8FromIdentifier;
- host_funcs_.intfromidentifier = WebBindings::intFromIdentifier;
- host_funcs_.createobject = WebBindings::createObject;
- host_funcs_.retainobject = WebBindings::retainObject;
- host_funcs_.releaseobject = WebBindings::releaseObject;
- host_funcs_.invoke = WebBindings::invoke;
- host_funcs_.invokeDefault = WebBindings::invokeDefault;
- host_funcs_.evaluate = WebBindings::evaluate;
- host_funcs_.getproperty = WebBindings::getProperty;
- host_funcs_.setproperty = WebBindings::setProperty;
- host_funcs_.removeproperty = WebBindings::removeProperty;
- host_funcs_.hasproperty = WebBindings::hasProperty;
- host_funcs_.hasmethod = WebBindings::hasMethod;
- host_funcs_.releasevariantvalue = WebBindings::releaseVariantValue;
- host_funcs_.setexception = WebBindings::setException;
- host_funcs_.pushpopupsenabledstate = NPN_PushPopupsEnabledState;
- host_funcs_.poppopupsenabledstate = NPN_PopPopupsEnabledState;
- host_funcs_.enumerate = WebBindings::enumerate;
- host_funcs_.pluginthreadasynccall = NPN_PluginThreadAsyncCall;
- host_funcs_.construct = WebBindings::construct;
- host_funcs_.getvalueforurl = NPN_GetValueForURL;
- host_funcs_.setvalueforurl = NPN_SetValueForURL;
- host_funcs_.getauthenticationinfo = NPN_GetAuthenticationInfo;
- host_funcs_.scheduletimer = NPN_ScheduleTimer;
- host_funcs_.unscheduletimer = NPN_UnscheduleTimer;
- host_funcs_.popupcontextmenu = NPN_PopUpContextMenu;
- host_funcs_.convertpoint = NPN_ConvertPoint;
- host_funcs_.handleevent = NPN_HandleEvent;
- host_funcs_.unfocusinstance = NPN_UnfocusInstance;
- host_funcs_.urlredirectresponse = NPN_URLRedirectResponse;
-}
-
-void PluginHost::PatchNPNetscapeFuncs(NPNetscapeFuncs* overrides) {
- // When running in the plugin process, we need to patch the NPN functions
- // that the plugin calls to interact with NPObjects that we give. Otherwise
- // the plugin will call the v8 NPN functions, which won't work since we have
- // an NPObjectProxy and not a real v8 implementation.
- if (overrides->invoke)
- host_funcs_.invoke = overrides->invoke;
-
- if (overrides->invokeDefault)
- host_funcs_.invokeDefault = overrides->invokeDefault;
-
- if (overrides->evaluate)
- host_funcs_.evaluate = overrides->evaluate;
-
- if (overrides->getproperty)
- host_funcs_.getproperty = overrides->getproperty;
-
- if (overrides->setproperty)
- host_funcs_.setproperty = overrides->setproperty;
-
- if (overrides->removeproperty)
- host_funcs_.removeproperty = overrides->removeproperty;
-
- if (overrides->hasproperty)
- host_funcs_.hasproperty = overrides->hasproperty;
-
- if (overrides->hasmethod)
- host_funcs_.hasmethod = overrides->hasmethod;
-
- if (overrides->setexception)
- host_funcs_.setexception = overrides->setexception;
-
- if (overrides->enumerate)
- host_funcs_.enumerate = overrides->enumerate;
-}
-
-bool PluginHost::SetPostData(const char* buf,
- uint32 length,
- std::vector<std::string>* names,
- std::vector<std::string>* values,
- std::vector<char>* body) {
- // Use a state table to do the parsing. Whitespace must be
- // trimmed after the fact if desired. In our case, we actually
- // don't care about the whitespace, because we're just going to
- // pass this back into another POST. This function strips out the
- // "Content-length" header and does not append it to the request.
-
- //
- // This parser takes action only on state changes.
- //
- // Transition table:
- // : \n NULL Other
- // 0 GetHeader 1 2 4 0
- // 1 GetValue 1 0 3 1
- // 2 GetData 2 2 3 2
- // 3 DONE
- // 4 ERR
- //
- enum { INPUT_COLON=0, INPUT_NEWLINE, INPUT_NULL, INPUT_OTHER };
- enum { GETNAME, GETVALUE, GETDATA, DONE, ERR };
- int statemachine[3][4] = { { GETVALUE, GETDATA, GETDATA, GETNAME },
- { GETVALUE, GETNAME, DONE, GETVALUE },
- { GETDATA, GETDATA, DONE, GETDATA } };
- std::string name, value;
- const char* ptr = static_cast<const char*>(buf);
- const char* start = ptr;
- int state = GETNAME; // initial state
- bool done = false;
- bool err = false;
- do {
- int input;
-
- // Translate the current character into an input
- // for the state table.
- switch (*ptr) {
- case ':' :
- input = INPUT_COLON;
- break;
- case '\n':
- input = INPUT_NEWLINE;
- break;
- case 0 :
- input = INPUT_NULL;
- break;
- default :
- input = INPUT_OTHER;
- break;
- }
-
- int newstate = statemachine[state][input];
-
- // Take action based on the new state.
- if (state != newstate) {
- switch (newstate) {
- case GETNAME:
- // Got a value.
- value = std::string(start, ptr - start);
- TrimWhitespace(value, TRIM_ALL, &value);
- // If the name field is empty, we'll skip this header
- // but we won't error out.
- if (!name.empty() && name != "content-length") {
- names->push_back(name);
- values->push_back(value);
- }
- start = ptr + 1;
- break;
- case GETVALUE:
- // Got a header.
- name = StringToLowerASCII(std::string(start, ptr - start));
- TrimWhitespace(name, TRIM_ALL, &name);
- start = ptr + 1;
- break;
- case GETDATA: {
- // Finished headers, now get body
- if (*ptr)
- start = ptr + 1;
- size_t previous_size = body->size();
- size_t new_body_size = length - static_cast<int>(start - buf);
- body->resize(previous_size + new_body_size);
- if (!body->empty())
- memcpy(&body->front() + previous_size, start, new_body_size);
- done = true;
- break;
- }
- case ERR:
- // error
- err = true;
- done = true;
- break;
- }
- }
- state = newstate;
- ptr++;
- } while (!done);
-
- return !err;
-}
-
-} // namespace NPAPI
-
-extern "C" {
-
-// Allocates memory from the host's memory space.
-void* NPN_MemAlloc(uint32_t size) {
- // Note: We must use the same allocator/deallocator
- // that is used by the javascript library, as some of the
- // JS APIs will pass memory to the plugin which the plugin
- // will attempt to free.
- return malloc(size);
-}
-
-// Deallocates memory from the host's memory space
-void NPN_MemFree(void* ptr) {
- if (ptr != NULL && ptr != reinterpret_cast<void*>(-1))
- free(ptr);
-}
-
-// Requests that the host free a specified amount of memory.
-uint32_t NPN_MemFlush(uint32_t size) {
- // This is not relevant on Windows; MAC specific
- return size;
-}
-
-// This is for dynamic discovery of new plugins.
-// Should force a re-scan of the plugins directory to load new ones.
-void NPN_ReloadPlugins(NPBool reload_pages) {
- WebKit::resetPluginCache(reload_pages ? true : false);
-}
-
-// Requests a range of bytes for a seekable stream.
-NPError NPN_RequestRead(NPStream* stream, NPByteRange* range_list) {
- if (!stream || !range_list)
- return NPERR_GENERIC_ERROR;
-
- scoped_refptr<NPAPI::PluginInstance> plugin(
- reinterpret_cast<NPAPI::PluginInstance*>(stream->ndata));
- if (!plugin.get())
- return NPERR_GENERIC_ERROR;
-
- plugin->RequestRead(stream, range_list);
- return NPERR_NO_ERROR;
-}
-
-// Generic form of GetURL for common code between GetURL and GetURLNotify.
-static NPError GetURLNotify(NPP id,
- const char* url,
- const char* target,
- bool notify,
- void* notify_data) {
- if (!url)
- return NPERR_INVALID_URL;
-
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (!plugin.get()) {
- return NPERR_GENERIC_ERROR;
- }
-
- plugin->RequestURL(url, "GET", target, NULL, 0, notify, notify_data);
- return NPERR_NO_ERROR;
-}
-
-// Requests creation of a new stream with the contents of the
-// specified URL; gets notification of the result.
-NPError NPN_GetURLNotify(NPP id,
- const char* url,
- const char* target,
- void* notify_data) {
- // This is identical to NPN_GetURL, but after finishing, the
- // browser will call NPP_URLNotify to inform the plugin that
- // it has completed.
-
- // According to the NPAPI documentation, if target == _self
- // or a parent to _self, the browser should return NPERR_INVALID_PARAM,
- // because it can't notify the plugin once deleted. This is
- // absolutely false; firefox doesn't do this, and Flash relies on
- // being able to use this.
-
- // Also according to the NPAPI documentation, we should return
- // NPERR_INVALID_URL if the url requested is not valid. However,
- // this would require that we synchronously start fetching the
- // URL. That just isn't practical. As such, there really is
- // no way to return this error. From looking at the Firefox
- // implementation, it doesn't look like Firefox does this either.
-
- return GetURLNotify(id, url, target, true, notify_data);
-}
-
-NPError NPN_GetURL(NPP id, const char* url, const char* target) {
- // Notes:
- // Request from the Plugin to fetch content either for the plugin
- // or to be placed into a browser window.
- //
- // If target == null, the browser fetches content and streams to plugin.
- // otherwise, the browser loads content into an existing browser frame.
- // If the target is the window/frame containing the plugin, the plugin
- // may be destroyed.
- // If the target is _blank, a mailto: or news: url open content in a new
- // browser window
- // If the target is _self, no other instance of the plugin is created. The
- // plugin continues to operate in its own window
-
- return GetURLNotify(id, url, target, false, 0);
-}
-
-// Generic form of PostURL for common code between PostURL and PostURLNotify.
-static NPError PostURLNotify(NPP id,
- const char* url,
- const char* target,
- uint32_t len,
- const char* buf,
- NPBool file,
- bool notify,
- void* notify_data) {
- if (!url)
- return NPERR_INVALID_URL;
-
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (!plugin.get()) {
- NOTREACHED();
- return NPERR_GENERIC_ERROR;
- }
-
- std::string post_file_contents;
-
- if (file) {
- // Post data to be uploaded from a file. This can be handled in two
- // ways.
- // 1. Read entire file and send the contents as if it was a post data
- // specified in the argument
- // 2. Send just the file details and read them in the browser at the
- // time of sending the request.
- // Approach 2 is more efficient but complicated. Approach 1 has a major
- // drawback of sending potentially large data over two IPC hops. In a way
- // 'large data over IPC' problem exists as it is in case of plugin giving
- // the data directly instead of in a file.
- // Currently we are going with the approach 1 to get the feature working.
- // We can optimize this later with approach 2.
-
- // TODO(joshia): Design a scheme to send a file descriptor instead of
- // entire file contents across.
-
- // Security alert:
- // ---------------
- // Here we are blindly uploading whatever file requested by a plugin.
- // This is risky as someone could exploit a plugin to send private
- // data in arbitrary locations.
- // A malicious (non-sandboxed) plugin has unfeterred access to OS
- // resources and can do this anyway without using browser's HTTP stack.
- // FWIW, Firefox and Safari don't perform any security checks.
-
- if (!buf)
- return NPERR_FILE_NOT_FOUND;
-
- std::string file_path_ascii(buf);
- FilePath file_path;
- static const char kFileUrlPrefix[] = "file:";
- if (StartsWithASCII(file_path_ascii, kFileUrlPrefix, false)) {
- GURL file_url(file_path_ascii);
- DCHECK(file_url.SchemeIsFile());
- net::FileURLToFilePath(file_url, &file_path);
- } else {
- file_path = FilePath::FromWStringHack(
- base::SysNativeMBToWide(file_path_ascii));
- }
-
- base::PlatformFileInfo post_file_info = {0};
- if (!file_util::GetFileInfo(file_path, &post_file_info) ||
- post_file_info.is_directory)
- return NPERR_FILE_NOT_FOUND;
-
- if (!file_util::ReadFileToString(file_path, &post_file_contents))
- return NPERR_FILE_NOT_FOUND;
-
- buf = post_file_contents.c_str();
- len = post_file_contents.size();
- }
-
- // The post data sent by a plugin contains both headers
- // and post data. Example:
- // Content-type: text/html
- // Content-length: 200
- //
- // <200 bytes of content here>
- //
- // Unfortunately, our stream needs these broken apart,
- // so we need to parse the data and set headers and data
- // separately.
- plugin->RequestURL(url, "POST", target, buf, len, notify, notify_data);
- return NPERR_NO_ERROR;
-}
-
-NPError NPN_PostURLNotify(NPP id,
- const char* url,
- const char* target,
- uint32_t len,
- const char* buf,
- NPBool file,
- void* notify_data) {
- return PostURLNotify(id, url, target, len, buf, file, true, notify_data);
-}
-
-NPError NPN_PostURL(NPP id,
- const char* url,
- const char* target,
- uint32_t len,
- const char* buf,
- NPBool file) {
- // POSTs data to an URL, either from a temp file or a buffer.
- // If file is true, buf contains a temp file (which host will delete after
- // completing), and len contains the length of the filename.
- // If file is false, buf contains the data to send, and len contains the
- // length of the buffer
- //
- // If target is null,
- // server response is returned to the plugin
- // If target is _current, _self, or _top,
- // server response is written to the plugin window and plugin is unloaded.
- // If target is _new or _blank,
- // server response is written to a new browser window
- // If target is an existing frame,
- // server response goes to that frame.
- //
- // For protocols other than FTP
- // file uploads must be line-end converted from \r\n to \n
- //
- // Note: you cannot specify headers (even a blank line) in a memory buffer,
- // use NPN_PostURLNotify
-
- return PostURLNotify(id, url, target, len, buf, file, false, 0);
-}
-
-NPError NPN_NewStream(NPP id,
- NPMIMEType type,
- const char* target,
- NPStream** stream) {
- // Requests creation of a new data stream produced by the plugin,
- // consumed by the browser.
- //
- // Browser should put this stream into a window target.
- //
- // TODO: implement me
- DVLOG(1) << "NPN_NewStream is not implemented yet.";
- return NPERR_GENERIC_ERROR;
-}
-
-int32_t NPN_Write(NPP id, NPStream* stream, int32_t len, void* buffer) {
- // Writes data to an existing Plugin-created stream.
-
- // TODO: implement me
- DVLOG(1) << "NPN_Write is not implemented yet.";
- return NPERR_GENERIC_ERROR;
-}
-
-NPError NPN_DestroyStream(NPP id, NPStream* stream, NPReason reason) {
- // Destroys a stream (could be created by plugin or browser).
- //
- // Reasons:
- // NPRES_DONE - normal completion
- // NPRES_USER_BREAK - user terminated
- // NPRES_NETWORK_ERROR - network error (all errors fit here?)
- //
- //
-
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin.get() == NULL) {
- NOTREACHED();
- return NPERR_GENERIC_ERROR;
- }
-
- return plugin->NPP_DestroyStream(stream, reason);
-}
-
-const char* NPN_UserAgent(NPP id) {
-#if defined(OS_WIN)
- // Flash passes in a null id during the NP_initialize call. We need to
- // default to the Mozilla user agent if we don't have an NPP instance or
- // else Flash won't request windowless mode.
- bool use_mozilla_user_agent = true;
- if (id) {
- scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
- if (plugin.get() && !plugin->use_mozilla_user_agent())
- use_mozilla_user_agent = false;
- }
-
- if (use_mozilla_user_agent)
- return "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) "
- "Gecko/20061103 Firefox/2.0a1";
-#elif defined(OS_MACOSX)
- // Silverlight 4 doesn't handle events correctly unless we claim to be Safari.
- scoped_refptr<NPAPI::PluginInstance> plugin;
- if (id)
- plugin = FindInstance(id);
- if (plugin.get()) {
- WebPluginInfo plugin_info = plugin->plugin_lib()->plugin_info();
- if (plugin_info.name == ASCIIToUTF16("Silverlight Plug-In") &&
- StartsWith(plugin_info.version, ASCIIToUTF16("4."), false)) {
- return "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) "
- "AppleWebKit/534.1+ (KHTML, like Gecko) Version/5.0 Safari/533.16";
- }
- }
-#endif
-
- return webkit_glue::GetUserAgent(GURL()).c_str();
-}
-
-void NPN_Status(NPP id, const char* message) {
- // Displays a message on the status line of the browser window.
-
- // TODO: implement me
- DVLOG(1) << "NPN_Status is not implemented yet.";
-}
-
-void NPN_InvalidateRect(NPP id, NPRect *invalidRect) {
- // Invalidates specified drawing area prior to repainting or refreshing a
- // windowless plugin
-
- // Before a windowless plugin can refresh part of its drawing area, it must
- // first invalidate it. This function causes the NPP_HandleEvent method to
- // pass an update event or a paint message to the plug-in. After calling
- // this method, the plug-in recieves a paint message asynchronously.
-
- // The browser redraws invalid areas of the document and any windowless
- // plug-ins at regularly timed intervals. To force a paint message, the
- // plug-in can call NPN_ForceRedraw after calling this method.
-
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin.get() && plugin->webplugin()) {
- if (invalidRect) {
-#if defined(OS_WIN)
- if (!plugin->windowless()) {
- RECT rect = {0};
- rect.left = invalidRect->left;
- rect.right = invalidRect->right;
- rect.top = invalidRect->top;
- rect.bottom = invalidRect->bottom;
- ::InvalidateRect(plugin->window_handle(), &rect, false);
- return;
- }
-#endif
- gfx::Rect rect(invalidRect->left,
- invalidRect->top,
- invalidRect->right - invalidRect->left,
- invalidRect->bottom - invalidRect->top);
- plugin->webplugin()->InvalidateRect(rect);
- } else {
- plugin->webplugin()->Invalidate();
- }
- }
-}
-
-void NPN_InvalidateRegion(NPP id, NPRegion invalidRegion) {
- // Invalidates a specified drawing region prior to repainting
- // or refreshing a window-less plugin.
- //
- // Similar to NPN_InvalidateRect.
-
- // TODO: this is overkill--add platform-specific region handling (at the
- // very least, fetch the region's bounding box and pass it to InvalidateRect).
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- DCHECK(plugin.get() != NULL);
- if (plugin.get() && plugin->webplugin())
- plugin->webplugin()->Invalidate();
-}
-
-void NPN_ForceRedraw(NPP id) {
- // Forces repaint for a windowless plug-in.
- //
- // We deliberately do not implement this; we don't want plugins forcing
- // synchronous paints.
-}
-
-NPError NPN_GetValue(NPP id, NPNVariable variable, void* value) {
- // Allows the plugin to query the browser for information
- //
- // Variables:
- // NPNVxDisplay (unix only)
- // NPNVxtAppContext (unix only)
- // NPNVnetscapeWindow (win only) - Gets the native window on which the
- // plug-in drawing occurs, returns HWND
- // NPNVjavascriptEnabledBool: tells whether Javascript is enabled
- // NPNVasdEnabledBool: tells whether SmartUpdate is enabled
- // NPNVOfflineBool: tells whether offline-mode is enabled
-
- NPError rv = NPERR_GENERIC_ERROR;
-
- switch (static_cast<int>(variable)) {
- case NPNVWindowNPObject: {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- NPObject *np_object = plugin->webplugin()->GetWindowScriptNPObject();
- // Return value is expected to be retained, as
- // described here:
- // <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess>
- if (np_object) {
- WebBindings::retainObject(np_object);
- void **v = (void **)value;
- *v = np_object;
- rv = NPERR_NO_ERROR;
- } else {
- NOTREACHED();
- }
- break;
- }
- case NPNVPluginElementNPObject: {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- NPObject *np_object = plugin->webplugin()->GetPluginElement();
- // Return value is expected to be retained, as
- // described here:
- // <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess>
- if (np_object) {
- WebBindings::retainObject(np_object);
- void** v = static_cast<void**>(value);
- *v = np_object;
- rv = NPERR_NO_ERROR;
- } else {
- NOTREACHED();
- }
- break;
- }
- #if !defined(OS_MACOSX) // OS X doesn't have windowed plugins.
- case NPNVnetscapeWindow: {
- scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id);
- if (!plugin.get()) {
- NOTREACHED();
- return NPERR_GENERIC_ERROR;
- }
- gfx::PluginWindowHandle handle = plugin->window_handle();
- *((void**)value) = (void*)handle;
- rv = NPERR_NO_ERROR;
- break;
- }
- #endif
- case NPNVjavascriptEnabledBool: {
- // yes, JS is enabled.
- *((void**)value) = (void*)1;
- rv = NPERR_NO_ERROR;
- break;
- }
- #if defined(TOOLKIT_USES_GTK)
- case NPNVToolkit:
- // Tell them we are GTK2. (The alternative is GTK 1.2.)
- *reinterpret_cast<int*>(value) = NPNVGtk2;
- rv = NPERR_NO_ERROR;
- break;
-
- case NPNVSupportsXEmbedBool:
- *reinterpret_cast<NPBool*>(value) = true;
- rv = NPERR_NO_ERROR;
- break;
- #endif
- case NPNVSupportsWindowless: {
- NPBool* supports_windowless = reinterpret_cast<NPBool*>(value);
- *supports_windowless = true;
- rv = NPERR_NO_ERROR;
- break;
- }
- case NPNVprivateModeBool: {
- NPBool* private_mode = reinterpret_cast<NPBool*>(value);
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- *private_mode = plugin->webplugin()->IsOffTheRecord();
- rv = NPERR_NO_ERROR;
- break;
- }
- case default_plugin::kMissingPluginStatusStart +
- default_plugin::MISSING_PLUGIN_AVAILABLE:
- // fall through
- case default_plugin::kMissingPluginStatusStart +
- default_plugin::MISSING_PLUGIN_USER_STARTED_DOWNLOAD: {
- // This is a hack for the default plugin to send notification to
- // renderer. Even though we check if the plugin is the default plugin,
- // we still need to worry about future standard change that may conflict
- // with the variable definition, in order to avoid duplicate case clauses
- // in this big switch statement.
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin->plugin_lib()->plugin_info().path.value() ==
- kDefaultPluginLibraryName) {
- plugin->webplugin()->OnMissingPluginStatus(
- variable - default_plugin::kMissingPluginStatusStart);
- }
- break;
- }
- #if defined(OS_MACOSX)
- case NPNVpluginDrawingModel: {
- // return the drawing model that was negotiated when we initialized.
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- *reinterpret_cast<int*>(value) = plugin->drawing_model();
- rv = NPERR_NO_ERROR;
- break;
- }
-#ifndef NP_NO_QUICKDRAW
- case NPNVsupportsQuickDrawBool: {
- // We do not admit to supporting the QuickDraw drawing model. The logic
- // here is that our QuickDraw plugin support is so rudimentary that we
- // only want to use it as a fallback to keep plugins from crashing: if a
- // plugin knows enough to ask, we want them to use CoreGraphics.
- NPBool* supports_qd = reinterpret_cast<NPBool*>(value);
- *supports_qd = false;
- rv = NPERR_NO_ERROR;
- break;
- }
-#endif
- case NPNVsupportsCoreGraphicsBool:
-#ifndef NP_NO_CARBON
- case NPNVsupportsCarbonBool:
-#endif
- case NPNVsupportsCocoaBool: {
- // we do support these drawing and event models.
- NPBool* supports_model = reinterpret_cast<NPBool*>(value);
- *supports_model = true;
- rv = NPERR_NO_ERROR;
- break;
- }
- case NPNVsupportsCoreAnimationBool: {
- // We only support the Core Animation model on 10.6 and higher
- // TODO(stuartmorgan): Once existing CA plugins have implemented the
- // invalidating version, remove support for this one.
- NPBool* supports_model = reinterpret_cast<NPBool*>(value);
- *supports_model = SupportsSharingAcceleratedSurfaces() ? true : false;
- rv = NPERR_NO_ERROR;
- break;
- }
- case NPNVsupportsInvalidatingCoreAnimationBool: {
- NPBool* supports_model = reinterpret_cast<NPBool*>(value);
- *supports_model = true;
- rv = NPERR_NO_ERROR;
- break;
- }
- case NPNVsupportsOpenGLBool: {
- // This drawing model was never widely supported, and we don't plan to
- // support it.
- NPBool* supports_model = reinterpret_cast<NPBool*>(value);
- *supports_model = false;
- rv = NPERR_NO_ERROR;
- break;
- }
- #endif // OS_MACOSX
- case NPNVPepperExtensions:
- // Available for any plugin that attempts to get it.
- // If the plugin is not started in a Pepper implementation, it
- // will likely fail when it tries to use any of the functions
- // attached to the extension vector.
- rv = NPAPI::GetPepperExtensionsFunctions(value);
- break;
- default:
- DVLOG(1) << "NPN_GetValue(" << variable << ") is not implemented yet.";
- break;
- }
- return rv;
-}
-
-NPError NPN_SetValue(NPP id, NPPVariable variable, void* value) {
- // Allows the plugin to set various modes
-
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- switch(variable) {
- case NPPVpluginWindowBool: {
- // Sets windowless mode for display of the plugin
- // Note: the documentation at
- // http://developer.mozilla.org/en/docs/NPN_SetValue is wrong. When
- // value is NULL, the mode is set to true. This is the same way Mozilla
- // works.
- plugin->set_windowless(value == 0);
- return NPERR_NO_ERROR;
- }
- case NPPVpluginTransparentBool: {
- // Sets transparent mode for display of the plugin
- //
- // Transparent plugins require the browser to paint the background
- // before having the plugin paint. By default, windowless plugins
- // are transparent. Making a windowless plugin opaque means that
- // the plugin does not require the browser to paint the background.
- bool mode = (value != 0);
- plugin->set_transparent(mode);
- return NPERR_NO_ERROR;
- }
- case NPPVjavascriptPushCallerBool:
- // Specifies whether you are pushing or popping the JSContext off.
- // the stack
- // TODO: implement me
- DVLOG(1) << "NPN_SetValue(NPPVJavascriptPushCallerBool) is not "
- "implemented.";
- return NPERR_GENERIC_ERROR;
- case NPPVpluginKeepLibraryInMemory:
- // Tells browser that plugin library should live longer than usual.
- // TODO: implement me
- DVLOG(1) << "NPN_SetValue(NPPVpluginKeepLibraryInMemory) is not "
- "implemented.";
- return NPERR_GENERIC_ERROR;
- #if defined(OS_MACOSX)
- case NPPVpluginDrawingModel: {
- int model = reinterpret_cast<int>(value);
- if (model == NPDrawingModelCoreGraphics ||
- model == NPDrawingModelInvalidatingCoreAnimation ||
- (model == NPDrawingModelCoreAnimation &&
- SupportsSharingAcceleratedSurfaces())) {
- plugin->set_drawing_model(static_cast<NPDrawingModel>(model));
- return NPERR_NO_ERROR;
- }
- return NPERR_GENERIC_ERROR;
- }
- case NPPVpluginEventModel: {
- // we support Carbon and Cocoa event models
- int model = reinterpret_cast<int>(value);
- switch (model) {
-#ifndef NP_NO_CARBON
- case NPEventModelCarbon:
-#endif
- case NPEventModelCocoa:
- plugin->set_event_model(static_cast<NPEventModel>(model));
- return NPERR_NO_ERROR;
- break;
- }
- return NPERR_GENERIC_ERROR;
- }
- #endif
- default:
- // TODO: implement me
- DVLOG(1) << "NPN_SetValue(" << variable << ") is not implemented.";
- break;
- }
-
- NOTREACHED();
- return NPERR_GENERIC_ERROR;
-}
-
-void* NPN_GetJavaEnv() {
- // TODO: implement me
- DVLOG(1) << "NPN_GetJavaEnv is not implemented.";
- return NULL;
-}
-
-void* NPN_GetJavaPeer(NPP) {
- // TODO: implement me
- DVLOG(1) << "NPN_GetJavaPeer is not implemented.";
- return NULL;
-}
-
-void NPN_PushPopupsEnabledState(NPP id, NPBool enabled) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin)
- plugin->PushPopupsEnabledState(enabled ? true : false);
-}
-
-void NPN_PopPopupsEnabledState(NPP id) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin)
- plugin->PopPopupsEnabledState();
-}
-
-void NPN_PluginThreadAsyncCall(NPP id,
- void (*func)(void*),
- void* user_data) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin)
- plugin->PluginThreadAsyncCall(func, user_data);
-}
-
-NPError NPN_GetValueForURL(NPP id,
- NPNURLVariable variable,
- const char* url,
- char** value,
- uint32_t* len) {
- if (!id)
- return NPERR_INVALID_PARAM;
-
- if (!url || !*url || !len)
- return NPERR_INVALID_URL;
-
- *len = 0;
- std::string result;
-
- switch (variable) {
- case NPNURLVProxy: {
- result = "DIRECT";
- if (!webkit_glue::FindProxyForUrl(GURL((std::string(url))), &result))
- return NPERR_GENERIC_ERROR;
-
- break;
- }
- case NPNURLVCookie: {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (!plugin)
- return NPERR_GENERIC_ERROR;
-
- webkit_glue::WebPlugin* webplugin = plugin->webplugin();
- if (!webplugin)
- return NPERR_GENERIC_ERROR;
-
- // Bypass third-party cookie blocking by using the url as the
- // first_party_for_cookies.
- GURL cookies_url((std::string(url)));
- result = webplugin->GetCookies(cookies_url, cookies_url);
- break;
- }
- default:
- return NPERR_GENERIC_ERROR;
- }
-
- // Allocate this using the NPAPI allocator. The plugin will call
- // NPN_Free to free this.
- *value = static_cast<char*>(NPN_MemAlloc(result.length() + 1));
- base::strlcpy(*value, result.c_str(), result.length() + 1);
- *len = result.length();
-
- return NPERR_NO_ERROR;
-}
-
-NPError NPN_SetValueForURL(NPP id,
- NPNURLVariable variable,
- const char* url,
- const char* value,
- uint32_t len) {
- if (!id)
- return NPERR_INVALID_PARAM;
-
- if (!url || !*url)
- return NPERR_INVALID_URL;
-
- switch (variable) {
- case NPNURLVCookie: {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (!plugin)
- return NPERR_GENERIC_ERROR;
-
- webkit_glue::WebPlugin* webplugin = plugin->webplugin();
- if (!webplugin)
- return NPERR_GENERIC_ERROR;
-
- std::string cookie(value, len);
- GURL cookies_url((std::string(url)));
- webplugin->SetCookie(cookies_url, cookies_url, cookie);
- return NPERR_NO_ERROR;
- }
- case NPNURLVProxy:
- // We don't support setting proxy values, fall through...
- break;
- default:
- // Fall through and return an error...
- break;
- }
-
- return NPERR_GENERIC_ERROR;
-}
-
-NPError NPN_GetAuthenticationInfo(NPP id,
- const char* protocol,
- const char* host,
- int32_t port,
- const char* scheme,
- const char* realm,
- char** username,
- uint32_t* ulen,
- char** password,
- uint32_t* plen) {
- if (!id || !protocol || !host || !scheme || !realm || !username ||
- !ulen || !password || !plen)
- return NPERR_INVALID_PARAM;
-
- // TODO: implement me (bug 23928)
- return NPERR_GENERIC_ERROR;
-}
-
-uint32_t NPN_ScheduleTimer(NPP id,
- uint32_t interval,
- NPBool repeat,
- void (*func)(NPP id, uint32_t timer_id)) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (!plugin)
- return 0;
-
- return plugin->ScheduleTimer(interval, repeat, func);
-}
-
-void NPN_UnscheduleTimer(NPP id, uint32_t timer_id) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin)
- plugin->UnscheduleTimer(timer_id);
-}
-
-NPError NPN_PopUpContextMenu(NPP id, NPMenu* menu) {
- if (!menu)
- return NPERR_INVALID_PARAM;
-
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin.get()) {
- return plugin->PopUpContextMenu(menu);
- }
- NOTREACHED();
- return NPERR_GENERIC_ERROR;
-}
-
-NPBool NPN_ConvertPoint(NPP id, double sourceX, double sourceY,
- NPCoordinateSpace sourceSpace,
- double *destX, double *destY,
- NPCoordinateSpace destSpace) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(id));
- if (plugin.get()) {
- return plugin->ConvertPoint(sourceX, sourceY, sourceSpace,
- destX, destY, destSpace);
- }
- NOTREACHED();
- return false;
-}
-
-NPBool NPN_HandleEvent(NPP id, void *event, NPBool handled) {
- // TODO: Implement advanced key handling: http://crbug.com/46578
- NOTIMPLEMENTED();
- return false;
-}
-
-NPBool NPN_UnfocusInstance(NPP id, NPFocusDirection direction) {
- // TODO: Implement advanced key handling: http://crbug.com/46578
- NOTIMPLEMENTED();
- return false;
-}
-
-void NPN_URLRedirectResponse(NPP instance, void* notify_data, NPBool allow) {
- scoped_refptr<NPAPI::PluginInstance> plugin(FindInstance(instance));
- if (plugin.get()) {
- plugin->URLRedirectResponse(!!allow, notify_data);
- }
-}
-
-} // extern "C"
diff --git a/webkit/glue/plugins/plugin_host.h b/webkit/glue/plugins/plugin_host.h
deleted file mode 100644
index 4763df1..0000000
--- a/webkit/glue/plugins/plugin_host.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// 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.
-
-// TODO: Need mechanism to cleanup the static instance
-
-#ifndef WEBKIT_GLUE_PLUGIN_PLUGIN_HOST_H__
-#define WEBKIT_GLUE_PLUGIN_PLUGIN_HOST_H__
-
-#include <string>
-#include <vector>
-
-#include "base/ref_counted.h"
-#include "third_party/npapi/bindings/npapi.h"
-#include "third_party/npapi/bindings/nphostapi.h"
-
-namespace NPAPI
-{
-class PluginInstance;
-
-// The Plugin Host implements the NPN_xxx functions for NPAPI plugins.
-// These are the functions exposed from the Plugin Host for use
-// by the Plugin.
-//
-// The PluginHost is managed as a singleton. This isn't strictly
-// necessary, but since the callback functions are all global C
-// functions, there is really no point in having per-instance PluginHosts.
-class PluginHost : public base::RefCounted<PluginHost> {
- public:
- // Access the single PluginHost instance. Callers
- // must call deref() when finished with the object.
- static PluginHost *Singleton();
-
- // The table of functions provided to the plugin.
- NPNetscapeFuncs *host_functions() { return &host_funcs_; }
-
- // Helper function for parsing post headers, and applying attributes
- // to the stream. NPAPI post data include headers + data combined.
- // This function parses it out and adds it to the stream in a WebKit
- // style.
- static bool SetPostData(const char *buf,
- uint32 length,
- std::vector<std::string>* names,
- std::vector<std::string>* values,
- std::vector<char>* body);
-
- void PatchNPNetscapeFuncs(NPNetscapeFuncs* overrides);
-
- private:
- friend class base::RefCounted<PluginHost>;
-
- virtual ~PluginHost();
-
- PluginHost();
- void InitializeHostFuncs();
- static scoped_refptr<PluginHost> singleton_;
- NPNetscapeFuncs host_funcs_;
- DISALLOW_COPY_AND_ASSIGN(PluginHost);
-};
-
-} // namespace NPAPI
-
-#endif // WEBKIT_GLUE_PLUGIN_PLUGIN_HOST_H__
diff --git a/webkit/glue/plugins/plugin_instance.cc b/webkit/glue/plugins/plugin_instance.cc
deleted file mode 100644
index 4ccbadf..0000000
--- a/webkit/glue/plugins/plugin_instance.cc
+++ /dev/null
@@ -1,680 +0,0 @@
-// 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.
-
-#include "build/build_config.h"
-
-#include "webkit/glue/plugins/plugin_instance.h"
-
-#include "base/file_util.h"
-#include "base/message_loop.h"
-#include "base/string_number_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "webkit/glue/webkit_glue.h"
-#include "webkit/glue/plugins/plugin_host.h"
-#include "webkit/glue/plugins/plugin_lib.h"
-#include "webkit/glue/plugins/plugin_stream_url.h"
-#include "webkit/glue/plugins/plugin_string_stream.h"
-#include "webkit/glue/plugins/webplugin.h"
-#include "webkit/glue/plugins/webplugin_delegate.h"
-#include "net/base/escape.h"
-
-#if defined(OS_MACOSX)
-#include <ApplicationServices/ApplicationServices.h>
-#endif
-
-namespace NPAPI {
-
-PluginInstance::PluginInstance(PluginLib *plugin, const std::string &mime_type)
- : plugin_(plugin),
- npp_(0),
- host_(PluginHost::Singleton()),
- npp_functions_(plugin->functions()),
- window_handle_(0),
- windowless_(false),
- transparent_(true),
- webplugin_(0),
- mime_type_(mime_type),
- use_mozilla_user_agent_(false),
-#if defined (OS_MACOSX)
-#ifdef NP_NO_QUICKDRAW
- drawing_model_(NPDrawingModelCoreGraphics),
-#else
- drawing_model_(NPDrawingModelQuickDraw),
-#endif
-#ifdef NP_NO_CARBON
- event_model_(NPEventModelCocoa),
-#else
- event_model_(NPEventModelCarbon),
-#endif
- currently_handled_event_(NULL),
-#endif
- message_loop_(MessageLoop::current()),
- load_manually_(false),
- in_close_streams_(false),
- next_timer_id_(1),
- next_notify_id_(0),
- next_range_request_id_(0),
- handles_url_redirects_(false) {
- npp_ = new NPP_t();
- npp_->ndata = 0;
- npp_->pdata = 0;
-
- memset(&zero_padding_, 0, sizeof(zero_padding_));
- DCHECK(message_loop_);
-}
-
-PluginInstance::~PluginInstance() {
- CloseStreams();
-
- if (npp_ != 0) {
- delete npp_;
- npp_ = 0;
- }
-
- if (plugin_)
- plugin_->CloseInstance();
-}
-
-PluginStreamUrl* PluginInstance::CreateStream(unsigned long resource_id,
- const GURL& url,
- const std::string& mime_type,
- int notify_id) {
-
- bool notify;
- void* notify_data;
- GetNotifyData(notify_id, &notify, &notify_data);
- PluginStreamUrl* stream = new PluginStreamUrl(
- resource_id, url, this, notify, notify_data);
-
- AddStream(stream);
- return stream;
-}
-
-void PluginInstance::AddStream(PluginStream* stream) {
- open_streams_.push_back(make_scoped_refptr(stream));
-}
-
-void PluginInstance::RemoveStream(PluginStream* stream) {
- if (in_close_streams_)
- return;
-
- std::vector<scoped_refptr<PluginStream> >::iterator stream_index;
- for (stream_index = open_streams_.begin();
- stream_index != open_streams_.end(); ++stream_index) {
- if (*stream_index == stream) {
- open_streams_.erase(stream_index);
- break;
- }
- }
-}
-
-bool PluginInstance::IsValidStream(const NPStream* stream) {
- std::vector<scoped_refptr<PluginStream> >::iterator stream_index;
- for (stream_index = open_streams_.begin();
- stream_index != open_streams_.end(); ++stream_index) {
- if ((*stream_index)->stream() == stream)
- return true;
- }
-
- return false;
-}
-
-void PluginInstance::CloseStreams() {
- in_close_streams_ = true;
- for (unsigned int index = 0; index < open_streams_.size(); ++index) {
- // Close all streams on the way down.
- open_streams_[index]->Close(NPRES_USER_BREAK);
- }
- open_streams_.clear();
- in_close_streams_ = false;
-}
-
-webkit_glue::WebPluginResourceClient* PluginInstance::GetRangeRequest(
- int id) {
- PendingRangeRequestMap::iterator iter = pending_range_requests_.find(id);
- if (iter == pending_range_requests_.end()) {
- NOTREACHED();
- return NULL;
- }
-
- webkit_glue::WebPluginResourceClient* rv = iter->second->AsResourceClient();
- pending_range_requests_.erase(iter);
- return rv;
-}
-
-bool PluginInstance::Start(const GURL& url,
- char** const param_names,
- char** const param_values,
- int param_count,
- bool load_manually) {
- load_manually_ = load_manually;
- unsigned short mode = load_manually_ ? NP_FULL : NP_EMBED;
- npp_->ndata = this;
-
- NPError err = NPP_New(mode, param_count,
- const_cast<char **>(param_names), const_cast<char **>(param_values));
-
- if (err == NPERR_NO_ERROR) {
- handles_url_redirects_ =
- ((npp_functions_->version >= NPVERS_HAS_URL_REDIRECT_HANDLING) &&
- (npp_functions_->urlredirectnotify));
- }
- return err == NPERR_NO_ERROR;
-}
-
-NPObject *PluginInstance::GetPluginScriptableObject() {
- NPObject *value = NULL;
- NPError error = NPP_GetValue(NPPVpluginScriptableNPObject, &value);
- if (error != NPERR_NO_ERROR || value == NULL)
- return NULL;
- return value;
-}
-
-// WebPluginLoadDelegate methods
-void PluginInstance::DidFinishLoadWithReason(
- const GURL& url, NPReason reason, int notify_id) {
- bool notify;
- void* notify_data;
- GetNotifyData(notify_id, &notify, &notify_data);
- if (!notify) {
- NOTREACHED();
- return;
- }
-
- NPP_URLNotify(url.spec().c_str(), reason, notify_data);
-}
-
-unsigned PluginInstance::GetBackingTextureId() {
- // By default the plugin instance is not backed by an OpenGL texture.
- return 0;
-}
-
-// NPAPI methods
-NPError PluginInstance::NPP_New(unsigned short mode,
- short argc,
- char *argn[],
- char *argv[]) {
- DCHECK(npp_functions_ != 0);
- DCHECK(npp_functions_->newp != 0);
- DCHECK(argc >= 0);
-
- if (npp_functions_->newp != 0) {
- return npp_functions_->newp(
- (NPMIMEType)mime_type_.c_str(), npp_, mode, argc, argn, argv, NULL);
- }
- return NPERR_INVALID_FUNCTABLE_ERROR;
-}
-
-void PluginInstance::NPP_Destroy() {
- DCHECK(npp_functions_ != 0);
- DCHECK(npp_functions_->destroy != 0);
-
- if (npp_functions_->destroy != 0) {
- NPSavedData *savedData = 0;
- npp_functions_->destroy(npp_, &savedData);
-
- // TODO: Support savedData. Technically, these need to be
- // saved on a per-URL basis, and then only passed
- // to new instances of the plugin at the same URL.
- // Sounds like a huge security risk. When we do support
- // these, we should pass them back to the PluginLib
- // to be stored there.
- DCHECK(savedData == 0);
- }
-
- for (unsigned int file_index = 0; file_index < files_created_.size();
- file_index++) {
- file_util::Delete(files_created_[file_index], false);
- }
-
- // Ensure that no timer callbacks are invoked after NPP_Destroy.
- timers_.clear();
-}
-
-NPError PluginInstance::NPP_SetWindow(NPWindow *window) {
- DCHECK(npp_functions_ != 0);
- DCHECK(npp_functions_->setwindow != 0);
-
- if (npp_functions_->setwindow != 0) {
- return npp_functions_->setwindow(npp_, window);
- }
- return NPERR_INVALID_FUNCTABLE_ERROR;
-}
-
-NPError PluginInstance::NPP_NewStream(NPMIMEType type,
- NPStream *stream,
- NPBool seekable,
- unsigned short *stype) {
- DCHECK(npp_functions_ != 0);
- DCHECK(npp_functions_->newstream != 0);
- if (npp_functions_->newstream != 0) {
- return npp_functions_->newstream(npp_, type, stream, seekable, stype);
- }
- return NPERR_INVALID_FUNCTABLE_ERROR;
-}
-
-NPError PluginInstance::NPP_DestroyStream(NPStream *stream, NPReason reason) {
- DCHECK(npp_functions_ != 0);
- DCHECK(npp_functions_->destroystream != 0);
-
- if (stream == NULL || !IsValidStream(stream) || (stream->ndata == NULL))
- return NPERR_INVALID_INSTANCE_ERROR;
-
- if (npp_functions_->destroystream != 0) {
- NPError result = npp_functions_->destroystream(npp_, stream, reason);
- stream->ndata = NULL;
- return result;
- }
- return NPERR_INVALID_FUNCTABLE_ERROR;
-}
-
-int PluginInstance::NPP_WriteReady(NPStream *stream) {
- DCHECK(npp_functions_ != 0);
- DCHECK(npp_functions_->writeready != 0);
- if (npp_functions_->writeready != 0) {
- return npp_functions_->writeready(npp_, stream);
- }
- return 0;
-}
-
-int PluginInstance::NPP_Write(NPStream *stream,
- int offset,
- int len,
- void *buffer) {
- DCHECK(npp_functions_ != 0);
- DCHECK(npp_functions_->write != 0);
- if (npp_functions_->write != 0) {
- return npp_functions_->write(npp_, stream, offset, len, buffer);
- }
- return 0;
-}
-
-void PluginInstance::NPP_StreamAsFile(NPStream *stream, const char *fname) {
- DCHECK(npp_functions_ != 0);
- DCHECK(npp_functions_->asfile != 0);
- if (npp_functions_->asfile != 0) {
- npp_functions_->asfile(npp_, stream, fname);
- }
-
- // Creating a temporary FilePath instance on the stack as the explicit
- // FilePath constructor with StringType as an argument causes a compiler
- // error when invoked via vector push back.
- FilePath file_name = FilePath::FromWStringHack(UTF8ToWide(fname));
- files_created_.push_back(file_name);
-}
-
-void PluginInstance::NPP_URLNotify(const char *url,
- NPReason reason,
- void *notifyData) {
- DCHECK(npp_functions_ != 0);
- DCHECK(npp_functions_->urlnotify != 0);
- if (npp_functions_->urlnotify != 0) {
- npp_functions_->urlnotify(npp_, url, reason, notifyData);
- }
-}
-
-NPError PluginInstance::NPP_GetValue(NPPVariable variable, void *value) {
- DCHECK(npp_functions_ != 0);
- // getvalue is NULL for Shockwave
- if (npp_functions_->getvalue != 0) {
- return npp_functions_->getvalue(npp_, variable, value);
- }
- return NPERR_INVALID_FUNCTABLE_ERROR;
-}
-
-NPError PluginInstance::NPP_SetValue(NPNVariable variable, void *value) {
- DCHECK(npp_functions_ != 0);
- if (npp_functions_->setvalue != 0) {
- return npp_functions_->setvalue(npp_, variable, value);
- }
- return NPERR_INVALID_FUNCTABLE_ERROR;
-}
-
-short PluginInstance::NPP_HandleEvent(void* event) {
- DCHECK(npp_functions_ != 0);
- DCHECK(npp_functions_->event != 0);
- if (npp_functions_->event != 0) {
- return npp_functions_->event(npp_, (void*)event);
- }
- return false;
-}
-
-bool PluginInstance::NPP_Print(NPPrint* platform_print) {
- DCHECK(npp_functions_ != 0);
- if (npp_functions_->print != 0) {
- npp_functions_->print(npp_, platform_print);
- return true;
- }
- return false;
-}
-
-NPError PluginInstance::NPP_ClearSiteData(uint64 flags,
- const char* domain,
- uint64 max_age) {
- DCHECK(npp_functions_ != 0);
- // TODO(bauerb): Call NPAPI function when it is defined in the header.
- return NPERR_NO_ERROR;
-}
-
-void PluginInstance::NPP_URLRedirectNotify(const char* url, int32_t status,
- void* notify_data) {
- DCHECK(npp_functions_ != 0);
- if (npp_functions_->urlredirectnotify != 0) {
- npp_functions_->urlredirectnotify(npp_, url, status, notify_data);
- }
-}
-
-void PluginInstance::SendJavaScriptStream(const GURL& url,
- const std::string& result,
- bool success,
- int notify_id) {
- bool notify;
- void* notify_data;
- GetNotifyData(notify_id, &notify, &notify_data);
-
- if (success) {
- PluginStringStream *stream =
- new PluginStringStream(this, url, notify, notify_data);
- AddStream(stream);
- stream->SendToPlugin(result, "text/html");
- } else {
- // NOTE: Sending an empty stream here will crash MacroMedia
- // Flash 9. Just send the URL Notify.
- if (notify)
- NPP_URLNotify(url.spec().c_str(), NPRES_DONE, notify_data);
- }
-}
-
-void PluginInstance::DidReceiveManualResponse(const GURL& url,
- const std::string& mime_type,
- const std::string& headers,
- uint32 expected_length,
- uint32 last_modified) {
- DCHECK(load_manually_);
-
- plugin_data_stream_ = CreateStream(-1, url, mime_type, 0);
- plugin_data_stream_->DidReceiveResponse(mime_type, headers, expected_length,
- last_modified, true);
-}
-
-void PluginInstance::DidReceiveManualData(const char* buffer, int length) {
- DCHECK(load_manually_);
- if (plugin_data_stream_.get() != NULL) {
- plugin_data_stream_->DidReceiveData(buffer, length, 0);
- }
-}
-
-void PluginInstance::DidFinishManualLoading() {
- DCHECK(load_manually_);
- if (plugin_data_stream_.get() != NULL) {
- plugin_data_stream_->DidFinishLoading();
- plugin_data_stream_->Close(NPRES_DONE);
- plugin_data_stream_ = NULL;
- }
-}
-
-void PluginInstance::DidManualLoadFail() {
- DCHECK(load_manually_);
- if (plugin_data_stream_.get() != NULL) {
- plugin_data_stream_->DidFail();
- plugin_data_stream_ = NULL;
- }
-}
-
-void PluginInstance::PluginThreadAsyncCall(void (*func)(void *),
- void *user_data) {
- message_loop_->PostTask(
- FROM_HERE, NewRunnableMethod(
- this, &PluginInstance::OnPluginThreadAsyncCall, func, user_data));
-}
-
-void PluginInstance::OnPluginThreadAsyncCall(void (*func)(void *),
- void *user_data) {
- // Do not invoke the callback if NPP_Destroy has already been invoked.
- if (webplugin_)
- func(user_data);
-}
-
-uint32 PluginInstance::ScheduleTimer(uint32 interval,
- NPBool repeat,
- void (*func)(NPP id, uint32 timer_id)) {
- // Use next timer id.
- uint32 timer_id;
- timer_id = next_timer_id_;
- ++next_timer_id_;
- DCHECK(next_timer_id_ != 0);
-
- // Record timer interval and repeat.
- TimerInfo info;
- info.interval = interval;
- info.repeat = repeat ? true : false;
- timers_[timer_id] = info;
-
- // Schedule the callback.
- MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- NewRunnableMethod(
- this, &PluginInstance::OnTimerCall, func, npp_, timer_id),
- interval);
- return timer_id;
-}
-
-void PluginInstance::UnscheduleTimer(uint32 timer_id) {
- // Remove info about the timer.
- TimerMap::iterator it = timers_.find(timer_id);
- if (it != timers_.end())
- timers_.erase(it);
-}
-
-#if !defined(OS_MACOSX)
-NPError PluginInstance::PopUpContextMenu(NPMenu* menu) {
- NOTIMPLEMENTED();
- return NPERR_GENERIC_ERROR;
-}
-#endif
-
-void PluginInstance::OnTimerCall(void (*func)(NPP id, uint32 timer_id),
- NPP id,
- uint32 timer_id) {
- // Do not invoke callback if the timer has been unscheduled.
- TimerMap::iterator it = timers_.find(timer_id);
- if (it == timers_.end())
- return;
-
- // Get all information about the timer before invoking the callback. The
- // callback might unschedule the timer.
- TimerInfo info = it->second;
-
- func(id, timer_id);
-
- // If the timer was unscheduled by the callback, just free up the timer id.
- if (timers_.find(timer_id) == timers_.end())
- return;
-
- // Reschedule repeating timers after invoking the callback so callback is not
- // re-entered if it pumps the messager loop.
- if (info.repeat) {
- MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- NewRunnableMethod(
- this, &PluginInstance::OnTimerCall, func, npp_, timer_id),
- info.interval);
- } else {
- timers_.erase(it);
- }
-}
-
-void PluginInstance::PushPopupsEnabledState(bool enabled) {
- popups_enabled_stack_.push(enabled);
-}
-
-void PluginInstance::PopPopupsEnabledState() {
- popups_enabled_stack_.pop();
-}
-
-void PluginInstance::RequestRead(NPStream* stream, NPByteRange* range_list) {
- std::string range_info = "bytes=";
-
- while (range_list) {
- range_info += base::IntToString(range_list->offset);
- range_info.push_back('-');
- range_info +=
- base::IntToString(range_list->offset + range_list->length - 1);
- range_list = range_list->next;
- if (range_list)
- range_info.push_back(',');
- }
-
- if (plugin_data_stream_) {
- if (plugin_data_stream_->stream() == stream) {
- webplugin_->CancelDocumentLoad();
- plugin_data_stream_ = NULL;
- }
- }
-
- // The lifetime of a NPStream instance depends on the PluginStream instance
- // which owns it. When a plugin invokes NPN_RequestRead on a seekable stream,
- // we don't want to create a new stream when the corresponding response is
- // received. We send over a cookie which represents the PluginStream
- // instance which is sent back from the renderer when the response is
- // received.
- std::vector<scoped_refptr<PluginStream> >::iterator stream_index;
- for (stream_index = open_streams_.begin();
- stream_index != open_streams_.end(); ++stream_index) {
- PluginStream* plugin_stream = *stream_index;
- if (plugin_stream->stream() == stream) {
- // A stream becomes seekable the first time NPN_RequestRead
- // is called on it.
- plugin_stream->set_seekable(true);
-
- pending_range_requests_[++next_range_request_id_] = plugin_stream;
- webplugin_->InitiateHTTPRangeRequest(
- stream->url, range_info.c_str(), next_range_request_id_);
- return;
- }
- }
- NOTREACHED();
-}
-
-void PluginInstance::RequestURL(const char* url,
- const char* method,
- const char* target,
- const char* buf,
- unsigned int len,
- bool notify,
- void* notify_data) {
- int notify_id = 0;
- if (notify) {
- notify_id = ++next_notify_id_;
- pending_requests_[notify_id] = notify_data;
- }
-
- webplugin_->HandleURLRequest(
- url, method, target, buf, len, notify_id, popups_allowed(),
- notify ? handles_url_redirects_ : false);
-}
-
-bool PluginInstance::ConvertPoint(double source_x, double source_y,
- NPCoordinateSpace source_space,
- double* dest_x, double* dest_y,
- NPCoordinateSpace dest_space) {
-#if defined(OS_MACOSX)
- CGRect main_display_bounds = CGDisplayBounds(CGMainDisplayID());
-
- double flipped_screen_x = source_x;
- double flipped_screen_y = source_y;
- switch(source_space) {
- case NPCoordinateSpacePlugin:
- flipped_screen_x += plugin_origin_.x();
- flipped_screen_y += plugin_origin_.y();
- break;
- case NPCoordinateSpaceWindow:
- flipped_screen_x += containing_window_frame_.x();
- flipped_screen_y = containing_window_frame_.height() - source_y +
- containing_window_frame_.y();
- break;
- case NPCoordinateSpaceFlippedWindow:
- flipped_screen_x += containing_window_frame_.x();
- flipped_screen_y += containing_window_frame_.y();
- break;
- case NPCoordinateSpaceScreen:
- flipped_screen_y = main_display_bounds.size.height - flipped_screen_y;
- break;
- case NPCoordinateSpaceFlippedScreen:
- break;
- default:
- NOTREACHED();
- return false;
- }
-
- double target_x = flipped_screen_x;
- double target_y = flipped_screen_y;
- switch(dest_space) {
- case NPCoordinateSpacePlugin:
- target_x -= plugin_origin_.x();
- target_y -= plugin_origin_.y();
- break;
- case NPCoordinateSpaceWindow:
- target_x -= containing_window_frame_.x();
- target_y -= containing_window_frame_.y();
- target_y = containing_window_frame_.height() - target_y;
- break;
- case NPCoordinateSpaceFlippedWindow:
- target_x -= containing_window_frame_.x();
- target_y -= containing_window_frame_.y();
- break;
- case NPCoordinateSpaceScreen:
- target_y = main_display_bounds.size.height - flipped_screen_y;
- break;
- case NPCoordinateSpaceFlippedScreen:
- break;
- default:
- NOTREACHED();
- return false;
- }
-
- if (dest_x)
- *dest_x = target_x;
- if (dest_y)
- *dest_y = target_y;
- return true;
-#else
- NOTIMPLEMENTED();
- return false;
-#endif
-}
-
-void PluginInstance::GetNotifyData(
- int notify_id, bool* notify, void** notify_data) {
- PendingRequestMap::iterator iter = pending_requests_.find(notify_id);
- if (iter != pending_requests_.end()) {
- *notify = true;
- *notify_data = iter->second;
- pending_requests_.erase(iter);
- } else {
- *notify = false;
- *notify_data = NULL;
- }
-}
-
-void PluginInstance::URLRedirectResponse(bool allow, void* notify_data) {
- // The notify_data passed in allows us to identify the matching stream.
- std::vector<scoped_refptr<PluginStream> >::iterator stream_index;
- for (stream_index = open_streams_.begin();
- stream_index != open_streams_.end(); ++stream_index) {
- PluginStream* plugin_stream = *stream_index;
- if (plugin_stream->notify_data() == notify_data) {
- webkit_glue::WebPluginResourceClient* resource_client =
- plugin_stream->AsResourceClient();
- webplugin_->URLRedirectResponse(allow, resource_client->ResourceId());
- if (allow) {
- plugin_stream->UpdateUrl(
- plugin_stream->pending_redirect_url().c_str());
- }
- break;
- }
- }
-}
-
-} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_instance.h b/webkit/glue/plugins/plugin_instance.h
deleted file mode 100644
index fa0320e..0000000
--- a/webkit/glue/plugins/plugin_instance.h
+++ /dev/null
@@ -1,375 +0,0 @@
-// 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.
-
-// TODO: Need to deal with NPAPI's NPSavedData.
-// I haven't seen plugins use it yet.
-
-#ifndef WEBKIT_GLUE_PLUGIN_PLUGIN_INSTANCE_H__
-#define WEBKIT_GLUE_PLUGIN_PLUGIN_INSTANCE_H__
-
-#include <map>
-#include <stack>
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/file_path.h"
-#include "base/ref_counted.h"
-#include "base/scoped_ptr.h"
-#include "gfx/native_widget_types.h"
-#include "gfx/point.h"
-#include "gfx/rect.h"
-#include "googleurl/src/gurl.h"
-#include "third_party/npapi/bindings/npapi.h"
-#include "third_party/npapi/bindings/nphostapi.h"
-
-class MessageLoop;
-
-namespace webkit_glue {
-class WebPlugin;
-class WebPluginResourceClient;
-}
-
-namespace NPAPI
-{
-class PluginLib;
-class PluginHost;
-class PluginStream;
-class PluginStreamUrl;
-class PluginDataStream;
-#if defined(OS_MACOSX)
-class ScopedCurrentPluginEvent;
-#endif
-
-// A PluginInstance is an active, running instance of a Plugin.
-// A single plugin may have many PluginInstances.
-class PluginInstance : public base::RefCountedThreadSafe<PluginInstance> {
- public:
- // Create a new instance of a plugin. The PluginInstance
- // will hold a reference to the plugin.
- PluginInstance(PluginLib *plugin, const std::string &mime_type);
-
- // Activates the instance by calling NPP_New.
- // This should be called after our instance is all
- // setup from the host side and we are ready to receive
- // requests from the plugin. We must not call any
- // functions on the plugin instance until start has
- // been called.
- //
- // url: The instance URL.
- // param_names: the list of names of attributes passed via the
- // element.
- // param_values: the list of values corresponding to param_names
- // param_count: number of attributes
- // load_manually: if true indicates that the plugin data would be passed
- // from webkit. if false indicates that the plugin should
- // download the data.
- // This also controls whether the plugin is instantiated as
- // a full page plugin (NP_FULL) or embedded (NP_EMBED)
- //
- bool Start(const GURL& url,
- char** const param_names,
- char** const param_values,
- int param_count,
- bool load_manually);
-
- // NPAPI's instance identifier for this instance
- NPP npp() { return npp_; }
-
- // Get/Set for the instance's window handle.
- gfx::PluginWindowHandle window_handle() const { return window_handle_; }
- void set_window_handle(gfx::PluginWindowHandle value) {
- window_handle_ = value;
- }
-
- // Get/Set whether this instance is in Windowless mode.
- // Default is false.
- bool windowless() { return windowless_; }
- void set_windowless(bool value) { windowless_ = value; }
-
- // Get/Set whether this instance is transparent.
- // This only applies to windowless plugins. Transparent
- // plugins require that webkit paint the background.
- // Default is true.
- bool transparent() { return transparent_; }
- void set_transparent(bool value) { transparent_ = value; }
-
- // Get/Set the WebPlugin associated with this instance
- webkit_glue::WebPlugin* webplugin() { return webplugin_; }
- void set_web_plugin(webkit_glue::WebPlugin* webplugin) {
- webplugin_ = webplugin;
- }
-
- // Get the mimeType for this plugin stream
- const std::string &mime_type() { return mime_type_; }
-
- NPAPI::PluginLib* plugin_lib() { return plugin_; }
-
-#if defined(OS_MACOSX)
- // Get/Set the Mac NPAPI drawing and event models
- NPDrawingModel drawing_model() { return drawing_model_; }
- void set_drawing_model(NPDrawingModel value) { drawing_model_ = value; }
- NPEventModel event_model() { return event_model_; }
- void set_event_model(NPEventModel value) { event_model_ = value; }
- // Updates the instance's tracking of the location of the plugin location
- // relative to the upper left of the screen.
- void set_plugin_origin(const gfx::Point& origin) { plugin_origin_ = origin; }
- // Updates the instance's tracking of the frame of the containing window
- // relative to the upper left of the screen.
- void set_window_frame(const gfx::Rect& frame) {
- containing_window_frame_ = frame;
- }
-#endif
-
- // Creates a stream for sending an URL. If notify_id is non-zero, it will
- // send a notification to the plugin when the stream is complete; otherwise it
- // will not. Set object_url to true if the load is for the object tag's url,
- // or false if it's for a url that the plugin fetched through
- // NPN_GetUrl[Notify].
- PluginStreamUrl* CreateStream(unsigned long resource_id,
- const GURL& url,
- const std::string& mime_type,
- int notify_id);
-
- // For each instance, we track all streams. When the
- // instance closes, all remaining streams are also
- // closed. All streams associated with this instance
- // should call AddStream so that they can be cleaned
- // up when the instance shuts down.
- void AddStream(PluginStream* stream);
-
- // This is called when a stream is closed. We remove the stream from the
- // list, which releases the reference maintained to the stream.
- void RemoveStream(PluginStream* stream);
-
- // Closes all open streams on this instance.
- void CloseStreams();
-
- // Returns the WebPluginResourceClient object for a stream that has become
- // seekable.
- webkit_glue::WebPluginResourceClient* GetRangeRequest(int id);
-
- // Have the plugin create it's script object.
- NPObject *GetPluginScriptableObject();
-
- // WebViewDelegate methods that we implement. This is for handling
- // callbacks during getURLNotify.
- void DidFinishLoadWithReason(const GURL& url, NPReason reason, int notify_id);
-
- // If true, send the Mozilla user agent instead of Chrome's to the plugin.
- bool use_mozilla_user_agent() { return use_mozilla_user_agent_; }
- void set_use_mozilla_user_agent() { use_mozilla_user_agent_ = true; }
-
- // If the plugin instance is backed by a texture, return its ID in the
- // compositor's namespace. Otherwise return 0. Returns 0 by default.
- virtual unsigned GetBackingTextureId();
-
- // Helper that implements NPN_PluginThreadAsyncCall semantics
- void PluginThreadAsyncCall(void (*func)(void *),
- void *userData);
-
- uint32 ScheduleTimer(uint32 interval,
- NPBool repeat,
- void (*func)(NPP id, uint32 timer_id));
-
- void UnscheduleTimer(uint32 timer_id);
-
- bool ConvertPoint(double source_x, double source_y,
- NPCoordinateSpace source_space,
- double* dest_x, double* dest_y,
- NPCoordinateSpace dest_space);
-
- NPError PopUpContextMenu(NPMenu* menu);
-
- //
- // NPAPI methods for calling the Plugin Instance
- //
- NPError NPP_New(unsigned short, short, char *[], char *[]);
- NPError NPP_SetWindow(NPWindow *);
- NPError NPP_NewStream(NPMIMEType, NPStream *, NPBool, unsigned short *);
- NPError NPP_DestroyStream(NPStream *, NPReason);
- int NPP_WriteReady(NPStream *);
- int NPP_Write(NPStream *, int, int, void *);
- void NPP_StreamAsFile(NPStream *, const char *);
- void NPP_URLNotify(const char *, NPReason, void *);
- NPError NPP_GetValue(NPPVariable, void *);
- NPError NPP_SetValue(NPNVariable, void *);
- short NPP_HandleEvent(void*);
- void NPP_Destroy();
- bool NPP_Print(NPPrint* platform_print);
- NPError NPP_ClearSiteData(uint64, const char*, uint64);
- void NPP_URLRedirectNotify(const char* url, int32_t status,
- void* notify_data);
-
- void SendJavaScriptStream(const GURL& url,
- const std::string& result,
- bool success,
- int notify_id);
-
- void DidReceiveManualResponse(const GURL& url,
- const std::string& mime_type,
- const std::string& headers,
- uint32 expected_length,
- uint32 last_modified);
- void DidReceiveManualData(const char* buffer, int length);
- void DidFinishManualLoading();
- void DidManualLoadFail();
-
- void PushPopupsEnabledState(bool enabled);
- void PopPopupsEnabledState();
-
- bool popups_allowed() const {
- return popups_enabled_stack_.empty() ? false : popups_enabled_stack_.top();
- }
-
- // Initiates byte range reads for plugins.
- void RequestRead(NPStream* stream, NPByteRange* range_list);
-
- // Handles GetURL/GetURLNotify/PostURL/PostURLNotify requests initiated
- // by plugins.
- void RequestURL(const char* url,
- const char* method,
- const char* target,
- const char* buf,
- unsigned int len,
- bool notify,
- void* notify_data);
-
- // Handles NPN_URLRedirectResponse calls issued by plugins in response to
- // HTTP URL redirect notifications.
- void URLRedirectResponse(bool allow, void* notify_data);
-
- bool handles_url_redirects() const { return handles_url_redirects_; }
-
- private:
- friend class base::RefCountedThreadSafe<PluginInstance>;
-
-#if defined(OS_MACOSX)
- friend class ScopedCurrentPluginEvent;
- // Sets the event that the plugin is currently handling. The object is not
- // owned or copied, so the caller must call this again with NULL before the
- // event pointer becomes invalid. Clients use ScopedCurrentPluginEvent rather
- // than calling this directly.
- void set_currently_handled_event(NPCocoaEvent* event) {
- currently_handled_event_ = event;
- }
-#endif
-
- ~PluginInstance();
- void OnPluginThreadAsyncCall(void (*func)(void *), void *userData);
- void OnTimerCall(void (*func)(NPP id, uint32 timer_id),
- NPP id, uint32 timer_id);
- bool IsValidStream(const NPStream* stream);
- void GetNotifyData(int notify_id, bool* notify, void** notify_data);
-
- // This is a hack to get the real player plugin to work with chrome
- // The real player plugin dll(nppl3260) when loaded by firefox is loaded via
- // the NS COM API which is analogous to win32 COM. So the NPAPI functions in
- // the plugin are invoked via an interface by firefox. The plugin instance
- // handle which is passed to every NPAPI method is owned by the real player
- // plugin, i.e. it expects the ndata member to point to a structure which
- // it knows about. Eventually it dereferences this structure and compares
- // a member variable at offset 0x24(Version 6.0.11.2888) /2D (Version
- // 6.0.11.3088) with 0 and on failing this check, takes a different code
- // path which causes a crash. Safari and Opera work with version 6.0.11.2888
- // by chance as their ndata structure contains a 0 at the location which real
- // player checks:(. They crash with version 6.0.11.3088 as well. The
- // following member just adds a 96 byte padding to our PluginInstance class
- // which is passed in the ndata member. This magic number works correctly on
- // Vista with UAC on or off :(.
- // NOTE: Please dont change the ordering of the member variables
- // New members should be added after this padding array.
- // TODO(iyengar) : Disassemble the Realplayer ndata structure and look into
- // the possiblity of conforming to it (http://b/issue?id=936667). We
- // could also log a bug with Real, which would save the effort.
- uint8 zero_padding_[96];
- scoped_refptr<NPAPI::PluginLib> plugin_;
- NPP npp_;
- scoped_refptr<PluginHost> host_;
- NPPluginFuncs* npp_functions_;
- std::vector<scoped_refptr<PluginStream> > open_streams_;
- gfx::PluginWindowHandle window_handle_;
- bool windowless_;
- bool transparent_;
- webkit_glue::WebPlugin* webplugin_;
- std::string mime_type_;
- GURL get_url_;
- intptr_t get_notify_data_;
- bool use_mozilla_user_agent_;
-#if defined(OS_MACOSX)
- NPDrawingModel drawing_model_;
- NPEventModel event_model_;
- gfx::Point plugin_origin_;
- gfx::Rect containing_window_frame_;
- NPCocoaEvent* currently_handled_event_; // weak
-#endif
- MessageLoop* message_loop_;
- scoped_refptr<PluginStreamUrl> plugin_data_stream_;
-
- // This flag if true indicates that the plugin data would be passed from
- // webkit. if false indicates that the plugin should download the data.
- bool load_manually_;
-
- // Stack indicating if popups are to be enabled for the outgoing
- // NPN_GetURL/NPN_GetURLNotify calls.
- std::stack<bool> popups_enabled_stack_;
-
- // True if in CloseStreams().
- bool in_close_streams_;
-
- // List of files created for the current plugin instance. File names are
- // added to the list every time the NPP_StreamAsFile function is called.
- std::vector<FilePath> files_created_;
-
- // Next unusued timer id.
- uint32 next_timer_id_;
-
- // Map of timer id to settings for timer.
- struct TimerInfo {
- uint32 interval;
- bool repeat;
- };
- typedef std::map<uint32, TimerInfo> TimerMap;
- TimerMap timers_;
-
- // Tracks pending GET/POST requests so that the plugin-given data doesn't
- // cross process boundaries to an untrusted process.
- typedef std::map<int, void*> PendingRequestMap;
- PendingRequestMap pending_requests_;
- int next_notify_id_;
-
- // Used to track pending range requests so that when WebPlugin replies to us
- // we can match the reply to the stream.
- typedef std::map<int, scoped_refptr<PluginStream> > PendingRangeRequestMap;
- PendingRangeRequestMap pending_range_requests_;
- int next_range_request_id_;
- // The plugin handles the NPAPI URL redirect notification API.
- // See here https://wiki.mozilla.org/NPAPI:HTTPRedirectHandling
- bool handles_url_redirects_;
-
- DISALLOW_COPY_AND_ASSIGN(PluginInstance);
-};
-
-#if defined(OS_MACOSX)
-// Helper to simplify correct usage of set_currently_handled_event.
-// Instantiating will set |instance|'s currently handled to |event| for the
-// lifetime of the object, then NULL when it goes out of scope.
-class ScopedCurrentPluginEvent {
- public:
- ScopedCurrentPluginEvent(PluginInstance* instance, NPCocoaEvent* event)
- : instance_(instance) {
- instance_->set_currently_handled_event(event);
- }
- ~ScopedCurrentPluginEvent() {
- instance_->set_currently_handled_event(NULL);
- }
- private:
- scoped_refptr<PluginInstance> instance_;
- DISALLOW_COPY_AND_ASSIGN(ScopedCurrentPluginEvent);
-};
-#endif
-
-} // namespace NPAPI
-
-#endif // WEBKIT_GLUE_PLUGIN_PLUGIN_INSTANCE_H__
diff --git a/webkit/glue/plugins/plugin_instance_mac.mm b/webkit/glue/plugins/plugin_instance_mac.mm
deleted file mode 100644
index 9800198..0000000
--- a/webkit/glue/plugins/plugin_instance_mac.mm
+++ /dev/null
@@ -1,133 +0,0 @@
-// 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.
-
-#include "build/build_config.h"
-
-#import <AppKit/AppKit.h>
-
-#include "base/logging.h"
-#include "webkit/glue/plugins/plugin_instance.h"
-
-// When C++ exceptions are disabled, the C++ library defines |try| and
-// |catch| so as to allow exception-expecting C++ code to build properly when
-// language support for exceptions is not present. These macros interfere
-// with the use of |@try| and |@catch| in Objective-C files such as this one.
-// Undefine these macros here, after everything has been #included, since
-// there will be no C++ uses and only Objective-C uses from this point on.
-#undef try
-#undef catch
-
-#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5
-@interface NSMenu (SnowLeopardMenuPopUpDeclaration)
-- (BOOL)popUpMenuPositioningItem:(NSMenuItem*)item
- atLocation:(NSPoint)location
- inView:(NSView*)view;
-@end
-#endif
-
-namespace {
-
-// Returns an autoreleased NSEvent constructed from the given np_event,
-// targeting the given window.
-NSEvent* NSEventForNPCocoaEvent(NPCocoaEvent* np_event, NSWindow* window) {
- bool mouse_down = 1;
- switch (np_event->type) {
- case NPCocoaEventMouseDown:
- mouse_down = 1;
- break;
- case NPCocoaEventMouseUp:
- mouse_down = 0;
- break;
- default:
- // If plugins start bringing up context menus for things other than
- // clicks, this will need more plumbing; for now just log it and proceed
- // as if it were a mouse down.
- NOTREACHED();
- }
- NSEventType event_type = NSLeftMouseDown;
- switch (np_event->data.mouse.buttonNumber) {
- case 0:
- event_type = mouse_down ? NSLeftMouseDown : NSLeftMouseUp;
- break;
- case 1:
- event_type = mouse_down ? NSRightMouseDown : NSRightMouseUp;
- break;
- default:
- event_type = mouse_down ? NSOtherMouseDown : NSOtherMouseUp;
- break;
- }
-
- NSInteger click_count = np_event->data.mouse.clickCount;
- NSInteger modifiers = np_event->data.mouse.modifierFlags;
- // NPCocoaEvent doesn't have a timestamp, so just use the current time.
- NSEvent* event =
- [NSEvent mouseEventWithType:event_type
- location:NSMakePoint(0, 0)
- modifierFlags:modifiers
- timestamp:[[NSApp currentEvent] timestamp]
- windowNumber:[window windowNumber]
- context:[NSGraphicsContext currentContext]
- eventNumber:0
- clickCount:click_count
- pressure:1.0];
- return event;
-}
-
-} // namespace
-
-namespace NPAPI {
-
-NPError PluginInstance::PopUpContextMenu(NPMenu* menu) {
- if (!currently_handled_event_)
- return NPERR_GENERIC_ERROR;
-
- CGRect main_display_bounds = CGDisplayBounds(CGMainDisplayID());
- NSPoint screen_point = NSMakePoint(
- plugin_origin_.x() + currently_handled_event_->data.mouse.pluginX,
- plugin_origin_.y() + currently_handled_event_->data.mouse.pluginY);
- // Plugin offsets are upper-left based, so flip vertically for Cocoa.
- screen_point.y = main_display_bounds.size.height - screen_point.y;
-
- NSMenu* nsmenu = reinterpret_cast<NSMenu*>(menu);
- NPError return_val = NPERR_NO_ERROR;
- NSWindow* window = nil;
- @try {
- if ([nsmenu respondsToSelector:
- @selector(popUpMenuPositioningItem:atLocation:inView:)]) {
- [nsmenu popUpMenuPositioningItem:nil atLocation:screen_point inView:nil];
- } else {
- NSRect dummy_window_rect = NSMakeRect(screen_point.x, screen_point.y,
- 1, 1);
- window = [[NSWindow alloc] initWithContentRect:dummy_window_rect
- styleMask:NSBorderlessWindowMask
- backing:NSBackingStoreNonretained
- defer:YES];
- [window setTitle:@"PopupMenuDummy"]; // Lets interposing identify it.
- [window setAlphaValue:0];
- [window makeKeyAndOrderFront:nil];
- [NSMenu popUpContextMenu:nsmenu
- withEvent:NSEventForNPCocoaEvent(currently_handled_event_,
- window)
- forView:[window contentView]];
- }
- }
- @catch (NSException* e) {
- NSLog(@"Caught exception while handling PopUpContextMenu: %@", e);
- return_val = NPERR_GENERIC_ERROR;
- }
-
- if (window) {
- @try {
- [window orderOut:nil];
- [window release];
- }
- @catch (NSException* e) {
- NSLog(@"Caught exception while cleaning up in PopUpContextMenu: %@", e);
- }
- }
-
- return return_val;
-}
-
-} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_lib.cc b/webkit/glue/plugins/plugin_lib.cc
deleted file mode 100644
index 4ae4da4..0000000
--- a/webkit/glue/plugins/plugin_lib.cc
+++ /dev/null
@@ -1,349 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/plugin_lib.h"
-
-#include "base/logging.h"
-#include "base/message_loop.h"
-#include "base/metrics/stats_counters.h"
-#include "base/string_util.h"
-#include "webkit/glue/webkit_glue.h"
-#include "webkit/glue/plugins/plugin_instance.h"
-#include "webkit/glue/plugins/plugin_host.h"
-#include "webkit/glue/plugins/plugin_list.h"
-
-namespace NPAPI {
-
-const char kPluginLibrariesLoadedCounter[] = "PluginLibrariesLoaded";
-const char kPluginInstancesActiveCounter[] = "PluginInstancesActive";
-
-// A list of all the instantiated plugins.
-static std::vector<scoped_refptr<PluginLib> >* g_loaded_libs;
-
-PluginLib* PluginLib::CreatePluginLib(const FilePath& filename) {
- // We can only have one PluginLib object per plugin as it controls the per
- // instance function calls (i.e. NP_Initialize and NP_Shutdown). So we keep
- // a map of PluginLib objects.
- if (!g_loaded_libs)
- g_loaded_libs = new std::vector<scoped_refptr<PluginLib> >;
-
- for (size_t i = 0; i < g_loaded_libs->size(); ++i) {
- if ((*g_loaded_libs)[i]->plugin_info().path == filename)
- return (*g_loaded_libs)[i];
- }
-
- WebPluginInfo info;
- const PluginEntryPoints* entry_points = NULL;
- if (!PluginList::Singleton()->ReadPluginInfo(filename, &info, &entry_points))
- return NULL;
-
- return new PluginLib(info, entry_points);
-}
-
-void PluginLib::UnloadAllPlugins() {
- if (g_loaded_libs) {
- // PluginLib::Unload() can remove items from the list and even delete
- // the list when it removes the last item, so we must work with a copy
- // of the list so that we don't get the carpet removed under our feet.
- std::vector<scoped_refptr<PluginLib> > loaded_libs(*g_loaded_libs);
- for (size_t i = 0; i < loaded_libs.size(); ++i)
- loaded_libs[i]->Unload();
-
- if (g_loaded_libs && g_loaded_libs->empty()) {
- delete g_loaded_libs;
- g_loaded_libs = NULL;
- }
- }
-}
-
-void PluginLib::ShutdownAllPlugins() {
- if (g_loaded_libs) {
- for (size_t i = 0; i < g_loaded_libs->size(); ++i)
- (*g_loaded_libs)[i]->Shutdown();
- }
-}
-
-PluginLib::PluginLib(const WebPluginInfo& info,
- const PluginEntryPoints* entry_points)
- : web_plugin_info_(info),
- library_(NULL),
- initialized_(false),
- saved_data_(0),
- instance_count_(0),
- skip_unload_(false) {
- base::StatsCounter(kPluginLibrariesLoadedCounter).Increment();
- memset(static_cast<void*>(&plugin_funcs_), 0, sizeof(plugin_funcs_));
- g_loaded_libs->push_back(make_scoped_refptr(this));
-
- if (entry_points) {
- internal_ = true;
- entry_points_ = *entry_points;
- } else {
- internal_ = false;
- // We will read the entry points from the plugin directly.
- memset(&entry_points_, 0, sizeof(entry_points_));
- }
-}
-
-PluginLib::~PluginLib() {
- base::StatsCounter(kPluginLibrariesLoadedCounter).Decrement();
- if (saved_data_ != 0) {
- // TODO - delete the savedData object here
- }
-}
-
-NPPluginFuncs* PluginLib::functions() {
- return &plugin_funcs_;
-}
-
-NPError PluginLib::NP_Initialize() {
- LOG_IF(ERROR, PluginList::DebugPluginLoading())
- << "PluginLib::NP_Initialize(" << web_plugin_info_.path.value()
- << "): initialized=" << initialized_;
- if (initialized_)
- return NPERR_NO_ERROR;
-
- if (!Load())
- return NPERR_MODULE_LOAD_FAILED_ERROR;
-
- PluginHost* host = PluginHost::Singleton();
- if (host == 0)
- return NPERR_GENERIC_ERROR;
-
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
- NPError rv = entry_points_.np_initialize(host->host_functions(),
- &plugin_funcs_);
-#else
- NPError rv = entry_points_.np_initialize(host->host_functions());
-#if defined(OS_MACOSX)
- // On the Mac, we need to get entry points after calling np_initialize to
- // match the behavior of other browsers.
- if (rv == NPERR_NO_ERROR) {
- rv = entry_points_.np_getentrypoints(&plugin_funcs_);
- }
-#endif // OS_MACOSX
-#endif
- LOG_IF(ERROR, PluginList::DebugPluginLoading())
- << "PluginLib::NP_Initialize(" << web_plugin_info_.path.value()
- << "): result=" << rv;
- initialized_ = (rv == NPERR_NO_ERROR);
- return rv;
-}
-
-void PluginLib::NP_Shutdown(void) {
- DCHECK(initialized_);
- entry_points_.np_shutdown();
-}
-
-void PluginLib::PreventLibraryUnload() {
- skip_unload_ = true;
-}
-
-PluginInstance* PluginLib::CreateInstance(const std::string& mime_type) {
- PluginInstance* new_instance = new PluginInstance(this, mime_type);
- instance_count_++;
- base::StatsCounter(kPluginInstancesActiveCounter).Increment();
- DCHECK_NE(static_cast<PluginInstance*>(NULL), new_instance);
- return new_instance;
-}
-
-void PluginLib::CloseInstance() {
- base::StatsCounter(kPluginInstancesActiveCounter).Decrement();
- instance_count_--;
- // If a plugin is running in its own process it will get unloaded on process
- // shutdown.
- if ((instance_count_ == 0) && webkit_glue::IsPluginRunningInRendererProcess())
- Unload();
-}
-
-bool PluginLib::Load() {
- if (library_)
- return true;
-
- bool rv = false;
- base::NativeLibrary library = 0;
-
- if (!internal_) {
-#if defined(OS_WIN)
- // This is to work around a bug in the Real player recorder plugin which
- // intercepts LoadLibrary calls from chrome.dll and wraps NPAPI functions
- // provided by the plugin. It crashes if the media player plugin is being
- // loaded. Workaround is to load the dll dynamically by getting the
- // LoadLibrary API address from kernel32.dll which bypasses the recorder
- // plugin.
- if (web_plugin_info_.name.find(L"Windows Media Player") !=
- std::wstring::npos) {
- library = base::LoadNativeLibraryDynamically(web_plugin_info_.path);
- } else {
- library = base::LoadNativeLibrary(web_plugin_info_.path);
- }
-#else // OS_WIN
- library = base::LoadNativeLibrary(web_plugin_info_.path);
-#endif // OS_WIN
- if (library == 0) {
- LOG_IF(ERROR, PluginList::DebugPluginLoading())
- << "Couldn't load plugin " << web_plugin_info_.path.value();
- return rv;
- }
-
-#if defined(OS_MACOSX)
- // According to the WebKit source, QuickTime at least requires us to call
- // UseResFile on the plugin resources before loading.
- if (library->bundle_resource_ref != -1)
- UseResFile(library->bundle_resource_ref);
-#endif
-
- rv = true; // assume success now
-
- entry_points_.np_initialize =
- (NP_InitializeFunc)base::GetFunctionPointerFromNativeLibrary(library,
- "NP_Initialize");
- if (entry_points_.np_initialize == 0)
- rv = false;
-
-#if defined(OS_WIN) || defined(OS_MACOSX)
- entry_points_.np_getentrypoints =
- (NP_GetEntryPointsFunc)base::GetFunctionPointerFromNativeLibrary(
- library, "NP_GetEntryPoints");
- if (entry_points_.np_getentrypoints == 0)
- rv = false;
-#endif
-
- entry_points_.np_shutdown =
- (NP_ShutdownFunc)base::GetFunctionPointerFromNativeLibrary(library,
- "NP_Shutdown");
- if (entry_points_.np_shutdown == 0)
- rv = false;
- } else {
- rv = true;
- }
-
- if (rv) {
- plugin_funcs_.size = sizeof(plugin_funcs_);
- plugin_funcs_.version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
-#if !defined(OS_POSIX)
- if (entry_points_.np_getentrypoints(&plugin_funcs_) != NPERR_NO_ERROR)
- rv = false;
-#else
- // On Linux and Mac, we get the plugin entry points during NP_Initialize.
-#endif
- }
-
- if (!internal_) {
- if (rv) {
- LOG_IF(ERROR, PluginList::DebugPluginLoading())
- << "Plugin " << web_plugin_info_.path.value()
- << " loaded successfully.";
- library_ = library;
- } else {
- LOG_IF(ERROR, PluginList::DebugPluginLoading())
- << "Plugin " << web_plugin_info_.path.value()
- << " failed to load, unloading.";
- base::UnloadNativeLibrary(library);
- }
- }
-
- return rv;
-}
-
-// This class implements delayed NP_Shutdown and FreeLibrary on the plugin dll.
-class FreePluginLibraryTask : public Task {
- public:
- FreePluginLibraryTask(const FilePath& path,
- base::NativeLibrary library,
- NP_ShutdownFunc shutdown_func)
- : path_(path),
- library_(library),
- NP_Shutdown_(shutdown_func) {
- }
-
- ~FreePluginLibraryTask() {}
-
- void Run() {
- if (NP_Shutdown_) {
- // Don't call NP_Shutdown if the library has been reloaded since this task
- // was posted.
- bool reloaded = false;
- if (g_loaded_libs) {
- for (size_t i = 0; i < g_loaded_libs->size(); ++i) {
- if ((*g_loaded_libs)[i]->plugin_info().path == path_)
- reloaded = true;
- }
- }
- if (!reloaded)
- NP_Shutdown_();
- }
-
- if (library_) {
- // Always call base::UnloadNativeLibrary so that the system reference
- // count is decremented.
- base::UnloadNativeLibrary(library_);
- library_ = NULL;
- }
- }
-
- private:
- FilePath path_;
- base::NativeLibrary library_;
- NP_ShutdownFunc NP_Shutdown_;
- DISALLOW_COPY_AND_ASSIGN(FreePluginLibraryTask);
-};
-
-void PluginLib::Unload() {
- if (!internal_ && library_) {
- // In case of single process mode, a plugin can delete itself
- // by executing a script. So delay the unloading of the library
- // so that the plugin will have a chance to unwind.
- bool defer_unload = webkit_glue::IsPluginRunningInRendererProcess();
-
-/* TODO(dglazkov): Revisit when re-enabling the JSC build.
-#if USE(JSC)
- // The plugin NPAPI instances may still be around. Delay the
- // NP_Shutdown and FreeLibrary calls at least till the next
- // peek message.
- defer_unload = true;
-#endif
-*/
-
- if (defer_unload) {
- FreePluginLibraryTask* free_library_task =
- new FreePluginLibraryTask(web_plugin_info_.path,
- skip_unload_ ? NULL : library_,
- entry_points_.np_shutdown);
- LOG_IF(ERROR, PluginList::DebugPluginLoading())
- << "Scheduling delayed unload for plugin "
- << web_plugin_info_.path.value();
- MessageLoop::current()->PostTask(FROM_HERE, free_library_task);
- } else {
- Shutdown();
- if (!skip_unload_) {
- LOG_IF(ERROR, PluginList::DebugPluginLoading())
- << "Unloading plugin " << web_plugin_info_.path.value();
- base::UnloadNativeLibrary(library_);
- }
- }
-
- library_ = NULL;
- }
-
- for (size_t i = 0; i < g_loaded_libs->size(); ++i) {
- if ((*g_loaded_libs)[i].get() == this) {
- g_loaded_libs->erase(g_loaded_libs->begin() + i);
- break;
- }
- }
- if (g_loaded_libs->empty()) {
- delete g_loaded_libs;
- g_loaded_libs = NULL;
- }
-}
-
-void PluginLib::Shutdown() {
- if (initialized_ && !internal_) {
- NP_Shutdown();
- initialized_ = false;
- }
-}
-
-} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_lib.h b/webkit/glue/plugins/plugin_lib.h
deleted file mode 100644
index ca46e41..0000000
--- a/webkit/glue/plugins/plugin_lib.h
+++ /dev/null
@@ -1,120 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PLUGIN_LIB_H_
-#define WEBKIT_GLUE_PLUGINS_PLUGIN_LIB_H_
-
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/native_library.h"
-#include "base/ref_counted.h"
-#include "build/build_config.h"
-#include "webkit/glue/plugins/plugin_list.h"
-#include "webkit/glue/plugins/webplugin.h"
-
-class FilePath;
-struct WebPluginInfo;
-
-namespace NPAPI {
-
-class PluginInstance;
-
-// A PluginLib is a single NPAPI Plugin Library, and is the lifecycle
-// manager for new PluginInstances.
-class PluginLib : public base::RefCounted<PluginLib> {
- public:
- static PluginLib* CreatePluginLib(const FilePath& filename);
-
- // Creates a WebPluginInfo structure given a plugin's path. On success
- // returns true, with the information being put into "info".
- // Returns false if the library couldn't be found, or if it's not a plugin.
- static bool ReadWebPluginInfo(const FilePath& filename, WebPluginInfo* info);
-
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
- // Parse the result of an NP_GetMIMEDescription() call.
- // This API is only used on Unixes, and is exposed here for testing.
- static void ParseMIMEDescription(const std::string& description,
- std::vector<WebPluginMimeType>* mime_types);
-#endif
-
- // Unloads all the loaded plugin libraries and cleans up the plugin map.
- static void UnloadAllPlugins();
-
- // Shuts down all loaded plugin instances.
- static void ShutdownAllPlugins();
-
- // Get the Plugin's function pointer table.
- NPPluginFuncs* functions();
-
- // Creates a new instance of this plugin.
- PluginInstance* CreateInstance(const std::string& mime_type);
-
- // Called by the instance when the instance is tearing down.
- void CloseInstance();
-
- // Gets information about this plugin and the mime types that it
- // supports.
- const WebPluginInfo& plugin_info() { return web_plugin_info_; }
-
- bool internal() { return internal_; }
-
- //
- // NPAPI functions
- //
-
- // NPAPI method to initialize a Plugin.
- // Initialize can be safely called multiple times
- NPError NP_Initialize();
-
- // NPAPI method to shutdown a Plugin.
- void NP_Shutdown(void);
-
- int instance_count() const { return instance_count_; }
-
- // Prevents the library code from being unload when Unload() is called (since
- // some plugins crash if unloaded).
- void PreventLibraryUnload();
-
- // protected for testability.
- protected:
- friend class base::RefCounted<PluginLib>;
-
- // Creates a new PluginLib.
- // |entry_points| is non-NULL for internal plugins.
- PluginLib(const WebPluginInfo& info,
- const PluginEntryPoints* entry_points);
-
- virtual ~PluginLib();
-
- // Attempts to load the plugin from the library.
- // Returns true if it is a legitimate plugin, false otherwise
- bool Load();
-
- // Unloads the plugin library.
- void Unload();
-
- // Shutdown the plugin library.
- void Shutdown();
-
- private:
- bool internal_; // True for plugins that are built-in into chrome binaries.
- WebPluginInfo web_plugin_info_; // Supported mime types, description
- base::NativeLibrary library_; // The opened library reference.
- NPPluginFuncs plugin_funcs_; // The struct of plugin side functions.
- bool initialized_; // Is the plugin initialized?
- NPSavedData *saved_data_; // Persisted plugin info for NPAPI.
- int instance_count_; // Count of plugins in use.
- bool skip_unload_; // True if library_ should not be unloaded.
-
- // Function pointers to entry points into the plugin.
- PluginEntryPoints entry_points_;
-
- DISALLOW_COPY_AND_ASSIGN(PluginLib);
-};
-
-} // namespace NPAPI
-
-#endif // WEBKIT_GLUE_PLUGINS_PLUGIN_LIB_H_
diff --git a/webkit/glue/plugins/plugin_lib_mac.mm b/webkit/glue/plugins/plugin_lib_mac.mm
deleted file mode 100644
index 89444c8..0000000
--- a/webkit/glue/plugins/plugin_lib_mac.mm
+++ /dev/null
@@ -1,348 +0,0 @@
-// 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 <Carbon/Carbon.h>
-
-#include "webkit/glue/plugins/plugin_lib.h"
-
-#include "base/mac/scoped_cftyperef.h"
-#include "base/native_library.h"
-#include "base/scoped_ptr.h"
-#include "base/string_split.h"
-#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "webkit/glue/plugins/plugin_list.h"
-
-static const short kSTRTypeDefinitionResourceID = 128;
-static const short kSTRTypeDescriptionResourceID = 127;
-static const short kSTRPluginDescriptionResourceID = 126;
-
-using base::mac::ScopedCFTypeRef;
-
-namespace NPAPI {
-
-namespace {
-
-NSDictionary* GetMIMETypes(CFBundleRef bundle) {
- NSString* mime_filename =
- (NSString*)CFBundleGetValueForInfoDictionaryKey(bundle,
- CFSTR("WebPluginMIMETypesFilename"));
-
- if (mime_filename) {
-
- // get the file
-
- NSString* mime_path =
- [NSString stringWithFormat:@"%@/Library/Preferences/%@",
- NSHomeDirectory(), mime_filename];
- NSDictionary* mime_file_dict =
- [NSDictionary dictionaryWithContentsOfFile:mime_path];
-
- // is it valid?
-
- bool valid_file = false;
- if (mime_file_dict) {
- NSString* l10n_name =
- [mime_file_dict objectForKey:@"WebPluginLocalizationName"];
- NSString* preferred_l10n = [[NSLocale currentLocale] localeIdentifier];
- if ([l10n_name isEqualToString:preferred_l10n])
- valid_file = true;
- }
-
- if (valid_file)
- return [mime_file_dict objectForKey:@"WebPluginMIMETypes"];
-
- // dammit, I didn't want to have to do this
-
- typedef void (*CreateMIMETypesPrefsPtr)(void);
- CreateMIMETypesPrefsPtr create_prefs_file =
- (CreateMIMETypesPrefsPtr)CFBundleGetFunctionPointerForName(
- bundle, CFSTR("BP_CreatePluginMIMETypesPreferences"));
- if (!create_prefs_file)
- return nil;
- create_prefs_file();
-
- // one more time
-
- mime_file_dict = [NSDictionary dictionaryWithContentsOfFile:mime_path];
- if (mime_file_dict)
- return [mime_file_dict objectForKey:@"WebPluginMIMETypes"];
- else
- return nil;
-
- } else {
- return (NSDictionary*)CFBundleGetValueForInfoDictionaryKey(bundle,
- CFSTR("WebPluginMIMETypes"));
- }
-}
-
-bool ReadPlistPluginInfo(const FilePath& filename, CFBundleRef bundle,
- WebPluginInfo* info) {
- NSDictionary* mime_types = GetMIMETypes(bundle);
- if (!mime_types)
- return false; // no type info here; try elsewhere
-
- for (NSString* mime_type in [mime_types allKeys]) {
- NSDictionary* mime_dict = [mime_types objectForKey:mime_type];
- NSString* mime_desc = [mime_dict objectForKey:@"WebPluginTypeDescription"];
- NSArray* mime_exts = [mime_dict objectForKey:@"WebPluginExtensions"];
-
- WebPluginMimeType mime;
- mime.mime_type = base::SysNSStringToUTF8([mime_type lowercaseString]);
- // Remove PDF from the list of types handled by QuickTime, since it provides
- // a worse experience than just downloading the PDF.
- if (mime.mime_type == "application/pdf" &&
- StartsWithASCII(filename.BaseName().value(), "QuickTime", false)) {
- continue;
- }
-
- if (mime_desc)
- mime.description = base::SysNSStringToUTF16(mime_desc);
- for (NSString* ext in mime_exts)
- mime.file_extensions.push_back(
- base::SysNSStringToUTF8([ext lowercaseString]));
-
- info->mime_types.push_back(mime);
- }
-
- NSString* plugin_name =
- (NSString*)CFBundleGetValueForInfoDictionaryKey(bundle,
- CFSTR("WebPluginName"));
- NSString* plugin_vers =
- (NSString*)CFBundleGetValueForInfoDictionaryKey(bundle,
- CFSTR("CFBundleShortVersionString"));
- NSString* plugin_desc =
- (NSString*)CFBundleGetValueForInfoDictionaryKey(bundle,
- CFSTR("WebPluginDescription"));
-
- if (plugin_name)
- info->name = base::SysNSStringToUTF16(plugin_name);
- else
- info->name = UTF8ToUTF16(filename.BaseName().value());
- info->path = filename;
- if (plugin_vers)
- info->version = base::SysNSStringToUTF16(plugin_vers);
- if (plugin_desc)
- info->desc = base::SysNSStringToUTF16(plugin_desc);
- else
- info->desc = UTF8ToUTF16(filename.BaseName().value());
- info->enabled = true;
-
- return true;
-}
-
-class ScopedBundleResourceFile {
- public:
- ScopedBundleResourceFile(CFBundleRef bundle) : bundle_(bundle) {
- old_ref_num_ = CurResFile();
- bundle_ref_num_ = CFBundleOpenBundleResourceMap(bundle);
- UseResFile(bundle_ref_num_);
- }
- ~ScopedBundleResourceFile() {
- UseResFile(old_ref_num_);
- CFBundleCloseBundleResourceMap(bundle_, bundle_ref_num_);
- }
-
- private:
- CFBundleRef bundle_;
- CFBundleRefNum bundle_ref_num_;
- ResFileRefNum old_ref_num_;
-};
-
-bool GetSTRResource(CFBundleRef bundle, short res_id,
- std::vector<std::string>* contents) {
- Handle res_handle = Get1Resource('STR#', res_id);
- if (!res_handle || !*res_handle)
- return false;
-
- char* pointer = *res_handle;
- short num_strings = *(short*)pointer;
- pointer += sizeof(short);
- for (short i = 0; i < num_strings; ++i) {
- // Despite being 8-bits wide, these are legacy encoded. Make a round trip.
- ScopedCFTypeRef<CFStringRef> str(CFStringCreateWithPascalStringNoCopy(
- kCFAllocatorDefault,
- (unsigned char*)pointer,
- GetApplicationTextEncoding(), // is this right?
- kCFAllocatorNull)); // perhaps CFStringGetSystemEncoding?
- if (!str.get())
- return false;
- contents->push_back(base::SysCFStringRefToUTF8(str.get()));
- pointer += 1+*reinterpret_cast<unsigned char*>(pointer);
- }
-
- return true;
-}
-
-bool ReadSTRPluginInfo(const FilePath& filename, CFBundleRef bundle,
- WebPluginInfo* info) {
- ScopedBundleResourceFile res_file(bundle);
-
- std::vector<std::string> type_strings;
- if (!GetSTRResource(bundle, kSTRTypeDefinitionResourceID, &type_strings))
- return false;
-
- std::vector<std::string> type_descs;
- bool have_type_descs = GetSTRResource(bundle,
- kSTRTypeDescriptionResourceID,
- &type_descs);
-
- std::vector<std::string> plugin_descs;
- bool have_plugin_descs = GetSTRResource(bundle,
- kSTRPluginDescriptionResourceID,
- &plugin_descs);
-
- size_t num_types = type_strings.size()/2;
-
- for (size_t i = 0; i < num_types; ++i) {
- WebPluginMimeType mime;
- mime.mime_type = StringToLowerASCII(type_strings[2*i]);
- if (have_type_descs && i < type_descs.size())
- mime.description = UTF8ToUTF16(type_descs[i]);
- base::SplitString(
- StringToLowerASCII(type_strings[2*i+1]), ',', &mime.file_extensions);
-
- info->mime_types.push_back(mime);
- }
-
- NSString* plugin_vers =
- (NSString*)CFBundleGetValueForInfoDictionaryKey(bundle,
- CFSTR("CFBundleShortVersionString"));
-
- if (have_plugin_descs && plugin_descs.size() > 1)
- info->name = UTF8ToUTF16(plugin_descs[1]);
- else
- info->name = UTF8ToUTF16(filename.BaseName().value());
- info->path = filename;
- if (plugin_vers)
- info->version = base::SysNSStringToUTF16(plugin_vers);
- if (have_plugin_descs && plugin_descs.size() > 0)
- info->desc = UTF8ToUTF16(plugin_descs[0]);
- else
- info->desc = UTF8ToUTF16(filename.BaseName().value());
- info->enabled = true;
-
- return true;
-}
-
-} // anonymous namespace
-
-bool PluginLib::ReadWebPluginInfo(const FilePath &filename,
- WebPluginInfo* info) {
- // There are two ways to get information about plugin capabilities. One is an
- // Info.plist set of keys, documented at
- // http://developer.apple.com/documentation/InternetWeb/Conceptual/WebKit_PluginProgTopic/Concepts/AboutPlugins.html .
- // The other is a set of STR# resources, documented at
- // https://developer.mozilla.org/En/Gecko_Plugin_API_Reference/Plug-in_Development_Overview .
- //
- // Historically, the data was maintained in the STR# resources. Apple, with
- // the introduction of WebKit, noted the weaknesses of resources and moved the
- // information into the Info.plist. Mozilla had always supported a
- // NP_GetMIMEDescription() entry point for Unix plugins and also supports it
- // on the Mac to supplement the STR# format. WebKit does not support
- // NP_GetMIMEDescription() and neither do we. (That entry point is documented
- // at https://developer.mozilla.org/en/NP_GetMIMEDescription .) We prefer the
- // Info.plist format because it's more extensible and has a defined encoding,
- // but will fall back to the STR# format of the data if it is not present in
- // the Info.plist.
- //
- // The parsing of the data lives in the two functions ReadSTRPluginInfo() and
- // ReadPlistPluginInfo(), but a summary of the formats follows.
- //
- // Each data type handled by a plugin has several properties:
- // - <<type0mimetype>>
- // - <<type0fileextension0>>..<<type0fileextensionk>>
- // - <<type0description>>
- //
- // Each plugin may have any number of types defined. In addition, the plugin
- // itself has properties:
- // - <<plugindescription>>
- // - <<pluginname>>
- //
- // For the Info.plist version, the data is formatted as follows (in text plist
- // format):
- // {
- // ... the usual plist keys ...
- // WebPluginDescription = <<plugindescription>>;
- // WebPluginMIMETypes = {
- // <<type0mimetype>> = {
- // WebPluginExtensions = (
- // <<type0fileextension0>>,
- // ...
- // <<type0fileextensionk>>,
- // );
- // WebPluginTypeDescription = <<type0description>>;
- // };
- // <<type1mimetype>> = { ... };
- // ...
- // <<typenmimetype>> = { ... };
- // };
- // WebPluginName = <<pluginname>>;
- // }
- //
- // Alternatively (and this is undocumented), rather than a WebPluginMIMETypes
- // key, there may be a WebPluginMIMETypesFilename key. If it is present, then
- // it is the name of a file in the user's preferences folder in which to find
- // the WebPluginMIMETypes key. If the key is present but the file doesn't
- // exist, we must load the plugin and call a specific function to have the
- // plugin create the file.
- //
- // If we do not find those keys in the Info.plist, we fall back to the STR#
- // resources. In them, the data is formatted as follows:
- // STR# 128
- // (1) <<type0mimetype>>
- // (2) <<type0fileextension0>>,...,<<type0fileextensionk>>
- // (3) <<type1mimetype>>
- // (4) <<type1fileextension0>>,...,<<type1fileextensionk>>
- // (...)
- // (2n+1) <<typenmimetype>>
- // (2n+2) <<typenfileextension0>>,...,<<typenfileextensionk>>
- // STR# 127
- // (1) <<type0description>>
- // (2) <<type1description>>
- // (...)
- // (n+1) <<typendescription>>
- // STR# 126
- // (1) <<plugindescription>>
- // (2) <<pluginname>>
- //
- // Strictly speaking, only STR# 128 is required.
-
- ScopedCFTypeRef<CFURLRef> bundle_url(CFURLCreateFromFileSystemRepresentation(
- kCFAllocatorDefault, (const UInt8*)filename.value().c_str(),
- filename.value().length(), true));
- if (!bundle_url)
- return false;
- ScopedCFTypeRef<CFBundleRef> bundle(CFBundleCreate(kCFAllocatorDefault,
- bundle_url.get()));
- if (!bundle)
- return false;
-
- // preflight
-
- OSType type = 0;
- CFBundleGetPackageInfo(bundle.get(), &type, NULL);
- if (type != FOUR_CHAR_CODE('BRPL'))
- return false;
-
- CFErrorRef error;
- Boolean would_load = CFBundlePreflightExecutable(bundle.get(), &error);
- if (!would_load)
- return false;
-
- // get the info
-
- if (ReadPlistPluginInfo(filename, bundle.get(), info))
- return true;
-
- if (ReadSTRPluginInfo(filename, bundle.get(), info))
- return true;
-
- // ... or not
-
- return false;
-}
-
-} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_lib_posix.cc b/webkit/glue/plugins/plugin_lib_posix.cc
deleted file mode 100644
index ac937e1..0000000
--- a/webkit/glue/plugins/plugin_lib_posix.cc
+++ /dev/null
@@ -1,256 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/plugin_lib.h"
-
-#include <dlfcn.h>
-#if defined(OS_OPENBSD)
-#include <sys/exec_elf.h>
-#else
-#include <elf.h>
-#include <fcntl.h>
-#endif
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "base/eintr_wrapper.h"
-#include "base/file_util.h"
-#include "base/string_split.h"
-#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "webkit/glue/plugins/plugin_list.h"
-
-// These headers must be included in this order to make the declaration gods
-// happy.
-#include "base/third_party/nspr/prcpucfg_linux.h"
-
-namespace {
-
-using NPAPI::PluginList;
-
-// Copied from nsplugindefs.h instead of including the file since it has a bunch
-// of dependencies.
-enum nsPluginVariable {
- nsPluginVariable_NameString = 1,
- nsPluginVariable_DescriptionString = 2
-};
-
-// Read the ELF header and return true if it is usable on
-// the current architecture (e.g. 32-bit ELF on 32-bit build).
-// Returns false on other errors as well.
-bool ELFMatchesCurrentArchitecture(const FilePath& filename) {
- // First make sure we can open the file and it is in fact, a regular file.
- struct stat stat_buf;
- // Open with O_NONBLOCK so we don't block on pipes.
- int fd = open(filename.value().c_str(), O_RDONLY|O_NONBLOCK);
- if (fd < 0)
- return false;
- bool ret = (fstat(fd, &stat_buf) >= 0 && S_ISREG(stat_buf.st_mode));
- if (HANDLE_EINTR(close(fd)) < 0)
- return false;
- if (!ret)
- return false;
-
- const size_t kELFBufferSize = 5;
- char buffer[kELFBufferSize];
- if (!file_util::ReadFile(filename, buffer, kELFBufferSize))
- return false;
-
- if (buffer[0] != ELFMAG0 ||
- buffer[1] != ELFMAG1 ||
- buffer[2] != ELFMAG2 ||
- buffer[3] != ELFMAG3) {
- // Not an ELF file, perhaps?
- return false;
- }
-
- int elf_class = buffer[EI_CLASS];
-#if defined(ARCH_CPU_32_BITS)
- if (elf_class == ELFCLASS32)
- return true;
-#elif defined(ARCH_CPU_64_BITS)
- if (elf_class == ELFCLASS64)
- return true;
-#endif
-
- return false;
-}
-
-// This structure matches enough of nspluginwrapper's NPW_PluginInfo
-// for us to extract the real plugin path.
-struct __attribute__((packed)) NSPluginWrapperInfo {
- char ident[32]; // NSPluginWrapper magic identifier (includes version).
- char path[PATH_MAX]; // Path to wrapped plugin.
-};
-
-// Test a plugin for whether it's been wrapped by NSPluginWrapper, and
-// if so attempt to unwrap it. Pass in an opened plugin handle; on
-// success, |dl| and |unwrapped_path| will be filled in with the newly
-// opened plugin. On failure, params are left unmodified.
-void UnwrapNSPluginWrapper(void **dl, FilePath* unwrapped_path) {
- NSPluginWrapperInfo* info =
- reinterpret_cast<NSPluginWrapperInfo*>(dlsym(*dl, "NPW_Plugin"));
- if (!info)
- return; // Not a NSPW plugin.
-
- // Here we could check the NSPW ident field for the versioning
- // information, but the path field is available in all versions
- // anyway.
-
- // Grab the path to the wrapped plugin. Just in case the structure
- // format changes, protect against the path not being null-terminated.
- char* path_end = static_cast<char*>(memchr(info->path, '\0',
- sizeof(info->path)));
- if (!path_end)
- path_end = info->path + sizeof(info->path);
- FilePath path = FilePath(std::string(info->path, path_end - info->path));
-
- if (!ELFMatchesCurrentArchitecture(path)) {
- LOG(WARNING) << path.value() << " is nspluginwrapper wrapping a "
- << "plugin for a different architecture; it will "
- << "work better if you instead use a native plugin.";
- return;
- }
-
- void* newdl = base::LoadNativeLibrary(path);
- if (!newdl) {
- // We couldn't load the unwrapped plugin for some reason, despite
- // being able to load the wrapped one. Just use the wrapped one.
- LOG_IF(ERROR, PluginList::DebugPluginLoading())
- << "Could not use unwrapped nspluginwrapper plugin "
- << unwrapped_path->value() << ", using the wrapped one.";
- return;
- }
-
- // Unload the wrapped plugin, and use the wrapped plugin instead.
- LOG_IF(ERROR, PluginList::DebugPluginLoading())
- << "Using unwrapped version " << unwrapped_path->value()
- << " of nspluginwrapper-wrapped plugin.";
- base::UnloadNativeLibrary(*dl);
- *dl = newdl;
- *unwrapped_path = path;
-}
-
-} // anonymous namespace
-
-namespace NPAPI {
-
-bool PluginLib::ReadWebPluginInfo(const FilePath& filename,
- WebPluginInfo* info) {
- // The file to reference is:
- // http://mxr.mozilla.org/firefox/source/modules/plugin/base/src/nsPluginsDirUnix.cpp
-
- // Skip files that aren't appropriate for our architecture.
- if (!ELFMatchesCurrentArchitecture(filename)) {
- LOG_IF(ERROR, PluginList::DebugPluginLoading())
- << "Skipping plugin " << filename.value()
- << " because it doesn't match the current architecture.";
- return false;
- }
-
- void* dl = base::LoadNativeLibrary(filename);
- if (!dl) {
- LOG_IF(ERROR, PluginList::DebugPluginLoading())
- << "While reading plugin info, unable to load library "
- << filename.value() << ", skipping.";
- return false;
- }
-
- info->path = filename;
- info->enabled = true;
-
- // Attempt to swap in the wrapped plugin if this is nspluginwrapper.
- UnwrapNSPluginWrapper(&dl, &info->path);
-
- // See comments in plugin_lib_mac regarding this symbol.
- typedef const char* (*NP_GetMimeDescriptionType)();
- NP_GetMimeDescriptionType NP_GetMIMEDescription =
- reinterpret_cast<NP_GetMimeDescriptionType>(
- dlsym(dl, "NP_GetMIMEDescription"));
- const char* mime_description = NULL;
- if (NP_GetMIMEDescription)
- mime_description = NP_GetMIMEDescription();
-
- if (mime_description)
- ParseMIMEDescription(mime_description, &info->mime_types);
-
- // The plugin name and description live behind NP_GetValue calls.
- typedef NPError (*NP_GetValueType)(void* unused,
- nsPluginVariable variable,
- void* value_out);
- NP_GetValueType NP_GetValue =
- reinterpret_cast<NP_GetValueType>(dlsym(dl, "NP_GetValue"));
- if (NP_GetValue) {
- const char* name = NULL;
- NP_GetValue(NULL, nsPluginVariable_NameString, &name);
- if (name)
- info->name = UTF8ToUTF16(name);
-
- const char* description = NULL;
- NP_GetValue(NULL, nsPluginVariable_DescriptionString, &description);
- if (description)
- info->desc = UTF8ToUTF16(description);
-
- LOG_IF(ERROR, PluginList::DebugPluginLoading())
- << "Got info for plugin " << filename.value()
- << " Name = \"" << UTF16ToUTF8(info->name)
- << "\", Description = \"" << UTF16ToUTF8(info->desc) << "\".";
- } else {
- LOG_IF(ERROR, PluginList::DebugPluginLoading())
- << "Plugin " << filename.value()
- << " has no GetValue() and probably won't work.";
- }
-
- // Intentionally not unloading the plugin here, it can lead to crashes.
-
- return true;
-}
-
-// static
-void PluginLib::ParseMIMEDescription(
- const std::string& description,
- std::vector<WebPluginMimeType>* mime_types) {
- // We parse the description here into WebPluginMimeType structures.
- // Naively from the NPAPI docs you'd think you could use
- // string-splitting, but the Firefox parser turns out to do something
- // different: find the first colon, then the second, then a semi.
- //
- // See ParsePluginMimeDescription near
- // http://mxr.mozilla.org/firefox/source/modules/plugin/base/src/nsPluginsDirUtils.h#53
-
- std::string::size_type ofs = 0;
- for (;;) {
- WebPluginMimeType mime_type;
-
- std::string::size_type end = description.find(':', ofs);
- if (end == std::string::npos)
- break;
- mime_type.mime_type = description.substr(ofs, end - ofs);
- ofs = end + 1;
-
- end = description.find(':', ofs);
- if (end == std::string::npos)
- break;
- const std::string extensions = description.substr(ofs, end - ofs);
- base::SplitString(extensions, ',', &mime_type.file_extensions);
- ofs = end + 1;
-
- end = description.find(';', ofs);
- // It's ok for end to run off the string here. If there's no
- // trailing semicolon we consume the remainder of the string.
- if (end != std::string::npos) {
- mime_type.description = UTF8ToUTF16(description.substr(ofs, end - ofs));
- } else {
- mime_type.description = UTF8ToUTF16(description.substr(ofs));
- }
- mime_types->push_back(mime_type);
- if (end == std::string::npos)
- break;
- ofs = end + 1;
- }
-}
-
-} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_lib_unittest.cc b/webkit/glue/plugins/plugin_lib_unittest.cc
deleted file mode 100644
index 45c4bb6..0000000
--- a/webkit/glue/plugins/plugin_lib_unittest.cc
+++ /dev/null
@@ -1,152 +0,0 @@
-// Copyright (c) 2009 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 "webkit/glue/plugins/plugin_lib.h"
-
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-#include "build/build_config.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-// Test the unloading of plugin libs. Bug http://crbug.com/46526 showed that
-// if UnloadAllPlugins() simply iterates through the g_loaded_libs global
-// variable, we can get a crash if no plugin libs were marked as always loaded.
-class PluginLibTest : public NPAPI::PluginLib {
- public:
- PluginLibTest() : NPAPI::PluginLib(WebPluginInfo(), NULL) {
- }
- using NPAPI::PluginLib::Unload;
-};
-
-TEST(PluginLibLoading, UnloadAllPlugins) {
- // For the creation of the g_loaded_libs global variable.
- ASSERT_EQ(static_cast<PluginLibTest*>(NULL),
- PluginLibTest::CreatePluginLib(FilePath()));
-
- // Try with a single plugin lib.
- scoped_refptr<PluginLibTest> plugin_lib1(new PluginLibTest());
- NPAPI::PluginLib::UnloadAllPlugins();
-
- // Need to create it again, it should have been destroyed above.
- ASSERT_EQ(static_cast<PluginLibTest*>(NULL),
- PluginLibTest::CreatePluginLib(FilePath()));
-
- // Try with two plugin libs.
- plugin_lib1 = new PluginLibTest();
- scoped_refptr<PluginLibTest> plugin_lib2(new PluginLibTest());
- NPAPI::PluginLib::UnloadAllPlugins();
-
- // Need to create it again, it should have been destroyed above.
- ASSERT_EQ(static_cast<PluginLibTest*>(NULL),
- PluginLibTest::CreatePluginLib(FilePath()));
-
- // Now try to manually Unload one and then UnloadAll.
- plugin_lib1 = new PluginLibTest();
- plugin_lib2 = new PluginLibTest();
- plugin_lib1->Unload();
- NPAPI::PluginLib::UnloadAllPlugins();
-
- // Need to create it again, it should have been destroyed above.
- ASSERT_EQ(static_cast<PluginLibTest*>(NULL),
- PluginLibTest::CreatePluginLib(FilePath()));
-
- // Now try to manually Unload the only one and then UnloadAll.
- plugin_lib1 = new PluginLibTest();
- plugin_lib1->Unload();
- NPAPI::PluginLib::UnloadAllPlugins();
-}
-
-#if defined(OS_LINUX)
-
-// Test parsing a simple description: Real Audio.
-TEST(MIMEDescriptionParse, Simple) {
- std::vector<WebPluginMimeType> types;
- NPAPI::PluginLib::ParseMIMEDescription(
- "audio/x-pn-realaudio-plugin:rpm:RealAudio document;",
- &types);
- ASSERT_EQ(1U, types.size());
- const WebPluginMimeType& type = types[0];
- EXPECT_EQ("audio/x-pn-realaudio-plugin", type.mime_type);
- ASSERT_EQ(1U, type.file_extensions.size());
- EXPECT_EQ("rpm", type.file_extensions[0]);
- EXPECT_EQ(ASCIIToUTF16("RealAudio document"), type.description);
-}
-
-// Test parsing a multi-entry description: QuickTime as provided by Totem.
-TEST(MIMEDescriptionParse, Multi) {
- std::vector<WebPluginMimeType> types;
- NPAPI::PluginLib::ParseMIMEDescription(
- "video/quicktime:mov:QuickTime video;video/mp4:mp4:MPEG-4 "
- "video;image/x-macpaint:pntg:MacPaint Bitmap image;image/x"
- "-quicktime:pict, pict1, pict2:QuickTime image;video/x-m4v"
- ":m4v:MPEG-4 video;",
- &types);
-
- ASSERT_EQ(5U, types.size());
-
- // Check the x-quicktime one, since it looks tricky with spaces in the
- // extension list.
- const WebPluginMimeType& type = types[3];
- EXPECT_EQ("image/x-quicktime", type.mime_type);
- ASSERT_EQ(3U, type.file_extensions.size());
- EXPECT_EQ("pict2", type.file_extensions[2]);
- EXPECT_EQ(ASCIIToUTF16("QuickTime image"), type.description);
-}
-
-// Test parsing a Japanese description, since we got this wrong in the past.
-// This comes from loading Totem with LANG=ja_JP.UTF-8.
-TEST(MIMEDescriptionParse, JapaneseUTF8) {
- std::vector<WebPluginMimeType> types;
- NPAPI::PluginLib::ParseMIMEDescription(
- "audio/x-ogg:ogg:Ogg \xe3\x82\xaa\xe3\x83\xbc\xe3\x83\x87"
- "\xe3\x82\xa3\xe3\x83\xaa",
- &types);
-
- ASSERT_EQ(1U, types.size());
- // Check we got the right number of Unicode characters out of the parse.
- EXPECT_EQ(9U, types[0].description.size());
-}
-
-// Test that we handle corner cases gracefully.
-TEST(MIMEDescriptionParse, CornerCases) {
- std::vector<WebPluginMimeType> types;
- NPAPI::PluginLib::ParseMIMEDescription("mime/type:", &types);
- EXPECT_TRUE(types.empty());
-
- types.clear();
- NPAPI::PluginLib::ParseMIMEDescription("mime/type:ext1:", &types);
- ASSERT_EQ(1U, types.size());
- EXPECT_EQ("mime/type", types[0].mime_type);
- EXPECT_EQ(1U, types[0].file_extensions.size());
- EXPECT_EQ("ext1", types[0].file_extensions[0]);
- EXPECT_EQ(string16(), types[0].description);
-}
-
-// This Java plugin has embedded semicolons in the mime type.
-TEST(MIMEDescriptionParse, ComplicatedJava) {
- std::vector<WebPluginMimeType> types;
- NPAPI::PluginLib::ParseMIMEDescription(
- "application/x-java-vm:class,jar:IcedTea;application/x-java"
- "-applet:class,jar:IcedTea;application/x-java-applet;versio"
- "n=1.1:class,jar:IcedTea;application/x-java-applet;version="
- "1.1.1:class,jar:IcedTea;application/x-java-applet;version="
- "1.1.2:class,jar:IcedTea;application/x-java-applet;version="
- "1.1.3:class,jar:IcedTea;application/x-java-applet;version="
- "1.2:class,jar:IcedTea;application/x-java-applet;version=1."
- "2.1:class,jar:IcedTea;application/x-java-applet;version=1."
- "2.2:class,jar:IcedTea;application/x-java-applet;version=1."
- "3:class,jar:IcedTea;application/x-java-applet;version=1.3."
- "1:class,jar:IcedTea;application/x-java-applet;version=1.4:"
- "class,jar:IcedTea",
- &types);
-
- ASSERT_EQ(12U, types.size());
- for (size_t i = 0; i < types.size(); ++i)
- EXPECT_EQ(ASCIIToUTF16("IcedTea"), types[i].description);
-
- // Verify that the mime types with semis are coming through ok.
- EXPECT_TRUE(types[4].mime_type.find(';') != std::string::npos);
-}
-
-#endif // defined(OS_LINUX)
diff --git a/webkit/glue/plugins/plugin_lib_win.cc b/webkit/glue/plugins/plugin_lib_win.cc
deleted file mode 100644
index 382c2c8..0000000
--- a/webkit/glue/plugins/plugin_lib_win.cc
+++ /dev/null
@@ -1,46 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/plugin_lib.h"
-
-#include "base/file_version_info.h"
-#include "base/file_version_info_win.h"
-#include "base/logging.h"
-#include "base/path_service.h"
-#include "webkit/glue/plugins/plugin_constants_win.h"
-#include "webkit/glue/plugins/plugin_list.h"
-
-namespace NPAPI {
-
-bool PluginLib::ReadWebPluginInfo(const FilePath &filename,
- WebPluginInfo* info) {
- // On windows, the way we get the mime types for the library is
- // to check the version information in the DLL itself. This
- // will be a string of the format: <type1>|<type2>|<type3>|...
- // For example:
- // video/quicktime|audio/aiff|image/jpeg
- scoped_ptr<FileVersionInfo> version_info(
- FileVersionInfo::CreateFileVersionInfo(filename.value()));
- if (!version_info.get()) {
- LOG_IF(ERROR, PluginList::DebugPluginLoading())
- << "Could not get version info for plugin "
- << filename.value();
- return false;
- }
-
- FileVersionInfoWin* version_info_win =
- static_cast<FileVersionInfoWin*>(version_info.get());
- PluginVersionInfo pvi;
- pvi.mime_types = version_info_win->GetStringValue(L"MIMEType");
- pvi.file_extensions = version_info_win->GetStringValue(L"FileExtents");
- pvi.type_descriptions = version_info_win->GetStringValue(L"FileOpenName");
- pvi.product_name = version_info->product_name();
- pvi.file_description = version_info->file_description();
- pvi.file_version = version_info->file_version();
- pvi.path = filename;
-
- return PluginList::CreateWebPluginInfo(pvi, info);
-}
-
-} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_list.cc b/webkit/glue/plugins/plugin_list.cc
deleted file mode 100644
index 84736cb..0000000
--- a/webkit/glue/plugins/plugin_list.cc
+++ /dev/null
@@ -1,613 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/plugin_list.h"
-
-#include <algorithm>
-
-#include "base/command_line.h"
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/string_split.h"
-#include "base/string_util.h"
-#include "base/sys_string_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "googleurl/src/gurl.h"
-#include "net/base/mime_util.h"
-#include "webkit/glue/plugins/plugin_constants_win.h"
-#include "webkit/glue/plugins/plugin_lib.h"
-#include "webkit/glue/plugins/plugin_switches.h"
-#include "webkit/glue/webkit_glue.h"
-
-namespace NPAPI {
-
-base::LazyInstance<PluginList> g_singleton(base::LINKER_INITIALIZED);
-
-// static
-PluginList* PluginList::Singleton() {
- return g_singleton.Pointer();
-}
-
-// static
-bool PluginList::DebugPluginLoading() {
- return CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDebugPluginLoading);
-}
-
-bool PluginList::PluginsLoaded() {
- AutoLock lock(lock_);
- return plugins_loaded_;
-}
-
-void PluginList::RefreshPlugins() {
- AutoLock lock(lock_);
- plugins_need_refresh_ = true;
-}
-
-void PluginList::AddExtraPluginPath(const FilePath& plugin_path) {
- // Chrome OS only loads plugins from /opt/google/chrome/plugins.
-#if !defined(OS_CHROMEOS)
- AutoLock lock(lock_);
- extra_plugin_paths_.push_back(plugin_path);
-#endif
-}
-
-void PluginList::RemoveExtraPluginPath(const FilePath& plugin_path) {
- AutoLock lock(lock_);
- std::vector<FilePath>::iterator it =
- std::find(extra_plugin_paths_.begin(), extra_plugin_paths_.end(),
- plugin_path);
- if (it != extra_plugin_paths_.end())
- extra_plugin_paths_.erase(it);
-}
-
-void PluginList::AddExtraPluginDir(const FilePath& plugin_dir) {
- // Chrome OS only loads plugins from /opt/google/chrome/plugins.
-#if !defined(OS_CHROMEOS)
- AutoLock lock(lock_);
- extra_plugin_dirs_.push_back(plugin_dir);
-#endif
-}
-
-void PluginList::RegisterInternalPlugin(const PluginVersionInfo& info) {
- AutoLock lock(lock_);
- internal_plugins_.push_back(info);
-}
-
-void PluginList::UnregisterInternalPlugin(const FilePath& path) {
- AutoLock lock(lock_);
- for (size_t i = 0; i < internal_plugins_.size(); i++) {
- if (internal_plugins_[i].path == path) {
- internal_plugins_.erase(internal_plugins_.begin() + i);
- return;
- }
- }
- NOTREACHED();
-}
-
-bool PluginList::ReadPluginInfo(const FilePath& filename,
- WebPluginInfo* info,
- const PluginEntryPoints** entry_points) {
- {
- AutoLock lock(lock_);
- for (size_t i = 0; i < internal_plugins_.size(); ++i) {
- if (filename == internal_plugins_[i].path) {
- *entry_points = &internal_plugins_[i].entry_points;
- return CreateWebPluginInfo(internal_plugins_[i], info);
- }
- }
- }
-
- // Not an internal plugin.
- *entry_points = NULL;
-
- return PluginLib::ReadWebPluginInfo(filename, info);
-}
-
-bool PluginList::CreateWebPluginInfo(const PluginVersionInfo& pvi,
- WebPluginInfo* info) {
- std::vector<std::string> mime_types, file_extensions;
- std::vector<string16> descriptions;
- base::SplitString(WideToUTF8(pvi.mime_types), '|', &mime_types);
- base::SplitString(WideToUTF8(pvi.file_extensions), '|', &file_extensions);
- base::SplitString(WideToUTF16(pvi.type_descriptions), '|', &descriptions);
-
- info->mime_types.clear();
-
- if (mime_types.empty()) {
- LOG_IF(ERROR, PluginList::DebugPluginLoading())
- << "Plugin " << pvi.product_name << " has no MIME types, skipping";
- return false;
- }
-
- info->name = WideToUTF16(pvi.product_name);
- info->desc = WideToUTF16(pvi.file_description);
- info->version = WideToUTF16(pvi.file_version);
- info->path = pvi.path;
- info->enabled = true;
-
- for (size_t i = 0; i < mime_types.size(); ++i) {
- WebPluginMimeType mime_type;
- mime_type.mime_type = StringToLowerASCII(mime_types[i]);
- if (file_extensions.size() > i)
- base::SplitString(file_extensions[i], ',', &mime_type.file_extensions);
-
- if (descriptions.size() > i) {
- mime_type.description = descriptions[i];
-
- // On Windows, the description likely has a list of file extensions
- // embedded in it (e.g. "SurfWriter file (*.swr)"). Remove an extension
- // list from the description if it is present.
- size_t ext = mime_type.description.find(ASCIIToUTF16("(*"));
- if (ext != string16::npos) {
- if (ext > 1 && mime_type.description[ext -1] == ' ')
- ext--;
-
- mime_type.description.erase(ext);
- }
- }
-
- info->mime_types.push_back(mime_type);
- }
-
- return true;
-}
-
-PluginList::PluginList()
- : plugins_loaded_(false),
- plugins_need_refresh_(false),
- disable_outdated_plugins_(false) {
- PlatformInit();
-}
-
-bool PluginList::ShouldDisableGroup(const string16& group_name) {
- AutoLock lock(lock_);
- if (PluginGroup::IsPluginNameDisabledByPolicy(group_name)) {
- disabled_groups_.insert(group_name);
- return true;
- }
- return disabled_groups_.count(group_name) > 0;
-}
-
-void PluginList::LoadPlugins(bool refresh) {
- // Don't want to hold the lock while loading new plugins, so we don't block
- // other methods if they're called on other threads.
- std::vector<FilePath> extra_plugin_paths;
- std::vector<FilePath> extra_plugin_dirs;
- std::vector<PluginVersionInfo> internal_plugins;
- {
- AutoLock lock(lock_);
- if (plugins_loaded_ && !refresh && !plugins_need_refresh_)
- return;
-
- // Clear the refresh bit now, because it might get set again before we
- // reach the end of the method.
- plugins_need_refresh_ = false;
- extra_plugin_paths = extra_plugin_paths_;
- extra_plugin_dirs = extra_plugin_dirs_;
- internal_plugins = internal_plugins_;
- }
-
- std::vector<WebPluginInfo> new_plugins;
- std::set<FilePath> visited_plugins;
-
- std::vector<FilePath> directories_to_scan;
- GetPluginDirectories(&directories_to_scan);
-
- // Load internal plugins first so that, if both an internal plugin and a
- // "discovered" plugin want to handle the same type, the internal plugin
- // will have precedence.
- for (size_t i = 0; i < internal_plugins.size(); ++i) {
- if (internal_plugins[i].path.value() == kDefaultPluginLibraryName)
- continue;
- LoadPlugin(internal_plugins[i].path, &new_plugins);
- }
-
- for (size_t i = 0; i < extra_plugin_paths.size(); ++i) {
- const FilePath& path = extra_plugin_paths[i];
- if (visited_plugins.find(path) != visited_plugins.end())
- continue;
- LoadPlugin(path, &new_plugins);
- visited_plugins.insert(path);
- }
-
- for (size_t i = 0; i < extra_plugin_dirs.size(); ++i) {
- LoadPluginsFromDir(extra_plugin_dirs[i], &new_plugins, &visited_plugins);
- }
-
- for (size_t i = 0; i < directories_to_scan.size(); ++i) {
- LoadPluginsFromDir(directories_to_scan[i], &new_plugins, &visited_plugins);
- }
-
-#if defined OS_WIN
- LoadPluginsFromRegistry(&new_plugins, &visited_plugins);
-#endif
-
- // Load the default plugin last.
- if (webkit_glue::IsDefaultPluginEnabled())
- LoadPlugin(FilePath(kDefaultPluginLibraryName), &new_plugins);
-
- // Disable all of the plugins and plugin groups that are disabled by policy.
- // There's currenly a bug that makes it impossible to correctly re-enable
- // plugins or plugin-groups to their original, "pre-policy" state, so
- // plugins and groups are only changed to a more "safe" state after a policy
- // change, i.e. from enabled to disabled. See bug 54681.
- PluginMap plugin_groups;
- GetPluginGroups(&new_plugins, &plugin_groups);
- for (PluginMap::const_iterator it = plugin_groups.begin();
- it != plugin_groups.end(); ++it) {
- PluginGroup* group = it->second.get();
- string16 group_name = group->GetGroupName();
- if (ShouldDisableGroup(group_name)) {
- it->second->Enable(false);
- }
-
- if (disable_outdated_plugins_) {
- group->DisableOutdatedPlugins();
- if (!group->Enabled()) {
- AutoLock lock(lock_);
- disabled_groups_.insert(group_name);
- }
- }
- }
-
- // Only update the data now since loading plugins can take a while.
- AutoLock lock(lock_);
-
- // Mark disabled plugins as such.
- for (size_t i = 0; i < new_plugins.size(); ++i) {
- if (disabled_plugins_.count(new_plugins[i].path))
- new_plugins[i].enabled = false;
- }
-
- plugins_ = new_plugins;
- plugins_loaded_ = true;
-}
-
-void PluginList::LoadPlugin(const FilePath& path,
- std::vector<WebPluginInfo>* plugins) {
- LOG_IF(ERROR, PluginList::DebugPluginLoading())
- << "Loading plugin " << path.value();
-
- WebPluginInfo plugin_info;
- const PluginEntryPoints* entry_points;
-
- if (!ReadPluginInfo(path, &plugin_info, &entry_points))
- return;
-
- if (!ShouldLoadPlugin(plugin_info, plugins))
- return;
-
- if (path.value() != kDefaultPluginLibraryName
-#if defined(OS_WIN) && !defined(NDEBUG)
- && path.BaseName().value() != L"npspy.dll" // Make an exception for NPSPY
-#endif
- ) {
- for (size_t i = 0; i < plugin_info.mime_types.size(); ++i) {
- // TODO: don't load global handlers for now.
- // WebKit hands to the Plugin before it tries
- // to handle mimeTypes on its own.
- const std::string &mime_type = plugin_info.mime_types[i].mime_type;
- if (mime_type == "*" )
- return;
- }
- }
-
- plugins->push_back(plugin_info);
-}
-
-bool PluginList::SupportsType(const WebPluginInfo& info,
- const std::string &mime_type,
- bool allow_wildcard) {
- // Webkit will ask for a plugin to handle empty mime types.
- if (mime_type.empty())
- return false;
-
- for (size_t i = 0; i < info.mime_types.size(); ++i) {
- const WebPluginMimeType& mime_info = info.mime_types[i];
- if (net::MatchesMimeType(mime_info.mime_type, mime_type)) {
- if (!allow_wildcard && mime_info.mime_type == "*") {
- continue;
- }
- return true;
- }
- }
- return false;
-}
-
-bool PluginList::SupportsExtension(const WebPluginInfo& info,
- const std::string &extension,
- std::string* actual_mime_type) {
- for (size_t i = 0; i < info.mime_types.size(); ++i) {
- const WebPluginMimeType& mime_type = info.mime_types[i];
- for (size_t j = 0; j < mime_type.file_extensions.size(); ++j) {
- if (mime_type.file_extensions[j] == extension) {
- if (actual_mime_type)
- *actual_mime_type = mime_type.mime_type;
- return true;
- }
- }
- }
-
- return false;
-}
-
-
-void PluginList::GetPlugins(bool refresh, std::vector<WebPluginInfo>* plugins) {
- LoadPlugins(refresh);
-
- AutoLock lock(lock_);
- *plugins = plugins_;
-}
-
-void PluginList::GetEnabledPlugins(bool refresh,
- std::vector<WebPluginInfo>* plugins) {
- LoadPlugins(refresh);
-
- plugins->clear();
- AutoLock lock(lock_);
- for (std::vector<WebPluginInfo>::const_iterator it = plugins_.begin();
- it != plugins_.end();
- ++it) {
- if (it->enabled)
- plugins->push_back(*it);
- }
-}
-
-void PluginList::GetPluginInfoArray(const GURL& url,
- const std::string& mime_type,
- bool allow_wildcard,
- std::vector<WebPluginInfo>* info,
- std::vector<std::string>* actual_mime_types)
-{
- DCHECK(mime_type == StringToLowerASCII(mime_type));
- DCHECK(info);
-
- LoadPlugins(false);
- AutoLock lock(lock_);
- info->clear();
- if (actual_mime_types)
- actual_mime_types->clear();
-
- std::set<FilePath> visited_plugins;
-
- // Add in enabled plugins by mime type.
- WebPluginInfo default_plugin;
- for (size_t i = 0; i < plugins_.size(); ++i) {
- if (plugins_[i].enabled &&
- SupportsType(plugins_[i], mime_type, allow_wildcard)) {
- FilePath path = plugins_[i].path;
- if (path.value() != kDefaultPluginLibraryName &&
- visited_plugins.insert(path).second) {
- info->push_back(plugins_[i]);
- if (actual_mime_types)
- actual_mime_types->push_back(mime_type);
- }
- }
- }
-
- // Add in enabled plugins by url.
- std::string path = url.path();
- std::string::size_type last_dot = path.rfind('.');
- if (last_dot != std::string::npos) {
- std::string extension = StringToLowerASCII(std::string(path, last_dot+1));
- std::string actual_mime_type;
- for (size_t i = 0; i < plugins_.size(); ++i) {
- if (plugins_[i].enabled &&
- SupportsExtension(plugins_[i], extension, &actual_mime_type)) {
- FilePath path = plugins_[i].path;
- if (path.value() != kDefaultPluginLibraryName &&
- visited_plugins.insert(path).second) {
- info->push_back(plugins_[i]);
- if (actual_mime_types)
- actual_mime_types->push_back(actual_mime_type);
- }
- }
- }
- }
-
- // Add in disabled plugins by mime type.
- for (size_t i = 0; i < plugins_.size(); ++i) {
- if (!plugins_[i].enabled &&
- SupportsType(plugins_[i], mime_type, allow_wildcard)) {
- FilePath path = plugins_[i].path;
- if (path.value() != kDefaultPluginLibraryName &&
- visited_plugins.insert(path).second) {
- info->push_back(plugins_[i]);
- if (actual_mime_types)
- actual_mime_types->push_back(mime_type);
- }
- }
- }
-
- // Add the default plugin at the end if it supports the mime type given,
- // and the default plugin is enabled.
- if (!plugins_.empty() && webkit_glue::IsDefaultPluginEnabled()) {
- const WebPluginInfo& default_info = plugins_.back();
- if (SupportsType(default_info, mime_type, allow_wildcard)) {
- info->push_back(default_info);
- if (actual_mime_types)
- actual_mime_types->push_back(mime_type);
- }
- }
-}
-
-bool PluginList::GetPluginInfo(const GURL& url,
- const std::string& mime_type,
- bool allow_wildcard,
- WebPluginInfo* info,
- std::string* actual_mime_type) {
- DCHECK(info);
- std::vector<WebPluginInfo> info_list;
-
- // GetPluginInfoArray has slightly less work to do if we can pass
- // NULL for the mime type list...
- if (actual_mime_type) {
- std::vector<std::string> mime_type_list;
- GetPluginInfoArray(
- url, mime_type, allow_wildcard, &info_list, &mime_type_list);
- if (!info_list.empty()) {
- *info = info_list[0];
- *actual_mime_type = mime_type_list[0];
- return true;
- }
- } else {
- GetPluginInfoArray(url, mime_type, allow_wildcard, &info_list, NULL);
- if (!info_list.empty()) {
- *info = info_list[0];
- return true;
- }
- }
- return false;
-}
-
-bool PluginList::GetPluginInfoByPath(const FilePath& plugin_path,
- WebPluginInfo* info) {
- LoadPlugins(false);
- AutoLock lock(lock_);
- for (size_t i = 0; i < plugins_.size(); ++i) {
- if (plugins_[i].path == plugin_path) {
- *info = plugins_[i];
- return true;
- }
- }
-
- return false;
-}
-
-void PluginList::GetPluginGroups(bool load_if_necessary,
- PluginMap* plugin_groups) {
- if (load_if_necessary)
- LoadPlugins(false);
-
- AutoLock lock(lock_);
- GetPluginGroups(&plugins_, plugin_groups);
-}
-
-// static
-void PluginList::GetPluginGroups(const std::vector<WebPluginInfo>* plugins,
- PluginMap* plugin_groups) {
- plugin_groups->clear();
- // We first search for an existing group that matches our name,
- // and only create a new group if we can't find any.
- for (size_t i = 0; i < plugins->size(); ++i) {
- const WebPluginInfo& web_plugin = (*plugins)[i];
- PluginGroup* group = PluginGroup::FindGroupMatchingPlugin(
- *plugin_groups, web_plugin);
- if (!group) {
- group = PluginGroup::CopyOrCreatePluginGroup(web_plugin);
- std::string identifier = group->identifier();
- // If the identifier is not unique, use the full path. This means that we
- // probably won't be able to search for this group by identifier, but at
- // least it's going to be in the set of plugin groups, and if there
- // is already a plug-in with the same filename, it's probably going to
- // handle the same MIME types (and it has a higher priority), so this one
- // is not going to run anyway.
- if (plugin_groups->find(identifier) != plugin_groups->end())
-#if defined(OS_POSIX)
- identifier = web_plugin.path.value();
-#elif defined(OS_WIN)
- identifier = base::SysWideToUTF8(web_plugin.path.value());
-#endif
- DCHECK(plugin_groups->find(identifier) == plugin_groups->end());
- (*plugin_groups)[identifier] = linked_ptr<PluginGroup>(group);
- }
- group->AddPlugin(web_plugin, i);
- }
-}
-
-bool PluginList::EnablePlugin(const FilePath& filename) {
- AutoLock lock(lock_);
-
- bool did_enable = false;
-
- std::set<FilePath>::iterator entry = disabled_plugins_.find(filename);
- if (entry == disabled_plugins_.end())
- return did_enable; // Early exit if plugin not in disabled list.
-
- disabled_plugins_.erase(entry); // Remove from disabled list.
-
- // Set enabled flags if necessary.
- for (std::vector<WebPluginInfo>::iterator it = plugins_.begin();
- it != plugins_.end();
- ++it) {
- if (it->path == filename) {
- DCHECK(!it->enabled); // Should have been disabled.
- it->enabled = true;
- did_enable = true;
- }
- }
-
- return did_enable;
-}
-
-bool PluginList::DisablePlugin(const FilePath& filename) {
- AutoLock lock(lock_);
-
- bool did_disable = false;
-
- if (disabled_plugins_.find(filename) != disabled_plugins_.end())
- return did_disable; // Early exit if plugin already in disabled list.
-
- disabled_plugins_.insert(filename); // Add to disabled list.
-
- // Unset enabled flags if necessary.
- for (std::vector<WebPluginInfo>::iterator it = plugins_.begin();
- it != plugins_.end();
- ++it) {
- if (it->path == filename) {
- DCHECK(it->enabled); // Should have been enabled.
- it->enabled = false;
- did_disable = true;
- }
- }
-
- return did_disable;
-}
-
-bool PluginList::EnableGroup(bool enable, const string16& group_name) {
- bool did_change = false;
- {
- AutoLock lock(lock_);
-
- std::set<string16>::iterator entry = disabled_groups_.find(group_name);
- if (enable) {
- if (entry == disabled_groups_.end())
- return did_change; // Early exit if group not in disabled list.
- disabled_groups_.erase(entry); // Remove from disabled list.
- } else {
- if (entry != disabled_groups_.end())
- return did_change; // Early exit if group already in disabled list.
- disabled_groups_.insert(group_name);
- }
- }
-
- PluginMap plugin_groups;
- GetPluginGroups(false, &plugin_groups);
- for (PluginMap::const_iterator it = plugin_groups.begin();
- it != plugin_groups.end(); ++it) {
- if (it->second->GetGroupName() == group_name) {
- if (it->second->Enabled() != enable) {
- it->second->Enable(enable);
- did_change = true;
- break;
- }
- }
- }
-
- return did_change;
-}
-
-void PluginList::DisableOutdatedPluginGroups() {
- disable_outdated_plugins_ = true;
-}
-
-PluginList::~PluginList() {
-}
-
-void PluginList::Shutdown() {
- // TODO
-}
-
-} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_list.h b/webkit/glue/plugins/plugin_list.h
index 101e6b7..111e8fa 100644
--- a/webkit/glue/plugins/plugin_list.h
+++ b/webkit/glue/plugins/plugin_list.h
@@ -5,304 +5,26 @@
#ifndef WEBKIT_GLUE_PLUGINS_PLUGIN_LIST_H_
#define WEBKIT_GLUE_PLUGINS_PLUGIN_LIST_H_
-#include <map>
-#include <set>
-#include <string>
-#include <vector>
-#include <set>
+// This file is here to keep NativeClient compiling. PluginList was moved to
+// webkit/plugins/npapi and into the webkit::npapi namespace. Native Client
+// depends on this old location & namespace, so we provide just enough
+// definitions here to keep it compiling until it can be updated to use the
+// new location & namespace.
+//
+// TODO(brettw) remove this flie when NaCl is updated.
-#include "base/basictypes.h"
-#include "base/file_path.h"
-#include "base/linked_ptr.h"
-#include "base/lock.h"
-#include "third_party/npapi/bindings/nphostapi.h"
-#include "webkit/glue/plugins/plugin_group.h"
-#include "webkit/glue/plugins/webplugininfo.h"
-
-class GURL;
-
-namespace base {
-
-template <typename T>
-struct DefaultLazyInstanceTraits;
-
-} // namespace base
+#include "webkit/plugins/npapi/plugin_list.h"
namespace NPAPI {
-#define kDefaultPluginLibraryName FILE_PATH_LITERAL("default_plugin")
-#define kGearsPluginLibraryName FILE_PATH_LITERAL("gears")
+typedef webkit::npapi::PluginEntryPoints PluginEntryPoints;
+typedef webkit::npapi::PluginVersionInfo PluginVersionInfo;
-class PluginInstance;
-
-// This struct holds entry points into a plugin. The entry points are
-// slightly different between Win/Mac and Unixes.
-struct PluginEntryPoints {
-#if !defined(OS_POSIX) || defined(OS_MACOSX)
- NP_GetEntryPointsFunc np_getentrypoints;
-#endif
- NP_InitializeFunc np_initialize;
- NP_ShutdownFunc np_shutdown;
-};
-
-// This struct fully describes a plugin. For external plugins, it's read in from
-// the version info of the dll; For internal plugins, it's predefined and
-// includes addresses of entry functions. (Yes, it's Win32 NPAPI-centric, but
-// it'll do for holding descriptions of internal plugins cross-platform.)
-struct PluginVersionInfo {
- FilePath path;
- // Info about the plugin itself.
- std::wstring product_name;
- std::wstring file_description;
- std::wstring file_version;
- // Info about the data types that the plugin supports.
- std::wstring mime_types;
- std::wstring file_extensions;
- std::wstring type_descriptions;
- // Entry points for internal plugins. Pointers are NULL for external plugins.
- PluginEntryPoints entry_points;
-};
-
-// The PluginList is responsible for loading our NPAPI based plugins. It does
-// so in whatever manner is appropriate for the platform. On Windows, it loads
-// plugins from a known directory by looking for DLLs which start with "NP",
-// and checking to see if they are valid NPAPI libraries. On the Mac, it walks
-// the machine-wide and user plugin directories and loads anything that has
-// the correct types. On Linux, it walks the plugin directories as well
-// (e.g. /usr/lib/browser-plugins/).
-// This object is thread safe.
class PluginList {
public:
- // Gets the one instance of the PluginList.
- static PluginList* Singleton();
-
- // Returns true if we're in debug-plugin-loading mode. This is controlled
- // by a command line switch.
- static bool DebugPluginLoading();
-
- // Returns true iff the plugin list has been loaded already.
- bool PluginsLoaded();
-
- // Cause the plugin list to refresh next time they are accessed, regardless
- // of whether they are already loaded.
- void RefreshPlugins();
-
- // Add/Remove an extra plugin to load when we actually do the loading. Must
- // be called before the plugins have been loaded.
- void AddExtraPluginPath(const FilePath& plugin_path);
- void RemoveExtraPluginPath(const FilePath& plugin_path);
-
- // Same as above, but specifies a directory in which to search for plugins.
- void AddExtraPluginDir(const FilePath& plugin_dir);
-
- // Register an internal plugin with the specified plugin information and
- // function pointers. An internal plugin must be registered before it can
- // be loaded using PluginList::LoadPlugin().
- void RegisterInternalPlugin(const PluginVersionInfo& info);
-
- // Removes a specified internal plugin from the list. The search will match
- // on the path from the version info previously registered.
- //
- // This is generally only necessary for tests.
- void UnregisterInternalPlugin(const FilePath& path);
-
- // Creates a WebPluginInfo structure given a plugin's path. On success
- // returns true, with the information being put into "info". If it's an
- // internal plugin, "entry_points" is filled in as well with a
- // internally-owned PluginEntryPoints pointer.
- // Returns false if the library couldn't be found, or if it's not a plugin.
- bool ReadPluginInfo(const FilePath& filename,
- WebPluginInfo* info,
- const PluginEntryPoints** entry_points);
-
- // Populate a WebPluginInfo from a PluginVersionInfo.
- static bool CreateWebPluginInfo(const PluginVersionInfo& pvi,
- WebPluginInfo* info);
-
- // Shutdown all plugins. Should be called at process teardown.
- void Shutdown();
-
- // Get all the plugins.
- void GetPlugins(bool refresh, std::vector<WebPluginInfo>* plugins);
-
- // Get all the enabled plugins.
- void GetEnabledPlugins(bool refresh, std::vector<WebPluginInfo>* plugins);
-
- // Returns a list in |info| containing plugins that are found for
- // the given url and mime type (including disabled plugins, for
- // which |info->enabled| is false). The mime type which corresponds
- // to the URL is optionally returned back in |actual_mime_types| (if
- // it is non-NULL), one for each of the plugin info objects found.
- // The |allow_wildcard| parameter controls whether this function
- // returns plugins which support wildcard mime types (* as the mime
- // type). The |info| parameter is required to be non-NULL. The
- // list is in order of "most desirable" to "least desirable",
- // meaning that the default plugin is at the end of the list.
- void GetPluginInfoArray(const GURL& url,
- const std::string& mime_type,
- bool allow_wildcard,
- std::vector<WebPluginInfo>* info,
- std::vector<std::string>* actual_mime_types);
-
- // Returns the first item from the list returned in GetPluginInfo in |info|.
- // Returns true if it found a match. |actual_mime_type| may be NULL.
- bool GetPluginInfo(const GURL& url,
- const std::string& mime_type,
- bool allow_wildcard,
- WebPluginInfo* info,
- std::string* actual_mime_type);
-
- // Get plugin info by plugin path (including disabled plugins). Returns true
- // if the plugin is found and WebPluginInfo has been filled in |info|.
- bool GetPluginInfoByPath(const FilePath& plugin_path,
- WebPluginInfo* info);
-
- typedef std::map<std::string, linked_ptr<PluginGroup> > PluginMap;
-
- // Fill the map from identifier to plugin group for all plugin groups. If
- // |load_if_necessary| is set, the plugins will be loaded if they haven't
- // already been loaded, or if Refresh() has been called in the meantime;
- // otherwise a possibly empty or stale list may be returned.
- void GetPluginGroups(bool load_if_necessary, PluginMap* plugin_groups);
-
- // Load a specific plugin with full path.
- void LoadPlugin(const FilePath& filename,
- std::vector<WebPluginInfo>* plugins);
-
- // Enable a specific plugin, specified by path. Returns |true| iff a plugin
- // currently in the plugin list was actually enabled as a result; regardless
- // of return value, if a plugin is found in the future with the given name, it
- // will be enabled. Note that plugins are enabled by default as far as
- // |PluginList| is concerned.
- bool EnablePlugin(const FilePath& filename);
-
- // Disable a specific plugin, specified by path. Returns |true| iff a plugin
- // currently in the plugin list was actually disabled as a result; regardless
- // of return value, if a plugin is found in the future with the given name, it
- // will be disabled.
- bool DisablePlugin(const FilePath& filename);
-
- // Enable/disable a plugin group, specified by group_name. Returns |true| iff
- // a plugin currently in the plugin list was actually enabled/disabled as a
- // result; regardless of return value, if a plugin is found in the future with
- // the given name, it will be enabled/disabled. Note that plugins are enabled
- // by default as far as |PluginList| is concerned.
- bool EnableGroup(bool enable, const string16& name);
-
- // Disable all plugins groups that are known to be outdated, according to
- // the information hardcoded in PluginGroup, to make sure that they can't
- // be loaded on a web page and instead show a UI to update to the latest
- // version.
- void DisableOutdatedPluginGroups();
-
- ~PluginList();
-
- private:
- // Constructors are private for singletons
- PluginList();
-
- // Load all plugins from the default plugins directory
- void LoadPlugins(bool refresh);
-
- // Load all plugins from a specific directory.
- // |plugins| is updated with loaded plugin information.
- // |visited_plugins| is updated with paths to all plugins that were considered
- // (including those we didn't load)
- void LoadPluginsFromDir(const FilePath& path,
- std::vector<WebPluginInfo>* plugins,
- std::set<FilePath>* visited_plugins);
-
- // Returns true if we should load the given plugin, or false otherwise.
- // plugins is the list of plugins we have crawled in the current plugin
- // loading run.
- bool ShouldLoadPlugin(const WebPluginInfo& info,
- std::vector<WebPluginInfo>* plugins);
-
- // Return whether a plug-in group with the given name should be disabled,
- // either because it already is on the list of disabled groups, or because it
- // is blacklisted by a policy. In the latter case, add the plugin group to the
- // list of disabled groups as well.
- bool ShouldDisableGroup(const string16& group_name);
-
- // Like GetPluginGroups above, but works on a given vector of plugins.
- static void GetPluginGroups(const std::vector<WebPluginInfo>* plugins,
- PluginMap* plugin_groups);
-
- // Returns true if the given WebPluginInfo supports "mime-type".
- // mime_type should be all lower case.
- static bool SupportsType(const WebPluginInfo& info,
- const std::string &mime_type,
- bool allow_wildcard);
-
- // Returns true if the given WebPluginInfo supports a given file extension.
- // extension should be all lower case.
- // If mime_type is not NULL, it will be set to the mime type if found.
- // The mime type which corresponds to the extension is optionally returned
- // back.
- static bool SupportsExtension(const WebPluginInfo& info,
- const std::string &extension,
- std::string* actual_mime_type);
-
- //
- // Platform functions
- //
-
- // Do any initialization.
- void PlatformInit();
-
- // Get the ordered list of directories from which to load plugins
- void GetPluginDirectories(std::vector<FilePath>* plugin_dirs);
-
- //
- // Command-line switches
- //
-
-#if defined(OS_WIN)
- // true if we shouldn't load the new WMP plugin.
- bool dont_load_new_wmp_;
-
- // Loads plugins registered under HKCU\Software\MozillaPlugins and
- // HKLM\Software\MozillaPlugins.
- void LoadPluginsFromRegistry(std::vector<WebPluginInfo>* plugins,
- std::set<FilePath>* visited_plugins);
-#endif
-
- //
- // Internals
- //
-
- bool plugins_loaded_;
-
- // If true, we reload plugins even if they've been loaded already.
- bool plugins_need_refresh_;
-
- // Contains information about the available plugins.
- std::vector<WebPluginInfo> plugins_;
-
- // Extra plugin paths that we want to search when loading.
- std::vector<FilePath> extra_plugin_paths_;
-
- // Extra plugin directories that we want to search when loading.
- std::vector<FilePath> extra_plugin_dirs_;
-
- // Holds information about internal plugins.
- std::vector<PluginVersionInfo> internal_plugins_;
-
- // Path names of plugins to disable (the default is to enable them all).
- std::set<FilePath> disabled_plugins_;
-
- // Group names disable (the default is to enable them all).
- std::set<string16> disabled_groups_;
-
- bool disable_outdated_plugins_;
-
- // Need synchronization for the above members since this object can be
- // accessed on multiple threads.
- Lock lock_;
-
- friend struct base::DefaultLazyInstanceTraits<PluginList>;
-
- DISALLOW_COPY_AND_ASSIGN(PluginList);
+ static inline webkit::npapi::PluginList* Singleton() {
+ return webkit::npapi::PluginList::Singleton();
+ }
};
} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_list_mac.mm b/webkit/glue/plugins/plugin_list_mac.mm
deleted file mode 100644
index 6e5019d..0000000
--- a/webkit/glue/plugins/plugin_list_mac.mm
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright (c) 2006-2009 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 "webkit/glue/plugins/plugin_list.h"
-
-#import <Foundation/Foundation.h>
-
-#include "base/file_util.h"
-#include "base/mac_util.h"
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-#include "webkit/glue/plugins/plugin_lib.h"
-
-namespace {
-
-void GetPluginCommonDirectory(std::vector<FilePath>* plugin_dirs,
- bool user) {
- // Note that there are no NSSearchPathDirectory constants for these
- // directories so we can't use Cocoa's NSSearchPathForDirectoriesInDomains().
- // Interestingly, Safari hard-codes the location (see
- // WebKit/WebKit/mac/Plugins/WebPluginDatabase.mm's +_defaultPlugInPaths).
- FSRef ref;
- OSErr err = FSFindFolder(user ? kUserDomain : kLocalDomain,
- kInternetPlugInFolderType, false, &ref);
-
- if (err)
- return;
-
- plugin_dirs->push_back(FilePath(mac_util::PathFromFSRef(ref)));
-}
-
-// Returns true if the plugin should be prevented from loading.
-bool IsBlacklistedPlugin(const WebPluginInfo& info) {
- // We blacklist Gears by included MIME type, since that is more stable than
- // its name. Be careful about adding any more plugins to this list though,
- // since it's easy to accidentally blacklist plugins that support lots of
- // MIME types.
- for (std::vector<WebPluginMimeType>::const_iterator i =
- info.mime_types.begin(); i != info.mime_types.end(); ++i) {
- // The Gears plugin is Safari-specific, so don't load it.
- if (i->mime_type == "application/x-googlegears")
- return true;
- }
-
- return false;
-}
-
-} // namespace
-
-namespace NPAPI
-{
-
-void PluginList::PlatformInit() {
-}
-
-void PluginList::GetPluginDirectories(std::vector<FilePath>* plugin_dirs) {
- // Load from the user's area
- GetPluginCommonDirectory(plugin_dirs, true);
-
- // Load from the machine-wide area
- GetPluginCommonDirectory(plugin_dirs, false);
-}
-
-void PluginList::LoadPluginsFromDir(const FilePath &path,
- std::vector<WebPluginInfo>* plugins,
- std::set<FilePath>* visited_plugins) {
- file_util::FileEnumerator enumerator(path,
- false, // not recursive
- file_util::FileEnumerator::DIRECTORIES);
- for (FilePath path = enumerator.Next(); !path.value().empty();
- path = enumerator.Next()) {
- LoadPlugin(path, plugins);
- visited_plugins->insert(path);
- }
-}
-
-bool PluginList::ShouldLoadPlugin(const WebPluginInfo& info,
- std::vector<WebPluginInfo>* plugins) {
- if (IsBlacklistedPlugin(info))
- return false;
-
- // Flip4Mac has a reproducible hang during a synchronous call from the render
- // with certain content types (as well as a common crash). Disable by default
- // to minimize those issues, but don't blacklist it so that users can choose
- // to enable it.
- if (StartsWith(info.name, ASCIIToUTF16("Flip4Mac Windows Media Plugin"),
- false))
- DisablePlugin(info.path);
-
- // Hierarchy check
- // (we're loading plugins hierarchically from Library folders, so plugins we
- // encounter earlier must override plugins we encounter later)
- for (size_t i = 0; i < plugins->size(); ++i) {
- if ((*plugins)[i].path.BaseName() == info.path.BaseName()) {
- return false; // We already have a loaded plugin higher in the hierarchy.
- }
- }
-
- return true;
-}
-
-} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_list_posix.cc b/webkit/glue/plugins/plugin_list_posix.cc
deleted file mode 100644
index 654c0c5..0000000
--- a/webkit/glue/plugins/plugin_list_posix.cc
+++ /dev/null
@@ -1,270 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/plugin_list.h"
-
-#include "base/file_util.h"
-#include "base/path_service.h"
-#include "base/sha1.h"
-#include "base/string_split.h"
-#include "base/string_util.h"
-#include "build/build_config.h"
-
-namespace {
-
-// We build up a list of files and mtimes so we can sort them.
-typedef std::pair<FilePath, base::Time> FileAndTime;
-typedef std::vector<FileAndTime> FileTimeList;
-
-// Comparator used to sort by descending mtime then ascending filename.
-bool CompareTime(const FileAndTime& a, const FileAndTime& b) {
- if (a.second == b.second) {
- // Fall back on filename sorting, just to make the predicate valid.
- return a.first < b.first;
- }
-
- // Sort by mtime, descending.
- return a.second > b.second;
-}
-
-// Return true if |path| matches a known (file size, sha1sum) pair.
-// The use of the file size is an optimization so we don't have to read in
-// the entire file unless we have to.
-bool IsBlacklistedBySha1sum(const FilePath& path) {
- const struct BadEntry {
- int64 size;
- std::string sha1;
- } bad_entries[] = {
- // Flash 9 r31 - http://crbug.com/29237
- { 7040080, "fa5803061125ca47846713b34a26a42f1f1e98bb" },
- // Flash 9 r48 - http://crbug.com/29237
- { 7040036, "0c4b3768a6d4bfba003088e4b9090d381de1af2b" },
- };
-
- int64 size;
- if (!file_util::GetFileSize(path, &size))
- return false;
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(bad_entries); i++) {
- if (bad_entries[i].size != size)
- continue;
-
- std::string file_content;
- if (!file_util::ReadFileToString(path, &file_content))
- continue;
- std::string sha1 = base::SHA1HashString(file_content);
- std::string sha1_readable;
- for (size_t j = 0; j < sha1.size(); j++)
- base::StringAppendF(&sha1_readable, "%02x", sha1[j] & 0xFF);
- if (bad_entries[i].sha1 == sha1_readable)
- return true;
- }
- return false;
-}
-
-// Some plugins are shells around other plugins; we prefer to use the
-// real plugin directly, if it's available. This function returns
-// true if we should prefer other plugins over this one. We'll still
-// use a "undesirable" plugin if no other option is available.
-bool IsUndesirablePlugin(const WebPluginInfo& info) {
- std::string filename = info.path.BaseName().value();
- const char* kUndesiredPlugins[] = {
- "npcxoffice", // Crossover
- "npwrapper", // nspluginwrapper
- };
- for (size_t i = 0; i < arraysize(kUndesiredPlugins); i++) {
- if (filename.find(kUndesiredPlugins[i]) != std::string::npos) {
- return true;
- }
- }
- return false;
-}
-
-// Return true if we shouldn't load a plugin at all.
-// This is an ugly hack to blacklist Adobe Acrobat due to not supporting
-// its Xt-based mainloop.
-// http://code.google.com/p/chromium/issues/detail?id=38229
-// The gecko-mediaplayer plugins also crashes the entire browser sometimes.
-// http://code.google.com/p/chromium/issues/detail?id=24507
-bool IsBlacklistedPlugin(const FilePath& path) {
- const char* kBlackListedPlugins[] = {
- "nppdf.so", // Adobe PDF
- "gecko-mediaplayer", // Gecko Media Player
- };
- std::string filename = path.BaseName().value();
- for (size_t i = 0; i < arraysize(kBlackListedPlugins); i++) {
- if (filename.find(kBlackListedPlugins[i]) != std::string::npos) {
- return true;
- }
- }
- return IsBlacklistedBySha1sum(path);
-}
-
-} // anonymous namespace
-
-namespace NPAPI {
-
-void PluginList::PlatformInit() {
-}
-
-void PluginList::GetPluginDirectories(std::vector<FilePath>* plugin_dirs) {
- // See http://groups.google.com/group/chromium-dev/browse_thread/thread/7a70e5fcbac786a9
- // for discussion.
- // We first consult Chrome-specific dirs, then fall back on the logic
- // Mozilla uses.
-
- // Note: "extra" plugin dirs, including the Plugins subdirectory of
- // your Chrome config, are examined before these. See the logic
- // related to extra_plugin_dirs in plugin_list.cc.
-
- // The Chrome binary dir + "plugins/".
- FilePath dir;
- PathService::Get(base::DIR_EXE, &dir);
- plugin_dirs->push_back(dir.Append("plugins"));
-
- // Chrome OS only loads plugins from /opt/google/chrome/plugins.
-#if !defined(OS_CHROMEOS)
- // Mozilla code to reference:
- // http://mxr.mozilla.org/firefox/ident?i=NS_APP_PLUGINS_DIR_LIST
- // and tens of accompanying files (mxr is very helpful).
- // This code carefully matches their behavior for compat reasons.
-
- // 1) MOZ_PLUGIN_PATH env variable.
- const char* moz_plugin_path = getenv("MOZ_PLUGIN_PATH");
- if (moz_plugin_path) {
- std::vector<std::string> paths;
- base::SplitString(moz_plugin_path, ':', &paths);
- for (size_t i = 0; i < paths.size(); ++i)
- plugin_dirs->push_back(FilePath(paths[i]));
- }
-
- // 2) NS_USER_PLUGINS_DIR: ~/.mozilla/plugins.
- // This is a de-facto standard, so even though we're not Mozilla, let's
- // look in there too.
- FilePath home = file_util::GetHomeDir();
- if (!home.empty())
- plugin_dirs->push_back(home.Append(".mozilla/plugins"));
-
- // 3) NS_SYSTEM_PLUGINS_DIR:
- // This varies across different browsers and versions, so check 'em all.
- plugin_dirs->push_back(FilePath("/usr/lib/browser-plugins"));
- plugin_dirs->push_back(FilePath("/usr/lib/mozilla/plugins"));
- plugin_dirs->push_back(FilePath("/usr/lib/firefox/plugins"));
- plugin_dirs->push_back(FilePath("/usr/lib/xulrunner-addons/plugins"));
-
-#if defined(ARCH_CPU_64_BITS)
- // On my Ubuntu system, /usr/lib64 is a symlink to /usr/lib.
- // But a user reported on their Fedora system they are separate.
- plugin_dirs->push_back(FilePath("/usr/lib64/browser-plugins"));
- plugin_dirs->push_back(FilePath("/usr/lib64/mozilla/plugins"));
- plugin_dirs->push_back(FilePath("/usr/lib64/firefox/plugins"));
- plugin_dirs->push_back(FilePath("/usr/lib64/xulrunner-addons/plugins"));
-#endif // defined(ARCH_CPU_64_BITS)
-#endif // !defined(OS_CHROMEOS)
-}
-
-void PluginList::LoadPluginsFromDir(const FilePath& dir_path,
- std::vector<WebPluginInfo>* plugins,
- std::set<FilePath>* visited_plugins) {
- // See ScanPluginsDirectory near
- // http://mxr.mozilla.org/firefox/source/modules/plugin/base/src/nsPluginHostImpl.cpp#5052
-
- // Construct and stat a list of all filenames under consideration, for
- // later sorting by mtime.
- FileTimeList files;
- file_util::FileEnumerator enumerator(dir_path,
- false, // not recursive
- file_util::FileEnumerator::FILES);
- for (FilePath path = enumerator.Next(); !path.value().empty();
- path = enumerator.Next()) {
- // Skip over Mozilla .xpt files.
- if (path.MatchesExtension(FILE_PATH_LITERAL(".xpt")))
- continue;
-
- // Java doesn't like being loaded through a symlink, since it uses
- // its path to find dependent data files.
- // file_util::AbsolutePath calls through to realpath(), which resolves
- // symlinks.
- FilePath orig_path = path;
- file_util::AbsolutePath(&path);
- LOG_IF(ERROR, PluginList::DebugPluginLoading())
- << "Resolved " << orig_path.value() << " -> " << path.value();
-
- if (visited_plugins->find(path) != visited_plugins->end()) {
- LOG_IF(ERROR, PluginList::DebugPluginLoading())
- << "Skipping duplicate instance of " << path.value();
- continue;
- }
- visited_plugins->insert(path);
-
- if (IsBlacklistedPlugin(path)) {
- LOG_IF(ERROR, PluginList::DebugPluginLoading())
- << "Skipping blacklisted plugin " << path.value();
- continue;
- }
-
- // Flash stops working if the containing directory involves 'netscape'.
- // No joke. So use the other path if it's better.
- static const char kFlashPlayerFilename[] = "libflashplayer.so";
- static const char kNetscapeInPath[] = "/netscape/";
- if (path.BaseName().value() == kFlashPlayerFilename &&
- path.value().find(kNetscapeInPath) != std::string::npos) {
- if (orig_path.value().find(kNetscapeInPath) == std::string::npos) {
- // Go back to the old path.
- path = orig_path;
- } else {
- LOG_IF(ERROR, PluginList::DebugPluginLoading())
- << "Flash misbehaves when used from a directory containing "
- << kNetscapeInPath << ", so skipping " << orig_path.value();
- continue;
- }
- }
-
- // Get mtime.
- base::PlatformFileInfo info;
- if (!file_util::GetFileInfo(path, &info))
- continue;
-
- files.push_back(std::make_pair(path, info.last_modified));
- }
-
- // Sort the file list by time (and filename).
- std::sort(files.begin(), files.end(), CompareTime);
-
- // Load the files in order.
- for (FileTimeList::const_iterator i = files.begin(); i != files.end(); ++i) {
- LoadPlugin(i->first, plugins);
- }
-}
-
-bool PluginList::ShouldLoadPlugin(const WebPluginInfo& info,
- std::vector<WebPluginInfo>* plugins) {
- LOG_IF(ERROR, PluginList::DebugPluginLoading())
- << "Considering " << info.path.value() << " (" << info.name << ")";
-
- if (IsUndesirablePlugin(info)) {
- LOG_IF(ERROR, PluginList::DebugPluginLoading())
- << info.path.value() << " is undesirable.";
-
- // See if we have a better version of this plugin.
- for (size_t i = 0; i < plugins->size(); ++i) {
- if (plugins->at(i).name == info.name &&
- !IsUndesirablePlugin(plugins->at(i))) {
- // Skip the current undesirable one so we can use the better one
- // we just found.
- LOG_IF(ERROR, PluginList::DebugPluginLoading())
- << "Skipping " << info.path.value() << ", preferring "
- << plugins->at(i).path.value();
- return false;
- }
- }
- }
-
- // TODO(evanm): prefer the newest version of flash, etc. here?
-
- VLOG_IF(1, PluginList::DebugPluginLoading()) << "Using " << info.path.value();
-
- return true;
-}
-
-} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_list_win.cc b/webkit/glue/plugins/plugin_list_win.cc
deleted file mode 100644
index 4869262..0000000
--- a/webkit/glue/plugins/plugin_list_win.cc
+++ /dev/null
@@ -1,410 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/plugin_list.h"
-
-#include <tchar.h>
-
-#include <set>
-
-#include "base/basictypes.h"
-#include "base/command_line.h"
-#include "base/file_util.h"
-#include "base/path_service.h"
-#include "base/scoped_ptr.h"
-#include "base/string_number_conversions.h"
-#include "base/string_split.h"
-#include "base/string_util.h"
-#include "base/win/registry.h"
-#include "webkit/glue/plugins/plugin_constants_win.h"
-#include "webkit/glue/plugins/plugin_lib.h"
-#include "webkit/glue/webkit_glue.h"
-
-namespace {
-
-const TCHAR kRegistryApps[] =
- _T("Software\\Microsoft\\Windows\\CurrentVersion\\App Paths");
-const TCHAR kRegistryFirefox[] = _T("firefox.exe");
-const TCHAR kRegistryAcrobat[] = _T("Acrobat.exe");
-const TCHAR kRegistryAcrobatReader[] = _T("AcroRd32.exe");
-const TCHAR kRegistryWindowsMedia[] = _T("wmplayer.exe");
-const TCHAR kRegistryQuickTime[] = _T("QuickTimePlayer.exe");
-const TCHAR kRegistryPath[] = _T("Path");
-const TCHAR kRegistryFirefoxInstalled[] =
- _T("SOFTWARE\\Mozilla\\Mozilla Firefox");
-const TCHAR kRegistryJava[] =
- _T("Software\\JavaSoft\\Java Runtime Environment");
-const TCHAR kRegistryBrowserJavaVersion[] = _T("BrowserJavaVersion");
-const TCHAR kRegistryCurrentJavaVersion[] = _T("CurrentVersion");
-const TCHAR kRegistryJavaHome[] = _T("JavaHome");
-const TCHAR kJavaDeploy1[] = _T("npdeploytk.dll");
-const TCHAR kJavaDeploy2[] = _T("npdeployjava1.dll");
-
-// The application path where we expect to find plugins.
-void GetAppDirectory(std::set<FilePath>* plugin_dirs) {
- FilePath app_path;
- if (!webkit_glue::GetApplicationDirectory(&app_path))
- return;
-
- app_path = app_path.AppendASCII("plugins");
- plugin_dirs->insert(app_path);
-}
-
-// The executable path where we expect to find plugins.
-void GetExeDirectory(std::set<FilePath>* plugin_dirs) {
- FilePath exe_path;
- if (!webkit_glue::GetExeDirectory(&exe_path))
- return;
-
- exe_path = exe_path.AppendASCII("plugins");
- plugin_dirs->insert(exe_path);
-}
-
-// Gets the installed path for a registered app.
-bool GetInstalledPath(const TCHAR* app, FilePath* out) {
- std::wstring reg_path(kRegistryApps);
- reg_path.append(L"\\");
- reg_path.append(app);
-
- base::win::RegKey key(HKEY_LOCAL_MACHINE, reg_path.c_str(), KEY_READ);
- std::wstring path;
- if (key.ReadValue(kRegistryPath, &path)) {
- *out = FilePath(path);
- return true;
- }
-
- return false;
-}
-
-// Search the registry at the given path and detect plugin directories.
-void GetPluginsInRegistryDirectory(
- HKEY root_key,
- const std::wstring& registry_folder,
- std::set<FilePath>* plugin_dirs) {
- for (base::win::RegistryKeyIterator iter(root_key, registry_folder.c_str());
- iter.Valid(); ++iter) {
- // Use the registry to gather plugin across the file system.
- std::wstring reg_path = registry_folder;
- reg_path.append(L"\\");
- reg_path.append(iter.Name());
- base::win::RegKey key(root_key, reg_path.c_str(), KEY_READ);
-
- std::wstring path;
- if (key.ReadValue(kRegistryPath, &path))
- plugin_dirs->insert(FilePath(path));
- }
-}
-
-// Enumerate through the registry key to find all installed FireFox paths.
-// FireFox 3 beta and version 2 can coexist. See bug: 1025003
-void GetFirefoxInstalledPaths(std::vector<FilePath>* out) {
- base::win::RegistryKeyIterator it(HKEY_LOCAL_MACHINE,
- kRegistryFirefoxInstalled);
- for (; it.Valid(); ++it) {
- std::wstring full_path = std::wstring(kRegistryFirefoxInstalled) + L"\\" +
- it.Name() + L"\\Main";
- base::win::RegKey key(HKEY_LOCAL_MACHINE, full_path.c_str(), KEY_READ);
- std::wstring install_dir;
- if (!key.ReadValue(L"Install Directory", &install_dir))
- continue;
- out->push_back(FilePath(install_dir));
- }
-}
-
-// Get plugin directory locations from the Firefox install path. This is kind
-// of a kludge, but it helps us locate the flash player for users that
-// already have it for firefox. Not having to download yet-another-plugin
-// is a good thing.
-void GetFirefoxDirectory(std::set<FilePath>* plugin_dirs) {
- std::vector<FilePath> paths;
- GetFirefoxInstalledPaths(&paths);
- for (unsigned int i = 0; i < paths.size(); ++i) {
- plugin_dirs->insert(paths[i].Append(L"plugins"));
- }
-
- FilePath firefox_app_data_plugin_path;
- if (PathService::Get(base::DIR_APP_DATA, &firefox_app_data_plugin_path)) {
- firefox_app_data_plugin_path =
- firefox_app_data_plugin_path.AppendASCII("Mozilla")
- .AppendASCII("plugins");
- plugin_dirs->insert(firefox_app_data_plugin_path);
- }
-}
-
-// Hardcoded logic to detect Acrobat plugins locations.
-void GetAcrobatDirectory(std::set<FilePath>* plugin_dirs) {
- FilePath path;
- if (!GetInstalledPath(kRegistryAcrobatReader, &path) &&
- !GetInstalledPath(kRegistryAcrobat, &path)) {
- return;
- }
-
- plugin_dirs->insert(path.Append(L"Browser"));
-}
-
-// Hardcoded logic to detect QuickTime plugin location.
-void GetQuicktimeDirectory(std::set<FilePath>* plugin_dirs) {
- FilePath path;
- if (GetInstalledPath(kRegistryQuickTime, &path))
- plugin_dirs->insert(path.Append(L"plugins"));
-}
-
-// Hardcoded logic to detect Windows Media Player plugin location.
-void GetWindowsMediaDirectory(std::set<FilePath>* plugin_dirs) {
- FilePath path;
- if (GetInstalledPath(kRegistryWindowsMedia, &path))
- plugin_dirs->insert(path);
-
- // If the Windows Media Player Firefox plugin is installed before Firefox,
- // the plugin will get written under PFiles\Plugins on one the drives
- // (usually, but not always, the last letter).
- int size = GetLogicalDriveStrings(0, NULL);
- if (size) {
- scoped_array<wchar_t> strings(new wchar_t[size]);
- if (GetLogicalDriveStrings(size, strings.get())) {
- wchar_t* next_drive = strings.get();
- while (*next_drive) {
- if (GetDriveType(next_drive) == DRIVE_FIXED) {
- FilePath pfiles(next_drive);
- pfiles = pfiles.Append(L"PFiles\\Plugins");
- if (file_util::PathExists(pfiles))
- plugin_dirs->insert(pfiles);
- }
- next_drive = &next_drive[wcslen(next_drive) + 1];
- }
- }
- }
-}
-
-// Hardcoded logic to detect Java plugin location.
-void GetJavaDirectory(std::set<FilePath>* plugin_dirs) {
- // Load the new NPAPI Java plugin
- // 1. Open the main JRE key under HKLM
- base::win::RegKey java_key(HKEY_LOCAL_MACHINE, kRegistryJava,
- KEY_QUERY_VALUE);
-
- // 2. Read the current Java version
- std::wstring java_version;
- if (!java_key.ReadValue(kRegistryBrowserJavaVersion, &java_version))
- java_key.ReadValue(kRegistryCurrentJavaVersion, &java_version);
-
- if (!java_version.empty()) {
- java_key.OpenKey(java_version.c_str(), KEY_QUERY_VALUE);
-
- // 3. Install path of the JRE binaries is specified in "JavaHome"
- // value under the Java version key.
- std::wstring java_plugin_directory;
- if (java_key.ReadValue(kRegistryJavaHome, &java_plugin_directory)) {
- // 4. The new plugin resides under the 'bin/new_plugin'
- // subdirectory.
- DCHECK(!java_plugin_directory.empty());
- java_plugin_directory.append(L"\\bin\\new_plugin");
-
- // 5. We don't know the exact name of the DLL but it's in the form
- // NP*.dll so just invoke LoadPlugins on this path.
- plugin_dirs->insert(FilePath(java_plugin_directory));
- }
- }
-}
-
-} // anonymous namespace
-
-namespace NPAPI {
-
-void PluginList::PlatformInit() {
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- dont_load_new_wmp_ = command_line.HasSwitch(kUseOldWMPPluginSwitch);
-}
-
-void PluginList::GetPluginDirectories(std::vector<FilePath>* plugin_dirs) {
- // We use a set for uniqueness, which we require, over order, which we do not.
- std::set<FilePath> dirs;
-
- // Load from the application-specific area
- GetAppDirectory(&dirs);
-
- // Load from the executable area
- GetExeDirectory(&dirs);
-
- // Load Java
- GetJavaDirectory(&dirs);
-
- // Load firefox plugins too. This is mainly to try to locate
- // a pre-installed Flash player.
- GetFirefoxDirectory(&dirs);
-
- // Firefox hard-codes the paths of some popular plugins to ensure that
- // the plugins are found. We are going to copy this as well.
- GetAcrobatDirectory(&dirs);
- GetQuicktimeDirectory(&dirs);
- GetWindowsMediaDirectory(&dirs);
-
- for (std::set<FilePath>::iterator i = dirs.begin(); i != dirs.end(); ++i)
- plugin_dirs->push_back(*i);
-}
-
-void PluginList::LoadPluginsFromDir(const FilePath &path,
- std::vector<WebPluginInfo>* plugins,
- std::set<FilePath>* visited_plugins) {
- WIN32_FIND_DATA find_file_data;
- HANDLE find_handle;
-
- std::wstring dir = path.value();
- // FindFirstFile requires that you specify a wildcard for directories.
- dir.append(L"\\NP*.DLL");
-
- find_handle = FindFirstFile(dir.c_str(), &find_file_data);
- if (find_handle == INVALID_HANDLE_VALUE)
- return;
-
- do {
- if (!(find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
- FilePath filename = path.Append(find_file_data.cFileName);
- LoadPlugin(filename, plugins);
- visited_plugins->insert(filename);
- }
- } while (FindNextFile(find_handle, &find_file_data) != 0);
-
- DCHECK(GetLastError() == ERROR_NO_MORE_FILES);
- FindClose(find_handle);
-}
-
-void PluginList::LoadPluginsFromRegistry(
- std::vector<WebPluginInfo>* plugins,
- std::set<FilePath>* visited_plugins) {
- std::set<FilePath> plugin_dirs;
-
- GetPluginsInRegistryDirectory(
- HKEY_CURRENT_USER, kRegistryMozillaPlugins, &plugin_dirs);
- GetPluginsInRegistryDirectory(
- HKEY_LOCAL_MACHINE, kRegistryMozillaPlugins, &plugin_dirs);
-
- for (std::set<FilePath>::iterator i = plugin_dirs.begin();
- i != plugin_dirs.end(); ++i) {
- LoadPlugin(*i, plugins);
- visited_plugins->insert(*i);
- }
-}
-
-// Returns true if the given plugins share at least one mime type. This is used
-// to differentiate newer versions of a plugin vs two plugins which happen to
-// have the same filename.
-bool HaveSharedMimeType(const WebPluginInfo& plugin1,
- const WebPluginInfo& plugin2) {
- for (size_t i = 0; i < plugin1.mime_types.size(); ++i) {
- for (size_t j = 0; j < plugin2.mime_types.size(); ++j) {
- if (plugin1.mime_types[i].mime_type == plugin2.mime_types[j].mime_type)
- return true;
- }
- }
-
- return false;
-}
-
-// Compares Windows style version strings (i.e. 1,2,3,4). Returns true if b's
-// version is newer than a's, or false if it's equal or older.
-bool IsNewerVersion(const std::wstring& a, const std::wstring& b) {
- std::vector<std::wstring> a_ver, b_ver;
- base::SplitString(a, ',', &a_ver);
- base::SplitString(b, ',', &b_ver);
- if (a_ver.size() == 1 && b_ver.size() == 1) {
- a_ver.clear();
- b_ver.clear();
- base::SplitString(a, '.', &a_ver);
- base::SplitString(b, '.', &b_ver);
- }
- if (a_ver.size() != b_ver.size())
- return false;
- for (size_t i = 0; i < a_ver.size(); i++) {
- int cur_a, cur_b;
- base::StringToInt(a_ver[i], &cur_a);
- base::StringToInt(b_ver[i], &cur_b);
-
- if (cur_a > cur_b)
- return false;
- if (cur_a < cur_b)
- return true;
- }
- return false;
-}
-
-bool PluginList::ShouldLoadPlugin(const WebPluginInfo& info,
- std::vector<WebPluginInfo>* plugins) {
- // Version check
-
- for (size_t i = 0; i < plugins->size(); ++i) {
- std::wstring plugin1 =
- StringToLowerASCII((*plugins)[i].path.BaseName().ToWStringHack());
- std::wstring plugin2 =
- StringToLowerASCII(info.path.BaseName().ToWStringHack());
- if ((plugin1 == plugin2 && HaveSharedMimeType((*plugins)[i], info)) ||
- (plugin1 == kJavaDeploy1 && plugin2 == kJavaDeploy2) ||
- (plugin1 == kJavaDeploy2 && plugin2 == kJavaDeploy1)) {
- if (!IsNewerVersion((*plugins)[i].version, info.version))
- return false; // We have loaded a plugin whose version is newer.
-
- plugins->erase(plugins->begin() + i);
- break;
- }
- }
-
- // Troublemakers
-
- std::wstring filename = StringToLowerASCII(info.path.BaseName().value());
- // Depends on XPCOM.
- if (filename == kMozillaActiveXPlugin)
- return false;
-
- // Disable the Yahoo Application State plugin as it crashes the plugin
- // process on return from NPObjectStub::OnInvoke. Please refer to
- // http://b/issue?id=1372124 for more information.
- if (filename == kYahooApplicationStatePlugin)
- return false;
-
- // Disable the WangWang protocol handler plugin (npww.dll) as it crashes
- // chrome during shutdown. Firefox also disables this plugin.
- // Please refer to http://code.google.com/p/chromium/issues/detail?id=3953
- // for more information.
- if (filename == kWanWangProtocolHandlerPlugin)
- return false;
-
- // We only work with newer versions of the Java plugin which use NPAPI only
- // and don't depend on XPCOM.
- if (filename == kJavaPlugin1 || filename == kJavaPlugin2) {
- std::vector<std::wstring> ver;
- base::SplitString(info.version, '.', &ver);
- int major, minor, update;
- if (ver.size() == 4 &&
- base::StringToInt(ver[0], &major) &&
- base::StringToInt(ver[1], &minor) &&
- base::StringToInt(ver[2], &update)) {
- if (major == 6 && minor == 0 && update < 120)
- return false; // Java SE6 Update 11 or older.
- }
- }
-
- // Special WMP handling
-
- // If both the new and old WMP plugins exist, only load the new one.
- if (filename == kNewWMPPlugin) {
- if (dont_load_new_wmp_)
- return false;
-
- for (size_t i = 0; i < plugins->size(); ++i) {
- if ((*plugins)[i].path.BaseName().value() == kOldWMPPlugin) {
- plugins->erase(plugins->begin() + i);
- break;
- }
- }
- } else if (filename == kOldWMPPlugin) {
- for (size_t i = 0; i < plugins->size(); ++i) {
- if ((*plugins)[i].path.BaseName().value() == kNewWMPPlugin)
- return false;
- }
- }
-
- return true;
-}
-
-} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_stream.cc b/webkit/glue/plugins/plugin_stream.cc
deleted file mode 100644
index 728b180..0000000
--- a/webkit/glue/plugins/plugin_stream.cc
+++ /dev/null
@@ -1,254 +0,0 @@
-// 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.
-
-// TODO : Support NP_ASFILEONLY mode
-// TODO : Support NP_SEEK mode
-// TODO : Support SEEKABLE=true in NewStream
-
-#include "webkit/glue/plugins/plugin_stream.h"
-
-#include "base/message_loop.h"
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-#include "net/base/mime_util.h"
-#include "webkit/glue/plugins/plugin_instance.h"
-#include "googleurl/src/gurl.h"
-
-namespace NPAPI {
-
-PluginStream::~PluginStream() {
- // always close our temporary files.
- CloseTempFile();
- free(const_cast<char*>(stream_.url));
-}
-
-bool PluginStream::Open(const std::string &mime_type,
- const std::string &headers,
- uint32 length,
- uint32 last_modified,
- bool request_is_seekable) {
- headers_ = headers;
- NPP id = instance_->npp();
- stream_.end = length;
- stream_.lastmodified = last_modified;
- stream_.pdata = 0;
- stream_.ndata = id->ndata;
- stream_.notifyData = notify_data_;
- if (!headers_.empty())
- stream_.headers = headers_.c_str();
-
- bool seekable_stream = false;
- if (request_is_seekable) {
- std::string headers_lc = StringToLowerASCII(headers);
- if (headers_lc.find("accept-ranges: bytes") != std::string::npos) {
- seekable_stream = true;
- }
- }
-
- const char *char_mime_type = "application/x-unknown-content-type";
- std::string temp_mime_type;
- if (!mime_type.empty()) {
- char_mime_type = mime_type.c_str();
- } else {
- GURL gurl(stream_.url);
-
-#if defined(OS_WIN)
- FilePath path(UTF8ToWide(gurl.path()));
-#elif defined(OS_POSIX)
- FilePath path(gurl.path());
-#endif
- if (net::GetMimeTypeFromFile(path, &temp_mime_type))
- char_mime_type = temp_mime_type.c_str();
- }
-
- // Silverlight expects a valid mime type
- DCHECK(strlen(char_mime_type) != 0);
- NPError err = instance_->NPP_NewStream((NPMIMEType)char_mime_type,
- &stream_, seekable_stream,
- &requested_plugin_mode_);
- if (err != NPERR_NO_ERROR) {
- Notify(err);
- return false;
- }
-
- opened_ = true;
-
- if (requested_plugin_mode_ == NP_SEEK) {
- seekable_stream_ = true;
- }
- // If the plugin has requested certain modes, then we need a copy
- // of this file on disk. Open it and save it as we go.
- if (requested_plugin_mode_ == NP_ASFILEONLY ||
- requested_plugin_mode_ == NP_ASFILE) {
- if (OpenTempFile() == false)
- return false;
- }
-
- mime_type_ = char_mime_type;
- return true;
-}
-
-int PluginStream::Write(const char *buffer, const int length,
- int data_offset) {
- // There may be two streams to write to - the plugin and the file.
- // It is unclear what to do if we cannot write to both. The rules of
- // this function are that the plugin must consume at least as many
- // bytes as returned by the WriteReady call. So, we will attempt to
- // write that many to both streams. If we can't write that many bytes
- // to each stream, we'll return failure.
-
- DCHECK(opened_);
- if (WriteToFile(buffer, length) &&
- WriteToPlugin(buffer, length, data_offset))
- return length;
-
- return -1;
-}
-
-bool PluginStream::WriteToFile(const char *buf, size_t length) {
- // For ASFILEONLY, ASFILE, and SEEK modes, we need to write
- // to the disk
- if (TempFileIsValid() &&
- (requested_plugin_mode_ == NP_ASFILE ||
- requested_plugin_mode_ == NP_ASFILEONLY) ) {
- size_t totalBytesWritten = 0, bytes;
- do {
- bytes = WriteBytes(buf, length);
- totalBytesWritten += bytes;
- } while (bytes > 0U && totalBytesWritten < length);
-
- if (totalBytesWritten != length)
- return false;
- }
-
- return true;
-}
-
-bool PluginStream::WriteToPlugin(const char *buf, const int length,
- const int data_offset) {
- // For NORMAL and ASFILE modes, we send the data to the plugin now
- if (requested_plugin_mode_ != NP_NORMAL &&
- requested_plugin_mode_ != NP_ASFILE &&
- requested_plugin_mode_ != NP_SEEK)
- return true;
-
- int written = TryWriteToPlugin(buf, length, data_offset);
- if (written == -1)
- return false;
-
- if (written < length) {
- // Buffer the remaining data.
- size_t remaining = length - written;
- size_t previous_size = delivery_data_.size();
- delivery_data_.resize(previous_size + remaining);
- data_offset_ = data_offset;
- memcpy(&delivery_data_[previous_size], buf + written, remaining);
- MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
- this, &PluginStream::OnDelayDelivery));
- }
-
- return true;
-}
-
-void PluginStream::OnDelayDelivery() {
- // It is possible that the plugin stream may have closed before the task
- // was hit.
- if (!opened_) {
- return;
- }
-
- int size = static_cast<int>(delivery_data_.size());
- int written = TryWriteToPlugin(&delivery_data_.front(), size,
- data_offset_);
- if (written > 0) {
- // Remove the data that we already wrote.
- delivery_data_.erase(delivery_data_.begin(),
- delivery_data_.begin() + written);
- }
-}
-
-int PluginStream::TryWriteToPlugin(const char *buf, const int length,
- const int data_offset) {
- int byte_offset = 0;
-
- if (data_offset > 0)
- data_offset_ = data_offset;
-
- while (byte_offset < length) {
- int bytes_remaining = length - byte_offset;
- int bytes_to_write = instance_->NPP_WriteReady(&stream_);
- if (bytes_to_write > bytes_remaining)
- bytes_to_write = bytes_remaining;
-
- if (bytes_to_write == 0)
- return byte_offset;
-
- int bytes_consumed = instance_->NPP_Write(
- &stream_, data_offset_, bytes_to_write,
- const_cast<char*>(buf + byte_offset));
- if (bytes_consumed < 0) {
- // The plugin failed, which means that we need to close the stream.
- Close(NPRES_NETWORK_ERR);
- return -1;
- }
- if (bytes_consumed == 0) {
- // The plugin couldn't take all of the data now.
- return byte_offset;
- }
-
- // The plugin might report more that we gave it.
- bytes_consumed = std::min(bytes_consumed, bytes_to_write);
-
- data_offset_ += bytes_consumed;
- byte_offset += bytes_consumed;
- }
-
- if (close_on_write_data_)
- Close(NPRES_DONE);
-
- return length;
-}
-
-bool PluginStream::Close(NPReason reason) {
- if (opened_ == true) {
- opened_ = false;
-
- if (delivery_data_.size()) {
- if (reason == NPRES_DONE) {
- // There is more data to be streamed, don't destroy the stream now.
- close_on_write_data_ = true;
- return true;
- } else {
- // Stop any pending data from being streamed
- delivery_data_.resize(0);
- }
- }
-
- // If we have a temp file, be sure to close it.
- // Also, allow the plugin to access it now.
- if (TempFileIsValid()) {
- CloseTempFile();
- if (reason == NPRES_DONE)
- WriteAsFile();
- }
-
- if (stream_.ndata != NULL) {
- // Stream hasn't been closed yet.
- NPError err = instance_->NPP_DestroyStream(&stream_, reason);
- DCHECK(err == NPERR_NO_ERROR);
- }
- }
-
- Notify(reason);
- return true;
-}
-
-void PluginStream::Notify(NPReason reason) {
- if (notify_needed_) {
- instance_->NPP_URLNotify(stream_.url, reason, notify_data_);
- notify_needed_ = false;
- }
-}
-
-} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_stream.h b/webkit/glue/plugins/plugin_stream.h
deleted file mode 100644
index b277465..0000000
--- a/webkit/glue/plugins/plugin_stream.h
+++ /dev/null
@@ -1,158 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PLUGIN_STREAM_H_
-#define WEBKIT_GLUE_PLUGINS_PLUGIN_STREAM_H_
-
-#include "build/build_config.h"
-
-#include <string>
-#include <vector>
-
-#if defined(OS_POSIX)
-#include "base/file_path.h"
-#endif
-#include "base/ref_counted.h"
-#include "third_party/npapi/bindings/npapi.h"
-
-namespace webkit_glue {
-class WebPluginResourceClient;
-}
-
-namespace NPAPI {
-
-class PluginInstance;
-
-// Base class for a NPAPI stream. Tracks basic elements
-// of a stream for NPAPI notifications and stream position.
-class PluginStream : public base::RefCounted<PluginStream> {
- public:
- // Create a new PluginStream object. If needNotify is true, then the
- // plugin will be notified when the stream has been fully sent.
- PluginStream(PluginInstance *instance,
- const char *url,
- bool need_notify,
- void *notify_data);
-
- // In case of a redirect, this can be called to update the url. But it must
- // be called before Open().
- void UpdateUrl(const char* url);
-
- // Opens the stream to the Plugin.
- // If the mime-type is not specified, we'll try to find one based on the
- // mime-types table and the extension (if any) in the URL.
- // If the size of the stream is known, use length to set the size. If
- // not known, set length to 0.
- // The request_is_seekable parameter indicates whether byte range requests
- // can be issued on the stream.
- bool Open(const std::string &mime_type,
- const std::string &headers,
- uint32 length,
- uint32 last_modified,
- bool request_is_seekable);
-
- // Writes to the stream.
- int Write(const char *buf, const int len, int data_offset);
-
- // Write the result as a file.
- void WriteAsFile();
-
- // Notify the plugin that a stream is complete.
- void Notify(NPReason reason);
-
- // Close the stream.
- virtual bool Close(NPReason reason);
-
- virtual webkit_glue::WebPluginResourceClient* AsResourceClient() {
- return NULL;
- }
-
- // Cancels any HTTP requests initiated by the stream.
- virtual void CancelRequest() {}
-
- const NPStream* stream() const { return &stream_; }
-
- // setter/getter for the seekable attribute on the stream.
- bool seekable() const { return seekable_stream_; }
-
- void set_seekable(bool seekable) { seekable_stream_ = seekable; }
-
- // getters for reading the notification related attributes on the stream.
- bool notify_needed() const { return notify_needed_; }
-
- void* notify_data() const { return notify_data_; }
-
- std::string pending_redirect_url() const { return pending_redirect_url_; }
-
- protected:
- friend class base::RefCounted<PluginStream>;
-
- virtual ~PluginStream();
-
- PluginInstance* instance() { return instance_.get(); }
- // Check if the stream is open.
- bool open() { return opened_; }
-
- // If the plugin participates in HTTP URL redirect handling then this member
- // holds the url being redirected to while we wait for the plugin to make a
- // decision on whether to allow or deny the redirect.
- std::string pending_redirect_url_;
-
- private:
-
- // Open a temporary file for this stream.
- // If successful, will set temp_file_name_, temp_file_handle_, and
- // return true.
- bool OpenTempFile();
-
- // Closes the temporary file if it is open.
- void CloseTempFile();
-
- // Sends the data to the file. Called From WriteToFile.
- size_t WriteBytes(const char *buf, size_t length);
-
- // Sends the data to the file if it's open.
- bool WriteToFile(const char *buf, size_t length);
-
- // Sends the data to the plugin. If it's not ready, handles buffering it
- // and retrying later.
- bool WriteToPlugin(const char *buf, const int length, const int data_offset);
-
- // Send the data to the plugin, returning how many bytes it accepted, or -1
- // if an error occurred.
- int TryWriteToPlugin(const char *buf, const int length,
- const int data_offset);
-
- // The callback which calls TryWriteToPlugin.
- void OnDelayDelivery();
-
- // Returns true if the temp file is valid and open for writing.
- bool TempFileIsValid();
-
- private:
- NPStream stream_;
- std::string headers_;
- scoped_refptr<PluginInstance> instance_;
- bool notify_needed_;
- void * notify_data_;
- bool close_on_write_data_;
- uint16 requested_plugin_mode_;
- bool opened_;
-#if defined(OS_WIN)
- char temp_file_name_[MAX_PATH];
- HANDLE temp_file_handle_;
-#elif defined(OS_POSIX)
- FILE* temp_file_;
- FilePath temp_file_path_;
-#endif
- std::vector<char> delivery_data_;
- int data_offset_;
- bool seekable_stream_;
- std::string mime_type_;
- DISALLOW_COPY_AND_ASSIGN(PluginStream);
-};
-
-} // namespace NPAPI
-
-#endif // WEBKIT_GLUE_PLUGINS_PLUGIN_STREAM_H_
diff --git a/webkit/glue/plugins/plugin_stream_posix.cc b/webkit/glue/plugins/plugin_stream_posix.cc
deleted file mode 100644
index d0e2291..0000000
--- a/webkit/glue/plugins/plugin_stream_posix.cc
+++ /dev/null
@@ -1,74 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/plugin_stream.h"
-
-#include <string.h>
-
-#include "base/file_path.h"
-#include "base/file_util.h"
-#include "base/logging.h"
-#include "webkit/glue/plugins/plugin_instance.h"
-
-namespace NPAPI {
-
-PluginStream::PluginStream(
- PluginInstance *instance,
- const char *url,
- bool need_notify,
- void *notify_data)
- : instance_(instance),
- notify_needed_(need_notify),
- notify_data_(notify_data),
- close_on_write_data_(false),
- requested_plugin_mode_(NP_NORMAL),
- opened_(false),
- temp_file_(NULL),
- temp_file_path_(),
- data_offset_(0),
- seekable_stream_(false) {
- memset(&stream_, 0, sizeof(stream_));
- stream_.url = strdup(url);
-}
-
-void PluginStream::UpdateUrl(const char* url) {
- DCHECK(!opened_);
- free(const_cast<char*>(stream_.url));
- stream_.url = strdup(url);
-}
-
-void PluginStream::WriteAsFile() {
- if (requested_plugin_mode_ == NP_ASFILE ||
- requested_plugin_mode_ == NP_ASFILEONLY)
- instance_->NPP_StreamAsFile(&stream_, temp_file_path_.value().c_str());
-}
-
-size_t PluginStream::WriteBytes(const char *buf, size_t length) {
- return fwrite(buf, sizeof(char), length, temp_file_);
-}
-
-bool PluginStream::OpenTempFile() {
- DCHECK(temp_file_ == NULL);
-
- if (file_util::CreateTemporaryFile(&temp_file_path_))
- temp_file_ = file_util::OpenFile(temp_file_path_, "a");
-
- if (!temp_file_) {
- temp_file_path_ = FilePath("");
- return false;
- }
-
- return true;
-}
-
-void PluginStream::CloseTempFile() {
- file_util::CloseFile(temp_file_);
- temp_file_ = NULL;
-}
-
-bool PluginStream::TempFileIsValid() {
- return temp_file_ != NULL;
-}
-
-} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_stream_url.cc b/webkit/glue/plugins/plugin_stream_url.cc
deleted file mode 100644
index 1af4485..0000000
--- a/webkit/glue/plugins/plugin_stream_url.cc
+++ /dev/null
@@ -1,118 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/plugin_stream_url.h"
-
-#include "net/http/http_response_headers.h"
-#include "webkit/glue/plugins/plugin_host.h"
-#include "webkit/glue/plugins/plugin_instance.h"
-#include "webkit/glue/plugins/plugin_lib.h"
-#include "webkit/glue/plugins/webplugin.h"
-
-namespace NPAPI {
-
-PluginStreamUrl::PluginStreamUrl(
- unsigned long resource_id,
- const GURL &url,
- PluginInstance *instance,
- bool notify_needed,
- void *notify_data)
- : PluginStream(instance, url.spec().c_str(), notify_needed, notify_data),
- url_(url),
- id_(resource_id) {
-}
-
-PluginStreamUrl::~PluginStreamUrl() {
- if (instance() && instance()->webplugin()) {
- instance()->webplugin()->ResourceClientDeleted(AsResourceClient());
- }
-}
-
-bool PluginStreamUrl::Close(NPReason reason) {
- // Protect the stream against it being destroyed or the whole plugin instance
- // being destroyed within the destroy stream handler.
- scoped_refptr<PluginStream> protect(this);
- CancelRequest();
- bool result = PluginStream::Close(reason);
- instance()->RemoveStream(this);
- return result;
-}
-
-void PluginStreamUrl::WillSendRequest(const GURL& url, int http_status_code) {
- if (notify_needed()) {
- // If the plugin participates in HTTP url redirect handling then notify it.
- if (net::HttpResponseHeaders::IsRedirectResponseCode(http_status_code) &&
- instance()->handles_url_redirects()) {
- pending_redirect_url_ = url.spec();
- instance()->NPP_URLRedirectNotify(url.spec().c_str(), http_status_code,
- notify_data());
- return;
- }
- }
- url_ = url;
- UpdateUrl(url.spec().c_str());
-}
-
-void PluginStreamUrl::DidReceiveResponse(const std::string& mime_type,
- const std::string& headers,
- uint32 expected_length,
- uint32 last_modified,
- bool request_is_seekable) {
- // Protect the stream against it being destroyed or the whole plugin instance
- // being destroyed within the new stream handler.
- scoped_refptr<PluginStream> protect(this);
-
- bool opened = Open(mime_type,
- headers,
- expected_length,
- last_modified,
- request_is_seekable);
- if (!opened) {
- CancelRequest();
- instance()->RemoveStream(this);
- } else {
- if (id_ > 0)
- instance()->webplugin()->SetDeferResourceLoading(id_, false);
- }
-}
-
-void PluginStreamUrl::DidReceiveData(const char* buffer, int length,
- int data_offset) {
- if (!open())
- return;
-
- // Protect the stream against it being destroyed or the whole plugin instance
- // being destroyed within the write handlers
- scoped_refptr<PluginStream> protect(this);
-
- if (length > 0) {
- // The PluginStreamUrl instance could get deleted if the plugin fails to
- // accept data in NPP_Write.
- if (Write(const_cast<char*>(buffer), length, data_offset) > 0) {
- if (id_ > 0)
- instance()->webplugin()->SetDeferResourceLoading(id_, false);
- }
- }
-}
-
-void PluginStreamUrl::DidFinishLoading() {
- if (!seekable()) {
- Close(NPRES_DONE);
- }
-}
-
-void PluginStreamUrl::DidFail() {
- Close(NPRES_NETWORK_ERR);
-}
-
-void PluginStreamUrl::CancelRequest() {
- if (id_ > 0) {
- if (instance()->webplugin()) {
- instance()->webplugin()->CancelResource(id_);
- }
- id_ = 0;
- }
-}
-
-} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_stream_url.h b/webkit/glue/plugins/plugin_stream_url.h
deleted file mode 100644
index 8c03edc..0000000
--- a/webkit/glue/plugins/plugin_stream_url.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGIN_PLUGIN_STREAM_URL_H__
-#define WEBKIT_GLUE_PLUGIN_PLUGIN_STREAM_URL_H__
-
-
-#include "webkit/glue/plugins/plugin_stream.h"
-#include "webkit/glue/plugins/webplugin.h"
-#include "googleurl/src/gurl.h"
-
-namespace NPAPI {
-
-class PluginInstance;
-
-// A NPAPI Stream based on a URL.
-class PluginStreamUrl : public PluginStream,
- public webkit_glue::WebPluginResourceClient {
- public:
- // Create a new stream for sending to the plugin by fetching
- // a URL. If notifyNeeded is set, then the plugin will be notified
- // when the stream has been fully sent to the plugin. Initialize
- // must be called before the object is used.
- PluginStreamUrl(unsigned long resource_id,
- const GURL &url,
- PluginInstance *instance,
- bool notify_needed,
- void *notify_data);
- virtual ~PluginStreamUrl();
-
- // Stop sending the stream to the client.
- // Overrides the base Close so we can cancel our fetching the URL if
- // it is still loading.
- virtual bool Close(NPReason reason);
-
- virtual webkit_glue::WebPluginResourceClient* AsResourceClient() {
- return static_cast<webkit_glue::WebPluginResourceClient*>(this);
- }
-
- virtual void CancelRequest();
-
- //
- // WebPluginResourceClient methods
- //
- void WillSendRequest(const GURL& url, int http_status_code);
- void DidReceiveResponse(const std::string& mime_type,
- const std::string& headers,
- uint32 expected_length,
- uint32 last_modified,
- bool request_is_seekable);
- void DidReceiveData(const char* buffer, int length, int data_offset);
- void DidFinishLoading();
- void DidFail();
- bool IsMultiByteResponseExpected() {
- return seekable();
- }
- int ResourceId() {
- return id_;
- }
-
- private:
- GURL url_;
- unsigned long id_;
-
- DISALLOW_COPY_AND_ASSIGN(PluginStreamUrl);
-};
-
-} // namespace NPAPI
-
-#endif // WEBKIT_GLUE_PLUGIN_PLUGIN_STREAM_URL_H__
diff --git a/webkit/glue/plugins/plugin_stream_win.cc b/webkit/glue/plugins/plugin_stream_win.cc
deleted file mode 100644
index 0b6fcbd..0000000
--- a/webkit/glue/plugins/plugin_stream_win.cc
+++ /dev/null
@@ -1,97 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/plugin_stream.h"
-
-#include "base/logging.h"
-#include "webkit/glue/plugins/plugin_instance.h"
-
-namespace NPAPI {
-
-PluginStream::PluginStream(
- PluginInstance *instance,
- const char *url,
- bool need_notify,
- void *notify_data)
- : instance_(instance),
- notify_needed_(need_notify),
- notify_data_(notify_data),
- close_on_write_data_(false),
- opened_(false),
- requested_plugin_mode_(NP_NORMAL),
- temp_file_handle_(INVALID_HANDLE_VALUE),
- seekable_stream_(false),
- data_offset_(0) {
- memset(&stream_, 0, sizeof(stream_));
- stream_.url = _strdup(url);
- temp_file_name_[0] = '\0';
-}
-
-void PluginStream::UpdateUrl(const char* url) {
- DCHECK(!opened_);
- free(const_cast<char*>(stream_.url));
- stream_.url = _strdup(url);
- pending_redirect_url_.clear();
-}
-
-void PluginStream::WriteAsFile() {
- if (requested_plugin_mode_ == NP_ASFILE ||
- requested_plugin_mode_ == NP_ASFILEONLY)
- instance_->NPP_StreamAsFile(&stream_, temp_file_name_);
-}
-
-size_t PluginStream::WriteBytes(const char *buf, size_t length) {
- DWORD bytes;
-
- if (!WriteFile(temp_file_handle_, buf, length, &bytes, 0))
- return 0U;
-
- return static_cast<size_t>(bytes);
-}
-
-bool PluginStream::OpenTempFile() {
- DCHECK(temp_file_handle_ == INVALID_HANDLE_VALUE);
-
- // The reason for using all the Ascii versions of these filesystem
- // calls is that the filename which we pass back to the plugin
- // via NPAPI is an ascii filename. Otherwise, we'd use wide-chars.
- //
- // TODO:
- // This is a bug in NPAPI itself, and it needs to be fixed.
- // The case which will fail is if a user has a multibyte name,
- // but has the system locale set to english. GetTempPathA will
- // return junk in this case, causing us to be unable to open the
- // file.
-
- char temp_directory[MAX_PATH];
- if (GetTempPathA(MAX_PATH, temp_directory) == 0)
- return false;
- if (GetTempFileNameA(temp_directory, "npstream", 0, temp_file_name_) == 0)
- return false;
- temp_file_handle_ = CreateFileA(temp_file_name_,
- FILE_ALL_ACCESS,
- FILE_SHARE_READ,
- 0,
- CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL,
- 0);
- if (temp_file_handle_ == INVALID_HANDLE_VALUE) {
- temp_file_name_[0] = '\0';
- return false;
- }
- return true;
-}
-
-void PluginStream::CloseTempFile() {
- if (temp_file_handle_ != INVALID_HANDLE_VALUE) {
- CloseHandle(temp_file_handle_);
- temp_file_handle_ = INVALID_HANDLE_VALUE;
- }
-}
-
-bool PluginStream::TempFileIsValid() {
- return temp_file_handle_ != INVALID_HANDLE_VALUE;
-}
-
-} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_string_stream.cc b/webkit/glue/plugins/plugin_string_stream.cc
deleted file mode 100644
index f174267..0000000
--- a/webkit/glue/plugins/plugin_string_stream.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/plugin_string_stream.h"
-
-#include "googleurl/src/gurl.h"
-
-namespace NPAPI {
-
-PluginStringStream::PluginStringStream(
- PluginInstance* instance,
- const GURL& url,
- bool notify_needed,
- void* notify_data)
- : PluginStream(instance, url.spec().c_str(), notify_needed, notify_data) {
-}
-
-PluginStringStream::~PluginStringStream() {
-}
-
-void PluginStringStream::SendToPlugin(const std::string &data,
- const std::string &mime_type) {
- // Protect the stream against it being destroyed or the whole plugin instance
- // being destroyed within the plugin stream callbacks.
- scoped_refptr<PluginStringStream> protect(this);
-
- int length = static_cast<int>(data.length());
- if (Open(mime_type, std::string(), length, 0, false)) {
- // TODO - check if it was not fully sent, and figure out a backup plan.
- int written = Write(data.c_str(), length, 0);
- NPReason reason = written == length ? NPRES_DONE : NPRES_NETWORK_ERR;
- Close(reason);
- }
-}
-
-}
diff --git a/webkit/glue/plugins/plugin_string_stream.h b/webkit/glue/plugins/plugin_string_stream.h
deleted file mode 100644
index 68db2bf..0000000
--- a/webkit/glue/plugins/plugin_string_stream.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGIN_PLUGIN_STRING_STREAM_H_
-#define WEBKIT_GLUE_PLUGIN_PLUGIN_STRING_STREAM_H_
-
-#include "webkit/glue/plugins/plugin_stream.h"
-
-class GURL;
-
-namespace NPAPI {
-
-class PluginInstance;
-
-// An NPAPI stream from a string.
-class PluginStringStream : public PluginStream {
- public:
- // Create a new stream for sending to the plugin.
- // If notify_needed, will notify the plugin after the data has
- // all been sent.
- PluginStringStream(PluginInstance* instance,
- const GURL& url,
- bool notify_needed,
- void* notify_data);
-
- // Initiates the sending of data to the plugin.
- void SendToPlugin(const std::string& data,
- const std::string& mime_type);
-
- private:
- virtual ~PluginStringStream();
-
- DISALLOW_COPY_AND_ASSIGN(PluginStringStream);
-};
-
-} // namespace NPAPI
-
-#endif // WEBKIT_GLUE_PLUGIN_PLUGIN_STRING_STREAM_H_
diff --git a/webkit/glue/plugins/plugin_stubs.cc b/webkit/glue/plugins/plugin_stubs.cc
deleted file mode 100644
index f8210c3..0000000
--- a/webkit/glue/plugins/plugin_stubs.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// 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.
-
-// This file stubs out some functions needed to make the linker happy
-// without linking in all the plugin code. It should be removed once
-// we have plugins working on all platforms.
-
-// TODO(port): remove this file.
-
-#include "base/logging.h"
-#include "webkit/glue/plugins/plugin_instance.h"
-#include "webkit/glue/plugins/plugin_stream.h"
-
-namespace NPAPI {
-
-PluginStream::~PluginStream() {
- NOTIMPLEMENTED();
-}
-
-bool PluginStream::Close(NPReason reason) {
- NOTIMPLEMENTED();
- return false;
-}
-
-void PluginInstance::NPP_StreamAsFile(NPStream*, const char*) {
- NOTIMPLEMENTED();
-}
-
-} // namespace NPAPI
diff --git a/webkit/glue/plugins/plugin_switches.cc b/webkit/glue/plugins/plugin_switches.cc
deleted file mode 100644
index eb5c958..0000000
--- a/webkit/glue/plugins/plugin_switches.cc
+++ /dev/null
@@ -1,15 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/plugin_switches.h"
-
-namespace switches {
-
-// Enables the testing interface for PPAPI.
-const char kEnablePepperTesting[] = "enable-pepper-testing";
-
-// Dumps extra logging about plugin loading to the log file.
-const char kDebugPluginLoading[] = "debug-plugin-loading";
-
-} // namespace switches
diff --git a/webkit/glue/plugins/plugin_switches.h b/webkit/glue/plugins/plugin_switches.h
deleted file mode 100644
index 772c047..0000000
--- a/webkit/glue/plugins/plugin_switches.h
+++ /dev/null
@@ -1,15 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PLUGIN_SWITCHES_H_
-#define WEBKIT_GLUE_PLUGINS_PLUGIN_SWITCHES_H_
-
-namespace switches {
-
-extern const char kDebugPluginLoading[];
-extern const char kEnablePepperTesting[];
-
-} // namespace switches
-
-#endif // WEBKIT_GLUE_PLUGINS_PLUGIN_SWITCHES_H_
diff --git a/webkit/glue/plugins/plugin_web_event_converter_mac.h b/webkit/glue/plugins/plugin_web_event_converter_mac.h
deleted file mode 100644
index ec5b86f..0000000
--- a/webkit/glue/plugins/plugin_web_event_converter_mac.h
+++ /dev/null
@@ -1,60 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGIN_PLUGIN_WEB_EVENT_CONVERTER_MAC_H_
-#define WEBKIT_GLUE_PLUGIN_PLUGIN_WEB_EVENT_CONVERTER_MAC_H_
-
-#include "third_party/npapi/bindings/npapi.h"
-
-namespace WebKit {
-class WebInputEvent;
-class WebKeyboardEvent;
-class WebMouseEvent;
-class WebMouseWheelEvent;
-}
-
-// Utility class to translating WebInputEvent structs to equivalent structures
-// suitable for sending to Mac plugins (via NPP_HandleEvent).
-class PluginWebEventConverter {
- public:
- PluginWebEventConverter() {}
- virtual ~PluginWebEventConverter() {}
-
- // Initializes a converter for the given web event. Returns false if the event
- // could not be converted.
- virtual bool InitWithEvent(const WebKit::WebInputEvent& web_event);
-
- // Returns a pointer to a plugin event--suitable for passing to
- // NPP_HandleEvent--corresponding to the the web event this converter was
- // created with. The pointer is valid only as long as this object is.
- // Returns NULL iff InitWithEvent returned false.
- virtual void* plugin_event() = 0;
-
-protected:
- // To be overridden by subclasses to store a converted plugin representation
- // of the given web event, suitable for returning from plugin_event.
- // Returns true if the event was successfully converted.
- virtual bool ConvertKeyboardEvent(
- const WebKit::WebKeyboardEvent& web_event) = 0;
- virtual bool ConvertMouseEvent(const WebKit::WebMouseEvent& web_event) = 0;
- virtual bool ConvertMouseWheelEvent(
- const WebKit::WebMouseWheelEvent& web_event) = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(PluginWebEventConverter);
-};
-
-// Factory for generating PluginWebEventConverter objects by event model.
-class PluginWebEventConverterFactory {
- public:
- // Returns a new PluginWebEventConverter corresponding to the given plugin
- // event model.
- static PluginWebEventConverter*
- CreateConverterForModel(NPEventModel event_model);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(PluginWebEventConverterFactory);
-};
-
-#endif // WEBKIT_GLUE_PLUGIN_PLUGIN_WEB_EVENT_CONVERTER_MAC_H_
diff --git a/webkit/glue/plugins/plugin_web_event_converter_mac.mm b/webkit/glue/plugins/plugin_web_event_converter_mac.mm
deleted file mode 100644
index 12d5cc6..0000000
--- a/webkit/glue/plugins/plugin_web_event_converter_mac.mm
+++ /dev/null
@@ -1,359 +0,0 @@
-// 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 "base/logging.h"
-#include "webkit/glue/plugins/plugin_web_event_converter_mac.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h"
-
-using WebKit::WebInputEvent;
-using WebKit::WebKeyboardEvent;
-using WebKit::WebMouseEvent;
-using WebKit::WebMouseWheelEvent;
-
-namespace {
-
-// Returns true if the caps lock flag should be set for the given event.
-bool CapsLockIsActive(const WebInputEvent& event) {
- // Only key events have accurate information for the caps lock flag; see
- // <https://bugs.webkit.org/show_bug.cgi?id=46518>.
- // For other types, use the live state.
- if (WebInputEvent::isKeyboardEventType(event.type))
- return (event.modifiers & WebInputEvent::CapsLockOn) != 0;
- else
- return ([[NSApp currentEvent] modifierFlags] & NSAlphaShiftKeyMask) != 0;
-}
-
-} // namespace
-
-#pragma mark -
-
-#ifndef NP_NO_CARBON
-
-// Converter implementation for the Carbon event model.
-class CarbonPluginWebEventConverter : public PluginWebEventConverter {
- public:
- CarbonPluginWebEventConverter() {}
- virtual ~CarbonPluginWebEventConverter() {}
-
- virtual bool InitWithEvent(const WebInputEvent& web_event);
-
- virtual void* plugin_event() { return &carbon_event_; }
-
- protected:
- virtual bool ConvertKeyboardEvent(const WebKeyboardEvent& key_event);
- virtual bool ConvertMouseEvent(const WebMouseEvent& mouse_event);
- virtual bool ConvertMouseWheelEvent(const WebMouseWheelEvent& wheel_event);
-
- private:
- // Returns the Carbon translation of web_event's modifiers.
- static EventModifiers CarbonModifiers(const WebInputEvent& web_event);
-
- NPEvent carbon_event_;
-
- DISALLOW_COPY_AND_ASSIGN(CarbonPluginWebEventConverter);
-};
-
-bool CarbonPluginWebEventConverter::InitWithEvent(
- const WebInputEvent& web_event) {
- memset(&carbon_event_, 0, sizeof(carbon_event_));
- // Set the fields common to all event types.
- carbon_event_.when = TickCount();
- carbon_event_.modifiers |= CarbonModifiers(web_event);
-
- return PluginWebEventConverter::InitWithEvent(web_event);
-}
-
-bool CarbonPluginWebEventConverter::ConvertKeyboardEvent(
- const WebKeyboardEvent& key_event) {
- // TODO: Figure out how to handle Unicode input to plugins, if that's
- // even possible in the NPAPI Carbon event model.
- carbon_event_.message = (key_event.nativeKeyCode << 8) & keyCodeMask;
- carbon_event_.message |= key_event.text[0] & charCodeMask;
- carbon_event_.modifiers |= btnState;
-
- switch (key_event.type) {
- case WebInputEvent::KeyDown:
- if (key_event.modifiers & WebInputEvent::IsAutoRepeat)
- carbon_event_.what = autoKey;
- else
- carbon_event_.what = keyDown;
- return true;
- case WebInputEvent::KeyUp:
- carbon_event_.what = keyUp;
- return true;
- case WebInputEvent::RawKeyDown:
- case WebInputEvent::Char:
- // May be used eventually for IME, but currently not needed.
- return false;
- default:
- NOTREACHED();
- return false;
- }
-}
-
-bool CarbonPluginWebEventConverter::ConvertMouseEvent(
- const WebMouseEvent& mouse_event) {
- carbon_event_.where.h = mouse_event.globalX;
- carbon_event_.where.v = mouse_event.globalY;
-
- // Default to "button up"; override this for mouse down events below.
- carbon_event_.modifiers |= btnState;
-
- switch (mouse_event.button) {
- case WebMouseEvent::ButtonLeft:
- break;
- case WebMouseEvent::ButtonMiddle:
- carbon_event_.modifiers |= cmdKey;
- break;
- case WebMouseEvent::ButtonRight:
- carbon_event_.modifiers |= controlKey;
- break;
- default:
- NOTIMPLEMENTED();
- }
- switch (mouse_event.type) {
- case WebInputEvent::MouseMove:
- carbon_event_.what = nullEvent;
- return true;
- case WebInputEvent::MouseLeave:
- case WebInputEvent::MouseEnter:
- carbon_event_.what = NPEventType_AdjustCursorEvent;
- return true;
- case WebInputEvent::MouseDown:
- carbon_event_.modifiers &= ~btnState;
- carbon_event_.what = mouseDown;
- return true;
- case WebInputEvent::MouseUp:
- carbon_event_.what = mouseUp;
- return true;
- default:
- NOTREACHED();
- return false;
- }
-}
-
-bool CarbonPluginWebEventConverter::ConvertMouseWheelEvent(
- const WebMouseWheelEvent& wheel_event) {
- return false; // The Carbon NPAPI event model has no "mouse wheel" concept.
-}
-
-EventModifiers CarbonPluginWebEventConverter::CarbonModifiers(
- const WebInputEvent& web_event) {
- NSInteger modifiers = 0;
- if (web_event.modifiers & WebInputEvent::ControlKey)
- modifiers |= controlKey;
- if (web_event.modifiers & WebInputEvent::ShiftKey)
- modifiers |= shiftKey;
- if (web_event.modifiers & WebInputEvent::AltKey)
- modifiers |= optionKey;
- if (web_event.modifiers & WebInputEvent::MetaKey)
- modifiers |= cmdKey;
- if (CapsLockIsActive(web_event))
- modifiers |= alphaLock;
- return modifiers;
-}
-
-#endif // !NP_NO_CARBON
-
-#pragma mark -
-
-// Converter implementation for the Cocoa event model.
-class CocoaPluginWebEventConverter : public PluginWebEventConverter {
-public:
- CocoaPluginWebEventConverter() {}
- virtual ~CocoaPluginWebEventConverter() {}
-
- virtual bool InitWithEvent(const WebInputEvent& web_event);
-
- virtual void* plugin_event() { return &cocoa_event_; }
-
-protected:
- virtual bool ConvertKeyboardEvent(const WebKeyboardEvent& key_event);
- virtual bool ConvertMouseEvent(const WebMouseEvent& mouse_event);
- virtual bool ConvertMouseWheelEvent(const WebMouseWheelEvent& wheel_event);
-
-private:
- // Returns the Cocoa translation of web_event's modifiers.
- static NSUInteger CocoaModifiers(const WebInputEvent& web_event);
-
- // Returns true if the given key is a modifier key.
- static bool KeyIsModifier(int native_key_code);
-
- NPCocoaEvent cocoa_event_;
-
- DISALLOW_COPY_AND_ASSIGN(CocoaPluginWebEventConverter);
-};
-
-bool CocoaPluginWebEventConverter::InitWithEvent(
- const WebInputEvent& web_event) {
- memset(&cocoa_event_, 0, sizeof(cocoa_event_));
- return PluginWebEventConverter::InitWithEvent(web_event);
-}
-
-bool CocoaPluginWebEventConverter::ConvertKeyboardEvent(
- const WebKeyboardEvent& key_event) {
- cocoa_event_.data.key.keyCode = key_event.nativeKeyCode;
-
- cocoa_event_.data.key.modifierFlags |= CocoaModifiers(key_event);
-
- // Modifier keys have their own event type, and don't get character or
- // repeat data.
- if (KeyIsModifier(key_event.nativeKeyCode)) {
- cocoa_event_.type = NPCocoaEventFlagsChanged;
- return true;
- }
-
- cocoa_event_.data.key.characters = reinterpret_cast<NPNSString*>(
- [NSString stringWithFormat:@"%S", key_event.text]);
- cocoa_event_.data.key.charactersIgnoringModifiers =
- reinterpret_cast<NPNSString*>(
- [NSString stringWithFormat:@"%S", key_event.unmodifiedText]);
-
- if (key_event.modifiers & WebInputEvent::IsAutoRepeat)
- cocoa_event_.data.key.isARepeat = true;
-
- switch (key_event.type) {
- case WebInputEvent::KeyDown:
- cocoa_event_.type = NPCocoaEventKeyDown;
- return true;
- case WebInputEvent::KeyUp:
- cocoa_event_.type = NPCocoaEventKeyUp;
- return true;
- case WebInputEvent::RawKeyDown:
- case WebInputEvent::Char:
- // May be used eventually for IME, but currently not needed.
- return false;
- default:
- NOTREACHED();
- return false;
- }
-}
-
-bool CocoaPluginWebEventConverter::ConvertMouseEvent(
- const WebMouseEvent& mouse_event) {
- cocoa_event_.data.mouse.pluginX = mouse_event.x;
- cocoa_event_.data.mouse.pluginY = mouse_event.y;
- cocoa_event_.data.mouse.modifierFlags |= CocoaModifiers(mouse_event);
- cocoa_event_.data.mouse.clickCount = mouse_event.clickCount;
- switch (mouse_event.button) {
- case WebMouseEvent::ButtonLeft:
- cocoa_event_.data.mouse.buttonNumber = 0;
- break;
- case WebMouseEvent::ButtonMiddle:
- cocoa_event_.data.mouse.buttonNumber = 2;
- break;
- case WebMouseEvent::ButtonRight:
- cocoa_event_.data.mouse.buttonNumber = 1;
- break;
- default:
- cocoa_event_.data.mouse.buttonNumber = mouse_event.button;
- break;
- }
- switch (mouse_event.type) {
- case WebInputEvent::MouseDown:
- cocoa_event_.type = NPCocoaEventMouseDown;
- return true;
- case WebInputEvent::MouseUp:
- cocoa_event_.type = NPCocoaEventMouseUp;
- return true;
- case WebInputEvent::MouseMove: {
- bool mouse_is_down =
- (mouse_event.modifiers & WebInputEvent::LeftButtonDown) ||
- (mouse_event.modifiers & WebInputEvent::RightButtonDown) ||
- (mouse_event.modifiers & WebInputEvent::MiddleButtonDown);
- cocoa_event_.type = mouse_is_down ? NPCocoaEventMouseDragged
- : NPCocoaEventMouseMoved;
- return true;
- }
- case WebInputEvent::MouseEnter:
- cocoa_event_.type = NPCocoaEventMouseEntered;
- return true;
- case WebInputEvent::MouseLeave:
- cocoa_event_.type = NPCocoaEventMouseExited;
- return true;
- default:
- NOTREACHED();
- return false;
- }
-}
-
-bool CocoaPluginWebEventConverter::ConvertMouseWheelEvent(
- const WebMouseWheelEvent& wheel_event) {
- cocoa_event_.type = NPCocoaEventScrollWheel;
- cocoa_event_.data.mouse.pluginX = wheel_event.x;
- cocoa_event_.data.mouse.pluginY = wheel_event.y;
- cocoa_event_.data.mouse.modifierFlags |= CocoaModifiers(wheel_event);
- cocoa_event_.data.mouse.deltaX = wheel_event.deltaX;
- cocoa_event_.data.mouse.deltaY = wheel_event.deltaY;
- return true;
-}
-
-NSUInteger CocoaPluginWebEventConverter::CocoaModifiers(
- const WebInputEvent& web_event) {
- NSInteger modifiers = 0;
- if (web_event.modifiers & WebInputEvent::ControlKey)
- modifiers |= NSControlKeyMask;
- if (web_event.modifiers & WebInputEvent::ShiftKey)
- modifiers |= NSShiftKeyMask;
- if (web_event.modifiers & WebInputEvent::AltKey)
- modifiers |= NSAlternateKeyMask;
- if (web_event.modifiers & WebInputEvent::MetaKey)
- modifiers |= NSCommandKeyMask;
- if (CapsLockIsActive(web_event))
- modifiers |= NSAlphaShiftKeyMask;
- return modifiers;
-}
-
-bool CocoaPluginWebEventConverter::KeyIsModifier(int native_key_code) {
- switch (native_key_code) {
- case 55: // Left command
- case 54: // Right command
- case 58: // Left option
- case 61: // Right option
- case 59: // Left control
- case 62: // Right control
- case 56: // Left shift
- case 60: // Right shift
- case 57: // Caps lock
- return true;
- default:
- return false;
- }
-}
-
-#pragma mark -
-
-bool PluginWebEventConverter::InitWithEvent(const WebInputEvent& web_event) {
- if (web_event.type == WebInputEvent::MouseWheel) {
- return ConvertMouseWheelEvent(
- *static_cast<const WebMouseWheelEvent*>(&web_event));
- } else if (WebInputEvent::isMouseEventType(web_event.type)) {
- return ConvertMouseEvent(*static_cast<const WebMouseEvent*>(&web_event));
- } else if (WebInputEvent::isKeyboardEventType(web_event.type)) {
- return ConvertKeyboardEvent(
- *static_cast<const WebKeyboardEvent*>(&web_event));
- }
- DLOG(WARNING) << "Unknown event type " << web_event.type;
- return false;
-}
-
-#pragma mark -
-
-PluginWebEventConverter*
- PluginWebEventConverterFactory::CreateConverterForModel(
- NPEventModel event_model) {
- switch (event_model) {
- case NPEventModelCocoa:
- return new CocoaPluginWebEventConverter();
-#ifndef NP_NO_CARBON
- case NPEventModelCarbon:
- return new CarbonPluginWebEventConverter();
-#endif
- default:
- NOTIMPLEMENTED();
- return NULL;
- }
-}
diff --git a/webkit/glue/plugins/ppb_private.h b/webkit/glue/plugins/ppb_private.h
deleted file mode 100644
index b3d2b67..0000000
--- a/webkit/glue/plugins/ppb_private.h
+++ /dev/null
@@ -1,135 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PPB_PRIVATE_H_
-#define WEBKIT_GLUE_PLUGINS_PPB_PRIVATE_H_
-
-#include "ppapi/c/dev/ppb_font_dev.h"
-#include "ppapi/c/pp_instance.h"
-#include "ppapi/c/pp_module.h"
-#include "ppapi/c/pp_resource.h"
-#include "ppapi/c/pp_var.h"
-
-#define PPB_PRIVATE_INTERFACE "PPB_Private;1"
-
-// From the public PPB_Font_Dev file.
-struct PP_FontDescription_Dev;
-
-typedef enum {
- PP_RESOURCESTRING_PDFGETPASSWORD = 0,
- PP_RESOURCESTRING_PDFLOADING = 1,
- PP_RESOURCESTRING_PDFLOAD_FAILED = 2,
-} PP_ResourceString;
-
-typedef enum {
- PP_RESOURCEIMAGE_PDF_BUTTON_FTH = 0,
- PP_RESOURCEIMAGE_PDF_BUTTON_FTH_HOVER = 1,
- PP_RESOURCEIMAGE_PDF_BUTTON_FTH_PRESSED = 2,
- PP_RESOURCEIMAGE_PDF_BUTTON_FTW = 3,
- PP_RESOURCEIMAGE_PDF_BUTTON_FTW_HOVER = 4,
- PP_RESOURCEIMAGE_PDF_BUTTON_FTW_PRESSED = 5,
- PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN = 6,
- PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN_HOVER = 7,
- PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMIN_PRESSED = 8,
- PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMOUT = 9,
- PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMOUT_HOVER = 10,
- PP_RESOURCEIMAGE_PDF_BUTTON_ZOOMOUT_PRESSED = 11,
- PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_0 = 12,
- PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_1 = 13,
- PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_2 = 14,
- PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_3 = 15,
- PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_4 = 16,
- PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_5 = 17,
- PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_6 = 18,
- PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_7 = 19,
- PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_8 = 20,
- PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_9 = 21,
- PP_RESOURCEIMAGE_PDF_BUTTON_THUMBNAIL_NUM_BACKGROUND = 22,
-} PP_ResourceImage;
-
-typedef enum {
- PP_PRIVATEFONTCHARSET_ANSI = 0,
- PP_PRIVATEFONTCHARSET_DEFAULT = 1,
- PP_PRIVATEFONTCHARSET_SYMBOL = 2,
- PP_PRIVATEFONTCHARSET_MAC = 77,
- PP_PRIVATEFONTCHARSET_SHIFTJIS = 128,
- PP_PRIVATEFONTCHARSET_HANGUL = 129,
- PP_PRIVATEFONTCHARSET_JOHAB = 130,
- PP_PRIVATEFONTCHARSET_GB2312 =134,
- PP_PRIVATEFONTCHARSET_CHINESEBIG5 = 136,
- PP_PRIVATEFONTCHARSET_GREEK = 161,
- PP_PRIVATEFONTCHARSET_TURKISH = 162,
- PP_PRIVATEFONTCHARSET_VIETNAMESE = 163,
- PP_PRIVATEFONTCHARSET_HEBREW = 177,
- PP_PRIVATEFONTCHARSET_ARABIC = 178,
- PP_PRIVATEFONTCHARSET_BALTIC = 186,
- PP_PRIVATEFONTCHARSET_RUSSIAN = 204,
- PP_PRIVATEFONTCHARSET_THAI = 222,
- PP_PRIVATEFONTCHARSET_EASTEUROPE = 238,
- PP_PRIVATEFONTCHARSET_OEM = 255
-} PP_PrivateFontCharset;
-
-struct PP_PrivateFontFileDescription {
- const char* face;
- uint32_t weight;
- bool italic;
-};
-
-struct PP_PrivateFindResult {
- int start_index;
- int length;
-};
-
-struct PPB_Private {
- // Returns a localized string.
- PP_Var (*GetLocalizedString)(PP_Module module, PP_ResourceString string_id);
-
- // Returns a resource image.
- PP_Resource (*GetResourceImage)(PP_Module module,
- PP_ResourceImage image_id);
-
- // Returns a resource identifying a font file corresponding to the given font
- // request after applying the browser-specific fallback.
- //
- // Currently Linux-only.
- PP_Resource (*GetFontFileWithFallback)(
- PP_Module module,
- const PP_FontDescription_Dev* description,
- PP_PrivateFontCharset charset);
-
- // Given a resource previously returned by GetFontFileWithFallback, returns
- // a pointer to the requested font table. Linux only.
- bool (*GetFontTableForPrivateFontFile)(PP_Resource font_file,
- uint32_t table,
- void* output,
- uint32_t* output_length);
-
- // Search the given string using ICU. Use PPB_Core's MemFree on results when
- // done.
- void (*SearchString)(
- PP_Module module,
- const unsigned short* string,
- const unsigned short* term,
- bool case_sensitive,
- PP_PrivateFindResult** results,
- int* count);
-
- // Since WebFrame doesn't know about Pepper requests, it'll think the page has
- // finished loading even if there are outstanding requests by the plugin.
- // Take this out once WebFrame knows about requests by pepper plugins.
- void (*DidStartLoading)(PP_Instance instance);
- void (*DidStopLoading)(PP_Instance instance);
-
- // Sets content restriction for a full-page plugin (i.e. can't copy/print).
- // The value is a bitfield of ContentRestriction enums.
- void (*SetContentRestriction)(PP_Instance instance, int restrictions);
-
- // Use UMA so we know average pdf page count.
- void (*HistogramPDFPageCount)(int count);
-
- // Notifies the browser that the given action has been performed.
- void (*UserMetricsRecordAction)(PP_Var action);
-};
-
-#endif // WEBKIT_GLUE_PLUGINS_PPB_PRIVATE_H_
diff --git a/webkit/glue/plugins/ppb_private2.h b/webkit/glue/plugins/ppb_private2.h
deleted file mode 100644
index acf7831..0000000
--- a/webkit/glue/plugins/ppb_private2.h
+++ /dev/null
@@ -1,117 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PPB_PRIVATE2_H_
-#define WEBKIT_GLUE_PLUGINS_PPB_PRIVATE2_H_
-
-#ifdef _WIN32
-#include <windows.h>
-#endif
-
-#include "ppapi/c/pp_errors.h"
-#include "ppapi/c/pp_instance.h"
-#include "ppapi/c/pp_module.h"
-#include "ppapi/c/pp_point.h"
-#include "ppapi/c/pp_rect.h"
-#include "ppapi/c/pp_resource.h"
-#include "ppapi/c/pp_var.h"
-
-#define PPB_PRIVATE2_INTERFACE "PPB_Private2;4"
-
-#ifdef _WIN32
-typedef HANDLE PP_FileHandle;
-static const PP_FileHandle PP_kInvalidFileHandle = NULL;
-#else
-typedef int PP_FileHandle;
-static const PP_FileHandle PP_kInvalidFileHandle = -1;
-#endif
-
-struct PP_FontDescription_Dev;
-struct PP_FileInfo_Dev;
-
-struct PP_DirEntry_Dev {
- const char* name;
- bool is_dir;
-};
-
-struct PP_DirContents_Dev {
- int32_t count;
- PP_DirEntry_Dev* entries;
-};
-
-struct PPB_Private2 {
- // Sets or clears the rendering hint that the given plugin instance is always
- // on top of page content. Somewhat more optimized painting can be used in
- // this case.
- void (*SetInstanceAlwaysOnTop)(PP_Instance instance, bool on_top);
-
- bool (*DrawGlyphs)(PP_Resource pp_image_data,
- const PP_FontDescription_Dev* font_desc,
- uint32_t color,
- PP_Point position,
- PP_Rect clip,
- float transformation[3][3],
- uint32_t glyph_count,
- uint16_t glyph_indices[],
- PP_Point glyph_advances[]);
-
- // Retrieves the proxy that will be used for the given URL. The result will
- // be a string in PAC format, or an undefined var on error.
- PP_Var (*GetProxyForURL)(PP_Module module, const char* url);
-
- // Opens a module-local file, returning a file descriptor (posix) or a HANDLE
- // (win32) into file. Module-local file paths (here and below) are
- // '/'-separated UTF-8 strings, relative to a module-specific root. The return
- // value is the ppapi error, PP_OK if success, one of the PP_ERROR_* in case
- // of failure.
- int32_t (*OpenModuleLocalFile)(PP_Module module,
- const char* path,
- int32_t mode,
- PP_FileHandle* file);
-
- // Renames a module-local file. The return value is the ppapi error, PP_OK if
- // success, one of the PP_ERROR_* in case of failure.
- int32_t (*RenameModuleLocalFile)(PP_Module module,
- const char* path_from,
- const char* path_to);
-
- // Deletes a module-local file or directory. If recursive is set and the path
- // points to a directory, deletes all the contents of the directory. The
- // return value is the ppapi error, PP_OK if success, one of the PP_ERROR_* in
- // case of failure.
- int32_t (*DeleteModuleLocalFileOrDir)(PP_Module module,
- const char* path,
- bool recursive);
-
- // Creates a module-local directory. The return value is the ppapi error,
- // PP_OK if success, one of the PP_ERROR_* in case of failure.
- int32_t (*CreateModuleLocalDir)(PP_Module module, const char* path);
-
- // Queries information about a module-local file. The return value is the
- // ppapi error, PP_OK if success, one of the PP_ERROR_* in case of failure.
- int32_t (*QueryModuleLocalFile)(PP_Module module,
- const char* path,
- PP_FileInfo_Dev* info);
-
- // Gets the list of files contained in a module-local directory. The return
- // value is the ppapi error, PP_OK if success, one of the PP_ERROR_* in case
- // of failure. If non-NULL, the returned contents should be freed with
- // FreeModuleLocalDirContents.
- int32_t (*GetModuleLocalDirContents)(PP_Module module,
- const char* path,
- PP_DirContents_Dev** contents);
-
- // Frees the data allocated by GetModuleLocalDirContents.
- void (*FreeModuleLocalDirContents)(PP_Module module,
- PP_DirContents_Dev* contents);
-
- // Navigate to URL. May open a new tab if target is not "_self". Return true
- // if success. This differs from javascript:window.open() in that it bypasses
- // the popup blocker, even when this is not called from an event handler.
- bool (*NavigateToURL)(PP_Instance instance,
- const char* url,
- const char* target);
-};
-
-#endif // WEBKIT_GLUE_PLUGINS_PPB_PRIVATE2_H_
diff --git a/webkit/glue/plugins/ppp_private.h b/webkit/glue/plugins/ppp_private.h
deleted file mode 100644
index 7f5921e..0000000
--- a/webkit/glue/plugins/ppp_private.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_PPP_PRIVATE_H_
-#define WEBKIT_GLUE_PLUGINS_PPP_PRIVATE_H_
-
-#include "ppapi/c/pp_instance.h"
-#include "ppapi/c/pp_point.h"
-#include "ppapi/c/pp_var.h"
-
-#define PPP_PRIVATE_INTERFACE "PPP_Private;1"
-
-struct PPP_Private {
- // Returns an absolute URL if the position is over a link.
- PP_Var (*GetLinkAtPosition)(PP_Instance instance,
- PP_Point point);
-};
-
-#endif // WEBKIT_GLUE_PLUGINS_PPP_PRIVATE_H_
diff --git a/webkit/glue/plugins/quickdraw_drawing_manager_mac.cc b/webkit/glue/plugins/quickdraw_drawing_manager_mac.cc
deleted file mode 100644
index 424cc1e..0000000
--- a/webkit/glue/plugins/quickdraw_drawing_manager_mac.cc
+++ /dev/null
@@ -1,154 +0,0 @@
-// 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.
-
-#ifndef NP_NO_QUICKDRAW
-
-#include "webkit/glue/plugins/quickdraw_drawing_manager_mac.h"
-
-#include "webkit/glue/plugins/coregraphics_private_symbols_mac.h"
-
-// Turn off GCC warnings about deprecated functions (since QuickDraw is a
-// deprecated API). According to the GCC documentation, this can only be done
-// per file, not pushed and popped like some options can be.
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-
-QuickDrawDrawingManager::QuickDrawDrawingManager()
- : plugin_window_(NULL), target_context_(NULL), fast_path_enabled_(false),
- current_port_(NULL), target_world_(NULL), plugin_world_(NULL) {}
-
-QuickDrawDrawingManager::~QuickDrawDrawingManager() {
- DestroyGWorlds();
-}
-
-void QuickDrawDrawingManager::SetFastPathEnabled(bool enabled) {
- if (fast_path_enabled_ == enabled)
- return;
-
- fast_path_enabled_ = enabled;
- if (enabled) {
- if (!target_world_)
- UpdateGWorlds();
- // Copy our last window snapshot into our new source, since the plugin
- // may not repaint everything.
- CopyGWorldBits(target_world_, plugin_world_, plugin_size_);
- current_port_ = plugin_world_;
- } else {
- current_port_ = GetWindowPort(plugin_window_);
- }
-}
-
-void QuickDrawDrawingManager::SetTargetContext(CGContextRef context,
- const gfx::Size& plugin_size) {
- target_context_ = context;
- if (plugin_size != plugin_size_) {
- plugin_size_ = plugin_size;
- // Pitch the old GWorlds, since they are the wrong size now.
- DestroyGWorlds();
- if (fast_path_enabled_)
- UpdateGWorlds();
- }
-}
-
-void QuickDrawDrawingManager::SetPluginWindow(WindowRef window) {
- plugin_window_ = window;
- if (!fast_path_enabled_)
- current_port_ = GetWindowPort(window);
-}
-
-void QuickDrawDrawingManager::UpdateContext() {
- if (fast_path_enabled_)
- CopyGWorldBits(plugin_world_, target_world_, plugin_size_);
- else
- ScrapeWindow(plugin_window_, target_context_, plugin_size_);
-}
-
-bool QuickDrawDrawingManager::IsFastPathEnabled() {
- return fast_path_enabled_;
-}
-
-void QuickDrawDrawingManager::MakePortCurrent() {
- if (fast_path_enabled_)
- SetGWorld(current_port_, NULL);
- else
- SetPort(current_port_);
-}
-
-void QuickDrawDrawingManager::DestroyGWorlds() {
- if (plugin_world_) {
- DisposeGWorld(plugin_world_);
- plugin_world_ = NULL;
- }
- if (target_world_) {
- DisposeGWorld(target_world_);
- target_world_ = NULL;
- }
-}
-
-void QuickDrawDrawingManager::UpdateGWorlds() {
- DestroyGWorlds();
- if (!target_context_)
- return;
-
- Rect window_bounds = {
- 0, 0, plugin_size_.height(), plugin_size_.width()
- };
- // Create a GWorld pointing at the same bits as our target context.
- if (target_context_) {
- NewGWorldFromPtr(
- &target_world_, k32BGRAPixelFormat, &window_bounds, NULL, NULL, 0,
- static_cast<Ptr>(CGBitmapContextGetData(target_context_)),
- static_cast<SInt32>(CGBitmapContextGetBytesPerRow(target_context_)));
- }
- // Create a GWorld for the plugin to paint into whenever it wants; since
- // QuickDraw plugins don't draw at known times, they can't be allowed to draw
- // directly into the shared memory.
- NewGWorld(&plugin_world_, k32ARGBPixelFormat, &window_bounds,
- NULL, NULL, kNativeEndianPixMap);
- if (fast_path_enabled_)
- current_port_ = plugin_world_;
-}
-
-void QuickDrawDrawingManager::ScrapeWindow(WindowRef window,
- CGContextRef target_context,
- const gfx::Size& plugin_size) {
- if (!target_context)
- return;
-
- CGRect window_bounds = CGRectMake(0, 0,
- plugin_size.width(),
- plugin_size.height());
- CGWindowID window_id = HIWindowGetCGWindowID(window);
- CGContextSaveGState(target_context);
- CGContextTranslateCTM(target_context, 0, plugin_size.height());
- CGContextScaleCTM(target_context, 1.0, -1.0);
- CGContextCopyWindowCaptureContentsToRect(target_context, window_bounds,
- _CGSDefaultConnection(),
- window_id, 0);
- CGContextRestoreGState(target_context);
-}
-
-void QuickDrawDrawingManager::CopyGWorldBits(GWorldPtr source, GWorldPtr dest,
- const gfx::Size& plugin_size) {
- if (!(source && dest))
- return;
-
- Rect window_bounds = { 0, 0, plugin_size.height(), plugin_size.width() };
- PixMapHandle source_pixmap = GetGWorldPixMap(source);
- if (LockPixels(source_pixmap)) {
- PixMapHandle dest_pixmap = GetGWorldPixMap(dest);
- if (LockPixels(dest_pixmap)) {
- SetGWorld(dest, NULL);
- // Set foreground and background colors to avoid "colorizing" the image.
- ForeColor(blackColor);
- BackColor(whiteColor);
- CopyBits(reinterpret_cast<BitMap*>(*source_pixmap),
- reinterpret_cast<BitMap*>(*dest_pixmap),
- &window_bounds, &window_bounds, srcCopy, NULL);
- UnlockPixels(dest_pixmap);
- }
- UnlockPixels(source_pixmap);
- }
-}
-
-#endif // !NP_NO_QUICKDRAW
diff --git a/webkit/glue/plugins/quickdraw_drawing_manager_mac.h b/webkit/glue/plugins/quickdraw_drawing_manager_mac.h
deleted file mode 100644
index 8163f92..0000000
--- a/webkit/glue/plugins/quickdraw_drawing_manager_mac.h
+++ /dev/null
@@ -1,83 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_QUICKDRAW_DRAWING_MANAGER_MAC_H_
-#define WEBKIT_GLUE_QUICKDRAW_DRAWING_MANAGER_MAC_H_
-
-#ifndef NP_NO_QUICKDRAW
-
-#import <Carbon/Carbon.h>
-
-#include "gfx/rect.h"
-
-// Plugin helper class encapsulating the details of capturing what a QuickDraw
-// drawing model plugin draws, then drawing it into a CGContext.
-class QuickDrawDrawingManager {
- public:
- QuickDrawDrawingManager();
- ~QuickDrawDrawingManager();
-
- // Sets the mode used for plugin drawing. If enabled is true the plugin draws
- // into a GWorld that's not connected to a window, otherwise the plugin draws
- // into our the plugin's dummy window (which is slower, since the call we use
- // to scrape the window contents is much more expensive than copying between
- // GWorlds).
- void SetFastPathEnabled(bool enabled);
-
- // Returns true if the fast path is currently enabled.
- bool IsFastPathEnabled();
-
- // Sets the context that the plugin bits should be copied into when
- // UpdateContext is called. This object does not retain |context|, so the
- // caller must call SetTargetContext again if the context changes.
- // If the fast path is currently enabled, this call will cause the port to
- // change.
- void SetTargetContext(CGContextRef context, const gfx::Size& plugin_size);
-
- // Sets the window that is used by the plugin. This object does not own the
- // window, so the caler must call SetPluginWindow again if the window changes.
- void SetPluginWindow(WindowRef window);
-
- // Updates the target context with the current plugin bits.
- void UpdateContext();
-
- // Returns the port that the plugin should draw into. This returned port is
- // only valid until the next call to SetFastPathEnabled (or SetTargetContext
- // while the fast path is enabled).
- CGrafPtr port() { return current_port_; }
-
- // Makes the QuickDraw port current; should be called before calls where the
- // plugin might draw.
- void MakePortCurrent();
-
- private:
- // Updates the GWorlds used by the faster path.
- void UpdateGWorlds();
-
- // Deletes the GWorlds used by the faster path.
- void DestroyGWorlds();
-
- // Scrapes the contents of the window into the given context.
- // Used for the slower path.
- static void ScrapeWindow(WindowRef window, CGContextRef target_context,
- const gfx::Size& plugin_size);
-
- // Copies the source GWorld's bits into the target GWorld.
- // Used for the faster path.
- static void CopyGWorldBits(GWorldPtr source, GWorldPtr dest,
- const gfx::Size& plugin_size);
-
- WindowRef plugin_window_; // Weak reference.
- CGContextRef target_context_; // Weak reference.
- gfx::Size plugin_size_;
- bool fast_path_enabled_;
- CGrafPtr current_port_;
- // Variables used for the faster path:
- GWorldPtr target_world_; // Created lazily; may be NULL.
- GWorldPtr plugin_world_; // Created lazily; may be NULL.
-};
-
-#endif // !NP_NO_QUICKDRAW
-
-#endif // QUICKDRAW_DRAWING_MANAGER_MAC
diff --git a/webkit/glue/plugins/test/Info.plist b/webkit/glue/plugins/test/Info.plist
deleted file mode 100644
index 37145fd..0000000
--- a/webkit/glue/plugins/test/Info.plist
+++ /dev/null
@@ -1,46 +0,0 @@
-<?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>NPAPITestPlugIn</string>
- <key>CFBundleIdentifier</key>
- <string>org.chromium.npapi_test_plugin</string>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
- <key>CFBundleExecutable</key>
- <string>${EXECUTABLE_NAME}</string>
- <key>CFBundleName</key>
- <string>${PRODUCT_NAME}</string>
- <key>CFBundlePackageType</key>
- <string>BRPL</string>
- <key>CFBundleShortVersionString</key>
- <string>1.0</string>
- <key>CFBundleSignature</key>
- <string>????</string>
- <key>CFBundleVersion</key>
- <string>1.0</string>
- <key>CFPlugInDynamicRegisterFunction</key>
- <string></string>
- <key>CFPlugInDynamicRegistration</key>
- <string>NO</string>
- <key>WebPluginDescription</key>
- <string>Simple NPAPI plug-in for Chromium unit tests</string>
- <key>WebPluginMIMETypes</key>
- <dict>
- <key>application/vnd.npapi-test</key>
- <dict>
- <key>WebPluginExtensions</key>
- <array>
- <string>npapitest</string>
- </array>
- <key>WebPluginTypeDescription</key>
- <string>test npapi</string>
- </dict>
- </dict>
- <key>WebPluginName</key>
- <string>Chromium NPAPI Test Plugin</string>
-</dict>
-</plist>
diff --git a/webkit/glue/plugins/test/npapi_constants.cc b/webkit/glue/plugins/test/npapi_constants.cc
deleted file mode 100644
index 75cc68f..0000000
--- a/webkit/glue/plugins/test/npapi_constants.cc
+++ /dev/null
@@ -1,10 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/test/npapi_constants.h"
-
-namespace NPAPIClient {
-const char kTestCompleteCookie[] = "status";
-const char kTestCompleteSuccess[] = "OK";
-}
diff --git a/webkit/glue/plugins/test/npapi_constants.h b/webkit/glue/plugins/test/npapi_constants.h
deleted file mode 100644
index 6570c35..0000000
--- a/webkit/glue/plugins/test/npapi_constants.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// 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.
-
-// Constants for the NPAPI test
-
-#ifndef WEBKIT_PORT_PLUGINS_TEST_NPAPI_CONSTANTS_H__
-#define WEBKIT_PORT_PLUGINS_TEST_NPAPI_CONSTANTS_H__
-
-namespace NPAPIClient {
-// The name of the cookie which will be used to communicate between
-// the plugin and the test harness.
-extern const char kTestCompleteCookie[];
-
-// The cookie value which will be sent to the client upon successful
-// test.
-extern const char kTestCompleteSuccess[];
-}
-#endif // WEBKIT_PORT_PLUGINS_TEST_NPAPI_CONSTANTS_H__
diff --git a/webkit/glue/plugins/test/npapi_test.cc b/webkit/glue/plugins/test/npapi_test.cc
deleted file mode 100644
index 895a842..0000000
--- a/webkit/glue/plugins/test/npapi_test.cc
+++ /dev/null
@@ -1,122 +0,0 @@
-// 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.
-
-//
-// npapitest
-//
-// This is a NPAPI Plugin Program which is used to test the Browser's NPAPI
-// host implementation. It is used in conjunction with the npapi_unittest.
-//
-// As a NPAPI Plugin, you can invoke it by creating a web page of the following
-// type:
-//
-// <embed src="content-to-load" type="application/vnd.npapi-test"
-// name="test-name">
-//
-// arguments:
-// src: This is the initial content which will be sent to the plugin.
-// type: Must be "application/vnd.npapi-test"
-// name: The testcase to run when invoked
-// id: The id of the test being run (for testing concurrent plugins)
-//
-// The Plugin drives the actual test, calling host functions and validating the
-// Host callbacks which it receives. It is the duty of the plugin to record
-// all errors.
-//
-// To indicate test completion, the plugin expects the containing HTML page to
-// implement two javascript functions:
-// onSuccess(string testname);
-// onFailure(string testname, string results);
-// The HTML host pages used in this test will then set a document cookie
-// which the automated test framework can poll for and discover that the
-// test has completed.
-//
-//
-// TESTS
-// When the PluginClient receives a NPP_New callback from the browser,
-// it looks at the "name" argument which is passed in. It verifies that
-// the name matches a known test, and instantiates that test. The test is
-// a subclass of PluginTest.
-//
-//
-
-#include "base/basictypes.h"
-
-#if defined(OS_WIN)
-#include <windows.h>
-#endif
-
-#if defined(__GNUC__) && __GNUC__ >= 4
-#define EXPORT __attribute__((visibility ("default")))
-#else
-#define EXPORT
-#endif
-
-#include "webkit/glue/plugins/test/plugin_client.h"
-
-#if defined(OS_WIN)
-BOOL API_CALL DllMain(HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved) {
- return TRUE;
-}
-#endif
-
-extern "C" {
-EXPORT NPError API_CALL NP_GetEntryPoints(NPPluginFuncs* pFuncs) {
- return NPAPIClient::PluginClient::GetEntryPoints(pFuncs);
-}
-
-EXPORT NPError API_CALL NP_Shutdown() {
- return NPAPIClient::PluginClient::Shutdown();
-}
-
-#if defined(OS_WIN) || defined(OS_MACOSX)
-EXPORT NPError API_CALL NP_Initialize(NPNetscapeFuncs* npnFuncs) {
- return NPAPIClient::PluginClient::Initialize(npnFuncs);
-}
-#elif defined(OS_POSIX)
-EXPORT NPError API_CALL NP_Initialize(NPNetscapeFuncs* npnFuncs,
- NPPluginFuncs* nppFuncs) {
- NPError error = NPAPIClient::PluginClient::Initialize(npnFuncs);
- if (error == NPERR_NO_ERROR) {
- error = NP_GetEntryPoints(nppFuncs);
- }
- return error;
-}
-
-EXPORT NPError API_CALL NP_GetValue(NPP instance, NPPVariable variable,
- void* value) {
- NPError err = NPERR_NO_ERROR;
-
- switch (variable) {
- case NPPVpluginNameString:
- *(static_cast<const char**>(value)) = "NPAPI Test Plugin";
- break;
- case NPPVpluginDescriptionString:
- *(static_cast<const char**>(value)) =
- "Simple NPAPI plug-in for Chromium unit tests";
- break;
- case NPPVpluginNeedsXEmbed:
- *(static_cast<NPBool*>(value)) = true;
- break;
- default:
- err = NPERR_GENERIC_ERROR;
- break;
- }
-
- return err;
-}
-
-EXPORT const char* API_CALL NP_GetMIMEDescription(void) {
- // The layout test LayoutTests/fast/js/navigator-mimeTypes-length.html
- // asserts that the number of mimetypes handled by plugins should be
- // greater than the number of plugins. We specify a mimetype here so
- // this plugin has at least one.
- return "application/vnd.npapi-test:npapitest:test npapi";
-}
-#endif // OS_POSIX
-} // extern "C"
-
-namespace WebCore {
- const char* currentTextBreakLocaleID() { return "en_us"; }
-}
diff --git a/webkit/glue/plugins/test/npapi_test.def b/webkit/glue/plugins/test/npapi_test.def
deleted file mode 100644
index 4481c16..0000000
--- a/webkit/glue/plugins/test/npapi_test.def
+++ /dev/null
@@ -1,6 +0,0 @@
-LIBRARY npapi_test_plugin
-
-EXPORTS
- NP_GetEntryPoints @1
- NP_Initialize @2
- NP_Shutdown @3
diff --git a/webkit/glue/plugins/test/npapi_test.rc b/webkit/glue/plugins/test/npapi_test.rc
deleted file mode 100644
index 524dda4..0000000
--- a/webkit/glue/plugins/test/npapi_test.rc
+++ /dev/null
@@ -1,102 +0,0 @@
-// Microsoft Visual C++ generated resource script.
-//
-#include "resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include "afxres.h"
-
-/////////////////////////////////////////////////////////////////////////////
-#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
- "#include ""afxres.h""\r\n"
- "\0"
-END
-
-3 TEXTINCLUDE
-BEGIN
- "\r\n"
- "\0"
-END
-
-#endif // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Version
-//
-
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,0,0,1
- PRODUCTVERSION 1,0,0,1
- FILEFLAGSMASK 0x17L
-#ifdef _DEBUG
- FILEFLAGS 0x1L
-#else
- FILEFLAGS 0x0L
-#endif
- FILEOS 0x4L
- FILETYPE 0x2L
- FILESUBTYPE 0x0L
-BEGIN
- BLOCK "StringFileInfo"
- BEGIN
- BLOCK "040904e4"
- BEGIN
- VALUE "FileDescription", "NPAPI Test Plugin"
- VALUE "FileVersion", "1, 0, 0, 1"
- VALUE "InternalName", "npapi_test_plugin"
- VALUE "LegalCopyright", "Copyright (C) 2007"
- VALUE "MIMEType", "application/vnd.npapi-test"
- VALUE "OriginalFilename", "npapi_test_plugin.dll"
- VALUE "ProductName", "NPAPI Test Plugin"
- VALUE "ProductVersion", "1, 0, 0, 1"
- END
- END
- BLOCK "VarFileInfo"
- BEGIN
- VALUE "Translation", 0x409, 1252
- END
-END
-
-#endif // English (U.S.) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-
-
-/////////////////////////////////////////////////////////////////////////////
-#endif // not APSTUDIO_INVOKED
-
diff --git a/webkit/glue/plugins/test/plugin_arguments_test.cc b/webkit/glue/plugins/test/plugin_arguments_test.cc
deleted file mode 100644
index 46ccf43..0000000
--- a/webkit/glue/plugins/test/plugin_arguments_test.cc
+++ /dev/null
@@ -1,69 +0,0 @@
-// 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.
-
-#include "base/basictypes.h"
-#include "base/string_util.h"
-#include "base/stringprintf.h"
-
-#include "webkit/glue/plugins/test/plugin_arguments_test.h"
-
-namespace NPAPIClient {
-
-PluginArgumentsTest::PluginArgumentsTest(NPP id,
- NPNetscapeFuncs *host_functions)
- : PluginTest(id, host_functions) {
-}
-
-NPError PluginArgumentsTest::New(uint16 mode, int16 argc,
- const char* argn[], const char* argv[],
- NPSavedData* saved) {
- // mode: should be the string either "NP_EMBED" or "NP_FULL",
- // depending on the mode passed in.
- // count: the count of "val" arguments. If the value is
- // 2, then we'll find arguments "val1" and "val2". If
- // the value is 0, then there will be no "val" arguments.
- // size: each val string will be this size * the value's
- // index. E.g if size is "10", val1 will be 10bytes,
- // and val2 will be 20bytes.
- const char *mode_string = GetArgValue("mode", argc, argn, argv);
- ExpectAsciiStringNotEqual(mode_string, (const char *)NULL);
- if (mode_string != NULL) {
- std::string mode_dep_string = mode_string;
- if (mode == NP_EMBED)
- ExpectStringLowerCaseEqual(mode_dep_string, "np_embed");
- else if (mode == NP_FULL)
- ExpectStringLowerCaseEqual(mode_dep_string, "np_full");
- }
-
- const char *count_string = GetArgValue("count", argc, argn, argv);
- if (count_string != NULL) {
- int max_args = atoi(count_string);
-
- const char *size_string = GetArgValue("size", argc, argn, argv);
- ExpectAsciiStringNotEqual(size_string, (const char *)NULL);
- if (size_string != NULL) {
- int size = atoi(size_string);
-
- for (int index = 1; index <= max_args; index++) {
- std::string arg_name = base::StringPrintf("%s%d", "val", index);
- const char *val_string = GetArgValue(arg_name.c_str(), argc, argn,
- argv);
- ExpectAsciiStringNotEqual(val_string, (const char*)NULL);
- if (val_string != NULL)
- ExpectIntegerEqual((int)strlen(val_string), (index*size));
- }
- }
- }
-
- return PluginTest::New(mode, argc, argn, argv, saved);
-}
-
-NPError PluginArgumentsTest::SetWindow(NPWindow* pNPWindow) {
- // This test just tests the arguments. We're done now.
- this->SignalTestCompleted();
-
- return NPERR_NO_ERROR;
-}
-
-} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_arguments_test.h b/webkit/glue/plugins/test/plugin_arguments_test.h
deleted file mode 100644
index aa05f19..0000000
--- a/webkit/glue/plugins/test/plugin_arguments_test.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_PORT_PLUGINS_TEST_PLUGIN_ARGUMENTS_TEST_H__
-#define WEBKIT_PORT_PLUGINS_TEST_PLUGIN_ARGUMENTS_TEST_H__
-
-#include "webkit/glue/plugins/test/plugin_test.h"
-
-namespace NPAPIClient {
-
-// The PluginArgumentsTest test that we properly receive arguments
-// intended for the plugin.
-//
-// This is basically overkill for testing that the arguments passed
-// to the plugin match what we expect.
-//
-// We expect to find the following arguments:
-// mode: should be the string either "NP_EMBED" or "NP_FULL",
-// depending on the mode passed in.
-// count: the count of "val" arguments. If the value is
-// 2, then we'll find arguments "val1" and "val2". If
-// the value is 0, then there will be no "val" arguments.
-// size: each val string will be this size * the value's
-// index. E.g if size is "10", val1 will be 10bytes,
-// and val2 will be 20bytes.
-//
-class PluginArgumentsTest : public PluginTest {
- public:
- // Constructor.
- PluginArgumentsTest(NPP id, NPNetscapeFuncs *host_functions);
-
- // Initialize this PluginTest based on the arguments from NPP_New.
- virtual NPError New(uint16 mode, int16 argc, const char* argn[],
- const char* argv[], NPSavedData* saved);
-
- // NPAPI SetWindow handler.
- virtual NPError SetWindow(NPWindow* pNPWindow);
-};
-
-} // namespace NPAPIClient
-
-#endif // WEBKIT_PORT_PLUGINS_TEST_PLUGIN_ARGUMENTS_TEST_H__
diff --git a/webkit/glue/plugins/test/plugin_client.cc b/webkit/glue/plugins/test/plugin_client.cc
deleted file mode 100644
index 8358340..0000000
--- a/webkit/glue/plugins/test/plugin_client.cc
+++ /dev/null
@@ -1,240 +0,0 @@
-// Copyright (c) 2009 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 "webkit/glue/plugins/test/plugin_client.h"
-
-#include "base/string_util.h"
-#include "webkit/glue/plugins/test/plugin_test.h"
-#include "webkit/glue/plugins/test/plugin_test_factory.h"
-
-namespace NPAPIClient {
-
-NPNetscapeFuncs* PluginClient::host_functions_;
-
-NPError PluginClient::GetEntryPoints(NPPluginFuncs* pFuncs) {
- if (pFuncs == NULL)
- return NPERR_INVALID_FUNCTABLE_ERROR;
-
- if (pFuncs->size < sizeof(NPPluginFuncs))
- return NPERR_INVALID_FUNCTABLE_ERROR;
-
- pFuncs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
- pFuncs->newp = NPP_New;
- pFuncs->destroy = NPP_Destroy;
- pFuncs->setwindow = NPP_SetWindow;
- pFuncs->newstream = NPP_NewStream;
- pFuncs->destroystream = NPP_DestroyStream;
- pFuncs->asfile = NPP_StreamAsFile;
- pFuncs->writeready = NPP_WriteReady;
- pFuncs->write = NPP_Write;
- pFuncs->print = NPP_Print;
- pFuncs->event = NPP_HandleEvent;
- pFuncs->urlnotify = NPP_URLNotify;
- pFuncs->getvalue = NPP_GetValue;
- pFuncs->setvalue = NPP_SetValue;
- pFuncs->javaClass = NULL;
- pFuncs->urlredirectnotify = NPP_URLRedirectNotify;
-
- return NPERR_NO_ERROR;
-}
-
-NPError PluginClient::Initialize(NPNetscapeFuncs* pFuncs) {
- if (pFuncs == NULL) {
- return NPERR_INVALID_FUNCTABLE_ERROR;
- }
-
- if (static_cast<unsigned char>((pFuncs->version >> 8) & 0xff) >
- NP_VERSION_MAJOR) {
- return NPERR_INCOMPATIBLE_VERSION_ERROR;
- }
-
-#if defined(OS_WIN)
- // Check if we should crash.
- HANDLE crash_event = CreateEvent(NULL, TRUE, FALSE, L"TestPluginCrashOnInit");
- if (WaitForSingleObject(crash_event, 0) == WAIT_OBJECT_0) {
- int *zero = NULL;
- *zero = 0;
- }
- CloseHandle(crash_event);
-#endif
-
- host_functions_ = pFuncs;
-
- return NPERR_NO_ERROR;
-}
-
-NPError PluginClient::Shutdown() {
- return NPERR_NO_ERROR;
-}
-
-} // namespace NPAPIClient
-
-extern "C" {
-NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode,
- int16 argc, char* argn[], char* argv[], NPSavedData* saved) {
- if (instance == NULL)
- return NPERR_INVALID_INSTANCE_ERROR;
-
- // We look at the test name requested via the plugin arguments. We match
- // that against a given test and try to instantiate it.
-
- // lookup the name parameter
- std::string test_name;
- for (int name_index = 0; name_index < argc; name_index++) {
- if (base::strcasecmp(argn[name_index], "name") == 0) {
- test_name = argv[name_index];
- break;
- }
- }
- if (test_name.empty())
- return NPERR_GENERIC_ERROR; // no name found
-
- NPAPIClient::PluginTest* new_test = NPAPIClient::CreatePluginTest(test_name,
- instance, NPAPIClient::PluginClient::HostFunctions());
- if (new_test == NULL) {
- // If we don't have a test case for this, create a
- // generic one which basically never fails.
- LOG(WARNING) << "Unknown test name '" << test_name
- << "'; using default test.";
- new_test = new NPAPIClient::PluginTest(instance,
- NPAPIClient::PluginClient::HostFunctions());
- }
-
- NPError ret = new_test->New(mode, argc, (const char**)argn,
- (const char**)argv, saved);
- if ((ret == NPERR_NO_ERROR) && new_test->IsWindowless()) {
- NPAPIClient::PluginClient::HostFunctions()->setvalue(
- instance, NPPVpluginWindowBool, NULL);
- }
-
- return ret;
-}
-
-NPError NPP_Destroy(NPP instance, NPSavedData** save) {
- if (instance == NULL)
- return NPERR_INVALID_INSTANCE_ERROR;
-
- NPAPIClient::PluginTest* plugin =
- reinterpret_cast<NPAPIClient::PluginTest*>(instance->pdata);
-
- NPError rv = plugin->Destroy();
- delete plugin;
- return rv;
-}
-
-NPError NPP_SetWindow(NPP instance, NPWindow* pNPWindow) {
- if (instance == NULL)
- return NPERR_INVALID_INSTANCE_ERROR;
-
- NPAPIClient::PluginTest* plugin =
- reinterpret_cast<NPAPIClient::PluginTest*>(instance->pdata);
-
- return plugin->SetWindow(pNPWindow);
-}
-
-NPError NPP_NewStream(NPP instance, NPMIMEType type,
- NPStream* stream, NPBool seekable, uint16* stype) {
- if (instance == NULL)
- return NPERR_INVALID_INSTANCE_ERROR;
-
- NPAPIClient::PluginTest* plugin =
- reinterpret_cast<NPAPIClient::PluginTest*>(instance->pdata);
-
- return plugin->NewStream(type, stream, seekable, stype);
-}
-
-int32 NPP_WriteReady(NPP instance, NPStream *stream) {
- if (instance == NULL)
- return NPERR_INVALID_INSTANCE_ERROR;
-
- NPAPIClient::PluginTest* plugin =
- reinterpret_cast<NPAPIClient::PluginTest*>(instance->pdata);
-
- return plugin->WriteReady(stream);
-}
-
-int32 NPP_Write(NPP instance, NPStream *stream, int32 offset,
- int32 len, void *buffer) {
- if (instance == NULL)
- return NPERR_INVALID_INSTANCE_ERROR;
-
- NPAPIClient::PluginTest* plugin =
- reinterpret_cast<NPAPIClient::PluginTest*>(instance->pdata);
-
- return plugin->Write(stream, offset, len, buffer);
-}
-
-NPError NPP_DestroyStream(NPP instance, NPStream *stream, NPError reason) {
- if (instance == NULL)
- return NPERR_INVALID_INSTANCE_ERROR;
-
- NPAPIClient::PluginTest* plugin =
- reinterpret_cast<NPAPIClient::PluginTest*>(instance->pdata);
-
- return plugin->DestroyStream(stream, reason);
-}
-
-void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname) {
- if (instance == NULL)
- return;
-
- NPAPIClient::PluginTest* plugin =
- reinterpret_cast<NPAPIClient::PluginTest*>(instance->pdata);
-
- return plugin->StreamAsFile(stream, fname);
-}
-
-void NPP_Print(NPP instance, NPPrint* printInfo) {
- if (instance == NULL)
- return;
-
- // XXXMB - do work here.
-}
-
-void NPP_URLNotify(NPP instance, const char* url, NPReason reason,
- void* notifyData) {
- if (instance == NULL)
- return;
-
- NPAPIClient::PluginTest* plugin =
- reinterpret_cast<NPAPIClient::PluginTest*>(instance->pdata);
-
- return plugin->URLNotify(url, reason, notifyData);
-}
-
-NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value) {
- if (instance == NULL)
- return NPERR_INVALID_INSTANCE_ERROR;
-
- // XXXMB - do work here.
- return NPERR_GENERIC_ERROR;
-}
-
-NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value) {
- if (instance == NULL)
- return NPERR_INVALID_INSTANCE_ERROR;
-
- // XXXMB - do work here.
- return NPERR_GENERIC_ERROR;
-}
-
-int16 NPP_HandleEvent(NPP instance, void* event) {
- if (instance == NULL)
- return 0;
-
- NPAPIClient::PluginTest* plugin =
- reinterpret_cast<NPAPIClient::PluginTest*>(instance->pdata);
-
- return plugin->HandleEvent(event);
-}
-
-void NPP_URLRedirectNotify(NPP instance, const char* url, int32_t status,
- void* notify_data) {
- if (instance) {
- NPAPIClient::PluginTest* plugin =
- reinterpret_cast<NPAPIClient::PluginTest*>(instance->pdata);
- plugin->URLRedirectNotify(url, status, notify_data);
- }
-}
-} // extern "C"
diff --git a/webkit/glue/plugins/test/plugin_client.h b/webkit/glue/plugins/test/plugin_client.h
deleted file mode 100644
index a6291b0..0000000
--- a/webkit/glue/plugins/test/plugin_client.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_PORT_PLUGINS_TEST_PLUGIN_CLIENT_H__
-#define WEBKIT_PORT_PLUGINS_TEST_PLUGIN_CLIENT_H__
-
-#include "third_party/npapi/bindings/npapi.h"
-#include "third_party/npapi/bindings/nphostapi.h"
-
-namespace NPAPIClient {
-
-// A PluginClient is a NPAPI Plugin. This class contains
-// the bootstrapping functions used by the browser to load
-// the plugin.
-class PluginClient {
- public:
- // Although not documented in the NPAPI specification, this function
- // gets the list of entry points in the NPAPI Plugin (client) for the
- // NPAPI Host to call.
- static NPError GetEntryPoints(NPPluginFuncs* pFuncs);
-
- // The browser calls this function only once: when a plug-in is loaded,
- // before the first instance is created. This is the first function that
- // the browser calls. NP_Initialize tells the plug-in that the browser has
- // loaded it and provides global initialization. Allocate any memory or
- // resources shared by all instances of your plug-in at this time.
- static NPError Initialize(NPNetscapeFuncs* pFuncs);
-
- // The browser calls this function once after the last instance of your
- // plug-in is destroyed, before unloading the plug-in library itself. Use
- // NP_Shutdown to delete any data allocated in NP_Initialize to be shared
- // by all instances of a plug-in.
- static NPError Shutdown();
-
- // The table of functions provided by the host.
- static NPNetscapeFuncs *HostFunctions() { return host_functions_; }
-
- private:
- static NPNetscapeFuncs* host_functions_;
-};
-
-} // namespace NPAPIClient
-
-#endif // WEBKIT_PORT_PLUGINS_TEST_PLUGIN_CLIENT_H__
diff --git a/webkit/glue/plugins/test/plugin_create_instance_in_paint.cc b/webkit/glue/plugins/test/plugin_create_instance_in_paint.cc
deleted file mode 100644
index f98f89b..0000000
--- a/webkit/glue/plugins/test/plugin_create_instance_in_paint.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright (c) 2009 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 "webkit/glue/plugins/test/plugin_create_instance_in_paint.h"
-
-#include "webkit/glue/plugins/test/plugin_client.h"
-
-namespace NPAPIClient {
-
-CreateInstanceInPaintTest::CreateInstanceInPaintTest(
- NPP id, NPNetscapeFuncs *host_functions)
- : PluginTest(id, host_functions),
- window_(NULL), created_(false) {
-}
-
-NPError CreateInstanceInPaintTest::SetWindow(NPWindow* pNPWindow) {
- if (pNPWindow->window == NULL)
- return NPERR_NO_ERROR;
-
- if (test_id() == "1") {
- if (!window_) {
- static ATOM window_class = 0;
- if (!window_class) {
- WNDCLASSEX wcex;
- wcex.cbSize = sizeof(WNDCLASSEX);
- wcex.style = CS_DBLCLKS;
- wcex.lpfnWndProc =
- &NPAPIClient::CreateInstanceInPaintTest::WindowProc;
- wcex.cbClsExtra = 0;
- wcex.cbWndExtra = 0;
- wcex.hInstance = GetModuleHandle(NULL);
- wcex.hIcon = 0;
- wcex.hCursor = 0;
- wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW+1);
- wcex.lpszMenuName = 0;
- wcex.lpszClassName = L"CreateInstanceInPaintTestWindowClass";
- wcex.hIconSm = 0;
- window_class = RegisterClassEx(&wcex);
- }
-
- HWND parent = reinterpret_cast<HWND>(pNPWindow->window);
- window_ = CreateWindowEx(
- WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR,
- MAKEINTATOM(window_class), 0,
- WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE ,
- 0, 0, 100, 100, parent, 0, GetModuleHandle(NULL), 0);
- DCHECK(window_);
- // TODO: this property leaks.
- ::SetProp(window_, L"Plugin_Instance", this);
- }
- } else if (test_id() == "2") {
- SignalTestCompleted();
- } else {
- NOTREACHED();
- }
- return NPERR_NO_ERROR;
-}
-
-LRESULT CALLBACK CreateInstanceInPaintTest::WindowProc(
- HWND window, UINT message, WPARAM wparam, LPARAM lparam) {
- if (message == WM_PAINT) {
- CreateInstanceInPaintTest* this_instance =
- reinterpret_cast<CreateInstanceInPaintTest*>
- (::GetProp(window, L"Plugin_Instance"));
- if (this_instance->test_id() == "1" && !this_instance->created_) {
- ::RemoveProp(window, L"Plugin_Instance");
- this_instance->created_ = true;
- this_instance->HostFunctions()->geturlnotify(
- this_instance->id(), "javascript:CreateNewInstance()", NULL,
- reinterpret_cast<void*>(1));
- }
- }
-
- return DefWindowProc(window, message, wparam, lparam);
-}
-
-} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_create_instance_in_paint.h b/webkit/glue/plugins/test/plugin_create_instance_in_paint.h
deleted file mode 100644
index 84d7a94..0000000
--- a/webkit/glue/plugins/test/plugin_create_instance_in_paint.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) 2009 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 WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_CREATE_INSTANCE_IN_PAINT_H
-#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_CREATE_INSTANCE_IN_PAINT_H
-
-#include "webkit/glue/plugins/test/plugin_test.h"
-
-namespace NPAPIClient {
-
-// This class tests that creating a new plugin via script while handling a
-// Windows message doesn't cause a deadlock.
-class CreateInstanceInPaintTest : public PluginTest {
- public:
- // Constructor.
- CreateInstanceInPaintTest(NPP id, NPNetscapeFuncs *host_functions);
- //
- // NPAPI functions
- //
- virtual NPError SetWindow(NPWindow* pNPWindow);
-
- private:
- static LRESULT CALLBACK WindowProc(
- HWND window, UINT message, WPARAM wparam, LPARAM lparam);
-
- HWND window_;
- bool created_;
-};
-
-} // namespace NPAPIClient
-
-#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_CREATE_INSTANCE_IN_PAINT_H
diff --git a/webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.cc b/webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.cc
deleted file mode 100644
index 15318b4..0000000
--- a/webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.h"
-
-#include "webkit/glue/plugins/test/plugin_client.h"
-
-namespace NPAPIClient {
-
-#define kUrl "javascript:window.location+\"\""
-#define kUrlStreamId 1
-
-DeletePluginInStreamTest::DeletePluginInStreamTest(NPP id, NPNetscapeFuncs *host_functions)
- : PluginTest(id, host_functions),
- test_started_(false) {
-}
-
-NPError DeletePluginInStreamTest::SetWindow(NPWindow* pNPWindow) {
- if (pNPWindow->window == NULL)
- return NPERR_NO_ERROR;
-
- if (!test_started_) {
- std::string url = "self_delete_plugin_stream.html";
- HostFunctions()->geturlnotify(id(), url.c_str(), NULL,
- reinterpret_cast<void*>(kUrlStreamId));
- test_started_ = true;
- }
- return NPERR_NO_ERROR;
-}
-
-NPError DeletePluginInStreamTest::NewStream(NPMIMEType type, NPStream* stream,
- NPBool seekable, uint16* stype) {
- NPIdentifier delete_id = HostFunctions()->getstringidentifier("DeletePluginWithinScript");
-
- NPObject *window_obj = NULL;
- HostFunctions()->getvalue(id(), NPNVWindowNPObject, &window_obj);
-
- NPVariant rv;
- HostFunctions()->invoke(id(), window_obj, delete_id, NULL, 0, &rv);
-
- return NPERR_NO_ERROR;
-}
-
-} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.h b/webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.h
deleted file mode 100644
index 418e976..0000000
--- a/webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_DELETE_PLUGIN_IN_STREAM_TEST_H
-#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_DELETE_PLUGIN_IN_STREAM_TEST_H
-
-#include "webkit/glue/plugins/test/plugin_test.h"
-
-namespace NPAPIClient {
-
-// This class tests
-class DeletePluginInStreamTest : public PluginTest {
- public:
- // Constructor.
- DeletePluginInStreamTest(NPP id, NPNetscapeFuncs *host_functions);
- //
- // NPAPI functions
- //
- virtual NPError SetWindow(NPWindow* pNPWindow);
- virtual NPError NewStream(NPMIMEType type, NPStream* stream,
- NPBool seekable, uint16* stype);
- private:
- bool test_started_;
- std::string self_url_;
-};
-
-} // namespace NPAPIClient
-
-#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_DELETE_PLUGIN_IN_STREAM_TEST_H
diff --git a/webkit/glue/plugins/test/plugin_get_javascript_url2_test.cc b/webkit/glue/plugins/test/plugin_get_javascript_url2_test.cc
deleted file mode 100644
index d17dced..0000000
--- a/webkit/glue/plugins/test/plugin_get_javascript_url2_test.cc
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright (c) 2006-2009 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 "webkit/glue/plugins/test/plugin_get_javascript_url2_test.h"
-
-#include "base/basictypes.h"
-
-// url for "self".
-#define SELF_URL "javascript:window.location+\"\""
-// The identifier for the self url stream.
-#define SELF_URL_STREAM_ID 1
-
-// The identifier for the fetched url stream.
-#define FETCHED_URL_STREAM_ID 2
-
-// The maximum chunk size of stream data.
-#define STREAM_CHUNK 197
-
-const int kNPNEvaluateTimerID = 100;
-const int kNPNEvaluateTimerElapse = 50;
-
-namespace NPAPIClient {
-
-ExecuteGetJavascriptUrl2Test::ExecuteGetJavascriptUrl2Test(
- NPP id, NPNetscapeFuncs *host_functions)
- : PluginTest(id, host_functions),
- test_started_(false) {
-}
-
-NPError ExecuteGetJavascriptUrl2Test::SetWindow(NPWindow* pNPWindow) {
- if (pNPWindow->window == NULL)
- return NPERR_NO_ERROR;
-
- if (!test_started_) {
- std::string url = SELF_URL;
- HostFunctions()->geturlnotify(id(), url.c_str(), "_self",
- reinterpret_cast<void*>(SELF_URL_STREAM_ID));
- test_started_ = true;
- }
- return NPERR_NO_ERROR;
-}
-
-NPError ExecuteGetJavascriptUrl2Test::NewStream(NPMIMEType type, NPStream* stream,
- NPBool seekable, uint16* stype) {
- if (stream == NULL) {
- SetError("NewStream got null stream");
- return NPERR_INVALID_PARAM;
- }
-
- COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData),
- cast_validity_check);
- unsigned long stream_id = reinterpret_cast<unsigned long>(stream->notifyData);
- switch (stream_id) {
- case SELF_URL_STREAM_ID:
- break;
- default:
- SetError("Unexpected NewStream callback");
- break;
- }
- return NPERR_NO_ERROR;
-}
-
-int32 ExecuteGetJavascriptUrl2Test::WriteReady(NPStream *stream) {
- return STREAM_CHUNK;
-}
-
-int32 ExecuteGetJavascriptUrl2Test::Write(NPStream *stream, int32 offset, int32 len,
- void *buffer) {
- if (stream == NULL) {
- SetError("Write got null stream");
- return -1;
- }
- if (len < 0 || len > STREAM_CHUNK) {
- SetError("Write got bogus stream chunk size");
- return -1;
- }
-
- COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData),
- cast_validity_check);
- unsigned long stream_id = reinterpret_cast<unsigned long>(stream->notifyData);
- switch (stream_id) {
- case SELF_URL_STREAM_ID:
- self_url_.append(static_cast<char*>(buffer), len);
- break;
- default:
- SetError("Unexpected write callback");
- break;
- }
- // Pretend that we took all the data.
- return len;
-}
-
-
-NPError ExecuteGetJavascriptUrl2Test::DestroyStream(NPStream *stream, NPError reason) {
- if (stream == NULL) {
- SetError("NewStream got null stream");
- return NPERR_INVALID_PARAM;
- }
-
- COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData),
- cast_validity_check);
- unsigned long stream_id = reinterpret_cast<unsigned long>(stream->notifyData);
- switch (stream_id) {
- case SELF_URL_STREAM_ID:
- // don't care
- break;
- default:
- SetError("Unexpected NewStream callback");
- break;
- }
- return NPERR_NO_ERROR;
-}
-
-void ExecuteGetJavascriptUrl2Test::URLNotify(const char* url, NPReason reason, void* data) {
- COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(data),
- cast_validity_check);
-
- unsigned long stream_id = reinterpret_cast<unsigned long>(data);
- switch (stream_id) {
- case SELF_URL_STREAM_ID:
- if (strcmp(url, SELF_URL) != 0)
- SetError("URLNotify reported incorrect url for SELF_URL");
- if (self_url_.empty())
- SetError("Failed to obtain window location.");
- SignalTestCompleted();
- break;
- default:
- SetError("Unexpected NewStream callback");
- break;
- }
-}
-
-} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_get_javascript_url2_test.h b/webkit/glue/plugins/test/plugin_get_javascript_url2_test.h
deleted file mode 100644
index 557da76..0000000
--- a/webkit/glue/plugins/test/plugin_get_javascript_url2_test.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_GET_JAVASCRIPT_URL2_H
-#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_GET_JAVASCRIPT_URL2_H
-
-#include "webkit/glue/plugins/test/plugin_test.h"
-
-namespace NPAPIClient {
-
-// This class tests NPP_GetURLNotify for a javascript URL with _top
-// as the target frame.
-class ExecuteGetJavascriptUrl2Test : public PluginTest {
- public:
- // Constructor.
- ExecuteGetJavascriptUrl2Test(NPP id, NPNetscapeFuncs *host_functions);
-
- //
- // NPAPI functions
- //
- virtual NPError SetWindow(NPWindow* pNPWindow);
- virtual NPError NewStream(NPMIMEType type, NPStream* stream,
- NPBool seekable, uint16* stype);
- virtual int32 WriteReady(NPStream *stream);
- virtual int32 Write(NPStream *stream, int32 offset, int32 len,
- void *buffer);
- virtual NPError DestroyStream(NPStream *stream, NPError reason);
- virtual void URLNotify(const char* url, NPReason reason, void* data);
-
- private:
- bool test_started_;
- std::string self_url_;
-};
-
-} // namespace NPAPIClient
-
-#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_GET_JAVASCRIPT_URL2_H
diff --git a/webkit/glue/plugins/test/plugin_get_javascript_url_test.cc b/webkit/glue/plugins/test/plugin_get_javascript_url_test.cc
deleted file mode 100644
index 50f5e5a..0000000
--- a/webkit/glue/plugins/test/plugin_get_javascript_url_test.cc
+++ /dev/null
@@ -1,218 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/test/plugin_get_javascript_url_test.h"
-
-#include "base/basictypes.h"
-
-// url for "self".
-#define SELF_URL "javascript:window.location+\"\""
-// The identifier for the self url stream.
-#define SELF_URL_STREAM_ID 1
-
-// The identifier for the fetched url stream.
-#define FETCHED_URL_STREAM_ID 2
-
-// The maximum chunk size of stream data.
-#define STREAM_CHUNK 197
-
-const int kNPNEvaluateTimerID = 100;
-const int kNPNEvaluateTimerElapse = 50;
-
-
-namespace NPAPIClient {
-
-ExecuteGetJavascriptUrlTest::ExecuteGetJavascriptUrlTest(
- NPP id, NPNetscapeFuncs *host_functions)
- : PluginTest(id, host_functions),
- test_started_(false),
-#ifdef OS_WIN
- window_(NULL),
-#endif
- npn_evaluate_context_(false) {
-}
-
-NPError ExecuteGetJavascriptUrlTest::SetWindow(NPWindow* pNPWindow) {
- if (pNPWindow->window == NULL)
- return NPERR_NO_ERROR;
-
- if (!test_started_) {
- std::string url = SELF_URL;
- HostFunctions()->geturlnotify(id(), url.c_str(), "_top",
- reinterpret_cast<void*>(SELF_URL_STREAM_ID));
- test_started_ = true;
-
-#ifdef OS_WIN
- HWND window_handle = reinterpret_cast<HWND>(pNPWindow->window);
- if (!::GetProp(window_handle, L"Plugin_Instance")) {
- // TODO: this propery leaks.
- ::SetProp(window_handle, L"Plugin_Instance", this);
- // We attempt to retreive the NPObject for the plugin instance identified
- // by the NPObjectLifetimeTestInstance2 class as it may not have been
- // instantiated yet.
- SetTimer(window_handle, kNPNEvaluateTimerID, kNPNEvaluateTimerElapse,
- TimerProc);
- }
- window_ = window_handle;
-#endif
- }
-
- return NPERR_NO_ERROR;
-}
-
-#ifdef OS_WIN
-void CALLBACK ExecuteGetJavascriptUrlTest::TimerProc(
- HWND window, UINT message, UINT timer_id, unsigned long elapsed_time) {
- ExecuteGetJavascriptUrlTest* this_instance =
- reinterpret_cast<ExecuteGetJavascriptUrlTest*>
- (::GetProp(window, L"Plugin_Instance"));
-
- ::RemoveProp(window, L"Plugin_Instance");
-
- NPObject *window_obj = NULL;
- this_instance->HostFunctions()->getvalue(this_instance->id(),
- NPNVWindowNPObject,
- &window_obj);
- if (!window_obj) {
- this_instance->SetError("Failed to get NPObject for plugin instance2");
- this_instance->SignalTestCompleted();
- return;
- }
-
- std::string script = "javascript:window.location";
- NPString script_string;
- script_string.UTF8Characters = script.c_str();
- script_string.UTF8Length = static_cast<unsigned int>(script.length());
- NPVariant result_var;
-
- this_instance->npn_evaluate_context_ = true;
- NPError result = this_instance->HostFunctions()->evaluate(
- this_instance->id(), window_obj, &script_string, &result_var);
- this_instance->npn_evaluate_context_ = false;
-}
-#endif
-
-NPError ExecuteGetJavascriptUrlTest::NewStream(NPMIMEType type,
- NPStream* stream,
- NPBool seekable,
- uint16* stype) {
- if (stream == NULL) {
- SetError("NewStream got null stream");
- return NPERR_INVALID_PARAM;
- }
-
- if (npn_evaluate_context_) {
- SetError("NewStream received in context of NPN_Evaluate");
- return NPERR_NO_ERROR;
- }
-
- COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData),
- cast_validity_check);
- unsigned long stream_id = reinterpret_cast<unsigned long>(stream->notifyData);
- switch (stream_id) {
- case SELF_URL_STREAM_ID:
- break;
- default:
- SetError("Unexpected NewStream callback");
- break;
- }
- return NPERR_NO_ERROR;
-}
-
-int32 ExecuteGetJavascriptUrlTest::WriteReady(NPStream *stream) {
- if (npn_evaluate_context_) {
- SetError("WriteReady received in context of NPN_Evaluate");
- return NPERR_NO_ERROR;
- }
- return STREAM_CHUNK;
-}
-
-int32 ExecuteGetJavascriptUrlTest::Write(NPStream *stream, int32 offset,
- int32 len, void *buffer) {
- if (stream == NULL) {
- SetError("Write got null stream");
- return -1;
- }
- if (len < 0 || len > STREAM_CHUNK) {
- SetError("Write got bogus stream chunk size");
- return -1;
- }
-
- if (npn_evaluate_context_) {
- SetError("Write received in context of NPN_Evaluate");
- return len;
- }
-
- COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData),
- cast_validity_check);
- unsigned long stream_id = reinterpret_cast<unsigned long>(stream->notifyData);
- switch (stream_id) {
- case SELF_URL_STREAM_ID:
- self_url_.append(static_cast<char*>(buffer), len);
- break;
- default:
- SetError("Unexpected write callback");
- break;
- }
- // Pretend that we took all the data.
- return len;
-}
-
-
-NPError ExecuteGetJavascriptUrlTest::DestroyStream(NPStream *stream,
- NPError reason) {
- if (stream == NULL) {
- SetError("NewStream got null stream");
- return NPERR_INVALID_PARAM;
- }
-
-#ifdef OS_WIN
- KillTimer(window_, kNPNEvaluateTimerID);
-#endif
-
- if (npn_evaluate_context_) {
- SetError("DestroyStream received in context of NPN_Evaluate");
- return NPERR_NO_ERROR;
- }
-
- COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData),
- cast_validity_check);
- unsigned long stream_id = reinterpret_cast<unsigned long>(stream->notifyData);
- switch (stream_id) {
- case SELF_URL_STREAM_ID:
- // don't care
- break;
- default:
- SetError("Unexpected NewStream callback");
- break;
- }
- return NPERR_NO_ERROR;
-}
-
-void ExecuteGetJavascriptUrlTest::URLNotify(const char* url, NPReason reason,
- void* data) {
- COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(data),
- cast_validity_check);
-
- if (npn_evaluate_context_) {
- SetError("URLNotify received in context of NPN_Evaluate");
- return;
- }
-
- unsigned long stream_id = reinterpret_cast<unsigned long>(data);
- switch (stream_id) {
- case SELF_URL_STREAM_ID:
- if (strcmp(url, SELF_URL) != 0)
- SetError("URLNotify reported incorrect url for SELF_URL");
- if (self_url_.empty())
- SetError("Failed to obtain window location.");
- SignalTestCompleted();
- break;
- default:
- SetError("Unexpected NewStream callback");
- break;
- }
-}
-
-} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_get_javascript_url_test.h b/webkit/glue/plugins/test/plugin_get_javascript_url_test.h
deleted file mode 100644
index 5c2540d..0000000
--- a/webkit/glue/plugins/test/plugin_get_javascript_url_test.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_GET_JAVASCRIPT_URL_H
-#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_GET_JAVASCRIPT_URL_H
-
-#include "webkit/glue/plugins/test/plugin_test.h"
-
-namespace NPAPIClient {
-
-// This class tests NPP_GetURLNotify for a javascript URL with _top
-// as the target frame.
-class ExecuteGetJavascriptUrlTest : public PluginTest {
- public:
- // Constructor.
- ExecuteGetJavascriptUrlTest(NPP id, NPNetscapeFuncs *host_functions);
- //
- // NPAPI functions
- //
- virtual NPError SetWindow(NPWindow* pNPWindow);
- virtual NPError NewStream(NPMIMEType type, NPStream* stream,
- NPBool seekable, uint16* stype);
- virtual int32 WriteReady(NPStream *stream);
- virtual int32 Write(NPStream *stream, int32 offset, int32 len,
- void *buffer);
- virtual NPError DestroyStream(NPStream *stream, NPError reason);
- virtual void URLNotify(const char* url, NPReason reason, void* data);
-
- private:
-#if defined(OS_WIN)
- static void CALLBACK TimerProc(HWND window, UINT message, UINT timer_id,
- unsigned long elapsed_time);
-#endif
- bool test_started_;
- // This flag is set to true in the context of the NPN_Evaluate call.
- bool npn_evaluate_context_;
- std::string self_url_;
-
-#if defined(OS_WIN)
- HWND window_;
-#endif
-};
-
-} // namespace NPAPIClient
-
-#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_GET_JAVASCRIPT_URL_H
diff --git a/webkit/glue/plugins/test/plugin_geturl_test.cc b/webkit/glue/plugins/test/plugin_geturl_test.cc
deleted file mode 100644
index 5363a66..0000000
--- a/webkit/glue/plugins/test/plugin_geturl_test.cc
+++ /dev/null
@@ -1,414 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/test/plugin_geturl_test.h"
-
-#include <stdio.h>
-
-#include "base/basictypes.h"
-#include "base/file_util.h"
-#include "base/string_number_conversions.h"
-#include "base/utf_string_conversions.h"
-
-// url for "self". The %22%22 is to make a statement for javascript to
-// evaluate and return.
-#define SELF_URL "javascript:window.location+\"\""
-
-// The identifier for the self url stream.
-#define SELF_URL_STREAM_ID 1
-
-// The identifier for the fetched url stream.
-#define FETCHED_URL_STREAM_ID 2
-
-// url for testing GetURL with a bogus URL.
-#define BOGUS_URL "bogoproto:///x:/asdf.xysdhffieasdf.asdhj/"
-
-// url for testing redirect notifications sent to plugins.
-#define REDIRECT_SRC_URL \
- "http://mock.http/npapi/plugin_read_page_redirect_src.html"
-
-// The notification id for the redirect notification url.
-#define REDIRECT_SRC_URL_NOTIFICATION_ID 4
-
-// The identifier for the bogus url stream.
-#define BOGUS_URL_STREAM_ID 3
-
-// The maximum chunk size of stream data.
-#define STREAM_CHUNK 197
-
-namespace NPAPIClient {
-
-PluginGetURLTest::PluginGetURLTest(NPP id, NPNetscapeFuncs *host_functions)
- : PluginTest(id, host_functions),
- tests_started_(false),
- tests_in_progress_(0),
- test_file_(NULL),
- expect_404_response_(false),
- npn_evaluate_context_(false),
- handle_url_redirects_(false),
- received_url_redirect_notification_(false) {
-}
-
-NPError PluginGetURLTest::New(uint16 mode, int16 argc, const char* argn[],
- const char* argv[], NPSavedData* saved) {
- const char* page_not_found_url = GetArgValue("page_not_found_url", argc,
- argn, argv);
- if (page_not_found_url) {
- page_not_found_url_ = page_not_found_url;
- expect_404_response_ = true;
- }
-
- const char* fail_write_url = GetArgValue("fail_write_url", argc,
- argn, argv);
- if (fail_write_url) {
- fail_write_url_ = fail_write_url;
- }
-
- const char* referrer_target_url = GetArgValue("ref_target", argc,
- argn, argv);
- if (referrer_target_url) {
- referrer_target_url_ = referrer_target_url;
- }
-
- if (!base::strcasecmp(GetArgValue("name", argc, argn, argv),
- "geturlredirectnotify")) {
- handle_url_redirects_ = true;
- }
- return PluginTest::New(mode, argc, argn, argv, saved);
-}
-
-NPError PluginGetURLTest::SetWindow(NPWindow* pNPWindow) {
- if (pNPWindow->window == NULL)
- return NPERR_NO_ERROR;
-
- if (!tests_started_) {
- tests_started_ = true;
-
- tests_in_progress_++;
-
- if (expect_404_response_) {
- HostFunctions()->geturl(id(), page_not_found_url_.c_str(), NULL);
- return NPERR_NO_ERROR;
- } else if (!fail_write_url_.empty()) {
- HostFunctions()->geturl(id(), fail_write_url_.c_str(), NULL);
- return NPERR_NO_ERROR;
- } else if (!referrer_target_url_.empty()) {
- HostFunctions()->pushpopupsenabledstate(id(), true);
- HostFunctions()->geturl(id(), referrer_target_url_.c_str(), "_blank");
- HostFunctions()->poppopupsenabledstate(id());
- return NPERR_NO_ERROR;
- } else if (handle_url_redirects_) {
- HostFunctions()->geturlnotify(
- id(), REDIRECT_SRC_URL, NULL,
- reinterpret_cast<void*>(REDIRECT_SRC_URL_NOTIFICATION_ID));
- return NPERR_NO_ERROR;
- }
-
- std::string url = SELF_URL;
- HostFunctions()->geturlnotify(id(), url.c_str(), NULL,
- reinterpret_cast<void*>(SELF_URL_STREAM_ID));
-
- tests_in_progress_++;
- std::string bogus_url = BOGUS_URL;
- HostFunctions()->geturlnotify(id(), bogus_url.c_str(), NULL,
- reinterpret_cast<void*>(BOGUS_URL_STREAM_ID));
- }
- return NPERR_NO_ERROR;
-}
-
-NPError PluginGetURLTest::NewStream(NPMIMEType type, NPStream* stream,
- NPBool seekable, uint16* stype) {
- if (stream == NULL) {
- SetError("NewStream got null stream");
- return NPERR_INVALID_PARAM;
- }
-
- if (test_completed()) {
- return PluginTest::NewStream(type, stream, seekable, stype);
- }
-
- if (!referrer_target_url_.empty()) {
- return NPERR_NO_ERROR;
- }
-
- COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData),
- cast_validity_check);
-
- if (expect_404_response_) {
- NPObject *window_obj = NULL;
- HostFunctions()->getvalue(id(), NPNVWindowNPObject, &window_obj);
- if (!window_obj) {
- SetError("Failed to get NPObject for plugin instance2");
- SignalTestCompleted();
- return NPERR_NO_ERROR;
- }
-
- std::string script = "javascript:alert('Hi there from plugin');";
- NPString script_string;
- script_string.UTF8Characters = script.c_str();
- script_string.UTF8Length = static_cast<unsigned int>(script.length());
- NPVariant result_var;
-
- npn_evaluate_context_ = true;
- HostFunctions()->evaluate(id(), window_obj, &script_string, &result_var);
- npn_evaluate_context_ = false;
- return NPERR_NO_ERROR;
- }
-
- if (!fail_write_url_.empty()) {
- return NPERR_NO_ERROR;
- }
-
-
- unsigned long stream_id = reinterpret_cast<unsigned long>(
- stream->notifyData);
-
- switch (stream_id) {
- case SELF_URL_STREAM_ID:
- break;
- case FETCHED_URL_STREAM_ID:
- {
- std::string filename = self_url_;
- if (filename.find("file:///", 0) != 0) {
- SetError("Test expects a file-url.");
- break;
- }
-
- // TODO(evanm): use the net:: functions to convert file:// URLs to
- // on-disk file paths. But it probably doesn't actually matter in
- // this test.
-
-#if defined(OS_WIN)
- filename = filename.substr(8); // remove "file:///"
- // Assume an ASCII path on Windows.
- FilePath path = FilePath(ASCIIToWide(filename));
-#else
- filename = filename.substr(7); // remove "file://"
- FilePath path = FilePath(filename);
-#endif
-
- test_file_ = file_util::OpenFile(path, "r");
- if (!test_file_) {
- SetError("Could not open source file");
- }
- }
- break;
- case BOGUS_URL_STREAM_ID:
- SetError("Unexpected NewStream for BOGUS_URL");
- break;
- case REDIRECT_SRC_URL_NOTIFICATION_ID:
- SetError("Should not redirect to URL when plugin denied it.");
- break;
- default:
- SetError("Unexpected NewStream callback");
- break;
- }
- return NPERR_NO_ERROR;
-}
-
-int32 PluginGetURLTest::WriteReady(NPStream *stream) {
- if (test_completed()) {
- return PluginTest::WriteReady(stream);
- }
-
- if (!referrer_target_url_.empty()) {
- return STREAM_CHUNK;
- }
-
- COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData),
- cast_validity_check);
- unsigned long stream_id = reinterpret_cast<unsigned long>(
- stream->notifyData);
- if (stream_id == BOGUS_URL_STREAM_ID)
- SetError("Received WriteReady for BOGUS_URL");
-
- return STREAM_CHUNK;
-}
-
-int32 PluginGetURLTest::Write(NPStream *stream, int32 offset, int32 len,
- void *buffer) {
- if (test_completed()) {
- return PluginTest::Write(stream, offset, len, buffer);
- }
-
- if (!fail_write_url_.empty()) {
- SignalTestCompleted();
- return -1;
- }
-
- if (!referrer_target_url_.empty()) {
- return len;
- }
-
- if (stream == NULL) {
- SetError("Write got null stream");
- return -1;
- }
- if (len < 0 || len > STREAM_CHUNK) {
- SetError("Write got bogus stream chunk size");
- return -1;
- }
-
- COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData),
- cast_validity_check);
- unsigned long stream_id = reinterpret_cast<unsigned long>(
- stream->notifyData);
- switch (stream_id) {
- case SELF_URL_STREAM_ID:
- self_url_.append(static_cast<char*>(buffer), len);
- break;
- case FETCHED_URL_STREAM_ID:
- {
- char read_buffer[STREAM_CHUNK];
- int32 bytes = fread(read_buffer, 1, len, test_file_);
- // Technically, fread could return fewer than len
- // bytes. But this is not likely.
- if (bytes != len)
- SetError("Did not read correct bytelength from source file");
- if (memcmp(read_buffer, buffer, len))
- SetError("Content mismatch between data and source!");
- }
- break;
- case BOGUS_URL_STREAM_ID:
- SetError("Unexpected write callback for BOGUS_URL");
- break;
- default:
- SetError("Unexpected write callback");
- break;
- }
- // Pretend that we took all the data.
- return len;
-}
-
-
-NPError PluginGetURLTest::DestroyStream(NPStream *stream, NPError reason) {
- if (test_completed()) {
- return PluginTest::DestroyStream(stream, reason);
- }
-
- if (stream == NULL) {
- SetError("NewStream got null stream");
- return NPERR_INVALID_PARAM;
- }
-
- COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData),
- cast_validity_check);
-
- if (expect_404_response_) {
- if (npn_evaluate_context_) {
- SetError("Received destroyStream in the context of NPN_Evaluate.");
- }
-
- SignalTestCompleted();
- return NPERR_NO_ERROR;
- }
-
- if (!referrer_target_url_.empty()) {
- return NPERR_NO_ERROR;
- }
-
- unsigned long stream_id =
- reinterpret_cast<unsigned long>(stream->notifyData);
- switch (stream_id) {
- case SELF_URL_STREAM_ID:
- // don't care
- break;
- case FETCHED_URL_STREAM_ID:
- {
- char read_buffer[STREAM_CHUNK];
- size_t bytes = fread(read_buffer, 1, sizeof(read_buffer), test_file_);
- if (bytes != 0)
- SetError("Data and source mismatch on length");
- file_util::CloseFile(test_file_);
- }
- break;
- default:
- SetError("Unexpected NewStream callback");
- break;
- }
- return NPERR_NO_ERROR;
-}
-
-void PluginGetURLTest::StreamAsFile(NPStream* stream, const char* fname) {
- if (stream == NULL) {
- SetError("NewStream got null stream");
- return;
- }
-
- COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData),
- cast_validity_check);
- unsigned long stream_id =
- reinterpret_cast<unsigned long>(stream->notifyData);
- switch (stream_id) {
- case SELF_URL_STREAM_ID:
- // don't care
- break;
- default:
- SetError("Unexpected NewStream callback");
- break;
- }
-}
-
-void PluginGetURLTest::URLNotify(const char* url, NPReason reason, void* data) {
- if (!tests_in_progress_) {
- SetError("URLNotify received after tests completed");
- return;
- }
-
- if (!url) {
- SetError("URLNotify received NULL url");
- return;
- }
-
- COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(data), cast_validity_check);
- unsigned long stream_id = reinterpret_cast<unsigned long>(data);
- switch (stream_id) {
- case SELF_URL_STREAM_ID:
- if (strcmp(url, SELF_URL) != 0)
- SetError("URLNotify reported incorrect url for SELF_URL");
-
- // We have our stream url. Go fetch it.
- HostFunctions()->geturlnotify(id(), self_url_.c_str(), NULL,
- reinterpret_cast<void*>(FETCHED_URL_STREAM_ID));
- break;
- case FETCHED_URL_STREAM_ID:
- if (!url || strcmp(url, self_url_.c_str()) != 0)
- SetError("URLNotify reported incorrect url for FETCHED_URL");
- tests_in_progress_--;
- break;
- case BOGUS_URL_STREAM_ID:
- if (reason != NPRES_NETWORK_ERR) {
- std::string err = "BOGUS_URL received unexpected URLNotify status: ";
- err.append(base::IntToString(reason));
- SetError(err);
- }
- tests_in_progress_--;
- break;
- case REDIRECT_SRC_URL_NOTIFICATION_ID: {
- if (!received_url_redirect_notification_) {
- SetError("Failed to receive URLRedirect notification");
- }
- tests_in_progress_--;
- break;
- }
- default:
- SetError("Unexpected NewStream callback");
- break;
- }
-
- if (tests_in_progress_ == 0)
- SignalTestCompleted();
-}
-
-void PluginGetURLTest::URLRedirectNotify(const char* url,
- int32_t status,
- void* notify_data) {
- if (!base::strcasecmp(url, "http://mock.http/npapi/plugin_read_page.html")) {
- received_url_redirect_notification_ = true;
- // Disallow redirect notification.
- HostFunctions()->urlredirectresponse(id(), notify_data, false);
- }
-}
-
-} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_geturl_test.h b/webkit/glue/plugins/test/plugin_geturl_test.h
deleted file mode 100644
index df8d741..0000000
--- a/webkit/glue/plugins/test/plugin_geturl_test.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_PORT_PLUGINS_TEST_PLUGIN_GETURL_TEST_H__
-#define WEBKIT_PORT_PLUGINS_TEST_PLUGIN_GETURL_TEST_H__
-
-#include <stdio.h>
-
-#include "webkit/glue/plugins/test/plugin_test.h"
-
-namespace NPAPIClient {
-
-// The PluginGetURLTest test functionality of the NPN_GetURL
-// and NPN_GetURLNotify methods.
-//
-// This test first discovers it's URL by sending a GetURL request
-// for 'javascript:top.location'. After receiving that, the
-// test will request the url itself (again via GetURL).
-class PluginGetURLTest : public PluginTest {
- public:
- // Constructor.
- PluginGetURLTest(NPP id, NPNetscapeFuncs *host_functions);
-
- //
- // NPAPI functions
- //
- virtual NPError New(uint16 mode, int16 argc, const char* argn[],
- const char* argv[], NPSavedData* saved);
- virtual NPError SetWindow(NPWindow* pNPWindow);
- virtual NPError NewStream(NPMIMEType type, NPStream* stream,
- NPBool seekable, uint16* stype);
- virtual int32 WriteReady(NPStream *stream);
- virtual int32 Write(NPStream *stream, int32 offset, int32 len,
- void *buffer);
- virtual NPError DestroyStream(NPStream *stream, NPError reason);
- virtual void StreamAsFile(NPStream* stream, const char* fname);
- virtual void URLNotify(const char* url, NPReason reason, void* data);
- virtual void URLRedirectNotify(const char* url, int32_t status,
- void* notify_data);
-
- private:
- bool tests_started_;
- int tests_in_progress_;
- std::string self_url_;
- FILE* test_file_;
- bool expect_404_response_;
- // This flag is set to true in the context of the NPN_Evaluate call.
- bool npn_evaluate_context_;
- // The following two flags handle URL redirect notifications received by
- // plugins.
- bool handle_url_redirects_;
- bool received_url_redirect_notification_;
- std::string page_not_found_url_;
- std::string fail_write_url_;
- std::string referrer_target_url_;
-};
-
-} // namespace NPAPIClient
-
-#endif // WEBKIT_PORT_PLUGINS_TEST_PLUGIN_GETURL_TEST_H__
diff --git a/webkit/glue/plugins/test/plugin_javascript_open_popup.cc b/webkit/glue/plugins/test/plugin_javascript_open_popup.cc
deleted file mode 100644
index 0f93bf4..0000000
--- a/webkit/glue/plugins/test/plugin_javascript_open_popup.cc
+++ /dev/null
@@ -1,103 +0,0 @@
-// 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.
-
-#include "build/build_config.h"
-#include "webkit/glue/plugins/test/plugin_javascript_open_popup.h"
-
-#if defined(USE_X11)
-#include "third_party/npapi/bindings/npapi_x11.h"
-#endif
-#include "webkit/glue/plugins/test/plugin_client.h"
-
-namespace NPAPIClient {
-
-ExecuteJavascriptOpenPopupWithPluginTest::
- ExecuteJavascriptOpenPopupWithPluginTest(NPP id,
- NPNetscapeFuncs *host_functions)
- : PluginTest(id, host_functions),
- popup_window_test_started_(false) {
-}
-
-int16 ExecuteJavascriptOpenPopupWithPluginTest::SetWindow(
- NPWindow* window) {
- if (window->window == NULL)
- return NPERR_NO_ERROR;
-
- if (!popup_window_test_started_) {
- popup_window_test_started_ = true;
- HostFunctions()->geturl(
- id(), "popup_window_with_target_plugin.html", "_blank");
- }
- return NPERR_NO_ERROR;
-}
-
-// ExecuteJavascriptPopupWindowTargetPluginTest member defines.
-ExecuteJavascriptPopupWindowTargetPluginTest::
- ExecuteJavascriptPopupWindowTargetPluginTest(
- NPP id, NPNetscapeFuncs* host_functions)
- : PluginTest(id, host_functions),
- test_completed_(false) {
-}
-
-int16 ExecuteJavascriptPopupWindowTargetPluginTest::SetWindow(
- NPWindow* window) {
- if (window->window == NULL)
- return NPERR_NO_ERROR;
-
- if (!test_completed_) {
- if (CheckWindow(window)) {
- SignalTestCompleted();
- test_completed_ = true;
- }
- }
- return PluginTest::SetWindow(window);
-}
-
-#if defined(OS_WIN)
-bool ExecuteJavascriptPopupWindowTargetPluginTest::CheckWindow(
- NPWindow* window) {
- HWND window_handle = reinterpret_cast<HWND>(window->window);
-
- if (IsWindow(window_handle)) {
- HWND parent_window = GetParent(window_handle);
- if (!IsWindow(parent_window) || parent_window == GetDesktopWindow())
- SetError("Windowed plugin instantiated with NULL parent");
- return true;
- }
-
- return false;
-}
-
-#elif defined(USE_X11)
-// This code blindly follows the same sorts of verifications done on
-// the Windows side. Does it make sense on X? Maybe not really, but
-// it can't hurt to do extra validations.
-bool ExecuteJavascriptPopupWindowTargetPluginTest::CheckWindow(
- NPWindow* window) {
- Window xwindow = reinterpret_cast<Window>(window->window);
- // Grab a pointer to the extra SetWindow data so we can grab the display out.
- NPSetWindowCallbackStruct* extra =
- static_cast<NPSetWindowCallbackStruct*>(window->ws_info);
-
- if (xwindow) {
- Window root, parent;
- Status status = XQueryTree(extra->display, xwindow, &root, &parent,
- NULL, NULL); // NULL children info.
- DCHECK(status != 0);
- if (!parent || parent == root)
- SetError("Windowed plugin instantiated with NULL parent");
- return true;
- }
-
- return false;
-}
-#elif defined(OS_MACOSX)
-bool ExecuteJavascriptPopupWindowTargetPluginTest::CheckWindow(
- NPWindow* window) {
- // TODO(port) scaffolding--replace with a real test once NPWindow is done.
- return false;
-}
-#endif
-
-} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_javascript_open_popup.h b/webkit/glue/plugins/test/plugin_javascript_open_popup.h
deleted file mode 100644
index 552397a..0000000
--- a/webkit/glue/plugins/test/plugin_javascript_open_popup.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_JAVASCRIPT_OPEN_POPUP_H
-#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_JAVASCRIPT_OPEN_POPUP_H
-
-#include "webkit/glue/plugins/test/plugin_test.h"
-
-namespace NPAPIClient {
-
-// This class tests the case where a windowed plugin instance is
-// instantiated in a popup window. The plugin instance needs to
-// have a valid parent window.
-class ExecuteJavascriptOpenPopupWithPluginTest : public PluginTest {
- public:
- // Constructor.
- ExecuteJavascriptOpenPopupWithPluginTest(
- NPP id, NPNetscapeFuncs *host_functions);
- // NPAPI SetWindow handler.
- virtual NPError SetWindow(NPWindow* window);
-
- private:
- bool popup_window_test_started_;
-};
-
-// This class represents a windowed plugin instance instantiated within a
-// popup window. It verifies that the plugin instance has a valid parent.
-class ExecuteJavascriptPopupWindowTargetPluginTest : public PluginTest {
- public:
- ExecuteJavascriptPopupWindowTargetPluginTest(
- NPP id, NPNetscapeFuncs *host_functions);
- // NPAPI SetWindow handler.
- virtual NPError SetWindow(NPWindow* window);
-
- private:
- // Do a platform-specific validation of the passed-in |window|.
- // E.g. on Windows, verifies window->window is a reasonable HWND.
- // Returns true if the test should be marked complete.
- bool CheckWindow(NPWindow* window);
-
- bool test_completed_;
-};
-
-} // namespace NPAPIClient
-
-#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_JAVASCRIPT_OPEN_POPUP_H
diff --git a/webkit/glue/plugins/test/plugin_new_fails_test.cc b/webkit/glue/plugins/test/plugin_new_fails_test.cc
deleted file mode 100644
index 2feeec6..0000000
--- a/webkit/glue/plugins/test/plugin_new_fails_test.cc
+++ /dev/null
@@ -1,18 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/test/plugin_new_fails_test.h"
-
-namespace NPAPIClient {
-
-NewFailsTest::NewFailsTest(NPP id, NPNetscapeFuncs *host_functions)
- : PluginTest(id, host_functions) {
-}
-
-NPError NewFailsTest::New(uint16 mode, int16 argc, const char* argn[],
- const char* argv[], NPSavedData* saved) {
- return NPERR_GENERIC_ERROR;
-}
-
-} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_new_fails_test.h b/webkit/glue/plugins/test/plugin_new_fails_test.h
deleted file mode 100644
index 1acf9e5..0000000
--- a/webkit/glue/plugins/test/plugin_new_fails_test.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_PLUGIN_NEW_FAILS_TEST_H__
-#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_PLUGIN_NEW_FAILS_TEST_H__
-
-#include "webkit/glue/plugins/test/plugin_test.h"
-
-namespace NPAPIClient {
-
-class NewFailsTest : public PluginTest {
- public:
- NewFailsTest(NPP id, NPNetscapeFuncs *host_functions);
- virtual NPError New(uint16 mode, int16 argc, const char* argn[],
- const char* argv[], NPSavedData* saved);
-};
-
-} // namespace NPAPIClient
-
-#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_PLUGIN_NPP_NEW_FAILS_TEST_H__
diff --git a/webkit/glue/plugins/test/plugin_npobject_lifetime_test.cc b/webkit/glue/plugins/test/plugin_npobject_lifetime_test.cc
deleted file mode 100644
index 4564506..0000000
--- a/webkit/glue/plugins/test/plugin_npobject_lifetime_test.cc
+++ /dev/null
@@ -1,174 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/test/plugin_npobject_lifetime_test.h"
-
-namespace NPAPIClient {
-
-const int kNPObjectLifetimeTimer = 100;
-const int kNPObjectLifetimeTimerElapse = 2000;
-
-NPObject* NPObjectLifetimeTestInstance2::plugin_instance_object_ = NULL;
-
-NPObjectDeletePluginInNPN_Evaluate*
- NPObjectDeletePluginInNPN_Evaluate::g_npn_evaluate_test_instance_ = NULL;
-
-NPObjectLifetimeTest::NPObjectLifetimeTest(NPP id,
- NPNetscapeFuncs *host_functions)
- : PluginTest(id, host_functions),
- other_plugin_instance_object_(NULL),
- timer_id_(0) {
-}
-
-NPError NPObjectLifetimeTest::SetWindow(NPWindow* pNPWindow) {
- if (pNPWindow->window == NULL)
- return NPERR_NO_ERROR;
-
- HWND window_handle = reinterpret_cast<HWND>(pNPWindow->window);
- if (!::GetProp(window_handle, L"Plugin_Instance")) {
- // TODO: this propery leaks.
- ::SetProp(window_handle, L"Plugin_Instance", this);
- // We attempt to retreive the NPObject for the plugin instance identified
- // by the NPObjectLifetimeTestInstance2 class as it may not have been
- // instantiated yet.
- timer_id_ = SetTimer(window_handle, kNPObjectLifetimeTimer,
- kNPObjectLifetimeTimerElapse, TimerProc);
- }
- return NPERR_NO_ERROR;
-}
-
-void CALLBACK NPObjectLifetimeTest::TimerProc(
- HWND window, UINT message, UINT timer_id,
- unsigned long elapsed_milli_seconds) {
-
- NPObjectLifetimeTest* this_instance =
- reinterpret_cast<NPObjectLifetimeTest*>
- (::GetProp(window, L"Plugin_Instance"));
- KillTimer(window, this_instance->timer_id_);
- ::RemoveProp(window, L"Plugin_Instance");
-
- this_instance->timer_id_ = 0;
-
- this_instance->other_plugin_instance_object_ =
- NPObjectLifetimeTestInstance2::plugin_instance_object_;
- this_instance->HostFunctions()->retainobject(
- this_instance->other_plugin_instance_object_);
-
- NPString script;
- script.UTF8Characters = "javascript:DeleteSecondPluginInstance()";
- script.UTF8Length = static_cast<uint32_t>(strlen(script.UTF8Characters));
-
- this_instance->HostFunctions()->geturlnotify(
- this_instance->id(), "javascript:DeleteSecondPluginInstance()", NULL,
- reinterpret_cast<void*>(1));
-}
-
-void NPObjectLifetimeTest::URLNotify(const char* url, NPReason reason,
- void* data) {
- // Create a "location" identifier.
- NPIdentifier identifier = HostFunctions()->getstringidentifier("location");
- // Declare a local variant value.
- NPVariant variantValue;
- // Get the location property from the window object (which is another object).
- bool b1 = HostFunctions()->getproperty(id(), other_plugin_instance_object_,
- identifier, &variantValue );
- HostFunctions()->releaseobject(other_plugin_instance_object_);
- other_plugin_instance_object_ = NULL;
- // If this test failed, then we'd have crashed by now.
- SignalTestCompleted();
-}
-
-NPObjectLifetimeTestInstance2::NPObjectLifetimeTestInstance2(
- NPP id, NPNetscapeFuncs *host_functions)
- : PluginTest(id, host_functions) {
-}
-
-NPObjectLifetimeTestInstance2::~NPObjectLifetimeTestInstance2() {
- if (plugin_instance_object_) {
- HostFunctions()->releaseobject(plugin_instance_object_);
- plugin_instance_object_ = NULL;
- }
-}
-
-NPError NPObjectLifetimeTestInstance2::SetWindow(NPWindow* pNPWindow) {
- if (pNPWindow->window == NULL)
- return NPERR_NO_ERROR;
-
- if (!plugin_instance_object_) {
- if (!HostFunctions()->getvalue(id(), NPNVWindowNPObject,
- &plugin_instance_object_)) {
- SetError("Failed to get NPObject for plugin instance2");
- SignalTestCompleted();
- return NPERR_GENERIC_ERROR;
- }
- }
-
- return NPERR_NO_ERROR;
-}
-
-
-NPObjectDeletePluginInNPN_Evaluate::NPObjectDeletePluginInNPN_Evaluate(
- NPP id, NPNetscapeFuncs *host_functions)
- : PluginTest(id, host_functions),
- plugin_instance_object_(NULL),
- timer_id_(0) {
- g_npn_evaluate_test_instance_ = this;
-}
-
-NPObjectDeletePluginInNPN_Evaluate::~NPObjectDeletePluginInNPN_Evaluate() {
- if (plugin_instance_object_) {
- HostFunctions()->releaseobject(plugin_instance_object_);
- plugin_instance_object_ = NULL;
- }
-}
-
-NPError NPObjectDeletePluginInNPN_Evaluate::SetWindow(NPWindow* np_window) {
- if (np_window->window == NULL)
- return NPERR_NO_ERROR;
-
- HWND window_handle = reinterpret_cast<HWND>(np_window->window);
- // We setup a timerproc to invoke NPN_Evaluate to destroy this plugin
- // instance. This is to ensure that we don't destroy the plugin instance
- // while it is being used in webkit as this leads to crashes and is a
- // more accurate representation of the renderer crash as described in
- // http://b/issue?id=1134683.
- if (!timer_id_) {
- timer_id_ = SetTimer(window_handle, kNPObjectLifetimeTimer,
- kNPObjectLifetimeTimerElapse, TimerProc);
- }
- return NPERR_NO_ERROR;
-}
-
-void CALLBACK NPObjectDeletePluginInNPN_Evaluate::TimerProc(
- HWND window, UINT message, UINT timer_id,
- unsigned long elapsed_milli_seconds) {
-
- KillTimer(window, g_npn_evaluate_test_instance_->timer_id_);
- g_npn_evaluate_test_instance_->timer_id_ = 0;
- NPObject *window_obj = NULL;
- g_npn_evaluate_test_instance_->HostFunctions()->getvalue(
- g_npn_evaluate_test_instance_->id(), NPNVWindowNPObject,
- &window_obj);
-
- if (!window_obj) {
- g_npn_evaluate_test_instance_->SetError(
- "Failed to get NPObject for plugin instance2");
- g_npn_evaluate_test_instance_->SignalTestCompleted();
- return;
- }
-
- std::string script = "javascript:DeletePluginWithinScript()";
- NPString script_string;
- script_string.UTF8Characters = script.c_str();
- script_string.UTF8Length =
- static_cast<unsigned int>(script.length());
-
- NPVariant result_var;
- bool result = g_npn_evaluate_test_instance_->HostFunctions()->evaluate(
- g_npn_evaluate_test_instance_->id(), window_obj,
- &script_string, &result_var);
- // If this test failed we would have crashed by now.
-}
-
-} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_npobject_lifetime_test.h b/webkit/glue/plugins/test/plugin_npobject_lifetime_test.h
deleted file mode 100644
index 60d0314..0000000
--- a/webkit/glue/plugins/test/plugin_npobject_lifetime_test.h
+++ /dev/null
@@ -1,82 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_NPOBJECT_LIFETIME_TEST_H__
-#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_NPOBJECT_LIFETIME_TEST_H__
-
-#include "build/build_config.h"
-#include "webkit/glue/plugins/test/plugin_test.h"
-
-namespace NPAPIClient {
-
-// The NPObjectLifeTime class tests the case where a plugin has an NPObject
-// which points to a different plugin instance on a different frame in the
-// page and whether refcounts on this npobject are valid when the source frame
-// is destroyed.
-class NPObjectLifetimeTest : public PluginTest {
- public:
- // Constructor.
- NPObjectLifetimeTest(NPP id, NPNetscapeFuncs *host_functions);
-
- // NPAPI SetWindow handler.
- virtual NPError SetWindow(NPWindow* pNPWindow);
-
- virtual void URLNotify(const char* url, NPReason reason, void* data);
-
- protected:
- NPObject* other_plugin_instance_object_;
-
-#if defined(OS_WIN)
- static void CALLBACK TimerProc(HWND window, UINT message, UINT timer_id,
- unsigned long elapsed_milli_seconds);
- UINT_PTR timer_id_;
-#endif
- DISALLOW_IMPLICIT_CONSTRUCTORS(NPObjectLifetimeTest);
-};
-
-// The NPObjectLifetimeTestInstance2 class represents the plugin instance
-// which is deleted by the NPObjectLifeTime class via a javascript function.
-class NPObjectLifetimeTestInstance2 : public PluginTest {
- public:
- // Constructor.
- NPObjectLifetimeTestInstance2(NPP id, NPNetscapeFuncs *host_functions);
- ~NPObjectLifetimeTestInstance2();
-
- // NPAPI SetWindow handler.
- virtual NPError SetWindow(NPWindow* pNPWindow);
- protected:
- static NPObject* plugin_instance_object_;
- friend class NPObjectLifetimeTest;
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(NPObjectLifetimeTestInstance2);
-};
-
-// The NPObjectLifeTime class tests the case where a plugin instance is
-// destroyed in NPN_Evaluate
-class NPObjectDeletePluginInNPN_Evaluate : public PluginTest {
- public:
- // Constructor.
- NPObjectDeletePluginInNPN_Evaluate(NPP id, NPNetscapeFuncs *host_functions);
- ~NPObjectDeletePluginInNPN_Evaluate();
-
- // NPAPI SetWindow handler.
- virtual NPError SetWindow(NPWindow* pNPWindow);
-
- protected:
- NPObject* plugin_instance_object_;
-#if defined(OS_WIN)
- static void CALLBACK TimerProc(HWND window, UINT message, UINT timer_id,
- unsigned long elapsed_milli_seconds);
- UINT_PTR timer_id_;
-#endif
-
- private:
- static NPObjectDeletePluginInNPN_Evaluate* g_npn_evaluate_test_instance_;
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(NPObjectDeletePluginInNPN_Evaluate);
-};
-
-} // namespace NPAPIClient
-
-#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_NPOBJECT_LIFETIME_TEST_H__
diff --git a/webkit/glue/plugins/test/plugin_npobject_proxy_test.cc b/webkit/glue/plugins/test/plugin_npobject_proxy_test.cc
deleted file mode 100644
index 5b3a2ca..0000000
--- a/webkit/glue/plugins/test/plugin_npobject_proxy_test.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// 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.
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-
-#if defined(OS_WIN)
-#define STRSAFE_NO_DEPRECATE
-#include <strsafe.h>
-#endif
-#include "webkit/glue/plugins/test/plugin_npobject_proxy_test.h"
-
-namespace NPAPIClient {
-
-NPObjectProxyTest::NPObjectProxyTest(NPP id, NPNetscapeFuncs *host_functions)
- : PluginTest(id, host_functions) {
-}
-
-NPError NPObjectProxyTest::SetWindow(NPWindow* pNPWindow) {
- if (pNPWindow->window == NULL)
- return NPERR_NO_ERROR;
-
- NPIdentifier document_id = HostFunctions()->getstringidentifier("document");
- NPIdentifier create_text_node_id = HostFunctions()->getstringidentifier("createTextNode");
- NPIdentifier append_child_id = HostFunctions()->getstringidentifier("appendChild");
-
- NPVariant docv;
- NPObject *window_obj = NULL;
- HostFunctions()->getvalue(id(), NPNVWindowNPObject, &window_obj);
-
- HostFunctions()->getproperty(id(), window_obj, document_id, &docv);
- NPObject *doc = NPVARIANT_TO_OBJECT(docv);
-
- NPVariant strv;
- MSVC_SUPPRESS_WARNING(4267);
- STRINGZ_TO_NPVARIANT("div", strv);
-
- NPVariant textv;
- HostFunctions()->invoke(id(), doc, create_text_node_id, &strv, 1, &textv);
-
- NPVariant v;
- HostFunctions()->invoke(id(), doc, append_child_id, &textv, 1, &v);
-
- // If this test failed, then we'd have crashed by now.
- SignalTestCompleted();
-
- return NPERR_NO_ERROR;
-}
-
-} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_npobject_proxy_test.h b/webkit/glue/plugins/test/plugin_npobject_proxy_test.h
deleted file mode 100644
index 3d14ddb..0000000
--- a/webkit/glue/plugins/test/plugin_npobject_proxy_test.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_NPOBJECT_PROXY_TEST_H__
-#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_NPOBJECT_PROXY_TEST_H__
-
-#include "webkit/glue/plugins/test/plugin_test.h"
-
-namespace NPAPIClient {
-
-// The NPObjectProxyTest tests that when we proxy an NPObject that is itself
-// a proxy, we don't create a new proxy but instead just use the original
-// pointer.
-
-class NPObjectProxyTest : public PluginTest {
- public:
- // Constructor.
- NPObjectProxyTest(NPP id, NPNetscapeFuncs *host_functions);
-
- // NPAPI SetWindow handler.
- virtual NPError SetWindow(NPWindow* pNPWindow);
-};
-
-} // namespace NPAPIClient
-
-#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_NPOBJECT_PROXY_TEST_H__
diff --git a/webkit/glue/plugins/test/plugin_private_test.cc b/webkit/glue/plugins/test/plugin_private_test.cc
deleted file mode 100644
index cdab7ce..0000000
--- a/webkit/glue/plugins/test/plugin_private_test.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (c) 2009 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 "webkit/glue/plugins/test/plugin_private_test.h"
-
-#include "base/basictypes.h"
-#include "base/string_util.h"
-#include "webkit/glue/plugins/test/plugin_client.h"
-
-namespace NPAPIClient {
-
-PrivateTest::PrivateTest(NPP id, NPNetscapeFuncs *host_functions)
- : PluginTest(id, host_functions) {
-}
-
-NPError PrivateTest::New(uint16 mode, int16 argc,
- const char* argn[], const char* argv[],
- NPSavedData* saved) {
- PluginTest::New(mode, argc, argn, argv, saved);
-
- NPBool private_mode = 0;
- NPNetscapeFuncs* browser = NPAPIClient::PluginClient::HostFunctions();
- NPError result = browser->getvalue(
- id(), NPNVprivateModeBool, &private_mode);
- if (result != NPERR_NO_ERROR) {
- SetError("Failed to read NPNVprivateModeBool value.");
- } else {
- NPIdentifier location = HostFunctions()->getstringidentifier("location");
- NPIdentifier href = HostFunctions()->getstringidentifier("href");
-
- NPObject *window_obj = NULL;
- HostFunctions()->getvalue(id(), NPNVWindowNPObject, &window_obj);
-
- NPVariant location_var;
- HostFunctions()->getproperty(id(), window_obj, location, &location_var);
-
- NPVariant href_var;
- HostFunctions()->getproperty(id(), NPVARIANT_TO_OBJECT(location_var), href,
- &href_var);
- std::string href_str(href_var.value.stringValue.UTF8Characters,
- href_var.value.stringValue.UTF8Length);
- bool private_expected = href_str.find("?private") != href_str.npos;
- if (private_mode != static_cast<NPBool>(private_expected))
- SetError("NPNVprivateModeBool returned incorrect value.");
-
- HostFunctions()->releasevariantvalue(&href_var);
- HostFunctions()->releasevariantvalue(&location_var);
- HostFunctions()->releaseobject(window_obj);
- }
-
- SignalTestCompleted();
-
- return NPERR_NO_ERROR;
-}
-
-} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_private_test.h b/webkit/glue/plugins/test/plugin_private_test.h
deleted file mode 100644
index db6b5d1..0000000
--- a/webkit/glue/plugins/test/plugin_private_test.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2009 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 WEBKIT_PORT_PLUGINS_TEST_PLUGIN_PRIVATE_TEST_H_
-#define WEBKIT_PORT_PLUGINS_TEST_PLUGIN_PRIVATE_TEST_H_
-
-#include "webkit/glue/plugins/test/plugin_test.h"
-
-namespace NPAPIClient {
-
-// The PluginPrivateTest tests that a plugin can query if the browser is in
-// private browsing mode.
-class PrivateTest : public PluginTest {
- public:
- PrivateTest(NPP id, NPNetscapeFuncs *host_functions);
-
- // Initialize this PluginTest based on the arguments from NPP_New.
- virtual NPError New(uint16 mode, int16 argc, const char* argn[],
- const char* argv[], NPSavedData* saved);
-};
-
-} // namespace NPAPIClient
-
-#endif // WEBKIT_PORT_PLUGINS_TEST_PLUGIN_PRIVATE_TEST_H_
diff --git a/webkit/glue/plugins/test/plugin_schedule_timer_test.cc b/webkit/glue/plugins/test/plugin_schedule_timer_test.cc
deleted file mode 100644
index fbfce34..0000000
--- a/webkit/glue/plugins/test/plugin_schedule_timer_test.cc
+++ /dev/null
@@ -1,116 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/test/plugin_schedule_timer_test.h"
-#include "webkit/glue/plugins/test/plugin_client.h"
-
-using base::Time;
-
-namespace NPAPIClient {
-
-// The times below are accurate but they are not tested against because it
-// might make the test flakey.
-ScheduleTimerTest::Event
- ScheduleTimerTest::schedule_[ScheduleTimerTest::kNumEvents] = {
- { 0, -1, 0, 100, false, -1 }, // schedule 0 100ms no-repeat
- { 100, 0, 0, 200, false, -1 }, // schedule 0 200ms no-repeat
- { 300, 0, 0, 100, true, -1 }, // schedule 0 100ms repeat
- { 400, 0, 1, 50, true, -1 }, // schedule 1 50ms repeat
- { 450, 1, -1, 0, true, -1 }, // receive 1 repeating
- { 500, 0, -1, 0, true, -1 }, // receive 0 repeating
- { 500, 1, -1, 0, true, -1 }, // receive 1 repeating
- { 550, 1, -1, 0, true, -1 }, // receive 1 repeating
- { 600, 0, -1, 0, true, 0 }, // receive 0 repeating and unschedule
- { 600, 1, 2, 400, true, 1 }, // receive 1 repeating and unschedule
- { 1000, 2, -1, 0, true, 2 }, // receive final and unschedule
-};
-
-ScheduleTimerTest::ScheduleTimerTest(
- NPP id, NPNetscapeFuncs *host_functions)
- : PluginTest(id, host_functions),
- num_received_events_(0) {
- for (int i = 0; i < kNumTimers; ++i) {
- timer_ids_[i] = 0;
- }
- for (int i = 0; i < kNumEvents; ++i) {
- received_events_[i] = false;
- }
-}
-
-NPError ScheduleTimerTest::New(
- uint16 mode, int16 argc, const char* argn[], const char* argv[],
- NPSavedData* saved) {
- NPError error = PluginTest::New(mode, argc, argn, argv, saved);
- if (error != NPERR_NO_ERROR)
- return error;
-
- start_time_ = Time::Now();
- HandleEvent(0);
-
- return NPERR_NO_ERROR;
-}
-
-void ScheduleTimerTest::OnTimer(uint32 timer_id) {
- Time current_time = Time::Now();
- int relative_time = static_cast<int>(
- (current_time - start_time_).InMilliseconds());
-
- // See if there is a matching unreceived event.
- int event_index = FindUnreceivedEvent(relative_time, timer_id);
- if (event_index < 0) {
- SetError("Received unexpected timer event");
- SignalTestCompleted();
- return;
- }
-
- HandleEvent(event_index);
-
- // Finish test if all events have happened.
- if (num_received_events_ == kNumEvents)
- SignalTestCompleted();
-}
-
-int ScheduleTimerTest::FindUnreceivedEvent(int time, uint32 timer_id) {
- for (int i = 0; i < kNumEvents; ++i) {
- const Event& event = schedule_[i];
- if (!received_events_[i] &&
- timer_ids_[event.received_index] == timer_id) {
- return i;
- }
- }
- return -1;
-}
-
-namespace {
-void OnTimerHelper(NPP id, uint32 timer_id) {
- ScheduleTimerTest* plugin_object =
- static_cast<ScheduleTimerTest*>(id->pdata);
- if (plugin_object) {
- plugin_object->OnTimer(timer_id);
- }
-}
-}
-
-void ScheduleTimerTest::HandleEvent(int event_index) {
- const Event& event = schedule_[event_index];
-
- // Mark event as received.
- DCHECK(!received_events_[event_index]);
- received_events_[event_index] = true;
- ++num_received_events_;
-
- // Unschedule timer if present.
- if (event.unscheduled_index >= 0) {
- HostFunctions()->unscheduletimer(
- id(), timer_ids_[event.unscheduled_index]);
- }
-
- // Schedule timer if present.
- if (event.scheduled_index >= 0) {
- timer_ids_[event.scheduled_index] = HostFunctions()->scheduletimer(
- id(), event.scheduled_interval, event.schedule_repeated, OnTimerHelper);
- }
-}
-
-} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_schedule_timer_test.h b/webkit/glue/plugins/test/plugin_schedule_timer_test.h
deleted file mode 100644
index e3e6505..0000000
--- a/webkit/glue/plugins/test/plugin_schedule_timer_test.h
+++ /dev/null
@@ -1,68 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_SCHEDULE_TIMER_TEST_H
-#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_SCHEDULE_TIMER_TEST_H
-
-#include "base/at_exit.h"
-#include "base/time.h"
-#include "webkit/glue/plugins/test/plugin_test.h"
-
-namespace NPAPIClient {
-
-// This class tests scheduling and unscheduling of timers using
-// NPN_ScheduleTimer and NPN_UnscheduleTimer.
-class ScheduleTimerTest : public PluginTest {
- public:
- ScheduleTimerTest(NPP id, NPNetscapeFuncs *host_functions);
-
- virtual NPError New(uint16 mode, int16 argc, const char* argn[],
- const char* argv[], NPSavedData* saved);
-
- void OnTimer(uint32 timer_id);
-
- private:
- // base::Time needs one of these.
- base::AtExitManager at_exit_manager_;
-
- // Table mapping timer index (as used in event schedule) to timer id.
- static const int kNumTimers = 3;
- uint32 timer_ids_[kNumTimers];
-
- // Schedule of events for test.
- static const int kNumEvents = 11;
- struct Event {
- int time;
-
- // The index of the timer that triggered the event or -1 for the first
- // event.
- int received_index;
-
- // The index of the timer to schedule on this event or -1.
- int scheduled_index;
-
- // Info about the timer to be scheduled (if any).
- uint32 scheduled_interval;
- bool schedule_repeated;
-
- // The index of the timer to unschedule on this event or -1.
- int unscheduled_index;
- };
- static Event schedule_[kNumEvents];
- int num_received_events_;
-
- // Set of events that have been received (by index).
- bool received_events_[kNumEvents];
-
- // Time of initial event.
- base::Time start_time_;
-
- // Returns index of matching unreceived event or -1 if not found.
- int FindUnreceivedEvent(int time, uint32 timer_id);
- void HandleEvent(int event_index);
-};
-
-} // namespace NPAPIClient
-
-#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_SCHEDULE_TIMER_TEST_H
diff --git a/webkit/glue/plugins/test/plugin_setup_test.cc b/webkit/glue/plugins/test/plugin_setup_test.cc
deleted file mode 100644
index e4c4903..0000000
--- a/webkit/glue/plugins/test/plugin_setup_test.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// 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.
-
-#include "base/basictypes.h"
-#include "base/string_util.h"
-
-#include "webkit/glue/plugins/test/plugin_setup_test.h"
-
-namespace NPAPIClient {
-
-PluginSetupTest::PluginSetupTest(NPP id, NPNetscapeFuncs *host_functions)
- : PluginTest(id, host_functions) {
-}
-
-NPError PluginSetupTest::SetWindow(NPWindow* pNPWindow) {
- this->SignalTestCompleted();
-
- return NPERR_NO_ERROR;
-}
-
-} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_setup_test.h b/webkit/glue/plugins/test/plugin_setup_test.h
deleted file mode 100644
index b01bc42..0000000
--- a/webkit/glue/plugins/test/plugin_setup_test.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_SETUP_TEST_H__
-#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_SETUP_TEST_H__
-
-#include "webkit/glue/plugins/test/plugin_test.h"
-
-namespace NPAPIClient {
-
-// A very simple test that just sets up a new plug-in.
-class PluginSetupTest : public PluginTest {
- public:
- // Constructor.
- PluginSetupTest(NPP id, NPNetscapeFuncs *host_functions);
-
- // NPAPI SetWindow handler.
- virtual NPError SetWindow(NPWindow* pNPWindow);
-};
-
-} // namespace NPAPIClient
-
-#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_SETUP_TEST_H__
diff --git a/webkit/glue/plugins/test/plugin_test.cc b/webkit/glue/plugins/test/plugin_test.cc
deleted file mode 100644
index 6717e4b..0000000
--- a/webkit/glue/plugins/test/plugin_test.cc
+++ /dev/null
@@ -1,155 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/test/plugin_test.h"
-
-#include "base/string_util.h"
-#include "webkit/glue/plugins/test/npapi_constants.h"
-
-namespace NPAPIClient {
-
-PluginTest::PluginTest(NPP id, NPNetscapeFuncs *host_functions) {
- id_ = id;
- id_->pdata = this;
- host_functions_ = host_functions;
- test_completed_ = false;
-}
-
-NPError PluginTest::New(uint16 mode, int16 argc, const char* argn[],
- const char* argv[], NPSavedData* saved) {
- test_name_ = this->GetArgValue("name", argc, argn, argv);
- test_id_ = this->GetArgValue("id", argc, argn, argv);
- return NPERR_NO_ERROR;
-}
-
-NPError PluginTest::Destroy() {
- return NPERR_NO_ERROR;
-}
-
-NPError PluginTest::SetWindow(NPWindow* pNPWindow) {
- return NPERR_NO_ERROR;
-}
-
-// It's a shame I have to implement URLEncode. But, using webkit's
-// or using chrome's means a ball of string of dlls and dependencies that
-// is very very long. After spending far too much time on it,
-// I'll just encode it myself. Too bad Microsoft doesn't implement
-// this in a reusable way either. Both webkit and chrome will
-// end up using libicu, which is a string of dependencies we don't
-// want.
-
-inline unsigned char toHex(const unsigned char x) {
- return x > 9 ? (x + 'A' - 10) : (x + '0');
-}
-
-std::string URLEncode(const std::string &sIn) {
- std::string sOut;
-
- const size_t length = sIn.length();
- for (size_t idx = 0; idx < length;) {
- const char ch = sIn.at(idx);
- if (isalnum(ch)) {
- sOut.append(1, ch);
- } else if (isspace(ch) && ((ch != '\n') && (ch != '\r'))) {
- sOut.append(1, '+');
- } else {
- sOut.append(1, '%');
- sOut.append(1, toHex(ch>>4));
- sOut.append(1, toHex(ch%16));
- }
- idx++;
- }
- return sOut;
-}
-
-void PluginTest::SignalTestCompleted() {
- NPObject *window_obj = NULL;
- host_functions_->getvalue(id_, NPNVWindowNPObject, &window_obj);
- if (!window_obj)
- return;
-
- test_completed_ = true;
- // To signal test completion, we expect a couple of
- // javascript functions to be defined in the webpage
- // which hosts this plugin:
- // onSuccess(test_name, test_id)
- // onFailure(test_name, test_id, error_message)
- std::string script("javascript:");
- if (Succeeded()) {
- script.append("onSuccess(\"");
- script.append(test_name_);
- script.append("\",\"");
- script.append(test_id_);
- script.append("\");");
- } else {
- script.append("onFailure(\"");
- script.append(test_name_);
- script.append("\",\"");
- script.append(test_id_);
- script.append("\",\"");
- script.append(test_status_);
- script.append("\");");
- }
-
- NPString script_string;
- script_string.UTF8Characters = script.c_str();
- script_string.UTF8Length = static_cast<unsigned int>(script.length());
-
- NPVariant result_var;
- host_functions_->evaluate(id_, window_obj, &script_string, &result_var);
-}
-
-const char *PluginTest::GetArgValue(const char *name, const int16 argc,
- const char *argn[], const char *argv[]) {
- for (int idx = 0; idx < argc; idx++)
- if (base::strcasecmp(argn[idx], name) == 0)
- return argv[idx];
- return NULL;
-}
-
-void PluginTest::SetError(const std::string &msg) {
- test_status_.append(msg);
-}
-
-NPError PluginTest::NewStream(NPMIMEType type, NPStream* stream,
- NPBool seekable, uint16* stype) {
- // There is no default action here.
- return NPERR_NO_ERROR;
-}
-
-int32 PluginTest::WriteReady(NPStream *stream) {
- // Take data in small chunks
- return 4096;
-}
-
-int32 PluginTest::Write(NPStream *stream, int32 offset, int32 len,
- void *buffer) {
- // Pretend that we took all the data.
- return len;
-}
-
-NPError PluginTest::DestroyStream(NPStream *stream, NPError reason) {
- // There is no default action.
- return NPERR_NO_ERROR;
-}
-
-void PluginTest::StreamAsFile(NPStream* stream, const char* fname) {
- // There is no default action.
-}
-
-void PluginTest::URLNotify(const char* url, NPReason reason, void* data) {
- // There is no default action
-}
-
-int16 PluginTest::HandleEvent(void* event) {
- // There is no default action
- return 0;
-}
-
-void PluginTest::URLRedirectNotify(const char* url, int32_t status,
- void* notify_data) {
- // There is no default action
-}
-
-} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_test.h b/webkit/glue/plugins/test/plugin_test.h
deleted file mode 100644
index f3f8937..0000000
--- a/webkit/glue/plugins/test/plugin_test.h
+++ /dev/null
@@ -1,134 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_PORT_PLUGINS_TEST_PLUGIN_TEST_H_
-#define WEBKIT_PORT_PLUGINS_TEST_PLUGIN_TEST_H_
-
-#include <string>
-
-#include "base/string_number_conversions.h"
-#include "base/string_util.h"
-#include "third_party/npapi/bindings/npapi.h"
-#include "third_party/npapi/bindings/nphostapi.h"
-
-namespace NPAPIClient {
-
-// A PluginTest represents an instance of the plugin, which in
-// our case is a test case.
-class PluginTest {
- public:
- // Constructor.
- PluginTest(NPP id, NPNetscapeFuncs *host_functions);
-
- // Destructor
- virtual ~PluginTest() {}
-
- // Returns true if the test runs in windowless plugin mode.
- virtual bool IsWindowless() const { return false; }
-
- //
- // NPAPI Functions
- //
- virtual NPError New(uint16 mode, int16 argc, const char* argn[],
- const char* argv[], NPSavedData* saved);
- virtual NPError Destroy();
- virtual NPError SetWindow(NPWindow* pNPWindow);
- virtual NPError NewStream(NPMIMEType type, NPStream* stream,
- NPBool seekable, uint16* stype);
- virtual int32 WriteReady(NPStream *stream);
- virtual int32 Write(NPStream *stream, int32 offset, int32 len,
- void *buffer);
- virtual NPError DestroyStream(NPStream *stream, NPError reason);
- virtual void StreamAsFile(NPStream* stream, const char* fname);
- virtual void URLNotify(const char* url, NPReason reason, void* data);
- virtual int16 HandleEvent(void* event);
- virtual void URLRedirectNotify(const char* url, int32_t status,
- void* notify_data);
- // Returns true if the test has not had any errors.
- bool Succeeded() { return test_status_.length() == 0; }
-
- // Sets an error for the test case. Appends the msg to the
- // error that will be returned from the test.
- void SetError(const std::string &msg);
-
- // Expect two string values are equal, and if not, logs an
- // appropriate error about it.
- void ExpectStringLowerCaseEqual(const std::string &val1, const std::string &val2) {
- if (!LowerCaseEqualsASCII(val1, val2.c_str())) {
- std::string err;
- err = "Expected Equal for '";
- err.append(val1);
- err.append("' and '");
- err.append(val2);
- err.append("'");
- SetError(err);
- }
- };
-
- // Expect two values to not be equal, and if they are
- // logs an appropriate error about it.
- void ExpectAsciiStringNotEqual(const char *val1, const char *val2) {
- if (val1 == val2) {
- std::string err;
- err = "Expected Not Equal for '";
- err.append(val1);
- err.append("' and '");
- err.append(val2);
- err.append("'");
- SetError(err);
- }
- }
- // Expect two integer values are equal, and if not, logs an
- // appropriate error about it.
- void ExpectIntegerEqual(int val1, int val2) {
- if (val1 != val2) {
- std::string err;
- err = "Expected Equal for '";
- err.append(base::IntToString(val1));
- err.append("' and '");
- err.append(base::IntToString(val2));
- err.append("'");
- SetError(err);
- }
- }
-
-
- protected:
- // Signals to the Test that invoked us that the test is
- // completed. This is done by forcing the plugin to
- // set a cookie in the browser window, which the test program
- // is waiting for. Note - because this is done by
- // using javascript, the browser must have the frame
- // setup before the plugin calls this function. So plugin
- // tests MUST NOT call this function prior to having
- // received the SetWindow() callback from the browser.
- void SignalTestCompleted();
-
- // Helper function to lookup names in the input array.
- // If the name is found, returns the value, otherwise
- // returns NULL.
- const char *GetArgValue(const char *name, const int16 argc,
- const char *argn[], const char *argv[]);
-
- // Access to the list of functions provided
- // by the NPAPI host.
- NPNetscapeFuncs *HostFunctions() { return host_functions_; }
-
- // The NPP Identifier for this plugin instance.
- NPP id() { return id_; }
- std::string test_id() const { return test_id_; }
- std::string test_name() const { return test_name_; }
- bool test_completed() const { return test_completed_; }
- private:
- NPP id_;
- NPNetscapeFuncs * host_functions_;
- std::string test_name_;
- std::string test_id_;
- std::string test_status_;
- bool test_completed_;
-};
-
-} // namespace NPAPIClient
-
-#endif // WEBKIT_PORT_PLUGINS_TEST_PLUGIN_TEST_H_
diff --git a/webkit/glue/plugins/test/plugin_test_factory.cc b/webkit/glue/plugins/test/plugin_test_factory.cc
deleted file mode 100644
index b4ae4f1..0000000
--- a/webkit/glue/plugins/test/plugin_test_factory.cc
+++ /dev/null
@@ -1,104 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/test/plugin_test_factory.h"
-
-#include "webkit/glue/plugins/test/plugin_arguments_test.h"
-#include "webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.h"
-#include "webkit/glue/plugins/test/plugin_get_javascript_url_test.h"
-#include "webkit/glue/plugins/test/plugin_get_javascript_url2_test.h"
-#include "webkit/glue/plugins/test/plugin_geturl_test.h"
-#include "webkit/glue/plugins/test/plugin_javascript_open_popup.h"
-#include "webkit/glue/plugins/test/plugin_new_fails_test.h"
-#include "webkit/glue/plugins/test/plugin_npobject_lifetime_test.h"
-#include "webkit/glue/plugins/test/plugin_npobject_proxy_test.h"
-#include "webkit/glue/plugins/test/plugin_private_test.h"
-#include "webkit/glue/plugins/test/plugin_schedule_timer_test.h"
-#include "webkit/glue/plugins/test/plugin_setup_test.h"
-#include "webkit/glue/plugins/test/plugin_thread_async_call_test.h"
-#include "webkit/glue/plugins/test/plugin_window_size_test.h"
-#if defined(OS_WIN)
-#include "webkit/glue/plugins/test/plugin_windowed_test.h"
-#endif
-#include "webkit/glue/plugins/test/plugin_windowless_test.h"
-
-namespace NPAPIClient {
-
-PluginTest* CreatePluginTest(const std::string& test_name,
- NPP instance,
- NPNetscapeFuncs* host_functions) {
- PluginTest* new_test = NULL;
-
- if (test_name == "arguments") {
- new_test = new PluginArgumentsTest(instance, host_functions);
- } else if (test_name == "geturl" || test_name == "geturl_404_response" ||
- test_name == "geturl_fail_write" ||
- test_name == "plugin_referrer_test" ||
- test_name == "geturlredirectnotify") {
- new_test = new PluginGetURLTest(instance, host_functions);
- } else if (test_name == "npobject_proxy") {
- new_test = new NPObjectProxyTest(instance, host_functions);
-#if defined(OS_WIN) || defined(OS_MACOSX)
- // TODO(port): plugin_windowless_test.*.
- } else if (test_name == "execute_script_delete_in_paint" ||
- test_name == "execute_script_delete_in_mouse_move" ||
- test_name == "delete_frame_test" ||
- test_name == "multiple_instances_sync_calls" ||
- test_name == "no_hang_if_init_crashes" ||
- test_name == "convert_point") {
- new_test = new WindowlessPluginTest(instance, host_functions);
-#endif
- } else if (test_name == "getjavascripturl") {
- new_test = new ExecuteGetJavascriptUrlTest(instance, host_functions);
- } else if (test_name == "getjavascripturl2") {
- new_test = new ExecuteGetJavascriptUrl2Test(instance, host_functions);
-#if defined(OS_WIN)
- // TODO(port): plugin_window_size_test.*.
- } else if (test_name == "checkwindowrect") {
- new_test = new PluginWindowSizeTest(instance, host_functions);
-#endif
- } else if (test_name == "self_delete_plugin_stream") {
- new_test = new DeletePluginInStreamTest(instance, host_functions);
-#if defined(OS_WIN)
- // TODO(port): plugin_npobject_lifetime_test.*.
- } else if (test_name == "npobject_lifetime_test") {
- new_test = new NPObjectLifetimeTest(instance, host_functions);
- } else if (test_name == "npobject_lifetime_test_second_instance") {
- new_test = new NPObjectLifetimeTestInstance2(instance, host_functions);
- } else if (test_name == "new_fails") {
- new_test = new NewFailsTest(instance, host_functions);
- } else if (test_name == "npobject_delete_plugin_in_evaluate" ||
- test_name == "npobject_delete_create_plugin_in_evaluate") {
- new_test = new NPObjectDeletePluginInNPN_Evaluate(instance, host_functions);
-#endif
- } else if (test_name == "plugin_javascript_open_popup_with_plugin") {
- new_test = new ExecuteJavascriptOpenPopupWithPluginTest(
- instance, host_functions);
- } else if (test_name == "plugin_popup_with_plugin_target") {
- new_test = new ExecuteJavascriptPopupWindowTargetPluginTest(
- instance, host_functions);
- } else if (test_name == "plugin_thread_async_call") {
- new_test = new PluginThreadAsyncCallTest(instance, host_functions);
- } else if (test_name == "private") {
- new_test = new PrivateTest(instance, host_functions);
- } else if (test_name == "schedule_timer") {
- new_test = new ScheduleTimerTest(instance, host_functions);
-#if defined(OS_WIN)
- // TODO(port): plugin_windowed_test.*.
- } else if (test_name == "hidden_plugin" ||
- test_name == "create_instance_in_paint" ||
- test_name == "alert_in_window_message" ||
- test_name == "ensure_scripting_works_in_destroy" ||
- test_name == "invoke_js_function_on_create") {
- new_test = new WindowedPluginTest(instance, host_functions);
-#endif
- } else if (test_name == "setup") {
- // "plugin" is the name for plugin documents.
- new_test = new PluginSetupTest(instance, host_functions);
- }
-
- return new_test;
-}
-
-} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_test_factory.h b/webkit/glue/plugins/test/plugin_test_factory.h
deleted file mode 100644
index 3fd38d5..0000000
--- a/webkit/glue/plugins/test/plugin_test_factory.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_PORT_PLUGINS_TEST_PLUGIN_TEST_FACTROY_H__
-#define WEBKIT_PORT_PLUGINS_TEST_PLUGIN_TEST_FACTROY_H__
-
-#include <string>
-
-#include "third_party/npapi/bindings/nphostapi.h"
-
-namespace NPAPIClient {
-
-class PluginTest;
-
-extern PluginTest* CreatePluginTest(const std::string& test_name,
- NPP instance,
- NPNetscapeFuncs* host_functions);
-
-} // namespace NPAPIClient
-
-#endif // WEBKIT_PORT_PLUGINS_TEST_PLUGIN_TEST_FACTROY_H__
diff --git a/webkit/glue/plugins/test/plugin_thread_async_call_test.cc b/webkit/glue/plugins/test/plugin_thread_async_call_test.cc
deleted file mode 100644
index c01a49e..0000000
--- a/webkit/glue/plugins/test/plugin_thread_async_call_test.cc
+++ /dev/null
@@ -1,117 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/test/plugin_thread_async_call_test.h"
-
-#include "base/at_exit.h"
-#include "base/message_loop.h"
-#include "base/thread.h"
-#include "webkit/glue/plugins/test/plugin_client.h"
-
-namespace NPAPIClient {
-
-namespace {
-
-// There are two plugin instances in this test. The long lived instance is used
-// for reporting errors and signalling test completion. The short lived one is
-// used to verify that async callbacks are not invoked after NPP_Destroy.
-PluginThreadAsyncCallTest* g_short_lived_instance;
-PluginThreadAsyncCallTest* g_long_lived_instance;
-
-void OnCallSucceededHelper(void* data) {
- static_cast<PluginThreadAsyncCallTest*>(data)->OnCallSucceeded();
-}
-
-class AsyncCallTask : public Task {
- public:
- AsyncCallTask(PluginThreadAsyncCallTest* test_class)
- : test_class_(test_class) {}
-
- void Run() {
- test_class_->AsyncCall();
- }
-
- private:
- PluginThreadAsyncCallTest* test_class_;
-};
-
-void OnCallFailed(void* data) {
- g_long_lived_instance->SetError("Async callback invoked after NPP_Destroy");
-}
-
-void OnCallCompletedHelper(void* data) {
- static_cast<PluginThreadAsyncCallTest*>(data)->OnCallCompleted();
-}
-}
-
-PluginThreadAsyncCallTest::PluginThreadAsyncCallTest(
- NPP id, NPNetscapeFuncs *host_functions)
- : PluginTest(id, host_functions) {
-}
-
-NPError PluginThreadAsyncCallTest::New(
- uint16 mode, int16 argc, const char* argn[], const char* argv[],
- NPSavedData* saved) {
- NPError error = PluginTest::New(mode, argc, argn, argv, saved);
- if (error != NPERR_NO_ERROR)
- return error;
-
- // Determine whether this is the short lived instance.
- for (int i = 0; i < argc; ++i) {
- if (base::strcasecmp(argn[i], "short_lived") == 0) {
- if (base::strcasecmp(argv[i], "true") == 0) {
- g_short_lived_instance = this;
- } else {
- g_long_lived_instance = this;
- }
- }
- }
-
- // Schedule an async call that will succeed. Make sure to call that API from
- // a different thread to fully test it.
- if (this == g_short_lived_instance) {
- at_exit_manager_.reset(new base::AtExitManager());
- base::Thread random_thread("random_thread");
- random_thread.Start();
- random_thread.message_loop()->PostTask(FROM_HERE, new AsyncCallTask(this));
- }
-
- return NPERR_NO_ERROR;
-}
-
-void PluginThreadAsyncCallTest::AsyncCall() {
- HostFunctions()->pluginthreadasynccall(id(), OnCallSucceededHelper, this);
-}
-
-void PluginThreadAsyncCallTest::OnCallSucceeded() {
- // Delete the short lived instance.
- NPIdentifier delete_id = HostFunctions()->getstringidentifier(
- "deleteShortLivedInstance");
-
- NPObject *window_obj = NULL;
- HostFunctions()->getvalue(id(), NPNVWindowNPObject, &window_obj);
-
- NPVariant result;
- HostFunctions()->invoke(id(), window_obj, delete_id, NULL, 0, &result);
-}
-
-NPError PluginThreadAsyncCallTest::Destroy() {
- if (this == g_short_lived_instance) {
- // Schedule an async call that should not be called.
- HostFunctions()->pluginthreadasynccall(id(), OnCallFailed, NULL);
-
- // Schedule an async call to end the test using the long lived instance.
- HostFunctions()->pluginthreadasynccall(g_long_lived_instance->id(),
- OnCallCompletedHelper,
- g_long_lived_instance);
- }
-
- return NPERR_NO_ERROR;
-}
-
-void PluginThreadAsyncCallTest::OnCallCompleted() {
- SignalTestCompleted();
-}
-
-} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_thread_async_call_test.h b/webkit/glue/plugins/test/plugin_thread_async_call_test.h
deleted file mode 100644
index 78e4e8d..0000000
--- a/webkit/glue/plugins/test/plugin_thread_async_call_test.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_THREAD_ASYNC_CALL_TEST_H_
-#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_THREAD_ASYNC_CALL_TEST_H_
-
-#include "base/scoped_ptr.h"
-#include "webkit/glue/plugins/test/plugin_test.h"
-
-namespace base {
-class AtExitManager;
-}
-
-namespace NPAPIClient {
-
-// This class tests scheduling and unscheduling of async callbacks using
-// NPN_PluginThreadAsyncCall.
-class PluginThreadAsyncCallTest : public PluginTest {
- public:
- PluginThreadAsyncCallTest(NPP id, NPNetscapeFuncs *host_functions);
-
- virtual NPError New(uint16 mode, int16 argc, const char* argn[],
- const char* argv[], NPSavedData* saved);
-
- virtual NPError Destroy();
-
- void AsyncCall();
- void OnCallSucceeded();
- void OnCallCompleted();
-
- private:
- // base::Thread needs one of these.
- scoped_ptr<base::AtExitManager> at_exit_manager_;
-};
-
-} // namespace NPAPIClient
-
-#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_THREAD_ASYNC_CALL_TEST_H_
diff --git a/webkit/glue/plugins/test/plugin_window_size_test.cc b/webkit/glue/plugins/test/plugin_window_size_test.cc
deleted file mode 100644
index 9bfabca..0000000
--- a/webkit/glue/plugins/test/plugin_window_size_test.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/test/plugin_window_size_test.h"
-#include "webkit/glue/plugins/test/plugin_client.h"
-
-namespace NPAPIClient {
-
-PluginWindowSizeTest::PluginWindowSizeTest(NPP id,
- NPNetscapeFuncs *host_functions)
- : PluginTest(id, host_functions) {
-}
-
-NPError PluginWindowSizeTest::SetWindow(NPWindow* pNPWindow) {
- if (pNPWindow->window == NULL)
- return NPERR_NO_ERROR;
-
- HWND window = reinterpret_cast<HWND>(pNPWindow->window);
- if (!pNPWindow || !::IsWindow(window)) {
- SetError("Invalid arguments passed in");
- return NPERR_INVALID_PARAM;
- }
-
- RECT window_rect = {0};
- window_rect.left = pNPWindow->x;
- window_rect.top = pNPWindow->y;
- window_rect.right = pNPWindow->width;
- window_rect.bottom = pNPWindow->height;
-
- if (!::IsRectEmpty(&window_rect)) {
- RECT client_rect = {0};
- ::GetClientRect(window, &client_rect);
- if (::IsRectEmpty(&client_rect)) {
- SetError("The client rect of the plugin window is empty. Test failed");
- }
-
- // Bug 6742: ensure that the coordinates passed in are relative to the
- // parent HWND.
- POINT origin_from_os;
- RECT window_rect_from_os;
- ::GetWindowRect(window, &window_rect_from_os);
- origin_from_os.x = window_rect_from_os.left;
- origin_from_os.y = window_rect_from_os.top;
- ::ScreenToClient(GetParent(window), &origin_from_os);
- if (origin_from_os.x != pNPWindow->x || origin_from_os.y != pNPWindow->y)
- SetError("Wrong position passed in to SetWindow! Test failed");
-
- SignalTestCompleted();
- }
-
- return NPERR_NO_ERROR;
-}
-
-} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_window_size_test.h b/webkit/glue/plugins/test/plugin_window_size_test.h
deleted file mode 100644
index 3650671..0000000
--- a/webkit/glue/plugins/test/plugin_window_size_test.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_WINDOW_SIZE_TEST_H
-#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_WINDOW_SIZE_TEST_H
-
-#include "webkit/glue/plugins/test/plugin_test.h"
-
-namespace NPAPIClient {
-
-// This class tests whether the plugin window has a non zero rect
-// on the second SetWindow call.
-class PluginWindowSizeTest : public PluginTest {
- public:
- // Constructor.
- PluginWindowSizeTest(NPP id, NPNetscapeFuncs *host_functions);
- // NPAPI SetWindow handler
- virtual NPError SetWindow(NPWindow* pNPWindow);
-};
-
-} // namespace NPAPIClient
-
-#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_WINDOW_SIZE_TEST_H
diff --git a/webkit/glue/plugins/test/plugin_windowed_test.cc b/webkit/glue/plugins/test/plugin_windowed_test.cc
deleted file mode 100644
index 2ed3ae6..0000000
--- a/webkit/glue/plugins/test/plugin_windowed_test.cc
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright (c) 2009 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 "webkit/glue/plugins/test/plugin_windowed_test.h"
-#include "webkit/glue/plugins/test/plugin_client.h"
-
-namespace NPAPIClient {
-
-WindowedPluginTest::WindowedPluginTest(NPP id, NPNetscapeFuncs *host_functions)
- : PluginTest(id, host_functions),
- window_(NULL), done_(false) {
-}
-
-WindowedPluginTest::~WindowedPluginTest() {
- if (window_)
- DestroyWindow(window_);
-}
-
-NPError WindowedPluginTest::SetWindow(NPWindow* pNPWindow) {
- if (pNPWindow->window == NULL)
- return NPERR_NO_ERROR;
-
- if (test_name() == "create_instance_in_paint" && test_id() == "2") {
- SignalTestCompleted();
- return NPERR_NO_ERROR;
- }
-
- if (window_)
- return NPERR_NO_ERROR;
-
- HWND parent = reinterpret_cast<HWND>(pNPWindow->window);
- if (!pNPWindow || !::IsWindow(parent)) {
- SetError("Invalid arguments passed in");
- return NPERR_INVALID_PARAM;
- }
-
- if ((test_name() == "create_instance_in_paint" && test_id() == "1") ||
- test_name() == "alert_in_window_message" ||
- test_name() == "invoke_js_function_on_create") {
- static ATOM window_class = 0;
- if (!window_class) {
- WNDCLASSEX wcex;
- wcex.cbSize = sizeof(WNDCLASSEX);
- wcex.style = CS_DBLCLKS;
- wcex.lpfnWndProc = &NPAPIClient::WindowedPluginTest::WindowProc;
- wcex.cbClsExtra = 0;
- wcex.cbWndExtra = 0;
- wcex.hInstance = GetModuleHandle(NULL);
- wcex.hIcon = 0;
- wcex.hCursor = 0;
- wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW+1);
- wcex.lpszMenuName = 0;
- wcex.lpszClassName = L"CreateInstanceInPaintTestWindowClass";
- wcex.hIconSm = 0;
- window_class = RegisterClassEx(&wcex);
- }
-
- window_ = CreateWindowEx(
- WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR,
- MAKEINTATOM(window_class), 0,
- WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE ,
- 0, 0, 100, 100, parent, 0, GetModuleHandle(NULL), 0);
- DCHECK(window_);
- // TODO: this propery leaks.
- ::SetProp(window_, L"Plugin_Instance", this);
- }
-
- return NPERR_NO_ERROR;
-}
-
-NPError WindowedPluginTest::Destroy() {
- if (test_name() != "ensure_scripting_works_in_destroy")
- return NPERR_NO_ERROR;
-
- // Bug 23706: ensure that scripting works with no asserts.
- NPObject *window_obj = NULL;
- HostFunctions()->getvalue(id(), NPNVWindowNPObject,&window_obj);
-
- if (!window_obj) {
- SetError("Failed to get NPObject for plugin instance");
- } else {
- std::string script = "javascript:GetMagicNumber()";
- NPString script_string;
- script_string.UTF8Characters = script.c_str();
- script_string.UTF8Length =
- static_cast<unsigned int>(script.length());
-
- NPVariant result_var;
- bool result = HostFunctions()->evaluate(
- id(), window_obj, &script_string, &result_var);
- if (!result ||
- result_var.type != NPVariantType_Int32 ||
- result_var.value.intValue != 42) {
- SetError("Failed to script during NPP_Destroy");
- }
- }
-
- SignalTestCompleted();
- return NPERR_NO_ERROR;
-}
-
-void WindowedPluginTest::CallJSFunction(
- WindowedPluginTest* this_ptr, const char* function) {
- NPIdentifier function_id = this_ptr->HostFunctions()->getstringidentifier(
- function);
-
- NPObject *window_obj = NULL;
- this_ptr->HostFunctions()->getvalue(
- this_ptr->id(), NPNVWindowNPObject, &window_obj);
-
- NPVariant rv;
- this_ptr->HostFunctions()->invoke(
- this_ptr->id(), window_obj, function_id, NULL, 0, &rv);
-}
-
-LRESULT CALLBACK WindowedPluginTest::WindowProc(
- HWND window, UINT message, WPARAM wparam, LPARAM lparam) {
- WindowedPluginTest* this_ptr =
- reinterpret_cast<WindowedPluginTest*>
- (::GetProp(window, L"Plugin_Instance"));
-
- if (this_ptr && !this_ptr->done_) {
- if (this_ptr->test_name() == "create_instance_in_paint" &&
- message == WM_PAINT) {
- this_ptr->done_ = true;
- CallJSFunction(this_ptr, "CreateNewInstance");
- } else if (this_ptr->test_name() == "alert_in_window_message" &&
- message == WM_PAINT) {
- this_ptr->done_ = true;
- // We call this function twice as we want to display two alerts
- // and verify that we don't hang the browser.
- CallJSFunction(this_ptr, "CallAlert");
- CallJSFunction(this_ptr, "CallAlert");
- } else if (this_ptr->test_name() ==
- "invoke_js_function_on_create" &&
- message == WM_PAINT) {
- this_ptr->done_ = true;
- CallJSFunction(this_ptr, "PluginCreated");
- }
-
- if (this_ptr->done_) {
- ::RemoveProp(window, L"Plugin_Instance");
- }
- }
-
- return DefWindowProc(window, message, wparam, lparam);
-}
-
-} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_windowed_test.h b/webkit/glue/plugins/test/plugin_windowed_test.h
deleted file mode 100644
index 949ea86..0000000
--- a/webkit/glue/plugins/test/plugin_windowed_test.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) 2009 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 WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_WINDOWED_TEST_H
-#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_WINDOWED_TEST_H
-
-#include "webkit/glue/plugins/test/plugin_test.h"
-
-namespace NPAPIClient {
-
-// This class contains a list of windowed plugin tests. Please add additional
-// tests to this class.
-class WindowedPluginTest : public PluginTest {
- public:
- WindowedPluginTest(NPP id, NPNetscapeFuncs *host_functions);
- ~WindowedPluginTest();
-
- private:
- static LRESULT CALLBACK WindowProc(
- HWND window, UINT message, WPARAM wparam, LPARAM lparam);
- static void CallJSFunction(WindowedPluginTest*, const char*);
-
- virtual NPError SetWindow(NPWindow* pNPWindow);
- virtual NPError Destroy();
-
- HWND window_;
- bool done_;
-};
-
-} // namespace NPAPIClient
-
-#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_WINDOWED_TEST_H
diff --git a/webkit/glue/plugins/test/plugin_windowless_test.cc b/webkit/glue/plugins/test/plugin_windowless_test.cc
deleted file mode 100644
index aa6a9d7..0000000
--- a/webkit/glue/plugins/test/plugin_windowless_test.cc
+++ /dev/null
@@ -1,261 +0,0 @@
-// 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.
-
-#define STRSAFE_NO_DEPRECATE
-#include "base/string_number_conversions.h"
-#include "base/string_util.h"
-#include "webkit/glue/plugins/test/plugin_windowless_test.h"
-#include "webkit/glue/plugins/test/plugin_client.h"
-
-#if defined(OS_MACOSX)
-#include <ApplicationServices/ApplicationServices.h>
-#include <Carbon/Carbon.h>
-#endif
-
-namespace NPAPIClient {
-
-// Remember the first plugin instance for tests involving multiple instances
-WindowlessPluginTest* g_other_instance = NULL;
-
-WindowlessPluginTest::WindowlessPluginTest(NPP id,
- NPNetscapeFuncs *host_functions)
- : PluginTest(id, host_functions) {
- if (!g_other_instance)
- g_other_instance = this;
-}
-
-static bool IsPaintEvent(NPEvent* np_event) {
-#if defined(OS_WIN)
- return WM_PAINT == np_event->event;
-#elif defined(OS_MACOSX)
- return np_event->what == updateEvt;
-#endif
-}
-
-static bool IsMouseMoveEvent(NPEvent* np_event) {
-#if defined(OS_WIN)
- return WM_MOUSEMOVE == np_event->event;
-#elif defined(OS_MACOSX)
- return np_event->what == nullEvent;
-#endif
-}
-
-static bool IsMouseUpEvent(NPEvent* np_event) {
-#if defined(OS_WIN)
- return WM_LBUTTONUP == np_event->event;
-#elif defined(OS_MACOSX)
- return np_event->what == mouseUp;
-#endif
-}
-
-static bool IsWindowActivationEvent(NPEvent* np_event) {
-#if defined(OS_WIN)
- NOTIMPLEMENTED();
- return false;
-#elif defined(OS_MACOSX)
- return np_event->what == activateEvt;
-#endif
-}
-
-int16 WindowlessPluginTest::HandleEvent(void* event) {
-
- NPNetscapeFuncs* browser = NPAPIClient::PluginClient::HostFunctions();
-
- NPBool supports_windowless = 0;
- NPError result = browser->getvalue(id(), NPNVSupportsWindowless,
- &supports_windowless);
- if ((result != NPERR_NO_ERROR) || (supports_windowless != TRUE)) {
- SetError("Failed to read NPNVSupportsWindowless value");
- SignalTestCompleted();
- return PluginTest::HandleEvent(event);
- }
-
- NPEvent* np_event = reinterpret_cast<NPEvent*>(event);
- if (IsPaintEvent(np_event)) {
-#if defined(OS_WIN)
- HDC paint_dc = reinterpret_cast<HDC>(np_event->wParam);
- if (paint_dc == NULL) {
- SetError("Invalid Window DC passed to HandleEvent for WM_PAINT");
- SignalTestCompleted();
- return NPERR_GENERIC_ERROR;
- }
-
- HRGN clipping_region = CreateRectRgn(0, 0, 0, 0);
- if (!GetClipRgn(paint_dc, clipping_region)) {
- SetError("No clipping region set in window DC");
- DeleteObject(clipping_region);
- SignalTestCompleted();
- return NPERR_GENERIC_ERROR;
- }
-
- DeleteObject(clipping_region);
-#endif
-
- if (test_name() == "execute_script_delete_in_paint") {
- ExecuteScriptDeleteInPaint(browser);
- } else if (test_name() == "multiple_instances_sync_calls") {
- MultipleInstanceSyncCalls(browser);
- }
-#if OS_MACOSX
- } else if (IsWindowActivationEvent(np_event) &&
- test_name() == "convert_point") {
- ConvertPoint(browser);
-#endif
- } else if (IsMouseMoveEvent(np_event) &&
- test_name() == "execute_script_delete_in_mouse_move") {
- ExecuteScript(browser, id(), "DeletePluginWithinScript();", NULL);
- SignalTestCompleted();
- } else if (IsMouseUpEvent(np_event) &&
- test_name() == "delete_frame_test") {
- ExecuteScript(
- browser, id(),
- "parent.document.getElementById('frame').outerHTML = ''", NULL);
- }
- // If this test failed, then we'd have crashed by now.
- return PluginTest::HandleEvent(event);
-}
-
-NPError WindowlessPluginTest::ExecuteScript(NPNetscapeFuncs* browser, NPP id,
- const std::string& script, NPVariant* result) {
- std::string script_url = "javascript:";
- script_url += script;
-
- NPString script_string = { script_url.c_str(), script_url.length() };
- NPObject *window_obj = NULL;
- browser->getvalue(id, NPNVWindowNPObject, &window_obj);
-
- NPVariant unused_result;
- if (!result)
- result = &unused_result;
-
- return browser->evaluate(id, window_obj, &script_string, result);
-}
-
-void WindowlessPluginTest::ExecuteScriptDeleteInPaint(
- NPNetscapeFuncs* browser) {
- const NPUTF8* urlString = "javascript:DeletePluginWithinScript()";
- const NPUTF8* targetString = NULL;
- browser->geturl(id(), urlString, targetString);
- SignalTestCompleted();
-}
-
-void WindowlessPluginTest::MultipleInstanceSyncCalls(NPNetscapeFuncs* browser) {
- if (this == g_other_instance)
- return;
-
- DCHECK(g_other_instance);
- ExecuteScript(browser, g_other_instance->id(), "TestCallback();", NULL);
- SignalTestCompleted();
-}
-
-#if defined(OS_MACOSX)
-std::string StringForPoint(int x, int y) {
- std::string point_string("(");
- point_string.append(base::IntToString(x));
- point_string.append(", ");
- point_string.append(base::IntToString(y));
- point_string.append(")");
- return point_string;
-}
-#endif
-
-void WindowlessPluginTest::ConvertPoint(NPNetscapeFuncs* browser) {
-#if defined(OS_MACOSX)
- // First, just sanity-test that round trips work.
- NPCoordinateSpace spaces[] = { NPCoordinateSpacePlugin,
- NPCoordinateSpaceWindow,
- NPCoordinateSpaceFlippedWindow,
- NPCoordinateSpaceScreen,
- NPCoordinateSpaceFlippedScreen };
- for (unsigned int i = 0; i < arraysize(spaces); ++i) {
- for (unsigned int j = 0; j < arraysize(spaces); ++j) {
- double x, y, round_trip_x, round_trip_y;
- if (!(browser->convertpoint(id(), 0, 0, spaces[i], &x, &y, spaces[j])) ||
- !(browser->convertpoint(id(), x, y, spaces[j], &round_trip_x,
- &round_trip_y, spaces[i]))) {
- SetError("Conversion failed");
- SignalTestCompleted();
- return;
- }
- if (i != j && x == 0 && y == 0) {
- SetError("Converting a coordinate should change it");
- SignalTestCompleted();
- return;
- }
- if (round_trip_x != 0 || round_trip_y != 0) {
- SetError("Round-trip conversion should return the original point");
- SignalTestCompleted();
- return;
- }
- }
- }
-
- // Now, more extensive testing on a single point.
- double screen_x, screen_y;
- browser->convertpoint(id(), 0, 0, NPCoordinateSpacePlugin,
- &screen_x, &screen_y, NPCoordinateSpaceScreen);
- double flipped_screen_x, flipped_screen_y;
- browser->convertpoint(id(), 0, 0, NPCoordinateSpacePlugin,
- &flipped_screen_x, &flipped_screen_y,
- NPCoordinateSpaceFlippedScreen);
- double window_x, window_y;
- browser->convertpoint(id(), 0, 0, NPCoordinateSpacePlugin,
- &window_x, &window_y, NPCoordinateSpaceWindow);
- double flipped_window_x, flipped_window_y;
- browser->convertpoint(id(), 0, 0, NPCoordinateSpacePlugin,
- &flipped_window_x, &flipped_window_y,
- NPCoordinateSpaceFlippedWindow);
-
- CGRect main_display_bounds = CGDisplayBounds(CGMainDisplayID());
-
- // Check that all the coordinates are right. The constants below are based on
- // the window frame set in the UI test and the content offset in the test
- // html. Y-coordinates are not checked exactly so that the test is robust
- // against toolbar changes, info and bookmark bar visibility, etc.
- const int kWindowHeight = 400;
- const int kWindowXOrigin = 50;
- const int kWindowYOrigin = 50;
- const int kPluginXContentOffset = 50;
- const int kPluginYContentOffset = 50;
- const int kChromeYTolerance = 200;
-
- std::string error_string;
- if (screen_x != flipped_screen_x)
- error_string = "Flipping screen coordinates shouldn't change x";
- else if (flipped_screen_y != main_display_bounds.size.height - screen_y)
- error_string = "Flipped screen coordinates should be flipped vertically";
- else if (screen_x != kWindowXOrigin + kPluginXContentOffset)
- error_string = "Screen x location is wrong";
- else if (flipped_screen_y < kWindowYOrigin + kPluginYContentOffset ||
- flipped_screen_y > kWindowYOrigin + kPluginYContentOffset +
- kChromeYTolerance)
- error_string = "Screen y location is wrong";
- else if (window_x != flipped_window_x)
- error_string = "Flipping window coordinates shouldn't change x";
- else if (flipped_window_y != kWindowHeight - window_y)
- error_string = "Flipped window coordinates should be flipped vertically";
- else if (window_x != kPluginXContentOffset)
- error_string = "Window x location is wrong";
- else if (flipped_window_y < kPluginYContentOffset ||
- flipped_window_y > kPluginYContentOffset + kChromeYTolerance)
- error_string = "Window y location is wrong";
-
- if (!error_string.empty()) {
- error_string.append(" - ");
- error_string.append(StringForPoint(screen_x, screen_y));
- error_string.append(" - ");
- error_string.append(StringForPoint(flipped_screen_x, flipped_screen_y));
- error_string.append(" - ");
- error_string.append(StringForPoint(window_x, window_y));
- error_string.append(" - ");
- error_string.append(StringForPoint(flipped_window_x, flipped_window_y));
- SetError(error_string);
- }
-#else
- SetError("Unimplemented");
-#endif
- SignalTestCompleted();
-}
-
-} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_windowless_test.h b/webkit/glue/plugins/test/plugin_windowless_test.h
deleted file mode 100644
index f336653..0000000
--- a/webkit/glue/plugins/test/plugin_windowless_test.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_EXECUTE_SCRIPT_DELETE_TEST_H
-#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_EXECUTE_SCRIPT_DELETE_TEST_H
-
-#include "webkit/glue/plugins/test/plugin_test.h"
-
-namespace NPAPIClient {
-
-// This class contains a list of windowless plugin tests. Please add additional
-// tests to this class.
-class WindowlessPluginTest : public PluginTest {
- public:
- // Constructor.
- WindowlessPluginTest(NPP id, NPNetscapeFuncs *host_functions);
-
- // These tests run in windowless plugin mode.
- virtual bool IsWindowless() const { return true; }
-
- // NPAPI HandleEvent handler
- virtual int16 HandleEvent(void* event);
-
- protected:
- NPError ExecuteScript(NPNetscapeFuncs* browser, NPP id,
- const std::string& script, NPVariant* result);
- void ExecuteScriptDeleteInPaint(NPNetscapeFuncs* browser);
- void MultipleInstanceSyncCalls(NPNetscapeFuncs* browser);
- void ConvertPoint(NPNetscapeFuncs* browser);
-};
-
-} // namespace NPAPIClient
-
-#endif // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_EXECUTE_SCRIPT_DELETE_TEST_H
diff --git a/webkit/glue/plugins/test/resource.h b/webkit/glue/plugins/test/resource.h
deleted file mode 100644
index c52fa82..0000000
--- a/webkit/glue/plugins/test/resource.h
+++ /dev/null
@@ -1,15 +0,0 @@
-//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by npapi_test.rc
-//
-
-// Next default values for new objects
-//
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE 101
-#define _APS_NEXT_COMMAND_VALUE 40001
-#define _APS_NEXT_CONTROL_VALUE 1001
-#define _APS_NEXT_SYMED_VALUE 101
-#endif
-#endif
diff --git a/webkit/glue/plugins/webplugin.cc b/webkit/glue/plugins/webplugin.cc
deleted file mode 100644
index 18f722b..0000000
--- a/webkit/glue/plugins/webplugin.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/webplugin.h"
-
-namespace webkit_glue {
-
-WebPluginGeometry::WebPluginGeometry()
- : window(gfx::kNullPluginWindow),
- rects_valid(false),
- visible(false) {
-}
-
-WebPluginGeometry::~WebPluginGeometry() {
-}
-
-bool WebPluginGeometry::Equals(const WebPluginGeometry& rhs) const {
- return window == rhs.window &&
- window_rect == rhs.window_rect &&
- clip_rect == rhs.clip_rect &&
- cutout_rects == rhs.cutout_rects &&
- rects_valid == rhs.rects_valid &&
- visible == rhs.visible;
-}
-} // namespace webkit_glue
diff --git a/webkit/glue/plugins/webplugin.h b/webkit/glue/plugins/webplugin.h
deleted file mode 100644
index 5fbef1f..0000000
--- a/webkit/glue/plugins/webplugin.h
+++ /dev/null
@@ -1,200 +0,0 @@
-// Copyright (c) 2006-2009 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 WEBKIT_GLUE_WEBPLUGIN_H_
-#define WEBKIT_GLUE_WEBPLUGIN_H_
-
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "gfx/native_widget_types.h"
-#include "gfx/rect.h"
-
-// TODO(port): this typedef is obviously incorrect on non-Windows
-// platforms, but now a lot of code now accidentally depends on them
-// existing. #ifdef out these declarations and fix all the users.
-typedef void* HANDLE;
-
-class GURL;
-struct NPObject;
-
-namespace WebKit {
-class WebFrame;
-}
-
-namespace webkit_glue {
-
-class WebPluginDelegate;
-class WebPluginParentView;
-class WebPluginResourceClient;
-#if defined(OS_MACOSX)
-class WebPluginAcceleratedSurface;
-#endif
-
-// Describes the new location for a plugin window.
-struct WebPluginGeometry {
- WebPluginGeometry();
- ~WebPluginGeometry();
-
- bool Equals(const WebPluginGeometry& rhs) const;
-
- // On Windows, this is the plugin window in the plugin process.
- // On X11, this is the XID of the plugin-side GtkPlug containing the
- // GtkSocket hosting the actual plugin window.
- //
- // On Mac OS X, all of the plugin types are currently "windowless"
- // (window == 0) except for the special case of the GPU plugin,
- // which currently performs rendering on behalf of the Pepper 3D API
- // and WebGL. The GPU plugin uses a simple integer for the
- // PluginWindowHandle which is used to map to a side data structure
- // containing information about the plugin. Soon this plugin will be
- // generalized, at which point this mechanism will be rethought or
- // removed.
- gfx::PluginWindowHandle window;
- gfx::Rect window_rect;
- // Clip rect (include) and cutouts (excludes), relative to
- // window_rect origin.
- gfx::Rect clip_rect;
- std::vector<gfx::Rect> cutout_rects;
- bool rects_valid;
- bool visible;
-};
-
-// The WebKit side of a plugin implementation. It provides wrappers around
-// operations that need to interact with the frame and other WebCore objects.
-class WebPlugin {
- public:
- virtual ~WebPlugin() {}
-
- // Called by the plugin delegate to let the WebPlugin know if the plugin is
- // windowed (i.e. handle is not NULL) or windowless (handle is NULL). This
- // tells the WebPlugin to send mouse/keyboard events to the plugin delegate,
- // as well as the information about the HDC for paint operations.
- virtual void SetWindow(gfx::PluginWindowHandle window) = 0;
-
- // Whether input events should be sent to the delegate.
- virtual void SetAcceptsInputEvents(bool accepts) = 0;
-
- // Called by the plugin delegate to let it know that the window is being
- // destroyed.
- virtual void WillDestroyWindow(gfx::PluginWindowHandle window) = 0;
-#if defined(OS_WIN)
- // The pump_messages_event is a event handle which is valid only for
- // windowless plugins and is used in NPP_HandleEvent calls to pump messages
- // if the plugin enters a modal loop.
- // Cancels a pending request.
- virtual void SetWindowlessPumpEvent(HANDLE pump_messages_event) = 0;
-#endif
- virtual void CancelResource(unsigned long id) = 0;
- virtual void Invalidate() = 0;
- virtual void InvalidateRect(const gfx::Rect& rect) = 0;
-
- // Returns the NPObject for the browser's window object.
- virtual NPObject* GetWindowScriptNPObject() = 0;
-
- // Returns the DOM element that loaded the plugin.
- virtual NPObject* GetPluginElement() = 0;
-
- // Cookies
- virtual void SetCookie(const GURL& url,
- const GURL& first_party_for_cookies,
- const std::string& cookie) = 0;
- virtual std::string GetCookies(const GURL& url,
- const GURL& first_party_for_cookies) = 0;
-
- // Shows a modal HTML dialog containing the given URL. json_arguments are
- // passed to the dialog via the DOM 'window.chrome.dialogArguments', and the
- // retval is the string returned by 'window.chrome.send("DialogClose",
- // retval)'.
- virtual void ShowModalHTMLDialog(const GURL& url, int width, int height,
- const std::string& json_arguments,
- std::string* json_retval) = 0;
-
- // When a default plugin has downloaded the plugin list and finds it is
- // available, it calls this method to notify the renderer. Also it will update
- // the status when user clicks on the plugin to install.
- virtual void OnMissingPluginStatus(int status) = 0;
-
- // Handles GetURL/GetURLNotify/PostURL/PostURLNotify requests initiated
- // by plugins. If the plugin wants notification of the result, notify_id will
- // be non-zero.
- virtual void HandleURLRequest(const char* url,
- const char* method,
- const char* target,
- const char* buf,
- unsigned int len,
- int notify_id,
- bool popups_allowed,
- bool notify_redirects) = 0;
-
- // Cancels document load.
- virtual void CancelDocumentLoad() = 0;
-
- // Initiates a HTTP range request for an existing stream.
- virtual void InitiateHTTPRangeRequest(const char* url,
- const char* range_info,
- int range_request_id) = 0;
-
- // Returns true iff in off the record (Incognito) mode.
- virtual bool IsOffTheRecord() = 0;
-
- // Called when the WebPluginResourceClient instance is deleted.
- virtual void ResourceClientDeleted(
- WebPluginResourceClient* resource_client) {}
-
- // Defers the loading of the resource identified by resource_id. This is
- // controlled by the defer parameter.
- virtual void SetDeferResourceLoading(unsigned long resource_id,
- bool defer) = 0;
-
-#if defined(OS_MACOSX)
- // Enables/disables plugin IME.
- virtual void SetImeEnabled(bool enabled) {};
-
- // Synthesize a fake window handle for the plug-in to identify the instance
- // to the browser, allowing mapping to a surface for hardware accelleration
- // of plug-in content. The browser generates the handle which is then set on
- // the plug-in. |opaque| indicates whether the content should be treated as
- // opaque or translucent.
- // TODO(stuartmorgan): Move this into WebPluginProxy.
- virtual void BindFakePluginWindowHandle(bool opaque) {}
-
- // Returns the accelerated surface abstraction for accelerated plugins.
- virtual WebPluginAcceleratedSurface* GetAcceleratedSurface() { return NULL; }
-#endif
-
- // Gets the WebPluginDelegate that implements the interface.
- // This API is only for use with Pepper, and is only overridden
- // by in-renderer implementations.
- virtual WebPluginDelegate* delegate() { return NULL; }
-
- // Handles NPN_URLRedirectResponse calls issued by plugins in response to
- // HTTP URL redirect notifications.
- virtual void URLRedirectResponse(bool allow, int resource_id) = 0;
-};
-
-// Simpler version of ResourceHandleClient that lends itself to proxying.
-class WebPluginResourceClient {
- public:
- virtual ~WebPluginResourceClient() {}
- virtual void WillSendRequest(const GURL& url, int http_status_code) = 0;
- // The request_is_seekable parameter indicates whether byte range requests
- // can be issued for the underlying stream.
- virtual void DidReceiveResponse(const std::string& mime_type,
- const std::string& headers,
- uint32 expected_length,
- uint32 last_modified,
- bool request_is_seekable) = 0;
- virtual void DidReceiveData(const char* buffer, int length,
- int data_offset) = 0;
- virtual void DidFinishLoading() = 0;
- virtual void DidFail() = 0;
- virtual bool IsMultiByteResponseExpected() = 0;
- virtual int ResourceId() = 0;
-};
-
-} // namespace webkit_glue
-
-#endif // #ifndef WEBKIT_GLUE_WEBPLUGIN_H_
diff --git a/webkit/glue/plugins/webplugin_2d_device_delegate.h b/webkit/glue/plugins/webplugin_2d_device_delegate.h
deleted file mode 100644
index 69bd53a..0000000
--- a/webkit/glue/plugins/webplugin_2d_device_delegate.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (c) 2009 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 WEBKIT_GLUE_PLUGINS_WEBPLUGIN_2D_DEVICE_DELEGATE_H_
-#define WEBKIT_GLUE_PLUGINS_WEBPLUGIN_2D_DEVICE_DELEGATE_H_
-
-#include "base/basictypes.h"
-#include "third_party/npapi/bindings/npapi_extensions.h"
-
-namespace webkit_glue {
-
-// Interface for the NPAPI 2D device extension. This class implements "NOP"
-// versions of all these functions so it can be used seamlessly by the
-// "regular" plugin delegate while being overridden by the "pepper" one.
-class WebPlugin2DDeviceDelegate {
- public:
- virtual NPError Device2DQueryCapability(int32 capability, int32* value) {
- return NPERR_GENERIC_ERROR;
- }
- virtual NPError Device2DQueryConfig(const NPDeviceContext2DConfig* request,
- NPDeviceContext2DConfig* obtain) {
- return NPERR_GENERIC_ERROR;
- }
- virtual NPError Device2DInitializeContext(
- const NPDeviceContext2DConfig* config,
- NPDeviceContext2D* context) {
- return NPERR_GENERIC_ERROR;
- }
- virtual NPError Device2DSetStateContext(NPDeviceContext2D* context,
- int32 state,
- intptr_t value) {
- return NPERR_GENERIC_ERROR;
- }
- virtual NPError Device2DGetStateContext(NPDeviceContext2D* context,
- int32 state,
- intptr_t* value) {
- return NPERR_GENERIC_ERROR;
- }
- virtual NPError Device2DFlushContext(NPP id,
- NPDeviceContext2D* context,
- NPDeviceFlushContextCallbackPtr callback,
- void* user_data) {
- return NPERR_GENERIC_ERROR;
- }
- virtual NPError Device2DDestroyContext(NPDeviceContext2D* context) {
- return NPERR_GENERIC_ERROR;
- }
-
- protected:
- WebPlugin2DDeviceDelegate() {}
- virtual ~WebPlugin2DDeviceDelegate() {}
-};
-
-} // namespace webkit_glue
-
-#endif // WEBKIT_GLUE_PLUGINS_WEBPLUGIN_2D_DEVICE_DELEGATE_H_
diff --git a/webkit/glue/plugins/webplugin_3d_device_delegate.h b/webkit/glue/plugins/webplugin_3d_device_delegate.h
deleted file mode 100644
index fbb46eb..0000000
--- a/webkit/glue/plugins/webplugin_3d_device_delegate.h
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright (c) 2009 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 WEBKIT_GLUE_PLUGINS_WEBPLUGIN_3D_DEVICE_DELEGATE_H_
-#define WEBKIT_GLUE_PLUGINS_WEBPLUGIN_3D_DEVICE_DELEGATE_H_
-
-#include "base/basictypes.h"
-#include "third_party/npapi/bindings/npapi_extensions.h"
-
-namespace webkit_glue {
-
-// Interface for the NPAPI 3D device extension. This class implements "NOP"
-// versions of all these functions so it can be used seamlessly by the
-// "regular" plugin delegate while being overridden by the "pepper" one.
-class WebPlugin3DDeviceDelegate {
- public:
- virtual NPError Device3DQueryCapability(int32 capability, int32* value) {
- return NPERR_GENERIC_ERROR;
- }
- virtual NPError Device3DQueryConfig(const NPDeviceContext3DConfig* request,
- NPDeviceContext3DConfig* obtain) {
- return NPERR_GENERIC_ERROR;
- }
- virtual NPError Device3DInitializeContext(
- const NPDeviceContext3DConfig* config,
- NPDeviceContext3D* context) {
- return NPERR_GENERIC_ERROR;
- }
- virtual NPError Device3DSetStateContext(NPDeviceContext3D* context,
- int32 state,
- intptr_t value) {
- return NPERR_GENERIC_ERROR;
- }
- virtual NPError Device3DGetStateContext(NPDeviceContext3D* context,
- int32 state,
- intptr_t* value) {
- return NPERR_GENERIC_ERROR;
- }
- virtual NPError Device3DFlushContext(NPP id,
- NPDeviceContext3D* context,
- NPDeviceFlushContextCallbackPtr callback,
- void* user_data) {
- return NPERR_GENERIC_ERROR;
- }
- virtual NPError Device3DDestroyContext(NPDeviceContext3D* context) {
- return NPERR_GENERIC_ERROR;
- }
- virtual NPError Device3DCreateBuffer(NPDeviceContext3D* context,
- size_t size,
- int32* id) {
- return NPERR_GENERIC_ERROR;
- }
- virtual NPError Device3DDestroyBuffer(NPDeviceContext3D* context,
- int32 id) {
- return NPERR_GENERIC_ERROR;
- }
- virtual NPError Device3DMapBuffer(NPDeviceContext3D* context,
- int32 id,
- NPDeviceBuffer* buffer) {
- return NPERR_GENERIC_ERROR;
- }
- virtual NPError Device3DGetNumConfigs(int32* num_configs) {
- return NPERR_GENERIC_ERROR;
- }
- virtual NPError Device3DGetConfigAttribs(int32 config,
- int32* attrib_list) {
- return NPERR_GENERIC_ERROR;
- }
- virtual NPError Device3DCreateContext(int32 config,
- const int32* attrib_list,
- NPDeviceContext3D** context) {
- return NPERR_GENERIC_ERROR;
- }
- virtual NPError Device3DRegisterCallback(
- NPP id,
- NPDeviceContext* context,
- int32 callback_type,
- NPDeviceGenericCallbackPtr callback,
- void* callback_data) {
- return NPERR_GENERIC_ERROR;
- }
- virtual NPError Device3DSynchronizeContext(
- NPP id,
- NPDeviceContext3D* context,
- NPDeviceSynchronizationMode mode,
- const int32* input_attrib_list,
- int32* output_attrib_list,
- NPDeviceSynchronizeContextCallbackPtr callback,
- void* callback_data) {
- return NPERR_GENERIC_ERROR;
- }
-
- protected:
- WebPlugin3DDeviceDelegate() {}
- virtual ~WebPlugin3DDeviceDelegate() {}
-};
-
-} // namespace webkit_glue
-
-#endif // WEBKIT_GLUE_PLUGINS_WEBPLUGIN_3D_DEVICE_DELEGATE_H_
diff --git a/webkit/glue/plugins/webplugin_accelerated_surface_mac.h b/webkit/glue/plugins/webplugin_accelerated_surface_mac.h
deleted file mode 100644
index 13980ca..0000000
--- a/webkit/glue/plugins/webplugin_accelerated_surface_mac.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 2006-2009 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 WEBKIT_GLUE_WEBPLUGIN_ACCELERATED_SURFACE_MAC_H_
-#define WEBKIT_GLUE_WEBPLUGIN_ACCELERATED_SURFACE_MAC_H_
-#pragma once
-
-#include "gfx/native_widget_types.h"
-#include "gfx/size.h"
-
-// Avoid having to include OpenGL headers here.
-typedef struct _CGLContextObject* CGLContextObj;
-
-namespace webkit_glue {
-
-// Interface class for interacting with an accelerated plugin surface, used
-// for the Core Animation flavors of plugin drawing on the Mac.
-class WebPluginAcceleratedSurface {
- public:
- virtual ~WebPluginAcceleratedSurface() {}
-
- // Sets the window handle used throughout the browser to identify this
- // surface.
- virtual void SetWindowHandle(gfx::PluginWindowHandle window) = 0;
-
- // Sets the size of the surface.
- virtual void SetSize(const gfx::Size& size) = 0;
-
- // Returns the context used to draw into this surface.
- // If initializing the surface failed, this will be NULL.
- virtual CGLContextObj context() = 0;
-
- // Readies the surface for drawing. Must be called before any drawing session.
- virtual void StartDrawing() = 0;
-
- // Ends a drawing session. Changes to the surface may not be reflected until
- // this is called.
- virtual void EndDrawing() = 0;
-};
-
-} // namespace webkit_glue
-
-#endif // WEBKIT_GLUE_WEBPLUGIN_ACCELERATED_SURFACE_MAC_H_
diff --git a/webkit/glue/plugins/webplugin_audio_device_delegate.h b/webkit/glue/plugins/webplugin_audio_device_delegate.h
deleted file mode 100644
index 3f37246..0000000
--- a/webkit/glue/plugins/webplugin_audio_device_delegate.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright (c) 2009 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 WEBKIT_GLUE_PLUGINS_WEBPLUGIN_AUDIO_DEVICE_DELEGATE_H_
-#define WEBKIT_GLUE_PLUGINS_WEBPLUGIN_AUDIO_DEVICE_DELEGATE_H_
-
-#include "base/basictypes.h"
-#include "third_party/npapi/bindings/npapi_extensions.h"
-
-namespace webkit_glue {
-
-// Interface for the NPAPI audio device extension. This class implements "NOP"
-// versions of all these functions so it can be used seamlessly by the
-// "regular" plugin delegate while being overridden by the "pepper" one.
-class WebPluginAudioDeviceDelegate {
- public:
- virtual NPError DeviceAudioQueryCapability(int32 capability, int32* value) {
- return NPERR_GENERIC_ERROR;
- }
- virtual NPError DeviceAudioQueryConfig(
- const NPDeviceContextAudioConfig* request,
- NPDeviceContextAudioConfig* obtain) {
- return NPERR_GENERIC_ERROR;
- }
- virtual NPError DeviceAudioInitializeContext(
- const NPDeviceContextAudioConfig* config,
- NPDeviceContextAudio* context) {
- return NPERR_GENERIC_ERROR;
- }
- virtual NPError DeviceAudioSetStateContext(NPDeviceContextAudio* context,
- int32 state, intptr_t value) {
- return NPERR_GENERIC_ERROR;
- }
- virtual NPError DeviceAudioGetStateContext(NPDeviceContextAudio* context,
- int32 state, intptr_t* value) {
- return NPERR_GENERIC_ERROR;
- }
- virtual NPError DeviceAudioFlushContext(
- NPP id, NPDeviceContextAudio* context,
- NPDeviceFlushContextCallbackPtr callback, void* user_data) {
- return NPERR_GENERIC_ERROR;
- }
- virtual NPError DeviceAudioDestroyContext(NPDeviceContextAudio* context) {
- return NPERR_GENERIC_ERROR;
- }
-
- protected:
- WebPluginAudioDeviceDelegate() {}
- virtual ~WebPluginAudioDeviceDelegate() {}
-};
-
-} // namespace webkit_glue
-
-#endif // WEBKIT_GLUE_PLUGINS_WEBPLUGIN_AUDIO_DEVICE_DELEGATE_H_
-
diff --git a/webkit/glue/plugins/webplugin_delegate.h b/webkit/glue/plugins/webplugin_delegate.h
deleted file mode 100644
index 901cdea..0000000
--- a/webkit/glue/plugins/webplugin_delegate.h
+++ /dev/null
@@ -1,166 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_WEBPLUGIN_DELEGATE_H_
-#define WEBKIT_GLUE_WEBPLUGIN_DELEGATE_H_
-
-#include <string>
-#include <vector>
-
-#include "base/string16.h"
-#include "build/build_config.h"
-#include "gfx/native_widget_types.h"
-#include "third_party/npapi/bindings/npapi.h"
-#include "third_party/npapi/bindings/npapi_extensions.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebCanvas.h"
-#include "webkit/glue/plugins/webplugin_2d_device_delegate.h"
-#include "webkit/glue/plugins/webplugin_3d_device_delegate.h"
-#include "webkit/glue/plugins/webplugin_audio_device_delegate.h"
-#include "webkit/glue/plugins/webplugin_file_delegate.h"
-#include "webkit/glue/plugins/webplugin_print_delegate.h"
-
-class FilePath;
-class GURL;
-struct NPObject;
-
-namespace WebKit {
-class WebInputEvent;
-struct WebCursorInfo;
-}
-
-namespace gfx {
-class Rect;
-}
-
-namespace webkit_glue {
-
-class WebPlugin;
-class WebPluginResourceClient;
-
-// This is the interface that a plugin implementation needs to provide.
-class WebPluginDelegate : public WebPlugin2DDeviceDelegate,
- public WebPlugin3DDeviceDelegate,
- public WebPluginAudioDeviceDelegate,
- public WebPluginPrintDelegate,
- public WebPluginFileDelegate {
- public:
- virtual ~WebPluginDelegate() {}
-
- // Initializes the plugin implementation with the given (UTF8) arguments.
- // Note that the lifetime of WebPlugin must be longer than this delegate.
- // If this function returns false the plugin isn't started and shouldn't be
- // called again. If this method succeeds, then the WebPlugin is valid until
- // PluginDestroyed is called.
- // The load_manually parameter if true indicates that the plugin data would
- // be passed from webkit. if false indicates that the plugin should download
- // the data. This also controls whether the plugin is instantiated as a full
- // page plugin (NP_FULL) or embedded (NP_EMBED).
- virtual bool Initialize(const GURL& url,
- const std::vector<std::string>& arg_names,
- const std::vector<std::string>& arg_values,
- WebPlugin* plugin,
- bool load_manually) = 0;
-
- // Called when the WebPlugin is being destroyed. This is a signal to the
- // delegate that it should tear-down the plugin implementation and not call
- // methods on the WebPlugin again.
- virtual void PluginDestroyed() = 0;
-
- // Update the geometry of the plugin. This is a request to move the
- // plugin, relative to its containing window, to the coords given by
- // window_rect. Its contents should be clipped to the coords given
- // by clip_rect, which are relative to the origin of the plugin
- // window. The clip_rect is in plugin-relative coordinates.
- virtual void UpdateGeometry(const gfx::Rect& window_rect,
- const gfx::Rect& clip_rect) = 0;
-
- // Tells the plugin to paint the damaged rect. |canvas| is only used for
- // windowless plugins.
- virtual void Paint(WebKit::WebCanvas* canvas, const gfx::Rect& rect) = 0;
-
- // Tells the plugin to print itself.
- virtual void Print(gfx::NativeDrawingContext hdc) = 0;
-
- // Informs the plugin that it has gained or lost focus. This is only called in
- // windowless mode.
- virtual void SetFocus(bool focused) = 0;
-
- // For windowless plugins, gives them a user event like mouse/keyboard.
- // Returns whether the event was handled. This is only called in windowsless
- // mode. See NPAPI NPP_HandleEvent for more information.
- virtual bool HandleInputEvent(const WebKit::WebInputEvent& event,
- WebKit::WebCursorInfo* cursor) = 0;
-
- // Gets the NPObject associated with the plugin for scripting.
- virtual NPObject* GetPluginScriptableObject() = 0;
-
- // Receives notification about a resource load that the plugin initiated
- // for a frame.
- virtual void DidFinishLoadWithReason(const GURL& url, NPReason reason,
- int notify_id) = 0;
-
- // Returns the process id of the process that is running the plugin.
- virtual int GetProcessId() = 0;
-
- // The result, UTF-8 encoded, of the script execution is returned via this
- // function.
- virtual void SendJavaScriptStream(const GURL& url,
- const std::string& result,
- bool success,
- int notify_id) = 0;
-
- // Receives notification about data being available.
- virtual void DidReceiveManualResponse(const GURL& url,
- const std::string& mime_type,
- const std::string& headers,
- uint32 expected_length,
- uint32 last_modified) = 0;
-
- // Receives the data.
- virtual void DidReceiveManualData(const char* buffer, int length) = 0;
-
- // Indicates end of data load.
- virtual void DidFinishManualLoading() = 0;
-
- // Indicates a failure in data receipt.
- virtual void DidManualLoadFail() = 0;
-
- // Only supported when the plugin is the default plugin.
- virtual void InstallMissingPlugin() = 0;
-
- // Creates a WebPluginResourceClient instance and returns the same.
- virtual WebPluginResourceClient* CreateResourceClient(
- unsigned long resource_id,
- const GURL& url,
- int notify_id) = 0;
-
- // Creates a WebPluginResourceClient instance for an existing stream that is
- // has become seekable.
- virtual WebPluginResourceClient* CreateSeekableResourceClient(
- unsigned long resource_id, int range_request_id) = 0;
-
- // See WebPluginContainerImpl's description of the interface.
- virtual bool StartFind(const string16& search_text,
- bool case_sensitive,
- int identifier) { return false; }
- virtual void SelectFindResult(bool forward) {}
- virtual void StopFind() {}
- virtual void NumberOfFindResultsChanged(int total, bool final_result) {}
- virtual void SelectedFindResultChanged(int index) {}
- virtual NPWidgetExtensions* GetWidgetExtensions() { return NULL; }
- virtual bool SetCursor(NPCursorType type) { return false; }
- virtual NPFontExtensions* GetFontExtensions() { return NULL; }
-
- // Used for zooming of full page plugins. 0 means reset, while -1 means zoom
- // out and +1 means zoom in.
- virtual void SetZoomFactor(float scale, bool text_only) {}
- // Gets the selected text, if any.
- virtual bool HasSelection() const { return false; }
- virtual string16 GetSelectionAsText() const { return string16(); }
- virtual string16 GetSelectionAsMarkup() const { return string16(); }
-};
-
-} // namespace webkit_glue
-
-#endif // WEBKIT_GLUE_WEBPLUGIN_DELEGATE_H_
diff --git a/webkit/glue/plugins/webplugin_delegate_impl.cc b/webkit/glue/plugins/webplugin_delegate_impl.cc
deleted file mode 100644
index e3e4f9d..0000000
--- a/webkit/glue/plugins/webplugin_delegate_impl.cc
+++ /dev/null
@@ -1,304 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/webplugin_delegate_impl.h"
-
-#include <string>
-#include <vector>
-
-#include "base/file_util.h"
-#include "base/message_loop.h"
-#include "base/process_util.h"
-#include "base/scoped_ptr.h"
-#include "base/string_util.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h"
-#include "webkit/glue/plugins/plugin_constants_win.h"
-#include "webkit/glue/plugins/plugin_instance.h"
-#include "webkit/glue/plugins/plugin_lib.h"
-#include "webkit/glue/plugins/plugin_list.h"
-#include "webkit/glue/plugins/plugin_stream_url.h"
-#include "webkit/glue/webkit_glue.h"
-
-using webkit_glue::WebPlugin;
-using webkit_glue::WebPluginDelegate;
-using webkit_glue::WebPluginResourceClient;
-using WebKit::WebCursorInfo;
-using WebKit::WebKeyboardEvent;
-using WebKit::WebInputEvent;
-using WebKit::WebMouseEvent;
-
-WebPluginDelegateImpl* WebPluginDelegateImpl::Create(
- const FilePath& filename,
- const std::string& mime_type,
- gfx::PluginWindowHandle containing_view) {
- scoped_refptr<NPAPI::PluginLib> plugin_lib(
- NPAPI::PluginLib::CreatePluginLib(filename));
- if (plugin_lib.get() == NULL)
- return NULL;
-
- NPError err = plugin_lib->NP_Initialize();
- if (err != NPERR_NO_ERROR)
- return NULL;
-
- scoped_refptr<NPAPI::PluginInstance> instance(
- plugin_lib->CreateInstance(mime_type));
- return new WebPluginDelegateImpl(containing_view, instance.get());
-}
-
-void WebPluginDelegateImpl::PluginDestroyed() {
- if (handle_event_depth_) {
- MessageLoop::current()->DeleteSoon(FROM_HERE, this);
- } else {
- delete this;
- }
-}
-
-bool WebPluginDelegateImpl::Initialize(
- const GURL& url,
- const std::vector<std::string>& arg_names,
- const std::vector<std::string>& arg_values,
- WebPlugin* plugin,
- bool load_manually) {
- plugin_ = plugin;
-
- instance_->set_web_plugin(plugin_);
- if (quirks_ & PLUGIN_QUIRK_DONT_ALLOW_MULTIPLE_INSTANCES) {
- NPAPI::PluginLib* plugin_lib = instance()->plugin_lib();
- if (plugin_lib->instance_count() > 1) {
- return false;
- }
- }
-
- if (quirks_ & PLUGIN_QUIRK_DIE_AFTER_UNLOAD)
- webkit_glue::SetForcefullyTerminatePluginProcess(true);
-
- int argc = 0;
- scoped_array<char*> argn(new char*[arg_names.size()]);
- scoped_array<char*> argv(new char*[arg_names.size()]);
- for (size_t i = 0; i < arg_names.size(); ++i) {
- if (quirks_ & PLUGIN_QUIRK_NO_WINDOWLESS &&
- LowerCaseEqualsASCII(arg_names[i], "windowlessvideo")) {
- continue;
- }
- argn[argc] = const_cast<char*>(arg_names[i].c_str());
- argv[argc] = const_cast<char*>(arg_values[i].c_str());
- argc++;
- }
-
- creation_succeeded_ = instance_->Start(
- url, argn.get(), argv.get(), argc, load_manually);
- if (!creation_succeeded_)
- return false;
-
- windowless_ = instance_->windowless();
- if (!windowless_) {
- if (!WindowedCreatePlugin())
- return false;
- } else {
- // For windowless plugins we should set the containing window handle
- // as the instance window handle. This is what Safari does. Not having
- // a valid window handle causes subtle bugs with plugins which retrieve
- // the window handle and validate the same. The window handle can be
- // retrieved via NPN_GetValue of NPNVnetscapeWindow.
- instance_->set_window_handle(parent_);
- }
-
- bool should_load = PlatformInitialize();
-
- plugin_url_ = url.spec();
-
- return should_load;
-}
-
-void WebPluginDelegateImpl::DestroyInstance() {
- if (instance_ && (instance_->npp()->ndata != NULL)) {
- // Shutdown all streams before destroying so that
- // no streams are left "in progress". Need to do
- // this before calling set_web_plugin(NULL) because the
- // instance uses the helper to do the download.
- instance_->CloseStreams();
-
- window_.window = NULL;
- if (creation_succeeded_ &&
- !(quirks_ & PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY)) {
- instance_->NPP_SetWindow(&window_);
- }
-
- instance_->NPP_Destroy();
-
- instance_->set_web_plugin(NULL);
-
- PlatformDestroyInstance();
-
- instance_ = 0;
- }
-}
-
-void WebPluginDelegateImpl::UpdateGeometry(
- const gfx::Rect& window_rect,
- const gfx::Rect& clip_rect) {
-
- if (first_set_window_call_) {
- first_set_window_call_ = false;
- // Plugins like media player on Windows have a bug where in they handle the
- // first geometry update and ignore the rest resulting in painting issues.
- // This quirk basically ignores the first set window call sequence for
- // these plugins and has been tested for Windows plugins only.
- if (quirks_ & PLUGIN_QUIRK_IGNORE_FIRST_SETWINDOW_CALL)
- return;
- }
-
- if (windowless_) {
- WindowlessUpdateGeometry(window_rect, clip_rect);
- } else {
- WindowedUpdateGeometry(window_rect, clip_rect);
- }
-}
-
-void WebPluginDelegateImpl::SetFocus(bool focused) {
- DCHECK(windowless_);
- // This is called when internal WebKit focus (the focused element on the page)
- // changes, but plugins need to know about OS-level focus, so we have an extra
- // layer of focus tracking.
- //
- // On Windows, historically browsers did not set focus events to windowless
- // plugins when the toplevel window focus changes. Sending such focus events
- // breaks full screen mode in Flash because it will come out of full screen
- // mode when it loses focus, and its full screen window causes the browser to
- // lose focus.
- has_webkit_focus_ = focused;
-#ifndef OS_WIN
- if (containing_view_has_focus_)
- SetPluginHasFocus(focused);
-#else
- SetPluginHasFocus(focused);
-#endif
-}
-
-void WebPluginDelegateImpl::SetPluginHasFocus(bool focused) {
- if (focused == plugin_has_focus_)
- return;
- if (PlatformSetPluginHasFocus(focused))
- plugin_has_focus_ = focused;
-}
-
-void WebPluginDelegateImpl::SetContentAreaHasFocus(bool has_focus) {
- containing_view_has_focus_ = has_focus;
- if (!windowless_)
- return;
-#ifndef OS_WIN // See SetFocus above.
- SetPluginHasFocus(containing_view_has_focus_ && has_webkit_focus_);
-#endif
-}
-
-NPObject* WebPluginDelegateImpl::GetPluginScriptableObject() {
- return instance_->GetPluginScriptableObject();
-}
-
-void WebPluginDelegateImpl::DidFinishLoadWithReason(const GURL& url,
- NPReason reason,
- int notify_id) {
- if (quirks_ & PLUGIN_QUIRK_ALWAYS_NOTIFY_SUCCESS &&
- reason == NPRES_NETWORK_ERR) {
- // Flash needs this or otherwise it unloads the launching swf object.
- reason = NPRES_DONE;
- }
-
- instance()->DidFinishLoadWithReason(url, reason, notify_id);
-}
-
-int WebPluginDelegateImpl::GetProcessId() {
- // We are in process, so the plugin pid is this current process pid.
- return base::GetCurrentProcId();
-}
-
-void WebPluginDelegateImpl::SendJavaScriptStream(const GURL& url,
- const std::string& result,
- bool success,
- int notify_id) {
- instance()->SendJavaScriptStream(url, result, success, notify_id);
-}
-
-void WebPluginDelegateImpl::DidReceiveManualResponse(
- const GURL& url, const std::string& mime_type,
- const std::string& headers, uint32 expected_length, uint32 last_modified) {
- if (!windowless_) {
- // Calling NPP_WriteReady before NPP_SetWindow causes movies to not load in
- // Flash. See http://b/issue?id=892174.
- DCHECK(windowed_did_set_window_);
- }
-
- instance()->DidReceiveManualResponse(url, mime_type, headers,
- expected_length, last_modified);
-}
-
-void WebPluginDelegateImpl::DidReceiveManualData(const char* buffer,
- int length) {
- instance()->DidReceiveManualData(buffer, length);
-}
-
-void WebPluginDelegateImpl::DidFinishManualLoading() {
- instance()->DidFinishManualLoading();
-}
-
-void WebPluginDelegateImpl::DidManualLoadFail() {
- instance()->DidManualLoadFail();
-}
-
-FilePath WebPluginDelegateImpl::GetPluginPath() {
- return instance()->plugin_lib()->plugin_info().path;
-}
-
-void WebPluginDelegateImpl::WindowedUpdateGeometry(
- const gfx::Rect& window_rect,
- const gfx::Rect& clip_rect) {
- if (WindowedReposition(window_rect, clip_rect) ||
- !windowed_did_set_window_) {
- // Let the plugin know that it has been moved
- WindowedSetWindow();
- }
-}
-
-bool WebPluginDelegateImpl::HandleInputEvent(const WebInputEvent& event,
- WebCursorInfo* cursor_info) {
- DCHECK(windowless_) << "events should only be received in windowless mode";
-
- bool pop_user_gesture = false;
- if (IsUserGesture(event)) {
- pop_user_gesture = true;
- instance()->PushPopupsEnabledState(true);
- }
-
- bool handled = PlatformHandleInputEvent(event, cursor_info);
-
- if (pop_user_gesture) {
- instance()->PopPopupsEnabledState();
- }
-
- return handled;
-}
-
-bool WebPluginDelegateImpl::IsUserGesture(const WebInputEvent& event) {
- switch (event.type) {
- case WebInputEvent::MouseDown:
- case WebInputEvent::MouseUp:
- case WebInputEvent::KeyDown:
- case WebInputEvent::KeyUp:
- return true;
- default:
- return false;
- }
- return false;
-}
-
-WebPluginResourceClient* WebPluginDelegateImpl::CreateResourceClient(
- unsigned long resource_id, const GURL& url, int notify_id) {
- return instance()->CreateStream(
- resource_id, url, std::string(), notify_id);
-}
-
-WebPluginResourceClient* WebPluginDelegateImpl::CreateSeekableResourceClient(
- unsigned long resource_id, int range_request_id) {
- return instance()->GetRangeRequest(range_request_id);
-}
diff --git a/webkit/glue/plugins/webplugin_delegate_impl.h b/webkit/glue/plugins/webplugin_delegate_impl.h
deleted file mode 100644
index 4046c95..0000000
--- a/webkit/glue/plugins/webplugin_delegate_impl.h
+++ /dev/null
@@ -1,511 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_WEBPLUGIN_DELEGATE_IMPL_H_
-#define WEBKIT_GLUE_PLUGINS_WEBPLUGIN_DELEGATE_IMPL_H_
-
-#include "build/build_config.h"
-
-#include <string>
-#include <list>
-
-#include "base/ref_counted.h"
-#include "base/scoped_ptr.h"
-#include "base/task.h"
-#include "base/time.h"
-#include "base/timer.h"
-#include "gfx/native_widget_types.h"
-#include "gfx/rect.h"
-#include "third_party/npapi/bindings/npapi.h"
-#include "webkit/glue/plugins/webplugin_delegate.h"
-#include "webkit/glue/webcursor.h"
-
-#if defined(USE_X11)
-#include "app/x11_util.h"
-
-typedef struct _GdkDrawable GdkPixmap;
-#endif
-
-class FilePath;
-
-namespace NPAPI {
-class PluginInstance;
-}
-
-namespace WebKit {
-class WebMouseEvent;
-}
-
-#if defined(OS_MACOSX)
-class ExternalDragTracker;
-#ifndef NP_NO_QUICKDRAW
-class QuickDrawDrawingManager;
-#endif
-#ifdef __OBJC__
-@class CALayer;
-@class CARenderer;
-#else
-class CALayer;
-class CARenderer;
-#endif
-namespace webkit_glue {
-class WebPluginAcceleratedSurface;
-}
-#endif
-
-// An implementation of WebPluginDelegate that runs in the plugin process,
-// proxied from the renderer by WebPluginDelegateProxy.
-class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate {
- public:
- enum PluginQuirks {
- PLUGIN_QUIRK_SETWINDOW_TWICE = 1, // Win32
- PLUGIN_QUIRK_THROTTLE_WM_USER_PLUS_ONE = 2, // Win32
- PLUGIN_QUIRK_DONT_CALL_WND_PROC_RECURSIVELY = 4, // Win32
- PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY = 8, // Win32
- PLUGIN_QUIRK_DONT_ALLOW_MULTIPLE_INSTANCES = 16, // Win32
- PLUGIN_QUIRK_DIE_AFTER_UNLOAD = 32, // Win32
- PLUGIN_QUIRK_PATCH_SETCURSOR = 64, // Win32
- PLUGIN_QUIRK_BLOCK_NONSTANDARD_GETURL_REQUESTS = 128, // Win32
- PLUGIN_QUIRK_WINDOWLESS_OFFSET_WINDOW_TO_DRAW = 256, // Linux
- PLUGIN_QUIRK_WINDOWLESS_INVALIDATE_AFTER_SET_WINDOW = 512, // Linux
- PLUGIN_QUIRK_NO_WINDOWLESS = 1024, // Windows
- PLUGIN_QUIRK_PATCH_REGENUMKEYEXW = 2048, // Windows
- PLUGIN_QUIRK_ALWAYS_NOTIFY_SUCCESS = 4096, // Windows
- PLUGIN_QUIRK_ALLOW_FASTER_QUICKDRAW_PATH = 8192, // Mac
- PLUGIN_QUIRK_HANDLE_MOUSE_CAPTURE = 16384, // Windows
- PLUGIN_QUIRK_WINDOWLESS_NO_RIGHT_CLICK = 32768, // Linux
- PLUGIN_QUIRK_IGNORE_FIRST_SETWINDOW_CALL = 65536, // Windows.
- };
-
- static WebPluginDelegateImpl* Create(const FilePath& filename,
- const std::string& mime_type,
- gfx::PluginWindowHandle containing_view);
-
- static bool IsPluginDelegateWindow(gfx::NativeWindow window);
- static bool GetPluginNameFromWindow(gfx::NativeWindow window,
- std::wstring *plugin_name);
-
- // Returns true if the window handle passed in is that of the dummy
- // activation window for windowless plugins.
- static bool IsDummyActivationWindow(gfx::NativeWindow window);
-
- // WebPluginDelegate implementation
- virtual bool Initialize(const GURL& url,
- const std::vector<std::string>& arg_names,
- const std::vector<std::string>& arg_values,
- webkit_glue::WebPlugin* plugin,
- bool load_manually);
- virtual void PluginDestroyed();
- virtual void UpdateGeometry(const gfx::Rect& window_rect,
- const gfx::Rect& clip_rect);
- virtual void Paint(WebKit::WebCanvas* canvas, const gfx::Rect& rect);
- virtual void Print(gfx::NativeDrawingContext context);
- virtual void SetFocus(bool focused);
- virtual bool HandleInputEvent(const WebKit::WebInputEvent& event,
- WebKit::WebCursorInfo* cursor_info);
- virtual NPObject* GetPluginScriptableObject();
- virtual void DidFinishLoadWithReason(
- const GURL& url, NPReason reason, int notify_id);
- virtual int GetProcessId();
- virtual void SendJavaScriptStream(const GURL& url,
- const std::string& result,
- bool success,
- int notify_id);
- virtual void DidReceiveManualResponse(const GURL& url,
- const std::string& mime_type,
- const std::string& headers,
- uint32 expected_length,
- uint32 last_modified);
- virtual void DidReceiveManualData(const char* buffer, int length);
- virtual void DidFinishManualLoading();
- virtual void DidManualLoadFail();
- virtual void InstallMissingPlugin();
- virtual webkit_glue::WebPluginResourceClient* CreateResourceClient(
- unsigned long resource_id, const GURL& url, int notify_id);
- virtual webkit_glue::WebPluginResourceClient* CreateSeekableResourceClient(
- unsigned long resource_id, int range_request_id);
- // End of WebPluginDelegate implementation.
-
- bool IsWindowless() const { return windowless_ ; }
- gfx::Rect GetRect() const { return window_rect_; }
- gfx::Rect GetClipRect() const { return clip_rect_; }
-
- // Returns the path for the library implementing this plugin.
- FilePath GetPluginPath();
-
- // Returns a combination of PluginQuirks.
- int GetQuirks() const { return quirks_; }
-
- // Informs the plugin that the view it is in has gained or lost focus.
- void SetContentAreaHasFocus(bool has_focus);
-
-#if defined(OS_MACOSX)
- // Informs the plugin that the geometry has changed, as with UpdateGeometry,
- // but also includes the new buffer context for that new geometry.
- void UpdateGeometryAndContext(const gfx::Rect& window_rect,
- const gfx::Rect& clip_rect,
- gfx::NativeDrawingContext context);
- // Informs the delegate that the plugin called NPN_Invalidate*. Used as a
- // trigger for Core Animation drawing.
- void PluginDidInvalidate();
- // Returns the delegate currently processing events.
- static WebPluginDelegateImpl* GetActiveDelegate();
- // Informs the plugin that the window it is in has gained or lost focus.
- void SetWindowHasFocus(bool has_focus);
- // Returns whether or not the window the plugin is in has focus.
- bool GetWindowHasFocus() const { return containing_window_has_focus_; }
- // Informs the plugin that its tab or window has been hidden or shown.
- void SetContainerVisibility(bool is_visible);
- // Informs the plugin that its containing window's frame has changed.
- // Frames are in screen coordinates.
- void WindowFrameChanged(const gfx::Rect& window_frame,
- const gfx::Rect& view_frame);
- // Informs the plugin that IME composition has been confirmed.
- void ImeCompositionConfirmed(const string16& text);
- // Informs the delegate that the plugin set a Carbon ThemeCursor.
- void SetThemeCursor(ThemeCursor cursor);
- // Informs the delegate that the plugin set a Carbon Cursor.
- void SetCursor(const Cursor* cursor);
- // Informs the delegate that the plugin set a Cocoa NSCursor.
- void SetNSCursor(NSCursor* cursor);
-
-#ifndef NP_NO_CARBON
- // Indicates that it's time to send the plugin a null event.
- void FireIdleEvent();
-#endif
-#endif // OS_MACOSX
-
- gfx::PluginWindowHandle windowed_handle() const {
- return windowed_handle_;
- }
-
-#if defined(OS_MACOSX)
- // Allow setting a "fake" window handle to associate this plug-in with
- // an IOSurface in the browser. Used for accelerated drawing surfaces.
- void set_windowed_handle(gfx::PluginWindowHandle handle);
-#endif
-
-#if defined(USE_X11)
- void SetWindowlessShmPixmap(XID shm_pixmap) {
- windowless_shm_pixmap_ = shm_pixmap;
- }
-#endif
-
- private:
- friend class DeleteTask<WebPluginDelegateImpl>;
- friend class webkit_glue::WebPluginDelegate;
-
- WebPluginDelegateImpl(gfx::PluginWindowHandle containing_view,
- NPAPI::PluginInstance *instance);
- ~WebPluginDelegateImpl();
-
- // Called by Initialize() for platform-specific initialization.
- // If this returns false, the plugin shouldn't be started--see Initialize().
- bool PlatformInitialize();
-
- // Called by DestroyInstance(), used for platform-specific destruction.
- void PlatformDestroyInstance();
-
- //--------------------------
- // used for windowed plugins
- void WindowedUpdateGeometry(const gfx::Rect& window_rect,
- const gfx::Rect& clip_rect);
- // Create the native window.
- // Returns true if the window is created (or already exists).
- // Returns false if unable to create the window.
- bool WindowedCreatePlugin();
-
- // Destroy the native window.
- void WindowedDestroyWindow();
-
- // Reposition the native window to be in sync with the given geometry.
- // Returns true if the native window has moved or been clipped differently.
- bool WindowedReposition(const gfx::Rect& window_rect,
- const gfx::Rect& clip_rect);
-
- // Tells the plugin about the current state of the window.
- // See NPAPI NPP_SetWindow for more information.
- void WindowedSetWindow();
-
-#if defined(OS_WIN)
- // Registers the window class for our window
- ATOM RegisterNativeWindowClass();
-
- // Our WndProc functions.
- static LRESULT CALLBACK DummyWindowProc(
- HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
- static LRESULT CALLBACK NativeWndProc(
- HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
- static LRESULT CALLBACK FlashWindowlessWndProc(
- HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
-
- // Used for throttling Flash messages.
- static void ClearThrottleQueueForWindow(HWND window);
- static void OnThrottleMessage();
- static void ThrottleMessage(WNDPROC proc, HWND hwnd, UINT message,
- WPARAM wParam, LPARAM lParam);
-#endif
-
- //----------------------------
- // used for windowless plugins
- void WindowlessUpdateGeometry(const gfx::Rect& window_rect,
- const gfx::Rect& clip_rect);
- void WindowlessPaint(gfx::NativeDrawingContext hdc, const gfx::Rect& rect);
-
- // Tells the plugin about the current state of the window.
- // See NPAPI NPP_SetWindow for more information.
- void WindowlessSetWindow();
-
- // Informs the plugin that it has gained or lost keyboard focus (on the Mac,
- // this just means window first responder status).
- void SetPluginHasFocus(bool focused);
-
- // Handles the platform specific details of setting plugin focus. Returns
- // false if the platform cancelled the focus tranfer.
- bool PlatformSetPluginHasFocus(bool focused);
-
- //-----------------------------------------
- // used for windowed and windowless plugins
-
- // Does platform-specific event handling. Arguments and return are identical
- // to HandleInputEvent.
- bool PlatformHandleInputEvent(const WebKit::WebInputEvent& event,
- WebKit::WebCursorInfo* cursor_info);
-
- NPAPI::PluginInstance* instance() { return instance_.get(); }
-
- // Closes down and destroys our plugin instance.
- void DestroyInstance();
-
-
- // used for windowed plugins
- // Note: on Mac OS X, the only time the windowed handle is non-zero
- // is the case of accelerated rendering, which uses a fake window handle to
- // identify itself back to the browser. It still performs all of its
- // work offscreen.
- gfx::PluginWindowHandle windowed_handle_;
- gfx::Rect windowed_last_pos_;
-
- bool windowed_did_set_window_;
-
- // used by windowed and windowless plugins
- bool windowless_;
-
- webkit_glue::WebPlugin* plugin_;
- scoped_refptr<NPAPI::PluginInstance> instance_;
-
-#if defined(OS_WIN)
- // Original wndproc before we subclassed.
- WNDPROC plugin_wnd_proc_;
-
- // Used to throttle WM_USER+1 messages in Flash.
- uint32 last_message_;
- bool is_calling_wndproc;
-
- // The current keyboard layout of this process and the main thread ID of the
- // browser process. These variables are used for synchronizing the keyboard
- // layout of this process with the one of the browser process.
- HKL keyboard_layout_;
- int parent_thread_id_;
-#endif // defined(OS_WIN)
-
-#if defined(USE_X11)
- // The SHM pixmap for a windowless plugin.
- XID windowless_shm_pixmap_;
-
- // The pixmap we're drawing into, for a windowless plugin.
- GdkPixmap* pixmap_;
- double first_event_time_;
-
- // On Linux some plugins assume that the GtkSocket container is in the same
- // process. So we create a GtkPlug to plug into the browser's container, and
- // a GtkSocket to hold the plugin. We then send the GtkPlug to the browser
- // process.
- GtkWidget* plug_;
- GtkWidget* socket_;
-
- // Ensure pixmap_ exists and is at least width by height pixels.
- void EnsurePixmapAtLeastSize(int width, int height);
-#endif
-
- gfx::PluginWindowHandle parent_;
- NPWindow window_;
- gfx::Rect window_rect_;
- gfx::Rect clip_rect_;
- int quirks_;
-
-#if defined(OS_WIN)
- // Windowless plugins don't have keyboard focus causing issues with the
- // plugin not receiving keyboard events if the plugin enters a modal
- // loop like TrackPopupMenuEx or MessageBox, etc.
- // This is a basic issue with windows activation and focus arising due to
- // the fact that these windows are created by different threads. Activation
- // and focus are thread specific states, and if the browser has focus,
- // the plugin may not have focus.
- // To fix a majority of these activation issues we create a dummy visible
- // child window to which we set focus whenever the windowless plugin
- // receives a WM_LBUTTONDOWN/WM_RBUTTONDOWN message via NPP_HandleEvent.
-
- HWND dummy_window_for_activation_;
- bool CreateDummyWindowForActivation();
-
- // Returns true if the event passed in needs to be tracked for a potential
- // modal loop.
- static bool ShouldTrackEventForModalLoops(NPEvent* event);
-
- // The message filter hook procedure, which tracks modal loops entered by
- // a plugin in the course of a NPP_HandleEvent call.
- static LRESULT CALLBACK HandleEventMessageFilterHook(int code, WPARAM wParam,
- LPARAM lParam);
-
- // TrackPopupMenu interceptor. Parameters are the same as the Win32 function
- // TrackPopupMenu.
- static BOOL WINAPI TrackPopupMenuPatch(HMENU menu, unsigned int flags, int x,
- int y, int reserved, HWND window,
- const RECT* rect);
-
- // SetCursor interceptor for windowless plugins.
- static HCURSOR WINAPI SetCursorPatch(HCURSOR cursor);
-
- // RegEnumKeyExW interceptor.
- static LONG WINAPI RegEnumKeyExWPatch(
- HKEY key, DWORD index, LPWSTR name, LPDWORD name_size, LPDWORD reserved,
- LPWSTR class_name, LPDWORD class_size, PFILETIME last_write_time);
-
- // The mouse hook proc which handles mouse capture in windowed plugins.
- static LRESULT CALLBACK MouseHookProc(int code, WPARAM wParam,
- LPARAM lParam);
-
- // Calls SetCapture/ReleaseCapture based on the message type.
- static void HandleCaptureForMessage(HWND window, UINT message);
-
-#elif defined(OS_MACOSX)
- // Sets window_rect_ to |rect|
- void SetPluginRect(const gfx::Rect& rect);
- // Sets content_area_origin to |origin|
- void SetContentAreaOrigin(const gfx::Point& origin);
- // Updates everything that depends on the plugin's absolute screen location.
- void PluginScreenLocationChanged();
- // Updates anything that depends on plugin visibility.
- void PluginVisibilityChanged();
-
- // Enables/disables IME.
- void SetImeEnabled(bool enabled);
-
- // Informs the browser about the updated accelerated drawing surface.
- void UpdateAcceleratedSurface();
-
- // Uses a CARenderer to draw the plug-in's layer in our OpenGL surface.
- void DrawLayerInSurface();
-
-#ifndef NP_NO_CARBON
- // Moves our dummy window to match the current screen location of the plugin.
- void UpdateDummyWindowBounds(const gfx::Point& plugin_origin);
-
-#ifndef NP_NO_QUICKDRAW
- // Sets the mode used for QuickDraw plugin drawing. If enabled is true the
- // plugin draws into a GWorld that's not connected to a window (the faster
- // path), otherwise the plugin draws into our invisible dummy window (which is
- // slower, since the call we use to scrape the window contents is much more
- // expensive than copying between GWorlds).
- void SetQuickDrawFastPathEnabled(bool enabled);
-#endif
-
- // Adjusts the idle event rate for a Carbon plugin based on its current
- // visibility.
- void UpdateIdleEventRate();
-#endif // !NP_NO_CARBON
-
- CGContextRef buffer_context_; // Weak ref.
-
-#ifndef NP_NO_CARBON
- NP_CGContext np_cg_context_;
-#endif
-#ifndef NP_NO_QUICKDRAW
- NP_Port qd_port_;
- scoped_ptr<QuickDrawDrawingManager> qd_manager_;
- base::TimeTicks fast_path_enable_tick_;
-#endif
-
- CALayer* layer_; // Used for CA drawing mode. Weak, retained by plug-in.
- webkit_glue::WebPluginAcceleratedSurface* surface_; // Weak ref.
- CARenderer* renderer_; // Renders layer_ to surface_.
- scoped_ptr<base::RepeatingTimer<WebPluginDelegateImpl> > redraw_timer_;
-
- // The upper-left corner of the web content area in screen coordinates,
- // relative to an upper-left (0,0).
- gfx::Point content_area_origin_;
-
- bool containing_window_has_focus_;
- bool initial_window_focus_;
- bool container_is_visible_;
- bool have_called_set_window_;
-
- gfx::Rect cached_clip_rect_;
-
- bool ime_enabled_;
-
- scoped_ptr<ExternalDragTracker> external_drag_tracker_;
-#endif // OS_MACOSX
-
- // Called by the message filter hook when the plugin enters a modal loop.
- void OnModalLoopEntered();
-
- // Returns true if the message passed in corresponds to a user gesture.
- static bool IsUserGesture(const WebKit::WebInputEvent& event);
-
- // The url with which the plugin was instantiated.
- std::string plugin_url_;
-
-#if defined(OS_WIN)
- // Indicates the end of a user gesture period.
- void OnUserGestureEnd();
-
- // Handle to the message filter hook
- HHOOK handle_event_message_filter_hook_;
-
- // Event which is set when the plugin enters a modal loop in the course
- // of a NPP_HandleEvent call.
- HANDLE handle_event_pump_messages_event_;
-
- // This flag indicates whether we started tracking a user gesture message.
- bool user_gesture_message_posted_;
-
- // Runnable Method Factory used to invoke the OnUserGestureEnd method
- // asynchronously.
- ScopedRunnableMethodFactory<WebPluginDelegateImpl> user_gesture_msg_factory_;
-
- // Handle to the mouse hook installed for certain windowed plugins like
- // flash.
- HHOOK mouse_hook_;
-#endif
-
- // Holds the depth of the HandleEvent callstack.
- int handle_event_depth_;
-
- // Holds the current cursor set by the windowless plugin.
- WebCursor current_windowless_cursor_;
-
- // Set to true initially and indicates if this is the first npp_setwindow
- // call received by the plugin.
- bool first_set_window_call_;
-
- // True if the plugin thinks it has keyboard focus
- bool plugin_has_focus_;
- // True if the plugin element has focus within the web content, regardless of
- // whether its containing view currently has focus.
- bool has_webkit_focus_;
- // True if the containing view currently has focus.
- // Initially set to true so that plugin focus still works in environments
- // where SetContentAreaHasFocus is never called. See
- // https://bugs.webkit.org/show_bug.cgi?id=46013 for details.
- bool containing_view_has_focus_;
-
- // True if NPP_New did not return an error.
- bool creation_succeeded_;
-
- DISALLOW_COPY_AND_ASSIGN(WebPluginDelegateImpl);
-};
-
-#endif // WEBKIT_GLUE_PLUGINS_WEBPLUGIN_DELEGATE_IMPL_H_
diff --git a/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc b/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc
deleted file mode 100644
index 609b41e..0000000
--- a/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc
+++ /dev/null
@@ -1,767 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/webplugin_delegate_impl.h"
-
-#include <string>
-#include <vector>
-
-#include <gtk/gtk.h>
-#include <gdk/gdkx.h>
-
-#include "base/basictypes.h"
-#include "base/file_util.h"
-#include "base/message_loop.h"
-#include "base/process_util.h"
-#include "base/metrics/stats_counters.h"
-#include "base/string_util.h"
-#include "gfx/blit.h"
-#include "skia/ext/platform_canvas.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebCursorInfo.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h"
-#include "webkit/glue/plugins/gtk_plugin_container.h"
-#include "webkit/glue/plugins/plugin_constants_win.h"
-#include "webkit/glue/plugins/plugin_instance.h"
-#include "webkit/glue/plugins/plugin_lib.h"
-#include "webkit/glue/plugins/plugin_list.h"
-#include "webkit/glue/plugins/plugin_stream_url.h"
-#include "webkit/glue/plugins/webplugin.h"
-#include "webkit/glue/webkit_glue.h"
-
-#include "third_party/npapi/bindings/npapi_x11.h"
-
-using WebKit::WebCursorInfo;
-using WebKit::WebKeyboardEvent;
-using WebKit::WebInputEvent;
-using WebKit::WebMouseEvent;
-
-WebPluginDelegateImpl::WebPluginDelegateImpl(
- gfx::PluginWindowHandle containing_view,
- NPAPI::PluginInstance *instance)
- : windowed_handle_(0),
- windowed_did_set_window_(false),
- windowless_(false),
- plugin_(NULL),
- instance_(instance),
- windowless_shm_pixmap_(None),
- pixmap_(NULL),
- first_event_time_(-1.0),
- plug_(NULL),
- socket_(NULL),
- parent_(containing_view),
- quirks_(0),
- handle_event_depth_(0),
- first_set_window_call_(true),
- plugin_has_focus_(false),
- has_webkit_focus_(false),
- containing_view_has_focus_(true),
- creation_succeeded_(false) {
- memset(&window_, 0, sizeof(window_));
- if (instance_->mime_type() == "application/x-shockwave-flash") {
- // Flash is tied to Firefox's whacky behavior with windowless plugins. See
- // comments in WindowlessPaint.
- // TODO(viettrungluu): PLUGIN_QUIRK_WINDOWLESS_NO_RIGHT_CLICK: Don't allow
- // right-clicks in windowless content since Flash 10.1 (initial release, at
- // least) hangs in that case. Remove this once Flash is fixed.
- quirks_ |= PLUGIN_QUIRK_WINDOWLESS_OFFSET_WINDOW_TO_DRAW
- | PLUGIN_QUIRK_WINDOWLESS_INVALIDATE_AFTER_SET_WINDOW
- | PLUGIN_QUIRK_WINDOWLESS_NO_RIGHT_CLICK;
- }
-
- // TODO(evanm): I played with this for quite a while but couldn't
- // figure out a way to make Flash not crash unless I didn't call
- // NPP_SetWindow.
- // However, after piman's grand refactor of windowed plugins, maybe
- // this is no longer necessary.
- quirks_ |= PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY;
-}
-
-WebPluginDelegateImpl::~WebPluginDelegateImpl() {
- DestroyInstance();
-
- if (!windowless_)
- WindowedDestroyWindow();
-
- if (window_.ws_info) {
- // We only ever use ws_info as an NPSetWindowCallbackStruct.
- delete static_cast<NPSetWindowCallbackStruct*>(window_.ws_info);
- }
-
- if (pixmap_) {
- g_object_unref(pixmap_);
- pixmap_ = NULL;
- }
-}
-
-bool WebPluginDelegateImpl::PlatformInitialize() {
- gfx::PluginWindowHandle handle =
- windowless_ ? 0 : gtk_plug_get_id(GTK_PLUG(plug_));
- plugin_->SetWindow(handle);
- return true;
-}
-
-void WebPluginDelegateImpl::PlatformDestroyInstance() {
- // Nothing to do here.
-}
-
-void WebPluginDelegateImpl::Paint(WebKit::WebCanvas* canvas,
- const gfx::Rect& rect) {
- if (!windowless_)
- return;
- cairo_t* context = canvas->beginPlatformPaint();
- WindowlessPaint(context, rect);
- canvas->endPlatformPaint();
-}
-
-void WebPluginDelegateImpl::Print(cairo_t* context) {
- NOTIMPLEMENTED();
-}
-
-void WebPluginDelegateImpl::InstallMissingPlugin() {
- NOTIMPLEMENTED();
-}
-
-bool WebPluginDelegateImpl::WindowedCreatePlugin() {
- DCHECK(!windowed_handle_);
- DCHECK(!plug_);
-
- // NPP_GetValue() might write 4 bytes of data to this variable. Don't use a
- // single byte bool, use an int instead and make sure it is initialized.
- int xembed = 0;
- NPError err = instance_->NPP_GetValue(NPPVpluginNeedsXEmbed, &xembed);
- if (err != NPERR_NO_ERROR || !xembed) {
- NOTIMPLEMENTED() << " windowed plugin but without xembed. "
- "See http://code.google.com/p/chromium/issues/detail?id=38229";
- return false;
- }
-
- // Passing 0 as the socket XID creates a plug without plugging it in a socket
- // yet, so that it can be latter added with gtk_socket_add_id().
- plug_ = gtk_plug_new(0);
- gtk_widget_show(plug_);
- socket_ = gtk_socket_new();
- gtk_widget_show(socket_);
- gtk_container_add(GTK_CONTAINER(plug_), socket_);
- gtk_widget_show_all(plug_);
-
- // Prevent the plug from being destroyed if the browser kills the container
- // window.
- g_signal_connect(plug_, "delete-event", G_CALLBACK(gtk_true), NULL);
- // Prevent the socket from being destroyed when the plugin removes itself.
- g_signal_connect(socket_, "plug_removed", G_CALLBACK(gtk_true), NULL);
-
- windowed_handle_ = gtk_socket_get_id(GTK_SOCKET(socket_));
-
- window_.window = reinterpret_cast<void*>(windowed_handle_);
-
- if (!window_.ws_info)
- window_.ws_info = new NPSetWindowCallbackStruct;
- NPSetWindowCallbackStruct* extra =
- static_cast<NPSetWindowCallbackStruct*>(window_.ws_info);
- extra->display = GDK_DISPLAY();
- extra->visual = DefaultVisual(GDK_DISPLAY(), 0);
- extra->depth = DefaultDepth(GDK_DISPLAY(), 0);
- extra->colormap = DefaultColormap(GDK_DISPLAY(), 0);
-
- return true;
-}
-
-void WebPluginDelegateImpl::WindowedDestroyWindow() {
- if (plug_) {
- plugin_->WillDestroyWindow(gtk_plug_get_id(GTK_PLUG(plug_)));
-
- gtk_widget_destroy(plug_);
- plug_ = NULL;
- socket_ = NULL;
- windowed_handle_ = 0;
- }
-}
-
-bool WebPluginDelegateImpl::WindowedReposition(
- const gfx::Rect& window_rect,
- const gfx::Rect& clip_rect) {
- if (window_rect == window_rect_ && clip_rect == clip_rect_)
- return false;
-
- window_rect_ = window_rect;
- clip_rect_ = clip_rect;
-
- return true;
-}
-
-void WebPluginDelegateImpl::WindowedSetWindow() {
- if (!instance_)
- return;
-
- if (!windowed_handle_) {
- NOTREACHED();
- return;
- }
-
- // See https://bugzilla.mozilla.org/show_bug.cgi?id=108347
- // If we call NPP_SetWindow with a <= 0 width or height, problems arise in
- // Flash (and possibly other plugins).
- // TODO(piman): the Mozilla code suggests that for the Java plugin, we should
- // still call NPP_SetWindow in that case. We need to verify that.
- if (window_rect_.width() <= 0 || window_rect_.height() <= 0) {
- return;
- }
-
- instance()->set_window_handle(windowed_handle_);
-
- DCHECK(!instance()->windowless());
-
- window_.clipRect.top = clip_rect_.y();
- window_.clipRect.left = clip_rect_.x();
- window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height();
- window_.clipRect.right = clip_rect_.x() + clip_rect_.width();
- window_.height = window_rect_.height();
- window_.width = window_rect_.width();
- window_.x = window_rect_.x();
- window_.y = window_rect_.y();
-
- //window_.window = windowed_handle_;
- window_.type = NPWindowTypeWindow;
-
- // Reset this flag before entering the instance in case of side-effects.
- windowed_did_set_window_ = true;
-
- NPError err = instance()->NPP_SetWindow(&window_);
- DCHECK(err == NPERR_NO_ERROR);
-}
-
-void WebPluginDelegateImpl::WindowlessUpdateGeometry(
- const gfx::Rect& window_rect,
- const gfx::Rect& clip_rect) {
- // Only resend to the instance if the geometry has changed.
- if (window_rect == window_rect_ && clip_rect == clip_rect_)
- return;
-
- clip_rect_ = clip_rect;
- window_rect_ = window_rect;
- WindowlessSetWindow();
-}
-
-void WebPluginDelegateImpl::EnsurePixmapAtLeastSize(int width, int height) {
- if (pixmap_) {
- gint cur_width, cur_height;
- gdk_drawable_get_size(pixmap_, &cur_width, &cur_height);
- if (cur_width >= width && cur_height >= height)
- return; // We are already the appropriate size.
-
- // Otherwise, we need to recreate ourselves.
- g_object_unref(pixmap_);
- pixmap_ = NULL;
- }
-
- // |sys_visual| is owned by gdk; we shouldn't free it.
- GdkVisual* sys_visual = gdk_visual_get_system();
- pixmap_ = gdk_pixmap_new(NULL, // use width/height/depth params
- std::max(1, width), std::max(1, height),
- sys_visual->depth);
- GdkColormap* colormap = gdk_colormap_new(gdk_visual_get_system(),
- FALSE);
- gdk_drawable_set_colormap(GDK_DRAWABLE(pixmap_), colormap);
- // The GdkDrawable now owns the GdkColormap.
- g_object_unref(colormap);
-}
-
-#ifdef DEBUG_RECTANGLES
-namespace {
-
-// Draw a rectangle on a Cairo context.
-// Useful for debugging various rectangles involved in drawing plugins.
-void DrawDebugRectangle(cairo_t* cairo,
- const gfx::Rect& rect,
- float r, float g, float b) {
- cairo_set_source_rgba(cairo, r, g, b, 0.5);
- cairo_rectangle(cairo, rect.x(), rect.y(),
- rect.width(), rect.height());
- cairo_stroke(cairo);
-}
-
-} // namespace
-#endif
-
-void WebPluginDelegateImpl::WindowlessPaint(cairo_t* context,
- const gfx::Rect& damage_rect) {
- // Compare to:
- // http://mxr.mozilla.org/firefox/source/layout/generic/nsObjectFrame.cpp:
- // nsPluginInstanceOwner::Renderer::NativeDraw().
-
- DCHECK(context);
-
- // TODO(darin): we should avoid calling NPP_SetWindow here since it may
- // cause page layout to be invalidated.
-
- // The actual dirty region is just the intersection of the plugin window and
- // the clip window with the damage region. However, the plugin wants to draw
- // relative to the containing window's origin, so our pixmap must be from the
- // window's origin down to the bottom-right edge of the dirty region.
- //
- // Typical case:
- // X-----------------------------------+-----------------------------+
- // | | |
- // | pixmap +-------------------+ |
- // | | damage | window |
- // | | | |
- // | +---+-------------------+-------------+ |
- // | | | | clip | |
- // | +---+---+-------------------+----------+ | |
- // | | | | | | | |
- // | | | | draw | | | |
- // | | | | | | | |
- // +-------+---+---+-------------------+----------+--+ |
- // | | | | | |
- // | | +-------------------+ | |
- // | | | |
- // | | plugin | |
- // | +--------------------------------------+ |
- // | |
- // | |
- // +-----------------------------------------------------------------+
- // X = origin
- //
- // NPAPI doesn't properly define which coordinates each of
- // - window.clipRect, window.x and window.y in the SetWindow call
- // - x and y in GraphicsExpose HandleEvent call
- // are relative to, nor does it define what the pixmap is relative to.
- //
- // Any sane values for them just don't work with the flash plugin. Firefox
- // has some interesting behavior. Experiments showed that:
- // - window.clipRect is always in the same space as window.x and window.y
- // - in the first SetWindow call, or when scrolling, window.x and window.y are
- // the coordinates of the plugin relative to the window.
- // - whenever only a part of the plugin is drawn, Firefox issues a SetWindow
- // call before each GraphicsExpose event, that sets the drawing origin to
- // (0, 0) as if the plugin was scrolled to be partially out of the view. The
- // GraphicsExpose event has coordinates relative to the "window" (assuming
- // that virtual scroll). The pixmap is also relative to the window. It always
- // sets the clip rect to the draw rect.
- //
- // Attempts to deviate from that makes Flash render at the wrong place in the
- // pixmap, or render the wrong pixels.
- //
- // Flash plugin:
- // X-----------------------------------------------------------------+
- // | |
- // | +-------------------+ "real" window |
- // | | damage | |
- // | | | |
- // | +---+-------------------+-------------+ |
- // | | | | "real" clip | |
- // | +---+---O===================#==========#==#===============#
- // | | | H draw | | | H
- // | | | H = pixmap | | | H
- // | | | H = "apparent" clip | | | H
- // | + +---#-------------------+----------+--+ H
- // | | H | | H
- // | | H-------------------+ | H
- // | | H | H
- // | | H plugin | H
- // | +-------#------------------------------+ H
- // | H H
- // | H "apparent" window H
- // +---------------#=================================================#
- // X = "real" origin
- // O = "apparent" origin
- // "real" means as seen by Chrome
- // "apparent" means as seen by the plugin.
-
- gfx::Rect draw_rect = window_rect_.Intersect(damage_rect);
-
- // clip_rect_ is relative to the plugin
- gfx::Rect clip_rect_window = clip_rect_;
- clip_rect_window.Offset(window_rect_.x(), window_rect_.y());
- draw_rect = draw_rect.Intersect(clip_rect_window);
-
- // These offsets represent by how much the view is shifted to accomodate
- // Flash (the coordinates of X relative to O in the diagram above).
- int offset_x = 0;
- int offset_y = 0;
- if (quirks_ & PLUGIN_QUIRK_WINDOWLESS_OFFSET_WINDOW_TO_DRAW) {
- offset_x = -draw_rect.x();
- offset_y = -draw_rect.y();
- window_.clipRect.top = 0;
- window_.clipRect.left = 0;
- window_.clipRect.bottom = draw_rect.height();
- window_.clipRect.right = draw_rect.width();
- window_.height = window_rect_.height();
- window_.width = window_rect_.width();
- window_.x = window_rect_.x() - draw_rect.x();
- window_.y = window_rect_.y() - draw_rect.y();
- window_.type = NPWindowTypeDrawable;
- DCHECK(window_.ws_info);
- NPError err = instance()->NPP_SetWindow(&window_);
- DCHECK_EQ(err, NPERR_NO_ERROR);
- }
-
- gfx::Rect pixmap_draw_rect = draw_rect;
- pixmap_draw_rect.Offset(offset_x, offset_y);
-
- gfx::Rect pixmap_rect(0, 0,
- pixmap_draw_rect.right(),
- pixmap_draw_rect.bottom());
-
- // Construct the paint message, targeting the pixmap.
- NPEvent np_event = {0};
- XGraphicsExposeEvent &event = np_event.xgraphicsexpose;
- event.type = GraphicsExpose;
- event.x = pixmap_draw_rect.x();
- event.y = pixmap_draw_rect.y();
- event.width = pixmap_draw_rect.width();
- event.height = pixmap_draw_rect.height();
- event.display = GDK_DISPLAY();
-
- if (windowless_shm_pixmap_ != None) {
- Pixmap pixmap = None;
- GC xgc = NULL;
- Display* display = event.display;
- gfx::Rect plugin_draw_rect = draw_rect;
-
- // Make plugin_draw_rect relative to the plugin window.
- plugin_draw_rect.Offset(-window_rect_.x(), -window_rect_.y());
-
- // In case the drawing area does not start with the plugin window origin,
- // we can not let the plugin directly draw over the shared memory pixmap.
- if (plugin_draw_rect.x() != pixmap_draw_rect.x() ||
- plugin_draw_rect.y() != pixmap_draw_rect.y()) {
- pixmap = XCreatePixmap(display, windowless_shm_pixmap_,
- std::max(1, pixmap_rect.width()),
- std::max(1, pixmap_rect.height()),
- DefaultDepth(display, 0));
- xgc = XCreateGC(display, windowless_shm_pixmap_, 0, NULL);
- // Copy the current image into the pixmap, so the plugin can draw over it.
- XCopyArea(display, windowless_shm_pixmap_, pixmap, xgc,
- plugin_draw_rect.x(), plugin_draw_rect.y(),
- pixmap_draw_rect.width(), pixmap_draw_rect.height(),
- pixmap_draw_rect.x(), pixmap_draw_rect.y());
-
- event.drawable = pixmap;
- } else {
- event.drawable = windowless_shm_pixmap_;
- }
-
- // Tell the plugin to paint into the pixmap.
- static base::StatsRate plugin_paint("Plugin.Paint");
- base::StatsScope<base::StatsRate> scope(plugin_paint);
- NPError err = instance()->NPP_HandleEvent(&np_event);
- DCHECK_EQ(err, NPERR_NO_ERROR);
-
- if (pixmap != None) {
- // Copy the rendered image pixmap back into the shm pixmap
- // and thus the drawing buffer.
- XCopyArea(display, pixmap, windowless_shm_pixmap_, xgc,
- pixmap_draw_rect.x(), pixmap_draw_rect.y(),
- pixmap_draw_rect.width(), pixmap_draw_rect.height(),
- plugin_draw_rect.x(), plugin_draw_rect.y());
- XSync(display, FALSE);
- if (xgc)
- XFreeGC(display, xgc);
- XFreePixmap(display, pixmap);
- } else {
- XSync(display, FALSE);
- }
- } else {
- EnsurePixmapAtLeastSize(pixmap_rect.width(), pixmap_rect.height());
-
- // Copy the current image into the pixmap, so the plugin can draw over
- // this background.
- cairo_t* cairo = gdk_cairo_create(pixmap_);
- BlitContextToContext(cairo, pixmap_draw_rect, context, draw_rect.origin());
- cairo_destroy(cairo);
-
- event.drawable = GDK_PIXMAP_XID(pixmap_);
-
- // Tell the plugin to paint into the pixmap.
- static base::StatsRate plugin_paint("Plugin.Paint");
- base::StatsScope<base::StatsRate> scope(plugin_paint);
- NPError err = instance()->NPP_HandleEvent(&np_event);
- DCHECK_EQ(err, NPERR_NO_ERROR);
-
- cairo_save(context);
- // Now copy the rendered image pixmap back into the drawing buffer.
- gdk_cairo_set_source_pixmap(context, pixmap_, -offset_x, -offset_y);
- cairo_rectangle(context, draw_rect.x(), draw_rect.y(),
- draw_rect.width(), draw_rect.height());
- cairo_clip(context);
- cairo_paint(context);
-
-#ifdef DEBUG_RECTANGLES
- // Draw some debugging rectangles.
- // Pixmap rect = blue.
- DrawDebugRectangle(context, pixmap_rect, 0, 0, 1);
- // Drawing rect = red.
- DrawDebugRectangle(context, draw_rect, 1, 0, 0);
-#endif
- cairo_restore(context);
- }
-}
-
-void WebPluginDelegateImpl::WindowlessSetWindow() {
- if (!instance())
- return;
-
- if (window_rect_.IsEmpty()) // wait for geometry to be set.
- return;
-
- DCHECK(instance()->windowless());
- // Mozilla docs say that this window param is not used for windowless
- // plugins; rather, the window is passed during the GraphicsExpose event.
- DCHECK(window_.window == 0);
-
- window_.clipRect.top = clip_rect_.y() + window_rect_.y();
- window_.clipRect.left = clip_rect_.x() + window_rect_.x();
- window_.clipRect.bottom =
- clip_rect_.y() + clip_rect_.height() + window_rect_.y();
- window_.clipRect.right =
- clip_rect_.x() + clip_rect_.width() + window_rect_.x();
- window_.height = window_rect_.height();
- window_.width = window_rect_.width();
- window_.x = window_rect_.x();
- window_.y = window_rect_.y();
- window_.type = NPWindowTypeDrawable;
-
- if (!window_.ws_info)
- window_.ws_info = new NPSetWindowCallbackStruct;
- NPSetWindowCallbackStruct* extra =
- static_cast<NPSetWindowCallbackStruct*>(window_.ws_info);
- extra->display = GDK_DISPLAY();
- extra->visual = DefaultVisual(GDK_DISPLAY(), 0);
- extra->depth = DefaultDepth(GDK_DISPLAY(), 0);
- extra->colormap = DefaultColormap(GDK_DISPLAY(), 0);
-
- NPError err = instance()->NPP_SetWindow(&window_);
- DCHECK(err == NPERR_NO_ERROR);
- if (quirks_ & PLUGIN_QUIRK_WINDOWLESS_INVALIDATE_AFTER_SET_WINDOW) {
- // After a NPP_SetWindow, Flash cancels its timer that generates the
- // invalidates until it gets a paint event, but doesn't explicitly call
- // NPP_InvalidateRect.
- plugin_->InvalidateRect(clip_rect_);
- }
-}
-
-bool WebPluginDelegateImpl::PlatformSetPluginHasFocus(bool focused) {
- DCHECK(instance()->windowless());
-
- NPEvent np_event = {0};
- XFocusChangeEvent &event = np_event.xfocus;
- event.type = focused ? FocusIn : FocusOut;
- event.display = GDK_DISPLAY();
- // Same values as Firefox. .serial and .window stay 0.
- event.mode = -1;
- event.detail = NotifyDetailNone;
- instance()->NPP_HandleEvent(&np_event);
- return true;
-}
-
-// Converts a WebInputEvent::Modifiers bitfield into a
-// corresponding X modifier state.
-static int GetXModifierState(int modifiers) {
- int x_state = 0;
- if (modifiers & WebInputEvent::ControlKey)
- x_state |= ControlMask;
- if (modifiers & WebInputEvent::ShiftKey)
- x_state |= ShiftMask;
- if (modifiers & WebInputEvent::AltKey)
- x_state |= Mod1Mask;
- if (modifiers & WebInputEvent::MetaKey)
- x_state |= Mod2Mask;
- if (modifiers & WebInputEvent::LeftButtonDown)
- x_state |= Button1Mask;
- if (modifiers & WebInputEvent::MiddleButtonDown)
- x_state |= Button2Mask;
- if (modifiers & WebInputEvent::RightButtonDown)
- x_state |= Button3Mask;
- // TODO(piman@google.com): There are other modifiers, e.g. Num Lock, that
- // should be set (and Firefox does), but we didn't keep the information in
- // the WebKit event.
- return x_state;
-}
-
-static bool NPEventFromWebMouseEvent(const WebMouseEvent& event,
- Time timestamp,
- NPEvent *np_event) {
- np_event->xany.display = GDK_DISPLAY();
- // NOTE: Firefox keeps xany.serial and xany.window as 0.
-
- int modifier_state = GetXModifierState(event.modifiers);
-
- Window root = GDK_ROOT_WINDOW();
- switch (event.type) {
- case WebInputEvent::MouseMove: {
- np_event->type = MotionNotify;
- XMotionEvent &motion_event = np_event->xmotion;
- motion_event.root = root;
- motion_event.time = timestamp;
- motion_event.x = event.x;
- motion_event.y = event.y;
- motion_event.x_root = event.globalX;
- motion_event.y_root = event.globalY;
- motion_event.state = modifier_state;
- motion_event.is_hint = NotifyNormal;
- motion_event.same_screen = True;
- break;
- }
- case WebInputEvent::MouseLeave:
- case WebInputEvent::MouseEnter: {
- if (event.type == WebInputEvent::MouseEnter) {
- np_event->type = EnterNotify;
- } else {
- np_event->type = LeaveNotify;
- }
- XCrossingEvent &crossing_event = np_event->xcrossing;
- crossing_event.root = root;
- crossing_event.time = timestamp;
- crossing_event.x = event.x;
- crossing_event.y = event.y;
- crossing_event.x_root = event.globalX;
- crossing_event.y_root = event.globalY;
- crossing_event.mode = -1; // This is what Firefox sets it to.
- crossing_event.detail = NotifyDetailNone;
- crossing_event.same_screen = True;
- // TODO(piman@google.com): set this to the correct value. Firefox does. I
- // don't know where to get the information though, we get focus
- // notifications, but no unfocus.
- crossing_event.focus = 0;
- crossing_event.state = modifier_state;
- break;
- }
- case WebInputEvent::MouseUp:
- case WebInputEvent::MouseDown: {
- if (event.type == WebInputEvent::MouseDown) {
- np_event->type = ButtonPress;
- } else {
- np_event->type = ButtonRelease;
- }
- XButtonEvent &button_event = np_event->xbutton;
- button_event.root = root;
- button_event.time = timestamp;
- button_event.x = event.x;
- button_event.y = event.y;
- button_event.x_root = event.globalX;
- button_event.y_root = event.globalY;
- button_event.state = modifier_state;
- switch (event.button) {
- case WebMouseEvent::ButtonLeft:
- button_event.button = Button1;
- break;
- case WebMouseEvent::ButtonMiddle:
- button_event.button = Button2;
- break;
- case WebMouseEvent::ButtonRight:
- button_event.button = Button3;
- break;
- default:
- NOTREACHED();
- }
- button_event.same_screen = True;
- break;
- }
- default:
- NOTREACHED();
- return false;
- }
- return true;
-}
-
-static bool NPEventFromWebKeyboardEvent(const WebKeyboardEvent& event,
- Time timestamp,
- NPEvent *np_event) {
- np_event->xany.display = GDK_DISPLAY();
- // NOTE: Firefox keeps xany.serial and xany.window as 0.
-
- switch (event.type) {
- case WebKeyboardEvent::KeyDown:
- np_event->type = KeyPress;
- break;
- case WebKeyboardEvent::KeyUp:
- np_event->type = KeyRelease;
- break;
- default:
- NOTREACHED();
- return false;
- }
- XKeyEvent &key_event = np_event->xkey;
- key_event.send_event = False;
- key_event.display = GDK_DISPLAY();
- // NOTE: Firefox keeps xany.serial and xany.window as 0.
- // TODO(piman@google.com): is this right for multiple screens ?
- key_event.root = DefaultRootWindow(key_event.display);
- key_event.time = timestamp;
- // NOTE: We don't have the correct information for x/y/x_root/y_root. Firefox
- // doesn't have it either, so we pass the same values.
- key_event.x = 0;
- key_event.y = 0;
- key_event.x_root = -1;
- key_event.y_root = -1;
- key_event.state = GetXModifierState(event.modifiers);
- key_event.keycode = event.nativeKeyCode;
- key_event.same_screen = True;
- return true;
-}
-
-static bool NPEventFromWebInputEvent(const WebInputEvent& event,
- Time timestamp,
- NPEvent* np_event) {
- switch (event.type) {
- case WebInputEvent::MouseMove:
- case WebInputEvent::MouseLeave:
- case WebInputEvent::MouseEnter:
- case WebInputEvent::MouseDown:
- case WebInputEvent::MouseUp:
- if (event.size < sizeof(WebMouseEvent)) {
- NOTREACHED();
- return false;
- }
- return NPEventFromWebMouseEvent(
- *static_cast<const WebMouseEvent*>(&event), timestamp, np_event);
- case WebInputEvent::KeyDown:
- case WebInputEvent::KeyUp:
- if (event.size < sizeof(WebKeyboardEvent)) {
- NOTREACHED();
- return false;
- }
- return NPEventFromWebKeyboardEvent(
- *static_cast<const WebKeyboardEvent*>(&event), timestamp, np_event);
- default:
- return false;
- }
-}
-
-bool WebPluginDelegateImpl::PlatformHandleInputEvent(
- const WebInputEvent& event, WebCursorInfo* cursor_info) {
-
- if (first_event_time_ < 0.0)
- first_event_time_ = event.timeStampSeconds;
- Time timestamp = static_cast<Time>(
- (event.timeStampSeconds - first_event_time_) * 1.0e3);
- NPEvent np_event = {0};
- if (!NPEventFromWebInputEvent(event, timestamp, &np_event)) {
- return false;
- }
- // See comment about PLUGIN_QUIRK_WINDOWLESS_NO_RIGHT_CLICK in constructor.
- if (windowless_ &&
- (quirks_ & PLUGIN_QUIRK_WINDOWLESS_NO_RIGHT_CLICK) &&
- (np_event.type == ButtonPress || np_event.type == ButtonRelease) &&
- (np_event.xbutton.button == Button3)) {
- return false;
- }
-
- bool ret = instance()->NPP_HandleEvent(&np_event) != 0;
-
- // Flash always returns false, even when the event is handled.
- ret = true;
-
-#if 0
- if (event->event == WM_MOUSEMOVE) {
- // Snag a reference to the current cursor ASAP in case the plugin modified
- // it. There is a nasty race condition here with the multiprocess browser
- // as someone might be setting the cursor in the main process as well.
- *cursor = current_windowless_cursor_;
- }
-#endif
-
- return ret;
-}
diff --git a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm
deleted file mode 100644
index 552484a..0000000
--- a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm
+++ /dev/null
@@ -1,1145 +0,0 @@
-// 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>
-#import <QuartzCore/QuartzCore.h>
-
-#include "webkit/glue/plugins/webplugin_delegate_impl.h"
-
-#include <string>
-#include <unistd.h>
-#include <set>
-
-#include "base/file_util.h"
-#include "base/message_loop.h"
-#include "base/metrics/stats_counters.h"
-#include "base/scoped_ptr.h"
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-#include "base/sys_string_conversions.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h"
-#include "webkit/glue/plugins/plugin_instance.h"
-#include "webkit/glue/plugins/plugin_lib.h"
-#include "webkit/glue/plugins/plugin_list.h"
-#include "webkit/glue/plugins/plugin_stream_url.h"
-#include "webkit/glue/plugins/plugin_web_event_converter_mac.h"
-#include "webkit/glue/plugins/webplugin.h"
-#include "webkit/glue/plugins/webplugin_accelerated_surface_mac.h"
-#include "webkit/glue/webkit_glue.h"
-
-#ifndef NP_NO_CARBON
-#include "webkit/glue/plugins/carbon_plugin_window_tracker_mac.h"
-#endif
-
-#ifndef NP_NO_QUICKDRAW
-#include "webkit/glue/plugins/quickdraw_drawing_manager_mac.h"
-#endif
-
-using webkit_glue::WebPlugin;
-using webkit_glue::WebPluginDelegate;
-using webkit_glue::WebPluginResourceClient;
-using WebKit::WebCursorInfo;
-using WebKit::WebKeyboardEvent;
-using WebKit::WebInputEvent;
-using WebKit::WebMouseEvent;
-using WebKit::WebMouseWheelEvent;
-
-const int kCoreAnimationRedrawPeriodMs = 10; // 100 Hz
-
-// Important implementation notes: The Mac definition of NPAPI, particularly
-// the distinction between windowed and windowless modes, differs from the
-// Windows and Linux definitions. Most of those differences are
-// accomodated by the WebPluginDelegate class.
-
-namespace {
-
-WebPluginDelegateImpl* g_active_delegate;
-
-// Helper to simplify correct usage of g_active_delegate. Instantiating will
-// set the active delegate to |delegate| for the lifetime of the object, then
-// NULL when it goes out of scope.
-class ScopedActiveDelegate {
-public:
- explicit ScopedActiveDelegate(WebPluginDelegateImpl* delegate) {
- g_active_delegate = delegate;
- }
- ~ScopedActiveDelegate() {
- g_active_delegate = NULL;
- }
-private:
- DISALLOW_COPY_AND_ASSIGN(ScopedActiveDelegate);
-};
-
-#ifndef NP_NO_CARBON
-// Timer periods for sending idle events to Carbon plugins. The visible value
-// (50Hz) matches both Safari and Firefox. The hidden value (8Hz) matches
-// Firefox; according to https://bugzilla.mozilla.org/show_bug.cgi?id=525533
-// going lower than that causes issues.
-const int kVisibleIdlePeriodMs = 20; // (50Hz)
-const int kHiddenIdlePeriodMs = 125; // (8Hz)
-
-class CarbonIdleEventSource {
- public:
- // Returns the shared Carbon idle event source.
- static CarbonIdleEventSource* SharedInstance() {
- DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI);
- static CarbonIdleEventSource* event_source = new CarbonIdleEventSource();
- return event_source;
- }
-
- // Registers the plugin delegate as interested in receiving idle events at
- // a rate appropriate for the given visibility. A delegate can safely be
- // re-registered any number of times, with the latest registration winning.
- void RegisterDelegate(WebPluginDelegateImpl* delegate, bool visible) {
- if (visible) {
- visible_delegates_->RegisterDelegate(delegate);
- hidden_delegates_->UnregisterDelegate(delegate);
- } else {
- hidden_delegates_->RegisterDelegate(delegate);
- visible_delegates_->UnregisterDelegate(delegate);
- }
- }
-
- // Removes the plugin delegate from the list of plugins receiving idle events.
- void UnregisterDelegate(WebPluginDelegateImpl* delegate) {
- visible_delegates_->UnregisterDelegate(delegate);
- hidden_delegates_->UnregisterDelegate(delegate);
- }
-
- private:
- class VisibilityGroup {
- public:
- explicit VisibilityGroup(int timer_period)
- : timer_period_(timer_period), iterator_(delegates_.end()) {}
-
- // Adds |delegate| to this visibility group.
- void RegisterDelegate(WebPluginDelegateImpl* delegate) {
- if (delegates_.empty()) {
- timer_.Start(base::TimeDelta::FromMilliseconds(timer_period_),
- this, &VisibilityGroup::SendIdleEvents);
- }
- delegates_.insert(delegate);
- }
-
- // Removes |delegate| from this visibility group.
- void UnregisterDelegate(WebPluginDelegateImpl* delegate) {
- // If a plugin changes visibility during idle event handling, it
- // may be removed from this set while SendIdleEvents is still iterating;
- // if that happens and it's next on the list, increment the iterator
- // before erasing so that the iteration won't be corrupted.
- if ((iterator_ != delegates_.end()) && (*iterator_ == delegate))
- ++iterator_;
- size_t removed = delegates_.erase(delegate);
- if (removed > 0 && delegates_.empty())
- timer_.Stop();
- }
-
- private:
- // Fires off idle events for each delegate in the group.
- void SendIdleEvents() {
- for (iterator_ = delegates_.begin(); iterator_ != delegates_.end();) {
- // Pre-increment so that the skip logic in UnregisterDelegates works.
- WebPluginDelegateImpl* delegate = *(iterator_++);
- delegate->FireIdleEvent();
- }
- }
-
- int timer_period_;
- base::RepeatingTimer<VisibilityGroup> timer_;
- std::set<WebPluginDelegateImpl*> delegates_;
- std::set<WebPluginDelegateImpl*>::iterator iterator_;
- };
-
- CarbonIdleEventSource()
- : visible_delegates_(new VisibilityGroup(kVisibleIdlePeriodMs)),
- hidden_delegates_(new VisibilityGroup(kHiddenIdlePeriodMs)) {}
-
- scoped_ptr<VisibilityGroup> visible_delegates_;
- scoped_ptr<VisibilityGroup> hidden_delegates_;
-
- DISALLOW_COPY_AND_ASSIGN(CarbonIdleEventSource);
-};
-#endif // !NP_NO_CARBON
-
-} // namespace
-
-// Helper to build and maintain a model of a drag entering the plugin but not
-// starting there. See explanation in PlatformHandleInputEvent.
-class ExternalDragTracker {
- public:
- ExternalDragTracker() : pressed_buttons_(0) {}
-
- // Returns true if an external drag is in progress.
- bool IsDragInProgress() { return pressed_buttons_ != 0; };
-
- // Returns true if the given event appears to be related to an external drag.
- bool EventIsRelatedToDrag(const WebInputEvent& event);
-
- // Updates the tracking of whether an external drag is in progress--and if
- // so what buttons it involves--based on the given event.
- void UpdateDragStateFromEvent(const WebInputEvent& event);
-
- private:
- // Returns the mask for just the button state in a WebInputEvent's modifiers.
- static int WebEventButtonModifierMask();
-
- // The WebInputEvent modifier flags for any buttons that were down when an
- // external drag entered the plugin, and which and are still down now.
- int pressed_buttons_;
-
- DISALLOW_COPY_AND_ASSIGN(ExternalDragTracker);
-};
-
-void ExternalDragTracker::UpdateDragStateFromEvent(const WebInputEvent& event) {
- switch (event.type) {
- case WebInputEvent::MouseEnter:
- pressed_buttons_ = event.modifiers & WebEventButtonModifierMask();
- break;
- case WebInputEvent::MouseUp: {
- const WebMouseEvent* mouse_event =
- static_cast<const WebMouseEvent*>(&event);
- if (mouse_event->button == WebMouseEvent::ButtonLeft)
- pressed_buttons_ &= ~WebInputEvent::LeftButtonDown;
- if (mouse_event->button == WebMouseEvent::ButtonMiddle)
- pressed_buttons_ &= ~WebInputEvent::MiddleButtonDown;
- if (mouse_event->button == WebMouseEvent::ButtonRight)
- pressed_buttons_ &= ~WebInputEvent::RightButtonDown;
- break;
- }
- default:
- break;
- }
-}
-
-bool ExternalDragTracker::EventIsRelatedToDrag(const WebInputEvent& event) {
- const WebMouseEvent* mouse_event = static_cast<const WebMouseEvent*>(&event);
- switch (event.type) {
- case WebInputEvent::MouseUp:
- // We only care about release of buttons that were part of the drag.
- return ((mouse_event->button == WebMouseEvent::ButtonLeft &&
- (pressed_buttons_ & WebInputEvent::LeftButtonDown)) ||
- (mouse_event->button == WebMouseEvent::ButtonMiddle &&
- (pressed_buttons_ & WebInputEvent::MiddleButtonDown)) ||
- (mouse_event->button == WebMouseEvent::ButtonRight &&
- (pressed_buttons_ & WebInputEvent::RightButtonDown)));
- case WebInputEvent::MouseEnter:
- return (event.modifiers & WebEventButtonModifierMask()) != 0;
- case WebInputEvent::MouseLeave:
- case WebInputEvent::MouseMove: {
- int event_buttons = (event.modifiers & WebEventButtonModifierMask());
- return (pressed_buttons_ &&
- pressed_buttons_ == event_buttons);
- }
- default:
- return false;
- }
- return false;
-}
-
-int ExternalDragTracker::WebEventButtonModifierMask() {
- return WebInputEvent::LeftButtonDown |
- WebInputEvent::RightButtonDown |
- WebInputEvent::MiddleButtonDown;
-}
-
-#pragma mark -
-#pragma mark Core WebPluginDelegate implementation
-
-WebPluginDelegateImpl::WebPluginDelegateImpl(
- gfx::PluginWindowHandle containing_view,
- NPAPI::PluginInstance *instance)
- : windowed_handle_(NULL),
- // all Mac plugins are "windowless" in the Windows/X11 sense
- windowless_(true),
- plugin_(NULL),
- instance_(instance),
- parent_(containing_view),
- quirks_(0),
- buffer_context_(NULL),
- layer_(nil),
- surface_(NULL),
- renderer_(nil),
- containing_window_has_focus_(false),
- initial_window_focus_(false),
- container_is_visible_(false),
- have_called_set_window_(false),
- ime_enabled_(false),
- external_drag_tracker_(new ExternalDragTracker()),
- handle_event_depth_(0),
- first_set_window_call_(true),
- plugin_has_focus_(false),
- has_webkit_focus_(false),
- containing_view_has_focus_(true),
- creation_succeeded_(false) {
- memset(&window_, 0, sizeof(window_));
-#ifndef NP_NO_CARBON
- memset(&np_cg_context_, 0, sizeof(np_cg_context_));
-#endif
-#ifndef NP_NO_QUICKDRAW
- memset(&qd_port_, 0, sizeof(qd_port_));
-#endif
- instance->set_windowless(true);
-}
-
-WebPluginDelegateImpl::~WebPluginDelegateImpl() {
- DestroyInstance();
-
-#ifndef NP_NO_CARBON
- if (np_cg_context_.window) {
- CarbonPluginWindowTracker::SharedInstance()->DestroyDummyWindowForDelegate(
- this, reinterpret_cast<WindowRef>(np_cg_context_.window));
- }
-#endif
-}
-
-bool WebPluginDelegateImpl::PlatformInitialize() {
- // Don't set a NULL window handle on destroy for Mac plugins. This matches
- // Safari and other Mac browsers (see PluginView::stop() in PluginView.cpp,
- // where code to do so is surrounded by an #ifdef that excludes Mac OS X, or
- // destroyPlugin in WebNetscapePluginView.mm, for examples).
- quirks_ |= PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY;
-
- // Mac plugins don't expect to be unloaded, and they don't always do so
- // cleanly, so don't unload them at shutdown.
- instance()->plugin_lib()->PreventLibraryUnload();
-
-#ifndef NP_NO_QUICKDRAW
- if (instance()->drawing_model() == NPDrawingModelQuickDraw) {
- // For some QuickDraw plugins, we can sometimes get away with giving them
- // a port pointing to a pixel buffer instead of a our actual dummy window.
- // This gives us much better frame rates, because the window scraping we
- // normally use is very slow.
- // This breaks down if the plugin does anything complicated with the port
- // (as QuickTime seems to during event handling, and sometimes when painting
- // its controls), so we switch on the fly as necessary. (It might be
- // possible to interpose sufficiently that we wouldn't have to switch back
- // and forth, but the current approach gets us most of the benefit.)
- // We can't do this at all with plugins that bypass the port entirely and
- // attaches their own surface to the window.
- // TODO(stuartmorgan): Test other QuickDraw plugins that we support and
- // see if any others can use the fast path.
- const WebPluginInfo& plugin_info = instance_->plugin_lib()->plugin_info();
- if (plugin_info.name.find(ASCIIToUTF16("QuickTime")) != string16::npos)
- quirks_ |= PLUGIN_QUIRK_ALLOW_FASTER_QUICKDRAW_PATH;
- }
-#endif
-
-#ifndef NP_NO_CARBON
- if (instance()->event_model() == NPEventModelCarbon) {
- // Create a stand-in for the browser window so that the plugin will have
- // a non-NULL WindowRef to which it can refer.
- CarbonPluginWindowTracker* window_tracker =
- CarbonPluginWindowTracker::SharedInstance();
- np_cg_context_.window = window_tracker->CreateDummyWindowForDelegate(this);
- np_cg_context_.context = NULL;
- UpdateDummyWindowBounds(gfx::Point(0, 0));
- }
-#endif
-
- NPDrawingModel drawing_model = instance()->drawing_model();
- switch (drawing_model) {
-#ifndef NP_NO_QUICKDRAW
- case NPDrawingModelQuickDraw:
- if (instance()->event_model() != NPEventModelCarbon)
- return false;
- qd_manager_.reset(new QuickDrawDrawingManager());
- qd_manager_->SetPluginWindow(
- reinterpret_cast<WindowRef>(np_cg_context_.window));
- qd_port_.port = qd_manager_->port();
- window_.window = &qd_port_;
- window_.type = NPWindowTypeDrawable;
- break;
-#endif
- case NPDrawingModelCoreGraphics:
-#ifndef NP_NO_CARBON
- if (instance()->event_model() == NPEventModelCarbon)
- window_.window = &np_cg_context_;
-#endif
- window_.type = NPWindowTypeDrawable;
- break;
- case NPDrawingModelCoreAnimation:
- case NPDrawingModelInvalidatingCoreAnimation: {
- if (instance()->event_model() != NPEventModelCocoa)
- return false;
- window_.type = NPWindowTypeDrawable;
- // Ask the plug-in for the CALayer it created for rendering content.
- // Create a surface to host it, and request a "window" handle to identify
- // the surface.
- CALayer* layer = nil;
- NPError err = instance()->NPP_GetValue(NPPVpluginCoreAnimationLayer,
- reinterpret_cast<void*>(&layer));
- if (!err) {
- if (drawing_model == NPDrawingModelCoreAnimation) {
- // Create the timer; it will be started when we get a window handle.
- redraw_timer_.reset(new base::RepeatingTimer<WebPluginDelegateImpl>);
- }
- layer_ = layer;
- surface_ = plugin_->GetAcceleratedSurface();
-
- // If surface initialization fails for some reason, just continue
- // without any drawing; returning false would be a more confusing user
- // experience (since it triggers a missing plugin placeholder).
- if (surface_->context()) {
- renderer_ = [[CARenderer rendererWithCGLContext:surface_->context()
- options:NULL] retain];
- [renderer_ setLayer:layer_];
- }
- plugin_->BindFakePluginWindowHandle(false);
- }
- break;
- }
- default:
- NOTREACHED();
- break;
- }
-
- // Let the WebPlugin know that we are windowless (unless this is a
- // Core Animation plugin, in which case BindFakePluginWindowHandle will take
- // care of setting up the appropriate window handle).
- if (!layer_)
- plugin_->SetWindow(NULL);
-
-#ifndef NP_NO_CARBON
- // If the plugin wants Carbon events, hook up to the source of idle events.
- if (instance()->event_model() == NPEventModelCarbon)
- UpdateIdleEventRate();
-#endif
-
- // QuickTime (in QD mode only) can crash if it gets other calls (e.g.,
- // NPP_Write) before it gets a SetWindow call, so call SetWindow (with a 0x0
- // rect) immediately.
-#ifndef NP_NO_QUICKDRAW
- if (instance()->drawing_model() == NPDrawingModelQuickDraw) {
- const WebPluginInfo& plugin_info = instance_->plugin_lib()->plugin_info();
- if (plugin_info.name.find(ASCIIToUTF16("QuickTime")) != string16::npos)
- WindowlessSetWindow();
- }
-#endif
-
- return true;
-}
-
-void WebPluginDelegateImpl::PlatformDestroyInstance() {
-#ifndef NP_NO_CARBON
- if (instance()->event_model() == NPEventModelCarbon)
- CarbonIdleEventSource::SharedInstance()->UnregisterDelegate(this);
-#endif
- if (redraw_timer_.get())
- redraw_timer_->Stop();
- [renderer_ release];
- renderer_ = nil;
- layer_ = nil;
-}
-
-void WebPluginDelegateImpl::UpdateGeometryAndContext(
- const gfx::Rect& window_rect, const gfx::Rect& clip_rect,
- CGContextRef context) {
- buffer_context_ = context;
-#ifndef NP_NO_CARBON
- if (instance()->event_model() == NPEventModelCarbon) {
- // Update the structure that is passed to Carbon+CoreGraphics plugins in
- // NPP_SetWindow before calling UpdateGeometry, since that will trigger an
- // NPP_SetWindow call if the geometry changes (which is the only time the
- // context would be different), and some plugins (e.g., Flash) have an
- // internal cache of the context that they only update when NPP_SetWindow
- // is called.
- np_cg_context_.context = context;
- }
-#endif
-#ifndef NP_NO_QUICKDRAW
- if (instance()->drawing_model() == NPDrawingModelQuickDraw)
- qd_manager_->SetTargetContext(context, window_rect.size());
-#endif
- UpdateGeometry(window_rect, clip_rect);
-}
-
-void WebPluginDelegateImpl::Paint(CGContextRef context, const gfx::Rect& rect) {
- WindowlessPaint(context, rect);
-
-#ifndef NP_NO_QUICKDRAW
- // Paint events are our cue to dump the current plugin bits into the buffer
- // context if we are dealing with a QuickDraw plugin.
- if (instance()->drawing_model() == NPDrawingModelQuickDraw) {
- qd_manager_->UpdateContext();
- }
-#endif
-}
-
-void WebPluginDelegateImpl::Print(CGContextRef context) {
- NOTIMPLEMENTED();
-}
-
-bool WebPluginDelegateImpl::PlatformHandleInputEvent(
- const WebInputEvent& event, WebCursorInfo* cursor_info) {
- DCHECK(cursor_info != NULL);
-
- // If we get an event before we've set up the plugin, bail.
- if (!have_called_set_window_)
- return false;
-#ifndef NP_NO_CARBON
- if (instance()->event_model() == NPEventModelCarbon &&
- !np_cg_context_.context) {
- return false;
- }
-#endif
-
- if (WebInputEvent::isMouseEventType(event.type) ||
- event.type == WebInputEvent::MouseWheel) {
- // Check our plugin location before we send the event to the plugin, just
- // in case we somehow missed a plugin frame change.
- const WebMouseEvent* mouse_event =
- static_cast<const WebMouseEvent*>(&event);
- gfx::Point content_origin(
- mouse_event->globalX - mouse_event->x - window_rect_.x(),
- mouse_event->globalY - mouse_event->y - window_rect_.y());
- if (content_origin.x() != content_area_origin_.x() ||
- content_origin.y() != content_area_origin_.y()) {
- DLOG(WARNING) << "Stale plugin content area location: "
- << content_area_origin_ << " instead of "
- << content_origin;
- SetContentAreaOrigin(content_origin);
- }
-
- current_windowless_cursor_.GetCursorInfo(cursor_info);
- }
-
-#ifndef NP_NO_CARBON
- if (instance()->event_model() == NPEventModelCarbon) {
-#ifndef NP_NO_QUICKDRAW
- if (instance()->drawing_model() == NPDrawingModelQuickDraw) {
- if (quirks_ & PLUGIN_QUIRK_ALLOW_FASTER_QUICKDRAW_PATH) {
- // Mouse event handling doesn't work correctly in the fast path mode,
- // so any time we get a mouse event turn the fast path off, but set a
- // time to switch it on again (we don't rely just on MouseLeave because
- // we don't want poor performance in the case of clicking the play
- // button and then leaving the mouse there).
- // This isn't perfect (specifically, click-and-hold doesn't seem to work
- // if the fast path is on), but the slight regression is worthwhile
- // for the improved framerates.
- if (WebInputEvent::isMouseEventType(event.type)) {
- if (event.type == WebInputEvent::MouseLeave) {
- SetQuickDrawFastPathEnabled(true);
- } else {
- SetQuickDrawFastPathEnabled(false);
- }
- // Make sure the plugin wasn't destroyed during the switch.
- if (!instance())
- return false;
- }
- }
-
- qd_manager_->MakePortCurrent();
- }
-#endif
-
- if (event.type == WebInputEvent::MouseMove) {
- return true; // The recurring FireIdleEvent will send null events.
- }
- }
-#endif
-
- ScopedActiveDelegate active_delegate(this);
-
- // Create the plugin event structure.
- NPEventModel event_model = instance()->event_model();
- scoped_ptr<PluginWebEventConverter> event_converter(
- PluginWebEventConverterFactory::CreateConverterForModel(event_model));
- if (!(event_converter.get() && event_converter->InitWithEvent(event))) {
- // Silently consume any keyboard event types that we don't handle, so that
- // they don't fall through to the page.
- if (WebInputEvent::isKeyboardEventType(event.type))
- return true;
- return false;
- }
- void* plugin_event = event_converter->plugin_event();
-
- if (instance()->event_model() == NPEventModelCocoa) {
- // We recieve events related to drags starting outside the plugin, but the
- // NPAPI Cocoa event model spec says plugins shouldn't receive them, so
- // filter them out.
- // If we add a page capture mode at the WebKit layer (like the plugin
- // capture mode that handles drags starting inside) this can be removed.
- bool drag_related = external_drag_tracker_->EventIsRelatedToDrag(event);
- external_drag_tracker_->UpdateDragStateFromEvent(event);
- if (drag_related) {
- if (event.type == WebInputEvent::MouseUp &&
- !external_drag_tracker_->IsDragInProgress()) {
- // When an external drag ends, we need to synthesize a MouseEntered.
- NPCocoaEvent enter_event = *(static_cast<NPCocoaEvent*>(plugin_event));
- enter_event.type = NPCocoaEventMouseEntered;
- NPAPI::ScopedCurrentPluginEvent event_scope(instance(), &enter_event);
- instance()->NPP_HandleEvent(&enter_event);
- }
- return false;
- }
- }
-
- // Send the plugin the event.
- scoped_ptr<NPAPI::ScopedCurrentPluginEvent> event_scope(NULL);
- if (instance()->event_model() == NPEventModelCocoa) {
- event_scope.reset(new NPAPI::ScopedCurrentPluginEvent(
- instance(), static_cast<NPCocoaEvent*>(plugin_event)));
- }
- int16_t handle_response = instance()->NPP_HandleEvent(plugin_event);
- bool handled = handle_response != kNPEventNotHandled;
-
- if (handled && event.type == WebInputEvent::KeyDown) {
- // Update IME state as requested by the plugin.
- SetImeEnabled(handle_response == kNPEventStartIME);
- }
-
- // Plugins don't give accurate information about whether or not they handled
- // events, so browsers on the Mac ignore the return value.
- // Scroll events are the exception, since the Cocoa spec defines a meaning
- // for the return value.
- if (WebInputEvent::isMouseEventType(event.type)) {
- handled = true;
- } else if (WebInputEvent::isKeyboardEventType(event.type)) {
- // For Command-key events, trust the return value since eating all menu
- // shortcuts is not ideal.
- // TODO(stuartmorgan): Implement the advanced key handling spec, and trust
- // trust the key event return value from plugins that implement it.
- if (!(event.modifiers & WebInputEvent::MetaKey))
- handled = true;
- }
-
- return handled;
-}
-
-void WebPluginDelegateImpl::InstallMissingPlugin() {
- NOTIMPLEMENTED();
-}
-
-#pragma mark -
-
-void WebPluginDelegateImpl::WindowlessUpdateGeometry(
- const gfx::Rect& window_rect,
- const gfx::Rect& clip_rect) {
- gfx::Rect old_clip_rect = clip_rect_;
- cached_clip_rect_ = clip_rect;
- if (container_is_visible_) // Remove check when cached_clip_rect_ is removed.
- clip_rect_ = clip_rect;
- bool clip_rect_changed = (clip_rect_ != old_clip_rect);
- bool window_size_changed = (window_rect.size() != window_rect_.size());
-
- bool force_set_window = false;
-#ifndef NP_NO_QUICKDRAW
- // In a QuickDraw plugin, a geometry update might have caused a port change;
- // if so, we need to call SetWindow even if nothing else changed.
- if (qd_manager_.get() && (qd_port_.port != qd_manager_->port())) {
- qd_port_.port = qd_manager_->port();
- force_set_window = true;
- }
-#endif
-
- if (window_rect == window_rect_ && !clip_rect_changed && !force_set_window)
- return;
-
- if (old_clip_rect.IsEmpty() != clip_rect_.IsEmpty()) {
- PluginVisibilityChanged();
- }
-
- SetPluginRect(window_rect);
-
-#ifndef NP_NO_QUICKDRAW
- if (window_size_changed && qd_manager_.get() &&
- qd_manager_->IsFastPathEnabled()) {
- // If the window size has changed, we need to turn off the fast path so that
- // the full redraw goes to the window and we get a correct baseline paint.
- SetQuickDrawFastPathEnabled(false);
- return; // SetQuickDrawFastPathEnabled will call SetWindow for us.
- }
-#endif
-
- if (window_size_changed || clip_rect_changed || force_set_window)
- WindowlessSetWindow();
-}
-
-void WebPluginDelegateImpl::WindowlessPaint(gfx::NativeDrawingContext context,
- const gfx::Rect& damage_rect) {
- // If we get a paint event before we are completely set up (e.g., a nested
- // call while the plugin is still in NPP_SetWindow), bail.
- if (!have_called_set_window_ || !buffer_context_)
- return;
- DCHECK(buffer_context_ == context);
-
- static base::StatsRate plugin_paint("Plugin.Paint");
- base::StatsScope<base::StatsRate> scope(plugin_paint);
-
- // Plugin invalidates trigger asynchronous paints with the original
- // invalidation rect; the plugin may be resized before the paint is handled,
- // so we need to ensure that the damage rect is still sane.
- const gfx::Rect paint_rect(damage_rect.Intersect(
- gfx::Rect(0, 0, window_rect_.width(), window_rect_.height())));
-
- ScopedActiveDelegate active_delegate(this);
-
-#ifndef NP_NO_QUICKDRAW
- if (instance()->drawing_model() == NPDrawingModelQuickDraw)
- qd_manager_->MakePortCurrent();
-#endif
-
- CGContextSaveGState(context);
-
- switch (instance()->event_model()) {
-#ifndef NP_NO_CARBON
- case NPEventModelCarbon: {
- NPEvent paint_event = { 0 };
- paint_event.what = updateEvt;
- paint_event.message = reinterpret_cast<uint32>(np_cg_context_.window);
- paint_event.when = TickCount();
- instance()->NPP_HandleEvent(&paint_event);
- break;
- }
-#endif
- case NPEventModelCocoa: {
- NPCocoaEvent paint_event;
- memset(&paint_event, 0, sizeof(NPCocoaEvent));
- paint_event.type = NPCocoaEventDrawRect;
- paint_event.data.draw.context = context;
- paint_event.data.draw.x = paint_rect.x();
- paint_event.data.draw.y = paint_rect.y();
- paint_event.data.draw.width = paint_rect.width();
- paint_event.data.draw.height = paint_rect.height();
- instance()->NPP_HandleEvent(&paint_event);
- break;
- }
- }
-
- // The backing buffer can change during the call to NPP_HandleEvent, in which
- // case the old context is (or is about to be) invalid.
- if (context == buffer_context_)
- CGContextRestoreGState(context);
-}
-
-void WebPluginDelegateImpl::WindowlessSetWindow() {
- if (!instance())
- return;
-
- window_.x = 0;
- window_.y = 0;
- window_.height = window_rect_.height();
- window_.width = window_rect_.width();
- window_.clipRect.left = clip_rect_.x();
- window_.clipRect.top = clip_rect_.y();
- window_.clipRect.right = clip_rect_.x() + clip_rect_.width();
- window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height();
-
- NPError err = instance()->NPP_SetWindow(&window_);
-
- // Send an appropriate window focus event after the first SetWindow.
- if (!have_called_set_window_) {
- have_called_set_window_ = true;
- SetWindowHasFocus(initial_window_focus_);
- }
-
-#ifndef NP_NO_QUICKDRAW
- if ((quirks_ & PLUGIN_QUIRK_ALLOW_FASTER_QUICKDRAW_PATH) &&
- !qd_manager_->IsFastPathEnabled() && !clip_rect_.IsEmpty()) {
- // Give the plugin a few seconds to stabilize so we get a good initial paint
- // to use as a baseline, then switch to the fast path.
- fast_path_enable_tick_ = base::TimeTicks::Now() +
- base::TimeDelta::FromSeconds(3);
- }
-#endif
-
- DCHECK(err == NPERR_NO_ERROR);
-}
-
-#pragma mark -
-
-bool WebPluginDelegateImpl::WindowedCreatePlugin() {
- NOTREACHED();
- return false;
-}
-
-void WebPluginDelegateImpl::WindowedDestroyWindow() {
- NOTREACHED();
-}
-
-bool WebPluginDelegateImpl::WindowedReposition(const gfx::Rect& window_rect,
- const gfx::Rect& clip_rect) {
- NOTREACHED();
- return false;
-}
-
-void WebPluginDelegateImpl::WindowedSetWindow() {
- NOTREACHED();
-}
-
-#pragma mark -
-#pragma mark Mac Extensions
-
-void WebPluginDelegateImpl::PluginDidInvalidate() {
- if (instance()->drawing_model() == NPDrawingModelInvalidatingCoreAnimation)
- DrawLayerInSurface();
-}
-
-WebPluginDelegateImpl* WebPluginDelegateImpl::GetActiveDelegate() {
- return g_active_delegate;
-}
-
-void WebPluginDelegateImpl::SetWindowHasFocus(bool has_focus) {
- // If we get a window focus event before calling SetWindow, just remember the
- // states (WindowlessSetWindow will then send it on the first call).
- if (!have_called_set_window_) {
- initial_window_focus_ = has_focus;
- return;
- }
-
- if (has_focus == containing_window_has_focus_)
- return;
- containing_window_has_focus_ = has_focus;
-
- if (!has_focus)
- SetImeEnabled(false);
-
-#ifndef NP_NO_QUICKDRAW
- // Make sure controls repaint with the correct look.
- if (quirks_ & PLUGIN_QUIRK_ALLOW_FASTER_QUICKDRAW_PATH)
- SetQuickDrawFastPathEnabled(false);
-#endif
-
- ScopedActiveDelegate active_delegate(this);
- switch (instance()->event_model()) {
-#ifndef NP_NO_CARBON
- case NPEventModelCarbon: {
- NPEvent focus_event = { 0 };
- focus_event.what = activateEvt;
- if (has_focus)
- focus_event.modifiers |= activeFlag;
- focus_event.message =
- reinterpret_cast<unsigned long>(np_cg_context_.window);
- focus_event.when = TickCount();
- instance()->NPP_HandleEvent(&focus_event);
- break;
- }
-#endif
- case NPEventModelCocoa: {
- NPCocoaEvent focus_event;
- memset(&focus_event, 0, sizeof(focus_event));
- focus_event.type = NPCocoaEventWindowFocusChanged;
- focus_event.data.focus.hasFocus = has_focus;
- instance()->NPP_HandleEvent(&focus_event);
- break;
- }
- }
-}
-
-bool WebPluginDelegateImpl::PlatformSetPluginHasFocus(bool focused) {
- if (!have_called_set_window_)
- return false;
-
- if (!focused)
- SetImeEnabled(false);
-
- ScopedActiveDelegate active_delegate(this);
-
- switch (instance()->event_model()) {
-#ifndef NP_NO_CARBON
- case NPEventModelCarbon: {
- NPEvent focus_event = { 0 };
- if (focused)
- focus_event.what = NPEventType_GetFocusEvent;
- else
- focus_event.what = NPEventType_LoseFocusEvent;
- focus_event.when = TickCount();
- instance()->NPP_HandleEvent(&focus_event);
- break;
- }
-#endif
- case NPEventModelCocoa: {
- NPCocoaEvent focus_event;
- memset(&focus_event, 0, sizeof(focus_event));
- focus_event.type = NPCocoaEventFocusChanged;
- focus_event.data.focus.hasFocus = focused;
- instance()->NPP_HandleEvent(&focus_event);
- break;
- }
- }
- return true;
-}
-
-void WebPluginDelegateImpl::SetContainerVisibility(bool is_visible) {
- if (is_visible == container_is_visible_)
- return;
- container_is_visible_ = is_visible;
-
- // TODO(stuartmorgan): This is a temporary workarond for
- // <http://crbug.com/34266>. When that is fixed, the cached_clip_rect_ code
- // should all be removed.
- if (is_visible) {
- clip_rect_ = cached_clip_rect_;
- } else {
- clip_rect_.set_width(0);
- clip_rect_.set_height(0);
- }
-
- // If the plugin is changing visibility, let the plugin know. If it's scrolled
- // off screen (i.e., cached_clip_rect_ is empty), then container visibility
- // doesn't change anything.
- if (!cached_clip_rect_.IsEmpty()) {
- PluginVisibilityChanged();
- WindowlessSetWindow();
- }
-
- // When the plugin become visible, send an empty invalidate. If there were any
- // pending invalidations this will trigger a paint event for the damaged
- // region, and if not it's a no-op. This is necessary since higher levels
- // that would normally do this weren't responsible for the clip_rect_ change).
- if (!clip_rect_.IsEmpty())
- instance()->webplugin()->InvalidateRect(gfx::Rect());
-}
-
-void WebPluginDelegateImpl::WindowFrameChanged(const gfx::Rect& window_frame,
- const gfx::Rect& view_frame) {
- instance()->set_window_frame(window_frame);
- SetContentAreaOrigin(gfx::Point(view_frame.x(), view_frame.y()));
-}
-
-void WebPluginDelegateImpl::ImeCompositionConfirmed(const string16& text) {
- if (instance()->event_model() != NPEventModelCocoa) {
- DLOG(ERROR) << "IME text receieved in Carbon event model";
- return;
- }
-
- NPCocoaEvent text_event;
- memset(&text_event, 0, sizeof(NPCocoaEvent));
- text_event.type = NPCocoaEventTextInput;
- text_event.data.text.text =
- reinterpret_cast<NPNSString*>(base::SysUTF16ToNSString(text));
- instance()->NPP_HandleEvent(&text_event);
-}
-
-void WebPluginDelegateImpl::SetThemeCursor(ThemeCursor cursor) {
- current_windowless_cursor_.InitFromThemeCursor(cursor);
-}
-
-void WebPluginDelegateImpl::SetCursor(const Cursor* cursor) {
- current_windowless_cursor_.InitFromCursor(cursor);
-}
-
-void WebPluginDelegateImpl::SetNSCursor(NSCursor* cursor) {
- current_windowless_cursor_.InitFromNSCursor(cursor);
-}
-
-#pragma mark -
-#pragma mark Internal Tracking
-
-void WebPluginDelegateImpl::SetPluginRect(const gfx::Rect& rect) {
- bool plugin_size_changed = rect.width() != window_rect_.width() ||
- rect.height() != window_rect_.height();
- window_rect_ = rect;
- PluginScreenLocationChanged();
- if (plugin_size_changed)
- UpdateAcceleratedSurface();
-}
-
-void WebPluginDelegateImpl::SetContentAreaOrigin(const gfx::Point& origin) {
- content_area_origin_ = origin;
- PluginScreenLocationChanged();
-}
-
-void WebPluginDelegateImpl::PluginScreenLocationChanged() {
- gfx::Point plugin_origin(content_area_origin_.x() + window_rect_.x(),
- content_area_origin_.y() + window_rect_.y());
- instance()->set_plugin_origin(plugin_origin);
-
-#ifndef NP_NO_CARBON
- if (instance()->event_model() == NPEventModelCarbon) {
- UpdateDummyWindowBounds(plugin_origin);
- }
-#endif
-}
-
-void WebPluginDelegateImpl::PluginVisibilityChanged() {
-#ifndef NP_NO_CARBON
- if (instance()->event_model() == NPEventModelCarbon)
- UpdateIdleEventRate();
-#endif
- if (instance()->drawing_model() == NPDrawingModelCoreAnimation) {
- bool plugin_visible = container_is_visible_ && !clip_rect_.IsEmpty();
- if (plugin_visible && !redraw_timer_->IsRunning() && windowed_handle()) {
- redraw_timer_->Start(
- base::TimeDelta::FromMilliseconds(kCoreAnimationRedrawPeriodMs),
- this, &WebPluginDelegateImpl::DrawLayerInSurface);
- } else if (!plugin_visible) {
- redraw_timer_->Stop();
- }
- }
-}
-
-void WebPluginDelegateImpl::SetImeEnabled(bool enabled) {
- if (instance()->event_model() != NPEventModelCocoa)
- return;
- if (enabled == ime_enabled_)
- return;
- ime_enabled_ = enabled;
- plugin_->SetImeEnabled(enabled);
-}
-
-#pragma mark -
-#pragma mark Core Animation Support
-
-void WebPluginDelegateImpl::DrawLayerInSurface() {
- // If we haven't plumbed up the surface yet, don't try to draw.
- if (!windowed_handle() || !renderer_)
- return;
-
- [renderer_ beginFrameAtTime:CACurrentMediaTime() timeStamp:NULL];
- if (CGRectIsEmpty([renderer_ updateBounds])) {
- // If nothing has changed, we are done.
- [renderer_ endFrame];
- return;
- }
-
- surface_->StartDrawing();
-
- CGRect layerRect = [layer_ bounds];
- [renderer_ addUpdateRect:layerRect];
- [renderer_ render];
- [renderer_ endFrame];
-
- surface_->EndDrawing();
-}
-
-// Update the size of the surface to match the current size of the plug-in.
-void WebPluginDelegateImpl::UpdateAcceleratedSurface() {
- // Will only have a window handle when using a Core Animation drawing model.
- if (!windowed_handle() || !layer_)
- return;
-
- [CATransaction begin];
- [CATransaction setValue:[NSNumber numberWithInt:0]
- forKey:kCATransactionAnimationDuration];
- [layer_ setFrame:CGRectMake(0, 0,
- window_rect_.width(), window_rect_.height())];
- [CATransaction commit];
-
- [renderer_ setBounds:[layer_ bounds]];
- surface_->SetSize(window_rect_.size());
-}
-
-void WebPluginDelegateImpl::set_windowed_handle(
- gfx::PluginWindowHandle handle) {
- windowed_handle_ = handle;
- surface_->SetWindowHandle(handle);
- UpdateAcceleratedSurface();
- // Kick off the drawing timer, if necessary.
- PluginVisibilityChanged();
-}
-
-#pragma mark -
-#pragma mark Carbon Event support
-
-#ifndef NP_NO_CARBON
-void WebPluginDelegateImpl::UpdateDummyWindowBounds(
- const gfx::Point& plugin_origin) {
- WindowRef window = reinterpret_cast<WindowRef>(np_cg_context_.window);
- Rect current_bounds;
- GetWindowBounds(window, kWindowContentRgn, &current_bounds);
-
- Rect new_bounds;
- // We never want to resize the window to 0x0, so if the plugin is 0x0 just
- // move the window without resizing it.
- if (window_rect_.width() > 0 && window_rect_.height() > 0) {
- SetRect(&new_bounds, 0, 0, window_rect_.width(), window_rect_.height());
- OffsetRect(&new_bounds, plugin_origin.x(), plugin_origin.y());
- } else {
- new_bounds = current_bounds;
- OffsetRect(&new_bounds, plugin_origin.x() - current_bounds.left,
- plugin_origin.y() - current_bounds.top);
- }
-
- if (new_bounds.left != current_bounds.left ||
- new_bounds.top != current_bounds.top ||
- new_bounds.right != current_bounds.right ||
- new_bounds.bottom != current_bounds.bottom)
- SetWindowBounds(window, kWindowContentRgn, &new_bounds);
-}
-
-void WebPluginDelegateImpl::UpdateIdleEventRate() {
- bool plugin_visible = container_is_visible_ && !clip_rect_.IsEmpty();
- CarbonIdleEventSource::SharedInstance()->RegisterDelegate(this,
- plugin_visible);
-}
-
-void WebPluginDelegateImpl::FireIdleEvent() {
- // Avoid a race condition between IO and UI threads during plugin shutdown
- if (!instance())
- return;
- // Don't send idle events until we've called SetWindow.
- if (!have_called_set_window_)
- return;
-
-#ifndef NP_NO_QUICKDRAW
- // Check whether it's time to turn the QuickDraw fast path back on.
- if (!fast_path_enable_tick_.is_null() &&
- (base::TimeTicks::Now() > fast_path_enable_tick_)) {
- SetQuickDrawFastPathEnabled(true);
- fast_path_enable_tick_ = base::TimeTicks();
- }
-#endif
-
- ScopedActiveDelegate active_delegate(this);
-
-#ifndef NP_NO_QUICKDRAW
- if (instance()->drawing_model() == NPDrawingModelQuickDraw)
- qd_manager_->MakePortCurrent();
-#endif
-
- // Send an idle event so that the plugin can do background work
- NPEvent np_event = {0};
- np_event.what = nullEvent;
- np_event.when = TickCount();
- np_event.modifiers = GetCurrentKeyModifiers();
- if (!Button())
- np_event.modifiers |= btnState;
- HIPoint mouse_location;
- HIGetMousePosition(kHICoordSpaceScreenPixel, NULL, &mouse_location);
- np_event.where.h = mouse_location.x;
- np_event.where.v = mouse_location.y;
- instance()->NPP_HandleEvent(&np_event);
-
-#ifndef NP_NO_QUICKDRAW
- // Quickdraw-based plugins can draw at any time, so tell the renderer to
- // repaint.
- if (instance() && instance()->drawing_model() == NPDrawingModelQuickDraw)
- instance()->webplugin()->Invalidate();
-#endif
-}
-#endif // !NP_NO_CARBON
-
-#pragma mark -
-#pragma mark QuickDraw Support
-
-#ifndef NP_NO_QUICKDRAW
-void WebPluginDelegateImpl::SetQuickDrawFastPathEnabled(bool enabled) {
- if (!enabled) {
- // Wait a couple of seconds, then turn the fast path back on. If we're
- // turning it off for event handling, that ensures that the common case of
- // move-mouse-then-click works (as well as making it likely that a second
- // click attempt will work if the first one fails). If we're turning it
- // off to force a new baseline image, this leaves plenty of time for the
- // plugin to draw.
- fast_path_enable_tick_ = base::TimeTicks::Now() +
- base::TimeDelta::FromSeconds(2);
- }
-
- if (enabled == qd_manager_->IsFastPathEnabled())
- return;
- if (enabled && clip_rect_.IsEmpty()) {
- // Don't switch to the fast path while the plugin is completely clipped;
- // we can only switch when the window has an up-to-date image for us to
- // scrape. We'll automatically switch after we become visible again.
- return;
- }
-
- qd_manager_->SetFastPathEnabled(enabled);
- qd_port_.port = qd_manager_->port();
- WindowlessSetWindow();
- // Send a paint event so that the new buffer gets updated immediately.
- WindowlessPaint(buffer_context_, clip_rect_);
-}
-#endif // !NP_NO_QUICKDRAW
diff --git a/webkit/glue/plugins/webplugin_delegate_impl_win.cc b/webkit/glue/plugins/webplugin_delegate_impl_win.cc
deleted file mode 100644
index e1acba1..0000000
--- a/webkit/glue/plugins/webplugin_delegate_impl_win.cc
+++ /dev/null
@@ -1,1410 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/webplugin_delegate_impl.h"
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include "app/win/iat_patch_function.h"
-#include "base/file_util.h"
-#include "base/lazy_instance.h"
-#include "base/message_loop.h"
-#include "base/metrics/stats_counters.h"
-#include "base/scoped_ptr.h"
-#include "base/string_number_conversions.h"
-#include "base/string_split.h"
-#include "base/string_util.h"
-#include "base/stringprintf.h"
-#include "base/win/registry.h"
-#include "base/win/windows_version.h"
-#include "skia/ext/platform_canvas.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h"
-#include "webkit/glue/plugins/default_plugin_shared.h"
-#include "webkit/glue/plugins/plugin_constants_win.h"
-#include "webkit/glue/plugins/plugin_instance.h"
-#include "webkit/glue/plugins/plugin_lib.h"
-#include "webkit/glue/plugins/plugin_list.h"
-#include "webkit/glue/plugins/plugin_stream_url.h"
-#include "webkit/glue/plugins/webplugin.h"
-#include "webkit/glue/webkit_glue.h"
-
-using WebKit::WebCursorInfo;
-using WebKit::WebKeyboardEvent;
-using WebKit::WebInputEvent;
-using WebKit::WebMouseEvent;
-
-namespace {
-
-const wchar_t kWebPluginDelegateProperty[] = L"WebPluginDelegateProperty";
-const wchar_t kPluginNameAtomProperty[] = L"PluginNameAtom";
-const wchar_t kDummyActivationWindowName[] = L"DummyWindowForActivation";
-const wchar_t kPluginFlashThrottle[] = L"FlashThrottle";
-
-// The fastest we are willing to process WM_USER+1 events for Flash.
-// Flash can easily exceed the limits of our CPU if we don't throttle it.
-// The throttle has been chosen by testing various delays and compromising
-// on acceptable Flash performance and reasonable CPU consumption.
-//
-// I'd like to make the throttle delay variable, based on the amount of
-// time currently required to paint Flash plugins. There isn't a good
-// way to count the time spent in aggregate plugin painting, however, so
-// this seems to work well enough.
-const int kFlashWMUSERMessageThrottleDelayMs = 5;
-
-// Flash displays popups in response to user clicks by posting a WM_USER
-// message to the plugin window. The handler for this message displays
-// the popup. To ensure that the popups allowed state is sent correctly
-// to the renderer we reset the popups allowed state in a timer.
-const int kWindowedPluginPopupTimerMs = 50;
-
-// The current instance of the plugin which entered the modal loop.
-WebPluginDelegateImpl* g_current_plugin_instance = NULL;
-
-typedef std::deque<MSG> ThrottleQueue;
-base::LazyInstance<ThrottleQueue> g_throttle_queue(base::LINKER_INITIALIZED);
-base::LazyInstance<std::map<HWND, WNDPROC> > g_window_handle_proc_map(
- base::LINKER_INITIALIZED);
-
-
-// Helper object for patching the TrackPopupMenu API.
-base::LazyInstance<app::win::IATPatchFunction> g_iat_patch_track_popup_menu(
- base::LINKER_INITIALIZED);
-
-// Helper object for patching the SetCursor API.
-base::LazyInstance<app::win::IATPatchFunction> g_iat_patch_set_cursor(
- base::LINKER_INITIALIZED);
-
-// Helper object for patching the RegEnumKeyExW API.
-base::LazyInstance<app::win::IATPatchFunction> g_iat_patch_reg_enum_key_ex_w(
- base::LINKER_INITIALIZED);
-
-// http://crbug.com/16114
-// Enforces providing a valid device context in NPWindow, so that NPP_SetWindow
-// is never called with NPNWindoTypeDrawable and NPWindow set to NULL.
-// Doing so allows removing NPP_SetWindow call during painting a windowless
-// plugin, which otherwise could trigger layout change while painting by
-// invoking NPN_Evaluate. Which would cause bad, bad crashes. Bad crashes.
-// TODO(dglazkov): If this approach doesn't produce regressions, move class to
-// webplugin_delegate_impl.h and implement for other platforms.
-class DrawableContextEnforcer {
- public:
- explicit DrawableContextEnforcer(NPWindow* window)
- : window_(window),
- disposable_dc_(window && !window->window) {
- // If NPWindow is NULL, create a device context with monochrome 1x1 surface
- // and stuff it to NPWindow.
- if (disposable_dc_)
- window_->window = CreateCompatibleDC(NULL);
- }
-
- ~DrawableContextEnforcer() {
- if (!disposable_dc_)
- return;
-
- DeleteDC(static_cast<HDC>(window_->window));
- window_->window = NULL;
- }
-
- private:
- NPWindow* window_;
- bool disposable_dc_;
-};
-
-// These are from ntddk.h
-typedef LONG NTSTATUS;
-
-#ifndef STATUS_SUCCESS
-#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
-#endif
-
-#ifndef STATUS_BUFFER_TOO_SMALL
-#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L)
-#endif
-
-typedef enum _KEY_INFORMATION_CLASS {
- KeyBasicInformation,
- KeyNodeInformation,
- KeyFullInformation,
- KeyNameInformation,
- KeyCachedInformation,
- KeyVirtualizationInformation
-} KEY_INFORMATION_CLASS;
-
-typedef struct _KEY_NAME_INFORMATION {
- ULONG NameLength;
- WCHAR Name[1];
-} KEY_NAME_INFORMATION, *PKEY_NAME_INFORMATION;
-
-typedef DWORD (__stdcall *ZwQueryKeyType)(
- HANDLE key_handle,
- int key_information_class,
- PVOID key_information,
- ULONG length,
- PULONG result_length);
-
-// Returns a key's full path.
-std::wstring GetKeyPath(HKEY key) {
- if (key == NULL)
- return L"";
-
- HMODULE dll = GetModuleHandle(L"ntdll.dll");
- if (dll == NULL)
- return L"";
-
- ZwQueryKeyType func = reinterpret_cast<ZwQueryKeyType>(
- ::GetProcAddress(dll, "ZwQueryKey"));
- if (func == NULL)
- return L"";
-
- DWORD size = 0;
- DWORD result = 0;
- result = func(key, KeyNameInformation, 0, 0, &size);
- if (result != STATUS_BUFFER_TOO_SMALL)
- return L"";
-
- scoped_array<char> buffer(new char[size]);
- if (buffer.get() == NULL)
- return L"";
-
- result = func(key, KeyNameInformation, buffer.get(), size, &size);
- if (result != STATUS_SUCCESS)
- return L"";
-
- KEY_NAME_INFORMATION* info =
- reinterpret_cast<KEY_NAME_INFORMATION*>(buffer.get());
- return std::wstring(info->Name, info->NameLength / sizeof(wchar_t));
-}
-
-} // namespace
-
-bool WebPluginDelegateImpl::IsPluginDelegateWindow(HWND window) {
- // We use a buffer that is one char longer than we need to detect cases where
- // kNativeWindowClassName is a prefix of the given window's class name. It
- // happens that GetClassNameW will just silently truncate the class name to
- // fit into the given buffer.
- wchar_t class_name[arraysize(kNativeWindowClassName) + 1];
- if (!GetClassNameW(window, class_name, arraysize(class_name)))
- return false;
- return wcscmp(class_name, kNativeWindowClassName) == 0;
-}
-
-bool WebPluginDelegateImpl::GetPluginNameFromWindow(
- HWND window, std::wstring *plugin_name) {
- if (NULL == plugin_name) {
- return false;
- }
- if (!IsPluginDelegateWindow(window)) {
- return false;
- }
- ATOM plugin_name_atom = reinterpret_cast<ATOM>(
- GetPropW(window, kPluginNameAtomProperty));
- if (plugin_name_atom != 0) {
- WCHAR plugin_name_local[MAX_PATH] = {0};
- GlobalGetAtomNameW(plugin_name_atom,
- plugin_name_local,
- ARRAYSIZE(plugin_name_local));
- *plugin_name = plugin_name_local;
- return true;
- }
- return false;
-}
-
-bool WebPluginDelegateImpl::IsDummyActivationWindow(HWND window) {
- if (!IsWindow(window))
- return false;
-
- wchar_t window_title[MAX_PATH + 1] = {0};
- if (GetWindowText(window, window_title, arraysize(window_title))) {
- return (0 == lstrcmpiW(window_title, kDummyActivationWindowName));
- }
- return false;
-}
-
-LRESULT CALLBACK WebPluginDelegateImpl::HandleEventMessageFilterHook(
- int code, WPARAM wParam, LPARAM lParam) {
- if (g_current_plugin_instance) {
- g_current_plugin_instance->OnModalLoopEntered();
- } else {
- NOTREACHED();
- }
- return CallNextHookEx(NULL, code, wParam, lParam);
-}
-
-LRESULT CALLBACK WebPluginDelegateImpl::MouseHookProc(
- int code, WPARAM wParam, LPARAM lParam) {
- if (code == HC_ACTION) {
- MOUSEHOOKSTRUCT* hook_struct = reinterpret_cast<MOUSEHOOKSTRUCT*>(lParam);
- if (hook_struct)
- HandleCaptureForMessage(hook_struct->hwnd, wParam);
- }
-
- return CallNextHookEx(NULL, code, wParam, lParam);
-}
-
-WebPluginDelegateImpl::WebPluginDelegateImpl(
- gfx::PluginWindowHandle containing_view,
- NPAPI::PluginInstance *instance)
- : parent_(containing_view),
- instance_(instance),
- quirks_(0),
- plugin_(NULL),
- windowless_(false),
- windowed_handle_(NULL),
- windowed_did_set_window_(false),
- plugin_wnd_proc_(NULL),
- last_message_(0),
- is_calling_wndproc(false),
- keyboard_layout_(NULL),
- parent_thread_id_(0),
- dummy_window_for_activation_(NULL),
- handle_event_message_filter_hook_(NULL),
- handle_event_pump_messages_event_(NULL),
- user_gesture_message_posted_(false),
-#pragma warning(suppress: 4355) // can use this
- user_gesture_msg_factory_(this),
- handle_event_depth_(0),
- mouse_hook_(NULL),
- first_set_window_call_(true),
- plugin_has_focus_(false),
- has_webkit_focus_(false),
- containing_view_has_focus_(true),
- creation_succeeded_(false) {
- memset(&window_, 0, sizeof(window_));
-
- const WebPluginInfo& plugin_info = instance_->plugin_lib()->plugin_info();
- std::wstring filename =
- StringToLowerASCII(plugin_info.path.BaseName().value());
-
- if (instance_->mime_type() == "application/x-shockwave-flash" ||
- filename == kFlashPlugin) {
- // Flash only requests windowless plugins if we return a Mozilla user
- // agent.
- instance_->set_use_mozilla_user_agent();
- quirks_ |= PLUGIN_QUIRK_THROTTLE_WM_USER_PLUS_ONE;
- quirks_ |= PLUGIN_QUIRK_PATCH_SETCURSOR;
- quirks_ |= PLUGIN_QUIRK_ALWAYS_NOTIFY_SUCCESS;
- quirks_ |= PLUGIN_QUIRK_HANDLE_MOUSE_CAPTURE;
- } else if (filename == kAcrobatReaderPlugin) {
- // Check for the version number above or equal 9.
- std::vector<std::wstring> version;
- base::SplitString(plugin_info.version, L'.', &version);
- if (version.size() > 0) {
- int major;
- base::StringToInt(version[0], &major);
- if (major >= 9) {
- quirks_ |= PLUGIN_QUIRK_DIE_AFTER_UNLOAD;
-
- // 9.2 needs this.
- quirks_ |= PLUGIN_QUIRK_SETWINDOW_TWICE;
- }
- }
- quirks_ |= PLUGIN_QUIRK_BLOCK_NONSTANDARD_GETURL_REQUESTS;
- } else if (plugin_info.name.find(L"Windows Media Player") !=
- std::wstring::npos) {
- // Windows Media Player needs two NPP_SetWindow calls.
- quirks_ |= PLUGIN_QUIRK_SETWINDOW_TWICE;
-
- // Windowless mode doesn't work in the WMP NPAPI plugin.
- quirks_ |= PLUGIN_QUIRK_NO_WINDOWLESS;
-
- // The media player plugin sets its size on the first NPP_SetWindow call
- // and never updates its size. We should call the underlying NPP_SetWindow
- // only when we have the correct size.
- quirks_ |= PLUGIN_QUIRK_IGNORE_FIRST_SETWINDOW_CALL;
-
- if (filename == kOldWMPPlugin) {
- // Non-admin users on XP couldn't modify the key to force the new UI.
- quirks_ |= PLUGIN_QUIRK_PATCH_REGENUMKEYEXW;
- }
- } else if (instance_->mime_type() == "audio/x-pn-realaudio-plugin" ||
- filename == kRealPlayerPlugin) {
- quirks_ |= PLUGIN_QUIRK_DONT_CALL_WND_PROC_RECURSIVELY;
- } else if (plugin_info.name.find(L"VLC Multimedia Plugin") !=
- std::wstring::npos ||
- plugin_info.name.find(L"VLC Multimedia Plug-in") !=
- std::wstring::npos) {
- // VLC hangs on NPP_Destroy if we call NPP_SetWindow with a null window
- // handle
- quirks_ |= PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY;
- // VLC 0.8.6d and 0.8.6e crash if multiple instances are created.
- quirks_ |= PLUGIN_QUIRK_DONT_ALLOW_MULTIPLE_INSTANCES;
- } else if (filename == kSilverlightPlugin) {
- // Explanation for this quirk can be found in
- // WebPluginDelegateImpl::Initialize.
- quirks_ |= PLUGIN_QUIRK_PATCH_SETCURSOR;
- } else if (plugin_info.name.find(L"DivX Web Player") !=
- std::wstring::npos) {
- // The divx plugin sets its size on the first NPP_SetWindow call and never
- // updates its size. We should call the underlying NPP_SetWindow only when
- // we have the correct size.
- quirks_ |= PLUGIN_QUIRK_IGNORE_FIRST_SETWINDOW_CALL;
- }
-}
-
-WebPluginDelegateImpl::~WebPluginDelegateImpl() {
- if (::IsWindow(dummy_window_for_activation_)) {
- ::DestroyWindow(dummy_window_for_activation_);
- }
-
- DestroyInstance();
-
- if (!windowless_)
- WindowedDestroyWindow();
-
- if (handle_event_pump_messages_event_) {
- CloseHandle(handle_event_pump_messages_event_);
- }
-}
-
-bool WebPluginDelegateImpl::PlatformInitialize() {
- plugin_->SetWindow(windowed_handle_);
-
- if (windowless_ && !instance_->plugin_lib()->internal()) {
- CreateDummyWindowForActivation();
- handle_event_pump_messages_event_ = CreateEvent(NULL, TRUE, FALSE, NULL);
- plugin_->SetWindowlessPumpEvent(handle_event_pump_messages_event_);
- }
-
- // We cannot patch internal plugins as they are not shared libraries.
- if (!instance_->plugin_lib()->internal()) {
- // Windowless plugins call the WindowFromPoint API and passes the result of
- // that to the TrackPopupMenu API call as the owner window. This causes the
- // API to fail as the API expects the window handle to live on the same
- // thread as the caller. It works in the other browsers as the plugin lives
- // on the browser thread. Our workaround is to intercept the TrackPopupMenu
- // API and replace the window handle with the dummy activation window.
- if (windowless_ && !g_iat_patch_track_popup_menu.Pointer()->is_patched()) {
- g_iat_patch_track_popup_menu.Pointer()->Patch(
- GetPluginPath().value().c_str(), "user32.dll", "TrackPopupMenu",
- WebPluginDelegateImpl::TrackPopupMenuPatch);
- }
-
- // Windowless plugins can set cursors by calling the SetCursor API. This
- // works because the thread inputs of the browser UI thread and the plugin
- // thread are attached. We intercept the SetCursor API for windowless
- // plugins and remember the cursor being set. This is shipped over to the
- // browser in the HandleEvent call, which ensures that the cursor does not
- // change when a windowless plugin instance changes the cursor
- // in a background tab.
- if (windowless_ && !g_iat_patch_set_cursor.Pointer()->is_patched() &&
- (quirks_ & PLUGIN_QUIRK_PATCH_SETCURSOR)) {
- g_iat_patch_set_cursor.Pointer()->Patch(
- GetPluginPath().value().c_str(), "user32.dll", "SetCursor",
- WebPluginDelegateImpl::SetCursorPatch);
- }
-
- // The windowed flash plugin has a bug which occurs when the plugin enters
- // fullscreen mode. It basically captures the mouse on WM_LBUTTONDOWN and
- // does not release capture correctly causing it to stop receiving
- // subsequent mouse events. This problem is also seen in Safari where there
- // is code to handle this in the wndproc. However the plugin subclasses the
- // window again in WM_LBUTTONDOWN before entering full screen. As a result
- // Safari does not receive the WM_LBUTTONUP message. To workaround this
- // issue we use a per thread mouse hook. This bug does not occur in Firefox
- // and opera. Firefox has code similar to Safari. It could well be a bug in
- // the flash plugin, which only occurs in webkit based browsers.
- if (quirks_ & PLUGIN_QUIRK_HANDLE_MOUSE_CAPTURE) {
- mouse_hook_ = SetWindowsHookEx(WH_MOUSE, MouseHookProc, NULL,
- GetCurrentThreadId());
- }
- }
-
- // On XP, WMP will use its old UI unless a registry key under HKLM has the
- // name of the current process. We do it in the installer for admin users,
- // for the rest patch this function.
- if ((quirks_ & PLUGIN_QUIRK_PATCH_REGENUMKEYEXW) &&
- base::win::GetVersion() == base::win::VERSION_XP &&
- !base::win::RegKey().Open(HKEY_LOCAL_MACHINE,
- L"SOFTWARE\\Microsoft\\MediaPlayer\\ShimInclusionList\\chrome.exe",
- KEY_READ) &&
- !g_iat_patch_reg_enum_key_ex_w.Pointer()->is_patched()) {
- g_iat_patch_reg_enum_key_ex_w.Pointer()->Patch(
- L"wmpdxm.dll", "advapi32.dll", "RegEnumKeyExW",
- WebPluginDelegateImpl::RegEnumKeyExWPatch);
- }
-
- return true;
-}
-
-void WebPluginDelegateImpl::PlatformDestroyInstance() {
- if (!instance_->plugin_lib())
- return;
-
- // Unpatch if this is the last plugin instance.
- if (instance_->plugin_lib()->instance_count() != 1)
- return;
-
- if (g_iat_patch_set_cursor.Pointer()->is_patched())
- g_iat_patch_set_cursor.Pointer()->Unpatch();
-
- if (g_iat_patch_track_popup_menu.Pointer()->is_patched())
- g_iat_patch_track_popup_menu.Pointer()->Unpatch();
-
- if (g_iat_patch_reg_enum_key_ex_w.Pointer()->is_patched())
- g_iat_patch_reg_enum_key_ex_w.Pointer()->Unpatch();
-
- if (mouse_hook_) {
- UnhookWindowsHookEx(mouse_hook_);
- mouse_hook_ = NULL;
- }
-}
-
-void WebPluginDelegateImpl::Paint(skia::PlatformCanvas* canvas,
- const gfx::Rect& rect) {
- if (windowless_) {
- HDC hdc = canvas->beginPlatformPaint();
- WindowlessPaint(hdc, rect);
- canvas->endPlatformPaint();
- }
-}
-
-void WebPluginDelegateImpl::Print(HDC hdc) {
- // Disabling the call to NPP_Print as it causes a crash in
- // flash in some cases. In any case this does not work as expected
- // as the EMF meta file dc passed in needs to be created with the
- // the plugin window dc as its sibling dc and the window rect
- // in .01 mm units.
-#if 0
- NPPrint npprint;
- npprint.mode = NP_EMBED;
- npprint.print.embedPrint.platformPrint = reinterpret_cast<void*>(hdc);
- npprint.print.embedPrint.window = window_;
- instance()->NPP_Print(&npprint);
-#endif
-}
-
-void WebPluginDelegateImpl::InstallMissingPlugin() {
- NPEvent evt;
- evt.event = default_plugin::kInstallMissingPluginMessage;
- evt.lParam = 0;
- evt.wParam = 0;
- instance()->NPP_HandleEvent(&evt);
-}
-
-bool WebPluginDelegateImpl::WindowedCreatePlugin() {
- DCHECK(!windowed_handle_);
-
- RegisterNativeWindowClass();
-
- // The window will be sized and shown later.
- windowed_handle_ = CreateWindowEx(
- WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR,
- kNativeWindowClassName,
- 0,
- WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
- 0,
- 0,
- 0,
- 0,
- parent_,
- 0,
- GetModuleHandle(NULL),
- 0);
- if (windowed_handle_ == 0)
- return false;
-
- if (IsWindow(parent_)) {
- // This is a tricky workaround for Issue 2673 in chromium "Flash: IME not
- // available". To use IMEs in this window, we have to make Windows attach
- // IMEs to this window (i.e. load IME DLLs, attach them to this process,
- // and add their message hooks to this window). Windows attaches IMEs while
- // this process creates a top-level window. On the other hand, to layout
- // this window correctly in the given parent window (RenderWidgetHostHWND),
- // this window should be a child window of the parent window.
- // To satisfy both of the above conditions, this code once creates a
- // top-level window and change it to a child window of the parent window.
- SetWindowLongPtr(windowed_handle_, GWL_STYLE,
- WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
- SetParent(windowed_handle_, parent_);
- }
-
- BOOL result = SetProp(windowed_handle_, kWebPluginDelegateProperty, this);
- DCHECK(result == TRUE) << "SetProp failed, last error = " << GetLastError();
- // Get the name of the plugin, create an atom and set that in a window
- // property. Use an atom so that other processes can access the name of
- // the plugin that this window is hosting
- if (instance_ != NULL) {
- NPAPI::PluginLib* plugin_lib = instance()->plugin_lib();
- if (plugin_lib != NULL) {
- std::wstring plugin_name = plugin_lib->plugin_info().name;
- if (!plugin_name.empty()) {
- ATOM plugin_name_atom = GlobalAddAtomW(plugin_name.c_str());
- DCHECK(0 != plugin_name_atom);
- result = SetProp(windowed_handle_,
- kPluginNameAtomProperty,
- reinterpret_cast<HANDLE>(plugin_name_atom));
- DCHECK(result == TRUE) << "SetProp failed, last error = " <<
- GetLastError();
- }
- }
- }
-
- // Calling SetWindowLongPtrA here makes the window proc ASCII, which is
- // required by at least the Shockwave Director plug-in.
- SetWindowLongPtrA(
- windowed_handle_, GWL_WNDPROC, reinterpret_cast<LONG>(DefWindowProcA));
-
- return true;
-}
-
-void WebPluginDelegateImpl::WindowedDestroyWindow() {
- if (windowed_handle_ != NULL) {
- // Unsubclass the window.
- WNDPROC current_wnd_proc = reinterpret_cast<WNDPROC>(
- GetWindowLongPtr(windowed_handle_, GWLP_WNDPROC));
- if (current_wnd_proc == NativeWndProc) {
- SetWindowLongPtr(windowed_handle_,
- GWLP_WNDPROC,
- reinterpret_cast<LONG>(plugin_wnd_proc_));
- }
-
- plugin_->WillDestroyWindow(windowed_handle_);
-
- DestroyWindow(windowed_handle_);
- windowed_handle_ = 0;
- }
-}
-
-// Erase all messages in the queue destined for a particular window.
-// When windows are closing, callers should use this function to clear
-// the queue.
-// static
-void WebPluginDelegateImpl::ClearThrottleQueueForWindow(HWND window) {
- ThrottleQueue* throttle_queue = g_throttle_queue.Pointer();
-
- ThrottleQueue::iterator it;
- for (it = throttle_queue->begin(); it != throttle_queue->end(); ) {
- if (it->hwnd == window) {
- it = throttle_queue->erase(it);
- } else {
- it++;
- }
- }
-}
-
-// Delayed callback for processing throttled messages.
-// Throttled messages are aggregated globally across all plugins.
-// static
-void WebPluginDelegateImpl::OnThrottleMessage() {
- // The current algorithm walks the list and processes the first
- // message it finds for each plugin. It is important to service
- // all active plugins with each pass through the throttle, otherwise
- // we see video jankiness. Copy the set to notify before notifying
- // since we may re-enter OnThrottleMessage from CallWindowProc!
- ThrottleQueue* throttle_queue = g_throttle_queue.Pointer();
- ThrottleQueue notify_queue;
- std::set<HWND> processed;
-
- ThrottleQueue::iterator it = throttle_queue->begin();
- while (it != throttle_queue->end()) {
- const MSG& msg = *it;
- if (processed.find(msg.hwnd) == processed.end()) {
- processed.insert(msg.hwnd);
- notify_queue.push_back(msg);
- it = throttle_queue->erase(it);
- } else {
- it++;
- }
- }
-
- for (it = notify_queue.begin(); it != notify_queue.end(); ++it) {
- const MSG& msg = *it;
- WNDPROC proc = reinterpret_cast<WNDPROC>(msg.time);
- // It is possible that the window was closed after we queued
- // this message. This is a rare event; just verify the window
- // is alive. (see also bug 1259488)
- if (IsWindow(msg.hwnd))
- CallWindowProc(proc, msg.hwnd, msg.message, msg.wParam, msg.lParam);
- }
-
- if (!throttle_queue->empty()) {
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- NewRunnableFunction(&WebPluginDelegateImpl::OnThrottleMessage),
- kFlashWMUSERMessageThrottleDelayMs);
- }
-}
-
-// Schedule a windows message for delivery later.
-// static
-void WebPluginDelegateImpl::ThrottleMessage(WNDPROC proc, HWND hwnd,
- UINT message, WPARAM wParam,
- LPARAM lParam) {
- MSG msg;
- msg.time = reinterpret_cast<DWORD>(proc);
- msg.hwnd = hwnd;
- msg.message = message;
- msg.wParam = wParam;
- msg.lParam = lParam;
-
- ThrottleQueue* throttle_queue = g_throttle_queue.Pointer();
-
- throttle_queue->push_back(msg);
-
- if (throttle_queue->size() == 1) {
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- NewRunnableFunction(&WebPluginDelegateImpl::OnThrottleMessage),
- kFlashWMUSERMessageThrottleDelayMs);
- }
-}
-
-// We go out of our way to find the hidden windows created by Flash for
-// windowless plugins. We throttle the rate at which they deliver messages
-// so that they will not consume outrageous amounts of CPU.
-// static
-LRESULT CALLBACK WebPluginDelegateImpl::FlashWindowlessWndProc(HWND hwnd,
- UINT message, WPARAM wparam, LPARAM lparam) {
- std::map<HWND, WNDPROC>::iterator index =
- g_window_handle_proc_map.Get().find(hwnd);
-
- WNDPROC old_proc = (*index).second;
- DCHECK(old_proc);
-
- switch (message) {
- case WM_NCDESTROY: {
- WebPluginDelegateImpl::ClearThrottleQueueForWindow(hwnd);
- g_window_handle_proc_map.Get().erase(index);
- break;
- }
- // Flash may flood the message queue with WM_USER+1 message causing 100% CPU
- // usage. See https://bugzilla.mozilla.org/show_bug.cgi?id=132759. We
- // prevent this by throttling the messages.
- case WM_USER + 1: {
- WebPluginDelegateImpl::ThrottleMessage(old_proc, hwnd, message, wparam,
- lparam);
- return TRUE;
- }
- default: {
- break;
- }
- }
- return CallWindowProc(old_proc, hwnd, message, wparam, lparam);
-}
-
-// Callback for enumerating the Flash windows.
-BOOL CALLBACK EnumFlashWindows(HWND window, LPARAM arg) {
- WNDPROC wnd_proc = reinterpret_cast<WNDPROC>(arg);
- TCHAR class_name[1024];
- if (!RealGetWindowClass(window, class_name,
- sizeof(class_name)/sizeof(TCHAR))) {
- LOG(ERROR) << "RealGetWindowClass failure: " << GetLastError();
- return FALSE;
- }
-
- if (wcscmp(class_name, L"SWFlash_PlaceholderX"))
- return TRUE;
-
- WNDPROC current_wnd_proc = reinterpret_cast<WNDPROC>(
- GetWindowLongPtr(window, GWLP_WNDPROC));
- if (current_wnd_proc != wnd_proc) {
- WNDPROC old_flash_proc = reinterpret_cast<WNDPROC>(SetWindowLongPtr(
- window, GWLP_WNDPROC,
- reinterpret_cast<LONG>(wnd_proc)));
- DCHECK(old_flash_proc);
- g_window_handle_proc_map.Get()[window] = old_flash_proc;
- }
-
- return TRUE;
-}
-
-bool WebPluginDelegateImpl::CreateDummyWindowForActivation() {
- DCHECK(!dummy_window_for_activation_);
- dummy_window_for_activation_ = CreateWindowEx(
- 0,
- L"Static",
- kDummyActivationWindowName,
- WS_CHILD,
- 0,
- 0,
- 0,
- 0,
- parent_,
- 0,
- GetModuleHandle(NULL),
- 0);
-
- if (dummy_window_for_activation_ == 0)
- return false;
-
- // Flash creates background windows which use excessive CPU in our
- // environment; we wrap these windows and throttle them so that they don't
- // get out of hand.
- if (!EnumThreadWindows(::GetCurrentThreadId(), EnumFlashWindows,
- reinterpret_cast<LPARAM>(
- &WebPluginDelegateImpl::FlashWindowlessWndProc))) {
- // Log that this happened. Flash will still work; it just means the
- // throttle isn't installed (and Flash will use more CPU).
- NOTREACHED();
- LOG(ERROR) << "Failed to wrap all windowless Flash windows";
- }
- return true;
-}
-
-bool WebPluginDelegateImpl::WindowedReposition(
- const gfx::Rect& window_rect,
- const gfx::Rect& clip_rect) {
- if (!windowed_handle_) {
- NOTREACHED();
- return false;
- }
-
- if (window_rect_ == window_rect && clip_rect_ == clip_rect)
- return false;
-
- // We only set the plugin's size here. Its position is moved elsewhere, which
- // allows the window moves/scrolling/clipping to be synchronized with the page
- // and other windows.
- // If the plugin window has no parent, then don't focus it because it isn't
- // being displayed anywhere. See:
- // http://code.google.com/p/chromium/issues/detail?id=32658
- if (window_rect.size() != window_rect_.size()) {
- UINT flags = SWP_NOMOVE | SWP_NOZORDER;
- if (!GetParent(windowed_handle_))
- flags |= SWP_NOACTIVATE;
- ::SetWindowPos(windowed_handle_,
- NULL,
- 0,
- 0,
- window_rect.width(),
- window_rect.height(),
- flags);
- }
-
- window_rect_ = window_rect;
- clip_rect_ = clip_rect;
-
- // Ensure that the entire window gets repainted.
- ::InvalidateRect(windowed_handle_, NULL, FALSE);
-
- return true;
-}
-
-void WebPluginDelegateImpl::WindowedSetWindow() {
- if (!instance_)
- return;
-
- if (!windowed_handle_) {
- NOTREACHED();
- return;
- }
-
- instance()->set_window_handle(windowed_handle_);
-
- DCHECK(!instance()->windowless());
-
- window_.clipRect.top = std::max(0, clip_rect_.y());
- window_.clipRect.left = std::max(0, clip_rect_.x());
- window_.clipRect.bottom = std::max(0, clip_rect_.y() + clip_rect_.height());
- window_.clipRect.right = std::max(0, clip_rect_.x() + clip_rect_.width());
- window_.height = window_rect_.height();
- window_.width = window_rect_.width();
- window_.x = 0;
- window_.y = 0;
-
- window_.window = windowed_handle_;
- window_.type = NPWindowTypeWindow;
-
- // Reset this flag before entering the instance in case of side-effects.
- windowed_did_set_window_ = true;
-
- NPError err = instance()->NPP_SetWindow(&window_);
- if (quirks_ & PLUGIN_QUIRK_SETWINDOW_TWICE)
- instance()->NPP_SetWindow(&window_);
-
- WNDPROC current_wnd_proc = reinterpret_cast<WNDPROC>(
- GetWindowLongPtr(windowed_handle_, GWLP_WNDPROC));
- if (current_wnd_proc != NativeWndProc) {
- plugin_wnd_proc_ = reinterpret_cast<WNDPROC>(SetWindowLongPtr(
- windowed_handle_, GWLP_WNDPROC, reinterpret_cast<LONG>(NativeWndProc)));
- }
-}
-
-ATOM WebPluginDelegateImpl::RegisterNativeWindowClass() {
- static bool have_registered_window_class = false;
- if (have_registered_window_class == true)
- return true;
-
- have_registered_window_class = true;
-
- WNDCLASSEX wcex;
- wcex.cbSize = sizeof(WNDCLASSEX);
- wcex.style = CS_DBLCLKS;
- wcex.lpfnWndProc = DummyWindowProc;
- wcex.cbClsExtra = 0;
- wcex.cbWndExtra = 0;
- wcex.hInstance = GetModuleHandle(NULL);
- wcex.hIcon = 0;
- wcex.hCursor = 0;
- // Some plugins like windows media player 11 create child windows parented
- // by our plugin window, where the media content is rendered. These plugins
- // dont implement WM_ERASEBKGND, which causes painting issues, when the
- // window where the media is rendered is moved around. DefWindowProc does
- // implement WM_ERASEBKGND correctly if we have a valid background brush.
- wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW+1);
- wcex.lpszMenuName = 0;
- wcex.lpszClassName = kNativeWindowClassName;
- wcex.hIconSm = 0;
-
- return RegisterClassEx(&wcex);
-}
-
-LRESULT CALLBACK WebPluginDelegateImpl::DummyWindowProc(
- HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
- // This is another workaround for Issue 2673 in chromium "Flash: IME not
- // available". Somehow, the CallWindowProc() function does not dispatch
- // window messages when its first parameter is a handle representing the
- // DefWindowProc() function. To avoid this problem, this code creates a
- // wrapper function which just encapsulates the DefWindowProc() function
- // and set it as the window procedure of a windowed plug-in.
- return DefWindowProc(hWnd, message, wParam, lParam);
-}
-
-// Returns true if the message passed in corresponds to a user gesture.
-static bool IsUserGestureMessage(unsigned int message) {
- switch (message) {
- case WM_LBUTTONUP:
- case WM_RBUTTONUP:
- case WM_MBUTTONUP:
- case WM_KEYUP:
- return true;
-
- default:
- break;
- }
-
- return false;
-}
-
-LRESULT CALLBACK WebPluginDelegateImpl::NativeWndProc(
- HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
- WebPluginDelegateImpl* delegate = reinterpret_cast<WebPluginDelegateImpl*>(
- GetProp(hwnd, kWebPluginDelegateProperty));
- if (!delegate) {
- NOTREACHED();
- return 0;
- }
-
- if (message == delegate->last_message_ &&
- delegate->GetQuirks() & PLUGIN_QUIRK_DONT_CALL_WND_PROC_RECURSIVELY &&
- delegate->is_calling_wndproc) {
- // Real may go into a state where it recursively dispatches the same event
- // when subclassed. See https://bugzilla.mozilla.org/show_bug.cgi?id=192914
- // We only do the recursive check for Real because it's possible and valid
- // for a plugin to synchronously dispatch a message to itself such that it
- // looks like it's in recursion.
- return TRUE;
- }
-
- // Flash may flood the message queue with WM_USER+1 message causing 100% CPU
- // usage. See https://bugzilla.mozilla.org/show_bug.cgi?id=132759. We
- // prevent this by throttling the messages.
- if (message == WM_USER + 1 &&
- delegate->GetQuirks() & PLUGIN_QUIRK_THROTTLE_WM_USER_PLUS_ONE) {
- WebPluginDelegateImpl::ThrottleMessage(delegate->plugin_wnd_proc_, hwnd,
- message, wparam, lparam);
- return FALSE;
- }
-
- LRESULT result;
- uint32 old_message = delegate->last_message_;
- delegate->last_message_ = message;
-
- static UINT custom_msg = RegisterWindowMessage(kPaintMessageName);
- if (message == custom_msg) {
- // Get the invalid rect which is in screen coordinates and convert to
- // window coordinates.
- gfx::Rect invalid_rect;
- invalid_rect.set_x(wparam >> 16);
- invalid_rect.set_y(wparam & 0xFFFF);
- invalid_rect.set_width(lparam >> 16);
- invalid_rect.set_height(lparam & 0xFFFF);
-
- RECT window_rect;
- GetWindowRect(hwnd, &window_rect);
- invalid_rect.Offset(-window_rect.left, -window_rect.top);
-
- // The plugin window might have non-client area. If we don't pass in
- // RDW_FRAME then the children don't receive WM_NCPAINT messages while
- // scrolling, which causes painting problems (http://b/issue?id=923945).
- uint32 flags = RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_FRAME;
-
- // If a plugin (like Google Earth or Java) has child windows that are hosted
- // in a different process, then RedrawWindow with UPDATENOW will
- // synchronously wait for this call to complete. Some messages are pumped
- // but not others, which could lead to a deadlock. So avoid reentrancy by
- // only synchronously calling RedrawWindow once at a time.
- if (old_message != custom_msg)
- flags |= RDW_UPDATENOW;
-
- RedrawWindow(hwnd, &invalid_rect.ToRECT(), NULL, flags);
- result = FALSE;
- } else {
- delegate->is_calling_wndproc = true;
-
- if (!delegate->user_gesture_message_posted_ &&
- IsUserGestureMessage(message)) {
- delegate->user_gesture_message_posted_ = true;
-
- delegate->instance()->PushPopupsEnabledState(true);
-
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- delegate->user_gesture_msg_factory_.NewRunnableMethod(
- &WebPluginDelegateImpl::OnUserGestureEnd),
- kWindowedPluginPopupTimerMs);
- }
-
- HandleCaptureForMessage(hwnd, message);
-
- // Maintain a local/global stack for the g_current_plugin_instance variable
- // as this may be a nested invocation.
- WebPluginDelegateImpl* last_plugin_instance = g_current_plugin_instance;
-
- g_current_plugin_instance = delegate;
-
- result = CallWindowProc(
- delegate->plugin_wnd_proc_, hwnd, message, wparam, lparam);
-
- delegate->is_calling_wndproc = false;
- g_current_plugin_instance = last_plugin_instance;
-
- if (message == WM_NCDESTROY) {
- RemoveProp(hwnd, kWebPluginDelegateProperty);
- ATOM plugin_name_atom = reinterpret_cast<ATOM>(
- RemoveProp(hwnd, kPluginNameAtomProperty));
- if (plugin_name_atom != 0)
- GlobalDeleteAtom(plugin_name_atom);
- ClearThrottleQueueForWindow(hwnd);
- }
- }
- delegate->last_message_ = old_message;
- return result;
-}
-
-void WebPluginDelegateImpl::WindowlessUpdateGeometry(
- const gfx::Rect& window_rect,
- const gfx::Rect& clip_rect) {
- bool window_rect_changed = (window_rect_ != window_rect);
- // Only resend to the instance if the geometry has changed.
- if (!window_rect_changed && clip_rect == clip_rect_)
- return;
-
- clip_rect_ = clip_rect;
- window_rect_ = window_rect;
-
- WindowlessSetWindow();
-
- if (window_rect_changed) {
- WINDOWPOS win_pos = {0};
- win_pos.x = window_rect_.x();
- win_pos.y = window_rect_.y();
- win_pos.cx = window_rect_.width();
- win_pos.cy = window_rect_.height();
-
- NPEvent pos_changed_event;
- pos_changed_event.event = WM_WINDOWPOSCHANGED;
- pos_changed_event.wParam = 0;
- pos_changed_event.lParam = PtrToUlong(&win_pos);
-
- instance()->NPP_HandleEvent(&pos_changed_event);
- }
-}
-
-void WebPluginDelegateImpl::WindowlessPaint(HDC hdc,
- const gfx::Rect& damage_rect) {
- DCHECK(hdc);
-
- RECT damage_rect_win;
- damage_rect_win.left = damage_rect.x(); // + window_rect_.x();
- damage_rect_win.top = damage_rect.y(); // + window_rect_.y();
- damage_rect_win.right = damage_rect_win.left + damage_rect.width();
- damage_rect_win.bottom = damage_rect_win.top + damage_rect.height();
-
- // Save away the old HDC as this could be a nested invocation.
- void* old_dc = window_.window;
- window_.window = hdc;
-
- NPEvent paint_event;
- paint_event.event = WM_PAINT;
- // NOTE: NPAPI is not 64bit safe. It puts pointers into 32bit values.
- paint_event.wParam = PtrToUlong(hdc);
- paint_event.lParam = PtrToUlong(&damage_rect_win);
- static base::StatsRate plugin_paint("Plugin.Paint");
- base::StatsScope<base::StatsRate> scope(plugin_paint);
- instance()->NPP_HandleEvent(&paint_event);
- window_.window = old_dc;
-}
-
-void WebPluginDelegateImpl::WindowlessSetWindow() {
- if (!instance())
- return;
-
- if (window_rect_.IsEmpty()) // wait for geometry to be set.
- return;
-
- DCHECK(instance()->windowless());
-
- window_.clipRect.top = clip_rect_.y();
- window_.clipRect.left = clip_rect_.x();
- window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height();
- window_.clipRect.right = clip_rect_.x() + clip_rect_.width();
- window_.height = window_rect_.height();
- window_.width = window_rect_.width();
- window_.x = window_rect_.x();
- window_.y = window_rect_.y();
- window_.type = NPWindowTypeDrawable;
- DrawableContextEnforcer enforcer(&window_);
-
- NPError err = instance()->NPP_SetWindow(&window_);
- DCHECK(err == NPERR_NO_ERROR);
-}
-
-bool WebPluginDelegateImpl::PlatformSetPluginHasFocus(bool focused) {
- DCHECK(instance()->windowless());
-
- NPEvent focus_event;
- focus_event.event = focused ? WM_SETFOCUS : WM_KILLFOCUS;
- focus_event.wParam = 0;
- focus_event.lParam = 0;
-
- instance()->NPP_HandleEvent(&focus_event);
- return true;
-}
-
-static bool NPEventFromWebMouseEvent(const WebMouseEvent& event,
- NPEvent *np_event) {
- np_event->lParam = static_cast<uint32>(MAKELPARAM(event.windowX,
- event.windowY));
- np_event->wParam = 0;
-
- if (event.modifiers & WebInputEvent::ControlKey)
- np_event->wParam |= MK_CONTROL;
- if (event.modifiers & WebInputEvent::ShiftKey)
- np_event->wParam |= MK_SHIFT;
- if (event.modifiers & WebInputEvent::LeftButtonDown)
- np_event->wParam |= MK_LBUTTON;
- if (event.modifiers & WebInputEvent::MiddleButtonDown)
- np_event->wParam |= MK_MBUTTON;
- if (event.modifiers & WebInputEvent::RightButtonDown)
- np_event->wParam |= MK_RBUTTON;
-
- switch (event.type) {
- case WebInputEvent::MouseMove:
- case WebInputEvent::MouseLeave:
- case WebInputEvent::MouseEnter:
- np_event->event = WM_MOUSEMOVE;
- return true;
- case WebInputEvent::MouseDown:
- switch (event.button) {
- case WebMouseEvent::ButtonLeft:
- np_event->event = WM_LBUTTONDOWN;
- break;
- case WebMouseEvent::ButtonMiddle:
- np_event->event = WM_MBUTTONDOWN;
- break;
- case WebMouseEvent::ButtonRight:
- np_event->event = WM_RBUTTONDOWN;
- break;
- }
- return true;
- case WebInputEvent::MouseUp:
- switch (event.button) {
- case WebMouseEvent::ButtonLeft:
- np_event->event = WM_LBUTTONUP;
- break;
- case WebMouseEvent::ButtonMiddle:
- np_event->event = WM_MBUTTONUP;
- break;
- case WebMouseEvent::ButtonRight:
- np_event->event = WM_RBUTTONUP;
- break;
- }
- return true;
- default:
- NOTREACHED();
- return false;
- }
-}
-
-static bool NPEventFromWebKeyboardEvent(const WebKeyboardEvent& event,
- NPEvent *np_event) {
- np_event->wParam = event.windowsKeyCode;
-
- switch (event.type) {
- case WebInputEvent::KeyDown:
- np_event->event = WM_KEYDOWN;
- np_event->lParam = 0;
- return true;
- case WebInputEvent::Char:
- np_event->event = WM_CHAR;
- np_event->lParam = 0;
- return true;
- case WebInputEvent::KeyUp:
- np_event->event = WM_KEYUP;
- np_event->lParam = 0x8000;
- return true;
- default:
- NOTREACHED();
- return false;
- }
-}
-
-static bool NPEventFromWebInputEvent(const WebInputEvent& event,
- NPEvent* np_event) {
- switch (event.type) {
- case WebInputEvent::MouseMove:
- case WebInputEvent::MouseLeave:
- case WebInputEvent::MouseEnter:
- case WebInputEvent::MouseDown:
- case WebInputEvent::MouseUp:
- if (event.size < sizeof(WebMouseEvent)) {
- NOTREACHED();
- return false;
- }
- return NPEventFromWebMouseEvent(
- *static_cast<const WebMouseEvent*>(&event), np_event);
- case WebInputEvent::KeyDown:
- case WebInputEvent::Char:
- case WebInputEvent::KeyUp:
- if (event.size < sizeof(WebKeyboardEvent)) {
- NOTREACHED();
- return false;
- }
- return NPEventFromWebKeyboardEvent(
- *static_cast<const WebKeyboardEvent*>(&event), np_event);
- default:
- return false;
- }
-}
-
-bool WebPluginDelegateImpl::PlatformHandleInputEvent(
- const WebInputEvent& event, WebCursorInfo* cursor_info) {
- DCHECK(cursor_info != NULL);
-
- NPEvent np_event;
- if (!NPEventFromWebInputEvent(event, &np_event)) {
- return false;
- }
-
- // Synchronize the keyboard layout with the one of the browser process. Flash
- // uses the keyboard layout of this window to verify a WM_CHAR message is
- // valid. That is, Flash discards a WM_CHAR message unless its character is
- // the one translated with ToUnicode(). (Since a plug-in is running on a
- // separate process from the browser process, we need to syncronize it
- // manually.)
- if (np_event.event == WM_CHAR) {
- if (!keyboard_layout_)
- keyboard_layout_ = GetKeyboardLayout(GetCurrentThreadId());
- if (!parent_thread_id_)
- parent_thread_id_ = GetWindowThreadProcessId(parent_, NULL);
- HKL parent_layout = GetKeyboardLayout(parent_thread_id_);
- if (keyboard_layout_ != parent_layout) {
- std::wstring layout_name(base::StringPrintf(L"%08x", parent_layout));
- LoadKeyboardLayout(layout_name.c_str(), KLF_ACTIVATE);
- keyboard_layout_ = parent_layout;
- }
- }
-
- if (ShouldTrackEventForModalLoops(&np_event)) {
- // A windowless plugin can enter a modal loop in a NPP_HandleEvent call.
- // For e.g. Flash puts up a context menu when we right click on the
- // windowless plugin area. We detect this by setting up a message filter
- // hook pror to calling NPP_HandleEvent on the plugin and unhook on
- // return from NPP_HandleEvent. If the plugin does enter a modal loop
- // in that context we unhook on receiving the first notification in
- // the message filter hook.
- handle_event_message_filter_hook_ =
- SetWindowsHookEx(WH_MSGFILTER, HandleEventMessageFilterHook, NULL,
- GetCurrentThreadId());
- }
-
- bool old_task_reentrancy_state =
- MessageLoop::current()->NestableTasksAllowed();
-
-
- // Maintain a local/global stack for the g_current_plugin_instance variable
- // as this may be a nested invocation.
- WebPluginDelegateImpl* last_plugin_instance = g_current_plugin_instance;
-
- g_current_plugin_instance = this;
-
- handle_event_depth_++;
-
- bool ret = instance()->NPP_HandleEvent(&np_event) != 0;
-
- // Flash and SilverLight always return false, even when they swallow the
- // event. Flash does this because it passes the event to its window proc,
- // which is supposed to return 0 if an event was handled. There are few
- // exceptions, such as IME, where it sometimes returns true.
- ret = true;
-
- if (np_event.event == WM_MOUSEMOVE) {
- // Snag a reference to the current cursor ASAP in case the plugin modified
- // it. There is a nasty race condition here with the multiprocess browser
- // as someone might be setting the cursor in the main process as well.
- current_windowless_cursor_.GetCursorInfo(cursor_info);
- }
-
- handle_event_depth_--;
-
- g_current_plugin_instance = last_plugin_instance;
-
- MessageLoop::current()->SetNestableTasksAllowed(old_task_reentrancy_state);
-
- // We could have multiple NPP_HandleEvent calls nested together in case
- // the plugin enters a modal loop. Reset the pump messages event when
- // the outermost NPP_HandleEvent call unwinds.
- if (handle_event_depth_ == 0) {
- ResetEvent(handle_event_pump_messages_event_);
- }
-
- return ret;
-}
-
-
-void WebPluginDelegateImpl::OnModalLoopEntered() {
- DCHECK(handle_event_pump_messages_event_ != NULL);
- SetEvent(handle_event_pump_messages_event_);
-
- MessageLoop::current()->SetNestableTasksAllowed(true);
-
- UnhookWindowsHookEx(handle_event_message_filter_hook_);
- handle_event_message_filter_hook_ = NULL;
-}
-
-bool WebPluginDelegateImpl::ShouldTrackEventForModalLoops(NPEvent* event) {
- if (event->event == WM_RBUTTONDOWN)
- return true;
- return false;
-}
-
-void WebPluginDelegateImpl::OnUserGestureEnd() {
- user_gesture_message_posted_ = false;
- instance()->PopPopupsEnabledState();
-}
-
-BOOL WINAPI WebPluginDelegateImpl::TrackPopupMenuPatch(
- HMENU menu, unsigned int flags, int x, int y, int reserved,
- HWND window, const RECT* rect) {
-
- HWND last_focus_window = NULL;
-
- if (g_current_plugin_instance) {
- unsigned long window_process_id = 0;
- unsigned long window_thread_id =
- GetWindowThreadProcessId(window, &window_process_id);
- // TrackPopupMenu fails if the window passed in belongs to a different
- // thread.
- if (::GetCurrentThreadId() != window_thread_id) {
- window = g_current_plugin_instance->dummy_window_for_activation_;
- }
-
- // To ensure that the plugin receives keyboard events we set focus to the
- // dummy window.
- // TODO(iyengar) We need a framework in the renderer to identify which
- // windowless plugin is under the mouse and to handle this. This would
- // also require some changes in RenderWidgetHost to detect this in the
- // WM_MOUSEACTIVATE handler and inform the renderer accordingly.
- if (g_current_plugin_instance->dummy_window_for_activation_) {
- last_focus_window =
- ::SetFocus(g_current_plugin_instance->dummy_window_for_activation_);
- }
- }
-
- BOOL result = TrackPopupMenu(menu, flags, x, y, reserved, window, rect);
-
- if (IsWindow(last_focus_window)) {
- // The Flash plugin at times sets focus to its hidden top level window
- // with class name SWFlash_PlaceholderX. This causes the chrome browser
- // window to receive a WM_ACTIVATEAPP message as a top level window from
- // another thread is now active. We end up in a state where the chrome
- // browser window is not active even though the user clicked on it.
- // Our workaround for this is to send over a raw
- // WM_LBUTTONDOWN/WM_LBUTTONUP combination to the last focus window, which
- // does the trick.
- if (g_current_plugin_instance->dummy_window_for_activation_ !=
- ::GetFocus()) {
- INPUT input_info = {0};
- input_info.type = INPUT_MOUSE;
- input_info.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
- ::SendInput(1, &input_info, sizeof(INPUT));
-
- input_info.type = INPUT_MOUSE;
- input_info.mi.dwFlags = MOUSEEVENTF_LEFTUP;
- ::SendInput(1, &input_info, sizeof(INPUT));
- } else {
- ::SetFocus(last_focus_window);
- }
- }
-
- return result;
-}
-
-HCURSOR WINAPI WebPluginDelegateImpl::SetCursorPatch(HCURSOR cursor) {
- // The windowless flash plugin periodically calls SetCursor in a wndproc
- // instantiated on the plugin thread. This causes annoying cursor flicker
- // when the mouse is moved on a foreground tab, with a windowless plugin
- // instance in a background tab. We just ignore the call here.
- if (!g_current_plugin_instance) {
- HCURSOR current_cursor = GetCursor();
- if (current_cursor != cursor) {
- ::SetCursor(cursor);
- }
- return current_cursor;
- }
-
- if (!g_current_plugin_instance->IsWindowless()) {
- return ::SetCursor(cursor);
- }
-
- // It is ok to pass NULL here to GetCursor as we are not looking for cursor
- // types defined by Webkit.
- HCURSOR previous_cursor =
- g_current_plugin_instance->current_windowless_cursor_.GetCursor(NULL);
-
- g_current_plugin_instance->current_windowless_cursor_.InitFromExternalCursor(
- cursor);
- return previous_cursor;
-}
-
-LONG WINAPI WebPluginDelegateImpl::RegEnumKeyExWPatch(
- HKEY key, DWORD index, LPWSTR name, LPDWORD name_size, LPDWORD reserved,
- LPWSTR class_name, LPDWORD class_size, PFILETIME last_write_time) {
- DWORD orig_size = *name_size;
- LONG rv = RegEnumKeyExW(key, index, name, name_size, reserved, class_name,
- class_size, last_write_time);
- if (rv == ERROR_SUCCESS &&
- GetKeyPath(key).find(L"Microsoft\\MediaPlayer\\ShimInclusionList") !=
- std::wstring::npos) {
- static const wchar_t kChromeExeName[] = L"chrome.exe";
- wcsncpy_s(name, orig_size, kChromeExeName, arraysize(kChromeExeName));
- *name_size =
- std::min(orig_size, static_cast<DWORD>(arraysize(kChromeExeName)));
- }
-
- return rv;
-}
-
-void WebPluginDelegateImpl::HandleCaptureForMessage(HWND window,
- UINT message) {
- if (!WebPluginDelegateImpl::IsPluginDelegateWindow(window))
- return;
-
- switch (message) {
- case WM_LBUTTONDOWN:
- case WM_MBUTTONDOWN:
- case WM_RBUTTONDOWN:
- ::SetCapture(window);
- break;
-
- case WM_LBUTTONUP:
- case WM_MBUTTONUP:
- case WM_RBUTTONUP:
- ::ReleaseCapture();
- break;
-
- default:
- break;
- }
-}
diff --git a/webkit/glue/plugins/webplugin_file_delegate.h b/webkit/glue/plugins/webplugin_file_delegate.h
deleted file mode 100644
index 162516c..0000000
--- a/webkit/glue/plugins/webplugin_file_delegate.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_WEBPLUGIN_FILE_DELEGATE_H_
-#define WEBKIT_GLUE_PLUGINS_WEBPLUGIN_FILE_DELEGATE_H_
-
-#include "base/basictypes.h"
-#include "third_party/npapi/bindings/npapi_extensions.h"
-
-namespace webkit_glue {
-
-// Interface for the NPAPI file extensions. This class implements "NOP"
-// versions of all these functions so it can be used seamlessly by the
-// "regular" plugin delegate while being overridden by the "pepper" one.
-class WebPluginFileDelegate {
- public:
- // See NPChooseFilePtr in npapi_extensions.h. Returns true on success, on
- // cancel, returns true but *filename will be filled with an empty FilePath
- // and *handle will be 0.
- virtual bool ChooseFile(const char* mime_types,
- int mode,
- NPChooseFileCallback callback,
- void* user_data) {
- return false;
- }
-
- protected:
- WebPluginFileDelegate() {}
- virtual ~WebPluginFileDelegate() {}
-};
-
-} // namespace webkit_glue
-
-#endif // WEBKIT_GLUE_PLUGINS_WEBPLUGIN_FILE_DELEGATE_H_
diff --git a/webkit/glue/plugins/webplugin_impl.cc b/webkit/glue/plugins/webplugin_impl.cc
deleted file mode 100644
index cd91744..0000000
--- a/webkit/glue/plugins/webplugin_impl.cc
+++ /dev/null
@@ -1,1379 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/webplugin_impl.h"
-
-#include "base/linked_ptr.h"
-#include "base/logging.h"
-#include "base/message_loop.h"
-#include "base/string_util.h"
-#include "base/stringprintf.h"
-#include "base/utf_string_conversions.h"
-#include "gfx/rect.h"
-#include "googleurl/src/gurl.h"
-#include "net/base/escape.h"
-#include "net/base/net_errors.h"
-#include "net/http/http_response_headers.h"
-#include "skia/ext/platform_canvas.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebConsoleMessage.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebCookieJar.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebCString.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebCursorInfo.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebDevToolsAgent.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebData.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebDocument.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebHTTPBody.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebHTTPHeaderVisitor.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebKit.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebKitClient.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebPluginContainer.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebPluginParams.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebURL.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebURLError.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebURLLoader.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebURLLoaderClient.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebURLResponse.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebView.h"
-#include "webkit/appcache/web_application_cache_host_impl.h"
-#include "webkit/glue/multipart_response_delegate.h"
-#include "webkit/glue/plugins/plugin_host.h"
-#include "webkit/glue/plugins/plugin_instance.h"
-#include "webkit/glue/plugins/webplugin_delegate.h"
-#include "webkit/glue/plugins/webplugin_page_delegate.h"
-
-using appcache::WebApplicationCacheHostImpl;
-using WebKit::WebCanvas;
-using WebKit::WebConsoleMessage;
-using WebKit::WebCookieJar;
-using WebKit::WebCString;
-using WebKit::WebCursorInfo;
-using WebKit::WebData;
-using WebKit::WebDataSource;
-using WebKit::WebDevToolsAgent;
-using WebKit::WebFrame;
-using WebKit::WebHTTPBody;
-using WebKit::WebHTTPHeaderVisitor;
-using WebKit::WebInputEvent;
-using WebKit::WebKeyboardEvent;
-using WebKit::WebMouseEvent;
-using WebKit::WebPluginContainer;
-using WebKit::WebPluginParams;
-using WebKit::WebRect;
-using WebKit::WebString;
-using WebKit::WebURL;
-using WebKit::WebURLError;
-using WebKit::WebURLLoader;
-using WebKit::WebURLLoaderClient;
-using WebKit::WebURLRequest;
-using WebKit::WebURLResponse;
-using WebKit::WebVector;
-using WebKit::WebView;
-using webkit_glue::MultipartResponseDelegate;
-
-namespace webkit_glue {
-namespace {
-
-// This class handles individual multipart responses. It is instantiated when
-// we receive HTTP status code 206 in the HTTP response. This indicates
-// that the response could have multiple parts each separated by a boundary
-// specified in the response header.
-class MultiPartResponseClient : public WebURLLoaderClient {
- public:
- explicit MultiPartResponseClient(WebPluginResourceClient* resource_client)
- : resource_client_(resource_client) {
- Clear();
- }
-
- virtual void willSendRequest(
- WebURLLoader*, WebURLRequest&, const WebURLResponse&) {}
- virtual void didSendData(
- WebURLLoader*, unsigned long long, unsigned long long) {}
-
- // Called when the multipart parser encounters an embedded multipart
- // response.
- virtual void didReceiveResponse(
- WebURLLoader*, const WebURLResponse& response) {
- if (!MultipartResponseDelegate::ReadContentRanges(
- response,
- &byte_range_lower_bound_,
- &byte_range_upper_bound_)) {
- NOTREACHED();
- return;
- }
-
- resource_response_ = response;
- }
-
- // Receives individual part data from a multipart response.
- virtual void didReceiveData(
- WebURLLoader*, const char* data, int data_size) {
- // TODO(ananta)
- // We should defer further loads on multipart resources on the same lines
- // as regular resources requested by plugins to prevent reentrancy.
- resource_client_->DidReceiveData(
- data, data_size, byte_range_lower_bound_);
- byte_range_lower_bound_ += data_size;
- }
-
- virtual void didFinishLoading(WebURLLoader*, double finishTime) {}
- virtual void didFail(WebURLLoader*, const WebURLError&) {}
-
- void Clear() {
- resource_response_.reset();
- byte_range_lower_bound_ = 0;
- byte_range_upper_bound_ = 0;
- }
-
- private:
- WebURLResponse resource_response_;
- // The lower bound of the byte range.
- int byte_range_lower_bound_;
- // The upper bound of the byte range.
- int byte_range_upper_bound_;
- // The handler for the data.
- WebPluginResourceClient* resource_client_;
-};
-
-class HeaderFlattener : public WebHTTPHeaderVisitor {
- public:
- HeaderFlattener(std::string* buf) : buf_(buf) {
- }
-
- virtual void visitHeader(const WebString& name, const WebString& value) {
- // TODO(darin): Should we really exclude headers with an empty value?
- if (!name.isEmpty() && !value.isEmpty()) {
- buf_->append(name.utf8());
- buf_->append(": ");
- buf_->append(value.utf8());
- buf_->append("\n");
- }
- }
-
- private:
- std::string* buf_;
-};
-
-std::string GetAllHeaders(const WebURLResponse& response) {
- // TODO(darin): It is possible for httpStatusText to be empty and still have
- // an interesting response, so this check seems wrong.
- std::string result;
- const WebString& status = response.httpStatusText();
- if (status.isEmpty())
- return result;
-
- // TODO(darin): Shouldn't we also report HTTP version numbers?
- result = base::StringPrintf("HTTP %d ", response.httpStatusCode());
- result.append(status.utf8());
- result.append("\n");
-
- HeaderFlattener flattener(&result);
- response.visitHTTPHeaderFields(&flattener);
-
- return result;
-}
-
-struct ResponseInfo {
- GURL url;
- std::string mime_type;
- uint32 last_modified;
- uint32 expected_length;
-};
-
-void GetResponseInfo(const WebURLResponse& response,
- ResponseInfo* response_info) {
- response_info->url = response.url();
- response_info->mime_type = response.mimeType().utf8();
-
- // Measured in seconds since 12:00 midnight GMT, January 1, 1970.
- response_info->last_modified =
- static_cast<uint32>(response.lastModifiedDate());
-
- // If the length comes in as -1, then it indicates that it was not
- // read off the HTTP headers. We replicate Safari webkit behavior here,
- // which is to set it to 0.
- response_info->expected_length =
- static_cast<uint32>(std::max(response.expectedContentLength(), 0LL));
-
- WebString content_encoding =
- response.httpHeaderField(WebString::fromUTF8("Content-Encoding"));
- if (!content_encoding.isNull() &&
- !EqualsASCII(content_encoding, "identity")) {
- // Don't send the compressed content length to the plugin, which only
- // cares about the decoded length.
- response_info->expected_length = 0;
- }
-}
-
-} // namespace
-
-// WebKit::WebPlugin ----------------------------------------------------------
-
-struct WebPluginImpl::ClientInfo {
- unsigned long id;
- WebPluginResourceClient* client;
- WebKit::WebURLRequest request;
- bool pending_failure_notification;
- linked_ptr<WebKit::WebURLLoader> loader;
- bool notify_redirects;
-};
-
-bool WebPluginImpl::initialize(WebPluginContainer* container) {
- if (!page_delegate_)
- return false;
-
- WebPluginDelegate* plugin_delegate = page_delegate_->CreatePluginDelegate(
- file_path_, mime_type_);
- if (!plugin_delegate)
- return false;
-
- // Set the container before Initialize because the plugin may
- // synchronously call NPN_GetValue to get its container during its
- // initialization.
- SetContainer(container);
- bool ok = plugin_delegate->Initialize(
- plugin_url_, arg_names_, arg_values_, this, load_manually_);
- if (!ok) {
- plugin_delegate->PluginDestroyed();
- return false;
- }
-
- delegate_ = plugin_delegate;
-
- return true;
-}
-
-void WebPluginImpl::destroy() {
- SetContainer(NULL);
- MessageLoop::current()->DeleteSoon(FROM_HERE, this);
-}
-
-NPObject* WebPluginImpl::scriptableObject() {
- return delegate_->GetPluginScriptableObject();
-}
-
-void WebPluginImpl::paint(WebCanvas* canvas, const WebRect& paint_rect) {
- if (!delegate_ || !container_)
- return;
-
-#if defined(OS_WIN)
- // Force a geometry update if needed to allow plugins like media player
- // which defer the initial geometry update to work.
- container_->reportGeometry();
-#endif // OS_WIN
-
- // Note that |canvas| is only used when in windowless mode.
- delegate_->Paint(canvas, paint_rect);
-}
-
-void WebPluginImpl::updateGeometry(
- const WebRect& window_rect, const WebRect& clip_rect,
- const WebVector<WebRect>& cutout_rects, bool is_visible) {
- WebPluginGeometry new_geometry;
- new_geometry.window = window_;
- new_geometry.window_rect = window_rect;
- new_geometry.clip_rect = clip_rect;
- new_geometry.visible = is_visible;
- new_geometry.rects_valid = true;
- for (size_t i = 0; i < cutout_rects.size(); ++i)
- new_geometry.cutout_rects.push_back(cutout_rects[i]);
-
- // Only send DidMovePlugin if the geometry changed in some way.
- if (window_ &&
- page_delegate_ &&
- (first_geometry_update_ || !new_geometry.Equals(geometry_))) {
- page_delegate_->DidMovePlugin(new_geometry);
- }
-
- // Only UpdateGeometry if either the window or clip rects have changed.
- if (first_geometry_update_ ||
- new_geometry.window_rect != geometry_.window_rect ||
- new_geometry.clip_rect != geometry_.clip_rect) {
- // Notify the plugin that its parameters have changed.
- delegate_->UpdateGeometry(new_geometry.window_rect, new_geometry.clip_rect);
- }
-
- // Initiate a download on the plugin url. This should be done for the
- // first update geometry sequence. We need to ensure that the plugin
- // receives the geometry update before it starts receiving data.
- if (first_geometry_update_) {
- // An empty url corresponds to an EMBED tag with no src attribute.
- if (!load_manually_ && plugin_url_.is_valid()) {
- // The Flash plugin hangs for a while if it receives data before
- // receiving valid plugin geometry. By valid geometry we mean the
- // geometry received by a call to setFrameRect in the Webkit
- // layout code path. To workaround this issue we download the
- // plugin source url on a timer.
- MessageLoop::current()->PostDelayedTask(
- FROM_HERE, method_factory_.NewRunnableMethod(
- &WebPluginImpl::OnDownloadPluginSrcUrl), 0);
- }
- }
-
-#if defined(OS_WIN)
- // Don't cache the geometry during the first geometry update. The first
- // geometry update sequence is received when Widget::setParent is called.
- // For plugins like media player which have a bug where they only honor
- // the first geometry update, we have a quirk which ignores the first
- // geometry update. To ensure that these plugins work correctly in cases
- // where we receive only one geometry update from webkit, we also force
- // a geometry update during paint which should go out correctly as the
- // initial geometry update was not cached.
- if (!first_geometry_update_)
- geometry_ = new_geometry;
-#else // OS_WIN
- geometry_ = new_geometry;
-#endif // OS_WIN
- first_geometry_update_ = false;
-}
-
-unsigned WebPluginImpl::getBackingTextureId() {
- // Regular plugins do not have a backing texture.
- return 0;
-}
-
-void WebPluginImpl::updateFocus(bool focused) {
- if (accepts_input_events_)
- delegate_->SetFocus(focused);
-}
-
-void WebPluginImpl::updateVisibility(bool visible) {
- if (!window_ || !page_delegate_)
- return;
-
- WebPluginGeometry move;
- move.window = window_;
- move.window_rect = gfx::Rect();
- move.clip_rect = gfx::Rect();
- move.rects_valid = false;
- move.visible = visible;
-
- page_delegate_->DidMovePlugin(move);
-}
-
-bool WebPluginImpl::acceptsInputEvents() {
- return accepts_input_events_;
-}
-
-bool WebPluginImpl::handleInputEvent(
- const WebInputEvent& event, WebCursorInfo& cursor_info) {
- // Swallow context menu events in order to suppress the default context menu.
- if (event.type == WebInputEvent::ContextMenu)
- return true;
-
- return delegate_->HandleInputEvent(event, &cursor_info);
-}
-
-void WebPluginImpl::didReceiveResponse(const WebURLResponse& response) {
- ignore_response_error_ = false;
-
- ResponseInfo response_info;
- GetResponseInfo(response, &response_info);
-
- delegate_->DidReceiveManualResponse(
- response_info.url,
- response_info.mime_type,
- GetAllHeaders(response),
- response_info.expected_length,
- response_info.last_modified);
-}
-
-void WebPluginImpl::didReceiveData(const char* data, int data_length) {
- delegate_->DidReceiveManualData(data, data_length);
-}
-
-void WebPluginImpl::didFinishLoading() {
- delegate_->DidFinishManualLoading();
-}
-
-void WebPluginImpl::didFailLoading(const WebURLError& error) {
- if (!ignore_response_error_)
- delegate_->DidManualLoadFail();
-}
-
-void WebPluginImpl::didFinishLoadingFrameRequest(
- const WebURL& url, void* notify_data) {
- if (delegate_) {
- // We're converting a void* into an arbitrary int id. Though
- // these types are the same size on all the platforms we support,
- // the compiler may complain as though they are different, so to
- // make the casting gods happy go through an intptr_t (the union
- // of void* and int) rather than converting straight across.
- delegate_->DidFinishLoadWithReason(
- url, NPRES_DONE, reinterpret_cast<intptr_t>(notify_data));
- }
-}
-
-void WebPluginImpl::didFailLoadingFrameRequest(
- const WebURL& url, void* notify_data, const WebURLError& error) {
- if (!delegate_)
- return;
-
- NPReason reason =
- error.reason == net::ERR_ABORTED ? NPRES_USER_BREAK : NPRES_NETWORK_ERR;
- // See comment in didFinishLoadingFrameRequest about the cast here.
- delegate_->DidFinishLoadWithReason(
- url, reason, reinterpret_cast<intptr_t>(notify_data));
-}
-
-bool WebPluginImpl::supportsPaginatedPrint() {
- if (!delegate_)
- return false;
- return delegate_->PrintSupportsPrintExtension();
-}
-
-int WebPluginImpl::printBegin(const WebRect& printable_area, int printer_dpi) {
- if (!delegate_)
- return 0;
-
- if (!supportsPaginatedPrint())
- return 0;
-
- return delegate_->PrintBegin(printable_area, printer_dpi);
-}
-
-bool WebPluginImpl::printPage(int page_number, WebCanvas* canvas) {
- if (!delegate_)
- return false;
-
- return delegate_->PrintPage(page_number, canvas);
-}
-
-void WebPluginImpl::printEnd() {
- if (delegate_)
- delegate_->PrintEnd();
-}
-
-bool WebPluginImpl::hasSelection() const {
- if (!delegate_)
- return false;
-
- return delegate_->HasSelection();
-}
-
-WebKit::WebString WebPluginImpl::selectionAsText() const {
- if (!delegate_)
- return WebString();
-
- return delegate_->GetSelectionAsText();
-}
-
-WebKit::WebString WebPluginImpl::selectionAsMarkup() const {
- if (!delegate_)
- return WebString();
-
- return delegate_->GetSelectionAsMarkup();
-}
-
-void WebPluginImpl::setZoomFactor(float scale, bool text_only) {
- if (delegate_)
- delegate_->SetZoomFactor(scale, text_only);
-}
-
-bool WebPluginImpl::startFind(const WebKit::WebString& search_text,
- bool case_sensitive,
- int identifier) {
- if (!delegate_)
- return false;
- return delegate_->StartFind(search_text, case_sensitive, identifier);
-}
-
-void WebPluginImpl::selectFindResult(bool forward) {
- if (delegate_)
- delegate_->SelectFindResult(forward);
-}
-
-void WebPluginImpl::stopFind() {
- if (delegate_)
- delegate_->StopFind();
-}
-
-
-// -----------------------------------------------------------------------------
-
-WebPluginImpl::WebPluginImpl(
- WebFrame* webframe,
- const WebPluginParams& params,
- const FilePath& file_path,
- const std::string& mime_type,
- const base::WeakPtr<WebPluginPageDelegate>& page_delegate)
- : windowless_(false),
- window_(gfx::kNullPluginWindow),
- accepts_input_events_(false),
- page_delegate_(page_delegate),
- webframe_(webframe),
- delegate_(NULL),
- container_(NULL),
- plugin_url_(params.url),
- load_manually_(params.loadManually),
- first_geometry_update_(true),
- ignore_response_error_(false),
- file_path_(file_path),
- mime_type_(mime_type),
- ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
- DCHECK_EQ(params.attributeNames.size(), params.attributeValues.size());
- StringToLowerASCII(&mime_type_);
-
- for (size_t i = 0; i < params.attributeNames.size(); ++i) {
- arg_names_.push_back(params.attributeNames[i].utf8());
- arg_values_.push_back(params.attributeValues[i].utf8());
- }
-}
-
-WebPluginImpl::~WebPluginImpl() {
-}
-
-void WebPluginImpl::SetWindow(gfx::PluginWindowHandle window) {
-#if defined(OS_MACOSX)
- // The only time this is called twice, and the second time with a
- // non-zero PluginWindowHandle, is the case when this WebPluginImpl
- // is created on behalf of the GPU plugin. This entire code path
- // will go away soon, as soon as the GPU plugin becomes the GPU
- // process, so it is being separated out for easy deletion.
-
- // The logic we want here is: if (window) DCHECK(!window_);
- DCHECK(!(window_ && window));
- window_ = window;
- // Lie to ourselves about being windowless even if we got a fake
- // plugin window handle, so we continue to get input events.
- windowless_ = true;
- accepts_input_events_ = true;
- // We do not really need to notify the page delegate that a plugin
- // window was created -- so don't.
-#else
- if (window) {
- DCHECK(!windowless_);
- window_ = window;
- accepts_input_events_ = false;
- if (page_delegate_) {
- // Tell the view delegate that the plugin window was created, so that it
- // can create necessary container widgets.
- page_delegate_->CreatedPluginWindow(window);
- }
- } else {
- DCHECK(!window_); // Make sure not called twice.
- windowless_ = true;
- accepts_input_events_ = true;
- }
-#endif
-}
-
-void WebPluginImpl::WillDestroyWindow(gfx::PluginWindowHandle window) {
- DCHECK_EQ(window, window_);
- window_ = gfx::kNullPluginWindow;
- if (page_delegate_)
- page_delegate_->WillDestroyPluginWindow(window);
-}
-
-GURL WebPluginImpl::CompleteURL(const char* url) {
- if (!webframe_) {
- NOTREACHED();
- return GURL();
- }
- // TODO(darin): Is conversion from UTF8 correct here?
- return webframe_->document().completeURL(WebString::fromUTF8(url));
-}
-
-void WebPluginImpl::CancelResource(unsigned long id) {
- for (size_t i = 0; i < clients_.size(); ++i) {
- if (clients_[i].id == id) {
- if (clients_[i].loader.get()) {
- clients_[i].loader->setDefersLoading(false);
- clients_[i].loader->cancel();
- RemoveClient(i);
- }
- return;
- }
- }
-}
-
-bool WebPluginImpl::SetPostData(WebURLRequest* request,
- const char *buf,
- uint32 length) {
- std::vector<std::string> names;
- std::vector<std::string> values;
- std::vector<char> body;
- bool rv = NPAPI::PluginHost::SetPostData(buf, length, &names, &values, &body);
-
- for (size_t i = 0; i < names.size(); ++i) {
- request->addHTTPHeaderField(WebString::fromUTF8(names[i]),
- WebString::fromUTF8(values[i]));
- }
-
- WebString content_type_header = WebString::fromUTF8("Content-Type");
- const WebString& content_type =
- request->httpHeaderField(content_type_header);
- if (content_type.isEmpty()) {
- request->setHTTPHeaderField(
- content_type_header,
- WebString::fromUTF8("application/x-www-form-urlencoded"));
- }
-
- WebHTTPBody http_body;
- if (body.size()) {
- http_body.initialize();
- http_body.appendData(WebData(&body[0], body.size()));
- }
- request->setHTTPBody(http_body);
-
- return rv;
-}
-
-bool WebPluginImpl::IsValidUrl(const GURL& url, Referrer referrer_flag) {
- if (referrer_flag == PLUGIN_SRC &&
- mime_type_ == "application/x-shockwave-flash" &&
- url.GetOrigin() != plugin_url_.GetOrigin()) {
- // Do url check to make sure that there are no @, ;, \ chars in between url
- // scheme and url path.
- const char* url_to_check(url.spec().data());
- url_parse::Parsed parsed;
- url_parse::ParseStandardURL(url_to_check, strlen(url_to_check), &parsed);
- if (parsed.path.begin <= parsed.scheme.end())
- return true;
- std::string string_to_search;
- string_to_search.assign(url_to_check + parsed.scheme.end(),
- parsed.path.begin - parsed.scheme.end());
- if (string_to_search.find("@") != std::string::npos ||
- string_to_search.find(";") != std::string::npos ||
- string_to_search.find("\\") != std::string::npos)
- return false;
- }
-
- return true;
-}
-
-WebPluginImpl::RoutingStatus WebPluginImpl::RouteToFrame(
- const char* url,
- bool is_javascript_url,
- const char* method,
- const char* target,
- const char* buf,
- unsigned int len,
- int notify_id,
- Referrer referrer_flag) {
- // If there is no target, there is nothing to do
- if (!target)
- return NOT_ROUTED;
-
- // This could happen if the WebPluginContainer was already deleted.
- if (!webframe_)
- return NOT_ROUTED;
-
- WebString target_str = WebString::fromUTF8(target);
-
- // Take special action for JavaScript URLs
- if (is_javascript_url) {
- WebFrame* target_frame =
- webframe_->view()->findFrameByName(target_str, webframe_);
- // For security reasons, do not allow JavaScript on frames
- // other than this frame.
- if (target_frame != webframe_) {
- // TODO(darin): Localize this message.
- const char kMessage[] =
- "Ignoring cross-frame javascript URL load requested by plugin.";
- webframe_->addMessageToConsole(
- WebConsoleMessage(WebConsoleMessage::LevelError,
- WebString::fromUTF8(kMessage)));
- return ROUTED;
- }
-
- // Route javascript calls back to the plugin.
- return NOT_ROUTED;
- }
-
- // If we got this far, we're routing content to a target frame.
- // Go fetch the URL.
-
- GURL complete_url = CompleteURL(url);
- // Remove when flash bug is fixed. http://crbug.com/40016.
- if (!WebPluginImpl::IsValidUrl(complete_url, referrer_flag))
- return INVALID_URL;
-
- if (strcmp(method, "GET") != 0) {
- // We're only going to route HTTP/HTTPS requests
- if (!(complete_url.SchemeIs("http") || complete_url.SchemeIs("https")))
- return INVALID_URL;
- }
-
- WebURLRequest request(complete_url);
- SetReferrer(&request, referrer_flag);
-
- request.setHTTPMethod(WebString::fromUTF8(method));
- request.setFirstPartyForCookies(
- webframe_->document().firstPartyForCookies());
- if (len > 0) {
- if (!SetPostData(&request, buf, len)) {
- // Uhoh - we're in trouble. There isn't a good way
- // to recover at this point. Break out.
- NOTREACHED();
- return ROUTED;
- }
- }
-
- container_->loadFrameRequest(
- request, target_str, notify_id != 0, reinterpret_cast<void*>(notify_id));
- return ROUTED;
-}
-
-NPObject* WebPluginImpl::GetWindowScriptNPObject() {
- if (!webframe_) {
- NOTREACHED();
- return NULL;
- }
- return webframe_->windowObject();
-}
-
-NPObject* WebPluginImpl::GetPluginElement() {
- return container_->scriptableObjectForElement();
-}
-
-void WebPluginImpl::SetCookie(const GURL& url,
- const GURL& first_party_for_cookies,
- const std::string& cookie) {
- if (!page_delegate_)
- return;
-
- WebCookieJar* cookie_jar = page_delegate_->GetCookieJar();
- if (!cookie_jar) {
- DLOG(WARNING) << "No cookie jar!";
- return;
- }
-
- cookie_jar->setCookie(
- url, first_party_for_cookies, WebString::fromUTF8(cookie));
-}
-
-std::string WebPluginImpl::GetCookies(const GURL& url,
- const GURL& first_party_for_cookies) {
- if (!page_delegate_)
- return std::string();
-
- WebCookieJar* cookie_jar = page_delegate_->GetCookieJar();
- if (!cookie_jar) {
- DLOG(WARNING) << "No cookie jar!";
- return std::string();
- }
-
- return UTF16ToUTF8(cookie_jar->cookies(url, first_party_for_cookies));
-}
-
-void WebPluginImpl::ShowModalHTMLDialog(const GURL& url, int width, int height,
- const std::string& json_arguments,
- std::string* json_retval) {
- if (page_delegate_) {
- page_delegate_->ShowModalHTMLDialogForPlugin(
- url, gfx::Size(width, height), json_arguments, json_retval);
- }
-}
-
-void WebPluginImpl::OnMissingPluginStatus(int status) {
- NOTREACHED();
-}
-
-void WebPluginImpl::URLRedirectResponse(bool allow, int resource_id) {
- for (size_t i = 0; i < clients_.size(); ++i) {
- if (clients_[i].id == static_cast<unsigned long>(resource_id)) {
- if (clients_[i].loader.get()) {
- if (allow) {
- clients_[i].loader->setDefersLoading(false);
- } else {
- clients_[i].loader->cancel();
- clients_[i].client->DidFail();
- }
- }
- break;
- }
- }
-}
-
-void WebPluginImpl::Invalidate() {
- if (container_)
- container_->invalidate();
-}
-
-void WebPluginImpl::InvalidateRect(const gfx::Rect& rect) {
- if (container_)
- container_->invalidateRect(rect);
-}
-
-void WebPluginImpl::OnDownloadPluginSrcUrl() {
- HandleURLRequestInternal(
- plugin_url_.spec().c_str(), "GET", NULL, NULL, 0, 0, false, DOCUMENT_URL,
- false);
-}
-
-WebPluginResourceClient* WebPluginImpl::GetClientFromLoader(
- WebURLLoader* loader) {
- ClientInfo* client_info = GetClientInfoFromLoader(loader);
- if (client_info)
- return client_info->client;
- return NULL;
-}
-
-WebPluginImpl::ClientInfo* WebPluginImpl::GetClientInfoFromLoader(
- WebURLLoader* loader) {
- for (size_t i = 0; i < clients_.size(); ++i) {
- if (clients_[i].loader.get() == loader)
- return &clients_[i];
- }
-
- NOTREACHED();
- return 0;
-}
-
-void WebPluginImpl::willSendRequest(WebURLLoader* loader,
- WebURLRequest& request,
- const WebURLResponse& response) {
- WebPluginImpl::ClientInfo* client_info = GetClientInfoFromLoader(loader);
- if (client_info) {
- if (net::HttpResponseHeaders::IsRedirectResponseCode(
- response.httpStatusCode())) {
- // If the plugin does not participate in url redirect notifications then
- // just block cross origin 307 POST redirects.
- if (!client_info->notify_redirects) {
- if (response.httpStatusCode() == 307 &&
- LowerCaseEqualsASCII(request.httpMethod().utf8(), "post")) {
- GURL original_request_url(response.url());
- GURL response_url(request.url());
- if (original_request_url.GetOrigin() != response_url.GetOrigin()) {
- loader->setDefersLoading(true);
- loader->cancel();
- client_info->client->DidFail();
- return;
- }
- }
- } else {
- loader->setDefersLoading(true);
- }
- }
- client_info->client->WillSendRequest(request.url(),
- response.httpStatusCode());
- }
-}
-
-void WebPluginImpl::didSendData(WebURLLoader* loader,
- unsigned long long bytes_sent,
- unsigned long long total_bytes_to_be_sent) {
-}
-
-void WebPluginImpl::didReceiveResponse(WebURLLoader* loader,
- const WebURLResponse& response) {
- static const int kHttpPartialResponseStatusCode = 206;
- static const int kHttpResponseSuccessStatusCode = 200;
-
- WebPluginResourceClient* client = GetClientFromLoader(loader);
- if (!client)
- return;
-
- ResponseInfo response_info;
- GetResponseInfo(response, &response_info);
-
- bool request_is_seekable = true;
- if (client->IsMultiByteResponseExpected()) {
- if (response.httpStatusCode() == kHttpPartialResponseStatusCode) {
- HandleHttpMultipartResponse(response, client);
- return;
- } else if (response.httpStatusCode() == kHttpResponseSuccessStatusCode) {
- // If the client issued a byte range request and the server responds with
- // HTTP 200 OK, it indicates that the server does not support byte range
- // requests.
- // We need to emulate Firefox behavior by doing the following:-
- // 1. Destroy the plugin instance in the plugin process. Ensure that
- // existing resource requests initiated for the plugin instance
- // continue to remain valid.
- // 2. Create a new plugin instance and notify it about the response
- // received here.
- if (!ReinitializePluginForResponse(loader)) {
- NOTREACHED();
- return;
- }
-
- // The server does not support byte range requests. No point in creating
- // seekable streams.
- request_is_seekable = false;
-
- delete client;
- client = NULL;
-
- // Create a new resource client for this request.
- for (size_t i = 0; i < clients_.size(); ++i) {
- if (clients_[i].loader.get() == loader) {
- WebPluginResourceClient* resource_client =
- delegate_->CreateResourceClient(clients_[i].id, plugin_url_, 0);
- clients_[i].client = resource_client;
- client = resource_client;
- break;
- }
- }
-
- DCHECK(client != NULL);
- }
- }
-
- // Calling into a plugin could result in reentrancy if the plugin yields
- // control to the OS like entering a modal loop etc. Prevent this by
- // stopping further loading until the plugin notifies us that it is ready to
- // accept data
- loader->setDefersLoading(true);
-
- client->DidReceiveResponse(
- response_info.mime_type,
- GetAllHeaders(response),
- response_info.expected_length,
- response_info.last_modified,
- request_is_seekable);
-
- if (WebDevToolsAgent* devtools_agent = GetDevToolsAgent()) {
- ClientInfo* client_info = GetClientInfoFromLoader(loader);
- if (client_info)
- devtools_agent->didReceiveResponse(client_info->id, response);
- }
-
- // Bug http://b/issue?id=925559. The flash plugin would not handle the HTTP
- // error codes in the stream header and as a result, was unaware of the
- // fate of the HTTP requests issued via NPN_GetURLNotify. Webkit and FF
- // destroy the stream and invoke the NPP_DestroyStream function on the
- // plugin if the HTTP request fails.
- const GURL& url = response.url();
- if (url.SchemeIs("http") || url.SchemeIs("https")) {
- if (response.httpStatusCode() < 100 || response.httpStatusCode() >= 400) {
- // The plugin instance could be in the process of deletion here.
- // Verify if the WebPluginResourceClient instance still exists before
- // use.
- ClientInfo* client_info = GetClientInfoFromLoader(loader);
- if (client_info) {
- client_info->pending_failure_notification = true;
- }
- }
- }
-}
-
-void WebPluginImpl::didReceiveData(WebURLLoader* loader,
- const char *buffer,
- int length) {
- WebPluginResourceClient* client = GetClientFromLoader(loader);
- if (!client)
- return;
-
- // ClientInfo can be removed from clients_ vector by next statements.
- if (WebDevToolsAgent* devtools_agent = GetDevToolsAgent()) {
- ClientInfo* client_info = GetClientInfoFromLoader(loader);
- if (client_info)
- devtools_agent->didReceiveData(client_info->id, length);
- }
- MultiPartResponseHandlerMap::iterator index =
- multi_part_response_map_.find(client);
- if (index != multi_part_response_map_.end()) {
- MultipartResponseDelegate* multi_part_handler = (*index).second;
- DCHECK(multi_part_handler != NULL);
- multi_part_handler->OnReceivedData(buffer, length);
- } else {
- loader->setDefersLoading(true);
- client->DidReceiveData(buffer, length, 0);
- }
-}
-
-void WebPluginImpl::didFinishLoading(WebURLLoader* loader, double finishTime) {
- ClientInfo* client_info = GetClientInfoFromLoader(loader);
- if (client_info && client_info->client) {
- MultiPartResponseHandlerMap::iterator index =
- multi_part_response_map_.find(client_info->client);
- if (index != multi_part_response_map_.end()) {
- delete (*index).second;
- multi_part_response_map_.erase(index);
- if (page_delegate_)
- page_delegate_->DidStopLoadingForPlugin();
- }
- loader->setDefersLoading(true);
- WebPluginResourceClient* resource_client = client_info->client;
- // The ClientInfo can get deleted in the call to DidFinishLoading below.
- // It is not safe to access this structure after that.
- client_info->client = NULL;
- resource_client->DidFinishLoading();
-
- if (WebDevToolsAgent* devtools_agent = GetDevToolsAgent())
- devtools_agent->didFinishLoading(client_info->id);
- }
-}
-
-void WebPluginImpl::didFail(WebURLLoader* loader,
- const WebURLError& error) {
- ClientInfo* client_info = GetClientInfoFromLoader(loader);
- if (client_info && client_info->client) {
- loader->setDefersLoading(true);
- WebPluginResourceClient* resource_client = client_info->client;
- // The ClientInfo can get deleted in the call to DidFail below.
- // It is not safe to access this structure after that.
- client_info->client = NULL;
- resource_client->DidFail();
-
- if (WebDevToolsAgent* devtools_agent = GetDevToolsAgent())
- devtools_agent->didFailLoading(client_info->id, error);
- }
-}
-
-void WebPluginImpl::RemoveClient(size_t i) {
- clients_.erase(clients_.begin() + i);
-}
-
-void WebPluginImpl::RemoveClient(WebURLLoader* loader) {
- for (size_t i = 0; i < clients_.size(); ++i) {
- if (clients_[i].loader.get() == loader) {
- RemoveClient(i);
- return;
- }
- }
-}
-
-void WebPluginImpl::SetContainer(WebPluginContainer* container) {
- if (!container)
- TearDownPluginInstance(NULL);
- container_ = container;
-}
-
-void WebPluginImpl::HandleURLRequest(const char* url,
- const char* method,
- const char* target,
- const char* buf,
- unsigned int len,
- int notify_id,
- bool popups_allowed,
- bool notify_redirects) {
- // GetURL/PostURL requests initiated explicitly by plugins should specify the
- // plugin SRC url as the referrer if it is available.
- HandleURLRequestInternal(
- url, method, target, buf, len, notify_id, popups_allowed, PLUGIN_SRC,
- notify_redirects);
-}
-
-void WebPluginImpl::HandleURLRequestInternal(const char* url,
- const char* method,
- const char* target,
- const char* buf,
- unsigned int len,
- int notify_id,
- bool popups_allowed,
- Referrer referrer_flag,
- bool notify_redirects) {
- // For this request, we either route the output to a frame
- // because a target has been specified, or we handle the request
- // here, i.e. by executing the script if it is a javascript url
- // or by initiating a download on the URL, etc. There is one special
- // case in that the request is a javascript url and the target is "_self",
- // in which case we route the output to the plugin rather than routing it
- // to the plugin's frame.
- bool is_javascript_url = StartsWithASCII(url, "javascript:", false);
- RoutingStatus routing_status = RouteToFrame(
- url, is_javascript_url, method, target, buf, len, notify_id,
- referrer_flag);
- if (routing_status == ROUTED)
- return;
-
- if (is_javascript_url) {
- GURL gurl(url);
- WebString result = container_->executeScriptURL(gurl, popups_allowed);
-
- // delegate_ could be NULL because executeScript caused the container to
- // be deleted.
- if (delegate_) {
- delegate_->SendJavaScriptStream(
- gurl, result.utf8(), !result.isNull(), notify_id);
- }
-
- return;
- }
-
- unsigned long resource_id = GetNextResourceId();
- if (!resource_id)
- return;
-
- GURL complete_url = CompleteURL(url);
- // Remove when flash bug is fixed. http://crbug.com/40016.
- if (!WebPluginImpl::IsValidUrl(complete_url, referrer_flag))
- return;
-
- WebPluginResourceClient* resource_client = delegate_->CreateResourceClient(
- resource_id, complete_url, notify_id);
- if (!resource_client)
- return;
-
- // If the RouteToFrame call returned a failure then inform the result
- // back to the plugin asynchronously.
- if ((routing_status == INVALID_URL) ||
- (routing_status == GENERAL_FAILURE)) {
- resource_client->DidFail();
- return;
- }
-
- // CreateResourceClient() sends a synchronous IPC message so it's possible
- // that TearDownPluginInstance() may have been called in the nested
- // message loop. If so, don't start the request.
- if (!delegate_)
- return;
-
- InitiateHTTPRequest(resource_id, resource_client, complete_url, method, buf,
- len, NULL, referrer_flag, notify_redirects);
-}
-
-unsigned long WebPluginImpl::GetNextResourceId() {
- if (!webframe_)
- return 0;
- WebView* view = webframe_->view();
- if (!view)
- return 0;
- return view->createUniqueIdentifierForRequest();
-}
-
-bool WebPluginImpl::InitiateHTTPRequest(unsigned long resource_id,
- WebPluginResourceClient* client,
- const GURL& url,
- const char* method,
- const char* buf,
- int buf_len,
- const char* range_info,
- Referrer referrer_flag,
- bool notify_redirects) {
- if (!client) {
- NOTREACHED();
- return false;
- }
-
- ClientInfo info;
- info.id = resource_id;
- info.client = client;
- info.request.initialize();
- info.request.setURL(url);
- info.request.setFirstPartyForCookies(
- webframe_->document().firstPartyForCookies());
- info.request.setRequestorProcessID(delegate_->GetProcessId());
- info.request.setTargetType(WebURLRequest::TargetIsObject);
- info.request.setHTTPMethod(WebString::fromUTF8(method));
- info.pending_failure_notification = false;
- info.notify_redirects = notify_redirects;
-
- if (range_info) {
- info.request.addHTTPHeaderField(WebString::fromUTF8("Range"),
- WebString::fromUTF8(range_info));
- }
-
- if (strcmp(method, "POST") == 0) {
- // Adds headers or form data to a request. This must be called before
- // we initiate the actual request.
- SetPostData(&info.request, buf, buf_len);
- }
-
- SetReferrer(&info.request, referrer_flag);
-
- // Sets the routing id to associate the ResourceRequest with the RenderView.
- webframe_->dispatchWillSendRequest(info.request);
-
- // Sets the appcache host id to allow retrieval from the appcache.
- if (WebApplicationCacheHostImpl* appcache_host =
- WebApplicationCacheHostImpl::FromFrame(webframe_)) {
- appcache_host->willStartSubResourceRequest(info.request);
- }
-
- if (WebDevToolsAgent* devtools_agent = GetDevToolsAgent()) {
- devtools_agent->identifierForInitialRequest(resource_id, webframe_,
- info.request);
- devtools_agent->willSendRequest(resource_id, info.request);
- }
-
- info.loader.reset(WebKit::webKitClient()->createURLLoader());
- if (!info.loader.get())
- return false;
- info.loader->loadAsynchronously(info.request, this);
-
- clients_.push_back(info);
- return true;
-}
-
-void WebPluginImpl::CancelDocumentLoad() {
- if (webframe_) {
- ignore_response_error_ = true;
- webframe_->stopLoading();
- }
-}
-
-void WebPluginImpl::InitiateHTTPRangeRequest(
- const char* url, const char* range_info, int range_request_id) {
- unsigned long resource_id = GetNextResourceId();
- if (!resource_id)
- return;
-
- GURL complete_url = CompleteURL(url);
- // Remove when flash bug is fixed. http://crbug.com/40016.
- if (!WebPluginImpl::IsValidUrl(complete_url,
- load_manually_ ? NO_REFERRER : PLUGIN_SRC))
- return;
-
- WebPluginResourceClient* resource_client =
- delegate_->CreateSeekableResourceClient(resource_id, range_request_id);
- InitiateHTTPRequest(
- resource_id, resource_client, complete_url, "GET", NULL, 0, range_info,
- load_manually_ ? NO_REFERRER : PLUGIN_SRC, false);
-}
-
-void WebPluginImpl::SetDeferResourceLoading(unsigned long resource_id,
- bool defer) {
- std::vector<ClientInfo>::iterator client_index = clients_.begin();
- while (client_index != clients_.end()) {
- ClientInfo& client_info = *client_index;
-
- if (client_info.id == resource_id) {
- client_info.loader->setDefersLoading(defer);
-
- // If we determined that the request had failed via the HTTP headers
- // in the response then we send out a failure notification to the
- // plugin process, as certain plugins don't handle HTTP failure codes
- // correctly.
- if (!defer && client_info.client &&
- client_info.pending_failure_notification) {
- // The ClientInfo and the iterator can become invalid due to the call
- // to DidFail below.
- WebPluginResourceClient* resource_client = client_info.client;
- client_info.loader->cancel();
- clients_.erase(client_index++);
- resource_client->DidFail();
-
- // Report that resource loading finished.
- if (WebDevToolsAgent* devtools_agent = GetDevToolsAgent())
- devtools_agent->didFinishLoading(resource_id);
- }
- break;
- }
- client_index++;
- }
-}
-
-void WebPluginImpl::HandleHttpMultipartResponse(
- const WebURLResponse& response, WebPluginResourceClient* client) {
- std::string multipart_boundary;
- if (!MultipartResponseDelegate::ReadMultipartBoundary(
- response, &multipart_boundary)) {
- NOTREACHED();
- return;
- }
-
- if (page_delegate_)
- page_delegate_->DidStartLoadingForPlugin();
-
- MultiPartResponseClient* multi_part_response_client =
- new MultiPartResponseClient(client);
-
- MultipartResponseDelegate* multi_part_response_handler =
- new MultipartResponseDelegate(multi_part_response_client, NULL,
- response,
- multipart_boundary);
- multi_part_response_map_[client] = multi_part_response_handler;
-}
-
-bool WebPluginImpl::ReinitializePluginForResponse(
- WebURLLoader* loader) {
- WebFrame* webframe = webframe_;
- if (!webframe)
- return false;
-
- WebView* webview = webframe->view();
- if (!webview)
- return false;
-
- WebPluginContainer* container_widget = container_;
-
- // Destroy the current plugin instance.
- TearDownPluginInstance(loader);
-
- container_ = container_widget;
- webframe_ = webframe;
-
- WebPluginDelegate* plugin_delegate = page_delegate_->CreatePluginDelegate(
- file_path_, mime_type_);
-
- bool ok = plugin_delegate && plugin_delegate->Initialize(
- plugin_url_, arg_names_, arg_values_, this, load_manually_);
-
- if (!ok) {
- container_ = NULL;
- // TODO(iyengar) Should we delete the current plugin instance here?
- return false;
- }
-
- delegate_ = plugin_delegate;
-
- // Force a geometry update to occur to ensure that the plugin becomes
- // visible.
- container_->reportGeometry();
-
- // The plugin move sequences accumulated via DidMove are sent to the browser
- // whenever the renderer paints. Force a paint here to ensure that changes
- // to the plugin window are propagated to the browser.
- container_->invalidate();
- return true;
-}
-
-void WebPluginImpl::TearDownPluginInstance(
- WebURLLoader* loader_to_ignore) {
- // The container maintains a list of JSObjects which are related to this
- // plugin. Tell the frame we're gone so that it can invalidate all of
- // those sub JSObjects.
- if (container_)
- container_->clearScriptObjects();
-
- if (delegate_) {
- // Call PluginDestroyed() first to prevent the plugin from calling us back
- // in the middle of tearing down the render tree.
- delegate_->PluginDestroyed();
- delegate_ = NULL;
- }
-
- // Cancel any pending requests because otherwise this deleted object will
- // be called by the ResourceDispatcher.
- std::vector<ClientInfo>::iterator client_index = clients_.begin();
- while (client_index != clients_.end()) {
- ClientInfo& client_info = *client_index;
-
- if (loader_to_ignore == client_info.loader) {
- client_index++;
- continue;
- }
-
- if (client_info.loader.get())
- client_info.loader->cancel();
-
- client_index = clients_.erase(client_index);
- }
-
- // This needs to be called now and not in the destructor since the
- // webframe_ might not be valid anymore.
- webframe_ = NULL;
- method_factory_.RevokeAll();
-}
-
-void WebPluginImpl::SetReferrer(WebKit::WebURLRequest* request,
- Referrer referrer_flag) {
- switch (referrer_flag) {
- case DOCUMENT_URL:
- webframe_->setReferrerForRequest(*request, GURL());
- break;
-
- case PLUGIN_SRC:
- webframe_->setReferrerForRequest(*request, plugin_url_);
- break;
-
- default:
- break;
- }
-}
-
-WebDevToolsAgent* WebPluginImpl::GetDevToolsAgent() {
- if (!webframe_)
- return NULL;
- WebView* view = webframe_->view();
- if (!view)
- return NULL;
- return view->devToolsAgent();
-}
-
-} // namespace webkit_glue
diff --git a/webkit/glue/plugins/webplugin_impl.h b/webkit/glue/plugins/webplugin_impl.h
deleted file mode 100644
index 4f3b6c7..0000000
--- a/webkit/glue/plugins/webplugin_impl.h
+++ /dev/null
@@ -1,332 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_WEBPLUGIN_IMPL_H_
-#define WEBKIT_GLUE_WEBPLUGIN_IMPL_H_
-
-#include <string>
-#include <map>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/file_path.h"
-#include "base/task.h"
-#include "base/weak_ptr.h"
-#include "gfx/native_widget_types.h"
-#include "googleurl/src/gurl.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebPlugin.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebRect.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebURLLoaderClient.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebURLRequest.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebVector.h"
-#include "webkit/glue/plugins/webplugin.h"
-
-class WebViewDelegate;
-
-namespace WebKit {
-class WebDevToolsAgent;
-class WebFrame;
-class WebPluginContainer;
-class WebURLResponse;
-class WebURLLoader;
-class WebURLRequest;
-}
-
-namespace webkit_glue {
-
-class MultipartResponseDelegate;
-class WebPluginDelegate;
-class WebPluginPageDelegate;
-
-// This is the WebKit side of the plugin implementation that forwards calls,
-// after changing out of WebCore types, to a delegate. The delegate may
-// be in a different process.
-class WebPluginImpl : public WebPlugin,
- public WebKit::WebPlugin,
- public WebKit::WebURLLoaderClient {
- public:
- WebPluginImpl(
- WebKit::WebFrame* frame,
- const WebKit::WebPluginParams& params,
- const FilePath& file_path,
- const std::string& mime_type,
- const base::WeakPtr<WebPluginPageDelegate>& page_delegate);
- virtual ~WebPluginImpl();
-
- // Helper function for sorting post data.
- static bool SetPostData(WebKit::WebURLRequest* request,
- const char* buf,
- uint32 length);
-
- virtual WebPluginDelegate* delegate() { return delegate_; }
-
- private:
- // WebKit::WebPlugin methods:
- virtual bool initialize(
- WebKit::WebPluginContainer* container);
- virtual void destroy();
- virtual NPObject* scriptableObject();
- virtual void paint(
- WebKit::WebCanvas* canvas, const WebKit::WebRect& paint_rect);
- virtual void updateGeometry(
- const WebKit::WebRect& frame_rect, const WebKit::WebRect& clip_rect,
- const WebKit::WebVector<WebKit::WebRect>& cut_outs, bool is_visible);
- virtual unsigned getBackingTextureId();
- virtual void updateFocus(bool focused);
- virtual void updateVisibility(bool visible);
- virtual bool acceptsInputEvents();
- virtual bool handleInputEvent(
- const WebKit::WebInputEvent& event, WebKit::WebCursorInfo& cursor_info);
- virtual void didReceiveResponse(const WebKit::WebURLResponse& response);
- virtual void didReceiveData(const char* data, int data_length);
- virtual void didFinishLoading();
- virtual void didFailLoading(const WebKit::WebURLError& error);
- virtual void didFinishLoadingFrameRequest(
- const WebKit::WebURL& url, void* notify_data);
- virtual void didFailLoadingFrameRequest(
- const WebKit::WebURL& url, void* notify_data,
- const WebKit::WebURLError& error);
- virtual bool supportsPaginatedPrint();
- virtual int printBegin(const WebKit::WebRect& printable_area,
- int printer_dpi);
- virtual bool printPage(int page_number, WebKit::WebCanvas* canvas);
- virtual void printEnd();
- virtual bool hasSelection() const;
- virtual WebKit::WebString selectionAsText() const;
- virtual WebKit::WebString selectionAsMarkup() const;
- virtual void setZoomFactor(float scale, bool text_only);
- virtual bool startFind(const WebKit::WebString& search_text,
- bool case_sensitive,
- int identifier);
- virtual void selectFindResult(bool forward);
- virtual void stopFind();
-
- // WebPlugin implementation:
- void SetWindow(gfx::PluginWindowHandle window);
- virtual void SetAcceptsInputEvents(bool accepts) {
- accepts_input_events_ = accepts;
- }
- void WillDestroyWindow(gfx::PluginWindowHandle window);
-#if defined(OS_WIN)
- void SetWindowlessPumpEvent(HANDLE pump_messages_event) { }
-#endif
- virtual void CancelResource(unsigned long id);
- virtual void Invalidate();
- virtual void InvalidateRect(const gfx::Rect& rect);
- virtual NPObject* GetWindowScriptNPObject();
- virtual NPObject* GetPluginElement();
- virtual void SetCookie(const GURL& url,
- const GURL& first_party_for_cookies,
- const std::string& cookie);
- virtual std::string GetCookies(const GURL& url,
- const GURL& first_party_for_cookies);
- virtual void ShowModalHTMLDialog(const GURL& url, int width, int height,
- const std::string& json_arguments,
- std::string* json_retval);
- virtual void OnMissingPluginStatus(int status);
-
- virtual void URLRedirectResponse(bool allow, int resource_id);
-
- // Given a (maybe partial) url, completes using the base url.
- GURL CompleteURL(const char* url);
-
- // Executes the script passed in. The notify_needed and notify_data arguments
- // are passed in by the plugin process. These indicate whether the plugin
- // expects a notification on script execution. We pass them back to the
- // plugin as is. This avoids having to track the notification arguments in
- // the plugin process.
- bool ExecuteScript(const std::string& url, const std::wstring& script,
- bool notify_needed, intptr_t notify_data,
- bool popups_allowed);
-
- enum RoutingStatus {
- ROUTED,
- NOT_ROUTED,
- INVALID_URL,
- GENERAL_FAILURE
- };
-
- // Determines the referrer value sent along with outgoing HTTP requests
- // issued by plugins.
- enum Referrer {
- PLUGIN_SRC,
- DOCUMENT_URL,
- NO_REFERRER
- };
-
- // Given a download request, check if we need to route the output to a frame.
- // Returns ROUTED if the load is done and routed to a frame, NOT_ROUTED or
- // corresponding error codes otherwise.
- RoutingStatus RouteToFrame(const char* url,
- bool is_javascript_url,
- const char* method,
- const char* target,
- const char* buf,
- unsigned int len,
- int notify_id,
- Referrer referrer_flag);
-
- // Returns the next avaiable resource id. Returns 0 if the operation fails.
- // It may fail if the page has already been closed.
- unsigned long GetNextResourceId();
-
- // Initiates HTTP GET/POST requests.
- // Returns true on success.
- bool InitiateHTTPRequest(unsigned long resource_id,
- WebPluginResourceClient* client,
- const GURL& url,
- const char* method,
- const char* buf,
- int len,
- const char* range_info,
- Referrer referrer_flag,
- bool notify_redirects);
-
- gfx::Rect GetWindowClipRect(const gfx::Rect& rect);
-
- // Sets the actual Widget for the plugin.
- void SetContainer(WebKit::WebPluginContainer* container);
-
- // Destroys the plugin instance.
- // The response_handle_to_ignore parameter if not NULL indicates the
- // resource handle to be left valid during plugin shutdown.
- void TearDownPluginInstance(WebKit::WebURLLoader* loader_to_ignore);
-
- // WebURLLoaderClient implementation. We implement this interface in the
- // renderer process, and then use the simple WebPluginResourceClient interface
- // to relay the callbacks to the plugin.
- virtual void willSendRequest(WebKit::WebURLLoader* loader,
- WebKit::WebURLRequest& request,
- const WebKit::WebURLResponse& response);
- virtual void didSendData(WebKit::WebURLLoader* loader,
- unsigned long long bytes_sent,
- unsigned long long total_bytes_to_be_sent);
- virtual void didReceiveResponse(WebKit::WebURLLoader* loader,
- const WebKit::WebURLResponse& response);
- virtual void didReceiveData(WebKit::WebURLLoader* loader, const char *buffer,
- int length);
- virtual void didFinishLoading(WebKit::WebURLLoader* loader,
- double finishTime);
- virtual void didFail(WebKit::WebURLLoader* loader,
- const WebKit::WebURLError& error);
-
- // Helper function to remove the stored information about a resource
- // request given its index in m_clients.
- void RemoveClient(size_t i);
-
- // Helper function to remove the stored information about a resource
- // request given a handle.
- void RemoveClient(WebKit::WebURLLoader* loader);
-
- void HandleURLRequest(const char* url,
- const char *method,
- const char* target,
- const char* buf,
- unsigned int len,
- int notify_id,
- bool popups_allowed,
- bool notify_redirects);
-
- void CancelDocumentLoad();
-
- void InitiateHTTPRangeRequest(
- const char* url, const char* range_info, int pending_request_id);
-
- void SetDeferResourceLoading(unsigned long resource_id, bool defer);
-
- // Ignore in-process plugins mode for this flag.
- bool IsOffTheRecord() { return false; }
-
- // Handles HTTP multipart responses, i.e. responses received with a HTTP
- // status code of 206.
- void HandleHttpMultipartResponse(const WebKit::WebURLResponse& response,
- WebPluginResourceClient* client);
-
- void HandleURLRequestInternal(const char* url,
- const char* method,
- const char* target,
- const char* buf,
- unsigned int len,
- int notify_id,
- bool popups_allowed,
- Referrer referrer_flag,
- bool notify_redirects);
-
- // Tears down the existing plugin instance and creates a new plugin instance
- // to handle the response identified by the loader parameter.
- bool ReinitializePluginForResponse(WebKit::WebURLLoader* loader);
-
- // Delayed task for downloading the plugin source URL.
- void OnDownloadPluginSrcUrl();
-
- struct ClientInfo;
-
- // Helper functions
- WebPluginResourceClient* GetClientFromLoader(WebKit::WebURLLoader* loader);
- ClientInfo* GetClientInfoFromLoader(WebKit::WebURLLoader* loader);
-
- // Helper function to set the referrer on the request passed in.
- void SetReferrer(WebKit::WebURLRequest* request, Referrer referrer_flag);
-
- // Returns DevToolsAgent for the frame or 0.
- WebKit::WebDevToolsAgent* GetDevToolsAgent();
-
- // Check for invalid chars like @, ;, \ before the first / (in path).
- bool IsValidUrl(const GURL& url, Referrer referrer_flag);
-
- std::vector<ClientInfo> clients_;
-
- bool windowless_;
- gfx::PluginWindowHandle window_;
- bool accepts_input_events_;
- base::WeakPtr<WebPluginPageDelegate> page_delegate_;
- WebKit::WebFrame* webframe_;
-
- WebPluginDelegate* delegate_;
-
- // This is just a weak reference.
- WebKit::WebPluginContainer* container_;
-
- typedef std::map<WebPluginResourceClient*,
- webkit_glue::MultipartResponseDelegate*>
- MultiPartResponseHandlerMap;
- // Tracks HTTP multipart response handlers instantiated for
- // a WebPluginResourceClient instance.
- MultiPartResponseHandlerMap multi_part_response_map_;
-
- // The plugin source URL.
- GURL plugin_url_;
-
- // Indicates if the download would be initiated by the plugin or us.
- bool load_manually_;
-
- // Indicates if this is the first geometry update received by the plugin.
- bool first_geometry_update_;
-
- // Set to true if the next response error should be ignored.
- bool ignore_response_error_;
-
- // The current plugin geometry and clip rectangle.
- WebPluginGeometry geometry_;
-
- // The location of the plugin on disk.
- FilePath file_path_;
-
- // The mime type of the plugin.
- std::string mime_type_;
-
- // Holds the list of argument names and values passed to the plugin. We keep
- // these so that we can re-initialize the plugin if we need to.
- std::vector<std::string> arg_names_;
- std::vector<std::string> arg_values_;
-
- ScopedRunnableMethodFactory<WebPluginImpl> method_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(WebPluginImpl);
-};
-
-} // namespace webkit_glue
-
-#endif // #ifndef WEBKIT_GLUE_WEBPLUGIN_IMPL_H_
diff --git a/webkit/glue/plugins/webplugin_impl_unittest.cc b/webkit/glue/plugins/webplugin_impl_unittest.cc
deleted file mode 100644
index e70e39a..0000000
--- a/webkit/glue/plugins/webplugin_impl_unittest.cc
+++ /dev/null
@@ -1,232 +0,0 @@
-// 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.
-
-#include "base/string_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebCString.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebURLRequest.h"
-#include "webkit/glue/plugins/webplugin_impl.h"
-
-using WebKit::WebHTTPBody;
-using WebKit::WebString;
-using WebKit::WebURLRequest;
-using webkit_glue::WebPluginImpl;
-
-namespace {
-
-class WebPluginImplTest : public testing::Test {
-};
-
-}
-
-static std::string GetHeader(const WebURLRequest& request, const char* name) {
- std::string result;
- TrimWhitespace(
- request.httpHeaderField(WebString::fromUTF8(name)).utf8(),
- TRIM_ALL,
- &result);
- return result;
-}
-
-static std::string GetBodyText(const WebURLRequest& request) {
- const WebHTTPBody& body = request.httpBody();
- if (body.isNull())
- return std::string();
-
- std::string result;
- size_t i = 0;
- WebHTTPBody::Element element;
- while (body.elementAt(i++, element)) {
- if (element.type == WebHTTPBody::Element::TypeData) {
- result.append(element.data.data(), element.data.size());
- } else {
- NOTREACHED() << "unexpected element type encountered!";
- }
- }
- return result;
-}
-
-// The Host functions for NPN_PostURL and NPN_PostURLNotify
-// need to parse out some HTTP headers. Make sure it works
-// with the following tests
-
-TEST(WebPluginImplTest, PostParserSimple) {
- // Test a simple case with headers & data
- const char *ex1 = "foo: bar\nContent-length: 10\n\nabcdefghij";
- WebURLRequest request;
- request.initialize();
- bool rv = WebPluginImpl::SetPostData(&request, ex1,
- static_cast<uint32>(strlen(ex1)));
- EXPECT_EQ(true, rv);
- EXPECT_EQ("bar", GetHeader(request, "foo"));
- EXPECT_EQ(0U, GetHeader(request, "bar").length());
- EXPECT_EQ(0U, GetHeader(request, "Content-length").length());
- EXPECT_EQ("abcdefghij", GetBodyText(request));
-}
-
-TEST(WebPluginImplTest, PostParserLongHeader) {
- // Test a simple case with long headers
- const char *ex1 = "foo: 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n\nabcdefghij";
- WebURLRequest request;
- request.initialize();
- bool rv = WebPluginImpl::SetPostData(&request, ex1,
- static_cast<uint32>(strlen(ex1)));
- EXPECT_EQ(true, rv);
- EXPECT_EQ(100U, GetHeader(request, "foo").length());
-}
-
-TEST(WebPluginImplTest, PostParserManyHeaders) {
- // Test a simple case with long headers
- const char *ex1 = "h1:h1\nh2:h2\nh3:h3\nh4:h4\nh5:h5\nh6:h6\nh7:h7\nh8:h8\nh9:h9\nh10:h10\n\nbody";
- WebURLRequest request;
- request.initialize();
- bool rv = WebPluginImpl::SetPostData(&request, ex1,
- static_cast<uint32>(strlen(ex1)));
- EXPECT_EQ(true, rv);
- EXPECT_EQ("h1", GetHeader(request, "h1"));
- EXPECT_EQ("h2", GetHeader(request, "h2"));
- EXPECT_EQ("h3", GetHeader(request, "h3"));
- EXPECT_EQ("h4", GetHeader(request, "h4"));
- EXPECT_EQ("h5", GetHeader(request, "h5"));
- EXPECT_EQ("h6", GetHeader(request, "h6"));
- EXPECT_EQ("h7", GetHeader(request, "h7"));
- EXPECT_EQ("h8", GetHeader(request, "h8"));
- EXPECT_EQ("h9", GetHeader(request, "h9"));
- EXPECT_EQ("h10", GetHeader(request, "h10"));
- EXPECT_EQ("body", GetBodyText(request));
-}
-
-TEST(WebPluginImplTest, PostParserDuplicateHeaders) {
- // Test a simple case with long headers
- // What value gets returned doesn't really matter. It shouldn't error
- // out.
- const char *ex1 = "h1:h1\nh1:h2\n\nbody";
- WebURLRequest request;
- request.initialize();
- bool rv = WebPluginImpl::SetPostData(&request, ex1,
- static_cast<uint32>(strlen(ex1)));
- EXPECT_EQ(true, rv);
-}
-
-TEST(WebPluginImplTest, PostParserNoHeaders) {
- // Test a simple case with no headers but with data
- const char *ex1 = "\nabcdefghij";
- WebURLRequest request;
- request.initialize();
- bool rv = WebPluginImpl::SetPostData(&request, ex1,
- static_cast<uint32>(strlen(ex1)));
- EXPECT_EQ(true, rv);
- EXPECT_EQ(0U, GetHeader(request, "foo").length());
- EXPECT_EQ(0U, GetHeader(request, "bar").length());
- EXPECT_EQ(0U, GetHeader(request, "Content-length").length());
- EXPECT_EQ("abcdefghij", GetBodyText(request));
-}
-
-TEST(WebPluginImplTest, PostParserNoBody) {
- // Test a simple case with headers and no body
- const char *ex1 = "Foo:bar\n\n";
- WebURLRequest request;
- request.initialize();
- bool rv = WebPluginImpl::SetPostData(&request, ex1,
- static_cast<uint32>(strlen(ex1)));
- EXPECT_EQ(true, rv);
- EXPECT_EQ("bar", GetHeader(request, "foo"));
- EXPECT_EQ(0U, GetHeader(request, "bar").length());
- EXPECT_EQ(0U, GetHeader(request, "Content-length").length());
- EXPECT_EQ(0U, GetBodyText(request).length());
-}
-
-TEST(WebPluginImplTest, PostParserBodyWithNewLines) {
- // Test a simple case with headers and no body
- const char *ex1 = "Foo:bar\n\n\n\nabcdefg\n\nabcdefg";
- WebURLRequest request;
- request.initialize();
- bool rv = WebPluginImpl::SetPostData(&request, ex1,
- static_cast<uint32>(strlen(ex1)));
- EXPECT_EQ(true, rv);
- EXPECT_EQ(GetBodyText(request), "\n\nabcdefg\n\nabcdefg");
-}
-
-TEST(WebPluginImplTest, PostParserErrorNoBody) {
- // Test with headers and no body
- const char *ex1 = "Foo:bar\n";
- WebURLRequest request;
- request.initialize();
- bool rv = WebPluginImpl::SetPostData(&request, ex1,
- static_cast<uint32>(strlen(ex1)));
- EXPECT_EQ(true, rv);
-}
-
-TEST(WebPluginImplTest, PostParserErrorEmpty) {
- // Test with an empty string
- const char *ex1 = "";
- WebURLRequest request;
- request.initialize();
- bool rv = WebPluginImpl::SetPostData(&request, ex1,
- static_cast<uint32>(strlen(ex1)));
- EXPECT_EQ(true, rv);
-}
-
-TEST(WebPluginImplTest, PostParserEmptyName) {
- // Test an error case with an empty header name field
- const char *ex1 = "foo:bar\n:blat\n\nbody";
- WebURLRequest request;
- request.initialize();
- bool rv = WebPluginImpl::SetPostData(&request, ex1,
- static_cast<uint32>(strlen(ex1)));
- EXPECT_EQ(true, rv);
- EXPECT_EQ("bar", GetHeader(request, "foo"));
- EXPECT_EQ("body", GetBodyText(request));
-}
-
-TEST(WebPluginImplTest, PostParserEmptyValue) {
- // Test an error case with an empty value field
- const char *ex1 = "foo:bar\nbar:\n\nbody";
- WebURLRequest request;
- request.initialize();
- bool rv = WebPluginImpl::SetPostData(&request, ex1,
- static_cast<uint32>(strlen(ex1)));
- EXPECT_EQ(true, rv);
- EXPECT_EQ("bar", GetHeader(request, "foo"));
- EXPECT_EQ(0U, GetHeader(request, "bar").length());
- EXPECT_EQ("body", GetBodyText(request));
-}
-
-TEST(WebPluginImplTest, PostParserCRLF) {
- // Test an error case with an empty value field
- const char *ex1 = "foo: bar\r\nbar:\r\n\r\nbody\r\n\r\nbody2";
- WebURLRequest request;
- request.initialize();
- bool rv = WebPluginImpl::SetPostData(&request, ex1,
- static_cast<uint32>(strlen(ex1)));
- EXPECT_EQ(true, rv);
- EXPECT_EQ("bar", GetHeader(request, "foo"));
- EXPECT_EQ(0U, GetHeader(request, "bar").length());
- EXPECT_EQ("body\r\n\r\nbody2", GetBodyText(request));
-}
-
-TEST(WebPluginImplTest, PostParserBodyWithBinaryData) {
- // Test a simple case with headers and binary data.
- char ex1[33] = "foo: bar\nContent-length: 10\n\n";
- unsigned int binary_data = 0xFFFFFFF0;
- memcpy(ex1 + strlen("foo: bar\nContent-length: 10\n\n"), &binary_data,
- sizeof(binary_data));
-
- WebURLRequest request;
- request.initialize();
- bool rv = WebPluginImpl::SetPostData(&request, ex1,
- sizeof(ex1)/sizeof(ex1[0]));
- EXPECT_EQ(true, rv);
- EXPECT_EQ("bar", GetHeader(request, "foo"));
- EXPECT_EQ(0U, GetHeader(request, "bar").length());
- EXPECT_EQ(0U, GetHeader(request, "Content-length").length());
-
- std::string body = GetBodyText(request);
-
- EXPECT_EQ(0xF0, (unsigned char)body[0]);
- EXPECT_EQ(0xFF, (unsigned char)body[1]);
- EXPECT_EQ(0xFF, (unsigned char)body[2]);
- EXPECT_EQ(0xFF, (unsigned char)body[3]);
-}
diff --git a/webkit/glue/plugins/webplugin_page_delegate.h b/webkit/glue/plugins/webplugin_page_delegate.h
deleted file mode 100644
index d915fdd..0000000
--- a/webkit/glue/plugins/webplugin_page_delegate.h
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) 2009 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 WEBKIT_GLUE_WEBPLUGIN_PAGE_DELEGATE_
-#define WEBKIT_GLUE_WEBPLUGIN_PAGE_DELEGATE_
-
-#include "gfx/native_widget_types.h"
-
-class FilePath;
-class GURL;
-
-namespace WebKit {
-class WebCookieJar;
-}
-
-namespace webkit_glue {
-
-class WebPluginDelegate;
-struct WebPluginGeometry;
-
-// Used by the WebPlugin to communicate back to the containing page.
-class WebPluginPageDelegate {
- public:
- // This method is called to create a WebPluginDelegate implementation when a
- // new plugin is instanced. See webkit_glue::CreateWebPluginDelegateHelper
- // for a default WebPluginDelegate implementation.
- virtual WebPluginDelegate* CreatePluginDelegate(
- const FilePath& file_path,
- const std::string& mime_type) = 0;
-
- // Called when a windowed plugin is created.
- // Lets the view delegate create anything it is using to wrap the plugin.
- virtual void CreatedPluginWindow(
- gfx::PluginWindowHandle handle) = 0;
-
- // Called when a windowed plugin is closing.
- // Lets the view delegate shut down anything it is using to wrap the plugin.
- virtual void WillDestroyPluginWindow(
- gfx::PluginWindowHandle handle) = 0;
-
- // Keeps track of the necessary window move for a plugin window that resulted
- // from a scroll operation. That way, all plugin windows can be moved at the
- // same time as each other and the page.
- virtual void DidMovePlugin(
- const WebPluginGeometry& move) = 0;
-
- // Notifies the parent view that a load has begun.
- virtual void DidStartLoadingForPlugin() = 0;
-
- // Notifies the parent view that all loads are finished.
- virtual void DidStopLoadingForPlugin() = 0;
-
- // Asks the browser to show a modal HTML dialog. The dialog is passed the
- // given arguments as a JSON string, and returns its result as a JSON string
- // through json_retval.
- virtual void ShowModalHTMLDialogForPlugin(
- const GURL& url,
- const gfx::Size& size,
- const std::string& json_arguments,
- std::string* json_retval) = 0;
-
- // The WebCookieJar to use for this plugin.
- virtual WebKit::WebCookieJar* GetCookieJar() = 0;
-};
-
-} // namespace webkit_glue
-
-#endif // WEBKIT_GLUE_WEBPLUGIN_PAGE_DELEGATE_H_
diff --git a/webkit/glue/plugins/webplugin_print_delegate.h b/webkit/glue/plugins/webplugin_print_delegate.h
deleted file mode 100644
index 040e58f..0000000
--- a/webkit/glue/plugins/webplugin_print_delegate.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_WEBPLUGIN_PRINT_DELEGATE_H_
-#define WEBKIT_GLUE_PLUGINS_WEBPLUGIN_PRINT_DELEGATE_H_
-
-#include "base/basictypes.h"
-#include "third_party/npapi/bindings/npapi_extensions.h"
-
-namespace gfx {
-class Rect;
-}
-
-namespace webkit_glue {
-
-// Interface for the NPAPI print extension. This class implements "NOP"
-// versions of all these functions so it can be used seamlessly by the
-// "regular" plugin delegate while being overridden by the "pepper" one.
-class WebPluginPrintDelegate {
- public:
- // If a plugin supports print extensions, then it gets to participate fully
- // in the browser's print workflow by specifying the number of pages to be
- // printed and providing a print output for specified pages.
- virtual bool PrintSupportsPrintExtension() {
- return false;
- }
-
- // Note: printable_area is in points (a point is 1/72 of an inch).
- virtual int PrintBegin(const gfx::Rect& printable_area, int printer_dpi) {
- return 0;
- }
-
- virtual bool PrintPage(int page_number, WebKit::WebCanvas* canvas) {
- return false;
- }
-
- virtual void PrintEnd() {
- }
-
- protected:
- WebPluginPrintDelegate() {}
- virtual ~WebPluginPrintDelegate() {}
-};
-
-} // namespace webkit_glue
-
-#endif // WEBKIT_GLUE_PLUGINS_WEBPLUGIN_PRINT_DELEGATE_H_
-
diff --git a/webkit/glue/plugins/webplugininfo.cc b/webkit/glue/plugins/webplugininfo.cc
deleted file mode 100644
index 7d2b4e4..0000000
--- a/webkit/glue/plugins/webplugininfo.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/webplugininfo.h"
-
-WebPluginMimeType::WebPluginMimeType() {}
-
-WebPluginMimeType::~WebPluginMimeType() {}
-
-WebPluginInfo::WebPluginInfo() : enabled(false) {}
-
-WebPluginInfo::WebPluginInfo(const WebPluginInfo& rhs)
- : name(rhs.name),
- path(rhs.path),
- version(rhs.version),
- desc(rhs.desc),
- mime_types(rhs.mime_types),
- enabled(rhs.enabled) {
-}
-
-WebPluginInfo::~WebPluginInfo() {}
-
-WebPluginInfo& WebPluginInfo::operator=(const WebPluginInfo& rhs) {
- name = rhs.name;
- path = rhs.path;
- version = rhs.version;
- desc = rhs.desc;
- mime_types = rhs.mime_types;
- enabled = rhs.enabled;
- return *this;
-}
-
-WebPluginInfo::WebPluginInfo(const string16& fake_name,
- const string16& fake_version,
- const string16& fake_desc)
- : name(fake_name),
- path(),
- version(fake_version),
- desc(fake_desc),
- mime_types(),
- enabled(true) {
-}
-
diff --git a/webkit/glue/plugins/webplugininfo.h b/webkit/glue/plugins/webplugininfo.h
deleted file mode 100644
index 34eff3d..0000000
--- a/webkit/glue/plugins/webplugininfo.h
+++ /dev/null
@@ -1,60 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_WEBPLUGININFO_H_
-#define WEBKIT_GLUE_WEBPLUGININFO_H_
-
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/file_path.h"
-
-// Describes a mime type entry for a plugin.
-struct WebPluginMimeType {
- WebPluginMimeType();
- ~WebPluginMimeType();
-
- // The name of the mime type (e.g., "application/x-shockwave-flash").
- std::string mime_type;
-
- // A list of all the file extensions for this mime type.
- std::vector<std::string> file_extensions;
-
- // Description of the mime type.
- string16 description;
-};
-
-// Describes an available NPAPI plugin.
-struct WebPluginInfo {
- WebPluginInfo();
- WebPluginInfo(const WebPluginInfo& rhs);
- ~WebPluginInfo();
- WebPluginInfo& operator=(const WebPluginInfo& rhs);
-
- // Special constructor only used during unit testing:
- WebPluginInfo(const string16& fake_name,
- const string16& fake_version,
- const string16& fake_desc);
-
- // The name of the plugin (i.e. Flash).
- string16 name;
-
- // The path to the plugin file (DLL/bundle/library).
- FilePath path;
-
- // The version number of the plugin file (may be OS-specific)
- string16 version;
-
- // A description of the plugin that we get from its version info.
- string16 desc;
-
- // A list of all the mime types that this plugin supports.
- std::vector<WebPluginMimeType> mime_types;
-
- // Whether the plugin is enabled.
- bool enabled;
-};
-
-#endif // WEBKIT_GLUE_WEBPLUGININFO_H_
diff --git a/webkit/glue/plugins/webview_plugin.cc b/webkit/glue/plugins/webview_plugin.cc
deleted file mode 100644
index e1dc2c1..0000000
--- a/webkit/glue/plugins/webview_plugin.cc
+++ /dev/null
@@ -1,217 +0,0 @@
-// 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.
-
-#include "webkit/glue/plugins/webview_plugin.h"
-
-#include "base/message_loop.h"
-#include "base/metrics/histogram.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebCursorInfo.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebElement.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebPluginContainer.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebSize.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebURL.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebURLRequest.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebURLResponse.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebView.h"
-#include "webkit/glue/webpreferences.h"
-
-#if WEBKIT_USING_CG
-#include <CoreGraphics/CGContext.h>
-#elif WEBKIT_USING_SKIA
-#include "skia/ext/platform_canvas.h"
-#endif
-
-using WebKit::WebCanvas;
-using WebKit::WebCursorInfo;
-using WebKit::WebDragData;
-using WebKit::WebDragOperationsMask;
-using WebKit::WebFrame;
-using WebKit::WebImage;
-using WebKit::WebInputEvent;
-using WebKit::WebPlugin;
-using WebKit::WebPluginContainer;
-using WebKit::WebPoint;
-using WebKit::WebRect;
-using WebKit::WebSize;
-using WebKit::WebURLError;
-using WebKit::WebURLRequest;
-using WebKit::WebURLResponse;
-using WebKit::WebVector;
-using WebKit::WebView;
-
-WebViewPlugin::WebViewPlugin(WebViewPlugin::Delegate* delegate)
- : delegate_(delegate),
- container_(NULL),
- finished_loading_(false) {
- web_view_ = WebView::create(this, NULL);
- web_view_->initializeMainFrame(this);
-}
-
-// static
-WebViewPlugin* WebViewPlugin::Create(WebViewPlugin::Delegate* delegate,
- const WebPreferences& preferences,
- const std::string& html_data,
- const GURL& url) {
- WebViewPlugin* plugin = new WebViewPlugin(delegate);
- WebView* web_view = plugin->web_view();
- preferences.Apply(web_view);
- web_view->mainFrame()->loadHTMLString(html_data, url);
- return plugin;
-}
-
-WebViewPlugin::~WebViewPlugin() {
- web_view_->close();
-}
-
-void WebViewPlugin::ReplayReceivedData(WebPlugin* plugin) {
- if (!response_.isNull()) {
- plugin->didReceiveResponse(response_);
- size_t total_bytes = 0;
- for (std::list<std::string>::iterator it = data_.begin();
- it != data_.end(); ++it) {
- plugin->didReceiveData(it->c_str(), it->length());
- total_bytes += it->length();
- }
- UMA_HISTOGRAM_MEMORY_KB("PluginDocument.Memory", (total_bytes / 1024));
- UMA_HISTOGRAM_COUNTS("PluginDocument.NumChunks", data_.size());
- }
- if (finished_loading_) {
- plugin->didFinishLoading();
- }
- if (error_.get()) {
- plugin->didFailLoading(*error_);
- }
-}
-
-void WebViewPlugin::RestoreTitleText() {
- if (container_)
- container_->element().setAttribute("title", old_title_);
-}
-
-
-bool WebViewPlugin::initialize(WebPluginContainer* container) {
- container_ = container;
- if (container_)
- old_title_ = container_->element().getAttribute("title");
- return true;
-}
-
-void WebViewPlugin::destroy() {
- if (delegate_) {
- delegate_->WillDestroyPlugin();
- delegate_ = NULL;
- }
- container_ = NULL;
- MessageLoop::current()->DeleteSoon(FROM_HERE, this);
-}
-
-void WebViewPlugin::paint(WebCanvas* canvas, const WebRect& rect) {
- gfx::Rect paintRect(rect_.Intersect(rect));
- if (paintRect.IsEmpty())
- return;
-
- paintRect.Offset(-rect_.x(), -rect_.y());
-
-#if WEBKIT_USING_CG
- CGContextRef context = canvas;
- CGContextTranslateCTM(context, rect_.x(), rect_.y());
- CGContextSaveGState(context);
-#elif WEBKIT_USING_SKIA
- skia::PlatformCanvas* platform_canvas = canvas;
- platform_canvas->translate(SkIntToScalar(rect_.x()),
- SkIntToScalar(rect_.y()));
- platform_canvas->save();
-#endif
-
- web_view_->layout();
- web_view_->paint(canvas, paintRect);
-
-#if WEBKIT_USING_SKIA
- platform_canvas->restore();
-#elif WEBKIT_USING_CG
- CGContextRestoreGState(context);
-#endif
-}
-
-// Coordinates are relative to the containing window.
-void WebViewPlugin::updateGeometry(
- const WebRect& frame_rect, const WebRect& clip_rect,
- const WebVector<WebRect>& cut_out_rects, bool is_visible) {
- if (frame_rect != rect_) {
- rect_ = frame_rect;
- web_view_->resize(WebSize(frame_rect.width, frame_rect.height));
- }
-}
-
-bool WebViewPlugin::handleInputEvent(const WebInputEvent& event,
- WebCursorInfo& cursor) {
- current_cursor_ = cursor;
- bool handled = web_view_->handleInputEvent(event);
- cursor = current_cursor_;
- return handled;
-}
-
-void WebViewPlugin::didReceiveResponse(const WebURLResponse& response) {
- DCHECK(response_.isNull());
- response_ = response;
-}
-
-void WebViewPlugin::didReceiveData(const char* data, int data_length) {
- data_.push_back(std::string(data, data_length));
-}
-
-void WebViewPlugin::didFinishLoading() {
- DCHECK(!finished_loading_);
- finished_loading_ = true;
-}
-
-void WebViewPlugin::didFailLoading(const WebURLError& error) {
- DCHECK(!error_.get());
- error_.reset(new WebURLError(error));
-}
-
-void WebViewPlugin::setToolTipText(const WebKit::WebString& text,
- WebKit::WebTextDirection hint) {
- if (container_)
- container_->element().setAttribute("title", text);
-}
-
-void WebViewPlugin::startDragging(const WebDragData&,
- WebDragOperationsMask,
- const WebImage&,
- const WebPoint&) {
- // Immediately stop dragging.
- web_view_->dragSourceSystemDragEnded();
-}
-
-void WebViewPlugin::didInvalidateRect(const WebRect& rect) {
- if (container_)
- container_->invalidateRect(rect);
-}
-
-void WebViewPlugin::didChangeCursor(const WebCursorInfo& cursor) {
- current_cursor_ = cursor;
-}
-
-void WebViewPlugin::didClearWindowObject(WebFrame* frame) {
- if (delegate_)
- delegate_->BindWebFrame(frame);
-}
-
-bool WebViewPlugin::canHandleRequest(WebFrame* frame,
- const WebURLRequest& request) {
- return GURL(request.url()).SchemeIs("chrome");
-}
-
-WebURLError WebViewPlugin::cancelledError(WebFrame* frame,
- const WebURLRequest& request) {
- // Return an error with a non-zero reason so isNull() on the corresponding
- // ResourceError is false.
- WebURLError error;
- error.domain = "WebViewPlugin";
- error.reason = -1;
- error.unreachableURL = request.url();
- return error;
-}
diff --git a/webkit/glue/plugins/webview_plugin.h b/webkit/glue/plugins/webview_plugin.h
deleted file mode 100644
index ef85d77..0000000
--- a/webkit/glue/plugins/webview_plugin.h
+++ /dev/null
@@ -1,138 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_GLUE_PLUGINS_WEBVIEW_PLUGIN_H_
-#define WEBKIT_GLUE_PLUGINS_WEBVIEW_PLUGIN_H_
-
-#include <list>
-
-#include "base/scoped_ptr.h"
-#include "base/task.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebCursorInfo.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebFrameClient.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebPlugin.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebTextDirection.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebURLResponse.h"
-#include "third_party/WebKit/WebKit/chromium/public/WebViewClient.h"
-
-struct WebPreferences;
-
-// This class implements the WebPlugin interface by forwarding drawing and
-// handling input events to a WebView.
-// It can be used as a placeholder for an actual plugin, using HTML for the UI.
-// To show HTML data inside the WebViewPlugin,
-// call web_view->mainFrame()->loadHTMLString() with the HTML data and a fake
-// chrome:// URL as origin.
-
-class WebViewPlugin: public WebKit::WebPlugin, public WebKit::WebViewClient,
- public WebKit::WebFrameClient {
- public:
- class Delegate {
- public:
- // Bind |frame| to a Javascript object, enabling the delegate to receive
- // callback methods from Javascript inside the WebFrame.
- // This method is called from WebFrameClient::didClearWindowObject.
- virtual void BindWebFrame(WebKit::WebFrame* frame) = 0;
-
- // Called before the WebViewPlugin is destroyed. The delegate should delete
- // itself here.
- virtual void WillDestroyPlugin() = 0;
- };
-
- explicit WebViewPlugin(Delegate* delegate);
-
- // Convenience method to set up a new WebViewPlugin using |preferences|
- // and displaying |html_data|. |url| should be a (fake) chrome:// URL; it is
- // only used for navigation and never actually resolved.
- static WebViewPlugin* Create(Delegate* delegate,
- const WebPreferences& preferences,
- const std::string& html_data,
- const GURL& url);
-
- WebKit::WebView* web_view() { return web_view_; }
-
- WebKit::WebPluginContainer* container() { return container_; }
-
- // When loading a plug-in document (i.e. a full page plug-in not embedded in
- // another page), we save all data that has been received, and replay it with
- // this method on the actual plug-in.
- void ReplayReceivedData(WebKit::WebPlugin* plugin);
-
- void RestoreTitleText();
-
- // WebPlugin methods:
- virtual bool initialize(WebKit::WebPluginContainer*);
- virtual void destroy();
-
- virtual NPObject* scriptableObject() { return NULL; }
-
- virtual void paint(WebKit::WebCanvas* canvas, const WebKit::WebRect& rect);
-
- // Coordinates are relative to the containing window.
- virtual void updateGeometry(
- const WebKit::WebRect& frame_rect, const WebKit::WebRect& clip_rect,
- const WebKit::WebVector<WebKit::WebRect>& cut_out_rects, bool is_visible);
-
- virtual void updateFocus(bool) { }
- virtual void updateVisibility(bool) { }
-
- virtual bool acceptsInputEvents() { return true; }
- virtual bool handleInputEvent(const WebKit::WebInputEvent& event,
- WebKit::WebCursorInfo& cursor_info);
-
- virtual void didReceiveResponse(const WebKit::WebURLResponse& response);
- virtual void didReceiveData(const char* data, int data_length);
- virtual void didFinishLoading();
- virtual void didFailLoading(const WebKit::WebURLError& error);
-
- // Called in response to WebPluginContainer::loadFrameRequest
- virtual void didFinishLoadingFrameRequest(
- const WebKit::WebURL& url, void* notifyData) { }
- virtual void didFailLoadingFrameRequest(const WebKit::WebURL& url,
- void* notify_data,
- const WebKit::WebURLError& error) { }
-
- // WebViewClient methods:
- virtual bool acceptsLoadDrops() { return false; }
-
- virtual void setToolTipText(const WebKit::WebString&,
- WebKit::WebTextDirection);
-
- virtual void startDragging(const WebKit::WebDragData& drag_data,
- WebKit::WebDragOperationsMask mask,
- const WebKit::WebImage& image,
- const WebKit::WebPoint& point);
-
- // WebWidgetClient methods:
- virtual void didInvalidateRect(const WebKit::WebRect&);
- virtual void didChangeCursor(const WebKit::WebCursorInfo& cursor);
-
- // WebFrameClient methods:
- virtual void didClearWindowObject(WebKit::WebFrame* frame);
-
- virtual bool canHandleRequest(WebKit::WebFrame* frame,
- const WebKit::WebURLRequest& request);
-
- virtual WebKit::WebURLError cancelledError(
- WebKit::WebFrame* frame, const WebKit::WebURLRequest& request);
-
- private:
- friend class DeleteTask<WebViewPlugin>;
- virtual ~WebViewPlugin();
-
- Delegate* delegate_;
- WebKit::WebCursorInfo current_cursor_;
- WebKit::WebPluginContainer* container_;
- WebKit::WebView* web_view_;
- gfx::Rect rect_;
-
- WebKit::WebURLResponse response_;
- std::list<std::string> data_;
- bool finished_loading_;
- scoped_ptr<WebKit::WebURLError> error_;
- WebKit::WebString old_title_;
-};
-
-#endif // WEBKIT_GLUE_PLUGINS_WEBVIEW_PLUGIN_H_
diff --git a/webkit/glue/resource_loader_bridge.cc b/webkit/glue/resource_loader_bridge.cc
index 86029e2..3e9c9e8 100644
--- a/webkit/glue/resource_loader_bridge.cc
+++ b/webkit/glue/resource_loader_bridge.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// 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.
@@ -54,7 +54,8 @@ ResourceLoaderBridge::RequestInfo::RequestInfo()
request_context(0),
appcache_host_id(0),
routing_id(0),
- download_to_file(false) {
+ download_to_file(false),
+ has_user_gesture(false) {
}
ResourceLoaderBridge::RequestInfo::~RequestInfo() {
diff --git a/webkit/glue/resource_loader_bridge.h b/webkit/glue/resource_loader_bridge.h
index bd2f8b9..7257b0c 100644
--- a/webkit/glue/resource_loader_bridge.h
+++ b/webkit/glue/resource_loader_bridge.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// 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.
//
@@ -236,6 +236,9 @@ class ResourceLoaderBridge {
// If true, then the response body will be downloaded to a file and the
// path to that file will be provided in ResponseInfo::download_file_path.
bool download_to_file;
+
+ // True if the request was user initiated.
+ bool has_user_gesture;
};
// See the SyncLoad method declared below. (The name of this struct is not
@@ -259,9 +262,9 @@ class ResourceLoaderBridge {
// within webkit. The Peer and it's bridge should have identical lifetimes
// as they represent each end of a communication channel.
//
- // These callbacks mirror URLRequest::Delegate and the order and conditions
- // in which they will be called are identical. See url_request.h for more
- // information.
+ // These callbacks mirror net::URLRequest::Delegate and the order and
+ // conditions in which they will be called are identical. See url_request.h
+ // for more information.
class Peer {
public:
virtual ~Peer() {}
diff --git a/webkit/glue/resources/webkit_strings_am.xtb b/webkit/glue/resources/webkit_strings_am.xtb
index 4f5108e..1a71058 100644
--- a/webkit/glue/resources/webkit_strings_am.xtb
+++ b/webkit/glue/resources/webkit_strings_am.xtb
@@ -8,7 +8,6 @@
<translation id="7658239707568436148">ሰርዝ</translation>
<translation id="795667975304826397">ምንም ፋይል አልተመረጠም</translation>
<translation id="8141602879876242471">ይህ ሊፈለግ የሚችል መረጃ ጠቋሚ ነው። የፍለጋ ቁልፍ ቃላት አስገባ፦</translation>
-<translation id="370665806235115550">በመጫን ላይ...</translation>
<translation id="6845533974506654842">ተጫን</translation>
<translation id="8244226242650769279">የምስል ካርታ</translation>
<translation id="2548326553472216322">የቅርብ ጊዜ ፍለጋዎች የሉም</translation>
@@ -21,6 +20,7 @@
<translation id="5476505524087279545">አታመልክት</translation>
<translation id="3789841737615482174">ጫን</translation>
<translation id="6663448176199120256">የቅርብ ጊዜ ፍለጋዎችን</translation>
+<translation id="6807599807928161586">የድር ክልል</translation>
<translation id="5939518447894949180">ዳግም አስጀምር</translation>
<translation id="1842960171412779397">ምረጥ</translation>
<translation id="6119846243427417423">አንቃ</translation>
diff --git a/webkit/glue/resources/webkit_strings_ar.xtb b/webkit/glue/resources/webkit_strings_ar.xtb
index 0f2e739..6f454f7 100644
--- a/webkit/glue/resources/webkit_strings_ar.xtb
+++ b/webkit/glue/resources/webkit_strings_ar.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="ar">
<translation id="4519964825805946997">أخفق تثبيت المكون الإضافي من <ph name="URL"/></translation>
-<translation id="9186171386827445984">جارٍ تحميل المستند: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> من الصفحات...</translation>
<translation id="1235745349614807883">محو آخر عمليات البحث</translation>
<translation id="5048533449481078685">محدّد القائمة</translation>
<translation id="372362261556059955">المكوّن الإضافي المطلوب</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">أخفق تثبيت المكون الإضافي</translation>
<translation id="8141602879876242471">يمكن البحث في هذا الفهرس بإدخال كلمات مفتاحية:</translation>
<translation id="5650795167354946011">بعد تثبيت المكون الإضافي، انقر هنا للتحديث</translation>
-<translation id="370665806235115550">تحميل...</translation>
<translation id="6845533974506654842">اضغط</translation>
<translation id="8244226242650769279">مخطّط صورة</translation>
<translation id="2548326553472216322">لا عمليات بحث حديثة</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">الرجاء التأكيد على أنك تريد تثبيت المكوّن الإضافي <ph name="PLUGIN"/>. يجب تثبيت المكونات الإضافية التي تثق فيها فقط.</translation>
<translation id="6663448176199120256">آخر عمليات البحث</translation>
<translation id="2597378329261239068">هذا المستند محمي بكلمة المرور. الرجاء إدخال كلمة مرور.</translation>
-<translation id="7740050170769002709">محتوى HTML</translation>
+<translation id="6807599807928161586">منطقة الويب</translation>
<translation id="5939518447894949180">إعادة</translation>
<translation id="1842960171412779397">الاختيار</translation>
<translation id="7638452146404718955">انقر هنا لتنزيل المكون الإضافي</translation>
diff --git a/webkit/glue/resources/webkit_strings_bg.xtb b/webkit/glue/resources/webkit_strings_bg.xtb
index 09f4a71..4edbd69 100644
--- a/webkit/glue/resources/webkit_strings_bg.xtb
+++ b/webkit/glue/resources/webkit_strings_bg.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="bg">
<translation id="4519964825805946997">Инсталирането на приставката от <ph name="URL"/> не бе успешно</translation>
-<translation id="9186171386827445984">Документът се зарежда: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> страници...</translation>
<translation id="1235745349614807883">Изчистване на скорошните търсения</translation>
<translation id="5048533449481078685">списъчен показалец</translation>
<translation id="372362261556059955">Необходима е допълнителна приставка</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">Инсталирането на приставката не бе успешно</translation>
<translation id="8141602879876242471">В този индекс може да се търси. Въведете ключови думи за търсене:</translation>
<translation id="5650795167354946011">След инсталирането на приставката кликнете тук за опресняване</translation>
-<translation id="370665806235115550">Зарежда се...</translation>
<translation id="6845533974506654842">натискане</translation>
<translation id="8244226242650769279">карта с изображения</translation>
<translation id="2548326553472216322">Няма скорошни търсения</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Моля, потвърдете, че искате да инсталирате приставката <ph name="PLUGIN"/>. Трябва да инсталирате само приставки, на които имате доверие.</translation>
<translation id="6663448176199120256">Скорошни търсения</translation>
<translation id="2597378329261239068">Този документ е защитен с парола. Моля, въведете я.</translation>
-<translation id="7740050170769002709">HTML съдържание</translation>
+<translation id="6807599807928161586">уеб зона</translation>
<translation id="5939518447894949180">Повторно задаване</translation>
<translation id="1842960171412779397">Избиране</translation>
<translation id="7638452146404718955">Кликнете тук, за да изтеглите приставката</translation>
diff --git a/webkit/glue/resources/webkit_strings_bn.xtb b/webkit/glue/resources/webkit_strings_bn.xtb
index 7143769..1a29278 100644
--- a/webkit/glue/resources/webkit_strings_bn.xtb
+++ b/webkit/glue/resources/webkit_strings_bn.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="bn">
<translation id="4519964825805946997"><ph name="URL"/>-এর থেকে প্ল্যাগ-ইন ইনস্টল করতে ব্যর্থ হয়েছে</translation>
-<translation id="9186171386827445984">নথি লোড হচ্ছে: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> পৃষ্ঠা...</translation>
<translation id="1235745349614807883">সাম্প্রতিক অনুসন্ধানগুলি সাফ করুন</translation>
<translation id="5048533449481078685">তালিকা নির্দেশক</translation>
<translation id="372362261556059955">অতিরিক্ত প্লাগ-ইন দরকার</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">প্লাগ-ইন ইনস্টলেশান ব্যর্থ হয়েছে</translation>
<translation id="8141602879876242471">এটি অনুসন্ধানযোগ্য সূচি৷ অনুসন্ধানের মূলশব্দ প্রবেশ করান:</translation>
<translation id="5650795167354946011">প্ল্যাগ-ইন ইনস্টল করার পরে, রিফ্রেশ করার জন্য এখানে ক্লিক করুন</translation>
-<translation id="370665806235115550">লোড হচ্ছে...</translation>
<translation id="6845533974506654842">টিপুন</translation>
<translation id="8244226242650769279">ছবি মানচিত্র</translation>
<translation id="2548326553472216322">কোন সাম্প্রতিক অনুসন্ধান নেই</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">আপনি <ph name="PLUGIN"/> প্ল্যাগ-ইনটি ইনস্টল করতে চান কি না দয়া করে নিশ্চিত করুন৷ আপনার কেবল সেই প্ল্যাগ-ইনগুলি ইনস্টল করার উচিত যেগুলিকে আপনি বিশ্বাস করেন৷</translation>
<translation id="6663448176199120256">সাম্প্রতিক অনুসন্ধানগুলি</translation>
<translation id="2597378329261239068">এই দস্তাবেজটি পাসওয়ার্ড সুরক্ষিত৷ দয়া করে একটি পাসওয়ার্ড লিখুন৷</translation>
-<translation id="7740050170769002709">HTML সামগ্রী</translation>
+<translation id="6807599807928161586">ওয়েব এলাকা</translation>
<translation id="5939518447894949180">রিসেট করুন</translation>
<translation id="1842960171412779397">নির্বাচন করুন</translation>
<translation id="7638452146404718955">প্ল্যাগ-ইন ডাউনলোড করার জন্য এখানে ক্লিক করুন</translation>
diff --git a/webkit/glue/resources/webkit_strings_ca.xtb b/webkit/glue/resources/webkit_strings_ca.xtb
index 59756a8..6f3dc90 100644
--- a/webkit/glue/resources/webkit_strings_ca.xtb
+++ b/webkit/glue/resources/webkit_strings_ca.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="ca">
<translation id="4519964825805946997">S'ha produït un error en instal·lar el connector des de <ph name="URL"/></translation>
-<translation id="9186171386827445984">S'està carregant el document: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> pàgines...</translation>
<translation id="1235745349614807883">Esborra les cerques recents</translation>
<translation id="5048533449481078685">marcador de llistes</translation>
<translation id="372362261556059955">Es necessita un connector addicional</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">S'ha produït un error en instal·lar el connector </translation>
<translation id="8141602879876242471">És un índex on es poden realitzar cerques. Introdueix els termes de cerca:</translation>
<translation id="5650795167354946011">Després d'instal·lar el connector, feu clic aquí per actualitzar</translation>
-<translation id="370665806235115550">S'està carregant...</translation>
<translation id="6845533974506654842">prem</translation>
<translation id="8244226242650769279">mapa d'imatges</translation>
<translation id="2548326553472216322">No hi ha cerques recents</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Confirmeu que voleu instal·lar el connector <ph name="PLUGIN"/>. Us recomanem que només instal·leu connectors de la vostra confiança.</translation>
<translation id="6663448176199120256">Cerques recents</translation>
<translation id="2597378329261239068">Aquest document està protegit mitjançant contrasenya. Introduïu una contrasenya.</translation>
-<translation id="7740050170769002709">Contingut HTML</translation>
+<translation id="6807599807928161586">àrea web</translation>
<translation id="5939518447894949180">Restablir</translation>
<translation id="1842960171412779397">selecciona</translation>
<translation id="7638452146404718955">Feu clic aquí per baixar el connector</translation>
diff --git a/webkit/glue/resources/webkit_strings_cs.xtb b/webkit/glue/resources/webkit_strings_cs.xtb
index 8d3784f..33a0d12 100644
--- a/webkit/glue/resources/webkit_strings_cs.xtb
+++ b/webkit/glue/resources/webkit_strings_cs.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="cs">
<translation id="4519964825805946997">Instalace pluginu z adresy URL <ph name="URL"/> se nezdařila</translation>
-<translation id="9186171386827445984">Načítání dokumentu: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> stran...</translation>
<translation id="1235745349614807883">Smazat nedávná vyhledávání</translation>
<translation id="5048533449481078685">značka seznamu</translation>
<translation id="372362261556059955">Je zapotřebí další plugin</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">Instalace pluginu selhala</translation>
<translation id="8141602879876242471">Toto je prohledávatelný index. Zadejte hledaná klíčová slova:</translation>
<translation id="5650795167354946011">Po instalaci pluginu obnovte okno kliknutím sem</translation>
-<translation id="370665806235115550">Načítání...</translation>
<translation id="6845533974506654842">zmáčknout</translation>
<translation id="8244226242650769279">obrázková mapa</translation>
<translation id="2548326553472216322">Žádná nedávná vyhledávání</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Potvrďte prosím, zda chcete nainstalovat plugin <ph name="PLUGIN"/>. Instalujte pouze pluginy, kterým důvěřujete.</translation>
<translation id="6663448176199120256">Nedávná vyhledávání</translation>
<translation id="2597378329261239068">Tento dokument je chráněn heslem. Zadejte prosím heslo.</translation>
-<translation id="7740050170769002709">Obsah ve formátu HTML</translation>
+<translation id="6807599807928161586">oblast webu</translation>
<translation id="5939518447894949180">Resetovat</translation>
<translation id="1842960171412779397">zvolit</translation>
<translation id="7638452146404718955">Plugin můžete stáhnout kliknutím sem</translation>
diff --git a/webkit/glue/resources/webkit_strings_da.xtb b/webkit/glue/resources/webkit_strings_da.xtb
index 71d2a6a..78f06ff 100644
--- a/webkit/glue/resources/webkit_strings_da.xtb
+++ b/webkit/glue/resources/webkit_strings_da.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="da">
<translation id="4519964825805946997">Installation af plugin fra <ph name="URL"/> mislykkedes</translation>
-<translation id="9186171386827445984">Indlæser dokument: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> sider...</translation>
<translation id="1235745349614807883">Slet nylige søgninger</translation>
<translation id="5048533449481078685">listemarkering</translation>
<translation id="372362261556059955">Ekstra plugin påkrævet</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">Installation af plugin mislykkedes</translation>
<translation id="8141602879876242471">Der kan søges i dette indeks. Indtast søge-nøgleord:</translation>
<translation id="5650795167354946011">Når du har installeret plugin'et, skal du klikke her for at opdatere</translation>
-<translation id="370665806235115550">Indlæser ...</translation>
<translation id="6845533974506654842">tryk</translation>
<translation id="8244226242650769279">billedekort</translation>
<translation id="2548326553472216322">Ingen nylige søgninger</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Bekræft, at du vil installere dette <ph name="PLUGIN"/>-plugin. Du skal kun installere plugins, som du har tillid til.</translation>
<translation id="6663448176199120256">Nylige søgninger</translation>
<translation id="2597378329261239068">Dette dokument er adgangskodebeskyttet. Indtast en adgangskode.</translation>
-<translation id="7740050170769002709">HTML-indhold</translation>
+<translation id="6807599807928161586">webområde</translation>
<translation id="5939518447894949180">Nulstil</translation>
<translation id="1842960171412779397">vælg</translation>
<translation id="7638452146404718955">Klik her for at downloade plugin</translation>
diff --git a/webkit/glue/resources/webkit_strings_de.xtb b/webkit/glue/resources/webkit_strings_de.xtb
index 6d27410..45fab1b 100644
--- a/webkit/glue/resources/webkit_strings_de.xtb
+++ b/webkit/glue/resources/webkit_strings_de.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="de">
<translation id="4519964825805946997">Installation des Plug-ins von <ph name="URL"/> fehlgeschlagen</translation>
-<translation id="9186171386827445984">Dokument wird geladen <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> Seiten...</translation>
<translation id="1235745349614807883">Vor kurzem durchgeführte Suchanfragen löschen</translation>
<translation id="5048533449481078685">Listenmarkierung</translation>
<translation id="372362261556059955">Zusätzliches Plug-in erforderlich</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">Plug-in-Installation fehlgeschlagen</translation>
<translation id="8141602879876242471">Dieser Index kann durchsucht werden. Geben Sie Suchbegriffe ein:</translation>
<translation id="5650795167354946011">Klicken Sie nach der Installation des Plug-ins hier, um eine Aktualisierung durchzuführen.</translation>
-<translation id="370665806235115550">Wird geladen...</translation>
<translation id="6845533974506654842">klicken</translation>
<translation id="8244226242650769279">Imagemap</translation>
<translation id="2548326553472216322">Keine vor kurzem durchgeführte Suchanfragen</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Bitte bestätigen Sie, dass Sie das Plug-in <ph name="PLUGIN"/> installieren möchten. Installieren Sie nur Plug-ins, denen Sie vertrauen.</translation>
<translation id="6663448176199120256">Vor kurzem durchgeführte Suchanfragen</translation>
<translation id="2597378329261239068">Dieses Dokument ist passwortgeschützt. Geben Sie ein Passwort ein.</translation>
-<translation id="7740050170769002709">HTML-Inhalte</translation>
+<translation id="6807599807928161586">Webbereich</translation>
<translation id="5939518447894949180">Zurücksetzen</translation>
<translation id="1842960171412779397">auswählen</translation>
<translation id="7638452146404718955">Hier klicken, um das Plug-in herunterzuladen</translation>
diff --git a/webkit/glue/resources/webkit_strings_el.xtb b/webkit/glue/resources/webkit_strings_el.xtb
index c429294..509307e 100644
--- a/webkit/glue/resources/webkit_strings_el.xtb
+++ b/webkit/glue/resources/webkit_strings_el.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="el">
<translation id="4519964825805946997">Η εγκατάσταση της προσθήκης από τη διεύθυνση <ph name="URL"/> απέτυχε</translation>
-<translation id="9186171386827445984">Φόρτωση εγγράφου: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> σελίδες...</translation>
<translation id="1235745349614807883">Εκκαθάριση πρόσφατων αναζητήσεων</translation>
<translation id="5048533449481078685">δείκτης λίστας</translation>
<translation id="372362261556059955">Απαιτείται επιπλέον προσθήκη</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">Η εγκατάσταση προσθήκης απέτυχε</translation>
<translation id="8141602879876242471">Πρόκειται για ευρετήριο με δυνατότητα αναζήτησης. Πληκτρολογήστε λέξεις-κλειδιά αναζήτησης:</translation>
<translation id="5650795167354946011">Μετά την εγκατάσταση της προσθήκης, κάντε κλικ εδώ για ανανέωση των δεδομένων</translation>
-<translation id="370665806235115550">Φόρτωση...</translation>
<translation id="6845533974506654842">πατήστε</translation>
<translation id="8244226242650769279">χάρτης εικόνας</translation>
<translation id="2548326553472216322">Δεν υπάρχουν πρόσφατες αναζητήσεις</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Επιβεβαιώστε ότι θέλετε να εγκαταστήσετε την προσθήκη <ph name="PLUGIN"/>. Πρέπει να εγκαθιστάτε μόνο προσθήκες που θεωρείτε αξιόπιστες.</translation>
<translation id="6663448176199120256">Πρόσφατες αναζητήσεις</translation>
<translation id="2597378329261239068">Αυτό το έγγραφο προστατεύεται με κωδικό πρόσβασης. Πληκτρολογήστε έναν κωδικό πρόσβασης.</translation>
-<translation id="7740050170769002709">Περιεχόμενο HTML</translation>
+<translation id="6807599807928161586">περιοχή ιστού</translation>
<translation id="5939518447894949180">Επαναφορά</translation>
<translation id="1842960171412779397">επιλογή</translation>
<translation id="7638452146404718955">Κάντε κλικ εδώ για να κάνετε λήψη της προσθήκης</translation>
diff --git a/webkit/glue/resources/webkit_strings_en-GB.xtb b/webkit/glue/resources/webkit_strings_en-GB.xtb
index 417f44a..14befa8 100644
--- a/webkit/glue/resources/webkit_strings_en-GB.xtb
+++ b/webkit/glue/resources/webkit_strings_en-GB.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="en-GB">
<translation id="4519964825805946997">Failed to install plug-in from <ph name="URL"/></translation>
-<translation id="9186171386827445984">Loading document: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> pages...</translation>
<translation id="1235745349614807883">Clear Recent Searches</translation>
<translation id="5048533449481078685">list marker</translation>
<translation id="372362261556059955">Additional plug-in needed</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">Plug-in installation failed</translation>
<translation id="8141602879876242471">This is a searchable index. Enter search keywords:</translation>
<translation id="5650795167354946011">After installing the plug-in, click here to refresh</translation>
-<translation id="370665806235115550">Loading...</translation>
<translation id="6845533974506654842">press</translation>
<translation id="8244226242650769279">image map</translation>
<translation id="2548326553472216322">No recent searches</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Please confirm that you would like to install the <ph name="PLUGIN"/> plug-in. You should only install plug-ins that you trust.</translation>
<translation id="6663448176199120256">Recent Searches</translation>
<translation id="2597378329261239068">This document is password-protected. Please enter a password.</translation>
-<translation id="7740050170769002709">HTML content</translation>
+<translation id="6807599807928161586">web area</translation>
<translation id="5939518447894949180">Reset</translation>
<translation id="1842960171412779397">select</translation>
<translation id="7638452146404718955">Click here to download plug-in</translation>
diff --git a/webkit/glue/resources/webkit_strings_es-419.xtb b/webkit/glue/resources/webkit_strings_es-419.xtb
index 5ec0935..12bc57b 100644
--- a/webkit/glue/resources/webkit_strings_es-419.xtb
+++ b/webkit/glue/resources/webkit_strings_es-419.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="es-419">
<translation id="4519964825805946997">Error al instalar el complemento desde <ph name="URL"/></translation>
-<translation id="9186171386827445984">Cargando documento: páginas <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/>...</translation>
<translation id="1235745349614807883">Eliminar búsquedas recientes</translation>
<translation id="5048533449481078685">marcador de listas</translation>
<translation id="372362261556059955">Se necesita un complemento adicional</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">Error de instalación del complemento</translation>
<translation id="8141602879876242471">Se trata de un índice que admite búsquedas. Escribe las palabras clave de búsqueda:</translation>
<translation id="5650795167354946011">Después de instalar el complemento, haz clic aquí para actualizar</translation>
-<translation id="370665806235115550">Cargando...</translation>
<translation id="6845533974506654842">hacer clic</translation>
<translation id="8244226242650769279">mapa de imágenes</translation>
<translation id="2548326553472216322">No hay búsquedas recientes</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Confirma que deseas instalar el complemento <ph name="PLUGIN"/>. Sólo deberías instalar los complementos confiables.</translation>
<translation id="6663448176199120256">Búsquedas recientes</translation>
<translation id="2597378329261239068">Este documento está protegido por contraseña. Ingresa una contraseña.</translation>
-<translation id="7740050170769002709">Contenido HTML</translation>
+<translation id="6807599807928161586">área web</translation>
<translation id="5939518447894949180">Restablecer</translation>
<translation id="1842960171412779397">seleccionar</translation>
<translation id="7638452146404718955">Haz clic aquí para descargar el complemento</translation>
diff --git a/webkit/glue/resources/webkit_strings_es.xtb b/webkit/glue/resources/webkit_strings_es.xtb
index 8315543..5f9a245 100644
--- a/webkit/glue/resources/webkit_strings_es.xtb
+++ b/webkit/glue/resources/webkit_strings_es.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="es">
<translation id="4519964825805946997">Se ha producido un error al descargar el complemento de la página <ph name="URL"/>.</translation>
-<translation id="9186171386827445984">Cargando documento: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> páginas...</translation>
<translation id="1235745349614807883">Eliminar búsquedas recientes</translation>
<translation id="5048533449481078685">marcador de listas</translation>
<translation id="372362261556059955">Se necesita un complemento adicional</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">Se ha producido un error al instalar el complemento.</translation>
<translation id="8141602879876242471">Se trata de un índice que admite búsquedas. Introduce las palabras clave de búsqueda:</translation>
<translation id="5650795167354946011">Una vez que hayas instalado el complemento, haz clic aquí para actualizar la ventana.</translation>
-<translation id="370665806235115550">Cargando...</translation>
<translation id="6845533974506654842">pulsar</translation>
<translation id="8244226242650769279">mapa de imágenes</translation>
<translation id="2548326553472216322">No hay búsquedas recientes</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Confirma que quieres instalar el complemento <ph name="PLUGIN"/>. Solo debes instalar complementos en los que confíes.</translation>
<translation id="6663448176199120256">Búsquedas recientes</translation>
<translation id="2597378329261239068">Este documento está protegido por contraseña. Introduce una contraseña.</translation>
-<translation id="7740050170769002709">Contenido HTML</translation>
+<translation id="6807599807928161586">área web</translation>
<translation id="5939518447894949180">Restablecer</translation>
<translation id="1842960171412779397">seleccionar</translation>
<translation id="7638452146404718955">Haz clic aquí para descargar el complemento.</translation>
diff --git a/webkit/glue/resources/webkit_strings_et.xtb b/webkit/glue/resources/webkit_strings_et.xtb
index e5932ac..2ac3c7a 100644
--- a/webkit/glue/resources/webkit_strings_et.xtb
+++ b/webkit/glue/resources/webkit_strings_et.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="et">
<translation id="4519964825805946997">Pistikprogrammi installimine asukohast <ph name="URL"/> ebaõnnestus.</translation>
-<translation id="9186171386827445984">Dokumendi laadimine: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> lehte ...</translation>
<translation id="1235745349614807883">Kustuta viimased otsingud</translation>
<translation id="5048533449481078685">loendilooja</translation>
<translation id="372362261556059955">Vaja on täiendavat pistikprogrammi</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">Pistikprogrammi installimine nurjus</translation>
<translation id="8141602879876242471">See on otsitav indeks. Sisestage otsingu jaoks märksõnad:</translation>
<translation id="5650795167354946011">Pärast lisandmooduli installimist klõpsake värskendamiseks siin</translation>
-<translation id="370665806235115550">Laadimine...</translation>
<translation id="6845533974506654842">vajuta</translation>
<translation id="8244226242650769279">hüperpilt</translation>
<translation id="2548326553472216322">Pole viimaseid otsingud</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Palun kinnitage, et soovite pistikprogrammi <ph name="PLUGIN"/> installida. Peaksite installima vaid usaldusväärseid pistikprogramme.</translation>
<translation id="6663448176199120256">Viimased otsingud</translation>
<translation id="2597378329261239068">Dokument on parooliga kaitstud. Sisestage parool.</translation>
-<translation id="7740050170769002709">HTML-sisu</translation>
+<translation id="6807599807928161586">veebiala</translation>
<translation id="5939518447894949180">Lähtesta</translation>
<translation id="1842960171412779397">vali</translation>
<translation id="7638452146404718955">Pistikprogrammi allalaadimiseks klõpsake siin</translation>
diff --git a/webkit/glue/resources/webkit_strings_fa.xtb b/webkit/glue/resources/webkit_strings_fa.xtb
index 094ad9f..870dcf6 100644
--- a/webkit/glue/resources/webkit_strings_fa.xtb
+++ b/webkit/glue/resources/webkit_strings_fa.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="fa">
<translation id="4519964825805946997">نصب افزونه از <ph name="URL"/> ناموفق بود</translation>
-<translation id="9186171386827445984">در حال بارگیری سند: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> صفحات...</translation>
<translation id="1235745349614807883">پاک کردن جستجوهای اخیر</translation>
<translation id="5048533449481078685">علامت گذار لیست</translation>
<translation id="372362261556059955">افزونه دیگری مورد نیاز است</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">نصب افزونه انجام نشد</translation>
<translation id="8141602879876242471">این نمایه قابل جستجو است. کلمات کلیدی جستجو را وارد کنید:</translation>
<translation id="5650795167354946011">بعد از نصب افزونه، برای تازه کردن اینجا را کلیک کنید</translation>
-<translation id="370665806235115550">درحال بارگیری...</translation>
<translation id="6845533974506654842">فشار دادن</translation>
<translation id="8244226242650769279">نقشه تصویر</translation>
<translation id="2548326553472216322">جستجوی جدیدی وجود ندارد</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">لطفاً تأیید کنید که مایلید افزونه <ph name="PLUGIN"/> نصب شود. فقط باید افزونه هایی را نصب کنید که به آنها اعتماد دارید.</translation>
<translation id="6663448176199120256">جستجوهای جدید</translation>
<translation id="2597378329261239068">این سند توسط رمز ورود محافظت می شود. لطفاً یک رمز ورود وارد کنید.</translation>
-<translation id="7740050170769002709">محتوای HTML</translation>
+<translation id="6807599807928161586">حیطه وب</translation>
<translation id="5939518447894949180">بازنشانی</translation>
<translation id="1842960171412779397">انتخاب</translation>
<translation id="7638452146404718955">برای دانلود کردن افزونه اینجا را کلیک کنید</translation>
diff --git a/webkit/glue/resources/webkit_strings_fi.xtb b/webkit/glue/resources/webkit_strings_fi.xtb
index 604021f..4a1b6a3 100644
--- a/webkit/glue/resources/webkit_strings_fi.xtb
+++ b/webkit/glue/resources/webkit_strings_fi.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="fi">
<translation id="4519964825805946997">Laajennuksen asennus osoitteesta <ph name="URL"/> epäonnistui</translation>
-<translation id="9186171386827445984">Ladataan asiakirjaa: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> sivua...</translation>
<translation id="1235745349614807883">Poista viimeisimmät haut</translation>
<translation id="5048533449481078685">luettelon merkitsijä</translation>
<translation id="372362261556059955">Toinen laajennus vaaditaan</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">Laajennuksen asennus epäonnistui</translation>
<translation id="8141602879876242471">Tämä on haettavissa oleva hakemisto. Anna hakusanat:</translation>
<translation id="5650795167354946011">Päivitä laajennuksen asennuksen jälkeen napsauttamalla tästä</translation>
-<translation id="370665806235115550">Ladataan...</translation>
<translation id="6845533974506654842">paina</translation>
<translation id="8244226242650769279">kuvakartta</translation>
<translation id="2548326553472216322">Ei viimeisimpiä hakuja</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Vahvista, että haluat asentaa laajennuksen <ph name="PLUGIN"/>. Suosittelemme asentamaan vain laajennuksia, joihin luotat.</translation>
<translation id="6663448176199120256">Viimeisimmät haut</translation>
<translation id="2597378329261239068">Tämä asiakirja on suojattu salasanalla. Anna salasana.</translation>
-<translation id="7740050170769002709">HTML-sisältö</translation>
+<translation id="6807599807928161586">verkkoalue</translation>
<translation id="5939518447894949180">Tyhjennä</translation>
<translation id="1842960171412779397">Valitse</translation>
<translation id="7638452146404718955">Lataa laajennus napsauttamalla tätä</translation>
diff --git a/webkit/glue/resources/webkit_strings_fil.xtb b/webkit/glue/resources/webkit_strings_fil.xtb
index 8459aca..43f88c3 100644
--- a/webkit/glue/resources/webkit_strings_fil.xtb
+++ b/webkit/glue/resources/webkit_strings_fil.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="fil">
<translation id="4519964825805946997">Nabigong ma-install ang plug-in mula sa <ph name="URL"/></translation>
-<translation id="9186171386827445984">Nilo-load ang dokumento: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> (na) pahina...</translation>
<translation id="1235745349614807883">Lisiman ang Kasalukuyang Mga Paghahanap</translation>
<translation id="5048533449481078685">Ilista ang marker</translation>
<translation id="372362261556059955">Kinakailangan ang karagdagang plug-in</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">Nabigo ang pag-install ng plug-in</translation>
<translation id="8141602879876242471">Isa itong paghahanap ng index. Ipasok ang paghahanap sa mga keyword:</translation>
<translation id="5650795167354946011">Pagkatapos i-install ng plug-in, mag-click dito upang mag-refresh</translation>
-<translation id="370665806235115550">Kumakarga...</translation>
<translation id="6845533974506654842">pindutin</translation>
<translation id="8244226242650769279">mapa ng imahe</translation>
<translation id="2548326553472216322">Walang kamakailang mga paghahanap</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Pakikumpirma na gusto mong i-install ang <ph name="PLUGIN"/> plug-in na ito. Dapat mong i-install lamang ang mga plug-in na iyong pinagkakatiwalaan.</translation>
<translation id="6663448176199120256">Kasalukuyang Mga Paghahanap</translation>
<translation id="2597378329261239068">Protektado ng password ang dokumentong ito. Mangyaring magpasok ng password.</translation>
-<translation id="7740050170769002709">HTML na nilalaman</translation>
+<translation id="6807599807928161586">web area</translation>
<translation id="5939518447894949180">I-reset</translation>
<translation id="1842960171412779397">piliin</translation>
<translation id="7638452146404718955">Mag-click dito upang ma-download ang plug-in</translation>
diff --git a/webkit/glue/resources/webkit_strings_fr.xtb b/webkit/glue/resources/webkit_strings_fr.xtb
index ab1e32f..00ab953 100644
--- a/webkit/glue/resources/webkit_strings_fr.xtb
+++ b/webkit/glue/resources/webkit_strings_fr.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="fr">
<translation id="4519964825805946997">Échec de l'installation du plug-in depuis <ph name="URL"/></translation>
-<translation id="9186171386827445984">Chargement du document : <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> pages...</translation>
<translation id="1235745349614807883">Effacer les recherches récentes</translation>
<translation id="5048533449481078685">marqueur de liste</translation>
<translation id="372362261556059955">Plug-in supplémentaire requis</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">Échec de l'installation du plug-in</translation>
<translation id="8141602879876242471">Vous pouvez lancer des recherches dans cet index. Pour cela, entrez des mots clés de recherche :</translation>
<translation id="5650795167354946011">Après l'installation du plug-in, cliquez ici pour actualiser.</translation>
-<translation id="370665806235115550">Chargement...</translation>
<translation id="6845533974506654842">appuyer</translation>
<translation id="8244226242650769279">image map</translation>
<translation id="2548326553472216322">Aucune recherche récente</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Merci de confirmer que vous souhaitez installer le plug-in <ph name="PLUGIN"/>. N'installez que les plug-ins que vous considérez fiables.</translation>
<translation id="6663448176199120256">Recherches récentes</translation>
<translation id="2597378329261239068">Ce document est protégé par mot de passe. Veuillez saisir ce dernier.</translation>
-<translation id="7740050170769002709">Contenu HTML</translation>
+<translation id="6807599807928161586">Zone Web</translation>
<translation id="5939518447894949180">Réinitialiser</translation>
<translation id="1842960171412779397">sélectionner</translation>
<translation id="7638452146404718955">Cliquer ici pour télécharger le plug-in</translation>
diff --git a/webkit/glue/resources/webkit_strings_gu.xtb b/webkit/glue/resources/webkit_strings_gu.xtb
index ad48fa1..e7160bb 100644
--- a/webkit/glue/resources/webkit_strings_gu.xtb
+++ b/webkit/glue/resources/webkit_strings_gu.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="gu">
<translation id="4519964825805946997"><ph name="URL"/> થી પ્લગ-ઇન ઇન્સ્ટોલ કરવામાં નિષ્ફળ રહ્યાં</translation>
-<translation id="9186171386827445984">દસ્તાવેજ લોડ કરી રહ્યું છે: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> પૃષ્ઠ...</translation>
<translation id="1235745349614807883">હાલની શોધને સાફ કરો</translation>
<translation id="5048533449481078685">સૂચિ માર્કર</translation>
<translation id="372362261556059955">વધારાનું પ્લગ-ઇન આવશ્યક છે </translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">પ્લગ-ઇન ઇન્સ્ટોલેશન નિષ્ફળ ગયું</translation>
<translation id="8141602879876242471">આ એક શોધસક્ષમ અનુક્રમણિકા છે. શોધ કીવર્ડ્સ દાખલ કરો:</translation>
<translation id="5650795167354946011">પ્લગ-ઇન ઇન્સ્ટોલ કર્યા પછી, રીફ્રેશ કરવા અહીં ક્લિક કરો</translation>
-<translation id="370665806235115550">લોડ કરી રહ્યું છે...</translation>
<translation id="6845533974506654842">દબાવો</translation>
<translation id="8244226242650769279">છબી નકશો</translation>
<translation id="2548326553472216322">હાલની શોધો નથી</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">કૃપા કરીને પુષ્ટી કરો કે તમે <ph name="PLUGIN"/> પ્લગ-ઇન ઇન્સ્ટોલ કરવાનું પસંદ કરશો. તમારે ફક્ત તે જ પ્લગ-ઇન્સ ઇન્સ્ટોલ કરવા જોઈએ જે વિશ્વસ્ત હોય.</translation>
<translation id="6663448176199120256">તાજેતરની શોધ</translation>
<translation id="2597378329261239068">આ દસ્તાવેજ પાસવર્ડ સુરક્ષિત છે. કૃપા કરીને પાસવર્ડ દાખલ કરો.</translation>
-<translation id="7740050170769002709">HTML સામગ્રી</translation>
+<translation id="6807599807928161586">વેબ ક્ષેત્ર</translation>
<translation id="5939518447894949180">રીસેટ કરો</translation>
<translation id="1842960171412779397">પસંદ કરો</translation>
<translation id="7638452146404718955">પ્લગ-ઇન ડાઉનલોડ કરવા માટે અહીં ક્લિક કરો</translation>
diff --git a/webkit/glue/resources/webkit_strings_hi.xtb b/webkit/glue/resources/webkit_strings_hi.xtb
index e7ef77f..e9bf9e7 100644
--- a/webkit/glue/resources/webkit_strings_hi.xtb
+++ b/webkit/glue/resources/webkit_strings_hi.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="hi">
<translation id="4519964825805946997"><ph name="URL"/> से प्लग-इन स्थापित करने में विफल हुआ</translation>
-<translation id="9186171386827445984">दस्तावेज़ लोड कर रहा है: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> पृष्ठ...</translation>
<translation id="1235745349614807883">हाल ही की खोजें साफ़ करें</translation>
<translation id="5048533449481078685">सूची चिन्हक</translation>
<translation id="372362261556059955">अतिरिक्त प्‍लग-इन की आवश्यकता है</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">प्लग-इन स्थापना विफल हुई</translation>
<translation id="8141602879876242471">यह एक खोजने योग्य इंडेक्स है. खोज कुंजीशब्द प्रविष्ट करें :</translation>
<translation id="5650795167354946011">प्लग-इन स्थापित करने के बाद, रीफ़्रेश करने के लिए यहां क्लिक करें</translation>
-<translation id="370665806235115550">लोड हो रहा है ...</translation>
<translation id="6845533974506654842">दबाएँ</translation>
<translation id="8244226242650769279">चित्र मैप</translation>
<translation id="2548326553472216322">हाल ही में कोई खोज नहीं</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">कृपया पुष्टि करें कि आप <ph name="PLUGIN"/> प्लग-इन स्थापित करना चाहेंगे. आपको केवल वे प्लग-इन स्थापित करने चाहिए जिन पर आप विश्वास करते हैं.</translation>
<translation id="6663448176199120256">हाल ही में की गई खोजें</translation>
<translation id="2597378329261239068">यह दस्तावेज़ पासवर्ड सुरक्षित है. कृपया एक पासवर्ड दर्ज करें.</translation>
-<translation id="7740050170769002709">HTML सामग्री</translation>
+<translation id="6807599807928161586">वेब क्षेत्र</translation>
<translation id="5939518447894949180">पुन: सेट करें</translation>
<translation id="1842960171412779397">चुनें</translation>
<translation id="7638452146404718955">प्लग-इन डाउनलोड करने के लिए यहां क्लिक करें</translation>
diff --git a/webkit/glue/resources/webkit_strings_hr.xtb b/webkit/glue/resources/webkit_strings_hr.xtb
index dfef690..89458bb 100644
--- a/webkit/glue/resources/webkit_strings_hr.xtb
+++ b/webkit/glue/resources/webkit_strings_hr.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="hr">
<translation id="4519964825805946997">Nije uspjela instalacija dodatka s adrese <ph name="URL"/></translation>
-<translation id="9186171386827445984">Učitavanje dokumenta: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> stranica...</translation>
<translation id="1235745349614807883">Obriši najnovija pretraživanja</translation>
<translation id="5048533449481078685">oznaka popisa</translation>
<translation id="372362261556059955">Potreban je dodatni dodatak</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">Nije uspjela instalacija dodatka</translation>
<translation id="8141602879876242471">Ovaj je indeks moguće pretraživati. Unesite ključne riječi za pretraživanje:</translation>
<translation id="5650795167354946011">Nakon instalacije dodatka kliknite ovdje za osvježenje stranice</translation>
-<translation id="370665806235115550">Učitavanje...</translation>
<translation id="6845533974506654842">pritisni</translation>
<translation id="8244226242650769279">karta slika</translation>
<translation id="2548326553472216322">Nema najnovijih pretraživanja</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Potvrdite da želite instalirati dodatak <ph name="PLUGIN"/>. Instalirajte samo dodatke koje smatrate pouzdanima.</translation>
<translation id="6663448176199120256">Najnovija pretraživanja</translation>
<translation id="2597378329261239068">Ovaj je dokument zaštićen zaporkom. Unesite zaporku.</translation>
-<translation id="7740050170769002709">HTML sadržaj</translation>
+<translation id="6807599807928161586">web područje</translation>
<translation id="5939518447894949180">Ponovno postavi</translation>
<translation id="1842960171412779397">odaberi</translation>
<translation id="7638452146404718955">Kliknite ovdje za preuzimanje dodatka</translation>
diff --git a/webkit/glue/resources/webkit_strings_hu.xtb b/webkit/glue/resources/webkit_strings_hu.xtb
index 1b43f0f..848f2df 100644
--- a/webkit/glue/resources/webkit_strings_hu.xtb
+++ b/webkit/glue/resources/webkit_strings_hu.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="hu">
<translation id="4519964825805946997">A plug-in telepítése nem sikerült a következő helyről: <ph name="URL"/></translation>
-<translation id="9186171386827445984">Dokumentum betöltése: <ph name="NUMBER_OF_PAGES"/>/<ph name="PAGE_NUMBER"/>. oldal...</translation>
<translation id="1235745349614807883">Friss keresések törlése</translation>
<translation id="5048533449481078685">listajelölő</translation>
<translation id="372362261556059955">További plug-in szükséges</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">A plug-in telepítése sikertelen</translation>
<translation id="8141602879876242471">Ez egy kereshető index. Írjon be keresési kulcsszavakat:</translation>
<translation id="5650795167354946011">A plug-in telepítését követően kattintson ide a frissítéshez</translation>
-<translation id="370665806235115550">Betöltés…</translation>
<translation id="6845533974506654842">Gomb lenyomása</translation>
<translation id="8244226242650769279">képtérkép</translation>
<translation id="2548326553472216322">Nincsenek friss keresések</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Kérjük, erősítse meg, hogy valóban telepíteni szeretné a következő plug-int: <ph name="PLUGIN"/>. Csak azokat a plug-ineket telepítse, amelyekben megbízik.</translation>
<translation id="6663448176199120256">Friss keresések</translation>
<translation id="2597378329261239068">Ez a dokumentum jelszóval védett. Kérjük, adja meg a jelszót.</translation>
-<translation id="7740050170769002709">HTML-tartalom</translation>
+<translation id="6807599807928161586">internetes terület</translation>
<translation id="5939518447894949180">Visszaállítás</translation>
<translation id="1842960171412779397">Kiválasztás</translation>
<translation id="7638452146404718955">Ide kattintva letöltheti a plug-int</translation>
diff --git a/webkit/glue/resources/webkit_strings_id.xtb b/webkit/glue/resources/webkit_strings_id.xtb
index 50c97a2..6451c08 100644
--- a/webkit/glue/resources/webkit_strings_id.xtb
+++ b/webkit/glue/resources/webkit_strings_id.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="id">
<translation id="4519964825805946997">Gagal memasang pengaya dari <ph name="URL"/></translation>
-<translation id="9186171386827445984">Memuat dokumen: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> halaman...</translation>
<translation id="1235745349614807883">Hapus Penelusuran Barusan</translation>
<translation id="5048533449481078685">penanda daftar</translation>
<translation id="372362261556059955">Diperlukan pengaya tambahan</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">Pemasangan pengaya gagal</translation>
<translation id="8141602879876242471">Terdapat indeks yang dapat dicari. Masukkan kata kunci penelusuran:</translation>
<translation id="5650795167354946011">Setelah memasang pengaya, klik di sini untuk menyegarkan</translation>
-<translation id="370665806235115550">Membuka...</translation>
<translation id="6845533974506654842">tekan</translation>
<translation id="8244226242650769279">gambar peta</translation>
<translation id="2548326553472216322">Tidak ada penelusuran terkini</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Konfirmasikan bahwa Anda ingin memasang pengaya <ph name="PLUGIN"/>. Anda harus memasang pengaya yang Anda percayai saja.</translation>
<translation id="6663448176199120256">Penelusuran Barusan</translation>
<translation id="2597378329261239068">Dokumen ini dilindungi sandi. Masukkan sandi.</translation>
-<translation id="7740050170769002709">Konten HTML</translation>
+<translation id="6807599807928161586">area Web</translation>
<translation id="5939518447894949180">Atur ulang</translation>
<translation id="1842960171412779397">pilih</translation>
<translation id="7638452146404718955">Klik di sini untuk mengunduh pengaya</translation>
diff --git a/webkit/glue/resources/webkit_strings_it.xtb b/webkit/glue/resources/webkit_strings_it.xtb
index 1fae27f..61c1e79 100644
--- a/webkit/glue/resources/webkit_strings_it.xtb
+++ b/webkit/glue/resources/webkit_strings_it.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="it">
<translation id="4519964825805946997">Installazione del plug-in da <ph name="URL"/> non riuscita</translation>
-<translation id="9186171386827445984">Caricamento del documento in corso: pagine <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/>...</translation>
<translation id="1235745349614807883">Cancella ricerche recenti</translation>
<translation id="5048533449481078685">indicatore elenco</translation>
<translation id="372362261556059955">È necessario un plug-in aggiuntivo</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">Installazione del plug-in non riuscita</translation>
<translation id="8141602879876242471">Questo è un indice di ricerca. Inserisci le parole chiave di ricerca:</translation>
<translation id="5650795167354946011">Dopo aver installato il plug-in, fai clic qui per aggiornare</translation>
-<translation id="370665806235115550">Caricamento in corso...</translation>
<translation id="6845533974506654842">premi</translation>
<translation id="8244226242650769279">image map</translation>
<translation id="2548326553472216322">Nessuna ricerca recente</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Conferma che desideri installare il plug-in <ph name="PLUGIN"/>. Dovresti installare soltanto plug-in attendibili.</translation>
<translation id="6663448176199120256">Ricerche recenti</translation>
<translation id="2597378329261239068">Questo documento è protetto da password. Inserisci una password.</translation>
-<translation id="7740050170769002709">Contenuti HTML</translation>
+<translation id="6807599807928161586">area web</translation>
<translation id="5939518447894949180">Ripristina</translation>
<translation id="1842960171412779397">seleziona</translation>
<translation id="7638452146404718955">Fai clic qui per scaricare il plug-in</translation>
diff --git a/webkit/glue/resources/webkit_strings_iw.xtb b/webkit/glue/resources/webkit_strings_iw.xtb
index f748311..436b298 100644
--- a/webkit/glue/resources/webkit_strings_iw.xtb
+++ b/webkit/glue/resources/webkit_strings_iw.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="iw">
<translation id="4519964825805946997">התקנת הפלאגין מתוך <ph name="URL"/> נכשלה</translation>
-<translation id="9186171386827445984">טוען מסמך: דפים <ph name="NUMBER_OF_PAGES"/>/<ph name="PAGE_NUMBER"/>...</translation>
<translation id="1235745349614807883">הסר חיפושים אחרונים</translation>
<translation id="5048533449481078685">סמן רשימה</translation>
<translation id="372362261556059955">פלאגין נוסף נחוץ</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">התקנת הפלאגין נכשלה</translation>
<translation id="8141602879876242471">זהו אינדקס שניתן לבצע בו חיפוש. הזן מילות מפתח לחיפוש:</translation>
<translation id="5650795167354946011">לאחר התקנת הפלאגין, לחץ כאן לרענון</translation>
-<translation id="370665806235115550">טוען...</translation>
<translation id="6845533974506654842">לחץ</translation>
<translation id="8244226242650769279">מפת תמונות</translation>
<translation id="2548326553472216322">אין חיפושים אחרונים</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">אשר שברצונך להתקין את הפלאגין <ph name="PLUGIN"/>. יש להתקין רכיבי פלאגין שאתה בוטח בהם בלבד.</translation>
<translation id="6663448176199120256">חיפושים אחרונים</translation>
<translation id="2597378329261239068">מסמך זה מוגן באמצעות סיסמה. הזן סיסמה.</translation>
-<translation id="7740050170769002709">תוכן HTML</translation>
+<translation id="6807599807928161586">אזור אינטרנט</translation>
<translation id="5939518447894949180">אפס</translation>
<translation id="1842960171412779397">בחר</translation>
<translation id="7638452146404718955">לחץ כאן להורדת פלאגין</translation>
diff --git a/webkit/glue/resources/webkit_strings_ja.xtb b/webkit/glue/resources/webkit_strings_ja.xtb
index 865979d..2eccba2 100644
--- a/webkit/glue/resources/webkit_strings_ja.xtb
+++ b/webkit/glue/resources/webkit_strings_ja.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="ja">
<translation id="4519964825805946997"><ph name="URL"/> からプラグインをインストールできませんでした</translation>
-<translation id="9186171386827445984">ドキュメントの読み込み中: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> ページ...</translation>
<translation id="1235745349614807883">最近の検索履歴を消去</translation>
<translation id="5048533449481078685">リスト マーカー</translation>
<translation id="372362261556059955">追加のプラグインが必要です</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">プラグインをインストールできませんでした</translation>
<translation id="8141602879876242471">このインデックスは検索できます。キーワードを入力してください:</translation>
<translation id="5650795167354946011">プラグインをインストールした後は、ここをクリックして更新を行ってください</translation>
-<translation id="370665806235115550">読み込み中...</translation>
<translation id="6845533974506654842">押す</translation>
<translation id="8244226242650769279">イメージ マップ</translation>
<translation id="2548326553472216322">最近の検索はありません</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">この <ph name="PLUGIN"/> プラグインをインストールしてもよいかご確認ください。信頼できるプラグインのみをインストールする必要があります。</translation>
<translation id="6663448176199120256">最近の検索</translation>
<translation id="2597378329261239068">このドキュメントはパスワードで保護されています。パスワードを入力してください。</translation>
-<translation id="7740050170769002709">HTML コンテンツ</translation>
+<translation id="6807599807928161586">ウェブ領域</translation>
<translation id="5939518447894949180">リセット</translation>
<translation id="1842960171412779397">選択</translation>
<translation id="7638452146404718955">ここをクリックしてプラグインをダウンロード</translation>
diff --git a/webkit/glue/resources/webkit_strings_kn.xtb b/webkit/glue/resources/webkit_strings_kn.xtb
index 9a8f827..61dbd2c 100644
--- a/webkit/glue/resources/webkit_strings_kn.xtb
+++ b/webkit/glue/resources/webkit_strings_kn.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="kn">
<translation id="4519964825805946997"><ph name="URL"/> ನಿಂದ ಪ್ಲಗ್-ಇನ್ ಅನ್ನು ಸ್ಥಾಪಿಸುವಲ್ಲಿ ವಿಫಲವಾಗಿದೆ</translation>
-<translation id="9186171386827445984">ಲೋಡಿಂಗ್ ಡಾಕ್ಯುಮೆಂಟ್: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> ಪುಟಗಳು...</translation>
<translation id="1235745349614807883">ಇತ್ತೀಚಿನ ಹುಡುಕಾಟವನ್ನು ತೆರವುಗೊಳಿಸಿ</translation>
<translation id="5048533449481078685">ಪಟ್ಟಿ ಗುರುತು</translation>
<translation id="372362261556059955">ಹೆಚ್ಚುವರಿ ಪ್ಲಗ್-ಇನ್ ಅಗತ್ಯವಿದೆ</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">ಪ್ಲಗ್-ಇನ್ ಅಳವಡಿಸುವಿಕೆಯು ವಿಫಲವಾಗಿದೆ</translation>
<translation id="8141602879876242471">ಇದು ಹುಡುಕಾಡಬಹುದಾದ ಸೂಚಿಕೆ ಹುಡುಕಾಟ ಕೀವರ್ಡ್‌ಗಳನ್ನು ನಮೂದಿಸಿ:</translation>
<translation id="5650795167354946011">ಪ್ಲಗ್-ಇನ್ ಸ್ಥಾಪನೆ ಮಾಡಿದ ನಂತರ, ರಿಫ್ರೆಶ್‌‌ ಮಾಡಲು ಇಲ್ಲಿ ಕ್ಲಿಕ್ ಮಾಡಿ</translation>
-<translation id="370665806235115550">ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ...</translation>
<translation id="6845533974506654842">ಒತ್ತಿ</translation>
<translation id="8244226242650769279">ಇಮೇಜ್ ನಕ್ಷೆ</translation>
<translation id="2548326553472216322">ಇತ್ತೀಚಿನ ಹುಡುಕಾಟಗಳು ಇಲ್ಲ</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">ನೀವು <ph name="PLUGIN"/> ಪ್ಲಗ್-ಇನ್ ಅನ್ನು ಅಳವಡಿಸಲು ಬಯಸುವುದಾದಲ್ಲಿ ದಯವಿಟ್ಟು ಖಚಿತಪಡಿಸಿ. ನೀವು ನಂಬುವಂತಹ ಫ್ಲಗ್-ಇನ್‌ಗಳನ್ನು ಮಾತ್ರ ನೀವು ಅಳವಡಿಸಬೇಕು.</translation>
<translation id="6663448176199120256">ಇತ್ತೀಚಿನ ಹುಡುಕಾಟಗಳು</translation>
<translation id="2597378329261239068">ಈ ಡಾಕ್ಯುಮೆಂಟ್‌ ಅನ್ನು ಪಾಸ್‌ವರ್ಡ್‌ನಿಂದ ರಕ್ಷಿಸಲಾಗಿದೆ. ದಯವಿಟ್ಟು ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ನಮೂದಿಸಿ.</translation>
-<translation id="7740050170769002709">HTML ವಿಷಯ</translation>
+<translation id="6807599807928161586">ವೆಬ್ ಪ್ರದೇಶ</translation>
<translation id="5939518447894949180">ಮರುಹೊಂದಿಸು</translation>
<translation id="1842960171412779397">ಆಯ್ಕೆ ಮಾಡಿ</translation>
<translation id="7638452146404718955">ಪ್ಲಗ್-ಇನ್ ಅನ್ನು ಡೌನ್‌ಲೋಡ್ ಮಾಡಲು ಇಲ್ಲಿ ಕ್ಲಿಕ್ ಮಾಡಿ</translation>
diff --git a/webkit/glue/resources/webkit_strings_ko.xtb b/webkit/glue/resources/webkit_strings_ko.xtb
index f3e829e..819c8ce 100644
--- a/webkit/glue/resources/webkit_strings_ko.xtb
+++ b/webkit/glue/resources/webkit_strings_ko.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="ko">
<translation id="4519964825805946997"><ph name="URL"/>의 플러그인 설치 실패</translation>
-<translation id="9186171386827445984">문서 로드 중: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/>페이지</translation>
<translation id="1235745349614807883">최근 검색 삭제</translation>
<translation id="5048533449481078685">목록 표시기</translation>
<translation id="372362261556059955">추가 플러그인 필요</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">플러그인 설치 실패</translation>
<translation id="8141602879876242471">이것은 검색 색인합니다. 검색 키워드 입력:</translation>
<translation id="5650795167354946011">플러그인 설치 후 여기를 클릭하여 새로고침</translation>
-<translation id="370665806235115550">로드 중...</translation>
<translation id="6845533974506654842">누르기</translation>
<translation id="8244226242650769279">이미지 지도</translation>
<translation id="2548326553472216322">최근 수행된 검색 없음</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419"><ph name="PLUGIN"/> 플러그인을 설치할지 여부를 확인하시기 바랍니다. 신뢰할 수 있는 플러그인만 설치해야 합니다.</translation>
<translation id="6663448176199120256">최근 수행된 검색</translation>
<translation id="2597378329261239068">문서가 비밀번호로 보호되고 있습니다. 비밀번호를 입력하세요.</translation>
-<translation id="7740050170769002709">HTML 콘텐츠</translation>
+<translation id="6807599807928161586">웹 영역</translation>
<translation id="5939518447894949180">재설정</translation>
<translation id="1842960171412779397">선택</translation>
<translation id="7638452146404718955">여기를 클릭하여 플러그인 다운로드</translation>
diff --git a/webkit/glue/resources/webkit_strings_lt.xtb b/webkit/glue/resources/webkit_strings_lt.xtb
index 7138796..8e8a7a7 100644
--- a/webkit/glue/resources/webkit_strings_lt.xtb
+++ b/webkit/glue/resources/webkit_strings_lt.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="lt">
<translation id="4519964825805946997">Nepavyko įdiegti papildinio iš <ph name="URL"/></translation>
-<translation id="9186171386827445984">Įkeliamas dokumentas: <ph name="PAGE_NUMBER"/> / <ph name="NUMBER_OF_PAGES"/> psl...</translation>
<translation id="1235745349614807883">Išvalyti pastarąsias paieškas</translation>
<translation id="5048533449481078685">sąrašo žymeklis</translation>
<translation id="372362261556059955">Reikia papildomo papildinio</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">Papildinio diegimas nepavyko</translation>
<translation id="8141602879876242471">Tai yra ieškotinas indeksas. Įveskite paieškos raktinių žodžių:</translation>
<translation id="5650795167354946011">Įdiegę papildinį spustelėkite čia, kad puslapis būtų atnaujintas</translation>
-<translation id="370665806235115550">Įkeliama...</translation>
<translation id="6845533974506654842">paspausti</translation>
<translation id="8244226242650769279">paveikslėlio žemėlapis</translation>
<translation id="2548326553472216322">Pastaruoju metu paieškų nevykdyta</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Patvirtinkite, kad norite įdiegti šį „<ph name="PLUGIN"/>“ papildinį. Turėtumėte diegti tik tuos papildinius, kurie patikimi.</translation>
<translation id="6663448176199120256">Naujausios paieškos</translation>
<translation id="2597378329261239068">Šis dokumentas apsaugotas slaptažodžiu. Įveskite slaptažodį.</translation>
-<translation id="7740050170769002709">HTML turinys</translation>
+<translation id="6807599807928161586">interneto sritis</translation>
<translation id="5939518447894949180">Nustatyti iš naujo</translation>
<translation id="1842960171412779397">pasirinkti</translation>
<translation id="7638452146404718955">Spustelėkite čia, kad atsisiųstumėte papildinį</translation>
diff --git a/webkit/glue/resources/webkit_strings_lv.xtb b/webkit/glue/resources/webkit_strings_lv.xtb
index f070834..c97eb32 100644
--- a/webkit/glue/resources/webkit_strings_lv.xtb
+++ b/webkit/glue/resources/webkit_strings_lv.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="lv">
<translation id="4519964825805946997">Neizdevās instalēt spraudni no <ph name="URL"/></translation>
-<translation id="9186171386827445984">Notiek dokumenta ielāde: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> lappuses...</translation>
<translation id="1235745349614807883">Dzēst nesenos meklējumus</translation>
<translation id="5048533449481078685">sarakstu marķieris</translation>
<translation id="372362261556059955">Nepieciešams papildu spraudnis</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">Spraudņa instalēšana neizdevās</translation>
<translation id="8141602879876242471">Šis ir indekss ar meklēšanas iespējām. Ievadīt meklēšanas atslēgvārdus:</translation>
<translation id="5650795167354946011">Pēc spraudņa instalēšanas noklikšķiniet šeit, lai atsvaidzinātu</translation>
-<translation id="370665806235115550">Notiek ielāde...</translation>
<translation id="6845533974506654842">nospiest</translation>
<translation id="8244226242650769279">attēlu karte</translation>
<translation id="2548326553472216322">Nav nesenu meklējumu</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Lūdzu, apstipriniet, ka vēlaties instalēt <ph name="PLUGIN"/> spraudni. Jums ir jāinstalē tikai tie spraudņi, kuriem uzticaties.</translation>
<translation id="6663448176199120256">Neseni meklējumi</translation>
<translation id="2597378329261239068">Šis dokuments ir aizsargāts ar paroli. Lūdzu, ievadiet paroli.</translation>
-<translation id="7740050170769002709">HTML saturs</translation>
+<translation id="6807599807928161586">tīmekļa apgabals</translation>
<translation id="5939518447894949180">Atiestatīt</translation>
<translation id="1842960171412779397">Atlasiet</translation>
<translation id="7638452146404718955">Noklikšķiniet šeit, lai lejupielādētu spraudni</translation>
diff --git a/webkit/glue/resources/webkit_strings_ml.xtb b/webkit/glue/resources/webkit_strings_ml.xtb
index fdf0843..437330d 100644
--- a/webkit/glue/resources/webkit_strings_ml.xtb
+++ b/webkit/glue/resources/webkit_strings_ml.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="ml">
<translation id="4519964825805946997"><ph name="URL"/> എന്നതില്‍‌ നിന്നുള്ള പ്ലഗ്-ഇന്‍‌ ഇന്‍‌സ്റ്റാളുചെയ്യുന്നതിന് പരാജയപ്പെട്ടു</translation>
-<translation id="9186171386827445984">പ്രമാണങ്ങള്‍ ലോഡുചെയ്യുന്നു: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> പേജുകള്‍...</translation>
<translation id="1235745349614807883">അടുത്തിടെയുള്ള തിരയലുകള്‍ മായ്ക്കുക</translation>
<translation id="5048533449481078685">പട്ടിക മാര്‍ക്കര്‍</translation>
<translation id="372362261556059955">കൂടുതല്‍‌ പ്ലഗ്-ഇന്‍‌ ആവശ്യമുണ്ട്‌‌</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">പ്ലഗ്-ഇന്‍‌ ഇന്‍‌സ്റ്റാളേഷന്‍‌ പരാജയപ്പെട്ടു</translation>
<translation id="8141602879876242471">ഇത് തിരയാവുന്ന സൂചികയാണ്. തിരയല്‍ കീവേഡുകള്‍ നല്‍കുക:</translation>
<translation id="5650795167354946011">പ്ലഗ്-ഇന്‍‌ ഇന്‍‌സ്റ്റാളുചെയ്തതിനുശേഷം, പുതുക്കുന്നതിന് ഇവിടെ ക്ലിക്കുചെയ്യുക</translation>
-<translation id="370665806235115550">ലോഡ്ചെയ്യുന്നു...</translation>
<translation id="6845533974506654842">അമര്‍ത്തുക</translation>
<translation id="8244226242650769279">ഇമേജ് മാപ്പ്</translation>
<translation id="2548326553472216322">സമീപകാല തിരയലുകള്‍ ഇല്ല</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">നിങ്ങള്‍‌ ഈ <ph name="PLUGIN"/> പ്ലഗ്-ഇന്‍‌ ഇന്‍‌സ്റ്റാളുചെയ്യാന്‍‌ താല്‍‌പ്പര്യപ്പെടുന്നുവെന്നത് ദയവായി സ്ഥിരീകരിക്കുക. നിങ്ങള്‍‌ വിശ്വസിക്കുന്ന പ്ലഗ്-ഇനുകള്‍‌ മാത്രമേ ഇന്‍‌സ്റ്റാള്‍‌ ചെയ്യാവൂ.</translation>
<translation id="6663448176199120256">സമീപകാല തിരയലുകള്‍</translation>
<translation id="2597378329261239068">ഈ പ്രമാണം പാസ്‌വേഡ് പരിരക്ഷിതമാണ്. ദയവായി ഒരു പാസ്‌വേഡ് നല്‍‌കുക.</translation>
-<translation id="7740050170769002709">HTML ഉള്ളടക്കം</translation>
+<translation id="6807599807928161586">വെബ് മേഖല</translation>
<translation id="5939518447894949180">വീണ്ടും സജ്ജീകരിക്കുക</translation>
<translation id="1842960171412779397">തിരഞ്ഞെടുക്കൂ</translation>
<translation id="7638452146404718955">പ്ലഗ്-ഇന്‍‌ ഡൌണ്‍‌ലോഡുചെയ്യുന്നതിന് ഇവിടെ ക്ലിക്കുചെയ്യുക</translation>
diff --git a/webkit/glue/resources/webkit_strings_mr.xtb b/webkit/glue/resources/webkit_strings_mr.xtb
index da03fe1..3061c16 100644
--- a/webkit/glue/resources/webkit_strings_mr.xtb
+++ b/webkit/glue/resources/webkit_strings_mr.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="mr">
<translation id="4519964825805946997"><ph name="URL"/> वरून प्लग-इन स्थापित करणे अयशस्वी</translation>
-<translation id="9186171386827445984">दस्तऐवज लोड करत आहे: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> पृष्ठे...</translation>
<translation id="1235745349614807883">अलीकडील शोध साफ करा</translation>
<translation id="5048533449481078685">सूची चिन्हक</translation>
<translation id="372362261556059955">अतिरिक्त प्लग-इन आवश्यक</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">प्लग-इन स्थापना अयशस्वी</translation>
<translation id="8141602879876242471">ही शोध घेण्यायोग्य अनुक्रमणिका आहे. शोध कीवर्ड प्रविष्ट करा:</translation>
<translation id="5650795167354946011">प्लग-इन स्थापित केल्यानंतर, रीफ्रेश करण्यासाठी येथे क्लिक करा</translation>
-<translation id="370665806235115550">लोड करीत आहे...</translation>
<translation id="6845533974506654842">दाबा</translation>
<translation id="8244226242650769279">प्रतिमा नकाशा</translation>
<translation id="2548326553472216322">अलीकडील शोध नाहीत</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">कृपया आपल्याला प्लग-इन <ph name="PLUGIN"/> स्थापित करणे आवडत असल्याची पुष्टी करा. आपण आपला विश्वास असलेले प्लग-इन्स फक्त स्थापित करावे. </translation>
<translation id="6663448176199120256">अलीकडील शोध</translation>
<translation id="2597378329261239068">हा दस्तऐवज संकेतशब्द संरक्षित आहे. कृपया संकेतशब्द प्रविष्ट करा.</translation>
-<translation id="7740050170769002709">HTML सामुग्री</translation>
+<translation id="6807599807928161586">वेब क्षेत्र</translation>
<translation id="5939518447894949180">रीसेट करा</translation>
<translation id="1842960171412779397">निवडा</translation>
<translation id="7638452146404718955">प्लग-इन डाउनलोड करण्यासाठी येथे क्लिक करा</translation>
diff --git a/webkit/glue/resources/webkit_strings_nl.xtb b/webkit/glue/resources/webkit_strings_nl.xtb
index d3b90a2..df39241 100644
--- a/webkit/glue/resources/webkit_strings_nl.xtb
+++ b/webkit/glue/resources/webkit_strings_nl.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="nl">
<translation id="4519964825805946997">Het installeren van de invoegtoepassing van <ph name="URL"/> is mislukt</translation>
-<translation id="9186171386827445984">Document wordt geladen: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> pagina's...</translation>
<translation id="1235745349614807883">Recente zoekopdrachten wissen</translation>
<translation id="5048533449481078685">lijstmarkering</translation>
<translation id="372362261556059955">Aanvullende invoegtoepassing vereist</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">De installatie van de invoegtoepassing is mislukt</translation>
<translation id="8141602879876242471">Dit is een doorzoekbare index. Geef zoekwoorden op:</translation>
<translation id="5650795167354946011">Klik hier na het installeren van de invoegtoepassing om te vernieuwen</translation>
-<translation id="370665806235115550">Laden...</translation>
<translation id="6845533974506654842">Indrukken</translation>
<translation id="8244226242650769279">image map</translation>
<translation id="2548326553472216322">Geen recente zoekopdrachten</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Bevestig dat u de invoegtoepassing van <ph name="PLUGIN"/> wilt installeren. U moet alleen invoegtoepassingen installeren die u vertrouwt.</translation>
<translation id="6663448176199120256">Recente zoekopdrachten</translation>
<translation id="2597378329261239068">Dit document is beveiligd met een wachtwoord. Geef een wachtwoord op.</translation>
-<translation id="7740050170769002709">HTML-inhoud</translation>
+<translation id="6807599807928161586">webgedeelte</translation>
<translation id="5939518447894949180">Herstellen</translation>
<translation id="1842960171412779397">Selecteren</translation>
<translation id="7638452146404718955">Klik hier om de invoegtoepassing te downloaden</translation>
diff --git a/webkit/glue/resources/webkit_strings_no.xtb b/webkit/glue/resources/webkit_strings_no.xtb
index 6346872..c94ad8f 100644
--- a/webkit/glue/resources/webkit_strings_no.xtb
+++ b/webkit/glue/resources/webkit_strings_no.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="no">
<translation id="4519964825805946997">Kunne ikke installere programtillegget fra <ph name="URL"/></translation>
-<translation id="9186171386827445984">Laster inn dokument: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> sider</translation>
<translation id="1235745349614807883">Fjern nylige søk</translation>
<translation id="5048533449481078685">listemarkør</translation>
<translation id="372362261556059955">Ekstra programtillegg kreves</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">Installering av programtillegg mislyktes</translation>
<translation id="8141602879876242471">Dette er en søkbar indeks. Angi søkeordene:</translation>
<translation id="5650795167354946011">Når programtillegget er installert, klikker du her for å oppdatere</translation>
-<translation id="370665806235115550">Laster inn...</translation>
<translation id="6845533974506654842">trykk</translation>
<translation id="8244226242650769279">bildekart</translation>
<translation id="2548326553472216322">Ingen nylige søk</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Bekreft at du ønsker å installere programtillegget <ph name="PLUGIN"/>. Du bør kun installere programtillegg du stoler på.</translation>
<translation id="6663448176199120256">Nylige søk</translation>
<translation id="2597378329261239068">Dette dokumentet er passordbeskyttet. Skriv inn et passord.</translation>
-<translation id="7740050170769002709">HTML-innhold</translation>
+<translation id="6807599807928161586">nettområde</translation>
<translation id="5939518447894949180">Tilbakestill</translation>
<translation id="1842960171412779397">velg</translation>
<translation id="7638452146404718955">Klikk her for å laste ned programtillegget</translation>
diff --git a/webkit/glue/resources/webkit_strings_pl.xtb b/webkit/glue/resources/webkit_strings_pl.xtb
index b37ec7e..ea4f6cf 100644
--- a/webkit/glue/resources/webkit_strings_pl.xtb
+++ b/webkit/glue/resources/webkit_strings_pl.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="pl">
<translation id="4519964825805946997">Nie można zainstalować wtyczki dostępnej pod adresem <ph name="URL"/></translation>
-<translation id="9186171386827445984">Wczytywanie dokumentu: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> stron...</translation>
<translation id="1235745349614807883">Wyczyść ostatnie wyszukiwania</translation>
<translation id="5048533449481078685">znacznik listy</translation>
<translation id="372362261556059955">Potrzebna jest dodatkowa wtyczka</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">Instalacja wtyczki nie powiodła się</translation>
<translation id="8141602879876242471">Ten indeks można przeszukiwać. Wprowadź wyszukiwane słowa kluczowe:</translation>
<translation id="5650795167354946011">Po zainstalowaniu wtyczki kliknij tutaj, aby odświeżyć okno</translation>
-<translation id="370665806235115550">Ładowanie...</translation>
<translation id="6845533974506654842">naciśnij</translation>
<translation id="8244226242650769279">mapa grafiki</translation>
<translation id="2548326553472216322">Brak ostatnich wyszukiwań</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Potwierdź zamiar zainstalowania wtyczki <ph name="PLUGIN"/>. Należy instalować wyłącznie zaufane wtyczki.</translation>
<translation id="6663448176199120256">Ostatnie wyszukiwania</translation>
<translation id="2597378329261239068">Ten dokument jest chroniony hasłem. Wprowadź hasło.</translation>
-<translation id="7740050170769002709">Treść HTML</translation>
+<translation id="6807599807928161586">obszar sieci</translation>
<translation id="5939518447894949180">Resetuj</translation>
<translation id="1842960171412779397">wybierz</translation>
<translation id="7638452146404718955">Kliknij tutaj, aby pobrać wtyczkę</translation>
diff --git a/webkit/glue/resources/webkit_strings_pt-BR.xtb b/webkit/glue/resources/webkit_strings_pt-BR.xtb
index 5233854..b34c7cb 100644
--- a/webkit/glue/resources/webkit_strings_pt-BR.xtb
+++ b/webkit/glue/resources/webkit_strings_pt-BR.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="pt-BR">
<translation id="4519964825805946997">Falha ao instalar o plug-in de <ph name="URL"/></translation>
-<translation id="9186171386827445984">Carregando documento: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> páginas...</translation>
<translation id="1235745349614807883">Limpar pesquisas recentes</translation>
<translation id="5048533449481078685">marcador de lista</translation>
<translation id="372362261556059955">Plug-in adicional necessário</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">Falha na instalação do plug-in</translation>
<translation id="8141602879876242471">Este é um índice pesquisável. Insira palavras-chave de pesquisa:</translation>
<translation id="5650795167354946011">Depois de instalar o plug-in, clique aqui para atualizar</translation>
-<translation id="370665806235115550">Carregando...</translation>
<translation id="6845533974506654842">pressione</translation>
<translation id="8244226242650769279">mapa de imagens</translation>
<translation id="2548326553472216322">Nenhuma pesquisa recente</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Confirme se você deseja instalar o plug-in do <ph name="PLUGIN"/>. Você deve instalar apenas plug-ins em que você confia.</translation>
<translation id="6663448176199120256">Pesquisas recentes</translation>
<translation id="2597378329261239068">Este documento está protegido por senha. Digite a senha.</translation>
-<translation id="7740050170769002709">Conteúdo HTML</translation>
+<translation id="6807599807928161586">área da web</translation>
<translation id="5939518447894949180">Redefinir</translation>
<translation id="1842960171412779397">selecione</translation>
<translation id="7638452146404718955">Clique aqui para fazer download do plug-in</translation>
diff --git a/webkit/glue/resources/webkit_strings_pt-PT.xtb b/webkit/glue/resources/webkit_strings_pt-PT.xtb
index a93bd4f..817cdf4 100644
--- a/webkit/glue/resources/webkit_strings_pt-PT.xtb
+++ b/webkit/glue/resources/webkit_strings_pt-PT.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="pt-PT">
<translation id="4519964825805946997">Falha ao instalar o plug-in de <ph name="URL"/></translation>
-<translation id="9186171386827445984">A carregar o documento: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> páginas...</translation>
<translation id="1235745349614807883">Limpar pesquisas recentes</translation>
<translation id="5048533449481078685">marcador de lista</translation>
<translation id="372362261556059955">Plug-in adicional requerido</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">A instalação do plug-in falhou</translation>
<translation id="8141602879876242471">Este índice é pesquisável. Introduza palavras-chave de pesquisa:</translation>
<translation id="5650795167354946011">Após instalar o plug-in, clique aqui para actualizar</translation>
-<translation id="370665806235115550">A carregar...</translation>
<translation id="6845533974506654842">premir</translation>
<translation id="8244226242650769279">mapa de imagem</translation>
<translation id="2548326553472216322">Nenhuma pesquisa recente</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Confirme se pretende instalar o plug-in do <ph name="PLUGIN"/>. Deve instalar apenas plug-ins fidedignos.</translation>
<translation id="6663448176199120256">Pesquisas recentes</translation>
<translation id="2597378329261239068">Este documento está protegido por palavra-passe. Introduza uma palavra-passe.</translation>
-<translation id="7740050170769002709">Conteúdo HTML</translation>
+<translation id="6807599807928161586">Área Web</translation>
<translation id="5939518447894949180">Repor</translation>
<translation id="1842960171412779397">seleccionar</translation>
<translation id="7638452146404718955">Clique aqui para transferir o plug-in</translation>
diff --git a/webkit/glue/resources/webkit_strings_ro.xtb b/webkit/glue/resources/webkit_strings_ro.xtb
index eeebfc3..2f8ec55 100644
--- a/webkit/glue/resources/webkit_strings_ro.xtb
+++ b/webkit/glue/resources/webkit_strings_ro.xtb
@@ -1,46 +1,44 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="ro">
-<translation id="4519964825805946997">Instalarea pluginului de la <ph name="URL"/> a eșuat</translation>
-<translation id="9186171386827445984">Se încarcă documentul: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> (de) pagini...</translation>
-<translation id="1235745349614807883">Ștergeți căutările recente</translation>
+<translation id="4519964825805946997">Instalarea pluginului de la <ph name="URL"/> a eşuat</translation>
+<translation id="1235745349614807883">Ştergeţi căutările recente</translation>
<translation id="5048533449481078685">marcator listă</translation>
<translation id="372362261556059955">Este necesar un plugin suplimentar</translation>
<translation id="4202807286478387388">Salt</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
-<translation id="7658239707568436148">Anulați</translation>
-<translation id="795667975304826397">Nu s-au ales fișiere</translation>
-<translation id="1416462845279468967">Instalarea pluginului a eșuat</translation>
-<translation id="8141602879876242471">Acesta este un index în care se poate căuta. Introduceți cuvintele cheie pentru căutare:</translation>
-<translation id="5650795167354946011">După instalarea pluginului, faceți clic aici pentru a actualiza</translation>
-<translation id="370665806235115550">Se încarcă...</translation>
-<translation id="6845533974506654842">Apăsați</translation>
+<translation id="7658239707568436148">Anulaţi</translation>
+<translation id="795667975304826397">Nu s-au ales fişiere</translation>
+<translation id="1416462845279468967">Instalarea pluginului a eşuat</translation>
+<translation id="8141602879876242471">Acesta este un index în care se poate căuta. Introduceţi cuvintele cheie pentru căutare:</translation>
+<translation id="5650795167354946011">După instalarea pluginului, faceţi clic aici pentru a actualiza</translation>
+<translation id="6845533974506654842">Apăsaţi</translation>
<translation id="8244226242650769279">hartă cu imagini</translation>
<translation id="2548326553472216322">Nicio căutare recentă</translation>
<translation id="5944544982112848342">2048 (Grad înalt)</translation>
<translation id="3040011195152428237">link</translation>
-<translation id="2745343197843472802">Descărcați pluginul</translation>
-<translation id="5776402066334188252">Confirmați că doriți să instalați acest plugin. Vă recomandăm să instalați numai pluginuri în care aveți încredere.</translation>
+<translation id="2745343197843472802">Descărcaţi pluginul</translation>
+<translation id="5776402066334188252">Confirmaţi că doriţi să instalaţi acest plugin. Vă recomandăm să instalaţi numai pluginuri în care aveţi încredere.</translation>
<translation id="4003986561708175844">Pluginul necesar nu este instalat</translation>
<translation id="3018094406922859308">Se descarcă pluginul...</translation>
-<translation id="7364796246159120393">Alegeți fișierul</translation>
-<translation id="8964020114565522021">Trageți fișierul aici</translation>
-<translation id="838869780401515933">Bifați</translation>
+<translation id="7364796246159120393">Alegeţi fişierul</translation>
+<translation id="8964020114565522021">Trageţi fişierul aici</translation>
+<translation id="838869780401515933">Bifaţi</translation>
<translation id="2846343701378493991">1024 (Grad mediu)</translation>
-<translation id="5476505524087279545">Debifați</translation>
-<translation id="3789841737615482174">Instalați</translation>
-<translation id="5253117816378681419">Confirmați că doriți să instalați pluginul <ph name="PLUGIN"/>. Vă recomandăm să instalați numai pluginuri în care aveți încredere.</translation>
+<translation id="5476505524087279545">Debifaţi</translation>
+<translation id="3789841737615482174">Instalaţi</translation>
+<translation id="5253117816378681419">Confirmaţi că doriţi să instalaţi pluginul <ph name="PLUGIN"/>. Vă recomandăm să instalaţi numai pluginuri în care aveţi încredere.</translation>
<translation id="6663448176199120256">Căutări recente</translation>
-<translation id="2597378329261239068">Acest document este protejat cu parolă. Introduceți o parolă.</translation>
-<translation id="7740050170769002709">Conținut HTML</translation>
-<translation id="5939518447894949180">Resetați</translation>
-<translation id="1842960171412779397">Selectați</translation>
-<translation id="7638452146404718955">Faceți clic aici pentru a descărca pluginul</translation>
-<translation id="6119846243427417423">Activați</translation>
-<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> fișiere</translation>
+<translation id="2597378329261239068">Acest document este protejat cu parolă. Introduceţi o parolă.</translation>
+<translation id="6807599807928161586">zona Web</translation>
+<translation id="5939518447894949180">Resetaţi</translation>
+<translation id="1842960171412779397">Selectaţi</translation>
+<translation id="7638452146404718955">Faceţi clic aici pentru a descărca pluginul</translation>
+<translation id="6119846243427417423">Activaţi</translation>
+<translation id="8444882422881193423"><ph name="NUMBER_OF_FILES"/> fişiere</translation>
<translation id="4470547978413275879">Pluginul <ph name="PLUGIN"/> nu este instalat</translation>
-<translation id="6765711848403622008">Niciun plugin disponibil pentru a afișa acest conținut</translation>
+<translation id="6765711848403622008">Niciun plugin disponibil pentru a afişa acest conţinut</translation>
<translation id="8597182159515967513">titlu</translation>
-<translation id="2653659639078652383">Trimiteți</translation>
+<translation id="2653659639078652383">Trimiteţi</translation>
<translation id="8475551193147984329">Este necesar pluginul <ph name="PLUGIN"/></translation>
</translationbundle> \ No newline at end of file
diff --git a/webkit/glue/resources/webkit_strings_ru.xtb b/webkit/glue/resources/webkit_strings_ru.xtb
index 5ea9049..97e2796 100644
--- a/webkit/glue/resources/webkit_strings_ru.xtb
+++ b/webkit/glue/resources/webkit_strings_ru.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="ru">
<translation id="4519964825805946997">Не удалось установить подключаемый модуль с адреса <ph name="URL"/></translation>
-<translation id="9186171386827445984">Загрузка документа: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> стр.</translation>
<translation id="1235745349614807883">Очистить недавние поиски</translation>
<translation id="5048533449481078685">маркер списка</translation>
<translation id="372362261556059955">Необходим дополнительный подключаемый модуль</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">Не удалось установить подключаемый модуль</translation>
<translation id="8141602879876242471">Это индекс с возможностью поиска. Введите ключевые слова для поиска:</translation>
<translation id="5650795167354946011">После установки подключаемого модуля нажмите здесь, чтобы обновить страницу</translation>
-<translation id="370665806235115550">Загрузка...</translation>
<translation id="6845533974506654842">нажать</translation>
<translation id="8244226242650769279">графическая карта</translation>
<translation id="2548326553472216322">Нет недавних поисков</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Подтвердите, что вы хотите установить подключаемый модуль <ph name="PLUGIN"/>. Вы доверяете ему?</translation>
<translation id="6663448176199120256">Недавние поиски</translation>
<translation id="2597378329261239068">Документ защищен паролем. Введите пароль.</translation>
-<translation id="7740050170769002709">HTML-содержание</translation>
+<translation id="6807599807928161586">область Интернетеа</translation>
<translation id="5939518447894949180">Изменить</translation>
<translation id="1842960171412779397">выбрать</translation>
<translation id="7638452146404718955">Нажмите здесь, чтобы загрузить подключаемый модуль</translation>
diff --git a/webkit/glue/resources/webkit_strings_sk.xtb b/webkit/glue/resources/webkit_strings_sk.xtb
index a9b37ba..71e68a9 100644
--- a/webkit/glue/resources/webkit_strings_sk.xtb
+++ b/webkit/glue/resources/webkit_strings_sk.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="sk">
<translation id="4519964825805946997">Inštalácia doplnku z adresy <ph name="URL"/> zlyhala</translation>
-<translation id="9186171386827445984">Prebieha načítavanie dokumentu: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> stránok...</translation>
<translation id="1235745349614807883">Vyčistiť posledné vyhľadávania</translation>
<translation id="5048533449481078685">ukazovateľ v zozname</translation>
<translation id="372362261556059955">Vyžaduje sa ďalší doplnok</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">Inštalácia doplnku zlyhala</translation>
<translation id="8141602879876242471">Tento index sa dá prehľadávať. Zadajte kľúčové slová na vyhľadanie:</translation>
<translation id="5650795167354946011">Kliknutím sem po inštalácii doplnku obnovíte obsah</translation>
-<translation id="370665806235115550">Načítava sa...</translation>
<translation id="6845533974506654842">stlačiť</translation>
<translation id="8244226242650769279">mapa obrázka</translation>
<translation id="2548326553472216322">Žiadne posledné vyhľadávania</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Potvrďte, že chcete nainštalovať doplnok <ph name="PLUGIN"/>. Mali by ste inštalovať len doplnky, ktorým dôverujete.</translation>
<translation id="6663448176199120256">Posledné vyhľadávania</translation>
<translation id="2597378329261239068">Tento dokument je chránený heslom. Zadajte heslo.</translation>
-<translation id="7740050170769002709">Obsah HTML</translation>
+<translation id="6807599807928161586">webová oblasť</translation>
<translation id="5939518447894949180">Vynulovať</translation>
<translation id="1842960171412779397">vybrať</translation>
<translation id="7638452146404718955">Kliknutím sem prevezmete doplnok</translation>
diff --git a/webkit/glue/resources/webkit_strings_sl.xtb b/webkit/glue/resources/webkit_strings_sl.xtb
index e3b1061..2ee1e5b 100644
--- a/webkit/glue/resources/webkit_strings_sl.xtb
+++ b/webkit/glue/resources/webkit_strings_sl.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="sl">
<translation id="4519964825805946997">Namestitev vtičnika z naslova <ph name="URL"/> ni bila uspešna</translation>
-<translation id="9186171386827445984">Nalaganje dokumenta: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> strani ...</translation>
<translation id="1235745349614807883">Počisti zadnja iskanja</translation>
<translation id="5048533449481078685">označevalnik seznama</translation>
<translation id="372362261556059955">Potreben je dodaten vtičnik</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">Namestitev vtičnika ni bila uspešna</translation>
<translation id="8141602879876242471">To je kazalo, ki omogoča iskanje. Vnesite ključne besede za iskanje:</translation>
<translation id="5650795167354946011">Po namestitvi vtičnika, kliknite tu, da osvežite</translation>
-<translation id="370665806235115550">Nalagam ...</translation>
<translation id="6845533974506654842">pritisni</translation>
<translation id="8244226242650769279">slikovni zemljevid</translation>
<translation id="2548326553472216322">Ni zadnjih iskanj</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Potrdite, da želite namestiti ta <ph name="PLUGIN"/> vtičnik. Nameščajte le vtičnike, ki jim zaupate.</translation>
<translation id="6663448176199120256">Zadnja iskanja</translation>
<translation id="2597378329261239068">Dokument je zaščiten z geslom. Vnesite geslo.</translation>
-<translation id="7740050170769002709">Vsebina HTML</translation>
+<translation id="6807599807928161586">spletno področje</translation>
<translation id="5939518447894949180">Ponastavi</translation>
<translation id="1842960171412779397">izberi</translation>
<translation id="7638452146404718955">Če želite prenesti vtičnik, kliknite tukaj</translation>
diff --git a/webkit/glue/resources/webkit_strings_sr.xtb b/webkit/glue/resources/webkit_strings_sr.xtb
index 3b32e4d..a54c61b 100644
--- a/webkit/glue/resources/webkit_strings_sr.xtb
+++ b/webkit/glue/resources/webkit_strings_sr.xtb
@@ -2,18 +2,16 @@
<!DOCTYPE translationbundle>
<translationbundle lang="sr">
<translation id="4519964825805946997">Инсталирање додатка са адресе <ph name="URL"/> није успело</translation>
-<translation id="9186171386827445984">Учитавање документа: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> странице(а)...</translation>
<translation id="1235745349614807883">Обриши недавне претраге</translation>
<translation id="5048533449481078685">означивач листе</translation>
<translation id="372362261556059955">Потребан је још један додатак</translation>
<translation id="4202807286478387388">прескочи</translation>
<translation id="4611115858363067980"><ph name="FILENAME"/><ph name="WIDTH"/>×<ph name="HEIGHT"/></translation>
<translation id="7658239707568436148">Откажи</translation>
-<translation id="795667975304826397">Није одабрано</translation>
+<translation id="795667975304826397">Није одабрана датотека</translation>
<translation id="1416462845279468967">Инсталација додатка није успела</translation>
<translation id="8141602879876242471">Ово је индекс који може да се претражује. Унесите кључне речи за претрагу:</translation>
<translation id="5650795167354946011">Након инсталирања додатка, кликните овде да бисте освежили</translation>
-<translation id="370665806235115550">Учитавање...</translation>
<translation id="6845533974506654842">притисни</translation>
<translation id="8244226242650769279">мапа слике</translation>
<translation id="2548326553472216322">Нема недавних претрага</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Потврдите да желите да инсталирате <ph name="PLUGIN"/> додатак. Инсталирајте само додатке у које имате поверења.</translation>
<translation id="6663448176199120256">Недавне претраге</translation>
<translation id="2597378329261239068">Овај документ је заштићен лозинком. Унесите лозинку.</translation>
-<translation id="7740050170769002709">HTML садржај</translation>
+<translation id="6807599807928161586">веб област</translation>
<translation id="5939518447894949180">Ресетуј</translation>
<translation id="1842960171412779397">изабери</translation>
<translation id="7638452146404718955">Кликните овде да бисте преузели додатак</translation>
diff --git a/webkit/glue/resources/webkit_strings_sv.xtb b/webkit/glue/resources/webkit_strings_sv.xtb
index 7cbe67d..aa42d57 100644
--- a/webkit/glue/resources/webkit_strings_sv.xtb
+++ b/webkit/glue/resources/webkit_strings_sv.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="sv">
<translation id="4519964825805946997">Det gick inte att installera plugin-program från <ph name="URL"/></translation>
-<translation id="9186171386827445984">Läser in dokument: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> sidor...</translation>
<translation id="1235745349614807883">Rensa senaste sökningar</translation>
<translation id="5048533449481078685">listmarkör</translation>
<translation id="372362261556059955">Ett ytterligare plugin-program krävs</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">Installationen av plugin-programmet misslyckades</translation>
<translation id="8141602879876242471">Det här är ett sökbart index. Skriv sökord:</translation>
<translation id="5650795167354946011">Klicka här för att uppdatera när du har installerat plugin-programmet</translation>
-<translation id="370665806235115550">Laddar...</translation>
<translation id="6845533974506654842">tryck</translation>
<translation id="8244226242650769279">bildkarta</translation>
<translation id="2548326553472216322">Inga nya sökningar</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Bekräfta att du vill installera plugin-programmet <ph name="PLUGIN"/>. Installera bara plugin-program från tillförlitliga källor.</translation>
<translation id="6663448176199120256">Senaste sökningar</translation>
<translation id="2597378329261239068">Dokumentet är lösenordsskyddat. Ange ett lösenord.</translation>
-<translation id="7740050170769002709">HTML-innehåll</translation>
+<translation id="6807599807928161586">webbområde</translation>
<translation id="5939518447894949180">Återställ</translation>
<translation id="1842960171412779397">välj</translation>
<translation id="7638452146404718955">Klicka här för att hämta plugin-programmet</translation>
diff --git a/webkit/glue/resources/webkit_strings_sw.xtb b/webkit/glue/resources/webkit_strings_sw.xtb
index 088048a..e507aa6 100644
--- a/webkit/glue/resources/webkit_strings_sw.xtb
+++ b/webkit/glue/resources/webkit_strings_sw.xtb
@@ -8,7 +8,6 @@
<translation id="7658239707568436148">Ghairi</translation>
<translation id="795667975304826397">Hakuna faili lililochaguliwa</translation>
<translation id="8141602879876242471">Hii ni fahirisi inayoweza kutafutwa. Weka maneno muhimu ya utafutaji.</translation>
-<translation id="370665806235115550">Inapakia...</translation>
<translation id="6845533974506654842">bofya</translation>
<translation id="8244226242650769279">ramani ya picha</translation>
<translation id="2548326553472216322">Hakuna utafutaji wa hivi karibuni</translation>
@@ -21,6 +20,7 @@
<translation id="5476505524087279545">toa tiki</translation>
<translation id="3789841737615482174">Sakinisha</translation>
<translation id="6663448176199120256">Utafutaji wa hivi karibuni</translation>
+<translation id="6807599807928161586">eneo wavuti</translation>
<translation id="5939518447894949180">Weka upya</translation>
<translation id="1842960171412779397">chagua</translation>
<translation id="6119846243427417423">wezesha</translation>
diff --git a/webkit/glue/resources/webkit_strings_ta.xtb b/webkit/glue/resources/webkit_strings_ta.xtb
index f8dbf00..47d8547 100644
--- a/webkit/glue/resources/webkit_strings_ta.xtb
+++ b/webkit/glue/resources/webkit_strings_ta.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="ta">
<translation id="4519964825805946997"><ph name="URL"/> இலிருந்து செருகுநிரலை நிறுவுதல் தோல்வியடைந்தது</translation>
-<translation id="9186171386827445984">ஆவணத்தை ஏற்றுகிறது: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> பக்கங்கள்...</translation>
<translation id="1235745349614807883">சமீபத்திய தேடல்களை சுத்தமாக்கு</translation>
<translation id="5048533449481078685">பட்டியல் குறிப்பான்</translation>
<translation id="372362261556059955">கூடுதல் செருகுநிரல் தேவைப்படுகிறது</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">செருகுநிரலை நிறுவுதல் தோல்வியடைந்தது</translation>
<translation id="8141602879876242471">இது தேடக்கூடிய பொருளடக்கம். தேடல் சொற்களை உள்ளிடுக:</translation>
<translation id="5650795167354946011">செருகுநிரலை நிறுவிய பின்பு புதுப்பிக்க இங்கு கிளிக்செய்க</translation>
-<translation id="370665806235115550">நினைவேறுகிறது...</translation>
<translation id="6845533974506654842">அழுத்துக</translation>
<translation id="8244226242650769279">பட மேப்</translation>
<translation id="2548326553472216322">சமீபத்திய தேடல்கள் எதுவுமில்லை</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419"><ph name="PLUGIN"/> செருகுநிரலை நிறுவ நீங்கள் விரும்புகிறீர்கள் என்பதை தயவுசெய்து உறுதிசெய்க. நீங்கள் நம்பும் செருகுநிரல்களை மட்டும் நிறுவ வேண்டும்.</translation>
<translation id="6663448176199120256">சமீபத்திய தேடல்கள்</translation>
<translation id="2597378329261239068">இந்த ஆவணம் கடவுச்சொல் பாதுகாக்கப்பட்ட ஒன்று. தயவுசெய்து ஒரு கடவுச்சொல்லை உள்ளிடுக.</translation>
-<translation id="7740050170769002709">HTML உள்ளடக்கம்</translation>
+<translation id="6807599807928161586">வலைப் பகுதி</translation>
<translation id="5939518447894949180">மீட்டமை</translation>
<translation id="1842960171412779397">தேர்ந்தெடு</translation>
<translation id="7638452146404718955">செருகுநிரலைப் பதிவிறக்க இங்கே கிளிக் செய்க</translation>
diff --git a/webkit/glue/resources/webkit_strings_te.xtb b/webkit/glue/resources/webkit_strings_te.xtb
index a1f9fd6..3c1e875 100644
--- a/webkit/glue/resources/webkit_strings_te.xtb
+++ b/webkit/glue/resources/webkit_strings_te.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="te">
<translation id="4519964825805946997"><ph name="URL"/> నుండి ప్లగ్-ఇన్‌ను వ్యవస్థాపించడానికి విఫలమైంది</translation>
-<translation id="9186171386827445984">పత్రాన్ని లోడ్ చేస్తోంది: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> పేజీలు...</translation>
<translation id="1235745349614807883">ఇటీవల శోధనలను క్లియర్ చెయ్యి</translation>
<translation id="5048533449481078685">జాబితా మార్కర్</translation>
<translation id="372362261556059955">అదనపు ప్లగ్-ఇన్ అవసరం</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">ప్లగ్-ఇన్ వ్యవస్థాపన విఫలమైంది</translation>
<translation id="8141602879876242471">ఇది ఒక శోధించగల సూచిక. శోధన కీవర్డ్‌లను ఎంటర్ చెయ్యండి:</translation>
<translation id="5650795167354946011">ప్లగ్-ఇన్‌ను వ్యవస్థాపించిన తర్వాత, రిఫ్రెష్ చెయ్యడానికి ఇక్కడ క్లిక్ చెయ్యండి.</translation>
-<translation id="370665806235115550">లోడ్ అవుతోంది...</translation>
<translation id="6845533974506654842">నొక్కండి</translation>
<translation id="8244226242650769279">చిత్రం మాప్</translation>
<translation id="2548326553472216322">ఇటీవల శోధనలు లేవు</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">దయచేసి మీరు <ph name="PLUGIN"/> ప్లగ్-ఇన్‌ను వ్యవస్థాపించాలనుకుంటున్నారని నిర్థారించండి. మీరు విశ్వసించే ప్లగ్-ఇన్‌లను మాత్రమే వ్యవస్థాపించాలి.</translation>
<translation id="6663448176199120256">ఇటీవల శోధనలు</translation>
<translation id="2597378329261239068">ఈ పత్రం అనుమతి పదంచే రక్షించబడింది. దయచేసి అనుమతి పదాన్ని నమోదు చేయండి.</translation>
-<translation id="7740050170769002709">HTML కంటెంట్</translation>
+<translation id="6807599807928161586">వెబ్ ప్రాంతం</translation>
<translation id="5939518447894949180">తిరిగి అమర్చండి</translation>
<translation id="1842960171412779397">ఎంచుకోండి</translation>
<translation id="7638452146404718955">ప్లగ్-ఇన్‌ను డౌన్‌లోడ్ చేయడానికి ఇక్కడ క్లిక్ చేయండి</translation>
diff --git a/webkit/glue/resources/webkit_strings_th.xtb b/webkit/glue/resources/webkit_strings_th.xtb
index a6ffcc6..80dd787 100644
--- a/webkit/glue/resources/webkit_strings_th.xtb
+++ b/webkit/glue/resources/webkit_strings_th.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="th">
<translation id="4519964825805946997">การติดตั้งปลั๊กอินจาก <ph name="URL"/> ล้มเหลว</translation>
-<translation id="9186171386827445984">กำลังโหลดเอกสาร: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> หน้า...</translation>
<translation id="1235745349614807883">ลบการค้นหาล่าสุด</translation>
<translation id="5048533449481078685">ผู้สร้างรายการ</translation>
<translation id="372362261556059955">ต้องการปลั๊กอินเพิ่มเติม</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">การติดตั้งปลั๊กอินล้มเหลว</translation>
<translation id="8141602879876242471">นี่คือดัชนีที่สามารถค้นหาได้ ป้อนคำหลักในการค้นหา:</translation>
<translation id="5650795167354946011">หลังจากติดตั้งปลั๊กอิน ให้คลิกที่นี่เพื่อรีเฟรช</translation>
-<translation id="370665806235115550">กำลังโหลด...</translation>
<translation id="6845533974506654842">กด</translation>
<translation id="8244226242650769279">แผนที่รูปภาพ</translation>
<translation id="2548326553472216322">ไม่พบการค้นหาล่าสุด</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">โปรดยืนยันว่าคุณต้องการติดตั้งปลั๊กอิน <ph name="PLUGIN"/> คุณควรติดตั้งเฉพาะปลั๊กอินที่คุณไว้ใจเท่านั้น</translation>
<translation id="6663448176199120256">การค้นหาล่าสุด</translation>
<translation id="2597378329261239068">เอกสารนี้ได้รับการป้องกันด้วยรหัสผ่าน โปรดป้อนรหัสผ่าน</translation>
-<translation id="7740050170769002709">เนื้อหา HTML</translation>
+<translation id="6807599807928161586">พื้นที่เว็บ</translation>
<translation id="5939518447894949180">ตั้งค่าใหม่</translation>
<translation id="1842960171412779397">เลือก</translation>
<translation id="7638452146404718955">คลิกที่นี่เพื่อดาวน์โหลดปลั๊กอิน</translation>
diff --git a/webkit/glue/resources/webkit_strings_tr.xtb b/webkit/glue/resources/webkit_strings_tr.xtb
index 5a24891..a4d880d 100644
--- a/webkit/glue/resources/webkit_strings_tr.xtb
+++ b/webkit/glue/resources/webkit_strings_tr.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="tr">
<translation id="4519964825805946997">Eklenti, <ph name="URL"/> kaynağından yüklenemedi</translation>
-<translation id="9186171386827445984">Belge yükleniyor: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> sayfa...</translation>
<translation id="1235745349614807883">Son Aramaları Temizle</translation>
<translation id="5048533449481078685">liste işaretçisi</translation>
<translation id="372362261556059955">Başka eklenti gerekiyor</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">Eklenti yüklenemedi</translation>
<translation id="8141602879876242471">Bu dizinde arama yapılabilir. Arama anahtar kelimeleri girin:</translation>
<translation id="5650795167354946011">Eklentiyi yükledikten sonra yenilemek için burayı tıklayın</translation>
-<translation id="370665806235115550">Yükleniyor...</translation>
<translation id="6845533974506654842">bas</translation>
<translation id="8244226242650769279">resim haritası</translation>
<translation id="2548326553472216322">Yeni arama yok</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Lütfen <ph name="PLUGIN"/> eklentisini yüklemek istediğinizi onaylayın. Yalnızca güvendiğiniz eklentileri yüklemelisiniz.</translation>
<translation id="6663448176199120256">Son Aramalar</translation>
<translation id="2597378329261239068">Doküman şifre korumalı. Lütfen şifreyi girin.</translation>
-<translation id="7740050170769002709">HTML içeriği</translation>
+<translation id="6807599807928161586">web alanı</translation>
<translation id="5939518447894949180">Sıfırla</translation>
<translation id="1842960171412779397">seç</translation>
<translation id="7638452146404718955">Eklentiyi indirmek için burayı tıklayın</translation>
diff --git a/webkit/glue/resources/webkit_strings_uk.xtb b/webkit/glue/resources/webkit_strings_uk.xtb
index 360c85f..a125fe2 100644
--- a/webkit/glue/resources/webkit_strings_uk.xtb
+++ b/webkit/glue/resources/webkit_strings_uk.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="uk">
<translation id="4519964825805946997">Не вдалося встановити плагін із <ph name="URL"/></translation>
-<translation id="9186171386827445984">Завантаження документа – сторінки: <ph name="PAGE_NUMBER"/> із <ph name="NUMBER_OF_PAGES"/>...</translation>
<translation id="1235745349614807883">Очистити останні пошуки</translation>
<translation id="5048533449481078685">маркер списку</translation>
<translation id="372362261556059955">Потрібен додатковий плагін.</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">Помилка встановлення плагіна</translation>
<translation id="8141602879876242471">Цей доступний для пошуку індекс. Введіть ключові слова пошуку:</translation>
<translation id="5650795167354946011">Після встановлення плагіна натисніть тут, щоб оновити</translation>
-<translation id="370665806235115550">Завантаження...</translation>
<translation id="6845533974506654842">натиснути</translation>
<translation id="8244226242650769279">мапа зображення</translation>
<translation id="2548326553472216322">Немає останніх пошуків</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Підтвердьте встановлення плагіна <ph name="PLUGIN"/>. Слід установлювати лише плагіни, яким ви довіряєте.</translation>
<translation id="6663448176199120256">Останні пошуки</translation>
<translation id="2597378329261239068">Цей документ захищено паролем. Введіть пароль.</translation>
-<translation id="7740050170769002709">Вміст HTML</translation>
+<translation id="6807599807928161586">область Інтернету</translation>
<translation id="5939518447894949180">Скинути</translation>
<translation id="1842960171412779397">вибрати</translation>
<translation id="7638452146404718955">Натисніть тут, щоб завантажити плагін</translation>
diff --git a/webkit/glue/resources/webkit_strings_vi.xtb b/webkit/glue/resources/webkit_strings_vi.xtb
index 0ee2d09..84668c5 100644
--- a/webkit/glue/resources/webkit_strings_vi.xtb
+++ b/webkit/glue/resources/webkit_strings_vi.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="vi">
<translation id="4519964825805946997">Cài đặt trình cắm từ <ph name="URL"/> không thành công</translation>
-<translation id="9186171386827445984">Đang tải tài liệu: <ph name="PAGE_NUMBER"/>/<ph name="NUMBER_OF_PAGES"/> trang...</translation>
<translation id="1235745349614807883">Xoá Tìm kiếm Gần đây</translation>
<translation id="5048533449481078685">đánh dấu danh sách</translation>
<translation id="372362261556059955">Cần trình cắm bổ sung</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">Cài đặt trình cắm không thành công</translation>
<translation id="8141602879876242471">Đây là chỉ mục có thể tìm kiếm. Nhập từ khoá tìm kiếm vào:</translation>
<translation id="5650795167354946011">Sau khi cài đặt trình cắm, hãy nhấp vào đây để làm mới</translation>
-<translation id="370665806235115550">Đang tải...</translation>
<translation id="6845533974506654842">nhấn</translation>
<translation id="8244226242650769279">bản đồ hình ảnh</translation>
<translation id="2548326553472216322">Không có tìm kiếm nào gần đây</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">Vui lòng xác nhận rằng bạn muốn cài đặt trình cắm <ph name="PLUGIN"/>. Bạn chỉ nên cài đặt những trình cắm mà bạn tin tưởng.</translation>
<translation id="6663448176199120256">Tìm kiếm Gần đây</translation>
<translation id="2597378329261239068">Tài liệu này được bảo vệ bằng mật khẩu. Vui lòng nhập mật khẩu.</translation>
-<translation id="7740050170769002709">Nội dung HTML</translation>
+<translation id="6807599807928161586">khu vực web</translation>
<translation id="5939518447894949180">Đặt lại</translation>
<translation id="1842960171412779397">chọn</translation>
<translation id="7638452146404718955">Nhấp vào đây để tải xuống trình cắm</translation>
diff --git a/webkit/glue/resources/webkit_strings_zh-CN.xtb b/webkit/glue/resources/webkit_strings_zh-CN.xtb
index f931c5c..f5c0644 100644
--- a/webkit/glue/resources/webkit_strings_zh-CN.xtb
+++ b/webkit/glue/resources/webkit_strings_zh-CN.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="zh-CN">
<translation id="4519964825805946997">无法从 <ph name="URL"/> 安装插件</translation>
-<translation id="9186171386827445984">正在载入文档:已载入 <ph name="PAGE_NUMBER"/> 页,共 <ph name="NUMBER_OF_PAGES"/> 页...</translation>
<translation id="1235745349614807883">清除最近的搜索</translation>
<translation id="5048533449481078685">列表标记</translation>
<translation id="372362261556059955">需要其他插件</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">插件安装失败</translation>
<translation id="8141602879876242471">这是一个可搜索的索引。请输入搜索关键字:</translation>
<translation id="5650795167354946011">安装插件后,点击此处可刷新</translation>
-<translation id="370665806235115550">正在载入...</translation>
<translation id="6845533974506654842">按</translation>
<translation id="8244226242650769279">图片映射</translation>
<translation id="2548326553472216322">最近未执行搜索</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">请确认您要安装 <ph name="PLUGIN"/> 插件。您应该只安装自己信任的插件。</translation>
<translation id="6663448176199120256">近期搜索</translation>
<translation id="2597378329261239068">本文档设置了密码保护,请输入密码。</translation>
-<translation id="7740050170769002709">HTML 内容</translation>
+<translation id="6807599807928161586">网络区域</translation>
<translation id="5939518447894949180">重置</translation>
<translation id="1842960171412779397">选中</translation>
<translation id="7638452146404718955">点击此处可下载插件</translation>
diff --git a/webkit/glue/resources/webkit_strings_zh-TW.xtb b/webkit/glue/resources/webkit_strings_zh-TW.xtb
index 368a365..7d7eda3 100644
--- a/webkit/glue/resources/webkit_strings_zh-TW.xtb
+++ b/webkit/glue/resources/webkit_strings_zh-TW.xtb
@@ -2,7 +2,6 @@
<!DOCTYPE translationbundle>
<translationbundle lang="zh-TW">
<translation id="4519964825805946997">無法從 <ph name="URL"/> 安裝外掛程式</translation>
-<translation id="9186171386827445984">正在載入文件:第 <ph name="PAGE_NUMBER"/> 頁,共 <ph name="NUMBER_OF_PAGES"/> 頁...</translation>
<translation id="1235745349614807883">清除最近的搜尋記錄</translation>
<translation id="5048533449481078685">清單標記</translation>
<translation id="372362261556059955">需要其他外掛程式</translation>
@@ -13,7 +12,6 @@
<translation id="1416462845279468967">外掛程式安裝不成功</translation>
<translation id="8141602879876242471">這是可搜尋的索引,輸入搜尋關鍵字:</translation>
<translation id="5650795167354946011">安裝外掛程式後,請按一下這裡重新整理</translation>
-<translation id="370665806235115550">載入中...</translation>
<translation id="6845533974506654842">按下</translation>
<translation id="8244226242650769279">影像地圖</translation>
<translation id="2548326553472216322">沒有近期的搜尋</translation>
@@ -32,7 +30,7 @@
<translation id="5253117816378681419">請確認您要安裝 <ph name="PLUGIN"/> 外掛程式,建議您僅安裝您所信任的外掛程式。</translation>
<translation id="6663448176199120256">最近的搜尋</translation>
<translation id="2597378329261239068">此文件受到密碼保護,請輸入密碼。</translation>
-<translation id="7740050170769002709">HTML 內容</translation>
+<translation id="6807599807928161586">網頁範圍</translation>
<translation id="5939518447894949180">重設</translation>
<translation id="1842960171412779397">選取</translation>
<translation id="7638452146404718955">按一下這裡下載外掛程式</translation>
diff --git a/webkit/glue/webaccessibility.cc b/webkit/glue/webaccessibility.cc
index 0888a62..c3ef261 100644
--- a/webkit/glue/webaccessibility.cc
+++ b/webkit/glue/webaccessibility.cc
@@ -324,6 +324,8 @@ void WebAccessibility::Init(const WebKit::WebAccessibilityObject& src,
attributes[ATTR_SHORTCUT] = src.keyboardShortcut();
if (src.hasComputedStyle())
attributes[ATTR_DISPLAY] = src.computedStyleDisplay();
+ if (!src.url().isEmpty())
+ attributes[ATTR_URL] = src.url().spec().utf16();
WebKit::WebNode node = src.node();
diff --git a/webkit/glue/webaccessibility.h b/webkit/glue/webaccessibility.h
index a8e4b11..c073502 100644
--- a/webkit/glue/webaccessibility.h
+++ b/webkit/glue/webaccessibility.h
@@ -175,8 +175,8 @@ struct WebAccessibility {
ATTR_DISPLAY,
ATTR_HELP,
ATTR_HTML_TAG,
- ATTR_LINK_TARGET,
ATTR_SHORTCUT,
+ ATTR_URL,
NUM_ATTRIBUTES
};
diff --git a/webkit/glue/webcursor.cc b/webkit/glue/webcursor.cc
index 8f76ef9..fb67b6b 100644
--- a/webkit/glue/webcursor.cc
+++ b/webkit/glue/webcursor.cc
@@ -89,26 +89,28 @@ bool WebCursor::Deserialize(const Pickle* pickle, void** iter) {
size_y > kMaxCursorDimension)
return false;
- if (type == WebCursorInfo::TypeCustom && (size_x == 0 || size_y == 0))
- return false;
-
- // The * 4 is because the expected format is an array of RGBA pixel values.
- if (size_x * size_y * 4 > data_len)
- return false;
-
type_ = type;
- hotspot_.set_x(hotspot_x);
- hotspot_.set_y(hotspot_y);
- custom_size_.set_width(size_x);
- custom_size_.set_height(size_y);
- ClampHotspot();
- custom_data_.clear();
- if (data_len > 0) {
- custom_data_.resize(data_len);
- memcpy(&custom_data_[0], data, data_len);
+ if (type == WebCursorInfo::TypeCustom) {
+ if (size_x > 0 && size_y > 0) {
+ // The * 4 is because the expected format is an array of RGBA pixel
+ // values.
+ if (size_x * size_y * 4 > data_len)
+ return false;
+
+ hotspot_.set_x(hotspot_x);
+ hotspot_.set_y(hotspot_y);
+ custom_size_.set_width(size_x);
+ custom_size_.set_height(size_y);
+ ClampHotspot();
+
+ custom_data_.clear();
+ if (data_len > 0) {
+ custom_data_.resize(data_len);
+ memcpy(&custom_data_[0], data, data_len);
+ }
+ }
}
-
return DeserializePlatformData(pickle, iter);
}
diff --git a/webkit/glue/webcursor_mac.mm b/webkit/glue/webcursor_mac.mm
index 1aeb1e0..4c3d69a 100644
--- a/webkit/glue/webcursor_mac.mm
+++ b/webkit/glue/webcursor_mac.mm
@@ -1,14 +1,14 @@
-// Copyright (c) 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.
+// 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.
#include "webkit/glue/webcursor.h"
#import <AppKit/AppKit.h>
#include <Carbon/Carbon.h>
+#include "app/mac/nsimage_cache.h"
#include "base/logging.h"
-#include "base/nsimage_cache_mac.h"
#include "base/mac/scoped_cftyperef.h"
#include "third_party/WebKit/WebKit/chromium/public/WebCursorInfo.h"
#include "third_party/WebKit/WebKit/chromium/public/WebImage.h"
@@ -21,11 +21,11 @@ using WebKit::WebSize;
namespace {
// TODO: This image fetch can (and probably should) be serviced by the resource
-// resource bundle instead of going through nsimage_cache.
+// resource bundle instead of going through the image cache.
NSCursor* LoadCursor(const char* name, int x, int y) {
NSString* file_name = [NSString stringWithUTF8String:name];
DCHECK(file_name);
- NSImage* cursor_image = nsimage_cache::ImageNamed(file_name);
+ NSImage* cursor_image = app::mac::GetCachedImageWithName(file_name);
DCHECK(cursor_image);
return [[[NSCursor alloc] initWithImage:cursor_image
hotSpot:NSMakePoint(x, y)] autorelease];
diff --git a/webkit/glue/webcursor_unittest.cc b/webkit/glue/webcursor_unittest.cc
index 6e7701d..f449515 100644
--- a/webkit/glue/webcursor_unittest.cc
+++ b/webkit/glue/webcursor_unittest.cc
@@ -15,7 +15,7 @@ TEST(WebCursorTest, CursorSerialization) {
// This is a valid custom cursor.
Pickle ok_custom_pickle;
// Type and hotspots.
- ok_custom_pickle.WriteInt(0);
+ ok_custom_pickle.WriteInt(WebCursorInfo::TypeCustom);
ok_custom_pickle.WriteInt(0);
ok_custom_pickle.WriteInt(0);
// X & Y
@@ -32,7 +32,7 @@ TEST(WebCursorTest, CursorSerialization) {
// This custom cursor has not been send with enough data.
Pickle short_custom_pickle;
// Type and hotspots.
- short_custom_pickle.WriteInt(0);
+ short_custom_pickle.WriteInt(WebCursorInfo::TypeCustom);
short_custom_pickle.WriteInt(0);
short_custom_pickle.WriteInt(0);
// X & Y
@@ -49,7 +49,7 @@ TEST(WebCursorTest, CursorSerialization) {
// This custom cursor has enough data but is too big.
Pickle large_custom_pickle;
// Type and hotspots.
- large_custom_pickle.WriteInt(0);
+ large_custom_pickle.WriteInt(WebCursorInfo::TypeCustom);
large_custom_pickle.WriteInt(0);
large_custom_pickle.WriteInt(0);
// X & Y
@@ -68,7 +68,7 @@ TEST(WebCursorTest, CursorSerialization) {
// This custom cursor uses negative lengths.
Pickle neg_custom_pickle;
// Type and hotspots.
- neg_custom_pickle.WriteInt(0);
+ neg_custom_pickle.WriteInt(WebCursorInfo::TypeCustom);
neg_custom_pickle.WriteInt(0);
neg_custom_pickle.WriteInt(0);
// X & Y
@@ -81,6 +81,17 @@ TEST(WebCursorTest, CursorSerialization) {
neg_custom_pickle.WriteUInt32(0);
iter = NULL;
EXPECT_FALSE(custom_cursor.Deserialize(&neg_custom_pickle, &iter));
+
+#if defined(OS_WIN)
+ Pickle win32_custom_pickle;
+ WebCursor win32_custom_cursor;
+ win32_custom_cursor.InitFromExternalCursor(
+ reinterpret_cast<HCURSOR>(1000));
+ EXPECT_TRUE(win32_custom_cursor.Serialize(&win32_custom_pickle));
+ iter = NULL;
+ EXPECT_TRUE(custom_cursor.Deserialize(&win32_custom_pickle, &iter));
+ EXPECT_EQ(reinterpret_cast<HCURSOR>(1000), custom_cursor.GetCursor(NULL));
+#endif // OS_WIN
}
TEST(WebCursorTest, ClampHotspot) {
diff --git a/webkit/glue/webkit_glue.cc b/webkit/glue/webkit_glue.cc
index 67b61ba..fe3edd9 100644
--- a/webkit/glue/webkit_glue.cc
+++ b/webkit/glue/webkit_glue.cc
@@ -11,9 +11,9 @@
#include <sys/utsname.h>
#endif
+#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
-#include "base/singleton.h"
#include "base/string_piece.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
@@ -84,29 +84,29 @@ void EnableWebCoreNotImplementedLogging() {
WebKit::enableLogChannel("NotYetImplemented");
}
-std::wstring DumpDocumentText(WebFrame* web_frame) {
+string16 DumpDocumentText(WebFrame* web_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.
WebElement document_element = web_frame->document().documentElement();
if (document_element.isNull())
- return std::wstring();
+ return string16();
- return UTF16ToWideHack(document_element.innerText());
+ return document_element.innerText();
}
-std::wstring DumpFramesAsText(WebFrame* web_frame, bool recursive) {
- std::wstring result;
+string16 DumpFramesAsText(WebFrame* web_frame, bool recursive) {
+ string16 result;
// Add header for all but the main frame. Skip empty frames.
if (web_frame->parent() &&
!web_frame->document().documentElement().isNull()) {
- result.append(L"\n--------\nFrame: '");
- result.append(UTF16ToWideHack(web_frame->name()));
- result.append(L"'\n--------\n");
+ result.append(ASCIIToUTF16("\n--------\nFrame: '"));
+ result.append(web_frame->name());
+ result.append(ASCIIToUTF16("'\n--------\n"));
}
result.append(DumpDocumentText(web_frame));
- result.append(L"\n");
+ result.append(ASCIIToUTF16("\n"));
if (recursive) {
WebFrame* child = web_frame->firstChild();
@@ -117,18 +117,18 @@ std::wstring DumpFramesAsText(WebFrame* web_frame, bool recursive) {
return result;
}
-std::wstring DumpRenderer(WebFrame* web_frame) {
- return UTF16ToWideHack(web_frame->renderTreeAsText());
+string16 DumpRenderer(WebFrame* web_frame) {
+ return web_frame->renderTreeAsText();
}
bool CounterValueForElementById(WebFrame* web_frame, const std::string& id,
- std::wstring* counter_value) {
+ string16* counter_value) {
WebString result =
web_frame->counterValueForElementById(WebString::fromUTF8(id));
if (result.isNull())
return false;
- *counter_value = UTF16ToWideHack(result);
+ *counter_value = result;
return true;
}
@@ -151,19 +151,21 @@ int NumberOfPages(WebFrame* web_frame,
return number_of_pages;
}
-std::wstring DumpFrameScrollPosition(WebFrame* web_frame, bool recursive) {
+string16 DumpFrameScrollPosition(WebFrame* web_frame, bool recursive) {
gfx::Size offset = web_frame->scrollOffset();
- std::wstring result;
+ std::string result_utf8;
if (offset.width() > 0 || offset.height() > 0) {
if (web_frame->parent()) {
- base::StringAppendF(&result, L"frame '%ls' ", UTF16ToWide(
- web_frame->name()).c_str());
+ base::StringAppendF(&result_utf8, "frame '%s' ",
+ UTF16ToUTF8(web_frame->name()).c_str());
}
- base::StringAppendF(&result, L"scrolled to %d,%d\n",
+ base::StringAppendF(&result_utf8, "scrolled to %d,%d\n",
offset.width(), offset.height());
}
+ string16 result = UTF8ToUTF16(result_utf8);
+
if (recursive) {
WebFrame* child = web_frame->firstChild();
for (; child; child = child->nextSibling())
@@ -183,16 +185,16 @@ static bool HistoryItemCompareLess(const WebHistoryItem& item1,
return target1 < target2;
}
-// Writes out a HistoryItem into a string in a readable format.
-static std::wstring DumpHistoryItem(const WebHistoryItem& item,
- int indent, bool is_current) {
- std::wstring result;
+// Writes out a HistoryItem into a UTF-8 string in a readable format.
+static std::string DumpHistoryItem(const WebHistoryItem& item,
+ int indent, bool is_current) {
+ std::string result;
if (is_current) {
- result.append(L"curr->");
- result.append(indent - 6, L' '); // 6 == L"curr->".length()
+ result.append("curr->");
+ result.append(indent - 6, ' '); // 6 == "curr->".length()
} else {
- result.append(indent, L' ');
+ result.append(indent, ' ');
}
std::string url = item.urlString().utf8();
@@ -207,12 +209,12 @@ static std::wstring DumpHistoryItem(const WebHistoryItem& item,
url.replace(kDataUrlPatternSize, url.length(), path);
}
- result.append(UTF8ToWide(url));
+ result.append(url);
if (!item.target().isEmpty())
- result.append(L" (in frame \"" + UTF16ToWide(item.target()) + L"\")");
+ result.append(" (in frame \"" + UTF16ToUTF8(item.target()) + "\")");
if (item.isTargetItem())
- result.append(L" **nav target**");
- result.append(L"\n");
+ result.append(" **nav target**");
+ result.append("\n");
const WebVector<WebHistoryItem>& children = item.children();
if (!children.isEmpty()) {
@@ -231,10 +233,11 @@ static std::wstring DumpHistoryItem(const WebHistoryItem& item,
return result;
}
-std::wstring DumpHistoryState(const std::string& history_state, int indent,
- bool is_current) {
- return DumpHistoryItem(HistoryItemFromString(history_state), indent,
- is_current);
+string16 DumpHistoryState(const std::string& history_state, int indent,
+ bool is_current) {
+ return UTF8ToUTF16(
+ DumpHistoryItem(HistoryItemFromString(history_state), indent,
+ is_current));
}
void ResetBeforeTestRun(WebView* view) {
@@ -356,10 +359,11 @@ struct UserAgentState {
bool user_agent_is_overridden;
};
-Singleton<UserAgentState> g_user_agent;
+static base::LazyInstance<UserAgentState> g_user_agent(
+ base::LINKER_INITIALIZED);
void SetUserAgentToDefault() {
- BuildUserAgent(false, &g_user_agent->user_agent);
+ BuildUserAgent(false, &g_user_agent.Get().user_agent);
}
} // namespace
@@ -367,31 +371,31 @@ void SetUserAgentToDefault() {
void SetUserAgent(const std::string& new_user_agent) {
// If you combine this with the previous line, the function only works the
// first time.
- DCHECK(!g_user_agent->user_agent_requested) <<
+ DCHECK(!g_user_agent.Get().user_agent_requested) <<
"Setting the user agent after someone has "
"already requested it can result in unexpected behavior.";
- g_user_agent->user_agent_is_overridden = true;
- g_user_agent->user_agent = new_user_agent;
+ g_user_agent.Get().user_agent_is_overridden = true;
+ g_user_agent.Get().user_agent = new_user_agent;
}
const std::string& GetUserAgent(const GURL& url) {
- if (g_user_agent->user_agent.empty())
+ if (g_user_agent.Get().user_agent.empty())
SetUserAgentToDefault();
- g_user_agent->user_agent_requested = true;
- if (!g_user_agent->user_agent_is_overridden) {
+ g_user_agent.Get().user_agent_requested = true;
+ if (!g_user_agent.Get().user_agent_is_overridden) {
// Workarounds for sites that use misguided UA sniffing.
#if defined(OS_POSIX) && !defined(OS_MACOSX)
if (MatchPattern(url.host(), "*.mail.yahoo.com")) {
// mail.yahoo.com is ok with Windows Chrome but not Linux Chrome.
// http://bugs.chromium.org/11136
// TODO(evanm): remove this if Yahoo fixes their sniffing.
- if (g_user_agent->mimic_windows_user_agent.empty())
- BuildUserAgent(true, &g_user_agent->mimic_windows_user_agent);
- return g_user_agent->mimic_windows_user_agent;
+ if (g_user_agent.Get().mimic_windows_user_agent.empty())
+ BuildUserAgent(true, &g_user_agent.Get().mimic_windows_user_agent);
+ return g_user_agent.Get().mimic_windows_user_agent;
}
#endif
}
- return g_user_agent->user_agent;
+ return g_user_agent.Get().user_agent;
}
void SetForcefullyTerminatePluginProcess(bool value) {
diff --git a/webkit/glue/webkit_glue.gypi b/webkit/glue/webkit_glue.gypi
index 8ed3e8b..959f4e1 100644
--- a/webkit/glue/webkit_glue.gypi
+++ b/webkit/glue/webkit_glue.gypi
@@ -147,7 +147,7 @@
'<(DEPTH)/base/base.gyp:base_i18n',
'<(DEPTH)/gpu/gpu.gyp:gles2_implementation',
'<(DEPTH)/net/net.gyp:net',
- '<(DEPTH)/ppapi/ppapi.gyp:ppapi_proxy',
+ '<(DEPTH)/ppapi/ppapi.gyp:ppapi_shared_impl',
'<(DEPTH)/printing/printing.gyp:printing',
'<(DEPTH)/skia/skia.gyp:skia',
'<(DEPTH)/third_party/icu/icu.gyp:icui18n',
@@ -168,10 +168,170 @@
# This list contains all .h, .cc, and .mm files in glue except for
# those in the test subdirectory and those with unittest in in their
# names.
+ '../plugins/npapi/carbon_plugin_window_tracker_mac.cc',
+ '../plugins/npapi/carbon_plugin_window_tracker_mac.h',
+ '../plugins/npapi/coregraphics_private_symbols_mac.h',
+ '../plugins/npapi/default_plugin_shared.h',
+ '../plugins/npapi/gtk_plugin_container.cc',
+ '../plugins/npapi/gtk_plugin_container.h',
+ '../plugins/npapi/gtk_plugin_container_manager.cc',
+ '../plugins/npapi/gtk_plugin_container_manager.h',
+ '../plugins/npapi/npapi_extension_thunk.cc',
+ '../plugins/npapi/npapi_extension_thunk.h',
+ '../plugins/npapi/nphostapi.h',
+ '../plugins/npapi/plugin_constants_win.cc',
+ '../plugins/npapi/plugin_constants_win.h',
+ '../plugins/npapi/plugin_group.cc',
+ '../plugins/npapi/plugin_group.h',
+ '../plugins/npapi/plugin_host.cc',
+ '../plugins/npapi/plugin_host.h',
+ '../plugins/npapi/plugin_instance.cc',
+ '../plugins/npapi/plugin_instance.h',
+ '../plugins/npapi/plugin_instance_mac.mm',
+ '../plugins/npapi/plugin_lib.cc',
+ '../plugins/npapi/plugin_lib.h',
+ '../plugins/npapi/plugin_lib_mac.mm',
+ '../plugins/npapi/plugin_lib_posix.cc',
+ '../plugins/npapi/plugin_lib_win.cc',
+ '../plugins/npapi/plugin_list.cc',
+ '../plugins/npapi/plugin_list.h',
+ '../plugins/npapi/plugin_list_mac.mm',
+ '../plugins/npapi/plugin_list_posix.cc',
+ '../plugins/npapi/plugin_list_win.cc',
+ '../plugins/npapi/plugin_stream.cc',
+ '../plugins/npapi/plugin_stream.h',
+ '../plugins/npapi/plugin_stream_posix.cc',
+ '../plugins/npapi/plugin_stream_url.cc',
+ '../plugins/npapi/plugin_stream_url.h',
+ '../plugins/npapi/plugin_stream_win.cc',
+ '../plugins/npapi/plugin_string_stream.cc',
+ '../plugins/npapi/plugin_string_stream.h',
+ '../plugins/npapi/plugin_web_event_converter_mac.h',
+ '../plugins/npapi/plugin_web_event_converter_mac.mm',
+ '../plugins/npapi/ppb_private.h',
+ '../plugins/npapi/quickdraw_drawing_manager_mac.cc',
+ '../plugins/npapi/quickdraw_drawing_manager_mac.h',
+ '../plugins/npapi/webplugin.cc',
+ '../plugins/npapi/webplugin.h',
+ '../plugins/npapi/webplugin_2d_device_delegate.cc',
+ '../plugins/npapi/webplugin_2d_device_delegate.h',
+ '../plugins/npapi/webplugin_3d_device_delegate.cc',
+ '../plugins/npapi/webplugin_3d_device_delegate.h',
+ '../plugins/npapi/webplugin_accelerated_surface_mac.h',
+ '../plugins/npapi/webplugin_audio_device_delegate.cc',
+ '../plugins/npapi/webplugin_audio_device_delegate.h',
+ '../plugins/npapi/webplugin_delegate.cc',
+ '../plugins/npapi/webplugin_delegate.h',
+ '../plugins/npapi/webplugin_delegate_impl.cc',
+ '../plugins/npapi/webplugin_delegate_impl.h',
+ '../plugins/npapi/webplugin_delegate_impl_gtk.cc',
+ '../plugins/npapi/webplugin_delegate_impl_mac.mm',
+ '../plugins/npapi/webplugin_delegate_impl_win.cc',
+ '../plugins/npapi/webplugin_file_delegate.cc',
+ '../plugins/npapi/webplugin_file_delegate.h',
+ '../plugins/npapi/webplugin_impl.cc',
+ '../plugins/npapi/webplugin_impl.h',
+ '../plugins/npapi/webplugin_print_delegate.cc',
+ '../plugins/npapi/webplugin_print_delegate.h',
+ '../plugins/npapi/webplugininfo.cc',
+ '../plugins/npapi/webplugininfo.h',
+ '../plugins/npapi/webview_plugin.cc',
+ '../plugins/npapi/webview_plugin.h',
+ '../plugins/plugin_switches.cc',
+ '../plugins/plugin_switches.h',
+ '../plugins/ppapi/callbacks.cc',
+ '../plugins/ppapi/callbacks.h',
+ '../plugins/ppapi/common.h',
+ '../plugins/ppapi/dir_contents.h',
+ '../plugins/ppapi/error_util.cc',
+ '../plugins/ppapi/error_util.h',
+ '../plugins/ppapi/event_conversion.cc',
+ '../plugins/ppapi/event_conversion.h',
+ '../plugins/ppapi/file_callbacks.cc',
+ '../plugins/ppapi/file_callbacks.h',
+ '../plugins/ppapi/fullscreen_container.h',
+ '../plugins/ppapi/npapi_glue.cc',
+ '../plugins/ppapi/npapi_glue.h',
+ '../plugins/ppapi/plugin_delegate.h',
+ '../plugins/ppapi/plugin_module.cc',
+ '../plugins/ppapi/plugin_module.h',
+ '../plugins/ppapi/plugin_object.cc',
+ '../plugins/ppapi/plugin_object.h',
+ '../plugins/ppapi/ppapi_plugin_instance.cc',
+ '../plugins/ppapi/ppapi_plugin_instance.h',
+ '../plugins/ppapi/ppapi_webplugin_impl.cc',
+ '../plugins/ppapi/ppapi_webplugin_impl.h',
+ '../plugins/ppapi/ppb_audio_impl.cc',
+ '../plugins/ppapi/ppb_audio_impl.h',
+ '../plugins/ppapi/ppb_buffer_impl.cc',
+ '../plugins/ppapi/ppb_buffer_impl.h',
+ '../plugins/ppapi/ppb_char_set_impl.cc',
+ '../plugins/ppapi/ppb_char_set_impl.h',
+ '../plugins/ppapi/ppb_context_3d_impl.cc',
+ '../plugins/ppapi/ppb_context_3d_impl.h',
+ '../plugins/ppapi/ppb_cursor_control_impl.cc',
+ '../plugins/ppapi/ppb_cursor_control_impl.h',
+ '../plugins/ppapi/ppb_directory_reader_impl.cc',
+ '../plugins/ppapi/ppb_directory_reader_impl.h',
+ '../plugins/ppapi/ppb_file_chooser_impl.cc',
+ '../plugins/ppapi/ppb_file_chooser_impl.h',
+ '../plugins/ppapi/ppb_file_io_impl.cc',
+ '../plugins/ppapi/ppb_file_io_impl.h',
+ '../plugins/ppapi/ppb_file_ref_impl.cc',
+ '../plugins/ppapi/ppb_file_ref_impl.h',
+ '../plugins/ppapi/ppb_file_system_impl.cc',
+ '../plugins/ppapi/ppb_file_system_impl.h',
+ '../plugins/ppapi/ppb_flash.h',
+ '../plugins/ppapi/ppb_flash_impl.cc',
+ '../plugins/ppapi/ppb_flash_impl.h',
+ '../plugins/ppapi/ppb_flash_impl_linux.cc',
+ '../plugins/ppapi/ppb_font_impl.cc',
+ '../plugins/ppapi/ppb_font_impl.h',
+ '../plugins/ppapi/ppb_graphics_2d_impl.cc',
+ '../plugins/ppapi/ppb_graphics_2d_impl.h',
+ '../plugins/ppapi/ppb_graphics_3d_impl.cc',
+ '../plugins/ppapi/ppb_graphics_3d_impl.h',
+ '../plugins/ppapi/ppb_image_data_impl.cc',
+ '../plugins/ppapi/ppb_image_data_impl.h',
+ '../plugins/ppapi/ppb_nacl_private_impl.cc',
+ '../plugins/ppapi/ppb_nacl_private_impl.h',
+ '../plugins/ppapi/ppb_opengles_impl.cc',
+ '../plugins/ppapi/ppb_opengles_impl.h',
+ '../plugins/ppapi/ppb_pdf.h',
+ '../plugins/ppapi/ppb_pdf_impl.cc',
+ '../plugins/ppapi/ppb_pdf_impl.h',
+ '../plugins/ppapi/ppb_scrollbar_impl.cc',
+ '../plugins/ppapi/ppb_scrollbar_impl.h',
+ '../plugins/ppapi/ppb_transport_impl.cc',
+ '../plugins/ppapi/ppb_transport_impl.h',
+ '../plugins/ppapi/ppb_url_loader_impl.cc',
+ '../plugins/ppapi/ppb_url_loader_impl.h',
+ '../plugins/ppapi/ppb_url_request_info_impl.cc',
+ '../plugins/ppapi/ppb_url_request_info_impl.h',
+ '../plugins/ppapi/ppb_url_response_info_impl.cc',
+ '../plugins/ppapi/ppb_url_response_info_impl.h',
+ '../plugins/ppapi/ppb_url_util_impl.cc',
+ '../plugins/ppapi/ppb_url_util_impl.h',
+ '../plugins/ppapi/ppb_video_decoder_impl.cc',
+ '../plugins/ppapi/ppb_video_decoder_impl.h',
+ '../plugins/ppapi/ppb_widget_impl.cc',
+ '../plugins/ppapi/ppb_widget_impl.h',
+ '../plugins/ppapi/resource.cc',
+ '../plugins/ppapi/resource.h',
+ '../plugins/ppapi/resource_tracker.cc',
+ '../plugins/ppapi/resource_tracker.h',
+ '../plugins/ppapi/string.cc',
+ '../plugins/ppapi/string.h',
+ '../plugins/ppapi/var.cc',
+ '../plugins/ppapi/var.h',
+ '../plugins/ppapi/var_object_class.cc',
+ '../plugins/ppapi/var_object_class.h',
+ 'media/audio_decoder.cc',
+ 'media/audio_decoder.h',
'media/buffered_data_source.cc',
'media/buffered_data_source.h',
- 'media/media_resource_loader_bridge_factory.cc',
- 'media/media_resource_loader_bridge_factory.h',
+ 'media/buffered_resource_loader.cc',
+ 'media/buffered_resource_loader.h',
'media/simple_data_source.cc',
'media/simple_data_source.h',
'media/video_renderer_impl.cc',
@@ -179,137 +339,6 @@
'media/web_data_source.cc',
'media/web_data_source.h',
'media/web_video_renderer.h',
- 'plugins/carbon_plugin_window_tracker_mac.h',
- 'plugins/carbon_plugin_window_tracker_mac.cc',
- 'plugins/coregraphics_private_symbols_mac.h',
- 'plugins/default_plugin_shared.h',
- 'plugins/nphostapi.h',
- 'plugins/gtk_plugin_container.h',
- 'plugins/gtk_plugin_container.cc',
- 'plugins/gtk_plugin_container_manager.h',
- 'plugins/gtk_plugin_container_manager.cc',
- 'plugins/npapi_extension_thunk.cc',
- 'plugins/npapi_extension_thunk.h',
- 'plugins/pepper_audio.cc',
- 'plugins/pepper_audio.h',
- 'plugins/pepper_buffer.cc',
- 'plugins/pepper_buffer.h',
- 'plugins/pepper_char_set.cc',
- 'plugins/pepper_char_set.h',
- 'plugins/pepper_class.h',
- 'plugins/pepper_cursor_control.cc',
- 'plugins/pepper_cursor_control.h',
- 'plugins/pepper_directory_reader.cc',
- 'plugins/pepper_directory_reader.h',
- 'plugins/pepper_error_util.cc',
- 'plugins/pepper_error_util.h',
- 'plugins/pepper_event_conversion.cc',
- 'plugins/pepper_event_conversion.h',
- 'plugins/pepper_file_callbacks.cc',
- 'plugins/pepper_file_callbacks.h',
- 'plugins/pepper_file_chooser.cc',
- 'plugins/pepper_file_chooser.h',
- 'plugins/pepper_file_io.cc',
- 'plugins/pepper_file_io.h',
- 'plugins/pepper_file_ref.cc',
- 'plugins/pepper_file_ref.h',
- 'plugins/pepper_file_system.cc',
- 'plugins/pepper_file_system.h',
- 'plugins/pepper_font.cc',
- 'plugins/pepper_font.h',
- 'plugins/pepper_graphics_2d.cc',
- 'plugins/pepper_graphics_2d.h',
- 'plugins/pepper_image_data.cc',
- 'plugins/pepper_image_data.h',
- 'plugins/pepper_plugin_delegate.h',
- 'plugins/pepper_plugin_instance.cc',
- 'plugins/pepper_plugin_instance.h',
- 'plugins/pepper_plugin_module.cc',
- 'plugins/pepper_plugin_module.h',
- 'plugins/pepper_plugin_object.cc',
- 'plugins/pepper_plugin_object.h',
- 'plugins/pepper_private.cc',
- 'plugins/pepper_private.h',
- 'plugins/pepper_private2.cc',
- 'plugins/pepper_private2.h',
- 'plugins/pepper_private2_linux.cc',
- 'plugins/pepper_resource_tracker.cc',
- 'plugins/pepper_resource_tracker.h',
- 'plugins/pepper_resource.cc',
- 'plugins/pepper_resource.h',
- 'plugins/pepper_scrollbar.cc',
- 'plugins/pepper_scrollbar.h',
- 'plugins/pepper_string.cc',
- 'plugins/pepper_string.h',
- 'plugins/pepper_transport.cc',
- 'plugins/pepper_transport.h',
- 'plugins/pepper_url_loader.cc',
- 'plugins/pepper_url_loader.h',
- 'plugins/pepper_url_request_info.cc',
- 'plugins/pepper_url_request_info.h',
- 'plugins/pepper_url_response_info.cc',
- 'plugins/pepper_url_response_info.h',
- 'plugins/pepper_url_util.cc',
- 'plugins/pepper_url_util.h',
- 'plugins/pepper_var.cc',
- 'plugins/pepper_var.h',
- 'plugins/pepper_video_decoder.cc',
- 'plugins/pepper_video_decoder.h',
- 'plugins/pepper_webplugin_impl.cc',
- 'plugins/pepper_webplugin_impl.h',
- 'plugins/pepper_widget.cc',
- 'plugins/pepper_widget.h',
- 'plugins/plugin_constants_win.h',
- 'plugins/plugin_group.cc',
- 'plugins/plugin_group.h',
- 'plugins/plugin_host.cc',
- 'plugins/plugin_host.h',
- 'plugins/plugin_instance.cc',
- 'plugins/plugin_instance.h',
- 'plugins/plugin_instance_mac.mm',
- 'plugins/plugin_lib.cc',
- 'plugins/plugin_lib.h',
- 'plugins/plugin_lib_mac.mm',
- 'plugins/plugin_lib_posix.cc',
- 'plugins/plugin_lib_win.cc',
- 'plugins/plugin_list.cc',
- 'plugins/plugin_list.h',
- 'plugins/plugin_list_mac.mm',
- 'plugins/plugin_list_posix.cc',
- 'plugins/plugin_list_win.cc',
- 'plugins/plugin_stream.cc',
- 'plugins/plugin_stream.h',
- 'plugins/plugin_stream_posix.cc',
- 'plugins/plugin_stream_url.cc',
- 'plugins/plugin_stream_url.h',
- 'plugins/plugin_stream_win.cc',
- 'plugins/plugin_string_stream.cc',
- 'plugins/plugin_string_stream.h',
- 'plugins/plugin_stubs.cc',
- 'plugins/plugin_switches.cc',
- 'plugins/plugin_switches.h',
- 'plugins/plugin_web_event_converter_mac.h',
- 'plugins/plugin_web_event_converter_mac.mm',
- 'plugins/ppb_private.h',
- 'plugins/quickdraw_drawing_manager_mac.h',
- 'plugins/quickdraw_drawing_manager_mac.cc',
- 'plugins/webview_plugin.cc',
- 'plugins/webview_plugin.h',
- 'plugins/webplugin.cc',
- 'plugins/webplugin.h',
- 'plugins/webplugin_2d_device_delegate.h',
- 'plugins/webplugin_3d_device_delegate.h',
- 'plugins/webplugin_accelerated_surface_mac.h',
- 'plugins/webplugin_delegate.h',
- 'plugins/webplugin_delegate_impl.cc',
- 'plugins/webplugin_delegate_impl.h',
- 'plugins/webplugin_delegate_impl_gtk.cc',
- 'plugins/webplugin_delegate_impl_mac.mm',
- 'plugins/webplugin_delegate_impl_win.cc',
- 'plugins/webplugin_impl.cc',
- 'plugins/webplugin_impl.h',
- 'plugins/webplugininfo.cc',
- 'plugins/webplugininfo.h',
'alt_error_page_resource_fetcher.cc',
'alt_error_page_resource_fetcher.h',
'context_menu.cc',
@@ -442,12 +471,14 @@
],
},
}],
- ['enable_gpu==1', {
- 'sources': [
- 'plugins/pepper_graphics_3d_gl.cc',
- 'plugins/pepper_graphics_3d.cc',
- 'plugins/pepper_graphics_3d.h',
+ ['enable_gpu!=1', {
+ 'sources!': [
+ '../plugins/ppapi/ppb_graphics_3d_impl.cc',
+ '../plugins/ppapi/ppb_graphics_3d_impl.h',
+ '../plugins/ppapi/ppb_open_gl_es_impl.cc',
],
+ }],
+ ['enable_gpu==1', {
'dependencies': [
'<(DEPTH)/gpu/gpu.gyp:gpu_plugin',
],
diff --git a/webkit/glue/webkit_glue.h b/webkit/glue/webkit_glue.h
index 6cc55b2..38ea659 100644
--- a/webkit/glue/webkit_glue.h
+++ b/webkit/glue/webkit_glue.h
@@ -23,7 +23,6 @@
class GURL;
class SkBitmap;
-struct WebPluginInfo;
namespace base {
class StringPiece;
@@ -39,6 +38,12 @@ class WebString;
class WebView;
}
+namespace webkit {
+namespace npapi {
+struct WebPluginInfo;
+}
+}
+
namespace webkit_glue {
@@ -50,21 +55,21 @@ void SetJavaScriptFlags(const std::string& flags);
void EnableWebCoreNotImplementedLogging();
// Returns the text of the document element.
-std::wstring DumpDocumentText(WebKit::WebFrame* web_frame);
+string16 DumpDocumentText(WebKit::WebFrame* web_frame);
// Returns the text of the document element and optionally its child frames.
// If recursive is false, this is equivalent to DumpDocumentText followed by
// a newline. If recursive is true, it recursively dumps all frames as text.
-std::wstring DumpFramesAsText(WebKit::WebFrame* web_frame, bool recursive);
+string16 DumpFramesAsText(WebKit::WebFrame* web_frame, bool recursive);
// Returns the renderer's description of its tree (its externalRepresentation).
-std::wstring DumpRenderer(WebKit::WebFrame* web_frame);
+string16 DumpRenderer(WebKit::WebFrame* web_frame);
// Fill the value of counter in the element specified by the id into
// counter_value. Return false when the specified id doesn't exist.
bool CounterValueForElementById(WebKit::WebFrame* web_frame,
const std::string& id,
- std::wstring* counter_value);
+ string16* counter_value);
// Returns the number of page where the specified element will be put.
int PageNumberForElementById(WebKit::WebFrame* web_frame,
@@ -78,13 +83,12 @@ int NumberOfPages(WebKit::WebFrame* web_frame,
float page_height_in_pixels);
// Returns a dump of the scroll position of the webframe.
-std::wstring DumpFrameScrollPosition(WebKit::WebFrame* web_frame,
- bool recursive);
+string16 DumpFrameScrollPosition(WebKit::WebFrame* web_frame, bool recursive);
// Returns a dump of the given history state suitable for implementing the
// dumpBackForwardList command of the layoutTestController.
-std::wstring DumpHistoryState(const std::string& history_state, int indent,
- bool is_current);
+string16 DumpHistoryState(const std::string& history_state, int indent,
+ bool is_current);
// Cleans up state left over from the previous test run.
void ResetBeforeTestRun(WebKit::WebView* view);
@@ -110,6 +114,10 @@ std::string CreateHistoryStateForURL(const GURL& url);
// Removes any form data state from the history state string |content_state|.
std::string RemoveFormDataFromHistoryState(const std::string& content_state);
+// Removes scroll offset from the history state string |content_state|.
+std::string RemoveScrollOffsetFromHistoryState(
+ const std::string& content_state);
+
#ifndef NDEBUG
// Checks various important objects to see if there are any in memory, and
// calls AppendToLog with any leaked objects. Designed to be called on shutdown
@@ -222,7 +230,8 @@ bool GetApplicationDirectory(FilePath* path);
bool GetExeDirectory(FilePath* path);
// Embedders implement this function to return the list of plugins to Webkit.
-void GetPlugins(bool refresh, std::vector<WebPluginInfo>* plugins);
+void GetPlugins(bool refresh,
+ std::vector<webkit::npapi::WebPluginInfo>* plugins);
// Returns true if the plugins run in the same process as the renderer, and
// false otherwise.
@@ -272,6 +281,12 @@ void EnableSpdy(bool enable);
// Notifies the browser that the given action has been performed.
void UserMetricsRecordAction(const std::string& action);
+#if !defined(DISABLE_NACL)
+// Launch NaCl's sel_ldr process.
+bool LaunchSelLdr(const char* alleged_url, int socket_count, void* imc_handles,
+ void* nacl_process_handle, int* nacl_process_id);
+#endif
+
#if defined(OS_LINUX)
// Return a read-only file descriptor to the font which best matches the given
// properties or -1 on failure.
diff --git a/webkit/glue/webkitclient_impl.cc b/webkit/glue/webkitclient_impl.cc
index 12d5702..844aae7 100644
--- a/webkit/glue/webkitclient_impl.cc
+++ b/webkit/glue/webkitclient_impl.cc
@@ -34,8 +34,9 @@
#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
#include "third_party/WebKit/WebKit/chromium/public/WebVector.h"
#include "third_party/WebKit/WebKit/chromium/public/WebURL.h"
-#include "webkit/glue/plugins/plugin_instance.h"
-#include "webkit/glue/plugins/webplugininfo.h"
+#include "webkit/glue/media/audio_decoder.h"
+#include "webkit/plugins/npapi/plugin_instance.h"
+#include "webkit/plugins/npapi/webplugininfo.h"
#include "webkit/glue/webkit_glue.h"
#include "webkit/glue/websocketstreamhandle_impl.h"
#include "webkit/glue/weburlloader_impl.h"
@@ -44,6 +45,7 @@
#include "v8/include/v8.h"
#endif
+using WebKit::WebAudioBus;
using WebKit::WebCookie;
using WebKit::WebData;
using WebKit::WebLocalizedString;
@@ -61,7 +63,7 @@ namespace {
class MemoryUsageCache {
public:
// Retrieves the Singleton.
- static MemoryUsageCache* Get() {
+ static MemoryUsageCache* GetInstance() {
return Singleton<MemoryUsageCache>::get();
}
@@ -223,18 +225,18 @@ WebString WebKitClientImpl::userAgent(const WebURL& url) {
void WebKitClientImpl::getPluginList(bool refresh,
WebPluginListBuilder* builder) {
- std::vector<WebPluginInfo> plugins;
+ std::vector<webkit::npapi::WebPluginInfo> plugins;
GetPlugins(refresh, &plugins);
for (size_t i = 0; i < plugins.size(); ++i) {
- const WebPluginInfo& plugin = plugins[i];
+ const webkit::npapi::WebPluginInfo& plugin = plugins[i];
builder->addPlugin(
plugin.name, plugin.desc,
FilePathStringToWebString(plugin.path.BaseName().value()));
for (size_t j = 0; j < plugin.mime_types.size(); ++j) {
- const WebPluginMimeType& mime_type = plugin.mime_types[j];
+ const webkit::npapi::WebPluginMimeType& mime_type = plugin.mime_types[j];
builder->addMediaTypeToLastPlugin(
WebString::fromUTF8(mime_type.mime_type), mime_type.description);
@@ -352,6 +354,15 @@ WebData WebKitClientImpl::loadResource(const char* name) {
return WebData();
}
+bool WebKitClientImpl::loadAudioResource(
+ WebKit::WebAudioBus* destination_bus, const char* audio_file_data,
+ size_t data_size, double sample_rate) {
+ return DecodeAudioFileData(destination_bus,
+ audio_file_data,
+ data_size,
+ sample_rate);
+}
+
WebString WebKitClientImpl::queryLocalizedString(
WebLocalizedString::Name name) {
int message_id = ToMessageID(name);
@@ -499,7 +510,7 @@ static size_t memoryUsageMBGeneric() {
static size_t getMemoryUsageMB(bool bypass_cache) {
size_t current_mem_usage = 0;
- MemoryUsageCache* mem_usage_cache_singleton = MemoryUsageCache::Get();
+ MemoryUsageCache* mem_usage_cache_singleton = MemoryUsageCache::GetInstance();
if (!bypass_cache &&
mem_usage_cache_singleton->IsCachedValueValid(&current_mem_usage))
return current_mem_usage;
diff --git a/webkit/glue/webkitclient_impl.h b/webkit/glue/webkitclient_impl.h
index 2836e8e..cc361d3 100644
--- a/webkit/glue/webkitclient_impl.h
+++ b/webkit/glue/webkitclient_impl.h
@@ -52,6 +52,9 @@ class WebKitClientImpl : public WebKit::WebKitClient {
virtual void traceEventBegin(const char* name, void* id, const char* extra);
virtual void traceEventEnd(const char* name, void* id, const char* extra);
virtual WebKit::WebData loadResource(const char* name);
+ virtual bool loadAudioResource(
+ WebKit::WebAudioBus* destination_bus, const char* audio_file_data,
+ size_t data_size, double sample_rate);
virtual WebKit::WebString queryLocalizedString(
WebKit::WebLocalizedString::Name name);
virtual WebKit::WebString queryLocalizedString(
diff --git a/webkit/glue/webmediaplayer_impl.cc b/webkit/glue/webmediaplayer_impl.cc
index 58489cc..4a64b0f 100644
--- a/webkit/glue/webmediaplayer_impl.cc
+++ b/webkit/glue/webmediaplayer_impl.cc
@@ -8,6 +8,7 @@
#include "base/callback.h"
#include "base/command_line.h"
+#include "media/base/filter_collection.h"
#include "media/base/limits.h"
#include "media/base/media_format.h"
#include "media/base/media_switches.h"
@@ -23,7 +24,6 @@
#include "third_party/WebKit/WebKit/chromium/public/WebURL.h"
#include "third_party/WebKit/WebKit/chromium/public/WebVideoFrame.h"
#include "webkit/glue/media/buffered_data_source.h"
-#include "webkit/glue/media/media_resource_loader_bridge_factory.h"
#include "webkit/glue/media/simple_data_source.h"
#include "webkit/glue/media/video_renderer_impl.h"
#include "webkit/glue/media/web_video_renderer.h"
@@ -225,7 +225,7 @@ void WebMediaPlayerImpl::Proxy::PutCurrentFrame(
WebMediaPlayerImpl::WebMediaPlayerImpl(
WebKit::WebMediaPlayerClient* client,
- media::MediaFilterCollection* collection)
+ media::FilterCollection* collection)
: network_state_(WebKit::WebMediaPlayer::Empty),
ready_state_(WebKit::WebMediaPlayer::HaveNothing),
main_loop_(NULL),
@@ -233,6 +233,7 @@ WebMediaPlayerImpl::WebMediaPlayerImpl(
pipeline_(NULL),
pipeline_thread_("PipelineThread"),
paused_(true),
+ seeking_(false),
playback_rate_(0.0f),
client_(client),
proxy_(NULL),
@@ -243,8 +244,7 @@ WebMediaPlayerImpl::WebMediaPlayerImpl(
}
bool WebMediaPlayerImpl::Initialize(
- MediaResourceLoaderBridgeFactory* bridge_factory_simple,
- MediaResourceLoaderBridgeFactory* bridge_factory_buffered,
+ WebKit::WebFrame* frame,
bool use_simple_data_source,
scoped_refptr<WebVideoRenderer> web_video_renderer) {
// Create the pipeline and its thread.
@@ -274,11 +274,11 @@ bool WebMediaPlayerImpl::Initialize(
// A simple data source that keeps all data in memory.
scoped_refptr<SimpleDataSource> simple_data_source(
- new SimpleDataSource(MessageLoop::current(), bridge_factory_simple));
+ new SimpleDataSource(MessageLoop::current(), frame));
// A sophisticated data source that does memory caching.
scoped_refptr<BufferedDataSource> buffered_data_source(
- new BufferedDataSource(MessageLoop::current(), bridge_factory_buffered));
+ new BufferedDataSource(MessageLoop::current(), frame));
proxy_->SetDataSource(buffered_data_source);
if (use_simple_data_source) {
@@ -369,11 +369,6 @@ void WebMediaPlayerImpl::seek(float seconds) {
return;
}
- // Drop our ready state if the media file isn't fully loaded.
- if (!pipeline_->IsLoaded()) {
- SetReadyState(WebKit::WebMediaPlayer::HaveMetadata);
- }
-
// Try to preserve as much accuracy as possible.
float microseconds = seconds * base::Time::kMicrosecondsPerSecond;
base::TimeDelta seek_time =
@@ -384,6 +379,8 @@ void WebMediaPlayerImpl::seek(float seconds) {
paused_time_ = seek_time;
}
+ seeking_ = true;
+
// Kick off the asynchronous seek!
pipeline_->Seek(
seek_time,
@@ -477,7 +474,7 @@ bool WebMediaPlayerImpl::seeking() const {
if (ready_state_ == WebKit::WebMediaPlayer::HaveNothing)
return false;
- return ready_state_ == WebKit::WebMediaPlayer::HaveMetadata;
+ return seeking_;
}
float WebMediaPlayerImpl::duration() const {
@@ -505,6 +502,14 @@ int WebMediaPlayerImpl::dataRate() const {
return 0;
}
+WebKit::WebMediaPlayer::NetworkState WebMediaPlayerImpl::networkState() const {
+ return network_state_;
+}
+
+WebKit::WebMediaPlayer::ReadyState WebMediaPlayerImpl::readyState() const {
+ return ready_state_;
+}
+
const WebKit::WebTimeRanges& WebMediaPlayerImpl::buffered() {
DCHECK(MessageLoop::current() == main_loop_);
@@ -698,6 +703,7 @@ void WebMediaPlayerImpl::OnPipelineSeek() {
}
SetReadyState(WebKit::WebMediaPlayer::HaveEnoughData);
+ seeking_ = false;
GetClient()->timeChanged();
}
}
diff --git a/webkit/glue/webmediaplayer_impl.h b/webkit/glue/webmediaplayer_impl.h
index 26825da..bae0d9b 100644
--- a/webkit/glue/webmediaplayer_impl.h
+++ b/webkit/glue/webmediaplayer_impl.h
@@ -69,6 +69,10 @@
class GURL;
+namespace WebKit {
+class WebFrame;
+}
+
namespace webkit_glue {
class MediaResourceLoaderBridgeFactory;
@@ -91,12 +95,12 @@ class WebMediaPlayerImpl : public WebKit::WebMediaPlayer,
Proxy(MessageLoop* render_loop,
WebMediaPlayerImpl* webmediaplayer);
- // Methods for MediaFilter -> WebMediaPlayerImpl communication.
+ // Methods for Filter -> WebMediaPlayerImpl communication.
void Repaint();
void SetVideoRenderer(scoped_refptr<WebVideoRenderer> video_renderer);
void SetDataSource(scoped_refptr<WebDataSource> data_source);
- // Methods for WebMediaPlayerImpl -> MediaFilter communication.
+ // Methods for WebMediaPlayerImpl -> Filter communication.
void Paint(skia::PlatformCanvas* canvas, const gfx::Rect& dest_rect);
void SetSize(const gfx::Rect& rect);
void Detach();
@@ -171,13 +175,12 @@ class WebMediaPlayerImpl : public WebKit::WebMediaPlayer,
//
// Callers must call |Initialize()| before they can use the object.
WebMediaPlayerImpl(WebKit::WebMediaPlayerClient* client,
- media::MediaFilterCollection* collection);
+ media::FilterCollection* collection);
virtual ~WebMediaPlayerImpl();
// Finalizes initialization of the object.
bool Initialize(
- MediaResourceLoaderBridgeFactory* bridge_factory_simple,
- MediaResourceLoaderBridgeFactory* bridge_factory_buffered,
+ WebKit::WebFrame* frame,
bool use_simple_data_source,
scoped_refptr<WebVideoRenderer> web_video_renderer);
@@ -223,12 +226,8 @@ class WebMediaPlayerImpl : public WebKit::WebMediaPlayer,
// Internal states of loading and network.
// TODO(hclam): Ask the pipeline about the state rather than having reading
// them from members which would cause race conditions.
- virtual WebKit::WebMediaPlayer::NetworkState networkState() const {
- return network_state_;
- }
- virtual WebKit::WebMediaPlayer::ReadyState readyState() const {
- return ready_state_;
- }
+ virtual WebKit::WebMediaPlayer::NetworkState networkState() const;
+ virtual WebKit::WebMediaPlayer::ReadyState readyState() const;
virtual unsigned long long bytesLoaded() const;
virtual unsigned long long totalBytes() const;
@@ -285,7 +284,7 @@ class WebMediaPlayerImpl : public WebKit::WebMediaPlayer,
MessageLoop* main_loop_;
// A collection of filters.
- scoped_ptr<media::MediaFilterCollection> filter_collection_;
+ scoped_ptr<media::FilterCollection> filter_collection_;
// The actual pipeline and the thread it runs on.
scoped_refptr<media::Pipeline> pipeline_;
@@ -304,6 +303,7 @@ class WebMediaPlayerImpl : public WebKit::WebMediaPlayer,
// clock can creep forward a little bit while the asynchronous
// SetPlaybackRate(0) is being executed.
bool paused_;
+ bool seeking_;
float playback_rate_;
base::TimeDelta paused_time_;
diff --git a/webkit/glue/webpreferences.cc b/webkit/glue/webpreferences.cc
index afc39bd..abe5903 100644
--- a/webkit/glue/webpreferences.cc
+++ b/webkit/glue/webpreferences.cc
@@ -21,11 +21,11 @@ using WebKit::WebURL;
using WebKit::WebView;
WebPreferences::WebPreferences()
- : standard_font_family(L"Times New Roman"),
- fixed_font_family(L"Courier New"),
- serif_font_family(L"Times New Roman"),
- sans_serif_font_family(L"Arial"),
- cursive_font_family(L"Script"),
+ : standard_font_family(ASCIIToUTF16("Times New Roman")),
+ fixed_font_family(ASCIIToUTF16("Courier New")),
+ serif_font_family(ASCIIToUTF16("Times New Roman")),
+ sans_serif_font_family(ASCIIToUTF16("Arial")),
+ cursive_font_family(ASCIIToUTF16("Script")),
fantasy_font_family(), // Not sure what to use on Windows.
default_font_size(16),
default_fixed_font_size(13),
@@ -73,12 +73,12 @@ WebPreferences::~WebPreferences() {
void WebPreferences::Apply(WebView* web_view) const {
WebSettings* settings = web_view->settings();
- settings->setStandardFontFamily(WideToUTF16Hack(standard_font_family));
- settings->setFixedFontFamily(WideToUTF16Hack(fixed_font_family));
- settings->setSerifFontFamily(WideToUTF16Hack(serif_font_family));
- settings->setSansSerifFontFamily(WideToUTF16Hack(sans_serif_font_family));
- settings->setCursiveFontFamily(WideToUTF16Hack(cursive_font_family));
- settings->setFantasyFontFamily(WideToUTF16Hack(fantasy_font_family));
+ settings->setStandardFontFamily(standard_font_family);
+ settings->setFixedFontFamily(fixed_font_family);
+ settings->setSerifFontFamily(serif_font_family);
+ settings->setSansSerifFontFamily(sans_serif_font_family);
+ settings->setCursiveFontFamily(cursive_font_family);
+ settings->setFantasyFontFamily(fantasy_font_family);
settings->setDefaultFontSize(default_font_size);
settings->setDefaultFixedFontSize(default_fixed_font_size);
settings->setMinimumFontSize(minimum_font_size);
@@ -142,7 +142,7 @@ void WebPreferences::Apply(WebView* web_view) const {
// Enable experimental WebGL support if requested on command line
// and support is compiled in.
bool enable_webgl =
- WebRuntimeFeatures::isWebGLEnabled() || experimental_webgl_enabled;
+ WebRuntimeFeatures::isWebGLEnabled() && experimental_webgl_enabled;
settings->setExperimentalWebGLEnabled(enable_webgl);
// Display colored borders around composited render layers if requested
diff --git a/webkit/glue/webpreferences.h b/webkit/glue/webpreferences.h
index 6cb8044..8ee4ce8 100644
--- a/webkit/glue/webpreferences.h
+++ b/webkit/glue/webpreferences.h
@@ -13,6 +13,8 @@
#include <string>
#include <vector>
+
+#include "base/string16.h"
#include "googleurl/src/gurl.h"
namespace WebKit {
@@ -20,12 +22,12 @@ class WebView;
}
struct WebPreferences {
- std::wstring standard_font_family;
- std::wstring fixed_font_family;
- std::wstring serif_font_family;
- std::wstring sans_serif_font_family;
- std::wstring cursive_font_family;
- std::wstring fantasy_font_family;
+ string16 standard_font_family;
+ string16 fixed_font_family;
+ string16 serif_font_family;
+ string16 sans_serif_font_family;
+ string16 cursive_font_family;
+ string16 fantasy_font_family;
int default_font_size;
int default_fixed_font_size;
int minimum_font_size;
diff --git a/webkit/glue/weburlloader_impl.cc b/webkit/glue/weburlloader_impl.cc
index a7f219d..0372567 100644
--- a/webkit/glue/weburlloader_impl.cc
+++ b/webkit/glue/weburlloader_impl.cc
@@ -14,6 +14,7 @@
#include "base/time.h"
#include "net/base/data_url.h"
#include "net/base/load_flags.h"
+#include "net/base/mime_util.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
#include "net/http/http_response_headers.h"
@@ -302,6 +303,8 @@ class WebURLLoaderImpl::Context : public base::RefCounted<Context>,
friend class base::RefCounted<Context>;
~Context() {}
+ // We can optimize the handling of data URLs in most cases.
+ bool CanHandleDataURL(const GURL& url) const;
void HandleDataURL();
WebURLLoaderImpl* loader_;
@@ -350,7 +353,7 @@ void WebURLLoaderImpl::Context::Start(
request_ = request; // Save the request.
GURL url = request.url();
- if (url.SchemeIs("data")) {
+ if (url.SchemeIs("data") && CanHandleDataURL(url)) {
if (sync_load_response) {
// This is a sync load. Do the work now.
sync_load_response->url = url;
@@ -432,6 +435,7 @@ void WebURLLoaderImpl::Context::Start(
request_info.appcache_host_id = request.appCacheHostID();
request_info.routing_id = request.requestorID();
request_info.download_to_file = request.downloadToFile();
+ request_info.has_user_gesture = request.hasUserGesture();
bridge_.reset(ResourceLoaderBridge::Create(request_info));
if (!request.httpBody().isNull()) {
@@ -662,6 +666,29 @@ void WebURLLoaderImpl::Context::OnCompletedRequest(
Release();
}
+bool WebURLLoaderImpl::Context::CanHandleDataURL(const GURL& url) const {
+ DCHECK(url.SchemeIs("data"));
+
+ // Optimize for the case where we can handle a data URL locally. We must
+ // skip this for data URLs targetted at frames since those could trigger a
+ // download.
+ //
+ // NOTE: We special case MIME types we can render both for performance
+ // reasons as well as to support unit tests, which do not have an underlying
+ // ResourceLoaderBridge implementation.
+
+ if (request_.targetType() != WebURLRequest::TargetIsMainFrame &&
+ request_.targetType() != WebURLRequest::TargetIsSubframe)
+ return true;
+
+ std::string mime_type, unused_charset;
+ if (net::DataURL::Parse(url, &mime_type, &unused_charset, NULL) &&
+ net::IsSupportedMimeType(mime_type))
+ return true;
+
+ return false;
+}
+
void WebURLLoaderImpl::Context::HandleDataURL() {
ResourceResponseInfo info;
URLRequestStatus status;